@heroui/agent 0.2.0-beta.7 → 0.2.0-beta.8

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.
@@ -18,218 +18,27 @@ function resolveDirectToolAction(tools, toolName) {
18
18
  return tool;
19
19
  }
20
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);
21
+ // src/embed/agent-loading-state.tsx
22
+ import { jsx, jsxs } from "react/jsx-runtime";
23
+ function AgentLoadingState({
24
+ indicator,
25
+ label = "Loading agent\u2026"
26
+ }) {
27
+ return /* @__PURE__ */ jsxs("div", { "aria-live": "polite", className: "ha-agent-loading", role: "status", children: [
28
+ indicator,
29
+ /* @__PURE__ */ jsx("span", { children: label })
30
+ ] });
222
31
  }
223
32
 
224
33
  // src/embed/composer-control-tooltip.tsx
225
- import { jsx, jsxs } from "react/jsx-runtime";
34
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
226
35
  function ComposerControlTooltip({
227
36
  children,
228
37
  shortcut
229
38
  }) {
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
39
+ return /* @__PURE__ */ jsxs2("span", { "aria-hidden": "true", className: "ha-control-tooltip", children: [
40
+ /* @__PURE__ */ jsx2("span", { children }),
41
+ shortcut ? /* @__PURE__ */ jsx2("kbd", { className: "ha-control-tooltip__shortcut", children: shortcut }) : null
233
42
  ] });
234
43
  }
235
44
 
@@ -265,7 +74,7 @@ function persistSidebarWidth(agentId, width) {
265
74
  }
266
75
 
267
76
  // src/embed/panel-shell.tsx
