@ykurilov/agent-chat-flows 0.65.1 → 0.67.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 +24 -0
- package/agent-flow.schema.json +12 -0
- package/dist/{chunk-L7XNC3RB.js → chunk-2ZHBD7MF.js} +2 -2
- package/dist/{chunk-7VR4YNTJ.js → chunk-C7PMUVRN.js} +23 -5
- package/dist/chunk-C7PMUVRN.js.map +1 -0
- package/dist/{chunk-KRZMJJKG.js → chunk-H2TPYIWU.js} +11 -7
- package/dist/chunk-H2TPYIWU.js.map +1 -0
- package/dist/format.js +2 -2
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/react.js +51 -9
- package/dist/react.js.map +1 -1
- package/dist/types/engine/nudges.d.ts +1 -1
- package/dist/types/format/flow-format.d.ts +10 -0
- package/dist/types/format/flow-schema.d.ts +6 -0
- package/dist/types/labels/editor.d.ts +5 -1
- package/dist/types/react/editor/index.d.ts +1 -1
- package/dist/types/react/editor/schedule-model.d.ts +9 -1
- package/dist/types/react/flow-editor-skin.d.ts +3 -0
- package/dist/types/runtime/first-message-rules.d.ts +2 -0
- package/dist/types/runtime/flow-types.d.ts +2 -0
- package/package.json +4 -4
- package/dist/chunk-7VR4YNTJ.js.map +0 -1
- package/dist/chunk-KRZMJJKG.js.map +0 -1
- /package/dist/{chunk-L7XNC3RB.js.map → chunk-2ZHBD7MF.js.map} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# @ykurilov/agent-chat-flows
|
|
2
2
|
|
|
3
|
+
## 0.67.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 12c0dd8: Потолок «пишет первым» по дням программы: `schedule.firstMessages.maxPerDayByDay` (`[3, 2]` — день 1 три, со дня 2 по
|
|
8
|
+
два; главнее `maxPerDay`; ответ человека счёт не обнуляет). Свои касания ноды до N-го дня программы:
|
|
9
|
+
`nudges.untilProgramDay` (дошёл до ноды позже — сразу общий ряд). `checkFlow`: `nudges_until_day_invalid`,
|
|
10
|
+
`nudges_until_day_after_end`, `max_per_day_by_day_after_end`. Доска: поле «по дням программы» и режим «до дня программы»
|
|
11
|
+
(ru/en); `FlowStateTimingProps` + `nudgesUntilProgramDay`, `onNudgesUntilProgramDayChange`; выгружены `parseCapsByDay`,
|
|
12
|
+
`capsByDayText`.
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- @ykurilov/agent-chat-core@0.67.0
|
|
17
|
+
- @ykurilov/agent-chat-react@0.67.0
|
|
18
|
+
|
|
19
|
+
## 0.66.0
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- Updated dependencies [1d57795]
|
|
24
|
+
- @ykurilov/agent-chat-core@0.66.0
|
|
25
|
+
- @ykurilov/agent-chat-react@0.66.0
|
|
26
|
+
|
|
3
27
|
## 0.65.1
|
|
4
28
|
|
|
5
29
|
### Patch Changes
|
package/agent-flow.schema.json
CHANGED
|
@@ -718,6 +718,9 @@
|
|
|
718
718
|
},
|
|
719
719
|
"days": {
|
|
720
720
|
"type": "number"
|
|
721
|
+
},
|
|
722
|
+
"untilProgramDay": {
|
|
723
|
+
"type": "number"
|
|
721
724
|
}
|
|
722
725
|
},
|
|
723
726
|
"required": [
|
|
@@ -801,6 +804,15 @@
|
|
|
801
804
|
"minimum": 0,
|
|
802
805
|
"maximum": 9007199254740991
|
|
803
806
|
},
|
|
807
|
+
"maxPerDayByDay": {
|
|
808
|
+
"minItems": 1,
|
|
809
|
+
"type": "array",
|
|
810
|
+
"items": {
|
|
811
|
+
"type": "integer",
|
|
812
|
+
"minimum": 0,
|
|
813
|
+
"maximum": 9007199254740991
|
|
814
|
+
}
|
|
815
|
+
},
|
|
804
816
|
"morning": {
|
|
805
817
|
"type": "boolean"
|
|
806
818
|
},
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
fieldValueFits,
|
|
6
6
|
isFinal,
|
|
7
7
|
stateById
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-C7PMUVRN.js";
|
|
9
9
|
|
|
10
10
|
// src/format/flow-json-schema.ts
|
|
11
11
|
import { z } from "zod";
|
|
@@ -68,4 +68,4 @@ export {
|
|
|
68
68
|
sideTaskStanding,
|
|
69
69
|
openSideTasks
|
|
70
70
|
};
|
|
71
|
-
//# sourceMappingURL=chunk-
|
|
71
|
+
//# sourceMappingURL=chunk-2ZHBD7MF.js.map
|
|
@@ -80,6 +80,7 @@ var schedule = z.strictObject({
|
|
|
80
80
|
farewellText: z.string().optional(),
|
|
81
81
|
firstMessages: z.strictObject({
|
|
82
82
|
maxPerDay: z.int().min(0).optional(),
|
|
83
|
+
maxPerDayByDay: z.array(z.int().min(0)).min(1).optional(),
|
|
83
84
|
morning: z.boolean().optional(),
|
|
84
85
|
skipMorningIfHumanWithinMin: z.int().min(0).optional()
|
|
85
86
|
}).optional(),
|
|
@@ -108,7 +109,7 @@ var flowState = z.strictObject({
|
|
|
108
109
|
tools: names,
|
|
109
110
|
tags: names,
|
|
110
111
|
exits,
|
|
111
|
-
nudges: z.union([nudges.extend({ days: z.number().optional() }), z.literal("off")]).optional()
|
|
112
|
+
nudges: z.union([nudges.extend({ days: z.number().optional(), untilProgramDay: z.number().optional() }), z.literal("off")]).optional()
|
|
112
113
|
});
|
|
113
114
|
var DEFAULT_SIDE_QUESTION_EVERY_MESSAGES = 5;
|
|
114
115
|
var agentFlowSchema = z.strictObject({
|
|
@@ -578,10 +579,12 @@ function nudgeRings(flow, run, timeZone) {
|
|
|
578
579
|
if (own === "off") return null;
|
|
579
580
|
const common = flow.schedule?.nudges ?? flow.nudges ?? null;
|
|
580
581
|
if (!own) return common && { ring: common };
|
|
581
|
-
if (own.days === void 0) return { ring: own };
|
|
582
|
+
if (own.days === void 0 && own.untilProgramDay === void 0) return { ring: own };
|
|
582
583
|
const schedule2 = flow.schedule ?? CALENDAR_DAYS;
|
|
583
|
-
const
|
|
584
|
-
|
|
584
|
+
const ends = [];
|
|
585
|
+
if (own.days !== void 0) ends.push(programDayDue(run, flowDay(run, run.enteredAt, timeZone, schedule2).day + own.days, timeZone, schedule2));
|
|
586
|
+
if (own.untilProgramDay !== void 0) ends.push(programDayDue(run, own.untilProgramDay + 1, timeZone, schedule2));
|
|
587
|
+
return { ring: own, until: Math.min(...ends), after: common };
|
|
585
588
|
}
|
|
586
589
|
var UNIT_MS2 = { min: 6e4, h: 36e5, d: 864e5 };
|
|
587
590
|
var durationMs = (duration2) => duration2.amount * UNIT_MS2[duration2.unit];
|
|
@@ -1211,6 +1214,14 @@ function checkState(flow, catalog, issues, state) {
|
|
|
1211
1214
|
if (days !== void 0 && (!Number.isInteger(days) || days < 1)) {
|
|
1212
1215
|
issues.error("nudges_days_invalid", `${stateName(state)}: \u0441\u0432\u043E\u0438 \u043A\u0430\u0441\u0430\u043D\u0438\u044F \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044E\u0442 \u0446\u0435\u043B\u043E\u0435 \u0447\u0438\u0441\u043B\u043E \u0434\u043D\u0435\u0439, \u0441 1`, { stateId: state.id });
|
|
1213
1216
|
}
|
|
1217
|
+
const untilDay = state.nudges && state.nudges !== "off" ? state.nudges.untilProgramDay : void 0;
|
|
1218
|
+
if (untilDay !== void 0 && (!Number.isInteger(untilDay) || untilDay < 1)) {
|
|
1219
|
+
issues.error("nudges_until_day_invalid", `${stateName(state)}: \u0441\u0432\u043E\u0438 \u043A\u0430\u0441\u0430\u043D\u0438\u044F \xAB\u0434\u043E \u0434\u043D\u044F \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u044B\xBB \u2014 \u0446\u0435\u043B\u043E\u0435 \u0447\u0438\u0441\u043B\u043E \u0441 1`, { stateId: state.id });
|
|
1220
|
+
} else if (untilDay !== void 0 && flow.schedule?.lengthDays !== void 0 && untilDay > flow.schedule.lengthDays) {
|
|
1221
|
+
issues.warning("nudges_until_day_after_end", `${stateName(state)}: \u0441\u0432\u043E\u0438 \u043A\u0430\u0441\u0430\u043D\u0438\u044F \u0434\u043E \u0434\u043D\u044F ${untilDay}, \u0430 \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u0430 \u0434\u043B\u0438\u0442\u0441\u044F ${flow.schedule.lengthDays} \u0434\u043D. \u2014 \u043E\u043D\u0438 \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044E\u0442 \u0432\u0441\u044E \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u0443`, {
|
|
1222
|
+
stateId: state.id
|
|
1223
|
+
});
|
|
1224
|
+
}
|
|
1214
1225
|
}
|
|
1215
1226
|
var nudgesEmpty = (nudges2) => nudges2.afterSilence.length === 0 && !nudges2.dailyAt?.length;
|
|
1216
1227
|
function checkSchedule(flow, issues) {
|
|
@@ -1230,6 +1241,13 @@ function checkSchedule(flow, issues) {
|
|
|
1230
1241
|
if (frame?.softFrom !== void 0 && frame.hardAt !== void 0 && frame.softFrom >= frame.hardAt) {
|
|
1231
1242
|
issues.error("day_frame_soft_after_hard", `\xAB\u0414\u043D\u0438 \u0438 \u0432\u0440\u0435\u043C\u044F\xBB: \u043C\u044F\u0433\u043A\u0430\u044F \u0440\u0430\u043C\u043A\u0430 (${frame.softFrom}) \u0434\u043E\u043B\u0436\u043D\u0430 \u0431\u044B\u0442\u044C \u0440\u0430\u043D\u044C\u0448\u0435 \u0436\u0451\u0441\u0442\u043A\u043E\u0439 (${frame.hardAt})`);
|
|
1232
1243
|
}
|
|
1244
|
+
const byDay = schedule2.firstMessages?.maxPerDayByDay;
|
|
1245
|
+
if (byDay && schedule2.lengthDays !== void 0 && byDay.length > schedule2.lengthDays) {
|
|
1246
|
+
issues.warning(
|
|
1247
|
+
"max_per_day_by_day_after_end",
|
|
1248
|
+
`\xAB\u0414\u043D\u0438 \u0438 \u0432\u0440\u0435\u043C\u044F\xBB: \u043F\u043E\u0442\u043E\u043B\u043E\u043A \u0437\u0430\u0434\u0430\u043D \u043D\u0430 ${byDay.length} \u0434\u043D., \u0430 \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u0430 \u0434\u043B\u0438\u0442\u0441\u044F ${schedule2.lengthDays} \u0434\u043D. \u2014 \u043B\u0438\u0448\u043D\u0438\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F \u043D\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044E\u0442`
|
|
1249
|
+
);
|
|
1250
|
+
}
|
|
1233
1251
|
if (schedule2.nudges && nudgesEmpty(schedule2.nudges)) {
|
|
1234
1252
|
issues.warning("empty_nudges", "\xAB\u0414\u043D\u0438 \u0438 \u0432\u0440\u0435\u043C\u044F\xBB: \u0432 \u043A\u0430\u0441\u0430\u043D\u0438\u044F\u0445 \u043D\u0435\u0442 \u043D\u0438 \u043E\u0434\u043D\u043E\u0433\u043E \u0441\u0440\u043E\u043A\u0430 \u2014 \u0430\u0433\u0435\u043D\u0442 \u043D\u0435 \u043D\u0430\u043F\u0438\u0448\u0435\u0442 \u043F\u0435\u0440\u0432\u044B\u043C");
|
|
1235
1253
|
}
|
|
@@ -1393,4 +1411,4 @@ export {
|
|
|
1393
1411
|
appIssues,
|
|
1394
1412
|
checkFlow
|
|
1395
1413
|
};
|
|
1396
|
-
//# sourceMappingURL=chunk-
|
|
1414
|
+
//# sourceMappingURL=chunk-C7PMUVRN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/format/flow-format.ts","../src/format/flow-schema.ts","../src/format/migrate-flow.ts","../src/format/parse-flow.ts","../src/format/catalog-events.ts","../src/format/compact-flow.ts","../src/format/parse-duration.ts","../src/engine/flow-run.ts","../src/engine/flow-graph.ts","../src/engine/data-conditions.ts","../src/engine/targets.ts","../src/engine/zoned-time.ts","../src/engine/flow-days.ts","../src/engine/nudges.ts","../src/engine/timers.ts","../src/engine/next-transition.ts","../src/engine/run-updates.ts","../src/engine/first-messages.ts","../src/engine/side-questions.ts","../src/engine/migrate-run.ts","../src/engine/day-frame.ts","../src/check/app-checks.ts","../src/check/check-flow.ts"],"sourcesContent":["/** Поле `format` у каждого сценария: по нему JSON узнаётся как сценарий агента. */\nexport const AGENT_FLOW_FORMAT = \"agent-flow\";\n\n/** Версия формата, которую понимает этот SDK. Старые версии `parseFlow` переводит сам (`migrate-flow.ts`). */\nexport const AGENT_FLOW_FORMAT_VERSION = 2;\n\n/** Особая цель перехода: вернуться в последнее основное состояние (после напоминаний и касаний). */\nexport const RETURN_TARGET = \"@return\";\n\n/** Ключ места «Из любого состояния» в `layout`. */\nexport const ANY_STATE_LAYOUT_KEY = \"@any\";\n\n/** `boolean` — «да/нет» (с версии 2): хранится `true` / `false`. */\nexport const FLOW_FIELD_TYPES = [\"text\", \"number\", \"choice\", \"boolean\"] as const;\nexport type FlowFieldType = (typeof FLOW_FIELD_TYPES)[number];\n\n/** `ne` — «≠» (с версии 2), пока только для «да/нет». */\nexport const FLOW_DATA_OPS = [\"filled\", \"eq\", \"ne\", \"gt\", \"lt\", \"contains\"] as const;\nexport type FlowDataOp = (typeof FLOW_DATA_OPS)[number];\n\n/** Какие сравнения подходят к типу поля. Остальные — ошибка проверки графа. */\nexport const FLOW_OPS_BY_FIELD_TYPE: Readonly<Record<FlowFieldType, readonly FlowDataOp[]>> = {\n text: [\"filled\", \"contains\"],\n number: [\"filled\", \"eq\", \"gt\", \"lt\"],\n choice: [\"filled\", \"eq\"],\n boolean: [\"filled\", \"eq\", \"ne\"],\n};\n\nexport const FLOW_EVENT_TYPES = [\"message\", \"button\", \"tool\", \"app\"] as const;\nexport type FlowEventType = (typeof FLOW_EVENT_TYPES)[number];\n\nexport const FLOW_TIMER_UNITS = [\"min\", \"h\", \"d\"] as const;\nexport type FlowTimerUnit = (typeof FLOW_TIMER_UNITS)[number];\n\n/** Откуда считается срок: время в состоянии, тишина человека, с начала чата. */\nexport const FLOW_TIMER_SPANS = [\"in_state\", \"silence\", \"since_start\"] as const;\nexport type FlowTimerSpan = (typeof FLOW_TIMER_SPANS)[number];\n\n/** Заметка чата: живёт весь чат, в следующем чате не помнится. */\nexport interface FlowField {\n id: string;\n name: string;\n /** Что это и когда уместно спросить. Видит модель. */\n about: string;\n type: FlowFieldType;\n /** Варианты для `choice`; у остальных типов пусто. */\n options: string[];\n}\n\n/** Поле карточки клиента: долгая память о человеке, переживает чаты. */\nexport interface ClientCardField extends FlowField {\n /** Через сколько месяцев мягко уточнить; `null` — не устаревает. */\n refreshAfterMonths: number | null;\n}\n\n/** Условие словами: решает судья по разговору. */\nexport interface JudgeCondition {\n type: \"judge\";\n text: string;\n}\n\n/** Условие по данным: поле карточки или заметки чата. При `filled` значения нет; у «да/нет» значение — `true` / `false`. */\nexport interface DataCondition {\n type: \"data\";\n field: string;\n op: FlowDataOp;\n value?: string | number | boolean;\n}\n\n/** Событие: сообщение человека, кнопка, вызов инструмента или событие приложения — по именам, которые объявило приложение. */\nexport interface EventCondition {\n type: \"event\";\n event: FlowEventType;\n name?: string;\n}\n\nexport interface SpanTimerCondition {\n type: \"timer\";\n from: FlowTimerSpan;\n amount: number;\n unit: FlowTimerUnit;\n}\n\n/** Наступило время суток (в поясе человека), `at` — «ЧЧ:ММ». */\nexport interface TimeOfDayTimerCondition {\n type: \"timer\";\n from: \"time_of_day\";\n at: string;\n}\n\n/** Нода длится `days` дней сценария: срок — начало дня «день входа + days» (`schedule.dayStart`). С версии 2. */\nexport interface StateDaysTimerCondition {\n type: \"timer\";\n from: \"state_days\";\n days: number;\n}\n\n/**\n * Наступил день `day` сценария: начало этого дня (`schedule.dayStart`) по часам человека, по той же нумерации, что день в\n * `readRun`. Нода вошла в день `day` или позже — выход сразу. Дополнение к версии 2 (0.55).\n */\nexport interface ProgramDayTimerCondition {\n type: \"timer\";\n from: \"program_day\";\n day: number;\n}\n\nexport type TimerCondition = SpanTimerCondition | TimeOfDayTimerCondition | StateDaysTimerCondition | ProgramDayTimerCondition;\nexport type FlowCondition = JudgeCondition | DataCondition | EventCondition | TimerCondition;\nexport type FlowConditionType = FlowCondition[\"type\"];\n\nexport interface FlowExit {\n /** Постоянный адрес условия: на него ссылаются история переходов и таймеры. */\n id: string;\n when: FlowCondition;\n /** `id` состояния или `RETURN_TARGET`; `null` — цель ещё не выбрана. */\n to: string | null;\n}\n\nexport interface FlowState {\n id: string;\n /** Зарезервировано под подсценарии. */\n kind: \"state\";\n title: string;\n /** Первая строка — цель (её видно на доске), дальше — как себя вести. */\n instructions: string;\n /** Что написать при входе в состояние; `null` — агент пишет сам. */\n firstMessage: string | null;\n /** Поля карточки и заметок, которые нужно узнать здесь. */\n learn: string[];\n /** Не задавать вопросов между делом. */\n noSideQuestions: boolean;\n /** Инструменты приложения, доступные в этом состоянии. */\n tools: string[];\n /** Метки перехода в это состояние: приходят в `onTransition`. */\n tags: string[];\n /** Состояние без условий — конец сценария. */\n exits: FlowExit[];\n /** Свои касания ноды; `\"off\"` — без касаний; нет — общие `schedule.nudges`, затем `nudges` сценария. С версии 2. */\n nudges?: FlowStateNudges | \"off\";\n}\n\n/** Общие переходы: работают из любого состояния, кроме перечисленных. */\nexport interface FlowAnyState {\n except: string[];\n exits: FlowExit[];\n}\n\nexport interface FlowPace {\n /** Как часто можно спросить между делом: раз в столько сообщений человека. */\n sideQuestionEveryMessages: number;\n}\n\nexport interface FlowPoint {\n x: number;\n y: number;\n}\n\n/** Срок словами формата: «15 min», «4 h», «3 d» (d = 24 ч). */\nexport interface FlowDuration {\n amount: number;\n unit: FlowTimerUnit;\n}\n\n/** Касания — ход агента в той же ноде, когда человек молчит. И у сценария, и у ноды. */\nexport interface FlowNudges {\n /** Ряд сроков тишины от последнего ответа агента; сообщение человека начинает ряд сначала. */\n afterSilence: FlowDuration[];\n /** После ряда — касания в эти часы («ЧЧ:ММ») каждый день. */\n dailyAt?: string[];\n /** Столько тишины — конец разговора «не завершил», без сообщения. */\n giveUpAfter?: FlowDuration;\n}\n\n/** Свои касания ноды: можно ограничить первыми днями в ноде. */\nexport interface FlowStateNudges extends FlowNudges {\n /**\n * Свой ряд действует столько дней сценария, считая день входа в ноду (1 — только день входа). Потом — общие касания\n * (`schedule.nudges`, затем `nudges` сценария), их ряд с начала. Нет — всё время в ноде. С 0.55.\n */\n days?: number;\n /**\n * Свой ряд действует, пока идёт день программы не позже этого (1 — только первый день программы). Человек дошёл до\n * ноды позже — своего ряда нет, сразу общие касания. Вместе с `days` — что наступит раньше. С 0.67.\n */\n untilProgramDay?: number;\n}\n\n/** Порог позднего старта по умолчанию: до ночи меньше 3 ч — первым днём считается завтра. */\nexport const DEFAULT_LATE_START_HOURS = 3;\n\n/** «Дни и время»: дни сценария, ночь, срок, касания, рамки дня. С версии 2. */\nexport interface FlowSchedule {\n /** Начало дня, оно же утреннее касание: «09:00». */\n dayStart: string;\n /** Начало ночи: ночь = [nightFrom, dayStart). Нет — ночь из настроек приложения. */\n nightFrom?: string;\n /** Пришёл позже, чем за столько часов до ночи, — первый день завтра. 0 — день старта всегда первый. */\n lateStartHours: number;\n /** Общий срок в днях, 1–60. */\n lengthDays?: number;\n /** Куда перейти при «срок вышел» перед концом. */\n deadlineState?: string;\n /** При «срок вышел» агент пишет одно прощальное сообщение по правилам «писать первым» (→ В5). */\n farewellOnDeadline: boolean;\n /** Готовый текст прощания: уходит слово в слово, без модели. Нет — прощание пишет модель. */\n farewellText?: string;\n firstMessages?: {\n /** Нет — из настроек приложения. */\n maxPerDay?: number;\n /**\n * Потолок по дням программы: `[3, 2]` — в день 1 не больше трёх, со дня 2 — не больше двух (последнее значение — на\n * все следующие дни). Главнее `maxPerDay`. Счёт идёт по дням программы, ответ человека его не обнуляет. С 0.67.\n */\n maxPerDayByDay?: number[];\n /** Писать в начале дня; нет — да, если задан `lengthDays`. */\n morning?: boolean;\n /** Утреннее пропускается, если человек писал за столько минут до него; нет — 180. */\n skipMorningIfHumanWithinMin?: number;\n };\n /** Общее правило касаний. */\n nudges?: FlowNudges;\n /** Рамки дня по числу сообщений человека: мягкая с `softFrom`, жёсткая на `hardAt`. */\n dayFrame?: { softFrom?: number; hardAt?: number; hardText?: string };\n}\n\n/** Попытки попутной задачи по умолчанию. */\nexport const DEFAULT_SIDE_TASK_MAX_ATTEMPTS = 2;\n\n/** Попутная задача: агент делает её между делом, в общем темпе вопросов между делом. С версии 2. */\nexport interface FlowSideTask {\n id: string;\n /** Что сделать, словами для агента. */\n text: string;\n /** Когда уместно, словами. */\n when?: string;\n /** Поле карточки или заметки: задача решена, когда оно известно. */\n field?: string;\n maxAttempts: number;\n /** Попытки считаются в каждом разговоре заново; иначе — на человека. */\n perConversation: boolean;\n}\n\n/** Что делать с сообщением человека после конца разговора (→ В6): `reply` — агент отвечает по общей части, `silent` — молчит. */\nexport const FLOW_AFTER_END_MODES = [\"reply\", \"silent\"] as const;\nexport type FlowAfterEnd = (typeof FLOW_AFTER_END_MODES)[number];\n\n/** Сценарий поведения агента после `parseFlow`: все значения по умолчанию на месте. */\nexport interface AgentFlow {\n format: typeof AGENT_FLOW_FORMAT;\n version: typeof AGENT_FLOW_FORMAT_VERSION;\n id: string;\n name: string;\n /** Начальное состояние; `null` — не выбрано (ошибка проверки графа). */\n start: string | null;\n /** Общее для всех состояний: роль, тон, цены, условия, ссылки. */\n common: string;\n pace: FlowPace;\n clientCard: ClientCardField[];\n chatNotes: FlowField[];\n /** Имена инструментов приложения, которыми пользуется сценарий. */\n tools: string[];\n anyState: FlowAnyState;\n states: FlowState[];\n /** Места на доске по `id` состояния (и `ANY_STATE_LAYOUT_KEY`). Движок их не читает. */\n layout: Record<string, FlowPoint>;\n /** «Дни и время». Нет — сценарий без дней, как в версии 1. */\n schedule?: FlowSchedule;\n /**\n * Касания на весь сценарий без «Дней и времени» (0.50): нодам без своих касаний. Есть `schedule.nudges` — действуют\n * они. Нет — как в 0.49.\n */\n nudges?: FlowNudges;\n /** Попутные задачи. */\n sideTasks?: FlowSideTask[];\n /**\n * После конца разговора (→ В6). Нет — `reply`. Задан он или «Дни и время» — вход в конечную ноду закрывает разговор;\n * иначе, как в 0.48, конечная нода только сообщает `onFinish`.\n */\n afterEnd?: FlowAfterEnd;\n}\n\nexport interface FlowFormatError {\n /** Место в JSON: `states[0].exits[1].when.amount`. Пусто — весь документ. */\n path: string;\n message: string;\n}\n\nexport type ParseFlowResult = { ok: true; flow: AgentFlow } | { ok: false; errors: FlowFormatError[] };\n\n/** Что объявило приложение: по этим именам сценарий ссылается на инструменты, события и виджеты. */\nexport interface FlowCatalog {\n tools: readonly string[];\n /** Кнопки и события приложения: имя или `{ name, label }` — подпись видна на доске вместо имени. */\n events: readonly FlowCatalogEvent[];\n widgets: readonly string[];\n /** Словарь полей приложения: редактор предлагает их в карточке, заметках и попутных задачах. */\n fields?: readonly FlowCatalogField[];\n}\n\n/** Кнопка или событие приложения: просто имя или имя с подписью для доски («paid» → «Оплачено»). Объект — с 0.55. */\nexport type FlowCatalogEvent = string | { name: string; label?: string };\n\n/** Поле из словаря приложения. */\nexport interface FlowCatalogField {\n id: string;\n title: string;\n type: FlowFieldType;\n options?: readonly string[];\n}\n\n/** Ошибка не даёт запустить сценарий, замечание — подсказка автору. */\nexport type FlowIssueLevel = \"error\" | \"warning\";\n\n/** Находка `checkFlow`: одна и та же в редакторе и при загрузке сценария на сервере. */\nexport interface FlowIssue {\n level: FlowIssueLevel;\n /** Постоянный код находки, например `unreachable_state`. */\n code: string;\n message: string;\n /** Где показать: состояние, условие, поле, попутная задача. */\n place: { stateId?: string; exitId?: string; fieldId?: string; sideTaskId?: string };\n}\n","import { z } from \"zod\";\nimport {\n AGENT_FLOW_FORMAT,\n AGENT_FLOW_FORMAT_VERSION,\n DEFAULT_LATE_START_HOURS,\n DEFAULT_SIDE_TASK_MAX_ATTEMPTS,\n FLOW_AFTER_END_MODES,\n FLOW_DATA_OPS,\n FLOW_EVENT_TYPES,\n FLOW_FIELD_TYPES,\n FLOW_TIMER_SPANS,\n FLOW_TIMER_UNITS,\n type AgentFlow,\n} from \"./flow-format\";\n\n// Схема только про форму JSON. Пустой текст условия, условие без цели, сценарий без старта, ссылки на несуществующие\n// состояния — не ошибки формата: их показывает `checkFlow`, чтобы недописанный сценарий можно было сохранить.\n\nconst id = z.string().min(1);\nconst names = z.array(z.string()).default([]);\nconst clock = z.string().regex(/^([01]\\d|2[0-3]):[0-5]\\d$/, \"Время суток пишется как «ЧЧ:ММ», например «10:00».\");\n\nconst fieldShape = {\n id,\n name: z.string(),\n about: z.string().default(\"\"),\n type: z.enum(FLOW_FIELD_TYPES).default(\"text\"),\n options: names,\n};\n\nconst flowField = z.strictObject(fieldShape);\n\nconst clientCardField = z.strictObject({\n ...fieldShape,\n refreshAfterMonths: z.int().positive().nullable().default(null),\n});\n\nconst judgeCondition = z.strictObject({ type: z.literal(\"judge\"), text: z.string() });\n\nconst dataCondition = z\n .strictObject({\n type: z.literal(\"data\"),\n field: id,\n op: z.enum(FLOW_DATA_OPS).default(\"filled\"),\n value: z.union([z.string(), z.number(), z.boolean()]).optional(),\n })\n .superRefine((condition, context) => {\n if (condition.op !== \"filled\" && condition.value === undefined) {\n context.addIssue({ code: \"custom\", path: [\"value\"], message: \"Для сравнения нужно значение `value`.\" });\n }\n });\n\nconst eventCondition = z.strictObject({\n type: z.literal(\"event\"),\n event: z.enum(FLOW_EVENT_TYPES),\n name: z.string().optional(),\n});\n\nconst timerCondition = z.discriminatedUnion(\"from\", [\n z.strictObject({\n type: z.literal(\"timer\"),\n from: z.enum(FLOW_TIMER_SPANS),\n amount: z.number().positive(),\n unit: z.enum(FLOW_TIMER_UNITS),\n }),\n z.strictObject({ type: z.literal(\"timer\"), from: z.literal(\"time_of_day\"), at: clock }),\n // `days` < 1 — не ошибка формы: недописанный сценарий сохраняется, находку показывает `checkFlow`.\n z.strictObject({ type: z.literal(\"timer\"), from: z.literal(\"state_days\"), days: z.int() }),\n // Дробный и меньше 1 — тоже находка `checkFlow`.\n z.strictObject({ type: z.literal(\"timer\"), from: z.literal(\"program_day\"), day: z.number() }),\n]);\n\nconst duration = z.strictObject({ amount: z.number().positive(), unit: z.enum(FLOW_TIMER_UNITS) });\n\n// Пустой ряд касаний — не ошибка формы, а находка `checkFlow`.\nconst nudges = z.strictObject({\n afterSilence: z.array(duration),\n dailyAt: z.array(clock).optional(),\n giveUpAfter: duration.optional(),\n});\n\nconst schedule = z.strictObject({\n dayStart: clock,\n nightFrom: clock.optional(),\n lateStartHours: z.number().min(0).max(24).default(DEFAULT_LATE_START_HOURS),\n lengthDays: z.int().min(1).max(60).optional(),\n deadlineState: z.string().optional(),\n farewellOnDeadline: z.boolean().default(false),\n farewellText: z.string().optional(),\n firstMessages: z\n .strictObject({\n maxPerDay: z.int().min(0).optional(),\n maxPerDayByDay: z.array(z.int().min(0)).min(1).optional(),\n morning: z.boolean().optional(),\n skipMorningIfHumanWithinMin: z.int().min(0).optional(),\n })\n .optional(),\n nudges: nudges.optional(),\n dayFrame: z\n .strictObject({ softFrom: z.int().positive().optional(), hardAt: z.int().positive().optional(), hardText: z.string().optional() })\n .optional(),\n});\n\nconst sideTask = z.strictObject({\n id,\n text: z.string(),\n when: z.string().optional(),\n field: z.string().optional(),\n maxAttempts: z.int().positive().default(DEFAULT_SIDE_TASK_MAX_ATTEMPTS),\n perConversation: z.boolean().default(false),\n});\n\nconst flowCondition = z.discriminatedUnion(\"type\", [judgeCondition, dataCondition, eventCondition, timerCondition]);\n\nconst flowExit = z.strictObject({ id, when: flowCondition, to: z.string().nullable().default(null) });\nconst exits = z.array(flowExit).default([]);\n\nconst flowState = z.strictObject({\n id,\n kind: z.literal(\"state\").default(\"state\"),\n title: z.string().default(\"\"),\n instructions: z.string().default(\"\"),\n firstMessage: z.string().nullable().default(null),\n learn: names,\n noSideQuestions: z.boolean().default(false),\n tools: names,\n tags: names,\n exits,\n nudges: z.union([nudges.extend({ days: z.number().optional(), untilProgramDay: z.number().optional() }), z.literal(\"off\")]).optional(),\n});\n\nexport const DEFAULT_SIDE_QUESTION_EVERY_MESSAGES = 5;\n\n/** Схема сценария текущей версии формата. Вход — JSON без значений по умолчанию, выход — `AgentFlow`. */\nexport const agentFlowSchema = z\n .strictObject({\n $schema: z.string().optional(),\n format: z.literal(AGENT_FLOW_FORMAT),\n version: z.literal(AGENT_FLOW_FORMAT_VERSION),\n id,\n name: z.string(),\n start: z.string().nullable().default(null),\n common: z.string().default(\"\"),\n pace: z\n .strictObject({ sideQuestionEveryMessages: z.int().positive().default(DEFAULT_SIDE_QUESTION_EVERY_MESSAGES) })\n .default({ sideQuestionEveryMessages: DEFAULT_SIDE_QUESTION_EVERY_MESSAGES }),\n clientCard: z.array(clientCardField).default([]),\n chatNotes: z.array(flowField).default([]),\n tools: names,\n anyState: z.strictObject({ except: names, exits }).default({ except: [], exits: [] }),\n states: z.array(flowState),\n layout: z.record(z.string(), z.strictObject({ x: z.number(), y: z.number() })).default({}),\n schedule: schedule.optional(),\n nudges: nudges.optional(),\n sideTasks: z.array(sideTask).optional(),\n afterEnd: z.enum(FLOW_AFTER_END_MODES).optional(),\n })\n .transform(({ $schema: _schema, ...flow }) => flow);\n\n/** Выход схемы и `AgentFlow` описывают одно и то же: расхождение — ошибка сборки. */\ntype SchemaOutput = z.output<typeof agentFlowSchema>;\ntype Same<A, B> = [A] extends [B] ? ([B] extends [A] ? true : false) : false;\nconst schemaMatchesTypes: Same<SchemaOutput, AgentFlow> = true;\nvoid schemaMatchesTypes;\n","import { AGENT_FLOW_FORMAT_VERSION } from \"./flow-format\";\n\ntype FlowJson = Record<string, unknown>;\n\n/**\n * Шаги перевода сценария: ключ — версия, из которой шаг переводит в следующую.\n * Новая версия формата добавляет сюда шаг «N → N+1», старые сценарии продолжают открываться.\n */\nconst FORMAT_STEPS: Readonly<Record<number, (flow: FlowJson) => FlowJson>> = {\n // 1 → 2: новые поля («Дни и время», касания, «нода длится», «да/нет», попутные задачи) необязательные,\n // без них сценарий ведёт себя как в версии 1. Меняется только номер версии.\n 1: (flow) => flow,\n};\n\n/** Переводит JSON сценария из версии `from` в текущую. Вызывающий проверил, что `from` не новее текущей. */\nexport function migrateFlow(flow: FlowJson, from: number): FlowJson {\n let current = flow;\n for (let version = from; version < AGENT_FLOW_FORMAT_VERSION; version += 1) {\n const step = FORMAT_STEPS[version];\n if (!step) throw new Error(`Нет шага перевода формата сценария с версии ${version}.`);\n current = { ...step(current), version: version + 1 };\n }\n return current;\n}\n","import { z } from \"zod\";\nimport { AGENT_FLOW_FORMAT, AGENT_FLOW_FORMAT_VERSION, type FlowFormatError, type ParseFlowResult } from \"./flow-format\";\nimport { agentFlowSchema } from \"./flow-schema\";\nimport { migrateFlow } from \"./migrate-flow\";\n\nconst russianMessages = z.locales.ru().localeError;\n\nconst OTHERWISE_REMOVED =\n \"Условия «иначе» больше нет (поле `otherwise`): если ни одно условие не сработало, агент остаётся в состоянии. \" +\n \"Общее для всех состояний — цены, условия, тон — пишется в `common`.\";\n\n/**\n * Разбирает сценарий: объект или строку JSON. Старые версии формата переводит в текущую,\n * пропущенные значения дополняет. Проверяет только форму; связи между состояниями проверяет `checkFlow`.\n */\nexport function parseFlow(input: unknown): ParseFlowResult {\n let json = input;\n if (typeof input === \"string\") {\n try {\n json = JSON.parse(input);\n } catch (error) {\n return failure(\"\", `Это не JSON: ${(error as Error).message}`);\n }\n }\n if (typeof json !== \"object\" || json === null || Array.isArray(json)) {\n return failure(\"\", \"Сценарий — это объект JSON.\");\n }\n const raw = json as Record<string, unknown>;\n if (raw.format !== AGENT_FLOW_FORMAT) {\n return failure(\"format\", `Это не сценарий agent-flow: у сценария должно быть поле \"format\": \"${AGENT_FLOW_FORMAT}\".`);\n }\n const version = raw.version;\n if (typeof version !== \"number\" || !Number.isInteger(version) || version < 1) {\n return failure(\"version\", \"Номер версии формата (`version`) — целое число от 1.\");\n }\n if (version > AGENT_FLOW_FORMAT_VERSION) {\n return failure(\n \"version\",\n `Сценарий записан в версии формата ${version}, а этот SDK знает версии до ${AGENT_FLOW_FORMAT_VERSION}: обновите SDK.`,\n );\n }\n\n const parsed = agentFlowSchema.safeParse(migrateFlow(raw, version), { error: russianMessages });\n if (parsed.success) return { ok: true, flow: parsed.data };\n return { ok: false, errors: parsed.error.issues.flatMap(formatIssue) };\n}\n\nfunction formatIssue(issue: z.core.$ZodIssue): FlowFormatError[] {\n if (issue.code === \"unrecognized_keys\") {\n return issue.keys.map((key) => ({\n path: formatPath([...issue.path, key]),\n message: key === \"otherwise\" ? OTHERWISE_REMOVED : `Неизвестное поле «${key}».`,\n }));\n }\n if (issue.code === \"invalid_union\" && issue.discriminator) {\n // Варианты zod кладёт в ошибку, но в типе их нет.\n const options = (issue as { options?: readonly unknown[] }).options ?? [];\n const known = options.map((option) => `«${String(option)}»`).join(\", \");\n return [{ path: formatPath(issue.path), message: `Неизвестное значение поля «${issue.discriminator}». Можно: ${known}.` }];\n }\n return [{ path: formatPath(issue.path), message: issue.message }];\n}\n\nfunction formatPath(path: readonly PropertyKey[]): string {\n return path.reduce<string>((text, key) => {\n if (typeof key === \"number\") return `${text}[${key}]`;\n return text ? `${text}.${String(key)}` : String(key);\n }, \"\");\n}\n\nfunction failure(path: string, message: string): ParseFlowResult {\n return { ok: false, errors: [{ path, message }] };\n}\n","import type { FlowCatalog } from \"./flow-format\";\n\n/** Имена кнопок и событий приложения — каталог даёт их строками или объектами `{ name, label }`. */\nexport function catalogEventNames(catalog: Pick<FlowCatalog, \"events\">): string[] {\n return catalog.events.map((event) => (typeof event === \"string\" ? event : event.name));\n}\n\n/** Подпись события из каталога; нет каталога, события или подписи — `undefined`, и показывают имя. */\nexport function catalogEventLabel(catalog: Pick<FlowCatalog, \"events\"> | undefined, name: string): string | undefined {\n const found = catalog?.events.find((event) => typeof event !== \"string\" && event.name === name);\n return typeof found === \"object\" ? found.label?.trim() || undefined : undefined;\n}\n","import { DEFAULT_SIDE_QUESTION_EVERY_MESSAGES } from \"./flow-schema\";\nimport {\n DEFAULT_LATE_START_HOURS,\n DEFAULT_SIDE_TASK_MAX_ATTEMPTS,\n type AgentFlow,\n type FlowExit,\n type FlowField,\n type FlowSchedule,\n type FlowSideTask,\n type FlowState,\n} from \"./flow-format\";\n\ntype Json = Record<string, unknown>;\n\n/**\n * JSON сценария без значений по умолчанию — так его хранят и показывают в окне JSON.\n * `parseFlow(compactFlow(flow))` возвращает тот же сценарий.\n */\nexport function compactFlow(flow: AgentFlow): Json {\n return withoutEmpty({\n format: flow.format,\n version: flow.version,\n id: flow.id,\n name: flow.name,\n start: flow.start,\n common: flow.common,\n pace:\n flow.pace.sideQuestionEveryMessages === DEFAULT_SIDE_QUESTION_EVERY_MESSAGES\n ? undefined\n : { sideQuestionEveryMessages: flow.pace.sideQuestionEveryMessages },\n clientCard: flow.clientCard.map(compactField),\n chatNotes: flow.chatNotes.map(compactField),\n tools: flow.tools,\n anyState: flow.anyState.except.length || flow.anyState.exits.length\n ? withoutEmpty({ except: flow.anyState.except, exits: flow.anyState.exits.map(compactExit) })\n : undefined,\n states: flow.states.map(compactState),\n layout: Object.keys(flow.layout).length ? flow.layout : undefined,\n schedule: flow.schedule && compactSchedule(flow.schedule),\n nudges: flow.nudges,\n sideTasks: flow.sideTasks?.map(compactSideTask),\n afterEnd: flow.afterEnd,\n }, [\"states\"]);\n}\n\nfunction compactSchedule(schedule: FlowSchedule): Json {\n return withoutEmpty({\n ...schedule,\n lateStartHours: schedule.lateStartHours === DEFAULT_LATE_START_HOURS ? undefined : schedule.lateStartHours,\n farewellOnDeadline: schedule.farewellOnDeadline || undefined,\n });\n}\n\nfunction compactSideTask(task: FlowSideTask): Json {\n return withoutEmpty({\n ...task,\n maxAttempts: task.maxAttempts === DEFAULT_SIDE_TASK_MAX_ATTEMPTS ? undefined : task.maxAttempts,\n perConversation: task.perConversation || undefined,\n });\n}\n\nfunction compactField(field: FlowField): Json {\n return withoutEmpty({ ...field, type: field.type === \"text\" ? undefined : field.type });\n}\n\nfunction compactState(state: FlowState): Json {\n return withoutEmpty({\n ...state,\n kind: state.kind === \"state\" ? undefined : state.kind,\n noSideQuestions: state.noSideQuestions || undefined,\n exits: state.exits.map(compactExit),\n });\n}\n\nfunction compactExit(exit: FlowExit): Json {\n const when = exit.when.type === \"data\" && exit.when.op === \"filled\" ? { ...exit.when, op: undefined } : exit.when;\n return withoutEmpty({ id: exit.id, when: withoutEmpty(when as Json), to: exit.to });\n}\n\n/** Убирает `undefined`, `null`, пустые строки и пустые списки — кроме перечисленных ключей. */\nfunction withoutEmpty(object: Json, keep: readonly string[] = []): Json {\n return Object.fromEntries(\n Object.entries(object).filter(([key, value]) => {\n if (keep.includes(key)) return true;\n if (value === undefined || value === null || value === \"\") return false;\n return !(Array.isArray(value) && value.length === 0);\n }),\n );\n}\n","// Длительность словами — поле «своё время» тестового чата: «15 мин», «1 ч 30 мин», «2 дня», «1h 30m», «2 days».\n\nconst MINUTE_MS = 60_000;\nconst HOUR_MS = 60 * MINUTE_MS;\nconst DAY_MS = 24 * HOUR_MS;\n\n/** Единица по слову: русские и английские формы с сокращениями. */\nconst UNIT_MS: Record<string, number> = Object.fromEntries([\n ...[\"м\", \"мин\", \"минута\", \"минуты\", \"минут\", \"минуту\", \"m\", \"min\", \"mins\", \"minute\", \"minutes\"].map((word) => [word, MINUTE_MS]),\n ...[\"ч\", \"час\", \"часа\", \"часов\", \"h\", \"hr\", \"hrs\", \"hour\", \"hours\"].map((word) => [word, HOUR_MS]),\n ...[\"д\", \"дн\", \"день\", \"дня\", \"дней\", \"d\", \"day\", \"days\"].map((word) => [word, DAY_MS]),\n]);\n\n/** Число с единицей; между частями — пробелы, запятые, «и», «and». */\nconst PART = /\\s*(\\d+(?:[.,]\\d+)?)\\s*([a-zа-яё]+)\\.?\\s*(?:(?:,|и(?![a-zа-яё])|and(?![a-zа-яё]))\\s*)?/uy;\n\n/**\n * Длительность словами в мс: «15 мин» → 900 000, «1 ч 30 мин», «2 дня», «1h 30m», «2 days». Каждое число — со своей\n * единицей; непонятное, пустое или ноль — `undefined`.\n */\nexport function parseDuration(text: string): number | undefined {\n const input = text.trim().toLowerCase();\n if (!input) return undefined;\n PART.lastIndex = 0;\n let total = 0;\n while (PART.lastIndex < input.length) {\n const match = PART.exec(input);\n const unit = match ? UNIT_MS[match[2]!] : undefined;\n if (!match || unit === undefined) return undefined;\n total += Number(match[1]!.replace(\",\", \".\")) * unit;\n }\n return total > 0 ? Math.round(total) : undefined;\n}\n","/** Ключ в состоянии чата (`ChatState`), под которым лежит `FlowRun`. */\nexport const FLOW_STATE_KEY = \"flow\";\n\n/** Сколько последних шагов пути хранить в чате. */\nexport const FLOW_PATH_LIMIT = 50;\n\n/** Больше стольких переходов подряд без ответа агента — сценарий зациклился, движок останавливается. */\nexport const FLOW_CHAIN_LIMIT = 5;\n\n/** Кто решил переход: агент заявил и судья подтвердил, судья сам, данные, событие или таймер. */\nexport type TransitionDecider = \"claim\" | \"judge\" | \"data\" | \"event\" | \"timer\";\n\n/** Почему случился переход — словами для людей: «тишина 3 ч», «нода длится 1 день», «поле „Оплатил“ = да». */\nexport interface TransitionReason {\n kind: TransitionDecider;\n text: string;\n}\n\n/** Почему разговор закончился: конечная нода, срок вышел, человек пропал, канал заблокирован, своя причина приложения (`flow.end`). */\nexport type FlowEndReason = \"final\" | \"deadline\" | \"abandoned\" | \"blocked\" | (string & {});\n\n/** Как чат попал в состояние: старт сценария, переход или перевод на новую версию. */\nexport type FlowPathCause = TransitionDecider | \"start\" | \"migrate\";\n\nexport interface FlowPathEntry {\n state: string;\n /** Время входа, мс с 1970 года. */\n at: number;\n /** Метки состояния на момент входа. */\n tags: string[];\n from: string | null;\n exitId: string | null;\n decidedBy: FlowPathCause;\n /** Уверенность судьи, 0…1. */\n probability?: number;\n /** Причина перехода словами. В записях до 0.49 нет. */\n reason?: TransitionReason;\n}\n\n/** Где чат в сценарии. Хранится в состоянии чата под `FLOW_STATE_KEY`; все времена — мс с 1970 года. */\nexport interface FlowRun {\n state: string;\n /** Когда вошли в текущее состояние. */\n enteredAt: number;\n /** Когда чат начал сценарий. */\n startedAt: number;\n /** Последние `FLOW_PATH_LIMIT` шагов, первый — самый старый. */\n path: FlowPathEntry[];\n /** Остановленные часы «время в состоянии» основных состояний, пока чат в напоминаниях: id состояния → накоплено мс. */\n pausedClocks: Record<string, number>;\n /** Заметки этого чата по `id` поля `chatNotes`. */\n notes: Record<string, unknown>;\n humanMessages: number;\n /** Ответ агента, к которому записано место чата. У симуляции редактора нет. */\n answerId?: string;\n /**\n * Ответ агента, на котором вошли в текущее состояние, с 0.62: судья после хода смотрит реплики с него. Нет — переходов\n * ещё не было, место записано раньше или это симуляция: судья видит последние реплики.\n */\n enteredAfterAnswer?: string;\n agentAnswers: number;\n /** На каком сообщении человека (`humanMessages`) был последний вопрос между делом. */\n sideQuestionAt: number | null;\n /** Последний переход, который судья не подтвердил: заявлять его снова можно после нового сообщения человека. */\n lastRejected: { exitId: string; atHumanMessages: number } | null;\n lastAgentAt: number | null;\n lastHumanAt: number | null;\n /** Переходов подряд без ответа агента; предел — `FLOW_CHAIN_LIMIT`. */\n chain: number;\n /** Сдвиг часов для тестового чата, мс. В рабочих чатах нет. */\n timeOffset?: number;\n // Поля 0.49 — только у сценариев с «Днями и временем», касаниями или концом разговора. Записи 0.48 их не имеют.\n /** Начало первого дня сценария (с учётом позднего старта и пояса человека). */\n dayAnchorAt?: number;\n /** Сообщения человека за текущий день сценария: местная дата «ГГГГ-ММ-ДД» → сколько. Хранится только текущий день. */\n dayCounts?: Record<string, number>;\n /** Какой шаг ряда касаний следующий; сообщение человека возвращает к 0. */\n nudgeStep?: number;\n /** `nudgeStep` насчитан своим рядом ноды на N дней (`nudges.days`): после них общий ряд начинается сначала. С 0.55. */\n nudgeStepOwn?: boolean;\n /** Ходов сервера подряд (по служебным сообщениям) после последнего сообщения человека, с 0.53; нет — 0. */\n serverTurns?: number;\n /** Последний ход «пишет первым», после которого человек не писал, и счёт до него: не доставлен — не засчитан (FR-309). */\n touch?: FlowTouch;\n /** Когда разговор закончился. После конца таймеров и касаний нет. */\n endedAt?: number;\n endReason?: FlowEndReason;\n}\n\n/** Ход «пишет первым» и что было до него. Ответ хода помечен «не доставлено» — счёт возвращается к этому. */\nexport interface FlowTouch {\n /** Ответ агента этого хода. */\n answerId: string;\n /** Когда ход был, по часам чата: от него считается следующий срок, если касание не дошло. */\n at: number;\n lastAgentAt: number | null;\n nudgeStep: number;\n nudgeStepOwn?: boolean;\n agentAnswers: number;\n}\n\n/** Переход, который движок решил сделать. */\nexport interface Transition {\n from: string;\n /** Новое состояние; при «назад» — уже найденное основное состояние. */\n to: string;\n exitId: string;\n decidedBy: TransitionDecider;\n probability?: number;\n /** Метки состояния `to`. */\n tags: string[];\n at: number;\n /** Переход «назад» (`@return`). */\n returned?: boolean;\n /** Причина словами: уходит в `onTransition` и в путь. */\n reason?: TransitionReason;\n}\n\n/** Тихие часы и потолок сообщений, которые агент пишет первым (по таймерам). */\nexport interface FirstMessagesRules {\n /** Ночью не писать: «ЧЧ:ММ» в поясе человека. Срок переносится на конец тихих часов. */\n quietHours: { from: string; to: string };\n /** Не больше стольких сообщений первым за сутки человека. */\n maxPerDay: number;\n /**\n * Своя проверка приложения: например, человек отписался или остановлены расходы. `true` — писать. `false` — не сейчас:\n * касание повторится через час. `\"never\"` — молчать до сообщения человека. `{ retryAt }` — повторить в этот момент\n * (негодная дата — как `false`, прошедшая — через минуту). Конец разговора («срок вышел», «не завершил») и переходы нод\n * по таймерам от ответа не зависят: наступают в свой срок.\n */\n canWriteNow?: (input: { ownerId: string; chatId: string; at: Date }) => CanWriteNow | Promise<CanWriteNow>;\n}\n\n/** Ответ `canWriteNow`: писать, не сейчас (повтор через час), молчать до сообщения человека или повторить в названный момент (с 0.53). */\nexport type CanWriteNow = boolean | \"never\" | { retryAt: Date };\n\n/** `false` — правила выключены: агент пишет первым без тихих часов и потолка. Не писать первым — `canWriteNow: () => \"never\"`. */\nexport type FirstMessagesSetting = Partial<FirstMessagesRules> | false;\n\nexport const DEFAULT_FIRST_MESSAGES: Readonly<Omit<FirstMessagesRules, \"canWriteNow\">> = {\n quietHours: { from: \"21:00\", to: \"09:00\" },\n maxPerDay: 3,\n};\n","import { RETURN_TARGET, type AgentFlow, type ClientCardField, type FlowExit, type FlowField, type FlowState } from \"../format/flow-format\";\n\n// Что движок и проверка графа читают из сценария: состояния, их виды и условия, которые сейчас действуют.\n\nexport function stateById(flow: AgentFlow, id: string | null): FlowState | undefined {\n return id === null ? undefined : flow.states.find((state) => state.id === id);\n}\n\n/** Конечное состояние: условий выхода нет. */\nexport function isFinal(state: FlowState): boolean {\n return state.exits.length === 0;\n}\n\n/** Касание — состояние с переходом «назад» («Напоминание», «Утреннее касание»). Остальные — основные. */\nexport function isTouch(state: FlowState): boolean {\n return state.exits.some((exit) => exit.to === RETURN_TARGET);\n}\n\n/** Общие переходы действуют везде, кроме конечных и исключённых состояний. */\nexport function commonApplies(flow: AgentFlow, state: FlowState): boolean {\n return !isFinal(state) && !flow.anyState.except.includes(state.id);\n}\n\nexport interface ActiveExit {\n exit: FlowExit;\n /** Условие самого состояния, а не общее. */\n own: boolean;\n}\n\n/** Условия, которые действуют в состоянии, в порядке проверки: свои, потом общие. Общий переход в то же состояние не действует. */\nexport function activeExits(flow: AgentFlow, state: FlowState): ActiveExit[] {\n const own = state.exits.map((exit) => ({ exit, own: true }));\n if (!commonApplies(flow, state)) return own;\n const common = flow.anyState.exits.filter((exit) => exit.to !== state.id).map((exit) => ({ exit, own: false }));\n return [...own, ...common];\n}\n\nexport type FieldPlace = { field: ClientCardField; place: \"card\" } | { field: FlowField; place: \"notes\" };\n\n/** Поле по `id`: карточка клиента или заметка чата. */\nexport function fieldById(flow: AgentFlow, id: string): FieldPlace | undefined {\n const card = flow.clientCard.find((field) => field.id === id);\n if (card) return { field: card, place: \"card\" };\n const note = flow.chatNotes.find((field) => field.id === id);\n return note ? { field: note, place: \"notes\" } : undefined;\n}\n\n/** Строки сравниваются без учёта регистра и пробелов по краям: «Да» и «да» — одно. */\nexport function sameText(left: string, right: string): boolean {\n return left.trim().toLocaleLowerCase() === right.trim().toLocaleLowerCase();\n}\n","import { FLOW_OPS_BY_FIELD_TYPE, type DataCondition, type FlowField, type FlowFieldType } from \"../format/flow-format\";\nimport { sameText } from \"./flow-graph\";\n\n/** Значение подходит типу поля: непустая строка для текста и выбора, конечное число для числа, `true`/`false` для «да/нет». */\nfunction fitsType(type: FlowFieldType, value: unknown): boolean {\n if (type === \"number\") return typeof value === \"number\" && Number.isFinite(value);\n if (type === \"boolean\") return typeof value === \"boolean\";\n return typeof value === \"string\" && value.trim() !== \"\";\n}\n\nconst YES_WORDS = new Set([\"да\", \"yes\", \"true\"]);\nconst NO_WORDS = new Set([\"нет\", \"no\", \"false\"]);\n\n/**\n * Ответ на вопрос «да/нет»: слово «да»/«нет» (также yes/no/true/false, любой регистр, точка или «!» в конце) или готовое\n * логическое значение. Ничего другого ответом не считается — «может быть» не записывается ни как да, ни как нет.\n */\nexport function parseBooleanAnswer(raw: unknown): boolean | undefined {\n if (typeof raw === \"boolean\") return raw;\n if (typeof raw !== \"string\") return undefined;\n const word = raw.trim().toLocaleLowerCase().replace(/[.!\\s]+$/u, \"\");\n if (YES_WORDS.has(word)) return true;\n return NO_WORDS.has(word) ? false : undefined;\n}\n\n/** Значение известно и подходит полю: по типу, а у выбора — ещё и по вариантам. Не подходит — считается неизвестным. */\nexport function fieldValueFits(field: Pick<FlowField, \"type\" | \"options\">, value: unknown): boolean {\n if (!fitsType(field.type, value)) return false;\n if (field.type !== \"choice\" || field.options.length === 0) return true;\n return field.options.some((option) => sameText(option, value as string));\n}\n\n/** Выполнено ли условие по данным: `filled` / `eq` / `ne` / `gt` / `lt` / `contains` по типу поля. */\nexport function dataConditionHolds(condition: DataCondition, fieldType: FlowFieldType, value: unknown): boolean {\n if (!FLOW_OPS_BY_FIELD_TYPE[fieldType].includes(condition.op)) return false;\n if (!fitsType(fieldType, value)) return false;\n const expected = condition.value;\n switch (condition.op) {\n case \"filled\":\n return true;\n case \"eq\":\n if (fieldType === \"number\" || fieldType === \"boolean\") return value === expected;\n return typeof expected === \"string\" && sameText(value as string, expected);\n case \"ne\":\n return typeof expected === \"boolean\" && value !== expected;\n case \"gt\":\n return typeof expected === \"number\" && (value as number) > expected;\n case \"lt\":\n return typeof expected === \"number\" && (value as number) < expected;\n case \"contains\":\n return (\n typeof expected === \"string\" &&\n expected.trim() !== \"\" &&\n (value as string).toLocaleLowerCase().includes(expected.trim().toLocaleLowerCase())\n );\n }\n}\n","import { RETURN_TARGET, type AgentFlow, type FlowState } from \"../format/flow-format\";\nimport type { FlowRun } from \"./flow-run\";\nimport { isTouch, stateById } from \"./flow-graph\";\n\n/** Куда ведёт «назад»: последнее в пути основное состояние, касания пропускаются. Такого нет — старт (→ В1). */\nexport function returnTarget(flow: AgentFlow, run: FlowRun): FlowState | undefined {\n for (let index = run.path.length - 1; index >= 0; index -= 1) {\n const id = run.path[index]!.state;\n if (id === run.state) continue;\n const state = stateById(flow, id);\n if (state && !isTouch(state)) return state;\n }\n return stateById(flow, flow.start);\n}\n\n/** Состояние, в которое ведёт условие, или `undefined`: цели нет, она удалена или «назад» ведёт туда же, где чат. */\nexport function exitTarget(flow: AgentFlow, run: FlowRun, to: string | null): { state: FlowState; returned: boolean } | undefined {\n if (to === null) return undefined;\n if (to !== RETURN_TARGET) {\n const state = stateById(flow, to);\n return state ? { state, returned: false } : undefined;\n }\n const state = returnTarget(flow, run);\n return state && state.id !== run.state ? { state, returned: true } : undefined;\n}\n","// Время на часах человека без сторонних библиотек: дата и часы в его поясе и обратно — в миллисекунды.\n\nexport interface ZonedDate {\n year: number;\n /** 1…12 */\n month: number;\n day: number;\n}\n\nexport interface ZonedParts extends ZonedDate {\n hour: number;\n minute: number;\n second: number;\n}\n\nconst formatters = new Map<string, Intl.DateTimeFormat>();\n\nfunction formatterFor(timeZone: string): Intl.DateTimeFormat {\n let formatter = formatters.get(timeZone);\n if (!formatter) {\n const options: Intl.DateTimeFormatOptions = {\n year: \"numeric\",\n month: \"numeric\",\n day: \"numeric\",\n hour: \"numeric\",\n minute: \"numeric\",\n second: \"numeric\",\n hourCycle: \"h23\",\n };\n try {\n formatter = new Intl.DateTimeFormat(\"en-US\", { ...options, timeZone });\n } catch {\n // Неизвестный пояс: считаем по UTC. Предупредить о нём — дело сервера, движок чистый.\n formatter = new Intl.DateTimeFormat(\"en-US\", { ...options, timeZone: \"UTC\" });\n }\n formatters.set(timeZone, formatter);\n }\n return formatter;\n}\n\n/** Дата и часы на часах человека в момент `at`. */\nexport function zonedParts(at: number, timeZone: string): ZonedParts {\n const parts: Record<string, number> = {};\n for (const part of formatterFor(timeZone).formatToParts(at)) {\n if (part.type !== \"literal\") parts[part.type] = Number(part.value);\n }\n return {\n year: parts.year!,\n month: parts.month!,\n day: parts.day!,\n hour: parts.hour! % 24,\n minute: parts.minute!,\n second: parts.second!,\n };\n}\n\n/** На сколько мс часы пояса впереди UTC в момент `at`. */\nfunction offsetAt(at: number, timeZone: string): number {\n const parts = zonedParts(at, timeZone);\n const wall = Date.UTC(parts.year, parts.month - 1, parts.day, parts.hour, parts.minute, parts.second);\n return wall - Math.floor(at / 1000) * 1000;\n}\n\n/** Момент, когда на часах человека будет `date` и `minutes` минут от полуночи. */\nexport function zonedTime(date: ZonedDate, minutes: number, timeZone: string): number {\n const wall = Date.UTC(date.year, date.month - 1, date.day, 0, minutes);\n const first = wall - offsetAt(wall, timeZone);\n const second = wall - offsetAt(first, timeZone);\n return second;\n}\n\n/** Следующий календарный день. */\nexport function nextDate(date: ZonedDate, days = 1): ZonedDate {\n const moved = new Date(Date.UTC(date.year, date.month - 1, date.day + days));\n return { year: moved.getUTCFullYear(), month: moved.getUTCMonth() + 1, day: moved.getUTCDate() };\n}\n\n/** «ЧЧ:ММ» → минуты от полуночи; не то — `null`. */\nexport function parseClock(clock: string): number | null {\n const match = /^([01]\\d|2[0-3]):([0-5]\\d)$/.exec(clock);\n return match ? Number(match[1]) * 60 + Number(match[2]) : null;\n}\n\n/** Минуты от полуночи на часах человека. */\nexport function clockMinutes(at: number, timeZone: string): number {\n const parts = zonedParts(at, timeZone);\n return parts.hour * 60 + parts.minute;\n}\n\n/** Первый момент строго после `after`, когда на часах человека `minutes` минут от полуночи. */\nexport function nextClockTime(after: number, minutes: number, timeZone: string): number {\n let date: ZonedDate = zonedParts(after, timeZone);\n for (let attempt = 0; attempt < 3; attempt += 1) {\n const candidate = zonedTime(date, minutes, timeZone);\n if (candidate > after) return candidate;\n date = nextDate(date);\n }\n return zonedTime(date, minutes, timeZone);\n}\n\n/** Начало следующих суток на часах человека. */\nexport function startOfNextDay(at: number, timeZone: string): number {\n return zonedTime(nextDate(zonedParts(at, timeZone)), 0, timeZone);\n}\n\n/** Сутки человека: «ГГГГ-ММ-ДД» в его поясе. */\nexport function localDay(at: number, timeZone: string): string {\n const { year, month, day } = zonedParts(at, timeZone);\n return `${year}-${String(month).padStart(2, \"0\")}-${String(day).padStart(2, \"0\")}`;\n}\n","import { DEFAULT_LATE_START_HOURS, type FlowSchedule } from \"../format/flow-format\";\nimport { DEFAULT_FIRST_MESSAGES, type FlowRun } from \"./flow-run\";\nimport { clockMinutes, localDay, nextDate, parseClock, zonedParts, zonedTime, type ZonedDate } from \"./zoned-time\";\n\n// Этап 4 сценариев: дни сценария по поясу человека. Чистые функции на `zoned-time.ts`, по plan.md, «Время и дни».\n// День сценария длится от `dayStart` до `dayStart` следующих суток: ночь — ещё вчерашний день, нода «во сне» не проходит.\n\n/** День сценария для хвоста шага, `readRun` и событий. Моменты — мс с 1970 года. */\nexport interface FlowDayInfo {\n /** Номер дня, с 1. 0 — вечер позднего старта до первого дня (→ В1). */\n day: number;\n /** Сколько дней в сценарии (`schedule.lengthDays`); нет срока — нет поля. */\n totalDays?: number;\n isLastDay: boolean;\n dayStartedAt: number;\n nextDayStartAt: number;\n}\n\nconst DAY_MINUTES = 24 * 60;\nconst DAY_MS = 86_400_000;\n\nconst dayStartMinutes = (schedule: FlowSchedule) => parseClock(schedule.dayStart) ?? 0;\nconst nightMinutes = (schedule: FlowSchedule) => parseClock(schedule.nightFrom ?? DEFAULT_FIRST_MESSAGES.quietHours.from) ?? 0;\n\nconst dateKey = ({ year, month, day }: ZonedDate) => `${year}-${String(month).padStart(2, \"0\")}-${String(day).padStart(2, \"0\")}`;\nconst dateOf = (key: string): ZonedDate => {\n const [year, month, day] = key.split(\"-\").map(Number);\n return { year: year!, month: month!, day: day! };\n};\nconst shiftDate = (key: string, days: number) => dateKey(nextDate(dateOf(key), days));\n/** Сколько суток от `from` до `to`, обе — «ГГГГ-ММ-ДД». */\nconst daysBetween = (from: string, to: string) => {\n const [a, b] = [dateOf(from), dateOf(to)];\n return Math.round((Date.UTC(b.year, b.month - 1, b.day) - Date.UTC(a.year, a.month - 1, a.day)) / DAY_MS);\n};\nconst later = (a: string, b: string) => (a > b ? a : b);\n\n/** Ночь начинается вечером (а не после полуночи) — тогда вечер после её начала относится к завтрашнему дню. */\nconst eveningNight = (schedule: FlowSchedule) => nightMinutes(schedule) > dayStartMinutes(schedule);\n\n/** Местная дата дня сценария (`ГГГГ-ММ-ДД`): ночь и время до начала дня относятся к ближайшему утру. */\nexport function dayOf(at: number, timeZone: string, schedule: FlowSchedule): string {\n const today = localDay(at, timeZone);\n return eveningNight(schedule) && clockMinutes(at, timeZone) >= nightMinutes(schedule) ? shiftDate(today, 1) : today;\n}\n\n/** Какой день сценария идёт в момент `at`: последний наступивший `dayStart`. Ключ `dayCounts` и номера дня. */\nexport function dayInProgress(at: number, timeZone: string, schedule: FlowSchedule): string {\n const today = localDay(at, timeZone);\n return clockMinutes(at, timeZone) < dayStartMinutes(schedule) ? shiftDate(today, -1) : today;\n}\n\n/** Момент начала дня `localDate` в поясе (переход часов учтён). */\nexport function dayStartAt(localDate: string, timeZone: string, schedule: FlowSchedule): number {\n return zonedTime(dateOf(localDate), dayStartMinutes(schedule), timeZone);\n}\n\n/** Начало дня сценария, следующего за днём, к которому идёт момент `at` (ночь до начала дня — ещё прошлый день). */\nexport function nextDayStartAfter(at: number, timeZone: string, schedule: FlowSchedule): number {\n return dayStartAt(shiftDate(dayInProgress(at, timeZone, schedule), 1), timeZone, schedule);\n}\n\n/** Первый день сценария по моменту старта: день старта, а если до ночи осталось меньше порога — завтра (→ В1). */\nfunction firstDayOf(startedAt: number, timeZone: string, schedule: FlowSchedule): string {\n const first = dayOf(startedAt, timeZone, schedule);\n const threshold = (schedule.lateStartHours ?? DEFAULT_LATE_START_HOURS) * 60;\n const clock = clockMinutes(startedAt, timeZone);\n if (threshold <= 0 || clock < dayStartMinutes(schedule) || first !== localDay(startedAt, timeZone)) return first;\n const untilNight = (nightMinutes(schedule) - clock + DAY_MINUTES) % DAY_MINUTES;\n return untilNight < threshold ? shiftDate(first, 1) : first;\n}\n\n/** Когда человек последний раз был в разговоре. */\nconst lastActivity = (run: FlowRun) => Math.max(run.startedAt, run.enteredAt, run.lastHumanAt ?? 0, run.lastAgentAt ?? 0);\n\n/**\n * Начало первого дня в поясе человека. Записанный якорь в том же поясе — как есть. Пояс сменился (FR-207): если разговор\n * ещё в первом дне — первый день считается заново по новому поясу, позже — номер дня сохраняется, а сроки идут по новым часам.\n */\nexport function dayAnchor(run: FlowRun, timeZone: string, schedule: FlowSchedule): number {\n const fresh = () => dayStartAt(firstDayOf(run.startedAt, timeZone, schedule), timeZone, schedule);\n const stored = run.dayAnchorAt;\n if (stored === undefined) return fresh();\n if (clockMinutes(stored, timeZone) === dayStartMinutes(schedule)) return stored;\n // Ближайшее к прежнему якорю начало дня в новом поясе.\n const around = localDay(stored, timeZone);\n const moved = [-1, 0, 1]\n .map((shift) => dayStartAt(shiftDate(around, shift), timeZone, schedule))\n .reduce((best, candidate) => (Math.abs(candidate - stored) < Math.abs(best - stored) ? candidate : best));\n const dayNow = daysBetween(localDay(moved, timeZone), dayInProgress(lastActivity(run), timeZone, schedule)) + 1;\n return dayNow <= 1 ? fresh() : moved;\n}\n\nconst anchorDate = (run: FlowRun, timeZone: string, schedule: FlowSchedule) => localDay(dayAnchor(run, timeZone, schedule), timeZone);\n\n/** Срок таймера «нода длится N дней»: начало дня входа в ноду + N. Вход до первого дня — как вход в первый день. */\nexport function stateDaysDue(run: FlowRun, days: number, timeZone: string, schedule: FlowSchedule): number {\n const entered = later(dayOf(run.enteredAt, timeZone, schedule), anchorDate(run, timeZone, schedule));\n return dayStartAt(shiftDate(entered, days), timeZone, schedule);\n}\n\n/** Срок таймера «наступил день N сценария»: начало дня N от якоря первого дня. Уже наступил — срок в прошлом. */\nexport function programDayDue(run: FlowRun, day: number, timeZone: string, schedule: FlowSchedule): number {\n return dayStartAt(shiftDate(anchorDate(run, timeZone, schedule), day - 1), timeZone, schedule);\n}\n\n/** День сценария сейчас. Якорь — `dayAnchor`; порог позднего старта — `schedule.lateStartHours` (→ В1). */\nexport function flowDay(run: FlowRun, now: number, timeZone: string, schedule: FlowSchedule): FlowDayInfo {\n const first = anchorDate(run, timeZone, schedule);\n const current = later(dayInProgress(now, timeZone, schedule), shiftDate(first, -1));\n const day = Math.max(0, daysBetween(first, current) + 1);\n const today = day === 0 ? shiftDate(first, -1) : current;\n return {\n day,\n ...(schedule.lengthDays !== undefined && { totalDays: schedule.lengthDays }),\n isLastDay: schedule.lengthDays !== undefined && day === schedule.lengthDays,\n dayStartedAt: dayStartAt(today, timeZone, schedule),\n nextDayStartAt: dayStartAt(shiftDate(today, 1), timeZone, schedule),\n };\n}\n\n/** «Срок вышел»: начало дня `lengthDays + 1`. Срока нет — `null`. */\nexport function deadlineAt(run: FlowRun, timeZone: string, schedule: FlowSchedule): number | null {\n if (schedule.lengthDays === undefined) return null;\n return dayStartAt(shiftDate(anchorDate(run, timeZone, schedule), schedule.lengthDays), timeZone, schedule);\n}\n\n/** Идёт первый день сценария (или вечер перед ним) и первая ночь ещё не наступила: окно, чтобы узнать город (→ В1). */\nexport function beforeFirstNight(run: FlowRun, now: number, timeZone: string, schedule: FlowSchedule): boolean {\n const first = anchorDate(run, timeZone, schedule);\n const nightDate = eveningNight(schedule) ? first : shiftDate(first, 1);\n return now < zonedTime(dateOf(nightDate), nightMinutes(schedule), timeZone);\n}\n\n/** Тот же `run` с якорем первого дня в поясе человека: записать в состояние чата. Без «Дней и времени» — как есть. */\nexport function withDayAnchor(run: FlowRun, timeZone: string, schedule: FlowSchedule | undefined): FlowRun {\n if (!schedule) return run;\n const dayAnchorAt = dayAnchor(run, timeZone, schedule);\n return run.dayAnchorAt === dayAnchorAt ? run : { ...run, dayAnchorAt };\n}\n\n/** Местные часы человека «ЧЧ:ММ». */\nexport function clockText(at: number, timeZone: string): string {\n const { hour, minute } = zonedParts(at, timeZone);\n return `${String(hour).padStart(2, \"0\")}:${String(minute).padStart(2, \"0\")}`;\n}\n","import type { AgentFlow, FlowDuration, FlowNudges, FlowSchedule } from \"../format/flow-format\";\nimport type { FlowRun } from \"./flow-run\";\nimport { stateById } from \"./flow-graph\";\nimport { flowDay, programDayDue } from \"./flow-days\";\nimport { nextClockTime, parseClock } from \"./zoned-time\";\n\n// Этап 7 сценариев: касания — ход агента в той же ноде, по plan.md, «Касания и „пишет первым“».\n\n/** Почему агент пишет первым. Причины одного срока собираются в один ход. */\nexport type FlowFirstReason =\n /** Переход по таймеру в новую ноду. */\n | { kind: \"transition\"; stateId: string }\n /** Утреннее сообщение (`schedule.firstMessages.morning`). */\n | { kind: \"morning\" }\n /** Касание по тишине: номер шага ряда `afterSilence`, с 1. */\n | { kind: \"silence\"; step: number }\n /** Касание по часам (`dailyAt`). */\n | { kind: \"daily\"; at: string }\n /** Сообщения человека остались без ответа (после жёсткой рамки дня, при лимите расходов) — ответить на накопленное. */\n | { kind: \"night_messages\"; count: number }\n /** Прощание при «срок вышел» (`schedule.farewellOnDeadline`, → В5). */\n | { kind: \"farewell\" };\n\n/** Ближайшее касание; `give_up` — конец разговора «не завершил» без сообщения. */\nexport interface NudgeDue {\n at: number;\n reason: FlowFirstReason | { kind: \"give_up\" };\n /** Касание своего ряда ноды, ограниченного днями (`nudges.days`, `nudges.untilProgramDay`): его шаг не идёт в счёт общего ряда. */\n own?: boolean;\n}\n\n/** Касания ноды: свои, «off», общие из «Дней и времени», общие сценария. Нет ни тех, ни других — `null`. */\nexport function stateNudges(flow: AgentFlow, stateId: string): FlowNudges | null {\n const own = stateById(flow, stateId)?.nudges;\n if (own === \"off\") return null;\n return own ?? flow.schedule?.nudges ?? flow.nudges ?? null;\n}\n\n/** Без «Дней и времени» дни своего ряда — календарные, по поясу человека. */\nconst CALENDAR_DAYS: FlowSchedule = { dayStart: \"00:00\", lateStartHours: 0, farewellOnDeadline: false };\n\n/** Ряд касаний ноды и, если свой ряд ограничен днями, момент их конца и общий ряд после. */\ninterface NudgeRings {\n ring: FlowNudges;\n /** Начало дня, с которого свой ряд уступает общему; нет — ряд на всё время в ноде. */\n until?: number;\n after?: FlowNudges | null;\n}\n\nfunction nudgeRings(flow: AgentFlow, run: FlowRun, timeZone: string): NudgeRings | null {\n const own = stateById(flow, run.state)?.nudges;\n if (own === \"off\") return null;\n const common = flow.schedule?.nudges ?? flow.nudges ?? null;\n if (!own) return common && { ring: common };\n if (own.days === undefined && own.untilProgramDay === undefined) return { ring: own };\n const schedule = flow.schedule ?? CALENDAR_DAYS;\n const ends: number[] = [];\n if (own.days !== undefined) ends.push(programDayDue(run, flowDay(run, run.enteredAt, timeZone, schedule).day + own.days, timeZone, schedule));\n // До N-го дня программы: человек дошёл до ноды позже — конец уже прошёл, сразу общий ряд.\n if (own.untilProgramDay !== undefined) ends.push(programDayDue(run, own.untilProgramDay + 1, timeZone, schedule));\n return { ring: own, until: Math.min(...ends), after: common };\n}\n\nconst UNIT_MS = { min: 60_000, h: 3_600_000, d: 86_400_000 } as const;\nconst durationMs = (duration: FlowDuration) => duration.amount * UNIT_MS[duration.unit];\n\n/** Порог утреннего по умолчанию: человек писал за 3 ч до него — утреннее завтра. */\nexport const DEFAULT_SKIP_MORNING_MIN = 180;\n\n/** То, чего нет в месте чата: пауза сотрудника из записи и сообщения человека без ответа из истории. */\nexport interface FirstWakeContext {\n /** Пауза сотрудника до этого момента (мс): тишина считается от её конца, утро на паузе пропускается. */\n pausedUntil?: number | null;\n /** Сообщения человека после последнего ответа агента, записанные без хода (ночь, рамка дня, пауза). */\n unanswered?: number;\n /** Последнее касание не доставлено (мс): оно не засчитано, а следующий срок — не раньше этого момента. */\n undeliveredAt?: number | null;\n}\n\n/**\n * Ближайшее касание чата: ряд `afterSilence` от последнего ответа агента, после ряда — часы `dailyAt`. `give_up`\n * («не завершил») — `giveUpAfter` тишины человека; побеждает, если наступает не позже касания. Касаний в ноде нет,\n * человек ответил или писал без ответа, агент ещё не писал, разговор закончен — `null`.\n */\nexport function nextNudge(flow: AgentFlow, run: FlowRun, now: number, timeZone: string, context: FirstWakeContext = {}): NudgeDue | null {\n const rings = nudgesRunning(flow, run, timeZone, context);\n if (!rings || run.lastAgentAt === null) return null;\n // Ответ сотрудника — слова агента (FR-507): тишина идёт от конца паузы.\n const base = Math.max(run.lastAgentAt, context.pausedUntil ?? 0, context.undeliveredAt ?? 0);\n const step = run.nudgeStep ?? 0;\n let nudge: NudgeDue | null = null;\n if (rings.until === undefined) nudge = ringNudge(rings.ring, base, step, timeZone);\n else {\n // Свой ряд — в свои дни; потом общий ряд с начала, тишина — не раньше начала того дня.\n const own = base < rings.until ? ringNudge(rings.ring, base, step, timeZone) : null;\n if (own && own.at < rings.until) nudge = { ...own, own: true };\n else if (rings.after) nudge = ringNudge(rings.after, Math.max(base, rings.until), run.nudgeStepOwn || base < rings.until ? 0 : step, timeZone);\n }\n const giveUp = giveUpAt(flow, run, timeZone, context);\n // Сервер стоял дольше тишины: пропущенное касание уже не к месту — разговор кончается.\n if (giveUp !== null && (!nudge || giveUp <= nudge.at || giveUp <= now)) return { at: giveUp, reason: { kind: \"give_up\" } };\n return nudge;\n}\n\n/** Шаг ряда `step` от `base`: срок тишины, а после ряда — ближайшие часы `dailyAt`. Ряд кончился — `null`. */\nfunction ringNudge(ring: FlowNudges, base: number, step: number, timeZone: string): NudgeDue | null {\n const silence = ring.afterSilence[step];\n if (silence) return { at: base + durationMs(silence), reason: { kind: \"silence\", step: step + 1 } };\n let nudge: NudgeDue | null = null;\n for (const clock of ring.dailyAt ?? []) {\n const minutes = parseClock(clock);\n if (minutes === null) continue;\n const at = nextClockTime(base, minutes, timeZone);\n if (!nudge || at < nudge.at) nudge = { at, reason: { kind: \"daily\", at: clock } };\n }\n return nudge;\n}\n\n/** Касания ноды идут: они есть, разговор не кончен, агент писал последним и сообщений без ответа нет. */\nfunction nudgesRunning(flow: AgentFlow, run: FlowRun, timeZone: string, context: FirstWakeContext): NudgeRings | null {\n const rings = nudgeRings(flow, run, timeZone);\n if (!rings || run.endedAt !== undefined || run.lastAgentAt === null) return null;\n if ((run.lastHumanAt !== null && run.lastHumanAt > run.lastAgentAt) || (context.unanswered ?? 0) > 0) return null;\n return rings;\n}\n\n/**\n * Когда наступит «не завершил» (`giveUpAfter` тишины человека), независимо от касаний: отложенное или не начатое\n * касание конец разговора не двигает. Нет `giveUpAfter` или тишина не идёт — `null`.\n */\nexport function giveUpAt(flow: AgentFlow, run: FlowRun, timeZone: string, context: FirstWakeContext = {}): number | null {\n const rings = nudgesRunning(flow, run, timeZone, context);\n // Свой ряд на N дней без своего «не завершил» — общий: тишина человека считается всё время в ноде.\n const giveUpAfter = rings && (rings.ring.giveUpAfter ?? (rings.until !== undefined ? rings.after?.giveUpAfter : undefined));\n // Слова сотрудника на паузе — тоже разговор (FR-507): тишина человека считается и от конца паузы.\n return giveUpAfter ? Math.max(run.lastHumanAt ?? run.startedAt, context.pausedUntil ?? 0) + durationMs(giveUpAfter) : null;\n}\n\n/** Пишет ли сценарий утреннее: так задано, а нет — если у программы есть срок. */\nconst morningOn = (schedule: FlowSchedule) => schedule.firstMessages?.morning ?? schedule.lengthDays !== undefined;\n\n/**\n * Утреннее сообщение: начало следующего дня после последних слов агента. Человек писал меньше чем за\n * `skipMorningIfHumanWithinMin` до него или на нём стояла пауза сотрудника — утреннее следующего дня.\n */\nexport function nextMorning(flow: AgentFlow, run: FlowRun, timeZone: string, context: FirstWakeContext = {}): number | null {\n const schedule = flow.schedule;\n if (!schedule || !morningOn(schedule) || run.endedAt !== undefined) return null;\n const skipMs = (schedule.firstMessages?.skipMorningIfHumanWithinMin ?? DEFAULT_SKIP_MORNING_MIN) * 60_000;\n // Утреннее не дошло — следующее утро, а не то же сразу.\n const since = Math.max(run.lastAgentAt ?? run.startedAt, context.undeliveredAt ?? 0);\n let morning = flowDay(run, since, timeZone, schedule).nextDayStartAt;\n for (let day = 0; day < 3; day += 1) {\n const humanJustWrote = run.lastHumanAt !== null && run.lastHumanAt < morning && morning - run.lastHumanAt < skipMs;\n const paused = (context.pausedUntil ?? 0) > morning;\n if (!humanJustWrote && !paused) return morning;\n morning = flowDay(run, morning, timeZone, schedule).nextDayStartAt;\n }\n return morning;\n}\n\n/** Касания, которые ждут правила «человек писал недавно»: агент пишет первым без дела, а не по программе или ответу. */\nconst HELD_AT_DAY_START = new Set<FlowFirstReason[\"kind\"]>([\"morning\", \"silence\", \"daily\"]);\n\n/**\n * До какого момента молчат касания в начале дня: человек писал до начала дня и меньше `skipMorningIfHumanWithinMin`\n * назад — как утреннее, ждут и касание тишины, перенесённое ночью на утро, и касание по часам. Переход ноды по сроку и\n * ответ на ночные сообщения — по делу, они не ждут. Ждать не нужно — `null`.\n */\nexport function dayStartHoldUntil(flow: AgentFlow, run: FlowRun, now: number, timeZone: string, reasons: readonly FlowFirstReason[]): number | null {\n const schedule = flow.schedule;\n if (!schedule || run.lastHumanAt === null || !reasons.every((reason) => HELD_AT_DAY_START.has(reason.kind))) return null;\n const until = run.lastHumanAt + (schedule.firstMessages?.skipMorningIfHumanWithinMin ?? DEFAULT_SKIP_MORNING_MIN) * 60_000;\n if (until <= now) return null;\n return run.lastHumanAt < flowDay(run, now, timeZone, schedule).dayStartedAt ? until : null;\n}\n\n/** Ответить на накопленное: в начале дня после последних записанных в место слов. Сообщений без ответа нет — `null`. */\nexport function nextNightReply(flow: AgentFlow, run: FlowRun, timeZone: string, context: FirstWakeContext = {}): number | null {\n if (!(context.unanswered ?? 0) || run.endedAt !== undefined) return null;\n const last = Math.max(run.lastAgentAt ?? 0, run.lastHumanAt ?? 0, run.startedAt, context.undeliveredAt ?? 0);\n return flow.schedule ? flowDay(run, last, timeZone, flow.schedule).nextDayStartAt : last;\n}\n","import type { AgentFlow, FlowSchedule, FlowTimerUnit, TimerCondition } from \"../format/flow-format\";\nimport type { FlowRun } from \"./flow-run\";\nimport { activeExits, stateById } from \"./flow-graph\";\nimport { exitTarget } from \"./targets\";\nimport { nextClockTime, parseClock } from \"./zoned-time\";\nimport { deadlineAt, programDayDue, stateDaysDue } from \"./flow-days\";\nimport { giveUpAt, nextMorning, nextNightReply, nextNudge, type FirstWakeContext, type FlowFirstReason } from \"./nudges\";\n\n/** `exitId` срока «срок вышел» в `FlowDue`: это не выход ноды, а конец разговора (`schedule.lengthDays`). */\nexport const FLOW_DEADLINE_EXIT = \"@deadline\";\n\nexport interface FlowDue {\n /** Когда сработает, мс с 1970 года. */\n at: number;\n exitId: string;\n}\n\nconst UNIT_MS: Readonly<Record<FlowTimerUnit, number>> = { min: 60_000, h: 3_600_000, d: 86_400_000 };\n\n/** Когда на самом деле вошли в текущее состояние. `enteredAt` после «назад» сдвинут на остановленные часы — время суток от него не считается. */\nfunction actualEntry(run: FlowRun): number {\n const last = run.path.at(-1);\n return last && last.state === run.state ? last.at : run.enteredAt;\n}\n\n/**\n * Срок одного таймера в текущем состоянии чата; `null` — сейчас не идёт (тишины нет: человек ответил или агент ещё не писал).\n * «Нода длится N дней» и «наступил день N» считаются по «Дням и времени»: без `schedule` не идут.\n */\nexport function timerDueAt(condition: TimerCondition, run: FlowRun, timeZone: string, schedule?: FlowSchedule): number | null {\n switch (condition.from) {\n case \"in_state\":\n return run.enteredAt + condition.amount * UNIT_MS[condition.unit];\n case \"since_start\":\n return run.startedAt + condition.amount * UNIT_MS[condition.unit];\n case \"silence\":\n if (run.lastAgentAt === null) return null;\n if (run.lastHumanAt !== null && run.lastHumanAt > run.lastAgentAt) return null;\n return run.lastAgentAt + condition.amount * UNIT_MS[condition.unit];\n case \"time_of_day\": {\n const minutes = parseClock(condition.at);\n return minutes === null ? null : nextClockTime(actualEntry(run), minutes, timeZone);\n }\n case \"state_days\":\n return schedule ? stateDaysDue(run, condition.days, timeZone, schedule) : null;\n case \"program_day\":\n return schedule ? programDayDue(run, condition.day, timeZone, schedule) : null;\n }\n}\n\n/** Таймеры, чей срок не зависит от момента входа в состояние: от начала разговора или дня программы. */\nconst ENTRY_FREE_TIMERS: ReadonlySet<TimerCondition[\"from\"]> = new Set([\"since_start\", \"program_day\"]);\n\n/**\n * Выход по таймеру, который уже наступил к входу в состояние и срок которого от входа не зависит: срабатывает сразу, в том\n * же шаге, а не отдельным ходом. Тишина, время в состоянии, «длится N дней», время суток — нет: их срок от входа. Нет — `null`.\n */\nexport function overdueOnEntry(flow: AgentFlow, run: FlowRun, now: number, timeZone: string): string | null {\n const state = stateById(flow, run.state);\n if (!state) return null;\n let best: FlowDue | null = null;\n for (const { exit } of activeExits(flow, state)) {\n if (exit.when.type !== \"timer\" || !ENTRY_FREE_TIMERS.has(exit.when.from) || !exitTarget(flow, run, exit.to)) continue;\n const at = timerDueAt(exit.when, run, timeZone, flow.schedule);\n // Как `nextDue`: самый ранний срок, при равенстве — порядок в ноде.\n if (at !== null && at <= now && (best === null || at < best.at)) best = { at, exitId: exit.id };\n }\n return best?.exitId ?? null;\n}\n\n/**\n * Ближайший таймер чата: побеждает наступивший раньше, при равенстве — таймер состояния. «Срок вышел» побеждает и при\n * равенстве: разговор кончается, а не переходит. Законченный разговор сроков не имеет. `timeZone` — пояс человека.\n */\nexport function nextDue(flow: AgentFlow, run: FlowRun, _now: number, timeZone: string): FlowDue | null {\n if (run.endedAt !== undefined) return null;\n const state = stateById(flow, run.state);\n if (!state) return null;\n let best: FlowDue | null = null;\n for (const { exit } of activeExits(flow, state)) {\n if (exit.when.type !== \"timer\" || !exitTarget(flow, run, exit.to)) continue;\n const at = timerDueAt(exit.when, run, timeZone, flow.schedule);\n // Свои условия идут первыми: общий таймер забирает срок, только если наступает строго раньше.\n if (at !== null && (best === null || at < best.at)) best = { at, exitId: exit.id };\n }\n const deadline = flow.schedule ? deadlineAt(run, timeZone, flow.schedule) : null;\n if (deadline !== null && (best === null || deadline <= best.at)) best = { at: deadline, exitId: FLOW_DEADLINE_EXIT };\n return best;\n}\n\n// ---------- «Пишет первым»: касания, утро, накопленное (этап 7) ----------\n\n/** `exitId` срока «пишет первым» в `FlowDue`: касание, утреннее или ответ на накопленное, без перехода. */\nexport const FLOW_FIRST_EXIT = \"@first\";\n/** `exitId` срока «не завершил»: конец разговора без сообщения. */\nexport const FLOW_GIVE_UP_EXIT = \"@give_up\";\n\n/** Сроки «пишет первым»: каждая причина со своим моментом. */\nfunction firstMessageDues(flow: AgentFlow, run: FlowRun, now: number, timeZone: string, context: FirstWakeContext) {\n const nudge = nextNudge(flow, run, now, timeZone, context);\n const morning = nextMorning(flow, run, timeZone, context);\n const night = nextNightReply(flow, run, timeZone, context);\n const dues: Array<{ at: number; reason: FlowFirstReason }> = [];\n if (morning !== null) dues.push({ at: morning, reason: { kind: \"morning\" } });\n if (night !== null) dues.push({ at: night, reason: { kind: \"night_messages\", count: context.unanswered ?? 0 } });\n if (nudge && nudge.reason.kind !== \"give_up\") dues.push({ at: nudge.at, reason: nudge.reason });\n return { dues, giveUp: nudge?.reason.kind === \"give_up\" ? nudge.at : null, ownNudge: nudge?.own === true };\n}\n\n/**\n * Ближайший срок чата: переход ноды, «срок вышел», «не завершил» или «пишет первым». При равенстве побеждает «срок\n * вышел», затем «не завершил» (разговор кончается), затем таймер ноды: причины «пишет первым» того же момента он заберёт с собой.\n */\nexport function nextWake(flow: AgentFlow, run: FlowRun, now: number, timeZone: string, context: FirstWakeContext = {}): FlowDue | null {\n if (run.endedAt !== undefined) return null;\n let best = nextDue(flow, run, now, timeZone);\n const { dues, giveUp } = firstMessageDues(flow, run, now, timeZone, context);\n const deadlineFirst = best?.exitId === FLOW_DEADLINE_EXIT;\n if (giveUp !== null && (best === null || giveUp < best.at || (giveUp === best.at && !deadlineFirst))) best = { at: giveUp, exitId: FLOW_GIVE_UP_EXIT };\n for (const due of dues) if (best === null || due.at < best.at) best = { at: due.at, exitId: FLOW_FIRST_EXIT };\n return best;\n}\n\n/** Что наступило к `now`: конец разговора, переход ноды и все причины написать первым — на один ход. */\nexport interface DueReasons {\n /** «Срок вышел»: остальное не считается. */\n deadline: boolean;\n /** «Не завершил»: конец без сообщения. */\n giveUp: boolean;\n /** Наступивший выход ноды по таймеру. */\n exitId: string | null;\n /** Утро, накопленное, касание — по порядку. Переход ноды в них не входит: его причину даёт сам переход. */\n reasons: FlowFirstReason[];\n /** Касание в причинах — своего ряда ноды на N дней: шаг помечается, общий ряд потом начнётся сначала. */\n ownNudge?: boolean;\n}\n\nexport function dueReasons(flow: AgentFlow, run: FlowRun, now: number, timeZone: string, context: FirstWakeContext = {}): DueReasons {\n const none: DueReasons = { deadline: false, giveUp: false, exitId: null, reasons: [] };\n if (run.endedAt !== undefined) return none;\n const exit = nextDue(flow, run, now, timeZone);\n // Срок — сам по себе: переход ноды, который наступил раньше, но ждёт хода (касание отложено), его не заслоняет.\n const deadline = flow.schedule ? deadlineAt(run, timeZone, flow.schedule) : null;\n if (deadline !== null && deadline <= now) return { ...none, deadline: true };\n const { dues, giveUp, ownNudge } = firstMessageDues(flow, run, now, timeZone, context);\n if (giveUp !== null && giveUp <= now) return { ...none, giveUp: true };\n const exitId = exit && exit.at <= now ? exit.exitId : null;\n // Новая нода — свой разговор: касание по тишине старой ноды уже не к месту. Утреннее тоже заменяет касание: ряд после\n // него начинается заново, хвост вчерашнего ряда (ночь, потолок дня) не уходит.\n const morning = dues.some((due) => due.at <= now && due.reason.kind === \"morning\");\n const reasons = dues.filter((due) => due.at <= now && !((exitId || morning) && (due.reason.kind === \"silence\" || due.reason.kind === \"daily\"))).map((due) => due.reason);\n const nudged = reasons.some((reason) => reason.kind === \"silence\" || reason.kind === \"daily\");\n return { ...none, exitId, reasons, ...(ownNudge && nudged && { ownNudge: true }) };\n}\n\n/** Ближайший срок «пишет первым» строго после `now`: касание, утреннее, накопленное. Нет — `null`. */\nexport function nextFirstMessageAfter(flow: AgentFlow, run: FlowRun, now: number, timeZone: string, context: FirstWakeContext = {}): number | null {\n if (run.endedAt !== undefined) return null;\n const ahead = firstMessageDues(flow, run, now, timeZone, context).dues.filter((due) => due.at > now);\n return ahead.length === 0 ? null : Math.min(...ahead.map((due) => due.at));\n}\n\n/** Ближайший конец разговора после `now`: «срок вышел» или «не завершил». Нет — `null`. */\nexport function endingWake(flow: AgentFlow, run: FlowRun, now: number, timeZone: string, context: FirstWakeContext): FlowDue | null {\n if (run.endedAt !== undefined) return null;\n const deadline = flow.schedule ? deadlineAt(run, timeZone, flow.schedule) : null;\n const giveUp = giveUpAt(flow, run, timeZone, context);\n const candidates: FlowDue[] = [\n ...(deadline !== null && deadline > now ? [{ at: deadline, exitId: FLOW_DEADLINE_EXIT }] : []),\n ...(giveUp !== null && giveUp > now ? [{ at: giveUp, exitId: FLOW_GIVE_UP_EXIT }] : []),\n ];\n return earliest(candidates);\n}\n\nconst earliest = (dues: FlowDue[]): FlowDue | null => dues.reduce<FlowDue | null>((best, due) => (best === null || due.at < best.at ? due : best), null);\n\n/**\n * Касание отложено (нельзя писать сейчас, ход не начался): срок — повтор `retry`, но не позже ближайшего срока, который не\n * касание: выход ноды, «срок вышел», «не завершил». Конец разговора не зависит от того, дошло ли касание. Сроки не позже\n * `now` (наступивший выход, который ждёт хода) не в счёт. `retry.at: null` — повтора нет. Ничего нет — `null`.\n */\nexport function deferredWake(\n flow: AgentFlow,\n run: FlowRun,\n now: number,\n timeZone: string,\n context: FirstWakeContext,\n retry: { at: number | null; exitId: string },\n): FlowDue | null {\n if (run.endedAt !== undefined) return null;\n const exit = nextDue(flow, run, now, timeZone);\n const ending = endingWake(flow, run, now, timeZone, context);\n return earliest([\n ...(exit && exit.at > now && exit.exitId !== FLOW_DEADLINE_EXIT ? [exit] : []),\n ...(ending ? [ending] : []),\n ...(retry.at !== null ? [{ at: Math.max(retry.at, now), exitId: retry.exitId }] : []),\n ]);\n}\n","import type { AgentFlow, FlowCatalog, FlowCondition, FlowEventType } from \"../format/flow-format\";\nimport { catalogEventLabel } from \"../format/catalog-events\";\nimport { FLOW_CHAIN_LIMIT, type FlowRun, type Transition, type TransitionDecider, type TransitionReason } from \"./flow-run\";\nimport { dataConditionHolds } from \"./data-conditions\";\nimport { activeExits, fieldById, stateById } from \"./flow-graph\";\nimport { exitTarget } from \"./targets\";\nimport { timerDueAt } from \"./timers\";\n\n/** Что случилось в чате: на это движок ищет переход. */\nexport type FlowEvent =\n /** Сообщение человека, нажатая кнопка, вызванный инструмент, событие приложения. */\n | { type: \"event\"; event: FlowEventType; name?: string }\n /**\n * Изменились данные: проверить условия по ним. `field` — какое поле изменилось (нет — все условия по данным).\n * Заметки чата движок берёт из `run.notes`, карточку клиента приносит событие.\n */\n | { type: \"data\"; field?: string; card?: Record<string, unknown> }\n /** Судья подтвердил условие словами: по заявке агента (`claim`) или сам после ответа (`judge`). `why` — слова агента из заявки. */\n | { type: \"verdict\"; exitId: string; probability: number; decidedBy: \"claim\" | \"judge\"; why?: string }\n /** Наступил таймер из `nextDue`. Пояс человека нужен, чтобы перепроверить срок: человек мог успеть ответить. */\n | { type: \"timer\"; exitId: string; timeZone: string };\n\nfunction matches(flow: AgentFlow, run: FlowRun, exitId: string, when: FlowCondition, event: FlowEvent, now: number): boolean {\n switch (event.type) {\n case \"event\":\n if (when.type !== \"event\" || when.event !== event.event) return false;\n return when.event === \"message\" || when.name === undefined || when.name === event.name;\n case \"data\": {\n if (when.type !== \"data\" || (event.field !== undefined && when.field !== event.field)) return false;\n const found = fieldById(flow, when.field);\n if (!found) return false;\n const value = found.place === \"notes\" ? run.notes[when.field] : event.card?.[when.field];\n return dataConditionHolds(when, found.field.type, value);\n }\n case \"verdict\":\n return exitId === event.exitId && when.type === \"judge\";\n case \"timer\": {\n if (exitId !== event.exitId || when.type !== \"timer\") return false;\n const due = timerDueAt(when, run, event.timeZone, flow.schedule);\n return due !== null && due <= now;\n }\n }\n}\n\nconst UNITS = { min: \"мин\", h: \"ч\", d: \"д\" } as const;\nconst DATA_SIGNS = { eq: \"=\", ne: \"≠\", gt: \">\", lt: \"<\", contains: \"содержит\" } as const;\n\n/** «1 день», «3 дня», «5 дней». */\nfunction daysText(days: number): string {\n const last = days % 10;\n const tens = days % 100;\n const word = last === 1 && tens !== 11 ? \"день\" : last >= 2 && last <= 4 && (tens < 12 || tens > 14) ? \"дня\" : \"дней\";\n return `${days} ${word}`;\n}\n\nconst valueText = (value: string | number | boolean | undefined) => (value === true ? \"да\" : value === false ? \"нет\" : String(value));\n\n/** Условие человеческими словами: для служебного сообщения модели и для причины перехода. С каталогом — подписи событий. */\nexport function describeCondition(flow: AgentFlow, when: FlowCondition, catalog?: Pick<FlowCatalog, \"events\">): string {\n switch (when.type) {\n case \"judge\":\n return when.text;\n case \"data\": {\n const field = flow.clientCard.find((item) => item.id === when.field) ?? flow.chatNotes.find((item) => item.id === when.field);\n const name = `«${field?.name ?? when.field}»`;\n return when.op === \"filled\" ? `узнали ${name}` : `${name} ${DATA_SIGNS[when.op]} ${valueText(when.value)}`;\n }\n case \"event\": {\n if (when.event === \"message\") return \"человек написал\";\n if (when.event === \"tool\") return `вызван инструмент «${when.name ?? \"\"}»`;\n const name = (when.name && catalogEventLabel(catalog, when.name)) ?? when.name ?? \"\";\n return when.event === \"button\" ? `нажата кнопка «${name}»` : `событие «${name}»`;\n }\n case \"timer\":\n if (when.from === \"time_of_day\") return `наступило ${when.at}`;\n if (when.from === \"state_days\") return `нода длится ${daysText(when.days)}`;\n if (when.from === \"program_day\") return `наступил день ${when.day}`;\n if (when.from === \"silence\") return `тишина ${when.amount} ${UNITS[when.unit]}`;\n if (when.from === \"in_state\") return `в состоянии ${when.amount} ${UNITS[when.unit]}`;\n return `с начала разговора ${when.amount} ${UNITS[when.unit]}`;\n }\n}\n\n/** Причина перехода: у заявки — слова агента, у остальных — условие, по которому сработал выход. */\nfunction reasonOf(flow: AgentFlow, event: FlowEvent, when: FlowCondition): TransitionReason {\n const claimed = event.type === \"verdict\" ? event.why?.trim() : undefined;\n return { kind: deciderOf(event), text: claimed || describeCondition(flow, when) };\n}\n\nconst deciderOf = (event: FlowEvent): TransitionDecider => (event.type === \"verdict\" ? event.decidedBy : event.type);\n\n/**\n * Следующий переход или `null` — агент остаётся (→ В2). Порядок: свои условия, потом общие (→ В3); «назад» — в последнее\n * основное состояние (→ В1). После `FLOW_CHAIN_LIMIT` переходов подряд без ответа агента и сообщения человека — `null`.\n */\nexport function nextTransition(flow: AgentFlow, run: FlowRun, event: FlowEvent, now: number): Transition | null {\n if (run.chain >= FLOW_CHAIN_LIMIT) return null;\n const state = stateById(flow, run.state);\n if (!state) return null;\n for (const { exit } of activeExits(flow, state)) {\n if (!matches(flow, run, exit.id, exit.when, event, now)) continue;\n const target = exitTarget(flow, run, exit.to);\n if (!target) continue;\n return {\n from: run.state,\n to: target.state.id,\n exitId: exit.id,\n decidedBy: deciderOf(event),\n ...(event.type === \"verdict\" ? { probability: event.probability } : {}),\n tags: target.state.tags,\n at: now,\n ...(target.returned ? { returned: true } : {}),\n reason: reasonOf(flow, event, exit.when),\n };\n }\n return null;\n}\n","import type { AgentFlow } from \"../format/flow-format\";\nimport { FLOW_PATH_LIMIT, type FlowPathEntry, type FlowRun, type Transition } from \"./flow-run\";\nimport { isTouch, stateById } from \"./flow-graph\";\n\n// Как меняется `FlowRun`: старт, переход, сообщение человека, ответ агента. Чистые функции — новый объект на каждый шаг.\n\n/** Чат начинает сценарий в стартовом состоянии. */\nexport function startRun(flow: AgentFlow, now: number): FlowRun {\n const start = stateById(flow, flow.start);\n if (!start) throw new Error(`Сценарий «${flow.id}» без старта: стартовое состояние не выбрано или его нет.`);\n return {\n state: start.id,\n enteredAt: now,\n startedAt: now,\n path: [{ state: start.id, at: now, tags: start.tags, from: null, exitId: null, decidedBy: \"start\" }],\n pausedClocks: {},\n notes: {},\n humanMessages: 0,\n agentAnswers: 0,\n sideQuestionAt: null,\n lastRejected: null,\n lastAgentAt: null,\n lastHumanAt: null,\n chain: 0,\n };\n}\n\n/** Добавляет шаг в путь, храня последние `FLOW_PATH_LIMIT`. */\nexport function appendPath(path: FlowPathEntry[], entry: FlowPathEntry): FlowPathEntry[] {\n return [...path, entry].slice(-FLOW_PATH_LIMIT);\n}\n\n/**\n * Применяет переход из `nextTransition`. Часы «времени в состоянии» (→ В5): уходя из основного состояния в касание, движок\n * запоминает, сколько там пробыли; «назад» продолжает отсчёт с этого места, обычный вход — с нуля.\n */\nexport function applyTransition(flow: AgentFlow, run: FlowRun, transition: Transition): FlowRun {\n const from = stateById(flow, transition.from);\n const to = stateById(flow, transition.to);\n let enteredAt = transition.at;\n let pausedClocks: Record<string, number> = {};\n if (transition.returned) {\n enteredAt = transition.at - (run.pausedClocks[transition.to] ?? 0);\n } else if (to && isTouch(to)) {\n // В касание: из основного — часы остановлены, из касания — остаются стоять как были.\n pausedClocks = from && !isTouch(from) ? { [from.id]: transition.at - run.enteredAt } : run.pausedClocks;\n }\n // В основное состояние вошли — прежние остановленные часы больше не понадобятся: «назад» поведёт уже сюда.\n return {\n ...run,\n state: transition.to,\n enteredAt,\n pausedClocks,\n path: appendPath(run.path, {\n state: transition.to,\n at: transition.at,\n tags: transition.tags,\n from: transition.from,\n exitId: transition.exitId,\n decidedBy: transition.decidedBy,\n ...(transition.probability === undefined ? {} : { probability: transition.probability }),\n ...(transition.reason === undefined ? {} : { reason: transition.reason }),\n }),\n chain: run.chain + 1,\n lastRejected: null,\n enteredAfterAnswer: run.answerId,\n };\n}\n\n/**\n * Пришло сообщение человека: тишина прервана, счёт переходов подряд — заново, ряд касаний — с первого шага.\n * `dayKey` — местная дата дня сценария («ГГГГ-ММ-ДД»), только у сценариев с днями: по нему считаются рамки дня.\n */\nexport function noteHumanMessage(run: FlowRun, now: number, dayKey?: string, count = 1): FlowRun {\n return {\n ...run,\n humanMessages: run.humanMessages + count,\n lastHumanAt: now,\n chain: 0,\n ...(run.nudgeStep === undefined ? {} : { nudgeStep: 0 }),\n ...(run.serverTurns === undefined ? {} : { serverTurns: 0 }),\n ...(dayKey === undefined ? {} : { dayCounts: { [dayKey]: (run.dayCounts?.[dayKey] ?? 0) + count } }),\n };\n}\n\n/** Агент ответил (или написал первым): от этого момента считается тишина, счёт переходов подряд — заново. */\nexport function noteAgentAnswer(run: FlowRun, now: number): FlowRun {\n return { ...run, agentAnswers: run.agentAnswers + 1, lastAgentAt: now, chain: 0 };\n}\n\n/**\n * Ответ касания не доставлен (FR-309): касание не засчитано — шаг ряда, последние слова агента и счёт ответов как до\n * него. `undeliveredAt` — когда касание было: раньше него следующий срок не наступает. Пометка не меняется — откат тот же\n * сколько ни считай.\n */\nexport function withoutUndeliveredTouch(run: FlowRun, undelivered: ReadonlySet<string>): { run: FlowRun; undeliveredAt: number | null } {\n const touch = run.touch;\n if (!touch || !undelivered.has(touch.answerId)) return { run, undeliveredAt: null };\n const { touch: _touch, ...rest } = run;\n return {\n run: { ...withoutOwnStep(rest), lastAgentAt: touch.lastAgentAt, nudgeStep: touch.nudgeStep, ...(touch.nudgeStepOwn && { nudgeStepOwn: true }), agentAnswers: touch.agentAnswers },\n undeliveredAt: touch.at,\n };\n}\n\n/** Судья не подтвердил заявку агента: тот же выход можно заявить снова после нового сообщения человека. */\nexport function noteRejectedClaim(run: FlowRun, exitId: string): FlowRun {\n return { ...run, lastRejected: { exitId, atHumanMessages: run.humanMessages } };\n}\n\n/** Можно ли заявить выход: его не отклоняли с последнего сообщения человека. */\nexport function claimAllowed(run: FlowRun, exitId: string): boolean {\n return !(run.lastRejected?.exitId === exitId && run.lastRejected.atHumanMessages === run.humanMessages);\n}\n\n/** Агент спросил о человеке между делом: следующий такой вопрос — по темпу сценария. */\nexport function noteSideQuestion(run: FlowRun): FlowRun {\n return { ...run, sideQuestionAt: run.humanMessages };\n}\n\n/** Место без пометки «шаг насчитан своим рядом ноды». */\nexport function withoutOwnStep<R extends FlowRun>(run: R): R {\n const { nudgeStepOwn: _own, ...rest } = run;\n return rest as R;\n}\n\n/** Шаг ряда касаний после хода «пишет первым»: `own` — его насчитал свой ряд ноды на N дней. */\nexport function withNudgeStep<R extends FlowRun>(run: R, step: number, own: boolean): R {\n return { ...withoutOwnStep(run), nudgeStep: step, ...(own && { nudgeStepOwn: true }) };\n}\n","import { DEFAULT_FIRST_MESSAGES, type FirstMessagesRules, type FirstMessagesSetting } from \"./flow-run\";\nimport { clockMinutes, nextClockTime, parseClock, startOfNextDay } from \"./zoned-time\";\n\nexport { localDay } from \"./zoned-time\";\n\nexport interface FirstMessageInput {\n /** Когда агент хочет написать, мс. */\n at: number;\n timeZone: string;\n /** Сколько уже написал первым за эти сутки человека (`localDay`). */\n sentToday: number;\n}\n\n/** Настройка приложения поверх значений SDK (→ В10). `false` — правила выключены: `null`, агент пишет первым без ограничений. */\nexport function resolveFirstMessages(setting: FirstMessagesSetting | undefined): FirstMessagesRules | null {\n if (setting === false) return null;\n const rules: FirstMessagesRules = {\n quietHours: { ...DEFAULT_FIRST_MESSAGES.quietHours, ...setting?.quietHours },\n maxPerDay: setting?.maxPerDay ?? DEFAULT_FIRST_MESSAGES.maxPerDay,\n ...(setting?.canWriteNow ? { canWriteNow: setting.canWriteNow } : {}),\n };\n for (const clock of [rules.quietHours.from, rules.quietHours.to]) {\n if (parseClock(clock) === null) throw new Error(`Тихие часы пишутся как «ЧЧ:ММ», например «21:00», а не «${clock}».`);\n }\n return rules;\n}\n\ntype QuietHours = FirstMessagesRules[\"quietHours\"];\n\n/** Тихо ли сейчас на часах человека. Тихие часы могут идти через полночь; `from` = `to` — тихих часов нет. */\nfunction isQuiet(quietHours: QuietHours, at: number, timeZone: string): boolean {\n const from = parseClock(quietHours.from)!;\n const to = parseClock(quietHours.to)!;\n const now = clockMinutes(at, timeZone);\n if (from === to) return false;\n return from < to ? now >= from && now < to : now >= from || now < to;\n}\n\n/** Первый момент от `at`, когда не тихо. */\nfunction firstAwake(quietHours: QuietHours, at: number, timeZone: string): number {\n return isQuiet(quietHours, at, timeZone) ? nextClockTime(at, parseClock(quietHours.to)!, timeZone) : at;\n}\n\n/**\n * Можно ли написать первым сейчас; нет — на когда перенести. Тихие часы → их конец. Потолок за сутки исчерпан →\n * следующие сутки человека, после тихих часов.\n */\nexport function firstMessageSlot(\n rules: Omit<FirstMessagesRules, \"canWriteNow\">,\n input: FirstMessageInput,\n): { allowed: true } | { allowed: false; retryAt: number } {\n const { at, timeZone } = input;\n if (input.sentToday >= rules.maxPerDay) {\n return { allowed: false, retryAt: firstAwake(rules.quietHours, startOfNextDay(at, timeZone), timeZone) };\n }\n const awake = firstAwake(rules.quietHours, at, timeZone);\n return awake === at ? { allowed: true } : { allowed: false, retryAt: awake };\n}\n","import type { AgentFlow, ClientCardField } from \"../format/flow-format\";\nimport type { FlowRun } from \"./flow-run\";\nimport { fieldValueFits } from \"./data-conditions\";\nimport { fieldById, isFinal, stateById } from \"./flow-graph\";\n\nexport interface SideQuestionInput {\n /** Карточка клиента: id поля → значение и когда записано (мс). */\n card: Record<string, { value: unknown; updatedAt: number }>;\n now: number;\n}\n\n/**\n * О чём спросить человека: `learn` — «узнать здесь», спросить прямо; `stale` — известно давно, мягко уточнить;\n * `unknown` — следующее неизвестное поле карточки, спросить между делом.\n */\nexport interface SideQuestion {\n fieldId: string;\n reason: \"learn\" | \"stale\" | \"unknown\";\n}\n\n/** Пора ли уточнить поле: прошло больше `refreshAfterMonths` месяцев с записи. Без срока поле не устаревает. */\nexport function isFieldStale(field: Pick<ClientCardField, \"refreshAfterMonths\">, updatedAt: number, now: number): boolean {\n if (field.refreshAfterMonths === null) return false;\n const due = new Date(updatedAt);\n due.setUTCMonth(due.getUTCMonth() + field.refreshAfterMonths);\n return due.getTime() <= now;\n}\n\n/**\n * Что спросить сейчас или `null`. «Узнать здесь» — прямо и вне темпа. Дальше — только если состояние не «без вопросов» и\n * с прошлого вопроса между делом прошло `pace.sideQuestionEveryMessages` сообщений человека: сначала устаревшее, потом\n * первое неизвестное поле карточки по порядку. В конце сценария не спрашиваем.\n */\nexport function sideQuestion(flow: AgentFlow, run: FlowRun, input: SideQuestionInput): SideQuestion | null {\n const state = stateById(flow, run.state);\n if (!state || isFinal(state)) return null;\n const known = (id: string): boolean => {\n const found = fieldById(flow, id);\n if (!found) return true;\n const value = found.place === \"notes\" ? run.notes[id] : input.card[id]?.value;\n return fieldValueFits(found.field, value);\n };\n const learn = state.learn.find((id) => !known(id));\n if (learn) return { fieldId: learn, reason: \"learn\" };\n if (state.noSideQuestions) return null;\n if (run.sideQuestionAt !== null && run.humanMessages - run.sideQuestionAt < flow.pace.sideQuestionEveryMessages) return null;\n const stale = flow.clientCard.find((field) => {\n const entry = input.card[field.id];\n return entry !== undefined && known(field.id) && isFieldStale(field, entry.updatedAt, input.now);\n });\n if (stale) return { fieldId: stale.id, reason: \"stale\" };\n const unknown = flow.clientCard.find((field) => !known(field.id));\n return unknown ? { fieldId: unknown.id, reason: \"unknown\" } : null;\n}\n","import type { AgentFlow } from \"../format/flow-format\";\nimport type { FlowRun } from \"./flow-run\";\nimport { stateById } from \"./flow-graph\";\nimport { appendPath } from \"./run-updates\";\n\n/** Куда перевести чаты из состояний, которых нет в новой версии: id старого → id нового. */\nexport type StateMap = Record<string, string>;\n\n/**\n * Переводит чат на новую версию сценария (→ В11). Состояние есть в новой версии — часы и путь целы. Удалено — вход в\n * состояние из `map`; без цели — ошибка (её ловит перевод чатов раньше). Заметки чата — по совпадающим `id`.\n * Удалённые состояния в пути и в остановленных часах переименовываются по `map`: так «назад» ведёт туда, куда автор\n * отправил удалённое состояние.\n */\nexport function migrateRun(run: FlowRun, next: AgentFlow, map: StateMap, now: number): FlowRun {\n const exists = (id: string) => stateById(next, id) !== undefined;\n const renamed = (id: string) => (!exists(id) && map[id] !== undefined && exists(map[id]) ? map[id] : id);\n const noteIds = new Set(next.chatNotes.map((field) => field.id));\n const notes = Object.fromEntries(Object.entries(run.notes).filter(([id]) => noteIds.has(id)));\n const path = run.path.map((entry) => ({ ...entry, state: renamed(entry.state), from: entry.from === null ? null : renamed(entry.from) }));\n const pausedClocks = Object.fromEntries(\n Object.entries(run.pausedClocks)\n .map(([id, ms]) => [renamed(id), ms] as const)\n .filter(([id]) => exists(id)),\n );\n if (exists(run.state)) return { ...run, path, pausedClocks, notes };\n\n const targetId = map[run.state];\n if (targetId === undefined) {\n throw new Error(`Состояния «${run.state}» нет в новой версии сценария «${next.id}», а куда перевести чат — не выбрано.`);\n }\n const target = stateById(next, targetId);\n if (!target) throw new Error(`Состояния «${targetId}» нет в новой версии сценария «${next.id}»: туда не перевести чат из «${run.state}».`);\n return {\n ...run,\n state: target.id,\n enteredAt: now,\n pausedClocks: {},\n notes,\n path: appendPath(path, { state: target.id, at: now, tags: target.tags, from: run.state, exitId: null, decidedBy: \"migrate\" }),\n lastRejected: null,\n };\n}\n","import type { FlowSchedule } from \"../format/flow-format\";\nimport type { FlowRun } from \"./flow-run\";\nimport { dayInProgress } from \"./flow-days\";\n\n// Рамки дня по числу сообщений человека за день сценария, по plan.md, «Рамки дня и решение о входящем». Чистые функции.\n\n/** `normal` — как обычно; `soft` — сворачиваться (строка хвоста); `last` — готовая фраза `hardText`; `closed` — молчать до утра. */\nexport type FrameState = \"normal\" | \"soft\" | \"last\" | \"closed\";\n\n/** Готовая фраза жёсткой рамки, если автор свою не задал. */\nexport const DEFAULT_HARD_FRAME_TEXT = \"На сегодня всё — утром обязательно отвечу!\";\n\n/**\n * Состояние рамки дня для `humanMessagesToday`-го сообщения человека за день сценария: на `hardAt`-м — готовая фраза,\n * после — молчание; с `softFrom`-го — сворачиваться. Рамок нет — `normal`.\n */\nexport function frameState(humanMessagesToday: number, frame: FlowSchedule[\"dayFrame\"]): FrameState {\n if (!frame) return \"normal\";\n const { softFrom, hardAt } = frame;\n if (hardAt !== undefined && humanMessagesToday > hardAt) return \"closed\";\n if (hardAt !== undefined && humanMessagesToday === hardAt) return \"last\";\n if (softFrom !== undefined && humanMessagesToday >= softFrom) return \"soft\";\n return \"normal\";\n}\n\n/** Готовая фраза жёсткой рамки: автора, иначе по умолчанию. */\nexport function hardFrameText(frame: FlowSchedule[\"dayFrame\"]): string {\n return frame?.hardText?.trim() || DEFAULT_HARD_FRAME_TEXT;\n}\n\n/** Сколько сообщений человека уже посчитано за день сценария, который идёт в `at` (`run.dayCounts`). */\nexport function humanMessagesToday(run: FlowRun, at: number, timeZone: string, schedule: FlowSchedule): number {\n return run.dayCounts?.[dayInProgress(at, timeZone, schedule)] ?? 0;\n}\n\n/** Человек закрыл день (`flow_close_day`, запись `dayClosedOn`), и этот день ещё идёт: сегодня первым не пишем. */\nexport function dayClosedToday(dayClosedOn: string | null, at: number, timeZone: string, schedule: FlowSchedule): boolean {\n return dayClosedOn !== null && dayClosedOn === dayInProgress(at, timeZone, schedule);\n}\n","import type { AgentFlow, FlowIssue, FlowIssueLevel } from \"../format/flow-format\";\n\n// Свои проверки приложения в «Проверить сценарий»: приложение пишет `{ path, message }` по месту в JSON сценария\n// (`states[2]`, `states[0].exits[1]`, `sideTasks[0]`) или готовую находку с `place`. Редактор переводит путь в место.\n\n/** Находка приложения: путь в JSON сценария или готовое место. Нет `level` — ошибка, нет `code` — `app_check`. */\nexport interface FlowAppIssue {\n message: string;\n level?: FlowIssueLevel;\n code?: string;\n /** `states[2]`, `states[intro].exits[0]`, `anyState.exits[0]`, `clientCard[1]`, `chatNotes[0]`, `sideTasks[0]`. */\n path?: string;\n place?: FlowIssue[\"place\"];\n}\n\n/** Проверки приложения: одни и те же в `checkFlow(flow, catalog, { checks })` на сервере и в `checks` у `FlowEditor`. */\nexport type FlowAppChecks = (flow: AgentFlow) => readonly FlowAppIssue[];\n\n/** Элемент списка по `[номер]` или `[id]`. */\nfunction pick<T extends { id: string }>(items: readonly T[] | undefined, key: string | undefined): T | undefined {\n if (!items || key === undefined) return undefined;\n return /^\\d+$/.test(key) ? items[Number(key)] : items.find((item) => item.id === key);\n}\n\n/** Место находки по пути в JSON сценария; непонятный путь — весь сценарий. */\nexport function placeOfPath(flow: AgentFlow, path: string): FlowIssue[\"place\"] {\n const state = /^states\\[([^\\]]+)\\](?:\\.exits\\[([^\\]]+)\\])?/.exec(path);\n if (state) {\n const found = pick(flow.states, state[1]);\n if (!found) return {};\n const exit = pick(found.exits, state[2]);\n return exit ? { stateId: found.id, exitId: exit.id } : { stateId: found.id };\n }\n const any = /^anyState\\.exits\\[([^\\]]+)\\]/.exec(path);\n if (any) {\n const exit = pick(flow.anyState.exits, any[1]);\n return exit ? { exitId: exit.id } : {};\n }\n const field = /^(clientCard|chatNotes)\\[([^\\]]+)\\]/.exec(path);\n if (field) {\n const found = pick<{ id: string }>(flow[field[1] as \"clientCard\" | \"chatNotes\"], field[2]);\n return found ? { fieldId: found.id } : {};\n }\n const task = /^sideTasks\\[([^\\]]+)\\]/.exec(path);\n if (task) {\n const found = pick(flow.sideTasks, task[1]);\n return found ? { sideTaskId: found.id } : {};\n }\n return {};\n}\n\n/** Находки приложения как находки `checkFlow`. */\nexport function appIssues(flow: AgentFlow, found: readonly FlowAppIssue[]): FlowIssue[] {\n return found.map((issue) => ({\n level: issue.level ?? \"error\",\n code: issue.code ?? \"app_check\",\n message: issue.message,\n place: issue.place ?? (issue.path === undefined ? {} : placeOfPath(flow, issue.path)),\n }));\n}\n","import {\n FLOW_OPS_BY_FIELD_TYPE,\n RETURN_TARGET,\n type AgentFlow,\n type FlowCatalog,\n type FlowExit,\n type FlowIssue,\n type FlowNudges,\n type FlowState,\n} from \"../format/flow-format\";\nimport { appIssues, type FlowAppChecks } from \"./app-checks\";\nimport { catalogEventNames } from \"../format/catalog-events\";\nimport { commonApplies, fieldById, isFinal, sameText, stateById } from \"../engine/flow-graph\";\nimport { parseClock } from \"../engine/zoned-time\";\n\n// Одна проверка для редактора и сервера (FR-002): сервер не запускает сценарий с ошибками, редактор ведёт к месту ошибки.\n// Порядок находок: повторы id, старт, инструменты сценария, состояния по порядку, общие переходы, «Дни и время»,\n// попутные задачи, достижимость, свои проверки приложения.\n\ntype Place = FlowIssue[\"place\"];\n\nclass Issues {\n readonly list: FlowIssue[] = [];\n error(code: string, message: string, place: Place = {}) {\n this.list.push({ level: \"error\", code, message, place });\n }\n warning(code: string, message: string, place: Place = {}) {\n this.list.push({ level: \"warning\", code, message, place });\n }\n}\n\nconst quote = (text: string) => `«${text}»`;\nconst stateName = (state: FlowState) => quote(state.title.trim() || state.id);\n\nfunction checkDuplicates(flow: AgentFlow, issues: Issues) {\n const states = new Set<string>();\n for (const state of flow.states) {\n if (states.has(state.id)) issues.error(\"duplicate_state\", `Два состояния с id ${quote(state.id)}`, { stateId: state.id });\n states.add(state.id);\n }\n const exits = new Set<string>();\n const exitsOf: Array<{ stateId?: string; exits: FlowExit[] }> = [\n ...flow.states.map((state) => ({ stateId: state.id, exits: state.exits })),\n { exits: flow.anyState.exits },\n ];\n for (const { stateId, exits: list } of exitsOf) {\n for (const exit of list) {\n if (exits.has(exit.id)) {\n issues.error(\"duplicate_exit\", `Два условия с id ${quote(exit.id)}: история переходов их не различит`, {\n ...(stateId === undefined ? {} : { stateId }),\n exitId: exit.id,\n });\n }\n exits.add(exit.id);\n }\n }\n const fields = new Set<string>();\n for (const field of [...flow.clientCard, ...flow.chatNotes]) {\n if (fields.has(field.id)) issues.error(\"duplicate_field\", `Два поля с id ${quote(field.id)} в карточке и заметках`, { fieldId: field.id });\n fields.add(field.id);\n }\n}\n\nfunction eventKnown(exit: FlowExit, catalog: FlowCatalog): boolean {\n if (exit.when.type !== \"event\" || exit.when.name === undefined) return true;\n const { event, name } = exit.when;\n if (event === \"tool\") return catalog.tools.includes(name);\n if (event === \"button\") return catalog.widgets.includes(name) || catalogEventNames(catalog).includes(name);\n if (event === \"app\") return catalogEventNames(catalog).includes(name);\n return true;\n}\n\nfunction checkExit(flow: AgentFlow, catalog: FlowCatalog, issues: Issues, exit: FlowExit, index: number, state?: FlowState) {\n const where = state ? stateName(state) : \"Общие переходы\";\n const what = `${where}: условие №${index + 1}`;\n const place: Place = state ? { stateId: state.id, exitId: exit.id } : { exitId: exit.id };\n\n if (exit.to === null) issues.error(\"exit_without_target\", `${what} никуда не ведёт`, place);\n else if (exit.to === RETURN_TARGET) {\n if (!state) issues.error(\"return_from_any_state\", `${what}: «назад» из общих переходов — непонятно, куда возвращаться`, place);\n } else if (!stateById(flow, exit.to)) issues.error(\"unknown_target\", `${what} ведёт в состояние ${quote(exit.to)}, которого нет`, place);\n\n const when = exit.when;\n if (when.type === \"judge\" && when.text.trim() === \"\") {\n issues.error(\"empty_judge\", `${what} не написано: агенту и судье нечего проверять`, place);\n }\n if (when.type === \"data\") {\n const found = fieldById(flow, when.field);\n const fieldPlace = { ...place, fieldId: when.field };\n if (!found) {\n issues.error(\"unknown_field\", `${what}: поля ${quote(when.field)} нет ни в карточке клиента, ни в заметках чата`, fieldPlace);\n } else if (!FLOW_OPS_BY_FIELD_TYPE[found.field.type].includes(when.op)) {\n issues.error(\"op_not_for_type\", `${what}: поле ${quote(found.field.name)} так не сравнивается`, fieldPlace);\n } else if (found.field.type === \"number\" && when.op !== \"filled\" && typeof when.value !== \"number\") {\n issues.error(\"value_not_number\", `${what}: поле ${quote(found.field.name)} — число, сравнивать его нужно с числом`, fieldPlace);\n } else if (found.field.type === \"boolean\" && when.op !== \"filled\" && typeof when.value !== \"boolean\") {\n issues.error(\"value_not_boolean\", `${what}: поле ${quote(found.field.name)} — «да/нет», сравнивать его нужно с «да» или «нет»`, fieldPlace);\n } else if (\n found.field.type === \"choice\" &&\n when.op === \"eq\" &&\n found.field.options.length > 0 &&\n !found.field.options.some((option) => sameText(option, String(when.value)))\n ) {\n issues.error(\"value_not_in_options\", `${what}: у поля ${quote(found.field.name)} нет варианта ${quote(String(when.value))}`, fieldPlace);\n }\n }\n if (when.type === \"timer\" && when.from === \"state_days\") {\n if (!flow.schedule) {\n issues.error(\"state_days_without_day_start\", `${what}: «длится ${when.days} дн.» — у сценария не задано начало дня («Дни и время»)`, place);\n }\n if (when.days < 1) issues.error(\"state_days_below_one\", `${what}: нода должна длиться хотя бы один день`, place);\n }\n if (when.type === \"timer\" && when.from === \"program_day\") {\n if (!Number.isInteger(when.day) || when.day < 1) {\n issues.error(\"program_day_invalid\", `${what}: день программы — целое число с 1`, place);\n } else if (flow.schedule?.lengthDays !== undefined && when.day > flow.schedule.lengthDays) {\n issues.error(\"program_day_after_end\", `${what}: дня ${when.day} нет — программа длится ${flow.schedule.lengthDays} дн.`, place);\n }\n if (!flow.schedule) issues.warning(\"program_day_without_schedule\", `${what}: «с дня ${when.day}» не сработает — у сценария нет «Дней и времени»`, place);\n }\n if (when.type === \"event\" && when.event !== \"message\") {\n if (when.name === undefined || when.name.trim() === \"\") {\n issues.error(\"event_without_name\", `${what}: не выбрано, какое событие ждать`, place);\n } else if (!eventKnown(exit, catalog)) {\n issues.error(\"unknown_event\", `${what}: приложение не объявило ${quote(when.name)}`, place);\n }\n }\n}\n\nfunction checkState(flow: AgentFlow, catalog: FlowCatalog, issues: Issues, state: FlowState) {\n for (const tool of state.tools) {\n if (!flow.tools.includes(tool)) {\n issues.error(\"tool_not_in_flow\", `${stateName(state)}: инструмента ${quote(tool)} нет в списке инструментов сценария`, { stateId: state.id });\n } else if (!catalog.tools.includes(tool)) {\n issues.error(\"unknown_tool\", `${stateName(state)}: инструмента ${quote(tool)} нет у приложения`, { stateId: state.id });\n }\n }\n for (const fieldId of state.learn) {\n if (!fieldById(flow, fieldId)) {\n issues.error(\"unknown_learn_field\", `${stateName(state)}: «узнать здесь» — поля ${quote(fieldId)} нет`, { stateId: state.id, fieldId });\n }\n }\n state.exits.forEach((exit, index) => checkExit(flow, catalog, issues, exit, index, state));\n if (state.nudges && state.nudges !== \"off\" && nudgesEmpty(state.nudges)) {\n issues.warning(\"empty_nudges\", `${stateName(state)}: в касаниях нет ни одного срока — агент не напишет первым`, { stateId: state.id });\n }\n const days = state.nudges && state.nudges !== \"off\" ? state.nudges.days : undefined;\n if (days !== undefined && (!Number.isInteger(days) || days < 1)) {\n issues.error(\"nudges_days_invalid\", `${stateName(state)}: свои касания действуют целое число дней, с 1`, { stateId: state.id });\n }\n const untilDay = state.nudges && state.nudges !== \"off\" ? state.nudges.untilProgramDay : undefined;\n if (untilDay !== undefined && (!Number.isInteger(untilDay) || untilDay < 1)) {\n issues.error(\"nudges_until_day_invalid\", `${stateName(state)}: свои касания «до дня программы» — целое число с 1`, { stateId: state.id });\n } else if (untilDay !== undefined && flow.schedule?.lengthDays !== undefined && untilDay > flow.schedule.lengthDays) {\n issues.warning(\"nudges_until_day_after_end\", `${stateName(state)}: свои касания до дня ${untilDay}, а программа длится ${flow.schedule.lengthDays} дн. — они действуют всю программу`, {\n stateId: state.id,\n });\n }\n}\n\nconst nudgesEmpty = (nudges: FlowNudges) => nudges.afterSilence.length === 0 && !nudges.dailyAt?.length;\n\nfunction checkSchedule(flow: AgentFlow, issues: Issues) {\n const schedule = flow.schedule;\n if (!schedule) return;\n const dayStart = parseClock(schedule.dayStart);\n const nightFrom = schedule.nightFrom === undefined ? null : parseClock(schedule.nightFrom);\n if (dayStart !== null && nightFrom !== null && nightFrom <= dayStart) {\n issues.error(\"night_before_day_start\", `«Дни и время»: ночь (${schedule.nightFrom}) начинается не позже начала дня (${schedule.dayStart})`);\n }\n if (schedule.deadlineState !== undefined && !stateById(flow, schedule.deadlineState)) {\n issues.error(\"unknown_deadline_state\", `«Дни и время»: при «срок вышел» переход в состояние ${quote(schedule.deadlineState)}, которого нет`, {\n stateId: schedule.deadlineState,\n });\n }\n const frame = schedule.dayFrame;\n if (frame?.softFrom !== undefined && frame.hardAt !== undefined && frame.softFrom >= frame.hardAt) {\n issues.error(\"day_frame_soft_after_hard\", `«Дни и время»: мягкая рамка (${frame.softFrom}) должна быть раньше жёсткой (${frame.hardAt})`);\n }\n const byDay = schedule.firstMessages?.maxPerDayByDay;\n if (byDay && schedule.lengthDays !== undefined && byDay.length > schedule.lengthDays) {\n issues.warning(\n \"max_per_day_by_day_after_end\",\n `«Дни и время»: потолок задан на ${byDay.length} дн., а программа длится ${schedule.lengthDays} дн. — лишние значения не действуют`,\n );\n }\n if (schedule.nudges && nudgesEmpty(schedule.nudges)) {\n issues.warning(\"empty_nudges\", \"«Дни и время»: в касаниях нет ни одного срока — агент не напишет первым\");\n }\n if (schedule.nudges && flow.nudges) {\n issues.warning(\"nudges_shadowed\", \"Касания заданы и у сценария, и в «Днях и времени»: действуют касания «Дней и времени»\");\n }\n}\n\nfunction checkFlowNudges(flow: AgentFlow, issues: Issues) {\n if (flow.nudges && nudgesEmpty(flow.nudges)) {\n issues.warning(\"empty_nudges\", \"Касания сценария: нет ни одного срока — агент не напишет первым\");\n }\n}\n\nfunction checkSideTasks(flow: AgentFlow, issues: Issues) {\n const seen = new Set<string>();\n for (const task of flow.sideTasks ?? []) {\n if (seen.has(task.id)) issues.error(\"duplicate_side_task\", `Две попутные задачи с id ${quote(task.id)}`, { sideTaskId: task.id });\n seen.add(task.id);\n if (task.field !== undefined && !fieldById(flow, task.field)) {\n issues.error(\"side_task_unknown_field\", `Попутная задача ${quote(task.id)}: поля ${quote(task.field)} нет ни в карточке, ни в заметках`, {\n sideTaskId: task.id,\n fieldId: task.field,\n });\n }\n }\n}\n\n/**\n * Состояния, до которых можно дойти от старта: обычными переходами и общими (кроме конечных и исключённых).\n * «Срок вышел» (`schedule.deadlineState`) — тоже вход: срок может выйти в любой момент разговора.\n */\nfunction reachableFrom(flow: AgentFlow, start: FlowState): Set<string> {\n const seen = new Set<string>();\n const queue = [start];\n const deadline = flow.schedule?.deadlineState === undefined ? undefined : stateById(flow, flow.schedule.deadlineState);\n if (deadline) queue.push(deadline);\n while (queue.length > 0) {\n const state = queue.shift()!;\n if (seen.has(state.id)) continue;\n seen.add(state.id);\n const exits = commonApplies(flow, state) ? [...state.exits, ...flow.anyState.exits] : state.exits;\n for (const exit of exits) {\n const next = stateById(flow, exit.to);\n if (next && !seen.has(next.id)) queue.push(next);\n }\n }\n return seen;\n}\n\nexport interface CheckFlowOptions {\n /** Свои проверки приложения: их находки идут после встроенных. Те же — в редакторе (`checks` у `FlowEditor`). */\n checks?: FlowAppChecks;\n}\n\n/** Ошибки и замечания сценария: недостижимые состояния, условия без цели, чужие имена инструментов… */\nexport function checkFlow(flow: AgentFlow, catalog: FlowCatalog, options: CheckFlowOptions = {}): FlowIssue[] {\n const issues = new Issues();\n checkDuplicates(flow, issues);\n\n const start = stateById(flow, flow.start);\n if (flow.start === null) issues.error(\"no_start\", \"Нет стартового состояния: отметьте, где начинается сценарий\");\n else if (!start) issues.error(\"unknown_start\", `Стартовое состояние ${quote(flow.start)} не найдено`);\n\n for (const tool of flow.tools) {\n if (!catalog.tools.includes(tool)) issues.error(\"unknown_tool\", `Инструмента ${quote(tool)} нет у приложения`);\n }\n for (const state of flow.states) checkState(flow, catalog, issues, state);\n\n for (const stateId of flow.anyState.except) {\n if (!stateById(flow, stateId)) {\n issues.warning(\"unknown_except_state\", `Общие переходы: исключено состояние ${quote(stateId)}, которого нет`, { stateId });\n }\n }\n flow.anyState.exits.forEach((exit, index) => checkExit(flow, catalog, issues, exit, index));\n checkSchedule(flow, issues);\n checkFlowNudges(flow, issues);\n checkSideTasks(flow, issues);\n\n if (start) {\n const reachable = reachableFrom(flow, start);\n const reported = new Set<string>();\n for (const state of flow.states) {\n if (reachable.has(state.id) || reported.has(state.id)) continue;\n reported.add(state.id);\n issues.error(\"unreachable_state\", `${stateName(state)}: недостижимо — сюда не ведёт ни один переход от старта`, { stateId: state.id });\n }\n if (!flow.states.some((state) => reachable.has(state.id) && isFinal(state))) {\n issues.warning(\"no_reachable_end\", \"Нет достижимого конечного состояния: сценарий никогда не закончится сам\");\n }\n }\n return [...issues.list, ...(options.checks ? appIssues(flow, options.checks(flow)) : [])];\n}\n"],"mappings":"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","names":["z","z","schedule","id","id","state","clock","DAY_MS","schedule","clock","schedule","UNIT_MS","duration","clock","UNIT_MS","schedule","clock","id","id","humanMessagesToday","schedule","exits","nudges","schedule"]}
|