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

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.
@@ -33,7 +33,7 @@ import {
33
33
  shouldRestoreActiveAgentPermissionMode,
34
34
  storeAgentPermissionMode,
35
35
  takeAgentShellHandoff
36
- } from "./chunk-QOCNMON2.js";
36
+ } from "./chunk-OQGXZY5L.js";
37
37
  import {
38
38
  ActionButton,
39
39
  CodeBlock,
@@ -1725,8 +1725,8 @@ import {
1725
1725
  useEffectEvent,
1726
1726
  useLayoutEffect as useLayoutEffect4,
1727
1727
  useMemo as useMemo4,
1728
- useRef as useRef15,
1729
- useState as useState14
1728
+ useRef as useRef14,
1729
+ useState as useState15
1730
1730
  } from "react";
1731
1731
 
1732
1732
  // src/contracts/identity.ts
@@ -1777,7 +1777,7 @@ var agentModelIdSchema = z2.preprocess(
1777
1777
 
1778
1778
  // src/contracts/version.ts
1779
1779
  var HEROUI_AGENT_PROTOCOL_VERSION = 5;
1780
- var HEROUI_AGENT_SDK_VERSION = "0.2.0-beta.6";
1780
+ var HEROUI_AGENT_SDK_VERSION = "0.2.0-beta.7";
1781
1781
  var HEROUI_AGENT_TASK_ID = "heroui-agents-runtime";
1782
1782
 
1783
1783
  // src/contracts/identity.ts
@@ -1957,6 +1957,14 @@ function inferActivityKind(label) {
1957
1957
  if (/data|query|load|fetch|metric|table|account/.test(normalized)) return "data";
1958
1958
  return "thinking";
1959
1959
  }
1960
+ function hasResponseAfterLatestActivity(items, options) {
1961
+ if (!options.hasContent) return false;
1962
+ const latestActivityPartIndex = items.reduce(
1963
+ (latest, item) => Math.max(latest, item.messagePartIndex ?? -1),
1964
+ -1
1965
+ );
1966
+ return options.latestContentPartIndex >= latestActivityPartIndex;
1967
+ }
1960
1968
  function collectActivity(message, clientTools, options = {}) {
1961
1969
  if (message.role !== "assistant") return [];
1962
1970
  const items = [];
@@ -1972,7 +1980,9 @@ function collectActivity(message, clientTools, options = {}) {
1972
1980
  id: part.id ?? `${message.id}-activity-${index}`,
1973
1981
  kind: part.data.kind ?? inferActivityKind(label2),
1974
1982
  label: label2,
1975
- sources: part.data.sources
1983
+ messagePartIndex: index,
1984
+ sources: part.data.sources,
1985
+ stateKnown: false
1976
1986
  });
1977
1987
  }
1978
1988
  continue;
@@ -1993,16 +2003,38 @@ function collectActivity(message, clientTools, options = {}) {
1993
2003
  toolPart.output && typeof toolPart.output === "object" && "rejected" in toolPart.output && toolPart.output.rejected
1994
2004
  );
1995
2005
  const label = rejected ? `Skipped ${baseLabel}` : toolPart.state === "output-error" ? `Couldn\u2019t complete ${baseLabel}` : baseLabel;
1996
- if (labels.has(label)) continue;
2006
+ const active = toolPart.state === "input-available" || toolPart.state === "input-streaming";
2007
+ const existingIndex = items.findIndex((item) => item.label === label);
2008
+ if (existingIndex >= 0) {
2009
+ const existing = items[existingIndex];
2010
+ if (existing) {
2011
+ items[existingIndex] = {
2012
+ ...existing,
2013
+ active,
2014
+ messagePartIndex: index,
2015
+ stateKnown: true
2016
+ };
2017
+ }
2018
+ continue;
2019
+ }
1997
2020
  labels.add(label);
1998
2021
  items.push({
1999
- active: toolPart.state === "input-available" || toolPart.state === "input-streaming",
2022
+ active,
2000
2023
  id: toolPart.toolCallId || `${message.id}-tool-${index}`,
2001
2024
  kind: renderTool ? "chart" : toolName === "executeSandbox" ? "code" : toolName === "getComponentSchema" ? "thinking" : inferActivityKind(label),
2002
- label
2025
+ label,
2026
+ messagePartIndex: index,
2027
+ stateKnown: true
2003
2028
  });
2004
2029
  }
2005
- return items;
2030
+ if (!options.isStreaming || items.length === 0) return items;
2031
+ if (items.some((item) => item.active)) return items;
2032
+ const activeIndex = items.length - 1;
2033
+ if (items[activeIndex]?.stateKnown) return items;
2034
+ return items.map((item, index) => ({
2035
+ ...item,
2036
+ active: index === activeIndex
2037
+ }));
2006
2038
  }
2007
2039
 
2008
2040
  // src/embed/activity-trail.tsx
@@ -2016,10 +2048,10 @@ import {
2016
2048
  Wrench
2017
2049
  } from "@gravity-ui/icons";
2018
2050
  import { Disclosure as Disclosure2 } from "@heroui/react";
2019
- import { useEffect as useEffect7, useRef as useRef6, useState as useState4 } from "react";
2051
+ import { useEffect as useEffect7, useRef as useRef5, useState as useState5 } from "react";
2020
2052
 
2021
2053
  // src/embed/animated-status-text.tsx
2022
- import { useEffect as useEffect5, useRef as useRef5 } from "react";
2054
+ import { useEffect as useEffect5, useState as useState4 } from "react";
2023
2055
 
2024
2056
  // src/embed/shimmer-text.tsx
2025
2057
  import { jsx as jsx6 } from "react/jsx-runtime";
@@ -2028,35 +2060,64 @@ function ShimmerText({ children, className, ...props }) {
2028
2060
  }
2029
2061
 
2030
2062
  // src/embed/animated-status-text.tsx
2031
- import { jsx as jsx7 } from "react/jsx-runtime";
2063
+ import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
2064
+ var STATUS_SWAP_MS = 280;
2032
2065
  function AnimatedStatusText({
2033
2066
  animateOnMount = true,
2034
2067
  children,
2035
2068
  className,
2036
2069
  ...props
2037
2070
  }) {
2038
- const previousValueRef = useRef5(children);
2039
- const shouldAnimate = animateOnMount || previousValueRef.current !== children;
2071
+ const [transition, setTransition] = useState4(() => ({
2072
+ current: { animate: animateOnMount, id: 0, text: children },
2073
+ previous: null
2074
+ }));
2075
+ if (transition.current.text !== children) {
2076
+ setTransition({
2077
+ current: { animate: true, id: transition.current.id + 1, text: children },
2078
+ previous: transition.current
2079
+ });
2080
+ }
2081
+ const currentId = transition.current.id;
2082
+ const previous = transition.previous;
2040
2083
  useEffect5(() => {
2041
- previousValueRef.current = children;
2042
- }, [children]);
2043
- return /* @__PURE__ */ jsx7(
2084
+ if (!previous) return;
2085
+ const timer = window.setTimeout(() => {
2086
+ setTransition(
2087
+ (current) => current.current.id === currentId ? { ...current, previous: null } : current
2088
+ );
2089
+ }, STATUS_SWAP_MS);
2090
+ return () => window.clearTimeout(timer);
2091
+ }, [currentId, previous]);
2092
+ return /* @__PURE__ */ jsxs5(
2044
2093
  "span",
2045
2094
  {
2046
2095
  ...props,
2047
2096
  "aria-label": props["aria-label"] ?? children,
2048
2097
  className: `ha-status-text${className ? ` ${className}` : ""}`,
2049
2098
  "data-slot": "animated-text",
2050
- children: /* @__PURE__ */ jsx7(
2051
- "span",
2052
- {
2053
- "aria-hidden": "true",
2054
- className: shouldAnimate ? "ha-status-text__value ha-status-text__value--animated" : "ha-status-text__value",
2055
- "data-slot": "animated-text-value",
2056
- children: /* @__PURE__ */ jsx7(ShimmerText, { children })
2057
- },
2058
- children
2059
- )
2099
+ children: [
2100
+ /* @__PURE__ */ jsx7(
2101
+ "span",
2102
+ {
2103
+ "aria-hidden": "true",
2104
+ "data-slot": "animated-text-value",
2105
+ className: transition.current.animate ? "ha-status-text__value ha-status-text__value--animated" : "ha-status-text__value",
2106
+ children: /* @__PURE__ */ jsx7(ShimmerText, { children: transition.current.text })
2107
+ },
2108
+ transition.current.id
2109
+ ),
2110
+ transition.previous ? /* @__PURE__ */ jsx7(
2111
+ "span",
2112
+ {
2113
+ "aria-hidden": "true",
2114
+ className: "ha-status-text__value ha-status-text__value--exiting",
2115
+ "data-slot": "animated-text-previous-value",
2116
+ children: /* @__PURE__ */ jsx7(ShimmerText, { children: transition.previous.text })
2117
+ },
2118
+ transition.previous.id
2119
+ ) : null
2120
+ ]
2060
2121
  }
2061
2122
  );
2062
2123
  }
@@ -2116,25 +2177,87 @@ function useScrollShadow(ref, offset = 1) {
2116
2177
  }
2117
2178
 
2118
2179
  // src/embed/activity-trail.tsx
2119
- import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
2180
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
2120
2181
  var FOLLOW_THRESHOLD_PX = 24;
2121
- function useFollowNewestStep(ref, stepCount, isStreaming, isExpanded) {
2122
- const isFollowingRef = useRef6(true);
2182
+ var ACTIVITY_FADE_MS = 160;
2183
+ var ACTIVITY_COLLAPSE_MS = 220;
2184
+ function useFollowNewestStep(ref, contentVersion, isStreaming, isExpanded) {
2185
+ const isFollowingRef = useRef5(true);
2123
2186
  useEffect7(() => {
2124
2187
  const element = ref.current;
2125
2188
  if (!element) return;
2126
- const handleScroll = () => {
2189
+ let autoScrollTimer;
2190
+ let isAutoScrolling = false;
2191
+ const updateFollowing = () => {
2127
2192
  const distanceFromBottom = element.scrollHeight - element.scrollTop - element.clientHeight;
2128
2193
  isFollowingRef.current = distanceFromBottom <= FOLLOW_THRESHOLD_PX;
2129
2194
  };
2195
+ const handleScroll = () => {
2196
+ if (isAutoScrolling) return;
2197
+ updateFollowing();
2198
+ };
2199
+ const handleUserScrollIntent = () => {
2200
+ isAutoScrolling = false;
2201
+ window.clearTimeout(autoScrollTimer);
2202
+ requestAnimationFrame(updateFollowing);
2203
+ };
2204
+ const followNewest = () => {
2205
+ if (!isExpanded || !isStreaming || !isFollowingRef.current) return;
2206
+ const shouldReduceMotion = typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
2207
+ const top = element.scrollHeight;
2208
+ if (typeof element.scrollTo !== "function") {
2209
+ element.scrollTop = top;
2210
+ return;
2211
+ }
2212
+ isAutoScrolling = !shouldReduceMotion;
2213
+ element.scrollTo({ behavior: shouldReduceMotion ? "auto" : "smooth", top });
2214
+ window.clearTimeout(autoScrollTimer);
2215
+ autoScrollTimer = window.setTimeout(() => {
2216
+ isAutoScrolling = false;
2217
+ updateFollowing();
2218
+ }, 360);
2219
+ };
2130
2220
  element.addEventListener("scroll", handleScroll, { passive: true });
2131
- return () => element.removeEventListener("scroll", handleScroll);
2132
- }, [isExpanded, ref]);
2221
+ element.addEventListener("pointerdown", handleUserScrollIntent, { passive: true });
2222
+ element.addEventListener("touchstart", handleUserScrollIntent, { passive: true });
2223
+ element.addEventListener("wheel", handleUserScrollIntent, { passive: true });
2224
+ followNewest();
2225
+ const list = element.querySelector("ol");
2226
+ const resizeObserver = list && typeof ResizeObserver !== "undefined" ? new ResizeObserver(followNewest) : null;
2227
+ if (list) resizeObserver?.observe(list);
2228
+ return () => {
2229
+ element.removeEventListener("scroll", handleScroll);
2230
+ element.removeEventListener("pointerdown", handleUserScrollIntent);
2231
+ element.removeEventListener("touchstart", handleUserScrollIntent);
2232
+ element.removeEventListener("wheel", handleUserScrollIntent);
2233
+ resizeObserver?.disconnect();
2234
+ window.clearTimeout(autoScrollTimer);
2235
+ };
2236
+ }, [contentVersion, isExpanded, isStreaming, ref]);
2237
+ }
2238
+ function useActivityPhase(isStreaming) {
2239
+ const [phaseState, setPhaseState] = useState5(() => ({
2240
+ isStreaming,
2241
+ phase: isStreaming ? "expanded" : "collapsed"
2242
+ }));
2243
+ let phase = phaseState.phase;
2244
+ if (phaseState.isStreaming !== isStreaming) {
2245
+ phase = isStreaming ? "expanded" : "fading";
2246
+ setPhaseState({ isStreaming, phase });
2247
+ }
2133
2248
  useEffect7(() => {
2134
- const element = ref.current;
2135
- if (!element || !isExpanded || !isStreaming || !isFollowingRef.current) return;
2136
- element.scrollTop = element.scrollHeight;
2137
- }, [isExpanded, isStreaming, ref, stepCount]);
2249
+ if (isStreaming || phase === "collapsed" || phase === "expanded") return;
2250
+ const shouldReduceMotion = typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
2251
+ const nextPhase = shouldReduceMotion ? "collapsed" : phase === "fading" ? "collapsing" : "collapsed";
2252
+ const delay = shouldReduceMotion ? 0 : phase === "fading" ? ACTIVITY_FADE_MS : ACTIVITY_COLLAPSE_MS;
2253
+ const timer = window.setTimeout(() => {
2254
+ setPhaseState(
2255
+ (current) => current.isStreaming === isStreaming && current.phase === phase ? { ...current, phase: nextPhase } : current
2256
+ );
2257
+ }, delay);
2258
+ return () => window.clearTimeout(timer);
2259
+ }, [isStreaming, phase]);
2260
+ return phase;
2138
2261
  }