268
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
77
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
269
78
  function PanelShell({
270
79
  actionsSlot,
271
80
  agentId,
@@ -275,6 +84,7 @@ function PanelShell({
275
84
  expandedSidebarSlot,
276
85
  expandedTitle,
277
86
  historySlot,
87
+ keepMounted = false,
278
88
  modal,
279
89
  name,
280
90
  onClose,
@@ -351,7 +161,7 @@ function PanelShell({
351
161
  const first = panel.querySelector(
352
162
  "button,textarea,input,[tabindex]:not([tabindex='-1'])"
353
163
  );
354
- first?.focus();
164
+ if (!panel.contains(document.activeElement)) first?.focus();
355
165
  const handleKeyDown = (event) => {
356
166
  if (!effectiveModal && event.key === "Escape") {
357
167
  if (dismissOpenPanelOverlay(panel)) {
@@ -396,11 +206,11 @@ function PanelShell({
396
206
  document.body.style.right = previousBodyRight;
397
207
  document.body.style.width = previousBodyWidth;
398
208
  if (effectiveModal) window.scrollTo(scrollX, scrollY);
399
- previous?.focus();
209
+ if (document.activeElement === document.body) previous?.focus();
400
210
  };
401
211
  }, [effectiveModal, open]);
402
- if (!open) return null;
403
- return /* @__PURE__ */ jsxs2(
212
+ if (!open && !keepMounted) return null;
213
+ return /* @__PURE__ */ jsxs3(
404
214
  "dialog",
405
215
  {
406
216
  ref: panelRef,
@@ -411,6 +221,7 @@ function PanelShell({
411
221
  "data-expanded": !isMobileViewport && isExpanded ? "true" : void 0,
412
222
  "data-expanded-sidebar": showExpandedSidebar ? "true" : void 0,
413
223
  "data-resizing": isResizing ? "true" : void 0,
224
+ hidden: !open,
414
225
  onCancel: (event) => {
415
226
  event.preventDefault();
416
227
  if (Date.now() - overlayEscapeAt.current < 350 || dismissOpenPanelOverlay(panelRef.current)) {
@@ -420,23 +231,23 @@ function PanelShell({
420
231
  onClose();
421
232
  },
422
233
  children: [
423
- isDesktopSidebar && !isExpanded ? /* @__PURE__ */ jsx2(SidebarResizeHandle, { agentId, panelRef }) : 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(
234
+ isDesktopSidebar && !isExpanded ? /* @__PURE__ */ jsx3(SidebarResizeHandle, { agentId, panelRef }) : null,
235
+ showExpandedSidebar ? /* @__PURE__ */ jsx3("aside", { "aria-label": "Chat history", className: "ha-expanded-sidebar", children: expandedSidebarSlot }) : null,
236
+ /* @__PURE__ */ jsxs3("div", { className: "ha-panel-main", children: [
237
+ /* @__PURE__ */ jsxs3("header", { className: "ha-header", children: [
238
+ showExpandedSidebar ? /* @__PURE__ */ jsx3("span", { className: "ha-session-title ha-expanded-chat-title", children: expandedTitle ?? name }) : historySlot ?? /* @__PURE__ */ jsx3("strong", { children: name }),
239
+ /* @__PURE__ */ jsxs3("div", { className: "ha-header-actions", children: [
240
+ showExpandedSidebar ? null : actionsSlot ?? (onNewConversation ? /* @__PURE__ */ jsx3(
430
241
  "button",
431
242
  {
432
243
  "aria-label": "New chat",
433
244
  className: "ha-icon-button ha-new-chat-button",
434
245
  type: "button",
435
246
  onClick: onNewConversation,
436
- children: /* @__PURE__ */ jsx2(PlusGlyph, {})
247
+ children: /* @__PURE__ */ jsx3(PlusGlyph, {})
437
248
  }
438
249
  ) : null),
439
- canExpand ? /* @__PURE__ */ jsx2(
250
+ canExpand ? /* @__PURE__ */ jsx3(
440
251
  "button",
441
252
  {
442
253
  "aria-expanded": isExpanded,
@@ -447,10 +258,10 @@ function PanelShell({
447
258
  setIsResizing(true);
448
259
  setIsExpanded((expanded) => !expanded);
449
260
  },
450
- children: isExpanded ? /* @__PURE__ */ jsx2(ChevronsCollapseUpRight, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx2(ChevronsExpandUpRight, { "aria-hidden": "true" })
261
+ children: isExpanded ? /* @__PURE__ */ jsx3(ChevronsCollapseUpRight, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx3(ChevronsExpandUpRight, { "aria-hidden": "true" })
451
262
  }
452
263
  ) : null,
453
- /* @__PURE__ */ jsxs2(
264
+ /* @__PURE__ */ jsxs3(
454
265
  "button",
455
266
  {
456
267
  "aria-keyshortcuts": "Escape",
@@ -461,15 +272,15 @@ function PanelShell({
461
272
  type: "button",
462
273
  onClick: onClose,
463
274
  children: [
464
- /* @__PURE__ */ jsx2(CloseGlyph, {}),
465
- /* @__PURE__ */ jsx2(ComposerControlTooltip, { shortcut: "ESC", children: "Close assistant" })
275
+ /* @__PURE__ */ jsx3(CloseGlyph, {}),
276
+ /* @__PURE__ */ jsx3(ComposerControlTooltip, { shortcut: "ESC", children: "Close assistant" })
466
277
  ]
467
278
  }
468
279
  )
469
280
  ] })
470
281
  ] }),
471
282
  children,
472
- /* @__PURE__ */ jsx2("div", { className: "ha-overlay-portal", "data-agent-overlay-portal": "" })
283
+ /* @__PURE__ */ jsx3("div", { className: "ha-overlay-portal", "data-agent-overlay-portal": "" })
473
284
  ] })
474
285
  ]
475
286
  }
@@ -518,7 +329,7 @@ function SidebarResizeHandle({
518
329
  );
519
330
  return (
520
331
  // 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.
521
- /* @__PURE__ */ jsx2(
332
+ /* @__PURE__ */ jsx3(
522
333
  "div",
523
334
  {
524
335
  "aria-label": "Resize assistant panel",
@@ -578,7 +389,7 @@ function SidebarResizeHandle({
578
389
  );
579
390
  }
580
391
  function CloseGlyph() {
581
- return /* @__PURE__ */ jsx2("svg", { "aria-hidden": "true", fill: "none", height: "18", viewBox: "0 0 18 18", width: "18", children: /* @__PURE__ */ jsx2(
392
+ return /* @__PURE__ */ jsx3("svg", { "aria-hidden": "true", fill: "none", height: "18", viewBox: "0 0 18 18", width: "18", children: /* @__PURE__ */ jsx3(
582
393
  "path",
583
394
  {
584
395
  d: "m4.25 4.25 9.5 9.5m0-9.5-9.5 9.5",
@@ -589,7 +400,192 @@ function CloseGlyph() {
589
400
  ) });
590
401
  }
591
402
  function PlusGlyph() {
592
- 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" }) });
403
+ return /* @__PURE__ */ jsx3("svg", { "aria-hidden": "true", fill: "none", height: "18", viewBox: "0 0 18 18", width: "18", children: /* @__PURE__ */ jsx3("path", { d: "M9 4v10M4 9h10", stroke: "currentColor", strokeLinecap: "round", strokeWidth: "1.6" }) });
404
+ }
405
+
406
+ // src/contracts/models.ts
407
+ var AGENT_MODEL_IDS = [
408
+ "moonshotai/Kimi-K3",
409
+ "openai/gpt-5.6-luna",
410
+ "openai/gpt-5.6-terra",
411
+ "openai/gpt-5.6-sol",
412
+ "google/gemini-3.6-flash",
413
+ "anthropic/claude-sonnet-5",
414
+ "anthropic/claude-opus-4.8"
415
+ ];
416
+ var LEGACY_AGENT_MODEL_IDS = {
417
+ "google/gemini-3.5-flash": "google/gemini-3.6-flash"
418
+ };
419
+ function resolveAgentModelId(value) {
420
+ return LEGACY_AGENT_MODEL_IDS[value] ?? value;
421
+ }
422
+ var DEFAULT_AGENT_PICKER_MODEL_ID = "openai/gpt-5.6-luna";
423
+ var AGENT_MODEL_OPTIONS = [
424
+ {
425
+ description: "Flagship model for coding, reasoning, and knowledge work",
426
+ id: "moonshotai/Kimi-K3",
427
+ label: "Kimi K3",
428
+ provider: "Moonshot AI",
429
+ tier: "light"
430
+ },
431
+ {
432
+ description: "Fast answers and lightweight agent workflows",
433
+ id: "openai/gpt-5.6-luna",
434
+ label: "GPT-5.6 Luna",
435
+ provider: "OpenAI",
436
+ tier: "light"
437
+ },
438
+ {
439
+ description: "Balanced reasoning for everyday agent tasks",
440
+ id: "openai/gpt-5.6-terra",
441
+ label: "GPT-5.6 Terra",
442
+ provider: "OpenAI",
443
+ tier: "codegen"
444
+ },
445
+ {
446
+ description: "Deep reasoning for complex, multi-step analysis",
447
+ id: "openai/gpt-5.6-sol",
448
+ label: "GPT-5.6 Sol",
449
+ provider: "OpenAI",
450
+ tier: "complex"
451
+ },
452
+ {
453
+ description: "Fast multimodal analysis with a large context window",
454
+ id: "google/gemini-3.6-flash",
455
+ label: "Gemini 3.6 Flash",
456
+ provider: "Google",
457
+ tier: "light"
458
+ },
459
+ {
460
+ description: "Strong agentic reasoning and polished UI decisions",
461
+ id: "anthropic/claude-sonnet-5",
462
+ label: "Claude Sonnet 5",
463
+ provider: "Anthropic",
464
+ tier: "codegen"
465
+ },
466
+ {
467
+ description: "Highest-capability Claude for difficult research and analysis",
468
+ id: "anthropic/claude-opus-4.8",
469
+ label: "Claude Opus 4.8",
470
+ provider: "Anthropic",
471
+ tier: "complex"
472
+ }
473
+ ];
474
+ var AGENT_MODEL_ID_SET = new Set(AGENT_MODEL_IDS);
475
+ function isAgentModelId(value) {
476
+ return typeof value === "string" && AGENT_MODEL_ID_SET.has(value);
477
+ }
478
+ function getAgentModelTier(modelId) {
479
+ const resolved = modelId ? resolveAgentModelId(modelId) : void 0;
480
+ return AGENT_MODEL_OPTIONS.find((option) => option.id === resolved)?.tier ?? "light";
481
+ }
482
+
483
+ // src/embed/shell-handoff.ts
484
+ function createSubmittedAgentShellHandoff(prompt) {
485
+ const startedAt = performance.now();
486
+ const startedAtWallClock = Date.now();
487
+ const trimmedPrompt = prompt.trim();
488
+ if (!trimmedPrompt) return null;
489
+ return {
490
+ messageId: crypto.randomUUID(),
491
+ prompt: trimmedPrompt,
492
+ startedAt,
493
+ startedAtWallClock,
494
+ submitted: true
495
+ };
496
+ }
497
+ var handoffs = /* @__PURE__ */ new Map();
498
+ var attachmentHandoffs = /* @__PURE__ */ new Map();
499
+ var SHELL_DRAFT_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
500
+ var focus = /* @__PURE__ */ new Map();
501
+ function shellDraftStorageKey(agentId) {
502
+ return `heroui-agent:shell-draft:${agentId}:composer-draft:v1`;
503
+ }
504
+ function saveShellDraft(agentId, prompt) {
505
+ try {
506
+ const key = shellDraftStorageKey(agentId);
507
+ if (prompt.trim()) localStorage.setItem(key, JSON.stringify({ prompt, savedAt: Date.now() }));
508
+ else localStorage.removeItem(key);
509
+ } catch {
510
+ }
511
+ }
512
+ function readShellDraft(agentId) {
513
+ const key = shellDraftStorageKey(agentId);
514
+ try {
515
+ const draft = JSON.parse(localStorage.getItem(key) ?? "null");
516
+ if (draft && typeof draft.prompt === "string" && draft.prompt.trim() && typeof draft.savedAt === "number" && Date.now() - draft.savedAt <= SHELL_DRAFT_MAX_AGE_MS) {
517
+ return draft.prompt;
518
+ }
519
+ localStorage.removeItem(key);
520
+ } catch {
521
+ }
522
+ return "";
523
+ }
524
+ function writeAgentShellHandoff(agentId, handoff) {
525
+ if (!handoff.prompt.trim() && !handoff.submitted) {
526
+ handoffs.delete(agentId);
527
+ saveShellDraft(agentId, "");
528
+ return;
529
+ }
530
+ handoffs.set(agentId, handoff);
531
+ if (!handoff.submitted) {
532
+ saveShellDraft(agentId, handoff.prompt);
533
+ }
534
+ }
535
+ function readAgentShellHandoff(agentId) {
536
+ const buffered = handoffs.get(agentId);
537
+ if (buffered) return buffered;
538
+ const persisted = readShellDraft(agentId);
539
+ return persisted ? { prompt: persisted, submitted: false } : void 0;
540
+ }
541
+ function markAgentShellFeedbackPainted(agentId, messageId, paintedAt) {
542
+ const handoff = handoffs.get(agentId);
543
+ if (!handoff?.submitted || handoff.messageId !== messageId || handoff.firstFeedbackPaintedAt !== void 0) {
544
+ return;
545
+ }
546
+ handoffs.set(agentId, { ...handoff, firstFeedbackPaintedAt: paintedAt });
547
+ }
548
+ function takeAgentShellHandoff(agentId) {
549
+ const handoff = readAgentShellHandoff(agentId);
550
+ handoffs.delete(agentId);
551
+ saveShellDraft(agentId, "");
552
+ return handoff;
553
+ }
554
+ function setFocus(agentId, focused, textarea) {
555
+ if (focused) {
556
+ focus.set(agentId, [
557
+ textarea?.selectionStart ?? 0,
558
+ textarea?.selectionEnd ?? 0,
559
+ textarea?.selectionDirection ?? "none"
560
+ ]);
561
+ } else {
562
+ focus.delete(agentId);
563
+ }
564
+ }
565
+ function restoreFocus(agentId, textarea) {
566
+ const selection = focus.get(agentId);
567
+ if (!selection || !textarea) return;
568
+ textarea.focus({ preventScroll: true });
569
+ const start = Math.min(selection[0], textarea.value.length);
570
+ const end = Math.min(selection[1], textarea.value.length);
571
+ textarea.setSelectionRange(start, end, selection[2]);
572
+ focus.set(agentId, [start, end, selection[2]]);
573
+ }
574
+ function containsComposerFocus(composer, target) {
575
+ if (!(target instanceof Node)) return false;
576
+ return composer.contains(target) || composer.closest(".ha-composer-wrap")?.querySelector(".ha-footnote")?.contains(target) === true || composer.closest(".ha-root")?.querySelector(".ha-overlay-portal")?.contains(target) === true;
577
+ }
578
+ function writeAgentShellAttachments(agentId, files) {
579
+ if (files.length === 0) attachmentHandoffs.delete(agentId);
580
+ else attachmentHandoffs.set(agentId, files);
581
+ }
582
+ function readAgentShellAttachments(agentId) {
583
+ return attachmentHandoffs.get(agentId) ?? [];
584
+ }
585
+ function takeAgentShellAttachments(agentId) {
586
+ const files = readAgentShellAttachments(agentId);
587
+ attachmentHandoffs.delete(agentId);
588
+ return files;
593
589
  }
594
590
 
595
591
  // src/embed/composer-textarea.ts
@@ -648,10 +644,10 @@ function resizeComposerTextarea(textarea, {
648
644
  }
649
645
 
650
646
  // src/embed/powered-by-hero.tsx
651
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
647
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
652
648
  var POWERED_BY_HERO_URL = "https://heroui.pro/?utm_source=heroui-agent&utm_medium=referral&utm_campaign=powered-by-hero";
653
649
  function PoweredByHero() {
654
- return /* @__PURE__ */ jsxs3(
650
+ return /* @__PURE__ */ jsxs4(
655
651
  "a",
656
652
  {
657
653
  "aria-label": "Powered by HeroUI Pro (opens in a new tab)",
@@ -660,16 +656,16 @@ function PoweredByHero() {
660
656
  rel: "noopener noreferrer",
661
657
  target: "_blank",
662
658
  children: [
663
- /* @__PURE__ */ jsx3("span", { children: "Powered by" }),
664
- /* @__PURE__ */ jsxs3("svg", { "aria-hidden": "true", className: "ha-powered-by-logo", fill: "none", viewBox: "0 0 140 44", children: [
665
- /* @__PURE__ */ jsx3(
659
+ /* @__PURE__ */ jsx4("span", { children: "Powered by" }),
660
+ /* @__PURE__ */ jsxs4("svg", { "aria-hidden": "true", className: "ha-powered-by-logo", fill: "none", viewBox: "0 0 140 44", children: [
661
+ /* @__PURE__ */ jsx4(
666
662
  "path",
667
663
  {
668
664
  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",
669
665
  fill: "currentColor"
670
666
  }
671
667
  ),
672
- /* @__PURE__ */ jsx3(
668
+ /* @__PURE__ */ jsx4(
673
669
  "path",
674
670
  {
675
671
  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",
@@ -682,43 +678,11 @@ function PoweredByHero() {
682
678
  );
683
679
  }
684
680
 
685
- // src/embed/shell-handoff.ts
686
- var handoffs = /* @__PURE__ */ new Map();
687
- function shellDraftStorageKey(agentId) {
688
- return `heroui-agent:shell-draft:${agentId}:composer-draft:v1`;
689
- }
690
- function writeAgentShellHandoff(agentId, handoff) {
691
- if (!handoff.prompt.trim() && !handoff.submitted) {
692
- handoffs.delete(agentId);
693
- saveAgentComposerPromptDraft(shellDraftStorageKey(agentId), "");
694
- return;
695
- }
696
- handoffs.set(agentId, handoff);
697
- if (!handoff.submitted) {
698
- saveAgentComposerPromptDraft(shellDraftStorageKey(agentId), handoff.prompt);
699
- }
700
- }
701
- function readAgentShellHandoff(agentId) {
702
- const buffered = handoffs.get(agentId);
703
- if (buffered) return buffered;
704
- const persisted = readAgentComposerPromptDraft(shellDraftStorageKey(agentId));
705
- return persisted ? { prompt: persisted, submitted: false } : void 0;
706
- }
707
- function takeAgentShellHandoff(agentId) {
708
- const handoff = readAgentShellHandoff(agentId);
709
- handoffs.delete(agentId);
710
- saveAgentComposerPromptDraft(shellDraftStorageKey(agentId), "");
711
- return handoff;
712
- }
713
-
714
681
  // src/embed/permissions.ts
715
682
  var AGENT_PERMISSION_MODES = /* @__PURE__ */ new Set(["ask", "auto", "full"]);
716
683
  function resolveAgentPermissionMode(value) {
717
684
  return AGENT_PERMISSION_MODES.has(value) ? value : "auto";
718
685
  }
719
- function shouldRestoreActiveAgentPermissionMode(bootstrapStatus, hasUnresolvedClientTool) {
720
- return hasUnresolvedClientTool || bootstrapStatus === "pending" || bootstrapStatus === "streaming";
721
- }
722
686
  function agentPermissionModeStorageKey(conversationStorageKey, conversationId) {
723
687
  return `${conversationStorageKey}:permission-mode:${conversationId}:v1`;
724
688
  }
@@ -843,81 +807,103 @@ function buildThemeStyle(theme) {
843
807
  return style;
844
808
  }
845
809
 
846
- // src/contracts/models.ts
847
- var AGENT_MODEL_IDS = [
848
- "moonshotai/Kimi-K3",
849
- "openai/gpt-5.6-luna",
850
- "openai/gpt-5.6-terra",
851
- "openai/gpt-5.6-sol",
852
- "google/gemini-3.6-flash",
853
- "anthropic/claude-sonnet-5",
854
- "anthropic/claude-opus-4.8"
855
- ];
856
- var LEGACY_AGENT_MODEL_IDS = {
857
- "google/gemini-3.5-flash": "google/gemini-3.6-flash"
810
+ // src/contracts/runtime.ts
811
+ var HEROUI_AGENT_RUNTIME_TIMING_EVENT = "heroui-agent:runtime-timing";
812
+ var HEROUI_AGENT_TURN_ADMITTED_FRAME_TYPE = "heroui_agent_turn_admitted";
813
+ var HEROUI_AGENT_TURN_ADMISSION_STATUS_METHOD = "getTurnAdmissionStatuses";
814
+ var HEROUI_AGENT_TURN_ADMISSION_STATUS_MAX_IDS = 50;
815
+
816
+ // ../agent-client/src/token-manager.ts
817
+ function anonymousStorageKey(agentId) {
818
+ return `heroui-agent:anonymous:${agentId}`;
819
+ }
820
+ var EmbedSessionManager = class {
821
+ constructor(agentId, getAuthToken) {
822
+ this.agentId = agentId;
823
+ this.getAuthToken = getAuthToken;
824
+ }
825
+ cached = null;
826
+ generation = 0;
827
+ pending = null;
828
+ clear() {
829
+ this.generation += 1;
830
+ this.cached = null;
831
+ this.pending = null;
832
+ }
833
+ /**
834
+ * Forgets both the cached credential and the browser's anonymous id, so the
835
+ * next request represents a brand-new person. Used on logout to stop a
836
+ * shared device from attributing the next visitor to the previous user.
837
+ */
838
+ reset() {
839
+ this.clear();
840
+ try {
841
+ localStorage.removeItem(anonymousStorageKey(this.agentId));
842
+ } catch {
843
+ }
844
+ }
845
+ async get() {
846
+ if (this.cached && this.expiresAt(this.cached) > Date.now() + 6e4) {
847
+ return this.cached.token;
848
+ }
849
+ const generation = this.generation;
850
+ const pending = this.pending ?? this.refresh();
851
+ if (!this.pending) this.pending = pending;
852
+ try {
853
+ const result = await pending;
854
+ if (generation !== this.generation) return this.get();
855
+ this.cached = result;
856
+ return result.token;
857
+ } finally {
858
+ if (this.pending === pending) this.pending = null;
859
+ }
860
+ }
861
+ async subjectHash() {
862
+ const token = await this.get();
863
+ const payload = decodeTokenPayload(token);
864
+ const subject = typeof payload["sub"] === "string" ? payload["sub"] : "anonymous";
865
+ const digest = await crypto.subtle.digest(
866
+ "SHA-256",
867
+ new TextEncoder().encode(`${this.agentId}:${subject}`)
868
+ );
869
+ return Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("").slice(0, 24);
870
+ }
871
+ anonymousId() {
872
+ const key = anonymousStorageKey(this.agentId);
873
+ try {
874
+ const existing = localStorage.getItem(key);
875
+ if (existing) return existing;
876
+ const created = crypto.randomUUID();
877
+ localStorage.setItem(key, created);
878
+ return created;
879
+ } catch {
880
+ return crypto.randomUUID();
881
+ }
882
+ }
883
+ expiresAt(response) {
884
+ return response.expiresAt;
885
+ }
886
+ async refresh() {
887
+ const result = await this.getAuthToken({
888
+ agentId: this.agentId,
889
+ anonymousId: this.anonymousId()
890
+ });
891
+ if (!result || typeof result.token !== "string" || !result.token.trim() || typeof result.expiresAt !== "number" || !Number.isFinite(result.expiresAt) || result.expiresAt <= 0) {
892
+ throw new Error("Auth token callback returned invalid data");
893
+ }
894
+ return { expiresAt: result.expiresAt, token: result.token };
895
+ }
858
896
  };
859
- function resolveAgentModelId(value) {
860
- return LEGACY_AGENT_MODEL_IDS[value] ?? value;
861
- }
862
- var DEFAULT_AGENT_PICKER_MODEL_ID = "openai/gpt-5.6-luna";
863
- var AGENT_MODEL_OPTIONS = [
864
- {
865
- description: "Flagship model for coding, reasoning, and knowledge work",
866
- id: "moonshotai/Kimi-K3",
867
- label: "Kimi K3",
868
- provider: "Moonshot AI",
869
- tier: "light"
870
- },
871
- {
872
- description: "Fast answers and lightweight agent workflows",
873
- id: "openai/gpt-5.6-luna",
874
- label: "GPT-5.6 Luna",
875
- provider: "OpenAI",
876
- tier: "light"
877
- },
878
- {
879
- description: "Balanced reasoning for everyday agent tasks",
880
- id: "openai/gpt-5.6-terra",
881
- label: "GPT-5.6 Terra",
882
- provider: "OpenAI",
883
- tier: "codegen"
884
- },
885
- {
886
- description: "Deep reasoning for complex, multi-step analysis",
887
- id: "openai/gpt-5.6-sol",
888
- label: "GPT-5.6 Sol",
889
- provider: "OpenAI",
890
- tier: "complex"
891
- },
892
- {
893
- description: "Fast multimodal analysis with a large context window",
894
- id: "google/gemini-3.6-flash",
895
- label: "Gemini 3.6 Flash",
896
- provider: "Google",
897
- tier: "light"
898
- },
899
- {
900
- description: "Strong agentic reasoning and polished UI decisions",
901
- id: "anthropic/claude-sonnet-5",
902
- label: "Claude Sonnet 5",
903
- provider: "Anthropic",
904
- tier: "codegen"
905
- },
906
- {
907
- description: "Highest-capability Claude for difficult research and analysis",
908
- id: "anthropic/claude-opus-4.8",
909
- label: "Claude Opus 4.8",
910
- provider: "Anthropic",
911
- tier: "complex"
897
+ function decodeTokenPayload(token) {
898
+ try {
899
+ const payload = token.split(".")[1];
900
+ if (!payload) return {};
901
+ const normalized = payload.replace(/-/g, "+").replace(/_/g, "/");
902
+ const padded = normalized.padEnd(Math.ceil(normalized.length / 4) * 4, "=");
903
+ return JSON.parse(atob(padded));
904
+ } catch {
905
+ return {};
912
906
  }
913
- ];
914
- var AGENT_MODEL_ID_SET = new Set(AGENT_MODEL_IDS);
915
- function isAgentModelId(value) {
916
- return typeof value === "string" && AGENT_MODEL_ID_SET.has(value);
917
- }
918
- function getAgentModelTier(modelId) {
919
- const resolved = modelId ? resolveAgentModelId(modelId) : void 0;
920
- return AGENT_MODEL_OPTIONS.find((option) => option.id === resolved)?.tier ?? "light";
921
907
  }
922
908
 
923
909
  // src/contracts/attachments.ts
@@ -948,9 +934,210 @@ function isHeroUIAgentAttachmentContentType(value) {
948
934
  return HEROUI_AGENT_ATTACHMENT_CONTENT_TYPE_SET.has(value.trim().toLowerCase());
949
935
  }
950
936
 
937
+ // src/embed/shell-conversation.tsx
938
+ import { useEffect as useEffect2, useLayoutEffect, useRef as useRef2, useState as useState2 } from "react";
939
+ import { Fragment, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
940
+ function ShellConversation({
941
+ agentId,
942
+ composerConnecting = false,
943
+ composerControlsAvailable,
944
+ composerControlsRevealed,
945
+ composerEndSlot,
946
+ composerFooterSlot,
947
+ composerStartSlot,
948
+ greeting,
949
+ onComposerControlsReveal,
950
+ onIntent,
951
+ placeholder,
952
+ suggestedPrompts
953
+ }) {
954
+ const [initialHandoff] = useState2(() => readAgentShellHandoff(agentId));
955
+ const [input, setInput] = useState2(() => initialHandoff?.prompt ?? "");
956
+ const [submission, setSubmission] = useState2(
957
+ () => initialHandoff?.submitted ? initialHandoff : null
958
+ );
959
+ const [locallyRevealedControls, setLocallyRevealedControls] = useState2(false);
960
+ const textareaRef = useRef2(null);
961
+ const controlsAvailable = composerControlsAvailable ?? Boolean(composerStartSlot || composerEndSlot);
962
+ const controlsRevealed = composerControlsRevealed ?? (controlsAvailable && locallyRevealedControls);
963
+ const revealComposerControls = (event) => {
964
+ setFocus(agentId, true, event.currentTarget);
965
+ setLocallyRevealedControls(controlsAvailable);
966
+ if (controlsAvailable) onComposerControlsReveal?.();
967
+ onIntent();
968
+ };
969
+ const handleComposerBlur = (event) => {
970
+ const composer = event.currentTarget.querySelector(".ha-composer");
971
+ if (composer && containsComposerFocus(composer, event.relatedTarget)) return;
972
+ setLocallyRevealedControls(false);
973
+ setFocus(agentId, false);
974
+ };
975
+ useLayoutEffect(() => {
976
+ restoreFocus(agentId, textareaRef.current);
977
+ resizeComposerTextarea(textareaRef.current);
978
+ }, [agentId]);
979
+ useEffect2(() => {
980
+ if (submission) return;
981
+ writeAgentShellHandoff(agentId, { prompt: input, submitted: false });
982
+ }, [input, agentId, submission]);
983
+ useLayoutEffect(() => {
984
+ if (!submission) return;
985
+ const frame = requestAnimationFrame((paintedAt) => {
986
+ markAgentShellFeedbackPainted(agentId, submission.messageId, paintedAt);
987
+ });
988
+ return () => cancelAnimationFrame(frame);
989
+ }, [agentId, submission]);
990
+ const submit = (prompt) => {
991
+ if (submission) return;
992
+ const nextSubmission = createSubmittedAgentShellHandoff(prompt);
993
+ if (!nextSubmission) return;
994
+ setSubmission(nextSubmission);
995
+ setInput("");
996
+ textareaRef.current.style.height = "auto";
997
+ writeAgentShellHandoff(agentId, nextSubmission);
998
+ onIntent();
999
+ };
1000
+ return /* @__PURE__ */ jsxs5(Fragment, { children: [
1001
+ /* @__PURE__ */ jsx5("div", { className: "ha-conversation", children: /* @__PURE__ */ jsx5("div", { "aria-live": "polite", className: "ha-messages", role: "log", children: submission ? /* @__PURE__ */ jsxs5(Fragment, { children: [
1002
+ /* @__PURE__ */ jsx5("div", { className: "ha-message", "data-role": "user", children: /* @__PURE__ */ jsx5("div", { className: "ha-message-body", children: submission.prompt }) }),
1003
+ /* @__PURE__ */ jsx5(
1004
+ "div",
1005
+ {
1006
+ className: "ha-message",
1007
+ "data-role": "assistant",
1008
+ "data-stream-anchor": "true",
1009
+ "data-turn-feedback-id": submission.messageId,
1010
+ children: /* @__PURE__ */ jsx5("div", { className: "ha-message-body", children: /* @__PURE__ */ jsx5(
1011
+ "div",
1012
+ {
1013
+ "aria-label": "Working on your request\u2026",
1014
+ className: "ha-progress ha-activity-status ha-progress-shimmer",
1015
+ role: "status",
1016
+ children: /* @__PURE__ */ jsx5("span", { "aria-hidden": "true", className: "ha-shimmer", children: "Thinking\u2026" })
1017
+ }
1018
+ ) })
1019
+ }
1020
+ )
1021
+ ] }) : /* @__PURE__ */ jsxs5("div", { className: "ha-empty", children: [
1022
+ /* @__PURE__ */ jsx5("h2", { children: greeting }),
1023
+ /* @__PURE__ */ jsx5("p", { children: "Live answers with charts, metrics, and tables." })
1024
+ ] }) }) }),
1025
+ /* @__PURE__ */ jsxs5(
1026
+ "form",
1027
+ {
1028
+ className: "ha-composer-wrap",
1029
+ onBlur: handleComposerBlur,
1030
+ onSubmit: (event) => {
1031
+ event.preventDefault();
1032
+ submit(input);
1033
+ },
1034
+ children: [
1035
+ !submission && suggestedPrompts.length > 0 ? /* @__PURE__ */ jsx5("div", { "aria-label": "Suggested prompts", className: "ha-suggestions", role: "group", children: suggestedPrompts.map((prompt) => /* @__PURE__ */ jsxs5(
1036
+ "button",
1037
+ {
1038
+ className: "ha-suggestion",
1039
+ type: "button",
1040
+ onClick: () => submit(prompt),
1041
+ children: [
1042
+ /* @__PURE__ */ jsx5("span", { children: prompt }),
1043
+ /* @__PURE__ */ jsx5(ArrowUpRightGlyph, {})
1044
+ ]
1045
+ },
1046
+ prompt
1047
+ )) }) : null,
1048
+ /* @__PURE__ */ jsxs5(
1049
+ "div",
1050
+ {
1051
+ className: "@container ha-composer",
1052
+ "data-connecting": composerConnecting || void 0,
1053
+ "data-controls-revealed": controlsRevealed || void 0,
1054
+ children: [
1055
+ composerStartSlot,
1056
+ /* @__PURE__ */ jsx5(
1057
+ "textarea",
1058
+ {
1059
+ ref: textareaRef,
1060
+ "aria-label": "Message the assistant",
1061
+ placeholder,
1062
+ readOnly: Boolean(submission),
1063
+ rows: 1,
1064
+ value: input,
1065
+ onFocus: revealComposerControls,
1066
+ onSelect: (event) => setFocus(agentId, true, event.currentTarget),
1067
+ onChange: (event) => {
1068
+ const nextInput = event.currentTarget.value;
1069
+ writeAgentShellHandoff(agentId, { prompt: nextInput, submitted: false });
1070
+ setFocus(agentId, true, event.currentTarget);
1071
+ setInput(nextInput);
1072
+ resizeComposerTextarea(event.currentTarget);
1073
+ onIntent();
1074
+ },
1075
+ onKeyDown: (event) => {
1076
+ if (event.key !== "Enter" || event.shiftKey) return;
1077
+ event.preventDefault();
1078
+ submit(input);
1079
+ }
1080
+ }
1081
+ ),
1082
+ composerEndSlot,
1083
+ /* @__PURE__ */ jsxs5(
1084
+ "button",
1085
+ {
1086
+ "aria-label": "Send message",
1087
+ className: "ha-send",
1088
+ disabled: !input.trim() || Boolean(submission),
1089
+ type: "submit",
1090
+ children: [
1091
+ /* @__PURE__ */ jsx5(ArrowUpGlyph, {}),
1092
+ /* @__PURE__ */ jsx5(ComposerControlTooltip, { shortcut: "\u21B5", children: "Send message" })
1093
+ ]
1094
+ }
1095
+ )
1096
+ ]
1097
+ }
1098
+ ),
1099
+ /* @__PURE__ */ jsx5(
1100
+ "div",
1101
+ {
1102
+ className: "ha-composer-footer",
1103
+ "data-revealed": Boolean(composerFooterSlot) || void 0,
1104
+ children: /* @__PURE__ */ jsx5("div", { className: "ha-composer-footer-content", children: composerFooterSlot })
1105
+ }
1106
+ ),
1107
+ /* @__PURE__ */ jsx5(PoweredByHero, {})
1108
+ ]
1109
+ }
1110
+ )
1111
+ ] });
1112
+ }
1113
+ function ArrowUpGlyph() {
1114
+ return /* @__PURE__ */ jsx5("svg", { "aria-hidden": "true", fill: "none", height: "18", viewBox: "0 0 18 18", width: "18", children: /* @__PURE__ */ jsx5(
1115
+ "path",
1116
+ {
1117
+ d: "M9 14.5V3.5m0 0L4.5 8M9 3.5 13.5 8",
1118
+ stroke: "currentColor",
1119
+ strokeLinecap: "round",
1120
+ strokeLinejoin: "round",
1121
+ strokeWidth: "1.6"
1122
+ }
1123
+ ) });
1124
+ }
1125
+ function ArrowUpRightGlyph() {
1126
+ return /* @__PURE__ */ jsx5("svg", { "aria-hidden": "true", fill: "none", height: "16", viewBox: "0 0 16 16", width: "16", children: /* @__PURE__ */ jsx5(
1127
+ "path",
1128
+ {
1129
+ d: "M5 11 11 5m0 0H6m5 0v5",
1130
+ stroke: "currentColor",
1131
+ strokeLinecap: "round",
1132
+ strokeLinejoin: "round",
1133
+ strokeWidth: "1.5"
1134
+ }
1135
+ ) });
1136
+ }
1137
+
951
1138
  // src/embed/types.ts
952
1139
  var DEFAULT_MARKDOWN_ANIMATION = {
953
- animation: "blurIn",
1140
+ animation: "fadeIn",
954
1141
  duration: 160,
955
1142
  easing: "ease-out",
956
1143
  sep: "word",
@@ -992,16 +1179,18 @@ function resolveOptions(props) {
992
1179
  const composerAttachmentContentTypes = resolveComposerAttachmentContentTypes(
993
1180
  props.composer?.attachments
994
1181
  );
1182
+ const composerDisclaimer = typeof props.composer?.disclaimer === "string" ? props.composer.disclaimer.trim().slice(0, 240) || void 0 : void 0;
995
1183
  return {
996
1184
  apiBaseUrl: (props._api?.baseUrl ?? "https://api.heroui.com").replace(/\/$/, ""),
997
1185
  colorScheme: props.appearance?.theme?.colorScheme ?? "system",
998
1186
  componentExportFormats: props.componentExports === false ? [] : props.componentExports ?? ["csv", "svg", "png"],
999
1187
  composerAttachmentAccept: composerAttachmentContentTypes.join(","),
1000
1188
  composerAttachmentContentTypes,
1189
+ composerControlsAvailable: composerAttachmentContentTypes.length > 0 || props.permissions?.showPicker === true && !!props.tools?.length || props.composer?.modelPicker === true || (props.composer?.dictation ?? true),
1001
1190
  composerDefaultModel: props.composer?.defaultModel,
1002
1191
  composerDictation: props.composer?.dictation ?? true,
1003
1192
  designTheme: resolveAgentDesignTheme(props.appearance?.theme?.designTheme),
1004
- ...typeof props.composer?.disclaimer === "string" && props.composer.disclaimer.trim() ? { composerDisclaimer: props.composer.disclaimer.trim().slice(0, 240) } : {},
1193
+ ...composerDisclaimer ? { composerDisclaimer } : {},
1005
1194
  agentId: props.agentId,
1006
1195
  composerModelPicker: props.composer?.modelPicker ?? false,
1007
1196
  composerPlaceholder: props.composer?.placeholder?.trim().slice(0, 120) || "Ask anything\u2026",
@@ -1050,14 +1239,8 @@ export {
1050
1239
  isZodSchema,
1051
1240
  parseClientToolArgs,
1052
1241
  resolveDirectToolAction,
1053
- agentComposerDraftStorageKey,
1054
- readAgentComposerPromptDraft,
1055
- saveAgentComposerPromptDraft,
1056
- readAgentComposerImageDraft,
1057
- saveAgentComposerImageDraft,
1058
- clearAgentComposerDraft,
1059
- clearAgentComposerDraftsForProject,
1060
- scheduleIdleTask,
1242
+ EmbedSessionManager,
1243
+ AgentLoadingState,
1061
1244
  ComposerControlTooltip,
1062
1245
  readSidebarWidth,
1063
1246
  PanelShell,
@@ -1066,12 +1249,26 @@ export {
1066
1249
  HEROUI_AGENT_ATTACHMENT_EXTENSION_BY_CONTENT_TYPE,
1067
1250
  HEROUI_AGENT_ATTACHMENT_CONTENT_TYPES,
1068
1251
  isHeroUIAgentAttachmentContentType,
1069
- resizeComposerTextarea,
1070
- PoweredByHero,
1252
+ AGENT_MODEL_IDS,
1253
+ LEGACY_AGENT_MODEL_IDS,
1254
+ resolveAgentModelId,
1255
+ DEFAULT_AGENT_PICKER_MODEL_ID,
1256
+ AGENT_MODEL_OPTIONS,
1257
+ isAgentModelId,
1258
+ getAgentModelTier,
1259
+ createSubmittedAgentShellHandoff,
1071
1260
  writeAgentShellHandoff,
1072
1261
  readAgentShellHandoff,
1073
1262
  takeAgentShellHandoff,
1074
- shouldRestoreActiveAgentPermissionMode,
1263
+ setFocus,
1264
+ restoreFocus,
1265
+ containsComposerFocus,
1266
+ writeAgentShellAttachments,
1267
+ readAgentShellAttachments,
1268
+ takeAgentShellAttachments,
1269
+ resizeComposerTextarea,
1270
+ PoweredByHero,
1271
+ ShellConversation,
1075
1272
  agentPermissionModeStorageKey,
1076
1273
  agentActivePermissionModeStorageKey,
1077
1274
  readStoredAgentPermissionMode,
@@ -1081,11 +1278,8 @@ export {
1081
1278
  AGENT_DESIGN_THEMES,
1082
1279
  DEFAULT_MARKDOWN_ANIMATION,
1083
1280
  resolveOptions,
1084
- AGENT_MODEL_IDS,
1085
- LEGACY_AGENT_MODEL_IDS,
1086
- resolveAgentModelId,
1087
- DEFAULT_AGENT_PICKER_MODEL_ID,
1088
- AGENT_MODEL_OPTIONS,
1089
- isAgentModelId,
1090
- getAgentModelTier
1281
+ HEROUI_AGENT_RUNTIME_TIMING_EVENT,
1282
+ HEROUI_AGENT_TURN_ADMITTED_FRAME_TYPE,
1283
+ HEROUI_AGENT_TURN_ADMISSION_STATUS_METHOD,
1284
+ HEROUI_AGENT_TURN_ADMISSION_STATUS_MAX_IDS
1091
1285
  };