@heroui/agent 0.2.0-beta.3 → 0.2.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +10 -10
- package/dist/{chart-content-USUK4ZM5.js → chart-content-7PZT4YWI.js} +1 -1
- package/dist/{chunk-5FDSKYU6.js → chunk-5X2OXK4I.js} +39 -10
- package/dist/{chunk-CU6MPKAJ.js → chunk-6O3SFXJK.js} +25 -59
- package/dist/{chunk-AEUPMIPT.js → chunk-FNGGMHVR.js} +51 -3
- package/dist/{chunk-EXFDD3K3.js → chunk-XBYPU7PM.js} +5 -4
- package/dist/{component-renderer-EOOT6ONY.js → component-renderer-PTMCOJHE.js} +805 -767
- package/dist/contracts.d.ts +5 -5
- package/dist/contracts.js +2 -8
- package/dist/css/index.css +1 -1
- package/dist/{embed-runtime-O57PH7EP.js → embed-runtime-WVXLM2KL.js} +513 -412
- package/dist/{identity-hIGFpObN.d.ts → identity-CuhZgpvp.d.ts} +0 -3
- package/dist/index.d.ts +15 -3
- package/dist/index.js +2 -2
- package/dist/next.js +2 -2
- package/dist/server.d.ts +1 -1
- package/dist/server.js +1 -7
- package/package.json +2 -2
|
@@ -33,14 +33,13 @@ import {
|
|
|
33
33
|
shouldRestoreActiveAgentPermissionMode,
|
|
34
34
|
storeAgentPermissionMode,
|
|
35
35
|
takeAgentShellHandoff
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-XBYPU7PM.js";
|
|
37
37
|
import {
|
|
38
38
|
ActionButton,
|
|
39
39
|
CodeBlock,
|
|
40
|
-
ComponentSkeleton,
|
|
41
40
|
ScrollShadow,
|
|
42
41
|
renderInlineMarkdown
|
|
43
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-6O3SFXJK.js";
|
|
44
43
|
import {
|
|
45
44
|
CardVariantProvider,
|
|
46
45
|
resolveOverlayPortalContainer
|
|
@@ -1722,12 +1721,12 @@ import { useTriggerChatTransport } from "@trigger.dev/sdk/chat/react";
|
|
|
1722
1721
|
import { lastAssistantMessageIsCompleteWithToolCalls } from "ai";
|
|
1723
1722
|
import {
|
|
1724
1723
|
useCallback as useCallback11,
|
|
1725
|
-
useEffect as
|
|
1724
|
+
useEffect as useEffect14,
|
|
1726
1725
|
useEffectEvent,
|
|
1727
1726
|
useLayoutEffect as useLayoutEffect4,
|
|
1728
1727
|
useMemo as useMemo4,
|
|
1729
|
-
useRef as
|
|
1730
|
-
useState as
|
|
1728
|
+
useRef as useRef15,
|
|
1729
|
+
useState as useState14
|
|
1731
1730
|
} from "react";
|
|
1732
1731
|
|
|
1733
1732
|
// src/contracts/identity.ts
|
|
@@ -1778,7 +1777,7 @@ var agentModelIdSchema = z2.preprocess(
|
|
|
1778
1777
|
|
|
1779
1778
|
// src/contracts/version.ts
|
|
1780
1779
|
var HEROUI_AGENT_PROTOCOL_VERSION = 5;
|
|
1781
|
-
var HEROUI_AGENT_SDK_VERSION = "0.2.0-beta.
|
|
1780
|
+
var HEROUI_AGENT_SDK_VERSION = "0.2.0-beta.4";
|
|
1782
1781
|
var HEROUI_AGENT_TASK_ID = "heroui-agents-runtime";
|
|
1783
1782
|
|
|
1784
1783
|
// src/contracts/identity.ts
|
|
@@ -1910,12 +1909,6 @@ var agentProjectConfigSchema = z3.object({
|
|
|
1910
1909
|
*/
|
|
1911
1910
|
presence: z3.object({ appId: z3.uuid() }).optional(),
|
|
1912
1911
|
protocolVersion: z3.literal(HEROUI_AGENT_PROTOCOL_VERSION),
|
|
1913
|
-
/**
|
|
1914
|
-
* Internal streaming infrastructure endpoint, resolved server-side so
|
|
1915
|
-
* customers never configure it. Optional for compatibility with older API
|
|
1916
|
-
* deployments; the SDK falls back to Trigger.dev's public endpoint.
|
|
1917
|
-
*/
|
|
1918
|
-
realtime: z3.object({ url: z3.url() }).optional(),
|
|
1919
1912
|
sdkVersion: z3.string().default(HEROUI_AGENT_SDK_VERSION),
|
|
1920
1913
|
suggestedPrompts: z3.array(z3.string().trim().min(1).max(160)).max(5),
|
|
1921
1914
|
surfaceVariant: agentSurfaceVariantSchema.default("plain"),
|
|
@@ -1990,7 +1983,7 @@ function collectActivity(message, clientTools, options = {}) {
|
|
|
1990
1983
|
if (renderTool && toolPart.state === "output-error" && (options.isStreaming || laterRenderSucceeded)) {
|
|
1991
1984
|
continue;
|
|
1992
1985
|
}
|
|
1993
|
-
const baseLabel = renderTool ? "Building your data view" : toolName === "executeSandbox" ? "Analyzing your data" : clientTools.get(toolName)?.displayName ?? humanizeToolName(toolName);
|
|
1986
|
+
const baseLabel = renderTool ? "Building your data view" : toolName === "executeSandbox" ? "Analyzing your data" : toolName === "getComponentSchema" ? "Preparing your data view" : clientTools.get(toolName)?.displayName ?? humanizeToolName(toolName);
|
|
1994
1987
|
const rejected = Boolean(
|
|
1995
1988
|
toolPart.output && typeof toolPart.output === "object" && "rejected" in toolPart.output && toolPart.output.rejected
|
|
1996
1989
|
);
|
|
@@ -2000,7 +1993,7 @@ function collectActivity(message, clientTools, options = {}) {
|
|
|
2000
1993
|
items.push({
|
|
2001
1994
|
active: toolPart.state === "input-available" || toolPart.state === "input-streaming",
|
|
2002
1995
|
id: toolPart.toolCallId || `${message.id}-tool-${index}`,
|
|
2003
|
-
kind: renderTool ? "chart" : toolName === "executeSandbox" ? "code" : inferActivityKind(label),
|
|
1996
|
+
kind: renderTool ? "chart" : toolName === "executeSandbox" ? "code" : toolName === "getComponentSchema" ? "thinking" : inferActivityKind(label),
|
|
2004
1997
|
label
|
|
2005
1998
|
});
|
|
2006
1999
|
}
|
|
@@ -2018,7 +2011,10 @@ import {
|
|
|
2018
2011
|
Wrench
|
|
2019
2012
|
} from "@gravity-ui/icons";
|
|
2020
2013
|
import { Disclosure as Disclosure2 } from "@heroui/react";
|
|
2021
|
-
import { useEffect as
|
|
2014
|
+
import { useEffect as useEffect7, useRef as useRef6, useState as useState4 } from "react";
|
|
2015
|
+
|
|
2016
|
+
// src/embed/animated-status-text.tsx
|
|
2017
|
+
import { useEffect as useEffect5, useRef as useRef5 } from "react";
|
|
2022
2018
|
|
|
2023
2019
|
// src/embed/shimmer-text.tsx
|
|
2024
2020
|
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
@@ -2028,7 +2024,17 @@ function ShimmerText({ children, className, ...props }) {
|
|
|
2028
2024
|
|
|
2029
2025
|
// src/embed/animated-status-text.tsx
|
|
2030
2026
|
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
2031
|
-
function AnimatedStatusText({
|
|
2027
|
+
function AnimatedStatusText({
|
|
2028
|
+
animateOnMount = true,
|
|
2029
|
+
children,
|
|
2030
|
+
className,
|
|
2031
|
+
...props
|
|
2032
|
+
}) {
|
|
2033
|
+
const previousValueRef = useRef5(children);
|
|
2034
|
+
const shouldAnimate = animateOnMount || previousValueRef.current !== children;
|
|
2035
|
+
useEffect5(() => {
|
|
2036
|
+
previousValueRef.current = children;
|
|
2037
|
+
}, [children]);
|
|
2032
2038
|
return /* @__PURE__ */ jsx7(
|
|
2033
2039
|
"span",
|
|
2034
2040
|
{
|
|
@@ -2040,7 +2046,7 @@ function AnimatedStatusText({ children, className, ...props }) {
|
|
|
2040
2046
|
"span",
|
|
2041
2047
|
{
|
|
2042
2048
|
"aria-hidden": "true",
|
|
2043
|
-
className: "ha-status-text__value",
|
|
2049
|
+
className: shouldAnimate ? "ha-status-text__value ha-status-text__value--animated" : "ha-status-text__value",
|
|
2044
2050
|
"data-slot": "animated-text-value",
|
|
2045
2051
|
children: /* @__PURE__ */ jsx7(ShimmerText, { children })
|
|
2046
2052
|
},
|
|
@@ -2051,7 +2057,7 @@ function AnimatedStatusText({ children, className, ...props }) {
|
|
|
2051
2057
|
}
|
|
2052
2058
|
|
|
2053
2059
|
// src/embed/use-scroll-shadow.ts
|
|
2054
|
-
import { useEffect as
|
|
2060
|
+
import { useEffect as useEffect6 } from "react";
|
|
2055
2061
|
function getScrollShadowState(element, offset = 1) {
|
|
2056
2062
|
const hasScrollBefore = element.scrollTop > offset;
|
|
2057
2063
|
const hasScrollAfter = element.scrollTop + element.clientHeight + offset < element.scrollHeight;
|
|
@@ -2073,7 +2079,7 @@ function applyScrollShadowState(element, state) {
|
|
|
2073
2079
|
}
|
|
2074
2080
|
}
|
|
2075
2081
|
function useScrollShadow(ref, offset = 1) {
|
|
2076
|
-
|
|
2082
|
+
useEffect6(() => {
|
|
2077
2083
|
const element = ref.current;
|
|
2078
2084
|
if (!element) return;
|
|
2079
2085
|
let animationFrame = null;
|
|
@@ -2108,8 +2114,8 @@ function useScrollShadow(ref, offset = 1) {
|
|
|
2108
2114
|
import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
2109
2115
|
var FOLLOW_THRESHOLD_PX = 24;
|
|
2110
2116
|
function useFollowNewestStep(ref, stepCount, isStreaming, isExpanded) {
|
|
2111
|
-
const isFollowingRef =
|
|
2112
|
-
|
|
2117
|
+
const isFollowingRef = useRef6(true);
|
|
2118
|
+
useEffect7(() => {
|
|
2113
2119
|
const element = ref.current;
|
|
2114
2120
|
if (!element) return;
|
|
2115
2121
|
const handleScroll = () => {
|
|
@@ -2119,7 +2125,7 @@ function useFollowNewestStep(ref, stepCount, isStreaming, isExpanded) {
|
|
|
2119
2125
|
element.addEventListener("scroll", handleScroll, { passive: true });
|
|
2120
2126
|
return () => element.removeEventListener("scroll", handleScroll);
|
|
2121
2127
|
}, [isExpanded, ref]);
|
|
2122
|
-
|
|
2128
|
+
useEffect7(() => {
|
|
2123
2129
|
const element = ref.current;
|
|
2124
2130
|
if (!element || !isExpanded || !isStreaming || !isFollowingRef.current) return;
|
|
2125
2131
|
element.scrollTop = element.scrollHeight;
|
|
@@ -2142,15 +2148,8 @@ function formatActivityDuration(durationMs) {
|
|
|
2142
2148
|
if (minutes > 0) return `${minutes}m ${seconds}s`;
|
|
2143
2149
|
return `${seconds}s`;
|
|
2144
2150
|
}
|
|
2145
|
-
function
|
|
2146
|
-
|
|
2147
|
-
return /* @__PURE__ */ jsx8("span", { className: "ha-activity-status-icon", children: /* @__PURE__ */ jsx8(Icon, { "aria-hidden": "true" }) }, kind);
|
|
2148
|
-
}
|
|
2149
|
-
function ActivityStatus({ label }) {
|
|
2150
|
-
return /* @__PURE__ */ jsxs5("div", { className: "ha-progress ha-activity-status", children: [
|
|
2151
|
-
/* @__PURE__ */ jsx8(ActivityStatusIcon, { kind: inferActivityKind(label) }),
|
|
2152
|
-
/* @__PURE__ */ jsx8(AnimatedStatusText, { className: "ha-progress-shimmer", role: "status", children: label })
|
|
2153
|
-
] });
|
|
2151
|
+
function ActivityStatus({ ariaLabel, label }) {
|
|
2152
|
+
return /* @__PURE__ */ jsx8("div", { className: "ha-progress ha-activity-status", children: /* @__PURE__ */ jsx8(AnimatedStatusText, { "aria-label": ariaLabel, className: "ha-progress-shimmer", role: "status", children: label }) });
|
|
2154
2153
|
}
|
|
2155
2154
|
function ActivityTrail({
|
|
2156
2155
|
completedAt,
|
|
@@ -2161,26 +2160,25 @@ function ActivityTrail({
|
|
|
2161
2160
|
startedAt
|
|
2162
2161
|
}) {
|
|
2163
2162
|
const [isExpanded, setIsExpanded] = useState4(defaultOpen);
|
|
2164
|
-
const panelRef =
|
|
2163
|
+
const panelRef = useRef6(null);
|
|
2165
2164
|
const activeItem = items.findLast((item) => item.active);
|
|
2166
2165
|
const latestItem = items.at(-1);
|
|
2167
2166
|
const activeLabel = activeItem?.label ?? latestItem?.label ?? progress ?? "Understanding your request\u2026";
|
|
2168
2167
|
const elapsedMs = startedAt !== void 0 && !isStreaming ? Math.max(0, (completedAt ?? Date.now()) - startedAt) : null;
|
|
2169
2168
|
const summary = isStreaming ? activeLabel : elapsedMs === null ? "Activity" : `Worked for ${formatActivityDuration(elapsedMs)}`;
|
|
2170
|
-
const summaryKind = isStreaming ? activeItem?.kind ?? inferActivityKind(activeLabel) : "complete";
|
|
2171
2169
|
useScrollShadow(panelRef);
|
|
2172
2170
|
useFollowNewestStep(panelRef, items.length, isStreaming, isExpanded);
|
|
2173
2171
|
return /* @__PURE__ */ jsxs5(Disclosure2, { className: "ha-activity", isExpanded, onExpandedChange: setIsExpanded, children: [
|
|
2174
2172
|
/* @__PURE__ */ jsx8(Disclosure2.Heading, { children: /* @__PURE__ */ jsxs5(Disclosure2.Trigger, { className: "ha-activity-trigger", children: [
|
|
2175
|
-
/* @__PURE__ */ jsx8(ActivityStatusIcon, { kind: summaryKind }),
|
|
2176
2173
|
isStreaming ? /* @__PURE__ */ jsx8(
|
|
2177
2174
|
AnimatedStatusText,
|
|
2178
2175
|
{
|
|
2179
|
-
|
|
2176
|
+
animateOnMount: summary !== progress,
|
|
2177
|
+
className: "ha-activity-summary-label ha-progress ha-progress-shimmer",
|
|
2180
2178
|
role: "status",
|
|
2181
2179
|
children: summary
|
|
2182
2180
|
}
|
|
2183
|
-
) : /* @__PURE__ */ jsx8("span", { children: summary }),
|
|
2181
|
+
) : /* @__PURE__ */ jsx8("span", { className: "ha-progress", children: summary }),
|
|
2184
2182
|
/* @__PURE__ */ jsx8(Disclosure2.Indicator, { className: "ha-activity-chevron" })
|
|
2185
2183
|
] }) }),
|
|
2186
2184
|
/* @__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: [
|
|
@@ -2224,6 +2222,24 @@ function agentRequestHeaders(token, json = false) {
|
|
|
2224
2222
|
"X-HeroUI-Agent-SDK-Version": HEROUI_AGENT_SDK_VERSION
|
|
2225
2223
|
};
|
|
2226
2224
|
}
|
|
2225
|
+
async function fetchWithAgentAuthorization(tokenManager, url, init = {}) {
|
|
2226
|
+
const request = async () => {
|
|
2227
|
+
const headers = new Headers(init.headers);
|
|
2228
|
+
headers.set("Authorization", `Bearer ${await tokenManager.get()}`);
|
|
2229
|
+
headers.set("X-HeroUI-Agent-Protocol-Version", String(HEROUI_AGENT_PROTOCOL_VERSION));
|
|
2230
|
+
headers.set("X-HeroUI-Agent-SDK-Version", HEROUI_AGENT_SDK_VERSION);
|
|
2231
|
+
return fetch(url, { ...init, headers });
|
|
2232
|
+
};
|
|
2233
|
+
let response = await request();
|
|
2234
|
+
if (response.status === 401) {
|
|
2235
|
+
tokenManager.clear();
|
|
2236
|
+
response = await request();
|
|
2237
|
+
}
|
|
2238
|
+
return response;
|
|
2239
|
+
}
|
|
2240
|
+
function agentTransportBaseUrl(apiBaseUrl) {
|
|
2241
|
+
return `${apiBaseUrl.replace(/\/$/, "")}/v1/trigger`;
|
|
2242
|
+
}
|
|
2227
2243
|
async function fetchConversationBootstrap(options, tokenManager, conversationId) {
|
|
2228
2244
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
2229
2245
|
const response = await fetch(
|
|
@@ -2425,88 +2441,40 @@ function serializeClientTools(tools) {
|
|
|
2425
2441
|
);
|
|
2426
2442
|
}
|
|
2427
2443
|
|
|
2444
|
+
// src/embed/component-action-routing.ts
|
|
2445
|
+
function routeComponentPromptAction(action, { fillComposer, setSelection, submitPrompt }) {
|
|
2446
|
+
if (action.type === "followup") {
|
|
2447
|
+
submitPrompt(action.prompt);
|
|
2448
|
+
return true;
|
|
2449
|
+
}
|
|
2450
|
+
if (action.type === "submit") {
|
|
2451
|
+
setSelection({
|
|
2452
|
+
componentId: action.componentId,
|
|
2453
|
+
componentTitle: action.componentTitle,
|
|
2454
|
+
datum: { actionId: action.actionId, values: action.values }
|
|
2455
|
+
});
|
|
2456
|
+
if (action.prompt) fillComposer(action.prompt);
|
|
2457
|
+
return true;
|
|
2458
|
+
}
|
|
2459
|
+
if (action.type === "tool") {
|
|
2460
|
+
fillComposer(action.prompt ?? action.label);
|
|
2461
|
+
return true;
|
|
2462
|
+
}
|
|
2463
|
+
return false;
|
|
2464
|
+
}
|
|
2465
|
+
|
|
2428
2466
|
// src/embed/component-preview.ts
|
|
2429
|
-
|
|
2430
|
-
"
|
|
2431
|
-
"kpi-grid",
|
|
2432
|
-
"line-chart",
|
|
2433
|
-
"area-chart",
|
|
2434
|
-
"bar-chart",
|
|
2435
|
-
"composed-chart",
|
|
2436
|
-
"pie-chart",
|
|
2437
|
-
"donut-chart",
|
|
2438
|
-
"radar-chart",
|
|
2439
|
-
"radial-chart",
|
|
2440
|
-
"sankey-chart",
|
|
2441
|
-
"scatter-chart",
|
|
2442
|
-
"heatmap",
|
|
2443
|
-
"data-table",
|
|
2444
|
-
"comparison-list",
|
|
2445
|
-
"meter-list",
|
|
2446
|
-
"form",
|
|
2447
|
-
"text",
|
|
2448
|
-
"callout",
|
|
2449
|
-
"channel-message",
|
|
2450
|
-
"create-event",
|
|
2451
|
-
"enable-notification",
|
|
2452
|
-
"event-session",
|
|
2453
|
-
"flight-tracker",
|
|
2454
|
-
"image",
|
|
2455
|
-
"tag-list",
|
|
2456
|
-
"list",
|
|
2457
|
-
"list-block",
|
|
2458
|
-
"map",
|
|
2459
|
-
"player-card",
|
|
2460
|
-
"playlist",
|
|
2461
|
-
"product-signals",
|
|
2462
|
-
"purchase-complete",
|
|
2463
|
-
"purchase-items",
|
|
2464
|
-
"accordion",
|
|
2465
|
-
"steps",
|
|
2466
|
-
"code-block",
|
|
2467
|
-
"tabs",
|
|
2468
|
-
"action-group",
|
|
2469
|
-
"followup",
|
|
2470
|
-
"switch-group",
|
|
2471
|
-
"toggle-group",
|
|
2472
|
-
"record-card",
|
|
2473
|
-
"ride-status",
|
|
2474
|
-
"view-event",
|
|
2475
|
-
"weather-current",
|
|
2476
|
-
"weather-forecast",
|
|
2477
|
-
"dashboard",
|
|
2478
|
-
"row",
|
|
2479
|
-
"col",
|
|
2480
|
-
"grid",
|
|
2481
|
-
"card",
|
|
2482
|
-
"item-card",
|
|
2483
|
-
"item-card-group"
|
|
2484
|
-
]);
|
|
2485
|
-
function componentPreview(toolName, input) {
|
|
2486
|
-
if (!input || typeof input !== "object") return {};
|
|
2487
|
-
const request = input;
|
|
2488
|
-
const candidate = toolName === "composeUI" && request["component"] && typeof request["component"] === "object" ? request["component"] : request;
|
|
2489
|
-
const kind = typeof candidate["kind"] === "string" && AGENT_UI_KINDS.has(candidate["kind"]) ? candidate["kind"] : void 0;
|
|
2490
|
-
return {
|
|
2491
|
-
kind,
|
|
2492
|
-
title: typeof candidate["title"] === "string" ? candidate["title"] : void 0
|
|
2493
|
-
};
|
|
2467
|
+
function isRenderToolName(value) {
|
|
2468
|
+
return value === "composeUI" || value === "renderComponent";
|
|
2494
2469
|
}
|
|
2495
|
-
function
|
|
2496
|
-
if (!part || typeof part !== "object") return
|
|
2470
|
+
function isStreamingComponentBuild(part) {
|
|
2471
|
+
if (!part || typeof part !== "object") return false;
|
|
2497
2472
|
const candidate = part;
|
|
2498
2473
|
const state = candidate["state"];
|
|
2499
|
-
if (state !== "input-streaming" && state !== "input-available") return
|
|
2474
|
+
if (state !== "input-streaming" && state !== "input-available") return false;
|
|
2500
2475
|
const type = candidate["type"];
|
|
2501
2476
|
const toolName = type === "dynamic-tool" ? candidate["toolName"] : typeof type === "string" && type.startsWith("tool-") ? type.slice("tool-".length) : null;
|
|
2502
|
-
|
|
2503
|
-
return null;
|
|
2504
|
-
}
|
|
2505
|
-
const toolCallId = candidate["toolCallId"];
|
|
2506
|
-
if (typeof toolCallId !== "string" || !toolCallId) return null;
|
|
2507
|
-
const preview = componentPreview(toolName, candidate["input"]);
|
|
2508
|
-
if (!preview.kind) return null;
|
|
2509
|
-
return { ...preview, kind: preview.kind, toolCallId };
|
|
2477
|
+
return isRenderToolName(toolName);
|
|
2510
2478
|
}
|
|
2511
2479
|
|
|
2512
2480
|
// src/embed/composer-attachment.tsx
|
|
@@ -2866,14 +2834,14 @@ var ConversationMarkdown = memo(function ConversationMarkdown2({
|
|
|
2866
2834
|
});
|
|
2867
2835
|
|
|
2868
2836
|
// src/embed/conversation-presence.tsx
|
|
2869
|
-
import { useEffect as
|
|
2837
|
+
import { useEffect as useEffect8 } from "react";
|
|
2870
2838
|
function AgentConversationPresence({
|
|
2871
2839
|
agentId,
|
|
2872
2840
|
appId,
|
|
2873
2841
|
conversationId,
|
|
2874
2842
|
userId
|
|
2875
2843
|
}) {
|
|
2876
|
-
|
|
2844
|
+
useEffect8(
|
|
2877
2845
|
() => syncAgentConversationPresence({ agentId, appId, conversationId, userId }),
|
|
2878
2846
|
[agentId, appId, conversationId, userId]
|
|
2879
2847
|
);
|
|
@@ -2881,6 +2849,7 @@ function AgentConversationPresence({
|
|
|
2881
2849
|
}
|
|
2882
2850
|
|
|
2883
2851
|
// src/embed/conversation-presentation.ts
|
|
2852
|
+
var DEFAULT_ACTIVITY_STATUS = "Planning next moves\u2026";
|
|
2884
2853
|
function getConversationPresentation({
|
|
2885
2854
|
hasError,
|
|
2886
2855
|
hasStreamingActivity,
|
|
@@ -2896,7 +2865,7 @@ function getConversationPresentation({
|
|
|
2896
2865
|
return { showHome, standaloneStatus: null };
|
|
2897
2866
|
}
|
|
2898
2867
|
if (isActiveTurn) {
|
|
2899
|
-
return { showHome, standaloneStatus: progress ??
|
|
2868
|
+
return { showHome, standaloneStatus: progress ?? DEFAULT_ACTIVITY_STATUS };
|
|
2900
2869
|
}
|
|
2901
2870
|
if (isAwaitingActiveConversation) {
|
|
2902
2871
|
return { showHome, standaloneStatus: "Loading chat\u2026" };
|
|
@@ -2927,16 +2896,32 @@ function ConversationRouteStack({
|
|
|
2927
2896
|
});
|
|
2928
2897
|
}
|
|
2929
2898
|
|
|
2899
|
+
// src/embed/conversation-turn-anchor.ts
|
|
2900
|
+
function resolveConversationTurnAnchor({
|
|
2901
|
+
conversationId,
|
|
2902
|
+
isActive,
|
|
2903
|
+
lastUserMessageId,
|
|
2904
|
+
pendingTurn
|
|
2905
|
+
}) {
|
|
2906
|
+
const normalizedLastUserMessageId = lastUserMessageId ?? null;
|
|
2907
|
+
const hasActiveOptimisticUser = pendingTurn ? normalizedLastUserMessageId !== pendingTurn.previousUserMessageId : normalizedLastUserMessageId !== null;
|
|
2908
|
+
const activeTurnMessageId = isActive ? hasActiveOptimisticUser ? normalizedLastUserMessageId : null : normalizedLastUserMessageId;
|
|
2909
|
+
const activeStreamKey = isActive ? pendingTurn?.messageId ?? activeTurnMessageId ?? conversationId : null;
|
|
2910
|
+
return { activeStreamKey, activeTurnMessageId };
|
|
2911
|
+
}
|
|
2912
|
+
|
|
2930
2913
|
// src/embed/conversation-viewport.tsx
|
|
2931
2914
|
import { ChevronDown } from "@gravity-ui/icons";
|
|
2932
2915
|
import { Button } from "@heroui/react";
|
|
2933
|
-
import { useLayoutEffect as useLayoutEffect2, useRef as
|
|
2916
|
+
import { useLayoutEffect as useLayoutEffect2, useRef as useRef8 } from "react";
|
|
2934
2917
|
|
|
2935
2918
|
// src/embed/use-conversation-scroll.ts
|
|
2936
|
-
import { useCallback as useCallback5, useEffect as
|
|
2919
|
+
import { useCallback as useCallback5, useEffect as useEffect9, useLayoutEffect, useRef as useRef7, useState as useState6 } from "react";
|
|
2937
2920
|
var BOTTOM_THRESHOLD = 4;
|
|
2938
2921
|
var SCROLL_DIRECTION_THRESHOLD = 1;
|
|
2922
|
+
var ACTIVE_TURN_SPACER_PROPERTY = "--ha-active-turn-spacer-height";
|
|
2939
2923
|
var STREAM_ANCHOR_SELECTOR = '[data-stream-anchor="true"]';
|
|
2924
|
+
var TURN_ANCHOR_SELECTOR = '[data-turn-anchor="true"]';
|
|
2940
2925
|
var DEFAULT_SCROLL_STATE = {
|
|
2941
2926
|
hasOverflow: false,
|
|
2942
2927
|
isAtBottom: true
|
|
@@ -2946,6 +2931,15 @@ function getConversationScrollState(element) {
|
|
|
2946
2931
|
const isAtBottom = !hasOverflow || element.scrollHeight - Math.max(0, element.scrollTop) - element.clientHeight <= BOTTOM_THRESHOLD;
|
|
2947
2932
|
return { hasOverflow, isAtBottom };
|
|
2948
2933
|
}
|
|
2934
|
+
function getActiveTurnSpacerHeight({
|
|
2935
|
+
anchorTop,
|
|
2936
|
+
clientHeight,
|
|
2937
|
+
contentHeight,
|
|
2938
|
+
paddingTop
|
|
2939
|
+
}) {
|
|
2940
|
+
const turnHeight = Math.max(0, contentHeight - anchorTop);
|
|
2941
|
+
return Math.min(Math.max(clientHeight - turnHeight - paddingTop, 0), clientHeight);
|
|
2942
|
+
}
|
|
2949
2943
|
function isSameScrollState(currentState, nextState) {
|
|
2950
2944
|
return currentState.hasOverflow === nextState.hasOverflow && currentState.isAtBottom === nextState.isAtBottom;
|
|
2951
2945
|
}
|
|
@@ -2956,24 +2950,51 @@ function getNativeScrollBehavior(behavior) {
|
|
|
2956
2950
|
return "auto";
|
|
2957
2951
|
}
|
|
2958
2952
|
function useConversationScroll(ref) {
|
|
2959
|
-
const
|
|
2960
|
-
const
|
|
2961
|
-
const
|
|
2962
|
-
const
|
|
2963
|
-
const
|
|
2964
|
-
const
|
|
2953
|
+
const activeTurnSpacerHeightRef = useRef7(0);
|
|
2954
|
+
const attachedRef = useRef7(true);
|
|
2955
|
+
const currentStreamKeyRef = useRef7(null);
|
|
2956
|
+
const isAutoScrollingRef = useRef7(false);
|
|
2957
|
+
const isPinnedTurnAnimatingRef = useRef7(false);
|
|
2958
|
+
const lastScrollTopRef = useRef7(0);
|
|
2959
|
+
const pinnedStreamKeyRef = useRef7(null);
|
|
2960
|
+
const pinnedStreamTopRef = useRef7(null);
|
|
2961
|
+
const shouldAnimatePinnedTurnRef = useRef7(false);
|
|
2965
2962
|
const [scrollState, setScrollState] = useState6(DEFAULT_SCROLL_STATE);
|
|
2966
2963
|
const setNextScrollState = useCallback5((nextState) => {
|
|
2967
2964
|
setScrollState(
|
|
2968
2965
|
(currentState) => isSameScrollState(currentState, nextState) ? currentState : nextState
|
|
2969
2966
|
);
|
|
2970
2967
|
}, []);
|
|
2968
|
+
const updateActiveTurnSpacer = useCallback5((element) => {
|
|
2969
|
+
const anchor = element.querySelector(STREAM_ANCHOR_SELECTOR) ?? element.querySelector(TURN_ANCHOR_SELECTOR);
|
|
2970
|
+
let nextHeight = 0;
|
|
2971
|
+
if (anchor) {
|
|
2972
|
+
const containerRect = element.getBoundingClientRect();
|
|
2973
|
+
const anchorRect = anchor.getBoundingClientRect();
|
|
2974
|
+
const anchorTop = anchorRect.top - containerRect.top + element.scrollTop;
|
|
2975
|
+
const contentHeight = element.scrollHeight - activeTurnSpacerHeightRef.current;
|
|
2976
|
+
const paddingTop = Number.parseFloat(window.getComputedStyle(element).paddingTop) || 0;
|
|
2977
|
+
nextHeight = getActiveTurnSpacerHeight({
|
|
2978
|
+
anchorTop,
|
|
2979
|
+
clientHeight: element.clientHeight,
|
|
2980
|
+
contentHeight,
|
|
2981
|
+
paddingTop
|
|
2982
|
+
});
|
|
2983
|
+
}
|
|
2984
|
+
if (Math.abs(nextHeight - activeTurnSpacerHeightRef.current) > 1) {
|
|
2985
|
+
activeTurnSpacerHeightRef.current = nextHeight;
|
|
2986
|
+
element.style.setProperty(ACTIVE_TURN_SPACER_PROPERTY, `${nextHeight}px`);
|
|
2987
|
+
}
|
|
2988
|
+
return activeTurnSpacerHeightRef.current;
|
|
2989
|
+
}, []);
|
|
2971
2990
|
const scrollToBottom = useCallback5(
|
|
2972
2991
|
(behavior = "smooth") => {
|
|
2973
2992
|
const element = ref.current;
|
|
2974
2993
|
if (!element) return;
|
|
2975
2994
|
pinnedStreamKeyRef.current = null;
|
|
2976
2995
|
pinnedStreamTopRef.current = null;
|
|
2996
|
+
isPinnedTurnAnimatingRef.current = false;
|
|
2997
|
+
shouldAnimatePinnedTurnRef.current = false;
|
|
2977
2998
|
attachedRef.current = true;
|
|
2978
2999
|
isAutoScrollingRef.current = true;
|
|
2979
3000
|
lastScrollTopRef.current = element.scrollTop;
|
|
@@ -3001,9 +3022,11 @@ function useConversationScroll(ref) {
|
|
|
3001
3022
|
return pinnedStreamTopRef.current;
|
|
3002
3023
|
}, []);
|
|
3003
3024
|
const scrollToPinnedPosition = useCallback5(
|
|
3004
|
-
(element, top) => {
|
|
3025
|
+
(element, top, behavior = "auto") => {
|
|
3005
3026
|
const maximumScrollTop = Math.max(0, element.scrollHeight - element.clientHeight);
|
|
3006
3027
|
const targetTop = Math.min(top, maximumScrollTop);
|
|
3028
|
+
const nativeBehavior = getNativeScrollBehavior(behavior);
|
|
3029
|
+
isPinnedTurnAnimatingRef.current = nativeBehavior === "smooth" && Math.abs(Math.max(0, element.scrollTop) - targetTop) > SCROLL_DIRECTION_THRESHOLD;
|
|
3007
3030
|
isAutoScrollingRef.current = true;
|
|
3008
3031
|
lastScrollTopRef.current = element.scrollTop;
|
|
3009
3032
|
setNextScrollState({
|
|
@@ -3011,9 +3034,10 @@ function useConversationScroll(ref) {
|
|
|
3011
3034
|
isAtBottom: maximumScrollTop - targetTop <= BOTTOM_THRESHOLD
|
|
3012
3035
|
});
|
|
3013
3036
|
if (typeof element.scrollTo === "function") {
|
|
3014
|
-
element.scrollTo({ behavior:
|
|
3037
|
+
element.scrollTo({ behavior: nativeBehavior, top });
|
|
3015
3038
|
} else {
|
|
3016
3039
|
element.scrollTop = top;
|
|
3040
|
+
isPinnedTurnAnimatingRef.current = false;
|
|
3017
3041
|
}
|
|
3018
3042
|
lastScrollTopRef.current = Math.max(0, element.scrollTop);
|
|
3019
3043
|
},
|
|
@@ -3022,6 +3046,7 @@ function useConversationScroll(ref) {
|
|
|
3022
3046
|
const maintainScrollPosition = useCallback5(() => {
|
|
3023
3047
|
const element = ref.current;
|
|
3024
3048
|
if (!element) return;
|
|
3049
|
+
const activeTurnSpacerHeight = updateActiveTurnSpacer(element);
|
|
3025
3050
|
const measuredState = getConversationScrollState(element);
|
|
3026
3051
|
const scrollTop = Math.max(0, element.scrollTop);
|
|
3027
3052
|
const scrolledUp = scrollTop < lastScrollTopRef.current - SCROLL_DIRECTION_THRESHOLD;
|
|
@@ -3029,8 +3054,10 @@ function useConversationScroll(ref) {
|
|
|
3029
3054
|
if (scrolledUp && !measuredState.isAtBottom) {
|
|
3030
3055
|
attachedRef.current = false;
|
|
3031
3056
|
isAutoScrollingRef.current = false;
|
|
3057
|
+
isPinnedTurnAnimatingRef.current = false;
|
|
3032
3058
|
pinnedStreamKeyRef.current = null;
|
|
3033
3059
|
pinnedStreamTopRef.current = null;
|
|
3060
|
+
shouldAnimatePinnedTurnRef.current = false;
|
|
3034
3061
|
setNextScrollState(measuredState);
|
|
3035
3062
|
return;
|
|
3036
3063
|
}
|
|
@@ -3039,15 +3066,34 @@ function useConversationScroll(ref) {
|
|
|
3039
3066
|
}
|
|
3040
3067
|
if (attachedRef.current) {
|
|
3041
3068
|
const pinnedStreamTop = getPinnedStreamTop(element);
|
|
3042
|
-
if (pinnedStreamTop !== null) {
|
|
3043
|
-
|
|
3069
|
+
if (pinnedStreamTop !== null && isPinnedTurnAnimatingRef.current) {
|
|
3070
|
+
const maximumScrollTop = Math.max(0, element.scrollHeight - element.clientHeight);
|
|
3071
|
+
const targetTop = Math.min(pinnedStreamTop, maximumScrollTop);
|
|
3072
|
+
if (Math.abs(scrollTop - targetTop) > SCROLL_DIRECTION_THRESHOLD) {
|
|
3073
|
+
setNextScrollState({ hasOverflow: measuredState.hasOverflow, isAtBottom: true });
|
|
3074
|
+
return;
|
|
3075
|
+
}
|
|
3076
|
+
isAutoScrollingRef.current = false;
|
|
3077
|
+
isPinnedTurnAnimatingRef.current = false;
|
|
3078
|
+
}
|
|
3079
|
+
if (pinnedStreamTop !== null && activeTurnSpacerHeight > BOTTOM_THRESHOLD) {
|
|
3080
|
+
const behavior = shouldAnimatePinnedTurnRef.current ? "smooth" : "auto";
|
|
3081
|
+
shouldAnimatePinnedTurnRef.current = false;
|
|
3082
|
+
scrollToPinnedPosition(element, pinnedStreamTop, behavior);
|
|
3044
3083
|
return;
|
|
3045
3084
|
}
|
|
3046
3085
|
scrollToBottom("auto");
|
|
3047
3086
|
return;
|
|
3048
3087
|
}
|
|
3049
3088
|
setNextScrollState({ hasOverflow: measuredState.hasOverflow, isAtBottom: false });
|
|
3050
|
-
}, [
|
|
3089
|
+
}, [
|
|
3090
|
+
getPinnedStreamTop,
|
|
3091
|
+
ref,
|
|
3092
|
+
scrollToBottom,
|
|
3093
|
+
scrollToPinnedPosition,
|
|
3094
|
+
setNextScrollState,
|
|
3095
|
+
updateActiveTurnSpacer
|
|
3096
|
+
]);
|
|
3051
3097
|
const setPinnedStream = useCallback5(
|
|
3052
3098
|
(streamKey) => {
|
|
3053
3099
|
const element = ref.current;
|
|
@@ -3056,10 +3102,15 @@ function useConversationScroll(ref) {
|
|
|
3056
3102
|
currentStreamKeyRef.current = streamKey;
|
|
3057
3103
|
pinnedStreamKeyRef.current = streamKey;
|
|
3058
3104
|
pinnedStreamTopRef.current = null;
|
|
3059
|
-
isAutoScrollingRef.current = false;
|
|
3060
3105
|
if (streamKey) {
|
|
3106
|
+
if (!hadActiveStream) {
|
|
3107
|
+
shouldAnimatePinnedTurnRef.current = true;
|
|
3108
|
+
}
|
|
3061
3109
|
attachedRef.current = true;
|
|
3062
3110
|
} else if (hadActiveStream) {
|
|
3111
|
+
isAutoScrollingRef.current = false;
|
|
3112
|
+
isPinnedTurnAnimatingRef.current = false;
|
|
3113
|
+
shouldAnimatePinnedTurnRef.current = false;
|
|
3063
3114
|
const measuredState = getConversationScrollState(element);
|
|
3064
3115
|
attachedRef.current = measuredState.isAtBottom;
|
|
3065
3116
|
setNextScrollState(measuredState);
|
|
@@ -3073,7 +3124,7 @@ function useConversationScroll(ref) {
|
|
|
3073
3124
|
lastScrollTopRef.current = element.scrollTop;
|
|
3074
3125
|
maintainScrollPosition();
|
|
3075
3126
|
}, [maintainScrollPosition, ref]);
|
|
3076
|
-
|
|
3127
|
+
useEffect9(() => {
|
|
3077
3128
|
const element = ref.current;
|
|
3078
3129
|
if (!element) return;
|
|
3079
3130
|
const handleScroll = () => {
|
|
@@ -3085,17 +3136,22 @@ function useConversationScroll(ref) {
|
|
|
3085
3136
|
const pinnedStreamTop = getPinnedStreamTop(element);
|
|
3086
3137
|
const maximumScrollTop = Math.max(0, element.scrollHeight - element.clientHeight);
|
|
3087
3138
|
const automaticTarget = Math.min(pinnedStreamTop ?? maximumScrollTop, maximumScrollTop);
|
|
3088
|
-
|
|
3139
|
+
const reachedAutomaticTarget = measuredState.isAtBottom || Math.abs(scrollTop - automaticTarget) <= SCROLL_DIRECTION_THRESHOLD;
|
|
3140
|
+
const wasPinnedTurnAnimating = isPinnedTurnAnimatingRef.current;
|
|
3141
|
+
if (reachedAutomaticTarget) {
|
|
3089
3142
|
isAutoScrollingRef.current = false;
|
|
3143
|
+
isPinnedTurnAnimatingRef.current = false;
|
|
3090
3144
|
}
|
|
3091
3145
|
setNextScrollState(
|
|
3092
|
-
pinnedStreamTop === null ? { hasOverflow: measuredState.hasOverflow, isAtBottom: attachedRef.current } : measuredState
|
|
3146
|
+
wasPinnedTurnAnimating && !reachedAutomaticTarget ? { hasOverflow: measuredState.hasOverflow, isAtBottom: true } : pinnedStreamTop === null ? { hasOverflow: measuredState.hasOverflow, isAtBottom: attachedRef.current } : measuredState
|
|
3093
3147
|
);
|
|
3094
3148
|
return;
|
|
3095
3149
|
}
|
|
3096
3150
|
isAutoScrollingRef.current = false;
|
|
3151
|
+
isPinnedTurnAnimatingRef.current = false;
|
|
3097
3152
|
pinnedStreamKeyRef.current = null;
|
|
3098
3153
|
pinnedStreamTopRef.current = null;
|
|
3154
|
+
shouldAnimatePinnedTurnRef.current = false;
|
|
3099
3155
|
attachedRef.current = measuredState.isAtBottom;
|
|
3100
3156
|
setNextScrollState(measuredState);
|
|
3101
3157
|
};
|
|
@@ -3132,8 +3188,12 @@ function useConversationScroll(ref) {
|
|
|
3132
3188
|
mutationObserver?.observe(element, { characterData: true, childList: true, subtree: true });
|
|
3133
3189
|
return () => {
|
|
3134
3190
|
element.removeEventListener("scroll", handleScroll);
|
|
3135
|
-
mutationObserver
|
|
3136
|
-
|
|
3191
|
+
if (mutationObserver) {
|
|
3192
|
+
mutationObserver.disconnect();
|
|
3193
|
+
}
|
|
3194
|
+
if (resizeObserver) {
|
|
3195
|
+
resizeObserver.disconnect();
|
|
3196
|
+
}
|
|
3137
3197
|
};
|
|
3138
3198
|
}, [getPinnedStreamTop, maintainScrollPosition, ref, setNextScrollState]);
|
|
3139
3199
|
return {
|
|
@@ -3151,7 +3211,7 @@ function ConversationViewport({
|
|
|
3151
3211
|
children,
|
|
3152
3212
|
streamKey = null
|
|
3153
3213
|
}) {
|
|
3154
|
-
const scrollRef =
|
|
3214
|
+
const scrollRef = useRef8(null);
|
|
3155
3215
|
const { hasOverflow, isAtBottom, maintainScrollPosition, scrollToBottom, setPinnedStream } = useConversationScroll(scrollRef);
|
|
3156
3216
|
const isScrollButtonVisible = hasOverflow && !isAtBottom;
|
|
3157
3217
|
useScrollShadow(scrollRef);
|
|
@@ -3188,32 +3248,32 @@ function ConversationViewport({
|
|
|
3188
3248
|
|
|
3189
3249
|
// src/embed/genui-renderer.tsx
|
|
3190
3250
|
import { Suspense as Suspense2, lazy as lazy2 } from "react";
|
|
3251
|
+
|
|
3252
|
+
// src/embed/genui-renderer-loader.ts
|
|
3253
|
+
var componentRendererPromise;
|
|
3254
|
+
function loadGenUIRenderer() {
|
|
3255
|
+
componentRendererPromise ??= import("./component-renderer-PTMCOJHE.js").then(
|
|
3256
|
+
(module) => ({ default: module.ComponentRenderer })
|
|
3257
|
+
);
|
|
3258
|
+
return componentRendererPromise;
|
|
3259
|
+
}
|
|
3260
|
+
function preloadGenUIRenderer() {
|
|
3261
|
+
void loadGenUIRenderer().catch(() => {
|
|
3262
|
+
componentRendererPromise = void 0;
|
|
3263
|
+
});
|
|
3264
|
+
}
|
|
3265
|
+
|
|
3266
|
+
// src/embed/genui-renderer.tsx
|
|
3191
3267
|
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
3192
|
-
var LazyComponentRenderer = lazy2(
|
|
3193
|
-
() => import("./component-renderer-EOOT6ONY.js").then((module) => ({
|
|
3194
|
-
default: module.ComponentRenderer
|
|
3195
|
-
}))
|
|
3196
|
-
);
|
|
3268
|
+
var LazyComponentRenderer = lazy2(loadGenUIRenderer);
|
|
3197
3269
|
function GenUIRenderer(props) {
|
|
3198
|
-
return /* @__PURE__ */ jsx15(
|
|
3199
|
-
Suspense2,
|
|
3200
|
-
{
|
|
3201
|
-
fallback: /* @__PURE__ */ jsx15(
|
|
3202
|
-
ComponentSkeleton,
|
|
3203
|
-
{
|
|
3204
|
-
className: props.className,
|
|
3205
|
-
kind: props.component && typeof props.component === "object" && "kind" in props.component ? props.component.kind : void 0
|
|
3206
|
-
}
|
|
3207
|
-
),
|
|
3208
|
-
children: /* @__PURE__ */ jsx15(LazyComponentRenderer, { ...props })
|
|
3209
|
-
}
|
|
3210
|
-
);
|
|
3270
|
+
return /* @__PURE__ */ jsx15(Suspense2, { fallback: null, children: /* @__PURE__ */ jsx15(LazyComponentRenderer, { ...props }) });
|
|
3211
3271
|
}
|
|
3212
3272
|
|
|
3213
3273
|
// src/embed/message-actions.tsx
|
|
3214
3274
|
import { ArrowsRotateLeft, Check, Copy, ThumbsDown, ThumbsUp } from "@gravity-ui/icons";
|
|
3215
3275
|
import { Button as Button2, Popover, TextArea } from "@heroui/react";
|
|
3216
|
-
import { useCallback as useCallback6, useEffect as
|
|
3276
|
+
import { useCallback as useCallback6, useEffect as useEffect10, useRef as useRef9, useState as useState7 } from "react";
|
|
3217
3277
|
import { Fragment, jsx as jsx16, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
3218
3278
|
var COPY_RESET_DELAY = 2e3;
|
|
3219
3279
|
var FEEDBACK_COMMENT_MAX_LENGTH = 1e3;
|
|
@@ -3237,12 +3297,12 @@ function MessageActions({
|
|
|
3237
3297
|
const [feedbackComment, setFeedbackComment] = useState7("");
|
|
3238
3298
|
const [feedbackReasons, setFeedbackReasons] = useState7([]);
|
|
3239
3299
|
const [feedbackPortalContainer, setFeedbackPortalContainer] = useState7();
|
|
3240
|
-
const resetTimeoutRef =
|
|
3241
|
-
const feedbackOpenedAtRef =
|
|
3300
|
+
const resetTimeoutRef = useRef9(null);
|
|
3301
|
+
const feedbackOpenedAtRef = useRef9(0);
|
|
3242
3302
|
const feedbackTriggerRef = useCallback6((node) => {
|
|
3243
3303
|
setFeedbackPortalContainer(node?.closest(".ha-panel") ?? void 0);
|
|
3244
3304
|
}, []);
|
|
3245
|
-
|
|
3305
|
+
useEffect10(() => {
|
|
3246
3306
|
return () => {
|
|
3247
3307
|
if (resetTimeoutRef.current !== null) window.clearTimeout(resetTimeoutRef.current);
|
|
3248
3308
|
};
|
|
@@ -3504,6 +3564,13 @@ function shouldQueueAgentMessage({
|
|
|
3504
3564
|
}
|
|
3505
3565
|
|
|
3506
3566
|
// src/embed/message-queue-coordinator.ts
|
|
3567
|
+
var AGENT_SESSION_START_ERROR_MESSAGE = "Could not start the assistant session";
|
|
3568
|
+
var AgentSessionStartError = class extends Error {
|
|
3569
|
+
constructor(options) {
|
|
3570
|
+
super(AGENT_SESSION_START_ERROR_MESSAGE, options);
|
|
3571
|
+
this.name = "AgentSessionStartError";
|
|
3572
|
+
}
|
|
3573
|
+
};
|
|
3507
3574
|
function getAgentTransportModelId({
|
|
3508
3575
|
activeTurnModelId,
|
|
3509
3576
|
defaultModelId,
|
|
@@ -3536,6 +3603,9 @@ function getAgentMessageFailureAction({
|
|
|
3536
3603
|
if (sendAcknowledged || transportFailure === "stream-error") return "reconcile";
|
|
3537
3604
|
return "requeue";
|
|
3538
3605
|
}
|
|
3606
|
+
function shouldRequeueAgentMessage(error) {
|
|
3607
|
+
return !(error instanceof AgentSessionStartError);
|
|
3608
|
+
}
|
|
3539
3609
|
function shouldReconcileStalledAgentTurn({
|
|
3540
3610
|
isLocalPending,
|
|
3541
3611
|
isReconciling,
|
|
@@ -3574,19 +3644,19 @@ function handleMessageQueueComposerKeyDown(event, queue) {
|
|
|
3574
3644
|
|
|
3575
3645
|
// src/embed/message-queue-list.tsx
|
|
3576
3646
|
import { ArrowUp, CircleExclamation, Clock, Grip, Pencil, TrashBin } from "@gravity-ui/icons";
|
|
3577
|
-
import { useImperativeHandle, useLayoutEffect as useLayoutEffect3, useRef as
|
|
3647
|
+
import { useImperativeHandle, useLayoutEffect as useLayoutEffect3, useRef as useRef11 } from "react";
|
|
3578
3648
|
|
|
3579
3649
|
// src/embed/use-message-queue-reorder.ts
|
|
3580
|
-
import { useRef as
|
|
3650
|
+
import { useRef as useRef10, useState as useState8 } from "react";
|
|
3581
3651
|
function useMessageQueueReorder({
|
|
3582
3652
|
messages,
|
|
3583
3653
|
onReorder,
|
|
3584
3654
|
onReorderStateChange
|
|
3585
3655
|
}) {
|
|
3586
|
-
const dragStateRef =
|
|
3587
|
-
const dropTargetRef =
|
|
3588
|
-
const positionPickerMessageIdRef =
|
|
3589
|
-
const suppressedClickMessageIdRef =
|
|
3656
|
+
const dragStateRef = useRef10(null);
|
|
3657
|
+
const dropTargetRef = useRef10(null);
|
|
3658
|
+
const positionPickerMessageIdRef = useRef10(null);
|
|
3659
|
+
const suppressedClickMessageIdRef = useRef10(null);
|
|
3590
3660
|
const [announcement, setAnnouncement] = useState8("");
|
|
3591
3661
|
const [draggedMessageId, setDraggedMessageId] = useState8(null);
|
|
3592
3662
|
const [dropTarget, setDropTarget] = useState8(null);
|
|
@@ -3758,9 +3828,9 @@ function MessageQueueList({
|
|
|
3758
3828
|
onSendNow,
|
|
3759
3829
|
ref
|
|
3760
3830
|
}) {
|
|
3761
|
-
const focusedMessageIdRef =
|
|
3762
|
-
const listRef =
|
|
3763
|
-
const previousMessagesRef =
|
|
3831
|
+
const focusedMessageIdRef = useRef11(null);
|
|
3832
|
+
const listRef = useRef11(null);
|
|
3833
|
+
const previousMessagesRef = useRef11(messages);
|
|
3764
3834
|
const {
|
|
3765
3835
|
announcement,
|
|
3766
3836
|
closePositionPicker,
|
|
@@ -3925,7 +3995,7 @@ import { composeRenderProps as composeRenderProps2 } from "react-aria-components
|
|
|
3925
3995
|
// ../agent-ui/src/components/hover-card/hover-card.tsx
|
|
3926
3996
|
import { mergeRefs } from "@react-aria/utils";
|
|
3927
3997
|
import { useControlledState } from "@react-stately/utils";
|
|
3928
|
-
import { createContext, useCallback as useCallback7, useContext, useEffect as
|
|
3998
|
+
import { createContext, useCallback as useCallback7, useContext, useEffect as useEffect11, useMemo as useMemo2, useRef as useRef12, useState as useState9 } from "react";
|
|
3929
3999
|
import {
|
|
3930
4000
|
OverlayArrow as OverlayArrowPrimitive,
|
|
3931
4001
|
Popover as PopoverPrimitive,
|
|
@@ -3955,16 +4025,16 @@ var HoverCardRoot = ({
|
|
|
3955
4025
|
}) => {
|
|
3956
4026
|
const [isOpen, setOpen] = useControlledState(open, defaultOpen, onOpenChange);
|
|
3957
4027
|
const [portalContainer, setPortalContainer] = useState9();
|
|
3958
|
-
const triggerRef =
|
|
3959
|
-
const isPointerInsideRef =
|
|
3960
|
-
const openTimerRef =
|
|
3961
|
-
const closeTimerRef =
|
|
4028
|
+
const triggerRef = useRef12(null);
|
|
4029
|
+
const isPointerInsideRef = useRef12(false);
|
|
4030
|
+
const openTimerRef = useRef12(void 0);
|
|
4031
|
+
const closeTimerRef = useRef12(void 0);
|
|
3962
4032
|
const clearTimers = useCallback7(() => {
|
|
3963
4033
|
clearTimeout(openTimerRef.current);
|
|
3964
4034
|
clearTimeout(closeTimerRef.current);
|
|
3965
4035
|
}, []);
|
|
3966
|
-
|
|
3967
|
-
|
|
4036
|
+
useEffect11(() => clearTimers, [clearTimers]);
|
|
4037
|
+
useEffect11(() => {
|
|
3968
4038
|
if (!isOpen) return;
|
|
3969
4039
|
const onKeyDown = (event) => {
|
|
3970
4040
|
if (event.key === "Escape") {
|
|
@@ -4594,7 +4664,7 @@ function writeCachedProjectConfig(agentId, config) {
|
|
|
4594
4664
|
// src/embed/session-picker.tsx
|
|
4595
4665
|
import { ChevronDown as ChevronDown2, Ellipsis, Pencil as Pencil2, Plus as Plus2, TrashBin as TrashBin2 } from "@gravity-ui/icons";
|
|
4596
4666
|
import { Button as Button4, Dropdown, Input, Label as Label3, Modal, Popover as Popover2, TextField } from "@heroui/react";
|
|
4597
|
-
import { useCallback as useCallback8, useRef as
|
|
4667
|
+
import { useCallback as useCallback8, useRef as useRef13, useState as useState10 } from "react";
|
|
4598
4668
|
import { Fragment as Fragment3, jsx as jsx24, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
4599
4669
|
var RENAME_KEY = "rename";
|
|
4600
4670
|
var DELETE_KEY = "delete";
|
|
@@ -4619,9 +4689,9 @@ function SessionPicker({
|
|
|
4619
4689
|
const [mutationError, setMutationError] = useState10(null);
|
|
4620
4690
|
const [isPending, setIsPending] = useState10(false);
|
|
4621
4691
|
const [portalContainer, setPortalContainer] = useState10();
|
|
4622
|
-
const pointerOpenAt =
|
|
4623
|
-
const actionPointerOpenAt =
|
|
4624
|
-
const sidebarHistoryRef =
|
|
4692
|
+
const pointerOpenAt = useRef13(0);
|
|
4693
|
+
const actionPointerOpenAt = useRef13(0);
|
|
4694
|
+
const sidebarHistoryRef = useRef13(null);
|
|
4625
4695
|
useScrollShadow(sidebarHistoryRef);
|
|
4626
4696
|
const activeConversation = groups.flatMap((group) => group.items).find((conversation) => conversation.id === activeConversationId);
|
|
4627
4697
|
const activeTitle = activeConversation?.title ?? "New chat";
|
|
@@ -4983,6 +5053,39 @@ function SessionDialogError({ message }) {
|
|
|
4983
5053
|
return message ? /* @__PURE__ */ jsx24("p", { className: "ha-session-modal-error", role: "alert", children: message }) : null;
|
|
4984
5054
|
}
|
|
4985
5055
|
|
|
5056
|
+
// src/embed/startup-activity-status.tsx
|
|
5057
|
+
import { useEffect as useEffect12, useState as useState11 } from "react";
|
|
5058
|
+
import { jsx as jsx25 } from "react/jsx-runtime";
|
|
5059
|
+
var STARTUP_ACTIVITY_STATUSES = [
|
|
5060
|
+
"Thinking\u2026",
|
|
5061
|
+
"Analyzing request\u2026",
|
|
5062
|
+
"Preparing next steps\u2026"
|
|
5063
|
+
];
|
|
5064
|
+
var STARTUP_ACTIVITY_STATUS_INTERVAL_MS = 1600;
|
|
5065
|
+
function StartupActivityStatus() {
|
|
5066
|
+
const [statusIndex, setStatusIndex] = useState11(0);
|
|
5067
|
+
useEffect12(() => {
|
|
5068
|
+
const timers = STARTUP_ACTIVITY_STATUSES.slice(1).map(
|
|
5069
|
+
(_, index) => window.setTimeout(
|
|
5070
|
+
() => setStatusIndex(index + 1),
|
|
5071
|
+
STARTUP_ACTIVITY_STATUS_INTERVAL_MS * (index + 1)
|
|
5072
|
+
)
|
|
5073
|
+
);
|
|
5074
|
+
return () => {
|
|
5075
|
+
for (const timer of timers) {
|
|
5076
|
+
window.clearTimeout(timer);
|
|
5077
|
+
}
|
|
5078
|
+
};
|
|
5079
|
+
}, []);
|
|
5080
|
+
return /* @__PURE__ */ jsx25(
|
|
5081
|
+
ActivityStatus,
|
|
5082
|
+
{
|
|
5083
|
+
ariaLabel: "Working on your request\u2026",
|
|
5084
|
+
label: STARTUP_ACTIVITY_STATUSES[statusIndex] ?? STARTUP_ACTIVITY_STATUSES[0]
|
|
5085
|
+
}
|
|
5086
|
+
);
|
|
5087
|
+
}
|
|
5088
|
+
|
|
4986
5089
|
// src/embed/trigger-session.ts
|
|
4987
5090
|
var ACTIVE_RUN_STATUSES = /* @__PURE__ */ new Set(["pending", "streaming"]);
|
|
4988
5091
|
function restoreTriggerSession(stored, bootstrapStatus) {
|
|
@@ -5003,7 +5106,7 @@ function restoreTriggerSession(stored, bootstrapStatus) {
|
|
|
5003
5106
|
}
|
|
5004
5107
|
|
|
5005
5108
|
// src/embed/use-composer-draft.ts
|
|
5006
|
-
import { useCallback as useCallback9, useEffect as
|
|
5109
|
+
import { useCallback as useCallback9, useEffect as useEffect13, useRef as useRef14, useState as useState12 } from "react";
|
|
5007
5110
|
var AGENT_COMPOSER_DRAFT_SAVE_DEBOUNCE_MS = 300;
|
|
5008
5111
|
function useComposerDraft({
|
|
5009
5112
|
attachments,
|
|
@@ -5012,14 +5115,14 @@ function useComposerDraft({
|
|
|
5012
5115
|
setAttachments,
|
|
5013
5116
|
setInput
|
|
5014
5117
|
}) {
|
|
5015
|
-
const [restoredImageDraftKey, setRestoredImageDraftKey] =
|
|
5016
|
-
const [restoredPromptDraftKey, setRestoredPromptDraftKey] =
|
|
5017
|
-
const latestInputRef =
|
|
5018
|
-
const saveTimeoutRef =
|
|
5019
|
-
|
|
5118
|
+
const [restoredImageDraftKey, setRestoredImageDraftKey] = useState12(null);
|
|
5119
|
+
const [restoredPromptDraftKey, setRestoredPromptDraftKey] = useState12(null);
|
|
5120
|
+
const latestInputRef = useRef14(input);
|
|
5121
|
+
const saveTimeoutRef = useRef14(null);
|
|
5122
|
+
useEffect13(() => {
|
|
5020
5123
|
latestInputRef.current = input;
|
|
5021
5124
|
}, [input]);
|
|
5022
|
-
|
|
5125
|
+
useEffect13(() => {
|
|
5023
5126
|
let cancelled = false;
|
|
5024
5127
|
const savedPrompt = readAgentComposerPromptDraft(draftKey);
|
|
5025
5128
|
queueMicrotask(() => {
|
|
@@ -5038,7 +5141,7 @@ function useComposerDraft({
|
|
|
5038
5141
|
cancelled = true;
|
|
5039
5142
|
};
|
|
5040
5143
|
}, [draftKey, setAttachments, setInput]);
|
|
5041
|
-
|
|
5144
|
+
useEffect13(() => {
|
|
5042
5145
|
if (restoredPromptDraftKey !== draftKey) return;
|
|
5043
5146
|
const flush = () => saveAgentComposerPromptDraft(draftKey, input);
|
|
5044
5147
|
saveTimeoutRef.current = window.setTimeout(flush, AGENT_COMPOSER_DRAFT_SAVE_DEBOUNCE_MS);
|
|
@@ -5049,11 +5152,11 @@ function useComposerDraft({
|
|
|
5049
5152
|
window.removeEventListener("pagehide", flush);
|
|
5050
5153
|
};
|
|
5051
5154
|
}, [draftKey, input, restoredPromptDraftKey]);
|
|
5052
|
-
|
|
5155
|
+
useEffect13(() => {
|
|
5053
5156
|
if (restoredPromptDraftKey !== draftKey) return;
|
|
5054
5157
|
return () => saveAgentComposerPromptDraft(draftKey, latestInputRef.current);
|
|
5055
5158
|
}, [draftKey, restoredPromptDraftKey]);
|
|
5056
|
-
|
|
5159
|
+
useEffect13(() => {
|
|
5057
5160
|
if (restoredImageDraftKey !== draftKey) return;
|
|
5058
5161
|
void saveAgentComposerImageDraft(draftKey, attachments);
|
|
5059
5162
|
}, [attachments, draftKey, restoredImageDraftKey]);
|
|
@@ -5066,7 +5169,7 @@ function useComposerDraft({
|
|
|
5066
5169
|
}
|
|
5067
5170
|
|
|
5068
5171
|
// src/embed/use-persisted-model-selection.ts
|
|
5069
|
-
import { useCallback as useCallback10, useState as
|
|
5172
|
+
import { useCallback as useCallback10, useState as useState13 } from "react";
|
|
5070
5173
|
function agentModelPreferenceStorageKey(identityStorageKey) {
|
|
5071
5174
|
return `${identityStorageKey}:model`;
|
|
5072
5175
|
}
|
|
@@ -5094,7 +5197,7 @@ function storeModelPreference(identityStorageKey, modelId) {
|
|
|
5094
5197
|
}
|
|
5095
5198
|
}
|
|
5096
5199
|
function usePersistedModelSelection(identityStorageKey, configuredDefaultModelId) {
|
|
5097
|
-
const [preferredModelId, setPreferredModelId] =
|
|
5200
|
+
const [preferredModelId, setPreferredModelId] = useState13(
|
|
5098
5201
|
() => readStoredModelPreference(identityStorageKey)
|
|
5099
5202
|
);
|
|
5100
5203
|
const selectedModelId = preferredModelId ?? configuredDefaultModelId ?? DEFAULT_AGENT_PICKER_MODEL_ID;
|
|
@@ -5209,8 +5312,7 @@ async function transcribeVoiceRecording({
|
|
|
5209
5312
|
}
|
|
5210
5313
|
|
|
5211
5314
|
// src/embed/embed-runtime.tsx
|
|
5212
|
-
import { Fragment as Fragment4, jsx as
|
|
5213
|
-
var DEFAULT_TRIGGER_API_URL = "https://api.trigger.dev";
|
|
5315
|
+
import { Fragment as Fragment4, jsx as jsx26, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
5214
5316
|
var TRANSPORT_COMPLETION_WATCHDOG_MS = 3e4;
|
|
5215
5317
|
function createReconciliationDeferred() {
|
|
5216
5318
|
let resolve;
|
|
@@ -5253,14 +5355,14 @@ function EmbedRuntime({
|
|
|
5253
5355
|
() => new EmbedSessionManager(options.agentId, options.getAuthToken),
|
|
5254
5356
|
[options.getAuthToken, options.agentId]
|
|
5255
5357
|
);
|
|
5256
|
-
const [activeConversationId, setActiveConversationId] =
|
|
5257
|
-
const [runtimeRoutes, setRuntimeRoutes] =
|
|
5258
|
-
const runtimeRoutesRef =
|
|
5259
|
-
const activeConversationIdRef =
|
|
5260
|
-
const [error, setError] =
|
|
5261
|
-
const [history, setHistory] =
|
|
5262
|
-
const [conversationActivity, setConversationActivity] =
|
|
5263
|
-
const [messageQueues, setMessageQueues] =
|
|
5358
|
+
const [activeConversationId, setActiveConversationId] = useState14(null);
|
|
5359
|
+
const [runtimeRoutes, setRuntimeRoutes] = useState14({});
|
|
5360
|
+
const runtimeRoutesRef = useRef15(runtimeRoutes);
|
|
5361
|
+
const activeConversationIdRef = useRef15(activeConversationId);
|
|
5362
|
+
const [error, setError] = useState14(null);
|
|
5363
|
+
const [history, setHistory] = useState14([]);
|
|
5364
|
+
const [conversationActivity, setConversationActivity] = useState14(createConversationActivityState);
|
|
5365
|
+
const [messageQueues, setMessageQueues] = useState14({});
|
|
5264
5366
|
const runtime = activeConversationId ? runtimeRoutes[activeConversationId] ?? null : null;
|
|
5265
5367
|
useLayoutEffect4(() => {
|
|
5266
5368
|
runtimeRoutesRef.current = runtimeRoutes;
|
|
@@ -5303,7 +5405,7 @@ function EmbedRuntime({
|
|
|
5303
5405
|
},
|
|
5304
5406
|
[]
|
|
5305
5407
|
);
|
|
5306
|
-
const bootstrapCacheRef =
|
|
5408
|
+
const bootstrapCacheRef = useRef15(null);
|
|
5307
5409
|
const apiBaseUrl = options.apiBaseUrl;
|
|
5308
5410
|
const agentId = options.agentId;
|
|
5309
5411
|
const notifyReady = useEffectEvent(onReady);
|
|
@@ -5321,7 +5423,7 @@ function EmbedRuntime({
|
|
|
5321
5423
|
const reportEmbedLoaded = useEffectEvent((conversationId) => {
|
|
5322
5424
|
void reportEvent(options, tokenManager, conversationId, "embed_loaded");
|
|
5323
5425
|
});
|
|
5324
|
-
const appliedIdentityEpochRef =
|
|
5426
|
+
const appliedIdentityEpochRef = useRef15(identityEpoch);
|
|
5325
5427
|
useLayoutEffect4(() => {
|
|
5326
5428
|
if (appliedIdentityEpochRef.current === identityEpoch) return;
|
|
5327
5429
|
appliedIdentityEpochRef.current = identityEpoch;
|
|
@@ -5336,7 +5438,7 @@ function EmbedRuntime({
|
|
|
5336
5438
|
if (identityReset) tokenManager.reset();
|
|
5337
5439
|
else tokenManager.clear();
|
|
5338
5440
|
}, [identityEpoch, identityReset, tokenManager]);
|
|
5339
|
-
|
|
5441
|
+
useEffect14(() => {
|
|
5340
5442
|
let cancelled = false;
|
|
5341
5443
|
if (clientToolValidationError) {
|
|
5342
5444
|
setError(clientToolValidationError);
|
|
@@ -5482,12 +5584,12 @@ function EmbedRuntime({
|
|
|
5482
5584
|
),
|
|
5483
5585
|
[clientToolValidationError, options.permissionDefaultMode, options.tools]
|
|
5484
5586
|
);
|
|
5485
|
-
const preloadedConversationIds =
|
|
5587
|
+
const preloadedConversationIds = useRef15(/* @__PURE__ */ new Set());
|
|
5486
5588
|
const warmAgentSession = useEffectEvent((conversationId) => {
|
|
5487
5589
|
preloadedConversationIds.current.add(conversationId);
|
|
5488
5590
|
void preloadAgentSession(options, tokenManager, conversationId, preloadClientTools);
|
|
5489
5591
|
});
|
|
5490
|
-
|
|
5592
|
+
useEffect14(() => {
|
|
5491
5593
|
if (!warmSession && !open) return;
|
|
5492
5594
|
const conversationId = runtime?.conversationId;
|
|
5493
5595
|
if (!conversationId || preloadedConversationIds.current.has(conversationId)) return;
|
|
@@ -5598,8 +5700,8 @@ function EmbedRuntime({
|
|
|
5598
5700
|
);
|
|
5599
5701
|
}, [options.suggestedPrompts, runtimeRoutes]);
|
|
5600
5702
|
const runtimeConfig = activeConversationId ? configuredRuntimeRoutes[activeConversationId]?.config ?? null : null;
|
|
5601
|
-
const openedConversationRef =
|
|
5602
|
-
|
|
5703
|
+
const openedConversationRef = useRef15(null);
|
|
5704
|
+
useEffect14(() => {
|
|
5603
5705
|
if (!open || !runtime || openedConversationRef.current === runtime.conversationId) return;
|
|
5604
5706
|
openedConversationRef.current = runtime.conversationId;
|
|
5605
5707
|
void reportEvent(options, tokenManager, runtime.conversationId, "opened");
|
|
@@ -5609,7 +5711,7 @@ function EmbedRuntime({
|
|
|
5609
5711
|
const activeConversationTitle = history.find((conversation) => conversation.id === activeConversationId)?.title ?? "New chat";
|
|
5610
5712
|
const loadingMessage = bootstrapCacheRef.current ? "Loading chat\u2026" : "Loading assistant\u2026";
|
|
5611
5713
|
return /* @__PURE__ */ jsxs17(Fragment4, { children: [
|
|
5612
|
-
open && runtime?.config.presence ? /* @__PURE__ */
|
|
5714
|
+
open && runtime?.config.presence ? /* @__PURE__ */ jsx26(
|
|
5613
5715
|
AgentConversationPresence,
|
|
5614
5716
|
{
|
|
5615
5717
|
agentId,
|
|
@@ -5621,15 +5723,15 @@ function EmbedRuntime({
|
|
|
5621
5723
|
/* @__PURE__ */ jsxs17(
|
|
5622
5724
|
PanelShell,
|
|
5623
5725
|
{
|
|
5624
|
-
actionsSlot: /* @__PURE__ */
|
|
5726
|
+
actionsSlot: /* @__PURE__ */ jsx26(NewChatButton, { onPress: onNewConversation }),
|
|
5727
|
+
agentId: options.agentId,
|
|
5625
5728
|
defaultExpanded: options.panelExpanded,
|
|
5626
5729
|
expandable: options.panelExpandable,
|
|
5730
|
+
expandedTitle: activeConversationTitle,
|
|
5627
5731
|
modal: options.viewMode !== "sidebar",
|
|
5628
5732
|
name: runtimeConfig?.name ?? "Data assistant",
|
|
5629
5733
|
open,
|
|
5630
|
-
|
|
5631
|
-
expandedTitle: activeConversationTitle,
|
|
5632
|
-
expandedSidebarSlot: /* @__PURE__ */ jsx25(
|
|
5734
|
+
expandedSidebarSlot: /* @__PURE__ */ jsx26(
|
|
5633
5735
|
SessionPicker,
|
|
5634
5736
|
{
|
|
5635
5737
|
activeConversationId,
|
|
@@ -5643,7 +5745,7 @@ function EmbedRuntime({
|
|
|
5643
5745
|
onSelectConversation: selectConversation
|
|
5644
5746
|
}
|
|
5645
5747
|
),
|
|
5646
|
-
historySlot: /* @__PURE__ */
|
|
5748
|
+
historySlot: /* @__PURE__ */ jsx26(
|
|
5647
5749
|
SessionPicker,
|
|
5648
5750
|
{
|
|
5649
5751
|
activeConversationId,
|
|
@@ -5658,13 +5760,13 @@ function EmbedRuntime({
|
|
|
5658
5760
|
onClose,
|
|
5659
5761
|
onNewConversation,
|
|
5660
5762
|
children: [
|
|
5661
|
-
visibleError ? /* @__PURE__ */
|
|
5662
|
-
/* @__PURE__ */
|
|
5763
|
+
visibleError ? /* @__PURE__ */ jsx26("div", { className: "ha-loading", role: "alert", children: visibleError }) : !runtime || !runtimeConfig ? /* @__PURE__ */ jsx26("div", { className: "ha-loading", children: /* @__PURE__ */ jsx26(ShimmerText, { className: "ha-progress ha-progress-shimmer", children: loadingMessage }) }) : null,
|
|
5764
|
+
/* @__PURE__ */ jsx26(
|
|
5663
5765
|
ConversationRouteStack,
|
|
5664
5766
|
{
|
|
5665
5767
|
activeConversationId: visibleError ? null : activeConversationId,
|
|
5666
5768
|
routes: configuredRuntimeRoutes,
|
|
5667
|
-
children: (route, active) => /* @__PURE__ */
|
|
5769
|
+
children: (route, active) => /* @__PURE__ */ jsx26(CardVariantProvider, { variant: route.config.surfaceVariant, children: /* @__PURE__ */ jsx26(
|
|
5668
5770
|
ChatRuntime,
|
|
5669
5771
|
{
|
|
5670
5772
|
active,
|
|
@@ -5725,11 +5827,11 @@ function ChatRuntime({
|
|
|
5725
5827
|
const permissionStorageKey = agentPermissionModeStorageKey(storageKey, conversationId);
|
|
5726
5828
|
const attachmentPolicyKey = options.composerAttachmentAccept;
|
|
5727
5829
|
const attachmentPolicy = useMemo4(() => ({ key: attachmentPolicyKey }), [attachmentPolicyKey]);
|
|
5728
|
-
const [attachmentSelection, setAttachmentSelection] =
|
|
5830
|
+
const [attachmentSelection, setAttachmentSelection] = useState14(() => ({
|
|
5729
5831
|
files: [],
|
|
5730
5832
|
policy: attachmentPolicy
|
|
5731
5833
|
}));
|
|
5732
|
-
const [attachmentErrorSelection, setAttachmentErrorSelection] =
|
|
5834
|
+
const [attachmentErrorSelection, setAttachmentErrorSelection] = useState14(() => ({
|
|
5733
5835
|
error: null,
|
|
5734
5836
|
policy: attachmentPolicy
|
|
5735
5837
|
}));
|
|
@@ -5755,16 +5857,16 @@ function ChatRuntime({
|
|
|
5755
5857
|
(error) => setAttachmentErrorSelection({ error, policy: attachmentPolicy }),
|
|
5756
5858
|
[attachmentPolicy]
|
|
5757
5859
|
);
|
|
5758
|
-
const [activeTurnSelection, setActiveTurnSelectionState] =
|
|
5860
|
+
const [activeTurnSelection, setActiveTurnSelectionState] = useState14(() => {
|
|
5759
5861
|
const storedMode = shouldRestoreActivePermission ? readStoredAgentPermissionMode(activePermissionStorageKey) : void 0;
|
|
5760
5862
|
const restoredMode = storedMode ?? (shouldRestoreActivePermission ? "ask" : void 0);
|
|
5761
5863
|
return restoredMode ? { modelId: void 0, permissionMode: restoredMode } : void 0;
|
|
5762
5864
|
});
|
|
5763
|
-
const [activityTimings, setActivityTimings] =
|
|
5764
|
-
const [feedbackByMessage, setFeedbackByMessage] =
|
|
5765
|
-
const [isComposerExpanded, setIsComposerExpanded] =
|
|
5766
|
-
const [input, setInput] =
|
|
5767
|
-
const [permissionSelection, setPermissionSelection] =
|
|
5865
|
+
const [activityTimings, setActivityTimings] = useState14({});
|
|
5866
|
+
const [feedbackByMessage, setFeedbackByMessage] = useState14({});
|
|
5867
|
+
const [isComposerExpanded, setIsComposerExpanded] = useState14(false);
|
|
5868
|
+
const [input, setInput] = useState14("");
|
|
5869
|
+
const [permissionSelection, setPermissionSelection] = useState14(() => {
|
|
5768
5870
|
const storedMode = options.permissionShowPicker ? readStoredAgentPermissionMode(permissionStorageKey) : void 0;
|
|
5769
5871
|
const hasUnresolvedClientTool = options.permissionShowPicker && initialMessages.some(
|
|
5770
5872
|
(message) => message.role === "assistant" && message.parts.some((part) => {
|
|
@@ -5780,20 +5882,20 @@ function ChatRuntime({
|
|
|
5780
5882
|
selectedMode: storedMode ?? (hasUnresolvedClientTool ? "ask" : options.permissionDefaultMode)
|
|
5781
5883
|
};
|
|
5782
5884
|
});
|
|
5783
|
-
const [isQueueReordering, setIsQueueReordering] =
|
|
5784
|
-
const [isReconciling, setIsReconciling] =
|
|
5785
|
-
const [localPending, setLocalPending] =
|
|
5786
|
-
const [pendingClientToolCallIds, setPendingClientToolCallIds] =
|
|
5885
|
+
const [isQueueReordering, setIsQueueReordering] = useState14(false);
|
|
5886
|
+
const [isReconciling, setIsReconciling] = useState14(false);
|
|
5887
|
+
const [localPending, setLocalPending] = useState14(false);
|
|
5888
|
+
const [pendingClientToolCallIds, setPendingClientToolCallIds] = useState14(
|
|
5787
5889
|
() => /* @__PURE__ */ new Set()
|
|
5788
5890
|
);
|
|
5789
|
-
const [isResuming, setIsResuming] =
|
|
5790
|
-
const [progress, setProgress] =
|
|
5791
|
-
const [queueDrainVersion, setQueueDrainVersion] =
|
|
5792
|
-
const [reconcileEpoch, setReconcileEpoch] =
|
|
5793
|
-
const [recoveryError, setRecoveryError] =
|
|
5794
|
-
const [selection, setSelection] =
|
|
5795
|
-
const [toolDecisions, setToolDecisions] =
|
|
5796
|
-
|
|
5891
|
+
const [isResuming, setIsResuming] = useState14(true);
|
|
5892
|
+
const [progress, setProgress] = useState14(null);
|
|
5893
|
+
const [queueDrainVersion, setQueueDrainVersion] = useState14(0);
|
|
5894
|
+
const [reconcileEpoch, setReconcileEpoch] = useState14(0);
|
|
5895
|
+
const [recoveryError, setRecoveryError] = useState14(false);
|
|
5896
|
+
const [selection, setSelection] = useState14(null);
|
|
5897
|
+
const [toolDecisions, setToolDecisions] = useState14({});
|
|
5898
|
+
useEffect14(() => {
|
|
5797
5899
|
if (!shouldRestoreActivePermission) {
|
|
5798
5900
|
clearStoredAgentPermissionMode(activePermissionStorageKey);
|
|
5799
5901
|
}
|
|
@@ -5830,7 +5932,7 @@ function ChatRuntime({
|
|
|
5830
5932
|
() => serializeClientTools(effectiveClientTools),
|
|
5831
5933
|
[effectiveClientTools]
|
|
5832
5934
|
);
|
|
5833
|
-
const clientToolManifestRef =
|
|
5935
|
+
const clientToolManifestRef = useRef15(clientToolManifest);
|
|
5834
5936
|
useLayoutEffect4(() => {
|
|
5835
5937
|
clientToolManifestRef.current = clientToolManifest;
|
|
5836
5938
|
}, [clientToolManifest]);
|
|
@@ -5839,26 +5941,27 @@ function ChatRuntime({
|
|
|
5839
5941
|
() => new Map(effectiveClientTools.map((tool) => [tool.name, tool])),
|
|
5840
5942
|
[effectiveClientTools]
|
|
5841
5943
|
);
|
|
5842
|
-
const executedToolCallsRef =
|
|
5843
|
-
const activeMessageIdRef =
|
|
5844
|
-
const isBusyRef =
|
|
5845
|
-
const isQueueReorderingRef =
|
|
5846
|
-
const messageQueueRef =
|
|
5847
|
-
const
|
|
5848
|
-
const
|
|
5849
|
-
const
|
|
5850
|
-
const
|
|
5851
|
-
const
|
|
5852
|
-
const
|
|
5853
|
-
const
|
|
5854
|
-
const
|
|
5855
|
-
const
|
|
5856
|
-
const
|
|
5857
|
-
const
|
|
5858
|
-
const
|
|
5859
|
-
const
|
|
5860
|
-
const
|
|
5861
|
-
const
|
|
5944
|
+
const executedToolCallsRef = useRef15(/* @__PURE__ */ new Set());
|
|
5945
|
+
const activeMessageIdRef = useRef15(null);
|
|
5946
|
+
const isBusyRef = useRef15(true);
|
|
5947
|
+
const isQueueReorderingRef = useRef15(false);
|
|
5948
|
+
const messageQueueRef = useRef15(messageQueue);
|
|
5949
|
+
const pendingTurnAnchorRef = useRef15(null);
|
|
5950
|
+
const reconciliationDeferredRef = useRef15(null);
|
|
5951
|
+
const reconcileMessageIdRef = useRef15(void 0);
|
|
5952
|
+
const resumePromiseRef = useRef15(null);
|
|
5953
|
+
const manualStopRequestedRef = useRef15(false);
|
|
5954
|
+
const sendAcknowledgedRef = useRef15(false);
|
|
5955
|
+
const sendErrorRef = useRef15(null);
|
|
5956
|
+
const streamedMessageIdsRef = useRef15(/* @__PURE__ */ new Set());
|
|
5957
|
+
const timedMessageIdRef = useRef15(null);
|
|
5958
|
+
const transportFailureRef = useRef15(null);
|
|
5959
|
+
const turnStartedAtRef = useRef15(null);
|
|
5960
|
+
const needsReconciliationRef = useRef15(false);
|
|
5961
|
+
const clearChatErrorRef = useRef15(() => void 0);
|
|
5962
|
+
const fileInputRef = useRef15(null);
|
|
5963
|
+
const messageQueueListRef = useRef15(null);
|
|
5964
|
+
const textareaRef = useRef15(null);
|
|
5862
5965
|
const composerDraftKey = useMemo4(
|
|
5863
5966
|
() => agentComposerDraftStorageKey(storageKey, conversationId),
|
|
5864
5967
|
[conversationId, storageKey]
|
|
@@ -5897,13 +6000,13 @@ function ChatRuntime({
|
|
|
5897
6000
|
transcribe: transcribeDictation,
|
|
5898
6001
|
value: input
|
|
5899
6002
|
});
|
|
5900
|
-
|
|
6003
|
+
useEffect14(() => {
|
|
5901
6004
|
messageQueueRef.current = messageQueue;
|
|
5902
6005
|
}, [messageQueue]);
|
|
5903
|
-
|
|
6006
|
+
useEffect14(() => {
|
|
5904
6007
|
if (!options.composerDictation) cancelDictation();
|
|
5905
6008
|
}, [cancelDictation, options.composerDictation]);
|
|
5906
|
-
|
|
6009
|
+
useEffect14(() => {
|
|
5907
6010
|
if (!active) cancelDictation();
|
|
5908
6011
|
}, [active, cancelDictation]);
|
|
5909
6012
|
const composerModelId = options.composerModelPicker ? selectedModelId : options.composerDefaultModel;
|
|
@@ -5970,7 +6073,6 @@ function ChatRuntime({
|
|
|
5970
6073
|
}),
|
|
5971
6074
|
onEvent: onTransportEvent,
|
|
5972
6075
|
options,
|
|
5973
|
-
realtimeUrl: options.triggerApiUrl ?? config.realtime?.url ?? DEFAULT_TRIGGER_API_URL,
|
|
5974
6076
|
tokenManager
|
|
5975
6077
|
});
|
|
5976
6078
|
const chatState = useChat({
|
|
@@ -6040,7 +6142,7 @@ function ChatRuntime({
|
|
|
6040
6142
|
useLayoutEffect4(() => {
|
|
6041
6143
|
clearChatErrorRef.current = clearError;
|
|
6042
6144
|
}, [clearError]);
|
|
6043
|
-
|
|
6145
|
+
useEffect14(() => {
|
|
6044
6146
|
const resumePromise = resumePromiseRef.current ?? chatState.resumeStream();
|
|
6045
6147
|
resumePromiseRef.current = resumePromise;
|
|
6046
6148
|
void resumePromise.then(
|
|
@@ -6081,7 +6183,7 @@ function ChatRuntime({
|
|
|
6081
6183
|
recoveryError
|
|
6082
6184
|
});
|
|
6083
6185
|
const reportConversationStatusChange = useEffectEvent(onConversationStatusChange);
|
|
6084
|
-
|
|
6186
|
+
useEffect14(() => {
|
|
6085
6187
|
if (!localPending || !isRunning || isReconciling) return;
|
|
6086
6188
|
const timeoutId = window.setTimeout(() => {
|
|
6087
6189
|
if (shouldReconcileStalledAgentTurn({
|
|
@@ -6096,7 +6198,7 @@ function ChatRuntime({
|
|
|
6096
6198
|
}, TRANSPORT_COMPLETION_WATCHDOG_MS);
|
|
6097
6199
|
return () => window.clearTimeout(timeoutId);
|
|
6098
6200
|
}, [isReconciling, isRunning, localPending, scheduleReconciliation]);
|
|
6099
|
-
|
|
6201
|
+
useEffect14(() => {
|
|
6100
6202
|
if (!activeTurnSelection) return;
|
|
6101
6203
|
if (!isRunning && !hasPendingClientToolCalls && !localPending && !isReconciling && !isResuming && !isAutoContinuationPending) {
|
|
6102
6204
|
clearStoredAgentPermissionMode(activePermissionStorageKey);
|
|
@@ -6112,17 +6214,17 @@ function ChatRuntime({
|
|
|
6112
6214
|
isRunning,
|
|
6113
6215
|
localPending
|
|
6114
6216
|
]);
|
|
6115
|
-
|
|
6217
|
+
useEffect14(() => {
|
|
6116
6218
|
isBusyRef.current = isBusy;
|
|
6117
6219
|
}, [isBusy]);
|
|
6118
|
-
|
|
6220
|
+
useEffect14(() => {
|
|
6119
6221
|
reportConversationStatusChange(conversationId, {
|
|
6120
6222
|
busy: isConversationBusy,
|
|
6121
6223
|
failed: conversationFailed,
|
|
6122
6224
|
turnActive: hasActiveTurn
|
|
6123
6225
|
});
|
|
6124
6226
|
}, [conversationFailed, conversationId, hasActiveTurn, isConversationBusy]);
|
|
6125
|
-
|
|
6227
|
+
useEffect14(
|
|
6126
6228
|
() => () => {
|
|
6127
6229
|
reportConversationStatusChange(conversationId, {
|
|
6128
6230
|
busy: false,
|
|
@@ -6138,7 +6240,7 @@ function ChatRuntime({
|
|
|
6138
6240
|
const hasStreamingActivity = Boolean(
|
|
6139
6241
|
streamingAssistantMessage && collectActivity(streamingAssistantMessage, clientToolsByName, { isStreaming: true }).length > 0
|
|
6140
6242
|
);
|
|
6141
|
-
|
|
6243
|
+
useEffect14(() => {
|
|
6142
6244
|
if (hasActiveTurn && streamingAssistantMessageId) {
|
|
6143
6245
|
if (timedMessageIdRef.current === streamingAssistantMessageId) return;
|
|
6144
6246
|
const startedAt = turnStartedAtRef.current ?? Date.now();
|
|
@@ -6197,7 +6299,7 @@ function ChatRuntime({
|
|
|
6197
6299
|
},
|
|
6198
6300
|
[conversationId, options, setClientToolCallPending, submitToolOutput, tokenManager]
|
|
6199
6301
|
);
|
|
6200
|
-
|
|
6302
|
+
useEffect14(() => {
|
|
6201
6303
|
for (const message of chatState.messages) {
|
|
6202
6304
|
if (message.role !== "assistant") continue;
|
|
6203
6305
|
for (const part of message.parts) {
|
|
@@ -6231,7 +6333,7 @@ function ChatRuntime({
|
|
|
6231
6333
|
submitToolOutput,
|
|
6232
6334
|
toolDecisions
|
|
6233
6335
|
]);
|
|
6234
|
-
|
|
6336
|
+
useEffect14(() => {
|
|
6235
6337
|
if (reconcileEpoch === 0) return;
|
|
6236
6338
|
let cancelled = false;
|
|
6237
6339
|
void (async () => {
|
|
@@ -6328,7 +6430,7 @@ function ChatRuntime({
|
|
|
6328
6430
|
}
|
|
6329
6431
|
startDictation();
|
|
6330
6432
|
}, [cancelDictation, isDictating, isDictationTranscribing, startDictation, stopDictation]);
|
|
6331
|
-
|
|
6433
|
+
useEffect14(() => {
|
|
6332
6434
|
if (!active || !options.composerDictation || !isDictationSupported) return;
|
|
6333
6435
|
const handleDictationShortcut = (event) => {
|
|
6334
6436
|
if (!isDictationShortcut(event)) return;
|
|
@@ -6341,6 +6443,9 @@ function ChatRuntime({
|
|
|
6341
6443
|
const sendAgentMessage = useCallback11(
|
|
6342
6444
|
async (message) => {
|
|
6343
6445
|
const previousMessages = chatState.messages;
|
|
6446
|
+
const previousUserMessageId = previousMessages.findLast(
|
|
6447
|
+
(previousMessage) => previousMessage.role === "user"
|
|
6448
|
+
)?.id;
|
|
6344
6449
|
const messagePermissionMode = options.permissionShowPicker ? message.permissionMode ?? composerPermissionMode : options.permissionDefaultMode;
|
|
6345
6450
|
const messageClientToolManifest = serializeClientTools(
|
|
6346
6451
|
applyAgentPermissionMode(options.tools, messagePermissionMode)
|
|
@@ -6353,9 +6458,13 @@ function ChatRuntime({
|
|
|
6353
6458
|
timedMessageIdRef.current = null;
|
|
6354
6459
|
turnStartedAtRef.current = Date.now();
|
|
6355
6460
|
prepareTransportSend();
|
|
6461
|
+
pendingTurnAnchorRef.current = {
|
|
6462
|
+
messageId: message.id,
|
|
6463
|
+
previousUserMessageId: previousUserMessageId ?? null
|
|
6464
|
+
};
|
|
6356
6465
|
setLocalPending(true);
|
|
6357
6466
|
setRecoveryError(false);
|
|
6358
|
-
setProgress(
|
|
6467
|
+
setProgress(DEFAULT_ACTIVITY_STATUS);
|
|
6359
6468
|
onConversationStarted(titleFromPrompt(message.text, message.files));
|
|
6360
6469
|
try {
|
|
6361
6470
|
const pageContext = await getSafePageContext(options, message.selection);
|
|
@@ -6375,7 +6484,7 @@ function ChatRuntime({
|
|
|
6375
6484
|
pageContext,
|
|
6376
6485
|
webSearch: options.webSearch
|
|
6377
6486
|
};
|
|
6378
|
-
setProgress(
|
|
6487
|
+
setProgress(DEFAULT_ACTIVITY_STATUS);
|
|
6379
6488
|
await chatState.sendMessage(createAgentMessageSendInput(message, fileParts), {
|
|
6380
6489
|
metadata
|
|
6381
6490
|
});
|
|
@@ -6414,10 +6523,11 @@ function ChatRuntime({
|
|
|
6414
6523
|
const sendMessageNow = useCallback11(
|
|
6415
6524
|
(message, { resumeDrainAfter = true } = {}) => {
|
|
6416
6525
|
activeMessageIdRef.current = message.id;
|
|
6417
|
-
void sendAgentMessage(message).catch(() => {
|
|
6526
|
+
void sendAgentMessage(message).catch((sendError) => {
|
|
6418
6527
|
if (activeMessageIdRef.current === message.id) {
|
|
6419
6528
|
activeMessageIdRef.current = null;
|
|
6420
6529
|
}
|
|
6530
|
+
if (!shouldRequeueAgentMessage(sendError)) return;
|
|
6421
6531
|
setMessageQueue(
|
|
6422
6532
|
(current) => setBlockedAgentMessageId(enqueueAgentMessage(current, message, "prepend"), message.id)
|
|
6423
6533
|
);
|
|
@@ -6475,14 +6585,14 @@ function ChatRuntime({
|
|
|
6475
6585
|
);
|
|
6476
6586
|
const visibleSuggestedPrompts = config.suggestedPrompts ?? [];
|
|
6477
6587
|
const replayShellHandoff = useEffectEvent((prompt) => submitComposerMessage(prompt));
|
|
6478
|
-
|
|
6588
|
+
useEffect14(() => {
|
|
6479
6589
|
if (!active) return;
|
|
6480
6590
|
const handoff = takeAgentShellHandoff(options.agentId);
|
|
6481
6591
|
if (!handoff) return;
|
|
6482
6592
|
if (handoff.submitted) replayShellHandoff(handoff.prompt);
|
|
6483
6593
|
else setInput((current) => current || handoff.prompt);
|
|
6484
6594
|
}, [active, options.agentId]);
|
|
6485
|
-
|
|
6595
|
+
useEffect14(() => {
|
|
6486
6596
|
if (!active || !options.suggestedPromptShortcuts || chatState.messages.length > 0 || visibleSuggestedPrompts.length === 0) {
|
|
6487
6597
|
return;
|
|
6488
6598
|
}
|
|
@@ -6515,7 +6625,7 @@ function ChatRuntime({
|
|
|
6515
6625
|
isQueueReorderingRef.current = isReordering;
|
|
6516
6626
|
setIsQueueReordering(isReordering);
|
|
6517
6627
|
}, []);
|
|
6518
|
-
|
|
6628
|
+
useEffect14(() => {
|
|
6519
6629
|
const nextMessage = getNextDrainableAgentMessage({
|
|
6520
6630
|
activeMessageId: activeMessageIdRef.current,
|
|
6521
6631
|
isBusy,
|
|
@@ -6631,21 +6741,25 @@ function ChatRuntime({
|
|
|
6631
6741
|
return;
|
|
6632
6742
|
}
|
|
6633
6743
|
}
|
|
6634
|
-
|
|
6635
|
-
|
|
6636
|
-
|
|
6637
|
-
|
|
6638
|
-
|
|
6639
|
-
|
|
6640
|
-
|
|
6641
|
-
|
|
6642
|
-
|
|
6643
|
-
|
|
6644
|
-
setInput(prompt);
|
|
6645
|
-
setIsComposerExpanded(true);
|
|
6646
|
-
requestAnimationFrame(() => textareaRef.current?.focus());
|
|
6744
|
+
routeComponentPromptAction(action, {
|
|
6745
|
+
fillComposer: (prompt) => {
|
|
6746
|
+
cancelDictation();
|
|
6747
|
+
setInput(prompt);
|
|
6748
|
+
setIsComposerExpanded(true);
|
|
6749
|
+
requestAnimationFrame(() => textareaRef.current?.focus());
|
|
6750
|
+
},
|
|
6751
|
+
setSelection,
|
|
6752
|
+
submitPrompt: submitComposerMessage
|
|
6753
|
+
});
|
|
6647
6754
|
},
|
|
6648
|
-
[
|
|
6755
|
+
[
|
|
6756
|
+
cancelDictation,
|
|
6757
|
+
clientToolsByName,
|
|
6758
|
+
conversationId,
|
|
6759
|
+
options,
|
|
6760
|
+
submitComposerMessage,
|
|
6761
|
+
tokenManager
|
|
6762
|
+
]
|
|
6649
6763
|
);
|
|
6650
6764
|
const copyMessage = useCallback11(
|
|
6651
6765
|
(message) => {
|
|
@@ -6712,6 +6826,7 @@ function ChatRuntime({
|
|
|
6712
6826
|
permissionMode: composerPermissionMode
|
|
6713
6827
|
});
|
|
6714
6828
|
prepareTransportSend();
|
|
6829
|
+
pendingTurnAnchorRef.current = null;
|
|
6715
6830
|
setLocalPending(true);
|
|
6716
6831
|
setRecoveryError(false);
|
|
6717
6832
|
void reportEvent(options, tokenManager, conversationId, "retry");
|
|
@@ -6744,7 +6859,12 @@ function ChatRuntime({
|
|
|
6744
6859
|
(message) => message.role === "assistant"
|
|
6745
6860
|
)?.id;
|
|
6746
6861
|
const lastUserMessageId = chatState.messages.findLast((message) => message.role === "user")?.id;
|
|
6747
|
-
const activeStreamKey
|
|
6862
|
+
const { activeStreamKey, activeTurnMessageId } = resolveConversationTurnAnchor({
|
|
6863
|
+
conversationId,
|
|
6864
|
+
isActive: localPending || isRunning,
|
|
6865
|
+
lastUserMessageId,
|
|
6866
|
+
pendingTurn: pendingTurnAnchorRef.current
|
|
6867
|
+
});
|
|
6748
6868
|
const { showHome, standaloneStatus } = getConversationPresentation({
|
|
6749
6869
|
hasError: Boolean(chatState.error || recoveryError),
|
|
6750
6870
|
hasStreamingActivity,
|
|
@@ -6760,13 +6880,13 @@ function ChatRuntime({
|
|
|
6760
6880
|
return /* @__PURE__ */ jsxs17(Fragment4, { children: [
|
|
6761
6881
|
/* @__PURE__ */ jsxs17(ConversationViewport, { streamKey: activeStreamKey, children: [
|
|
6762
6882
|
showHome ? /* @__PURE__ */ jsxs17("div", { className: "ha-empty", children: [
|
|
6763
|
-
/* @__PURE__ */
|
|
6764
|
-
/* @__PURE__ */
|
|
6765
|
-
] }) : chatState.messages.map((message) => /* @__PURE__ */
|
|
6883
|
+
/* @__PURE__ */ jsx26("h2", { children: options.greeting }),
|
|
6884
|
+
/* @__PURE__ */ jsx26("p", { children: "Live answers with charts, metrics, and tables." })
|
|
6885
|
+
] }) : chatState.messages.map((message) => /* @__PURE__ */ jsx26(
|
|
6766
6886
|
Message,
|
|
6767
6887
|
{
|
|
6768
|
-
activityTiming: activityTimings[message.id],
|
|
6769
6888
|
actions: options.messageActions,
|
|
6889
|
+
activityTiming: activityTimings[message.id],
|
|
6770
6890
|
canRetry: message.id === lastAssistantMessageId && !isBusy,
|
|
6771
6891
|
clientTools: clientToolsByName,
|
|
6772
6892
|
exportFormats: options.componentExportFormats,
|
|
@@ -6778,6 +6898,7 @@ function ChatRuntime({
|
|
|
6778
6898
|
message,
|
|
6779
6899
|
progress: message.id === streamingAssistantMessageId ? progress : null,
|
|
6780
6900
|
toolDecisions,
|
|
6901
|
+
turnAnchor: message.id === activeTurnMessageId && activeStreamKey !== null ? "active" : message.id === lastUserMessageId ? "latest" : null,
|
|
6781
6902
|
onAction: handleComponentAction,
|
|
6782
6903
|
onClientToolDecision: decideClientTool,
|
|
6783
6904
|
onCopy: copyMessage,
|
|
@@ -6787,14 +6908,14 @@ function ChatRuntime({
|
|
|
6787
6908
|
},
|
|
6788
6909
|
message.id
|
|
6789
6910
|
)),
|
|
6790
|
-
standaloneStatus ? /* @__PURE__ */
|
|
6911
|
+
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,
|
|
6791
6912
|
chatState.error || recoveryError ? /* @__PURE__ */ jsxs17("div", { className: "ha-error", role: "alert", children: [
|
|
6792
|
-
/* @__PURE__ */
|
|
6793
|
-
/* @__PURE__ */
|
|
6913
|
+
/* @__PURE__ */ jsx26("span", { children: "The request could not be completed." }),
|
|
6914
|
+
/* @__PURE__ */ jsx26("button", { type: "button", onClick: retryLastResponse, children: "Retry" })
|
|
6794
6915
|
] }) : null
|
|
6795
6916
|
] }),
|
|
6796
6917
|
/* @__PURE__ */ jsxs17("form", { className: "ha-composer-wrap", onSubmit: submit, children: [
|
|
6797
|
-
showHome && visibleSuggestedPrompts.length > 0 ? /* @__PURE__ */
|
|
6918
|
+
showHome && visibleSuggestedPrompts.length > 0 ? /* @__PURE__ */ jsx26("div", { "aria-label": "Suggested prompts", className: "ha-suggestions", role: "group", children: visibleSuggestedPrompts.map((prompt, index) => /* @__PURE__ */ jsxs17(
|
|
6798
6919
|
"button",
|
|
6799
6920
|
{
|
|
6800
6921
|
className: "ha-suggestion",
|
|
@@ -6802,17 +6923,17 @@ function ChatRuntime({
|
|
|
6802
6923
|
"aria-keyshortcuts": options.suggestedPromptShortcuts ? `Control+${index + 1}` : void 0,
|
|
6803
6924
|
onClick: () => submitComposerMessage(prompt),
|
|
6804
6925
|
children: [
|
|
6805
|
-
/* @__PURE__ */
|
|
6926
|
+
/* @__PURE__ */ jsx26("span", { children: prompt }),
|
|
6806
6927
|
options.suggestedPromptShortcuts ? /* @__PURE__ */ jsxs17("span", { "aria-hidden": "true", className: "ha-suggestion-shortcut", children: [
|
|
6807
|
-
/* @__PURE__ */
|
|
6808
|
-
/* @__PURE__ */
|
|
6809
|
-
] }) : /* @__PURE__ */
|
|
6928
|
+
/* @__PURE__ */ jsx26("kbd", { children: "Ctrl" }),
|
|
6929
|
+
/* @__PURE__ */ jsx26("kbd", { children: index + 1 })
|
|
6930
|
+
] }) : /* @__PURE__ */ jsx26(ArrowUpRight, { "aria-hidden": "true" })
|
|
6810
6931
|
]
|
|
6811
6932
|
},
|
|
6812
6933
|
prompt
|
|
6813
6934
|
)) }) : null,
|
|
6814
|
-
selection ? /* @__PURE__ */
|
|
6815
|
-
/* @__PURE__ */
|
|
6935
|
+
selection ? /* @__PURE__ */ jsx26(ComposerContext, { title: selection.componentTitle, onRemove: () => setSelection(null) }) : null,
|
|
6936
|
+
/* @__PURE__ */ jsx26(
|
|
6816
6937
|
MessageQueueList,
|
|
6817
6938
|
{
|
|
6818
6939
|
ref: messageQueueListRef,
|
|
@@ -6836,7 +6957,7 @@ function ChatRuntime({
|
|
|
6836
6957
|
disabled: options.composerAttachmentContentTypes.length === 0,
|
|
6837
6958
|
onFilesSelected: addComposerAttachments,
|
|
6838
6959
|
children: [
|
|
6839
|
-
options.composerAttachmentContentTypes.length > 0 ? /* @__PURE__ */
|
|
6960
|
+
options.composerAttachmentContentTypes.length > 0 ? /* @__PURE__ */ jsx26(
|
|
6840
6961
|
"input",
|
|
6841
6962
|
{
|
|
6842
6963
|
ref: fileInputRef,
|
|
@@ -6852,14 +6973,14 @@ function ChatRuntime({
|
|
|
6852
6973
|
}
|
|
6853
6974
|
}
|
|
6854
6975
|
) : null,
|
|
6855
|
-
attachments.length > 0 ? /* @__PURE__ */
|
|
6976
|
+
attachments.length > 0 ? /* @__PURE__ */ jsx26(
|
|
6856
6977
|
ScrollShadow,
|
|
6857
6978
|
{
|
|
6858
6979
|
"aria-label": "Selected attachments",
|
|
6859
6980
|
className: "ha-attachments",
|
|
6860
6981
|
offset: 1,
|
|
6861
6982
|
size: 24,
|
|
6862
|
-
children: attachments.map((file) => /* @__PURE__ */
|
|
6983
|
+
children: attachments.map((file) => /* @__PURE__ */ jsx26(
|
|
6863
6984
|
ComposerAttachment,
|
|
6864
6985
|
{
|
|
6865
6986
|
file,
|
|
@@ -6872,17 +6993,17 @@ function ChatRuntime({
|
|
|
6872
6993
|
))
|
|
6873
6994
|
}
|
|
6874
6995
|
) : null,
|
|
6875
|
-
options.composerAttachmentContentTypes.length > 0 ? /* @__PURE__ */
|
|
6996
|
+
options.composerAttachmentContentTypes.length > 0 ? /* @__PURE__ */ jsx26(
|
|
6876
6997
|
"button",
|
|
6877
6998
|
{
|
|
6878
6999
|
"aria-label": "Attach files",
|
|
6879
7000
|
className: "ha-attach",
|
|
6880
7001
|
type: "button",
|
|
6881
7002
|
onClick: () => fileInputRef.current?.click(),
|
|
6882
|
-
children: /* @__PURE__ */
|
|
7003
|
+
children: /* @__PURE__ */ jsx26(Plus3, { "aria-hidden": "true" })
|
|
6883
7004
|
}
|
|
6884
7005
|
) : null,
|
|
6885
|
-
/* @__PURE__ */
|
|
7006
|
+
/* @__PURE__ */ jsx26(
|
|
6886
7007
|
"textarea",
|
|
6887
7008
|
{
|
|
6888
7009
|
ref: textareaRef,
|
|
@@ -6909,8 +7030,8 @@ function ChatRuntime({
|
|
|
6909
7030
|
}
|
|
6910
7031
|
}
|
|
6911
7032
|
),
|
|
6912
|
-
isDictating ? /* @__PURE__ */
|
|
6913
|
-
/* @__PURE__ */
|
|
7033
|
+
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: [
|
|
7034
|
+
/* @__PURE__ */ jsx26(
|
|
6914
7035
|
VoiceLiveWaveform,
|
|
6915
7036
|
{
|
|
6916
7037
|
active: isDictationRecording,
|
|
@@ -6920,7 +7041,7 @@ function ChatRuntime({
|
|
|
6920
7041
|
stream: dictationStream
|
|
6921
7042
|
}
|
|
6922
7043
|
),
|
|
6923
|
-
/* @__PURE__ */
|
|
7044
|
+
/* @__PURE__ */ jsx26(
|
|
6924
7045
|
"time",
|
|
6925
7046
|
{
|
|
6926
7047
|
"aria-label": `Recording duration ${formatVoiceDuration(dictationElapsedSeconds)}`,
|
|
@@ -6930,7 +7051,7 @@ function ChatRuntime({
|
|
|
6930
7051
|
}
|
|
6931
7052
|
)
|
|
6932
7053
|
] }) }) : null,
|
|
6933
|
-
options.permissionShowPicker && options.tools.length > 0 && !isDictating ? /* @__PURE__ */
|
|
7054
|
+
options.permissionShowPicker && options.tools.length > 0 && !isDictating ? /* @__PURE__ */ jsx26(
|
|
6934
7055
|
PermissionPicker,
|
|
6935
7056
|
{
|
|
6936
7057
|
"aria-label": "Tool permissions",
|
|
@@ -6940,7 +7061,7 @@ function ChatRuntime({
|
|
|
6940
7061
|
onChange: setSelectedPermissionMode
|
|
6941
7062
|
}
|
|
6942
7063
|
) : null,
|
|
6943
|
-
options.composerModelPicker && !isDictating ? /* @__PURE__ */
|
|
7064
|
+
options.composerModelPicker && !isDictating ? /* @__PURE__ */ jsx26(
|
|
6944
7065
|
ModelPicker,
|
|
6945
7066
|
{
|
|
6946
7067
|
"aria-label": "AI model",
|
|
@@ -6964,8 +7085,8 @@ function ChatRuntime({
|
|
|
6964
7085
|
type: "button",
|
|
6965
7086
|
onClick: toggleDictation,
|
|
6966
7087
|
children: [
|
|
6967
|
-
isDictationTranscribing ? /* @__PURE__ */
|
|
6968
|
-
/* @__PURE__ */
|
|
7088
|
+
isDictationTranscribing ? /* @__PURE__ */ jsx26(Xmark3, { "aria-hidden": "true" }) : isDictating ? /* @__PURE__ */ jsx26(StopFill, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx26(Microphone, { "aria-hidden": "true" }),
|
|
7089
|
+
/* @__PURE__ */ jsx26(
|
|
6969
7090
|
ComposerControlTooltip,
|
|
6970
7091
|
{
|
|
6971
7092
|
shortcut: isDictationSupported ? DICTATION_SHORTCUT_LABEL : void 0,
|
|
@@ -6975,7 +7096,7 @@ function ChatRuntime({
|
|
|
6975
7096
|
]
|
|
6976
7097
|
}
|
|
6977
7098
|
) : null,
|
|
6978
|
-
attachmentError || options.composerDictation && dictationError ? /* @__PURE__ */
|
|
7099
|
+
attachmentError || options.composerDictation && dictationError ? /* @__PURE__ */ jsx26("span", { className: "ha-dictation-error", role: "alert", children: attachmentError ?? dictationError }) : null,
|
|
6979
7100
|
isRunning && !hasComposerDraft ? /* @__PURE__ */ jsxs17(
|
|
6980
7101
|
"button",
|
|
6981
7102
|
{
|
|
@@ -6987,8 +7108,8 @@ function ChatRuntime({
|
|
|
6987
7108
|
type: "button",
|
|
6988
7109
|
onClick: stopGeneration,
|
|
6989
7110
|
children: [
|
|
6990
|
-
/* @__PURE__ */
|
|
6991
|
-
/* @__PURE__ */
|
|
7111
|
+
/* @__PURE__ */ jsx26(StopFill, { "aria-hidden": "true" }),
|
|
7112
|
+
/* @__PURE__ */ jsx26(ComposerControlTooltip, { shortcut: COMPOSER_ACTION_SHORTCUT_LABEL, children: sendButtonLabel })
|
|
6992
7113
|
]
|
|
6993
7114
|
}
|
|
6994
7115
|
) : /* @__PURE__ */ jsxs17(
|
|
@@ -7002,16 +7123,16 @@ function ChatRuntime({
|
|
|
7002
7123
|
disabled: !hasComposerDraft || isDictating,
|
|
7003
7124
|
type: "submit",
|
|
7004
7125
|
children: [
|
|
7005
|
-
/* @__PURE__ */
|
|
7006
|
-
/* @__PURE__ */
|
|
7126
|
+
/* @__PURE__ */ jsx26(ArrowUp2, { "aria-hidden": "true" }),
|
|
7127
|
+
/* @__PURE__ */ jsx26(ComposerControlTooltip, { shortcut: COMPOSER_ACTION_SHORTCUT_LABEL, children: sendButtonLabel })
|
|
7007
7128
|
]
|
|
7008
7129
|
}
|
|
7009
7130
|
)
|
|
7010
7131
|
]
|
|
7011
7132
|
}
|
|
7012
7133
|
),
|
|
7013
|
-
options.composerDisclaimer ? /* @__PURE__ */
|
|
7014
|
-
/* @__PURE__ */
|
|
7134
|
+
options.composerDisclaimer ? /* @__PURE__ */ jsx26("p", { className: "ha-footnote", children: renderInlineMarkdown(options.composerDisclaimer) }) : null,
|
|
7135
|
+
/* @__PURE__ */ jsx26(PoweredByHero, {})
|
|
7015
7136
|
] })
|
|
7016
7137
|
] });
|
|
7017
7138
|
}
|
|
@@ -7034,23 +7155,25 @@ function Message({
|
|
|
7034
7155
|
onRetry,
|
|
7035
7156
|
onSelect,
|
|
7036
7157
|
progress,
|
|
7037
|
-
toolDecisions
|
|
7158
|
+
toolDecisions,
|
|
7159
|
+
turnAnchor
|
|
7038
7160
|
}) {
|
|
7039
7161
|
const activity = collectActivity(message, clientTools, { isStreaming });
|
|
7040
7162
|
const sources = collectMessageSources(message.parts);
|
|
7163
|
+
const isBuildingComponent = message.parts.some(isStreamingComponentBuild);
|
|
7164
|
+
useEffect14(() => {
|
|
7165
|
+
if (isBuildingComponent) preloadGenUIRenderer();
|
|
7166
|
+
}, [isBuildingComponent]);
|
|
7041
7167
|
const activeTextPartIndex = isStreaming ? message.parts.findLastIndex((part) => part.type === "text") : -1;
|
|
7042
7168
|
const userAttachments = message.role === "user" ? message.parts.flatMap(
|
|
7043
|
-
(part, index) => part.type === "file" ? [/* @__PURE__ */
|
|
7169
|
+
(part, index) => part.type === "file" ? [/* @__PURE__ */ jsx26(MessageAttachment, { file: part }, `${message.id}-attachment-${index}`)] : []
|
|
7044
7170
|
) : [];
|
|
7045
|
-
const lastComponentPartIndex = message.parts.findLastIndex(
|
|
7046
|
-
(part) => part.type === "data-component"
|
|
7047
|
-
);
|
|
7048
7171
|
const content = message.parts.reduce((items, part, index) => {
|
|
7049
7172
|
if (part.type === "text") {
|
|
7050
7173
|
if (!part.text.trim()) return items;
|
|
7051
7174
|
return [
|
|
7052
7175
|
...items,
|
|
7053
|
-
message.role === "assistant" ? /* @__PURE__ */
|
|
7176
|
+
message.role === "assistant" ? /* @__PURE__ */ jsx26(
|
|
7054
7177
|
ConversationMarkdown,
|
|
7055
7178
|
{
|
|
7056
7179
|
animated: markdownAnimation,
|
|
@@ -7060,17 +7183,17 @@ function Message({
|
|
|
7060
7183
|
children: part.text
|
|
7061
7184
|
},
|
|
7062
7185
|
`${message.id}-text-${index}`
|
|
7063
|
-
) : /* @__PURE__ */
|
|
7186
|
+
) : /* @__PURE__ */ jsx26("p", { className: "ha-message-text", children: part.text }, `${message.id}-text-${index}`)
|
|
7064
7187
|
];
|
|
7065
7188
|
}
|
|
7066
7189
|
if (part.type === "file") {
|
|
7067
7190
|
if (message.role === "user") return items;
|
|
7068
|
-
return [...items, /* @__PURE__ */
|
|
7191
|
+
return [...items, /* @__PURE__ */ jsx26(MessageAttachment, { file: part }, `${message.id}-file-${index}`)];
|
|
7069
7192
|
}
|
|
7070
7193
|
if (part.type === "data-component") {
|
|
7071
7194
|
return [
|
|
7072
7195
|
...items,
|
|
7073
|
-
/* @__PURE__ */
|
|
7196
|
+
/* @__PURE__ */ jsx26(
|
|
7074
7197
|
GenUIRenderer,
|
|
7075
7198
|
{
|
|
7076
7199
|
component: part.data,
|
|
@@ -7082,20 +7205,7 @@ function Message({
|
|
|
7082
7205
|
)
|
|
7083
7206
|
];
|
|
7084
7207
|
}
|
|
7085
|
-
|
|
7086
|
-
if (componentPreview2 && index > lastComponentPartIndex) {
|
|
7087
|
-
return [
|
|
7088
|
-
...items,
|
|
7089
|
-
/* @__PURE__ */ jsx25(
|
|
7090
|
-
ComponentSkeleton,
|
|
7091
|
-
{
|
|
7092
|
-
kind: componentPreview2.kind,
|
|
7093
|
-
title: componentPreview2.title
|
|
7094
|
-
},
|
|
7095
|
-
componentPreview2.toolCallId
|
|
7096
|
-
)
|
|
7097
|
-
];
|
|
7098
|
-
}
|
|
7208
|
+
if (isStreamingComponentBuild(part)) return items;
|
|
7099
7209
|
const clientToolName = clientToolPartName(part);
|
|
7100
7210
|
const clientTool = clientToolName ? clientTools.get(clientToolName) : void 0;
|
|
7101
7211
|
if (clientToolName && clientTool?.needsApproval) {
|
|
@@ -7103,7 +7213,7 @@ function Message({
|
|
|
7103
7213
|
if (toolPart.state !== "input-available" || toolDecisions[toolPart.toolCallId]) return items;
|
|
7104
7214
|
return [
|
|
7105
7215
|
...items,
|
|
7106
|
-
/* @__PURE__ */
|
|
7216
|
+
/* @__PURE__ */ jsx26(
|
|
7107
7217
|
ClientToolCard,
|
|
7108
7218
|
{
|
|
7109
7219
|
decision: toolDecisions[toolPart.toolCallId],
|
|
@@ -7125,22 +7235,31 @@ function Message({
|
|
|
7125
7235
|
return null;
|
|
7126
7236
|
}
|
|
7127
7237
|
if (message.role === "user") {
|
|
7128
|
-
return /* @__PURE__ */ jsxs17(
|
|
7129
|
-
|
|
7130
|
-
|
|
7131
|
-
|
|
7238
|
+
return /* @__PURE__ */ jsxs17(
|
|
7239
|
+
"div",
|
|
7240
|
+
{
|
|
7241
|
+
className: "ha-message",
|
|
7242
|
+
"data-role": "user",
|
|
7243
|
+
"data-stream-anchor": turnAnchor === "active" ? true : void 0,
|
|
7244
|
+
"data-turn-anchor": turnAnchor ? true : void 0,
|
|
7245
|
+
children: [
|
|
7246
|
+
userAttachments.length > 0 ? /* @__PURE__ */ jsx26("div", { "aria-label": "Message attachments", className: "ha-message-attachments", children: userAttachments }) : null,
|
|
7247
|
+
content.length > 0 ? /* @__PURE__ */ jsx26("div", { className: "ha-bubble", children: /* @__PURE__ */ jsx26("div", { className: "ha-message-content", children: content }) }) : null
|
|
7248
|
+
]
|
|
7249
|
+
}
|
|
7250
|
+
);
|
|
7132
7251
|
}
|
|
7133
7252
|
const hasCopyableText = message.parts.some(
|
|
7134
7253
|
(part) => part.type === "text" && part.text.trim().length > 0
|
|
7135
7254
|
);
|
|
7136
|
-
return /* @__PURE__ */
|
|
7255
|
+
return /* @__PURE__ */ jsx26(
|
|
7137
7256
|
"div",
|
|
7138
7257
|
{
|
|
7139
7258
|
className: "ha-message",
|
|
7140
7259
|
"data-role": "assistant",
|
|
7141
7260
|
"data-stream-anchor": isStreaming ? true : void 0,
|
|
7142
7261
|
children: /* @__PURE__ */ jsxs17("div", { className: "ha-message-body", children: [
|
|
7143
|
-
activity.length > 0 ? /* @__PURE__ */
|
|
7262
|
+
activity.length > 0 ? /* @__PURE__ */ jsx26(
|
|
7144
7263
|
ActivityTrail,
|
|
7145
7264
|
{
|
|
7146
7265
|
completedAt: activityTiming?.completedAt,
|
|
@@ -7150,9 +7269,9 @@ function Message({
|
|
|
7150
7269
|
startedAt: activityTiming?.startedAt
|
|
7151
7270
|
}
|
|
7152
7271
|
) : null,
|
|
7153
|
-
content.length > 0 ? /* @__PURE__ */
|
|
7154
|
-
/* @__PURE__ */
|
|
7155
|
-
!isStreaming && content.length > 0 && actions.length > 0 ? /* @__PURE__ */
|
|
7272
|
+
content.length > 0 ? /* @__PURE__ */ jsx26("div", { className: "ha-message-content", children: content }) : null,
|
|
7273
|
+
/* @__PURE__ */ jsx26(MessageSources, { sources: visibleSources }),
|
|
7274
|
+
!isStreaming && content.length > 0 && actions.length > 0 ? /* @__PURE__ */ jsx26(
|
|
7156
7275
|
MessageActions,
|
|
7157
7276
|
{
|
|
7158
7277
|
actions,
|
|
@@ -7174,11 +7293,11 @@ function ClientToolCard({
|
|
|
7174
7293
|
}) {
|
|
7175
7294
|
if (part.state !== "input-available" || decision) return null;
|
|
7176
7295
|
const Icon = tool.icon;
|
|
7177
|
-
return /* @__PURE__ */
|
|
7296
|
+
return /* @__PURE__ */ jsx26(
|
|
7178
7297
|
ApprovalCard,
|
|
7179
7298
|
{
|
|
7180
7299
|
"data-tool-status": "approval-requested",
|
|
7181
|
-
icon: Icon ? /* @__PURE__ */
|
|
7300
|
+
icon: Icon ? /* @__PURE__ */ jsx26(Icon, { color: tool.iconColor, size: 16 }) : void 0,
|
|
7182
7301
|
input: part.input,
|
|
7183
7302
|
title: tool.displayName ?? tool.name,
|
|
7184
7303
|
onApprove: () => onDecision(true),
|
|
@@ -7193,7 +7312,6 @@ function useAgentTransport({
|
|
|
7193
7312
|
modelId,
|
|
7194
7313
|
onEvent,
|
|
7195
7314
|
options,
|
|
7196
|
-
realtimeUrl,
|
|
7197
7315
|
tokenManager
|
|
7198
7316
|
}) {
|
|
7199
7317
|
const sessionKey = `heroui-agent:session:${options.agentId}:${conversationId}`;
|
|
@@ -7208,41 +7326,19 @@ function useAgentTransport({
|
|
|
7208
7326
|
const session = restoreTriggerSession(stored, bootstrapStatus);
|
|
7209
7327
|
return session ? { [conversationId]: session } : void 0;
|
|
7210
7328
|
}, [bootstrapStatus, conversationId, sessionKey]);
|
|
7211
|
-
const reportedReconnectRef =
|
|
7329
|
+
const reportedReconnectRef = useRef15(false);
|
|
7212
7330
|
const authorizedFetch = useCallback11(
|
|
7213
|
-
|
|
7214
|
-
const request = async () => {
|
|
7215
|
-
const headers = new Headers(init.headers);
|
|
7216
|
-
headers.set("Authorization", `Bearer ${await tokenManager.get()}`);
|
|
7217
|
-
headers.set("X-HeroUI-Agent-Protocol-Version", String(HEROUI_AGENT_PROTOCOL_VERSION));
|
|
7218
|
-
headers.set("X-HeroUI-Agent-SDK-Version", HEROUI_AGENT_SDK_VERSION);
|
|
7219
|
-
return fetch(url, { ...init, headers });
|
|
7220
|
-
};
|
|
7221
|
-
let response = await request();
|
|
7222
|
-
if (response.status === 401) {
|
|
7223
|
-
tokenManager.clear();
|
|
7224
|
-
response = await request();
|
|
7225
|
-
}
|
|
7226
|
-
return response;
|
|
7227
|
-
},
|
|
7331
|
+
(url, init = {}) => fetchWithAgentAuthorization(tokenManager, url, init),
|
|
7228
7332
|
[tokenManager]
|
|
7229
7333
|
);
|
|
7230
7334
|
return useTriggerChatTransport({
|
|
7231
|
-
//
|
|
7232
|
-
//
|
|
7233
|
-
//
|
|
7234
|
-
accessToken:
|
|
7235
|
-
|
|
7236
|
-
`${options.apiBaseUrl}/v1/conversations/${encodeURIComponent(chatId)}/access-token`,
|
|
7237
|
-
{ method: "POST" }
|
|
7238
|
-
);
|
|
7239
|
-
if (!response.ok) throw new Error("Could not refresh the assistant session");
|
|
7240
|
-
return (await response.json()).publicAccessToken;
|
|
7241
|
-
},
|
|
7242
|
-
baseURL: ({ endpoint }) => endpoint === "out" ? realtimeUrl : `${options.apiBaseUrl}/v1/trigger`,
|
|
7335
|
+
// Both directions terminate at the HeroUI API. The transport continues to
|
|
7336
|
+
// own parsing, resume cursors, and stop semantics, while the browser only
|
|
7337
|
+
// authenticates with the credential supplied by the customer's backend.
|
|
7338
|
+
accessToken: () => tokenManager.get(),
|
|
7339
|
+
baseURL: agentTransportBaseUrl(options.apiBaseUrl),
|
|
7243
7340
|
clientData: modelId ? { modelId } : void 0,
|
|
7244
|
-
fetch: async (url, init
|
|
7245
|
-
if (context.endpoint !== "in") return fetch(url, init);
|
|
7341
|
+
fetch: async (url, init) => {
|
|
7246
7342
|
const headers = new Headers(init.headers);
|
|
7247
7343
|
headers.delete("Authorization");
|
|
7248
7344
|
return authorizedFetch(String(url), { ...init, headers });
|
|
@@ -7264,26 +7360,31 @@ function useAgentTransport({
|
|
|
7264
7360
|
},
|
|
7265
7361
|
...initialSessions ? { sessions: initialSessions } : {},
|
|
7266
7362
|
startSession: async ({ chatId, clientData }) => {
|
|
7267
|
-
|
|
7268
|
-
|
|
7269
|
-
|
|
7270
|
-
|
|
7271
|
-
|
|
7272
|
-
|
|
7273
|
-
|
|
7274
|
-
|
|
7275
|
-
|
|
7276
|
-
|
|
7277
|
-
|
|
7278
|
-
|
|
7279
|
-
|
|
7280
|
-
|
|
7281
|
-
|
|
7282
|
-
|
|
7283
|
-
|
|
7284
|
-
|
|
7285
|
-
|
|
7286
|
-
|
|
7363
|
+
try {
|
|
7364
|
+
const pageContext = clientData && typeof clientData === "object" ? clientData["pageContext"] : void 0;
|
|
7365
|
+
const requestedModelId = clientData && typeof clientData === "object" ? clientData["modelId"] : void 0;
|
|
7366
|
+
const response = await authorizedFetch(
|
|
7367
|
+
`${options.apiBaseUrl}/v1/conversations/${encodeURIComponent(chatId)}/session`,
|
|
7368
|
+
{
|
|
7369
|
+
body: JSON.stringify({
|
|
7370
|
+
clientTools: getClientToolManifest(),
|
|
7371
|
+
...requestedModelId ? { modelId: requestedModelId } : {},
|
|
7372
|
+
imageSearch: options.imageSearch,
|
|
7373
|
+
pageContext,
|
|
7374
|
+
protocolVersion: HEROUI_AGENT_PROTOCOL_VERSION,
|
|
7375
|
+
sdkVersion: HEROUI_AGENT_SDK_VERSION,
|
|
7376
|
+
webSearch: options.webSearch
|
|
7377
|
+
}),
|
|
7378
|
+
headers: { "Content-Type": "application/json" },
|
|
7379
|
+
method: "POST"
|
|
7380
|
+
}
|
|
7381
|
+
);
|
|
7382
|
+
if (!response.ok) throw new AgentSessionStartError();
|
|
7383
|
+
return await response.json();
|
|
7384
|
+
} catch (sessionError) {
|
|
7385
|
+
if (sessionError instanceof AgentSessionStartError) throw sessionError;
|
|
7386
|
+
throw new AgentSessionStartError({ cause: sessionError });
|
|
7387
|
+
}
|
|
7287
7388
|
},
|
|
7288
7389
|
task: HEROUI_AGENT_TASK_ID
|
|
7289
7390
|
});
|