@tangle-network/sandbox-ui 0.3.7 → 0.3.11

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.
Files changed (39) hide show
  1. package/dist/active-sessions-store-CeOmXgv5.d.ts +85 -0
  2. package/dist/artifact-pane-Bh45Ssco.d.ts +24 -0
  3. package/dist/{chat-container-B34uj-J1.d.ts → chat-container-Dn1jWtWo.d.ts} +15 -3
  4. package/dist/chat.d.ts +16 -4
  5. package/dist/chat.js +2 -2
  6. package/dist/{chunk-PXRPYAMM.js → chunk-6H3EFUUC.js} +96 -74
  7. package/dist/{chunk-JF6E2DS5.js → chunk-6NYG2R7V.js} +171 -155
  8. package/dist/{chunk-WUR652Y3.js → chunk-72UEKFZ2.js} +113 -89
  9. package/dist/chunk-BOBXH6CH.js +10981 -0
  10. package/dist/{chunk-ZSNOGOUX.js → chunk-CREVWUCA.js} +541 -76
  11. package/dist/{chunk-5LV6DZZF.js → chunk-FOQTE67I.js} +278 -21
  12. package/dist/chunk-OEX7NZE3.js +321 -0
  13. package/dist/chunk-Q56BYXQF.js +61 -0
  14. package/dist/{chunk-PDV7W4NY.js → chunk-SULQQJPB.js} +1 -56
  15. package/dist/chunk-W4LM3QYZ.js +54 -0
  16. package/dist/document-editor-pane-AFBP2KFT.js +11 -0
  17. package/dist/document-editor-pane-Xnl8SmA7.d.ts +124 -0
  18. package/dist/editor.d.ts +7 -84
  19. package/dist/editor.js +18 -699
  20. package/dist/{expanded-tool-detail-BDi_h_dZ.d.ts → expanded-tool-detail-DM5M_T9h.d.ts} +10 -2
  21. package/dist/{file-tabs-CmaoDVBI.d.ts → file-tabs-BLfxfmAH.d.ts} +1 -22
  22. package/dist/files.d.ts +25 -3
  23. package/dist/files.js +2 -1
  24. package/dist/hooks.d.ts +3 -1
  25. package/dist/hooks.js +6 -1
  26. package/dist/index.d.ts +12 -6
  27. package/dist/index.js +21 -8
  28. package/dist/pages.js +4 -2
  29. package/dist/primitives.js +4 -2
  30. package/dist/run.d.ts +1 -1
  31. package/dist/run.js +1 -1
  32. package/dist/sdk-hooks.d.ts +32 -1
  33. package/dist/sdk-hooks.js +6 -1
  34. package/dist/stores.d.ts +1 -0
  35. package/dist/stores.js +60 -1
  36. package/dist/types.d.ts +2 -0
  37. package/dist/workspace.d.ts +84 -6
  38. package/dist/workspace.js +10 -4
  39. 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,10 @@
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';
6
8
  import { OpenUIAction } from './openui.js';
7
9
 
8
10
  /**
@@ -62,11 +64,21 @@ interface ChatContainerProps {
62
64
  onOpenUIAction?: (action: OpenUIAction) => void;
63
65
  /** Enable rendering OpenUI schemas inline in the chat timeline. Defaults to true. */
64
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;
65
77
  }
66
78
  /**
67
79
  * Full chat container: message list + auto-scroll + input area.
68
80
  * Orchestrates useRunGroups, useRunCollapseState, and useAutoScroll.
69
81
  */
