bridge: remove gateway target compatibility layer

This commit is contained in:
Haitao Pan 2026-04-11 17:23:19 +08:00
parent 5004ee2438
commit 9d52d75fff
13 changed files with 85 additions and 146 deletions

View File

@ -264,6 +264,13 @@ Response:
}
```
Notes:
- `accepted` indicates the request envelope was accepted
- `cancelled` is `true` only when an active session was actually cancelled
- if the session does not exist or is already finished, `cancelled` may be
`false`
### 3.5 `session.close`
Request:
@ -288,6 +295,12 @@ Response:
}
```
Notes:
- `accepted` indicates the request envelope was accepted
- `closed` is `true` only when an existing session state was actually closed
- if the session does not exist or is already gone, `closed` may be `false`
### 3.6 `xworkmate.dispatch.resolve`
Purpose:
@ -342,7 +355,6 @@ Key input fields:
- `workingDirectory`
- `routing.routingMode`
- `routing.preferredGatewayProviderId`
- `routing.preferredGatewayTarget`
- `routing.explicitExecutionTarget`
- `routing.explicitProviderId`
- `routing.explicitModel`
@ -358,7 +370,6 @@ Representative response fields:
- `resolvedExecutionTarget`
- `resolvedProviderId`
- `resolvedGatewayProviderId`
- `resolvedEndpointTarget`
- `resolvedModel`
- `resolvedSkills`
- `skillResolutionSource`
@ -374,8 +385,6 @@ APP-facing interpretation:
- if `resolvedExecutionTarget = single-agent`, use `resolvedProviderId`
- if `resolvedExecutionTarget = gateway`, use `resolvedGatewayProviderId`
- `resolvedEndpointTarget` is retained as a compatibility field for bridge
internals; APP code should prefer `resolvedGatewayProviderId`
### 3.7.1 UI / APP consumption model
@ -412,21 +421,12 @@ Recommended interpretation rules:
- read `resolvedGatewayProviderId`
- ignore `resolvedProviderId`
Compatibility rule:
- `resolvedEndpointTarget` is a compatibility field
- APP code should not use `local` / `remote` as its primary business model
- current bridge mapping is:
- `resolvedGatewayProviderId = local` -> `resolvedEndpointTarget = local`
- `resolvedGatewayProviderId = openclaw` -> `resolvedEndpointTarget = remote`
UI binding guidance:
- provider picker for single-agent mode should be populated from
`providerCatalog`
- gateway picker should be populated from `gatewayProviders`
- gateway UI should display `local` and `openclaw` as selectable providers
rather than exposing transport-level `local` / `remote` terminology
- disabled or unavailable states should come from `xworkmate.routing.resolve`
response fields such as:
- `unavailable`
@ -482,7 +482,7 @@ Purpose:
Key params:
- `runtimeId`
- `mode`
- `gatewayProviderId`
- `clientId`
- `locale`
- `userAgent`
@ -509,8 +509,10 @@ Response fields:
Notes:
- for `mode=remote`, the bridge overrides runtime endpoint selection to
`wss://openclaw.svc.plus`
- for `gatewayProviderId=openclaw`, the bridge overrides runtime endpoint
selection to `wss://openclaw.svc.plus`
- for `gatewayProviderId=local`, the bridge keeps the caller-provided local
gateway endpoint configuration
- upstream gateway auth uses `Authorization: Bearer $INTERNAL_SERVICE_TOKEN`
- the app does not provide production openclaw endpoint truth
@ -557,6 +559,13 @@ Differences from HTTP:
- notifications are written back as WebSocket JSON messages
- result envelopes and error envelopes are also written as WebSocket JSON messages
Observed bridge behavior on the public deployment:
- authenticated plain `GET /acp` without WebSocket upgrade headers returns HTTP
`400 Bad Request`
- authenticated `GET /acp` with valid WebSocket upgrade headers returns HTTP
`101 Switching Protocols`
## 5. Gemini ACP Adapter API
### 5.1 Default listen address

