ADR-043: Configurable Workflow UI — Per-Step Node Config, UI Settings Store, and Run Comparison¶
Status: Accepted
Date: 2026-07-07
Related: agentic_v2/langchain/config.py (StepConfig),
agentic_v2/langchain/personas.py (new), agentic_v2/ui_settings.py (new),
agentic_v2/server/routes/{catalog,settings_routes}.py (new),
agentic_v2/server/models_settings.py (new), POST /api/eval/compare
(server/routes/runs.py), ADR-014 (wire-format drift), ADR-040 (curated
model registry)
Context¶
The web UI could visualize workflows but not configure them: the editor was a raw-YAML textarea with a read-only inspector, DAG edges were anonymous arrows, model routing was env-var-only, and evaluation offered no way to compare two runs of the same task. Making the platform usable from the front end (ComfyUI-style: click a node or edge, edit everything that matters) requires new wire contracts, per-step engine plumbing, and a place to persist UI-managed settings.
Decision¶
-
Per-step node config lives in the workflow YAML schema.
StepConfiggainsmodel_params(temperature/top_p/max_tokens, validated ranges),persona(registry id), andobservers(channel allowlist:trace/websocket/scoring;null= all). Temperature threads throughcreate_agent → get_model_for_tier → get_chat_model;top_p/max_tokensare applied generically via Pydanticmodel_copywith per-provider field aliasing (num_predictfor Ollama, etc.), so unsupported params degrade silently instead of breaking a provider. -
Personas are a first-class registry (
config/defaults/personas.yaml), combining pre-canned BMAD-style personas (Winston the architect, Mary, James, Quinn) with the existingprompts/*.mdrole prompts. Resolution order:step.persona>step.prompt_file> role-from-agent-name > generic fallback. -
UI-managed settings persist in a JSON store (
agentic_v2/ui_settings.py, default<repo>/.agentic_ui_settings.json, env overrideAGENTIC_UI_SETTINGS_PATH) — NOT inmodel_registry.yamlor env vars, which stay deployment-owned. It holds provider endpoint entries (base URL + the name of the credential env var, never the secret), tier rerank overrides, and model capability tags. Routing consumes tier overrides between the env-var pin and the probed default:model_override > AGENTIC_MODEL_TIER_{n} > UI override > probed default > registry chain. Rationale: a UI edit should never silently beat an explicit deployment pin. -
DAG edges are self-describing. The DAG endpoint enriches each edge with
id,label(target input keys fed by the source),mappings(fullkey = ${...}expressions), and the target'swhen— the editor renders labels and an edge inspector instead of anonymous arrows, and the same derivation runs client-side against unsaved drafts. -
Run comparison is replay-based.
POST /api/eval/comparere-scores two captured run logs under one rubric (same path as re-evaluate) and returns per-criterion deltas plus a winner. Nothing persists and no workflow re-executes; comparing prompt/workflow variants means running each once, then comparing the logs. -
Media inputs are data URLs, summarized in prompts.
image/audiotyped workflow inputs arrive asdata:URLs from the run form;build_task_descriptionreplaces payloads with<media mime ~N KB>placeholders so base64 never burns prompt context. True multimodal message construction is future work.
Consequences¶
- Wire-format change:
WorkflowEditorStep(+model/persona/observers/model_params),DAGNodeModel(+persona/model),DAGEdgeModel(+id/label/mappings/when). Schemas and generated TS committed per ADR-014. .agentic_ui_settings.jsonis per-instance mutable state (gitignored); multi-worker deployments share it via the filesystem only — Redis-backed parity is future work if needed.- Observer filtering is coarse (per-channel gating of existing emitters), not a pluggable observer framework.