70
- declare const ChatContainer: React.MemoExoticComponent<({ messages, partMap, isStreaming, onSend, onCancel, branding, placeholder, className, hideInput, renderToolDetail, presentation, modelLabel, onModelClick, pendingFiles, onRemoveFile, onAttach, disabled, onOpenUIAction, enableOpenUI, }: 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>;
71
83
 
72
- export { ChatContainer as C, type PendingFile as P, ChatInput as a, type ChatInputProps as b, type ChatContainerProps as c };
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,9 +1,9 @@
1
- export { C as ChatContainer, c as ChatContainerProps, a as ChatInput, b as ChatInputProps, P as PendingFile } from './chat-container-B34uj-J1.js';
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';
@@ -30,22 +30,34 @@ interface MessageListProps {
30
30
  onToggleCollapse: (runId: string) => void;
31
31
  branding?: AgentBranding;
32
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;
33
44
  }
34
45
  /**
35
46
  * Maps GroupedMessage[] to UserMessage and RunGroup components.
36
47
  * This is the main render list for the chat view.
37
48
  */
38
- 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>;
39
50
 
40
51
  interface UserMessageProps {
41
52
  message: SessionMessage;
42
53
  parts: SessionPart[];
54
+ actions?: ReactNode;
43
55
  }
44
56
  /**
45
57
  * Simple user message bubble.
46
58
  * Renders text parts from the user's message.
47
59
  */
48
- 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>;
49
61
 
50
62
  interface ThinkingIndicatorProps {
51
63
  className?: string;
package/dist/chat.js CHANGED
@@ -6,9 +6,9 @@ import {
6
6
  MessageList,
7
7
  ThinkingIndicator,
8
8
  UserMessage
9
- } from "./chunk-PXRPYAMM.js";
9
+ } from "./chunk-6H3EFUUC.js";
10
10
  import "./chunk-CNWVHQFY.js";
11
- import "./chunk-WUR652Y3.js";
11
+ import "./chunk-72UEKFZ2.js";
12
12
  import "./chunk-HRMUF35V.js";
13
13
  import "./chunk-CJ2RYVZH.js";
14
14
  import "./chunk-BX6AQMUS.js";
@@ -6,7 +6,7 @@ import {
6
6
  import {
7
7
  InlineThinkingItem,
8
8
  RunGroup
9
- } from "./chunk-WUR652Y3.js";
9
+ } from "./chunk-72UEKFZ2.js";
10
10
  import {
11
11
  ToolCallGroup,
12
12
  ToolCallStep
@@ -27,12 +27,15 @@ import {
27
27
  // src/chat/user-message.tsx
28
28
  import { memo } from "react";
29
29
  import { jsx, jsxs } from "react/jsx-runtime";
30
- var UserMessage = memo(({ message, parts }) => {
30
+ var UserMessage = memo(({ message, parts, actions }) => {
31
31
  const textContent = parts.filter((p) => p.type === "text").map((p) => p.text).join("\n");
32
32
  if (!textContent.trim()) return null;
33
- return /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxs("div", { className: "max-w-[85%] rounded-[var(--radius-xl)] rounded-br-[var(--radius-sm)] border border-[var(--border-accent)] bg-[linear-gradient(135deg,rgba(98,114,243,0.16),rgba(98,114,243,0.06))] px-4 py-3 shadow-[var(--shadow-card)]", children: [
34
- /* @__PURE__ */ jsx("div", { className: "mb-1 text-[11px] font-semibold uppercase tracking-[0.12em] text-[var(--brand-cool)]", children: "You" }),
35
- /* @__PURE__ */ jsx("div", { className: "text-sm text-[var(--text-primary)]", children: /* @__PURE__ */ jsx(Markdown, { children: textContent }) })
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
36
39
  ] }) });
37
40
  });
38
41
  UserMessage.displayName = "UserMessage";
@@ -47,15 +50,20 @@ var MessageList = memo2(
47
50
  isCollapsed,
48
51
  onToggleCollapse,
49
52
  branding,
50
- renderToolDetail
53
+ renderToolDetail,
54
+ renderRunActions,
55
+ renderUserMessageActions,
56
+ renderToolActions
51
57
  }) => {
52
58
  return /* @__PURE__ */ jsx2("div", { className: "space-y-3", children: groups.map((group) => {
53
59
  if (group.type === "user") {
60
+ const messageParts = partMap[group.message.id] ?? [];
54
61
  return /* @__PURE__ */ jsx2(
55
62
  UserMessage,
56
63
  {
57
64
  message: group.message,
58
- parts: partMap[group.message.id] ?? []
65
+ parts: messageParts,
66
+ actions: renderUserMessageActions?.(group.message, messageParts)
59
67
  },
60
68
  group.message.id
61
69
  );
@@ -68,7 +76,9 @@ var MessageList = memo2(
68
76
  collapsed: isCollapsed(group.run.id),
69
77
  onToggle: () => onToggleCollapse(group.run.id),
70
78
  branding,
71
- renderToolDetail
79
+ renderToolDetail,
80
+ headerActions: renderRunActions?.(group.run),
81
+ renderToolActions
72
82
  },
73
83
  group.run.id
74
84
  );
@@ -93,8 +103,8 @@ function ChatMessage({
93
103
  "div",
94
104
  {
95
105
  className: cn(
96
- "flex gap-3 rounded-[var(--radius-xl)] border px-4 py-4 shadow-[var(--shadow-card)]",
97
- isUser ? "border-[var(--border-accent)] bg-[linear-gradient(135deg,rgba(98,114,243,0.14),rgba(98,114,243,0.05))]" : "border-[var(--border-subtle)] bg-[linear-gradient(180deg,rgba(255,255,255,0.02),transparent_32%),var(--bg-card)]",
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)]",
98
108
  className
99
109
  ),
100
110
  children: [
@@ -102,20 +112,20 @@ function ChatMessage({
102
112
  "div",
103
113
  {
104
114
  className: cn(
105
- "mt-0.5 flex h-8 w-8 shrink-0 items-center justify-center rounded-[var(--radius-md)] border",
106
- isUser ? "border-[var(--border-accent)] bg-[var(--brand-cool)]/15 text-[var(--brand-cool)]" : "border-[var(--border-subtle)] bg-[var(--brand-glow)]/12 text-[var(--brand-glow)]"
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)]"
107
117
  ),
108
118
  children: isUser ? /* @__PURE__ */ jsx3(User, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx3(Bot, { className: "h-4 w-4" })
109
119
  }
110
120
  ),
111
- /* @__PURE__ */ jsxs2("div", { className: "flex-1 min-w-0 space-y-1", children: [
121
+ /* @__PURE__ */ jsxs2("div", { className: "min-w-0 flex-1 space-y-2", children: [
112
122
  /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
113
- /* @__PURE__ */ jsx3("span", { className: "text-xs font-semibold text-[var(--text-secondary)]", children: isUser ? "You" : "Agent" }),
114
- timestamp && /* @__PURE__ */ jsx3("span", { className: "text-xs text-[var(--text-muted)]", children: formatTime(timestamp) })
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) })
115
125
  ] }),
116
- isUser ? /* @__PURE__ */ jsx3("div", { className: "text-sm leading-relaxed text-[var(--text-primary)] whitespace-pre-wrap", children: content }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
117
- content && /* @__PURE__ */ jsx3(Markdown, { className: "tangle-prose", children: content }),
118
- isStreaming && /* @__PURE__ */ jsx3("span", { className: "inline-block w-2 h-4 bg-[var(--brand-cool)] animate-pulse rounded-sm ml-0.5 align-text-bottom" })
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" })
119
129
  ] }),
120
130
  toolCalls
121
131
  ] })
@@ -405,8 +415,8 @@ function ChatInput({
405
415
  "span",
406
416
  {
407
417
  className: cn(
408
- "inline-flex items-center gap-1.5 rounded-[var(--radius-full)] border px-3 py-1.5 text-xs shadow-[var(--shadow-card)]",
409
- "border-[var(--border-subtle)] bg-[linear-gradient(180deg,rgba(255,255,255,0.03),transparent)]",
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))]",
410
420
  f.status === "error" && "border-[var(--code-error)]/30 text-[var(--code-error)]",
411
421
  f.status !== "error" && "text-[var(--text-secondary)]"
412
422
  ),
@@ -427,65 +437,71 @@ function ChatInput({
427
437
  },
428
438
  f.id
429
439
  )) }),
430
- /* @__PURE__ */ jsx6("div", { className: "rounded-[calc(var(--radius-xl)+2px)] border border-[var(--border-subtle)] bg-[linear-gradient(135deg,rgba(98,114,243,0.08),rgba(255,255,255,0.02)_40%,transparent)] p-[1px] shadow-[var(--shadow-card)]", children: /* @__PURE__ */ jsxs5("div", { className: "flex items-end gap-2 rounded-[var(--radius-xl)] border border-white/4 bg-[var(--bg-card)] px-3 py-3 transition-colors focus-within:border-[var(--border-accent)]", children: [
431
- onAttach && /* @__PURE__ */ jsxs5(Fragment2, { children: [
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
+ ] }),
432
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(
433
485
  "button",
434
486
  {
435
487
  type: "button",
436
- onClick: handleAttachClick,
437
- disabled: isStreaming,
438
- "aria-label": "Attach files",
439
- className: "mb-0.5 shrink-0 rounded-[var(--radius-md)] p-2 text-[var(--text-muted)] transition-colors 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",
440
- 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" })
441
492
  }
442
- ),
443
- /* @__PURE__ */ jsx6(
444
- "input",
493
+ ) : /* @__PURE__ */ jsx6(
494
+ "button",
445
495
  {
446
- ref: fileInputRef,
447
- type: "file",
448
- multiple: true,
449
- className: "hidden",
450
- onChange: handleFileChange,
451
- accept: ".pdf,.csv,.xlsx,.xls,.jpg,.jpeg,.png,.gif,.txt,.json,.yaml,.yml"
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" })
452
502
  }
453
503
  )
454
- ] }),
455
- /* @__PURE__ */ jsx6(
456
- "textarea",
457
- {
458
- ref: textareaRef,
459
- value,
460
- onChange: handleChange,
461
- onKeyDown: handleKeyDown,
462
- placeholder,
463
- disabled: isStreaming || disabled,
464
- rows: 1,
465
- "aria-label": "Message input",
466
- 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"
467
- }
468
- ),
469
- isStreaming ? /* @__PURE__ */ jsx6(
470
- "button",
471
- {
472
- type: "button",
473
- onClick: onCancel,
474
- "aria-label": "Stop response",
475
- 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",
476
- children: /* @__PURE__ */ jsx6(Square, { className: "h-4 w-4" })
477
- }
478
- ) : /* @__PURE__ */ jsx6(
479
- "button",
480
- {
481
- type: "button",
482
- onClick: handleSend,
483
- disabled: !value.trim() || disabled,
484
- "aria-label": "Send message",
485
- 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",
486
- children: /* @__PURE__ */ jsx6(Send, { className: "h-4 w-4" })
487
- }
488
- )
504
+ ] })
489
505
  ] }) }),