View File

@ -55,7 +55,7 @@ flowchart LR
CAP3["gemini"]
GW["Bridge-owned gateway routing"]
GW1["remote mode -> openclaw"]
GW1["gatewayProviderId=openclaw"]
BRIDGE --> CAP
CAP --> CAP1
@ -93,7 +93,7 @@ Important distinction:
single-agent providers: `codex`, `opencode`, and `gemini`
- `gateway` is not part of that provider catalog; it is exposed through the
separate `xworkmate.gateway.*` bridge-owned runtime path
- for remote gateway mode, the bridge rewrites the upstream target to
- for `gatewayProviderId=openclaw`, the bridge rewrites the upstream target to
`wss://openclaw.svc.plus`
## Production Truth
@ -126,4 +126,4 @@ Canonical APP-facing paths stay on the bridge origin:
- no production `xworkmate.providers.sync`
- no app direct call to `acp-server.svc.plus/*`
- no app direct call to `openclaw.svc.plus`
- remote gateway runtime status is reported as `openclaw.svc.plus:443`, but the app still talks only to the bridge
- openclaw gateway runtime status is reported as `openclaw.svc.plus:443`, but the app still talks only to the bridge

View File

@ -64,8 +64,6 @@ APP-facing routing should be modeled in three layers:
- `openclaw`
For APP integration, `gatewayProviders` is the stable gateway-facing concept.
The older `local` / `remote` endpoint-target split is retained only as a
bridge-internal compatibility layer.
APP and UI code should consume bridge state in two phases:
@ -116,8 +114,6 @@ Use these terms consistently in docs:
- `bridge-owned routing`: bridge logic that selects and proxies to upstreams
- `gatewayProvider`: the APP-facing identifier for a gateway backend such as
`local` or `openclaw`
- `endpoint target`: an internal compatibility field, not the preferred APP
concept
Avoid describing upstream URLs as if the APP should call them directly.

View File

@ -21,10 +21,9 @@
- `resolvedExecutionTarget`
- `resolvedProviderId`
- `resolvedGatewayProviderId`
- `resolvedEndpointTarget`
- `acp.capabilities` 暴露 bridge 内建的生产 provider catalog并参与后续路由选择。
- APP 对 gateway 的分区应以 `gatewayProviders` / `resolvedGatewayProviderId`
为主,不以 `local / remote` 传输语义为主
为主。
### 2. 典型 Case 层
@ -105,8 +104,6 @@ flutter test test/runtime/app_controller_single_agent_workspace_binding_regressi
- bridge 还会暴露 `gatewayProviders = local / openclaw`
- `xworkmate.routing.resolve` 在 skill / prompt / target 组合下,返回合理的
`resolvedProviderId``resolvedGatewayProviderId`
- `resolvedEndpointTarget` 仅作为兼容字段保留APP 侧 gateway 分流以
`resolvedGatewayProviderId` 为主。
### 执行层断言

View File

