Files
agentic-mobile-control/openspec/changes/cloud-planner-proxy/tasks.md
T
q792602257 1107ace89c
Tests / Test passed: 626
Default-enable AI Planner in Host Agent; propose cloud-planner-proxy
- Host Agent now defaults AI_PLANNER_ENABLED=true (opt-out via env),
  scoped to apps/device-host-agent/host_agent/execution.py only; the
  shared runtime.planner_config default (disabled) is unchanged.
- Add openspec proposal for cloud-planner-proxy: centralize LLM
  provider config/credentials on the Cloud Control Plane and let the
  Host Agent proxy AI Planner decisions through it instead of holding
  provider API keys locally. Proposal only, no implementation yet.
2026-07-13 20:50:35 +08:00

93 lines
4.8 KiB
Markdown

## 1. Cloud API: planner configuration
- [ ] 1.1 Add Cloud API-side planner configuration (provider, model, timeout,
provider API keys) analogous to `runtime/planner_config.py`, loaded
from the Cloud API's own process environment (e.g.
`AI_PLANNER_PROVIDER`/`AI_PLANNER_MODEL`/`AI_PLANNER_TIMEOUT_SECONDS`,
`ANTHROPIC_API_KEY`/`OPENAI_API_KEY`), living in
`packages/cloud-platform/cloud` or `apps/cloud-api`.
- [ ] 1.2 Add `anthropic`/`openai` as explicit dependencies of the package
that hosts this configuration (confirm whether `packages/cloud-platform`
or `apps/cloud-api` is the right home, matching where the new endpoint
handler will live).
## 2. Cloud API: planner-decision internal endpoint
- [ ] 2.1 Add request/response Pydantic models to `cloud.internal_api.models`
for a planner-decision call: request carries `system_prompt`,
`user_prompt`, optional base64 screenshot, tool specs, timeout;
response carries resolved `tool_name`/`arguments` or a structured
error.
- [ ] 2.2 Add the internal route (e.g. `POST /internal/v1/planner/decide`)
to the existing internal router, reusing the current host-scoped
bearer auth dependency used by heartbeat/claim/renew/result -- no new
scope.
- [ ] 2.3 Implement the route handler by constructing
`runtime.tool_calling_client.AnthropicToolCallingClient` or
`OpenAIToolCallingClient` (per D1) from the Cloud API's own planner
configuration, calling `.decide(...)`, and translating
`ToolCallDecision`/`ToolCallUnavailable` into the response model.
- [ ] 2.4 Ensure the handler does not log or persist raw prompt text or
screenshot bytes; only metadata (host id, resolved tool name,
latency, error class) may be logged.
## 3. Host Agent: cloud-proxy transport
- [ ] 3.1 Add `AI_PLANNER_TRANSPORT` (`direct` default | `cloud`) to
`apps/device-host-agent/host_agent/config.py`.
- [ ] 3.2 Add a `request_planner_decision(...)` method to
`host_agent/client.py::HostAgentClient` that calls the new Cloud API
endpoint using the existing authenticated `httpx` session, importing
the new request/response models from `cloud.internal_api.models`.
- [ ] 3.3 Add `host_agent/cloud_planner_client.py::CloudProxyToolCallingClient`
implementing the `runtime.tool_calling_client.ToolCallingClient`
Protocol structurally (no import of `host_agent`/`cloud` from
`runtime`), wrapping `HostAgentClient.request_planner_decision(...)`
and raising `ToolCallUnavailable` on any failure (network error, auth
rejection, non-2xx, provider error, timeout) -- matching D7.
## 4. Host Agent: wiring
- [ ] 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
`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`.
- [ ] 4.2 Confirm `apps/device-host-agent/tests/test_execution.py::test_runtime_owned_packages_do_not_import_host_or_cloud_concerns`-style
boundary checks still pass with the new module in place.
## 5. Tests
- [ ] 5.1 Unit tests for Cloud API planner configuration loading
(defaults, provider/model/timeout parsing) mirroring
`tests/test_planner_config.py`.
- [ ] 5.2 Unit tests for the planner-decision endpoint: authorized request
resolves a decision, unauthenticated/foreign-host request is
rejected, provider failure returns a structured error without
crashing.
- [ ] 5.3 Unit tests for `CloudProxyToolCallingClient`: successful decision
round-trip, and each failure mode raises `ToolCallUnavailable`.
- [ ] 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).
- [ ] 5.5 Full non-integration suite (`uv run --all-packages pytest -m
"not integration"`) passes with no regressions.
## 6. Documentation
- [ ] 6.1 Update `docs/CLOUD_DEPLOYMENT.md`'s Runtime AI Planner section
with the `cloud` transport configuration path, its trade-offs
(latency, cloud-availability coupling, expanded data path for
screenshots/prompts), and the credential split (Cloud API holds
provider keys for `cloud` transport; Host Agent holds them for
`direct` transport).
## 7. Validation
- [ ] 7.1 `openspec validate --strict` passes for this change.
- [ ] 7.2 Ruff check/format and `compileall` pass for all touched packages.