@epam/ai-dial-chat-hooks 1.2.0-dev.3 → 1.2.0-dev.303

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/api-error/api-error.js +7 -4
  2. package/attachment/useAttachmentValidation/useAttachmentValidation.js +26 -19
  3. package/attachments.d.ts +10 -4
  4. package/catalog/catalog-derivations.js +1 -1
  5. package/catalog/deployment-id.js +8 -2
  6. package/catalog/map-deployment-limits-to-catalog.js +16 -24
  7. package/catalog/map-deployment-limits-to-input.js +81 -9
  8. package/catalog/map-deployment-to-catalog-item.js +34 -34
  9. package/catalog/map-entity-details-to-catalog.js +7 -0
  10. package/catalog/map-skill-to-catalog-item.js +55 -48
  11. package/catalog/publish.js +6 -5
  12. package/catalog/useApplicationCredentials/useApplicationCredentials.js +39 -0
  13. package/catalog/useCatalogEditNavigation/useCatalogEditNavigation.js +122 -101
  14. package/catalog/usePublishFolders/usePublishFolders.js +1 -1
  15. package/catalog/useSkillDetailsPanelData/useSkillDetailsPanelData.js +39 -39
  16. package/catalog/useSkillItemDetails.js +19 -17
  17. package/catalog.d.ts +159 -35
  18. package/catalog.js +23 -22
  19. package/conversation/announcement-message.js +16 -5
  20. package/conversation/conversation-transfer/export-conversation.js +24 -16
  21. package/conversation/conversation-transfer/import-conversation.js +80 -31
  22. package/conversation/conversation-transfer/queue.js +8 -5
  23. package/conversation/create-chat-stream-api.js +85 -49
  24. package/conversation/message-utils.js +44 -2
  25. package/conversation/stage.js +27 -0
  26. package/conversation/useActiveConversationSync/useActiveConversationSync.js +7 -8
  27. package/conversation/useAttachmentUpload/useAttachmentUpload.js +12 -5
  28. package/conversation/useConversationExport/useConversationExport.js +9 -9
  29. package/conversation/useConversationHandlers/message-utils.js +8 -5
  30. package/conversation/useConversationHandlers/useConversationHandlers.js +187 -177
  31. package/conversation/useConversationImport/useConversationImport.js +123 -121
  32. package/conversation/useConversationPanelItems/useConversationPanelItems.js +50 -32
  33. package/conversation/useConversationScroll/useConversationScroll.js +68 -64
  34. package/conversation/useConversationStream/apply-chunk.js +1 -1
  35. package/conversation/useConversationStream/frame-scheduler.js +39 -0
  36. package/conversation/useConversationStream/generation-resume.js +122 -64
  37. package/conversation/useConversationStream/useConversationStream.js +279 -116
  38. package/conversation/useMessageSelectionReply/useMessageSelectionReply.js +189 -0
  39. package/conversation/useTranscribeAudio/transcription-retry.js +5 -4
  40. package/conversation-overlay.d.ts +7 -0
  41. package/conversation-overlay.js +2 -0
  42. package/conversation-sources/useConversationSources/useConversationSources.js +31 -24
  43. package/conversation-sources.d.ts +1 -1
  44. package/conversation-transfer.d.ts +2 -1
  45. package/conversation.d.ts +328 -25
  46. package/conversation.js +32 -30
  47. package/file-manager-canvas.d.ts +418 -0
  48. package/file-manager-canvas.js +2 -0
  49. package/file-manager.d.ts +155 -359
  50. package/file-manager.js +25 -24
  51. package/files/attachment-canvas.js +116 -55
  52. package/files/attachment-types.js +14 -13
  53. package/files/dial-file-manager-copy-move.util.js +9 -8
  54. package/files/dial-file-manager-mapping.util.js +2 -1
  55. package/files/dial-file-manager-path.util.js +24 -2
  56. package/files/dial-file-manager.model.js +23 -19
  57. package/files/dial-file-manager.types.js +3 -3
  58. package/files/file-manager-variant.js +1 -1
  59. package/files/resolve-dial-file-api-path.js +11 -12
  60. package/files/useDialFileListing/useDialFileListing.js +140 -127
  61. package/files/useDialFileManager/useDialFileManager.js +139 -135
  62. package/files/useDialFileManagerSections/useDialFileManagerSections.js +155 -0
  63. package/files/useDialFileManagerTabConfig/useDialFileManagerTabConfig.js +20 -19
  64. package/files/useDialFileMutations/useDialFileMutations.js +65 -60
  65. package/files/useDialFileUploadBatch/useDialFileUploadBatch.js +117 -110
  66. package/files/useFileAttachmentPicker/useFileAttachmentPicker.js +48 -0
  67. package/index.d.ts +1281 -136
  68. package/index.js +136 -122
  69. package/mcp-apps/useMcpAppHostAdapter/useMcpAppHostAdapter.js +7 -5
  70. package/mcp-apps/useMcpAppHostContext/useMcpAppHostContext.js +1 -1
  71. package/mcp-apps/useMcpAppTools/useMcpAppTools.js +1 -1
  72. package/mcp-apps/useOpenMcpAppCanvas/useOpenMcpAppCanvas.js +25 -23
  73. package/mcp-apps.d.ts +8 -6
  74. package/oauth/toolset-id.js +5 -3
  75. package/oauth/useToolsetLogin/useToolsetLogin.js +8 -8
  76. package/oauth.d.ts +32 -0
  77. package/oauth.js +9 -9
  78. package/package.json +38 -23
  79. package/scheduled-task/scheduled-task-description.js +81 -0
  80. package/scheduled-task/scheduled-task-preparation.js +24 -0
  81. package/scheduled-task/scheduled-task-trigger.js +74 -71
  82. package/scheduled-task/scheduled-tasks-api-client.js +19 -0
  83. package/scheduled-task/use-scheduled-task-runs.js +194 -0
  84. package/scheduled-task/use-scheduled-tasks.js +93 -0
  85. package/scheduled-tasks.d.ts +197 -3
  86. package/scheduled-tasks.js +7 -2
  87. package/shared/application-schema.js +5 -2
  88. package/shared/cron-day-of-month.js +13 -0
  89. package/skill/skill-archive.js +19 -0
  90. package/skill/skill-types.js +8 -7
  91. package/skill/skill.js +53 -27
  92. package/skill/useSkillArchiveImport/useSkillArchiveImport.js +79 -0
  93. package/skill/useSkillEditorLoad.js +65 -59
  94. package/skill/useSkillEditorSubmit.js +108 -84
  95. package/skill/useSkillFileActions.js +70 -58
  96. package/skill-editor.d.ts +160 -8
  97. package/skill-editor.js +9 -8
  98. package/usage/map-usage-data-to-dashboard.js +66 -0
  99. package/usage/map-user-usage-to-model-limits.js +202 -0
  100. package/usage.d.ts +125 -0
  101. package/usage.js +3 -0
  102. package/usePageFileDrag/usePageFileDrag.js +3 -3
  103. package/utils.d.ts +26 -6
  104. package/utils.js +10 -10
