Skip to content

feat: add OpenClaw/Hermes/OpenCode proxy_config support and UI integration#1

Closed
dashitongzhi wants to merge 4 commits intomainfrom
feat/openclaw-auto-rotation
Closed

feat: add OpenClaw/Hermes/OpenCode proxy_config support and UI integration#1
dashitongzhi wants to merge 4 commits intomainfrom
feat/openclaw-auto-rotation

Conversation

@dashitongzhi
Copy link
Copy Markdown
Owner

@dashitongzhi dashitongzhi commented May 1, 2026

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)

  • 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
  • Bump SCHEMA_VERSION to 11

Backend (proxy.rs, types.rs)

  • Add hermes field to ProxyTakeoverStatus struct
  • Read OpenClaw/OpenCode/Hermes takeover status from DB instead of hardcoding false
  • HTTP proxy interception remains disabled for additive-mode apps (by design)

Frontend

  • ProxyPanel: Add OpenClaw and Hermes to app takeover grid
  • PricingConfigPanel: Add OpenClaw and Hermes to pricing apps list
  • usage.ts: Add opencode/openclaw to AppTypeFilter type
  • AboutSection: Add openclaw/hermes to tool names

Notes

  • OpenClaw/Hermes/OpenCode use additive mode (all providers coexist in config), not switch mode (HTTP proxy interception). The proxy_config settings (circuit breaker, retries, timeouts) are now available for health monitoring and future config-based failover.
  • HTTP proxy takeover still only applies to Claude/Codex/Gemini. Additive-mode apps manage providers in their own config files.

Future Work

  • Implement config-based failover for additive-mode apps (reorder providers based on health)
  • This will be a separate PR as it requires changes to stream_check and provider sync logic

Kral added 3 commits May 1, 2026 15:41
…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
Copilot AI review requested due to automatic review settings May 1, 2026 07:52
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 898641604d

ℹ️ 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".

Comment on lines +173 to +177
"INSERT OR IGNORE INTO proxy_config (app_type, max_retries,
streaming_first_byte_timeout, streaming_idle_timeout, non_streaming_timeout,
circuit_failure_threshold, circuit_success_threshold, circuit_timeout_seconds,
circuit_error_rate_threshold, circuit_min_requests)
VALUES ('opencode', 3, 60, 120, 600, 4, 2, 60, 0.6, 10)",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P0 Badge Avoid seeding new app rows before migration runs

Database::init() calls create_tables() before apply_schema_migrations(), so existing v10 databases still enforce proxy_config's old CHECK(app_type IN ('claude','codex','gemini')) when this insert executes. In that upgrade path, inserting 'opencode' fails immediately with a CHECK-constraint error and aborts startup, which means users cannot reach the v10→v11 migration step at all.

Useful? React with 👍 / 👎.

import { proxyApi } from "@/lib/api/proxy";

const PRICING_APPS = ["claude", "codex", "gemini"] as const;
const PRICING_APPS = ["claude", "codex", "gemini", "openclaw"] as const;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep PRICING_APPS aligned with initialized state shape

After adding openclaw here, appConfigs/newState still initialize only claude|codex|gemini; if loading config fails for any app, isConfigLoading is cleared and render paths read appConfigs[openclaw].multiplier, which dereferences undefined and crashes the pricing panel. This regression is triggered specifically on partial/failed API loads.

Useful? React with 👍 / 👎.

- Add hermes field to ProxyTakeoverStatus struct
- Read hermes takeover status from DB
- Add hermes to ProxyPanel and PricingConfigPanel
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Extends the proxy_config database table and related backend/frontend surfaces to recognize additional app types (OpenCode/OpenClaw/Hermes), aiming to enable health monitoring / circuit-breaker configuration and surface new apps in the UI.

Changes:

  • Expanded proxy_config schema CHECK constraint and added seed rows + a v10→v11 migration; bumped DB SCHEMA_VERSION to 11.
  • Updated proxy takeover status reading in the backend to consult DB flags for OpenCode/OpenClaw.
  • Updated UI/type surfaces to include OpenClaw (proxy takeover UI + pricing config) and OpenClaw/Hermes (About tool list), plus expanded usage filter types.

