fix: make name/emoji/persona optional, auto-skip empty steps, back button
- Make name, emoji, persona params optional in dedicated-channel-agent - Auto-skip steps whose template args resolve to empty strings - Move "Back to Recipes" to a back arrow next to the title Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -11,9 +11,9 @@
|
|||||||
{ "id": "agent_id", "label": "Agent ID", "type": "string", "required": true, "placeholder": "e.g. my-bot" },
|
{ "id": "agent_id", "label": "Agent ID", "type": "string", "required": true, "placeholder": "e.g. my-bot" },
|
||||||
{ "id": "guild_id", "label": "Guild", "type": "discord_guild", "required": true },
|
{ "id": "guild_id", "label": "Guild", "type": "discord_guild", "required": true },
|
||||||
{ "id": "channel_id", "label": "Channel", "type": "discord_channel", "required": true },
|
{ "id": "channel_id", "label": "Channel", "type": "discord_channel", "required": true },
|
||||||
{ "id": "name", "label": "Display Name", "type": "string", "required": true, "placeholder": "e.g. MyBot" },
|
{ "id": "name", "label": "Display Name", "type": "string", "required": false, "placeholder": "e.g. MyBot" },
|
||||||
{ "id": "emoji", "label": "Emoji", "type": "string", "required": false, "placeholder": "e.g. \ud83e\udd16" },
|
{ "id": "emoji", "label": "Emoji", "type": "string", "required": false, "placeholder": "e.g. \ud83e\udd16" },
|
||||||
{ "id": "persona", "label": "Persona", "type": "textarea", "required": true, "placeholder": "You are..." }
|
{ "id": "persona", "label": "Persona", "type": "textarea", "required": false, "placeholder": "You are..." }
|
||||||
],
|
],
|
||||||
"steps": [
|
"steps": [
|
||||||
{ "action": "create_agent", "label": "Create independent agent", "args": { "agentId": "{{agent_id}}", "independent": true } },
|
{ "action": "create_agent", "label": "Create independent agent", "args": { "agentId": "{{agent_id}}", "independent": true } },
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ export interface ResolvedStep {
|
|||||||
label: string;
|
label: string;
|
||||||
args: Record<string, unknown>;
|
args: Record<string, unknown>;
|
||||||
description: string;
|
description: string;
|
||||||
|
skippable: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolveSteps(
|
export function resolveSteps(
|
||||||
@@ -92,6 +93,14 @@ export function resolveSteps(
|
|||||||
if (step.action === "config_patch") {
|
if (step.action === "config_patch") {
|
||||||
resolved.params = params;
|
resolved.params = params;
|
||||||
}
|
}
|
||||||
|
// A step is skippable if any of its template args resolved to empty string
|
||||||
|
const skippable = Object.entries(step.args).some(([key, origValue]) => {
|
||||||
|
if (typeof origValue === "string" && origValue.includes("{{")) {
|
||||||
|
const rv = resolved[key];
|
||||||
|
return typeof rv === "string" && rv.trim() === "";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
const actionDef = getAction(step.action);
|
const actionDef = getAction(step.action);
|
||||||
const description = actionDef?.describe(resolved) || step.label;
|
const description = actionDef?.describe(resolved) || step.label;
|
||||||
return {
|
return {
|
||||||
@@ -100,6 +109,7 @@ export function resolveSteps(
|
|||||||
label: step.label,
|
label: step.label,
|
||||||
args: resolved,
|
args: resolved,
|
||||||
description: description || step.label,
|
description: description || step.label,
|
||||||
|
skippable,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,9 +48,10 @@ export function Cook({
|
|||||||
const handleNext = () => {
|
const handleNext = () => {
|
||||||
const steps = resolveSteps(recipe.steps, params);
|
const steps = resolveSteps(recipe.steps, params);
|
||||||
setResolvedStepList(steps);
|
setResolvedStepList(steps);
|
||||||
setStepStatuses(steps.map(() => "pending"));
|
// Auto-skip steps whose template args resolved to empty
|
||||||
|
setStepStatuses(steps.map((s) => (s.skippable ? "skipped" : "pending")));
|
||||||
setStepErrors({});
|
setStepErrors({});
|
||||||
setHasConfigPatch(steps.some((s) => s.action === "config_patch"));
|
setHasConfigPatch(steps.some((s) => !s.skippable && s.action === "config_patch"));
|
||||||
setPhase("confirm");
|
setPhase("confirm");
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -75,8 +76,7 @@ export function Cook({
|
|||||||
|
|
||||||
const handleExecute = () => {
|
const handleExecute = () => {
|
||||||
setPhase("execute");
|
setPhase("execute");
|
||||||
const statuses: StepStatus[] = resolvedStepList.map(() => "pending");
|
const statuses = [...stepStatuses];
|
||||||
setStepStatuses([...statuses]);
|
|
||||||
runFrom(0, statuses);
|
runFrom(0, statuses);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -131,7 +131,12 @@ export function Cook({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<section>
|
<section>
|
||||||
<h2 className="text-2xl font-bold mb-4">{recipe.name}</h2>
|
<div className="flex items-center gap-2 mb-4">
|
||||||
|
<Button variant="ghost" size="sm" className="px-2" onClick={onDone}>
|
||||||
|
←
|
||||||
|
</Button>
|
||||||
|
<h2 className="text-2xl font-bold">{recipe.name}</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
{phase === "params" && (
|
{phase === "params" && (
|
||||||
<ParamForm
|
<ParamForm
|
||||||
@@ -149,13 +154,18 @@ export function Cook({
|
|||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
{resolvedStepList.map((step, i) => (
|
{resolvedStepList.map((step, i) => (
|
||||||
<div key={i} className="flex items-start gap-3">
|
<div key={i} className={cn("flex items-start gap-3", stepStatuses[i] === "skipped" && "opacity-50")}>
|
||||||
<span className={cn("text-lg font-mono w-5 text-center", statusColor(stepStatuses[i]))}>
|
<span className={cn("text-lg font-mono w-5 text-center", statusColor(stepStatuses[i]))}>
|
||||||
{statusIcon(stepStatuses[i])}
|
{statusIcon(stepStatuses[i])}
|
||||||
</span>
|
</span>
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<div className="text-sm font-medium">{step.label}</div>
|
<div className="text-sm font-medium">
|
||||||
{step.description !== step.label && (
|
{step.label}
|
||||||
|
{stepStatuses[i] === "skipped" && phase === "confirm" && (
|
||||||
|
<span className="text-xs text-muted-foreground ml-2">(skipped — empty params)</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{step.description !== step.label && stepStatuses[i] !== "skipped" && (
|
||||||
<div className="text-xs text-muted-foreground">{step.description}</div>
|
<div className="text-xs text-muted-foreground">{step.description}</div>
|
||||||
)}
|
)}
|
||||||
{stepErrors[i] && (
|
{stepErrors[i] && (
|
||||||
@@ -198,9 +208,6 @@ export function Cook({
|
|||||||
Use "Apply Changes" in the sidebar to restart the gateway and activate config changes.
|
Use "Apply Changes" in the sidebar to restart the gateway and activate config changes.
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
<Button className="mt-4" onClick={onDone}>
|
|
||||||
Back to Recipes
|
|
||||||
</Button>
|
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user