@springbrand/message-panel 0.2.0-alpha.56 → 0.3.0-alpha.2
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/chat/cloud-os-chat-messages.tsx +5 -8
- package/cloud-os/chat/markdown-message.tsx +8 -3
- package/cloud-os/chat/rich-blocks.tsx +90 -86
- package/cloud-os/chat/tool-presentation.ts +2 -2
- package/cloud-os/chat/transcript-model.ts +2 -7
- package/cloud-os/index.ts +2 -0
- package/package.json +1 -1
- package/springbrand-pet/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
- package/src/camel/camel-chat-messages.tsx +1 -5
- package/src/camel/camel-tool-presentation.tsx +3 -0
- package/src/parts/index.tsx +3 -14
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ScheduleCardControls } from "./rich-blocks";
|
|
1
2
|
import type { UIMessage } from "ai";
|
|
2
3
|
import { AnimatePresence, motion, useReducedMotion } from "motion/react";
|
|
3
4
|
import {
|
|
@@ -72,8 +73,6 @@ export interface CloudOsChatMessagesProps {
|
|
|
72
73
|
/** 权威 Turn 生命周期;提供时替代本地 status 推断。 */
|
|
73
74
|
turnActive?: boolean;
|
|
74
75
|
isRecovering?: boolean;
|
|
75
|
-
recoveryAttempt?: number;
|
|
76
|
-
recoveryMax?: number;
|
|
77
76
|
recoveryStatusLabel?: string;
|
|
78
77
|
awaitingApproval?: boolean;
|
|
79
78
|
/** 有 pending steer 时,活动占位说明「正在等当前步骤收尾」。 */
|
|
@@ -119,6 +118,7 @@ export interface CloudOsChatMessagesProps {
|
|
|
119
118
|
*/
|
|
120
119
|
onRespond?: (toolCallId: string, response: unknown) => Promise<boolean>;
|
|
121
120
|
/** 点击定时任务卡片:宿主决定跳到哪(缺省 → 卡片不可点)。 */
|
|
121
|
+
scheduleControls?: ScheduleCardControls;
|
|
122
122
|
onOpenSchedule?: (scheduleId: string) => void;
|
|
123
123
|
onCopy?: (text: string) => void;
|
|
124
124
|
}
|
|
@@ -375,8 +375,6 @@ export function CloudOsChatMessages({
|
|
|
375
375
|
status,
|
|
376
376
|
turnActive,
|
|
377
377
|
isRecovering = false,
|
|
378
|
-
recoveryAttempt,
|
|
379
|
-
recoveryMax,
|
|
380
378
|
recoveryStatusLabel,
|
|
381
379
|
awaitingApproval = false,
|
|
382
380
|
hasPendingSteer = false,
|
|
@@ -397,6 +395,7 @@ export function CloudOsChatMessages({
|
|
|
397
395
|
onSuggestion,
|
|
398
396
|
onRespond,
|
|
399
397
|
onOpenSchedule,
|
|
398
|
+
scheduleControls,
|
|
400
399
|
onOpenArtifact,
|
|
401
400
|
onCopy,
|
|
402
401
|
}: CloudOsChatMessagesProps) {
|
|
@@ -550,8 +549,6 @@ export function CloudOsChatMessages({
|
|
|
550
549
|
const activity = deriveTurnActivity(entries, {
|
|
551
550
|
isActive,
|
|
552
551
|
isRecovering,
|
|
553
|
-
recoveryAttempt,
|
|
554
|
-
recoveryMax,
|
|
555
552
|
recoveryStatusLabel,
|
|
556
553
|
awaitingApproval,
|
|
557
554
|
hasPendingSteer,
|
|
@@ -722,8 +719,7 @@ export function CloudOsChatMessages({
|
|
|
722
719
|
);
|
|
723
720
|
const actionResultBlocks = entry.blocks.filter(
|
|
724
721
|
(block): block is Extract<AssistantBlock, { kind: "actionPresentation" }> =>
|
|
725
|
-
block.kind === "actionPresentation"
|
|
726
|
-
!(block.presentation.state === "ready" && block.presentation.content.length === 0),
|
|
722
|
+
block.kind === "actionPresentation",
|
|
727
723
|
);
|
|
728
724
|
const finalMediaBlocks = entry.blocks.filter(
|
|
729
725
|
(block): block is Extract<AssistantBlock, { kind: "image" | "file" }> =>
|
|
@@ -847,6 +843,7 @@ export function CloudOsChatMessages({
|
|
|
847
843
|
key={block.key}
|
|
848
844
|
call={block.call}
|
|
849
845
|
onOpen={onOpenSchedule}
|
|
846
|
+
controls={scheduleControls}
|
|
850
847
|
/>
|
|
851
848
|
);
|
|
852
849
|
case "approval": {
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
useSmooth,
|
|
5
5
|
type SmoothOptions,
|
|
6
6
|
} from "@assistant-ui/react";
|
|
7
|
-
import { memo, useMemo, type ReactNode } from "react";
|
|
7
|
+
import { memo, useMemo, useRef, type ReactNode } from "react";
|
|
8
8
|
import {
|
|
9
9
|
defaultRehypePlugins,
|
|
10
10
|
Streamdown,
|
|
@@ -135,8 +135,13 @@ function MarkdownMessageContent({
|
|
|
135
135
|
resolveArtifactId?: CloudOsArtifactResolver;
|
|
136
136
|
onOpenArtifact?: (artifactId: string) => void;
|
|
137
137
|
}) {
|
|
138
|
-
const
|
|
139
|
-
const
|
|
138
|
+
const received = useMessagePartText();
|
|
139
|
+
const initialText = useRef(received.text);
|
|
140
|
+
// A mounted snapshot is already visible history; only later deltas need a reveal.
|
|
141
|
+
const part = useSmooth(received.text === initialText.current
|
|
142
|
+
? { ...received, status: { type: "complete" } }
|
|
143
|
+
: received, SMOOTH_STREAMING);
|
|
144
|
+
const streaming = received.status.type === "running" || part.status.type === "running";
|
|
140
145
|
const rehypePlugins = useMemo(
|
|
141
146
|
() =>
|
|
142
147
|
resolveUrl
|
|
@@ -152,7 +152,7 @@ interface AskQuestion {
|
|
|
152
152
|
|
|
153
153
|
function questionsOf(input: Record<string, unknown>): AskQuestion[] {
|
|
154
154
|
if (!Array.isArray(input.questions)) return [];
|
|
155
|
-
return input.questions.
|
|
155
|
+
return input.questions.flatMap((item) => {
|
|
156
156
|
const question = (item ?? {}) as Record<string, unknown>;
|
|
157
157
|
const options = Array.isArray(question.options)
|
|
158
158
|
? question.options.filter((option): option is string =>
|
|
@@ -164,14 +164,9 @@ function questionsOf(input: Record<string, unknown>): AskQuestion[] {
|
|
|
164
164
|
question.responseType === "multi_select" ||
|
|
165
165
|
question.responseType === "attachment"
|
|
166
166
|
? question.responseType
|
|
167
|
-
:
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
? "text"
|
|
171
|
-
: question.multiSelect === true
|
|
172
|
-
? "multi_select"
|
|
173
|
-
: "single_select";
|
|
174
|
-
return {
|
|
167
|
+
: undefined;
|
|
168
|
+
if (!responseType) return [];
|
|
169
|
+
return [{
|
|
175
170
|
prompt: typeof question.question === "string"
|
|
176
171
|
? question.question
|
|
177
172
|
: "Choose an option",
|
|
@@ -179,7 +174,7 @@ function questionsOf(input: Record<string, unknown>): AskQuestion[] {
|
|
|
179
174
|
allowCustom: responseType === "text" || question.allowCustom === true,
|
|
180
175
|
required: question.required === true,
|
|
181
176
|
responseType,
|
|
182
|
-
};
|
|
177
|
+
}];
|
|
183
178
|
});
|
|
184
179
|
}
|
|
185
180
|
|
|
@@ -713,6 +708,14 @@ function scheduleCadence(input: Record<string, unknown>): string {
|
|
|
713
708
|
} else if (trigger.kind === "cron" && typeof trigger.cron === "string") {
|
|
714
709
|
cadence = `Cron ${trigger.cron}`;
|
|
715
710
|
}
|
|
711
|
+
if (trigger.kind === "local" && typeof trigger.rule === "object" && trigger.rule) {
|
|
712
|
+
const rule = trigger.rule as Record<string, unknown>;
|
|
713
|
+
cadence = rule.kind === "once" ? `Once ${rule.date} at ${rule.time}`
|
|
714
|
+
: rule.kind === "weekly" ? `Weekly (${Array.isArray(rule.weekdays) ? rule.weekdays.map(day => ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"][Number(day)]).join(", ") : ""}) at ${rule.time}`
|
|
715
|
+
: `Daily at ${rule.time}`;
|
|
716
|
+
if (trigger.startDate) cadence += ` from ${trigger.startDate}`;
|
|
717
|
+
if (trigger.endDate) cadence += ` through ${trigger.endDate}`;
|
|
718
|
+
}
|
|
716
719
|
if (!cadence) cadence = String(input.cadence ?? input.schedule ?? "Scheduled");
|
|
717
720
|
const timezone =
|
|
718
721
|
typeof input.timezone === "string"
|
|
@@ -741,9 +744,11 @@ export function ScheduleConfirmation({
|
|
|
741
744
|
onCancel: () => void;
|
|
742
745
|
onConfirm: () => void;
|
|
743
746
|
}) {
|
|
747
|
+
const authorization = input.authorization as { scope?: string; missing?: string[] } | undefined;
|
|
748
|
+
const missing = authorization?.missing ?? [];
|
|
744
749
|
const name = String(input.label ?? input.title ?? "Scheduled task");
|
|
745
750
|
const prompt = typeof input.prompt === "string" && input.prompt.trim()
|
|
746
|
-
? input.prompt
|
|
751
|
+
? input.prompt
|
|
747
752
|
: "Run the scheduled task";
|
|
748
753
|
|
|
749
754
|
return (
|
|
@@ -760,10 +765,10 @@ export function ScheduleConfirmation({
|
|
|
760
765
|
<Clock size={14} />
|
|
761
766
|
</span>
|
|
762
767
|
<div className="flex min-w-0 flex-1 flex-col">
|
|
763
|
-
<span className="
|
|
768
|
+
<span className="break-words text-[13.5px] leading-[18px] font-medium">
|
|
764
769
|
{name}
|
|
765
770
|
</span>
|
|
766
|
-
<span className="
|
|
771
|
+
<span className="break-words font-mono text-[11px] leading-4 tracking-tight text-kumo-inactive">
|
|
767
772
|
{scheduleCadence(input)}
|
|
768
773
|
</span>
|
|
769
774
|
</div>
|
|
@@ -773,16 +778,20 @@ export function ScheduleConfirmation({
|
|
|
773
778
|
<span className="shrink-0 font-mono text-[11px] leading-[18px] tracking-tight text-kumo-inactive">
|
|
774
779
|
task
|
|
775
780
|
</span>
|
|
776
|
-
<span className="min-w-0 flex-1 text-[13px] leading-[18px] text-kumo-subtle">
|
|
781
|
+
<span className="min-w-0 flex-1 whitespace-pre-wrap text-[13px] leading-[18px] text-kumo-subtle">
|
|
777
782
|
{prompt}
|
|
778
783
|
</span>
|
|
779
784
|
</div>
|
|
780
785
|
|
|
786
|
+
{input.id != null && <p className="m-0 text-xs">Task ID: {String(input.id)}</p>}
|
|
787
|
+
{typeof input.nextRunAt === "number" && <p className="m-0 text-xs">Next run: {new Intl.DateTimeFormat("en", { dateStyle: "medium", timeStyle: "short", timeZone: String(input.timezone) }).format(input.nextRunAt)}</p>}
|
|
788
|
+
{authorization?.scope && <div className="text-sm"><strong>Ongoing execution scope</strong><p className="m-0 whitespace-pre-wrap">{authorization.scope}</p></div>}
|
|
789
|
+
{missing.length > 0 && <div role="alert" className="text-sm text-kumo-danger">{missing.map((item, i) => <p key={i}>{item}</p>)}</div>}
|
|
781
790
|
<div className="flex items-center justify-end gap-2">
|
|
782
791
|
<WorkshopButton disabled={disabled} onClick={onCancel}>
|
|
783
792
|
Cancel
|
|
784
793
|
</WorkshopButton>
|
|
785
|
-
<WorkshopButton tone="primary" disabled={disabled} onClick={onConfirm}>
|
|
794
|
+
<WorkshopButton tone="primary" disabled={disabled || missing.length > 0} onClick={onConfirm}>
|
|
786
795
|
{disabled ? "Confirming…" : "Confirm schedule"}
|
|
787
796
|
</WorkshopButton>
|
|
788
797
|
</div>
|
|
@@ -790,81 +799,76 @@ export function ScheduleConfirmation({
|
|
|
790
799
|
);
|
|
791
800
|
}
|
|
792
801
|
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
802
|
+
/** Current task facts are supplied by the Host, never inferred from a past Tool result. */
|
|
803
|
+
export interface ScheduleCardState {
|
|
804
|
+
id: string;
|
|
805
|
+
enabled: boolean;
|
|
806
|
+
status: string;
|
|
807
|
+
deleted: boolean;
|
|
808
|
+
canToggle?: boolean;
|
|
809
|
+
}
|
|
810
|
+
export interface ScheduleCardControls {
|
|
811
|
+
load(id: string): Promise<ScheduleCardState>;
|
|
812
|
+
setEnabled(id: string, enabled: boolean): Promise<ScheduleCardState>;
|
|
813
|
+
open(id: string): void;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
export function ScheduleBlock({ call, onOpen, controls }: {
|
|
797
817
|
call: CloudOsToolCall;
|
|
798
|
-
/** 有 id 且宿主给了回调时,整张卡变成跳到「已安排」详情的按钮。 */
|
|
799
818
|
onOpen?: (scheduleId: string) => void;
|
|
819
|
+
controls?: ScheduleCardControls;
|
|
800
820
|
}) {
|
|
801
|
-
|
|
821
|
+
const scheduleId = !call.failed && !call.running ? scheduleIdOf(call.output) : "";
|
|
822
|
+
const [current, setCurrent] = useState<ScheduleCardState>();
|
|
823
|
+
const [busy, setBusy] = useState(false);
|
|
824
|
+
const [error, setError] = useState("");
|
|
825
|
+
const generation = useRef(0);
|
|
826
|
+
useEffect(() => {
|
|
827
|
+
const token = ++generation.current;
|
|
828
|
+
setCurrent(undefined); setError(""); setBusy(false);
|
|
829
|
+
if (scheduleId && controls) {
|
|
830
|
+
controls.load(scheduleId).then(value => {
|
|
831
|
+
if (token !== generation.current) return;
|
|
832
|
+
if (value.id !== scheduleId) throw new Error("Host returned a different task");
|
|
833
|
+
setCurrent(value);
|
|
834
|
+
}).catch(cause => { if (token === generation.current) setError(String(cause instanceof Error ? cause.message : cause)); });
|
|
835
|
+
}
|
|
836
|
+
return () => { generation.current++; };
|
|
837
|
+
}, [scheduleId, controls]);
|
|
802
838
|
if (call.awaitingApproval) return null;
|
|
803
|
-
const
|
|
804
|
-
const
|
|
805
|
-
const
|
|
806
|
-
const
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
</p>
|
|
837
|
-
</div>
|
|
838
|
-
<span
|
|
839
|
-
className={`ml-auto flex flex-shrink-0 items-center gap-1 self-center text-[12px] leading-4 font-medium ${
|
|
840
|
-
state === "failed"
|
|
841
|
-
? "text-kumo-danger"
|
|
842
|
-
: state === "running"
|
|
843
|
-
? "text-kumo-brand"
|
|
844
|
-
: "text-kumo-success"
|
|
845
|
-
}`}
|
|
846
|
-
>
|
|
847
|
-
{state === "failed" ? (
|
|
848
|
-
<WarningCircle size={13} weight="fill" />
|
|
849
|
-
) : state === "running" ? (
|
|
850
|
-
<CircleNotch
|
|
851
|
-
size={13}
|
|
852
|
-
weight="bold"
|
|
853
|
-
className="animate-spin motion-reduce:animate-none"
|
|
854
|
-
/>
|
|
855
|
-
) : (
|
|
856
|
-
<Check size={13} weight="bold" />
|
|
857
|
-
)}
|
|
858
|
-
{state === "failed"
|
|
859
|
-
? "Failed"
|
|
860
|
-
: state === "running"
|
|
861
|
-
? "Scheduling…"
|
|
862
|
-
: "Scheduled"}
|
|
863
|
-
</span>
|
|
864
|
-
</div>
|
|
865
|
-
</Card>
|
|
866
|
-
</div>
|
|
867
|
-
);
|
|
839
|
+
const saved = (call.output as { task?: Record<string, unknown> } | undefined)?.task;
|
|
840
|
+
const task = saved ?? call.input;
|
|
841
|
+
const name = String(task.label ?? task.title ?? "Scheduled task");
|
|
842
|
+
const open = controls ? (current && !current.deleted ? controls.open : undefined) : onOpen;
|
|
843
|
+
const clickable = Boolean(scheduleId && open);
|
|
844
|
+
const Card = clickable && !controls ? "button" : "div";
|
|
845
|
+
const toggle = async () => {
|
|
846
|
+
if (!controls || !current || current.deleted || current.canToggle === false || busy) return;
|
|
847
|
+
const token = generation.current;
|
|
848
|
+
setBusy(true); setError("");
|
|
849
|
+
try {
|
|
850
|
+
const value = await controls.setEnabled(scheduleId, !current.enabled);
|
|
851
|
+
if (value.id !== scheduleId) throw new Error("Host returned a different task");
|
|
852
|
+
if (token === generation.current) setCurrent(value);
|
|
853
|
+
} catch (cause) {
|
|
854
|
+
if (token === generation.current) setError(cause instanceof Error ? cause.message : String(cause));
|
|
855
|
+
} finally { if (token === generation.current) setBusy(false); }
|
|
856
|
+
};
|
|
857
|
+
return <div className="max-w-[860px]">
|
|
858
|
+
<Card className="w-full rounded-2xl border border-kumo-line bg-kumo-base px-4 py-3 text-left"
|
|
859
|
+
{...(clickable && !controls ? { type: "button" as const, onClick: () => open?.(scheduleId), "aria-label": `Open scheduled task: ${name}` } : {})}>
|
|
860
|
+
<div className="flex items-center gap-3"><Bell size={18} /><span className="min-w-0 flex-1 break-words text-sm font-medium">{name}</span>
|
|
861
|
+
<span className="text-xs">{call.failed ? "Failed" : call.running ? "Scheduling…" : "Scheduled"}</span>
|
|
862
|
+
</div>
|
|
863
|
+
<p className="my-1 text-xs text-kumo-inactive">{scheduleCadence(task)}</p>
|
|
864
|
+
{controls && scheduleId && <div className="flex items-center gap-3 text-sm">
|
|
865
|
+
<span>{current?.status ?? (error ? "Status unavailable" : "Loading…")}</span>
|
|
866
|
+
{current && !current.deleted && <button type="button" role="switch" aria-label="Enable scheduled task" aria-checked={current.enabled} disabled={busy || current.canToggle === false} onClick={() => void toggle()}>{current.enabled ? "On" : "Off"}</button>}
|
|
867
|
+
{clickable && <button type="button" aria-label={`Open scheduled task: ${name}`} onClick={() => open?.(scheduleId)}>Scheduled</button>}
|
|
868
|
+
</div>}
|
|
869
|
+
{error && <p role="alert" className="text-xs text-kumo-danger">{error}</p>}
|
|
870
|
+
</Card>
|
|
871
|
+
</div>;
|
|
868
872
|
}
|
|
869
873
|
|
|
870
874
|
// ── 原位授权 ──────────────────────────────────────────────
|
|
@@ -241,7 +241,7 @@ export function canonicalToolKind(name: string): CloudOsToolKind {
|
|
|
241
241
|
return "ask-user";
|
|
242
242
|
}
|
|
243
243
|
if (["suggest_followups", "suggestions"].includes(normalized)) return "suggestions";
|
|
244
|
-
if (["schedule", "cancel_schedule"].includes(normalized)) return "schedule";
|
|
244
|
+
if (["schedule", "update_schedule", "pause_schedule", "resume_schedule", "cancel_schedule", "list_schedules", "change_schedule_agent"].includes(normalized)) return "schedule";
|
|
245
245
|
if (normalized === "create_agent") return "create-agent";
|
|
246
246
|
if (normalized === "publish_extension") return "publish-extension";
|
|
247
247
|
return "generic";
|
|
@@ -353,7 +353,7 @@ export function getToolCallSummary(call: CloudOsToolCall): {
|
|
|
353
353
|
case "schedule": {
|
|
354
354
|
const label = stringField(input, "label", "title");
|
|
355
355
|
return {
|
|
356
|
-
verb: toolName === "cancel_schedule" ? "Cancelled schedule" : "Scheduled",
|
|
356
|
+
verb: toolName === "cancel_schedule" ? "Cancelled schedule" : toolName === "update_schedule" ? "Updated schedule" : toolName === "pause_schedule" ? "Paused schedule" : toolName === "resume_schedule" ? "Resumed schedule" : toolName === "list_schedules" ? "Listed schedules" : toolName === "change_schedule_agent" ? "Changed schedule Agent" : "Scheduled",
|
|
357
357
|
target: label || undefined,
|
|
358
358
|
};
|
|
359
359
|
}
|
|
@@ -594,7 +594,7 @@ function assistantBlocks(
|
|
|
594
594
|
}
|
|
595
595
|
}
|
|
596
596
|
|
|
597
|
-
if (call.kind === "schedule" && call.toolName === "schedule") {
|
|
597
|
+
if (call.kind === "schedule" && (call.toolName === "schedule" || call.toolName === "update_schedule")) {
|
|
598
598
|
flush();
|
|
599
599
|
blocks.push({ kind: "schedule", key, call });
|
|
600
600
|
return;
|
|
@@ -973,8 +973,6 @@ export function deriveTurnActivity(
|
|
|
973
973
|
options: {
|
|
974
974
|
isActive: boolean;
|
|
975
975
|
isRecovering?: boolean;
|
|
976
|
-
recoveryAttempt?: number;
|
|
977
|
-
recoveryMax?: number;
|
|
978
976
|
recoveryStatusLabel?: string;
|
|
979
977
|
awaitingApproval?: boolean;
|
|
980
978
|
hasPendingSteer?: boolean;
|
|
@@ -983,10 +981,7 @@ export function deriveTurnActivity(
|
|
|
983
981
|
if (options.isRecovering) {
|
|
984
982
|
return {
|
|
985
983
|
state: "connecting",
|
|
986
|
-
label: options.recoveryStatusLabel ??
|
|
987
|
-
(options.recoveryAttempt === undefined || options.recoveryMax === undefined
|
|
988
|
-
? "Recovering model response…"
|
|
989
|
-
: `Recovering model response ${options.recoveryAttempt}/${options.recoveryMax}…`),
|
|
984
|
+
label: options.recoveryStatusLabel ?? "Recovering model response…",
|
|
990
985
|
};
|
|
991
986
|
}
|
|
992
987
|
if (!options.isActive) return null;
|
package/cloud-os/index.ts
CHANGED
package/package.json
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":"4.1.10","results":[[":bot/cycles.test.ts",{"duration":55.58770800000002,"failed":false}],[":bot/skins.test.ts",{"duration":3032.4465840000003,"failed":false}],[":bot/engine.test.ts",{"duration":100.501834,"failed":false}],[":bot/shape.test.ts",{"duration":16.04204200000001,"failed":false}],[":bot/expressions.test.ts",{"duration":8.212458999999996,"failed":false}],[":bot/face.test.ts",{"duration":3.6211250000000064,"failed":false}],[":drag.test.ts",{"duration":1.7712499999999807,"failed":false}],[":animation.test.ts",{"duration":2.3806249999999807,"failed":false}]]}
|
|
@@ -673,11 +673,7 @@ function askUserResponseType(question: Record<string, unknown>) {
|
|
|
673
673
|
question.responseType === "multi_select" ||
|
|
674
674
|
question.responseType === "attachment"
|
|
675
675
|
) return question.responseType;
|
|
676
|
-
|
|
677
|
-
if (!Array.isArray(question.options) || question.options.length === 0) {
|
|
678
|
-
return "text";
|
|
679
|
-
}
|
|
680
|
-
return question.multiSelect === true ? "multi_select" : "single_select";
|
|
676
|
+
return undefined;
|
|
681
677
|
}
|
|
682
678
|
|
|
683
679
|
function CamelAskUser({
|
|
@@ -544,6 +544,9 @@ function summaryFor(
|
|
|
544
544
|
? `Could not publish ${extension}`
|
|
545
545
|
: `Published ${extension}`;
|
|
546
546
|
}
|
|
547
|
+
if (name === "schedule" || name === "update_schedule") {
|
|
548
|
+
return running ? "Preparing schedule..." : failed ? "Schedule was not saved" : name === "schedule" ? "Scheduled task" : "Updated schedule";
|
|
549
|
+
}
|
|
547
550
|
if (name === "cancel_schedule") {
|
|
548
551
|
return running
|
|
549
552
|
? "Cancelling schedule..."
|
package/src/parts/index.tsx
CHANGED
|
@@ -840,17 +840,6 @@ export interface AskQuestion {
|
|
|
840
840
|
required?: boolean;
|
|
841
841
|
}
|
|
842
842
|
|
|
843
|
-
function askQuestionResponseType(question: AskQuestion) {
|
|
844
|
-
if (question.responseType) return question.responseType;
|
|
845
|
-
const legacy = question as AskQuestion & {
|
|
846
|
-
kind?: string;
|
|
847
|
-
multiSelect?: boolean;
|
|
848
|
-
};
|
|
849
|
-
if (legacy.kind === "attachment") return "attachment";
|
|
850
|
-
if (!question.options?.length) return "text";
|
|
851
|
-
return legacy.multiSelect ? "multi_select" : "single_select";
|
|
852
|
-
}
|
|
853
|
-
|
|
854
843
|
interface AskAnswer {
|
|
855
844
|
selections: string[];
|
|
856
845
|
text: string;
|
|
@@ -878,7 +867,7 @@ export function AskUserPart({
|
|
|
878
867
|
const resolvedSubmitted = submittedAnswers.length > 0;
|
|
879
868
|
const valid = questions.length > 0 && questions.every(
|
|
880
869
|
(question, index) => {
|
|
881
|
-
const responseType =
|
|
870
|
+
const responseType = question.responseType;
|
|
882
871
|
const answer = answerAt(index);
|
|
883
872
|
if (
|
|
884
873
|
answer.selections.length === 0 && !answer.text.trim()
|
|
@@ -898,7 +887,7 @@ export function AskUserPart({
|
|
|
898
887
|
const answer = next[questionIndex]!;
|
|
899
888
|
next[questionIndex] = {
|
|
900
889
|
...answer,
|
|
901
|
-
selections:
|
|
890
|
+
selections: questions[questionIndex]!.responseType ===
|
|
902
891
|
"multi_select"
|
|
903
892
|
? answer.selections.includes(option)
|
|
904
893
|
? answer.selections.filter((item) => item !== option)
|
|
@@ -930,7 +919,7 @@ export function AskUserPart({
|
|
|
930
919
|
data-state={resolvedSubmitted ? "submitted" : "pending"}
|
|
931
920
|
>
|
|
932
921
|
{questions.map((question, questionIndex) => {
|
|
933
|
-
const responseType =
|
|
922
|
+
const responseType = question.responseType;
|
|
934
923
|
const choice = responseType === "single_select" ||
|
|
935
924
|
responseType === "multi_select";
|
|
936
925
|
return (
|