-
Notifications
You must be signed in to change notification settings - Fork 0
feat(ui): full ACP agent configuration in Reboot settings page #38
Description
Summary
The Reboot settings page currently exposes only model selection, permission mode, and an auto-approve toggle. The ACP layer supports far more configuration — thinking budgets, extended thinking, tool allowlists, system prompt overrides, beta flags, per-agent options — none of which is surfaced in the UI. Make the settings page the comprehensive control panel for all ACP agent config.
Current State
What's configurable today (apps/web/app/settings/):
- Model (via
AcpConfigOptionfrom backend, falls back to hardcodedCLAUDE_MODEL_OPTIONS) - Permission mode:
plan | accept-edits | bypass-permissions - Auto-approve permissions toggle (localStorage only, not synced to Rust)
What's hardcoded / not surfaced:
- Context budget: hardcoded 800k characters
- Chat timeout: hardcoded 300 seconds
- Thinking budget (for extended thinking)
- Extended thinking enabled/disabled flag
- Tool allowlist / blocklist
- System prompt overrides per agent
- Beta features (
--betas/AXON_ALLOWED_CLAUDE_BETAS) - Per-agent flags (Codex
--model, Gemini--model, Claude--thinking-budget) - MCP server configuration (section exists but incomplete)
- Temperature, max_tokens (for OpenAI-compatible endpoints — see issue feat(llm): support OpenAI-compatible endpoints alongside ACP agents #37)
Data flow (well-architected, just not fully used):
Rust ACP Runtime → AcpBridgeEvent::ConfigOptionsUpdate { config_options: Vec<AcpConfigOption> }
→ WebSocket → useWsMessages → setAcpConfigOptions
→ WsMessagesContext.acpConfigOptions
→ SettingsPage → getAcpModelConfigOption() → renders one dropdown
The pipeline supports dynamic config options from the backend — it's just not being used for anything beyond model selection.
What Needs To Be Built
1. Per-agent settings panels
The settings page should switch context based on the active agent (pulseAgent: 'claude' | 'codex' | 'gemini' + OpenAI endpoints from #37):
Claude panel:
- Model (already works — extend to show all claude-* models)
- Permission mode (already works)
- Extended thinking: enabled/disabled toggle
- Thinking budget: slider or number input (tokens)
- Allowed betas: multi-select from
AXON_ALLOWED_CLAUDE_BETAS+ free-entry - System prompt override: textarea (prepended to Claude's context)
- Max turns per session: number input
- Tool allowlist: multi-select of available tools
- Auto-approve permissions: toggle (already exists)
Codex panel:
- Model (dynamic from
~/.codex/models_cache.jsonviaread_codex_cached_model_options) - Permission mode
- System prompt override
- Working directory override
Gemini panel:
- Model (dynamic from
read_gemini_cached_model_options) - System prompt override
- Tool allowlist
OpenAI-compatible panel (once #37 lands):
- Endpoint selector (from
[[llm.endpoints]]config) - Model (fetched from endpoint's
GET /models) - Temperature slider
- Max tokens input
- System prompt override
2. Dynamic AcpConfigOption rendering
Instead of getAcpModelConfigOption() extracting only the model option, render all AcpConfigOption entries the backend sends — each one becomes a settings control:
// current: only model extracted
const modelOption = getAcpModelConfigOption(acpConfigOptions)
// target: render all dynamic options
acpConfigOptions.map(opt => <AcpConfigControl key={opt.id} option={opt} />)AcpConfigControl renders the appropriate input based on opt.category:
"model"→ dropdown"mode"→ radio group"thought_level"→ slider or segmented control"boolean"→ toggle"text"→ input
3. Persist settings to backend (not just localStorage)
Currently autoApprovePermissions is localStorage-only — not synced to Rust. Settings that affect ACP behavior need to reach the backend:
- New WS message type:
settings_update { key, value }→ Rust persists in DB or passes to next ACP session - Or: include all settings in the
PulseChatRequestflags object (already hassession_id,agent,model,permissionLevel) - Settings that only affect UI (theme, layout prefs) → stay in localStorage
4. AcpPromptTurnRequest extensions
Current:
pub struct AcpPromptTurnRequest {
pub session_id: Option<String>,
pub prompt: Vec<String>,
pub model: Option<String>,
pub mcp_servers: Vec<AcpMcpServerConfig>,
}Add:
pub struct AcpPromptTurnRequest {
pub session_id: Option<String>,
pub prompt: Vec<String>,
pub model: Option<String>,
pub mcp_servers: Vec<AcpMcpServerConfig>,
pub thinking_budget: Option<u32>, // NEW
pub extended_thinking: Option<bool>, // NEW
pub system_prompt_override: Option<String>, // NEW
pub allowed_betas: Vec<String>, // NEW
pub tool_allowlist: Option<Vec<String>>, // NEW
pub max_turns: Option<u32>, // NEW
}Wire each new field through apply_config_and_model() in crates/services/acp/session.rs.
5. Settings persistence layer
New table axon_agent_settings:
CREATE TABLE axon_agent_settings (
agent TEXT NOT NULL, -- 'claude' | 'codex' | 'gemini' | endpoint name
key TEXT NOT NULL,
value JSONB NOT NULL,
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY (agent, key)
);Expose via:
GET /api/settings/acp/:agent→ return all settings for agentPUT /api/settings/acp/:agent→ upsert settings- Load on session init, pass through
AcpPromptTurnRequest
6. Settings page UX
- Agent tabs at top: Claude | Codex | Gemini | (OpenAI endpoints)
- Each tab renders that agent's panel
- "Reset to defaults" per-agent (already has global reset — add per-agent)
- Settings auto-save on change (no Save button)
- Show which settings require a new session to take effect vs apply immediately
Files
| File | Action |
|---|---|
apps/web/app/settings/settings-sections.tsx |
Render all acpConfigOptions; add per-agent panels |
apps/web/app/settings/settings-data.ts |
Add config definitions for new options |
apps/web/hooks/use-pulse-settings.ts |
Extend to include all agent settings; sync to backend |
apps/web/lib/pulse/types.ts |
Extend PulseChatRequest with new fields |
crates/services/types/acp.rs |
Extend AcpPromptTurnRequest with new fields |
crates/services/acp/session.rs |
Wire new fields through apply_config_and_model() |
crates/web/execute/sync_mode/pulse_chat.rs |
Pass extended settings from WS flags to service layer |
crates/jobs/common/ (or new file) |
axon_agent_settings table schema + CRUD |
crates/web.rs |
GET/PUT /api/settings/acp/:agent routes |
Acceptance Criteria
- Settings page has per-agent tabs: Claude, Codex, Gemini
- All
AcpConfigOptionentries from backend rendered as controls (not just model) - Claude: extended thinking toggle + thinking budget input wired end-to-end
- Claude: allowed betas multi-select wired end-to-end
- Claude: system prompt override textarea wired end-to-end
- Claude: tool allowlist multi-select wired end-to-end
- Codex/Gemini: model selector from dynamic backend list
- Settings persisted to
axon_agent_settingsDB table (not just localStorage) - Settings loaded and applied on ACP session init
-
GET/PUT /api/settings/acp/:agentREST endpoints - New session picks up latest settings without page reload
-
cargo clippyclean,tsc --noEmitclean