Commit Graph
55 Commits
Author SHA1 Message Date
q792602257 cdef630e67 feat(cloud-console): add user authentication and administration 2026-07-13 17:54:53 +08:00
q792602257 8f74eac50c Jenkins
Tests / Test passed: 545
2026-07-13 16:11:40 +08:00
q792602257andClaude Opus 4.6 50f0b8ade9 feat(driver): add Android UiAutomator2 driver
Tests / Test No test results found
Register `SUPPORTED_DRIVER_TYPES["uiautomator2"]` backed by the new
`AndroidDriver`, mirroring `WDADriver` method-for-method. tap/swipe/home use
the confirmed UiAutomator2 mobile commands (`clickGesture`, `dragGesture`,
`pressKey`); swipe converts `duration_ms` to a drag speed with a zero-distance
guard. Adds 34 mocked unit tests, an env-var-gated integration test, and
corrects the outdated "Android not registered" note in the iPhone setup doc.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-07-13 14:47:01 +08:00
q792602257andClaude Opus 4.6 2169bb03d9 feat(cloud-console): task listing, attempt history, CORS, and console SPA
Implements the cloud-console OpenSpec change: adds GET /v1/tasks (filterable,
bounded pagination, tasks:read) and GET /v1/tasks/{id}/attempts (404 on unknown
task) to the platform SDK, with matching CloudClient methods and a closed-by-
default CLOUD_CONSOLE_CORS_ORIGINS allow-list wired through CloudControlConfig.
Ships an independent Vue 3 + Vite SPA at cloud-console/ that authenticates with
an operator-supplied bearer token held in sessionStorage, renders tasks with
attempt history, device pool, host registry, and the plugin registry with a
registration form.

Backend test suite: 438 passed (-m "not integration"); cloud-console typecheck
and production build both succeed. PostgreSQL-backed repository tests and
manual end-to-end verification remain pending external infrastructure.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-07-13 14:00:23 +08:00
q792602257 e61dcca801 feat(cloud): add edge host enrollment 2026-07-13 13:54:16 +08:00
q792602257 7b717a05a9 test(openspec): map cloud integration scenarios 2026-07-13 08:21:44 +08:00
q792602257 22d37ca95b chore(cloud): verify integration change 2026-07-13 08:06:15 +08:00
q792602257 e28705b0f2 docs(cloud): add deployment runbook 2026-07-13 07:58:24 +08:00
q792602257 90961bd0a4 fix(host-agent): load configured devices 2026-07-13 07:56:41 +08:00
q792602257 dbd70732e1 build(deploy): add cloud stack containers 2026-07-12 22:58:17 +08:00
q792602257 1f95d23beb feat(cloud-sdk): authenticate client requests 2026-07-12 22:53:34 +08:00
q792602257 16bcbf5a27 feat(cloud-sdk): expose distributed task status 2026-07-12 19:57:03 +08:00
q792602257 ec1e8c20d8 feat(host-agent): renew active assignment leases 2026-07-12 19:06:22 +08:00
q792602257 8131c0124b feat(cloud-api): add correlated lifecycle logging 2026-07-12 18:37:51 +08:00
q792602257 09cfe54dd9 test(host-protocol): verify internal API isolation 2026-07-12 18:17:39 +08:00
q792602257 a24efc1043 feat(host-protocol): renew and complete leases 2026-07-12 18:15:04 +08:00
q792602257 c7f8d0c128 feat(host-protocol): long poll assignments 2026-07-12 18:12:33 +08:00
q792602257 efb754fbe7 feat(host-protocol): accept heartbeat snapshots 2026-07-12 18:10:42 +08:00
q792602257 b4cbd83dcd feat(host-protocol): define internal API models 2026-07-12 18:07:42 +08:00
q792602257 a05465458c test(cloud-auth): cover authorization failures 2026-07-12 18:05:30 +08:00
q792602257 7d22b5234d feat(cloud-auth): require production credentials 2026-07-12 18:02:49 +08:00
q792602257 82b66f74a2 feat(cloud-auth): bind host principals 2026-07-12 17:58:20 +08:00
q792602257 71f0a892e3 feat(cloud-auth): enforce public scopes 2026-07-12 17:56:14 +08:00
q792602257 b916b394c7 feat(cloud-auth): verify scoped bearer tokens 2026-07-12 17:45:31 +08:00
q792602257 4cb116f527 test(cloud-scheduler): prove assignment concurrency 2026-07-12 17:42:20 +08:00
q792602257 c58d9e5316 feat(cloud-scheduler): reap expired leases 2026-07-12 17:32:11 +08:00
q792602257 e1af4403f5 feat(cloud-scheduler): record terminal results 2026-07-12 17:25:57 +08:00
q792602257 1b15a8a218 feat(cloud-scheduler): renew active leases 2026-07-12 17:23:07 +08:00
q792602257 b0a5b1426f feat(cloud-scheduler): claim host assignments 2026-07-12 17:20:51 +08:00
q792602257 ac7734c7dc feat(cloud-scheduler): reserve devices atomically 2026-07-12 17:19:10 +08:00
q792602257 0a9392b7ea feat(cloud-store): persist task lease history 2026-07-12 17:15:09 +08:00
q792602257 52d2a86a4c test(cloud-store): verify repository contracts 2026-07-12 17:11:10 +08:00
q792602257 7f5f740e2a test(cloud-store): verify schema migrations 2026-07-12 16:59:08 +08:00
q792602257 64aa9b39bc feat(cloud-store): support SQLite and PostgreSQL engines 2026-07-12 16:53:02 +08:00
q792602257 ae29477f6a feat(cloud-store): define repository contract 2026-07-12 16:48:07 +08:00
q792602257 638216d6e7 feat(cloud): validate control plane and host configuration 2026-07-12 16:45:12 +08:00
q792602257 351b2c6637 test(workspace): verify distribution boundaries 2026-07-12 14:14:09 +08:00
q792602257 00bf5ee428 test(workspace): enforce cloud package ownership 2026-07-12 14:12:51 +08:00
q792602257andClaude Sonnet 5 61ff3b425d feat(agent-runtime): add LLM-driven AI Planner with dual-provider tool calling
Replaces the stub Planner's fixed describe_screen/[] behavior with a real
decision-maker: AIPlanner uses native tool/function calling (Anthropic or
OpenAI, pluggable via AI_PLANNER_PROVIDER) to select exactly one grounded
action per turn, with an explicit finish_task(success, reason) tool for
completion/failure instead of an ambiguous "no tool call" signal. Default
disabled (AI_PLANNER_ENABLED=false) and additive; TaskRunner falls back to
the existing stub Planner unchanged when disabled.

