Tests / Test passed: 626
- 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.
4.8 KiB
4.8 KiB
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 inpackages/cloud-platform/cloudorapps/cloud-api. - 1.2 Add
anthropic/openaias explicit dependencies of the package that hosts this configuration (confirm whetherpackages/cloud-platformorapps/cloud-apiis 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.modelsfor a planner-decision call: request carriessystem_prompt,user_prompt, optional base64 screenshot, tool specs, timeout; response carries resolvedtool_name/argumentsor 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.AnthropicToolCallingClientorOpenAIToolCallingClient(per D1) from the Cloud API's own planner configuration, calling.decide(...), and translatingToolCallDecision/ToolCallUnavailableinto 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(directdefault |cloud) toapps/device-host-agent/host_agent/config.py. - 3.2 Add a
request_planner_decision(...)method tohost_agent/client.py::HostAgentClientthat calls the new Cloud API endpoint using the existing authenticatedhttpxsession, importing the new request/response models fromcloud.internal_api.models. - 3.3 Add
host_agent/cloud_planner_client.py::CloudProxyToolCallingClientimplementing theruntime.tool_calling_client.ToolCallingClientProtocol structurally (no import ofhost_agent/cloudfromruntime), wrappingHostAgentClient.request_planner_decision(...)and raisingToolCallUnavailableon 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 whenAI_PLANNER_TRANSPORT=cloud, the constructedTaskRunner'sAIPlanneris built with aCloudProxyToolCallingClientinstead of the default local provider client, while leaving the existing default-enabled/direct-transport behavior unchanged whenAI_PLANNER_TRANSPORTis unset ordirect. - 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 raisesToolCallUnavailable. - 5.4 Unit tests for Host Agent wiring:
AI_PLANNER_TRANSPORT=cloudconstructs anAIPlannerusingCloudProxyToolCallingClient;AI_PLANNER_TRANSPORTunset ordirectpreserves 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 thecloudtransport configuration path, its trade-offs (latency, cloud-availability coupling, expanded data path for screenshots/prompts), and the credential split (Cloud API holds provider keys forcloudtransport; Host Agent holds them fordirecttransport).
7. Validation
- 7.1
openspec validate --strictpasses for this change. - 7.2 Ruff check/format and
compileallpass for all touched packages.