Compare commits

...

3 Commits

Author SHA1 Message Date
Lluis Agusti
4fa9c6a797 chore: improvements 2026-02-13 23:33:09 +08:00
Lluis Agusti
256d59303a Merge remote-tracking branch 'origin/dev' into lluis/improve-create-edit-ux 2026-02-13 22:37:38 +08:00
Lluis Agusti
e0aa565192 fix: improve create agent ux 2026-02-13 21:41:35 +08:00
17 changed files with 811 additions and 272 deletions

View File

@@ -4,7 +4,6 @@ import { Button } from "@/components/atoms/Button/Button";
import { Text } from "@/components/atoms/Text/Text"; import { Text } from "@/components/atoms/Text/Text";
import { import {
BookOpenIcon, BookOpenIcon,
CheckFatIcon,
PencilSimpleIcon, PencilSimpleIcon,
WarningDiamondIcon, WarningDiamondIcon,
} from "@phosphor-icons/react"; } from "@phosphor-icons/react";
@@ -24,6 +23,7 @@ import {
ClarificationQuestionsCard, ClarificationQuestionsCard,
ClarifyingQuestion, ClarifyingQuestion,
} from "./components/ClarificationQuestionsCard"; } from "./components/ClarificationQuestionsCard";
import sparklesImg from "./components/MiniGame/assets/sparkles.png";
import { MiniGame } from "./components/MiniGame/MiniGame"; import { MiniGame } from "./components/MiniGame/MiniGame";
import { import {
AccordionIcon, AccordionIcon,
@@ -83,7 +83,8 @@ function getAccordionMeta(output: CreateAgentToolOutput) {
) { ) {
return { return {
icon, icon,
title: "Creating agent, this may take a few minutes. Sit back and relax.", title:
"Creating agent, this may take a few minutes. Play while you wait.",
expanded: true, expanded: true,
}; };
} }
@@ -167,16 +168,22 @@ export function CreateAgentTool({ part }: Props) {
{isAgentSavedOutput(output) && ( {isAgentSavedOutput(output) && (
<div className="rounded-xl border border-border/60 bg-card p-4 shadow-sm"> <div className="rounded-xl border border-border/60 bg-card p-4 shadow-sm">
<div className="flex items-baseline gap-2"> <div className="flex items-baseline gap-2">
<CheckFatIcon <img
size={18} src={sparklesImg.src}
weight="regular" alt="sparkles"
className="relative top-1 text-green-500" width={24}
height={24}
className="relative top-1"
/> />
<Text <Text
variant="body-medium" variant="body-medium"
className="text-blacks mb-2 text-[16px]" className="text-blacks mb-2 text-[16px]"
> >
{output.message} Agent{" "}
<span className="text-[rgb(124,58,237)]">
{output.agent_name}
</span>{" "}
has been saved to your library!
</Text> </Text>
</div> </div>
<div className="mt-3 flex flex-wrap gap-4"> <div className="mt-3 flex flex-wrap gap-4">

View File

@@ -2,20 +2,78 @@
import { useMiniGame } from "./useMiniGame"; import { useMiniGame } from "./useMiniGame";
function Key({ children }: { children: React.ReactNode }) {
return <strong>[{children}]</strong>;
}
export function MiniGame() { export function MiniGame() {
const { canvasRef } = useMiniGame(); const {
canvasRef,
activeMode,
showOverlay,
score,
highScore,
onContinue,
} = useMiniGame();
const isRunActive =
activeMode === "run" || activeMode === "idle" || activeMode === "over";
const isBossActive =
activeMode === "boss" ||
activeMode === "boss-intro" ||
activeMode === "boss-defeated";
let overlayText: string | undefined;
let buttonLabel = "Continue";
if (activeMode === "idle") {
buttonLabel = "Start";
} else if (activeMode === "boss-intro") {
overlayText = "Face the bandit!";
} else if (activeMode === "boss-defeated") {
overlayText = "Great job, keep on going";
} else if (activeMode === "over") {
overlayText = `Score: ${score} / Record: ${highScore}`;
buttonLabel = "Retry";
}
return ( return (
<div className="flex flex-col gap-2">
<p className="text-sm font-medium text-purple-500">
{isBossActive ? (
<>
Duel mode: <Key></Key> to move · <Key>Z</Key> to attack ·{" "}
<Key>X</Key> to block · <Key>Space</Key> to jump
</>
) : (
<>
Run mode: <Key>Space</Key> to jump
</>
)}
</p>
<div <div
className="w-full overflow-hidden rounded-md bg-background text-foreground" className="relative w-full overflow-hidden rounded-md bg-background text-foreground"
style={{ border: "1px solid #d17fff" }} style={{ border: "1px solid #d17fff" }}
> >
<canvas <canvas
ref={canvasRef} ref={canvasRef}
tabIndex={0} tabIndex={0}
className="block w-full outline-none" className="block w-full outline-none"
style={{ imageRendering: "pixelated" }}
/> />
{showOverlay && (
<div className="absolute inset-0 flex flex-col items-center justify-center gap-3 bg-black/40">
{overlayText && (
<p className="text-lg font-bold text-white">{overlayText}</p>
)}
<button
type="button"
onClick={onContinue}
className="rounded-md bg-white px-4 py-2 text-sm font-semibold text-zinc-800 shadow-md transition-colors hover:bg-zinc-100"
>
{buttonLabel}
</button>
</div>
)}
</div>
</div> </div>
); );
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -136,7 +136,7 @@ export function getAnimationText(part: {
if (isOperationPendingOutput(output)) return "Agent creation in progress"; if (isOperationPendingOutput(output)) return "Agent creation in progress";
if (isOperationInProgressOutput(output)) if (isOperationInProgressOutput(output))
return "Agent creation already in progress"; return "Agent creation already in progress";
if (isAgentSavedOutput(output)) return `Saved "${output.agent_name}"`; if (isAgentSavedOutput(output)) return `Saved ${output.agent_name}`;
if (isAgentPreviewOutput(output)) return `Preview "${output.agent_name}"`; if (isAgentPreviewOutput(output)) return `Preview "${output.agent_name}"`;
if (isClarificationNeededOutput(output)) return "Needs clarification"; if (isClarificationNeededOutput(output)) return "Needs clarification";
return "Error creating agent"; return "Error creating agent";

View File

@@ -5,7 +5,6 @@ import type { ToolUIPart } from "ai";
import { useCopilotChatActions } from "../../components/CopilotChatActionsProvider/useCopilotChatActions"; import { useCopilotChatActions } from "../../components/CopilotChatActionsProvider/useCopilotChatActions";
import { MorphingTextAnimation } from "../../components/MorphingTextAnimation/MorphingTextAnimation"; import { MorphingTextAnimation } from "../../components/MorphingTextAnimation/MorphingTextAnimation";
import { OrbitLoader } from "../../components/OrbitLoader/OrbitLoader"; import { OrbitLoader } from "../../components/OrbitLoader/OrbitLoader";
import { ProgressBar } from "../../components/ProgressBar/ProgressBar";
import { import {
ContentCardDescription, ContentCardDescription,
ContentCodeBlock, ContentCodeBlock,
@@ -15,7 +14,7 @@ import {
ContentMessage, ContentMessage,
} from "../../components/ToolAccordion/AccordionContent"; } from "../../components/ToolAccordion/AccordionContent";
import { ToolAccordion } from "../../components/ToolAccordion/ToolAccordion"; import { ToolAccordion } from "../../components/ToolAccordion/ToolAccordion";
import { useAsymptoticProgress } from "../../hooks/useAsymptoticProgress"; import { MiniGame } from "../CreateAgent/components/MiniGame/MiniGame";
import { import {
ClarificationQuestionsCard, ClarificationQuestionsCard,
ClarifyingQuestion, ClarifyingQuestion,
@@ -80,7 +79,12 @@ function getAccordionMeta(output: EditAgentToolOutput): {
isOperationPendingOutput(output) || isOperationPendingOutput(output) ||
isOperationInProgressOutput(output) isOperationInProgressOutput(output)
) { ) {
return { icon: <OrbitLoader size={32} />, title: "Editing agent" }; return {
icon: <OrbitLoader size={32} />,
title:
"Editing agent, this may take a few minutes. Play while you wait.",
expanded: true,
};
} }
return { return {
icon: ( icon: (
@@ -105,7 +109,6 @@ export function EditAgentTool({ part }: Props) {
(isOperationStartedOutput(output) || (isOperationStartedOutput(output) ||
isOperationPendingOutput(output) || isOperationPendingOutput(output) ||
isOperationInProgressOutput(output)); isOperationInProgressOutput(output));
const progress = useAsymptoticProgress(isOperating);
const hasExpandableContent = const hasExpandableContent =
part.state === "output-available" && part.state === "output-available" &&
!!output && !!output &&
@@ -149,9 +152,9 @@ export function EditAgentTool({ part }: Props) {
<ToolAccordion {...getAccordionMeta(output)}> <ToolAccordion {...getAccordionMeta(output)}>
{isOperating && ( {isOperating && (
<ContentGrid> <ContentGrid>
<ProgressBar value={progress} className="max-w-[280px]" /> <MiniGame />
<ContentHint> <ContentHint>
This could take a few minutes, grab a coffee This could take a few minutes play while you wait!
</ContentHint> </ContentHint>
</ContentGrid> </ContentGrid>
)} )}

View File

@@ -2,8 +2,14 @@
import type { ToolUIPart } from "ai"; import type { ToolUIPart } from "ai";
import { MorphingTextAnimation } from "../../components/MorphingTextAnimation/MorphingTextAnimation"; import { MorphingTextAnimation } from "../../components/MorphingTextAnimation/MorphingTextAnimation";
import { OrbitLoader } from "../../components/OrbitLoader/OrbitLoader";
import { ToolAccordion } from "../../components/ToolAccordion/ToolAccordion"; import { ToolAccordion } from "../../components/ToolAccordion/ToolAccordion";
import { ContentMessage } from "../../components/ToolAccordion/AccordionContent"; import {
ContentGrid,
ContentHint,
ContentMessage,
} from "../../components/ToolAccordion/AccordionContent";
import { MiniGame } from "../CreateAgent/components/MiniGame/MiniGame";
import { import {
getAccordionMeta, getAccordionMeta,
getAnimationText, getAnimationText,
@@ -60,6 +66,21 @@ export function RunAgentTool({ part }: Props) {
/> />
</div> </div>
{isStreaming && !output && (
<ToolAccordion
icon={<OrbitLoader size={32} />}
title="Running agent, this may take a few minutes. Play while you wait."
expanded={true}
>
<ContentGrid>
<MiniGame />
<ContentHint>
This could take a few minutes play while you wait!
</ContentHint>
</ContentGrid>
</ToolAccordion>
)}
{hasExpandableContent && output && ( {hasExpandableContent && output && (
<ToolAccordion {...getAccordionMeta(output)}> <ToolAccordion {...getAccordionMeta(output)}>
{isRunAgentExecutionStartedOutput(output) && ( {isRunAgentExecutionStartedOutput(output) && (