feat(host-agent): default planner transport to cloud
Tests / Test passed: 794

This commit is contained in:
2026-07-14 20:42:27 +08:00
parent 6e511111c4
commit 30f09b6268
10 changed files with 98 additions and 78 deletions
+18 -22
View File
@@ -36,8 +36,8 @@ which raises the stakes on where its provider credentials live.
- Reuse existing Host<->Cloud authentication and existing provider
wire-format code; add no new auth scope and no duplicated Anthropic/OpenAI
translation logic.
- Preserve today's direct-to-provider path as a fully supported, still-default
option, so existing Host Agent deployments with local keys are unaffected.
- Preserve the direct-to-provider path as a fully supported explicit opt-out
for Host Agent deployments that require local provider keys.
**Non-Goals:**
- Not moving prompt construction (`runtime/planner_prompts.py`, Scene
@@ -74,13 +74,12 @@ must stay in lockstep with the Host Agent's local transport as providers'
APIs evolve.
### D2: New transport axis, orthogonal to provider selection
Host Agent config gains `AI_PLANNER_TRANSPORT` (`direct` default | `cloud`),
independent of `AI_PLANNER_PROVIDER`. `direct` is today's behavior
unchanged (Host Agent builds the SDK client itself). `cloud` builds a new
Host Agent config gains `AI_PLANNER_TRANSPORT` (`cloud` default | `direct`),
independent of `AI_PLANNER_PROVIDER`. `cloud` builds a new
`CloudProxyToolCallingClient` instead; provider/model selection and
credentials for that path live in the Cloud API's own
`AI_PLANNER_PROVIDER`/`AI_PLANNER_MODEL`/`ANTHROPIC_API_KEY`/`OPENAI_API_KEY`
configuration, not the Host Agent's.
active Provider profile, not the Host Agent's. `direct` remains an explicit
opt-out that builds the provider SDK client locally.
Alternative considered: overload `AI_PLANNER_PROVIDER=cloud` as a third
provider value. Rejected: provider and transport are different axes (a
@@ -158,9 +157,9 @@ proposal does not change that risk profile, only where the call happens.
## Risks / Trade-offs
- **[Risk] Cloud Control Plane is now in the hot path of every planning
step for hosts on the `cloud` transport** -> Mitigation: `direct`
transport remains the default and fully supported; operators who need
offline/low-latency operation simply don't opt in. Bounded by the
step by default** -> Mitigation: `direct` transport remains fully
supported as an explicit opt-out for operators who need offline or
low-latency operation. Bounded by the
existing `AI_PLANNER_TIMEOUT_SECONDS`, same as today.
- **[Risk] Cloud Control Plane outage now stalls planning (not just new
task assignment) for opted-in hosts** -> Mitigation: same
@@ -195,20 +194,17 @@ proposal does not change that risk profile, only where the call happens.
## Migration Plan
1. Add Cloud API configuration (`AI_PLANNER_PROVIDER`/`AI_PLANNER_MODEL`/
`AI_PLANNER_TIMEOUT_SECONDS`/provider API keys) and the new internal
route, guarded by the existing host-scoped auth. Off by default in the
sense that no Host Agent calls it until configured to use `cloud`
transport.
2. Add the Host Agent's `AI_PLANNER_TRANSPORT` setting (default `direct`)
and `CloudProxyToolCallingClient`. Existing deployments are unaffected
until an operator sets `AI_PLANNER_TRANSPORT=cloud` and removes the
local provider key.
1. Add Cloud API Provider profile management and the new internal route,
guarded by the existing host-scoped auth. Configure and activate a
Cloud-held Provider key before running a Host Agent.
2. Add the Host Agent's `AI_PLANNER_TRANSPORT` setting (default `cloud`)
and `CloudProxyToolCallingClient`. Existing deployments that require a
local provider key set `AI_PLANNER_TRANSPORT=direct` explicitly.
3. Update `docs/CLOUD_DEPLOYMENT.md` with the proxy configuration path and
its trade-offs (latency, availability coupling, data-path expansion).
4. Rollback is setting `AI_PLANNER_TRANSPORT=direct` (or unsetting it) on
affected hosts and restoring their local provider key; the Cloud API
route can remain deployed but unused.
4. Rollback is setting `AI_PLANNER_TRANSPORT=direct` on affected Hosts and
restoring their local provider key; the Cloud API route can remain
deployed but unused.
## Open Questions
@@ -22,12 +22,11 @@ provider/model or rotate a key without touching any Host.
- Cloud API owns `AI_PLANNER_PROVIDER`/`AI_PLANNER_MODEL`/provider API keys
as its own configuration; these are no longer required on the Host Agent
when the new proxy transport is used.
- Host Agent gains a new opt-in transport setting (proxy vs. direct-to-provider)
- Host Agent gains a transport setting (cloud-proxy vs. direct-to-provider)
and a new `ToolCallingClient` implementation that calls the cloud endpoint
instead of constructing a local Anthropic/OpenAI SDK client. The existing
direct-to-provider transport remains fully supported and is the default,
so hosts that already run with a local provider key keep working
unchanged.
instead of constructing a local Anthropic/OpenAI SDK client. Cloud-proxy is
the default; the existing direct-to-provider transport remains fully
supported as an explicit opt-out for hosts with local provider keys.
- Reuse the existing Host-scoped bearer credential (already used for
heartbeat/claim/renew/result) for the new endpoint; no new auth scope.
- Cloud API does not durably persist screenshot bytes or full prompt text
@@ -31,10 +31,15 @@ to `AIPlanner`'s own decision logic.
transport, and its own decision logic is unchanged regardless of which
transport is in effect
#### Scenario: Direct transport remains available and default
#### Scenario: Cloud-proxy transport is the default
- **WHEN** no transport is explicitly configured
- **THEN** the AI Planner uses the direct-to-provider transport, matching
its behavior before the cloud-proxy transport existed
- **THEN** the AI Planner uses the cloud-proxy transport and the Cloud
Control Plane's planner-decision endpoint
#### Scenario: Direct transport remains available by explicit configuration
- **WHEN** the Host Agent is configured with the direct transport
- **THEN** the AI Planner uses the direct-to-provider transport with locally
configured credentials
#### Scenario: Cloud-proxy transport resolves a decision without a local provider client
- **WHEN** the Host Agent is configured with the cloud-proxy transport
+14 -10
View File
@@ -46,7 +46,7 @@
## 3. Host Agent: cloud-proxy transport
- [x] 3.1 Add `AI_PLANNER_TRANSPORT` (`direct` default | `cloud`) to
- [x] 3.1 Add `AI_PLANNER_TRANSPORT` (`cloud` default | `direct`) to
`apps/device-host-agent/host_agent/config.py`.
Done: `HostAgentConfig.ai_planner_transport` +
`_parse_ai_planner_transport`.
@@ -70,11 +70,10 @@
- [x] 4.1 Update `apps/device-host-agent/host_agent/execution.py`'s
`_host_agent_planner_config()`/`create_task_runner()` so that when
`AI_PLANNER_TRANSPORT=cloud`, the constructed `TaskRunner`'s
`AI_PLANNER_TRANSPORT` is unset or set to `cloud`, the constructed `TaskRunner`'s
`AIPlanner` is built with a `CloudProxyToolCallingClient` instead of
the default local provider client, while leaving the existing
default-enabled/direct-transport behavior unchanged when
`AI_PLANNER_TRANSPORT` is unset or `direct`.
the local provider client, while `AI_PLANNER_TRANSPORT=direct` remains
an explicit direct-to-provider fallback.
Done: new `_host_agent_planner()` helper + `host_agent_config` param
threaded through `create_execution_factories()` from
`app.py::create_application()`. Manually verified both transports
@@ -106,11 +105,10 @@
(7 tests, using `httpx.MockTransport` -- success, screenshot
base64-encoding, network error, structured 502 error, unstructured
error response, and client-ownership on `close()`).
- [x] 5.4 Unit tests for Host Agent wiring: `AI_PLANNER_TRANSPORT=cloud`
constructs an `AIPlanner` using `CloudProxyToolCallingClient`;
`AI_PLANNER_TRANSPORT` unset or `direct` preserves existing
direct-to-provider construction (no regression to the
already-implemented default-enabled behavior).
- [x] 5.4 Unit tests for Host Agent wiring: `AI_PLANNER_TRANSPORT` unset or
set to `cloud` constructs an `AIPlanner` using
`CloudProxyToolCallingClient`; explicit `direct` preserves local
provider construction.
Done: added to `apps/device-host-agent/tests/test_execution.py`
(2 new tests, one parametrized over `None`/`"direct"`).
- [x] 5.5 Full non-integration suite (`uv run --all-packages pytest -m
@@ -136,3 +134,9 @@
full non-integration suite (492 passed); `python -m compileall` clean
for `packages/cloud-platform/cloud`, `apps/cloud-api`,
`apps/device-host-agent`.
## 8. Default transport amendment
- [x] 8.1 Make `cloud` the Host Agent default for
`AI_PLANNER_TRANSPORT`, retain `direct` as an explicit fallback, and
update the runtime contract, deployment guidance, and regression tests.