@ykurilov/agent-chat-flows 0.66.0 → 0.68.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/agent-flow.schema.json +12 -0
  3. package/dist/{chunk-7VR4YNTJ.js → chunk-2LAVG3YR.js} +42 -9
  4. package/dist/chunk-2LAVG3YR.js.map +1 -0
  5. package/dist/{chunk-KRZMJJKG.js → chunk-DQQ2GCQ2.js} +22 -11
  6. package/dist/chunk-DQQ2GCQ2.js.map +1 -0
  7. package/dist/{chunk-L7XNC3RB.js → chunk-PLY57QT5.js} +2 -2
  8. package/dist/format.js +2 -2
  9. package/dist/index.js +63 -7
  10. package/dist/index.js.map +1 -1
  11. package/dist/postgres.js +7 -0
  12. package/dist/postgres.js.map +1 -1
  13. package/dist/react.js +51 -9
  14. package/dist/react.js.map +1 -1
  15. package/dist/sqlite.js +6 -0
  16. package/dist/sqlite.js.map +1 -1
  17. package/dist/types/engine/flow-run.d.ts +4 -2
  18. package/dist/types/engine/nudges.d.ts +1 -1
  19. package/dist/types/engine/run-updates.d.ts +5 -0
  20. package/dist/types/format/flow-format.d.ts +10 -0
  21. package/dist/types/format/flow-schema.d.ts +6 -0
  22. package/dist/types/labels/editor.d.ts +5 -1
  23. package/dist/types/react/editor/index.d.ts +1 -1
  24. package/dist/types/react/editor/schedule-model.d.ts +9 -1
  25. package/dist/types/react/flow-editor-skin.d.ts +3 -0
  26. package/dist/types/runtime/first-message-rules.d.ts +2 -0
  27. package/dist/types/runtime/flow-events.d.ts +6 -1
  28. package/dist/types/runtime/flow-types.d.ts +52 -0
  29. package/dist/types/store/flow-store.d.ts +10 -0
  30. package/dist/types/store/postgres-schema.d.ts +17 -0
  31. package/dist/types/store/sqlite-schema.d.ts +17 -0
  32. package/drizzle/postgres/0003_chat_reopen.sql +1 -0
  33. package/drizzle/postgres/meta/0003_snapshot.json +451 -0
  34. package/drizzle/postgres/meta/_journal.json +7 -0
  35. package/drizzle/sqlite/0003_chat_reopen.sql +1 -0
  36. package/drizzle/sqlite/meta/0003_snapshot.json +441 -0
  37. package/drizzle/sqlite/meta/_journal.json +7 -0
  38. package/package.json +4 -4
  39. package/dist/chunk-7VR4YNTJ.js.map +0 -1
  40. package/dist/chunk-KRZMJJKG.js.map +0 -1
  41. /package/dist/{chunk-L7XNC3RB.js.map → chunk-PLY57QT5.js.map} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # @ykurilov/agent-chat-flows
2
2
 
3
+ ## 0.68.0
4
+
5
+ ### Minor Changes
6
+
7
+ - d7fc4e6: flow.reopen: брошенный разговор (`abandoned`) или законченный своей причиной приложения открывается заново в той же ноде с памятью; касания с первого шага, дни программы от исходного старта; событие onReopen; поле reopened_at (миграции SQLite и PostgreSQL).
8
+
9
+ ### Patch Changes
10
+
11
+ - @ykurilov/agent-chat-core@0.68.0
12
+ - @ykurilov/agent-chat-react@0.68.0
13
+
14
+ ## 0.67.0
15
+
16
+ ### Minor Changes
17
+
18
+ - 12c0dd8: Потолок «пишет первым» по дням программы: `schedule.firstMessages.maxPerDayByDay` (`[3, 2]` — день 1 три, со дня 2 по
19
+ два; главнее `maxPerDay`; ответ человека счёт не обнуляет). Свои касания ноды до N-го дня программы:
20
+ `nudges.untilProgramDay` (дошёл до ноды позже — сразу общий ряд). `checkFlow`: `nudges_until_day_invalid`,
21
+ `nudges_until_day_after_end`, `max_per_day_by_day_after_end`. Доска: поле «по дням программы» и режим «до дня программы»
22
+ (ru/en); `FlowStateTimingProps` + `nudgesUntilProgramDay`, `onNudgesUntilProgramDayChange`; выгружены `parseCapsByDay`,
23
+ `capsByDayText`.
24
+
25
+ ### Patch Changes
26
+
27
+ - @ykurilov/agent-chat-core@0.67.0
28
+ - @ykurilov/agent-chat-react@0.67.0
29
+
3
30
  ## 0.66.0