Reviewed changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/types/usage.ts Expands AppTypeFilter union to include opencode/openclaw.
src/components/usage/PricingConfigPanel.tsx Adds openclaw to the pricing-app list for default multiplier/source configuration.
src/components/settings/AboutSection.tsx Adds openclaw/hermes to the list of tool names requested from backend version detection.
src/components/proxy/ProxyPanel.tsx Adds openclaw to the “app takeover” switch grid in the proxy UI.
src-tauri/src/services/proxy.rs Reads OpenCode/OpenClaw takeover enablement from DB instead of hardcoding false.
src-tauri/src/database/schema.rs Expands proxy_config app_type constraint, seeds new rows, and adds v10→v11 migration.
src-tauri/src/database/mod.rs Bumps SCHEMA_VERSION to 11.
.gitignore Ignores .codex-plans/.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 139 to +178
// 初始化三行数据(每应用不同默认值)
//
// 兼容旧数据库:
// - 老版本 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,
streaming_first_byte_timeout, streaming_idle_timeout, non_streaming_timeout,
circuit_failure_threshold, circuit_success_threshold, circuit_timeout_seconds,
circuit_error_rate_threshold, circuit_min_requests)
VALUES ('claude', 6, 90, 180, 600, 8, 3, 90, 0.7, 15)",
[],
)
.map_err(|e| AppError::Database(e.to_string()))?;
conn.execute(
"INSERT OR IGNORE INTO proxy_config (app_type, max_retries,
streaming_first_byte_timeout, streaming_idle_timeout, non_streaming_timeout,
circuit_failure_threshold, circuit_success_threshold, circuit_timeout_seconds,
circuit_error_rate_threshold, circuit_min_requests)
VALUES ('codex', 3, 60, 120, 600, 4, 2, 60, 0.6, 10)",
[],
)
.map_err(|e| AppError::Database(e.to_string()))?;
conn.execute(
"INSERT OR IGNORE INTO proxy_config (app_type, max_retries,
streaming_first_byte_timeout, streaming_idle_timeout, non_streaming_timeout,
circuit_failure_threshold, circuit_success_threshold, circuit_timeout_seconds,
circuit_error_rate_threshold, circuit_min_requests)
VALUES ('gemini', 5, 60, 120, 600, 4, 2, 60, 0.6, 10)",
[],
)
.map_err(|e| AppError::Database(e.to_string()))?;
conn.execute(
"INSERT OR IGNORE INTO proxy_config (app_type, max_retries,
streaming_first_byte_timeout, streaming_idle_timeout, non_streaming_timeout,
circuit_failure_threshold, circuit_success_threshold, circuit_timeout_seconds,
circuit_error_rate_threshold, circuit_min_requests)
VALUES ('opencode', 3, 60, 120, 600, 4, 2, 60, 0.6, 10)",
[],
Copy link

Copilot AI May 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

proxy_config seed logic now inserts additional app rows (opencode/openclaw/hermes). There are existing migration/unit tests that assert proxy_config has exactly 3 rows after migrations; those tests will now fail. Update the expected row count and/or assertions to reflect the expanded app set.

Copilot uses AI. Check for mistakes.
import { proxyApi } from "@/lib/api/proxy";

const PRICING_APPS = ["claude", "codex", "gemini"] as const;
const PRICING_APPS = ["claude", "codex", "gemini", "openclaw"] as const;
Copy link

Copilot AI May 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PRICING_APPS now includes "openclaw", but later in this component the appConfigs/newState initialization only defines claude/codex/gemini. That makes appConfigs[app] undefined for openclaw (and should also fail the AppConfigState type). Add openclaw defaults everywhere the config state is initialized (initial useState and newState in loadAllConfigs).

Copilot uses AI. Check for mistakes.
}

const TOOL_NAMES = ["claude", "codex", "gemini", "opencode"] as const;
const TOOL_NAMES = ["claude", "codex", "gemini", "opencode", "openclaw", "hermes"] as const;
Copy link