Amends CONSTITUTION.md's Perception Boundary with one narrow exception:
only the AI Planner may receive the current step's raw screenshot bytes
alongside Scene, for vision-grounded coordinate grounding. Also fixes a
latent gap in TaskRunner.run(): observe/plan exceptions are now caught per
iteration and turned into a failed task with a failure_reason, instead of
propagating uncaught.

openspec change: ai-planner-runtime.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-12 13:48:50 +08:00
q792602257andClaude Opus 4.6 b94abde92a feat(skill-catalog-subscription): synced catalog + HTTP sync + MCP tools
Consumes the external Subscription Platform as source of truth for skill
content; reuses skills_learning domain models (extended with KnowledgeSkill)
and workflow.skill_exec resolver. HTTP/MCP deps land in api/ per
CONSTITUTION.md; synced skills use a physically separate SQLite file
(tasks/skills.sqlite3) to preserve the skill-authoring capability boundary.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-07-07 10:33:23 +08:00
q792602257 763c1b2299 test(perception-provider): cover NullPerceptionProvider/DefaultPerceptionProvider directly
Existing tests only exercised perception.scene_builder.build_scene()
directly or substituted a FakePerceptionProvider, so the real provider
port classes had no direct coverage. Both were already correct on
manual inspection; this closes the coverage gap.

openspec: perception-provider capability, archived change device-agent-runtime-foundation
2026-07-07 08:31:14 +08:00
q792602257 a279441aee fix(skill-versioning): consume divergence_tolerance, replace vacuous catalog-isolation guard
- divergence_tolerance was loaded from config but diff_flow_versions
  never consulted it, so structural_divergence was always plain
  sequence-equality regardless of the configured tolerance. Now
  actually applied per design.md D4.
- The skill-catalog-subscription isolation guard test asserted
  'skills.catalog' not in sys.modules, which is vacuously true since
  that module doesn't exist anywhere yet. Replaced with a real check
  against store.py's actual imports.

openspec: skill-versioning capability, archived change skill-learning-runtime
2026-07-07 08:31:11 +08:00
q792602257 ca5e300289 fix(semantic-scene): preserve page/intents when all widgets are dangling, drop dead exception-name set
- _with_known_widgets_only used to discard the entire SemanticScene
  (returning None) when filtering dangling-element-id widgets left an
  empty list, losing valid page/intents. Now returns a SemanticScene
  with widgets=[] instead, matching design.md's 'dropped, not a hard
  failure' intent.
