@springbrand/message-panel 0.1.3-alpha.3 → 0.1.3-alpha.31
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 +6 -6
- 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-spark.svg +9 -0
- package/cloud-os/capability-chip.tsx +35 -0
- package/cloud-os/chat/activity-indicator.tsx +2 -2
- package/cloud-os/chat/cloud-os-chat-messages.tsx +374 -63
- 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/rich-blocks.tsx +548 -246
- package/cloud-os/chat/tool-presentation.ts +35 -16
- package/cloud-os/chat/tool-rows.tsx +330 -85
- package/cloud-os/chat/transcript-model.ts +428 -56
- package/cloud-os/composer/cloud-os-chat-input.tsx +228 -142
- package/cloud-os/composer/cloud-os-model-select.tsx +105 -0
- package/cloud-os/file-view.tsx +441 -0
- package/cloud-os/index.ts +35 -3
- package/cloud-os/layout/cloud-os-workspace-split.tsx +58 -15
- package/cloud-os/primitives/workshop-controls.tsx +2 -2
- package/cloud-os/styles/cloud-os.css +100 -20
- package/demo/camel-chat-showcase.tsx +21 -13
- package/demo/chat-scenarios.ts +223 -43
- package/demo/cloud-os-chat-showcase.tsx +47 -14
- package/demo/fixtures.ts +4 -5
- package/demo/message-panel-gallery.tsx +16 -2
- package/package.json +3 -4
- 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-trigger-popover.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
|
@@ -51,6 +51,8 @@
|
|
|
51
51
|
--color-kumo-success: oklch(72.3% 0.219 149.579);
|
|
52
52
|
--color-kumo-success-tint: oklch(92% 0.08 150);
|
|
53
53
|
|
|
54
|
+
--color-operation-base: #ffffff;
|
|
55
|
+
|
|
54
56
|
--color-kumo-tip-shadow: #14111014;
|
|
55
57
|
--color-kumo-tip-stroke: transparent;
|
|
56
58
|
|
|
@@ -73,6 +75,10 @@
|
|
|
73
75
|
--color-cos-status-live: oklch(72.3% 0.219 149.579);
|
|
74
76
|
--color-cos-status-draft: oklch(68.1% 0.162 75.834);
|
|
75
77
|
--color-cos-status-building: oklch(62.3% 0.214 259.815);
|
|
78
|
+
--text-color-cos-work-description: rgba(0, 0, 0, 0.5);
|
|
79
|
+
--text-color-cos-work-description-subtle: rgba(0, 0, 0, 0.7);
|
|
80
|
+
--text-color-cos-tool-group: rgba(0, 0, 0, 0.5);
|
|
81
|
+
--text-color-cos-output: #000000b3;
|
|
76
82
|
}
|
|
77
83
|
|
|
78
84
|
/* ── 作用域根:通用 token 只在 cloud-os 子树内生效 ─────────────────────────── */
|
|
@@ -152,6 +158,8 @@
|
|
|
152
158
|
--color-kumo-success: oklch(52.7% 0.154 150.069);
|
|
153
159
|
--color-kumo-success-tint: oklch(0.25 0.06 150.069);
|
|
154
160
|
|
|
161
|
+
--color-operation-base: var(--color-kumo-base);
|
|
162
|
+
|
|
155
163
|
--color-kumo-tip-shadow: #00000066;
|
|
156
164
|
--color-kumo-tip-stroke: oklch(0.34 0.022 285);
|
|
157
165
|
|
|
@@ -172,6 +180,10 @@
|
|
|
172
180
|
--color-cos-status-live: oklch(79.2% 0.209 151.711);
|
|
173
181
|
--color-cos-status-draft: oklch(82.8% 0.189 84.429);
|
|
174
182
|
--color-cos-status-building: oklch(74% 0.16 250);
|
|
183
|
+
--text-color-cos-work-description: var(--text-color-kumo-subtle);
|
|
184
|
+
--text-color-cos-work-description-subtle: var(--text-color-kumo-subtle);
|
|
185
|
+
--text-color-cos-tool-group: var(--text-color-kumo-inactive);
|
|
186
|
+
--text-color-cos-output: var(--text-color-kumo-subtle);
|
|
175
187
|
|
|
176
188
|
--color-selection-bg: color-mix(in srgb, var(--color-kumo-brand) 28%, transparent);
|
|
177
189
|
--color-selection-text: oklch(0.97 0.006 285);
|
|
@@ -341,6 +353,54 @@
|
|
|
341
353
|
display: none;
|
|
342
354
|
}
|
|
343
355
|
|
|
356
|
+
.cos-model-select {
|
|
357
|
+
--cos-model-select-bg: #fff;
|
|
358
|
+
--cos-model-select-border: rgb(0 0 0 / 7%);
|
|
359
|
+
--cos-model-select-text: #000;
|
|
360
|
+
--cos-model-select-muted: rgb(0 0 0 / 50%);
|
|
361
|
+
--cos-model-select-disabled: rgb(0 0 0 / 30%);
|
|
362
|
+
--cos-model-select-highlight: rgb(0 0 0 / 3%);
|
|
363
|
+
border-color: var(--cos-model-select-border);
|
|
364
|
+
background: var(--cos-model-select-bg);
|
|
365
|
+
box-shadow: 0 8px 14px rgb(0 0 0 / 6%);
|
|
366
|
+
color: var(--cos-model-select-text);
|
|
367
|
+
font-family: "Inter Variable", Inter, sans-serif;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
.cos-model-select__item[data-highlighted] {
|
|
371
|
+
background: var(--cos-model-select-highlight);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
.cos-model-select__item[data-disabled] {
|
|
375
|
+
cursor: not-allowed;
|
|
376
|
+
opacity: 1;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
.cos-model-select__name {
|
|
380
|
+
color: var(--cos-model-select-text);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
.cos-model-select__name[data-muted] {
|
|
384
|
+
color: var(--cos-model-select-muted);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
.cos-model-select__plan {
|
|
388
|
+
color: var(--cos-model-select-muted);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
.cos-model-select__plan[data-disabled] {
|
|
392
|
+
color: var(--cos-model-select-disabled);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
[data-cloud-os-portal][data-mode="dark"].cos-model-select {
|
|
396
|
+
--cos-model-select-bg: #343434;
|
|
397
|
+
--cos-model-select-border: rgb(255 255 255 / 10%);
|
|
398
|
+
--cos-model-select-text: #fff;
|
|
399
|
+
--cos-model-select-muted: rgb(255 255 255 / 50%);
|
|
400
|
+
--cos-model-select-disabled: rgb(255 255 255 / 30%);
|
|
401
|
+
--cos-model-select-highlight: rgb(255 255 255 / 7%);
|
|
402
|
+
}
|
|
403
|
+
|
|
344
404
|
.cos-chat-panel {
|
|
345
405
|
scrollbar-width: thin;
|
|
346
406
|
scrollbar-color: var(--color-kumo-line) transparent;
|
|
@@ -356,23 +416,6 @@
|
|
|
356
416
|
background: transparent;
|
|
357
417
|
}
|
|
358
418
|
|
|
359
|
-
/* ── 顶部推进条(isAgentActive)──────────────────────────────────────────── */
|
|
360
|
-
@keyframes cos-thinking {
|
|
361
|
-
0% {
|
|
362
|
-
left: -33%;
|
|
363
|
-
}
|
|
364
|
-
50% {
|
|
365
|
-
left: 100%;
|
|
366
|
-
}
|
|
367
|
-
100% {
|
|
368
|
-
left: -33%;
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
.cos-progress-sweep {
|
|
373
|
-
animation: cos-thinking 1.5s ease-in-out infinite;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
419
|
/* ============================================================================
|
|
377
420
|
* 以下整段来自 ChatInterface.module.css —— CSS Module 类名改成 cos- 全局前缀
|
|
378
421
|
* ========================================================================== */
|
|
@@ -382,6 +425,9 @@
|
|
|
382
425
|
line-height: 1.6;
|
|
383
426
|
overflow-wrap: anywhere;
|
|
384
427
|
}
|
|
428
|
+
.cos-user-markdown :where(p, li) {
|
|
429
|
+
white-space: pre-wrap;
|
|
430
|
+
}
|
|
385
431
|
.cos-markdown p {
|
|
386
432
|
margin: 0.4em 0;
|
|
387
433
|
}
|
|
@@ -486,8 +532,12 @@
|
|
|
486
532
|
font-weight: 600;
|
|
487
533
|
}
|
|
488
534
|
.cos-markdown img {
|
|
489
|
-
max-width: 100
|
|
535
|
+
max-width: min(100%, 16rem);
|
|
536
|
+
max-height: 13rem;
|
|
537
|
+
width: auto;
|
|
490
538
|
height: auto;
|
|
539
|
+
border-radius: 0.75rem;
|
|
540
|
+
object-fit: contain;
|
|
491
541
|
}
|
|
492
542
|
|
|
493
543
|
/* ── 输入框容器(container query 决定「添加资源」标签是否显示)─────────────── */
|
|
@@ -545,13 +595,43 @@
|
|
|
545
595
|
}
|
|
546
596
|
|
|
547
597
|
@media (prefers-reduced-motion: reduce) {
|
|
598
|
+
[data-sd-animate] {
|
|
599
|
+
animation: none !important;
|
|
600
|
+
}
|
|
601
|
+
|
|
548
602
|
.cos-thinking-shimmer {
|
|
549
603
|
animation: none;
|
|
550
604
|
background: none;
|
|
551
605
|
-webkit-text-fill-color: currentColor;
|
|
552
606
|
}
|
|
553
|
-
|
|
554
|
-
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/* ── 原位提问:逐题横向切换 ─────────────────────────────────────────────── */
|
|
610
|
+
.cos-ask-user-question[data-direction="forward"] {
|
|
611
|
+
animation: cos-ask-user-forward 180ms ease-out;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
.cos-ask-user-question[data-direction="back"] {
|
|
615
|
+
animation: cos-ask-user-back 180ms ease-out;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
@keyframes cos-ask-user-forward {
|
|
619
|
+
from {
|
|
620
|
+
opacity: 0;
|
|
621
|
+
transform: translateX(24px);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
@keyframes cos-ask-user-back {
|
|
626
|
+
from {
|
|
627
|
+
opacity: 0;
|
|
628
|
+
transform: translateX(-24px);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
@media (prefers-reduced-motion: reduce) {
|
|
633
|
+
.cos-ask-user-question {
|
|
634
|
+
animation: none !important;
|
|
555
635
|
}
|
|
556
636
|
}
|
|
557
637
|
|
|
@@ -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
|
/>
|
package/demo/chat-scenarios.ts
CHANGED
|
@@ -18,6 +18,7 @@ export interface ComposerCommandLike {
|
|
|
18
18
|
}
|
|
19
19
|
const demoCompletedAt = Date.now() - 1_000;
|
|
20
20
|
const demoTurnStartedAt = demoCompletedAt - 18_000;
|
|
21
|
+
const demoTurnId = "camel-demo-research-turn";
|
|
21
22
|
export const defaultPrompt =
|
|
22
23
|
"请调研 2026 年 AI Agent 产品的交互趋势,并给出可落地的消息 UI 建议。";
|
|
23
24
|
export const demoModels = [
|
|
@@ -37,6 +38,9 @@ export type DemoScenario =
|
|
|
37
38
|
| "temporary_agent"
|
|
38
39
|
| "agent_tools"
|
|
39
40
|
| "background_agent"
|
|
41
|
+
| "action_loading"
|
|
42
|
+
| "action_files"
|
|
43
|
+
| "schedule_create"
|
|
40
44
|
| "schedule"
|
|
41
45
|
| "schedule_cancel"
|
|
42
46
|
| "approval"
|
|
@@ -118,9 +122,27 @@ export const scenarios: Record<DemoScenario, DemoScenarioMeta> = {
|
|
|
118
122
|
status: "ready",
|
|
119
123
|
flowStep: 3,
|
|
120
124
|
},
|
|
125
|
+
action_loading: {
|
|
126
|
+
label: "Action product loading",
|
|
127
|
+
description: "Preview loading UI for every Action product type.",
|
|
128
|
+
status: "streaming",
|
|
129
|
+
flowStep: 2,
|
|
130
|
+
},
|
|
131
|
+
action_files: {
|
|
132
|
+
label: "Action file results",
|
|
133
|
+
description: "Preview image, audio, video, document, spreadsheet, archive, and unknown files.",
|
|
134
|
+
status: "ready",
|
|
135
|
+
flowStep: 3,
|
|
136
|
+
},
|
|
137
|
+
schedule_create: {
|
|
138
|
+
label: "Create scheduled task",
|
|
139
|
+
description: "Review the task, cadence, and timezone before creating the schedule.",
|
|
140
|
+
status: "ready",
|
|
141
|
+
flowStep: 2,
|
|
142
|
+
},
|
|
121
143
|
schedule: {
|
|
122
|
-
label: "
|
|
123
|
-
description: "schedule
|
|
144
|
+
label: "Scheduled task created",
|
|
145
|
+
description: "A completed schedule shows its task, cadence, timezone, and final status.",
|
|
124
146
|
status: "ready",
|
|
125
147
|
flowStep: 3,
|
|
126
148
|
},
|
|
@@ -239,42 +261,84 @@ function userMessage(prompt: string): UIMessage {
|
|
|
239
261
|
} as UIMessage;
|
|
240
262
|
}
|
|
241
263
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
output: { asked: true },
|
|
256
|
-
},
|
|
264
|
+
function actionUserMessage(prompt: string): UIMessage {
|
|
265
|
+
const message = userMessage(prompt);
|
|
266
|
+
return { ...message, parts: message.parts.filter((part) => part.type === "text") };
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export interface DemoAskUserResponse {
|
|
270
|
+
answers: Array<{ selections: string[]; text?: string }>;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
export const demoAskUserResponse: DemoAskUserResponse = {
|
|
274
|
+
answers: [
|
|
275
|
+
{ selections: ["管理层"], text: "" },
|
|
276
|
+
{ selections: ["报告"], text: "" },
|
|
257
277
|
],
|
|
258
|
-
}
|
|
278
|
+
};
|
|
259
279
|
|
|
260
|
-
|
|
280
|
+
const askUserQuestions = [
|
|
281
|
+
{
|
|
282
|
+
question: "这份建议优先面向哪个读者?",
|
|
283
|
+
options: ["产品团队", "管理层", "设计团队"],
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
question: "需要哪些交付物?",
|
|
287
|
+
options: ["报告", "演示文稿", "执行清单"],
|
|
288
|
+
multiSelect: true,
|
|
289
|
+
allowCustom: true,
|
|
290
|
+
},
|
|
291
|
+
];
|
|
292
|
+
|
|
293
|
+
function askUserRequest(response?: DemoAskUserResponse): UIMessage {
|
|
261
294
|
return {
|
|
262
|
-
id: "camel-demo-
|
|
263
|
-
role: "
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
295
|
+
id: "camel-demo-ask-user",
|
|
296
|
+
role: "assistant",
|
|
297
|
+
parts: [
|
|
298
|
+
{
|
|
299
|
+
type: "tool-ask_user",
|
|
300
|
+
toolCallId: "camel-demo-ask-user-1",
|
|
301
|
+
state: response ? "output-available" : "input-available",
|
|
302
|
+
input: { questions: askUserQuestions },
|
|
303
|
+
...(response
|
|
304
|
+
? {
|
|
305
|
+
output: {
|
|
306
|
+
answers: response.answers.map((answer, index) => ({
|
|
307
|
+
question: askUserQuestions[index]!.question,
|
|
308
|
+
selections: answer.selections,
|
|
309
|
+
text: answer.text?.trim() ?? "",
|
|
310
|
+
})),
|
|
311
|
+
},
|
|
312
|
+
}
|
|
313
|
+
: {}),
|
|
314
|
+
},
|
|
315
|
+
],
|
|
316
|
+
} as unknown as UIMessage;
|
|
271
317
|
}
|
|
272
318
|
|
|
273
319
|
const planningWork = {
|
|
274
320
|
id: "camel-demo-planning-work",
|
|
275
321
|
role: "assistant",
|
|
276
|
-
metadata: {
|
|
322
|
+
metadata: {
|
|
323
|
+
turnStartedAt: demoTurnStartedAt + 3_000,
|
|
324
|
+
turnDurationMs: 18_000,
|
|
325
|
+
},
|
|
277
326
|
parts: [
|
|
327
|
+
{
|
|
328
|
+
type: "reasoning",
|
|
329
|
+
text: `先确认受众和交付范围,再验证产品案例。
|
|
330
|
+
|
|
331
|
+
用户选择的读者是管理层,交付物是报告。因此内容不能只罗列界面趋势,还需要把每项趋势连接到业务价值、落地成本和潜在风险,帮助管理层判断优先级。
|
|
332
|
+
|
|
333
|
+
接下来会分三步推进:
|
|
334
|
+
|
|
335
|
+
1. 检索 2025–2026 年主流 AI Agent 产品,优先采集官方发布说明、产品文档和可验证的真实界面。
|
|
336
|
+
2. 对比任务规划、工具调用、人工确认、后台执行和结果交付等关键交互,区分普遍模式与单个产品的特色设计。
|
|
337
|
+
3. 把证据整理成可执行建议,并为每条建议标注适用场景、实现复杂度和预期收益。
|
|
338
|
+
|
|
339
|
+
第一轮检索先覆盖通用 Agent、开发者 Agent 与企业自动化产品。如果不同来源对同一趋势的描述冲突,会保留分歧并继续寻找一手证据,而不是直接下结论。`,
|
|
340
|
+
state: "done",
|
|
341
|
+
},
|
|
278
342
|
{
|
|
279
343
|
type: "tool-update_plan",
|
|
280
344
|
state: "output-available",
|
|
@@ -459,6 +523,115 @@ const backgroundResult = {
|
|
|
459
523
|
],
|
|
460
524
|
} as unknown as UIMessage;
|
|
461
525
|
|
|
526
|
+
const actionProductHints = [
|
|
527
|
+
{ type: "image", mediaType: "image/png" },
|
|
528
|
+
{ type: "audio", mediaType: "audio/mpeg" },
|
|
529
|
+
{ type: "video", mediaType: "video/mp4" },
|
|
530
|
+
{ type: "document", mediaType: "application/pdf" },
|
|
531
|
+
{ type: "archive", mediaType: "application/zip" },
|
|
532
|
+
{ type: "data", mediaType: "application/json" },
|
|
533
|
+
{ type: "other" },
|
|
534
|
+
] as const;
|
|
535
|
+
|
|
536
|
+
function demoExecutionId(index: number) {
|
|
537
|
+
return `00000000-0000-4000-8000-${String(index + 1).padStart(12, "0")}`;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
const actionProductLoading = {
|
|
541
|
+
id: "camel-demo-action-product-loading",
|
|
542
|
+
role: "assistant",
|
|
543
|
+
parts: actionProductHints.map((produces, index) => ({
|
|
544
|
+
type: "dynamic-tool",
|
|
545
|
+
toolCallId: `camel-demo-action-loading-${index}`,
|
|
546
|
+
toolName: `action_generate_${produces.type}`,
|
|
547
|
+
state: "output-available",
|
|
548
|
+
input: {},
|
|
549
|
+
output: {
|
|
550
|
+
status: "running",
|
|
551
|
+
executionId: demoExecutionId(index),
|
|
552
|
+
presentation: {
|
|
553
|
+
type: "action-execution",
|
|
554
|
+
executionId: demoExecutionId(index),
|
|
555
|
+
state: "running",
|
|
556
|
+
produces,
|
|
557
|
+
content: [],
|
|
558
|
+
},
|
|
559
|
+
},
|
|
560
|
+
})),
|
|
561
|
+
} as unknown as UIMessage;
|
|
562
|
+
|
|
563
|
+
const actionFileFixtures = [
|
|
564
|
+
{
|
|
565
|
+
name: "image",
|
|
566
|
+
mediaType: "image/png",
|
|
567
|
+
url: "https://images.unsplash.com/photo-1500530855697-b586d89ba3ee?auto=format&fit=crop&w=1024&q=80",
|
|
568
|
+
},
|
|
569
|
+
{ name: "audio", mediaType: "audio/mpeg", url: "https://files.example/action-demo/audio.mp3" },
|
|
570
|
+
{ name: "video", mediaType: "video/mp4", url: "https://files.example/action-demo/video.mp4" },
|
|
571
|
+
{ name: "pdf", mediaType: "application/pdf", url: "https://files.example/action-demo/report.pdf" },
|
|
572
|
+
{ name: "markdown", mediaType: "text/markdown", url: "https://files.example/action-demo/report.md" },
|
|
573
|
+
{
|
|
574
|
+
name: "spreadsheet",
|
|
575
|
+
mediaType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
576
|
+
url: "https://files.example/action-demo/data.xlsx",
|
|
577
|
+
},
|
|
578
|
+
{ name: "archive", mediaType: "application/zip", url: "https://files.example/action-demo/files.zip" },
|
|
579
|
+
{
|
|
580
|
+
name: "unknown",
|
|
581
|
+
mediaType: "application/octet-stream",
|
|
582
|
+
url: "https://files.example/action-demo/result.bin",
|
|
583
|
+
},
|
|
584
|
+
] as const;
|
|
585
|
+
|
|
586
|
+
const actionFileResults = {
|
|
587
|
+
id: "camel-demo-action-file-results",
|
|
588
|
+
role: "assistant",
|
|
589
|
+
parts: [
|
|
590
|
+
...actionFileFixtures.map((file, index) => ({
|
|
591
|
+
type: "dynamic-tool",
|
|
592
|
+
toolCallId: `camel-demo-action-file-${index}`,
|
|
593
|
+
toolName: `action_generate_${file.name}`,
|
|
594
|
+
state: "output-available",
|
|
595
|
+
input: {},
|
|
596
|
+
output: {
|
|
597
|
+
status: "succeeded",
|
|
598
|
+
executionId: demoExecutionId(index + actionProductHints.length),
|
|
599
|
+
result: { kind: "file", content_type: file.mediaType, url: file.url },
|
|
600
|
+
presentation: {
|
|
601
|
+
type: "action-execution",
|
|
602
|
+
executionId: demoExecutionId(index + actionProductHints.length),
|
|
603
|
+
state: "ready",
|
|
604
|
+
content: [{ type: "file", url: file.url, mediaType: file.mediaType }],
|
|
605
|
+
},
|
|
606
|
+
},
|
|
607
|
+
})),
|
|
608
|
+
{
|
|
609
|
+
type: "text",
|
|
610
|
+
text: "All Action file result types are rendered above from structured output.",
|
|
611
|
+
},
|
|
612
|
+
],
|
|
613
|
+
} as unknown as UIMessage;
|
|
614
|
+
|
|
615
|
+
export const demoScheduleInput = {
|
|
616
|
+
label: "Weekly competitor report",
|
|
617
|
+
prompt: "Generate and send this week's competitor report.",
|
|
618
|
+
trigger: { kind: "cron", cron: "0 9 * * 1" },
|
|
619
|
+
timezone: "Asia/Shanghai",
|
|
620
|
+
};
|
|
621
|
+
|
|
622
|
+
const scheduleRequest = {
|
|
623
|
+
id: "camel-demo-schedule-request",
|
|
624
|
+
role: "assistant",
|
|
625
|
+
parts: [
|
|
626
|
+
{
|
|
627
|
+
type: "tool-schedule",
|
|
628
|
+
toolCallId: "camel-demo-schedule-request-1",
|
|
629
|
+
state: "approval-requested",
|
|
630
|
+
input: demoScheduleInput,
|
|
631
|
+
},
|
|
632
|
+
],
|
|
633
|
+
} as unknown as UIMessage;
|
|
634
|
+
|
|
462
635
|
const scheduledTask = {
|
|
463
636
|
id: "camel-demo-schedule",
|
|
464
637
|
role: "assistant",
|
|
@@ -467,12 +640,7 @@ const scheduledTask = {
|
|
|
467
640
|
type: "tool-schedule",
|
|
468
641
|
toolCallId: "camel-demo-schedule-1",
|
|
469
642
|
state: "output-available",
|
|
470
|
-
input:
|
|
471
|
-
label: "每周发送竞品报告",
|
|
472
|
-
prompt: "生成并发送本周竞品报告。",
|
|
473
|
-
trigger: { kind: "cron", cron: "0 9 * * 1" },
|
|
474
|
-
timezone: "Asia/Shanghai",
|
|
475
|
-
},
|
|
643
|
+
input: demoScheduleInput,
|
|
476
644
|
output: { scheduled: true, id: "schedule-1" },
|
|
477
645
|
},
|
|
478
646
|
],
|
|
@@ -577,7 +745,7 @@ const commandMessages = [
|
|
|
577
745
|
const runningWork = {
|
|
578
746
|
id: "camel-demo-running-work",
|
|
579
747
|
role: "assistant",
|
|
580
|
-
metadata: { turnStartedAt: demoTurnStartedAt },
|
|
748
|
+
metadata: { turnId: demoTurnId, turnStartedAt: demoTurnStartedAt },
|
|
581
749
|
parts: [
|
|
582
750
|
{
|
|
583
751
|
type: "reasoning",
|
|
@@ -604,7 +772,7 @@ const runningWork = {
|
|
|
604
772
|
const completedResearch = {
|
|
605
773
|
id: "camel-demo-completed-research",
|
|
606
774
|
role: "assistant",
|
|
607
|
-
metadata: { turnStartedAt: demoTurnStartedAt },
|
|
775
|
+
metadata: { turnId: demoTurnId, turnStartedAt: demoTurnStartedAt },
|
|
608
776
|
parts: [
|
|
609
777
|
{
|
|
610
778
|
type: "reasoning",
|
|
@@ -639,6 +807,7 @@ const completedResearch = {
|
|
|
639
807
|
const completedSynthesis = {
|
|
640
808
|
id: "camel-demo-completed-synthesis",
|
|
641
809
|
role: "assistant",
|
|
810
|
+
metadata: { turnId: demoTurnId },
|
|
642
811
|
parts: [
|
|
643
812
|
{
|
|
644
813
|
type: "tool-update_plan",
|
|
@@ -670,6 +839,7 @@ const completedSynthesis = {
|
|
|
670
839
|
const approvalRequest = {
|
|
671
840
|
id: "camel-demo-approval-request",
|
|
672
841
|
role: "assistant",
|
|
842
|
+
metadata: { turnId: demoTurnId },
|
|
673
843
|
parts: [
|
|
674
844
|
{
|
|
675
845
|
type: "tool-write_file",
|
|
@@ -685,6 +855,7 @@ const approvalRequest = {
|
|
|
685
855
|
const collectedAnswer = {
|
|
686
856
|
id: "camel-demo-collected-answer",
|
|
687
857
|
role: "assistant",
|
|
858
|
+
metadata: { turnId: demoTurnId },
|
|
688
859
|
parts: [
|
|
689
860
|
{
|
|
690
861
|
type: "text",
|
|
@@ -701,6 +872,7 @@ const finalAnswer = {
|
|
|
701
872
|
id: "camel-demo-final-answer",
|
|
702
873
|
role: "assistant",
|
|
703
874
|
metadata: {
|
|
875
|
+
turnId: demoTurnId,
|
|
704
876
|
createdAt: demoCompletedAt,
|
|
705
877
|
completedAt: demoCompletedAt,
|
|
706
878
|
turnDurationMs: 18_000,
|
|
@@ -769,6 +941,7 @@ const interruptedByUser = {
|
|
|
769
941
|
id: "camel-demo-interrupted",
|
|
770
942
|
role: "assistant",
|
|
771
943
|
metadata: {
|
|
944
|
+
turnId: demoTurnId,
|
|
772
945
|
createdAt: demoCompletedAt,
|
|
773
946
|
completedAt: demoCompletedAt + 2_000,
|
|
774
947
|
turnDurationMs: 2_000,
|
|
@@ -798,7 +971,7 @@ const compactSummary = {
|
|
|
798
971
|
const failedWork = {
|
|
799
972
|
id: "camel-demo-failed-work",
|
|
800
973
|
role: "assistant",
|
|
801
|
-
metadata: { turnStartedAt: demoTurnStartedAt },
|
|
974
|
+
metadata: { turnId: demoTurnId, turnStartedAt: demoTurnStartedAt },
|
|
802
975
|
parts: [
|
|
803
976
|
...completedResearch.parts,
|
|
804
977
|
{
|
|
@@ -827,7 +1000,7 @@ const failedWork = {
|
|
|
827
1000
|
export function messagesForScenario(
|
|
828
1001
|
scenario: DemoScenario,
|
|
829
1002
|
prompt: string,
|
|
830
|
-
humanAnswer:
|
|
1003
|
+
humanAnswer: DemoAskUserResponse,
|
|
831
1004
|
approval: boolean | undefined,
|
|
832
1005
|
): UIMessage[] {
|
|
833
1006
|
if (scenario === "empty") return [];
|
|
@@ -835,15 +1008,13 @@ export function messagesForScenario(
|
|
|
835
1008
|
return [noticeMessage(scenario), ...commandMessages];
|
|
836
1009
|
}
|
|
837
1010
|
const conversation = [noticeMessage(scenario), userMessage(prompt)];
|
|
838
|
-
const answer = humanAnswer || "管理层";
|
|
839
1011
|
const decidedConversation = [
|
|
840
1012
|
...conversation,
|
|
841
|
-
askUserRequest,
|
|
842
|
-
humanReplyMessage(answer),
|
|
1013
|
+
askUserRequest(humanAnswer),
|
|
843
1014
|
];
|
|
844
1015
|
if (scenario === "hydrating") return conversation;
|
|
845
1016
|
if (scenario === "submitted") return conversation;
|
|
846
|
-
if (scenario === "ask") return [...conversation, askUserRequest];
|
|
1017
|
+
if (scenario === "ask") return [...conversation, askUserRequest()];
|
|
847
1018
|
if (scenario === "planning") {
|
|
848
1019
|
return [...decidedConversation, planningWork];
|
|
849
1020
|
}
|
|
@@ -860,6 +1031,15 @@ export function messagesForScenario(
|
|
|
860
1031
|
if (scenario === "background_agent") {
|
|
861
1032
|
return [...conversation, backgroundDispatch, backgroundResult];
|
|
862
1033
|
}
|
|
1034
|
+
if (scenario === "action_loading") {
|
|
1035
|
+
return [noticeMessage(scenario), actionUserMessage(prompt), actionProductLoading];
|
|
1036
|
+
}
|
|
1037
|
+
if (scenario === "action_files") {
|
|
1038
|
+
return [noticeMessage(scenario), actionUserMessage(prompt), actionFileResults];
|
|
1039
|
+
}
|
|
1040
|
+
if (scenario === "schedule_create") {
|
|
1041
|
+
return [...conversation, scheduleRequest];
|
|
1042
|
+
}
|
|
863
1043
|
if (scenario === "schedule") {
|
|
864
1044
|
return [...conversation, scheduledTask];
|
|
865
1045
|
}
|