490
506
  /* @__PURE__ */ jsxs5("div", { className: "mt-2 flex items-center justify-between px-1", children: [
491
507
  /* @__PURE__ */ jsx6("div", { className: "flex items-center gap-2", children: modelLabel && /* @__PURE__ */ jsxs5(
@@ -494,7 +510,7 @@ function ChatInput({
494
510
  type: "button",
495
511
  onClick: onModelClick,
496
512
  "aria-label": `Select model, current model ${modelLabel}`,
497
- className: "inline-flex items-center gap-1 rounded-[var(--radius-full)] border border-[var(--border-subtle)] bg-[var(--bg-section)]/55 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",
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",
498
514
  children: [
499
515
  /* @__PURE__ */ jsx6("span", { className: "w-1.5 h-1.5 rounded-full bg-[var(--code-success)]" }),
500
516
  modelLabel
@@ -762,7 +778,10 @@ var ChatContainer = memo3(
762
778
  onAttach,
763
779
  disabled = false,
764
780
  onOpenUIAction,
765
- enableOpenUI = true
781
+ enableOpenUI = true,
782
+ renderRunActions,
783
+ renderUserMessageActions,
784
+ renderToolActions
766
785
  }) => {
767
786
  const scrollRef = useRef2(null);
768
787
  const groups = useRunGroups({ messages, partMap, isStreaming });
@@ -800,7 +819,10 @@ var ChatContainer = memo3(
800
819
  isCollapsed,
801
820
  onToggleCollapse: toggleCollapse,
802
821
  branding,
803
- renderToolDetail
822
+ renderToolDetail,
823
+ renderRunActions,
824
+ renderUserMessageActions,
825
+ renderToolActions
804
826
  }
805
827
  ) })
806
828
  }