← Docs hub

Cloud·On-device·TaskManager Closed Loop

상위 Agent가 만든 기기 계획을 DeviceAgent TaskManager에 등록하고, 실제 진행·완료·실패 evidence를 같은 workflow로 되돌려 후속 실행 또는 제한적 재계획을 결정하는 계약이다.

Voice Agent To SoC TaskManager Closed Loop

1. 책임 경계

구성요소 책임
Cloud Planner 사용자 목표 해석, capability 선택, 단계와 의존관계 구성
On-device bridge Cloud JSON을 DeviceAgent Bundle로 변환하고 event를 Cloud에 전달
DeviceAgent TaskManager admission, queue, 실행, timeout, 취소와 terminal 판정
Device domain 이동·청정·화면·TTS 등 실제 기능 수행
Completion bridge callback과 상태 변화를 공통 evidence로 변환
Console·Monitor plan, dispatch, 단계, event와 기기 응답 관측

Planner는 물리 완료를 추정하지 않는다. TaskManager는 자연어 목표를 다시 해석하지 않는다.

2. Runtime 흐름

user or product goal
-> Cloud plan
-> device_task_requests or device_workflow_requests
-> On-device contract mapping
-> DeviceAgent submitTask or submitWorkflow
-> domain execution
-> progress and terminal evidence
-> On-device event relay
-> local continuation, user confirmation or bounded replanning

정상 STARTEDPROGRESS는 상태 갱신으로 끝낸다. BLOCKED, FAILED, TIMEOUT, 명시적 사용자 변경과 requires_cloud_decision=true인 event만 상위 판단 후보다.

3. Cloud 요청 계약

단일 Task

{
  "taskMethod": "setAirCleanerOperation",
  "executionMode": "async",
  "contract_version": "a2a-task-orchestration-v1",
  "cloud_workflow_id": "wf_voice_001",
  "cloud_step_id": "step_clean_bedroom",
  "cloud_plan_id": "plan_clean_house",
  "cloud_output_key": "clean_result",
  "wait_policy": "completed",
  "params": {
    "action": "1",
    "positionName": "안방"
  }
}

On-device adapter는 이를 forceTaskManager=true, source=CLOUD|VOICE, queue와 payload를 포함한 submitTask Bundle로 변환한다.

Workflow

submitWorkflow의 canonical dispatch에는 root-level subTasks가 있어야 한다. payload.subTasks는 모니터와 외부 호환을 위한 mirror다.

{
  "method": "submitWorkflow",
  "source": "CLOUD",
  "queue": "workflow",
  "taskQueue": "workflow",
  "forceTaskManager": true,
  "workflowName": "room_clean_return",
  "executionMode": "queued_wait",
  "subTasks": [
    {
      "taskMethod": "setMoveTo",
      "targetRoom": "안방",
      "areaId": "5",
      "positionId": "5",
      "completionTarget": "movement.arrived"
    },
    {
      "taskMethod": "startBasicAirClear",
      "targetRoom": "안방",
      "completionTarget": "cleaning.stopped"
    },
    {
      "taskMethod": "returnToStation",
      "completionTarget": "movement.stationCharging"
    }
  ]
}

4. Event와 correlation

필드 의미
taskId DeviceAgent native Task ID
taskMethod 실행된 도메인 method
status lifecycle 상태
reason_code, reason_params 실패와 차단 근거
recoverability 재시도·사용자 확인·취소 판단
requires_cloud_decision 상위 판단 필요 여부
cloud_workflow_id Cloud workflow 상관관계
cloud_step_id 원래 계획 단계
cloud_plan_id 계획 버전
cloud_output_key 후속 단계가 참조할 결과 이름
wait_policy submit, started, completed 중 대기 기준

Workflow, Task와 callback에서 같은 ID를 유지한다. event 재전송은 workflow ID, step ID와 state version으로 중복 제거한다.

5. 조회형 context 경로

getDevicePlanningContext, getTaskManagerStatus, getQueueStatus, listTasks, getTaskStatus, classifyTaskIngress는 실행 Task로 감싸지 않고 control method로 직접 전달한다.

{
  "method": "getDevicePlanningContext",
  "source": "CLOUD",
  "queue": "state",
  "taskQueue": "state",
  "forceTaskManager": true,
  "contract_version": "a2a-task-orchestration-v1"
}

Planner는 context의 위치, 공간, 배터리, 이동·청정 상태, queue와 capability를 사용한다. 값이 없거나 오래됐으면 기능을 임의 추정하지 않고 조회, 대기 또는 clarification으로 처리한다.

6. 복합 계획 보존

동일 capability가 여러 번 나타나도 종류 수로 축약하지 않는다.

욕실 이동
-> 안방 이동
-> 안방 청정
-> 스테이션 복귀

Planner 계약은 다음 정보를 함께 보존한다.