Copilot AI May 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TOOL_NAMES now includes "openclaw" and "hermes", but the backend get_tool_versions command filters requests against VALID_TOOLS (currently only claude/codex/gemini/opencode). As-is, these new tools will never show up (they'll be silently dropped). Either extend VALID_TOOLS + version detection to include them, or keep the frontend list aligned with what the backend supports.

Suggested change
const TOOL_NAMES = ["claude", "codex", "gemini", "opencode", "openclaw", "hermes"] as const;
const TOOL_NAMES = ["claude", "codex", "gemini", "opencode"] as const;

Copilot uses AI. Check for mistakes.
Comment on lines 252 to 257
})}
</p>
<div className="grid gap-2 sm:grid-cols-3">
{(["claude", "codex", "gemini"] as const).map((appType) => {
{(["claude", "codex", "gemini", "openclaw"] as const).map((appType) => {
const isEnabled =
takeoverStatus?.[
Copy link

Copilot AI May 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section is explicitly labeled as “应用接管” (live config takeover). Adding "openclaw" here allows users to toggle takeover for an additive-mode app, but backend takeover logic operates by rewriting Live config files and does not appear to guard against additive-mode apps. If takeover is intentionally unsupported for additive-mode apps (per PR notes), keep this list to switch-mode apps only and/or render additive apps as disabled with an explanation.

Copilot uses AI. Check for mistakes.
Comment on lines 265 to +297
/// 获取各应用的接管状态(是否改写该应用的 Live 配置指向本地代理)
pub async fn get_takeover_status(&self) -> Result<ProxyTakeoverStatus, String> {
// 从 proxy_config.enabled 读取(优先),兼容旧的 live_backup 备份检测
let claude_enabled = self
.db
.get_proxy_config_for_app("claude")
.await
.map(|c| c.enabled)
.unwrap_or(false);
let codex_enabled = self
.db
.get_proxy_config_for_app("codex")
.await
.map(|c| c.enabled)
.unwrap_or(false);
let gemini_enabled = self
.db
.get_proxy_config_for_app("gemini")
.await
.map(|c| c.enabled)
.unwrap_or(false);
// OpenCode and OpenClaw don't support proxy features, always return false
let opencode_enabled = false;
let openclaw_enabled = false;
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);
Copy link

Copilot AI May 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_takeover_status now reports takeover enabled for opencode/openclaw by reading proxy_config.enabled, but set_takeover_for_app rewrites Live configs and currently has no is_additive_mode() guard. This makes it possible to attempt a takeover on additive-mode apps, which is likely unsupported and can fail or corrupt configs. Consider hard-disabling takeover for additive-mode apps in the service/API layer (return false + reject enabling), and keep proxy_config.enabled for these apps reserved for non-takeover features if needed.

Copilot uses AI. Check for mistakes.

// 复制已有数据
conn.execute(
"INSERT INTO proxy_config_new SELECT * FROM proxy_config",
Copy link

Copilot AI May 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The v10→v11 migration copies rows with INSERT INTO proxy_config_new SELECT * FROM proxy_config, which is brittle and will fail if the existing table has extra columns (e.g., columns added via ALTER TABLE in create_tables_on_conn). Use an explicit column list for both sides (copy only the common columns), or ensure proxy_config_new matches the existing schema before copying.

Suggested change
"INSERT INTO proxy_config_new SELECT * FROM proxy_config",
"INSERT INTO proxy_config_new (
app_type, proxy_enabled, listen_address, listen_port, enable_logging,
enabled, auto_failover_enabled, max_retries, streaming_first_byte_timeout,
streaming_idle_timeout, non_streaming_timeout, circuit_failure_threshold,
circuit_success_threshold, circuit_timeout_seconds, circuit_error_rate_threshold,
circuit_min_requests, default_cost_multiplier, pricing_model_source,
created_at, updated_at
)
SELECT
app_type, proxy_enabled, listen_address, listen_port, enable_logging,
enabled, auto_failover_enabled, max_retries, streaming_first_byte_timeout,
streaming_idle_timeout, non_streaming_timeout, circuit_failure_threshold,
circuit_success_threshold, circuit_timeout_seconds, circuit_error_rate_threshold,
circuit_min_requests, default_cost_multiplier, pricing_model_source,
created_at, updated_at
FROM proxy_config",

Copilot uses AI. Check for mistakes.
dashitongzhi added a commit that referenced this pull request May 1, 2026
- 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)
dashitongzhi added a commit that referenced this pull request May 1, 2026
- 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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants