@mcp-b/react-components 0.7.1 → 0.9.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-403mckDG.d.ts → AgentChat-B9LD_WF1.d.ts} +67 -2
- package/dist/{CodeBlock-D9koxDA7.js → CodeBlock-XNQOupQ3.js} +1 -1
- package/dist/{FileTree-BdK93Uuu.js → FileTree-wMyZhhHO.js} +1 -1
- package/dist/{ModelSelector-MQvK-pNb.js → ModelSelector-9G_-GooI.js} +1 -1
- package/dist/{ThinkChatActivity-CeHzk6-K.d.ts → ThinkChatActivity-B2UD95My.d.ts} +1 -1
- package/dist/{ThinkChatContext-CC94HL4u.d.ts → ThinkChatContext-BLAAb8J5.d.ts} +1 -1
- package/dist/components/Activity.js +1 -1
- package/dist/components/AgentChat.d.ts +1 -1
- package/dist/components/AgentChat.js +107 -8
- package/dist/components/AgentConnection.js +2 -2
- package/dist/components/Artifact.js +1 -1
- package/dist/components/BrowserLiveView.js +1 -1
- package/dist/components/BrowserReplay.js +1 -1
- package/dist/components/ChainOfThought.d.ts +1 -1
- package/dist/components/ChainOfThought.js +1 -1
- package/dist/components/ChatGptSignInScreen.js +2 -2
- package/dist/components/CodeBlock.js +1 -1
- package/dist/components/Commit.js +1 -1
- package/dist/components/ContextMenu.js +1 -1
- package/dist/components/Conversation.js +1 -1
- package/dist/components/Dialog.js +1 -1
- package/dist/components/EnvironmentVariables.js +1 -1
- package/dist/components/FileTree.js +1 -1
- package/dist/components/McpServerPicker.js +7 -5
- package/dist/components/Menubar.js +1 -1
- package/dist/components/Message.js +1 -1
- package/dist/components/MessageScroller.js +1 -1
- package/dist/components/ModelSelector.js +1 -1
- package/dist/components/NavigationMenu.js +1 -1
- package/dist/components/PromptInput.js +6 -5
- package/dist/components/Queue.js +1 -1
- package/dist/components/Reasoning.js +1 -1
- package/dist/components/Select.js +1 -1
- package/dist/components/Sources.js +1 -1
- package/dist/components/Stepper.js +1 -1
- package/dist/components/Task.js +1 -1
- package/dist/components/Terminal.js +4 -3
- package/dist/components/TestResults.js +1 -1
- package/dist/components/ThinkChat.d.ts +8 -10
- package/dist/components/ThinkChatActivity.d.ts +1 -1
- package/dist/components/ThinkChatActivity.js +4 -3
- package/dist/components/ThinkChatContext.d.ts +1 -1
- package/dist/components/ThinkChatToolPanels.js +1 -1
- package/dist/components/ThinkChatToolParts.js +4 -4
- package/dist/components/ThinkExecutionWorkbench.d.ts +27 -0
- package/dist/components/ThinkExecutionWorkbench.js +450 -0
- package/dist/components/ThinkFullApp.d.ts +63 -9
- package/dist/components/ThinkFullApp.js +171 -73
- package/dist/components/ThinkThreadPicker.d.ts +88 -0
- package/dist/components/ThinkThreadPicker.js +282 -0
- package/dist/components/WebPreview.js +1 -1
- package/dist/components/WorkspaceExplorer.js +5 -4
- package/dist/components/icons.d.ts +2 -2
- package/dist/components/icons.js +2 -2
- package/dist/{copy-button-TVhDAroI.js → copy-button-C6JSKtFE.js} +1 -1
- package/dist/{icons-BRI54ATJ.d.ts → icons-CbjtbIJK.d.ts} +2 -1
- package/dist/{icons-BAlTbWWP.js → icons-D2Q5n5C1.js} +11 -1
- package/dist/styles/index.css +1 -0
- package/dist/styles/think-full-app.css +439 -26
- package/dist/styles/think-thread-picker.css +449 -0
- package/dist/utils/mcp-server-catalog.d.ts +5 -2
- package/package.json +7 -8
|
@@ -1,23 +1,77 @@
|
|
|
1
1
|
import { WorkspaceSource } from "./WorkspaceExplorer.js";
|
|
2
|
-
import {
|
|
2
|
+
import { ThinkChatMessagesProps } from "./ThinkChat.js";
|
|
3
|
+
import { ThinkExecutionAgent, ThinkExecutionWorkbench, ThinkExecutionWorkbenchProps, ThinkExecutionWorkbenchSource } from "./ThinkExecutionWorkbench.js";
|
|
3
4
|
import * as React from "react";
|
|
5
|
+
import { useAgentChat } from "@cloudflare/think/react";
|
|
6
|
+
import { UIMessage } from "ai";
|
|
7
|
+
import { useAgent } from "agents/react";
|
|
8
|
+
import { Think } from "@cloudflare/think";
|
|
4
9
|
|
|
5
10
|
//#region src/components/ThinkFullApp.d.ts
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
type ThinkFullAppAgent<State = unknown> = Think<object, State>;
|
|
12
|
+
type ThinkFullAppWorkbenchView = "files" | "execution" | (string & {});
|
|
13
|
+
interface ThinkFullAppPanelContext<AgentT extends ThinkFullAppAgent<State>, State = unknown> {
|
|
14
|
+
agent: ReturnType<typeof useAgent<AgentT, State>>;
|
|
15
|
+
chat: ReturnType<typeof useAgentChat<State, UIMessage>>;
|
|
16
|
+
workspace?: WorkspaceSource;
|
|
17
|
+
workspaceRoot?: string;
|
|
18
|
+
}
|
|
19
|
+
interface ThinkFullAppPanel<AgentT extends ThinkFullAppAgent<State>, State = unknown> {
|
|
20
|
+
/** Unique panel id used by `workbenchView`; custom panels should not reuse built-in ids. */
|
|
21
|
+
id: ThinkFullAppWorkbenchView;
|
|
22
|
+
label: string;
|
|
23
|
+
icon: React.ReactNode;
|
|
24
|
+
render: (context: ThinkFullAppPanelContext<AgentT, State>) => React.ReactNode;
|
|
25
|
+
}
|
|
26
|
+
interface ThinkFullAppProps<AgentT extends ThinkFullAppAgent<State>, State = unknown> extends React.HTMLAttributes<HTMLDivElement> {
|
|
27
|
+
/** The `useAgent` value from `agents/react`; its stub drives approvals and execution records. */
|
|
28
|
+
agent: ReturnType<typeof useAgent<AgentT, State>>;
|
|
29
|
+
/** The `useAgentChat` value from `@cloudflare/think/react` used by the chat surface. */
|
|
30
|
+
chat: ReturnType<typeof useAgentChat<State, UIMessage>>;
|
|
11
31
|
/** Optional workspace source shown in the file explorer pane. */
|
|
12
32
|
workspace?: WorkspaceSource;
|
|
13
33
|
/** Root path passed to the workspace explorer. */
|
|
14
34
|
workspaceRoot?: string;
|
|
15
35
|
/** Message rendering labels and approval overrides for ThinkChat. */
|
|
16
36
|
messages?: ThinkChatMessagesProps;
|
|
37
|
+
/** Extra workbench panels appended after the built-in Files and Execution panels. */
|
|
38
|
+
workbenchPanels?: readonly ThinkFullAppPanel<AgentT, State>[];
|
|
39
|
+
/** Optional parent-owned thread picker/sidebar rendered beside the selected child app. */
|
|
40
|
+
threadSidebar?: React.ReactNode;
|
|
41
|
+
/** Whether the thread sidebar is open. Omit for internal state. */
|
|
42
|
+
threadSidebarOpen?: boolean;
|
|
43
|
+
/** Initial thread sidebar state when `threadSidebarOpen` is uncontrolled. */
|
|
44
|
+
defaultThreadSidebarOpen?: boolean;
|
|
45
|
+
/** Called when the thread sidebar is opened or closed. */
|
|
46
|
+
onThreadSidebarOpenChange?: (open: boolean) => void;
|
|
47
|
+
/** Selected workbench lane. Use this when the parent app stores the lane in route state. */
|
|
48
|
+
workbenchView?: ThinkFullAppWorkbenchView;
|
|
49
|
+
/** Initial workbench lane when `workbenchView` is uncontrolled. */
|
|
50
|
+
defaultWorkbenchView?: ThinkFullAppWorkbenchView;
|
|
51
|
+
/** Called when the shell toolbar asks to switch workbench lanes. */
|
|
52
|
+
onWorkbenchViewChange?: (view: ThinkFullAppWorkbenchView) => void;
|
|
17
53
|
}
|
|
18
|
-
/** Combines ThinkChat with an optional resizable
|
|
19
|
-
declare function ThinkFullApp
|
|
54
|
+
/** Combines ThinkChat with an optional resizable workbench shell. */
|
|
55
|
+
declare function ThinkFullApp<AgentT extends ThinkFullAppAgent<State>, State = unknown>({
|
|
56
|
+
agent,
|
|
57
|
+
chat,
|
|
58
|
+
className,
|
|
59
|
+
defaultWorkbenchView,
|
|
60
|
+
defaultThreadSidebarOpen,
|
|
61
|
+
messages,
|
|
62
|
+
onThreadSidebarOpenChange,
|
|
63
|
+
onWorkbenchViewChange,
|
|
64
|
+
ref,
|
|
65
|
+
style,
|
|
66
|
+
threadSidebar,
|
|
67
|
+
threadSidebarOpen,
|
|
68
|
+
workbenchPanels,
|
|
69
|
+
workbenchView,
|
|
70
|
+
workspace,
|
|
71
|
+
workspaceRoot,
|
|
72
|
+
...props
|
|
73
|
+
}: ThinkFullAppProps<AgentT, State> & {
|
|
20
74
|
ref?: React.Ref<HTMLDivElement>;
|
|
21
75
|
}): React.JSX.Element;
|
|
22
76
|
//#endregion
|
|
23
|
-
export { ThinkFullApp, ThinkFullAppProps };
|
|
77
|
+
export { type ThinkExecutionAgent, ThinkExecutionWorkbench, type ThinkExecutionWorkbenchProps, type ThinkExecutionWorkbenchSource, ThinkFullApp, ThinkFullAppAgent, ThinkFullAppPanel, ThinkFullAppPanelContext, ThinkFullAppProps, ThinkFullAppWorkbenchView };
|
|
@@ -1,65 +1,93 @@
|
|
|
1
1
|
import { t as cx } from "../class-names-9UtZwb0J.js";
|
|
2
|
-
import { h as FileIcon, n as ArrowLeftIcon } from "../icons-
|
|
2
|
+
import { P as TerminalIcon, h as FileIcon, n as ArrowLeftIcon } from "../icons-D2Q5n5C1.js";
|
|
3
3
|
import { Button } from "./Button.js";
|
|
4
|
+
import { Tooltip, TooltipPopup, TooltipPortal, TooltipPositioner, TooltipTrigger } from "./Tooltip.js";
|
|
5
|
+
import { ToggleGroup, ToggleGroupItem } from "./ToggleGroup.js";
|
|
4
6
|
import { WorkspaceExplorer, useWorkspace } from "./WorkspaceExplorer.js";
|
|
5
7
|
import { ThinkChat, useThinkPendingApprovals } from "./ThinkChat.js";
|
|
8
|
+
import { ThinkExecutionWorkbench } from "./ThinkExecutionWorkbench.js";
|
|
9
|
+
import { ThinkThreadShell } from "./ThinkThreadPicker.js";
|
|
6
10
|
import * as React from "react";
|
|
7
|
-
import {
|
|
11
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
12
|
//#region src/components/ThinkFullApp.tsx
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
function
|
|
14
|
-
return Math.min(
|
|
13
|
+
const workbenchPanelDefaultWidth = 340;
|
|
14
|
+
const workbenchPanelMinWidth = 300;
|
|
15
|
+
const workbenchPanelMaxWidth = 600;
|
|
16
|
+
const workbenchPanelKeyboardStep = 24;
|
|
17
|
+
function clampWorkbenchPanelWidth(width) {
|
|
18
|
+
return Math.min(workbenchPanelMaxWidth, Math.max(workbenchPanelMinWidth, width));
|
|
15
19
|
}
|
|
16
|
-
function
|
|
20
|
+
function beginWorkbenchPanelResize(event, current, apply) {
|
|
17
21
|
event.preventDefault();
|
|
18
22
|
const startX = event.clientX;
|
|
19
23
|
const onMove = (move) => {
|
|
20
|
-
apply(
|
|
24
|
+
apply(clampWorkbenchPanelWidth(current - (move.clientX - startX)));
|
|
21
25
|
};
|
|
22
26
|
const onUp = () => {
|
|
23
27
|
window.removeEventListener("pointermove", onMove);
|
|
24
28
|
window.removeEventListener("pointerup", onUp);
|
|
29
|
+
window.removeEventListener("pointercancel", onUp);
|
|
25
30
|
document.body.classList.remove("is-resizing-columns");
|
|
26
31
|
};
|
|
27
32
|
document.body.classList.add("is-resizing-columns");
|
|
28
33
|
window.addEventListener("pointermove", onMove);
|
|
29
34
|
window.addEventListener("pointerup", onUp);
|
|
35
|
+
window.addEventListener("pointercancel", onUp);
|
|
30
36
|
}
|
|
31
|
-
function
|
|
37
|
+
function WorkbenchBackButton({ onBack }) {
|
|
38
|
+
return /* @__PURE__ */ jsx(Button, {
|
|
39
|
+
type: "button",
|
|
40
|
+
variant: "ghost",
|
|
41
|
+
color: "neutral",
|
|
42
|
+
size: "icon-sm",
|
|
43
|
+
className: "think-full-app__workspace-back",
|
|
44
|
+
"aria-label": "Show chat",
|
|
45
|
+
onClick: onBack,
|
|
46
|
+
children: /* @__PURE__ */ jsx(ArrowLeftIcon, {})
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
function WorkspacePanel({ source, root }) {
|
|
32
50
|
return /* @__PURE__ */ jsx(WorkspaceExplorer, {
|
|
33
51
|
className: "think-full-app__workbench",
|
|
34
52
|
workspace: useWorkspace({
|
|
35
53
|
source,
|
|
36
54
|
root
|
|
37
|
-
})
|
|
38
|
-
title: onBack ? /* @__PURE__ */ jsxs("span", {
|
|
39
|
-
className: "think-full-app__workspace-title",
|
|
40
|
-
children: [/* @__PURE__ */ jsx(Button, {
|
|
41
|
-
type: "button",
|
|
42
|
-
variant: "ghost",
|
|
43
|
-
color: "neutral",
|
|
44
|
-
size: "icon-sm",
|
|
45
|
-
className: "think-full-app__workspace-back",
|
|
46
|
-
"aria-label": "Show chat",
|
|
47
|
-
onClick: onBack,
|
|
48
|
-
children: /* @__PURE__ */ jsx(ArrowLeftIcon, {})
|
|
49
|
-
}), /* @__PURE__ */ jsx("span", { children: "Workspace" })]
|
|
50
|
-
}) : void 0
|
|
55
|
+
})
|
|
51
56
|
});
|
|
52
57
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
function WorkbenchViewItem({ children, label, value }) {
|
|
59
|
+
return /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, { render: /* @__PURE__ */ jsx(ToggleGroupItem, {
|
|
60
|
+
type: "button",
|
|
61
|
+
className: "think-full-app__workbench-view-item",
|
|
62
|
+
value,
|
|
63
|
+
"aria-label": label,
|
|
64
|
+
children
|
|
65
|
+
}) }), /* @__PURE__ */ jsx(TooltipPortal, { children: /* @__PURE__ */ jsx(TooltipPositioner, {
|
|
66
|
+
side: "bottom",
|
|
67
|
+
sideOffset: 6,
|
|
68
|
+
children: /* @__PURE__ */ jsx(TooltipPopup, { children: label })
|
|
69
|
+
}) })] });
|
|
70
|
+
}
|
|
71
|
+
function WorkbenchViewSwitch({ panels, value, onValueChange }) {
|
|
72
|
+
return /* @__PURE__ */ jsx(ToggleGroup, {
|
|
73
|
+
className: "think-full-app__workbench-view-switch",
|
|
74
|
+
size: "sm",
|
|
75
|
+
value: [value],
|
|
76
|
+
"aria-label": "Workbench views",
|
|
77
|
+
onValueChange: (nextValue) => {
|
|
78
|
+
const [next] = nextValue;
|
|
79
|
+
if (next) onValueChange(next);
|
|
80
|
+
},
|
|
81
|
+
children: panels.map((panel) => /* @__PURE__ */ jsx(WorkbenchViewItem, {
|
|
82
|
+
value: panel.id,
|
|
83
|
+
label: panel.label,
|
|
84
|
+
children: panel.icon
|
|
85
|
+
}, panel.id))
|
|
59
86
|
});
|
|
60
87
|
}
|
|
61
|
-
|
|
62
|
-
|
|
88
|
+
/** Combines ThinkChat with an optional resizable workbench shell. */
|
|
89
|
+
function ThinkFullApp({ agent, chat, className, defaultWorkbenchView, defaultThreadSidebarOpen, messages, onThreadSidebarOpenChange, onWorkbenchViewChange, ref, style, threadSidebar, threadSidebarOpen, workbenchPanels, workbenchView, workspace, workspaceRoot, ...props }) {
|
|
90
|
+
const approvals = useThinkPendingApprovals(agent.stub, `${chat.messages.length}:${chat.status}`);
|
|
63
91
|
const resolvedMessages = React.useMemo(() => ({
|
|
64
92
|
...messages,
|
|
65
93
|
executionApprovals: messages?.executionApprovals ?? approvals.executionApprovals,
|
|
@@ -69,44 +97,101 @@ function ThinkFullAppWithApprovals({ agentStub, chat, messages, ...props }) {
|
|
|
69
97
|
approvals.pendingApprovals,
|
|
70
98
|
messages
|
|
71
99
|
]);
|
|
72
|
-
return /* @__PURE__ */ jsx(ThinkFullAppLayout, {
|
|
73
|
-
...props,
|
|
74
|
-
chat,
|
|
75
|
-
messages: resolvedMessages
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
function ThinkFullAppLayout({ chat, className, messages, ref, style, workspace, workspaceRoot, ...props }) {
|
|
79
|
-
const hasWorkspace = workspace !== void 0;
|
|
80
100
|
const [mobileView, setMobileView] = React.useState("chat");
|
|
81
|
-
const [
|
|
82
|
-
const
|
|
83
|
-
const
|
|
101
|
+
const [innerWorkbenchView, setInnerWorkbenchView] = React.useState(defaultWorkbenchView ?? "files");
|
|
102
|
+
const [workbenchPanelWidth, setWorkbenchPanelWidth] = React.useState(workbenchPanelDefaultWidth);
|
|
103
|
+
const hasWorkspace = workspace !== void 0;
|
|
104
|
+
const panelContext = React.useMemo(() => ({
|
|
105
|
+
agent,
|
|
106
|
+
chat,
|
|
107
|
+
workspace,
|
|
108
|
+
workspaceRoot
|
|
109
|
+
}), [
|
|
110
|
+
agent,
|
|
111
|
+
chat,
|
|
112
|
+
workspace,
|
|
113
|
+
workspaceRoot
|
|
114
|
+
]);
|
|
115
|
+
const availableWorkbenchPanels = React.useMemo(() => {
|
|
116
|
+
const builtInPanels = [];
|
|
117
|
+
if (workspace !== void 0) builtInPanels.push({
|
|
118
|
+
id: "files",
|
|
119
|
+
label: "Files",
|
|
120
|
+
icon: /* @__PURE__ */ jsx(FileIcon, {}),
|
|
121
|
+
render: () => /* @__PURE__ */ jsx(WorkspacePanel, {
|
|
122
|
+
source: workspace,
|
|
123
|
+
root: workspaceRoot
|
|
124
|
+
})
|
|
125
|
+
});
|
|
126
|
+
builtInPanels.push({
|
|
127
|
+
id: "execution",
|
|
128
|
+
label: "Execution",
|
|
129
|
+
icon: /* @__PURE__ */ jsx(TerminalIcon, {}),
|
|
130
|
+
render: ({ agent }) => /* @__PURE__ */ jsx(ThinkExecutionWorkbench, {
|
|
131
|
+
source: agent.stub,
|
|
132
|
+
title: "Execution"
|
|
133
|
+
})
|
|
134
|
+
});
|
|
135
|
+
return workbenchPanels ? [...builtInPanels, ...workbenchPanels] : builtInPanels;
|
|
136
|
+
}, [
|
|
137
|
+
workbenchPanels,
|
|
138
|
+
workspace,
|
|
139
|
+
workspaceRoot
|
|
140
|
+
]);
|
|
141
|
+
const activeMobileView = mobileView === "workbench" ? "workbench" : "chat";
|
|
142
|
+
const isMobileWorkbenchView = activeMobileView === "workbench";
|
|
143
|
+
const requestedWorkbenchView = workbenchView ?? innerWorkbenchView;
|
|
144
|
+
const activePanel = availableWorkbenchPanels.find((panel) => panel.id === requestedWorkbenchView) ?? availableWorkbenchPanels[0];
|
|
145
|
+
const activeWorkbenchView = activePanel?.id ?? "execution";
|
|
146
|
+
const mobileWorkbenchLabel = hasWorkspace && activeWorkbenchView === "files" ? "Show workbench" : `Show ${activePanel?.label.toLowerCase() ?? "workbench"}`;
|
|
147
|
+
const showWorkbenchViewSwitch = availableWorkbenchPanels.length > 1;
|
|
148
|
+
const showShellTopbar = showWorkbenchViewSwitch || isMobileWorkbenchView;
|
|
84
149
|
const rootStyle = {
|
|
85
150
|
...style,
|
|
86
|
-
"--think-full-app-
|
|
151
|
+
"--think-full-app-workbench-w": `${workbenchPanelWidth}px`
|
|
87
152
|
};
|
|
88
|
-
const
|
|
89
|
-
|
|
153
|
+
const resizeWorkbenchPanelBy = (delta) => {
|
|
154
|
+
setWorkbenchPanelWidth((current) => clampWorkbenchPanelWidth(current + delta));
|
|
90
155
|
};
|
|
91
|
-
|
|
156
|
+
const setWorkbenchView = React.useCallback((next) => {
|
|
157
|
+
if (workbenchView === void 0) setInnerWorkbenchView(next);
|
|
158
|
+
onWorkbenchViewChange?.(next);
|
|
159
|
+
}, [onWorkbenchViewChange, workbenchView]);
|
|
160
|
+
const app = /* @__PURE__ */ jsxs("div", {
|
|
92
161
|
ref,
|
|
93
162
|
className: cx("think-full-app", className),
|
|
94
163
|
"data-has-files": hasWorkspace ? "true" : "false",
|
|
164
|
+
"data-has-thread-sidebar": threadSidebar ? "true" : "false",
|
|
165
|
+
"data-has-workbench": "true",
|
|
166
|
+
"data-has-workbench-topbar": showWorkbenchViewSwitch ? "true" : "false",
|
|
95
167
|
"data-mobile-view": activeMobileView,
|
|
96
168
|
style: rootStyle,
|
|
97
169
|
...props,
|
|
98
170
|
children: [
|
|
99
|
-
|
|
171
|
+
showShellTopbar ? /* @__PURE__ */ jsxs("div", {
|
|
172
|
+
className: "think-full-app__topbar",
|
|
173
|
+
role: "toolbar",
|
|
174
|
+
"aria-label": "Workbench controls",
|
|
175
|
+
"data-mobile-only": showWorkbenchViewSwitch ? void 0 : "true",
|
|
176
|
+
children: [/* @__PURE__ */ jsx(WorkbenchBackButton, { onBack: () => setMobileView("chat") }), showWorkbenchViewSwitch ? /* @__PURE__ */ jsx(WorkbenchViewSwitch, {
|
|
177
|
+
panels: availableWorkbenchPanels,
|
|
178
|
+
value: activeWorkbenchView,
|
|
179
|
+
onValueChange: setWorkbenchView
|
|
180
|
+
}) : null]
|
|
181
|
+
}) : null,
|
|
182
|
+
!isMobileWorkbenchView ? /* @__PURE__ */ jsx("div", {
|
|
100
183
|
className: "think-full-app__mobile-header",
|
|
184
|
+
role: "toolbar",
|
|
185
|
+
"aria-label": "Workbench",
|
|
101
186
|
children: /* @__PURE__ */ jsx(Button, {
|
|
102
187
|
type: "button",
|
|
103
188
|
variant: "ghost",
|
|
104
189
|
color: "neutral",
|
|
105
190
|
size: "icon-sm",
|
|
106
191
|
className: "think-full-app__mobile-action",
|
|
107
|
-
"aria-label":
|
|
108
|
-
onClick: () => setMobileView("
|
|
109
|
-
children: /* @__PURE__ */ jsx(
|
|
192
|
+
"aria-label": mobileWorkbenchLabel,
|
|
193
|
+
onClick: () => setMobileView("workbench"),
|
|
194
|
+
children: activePanel?.icon ?? /* @__PURE__ */ jsx(TerminalIcon, {})
|
|
110
195
|
})
|
|
111
196
|
}) : null,
|
|
112
197
|
/* @__PURE__ */ jsx("section", {
|
|
@@ -118,12 +203,16 @@ function ThinkFullAppLayout({ chat, className, messages, ref, style, workspace,
|
|
|
118
203
|
className: "think-full-app__chat-inner",
|
|
119
204
|
children: [/* @__PURE__ */ jsx(ThinkChat.Provider, {
|
|
120
205
|
chat,
|
|
121
|
-
children: /* @__PURE__ */ jsx(ThinkChat.Messages, { ...
|
|
206
|
+
children: /* @__PURE__ */ jsx(ThinkChat.Messages, { ...resolvedMessages })
|
|
122
207
|
}), chat.error ? /* @__PURE__ */ jsxs("div", {
|
|
123
208
|
className: "think-full-app__error",
|
|
124
209
|
role: "alert",
|
|
125
|
-
children: [chat.error.message, /* @__PURE__ */ jsx(
|
|
210
|
+
children: [chat.error.message, /* @__PURE__ */ jsx(Button, {
|
|
126
211
|
type: "button",
|
|
212
|
+
variant: "link",
|
|
213
|
+
color: "neutral",
|
|
214
|
+
size: "xs",
|
|
215
|
+
className: "think-full-app__error-dismiss",
|
|
127
216
|
onClick: () => chat.clearError(),
|
|
128
217
|
children: "Dismiss"
|
|
129
218
|
})]
|
|
@@ -131,45 +220,54 @@ function ThinkFullAppLayout({ chat, className, messages, ref, style, workspace,
|
|
|
131
220
|
})
|
|
132
221
|
})
|
|
133
222
|
}),
|
|
134
|
-
|
|
223
|
+
/* @__PURE__ */ jsx("button", {
|
|
135
224
|
type: "button",
|
|
136
225
|
role: "separator",
|
|
137
|
-
"aria-label": "Resize
|
|
226
|
+
"aria-label": "Resize workbench panel",
|
|
138
227
|
"aria-orientation": "vertical",
|
|
139
|
-
"aria-valuemin":
|
|
140
|
-
"aria-valuemax":
|
|
141
|
-
"aria-valuenow":
|
|
228
|
+
"aria-valuemin": workbenchPanelMinWidth,
|
|
229
|
+
"aria-valuemax": workbenchPanelMaxWidth,
|
|
230
|
+
"aria-valuenow": workbenchPanelWidth,
|
|
142
231
|
className: "think-full-app__resizer",
|
|
143
|
-
onPointerDown: (event) =>
|
|
232
|
+
onPointerDown: (event) => beginWorkbenchPanelResize(event, workbenchPanelWidth, setWorkbenchPanelWidth),
|
|
144
233
|
onKeyDown: (event) => {
|
|
145
234
|
if (event.key === "ArrowLeft") {
|
|
146
235
|
event.preventDefault();
|
|
147
|
-
|
|
236
|
+
resizeWorkbenchPanelBy(workbenchPanelKeyboardStep);
|
|
148
237
|
} else if (event.key === "ArrowRight") {
|
|
149
238
|
event.preventDefault();
|
|
150
|
-
|
|
239
|
+
resizeWorkbenchPanelBy(-24);
|
|
151
240
|
} else if (event.key === "Home") {
|
|
152
241
|
event.preventDefault();
|
|
153
|
-
|
|
242
|
+
setWorkbenchPanelWidth(workbenchPanelMinWidth);
|
|
154
243
|
} else if (event.key === "End") {
|
|
155
244
|
event.preventDefault();
|
|
156
|
-
|
|
245
|
+
setWorkbenchPanelWidth(workbenchPanelMaxWidth);
|
|
157
246
|
}
|
|
158
247
|
}
|
|
159
|
-
}),
|
|
248
|
+
}),
|
|
249
|
+
/* @__PURE__ */ jsx("aside", {
|
|
160
250
|
className: "think-full-app__aside",
|
|
161
|
-
"aria-label": "
|
|
251
|
+
"aria-label": "Workbench",
|
|
162
252
|
children: /* @__PURE__ */ jsx("div", {
|
|
163
|
-
className: "think-full-
|
|
164
|
-
children: /* @__PURE__ */ jsx(
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
253
|
+
className: "think-full-app__workbench-slot",
|
|
254
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
255
|
+
className: "think-full-app__workbench-panel",
|
|
256
|
+
"data-view": activeWorkbenchView,
|
|
257
|
+
children: activePanel?.render(panelContext)
|
|
168
258
|
})
|
|
169
259
|
})
|
|
170
|
-
})
|
|
260
|
+
})
|
|
171
261
|
]
|
|
172
262
|
});
|
|
263
|
+
if (!threadSidebar) return app;
|
|
264
|
+
return /* @__PURE__ */ jsx(ThinkThreadShell, {
|
|
265
|
+
sidebar: threadSidebar,
|
|
266
|
+
sidebarOpen: threadSidebarOpen,
|
|
267
|
+
defaultSidebarOpen: defaultThreadSidebarOpen,
|
|
268
|
+
onSidebarOpenChange: onThreadSidebarOpenChange,
|
|
269
|
+
children: app
|
|
270
|
+
});
|
|
173
271
|
}
|
|
174
272
|
//#endregion
|
|
175
|
-
export { ThinkFullApp };
|
|
273
|
+
export { ThinkExecutionWorkbench, ThinkFullApp };
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
//#region src/components/ThinkThreadPicker.d.ts
|
|
4
|
+
interface ThinkThreadItem {
|
|
5
|
+
/** Stable child-agent/thread id passed back to the app's route state. */
|
|
6
|
+
id: string;
|
|
7
|
+
/** Human-readable thread title, usually generated by the parent Think agent. */
|
|
8
|
+
title: string;
|
|
9
|
+
/** Optional parent-owned preview for apps that render their own richer sidebar. */
|
|
10
|
+
lastMessagePreview?: string;
|
|
11
|
+
/** Timestamp from the parent registry or metadata row. `updatedAt` wins over `createdAt`. */
|
|
12
|
+
createdAt?: Date | number;
|
|
13
|
+
/** Timestamp from parent-owned thread metadata when available. */
|
|
14
|
+
updatedAt?: Date | number;
|
|
15
|
+
/** Preformatted timestamp label when the app already has one, such as "14m". */
|
|
16
|
+
updatedAtLabel?: string;
|
|
17
|
+
/** Optional upstream/app status string. The picker only displays it; it does not derive it. */
|
|
18
|
+
status?: string;
|
|
19
|
+
/** Human label for `status` when the raw upstream value is not user-facing. */
|
|
20
|
+
statusLabel?: string;
|
|
21
|
+
}
|
|
22
|
+
interface ThinkThreadPickerProps extends Omit<React.HTMLAttributes<HTMLElement>, "onSelect" | "title"> {
|
|
23
|
+
/** Threads from the parent agent, already sorted in the order the app wants to show. */
|
|
24
|
+
threads: readonly ThinkThreadItem[];
|
|
25
|
+
/** Selected child-agent/thread id. */
|
|
26
|
+
selectedId?: string;
|
|
27
|
+
/** Called when a thread row is selected; callers route this into `useAgent({ sub })`. */
|
|
28
|
+
onSelect: (id: string) => void;
|
|
29
|
+
/** Optional parent-agent create action, usually `parent.stub.createThread()`. */
|
|
30
|
+
onCreate?: () => void | Promise<void>;
|
|
31
|
+
/** Visible heading for the roster. */
|
|
32
|
+
title?: React.ReactNode;
|
|
33
|
+
/** Accessible label for the list navigation. */
|
|
34
|
+
"aria-label"?: string;
|
|
35
|
+
}
|
|
36
|
+
interface ThinkThreadShellProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
37
|
+
/** Thread picker or app-owned sidebar shown beside the selected child shell. */
|
|
38
|
+
sidebar: React.ReactNode;
|
|
39
|
+
/** Whether the thread drawer is open. Omit for internal state. */
|
|
40
|
+
sidebarOpen?: boolean;
|
|
41
|
+
/** Initial thread drawer state when `sidebarOpen` is uncontrolled. */
|
|
42
|
+
defaultSidebarOpen?: boolean;
|
|
43
|
+
/** Called when the thread drawer is opened or closed. */
|
|
44
|
+
onSidebarOpenChange?: (open: boolean) => void;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Thread roster UI for sub-agent chat apps.
|
|
48
|
+
*
|
|
49
|
+
* This component does not call Think or Cloudflare RPC methods directly. Feed
|
|
50
|
+
* it from the parent agent's roster method, then route `onSelect` into the
|
|
51
|
+
* child `useAgent({ sub: [...] })` name. Keep backend contract notes beside the
|
|
52
|
+
* parent Think agent because `listThreads()`/`createThread()` are app-owned.
|
|
53
|
+
*/
|
|
54
|
+
declare function ThinkThreadPicker({
|
|
55
|
+
threads,
|
|
56
|
+
selectedId,
|
|
57
|
+
onSelect,
|
|
58
|
+
onCreate,
|
|
59
|
+
className,
|
|
60
|
+
title,
|
|
61
|
+
"aria-label": ariaLabel,
|
|
62
|
+
ref,
|
|
63
|
+
...props
|
|
64
|
+
}: ThinkThreadPickerProps & {
|
|
65
|
+
ref?: React.Ref<HTMLElement>;
|
|
66
|
+
}): React.JSX.Element;
|
|
67
|
+
/**
|
|
68
|
+
* Layout wrapper for a thread picker beside one selected `ThinkFullApp`.
|
|
69
|
+
*
|
|
70
|
+
* Mobile keeps the drawer at about 80% width so the selected chat remains
|
|
71
|
+
* visible as a preview. It only owns layout; callers still own the parent agent,
|
|
72
|
+
* selected child agent, chat hook, and shared workspace.
|
|
73
|
+
*/
|
|
74
|
+
declare function ThinkThreadShell({
|
|
75
|
+
sidebar,
|
|
76
|
+
sidebarOpen,
|
|
77
|
+
defaultSidebarOpen,
|
|
78
|
+
onSidebarOpenChange,
|
|
79
|
+
className,
|
|
80
|
+
children,
|
|
81
|
+
ref,
|
|
82
|
+
style,
|
|
83
|
+
...props
|
|
84
|
+
}: ThinkThreadShellProps & {
|
|
85
|
+
ref?: React.Ref<HTMLDivElement>;
|
|
86
|
+
}): React.JSX.Element;
|
|
87
|
+
//#endregion
|
|
88
|
+
export { ThinkThreadItem, ThinkThreadPicker, ThinkThreadPickerProps, ThinkThreadShell, ThinkThreadShellProps };
|