@heroui/agent 0.2.0-beta.1

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.
@@ -0,0 +1,1084 @@
1
+ // src/embed/client-tools.ts
2
+ function createToolHelper() {
3
+ return function defineClientTool(definition) {
4
+ return definition;
5
+ };
6
+ }
7
+ function isZodSchema(value) {
8
+ return Boolean(
9
+ value && typeof value === "object" && typeof value.safeParse === "function"
10
+ );
11
+ }
12
+ function parseClientToolArgs(tool, input) {
13
+ return isZodSchema(tool.parameters) ? tool.parameters.parse(input) : input;
14
+ }
15
+ function resolveDirectToolAction(tools, toolName) {
16
+ const tool = tools.get(toolName);
17
+ if (!tool || tool.needsApproval) return null;
18
+ return tool;
19
+ }
20
+
21
+ // src/embed/composer-draft.ts
22
+ var AGENT_COMPOSER_DRAFT_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
23
+ var AGENT_COMPOSER_DRAFT_DB_NAME = "heroui-agent-embed";
24
+ var AGENT_COMPOSER_DRAFT_DB_VERSION = 1;
25
+ var AGENT_COMPOSER_IMAGE_DRAFT_STORE = "composer-image-drafts";
26
+ var AGENT_COMPOSER_DRAFT_MARKER = ":composer-draft:";
27
+ var pendingImageDraftMutations = /* @__PURE__ */ new Map();
28
+ function agentComposerDraftStorageKey(conversationStorageKey, conversationId) {
29
+ return `${conversationStorageKey}${AGENT_COMPOSER_DRAFT_MARKER}${conversationId}:v1`;
30
+ }
31
+ function readAgentComposerPromptDraft(key, now = Date.now()) {
32
+ if (typeof window === "undefined") return "";
33
+ try {
34
+ const raw = window.localStorage.getItem(key);
35
+ if (!raw) return "";
36
+ const parsed = JSON.parse(raw);
37
+ const isFresh = typeof parsed.savedAt === "number" && now - parsed.savedAt <= AGENT_COMPOSER_DRAFT_MAX_AGE_MS;
38
+ if (!isFresh || typeof parsed.prompt !== "string" || !parsed.prompt.trim()) {
39
+ window.localStorage.removeItem(key);
40
+ return "";
41
+ }
42
+ return parsed.prompt;
43
+ } catch {
44
+ try {
45
+ window.localStorage.removeItem(key);
46
+ } catch {
47
+ }
48
+ return "";
49
+ }
50
+ }
51
+ function saveAgentComposerPromptDraft(key, prompt, now = Date.now()) {
52
+ if (typeof window === "undefined") return;
53
+ try {
54
+ if (!prompt.trim()) {
55
+ window.localStorage.removeItem(key);
56
+ return;
57
+ }
58
+ window.localStorage.setItem(
59
+ key,
60
+ JSON.stringify({ prompt, savedAt: now })
61
+ );
62
+ } catch {
63
+ }
64
+ }
65
+ async function readAgentComposerImageDraft(key, now = Date.now()) {
66
+ await pendingImageDraftMutations.get(key);
67
+ const stored = await readImageDraftRecord(key);
68
+ if (!stored) return [];
69
+ const isFresh = now - stored.savedAt <= AGENT_COMPOSER_DRAFT_MAX_AGE_MS;
70
+ const files = stored.files.filter(isPersistableImageFile);
71
+ if (!isFresh || files.length === 0) {
72
+ await queueImageDraftMutation(key, () => deleteImageDraftRecord(key));
73
+ return [];
74
+ }
75
+ return files;
76
+ }
77
+ function saveAgentComposerImageDraft(key, files, now = Date.now()) {
78
+ const images = files.filter(isPersistableImageFile);
79
+ return queueImageDraftMutation(
80
+ key,
81
+ () => images.length > 0 ? writeImageDraftRecord({ files: images, key, savedAt: now }) : deleteImageDraftRecord(key)
82
+ );
83
+ }
84
+ function clearAgentComposerDraft(key) {
85
+ if (typeof window !== "undefined") {
86
+ try {
87
+ window.localStorage.removeItem(key);
88
+ } catch {
89
+ }
90
+ }
91
+ return queueImageDraftMutation(key, () => deleteImageDraftRecord(key));
92
+ }
93
+ async function clearAgentComposerDraftsForProject(agentId) {
94
+ const prefix = `heroui-agent:conversation:${agentId}:`;
95
+ if (typeof window !== "undefined") {
96
+ try {
97
+ for (let index = window.localStorage.length - 1; index >= 0; index -= 1) {
98
+ const key = window.localStorage.key(index);
99
+ if (key?.startsWith(prefix) && key.includes(AGENT_COMPOSER_DRAFT_MARKER)) {
100
+ window.localStorage.removeItem(key);
101
+ }
102
+ }
103
+ } catch {
104
+ }
105
+ }
106
+ const pending = [...pendingImageDraftMutations.entries()].filter(([key]) => key.startsWith(prefix)).map(([, mutation]) => mutation);
107
+ await Promise.all(pending);
108
+ await deleteImageDraftRecordsByPrefix(prefix);
109
+ }
110
+ function isPersistableImageFile(value) {
111
+ return typeof File !== "undefined" && value instanceof File && typeof value.type === "string" && value.type.startsWith("image/");
112
+ }
113
+ function queueImageDraftMutation(key, mutation) {
114
+ const previous = pendingImageDraftMutations.get(key) ?? Promise.resolve();
115
+ const next = previous.catch(() => void 0).then(mutation).catch(() => void 0);
116
+ pendingImageDraftMutations.set(key, next);
117
+ void next.finally(() => {
118
+ if (pendingImageDraftMutations.get(key) === next) pendingImageDraftMutations.delete(key);
119
+ });
120
+ return next;
121
+ }
122
+ function openImageDraftDatabase() {
123
+ if (typeof indexedDB === "undefined") return Promise.resolve(null);
124
+ return new Promise((resolve) => {
125
+ const request = indexedDB.open(AGENT_COMPOSER_DRAFT_DB_NAME, AGENT_COMPOSER_DRAFT_DB_VERSION);
126
+ request.onerror = () => resolve(null);
127
+ request.onupgradeneeded = () => {
128
+ const database = request.result;
129
+ if (!database.objectStoreNames.contains(AGENT_COMPOSER_IMAGE_DRAFT_STORE)) {
130
+ database.createObjectStore(AGENT_COMPOSER_IMAGE_DRAFT_STORE, { keyPath: "key" });
131
+ }
132
+ };
133
+ request.onsuccess = () => resolve(request.result);
134
+ });
135
+ }
136
+ async function withImageDraftStore(mode, run) {
137
+ let database;
138
+ try {
139
+ database = await openImageDraftDatabase();
140
+ } catch {
141
+ return null;
142
+ }
143
+ if (!database) return null;
144
+ try {
145
+ const transaction = database.transaction(AGENT_COMPOSER_IMAGE_DRAFT_STORE, mode);
146
+ const completion = waitForTransaction(transaction);
147
+ const [result] = await Promise.all([
148
+ run(transaction.objectStore(AGENT_COMPOSER_IMAGE_DRAFT_STORE)),
149
+ completion
150
+ ]);
151
+ return result;
152
+ } catch {
153
+ return null;
154
+ } finally {
155
+ database.close();
156
+ }
157
+ }
158
+ async function readImageDraftRecord(key) {
159
+ const result = await withImageDraftStore(
160
+ "readonly",
161
+ (store) => waitForRequest(store.get(key))
162
+ );
163
+ if (typeof result !== "object" || result === null) return null;
164
+ const draft = result;
165
+ if (draft.key !== key || typeof draft.savedAt !== "number" || !Array.isArray(draft.files)) {
166
+ return null;
167
+ }
168
+ return { files: draft.files.filter(isPersistableImageFile), key, savedAt: draft.savedAt };
169
+ }
170
+ async function writeImageDraftRecord(draft) {
171
+ await withImageDraftStore("readwrite", async (store) => {
172
+ await waitForRequest(store.put(draft));
173
+ });
174
+ }
175
+ async function deleteImageDraftRecord(key) {
176
+ await withImageDraftStore("readwrite", async (store) => {
177
+ await waitForRequest(store.delete(key));
178
+ });
179
+ }
180
+ async function deleteImageDraftRecordsByPrefix(prefix) {
181
+ await withImageDraftStore(
182
+ "readwrite",
183
+ (store) => new Promise((resolve, reject) => {
184
+ const request = store.openCursor();
185
+ request.onerror = () => reject(request.error ?? new Error("Unable to clear image drafts"));
186
+ request.onsuccess = () => {
187
+ const cursor = request.result;
188
+ if (!cursor) {
189
+ resolve();
190
+ return;
191
+ }
192
+ if (typeof cursor.key === "string" && cursor.key.startsWith(prefix)) cursor.delete();
193
+ cursor.continue();
194
+ };
195
+ })
196
+ );
197
+ }
198
+ function waitForRequest(request) {
199
+ return new Promise((resolve, reject) => {
200
+ request.onerror = () => reject(request.error ?? new Error("IndexedDB request failed"));
201
+ request.onsuccess = () => resolve(request.result);
202
+ });
203
+ }
204
+ function waitForTransaction(transaction) {
205
+ return new Promise((resolve, reject) => {
206
+ transaction.onabort = () => reject(transaction.error ?? new Error("IndexedDB aborted"));
207
+ transaction.onerror = () => reject(transaction.error ?? new Error("IndexedDB failed"));
208
+ transaction.oncomplete = () => resolve();
209
+ });
210
+ }
211
+
212
+ // src/embed/idle.ts
213
+ function scheduleIdleTask(task, timeoutMs = 3e3) {
214
+ if (typeof window === "undefined") return () => void 0;
215
+ const idle = window.requestIdleCallback;
216
+ if (!idle) {
217
+ const timeout = window.setTimeout(task, Math.min(timeoutMs, 1500));
218
+ return () => window.clearTimeout(timeout);
219
+ }
220
+ const handle = idle(() => task(), { timeout: timeoutMs });
221
+ return () => window.cancelIdleCallback?.(handle);
222
+ }
223
+
224
+ // src/embed/composer-control-tooltip.tsx
225
+ import { jsx, jsxs } from "react/jsx-runtime";
226
+ function ComposerControlTooltip({
227
+ children,
228
+ shortcut
229
+ }) {
230
+ return /* @__PURE__ */ jsxs("span", { "aria-hidden": "true", className: "ha-control-tooltip", children: [
231
+ /* @__PURE__ */ jsx("span", { children }),
232
+ shortcut ? /* @__PURE__ */ jsx("kbd", { className: "ha-control-tooltip__shortcut", children: shortcut }) : null
233
+ ] });
234
+ }
235
+
236
+ // src/embed/panel-shell.tsx
237
+ import { ChevronsCollapseUpRight, ChevronsExpandUpRight } from "@gravity-ui/icons";
238
+ import { useCallback, useEffect, useEffectEvent, useRef, useState } from "react";
239
+
240
+ // src/embed/sidebar-width.ts
241
+ var SIDEBAR_DEFAULT_WIDTH = 420;
242
+ var SIDEBAR_MIN_WIDTH = 320;
243
+ var SIDEBAR_MAX_WIDTH = 720;
244
+ function sidebarWidthStorageKey(agentId) {
245
+ return `heroui-agent:sidebar-width:${agentId}`;
246
+ }
247
+ function clampSidebarWidth(width, viewportWidth) {
248
+ const viewportMax = Math.min(SIDEBAR_MAX_WIDTH, Math.floor(viewportWidth * 0.9));
249
+ const max = Math.max(viewportMax, SIDEBAR_MIN_WIDTH);
250
+ return Math.min(Math.max(Math.round(width), SIDEBAR_MIN_WIDTH), max);
251
+ }
252
+ function readSidebarWidth(agentId, viewportWidth) {
253
+ let stored = Number.NaN;
254
+ try {
255
+ stored = Number(localStorage.getItem(sidebarWidthStorageKey(agentId)) ?? Number.NaN);
256
+ } catch {
257
+ }
258
+ return clampSidebarWidth(Number.isFinite(stored) ? stored : SIDEBAR_DEFAULT_WIDTH, viewportWidth);
259
+ }
260
+ function persistSidebarWidth(agentId, width) {
261
+ try {
262
+ localStorage.setItem(sidebarWidthStorageKey(agentId), String(Math.round(width)));
263
+ } catch {
264
+ }
265
+ }
266
+
267
+ // src/embed/panel-shell.tsx
268
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
269
+ function PanelShell({
270
+ actionsSlot,
271
+ agentId,
272
+ children,
273
+ defaultExpanded = false,
274
+ expandable = true,
275
+ expandedSidebarSlot,
276
+ expandedTitle,
277
+ historySlot,
278
+ modal,
279
+ name,
280
+ onClose,
281
+ onNewConversation,
282
+ open
283
+ }) {
284
+ const panelRef = useRef(null);
285
+ const overlayEscapeAt = useRef(0);
286
+ const [isMobileViewport, setIsMobileViewport] = useState(
287
+ () => typeof window !== "undefined" && window.matchMedia?.("(max-width: 639px)").matches === true
288
+ );
289
+ const closePanel = useEffectEvent(onClose);
290
+ const [isExpanded, setIsExpanded] = useState(defaultExpanded);
291
+ const isDesktopSidebar = !modal && !isMobileViewport;
292
+ const effectiveModal = modal || isMobileViewport || isDesktopSidebar && isExpanded;
293
+ const [isResizing, setIsResizing] = useState(false);
294
+ const canExpand = !isMobileViewport && expandable;
295
+ const showExpandedSidebar = isDesktopSidebar && isExpanded && expandedSidebarSlot;
296
+ useEffect(() => {
297
+ const query = window.matchMedia?.("(max-width: 639px)");
298
+ if (!query) return;
299
+ const updateViewport = () => setIsMobileViewport(query.matches);
300
+ updateViewport();
301
+ query.addEventListener?.("change", updateViewport);
302
+ return () => query.removeEventListener?.("change", updateViewport);
303
+ }, []);
304
+ useEffect(() => {
305
+ if (!isResizing) return;
306
+ const panel = panelRef.current;
307
+ if (!panel) return;
308
+ const settle = () => setIsResizing(false);
309
+ const onTransitionEnd = (event) => {
310
+ const { propertyName, target } = event;
311
+ if (target !== panel) return;
312
+ if (propertyName !== "width" && propertyName !== "height") return;
313
+ settle();
314
+ };
315
+ const timer = window.setTimeout(settle, 600);
316
+ panel.addEventListener("transitionend", onTransitionEnd);
317
+ return () => {
318
+ window.clearTimeout(timer);
319
+ panel.removeEventListener("transitionend", onTransitionEnd);
320
+ };
321
+ }, [isResizing]);
322
+ useEffect(() => {
323
+ if (!open) return;
324
+ const panel = panelRef.current;
325
+ if (!panel) return;
326
+ const previous = document.activeElement instanceof HTMLElement ? document.activeElement : null;
327
+ if (!panel.open) {
328
+ if (effectiveModal && typeof panel.showModal === "function") panel.showModal();
329
+ else if (!effectiveModal && typeof panel.show === "function") panel.show();
330
+ else panel.open = true;
331
+ }
332
+ const documentRoot = document.documentElement;
333
+ const scrollX = window.scrollX;
334
+ const scrollY = window.scrollY;
335
+ const previousRootOverflow = documentRoot.style.overflow;
336
+ const previousBodyOverflow = document.body.style.overflow;
337
+ const previousBodyPosition = document.body.style.position;
338
+ const previousBodyTop = document.body.style.top;
339
+ const previousBodyLeft = document.body.style.left;
340
+ const previousBodyRight = document.body.style.right;
341
+ const previousBodyWidth = document.body.style.width;
342
+ if (effectiveModal) {
343
+ documentRoot.style.overflow = "hidden";
344
+ document.body.style.overflow = "hidden";
345
+ document.body.style.position = "fixed";
346
+ document.body.style.top = `${-scrollY}px`;
347
+ document.body.style.left = `${-scrollX}px`;
348
+ document.body.style.right = "0";
349
+ document.body.style.width = "100%";
350
+ }
351
+ const first = panel.querySelector(
352
+ "button,textarea,input,[tabindex]:not([tabindex='-1'])"
353
+ );
354
+ first?.focus();
355
+ const handleKeyDown = (event) => {
356
+ if (!effectiveModal && event.key === "Escape") {
357
+ if (dismissOpenPanelOverlay(panel)) {
358
+ overlayEscapeAt.current = Date.now();
359
+ event.preventDefault();
360
+ event.stopPropagation();
361
+ return;
362
+ }
363
+ event.preventDefault();
364
+ closePanel();
365
+ return;
366
+ }
367
+ if (!effectiveModal || event.key !== "Tab") return;
368
+ const focusable = Array.from(
369
+ panel.querySelectorAll(
370
+ "button:not(:disabled),textarea:not(:disabled),input:not(:disabled),[tabindex]:not([tabindex='-1'])"
371
+ )
372
+ );
373
+ if (focusable.length === 0) return;
374
+ const firstElement = focusable[0];
375
+ const lastElement = focusable[focusable.length - 1];
376
+ const root = panel.getRootNode();
377
+ const activeElement = root instanceof ShadowRoot ? root.activeElement : document.activeElement;
378
+ if (event.shiftKey && activeElement === firstElement) {
379
+ event.preventDefault();
380
+ lastElement.focus();
381
+ } else if (!event.shiftKey && activeElement === lastElement) {
382
+ event.preventDefault();
383
+ firstElement.focus();
384
+ }
385
+ };
386
+ panel.addEventListener("keydown", handleKeyDown);
387
+ return () => {
388
+ panel.removeEventListener("keydown", handleKeyDown);
389
+ if (typeof panel.close === "function") panel.close();
390
+ else panel.open = false;
391
+ documentRoot.style.overflow = previousRootOverflow;
392
+ document.body.style.overflow = previousBodyOverflow;
393
+ document.body.style.position = previousBodyPosition;
394
+ document.body.style.top = previousBodyTop;
395
+ document.body.style.left = previousBodyLeft;
396
+ document.body.style.right = previousBodyRight;
397
+ document.body.style.width = previousBodyWidth;
398
+ if (effectiveModal) window.scrollTo(scrollX, scrollY);
399
+ previous?.focus();
400
+ };
401
+ }, [effectiveModal, open]);
402
+ if (!open) return null;
403
+ return /* @__PURE__ */ jsxs2(
404
+ "dialog",
405
+ {
406
+ ref: panelRef,
407
+ "aria-label": name,
408
+ "aria-modal": effectiveModal,
409
+ className: "ha-panel",
410
+ "data-agent-overlay-root": "",
411
+ "data-expanded": !isMobileViewport && isExpanded ? "true" : void 0,
412
+ "data-expanded-sidebar": showExpandedSidebar ? "true" : void 0,
413
+ "data-resizing": isResizing ? "true" : void 0,
414
+ onCancel: (event) => {
415
+ event.preventDefault();
416
+ if (Date.now() - overlayEscapeAt.current < 350 || dismissOpenPanelOverlay(panelRef.current)) {
417
+ overlayEscapeAt.current = Date.now();
418
+ return;
419
+ }
420
+ onClose();
421
+ },
422
+ children: [
423
+ isDesktopSidebar && !isExpanded ? /* @__PURE__ */ jsx2(SidebarResizeHandle, { panelRef, agentId }) : null,
424
+ showExpandedSidebar ? /* @__PURE__ */ jsx2("aside", { "aria-label": "Chat history", className: "ha-expanded-sidebar", children: expandedSidebarSlot }) : null,
425
+ /* @__PURE__ */ jsxs2("div", { className: "ha-panel-main", children: [
426
+ /* @__PURE__ */ jsxs2("header", { className: "ha-header", children: [
427
+ showExpandedSidebar ? /* @__PURE__ */ jsx2("span", { className: "ha-session-title ha-expanded-chat-title", children: expandedTitle ?? name }) : historySlot ?? /* @__PURE__ */ jsx2("strong", { children: name }),
428
+ /* @__PURE__ */ jsxs2("div", { className: "ha-header-actions", children: [
429
+ showExpandedSidebar ? null : actionsSlot ?? (onNewConversation ? /* @__PURE__ */ jsx2(
430
+ "button",
431
+ {
432
+ "aria-label": "New chat",
433
+ className: "ha-icon-button ha-new-chat-button",
434
+ type: "button",
435
+ onClick: onNewConversation,
436
+ children: /* @__PURE__ */ jsx2(PlusGlyph, {})
437
+ }
438
+ ) : null),
439
+ canExpand ? /* @__PURE__ */ jsx2(
440
+ "button",
441
+ {
442
+ "aria-expanded": isExpanded,
443
+ "aria-label": isExpanded ? "Collapse assistant" : "Expand assistant",
444
+ className: "ha-expand-button ha-icon-button",
445
+ type: "button",
446
+ onClick: () => {
447
+ setIsResizing(true);
448
+ setIsExpanded((expanded) => !expanded);
449
+ },
450
+ children: isExpanded ? /* @__PURE__ */ jsx2(ChevronsCollapseUpRight, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx2(ChevronsExpandUpRight, { "aria-hidden": "true" })
451
+ }
452
+ ) : null,
453
+ /* @__PURE__ */ jsxs2(
454
+ "button",
455
+ {
456
+ "aria-keyshortcuts": "Escape",
457
+ "aria-label": "Close assistant",
458
+ className: "ha-close-button ha-icon-button",
459
+ "data-shortcut": "ESC",
460
+ "data-tooltip": "Close assistant",
461
+ type: "button",
462
+ onClick: onClose,
463
+ children: [
464
+ /* @__PURE__ */ jsx2(CloseGlyph, {}),
465
+ /* @__PURE__ */ jsx2(ComposerControlTooltip, { shortcut: "ESC", children: "Close assistant" })
466
+ ]
467
+ }
468
+ )
469
+ ] })
470
+ ] }),
471
+ children,
472
+ /* @__PURE__ */ jsx2("div", { className: "ha-overlay-portal", "data-agent-overlay-portal": "" })
473
+ ] })
474
+ ]
475
+ }
476
+ );
477
+ }
478
+ function dismissOpenPanelOverlay(panel) {
479
+ const overlay = panel?.querySelector(
480
+ [
481
+ '[data-slot$="-popover"]',
482
+ '[data-slot="agent-ui-image-modal"]',
483
+ '[data-slot="modal-dialog"]',
484
+ ".ha-feedback-popover"
485
+ ].join(",")
486
+ );
487
+ if (!overlay) return false;
488
+ overlay.querySelector('button[aria-label="Dismiss"]')?.click();
489
+ return true;
490
+ }
491
+ function SidebarResizeHandle({
492
+ agentId,
493
+ panelRef
494
+ }) {
495
+ const [width, setWidth] = useState(() => readSidebarWidth(agentId, window.innerWidth));
496
+ const dragRef = useRef(null);
497
+ const applyWidth = useCallback(
498
+ (nextWidth) => {
499
+ const root = panelRef.current?.getRootNode();
500
+ const host = root instanceof ShadowRoot ? root.host : null;
501
+ host?.style.setProperty("--ha-sidebar-width", `${nextWidth}px`);
502
+ if (window.innerWidth >= 640) {
503
+ document.documentElement.style.marginRight = `${Math.min(nextWidth, window.innerWidth)}px`;
504
+ }
505
+ setWidth(nextWidth);
506
+ },
507
+ [panelRef]
508
+ );
509
+ const resizeTo = useCallback(
510
+ (nextWidth, persist) => {
511
+ const clamped = clampSidebarWidth(nextWidth, window.innerWidth);
512
+ applyWidth(clamped);
513
+ if (persist) persistSidebarWidth(agentId, clamped);
514
+ return clamped;
515
+ },
516
+ [applyWidth, agentId]
517
+ );
518
+ return (
519
+ // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions -- A focusable separator is the WAI-ARIA "window splitter" pattern: it is interactive by specification even though jsx-a11y does not model it.
520
+ /* @__PURE__ */ jsx2(
521
+ "div",
522
+ {
523
+ "aria-label": "Resize assistant panel",
524
+ "aria-orientation": "vertical",
525
+ "aria-valuemax": SIDEBAR_MAX_WIDTH,
526
+ "aria-valuemin": SIDEBAR_MIN_WIDTH,
527
+ "aria-valuenow": width,
528
+ className: "ha-resize-handle",
529
+ role: "separator",
530
+ tabIndex: 0,
531
+ onKeyDown: (event) => {
532
+ const delta = event.key === "ArrowLeft" ? 24 : event.key === "ArrowRight" ? -24 : 0;
533
+ if (delta === 0) return;
534
+ event.preventDefault();
535
+ resizeTo(width + delta, true);
536
+ },
537
+ onPointerCancel: (event) => {
538
+ const drag = dragRef.current;
539
+ if (!drag) return;
540
+ dragRef.current = null;
541
+ delete event.currentTarget.dataset["resizing"];
542
+ document.documentElement.style.transition = drag.pageTransition;
543
+ resizeTo(drag.startWidth, false);
544
+ },
545
+ onPointerDown: (event) => {
546
+ if (event.button !== 0 && event.pointerType === "mouse") return;
547
+ event.preventDefault();
548
+ event.currentTarget.setPointerCapture(event.pointerId);
549
+ event.currentTarget.dataset["resizing"] = "true";
550
+ dragRef.current = {
551
+ pageTransition: document.documentElement.style.transition,
552
+ startWidth: width,
553
+ startX: event.clientX
554
+ };
555
+ document.documentElement.style.transition = "none";
556
+ },
557
+ onPointerMove: (event) => {
558
+ const drag = dragRef.current;
559
+ if (!drag) return;
560
+ resizeTo(drag.startWidth + (drag.startX - event.clientX), false);
561
+ },
562
+ onPointerUp: (event) => {
563
+ const drag = dragRef.current;
564
+ if (!drag) return;
565
+ dragRef.current = null;
566
+ delete event.currentTarget.dataset["resizing"];
567
+ event.currentTarget.releasePointerCapture(event.pointerId);
568
+ document.documentElement.style.transition = drag.pageTransition;
569
+ persistSidebarWidth(agentId, width);
570
+ }
571
+ }
572
+ )
573
+ );
574
+ }
575
+ function CloseGlyph() {
576
+ return /* @__PURE__ */ jsx2("svg", { "aria-hidden": "true", fill: "none", height: "18", viewBox: "0 0 18 18", width: "18", children: /* @__PURE__ */ jsx2(
577
+ "path",
578
+ {
579
+ d: "m4.25 4.25 9.5 9.5m0-9.5-9.5 9.5",
580
+ stroke: "currentColor",
581
+ strokeLinecap: "round",
582
+ strokeWidth: "1.6"
583
+ }
584
+ ) });
585
+ }
586
+ function PlusGlyph() {
587
+ return /* @__PURE__ */ jsx2("svg", { "aria-hidden": "true", fill: "none", height: "18", viewBox: "0 0 18 18", width: "18", children: /* @__PURE__ */ jsx2("path", { d: "M9 4v10M4 9h10", stroke: "currentColor", strokeLinecap: "round", strokeWidth: "1.6" }) });
588
+ }
589
+
590
+ // src/embed/composer-textarea.ts
591
+ function getCssPixelValue(value) {
592
+ const parsed = Number.parseFloat(value);
593
+ return Number.isFinite(parsed) ? parsed : 0;
594
+ }
595
+ function getComposerLineHeight(element) {
596
+ const styles = getComputedStyle(element);
597
+ const lineHeight = Number.parseFloat(styles.lineHeight);
598
+ if (Number.isFinite(lineHeight) && lineHeight > 0) return lineHeight;
599
+ const fontSize = Number.parseFloat(styles.fontSize);
600
+ if (Number.isFinite(fontSize) && fontSize > 0) return fontSize * 1.2;
601
+ return 20;
602
+ }
603
+ function getComposerPaddingBlock(element) {
604
+ const styles = getComputedStyle(element);
605
+ return getCssPixelValue(styles.paddingTop) + getCssPixelValue(styles.paddingBottom);
606
+ }
607
+ function measureComposerScrollHeight(element) {
608
+ const previousHeight = element.style.height;
609
+ const previousMinHeight = element.style.minHeight;
610
+ const previousMaxHeight = element.style.maxHeight;
611
+ element.style.height = "0px";
612
+ element.style.minHeight = "0px";
613
+ element.style.maxHeight = "none";
614
+ const scrollHeight = element.scrollHeight;
615
+ element.style.height = previousHeight;
616
+ element.style.minHeight = previousMinHeight;
617
+ element.style.maxHeight = previousMaxHeight;
618
+ return scrollHeight;
619
+ }
620
+ function isComposerTextAreaExpanded(element) {
621
+ if (element.value.includes("\n")) return true;
622
+ if (element.clientWidth === 0) return false;
623
+ const scrollHeight = measureComposerScrollHeight(element);
624
+ const paddingBlock = getComposerPaddingBlock(element);
625
+ const lineHeight = getComposerLineHeight(element);
626
+ const contentHeight = Math.max(0, scrollHeight - paddingBlock);
627
+ return contentHeight > lineHeight * 1.5;
628
+ }
629
+ function resizeComposerTextarea(textarea, {
630
+ hasAttachments = false,
631
+ maxHeight = 120
632
+ } = {}) {
633
+ if (!textarea) return false;
634
+ const hasValue = textarea.value.length > 0;
635
+ const shouldExpand = hasAttachments || hasValue && isComposerTextAreaExpanded(textarea);
636
+ if (!shouldExpand) {
637
+ textarea.style.height = "auto";
638
+ return false;
639
+ }
640
+ textarea.style.height = "auto";
641
+ textarea.style.height = `${Math.min(textarea.scrollHeight, maxHeight)}px`;
642
+ return true;
643
+ }
644
+
645
+ // src/embed/powered-by-hero.tsx
646
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
647
+ var POWERED_BY_HERO_URL = "https://heroui.pro/?utm_source=heroui-agent&utm_medium=referral&utm_campaign=powered-by-hero";
648
+ function PoweredByHero() {
649
+ return /* @__PURE__ */ jsxs3(
650
+ "a",
651
+ {
652
+ "aria-label": "Powered by HeroUI Pro (opens in a new tab)",
653
+ className: "ha-powered-by",
654
+ href: POWERED_BY_HERO_URL,
655
+ rel: "noopener noreferrer",
656
+ target: "_blank",
657
+ children: [
658
+ /* @__PURE__ */ jsx3("span", { children: "Powered by" }),
659
+ /* @__PURE__ */ jsxs3("svg", { "aria-hidden": "true", className: "ha-powered-by-logo", fill: "none", viewBox: "0 0 140 44", children: [
660
+ /* @__PURE__ */ jsx3(
661
+ "path",
662
+ {
663
+ d: "M.678 11.385V24.04c0 .599.307 1.155.813 1.471l8.628 5.396c1.15.719 2.639-.11 2.639-1.47V18.798c0-.612.322-1.18.847-1.491l5.263-3.13v27.267c0 1.355 1.48 2.186 2.63 1.476l8.905-5.497a1.72 1.72 0 0 0 .822-1.476V9.765c0-1.349-1.467-2.18-2.618-1.484l-9.74 5.897V2.556c0-1.345-1.46-2.177-2.61-1.488L1.52 9.897a1.72 1.72 0 0 0-.842 1.488Z",
664
+ fill: "currentColor"
665
+ }
666
+ ),
667
+ /* @__PURE__ */ jsx3(
668
+ "path",
669
+ {
670
+ d: "M63.876 24.071c0-3.59-1.468-5.246-4.405-5.246-3.363 0-5.732 2.255-5.732 7.316v11.595h-6.063V5.528h6.063v11.779c1.468-2.393 3.884-3.59 7.2-3.59 5.637 0 8.953 3.451 8.953 9.25v14.769h-6.016V24.071ZM84.9 38.473c-7.533 0-12.317-4.877-12.317-12.378 0-7.408 4.737-12.378 12.317-12.378 8.195 0 12.648 5.798 11.416 13.942H78.647c.331 3.865 2.605 6.075 6.253 6.075 2.984 0 4.784-1.52 5.258-3.037h6.016c-.947 4.509-5.115 7.776-11.274 7.776ZM78.789 23.657h11.653c-.047-3.175-2.132-5.338-5.685-5.338-3.174 0-5.4 1.84-5.968 5.338ZM99.623 20.344c0-3.82 2.131-5.89 6.205-5.89h7.77v4.97h-7.912v18.312h-6.063V20.344ZM126.863 38.473c-7.674 0-12.553-4.924-12.553-12.378 0-7.454 4.879-12.378 12.553-12.378 7.58 0 12.459 4.924 12.459 12.378 0 7.454-4.88 12.378-12.46 12.378Zm0-5.016c3.79 0 6.3-2.898 6.3-7.362 0-4.463-2.51-7.408-6.3-7.408-3.838 0-6.348 2.945-6.348 7.408 0 4.464 2.51 7.362 6.348 7.362Z",
671
+ fill: "currentColor"
672
+ }
673
+ )
674
+ ] })
675
+ ]
676
+ }
677
+ );
678
+ }
679
+
680
+ // src/embed/shell-handoff.ts
681
+ var handoffs = /* @__PURE__ */ new Map();
682
+ function shellDraftStorageKey(agentId) {
683
+ return `heroui-agent:shell-draft:${agentId}:composer-draft:v1`;
684
+ }
685
+ function writeAgentShellHandoff(agentId, handoff) {
686
+ if (!handoff.prompt.trim() && !handoff.submitted) {
687
+ handoffs.delete(agentId);
688
+ saveAgentComposerPromptDraft(shellDraftStorageKey(agentId), "");
689
+ return;
690
+ }
691
+ handoffs.set(agentId, handoff);
692
+ if (!handoff.submitted) {
693
+ saveAgentComposerPromptDraft(shellDraftStorageKey(agentId), handoff.prompt);
694
+ }
695
+ }
696
+ function readAgentShellHandoff(agentId) {
697
+ const buffered = handoffs.get(agentId);
698
+ if (buffered) return buffered;
699
+ const persisted = readAgentComposerPromptDraft(shellDraftStorageKey(agentId));
700
+ return persisted ? { prompt: persisted, submitted: false } : void 0;
701
+ }
702
+ function takeAgentShellHandoff(agentId) {
703
+ const handoff = readAgentShellHandoff(agentId);
704
+ handoffs.delete(agentId);
705
+ saveAgentComposerPromptDraft(shellDraftStorageKey(agentId), "");
706
+ return handoff;
707
+ }
708
+
709
+ // src/embed/permissions.ts
710
+ var AGENT_PERMISSION_MODES = /* @__PURE__ */ new Set(["ask", "auto", "full"]);
711
+ function resolveAgentPermissionMode(value) {
712
+ return AGENT_PERMISSION_MODES.has(value) ? value : "auto";
713
+ }
714
+ function shouldRestoreActiveAgentPermissionMode(bootstrapStatus, hasUnresolvedClientTool) {
715
+ return hasUnresolvedClientTool || bootstrapStatus === "pending" || bootstrapStatus === "streaming";
716
+ }
717
+ function agentPermissionModeStorageKey(conversationStorageKey, conversationId) {
718
+ return `${conversationStorageKey}:permission-mode:${conversationId}:v1`;
719
+ }
720
+ function agentActivePermissionModeStorageKey(conversationStorageKey, conversationId) {
721
+ return `${conversationStorageKey}:active-permission-mode:${conversationId}:v1`;
722
+ }
723
+ function readStoredAgentPermissionMode(key) {
724
+ try {
725
+ const stored = localStorage.getItem(key);
726
+ return stored !== null && AGENT_PERMISSION_MODES.has(stored) ? resolveAgentPermissionMode(stored) : void 0;
727
+ } catch {
728
+ return void 0;
729
+ }
730
+ }
731
+ function storeAgentPermissionMode(key, mode) {
732
+ try {
733
+ localStorage.setItem(key, mode);
734
+ } catch {
735
+ }
736
+ }
737
+ function clearStoredAgentPermissionMode(key) {
738
+ try {
739
+ localStorage.removeItem(key);
740
+ } catch {
741
+ }
742
+ }
743
+ function applyAgentPermissionMode(tools, mode) {
744
+ const resolvedMode = resolveAgentPermissionMode(mode);
745
+ if (resolvedMode === "auto") return tools;
746
+ const needsApproval = resolvedMode === "ask";
747
+ return tools.map(
748
+ (tool) => Boolean(tool.needsApproval) === needsApproval ? tool : { ...tool, needsApproval }
749
+ );
750
+ }
751
+
752
+ // src/embed/theme.ts
753
+ var AGENT_DESIGN_THEMES = [
754
+ "base",
755
+ "brutalism",
756
+ "glass",
757
+ "mouve"
758
+ ];
759
+ function resolveAgentDesignTheme(value) {
760
+ return AGENT_DESIGN_THEMES.includes(value) ? value : "base";
761
+ }
762
+ var COLOR_VARIABLES = {
763
+ accent: "accent",
764
+ background: "background",
765
+ foreground: "foreground",
766
+ overlay: "overlay",
767
+ surface: "surface",
768
+ surfaceSecondary: "surface-secondary",
769
+ tooltip: "tooltip"
770
+ };
771
+ var ACCENT_FOREGROUND_CSS = "oklch(from var(--ha-accent) clamp(0, (0.7 - l) * 1000, 1) 0 h)";
772
+ var LAUNCHER_FOREGROUND_CSS = "oklch(from var(--ha-launcher-bg) clamp(0, (0.7 - l) * 1000, 1) 0 h)";
773
+ function buildLauncherStyle(background) {
774
+ const style = {};
775
+ const light = schemeValue(background, "light");
776
+ const dark = schemeValue(background, "dark");
777
+ if (light) {
778
+ style["--ha-theme-launcher-background-light"] = light;
779
+ style["--ha-theme-launcher-foreground-light"] = LAUNCHER_FOREGROUND_CSS;
780
+ }
781
+ if (dark) {
782
+ style["--ha-theme-launcher-background-dark"] = dark;
783
+ style["--ha-theme-launcher-foreground-dark"] = LAUNCHER_FOREGROUND_CSS;
784
+ }
785
+ return style;
786
+ }
787
+ var SURFACE_TERTIARY_LIGHT_CSS = "oklch(from var(--ha-card-secondary) calc(l - 0.0151) c h)";
788
+ var SURFACE_TERTIARY_DARK_CSS = "oklch(from var(--ha-card-secondary) calc(l + 0.017) c h)";
789
+ var RADIUS_VALUES = {
790
+ pill: "0.875rem",
791
+ round: "0.5rem",
792
+ sharp: "0.125rem",
793
+ soft: "0.375rem"
794
+ };
795
+ var MIN_FONT_SIZE = 12;
796
+ var MAX_FONT_SIZE = 18;
797
+ function safeCssValue(value) {
798
+ const trimmed = value?.trim();
799
+ if (!trimmed || trimmed.length > 256 || /[;{}]/.test(trimmed)) return void 0;
800
+ return trimmed;
801
+ }
802
+ function schemeValue(color, scheme) {
803
+ if (color === void 0) return void 0;
804
+ return safeCssValue(typeof color === "string" ? color : color[scheme]);
805
+ }
806
+ function buildThemeStyle(theme) {
807
+ if (!theme) return {};
808
+ const style = {};
809
+ if (theme.radius && theme.radius in RADIUS_VALUES) {
810
+ style["--radius"] = RADIUS_VALUES[theme.radius];
811
+ }
812
+ const fontFamily = safeCssValue(theme.typography?.fontFamily);
813
+ if (fontFamily) style["--ha-font-family"] = fontFamily;
814
+ const baseSize = theme.typography?.baseSize;
815
+ if (typeof baseSize === "number" && Number.isFinite(baseSize)) {
816
+ const size = Math.min(Math.max(Math.round(baseSize), MIN_FONT_SIZE), MAX_FONT_SIZE);
817
+ style["--ha-font-size"] = `${size}px`;
818
+ }
819
+ for (const [token, variableName] of Object.entries(COLOR_VARIABLES)) {
820
+ const color = theme.colors?.[token];
821
+ const light = schemeValue(color, "light");
822
+ const darkValue = schemeValue(color, "dark");
823
+ if (light) style[`--ha-theme-${variableName}-light`] = light;
824
+ if (darkValue) style[`--ha-theme-${variableName}-dark`] = darkValue;
825
+ }
826
+ if (schemeValue(theme.colors?.accent, "light")) {
827
+ style["--ha-theme-accent-foreground-light"] = ACCENT_FOREGROUND_CSS;
828
+ }
829
+ if (schemeValue(theme.colors?.accent, "dark")) {
830
+ style["--ha-theme-accent-foreground-dark"] = ACCENT_FOREGROUND_CSS;
831
+ }
832
+ if (schemeValue(theme.colors?.surfaceSecondary, "light")) {
833
+ style["--ha-theme-surface-tertiary-light"] = SURFACE_TERTIARY_LIGHT_CSS;
834
+ }
835
+ if (schemeValue(theme.colors?.surfaceSecondary, "dark")) {
836
+ style["--ha-theme-surface-tertiary-dark"] = SURFACE_TERTIARY_DARK_CSS;
837
+ }
838
+ return style;
839
+ }
840
+
841
+ // src/contracts/models.ts
842
+ var AGENT_MODEL_IDS = [
843
+ "moonshotai/Kimi-K3",
844
+ "openai/gpt-5.6-luna",
845
+ "openai/gpt-5.6-terra",
846
+ "openai/gpt-5.6-sol",
847
+ "google/gemini-3.6-flash",
848
+ "anthropic/claude-sonnet-5",
849
+ "anthropic/claude-opus-4.8"
850
+ ];
851
+ var LEGACY_AGENT_MODEL_IDS = {
852
+ "google/gemini-3.5-flash": "google/gemini-3.6-flash"
853
+ };
854
+ function resolveAgentModelId(value) {
855
+ return LEGACY_AGENT_MODEL_IDS[value] ?? value;
856
+ }
857
+ var DEFAULT_AGENT_PICKER_MODEL_ID = "openai/gpt-5.6-luna";
858
+ var AGENT_MODEL_OPTIONS = [
859
+ {
860
+ description: "Flagship model for coding, reasoning, and knowledge work",
861
+ id: "moonshotai/Kimi-K3",
862
+ label: "Kimi K3",
863
+ provider: "Moonshot AI",
864
+ tier: "light"
865
+ },
866
+ {
867
+ description: "Fast answers and lightweight agent workflows",
868
+ id: "openai/gpt-5.6-luna",
869
+ label: "GPT-5.6 Luna",
870
+ provider: "OpenAI",
871
+ tier: "light"
872
+ },
873
+ {
874
+ description: "Balanced reasoning for everyday agent tasks",
875
+ id: "openai/gpt-5.6-terra",
876
+ label: "GPT-5.6 Terra",
877
+ provider: "OpenAI",
878
+ tier: "codegen"
879
+ },
880
+ {
881
+ description: "Deep reasoning for complex, multi-step analysis",
882
+ id: "openai/gpt-5.6-sol",
883
+ label: "GPT-5.6 Sol",
884
+ provider: "OpenAI",
885
+ tier: "complex"
886
+ },
887
+ {
888
+ description: "Fast multimodal analysis with a large context window",
889
+ id: "google/gemini-3.6-flash",
890
+ label: "Gemini 3.6 Flash",
891
+ provider: "Google",
892
+ tier: "light"
893
+ },
894
+ {
895
+ description: "Strong agentic reasoning and polished UI decisions",
896
+ id: "anthropic/claude-sonnet-5",
897
+ label: "Claude Sonnet 5",
898
+ provider: "Anthropic",
899
+ tier: "codegen"
900
+ },
901
+ {
902
+ description: "Highest-capability Claude for difficult research and analysis",
903
+ id: "anthropic/claude-opus-4.8",
904
+ label: "Claude Opus 4.8",
905
+ provider: "Anthropic",
906
+ tier: "complex"
907
+ }
908
+ ];
909
+ var AGENT_MODEL_ID_SET = new Set(AGENT_MODEL_IDS);
910
+ function isAgentModelId(value) {
911
+ return typeof value === "string" && AGENT_MODEL_ID_SET.has(value);
912
+ }
913
+ function getAgentModelTier(modelId) {
914
+ const resolved = modelId ? resolveAgentModelId(modelId) : void 0;
915
+ return AGENT_MODEL_OPTIONS.find((option) => option.id === resolved)?.tier ?? "light";
916
+ }
917
+
918
+ // src/contracts/attachments.ts
919
+ var HEROUI_AGENT_MAX_ATTACHMENTS = 5;
920
+ var HEROUI_AGENT_ATTACHMENT_MAX_BYTES = 10 * 1024 * 1024;
921
+ var HEROUI_AGENT_ATTACHMENT_EXTENSION_BY_CONTENT_TYPE = {
922
+ "application/json": "json",
923
+ "application/pdf": "pdf",
924
+ "image/gif": "gif",
925
+ "image/jpeg": "jpg",
926
+ "image/png": "png",
927
+ "image/webp": "webp",
928
+ "text/csv": "csv",
929
+ "text/markdown": "md",
930
+ "text/plain": "txt",
931
+ "text/tab-separated-values": "tsv"
932
+ };
933
+ var HEROUI_AGENT_ATTACHMENT_CONTENT_TYPES = Object.freeze(
934
+ Object.keys(
935
+ HEROUI_AGENT_ATTACHMENT_EXTENSION_BY_CONTENT_TYPE
936
+ )
937
+ );
938
+ var HEROUI_AGENT_ATTACHMENT_ACCEPT = HEROUI_AGENT_ATTACHMENT_CONTENT_TYPES.join(",");
939
+ var HEROUI_AGENT_ATTACHMENT_CONTENT_TYPE_SET = new Set(
940
+ HEROUI_AGENT_ATTACHMENT_CONTENT_TYPES
941
+ );
942
+ function isHeroUIAgentAttachmentContentType(value) {
943
+ return HEROUI_AGENT_ATTACHMENT_CONTENT_TYPE_SET.has(value.trim().toLowerCase());
944
+ }
945
+
946
+ // src/embed/types.ts
947
+ var DEFAULT_MARKDOWN_ANIMATION = {
948
+ animation: "blurIn",
949
+ duration: 160,
950
+ easing: "ease-out",
951
+ sep: "word",
952
+ stagger: 18
953
+ };
954
+ function panelLength(value) {
955
+ if (typeof value === "number")
956
+ return Number.isFinite(value) ? `${Math.round(value)}px` : void 0;
957
+ return value?.trim() || void 0;
958
+ }
959
+ function buildPanelStyle(panel) {
960
+ const width = panelLength(panel?.initialWidth);
961
+ const height = panelLength(panel?.initialHeight);
962
+ return {
963
+ ...width ? { "--ha-panel-width": width } : {},
964
+ ...height ? { "--ha-panel-height": height } : {}
965
+ };
966
+ }
967
+ function clampLauncherOffset(value) {
968
+ if (value === void 0 || !Number.isFinite(value)) return 24;
969
+ return Math.min(Math.max(Math.round(value), 0), 200);
970
+ }
971
+ function resolveComposerAttachmentContentTypes(value) {
972
+ if (value === void 0) return [...HEROUI_AGENT_ATTACHMENT_CONTENT_TYPES];
973
+ if (value === false || !Array.isArray(value)) return [];
974
+ const contentTypes = /* @__PURE__ */ new Set();
975
+ for (const item of value) {
976
+ if (typeof item !== "string") continue;
977
+ const contentType = item.trim().toLowerCase();
978
+ if (isHeroUIAgentAttachmentContentType(contentType)) contentTypes.add(contentType);
979
+ }
980
+ return [...contentTypes];
981
+ }
982
+ function resolveOptions(props) {
983
+ if (!props.agentId.trim()) throw new Error("HeroUI Agent agentId is required");
984
+ if (typeof props.getAuthToken !== "function") {
985
+ throw new Error("HeroUI Agent getAuthToken is required");
986
+ }
987
+ const composerAttachmentContentTypes = resolveComposerAttachmentContentTypes(
988
+ props.composer?.attachments
989
+ );
990
+ return {
991
+ apiBaseUrl: (props._api?.baseUrl ?? "https://api.heroui.com").replace(/\/$/, ""),
992
+ colorScheme: props.appearance?.theme?.colorScheme ?? "system",
993
+ componentExportFormats: props.componentExports === false ? [] : props.componentExports ?? ["csv", "svg", "png"],
994
+ composerAttachmentAccept: composerAttachmentContentTypes.join(","),
995
+ composerAttachmentContentTypes,
996
+ composerDefaultModel: props.composer?.defaultModel,
997
+ composerDictation: props.composer?.dictation ?? true,
998
+ designTheme: resolveAgentDesignTheme(props.appearance?.theme?.designTheme),
999
+ ...typeof props.composer?.disclaimer === "string" && props.composer.disclaimer.trim() ? { composerDisclaimer: props.composer.disclaimer.trim().slice(0, 240) } : {},
1000
+ agentId: props.agentId,
1001
+ composerModelPicker: props.composer?.modelPicker ?? false,
1002
+ composerPlaceholder: props.composer?.placeholder?.trim().slice(0, 120) || "Ask anything\u2026",
1003
+ context: props.context,
1004
+ getAuthToken: props.getAuthToken,
1005
+ greeting: props.startScreen?.greeting?.trim().slice(0, 120) || "Ask about your data",
1006
+ launcherPosition: props.appearance?.launcher?.position ?? "bottom-right",
1007
+ markdownAnimation: props.markdown?.animated ?? DEFAULT_MARKDOWN_ANIMATION,
1008
+ markdownCaret: props.markdown?.caret ?? "block",
1009
+ markdownPlugins: props.markdown?.plugins,
1010
+ messageActions: props.responseActions === false ? [] : props.responseActions ?? ["copy", "feedback", "retry"],
1011
+ onFeedback: props.onFeedback,
1012
+ panelExpandable: props.appearance?.panel?.expandable ?? true,
1013
+ panelExpanded: props.appearance?.panel?.expanded ?? false,
1014
+ panelStyle: buildPanelStyle(props.appearance?.panel),
1015
+ permissionDefaultMode: resolveAgentPermissionMode(props.permissions?.defaultMode),
1016
+ permissionShowPicker: props.permissions?.showPicker === true,
1017
+ preload: props.preload ?? true,
1018
+ showLauncher: props.showLauncher ?? true,
1019
+ suggestedPromptShortcuts: props.startScreen?.promptShortcuts ?? false,
1020
+ ...props.appearance?.launcher?.icon?.trim() ? { launcherIcon: props.appearance.launcher.icon.trim() } : {},
1021
+ ...props.appearance?.launcher?.style ? { launcherStyle: props.appearance.launcher.style } : {},
1022
+ ...props.appearance?.launcher?.offset ? {
1023
+ launcherOffset: {
1024
+ x: clampLauncherOffset(props.appearance.launcher.offset.x),
1025
+ y: clampLauncherOffset(props.appearance.launcher.offset.y)
1026
+ }
1027
+ } : {},
1028
+ imageSearch: (props.capabilities?.webSearch ?? false) && (props.capabilities?.imageSearch ?? true),
1029
+ suggestedPrompts: props.startScreen?.prompts?.map((prompt) => prompt.trim()).filter(Boolean).slice(0, 5),
1030
+ themeStyle: {
1031
+ ...buildThemeStyle(props.appearance?.theme),
1032
+ ...buildLauncherStyle(props.appearance?.launcher?.background)
1033
+ },
1034
+ tools: props.tools ?? [],
1035
+ viewMode: props.appearance?.viewMode ?? "floating",
1036
+ webSearch: props.capabilities?.webSearch ?? false,
1037
+ ...props._api?.realtimeUrl ? { triggerApiUrl: props._api.realtimeUrl.replace(/\/$/, "") } : {}
1038
+ };
1039
+ }
1040
+
1041
+ export {
1042
+ createToolHelper,
1043
+ isZodSchema,
1044
+ parseClientToolArgs,
1045
+ resolveDirectToolAction,
1046
+ agentComposerDraftStorageKey,
1047
+ readAgentComposerPromptDraft,
1048
+ saveAgentComposerPromptDraft,
1049
+ readAgentComposerImageDraft,
1050
+ saveAgentComposerImageDraft,
1051
+ clearAgentComposerDraft,
1052
+ clearAgentComposerDraftsForProject,
1053
+ scheduleIdleTask,
1054
+ ComposerControlTooltip,
1055
+ readSidebarWidth,
1056
+ PanelShell,
1057
+ HEROUI_AGENT_MAX_ATTACHMENTS,
1058
+ HEROUI_AGENT_ATTACHMENT_MAX_BYTES,
1059
+ HEROUI_AGENT_ATTACHMENT_EXTENSION_BY_CONTENT_TYPE,
1060
+ HEROUI_AGENT_ATTACHMENT_CONTENT_TYPES,
1061
+ isHeroUIAgentAttachmentContentType,
1062
+ resizeComposerTextarea,
1063
+ PoweredByHero,
1064
+ writeAgentShellHandoff,
1065
+ readAgentShellHandoff,
1066
+ takeAgentShellHandoff,
1067
+ shouldRestoreActiveAgentPermissionMode,
1068
+ agentPermissionModeStorageKey,
1069
+ agentActivePermissionModeStorageKey,
1070
+ readStoredAgentPermissionMode,
1071
+ storeAgentPermissionMode,
1072
+ clearStoredAgentPermissionMode,
1073
+ applyAgentPermissionMode,
1074
+ AGENT_DESIGN_THEMES,
1075
+ DEFAULT_MARKDOWN_ANIMATION,
1076
+ resolveOptions,
1077
+ AGENT_MODEL_IDS,
1078
+ LEGACY_AGENT_MODEL_IDS,
1079
+ resolveAgentModelId,
1080
+ DEFAULT_AGENT_PICKER_MODEL_ID,
1081
+ AGENT_MODEL_OPTIONS,
1082
+ isAgentModelId,
1083
+ getAgentModelTier
1084
+ };