@epam/ai-dial-chat-hooks 1.2.0-dev.265 → 1.2.0-dev.268

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.
@@ -23,15 +23,15 @@ var c = (e) => {
23
23
  clearTimeout(i), n && window.removeEventListener("online", r), t();
24
24
  }, i = setTimeout(r, e);
25
25
  n && window.addEventListener("online", r);
26
- }), h = async (e, t) => {
27
- for (let n = 0; n <= p.length; n++) {
26
+ }), h = async (e, t, n) => {
27
+ for (let r = 0; r <= p.length; r++) {
28
28
  if (t()) return null;
29
29
  try {
30
- return await e();
31
- } catch {
32
- if (n === p.length) return null;
33
- await m(p[n]);
34
- }
30
+ let t = await e();
31
+ if (!n?.(t)) return t;
32
+ } catch {}
33
+ if (r === p.length) return null;
34
+ await m(p[r]);
35
35
  }
36
36
  return null;
37
37
  }, g = async (e, t) => {
@@ -130,6 +130,13 @@ var c = (e) => {
130
130
  await I();
131
131
  return;
132
132
  }
133
+ try {
134
+ let i = await o.getConversation(e(t));
135
+ if (!u(i)) {
136
+ n.abort(), r.cancel().catch(() => void 0), F(i);
137
+ return;
138
+ }
139
+ } catch {}
133
140
  let i = !1, a = window.setTimeout(() => {
134
141
  n.abort();
135
142
  }, d);
@@ -3,155 +3,155 @@ import { DEFAULT_GENERATION_CONFLICT_MESSAGE as t, DEFAULT_GENERATION_PERSISTENC
3
3
  import { getConversationPath as s } from "./conversation-path.js";
4
4
  import { applyChunkToMessages as c } from "./apply-chunk.js";
5
5
  import { restoreBufferedMessage as l } from "./buffered-generation.js";
6
- import { createResumeIfAwaitingGeneration as ee, fetchConversationForRecovery as te, findPendingBackgroundMessageIndex as ne, hasGeneratedPayload as re, isAwaitingGenerationResume as u } from "./generation-resume.js";
7
- import { createFrameScheduler as d } from "./frame-scheduler.js";
8
- import { MessageRole as ie, generateUUID as ae } from "@epam/ai-dial-chat-shared";
9
- import { useCallback as f, useEffect as p, useMemo as m, useRef as h, useState as g } from "react";
10
- import { SendCompletionDtoModeEnum as _ } from "@epam/ai-dial-chat-api-client";
6
+ import { createResumeIfAwaitingGeneration as ee, fetchConversationForRecovery as te, findPendingBackgroundMessageIndex as u, hasGeneratedPayload as ne, isAwaitingGenerationResume as d } from "./generation-resume.js";
7
+ import { createFrameScheduler as re } from "./frame-scheduler.js";
8
+ import { MessageRole as f, generateUUID as ie } from "@epam/ai-dial-chat-shared";
9
+ import { useCallback as p, useEffect as m, useMemo as ae, useRef as h, useState as g } from "react";
10
+ import { SendCompletionDtoModeEnum as oe } from "@epam/ai-dial-chat-api-client";
11
11
  //#region src/conversation/useConversationStream/useConversationStream.ts
12
- var oe = 2e4, se = (e, t, n) => e instanceof i ? n : e instanceof r ? t : e instanceof o ? e.message : "", v = (e) => {
12
+ var se = 2e4, ce = (e, t, n) => e instanceof i ? n : e instanceof r ? t : e instanceof o ? e.message : "", _ = (e) => {
13
13
  if (!e) return;
14
- let t = ne(e);
14
+ let t = u(e);
15
15
  return t === -1 ? void 0 : e.messages[t].backgroundGeneration?.generationId;
16
- }, y = ({ conversationId: r, state: { setConversation: o, conversationRef: y }, transport: b, generation: { startGeneration: ce, completeGeneration: x }, channel: S, overlay: C, onStopError: w, generationConflictMessage: T = t, generationPersistenceErrorMessage: E = n, onStreamError: D, batchChunksPerFrame: O = !1 }) => {
17
- let k = h(D);
18
- p(() => {
19
- k.current = D;
16
+ }, v = ({ conversationId: o, state: { setConversation: v, conversationRef: y }, transport: b, generation: { startGeneration: le, completeGeneration: x }, channel: S, overlay: C, onStopError: w, generationConflictMessage: ue = t, generationPersistenceErrorMessage: T = n, onStreamError: E, batchChunksPerFrame: D = !1 }) => {
17
+ let O = h(E);
18
+ m(() => {
19
+ O.current = E;
20
+ }, [E]);
21
+ let de = h(D);
22
+ m(() => {
23
+ de.current = D;
20
24
  }, [D]);
21
- let le = h(O);
22
- p(() => {
23
- le.current = O;
24
- }, [O]);
25
- let [A] = g(d), [ue, j] = g(() => /* @__PURE__ */ new Set()), [M, N] = g(null), P = h(null), F = h(null), I = h(/* @__PURE__ */ new Set()), L = h(/* @__PURE__ */ new Map()), R = h(/* @__PURE__ */ new Set()), z = h(/* @__PURE__ */ new Map()), B = h(!0), V = h(/* @__PURE__ */ new Map()), [H, U] = g(V.current), W = h(/* @__PURE__ */ new Set()), [de, fe] = g(W.current);
26
- p(() => (B.current = !0, () => {
27
- B.current = !1;
25
+ let [k] = g(re), [A, j] = g(() => /* @__PURE__ */ new Set()), [M, N] = g(null), P = h(null), F = h(null), I = h(/* @__PURE__ */ new Set()), L = h(/* @__PURE__ */ new Map()), R = h(/* @__PURE__ */ new Set()), fe = h(/* @__PURE__ */ new Map()), z = h(!0), B = h(/* @__PURE__ */ new Map()), [V, H] = g(B.current), U = h(/* @__PURE__ */ new Set()), [W, G] = g(U.current);
26
+ m(() => (z.current = !0, () => {
27
+ z.current = !1;
28
28
  }), []);
29
- let G = f((e) => {
30
- if (!V.current.has(e)) return;
31
- let t = new Map(V.current);
32
- t.delete(e), V.current = t, B.current && U(t);
33
- }, []), K = f((e, t, n) => {
34
- if (!B.current || !n()) return;
35
- let r = new Map(V.current);
29
+ let K = p((e) => {
30
+ if (!B.current.has(e)) return;
31
+ let t = new Map(B.current);
32
+ t.delete(e), B.current = t, z.current && H(t);
33
+ }, []), q = p((e, t, n) => {
34
+ if (!z.current || !n()) return;
35
+ let r = new Map(B.current);
36
36
  r.set(e, {
37
37
  retry: t,
38
38
  isCurrent: n
39
- }), V.current = r, U(r);
40
- }, []), pe = f(async () => {
41
- if (!r) return;
42
- let e = V.current.get(s(r));
43
- if (!(!e || !e.isCurrent() || W.current.has(e))) {
44
- W.current.add(e), fe(new Set(W.current));
39
+ }), B.current = r, H(r);
40
+ }, []), pe = p(async () => {
41
+ if (!o) return;
42
+ let e = B.current.get(s(o));
43
+ if (!(!e || !e.isCurrent() || U.current.has(e))) {
44
+ U.current.add(e), G(new Set(U.current));
45
45
  try {
46
46
  await e.retry();
47
47
  } finally {
48
- W.current.delete(e), B.current && fe(new Set(W.current));
48
+ U.current.delete(e), z.current && G(new Set(U.current));
49
49
  }
50
50
  }
51
- }, [r]), me = h(r);
52
- p(() => (me.current = r, () => A.cancelAll()), [r, A]);
53
- let q = f((e) => B.current && s(me.current ?? "") === e, []), J = f((e) => {
54
- G(e), j((t) => {
51
+ }, [o]), J = h(o);
52
+ m(() => (J.current = o, () => k.cancelAll()), [o, k]);
53
+ let Y = p((e) => z.current && s(J.current ?? "") === e, []), X = p((e) => {
54
+ K(e), j((t) => {
55
55
  if (t.has(e)) return t;
56
56
  let n = new Set(t);
57
57
  return n.add(e), n;
58
58
  });
59
- }, [G]), Y = f((e) => {
59
+ }, [K]), Z = p((e) => {
60
60
  j((t) => {
61
61
  if (!t.has(e)) return t;
62
62
  let n = new Set(t);
63
63
  return n.delete(e), n;
64
64
  });
65
- }, []), X = m(() => ee({
65
+ }, []), Q = ae(() => ee({
66
66
  transport: b,
67
- setConversation: o,
67
+ setConversation: v,
68
68
  conversationRef: y,
69
69
  resumingPathsRef: I,
70
70
  bufferedGenerationsRef: L,
71
- addStreamingPath: J,
72
- removeStreamingPath: Y,
73
- isPathDisplayed: q,
74
- generationPersistenceErrorMessage: E,
75
- frameScheduler: O ? A : void 0,
71
+ addStreamingPath: X,
72
+ removeStreamingPath: Z,
73
+ isPathDisplayed: Y,
74
+ generationPersistenceErrorMessage: T,
75
+ frameScheduler: D ? k : void 0,
76
76
  stoppedGenerationIdsRef: R,
77
- onReloadError: K,
78
- onReloadSuccess: G
77
+ onReloadError: q,
78
+ onReloadSuccess: K
79
79
  }), [
80
- J,
80
+ X,
81
+ Z,
81
82
  Y,
82
- q,
83
83
  b,
84
- E,
85
- O,
86
- A,
87
- K,
88
- G
89
- ]), he = f((t, n, r, ee, d, f, p = _.Append) => {
90
- let m = f ?? ae(), h = s(t);
91
- A.flush(h), I.current.delete(h), P.current = m, F.current = h, z.current.set(h, m), N(h);
92
- let g;
93
- p === _.Regenerate ? g = r : p === _.Edit && (g = r - 1);
94
- let v = () => z.current.get(h) !== m, w = ce(h, m), D = y.current?.messages[r];
95
- D ? L.current.set(h, {
96
- generationId: m,
97
- messageIndex: r,
84
+ T,
85
+ D,
86
+ k,
87
+ q,
88
+ K
89
+ ]), me = p((t, n, o, ee, re, p, m = oe.Append, ae = {}) => {
90
+ let h = p ?? ie(), g = s(t);
91
+ k.flush(g), I.current.delete(g), P.current = h, F.current = g, fe.current.set(g, h), N(g);
92
+ let _;
93
+ m === oe.Regenerate ? _ = o : m === oe.Edit && (_ = o - 1);
94
+ let w = () => fe.current.get(g) !== h, E = le(g, h), D = y.current?.messages[o];
95
+ D ? L.current.set(g, {
96
+ generationId: h,
97
+ messageIndex: o,
98
98
  message: D
99
- }) : L.current.delete(h), J(h), C?.notifyGenerationStart?.(), S?.ensureConnected();
100
- let O = () => {
101
- v() || Y(h), P.current === m && (P.current = null, F.current = null, N(null)), x(h, m), S?.notifyGenerationSettled?.();
102
- }, ue = () => {
103
- if (v()) return;
104
- let e = L.current.get(h);
105
- !e || e.generationId !== m || (e.message = {
99
+ }) : L.current.delete(g), X(g), C?.notifyGenerationStart?.(), S?.ensureConnected();
100
+ let A = () => {
101
+ w() || Z(g), P.current === h && (P.current = null, F.current = null, N(null)), x(g, h), S?.notifyGenerationSettled?.();
102
+ }, j = () => {
103
+ if (w()) return;
104
+ let e = L.current.get(g);
105
+ !e || e.generationId !== h || (e.message = {
106
106
  ...e.message,
107
- streamErrorMessage: E
108
- }, k.current?.(new i()), q(h) && o((t) => {
109
- if (!t || v() || !q(h)) return t;
107
+ streamErrorMessage: T
108
+ }, O.current?.(new i()), Y(g) && v((t) => {
109
+ if (!t || w() || !Y(g)) return t;
110
110
  let n = l(t, e);
111
111
  return y.current = n, n;
112
112
  }));
113
- }, j = L.current.get(h), M = () => B.current && !v() && L.current.get(h) === j, V = async () => {
114
- if (M()) {
115
- if (!q(h)) {
116
- j && L.current.delete(h);
113
+ }, M = L.current.get(g), B = () => z.current && !w() && L.current.get(g) === M, V = async () => {
114
+ if (B()) {
115
+ if (!Y(g)) {
116
+ M && L.current.delete(g);
117
117
  return;
118
118
  }
119
119
  try {
120
120
  let n = await b.getConversation(e(t));
121
- if (!M()) return;
122
- if (G(h), !q(h)) {
123
- j && L.current.delete(h);
121
+ if (!B()) return;
122
+ if (K(g), !Y(g)) {
123
+ M && L.current.delete(g);
124
124
  return;
125
125
  }
126
- if (ne(n) !== -1) {
127
- X(t, n, { seedMessage: j?.message });
126
+ if (u(n) !== -1) {
127
+ Q(t, n, { seedMessage: M?.message });
128
128
  return;
129
129
  }
130
- if (j && j.messageIndex === n.messages.length - 1 && u(n) && re(j.message)) {
131
- ue();
130
+ if (M && M.messageIndex === n.messages.length - 1 && d(n) && ne(M.message)) {
131
+ j();
132
132
  return;
133
133
  }
134
- j && L.current.delete(h), o(n), y.current = n;
134
+ M && L.current.delete(g), v(n), y.current = n;
135
135
  } catch {
136
- M() && K(h, V, M);
136
+ B() && q(g, V, B);
137
137
  }
138
138
  }
139
139
  }, H = {
140
- signal: w.signal,
140
+ signal: E.signal,
141
141
  onChunk: (e) => {
142
- if (P.current !== m) return;
143
- let t = L.current.get(h);
144
- if (t?.generationId === m) {
142
+ if (P.current !== h) return;
143
+ let t = L.current.get(g);
144
+ if (t?.generationId === h) {
145
145
  let n = c([t.message], 0, e);
146
146
  n && (t.message = n[0]);
147
147
  }
148
- if (q(h)) {
149
- if (le.current && t?.generationId === m) {
150
- A.schedule(h, () => {
151
- let e = L.current.get(h);
152
- if (P.current !== m || !q(h) || e?.generationId !== m) return;
148
+ if (Y(g)) {
149
+ if (de.current && t?.generationId === h) {
150
+ k.schedule(g, () => {
151
+ let e = L.current.get(g);
152
+ if (P.current !== h || !Y(g) || e?.generationId !== h) return;
153
153
  let t = { ...e };
154
- o((e) => {
154
+ v((e) => {
155
155
  if (!e) return e;
156
156
  let n = l(e, t);
157
157
  return y.current = n, n;
@@ -159,113 +159,119 @@ var oe = 2e4, se = (e, t, n) => e instanceof i ? n : e instanceof r ? t : e inst
159
159
  });
160
160
  return;
161
161
  }
162
- o((t) => {
162
+ v((t) => {
163
163
  if (!t) return t;
164
- let n = L.current.get(h), i;
165
- if (n?.generationId === m) i = l(t, n);
164
+ let n = L.current.get(g), r;
165
+ if (n?.generationId === h) r = l(t, n);
166
166
  else {
167
- let n = c(t.messages, r, e);
167
+ let n = c(t.messages, o, e);
168
168
  if (!n) return t;
169
- i = {
169
+ r = {
170
170
  ...t,
171
171
  messages: n
172
172
  };
173
173
  }
174
- return y.current = i, i;
174
+ return y.current = r, r;
175
175
  });
176
176
  }
177
177
  },
178
178
  onComplete: async () => {
179
- A.flush(h), O(), R.current.has(m) ? R.current.delete(m) : v() || C?.notifyGenerationEnd?.(), await V();
179
+ k.flush(g), A(), R.current.has(h) ? R.current.delete(h) : w() || C?.notifyGenerationEnd?.(), await V();
180
180
  },
181
181
  onError: (e) => {
182
- if (A.flush(h), k.current?.(e), e instanceof a && !v()) {
183
- de(e);
182
+ if (k.flush(g), O.current?.(e), e instanceof a && !w()) {
183
+ G(e);
184
+ return;
185
+ }
186
+ if (e instanceof r && ae.resumeOnConflict && !w()) {
187
+ pe(e);
184
188
  return;
185
189
  }
186
190
  U(e);
187
191
  }
188
192
  }, U = (e) => {
189
- let t = L.current.get(h), n = t?.generationId === m ? t : void 0;
193
+ let t = L.current.get(g), n = t?.generationId === h ? t : void 0;
190
194
  if (n && (e instanceof i ? n.message = {
191
195
  ...n.message,
192
- streamErrorMessage: E
193
- } : L.current.delete(h)), O(), v() || !q(h)) return;
194
- let a = se(e, T, E);
195
- o((e) => {
196
- if (!e || v() || !q(h)) return e;
197
- let t = n?.generationId === m ? l(e, n) : e, i = {
196
+ streamErrorMessage: T
197
+ } : L.current.delete(g)), A(), w() || !Y(g)) return;
198
+ let r = ce(e, ue, T);
199
+ v((e) => {
200
+ if (!e || w() || !Y(g)) return e;
201
+ let t = n?.generationId === h ? l(e, n) : e, i = {
198
202
  ...t,
199
- messages: t.messages.map((e, t) => t === r ? {
203
+ messages: t.messages.map((e, t) => t === o ? {
200
204
  ...e,
201
- streamErrorMessage: a
205
+ streamErrorMessage: r
202
206
  } : e)
203
207
  };
204
208
  return y.current = i, i;
205
209
  });
206
210
  }, W = () => {
207
- O(), R.current.has(m) ? R.current.delete(m) : v() || C?.notifyGenerationEnd?.();
208
- }, de = async (n) => {
209
- I.current.add(h);
210
- let i = await te(() => b.getConversation(e(t)), v);
211
- if (v()) {
212
- O();
211
+ A(), R.current.has(h) ? R.current.delete(h) : w() || C?.notifyGenerationEnd?.();
212
+ }, G = async (n) => {
213
+ I.current.add(g), J(await te(() => b.getConversation(e(t)), w), n, !1);
214
+ }, pe = async (n) => {
215
+ P.current === h && N(null), I.current.add(g), J(await te(() => b.getConversation(e(t)), w, (e) => e.messages.length === o && e.messages.at(-1)?.role === f.User), n, !0);
216
+ }, J = (e, n, r) => {
217
+ if (w()) {
218
+ A();
213
219
  return;
214
220
  }
215
- let a = i?.messages[i.messages.length - 1], s = i != null && i.messages.length - 1 === r && a?.role === ie.Assistant;
216
- if (!i || !s) {
217
- I.current.delete(h), U(n);
221
+ let i = e?.messages[e.messages.length - 1], a = e != null && e.messages.length - 1 === o && i?.role === f.Assistant, s = r && e != null && u(e) !== -1;
222
+ if (!e || !a && !s) {
223
+ I.current.delete(g), U(n);
218
224
  return;
219
225
  }
220
- let c = L.current.get(h), l = c?.generationId === m ? c : void 0;
221
- if (u(i)) {
222
- X(t, i, {
223
- seedMessage: l?.message,
226
+ let c = L.current.get(g), l = c?.generationId === h ? c : void 0;
227
+ if (d(e)) {
228
+ Q(t, e, {
229
+ seedMessage: a ? l?.message : void 0,
224
230
  skipDedupe: !0,
225
231
  onSettled: W
226
232
  });
227
233
  return;
228
234
  }
229
- I.current.delete(h), l && L.current.delete(h), q(h) && (o(i), y.current = i), W();
235
+ I.current.delete(g), l && L.current.delete(g), Y(g) && (v(e), y.current = e), W();
230
236
  };
231
237
  (async () => {
232
238
  try {
233
- let e = S?.channelId ?? await S?.waitForChannel(oe) ?? void 0, t = R.current.has(m);
234
- if (w.signal.aborted || v() || t) {
235
- L.current.get(h)?.generationId === m && L.current.delete(h), v() || Y(h), P.current === m && (P.current = null, F.current = null, N(null)), x(h, m), S?.notifyGenerationSettled?.(), t ? R.current.delete(m) : v() || C?.notifyGenerationEnd?.();
239
+ let e = S?.channelId ?? await S?.waitForChannel(se) ?? void 0, t = R.current.has(h);
240
+ if (E.signal.aborted || w() || t) {
241
+ L.current.get(g)?.generationId === h && L.current.delete(g), w() || Z(g), P.current === h && (P.current = null, F.current = null, N(null)), x(g, h), S?.notifyGenerationSettled?.(), t ? R.current.delete(h) : w() || C?.notifyGenerationEnd?.();
236
242
  return;
237
243
  }
238
- b.streamCompletion(h, n, ee, H, d, m, p, g, e);
244
+ b.streamCompletion(g, n, ee, H, re, h, m, _, e);
239
245
  } catch (e) {
240
246
  H.onError(e instanceof Error ? e : Error(String(e)));
241
247
  }
242
248
  })();
243
249
  }, [
244
- ce,
250
+ le,
245
251
  x,
246
- J,
252
+ X,
253
+ Z,
247
254
  Y,
248
- q,
249
255
  S?.channelId,
250
256
  S?.ensureConnected,
251
257
  S?.waitForChannel,
252
258
  S?.notifyGenerationSettled,
253
259
  C,
254
260
  b,
255
- X,
261
+ Q,
262
+ ue,
256
263
  T,
257
- E,
258
- A,
259
- K,
260
- G
261
- ]), ge = f((e, t) => {
264
+ k,
265
+ q,
266
+ K
267
+ ]), he = p((e, t) => {
262
268
  let n = s(e), r = L.current.get(n);
263
- return V.current.get(n)?.isCurrent() && r && t.messages.length - 1 >= r.messageIndex && t.messages[r.messageIndex].role === ie.Assistant && !u(t) ? (G(n), L.current.delete(n), t) : r ? l(t, r) : t;
264
- }, [G]), _e = f(() => {
265
- if (!r) return;
266
- let e = s(r), t = (F.current === e ? P.current : null) ?? v(y.current);
269
+ return B.current.get(n)?.isCurrent() && r && t.messages.length - 1 >= r.messageIndex && t.messages[r.messageIndex].role === f.Assistant && !d(t) ? (K(n), L.current.delete(n), t) : r ? l(t, r) : t;
270
+ }, [K]), ge = p(() => {
271
+ if (!o) return;
272
+ let e = s(o), t = (F.current === e ? P.current : null) ?? _(y.current);
267
273
  if (!t) return;
268
- R.current.add(t), A.flush(e), C?.notifyStopGenerating?.();
274
+ R.current.add(t), k.flush(e), C?.notifyStopGenerating?.();
269
275
  let n = L.current.get(e)?.message.content;
270
276
  b.stopCompletion({
271
277
  generationId: t,
@@ -276,24 +282,24 @@ var oe = 2e4, se = (e, t, n) => e instanceof i ? n : e instanceof r ? t : e inst
276
282
  w?.(t);
277
283
  });
278
284
  }, [
279
- r,
285
+ o,
280
286
  y,
281
- A,
287
+ k,
282
288
  w,
283
289
  C,
284
290
  b
285
- ]), ve = f((e, t) => X(e, t), [X]), ye = r != null && ue.has(s(r)), Z = r == null ? null : s(r), be = Z != null && (M === Z || ye && v(y.current) != null), Q = Z ? H.get(Z) : void 0, $ = Q?.isCurrent() ?? !1;
291
+ ]), _e = p((e, t) => Q(e, t), [Q]), ve = o != null && A.has(s(o)), $ = o == null ? null : s(o), ye = $ != null && (M === $ || ve && _(y.current) != null), be = $ ? V.get($) : void 0, xe = be?.isCurrent() ?? !1;
286
292
  return {
287
- hasConversationReloadError: $,
288
- isReloadingConversation: !!Q && $ && de.has(Q),
293
+ hasConversationReloadError: xe,
294
+ isReloadingConversation: !!be && xe && W.has(be),
289
295
  retryConversationReload: pe,
290
- startStream: he,
291
- handleStop: _e,
292
- resumeIfAwaitingGeneration: ve,
293
- restoreBufferedGeneration: ge,
294
- isStreaming: ye,
295
- canStopStreaming: be
296
+ startStream: me,
297
+ handleStop: ge,
298
+ resumeIfAwaitingGeneration: _e,
299
+ restoreBufferedGeneration: he,
300
+ isStreaming: ve,
301
+ canStopStreaming: ye
296
302
  };
297
303
  };
298
304
  //#endregion
299
- export { y as useConversationStream };
305
+ export { v as useConversationStream };
package/conversation.d.ts CHANGED
@@ -298,7 +298,7 @@ export declare interface ConversationStreamOverlayNotifier {
298
298
  }
299
299
 
300
300
  /** The exact `startStream` shape `useConversationStream` returns. */
301
- export declare type ConversationStreamStarter = (conversationPath: string, userContent: string, messageIndex: number, model: string, customContent?: MessageCustomContent, generationId?: string, mode?: SendCompletionDtoModeEnum) => void;
301
+ export declare type ConversationStreamStarter = (conversationPath: string, userContent: string, messageIndex: number, model: string, customContent?: MessageCustomContent, generationId?: string, mode?: SendCompletionDtoModeEnum, options?: StartStreamOptions) => void;
302
302
 
303
303
  /**
304
304
  * Host-owned transport for the DIAL Core completion protocol. Implemented at
@@ -831,6 +831,18 @@ export declare const shouldRerunGenerationOnEdit: (messages: Message[], messageI
831
831
  /** True when the first user/assistant exchange is complete and LLM naming may still run. */
832
832
  export declare const shouldWatchForDisplayNameUpdate: (conversation: Conversation) => boolean;
833
833
 
834
+ /** Per-start options of {@link UseConversationStreamResult.startStream}. */
835
+ export declare interface StartStreamOptions {
836
+ /**
837
+ * Treats a `GenerationConflictError` as "this turn is already being
838
+ * generated" — e.g. a page reloaded before that generation saved its start
839
+ * state — and joins the running generation instead of showing the conflict
840
+ * message, which remains the fallback. Only for a start that sends no new
841
+ * user text; a send the user typed must keep reporting the conflict.
842
+ */
843
+ resumeOnConflict?: boolean;
844
+ }
845
+
834
846
  /** Options accepted by {@link ConversationStreamTransport.streamCompletion}. */
835
847
  export declare interface StreamCompletionOptions {
836
848
  onChunk: (chunk: StreamChunk) => void;
@@ -1187,7 +1199,7 @@ export declare interface UseConversationStreamParams {
1187
1199
 
1188
1200
  /** Return value of {@link useConversationStream}. */
1189
1201
  export declare interface UseConversationStreamResult {
1190
- startStream: (conversationId: string, userContent: string, messageIndex: number, model: string, customContent?: MessageCustomContent, generationId?: string, mode?: SendCompletionDtoModeEnum) => void;
1202
+ startStream: (conversationId: string, userContent: string, messageIndex: number, model: string, customContent?: MessageCustomContent, generationId?: string, mode?: SendCompletionDtoModeEnum, options?: StartStreamOptions) => void;
1191
1203
  handleStop: () => void;
1192
1204
  resumeIfAwaitingGeneration: (currentConversationId: string, conversation: Conversation) => void;
1193
1205
  /** Restores the accumulated live assistant message when its conversation is loaded again before completion. */
package/index.d.ts CHANGED
@@ -927,7 +927,7 @@ export declare interface ConversationStreamOverlayNotifier {
927
927
  }
928
928
 
929
929
  /** The exact `startStream` shape `useConversationStream` returns. */
930
- export declare type ConversationStreamStarter = (conversationPath: string, userContent: string, messageIndex: number, model: string, customContent?: MessageCustomContent, generationId?: string, mode?: SendCompletionDtoModeEnum) => void;
930
+ export declare type ConversationStreamStarter = (conversationPath: string, userContent: string, messageIndex: number, model: string, customContent?: MessageCustomContent, generationId?: string, mode?: SendCompletionDtoModeEnum, options?: StartStreamOptions) => void;
931
931
 
932
932
  /**
933
933
  * Host-owned transport for the DIAL Core completion protocol. Implemented at
@@ -1264,6 +1264,8 @@ export declare const deriveFavoriteItems: (items: readonly CatalogItem[]) => Cat
1264
1264
  * Unsupported constraints remain Custom, with the full source expression.
1265
1265
  * Calendar-month shifts crossing month boundaries or days 29–31 remain
1266
1266
  * Custom because a shifted monthly day is not equivalent around short months.
1267
+ * The one exception is `day: 'last'` one day behind local time, which is
1268
+ * exactly the local 1st.
1267
1269
  */
1268
1270
  export declare const describeScheduledTaskTrigger: (trigger: ScheduleTriggerDto, { timeZone, referenceDate, }?: ScheduledTaskTriggerDescriptionOptions) => ScheduledTaskTriggerDescription;
1269
1271
 
@@ -4098,6 +4100,18 @@ export declare const splitFileNameExtension: (fileName: string) => {
4098
4100
  extension: string;
4099
4101
  };
4100
4102
 
4103
+ /** Per-start options of {@link UseConversationStreamResult.startStream}. */
4104
+ export declare interface StartStreamOptions {
4105
+ /**
4106
+ * Treats a `GenerationConflictError` as "this turn is already being
4107
+ * generated" — e.g. a page reloaded before that generation saved its start
4108
+ * state — and joins the running generation instead of showing the conflict
4109
+ * message, which remains the fallback. Only for a start that sends no new
4110
+ * user text; a send the user typed must keep reporting the conflict.
4111
+ */
4112
+ resumeOnConflict?: boolean;
4113
+ }
4114
+
4101
4115
  /**
4102
4116
  * Answers one question: would appending this text after the fence that
4103
4117
  * `buildSkillManifest` writes produce a *second* frontmatter block?
@@ -5304,7 +5318,7 @@ export declare interface UseConversationStreamParams {
5304
5318
 
5305
5319
  /** Return value of {@link useConversationStream}. */
5306
5320
  export declare interface UseConversationStreamResult {
5307
- startStream: (conversationId: string, userContent: string, messageIndex: number, model: string, customContent?: MessageCustomContent, generationId?: string, mode?: SendCompletionDtoModeEnum) => void;
5321
+ startStream: (conversationId: string, userContent: string, messageIndex: number, model: string, customContent?: MessageCustomContent, generationId?: string, mode?: SendCompletionDtoModeEnum, options?: StartStreamOptions) => void;
5308
5322
  handleStop: () => void;
5309
5323
  resumeIfAwaitingGeneration: (currentConversationId: string, conversation: Conversation) => void;
5310
5324
  /** Restores the accumulated live assistant message when its conversation is loaded again before completion. */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@epam/ai-dial-chat-hooks",
3
3
  "description": "Framework-level React hooks extracted from AI DIAL Chat for building custom chat interfaces",
4
- "version": "1.2.0-dev.265",
4
+ "version": "1.2.0-dev.268",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
7
7
  "main": "./index.js",
@@ -111,7 +111,7 @@
111
111
  }
112
112
  },
113
113
  "dependencies": {
114
- "@epam/ai-dial-chat-api-client": "1.2.0-dev.265",
114
+ "@epam/ai-dial-chat-api-client": "1.2.0-dev.268",
115
115
  "dompurify": "3.4.16",
116
116
  "fflate": "^0.8.3",
117
117
  "lru-cache": "^10.4.3",
@@ -120,21 +120,21 @@
120
120
  },
121
121
  "peerDependencies": {
122
122
  "react": "^19.2.8",
123
- "@epam/ai-dial-attachment-canvas": "1.2.0-dev.265",
124
- "@epam/ai-dial-attachment-input": "1.2.0-dev.265",
125
- "@epam/ai-dial-catalog": "1.2.0-dev.265",
126
- "@epam/ai-dial-chat-overlay": "1.2.0-dev.265",
127
- "@epam/ai-dial-chat-shared": "1.2.0-dev.265",
128
- "@epam/ai-dial-mcp-apps": "1.2.0-dev.265",
129
- "@epam/ai-dial-publish-panel": "1.2.0-dev.265",
130
- "@epam/ai-dial-quotations": "1.2.0-dev.265",
123
+ "@epam/ai-dial-attachment-canvas": "1.2.0-dev.268",
124
+ "@epam/ai-dial-attachment-input": "1.2.0-dev.268",
125
+ "@epam/ai-dial-catalog": "1.2.0-dev.268",
126
+ "@epam/ai-dial-chat-overlay": "1.2.0-dev.268",
127
+ "@epam/ai-dial-chat-shared": "1.2.0-dev.268",
128
+ "@epam/ai-dial-mcp-apps": "1.2.0-dev.268",
129
+ "@epam/ai-dial-publish-panel": "1.2.0-dev.268",
130
+ "@epam/ai-dial-quotations": "1.2.0-dev.268",
131
131
  "@epam/ai-dial-react-file-manager": "^0.3.0-dev.22",
132
- "@epam/ai-dial-scheduled-tasks": "1.2.0-dev.265",
133
- "@epam/ai-dial-share": "1.2.0-dev.265",
134
- "@epam/ai-dial-skill-editor": "1.2.0-dev.265",
135
- "@epam/ai-dial-source-panel": "1.2.0-dev.265",
132
+ "@epam/ai-dial-scheduled-tasks": "1.2.0-dev.268",
133
+ "@epam/ai-dial-share": "1.2.0-dev.268",
134
+ "@epam/ai-dial-skill-editor": "1.2.0-dev.268",
135
+ "@epam/ai-dial-source-panel": "1.2.0-dev.268",
136
136
  "@epam/ai-dial-ui-kit": "^0.15.0-dev.36",
137
- "@epam/ai-dial-usage-dashboard": "1.2.0-dev.265",
137
+ "@epam/ai-dial-usage-dashboard": "1.2.0-dev.268",
138
138
  "@modelcontextprotocol/sdk": "^1.29.0",
139
139
  "@epam/pdf-highlighter-kit": "^0.0.19",
140
140
  "@mcp-ui/client": "^7.1.1"
@@ -1,20 +1,21 @@
1
+ import { CRON_LAST_DAY_OF_MONTH as e } from "../shared/cron-day-of-month.js";
1
2
  //#region src/scheduled-task/scheduled-task-description.ts
2
- var e = /* @__PURE__ */ function(e) {
3
+ var t = /* @__PURE__ */ function(e) {
3
4
  return e.OneTime = "oneTime", e.Hourly = "hourly", e.EveryNMinutes = "everyNMinutes", e.Daily = "daily", e.Weekly = "weekly", e.Monthly = "monthly", e.Custom = "custom", e.Invalid = "invalid", e;
4
- }({}), t = (e, { timeZone: t = "UTC", referenceDate: n = /* @__PURE__ */ new Date() } = {}) => {
5
- let r = (e, t = {}) => ({
5
+ }({}), n = (t, { timeZone: n = "UTC", referenceDate: r = /* @__PURE__ */ new Date() } = {}) => {
6
+ let i = (e, t = {}) => ({
6
7
  kind: e,
7
8
  sourceTimezone: "utc",
8
9
  ...t
9
10
  });
10
- if (e.date && e.cron) return r("invalid");
11
- if (e.date) {
12
- let t = new Date(e.date);
13
- return Number.isNaN(t.getTime()) ? r("invalid") : r("oneTime", { date: t });
11
+ if (t.date && t.cron) return i("invalid");
12
+ if (t.date) {
13
+ let e = new Date(t.date);
14
+ return Number.isNaN(e.getTime()) ? i("invalid") : i("oneTime", { date: e });
14
15
  }
15
- let i = e.cron?.fields;
16
- if (!i || Object.keys(i).length === 0) return r("invalid");
17
- let a = () => r("custom", { expression: JSON.stringify(i) }), o = {
16
+ let a = t.cron?.fields;
17
+ if (!a || Object.keys(a).length === 0) return i("invalid");
18
+ let o = () => i("custom", { expression: JSON.stringify(a) }), s = {
18
19
  hour: [0, 23],
19
20
  minute: [0, 59],
20
21
  day: [1, 31],
@@ -22,19 +23,19 @@ var e = /* @__PURE__ */ function(e) {
22
23
  month: [1, 12],
23
24
  second: [0, 59]
24
25
  };
25
- for (let [e, t] of Object.entries(i)) {
26
+ for (let [e, t] of Object.entries(a)) {
26
27
  if (t == null) continue;
27
- if (!t.trim()) return r("invalid");
28
- let n = o[e];
29
- if (n && /^-?\d+$/.test(t) && (Number(t) < n[0] || Number(t) > n[1])) return r("invalid");
28
+ if (!t.trim()) return i("invalid");
29
+ let n = s[e];
30
+ if (n && /^-?\d+$/.test(t) && (Number(t) < n[0] || Number(t) > n[1])) return i("invalid");
30
31
  if (e === "second" && t !== "0" || ![
31
32
  "hour",
32
33
  "minute",
33
34
  "day",
34
35
  "day_of_week"
35
- ].includes(e) && t !== "*" && !(e === "second" && t === "0")) return a();
36
+ ].includes(e) && t !== "*" && !(e === "second" && t === "0")) return o();
36
37
  }
37
- let s = i.hour, c = i.minute, l = i.day === "*" ? void 0 : i.day, u = i.day_of_week === "*" ? void 0 : i.day_of_week, d = u ? [
38
+ let c = a.hour, l = a.minute, u = a.day === "*" ? void 0 : a.day, d = u === e, f = a.day_of_week === "*" ? void 0 : a.day_of_week, p = f ? [
38
39
  "monday",
39
40
  "tuesday",
40
41
  "wednesday",
@@ -42,36 +43,39 @@ var e = /* @__PURE__ */ function(e) {
42
43
  "friday",
43
44
  "saturday",
44
45
  "sunday"
45
- ].findIndex((e) => e === u.toLowerCase() || e.slice(0, 3) === u.toLowerCase()) : -1, f = d >= 0 ? String(d) : u;
46
- if (l && f || l && !/^\d+$/.test(l) || f && !/^\d+$/.test(f)) return a();
47
- let p = s == null || s === "*", m = c?.match(/^\*\/(\d+)$/);
48
- if (p && m && !l && !f) {
49
- let e = Number(m[1]);
50
- return e > 0 && e <= 59 ? r("everyNMinutes", { intervalMinutes: e }) : r("invalid");
46
+ ].findIndex((e) => e === f.toLowerCase() || e.slice(0, 3) === f.toLowerCase()) : -1, m = p >= 0 ? String(p) : f;
47
+ if (u && m || u && !d && !/^\d+$/.test(u) || m && !/^\d+$/.test(m)) return o();
48
+ let h = c == null || c === "*", g = l?.match(/^\*\/(\d+)$/);
49
+ if (h && g && !u && !m) {
50
+ let e = Number(g[1]);
51
+ return e > 0 && e <= 59 ? i("everyNMinutes", { intervalMinutes: e }) : i("invalid");
51
52
  }
52
- if (!c || !/^\d+$/.test(c) || !p && !/^\d+$/.test(s) || p && (l || f)) return a();
53
- let h = new Date(n);
54
- if (Number.isNaN(h.getTime())) return r("invalid");
55
- if (h.setUTCHours(p ? 0 : Number(s), Number(c), 0, 0), f) {
56
- let e = (Number(f) + 1) % 7;
57
- h.setUTCDate(h.getUTCDate() + (e - h.getUTCDay() + 7) % 7);
53
+ if (!l || !/^\d+$/.test(l) || !h && !/^\d+$/.test(c) || h && (u || m)) return o();
54
+ let _ = new Date(r);
55
+ if (Number.isNaN(_.getTime())) return i("invalid");
56
+ if (_.setUTCHours(h ? 0 : Number(c), Number(l), 0, 0), m) {
57
+ let e = (Number(m) + 1) % 7;
58
+ _.setUTCDate(_.getUTCDate() + (e - _.getUTCDay() + 7) % 7);
58
59
  }
59
- let g = new Intl.DateTimeFormat("en-GB", {
60
- timeZone: t,
60
+ let v = new Intl.DateTimeFormat("en-GB", {
61
+ timeZone: n,
61
62
  hourCycle: "h23",
62
63
  year: "numeric",
63
64
  month: "2-digit",
64
65
  day: "2-digit",
65
66
  hour: "2-digit",
66
67
  minute: "2-digit"
67
- }).formatToParts(h), _ = (e) => g.find((t) => t.type === e)?.value ?? "", v = new Date(Date.UTC(Number(_("year")), Number(_("month")) - 1, Number(_("day")))), y = Date.UTC(h.getUTCFullYear(), h.getUTCMonth(), h.getUTCDate()), b = Math.round((v.getTime() - y) / 864e5), x = _("hour") + ":" + _("minute");
68
- return p ? r("hourly", { time: _("minute") }) : f ? r("weekly", {
69
- time: x,
70
- dayOfWeek: String((Number(f) + b + 7) % 7)
71
- }) : l ? b === 0 || Number(l) <= 28 && Number(l) + b >= 1 && Number(l) + b <= 28 ? r("monthly", {
72
- time: x,
73
- dayOfMonth: String(Number(l) + b)
74
- }) : a() : r("daily", { time: x });
68
+ }).formatToParts(_), y = (e) => v.find((t) => t.type === e)?.value ?? "", b = new Date(Date.UTC(Number(y("year")), Number(y("month")) - 1, Number(y("day")))), x = Date.UTC(_.getUTCFullYear(), _.getUTCMonth(), _.getUTCDate()), S = Math.round((b.getTime() - x) / 864e5), C = y("hour") + ":" + y("minute");
69
+ return h ? i("hourly", { time: y("minute") }) : m ? i("weekly", {
70
+ time: C,
71
+ dayOfWeek: String((Number(m) + S + 7) % 7)
72
+ }) : d ? S === 1 ? i("monthly", {
73
+ time: C,
74
+ dayOfMonth: "1"
75
+ }) : o() : u ? S === 0 || Number(u) <= 28 && Number(u) + S >= 1 && Number(u) + S <= 28 ? i("monthly", {
76
+ time: C,
77
+ dayOfMonth: String(Number(u) + S)
78
+ }) : o() : i("daily", { time: C });
75
79
  };
76
80
  //#endregion
77
- export { e as ScheduledTaskTriggerDescriptionKind, t as describeScheduledTaskTrigger };
81
+ export { t as ScheduledTaskTriggerDescriptionKind, n as describeScheduledTaskTrigger };
@@ -1,41 +1,42 @@
1
1
  import { padTwoDigits as e } from "../shared/formatting.js";
2
2
  import { UnsupportedTriggerReason as t } from "./scheduled-task-mapping.js";
3
- import { apSchedulerDayToJsDay as n, jsDayToApSchedulerDay as r } from "../shared/cron-weekday.js";
4
- import { ScheduledTaskRepeat as i } from "@epam/ai-dial-scheduled-tasks";
3
+ import { getUtcDayShift as n, toLocalDayOfMonth as r, toUtcCronDayOfMonth as i } from "../shared/cron-day-of-month.js";
4
+ import { apSchedulerDayToJsDay as a, jsDayToApSchedulerDay as o } from "../shared/cron-weekday.js";
5
+ import { ScheduledTaskRepeat as s } from "@epam/ai-dial-scheduled-tasks";
5
6
  //#region src/scheduled-task/scheduled-task-trigger.ts
6
- var a = new Set([
7
+ var c = new Set([
7
8
  "hour",
8
9
  "minute",
9
10
  "day_of_week",
10
11
  "day"
11
- ]), o = "09:00", s = (e) => {
12
- if (e.repeat === i.Hourly) {
12
+ ]), l = "09:00", u = (e) => {
13
+ if (e.repeat === s.Hourly) {
13
14
  let t = /* @__PURE__ */ new Date();
14
15
  return t.setHours(0, Number(e.minute), 0, 0), {
15
16
  hour: "*",
16
17
  minute: String(t.getUTCMinutes())
17
18
  };
18
19
  }
19
- let [t, a] = e.time.split(":"), o = Number(t), s = Number(a), c = /* @__PURE__ */ new Date();
20
- c.setHours(o, s, 0, 0);
21
- let l = e.repeat === i.Weekly && !!e.dayOfWeek, u = e.repeat === i.Monthly && !!e.dayOfMonth;
22
- if (l) {
23
- let t = (n(Number(e.dayOfWeek)) - c.getDay() + 7) % 7;
24
- c.setDate(c.getDate() + t);
25
- } else u && c.setDate(Number(e.dayOfMonth));
26
- let d = {
27
- hour: String(c.getUTCHours()),
28
- minute: String(c.getUTCMinutes())
20
+ let [t, r] = e.time.split(":"), c = Number(t), l = Number(r), u = /* @__PURE__ */ new Date();
21
+ u.setHours(c, l, 0, 0);
22
+ let d = e.repeat === s.Weekly && !!e.dayOfWeek, f = e.repeat === s.Monthly && !!e.dayOfMonth;
23
+ if (d) {
24
+ let t = (a(Number(e.dayOfWeek)) - u.getDay() + 7) % 7;
25
+ u.setDate(u.getDate() + t);
26
+ }
27
+ let p = {
28
+ hour: String(u.getUTCHours()),
29
+ minute: String(u.getUTCMinutes())
29
30
  };
30
- return l && (d.day_of_week = String(r(c.getUTCDay()))), u && (d.day = String(c.getUTCDate())), d;
31
- }, c = (e, t) => {
31
+ return d && (p.day_of_week = String(o(u.getUTCDay()))), f && (p.day = i(Number(e.dayOfMonth), n(u))), p;
32
+ }, d = (e, t) => {
32
33
  let [n, r, i] = e.split("-").map(Number), a = new Date(n, r - 1, i);
33
34
  return t === "start" ? a.setHours(0, 0, 0, 0) : a.setHours(23, 59, 59, 999), a.toISOString();
34
- }, l = (e) => {
35
- let t = e.repeat === i.OneTime ? { date: new Date(e.runAt ?? "").toISOString() } : { cron: {
36
- fields: s(e),
37
- ...e.startDate ? { startDate: c(e.startDate, "start") } : {},
38
- ...e.endDate ? { endDate: c(e.endDate, "end") } : {}
35
+ }, f = (e) => {
36
+ let t = e.repeat === s.OneTime ? { date: new Date(e.runAt ?? "").toISOString() } : { cron: {
37
+ fields: u(e),
38
+ ...e.startDate ? { startDate: d(e.startDate, "start") } : {},
39
+ ...e.endDate ? { endDate: d(e.endDate, "end") } : {}
39
40
  } }, n = e.description?.trim();
40
41
  return {
41
42
  displayName: e.displayName.trim(),
@@ -45,19 +46,19 @@ var a = new Set([
45
46
  ...e.skillUrl ? { skillUrl: e.skillUrl } : {},
46
47
  ...n ? { description: n } : {}
47
48
  };
48
- }, u = (e) => ({
49
- ...l(e),
49
+ }, p = (e) => ({
50
+ ...f(e),
50
51
  skillUrl: e.skillUrl || null
51
- }), d = (t) => {
52
+ }), m = (t) => {
52
53
  let n = new Date(t);
53
54
  return `${n.getFullYear()}-${e(n.getMonth() + 1)}-${e(n.getDate())}T${e(n.getHours())}:${e(n.getMinutes())}`;
54
- }, f = (t) => {
55
+ }, h = (t) => {
55
56
  let n = new Date(t);
56
57
  return `${n.getFullYear()}-${e(n.getMonth() + 1)}-${e(n.getDate())}`;
57
- }, p = (t) => {
58
- let i = new Set(Object.entries(t).filter(([, e]) => e != null).map(([e]) => e)), o = [...i].filter((e) => !a.has(e)), s = i.has("day_of_week"), c = i.has("day");
59
- if (o.length > 0 || s && c || !i.has("hour") || !i.has("minute")) return { ok: !1 };
60
- if (t.hour === "*" && /^\d+$/.test(String(t.minute)) && !s && !c) {
58
+ }, g = (t) => {
59
+ let i = new Set(Object.entries(t).filter(([, e]) => e != null).map(([e]) => e)), s = [...i].filter((e) => !c.has(e)), l = i.has("day_of_week"), u = i.has("day");
60
+ if (s.length > 0 || l && u || !i.has("hour") || !i.has("minute")) return { ok: !1 };
61
+ if (t.hour === "*" && /^\d+$/.test(String(t.minute)) && !l && !u) {
61
62
  let e = /* @__PURE__ */ new Date();
62
63
  return e.setUTCHours(0, Number(t.minute), 0, 0), {
63
64
  ok: !0,
@@ -65,85 +66,82 @@ var a = new Set([
65
66
  minute: String(e.getMinutes())
66
67
  };
67
68
  }
68
- let l = Number(t.hour), u = Number(t.minute);
69
- if (Number.isNaN(l) || Number.isNaN(u)) return { ok: !1 };
70
- let d = /* @__PURE__ */ new Date();
71
- if (d.setUTCHours(l, u, 0, 0), s) {
69
+ let d = Number(t.hour), f = Number(t.minute);
70
+ if (Number.isNaN(d) || Number.isNaN(f)) return { ok: !1 };
71
+ let p = /* @__PURE__ */ new Date();
72
+ if (p.setUTCHours(d, f, 0, 0), l) {
72
73
  let e = Number(t.day_of_week);
73
74
  if (Number.isNaN(e)) return { ok: !1 };
74
- let r = (n(e) - d.getUTCDay() + 7) % 7;
75
- d.setUTCDate(d.getUTCDate() + r);
76
- } else if (c) {
77
- let e = Number(t.day);
78
- if (Number.isNaN(e)) return { ok: !1 };
79
- d.setUTCDate(e);
75
+ let n = (a(e) - p.getUTCDay() + 7) % 7;
76
+ p.setUTCDate(p.getUTCDate() + n);
80
77
  }
81
- return {
78
+ let m = u ? r(String(t.day), n(p)) : void 0;
79
+ return u && !m ? { ok: !1 } : {
82
80
  ok: !0,
83
81
  isHourly: !1,
84
- time: `${e(d.getHours())}:${e(d.getMinutes())}`,
85
- ...s ? { dayOfWeek: String(r(d.getDay())) } : {},
86
- ...c ? { dayOfMonth: String(d.getDate()) } : {}
82
+ time: `${e(p.getHours())}:${e(p.getMinutes())}`,
83
+ ...l ? { dayOfWeek: String(o(p.getDay())) } : {},
84
+ ...m ? { dayOfMonth: m } : {}
87
85
  };
88
- }, m = (e) => {
86
+ }, _ = (e) => {
89
87
  if (!e.model || typeof e.prompt != "string" || !e.prompt.trim() && !e.skillUrl) return {
90
88
  ok: !1,
91
89
  reason: t.MissingRequiredFields
92
90
  };
93
- let { date: n, cron: r } = e.trigger, a = !!n;
94
- if (a === !!r) return {
91
+ let { date: n, cron: r } = e.trigger, i = !!n;
92
+ if (i === !!r) return {
95
93
  ok: !1,
96
94
  reason: t.UnsupportedTriggerType
97
95
  };
98
- let s = {
96
+ let a = {
99
97
  displayName: e.displayName,
100
98
  modelId: e.model,
101
99
  prompt: e.prompt,
102
100
  ...e.skillUrl ? { skillUrl: e.skillUrl } : {},
103
101
  ...e.description ? { description: e.description } : {}
104
102
  };
105
- if (a) return {
103
+ if (i) return {
106
104
  ok: !0,
107
105
  values: {
108
- ...s,
109
- repeat: i.OneTime,
110
- runAt: d(n),
111
- time: o
106
+ ...a,
107
+ repeat: s.OneTime,
108
+ runAt: m(n),
109
+ time: l
112
110
  }
113
111
  };
114
112
  if (!r) return {
115
113
  ok: !1,
116
114
  reason: t.UnsupportedTriggerType
117
115
  };
118
- let c = p(r.fields);
119
- if (!c.ok) return {
116
+ let o = g(r.fields);
117
+ if (!o.ok) return {
120
118
  ok: !1,
121
119
  reason: t.UnsupportedCronShape
122
120
  };
123
- if (c.isHourly) return {
121
+ if (o.isHourly) return {
124
122
  ok: !0,
125
123
  values: {
126
- ...s,
127
- repeat: i.Hourly,
128
- time: o,
129
- minute: c.minute,
130
- ...r.startDate ? { startDate: f(r.startDate) } : {},
131
- ...r.endDate ? { endDate: f(r.endDate) } : {}
124
+ ...a,
125
+ repeat: s.Hourly,
126
+ time: l,
127
+ minute: o.minute,
128
+ ...r.startDate ? { startDate: h(r.startDate) } : {},
129
+ ...r.endDate ? { endDate: h(r.endDate) } : {}
132
130
  }
133
131
  };
134
- let l = i.Daily;
135
- return c.dayOfWeek ? l = i.Weekly : c.dayOfMonth && (l = i.Monthly), {
132
+ let c = s.Daily;
133
+ return o.dayOfWeek ? c = s.Weekly : o.dayOfMonth && (c = s.Monthly), {
136
134
  ok: !0,
137
135
  values: {
138
- ...s,
139
- repeat: l,
140
- time: c.time,
141
- ...c.dayOfWeek ? { dayOfWeek: c.dayOfWeek } : {},
142
- ...c.dayOfMonth ? { dayOfMonth: c.dayOfMonth } : {},
143
- ...r.startDate ? { startDate: f(r.startDate) } : {},
144
- ...r.endDate ? { endDate: f(r.endDate) } : {}
136
+ ...a,
137
+ repeat: c,
138
+ time: o.time,
139
+ ...o.dayOfWeek ? { dayOfWeek: o.dayOfWeek } : {},
140
+ ...o.dayOfMonth ? { dayOfMonth: o.dayOfMonth } : {},
141
+ ...r.startDate ? { startDate: h(r.startDate) } : {},
142
+ ...r.endDate ? { endDate: h(r.endDate) } : {}
145
143
  }
146
144
  };
147
145
  };
148
146
  //#endregion
149
- export { l as mapFormValuesToCreateBody, u as mapFormValuesToUpdateBody, m as mapScheduledTaskDtoToFormValues };
147
+ export { f as mapFormValuesToCreateBody, p as mapFormValuesToUpdateBody, _ as mapScheduledTaskDtoToFormValues };
@@ -25,6 +25,8 @@ export declare const createScheduledTasksApiClient: (client: ScheduledTasksConfi
25
25
  * Unsupported constraints remain Custom, with the full source expression.
26
26
  * Calendar-month shifts crossing month boundaries or days 29–31 remain
27
27
  * Custom because a shifted monthly day is not equivalent around short months.
28
+ * The one exception is `day: 'last'` one day behind local time, which is
29
+ * exactly the local 1st.
28
30
  */
29
31
  export declare const describeScheduledTaskTrigger: (trigger: ScheduleTriggerDto, { timeZone, referenceDate, }?: ScheduledTaskTriggerDescriptionOptions) => ScheduledTaskTriggerDescription;
30
32
 
@@ -0,0 +1,13 @@
1
+ //#region src/shared/cron-day-of-month.ts
2
+ var e = "last", t = 31, n = 864e5, r = (e) => Math.round((Date.UTC(e.getUTCFullYear(), e.getUTCMonth(), e.getUTCDate()) - Date.UTC(e.getFullYear(), e.getMonth(), e.getDate())) / n), i = (n, r) => {
3
+ let i = n + r;
4
+ return i < 1 ? e : i > t ? "1" : String(i);
5
+ }, a = (e, n) => {
6
+ if (e === "last") return n === -1 ? "1" : void 0;
7
+ let r = Number(e);
8
+ if (!/^\d+$/.test(e) || r < 1 || r > t) return;
9
+ let i = r - n;
10
+ return i < 1 ? String(t) : i > t ? "1" : String(i);
11
+ };
12
+ //#endregion
13
+ export { e as CRON_LAST_DAY_OF_MONTH, r as getUtcDayShift, a as toLocalDayOfMonth, i as toUtcCronDayOfMonth };