bridge: remove gateway target compatibility layer
This commit is contained in:
parent
5004ee2438
commit
9d52d75fff
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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.
|
||||
|
||||
|
||||
@ -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` 为主。
|
||||
|
||||
### 执行层断言
|
||||
|
||||
|
||||
@ -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")
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user