- Removed _SDK_UNAVAILABLE_EXCEPTION_NAMES, dead code left over from an
  abandoned name-based exception-matching approach; the blanket except
  Exception already maps every SDK failure correctly.

openspec: semantic-scene capability, archived change semantic-scene-runtime
2026-07-07 08:31:03 +08:00
q792602257 725bf4cd9c fix(plugin-system): implement register_driver_type and stop discover() aborting on one bad manifest
- driver/registry.py never actually defined register_driver_type, so
  the plugin-system's 'driver plugin registered successfully' scenario
  was unreachable in production (only simulated via test monkeypatch).
  Added a real implementation wired into the existing driver factory
  registry.
- PluginRegistry.discover() only caught PluginValidationError/
  DuplicatePluginError, so a driver-kind manifest that failed wiring
  (DriverRegistryUnavailableError/PluginTargetResolutionError) aborted
  the whole scan, silently skipping co-located tool/skill manifests.
  Now caught and skipped per manifest instead.

openspec: plugin-system capability, archived change cloud-runtime
2026-07-07 08:31:00 +08:00
q792602257 031b929067 fix(multi-agent-collaboration): compose TaskRunner bookkeeping instead of forking it
CollaborativeTaskRunner hand-rolled its own step loop instead of
composing runtime/task.py's TaskRunner as design.md D3 requires,
silently dropping Timeline recording, WorldModel wiring,
TaskMetadataStore sync, and the on_task_succeeded/skill-synthesis
hook. Now calls TaskRunner's shared _start_world_view/
_record_step_result helpers for that bookkeeping. Also fixes
pre_observation being reused stale across steps in a multi-step plan
instead of refreshing to the prior step's post-observation.

openspec: multi-agent-collaboration capability, archived change multi-agent-runtime
2026-07-07 08:30:57 +08:00
q792602257 49ad589c2d fix(semantic-scene): move describe_screen_semantic out of the tools/ layer
tools/ is a Hexagonal inner layer that must never depend on LLM
concerns (ADR 0002), but describe_screen_semantic.py imported
semantic.enricher, which pulls in the Anthropic client by default.
Relocated the wrapper to runtime/, which is where LLM-dependent code
is allowed to live; updated the tool registry and all test imports
accordingly. No behavior change.

openspec: semantic-scene capability, archived change semantic-scene-runtime
2026-07-07 08:30:49 +08:00
q792602257 1bdc3784dc fix(device-pool): scope primary key by host and thread through capability_tags
- pooled_devices primary key changed from device_id alone to
  (host_id, device_id), so two hosts reporting the same local
  device_id no longer crash sync_host_devices() with an uncaught
  sqlite3.IntegrityError.
- Device gained a capability_tags field so DevicePool.sync_host_devices()
  can actually populate PooledDevice.capability_tags from a real host
  sync instead of always falling back to an empty list.

openspec: device-pool capability, archived change cloud-runtime
2026-07-07 08:30:47 +08:00
q792602257 a15756835c fix(workflow-orchestration): correct resume and failure-branch routing in WorkflowRunner
- Resume no longer infinite-loops when a crash occurs between
  append_step_result() and update_run() for a BranchStep: the recorded
  branch target is now read from the persisted result instead of
  recomputed as None.
- Resume no longer silently discards a recorded step failure that
  happened right before the crash; the run correctly ends failed.
- A failed step's own next_step_id (e.g. routing to a BranchStep that
  evaluates step_result_success) is now honored instead of
  unconditionally forcing the run to failed, per spec.

openspec: workflow-orchestration capability, archived change workflow-orchestration-runtime
2026-07-07 08:30:43 +08:00
q792602257 b5e68398f8 fix(world-model): scope WorldModel state per-task to prevent cross-task contamination
WorldModel routed all state through a single mutable _current_task_id,
so concurrent tasks sharing one instance could corrupt each other's
state. start_task() now returns a TaskWorldView handle scoped to that
task; TaskRunner.run() threads it through as a local variable instead
of reading self.world_model implicitly. Also extracts _start_world_view/
_record_step_result as reusable TaskRunner methods for composed runners.

openspec: world-model capability, archived change world-model-runtime
2026-07-07 08:30:36 +08:00
q792602257 d899b875ce cloud 2026-07-06 23:44:18 +08:00