Cloud·On-device·TaskManager Closed Loop
상위 Agent가 만든 기기 계획을 DeviceAgent TaskManager에 등록하고, 실제 진행·완료·실패 evidence를 같은 workflow로 되돌려 후속 실행 또는 제한적 재계획을 결정하는 계약이다.
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
정상 STARTED와 PROGRESS는 상태 갱신으로 끝낸다. 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를 누락하면 실행 가능한 계획으로 수용하지 않는다. setMoveTo는 movement.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-text는 VOICE_PIPELINE_TEST=true와 FORCE_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-dev의 task_event ingest가 HTTP 500을 반환한 기록은 배포본 동기화 문제로 분리했다. 로컬 handler는 동일 payload를 처리했다. 이 항목은 현재 운영 상태를 뜻하지 않으며, 새 배포에서는 동일 E2E를 다시 확인해야 한다.
10. Release gate
다음 증거가 모두 있어야 closed loop를 완료로 판정한다.
- Cloud plan이 canonical
submitTask또는submitWorkflow를 생성한다. - On-device bridge가 필드와 반복 단계를 손실 없이 전달한다.
- DeviceAgent가 Task와 각 Workflow step을 실행한다.
- 실제 callback이 completion target과 일치한다.
- 동일 correlation ID가 Cloud까지 왕복한다.
- 취소·차단·실패가 구조화된 reason으로 전달된다.
- 정상 진행은 추가 LLM 호출 없이 이어진다.
- 필요한 실패만 bounded replanning으로 연결된다.
- Console과 Monitor에서 plan, dispatch, device response와 terminal 상태가 함께 보인다.
- 실기기 system app은 설치본과 신규 APK의 platform certificate 일치 후 교체한다.
컴파일, unit test, dry-run과 command ACK만으로 물리 동작 완료를 주장하지 않는다.