@ykurilov/agent-chat-flows 0.64.0 → 0.65.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,32 +1,61 @@
1
1
  import {
2
2
  TIME_ZONE_TASK_ID,
3
- dayClosedToday,
4
- firstMessageSlot,
5
3
  flowJsonSchema,
6
- frameState,
7
- hardFrameText,
8
4
  hasSideTasks,
9
- humanMessagesToday,
10
- migrateRun,
11
5
  openSideTasks,
12
- resolveFirstMessages,
13
6
  sideTaskById,
14
7
  sideTaskFieldKnown,
15
8
  sideTaskRecord,
16
9
  sideTaskStanding
17
- } from "./chunk-3K72EVAT.js";
10
+ } from "./chunk-L7XNC3RB.js";
18
11
  import {
19
12
  FACT_PREFIX,
13
+ FIRST_MESSAGE_RETRY_MS,
14
+ FLOW_DEADLINE_NOTICE,
15
+ FLOW_EVENT_NOTICE,
16
+ FLOW_TIMER_NOTICE,
17
+ FlowTestClockError,
20
18
  MAX_FACTS,
21
19
  MAX_FACT_LENGTH,
20
+ UNKNOWN_TIME_ZONE,
21
+ advance,
22
+ advanceTestClock,
23
+ afterEndOf,
24
+ chainLimitMessage,
25
+ chatRun,
26
+ chatTime,
27
+ chatWriteBlock,
22
28
  clientCardBlock,
23
29
  clientFactStore,
30
+ createChatTimeZones,
31
+ createFirstMessageRules,
32
+ createFlowFinish,
33
+ createFlowTimeZones,
34
+ currentRun,
35
+ endedRun,
36
+ exactFirstText,
24
37
  factEntry,
25
38
  factId,
26
39
  fieldValueText,
40
+ firstReasonsNotice,
41
+ flowPrepareTurn,
42
+ flowTestChatData,
43
+ ianaTimeZone,
27
44
  isFactEntry,
28
- sameFact
29
- } from "./chunk-22FWN7NU.js";
45
+ judgeExits,
46
+ pageTimeZone,
47
+ personTimeZone,
48
+ reportTransition,
49
+ runOutsideTurn,
50
+ sameFact,
51
+ silentMsOf,
52
+ stateCard,
53
+ stateGoal,
54
+ storedRun,
55
+ testChatOffset,
56
+ transitionReport,
57
+ withPending
58
+ } from "./chunk-KRZMJJKG.js";
30
59
  import {
31
60
  AGENT_FLOW_FORMAT,
32
61
  AGENT_FLOW_FORMAT_VERSION,
@@ -69,17 +98,21 @@ import {
69
98
  dayStartHoldUntil,
70
99
  deadlineAt,
71
100
  deferredWake,
72
- describeCondition,
73
101
  dueReasons,
74
102
  endingWake,
75
103
  fieldById,
76
104
  fieldValueFits,
105
+ firstMessageSlot,
77
106
  flowDay,
107
+ frameState,
108
+ hardFrameText,
109
+ humanMessagesToday,
78
110
  isFieldStale,
79
111
  isFinal,
80
112
  isTouch,
81
113
  localDay,
82
114
  migrateFlow,
115
+ migrateRun,
83
116
  nextDayStartAfter,
84
117
  nextDue,
85
118
  nextFirstMessageAfter,
@@ -90,11 +123,11 @@ import {
90
123
  noteHumanMessage,
91
124
  noteRejectedClaim,
92
125
  noteSideQuestion,
93
- overdueOnEntry,
94
126
  parseBooleanAnswer,
95
127
  parseDuration,
96
128
  parseFlow,
97
129
  placeOfPath,
130
+ resolveFirstMessages,
98
131
  returnTarget,
99
132
  sameText,
100
133
  sideQuestion,
@@ -106,7 +139,7 @@ import {
106
139
  withDayAnchor,
107
140
  withNudgeStep,
108
141
  withoutUndeliveredTouch
109
- } from "./chunk-5RDY7QBA.js";
142
+ } from "./chunk-7VR4YNTJ.js";
110
143
  import {
111
144
  appliedInTime,
112
145
  byVersionAndState,
@@ -173,6 +206,42 @@ function turnToolNames(source, catalog, input) {
173
206
  }
174
207
  }
175
208
 
209
+ // src/runtime/notice-screen.ts
210
+ var TIMER_FIELDS = ["type", "from", "days", "day", "at", "amount", "unit"];
211
+ var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
212
+ var scalar = (value) => typeof value === "string" || typeof value === "number";
213
+ function screenReason(reason) {
214
+ if (!isRecord(reason) || typeof reason.kind !== "string") return void 0;
215
+ return {
216
+ kind: reason.kind,
217
+ ...reason.kind === "daily" && typeof reason.at === "string" && { at: reason.at },
218
+ ...reason.kind === "night_messages" && typeof reason.count === "number" && { count: reason.count }
219
+ };
220
+ }
221
+ function screenWhen(when) {
222
+ if (!isRecord(when) || when.type !== "timer") return void 0;
223
+ return Object.fromEntries(TIMER_FIELDS.flatMap((field) => scalar(when[field]) ? [[field, when[field]]] : []));
224
+ }
225
+ function screenExit(exit) {
226
+ if (!isRecord(exit)) return void 0;
227
+ const when = screenWhen(exit.when);
228
+ const stateTitle = typeof exit.stateTitle === "string" ? exit.stateTitle : void 0;
229
+ if (!when && stateTitle === void 0) return void 0;
230
+ return { ...stateTitle !== void 0 && { stateTitle }, ...when && { when } };
231
+ }
232
+ function flowNoticeScreenData(data) {
233
+ if (!isRecord(data) || !Array.isArray(data.reasons)) return void 0;
234
+ const reasons = data.reasons.flatMap((reason) => screenReason(reason) ?? []);
235
+ if (reasons.length === 0) return void 0;
236
+ const exit = screenExit(data.exit);
237
+ return {
238
+ reasons,
239
+ ...typeof data.silentMs === "number" && Number.isFinite(data.silentMs) && { silentMs: data.silentMs },
240
+ ...exit && { exit }
241
+ };
242
+ }
243
+ var FLOW_APP_NOTICE_VIEWS = { [FLOW_TIMER_NOTICE]: flowNoticeScreenData, [FLOW_DEADLINE_NOTICE]: flowNoticeScreenData };
244
+
176
245
  // src/prompt/rules/time-zone.ts
177
246
  var TIME_ZONE_RULES = `## \u0414\u043D\u0438 \u0438 \u0432\u0440\u0435\u043C\u044F
178
247
 
@@ -264,184 +333,9 @@ function afterEndRules(flow) {
264
333
  ${shared}` : AFTER_END_RULES;
265
334
  }
266
335
 
267
- // src/prompt/state-card.ts
268
- function judgeExits(flow, stateId) {
269
- const state = stateById(flow, stateId);
270
- if (!state) return [];
271
- return activeExits(flow, state).flatMap(({ exit }) => exit.when.type === "judge" ? [{ exitId: exit.id, text: exit.when.text }] : []);
272
- }
273
- function stateGoal(instructions) {
274
- return instructions.split("\n")[0].trim();
275
- }
276
- function stateCard(flow, run, present) {
277
- const state = stateById(flow, run.state);
278
- if (!state) return `\u0421\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435 \xAB${run.state}\xBB \u0432 \u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0438 \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E: \u0432\u0435\u0434\u0438 \u0440\u0430\u0437\u0433\u043E\u0432\u043E\u0440 \u043F\u043E \u043E\u0431\u0449\u0438\u043C \u043F\u0440\u0430\u0432\u0438\u043B\u0430\u043C.`;
279
- const [goal = "", ...rest] = state.instructions.split("\n");
280
- const lines = [`\u0421\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435: \xAB${state.title}\xBB`, `\u0426\u0435\u043B\u044C: ${goal.trim()}`];
281
- const how = rest.join("\n").trim();
282
- if (how) lines.push("", how);
283
- const fields = state.learn.map((id) => fieldById(flow, id)).flatMap((found) => found ? [`- ${found.field.name}: ${found.field.about}`] : []);
284
- if (fields.length > 0) lines.push("", "\u0423\u0437\u043D\u0430\u0442\u044C \u0437\u0434\u0435\u0441\u044C:", ...fields);
285
- const conditions = judgeExits(flow, state.id);
286
- if (isFinal(state)) {
287
- lines.push("", "\u042D\u0442\u043E \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u0435\u0435 \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435 \u0441\u0446\u0435\u043D\u0430\u0440\u0438\u044F: \u0443\u0441\u043B\u043E\u0432\u0438\u0439 \u0432\u044B\u0445\u043E\u0434\u0430 \u043D\u0435\u0442.");
288
- } else if (conditions.length > 0) {
289
- lines.push("", "\u0423\u0441\u043B\u043E\u0432\u0438\u044F \u0432\u044B\u0445\u043E\u0434\u0430 (\u043D\u043E\u043C\u0435\u0440 \u2014 \u0434\u043B\u044F flow_exit):", ...conditions.map((condition, index) => `${index + 1}. ${condition.text}`));
290
- }
291
- const inSet = (name) => !present || present.has(name);
292
- const tools = state.tools.filter(inSet);
293
- if (tools.length > 0) lines.push("", `\u0418\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u044B \u044D\u0442\u043E\u0433\u043E \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u044F: ${tools.join(", ")}.`);
294
- const unavailable = flow.tools.filter((name) => inSet(name) && !state.tools.includes(name));
295
- if (unavailable.length > 0) lines.push(`\u0421\u0435\u0439\u0447\u0430\u0441 \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B: ${unavailable.join(", ")}.`);
296
- return lines.join("\n");
297
- }
298
-
299
336
  // src/runtime/note-tools.ts
300
337
  import { tool } from "ai";
301
338
  import { z } from "zod";
302
-
303
- // src/runtime/flow-events.ts
304
- async function reportTransition(handler, event, logError) {
305
- if (!handler) return;
306
- try {
307
- await handler(event);
308
- } catch (error) {
309
- logError(`[\u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439] \u0447\u0430\u0442=${event.chatId} onTransition ${event.from} \u2192 ${event.to} \u0443\u043F\u0430\u043B: ${error instanceof Error ? error.message : String(error)}`);
310
- }
311
- }
312
- function storedRun(value) {
313
- return value && typeof value === "object" && typeof value.state === "string" ? value : null;
314
- }
315
- function currentRun(flow, values, now) {
316
- return storedRun(values?.[FLOW_STATE_KEY]) ?? startRun(flow, now);
317
- }
318
- function placedRun(flow, placement, now, timeZone) {
319
- const start = startRun(flow, now);
320
- const state = placement.stateId !== void 0 && stateById(flow, placement.stateId) || stateById(flow, flow.start);
321
- const startedAt = placement.startedAt ?? now;
322
- const enteredAt = placement.enteredAt ?? placement.startedAt ?? now;
323
- return {
324
- ...start,
325
- state: state.id,
326
- startedAt,
327
- enteredAt,
328
- path: [{ state: state.id, at: enteredAt, tags: state.tags, from: null, exitId: null, decidedBy: "start" }],
329
- ...placement.lastHumanAt !== void 0 && { lastHumanAt: placement.lastHumanAt },
330
- ...placement.lastAgentAt !== void 0 && { lastAgentAt: placement.lastAgentAt },
331
- ...placement.nudgeStep !== void 0 && { nudgeStep: placement.nudgeStep },
332
- ...placement.humanToday && flow.schedule && timeZone && { dayCounts: { [dayInProgress(placement.humanToday.at, timeZone, flow.schedule)]: placement.humanToday.count } }
333
- };
334
- }
335
- var msOf = (value) => value === void 0 ? void 0 : Date.parse(value);
336
- function recordPlacement(record) {
337
- const placement = record.placement;
338
- if (!placement) return null;
339
- const lastHumanAt = msOf(placement.lastHumanAt);
340
- const lastAgentAt = msOf(placement.lastAgentAt);
341
- return {
342
- stateId: record.stateId,
343
- startedAt: Date.parse(placement.startedAt),
344
- enteredAt: Date.parse(placement.enteredAt),
345
- ...lastHumanAt !== void 0 && { lastHumanAt },
346
- ...lastAgentAt !== void 0 && { lastAgentAt },
347
- ...placement.nudgeStep !== void 0 && { nudgeStep: placement.nudgeStep },
348
- ...placement.humanToday && { humanToday: { at: Date.parse(placement.humanToday.at), count: placement.humanToday.count } }
349
- };
350
- }
351
- function chatRun(flow, values, record, now, timeZone) {
352
- const stored = storedRun(values?.[FLOW_STATE_KEY]);
353
- if (stored) return stored;
354
- const placement = record ? recordPlacement(record) : null;
355
- return placement ? placedRun(flow, placement, now, timeZone) : startRun(flow, now);
356
- }
357
- async function personTimeZone(runtime, chat) {
358
- const known = runtime.timeZones ? await runtime.timeZones.of(chat.ownerId, chat.chatId) : (await runtime.store.getChat(chat.chatId))?.timeZone;
359
- return known || runtime.defaultTimeZone || Intl.DateTimeFormat().resolvedOptions().timeZone;
360
- }
361
- async function runOutsideTurn(runtime, chat, flow, values, now, record) {
362
- const stored = storedRun(values?.[FLOW_STATE_KEY]);
363
- if (stored) return stored;
364
- const found = record === void 0 ? await runtime.store.getChat(chat.chatId) : record;
365
- if (!found?.placement) return startRun(flow, now);
366
- const timeZone = runtime.timeZones ? await runtime.timeZones.of(chat.ownerId, chat.chatId) : found.timeZone || void 0;
367
- return chatRun(flow, values, found, now, timeZone);
368
- }
369
- function advance(flow, run, event, input) {
370
- let current = run;
371
- let step = event;
372
- let entered = false;
373
- let stopped = false;
374
- while (step) {
375
- const transition = nextTransition(flow, current, step, input.now);
376
- if (!transition) {
377
- if (current.chain >= FLOW_CHAIN_LIMIT && nextTransition(flow, { ...current, chain: 0 }, step, input.now)) {
378
- if (!stopped) input.onChainLimit(current);
379
- stopped = true;
380
- }
381
- const overdue = entered && !stopped && step.type === "data" ? overdueOnEntry(flow, current, input.now, input.timeZone) : null;
382
- step = overdue ? { type: "timer", exitId: overdue, timeZone: input.timeZone } : null;
383
- continue;
384
- }
385
- current = applyTransition(flow, current, transition);
386
- input.out.push(transition);
387
- entered = true;
388
- step = { type: "data", card: input.card };
389
- }
390
- return current;
391
- }
392
- function pendingEvent(transition, timeZone) {
393
- if (transition.decidedBy === "timer") return { type: "timer", exitId: transition.exitId, timeZone };
394
- return { type: "verdict", exitId: transition.exitId, probability: transition.probability ?? 1, decidedBy: "judge" };
395
- }
396
- function withPending(flow, run, pending, input) {
397
- let current = run;
398
- for (const change of pending) {
399
- if (change.kind === "transition") {
400
- if (change.branchHead !== run.answerId || current.state !== change.transition.from) continue;
401
- current = advance(flow, current, pendingEvent(change.transition, input.timeZone), input);
402
- } else if (change.kind === "event") {
403
- current = advance(flow, current, { type: "event", event: "app", name: change.name }, input);
404
- }
405
- }
406
- return current;
407
- }
408
- var chainLimitMessage = (chatId, run) => `[\u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439] \u0447\u0430\u0442=${chatId} ${FLOW_CHAIN_LIMIT} \u043F\u0435\u0440\u0435\u0445\u043E\u0434\u043E\u0432 \u043F\u043E\u0434\u0440\u044F\u0434 \u0431\u0435\u0437 \u043E\u0442\u0432\u0435\u0442\u0430 \u0430\u0433\u0435\u043D\u0442\u0430, \u0434\u0432\u0438\u0436\u043E\u043A \u043E\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D \u0432 \xAB${run.state}\xBB`;
409
- function exitById(flow, exitId) {
410
- for (const state of flow.states) {
411
- const found = state.exits.find((exit) => exit.id === exitId);
412
- if (found) return found;
413
- }
414
- return flow.anyState.exits.find((exit) => exit.id === exitId);
415
- }
416
- function exactFirstText(flow, stateId) {
417
- return stateById(flow, stateId)?.firstMessage ?? null;
418
- }
419
- var sayExactly = (text) => `\u041F\u0435\u0440\u0432\u043E\u0435 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u044D\u0442\u043E\u0433\u043E \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u044F \u2014 \u0441\u043A\u0430\u0436\u0438 \u0440\u043E\u0432\u043D\u043E \u044D\u0442\u043E: \xAB${text}\xBB`;
420
- function transitionNotice(flow, transitions) {
421
- const lines = transitions.map((transition) => {
422
- const exit = exitById(flow, transition.exitId);
423
- const title = stateById(flow, transition.to)?.title ?? transition.to;
424
- return `\u0421\u0440\u0430\u0431\u043E\u0442\u0430\u043B\u043E: ${exit ? describeCondition(flow, exit.when) : transition.exitId} \u2192 \xAB${title}\xBB.`;
425
- });
426
- const last = transitions.at(-1);
427
- const first = exactFirstText(flow, last.to);
428
- if (first) lines.push(sayExactly(first));
429
- return {
430
- kind: "app",
431
- name: "flow_transition",
432
- title: lines.join("\n"),
433
- data: { from: transitions[0].from, to: last.to, exitIds: transitions.map((transition) => transition.exitId) }
434
- };
435
- }
436
- function transitionReport(flow, run, transitions) {
437
- const from = stateById(flow, transitions[0].from)?.title ?? transitions[0].from;
438
- const lines = [`\u041F\u0435\u0440\u0435\u0445\u043E\u0434: \xAB${from}\xBB \u2192 \xAB${stateById(flow, run.state)?.title ?? run.state}\xBB. \u0421\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435 \u0441\u043C\u0435\u043D\u0438\u043B\u043E\u0441\u044C, \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0430\u0439 \u043F\u043E \u043D\u043E\u0432\u043E\u0439 \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0435.`, "", stateCard(flow, run)];
439
- const first = exactFirstText(flow, run.state);
440
- if (first) lines.push("", sayExactly(first));
441
- return lines.join("\n");
442
- }
443
-
444
- // src/runtime/note-tools.ts
445
339
  var FLOW_NOTE_TOOL = "flow_note";
446
340
  var CLIENT_CARD_TOOL = "client_card";
447
341
  var NO_FLOW = "\u0412 \u044D\u0442\u043E\u043C \u0447\u0430\u0442\u0435 \u043D\u0435\u0442 \u0441\u0446\u0435\u043D\u0430\u0440\u0438\u044F: \u0437\u0430\u043F\u0438\u0441\u044B\u0432\u0430\u0442\u044C \u043D\u0435\u043A\u0443\u0434\u0430, \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0430\u0439 \u0440\u0430\u0437\u0433\u043E\u0432\u043E\u0440.";
@@ -674,105 +568,6 @@ function createClientCard(store, now, adapter, logError = () => {
674
568
  };
675
569
  }
676
570
 
677
- // src/runtime/first-message-retry.ts
678
- var FIRST_MESSAGE_RETRY_MS = 36e5;
679
- var FIRST_MESSAGE_MIN_RETRY_MS = 6e4;
680
-
681
- // src/runtime/first-message-rules.ts
682
- function chatWriteBlock(chat, at, timeZone, schedule) {
683
- if (chat.windowClosed) return { retryAt: null };
684
- const pausedUntil = chat.pausedUntil ? Date.parse(chat.pausedUntil) : 0;
685
- if (pausedUntil > at) return { retryAt: pausedUntil };
686
- if (schedule && dayClosedToday(chat.dayClosedOn, at, timeZone, schedule)) return { retryAt: nextDayStartAfter(at, timeZone, schedule) };
687
- return null;
688
- }
689
- function scenarioRules(rules, schedule) {
690
- if (!schedule) return rules;
691
- return {
692
- quietHours: { from: schedule.nightFrom ?? rules.quietHours.from, to: schedule.dayStart },
693
- maxPerDay: schedule.firstMessages?.maxPerDay ?? rules.maxPerDay
694
- };
695
- }
696
- function createFirstMessageRules(setting, store) {
697
- const rules = resolveFirstMessages(setting);
698
- if (!rules) return null;
699
- return {
700
- async check({ ownerId, chatId, at, timeZone, schedule, chat }) {
701
- const blocked = chat ? chatWriteBlock(chat, at, timeZone, schedule) : null;
702
- if (blocked) return { allowed: false, retryAt: blocked.retryAt };
703
- const sentToday = await store.countFirstMessages(ownerId, localDay(at, timeZone));
704
- const slot = firstMessageSlot(scenarioRules(rules, schedule), { at, timeZone, sentToday });
705
- if (!slot.allowed) return slot;
706
- const answer = rules.canWriteNow ? await rules.canWriteNow({ ownerId, chatId, at: new Date(at) }) : true;
707
- if (answer === true) return { allowed: true };
708
- return { allowed: false, retryAt: retryAtOf(answer, at) };
709
- },
710
- async record({ ownerId, at, timeZone }) {
711
- await store.addFirstMessage(ownerId, localDay(at, timeZone));
712
- }
713
- };
714
- }
715
- function retryAtOf(answer, at) {
716
- if (answer === "never") return null;
717
- const retryAt = typeof answer === "object" && answer !== null && answer.retryAt instanceof Date ? answer.retryAt.getTime() : Number.NaN;
718
- if (!Number.isFinite(retryAt)) return at + FIRST_MESSAGE_RETRY_MS;
719
- return Math.max(retryAt, at + FIRST_MESSAGE_MIN_RETRY_MS);
720
- }
721
- var UNKNOWN_TIME_ZONE = "";
722
- var serverTimeZone = () => Intl.DateTimeFormat().resolvedOptions().timeZone;
723
- function pageTimeZone(turnZone, appZone, sent) {
724
- if (sent !== void 0) return sent;
725
- return turnZone === (appZone ?? serverTimeZone()) ? null : turnZone;
726
- }
727
- function createChatTimeZones(input) {
728
- const warned = /* @__PURE__ */ new Set();
729
- return {
730
- of(chatId, stored) {
731
- if (stored) return stored;
732
- if (input.defaultTimeZone) return input.defaultTimeZone;
733
- const app = input.appTimeZone();
734
- if (app) return app;
735
- const server = serverTimeZone();
736
- if (!warned.has(chatId)) {
737
- warned.add(chatId);
738
- input.warn(`[\u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439] \u0447\u0430\u0442=${chatId}: \u043F\u043E\u044F\u0441 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 \u043D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u0435\u043D (\u043D\u0435\u0442 \u043D\u0438 \u0441\u043E \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B, \u043D\u0438 defaultTimeZone, \u043D\u0438 agent.timeZone) \u2014 \u0442\u0438\u0445\u0438\u0435 \u0447\u0430\u0441\u044B \u0438 \xAB\u0432\u0440\u0435\u043C\u044F \u0441\u0443\u0442\u043E\u043A\xBB \u043F\u043E \u043F\u043E\u044F\u0441\u0443 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 ${server}`);
739
- }
740
- return server;
741
- }
742
- };
743
- }
744
- function ianaTimeZone(value) {
745
- if (!value.trim()) return null;
746
- try {
747
- return new Intl.DateTimeFormat("en-US", { timeZone: value.trim() }).resolvedOptions().timeZone;
748
- } catch {
749
- return null;
750
- }
751
- }
752
- function createFlowTimeZones(input) {
753
- const { store } = input;
754
- const iso = () => new Date(input.now()).toISOString();
755
- const readPerson = (ownerId) => input.people ? input.people.readTimeZone(ownerId) : store.readTimeZone(ownerId);
756
- const writePerson = (ownerId, timeZone) => input.people ? input.people.writeTimeZone(ownerId, timeZone) : store.writeTimeZone(ownerId, timeZone, iso());
757
- async function known(ownerId, chatId) {
758
- const person = await readPerson(ownerId);
759
- if (person) return person;
760
- return (await store.getChat(chatId))?.timeZone || null;
761
- }
762
- return {
763
- known,
764
- fallback: input.fallback,
765
- async of(ownerId, chatId) {
766
- return await known(ownerId, chatId) ?? input.fallback(chatId);
767
- },
768
- async write(ownerId, chatId, timeZone) {
769
- if (await readPerson(ownerId) !== timeZone) await writePerson(ownerId, timeZone);
770
- const record = await store.getChat(chatId);
771
- if (record && record.timeZone !== timeZone) await store.updateChat(chatId, { timeZone }, iso());
772
- }
773
- };
774
- }
775
-
776
571
  // src/runtime/decisions-client.ts
777
572
  function decisionsUrl(baseUrl) {
778
573
  const base = baseUrl.replace(/\/+$/, "");
@@ -1009,375 +804,11 @@ function errorText2(error) {
1009
804
  import { randomUUID } from "crypto";
1010
805
  import { ChatNotFoundError as ChatNotFoundError2, SpendingLimitReachedError } from "@ykurilov/agent-chat-core";
1011
806
 
1012
- // src/runtime/test-clock.ts
1013
- var FLOW_TEST_CHAT_KEY = "flowTestChat";
1014
- function flowTestChatData() {
1015
- return { [FLOW_TEST_CHAT_KEY]: { timeOffset: 0 } };
1016
- }
1017
- function testChatOffset(data) {
1018
- const mark = data?.[FLOW_TEST_CHAT_KEY];
1019
- if (!mark || typeof mark !== "object") return null;
1020
- const offset = mark.timeOffset;
1021
- return typeof offset === "number" && Number.isFinite(offset) ? offset : 0;
1022
- }
1023
- var chatTime = (run, serverNow) => serverNow + (run?.timeOffset ?? 0);
1024
- var FlowTestClockError = class extends Error {
1025
- constructor(code, message) {
1026
- super(message);
1027
- this.code = code;
1028
- this.name = "FlowTestClockError";
1029
- }
1030
- code;
1031
- };
1032
- var NEXT_FIRST_MESSAGE_STEPS = 50;
1033
- var TURN_WAIT_LIMIT = 5;
1034
- async function placeRun(runtime, port, chat, flow, now) {
1035
- const { values } = await port.getChatState(chat.ownerId, chat.chatId);
1036
- const stored = storedRun(values[FLOW_STATE_KEY]);
1037
- if (stored) return stored;
1038
- const record = await runtime.store.getChat(chat.chatId);
1039
- return record ? runOutsideTurn(runtime, chat, flow, values, now, record) : null;
1040
- }
1041
- async function msToNextDay(runtime, port, ownerId, chatId, offset) {
1042
- const pinned = await runtime.chatFlow(ownerId, chatId);
1043
- const schedule = pinned?.flow.schedule;
1044
- if (!pinned || !schedule) throw new Error("\u041F\u0435\u0440\u0435\u043C\u043E\u0442\u043A\u0430 \u0434\u043E \u0443\u0442\u0440\u0430: \u0443 \u0441\u0446\u0435\u043D\u0430\u0440\u0438\u044F \u043D\u0435 \u043D\u0430\u0441\u0442\u0440\u043E\u0435\u043D\u044B \xAB\u0414\u043D\u0438 \u0438 \u0432\u0440\u0435\u043C\u044F\xBB (schedule)");
1045
- const chatNow = runtime.now() + offset;
1046
- const run = await placeRun(runtime, port, { ownerId, chatId }, pinned.flow, chatNow);
1047
- if (!run) throw new Error("\u041F\u0435\u0440\u0435\u043C\u043E\u0442\u043A\u0430 \u0434\u043E \u0443\u0442\u0440\u0430: \u0432 \u0447\u0430\u0442\u0435 \u0435\u0449\u0451 \u043D\u0435 \u0431\u044B\u043B\u043E \u0445\u043E\u0434\u0430, \u0434\u043D\u0438 \u0441\u0446\u0435\u043D\u0430\u0440\u0438\u044F \u043D\u0435 \u043D\u0430\u0447\u0430\u043B\u0438\u0441\u044C");
1048
- const timeZone = runtime.timeZones ? await runtime.timeZones.of(ownerId, chatId) : "UTC";
1049
- return flowDay(run, chatNow, timeZone, schedule).nextDayStartAt - chatNow;
1050
- }
1051
- async function turnFinished(port, ownerId, chatId) {
1052
- for (let turn = 0; turn < TURN_WAIT_LIMIT; turn += 1) {
1053
- const stream = await port.subscribe?.(ownerId, chatId);
1054
- if (!stream) return;
1055
- for await (const _chunk of stream) ;
1056
- }
1057
- }
1058
- async function advanceTestClock(input) {
1059
- const { runtime, port, timers, ownerId, chatId, clock } = input;
1060
- const offset = testChatOffset(await port.getChatData(ownerId, chatId));
1061
- if (offset === null) throw new Error(`\u0427\u0430\u0442 ${chatId} \u043D\u0435 \u0442\u0435\u0441\u0442\u043E\u0432\u044B\u0439: \u0447\u0430\u0441\u044B \u043F\u0435\u0440\u0435\u043C\u0430\u0442\u044B\u0432\u0430\u044E\u0442\u0441\u044F \u0442\u043E\u043B\u044C\u043A\u043E \u0443 \u0442\u0435\u0441\u0442\u043E\u0432\u044B\u0445 \u0447\u0430\u0442\u043E\u0432`);
1062
- if (clock.to === "next_first_message") return advanceToNextFirstMessage({ runtime, port, timers, ownerId, chatId, offset });
1063
- const ms = clock.to === "next_day_start" ? await msToNextDay(runtime, port, ownerId, chatId, offset) : clock.ms ?? Number.NaN;
1064
- if (!Number.isFinite(ms) || ms <= 0) throw new Error("\u041F\u0435\u0440\u0435\u043C\u043E\u0442\u043A\u0430 \u0447\u0430\u0441\u043E\u0432: \u043D\u0443\u0436\u0435\u043D \u0441\u0434\u0432\u0438\u0433 \u0432\u043F\u0435\u0440\u0451\u0434, \u043C\u0441 \u0431\u043E\u043B\u044C\u0448\u0435 \u043D\u0443\u043B\u044F");
1065
- const timeOffset = offset + ms;
1066
- await port.updateChatData(ownerId, chatId, { [FLOW_TEST_CHAT_KEY]: { timeOffset } });
1067
- const pinned = timers && await runtime.chatFlow(ownerId, chatId);
1068
- if (!timers || !pinned) return { timeOffset };
1069
- const run = await placeRun(runtime, port, { ownerId, chatId }, pinned.flow, runtime.now() + timeOffset);
1070
- if (!run) return { timeOffset };
1071
- await timers.reschedule({ ownerId, chatId, run: { ...run, timeOffset }, branchHead: run.answerId ?? null });
1072
- await timers.tick();
1073
- await turnFinished(port, ownerId, chatId);
1074
- return { timeOffset };
1075
- }
1076
- var nothingScheduled = (chatId) => new FlowTestClockError("nothing_scheduled", `\u0427\u0430\u0442 ${chatId}: \u0432\u043F\u0435\u0440\u0435\u0434\u0438 \u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439 \u0441\u0430\u043C \u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u043D\u0430\u043F\u0438\u0448\u0435\u0442 \u2014 \u043F\u0435\u0440\u0435\u043C\u0430\u0442\u044B\u0432\u0430\u0442\u044C \u043D\u0435 \u043A \u0447\u0435\u043C\u0443`);
1077
- async function advanceToNextFirstMessage(input) {
1078
- const { runtime, port, timers, ownerId, chatId } = input;
1079
- const pinned = timers && await runtime.chatFlow(ownerId, chatId);
1080
- if (!timers?.watch || !pinned) throw nothingScheduled(chatId);
1081
- let timeOffset = input.offset;
1082
- for (let step = 0; step < NEXT_FIRST_MESSAGE_STEPS; step += 1) {
1083
- const run = await placeRun(runtime, port, { ownerId, chatId }, pinned.flow, runtime.now() + timeOffset);
1084
- if (!run) throw nothingScheduled(chatId);
1085
- if (step === 0) await timers.reschedule({ ownerId, chatId, run: { ...run, timeOffset }, branchHead: run.answerId ?? null });
1086
- const record = await runtime.store.getChat(chatId);
1087
- if (!record || record.endedAt !== null || record.dueAt === null) throw nothingScheduled(chatId);
1088
- const serverNow = runtime.now();
1089
- const shift = Math.max(0, Date.parse(record.dueAt) - serverNow);
1090
- if (shift > 0) {
1091
- timeOffset += shift;
1092
- await port.updateChatData(ownerId, chatId, { [FLOW_TEST_CHAT_KEY]: { timeOffset } });
1093
- await runtime.store.setDue(chatId, { at: new Date(serverNow).toISOString(), exitId: record.dueExitId ?? FLOW_FIRST_EXIT, branchHead: record.dueBranchHead });
1094
- }
1095
- let reason = null;
1096
- const unwatch = timers.watch(chatId, (fired) => reason ??= fired);
1097
- try {
1098
- await timers.tick();
1099
- await turnFinished(port, ownerId, chatId);
1100
- } finally {
1101
- unwatch();
1102
- }
1103
- if (reason) return { timeOffset, reason };
1104
- }
1105
- throw new FlowTestClockError("not_reached", `\u0427\u0430\u0442 ${chatId}: \u0441\u0440\u043E\u043A \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F \u043E\u0442\u043A\u043B\u0430\u0434\u044B\u0432\u0430\u043B\u0441\u044F ${NEXT_FIRST_MESSAGE_STEPS} \u0440\u0430\u0437 \u043F\u043E\u0434\u0440\u044F\u0434 \u2014 \u043F\u0435\u0440\u0435\u043C\u043E\u0442\u043A\u0430 \u043E\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u0430`);
1106
- }
1107
-
1108
- // src/runtime/flow-finish.ts
1109
- var FLOW_DEADLINE_NOTICE = "flow_deadline";
1110
- var DEADLINE_REASON = { kind: "timer", text: "\u0441\u0440\u043E\u043A \u0432\u044B\u0448\u0435\u043B" };
1111
- var FAREWELL_NOTICE = "\u0421\u0440\u043E\u043A \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u044B \u0432\u044B\u0448\u0435\u043B. \u041F\u043E\u043F\u0440\u043E\u0449\u0430\u0439\u0441\u044F \u0441 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u043E\u043C \u043E\u0434\u043D\u0438\u043C \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435\u043C: \u043A\u043E\u0440\u043E\u0442\u043A\u043E \u043F\u043E\u0434\u0432\u0435\u0434\u0438 \u0438\u0442\u043E\u0433 \u0438 \u0441\u043A\u0430\u0436\u0438, \u0447\u0442\u043E \u0434\u0430\u043B\u044C\u0448\u0435.";
1112
- function afterEndOf(flow) {
1113
- return flow.afterEnd ?? "reply";
1114
- }
1115
- var finalEndsChat = (flow) => flow.schedule !== void 0 || flow.afterEnd !== void 0;
1116
- function deadlineTransition(flow, run, at) {
1117
- const to = flow.schedule?.deadlineState;
1118
- const state = to === void 0 ? void 0 : stateById(flow, to);
1119
- if (!state || run.state === state.id) return null;
1120
- return { from: run.state, to: state.id, exitId: FLOW_DEADLINE_EXIT, decidedBy: "timer", tags: state.tags, at, reason: DEADLINE_REASON };
1121
- }
1122
- function endedRun(flow, run, ended) {
1123
- if (run.endedAt !== void 0) return run;
1124
- const transition = ended.endReason === "deadline" ? deadlineTransition(flow, run, ended.endedAt) : null;
1125
- const moved = transition ? applyTransition(flow, run, transition) : run;
1126
- return { ...moved, endedAt: ended.endedAt, endReason: ended.endReason };
1127
- }
1128
- function createFlowFinish(input) {
1129
- const { runtime } = input;
1130
- async function report(event) {
1131
- const { onFinish } = input;
1132
- if (!onFinish) return;
1133
- const { schedule } = event.pinned.flow;
1134
- let day = null;
1135
- if (schedule) {
1136
- const timeZone = await runtime.timeZones?.of(event.ownerId, event.chatId) ?? "UTC";
1137
- day = flowDay(event.run, event.at, timeZone, schedule).day;
1138
- if (schedule.lengthDays !== void 0) day = Math.min(day, schedule.lengthDays);
1139
- }
1140
- const { answerId: _answerId, firstReasons: _firstReasons, ...run } = event.run;
1141
- const finish = {
1142
- ownerId: event.ownerId,
1143
- chatId: event.chatId,
1144
- flowId: event.pinned.flowId,
1145
- versionId: event.pinned.versionId,
1146
- reason: event.reason,
1147
- ...event.outcome !== void 0 && { outcome: event.outcome },
1148
- day,
1149
- state: event.run.state,
1150
- tags: stateById(event.pinned.flow, event.run.state)?.tags ?? [],
1151
- run,
1152
- at: new Date(event.at)
1153
- };
1154
- const work = Promise.resolve().then(() => onFinish(finish)).catch((error) => runtime.logError(`[\u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439] \u0447\u0430\u0442=${event.chatId} onFinish \u0443\u043F\u0430\u043B: ${error instanceof Error ? error.message : String(error)}`));
1155
- if (runtime.track) runtime.track(work);
1156
- else await work;
1157
- }
1158
- async function close(chatId, reason, at) {
1159
- const before = await runtime.store.getChat(chatId);
1160
- if (!before || before.endedAt !== null) return false;
1161
- const after = await runtime.store.endChat(chatId, { reason, at: new Date(at).toISOString() });
1162
- return after !== null && after.endReason === reason && Date.parse(after.endedAt ?? "") === at;
1163
- }
1164
- return {
1165
- async afterTransitions({ ownerId, chatId, pinned, run, transitions }) {
1166
- const final = transitions.find((transition) => {
1167
- const state = stateById(pinned.flow, transition.to);
1168
- return state !== void 0 && isFinal(state);
1169
- });
1170
- if (!final) return;
1171
- if (finalEndsChat(pinned.flow) && !await close(chatId, "final", final.at)) return;
1172
- await report({ ownerId, chatId, pinned, run, reason: "final", at: final.at });
1173
- },
1174
- async deadline({ ownerId, chatId, pinned, run, at }) {
1175
- const ended = await close(chatId, "deadline", at);
1176
- const transition = deadlineTransition(pinned.flow, run, at);
1177
- let next = run;
1178
- if (ended && transition) {
1179
- next = applyTransition(pinned.flow, run, transition);
1180
- await runtime.afterTransitions({ ownerId, chatId, pinned, run: next, transitions: [transition] });
1181
- }
1182
- if (ended) await report({ ownerId, chatId, pinned, run: next, reason: "deadline", at });
1183
- return { run: endedRun(pinned.flow, next, { endedAt: at, endReason: "deadline" }), ended };
1184
- },
1185
- async farewell({ ownerId, chatId, pinned, at, timeZone, port, firstMessages, delivery }) {
1186
- const schedule = pinned.flow.schedule;
1187
- if (!schedule?.farewellOnDeadline) return;
1188
- const record = await runtime.store.getChat(chatId);
1189
- const chat = record ? { dayClosedOn: record.dayClosedOn, pausedUntil: record.pausedUntil, windowClosed: record.windowClosed } : void 0;
1190
- const allowed = firstMessages ? await firstMessages.check({ ownerId, chatId, at, timeZone, schedule, ...chat && { chat } }) : { allowed: true };
1191
- if (!allowed.allowed) return;
1192
- const text = schedule.farewellText?.trim();
1193
- const result = await port.deliverNotices({
1194
- ownerId,
1195
- chatId,
1196
- notices: [{ kind: "app", name: FLOW_DEADLINE_NOTICE, title: FAREWELL_NOTICE, data: { reasons: [{ kind: "farewell" }] } }],
1197
- wakeAgent: true,
1198
- deliveryKey: `flow:${chatId}:deadline`,
1199
- usageSource: "first_message",
1200
- maxServerTurnsInRow: false,
1201
- timeZone,
1202
- ...delivery?.own() && { awaitAnswer: true },
1203
- ...text && { reply: { text } }
1204
- });
1205
- if (result.status !== "delivered" || !result.turnStarted) return;
1206
- if (delivery) await delivery.afterFirstTurn({ ownerId, chatId, answer: result.answer, reasons: [{ kind: "farewell" }], at, timeZone });
1207
- else await firstMessages?.record({ ownerId, at, timeZone });
1208
- },
1209
- async end({ ownerId, chatId, pinned, run, reason, outcome, at }) {
1210
- const ended = await close(chatId, reason, at);
1211
- if (ended) await report({ ownerId, chatId, pinned, run, reason, ...outcome !== void 0 && { outcome }, at });
1212
- return { ended };
1213
- }
1214
- };
1215
- }
1216
-
1217
- // src/runtime/prepare-turn.ts
1218
- var FLOW_TIMER_NOTICE = "flow_timer";
1219
- var FLOW_EVENT_NOTICE = "flow_event";
1220
- var HUMAN_ACTIONS = /* @__PURE__ */ new Set(["send", "edit", "regenerate", "retry"]);
1221
- var transitionKey = (transition) => `${transition.from}\0${transition.exitId}`;
1222
- var errorText3 = (error) => error instanceof Error ? error.message : String(error);
1223
- var dataOf = (notice) => notice.data && typeof notice.data === "object" ? notice.data : {};
1224
- var firstReasonsOf = (notices) => notices.flatMap((notice) => {
1225
- if (notice.kind !== "app" || notice.name !== FLOW_TIMER_NOTICE && notice.name !== FLOW_DEADLINE_NOTICE) return [];
1226
- const { reasons } = dataOf(notice);
1227
- return Array.isArray(reasons) ? reasons : [];
1228
- });
1229
- function flowPrepareTurn(runtime, appTimeZone, finisher) {
1230
- return async (ctx) => {
1231
- if (ctx.audience === "group") return;
1232
- let pinned = await runtime.chatFlow(ctx.ownerId, ctx.chatId, ctx.chat);
1233
- if (!pinned) return;
1234
- const timeOffset = testChatOffset(ctx.chat.data);
1235
- const now = runtime.now() + (timeOffset ?? 0);
1236
- const transitions = [];
1237
- let card;
1238
- const applied = [];
1239
- const step = async (run2, event, out = transitions) => advance(pinned.flow, run2, event, {
1240
- now,
1241
- card: card ??= await runtime.cardValues(ctx.ownerId),
1242
- out,
1243
- onChainLimit: (stopped) => runtime.logError(chainLimitMessage(ctx.chatId, stopped)),
1244
- timeZone
1245
- });
1246
- const record = await runtime.store.getChat(ctx.chatId);
1247
- const page = pageTimeZone(ctx.timeZone, appTimeZone(), ctx.pageTimeZone);
1248
- const known = page ?? (runtime.timeZones ? await runtime.timeZones.known(ctx.ownerId, ctx.chatId) : record?.timeZone || null);
1249
- const timeZone = known ?? runtime.defaultTimeZone ?? ctx.timeZone;
1250
- let run = currentRun(pinned.flow, ctx.state, now);
1251
- const previousAnswer = run.answerId;
1252
- const pending = await runtime.store.takePending(ctx.chatId);
1253
- const appliedInTime2 = new Set(
1254
- pending.flatMap((change) => change.kind === "transition" && change.appliedAt !== void 0 && change.branchHead === previousAnswer ? [transitionKey(change.transition)] : [])
1255
- );
1256
- let restored = null;
1257
- const restore = () => restored ??= Promise.all(pending.map((change) => runtime.store.addPending(ctx.chatId, change)));
1258
- const onAbort = () => void restore().catch((error) => runtime.logError(`[\u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439] \u0447\u0430\u0442=${ctx.chatId} \u043E\u0436\u0438\u0434\u0430\u044E\u0449\u0435\u0435 \u043D\u0435 \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0435\u043D\u043E: ${errorText3(error)}`));
1259
- if (pending.length > 0) ctx.abortSignal.addEventListener("abort", onAbort, { once: true });
1260
- try {
1261
- return await applyTurn();
1262
- } catch (error) {
1263
- await restore();
1264
- throw error;
1265
- } finally {
1266
- ctx.abortSignal.removeEventListener("abort", onAbort);
1267
- }
1268
- async function applyTurn() {
1269
- const schedule = pinned.flow.schedule;
1270
- if (schedule) run = withDayAnchor(run, timeZone, schedule);
1271
- if (record?.endedAt) {
1272
- run = endedRun(pinned.flow, run, { endedAt: Date.parse(record.endedAt), endReason: record.endReason ?? "final" });
1273
- } else if (schedule && finisher) {
1274
- const deadline = deadlineAt(run, timeZone, schedule);
1275
- if (deadline !== null && deadline <= now) {
1276
- ({ run } = await finisher().deadline({ ownerId: ctx.ownerId, chatId: ctx.chatId, pinned, run, at: deadline, timeZone }));
1277
- }
1278
- }
1279
- const ended = run.endedAt !== void 0;
1280
- for (const change of ended ? [] : pending) {
1281
- if (change.kind === "migrate") {
1282
- const next = await runtime.chatFlow(ctx.ownerId, ctx.chatId);
1283
- if (next) {
1284
- run = { ...migrateRun(run, next.flow, change.map, now), answerId: previousAnswer };
1285
- pinned = next;
1286
- }
1287
- } else if (change.kind === "transition") {
1288
- if (change.branchHead !== previousAnswer || run.state !== change.transition.from) continue;
1289
- const out = [];
1290
- run = await step(run, pendingEvent(change.transition, timeZone), out);
1291
- for (const transition of out) (appliedInTime2.has(transitionKey(transition)) ? applied : transitions).push(transition);
1292
- } else {
1293
- run = await step(run, { type: "event", event: "app", name: change.name });
1294
- }
1295
- }
1296
- let touchBase = null;
1297
- for (const notice of ended ? [] : ctx.notices) {
1298
- if (notice.kind !== "app") continue;
1299
- const data = dataOf(notice);
1300
- if (notice.name === FLOW_TIMER_NOTICE) {
1301
- if (typeof data.undelivered === "string") run = withoutUndeliveredTouch(run, /* @__PURE__ */ new Set([data.undelivered])).run;
1302
- if (typeof data.exitId === "string") run = await step(run, { type: "timer", exitId: data.exitId, timeZone });
1303
- touchBase = { lastAgentAt: run.lastAgentAt, nudgeStep: run.nudgeStep ?? 0, ...run.nudgeStepOwn && { nudgeStepOwn: true }, agentAnswers: run.agentAnswers };
1304
- if (typeof data.nudgeStep === "number") run = withNudgeStep(run, data.nudgeStep, data.nudgeStepOwn === true);
1305
- } else if (notice.name === FLOW_EVENT_NOTICE && typeof data.name === "string") {
1306
- run = await step(run, { type: "event", event: "app", name: data.name });
1307
- }
1308
- }
1309
- if (!ctx.resumed && HUMAN_ACTIONS.has(ctx.action)) {
1310
- if (record?.windowClosed) await runtime.store.setWindowClosed(ctx.chatId, false);
1311
- run = noteHumanMessage(run, now, schedule ? dayInProgress(now, timeZone, schedule) : void 0, ctx.burstMessageIds?.length ?? 1);
1312
- if (!ended) run = await step(run, { type: "event", event: "message" });
1313
- }
1314
- if (ctx.action === "notice" && !ctx.resumed) run = { ...run, serverTurns: (run.serverTurns ?? 0) + 1 };
1315
- if (ctx.action !== "approval" && ctx.action !== "widget") run = noteAgentAnswer(run, now);
1316
- const { touch: earlierTouch, firstReasons: earlierReasons, ...withoutTouch } = run;
1317
- const continued = ctx.action === "approval" || ctx.action === "widget";
1318
- const touch = touchBase ? { answerId: ctx.messageId, at: now, ...touchBase } : continued ? earlierTouch : void 0;
1319
- const reasons = firstReasonsOf(ctx.notices);
1320
- const firstReasons = reasons.length > 0 ? reasons : continued ? earlierReasons : void 0;
1321
- run = { ...withoutTouch, answerId: ctx.messageId, ...timeOffset !== null && { timeOffset }, ...touch && { touch }, ...firstReasons && { firstReasons } };
1322
- if (ctx.abortSignal.aborted) {
1323
- await restore();
1324
- return void 0;
1325
- }
1326
- if (known && runtime.timeZones) await runtime.timeZones.write(ctx.ownerId, ctx.chatId, known);
1327
- else if (record && page && record.timeZone !== page) await runtime.store.updateChat(ctx.chatId, { timeZone: page }, new Date(runtime.now()).toISOString());
1328
- await runtime.afterTransitions({ ownerId: ctx.ownerId, chatId: ctx.chatId, pinned, run, transitions });
1329
- return {
1330
- set: { [FLOW_STATE_KEY]: run },
1331
- ...applied.length + transitions.length > 0 && { notices: [transitionNotice(pinned.flow, [...applied, ...transitions])] }
1332
- };
1333
- }
1334
- };
1335
- }
1336
-
1337
- // src/runtime/first-reasons-notice.ts
1338
- var REASON_LINES = {
1339
- morning: "\u041D\u0430\u0447\u0430\u043B\u0441\u044F \u043D\u043E\u0432\u044B\u0439 \u0434\u0435\u043D\u044C \u0441\u0446\u0435\u043D\u0430\u0440\u0438\u044F: \u0443\u043C\u0435\u0441\u0442\u043D\u043E \u0434\u043E\u0431\u0440\u043E\u0435 \u0443\u0442\u0440\u043E.",
1340
- silence: (step) => `\u0427\u0435\u043B\u043E\u0432\u0435\u043A \u043C\u043E\u043B\u0447\u0438\u0442 \u043F\u043E\u0441\u043B\u0435 \u0442\u0432\u043E\u0435\u0433\u043E \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F (\u043A\u0430\u0441\u0430\u043D\u0438\u0435 ${step}).`,
1341
- daily: (at) => `\u041A\u0430\u0441\u0430\u043D\u0438\u0435 \u043F\u043E \u0440\u0430\u0441\u043F\u0438\u0441\u0430\u043D\u0438\u044E, ${at}.`,
1342
- nightMessages: (count) => `\u0427\u0435\u043B\u043E\u0432\u0435\u043A \u043D\u0430\u043A\u043E\u043F\u0438\u043B \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F \u0431\u0435\u0437 \u043E\u0442\u0432\u0435\u0442\u0430 (${count}): \u043E\u0442\u0432\u0435\u0442\u044C \u043D\u0430 \u043D\u0438\u0445.`
1343
- };
1344
- var TASK = "\u0422\u044B \u043F\u0438\u0448\u0435\u0448\u044C \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443 \u043F\u0435\u0440\u0432\u044B\u043C. \u041D\u0430\u043F\u0438\u0448\u0438 \u043E\u0434\u043D\u043E \u043A\u043E\u0440\u043E\u0442\u043A\u043E\u0435 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435: \u043D\u043E\u0432\u043E\u0435 \u0438 \u043F\u043E\u043B\u0435\u0437\u043D\u043E\u0435 \u0434\u043B\u044F \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 \u043F\u043E \u0442\u0435\u043C\u0435 \u0440\u0430\u0437\u0433\u043E\u0432\u043E\u0440\u0430, \u0431\u0435\u0437 \u043F\u043E\u0432\u0442\u043E\u0440\u0430 \u0443\u0436\u0435 \u0441\u043A\u0430\u0437\u0430\u043D\u043D\u043E\u0433\u043E \u0438 \u0431\u0435\u0437 \u0443\u043F\u0440\u0451\u043A\u043E\u0432 \u0437\u0430 \u043C\u043E\u043B\u0447\u0430\u043D\u0438\u0435.";
1345
- var transitionLine = (flow, exitId) => {
1346
- const exit = exitById(flow, exitId);
1347
- return `\u0421\u0440\u0430\u0431\u043E\u0442\u0430\u043B\u043E: ${exit ? describeCondition(flow, exit.when) : exitId}`;
1348
- };
1349
- function reasonLine(reason) {
1350
- switch (reason.kind) {
1351
- case "morning":
1352
- return REASON_LINES.morning;
1353
- case "silence":
1354
- return REASON_LINES.silence(reason.step);
1355
- case "daily":
1356
- return REASON_LINES.daily(reason.at);
1357
- case "night_messages":
1358
- return REASON_LINES.nightMessages(reason.count);
1359
- default:
1360
- return null;
1361
- }
1362
- }
1363
- function firstReasonsNotice(flow, reasons, exitId, ownNudge = false) {
1364
- const silence = reasons.find((reason) => reason.kind === "silence");
1365
- const moved = exitId !== null && reasons.some((reason) => reason.kind === "transition");
1366
- const morning = reasons.some((reason) => reason.kind === "morning");
1367
- const nudgeStep = moved || morning ? 0 : silence?.kind === "silence" ? silence.step : void 0;
1368
- const own = ownNudge && silence !== void 0 && !moved && !morning;
1369
- const data = { ...moved && { exitId }, reasons: [...reasons], ...nudgeStep !== void 0 && { nudgeStep }, ...own && { nudgeStepOwn: true } };
1370
- const others = reasons.flatMap((reason) => reasonLine(reason) ?? []);
1371
- if (others.length === 0 && moved) return { kind: "app", name: FLOW_TIMER_NOTICE, title: transitionLine(flow, exitId), data };
1372
- const lines = [...moved ? [`${transitionLine(flow, exitId)}.`] : [], ...others, TASK];
1373
- return { kind: "app", name: FLOW_TIMER_NOTICE, title: lines.join("\n"), data };
1374
- }
1375
-
1376
807
  // src/runtime/flow-delivery.ts
1377
808
  import { answerText, ChatNotFoundError, deliverableParts } from "@ykurilov/agent-chat-core";
1378
809
  var FLOW_DELIVERY_EXIT = "@delivery";
1379
810
  var RETRY_DELAYS_MS = [6e4, 5 * 6e4, 30 * 6e4];
1380
- var errorText4 = (error) => error instanceof Error ? error.message : String(error);
811
+ var errorText3 = (error) => error instanceof Error ? error.message : String(error);
1381
812
  var isoOf = (at) => new Date(at).toISOString();
1382
813
  var hasContent = (answer) => answer.text.trim() !== "" || answer.parts.some((part) => part.type !== "text");
1383
814
  function createFlowDelivery(input) {
@@ -1392,7 +823,7 @@ function createFlowDelivery(input) {
1392
823
  await (await portOf({ ownerId, chatId })).markUndelivered({ ownerId, chatId, messageId });
1393
824
  } catch (error) {
1394
825
  if (error instanceof ChatNotFoundError) return;
1395
- runtime.logError(`[\u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439] \u0447\u0430\u0442=${chatId} \u043F\u043E\u043C\u0435\u0442\u043A\u0430 \xAB\u043D\u0435 \u0434\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u043E\xBB \u043D\u0435 \u0437\u0430\u043F\u0438\u0441\u0430\u043D\u0430: ${errorText4(error)}`);
826
+ runtime.logError(`[\u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439] \u0447\u0430\u0442=${chatId} \u043F\u043E\u043C\u0435\u0442\u043A\u0430 \xAB\u043D\u0435 \u0434\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u043E\xBB \u043D\u0435 \u0437\u0430\u043F\u0438\u0441\u0430\u043D\u0430: ${errorText3(error)}`);
1396
827
  }
1397
828
  }
1398
829
  async function blocked(ownerId, chatId) {
@@ -1444,7 +875,7 @@ function createFlowDelivery(input) {
1444
875
  try {
1445
876
  return await deliver(message);
1446
877
  } catch (error) {
1447
- runtime.logError(`[\u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439] \u0447\u0430\u0442=${message.chatId} \u0434\u043E\u0441\u0442\u0430\u0432\u043A\u0430 \u0443\u043F\u0430\u043B\u0430: ${errorText4(error)}`);
878
+ runtime.logError(`[\u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439] \u0447\u0430\u0442=${message.chatId} \u0434\u043E\u0441\u0442\u0430\u0432\u043A\u0430 \u0443\u043F\u0430\u043B\u0430: ${errorText3(error)}`);
1448
879
  return { status: "retry" };
1449
880
  }
1450
881
  }
@@ -1520,7 +951,7 @@ var TIMER_BATCH = 50;
1520
951
  var TIMER_PARALLEL = 5;
1521
952
  var DAY_MS = 864e5;
1522
953
  var DEFAULT_FLOW_SERVER_TURNS_IN_ROW = 50;
1523
- var errorText5 = (error) => error instanceof Error ? error.message : String(error);
954
+ var errorText4 = (error) => error instanceof Error ? error.message : String(error);
1524
955
  var isoOf2 = (at) => new Date(at).toISOString();
1525
956
  var timerKey = (chatId, exitId, run) => `flow:${chatId}:${exitId}:${run.enteredAt}`;
1526
957
  async function historyFacts(port, ownerId, chatId, answerId) {
@@ -1727,7 +1158,7 @@ function createFlowTimers(input) {
1727
1158
  await defer(flow.schedule ? nextDayStartAfter(at, timeZone, flow.schedule) : at + DAY_MS);
1728
1159
  return;
1729
1160
  }
1730
- const reasonsNotice = firstReasonsNotice(flow, reasons, moved ? due.exitId : null, due.ownNudge);
1161
+ const reasonsNotice = firstReasonsNotice(flow, reasons, moved ? due.exitId : null, due.ownNudge, silentMsOf(run, at));
1731
1162
  const notice = undelivered ? { ...reasonsNotice, data: { ...reasonsNotice.data, undelivered } } : reasonsNotice;
1732
1163
  const reply = moved ? exactFirstText(flow, next.state) : null;
1733
1164
  const delivery = input.delivery?.();
@@ -1772,7 +1203,7 @@ function createFlowTimers(input) {
1772
1203
  try {
1773
1204
  if (!await renew(record.chatId)) return;
1774
1205
  const heartbeat = setInterval(() => {
1775
- renew(record.chatId).catch((error) => logError(`[\u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439] \u0447\u0430\u0442=${record.chatId} \u0430\u0440\u0435\u043D\u0434\u0430 \u043D\u0435 \u043F\u0440\u043E\u0434\u043B\u0435\u043D\u0430: ${errorText5(error)}`));
1206
+ renew(record.chatId).catch((error) => logError(`[\u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439] \u0447\u0430\u0442=${record.chatId} \u0430\u0440\u0435\u043D\u0434\u0430 \u043D\u0435 \u043F\u0440\u043E\u0434\u043B\u0435\u043D\u0430: ${errorText4(error)}`));
1776
1207
  }, leaseMs / 3);
1777
1208
  heartbeat.unref?.();
1778
1209
  try {
@@ -1781,7 +1212,7 @@ function createFlowTimers(input) {
1781
1212
  clearInterval(heartbeat);
1782
1213
  }
1783
1214
  } catch (error) {
1784
- logError(`[\u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439] \u0447\u0430\u0442=${record.chatId} \u0442\u0430\u0439\u043C\u0435\u0440 \u043D\u0435 \u0441\u0440\u0430\u0431\u043E\u0442\u0430\u043B: ${errorText5(error)}`);
1215
+ logError(`[\u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439] \u0447\u0430\u0442=${record.chatId} \u0442\u0430\u0439\u043C\u0435\u0440 \u043D\u0435 \u0441\u0440\u0430\u0431\u043E\u0442\u0430\u043B: ${errorText4(error)}`);
1785
1216
  }
1786
1217
  }
1787
1218
  async function tickOnce() {
@@ -1803,7 +1234,7 @@ function createFlowTimers(input) {
1803
1234
  start() {
1804
1235
  if (interval) return;
1805
1236
  interval = setInterval(() => {
1806
- tick().catch((error) => logError(`[\u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439] \u043E\u0431\u0445\u043E\u0434 \u0442\u0430\u0439\u043C\u0435\u0440\u043E\u0432 \u0443\u043F\u0430\u043B: ${errorText5(error)}`));
1237
+ tick().catch((error) => logError(`[\u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439] \u043E\u0431\u0445\u043E\u0434 \u0442\u0430\u0439\u043C\u0435\u0440\u043E\u0432 \u0443\u043F\u0430\u043B: ${errorText4(error)}`));
1807
1238
  }, tickMs);
1808
1239
  interval.unref?.();
1809
1240
  },
@@ -2425,7 +1856,7 @@ var DELIVERY_RETRY_MS = [50, 250, 1e3, 3e3];
2425
1856
  var KNOWN_FLOWS_LIMIT = 1e4;
2426
1857
  var KNOWN_PORTS_LIMIT = 1e4;
2427
1858
  var SERVER_UNKNOWN_CODES = /* @__PURE__ */ new Set(["unknown_event"]);
2428
- var errorText6 = (error) => error instanceof Error ? error.message : String(error);
1859
+ var errorText5 = (error) => error instanceof Error ? error.message : String(error);
2429
1860
  var pause = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
2430
1861
  function stableJson(value) {
2431
1862
  if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
@@ -2500,7 +1931,7 @@ function buildAgentFlow(options, modules = {}) {
2500
1931
  try {
2501
1932
  return make();
2502
1933
  } catch (error) {
2503
- logError(`[\u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439] ${name} \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D: ${errorText6(error)}`);
1934
+ logError(`[\u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439] ${name} \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D: ${errorText5(error)}`);
2504
1935
  return null;
2505
1936
  }
2506
1937
  });
@@ -2565,7 +1996,7 @@ function buildAgentFlow(options, modules = {}) {
2565
1996
  );
2566
1997
  const background = /* @__PURE__ */ new Set();
2567
1998
  function track(work) {
2568
- const tracked = work.catch((error) => logError(`[\u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439] \u0444\u043E\u043D\u043E\u0432\u0430\u044F \u0440\u0430\u0431\u043E\u0442\u0430 \u0443\u043F\u0430\u043B\u0430: ${errorText6(error)}`)).finally(() => background.delete(tracked));
1999
+ const tracked = work.catch((error) => logError(`[\u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439] \u0444\u043E\u043D\u043E\u0432\u0430\u044F \u0440\u0430\u0431\u043E\u0442\u0430 \u0443\u043F\u0430\u043B\u0430: ${errorText5(error)}`)).finally(() => background.delete(tracked));
2569
2000
  background.add(tracked);
2570
2001
  }
2571
2002
  const known = /* @__PURE__ */ new Map();
@@ -2737,7 +2168,7 @@ function buildAgentFlow(options, modules = {}) {
2737
2168
  return Object.fromEntries(entries.map((entry) => [entry.fieldId, entry.value]));
2738
2169
  } catch (error) {
2739
2170
  if (!app) throw error;
2740
- logError(`[\u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439] \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0430 \u043A\u043B\u0438\u0435\u043D\u0442\u0430 \u043D\u0435 \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u043D\u0430: ${errorText6(error)}`);
2171
+ logError(`[\u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439] \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0430 \u043A\u043B\u0438\u0435\u043D\u0442\u0430 \u043D\u0435 \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u043D\u0430: ${errorText5(error)}`);
2741
2172
  return {};
2742
2173
  }
2743
2174
  },
@@ -2746,7 +2177,7 @@ function buildAgentFlow(options, modules = {}) {
2746
2177
  try {
2747
2178
  await store.updateChat(chatId, { stateId: run.state }, iso());
2748
2179
  } catch (error) {
2749
- logError(`[\u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439] \u0447\u0430\u0442=${chatId} \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435 \u043D\u0435 \u0437\u0430\u043F\u0438\u0441\u0430\u043D\u043E \u0432 \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0435: ${errorText6(error)}`);
2180
+ logError(`[\u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439] \u0447\u0430\u0442=${chatId} \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435 \u043D\u0435 \u0437\u0430\u043F\u0438\u0441\u0430\u043D\u043E \u0432 \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0435: ${errorText5(error)}`);
2750
2181
  }
2751
2182
  const { schedule } = pinned.flow;
2752
2183
  const timeZone = schedule ? await timeZones.of(ownerId, chatId) : null;
@@ -2779,7 +2210,7 @@ function buildAgentFlow(options, modules = {}) {
2779
2210
  try {
2780
2211
  await optionalTimers()?.reschedule({ ownerId, chatId, run, branchHead, ...failedAt !== void 0 && { failedAt } });
2781
2212
  } catch (error) {
2782
- logError(`[\u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439] \u0447\u0430\u0442=${chatId} \u0442\u0430\u0439\u043C\u0435\u0440 \u043D\u0435 \u043F\u0435\u0440\u0435\u0441\u0447\u0438\u0442\u0430\u043D: ${errorText6(error)}`);
2213
+ logError(`[\u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439] \u0447\u0430\u0442=${chatId} \u0442\u0430\u0439\u043C\u0435\u0440 \u043D\u0435 \u043F\u0435\u0440\u0435\u0441\u0447\u0438\u0442\u0430\u043D: ${errorText5(error)}`);
2783
2214
  }
2784
2215
  }
2785
2216
  async function rescheduleUndelivered({ ownerId, chatId, at }) {
@@ -2803,7 +2234,7 @@ function buildAgentFlow(options, modules = {}) {
2803
2234
  if (!run) return;
2804
2235
  await reschedule(record.ownerId, record.chatId, migrateRun(run, flow, map, chatTime(run, now())), run.answerId ?? null);
2805
2236
  } catch (error) {
2806
- logError(`[\u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439] \u0447\u0430\u0442=${record.chatId} \u0442\u0430\u0439\u043C\u0435\u0440 \u043D\u0435 \u043F\u0435\u0440\u0435\u0441\u0447\u0438\u0442\u0430\u043D: ${errorText6(error)}`);
2237
+ logError(`[\u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439] \u0447\u0430\u0442=${record.chatId} \u0442\u0430\u0439\u043C\u0435\u0440 \u043D\u0435 \u043F\u0435\u0440\u0435\u0441\u0447\u0438\u0442\u0430\u043D: ${errorText5(error)}`);
2807
2238
  }
2808
2239
  }
2809
2240
  async function deliverFirstText(ownerId, chatId, messageId, condition, text) {
@@ -2925,7 +2356,7 @@ function buildAgentFlow(options, modules = {}) {
2925
2356
  await store.updateChat(chatId, { placement: null }, iso());
2926
2357
  } catch (error) {
2927
2358
  placedNow.add(chatId);
2928
- logError(`[\u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439] \u0447\u0430\u0442=${chatId} \u0437\u0430\u043F\u0438\u0441\u044C \u043F\u0435\u0440\u0435\u043D\u043E\u0441\u0430 \u043D\u0435 \u0441\u043D\u044F\u0442\u0430: ${errorText6(error)}`);
2359
+ logError(`[\u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439] \u0447\u0430\u0442=${chatId} \u0437\u0430\u043F\u0438\u0441\u044C \u043F\u0435\u0440\u0435\u043D\u043E\u0441\u0430 \u043D\u0435 \u0441\u043D\u044F\u0442\u0430: ${errorText5(error)}`);
2929
2360
  }
2930
2361
  }
2931
2362
  async function readRun(ownerId, chatId) {
@@ -2959,6 +2390,8 @@ function buildAgentFlow(options, modules = {}) {
2959
2390
  ...chat,
2960
2391
  // Место в сценарии — служебное: посетитель его не видит, редактор и тестовый чат читают `readRun`.
2961
2392
  privateStateKeys: [.../* @__PURE__ */ new Set([...chat.privateStateKeys ?? [], FLOW_STATE_KEY])],
2393
+ // Строки «Агент написал первым» на экране (право `appNotices`): только проекция, сырые данные пометок не уходят.
2394
+ appNoticeViews: { ...chat.appNoticeViews, ...FLOW_APP_NOTICE_VIEWS },
2962
2395
  beforeTurn: async (input) => {
2963
2396
  const own = await chat.beforeTurn?.(input);
2964
2397
  return own ?? gate(input);
@@ -3027,7 +2460,7 @@ ${rules}`;
3027
2460
  try {
3028
2461
  await store.updateChat(input.chatId, { stateId: run.state }, iso());
3029
2462
  } catch (error) {
3030
- logError(`[\u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439] \u0447\u0430\u0442=${input.chatId} \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435 \u043D\u0435 \u0437\u0430\u043F\u0438\u0441\u0430\u043D\u043E \u0432 \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0435: ${errorText6(error)}`);
2463
+ logError(`[\u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439] \u0447\u0430\u0442=${input.chatId} \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435 \u043D\u0435 \u0437\u0430\u043F\u0438\u0441\u0430\u043D\u043E \u0432 \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0435: ${errorText5(error)}`);
3031
2464
  }
3032
2465
  await reschedule(input.ownerId, input.chatId, run, input.atMessageId);
3033
2466
  })();