import { Label } from "@/components/ui/label"; import { Input } from "@/components/ui/input"; import { Switch } from "@/components/ui/switch"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; import { Separator } from "@/components/ui/separator"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Plus, Trash2 } from "lucide-react"; import { useConfigStore } from "@/stores/configStore"; import type { EarlyStopCondition, EarlyStopType, TopologyHookConfig, TopologyHookType } from "@/types/execution"; export function RunnerConfigForm() { const { runnerConfig, updateRunnerConfig } = useConfigStore(); // ── Early-stop helpers ────────────────────────────────────────────── const addEarlyStop = () => { updateRunnerConfig({ early_stop_conditions: [ ...runnerConfig.early_stop_conditions, { type: "keyword", keyword: "FINAL ANSWER" }, ], }); }; const removeEarlyStop = (idx: number) => { updateRunnerConfig({ early_stop_conditions: runnerConfig.early_stop_conditions.filter((_, i) => i !== idx), }); }; const updateEarlyStop = (idx: number, patch: Partial) => { updateRunnerConfig({ early_stop_conditions: runnerConfig.early_stop_conditions.map((c, i) => i === idx ? { ...c, ...patch } : c ), }); }; // ── Topology-hook helpers ─────────────────────────────────────────── const addTopologyHook = () => { updateRunnerConfig({ topology_hooks: [ ...runnerConfig.topology_hooks, { type: "stop_on_keyword", keyword: "TASK_COMPLETE" }, ], }); }; const removeTopologyHook = (idx: number) => { updateRunnerConfig({ topology_hooks: runnerConfig.topology_hooks.filter((_, i) => i !== idx), }); }; const updateTopologyHook = (idx: number, patch: Partial) => { updateRunnerConfig({ topology_hooks: runnerConfig.topology_hooks.map((h, i) => i === idx ? { ...h, ...patch } : h ), }); }; const hasDynamicFeatures = runnerConfig.enable_dynamic_topology || runnerConfig.early_stop_conditions.length > 0 || runnerConfig.topology_hooks.length > 0; return (
{/* ── General settings ─────────────────────────────────────── */} Runner Configuration Configure the MACPRunner execution settings.
updateRunnerConfig({ timeout: parseFloat(e.target.value) || 60 })} />
updateRunnerConfig({ max_retries: parseInt(e.target.value) || 2 })} />
updateRunnerConfig({ max_parallel_size: parseInt(e.target.value) || 5 })} />
updateRunnerConfig({ max_tool_iterations: parseInt(e.target.value) || 3 })} />
updateRunnerConfig({ memory_context_limit: parseInt(e.target.value) || 5 })} />

Weight-aware scheduling that dynamically reorders agents based on edge weights and intermediate results.

updateRunnerConfig({ adaptive: v })} />

Allow agents without dependencies to execute concurrently, improving throughput for fan-out topologies.

updateRunnerConfig({ enable_parallel: v })} />

Activate shared memory so agents can read and write persistent context across execution steps.

updateRunnerConfig({ enable_memory: v })} />

Enable runtime graph modifications via early stopping conditions and topology hooks defined below.

updateRunnerConfig({ enable_dynamic_topology: v })} />

Send the task query to every agent in the graph, not just the start node. Useful when all agents need full context.

updateRunnerConfig({ broadcast_task_to_all: v })} />
{/* ── Early Stopping ───────────────────────────────────────── */} Early Stopping Halt execution when specific conditions are met. Saves tokens by stopping early. {runnerConfig.early_stop_conditions.map((cond, idx) => (
{cond.type === "keyword" && ( <> updateEarlyStop(idx, { keyword: e.target.value })} /> )} {cond.type === "token_limit" && ( <> updateEarlyStop(idx, { max_tokens: parseInt(e.target.value) || null })} /> )} {cond.type === "agent_count" && ( <> updateEarlyStop(idx, { max_agents: parseInt(e.target.value) || null })} /> )}
))}
{/* ── Topology Hooks ───────────────────────────────────────── */} Topology Hooks Dynamically modify the graph during execution based on intermediate results. {runnerConfig.topology_hooks.map((hook, idx) => (
{/* Parameters row */}
{/* Keyword field — used by most hook types */} {["stop_on_keyword", "insert_chain_on_keyword", "add_edge_on_keyword", "redirect_end_on_keyword", "skip_agent_on_keyword"].includes(hook.type) && (
updateTopologyHook(idx, { keyword: e.target.value })} />
)} {/* Token threshold */} {hook.type === "skip_on_token_budget" && (
updateTopologyHook(idx, { token_threshold: parseInt(e.target.value) || null })} />
)} {/* Reviewer agent */} {hook.type === "force_reviewer_on_error" && (
updateTopologyHook(idx, { reviewer_agent_id: e.target.value })} />
)} {/* Source agent — for insert_chain and add_edge */} {["insert_chain_on_keyword", "add_edge_on_keyword"].includes(hook.type) && (
updateTopologyHook(idx, { source_agent: e.target.value })} />
)} {/* Target agent — for insert_chain, add_edge, redirect_end, skip_agent */} {["insert_chain_on_keyword", "add_edge_on_keyword", "redirect_end_on_keyword", "skip_agent_on_keyword"].includes(hook.type) && (
updateTopologyHook(idx, { target_agent: e.target.value })} />
)} {/* Weight — for add_edge */} {hook.type === "add_edge_on_keyword" && (
updateTopologyHook(idx, { weight: parseFloat(e.target.value) || 1.0 })} />
)}
))}
); }