feat: add OpenClaw/Hermes/OpenCode proxy_config support and UI integration#2505
feat: add OpenClaw/Hermes/OpenCode proxy_config support and UI integration#2505dashitongzhi wants to merge 9 commits intofarion1231:mainfrom
Conversation
…r support - Expand proxy_config CHECK constraint to include opencode/openclaw/hermes - Add seed data for new app types with appropriate defaults - Add v10->v11 migration for existing databases - Update proxy.rs to read OpenClaw/OpenCode takeover status from DB - Bump SCHEMA_VERSION to 11
…out section - Add OpenClaw to ProxyPanel app takeover grid - Add OpenClaw to PricingConfigPanel apps list - Add opencode/openclaw to AppTypeFilter type - Add openclaw/hermes to AboutSection tool names
- Add hermes field to ProxyTakeoverStatus struct - Read hermes takeover status from DB - Add hermes to ProxyPanel and PricingConfigPanel
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 098d8ebc07
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| </p> | ||
| <div className="grid gap-2 sm:grid-cols-3"> | ||
| {(["claude", "codex", "gemini"] as const).map((appType) => { | ||
| {(["claude", "codex", "gemini", "openclaw", "hermes"] as const).map((appType) => { |
There was a problem hiding this comment.
Exclude unsupported apps from takeover switches
Adding openclaw and hermes to the app takeover grid makes the UI expose toggles that cannot succeed: when users enable either one, the request goes through set_takeover_for_app, which still routes additive-mode apps to the unsupported path (sync_live_to_provider/backup_live_config_strict/takeover_live_config_strict return "该应用不支持代理功能"). In practice this creates a permanently failing control for running proxy sessions, so these apps should not be listed in the takeover switch UI until backend takeover logic supports them.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Pull request overview
This PR extends proxy_config support and related UI wiring to additional app types (OpenCode, OpenClaw, Hermes), with the goal of enabling consistent health monitoring/circuit-breaker configuration across all supported tools.
Changes:
- Expanded DB
proxy_configschema constraints, added seed rows foropencode/openclaw/hermes, and introduced a v10→v11 migration (plus schema version bump). - Extended backend takeover status struct to include
hermesand started readingopencode/openclaw/hermesenabled state from DB. - Updated frontend filters/panels to include the new app/tool names in multiple places.
Reviewed changes
Copilot reviewed 8 out of 9 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/types/usage.ts | Extends AppTypeFilter union to include opencode/openclaw/hermes. |
| src/components/usage/PricingConfigPanel.tsx | Adds openclaw/hermes to pricing configuration apps list. |
| src/components/settings/AboutSection.tsx | Adds openclaw/hermes to tool environment/version grid list. |
| src/components/proxy/ProxyPanel.tsx | Adds openclaw/hermes to the “app takeover” switch grid. |
| src-tauri/src/services/proxy.rs | Reads opencode/openclaw/hermes enabled state from DB when building takeover status. |
| src-tauri/src/proxy/types.rs | Adds hermes field to ProxyTakeoverStatus. |
| src-tauri/src/database/schema.rs | Expands proxy_config CHECK constraint, adds seeds, and adds v10→v11 migration. |
| src-tauri/src/database/mod.rs | Bumps SCHEMA_VERSION to 11. |
| .gitignore | Ignores .codex-plans/. |
Comments suppressed due to low confidence (2)
src/components/proxy/ProxyPanel.tsx:283
- This UI now offers “应用接管” switches for
openclaw/hermes, but the backend takeover flow rejects these app types (e.g. returns “该应用不支持代理功能”), and the hint text claims requests will be forwarded through the local proxy. Either remove these app types from the takeover grid, or render them disabled with an explicit explanation and route their settings to the non-takeover/health-monitoring features instead.
{(["claude", "codex", "gemini", "openclaw", "hermes"] as const).map((appType) => {
const isEnabled =
takeoverStatus?.[
appType as keyof typeof takeoverStatus
] ?? false;
return (
<div
key={appType}
className="flex items-center justify-between rounded-md border border-primary/20 bg-background/60 px-3 py-2"
>
<span className="text-sm font-medium capitalize">
{appType}
</span>
<Switch
checked={isEnabled}
onCheckedChange={(checked) =>
handleTakeoverChange(appType, checked)
}
disabled={setTakeoverForApp.isPending}
/>
</div>
);
})}
</div>
<p className="text-xs text-muted-foreground">
{t("proxy.takeover.hint", {
defaultValue:
"选择要接管的应用,启用后该应用的请求将通过本地代理转发",
})}
src-tauri/src/database/schema.rs:146
- Comments around
proxy_configstill describe it as a “三行结构” (three-row structure) and “初始化三行数据”, but the table/seed now covers 6 app types. Updating these comments to reflect the current per-app row model will prevent confusion during future schema/migration work.
// 8. Proxy Config 表(三行结构,app_type 主键)
conn.execute("CREATE TABLE IF NOT EXISTS proxy_config (
app_type TEXT PRIMARY KEY CHECK (app_type IN ('claude','codex','gemini','opencode','openclaw','hermes')),
proxy_enabled INTEGER NOT NULL DEFAULT 0, listen_address TEXT NOT NULL DEFAULT '127.0.0.1',
listen_port INTEGER NOT NULL DEFAULT 15721, enable_logging INTEGER NOT NULL DEFAULT 1,
enabled INTEGER NOT NULL DEFAULT 0, auto_failover_enabled INTEGER NOT NULL DEFAULT 0,
max_retries INTEGER NOT NULL DEFAULT 3, streaming_first_byte_timeout INTEGER NOT NULL DEFAULT 60,
streaming_idle_timeout INTEGER NOT NULL DEFAULT 120, non_streaming_timeout INTEGER NOT NULL DEFAULT 600,
circuit_failure_threshold INTEGER NOT NULL DEFAULT 4, circuit_success_threshold INTEGER NOT NULL DEFAULT 2,
circuit_timeout_seconds INTEGER NOT NULL DEFAULT 60, circuit_error_rate_threshold REAL NOT NULL DEFAULT 0.6,
circuit_min_requests INTEGER NOT NULL DEFAULT 10,
default_cost_multiplier TEXT NOT NULL DEFAULT '1',
pricing_model_source TEXT NOT NULL DEFAULT 'response',
created_at TEXT NOT NULL DEFAULT (datetime('now')), updated_at TEXT NOT NULL DEFAULT (datetime('now'))
)", []).map_err(|e| AppError::Database(e.to_string()))?;
// 初始化三行数据(每应用不同默认值)
//
// 兼容旧数据库:
// - 老版本 proxy_config 是单例表(没有 app_type 列),此时不能执行三行 seed insert;
// - 旧表会在 apply_schema_migrations() 中迁移为三行结构后再插入。
if Self::has_column(conn, "proxy_config", "app_type")? {
conn.execute(
"INSERT OR IGNORE INTO proxy_config (app_type, max_retries,
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const PRICING_APPS = ["claude", "codex", "gemini", "openclaw", "hermes"] as const; | ||
| type PricingApp = (typeof PRICING_APPS)[number]; |
| let opencode_enabled = self | ||
| .db | ||
| .get_proxy_config_for_app("opencode") | ||
| .await | ||
| .map(|c| c.enabled) | ||
| .unwrap_or(false); | ||
| let openclaw_enabled = self | ||
| .db | ||
| .get_proxy_config_for_app("openclaw") | ||
| .await | ||
| .map(|c| c.enabled) | ||
| .unwrap_or(false); | ||
|
|
||
| let hermes_enabled = self | ||
| .db | ||
| .get_proxy_config_for_app("hermes") | ||
| .await | ||
| .map(|c| c.enabled) | ||
| .unwrap_or(false); | ||
|
|
||
| Ok(ProxyTakeoverStatus { | ||
| claude: claude_enabled, | ||
| codex: codex_enabled, | ||
| gemini: gemini_enabled, | ||
| opencode: opencode_enabled, | ||
| openclaw: openclaw_enabled, | ||
| hermes: hermes_enabled, | ||
| }) |
| // 复制已有数据 | ||
| conn.execute( | ||
| "INSERT INTO proxy_config_new SELECT * FROM proxy_config", |
| } | ||
|
|
||
| const TOOL_NAMES = ["claude", "codex", "gemini", "opencode"] as const; | ||
| const TOOL_NAMES = ["claude", "codex", "gemini", "opencode", "openclaw", "hermes"] as const; |
…n1231#2322) * feat(providers): add baidu qianfan coding plan presets * refactor(providers): align qianfan presets with existing format * chore(providers): narrow qianfan coding plan scope
Add the window-state plugin and explicitly save size and position across app exit, restart, and lightweight-mode transitions.
- PricingConfigPanel: add openclaw/hermes/opencode to appConfigs init (#1) - proxy/types: add hermes field to ProxyTakeoverStatus - proxy.rs: return consistent false for unsupported app takeover (farion1231#2) - schema.rs: use explicit column list + preserve live_takeover_active in migration (farion1231#3) - AboutSection + misc.rs: add openclaw/hermes to VALID_TOOLS (farion1231#4) - ProxyPanel: filter unsupported apps from takeover switches (farion1231#5)
|
@claude review |
|
Claude finished @farion1231's task in 5m 6s —— View job Claude's Review of PR #2505
|
|
@claude review (Re-running with the updated review prompt for comparison.) |
|
Claude finished @farion1231's task in 5m 13s —— View job Review (re-run with high-signal-only criteria)One Important issue. The author's "address all PR review feedback" commit ( 🔴 Important —
|

Summary
Extends proxy_config table support to all 6 app types (Claude, Codex, Gemini, OpenCode, OpenClaw, Hermes), enabling health monitoring, circuit breaker config, and failover settings for additive-mode apps.
Changes
Database (schema.rs)
Backend (proxy.rs, types.rs)
Frontend
Notes
Future Work