@springbrand/message-panel 0.1.2 → 0.1.3-alpha.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/demo/camel-chat-showcase.tsx +1265 -0
- package/demo/fixtures.ts +292 -0
- package/demo/message-panel-chat-showcase.tsx +250 -0
- package/demo/message-panel-gallery.tsx +389 -0
- package/package.json +6 -16
- package/src/adapters/ai-sdk.ts +32 -0
- package/src/camel/camel-chat-messages.tsx +1435 -0
- package/src/camel/camel-model-select.tsx +88 -0
- package/src/camel/camel-plan-bar.tsx +115 -0
- package/src/camel/camel-prompt-input.tsx +547 -0
- package/src/camel/camel-tool-presentation.tsx +1270 -0
- package/src/camel/camel-turn.ts +334 -0
- package/src/camel/turn-summary-bar.tsx +81 -0
- package/src/chat-summary-panel.tsx +229 -0
- package/src/composer/chat-composer.tsx +216 -0
- package/src/composer/composer-attachments.tsx +138 -0
- package/src/composer/composer-trigger-popover.tsx +236 -0
- package/src/composer/composer.tsx +425 -0
- package/src/composer/drop-controller.ts +80 -0
- package/src/composer/types.ts +79 -0
- package/src/contracts.ts +138 -0
- package/src/conversation.tsx +76 -0
- package/src/internal/cn.ts +3 -0
- package/src/message-panel.tsx +368 -0
- package/src/message.tsx +254 -0
- package/src/parts/index.tsx +1149 -0
- package/src/parts/kind.ts +67 -0
- package/src/parts/plan.ts +64 -0
- package/src/parts/primitives.tsx +439 -0
- package/src/registry.ts +44 -0
- package/src/status.tsx +132 -0
- package/dist/demo/camel-chat-showcase.d.ts +0 -1
- package/dist/demo/camel-chat-showcase.js +0 -1007
- package/dist/demo/fixtures.d.ts +0 -32
- package/dist/demo/fixtures.js +0 -250
- package/dist/demo/index.js +0 -4
- package/dist/demo/message-panel-chat-showcase.d.ts +0 -1
- package/dist/demo/message-panel-chat-showcase.js +0 -114
- package/dist/demo/message-panel-gallery.d.ts +0 -1
- package/dist/demo/message-panel-gallery.js +0 -130
- package/dist/src/adapters/ai-sdk.d.ts +0 -4
- package/dist/src/adapters/ai-sdk.js +0 -25
- package/dist/src/camel/camel-chat-messages.d.ts +0 -44
- package/dist/src/camel/camel-chat-messages.js +0 -421
- package/dist/src/camel/camel-model-select.d.ts +0 -13
- package/dist/src/camel/camel-model-select.js +0 -7
- package/dist/src/camel/camel-plan-bar.d.ts +0 -5
- package/dist/src/camel/camel-plan-bar.js +0 -24
- package/dist/src/camel/camel-prompt-input.d.ts +0 -32
- package/dist/src/camel/camel-prompt-input.js +0 -182
- package/dist/src/camel/camel-tool-presentation.d.ts +0 -21
- package/dist/src/camel/camel-tool-presentation.js +0 -784
- package/dist/src/camel/camel-turn.d.ts +0 -57
- package/dist/src/camel/camel-turn.js +0 -203
- package/dist/src/camel/index.js +0 -7
- package/dist/src/camel/turn-summary-bar.d.ts +0 -8
- package/dist/src/camel/turn-summary-bar.js +0 -12
- package/dist/src/chat-summary-panel.d.ts +0 -22
- package/dist/src/chat-summary-panel.js +0 -26
- package/dist/src/composer/chat-composer.d.ts +0 -4
- package/dist/src/composer/chat-composer.js +0 -90
- package/dist/src/composer/composer-attachments.d.ts +0 -13
- package/dist/src/composer/composer-attachments.js +0 -47
- package/dist/src/composer/composer-trigger-popover.d.ts +0 -31
- package/dist/src/composer/composer-trigger-popover.js +0 -29
- package/dist/src/composer/composer.d.ts +0 -15
- package/dist/src/composer/composer.js +0 -180
- package/dist/src/composer/drop-controller.d.ts +0 -8
- package/dist/src/composer/drop-controller.js +0 -69
- package/dist/src/composer/index.js +0 -6
- package/dist/src/composer/types.d.ts +0 -62
- package/dist/src/composer/types.js +0 -1
- package/dist/src/contracts.d.ts +0 -94
- package/dist/src/contracts.js +0 -1
- package/dist/src/conversation.d.ts +0 -13
- package/dist/src/conversation.js +0 -18
- package/dist/src/index.js +0 -12
- package/dist/src/internal/cn.d.ts +0 -1
- package/dist/src/internal/cn.js +0 -3
- package/dist/src/message-panel.d.ts +0 -4
- package/dist/src/message-panel.js +0 -144
- package/dist/src/message.d.ts +0 -36
- package/dist/src/message.js +0 -83
- package/dist/src/parts/index.d.ts +0 -187
- package/dist/src/parts/index.js +0 -332
- package/dist/src/parts/kind.d.ts +0 -3
- package/dist/src/parts/kind.js +0 -69
- package/dist/src/parts/plan.d.ts +0 -10
- package/dist/src/parts/plan.js +0 -40
- package/dist/src/parts/primitives.d.ts +0 -70
- package/dist/src/parts/primitives.js +0 -153
- package/dist/src/registry.d.ts +0 -4
- package/dist/src/registry.js +0 -31
- package/dist/src/status.d.ts +0 -26
- package/dist/src/status.js +0 -74
- /package/{dist/demo/index.d.ts → demo/index.ts} +0 -0
- /package/{dist/src/camel/index.d.ts → src/camel/index.ts} +0 -0
- /package/{dist/src/composer/index.d.ts → src/composer/index.ts} +0 -0
- /package/{dist/src/index.d.ts → src/index.ts} +0 -0
|
@@ -1,421 +0,0 @@
|
|
|
1
|
-
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { ArrowDownIcon, BellIcon, CheckIcon, ChevronRightIcon, CopyIcon, GitForkIcon, Loader2Icon, TriangleAlertIcon, } from "lucide-react";
|
|
3
|
-
import { useCallback, useEffect, useMemo, useRef, useState, } from "react";
|
|
4
|
-
import { MessageResponse, } from "../message";
|
|
5
|
-
import { ParallelPart, SubAgentsPart, resolvePartKind, toolNameOfPart, } from "../parts";
|
|
6
|
-
import { deriveThinkingActivity, ThinkingIndicator } from "../status";
|
|
7
|
-
import { cn } from "../internal/cn";
|
|
8
|
-
import { CamelToolDetails, getCamelToolPresentation, } from "./camel-tool-presentation";
|
|
9
|
-
import { camelCompletedAt, camelCreatedAt, camelMessageText, camelMetadata, formatCamelMessageTime, projectCamelMessages, } from "./camel-turn";
|
|
10
|
-
import { TurnSummaryBar } from "./turn-summary-bar";
|
|
11
|
-
const pendingSteerActivity = {
|
|
12
|
-
state: "working",
|
|
13
|
-
label: "Waiting for the current step to finish…",
|
|
14
|
-
};
|
|
15
|
-
function Button({ className, size = "sm", variant = "default", type = "button", ...props }) {
|
|
16
|
-
return (_jsx("button", { type: type, className: cn("inline-flex shrink-0 items-center justify-center gap-1 rounded-md text-xs font-medium transition-all outline-none disabled:pointer-events-none disabled:opacity-50", variant === "default" &&
|
|
17
|
-
"bg-primary text-primary-foreground hover:bg-primary/80", variant === "outline" &&
|
|
18
|
-
"border border-border bg-background hover:bg-muted", variant === "ghost" && "hover:bg-muted hover:text-foreground", size === "sm" && "h-7 px-2", size === "icon" && "size-9 rounded-full", size === "icon-sm" && "size-8 p-0", className), ...props }));
|
|
19
|
-
}
|
|
20
|
-
export function CamelChatError({ error, onRetry, }) {
|
|
21
|
-
return (_jsxs("div", { className: "flex items-start gap-2 rounded-lg border border-destructive/25 bg-destructive/5 px-3 py-2 text-sm text-destructive", "data-camel-chat-error": "", role: "alert", children: [_jsx(TriangleAlertIcon, { className: "size-4 shrink-0" }), _jsx("span", { className: "min-w-0 flex-1 break-words", children: error instanceof Error
|
|
22
|
-
? error.message
|
|
23
|
-
: typeof error === "string"
|
|
24
|
-
? error
|
|
25
|
-
: "Something went wrong" }), onRetry && (_jsx(Button, { type: "button", size: "sm", variant: "outline", className: "shrink-0", onClick: onRetry, children: "Retry" }))] }));
|
|
26
|
-
}
|
|
27
|
-
export function CamelApprovalPrompts({ approvals, error, onApprove, }) {
|
|
28
|
-
if (approvals.length === 0)
|
|
29
|
-
return null;
|
|
30
|
-
return (_jsxs("div", { className: "flex flex-col gap-2", "data-camel-approval-prompts": "", children: [approvals.map((approval) => (_jsxs("section", { "aria-label": "\u7B49\u5F85\u5BA1\u6279", className: "rounded-xl border border-border bg-background p-3 shadow-sm", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [_jsxs("p", { className: "text-xs font-medium text-muted-foreground", children: ["\u9700\u8981\u5BA1\u6279 \u00B7 ", approval.action] }), _jsxs("p", { className: "text-xs text-muted-foreground", children: ["Agent: ", approval.executionLevelLabel, " \u00B7 Tool:", " ", approval.requiredExecutionLevelLabel] })] }), _jsx("p", { className: "mt-1 text-sm text-foreground", children: approval.summary }), _jsxs("div", { className: "mt-2 flex flex-wrap justify-end gap-2", children: [_jsx(Button, { variant: "outline", disabled: approval.disabled, onClick: () => onApprove(approval.id, "deny"), children: "\u62D2\u7EDD" }), _jsx(Button, { variant: "outline", disabled: approval.disabled, onClick: () => onApprove(approval.id, "allow_once"), children: "\u4EC5\u672C\u6B21\u5141\u8BB8" }), _jsx(Button, { disabled: approval.disabled, onClick: () => onApprove(approval.id, "allow_level"), children: "\u5141\u8BB8\u8BE5\u6863\u4F4D" })] })] }, approval.id))), error && (_jsx("p", { className: "px-1 text-xs text-destructive", role: "alert", children: error }))] }));
|
|
31
|
-
}
|
|
32
|
-
function Collapsible({ open, onOpenChange, disabled = false, trigger, children, }) {
|
|
33
|
-
return (_jsxs(_Fragment, { children: [_jsx("div", { onClick: () => {
|
|
34
|
-
if (!disabled)
|
|
35
|
-
onOpenChange(!open);
|
|
36
|
-
}, children: trigger }), _jsx("div", { "data-camel-collapsible-content": "", "data-state": open ? "open" : "closed", "aria-hidden": !open, inert: !open ? true : undefined, children: open && (_jsx("div", { "data-camel-collapsible-inner": "", children: children })) })] }));
|
|
37
|
-
}
|
|
38
|
-
function recordOf(value) {
|
|
39
|
-
return value != null && typeof value === "object"
|
|
40
|
-
? value
|
|
41
|
-
: {};
|
|
42
|
-
}
|
|
43
|
-
function dataOf(part) {
|
|
44
|
-
const record = recordOf(part);
|
|
45
|
-
return recordOf(record.data ?? record.input ?? record);
|
|
46
|
-
}
|
|
47
|
-
function toolApprovalOf(part) {
|
|
48
|
-
const approval = recordOf(recordOf(part).approval);
|
|
49
|
-
return typeof approval.id === "string"
|
|
50
|
-
? {
|
|
51
|
-
id: approval.id,
|
|
52
|
-
...(typeof approval.approved === "boolean"
|
|
53
|
-
? { approved: approval.approved }
|
|
54
|
-
: {}),
|
|
55
|
-
}
|
|
56
|
-
: undefined;
|
|
57
|
-
}
|
|
58
|
-
function normalizedPartType(part) {
|
|
59
|
-
const record = recordOf(part);
|
|
60
|
-
const rawType = typeof record.type === "string" ? record.type : "unknown";
|
|
61
|
-
return (resolvePartKind(part) ??
|
|
62
|
-
(rawType.startsWith("data-")
|
|
63
|
-
? rawType.slice(5).replaceAll("-", "_")
|
|
64
|
-
: rawType));
|
|
65
|
-
}
|
|
66
|
-
function ClipboardAction({ text }) {
|
|
67
|
-
const [copied, setCopied] = useState(false);
|
|
68
|
-
const timerRef = useRef(null);
|
|
69
|
-
useEffect(() => () => {
|
|
70
|
-
if (timerRef.current !== null)
|
|
71
|
-
window.clearTimeout(timerRef.current);
|
|
72
|
-
}, []);
|
|
73
|
-
const copy = useCallback(() => {
|
|
74
|
-
void navigator.clipboard.writeText(text).then(() => {
|
|
75
|
-
setCopied(true);
|
|
76
|
-
if (timerRef.current !== null)
|
|
77
|
-
window.clearTimeout(timerRef.current);
|
|
78
|
-
timerRef.current = window.setTimeout(() => setCopied(false), 1500);
|
|
79
|
-
});
|
|
80
|
-
}, [text]);
|
|
81
|
-
return (_jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", className: "size-8 text-muted-foreground", onClick: copy, "aria-label": copied ? "Copied!" : "Copy message", title: copied ? "Copied!" : "Copy message", children: copied ? _jsx(CheckIcon, { className: "size-4" }) : _jsx(CopyIcon, { className: "size-4" }) }));
|
|
82
|
-
}
|
|
83
|
-
function CamelThinking({ part, isActive, }) {
|
|
84
|
-
const record = recordOf(part);
|
|
85
|
-
const data = dataOf(part);
|
|
86
|
-
const text = String(record.text ?? data.detail ?? data.text ?? "");
|
|
87
|
-
const streaming = isActive && record.state === "streaming";
|
|
88
|
-
const [open, setOpen] = useState(false);
|
|
89
|
-
return (_jsx("div", { "data-part-type": "reasoning", children: _jsx(Collapsible, { open: open, onOpenChange: setOpen, trigger: _jsxs("div", { role: "button", tabIndex: 0, className: cn("thinking-block group/thinking -mx-2 flex w-full cursor-pointer items-center gap-2 rounded px-2 py-1 text-left text-sm text-muted-foreground", "transition-colors duration-150 hover:bg-muted/30 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring/50"), onKeyDown: (event) => {
|
|
90
|
-
if (event.key === "Enter" || event.key === " ") {
|
|
91
|
-
event.preventDefault();
|
|
92
|
-
setOpen((current) => !current);
|
|
93
|
-
}
|
|
94
|
-
}, children: [_jsx("span", { className: cn("size-1.5 shrink-0 rounded-full", streaming
|
|
95
|
-
? "animate-pulse bg-blue-500 motion-reduce:animate-none"
|
|
96
|
-
: "bg-green-500") }), _jsx("span", { className: "min-w-0 flex-1 truncate", children: streaming ? "Thinking…" : "Thought" }), _jsx(ChevronRightIcon, { className: cn("size-4 text-muted-foreground/50 opacity-0 transition-all duration-150 group-hover/thinking:opacity-100", open && "rotate-90 opacity-100") })] }), children: _jsx("div", { className: "ml-1 mt-1 border-l border-border/40 pl-4 text-xs text-muted-foreground/80", children: _jsx(MessageResponse, { children: text }) }) }) }));
|
|
97
|
-
}
|
|
98
|
-
function CamelToolRow({ part, isActive, children, onApprove, getToolApproval, }) {
|
|
99
|
-
const [open, setOpen] = useState(false);
|
|
100
|
-
const approval = getToolApproval?.(part) ?? toolApprovalOf(part);
|
|
101
|
-
const pendingApproval = approval && approval.approved === undefined;
|
|
102
|
-
const presentation = getCamelToolPresentation(part, isActive);
|
|
103
|
-
const hasDetails = children != null || presentation.hasDetails;
|
|
104
|
-
const title = presentation.summary;
|
|
105
|
-
useEffect(() => {
|
|
106
|
-
if (presentation.isSubAgent && presentation.running)
|
|
107
|
-
setOpen(true);
|
|
108
|
-
}, [presentation.isSubAgent, presentation.running]);
|
|
109
|
-
return (_jsxs("div", { "data-part-type": normalizedPartType(part), children: [_jsx(Collapsible, { open: open, onOpenChange: setOpen, disabled: !hasDetails, trigger: _jsxs("div", { role: "button", tabIndex: 0, "aria-label": title, "aria-expanded": hasDetails ? open : undefined, className: cn("tool-call group/toolcall -mx-2 flex w-full items-center gap-2 rounded px-2 py-1 text-left text-sm text-muted-foreground", hasDetails && "cursor-pointer hover:bg-muted/30", "transition-colors duration-150 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring/50"), onKeyDown: (event) => {
|
|
110
|
-
if (hasDetails && (event.key === "Enter" || event.key === " ")) {
|
|
111
|
-
event.preventDefault();
|
|
112
|
-
setOpen((current) => !current);
|
|
113
|
-
}
|
|
114
|
-
}, children: [_jsx("span", { className: cn("size-1.5 shrink-0 rounded-full", presentation.failed
|
|
115
|
-
? "bg-red-500"
|
|
116
|
-
: presentation.running || pendingApproval
|
|
117
|
-
? "animate-pulse bg-blue-500 motion-reduce:animate-none"
|
|
118
|
-
: "bg-green-500") }), _jsx("span", { className: "min-w-0 flex-1 truncate", children: title }), hasDetails && (_jsx(ChevronRightIcon, { className: cn("size-4 text-muted-foreground/50 opacity-0 transition-all duration-150 group-hover/toolcall:opacity-100", open && "rotate-90 opacity-100") }))] }), children: hasDetails ? (_jsx("div", { className: "group/details ml-1 mt-1 border-l border-border/50 pl-4 text-xs text-muted-foreground/80", children: children ?? (_jsx(CamelToolDetails, { presentation: presentation })) })) : null }), pendingApproval && (_jsxs("div", { className: "ml-1 mt-2 flex flex-wrap items-center gap-2 border-l border-border/50 pl-4", children: [_jsx(Button, { type: "button", size: "sm", variant: "outline", onClick: () => onApprove(approval.id, "deny"), children: "Deny" }), _jsx(Button, { type: "button", size: "sm", variant: "outline", onClick: () => onApprove(approval.id, "allow_once"), children: "Allow once" }), _jsx(Button, { type: "button", size: "sm", onClick: () => onApprove(approval.id, "allow_level"), children: "Allow this level" })] }))] }));
|
|
119
|
-
}
|
|
120
|
-
function CamelSuggestions({ part, onSuggestion, }) {
|
|
121
|
-
const data = dataOf(part);
|
|
122
|
-
const items = Array.isArray(data.items)
|
|
123
|
-
? data.items.filter((item) => typeof item === "string")
|
|
124
|
-
: [];
|
|
125
|
-
return (_jsxs("div", { className: "space-y-2 pt-1", "data-part-type": "suggestions", children: [_jsxs("div", { className: "flex items-center gap-2 text-sm text-emerald-600", children: [_jsx(CheckIcon, { className: "size-4" }), _jsx("span", { children: "Task complete" })] }), _jsx("div", { className: "flex flex-wrap gap-2", children: items.map((item) => (_jsx(Button, { type: "button", variant: "outline", size: "sm", className: "rounded-full", onClick: () => onSuggestion(item), children: item }, item))) })] }));
|
|
126
|
-
}
|
|
127
|
-
function scheduleDuration(seconds) {
|
|
128
|
-
if (typeof seconds !== "number" || !Number.isFinite(seconds) || seconds <= 0) {
|
|
129
|
-
return "";
|
|
130
|
-
}
|
|
131
|
-
for (const [size, unit] of [
|
|
132
|
-
[86_400, "day"],
|
|
133
|
-
[3_600, "hour"],
|
|
134
|
-
[60, "minute"],
|
|
135
|
-
]) {
|
|
136
|
-
if (seconds % size === 0) {
|
|
137
|
-
const value = seconds / size;
|
|
138
|
-
return `${value} ${unit}${value === 1 ? "" : "s"}`;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
return `${seconds} second${seconds === 1 ? "" : "s"}`;
|
|
142
|
-
}
|
|
143
|
-
function scheduleCadence(data) {
|
|
144
|
-
const trigger = recordOf(data.trigger);
|
|
145
|
-
const kind = trigger.kind;
|
|
146
|
-
let cadence = "";
|
|
147
|
-
if (kind === "once-in") {
|
|
148
|
-
cadence = `In ${scheduleDuration(trigger.seconds)}`;
|
|
149
|
-
}
|
|
150
|
-
else if (kind === "once-at" && typeof trigger.at === "string") {
|
|
151
|
-
cadence = `Once at ${trigger.at}`;
|
|
152
|
-
}
|
|
153
|
-
else if (kind === "interval") {
|
|
154
|
-
cadence = `Every ${scheduleDuration(trigger.seconds)}`;
|
|
155
|
-
}
|
|
156
|
-
else if (kind === "cron" && typeof trigger.cron === "string") {
|
|
157
|
-
cadence = `Cron ${trigger.cron}`;
|
|
158
|
-
}
|
|
159
|
-
if (!cadence) {
|
|
160
|
-
cadence = String(data.cadence ?? data.schedule ?? "Scheduled");
|
|
161
|
-
}
|
|
162
|
-
const timezone = typeof data.timezone === "string"
|
|
163
|
-
? data.timezone
|
|
164
|
-
: typeof data.tz === "string"
|
|
165
|
-
? data.tz
|
|
166
|
-
: "";
|
|
167
|
-
return timezone ? `${cadence} · ${timezone}` : cadence;
|
|
168
|
-
}
|
|
169
|
-
function CamelSchedule({ part, isActive, }) {
|
|
170
|
-
const data = dataOf(part);
|
|
171
|
-
const presentation = getCamelToolPresentation(part, isActive);
|
|
172
|
-
const state = presentation.failed
|
|
173
|
-
? "failed"
|
|
174
|
-
: presentation.running
|
|
175
|
-
? "running"
|
|
176
|
-
: "scheduled";
|
|
177
|
-
return (_jsx("section", { className: "rounded-xl border border-border bg-muted/20 p-3", "data-part-type": "schedule", "data-state": state, children: _jsxs("div", { className: "flex items-start gap-3", children: [_jsx("span", { className: "flex size-8 shrink-0 items-center justify-center rounded-lg bg-muted text-muted-foreground", children: _jsx(BellIcon, { className: "size-4" }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("strong", { className: "block truncate text-sm text-foreground", children: String(data.label ?? data.title ?? "Scheduled task") }), _jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: scheduleCadence(data) })] }), _jsxs("span", { className: cn("flex shrink-0 items-center gap-1 text-xs", state === "failed"
|
|
178
|
-
? "text-destructive"
|
|
179
|
-
: state === "running"
|
|
180
|
-
? "text-blue-500"
|
|
181
|
-
: "text-emerald-600"), children: [state === "failed" ? (_jsx(TriangleAlertIcon, { className: "size-3.5" })) : state === "running" ? (_jsx(Loader2Icon, { className: "size-3.5 animate-spin motion-reduce:animate-none" })) : (_jsx(CheckIcon, { className: "size-3.5" })), state === "failed"
|
|
182
|
-
? "Failed"
|
|
183
|
-
: state === "running"
|
|
184
|
-
? "Scheduling…"
|
|
185
|
-
: "Scheduled"] })] }) }));
|
|
186
|
-
}
|
|
187
|
-
function CamelAskUser({ part, submittedAnswer, onAnswer, }) {
|
|
188
|
-
const record = recordOf(part);
|
|
189
|
-
const data = dataOf(part);
|
|
190
|
-
const output = record.output;
|
|
191
|
-
const questions = Array.isArray(data.questions)
|
|
192
|
-
? data.questions.map(recordOf)
|
|
193
|
-
: typeof data.question === "string"
|
|
194
|
-
? [{
|
|
195
|
-
prompt: data.question,
|
|
196
|
-
kind: data.multiSelect === true ? "multi" : "single",
|
|
197
|
-
options: Array.isArray(data.options)
|
|
198
|
-
? data.options.filter((option) => typeof option === "string")
|
|
199
|
-
: [],
|
|
200
|
-
}]
|
|
201
|
-
: [];
|
|
202
|
-
const [selections, setSelections] = useState(() => questions.map(() => []));
|
|
203
|
-
const [text, setText] = useState("");
|
|
204
|
-
const [submitted, setSubmitted] = useState(false);
|
|
205
|
-
const outputRecord = recordOf(output);
|
|
206
|
-
const externalAnswer = submittedAnswer?.trim() ||
|
|
207
|
-
(typeof output === "string"
|
|
208
|
-
? output.trim()
|
|
209
|
-
: typeof outputRecord.text === "string"
|
|
210
|
-
? outputRecord.text.trim()
|
|
211
|
-
: "");
|
|
212
|
-
const externalSelections = new Set(externalAnswer
|
|
213
|
-
.split("、")
|
|
214
|
-
.map((value) => value.trim())
|
|
215
|
-
.filter(Boolean));
|
|
216
|
-
const resolvedSubmitted = submitted || Boolean(externalAnswer);
|
|
217
|
-
const valid = questions.every((question, index) => {
|
|
218
|
-
const options = Array.isArray(question.options) ? question.options : [];
|
|
219
|
-
return options.length === 0 || (selections[index]?.length ?? 0) > 0;
|
|
220
|
-
});
|
|
221
|
-
return (_jsxs("section", { className: "space-y-3 rounded-xl border border-border bg-muted/20 p-3", "data-part-type": "ask_user", "data-state": resolvedSubmitted ? "submitted" : "idle", children: [questions.map((question, questionIndex) => {
|
|
222
|
-
const prompt = String(question.prompt ?? "Choose an option");
|
|
223
|
-
const options = Array.isArray(question.options)
|
|
224
|
-
? question.options.filter((option) => typeof option === "string")
|
|
225
|
-
: [];
|
|
226
|
-
const multi = question.kind === "multi";
|
|
227
|
-
return (_jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-sm text-foreground", children: prompt }), _jsx("div", { className: "flex flex-wrap gap-2", children: options.map((option) => {
|
|
228
|
-
const selected = externalAnswer
|
|
229
|
-
? externalSelections.has(option)
|
|
230
|
-
: selections[questionIndex]?.includes(option);
|
|
231
|
-
return (_jsx(Button, { type: "button", size: "sm", variant: selected ? "default" : "outline", disabled: resolvedSubmitted, onClick: () => setSelections((current) => current.map((values, index) => {
|
|
232
|
-
if (index !== questionIndex)
|
|
233
|
-
return values;
|
|
234
|
-
if (!multi)
|
|
235
|
-
return [option];
|
|
236
|
-
return values.includes(option)
|
|
237
|
-
? values.filter((value) => value !== option)
|
|
238
|
-
: [...values, option];
|
|
239
|
-
})), children: option }, option));
|
|
240
|
-
}) })] }, `${prompt}:${questionIndex}`));
|
|
241
|
-
}), typeof data.freeTextPlaceholder === "string" && (_jsx("input", { value: text, disabled: resolvedSubmitted, onChange: (event) => setText(event.currentTarget.value), placeholder: data.freeTextPlaceholder, className: "h-8 w-full rounded-md border border-input bg-background px-3 text-sm outline-none focus:border-ring focus:ring-2 focus:ring-ring/30" })), _jsx(Button, { type: "button", size: "sm", disabled: resolvedSubmitted || !valid, onClick: () => {
|
|
242
|
-
onAnswer({ selections, text });
|
|
243
|
-
setSubmitted(true);
|
|
244
|
-
}, children: resolvedSubmitted ? "Submitted" : "Submit" }), externalAnswer && (_jsxs("p", { className: "text-xs text-muted-foreground", children: ["\u5DF2\u56DE\u7B54\uFF1A", externalAnswer] }))] }));
|
|
245
|
-
}
|
|
246
|
-
function CamelRichPart({ part, isActive, onApprove, onSuggestion, onAnswer, replyText, getToolApproval, }) {
|
|
247
|
-
const kind = normalizedPartType(part);
|
|
248
|
-
const data = dataOf(part);
|
|
249
|
-
if (kind === "suggestions") {
|
|
250
|
-
return _jsx(CamelSuggestions, { part: part, onSuggestion: onSuggestion });
|
|
251
|
-
}
|
|
252
|
-
if (kind === "schedule") {
|
|
253
|
-
return _jsx(CamelSchedule, { part: part, isActive: isActive });
|
|
254
|
-
}
|
|
255
|
-
if (kind === "ask_user") {
|
|
256
|
-
return (_jsx(CamelAskUser, { part: part, submittedAnswer: replyText, onAnswer: onAnswer }));
|
|
257
|
-
}
|
|
258
|
-
if (kind === "parallel") {
|
|
259
|
-
const tools = Array.isArray(data.tools)
|
|
260
|
-
? data.tools
|
|
261
|
-
: [];
|
|
262
|
-
return (_jsx(ParallelPart, { label: typeof data.label === "string" ? data.label : "Parallel tasks", tools: tools, isActive: isActive }));
|
|
263
|
-
}
|
|
264
|
-
if (kind === "subagents") {
|
|
265
|
-
const presentation = getCamelToolPresentation(part, isActive);
|
|
266
|
-
const toolName = toolNameOfPart(part);
|
|
267
|
-
const fallbackName = toolName === "run_temporary_agent"
|
|
268
|
-
? "Temporary Agent"
|
|
269
|
-
: toolName === "dispatch_background"
|
|
270
|
-
? `${String(data.agentType ?? "Background").replace(/^./, (value) => value.toUpperCase())} Agent`
|
|
271
|
-
: toolName === "fanout"
|
|
272
|
-
? "Fanout Agent"
|
|
273
|
-
: toolName === "extract"
|
|
274
|
-
? "Extract Agent"
|
|
275
|
-
: "Sub-agent";
|
|
276
|
-
const agents = Array.isArray(data.agents)
|
|
277
|
-
? data.agents
|
|
278
|
-
: [
|
|
279
|
-
{
|
|
280
|
-
name: String(data.subagentName ??
|
|
281
|
-
data.name ??
|
|
282
|
-
fallbackName),
|
|
283
|
-
summary: presentation.errorText ||
|
|
284
|
-
presentation.outputText ||
|
|
285
|
-
String(data.summary ?? ""),
|
|
286
|
-
status: presentation.failed
|
|
287
|
-
? "failed"
|
|
288
|
-
: presentation.running
|
|
289
|
-
? "running"
|
|
290
|
-
: "done",
|
|
291
|
-
},
|
|
292
|
-
];
|
|
293
|
-
return _jsx(SubAgentsPart, { agents: agents, isActive: isActive });
|
|
294
|
-
}
|
|
295
|
-
if (kind === "image") {
|
|
296
|
-
const src = String(data.src ?? data.url ?? "");
|
|
297
|
-
return (_jsx("figure", { className: "my-1", "data-part-type": "image", children: _jsx("img", { src: src, alt: String(data.alt ?? data.filename ?? "Generated image"), className: "max-h-[28rem] max-w-full rounded-lg border border-border object-contain" }) }));
|
|
298
|
-
}
|
|
299
|
-
if (kind === "error") {
|
|
300
|
-
return (_jsxs("div", { className: "flex items-start gap-2 rounded-lg border border-destructive/25 bg-destructive/5 px-3 py-2 text-sm text-destructive", "data-part-type": "error", role: "alert", children: [_jsx(TriangleAlertIcon, { className: "mt-0.5 size-4 shrink-0" }), _jsxs("div", { children: [_jsx("div", { className: "font-medium", children: String(data.title ?? "Error") }), _jsx("div", { className: "mt-0.5 text-xs opacity-80", children: String(data.body ?? data.message ?? "") })] })] }));
|
|
301
|
-
}
|
|
302
|
-
return (_jsx(CamelToolRow, { part: part, isActive: isActive, onApprove: onApprove, getToolApproval: getToolApproval }));
|
|
303
|
-
}
|
|
304
|
-
function AssistantPart({ part, isActive, onApprove, onSuggestion, onAnswer, replyText, getToolApproval, resolveUrl, }) {
|
|
305
|
-
const record = recordOf(part);
|
|
306
|
-
if (record.type === "step-start")
|
|
307
|
-
return null;
|
|
308
|
-
if (record.type === "text") {
|
|
309
|
-
const text = String(record.text ?? "").trim();
|
|
310
|
-
if (!text)
|
|
311
|
-
return null;
|
|
312
|
-
return (_jsx("div", { "data-part-type": "text", children: _jsx(MessageResponse, { streaming: isActive, resolveUrl: resolveUrl, children: text }) }));
|
|
313
|
-
}
|
|
314
|
-
if (record.type === "reasoning") {
|
|
315
|
-
return _jsx(CamelThinking, { part: part, isActive: isActive });
|
|
316
|
-
}
|
|
317
|
-
return (_jsx(CamelRichPart, { part: part, isActive: isActive, onApprove: onApprove, onSuggestion: onSuggestion, onAnswer: onAnswer, replyText: replyText, getToolApproval: getToolApproval }));
|
|
318
|
-
}
|
|
319
|
-
function ForkAction({ messageId, onFork, }) {
|
|
320
|
-
const [forking, setForking] = useState(false);
|
|
321
|
-
return (_jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", className: "size-8 text-muted-foreground", disabled: forking, onClick: () => {
|
|
322
|
-
setForking(true);
|
|
323
|
-
void Promise.resolve(onFork(messageId)).finally(() => setForking(false));
|
|
324
|
-
}, "aria-label": forking ? "Starting new thread…" : "New thread from here", title: forking ? "Starting new thread…" : "New thread from here", children: forking ? (_jsx(Loader2Icon, { className: "size-4 animate-spin" })) : (_jsx(GitForkIcon, { className: "size-4" })) }));
|
|
325
|
-
}
|
|
326
|
-
function UserMessage({ message }) {
|
|
327
|
-
const text = camelMessageText(message);
|
|
328
|
-
const files = message.parts.filter((part) => part.type === "file");
|
|
329
|
-
const metadata = camelMetadata(message);
|
|
330
|
-
const createdAt = camelCreatedAt(message);
|
|
331
|
-
const messageTime = createdAt === undefined ? null : formatCamelMessageTime(createdAt);
|
|
332
|
-
const authorStamp = [metadata.authorDisplayName, messageTime]
|
|
333
|
-
.filter(Boolean)
|
|
334
|
-
.join(" ");
|
|
335
|
-
if (!text && files.length === 0)
|
|
336
|
-
return null;
|
|
337
|
-
return (_jsx("div", { className: "group mb-1 mt-6", "data-message-id": message.id, "data-message-role": "user", children: _jsxs("div", { className: "flex flex-col items-end gap-2", children: [files.length > 0 && (_jsx("div", { className: "flex max-w-[85%] flex-wrap justify-end gap-2", children: files.map((file, index) => file.mediaType?.startsWith("image/") ? (_jsx("img", { src: file.url, alt: file.filename ?? "Attachment", className: "max-h-52 max-w-64 rounded-xl border border-border object-cover" }, `${file.url}:${index}`)) : (_jsx("span", { className: "rounded-lg border border-border bg-muted/30 px-3 py-2 text-xs text-muted-foreground", children: file.filename ?? "Attachment" }, `${file.url}:${index}`))) })), text && (_jsx("div", { className: "camel-user-message max-w-[85%] rounded-3xl border border-border bg-muted/30 px-4 py-3 text-foreground", children: _jsx(MessageResponse, { children: text }) })), text && (_jsxs("div", { className: "flex items-center justify-end gap-0.5 opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100 pointer-coarse:opacity-100", role: "group", "aria-label": "Message actions", children: [authorStamp && (_jsx("span", { className: "mr-1 text-xs text-muted-foreground", children: authorStamp })), _jsx(ClipboardAction, { text: text })] }))] }) }));
|
|
338
|
-
}
|
|
339
|
-
function standaloneText(message) {
|
|
340
|
-
const part = message.parts.find((candidate) => candidate.type.startsWith("data-"));
|
|
341
|
-
const data = dataOf(part);
|
|
342
|
-
return String(data.text ?? data.command ?? data.output ?? "").trim();
|
|
343
|
-
}
|
|
344
|
-
function CompactSummary({ message }) {
|
|
345
|
-
const text = standaloneText(message);
|
|
346
|
-
if (!text)
|
|
347
|
-
return null;
|
|
348
|
-
return (_jsxs("details", { className: "my-3 rounded-xl border border-border bg-muted/20 px-3 py-2 text-sm", "data-camel-compact-summary": "", "data-message-id": message.id, children: [_jsx("summary", { className: "cursor-pointer text-xs font-medium text-muted-foreground", children: "Compacted context" }), _jsx("div", { className: "mt-3 border-t border-border/40 pt-3", children: _jsx(MessageResponse, { children: text }) })] }));
|
|
349
|
-
}
|
|
350
|
-
function StandaloneMessage({ item }) {
|
|
351
|
-
const { message, displayKind } = item;
|
|
352
|
-
if (displayKind === "user")
|
|
353
|
-
return _jsx(UserMessage, { message: message });
|
|
354
|
-
if (displayKind === "compact-summary") {
|
|
355
|
-
return _jsx(CompactSummary, { message: message });
|
|
356
|
-
}
|
|
357
|
-
const text = standaloneText(message);
|
|
358
|
-
if (!text)
|
|
359
|
-
return null;
|
|
360
|
-
if (displayKind === "slash-command") {
|
|
361
|
-
return (_jsx("div", { className: "mt-4 flex justify-end", "data-message-id": message.id, "data-message-kind": "slash-command", children: _jsx("span", { className: "font-mono text-sm text-foreground", children: text }) }));
|
|
362
|
-
}
|
|
363
|
-
if (displayKind === "local-command-output") {
|
|
364
|
-
return (_jsx("div", { className: "mt-4 flex justify-start", "data-message-id": message.id, "data-message-kind": "local-command-output", children: _jsx("span", { className: "text-sm italic text-muted-foreground", children: text }) }));
|
|
365
|
-
}
|
|
366
|
-
return (_jsx("div", { className: "my-3 text-sm italic text-muted-foreground", "data-message-id": message.id, "data-message-kind": "notice", children: text }));
|
|
367
|
-
}
|
|
368
|
-
function RenderAssistantPart({ partRef, isActive, onApprove, onSuggestion, onAnswer, replyText, getToolApproval, resolveUrl, }) {
|
|
369
|
-
return (_jsx(AssistantPart, { part: partRef.part, isActive: isActive, onApprove: onApprove, onSuggestion: onSuggestion, onAnswer: onAnswer, replyText: replyText, getToolApproval: getToolApproval, resolveUrl: resolveUrl }, `${partRef.messageId}:${partRef.partIndex}:${String(recordOf(partRef.part).type ?? "part")}`));
|
|
370
|
-
}
|
|
371
|
-
function AssistantTurn({ turn, isActive, hasPendingSteer, hasPendingApproval, onFork, onApprove, onSuggestion, onAnswer, getToolApproval, resolveUrl, }) {
|
|
372
|
-
const renderPart = (partRef, active = false) => (_jsx(RenderAssistantPart, { partRef: partRef, isActive: active, onApprove: onApprove, onSuggestion: onSuggestion, onAnswer: onAnswer, replyText: turn.replyText, getToolApproval: getToolApproval, resolveUrl: resolveUrl }, `${partRef.messageId}:${partRef.partIndex}`));
|
|
373
|
-
const showWorkInPlace = isActive || hasPendingApproval || turn.terminalState !== undefined;
|
|
374
|
-
const showSummary = !showWorkInPlace && turn.traceParts.length > 0;
|
|
375
|
-
const completedAt = turn.completedAt ?? camelCompletedAt(turn.message);
|
|
376
|
-
const messageTime = completedAt === undefined ? null : formatCamelMessageTime(completedAt);
|
|
377
|
-
const hasActions = !showWorkInPlace && Boolean(messageTime || turn.copyText || onFork);
|
|
378
|
-
const thinkingActivity = deriveThinkingActivity(turn.traceParts.at(-1)?.part ?? turn.finalParts.at(-1)?.part);
|
|
379
|
-
const activeActivity = hasPendingSteer
|
|
380
|
-
? pendingSteerActivity
|
|
381
|
-
: thinkingActivity;
|
|
382
|
-
return (_jsx("div", { className: "group/turn", "data-message-id": turn.actionMessageId, "data-message-role": "assistant", "data-turn-step-count": turn.stepCount, translate: showWorkInPlace ? "no" : undefined, children: _jsxs("div", { className: "flex flex-col gap-1", children: [showSummary && (_jsx(TurnSummaryBar, { durationMs: turn.durationMs, stepCount: turn.stepCount, showSeparator: turn.finalParts.length > 0 || turn.terminalState !== undefined, children: turn.traceParts.map((partRef) => renderPart(partRef)) })), showWorkInPlace && turn.traceParts.length > 0 && (_jsx("div", { className: "max-w-none space-y-1", "data-camel-turn-trace": "", children: turn.traceParts.map((partRef) => renderPart(partRef, isActive)) })), (turn.finalParts.length > 0 ||
|
|
383
|
-
turn.terminalState?.kind === "error") && (_jsxs("div", { className: "max-w-none space-y-4", "data-camel-final-answer": "", children: [turn.finalParts.map((partRef) => renderPart(partRef, isActive)), turn.terminalState?.kind === "error" && (_jsxs("div", { className: "flex items-start gap-2 rounded-lg border border-destructive/25 bg-destructive/5 px-3 py-2 text-sm text-destructive", "data-part-type": "error", role: "alert", children: [_jsx(TriangleAlertIcon, { className: "mt-0.5 size-4 shrink-0" }), _jsxs("div", { children: [_jsx("div", { className: "font-medium", children: turn.terminalState.title }), turn.terminalState.body && (_jsx("div", { className: "mt-0.5 text-xs opacity-80", children: turn.terminalState.body }))] })] }))] })), turn.terminalState?.kind === "interrupted" && (_jsx("div", { className: "px-1 py-1 text-xs text-muted-foreground/60", "data-camel-turn-status": "interrupted", role: "status", children: turn.terminalState.title })), hasActions && (_jsxs("div", { className: "flex items-center gap-0.5 opacity-0 transition-opacity group-hover/turn:opacity-100 group-focus-within/turn:opacity-100 pointer-coarse:opacity-100", role: "group", "aria-label": "Message actions", children: [messageTime && (_jsx("span", { className: "mr-1 text-xs text-muted-foreground", children: messageTime })), onFork && (_jsx(ForkAction, { messageId: turn.actionMessageId, onFork: onFork })), turn.copyText && _jsx(ClipboardAction, { text: turn.copyText })] })), isActive && turn.finalParts.length === 0 && (_jsx(ThinkingIndicator, { ...activeActivity }))] }) }));
|
|
384
|
-
}
|
|
385
|
-
export function CamelChatMessages({ messages, status, finalToolNames, isHydrating = false, isRecovering = false, isServerStreaming = false, hasPendingSteer = false, startedWithPending = false, error, onRetry, onApprove, onSuggestion, onAnswer, onFork, getToolApproval, resolveUrl, inlineApprovalActions = true, }) {
|
|
386
|
-
const scrollRef = useRef(null);
|
|
387
|
-
const endRef = useRef(null);
|
|
388
|
-
const [showScrollButton, setShowScrollButton] = useState(false);
|
|
389
|
-
const isActive = status === "submitted" || status === "streaming";
|
|
390
|
-
const items = useMemo(() => projectCamelMessages(messages, finalToolNames), [messages, finalToolNames]);
|
|
391
|
-
const presentedToolApproval = (part) => {
|
|
392
|
-
const approval = getToolApproval?.(part) ?? toolApprovalOf(part);
|
|
393
|
-
return !inlineApprovalActions && approval?.approved === undefined && approval
|
|
394
|
-
? { ...approval, approved: false }
|
|
395
|
-
: approval;
|
|
396
|
-
};
|
|
397
|
-
const lastItem = items.at(-1);
|
|
398
|
-
const activeAssistantMessageId = isActive && lastItem?.kind === "assistant"
|
|
399
|
-
? lastItem.actionMessageId
|
|
400
|
-
: null;
|
|
401
|
-
const syncScrollButton = useCallback(() => {
|
|
402
|
-
const element = scrollRef.current;
|
|
403
|
-
if (!element)
|
|
404
|
-
return;
|
|
405
|
-
const distance = element.scrollHeight - element.scrollTop - element.clientHeight;
|
|
406
|
-
setShowScrollButton(distance > 120);
|
|
407
|
-
}, []);
|
|
408
|
-
useEffect(() => {
|
|
409
|
-
const element = scrollRef.current;
|
|
410
|
-
if (!element || showScrollButton)
|
|
411
|
-
return;
|
|
412
|
-
element.scrollTo({ top: element.scrollHeight });
|
|
413
|
-
}, [messages, status, showScrollButton]);
|
|
414
|
-
return (_jsxs("div", { className: "relative flex min-h-0 flex-1 flex-col overflow-hidden", "data-sb-message-panel": "", "data-camel-chat-transcript": "", "data-status": status, "aria-busy": isActive || isHydrating, children: [(isRecovering || isServerStreaming) && (_jsxs("div", { className: "absolute inset-x-0 top-0 z-10 flex h-7 items-center justify-center gap-2 bg-background/85 text-xs text-muted-foreground backdrop-blur-sm", role: "status", children: [_jsx("span", { className: "size-1.5 animate-pulse rounded-full bg-blue-500" }), isRecovering ? "Recovering…" : "Running…"] })), _jsx("div", { ref: scrollRef, onScroll: syncScrollButton, tabIndex: 0, role: "region", "aria-label": "Chat messages", className: "flex min-h-0 flex-1 flex-col overflow-y-auto overflow-x-hidden", children: _jsxs("div", { className: "mx-auto flex w-full max-w-3xl flex-col px-4 pb-6 pt-2 md:px-6", children: [messages.length === 0 && !startedWithPending && !isHydrating ? (_jsx("div", { className: "flex min-h-56 items-center justify-center text-center font-[family-name:var(--font-display)] text-4xl text-foreground", children: "How can I help?" })) : null, items.map((item) => item.kind === "assistant" ? (_jsx(AssistantTurn, { turn: item, isActive: item.actionMessageId === activeAssistantMessageId, hasPendingSteer: hasPendingSteer, hasPendingApproval: item.parts.some((partRef) => {
|
|
415
|
-
const approval = getToolApproval?.(partRef.part) ??
|
|
416
|
-
toolApprovalOf(partRef.part);
|
|
417
|
-
return approval != null && approval.approved === undefined;
|
|
418
|
-
}), onFork: onFork, onApprove: onApprove, onSuggestion: onSuggestion, onAnswer: onAnswer, getToolApproval: presentedToolApproval, resolveUrl: resolveUrl }, item.key)) : (_jsx(StandaloneMessage, { item: item }, item.key))), error != null && _jsx(CamelChatError, { error: error, onRetry: onRetry }), isActive && activeAssistantMessageId === null && (_jsx(ThinkingIndicator, { ...(hasPendingSteer ? pendingSteerActivity : {}) })), _jsx("div", { ref: endRef })] }) }), _jsx("div", { className: "pointer-events-none absolute inset-x-0 bottom-0 h-8 bg-gradient-to-t from-background to-transparent" }), _jsx(Button, { type: "button", variant: "outline", size: "icon", className: cn("absolute bottom-3 left-1/2 z-20 -translate-x-1/2 rounded-full border-border/50 bg-background/80 shadow-md backdrop-blur-sm transition-all duration-200", showScrollButton
|
|
419
|
-
? "translate-y-0 opacity-100"
|
|
420
|
-
: "pointer-events-none translate-y-2 opacity-0"), onClick: () => endRef.current?.scrollIntoView({ behavior: "smooth" }), "aria-label": "Scroll to bottom", children: _jsx(ArrowDownIcon, { className: "size-4" }) }), isHydrating && (_jsx("div", { className: "absolute inset-0 z-30 grid place-items-center bg-background/90", children: _jsx("span", { className: "text-sm text-muted-foreground", children: "Loading conversation\u2026" }) }))] }));
|
|
421
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export interface CamelModelOption {
|
|
2
|
-
value: string;
|
|
3
|
-
label: string;
|
|
4
|
-
hint?: string;
|
|
5
|
-
}
|
|
6
|
-
export interface CamelModelSelectProps {
|
|
7
|
-
value: string;
|
|
8
|
-
options: readonly CamelModelOption[];
|
|
9
|
-
disabled?: boolean;
|
|
10
|
-
label?: string;
|
|
11
|
-
onValueChange: (value: string) => void;
|
|
12
|
-
}
|
|
13
|
-
export declare function CamelModelSelect({ value, options, disabled, label, onValueChange, }: CamelModelSelectProps): import("react").JSX.Element;
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { CheckIcon, ChevronDownIcon, ZapIcon } from "lucide-react";
|
|
3
|
-
import { Select as SelectPrimitive } from "radix-ui";
|
|
4
|
-
export function CamelModelSelect({ value, options, disabled, label = "Select model", onValueChange, }) {
|
|
5
|
-
const selected = options.find((option) => option.value === value);
|
|
6
|
-
return (_jsxs(SelectPrimitive.Root, { value: value, disabled: disabled, onValueChange: onValueChange, children: [_jsxs(SelectPrimitive.Trigger, { "data-camel-model-select": "", "aria-label": label, title: label, className: "inline-flex h-8 max-w-60 shrink-0 items-center justify-center gap-1.5 rounded-md px-1.5 text-sm font-medium text-foreground/90 outline-none transition-colors hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50", children: [_jsx(ZapIcon, { className: "size-[17px] shrink-0 text-foreground/90", strokeWidth: 1.8 }), _jsx(SelectPrimitive.Value, { className: "max-w-40 truncate text-[15px]", children: selected?.label ?? value }), _jsx(SelectPrimitive.Icon, { asChild: true, children: _jsx(ChevronDownIcon, { className: "size-4 shrink-0 text-muted-foreground", strokeWidth: 1.8 }) })] }), _jsx(SelectPrimitive.Portal, { children: _jsx(SelectPrimitive.Content, { "data-camel-model-select-content": "", position: "popper", align: "start", sideOffset: 4, className: "z-50 w-72 overflow-hidden rounded-md border border-border bg-popover text-popover-foreground shadow-md data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95", children: _jsx(SelectPrimitive.Viewport, { className: "max-h-80 overflow-y-auto p-1", children: options.map((option) => (_jsxs(SelectPrimitive.Item, { value: option.value, className: "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", children: [_jsx(SelectPrimitive.ItemText, { className: "w-full", children: _jsxs("span", { className: "flex min-w-0 items-center justify-between gap-3", children: [_jsx("span", { className: "truncate", children: option.label }), option.hint && (_jsx("span", { className: "shrink-0 text-xs text-muted-foreground", children: option.hint }))] }) }), _jsx(SelectPrimitive.ItemIndicator, { className: "absolute right-2 flex size-4 items-center justify-center", children: _jsx(CheckIcon, { className: "size-4" }) })] }, option.value))) }) }) })] }));
|
|
7
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { CheckIcon, ChevronDownIcon, CircleIcon } from "lucide-react";
|
|
3
|
-
import { useId, useMemo, useState } from "react";
|
|
4
|
-
import { cn } from "../internal/cn";
|
|
5
|
-
import { projectLatestPlan } from "../parts/plan";
|
|
6
|
-
export function CamelPlanBar({ messages }) {
|
|
7
|
-
const [open, setOpen] = useState(false);
|
|
8
|
-
const contentId = useId();
|
|
9
|
-
const steps = useMemo(() => projectLatestPlan(messages), [messages]);
|
|
10
|
-
if (!steps || steps.length === 0)
|
|
11
|
-
return null;
|
|
12
|
-
const doneCount = steps.filter((step) => step.status === "done").length;
|
|
13
|
-
const activeIndex = steps.findIndex((step) => step.status !== "done");
|
|
14
|
-
const allDone = activeIndex === -1;
|
|
15
|
-
const headline = steps[allDone ? steps.length - 1 : activeIndex];
|
|
16
|
-
return (_jsx("section", { className: "shrink-0 bg-background px-4 pt-2", "data-camel-plan-bar": "", "aria-label": "Task progress", children: _jsxs("div", { className: "mx-auto w-full max-w-3xl rounded-2xl border border-border bg-card shadow-[0_8px_16px_rgb(0_0_0/0.12)]", children: [_jsxs("button", { type: "button", className: "group flex w-full items-center gap-2 rounded-2xl px-4 py-2.5 text-left", "aria-expanded": open, "aria-controls": contentId, onClick: () => setOpen((current) => !current), children: [_jsxs("span", { className: "relative flex h-5 min-w-0 flex-1 items-center gap-2 overflow-hidden", children: [allDone ? (_jsx(CheckIcon, { className: "size-4 shrink-0 text-success" })) : (_jsx("span", { className: "flex size-4 shrink-0 items-center justify-center", children: _jsx("span", { className: "size-2 animate-manus-pulse rounded-full bg-primary" }) })), _jsx("span", { className: "min-w-0 truncate text-sm text-foreground", title: headline.text, children: headline.text })] }), _jsxs("span", { className: "shrink-0 text-[13px] tabular-nums text-muted-foreground", children: [doneCount, " / ", steps.length] }), _jsx(ChevronDownIcon, { className: cn("size-4 shrink-0 text-muted-foreground transition-transform duration-200", open && "rotate-180") })] }), _jsx("div", { id: contentId, "data-camel-plan-content": "", "data-camel-collapsible-content": "", "data-state": open ? "open" : "closed", "aria-hidden": !open, inert: !open ? true : undefined, children: _jsx("div", { "data-camel-collapsible-inner": "", children: _jsxs("div", { className: "px-4 pb-3", children: [_jsx("p", { className: "text-[13px] text-muted-foreground", children: "Task progress" }), _jsx("div", { className: "mt-2 max-h-72 space-y-2 overflow-y-auto overflow-x-hidden", children: steps.map((step, index) => {
|
|
17
|
-
const active = !allDone && index === activeIndex;
|
|
18
|
-
return (_jsxs("div", { className: "flex w-full min-w-0 items-center gap-2", children: [_jsx("span", { className: "flex h-5 w-4 shrink-0 items-center justify-center", children: step.status === "done" ? (_jsx(CheckIcon, { className: "size-4 text-success" })) : active ? (_jsx("span", { className: "size-2 animate-manus-pulse rounded-full bg-primary" })) : (_jsx(CircleIcon, { className: "size-3.5 text-muted-foreground/40" })) }), _jsx("span", { className: cn("min-w-0 flex-1 truncate text-sm", active
|
|
19
|
-
? "font-medium text-foreground"
|
|
20
|
-
: step.status === "done"
|
|
21
|
-
? "text-foreground"
|
|
22
|
-
: "text-muted-foreground"), title: step.text, children: step.text })] }, `${index}:${step.text}`));
|
|
23
|
-
}) })] }) }) })] }) }));
|
|
24
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { type ReactNode } from "react";
|
|
2
|
-
import type { ComposerCommand } from "../composer/types";
|
|
3
|
-
export interface CamelAttachmentView {
|
|
4
|
-
id: string;
|
|
5
|
-
filename?: string;
|
|
6
|
-
mediaType?: string;
|
|
7
|
-
size?: number;
|
|
8
|
-
url: string;
|
|
9
|
-
status: "uploading" | "ready" | "error";
|
|
10
|
-
}
|
|
11
|
-
interface CamelPromptInputProps {
|
|
12
|
-
value: string;
|
|
13
|
-
onChange: (value: string) => void;
|
|
14
|
-
onSubmit: () => void;
|
|
15
|
-
onStop: () => void;
|
|
16
|
-
status: "ready" | "submitted" | "streaming" | "error";
|
|
17
|
-
attachments: readonly CamelAttachmentView[];
|
|
18
|
-
commands: readonly ComposerCommand[];
|
|
19
|
-
onFilesSelected?: (files: readonly File[]) => void;
|
|
20
|
-
onAttachmentRemove: (id: string) => void;
|
|
21
|
-
onAttachmentRetry: (id: string) => void;
|
|
22
|
-
tools?: ReactNode;
|
|
23
|
-
/** Compact delivery selector rendered immediately beside the submit button. */
|
|
24
|
-
submitControl?: ReactNode;
|
|
25
|
-
placeholder?: string;
|
|
26
|
-
/** Durable Turn activity can outlive the local chat stream status. */
|
|
27
|
-
turnActive?: boolean;
|
|
28
|
-
/** Blocks new submissions without disabling the stop control for an active Turn. */
|
|
29
|
-
submissionBlocked?: boolean;
|
|
30
|
-
}
|
|
31
|
-
export declare function CamelPromptInput(props: CamelPromptInputProps): import("react").JSX.Element;
|
|
32
|
-
export {};
|