@epam/ai-dial-chat-hooks 1.2.0-dev.266 → 1.2.0-dev.270

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
@@ -4100,6 +4100,18 @@ export declare const splitFileNameExtension: (fileName: string) => {
4100
4100
  extension: string;
4101
4101
  };
4102
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
+
4103
4115
  /**
4104
4116
  * Answers one question: would appending this text after the fence that
4105
4117
  * `buildSkillManifest` writes produce a *second* frontmatter block?
@@ -5306,7 +5318,7 @@ export declare interface UseConversationStreamParams {
5306
5318
 
5307
5319
  /** Return value of {@link useConversationStream}. */
5308
5320
  export declare interface UseConversationStreamResult {
5309
- 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;
5310
5322
  handleStop: () => void;
5311
5323
  resumeIfAwaitingGeneration: (currentConversationId: string, conversation: Conversation) => void;
5312
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.266",
4
+ "version": "1.2.0-dev.270",
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.266",
114
+ "@epam/ai-dial-chat-api-client": "1.2.0-dev.270",
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.266",
124
- "@epam/ai-dial-attachment-input": "1.2.0-dev.266",
125
- "@epam/ai-dial-catalog": "1.2.0-dev.266",
126
- "@epam/ai-dial-chat-overlay": "1.2.0-dev.266",
127
- "@epam/ai-dial-chat-shared": "1.2.0-dev.266",
128
- "@epam/ai-dial-mcp-apps": "1.2.0-dev.266",
129
- "@epam/ai-dial-publish-panel": "1.2.0-dev.266",
130
- "@epam/ai-dial-quotations": "1.2.0-dev.266",
123
+ "@epam/ai-dial-attachment-canvas": "1.2.0-dev.270",
124
+ "@epam/ai-dial-attachment-input": "1.2.0-dev.270",
125
+ "@epam/ai-dial-catalog": "1.2.0-dev.270",
126
+ "@epam/ai-dial-chat-overlay": "1.2.0-dev.270",
127
+ "@epam/ai-dial-chat-shared": "1.2.0-dev.270",
128
+ "@epam/ai-dial-mcp-apps": "1.2.0-dev.270",
129
+ "@epam/ai-dial-publish-panel": "1.2.0-dev.270",
130
+ "@epam/ai-dial-quotations": "1.2.0-dev.270",
131
131
  "@epam/ai-dial-react-file-manager": "^0.3.0-dev.22",
132
- "@epam/ai-dial-scheduled-tasks": "1.2.0-dev.266",
133
- "@epam/ai-dial-share": "1.2.0-dev.266",
134
- "@epam/ai-dial-skill-editor": "1.2.0-dev.266",
135
- "@epam/ai-dial-source-panel": "1.2.0-dev.266",
132
+ "@epam/ai-dial-scheduled-tasks": "1.2.0-dev.270",
133
+ "@epam/ai-dial-share": "1.2.0-dev.270",
134
+ "@epam/ai-dial-skill-editor": "1.2.0-dev.270",
135
+ "@epam/ai-dial-source-panel": "1.2.0-dev.270",
136
136
  "@epam/ai-dial-ui-kit": "^0.15.0-dev.36",
137
- "@epam/ai-dial-usage-dashboard": "1.2.0-dev.266",
137
+ "@epam/ai-dial-usage-dashboard": "1.2.0-dev.270",
138
138
  "@modelcontextprotocol/sdk": "^1.29.0",
139
139
  "@epam/pdf-highlighter-kit": "^0.0.19",
140
140
  "@mcp-ui/client": "^7.1.1"