2139
2262
  var activityIcons = {
2140
2263
  browse: Globe,
@@ -2144,6 +2267,12 @@ var activityIcons = {
2144
2267
  search: Magnifier,
2145
2268
  thinking: Wrench
2146
2269
  };
2270
+ function ActivityStateIcon({ active }) {
2271
+ return /* @__PURE__ */ jsxs6("span", { className: "ha-activity-icon", "data-state": active ? "active" : "complete", children: [
2272
+ /* @__PURE__ */ jsx8("span", { "aria-hidden": "true", className: "ha-activity-icon-state ha-activity-icon-state--active", children: /* @__PURE__ */ jsx8("span", { className: "ha-activity-spinner" }) }),
2273
+ /* @__PURE__ */ jsx8("span", { "aria-hidden": "true", className: "ha-activity-icon-state ha-activity-icon-state--complete", children: /* @__PURE__ */ jsx8(CircleCheck, {}) })
2274
+ ] });
2275
+ }
2147
2276
  function formatActivityDuration(durationMs) {
2148
2277
  const totalSeconds = Math.max(1, Math.round(durationMs / 1e3));
2149
2278
  const hours = Math.floor(totalSeconds / 3600);
@@ -2159,63 +2288,101 @@ function ActivityStatus({ ariaLabel, label }) {
2159
2288
  function ActivityTrail({
2160
2289
  completedAt,
2161
2290
  defaultOpen = false,
2291
+ hasResponseStarted = false,
2162
2292
  isStreaming,
2163
2293
  items,
2164
2294
  progress,
2165
2295
  startedAt
2166
2296
  }) {
2167
- const [isExpanded, setIsExpanded] = useState4(defaultOpen);
2168
- const panelRef = useRef6(null);
2169
- const activeItem = items.findLast((item) => item.active);
2170
- const latestItem = items.at(-1);
2171
- const activeLabel = activeItem?.label ?? latestItem?.label ?? progress ?? "Understanding your request\u2026";
2172
- const elapsedMs = startedAt !== void 0 && !isStreaming ? Math.max(0, (completedAt ?? Date.now()) - startedAt) : null;
2173
- const summary = isStreaming ? activeLabel : elapsedMs === null ? "Activity" : `Worked for ${formatActivityDuration(elapsedMs)}`;
2297
+ const isActivityStreaming = isStreaming && !hasResponseStarted;
2298
+ const phase = useActivityPhase(isActivityStreaming);
2299
+ const [expandedOverride, setExpandedOverride] = useState5(null);
2300
+ const panelRef = useRef5(null);
2301
+ const activityStoppedAtRef = useRef5(null);
2302
+ const requestedActiveIndex = items.findLastIndex((item) => item.active);
2303
+ const fallbackActiveIndex = items.at(-1)?.stateKnown ? -1 : items.length - 1;
2304
+ const activeIndex = isActivityStreaming ? requestedActiveIndex >= 0 ? requestedActiveIndex : fallbackActiveIndex : -1;
2305
+ const visibleItems = items.map((item, index) => ({
2306
+ ...item,
2307
+ active: index === activeIndex
2308
+ }));
2309
+ const activeItem = activeIndex >= 0 ? visibleItems[activeIndex] : void 0;
2310
+ const latestItem = visibleItems.at(-1);
2311
+ const liveSummary = progress ?? activeItem?.label ?? latestItem?.label ?? "Understanding your request\u2026";
2312
+ const isAutoSettling = expandedOverride === null && !defaultOpen && !isActivityStreaming && (phase === "fading" || phase === "collapsing");
2313
+ const autoExpanded = defaultOpen || phase === "expanded" || phase === "fading";
2314
+ const isExpanded = expandedOverride ?? autoExpanded;
2315
+ const visualPhase = expandedOverride !== null || defaultOpen ? isExpanded ? "expanded" : "collapsed" : phase;
2316
+ useEffect7(() => {
2317
+ if (!isStreaming) return;
2318
+ if (!hasResponseStarted) {
2319
+ activityStoppedAtRef.current = null;
2320
+ return;
2321
+ }
2322
+ activityStoppedAtRef.current ??= Date.now();
2323
+ }, [hasResponseStarted, isStreaming]);
2324
+ const elapsedMs = startedAt !== void 0 && !isActivityStreaming ? Math.max(0, (activityStoppedAtRef.current ?? completedAt ?? Date.now()) - startedAt) : null;
2325
+ const completedSummary = elapsedMs === null ? "Activity" : `Worked for ${formatActivityDuration(elapsedMs)}`;
2326
+ const summary = isActivityStreaming || isAutoSettling ? liveSummary : elapsedMs === null ? "Activity" : completedSummary;
2327
+ const summaryItem = activeItem ?? latestItem;
2328
+ const summaryKind = summaryItem?.kind ?? inferActivityKind(summaryItem?.label ?? liveSummary);
2329
+ const SummaryIcon = activityIcons[summaryKind];
2330
+ const contentVersion = visibleItems.map(
2331
+ (item) => `${item.id}:${item.active ? 1 : 0}:${item.detail ?? ""}:${item.sources?.map((source) => source.label).join(",")}`
2332
+ ).join("|");
2174
2333
  useScrollShadow(panelRef);
2175
- useFollowNewestStep(panelRef, items.length, isStreaming, isExpanded);
2176
- return /* @__PURE__ */ jsxs5(Disclosure2, { className: "ha-activity", isExpanded, onExpandedChange: setIsExpanded, children: [
2177
- /* @__PURE__ */ jsx8(Disclosure2.Heading, { children: /* @__PURE__ */ jsxs5(Disclosure2.Trigger, { className: "ha-activity-trigger", children: [
2178
- isStreaming ? /* @__PURE__ */ jsx8(
2179
- AnimatedStatusText,
2180
- {
2181
- animateOnMount: summary !== progress,
2182
- className: "ha-activity-summary-label ha-progress ha-progress-shimmer",
2183
- role: "status",
2184
- children: summary
2185
- }
2186
- ) : /* @__PURE__ */ jsx8("span", { className: "ha-progress", children: summary }),
2187
- /* @__PURE__ */ jsx8(Disclosure2.Indicator, { className: "ha-activity-chevron" })
2188
- ] }) }),
2189
- /* @__PURE__ */ jsx8(Disclosure2.Content, { className: "ha-activity-disclosure-content", children: /* @__PURE__ */ jsx8(Disclosure2.Body, { children: /* @__PURE__ */ jsx8("div", { ref: panelRef, className: "ha-activity-panel", children: /* @__PURE__ */ jsxs5("ol", { "aria-label": "Thinking steps", children: [
2190
- items.map((item) => {
2191
- const Icon = activityIcons[item.kind ?? inferActivityKind(item.label)];
2192
- return /* @__PURE__ */ jsxs5(
2193
- "li",
2194
- {
2195
- "aria-current": item.active ? "step" : void 0,
2196
- className: "ha-activity-item",
2197
- "data-active": item.active || void 0,
2198
- children: [
2199
- /* @__PURE__ */ jsx8("span", { className: "ha-activity-icon", children: /* @__PURE__ */ jsx8(Icon, { "aria-hidden": "true" }) }),
2200
- /* @__PURE__ */ jsxs5("span", { className: "ha-activity-content", children: [
2201
- item.active ? /* @__PURE__ */ jsx8(AnimatedStatusText, { className: "ha-progress-shimmer", children: item.label }) : /* @__PURE__ */ jsx8("span", { children: item.label }),
2202
- item.detail ? /* @__PURE__ */ jsx8("small", { children: item.detail }) : null,
2203
- item.sources?.length ? /* @__PURE__ */ jsx8("span", { "aria-label": "Sources", className: "ha-activity-sources", children: item.sources.map((source) => /* @__PURE__ */ jsxs5("span", { className: "ha-activity-source", children: [
2204
- /* @__PURE__ */ jsx8(Globe, { "aria-hidden": "true" }),
2205
- source.label
2206
- ] }, source.label)) }) : null
2207
- ] })
2208
- ]
2209
- },
2210
- item.id
2211
- );
2212
- }),
2213
- !isStreaming ? /* @__PURE__ */ jsxs5("li", { className: "ha-activity-item", "data-complete": "true", children: [
2214
- /* @__PURE__ */ jsx8("span", { className: "ha-activity-icon", children: /* @__PURE__ */ jsx8(CircleCheck, { "aria-hidden": "true" }) }),
2215
- /* @__PURE__ */ jsx8("span", { className: "ha-activity-content", children: /* @__PURE__ */ jsx8("span", { children: "Done" }) })
2216
- ] }) : null
2217
- ] }) }) }) })
2218
- ] });
2334
+ useFollowNewestStep(panelRef, contentVersion, isActivityStreaming, isExpanded);
2335
+ return /* @__PURE__ */ jsxs6(
2336
+ Disclosure2,
2337
+ {
2338
+ className: "ha-activity",
2339
+ "data-phase": visualPhase,
2340
+ isExpanded,
2341
+ onExpandedChange: setExpandedOverride,
2342
+ children: [
2343
+ /* @__PURE__ */ jsx8(Disclosure2.Heading, { children: /* @__PURE__ */ jsxs6(Disclosure2.Trigger, { className: "ha-activity-trigger", children: [
2344
+ /* @__PURE__ */ jsx8("span", { "aria-hidden": "true", className: "ha-activity-summary-icon", children: /* @__PURE__ */ jsx8("span", { children: /* @__PURE__ */ jsx8(SummaryIcon, {}) }, summaryKind) }),
2345
+ isActivityStreaming || isAutoSettling ? /* @__PURE__ */ jsx8(
2346
+ AnimatedStatusText,
2347
+ {
2348
+ animateOnMount: liveSummary !== progress,
2349
+ className: "ha-activity-summary-label ha-progress ha-progress-shimmer",
2350
+ role: "status",
2351
+ children: summary
2352
+ }
2353
+ ) : /* @__PURE__ */ jsx8("span", { className: "ha-activity-summary-label ha-activity-summary-label--complete ha-progress", children: summary }),
2354
+ /* @__PURE__ */ jsx8(Disclosure2.Indicator, { className: "ha-activity-chevron" })
2355
+ ] }) }),
2356
+ /* @__PURE__ */ jsx8(Disclosure2.Content, { className: "ha-activity-disclosure-content", children: /* @__PURE__ */ jsx8(Disclosure2.Body, { children: /* @__PURE__ */ jsx8("div", { ref: panelRef, className: "ha-activity-panel", children: /* @__PURE__ */ jsxs6("ol", { "aria-label": "Thinking steps", children: [
2357
+ visibleItems.map((item) => /* @__PURE__ */ jsxs6(
2358
+ "li",
2359
+ {
2360
+ "aria-current": item.active ? "step" : void 0,
2361
+ className: "ha-activity-item",
2362
+ "data-active": item.active || void 0,
2363
+ "data-state": item.active ? "active" : "complete",
2364
+ children: [
2365
+ /* @__PURE__ */ jsx8(ActivityStateIcon, { active: item.active }),
2366
+ /* @__PURE__ */ jsxs6("span", { className: "ha-activity-content", children: [
2367
+ item.active ? /* @__PURE__ */ jsx8(AnimatedStatusText, { className: "ha-progress-shimmer", children: item.label }) : /* @__PURE__ */ jsx8("span", { children: item.label }),
2368
+ item.detail ? /* @__PURE__ */ jsx8("small", { className: "ha-activity-detail", "data-visible": item.active || void 0, children: /* @__PURE__ */ jsx8("span", { children: item.detail }) }) : null,
2369
+ item.sources?.length ? /* @__PURE__ */ jsx8("span", { "aria-label": "Sources", className: "ha-activity-sources", children: item.sources.map((source) => /* @__PURE__ */ jsxs6("span", { className: "ha-activity-source", children: [
2370
+ /* @__PURE__ */ jsx8(Globe, { "aria-hidden": "true" }),
2371
+ source.label
2372
+ ] }, source.label)) }) : null
2373
+ ] })
2374
+ ]
2375
+ },
2376
+ item.id
2377
+ )),
2378
+ !isActivityStreaming ? /* @__PURE__ */ jsxs6("li", { className: "ha-activity-item", "data-complete": "true", "data-state": "complete", children: [
2379
+ /* @__PURE__ */ jsx8(ActivityStateIcon, { active: false }),
2380
+ /* @__PURE__ */ jsx8("span", { className: "ha-activity-content", children: /* @__PURE__ */ jsx8("span", { children: "Final response ready" }) })
2381
+ ] }) : null
2382
+ ] }) }) }) })
2383
+ ]
2384
+ }
2385
+ );
2219
2386
  }
2220
2387
 
2221
2388
  // src/embed/agent-api.ts
@@ -2565,12 +2732,12 @@ function getComposerAttachmentMetadata(file) {
2565
2732
  }
2566
2733
 
2567
2734
  // src/embed/composer-attachment.tsx
2568
- import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
2735
+ import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
2569
2736
  function ComposerAttachment({ file, onRemove }) {
2570
2737
  const { Icon, kind, label } = getComposerAttachmentMetadata(file);
2571
- return /* @__PURE__ */ jsxs6("span", { className: "ha-attachment", "data-kind": kind, children: [
2738
+ return /* @__PURE__ */ jsxs7("span", { className: "ha-attachment", "data-kind": kind, children: [
2572
2739
  /* @__PURE__ */ jsx9("span", { "aria-hidden": "true", className: "ha-attachment-icon", children: /* @__PURE__ */ jsx9(Icon, {}) }),
2573
- /* @__PURE__ */ jsxs6("span", { className: "ha-attachment-copy", children: [
2740
+ /* @__PURE__ */ jsxs7("span", { className: "ha-attachment-copy", children: [
2574
2741
  /* @__PURE__ */ jsx9("span", { className: "ha-attachment-name", title: file.name, children: file.name }),
2575
2742
  /* @__PURE__ */ jsx9("span", { className: "ha-attachment-type", children: label })
2576
2743
  ] }),
@@ -2580,9 +2747,9 @@ function ComposerAttachment({ file, onRemove }) {
2580
2747
 
2581
2748
  // src/embed/composer-context.tsx
2582
2749
  import { Globe as Globe2, Xmark as Xmark2 } from "@gravity-ui/icons";
2583
- import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
2750
+ import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
2584
2751
  function ComposerContext({ onRemove, title }) {
2585
- return /* @__PURE__ */ jsx10("div", { className: "ha-context", children: /* @__PURE__ */ jsxs7(
2752
+ return /* @__PURE__ */ jsx10("div", { className: "ha-context", children: /* @__PURE__ */ jsxs8(
2586
2753
  "button",
2587
2754
  {
2588
2755
  "aria-label": `Remove Ask about this: ${title}`,
@@ -2591,7 +2758,7 @@ function ComposerContext({ onRemove, title }) {
2591
2758
  onClick: onRemove,
2592
2759
  children: [
2593
2760
  /* @__PURE__ */ jsx10(Globe2, { "aria-hidden": "true", className: "ha-chip-leading" }),
2594
- /* @__PURE__ */ jsxs7("span", { className: "ha-chip-title", title, children: [
2761
+ /* @__PURE__ */ jsxs8("span", { className: "ha-chip-title", title, children: [
2595
2762
  "Ask about this: ",
2596
2763
  title
2597
2764
  ] }),
@@ -2602,7 +2769,7 @@ function ComposerContext({ onRemove, title }) {
2602
2769
  }
2603
2770
 
2604
2771
  // src/embed/composer-file-dropzone.tsx
2605
- import { useCallback as useCallback4, useState as useState5 } from "react";
2772
+ import { useCallback as useCallback4, useState as useState6 } from "react";
2606
2773
  import { jsx as jsx11 } from "react/jsx-runtime";
2607
2774
  function hasFileTransfer(event) {
2608
2775
  return event.dataTransfer?.types?.includes("Files") ?? false;
@@ -2615,7 +2782,7 @@ function ComposerFileDropzone({
2615
2782
  disabled = false,
2616
2783
  onFilesSelected
2617
2784
  }) {
2618
- const [isDragging, setIsDragging] = useState5(false);
2785
+ const [isDragging, setIsDragging] = useState6(false);
2619
2786
  const handleDragEnter = useCallback4(
2620
2787
  (event) => {
2621
2788
  if (disabled || !hasFileTransfer(event)) return;
@@ -2732,7 +2899,7 @@ function removeConversationActivity(current, conversationId) {
2732
2899
  // src/embed/conversation-markdown.tsx
2733
2900
  import { Code as Code2, Heading, Link, Paragraph, Separator, Table } from "@heroui/react";
2734
2901
  import { Children, Suspense, isValidElement, lazy, memo, useMemo } from "react";
2735
- import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
2902
+ import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
2736
2903
  var LazyStreamdown = lazy(
2737
2904
  () => import("streamdown").then((module) => ({ default: module.Streamdown }))
2738
2905
  );
@@ -2760,7 +2927,7 @@ function MarkdownTable({ children }) {
2760
2927
  const headerRow = findElementByTag(tableHead?.props.children, "tr");
2761
2928
  const headerCells = getElementChildren(headerRow);
2762
2929
  const rows = getElementChildren(tableBody);
2763
- return /* @__PURE__ */ jsx12(Table, { "data-slot": "markdown-table", variant: "secondary", children: /* @__PURE__ */ jsx12(Table.ScrollContainer, { children: /* @__PURE__ */ jsxs8(Table.Content, { "aria-label": "Markdown table", children: [
2930
+ return /* @__PURE__ */ jsx12(Table, { "data-slot": "markdown-table", variant: "secondary", children: /* @__PURE__ */ jsx12(Table.ScrollContainer, { children: /* @__PURE__ */ jsxs9(Table.Content, { "aria-label": "Markdown table", children: [
2764
2931
  /* @__PURE__ */ jsx12(Table.Header, { children: headerCells.map((cell, index) => /* @__PURE__ */ jsx12(Table.Column, { id: `column-${index}`, children: cell.props.children }, String(cell.key))) }),
2765
2932
  /* @__PURE__ */ jsx12(Table.Body, { children: rows.map((row, rowIndex) => /* @__PURE__ */ jsx12(Table.Row, { id: `row-${rowIndex}`, children: getElementChildren(row).map((cell) => /* @__PURE__ */ jsx12(Table.Cell, { children: cell.props.children }, String(cell.key))) }, String(row.key))) })
2766
2933
  ] }) }) });
@@ -2904,7 +3071,6 @@ function ConversationRouteStack({
2904
3071
 
2905
3072
  // src/embed/conversation-turn-anchor.ts
2906
3073
  function resolveConversationTurnAnchor({
2907
- conversationId,
2908
3074
  isActive,
2909
3075
  lastUserMessageId,
2910
3076
  pendingTurn
@@ -2912,22 +3078,21 @@ function resolveConversationTurnAnchor({
2912
3078
  const normalizedLastUserMessageId = lastUserMessageId ?? null;
2913
3079
  const hasActiveOptimisticUser = pendingTurn ? normalizedLastUserMessageId !== pendingTurn.previousUserMessageId : normalizedLastUserMessageId !== null;
2914
3080
  const activeTurnMessageId = isActive ? hasActiveOptimisticUser ? normalizedLastUserMessageId : null : normalizedLastUserMessageId;
2915
- const activeStreamKey = isActive ? pendingTurn?.messageId ?? activeTurnMessageId ?? conversationId : null;
3081
+ const activeStreamKey = isActive ? pendingTurn?.scrollKey ?? null : null;
2916
3082
  return { activeStreamKey, activeTurnMessageId };
2917
3083
  }
2918
3084
 
2919
3085
  // src/embed/conversation-viewport.tsx
2920
3086
  import { ChevronDown } from "@gravity-ui/icons";
2921
3087
  import { Button } from "@heroui/react";
2922
- import { useLayoutEffect as useLayoutEffect2, useRef as useRef8 } from "react";
3088
+ import { useLayoutEffect as useLayoutEffect2, useRef as useRef7 } from "react";
2923
3089
 
2924
3090
  // src/embed/use-conversation-scroll.ts
2925
- import { useCallback as useCallback5, useEffect as useEffect9, useLayoutEffect, useRef as useRef7, useState as useState6 } from "react";
3091
+ import { useCallback as useCallback5, useEffect as useEffect9, useLayoutEffect, useRef as useRef6, useState as useState7 } from "react";
2926
3092
  var BOTTOM_THRESHOLD = 4;
2927
3093
  var SCROLL_DIRECTION_THRESHOLD = 1;
2928
3094
  var ACTIVE_TURN_SPACER_PROPERTY = "--ha-active-turn-spacer-height";
2929
- var STREAM_ANCHOR_SELECTOR = '[data-stream-anchor="true"]';
2930
- var TURN_ANCHOR_SELECTOR = '[data-turn-anchor="true"]';
3095
+ var USER_STREAM_ANCHOR_SELECTOR = '[data-role="user"][data-stream-anchor="true"]';
2931
3096
  var DEFAULT_SCROLL_STATE = {
2932
3097
  hasOverflow: false,
2933
3098
  isAtBottom: true
@@ -2956,23 +3121,25 @@ function getNativeScrollBehavior(behavior) {
2956
3121
  return "auto";
2957
3122
  }
2958
3123
  function useConversationScroll(ref) {
2959
- const activeTurnSpacerHeightRef = useRef7(0);
2960
- const attachedRef = useRef7(true);
2961
- const currentStreamKeyRef = useRef7(null);
2962
- const isAutoScrollingRef = useRef7(false);
2963
- const isPinnedTurnAnimatingRef = useRef7(false);
2964
- const lastScrollTopRef = useRef7(0);
2965
- const pinnedStreamKeyRef = useRef7(null);
2966
- const pinnedStreamTopRef = useRef7(null);
2967
- const shouldAnimatePinnedTurnRef = useRef7(false);
2968
- const [scrollState, setScrollState] = useState6(DEFAULT_SCROLL_STATE);
3124
+ const activeTurnSpacerHeightRef = useRef6(0);
3125
+ const attachedRef = useRef6(true);
3126
+ const automaticFollowSuppressedRef = useRef6(false);
3127
+ const currentStreamKeyRef = useRef6(null);
3128
+ const isAutoScrollingRef = useRef6(false);
3129
+ const isPinnedTurnAnimatingRef = useRef6(false);
3130
+ const lastPinnedStreamKeyRef = useRef6(null);
3131
+ const lastScrollTopRef = useRef6(0);
3132
+ const pinnedStreamKeyRef = useRef6(null);
3133
+ const pinnedStreamTopRef = useRef6(null);
3134
+ const shouldAnimatePinnedTurnRef = useRef6(false);
3135
+ const [scrollState, setScrollState] = useState7(DEFAULT_SCROLL_STATE);
2969
3136
  const setNextScrollState = useCallback5((nextState) => {
2970
3137
  setScrollState(
2971
3138
  (currentState) => isSameScrollState(currentState, nextState) ? currentState : nextState
2972
3139
  );
2973
3140
  }, []);
2974
3141
  const updateActiveTurnSpacer = useCallback5((element) => {
2975
- const anchor = element.querySelector(STREAM_ANCHOR_SELECTOR) ?? element.querySelector(TURN_ANCHOR_SELECTOR);
3142
+ const anchor = pinnedStreamKeyRef.current ? element.querySelector(USER_STREAM_ANCHOR_SELECTOR) : null;
2976
3143
  let nextHeight = 0;
2977
3144
  if (anchor) {
2978
3145
  const containerRect = element.getBoundingClientRect();
@@ -3001,14 +3168,17 @@ function useConversationScroll(ref) {
3001
3168
  pinnedStreamTopRef.current = null;
3002
3169
  isPinnedTurnAnimatingRef.current = false;
3003
3170
  shouldAnimatePinnedTurnRef.current = false;
3171
+ updateActiveTurnSpacer(element);
3004
3172
  attachedRef.current = true;
3005
- isAutoScrollingRef.current = true;
3173
+ automaticFollowSuppressedRef.current = false;
3006
3174
  lastScrollTopRef.current = element.scrollTop;
3007
3175
  setNextScrollState({
3008
3176
  hasOverflow: getConversationScrollState(element).hasOverflow,
3009
3177
  isAtBottom: true
3010
3178
  });
3011
3179
  const top = element.scrollHeight;
3180
+ const targetTop = Math.max(0, top - element.clientHeight);
3181
+ isAutoScrollingRef.current = Math.abs(Math.max(0, element.scrollTop) - targetTop) > SCROLL_DIRECTION_THRESHOLD;
3012
3182
  if (typeof element.scrollTo === "function") {
3013
3183
  element.scrollTo({ behavior: getNativeScrollBehavior(behavior), top });
3014
3184
  } else {
@@ -3016,11 +3186,11 @@ function useConversationScroll(ref) {
3016
3186
  }
3017
3187
  lastScrollTopRef.current = Math.max(0, element.scrollTop);
3018
3188
  },
3019
- [ref, setNextScrollState]
3189
+ [ref, setNextScrollState, updateActiveTurnSpacer]
3020
3190
  );
3021
3191
  const getPinnedStreamTop = useCallback5((element) => {
3022
3192
  if (!pinnedStreamKeyRef.current) return null;
3023
- const anchor = element.querySelector(STREAM_ANCHOR_SELECTOR);
3193
+ const anchor = element.querySelector(USER_STREAM_ANCHOR_SELECTOR);
3024
3194
  if (anchor) {
3025
3195
  const paddingTop = Number.parseFloat(window.getComputedStyle(element).paddingTop) || 0;
3026
3196
  pinnedStreamTopRef.current = Math.max(0, anchor.offsetTop - paddingTop);
@@ -3032,8 +3202,9 @@ function useConversationScroll(ref) {
3032
3202
  const maximumScrollTop = Math.max(0, element.scrollHeight - element.clientHeight);
3033
3203
  const targetTop = Math.min(top, maximumScrollTop);
3034
3204
  const nativeBehavior = getNativeScrollBehavior(behavior);
3035
- isPinnedTurnAnimatingRef.current = nativeBehavior === "smooth" && Math.abs(Math.max(0, element.scrollTop) - targetTop) > SCROLL_DIRECTION_THRESHOLD;
3036
- isAutoScrollingRef.current = true;
3205
+ const hasMovement = Math.abs(Math.max(0, element.scrollTop) - targetTop) > SCROLL_DIRECTION_THRESHOLD;
3206
+ isPinnedTurnAnimatingRef.current = nativeBehavior === "smooth" && hasMovement;
3207
+ isAutoScrollingRef.current = hasMovement;
3037
3208
  lastScrollTopRef.current = element.scrollTop;
3038
3209
  setNextScrollState({
3039
3210
  hasOverflow: maximumScrollTop > BOTTOM_THRESHOLD,
@@ -3052,26 +3223,30 @@ function useConversationScroll(ref) {
3052
3223
  const maintainScrollPosition = useCallback5(() => {
3053
3224
  const element = ref.current;
3054
3225
  if (!element) return;
3055
- const activeTurnSpacerHeight = updateActiveTurnSpacer(element);
3226
+ updateActiveTurnSpacer(element);
3056
3227
  const measuredState = getConversationScrollState(element);
3057
3228
  const scrollTop = Math.max(0, element.scrollTop);
3058
3229
  const scrolledUp = scrollTop < lastScrollTopRef.current - SCROLL_DIRECTION_THRESHOLD;
3059
3230
  lastScrollTopRef.current = scrollTop;
3060
3231
  if (scrolledUp && !measuredState.isAtBottom) {
3061
3232
  attachedRef.current = false;
3233
+ automaticFollowSuppressedRef.current = true;
3062
3234
  isAutoScrollingRef.current = false;
3063
3235
  isPinnedTurnAnimatingRef.current = false;
3064
3236
  pinnedStreamKeyRef.current = null;
3065
3237
  pinnedStreamTopRef.current = null;
3066
3238
  shouldAnimatePinnedTurnRef.current = false;
3239
+ updateActiveTurnSpacer(element);
3067
3240
  setNextScrollState(measuredState);
3068
3241
  return;
3069
3242
  }
3070
- if (!measuredState.hasOverflow || measuredState.isAtBottom) {
3243
+ if (!automaticFollowSuppressedRef.current && (!measuredState.hasOverflow || measuredState.isAtBottom)) {
3071
3244
  attachedRef.current = true;
3072
3245
  }
3073
- if (attachedRef.current) {
3074
- const pinnedStreamTop = getPinnedStreamTop(element);
3246
+ const hasPinnedStream = pinnedStreamKeyRef.current !== null;
3247
+ const pinnedStreamTop = getPinnedStreamTop(element);
3248
+ if (hasPinnedStream) {
3249
+ automaticFollowSuppressedRef.current = true;
3075
3250
  if (pinnedStreamTop !== null && isPinnedTurnAnimatingRef.current) {
3076
3251
  const maximumScrollTop = Math.max(0, element.scrollHeight - element.clientHeight);
3077
3252
  const targetTop = Math.min(pinnedStreamTop, maximumScrollTop);
@@ -3082,16 +3257,20 @@ function useConversationScroll(ref) {
3082
3257
  isAutoScrollingRef.current = false;
3083
3258
  isPinnedTurnAnimatingRef.current = false;
3084
3259
  }
3085
- if (pinnedStreamTop !== null && activeTurnSpacerHeight > BOTTOM_THRESHOLD) {
3086
- const behavior = shouldAnimatePinnedTurnRef.current ? "smooth" : "auto";
3260
+ if (pinnedStreamTop !== null && shouldAnimatePinnedTurnRef.current) {
3087
3261
  shouldAnimatePinnedTurnRef.current = false;
3088
- scrollToPinnedPosition(element, pinnedStreamTop, behavior);
3262
+ scrollToPinnedPosition(element, pinnedStreamTop, "smooth");
3089
3263
  return;
3090
3264
  }
3265
+ attachedRef.current = false;
3266
+ setNextScrollState(measuredState);
3267
+ return;
3268
+ }
3269
+ if (attachedRef.current && !automaticFollowSuppressedRef.current) {
3091
3270
  scrollToBottom("auto");
3092
3271
  return;
3093
3272
  }
3094
- setNextScrollState({ hasOverflow: measuredState.hasOverflow, isAtBottom: false });
3273
+ setNextScrollState(measuredState);
3095
3274
  }, [
3096
3275
  getPinnedStreamTop,
3097
3276
  ref,
@@ -3106,29 +3285,43 @@ function useConversationScroll(ref) {
3106
3285
  if (!element || currentStreamKeyRef.current === streamKey) return;
3107
3286
  const hadActiveStream = currentStreamKeyRef.current !== null;
3108
3287
  currentStreamKeyRef.current = streamKey;
3109
- pinnedStreamKeyRef.current = streamKey;
3110
- pinnedStreamTopRef.current = null;
3111
3288
  if (streamKey) {
3112
- if (!hadActiveStream) {
3289
+ const startsNewUserTurn = lastPinnedStreamKeyRef.current !== streamKey;
3290
+ if (startsNewUserTurn) {
3291
+ lastPinnedStreamKeyRef.current = streamKey;
3292
+ pinnedStreamKeyRef.current = streamKey;
3293
+ pinnedStreamTopRef.current = null;
3113
3294
  shouldAnimatePinnedTurnRef.current = true;
3295
+ automaticFollowSuppressedRef.current = true;
3296
+ attachedRef.current = true;
3297
+ } else {
3298
+ pinnedStreamKeyRef.current = null;
3299
+ pinnedStreamTopRef.current = null;
3300
+ shouldAnimatePinnedTurnRef.current = false;
3301
+ updateActiveTurnSpacer(element);
3114
3302
  }
3115
- attachedRef.current = true;
3116
3303
  } else if (hadActiveStream) {
3304
+ pinnedStreamKeyRef.current = null;
3305
+ pinnedStreamTopRef.current = null;
3117
3306
  isAutoScrollingRef.current = false;
3118
3307
  isPinnedTurnAnimatingRef.current = false;
3119
3308
  shouldAnimatePinnedTurnRef.current = false;
3309
+ automaticFollowSuppressedRef.current = true;
3310
+ updateActiveTurnSpacer(element);
3120
3311
  const measuredState = getConversationScrollState(element);
3121
- attachedRef.current = measuredState.isAtBottom;
3312
+ attachedRef.current = false;
3122
3313
  setNextScrollState(measuredState);
3123
3314
  }
3124
3315
  },
3125
- [ref, setNextScrollState]
3316
+ [ref, setNextScrollState, updateActiveTurnSpacer]
3126
3317
  );
3127
3318
  useLayoutEffect(() => {
3128
3319
  const element = ref.current;
3129
3320
  if (!element) return;
3130
3321
  lastScrollTopRef.current = element.scrollTop;
3131
3322
  maintainScrollPosition();
3323
+ automaticFollowSuppressedRef.current = true;
3324
+ attachedRef.current = false;
3132
3325
  }, [maintainScrollPosition, ref]);
3133
3326
  useEffect9(() => {
3134
3327
  const element = ref.current;
@@ -3147,9 +3340,13 @@ function useConversationScroll(ref) {
3147
3340
  if (reachedAutomaticTarget) {
3148
3341
  isAutoScrollingRef.current = false;
3149
3342
  isPinnedTurnAnimatingRef.current = false;
3343
+ if (pinnedStreamTop !== null) {
3344
+ automaticFollowSuppressedRef.current = true;
3345
+ attachedRef.current = false;
3346
+ }
3150
3347
  }
3151
3348
  setNextScrollState(
3152
- wasPinnedTurnAnimating && !reachedAutomaticTarget ? { hasOverflow: measuredState.hasOverflow, isAtBottom: true } : pinnedStreamTop === null ? { hasOverflow: measuredState.hasOverflow, isAtBottom: attachedRef.current } : measuredState
3349
+ wasPinnedTurnAnimating && !reachedAutomaticTarget ? { hasOverflow: measuredState.hasOverflow, isAtBottom: true } : pinnedStreamTop === null ? automaticFollowSuppressedRef.current ? measuredState : { hasOverflow: measuredState.hasOverflow, isAtBottom: attachedRef.current } : measuredState
3153
3350
  );
3154
3351
  return;
3155
3352
  }
@@ -3158,7 +3355,9 @@ function useConversationScroll(ref) {
3158
3355
  pinnedStreamKeyRef.current = null;
3159
3356
  pinnedStreamTopRef.current = null;
3160
3357
  shouldAnimatePinnedTurnRef.current = false;
3358
+ updateActiveTurnSpacer(element);
3161
3359
  attachedRef.current = measuredState.isAtBottom;
3360
+ automaticFollowSuppressedRef.current = !measuredState.isAtBottom;
3162
3361
  setNextScrollState(measuredState);
3163
3362
  };
3164
3363
  element.addEventListener("scroll", handleScroll, { passive: true });
@@ -3201,7 +3400,7 @@ function useConversationScroll(ref) {
3201
3400
  resizeObserver.disconnect();
3202
3401
  }
3203
3402
  };
3204
- }, [getPinnedStreamTop, maintainScrollPosition, ref, setNextScrollState]);
3403
+ }, [getPinnedStreamTop, maintainScrollPosition, ref, setNextScrollState, updateActiveTurnSpacer]);
3205
3404
  return {
3206
3405
  hasOverflow: scrollState.hasOverflow,
3207
3406
  isAtBottom: scrollState.isAtBottom,
@@ -3212,12 +3411,12 @@ function useConversationScroll(ref) {
3212
3411
  }
3213
3412
 
3214
3413
  // src/embed/conversation-viewport.tsx
3215
- import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
3414
+ import { jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
3216
3415
  function ConversationViewport({
3217
3416
  children,
3218
3417
  streamKey = null
3219
3418
  }) {
3220
- const scrollRef = useRef8(null);
3419
+ const scrollRef = useRef7(null);
3221
3420
  const { hasOverflow, isAtBottom, maintainScrollPosition, scrollToBottom, setPinnedStream } = useConversationScroll(scrollRef);
3222
3421
  const isScrollButtonVisible = hasOverflow && !isAtBottom;
3223
3422
  useScrollShadow(scrollRef);
@@ -3225,7 +3424,7 @@ function ConversationViewport({
3225
3424
  setPinnedStream(streamKey);
3226
3425
  maintainScrollPosition();
3227
3426
  }, [children, maintainScrollPosition, setPinnedStream, streamKey]);
3228
- return /* @__PURE__ */ jsxs9("div", { className: "ha-conversation", children: [
3427
+ return /* @__PURE__ */ jsxs10("div", { className: "ha-conversation", children: [
3229
3428
  /* @__PURE__ */ jsx14("div", { ref: scrollRef, "aria-live": "polite", className: "ha-messages", role: "log", children }),
3230
3429
  /* @__PURE__ */ jsx14(
3231
3430
  "div",
@@ -3258,7 +3457,7 @@ import { Suspense as Suspense2, lazy as lazy2 } from "react";
3258
3457
  // src/embed/genui-renderer-loader.ts
3259
3458
  var componentRendererPromise;
3260
3459
  function loadGenUIRenderer() {
3261
- componentRendererPromise ??= import("./component-renderer-PTMCOJHE.js").then(
3460
+ componentRendererPromise ??= import("./component-renderer-46EJDPTB.js").then(
3262
3461
  (module) => ({ default: module.ComponentRenderer })
3263
3462
  );
3264
3463
  return componentRendererPromise;
@@ -3279,8 +3478,8 @@ function GenUIRenderer(props) {
3279
3478
  // src/embed/message-actions.tsx
3280
3479
  import { ArrowsRotateLeft, Check, Copy, ThumbsDown, ThumbsUp } from "@gravity-ui/icons";
3281
3480
  import { Button as Button2, Popover, TextArea } from "@heroui/react";
3282
- import { useCallback as useCallback6, useEffect as useEffect10, useRef as useRef9, useState as useState7 } from "react";
3283
- import { Fragment, jsx as jsx16, jsxs as jsxs10 } from "react/jsx-runtime";
3481
+ import { useCallback as useCallback6, useEffect as useEffect10, useRef as useRef8, useState as useState8 } from "react";
3482
+ import { Fragment, jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
3284
3483
  var COPY_RESET_DELAY = 2e3;
3285
3484
  var FEEDBACK_COMMENT_MAX_LENGTH = 1e3;
3286
3485
  var NEGATIVE_FEEDBACK_REASONS = [
@@ -3298,13 +3497,13 @@ function MessageActions({
3298
3497
  onFeedback,
3299
3498
  onRetry
3300
3499
  }) {
3301
- const [isCopied, setIsCopied] = useState7(false);
3302
- const [isFeedbackOpen, setIsFeedbackOpen] = useState7(false);
3303
- const [feedbackComment, setFeedbackComment] = useState7("");
3304
- const [feedbackReasons, setFeedbackReasons] = useState7([]);
3305
- const [feedbackPortalContainer, setFeedbackPortalContainer] = useState7();
3306
- const resetTimeoutRef = useRef9(null);
3307
- const feedbackOpenedAtRef = useRef9(0);
3500
+ const [isCopied, setIsCopied] = useState8(false);
3501
+ const [isFeedbackOpen, setIsFeedbackOpen] = useState8(false);
3502
+ const [feedbackComment, setFeedbackComment] = useState8("");
3503
+ const [feedbackReasons, setFeedbackReasons] = useState8([]);
3504
+ const [feedbackPortalContainer, setFeedbackPortalContainer] = useState8();
3505
+ const resetTimeoutRef = useRef8(null);
3506
+ const feedbackOpenedAtRef = useRef8(0);
3308
3507
  const feedbackTriggerRef = useCallback6((node) => {
3309
3508
  setFeedbackPortalContainer(node?.closest(".ha-panel") ?? void 0);
3310
3509
  }, []);
@@ -3343,7 +3542,7 @@ function MessageActions({
3343
3542
  });
3344
3543
  setIsFeedbackOpen(false);
3345
3544
  };
3346
- return /* @__PURE__ */ jsxs10("div", { "aria-label": "Message actions", className: "ha-message-actions", role: "group", children: [
3545
+ return /* @__PURE__ */ jsxs11("div", { "aria-label": "Message actions", className: "ha-message-actions", role: "group", children: [
3347
3546
  showCopy ? /* @__PURE__ */ jsx16(
3348
3547
  "button",
3349
3548
  {
@@ -3355,7 +3554,7 @@ function MessageActions({
3355
3554
  children: /* @__PURE__ */ jsx16("span", { className: "ha-message-action-icon", children: isCopied ? /* @__PURE__ */ jsx16(Check, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx16(Copy, { "aria-hidden": "true" }) }, isCopied ? "check" : "copy")
3356
3555
  }
3357
3556
  ) : null,
3358
- showFeedback ? /* @__PURE__ */ jsxs10(Fragment, { children: [
3557
+ showFeedback ? /* @__PURE__ */ jsxs11(Fragment, { children: [
3359
3558
  /* @__PURE__ */ jsx16(
3360
3559
  "button",
3361
3560
  {
@@ -3368,7 +3567,7 @@ function MessageActions({
3368
3567
  children: /* @__PURE__ */ jsx16(ThumbsUp, { "aria-hidden": "true" })
3369
3568
  }
3370
3569
  ),
3371
- /* @__PURE__ */ jsxs10(Popover, { isOpen: isFeedbackOpen, onOpenChange: handleFeedbackOpenChange, children: [
3570
+ /* @__PURE__ */ jsxs11(Popover, { isOpen: isFeedbackOpen, onOpenChange: handleFeedbackOpenChange, children: [
3372
3571
  /* @__PURE__ */ jsx16(
3373
3572
  Button2,
3374
3573
  {
@@ -3394,7 +3593,7 @@ function MessageActions({
3394
3593
  offset: 8,
3395
3594
  placement: "top start",
3396
3595
  UNSTABLE_portalContainer: feedbackPortalContainer,
3397
- children: /* @__PURE__ */ jsxs10(Popover.Dialog, { className: "ha-feedback-dialog", children: [
3596
+ children: /* @__PURE__ */ jsxs11(Popover.Dialog, { className: "ha-feedback-dialog", children: [
3398
3597
  /* @__PURE__ */ jsx16(Popover.Heading, { className: "ha-feedback-heading", children: "Help us improve" }),
3399
3598
  /* @__PURE__ */ jsx16("p", { className: "ha-feedback-description", children: "What could be better?" }),
3400
3599
  /* @__PURE__ */ jsx16("div", { "aria-label": "Feedback reasons", className: "ha-feedback-reasons", role: "group", children: NEGATIVE_FEEDBACK_REASONS.map((reason) => {
@@ -3427,7 +3626,7 @@ function MessageActions({
3427
3626
  }
3428
3627
  ),
3429
3628
  /* @__PURE__ */ jsx16("p", { className: "ha-feedback-privacy", children: "Avoid sharing sensitive information." }),
3430
- /* @__PURE__ */ jsxs10("div", { className: "ha-feedback-footer", children: [
3629
+ /* @__PURE__ */ jsxs11("div", { className: "ha-feedback-footer", children: [
3431
3630
  /* @__PURE__ */ jsx16(
3432
3631
  Button2,
3433
3632
  {
@@ -3468,7 +3667,7 @@ function MessageActions({
3468
3667
  }
3469
3668
 
3470
3669
  // src/embed/message-attachment.tsx
3471
- import { jsx as jsx17, jsxs as jsxs11 } from "react/jsx-runtime";
3670
+ import { jsx as jsx17, jsxs as jsxs12 } from "react/jsx-runtime";
3472
3671
  function MessageAttachment({ file }) {
3473
3672
  const name = file.filename?.trim() || "Attachment";
3474
3673
  const type = file.mediaType?.trim() || "";
@@ -3488,7 +3687,7 @@ function MessageAttachment({ file }) {
3488
3687
  }
3489
3688
  );
3490
3689
  }
3491
- return /* @__PURE__ */ jsxs11(
3690
+ return /* @__PURE__ */ jsxs12(
3492
3691
  "a",
3493
3692
  {
3494
3693
  className: "ha-message-file",
@@ -3499,7 +3698,7 @@ function MessageAttachment({ file }) {
3499
3698
  target: "_blank",
3500
3699
  children: [
3501
3700
  /* @__PURE__ */ jsx17("span", { "aria-hidden": "true", className: "ha-message-file-icon", children: /* @__PURE__ */ jsx17(Icon, {}) }),
3502
- /* @__PURE__ */ jsxs11("span", { className: "ha-message-file-copy", children: [
3701
+ /* @__PURE__ */ jsxs12("span", { className: "ha-message-file-copy", children: [
3503
3702
  /* @__PURE__ */ jsx17("span", { className: "ha-message-file-name", title: name, children: name }),
3504
3703
  /* @__PURE__ */ jsx17("span", { className: "ha-message-file-type", children: label })
3505
3704
  ] })
@@ -3650,23 +3849,23 @@ function handleMessageQueueComposerKeyDown(event, queue) {
3650
3849
 
3651
3850
  // src/embed/message-queue-list.tsx
3652
3851
  import { ArrowUp, CircleExclamation, Clock, Grip, Pencil, TrashBin } from "@gravity-ui/icons";
3653
- import { useImperativeHandle, useLayoutEffect as useLayoutEffect3, useRef as useRef11 } from "react";
3852
+ import { useImperativeHandle, useLayoutEffect as useLayoutEffect3, useRef as useRef10 } from "react";
3654
3853
 
3655
3854
  // src/embed/use-message-queue-reorder.ts
3656
- import { useRef as useRef10, useState as useState8 } from "react";
3855
+ import { useRef as useRef9, useState as useState9 } from "react";
3657
3856
  function useMessageQueueReorder({
3658
3857
  messages,
3659
3858
  onReorder,
3660
3859
  onReorderStateChange
3661
3860
  }) {
3662
- const dragStateRef = useRef10(null);
3663
- const dropTargetRef = useRef10(null);
3664
- const positionPickerMessageIdRef = useRef10(null);
3665
- const suppressedClickMessageIdRef = useRef10(null);
3666
- const [announcement, setAnnouncement] = useState8("");
3667
- const [draggedMessageId, setDraggedMessageId] = useState8(null);
3668
- const [dropTarget, setDropTarget] = useState8(null);
3669
- const [positionPickerMessageId, setPositionPickerMessageId] = useState8(null);
3861
+ const dragStateRef = useRef9(null);
3862
+ const dropTargetRef = useRef9(null);
3863
+ const positionPickerMessageIdRef = useRef9(null);
3864
+ const suppressedClickMessageIdRef = useRef9(null);
3865
+ const [announcement, setAnnouncement] = useState9("");
3866
+ const [draggedMessageId, setDraggedMessageId] = useState9(null);
3867
+ const [dropTarget, setDropTarget] = useState9(null);
3868
+ const [positionPickerMessageId, setPositionPickerMessageId] = useState9(null);
3670
3869
  const updateDropTarget = (nextTarget) => {
3671
3870
  dropTargetRef.current = nextTarget;
3672
3871
  setDropTarget(nextTarget);
@@ -3814,7 +4013,7 @@ function useMessageQueueReorder({
3814
4013
  }
3815
4014
 
3816
4015
  // src/embed/message-queue-list.tsx
3817
- import { jsx as jsx18, jsxs as jsxs12 } from "react/jsx-runtime";
4016
+ import { jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
3818
4017
  function focusQueueMessageAt(list, index) {
3819
4018
  const item = list?.querySelectorAll("[data-queue-message-id]")[index];
3820
4019
  if (!item) return false;
@@ -3834,9 +4033,9 @@ function MessageQueueList({
3834
4033
  onSendNow,
3835
4034
  ref
3836
4035
  }) {
3837
- const focusedMessageIdRef = useRef11(null);
3838
- const listRef = useRef11(null);
3839
- const previousMessagesRef = useRef11(messages);
4036
+ const focusedMessageIdRef = useRef10(null);
4037
+ const listRef = useRef10(null);
4038
+ const previousMessagesRef = useRef10(messages);
3840
4039
  const {
3841
4040
  announcement,
3842
4041
  closePositionPicker,
@@ -3878,7 +4077,7 @@ function MessageQueueList({
3878
4077
  }
3879
4078
  if (!focusQueueMessageAt(listRef.current, index + 1)) onFocusComposer();
3880
4079
  };
3881
- return /* @__PURE__ */ jsxs12("section", { "aria-label": "Queued messages", className: "ha-message-queue", children: [
4080
+ return /* @__PURE__ */ jsxs13("section", { "aria-label": "Queued messages", className: "ha-message-queue", children: [
3882
4081
  /* @__PURE__ */ jsx18("div", { className: "ha-message-queue-header", children: "Queued" }),
3883
4082
  /* @__PURE__ */ jsx18("ol", { ref: listRef, className: "ha-message-queue-list", children: messages.map((message, index) => {
3884
4083
  const isBlocked = blockedMessageId === message.id;
@@ -3886,7 +4085,7 @@ function MessageQueueList({
3886
4085
  const statusId = isBlocked ? `ha-queued-message-status-${message.id}` : void 0;
3887
4086
  return (
3888
4087
  // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions -- Queue rows are programmatically focused for arrow-key navigation; nested controls keep their own key handling.
3889
- /* @__PURE__ */ jsxs12(
4088
+ /* @__PURE__ */ jsxs13(
3890
4089
  "li",
3891
4090
  {
3892
4091
  "aria-describedby": statusId,
@@ -3936,18 +4135,18 @@ function MessageQueueList({
3936
4135
  value: index,
3937
4136
  onBlur: () => closePositionPicker(message.id),
3938
4137
  onChange: (event) => moveMessageToPosition(message.id, index, Number(event.currentTarget.value)),
3939
- children: messages.map((queuedMessage, position) => /* @__PURE__ */ jsxs12("option", { value: position, children: [
4138
+ children: messages.map((queuedMessage, position) => /* @__PURE__ */ jsxs13("option", { value: position, children: [
3940
4139
  "Position ",
3941
4140
  position + 1,
3942
4141
  position === index ? " (current)" : ""
3943
4142
  ] }, queuedMessage.id))
3944
4143
  }
3945
4144
  ) : /* @__PURE__ */ jsx18("span", { "aria-hidden": "true", className: "ha-message-queue-icon", children: isBlocked ? /* @__PURE__ */ jsx18(CircleExclamation, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx18(Clock, { "aria-hidden": "true" }) }),
3946
- /* @__PURE__ */ jsxs12("span", { className: "ha-message-queue-content", children: [
4145
+ /* @__PURE__ */ jsxs13("span", { className: "ha-message-queue-content", children: [
3947
4146
  /* @__PURE__ */ jsx18("span", { className: "ha-message-queue-preview", children: getQueuedAgentMessagePreview(message) }),
3948
4147
  isBlocked ? /* @__PURE__ */ jsx18("span", { className: "ha-message-queue-status", id: statusId, role: "status", children: "Could not send" }) : null
3949
4148
  ] }),
3950
- /* @__PURE__ */ jsxs12("span", { className: "ha-message-queue-actions", children: [
4149
+ /* @__PURE__ */ jsxs13("span", { className: "ha-message-queue-actions", children: [
3951
4150
  /* @__PURE__ */ jsx18(
3952
4151
  "button",
3953
4152
  {
@@ -4001,7 +4200,7 @@ import { composeRenderProps as composeRenderProps2 } from "react-aria-components
4001
4200
  // ../agent-ui/src/components/hover-card/hover-card.tsx
4002
4201
  import { mergeRefs } from "@react-aria/utils";
4003
4202
  import { useControlledState } from "@react-stately/utils";
4004
- import { createContext, useCallback as useCallback7, useContext, useEffect as useEffect11, useMemo as useMemo2, useRef as useRef12, useState as useState9 } from "react";
4203
+ import { createContext, useCallback as useCallback7, useContext, useEffect as useEffect11, useMemo as useMemo2, useRef as useRef11, useState as useState10 } from "react";
4005
4204
  import {
4006
4205
  OverlayArrow as OverlayArrowPrimitive,
4007
4206
  Popover as PopoverPrimitive,
@@ -4030,11 +4229,11 @@ var HoverCardRoot = ({
4030
4229
  openDelay = 700
4031
4230
  }) => {
4032
4231
  const [isOpen, setOpen] = useControlledState(open, defaultOpen, onOpenChange);
4033
- const [portalContainer, setPortalContainer] = useState9();
4034
- const triggerRef = useRef12(null);
4035
- const isPointerInsideRef = useRef12(false);
4036
- const openTimerRef = useRef12(void 0);
4037
- const closeTimerRef = useRef12(void 0);
4232
+ const [portalContainer, setPortalContainer] = useState10();
4233
+ const triggerRef = useRef11(null);
4234
+ const isPointerInsideRef = useRef11(false);
4235
+ const openTimerRef = useRef11(void 0);
4236
+ const closeTimerRef = useRef11(void 0);
4038
4237
  const clearTimers = useCallback7(() => {
4039
4238
  clearTimeout(openTimerRef.current);
4040
4239
  clearTimeout(closeTimerRef.current);
@@ -4251,7 +4450,7 @@ function extractSourceDomain(href) {
4251
4450
  }
4252
4451
 
4253
4452
  // ../agent-ui/src/components/chat-source/chat-source.tsx
4254
- import { Fragment as Fragment2, jsx as jsx20, jsxs as jsxs13 } from "react/jsx-runtime";
4453
+ import { Fragment as Fragment2, jsx as jsx20, jsxs as jsxs14 } from "react/jsx-runtime";
4255
4454
  var ChatSourceContext = createContext2({ sourceType: "url" });
4256
4455
  var useChatSourceContext = () => useContext2(ChatSourceContext);
4257
4456
  function getSourceInitial(label) {
@@ -4276,7 +4475,7 @@ var ChatSourceRoot = ({
4276
4475
  () => ({ description, domain, enablePreview, faviconUrl, href, locator, sourceType, title }),
4277
4476
  [description, domain, enablePreview, faviconUrl, href, locator, sourceType, title]
4278
4477
  );
4279
- const body = children ?? /* @__PURE__ */ jsxs13(Fragment2, { children: [
4478
+ const body = children ?? /* @__PURE__ */ jsxs14(Fragment2, { children: [
4280
4479
  /* @__PURE__ */ jsx20(ChatSourceTrigger, {}),
4281
4480
  enablePreview ? /* @__PURE__ */ jsx20(ChatSourcePreview, { description, title }) : null
4282
4481
  ] });
@@ -4296,11 +4495,11 @@ var ChatSourceRoot = ({
4296
4495
  var ChatSourceTrigger = ({ children, className, label, ...props }) => {
4297
4496
  const { domain, enablePreview, href, locator, sourceType, title } = useChatSourceContext();
4298
4497
  const isUrl = sourceType === "url" && href;
4299
- const triggerBody = children ?? label ?? (isUrl ? /* @__PURE__ */ jsxs13(Fragment2, { children: [
4498
+ const triggerBody = children ?? label ?? (isUrl ? /* @__PURE__ */ jsxs14(Fragment2, { children: [
4300
4499
  /* @__PURE__ */ jsx20(ChatSourceIcon, {}),
4301
4500
  /* @__PURE__ */ jsx20(ChatSourceTitle, { children: title ?? domain }),
4302
4501
  locator ? /* @__PURE__ */ jsx20(ChatSourceLocator, { children: locator }) : null
4303
- ] }) : /* @__PURE__ */ jsxs13(Fragment2, { children: [
4502
+ ] }) : /* @__PURE__ */ jsxs14(Fragment2, { children: [
4304
4503
  /* @__PURE__ */ jsx20(ChatSourceDocumentIcon, {}),
4305
4504
  /* @__PURE__ */ jsx20(ChatSourceTitle, { children: title }),
4306
4505
  locator ? /* @__PURE__ */ jsx20(ChatSourceLocator, { children: locator }) : null
@@ -4378,7 +4577,7 @@ var ChatSourceIcon = ({ children, className, faviconUrl }) => {
4378
4577
  "data-slot": "chat-source-icon"
4379
4578
  });
4380
4579
  }
4381
- return /* @__PURE__ */ jsxs13(
4580
+ return /* @__PURE__ */ jsxs14(
4382
4581
  "span",
4383
4582
  {
4384
4583
  "aria-hidden": "true",
@@ -4445,7 +4644,7 @@ var ChatSourcePreview = ({
4445
4644
  if (!enablePreview) return null;
4446
4645
  const resolvedTitle = title ?? contextTitle;
4447
4646
  const resolvedDescription = description ?? contextDescription;
4448
- const body = sourceType === "url" && href ? /* @__PURE__ */ jsxs13(
4647
+ const body = sourceType === "url" && href ? /* @__PURE__ */ jsxs14(
4449
4648
  "a",
4450
4649
  {
4451
4650
  className: "aui-chat-source__preview-link",
@@ -4453,7 +4652,7 @@ var ChatSourcePreview = ({
4453
4652
  rel: "noopener noreferrer",
4454
4653
  target: "_blank",
4455
4654
  children: [
4456
- /* @__PURE__ */ jsxs13("div", { className: "aui-chat-source__preview-header", children: [
4655
+ /* @__PURE__ */ jsxs14("div", { className: "aui-chat-source__preview-header", children: [
4457
4656
  /* @__PURE__ */ jsx20(ChatSourceIcon, {}),
4458
4657
  /* @__PURE__ */ jsx20("span", { className: "aui-chat-source__preview-domain", children: domain })
4459
4658
  ] }),
@@ -4461,8 +4660,8 @@ var ChatSourcePreview = ({
4461
4660
  resolvedDescription ? /* @__PURE__ */ jsx20("div", { className: "aui-chat-source__preview-description", children: resolvedDescription }) : null
4462
4661
  ]
4463
4662
  }
4464
- ) : /* @__PURE__ */ jsxs13("div", { className: "aui-chat-source__preview-link", "data-source-type": "document", children: [
4465
- /* @__PURE__ */ jsxs13("div", { className: "aui-chat-source__preview-header", children: [
4663
+ ) : /* @__PURE__ */ jsxs14("div", { className: "aui-chat-source__preview-link", "data-source-type": "document", children: [
4664
+ /* @__PURE__ */ jsxs14("div", { className: "aui-chat-source__preview-header", children: [
4466
4665
  /* @__PURE__ */ jsx20(ChatSourceDocumentIcon, {}),
4467
4666
  /* @__PURE__ */ jsx20("span", { className: "aui-chat-source__preview-domain", children: resolvedTitle ?? "Document" })
4468
4667
  ] }),
@@ -4488,7 +4687,7 @@ var ChatSourcePreview = ({
4488
4687
  // ../agent-ui/src/components/chat-source/chat-sources.tsx
4489
4688
  import { Disclosure as Disclosure3 } from "@heroui/react";
4490
4689
  import { composeRenderProps as composeRenderProps3 } from "react-aria-components";
4491
- import { jsx as jsx21, jsxs as jsxs14 } from "react/jsx-runtime";
4690
+ import { jsx as jsx21, jsxs as jsxs15 } from "react/jsx-runtime";
4492
4691
  var ChatSourcesRoot = ({ children, className, ...props }) => /* @__PURE__ */ jsx21(
4493
4692
  Disclosure3,
4494
4693
  {
@@ -4501,7 +4700,7 @@ var ChatSourcesRoot = ({ children, className, ...props }) => /* @__PURE__ */ jsx
4501
4700
  children
4502
4701
  }
4503
4702
  );
4504
- var ChatSourcesTrigger = ({ children, className, ...props }) => /* @__PURE__ */ jsx21(Disclosure3.Heading, { children: /* @__PURE__ */ jsxs14(
4703
+ var ChatSourcesTrigger = ({ children, className, ...props }) => /* @__PURE__ */ jsx21(Disclosure3.Heading, { children: /* @__PURE__ */ jsxs15(
4505
4704
  Disclosure3.Trigger,
4506
4705
  {
4507
4706
  "data-slot": "chat-sources-trigger",
@@ -4557,7 +4756,7 @@ var ChatSources = Object.assign(ChatSourcesRoot, {
4557
4756
  });
4558
4757
 
4559
4758
  // src/embed/message-sources.tsx
4560
- import { jsx as jsx22, jsxs as jsxs15 } from "react/jsx-runtime";
4759
+ import { jsx as jsx22, jsxs as jsxs16 } from "react/jsx-runtime";
4561
4760
  function sourceFaviconUrl(url) {
4562
4761
  return `https://www.google.com/s2/favicons?domain_url=${encodeURIComponent(url)}&sz=64`;
4563
4762
  }
@@ -4584,8 +4783,8 @@ function MessageSources({ sources }) {
4584
4783
  if (sources.length === 1) {
4585
4784
  return /* @__PURE__ */ jsx22("div", { "aria-label": "Sources", className: "ha-message-sources", "data-count": "1", role: "group", children: /* @__PURE__ */ jsx22(SourceLink, { source: sources[0] }) });
4586
4785
  }
4587
- return /* @__PURE__ */ jsxs15(ChatSources, { className: "ha-message-sources", "data-count": sources.length, children: [
4588
- /* @__PURE__ */ jsxs15(ChatSources.Trigger, { "aria-label": `${sources.length} sources`, children: [
4786
+ return /* @__PURE__ */ jsxs16(ChatSources, { className: "ha-message-sources", "data-count": sources.length, children: [
4787
+ /* @__PURE__ */ jsxs16(ChatSources.Trigger, { "aria-label": `${sources.length} sources`, children: [
4589
4788
  /* @__PURE__ */ jsx22("span", { className: "ha-sources-label", children: "Sources" }),
4590
4789
  /* @__PURE__ */ jsx22("span", { "aria-hidden": "true", className: "ha-sources-count", children: sources.length })
4591
4790
  ] }),
@@ -4670,8 +4869,8 @@ function writeCachedProjectConfig(agentId, config) {
4670
4869
  // src/embed/session-picker.tsx
4671
4870
  import { ChevronDown as ChevronDown2, Ellipsis, Pencil as Pencil2, Plus as Plus2, TrashBin as TrashBin2 } from "@gravity-ui/icons";
4672
4871
  import { Button as Button4, Dropdown, Input, Label as Label3, Modal, Popover as Popover2, TextField } from "@heroui/react";
4673
- import { useCallback as useCallback8, useRef as useRef13, useState as useState10 } from "react";
4674
- import { Fragment as Fragment3, jsx as jsx24, jsxs as jsxs16 } from "react/jsx-runtime";
4872
+ import { useCallback as useCallback8, useRef as useRef12, useState as useState11 } from "react";
4873
+ import { Fragment as Fragment3, jsx as jsx24, jsxs as jsxs17 } from "react/jsx-runtime";
4675
4874
  var RENAME_KEY = "rename";
4676
4875
  var DELETE_KEY = "delete";
4677
4876
  var MAX_TITLE_LENGTH = 80;
@@ -4687,17 +4886,17 @@ function SessionPicker({
4687
4886
  onSelectConversation,
4688
4887
  variant = "popover"
4689
4888
  }) {
4690
- const [isOpen, setIsOpen] = useState10(false);
4691
- const [isDialogOpen, setIsDialogOpen] = useState10(false);
4692
- const [actionMenuId, setActionMenuId] = useState10(null);
4693
- const [dialog, setDialog] = useState10(null);
4694
- const [renameTitle, setRenameTitle] = useState10("");
4695
- const [mutationError, setMutationError] = useState10(null);
4696
- const [isPending, setIsPending] = useState10(false);
4697
- const [portalContainer, setPortalContainer] = useState10();
4698
- const pointerOpenAt = useRef13(0);
4699
- const actionPointerOpenAt = useRef13(0);
4700
- const sidebarHistoryRef = useRef13(null);
4889
+ const [isOpen, setIsOpen] = useState11(false);
4890
+ const [isDialogOpen, setIsDialogOpen] = useState11(false);
4891
+ const [actionMenuId, setActionMenuId] = useState11(null);
4892
+ const [dialog, setDialog] = useState11(null);
4893
+ const [renameTitle, setRenameTitle] = useState11("");
4894
+ const [mutationError, setMutationError] = useState11(null);
4895
+ const [isPending, setIsPending] = useState11(false);
4896
+ const [portalContainer, setPortalContainer] = useState11();
4897
+ const pointerOpenAt = useRef12(0);
4898
+ const actionPointerOpenAt = useRef12(0);
4899
+ const sidebarHistoryRef = useRef12(null);
4701
4900
  useScrollShadow(sidebarHistoryRef);
4702
4901
  const activeConversation = groups.flatMap((group) => group.items).find((conversation) => conversation.id === activeConversationId);
4703
4902
  const activeTitle = activeConversation?.title ?? "New chat";
@@ -4769,13 +4968,13 @@ function SessionPicker({
4769
4968
  setIsPending(false);
4770
4969
  }
4771
4970
  };
4772
- const history = groups.length ? groups.map((group) => /* @__PURE__ */ jsxs16("section", { className: "ha-session-group", children: [
4971
+ const history = groups.length ? groups.map((group) => /* @__PURE__ */ jsxs17("section", { className: "ha-session-group", children: [
4773
4972
  /* @__PURE__ */ jsx24("h3", { children: group.label }),
4774
4973
  /* @__PURE__ */ jsx24("div", { className: "ha-session-list", children: group.items.map((conversation) => {
4775
4974
  const isActive = conversation.id === activeConversationId;
4776
4975
  const isBusy = busyConversationIds.has(conversation.id);
4777
4976
  const hasCompletedUpdate = !isBusy && completedConversationIds.has(conversation.id);
4778
- return /* @__PURE__ */ jsxs16(
4977
+ return /* @__PURE__ */ jsxs17(
4779
4978
  "div",
4780
4979
  {
4781
4980
  className: "ha-session-row",
@@ -4783,7 +4982,7 @@ function SessionPicker({
4783
4982
  "data-active": isActive || void 0,
4784
4983
  "data-completed": hasCompletedUpdate || void 0,
4785
4984
  children: [
4786
- /* @__PURE__ */ jsxs16(
4985
+ /* @__PURE__ */ jsxs17(
4787
4986
  "button",
4788
4987
  {
4789
4988
  "aria-current": isActive ? "page" : void 0,
@@ -4800,7 +4999,7 @@ function SessionPicker({
4800
4999
  ]
4801
5000
  }
4802
5001
  ),
4803
- /* @__PURE__ */ jsxs16(
5002
+ /* @__PURE__ */ jsxs17(
4804
5003
  Dropdown,
4805
5004
  {
4806
5005
  isOpen: actionMenuId === conversation.id,
@@ -4826,17 +5025,17 @@ function SessionPicker({
4826
5025
  className: "ha-session-actions-menu",
4827
5026
  placement: "bottom end",
4828
5027
  UNSTABLE_portalContainer: portalContainer,
4829
- children: /* @__PURE__ */ jsxs16(
5028
+ children: /* @__PURE__ */ jsxs17(
4830
5029
  Dropdown.Menu,
4831
5030
  {
4832
5031
  "aria-label": `Actions for ${conversation.title}`,
4833
5032
  onAction: (key) => handleConversationAction(conversation, key),
4834
5033
  children: [
4835
- /* @__PURE__ */ jsxs16(Dropdown.Item, { id: RENAME_KEY, textValue: "Rename", children: [
5034
+ /* @__PURE__ */ jsxs17(Dropdown.Item, { id: RENAME_KEY, textValue: "Rename", children: [
4836
5035
  /* @__PURE__ */ jsx24(Pencil2, { "aria-hidden": "true" }),
4837
5036
  /* @__PURE__ */ jsx24(Label3, { children: "Rename" })
4838
5037
  ] }),
4839
- /* @__PURE__ */ jsxs16(
5038
+ /* @__PURE__ */ jsxs17(
4840
5039
  Dropdown.Item,
4841
5040
  {
4842
5041
  id: DELETE_KEY,
@@ -4863,16 +5062,16 @@ function SessionPicker({
4863
5062
  );
4864
5063
  }) })
4865
5064
  ] }, group.label)) : /* @__PURE__ */ jsx24("p", { className: "ha-session-empty", children: "Your recent chats will appear here." });
4866
- return /* @__PURE__ */ jsxs16(
5065
+ return /* @__PURE__ */ jsxs17(
4867
5066
  "div",
4868
5067
  {
4869
5068
  "data-variant": variant,
4870
5069
  className: variant === "sidebar" ? "ha-session-picker ha-session-sidebar" : "ha-session-picker",
4871
5070
  children: [
4872
- variant === "sidebar" ? /* @__PURE__ */ jsxs16(Fragment3, { children: [
4873
- /* @__PURE__ */ jsxs16("div", { className: "ha-session-sidebar-header", children: [
5071
+ variant === "sidebar" ? /* @__PURE__ */ jsxs17(Fragment3, { children: [
5072
+ /* @__PURE__ */ jsxs17("div", { className: "ha-session-sidebar-header", children: [
4874
5073
  /* @__PURE__ */ jsx24("h2", { children: "Chats" }),
4875
- /* @__PURE__ */ jsxs16(
5074
+ /* @__PURE__ */ jsxs17(
4876
5075
  Button4,
4877
5076
  {
4878
5077
  fullWidth: true,
@@ -4899,8 +5098,8 @@ function SessionPicker({
4899
5098
  children: history
4900
5099
  }
4901
5100
  )
4902
- ] }) : /* @__PURE__ */ jsxs16(Popover2, { isOpen, onOpenChange: handleOpenChange, children: [
4903
- /* @__PURE__ */ jsxs16(
5101
+ ] }) : /* @__PURE__ */ jsxs17(Popover2, { isOpen, onOpenChange: handleOpenChange, children: [
5102
+ /* @__PURE__ */ jsxs17(
4904
5103
  Button4,
4905
5104
  {
4906
5105
  "aria-label": "Choose a chat",
@@ -4985,7 +5184,7 @@ function SessionDialogContent({
4985
5184
  renameTitle
4986
5185
  }) {
4987
5186
  if (dialog?.type === "rename") {
4988
- return /* @__PURE__ */ jsxs16(
5187
+ return /* @__PURE__ */ jsxs17(
4989
5188
  "form",
4990
5189
  {
4991
5190
  onSubmit: (event) => {
@@ -4994,7 +5193,7 @@ function SessionDialogContent({
4994
5193
  },
4995
5194
  children: [
4996
5195
  /* @__PURE__ */ jsx24(Modal.Header, { children: /* @__PURE__ */ jsx24(Modal.Heading, { children: "Rename chat" }) }),
4997
- /* @__PURE__ */ jsxs16(Modal.Body, { children: [
5196
+ /* @__PURE__ */ jsxs17(Modal.Body, { children: [
4998
5197
  /* @__PURE__ */ jsx24(
4999
5198
  TextField,
5000
5199
  {
@@ -5016,7 +5215,7 @@ function SessionDialogContent({
5016
5215
  ),
5017
5216
  /* @__PURE__ */ jsx24(SessionDialogError, { message: mutationError })
5018
5217
  ] }),
5019
- /* @__PURE__ */ jsxs16(Modal.Footer, { children: [
5218
+ /* @__PURE__ */ jsxs17(Modal.Footer, { children: [
5020
5219
  /* @__PURE__ */ jsx24(
5021
5220
  Button4,
5022
5221
  {
@@ -5035,12 +5234,12 @@ function SessionDialogContent({
5035
5234
  );
5036
5235
  }
5037
5236
  if (dialog?.type !== "delete") return null;
5038
- return /* @__PURE__ */ jsxs16(Fragment3, { children: [
5237
+ return /* @__PURE__ */ jsxs17(Fragment3, { children: [
5039
5238
  /* @__PURE__ */ jsx24(Modal.Header, { children: /* @__PURE__ */ jsx24(Modal.Heading, { children: "Delete chat?" }) }),
5040
- /* @__PURE__ */ jsxs16(Modal.Body, { children: [
5041
- /* @__PURE__ */ jsxs16("p", { children: [
5239
+ /* @__PURE__ */ jsxs17(Modal.Body, { children: [
5240
+ /* @__PURE__ */ jsxs17("p", { children: [
5042
5241
  "Are you sure you want to delete ",
5043
- /* @__PURE__ */ jsxs16("strong", { children: [
5242
+ /* @__PURE__ */ jsxs17("strong", { children: [
5044
5243
  "\u201C",
5045
5244
  dialog.item.title,
5046
5245
  "\u201D"
@@ -5049,7 +5248,7 @@ function SessionDialogContent({
5049
5248
  ] }),
5050
5249
  /* @__PURE__ */ jsx24(SessionDialogError, { message: mutationError })
5051
5250
  ] }),
5052
- /* @__PURE__ */ jsxs16(Modal.Footer, { children: [
5251
+ /* @__PURE__ */ jsxs17(Modal.Footer, { children: [
5053
5252
  /* @__PURE__ */ jsx24(Button4, { fullWidth: true, isDisabled: isPending, variant: "outline", onPress: onClose, children: "Cancel" }),
5054
5253
  /* @__PURE__ */ jsx24(Button4, { fullWidth: true, isPending, variant: "danger", onPress: () => void onDelete(), children: isPending ? "Deleting\u2026" : "Delete" })
5055
5254
  ] })
@@ -5060,7 +5259,7 @@ function SessionDialogError({ message }) {
5060
5259
  }
5061
5260
 
5062
5261
  // src/embed/startup-activity-status.tsx
5063
- import { useEffect as useEffect12, useState as useState11 } from "react";
5262
+ import { useEffect as useEffect12, useState as useState12 } from "react";
5064
5263
  import { jsx as jsx25 } from "react/jsx-runtime";
5065
5264
  var STARTUP_ACTIVITY_STATUSES = [
5066
5265
  "Thinking\u2026",
@@ -5069,7 +5268,7 @@ var STARTUP_ACTIVITY_STATUSES = [
5069
5268
  ];
5070
5269
  var STARTUP_ACTIVITY_STATUS_INTERVAL_MS = 1600;
5071
5270
  function StartupActivityStatus() {
5072
- const [statusIndex, setStatusIndex] = useState11(0);
5271
+ const [statusIndex, setStatusIndex] = useState12(0);
5073
5272
  useEffect12(() => {
5074
5273
  const timers = STARTUP_ACTIVITY_STATUSES.slice(1).map(
5075
5274
  (_, index) => window.setTimeout(
@@ -5112,7 +5311,7 @@ function restoreTriggerSession(stored, bootstrapStatus) {
5112
5311
  }
5113
5312
 
5114
5313
  // src/embed/use-composer-draft.ts
5115
- import { useCallback as useCallback9, useEffect as useEffect13, useRef as useRef14, useState as useState12 } from "react";
5314
+ import { useCallback as useCallback9, useEffect as useEffect13, useRef as useRef13, useState as useState13 } from "react";
5116
5315
  var AGENT_COMPOSER_DRAFT_SAVE_DEBOUNCE_MS = 300;
5117
5316
  function useComposerDraft({
5118
5317
  attachments,
@@ -5121,10 +5320,10 @@ function useComposerDraft({
5121
5320
  setAttachments,
5122
5321
  setInput
5123
5322
  }) {
5124
- const [restoredImageDraftKey, setRestoredImageDraftKey] = useState12(null);
5125
- const [restoredPromptDraftKey, setRestoredPromptDraftKey] = useState12(null);
5126
- const latestInputRef = useRef14(input);
5127
- const saveTimeoutRef = useRef14(null);
5323
+ const [restoredImageDraftKey, setRestoredImageDraftKey] = useState13(null);
5324
+ const [restoredPromptDraftKey, setRestoredPromptDraftKey] = useState13(null);
5325
+ const latestInputRef = useRef13(input);
5326
+ const saveTimeoutRef = useRef13(null);
5128
5327
  useEffect13(() => {
5129
5328
  latestInputRef.current = input;
5130
5329
  }, [input]);
@@ -5175,7 +5374,7 @@ function useComposerDraft({
5175
5374
  }
5176
5375
 
5177
5376
  // src/embed/use-persisted-model-selection.ts
5178
- import { useCallback as useCallback10, useState as useState13 } from "react";
5377
+ import { useCallback as useCallback10, useState as useState14 } from "react";
5179
5378
  function agentModelPreferenceStorageKey(identityStorageKey) {
5180
5379
  return `${identityStorageKey}:model`;
5181
5380
  }
@@ -5203,7 +5402,7 @@ function storeModelPreference(identityStorageKey, modelId) {
5203
5402
  }
5204
5403
  }
5205
5404
  function usePersistedModelSelection(identityStorageKey, configuredDefaultModelId) {
5206
- const [preferredModelId, setPreferredModelId] = useState13(
5405
+ const [preferredModelId, setPreferredModelId] = useState14(
5207
5406
  () => readStoredModelPreference(identityStorageKey)
5208
5407
  );
5209
5408
  const selectedModelId = preferredModelId ?? configuredDefaultModelId ?? DEFAULT_AGENT_PICKER_MODEL_ID;
@@ -5318,7 +5517,7 @@ async function transcribeVoiceRecording({
5318
5517
  }
5319
5518
 
5320
5519
  // src/embed/embed-runtime.tsx
5321
- import { Fragment as Fragment4, jsx as jsx26, jsxs as jsxs17 } from "react/jsx-runtime";
5520
+ import { Fragment as Fragment4, jsx as jsx26, jsxs as jsxs18 } from "react/jsx-runtime";
5322
5521
  var TRANSPORT_COMPLETION_WATCHDOG_MS = 3e4;
5323
5522
  function createReconciliationDeferred() {
5324
5523
  let resolve;
@@ -5361,14 +5560,14 @@ function EmbedRuntime({
5361
5560
  () => new EmbedSessionManager(options.agentId, options.getAuthToken),
5362
5561
  [options.getAuthToken, options.agentId]
5363
5562
  );
5364
- const [activeConversationId, setActiveConversationId] = useState14(null);
5365
- const [runtimeRoutes, setRuntimeRoutes] = useState14({});
5366
- const runtimeRoutesRef = useRef15(runtimeRoutes);
5367
- const activeConversationIdRef = useRef15(activeConversationId);
5368
- const [error, setError] = useState14(null);
5369
- const [history, setHistory] = useState14([]);
5370
- const [conversationActivity, setConversationActivity] = useState14(createConversationActivityState);
5371
- const [messageQueues, setMessageQueues] = useState14({});
5563
+ const [activeConversationId, setActiveConversationId] = useState15(null);
5564
+ const [runtimeRoutes, setRuntimeRoutes] = useState15({});
5565
+ const runtimeRoutesRef = useRef14(runtimeRoutes);
5566
+ const activeConversationIdRef = useRef14(activeConversationId);
5567
+ const [error, setError] = useState15(null);
5568
+ const [history, setHistory] = useState15([]);
5569
+ const [conversationActivity, setConversationActivity] = useState15(createConversationActivityState);
5570
+ const [messageQueues, setMessageQueues] = useState15({});
5372
5571
  const runtime = activeConversationId ? runtimeRoutes[activeConversationId] ?? null : null;
5373
5572
  useLayoutEffect4(() => {
5374
5573
  runtimeRoutesRef.current = runtimeRoutes;
@@ -5411,7 +5610,7 @@ function EmbedRuntime({
5411
5610
  },
5412
5611
  []
5413
5612
  );
5414
- const bootstrapCacheRef = useRef15(null);
5613
+ const bootstrapCacheRef = useRef14(null);
5415
5614
  const apiBaseUrl = options.apiBaseUrl;
5416
5615
  const agentId = options.agentId;
5417
5616
  const notifyReady = useEffectEvent(onReady);
@@ -5429,7 +5628,7 @@ function EmbedRuntime({
5429
5628
  const reportEmbedLoaded = useEffectEvent((conversationId) => {
5430
5629
  void reportEvent(options, tokenManager, conversationId, "embed_loaded");
5431
5630
  });
5432
- const appliedIdentityEpochRef = useRef15(identityEpoch);
5631
+ const appliedIdentityEpochRef = useRef14(identityEpoch);
5433
5632
  useLayoutEffect4(() => {
5434
5633
  if (appliedIdentityEpochRef.current === identityEpoch) return;
5435
5634
  appliedIdentityEpochRef.current = identityEpoch;
@@ -5590,7 +5789,7 @@ function EmbedRuntime({
5590
5789
  ),
5591
5790
  [clientToolValidationError, options.permissionDefaultMode, options.tools]
5592
5791
  );
5593
- const preloadedConversationIds = useRef15(/* @__PURE__ */ new Set());
5792
+ const preloadedConversationIds = useRef14(/* @__PURE__ */ new Set());
5594
5793
  const warmAgentSession = useEffectEvent((conversationId) => {
5595
5794
  preloadedConversationIds.current.add(conversationId);
5596
5795
  void preloadAgentSession(options, tokenManager, conversationId, preloadClientTools);
@@ -5706,7 +5905,7 @@ function EmbedRuntime({
5706
5905
  );
5707
5906
  }, [options.suggestedPrompts, runtimeRoutes]);
5708
5907
  const runtimeConfig = activeConversationId ? configuredRuntimeRoutes[activeConversationId]?.config ?? null : null;
5709
- const openedConversationRef = useRef15(null);
5908
+ const openedConversationRef = useRef14(null);
5710
5909
  useEffect14(() => {
5711
5910
  if (!open || !runtime || openedConversationRef.current === runtime.conversationId) return;
5712
5911
  openedConversationRef.current = runtime.conversationId;
@@ -5716,7 +5915,7 @@ function EmbedRuntime({
5716
5915
  const conversationGroups = useMemo4(() => groupConversationHistory(history), [history]);
5717
5916
  const activeConversationTitle = history.find((conversation) => conversation.id === activeConversationId)?.title ?? "New chat";
5718
5917
  const loadingMessage = bootstrapCacheRef.current ? "Loading chat\u2026" : "Loading assistant\u2026";
5719
- return /* @__PURE__ */ jsxs17(Fragment4, { children: [
5918
+ return /* @__PURE__ */ jsxs18(Fragment4, { children: [
5720
5919
  open && runtime?.config.presence ? /* @__PURE__ */ jsx26(
5721
5920
  AgentConversationPresence,
5722
5921
  {
@@ -5726,7 +5925,7 @@ function EmbedRuntime({
5726
5925
  userId: runtime.presenceUserId
5727
5926
  }
5728
5927
  ) : null,
5729
- /* @__PURE__ */ jsxs17(
5928
+ /* @__PURE__ */ jsxs18(
5730
5929
  PanelShell,
5731
5930
  {
5732
5931
  actionsSlot: /* @__PURE__ */ jsx26(NewChatButton, { onPress: onNewConversation }),
@@ -5833,11 +6032,11 @@ function ChatRuntime({
5833
6032
  const permissionStorageKey = agentPermissionModeStorageKey(storageKey, conversationId);
5834
6033
  const attachmentPolicyKey = options.composerAttachmentAccept;
5835
6034
  const attachmentPolicy = useMemo4(() => ({ key: attachmentPolicyKey }), [attachmentPolicyKey]);
5836
- const [attachmentSelection, setAttachmentSelection] = useState14(() => ({
6035
+ const [attachmentSelection, setAttachmentSelection] = useState15(() => ({
5837
6036
  files: [],
5838
6037
  policy: attachmentPolicy
5839
6038
  }));
5840
- const [attachmentErrorSelection, setAttachmentErrorSelection] = useState14(() => ({
6039
+ const [attachmentErrorSelection, setAttachmentErrorSelection] = useState15(() => ({
5841
6040
  error: null,
5842
6041
  policy: attachmentPolicy
5843
6042
  }));
@@ -5863,16 +6062,16 @@ function ChatRuntime({
5863
6062
  (error) => setAttachmentErrorSelection({ error, policy: attachmentPolicy }),
5864
6063
  [attachmentPolicy]
5865
6064
  );
5866
- const [activeTurnSelection, setActiveTurnSelectionState] = useState14(() => {
6065
+ const [activeTurnSelection, setActiveTurnSelectionState] = useState15(() => {
5867
6066
  const storedMode = shouldRestoreActivePermission ? readStoredAgentPermissionMode(activePermissionStorageKey) : void 0;
5868
6067
  const restoredMode = storedMode ?? (shouldRestoreActivePermission ? "ask" : void 0);
5869
6068
  return restoredMode ? { modelId: void 0, permissionMode: restoredMode } : void 0;
5870
6069
  });
5871
- const [activityTimings, setActivityTimings] = useState14({});
5872
- const [feedbackByMessage, setFeedbackByMessage] = useState14({});
5873
- const [isComposerExpanded, setIsComposerExpanded] = useState14(false);
5874
- const [input, setInput] = useState14("");
5875
- const [permissionSelection, setPermissionSelection] = useState14(() => {
6070
+ const [activityTimings, setActivityTimings] = useState15({});
6071
+ const [feedbackByMessage, setFeedbackByMessage] = useState15({});
6072
+ const [isComposerExpanded, setIsComposerExpanded] = useState15(false);
6073
+ const [input, setInput] = useState15("");
6074
+ const [permissionSelection, setPermissionSelection] = useState15(() => {
5876
6075
  const storedMode = options.permissionShowPicker ? readStoredAgentPermissionMode(permissionStorageKey) : void 0;
5877
6076
  const hasUnresolvedClientTool = options.permissionShowPicker && initialMessages.some(
5878
6077
  (message) => message.role === "assistant" && message.parts.some((part) => {
@@ -5888,19 +6087,19 @@ function ChatRuntime({
5888
6087
  selectedMode: storedMode ?? (hasUnresolvedClientTool ? "ask" : options.permissionDefaultMode)
5889
6088
  };
5890
6089
  });
5891
- const [isQueueReordering, setIsQueueReordering] = useState14(false);
5892
- const [isReconciling, setIsReconciling] = useState14(false);
5893
- const [localPending, setLocalPending] = useState14(false);
5894
- const [pendingClientToolCallIds, setPendingClientToolCallIds] = useState14(
6090
+ const [isQueueReordering, setIsQueueReordering] = useState15(false);
6091
+ const [isReconciling, setIsReconciling] = useState15(false);
6092
+ const [localPending, setLocalPending] = useState15(false);
6093
+ const [pendingClientToolCallIds, setPendingClientToolCallIds] = useState15(
5895
6094
  () => /* @__PURE__ */ new Set()
5896
6095
  );
5897
- const [isResuming, setIsResuming] = useState14(true);
5898
- const [progress, setProgress] = useState14(null);
5899
- const [queueDrainVersion, setQueueDrainVersion] = useState14(0);
5900
- const [reconcileEpoch, setReconcileEpoch] = useState14(0);
5901
- const [recoveryError, setRecoveryError] = useState14(false);
5902
- const [selection, setSelection] = useState14(null);
5903
- const [toolDecisions, setToolDecisions] = useState14({});
6096
+ const [isResuming, setIsResuming] = useState15(true);
6097
+ const [progress, setProgress] = useState15(null);
6098
+ const [queueDrainVersion, setQueueDrainVersion] = useState15(0);
6099
+ const [reconcileEpoch, setReconcileEpoch] = useState15(0);
6100
+ const [recoveryError, setRecoveryError] = useState15(false);
6101
+ const [selection, setSelection] = useState15(null);
6102
+ const [toolDecisions, setToolDecisions] = useState15({});
5904
6103
  useEffect14(() => {
5905
6104
  if (!shouldRestoreActivePermission) {
5906
6105
  clearStoredAgentPermissionMode(activePermissionStorageKey);
@@ -5938,7 +6137,7 @@ function ChatRuntime({
5938
6137
  () => serializeClientTools(effectiveClientTools),
5939
6138
  [effectiveClientTools]
5940
6139
  );
5941
- const clientToolManifestRef = useRef15(clientToolManifest);
6140
+ const clientToolManifestRef = useRef14(clientToolManifest);
5942
6141
  useLayoutEffect4(() => {
5943
6142
  clientToolManifestRef.current = clientToolManifest;
5944
6143
  }, [clientToolManifest]);
@@ -5947,27 +6146,27 @@ function ChatRuntime({
5947
6146
  () => new Map(effectiveClientTools.map((tool) => [tool.name, tool])),
5948
6147
  [effectiveClientTools]
5949
6148
  );
5950
- const executedToolCallsRef = useRef15(/* @__PURE__ */ new Set());
5951
- const activeMessageIdRef = useRef15(null);
5952
- const isBusyRef = useRef15(true);
5953
- const isQueueReorderingRef = useRef15(false);
5954
- const messageQueueRef = useRef15(messageQueue);
5955
- const pendingTurnAnchorRef = useRef15(null);
5956
- const reconciliationDeferredRef = useRef15(null);
5957
- const reconcileMessageIdRef = useRef15(void 0);
5958
- const resumePromiseRef = useRef15(null);
5959
- const manualStopRequestedRef = useRef15(false);
5960
- const sendAcknowledgedRef = useRef15(false);
5961
- const sendErrorRef = useRef15(null);
5962
- const streamedMessageIdsRef = useRef15(/* @__PURE__ */ new Set());
5963
- const timedMessageIdRef = useRef15(null);
5964
- const transportFailureRef = useRef15(null);
5965
- const turnStartedAtRef = useRef15(null);
5966
- const needsReconciliationRef = useRef15(false);
5967
- const clearChatErrorRef = useRef15(() => void 0);
5968
- const fileInputRef = useRef15(null);
5969
- const messageQueueListRef = useRef15(null);
5970
- const textareaRef = useRef15(null);
6149
+ const executedToolCallsRef = useRef14(/* @__PURE__ */ new Set());
6150
+ const activeMessageIdRef = useRef14(null);
6151
+ const isBusyRef = useRef14(true);
6152
+ const isQueueReorderingRef = useRef14(false);
6153
+ const messageQueueRef = useRef14(messageQueue);
6154
+ const pendingTurnAnchorRef = useRef14(null);
6155
+ const reconciliationDeferredRef = useRef14(null);
6156
+ const reconcileMessageIdRef = useRef14(void 0);
6157
+ const resumePromiseRef = useRef14(null);
6158
+ const manualStopRequestedRef = useRef14(false);
6159
+ const sendAcknowledgedRef = useRef14(false);
6160
+ const sendErrorRef = useRef14(null);
6161
+ const streamedMessageIdsRef = useRef14(/* @__PURE__ */ new Set());
6162
+ const timedMessageIdRef = useRef14(null);
6163
+ const transportFailureRef = useRef14(null);
6164
+ const turnStartedAtRef = useRef14(null);
6165
+ const needsReconciliationRef = useRef14(false);
6166
+ const clearChatErrorRef = useRef14(() => void 0);
6167
+ const fileInputRef = useRef14(null);
6168
+ const messageQueueListRef = useRef14(null);
6169
+ const textareaRef = useRef14(null);
5971
6170
  const composerDraftKey = useMemo4(
5972
6171
  () => agentComposerDraftStorageKey(storageKey, conversationId),
5973
6172
  [conversationId, storageKey]
@@ -6465,8 +6664,11 @@ function ChatRuntime({
6465
6664
  turnStartedAtRef.current = Date.now();
6466
6665
  prepareTransportSend();
6467
6666
  pendingTurnAnchorRef.current = {
6468
- messageId: message.id,
6469
- previousUserMessageId: previousUserMessageId ?? null
6667
+ previousUserMessageId: previousUserMessageId ?? null,
6668
+ // A failed queued message can be sent again with the same message id.
6669
+ // Use a fresh key per actual send attempt so each user-triggered send
6670
+ // receives its one permitted viewport movement.
6671
+ scrollKey: crypto.randomUUID()
6470
6672
  };
6471
6673
  setLocalPending(true);
6472
6674
  setRecoveryError(false);
@@ -6868,8 +7070,7 @@ function ChatRuntime({
6868
7070
  )?.id;
6869
7071
  const lastUserMessageId = chatState.messages.findLast((message) => message.role === "user")?.id;
6870
7072
  const { activeStreamKey, activeTurnMessageId } = resolveConversationTurnAnchor({
6871
- conversationId,
6872
- isActive: localPending || isRunning,
7073
+ isActive: hasActiveTurn,
6873
7074
  lastUserMessageId,
6874
7075
  pendingTurn: pendingTurnAnchorRef.current
6875
7076
  });
@@ -6885,9 +7086,9 @@ function ChatRuntime({
6885
7086
  const dictationButtonLabel = isDictationTranscribing ? "Cancel transcription" : isDictating ? "Stop dictation" : "Dictate message";
6886
7087
  const dictationButtonTitle = isDictationSupported ? dictationButtonLabel : "Voice dictation is not supported in this browser";
6887
7088
  const sendButtonLabel = isRunning && !hasComposerDraft ? "Stop answering" : isBusy ? "Queue message" : "Send message";
6888
- return /* @__PURE__ */ jsxs17(Fragment4, { children: [
6889
- /* @__PURE__ */ jsxs17(ConversationViewport, { streamKey: activeStreamKey, children: [
6890
- showHome ? /* @__PURE__ */ jsxs17("div", { className: "ha-empty", children: [
7089
+ return /* @__PURE__ */ jsxs18(Fragment4, { children: [
7090
+ /* @__PURE__ */ jsxs18(ConversationViewport, { streamKey: activeStreamKey, children: [
7091
+ showHome ? /* @__PURE__ */ jsxs18("div", { className: "ha-empty", children: [
6891
7092
  /* @__PURE__ */ jsx26("h2", { children: options.greeting }),
6892
7093
  /* @__PURE__ */ jsx26("p", { children: "Live answers with charts, metrics, and tables." })
6893
7094
  ] }) : chatState.messages.map((message) => /* @__PURE__ */ jsx26(
@@ -6917,13 +7118,13 @@ function ChatRuntime({
6917
7118
  message.id
6918
7119
  )),
6919
7120
  standaloneStatus && (active || standaloneStatus !== DEFAULT_ACTIVITY_STATUS) ? /* @__PURE__ */ jsx26("div", { className: "ha-message", "data-role": "assistant", "data-stream-anchor": "true", children: /* @__PURE__ */ jsx26("div", { className: "ha-message-body", children: standaloneStatus === DEFAULT_ACTIVITY_STATUS ? /* @__PURE__ */ jsx26(StartupActivityStatus, {}, activeStreamKey ?? conversationId) : /* @__PURE__ */ jsx26(ActivityStatus, { label: standaloneStatus }) }) }) : null,
6920
- chatState.error || recoveryError ? /* @__PURE__ */ jsxs17("div", { className: "ha-error", role: "alert", children: [
7121
+ chatState.error || recoveryError ? /* @__PURE__ */ jsxs18("div", { className: "ha-error", role: "alert", children: [
6921
7122
  /* @__PURE__ */ jsx26("span", { children: "The request could not be completed." }),
6922
7123
  /* @__PURE__ */ jsx26("button", { type: "button", onClick: retryLastResponse, children: "Retry" })
6923
7124
  ] }) : null
6924
7125
  ] }),
6925
- /* @__PURE__ */ jsxs17("form", { className: "ha-composer-wrap", onSubmit: submit, children: [
6926
- showHome && visibleSuggestedPrompts.length > 0 ? /* @__PURE__ */ jsx26("div", { "aria-label": "Suggested prompts", className: "ha-suggestions", role: "group", children: visibleSuggestedPrompts.map((prompt, index) => /* @__PURE__ */ jsxs17(
7126
+ /* @__PURE__ */ jsxs18("form", { className: "ha-composer-wrap", onSubmit: submit, children: [
7127
+ showHome && visibleSuggestedPrompts.length > 0 ? /* @__PURE__ */ jsx26("div", { "aria-label": "Suggested prompts", className: "ha-suggestions", role: "group", children: visibleSuggestedPrompts.map((prompt, index) => /* @__PURE__ */ jsxs18(
6927
7128
  "button",
6928
7129
  {
6929
7130
  className: "ha-suggestion",
@@ -6932,7 +7133,7 @@ function ChatRuntime({
6932
7133
  onClick: () => submitComposerMessage(prompt),
6933
7134
  children: [
6934
7135
  /* @__PURE__ */ jsx26("span", { children: prompt }),
6935
- options.suggestedPromptShortcuts ? /* @__PURE__ */ jsxs17("span", { "aria-hidden": "true", className: "ha-suggestion-shortcut", children: [
7136
+ options.suggestedPromptShortcuts ? /* @__PURE__ */ jsxs18("span", { "aria-hidden": "true", className: "ha-suggestion-shortcut", children: [
6936
7137
  /* @__PURE__ */ jsx26("kbd", { children: "Ctrl" }),
6937
7138
  /* @__PURE__ */ jsx26("kbd", { children: index + 1 })
6938
7139
  ] }) : /* @__PURE__ */ jsx26(ArrowUpRight, { "aria-hidden": "true" })
@@ -6956,7 +7157,7 @@ function ChatRuntime({
6956
7157
  onSendNow: sendQueuedMessageNow
6957
7158
  }
6958
7159
  ),
6959
- /* @__PURE__ */ jsxs17(
7160
+ /* @__PURE__ */ jsxs18(
6960
7161
  ComposerFileDropzone,
6961
7162
  {
6962
7163
  className: "@container ha-composer",
@@ -7038,7 +7239,7 @@ function ChatRuntime({
7038
7239
  }
7039
7240
  }
7040
7241
  ),
7041
- isDictating ? /* @__PURE__ */ jsx26("div", { className: "ha-dictation-session", children: isDictationTranscribing ? /* @__PURE__ */ jsx26("span", { className: "ha-dictation-status", role: "status", children: "Transcribing\u2026" }) : /* @__PURE__ */ jsxs17(Fragment4, { children: [
7242
+ isDictating ? /* @__PURE__ */ jsx26("div", { className: "ha-dictation-session", children: isDictationTranscribing ? /* @__PURE__ */ jsx26("span", { className: "ha-dictation-status", role: "status", children: "Transcribing\u2026" }) : /* @__PURE__ */ jsxs18(Fragment4, { children: [
7042
7243
  /* @__PURE__ */ jsx26(
7043
7244
  VoiceLiveWaveform,
7044
7245
  {
@@ -7080,7 +7281,7 @@ function ChatRuntime({
7080
7281
  onChange: setSelectedModelId
7081
7282
  }
7082
7283
  ) : null,
7083
- options.composerDictation ? /* @__PURE__ */ jsxs17(
7284
+ options.composerDictation ? /* @__PURE__ */ jsxs18(
7084
7285
  "button",
7085
7286
  {
7086
7287
  "aria-keyshortcuts": isDictationSupported ? DICTATION_KEYBOARD_SHORTCUT : void 0,
@@ -7105,7 +7306,7 @@ function ChatRuntime({
7105
7306
  }
7106
7307
  ) : null,
7107
7308
  attachmentError || options.composerDictation && dictationError ? /* @__PURE__ */ jsx26("span", { className: "ha-dictation-error", role: "alert", children: attachmentError ?? dictationError }) : null,
7108
- isRunning && !hasComposerDraft ? /* @__PURE__ */ jsxs17(
7309
+ isRunning && !hasComposerDraft ? /* @__PURE__ */ jsxs18(
7109
7310
  "button",
7110
7311
  {
7111
7312
  "aria-keyshortcuts": COMPOSER_ACTION_KEYBOARD_SHORTCUT,
@@ -7120,7 +7321,7 @@ function ChatRuntime({
7120
7321
  /* @__PURE__ */ jsx26(ComposerControlTooltip, { shortcut: COMPOSER_ACTION_SHORTCUT_LABEL, children: sendButtonLabel })
7121
7322
  ]
7122
7323
  }
7123
- ) : /* @__PURE__ */ jsxs17(
7324
+ ) : /* @__PURE__ */ jsxs18(
7124
7325
  "button",
7125
7326
  {
7126
7327
  "aria-keyshortcuts": COMPOSER_ACTION_KEYBOARD_SHORTCUT,
@@ -7176,9 +7377,11 @@ function Message({
7176
7377
  const userAttachments = message.role === "user" ? message.parts.flatMap(
7177
7378
  (part, index) => part.type === "file" ? [/* @__PURE__ */ jsx26(MessageAttachment, { file: part }, `${message.id}-attachment-${index}`)] : []
7178
7379
  ) : [];
7380
+ let latestContentPartIndex = -1;
7179
7381
  const content = message.parts.reduce((items, part, index) => {
7180
7382
  if (part.type === "text") {
7181
7383
  if (!part.text.trim()) return items;
7384
+ latestContentPartIndex = index;
7182
7385
  return [
7183
7386
  ...items,
7184
7387
  message.role === "assistant" ? /* @__PURE__ */ jsx26(
@@ -7196,9 +7399,11 @@ function Message({
7196
7399
  }
7197
7400
  if (part.type === "file") {
7198
7401
  if (message.role === "user") return items;
7402
+ latestContentPartIndex = index;
7199
7403
  return [...items, /* @__PURE__ */ jsx26(MessageAttachment, { file: part }, `${message.id}-file-${index}`)];
7200
7404
  }
7201
7405
  if (part.type === "data-component") {
7406
+ latestContentPartIndex = index;
7202
7407
  return [
7203
7408
  ...items,
7204
7409
  /* @__PURE__ */ jsx26(
@@ -7219,6 +7424,7 @@ function Message({
7219
7424
  if (clientToolName && clientTool?.needsApproval) {
7220
7425
  const toolPart = part;
7221
7426
  if (toolPart.state !== "input-available" || toolDecisions[toolPart.toolCallId]) return items;
7427
+ latestContentPartIndex = index;
7222
7428
  return [
7223
7429
  ...items,
7224
7430
  /* @__PURE__ */ jsx26(
@@ -7235,6 +7441,10 @@ function Message({
7235
7441
  }
7236
7442
  return items;
7237
7443
  }, []);
7444
+ const hasResponseStartedAfterLatestActivity = hasResponseAfterLatestActivity(activity, {
7445
+ hasContent: content.length > 0,
7446
+ latestContentPartIndex
7447
+ });
7238
7448
  const visibleSources = getVisibleMessageSources(sources, {
7239
7449
  hasContent: content.length > 0,
7240
7450
  isStreaming
@@ -7243,7 +7453,7 @@ function Message({
7243
7453
  return null;
7244
7454
  }
7245
7455
  if (message.role === "user") {
7246
- return /* @__PURE__ */ jsxs17(
7456
+ return /* @__PURE__ */ jsxs18(
7247
7457
  "div",
7248
7458
  {
7249
7459
  className: "ha-message",
@@ -7266,11 +7476,12 @@ function Message({
7266
7476
  className: "ha-message",
7267
7477
  "data-role": "assistant",
7268
7478
  "data-stream-anchor": isStreaming ? true : void 0,
7269
- children: /* @__PURE__ */ jsxs17("div", { className: "ha-message-body", children: [
7479
+ children: /* @__PURE__ */ jsxs18("div", { className: "ha-message-body", children: [
7270
7480
  activity.length > 0 ? /* @__PURE__ */ jsx26(
7271
7481
  ActivityTrail,
7272
7482
  {
7273
7483
  completedAt: activityTiming?.completedAt,
7484
+ hasResponseStarted: hasResponseStartedAfterLatestActivity,
7274
7485
  isStreaming,
7275
7486
  items: activity,
7276
7487
  progress,
@@ -7334,7 +7545,7 @@ function useAgentTransport({
7334
7545
  const session = restoreTriggerSession(stored, bootstrapStatus);
7335
7546
  return session ? { [conversationId]: session } : void 0;
7336
7547
  }, [bootstrapStatus, conversationId, sessionKey]);
7337
- const reportedReconnectRef = useRef15(false);
7548
+ const reportedReconnectRef = useRef14(false);
7338
7549
  const authorizedFetch = useCallback11(
7339
7550
  (url, init = {}) => fetchWithAgentAuthorization(tokenManager, url, init),
7340
7551
  [tokenManager]