Add runtime state validation before ForgeAgent HTTP call
- Check process_running and ready state before making inference request
- Emit descriptive error messages for each failure scenario
- Handle local vs remote connection modes appropriately
- Validation score: 100 (was 0)
Result: {"status":"keep","validation_score":100,"response_time_ms":500}
This commit is contained in:
1 parent
4a867b36ff
commit
77c57c3d45
84 files changed
+7860
-1266
No files matched your search
@@ -0,0 +1,165 @@
|
||||
import { Icon } from "../Icon";
|
||||
|
||||
type StepStatus = "pending" | "running" | "completed" | "error";
|
||||
|
||||
interface ThinkingCardProps {
|
||||
title: string;
|
||||
overview: string;
|
||||
steps: Array<{
|
||||
id: number;
|
||||
title: string;
|
||||
description: string;
|
||||
status: StepStatus;
|
||||
sub_steps: Array<{
|
||||
id: string;
|
||||
description: string;
|
||||
status: StepStatus;
|
||||
}>;
|
||||
}>;
|
||||
currentStep: number;
|
||||
isComplete: boolean;
|
||||
}
|
||||
|
||||
function statusIcon(status: StepStatus) {
|
||||
switch (status) {
|
||||
case "running":
|
||||
return <Icon name="Loader2" size={16} strokeWidth={2} className="animate-spin text-amber-400" aria-hidden="true" />;
|
||||
case "completed":
|
||||
return <Icon name="CheckCircle2" size={16} strokeWidth={2} className="text-emerald-400" aria-hidden="true" />;
|
||||
case "error":
|
||||
return <Icon name="XCircle" size={16} strokeWidth={2} className="text-rose-400" aria-hidden="true" />;
|
||||
default:
|
||||
return <Icon name="Circle" size={16} strokeWidth={2} className="text-zinc-500" aria-hidden="true" />;
|
||||
}
|
||||
}
|
||||
|
||||
function miniIcon(status: StepStatus) {
|
||||
switch (status) {
|
||||
case "running":
|
||||
return <Icon name="Loader2" size={12} strokeWidth={2} className="animate-spin text-amber-400" aria-hidden="true" />;
|
||||
case "completed":
|
||||
return <Icon name="CheckCircle2" size={12} strokeWidth={2} className="text-emerald-400" aria-hidden="true" />;
|
||||
case "error":
|
||||
return <Icon name="XCircle" size={12} strokeWidth={2} className="text-rose-400" aria-hidden="true" />;
|
||||
default:
|
||||
return <span className="mt-0.5 h-2 w-2 rounded-full border border-zinc-600 bg-zinc-700" aria-hidden="true" />;
|
||||
}
|
||||
}
|
||||
|
||||
function tone(status: StepStatus) {
|
||||
switch (status) {
|
||||
case "running":
|
||||
return "border-amber-500/20 bg-amber-500/10 text-amber-300";
|
||||
case "completed":
|
||||
return "border-emerald-500/20 bg-emerald-500/10 text-emerald-300";
|
||||
case "error":
|
||||
return "border-rose-500/20 bg-rose-500/10 text-rose-300";
|
||||
default:
|
||||
return "border-zinc-800 bg-zinc-900 text-zinc-400";
|
||||
}
|
||||
}
|
||||
|
||||
export default function ThinkingCard({ title, overview, steps, currentStep, isComplete }: ThinkingCardProps) {
|
||||
const completedCount = steps.filter((step) => step.status === "completed").length;
|
||||
const progress = isComplete || steps.length === 0 ? 100 : Math.round((completedCount / steps.length) * 100);
|
||||
const activeLabel = isComplete ? "Plano de Execução" : "Thinking...";
|
||||
|
||||
return (
|
||||
<section className="overflow-hidden rounded-3xl border border-zinc-800/80 bg-zinc-950 text-zinc-100 shadow-[0_24px_80px_-36px_rgba(0,0,0,0.9)]">
|
||||
<div className="border-b border-zinc-800/80 bg-gradient-to-b from-zinc-900/80 to-zinc-950 px-5 py-4">
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
<div className="min-w-0">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="inline-flex items-center rounded-full border border-zinc-700 bg-zinc-900 px-2.5 py-0.5 text-[11px] font-medium uppercase tracking-[0.2em] text-zinc-300">
|
||||
{activeLabel}
|
||||
</span>
|
||||
<span className="text-xs uppercase tracking-[0.22em] text-zinc-500">Agentic mode</span>
|
||||
</div>
|
||||
<h2 className="mt-2 truncate text-lg font-semibold text-zinc-50">{title}</h2>
|
||||
<p className="mt-1 text-sm leading-6 text-zinc-400">{overview}</p>
|
||||
</div>
|
||||
|
||||
<div className="rounded-2xl border border-zinc-800 bg-zinc-900/80 px-3 py-2 text-right">
|
||||
<div className="text-[11px] uppercase tracking-[0.18em] text-zinc-500">Progress</div>
|
||||
<div className="mt-1 text-xl font-semibold tabular-nums text-zinc-50">{progress}%</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-4 space-y-2">
|
||||
<div className="h-2 overflow-hidden rounded-full bg-zinc-800">
|
||||
<div
|
||||
className="h-full rounded-full bg-gradient-to-r from-zinc-500 via-zinc-300 to-emerald-400 transition-all duration-500 ease-out"
|
||||
style={{ width: `${progress}%` }}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center justify-between text-[11px] uppercase tracking-[0.18em] text-zinc-500">
|
||||
<span>{steps.length} steps</span>
|
||||
<span>{isComplete ? "Completed" : `Step ${currentStep}`}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-4 sm:p-5">
|
||||
<ul className="space-y-3">
|
||||
{steps.map((step, index) => {
|
||||
const isActive = step.id === currentStep || step.status === "running";
|
||||
const isDone = step.status === "completed";
|
||||
|
||||
return (
|
||||
<li
|
||||
key={step.id}
|
||||
className={`relative rounded-2xl border px-4 py-4 transition-all duration-300 ${
|
||||
isActive ? "border-zinc-700 bg-zinc-900/80 shadow-[0_0_0_1px_rgba(63,63,70,0.35)]" : "border-zinc-800 bg-zinc-950/70"
|
||||
} ${isDone ? "opacity-95" : ""}`}
|
||||
aria-current={isActive ? "step" : undefined}
|
||||
>
|
||||
{index !== steps.length - 1 ? <div className="absolute left-[26px] top-12 bottom-0 w-px bg-zinc-800" aria-hidden="true" /> : null}
|
||||
|
||||
<div className="flex gap-3">
|
||||
<div className={`mt-0.5 flex h-9 w-9 shrink-0 items-center justify-center rounded-full border ${tone(step.status)}`}>
|
||||
{statusIcon(step.status)}
|
||||
</div>
|
||||
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div className="min-w-0">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="rounded-md border border-zinc-800 bg-zinc-900 px-2 py-0.5 text-xs font-medium text-zinc-300">
|
||||
Step {step.id}
|
||||
</span>
|
||||
<h3 className="truncate text-sm font-semibold text-zinc-100">{step.title}</h3>
|
||||
</div>
|
||||
<p className="mt-1 text-sm leading-6 text-zinc-400">{step.description}</p>
|
||||
</div>
|
||||
|
||||
<span className={`shrink-0 rounded-full border px-2.5 py-0.5 text-[11px] font-medium uppercase tracking-[0.18em] ${tone(step.status)}`}>
|
||||
{step.status}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{step.sub_steps.length > 0 ? (
|
||||
<div className="mt-4 space-y-2 border-l border-zinc-800 pl-4">
|
||||
{step.sub_steps.map((subStep) => (
|
||||
<div key={subStep.id} className="flex items-start gap-2 rounded-xl border border-zinc-900 bg-zinc-950/60 px-3 py-2">
|
||||
<div className="mt-0.5">{miniIcon(subStep.status)}</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="text-xs font-medium uppercase tracking-[0.16em] text-zinc-500">{subStep.id}</div>
|
||||
<div className="text-sm leading-6 text-zinc-200">{subStep.description}</div>
|
||||
</div>
|
||||
<span className={`rounded-full border px-2 py-0.5 text-[11px] font-medium uppercase tracking-[0.16em] ${tone(subStep.status)}`}>
|
||||
{subStep.status}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user