Cloud Planner · On-device · DeviceAgent 데이터 흐름과 스키마
이 문서는 사용자 발화가 Cloud plan이 되고, 온디바이스를 거쳐 DeviceAgent TaskManager에서 실행된 뒤, callback과 단계 결과가 다시 Cloud 판단으로 돌아오는 전체 데이터 흐름을 설명한다.
Hop 1. 음성·텍스트 입력
온디바이스 ForegroundService는 STT 또는 테스트 텍스트를
recognized_text로 정규화하고 session_id, 대화 이력, 활성 workflow를
voice_context에 넣는다.
{
"recognized_text": "안방으로 가서 청정하고 복귀해줘",
"session_id": "voice-session-001",
"voice_context": {
"active_workflow_id": ""
}
}
테스트 텍스트와 실제 STT는 입력 경로만 다르고 Cloud 이후 계약은 같아야 한다.
Hop 2. Device Planning Context
DeviceCommunicator.getDevicePlanningContext()가 MR6 DeviceAgent의
getDevicePlanningContext를 호출하고, 결과를
voice_context.device_context에 첨부한다.
현재 device_context.v1의 주요 영역은 다음과 같다.
- battery
- map과 실제 room catalog
- location
- air_quality
- cleaning
- movement
- task_manager queue
- 기본 capabilities
Planner가 임의 room ID나 좌표를 만들지 않도록 실제 room catalog를 grounding 근거로 사용한다.
snapshot_ts는 Context 조립 시각일 뿐 개별 sensor 관찰 시각이 아니다.
현재 MR6는 배터리, 공기질, AWS IoT, 음성 LLM 상태에
device-source-freshness.v1 metadata를 추가한다. Cloud는 명시적으로
usable=false 또는 stale=true인 값을 조건과 사용자 답변에서 제외한다.
주기 sensor와 상태변경 callback은 서로 다른 만료 정책을 사용한다.
세부 계약은 Device Source Freshness Contract를
참조한다.
Hop 3. Planner Output
Cloud Main Router와 Planner는 owner/skill과 typed step graph를 만든다.
{
"selected_routes": ["ODL"],
"steps": [
{
"id": "move",
"route": "ODL",
"action": {
"capability_id": "move_to_room",
"operation_id": "start",
"arguments": {"position_name": "안방"}
},
"depends_on": [],
"output_key": "arrival",
"execution_target": "device",
"wait_policy": "completed"
},
{
"id": "clean",
"route": "ODL",
"action": {
"capability_id": "room_cleaning",
"operation_id": "start",
"arguments": {"position_name": "안방"}
},
"depends_on": ["move"],
"input_from": {"arrival": "arrival.result"},
"execution_target": "device",
"wait_policy": "completed"
}
]
}
depends_on은 실행 순서다. output_key + input_from은 데이터 의존성이다.
선행 단계가 끝났다는 사실과 선행 단계가 만든 값을 후속 단계가 쓰는 것은
다른 계약이다.
Hop 4. Device Dispatch
Cloud runtime은 typed step을 실행 가능한 요청으로 컴파일한다.
{
"device_task_requests": [],
"device_workflow_requests": [
{
"method": "submitWorkflow",
"cloud_workflow_id": "wf-001",
"subTasks": [
{
"taskMethod": "setMoveTo",
"cloud_step_id": "move",
"completionTarget": "movement.arrived"
}
]
}
]
}
온디바이스는 device_task_requests와 device_workflow_requests를 해석해
Android Bundle 계약으로 변환한다. 이 계층은 task 성공을 임의로 판단하지
않는다.
Hop 5. DeviceAgent TaskManager
MR6 TaskManager는 다음을 소유한다.
- admission과 policy
- queue와 dependency
- timeout과 cancel
- executor dispatch
- completion target 관찰
- task/workflow event와 reason
실제 domain manager가 물리 동작을 수행하고,
TaskCompletionStateStore가 movement.arrived,
movement.stationCharging, security.started 같은 완료 표식을 보존한다.
Hop 6. Task Event Callback
DeviceAgent는 onTaskEvent Bundle을 온디바이스로 전달한다.
{
"event_name": "FAILED",
"cloud_workflow_id": "wf-001",
"cloud_step_id": "move",
"task_method": "setMoveTo",
"reason_code": "MOVE_POLICY_NOT_ALLOWED",
"reason_params": {},
"requires_cloud_decision": true
}
온디바이스는 event를 직렬화해 Cloud task_event 요청으로 보낸다.
현재 task event와 semantic observation은 app-private durable ordered
outbox를 공통으로 사용한다. 코드 연결과 로컬 회귀는 확인했지만 프로세스
kill/restart와 platform-signed 실기기 replay 증거는 남아 있다.
MR6 DeviceAgent의 순차 workflow 완료 event는 parent workflow 이름만
반복하지 않는다. task_method에는 실제로 끝난 step method를 넣고,
domain executor가 반환한 result Bundle도 같은 event에 포함한다. 이
payload는 Cloud가 그대로 신뢰하는 값이 아니라 다음 Hop의 capability
result contract로 다시 제한된다.
Hop 7. Step Resume 또는 Replan
Cloud workflow state는 COMPLETED와 WORKFLOW_STEP_COMPLETED를
단계 완료 의미로 정규화해 callback을 step_results에 반영한다. 원래
event 이름은 모니터링과 telemetry를 위해 그대로 보존한다.
{
"plan_state": {
"completed_step_ids": ["move"],
"step_results": {
"move": {
"status": "completed",
"event_name": "WORKFLOW_STEP_COMPLETED",
"task_method": "setMoveTo",
"result": {"area_id": "6", "current_room_name": "안방"}
}
}
}
}
Cloud capability catalog의 result_contract_defaults는 payload를
deny_unlisted로 시작한다. 각 capability의 bindable_result_fields에
선언된 필드만 위 result에 남는다. 현재 첫 연결 범위는
move_to_room과 stationary_purify다.
다음 device step의 input_from은 두 경계를 모두 통과해야 한다.
- source reference가 해당 capability의 허용 envelope/result path인가.
- destination key가 다음 capability의 required/optional slot인가.
경로가 없거나 허용되지 않으면 이전 단계 전체 result 객체로 대체하지 않는다.
task를 제출하지 않고 STEP_RESULT_BINDING_FAILED와 함께
waiting_replan으로 전환한다. 같은 턴의 Cloud step 연결도
source.result를 tts_response의 명시적 호환 alias로만 취급하며,
임의 field나 전체 객체 fallback을 허용하지 않는다.
bounded Experience Replanner의 result-dependent replan도 같은 경계를
사용한다. 모델은 source_step.result.field 형태의 input_from을 제안할 수
있지만, source step이 명시적 dependency이고 field가 source capability의
allowlist에 있으며 destination이 다음 capability의 slot일 때만 컴파일된다.
Cloud는 전체 plan을 DeviceAgent workflow로 즉시 보내지 않고 첫 ready step만
제출한다. terminal callback 이후 다음 step을 해제하고, 검증된 result를
slot에 주입해 후속 task를 만든다. 정상 callback 처리에는 추가 LLM 호출이
필요하지 않다.
정상 완료는 dependency를 해제하고 다음 step을 진행한다. 실패했다고 항상
LLM을 호출하지 않는다. 로컬 recovery가 소진됐거나
requires_cloud_decision이 true인 의미 경계에서만 retry, ask, replan,
cancel, return 중 하나를 결정한다.
Supervisor 또는 bounded Replanner가 사용자 확인을 선택하면 Cloud는 이를
별도 Android 응답 모델로 확장하지 않고 기존 공통
replan_decision.tts_response로 정규화한다. On-device는 task-event와
semantic-observation 응답을 동일한 orchestration handler에서 소비한다.
구현 상태와 빈 구간
| 경계 | 현재 | 빈 구간 |
|---|---|---|
| 입력·context | STT/텍스트, device_context.v1, 배터리·공기질·AWS·LLM source freshness 전달 |
위치·Map revision 등 나머지 source freshness |
| Cloud plan | 중첩 action typed step과 주요 device compiler |
내부 method 전체를 Planner capability로 노출하지 않음 |
| 온디바이스 dispatch | task/workflow/control 제출과 durable ordered outbox | platform-signed restart replay |
| DeviceAgent 실행 | generic TaskManager와 주요 executor | 일부 domain의 managed lifecycle |
| callback | event/reason/trace와 semantic observation durable relay 코드 연결 | platform-signed restart replay |
| workflow state | 완료 event 정규화, catalog result projection, typed input_from binding, bounded Experience Replanner result-dependent plan 설치·순차 resume, 공통 ask-user TTS |
나머지 capability result schema, production shared-state E2E |
스키마 경계 원칙
- Planner output은 자연어 token이 아니라
capability_id + operation_id + arguments를 실행 기준으로 사용한다. - 온디바이스는 Cloud JSON과 DeviceAgent Bundle 사이의 계약 adapter다.
- TaskManager accepted는 physical completed가 아니다.
- completion target과 task event name을 혼동하지 않는다.
- raw Vision frame, credential, 내부 전체 로그를 Planner context로 보내지 않는다.
- callback의
cloud_workflow_id,cloud_step_id,cloud_output_key를 end-to-end 보존한다. - 이전 단계 결과는 capability별 allowlist와 destination slot schema를 모두 통과한 값만 다음 device task에 사용한다.
소스 근거
Cloud
gemini/a2a/planner/main_router_api.pygemini/a2a/runtime/task_manager.pygemini/a2a/runtime/workflow_state.py
On-device
ForegroundService.ktDeviceCommunicator.ktCloudIntentWorkflowRunner.ktDurableOrderedDeviceEventOutbox.kt
MR6 DeviceAgent
TaskManager.javaDevicePlanningContextProvider.javaTaskCompletionStateStore.javaTaskExecutorBootstrap.java