omnillm

ToolConfig Structured Editors Added

Issue Fixed

The OpenCode, AMP, and Droid configurations were showing in Raw JSON format instead of Structured format like Claude Code does. This made them difficult to edit and understand.

Solution

Added full structured editors for all three tools with:

Changes Made

1. Added TypeScript Interfaces (lines 66-230)

OpenCode Config Types

interface OpenCodeModel {
  id: string
  name: string
  provider: string
  context_length?: number
  max_output_tokens?: number
  supports_vision?: boolean
  supports_tools?: boolean
}

interface OpenCodeProvider {
  id: string
  name: string
  type: string
  base_url: string
  api_key: string
  timeout?: number
  retry_attempts?: number
}

interface OpenCodeConfig {
  provider?: string
  model?: string
  endpoint?: string
  api_key_env?: string
  features?: { ... }
  models?: { ... }
  providers?: { ... }
  mcp?: { ... }
  skills?: { ... }
}

AMP Config Types

interface AMPProvider { ... }
interface AMPModelCapability { ... }
interface AMPModel { ... }
interface AMPConfig {
  models?: { ... }
  features?: { ... }
  ui?: { ... }
  logging?: { ... }
}

Droid Config Types

interface DroidModel {
  model: string
  id: string
  baseUrl: string
  apiKey: string
  provider: string
  displayName?: string
  enabled?: boolean
  capabilities?: Array<string>
  temperature?: number
  topP?: number
  // etc.
}

interface DroidConfig {
  customModels?: Array<DroidModel>
  providers?: { ... }
  features?: { ... }
  logging?: { ... }
  ui?: { ... }
  enabledPlugins?: Record<string, boolean>
}

2. Created OpenCodeEditor Component (lines 1167-1405)

Sections:

Features:

3. Created AMPEditor Component (lines 1407-1689)

Sections:

Features:

4. Created DroidEditor Component (lines 1691-1985)

Sections:

Features:

5. Updated State Management

Added State Variables (lines 1987-1992)

const [opencodeConfig, setOpenCodeConfig] = useState<OpenCodeConfig | null>(null)
const [ampConfig, setAMPConfig] = useState<AMPConfig | null>(null)
const [droidConfig, setDroidConfig] = useState<DroidConfig | null>(null)

Updated Config Loading (lines 2013-2044)

Added parsing for all three configs:

else if (activeConfig === "opencode" && resp.content) {
  try {
    setOpenCodeConfig(JSON.parse(resp.content))
  } catch {
    setOpenCodeConfig(null)
  }
} else if (activeConfig === "amp" && resp.content) {
  try {
    setAMPConfig(JSON.parse(resp.content))
  } catch {
    setAMPConfig(null)
  }
} else if (activeConfig === "droid" && resp.content) {
  try {
    setDroidConfig(JSON.parse(resp.content))
  } catch {
    setDroidConfig(null)
  }
}

Updated Save Logic (lines 2056-2068)

if (activeConfig === "opencode" && opencodeConfig)
  return JSON.stringify(opencodeConfig, null, 2) + "\n"
if (activeConfig === "amp" && ampConfig)
  return JSON.stringify(ampConfig, null, 2) + "\n"
if (activeConfig === "droid" && droidConfig)
  return JSON.stringify(droidConfig, null, 2) + "\n"

Updated Reload After Save (lines 2091-2125)

Re-parses all three configs after save to ensure latest data.

Updated Reset Logic (lines 2128-2162)

Resets all three configs when clicking Reset button.

Updated Structured View Detection (lines 2172-2179)

Shows structured view when any of the five configs are active.

Rendered New Editors (lines 2373-2403)

{activeConfig === "opencode" && opencodeConfig && (
  <OpenCodeEditor config={opencodeConfig} onChange={...} />
)}
{activeConfig === "amp" && ampConfig && (
  <AMPEditor config={ampConfig} onChange={...} />
)}
{activeConfig === "droid" && droidConfig && (
  <DroidEditor config={droidConfig} onChange={...} />
)}

Visual Improvements

Before

┌─────────────────────────────────────┐
│ Raw JSON Editor                     │
│ {                                   │
│   "provider": "openai-compatible",  │
│   "model": "glm-5.1",               │
│   ...                               │
│ }                                   │
└─────────────────────────────────────┘

After

┌─────────────────────────────────────┐
│ ● Global Settings                   │
│   Provider: [openai-compatible]     │
│   Model:    [glm-5.1          ]     │
│   Endpoint: [http://localhost:5000] │
│                                     │
│ ● Features                          │
│   ☑ streaming                       │
│   ☑ tool use                        │
│   ☐ auto backup                     │
│                                     │
│ ● Custom Providers           [+ Add]│
│   ┌─ omnillm ────────────┐         │
│   │ Type: [openai-compatible]      │
│   │ URL:  [http://...]             │
│   └────────────────────────┘       │
└─────────────────────────────────────┘

Testing Checklist

Next Steps

  1. Restart OmniLLM backend to apply all changes:
    bun run omni restart --rebuild
    
  2. Refresh browser to see structured editors

  3. Test each editor:
    • OpenCode: Edit provider, toggle features, add model
    • AMP: Change theme, edit providers, modify models
    • Droid: Adjust temperature/topP, edit models
  4. Verify save/reload works correctly for all three

  5. Test edge cases:
    • Empty configs (should show “Add” buttons)
    • Invalid JSON (should fall back to raw view)
    • Very long lists (should scroll properly)

Files Modified

File Lines Added Description
frontend/src/pages/ConfigPage.tsx ~820 Added 3 new editors + state management

Design Decisions

Why Separate Editors?

Each tool has unique configuration structure:

Why These Sections?

Organized by usage frequency:

  1. Global Settings: Most commonly edited
  2. Features: Quick toggles
  3. Providers/Models: Advanced configuration

Why These Field Types?

Comparison with Existing Editors

Feature Claude Codex OpenCode AMP Droid
Env Vars
Plugins
Providers
Models
UI Settings
Parameters

All editors now follow consistent patterns while respecting each tool’s unique structure.