@admin-layout/ai-chat-ext-browser 12.2.4-alpha.103 → 12.2.4-alpha.104

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.
@@ -7,11 +7,13 @@ export interface IMessageMediaProps {
7
7
  onMessageClick?: (ref: IPost) => void;
8
8
  }
9
9
  /**
10
- * Media card — renders the image / video / audio a cdecli generation connector
11
- * (yantra-image-generation, yantra-video-generation, audio / TTS, …) returned,
12
- * inline in the chat. Shows the asset(s), the prompt as a caption, an
13
- * attribution line (connector · model), and open / download actions. The asset
14
- * URLs live on the message's propsConfiguration, so they persist with the chat.
10
+ * Media result card — renders the image / video / audio a cdecli generation
11
+ * connector (yantra-image-generation, yantra-video-generation, audio / TTS, …)
12
+ * returned, inline in the chat. Shows the asset(s) in a real player, a technical
13
+ * metadata row (kind · dimensions · duration · format · model) derived from the
14
+ * loaded asset, the prompt as a caption, and open / download / copy-link actions.
15
+ * The asset URLs live on the message's propsConfiguration, so they persist with
16
+ * the chat.
15
17
  */
16
18
  export declare const MessageMedia: (props: IMessageMediaProps) => React.JSX.Element;
17
19
  //# sourceMappingURL=MessageMedia.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MessageMedia.d.ts","sourceRoot":"","sources":["../../../src/components/MessageWidgets/MessageMedia.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAM1B,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAI/B,MAAM,WAAW,kBAAkB;IAC/B,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,uFAAuF;IACvF,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,CAAC;CACzC;AAQD;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,GAAI,OAAO,kBAAkB,sBAsFrD,CAAC"}
