@epam/ai-dial-chat-hooks 1.1.0-dev.459 → 1.1.0-dev.467

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.
@@ -20,6 +20,9 @@ var t = (e) => {
20
20
  },
21
21
  markTaken: (e) => {
22
22
  o.add(e);
23
+ },
24
+ release: (e) => {
25
+ o.delete(e);
23
26
  }
24
27
  };
25
28
  };
@@ -1,38 +1,55 @@
1
- import { sanitizeFileName as e } from "../../files/file-name.js";
2
- import { AttachmentErrorReason as t } from "@epam/ai-dial-chat-shared";
3
- import { useCallback as n, useRef as r } from "react";
1
+ import { formatDateYM as e } from "../conversation-transfer/date.js";
2
+ import { sanitizeFileName as t } from "../../files/file-name.js";
3
+ import { createUploadPathAllocator as n } from "../conversation-transfer/build-upload-path.js";
4
+ import { AttachmentErrorReason as r } from "@epam/ai-dial-chat-shared";
5
+ import { useCallback as i, useRef as a } from "react";
4
6
  //#region src/conversation/useAttachmentUpload/useAttachmentUpload.ts
5
- var i = 700, a = (t) => e(t.split("/").filter(Boolean).pop() ?? "file").replace(/\.\.+/g, ".").replace(/^\.+/, "") || "file", o = (e, t = /* @__PURE__ */ new Date()) => `uploads/${t.getFullYear()}-${String(t.getMonth() + 1).padStart(2, "0")}/${encodeURIComponent(e)}`, s = ({ filesApi: e, bucket: s, onNetworkError: c, debounceMs: l = i }) => {
6
- let u = r([]), d = r(null);
7
- return { handleUploadAttachment: n(async (n) => {
8
- if (!s) throw Error("User bucket is not available");
9
- let r = a(n.name);
10
- try {
7
+ var o = 700, s = 5, c = (e) => t(e.split("/").filter(Boolean).pop() ?? "file").replace(/\.\.+/g, ".").replace(/^\.+/, "") || "file", l = (e) => typeof e == "object" && !!e && "response" in e && e.response?.status === 409, u = ({ filesApi: t, bucket: u, onNetworkError: d, debounceMs: f = o }) => {
8
+ let p = a([]), m = a(null), h = a(null), g = i((t, r) => {
9
+ let i = `${t}|${e(r)}`;
10
+ return h.current?.key !== i && (h.current = {
11
+ key: i,
12
+ allocator: n({ date: r })
13
+ }), h.current.allocator;
14
+ }, []);
15
+ return { handleUploadAttachment: i(async (e) => {
16
+ if (!u) throw Error("User bucket is not available");
17
+ let n = c(e.name), i = g(u, /* @__PURE__ */ new Date()), a = i.allocate(n);
18
+ for (let o = 0;; o += 1) try {
19
+ let n = a.isRenamed ? new File([e.file], a.fileName, { type: e.file.type }) : e.file;
11
20
  return {
12
- url: (await e.uploadFile({
13
- bucket: s,
14
- path: o(r),
15
- file: n.file
21
+ url: (await t.uploadFile({
22
+ bucket: u,
23
+ path: a.path,
24
+ file: n,
25
+ uploadMode: "create-only"
16
26
  })).url,
17
- name: r
27
+ name: a.fileName
18
28
  };
19
- } catch (e) {
29
+ } catch (t) {
30
+ if (l(t)) {
31
+ if (i.markTaken(a.fileName), o < s) {
32
+ a = i.allocate(n);
33
+ continue;
34
+ }
35
+ } else i.release(a.fileName);
20
36
  if (!navigator.onLine) {
21
- u.current.push(n.name), d.current != null && clearTimeout(d.current), d.current = setTimeout(() => {
22
- let e = u.current.splice(0);
23
- c?.(e), d.current = null;
24
- }, l);
25
- let r = e instanceof Error ? e : /* @__PURE__ */ Error("Network upload failed");
26
- throw r.errorReason = t.Network, r;
37
+ p.current.push(e.name), m.current != null && clearTimeout(m.current), m.current = setTimeout(() => {
38
+ let e = p.current.splice(0);
39
+ d?.(e), m.current = null;
40
+ }, f);
41
+ let n = t instanceof Error ? t : /* @__PURE__ */ Error("Network upload failed");
42
+ throw n.errorReason = r.Network, n;
27
43
  }
28
- throw e;
44
+ throw t;
29
45
  }
30
46
  }, [
31
- s,
32
- l,
33
- e,
34
- c
47
+ u,
48
+ f,
49
+ t,
50
+ g,
51
+ d
35
52
  ]) };
36
53
  };
37
54
  //#endregion
38
- export { s as useAttachmentUpload };
55
+ export { u as useAttachmentUpload };
@@ -1,10 +1,10 @@
1
1
  import { formatDateYM as e } from "../conversation-transfer/date.js";
2
2
  import { ConversationTransferWarningCode as t } from "../conversation-transfer/types.js";
3
3
  import { UnsupportedImportFormatError as n, getFolderBreadcrumb as r, parseImportEnvelope as i, planAttachmentUploads as a, rebaseConversationId as o, rewriteAttachmentUrls as s } from "../conversation-transfer/import-conversation.js";
4
- import { runWithConcurrency as c } from "../conversation-transfer/async.js";
5
- import { ConversationTransferKind as l, ConversationTransferPhase as u, buildTransferProgress as d } from "../conversation-transfer/progress.js";
6
- import { useConversationTransferQueue as f } from "../conversation-transfer/queue.js";
7
- import { createUploadPathAllocator as p } from "../conversation-transfer/build-upload-path.js";
4
+ import { createUploadPathAllocator as c } from "../conversation-transfer/build-upload-path.js";
5
+ import { runWithConcurrency as l } from "../conversation-transfer/async.js";
6
+ import { ConversationTransferKind as u, ConversationTransferPhase as d, buildTransferProgress as f } from "../conversation-transfer/progress.js";
7
+ import { useConversationTransferQueue as p } from "../conversation-transfer/queue.js";
8
8
  import { parseDialArchive as m } from "../conversation-transfer/zip-import.js";
9
9
  import { ConversationTransferErrorCode as h, ConversationTransferSubjectKind as g, ConversationTransferUnitKind as _, generateUUID as v } from "@epam/ai-dial-chat-shared";
10
10
  import { useCallback as y } from "react";
@@ -26,9 +26,9 @@ var b = 5, x = 5, S = (e) => /\.(dial|zip)$/i.test(e.name), C = (e) => new Promi
26
26
  attachments: /* @__PURE__ */ new Map(),
27
27
  isArchive: !1
28
28
  };
29
- }, T = async (e, t, n, r, i, o, s, l) => {
30
- let { plan: u, skippedNames: d } = a(e, t, r), f = !1, p = await c(u, b, async (e) => {
31
- if (l.aborted || f) return;
29
+ }, T = async (e, t, n, r, i, o, s, c) => {
30
+ let { plan: u, skippedNames: d } = a(e, t, r), f = !1, p = await l(u, b, async (e) => {
31
+ if (c.aborted || f) return;
32
32
  let t = e.allocated;
33
33
  for (let a = 0; a <= x; a += 1) try {
34
34
  let r = new File([new Uint8Array(e.bytes)], t.fileName), a = await i.uploadFile({
@@ -36,7 +36,7 @@ var b = 5, x = 5, S = (e) => /\.(dial|zip)$/i.test(e.name), C = (e) => new Promi
36
36
  path: t.path,
37
37
  file: r,
38
38
  uploadMode: "create-only"
39
- }, { signal: l });
39
+ }, { signal: c });
40
40
  return s(), {
41
41
  kind: "uploaded",
42
42
  oldFileId: e.fileId,
@@ -44,7 +44,7 @@ var b = 5, x = 5, S = (e) => /\.(dial|zip)$/i.test(e.name), C = (e) => new Promi
44
44
  newTitle: t.isRenamed ? t.fileName : void 0
45
45
  };
46
46
  } catch (n) {
47
- if (l.aborted) return;
47
+ if (c.aborted) return;
48
48
  if (o(n)) {
49
49
  f = !0;
50
50
  return;
@@ -66,22 +66,22 @@ var b = 5, x = 5, S = (e) => /\.(dial|zip)$/i.test(e.name), C = (e) => new Promi
66
66
  }) : h.push(e.name);
67
67
  return {
68
68
  targetMap: m,
69
- skippedNames: l.aborted || f ? [] : h,
70
- isUnauthorized: !l.aborted && f
69
+ skippedNames: c.aborted || f ? [] : h,
70
+ isUnauthorized: !c.aborted && f
71
71
  };
72
- }, E = ({ conversationsApi: i, filesApi: a, bucket: c, onImported: m, classifyTransferError: b = () => ({}), resolveErrorTraceId: x = async () => void 0, onSuccess: S, onWarning: C, onError: E }) => {
73
- let D = f(), O = y(async (n, r, f) => {
74
- if (!c) {
72
+ }, E = ({ conversationsApi: i, filesApi: a, bucket: l, onImported: m, classifyTransferError: b = () => ({}), resolveErrorTraceId: x = async () => void 0, onSuccess: S, onWarning: C, onError: E }) => {
73
+ let D = p(), O = y(async (n, r, p) => {
74
+ if (!l) {
75
75
  E?.({
76
76
  jobId: n,
77
77
  code: h.MissingBucket
78
78
  }), D.failJob(n, h.MissingBucket);
79
79
  return;
80
80
  }
81
- let g = l.Import, v = r.attachments.size, y = 0, w = () => {
82
- y += 1, D.setJobProgress(n, d({
81
+ let g = u.Import, v = r.attachments.size, y = 0, w = () => {
82
+ y += 1, D.setJobProgress(n, f({
83
83
  kind: g,
84
- phase: u.Transfer,
84
+ phase: d.Transfer,
85
85
  completed: y,
86
86
  total: v
87
87
  }, {
@@ -90,9 +90,9 @@ var b = 5, x = 5, S = (e) => /\.(dial|zip)$/i.test(e.name), C = (e) => new Promi
90
90
  kind: _.Attachment
91
91
  }));
92
92
  }, O = (e) => {
93
- D.setJobProgress(n, d({
93
+ D.setJobProgress(n, f({
94
94
  kind: g,
95
- phase: u.Finalize,
95
+ phase: d.Finalize,
96
96
  completed: e,
97
97
  total: r.history.length
98
98
  }, {
@@ -105,11 +105,11 @@ var b = 5, x = 5, S = (e) => /\.(dial|zip)$/i.test(e.name), C = (e) => new Promi
105
105
  let t = `uploads/${e(P)}`, r = [];
106
106
  try {
107
107
  r = (await a.listFiles({
108
- bucket: c,
108
+ bucket: l,
109
109
  path: t
110
- }, { signal: f })).items.map((e) => e.name);
110
+ }, { signal: p })).items.map((e) => e.name);
111
111
  } catch (e) {
112
- if (f.aborted) return;
112
+ if (p.aborted) return;
113
113
  if (F(e)) {
114
114
  E?.({
115
115
  jobId: n,
@@ -119,26 +119,26 @@ var b = 5, x = 5, S = (e) => /\.(dial|zip)$/i.test(e.name), C = (e) => new Promi
119
119
  }
120
120
  console.error("Failed to list the upload folder for attachment name disambiguation", e);
121
121
  }
122
- I = p({
122
+ I = c({
123
123
  date: P,
124
124
  existingNames: r
125
125
  });
126
126
  }
127
- D.setJobProgress(n, d({
127
+ D.setJobProgress(n, f({
128
128
  kind: g,
129
- phase: u.Prepare
130
- })), v === 0 && D.setJobProgress(n, d({
129
+ phase: d.Prepare
130
+ })), v === 0 && D.setJobProgress(n, f({
131
131
  kind: g,
132
- phase: u.Transfer
132
+ phase: d.Transfer
133
133
  }));
134
134
  for (let e of r.history) {
135
- if (f.aborted) return;
135
+ if (p.aborted) return;
136
136
  if (M) break;
137
137
  try {
138
138
  let t = /* @__PURE__ */ new Map();
139
139
  if (r.isArchive && I) {
140
- let n = await T(e, r.attachments, c, I, a, F, w, f);
141
- if (f.aborted) return;
140
+ let n = await T(e, r.attachments, l, I, a, F, w, p);
141
+ if (p.aborted) return;
142
142
  if (n.isUnauthorized) {
143
143
  M = !0;
144
144
  break;
@@ -146,17 +146,17 @@ var b = 5, x = 5, S = (e) => /\.(dial|zip)$/i.test(e.name), C = (e) => new Promi
146
146
  for (let e of n.skippedNames) j.add(e);
147
147
  t = n.targetMap;
148
148
  }
149
- let { conversation: n, subPath: l } = o(s(e, t), c);
149
+ let { conversation: n, subPath: c } = o(s(e, t), l);
150
150
  if (await i.saveConversation({
151
- path: l,
151
+ path: c,
152
152
  saveConversationBodyDto: { conversation: {
153
153
  ...n,
154
154
  llmNamingDone: !0
155
155
  } }
156
- }, { signal: f }), f.aborted) return;
156
+ }, { signal: p }), p.aborted) return;
157
157
  k.push(n.name);
158
158
  } catch (t) {
159
- if (f.aborted) return;
159
+ if (p.aborted) return;
160
160
  if (F(t)) {
161
161
  M = !0;
162
162
  break;
@@ -165,7 +165,7 @@ var b = 5, x = 5, S = (e) => /\.(dial|zip)$/i.test(e.name), C = (e) => new Promi
165
165
  }
166
166
  O(k.length + A.length);
167
167
  }
168
- if (!f.aborted) {
168
+ if (!p.aborted) {
169
169
  if (M) {
170
170
  E?.({
171
171
  jobId: n,
@@ -194,7 +194,7 @@ var b = 5, x = 5, S = (e) => /\.(dial|zip)$/i.test(e.name), C = (e) => new Promi
194
194
  }), A.length > 0 ? D.failJob(n, h.Unknown) : j.size > 0 ? D.warnJob(n, t.AttachmentSkipped) : D.succeedJob(n);
195
195
  }
196
196
  }, [
197
- c,
197
+ l,
198
198
  b,
199
199
  i,
200
200
  a,
package/conversation.d.ts CHANGED
@@ -690,7 +690,8 @@ export declare const useAsyncConfirmDialog: <T>() => AsyncConfirmDialogControls<
690
690
 
691
691
  /**
692
692
  * Uploads an attachment's file to DIAL Core storage against an
693
- * already-configured `FilesApi` instance, coalescing a burst of
693
+ * already-configured `FilesApi` instance, giving every upload a collision-free
694
+ * path so no attachment overwrites another, and coalescing a burst of
694
695
  * offline/network upload failures into a single debounced callback rather
695
696
  * than firing one notification per failed file.
696
697
  */
package/index.d.ts CHANGED
@@ -34,8 +34,8 @@ import type { CustomVisualizerDataLayout } from '@epam/ai-dial-chat-shared';
34
34
  import { DeleteFilesResponseDto } from '@epam/ai-dial-chat-api-client';
35
35
  import { DeleteItemDto } from '@epam/ai-dial-chat-api-client';
36
36
  import { DeploymentConfigurationSchema } from '@epam/ai-dial-chat-shared';
37
- import { DeploymentCreationFormLocaleEntry } from '@epam/ai-dial-deployment-creation-form';
38
- import { DeploymentCreationFormLocaleOption } from '@epam/ai-dial-deployment-creation-form';
37
+ import { DeploymentCreationFormLocaleEntry } from '@epam/ai-dial-builder-form';
38
+ import { DeploymentCreationFormLocaleOption } from '@epam/ai-dial-builder-form';
39
39
  import { DeploymentDetailsDto } from '@epam/ai-dial-chat-api-client';
40
40
  import { DeploymentFeatures } from '@epam/ai-dial-chat-shared';
41
41
  import { DeploymentItemDto } from '@epam/ai-dial-chat-api-client';
@@ -2186,6 +2186,9 @@ declare interface MarkdownCanvasContent {
2186
2186
  text: string;
2187
2187
  }
2188
2188
 
2189
+ /** Display mode an MCP App can ask the host to switch to via `ui/request-display-mode` — the MCP UI protocol's `inline`/`fullscreen`/`pip` union. */
2190
+ declare type McpAppDisplayMode = NonNullable<McpUiHostContext['displayMode']>;
2191
+
2189
2192
  /**
2190
2193
  * Dependencies the host must inject into `useMcpAppInlinePreview` /
2191
2194
  * `McpAppInlinePreview` — everything that requires host context (theming,
@@ -2213,6 +2216,12 @@ export declare interface McpAppHostContextParams {
2213
2216
  locale: string;
2214
2217
  /** Operator-configured MCP App user-agent override. Defaults to `'ai-dial-chat'`. */
2215
2218
  mcpAppUserAgent?: string;
2219
+ /**
2220
+ * Display modes the host can switch an app between via
2221
+ * `ui/request-display-mode`. Defaults to `['inline', 'fullscreen']` — the
2222
+ * compact inline preview and the full-width canvas.
2223
+ */
2224
+ availableDisplayModes?: McpAppDisplayMode[];
2216
2225
  }
2217
2226
 
2218
2227
  /** Thrown by `McpAppsApiClient.fetchResourceHtml` on a non-OK response, carrying the HTTP status so callers can distinguish `403` (forbidden) from any other failure. */
@@ -3853,7 +3862,8 @@ export declare interface UseAttachmentActionResult {
3853
3862
 
3854
3863
  /**
3855
3864
  * Uploads an attachment's file to DIAL Core storage against an
3856
- * already-configured `FilesApi` instance, coalescing a burst of
3865
+ * already-configured `FilesApi` instance, giving every upload a collision-free
3866
+ * path so no attachment overwrites another, and coalescing a burst of
3857
3867
  * offline/network upload failures into a single debounced callback rather
3858
3868
  * than firing one notification per failed file.
3859
3869
  */
@@ -4941,9 +4951,10 @@ export declare const useMcpAppHostAdapter: (displayMode: "inline" | "fullscreen"
4941
4951
  * `ui/initialize` handshake, shared by every place that mounts an app —
4942
4952
  * a full-width attachment canvas (`displayMode: 'fullscreen'`) and a compact
4943
4953
  * inline preview under a message (`displayMode: 'inline'`) — so the app can
4944
- * size/style itself differently for each.
4954
+ * size/style itself differently for each, and knows (via
4955
+ * `availableDisplayModes`) which surfaces it may ask the host to switch to.
4945
4956
  */
4946
- export declare const useMcpAppHostContext: (displayMode: "inline" | "fullscreen", { theme, mcpAppTheme, locale, mcpAppUserAgent }: McpAppHostContextParams) => McpUiHostContext;
4957
+ export declare const useMcpAppHostContext: (displayMode: "inline" | "fullscreen", { theme, mcpAppTheme, locale, mcpAppUserAgent, availableDisplayModes, }: McpAppHostContextParams) => McpUiHostContext;
4947
4958
 
4948
4959
  /**
4949
4960
  * Discovers MCP Apps-capable tools available to the current conversation, merging two
@@ -7,20 +7,22 @@ var t = /* @__PURE__ */ "--color-background-primary.--color-background-secondary
7
7
  t && (n[r] = t);
8
8
  }
9
9
  return n;
10
- }, r = (t, { theme: r, mcpAppTheme: i, locale: a, mcpAppUserAgent: o }) => e(() => ({
10
+ }, r = (t, { theme: r, mcpAppTheme: i, locale: a, mcpAppUserAgent: o, availableDisplayModes: s }) => e(() => ({
11
11
  theme: i ?? r,
12
12
  locale: a,
13
13
  timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,
14
14
  userAgent: o ?? "ai-dial-chat",
15
15
  platform: "web",
16
16
  displayMode: t,
17
+ availableDisplayModes: s ?? ["inline", "fullscreen"],
17
18
  styles: { variables: n() }
18
19
  }), [
19
20
  i,
20
21
  r,
21
22
  a,
22
23
  o,
23
- t
24
+ t,
25
+ s
24
26
  ]);
25
27
  //#endregion
26
28
  export { r as useMcpAppHostContext };
@@ -4,12 +4,12 @@ import { useCallback as i, useEffect as a, useRef as o } from "react";
4
4
  import { computeMcpAppSeedKey as s, resolveMcpAppToolResult as c } from "@epam/ai-dial-mcp-apps";
5
5
  //#region src/mcp-apps/useOpenMcpAppCanvas/useOpenMcpAppCanvas.ts
6
6
  var l = (l, u, d, f) => {
7
- let { openCanvas: p, openCanvasLoading: m } = r(), { hostContext: h, sandboxUrl: g, fetchResourceHtml: _, callTool: v } = u, y = o(null), b = i(async (r, i, a, o = !1) => {
8
- if (g == null) return !1;
7
+ let { openCanvas: p, openCanvasLoading: m, closeCanvas: h } = r(), { hostContext: g, sandboxUrl: _, fetchResourceHtml: v, callTool: y } = u, b = i((e) => e === "inline" ? (h(), "inline") : "fullscreen", [h]), x = o(null), S = i(async (r, i, a, o = !1) => {
8
+ if (_ == null) return !1;
9
9
  f?.(), m(d.title, i);
10
10
  try {
11
11
  let e = s(a), n = async () => {
12
- let [e, t] = await Promise.all([_(r.toolsetId, r.resourceUri), c(r, a, v)]);
12
+ let [e, t] = await Promise.all([v(r.toolsetId, r.resourceUri), c(r, a, y)]);
13
13
  return {
14
14
  html: e,
15
15
  toolResult: t
@@ -21,14 +21,14 @@ var l = (l, u, d, f) => {
21
21
  }, e)), p({
22
22
  type: t.McpApp,
23
23
  html: u,
24
- sandboxUrl: g,
25
- toolName: r.mcpToolName,
24
+ sandboxUrl: _,
26
25
  toolInput: a?.toolInput,
27
26
  toolResult: f,
28
- hostContext: h,
29
- onToolCall: (e, t) => v(r.toolsetId, e, t, r.kind),
27
+ hostContext: g,
28
+ onToolCall: (e, t) => y(r.toolsetId, e, t, r.kind),
29
+ onRequestDisplayMode: b,
30
30
  onReload: () => {
31
- i != null && l.invalidate(i), y.current?.(r, i, a, !0);
31
+ i != null && l.invalidate(i), x.current?.(r, i, a, !0);
32
32
  }
33
33
  }, d.title, i), !0;
34
34
  } catch (r) {
@@ -43,16 +43,17 @@ var l = (l, u, d, f) => {
43
43
  p,
44
44
  m,
45
45
  f,
46
- g,
47
- h,
48
46
  _,
47
+ g,
49
48
  v,
49
+ y,
50
50
  l,
51
- d
51
+ d,
52
+ b
52
53
  ]);
53
54
  return a(() => {
54
- y.current = b;
55
- }, [b]), { openMcpAppCanvas: b };
55
+ x.current = S;
56
+ }, [S]), { openMcpAppCanvas: S };
56
57
  };
57
58
  //#endregion
58
59
  export { l as useOpenMcpAppCanvas };
package/mcp-apps.d.ts CHANGED
@@ -36,6 +36,9 @@ toolsetId: string,
36
36
  resourceUri: string,
37
37
  ) => Promise<string>;
38
38
 
39
+ /** Display mode an MCP App can ask the host to switch to via `ui/request-display-mode` — the MCP UI protocol's `inline`/`fullscreen`/`pip` union. */
40
+ declare type McpAppDisplayMode = NonNullable<McpUiHostContext['displayMode']>;
41
+
39
42
  /**
40
43
  * Dependencies the host must inject into `useMcpAppInlinePreview` /
41
44
  * `McpAppInlinePreview` — everything that requires host context (theming,
@@ -63,6 +66,12 @@ export declare interface McpAppHostContextParams {
63
66
  locale: string;
64
67
  /** Operator-configured MCP App user-agent override. Defaults to `'ai-dial-chat'`. */
65
68
  mcpAppUserAgent?: string;
69
+ /**
70
+ * Display modes the host can switch an app between via
71
+ * `ui/request-display-mode`. Defaults to `['inline', 'fullscreen']` — the
72
+ * compact inline preview and the full-width canvas.
73
+ */
74
+ availableDisplayModes?: McpAppDisplayMode[];
66
75
  }
67
76
 
68
77
  /** Thrown by `McpAppsApiClient.fetchResourceHtml` on a non-OK response, carrying the HTTP status so callers can distinguish `403` (forbidden) from any other failure. */
@@ -181,9 +190,10 @@ export declare const useMcpAppHostAdapter: (displayMode: "inline" | "fullscreen"
181
190
  * `ui/initialize` handshake, shared by every place that mounts an app —
182
191
  * a full-width attachment canvas (`displayMode: 'fullscreen'`) and a compact
183
192
  * inline preview under a message (`displayMode: 'inline'`) — so the app can
184
- * size/style itself differently for each.
193
+ * size/style itself differently for each, and knows (via
194
+ * `availableDisplayModes`) which surfaces it may ask the host to switch to.
185
195
  */
186
- export declare const useMcpAppHostContext: (displayMode: "inline" | "fullscreen", { theme, mcpAppTheme, locale, mcpAppUserAgent }: McpAppHostContextParams) => McpUiHostContext;
196
+ export declare const useMcpAppHostContext: (displayMode: "inline" | "fullscreen", { theme, mcpAppTheme, locale, mcpAppUserAgent, availableDisplayModes, }: McpAppHostContextParams) => McpUiHostContext;
187
197
 
188
198
  /**
189
199
  * Discovers MCP Apps-capable tools available to the current conversation, merging two
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.1.0-dev.459",
4
+ "version": "1.1.0-dev.467",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
7
7
  "main": "./index.js",
@@ -96,7 +96,7 @@
96
96
  }
97
97
  },
98
98
  "dependencies": {
99
- "dompurify": "3.4.13",
99
+ "dompurify": "3.4.15",
100
100
  "fflate": "^0.8.3",
101
101
  "lru-cache": "^10.4.3",
102
102
  "mime-types": "^3.0.2",
@@ -104,21 +104,21 @@
104
104
  },
105
105
  "peerDependencies": {
106
106
  "react": "^19.2.6",
107
- "@epam/ai-dial-attachment-canvas": "1.1.0-dev.459",
108
- "@epam/ai-dial-attachment-input": "1.1.0-dev.459",
109
- "@epam/ai-dial-catalog": "1.1.0-dev.459",
110
- "@epam/ai-dial-chat-api-client": "1.1.0-dev.459",
111
- "@epam/ai-dial-chat-overlay": "1.1.0-dev.459",
112
- "@epam/ai-dial-chat-shared": "1.1.0-dev.459",
113
- "@epam/ai-dial-deployment-creation-form": "1.1.0-dev.459",
114
- "@epam/ai-dial-mcp-apps": "1.1.0-dev.459",
115
- "@epam/ai-dial-publish-panel": "1.1.0-dev.459",
116
- "@epam/ai-dial-quotations": "1.1.0-dev.459",
107
+ "@epam/ai-dial-attachment-canvas": "1.1.0-dev.467",
108
+ "@epam/ai-dial-attachment-input": "1.1.0-dev.467",
109
+ "@epam/ai-dial-builder-form": "1.1.0-dev.467",
110
+ "@epam/ai-dial-catalog": "1.1.0-dev.467",
111
+ "@epam/ai-dial-chat-api-client": "1.1.0-dev.467",
112
+ "@epam/ai-dial-chat-overlay": "1.1.0-dev.467",
113
+ "@epam/ai-dial-chat-shared": "1.1.0-dev.467",
114
+ "@epam/ai-dial-mcp-apps": "1.1.0-dev.467",
115
+ "@epam/ai-dial-publish-panel": "1.1.0-dev.467",
116
+ "@epam/ai-dial-quotations": "1.1.0-dev.467",
117
117
  "@epam/ai-dial-react-file-manager": "*",
118
- "@epam/ai-dial-scheduled-tasks": "1.1.0-dev.459",
119
- "@epam/ai-dial-share": "1.1.0-dev.459",
120
- "@epam/ai-dial-skill-editor": "1.1.0-dev.459",
121
- "@epam/ai-dial-source-panel": "1.1.0-dev.459",
118
+ "@epam/ai-dial-scheduled-tasks": "1.1.0-dev.467",
119
+ "@epam/ai-dial-share": "1.1.0-dev.467",
120
+ "@epam/ai-dial-skill-editor": "1.1.0-dev.467",
121
+ "@epam/ai-dial-source-panel": "1.1.0-dev.467",
122
122
  "@epam/ai-dial-ui-kit": "*",
123
123
  "@modelcontextprotocol/sdk": "^1.27.1",
124
124
  "@epam/pdf-highlighter-kit": ">=0.0.14",
@@ -131,6 +131,9 @@
131
131
  "@epam/ai-dial-attachment-input": {
132
132
  "optional": true
133
133
  },
134
+ "@epam/ai-dial-builder-form": {
135
+ "optional": true
136
+ },
134
137
  "@epam/ai-dial-catalog": {
135
138
  "optional": true
136
139
  },
@@ -143,9 +146,6 @@
143
146
  "@epam/ai-dial-chat-shared": {
144
147
  "optional": true
145
148
  },
146
- "@epam/ai-dial-deployment-creation-form": {
147
- "optional": true
148
- },
149
149
  "@epam/ai-dial-mcp-apps": {
150
150
  "optional": true
151
151
  },
package/utils.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { DeploymentCreationFormLocaleEntry } from '@epam/ai-dial-deployment-creation-form';
2
- import { DeploymentCreationFormLocaleOption } from '@epam/ai-dial-deployment-creation-form';
1
+ import { DeploymentCreationFormLocaleEntry } from '@epam/ai-dial-builder-form';
2
+ import { DeploymentCreationFormLocaleOption } from '@epam/ai-dial-builder-form';
3
3
  import { ExportFolder } from '@epam/ai-dial-chat-shared';
4
4
  import { LocaleTextEntryDto } from '@epam/ai-dial-chat-api-client';
5
5
  import { Middleware } from '@epam/ai-dial-chat-api-client';