@tangle-network/sandbox-ui 0.13.0 → 0.15.1
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/auth.d.ts +1 -74
- package/dist/auth.js +1 -4
- package/dist/chat.d.ts +1 -136
- package/dist/chat.js +2 -15
- package/dist/chunk-2BUPSB7O.js +0 -0
- package/dist/chunk-3J6FG3FJ.js +18 -0
- package/dist/chunk-76IQLPW2.js +206 -0
- package/dist/chunk-7ZA5SEK3.js +239 -0
- package/dist/{chunk-ESVYBDGA.js → chunk-AG7QDC2Q.js} +182 -2
- package/dist/chunk-AHBZCBDO.js +2960 -0
- package/dist/chunk-AZ3AWMTM.js +8 -0
- package/dist/chunk-CMY7W45U.js +380 -0
- package/dist/{chunk-QMU2PWOU.js → chunk-DNZ4DTNA.js} +71 -17
- package/dist/chunk-EI44GEQ5.js +6 -0
- package/dist/{chunk-5OQ27N57.js → chunk-GPT7VKK6.js} +34 -38
- package/dist/chunk-JBGKGLD7.js +16 -0
- package/dist/chunk-NJNME4J4.js +14 -0
- package/dist/chunk-QPAJR74X.js +20 -0
- package/dist/chunk-TK46XFLM.js +28 -0
- package/dist/chunk-WID73FPH.js +89 -0
- package/dist/chunk-YVXK4XRO.js +30 -0
- package/dist/dashboard.d.ts +538 -4
- package/dist/dashboard.js +15 -886
- package/dist/editor.d.ts +1 -120
- package/dist/editor.js +1 -5
- package/dist/files.d.ts +1 -129
- package/dist/files.js +2 -7
- package/dist/globals.css +5 -1265
- package/dist/hooks.d.ts +114 -11
- package/dist/hooks.js +17 -88
- package/dist/index.d.ts +24 -99
- package/dist/index.js +247 -252
- package/dist/markdown.d.ts +1 -29
- package/dist/markdown.js +2 -2
- package/dist/openui.d.ts +8 -115
- package/dist/openui.js +1 -6
- package/dist/pages.d.ts +1 -2
- package/dist/pages.js +68 -66
- package/dist/primitives.d.ts +14 -49
- package/dist/primitives.js +69 -77
- package/dist/run.d.ts +1 -14
- package/dist/run.js +2 -22
- package/dist/sdk-hooks.d.ts +3 -283
- package/dist/sdk-hooks.js +10 -14
- package/dist/stores.d.ts +2 -14
- package/dist/stores.js +11 -39
- package/dist/styles.css +5 -1265
- package/dist/{usage-chart-CPTcNlGs.d.ts → template-card-UhV3pmRC.d.ts} +16 -1
- package/dist/terminal.js +39 -2
- package/dist/types.d.ts +11 -8
- package/dist/types.js +1 -0
- package/dist/utils.d.ts +1 -44
- package/dist/utils.js +6 -12
- package/dist/workspace.d.ts +5 -10
- package/dist/workspace.js +3 -19
- package/package.json +23 -54
- package/dist/active-sessions-store-CeOmXgv5.d.ts +0 -85
- package/dist/artifact-pane-Bh45Ssco.d.ts +0 -24
- package/dist/branding-DCi5VEik.d.ts +0 -13
- package/dist/button-CMQuQEW_.d.ts +0 -17
- package/dist/chat-container-f4yEs6KN.d.ts +0 -106
- package/dist/chunk-34A66VBG.js +0 -214
- package/dist/chunk-34I7UFSX.js +0 -92
- package/dist/chunk-36QY2W5G.js +0 -802
- package/dist/chunk-4CLN43XT.js +0 -45
- package/dist/chunk-54SQQMMM.js +0 -156
- package/dist/chunk-66EZOYZR.js +0 -102
- package/dist/chunk-BX6AQMUS.js +0 -183
- package/dist/chunk-DI3NZ5ZX.js +0 -192
- package/dist/chunk-DPGIXDAI.js +0 -220
- package/dist/chunk-DXMIEK4K.js +0 -1426
- package/dist/chunk-GSZA3TSY.js +0 -79
- package/dist/chunk-HB5Y37YU.js +0 -54
- package/dist/chunk-LQNEZDRM.js +0 -109
- package/dist/chunk-MA7YKRUP.js +0 -131
- package/dist/chunk-MKTSMWVD.js +0 -109
- package/dist/chunk-MQXABZTB.js +0 -1348
- package/dist/chunk-MT5FJ3ZT.js +0 -186
- package/dist/chunk-NKUPJC34.js +0 -2070
- package/dist/chunk-OEX7NZE3.js +0 -321
- package/dist/chunk-OKLQVY3Y.js +0 -139
- package/dist/chunk-Q56BYXQF.js +0 -61
- package/dist/chunk-QD4QE5P5.js +0 -40
- package/dist/chunk-QDH5GEGY.js +0 -630
- package/dist/chunk-QID2OOMG.js +0 -133
- package/dist/chunk-RQHJBTEU.js +0 -10
- package/dist/chunk-T7HMZEVO.js +0 -216
- package/dist/chunk-U6QTHMY6.js +0 -1290
- package/dist/chunk-US6JKJKH.js +0 -124
- package/dist/chunk-VX3XOUEB.js +0 -63
- package/dist/chunk-XLG757B6.js +0 -933
- package/dist/chunk-ZMNSRDMH.js +0 -127
- package/dist/chunk-ZNCEM5CD.js +0 -316
- package/dist/document-editor-pane-A70-EhdQ.d.ts +0 -124
- package/dist/document-editor-pane-TLPVRBBU.js +0 -11
- package/dist/expanded-tool-detail-Dh99mcbY.d.ts +0 -63
- package/dist/file-tabs-BLfxfmAH.d.ts +0 -51
- package/dist/parts-CyGkM6Fp.d.ts +0 -50
- package/dist/run-CtFZ6s-D.d.ts +0 -41
- package/dist/sidebar-drop-zone-tDBsuOH5.d.ts +0 -301
- package/dist/sidecar-CFU2W9j1.d.ts +0 -8
- package/dist/template-card-BAtvcAkU.d.ts +0 -18
- package/dist/tool-call-feed-Bs3MyQMT.d.ts +0 -68
- package/dist/tool-display-Ct9nFAzJ.d.ts +0 -32
- package/dist/use-sandbox-metrics-B64diPqN.d.ts +0 -141
- package/dist/variant-list-BrHYcBCk.d.ts +0 -540
package/dist/auth.d.ts
CHANGED
|
@@ -1,74 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import * as React from 'react';
|
|
3
|
-
import { a as ButtonProps } from './button-CMQuQEW_.js';
|
|
4
|
-
import 'class-variance-authority/types';
|
|
5
|
-
|
|
6
|
-
interface SessionUser {
|
|
7
|
-
customer_id: string;
|
|
8
|
-
email: string;
|
|
9
|
-
name?: string;
|
|
10
|
-
tier?: string;
|
|
11
|
-
github?: {
|
|
12
|
-
login: string;
|
|
13
|
-
connected: boolean;
|
|
14
|
-
} | null;
|
|
15
|
-
session_expires_at: string;
|
|
16
|
-
}
|
|
17
|
-
interface GitHubLoginButtonProps extends Omit<ButtonProps, "onClick"> {
|
|
18
|
-
/** API base URL (defaults to /auth/github) */
|
|
19
|
-
authUrl?: string;
|
|
20
|
-
/** Product variant for styling */
|
|
21
|
-
variant?: "sandbox" | "default" | "outline";
|
|
22
|
-
}
|
|
23
|
-
declare function GitHubLoginButton({ authUrl, variant, className, children, ...props }: GitHubLoginButtonProps): react_jsx_runtime.JSX.Element;
|
|
24
|
-
interface UserMenuProps {
|
|
25
|
-
user: SessionUser;
|
|
26
|
-
/** API base URL for logout */
|
|
27
|
-
logoutUrl?: string;
|
|
28
|
-
/** Links to show in menu */
|
|
29
|
-
links?: Array<{
|
|
30
|
-
href: string;
|
|
31
|
-
label: string;
|
|
32
|
-
icon?: React.ReactNode;
|
|
33
|
-
}>;
|
|
34
|
-
/** Product variant for styling */
|
|
35
|
-
variant?: "sandbox";
|
|
36
|
-
/** Callback when logout is clicked */
|
|
37
|
-
onLogout?: () => void;
|
|
38
|
-
}
|
|
39
|
-
declare function UserMenu({ user, logoutUrl, links, variant, onLogout, }: UserMenuProps): react_jsx_runtime.JSX.Element;
|
|
40
|
-
interface AuthHeaderProps {
|
|
41
|
-
/** Current session user (null if not logged in) */
|
|
42
|
-
user: SessionUser | null;
|
|
43
|
-
/** Whether session is loading */
|
|
44
|
-
loading?: boolean;
|
|
45
|
-
/** Product variant */
|
|
46
|
-
variant?: "sandbox";
|
|
47
|
-
/** API base URL */
|
|
48
|
-
apiBaseUrl?: string;
|
|
49
|
-
/** Links for user menu */
|
|
50
|
-
menuLinks?: UserMenuProps["links"];
|
|
51
|
-
/** Custom className */
|
|
52
|
-
className?: string;
|
|
53
|
-
}
|
|
54
|
-
declare function AuthHeader({ user, loading, variant, apiBaseUrl, menuLinks, className, }: AuthHeaderProps): react_jsx_runtime.JSX.Element;
|
|
55
|
-
|
|
56
|
-
interface LoginLayoutProps {
|
|
57
|
-
title?: React.ReactNode;
|
|
58
|
-
subtitle?: React.ReactNode;
|
|
59
|
-
brandIcon?: React.ReactNode;
|
|
60
|
-
children: React.ReactNode;
|
|
61
|
-
className?: string;
|
|
62
|
-
/** (Deprecated) terminal lines from legacy layout, kept for backwards compatibility */
|
|
63
|
-
terminalLines?: string[];
|
|
64
|
-
/** (Deprecated) tagline, kept for backwards compatibility */
|
|
65
|
-
tagline?: React.ReactNode;
|
|
66
|
-
/** (Deprecated) footerLinks, kept for backwards compatibility */
|
|
67
|
-
footerLinks?: {
|
|
68
|
-
label: string;
|
|
69
|
-
href: string;
|
|
70
|
-
}[];
|
|
71
|
-
}
|
|
72
|
-
declare function LoginLayout({ title, subtitle, brandIcon, children, className, }: LoginLayoutProps): react_jsx_runtime.JSX.Element;
|
|
73
|
-
|
|
74
|
-
export { AuthHeader, type AuthHeaderProps, GitHubLoginButton, type GitHubLoginButtonProps, LoginLayout, type LoginLayoutProps, type SessionUser, UserMenu, type UserMenuProps };
|
|
1
|
+
export { AuthHeader, AuthHeaderProps, GitHubLoginButton, GitHubLoginButtonProps, LoginLayout, LoginLayoutProps, SessionUser, UserMenu, UserMenuProps } from '@tangle-network/ui/auth';
|
package/dist/auth.js
CHANGED
|
@@ -3,10 +3,7 @@ import {
|
|
|
3
3
|
GitHubLoginButton,
|
|
4
4
|
LoginLayout,
|
|
5
5
|
UserMenu
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-34A66VBG.js";
|
|
8
|
-
import "./chunk-MKTSMWVD.js";
|
|
9
|
-
import "./chunk-RQHJBTEU.js";
|
|
6
|
+
} from "./chunk-NJNME4J4.js";
|
|
10
7
|
export {
|
|
11
8
|
AuthHeader,
|
|
12
9
|
GitHubLoginButton,
|
package/dist/chat.d.ts
CHANGED
|
@@ -1,136 +1 @@
|
|
|
1
|
-
export {
|
|
2
|
-
import * as React from 'react';
|
|
3
|
-
import { ReactNode } from 'react';
|
|
4
|
-
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
5
|
-
import { G as GroupedMessage } from './run-CtFZ6s-D.js';
|
|
6
|
-
import { a as SessionPart, S as SessionMessage, b as ToolPart } from './parts-CyGkM6Fp.js';
|
|
7
|
-
import { A as AgentBranding } from './branding-DCi5VEik.js';
|
|
8
|
-
import { C as CustomToolRenderer } from './tool-display-Ct9nFAzJ.js';
|
|
9
|
-
import { T as ToolCallData } from './tool-call-feed-Bs3MyQMT.js';
|
|
10
|
-
import './openui.js';
|
|
11
|
-
|
|
12
|
-
type MessageRole = "user" | "assistant" | "system";
|
|
13
|
-
interface ChatMessageProps {
|
|
14
|
-
role: MessageRole;
|
|
15
|
-
content: string;
|
|
16
|
-
/** Inline tool call activity rendered between text chunks */
|
|
17
|
-
toolCalls?: ReactNode;
|
|
18
|
-
/** Whether the message is still streaming */
|
|
19
|
-
isStreaming?: boolean;
|
|
20
|
-
/** Timestamp */
|
|
21
|
-
timestamp?: Date;
|
|
22
|
-
className?: string;
|
|
23
|
-
/** Custom user label. Default: "You" */
|
|
24
|
-
userLabel?: string;
|
|
25
|
-
/** Custom assistant label. Default: "Agent" */
|
|
26
|
-
assistantLabel?: string;
|
|
27
|
-
/** Hide the role label row entirely */
|
|
28
|
-
hideRoleLabel?: boolean;
|
|
29
|
-
/** Hide the avatar icon */
|
|
30
|
-
hideAvatar?: boolean;
|
|
31
|
-
/** Custom avatar element (replaces default User/Bot icon) */
|
|
32
|
-
avatar?: ReactNode;
|
|
33
|
-
}
|
|
34
|
-
declare function ChatMessage({ role, content, toolCalls, isStreaming, timestamp, className, userLabel, assistantLabel, hideRoleLabel, hideAvatar, avatar, }: ChatMessageProps): react_jsx_runtime.JSX.Element;
|
|
35
|
-
|
|
36
|
-
interface MessageListProps {
|
|
37
|
-
groups: GroupedMessage[];
|
|
38
|
-
partMap: Record<string, SessionPart[]>;
|
|
39
|
-
isCollapsed: (runId: string) => boolean;
|
|
40
|
-
onToggleCollapse: (runId: string) => void;
|
|
41
|
-
branding?: AgentBranding;
|
|
42
|
-
renderToolDetail?: CustomToolRenderer;
|
|
43
|
-
renderRunActions?: (group: Extract<GroupedMessage, {
|
|
44
|
-
type: "run";
|
|
45
|
-
}>["run"]) => ReactNode;
|
|
46
|
-
renderUserMessageActions?: (message: SessionMessage, parts: SessionPart[]) => ReactNode;
|
|
47
|
-
renderToolActions?: (part: ToolPart, options: {
|
|
48
|
-
run: Extract<GroupedMessage, {
|
|
49
|
-
type: "run";
|
|
50
|
-
}>["run"];
|
|
51
|
-
messageId: string;
|
|
52
|
-
partIndex: number;
|
|
53
|
-
}) => ReactNode;
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Maps GroupedMessage[] to UserMessage and RunGroup components.
|
|
57
|
-
* This is the main render list for the chat view.
|
|
58
|
-
*/
|
|
59
|
-
declare const MessageList: React.MemoExoticComponent<({ groups, partMap, isCollapsed, onToggleCollapse, branding, renderToolDetail, renderRunActions, renderUserMessageActions, renderToolActions, }: MessageListProps) => react_jsx_runtime.JSX.Element>;
|
|
60
|
-
|
|
61
|
-
interface UserMessageProps {
|
|
62
|
-
message: SessionMessage;
|
|
63
|
-
parts: SessionPart[];
|
|
64
|
-
actions?: ReactNode;
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Simple user message bubble.
|
|
68
|
-
* Renders text parts from the user's message.
|
|
69
|
-
*/
|
|
70
|
-
declare const UserMessage: React.MemoExoticComponent<({ message, parts, actions }: UserMessageProps) => react_jsx_runtime.JSX.Element | null>;
|
|
71
|
-
|
|
72
|
-
interface ThinkingIndicatorProps {
|
|
73
|
-
className?: string;
|
|
74
|
-
}
|
|
75
|
-
declare function ThinkingIndicator({ className }: ThinkingIndicatorProps): react_jsx_runtime.JSX.Element;
|
|
76
|
-
|
|
77
|
-
type AgentTimelineTone = "default" | "info" | "success" | "warning" | "error";
|
|
78
|
-
interface AgentTimelineMessageItem {
|
|
79
|
-
id: string;
|
|
80
|
-
kind: "message";
|
|
81
|
-
role: MessageRole;
|
|
82
|
-
content: string;
|
|
83
|
-
toolCalls?: ReactNode;
|
|
84
|
-
isStreaming?: boolean;
|
|
85
|
-
timestamp?: Date;
|
|
86
|
-
after?: ReactNode;
|
|
87
|
-
}
|
|
88
|
-
interface AgentTimelineToolItem {
|
|
89
|
-
id: string;
|
|
90
|
-
kind: "tool";
|
|
91
|
-
call: ToolCallData;
|
|
92
|
-
}
|
|
93
|
-
interface AgentTimelineToolGroupItem {
|
|
94
|
-
id: string;
|
|
95
|
-
kind: "tool_group";
|
|
96
|
-
title?: string;
|
|
97
|
-
calls: ToolCallData[];
|
|
98
|
-
}
|
|
99
|
-
interface AgentTimelineStatusItem {
|
|
100
|
-
id: string;
|
|
101
|
-
kind: "status";
|
|
102
|
-
label: string;
|
|
103
|
-
detail?: string;
|
|
104
|
-
tone?: AgentTimelineTone;
|
|
105
|
-
}
|
|
106
|
-
interface AgentTimelineArtifactItem {
|
|
107
|
-
id: string;
|
|
108
|
-
kind: "artifact";
|
|
109
|
-
title: string;
|
|
110
|
-
description?: string;
|
|
111
|
-
meta?: ReactNode;
|
|
112
|
-
icon?: ReactNode;
|
|
113
|
-
tone?: AgentTimelineTone;
|
|
114
|
-
action?: ReactNode;
|
|
115
|
-
onClick?: () => void;
|
|
116
|
-
}
|
|
117
|
-
interface AgentTimelineCustomItem {
|
|
118
|
-
id: string;
|
|
119
|
-
kind: "custom";
|
|
120
|
-
content: ReactNode;
|
|
121
|
-
}
|
|
122
|
-
type AgentTimelineItem = AgentTimelineMessageItem | AgentTimelineToolItem | AgentTimelineToolGroupItem | AgentTimelineStatusItem | AgentTimelineArtifactItem | AgentTimelineCustomItem;
|
|
123
|
-
interface AgentTimelineProps {
|
|
124
|
-
items: AgentTimelineItem[];
|
|
125
|
-
isThinking?: boolean;
|
|
126
|
-
emptyState?: ReactNode;
|
|
127
|
-
className?: string;
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* AgentTimeline — unified mixed-content timeline for agent-backed sandbox
|
|
131
|
-
* sessions. Renders messages, tool steps, status cards, and artifact handoffs in
|
|
132
|
-
* a single execution narrative.
|
|
133
|
-
*/
|
|
134
|
-
declare function AgentTimeline({ items, isThinking, emptyState, className, }: AgentTimelineProps): react_jsx_runtime.JSX.Element | null;
|
|
135
|
-
|
|
136
|
-
export { AgentTimeline, type AgentTimelineArtifactItem, type AgentTimelineCustomItem, type AgentTimelineItem, type AgentTimelineMessageItem, type AgentTimelineProps, type AgentTimelineStatusItem, type AgentTimelineTone, type AgentTimelineToolGroupItem, type AgentTimelineToolItem, ChatMessage, type ChatMessageProps, MessageList, type MessageListProps, type MessageRole, ThinkingIndicator, type ThinkingIndicatorProps, UserMessage, type UserMessageProps };
|
|
1
|
+
export { AgentTimeline, AgentTimelineArtifactItem, AgentTimelineCustomItem, AgentTimelineItem, AgentTimelineMessageItem, AgentTimelineProps, AgentTimelineStatusItem, AgentTimelineTone, AgentTimelineToolGroupItem, AgentTimelineToolItem, ChatContainer, ChatContainerProps, ChatInput, ChatInputProps, ChatMessage, ChatMessageProps, MessageList, MessageListProps, MessageRole, PendingFile, ThinkingIndicator, ThinkingIndicatorProps, UserMessage, UserMessageProps } from '@tangle-network/ui/chat';
|
package/dist/chat.js
CHANGED
|
@@ -1,25 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ChatMessage
|
|
3
|
-
} from "./chunk-GSZA3TSY.js";
|
|
4
1
|
import {
|
|
5
2
|
AgentTimeline,
|
|
6
3
|
ChatContainer,
|
|
7
4
|
ChatInput,
|
|
5
|
+
ChatMessage,
|
|
8
6
|
MessageList,
|
|
9
7
|
ThinkingIndicator,
|
|
10
8
|
UserMessage
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
import "./chunk-54SQQMMM.js";
|
|
13
|
-
import "./chunk-MQXABZTB.js";
|
|
14
|
-
import "./chunk-4CLN43XT.js";
|
|
15
|
-
import "./chunk-MT5FJ3ZT.js";
|
|
16
|
-
import "./chunk-BX6AQMUS.js";
|
|
17
|
-
import "./chunk-ZNCEM5CD.js";
|
|
18
|
-
import "./chunk-34I7UFSX.js";
|
|
19
|
-
import "./chunk-T7HMZEVO.js";
|
|
20
|
-
import "./chunk-ZMNSRDMH.js";
|
|
21
|
-
import "./chunk-MKTSMWVD.js";
|
|
22
|
-
import "./chunk-RQHJBTEU.js";
|
|
9
|
+
} from "./chunk-QPAJR74X.js";
|
|
23
10
|
export {
|
|
24
11
|
AgentTimeline,
|
|
25
12
|
ChatContainer,
|
|
File without changes
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// src/files/index.ts
|
|
2
|
+
import {
|
|
3
|
+
FileArtifactPane,
|
|
4
|
+
FilePreview,
|
|
5
|
+
FileTabs,
|
|
6
|
+
FileTree,
|
|
7
|
+
RichFileTree,
|
|
8
|
+
filterFileTree
|
|
9
|
+
} from "@tangle-network/ui/files";
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
FileArtifactPane,
|
|
13
|
+
FilePreview,
|
|
14
|
+
FileTabs,
|
|
15
|
+
FileTree,
|
|
16
|
+
RichFileTree,
|
|
17
|
+
filterFileTree
|
|
18
|
+
};
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
// src/hooks/index.ts
|
|
2
|
+
import {
|
|
3
|
+
RealtimeSessionRegistry,
|
|
4
|
+
createAuthFetcher,
|
|
5
|
+
useApiKey,
|
|
6
|
+
useAuth,
|
|
7
|
+
useAutoScroll,
|
|
8
|
+
useDropdownMenu,
|
|
9
|
+
useLiveTime,
|
|
10
|
+
useRealtimeSession,
|
|
11
|
+
useRunCollapseState,
|
|
12
|
+
useRunGroups,
|
|
13
|
+
useSSEStream,
|
|
14
|
+
useSdkSession,
|
|
15
|
+
useToolCallStream
|
|
16
|
+
} from "@tangle-network/ui/hooks";
|
|
17
|
+
|
|
18
|
+
// src/hooks/use-sandbox-metrics.ts
|
|
19
|
+
import * as React from "react";
|
|
20
|
+
function useSandboxMetrics({
|
|
21
|
+
apiBaseUrl,
|
|
22
|
+
sandboxId,
|
|
23
|
+
token,
|
|
24
|
+
enabled = true,
|
|
25
|
+
intervalMs = 3e3
|
|
26
|
+
}) {
|
|
27
|
+
const [metrics, setMetrics] = React.useState(null);
|
|
28
|
+
const [loading, setLoading] = React.useState(false);
|
|
29
|
+
const [error, setError] = React.useState(null);
|
|
30
|
+
const [lastUpdatedAt, setLastUpdatedAt] = React.useState(null);
|
|
31
|
+
const sampleRef = React.useRef(null);
|
|
32
|
+
const hasLoadedRef = React.useRef(false);
|
|
33
|
+
const prevSandboxIdRef = React.useRef(null);
|
|
34
|
+
React.useEffect(() => {
|
|
35
|
+
const sandboxCleared = !sandboxId || !apiBaseUrl;
|
|
36
|
+
const sandboxChanged = prevSandboxIdRef.current !== null && prevSandboxIdRef.current !== sandboxId;
|
|
37
|
+
if (sandboxCleared && prevSandboxIdRef.current !== null || sandboxChanged) {
|
|
38
|
+
sampleRef.current = null;
|
|
39
|
+
hasLoadedRef.current = false;
|
|
40
|
+
setMetrics(null);
|
|
41
|
+
setLastUpdatedAt(null);
|
|
42
|
+
setError(null);
|
|
43
|
+
if (sandboxCleared) setLoading(false);
|
|
44
|
+
}
|
|
45
|
+
prevSandboxIdRef.current = sandboxId ?? null;
|
|
46
|
+
if (!enabled || sandboxCleared) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const controller = new AbortController();
|
|
50
|
+
let cancelled = false;
|
|
51
|
+
let timeoutId = null;
|
|
52
|
+
const delay = Math.max(intervalMs, 500);
|
|
53
|
+
const fetchOnce = async () => {
|
|
54
|
+
if (!hasLoadedRef.current) setLoading(true);
|
|
55
|
+
try {
|
|
56
|
+
const headers = {};
|
|
57
|
+
if (token) headers.Authorization = `Bearer ${token}`;
|
|
58
|
+
const res = await fetch(
|
|
59
|
+
`${apiBaseUrl}/v1/sidecar-proxy/${encodeURIComponent(sandboxId)}/metrics/json`,
|
|
60
|
+
{
|
|
61
|
+
method: "GET",
|
|
62
|
+
credentials: "include",
|
|
63
|
+
headers,
|
|
64
|
+
signal: controller.signal
|
|
65
|
+
}
|
|
66
|
+
);
|
|
67
|
+
if (!res.ok) {
|
|
68
|
+
throw new Error(`Metrics request failed (HTTP ${res.status})`);
|
|
69
|
+
}
|
|
70
|
+
const data = await res.json();
|
|
71
|
+
const user = data?.process?.cpuSeconds?.user ?? 0;
|
|
72
|
+
const system = data?.process?.cpuSeconds?.system ?? 0;
|
|
73
|
+
const cpuSeconds = user + system;
|
|
74
|
+
const wallMs = Date.now();
|
|
75
|
+
if (cancelled) return;
|
|
76
|
+
let cpuPercent = null;
|
|
77
|
+
const prev = sampleRef.current;
|
|
78
|
+
if (prev && prev.sandboxId === sandboxId) {
|
|
79
|
+
const dCpu = cpuSeconds - prev.cpuSeconds;
|
|
80
|
+
const dWallSec = (wallMs - prev.wallMs) / 1e3;
|
|
81
|
+
if (dWallSec > 0 && dCpu >= 0) {
|
|
82
|
+
cpuPercent = dCpu / dWallSec * 100;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
sampleRef.current = { cpuSeconds, wallMs, sandboxId };
|
|
86
|
+
setMetrics({
|
|
87
|
+
cpuPercent,
|
|
88
|
+
rssBytes: data?.process?.memoryBytes?.rss ?? 0,
|
|
89
|
+
heapUsedBytes: data?.process?.memoryBytes?.heapUsed ?? 0,
|
|
90
|
+
heapTotalBytes: data?.process?.memoryBytes?.heapTotal ?? 0
|
|
91
|
+
});
|
|
92
|
+
setLastUpdatedAt(wallMs);
|
|
93
|
+
setError(null);
|
|
94
|
+
hasLoadedRef.current = true;
|
|
95
|
+
setLoading(false);
|
|
96
|
+
} catch (err) {
|
|
97
|
+
if (cancelled || err instanceof DOMException && err.name === "AbortError") {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
101
|
+
if (!hasLoadedRef.current) setLoading(false);
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
const runLoop = async () => {
|
|
105
|
+
if (cancelled) return;
|
|
106
|
+
await fetchOnce();
|
|
107
|
+
if (cancelled) return;
|
|
108
|
+
timeoutId = window.setTimeout(runLoop, delay);
|
|
109
|
+
};
|
|
110
|
+
runLoop();
|
|
111
|
+
return () => {
|
|
112
|
+
cancelled = true;
|
|
113
|
+
controller.abort();
|
|
114
|
+
if (timeoutId !== null) window.clearTimeout(timeoutId);
|
|
115
|
+
};
|
|
116
|
+
}, [apiBaseUrl, sandboxId, token, enabled, intervalMs]);
|
|
117
|
+
return { metrics, loading, error, lastUpdatedAt };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// src/hooks/use-session-crud.ts
|
|
121
|
+
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
|
122
|
+
async function sessionFetch(apiUrl, token, path, opts) {
|
|
123
|
+
const res = await fetch(`${apiUrl}${path}`, {
|
|
124
|
+
...opts,
|
|
125
|
+
headers: {
|
|
126
|
+
"Content-Type": "application/json",
|
|
127
|
+
Authorization: `Bearer ${token}`,
|
|
128
|
+
...opts?.headers ?? {}
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
if (!res.ok) {
|
|
132
|
+
const text = await res.text();
|
|
133
|
+
throw new Error(text || `API error: ${res.status}`);
|
|
134
|
+
}
|
|
135
|
+
return res.json();
|
|
136
|
+
}
|
|
137
|
+
function useSessions(apiUrl, token) {
|
|
138
|
+
return useQuery({
|
|
139
|
+
queryKey: ["sessions", apiUrl, token],
|
|
140
|
+
queryFn: () => sessionFetch(apiUrl, token, "/session/sessions"),
|
|
141
|
+
enabled: !!token,
|
|
142
|
+
staleTime: 3e4
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
function useCreateSession(apiUrl, token) {
|
|
146
|
+
const queryClient = useQueryClient();
|
|
147
|
+
return useMutation({
|
|
148
|
+
mutationFn: async (title) => {
|
|
149
|
+
return sessionFetch(apiUrl, token, "/session/sessions", {
|
|
150
|
+
method: "POST",
|
|
151
|
+
body: JSON.stringify({ title, backend: { type: "opencode" } })
|
|
152
|
+
});
|
|
153
|
+
},
|
|
154
|
+
onSuccess: () => {
|
|
155
|
+
queryClient.invalidateQueries({ queryKey: ["sessions", apiUrl, token] });
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
function useDeleteSession(apiUrl, token) {
|
|
160
|
+
const queryClient = useQueryClient();
|
|
161
|
+
return useMutation({
|
|
162
|
+
mutationFn: async (sessionId) => {
|
|
163
|
+
return sessionFetch(apiUrl, token, `/session/sessions/${encodeURIComponent(sessionId)}`, {
|
|
164
|
+
method: "DELETE"
|
|
165
|
+
});
|
|
166
|
+
},
|
|
167
|
+
onSuccess: () => {
|
|
168
|
+
queryClient.invalidateQueries({ queryKey: ["sessions", apiUrl, token] });
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
function useRenameSession(apiUrl, token) {
|
|
173
|
+
const queryClient = useQueryClient();
|
|
174
|
+
return useMutation({
|
|
175
|
+
mutationFn: async ({ sessionId, title }) => {
|
|
176
|
+
return sessionFetch(apiUrl, token, `/session/sessions/${encodeURIComponent(sessionId)}`, {
|
|
177
|
+
method: "PATCH",
|
|
178
|
+
body: JSON.stringify({ title })
|
|
179
|
+
});
|
|
180
|
+
},
|
|
181
|
+
onSuccess: () => {
|
|
182
|
+
queryClient.invalidateQueries({ queryKey: ["sessions", apiUrl, token] });
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export {
|
|
188
|
+
useSandboxMetrics,
|
|
189
|
+
useSessions,
|
|
190
|
+
useCreateSession,
|
|
191
|
+
useDeleteSession,
|
|
192
|
+
useRenameSession,
|
|
193
|
+
RealtimeSessionRegistry,
|
|
194
|
+
createAuthFetcher,
|
|
195
|
+
useApiKey,
|
|
196
|
+
useAuth,
|
|
197
|
+
useAutoScroll,
|
|
198
|
+
useDropdownMenu,
|
|
199
|
+
useLiveTime,
|
|
200
|
+
useRealtimeSession,
|
|
201
|
+
useRunCollapseState,
|
|
202
|
+
useRunGroups,
|
|
203
|
+
useSSEStream,
|
|
204
|
+
useSdkSession,
|
|
205
|
+
useToolCallStream
|
|
206
|
+
};
|