1
+ {"version":3,"file":"MessageMedia.d.ts","sourceRoot":"","sources":["../../../src/components/MessageWidgets/MessageMedia.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAQxC,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAa/B,MAAM,WAAW,kBAAkB;IAC/B,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,uFAAuF;IACvF,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,CAAC;CACzC;AAaD;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,GAAI,OAAO,kBAAkB,sBAyIrD,CAAC"}
@@ -1,29 +1,28 @@
1
- import React from'react';import {FiImage}from'@react-icons/all-files/fi/FiImage.js';import {FiVideo}from'@react-icons/all-files/fi/FiVideo.js';import {FiMusic}from'@react-icons/all-files/fi/FiMusic.js';import {FiDownload}from'@react-icons/all-files/fi/FiDownload.js';import {FiExternalLink}from'@react-icons/all-files/fi/FiExternalLink.js';import {MediaAsset}from'@admin-layout/connector-widgets-browser';const KIND_META = {
2
- image: {
3
- icon: React.createElement(FiImage, {
4
- className: "w-4 h-4"
5
- }),
6
- label: 'Image'
7
- },
8
- video: {
9
- icon: React.createElement(FiVideo, {
10
- className: "w-4 h-4"
11
- }),
12
- label: 'Video'
13
- },
14
- audio: {
15
- icon: React.createElement(FiMusic, {
16
- className: "w-4 h-4"
17
- }),
18
- label: 'Audio'
19
- }
1
+ import React,{useState}from'react';import {FiImage}from'@react-icons/all-files/fi/FiImage.js';import {FiVideo}from'@react-icons/all-files/fi/FiVideo.js';import {FiMusic}from'@react-icons/all-files/fi/FiMusic.js';import {FiDownload}from'@react-icons/all-files/fi/FiDownload.js';import {FiExternalLink}from'@react-icons/all-files/fi/FiExternalLink.js';import {FiCopy}from'@react-icons/all-files/fi/FiCopy.js';import {FiCheck}from'@react-icons/all-files/fi/FiCheck.js';import {MediaAsset}from'@admin-layout/connector-widgets-browser';import {deriveMediaItems,MEDIA_KIND_LABEL,formatAttribution,formatDimensions,formatDuration,formatMediaFormat}from'./mediaUtils.js';const KIND_ICON = {
2
+ image: React.createElement(FiImage, {
3
+ className: "w-3.5 h-3.5"
4
+ }),
5
+ video: React.createElement(FiVideo, {
6
+ className: "w-3.5 h-3.5"
7
+ }),
8
+ audio: React.createElement(FiMusic, {
9
+ className: "w-3.5 h-3.5"
10
+ })
20
11
  };
12
+ /** One compact `·`-separated metadata cell. */
13
+ const MetaCell = ({
14
+ children
15
+ }) => React.createElement("span", {
16
+ className: "inline-flex items-center whitespace-nowrap"
17
+ }, children);
21
18
  /**
22
- * Media card — renders the image / video / audio a cdecli generation connector
23
- * (yantra-image-generation, yantra-video-generation, audio / TTS, …) returned,
24
- * inline in the chat. Shows the asset(s), the prompt as a caption, an
25
- * attribution line (connector · model), and open / download actions. The asset
26
- * URLs live on the message's propsConfiguration, so they persist with the chat.
19
+ * Media result card — renders the image / video / audio a cdecli generation
20
+ * connector (yantra-image-generation, yantra-video-generation, audio / TTS, …)
21
+ * returned, inline in the chat. Shows the asset(s) in a real player, a technical
22
+ * metadata row (kind · dimensions · duration · format · model) derived from the
23
+ * loaded asset, the prompt as a caption, and open / download / copy-link actions.
24
+ * The asset URLs live on the message's propsConfiguration, so they persist with
25
+ * the chat.
27
26
  */
28
27
  const MessageMedia = props => {
29
28
  const {
@@ -34,58 +33,91 @@ const MessageMedia = props => {
34
33
  const {
35
34
  attachment
36
35
  } = message.propsConfiguration?.contents ?? {};
36
+ const [assetMeta, setAssetMeta] = useState({});
37
+ const [copied, setCopied] = useState(false);
37
38
  if (!attachment || !attachment.url) return null;
38
- const items = attachment.items && attachment.items.length > 0 ? attachment.items : [{
39
- kind: attachment.kind,
40
- url: attachment.url,
41
- title: attachment.title,
42
- mimeType: attachment.mimeType,
43
- posterUrl: attachment.posterUrl
44
- }];
45
- const meta = KIND_META[attachment.kind] ?? KIND_META.image;
46
- const title = attachment.title || `${meta.label} generated`;
47
- const attribution = [attachment.connector, attachment.model].filter(Boolean).join(' · ');
48
- const isGrid = items.length > 1 && attachment.kind === 'image';
39
+ const items = deriveMediaItems(attachment);
40
+ if (items.length === 0) return null;
41
+ const kind = attachment.kind;
42
+ const kindLabel = MEDIA_KIND_LABEL[kind] ?? MEDIA_KIND_LABEL.image;
43
+ const kindIcon = KIND_ICON[kind] ?? KIND_ICON.image;
44
+ const title = attachment.title || `${kindLabel} generated`;
45
+ const attribution = formatAttribution(attachment);
46
+ const isImageGrid = items.length > 1 && kind === 'image';
47
+ // Technical metadata — dimensions/duration come from the loaded asset (single
48
+ // asset only; a grid has no one set of dimensions), format from the mime type.
49
+ const dimensions = !isImageGrid ? formatDimensions(assetMeta.width, assetMeta.height) : undefined;
50
+ const duration = !isImageGrid ? formatDuration(assetMeta.duration) : undefined;
51
+ const format = formatMediaFormat(attachment.mimeType, attachment.fileName);
52
+ const metaCells = [isImageGrid ? `${items.length} images` : undefined, dimensions, duration, format, attribution].filter(Boolean);
49
53
  const open = () => onMessageClick?.(message);
54
+ const copyLink = async () => {
55
+ try {
56
+ await navigator.clipboard?.writeText(attachment.url);
57
+ setCopied(true);
58
+ window.setTimeout(() => setCopied(false), 1600);
59
+ } catch {
60
+ /* clipboard unavailable — no-op */
61
+ }
62
+ };
50
63
  return React.createElement("div", {
51
64
  key: `${index}`,
52
- className: "my-2 mx-2 rounded-xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800/60 overflow-hidden"
65
+ className: "my-2 mx-2 w-[calc(100%-1rem)] rounded-xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800/60 overflow-hidden"
53
66
  }, React.createElement("div", {
54
- className: "flex items-center gap-2 px-3 py-2 border-b border-gray-100 dark:border-gray-700"
67
+ className: "flex items-center gap-2 px-3 py-2.5 border-b border-gray-100 dark:border-gray-700/80"
55
68
  }, React.createElement("span", {
56
- className: "flex-shrink-0 text-blue-500"
57
- }, meta.icon), React.createElement("p", {
58
- className: "flex-1 min-w-0 text-sm font-semibold text-gray-900 dark:text-gray-100 truncate"
69
+ className: "flex-shrink-0 inline-flex items-center gap-1 rounded-md bg-blue-50 dark:bg-gray-700 px-1.5 py-0.5 text-[11px] font-medium text-blue-600 dark:text-blue-400"
70
+ }, kindIcon, kindLabel), React.createElement("p", {
71
+ className: "flex-1 min-w-0 text-sm font-semibold text-gray-900 dark:text-gray-100 truncate",
72
+ title: title
59
73
  }, title), attribution && React.createElement("span", {
60
- className: "flex-shrink-0 text-[10px] text-gray-400 dark:text-gray-500 truncate max-w-[55%]"
74
+ className: "flex-shrink-0 text-[11px] text-gray-400 dark:text-gray-500 truncate max-w-[55%]"
61
75
  }, attribution)), React.createElement("div", {
62
- className: `p-2 ${isGrid ? 'grid grid-cols-2 gap-2' : 'flex flex-col gap-2'}`,
76
+ className: `p-2 ${isImageGrid ? 'grid grid-cols-2 gap-2' : 'flex flex-col gap-2'}`,
63
77
  onClick: open,
64
78
  role: onMessageClick ? 'button' : undefined
65
79
  }, items.map((item, i) => React.createElement(MediaAsset, {
66
80
  key: (item.url ?? '') + i,
67
- item: item
68
- }))), React.createElement("div", {
69
- className: "px-3 pb-3 pt-1"
81
+ item: item,
82
+ onMeta: items.length === 1 ? setAssetMeta : undefined
83
+ }))), metaCells.length > 0 && React.createElement("div", {
84
+ className: "px-3 pb-1 flex flex-wrap items-center gap-2 text-[11px] text-gray-500 dark:text-gray-400"
85
+ }, metaCells.map((cell, i) => React.createElement(React.Fragment, {
86
+ key: cell + i
87
+ }, i > 0 && React.createElement("span", {
88
+ className: "text-gray-300 dark:text-gray-600"
89
+ }, "\u00B7"), React.createElement(MetaCell, null, cell)))), React.createElement("div", {
90
+ className: "px-3 pb-3 pt-2"
70
91
  }, attachment.prompt && React.createElement("p", {
71
92
  className: "text-xs text-gray-500 dark:text-gray-400 line-clamp-2",
72
93
  title: attachment.prompt
73
94
  }, attachment.prompt), React.createElement("div", {
74
- className: "mt-2 flex items-center gap-3"
95
+ className: "mt-2 flex flex-wrap items-center gap-2"
75
96
  }, React.createElement("a", {
76
97
  href: attachment.url,
77
98
  target: "_blank",
78
99
  rel: "noopener noreferrer",
79
100
  onClick: e => e.stopPropagation(),
80
- className: "inline-flex items-center gap-1 text-xs font-medium text-blue-600 dark:text-blue-400 hover:underline"
81
- }, "Open ", React.createElement(FiExternalLink, {
82
- className: "w-3 h-3"
83
- })), React.createElement("a", {
101
+ className: "inline-flex items-center gap-1.5 rounded-lg bg-blue-600 hover:bg-blue-700 px-2.5 py-1.5 text-xs font-medium text-white transition-colors"
102
+ }, React.createElement(FiExternalLink, {
103
+ className: "w-3.5 h-3.5"
104
+ }), " Open"), React.createElement("a", {
84
105
  href: attachment.url,
85
106
  download: attachment.fileName || true,
86
107
  onClick: e => e.stopPropagation(),
87
- className: "inline-flex items-center gap-1 text-xs font-medium text-gray-600 dark:text-gray-300 hover:underline"
88
- }, "Download ", React.createElement(FiDownload, {
89
- className: "w-3 h-3"
90
- })))));
108
+ className: "inline-flex items-center gap-1.5 rounded-lg bg-gray-50 dark:bg-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600 px-2.5 py-1.5 text-xs font-medium text-gray-700 dark:text-gray-200 transition-colors"
109
+ }, React.createElement(FiDownload, {
110
+ className: "w-3.5 h-3.5"
111
+ }), " Download"), React.createElement("button", {
112
+ type: "button",
113
+ onClick: e => {
114
+ e.stopPropagation();
115
+ void copyLink();
116
+ },
117
+ className: "inline-flex items-center gap-1.5 rounded-lg bg-gray-50 dark:bg-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600 px-2.5 py-1.5 text-xs font-medium text-gray-700 dark:text-gray-200 transition-colors"
118
+ }, copied ? React.createElement(FiCheck, {
119
+ className: "w-3.5 h-3.5"
120
+ }) : React.createElement(FiCopy, {
121
+ className: "w-3.5 h-3.5"
122
+ }), copied ? 'Copied' : 'Copy link'))));
91
123
  };export{MessageMedia};//# sourceMappingURL=MessageMedia.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MessageMedia.js","sources":["../../../src/components/MessageWidgets/MessageMedia.tsx"],"sourcesContent":[null],"names":[],"mappings":"qZAiBA,MAAM,SAAS,GAAwE;AACnF,EAAA,KAAA,EAAK;AACL,IAAA,IAAA,EAAK,KAAI,CAAA,uBAAO;AAChB,MAAA,SAAS,EAAI;KACf,CAAA;AAEF,IAAA,KAAA,EAAA;;;;;;AAMG,IAAA,KAAA,EAAA;AACH,GAAA;OACI,EAAA;AACA,IAAA,IAAA,EAAM,KAAE,CAAA,aAAgB,CAAA,OAAQ,EAAA;AAIhC,MAAA,SAAK,EAAA;AAA+B,KAAA,CAAA;AAEpC,IAAA,KAAA,EAAM;;AAGE,CAAA;AACM;;;;;;AAMC;AACH,MAAA,YAAA,GAAA,KAAA,IAAA;AAEZ,EAAA,MAAA;IACA,OAAM;IACN,KAAA;AACA,IAAA;MAEA,KAAM;QAEN;;AAOY,GAAA,GAAA,OAAA,CAAA,kBAAA,EAAA,QAAM;AACN,EAAA,IAAA,CAAA,UAAA,IAAA,CAAA,UAAA,CAAA,GAAA,EAAA,OAAG,IAAS;aAGX,GAAA,UAAW,CAAI,KACZ,IAAA,UAAA,CAAA,KAAA,CAAA,MAAM,GAAA,CAAA,GAAA;AAOd,IAAA,IAAA,EAAA,UAAA,CAAA,IAAA;SAWA,UAAA,CAAA,GAAA;AACK,IAAA,KAAA,EAAA,UAAA,CAAU,KAAC;YAKZ,EAAA,UAAA,CAAA,QAAA;AACI,IAAA,SAAA,EAAA,UAAA,CAAA;;AAOS,EAAA,MAAA,IAAA,GAAA,SAAA,CAAA,UAAA,CAAA,IAAC,cAAc,CAAA,KAAC;AAEzB,EAAA,MAAA,KAAA,GAAA,UAAA,CAAA,KAAA,IAAA,CAAA,EAAA,IACI,CAAA,KAAM,CAAA,UAAW,CAAA;;sBAKR,CAAA,MAAA,GAAA,CAAA,IAAA,UAAC,CAAA,IAAU,KAAC,OAAS;AAMtD,EAAE,MAAA,IAAA,GAAA,MAAA,cAAA,GAAA,OAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"MessageMedia.js","sources":["../../../src/components/MessageWidgets/MessageMedia.tsx"],"sourcesContent":[null],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import { MediaAttachmentsInterface, MediaItem } from '../../interfaces';