4
31
 
5
32
  ### Patch Changes
@@ -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
  },
@@ -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 entryDay = flowDay(run, run.enteredAt, timeZone, schedule2).day;
584
- return { ring: own, until: programDayDue(run, entryDay + own.days, timeZone, schedule2), after: common };
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];
@@ -589,7 +592,7 @@ var DEFAULT_SKIP_MORNING_MIN = 180;
589
592
  function nextNudge(flow, run, now, timeZone, context = {}) {
590
593
  const rings = nudgesRunning(flow, run, timeZone, context);
591
594
  if (!rings || run.lastAgentAt === null) return null;
592
- const base = Math.max(run.lastAgentAt, context.pausedUntil ?? 0, context.undeliveredAt ?? 0);
595
+ const base = Math.max(run.lastAgentAt, context.pausedUntil ?? 0, context.undeliveredAt ?? 0, run.reopenedAt ?? 0);
593
596
  const step = run.nudgeStep ?? 0;
594
597
  let nudge = null;
595
598
  if (rings.until === void 0) nudge = ringNudge(rings.ring, base, step, timeZone);
@@ -623,14 +626,14 @@ function nudgesRunning(flow, run, timeZone, context) {
623
626
  function giveUpAt(flow, run, timeZone, context = {}) {
624
627
  const rings = nudgesRunning(flow, run, timeZone, context);
625
628
  const giveUpAfter = rings && (rings.ring.giveUpAfter ?? (rings.until !== void 0 ? rings.after?.giveUpAfter : void 0));
626
- return giveUpAfter ? Math.max(run.lastHumanAt ?? run.startedAt, context.pausedUntil ?? 0) + durationMs(giveUpAfter) : null;
629
+ return giveUpAfter ? Math.max(run.lastHumanAt ?? run.startedAt, context.pausedUntil ?? 0, run.reopenedAt ?? 0) + durationMs(giveUpAfter) : null;
627
630
  }
628
631
  var morningOn = (schedule2) => schedule2.firstMessages?.morning ?? schedule2.lengthDays !== void 0;
629
632
  function nextMorning(flow, run, timeZone, context = {}) {
630
633
  const schedule2 = flow.schedule;
631
634
  if (!schedule2 || !morningOn(schedule2) || run.endedAt !== void 0) return null;
632
635
  const skipMs = (schedule2.firstMessages?.skipMorningIfHumanWithinMin ?? DEFAULT_SKIP_MORNING_MIN) * 6e4;
633
- const since = Math.max(run.lastAgentAt ?? run.startedAt, context.undeliveredAt ?? 0);
636
+ const since = Math.max(run.lastAgentAt ?? run.startedAt, context.undeliveredAt ?? 0, run.reopenedAt ?? 0);
634
637
  let morning = flowDay(run, since, timeZone, schedule2).nextDayStartAt;
635
638
  for (let day = 0; day < 3; day += 1) {
636
639
  const humanJustWrote = run.lastHumanAt !== null && run.lastHumanAt < morning && morning - run.lastHumanAt < skipMs;
@@ -670,7 +673,7 @@ function timerDueAt(condition, run, timeZone, schedule2) {
670
673
  case "silence":
671
674
  if (run.lastAgentAt === null) return null;
672
675
  if (run.lastHumanAt !== null && run.lastHumanAt > run.lastAgentAt) return null;
673
- return run.lastAgentAt + condition.amount * UNIT_MS3[condition.unit];
676
+ return Math.max(run.lastAgentAt, run.reopenedAt ?? 0) + condition.amount * UNIT_MS3[condition.unit];
674
677
  case "time_of_day": {
675
678
  const minutes = parseClock(condition.at);
676
679
  return minutes === null ? null : nextClockTime(actualEntry(run), minutes, timeZone);
@@ -905,6 +908,20 @@ function applyTransition(flow, run, transition) {
905
908
  enteredAfterAnswer: run.answerId
906
909
  };
907
910
  }
911
+ function reopenRun(flow, run, at) {
912
+ const { endedAt: _endedAt, endReason: _endReason, nudgeStepOwn: _nudgeStepOwn, touch: _touch, ...live } = run;
913
+ const tags = stateById(flow, run.state)?.tags ?? [];
914
+ return {
915
+ ...live,
916
+ reopenedAt: at,
917
+ // Часы ноды — от открытия, как будто человек только что вошёл; дни программы — от исходного старта.
918
+ enteredAt: at,
919
+ nudgeStep: 0,
920
+ serverTurns: 0,
921
+ chain: 0,
922
+ path: appendPath(run.path, { state: run.state, at, tags, from: run.state, exitId: null, decidedBy: "reopen" })
923
+ };
924
+ }
908
925
  function noteHumanMessage(run, now, dayKey, count = 1) {
909
926
  return {
910
927
  ...run,
@@ -1211,6 +1228,14 @@ function checkState(flow, catalog, issues, state) {
1211
1228
  if (days !== void 0 && (!Number.isInteger(days) || days < 1)) {
1212
1229
  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
1230
  }
1231
+ const untilDay = state.nudges && state.nudges !== "off" ? state.nudges.untilProgramDay : void 0;
1232
+ if (untilDay !== void 0 && (!Number.isInteger(untilDay) || untilDay < 1)) {
1233
+ 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 });
1234
+ } else if (untilDay !== void 0 && flow.schedule?.lengthDays !== void 0 && untilDay > flow.schedule.lengthDays) {
1235
+ 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`, {
1236
+ stateId: state.id
1237
+ });
1238
+ }
1214
1239
  }
1215
1240
  var nudgesEmpty = (nudges2) => nudges2.afterSilence.length === 0 && !nudges2.dailyAt?.length;
1216
1241
  function checkSchedule(flow, issues) {
@@ -1230,6 +1255,13 @@ function checkSchedule(flow, issues) {
1230
1255
  if (frame?.softFrom !== void 0 && frame.hardAt !== void 0 && frame.softFrom >= frame.hardAt) {
1231
1256
  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
1257
  }
1258
+ const byDay = schedule2.firstMessages?.maxPerDayByDay;
1259
+ if (byDay && schedule2.lengthDays !== void 0 && byDay.length > schedule2.lengthDays) {
1260
+ issues.warning(
1261
+ "max_per_day_by_day_after_end",
1262
+ `\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`
1263
+ );
1264
+ }
1233
1265
  if (schedule2.nudges && nudgesEmpty(schedule2.nudges)) {
1234
1266
  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
1267
  }
@@ -1373,6 +1405,7 @@ export {
1373
1405
  nextTransition,
1374
1406
  startRun,
1375
1407
  applyTransition,
1408
+ reopenRun,
1376
1409
  noteHumanMessage,
1377
1410
  noteAgentAnswer,
1378
1411
  withoutUndeliveredTouch,
@@ -1393,4 +1426,4 @@ export {
1393
1426
  appIssues,
1394
1427
  checkFlow
1395
1428
  };
1396
- //# sourceMappingURL=chunk-7VR4YNTJ.js.map
1429
+ //# sourceMappingURL=chunk-2LAVG3YR.js.map