@ -35,7 +35,6 @@ func buildResolvedExecutionParams(
switch resolved.ResolvedExecutionTarget {
case router.ExecutionTargetGateway:
next["mode"] = router.ExecutionTargetGatewayChat
next["executionTarget"] = resolved.ResolvedEndpointTarget
case router.ExecutionTargetMultiAgent:
next["mode"] = router.ExecutionTargetMultiAgent
default:
@ -54,7 +53,6 @@ func buildResolvedExecutionParams(
next["selectedSkills"] = append([]string(nil), resolved.ResolvedSkills...)
}
next["resolvedExecutionTarget"] = resolved.ResolvedExecutionTarget
next["resolvedEndpointTarget"] = resolved.ResolvedEndpointTarget
next["resolvedProviderId"] = resolved.ResolvedProviderID
next["resolvedGatewayProviderId"] = resolved.ResolvedGatewayProviderID
next["resolvedModel"] = resolved.ResolvedModel
@ -82,12 +80,12 @@ func (s *Server) runGateway(
notify func(map[string]any),
) taskResult {
_ = ctx
executionTarget := strings.TrimSpace(shared.StringArg(params, "executionTarget", ""))
if executionTarget == "" {
executionTarget = router.EndpointTargetLocal
gatewayProvider := strings.TrimSpace(shared.StringArg(params, "gatewayProvider", ""))
if gatewayProvider == "" {
gatewayProvider = router.GatewayProviderLocal
}
result := s.gateway.RequestByMode(
executionTarget,
gatewayProvider,
method,
params,
2*time.Minute,
@ -180,7 +178,6 @@ func sanitizeExternalACPParams(method string, params map[string]any) map[string]
// Internal routing/runtime fields must not leak into external provider payloads.
delete(next, "metadata")
delete(next, "resolvedExecutionTarget")
delete(next, "resolvedEndpointTarget")
delete(next, "resolvedProviderId")
delete(next, "resolvedGatewayProviderId")
delete(next, "resolvedModel")

View File

@ -16,7 +16,7 @@ func handleGatewayConnect(
) map[string]any {
request := gatewayruntime.ConnectRequest{
RuntimeID: strings.TrimSpace(shared.StringArg(params, "runtimeId", "")),
Mode: strings.TrimSpace(shared.StringArg(params, "mode", "unconfigured")),
Mode: strings.TrimSpace(shared.StringArg(params, "gatewayProviderId", "")),
ClientID: strings.TrimSpace(shared.StringArg(params, "clientId", "")),
Locale: strings.TrimSpace(shared.StringArg(params, "locale", "")),
UserAgent: strings.TrimSpace(shared.StringArg(params, "userAgent", "")),
@ -53,6 +53,9 @@ func handleGatewayConnect(
Password: strings.TrimSpace(shared.StringArg(asMap(params["auth"]), "password", "")),
},
}
if request.Mode == "" {
request.Mode = "local"
}
request = applyProductionGatewayRouting(request)
request.ReportedRemoteAddress = resolveGatewayReportedRemoteAddress(server, request)
result := server.gateway.Connect(request, notify)
@ -68,7 +71,7 @@ func handleGatewayConnect(
func applyProductionGatewayRouting(
request gatewayruntime.ConnectRequest,
) gatewayruntime.ConnectRequest {
if strings.TrimSpace(strings.ToLower(request.Mode)) != "remote" {
if strings.TrimSpace(strings.ToLower(request.Mode)) != "openclaw" {
return request
}
request.Endpoint = gatewayruntime.Endpoint{
@ -187,7 +190,7 @@ func resolveGatewayReportedRemoteAddress(
server *Server,
request gatewayruntime.ConnectRequest,
) string {
if strings.TrimSpace(strings.ToLower(request.Mode)) != "remote" {
if strings.TrimSpace(strings.ToLower(request.Mode)) != "openclaw" {
return ""
}
_ = server

View File

@ -12,7 +12,7 @@ func TestResolveGatewayReportedRemoteAddressUsesBuiltInOpenClawEndpoint(t *testi
server := NewServer()
got := resolveGatewayReportedRemoteAddress(server, gatewayruntime.ConnectRequest{
Mode: "remote",
Mode: "openclaw",
Endpoint: gatewayruntime.Endpoint{
Host: "127.0.0.1",
Port: 18789,
@ -34,7 +34,7 @@ func TestResolveGatewayReportedRemoteAddressNormalizesExplicitPublicRemoteHost(
server := NewServer()
got := resolveGatewayReportedRemoteAddress(server, gatewayruntime.ConnectRequest{
Mode: "remote",
Mode: "openclaw",
Endpoint: gatewayruntime.Endpoint{
Host: "openclaw.svc.plus",
Port: 443,

View File

@ -30,7 +30,6 @@ func resolveRoutingMetadataWithProviders(
Prompt: strings.TrimSpace(sharedString(params, "taskPrompt")),
WorkingDirectory: strings.TrimSpace(sharedString(params, "workingDirectory")),
RoutingMode: strings.TrimSpace(sharedString(routingParams, "routingMode")),
PreferredGatewayTarget: strings.TrimSpace(sharedString(routingParams, "preferredGatewayTarget")),
PreferredGatewayProviderID: strings.TrimSpace(sharedString(routingParams, "preferredGatewayProviderId")),
ExplicitExecutionTarget: strings.TrimSpace(sharedString(routingParams, "explicitExecutionTarget")),
ExplicitProviderID: strings.TrimSpace(sharedString(routingParams, "explicitProviderId")),
@ -54,7 +53,6 @@ func mergeRoutingResponse(response map[string]any, result router.Result) map[str
response = map[string]any{}
}
response["resolvedExecutionTarget"] = result.ResolvedExecutionTarget
response["resolvedEndpointTarget"] = result.ResolvedEndpointTarget
response["resolvedProviderId"] = result.ResolvedProviderID
response["resolvedGatewayProviderId"] = result.ResolvedGatewayProviderID
response["resolvedModel"] = result.ResolvedModel

View File

@ -138,9 +138,9 @@ func TestHandleRoutingResolveCoversNineScenarioBuckets(t *testing.T) {
"taskPrompt": tc.prompt,
"workingDirectory": "/tmp/workspace",
"routing": map[string]any{
"routingMode": "auto",
"preferredGatewayTarget": "local",
"allowSkillInstall": false,
"routingMode": "auto",
"preferredGatewayProviderId": "local",
"allowSkillInstall": false,
"availableSkills": func() []any {
values := make([]any, 0, len(localAvailableSkills))
for _, item := range localAvailableSkills {
@ -159,6 +159,9 @@ func TestHandleRoutingResolveCoversNineScenarioBuckets(t *testing.T) {
t.Fatalf("expected gateway provider %q, got %#v", tc.expectedGatewayProviderID, got)
}
}
if _, exists := result["resolvedEndpointTarget"]; exists {
t.Fatalf("expected resolvedEndpointTarget compatibility field to be removed, got %#v", result)
}
if got := result["skillResolutionSource"]; got != tc.expectedSkillSource {
t.Fatalf("expected skill source %q, got %#v", tc.expectedSkillSource, got)
}
@ -202,8 +205,7 @@ func TestExecuteSessionTaskAutoRoutingRecordsProjectMemory(t *testing.T) {
"taskPrompt": "create a powerpoint deck for launch",
"workingDirectory": workspaceDir,
"routing": map[string]any{
"routingMode": "auto",
"preferredGatewayTarget": "local",
"routingMode": "auto",
"availableSkills": []any{
map[string]any{
"id": "pptx",
@ -373,8 +375,7 @@ func TestExecuteSessionTaskAutoRoutingUsesBridgeProductionProviderOrder(t *testi
"taskPrompt": "create a powerpoint deck for launch",
"workingDirectory": workspaceDir,
"routing": map[string]any{
"routingMode": "auto",
"preferredGatewayTarget": "local",
"routingMode": "auto",
"availableSkills": []any{
map[string]any{
"id": "pptx",
@ -442,8 +443,7 @@ func TestExecuteSessionTaskAutoRoutingPromotesComplexRequestToMultiAgent(t *test
"aiGatewayBaseUrl": aiGateway.URL,
"aiGatewayApiKey": "test-key",
"routing": map[string]any{
"routingMode": "auto",
"preferredGatewayTarget": "local",
"routingMode": "auto",
},
},
},

View File

@ -16,7 +16,7 @@ func TestManagerConnectUsesReportedRemoteAddressInSnapshot(t *testing.T) {
result := manager.Connect(ConnectRequest{
RuntimeID: "runtime-1",
Mode: "remote",
Mode: "openclaw",
ClientID: "openclaw-macos",
Locale: "en_US",
UserAgent: "XWorkmate/1.0.0",

View File

@ -303,7 +303,7 @@ func (f *fakeGatewayServer) Close() {
func buildTestConnectRequest(port int) ConnectRequest {
return ConnectRequest{
RuntimeID: "runtime-1",
Mode: "remote",
Mode: "openclaw",
ClientID: "openclaw-macos",
Locale: "en_US",
UserAgent: "XWorkmate/1.0.0",

View File

@ -17,10 +17,6 @@ const (
ExecutionTargetGateway = "gateway"
ExecutionTargetGatewayChat = "gateway-chat"
EndpointTargetSingleAgent = "singleAgent"
EndpointTargetLocal = "local"
EndpointTargetRemote = "remote"
GatewayProviderLocal = "local"
GatewayProviderOpenClaw = "openclaw"
)
@ -29,7 +25,6 @@ type Request struct {
Prompt string
WorkingDirectory string
RoutingMode string
PreferredGatewayTarget string
PreferredGatewayProviderID string
ExplicitExecutionTarget string
ExplicitProviderID string
@ -45,7 +40,6 @@ type Request struct {
type Result struct {
ResolvedExecutionTarget string
ResolvedEndpointTarget string
ResolvedProviderID string
ResolvedGatewayProviderID string
ResolvedModel string
@ -86,7 +80,7 @@ func (r Resolver) Resolve(req Request) Result {
MemorySources: mem.Sources,
}
result.ResolvedExecutionTarget, result.ResolvedEndpointTarget, result.ResolvedGatewayProviderID = r.resolveExecution(req, mem.Preferences)
result.ResolvedExecutionTarget, result.ResolvedGatewayProviderID = r.resolveExecution(req, mem.Preferences)
result.ResolvedProviderID, result.Unavailable, result.UnavailableCode, result.UnavailableMessage = resolveProvider(
req,
mem.Preferences,
@ -127,26 +121,21 @@ func (r Resolver) Resolve(req Request) Result {
result.ResolvedExecutionTarget = ExecutionTargetGateway
}
}
if result.ResolvedEndpointTarget == "" {
if result.ResolvedExecutionTarget == ExecutionTargetGateway {
result.ResolvedGatewayProviderID, result.ResolvedEndpointTarget = resolveGatewayRouting(
req.PreferredGatewayProviderID,
req.PreferredGatewayTarget,
)
} else {
result.ResolvedEndpointTarget = EndpointTargetSingleAgent
}
if result.ResolvedExecutionTarget == ExecutionTargetGateway &&
result.ResolvedGatewayProviderID == "" {
result.ResolvedGatewayProviderID = resolveGatewayProvider(
req.PreferredGatewayProviderID,
)
}
return result
}
func (r Resolver) resolveExecution(req Request, prefs memory.Preferences) (string, string, string) {
func (r Resolver) resolveExecution(req Request, prefs memory.Preferences) (string, string) {
explicit := strings.TrimSpace(req.ExplicitExecutionTarget)
if strings.EqualFold(strings.TrimSpace(req.RoutingMode), RoutingModeExplicit) && explicit != "" {
return mapExplicitTarget(
explicit,
req.PreferredGatewayProviderID,
req.PreferredGatewayTarget,
)
}
@ -158,56 +147,48 @@ func (r Resolver) resolveExecution(req Request, prefs memory.Preferences) (strin
switch {
case localTask && complexTask:
return ExecutionTargetMultiAgent, EndpointTargetSingleAgent, ""
return ExecutionTargetMultiAgent, ""
case onlineTask && complexTask:
return ExecutionTargetMultiAgent, EndpointTargetSingleAgent, ""
return ExecutionTargetMultiAgent, ""
case localTask:
return ExecutionTargetSingleAgent, EndpointTargetSingleAgent, ""
return ExecutionTargetSingleAgent, ""
case onlineTask:
providerID, endpointTarget := resolveGatewayRouting(
return ExecutionTargetGateway, resolveGatewayProvider(
req.PreferredGatewayProviderID,
req.PreferredGatewayTarget,
)
return ExecutionTargetGateway, endpointTarget, providerID
case complexTask:
return ExecutionTargetMultiAgent, EndpointTargetSingleAgent, ""
return ExecutionTargetMultiAgent, ""
}
switch normalizeExecutionTarget(r.classify(req)) {
case ExecutionTargetGateway:
providerID, endpointTarget := resolveGatewayRouting(
return ExecutionTargetGateway, resolveGatewayProvider(
req.PreferredGatewayProviderID,
req.PreferredGatewayTarget,
)
return ExecutionTargetGateway, endpointTarget, providerID
case ExecutionTargetMultiAgent:
return ExecutionTargetMultiAgent, EndpointTargetSingleAgent, ""
return ExecutionTargetMultiAgent, ""
case ExecutionTargetSingleAgent:
return ExecutionTargetSingleAgent, EndpointTargetSingleAgent, ""
return ExecutionTargetSingleAgent, ""
}
switch normalizeExecutionTarget(strings.TrimSpace(prefs.PreferredRoute)) {
case ExecutionTargetGateway:
providerID, endpointTarget := resolveGatewayRouting(
return ExecutionTargetGateway, resolveGatewayProvider(
req.PreferredGatewayProviderID,
req.PreferredGatewayTarget,
)
return ExecutionTargetGateway, endpointTarget, providerID
case ExecutionTargetMultiAgent:
return ExecutionTargetMultiAgent, EndpointTargetSingleAgent, ""
return ExecutionTargetMultiAgent, ""
case ExecutionTargetSingleAgent:
if len(normalizeProviders(req.AvailableProviders)) > 0 {
return ExecutionTargetSingleAgent, EndpointTargetSingleAgent, ""
return ExecutionTargetSingleAgent, ""
}
}
if len(normalizeProviders(req.AvailableProviders)) > 0 {
return ExecutionTargetSingleAgent, EndpointTargetSingleAgent, ""
return ExecutionTargetSingleAgent, ""
}
providerID, endpointTarget := resolveGatewayRouting(
return ExecutionTargetGateway, resolveGatewayProvider(
req.PreferredGatewayProviderID,
req.PreferredGatewayTarget,
)
return ExecutionTargetGateway, endpointTarget, providerID
}
func (r Resolver) classify(req Request) string {
@ -224,37 +205,27 @@ func (r Resolver) classify(req Request) string {
func mapExplicitTarget(
value string,
preferredGatewayProviderID string,
preferredGatewayTarget string,
) (string, string, string) {
) (string, string) {
switch strings.TrimSpace(value) {
case EndpointTargetLocal:
return ExecutionTargetGateway, EndpointTargetLocal, GatewayProviderLocal
case EndpointTargetRemote:
return ExecutionTargetGateway, EndpointTargetRemote, GatewayProviderOpenClaw
case "multiAgent", ExecutionTargetMultiAgent:
return ExecutionTargetMultiAgent, EndpointTargetSingleAgent, ""
case EndpointTargetSingleAgent, ExecutionTargetSingleAgent:
return ExecutionTargetSingleAgent, EndpointTargetSingleAgent, ""
return ExecutionTargetMultiAgent, ""
case "singleAgent", ExecutionTargetSingleAgent:
return ExecutionTargetSingleAgent, ""
case ExecutionTargetGateway:
providerID, endpointTarget := resolveGatewayRouting(
return ExecutionTargetGateway, resolveGatewayProvider(
preferredGatewayProviderID,
preferredGatewayTarget,
)
return ExecutionTargetGateway, endpointTarget, providerID
default:
return ExecutionTargetSingleAgent, EndpointTargetSingleAgent, ""
return ExecutionTargetSingleAgent, ""
}
}
func resolveGatewayRouting(preferredGatewayProviderID, preferredGatewayTarget string) (string, string) {
func resolveGatewayProvider(preferredGatewayProviderID string) string {
providerID := normalizeGatewayProvider(preferredGatewayProviderID)
if providerID == "" {
providerID = gatewayProviderFromEndpointTarget(preferredGatewayTarget)
}
if providerID == "" {
providerID = GatewayProviderLocal
}
return providerID, endpointTargetForGatewayProvider(providerID)
return providerID
}
func normalizeGatewayProvider(value string) string {
@ -268,26 +239,6 @@ func normalizeGatewayProvider(value string) string {
}
}
func gatewayProviderFromEndpointTarget(value string) string {
switch strings.TrimSpace(value) {
case EndpointTargetRemote:
return GatewayProviderOpenClaw
case EndpointTargetLocal, "":
return GatewayProviderLocal
default:
return ""
}
}
func endpointTargetForGatewayProvider(providerID string) string {
switch normalizeGatewayProvider(providerID) {
case GatewayProviderOpenClaw:
return EndpointTargetRemote
default:
return EndpointTargetLocal
}
}
func resolveProvider(
req Request,
prefs memory.Preferences,

View File

@ -32,9 +32,6 @@ func TestResolveExplicitTargetOverridesAuto(t *testing.T) {
if result.ResolvedExecutionTarget != ExecutionTargetSingleAgent {
t.Fatalf("expected explicit single-agent route, got %#v", result)
}
if result.ResolvedEndpointTarget != EndpointTargetSingleAgent {
t.Fatalf("expected singleAgent endpoint target, got %#v", result)
}
if result.ResolvedProviderID != "codex" || result.ResolvedModel != "gpt-5.4" {
t.Fatalf("unexpected explicit provider/model: %#v", result)
}
@ -86,16 +83,13 @@ func TestResolveAutoOnlineTaskToGateway(t *testing.T) {
}
result := resolver.Resolve(Request{
Prompt: "跨浏览器执行并搜索最新资讯",
PreferredGatewayTarget: EndpointTargetLocal,
Prompt: "跨浏览器执行并搜索最新资讯",
PreferredGatewayProviderID: GatewayProviderLocal,
})
if result.ResolvedExecutionTarget != ExecutionTargetGateway {
t.Fatalf("expected gateway route, got %#v", result)
}
if result.ResolvedEndpointTarget != EndpointTargetLocal {
t.Fatalf("expected local gateway target, got %#v", result)
}
if result.ResolvedGatewayProviderID != GatewayProviderLocal {
t.Fatalf("expected local gateway provider, got %#v", result)
}
@ -126,22 +120,19 @@ func TestResolveUsesClassifierForBoundarySamples(t *testing.T) {
}
result := resolver.Resolve(Request{
Prompt: "help me handle this ambiguous request",
PreferredGatewayTarget: EndpointTargetLocal,
Prompt: "help me handle this ambiguous request",
PreferredGatewayProviderID: GatewayProviderLocal,
})
if result.ResolvedExecutionTarget != ExecutionTargetGateway {
t.Fatalf("expected classifier to resolve gateway route, got %#v", result)
}
if result.ResolvedEndpointTarget != EndpointTargetLocal {
t.Fatalf("expected local endpoint target, got %#v", result)
}
if result.ResolvedGatewayProviderID != GatewayProviderLocal {
t.Fatalf("expected local gateway provider, got %#v", result)
}
}
func TestResolveGatewayProviderMapsOpenClawToRemoteEndpoint(t *testing.T) {
func TestResolveGatewayProviderSelectsOpenClaw(t *testing.T) {
resolver := Resolver{
SkillFinder: skills.StaticFinder{},
SkillInstaller: nil,
@ -159,7 +150,4 @@ func TestResolveGatewayProviderMapsOpenClawToRemoteEndpoint(t *testing.T) {
if result.ResolvedGatewayProviderID != GatewayProviderOpenClaw {
t.Fatalf("expected openclaw gateway provider, got %#v", result)
}
if result.ResolvedEndpointTarget != EndpointTargetRemote {
t.Fatalf("expected remote endpoint target for openclaw, got %#v", result)
}
}