@springbrand/message-panel 0.1.3-alpha.8 → 0.2.0-alpha.37
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/cloud-os/README.md +4 -3
- package/cloud-os/assets/followup-arrow.svg +3 -0
- package/cloud-os/assets/loading-corner.svg +3 -0
- package/cloud-os/assets/loading-mark.svg +16 -0
- package/cloud-os/assets/loading-spark.svg +3 -0
- package/cloud-os/assets/model-selected.svg +5 -0
- package/cloud-os/assets/thinking-star.svg +9 -0
- package/cloud-os/capability-chip.tsx +1 -1
- package/cloud-os/chat/cloud-os-chat-messages.tsx +441 -98
- package/cloud-os/chat/code-runner.tsx +106 -0
- package/cloud-os/chat/image-generation.tsx +76 -0
- package/cloud-os/chat/loading-state.tsx +25 -0
- package/cloud-os/chat/markdown-message.tsx +144 -41
- package/cloud-os/chat/range.ts +8 -0
- package/cloud-os/chat/rich-blocks.tsx +285 -227
- package/cloud-os/chat/surfaces.tsx +90 -0
- package/cloud-os/chat/tool-call.tsx +94 -0
- package/cloud-os/chat/tool-presentation.ts +31 -22
- package/cloud-os/chat/tool-rows.tsx +195 -143
- package/cloud-os/chat/tool-timeline.tsx +123 -0
- package/cloud-os/chat/transcript-model.ts +258 -20
- package/cloud-os/chat/web-search.tsx +135 -0
- package/cloud-os/composer/cloud-os-chat-input.tsx +38 -88
- package/cloud-os/composer/cloud-os-model-select.tsx +105 -0
- package/cloud-os/file-view.tsx +195 -12
- package/cloud-os/index.ts +24 -3
- package/cloud-os/layout/cloud-os-workspace-split.tsx +60 -3
- package/cloud-os/primitives/collapsible.tsx +21 -0
- package/cloud-os/primitives/workshop-controls.tsx +2 -2
- package/cloud-os/styles/cloud-os.css +132 -1
- package/demo/camel-chat-showcase.tsx +21 -13
- package/demo/chat-scenarios.ts +214 -40
- package/demo/cloud-os-chat-showcase.tsx +37 -14
- package/demo/fixtures.ts +4 -5
- package/demo/message-panel-gallery.tsx +16 -2
- package/package.json +8 -4
- package/springbrand-pet/LICENSE.bloub +21 -0
- package/springbrand-pet/bot/cycles.test.ts +221 -0
- package/springbrand-pet/bot/cycles.ts +225 -0
- package/springbrand-pet/bot/decor.ts +285 -0
- package/springbrand-pet/bot/engine.test.ts +543 -0
- package/springbrand-pet/bot/engine.ts +558 -0
- package/springbrand-pet/bot/expressions.test.ts +135 -0
- package/springbrand-pet/bot/expressions.ts +192 -0
- package/springbrand-pet/bot/eyefit.ts +455 -0
- package/springbrand-pet/bot/face.test.ts +101 -0
- package/springbrand-pet/bot/face.ts +179 -0
- package/springbrand-pet/bot/math.ts +42 -0
- package/springbrand-pet/bot/profiles.ts +22 -0
- package/springbrand-pet/bot/repere.ts +31 -0
- package/springbrand-pet/bot/shape.test.ts +97 -0
- package/springbrand-pet/bot/shape.ts +310 -0
- package/springbrand-pet/bot/skins.test.ts +325 -0
- package/springbrand-pet/bot/skins.ts +161 -0
- package/springbrand-pet/bot/states.ts +616 -0
- package/springbrand-pet/drag.test.ts +19 -0
- package/springbrand-pet/index.tsx +569 -0
- package/springbrand-pet/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
- package/springbrand-pet/vitest.config.ts +9 -0
- package/src/camel/camel-chat-messages.tsx +78 -78
- package/src/camel/camel-tool-presentation.tsx +19 -15
- package/src/camel/camel-turn.ts +1 -17
- package/src/composer/composer-attachments.tsx +1 -1
- package/src/composer/composer.tsx +2 -2
- package/src/contracts.ts +0 -2
- package/src/message-panel.tsx +1 -24
- package/src/parts/index.tsx +103 -64
package/cloud-os/index.ts
CHANGED
|
@@ -20,8 +20,12 @@ export type {
|
|
|
20
20
|
FileViewPlacement,
|
|
21
21
|
FileViewProps,
|
|
22
22
|
FileViewStatus,
|
|
23
|
+
FileViewVariant,
|
|
23
24
|
} from "./file-view";
|
|
24
|
-
export {
|
|
25
|
+
export {
|
|
26
|
+
CloudOsConversationLoading,
|
|
27
|
+
CloudOsWorkspaceSplit,
|
|
28
|
+
} from "./layout/cloud-os-workspace-split";
|
|
25
29
|
export type { CloudOsWorkspaceSplitProps } from "./layout/cloud-os-workspace-split";
|
|
26
30
|
|
|
27
31
|
export { CloudOsChatMessages } from "./chat/cloud-os-chat-messages";
|
|
@@ -36,8 +40,12 @@ export type {
|
|
|
36
40
|
CloudOsCapabilityView,
|
|
37
41
|
CloudOsChatInputProps,
|
|
38
42
|
CloudOsComposerCommand,
|
|
39
|
-
CloudOsModelOption,
|
|
40
43
|
} from "./composer/cloud-os-chat-input";
|
|
44
|
+
export { CloudOsModelSelect } from "./composer/cloud-os-model-select";
|
|
45
|
+
export type {
|
|
46
|
+
CloudOsModelOption,
|
|
47
|
+
CloudOsModelSelectProps,
|
|
48
|
+
} from "./composer/cloud-os-model-select";
|
|
41
49
|
|
|
42
50
|
export {
|
|
43
51
|
CloudOsWorkspacePanel,
|
|
@@ -53,13 +61,26 @@ export type {
|
|
|
53
61
|
} from "./workspace/cloud-os-workspace-panel";
|
|
54
62
|
|
|
55
63
|
export { MarkdownMessage } from "./chat/markdown-message";
|
|
56
|
-
export type {
|
|
64
|
+
export type {
|
|
65
|
+
CloudOsArtifactResolver,
|
|
66
|
+
CloudOsUrlResolver,
|
|
67
|
+
} from "./chat/markdown-message";
|
|
57
68
|
export {
|
|
58
69
|
ThinkingTraceRow,
|
|
59
70
|
ToolCallDetails,
|
|
60
71
|
ToolGroupRow,
|
|
61
72
|
WorkIcon,
|
|
62
73
|
} from "./chat/tool-rows";
|
|
74
|
+
export { ToolCall } from "./chat/tool-call";
|
|
75
|
+
export type { ToolCallProps } from "./chat/tool-call";
|
|
76
|
+
export { CodeRunner } from "./chat/code-runner";
|
|
77
|
+
export type { RunState } from "./chat/code-runner";
|
|
78
|
+
export { ToolTimeline } from "./chat/tool-timeline";
|
|
79
|
+
export type {
|
|
80
|
+
TimelineStat,
|
|
81
|
+
TimelineStep,
|
|
82
|
+
ToolTimelineProps,
|
|
83
|
+
} from "./chat/tool-timeline";
|
|
63
84
|
export {
|
|
64
85
|
ApprovalBlock,
|
|
65
86
|
AskUserBlock,
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
type PointerEvent as ReactPointerEvent,
|
|
7
7
|
type ReactNode,
|
|
8
8
|
} from "react";
|
|
9
|
+
import { motion, useReducedMotion } from "motion/react";
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* 左聊天 / 右工作区的双栏骨架。从 cloudflare-os-main `GadgetEditor.tsx` 的 BODY
|
|
@@ -17,14 +18,64 @@ import {
|
|
|
17
18
|
*/
|
|
18
19
|
|
|
19
20
|
const CHAT_WIDTH_STORAGE_KEY = "cloud-os:chatWidth";
|
|
20
|
-
const MIN_CHAT_WIDTH =
|
|
21
|
+
const MIN_CHAT_WIDTH = 360;
|
|
21
22
|
const MIN_WORKSPACE_WIDTH = 400;
|
|
22
23
|
const DEFAULT_CHAT_WIDTH = 420;
|
|
23
24
|
const WORKSPACE_TRANSITION_MS = 200;
|
|
24
25
|
|
|
25
26
|
const isBrowser = typeof window !== "undefined";
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
const loadingAssets = {
|
|
29
|
+
spark: new URL("../assets/loading-spark.svg", import.meta.url).href,
|
|
30
|
+
corner: new URL("../assets/loading-corner.svg", import.meta.url).href,
|
|
31
|
+
mark: new URL("../assets/loading-mark.svg", import.meta.url).href,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const loadingSpring = (t: number) =>
|
|
35
|
+
1 - Math.exp(-t * 7.6657) * (Math.cos(t * 6.7605) + 1.1339 * Math.sin(t * 6.7605));
|
|
36
|
+
|
|
37
|
+
export function CloudOsConversationLoading() {
|
|
38
|
+
const reducedMotion = useReducedMotion();
|
|
39
|
+
const repeat = reducedMotion ? 0 : Infinity;
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<div className="absolute inset-0 z-30 grid place-items-center bg-kumo-base/90">
|
|
43
|
+
<div role="status" aria-label="Loading conversation..." className="flex flex-col items-center gap-4">
|
|
44
|
+
<div className="relative h-[49px] w-[49px] overflow-hidden" aria-hidden="true">
|
|
45
|
+
<motion.img
|
|
46
|
+
src={loadingAssets.spark}
|
|
47
|
+
alt=""
|
|
48
|
+
className="absolute bottom-[18.5%] right-[61.46%] h-[20.04%] w-[20.04%] will-change-transform"
|
|
49
|
+
initial={reducedMotion ? false : { opacity: 0, rotate: 200, scaleX: 0.5, scaleY: 0.5, x: -140, y: 120 }}
|
|
50
|
+
animate={reducedMotion ? { opacity: 1, rotate: 0, scaleX: 1, scaleY: 1, x: 0, y: 0 } : { opacity: [0, 0, 1, 1, 0, 0], rotate: [200, 200, 10, 0, 0, 200, 200], scaleX: [0.5, 0.5, 1.3, 0.8, 1, 1], scaleY: [0.5, 0.5, 0.75, 1.2, 1, 1], x: [-140, -140, 2, 0, 0, -140, -140], y: [120, 120, -2, 0, 0, 120, 120] }}
|
|
51
|
+
transition={{ opacity: { duration: 1.68, times: [0, 0.2083, 0.25, 0.9998, 0.9999, 1], ease: ["linear", "linear", "linear", "easeIn", "linear"], repeat }, rotate: { duration: 1.68, times: [0, 0.2083, 0.3869, 0.506, 0.9998, 0.9999, 1], ease: ["linear", [0, 0, 0.15, 1], loadingSpring, "linear", "easeIn", "linear"], repeat }, scaleX: { duration: 1.68, times: [0, 0.2083, 0.3274, 0.3869, 0.506, 1], ease: ["linear", [0, 0, 0.15, 1], "easeOut", loadingSpring, "linear"], repeat }, scaleY: { duration: 1.68, times: [0, 0.2083, 0.3274, 0.3869, 0.506, 1], ease: ["linear", [0, 0, 0.15, 1], "easeOut", loadingSpring, "linear"], repeat }, x: { duration: 1.68, times: [0, 0.2083, 0.3869, 0.506, 0.9998, 0.9999, 1], ease: ["linear", [0, 0, 0.15, 1], loadingSpring, "linear", "easeIn", "linear"], repeat }, y: { duration: 1.68, times: [0, 0.2083, 0.3869, 0.506, 0.9998, 0.9999, 1], ease: ["linear", [0, 0, 0.15, 1], loadingSpring, "linear", "easeIn", "linear"], repeat } }}
|
|
52
|
+
/>
|
|
53
|
+
<motion.img
|
|
54
|
+
src={loadingAssets.corner}
|
|
55
|
+
alt=""
|
|
56
|
+
className="absolute bottom-[11.65%] right-[43.79%] h-[44.74%] w-[44.67%] will-change-transform"
|
|
57
|
+
initial={reducedMotion ? false : { opacity: 0, scaleX: 1, scaleY: 1, x: 0, y: 0 }}
|
|
58
|
+
animate={reducedMotion ? { opacity: 1, scaleX: 1, scaleY: 1, x: 0, y: 0 } : { opacity: [0, 1, 1, 0, 0], scaleX: [1, 1, 1.06, 1, 1], scaleY: [1, 1, 0.95, 1, 1], x: [0, 0, 4, 0, 0], y: [0, 0, -2, 0, 0] }}
|
|
59
|
+
transition={{ opacity: { duration: 1.68, times: [0, 0.1786, 0.9998, 0.9999, 1], ease: [[0, 0, 0.3, 1], "linear", "easeIn", "linear"], repeat }, scaleX: { duration: 1.68, times: [0, 0.3988, 0.4345, 0.6548, 1], ease: ["linear", [0.2, 0.9, 0.3, 1], loadingSpring, "linear"], repeat }, scaleY: { duration: 1.68, times: [0, 0.3988, 0.4345, 0.6548, 1], ease: ["linear", [0.2, 0.9, 0.3, 1], loadingSpring, "linear"], repeat }, x: { duration: 1.68, times: [0, 0.3988, 0.4345, 0.6845, 1], ease: ["linear", [0.2, 0.9, 0.3, 1], loadingSpring, "linear"], repeat }, y: { duration: 1.68, times: [0, 0.3988, 0.4345, 0.6845, 1], ease: ["linear", [0.2, 0.9, 0.3, 1], loadingSpring, "linear"], repeat } }}
|
|
60
|
+
/>
|
|
61
|
+
<motion.img
|
|
62
|
+
src={loadingAssets.mark}
|
|
63
|
+
alt=""
|
|
64
|
+
className="absolute bottom-[19.14%] right-[11.53%] h-[69.22%] w-[69.33%] will-change-transform"
|
|
65
|
+
initial={reducedMotion ? false : { opacity: 0, rotate: 0, scaleX: 0.85, scaleY: 0.85, x: 0, y: 0 }}
|
|
66
|
+
animate={reducedMotion ? { opacity: 1, rotate: 0, scaleX: 1, scaleY: 1, x: 0, y: 0 } : { opacity: [0, 1, 1, 0, 0], rotate: [0, 0, -3, 0, 0], scaleX: [0.85, 1, 1, 1.1, 0.95, 1, 1], scaleY: [0.85, 1, 1, 0.92, 1.05, 1, 1], x: [0, 0, 6, 0, 0], y: [0, 0, -4, 0, 0] }}
|
|
67
|
+
transition={{ opacity: { duration: 1.68, times: [0, 0.2083, 0.9998, 0.9999, 1], ease: [[0, 0, 0.3, 1], "linear", "easeIn", "linear"], repeat }, rotate: { duration: 1.68, times: [0, 0.3869, 0.4286, 0.6548, 1], ease: ["linear", [0.2, 0.9, 0.3, 1], loadingSpring, "linear"], repeat }, scaleX: { duration: 1.68, times: [0, 0.2083, 0.3869, 0.4167, 0.4643, 0.6548, 1], ease: [[0, 0, 0.3, 1], "linear", [0.2, 0.9, 0.3, 1], "easeOut", loadingSpring, "linear"], repeat }, scaleY: { duration: 1.68, times: [0, 0.2083, 0.3869, 0.4167, 0.4643, 0.6548, 1], ease: [[0, 0, 0.3, 1], "linear", [0.2, 0.9, 0.3, 1], "easeOut", loadingSpring, "linear"], repeat }, x: { duration: 1.68, times: [0, 0.3869, 0.4167, 0.6548, 1], ease: ["linear", [0.2, 0.9, 0.3, 1], loadingSpring, "linear"], repeat }, y: { duration: 1.68, times: [0, 0.3869, 0.4167, 0.6548, 1], ease: ["linear", [0.2, 0.9, 0.3, 1], loadingSpring, "linear"], repeat } }}
|
|
68
|
+
/>
|
|
69
|
+
</div>
|
|
70
|
+
<p className="m-0 text-center text-[14px] font-normal leading-[1.4] text-kumo-default">
|
|
71
|
+
Loading conversation...
|
|
72
|
+
</p>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function clampChatWidth(width: number, containerWidth?: number) {
|
|
28
79
|
if (!isBrowser) {
|
|
29
80
|
return Math.max(MIN_CHAT_WIDTH, Math.min(DEFAULT_CHAT_WIDTH, width));
|
|
30
81
|
}
|
|
@@ -62,6 +113,8 @@ export interface CloudOsWorkspaceSplitProps {
|
|
|
62
113
|
/** 右栏收起时依然保留的窄边栏宽度(原文件的 Outputs rail)。 */
|
|
63
114
|
railWidth?: number;
|
|
64
115
|
rail?: ReactNode;
|
|
116
|
+
/** 覆盖整个聊天 + 工作区主体;页面级导航应放在分栏外。 */
|
|
117
|
+
isLoading?: boolean;
|
|
65
118
|
}
|
|
66
119
|
|
|
67
120
|
export function CloudOsWorkspaceSplit({
|
|
@@ -70,6 +123,7 @@ export function CloudOsWorkspaceSplit({
|
|
|
70
123
|
workspaceOpen,
|
|
71
124
|
railWidth = 0,
|
|
72
125
|
rail,
|
|
126
|
+
isLoading = false,
|
|
73
127
|
}: CloudOsWorkspaceSplitProps) {
|
|
74
128
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
75
129
|
const resizeSessionRef = useRef<ResizeSession | null>(null);
|
|
@@ -184,6 +238,7 @@ export function CloudOsWorkspaceSplit({
|
|
|
184
238
|
<div
|
|
185
239
|
ref={containerRef}
|
|
186
240
|
className="relative flex h-full min-h-0 flex-1 overflow-hidden bg-kumo-base"
|
|
241
|
+
aria-busy={isLoading}
|
|
187
242
|
>
|
|
188
243
|
{/* ── 左:聊天 ──────────────────────────────────────────────────────── */}
|
|
189
244
|
<div
|
|
@@ -199,7 +254,7 @@ export function CloudOsWorkspaceSplit({
|
|
|
199
254
|
|
|
200
255
|
{/* ── 拖拽把手 ─────────────────────────────────────────────────────── */}
|
|
201
256
|
<div
|
|
202
|
-
className={`relative flex-shrink-0 cursor-col-resize touch-none overflow-visible bg-kumo-line ${transitionClass}`}
|
|
257
|
+
className={`cos-workspace-divider relative flex-shrink-0 cursor-col-resize touch-none overflow-visible bg-kumo-line ${transitionClass}`}
|
|
203
258
|
style={{ width: workspaceOpen ? 1 : 0 }}
|
|
204
259
|
onPointerDown={handleResizePointerDown}
|
|
205
260
|
onPointerMove={handleResizePointerMove}
|
|
@@ -223,6 +278,8 @@ export function CloudOsWorkspaceSplit({
|
|
|
223
278
|
</div>
|
|
224
279
|
|
|
225
280
|
{rail}
|
|
281
|
+
|
|
282
|
+
{isLoading && <CloudOsConversationLoading />}
|
|
226
283
|
</div>
|
|
227
284
|
);
|
|
228
285
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Collapsible as CollapsiblePrimitive } from "@base-ui/react/collapsible";
|
|
4
|
+
|
|
5
|
+
function Collapsible({ ...props }: CollapsiblePrimitive.Root.Props) {
|
|
6
|
+
return <CollapsiblePrimitive.Root data-slot="collapsible" {...props} />;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function CollapsibleTrigger({ ...props }: CollapsiblePrimitive.Trigger.Props) {
|
|
10
|
+
return (
|
|
11
|
+
<CollapsiblePrimitive.Trigger data-slot="collapsible-trigger" {...props} />
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function CollapsibleContent({ ...props }: CollapsiblePrimitive.Panel.Props) {
|
|
16
|
+
return (
|
|
17
|
+
<CollapsiblePrimitive.Panel data-slot="collapsible-content" {...props} />
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export { Collapsible, CollapsibleTrigger, CollapsibleContent };
|
|
@@ -11,7 +11,7 @@ const buttonBaseClassName =
|
|
|
11
11
|
|
|
12
12
|
const buttonToneClassNames = {
|
|
13
13
|
primary:
|
|
14
|
-
"!h-9 bg-
|
|
14
|
+
"!h-9 bg-gradient-to-br from-[#FFD077] to-[#FF9938] px-3 text-white enabled:hover:opacity-90 disabled:opacity-50",
|
|
15
15
|
secondary:
|
|
16
16
|
"!h-8 border border-kumo-line bg-kumo-base px-3 text-kumo-default enabled:hover:bg-kumo-elevated disabled:opacity-40",
|
|
17
17
|
danger:
|
|
@@ -59,7 +59,7 @@ export function WorkshopIconButton({
|
|
|
59
59
|
}: WorkshopIconButtonProps) {
|
|
60
60
|
const toneClassName =
|
|
61
61
|
tone === "primary"
|
|
62
|
-
? "bg-kumo-
|
|
62
|
+
? "bg-[var(--primary,var(--color-kumo-brand))] text-[var(--primary-foreground,var(--text-color-kumo-inverse))] enabled:hover:bg-[var(--primary-hover,var(--color-kumo-brand-hover))]"
|
|
63
63
|
: danger
|
|
64
64
|
? "text-kumo-subtle enabled:hover:bg-kumo-danger-tint enabled:hover:text-kumo-danger"
|
|
65
65
|
: "text-kumo-subtle enabled:hover:bg-kumo-tint enabled:hover:text-kumo-default";
|
|
@@ -99,6 +99,7 @@
|
|
|
99
99
|
--radius-2xl: 1rem;
|
|
100
100
|
|
|
101
101
|
--spacing: 0.25rem;
|
|
102
|
+
--cos-conversation-max-width: 48rem;
|
|
102
103
|
|
|
103
104
|
--ease-in: cubic-bezier(0.4, 0, 1, 1);
|
|
104
105
|
--ease-out: cubic-bezier(0, 0, 0.2, 1);
|
|
@@ -341,6 +342,54 @@
|
|
|
341
342
|
display: none;
|
|
342
343
|
}
|
|
343
344
|
|
|
345
|
+
.cos-model-select {
|
|
346
|
+
--cos-model-select-bg: #fff;
|
|
347
|
+
--cos-model-select-border: rgb(0 0 0 / 7%);
|
|
348
|
+
--cos-model-select-text: #000;
|
|
349
|
+
--cos-model-select-muted: rgb(0 0 0 / 50%);
|
|
350
|
+
--cos-model-select-disabled: rgb(0 0 0 / 30%);
|
|
351
|
+
--cos-model-select-highlight: rgb(0 0 0 / 3%);
|
|
352
|
+
border-color: var(--cos-model-select-border);
|
|
353
|
+
background: var(--cos-model-select-bg);
|
|
354
|
+
box-shadow: 0 8px 14px rgb(0 0 0 / 6%);
|
|
355
|
+
color: var(--cos-model-select-text);
|
|
356
|
+
font-family: "Inter Variable", Inter, sans-serif;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.cos-model-select__item[data-highlighted] {
|
|
360
|
+
background: var(--cos-model-select-highlight);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
.cos-model-select__item[data-disabled] {
|
|
364
|
+
cursor: not-allowed;
|
|
365
|
+
opacity: 1;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
.cos-model-select__name {
|
|
369
|
+
color: var(--cos-model-select-text);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
.cos-model-select__name[data-muted] {
|
|
373
|
+
color: var(--cos-model-select-muted);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
.cos-model-select__plan {
|
|
377
|
+
color: var(--cos-model-select-muted);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
.cos-model-select__plan[data-disabled] {
|
|
381
|
+
color: var(--cos-model-select-disabled);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
[data-cloud-os-portal][data-mode="dark"].cos-model-select {
|
|
385
|
+
--cos-model-select-bg: #343434;
|
|
386
|
+
--cos-model-select-border: rgb(255 255 255 / 10%);
|
|
387
|
+
--cos-model-select-text: #fff;
|
|
388
|
+
--cos-model-select-muted: rgb(255 255 255 / 50%);
|
|
389
|
+
--cos-model-select-disabled: rgb(255 255 255 / 30%);
|
|
390
|
+
--cos-model-select-highlight: rgb(255 255 255 / 7%);
|
|
391
|
+
}
|
|
392
|
+
|
|
344
393
|
.cos-chat-panel {
|
|
345
394
|
scrollbar-width: thin;
|
|
346
395
|
scrollbar-color: var(--color-kumo-line) transparent;
|
|
@@ -356,6 +405,13 @@
|
|
|
356
405
|
background: transparent;
|
|
357
406
|
}
|
|
358
407
|
|
|
408
|
+
.cos-workspace-divider {
|
|
409
|
+
transition: background-color var(--default-transition-duration) ease;
|
|
410
|
+
}
|
|
411
|
+
.cos-workspace-divider:hover {
|
|
412
|
+
background-color: var(--color-kumo-interact);
|
|
413
|
+
}
|
|
414
|
+
|
|
359
415
|
/* ============================================================================
|
|
360
416
|
* 以下整段来自 ChatInterface.module.css —— CSS Module 类名改成 cos- 全局前缀
|
|
361
417
|
* ========================================================================== */
|
|
@@ -365,6 +421,9 @@
|
|
|
365
421
|
line-height: 1.6;
|
|
366
422
|
overflow-wrap: anywhere;
|
|
367
423
|
}
|
|
424
|
+
.cos-user-markdown :where(p, li) {
|
|
425
|
+
white-space: pre-wrap;
|
|
426
|
+
}
|
|
368
427
|
.cos-markdown p {
|
|
369
428
|
margin: 0.4em 0;
|
|
370
429
|
}
|
|
@@ -469,8 +528,12 @@
|
|
|
469
528
|
font-weight: 600;
|
|
470
529
|
}
|
|
471
530
|
.cos-markdown img {
|
|
472
|
-
max-width: 100
|
|
531
|
+
max-width: min(100%, 16rem);
|
|
532
|
+
max-height: 13rem;
|
|
533
|
+
width: auto;
|
|
473
534
|
height: auto;
|
|
535
|
+
border-radius: 0.75rem;
|
|
536
|
+
object-fit: contain;
|
|
474
537
|
}
|
|
475
538
|
|
|
476
539
|
/* ── 输入框容器(container query 决定「添加资源」标签是否显示)─────────────── */
|
|
@@ -502,6 +565,24 @@
|
|
|
502
565
|
flex: none;
|
|
503
566
|
}
|
|
504
567
|
|
|
568
|
+
/* Trace 新块进入时轻推上浮;已有块更新不会重复播放。 */
|
|
569
|
+
.cos-trace-chain > * {
|
|
570
|
+
animation: cos-trace-enter 180ms cubic-bezier(0.32, 0.72, 0, 1) both;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
@keyframes cos-trace-enter {
|
|
574
|
+
from {
|
|
575
|
+
opacity: 0;
|
|
576
|
+
transform: translateY(6px);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
@media (prefers-reduced-motion: reduce) {
|
|
581
|
+
.cos-trace-chain > * {
|
|
582
|
+
animation: none;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
505
586
|
/* ── 流式占位:Thinking 扫光 ──────────────────────────────────────────────── */
|
|
506
587
|
.cos-thinking-shimmer {
|
|
507
588
|
color: var(--text-color-kumo-inactive);
|
|
@@ -527,14 +608,64 @@
|
|
|
527
608
|
}
|
|
528
609
|
}
|
|
529
610
|
|
|
611
|
+
.cos-thinking-star {
|
|
612
|
+
animation: cos-thinking-star 1.4s ease-in-out infinite;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
@keyframes cos-thinking-star {
|
|
616
|
+
0%, 100% {
|
|
617
|
+
transform: scale(0.82);
|
|
618
|
+
}
|
|
619
|
+
50% {
|
|
620
|
+
transform: scale(1.1);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
530
624
|
@media (prefers-reduced-motion: reduce) {
|
|
625
|
+
[data-sd-animate] {
|
|
626
|
+
animation: none !important;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
.cos-thinking-star,
|
|
531
630
|
.cos-thinking-shimmer {
|
|
532
631
|
animation: none;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
.cos-thinking-shimmer {
|
|
533
635
|
background: none;
|
|
534
636
|
-webkit-text-fill-color: currentColor;
|
|
535
637
|
}
|
|
536
638
|
}
|
|
537
639
|
|
|
640
|
+
/* ── 原位提问:逐题横向切换 ─────────────────────────────────────────────── */
|
|
641
|
+
.cos-ask-user-question[data-direction="forward"] {
|
|
642
|
+
animation: cos-ask-user-forward 180ms ease-out;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
.cos-ask-user-question[data-direction="back"] {
|
|
646
|
+
animation: cos-ask-user-back 180ms ease-out;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
@keyframes cos-ask-user-forward {
|
|
650
|
+
from {
|
|
651
|
+
opacity: 0;
|
|
652
|
+
transform: translateX(24px);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
@keyframes cos-ask-user-back {
|
|
657
|
+
from {
|
|
658
|
+
opacity: 0;
|
|
659
|
+
transform: translateX(-24px);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
@media (prefers-reduced-motion: reduce) {
|
|
664
|
+
.cos-ask-user-question {
|
|
665
|
+
animation: none !important;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
|
|
538
669
|
/* ── 观察类 markdown(行内、紧凑)────────────────────────────────────────── */
|
|
539
670
|
.cos-observation-markdown {
|
|
540
671
|
line-height: 1.5;
|
|
@@ -15,11 +15,13 @@ import {
|
|
|
15
15
|
import {
|
|
16
16
|
commands as sharedCommands,
|
|
17
17
|
defaultPrompt,
|
|
18
|
+
demoAskUserResponse,
|
|
18
19
|
demoModels,
|
|
19
20
|
finalToolNames,
|
|
20
21
|
flowSteps,
|
|
21
22
|
messagesForScenario,
|
|
22
23
|
scenarios,
|
|
24
|
+
type DemoAskUserResponse,
|
|
23
25
|
type DemoScenario,
|
|
24
26
|
type DemoScenarioMeta,
|
|
25
27
|
} from "./chat-scenarios";
|
|
@@ -42,7 +44,7 @@ export function CamelChatShowcase() {
|
|
|
42
44
|
const [theme, setTheme] = useState<"light" | "dark">("dark");
|
|
43
45
|
const [scenario, setScenario] = useState<DemoScenario>(initialScenario);
|
|
44
46
|
const [prompt, setPrompt] = useState(defaultPrompt);
|
|
45
|
-
const [humanAnswer, setHumanAnswer] = useState(
|
|
47
|
+
const [humanAnswer, setHumanAnswer] = useState(demoAskUserResponse);
|
|
46
48
|
const [model, setModel] = useState<string>(demoModels[0].value);
|
|
47
49
|
const [value, setValue] = useState("");
|
|
48
50
|
const [attachments, setAttachments] =
|
|
@@ -70,7 +72,8 @@ export function CamelChatShowcase() {
|
|
|
70
72
|
: {};
|
|
71
73
|
return (
|
|
72
74
|
record.type === "tool-write_file" ||
|
|
73
|
-
record.type === "tool-cancel_schedule"
|
|
75
|
+
record.type === "tool-cancel_schedule" ||
|
|
76
|
+
record.type === "tool-schedule"
|
|
74
77
|
) &&
|
|
75
78
|
record.state === "approval-requested"
|
|
76
79
|
? { id: "camel-demo-approval", approved: approval }
|
|
@@ -254,6 +257,14 @@ export function CamelChatShowcase() {
|
|
|
254
257
|
}}
|
|
255
258
|
onApprove={(_approvalId, decision) => {
|
|
256
259
|
const approved = decision !== "deny";
|
|
260
|
+
if (scenario === "schedule_create") {
|
|
261
|
+
setApproval(approved);
|
|
262
|
+
selectScenario(approved ? "schedule" : "submitted");
|
|
263
|
+
setLastEvent(approved
|
|
264
|
+
? "Scheduled task created"
|
|
265
|
+
: "Schedule creation cancelled");
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
257
268
|
if (scenario === "schedule_cancel") {
|
|
258
269
|
setApproval(approved);
|
|
259
270
|
setLastEvent(
|
|
@@ -274,20 +285,17 @@ export function CamelChatShowcase() {
|
|
|
274
285
|
onAnswer={(payload) => {
|
|
275
286
|
const data =
|
|
276
287
|
payload && typeof payload === "object"
|
|
277
|
-
? (payload as
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
...(data.selections?.flat() ?? []),
|
|
284
|
-
data.text?.trim() ?? "",
|
|
285
|
-
]
|
|
288
|
+
? (payload as DemoAskUserResponse)
|
|
289
|
+
: { answers: [] };
|
|
290
|
+
const answer = data.answers.flatMap((item) => [
|
|
291
|
+
...item.selections,
|
|
292
|
+
item.text?.trim() ?? "",
|
|
293
|
+
])
|
|
286
294
|
.filter(Boolean)
|
|
287
295
|
.join("、");
|
|
288
|
-
if (
|
|
296
|
+
if (data.answers.length > 0) setHumanAnswer(data);
|
|
289
297
|
selectScenario("planning");
|
|
290
|
-
setLastEvent(`已回答并继续:${answer
|
|
298
|
+
setLastEvent(`已回答并继续:${answer}`);
|
|
291
299
|
}}
|
|
292
300
|
getToolApproval={approvalView}
|
|
293
301
|
/>
|