@@ -1,260 +1,270 @@
1
1
  import { useAttachmentUpload as e } from "../useAttachmentUpload/useAttachmentUpload.js";
2
2
  import { attachmentsToDtos as t } from "./attachment-to-dto.js";
3
3
  import { createMessagePair as n } from "./message-factory.js";
4
- import { hasActiveToolConfig as r, shouldRerunGenerationOnEdit as i } from "./message-utils.js";
5
- import { getStarterDisplayText as a, getStarterSubmitText as o } from "./starter-option.js";
6
- import { getConversationPath as s } from "../useConversationStream/conversation-path.js";
7
- import { MessageRole as c, generateUUID as l } from "@epam/ai-dial-chat-shared";
8
- import { useCallback as u, useState as d } from "react";
9
- import { SendCompletionDtoModeEnum as f } from "@epam/ai-dial-chat-api-client";
4
+ import { hasActiveToolConfig as r, shouldRerunGenerationOnEdit as i, withToolConfiguration as a } from "./message-utils.js";
5
+ import { getStarterDisplayText as o, getStarterSubmitText as s } from "./starter-option.js";
6
+ import { getConversationPath as c } from "../useConversationStream/conversation-path.js";
7
+ import { MessageRole as l, generateUUID as u } from "@epam/ai-dial-chat-shared";
8
+ import { useCallback as d, useState as f } from "react";
9
+ import { SendCompletionDtoModeEnum as p } from "@epam/ai-dial-chat-api-client";
10
10
  //#region src/conversation/useConversationHandlers/useConversationHandlers.ts
