@tangle-network/sandbox-ui 0.3.6 → 0.3.10
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/dist/active-sessions-store-CeOmXgv5.d.ts +85 -0
- package/dist/artifact-pane-Bh45Ssco.d.ts +24 -0
- package/dist/{chat-container-C8eHLw8z.d.ts → chat-container-Dn1jWtWo.d.ts} +20 -3
- package/dist/chat.d.ts +17 -4
- package/dist/chat.js +6 -2
- package/dist/{chunk-4F2GJRGU.js → chunk-6H3EFUUC.js} +196 -77
- package/dist/{chunk-WUR652Y3.js → chunk-72UEKFZ2.js} +113 -89
- package/dist/{chunk-TXI4MZAZ.js → chunk-CSIXZEKN.js} +152 -1
- package/dist/{chunk-5LV6DZZF.js → chunk-FOQTE67I.js} +278 -21
- package/dist/chunk-MGCVTFKB.js +10910 -0
- package/dist/chunk-OEX7NZE3.js +321 -0
- package/dist/chunk-Q56BYXQF.js +61 -0
- package/dist/{chunk-QGI5E7JD.js → chunk-RQOX5JRR.js} +541 -76
- package/dist/{chunk-PDV7W4NY.js → chunk-SULQQJPB.js} +1 -56
- package/dist/chunk-W4LM3QYZ.js +54 -0
- package/dist/{chunk-JF6E2DS5.js → chunk-ZYGWTIWO.js} +171 -155
- package/dist/document-editor-pane-Bk-9MQmw.d.ts +116 -0
- package/dist/document-editor-pane-GRIQOJHB.js +11 -0
- package/dist/editor.d.ts +7 -84
- package/dist/editor.js +18 -699
- package/dist/{expanded-tool-detail-BDi_h_dZ.d.ts → expanded-tool-detail-DM5M_T9h.d.ts} +10 -2
- package/dist/{file-tabs-CmaoDVBI.d.ts → file-tabs-BLfxfmAH.d.ts} +1 -22
- package/dist/files.d.ts +25 -3
- package/dist/files.js +2 -1
- package/dist/hooks.d.ts +3 -1
- package/dist/hooks.js +6 -1
- package/dist/index.d.ts +13 -7
- package/dist/index.js +26 -9
- package/dist/pages.js +4 -2
- package/dist/primitives.d.ts +45 -1
- package/dist/primitives.js +9 -3
- package/dist/run.d.ts +1 -1
- package/dist/run.js +1 -1
- package/dist/sdk-hooks.d.ts +32 -1
- package/dist/sdk-hooks.js +6 -1
- package/dist/stores.d.ts +1 -0
- package/dist/stores.js +60 -1
- package/dist/types.d.ts +2 -0
- package/dist/workspace.d.ts +84 -6
- package/dist/workspace.js +10 -4
- package/package.json +17 -6
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import * as nanostores from 'nanostores';
|
|
2
|
+
|
|
3
|
+
type SessionProjectKey = string | number;
|
|
4
|
+
type ActiveSessionStatus = "idle" | "running" | "attention-needed" | "error";
|
|
5
|
+
type ActiveSessionReconnectState = "idle" | "reconnecting" | "failed";
|
|
6
|
+
type ActiveSessionConnectionState = "disconnected" | "connecting" | "connected" | "reconnecting" | "error";
|
|
7
|
+
type ActiveSessionTransportMode = "websocket" | "sse" | "polling" | "custom";
|
|
8
|
+
interface ActiveSessionRecord {
|
|
9
|
+
sessionId: string;
|
|
10
|
+
projectId: SessionProjectKey | null;
|
|
11
|
+
projectLabel?: string;
|
|
12
|
+
title?: string;
|
|
13
|
+
href?: string;
|
|
14
|
+
registeredAt: number;
|
|
15
|
+
lastActivityAt: number;
|
|
16
|
+
lastEventAt: number | null;
|
|
17
|
+
status: ActiveSessionStatus;
|
|
18
|
+
isRunning: boolean;
|
|
19
|
+
isForeground: boolean;
|
|
20
|
+
needsAttention: boolean;
|
|
21
|
+
connectionState: ActiveSessionConnectionState;
|
|
22
|
+
reconnectState: ActiveSessionReconnectState;
|
|
23
|
+
transportMode: ActiveSessionTransportMode | null;
|
|
24
|
+
lastError: string | null;
|
|
25
|
+
metadata?: Record<string, unknown>;
|
|
26
|
+
}
|
|
27
|
+
interface ActiveSessionsState {
|
|
28
|
+
sessions: Record<string, ActiveSessionRecord>;
|
|
29
|
+
lastUpdatedAt: number;
|
|
30
|
+
}
|
|
31
|
+
interface RegisterActiveSessionOptions {
|
|
32
|
+
sessionId: string;
|
|
33
|
+
projectId?: SessionProjectKey | null;
|
|
34
|
+
projectLabel?: string;
|
|
35
|
+
title?: string;
|
|
36
|
+
href?: string;
|
|
37
|
+
metadata?: Record<string, unknown>;
|
|
38
|
+
}
|
|
39
|
+
interface ActiveSessionConnectionOptions {
|
|
40
|
+
connectionState: ActiveSessionConnectionState;
|
|
41
|
+
reconnectState?: ActiveSessionReconnectState;
|
|
42
|
+
transportMode?: ActiveSessionTransportMode | null;
|
|
43
|
+
lastError?: string | null;
|
|
44
|
+
lastEventAt?: number | null;
|
|
45
|
+
}
|
|
46
|
+
interface ActiveSessionActivityOptions {
|
|
47
|
+
lastEventAt?: number | null;
|
|
48
|
+
}
|
|
49
|
+
interface ActiveProjectActivity {
|
|
50
|
+
projectId: SessionProjectKey;
|
|
51
|
+
projectLabel?: string;
|
|
52
|
+
activeSessionCount: number;
|
|
53
|
+
runningSessionIds: string[];
|
|
54
|
+
lastActivityAt: number;
|
|
55
|
+
}
|
|
56
|
+
declare const activeSessionsAtom: nanostores.PreinitializedWritableAtom<ActiveSessionsState> & object;
|
|
57
|
+
declare function registerActiveSession(options: RegisterActiveSessionOptions): void;
|
|
58
|
+
declare function unregisterActiveSession(sessionId: string): void;
|
|
59
|
+
declare function setForegroundActiveSession(sessionId: string | null): void;
|
|
60
|
+
declare function updateActiveSessionMeta(sessionId: string, meta: Partial<Pick<ActiveSessionRecord, "title" | "href" | "projectId" | "projectLabel" | "metadata">>): void;
|
|
61
|
+
declare function setActiveSessionConnection(sessionId: string, options: ActiveSessionConnectionOptions): void;
|
|
62
|
+
declare function setActiveSessionRunning(sessionId: string, isRunning: boolean, options?: ActiveSessionActivityOptions): void;
|
|
63
|
+
declare function setActiveSessionAttention(sessionId: string, needsAttention: boolean, options?: ActiveSessionActivityOptions): void;
|
|
64
|
+
declare function setActiveSessionError(sessionId: string, error: string | null): void;
|
|
65
|
+
declare function bumpActiveSessionActivity(sessionId: string, options?: ActiveSessionActivityOptions): void;
|
|
66
|
+
declare function resetActiveSessions(): void;
|
|
67
|
+
declare function getAllActiveSessions(state: ActiveSessionsState): ActiveSessionRecord[];
|
|
68
|
+
declare function getActiveSession(state: ActiveSessionsState, sessionId: string): ActiveSessionRecord | null;
|
|
69
|
+
declare function getSessionsForProject(state: ActiveSessionsState, projectId: SessionProjectKey): ActiveSessionRecord[];
|
|
70
|
+
declare function getSessionsForNavbar(state: ActiveSessionsState, projectId?: SessionProjectKey | null): ActiveSessionRecord[];
|
|
71
|
+
declare function getSessionsByActivity(state: ActiveSessionsState): ActiveSessionRecord[];
|
|
72
|
+
declare function getTotalRunningSessionCount(state: ActiveSessionsState): number;
|
|
73
|
+
declare function hasBackgroundRunningSessions(state: ActiveSessionsState): boolean;
|
|
74
|
+
declare function getAllProjectActivity(state: ActiveSessionsState): ActiveProjectActivity[];
|
|
75
|
+
declare function useActiveSessionsState(): ActiveSessionsState;
|
|
76
|
+
declare function useActiveSessions(): ActiveSessionRecord[];
|
|
77
|
+
declare function useActiveSession(sessionId: string | null): ActiveSessionRecord | null;
|
|
78
|
+
declare function useProjectSessions(projectId: SessionProjectKey | null): ActiveSessionRecord[];
|
|
79
|
+
declare function useNavbarSessions(projectId?: SessionProjectKey | null): ActiveSessionRecord[];
|
|
80
|
+
declare function useSessionsByActivity(): ActiveSessionRecord[];
|
|
81
|
+
declare function useProjectActivity(): ActiveProjectActivity[];
|
|
82
|
+
declare function useTotalRunningSessions(): number;
|
|
83
|
+
declare function useHasBackgroundRunningSessions(): boolean;
|
|
84
|
+
|
|
85
|
+
export { type ActiveProjectActivity as A, updateActiveSessionMeta as B, useActiveSession as C, useActiveSessions as D, useActiveSessionsState as E, useHasBackgroundRunningSessions as F, useNavbarSessions as G, useProjectActivity as H, useProjectSessions as I, useSessionsByActivity as J, useTotalRunningSessions as K, type RegisterActiveSessionOptions as R, type SessionProjectKey as S, type ActiveSessionActivityOptions as a, type ActiveSessionConnectionOptions as b, type ActiveSessionConnectionState as c, type ActiveSessionReconnectState as d, type ActiveSessionRecord as e, type ActiveSessionStatus as f, type ActiveSessionTransportMode as g, type ActiveSessionsState as h, activeSessionsAtom as i, bumpActiveSessionActivity as j, getActiveSession as k, getAllActiveSessions as l, getAllProjectActivity as m, getSessionsByActivity as n, getSessionsForNavbar as o, getSessionsForProject as p, getTotalRunningSessionCount as q, hasBackgroundRunningSessions as r, registerActiveSession as s, resetActiveSessions as t, setActiveSessionAttention as u, setActiveSessionConnection as v, setActiveSessionError as w, setActiveSessionRunning as x, setForegroundActiveSession as y, unregisterActiveSession as z };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
interface ArtifactPaneProps {
|
|
5
|
+
eyebrow?: ReactNode;
|
|
6
|
+
title: ReactNode;
|
|
7
|
+
subtitle?: ReactNode;
|
|
8
|
+
meta?: ReactNode;
|
|
9
|
+
headerActions?: ReactNode;
|
|
10
|
+
tabs?: ReactNode;
|
|
11
|
+
toolbar?: ReactNode;
|
|
12
|
+
footer?: ReactNode;
|
|
13
|
+
emptyState?: ReactNode;
|
|
14
|
+
children?: ReactNode;
|
|
15
|
+
className?: string;
|
|
16
|
+
contentClassName?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* ArtifactPane — shared frame for files, previews, documents, inspectors, and
|
|
20
|
+
* other artifact-like surfaces inside sandbox applications.
|
|
21
|
+
*/
|
|
22
|
+
declare function ArtifactPane({ eyebrow, title, subtitle, meta, headerActions, tabs, toolbar, footer, emptyState, children, className, contentClassName, }: ArtifactPaneProps): react_jsx_runtime.JSX.Element;
|
|
23
|
+
|
|
24
|
+
export { type ArtifactPaneProps as A, ArtifactPane as a };
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
2
3
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
-
import { S as SessionMessage, a as SessionPart } from './parts-CyGkM6Fp.js';
|
|
4
|
+
import { S as SessionMessage, a as SessionPart, b as ToolPart } from './parts-CyGkM6Fp.js';
|
|
4
5
|
import { A as AgentBranding } from './branding-DCi5VEik.js';
|
|
5
6
|
import { C as CustomToolRenderer } from './tool-display-Ct9nFAzJ.js';
|
|
7
|
+
import { R as Run } from './run-CtFZ6s-D.js';
|
|
8
|
+
import { OpenUIAction } from './openui.js';
|
|
6
9
|
|
|
7
10
|
/**
|
|
8
11
|
* ChatInput — message input bar with file attach, send/cancel, model selector.
|
|
@@ -57,11 +60,25 @@ interface ChatContainerProps {
|
|
|
57
60
|
onRemoveFile?: (id: string) => void;
|
|
58
61
|
onAttach?: (files: FileList) => void;
|
|
59
62
|
disabled?: boolean;
|
|
63
|
+
/** Callback when an OpenUI action button is pressed within inline OpenUI blocks. */
|
|
64
|
+
onOpenUIAction?: (action: OpenUIAction) => void;
|
|
65
|
+
/** Enable rendering OpenUI schemas inline in the chat timeline. Defaults to true. */
|
|
66
|
+
enableOpenUI?: boolean;
|
|
67
|
+
/** Optional actions rendered beside each grouped assistant run. */
|
|
68
|
+
renderRunActions?: (run: Run) => ReactNode;
|
|
69
|
+
/** Optional actions rendered below each user message bubble. */
|
|
70
|
+
renderUserMessageActions?: (message: SessionMessage, parts: SessionPart[]) => ReactNode;
|
|
71
|
+
/** Optional actions rendered beside individual tool items. */
|
|
72
|
+
renderToolActions?: (part: ToolPart, options: {
|
|
73
|
+
run: Run;
|
|
74
|
+
messageId: string;
|
|
75
|
+
partIndex: number;
|
|
76
|
+
}) => ReactNode;
|
|
60
77
|
}
|
|
61
78
|
/**
|
|
62
79
|
* Full chat container: message list + auto-scroll + input area.
|
|
63
80
|
* Orchestrates useRunGroups, useRunCollapseState, and useAutoScroll.
|
|
64
81
|
*/
|
|
65
|
-
declare const ChatContainer: React.MemoExoticComponent<({ messages, partMap, isStreaming, onSend, onCancel, branding, placeholder, className, hideInput, renderToolDetail, presentation, modelLabel, onModelClick, pendingFiles, onRemoveFile, onAttach, disabled, }: ChatContainerProps) => react_jsx_runtime.JSX.Element>;
|
|
82
|
+
declare const ChatContainer: React.MemoExoticComponent<({ messages, partMap, isStreaming, onSend, onCancel, branding, placeholder, className, hideInput, renderToolDetail, presentation, modelLabel, onModelClick, pendingFiles, onRemoveFile, onAttach, disabled, onOpenUIAction, enableOpenUI, renderRunActions, renderUserMessageActions, renderToolActions, }: ChatContainerProps) => react_jsx_runtime.JSX.Element>;
|
|
66
83
|
|
|
67
|
-
export { ChatContainer as C, type PendingFile as P,
|
|
84
|
+
export { ChatContainer as C, type PendingFile as P, type ChatContainerProps as a, ChatInput as b, type ChatInputProps as c };
|
package/dist/chat.d.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
export { C as ChatContainer,
|
|
1
|
+
export { C as ChatContainer, a as ChatContainerProps, b as ChatInput, c as ChatInputProps, P as PendingFile } from './chat-container-Dn1jWtWo.js';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import { ReactNode } from 'react';
|
|
4
4
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
5
5
|
import { G as GroupedMessage } from './run-CtFZ6s-D.js';
|
|
6
|
-
import { a as SessionPart, S as SessionMessage } from './parts-CyGkM6Fp.js';
|
|
6
|
+
import { a as SessionPart, S as SessionMessage, b as ToolPart } from './parts-CyGkM6Fp.js';
|
|
7
7
|
import { A as AgentBranding } from './branding-DCi5VEik.js';
|
|
8
8
|
import { C as CustomToolRenderer } from './tool-display-Ct9nFAzJ.js';
|
|
9
9
|
import { T as ToolCallData } from './tool-call-feed-D5Ume-Pt.js';
|
|
10
|
+
import './openui.js';
|
|
10
11
|
|
|
11
12
|
type MessageRole = "user" | "assistant" | "system";
|
|
12
13
|
interface ChatMessageProps {
|
|
@@ -29,22 +30,34 @@ interface MessageListProps {
|
|
|
29
30
|
onToggleCollapse: (runId: string) => void;
|
|
30
31
|
branding?: AgentBranding;
|
|
31
32
|
renderToolDetail?: CustomToolRenderer;
|
|
33
|
+
renderRunActions?: (group: Extract<GroupedMessage, {
|
|
34
|
+
type: "run";
|
|
35
|
+
}>["run"]) => ReactNode;
|
|
36
|
+
renderUserMessageActions?: (message: SessionMessage, parts: SessionPart[]) => ReactNode;
|
|
37
|
+
renderToolActions?: (part: ToolPart, options: {
|
|
38
|
+
run: Extract<GroupedMessage, {
|
|
39
|
+
type: "run";
|
|
40
|
+
}>["run"];
|
|
41
|
+
messageId: string;
|
|
42
|
+
partIndex: number;
|
|
43
|
+
}) => ReactNode;
|
|
32
44
|
}
|
|
33
45
|
/**
|
|
34
46
|
* Maps GroupedMessage[] to UserMessage and RunGroup components.
|
|
35
47
|
* This is the main render list for the chat view.
|
|
36
48
|
*/
|
|
37
|
-
declare const MessageList: React.MemoExoticComponent<({ groups, partMap, isCollapsed, onToggleCollapse, branding, renderToolDetail, }: MessageListProps) => react_jsx_runtime.JSX.Element>;
|
|
49
|
+
declare const MessageList: React.MemoExoticComponent<({ groups, partMap, isCollapsed, onToggleCollapse, branding, renderToolDetail, renderRunActions, renderUserMessageActions, renderToolActions, }: MessageListProps) => react_jsx_runtime.JSX.Element>;
|
|
38
50
|
|
|
39
51
|
interface UserMessageProps {
|
|
40
52
|
message: SessionMessage;
|
|
41
53
|
parts: SessionPart[];
|
|
54
|
+
actions?: ReactNode;
|
|
42
55
|
}
|
|
43
56
|
/**
|
|
44
57
|
* Simple user message bubble.
|
|
45
58
|
* Renders text parts from the user's message.
|
|
46
59
|
*/
|
|
47
|
-
declare const UserMessage: React.MemoExoticComponent<({ message, parts }: UserMessageProps) => react_jsx_runtime.JSX.Element | null>;
|
|
60
|
+
declare const UserMessage: React.MemoExoticComponent<({ message, parts, actions }: UserMessageProps) => react_jsx_runtime.JSX.Element | null>;
|
|
48
61
|
|
|
49
62
|
interface ThinkingIndicatorProps {
|
|
50
63
|
className?: string;
|
package/dist/chat.js
CHANGED
|
@@ -6,13 +6,17 @@ import {
|
|
|
6
6
|
MessageList,
|
|
7
7
|
ThinkingIndicator,
|
|
8
8
|
UserMessage
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-6H3EFUUC.js";
|
|
10
10
|
import "./chunk-CNWVHQFY.js";
|
|
11
|
-
import "./chunk-
|
|
11
|
+
import "./chunk-72UEKFZ2.js";
|
|
12
12
|
import "./chunk-HRMUF35V.js";
|
|
13
13
|
import "./chunk-CJ2RYVZH.js";
|
|
14
14
|
import "./chunk-BX6AQMUS.js";
|
|
15
|
+
import "./chunk-YDBXQQLC.js";
|
|
16
|
+
import "./chunk-TQN3VR4F.js";
|
|
15
17
|
import "./chunk-LTFK464G.js";
|
|
18
|
+
import "./chunk-MXCSSOGH.js";
|
|
19
|
+
import "./chunk-HWLX5NME.js";
|
|
16
20
|
import "./chunk-RQHJBTEU.js";
|
|
17
21
|
export {
|
|
18
22
|
AgentTimeline,
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
import {
|
|
7
7
|
InlineThinkingItem,
|
|
8
8
|
RunGroup
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-72UEKFZ2.js";
|
|
10
10
|
import {
|
|
11
11
|
ToolCallGroup,
|
|
12
12
|
ToolCallStep
|
|
@@ -14,6 +14,9 @@ import {
|
|
|
14
14
|
import {
|
|
15
15
|
getToolDisplayMetadata
|
|
16
16
|
} from "./chunk-BX6AQMUS.js";
|
|
17
|
+
import {
|
|
18
|
+
OpenUIArtifactRenderer
|
|
19
|
+
} from "./chunk-YDBXQQLC.js";
|
|
17
20
|
import {
|
|
18
21
|
Markdown
|
|
19
22
|
} from "./chunk-LTFK464G.js";
|
|
@@ -24,12 +27,15 @@ import {
|
|
|
24
27
|
// src/chat/user-message.tsx
|
|
25
28
|
import { memo } from "react";
|
|
26
29
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
27
|
-
var UserMessage = memo(({ message, parts }) => {
|
|
30
|
+
var UserMessage = memo(({ message, parts, actions }) => {
|
|
28
31
|
const textContent = parts.filter((p) => p.type === "text").map((p) => p.text).join("\n");
|
|
29
32
|
if (!textContent.trim()) return null;
|
|
30
|
-
return /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxs("div", { className: "max-w-[
|
|
31
|
-
/* @__PURE__ */
|
|
32
|
-
|
|
33
|
+
return /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxs("div", { className: "flex max-w-[82%] flex-col items-end gap-2", children: [
|
|
34
|
+
/* @__PURE__ */ jsxs("div", { className: "w-full rounded-[calc(var(--radius-xl)+2px)] rounded-br-[var(--radius-sm)] border border-[var(--border-accent)] bg-[radial-gradient(circle_at_top_right,rgba(96,165,250,0.18),transparent_45%),linear-gradient(135deg,rgba(98,114,243,0.18),rgba(98,114,243,0.06)_55%,rgba(255,255,255,0.02))] px-4 py-3.5 shadow-[var(--shadow-accent)] backdrop-blur-sm", children: [
|
|
35
|
+
/* @__PURE__ */ jsx("div", { className: "mb-1.5 text-[11px] font-semibold uppercase tracking-[0.14em] text-[var(--brand-cool)]", children: "You" }),
|
|
36
|
+
/* @__PURE__ */ jsx("div", { className: "text-[15px] leading-7 text-[var(--text-primary)]", children: /* @__PURE__ */ jsx(Markdown, { className: "tangle-prose", children: textContent }) })
|
|
37
|
+
] }),
|
|
38
|
+
actions ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center justify-end gap-1.5 text-xs text-[var(--text-muted)]", children: actions }) : null
|
|
33
39
|
] }) });
|
|
34
40
|
});
|
|
35
41
|
UserMessage.displayName = "UserMessage";
|
|
@@ -44,15 +50,20 @@ var MessageList = memo2(
|
|
|
44
50
|
isCollapsed,
|
|
45
51
|
onToggleCollapse,
|
|
46
52
|
branding,
|
|
47
|
-
renderToolDetail
|
|
53
|
+
renderToolDetail,
|
|
54
|
+
renderRunActions,
|
|
55
|
+
renderUserMessageActions,
|
|
56
|
+
renderToolActions
|
|
48
57
|
}) => {
|
|
49
58
|
return /* @__PURE__ */ jsx2("div", { className: "space-y-3", children: groups.map((group) => {
|
|
50
59
|
if (group.type === "user") {
|
|
60
|
+
const messageParts = partMap[group.message.id] ?? [];
|
|
51
61
|
return /* @__PURE__ */ jsx2(
|
|
52
62
|
UserMessage,
|
|
53
63
|
{
|
|
54
64
|
message: group.message,
|
|
55
|
-
parts:
|
|
65
|
+
parts: messageParts,
|
|
66
|
+
actions: renderUserMessageActions?.(group.message, messageParts)
|
|
56
67
|
},
|
|
57
68
|
group.message.id
|
|
58
69
|
);
|
|
@@ -65,7 +76,9 @@ var MessageList = memo2(
|
|
|
65
76
|
collapsed: isCollapsed(group.run.id),
|
|
66
77
|
onToggle: () => onToggleCollapse(group.run.id),
|
|
67
78
|
branding,
|
|
68
|
-
renderToolDetail
|
|
79
|
+
renderToolDetail,
|
|
80
|
+
headerActions: renderRunActions?.(group.run),
|
|
81
|
+
renderToolActions
|
|
69
82
|
},
|
|
70
83
|
group.run.id
|
|
71
84
|
);
|
|
@@ -90,8 +103,8 @@ function ChatMessage({
|
|
|
90
103
|
"div",
|
|
91
104
|
{
|
|
92
105
|
className: cn(
|
|
93
|
-
"flex gap-
|
|
94
|
-
isUser ? "border-[var(--border-accent)] bg-[linear-gradient(135deg,rgba(98,114,243,0.
|
|
106
|
+
"flex gap-4 rounded-[calc(var(--radius-xl)+2px)] border px-4 py-4 shadow-[var(--shadow-card)] backdrop-blur-sm",
|
|
107
|
+
isUser ? "border-[var(--border-accent)] bg-[radial-gradient(circle_at_top_right,rgba(96,165,250,0.18),transparent_42%),linear-gradient(135deg,rgba(98,114,243,0.18),rgba(98,114,243,0.06)_55%,rgba(255,255,255,0.02))]" : "border-[var(--border-subtle)] bg-[radial-gradient(circle_at_top_left,rgba(96,165,250,0.12),transparent_34%),linear-gradient(180deg,rgba(255,255,255,0.03),transparent_32%),var(--bg-card)]",
|
|
95
108
|
className
|
|
96
109
|
),
|
|
97
110
|
children: [
|
|
@@ -99,20 +112,20 @@ function ChatMessage({
|
|
|
99
112
|
"div",
|
|
100
113
|
{
|
|
101
114
|
className: cn(
|
|
102
|
-
"mt-0.5 flex h-
|
|
103
|
-
isUser ? "border-[var(--border-accent)] bg-[
|
|
115
|
+
"mt-0.5 flex h-9 w-9 shrink-0 items-center justify-center rounded-[calc(var(--radius-md)+2px)] border shadow-[var(--shadow-accent)]",
|
|
116
|
+
isUser ? "border-[var(--border-accent)] bg-[linear-gradient(135deg,rgba(82,164,255,0.24),rgba(82,164,255,0.08))] text-[var(--brand-cool)]" : "border-[var(--border-subtle)] bg-[linear-gradient(135deg,rgba(77,203,255,0.24),rgba(77,203,255,0.08))] text-[var(--brand-glow)]"
|
|
104
117
|
),
|
|
105
118
|
children: isUser ? /* @__PURE__ */ jsx3(User, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx3(Bot, { className: "h-4 w-4" })
|
|
106
119
|
}
|
|
107
120
|
),
|
|
108
|
-
/* @__PURE__ */ jsxs2("div", { className: "
|
|
121
|
+
/* @__PURE__ */ jsxs2("div", { className: "min-w-0 flex-1 space-y-2", children: [
|
|
109
122
|
/* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
|
|
110
|
-
/* @__PURE__ */ jsx3("span", { className: "text-
|
|
111
|
-
timestamp && /* @__PURE__ */ jsx3("span", { className: "text-
|
|
123
|
+
/* @__PURE__ */ jsx3("span", { className: "text-[11px] font-semibold uppercase tracking-[0.14em] text-[var(--text-secondary)]", children: isUser ? "You" : "Agent" }),
|
|
124
|
+
timestamp && /* @__PURE__ */ jsx3("span", { className: "text-[11px] text-[var(--text-muted)]", children: formatTime(timestamp) })
|
|
112
125
|
] }),
|
|
113
|
-
isUser ? /* @__PURE__ */ jsx3("div", { className: "text-
|
|
114
|
-
content && /* @__PURE__ */ jsx3(Markdown, { className: "tangle-prose", children: content }),
|
|
115
|
-
isStreaming && /* @__PURE__ */ jsx3("span", { className: "inline-block w-2
|
|
126
|
+
isUser ? /* @__PURE__ */ jsx3("div", { className: "whitespace-pre-wrap text-[15px] leading-7 text-[var(--text-primary)]", children: content }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
127
|
+
content && /* @__PURE__ */ jsx3(Markdown, { className: "tangle-prose text-[15px] leading-7", children: content }),
|
|
128
|
+
isStreaming && /* @__PURE__ */ jsx3("span", { className: "ml-0.5 inline-block h-4 w-2 animate-pulse rounded-sm bg-[var(--brand-cool)] align-text-bottom" })
|
|
116
129
|
] }),
|
|
117
130
|
toolCalls
|
|
118
131
|
] })
|
|
@@ -402,8 +415,8 @@ function ChatInput({
|
|
|
402
415
|
"span",
|
|
403
416
|
{
|
|
404
417
|
className: cn(
|
|
405
|
-
"inline-flex items-center gap-1.5 rounded-[var(--radius-full)] border px-3 py-1.5 text-xs shadow-[var(--shadow-card)]",
|
|
406
|
-
"border-[var(--border-subtle)] bg-[linear-gradient(180deg,rgba(255,255,255,0.
|
|
418
|
+
"inline-flex items-center gap-1.5 rounded-[var(--radius-full)] border px-3 py-1.5 text-xs shadow-[var(--shadow-card)] backdrop-blur-sm",
|
|
419
|
+
"border-[var(--border-subtle)] bg-[linear-gradient(180deg,rgba(255,255,255,0.05),rgba(255,255,255,0.02))]",
|
|
407
420
|
f.status === "error" && "border-[var(--code-error)]/30 text-[var(--code-error)]",
|
|
408
421
|
f.status !== "error" && "text-[var(--text-secondary)]"
|
|
409
422
|
),
|
|
@@ -424,65 +437,71 @@ function ChatInput({
|
|
|
424
437
|
},
|
|
425
438
|
f.id
|
|
426
439
|
)) }),
|
|
427
|
-
/* @__PURE__ */ jsx6("div", { className: "rounded-[
|
|
428
|
-
|
|
440
|
+
/* @__PURE__ */ jsx6("div", { className: "rounded-[28px] border border-[var(--border-subtle)] bg-[radial-gradient(circle_at_top,rgba(96,165,250,0.16),transparent_42%),linear-gradient(135deg,rgba(98,114,243,0.12),rgba(255,255,255,0.03)_42%,transparent)] p-[1px] shadow-[var(--shadow-accent)]", children: /* @__PURE__ */ jsxs5("div", { className: "rounded-[26px] border border-white/5 bg-[linear-gradient(180deg,rgba(255,255,255,0.03),transparent_35%),var(--bg-card)] px-3 py-3.5 transition-colors focus-within:border-[var(--border-accent)]", children: [
|
|
441
|
+
/* @__PURE__ */ jsxs5("div", { className: "mb-2 flex items-center justify-between gap-3 px-1", children: [
|
|
442
|
+
/* @__PURE__ */ jsx6("div", { className: "text-[11px] font-semibold uppercase tracking-[0.16em] text-[var(--text-muted)]", children: "Agent Command Deck" }),
|
|
443
|
+
/* @__PURE__ */ jsx6("div", { className: "text-[11px] text-[var(--text-muted)]", children: isStreaming ? "Streaming response" : "Ready for next instruction" })
|
|
444
|
+
] }),
|
|
445
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex items-end gap-2", children: [
|
|
446
|
+
onAttach && /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
447
|
+
/* @__PURE__ */ jsx6(
|
|
448
|
+
"button",
|
|
449
|
+
{
|
|
450
|
+
type: "button",
|
|
451
|
+
onClick: handleAttachClick,
|
|
452
|
+
disabled: isStreaming,
|
|
453
|
+
"aria-label": "Attach files",
|
|
454
|
+
className: "mb-0.5 shrink-0 rounded-[var(--radius-md)] border border-transparent p-2 text-[var(--text-muted)] transition-colors hover:border-[var(--border-subtle)] hover:bg-[var(--bg-hover)] hover:text-[var(--text-secondary)] disabled:opacity-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--brand-cool)]/60",
|
|
455
|
+
children: /* @__PURE__ */ jsx6(Paperclip, { className: "h-4 w-4" })
|
|
456
|
+
}
|
|
457
|
+
),
|
|
458
|
+
/* @__PURE__ */ jsx6(
|
|
459
|
+
"input",
|
|
460
|
+
{
|
|
461
|
+
ref: fileInputRef,
|
|
462
|
+
type: "file",
|
|
463
|
+
multiple: true,
|
|
464
|
+
className: "hidden",
|
|
465
|
+
onChange: handleFileChange,
|
|
466
|
+
accept: ".pdf,.csv,.xlsx,.xls,.jpg,.jpeg,.png,.gif,.txt,.json,.yaml,.yml"
|
|
467
|
+
}
|
|
468
|
+
)
|
|
469
|
+
] }),
|
|
429
470
|
/* @__PURE__ */ jsx6(
|
|
471
|
+
"textarea",
|
|
472
|
+
{
|
|
473
|
+
ref: textareaRef,
|
|
474
|
+
value,
|
|
475
|
+
onChange: handleChange,
|
|
476
|
+
onKeyDown: handleKeyDown,
|
|
477
|
+
placeholder,
|
|
478
|
+
disabled: isStreaming || disabled,
|
|
479
|
+
rows: 1,
|
|
480
|
+
"aria-label": "Message input",
|
|
481
|
+
className: "min-h-[36px] max-h-[160px] flex-1 resize-none bg-transparent text-[15px] leading-7 text-[var(--text-primary)] placeholder:text-[var(--text-muted)] disabled:opacity-50 focus-visible:outline-none"
|
|
482
|
+
}
|
|
483
|
+
),
|
|
484
|
+
isStreaming ? /* @__PURE__ */ jsx6(
|
|
430
485
|
"button",
|
|
431
486
|
{
|
|
432
487
|
type: "button",
|
|
433
|
-
onClick:
|
|
434
|
-
|
|
435
|
-
"
|
|
436
|
-
|
|
437
|
-
children: /* @__PURE__ */ jsx6(Paperclip, { className: "h-4 w-4" })
|
|
488
|
+
onClick: onCancel,
|
|
489
|
+
"aria-label": "Stop response",
|
|
490
|
+
className: "mb-0.5 shrink-0 rounded-[var(--radius-lg)] border border-[var(--code-error)]/20 bg-[var(--code-error)]/14 p-2.5 text-[var(--code-error)] transition-colors hover:bg-[var(--code-error)]/24 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--code-error)]/50",
|
|
491
|
+
children: /* @__PURE__ */ jsx6(Square, { className: "h-4 w-4" })
|
|
438
492
|
}
|
|
439
|
-
)
|
|
440
|
-
|
|
441
|
-
"input",
|
|
493
|
+
) : /* @__PURE__ */ jsx6(
|
|
494
|
+
"button",
|
|
442
495
|
{
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
496
|
+
type: "button",
|
|
497
|
+
onClick: handleSend,
|
|
498
|
+
disabled: !value.trim() || disabled,
|
|
499
|
+
"aria-label": "Send message",
|
|
500
|
+
className: "mb-0.5 shrink-0 rounded-[var(--radius-lg)] border border-[var(--border-accent)] bg-[linear-gradient(135deg,rgba(82,164,255,0.24),rgba(82,164,255,0.08))] p-2.5 text-[var(--brand-cool)] transition-colors hover:translate-y-[-1px] hover:bg-[linear-gradient(135deg,rgba(82,164,255,0.28),rgba(82,164,255,0.12))] disabled:opacity-30 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--brand-cool)]/60",
|
|
501
|
+
children: /* @__PURE__ */ jsx6(Send, { className: "h-4 w-4" })
|
|
449
502
|
}
|
|
450
503
|
)
|
|
451
|
-
] })
|
|
452
|
-
/* @__PURE__ */ jsx6(
|
|
453
|
-
"textarea",
|
|
454
|
-
{
|
|
455
|
-
ref: textareaRef,
|
|
456
|
-
value,
|
|
457
|
-
onChange: handleChange,
|
|
458
|
-
onKeyDown: handleKeyDown,
|
|
459
|
-
placeholder,
|
|
460
|
-
disabled: isStreaming || disabled,
|
|
461
|
-
rows: 1,
|
|
462
|
-
"aria-label": "Message input",
|
|
463
|
-
className: "min-h-[28px] max-h-[160px] flex-1 resize-none bg-transparent text-sm leading-relaxed text-[var(--text-primary)] placeholder:text-[var(--text-muted)] disabled:opacity-50 focus-visible:outline-none"
|
|
464
|
-
}
|
|
465
|
-
),
|
|
466
|
-
isStreaming ? /* @__PURE__ */ jsx6(
|
|
467
|
-
"button",
|
|
468
|
-
{
|
|
469
|
-
type: "button",
|
|
470
|
-
onClick: onCancel,
|
|
471
|
-
"aria-label": "Stop response",
|
|
472
|
-
className: "mb-0.5 shrink-0 rounded-[var(--radius-md)] bg-[var(--code-error)]/15 p-2 text-[var(--code-error)] transition-colors hover:bg-[var(--code-error)]/25 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--code-error)]/50",
|
|
473
|
-
children: /* @__PURE__ */ jsx6(Square, { className: "h-4 w-4" })
|
|
474
|
-
}
|
|
475
|
-
) : /* @__PURE__ */ jsx6(
|
|
476
|
-
"button",
|
|
477
|
-
{
|
|
478
|
-
type: "button",
|
|
479
|
-
onClick: handleSend,
|
|
480
|
-
disabled: !value.trim() || disabled,
|
|
481
|
-
"aria-label": "Send message",
|
|
482
|
-
className: "mb-0.5 shrink-0 rounded-[var(--radius-md)] bg-[var(--brand-cool)]/15 p-2 text-[var(--brand-cool)] transition-colors hover:bg-[var(--brand-cool)]/25 disabled:opacity-30 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--brand-cool)]/60",
|
|
483
|
-
children: /* @__PURE__ */ jsx6(Send, { className: "h-4 w-4" })
|
|
484
|
-
}
|
|
485
|
-
)
|
|
504
|
+
] })
|
|
486
505
|
] }) }),
|
|
487
506
|
/* @__PURE__ */ jsxs5("div", { className: "mt-2 flex items-center justify-between px-1", children: [
|
|
488
507
|
/* @__PURE__ */ jsx6("div", { className: "flex items-center gap-2", children: modelLabel && /* @__PURE__ */ jsxs5(
|
|
@@ -491,7 +510,7 @@ function ChatInput({
|
|
|
491
510
|
type: "button",
|
|
492
511
|
onClick: onModelClick,
|
|
493
512
|
"aria-label": `Select model, current model ${modelLabel}`,
|
|
494
|
-
className: "inline-flex items-center gap-1 rounded-[var(--radius-full)] border border-[var(--border-subtle)] bg-[
|
|
513
|
+
className: "inline-flex items-center gap-1.5 rounded-[var(--radius-full)] border border-[var(--border-subtle)] bg-[linear-gradient(180deg,rgba(255,255,255,0.04),transparent)] px-2.5 py-1 text-xs text-[var(--text-muted)] transition-colors hover:border-[var(--border-accent)] hover:text-[var(--text-secondary)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--brand-cool)]/60",
|
|
495
514
|
children: [
|
|
496
515
|
/* @__PURE__ */ jsx6("span", { className: "w-1.5 h-1.5 rounded-full bg-[var(--code-success)]" }),
|
|
497
516
|
modelLabel
|
|
@@ -516,6 +535,52 @@ import {
|
|
|
516
535
|
} from "react";
|
|
517
536
|
import { ArrowDown } from "lucide-react";
|
|
518
537
|
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
538
|
+
var OPENUI_NODE_TYPES = /* @__PURE__ */ new Set([
|
|
539
|
+
"heading",
|
|
540
|
+
"text",
|
|
541
|
+
"badge",
|
|
542
|
+
"stat",
|
|
543
|
+
"key_value",
|
|
544
|
+
"code",
|
|
545
|
+
"markdown",
|
|
546
|
+
"table",
|
|
547
|
+
"actions",
|
|
548
|
+
"separator",
|
|
549
|
+
"stack",
|
|
550
|
+
"grid",
|
|
551
|
+
"card"
|
|
552
|
+
]);
|
|
553
|
+
function isOpenUINode(value) {
|
|
554
|
+
return typeof value === "object" && value !== null && "type" in value && typeof value.type === "string" && OPENUI_NODE_TYPES.has(value.type);
|
|
555
|
+
}
|
|
556
|
+
function extractOpenUISchema(output) {
|
|
557
|
+
if (output == null) return null;
|
|
558
|
+
if (isOpenUINode(output)) return [output];
|
|
559
|
+
if (Array.isArray(output) && output.length > 0 && output.every(isOpenUINode)) {
|
|
560
|
+
return output;
|
|
561
|
+
}
|
|
562
|
+
if (typeof output === "object" && !Array.isArray(output)) {
|
|
563
|
+
const obj = output;
|
|
564
|
+
for (const key of ["openui", "schema", "ui"]) {
|
|
565
|
+
if (obj[key]) {
|
|
566
|
+
const inner = obj[key];
|
|
567
|
+
if (isOpenUINode(inner)) return [inner];
|
|
568
|
+
if (Array.isArray(inner) && inner.length > 0 && inner.every(isOpenUINode)) {
|
|
569
|
+
return inner;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
if (typeof output === "string") {
|
|
575
|
+
try {
|
|
576
|
+
const parsed = JSON.parse(output);
|
|
577
|
+
return extractOpenUISchema(parsed);
|
|
578
|
+
} catch {
|
|
579
|
+
return null;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
return null;
|
|
583
|
+
}
|
|
519
584
|
function formatUnknown(value) {
|
|
520
585
|
if (value == null) return void 0;
|
|
521
586
|
if (typeof value === "string") return value;
|
|
@@ -563,7 +628,7 @@ function mapToolPartToTimelineType(part) {
|
|
|
563
628
|
return "unknown";
|
|
564
629
|
}
|
|
565
630
|
}
|
|
566
|
-
function buildTimelineItems(messages, partMap, isStreaming) {
|
|
631
|
+
function buildTimelineItems(messages, partMap, isStreaming, onOpenUIAction, enableOpenUI = true) {
|
|
567
632
|
const items = [];
|
|
568
633
|
const lastAssistantMessage = [...messages].reverse().find((message) => message.role === "assistant");
|
|
569
634
|
const toToolCall = (part) => {
|
|
@@ -611,6 +676,18 @@ function buildTimelineItems(messages, partMap, isStreaming) {
|
|
|
611
676
|
calls: toolBuffer.map((part) => toToolCall(part))
|
|
612
677
|
});
|
|
613
678
|
}
|
|
679
|
+
if (enableOpenUI) {
|
|
680
|
+
for (const part of toolBuffer) {
|
|
681
|
+
if (part.state.status !== "completed" || !part.state.output) continue;
|
|
682
|
+
const schema = extractOpenUISchema(part.state.output);
|
|
683
|
+
if (!schema) continue;
|
|
684
|
+
items.push({
|
|
685
|
+
id: `${message.id}-openui-${part.id}`,
|
|
686
|
+
kind: "custom",
|
|
687
|
+
content: /* @__PURE__ */ jsx7("div", { className: "my-2 rounded-[var(--radius-lg)] border border-[var(--border-subtle)] bg-[var(--bg-card)] p-4 shadow-[var(--shadow-card)]", children: /* @__PURE__ */ jsx7(OpenUIArtifactRenderer, { schema, onAction: onOpenUIAction }) })
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
}
|
|
614
691
|
toolBuffer.length = 0;
|
|
615
692
|
};
|
|
616
693
|
parts.forEach((part, index) => {
|
|
@@ -621,6 +698,40 @@ function buildTimelineItems(messages, partMap, isStreaming) {
|
|
|
621
698
|
}
|
|
622
699
|
flushToolBuffer(index);
|
|
623
700
|
if (part.type === "text" && !part.synthetic && part.text.trim()) {
|
|
701
|
+
if (enableOpenUI) {
|
|
702
|
+
const jsonMatch = part.text.match(/```(?:json)?\s*\n([\s\S]*?)\n```/);
|
|
703
|
+
if (jsonMatch) {
|
|
704
|
+
const schema = extractOpenUISchema(jsonMatch[1]);
|
|
705
|
+
if (schema) {
|
|
706
|
+
const beforeJson = part.text.slice(0, part.text.indexOf("```")).trim();
|
|
707
|
+
if (beforeJson) {
|
|
708
|
+
items.push({
|
|
709
|
+
id: `${itemId}-text`,
|
|
710
|
+
kind: "message",
|
|
711
|
+
role: "assistant",
|
|
712
|
+
content: beforeJson,
|
|
713
|
+
timestamp: createdAtFromMessage(message)
|
|
714
|
+
});
|
|
715
|
+
}
|
|
716
|
+
items.push({
|
|
717
|
+
id: `${itemId}-openui`,
|
|
718
|
+
kind: "custom",
|
|
719
|
+
content: /* @__PURE__ */ jsx7("div", { className: "my-2 rounded-[var(--radius-lg)] border border-[var(--border-subtle)] bg-[var(--bg-card)] p-4 shadow-[var(--shadow-card)]", children: /* @__PURE__ */ jsx7(OpenUIArtifactRenderer, { schema, onAction: onOpenUIAction }) })
|
|
720
|
+
});
|
|
721
|
+
const afterJson = part.text.slice(part.text.lastIndexOf("```") + 3).trim();
|
|
722
|
+
if (afterJson) {
|
|
723
|
+
items.push({
|
|
724
|
+
id: `${itemId}-after`,
|
|
725
|
+
kind: "message",
|
|
726
|
+
role: "assistant",
|
|
727
|
+
content: afterJson,
|
|
728
|
+
timestamp: createdAtFromMessage(message)
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
}
|
|
624
735
|
items.push({
|
|
625
736
|
id: itemId,
|
|
626
737
|
kind: "message",
|
|
@@ -665,7 +776,12 @@ var ChatContainer = memo3(
|
|
|
665
776
|
pendingFiles,
|
|
666
777
|
onRemoveFile,
|
|
667
778
|
onAttach,
|
|
668
|
-
disabled = false
|
|
779
|
+
disabled = false,
|
|
780
|
+
onOpenUIAction,
|
|
781
|
+
enableOpenUI = true,
|
|
782
|
+
renderRunActions,
|
|
783
|
+
renderUserMessageActions,
|
|
784
|
+
renderToolActions
|
|
669
785
|
}) => {
|
|
670
786
|
const scrollRef = useRef2(null);
|
|
671
787
|
const groups = useRunGroups({ messages, partMap, isStreaming });
|
|
@@ -677,8 +793,8 @@ var ChatContainer = memo3(
|
|
|
677
793
|
isStreaming
|
|
678
794
|
]);
|
|
679
795
|
const timeline = useMemo(
|
|
680
|
-
() => buildTimelineItems(messages, partMap, isStreaming),
|
|
681
|
-
[messages, partMap, isStreaming]
|
|
796
|
+
() => buildTimelineItems(messages, partMap, isStreaming, onOpenUIAction, enableOpenUI),
|
|
797
|
+
[messages, partMap, isStreaming, onOpenUIAction, enableOpenUI]
|
|
682
798
|
);
|
|
683
799
|
const handleSend = useCallback2(
|
|
684
800
|
(text) => {
|
|
@@ -703,7 +819,10 @@ var ChatContainer = memo3(
|
|
|
703
819
|
isCollapsed,
|
|
704
820
|
onToggleCollapse: toggleCollapse,
|
|
705
821
|
branding,
|
|
706
|
-
renderToolDetail
|
|
822
|
+
renderToolDetail,
|
|
823
|
+
renderRunActions,
|
|
824
|
+
renderUserMessageActions,
|
|
825
|
+
renderToolActions
|
|
707
826
|
}
|
|
708
827
|
) })
|
|
709
828
|
}
|