fix acp discovery and bridge forwarding

This commit is contained in:
Haitao Pan 2026-04-10 10:18:02 +08:00
parent 72cef71ff8
commit 51d8ed6946
2 changed files with 97 additions and 3 deletions

View File

@ -148,7 +148,7 @@ func (s *Server) runSingleAgentViaExternalProvider(
params map[string]any,
notify func(map[string]any),
) (map[string]any, error) {
endpoint := strings.TrimSpace(provider.Endpoint)
endpoint := resolveSingleAgentForwardEndpoint(provider)
if endpoint == "" {
return nil, fmt.Errorf("external provider endpoint is missing")
}
@ -163,6 +163,21 @@ func (s *Server) runSingleAgentViaExternalProvider(
)
}
func resolveSingleAgentForwardEndpoint(provider syncedProvider) string {
endpoint := strings.TrimSpace(provider.Endpoint)
if endpoint == "" {
return ""
}
if !strings.Contains(strings.ToLower(endpoint), "xworkmate-bridge.svc.plus") {
return endpoint
}
providerID := strings.TrimSpace(strings.ToLower(provider.ProviderID))
if providerID == "" {
return endpoint
}
return fmt.Sprintf("https://acp-server.svc.plus/%s/acp/rpc", providerID)
}
func sanitizeExternalACPParams(method string, params map[string]any) map[string]any {
if len(params) == 0 {
return map[string]any{}
@ -259,8 +274,8 @@ func requestExternalACPHTTP(
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
req.Header.Set("Accept", "application/json")
if strings.TrimSpace(authorization) != "" {
req.Header.Set("Authorization", strings.TrimSpace(authorization))
if normalized := normalizeAuthorizationHeader(authorization); normalized != "" {
req.Header.Set("Authorization", normalized)
}
response, err := (&http.Client{Timeout: 2 * time.Minute}).Do(req)
if err != nil {
@ -280,6 +295,17 @@ func requestExternalACPHTTP(
return decoded, nil
}
func normalizeAuthorizationHeader(raw string) string {
normalized := strings.TrimSpace(raw)
if normalized == "" {
return ""
}
if strings.Contains(normalized, " ") {
return normalized
}
return "Bearer " + normalized
}
func requestExternalACPWebSocket(
ctx context.Context,
endpoint *urlSpec,

View File

@ -0,0 +1,68 @@
package acp
import "testing"
func TestResolveSingleAgentForwardEndpoint(t *testing.T) {
t.Parallel()
cases := []struct {
name string
provider syncedProvider
want string
}{
{
name: "preserves upstream endpoint",
provider: syncedProvider{
ProviderID: "opencode",
Endpoint: "https://acp-server.svc.plus/opencode/acp/rpc",
},
want: "https://acp-server.svc.plus/opencode/acp/rpc",
},
{
name: "rewrites bridge discovery endpoint to codex upstream",
provider: syncedProvider{
ProviderID: "codex",
Endpoint: "https://xworkmate-bridge.svc.plus",
},
want: "https://acp-server.svc.plus/codex/acp/rpc",
},
{
name: "rewrites bridge discovery endpoint to gemini upstream",
provider: syncedProvider{
ProviderID: "gemini",
Endpoint: "https://xworkmate-bridge.svc.plus",
},
want: "https://acp-server.svc.plus/gemini/acp/rpc",
},
}
for _, tc := range cases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
if got := resolveSingleAgentForwardEndpoint(tc.provider); got != tc.want {
t.Fatalf("resolveSingleAgentForwardEndpoint() = %q, want %q", got, tc.want)
}
})
}
}
func TestNormalizeAuthorizationHeader(t *testing.T) {
t.Parallel()
cases := map[string]string{
"": "",
"Bearer bridge": "Bearer bridge",
"bridge-token": "Bearer bridge-token",
" bridge-token ": "Bearer bridge-token",
}
for raw, want := range cases {
raw, want := raw, want
t.Run(raw, func(t *testing.T) {
t.Parallel()
if got := normalizeAuthorizationHeader(raw); got != want {
t.Fatalf("normalizeAuthorizationHeader(%q) = %q, want %q", raw, got, want)
}
})
}
}