refactor(acp): unify ingress topology and migrate all services to xworkmate-bridge.svc.plus
This commit is contained in:
parent
69045c6684
commit
104ab26356
@ -32,6 +32,7 @@ Verified public HTTP JSON-RPC endpoints:
|
||||
- Codex: `https://xworkmate-bridge.svc.plus/acp-server/codex/acp/rpc`
|
||||
- OpenCode: `https://xworkmate-bridge.svc.plus/acp-server/opencode/acp/rpc`
|
||||
- Gemini: `https://xworkmate-bridge.svc.plus/acp-server/gemini/acp/rpc`
|
||||
- OpenClaw: `https://xworkmate-bridge.svc.plus/gateway/openclaw/`
|
||||
|
||||
The `.../acp` path remains reserved for WebSocket ACP.
|
||||
|
||||
@ -46,11 +47,12 @@ Missing bearer auth returns a JSON-RPC error envelope with code `-32001`.
|
||||
|
||||
## Public Validation Results
|
||||
|
||||
The ingress returned `200 OK` on all three public routes after re-apply, and the deployment response confirmed the active upstream mappings:
|
||||
The ingress returned `200 OK` on all public routes after re-apply, and the deployment response confirmed the active upstream mappings:
|
||||
|
||||
- `codex` -> `127.0.0.1:9010`
|
||||
- `opencode` -> `127.0.0.1:3910`
|
||||
- `gemini` -> `127.0.0.1:8791`
|
||||
- `openclaw` -> `127.0.0.1:18789` (Host process)
|
||||
|
||||
### Codex
|
||||
|
||||
|
||||
@ -58,7 +58,7 @@ flowchart TD
|
||||
C1["https://xworkmate-bridge.svc.plus/acp-server/codex/acp/rpc"]
|
||||
C2["https://xworkmate-bridge.svc.plus/acp-server/opencode/acp/rpc"]
|
||||
C3["https://xworkmate-bridge.svc.plus/acp-server/gemini/acp/rpc"]
|
||||
C4["wss://openclaw.svc.plus"]
|
||||
C4["https://xworkmate-bridge.svc.plus/gateway/openclaw/"]
|
||||
end
|
||||
|
||||
B7 --> C1
|
||||
@ -110,7 +110,7 @@ flowchart LR
|
||||
U1["https://xworkmate-bridge.svc.plus/acp-server/codex/acp/rpc"]
|
||||
U2["https://xworkmate-bridge.svc.plus/acp-server/opencode/acp/rpc"]
|
||||
U3["https://xworkmate-bridge.svc.plus/acp-server/gemini/acp/rpc"]
|
||||
U4["wss://openclaw.svc.plus<br/>reported as openclaw.svc.plus:443"]
|
||||
U4["https://xworkmate-bridge.svc.plus/gateway/openclaw/<br/>reported as xworkmate-bridge.svc.plus:443"]
|
||||
end
|
||||
|
||||
APPMETHODS --> BRIDGE
|
||||
@ -138,7 +138,7 @@ Important distinction:
|
||||
- `availableExecutionTargets` tells the app which first-level task dialog modes
|
||||
are currently available
|
||||
- for `gatewayProviderId=openclaw`, the bridge rewrites the upstream target to
|
||||
`wss://openclaw.svc.plus`
|
||||
`https://xworkmate-bridge.svc.plus/gateway/openclaw/`
|
||||
## Production Truth
|
||||
|
||||
当前 production forwarding 事实:
|
||||
@ -152,7 +152,7 @@ Important distinction:
|
||||
- `opencode`
|
||||
- `gemini`
|
||||
- current production gateway forwarding target:
|
||||
- `openclaw -> wss://openclaw.svc.plus`
|
||||
- `openclaw -> https://xworkmate-bridge.svc.plus/gateway/openclaw/`
|
||||
|
||||
对 app 而言:
|
||||
|
||||
@ -163,7 +163,7 @@ Important distinction:
|
||||
## Invariants
|
||||
|
||||
- app traffic reaches upstream ACP and gateway services only through the bridge
|
||||
- app does not call `xworkmate-bridge.svc.plus/acp-server/*` or `openclaw.svc.plus` directly
|
||||
- app does not call `xworkmate-bridge.svc.plus/acp-server/*` or `xworkmate-bridge.svc.plus/gateway/openclaw/` directly
|
||||
- upstream auth stays bridge-internal:
|
||||
- `Authorization: Bearer $INTERNAL_SERVICE_TOKEN`
|
||||
- `acp.capabilities` is the provider / capability discovery source
|
||||
|
||||
@ -127,7 +127,7 @@ Use these terms consistently:
|
||||
|
||||
- `canonical app-facing path`: `/acp/rpc` and `/acp`
|
||||
- `gateway runtime method family`: `xworkmate.gateway.*`
|
||||
- `independent upstream service`: `xworkmate-bridge.svc.plus/acp-server/*`, `wss://openclaw.svc.plus`
|
||||
- `independent upstream service`: `xworkmate-bridge.svc.plus/acp-server/*`, `xworkmate-bridge.svc.plus/gateway/openclaw/`
|
||||
- `bridge-owned routing`: provider / gateway selection performed inside bridge
|
||||
- `routing metadata`: execution target and resolved provider/gateway identifiers returned to the app
|
||||
|
||||
|
||||
@ -13,6 +13,15 @@
|
||||
| `gemini-acp-adapter` | `geminiadapter.Serve` | 启动 Gemini 专用 ACP adapter,把 Gemini CLI 包装成 ACP HTTP / WebSocket 服务。 |
|
||||
| 默认模式 | `toolbridge.Run` | 启动 MCP 风格的本地工具桥,暴露 `chat`、`claude_review`、`vault_kv` 等工具。 |
|
||||
|
||||
|服务 │ 外部入口 (HTTPS/WSS) │ 后端转发目标 (Local) │ 部署方式 │
|
||||
├──────────┼────────────────────────────────────────────────┼──────────────────────────┼─────────────┤
|
||||
│ Bridge │ xworkmate-bridge.svc.plus/ │ 127.0.0.1:8787 │ Docker 容器 │
|
||||
│ OpenClaw │ xworkmate-bridge.svc.plus/gateway/openclaw/ │ 127.0.0.1:18789 │ 主机进程 │
|
||||
│ Codex │ xworkmate-bridge.svc.plus/acp-server/codex/ │ acp-server-codex:3911 │ Docker 容器 │
|
||||
│ OpenCode │ xworkmate-bridge.svc.plus/acp-server/opencode/ │ acp-server-opencode:3910 │ Docker 容器 │
|
||||
│ Gemini │ xworkmate-bridge.svc.plus/acp-server/gemini/ │ acp-server-gemini:3912 │ Docker 容器
|
||||
|
||||
|
||||
设计含义:
|
||||
|
||||
- `main.go` 不承载业务决策,只做模式分发。
|
||||
|
||||
@ -74,8 +74,9 @@ func applyProductionGatewayRouting(
|
||||
if strings.TrimSpace(strings.ToLower(request.Mode)) != "openclaw" {
|
||||
return request
|
||||
}
|
||||
// Route through the unified bridge ingress
|
||||
request.Endpoint = gatewayruntime.Endpoint{
|
||||
Host: "openclaw.svc.plus",
|
||||
Host: "xworkmate-bridge.svc.plus",
|
||||
Port: 443,
|
||||
TLS: true,
|
||||
}
|
||||
|
||||
@ -36,7 +36,7 @@ func TestResolveGatewayReportedRemoteAddressNormalizesExplicitPublicRemoteHost(
|
||||
got := resolveGatewayReportedRemoteAddress(server, gatewayruntime.ConnectRequest{
|
||||
Mode: "openclaw",
|
||||
Endpoint: gatewayruntime.Endpoint{
|
||||
Host: "openclaw.svc.plus",
|
||||
Host: "xworkmate-bridge.svc.plus",
|
||||
Port: 443,
|
||||
TLS: true,
|
||||
},
|
||||
|
||||
@ -71,16 +71,34 @@ func newProductionProviderCatalog() (map[string]syncedProvider, []string) {
|
||||
config := loadBridgeConfig()
|
||||
authorizationHeader := bridgeUpstreamAuthorizationHeader()
|
||||
|
||||
// Map both legacy OPENCLAW_*_URL and new *_RPC_URL patterns for compatibility
|
||||
providers := []struct {
|
||||
id string
|
||||
label string
|
||||
yaml string
|
||||
envKeys []string
|
||||
id string
|
||||
label string
|
||||
yaml string
|
||||
envKeys []string
|
||||
defaultURL string
|
||||
}{
|
||||
{"codex", "Codex", config.Upstream.CodexURL, []string{"CODEX_RPC_URL", "OPENCLAW_CODEX_URL"}},
|
||||
{"opencode", "OpenCode", config.Upstream.OpenCodeURL, []string{"OPENCODE_RPC_URL", "OPENCLAW_OPENCODE_URL"}},
|
||||
{"gemini", "Gemini", config.Upstream.GeminiURL, []string{"GEMINI_RPC_URL", "OPENCLAW_GEMINI_URL"}},
|
||||
{
|
||||
id: "codex",
|
||||
label: "Codex",
|
||||
yaml: config.Upstream.CodexURL,
|
||||
envKeys: []string{"CODEX_RPC_URL"},
|
||||
defaultURL: "https://xworkmate-bridge.svc.plus/acp-server/codex/acp/rpc",
|
||||
},
|
||||
{
|
||||
id: "opencode",
|
||||
label: "OpenCode",
|
||||
yaml: config.Upstream.OpenCodeURL,
|
||||
envKeys: []string{"OPENCODE_RPC_URL"},
|
||||
defaultURL: "https://xworkmate-bridge.svc.plus/acp-server/opencode/acp/rpc",
|
||||
},
|
||||
{
|
||||
id: "gemini",
|
||||
label: "Gemini",
|
||||
yaml: config.Upstream.GeminiURL,
|
||||
envKeys: []string{"GEMINI_RPC_URL"},
|
||||
defaultURL: "https://xworkmate-bridge.svc.plus/acp-server/gemini/acp/rpc",
|
||||
},
|
||||
}
|
||||
|
||||
catalog := make(map[string]syncedProvider)
|
||||
@ -88,6 +106,9 @@ func newProductionProviderCatalog() (map[string]syncedProvider, []string) {
|
||||
|
||||
for _, p := range providers {
|
||||
endpoint := resolveURL(p.yaml, p.envKeys...)
|
||||
if endpoint == "" {
|
||||
endpoint = p.defaultURL
|
||||
}
|
||||
catalog[p.id] = syncedProvider{
|
||||
ProviderID: p.id,
|
||||
Label: p.label,
|
||||
|
||||
@ -25,7 +25,7 @@ func TestManagerConnectUsesReportedRemoteAddressInSnapshot(t *testing.T) {
|
||||
Port: server.Port(),
|
||||
TLS: false,
|
||||
},
|
||||
ReportedRemoteAddress: "openclaw.svc.plus:443",
|
||||
ReportedRemoteAddress: "xworkmate-bridge.svc.plus:443",
|
||||
ConnectAuthMode: "shared-token",
|
||||
ConnectAuthFields: []string{"token"},
|
||||
ConnectAuthSources: []string{"shared:form"},
|
||||
@ -54,7 +54,7 @@ func TestManagerConnectUsesReportedRemoteAddressInSnapshot(t *testing.T) {
|
||||
t.Fatalf("expected connect success, got %#v", result.Error)
|
||||
}
|
||||
|
||||
if got := result.Snapshot["remoteAddress"]; got != "openclaw.svc.plus:443" {
|
||||
if got := result.Snapshot["remoteAddress"]; got != "xworkmate-bridge.svc.plus:443" {
|
||||
t.Fatalf("expected reported remote address, got %#v", got)
|
||||
}
|
||||
}
|
||||
|
||||
@ -213,11 +213,9 @@ func reconcileCodex(
|
||||
}
|
||||
state.DiscoveredMCPCount = discovered
|
||||
state.ManagedMCPCount = len(managedServers)
|
||||
if strings.TrimSpace(aiGatewayURL) != "" {
|
||||
state.Detail = "LLM API uses launch-scoped defaults for collaboration runs."
|
||||
} else {
|
||||
state.Detail = "LLM API not configured."
|
||||
}
|
||||
state.Detail = "Codex public base URL: https://xworkmate-bridge.svc.plus/acp-server/codex\n" +
|
||||
"Preferred WebSocket endpoint: https://xworkmate-bridge.svc.plus/acp-server/codex/acp\n" +
|
||||
"Compatibility HTTP RPC endpoint: https://xworkmate-bridge.svc.plus/acp-server/codex/acp/rpc"
|
||||
return state
|
||||
}
|
||||
|
||||
@ -246,8 +244,15 @@ func reconcileCLIListTarget(
|
||||
}
|
||||
state.DiscoveredMCPCount = discovered
|
||||
state.ManagedMCPCount = len(enabledServers(config.ManagedMCPServers))
|
||||
state.Detail = "MCP discovery uses `" + strings.Join(command, " ") +
|
||||
"`; LLM API stays launch-scoped."
|
||||
|
||||
if targetID == "gemini" {
|
||||
state.Detail = "Gemini public base URL: https://xworkmate-bridge.svc.plus/acp-server/gemini\n" +
|
||||
"Preferred WebSocket endpoint: https://xworkmate-bridge.svc.plus/acp-server/gemini/acp\n" +
|
||||
"Compatibility HTTP RPC endpoint: https://xworkmate-bridge.svc.plus/acp-server/gemini/acp/rpc"
|
||||
} else {
|
||||
state.Detail = "MCP discovery uses `" + strings.Join(command, " ") +
|
||||
"`; LLM API stays launch-scoped."
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
@ -286,7 +291,9 @@ func reconcileOpencode(config Config, opencodeHome string) MountTargetState {
|
||||
}
|
||||
state.DiscoveredMCPCount = discovered
|
||||
state.ManagedMCPCount = len(managedServers)
|
||||
state.Detail = "Managed MCP config is preserved in ~/.opencode/config.toml."
|
||||
state.Detail = "OpenCode public base URL: https://xworkmate-bridge.svc.plus/acp-server/opencode\n" +
|
||||
"Preferred WebSocket endpoint: https://xworkmate-bridge.svc.plus/acp-server/opencode/acp\n" +
|
||||
"Compatibility HTTP RPC endpoint: https://xworkmate-bridge.svc.plus/acp-server/opencode/acp/rpc"
|
||||
return state
|
||||
}
|
||||
|
||||
|
||||
@ -54,9 +54,9 @@ fi
|
||||
|
||||
BASE_URL="$(normalize_url "${BRIDGE_SERVER_URL:-${2:-https://xworkmate-bridge.svc.plus}}")"
|
||||
OPENCLAW_BASE_URL="$(normalize_url "${OPENCLAW_URL:-${3:-${BASE_URL}/gateway/openclaw}}")"
|
||||
CODEX_BASE_URL="$(normalize_url "${CODEX_RPC_URL:-${4:-${BASE_URL}/acp-server/codex}}")"
|
||||
OPENCODE_BASE_URL="$(normalize_url "${OPENCODE_RPC_URL:-${5:-${BASE_URL}/acp-server/opencode}}")"
|
||||
GEMINI_BASE_URL="$(normalize_url "${GEMINI_RPC_URL:-${6:-${BASE_URL}/acp-server/gemini}}")"
|
||||
CODEX_BASE_URL="$(normalize_url "${CODEX_RPC_URL:-${4:-${BASE_URL}/acp-server/codex/acp/rpc}}")"
|
||||
OPENCODE_BASE_URL="$(normalize_url "${OPENCODE_RPC_URL:-${5:-${BASE_URL}/acp-server/opencode/acp/rpc}}")"
|
||||
GEMINI_BASE_URL="$(normalize_url "${GEMINI_RPC_URL:-${6:-${BASE_URL}/acp-server/gemini/acp/rpc}}")"
|
||||
AUTH_TOKEN="${BRIDGE_AUTH_TOKEN:-${INTERNAL_SERVICE_TOKEN:-${7:-}}}"
|
||||
|
||||
ensure_rpc_path() {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user