필드 의미
matched_action_count 중복 제거된 capability 종류 수
minimum_executable_action_count 실제 필요한 최소 실행 횟수
required_action_instances 순서와 argument가 있는 capability occurrence

repair 결과가 목적지나 반복 occurrence를 누락하면 실행 가능한 계획으로 수용하지 않는다. setMoveTomovement.arrived, 청정은 cleaning.stopped, 복귀는 도킹 evidence를 받아야 다음 단계로 간다.

7. callback 이후 판단

event 기본 처리
STARTED, PROGRESS 상태와 UI 갱신, Planner 미호출
COMPLETED 의존 단계가 있으면 로컬 계속, 없으면 workflow 종료
CANCELLED 후속 dependent step 차단, 사용자 의도 확인
BLOCKED context·policy 사유를 보고 대기, 대체 또는 질문
FAILED, TIMEOUT bounded retry 가능 여부 판정 후 필요할 때만 replan
사용자 계획 변경 현재 Task 취소·보상 후 새 plan 검토

재계획은 새 문장 해석을 반복하는 기본 루프가 아니다. 실패 사유, 현재 context, 이미 완료한 단계와 남은 목표를 입력으로 사용하며 횟수와 도구 호출에 상한을 둔다.

8. Text Console 검증 경계

A2A Text Console의 /device-textVOICE_PIPELINE_TEST=trueFORCE_CLOUD_LLM=true를 사용해 STT 이후 경로를 검증한다.

TextInputTestReceiver
-> ForegroundService USE_TEXT_INPUT
-> processTextAsVoiceInput
-> processVoiceCmd
-> processCloudLLM
-> DeviceAgent TaskManager

이 경로는 device context, Cloud plan, TTS 응답, TaskManager dispatch와 callback을 포함한다. wake word, audio capture, STT decode와 실제 마이크 품질은 증명하지 않는다.

브라우저와 shim이 같은 PC에 있으면 기본 연결은 다음과 같다.

항목
Local shim http://127.0.0.1:18080
On-device Cloud API http://127.0.0.1:18080
기기 연결 현재 adb devices의 serial
기기 loopback adb reverse tcp:18080 tcp:18080

9. 검증 증거 요약

세부 로그는 보존 아카이브에 두고, 활성 문서에는 판정만 유지한다.

날짜 검증 판정
2026-07-22 Cloud request, AAR mapping, Iot bridge, TaskManager event unit tests 통과
2026-07-23 Worker → DeviceAgent workflow → step event → MaumAi callback 실기기 통과
2026-07-23 per-request dry-run과 subTaskResults[] ACK 통과
2026-07-23 조회형 planning context와 ingress classification 통과
2026-07-24 Text Console → local Cloud → TaskManager → callback 통과
2026-07-30 반복 위치 occurrence와 4단계 계획 보존 관련 회귀 322 passed, 실기기 완료 기록

당시 app-api-devtask_event ingest가 HTTP 500을 반환한 기록은 배포본 동기화 문제로 분리했다. 로컬 handler는 동일 payload를 처리했다. 이 항목은 현재 운영 상태를 뜻하지 않으며, 새 배포에서는 동일 E2E를 다시 확인해야 한다.

10. Release gate

다음 증거가 모두 있어야 closed loop를 완료로 판정한다.

  1. Cloud plan이 canonical submitTask 또는 submitWorkflow를 생성한다.
  2. On-device bridge가 필드와 반복 단계를 손실 없이 전달한다.
  3. DeviceAgent가 Task와 각 Workflow step을 실행한다.
  4. 실제 callback이 completion target과 일치한다.
  5. 동일 correlation ID가 Cloud까지 왕복한다.
  6. 취소·차단·실패가 구조화된 reason으로 전달된다.
  7. 정상 진행은 추가 LLM 호출 없이 이어진다.
  8. 필요한 실패만 bounded replanning으로 연결된다.
  9. Console과 Monitor에서 plan, dispatch, device response와 terminal 상태가 함께 보인다.
  10. 실기기 system app은 설치본과 신규 APK의 platform certificate 일치 후 교체한다.

컴파일, unit test, dry-run과 command ACK만으로 물리 동작 완료를 주장하지 않는다.

11. 관련 문서

Keyboard shortcuts

⌘K / Ctrl+KOpen command palette
/Focus search
g hGo to home
g pGo to projects
g sGo to sessions
j / kNext / prev row (tables)
?Show this help
EscClose dialogs

Structured queries

Mix key:value filters with free text in the palette:

type:sessionOnly session pages
project:llm-wikiFilter by project name (substring)
model:claudeFilter by model name (substring)
date:>2026-03-01Sessions after a date
date:<2026-04-01Sessions before a date
tags:rustPages mentioning a tag/topic
sort:dateSort results by date (newest first)

Example: type:session project:llm-wiki date:>2026-04 sort:date