@mcp-b/react-components 0.10.0 → 0.12.0
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/{AgentChat-B9LD_WF1.d.ts → AgentChat-CRmsKg9B.d.ts} +10 -6
- package/dist/{BrowserLiveView-ZktFZiMD.d.ts → BrowserLiveView-BV5qgFgI.d.ts} +11 -10
- package/dist/{BrowserReplay-6G-mnwcn.d.ts → BrowserReplay-xWvRjRAC.d.ts} +2 -1
- package/dist/{Menu-B5vDqZe_.d.ts → Menu-BLhnNnRK.d.ts} +3 -0
- package/dist/{ModelSelector-DXtpcRmT.js → ModelSelector-BB-xB-Es.js} +16 -13
- package/dist/{PromptInput-D6-G24p7.d.ts → PromptInput-IyM6ZETj.d.ts} +13 -45
- package/dist/ThinkChat-B3wYahor.js +190 -0
- package/dist/{ThinkChatActivity-B2UD95My.d.ts → ThinkChatActivity-F4KFPcJA.d.ts} +4 -4
- package/dist/ThinkChatContext-C3Eb1Xpi.d.ts +16 -0
- package/dist/{ThinkChatToolParts-DnUiZgCC.d.ts → ThinkChatToolParts-Cv4o7j6F.d.ts} +13 -5
- package/dist/components/AgentChat.d.ts +1 -1
- package/dist/components/AgentChat.js +57 -23
- package/dist/components/AgentConnection.d.ts +3 -14
- package/dist/components/AgentConnection.js +7 -111
- package/dist/components/Badge.js +1 -15
- package/dist/components/BrowserLiveView.d.ts +1 -1
- package/dist/components/BrowserLiveView.js +14 -10
- package/dist/components/BrowserReplay.d.ts +1 -1
- package/dist/components/BrowserRunPanel.d.ts +46 -0
- package/dist/components/BrowserRunPanel.js +159 -0
- package/dist/components/ChatGptSignInScreen.js +1 -1
- package/dist/components/CodexModelSelector.d.ts +63 -0
- package/dist/components/CodexModelSelector.js +148 -0
- package/dist/components/Commit.d.ts +2 -2
- package/dist/components/Commit.js +10 -22
- package/dist/components/Conversation.d.ts +2 -6
- package/dist/components/Conversation.js +2 -3
- package/dist/components/EnvironmentVariables.d.ts +2 -7
- package/dist/components/EnvironmentVariables.js +10 -33
- package/dist/components/Marker.js +1 -15
- package/dist/components/McpServerPicker.d.ts +31 -6
- package/dist/components/McpServerPicker.js +129 -67
- package/dist/components/Menu.d.ts +1 -1
- package/dist/components/Menu.js +2 -2
- package/dist/components/Message.d.ts +3 -2
- package/dist/components/Message.js +10 -3
- package/dist/components/ModelSelector.d.ts +11 -8
- package/dist/components/ModelSelector.js +1 -1
- package/dist/components/PromptInput.d.ts +2 -2
- package/dist/components/PromptInput.js +49 -98
- package/dist/components/Queue.d.ts +1 -12
- package/dist/components/Reasoning.js +2 -15
- package/dist/components/Stepper.js +1 -7
- package/dist/components/ThinkChat.d.ts +30 -30
- package/dist/components/ThinkChat.js +1 -152
- package/dist/components/ThinkChatActivity.d.ts +2 -2
- package/dist/components/ThinkChatActivity.js +3 -10
- package/dist/components/ThinkChatContext.d.ts +2 -2
- package/dist/components/ThinkChatContext.js +9 -2
- package/dist/components/ThinkChatToolPanels.d.ts +1 -1
- package/dist/components/ThinkChatToolPanels.js +19 -7
- package/dist/components/ThinkChatToolParts.d.ts +1 -1
- package/dist/components/ThinkExecutionWorkbench.d.ts +10 -7
- package/dist/components/ThinkExecutionWorkbench.js +382 -359
- package/dist/components/ThinkFullApp.d.ts +16 -13
- package/dist/components/ThinkFullApp.js +28 -18
- package/dist/components/ThinkThreadPicker.d.ts +1 -31
- package/dist/components/ThinkThreadPicker.js +32 -171
- package/dist/components/ThinkThreadShell.d.ts +35 -0
- package/dist/components/ThinkThreadShell.js +146 -0
- package/dist/components/WorkspaceExplorer.js +3 -1
- package/dist/merge-refs-DF_7w2x_.js +18 -0
- package/dist/styles/agent-chat.css +4 -1
- package/dist/styles/agent-connection.css +0 -166
- package/dist/styles/browser-run-panel.css +125 -0
- package/dist/styles/codex-model-selector.css +197 -0
- package/dist/styles/index.css +5 -0
- package/dist/styles/mcp-server-picker.css +62 -15
- package/dist/styles/message.css +1 -1
- package/dist/styles/model-selector.css +20 -8
- package/dist/styles/prompt-input.css +5 -0
- package/dist/styles/streamdown.css +2 -48
- package/dist/styles/think-execution-workbench.css +337 -0
- package/dist/styles/think-full-app.css +15 -390
- package/dist/styles/think-resize-handle.css +33 -0
- package/dist/styles/think-thread-picker.css +0 -238
- package/dist/styles/think-thread-shell.css +219 -0
- package/dist/styles/workspace-explorer.css +8 -2
- package/dist/summarize-tool-input-BUJsENSn.js +12 -0
- package/dist/utils/mcp-server-catalog.d.ts +2 -3
- package/package.json +2 -2
- package/dist/ThinkChatContext-BLAAb8J5.d.ts +0 -28
- package/dist/components/useStickToBottom.d.ts +0 -33
- package/dist/components/useStickToBottom.js +0 -107
|
@@ -6,10 +6,10 @@ import { MessageScroller, MessageScrollerButton, MessageScrollerContent, Message
|
|
|
6
6
|
import { ConversationEmptyState } from "./Conversation.js";
|
|
7
7
|
import { Message, MessageAction, MessageActions, MessageAttachment, MessageContent, MessageResponse } from "./Message.js";
|
|
8
8
|
import { Marker, MarkerContent } from "./Marker.js";
|
|
9
|
-
import { MenuGroup, MenuGroupLabel } from "./Menu.js";
|
|
10
9
|
import { PromptInput, PromptInputActionAddAttachments, PromptInputActionMenu, PromptInputActionMenuContent, PromptInputActionMenuTrigger, PromptInputApproval, PromptInputAttachments, PromptInputBody, PromptInputButton, PromptInputFooter, PromptInputPermissionSelector, PromptInputSubmit, PromptInputTextarea, PromptInputTools, getApprovalRequestId, getApprovalStateKey, getPendingToolApprovals, usePromptInputAttachments } from "./PromptInput.js";
|
|
11
10
|
import { Reasoning, ReasoningContent, ReasoningTrigger } from "./Reasoning.js";
|
|
12
11
|
import { Source, Sources, SourcesContent, SourcesTrigger } from "./Sources.js";
|
|
12
|
+
import { t as summarizeToolInput } from "../summarize-tool-input-BUJsENSn.js";
|
|
13
13
|
import * as React from "react";
|
|
14
14
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
15
15
|
import { isCompactionMessage } from "agents/experimental/memory/utils";
|
|
@@ -17,6 +17,17 @@ import { getToolInput, getToolOutput, getToolPartState } from "@cloudflare/think
|
|
|
17
17
|
import { getToolName, isFileUIPart, isReasoningUIPart, isTextUIPart, isToolUIPart } from "ai";
|
|
18
18
|
//#region src/components/AgentChat.tsx
|
|
19
19
|
const EMPTY_PENDING_APPROVALS = [];
|
|
20
|
+
const EMPTY_SKIPPED_APPROVAL_IDS = [];
|
|
21
|
+
function createApprovalSessionState(thinkStub) {
|
|
22
|
+
return {
|
|
23
|
+
thinkStub,
|
|
24
|
+
skippedApprovalIds: EMPTY_SKIPPED_APPROVAL_IDS,
|
|
25
|
+
permissionMode: "ask"
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function isCurrentApprovalSession(state, thinkStub) {
|
|
29
|
+
return state.thinkStub === thinkStub;
|
|
30
|
+
}
|
|
20
31
|
function AgentChatAttachButton() {
|
|
21
32
|
const attachments = usePromptInputAttachments();
|
|
22
33
|
return /* @__PURE__ */ jsx(PromptInputButton, {
|
|
@@ -33,7 +44,7 @@ function AgentChatAddMenu({ children }) {
|
|
|
33
44
|
sideOffset: 12,
|
|
34
45
|
collisionPadding: 8,
|
|
35
46
|
className: "agent-chat__add-menu",
|
|
36
|
-
children: [/* @__PURE__ */
|
|
47
|
+
children: [/* @__PURE__ */ jsx(PromptInputActionAddAttachments, {}), children]
|
|
37
48
|
})] });
|
|
38
49
|
}
|
|
39
50
|
/**
|
|
@@ -62,14 +73,6 @@ function getPartKey(part, partIndex) {
|
|
|
62
73
|
if ("id" in part && typeof part.id === "string") return `${part.type}-${part.id}`;
|
|
63
74
|
return `${part.type}-${partIndex}`;
|
|
64
75
|
}
|
|
65
|
-
function summarizeToolInput(input) {
|
|
66
|
-
if (!input || typeof input !== "object") return null;
|
|
67
|
-
for (const value of Object.values(input)) if (typeof value === "string" && value.trim()) {
|
|
68
|
-
const line = value.trim().split("\n", 1)[0] ?? "";
|
|
69
|
-
return line.length > 64 ? `${line.slice(0, 64)}…` : line;
|
|
70
|
-
}
|
|
71
|
-
return null;
|
|
72
|
-
}
|
|
73
76
|
function isToolPartWorking(part) {
|
|
74
77
|
const state = getToolPartState(part);
|
|
75
78
|
return state === "loading" || state === "streaming" || state === "waiting-approval";
|
|
@@ -188,38 +191,65 @@ function renderDefaultPart(part) {
|
|
|
188
191
|
* transport. Product code that talks to a Cloudflare Think agent should render
|
|
189
192
|
* `ThinkChat`; use this directly only for plain AI SDK or read-only messages.
|
|
190
193
|
*/
|
|
191
|
-
function AgentChat({ className, messages, status = "ready", onSubmit, onStop, placeholder = "Ask anything...", disabled, emptyState, composerTools, composerAddMenuItems, notice, onRegenerate, onApprovalResponse,
|
|
194
|
+
function AgentChat({ className, messages, status = "ready", onSubmit, onStop, placeholder = "Ask anything...", disabled, emptyState, composerTools, composerAddMenuItems, notice, onRegenerate, onApprovalResponse, thinkStub, onExecutionSettled, pendingApprovals: durableApprovals = EMPTY_PENDING_APPROVALS, contextWindow, renderPart, renderMessageAfter, ref }) {
|
|
192
195
|
const handleSubmit = React.useCallback((message) => {
|
|
193
196
|
onSubmit?.(message);
|
|
194
197
|
}, [onSubmit]);
|
|
195
|
-
const [
|
|
196
|
-
const
|
|
198
|
+
const [approvalSession, setApprovalSession] = React.useState(() => createApprovalSessionState(thinkStub));
|
|
199
|
+
const approvalSessionIsCurrent = isCurrentApprovalSession(approvalSession, thinkStub);
|
|
200
|
+
const skippedApprovalIds = approvalSessionIsCurrent ? approvalSession.skippedApprovalIds : EMPTY_SKIPPED_APPROVAL_IDS;
|
|
201
|
+
const permissionMode = approvalSessionIsCurrent ? approvalSession.permissionMode : "ask";
|
|
202
|
+
const updateApprovalSession = React.useCallback((update) => {
|
|
203
|
+
setApprovalSession((previous) => update(isCurrentApprovalSession(previous, thinkStub) ? previous : createApprovalSessionState(thinkStub)));
|
|
204
|
+
}, [thinkStub]);
|
|
205
|
+
const setPermissionMode = React.useCallback((next) => {
|
|
206
|
+
updateApprovalSession((current) => ({
|
|
207
|
+
...current,
|
|
208
|
+
permissionMode: next
|
|
209
|
+
}));
|
|
210
|
+
}, [updateApprovalSession]);
|
|
211
|
+
React.useLayoutEffect(() => {
|
|
212
|
+
setApprovalSession((previous) => isCurrentApprovalSession(previous, thinkStub) ? previous : createApprovalSessionState(thinkStub));
|
|
213
|
+
}, [thinkStub]);
|
|
214
|
+
const pendingApprovalItems = [...getPendingToolApprovals(messages, { pausedExecutions: Boolean(thinkStub) }).filter(({ part }) => {
|
|
197
215
|
if (part.state === "approval-requested" && !onApprovalResponse) return false;
|
|
198
216
|
const id = getApprovalStateKey(part);
|
|
199
217
|
return Boolean(id) && !skippedApprovalIds.includes(id);
|
|
200
|
-
}).map((approval) => ({ part: approval.part })), ...
|
|
201
|
-
const approvalsWired = Boolean(onApprovalResponse ||
|
|
202
|
-
const
|
|
203
|
-
|
|
218
|
+
}).map((approval) => ({ part: approval.part })), ...thinkStub ? durableApprovals.filter((approval) => approval.source === "action" && !skippedApprovalIds.includes(approval.executionId)).map((approval) => ({ approval })) : []];
|
|
219
|
+
const approvalsWired = Boolean(onApprovalResponse || thinkStub);
|
|
220
|
+
const autoApprovedIds = React.useRef({
|
|
221
|
+
thinkStub,
|
|
222
|
+
ids: /* @__PURE__ */ new Set()
|
|
223
|
+
});
|
|
224
|
+
React.useLayoutEffect(() => {
|
|
225
|
+
if (isCurrentApprovalSession(autoApprovedIds.current, thinkStub)) return;
|
|
226
|
+
autoApprovedIds.current = {
|
|
227
|
+
thinkStub,
|
|
228
|
+
ids: /* @__PURE__ */ new Set()
|
|
229
|
+
};
|
|
230
|
+
}, [thinkStub]);
|
|
204
231
|
React.useEffect(() => {
|
|
205
232
|
if (permissionMode !== "bypass") return;
|
|
206
233
|
for (const item of pendingApprovalItems) {
|
|
207
234
|
const id = "part" in item ? getApprovalRequestId(item.part) : item.approval.executionId;
|
|
208
235
|
const key = "part" in item ? getApprovalStateKey(item.part) : item.approval.executionId;
|
|
209
|
-
if (!id || !key || autoApprovedIds.current.has(key)) continue;
|
|
210
|
-
autoApprovedIds.current.add(key);
|
|
236
|
+
if (!id || !key || autoApprovedIds.current.ids.has(key)) continue;
|
|
237
|
+
autoApprovedIds.current.ids.add(key);
|
|
211
238
|
if ("part" in item && item.part.state === "approval-requested") onApprovalResponse?.({
|
|
212
239
|
id,
|
|
213
240
|
approved: true
|
|
214
241
|
});
|
|
215
|
-
else
|
|
242
|
+
else if (thinkStub) thinkStub.approveExecution(id).finally(() => {
|
|
243
|
+
onExecutionSettled?.();
|
|
244
|
+
});
|
|
216
245
|
}
|
|
217
246
|
}, [
|
|
218
247
|
permissionMode,
|
|
219
248
|
messages,
|
|
220
249
|
durableApprovals,
|
|
221
250
|
onApprovalResponse,
|
|
222
|
-
|
|
251
|
+
thinkStub,
|
|
252
|
+
onExecutionSettled
|
|
223
253
|
]);
|
|
224
254
|
const pendingApproval = permissionMode === "bypass" ? void 0 : pendingApprovalItems[0];
|
|
225
255
|
const contextUsage = contextWindow ? getContextUsage(messages) : void 0;
|
|
@@ -312,10 +342,14 @@ function AgentChat({ className, messages, status = "ready", onSubmit, onStop, pl
|
|
|
312
342
|
approval: "approval" in pendingApproval ? pendingApproval.approval : void 0,
|
|
313
343
|
count: pendingApprovalItems.length,
|
|
314
344
|
onRespond: onApprovalResponse,
|
|
315
|
-
|
|
345
|
+
thinkStub,
|
|
346
|
+
onExecutionSettled,
|
|
316
347
|
onSkip: () => {
|
|
317
348
|
const id = "part" in pendingApproval ? getApprovalStateKey(pendingApproval.part) : pendingApproval.approval.executionId;
|
|
318
|
-
if (id)
|
|
349
|
+
if (id) updateApprovalSession((current) => ({
|
|
350
|
+
...current,
|
|
351
|
+
skippedApprovalIds: [...current.skippedApprovalIds, id]
|
|
352
|
+
}));
|
|
319
353
|
}
|
|
320
354
|
}) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
321
355
|
/* @__PURE__ */ jsx(PromptInputAttachments, {}),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { McpServerSetupAuth } from "../utils/mcp-server-catalog.js";
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
|
|
4
4
|
//#region src/components/AgentConnection.d.ts
|
|
@@ -25,19 +25,14 @@ type NanitesAgentConnectionOptions = {
|
|
|
25
25
|
type AgentConnectionPanelProps = {
|
|
26
26
|
readonly className?: string;
|
|
27
27
|
readonly commands?: readonly AgentConnectionCommand[];
|
|
28
|
-
readonly dcrMcpServers?: readonly McpServerCard[];
|
|
29
28
|
readonly defaultTarget?: AgentConnectionTarget;
|
|
30
29
|
readonly headingLevel?: 2 | 3;
|
|
31
|
-
readonly manualMcpServers?: readonly McpServerCard[];
|
|
32
30
|
readonly origin?: string;
|
|
33
31
|
readonly section?: boolean;
|
|
34
32
|
};
|
|
35
33
|
type AgentConnectionPopoverProps = Omit<AgentConnectionPanelProps, "section"> & {
|
|
36
34
|
readonly className?: string;
|
|
37
35
|
};
|
|
38
|
-
type McpServerSetupProps = {
|
|
39
|
-
readonly setup: McpServerManualSetup;
|
|
40
|
-
};
|
|
41
36
|
type McpConnectorFormValues = {
|
|
42
37
|
readonly bearerToken?: string;
|
|
43
38
|
readonly clientId?: string;
|
|
@@ -46,11 +41,10 @@ type McpConnectorFormValues = {
|
|
|
46
41
|
readonly scope?: string;
|
|
47
42
|
readonly url: string;
|
|
48
43
|
};
|
|
49
|
-
type McpConnectorFormDefaults = Partial<Pick<McpConnectorFormValues, "name" | "url">>;
|
|
50
44
|
type McpConnectorFormProps = Omit<React.FormHTMLAttributes<HTMLFormElement>, "onSubmit" | "status"> & {
|
|
51
45
|
/** Authentication metadata that decides which credential fields render. */readonly auth?: McpServerSetupAuth; /** Label for the OAuth authorization button. */
|
|
52
46
|
readonly authorizeLabel?: string; /** Initial MCP name and URL values. */
|
|
53
|
-
readonly defaults?:
|
|
47
|
+
readonly defaults?: Partial<Pick<McpConnectorFormValues, "name" | "url">>; /** Pattern used to validate the MCP name field. */
|
|
54
48
|
readonly namePattern?: string; /** OAuth URL waiting for the user to authorize, when available. */
|
|
55
49
|
readonly pendingAuthUrl?: string | null; /** Read-only redirect URL shown for manual OAuth client setup. */
|
|
56
50
|
readonly redirectUrl?: string; /** Inline connection status announced politely to assistive tech. */
|
|
@@ -81,16 +75,11 @@ declare function buildNanitesAgentConnectionCommands(origin: string, {
|
|
|
81
75
|
declare function AgentConnectionPanel({
|
|
82
76
|
className,
|
|
83
77
|
commands: commandsProp,
|
|
84
|
-
dcrMcpServers,
|
|
85
78
|
defaultTarget,
|
|
86
79
|
headingLevel,
|
|
87
|
-
manualMcpServers,
|
|
88
80
|
origin,
|
|
89
81
|
section
|
|
90
82
|
}: AgentConnectionPanelProps): React.JSX.Element | null;
|
|
91
|
-
declare function McpServerSetup({
|
|
92
|
-
setup
|
|
93
|
-
}: McpServerSetupProps): React.JSX.Element;
|
|
94
83
|
/** Collects MCP connector settings and optional credentials with native form validation. */
|
|
95
84
|
declare function McpConnectorForm({
|
|
96
85
|
auth,
|
|
@@ -118,4 +107,4 @@ declare function AgentConnectionPopover({
|
|
|
118
107
|
...props
|
|
119
108
|
}: AgentConnectionPopoverProps): React.JSX.Element;
|
|
120
109
|
//#endregion
|
|
121
|
-
export { AgentConnectionCommand, AgentConnectionPanel, AgentConnectionPanelProps, AgentConnectionPopover, AgentConnectionPopoverProps, AgentConnectionTarget, Connection, ConnectionProps, McpConnectorForm,
|
|
110
|
+
export { AgentConnectionCommand, AgentConnectionPanel, AgentConnectionPanelProps, AgentConnectionPopover, AgentConnectionPopoverProps, AgentConnectionTarget, Connection, ConnectionProps, McpConnectorForm, McpConnectorFormProps, McpConnectorFormValues, NanitesAgentConnectionOptions, buildNanitesAgentConnectionCommands };
|
|
@@ -5,7 +5,6 @@ import { Button } from "./Button.js";
|
|
|
5
5
|
import { a as CodeBlockCopyButton, i as CodeBlockContent, n as CodeBlockActions, p as CodeBlockTitle, r as CodeBlockContainer, s as CodeBlockHeader, t as CodeBlock } from "../CodeBlock-XNQOupQ3.js";
|
|
6
6
|
import { Field } from "./Field.js";
|
|
7
7
|
import { Form } from "./Form.js";
|
|
8
|
-
import { DCR_MCP_SERVER_CARDS, MANUAL_MCP_SERVER_CARDS, getMcpServerIconSrc } from "../utils/mcp-server-catalog.js";
|
|
9
8
|
import * as React from "react";
|
|
10
9
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
11
10
|
//#region src/components/AgentConnection.tsx
|
|
@@ -104,7 +103,7 @@ function buildNanitesAgentConnectionCommands(origin, { mcpName = "nanites", plug
|
|
|
104
103
|
* Use inside setup screens where users need Codex, Claude Code, skill-only,
|
|
105
104
|
* or raw MCP JSON connection instructions.
|
|
106
105
|
*/
|
|
107
|
-
function AgentConnectionPanel({ className, commands: commandsProp,
|
|
106
|
+
function AgentConnectionPanel({ className, commands: commandsProp, defaultTarget = "codex", headingLevel = 2, origin, section = true }) {
|
|
108
107
|
const commands = React.useMemo(() => commandsProp ?? buildNanitesAgentConnectionCommands(origin ?? getBrowserOrigin()), [commandsProp, origin]);
|
|
109
108
|
const [target, setTarget] = React.useState(defaultTarget);
|
|
110
109
|
const selected = commands.find((command) => command.target === target) ?? commands[0];
|
|
@@ -150,72 +149,7 @@ function AgentConnectionPanel({ className, commands: commandsProp, dcrMcpServers
|
|
|
150
149
|
code: selected.code,
|
|
151
150
|
language: selected.language,
|
|
152
151
|
children: [/* @__PURE__ */ jsxs(CodeBlockHeader, { children: [/* @__PURE__ */ jsx(CodeBlockTitle, { children: selected.label }), /* @__PURE__ */ jsx(CodeBlockActions, { children: /* @__PURE__ */ jsx(CodeBlockCopyButton, {}) })] }), /* @__PURE__ */ jsx(CodeBlockContainer, { children: /* @__PURE__ */ jsx(CodeBlockContent, {}) })]
|
|
153
|
-
})
|
|
154
|
-
dcrMcpServers.length > 0 ? /* @__PURE__ */ jsx(McpServerList, {
|
|
155
|
-
heading: "Auto",
|
|
156
|
-
servers: dcrMcpServers
|
|
157
|
-
}) : null,
|
|
158
|
-
manualMcpServers.length > 0 ? /* @__PURE__ */ jsx(McpServerList, {
|
|
159
|
-
heading: "Manual",
|
|
160
|
-
servers: manualMcpServers
|
|
161
|
-
}) : null
|
|
162
|
-
]
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
function McpServerList({ heading, servers }) {
|
|
166
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
167
|
-
className: "agent-connect__mcp",
|
|
168
|
-
children: [/* @__PURE__ */ jsx("p", {
|
|
169
|
-
className: "agent-connect__mcp-heading",
|
|
170
|
-
children: heading
|
|
171
|
-
}), /* @__PURE__ */ jsx("ul", {
|
|
172
|
-
className: "agent-connect__mcp-list",
|
|
173
|
-
role: "list",
|
|
174
|
-
children: servers.map((server) => /* @__PURE__ */ jsxs("li", {
|
|
175
|
-
className: "agent-connect__mcp-item",
|
|
176
|
-
children: [/* @__PURE__ */ jsx("span", {
|
|
177
|
-
className: "agent-connect__mcp-icon",
|
|
178
|
-
children: renderMcpServerIcon(server)
|
|
179
|
-
}), /* @__PURE__ */ jsxs("div", {
|
|
180
|
-
className: "agent-connect__mcp-copy",
|
|
181
|
-
children: [
|
|
182
|
-
/* @__PURE__ */ jsx("a", {
|
|
183
|
-
className: "agent-connect__mcp-name",
|
|
184
|
-
href: server.url,
|
|
185
|
-
target: "_blank",
|
|
186
|
-
rel: "noreferrer",
|
|
187
|
-
children: server.name
|
|
188
|
-
}),
|
|
189
|
-
server.description ? /* @__PURE__ */ jsx("span", {
|
|
190
|
-
className: "agent-connect__mcp-description",
|
|
191
|
-
children: server.description
|
|
192
|
-
}) : null,
|
|
193
|
-
server.manualSetup ? /* @__PURE__ */ jsx(McpServerSetup, { setup: server.manualSetup }) : null
|
|
194
|
-
]
|
|
195
|
-
})]
|
|
196
|
-
}, server.id))
|
|
197
|
-
})]
|
|
198
|
-
});
|
|
199
|
-
}
|
|
200
|
-
function McpServerSetup({ setup }) {
|
|
201
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
202
|
-
className: "agent-connect__mcp-setup",
|
|
203
|
-
children: [
|
|
204
|
-
/* @__PURE__ */ jsx("p", { children: setup.description }),
|
|
205
|
-
/* @__PURE__ */ jsxs("p", {
|
|
206
|
-
className: "agent-connect__mcp-setup-auth",
|
|
207
|
-
children: [/* @__PURE__ */ jsx("span", { children: setup.auth.label }), setup.auth.fields.length > 0 ? /* @__PURE__ */ jsx("span", { children: setup.auth.fields.map((field) => field.label).join(", ") }) : null]
|
|
208
|
-
}),
|
|
209
|
-
setup.links.length > 0 ? /* @__PURE__ */ jsx("ul", {
|
|
210
|
-
className: "agent-connect__mcp-setup-links",
|
|
211
|
-
role: "list",
|
|
212
|
-
children: setup.links.map((link) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("a", {
|
|
213
|
-
href: link.url,
|
|
214
|
-
target: "_blank",
|
|
215
|
-
rel: "noreferrer",
|
|
216
|
-
children: link.label
|
|
217
|
-
}) }, `${link.label}:${link.url}`))
|
|
218
|
-
}) : null
|
|
152
|
+
})
|
|
219
153
|
]
|
|
220
154
|
});
|
|
221
155
|
}
|
|
@@ -244,12 +178,8 @@ function McpConnectorForm({ auth, authorizeLabel = "Authorize", className, defau
|
|
|
244
178
|
...props,
|
|
245
179
|
children: [
|
|
246
180
|
/* @__PURE__ */ jsxs(Field.Root, { children: [
|
|
247
|
-
/* @__PURE__ */ jsx(Field.Label, {
|
|
248
|
-
htmlFor: "mcpName",
|
|
249
|
-
children: "MCP name"
|
|
250
|
-
}),
|
|
181
|
+
/* @__PURE__ */ jsx(Field.Label, { children: "MCP name" }),
|
|
251
182
|
/* @__PURE__ */ jsx(Field.Control, {
|
|
252
|
-
id: "mcpName",
|
|
253
183
|
name: "name",
|
|
254
184
|
pattern: namePattern,
|
|
255
185
|
required: true,
|
|
@@ -266,12 +196,8 @@ function McpConnectorForm({ auth, authorizeLabel = "Authorize", className, defau
|
|
|
266
196
|
})
|
|
267
197
|
] }),
|
|
268
198
|
/* @__PURE__ */ jsxs(Field.Root, { children: [
|
|
269
|
-
/* @__PURE__ */ jsx(Field.Label, {
|
|
270
|
-
htmlFor: "mcpUrl",
|
|
271
|
-
children: "MCP URL"
|
|
272
|
-
}),
|
|
199
|
+
/* @__PURE__ */ jsx(Field.Label, { children: "MCP URL" }),
|
|
273
200
|
/* @__PURE__ */ jsx(Field.Control, {
|
|
274
|
-
id: "mcpUrl",
|
|
275
201
|
name: "url",
|
|
276
202
|
placeholder: "http://127.0.0.1:8787/mcp",
|
|
277
203
|
required: true,
|
|
@@ -287,24 +213,16 @@ function McpConnectorForm({ auth, authorizeLabel = "Authorize", className, defau
|
|
|
287
213
|
children: "MCP URL must use http or https."
|
|
288
214
|
})
|
|
289
215
|
] }),
|
|
290
|
-
redirectUrlField ? /* @__PURE__ */ jsxs(Field.Root, { children: [/* @__PURE__ */ jsx(Field.Label, {
|
|
291
|
-
htmlFor: "mcpRedirectUrl",
|
|
292
|
-
children: redirectUrlField.label
|
|
293
|
-
}), /* @__PURE__ */ jsx(Field.Control, {
|
|
294
|
-
id: "mcpRedirectUrl",
|
|
216
|
+
redirectUrlField ? /* @__PURE__ */ jsxs(Field.Root, { children: [/* @__PURE__ */ jsx(Field.Label, { children: redirectUrlField.label }), /* @__PURE__ */ jsx(Field.Control, {
|
|
295
217
|
name: "redirectUrl",
|
|
296
218
|
readOnly: true,
|
|
297
219
|
type: "url",
|
|
298
220
|
value: redirectUrl
|
|
299
221
|
})] }) : null,
|
|
300
222
|
credentialFields.map((authField) => /* @__PURE__ */ jsxs(Field.Root, { children: [
|
|
301
|
-
/* @__PURE__ */ jsx(Field.Label, {
|
|
302
|
-
htmlFor: `mcp-${authField.name}`,
|
|
303
|
-
children: authField.label
|
|
304
|
-
}),
|
|
223
|
+
/* @__PURE__ */ jsx(Field.Label, { children: authField.label }),
|
|
305
224
|
/* @__PURE__ */ jsx(Field.Control, {
|
|
306
225
|
autoComplete: "off",
|
|
307
|
-
id: `mcp-${authField.name}`,
|
|
308
226
|
name: authField.name,
|
|
309
227
|
placeholder: authField.placeholder,
|
|
310
228
|
required: authField.required,
|
|
@@ -362,28 +280,6 @@ function readFormString(data, name) {
|
|
|
362
280
|
function isCredentialAuthField(field) {
|
|
363
281
|
return field.name !== "redirectUrl";
|
|
364
282
|
}
|
|
365
|
-
function renderMcpServerIcon(server) {
|
|
366
|
-
const src = getMcpServerIconSrc(server);
|
|
367
|
-
if (src) return /* @__PURE__ */ jsx(McpServerIconImage, {
|
|
368
|
-
src,
|
|
369
|
-
name: server.name
|
|
370
|
-
});
|
|
371
|
-
return server.name.slice(0, 1);
|
|
372
|
-
}
|
|
373
|
-
function McpServerIconImage({ src, name }) {
|
|
374
|
-
const [failed, setFailed] = React.useState(false);
|
|
375
|
-
if (failed) return name.slice(0, 1);
|
|
376
|
-
return /* @__PURE__ */ jsx("img", {
|
|
377
|
-
src,
|
|
378
|
-
alt: "",
|
|
379
|
-
width: 16,
|
|
380
|
-
height: 16,
|
|
381
|
-
loading: "lazy",
|
|
382
|
-
decoding: "async",
|
|
383
|
-
referrerPolicy: "no-referrer",
|
|
384
|
-
onError: () => setFailed(true)
|
|
385
|
-
});
|
|
386
|
-
}
|
|
387
283
|
/**
|
|
388
284
|
* Compact popover trigger for showing AgentConnectionPanel inline.
|
|
389
285
|
*/
|
|
@@ -412,4 +308,4 @@ function AgentConnectionPopover({ className, ...props }) {
|
|
|
412
308
|
}) })] });
|
|
413
309
|
}
|
|
414
310
|
//#endregion
|
|
415
|
-
export { AgentConnectionPanel, AgentConnectionPopover, Connection, McpConnectorForm,
|
|
311
|
+
export { AgentConnectionPanel, AgentConnectionPopover, Connection, McpConnectorForm, buildNanitesAgentConnectionCommands };
|
package/dist/components/Badge.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { n as mergeRefs } from "../merge-refs-DF_7w2x_.js";
|
|
1
2
|
import * as React from "react";
|
|
2
3
|
import { jsx } from "react/jsx-runtime";
|
|
3
4
|
//#region src/components/Badge.tsx
|
|
@@ -26,21 +27,6 @@ function badgeVariants({ variant = "default", color, size = "md", className } =
|
|
|
26
27
|
className
|
|
27
28
|
].filter(Boolean).join(" ");
|
|
28
29
|
}
|
|
29
|
-
function assignRef(ref, value) {
|
|
30
|
-
if (!ref) return;
|
|
31
|
-
if (typeof ref === "function") {
|
|
32
|
-
ref(value);
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
ref.current = value;
|
|
36
|
-
}
|
|
37
|
-
function mergeRefs(...refs) {
|
|
38
|
-
const activeRefs = refs.filter(Boolean);
|
|
39
|
-
if (activeRefs.length === 0) return;
|
|
40
|
-
return (value) => {
|
|
41
|
-
for (const activeRef of activeRefs) assignRef(activeRef, value);
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
30
|
function isEventHandler(propName, value) {
|
|
45
31
|
return /^on[A-Z]/.test(propName) && typeof value === "function";
|
|
46
32
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as BrowserLiveViewProps, t as BrowserLiveView } from "../BrowserLiveView-
|
|
1
|
+
import { n as BrowserLiveViewProps, t as BrowserLiveView } from "../BrowserLiveView-BV5qgFgI.js";
|
|
2
2
|
export { BrowserLiveView, BrowserLiveViewProps };
|
|
@@ -22,8 +22,8 @@ function EndedState({ title, detail }) {
|
|
|
22
22
|
/**
|
|
23
23
|
* Embeds a Browser Run Live View — a real-time, interactive view of the
|
|
24
24
|
* agent's browser session. Links expire (~5 minutes), so the iframe swaps to
|
|
25
|
-
* `fallback` (e.g. the last screenshot) once `
|
|
26
|
-
* hosted viewer connects, a quiet loading overlay hides the frame; if it
|
|
25
|
+
* `fallback` (e.g. the last screenshot) once `source.expiresInMs` passes.
|
|
26
|
+
* While the hosted viewer connects, a quiet loading overlay hides the frame; if it
|
|
27
27
|
* never loads, the view degrades to `fallback` or an unavailable state. An
|
|
28
28
|
* expand button opens the same view in a fullscreen dialog.
|
|
29
29
|
*
|
|
@@ -39,13 +39,12 @@ function EndedState({ title, detail }) {
|
|
|
39
39
|
* The iframe is unsandboxed by design: the hosted Live View UI needs scripts
|
|
40
40
|
* and its own origin to stream the session. Only pass trusted Live View URLs.
|
|
41
41
|
*/
|
|
42
|
-
function BrowserLiveView({
|
|
43
|
-
const [expired, setExpired] = React.useState(() =>
|
|
42
|
+
function BrowserLiveView({ source, receivedAt, pageTitle, fallback, className, ...props }) {
|
|
43
|
+
const [expired, setExpired] = React.useState(() => receivedAt !== void 0 && receivedAt + source.expiresInMs <= Date.now());
|
|
44
44
|
const [frameState, setFrameState] = React.useState("loading");
|
|
45
45
|
const [expandedOpen, setExpandedOpen] = React.useState(false);
|
|
46
46
|
React.useEffect(() => {
|
|
47
|
-
|
|
48
|
-
const remaining = expiresAt - Date.now();
|
|
47
|
+
const remaining = (receivedAt ?? Date.now()) + source.expiresInMs - Date.now();
|
|
49
48
|
if (remaining <= 0) {
|
|
50
49
|
setExpired(true);
|
|
51
50
|
return;
|
|
@@ -53,10 +52,15 @@ function BrowserLiveView({ url, expiresAt, pageTitle, fallback, className, ...pr
|
|
|
53
52
|
setExpired(false);
|
|
54
53
|
const timer = setTimeout(() => setExpired(true), remaining);
|
|
55
54
|
return () => clearTimeout(timer);
|
|
56
|
-
}, [
|
|
55
|
+
}, [
|
|
56
|
+
receivedAt,
|
|
57
|
+
source.expiresInMs,
|
|
58
|
+
source.targetId,
|
|
59
|
+
source.url
|
|
60
|
+
]);
|
|
57
61
|
React.useEffect(() => {
|
|
58
62
|
setFrameState("loading");
|
|
59
|
-
}, [url]);
|
|
63
|
+
}, [source.url]);
|
|
60
64
|
React.useEffect(() => {
|
|
61
65
|
if (frameState !== "loading") return;
|
|
62
66
|
const timer = setTimeout(() => setFrameState("failed"), FRAME_LOAD_TIMEOUT_MS);
|
|
@@ -77,7 +81,7 @@ function BrowserLiveView({ url, expiresAt, pageTitle, fallback, className, ...pr
|
|
|
77
81
|
}),
|
|
78
82
|
/* @__PURE__ */ jsx("iframe", {
|
|
79
83
|
className: "browser-live-view__frame",
|
|
80
|
-
src: url,
|
|
84
|
+
src: source.url,
|
|
81
85
|
title: frameTitle,
|
|
82
86
|
allow: "clipboard-read; clipboard-write",
|
|
83
87
|
onLoad: () => setFrameState("ready")
|
|
@@ -118,7 +122,7 @@ function BrowserLiveView({ url, expiresAt, pageTitle, fallback, className, ...pr
|
|
|
118
122
|
}), /* @__PURE__ */ jsx("div", {
|
|
119
123
|
className: "browser-live-view__dialog-body",
|
|
120
124
|
children: live ? /* @__PURE__ */ jsx("iframe", {
|
|
121
|
-
src: url,
|
|
125
|
+
src: source.url,
|
|
122
126
|
title: frameTitle,
|
|
123
127
|
allow: "clipboard-read; clipboard-write"
|
|
124
128
|
}) : fallback ?? /* @__PURE__ */ jsx(EndedState, {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as BrowserReplayProps, t as BrowserReplay } from "../BrowserReplay-
|
|
1
|
+
import { n as BrowserReplayProps, t as BrowserReplay } from "../BrowserReplay-xWvRjRAC.js";
|
|
2
2
|
export { BrowserReplay, BrowserReplayProps };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { BrowserLiveView } from "agents/browser";
|
|
3
|
+
|
|
4
|
+
//#region src/components/BrowserRunPanel.d.ts
|
|
5
|
+
interface BrowserRunPanelProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "children"> {
|
|
6
|
+
/** Host-side Browser Run Live View data from `connector.liveView()`. */
|
|
7
|
+
liveView?: BrowserLiveView;
|
|
8
|
+
/** Refreshes the Live View URL before it expires. */
|
|
9
|
+
onRefresh?: () => void | Promise<void>;
|
|
10
|
+
/** Closes the app-owned shared browser session. */
|
|
11
|
+
onCloseSession?: () => void | Promise<void>;
|
|
12
|
+
/** True while the app is fetching Live View data. */
|
|
13
|
+
loading?: boolean;
|
|
14
|
+
/** Error from the app-owned browser session fetch/refresh path. */
|
|
15
|
+
error?: React.ReactNode;
|
|
16
|
+
/** Panel heading. */
|
|
17
|
+
label?: React.ReactNode;
|
|
18
|
+
/** Empty state shown when there is no shared browser session. */
|
|
19
|
+
empty?: React.ReactNode;
|
|
20
|
+
/** Fallback passed through to `BrowserLiveView` after URL expiry/failure. */
|
|
21
|
+
fallback?: React.ReactNode;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Right-side Browser Run panel for `ThinkFullApp.workbenchPanels`.
|
|
25
|
+
*
|
|
26
|
+
* The app owns `createBrowserRuntime()`, `connector.liveView()`, polling, and
|
|
27
|
+
* session cleanup. This component only renders upstream `BrowserLiveView`
|
|
28
|
+
* data and calls app-provided refresh/close callbacks.
|
|
29
|
+
*/
|
|
30
|
+
declare function BrowserRunPanel({
|
|
31
|
+
liveView,
|
|
32
|
+
onRefresh,
|
|
33
|
+
onCloseSession,
|
|
34
|
+
loading,
|
|
35
|
+
error,
|
|
36
|
+
label,
|
|
37
|
+
empty,
|
|
38
|
+
fallback,
|
|
39
|
+
className,
|
|
40
|
+
ref,
|
|
41
|
+
...props
|
|
42
|
+
}: BrowserRunPanelProps & {
|
|
43
|
+
ref?: React.Ref<HTMLDivElement>;
|
|
44
|
+
}): React.JSX.Element;
|
|
45
|
+
//#endregion
|
|
46
|
+
export { BrowserRunPanel, BrowserRunPanelProps };
|