@springbrand/message-panel 0.1.2 → 0.1.3-alpha.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.
Files changed (99) hide show
  1. package/demo/camel-chat-showcase.tsx +1265 -0
  2. package/demo/fixtures.ts +292 -0
  3. package/demo/message-panel-chat-showcase.tsx +250 -0
  4. package/demo/message-panel-gallery.tsx +389 -0
  5. package/package.json +6 -16
  6. package/src/adapters/ai-sdk.ts +32 -0
  7. package/src/camel/camel-chat-messages.tsx +1423 -0
  8. package/src/camel/camel-model-select.tsx +88 -0
  9. package/src/camel/camel-plan-bar.tsx +115 -0
  10. package/src/camel/camel-prompt-input.tsx +547 -0
  11. package/src/camel/camel-tool-presentation.tsx +1270 -0
  12. package/src/camel/camel-turn.ts +316 -0
  13. package/src/camel/turn-summary-bar.tsx +81 -0
  14. package/src/chat-summary-panel.tsx +229 -0
  15. package/src/composer/chat-composer.tsx +216 -0
  16. package/src/composer/composer-attachments.tsx +138 -0
  17. package/src/composer/composer-trigger-popover.tsx +236 -0
  18. package/src/composer/composer.tsx +425 -0
  19. package/src/composer/drop-controller.ts +80 -0
  20. package/src/composer/types.ts +79 -0
  21. package/src/contracts.ts +138 -0
  22. package/src/conversation.tsx +76 -0
  23. package/src/internal/cn.ts +3 -0
  24. package/src/message-panel.tsx +368 -0
  25. package/src/message.tsx +254 -0
  26. package/src/parts/index.tsx +1149 -0
  27. package/src/parts/kind.ts +67 -0
  28. package/src/parts/plan.ts +63 -0
  29. package/src/parts/primitives.tsx +439 -0
  30. package/src/registry.ts +44 -0
  31. package/src/status.tsx +132 -0
  32. package/dist/demo/camel-chat-showcase.d.ts +0 -1
  33. package/dist/demo/camel-chat-showcase.js +0 -1007
  34. package/dist/demo/fixtures.d.ts +0 -32
  35. package/dist/demo/fixtures.js +0 -250
  36. package/dist/demo/index.js +0 -4
  37. package/dist/demo/message-panel-chat-showcase.d.ts +0 -1
  38. package/dist/demo/message-panel-chat-showcase.js +0 -114
  39. package/dist/demo/message-panel-gallery.d.ts +0 -1
  40. package/dist/demo/message-panel-gallery.js +0 -130
  41. package/dist/src/adapters/ai-sdk.d.ts +0 -4
  42. package/dist/src/adapters/ai-sdk.js +0 -25
  43. package/dist/src/camel/camel-chat-messages.d.ts +0 -44
  44. package/dist/src/camel/camel-chat-messages.js +0 -421
  45. package/dist/src/camel/camel-model-select.d.ts +0 -13
  46. package/dist/src/camel/camel-model-select.js +0 -7
  47. package/dist/src/camel/camel-plan-bar.d.ts +0 -5
  48. package/dist/src/camel/camel-plan-bar.js +0 -24
  49. package/dist/src/camel/camel-prompt-input.d.ts +0 -32
  50. package/dist/src/camel/camel-prompt-input.js +0 -182
  51. package/dist/src/camel/camel-tool-presentation.d.ts +0 -21
  52. package/dist/src/camel/camel-tool-presentation.js +0 -784
  53. package/dist/src/camel/camel-turn.d.ts +0 -57
  54. package/dist/src/camel/camel-turn.js +0 -203
  55. package/dist/src/camel/index.js +0 -7
  56. package/dist/src/camel/turn-summary-bar.d.ts +0 -8
  57. package/dist/src/camel/turn-summary-bar.js +0 -12
  58. package/dist/src/chat-summary-panel.d.ts +0 -22
  59. package/dist/src/chat-summary-panel.js +0 -26
  60. package/dist/src/composer/chat-composer.d.ts +0 -4
  61. package/dist/src/composer/chat-composer.js +0 -90
  62. package/dist/src/composer/composer-attachments.d.ts +0 -13
  63. package/dist/src/composer/composer-attachments.js +0 -47
  64. package/dist/src/composer/composer-trigger-popover.d.ts +0 -31
  65. package/dist/src/composer/composer-trigger-popover.js +0 -29
  66. package/dist/src/composer/composer.d.ts +0 -15
  67. package/dist/src/composer/composer.js +0 -180
  68. package/dist/src/composer/drop-controller.d.ts +0 -8
  69. package/dist/src/composer/drop-controller.js +0 -69
  70. package/dist/src/composer/index.js +0 -6
  71. package/dist/src/composer/types.d.ts +0 -62
  72. package/dist/src/composer/types.js +0 -1
  73. package/dist/src/contracts.d.ts +0 -94
  74. package/dist/src/contracts.js +0 -1
  75. package/dist/src/conversation.d.ts +0 -13
  76. package/dist/src/conversation.js +0 -18
  77. package/dist/src/index.js +0 -12
  78. package/dist/src/internal/cn.d.ts +0 -1
  79. package/dist/src/internal/cn.js +0 -3
  80. package/dist/src/message-panel.d.ts +0 -4
  81. package/dist/src/message-panel.js +0 -144
  82. package/dist/src/message.d.ts +0 -36
  83. package/dist/src/message.js +0 -83
  84. package/dist/src/parts/index.d.ts +0 -187
  85. package/dist/src/parts/index.js +0 -332
  86. package/dist/src/parts/kind.d.ts +0 -3
  87. package/dist/src/parts/kind.js +0 -69
  88. package/dist/src/parts/plan.d.ts +0 -10
  89. package/dist/src/parts/plan.js +0 -40
  90. package/dist/src/parts/primitives.d.ts +0 -70
  91. package/dist/src/parts/primitives.js +0 -153
  92. package/dist/src/registry.d.ts +0 -4
  93. package/dist/src/registry.js +0 -31
  94. package/dist/src/status.d.ts +0 -26
  95. package/dist/src/status.js +0 -74
  96. /package/{dist/demo/index.d.ts → demo/index.ts} +0 -0
  97. /package/{dist/src/camel/index.d.ts → src/camel/index.ts} +0 -0
  98. /package/{dist/src/composer/index.d.ts → src/composer/index.ts} +0 -0
  99. /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,5 +0,0 @@
1
- import type { UIMessage } from "ai";
2
- export interface CamelPlanBarProps {
3
- messages: readonly UIMessage[];
4
- }
5
- export declare function CamelPlanBar({ messages }: CamelPlanBarProps): import("react").JSX.Element | null;
@@ -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 {};