@epam/ai-dial-mcp-apps 1.3.0-dev.16 → 1.3.0-dev.161

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.
package/index.css CHANGED
@@ -1,2 +1,3 @@
1
1
  ._preview_19as4_11{background:var(--mcpapp-preview-bg,var(--bg-layer-raised,#fcfcfc));border-color:var(--mcpapp-preview-border,var(--stroke-tertiary,#e0e6f0))}._previewHeader_19as4_23{border-bottom-color:var(--mcpapp-preview-header-border,var(--stroke-tertiary,#e0e6f0))}
2
- /*$vite$:1*/.visible{visibility:visible}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.mx-1\.5{margin-left:.375rem;margin-right:.375rem}.ms-2{margin-inline-start:.5rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.h-3{height:.75rem}.min-h-10{min-height:2.5rem}.min-h-\[200px\]{min-height:200px}.w-0{width:0}.w-full{width:100%}.min-w-0{min-width:0}.shrink-0{flex-shrink:0}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.overflow-hidden{overflow:hidden}.rounded-xl{border-radius:.75rem}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-s{border-inline-start-width:1px}.p-4{padding:1rem}.px-4{padding-left:1rem;padding-right:1rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.text-center{text-align:center}.align-middle{vertical-align:middle}.text-error{color:var(--text-error,#ae2f2f)}.text-primary{color:var(--text-primary,#161b2d)}.text-secondary{color:var(--text-secondary,#57647a)}
2
+ /*$vite$:1*//*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
3
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style:solid}}}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.mx-1\.5{margin-inline:.375rem}.ms-2{margin-inline-start:.5rem}.block{display:block}.flex{display:flex}.inline{display:inline}.inline-block{display:inline-block}.h-3{height:.75rem}.min-h-10{min-height:2.5rem}.min-h-\[100px\]{min-height:100px}.w-0{width:0}.w-full{width:100%}.min-w-0{min-width:0}.shrink-0{flex-shrink:0}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.overflow-hidden{overflow:hidden}.rounded-xl{border-radius:.75rem}.border{border-style:var(--tw-border-style);border-width:1px}.border-s{border-inline-start-style:var(--tw-border-style);border-inline-start-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-current{border-color:currentColor}.p-4{padding:1rem}.px-4{padding-inline:1rem}.py-2{padding-block:.5rem}.text-center{text-align:center}.align-middle{vertical-align:middle}.text-error{color:var(--text-error,#ae2f2f)}.text-primary{color:var(--text-primary,#161b2d)}.text-secondary{color:var(--text-secondary,#57647a)}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}
package/index.d.ts CHANGED
@@ -3,7 +3,7 @@ export { useMcpAppInlinePreview, type McpAppInlinePreviewState, } from './hooks/
3
3
  export { useMcpAppResponseCache } from './hooks/useMcpAppResponseCache/useMcpAppResponseCache';
4
4
  export type { McpDeploymentKind, McpAppToolDiscovery, McpAppToolRef, McpAppToolCallSeed, FetchMcpAppResourceHtml, CallMcpAppTool, CachedMcpAppResponse, McpAppResponseCache, McpAppHostAdapter, } from './models/mcp-apps';
5
5
  export { McpAppInlinePreviewStatus } from './models/mcp-apps';
6
- export { collectToolCallNames, findMcpAppForMessage, mcpAppCanvasKey, computeMcpAppSeedKey, resolveMcpAppToolCallSeed, resolveMcpAppToolResult, } from './utils/mcp-app';
6
+ export { collectToolCallNames, findMcpAppForMessage, mcpAppCanvasKey, computeMcpAppSeedKey, resolveMcpAppToolCallSeed, resolveMcpAppToolResult, sanitizeToolName, } from './utils/mcp-app';
7
7
  export { MCP_APPS_CLASS } from './constants/public-class-names';
8
8
  export type { McpAppInlinePreviewColors } from './models/mcp-apps';
9
9
  //# sourceMappingURL=index.d.ts.map
package/index.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,KAAK,wBAAwB,GAC9B,MAAM,sDAAsD,CAAC;AAC9D,OAAO,EACL,sBAAsB,EACtB,KAAK,wBAAwB,GAC9B,MAAM,uDAAuD,CAAC;AAC/D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uDAAuD,CAAC;AAC/F,YAAY,EACV,iBAAiB,EACjB,mBAAmB,EACnB,aAAa,EACb,kBAAkB,EAClB,uBAAuB,EACvB,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,eAAe,EACf,oBAAoB,EACpB,yBAAyB,EACzB,uBAAuB,GACxB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,YAAY,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,KAAK,wBAAwB,GAC9B,MAAM,sDAAsD,CAAC;AAC9D,OAAO,EACL,sBAAsB,EACtB,KAAK,wBAAwB,GAC9B,MAAM,uDAAuD,CAAC;AAC/D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uDAAuD,CAAC;AAC/F,YAAY,EACV,iBAAiB,EACjB,mBAAmB,EACnB,aAAa,EACb,kBAAkB,EAClB,uBAAuB,EACvB,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,eAAe,EACf,oBAAoB,EACpB,yBAAyB,EACzB,uBAAuB,EACvB,gBAAgB,GACjB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,YAAY,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC"}
package/index.js CHANGED
@@ -40,15 +40,18 @@ var C = {
40
40
  }
41
41
  }
42
42
  return t;
43
- }, D = (e) => {
43
+ }, D = /[^a-zA-Z0-9_-]+/g, O = 64, k = (e) => {
44
+ let t = e.replace(D, "_");
45
+ return t !== "" && !/^[a-zA-Z_]/.test(t) && (t = `_${t}`), t.slice(0, O);
46
+ }, A = (e) => {
44
47
  let t = /* @__PURE__ */ new Set();
45
48
  for (let n of e) for (let e of E(n.custom_content?.state).values()) t.add(e.name);
46
49
  return t;
47
- }, O = (e, t, r) => {
50
+ }, j = (e, t, r) => {
48
51
  if (t.length === 0 || e.role !== n.Assistant) return;
49
52
  let i = new Set([...E(e.custom_content?.state).values()].map((e) => e.name));
50
53
  return t.find((e) => i.has(e.toolName)) || t.find((e) => e.discovery === "direct") || (r ? t[0] : void 0);
51
- }, k = (e) => `${e}:mcp-app`, A = (e) => e == null ? void 0 : JSON.stringify(e.toolInput ?? null), j = (e, t) => {
54
+ }, M = (e) => `${e}:mcp-app`, N = (e) => e == null ? void 0 : JSON.stringify(e.toolInput ?? null), P = (e, t) => {
52
55
  let n = e.custom_content?.state;
53
56
  if (!n) return;
54
57
  let r = [...E(n).values()].reverse().find((e) => e.name === t);
@@ -59,20 +62,20 @@ var C = {
59
62
  text: r.result
60
63
  }] }
61
64
  };
62
- }, M = async (e, t, n) => {
63
- if (!(e.discovery === "direct" || t?.toolInput != null)) return t?.toolResult;
65
+ }, F = async (e, t, n) => {
66
+ if (e.discovery !== "direct" && t?.toolInput == null) return t?.toolResult;
64
67
  try {
65
68
  return await n(e.toolsetId, e.mcpToolName, t?.toolInput ?? {}, e.kind);
66
69
  } catch {
67
70
  return t?.toolResult;
68
71
  }
69
- }, N = (t, n, r, i, a, o) => {
72
+ }, I = (t, n, r, i, a, o) => {
70
73
  let { hostContext: s, hostInfo: c, sandboxUrl: l, fetchResourceHtml: u, callTool: d } = a, [f, p] = y(), [m, _] = y(), [v, b] = y(() => t == null || l == null ? w.Unavailable : w.Loading), [x, S] = y(0), C = h(() => {
71
74
  r.invalidate(i), S((e) => e + 1);
72
75
  }, [r, i]), T = h(async (e) => {
73
- if (!(t == null || l == null)) try {
74
- let a = A(n), { html: o, toolResult: s } = await r.getOrFetch(i, a, async () => {
75
- let [e, r] = await Promise.all([u(t.toolsetId, t.resourceUri), M(t, n, d)]);
76
+ if (t != null && l != null) try {
77
+ let a = N(n), { html: o, toolResult: s } = await r.getOrFetch(i, a, async () => {
78
+ let [e, r] = await Promise.all([u(t.toolsetId, t.resourceUri), F(t, n, d)]);
76
79
  return {
77
80
  html: e,
78
81
  toolResult: r
@@ -131,26 +134,26 @@ var C = {
131
134
  onRequestDisplayMode: o
132
135
  }
133
136
  };
134
- }, P = {
137
+ }, L = {
135
138
  preview: "_preview_19as4_11",
136
139
  previewHeader: "_previewHeader_19as4_23"
137
- }, F = m(({ match: e, toolCall: n, cache: m, cacheKey: _, hostAdapter: v, onExpand: T, expandAriaLabel: E, reloadAriaLabel: D, actionsGroupAriaLabel: O = "MCP app actions", loadErrorLabel: k, isOpenedInCanvas: A = !1, openedInCanvasLabel: j, colors: M }) => {
138
- let [F, I] = y(void 0);
140
+ }, R = m(({ match: e, toolCall: n, cache: m, cacheKey: _, hostAdapter: v, onExpand: T, expandAriaLabel: E, reloadAriaLabel: D, actionsGroupAriaLabel: O = "MCP app actions", loadErrorLabel: k, isOpenedInCanvas: A = !1, openedInCanvasLabel: j, colors: M }) => {
141
+ let [N, P] = y(void 0);
139
142
  g(() => {
140
- I(void 0);
143
+ P(void 0);
141
144
  }, [_]);
142
- let L = h((e) => e === "fullscreen" ? (T(), "fullscreen") : "inline", [T]), R = r({
145
+ let F = h((e) => e === "fullscreen" ? (T(), "fullscreen") : "inline", [T]), R = r({
143
146
  "--mcpapp-preview-bg": M?.previewBackground,
144
147
  "--mcpapp-preview-border": M?.previewBorder,
145
148
  "--mcpapp-preview-header-border": M?.previewHeaderBorder
146
- }), { status: z, content: B, reload: V, attemptId: H } = N(e, n, m, _, v, L);
149
+ }), { status: z, content: B, reload: V, attemptId: H } = I(e, n, m, _, v, F);
147
150
  return z === w.Unavailable ? null : /* @__PURE__ */ S("div", {
148
151
  style: R,
149
- className: u(P.preview, "flex w-full min-w-0 flex-col overflow-hidden rounded-xl border", C.preview),
152
+ className: u(L.preview, "flex w-full min-w-0 flex-col overflow-hidden rounded-xl border", C.preview),
150
153
  children: [/* @__PURE__ */ S("div", {
151
- className: u(P.previewHeader, "flex min-h-10 items-center justify-between gap-2 border-b px-4 py-2", C.previewHeader),
154
+ className: u(L.previewHeader, "flex min-h-10 items-center justify-between gap-2 border-b px-4 py-2", C.previewHeader),
152
155
  children: [/* @__PURE__ */ x(s, {
153
- text: F == null ? /* @__PURE__ */ x("span", {
156
+ text: N == null ? /* @__PURE__ */ x("span", {
154
157
  className: "dial-tiny-lead-semi-text",
155
158
  children: e.mcpToolName
156
159
  }) : /* @__PURE__ */ S(b, { children: [
@@ -160,15 +163,15 @@ var C = {
160
163
  }),
161
164
  /* @__PURE__ */ x("span", {
162
165
  "aria-hidden": !0,
163
- className: "border-current mx-1.5 inline-block h-3 w-0 border-s align-middle"
166
+ className: "mx-1.5 inline-block h-3 w-0 border-s border-current align-middle"
164
167
  }),
165
168
  /* @__PURE__ */ x("span", {
166
169
  className: "dial-tiny-lead-semi-text",
167
- children: F.name
170
+ children: N.name
168
171
  }),
169
- F.version && /* @__PURE__ */ x("span", {
172
+ N.version && /* @__PURE__ */ x("span", {
170
173
  className: "dial-caption-text ms-2",
171
- children: F.version
174
+ children: N.version
172
175
  })
173
176
  ] }),
174
177
  className: "text-secondary"
@@ -197,7 +200,7 @@ var C = {
197
200
  })]
198
201
  })]
199
202
  }), /* @__PURE__ */ x("div", {
200
- className: "relative min-h-[200px] w-full",
203
+ className: "relative min-h-[100px] w-full",
201
204
  children: A ? /* @__PURE__ */ x("div", {
202
205
  role: "status",
203
206
  "aria-live": "polite",
@@ -227,23 +230,23 @@ var C = {
227
230
  z === w.Ready && B && /* @__PURE__ */ x(t, {
228
231
  content: B,
229
232
  errorLabel: k,
230
- onAppInfo: I
233
+ onAppInfo: P
231
234
  }, H)
232
235
  ] })
233
236
  })]
234
237
  });
235
- }), I = 900 * 1e3, L = (e) => {
238
+ }), z = 9e5, B = (e) => {
236
239
  let t = v(/* @__PURE__ */ new Map()), n = v(/* @__PURE__ */ new Map());
237
240
  return _(() => {
238
241
  let r = (t) => `${e}:${t}`, i = (e, t) => `${r(e)}::${t ?? ""}`, a = (e, n) => {
239
242
  let i = t.current.get(r(e));
240
- if (i != null && i.seedKey === n && !(Date.now() - i.cachedAt > I)) return {
243
+ if (i != null && i.seedKey === n && !(Date.now() - i.cachedAt > z)) return {
241
244
  html: i.html,
242
245
  toolResult: i.toolResult
243
246
  };
244
247
  }, o = (e, n, i) => {
245
248
  let a = Date.now();
246
- for (let [e, n] of t.current) a - n.cachedAt > I && t.current.delete(e);
249
+ for (let [e, n] of t.current) a - n.cachedAt > z && t.current.delete(e);
247
250
  t.current.set(r(e), {
248
251
  ...n,
249
252
  seedKey: i,
@@ -270,4 +273,4 @@ var C = {
270
273
  }, [e]);
271
274
  };
272
275
  //#endregion
273
- export { C as MCP_APPS_CLASS, F as McpAppInlinePreview, w as McpAppInlinePreviewStatus, D as collectToolCallNames, A as computeMcpAppSeedKey, O as findMcpAppForMessage, k as mcpAppCanvasKey, j as resolveMcpAppToolCallSeed, M as resolveMcpAppToolResult, N as useMcpAppInlinePreview, L as useMcpAppResponseCache };
276
+ export { C as MCP_APPS_CLASS, R as McpAppInlinePreview, w as McpAppInlinePreviewStatus, A as collectToolCallNames, N as computeMcpAppSeedKey, j as findMcpAppForMessage, M as mcpAppCanvasKey, P as resolveMcpAppToolCallSeed, F as resolveMcpAppToolResult, k as sanitizeToolName, I as useMcpAppInlinePreview, B as useMcpAppResponseCache };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@epam/ai-dial-mcp-apps",
3
3
  "description": "Host-agnostic MCP Apps building blocks — tool-call/message matching, the response cache, and the inline preview hook/component shared by the full-width canvas and inline surfaces",
4
- "version": "1.3.0-dev.16",
4
+ "version": "1.3.0-dev.161",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
7
7
  "main": "./index.js",
@@ -20,11 +20,11 @@
20
20
  "@tabler/icons-react": "^3.44.0",
21
21
  "@mcp-ui/client": "^7.1.1",
22
22
  "@modelcontextprotocol/sdk": "^1.32.1",
23
- "@epam/ai-dial-attachment-canvas": "1.3.0-dev.16"
23
+ "@epam/ai-dial-attachment-canvas": "1.3.0-dev.161"
24
24
  },
25
25
  "peerDependencies": {
26
- "@epam/ai-dial-chat-shared": "1.3.0-dev.16",
27
- "@epam/ai-dial-ui-kit": "^0.15.1",
26
+ "@epam/ai-dial-chat-shared": "1.3.0-dev.161",
27
+ "@epam/ai-dial-ui-kit": "^0.16.0-dev.33",
28
28
  "react": "^19.2.8"
29
29
  },
30
30
  "repository": {
@@ -1,6 +1,20 @@
1
1
  import { Message } from '@epam/ai-dial-chat-shared';
2
2
  import { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
3
3
  import { CallMcpAppTool, McpAppToolCallSeed, McpAppToolRef } from '../models/mcp-apps';
4
+ /**
5
+ * Reproduces the tool-name sanitization QuickApps applies to
6
+ * `${toolsetName}_${toolName}` before sending a tool to the LLM
7
+ * (`sanitize_toolname` in `epam/ai-dial-quickapps-backend`,
8
+ * `src/quickapp/common/utils.py`): every run of characters outside
9
+ * `[a-zA-Z0-9_-]` becomes a single `_`, a name not starting with a letter or `_`
10
+ * gets a leading `_`, and the result is cut to 64 characters.
11
+ *
12
+ * Temporary heuristic: the host has no toolset id on a tool call, so it can only
13
+ * correlate a call with a toolset by guessing this name. Replace it once MCP Apps
14
+ * are fully supported and the orchestrator reports the toolset a call belongs to.
15
+ * @param input - raw `${toolsetName}_${toolName}` (or `${toolsetName}_` prefix)
16
+ */
17
+ export declare const sanitizeToolName: (input: string) => string;
4
18
  /**
5
19
  * Collects every real tool-call name seen across `messages`' `custom_content.state`
6
20
  * (in whichever known orchestrator shape is present). Used to discover an MCP-capable
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-app.d.ts","sourceRoot":"","sources":["../../src/utils/mcp-app.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,OAAO,EAEb,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,KAAK,EACV,cAAc,EACd,kBAAkB,EAClB,aAAa,EACd,MAAM,oBAAoB,CAAC;AA2D5B;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAAI,UAAU,OAAO,EAAE,KAAG,GAAG,CAAC,MAAM,CAUpE,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,oBAAoB,GAC/B,SAAS,OAAO,EAChB,aAAa,aAAa,EAAE,EAC5B,aAAa,OAAO,KACnB,aAAa,GAAG,SAclB,CAAC;AAEF,qMAAqM;AACrM,eAAO,MAAM,eAAe,GAAI,cAAc,MAAM,KAAG,MAC5B,CAAC;AAE5B;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAC/B,UAAU,kBAAkB,GAAG,SAAS,KACvC,MAAM,GAAG,SAC+D,CAAC;AAE5E;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,yBAAyB,GACpC,SAAS,OAAO,EAChB,UAAU,MAAM,KACf,kBAAkB,GAAG,SAgBvB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,uBAAuB,GAClC,OAAO,aAAa,EACpB,MAAM,kBAAkB,GAAG,SAAS,EACpC,UAAU,cAAc,KACvB,OAAO,CAAC,cAAc,GAAG,SAAS,CAgBpC,CAAC"}
1
+ {"version":3,"file":"mcp-app.d.ts","sourceRoot":"","sources":["../../src/utils/mcp-app.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,OAAO,EAEb,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,KAAK,EACV,cAAc,EACd,kBAAkB,EAClB,aAAa,EACd,MAAM,oBAAoB,CAAC;AA8D5B;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,gBAAgB,GAAI,OAAO,MAAM,KAAG,MAMhD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAAI,UAAU,OAAO,EAAE,KAAG,GAAG,CAAC,MAAM,CAUpE,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,oBAAoB,GAC/B,SAAS,OAAO,EAChB,aAAa,aAAa,EAAE,EAC5B,aAAa,OAAO,KACnB,aAAa,GAAG,SAclB,CAAC;AAEF,qMAAqM;AACrM,eAAO,MAAM,eAAe,GAAI,cAAc,MAAM,KAAG,MAC5B,CAAC;AAE5B;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAC/B,UAAU,kBAAkB,GAAG,SAAS,KACvC,MAAM,GAAG,SAC+D,CAAC;AAE5E;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,yBAAyB,GACpC,SAAS,OAAO,EAChB,UAAU,MAAM,KACf,kBAAkB,GAAG,SAgBvB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,uBAAuB,GAClC,OAAO,aAAa,EACpB,MAAM,kBAAkB,GAAG,SAAS,EACpC,UAAU,cAAc,KACvB,OAAO,CAAC,cAAc,GAAG,SAAS,CAgBpC,CAAC"}