2
+ export type MediaKind = MediaItem['kind'];
3
+ /** Human label for each asset kind. */
4
+ export declare const MEDIA_KIND_LABEL: Record<MediaKind, string>;
5
+ /**
6
+ * Normalise an attachment into a flat list of assets. Agents emit two shapes:
7
+ * a single top-level `url`, or a nested `items[]` array — this tolerates both.
8
+ */
9
+ export declare const deriveMediaItems: (attachment: MediaAttachmentsInterface) => MediaItem[];
10
+ /** Seconds → `m:ss` (hours fold into minutes). `65` → `"1:05"`, `8` → `"0:08"`. */
11
+ export declare const formatDuration: (seconds?: number) => string | undefined;
12
+ /** Intrinsic dimensions → `"1920×1080"`; undefined until both are known. */
13
+ export declare const formatDimensions: (width?: number, height?: number) => string | undefined;
14
+ /**
15
+ * Short uppercase format label from the mime subtype, falling back to the file
16
+ * extension. `"video/mp4"` → `"MP4"`, `"image/png"` → `"PNG"`, `foo.webp` → `"WEBP"`.
17
+ */
18
+ export declare const formatMediaFormat: (mimeType?: string, fileName?: string) => string | undefined;
19
+ /** The attribution line: `connector · model`, omitting whichever is absent. */
20
+ export declare const formatAttribution: (attachment: MediaAttachmentsInterface) => string | undefined;
21
+ //# sourceMappingURL=mediaUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mediaUtils.d.ts","sourceRoot":"","sources":["../../../src/components/MessageWidgets/mediaUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAExE,MAAM,MAAM,SAAS,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;AAE1C,uCAAuC;AACvC,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAItD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,gBAAgB,GAAI,YAAY,yBAAyB,KAAG,SAAS,EAcjF,CAAC;AAEF,mFAAmF;AACnF,eAAO,MAAM,cAAc,GAAI,UAAU,MAAM,KAAG,MAAM,GAAG,SAM1D,CAAC;AAEF,4EAA4E;AAC5E,eAAO,MAAM,gBAAgB,GAAI,QAAQ,MAAM,EAAE,SAAS,MAAM,KAAG,MAAM,GAAG,SACtB,CAAC;AAUvD;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,WAAW,MAAM,EAAE,WAAW,MAAM,KAAG,MAAM,GAAG,SAMjF,CAAC;AAEF,+EAA+E;AAC/E,eAAO,MAAM,iBAAiB,GAAI,YAAY,yBAAyB,KAAG,MAAM,GAAG,SAGlF,CAAC"}
@@ -0,0 +1,54 @@
1
+ /** Human label for each asset kind. */
2
+ const MEDIA_KIND_LABEL = {
3
+ image: 'Image',
4
+ video: 'Video',
5
+ audio: 'Audio'
6
+ };
7
+ /**
8
+ * Normalise an attachment into a flat list of assets. Agents emit two shapes:
9
+ * a single top-level `url`, or a nested `items[]` array — this tolerates both.
10
+ */
11
+ const deriveMediaItems = attachment => {
12
+ if (Array.isArray(attachment.items) && attachment.items.length > 0) {
13
+ return attachment.items;
14
+ }
15
+ if (!attachment.url) return [];
16
+ return [{
17
+ kind: attachment.kind,
18
+ url: attachment.url,
19
+ title: attachment.title,
20
+ mimeType: attachment.mimeType,
21
+ posterUrl: attachment.posterUrl
22
+ }];
23
+ };
24
+ /** Seconds → `m:ss` (hours fold into minutes). `65` → `"1:05"`, `8` → `"0:08"`. */
25
+ const formatDuration = seconds => {
26
+ if (seconds == null || !Number.isFinite(seconds) || seconds < 0) return undefined;
27
+ const total = Math.round(seconds);
28
+ const minutes = Math.floor(total / 60);
29
+ const secs = total % 60;
30
+ return `${minutes}:${secs.toString().padStart(2, '0')}`;
31
+ };
32
+ /** Intrinsic dimensions → `"1920×1080"`; undefined until both are known. */
33
+ const formatDimensions = (width, height) => width && height ? `${width}×${height}` : undefined;
34
+ /** Common mime subtypes that read better under a short alias than raw. */
35
+ const FORMAT_ALIASES = {
36
+ quicktime: 'MOV',
37
+ 'x-matroska': 'MKV',
38
+ jpeg: 'JPG',
39
+ 'svg+xml': 'SVG'
40
+ };
41
+ /**
42
+ * Short uppercase format label from the mime subtype, falling back to the file
43
+ * extension. `"video/mp4"` → `"MP4"`, `"image/png"` → `"PNG"`, `foo.webp` → `"WEBP"`.
44
+ */
45
+ const formatMediaFormat = (mimeType, fileName) => {
46
+ const sub = mimeType?.split('/')[1]?.split(';')[0]?.trim().toLowerCase() || fileName?.split('.').pop()?.trim().toLowerCase();
47
+ if (!sub) return undefined;
48
+ return (FORMAT_ALIASES[sub] ?? sub).toUpperCase();
49
+ };
50
+ /** The attribution line: `connector · model`, omitting whichever is absent. */
51
+ const formatAttribution = attachment => {
52
+ const parts = [attachment.connector, attachment.model].filter(Boolean);
53
+ return parts.length ? parts.join(' · ') : undefined;
54
+ };export{MEDIA_KIND_LABEL,deriveMediaItems,formatAttribution,formatDimensions,formatDuration,formatMediaFormat};//# sourceMappingURL=mediaUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mediaUtils.js","sources":["../../../src/components/MessageWidgets/mediaUtils.ts"],"sourcesContent":[null],"names":[],"mappings":"AAIA;AACO,MAAM,gBAAgB,GAA8B;AACvD,EAAA,KAAA,EAAK,OAAE;AACP,EAAA,KAAA,EAAK,OAAE;AACP,EAAA,KAAA,EAAK;;AAGT;;;AAGG;AACI,MAAM,gBAAgB,GAAG,UAAC,IAAoD;AACjF,EAAA,IAAA,aAAU,CAAA,UAAQ,CAAA,KAAW,CAAA,IAAM,UAAI,CAAA,KAAW,CAAA,SAAY,CAAA,EAAI;WAC9D,UAAO,CAAA,KAAW;;MAEtB,CAAA,UAAK,CAAA,GAAW,EAAG,OAAA,EAAA;AAAE,EAAA,OAAA,CAAA;IACrB,IAAA,EAAA,UAAO,CAAA,IAAA;AACH,IAAA,GAAA,EAAA,UAAA,CAAA,GAAA;qBACU,CAAA,KAAA;YACN,EAAA,UAAK,CAAA,QAAc;aACnB,EAAA,UAAO,CAAA;;;AAGV;AACH,MAAA,cAAA,GAAA,OAAA,IAAA;AACN,EAAE,IAAA,OAAA,IAAA,IAAA,IAAA,CAAA,MAAA,CAAA,QAAA,CAAA,OAAA,CAAA,IAAA,OAAA,GAAA,CAAA,EAAA,OAAA,SAAA;AAEF,EAAA,MAAA,KAAA,GAAA,IAAA,CAAA,KAAA,CAAA,OAAA,CAAA;AACA,EAAA,MAAO,OAAM,GAAA,IAAA,CAAA,WAAkB,GAAA,GAAsC;AACjE,EAAA,MAAI,IAAA,GAAO,KAAI,GAAI,EAAA;AAA8C,EAAA,OAAA,CAAA,EAAA,eAAiB,CAAA,QAAA,EAAA,CAAA,QAAA,CAAA,CAAA,EAAA,GAAA,CAAA,CAAA,CAAA;;;AAG5E,MAAA,gBAAkB,GAAA,CAAA,KAAA,EAAA,MAAA,KAAA,KAAA,IAAA,MAAA,GAAA,CAAA,EAAA,KAAA,CAAA,CAAA,EAAA,MAAA,CAAA,CAAA,GAAA;AACxB;AACJ,MAAE,cAAA,GAAA;AAEF,EAAA,SAAA,EAAA,KAAA;AACA,EAAA,YAAa,EAAA,KAAA;AAGb,EAAA,IAAA,EAAA,KAAA;AACA,EAAA;AACI,CAAA;AACA;AACA;AACA;;AAGJ,MAAA,iBAAA,GAAA,CAAA,QAAA,EAAA,QAAA,KAAA;;;AAGG,EAAA,OAAA,CAAA,cAAA,CAAA,GAAA,CAAA,IAAA,GAAA,EAAA,WAAA,EAAA;AACH;;AAGQ,MAAA,iBAAqB,GAAG,UAAW,IAAA;AACvC,EAAA,MAAI,KAAI,GAAA,CAAA,UAAA,CAAA,SAAA,EAAA,UAAA,CAAA,KAAA,CAAA,CAAA,MAAA,CAAA,OAAA,CAAA;AAAE,EAAA,OAAA,KAAA,CAAO,SAAS,KAAC,CAAA,IAAA,CAAA,KAAA,CAAA,GAAA,SAAA;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@admin-layout/ai-chat-ext-browser",
3
- "version": "12.2.4-alpha.103",
3
+ "version": "12.2.4-alpha.104",
4
4
  "description": "AI Chat extension for Messenger - supports AI assistant, thinking, code blocks, tool use, and service messages",
5
5
  "license": "ISC",
6
6
  "author": "CDMBase LLC",
@@ -21,7 +21,7 @@
21
21
  "watch": "npm run build:lib:watch"
22
22
  },
23
23
  "dependencies": {
24
- "@admin-layout/connector-widgets-browser": "12.2.4-alpha.103",
24
+ "@admin-layout/connector-widgets-browser": "12.2.4-alpha.104",
25
25
  "html-react-parser": "^3.0.1"
26
26
  },
27
27
  "devDependencies": {
@@ -36,7 +36,7 @@
36
36
  "publishConfig": {
37
37
  "access": "public"
38
38
  },
39
- "gitHead": "2fe65c48f3d39ef929660fd4c10535e48357f428",
39
+ "gitHead": "539eeb5806b9f83a8d25d83e7f95ad334f6c17c0",
40
40
  "typescript": {
41
41
  "definition": "lib/index.d.ts"
42
42
  }