@epam/ai-dial-chat-hooks 1.2.0-dev.219 → 1.2.0-dev.229

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.
@@ -14,10 +14,14 @@ var t = (t) => t === e.Completed ? e.Completed : t === e.Failed ? e.Failed : nul
14
14
  status: t(e.status),
15
15
  ...e.content != null && { content: e.content },
16
16
  ...e.tag != null && { tag: e.tag },
17
- ...e.attachments?.length && { attachments: e.attachments.map(n) }
17
+ ...e.attachments?.length && { attachments: e.attachments.map(n) },
18
+ ...e.parent_stage_index != null && { parent_stage_index: e.parent_stage_index }
18
19
  }), i = (e) => {
19
20
  let t = Array.isArray(e) ? e : e?.custom_content?.stages ?? e?.customContent?.stages;
20
- if (t?.length) return t.map(r);
21
+ if (t?.length) return t.map((e, t) => r(e.index == null ? {
22
+ ...e,
23
+ index: t
24
+ } : e));
21
25
  };
22
26
  //#endregion
23
27
  export { i as mapStages, r as toStage };
@@ -41,34 +41,34 @@ var p = ({ conversation: p, conversationId: m, bucket: h, isStreaming: g, startS
41
41
  _,
42
42
  E
43
43
  ]), F = u((e) => {
44
- if (g || !m || !p || e === -1 || p.messages[e]?.role !== c.Assistant) return;
45
- let t = p.messages[e - 1];
46
- if (!t || t.role !== c.User) return;
47
- let n = C(), i = r(E) ? {
48
- ...t.custom_content,
44
+ let t = y.current;
45
+ if (g || !m || !t || e === -1 || t.messages[e]?.role !== c.Assistant) return;
46
+ let n = t.messages[e - 1];
47
+ if (!n || n.role !== c.User) return;
48
+ let i = C(), a = r(E) ? {
49
+ ...n.custom_content,
49
50
  configuration_value: E
50
- } : t.custom_content, a = {
51
- ...p.messages[e],
51
+ } : n.custom_content, o = {
52
+ ...t.messages[e],
52
53
  content: "",
53
54
  custom_content: void 0,
54
55
  wasStoppedByUser: void 0,
55
56
  stoppedWithoutContent: void 0,
56
57
  streamErrorMessage: void 0,
57
- deploymentId: n
58
- }, o = {
59
- ...p,
58
+ deploymentId: i
59
+ }, s = {
60
+ ...t,
60
61
  messages: [
61
- ...p.messages.slice(0, e - 1),
62
+ ...t.messages.slice(0, e - 1),
62
63
  {
63
- ...t,
64
- custom_content: i
64
+ ...n,
65
+ custom_content: a
65
66
  },
66
- a
67
+ o
67
68
  ]
68
69
  };
69
- y.current = o, v(o), A((t) => new Set([...t].filter((t) => t < e))), _(m, t.content, e, n, i, l(), f.Regenerate);
70
+ y.current = s, v(s), A((t) => new Set([...t].filter((t) => t < e))), _(m, n.content, e, i, a, l(), f.Regenerate);
70
71
  }, [
71
- p,
72
72
  m,
73
73
  y,
74
74
  g,
@@ -105,54 +105,59 @@ var p = ({ conversation: p, conversationId: m, bucket: h, isStreaming: g, startS
105
105
  D,
106
106
  v
107
107
  ]), R = u(async (e, t, n) => {
108
- if (!m || !p) return !1;
109
- let r = p.messages[e];
110
- if (!r) return !1;
111
- let i = r.rating, a = {
112
- ...p,
113
- messages: p.messages.map((n, r) => r === e ? {
108
+ let r = y.current;
109
+ if (!m || !r) return !1;
110
+ let i = r.messages[e];
111
+ if (!i) return !1;
112
+ let a = i.rating, o = {
113
+ ...r,
114
+ messages: r.messages.map((n, r) => r === e ? {
114
115
  ...n,
115
116
  rating: t ?? void 0
116
117
  } : n)
117
118
  };
118
- v(() => (y.current = a, a));
119
- let o = s(m), c = () => {
120
- v((t) => t && {
121
- ...t,
122
- messages: t.messages.map((t, n) => n === e ? {
119
+ v(() => (y.current = o, o));
120
+ let c = s(m), l = () => {
121
+ v((t) => {
122
+ if (!t) return t;
123
+ let n = {
123
124
  ...t,
124
- rating: i
125
- } : t)
125
+ messages: t.messages.map((t, n) => n === e ? {
126
+ ...t,
127
+ rating: a
128
+ } : t)
129
+ };
130
+ return y.current = n, n;
126
131
  });
127
- }, l = () => x.saveConversation({
128
- path: o,
129
- saveConversationBodyDto: { conversation: a }
130
- }), u = r.responseId;
131
- if (!u) return c(), !1;
132
+ }, u = () => x.saveConversation({
133
+ path: c,
134
+ saveConversationBodyDto: { conversation: o }
135
+ }), d = i.responseId;
136
+ if (!d) return l(), !1;
132
137
  try {
133
138
  return await S.rateMessage({ rateMessageDto: {
134
- conversationId: p.id,
135
- responseId: u,
136
- modelId: p.model.id,
139
+ conversationId: r.id,
140
+ responseId: d,
141
+ modelId: r.model.id,
137
142
  rate: t,
138
143
  ...n ? { comment: n } : {}
139
- } }), await l(), !0;
144
+ } }), await u(), !0;
140
145
  } catch {
141
- return c(), !1;
146
+ return l(), !1;
142
147
  }
143
148
  }, [
144
- p,
145
149
  m,
146
150
  y,
147
151
  x,
148
152
  S,
149
153
  v
150
154
  ]), z = u((e, t, i) => {
151
- if (!m || !p) return;
152
- let s = a(e, i), c = o(e, i), u = t ? { [t]: e.const } : void 0, d = r(E), h = u || d ? {
153
- ...u ? { form_value: u } : {},
154
- ...d ? { configuration_value: E } : {}
155
- } : void 0, g = C(), { userMessage: b, assistantMessage: x } = n(s, h, g);
155
+ let s = y.current;
156
+ if (!m || !s) return;
157
+ let c = a(e, i), u = o(e, i), d = t ? { [t]: e.const } : void 0, p = r(E), h = d || p ? {
158
+ ...d ? { form_value: d } : {},
159
+ ...p ? { configuration_value: E } : {}
160
+ } : void 0, g = C(), { userMessage: b, assistantMessage: x } = n(c, h, g);
156
161
  v((e) => {
157
162
  if (!e) return e;
158
163
  let t = {
@@ -164,9 +169,8 @@ var p = ({ conversation: p, conversationId: m, bucket: h, isStreaming: g, startS
164
169
  ]
165
170
  };
166
171
  return y.current = t, t;
167
- }), _(m, c, p.messages.length + 1, g, h, l(), f.Append);
172
+ }), _(m, u, s.messages.length + 1, g, h, l(), f.Append);
168
173
  }, [
169
- p,
170
174
  m,
171
175
  y,
172
176
  C,
@@ -182,14 +186,15 @@ var p = ({ conversation: p, conversationId: m, bucket: h, isStreaming: g, startS
182
186
  handleConfirmDelete: L,
183
187
  handleRateMessage: R,
184
188
  handleButtonSelect: u((e, t, n) => {
185
- !m || !p || g || (e["dial:widgetOptions"].confirmationMessage ? M({
189
+ let r = y.current;
190
+ !m || !r || g || (e["dial:widgetOptions"].confirmationMessage ? M({
186
191
  starter: e,
187
192
  propertyKey: t,
188
193
  description: n
189
194
  }) : z(e, t, n));
190
195
  }, [
191
- p,
192
196
  m,
197
+ y,
193
198
  g,
194
199
  z
195
200
  ]),
@@ -208,28 +213,29 @@ var p = ({ conversation: p, conversationId: m, bucket: h, isStreaming: g, startS
208
213
  });
209
214
  }, []),
210
215
  handleEditMessage: u(async (e, n, r, a, o) => {
211
- if (g || !m || !p) return;
212
- let s = e;
213
- if (s === -1 || p.messages[s].role !== c.User) return;
214
- let u = p.messages[s];
215
- if (!i(p.messages, s, n, r, a, o)) {
216
+ let s = y.current;
217
+ if (g || !m || !s) return;
218
+ let u = e;
219
+ if (u === -1 || s.messages[u].role !== c.User) return;
220
+ let d = s.messages[u];
221
+ if (!i(s.messages, u, n, r, a, o)) {
216
222
  A((e) => {
217
223
  let t = new Set(e);
218
- return t.delete(s), t;
224
+ return t.delete(u), t;
219
225
  });
220
226
  return;
221
227
  }
222
- let d = t(a), h = new Set(r.map((e) => e.id)), b = [...(u.custom_content?.attachments ?? []).filter((e) => {
228
+ let p = t(a), h = new Set(r.map((e) => e.id)), b = [...(d.custom_content?.attachments ?? []).filter((e) => {
223
229
  let t = e.url ?? e.data ?? e.title;
224
230
  return h.has(t);
225
- }), ...d ?? []], { attachments: x, skills: S, ...w } = u.custom_content ?? {}, T = o ?? S, E;
231
+ }), ...p ?? []], { attachments: x, skills: S, ...w } = d.custom_content ?? {}, T = o ?? S, E;
226
232
  E = b.length > 0 || T?.length ? {
227
233
  ...w,
228
234
  ...b.length > 0 ? { attachments: b } : {},
229
235
  ...T?.length ? { skills: T } : {}
230
236
  } : Object.keys(w).length > 0 ? w : void 0;
231
237
  let D = {
232
- ...u,
238
+ ...d,
233
239
  content: n,
234
240
  custom_content: E
235
241
  }, O = Date.now(), k = {
@@ -237,18 +243,17 @@ var p = ({ conversation: p, conversationId: m, bucket: h, isStreaming: g, startS
237
243
  content: "",
238
244
  timestamp: new Date(O).toISOString()
239
245
  }, j = [
240
- ...p.messages.slice(0, s),
246
+ ...s.messages.slice(0, u),
241
247
  D,
242
248
  k
243
249
  ], M = {
244
- ...p,
250
+ ...s,
245
251
  messages: j
246
252
  };
247
253
  y.current = M, v(M);
248
254
  let N = C();
249
255
  _(m, n, j.length - 1, N, E, l(), f.Edit), A(/* @__PURE__ */ new Set());
250
256
  }, [
251
- p,
252
257
  m,
253
258
  y,
254
259
  g,
@@ -0,0 +1,39 @@
1
+ //#region src/conversation/useConversationStream/frame-scheduler.ts
2
+ var e = 16, t = (t) => {
3
+ if (typeof requestAnimationFrame == "function") {
4
+ let e = requestAnimationFrame(t);
5
+ return () => cancelAnimationFrame(e);
6
+ }
7
+ let n = setTimeout(t, e);
8
+ return () => clearTimeout(n);
9
+ }, n = () => {
10
+ let e = /* @__PURE__ */ new Map(), n = (t) => {
11
+ let n = e.get(t);
12
+ n && (e.delete(t), n.task());
13
+ };
14
+ return {
15
+ schedule: (r, i) => {
16
+ let a = e.get(r);
17
+ if (a) {
18
+ a.task = i;
19
+ return;
20
+ }
21
+ let o = {
22
+ task: i,
23
+ cancelFrame: () => void 0
24
+ };
25
+ e.set(r, o), o.cancelFrame = t(() => n(r));
26
+ },
27
+ flush: (t) => {
28
+ e.get(t)?.cancelFrame(), n(t);
29
+ },
30
+ cancel: (t) => {
31
+ e.get(t)?.cancelFrame(), e.delete(t);
32
+ },
33
+ cancelAll: () => {
34
+ e.forEach((e) => e.cancelFrame()), e.clear();
35
+ }
36
+ };
37
+ };
38
+ //#endregion
39
+ export { n as createFrameScheduler };
@@ -62,62 +62,68 @@ var s = (e) => {
62
62
  } catch {} finally {
63
63
  n.releaseLock();
64
64
  }
65
- }, h = ({ transport: o, setConversation: d, conversationRef: f, resumingPathsRef: p, bufferedGenerationsRef: h, addStreamingPath: g, removeStreamingPath: _, isPathDisplayed: v, generationPersistenceErrorMessage: y = t }) => (t, b, x = {}) => {
66
- if (!c(b)) {
67
- x.onSettled?.();
65
+ }, h = ({ transport: o, setConversation: d, conversationRef: f, resumingPathsRef: p, bufferedGenerationsRef: h, addStreamingPath: g, removeStreamingPath: _, isPathDisplayed: v, generationPersistenceErrorMessage: y = t, frameScheduler: b }) => (t, x, S = {}) => {
66
+ if (!c(x)) {
67
+ S.onSettled?.();
68
68
  return;
69
69
  }
70
- let S = r(t);
71
- if (!x.skipDedupe && p.current.has(S)) return;
72
- p.current.add(S), g(S);
73
- let C = b.messages.length - 1, w = {
70
+ let C = r(t);
71
+ if (!S.skipDedupe && p.current.has(C)) return;
72
+ p.current.add(C), g(C);
73
+ let w = x.messages.length - 1, T = {
74
74
  generationId: u,
75
- messageIndex: C,
76
- message: x.seedMessage ?? b.messages[C]
75
+ messageIndex: w,
76
+ message: S.seedMessage ?? x.messages[w]
77
77
  };
78
- h.current.set(S, w);
79
- let T = () => h.current.get(S) === w, E = (e, t = !1) => {
80
- if (!T()) return;
81
- p.current.delete(S), _(S);
82
- let n = e && e.messages.length - 1 === C && c(e) && s(w.message);
78
+ h.current.set(C, T);
79
+ let E = () => h.current.get(C) === T, D = (e, t = !1) => {
80
+ if (b?.flush(C), !E()) return;
81
+ p.current.delete(C), _(C);
82
+ let n = e && e.messages.length - 1 === w && c(e) && s(T.message);
83
83
  if (t || n) {
84
- w.message = {
85
- ...w.message,
84
+ T.message = {
85
+ ...T.message,
86
86
  streamErrorMessage: y
87
- }, v(S) && d((e) => {
88
- if (!e || !T() || !v(S)) return e;
89
- let t = a(e, w);
87
+ }, v(C) && d((e) => {
88
+ if (!e || !E() || !v(C)) return e;
89
+ let t = a(e, T);
90
90
  return f.current = t, t;
91
91
  });
92
92
  return;
93
93
  }
94
- h.current.delete(S), e && v(S) && (d(e), f.current = e);
95
- }, D = async () => {
94
+ h.current.delete(C), e && v(C) && (d(e), f.current = e);
95
+ }, O = async () => {
96
96
  try {
97
- E(await o.getConversation(e(t)));
97
+ D(await o.getConversation(e(t)));
98
98
  } catch {
99
- E(void 0, s(w.message));
99
+ D(void 0, s(T.message));
100
100
  }
101
- }, O = (e) => {
102
- T() && (w.message = e, v(S) && d((e) => {
103
- if (!e || !T() || !v(S)) return e;
104
- let t = a(e, w);
105
- return f.current = t, t;
106
- }));
107
101
  }, k = (e) => {
108
- if (!T()) return;
109
- let t = i([w.message], 0, e);
110
- t && (w.message = t[0]), v(S) && d((e) => {
111
- if (!e || !T() || !v(S)) return e;
112
- let t = a(e, w);
102
+ b?.cancel(C), E() && (T.message = e, v(C) && d((e) => {
103
+ if (!e || !E() || !v(C)) return e;
104
+ let t = a(e, T);
113
105
  return f.current = t, t;
114
- });
115
- }, A = async () => {
106
+ }));
107
+ }, A = () => d((e) => {
108
+ if (!e || !E() || !v(C)) return e;
109
+ let t = a(e, T);
110
+ return f.current = t, t;
111
+ }), j = (e) => {
112
+ if (!E()) return;
113
+ let t = i([T.message], 0, e);
114
+ if (t && (T.message = t[0]), v(C)) {
115
+ if (b) {
116
+ b.schedule(C, A);
117
+ return;
118
+ }
119
+ A();
120
+ }
121
+ }, M = async () => {
116
122
  let n = new AbortController(), r;
117
123
  try {
118
- r = await o.watchConversation(S, n.signal);
124
+ r = await o.watchConversation(C, n.signal);
119
125
  } catch {
120
- await D();
126
+ await O();
121
127
  return;
122
128
  }
123
129
  let i = !1, a = window.setTimeout(() => {
@@ -128,38 +134,38 @@ var s = (e) => {
128
134
  if (n?.action !== "UPDATE") return !1;
129
135
  try {
130
136
  let n = await o.getConversation(e(t));
131
- if (!c(n)) return E(n), i = !0, !0;
137
+ if (!c(n)) return D(n), i = !0, !0;
132
138
  } catch {}
133
139
  return !1;
134
140
  });
135
141
  } finally {
136
142
  clearTimeout(a);
137
143
  }
138
- i || await D();
139
- }, j = async () => {
144
+ i || await O();
145
+ }, N = async () => {
140
146
  let e = new AbortController(), t;
141
147
  try {
142
- t = await o.attachToGeneration(S, e.signal);
148
+ t = await o.attachToGeneration(C, e.signal);
143
149
  } catch {
144
150
  return !1;
145
151
  }
146
152
  let r = !1, i = !1;
147
153
  return await m(t, (e) => {
148
- if (!T()) return !0;
154
+ if (!E()) return !0;
149
155
  switch (e.type) {
150
- case "snapshot": return O(e.message), !1;
151
- case "chunk": return k(e.chunk), !1;
156
+ case "snapshot": return k(e.message), !1;
157
+ case "chunk": return j(e.chunk), !1;
152
158
  case "done":
153
159
  case "error":
154
160
  case "stopped": return i = e.type === "error" && e.errorType === n.type, r = !0, !0;
155
161
  }
156
- }), r ? (i ? E(void 0, !0) : await D(), !0) : !T();
162
+ }), r ? (i ? D(void 0, !0) : await O(), !0) : !E();
157
163
  };
158
164
  (async () => {
159
165
  try {
160
- await j() || await A();
166
+ await N() || await M();
161
167
  } finally {
162
- x.onSettled?.();
168
+ S.onSettled?.();
163
169
  }
164
170
  })();
165
171
  };
@@ -4,224 +4,248 @@ 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
6
  import { createResumeIfAwaitingGeneration as u, fetchConversationForRecovery as d, hasGeneratedPayload as f, isAwaitingGenerationResume as p } from "./generation-resume.js";
7
- import { MessageRole as m, generateUUID as h } from "@epam/ai-dial-chat-shared";
7
+ import { createFrameScheduler as m } from "./frame-scheduler.js";
8
+ import { MessageRole as ee, generateUUID as h } from "@epam/ai-dial-chat-shared";
8
9
  import { useCallback as g, useEffect as _, useMemo as v, useRef as y, useState as b } from "react";
9
10
  import { SendCompletionDtoModeEnum as x } from "@epam/ai-dial-chat-api-client";
10
11
  //#region src/conversation/useConversationStream/useConversationStream.ts
11
- var S = 2e4, ee = (e, t, n) => e instanceof i ? n : e instanceof r ? t : e instanceof o ? e.message : "", C = ({ conversationId: r, state: { setConversation: o, conversationRef: C }, transport: w, generation: { startGeneration: T, completeGeneration: E }, channel: D, overlay: O, onStopError: k, generationConflictMessage: A = t, generationPersistenceErrorMessage: j = n, onStreamError: M }) => {
12
- let N = y(M);
12
+ var te = 2e4, ne = (e, t, n) => e instanceof i ? n : e instanceof r ? t : e instanceof o ? e.message : "", S = ({ conversationId: r, state: { setConversation: o, conversationRef: S }, transport: C, generation: { startGeneration: w, completeGeneration: T }, channel: E, overlay: D, onStopError: O, generationConflictMessage: k = t, generationPersistenceErrorMessage: A = n, onStreamError: j, batchChunksPerFrame: M = !1 }) => {
13
+ let N = y(j);
13
14
  _(() => {
14
- N.current = M;
15
- }, [M]);
16
- let [P, F] = b(() => /* @__PURE__ */ new Set()), [I, L] = b(null), R = y(null), z = y(null), B = y(/* @__PURE__ */ new Set()), V = y(/* @__PURE__ */ new Map()), H = y(/* @__PURE__ */ new Set()), U = y(/* @__PURE__ */ new Map()), W = y(r);
15
+ N.current = j;
16
+ }, [j]);
17
+ let P = y(M);
17
18
  _(() => {
18
- W.current = r;
19
- }, [r]);
20
- let G = g((e) => s(W.current ?? "") === e, []), K = g((e) => {
21
- F((t) => {
19
+ P.current = M;
20
+ }, [M]);
21
+ let [F] = b(m), [I, L] = b(() => /* @__PURE__ */ new Set()), [R, z] = b(null), B = y(null), V = y(null), H = y(/* @__PURE__ */ new Set()), U = y(/* @__PURE__ */ new Map()), W = y(/* @__PURE__ */ new Set()), G = y(/* @__PURE__ */ new Map()), K = y(r);
22
+ _(() => (K.current = r, () => F.cancelAll()), [r, F]);
23
+ let q = g((e) => s(K.current ?? "") === e, []), J = g((e) => {
24
+ L((t) => {
22
25
  if (t.has(e)) return t;
23
26
  let n = new Set(t);
24
27
  return n.add(e), n;
25
28
  });
26
- }, []), q = g((e) => {
27
- F((t) => {
29
+ }, []), Y = g((e) => {
30
+ L((t) => {
28
31
  if (!t.has(e)) return t;
29
32
  let n = new Set(t);
30
33
  return n.delete(e), n;
31
34
  });
32
- }, []), J = v(() => u({
33
- transport: w,
35
+ }, []), X = v(() => u({
36
+ transport: C,
34
37
  setConversation: o,
35
- conversationRef: C,
36
- resumingPathsRef: B,
37
- bufferedGenerationsRef: V,
38
- addStreamingPath: K,
39
- removeStreamingPath: q,
40
- isPathDisplayed: G,
41
- generationPersistenceErrorMessage: j
38
+ conversationRef: S,
39
+ resumingPathsRef: H,
40
+ bufferedGenerationsRef: U,
41
+ addStreamingPath: J,
42
+ removeStreamingPath: Y,
43
+ isPathDisplayed: q,
44
+ generationPersistenceErrorMessage: A,
45
+ frameScheduler: M ? F : void 0
42
46
  }), [
43
- K,
47
+ J,
48
+ Y,
44
49
  q,
45
- G,
46
- w,
47
- j
48
- ]), Y = g((t, n, r, u, g, _, v = x.Append) => {
49
- let y = _ ?? h(), b = s(t);
50
- B.current.delete(b), R.current = y, z.current = b, U.current.set(b, y), L(b);
51
- let k;
52
- v === x.Regenerate ? k = r : v === x.Edit && (k = r - 1);
53
- let M = () => U.current.get(b) !== y, P = T(b, y), F = C.current?.messages[r];
54
- F ? V.current.set(b, {
55
- generationId: y,
50
+ C,
51
+ A,
52
+ M,
53
+ F
54
+ ]), Z = g((t, n, r, u, m, g, _ = x.Append) => {
55
+ let v = g ?? h(), y = s(t);
56
+ F.flush(y), H.current.delete(y), B.current = v, V.current = y, G.current.set(y, v), z(y);
57
+ let b;
58
+ _ === x.Regenerate ? b = r : _ === x.Edit && (b = r - 1);
59
+ let O = () => G.current.get(y) !== v, j = w(y, v), M = S.current?.messages[r];
60
+ M ? U.current.set(y, {
61
+ generationId: v,
56
62
  messageIndex: r,
57
- message: F
58
- }) : V.current.delete(b), K(b), O?.notifyGenerationStart?.(), D?.ensureConnected();
63
+ message: M
64
+ }) : U.current.delete(y), J(y), D?.notifyGenerationStart?.(), E?.ensureConnected();
59
65
  let I = () => {
60
- M() || q(b), R.current === y && (R.current = null, z.current = null, L(null)), E(b, y), D?.notifyGenerationSettled?.();
61
- }, W = () => {
62
- if (M()) return;
63
- let e = V.current.get(b);
64
- !e || e.generationId !== y || (e.message = {
66
+ O() || Y(y), B.current === v && (B.current = null, V.current = null, z(null)), T(y, v), E?.notifyGenerationSettled?.();
67
+ }, L = () => {
68
+ if (O()) return;
69
+ let e = U.current.get(y);
70
+ !e || e.generationId !== v || (e.message = {
65
71
  ...e.message,
66
- streamErrorMessage: j
67
- }, N.current?.(new i()), G(b) && o((t) => {
68
- if (!t || M() || !G(b)) return t;
72
+ streamErrorMessage: A
73
+ }, N.current?.(new i()), q(y) && o((t) => {
74
+ if (!t || O() || !q(y)) return t;
69
75
  let n = l(t, e);
70
- return C.current = n, n;
76
+ return S.current = n, n;
71
77
  }));
72
- }, Y = {
73
- signal: P.signal,
78
+ }, R = {
79
+ signal: j.signal,
74
80
  onChunk: (e) => {
75
- if (R.current !== y) return;
76
- let t = V.current.get(b);
77
- if (t?.generationId === y) {
81
+ if (B.current !== v) return;
82
+ let t = U.current.get(y);
83
+ if (t?.generationId === v) {
78
84
  let n = c([t.message], 0, e);
79
85
  n && (t.message = n[0]);
80
86
  }
81
- G(b) && o((t) => {
82
- if (!t) return t;
83
- let n = V.current.get(b), i;
84
- if (n?.generationId === y) i = l(t, n);
85
- else {
86
- let n = c(t.messages, r, e);
87
- if (!n) return t;
88
- i = {
89
- ...t,
90
- messages: n
91
- };
87
+ if (q(y)) {
88
+ if (P.current && t?.generationId === v) {
89
+ F.schedule(y, () => {
90
+ let e = U.current.get(y);
91
+ if (B.current !== v || !q(y) || e?.generationId !== v) return;
92
+ let t = { ...e };
93
+ o((e) => {
94
+ if (!e) return e;
95
+ let n = l(e, t);
96
+ return S.current = n, n;
97
+ });
98
+ });
99
+ return;
92
100
  }
93
- return C.current = i, i;
94
- });
101
+ o((t) => {
102
+ if (!t) return t;
103
+ let n = U.current.get(y), i;
104
+ if (n?.generationId === v) i = l(t, n);
105
+ else {
106
+ let n = c(t.messages, r, e);
107
+ if (!n) return t;
108
+ i = {
109
+ ...t,
110
+ messages: n
111
+ };
112
+ }
113
+ return S.current = i, i;
114
+ });
115
+ }
95
116
  },
96
117
  onComplete: async () => {
97
- let n = V.current.get(b), r = n?.generationId === y ? n : void 0;
98
- if (I(), H.current.has(y) ? H.current.delete(y) : M() || O?.notifyGenerationEnd?.(), !M()) {
99
- if (!G(b)) {
100
- r && V.current.delete(b);
118
+ F.flush(y);
119
+ let n = U.current.get(y), r = n?.generationId === v ? n : void 0;
120
+ if (I(), W.current.has(v) ? W.current.delete(v) : O() || D?.notifyGenerationEnd?.(), !O()) {
121
+ if (!q(y)) {
122
+ r && U.current.delete(y);
101
123
  return;
102
124
  }
103
125
  try {
104
- let n = await w.getConversation(e(t));
105
- if (M()) return;
106
- if (!G(b)) {
107
- r && V.current.delete(b);
126
+ let n = await C.getConversation(e(t));
127
+ if (O()) return;
128
+ if (!q(y)) {
129
+ r && U.current.delete(y);
108
130
  return;
109
131
  }
110
132
  if (r && r.messageIndex === n.messages.length - 1 && p(n) && f(r.message)) {
111
- W();
133
+ L();
112
134
  return;
113
135
  }
114
- r && V.current.delete(b), o(n), C.current = n;
136
+ r && U.current.delete(y), o(n), S.current = n;
115
137
  } catch {
116
- M() || W();
138
+ O() || L();
117
139
  }
118
140
  }
119
141
  },
120
142
  onError: (e) => {
121
- if (N.current?.(e), e instanceof a && !M()) {
143
+ if (F.flush(y), N.current?.(e), e instanceof a && !O()) {
122
144
  Q(e);
123
145
  return;
124
146
  }
125
- X(e);
147
+ K(e);
126
148
  }
127
- }, X = (e) => {
128
- let t = V.current.get(b), n = t?.generationId === y ? t : void 0;
149
+ }, K = (e) => {
150
+ let t = U.current.get(y), n = t?.generationId === v ? t : void 0;
129
151
  if (n && (e instanceof i ? n.message = {
130
152
  ...n.message,
131
- streamErrorMessage: j
132
- } : V.current.delete(b)), I(), M() || !G(b)) return;
133
- let a = ee(e, A, j);
153
+ streamErrorMessage: A
154
+ } : U.current.delete(y)), I(), O() || !q(y)) return;
155
+ let a = ne(e, k, A);
134
156
  o((e) => {
135
- if (!e || M() || !G(b)) return e;
136
- let t = n?.generationId === y ? l(e, n) : e, i = {
157
+ if (!e || O() || !q(y)) return e;
158
+ let t = n?.generationId === v ? l(e, n) : e, i = {
137
159
  ...t,
138
160
  messages: t.messages.map((e, t) => t === r ? {
139
161
  ...e,
140
162
  streamErrorMessage: a
141
163
  } : e)
142
164
  };
143
- return C.current = i, i;
165
+ return S.current = i, i;
144
166
  });
145
167
  }, Z = () => {
146
- I(), H.current.has(y) ? H.current.delete(y) : M() || O?.notifyGenerationEnd?.();
168
+ I(), W.current.has(v) ? W.current.delete(v) : O() || D?.notifyGenerationEnd?.();
147
169
  }, Q = async (n) => {
148
- B.current.add(b);
149
- let i = await d(() => w.getConversation(e(t)), M);
150
- if (M()) {
170
+ H.current.add(y);
171
+ let i = await d(() => C.getConversation(e(t)), O);
172
+ if (O()) {
151
173
  I();
152
174
  return;
153
175
  }
154
- let a = i?.messages[i.messages.length - 1], s = i != null && i.messages.length - 1 === r && a?.role === m.Assistant;
176
+ let a = i?.messages[i.messages.length - 1], s = i != null && i.messages.length - 1 === r && a?.role === ee.Assistant;
155
177
  if (!i || !s) {
156
- B.current.delete(b), X(n);
178
+ H.current.delete(y), K(n);
157
179
  return;
158
180
  }
159
- let c = V.current.get(b), l = c?.generationId === y ? c : void 0;
181
+ let c = U.current.get(y), l = c?.generationId === v ? c : void 0;
160
182
  if (p(i)) {
161
- J(t, i, {
183
+ X(t, i, {
162
184
  seedMessage: l?.message,
163
185
  skipDedupe: !0,
164
186
  onSettled: Z
165
187
  });
166
188
  return;
167
189
  }
168
- B.current.delete(b), l && V.current.delete(b), G(b) && (o(i), C.current = i), Z();
190
+ H.current.delete(y), l && U.current.delete(y), q(y) && (o(i), S.current = i), Z();
169
191
  };
170
192
  (async () => {
171
193
  try {
172
- let e = D?.channelId ?? await D?.waitForChannel(S) ?? void 0, t = H.current.has(y);
173
- if (P.signal.aborted || M() || t) {
174
- V.current.get(b)?.generationId === y && V.current.delete(b), M() || q(b), R.current === y && (R.current = null, z.current = null, L(null)), E(b, y), D?.notifyGenerationSettled?.(), t ? H.current.delete(y) : M() || O?.notifyGenerationEnd?.();
194
+ let e = E?.channelId ?? await E?.waitForChannel(te) ?? void 0, t = W.current.has(v);
195
+ if (j.signal.aborted || O() || t) {
196
+ U.current.get(y)?.generationId === v && U.current.delete(y), O() || Y(y), B.current === v && (B.current = null, V.current = null, z(null)), T(y, v), E?.notifyGenerationSettled?.(), t ? W.current.delete(v) : O() || D?.notifyGenerationEnd?.();
175
197
  return;
176
198
  }
177
- w.streamCompletion(b, n, u, Y, g, y, v, k, e);
199
+ C.streamCompletion(y, n, u, R, m, v, _, b, e);
178
200
  } catch (e) {
179
- Y.onError(e instanceof Error ? e : Error(String(e)));
201
+ R.onError(e instanceof Error ? e : Error(String(e)));
180
202
  }
181
203
  })();
182
204
  }, [
183
- T,
184
- E,
185
- K,
186
- q,
187
- G,
188
- D?.channelId,
189
- D?.ensureConnected,
190
- D?.waitForChannel,
191
- D?.notifyGenerationSettled,
192
- O,
193
205
  w,
206
+ T,
194
207
  J,
208
+ Y,
209
+ q,
210
+ E?.channelId,
211
+ E?.ensureConnected,
212
+ E?.waitForChannel,
213
+ E?.notifyGenerationSettled,
214
+ D,
215
+ C,
216
+ X,
217
+ k,
195
218
  A,
196
- j
197
- ]), X = g((e, t) => {
198
- let n = s(e), r = V.current.get(n);
219
+ F
220
+ ]), Q = g((e, t) => {
221
+ let n = s(e), r = U.current.get(n);
199
222
  return r ? l(t, r) : t;
200
- }, []), Z = g(() => {
201
- let e = R.current;
223
+ }, []), re = g(() => {
224
+ let e = B.current;
202
225
  if (!e || !r) return;
203
226
  let t = s(r);
204
- z.current === t && (H.current.add(e), O?.notifyStopGenerating?.(), w.stopCompletion({
227
+ V.current === t && (W.current.add(e), F.flush(t), D?.notifyStopGenerating?.(), C.stopCompletion({
205
228
  generationId: e,
206
229
  path: t
207
230
  }).catch((e) => {
208
231
  let t = e instanceof Error ? e : Error(String(e));
209
- k?.(t);
232
+ O?.(t);
210
233
  }));
211
234
  }, [
212
235
  r,
213
- k,
236
+ F,
214
237
  O,
215
- w
216
- ]), Q = g((e, t) => J(e, t), [J]), te = r != null && P.has(s(r)), $ = r == null ? null : s(r);
238
+ D,
239
+ C
240
+ ]), ie = g((e, t) => X(e, t), [X]), ae = r != null && I.has(s(r)), $ = r == null ? null : s(r);
217
241
  return {
218
- startStream: Y,
219
- handleStop: Z,
220
- resumeIfAwaitingGeneration: Q,
221
- restoreBufferedGeneration: X,
222
- isStreaming: te,
223
- canStopStreaming: $ != null && I === $
242
+ startStream: Z,
243
+ handleStop: re,
244
+ resumeIfAwaitingGeneration: ie,
245
+ restoreBufferedGeneration: Q,
246
+ isStreaming: ae,
247
+ canStopStreaming: $ != null && R === $
224
248
  };
225
249
  };
226
250
  //#endregion
227
- export { C as useConversationStream };
251
+ export { S as useConversationStream };
package/conversation.d.ts CHANGED
@@ -643,9 +643,12 @@ declare interface LocalModeValues {
643
643
  }
644
644
 
645
645
  /**
646
- * Returns the normalized stages of a raw stage array or a message-like
647
- * payload (reading `custom_content.stages`, falling back to
648
- * `customContent.stages`), or `undefined` when there are none.
646
+ * Returns the normalized stages of a complete raw stage array or a
647
+ * message-like payload (reading `custom_content.stages`, falling back to
648
+ * `customContent.stages`), or `undefined` when there are none. An entry
649
+ * without an `index` takes its array position — the identity a complete
650
+ * non-streaming array's `parent_stage_index` refers to — while explicit
651
+ * (possibly sparse) indexes are kept. Not for partial stream deltas.
649
652
  */
650
653
  export declare const mapStages: (source: RawStage[] | RawStageSource | null | undefined) => Stage[] | undefined;
651
654
 
@@ -731,6 +734,11 @@ export declare interface RawStage {
731
734
  tag?: string | null;
732
735
  /** Files produced or referenced by this stage. */
733
736
  attachments?: RawStageAttachment[] | null;
737
+ /**
738
+ * `index` of the parent stage (its array position in a complete unindexed
739
+ * array). Nullish means top level; `0` is a valid parent.
740
+ */
741
+ parent_stage_index?: number | null;
734
742
  }
735
743
 
736
744
  /**
@@ -851,7 +859,8 @@ export declare class StreamUpstreamError extends Error {
851
859
  /**
852
860
  * Returns a renderable `Stage` for one raw payload: `index` defaults to `0`,
853
861
  * `name` to `''`, an unrecognized `status` to `null` (still running), and
854
- * `content`/`tag`/`attachments` are passed through when present.
862
+ * `content`/`tag`/`attachments`/`parent_stage_index` are passed through when
863
+ * present (a parent of `0` included).
855
864
  */
856
865
  export declare const toStage: (stage: RawStage) => Stage;
857
866
 
@@ -1133,7 +1142,7 @@ export declare interface UseConversationPanelItemsResolvers {
1133
1142
  * `transport`/`generation`/`channel`/`overlay` capabilities rather than any
1134
1143
  * app context or `server-api` import.
1135
1144
  */
1136
- export declare const useConversationStream: ({ conversationId, state: { setConversation, conversationRef }, transport, generation: { startGeneration, completeGeneration }, channel, overlay, onStopError, generationConflictMessage, generationPersistenceErrorMessage, onStreamError, }: UseConversationStreamParams) => UseConversationStreamResult;
1145
+ export declare const useConversationStream: ({ conversationId, state: { setConversation, conversationRef }, transport, generation: { startGeneration, completeGeneration }, channel, overlay, onStopError, generationConflictMessage, generationPersistenceErrorMessage, onStreamError, batchChunksPerFrame, }: UseConversationStreamParams) => UseConversationStreamResult;
1137
1146
 
1138
1147
  /** Parameters for {@link useConversationStream}. */
1139
1148
  export declare interface UseConversationStreamParams {
@@ -1160,6 +1169,13 @@ export declare interface UseConversationStreamParams {
1160
1169
  * still log or report the raw error.
1161
1170
  */
1162
1171
  onStreamError?: (error: Error) => void;
1172
+ /**
1173
+ * Coalesces the displayed chunk updates into one `setConversation` per
1174
+ * animation frame. Chunks still reach the per-path buffer immediately, and
1175
+ * any pending update is flushed before completion, error, stop, or a
1176
+ * superseding generation. Defaults to `false` (one update per chunk).
1177
+ */
1178
+ batchChunksPerFrame?: boolean;
1163
1179
  }
1164
1180
 
1165
1181
  /** Return value of {@link useConversationStream}. */
@@ -21,6 +21,9 @@ export declare const annotationToOoxmlCanvasContent: (annotation: Annotation, an
21
21
  /**
22
22
  * Builds a `PdfCanvasContent` for a PDF citation annotation, including highlights
23
23
  * for the clicked annotation's document within its citation group.
24
+ * When the clicked annotation has a page but no selector with valid geometry,
25
+ * an invisible page-anchor highlight is added and selected so the viewer
26
+ * still opens that page.
24
27
  * Returns `null` if the annotation has no PDF source attachment.
25
28
  */
26
29
  export declare const annotationToPdfCanvasContent: (annotation: Annotation, groups: AnnotationGroup[], resolvers: AttachmentCanvasUrlResolvers) => PdfCanvasContent | null;
@@ -147,20 +147,43 @@ var g = (e, t) => URL.createObjectURL(s(e, t)), _ = (e) => {
147
147
  type: t.Html,
148
148
  srcdoc: i
149
149
  } : i;
150
- }, R = (n, r, i) => {
150
+ }, R = (e, t) => ({
151
+ id: e,
152
+ bboxes: [{
153
+ page: t,
154
+ x1: 0,
155
+ y1: 0,
156
+ x2: 0,
157
+ y2: 0
158
+ }],
159
+ style: {
160
+ backgroundColor: "transparent",
161
+ opacity: 0
162
+ }
163
+ }), z = (n, r, i) => {
151
164
  let a = n.body?.source?.attachment;
152
165
  if (a?.type !== o.PDF) return null;
153
166
  let s = e(a.url) ? i.resolveDialFileDownloadUrl(a.url) : a.url;
154
167
  if (s == null) return null;
155
- let c = (r.find((e) => e.annotations.includes(n))?.annotations ?? [n]).filter((e) => e.body?.source?.attachment?.url === a.url), u = c.indexOf(n), f = d(c), m = l(n, u);
168
+ let c = (r.find((e) => e.annotations.includes(n))?.annotations ?? [n]).filter((e) => e.body?.source?.attachment?.url === a.url), u = c.indexOf(n), f = d(c), m = l(n, u), h = p(n), g = f.some((e) => e.id === m);
169
+ if (!g && h != null) {
170
+ let e = `page-anchor-${m}`;
171
+ return {
172
+ type: t.Pdf,
173
+ url: s,
174
+ highlights: [...f, R(e, h)],
175
+ selectedHighlightId: e,
176
+ page: h
177
+ };
178
+ }
156
179
  return {
157
180
  type: t.Pdf,
158
181
  url: s,
159
182
  highlights: f,
160
- selectedHighlightId: f.some((e) => e.id === m) ? m : void 0,
161
- page: p(n)
183
+ selectedHighlightId: g ? m : void 0,
184
+ page: h
162
185
  };
163
- }, z = (e) => {
186
+ }, B = (e) => {
164
187
  switch (e.type) {
165
188
  case "docx_text_anchor": return {
166
189
  kind: i.DocxTableRow,
@@ -196,7 +219,7 @@ var g = (e, t) => URL.createObjectURL(s(e, t)), _ = (e) => {
196
219
  end: e.end
197
220
  };
198
221
  }
199
- }, B = (n, i, o) => {
222
+ }, V = (n, i, o) => {
200
223
  let s = n.body?.source?.attachment;
201
224
  if (s?.url == null) return null;
202
225
  let c = a(s.title ?? s.url, s.type);
@@ -210,7 +233,7 @@ var g = (e, t) => URL.createObjectURL(s(e, t)), _ = (e) => {
210
233
  let i = l(e, t);
211
234
  m.push({
212
235
  id: i,
213
- locations: r.map(z)
236
+ locations: r.map(B)
214
237
  }), e === n && (h = i);
215
238
  }), {
216
239
  type: t.Ooxml,
@@ -221,7 +244,7 @@ var g = (e, t) => URL.createObjectURL(s(e, t)), _ = (e) => {
221
244
  selectedHighlightId: h
222
245
  } : {}
223
246
  };
224
- }, V = (n, r) => {
247
+ }, H = (n, r) => {
225
248
  let i = m(n.url);
226
249
  if (i == null) return null;
227
250
  let a = e(i.baseUrl) ? r.resolveDialFileDownloadUrl(i.baseUrl) : i.baseUrl;
@@ -234,55 +257,42 @@ var g = (e, t) => URL.createObjectURL(s(e, t)), _ = (e) => {
234
257
  return {
235
258
  type: t.Pdf,
236
259
  url: a,
237
- highlights: [{
238
- id: o,
239
- bboxes: [{
240
- page: i.page,
241
- x1: 0,
242
- y1: 0,
243
- x2: 0,
244
- y2: 0
245
- }],
246
- style: {
247
- backgroundColor: "transparent",
248
- opacity: 0
249
- }
250
- }],
260
+ highlights: [R(o, i.page)],
251
261
  selectedHighlightId: o,
252
262
  page: i.page
253
263
  };
254
- }, H = (e) => {
264
+ }, U = (e) => {
255
265
  try {
256
266
  let t = new URL(e).protocol;
257
267
  return t === "http:" || t === "https:" || t === "blob:";
258
268
  } catch {
259
269
  return !1;
260
270
  }
261
- }, U = (t) => t.url != null && !e(t.url) && H(t.url) ? t.url : void 0, W = async (e, n) => {
271
+ }, W = (t) => t.url != null && !e(t.url) && U(t.url) ? t.url : void 0, G = async (e, n) => {
262
272
  let r = await O(e, n);
263
273
  if (r != null) return typeof r == "string" ? {
264
274
  type: t.Pdf,
265
275
  url: r
266
276
  } : r;
267
- let i = U(e);
277
+ let i = W(e);
268
278
  return i == null ? null : {
269
279
  type: t.Pdf,
270
280
  url: i
271
281
  };
272
- }, G = async (e, n, r) => {
282
+ }, K = async (e, n, r) => {
273
283
  let i = await O(e, n);
274
284
  if (i != null) return typeof i == "string" ? {
275
285
  type: t.Ooxml,
276
286
  url: i,
277
287
  format: r
278
288
  } : i;
279
- let a = U(e);
289
+ let a = W(e);
280
290
  return a == null ? null : {
281
291
  type: t.Ooxml,
282
292
  url: a,
283
293
  format: r
284
294
  };
285
- }, K = async (e, n) => {
295
+ }, q = async (e, n) => {
286
296
  let r = await k(e, n);
287
297
  if (r == null) return null;
288
298
  if (typeof r != "string") return r;
@@ -298,7 +308,7 @@ var g = (e, t) => URL.createObjectURL(s(e, t)), _ = (e) => {
298
308
  text: r
299
309
  };
300
310
  }
301
- }, q = async (e, n, r, i) => {
311
+ }, J = async (e, n, r, i) => {
302
312
  let a = await k(e, n);
303
313
  if (a == null || typeof a != "string") return null;
304
314
  let o = {};
@@ -320,7 +330,7 @@ var g = (e, t) => URL.createObjectURL(s(e, t)), _ = (e) => {
320
330
  visualizerName: r.title,
321
331
  requestTimeout: r.requestTimeout
322
332
  };
323
- }, J = (e, n, r, i) => {
333
+ }, Y = (e, n, r, i) => {
324
334
  let a = {
325
335
  width: r.width,
326
336
  height: r.height,
@@ -350,4 +360,4 @@ var g = (e, t) => URL.createObjectURL(s(e, t)), _ = (e) => {
350
360
  };
351
361
  };
352
362
  //#endregion
353
- export { B as annotationToOoxmlCanvasContent, R as annotationToPdfCanvasContent, S as clearAttachmentCache, A as hasAttachmentTextSource, V as referenceAttachmentToPdfCanvasContent, F as resolveCodeCanvasContent, J as resolveGroupedVisualizerCanvasContent, L as resolveHtmlCanvasContent, j as resolveImageCanvasContent, K as resolveJsonCanvasContent, N as resolveMarkdownCanvasContent, G as resolveOoxmlCanvasContent, W as resolvePdfCanvasContent, M as resolveTextCanvasContent, q as resolveVisualizerCanvasContent };
363
+ export { V as annotationToOoxmlCanvasContent, z as annotationToPdfCanvasContent, S as clearAttachmentCache, A as hasAttachmentTextSource, H as referenceAttachmentToPdfCanvasContent, F as resolveCodeCanvasContent, Y as resolveGroupedVisualizerCanvasContent, L as resolveHtmlCanvasContent, j as resolveImageCanvasContent, q as resolveJsonCanvasContent, N as resolveMarkdownCanvasContent, K as resolveOoxmlCanvasContent, G as resolvePdfCanvasContent, M as resolveTextCanvasContent, J as resolveVisualizerCanvasContent };
package/index.d.ts CHANGED
@@ -225,6 +225,9 @@ export declare const annotationToOoxmlCanvasContent: (annotation: Annotation, an
225
225
  /**
226
226
  * Builds a `PdfCanvasContent` for a PDF citation annotation, including highlights
227
227
  * for the clicked annotation's document within its citation group.
228
+ * When the clicked annotation has a page but no selector with valid geometry,
229
+ * an invisible page-anchor highlight is added and selected so the viewer
230
+ * still opens that page.
228
231
  * Returns `null` if the annotation has no PDF source attachment.
229
232
  */
230
233
  export declare const annotationToPdfCanvasContent: (annotation: Annotation, groups: AnnotationGroup[], resolvers: AttachmentCanvasUrlResolvers) => PdfCanvasContent | null;
@@ -2400,9 +2403,12 @@ export declare interface MapSkillToCatalogItemOptions {
2400
2403
  }
2401
2404
 
2402
2405
  /**
2403
- * Returns the normalized stages of a raw stage array or a message-like
2404
- * payload (reading `custom_content.stages`, falling back to
2405
- * `customContent.stages`), or `undefined` when there are none.
2406
+ * Returns the normalized stages of a complete raw stage array or a
2407
+ * message-like payload (reading `custom_content.stages`, falling back to
2408
+ * `customContent.stages`), or `undefined` when there are none. An entry
2409
+ * without an `index` takes its array position — the identity a complete
2410
+ * non-streaming array's `parent_stage_index` refers to — while explicit
2411
+ * (possibly sparse) indexes are kept. Not for partial stream deltas.
2406
2412
  */
2407
2413
  export declare const mapStages: (source: RawStage[] | RawStageSource | null | undefined) => Stage[] | undefined;
2408
2414
 
@@ -3221,6 +3227,11 @@ export declare interface RawStage {
3221
3227
  tag?: string | null;
3222
3228
  /** Files produced or referenced by this stage. */
3223
3229
  attachments?: RawStageAttachment[] | null;
3230
+ /**
3231
+ * `index` of the parent stage (its array position in a complete unindexed
3232
+ * array). Nullish means top level; `0` is a valid parent.
3233
+ */
3234
+ parent_stage_index?: number | null;
3224
3235
  }
3225
3236
 
3226
3237
  /**
@@ -4435,7 +4446,8 @@ export declare const toPublishRuleDto: (rule: PublicationRule) => PublishRuleDto
4435
4446
  /**
4436
4447
  * Returns a renderable `Stage` for one raw payload: `index` defaults to `0`,
4437
4448
  * `name` to `''`, an unrecognized `status` to `null` (still running), and
4438
- * `content`/`tag`/`attachments` are passed through when present.
4449
+ * `content`/`tag`/`attachments`/`parent_stage_index` are passed through when
4450
+ * present (a parent of `0` included).
4439
4451
  */
4440
4452
  export declare const toStage: (stage: RawStage) => Stage;
4441
4453
 
@@ -5225,7 +5237,7 @@ export declare interface UseConversationSourcesResult {
5225
5237
  * `transport`/`generation`/`channel`/`overlay` capabilities rather than any
5226
5238
  * app context or `server-api` import.
5227
5239
  */
5228
- export declare const useConversationStream: ({ conversationId, state: { setConversation, conversationRef }, transport, generation: { startGeneration, completeGeneration }, channel, overlay, onStopError, generationConflictMessage, generationPersistenceErrorMessage, onStreamError, }: UseConversationStreamParams) => UseConversationStreamResult;
5240
+ export declare const useConversationStream: ({ conversationId, state: { setConversation, conversationRef }, transport, generation: { startGeneration, completeGeneration }, channel, overlay, onStopError, generationConflictMessage, generationPersistenceErrorMessage, onStreamError, batchChunksPerFrame, }: UseConversationStreamParams) => UseConversationStreamResult;
5229
5241
 
5230
5242
  /** Parameters for {@link useConversationStream}. */
5231
5243
  export declare interface UseConversationStreamParams {
@@ -5252,6 +5264,13 @@ export declare interface UseConversationStreamParams {
5252
5264
  * still log or report the raw error.
5253
5265
  */
5254
5266
  onStreamError?: (error: Error) => void;
5267
+ /**
5268
+ * Coalesces the displayed chunk updates into one `setConversation` per
5269
+ * animation frame. Chunks still reach the per-path buffer immediately, and
5270
+ * any pending update is flushed before completion, error, stop, or a
5271
+ * superseding generation. Defaults to `false` (one update per chunk).
5272
+ */
5273
+ batchChunksPerFrame?: boolean;
5255
5274
  }
5256
5275
 
5257
5276
  /** Return value of {@link useConversationStream}. */
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.219",
4
+ "version": "1.2.0-dev.229",
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.219",
114
+ "@epam/ai-dial-chat-api-client": "1.2.0-dev.229",
115
115
  "dompurify": "3.4.15",
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.219",
124
- "@epam/ai-dial-attachment-input": "1.2.0-dev.219",
125
- "@epam/ai-dial-catalog": "1.2.0-dev.219",
126
- "@epam/ai-dial-chat-overlay": "1.2.0-dev.219",
127
- "@epam/ai-dial-chat-shared": "1.2.0-dev.219",
128
- "@epam/ai-dial-mcp-apps": "1.2.0-dev.219",
129
- "@epam/ai-dial-publish-panel": "1.2.0-dev.219",
130
- "@epam/ai-dial-quotations": "1.2.0-dev.219",
131
- "@epam/ai-dial-react-file-manager": "^0.3.0-dev.19",
132
- "@epam/ai-dial-scheduled-tasks": "1.2.0-dev.219",
133
- "@epam/ai-dial-share": "1.2.0-dev.219",
134
- "@epam/ai-dial-skill-editor": "1.2.0-dev.219",
135
- "@epam/ai-dial-source-panel": "1.2.0-dev.219",
136
- "@epam/ai-dial-ui-kit": "^0.15.0-dev.27",
137
- "@epam/ai-dial-usage-dashboard": "1.2.0-dev.219",
123
+ "@epam/ai-dial-attachment-canvas": "1.2.0-dev.229",
124
+ "@epam/ai-dial-attachment-input": "1.2.0-dev.229",
125
+ "@epam/ai-dial-catalog": "1.2.0-dev.229",
126
+ "@epam/ai-dial-chat-overlay": "1.2.0-dev.229",
127
+ "@epam/ai-dial-chat-shared": "1.2.0-dev.229",
128
+ "@epam/ai-dial-mcp-apps": "1.2.0-dev.229",
129
+ "@epam/ai-dial-publish-panel": "1.2.0-dev.229",
130
+ "@epam/ai-dial-quotations": "1.2.0-dev.229",
131
+ "@epam/ai-dial-react-file-manager": "^0.3.0-dev.20",
132
+ "@epam/ai-dial-scheduled-tasks": "1.2.0-dev.229",
133
+ "@epam/ai-dial-share": "1.2.0-dev.229",
134
+ "@epam/ai-dial-skill-editor": "1.2.0-dev.229",
135
+ "@epam/ai-dial-source-panel": "1.2.0-dev.229",
136
+ "@epam/ai-dial-ui-kit": "^0.15.0-dev.30",
137
+ "@epam/ai-dial-usage-dashboard": "1.2.0-dev.229",
138
138
  "@modelcontextprotocol/sdk": "^1.29.0",
139
139
  "@epam/pdf-highlighter-kit": "^0.0.19",
140
140
  "@mcp-ui/client": "^7.1.1"