11
- var p = ({ conversation: p, conversationId: m, bucket: h, isStreaming: g, startStream: _, state: { setConversation: v, conversationRef: y }, filesApi: b, conversationsApi: x, rateApi: S, resolveModelId: C, onConversationDeleted: w, showNetworkError: T, toolConfigurationValue: E }) => {
12
- let [D, O] = d(null), [k, A] = d(/* @__PURE__ */ new Set()), [j, M] = d(null), { handleUploadAttachment: N } = e({
13
- filesApi: b,
14
- bucket: h,
15
- onNetworkError: T
16
- }), P = u(async (e, i, a) => {
17
- if (!m || !p) return;
18
- let o = t(i), s = r(E), c = o?.length || s || a?.length ? {
11
+ var m = ({ conversation: m, conversationId: h, bucket: g, isStreaming: _, startStream: v, state: { setConversation: y, conversationRef: b }, filesApi: x, conversationsApi: S, rateApi: C, resolveModelId: w, onConversationDeleted: T, showNetworkError: E, toolConfigurationValue: D }) => {
12
+ let [O, k] = f(null), [A, j] = f(/* @__PURE__ */ new Set()), [M, N] = f(null), { handleUploadAttachment: P } = e({
13
+ filesApi: x,
14
+ bucket: g,
15
+ onNetworkError: E
16
+ }), F = d(async (e, i, a) => {
17
+ if (!h || !m) return;
18
+ let o = t(i), s = r(D), c = o?.length || s || a?.length ? {
19
19
  ...o?.length ? { attachments: o } : {},
20
- ...s ? { configuration_value: E } : {},
20
+ ...s ? { configuration_value: D } : {},
21
21
  ...a?.length ? { skills: a } : {}
22
- } : void 0, u = C(), { userMessage: d, assistantMessage: h } = n(e, c, u);
23
- v((e) => {
22
+ } : void 0, l = w(), { userMessage: d, assistantMessage: f } = n(e, c, l);
23
+ y((e) => {
24
24
  if (!e) return e;
25
25
  let t = {
26
26
  ...e,
27
27
  messages: [
28
28
  ...e.messages,
29
29
  d,
30
- h
30
+ f
31
31
  ]
32
32
  };
33
- return y.current = t, t;
34
- }), _(m, e, p.messages.length + 1, u, c, l(), f.Append);
33
+ return b.current = t, t;
34
+ }), v(h, e, m.messages.length + 1, l, c, u(), p.Append);
35
35
  }, [
36
- p,
37
36
  m,
37
+ h,
38
+ b,
39
+ w,
38
40
  y,
39
- C,
40
41
  v,
41
- _,
42
- E
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();
48
- v((t) => {
49
- if (!t) return t;
50
- let r = {
51
- ...t.messages[e],
52
- content: "",
53
- custom_content: void 0,
54
- wasStoppedByUser: void 0,
55
- stoppedWithoutContent: void 0,
56
- streamErrorMessage: void 0,
57
- deploymentId: n
58
- }, i = {
59
- ...t,
60
- messages: [...t.messages.slice(0, e), r]
61
- };
62
- return y.current = i, i;
63
- }), A((t) => new Set([...t].filter((t) => t < e))), _(m, t.content, e, n, t.custom_content, l(), f.Regenerate);
42
+ D
43
+ ]), I = d((e) => {
44
+ let t = b.current;
45
+ if (_ || !h || !t || e === -1 || t.messages[e]?.role !== l.Assistant) return;
46
+ let n = t.messages[e - 1];
47
+ if (!n || n.role !== l.User) return;
48
+ let r = w(), i = a(n.custom_content, D), o = {
49
+ ...t.messages[e],
50
+ content: "",
51
+ custom_content: void 0,
52
+ wasStoppedByUser: void 0,
53
+ stoppedWithoutContent: void 0,
54
+ streamErrorMessage: void 0,
55
+ deploymentId: r
56
+ }, s = {
57
+ ...t,
58
+ messages: [
59
+ ...t.messages.slice(0, e - 1),
60
+ {
61
+ ...n,
62
+ custom_content: i
63
+ },
64
+ o
65
+ ]
66
+ };
67
+ b.current = s, y(s), j((t) => new Set([...t].filter((t) => t < e))), v(h, n.content, e, r, i, u(), p.Regenerate);
64
68
  }, [
65
- p,
66
- m,
69
+ h,
70
+ b,
71
+ _,
72
+ w,
67
73
  y,
68
- g,
69
- C,
70
74
  v,
71
- _
72
- ]), I = u((e) => {
73
- g || O(e);
74
- }, [g]), L = u(() => {
75
- if (!m || D == null) return;
76
- let e = D;
77
- O(null);
78
- let t = y.current;
75
+ D
76
+ ]), L = d((e) => {
77
+ _ || k(e);
78
+ }, [_]), R = d(() => {
79
+ if (!h || O == null) return;
80
+ let e = O;
81
+ k(null);
82
+ let t = b.current;
79
83
  if (!t || e === -1) return;
80
- let n = s(m), r = t.messages[e + 1]?.role === c.Assistant ? t.messages.filter((t, n) => n !== e && n !== e + 1) : t.messages.filter((t, n) => n !== e);
81
- if (r.length === 0 || r.length === 1 && r[0].role === c.Status) {
82
- x.deleteConversation({ path: n }), w?.();
84
+ let n = c(h), r = t.messages[e + 1]?.role === l.Assistant ? t.messages.filter((t, n) => n !== e && n !== e + 1) : t.messages.filter((t, n) => n !== e);
85
+ if (r.length === 0 || r.length === 1 && r[0].role === l.Status) {
86
+ S.deleteConversation({ path: n }), T?.();
83
87
  return;
84
88
  }
85
89
  let i = {
86
90
  ...t,
87
91
  messages: r
88
92
  };
89
- y.current = i, v(i), x.saveConversation({
93
+ b.current = i, y(i), S.saveConversation({
90
94
  path: n,
91
95
  saveConversationBodyDto: { conversation: i }
92
96
  });
93
97
  }, [
94
- m,
95
- y,
96
- x,
97
- w,
98
- D,
99
- v
100
- ]), R = u(async (e, t, n) => {
101
- if (!m || !p) return !1;
102
- let r = p.messages[e];
103
- if (!r) return !1;
104
- let i = r.rating, a = {
105
- ...p,
106
- messages: p.messages.map((n, r) => r === e ? {
98
+ h,
99
+ b,
100
+ S,
101
+ T,
102
+ O,
103
+ y
104
+ ]), z = d(async (e, t, n) => {
105
+ let r = b.current;
106
+ if (!h || !r) return !1;
107
+ let i = r.messages[e];
108
+ if (!i) return !1;
109
+ let a = i.rating, o = {
110
+ ...r,
111
+ messages: r.messages.map((n, r) => r === e ? {
107
112
  ...n,
108
113
  rating: t ?? void 0
109
114
  } : n)
110
115
  };
111
- v(() => (y.current = a, a));
112
- let o = s(m), c = () => {
113
- v((t) => t && {
114
- ...t,
115
- messages: t.messages.map((t, n) => n === e ? {
116
+ y(() => (b.current = o, o));
117
+ let s = c(h), l = () => {
118
+ y((t) => {
119
+ if (!t) return t;
120
+ let n = {
116
121
  ...t,
117
- rating: i
118
- } : t)
122
+ messages: t.messages.map((t, n) => n === e ? {
123
+ ...t,
124
+ rating: a
125
+ } : t)
126
+ };
127
+ return b.current = n, n;
119
128
  });
120
- }, l = () => x.saveConversation({
121
- path: o,
122
- saveConversationBodyDto: { conversation: a }
123
- }), u = r.responseId;
124
- if (!u) return c(), !1;
129
+ }, u = () => S.saveConversation({
130
+ path: s,
131
+ saveConversationBodyDto: { conversation: o }
132
+ }), d = i.responseId;
133
+ if (!d) return l(), !1;
125
134
  try {
126
- return await S.rateMessage({ rateMessageDto: {
127
- conversationId: p.id,
128
- responseId: u,
129
- modelId: p.model.id,
135
+ return await C.rateMessage({ rateMessageDto: {
136
+ conversationId: r.id,
137
+ responseId: d,
138
+ modelId: r.model.id,
130
139
  rate: t,
131
140
  ...n ? { comment: n } : {}
132
- } }), await l(), !0;
141
+ } }), await u(), !0;
133
142
  } catch {
134
- return c(), !1;
143
+ return l(), !1;
135
144
  }
136
145
  }, [
137
- p,
138
- m,
139
- y,
140
- x,
146
+ h,
147
+ b,
141
148
  S,
142
- v
143
- ]), z = u((e, t, i) => {
144
- if (!m || !p) return;
145
- let s = a(e, i), c = o(e, i), u = t ? { [t]: e.const } : void 0, d = r(E), h = u || d ? {
146
- ...u ? { form_value: u } : {},
147
- ...d ? { configuration_value: E } : {}
148
- } : void 0, g = C(), { userMessage: b, assistantMessage: x } = n(s, h, g);
149
- v((e) => {
149
+ C,
150
+ y
151
+ ]), B = d((e, t, i) => {
152
+ let a = b.current;
153
+ if (!h || !a) return;
154
+ let c = o(e, i), l = s(e, i), d = t ? { [t]: e.const } : void 0, f = r(D), m = d || f ? {
155
+ ...d ? { form_value: d } : {},
156
+ ...f ? { configuration_value: D } : {}
157
+ } : void 0, g = w(), { userMessage: _, assistantMessage: x } = n(c, m, g);
158
+ y((e) => {
150
159
  if (!e) return e;
151
160
  let t = {
152
161
  ...e,
153
162
  messages: [
154
163
  ...e.messages,
155
- b,
164
+ _,
156
165
  x
157
166
  ]
158
167
  };
159
- return y.current = t, t;
160
- }), _(m, c, p.messages.length + 1, g, h, l(), f.Append);
168
+ return b.current = t, t;
169
+ }), v(h, l, a.messages.length + 1, g, m, u(), p.Append);
161
170
  }, [
162
- p,
163
- m,
171
+ h,
172
+ b,
173
+ w,
164
174
  y,
165
- C,
166
175
  v,
167
- _,
168
- E
176
+ D
169
177
  ]);
170
178
  return {
171
- handleSend: P,
172
- handleUploadAttachment: N,
173
- handleRegenerateMessage: F,
174
- handleDeleteMessage: I,
175
- handleConfirmDelete: L,
176
- handleRateMessage: R,
177
- handleButtonSelect: u((e, t, n) => {
178
- !m || !p || g || (e["dial:widgetOptions"].confirmationMessage ? M({
179
+ handleSend: F,
180
+ handleUploadAttachment: P,
181
+ handleRegenerateMessage: I,
182
+ handleDeleteMessage: L,
183
+ handleConfirmDelete: R,
184
+ handleRateMessage: z,
185
+ handleButtonSelect: d((e, t, n) => {
186
+ let r = b.current;
187
+ !h || !r || _ || (e["dial:widgetOptions"].confirmationMessage ? N({
179
188
  starter: e,
180
189
  propertyKey: t,
181
190
  description: n
182
- }) : z(e, t, n));
191
+ }) : B(e, t, n));
183
192
  }, [
184
- p,
185
- m,
186
- g,
187
- z
193
+ h,
194
+ b,
195
+ _,
196
+ B
188
197
  ]),
189
- handleConfirmStarter: u(() => {
190
- if (!j) return;
191
- let { starter: e, propertyKey: t, description: n } = j;
192
- M(null), z(e, t, n);
193
- }, [j, z]),
194
- handleStartEdit: u((e) => {
195
- A((t) => new Set([...t, e]));
198
+ handleConfirmStarter: d(() => {
199
+ if (!M) return;
200
+ let { starter: e, propertyKey: t, description: n } = M;
201
+ N(null), B(e, t, n);
202
+ }, [M, B]),
203
+ handleStartEdit: d((e) => {
204
+ j((t) => new Set([...t, e]));
196
205
  }, []),
197
- handleCancelEdit: u((e) => {
198
- A((t) => {
206
+ handleCancelEdit: d((e) => {
207
+ j((t) => {
199
208
  let n = new Set(t);
200
209
  return n.delete(e), n;
201
210
  });
202
211
  }, []),
203
- handleEditMessage: u(async (e, n, r, a, o) => {
204
- if (g || !m || !p) return;
205
- let s = e;
206
- if (s === -1 || p.messages[s].role !== c.User) return;
207
- let u = p.messages[s];
208
- if (!i(p.messages, s, n, r, a, o)) {
209
- A((e) => {
212
+ handleEditMessage: d(async (e, n, r, o, s) => {
213
+ let c = b.current;
214
+ if (_ || !h || !c) return;
215
+ let d = e;
216
+ if (d === -1 || c.messages[d].role !== l.User) return;
217
+ let f = c.messages[d];
218
+ if (!i(c.messages, d, n, r, o, s)) {
219
+ j((e) => {
210
220
  let t = new Set(e);
211
- return t.delete(s), t;
221
+ return t.delete(d), t;
212
222
  });
213
223
  return;
214
224
  }
215
- let d = t(a), h = new Set(r.map((e) => e.id)), b = [...(u.custom_content?.attachments ?? []).filter((e) => {
225
+ let m = t(o), g = new Set(r.map((e) => e.id)), x = [...(f.custom_content?.attachments ?? []).filter((e) => {
216
226
  let t = e.url ?? e.data ?? e.title;
217
- return h.has(t);
218
- }), ...d ?? []], { attachments: x, skills: S, ...w } = u.custom_content ?? {}, T = o ?? S, E;
219
- E = b.length > 0 || T?.length ? {
220
- ...w,
221
- ...b.length > 0 ? { attachments: b } : {},
222
- ...T?.length ? { skills: T } : {}
223
- } : Object.keys(w).length > 0 ? w : void 0;
224
- let D = {
225
- ...u,
227
+ return g.has(t);
228
+ }), ...m ?? []], { attachments: S, skills: C, ...T } = f.custom_content ?? {}, E = s ?? C, O;
229
+ O = x.length > 0 || E?.length ? {
230
+ ...T,
231
+ ...x.length > 0 ? { attachments: x } : {},
232
+ ...E?.length ? { skills: E } : {}
233
+ } : Object.keys(T).length > 0 ? T : void 0, O = a(O, D);
234
+ let k = {
235
+ ...f,
226
236
  content: n,
227
- custom_content: E
228
- }, O = Date.now(), k = {
229
- role: c.Assistant,
237
+ custom_content: O
238
+ }, A = Date.now(), M = {
239
+ role: l.Assistant,
230
240
  content: "",
231
- timestamp: new Date(O).toISOString()
232
- }, j = [
233
- ...p.messages.slice(0, s),
234
- D,
235
- k
236
- ], M = {
237
- ...p,
238
- messages: j
241
+ timestamp: new Date(A).toISOString()
242
+ }, N = [
243
+ ...c.messages.slice(0, d),
244
+ k,
245
+ M
246
+ ], P = {
247
+ ...c,
248
+ messages: N
239
249
  };
240
- y.current = M, v(M);
241
- let N = C();
242
- _(m, n, j.length - 1, N, E, l(), f.Edit), A(/* @__PURE__ */ new Set());
250
+ b.current = P, y(P);
251
+ let F = w();
252
+ v(h, n, N.length - 1, F, O, u(), p.Edit), j(/* @__PURE__ */ new Set());
243
253
  }, [
244
- p,
245
- m,
254
+ h,
255
+ b,
256
+ _,
257
+ w,
246
258
  y,
247
- g,
248
- C,
249
259
  v,
250
- _
260
+ D
251
261
  ]),
252
- editingMessageIndexes: k,
253
- pendingDeleteIndex: D,
254
- setPendingDeleteIndex: O,
255
- pendingStarterContext: j,
256
- setPendingStarterContext: M
262
+ editingMessageIndexes: A,
263
+ pendingDeleteIndex: O,
264
+ setPendingDeleteIndex: k,
265
+ pendingStarterContext: M,
266
+ setPendingStarterContext: N
257
267
  };
258
268
  };
259
269
  //#endregion
260
- export { p as useConversationHandlers };
270
+ export { m as useConversationHandlers };