DeviceAgent / SoC Domain Map
이 문서는 Cloud A2A와 온디바이스 브릿지가 실제 기기 실행으로 내려갈 때, DeviceAgent 내부의 어떤 도메인이 실행 권한을 가져야 하는지 정리한다.
핵심 결론은 단순하다.
- Cloud는 사용자 발화를 보고 계획과 순서를 만든다.
- 온디바이스 브릿지는 Cloud plan을 DeviceAgent가 소비할 수 있는 task/workflow 요청으로 바꾼다.
- DeviceAgent
TaskManager는 task queue, workflow, 상태 이벤트, reason code를 관리한다. - 실제 실행 가능 여부와 세부 조건은
cleaning,moving,map,schedule,interaction도메인 매니저가 최종 판단해야 한다. - Cloud나 브릿지가 기존 도메인 매니저의 조건 판단을 우회해서
set함수만 직접 호출하면 안전하지 않다.
TaskManager 자체를 SoC 실행 오케스트레이션 기능 범주로 자세히 보려면 SoC TaskManager Execution Subsystem을 먼저 본다.
1. 왜 이 지도가 필요한가
복합명령 예시는 아래처럼 보인다.
거실로 가서 청정하고 안방으로 이동해줘
Cloud A2A 관점에서는 2~3개의 ODL step으로 계획할 수 있다.
{
"steps": [
{"route": "ODL", "purpose": "거실 이동"},
{"route": "ODL", "purpose": "거실 청정"},
{"route": "ODL", "purpose": "안방 이동"}
]
}
하지만 실제 실행 시점에는 아래 조건들이 계속 바뀐다.
- 현재 충전대 위인지
- 맵이 편집 중인지
- 대상 방이 실제 맵에 있는지
- 이동 중인지, 청정 중인지, 인터렉션 스케줄 중인지
- 배터리 부족, 경로 막힘, 센서 오류가 있는지
- 1번 task가 끝난 뒤 2번 task를 시작해도 되는지
따라서 Cloud가 처음에 모든 실행 조건을 확정하는 구조가 아니라, DeviceAgent가 각 task 실행 직전에 도메인 매니저를 통해 다시 확인해야 한다.
2. 계층별 책임
| 계층 | 책임 | 하지 말아야 할 일 |
|---|---|---|
| Cloud A2A Planner | route family, multi-step plan, step dependency, replan 판단 | 기기 내부 상태를 추측해서 강제 실행 |
| Cloud Runtime | ODL step을 device_task_requests로 변환, 정상 event는 저장만 하고 replan event만 판단 |
모든 PROGRESS/COMPLETED마다 LLM 재호출 |
| On-device Bridge | Cloud request를 DeviceAgent method/token/task 형태로 변환, 순차 실행, event relay | 기존 음성 명령 안전 조건 우회 |
| DeviceAgent TaskManager | submitTask, submitWorkflow, queue, timeout, cancel, event, reason code 관리 |
도메인별 실행 가능 조건을 자체 추측으로 대체 |
| DeviceAgent Domain Managers | 이동/청정/맵/스케줄/상태의 실제 조건 판단과 실행 | Cloud plan 전체를 재해석 |
| MCU/AMR/Wrapper | 실제 모터, 팬, 센서, 설정 제어 | 사용자 의도 판단 |
3. DeviceAgent 핵심 도메인
3.1 task/
역할:
- Cloud/Bridge에서 들어온 task/workflow 요청의 공식 입구다.
- task queue, workflow step, parallel group, cancel/compensation, event listener를 관리한다.
- 실패 reason을
reason_code,reason_params,recoverability,suggested_action,requires_cloud_decision형태로 정규화한다.
주요 근거:
| 파일 | 근거 |
|---|---|
TaskManager.java |
METHOD_SUBMIT_TASK, METHOD_SUBMIT_WORKFLOW, METHOD_GET_DEVICE_PLANNING_CONTEXT, METHOD_CLASSIFY_INGRESS를 정의한다. |
TaskManager.java |
submitTask(...)에서 enabled, validation, caller policy, state condition, resource policy, command 생성, execution mode를 처리한다. |
TaskManager.java |
submitWorkflow(...)에서 subTasks를 순차 실행하고 WORKFLOW_STEP_STARTED, WORKFLOW_STEP_COMPLETED event를 발생시킨다. |
TaskReasonContract.java |
PATH_BLOCKED, ROOM_NOT_FOUND, LOW_BATTERY, STATE_CONDITION_FAILED 등을 Cloud가 이해 가능한 reason으로 정규화한다. |
DevicePlanningContextProvider.java |
계획 전 snapshot으로 battery, map, location, cleaning, movement, task_manager, capabilities를 만든다. |
설계상 의미:
COMPLETED는 “task 1개가 정상 완료됨”이라는 로컬 진행 이벤트다.WORKFLOW_COMPLETED는 workflow 전체가 정상 완료됨이라는 로컬 완료 이벤트다.- Cloud는 정상 이벤트에 매번 LLM 판단을 하지 않는다.
- Cloud replan은
FAILED,BLOCKED, 의미 있는PAUSED, 사용자 개입, 취소, 목표 변경처럼 판단이 필요한 event에서만 열린다.
3.2 cleaning/
역할:
- 팬 시작/정지, 고정 청정, 이동 청정, 선택/AI/스캐닝 청정, 청정 transaction 상태를 담당한다.
CleaningTransaction은 현재 청정 중인지, 일시정지인지, 마지막 action과 area 정보를 제공한다.
주요 근거:
| 파일 | 근거 |
|---|---|
AirCleaningManager.java |
start(), stop(), pause(), resume()를 통해 팬 제어와 callback을 처리한다. |
CleaningTransaction.java |
isAirClearingProcessing(), isAirClearFunctionPaused(), getLastAction(), getAreaInfo()가 planning context에서 사용된다. |
MovingCleaningManager.java |
이동 청정 중 MapManager.INSTANCE.getAllSplitSpaceList(...), RobotMovementController.getInstance().onCleaningMove(...)를 사용한다. |
BaseCleaningManager.java |
청정 중 InterScheduleManager, MapManager.isEditMap() 같은 조건을 함께 본다. |
설계상 의미:
- Cloud가 “안방 청정”이라고 계획해도, 실제 청정 시작 가능 여부는
cleaning/도메인과 현재 상태가 판단해야 한다. sk_4같은 token이 있다면 token 자체가 최종 하드웨어 명령이 아니라, DeviceAgent 내부에서 기존 청정 조건 판단을 타는 task entry로 연결되어야 한다.
3.3 moving/
역할:
- 방/좌표 이동, 스테이션 복귀, 일시정지/재개, 이동 callback을 담당한다.
- 이동 완료 callback은 청정, 인터렉션 스케줄, 매핑, 일반 이동 중 어느 flow가 이동을 요청했는지에 따라 다른 callback으로 전달된다.
주요 근거:
| 파일 | 근거 |
|---|---|
MovingLocationManager.java |
move(String target_areaid)는 MapManager.INSTANCE.getAreaById(...)로 target area 좌표를 찾는다. |
MovingLocationManager.java |
move(Position)와 private move(Position, int)가 실제 AMRMotor.INSTANCE.setMoveTo(...) 또는 returnToStation()으로 이어진다. |
MovingLocationManager.java |
stop(), pause(), resume()이 이동 lifecycle을 담당한다. |
MovingLocationManager.java |
notifyArrived(...)에서 cleaning, interaction schedule, mapping, robot movement callback으로 분기한다. |
MovingController.java |
isOnStation(), return/docking 상태와 target area 상태를 제공한다. |
RobotMovementController.java |
moving status, pause 상태, priority를 제공한다. |
설계상 의미:
- 복합명령에서 “1. 거실 이동 -> 2. 안방 이동 후 청정”은 1번 이동 완료 callback 이후 2번 task를 시작해야 한다.
- 2번 task 등록 시점에 조건을 고정하면 안 된다. 실행 직전에 현재 위치/맵/이동 상태를 다시 봐야 한다.
3.4 map/
역할:
- 공간 id/name, split space, station area, map edit state, room polygon, 현재 위치 판단을 담당한다.
- map 삭제 시 관련 스케줄과 공기질 연동 설정까지 영향을 받는다.
주요 근거:
| 파일 | 근거 |
|---|---|
MapManager.java |
getStationAreaId()가 station area 기준을 제공한다. |
MapManager.java |
getAllSplitSpaceList(String areaid)가 공기질 scan/선택청정용 split space를 반환한다. |
MapManager.java |
deleteMap()에서 ScheduleDao.deleteAllSchedules()와 공기질 link setting reset을 수행한다. |
MapManager.java |
loadAreaList(...)가 encrypted map json에서 room id/name/polygon을 구성한다. |
MapManager.java |
getAreaByPosition(...), setEditMap(...), isEditMap()이 위치/편집 상태를 제공한다. |
설계상 의미:
- Cloud plan의
roomName="안방"은 DeviceAgent에서 실제roomId또는 area id로 resolve되어야 한다. - map editing 중이거나 room id가 없으면 DeviceAgent는
STATE_CONDITION_FAILED또는ROOM_NOT_FOUND류 reason으로 막아야 한다.
3.5 schedule/와 interaction/
역할:
- 등록된 스케줄의 실행 조건, 인터렉션 스케줄, action prepare/start/stop/pause/resume을 담당한다.
- 스케줄은 단순 시간 트리거가 아니라 privacy mode, mapping, night mode, lock mode, off-station, current movement priority를 모두 확인한다.
주요 근거:
| 파일 | 근거 |
|---|---|
ScheduleAlarmReceiver.java |
canExecuteSchedule(...)에서 active 여부, mapping, privacy mode, off-station, night mode, lock mode, area id validity, movement priority를 확인한다. |
ScheduleAlarmReceiver.java |
interaction schedule이면 InterScheduleManager와 연결된다. |
InterScheduleManager.java |
pause/resume/stop, move, sub-action complete callback, notify callback을 가진다. |
ScheduleDao.java |
schedule CRUD와 delete all을 담당한다. |
Schedule.java |
schedule task와 time parsing 모델을 가진다. |
설계상 의미:
- Cloud가
SCHplan을 만들더라도 실행 가능성은 DeviceAgent의 schedule 정책이 최종 판단한다. - 기존 스케줄 정책을 우회해 Cloud가 직접 이동/청정 task만 내려버리면 privacy/night/lock/mapping 조건을 빠뜨릴 수 있다.
4. get과 set의 분리
복합명령 설계에서 중요한 분리는 get과 set이다.
| 유형 | 예 | 권장 처리 |
|---|---|---|
get / 상태조회 |
배터리, 현재 위치, 맵 편집 여부, queue 상태 | DevicePlanningContextProvider 또는 domain manager snapshot으로 읽는다. 보통 task queue에 넣지 않는다. |
set / 실행명령 |
이동, 청정 시작, 청정 정지, 스케줄 등록/취소 | TaskManager.submitTask 또는 submitWorkflow로 관리한다. |
| long-running set | 방 이동 후 청정, 스케줄 기반 이동, 공기질 스캐닝 | workflow/subtask로 만들고 callback/event로 다음 step을 진행한다. |
| 실패/차단 | 경로 막힘, 방 없음, 배터리 부족, 센서 오류 | reason code를 올리고 필요 시 Cloud replan을 연다. |
따라서 “현재 공기질 알려줘” 같은 조회는 task로 만들 필요가 약하다. 반대로 “거실로 가서 청정해줘”는 이동/청정의 실행 lifecycle이 있으므로 task/workflow로 관리해야 한다.
5. 안전한 실행 모델
권장 구조:
- Cloud가
recognized_text + voice_context + device_context를 보고 plan을 만든다. - ODL step은 Cloud runtime에서
device_task_requests로 변환된다. - 온디바이스 브릿지는 요청을 DeviceAgent의
submitWorkflow또는submitTask로 전달한다. - DeviceAgent
TaskManager는 queue에 등록하되, 각 subtask 실행 시점에 기존 domain manager 조건을 탄다. - 정상 이벤트는 DeviceAgent/온디바이스가 이어서 처리한다.
- 판단이 필요한 실패 이벤트만 Cloud에 올려 replan한다.
피해야 할 구조:
- Cloud가
setAirCleanerOperation같은 내부 함수를 직접 고른다. - 온디바이스가 기존 token/조건 판단을 거치지 않고 wrapper만 호출한다.
- TaskManager가 도메인별 조건을 모른 채 함수 호출만 순서대로 실행한다.
- 모든
PROGRESS/COMPLETEDevent마다 Cloud LLM을 다시 돌린다.
6. 예시: 이동 후 청정 workflow
발화:
거실로 가서 청정하고 안방으로 이동해줘
Cloud plan:
{
"turn_mode": "multi_turn",
"steps": [
{
"id": "step_1",
"route": "ODL",
"purpose": "거실로 이동",
"output": "arrival_state"
},
{
"id": "step_2",
"route": "ODL",
"purpose": "거실 청정 시작",
"input_from": ["step_1"]
},
{
"id": "step_3",
"route": "ODL",
"purpose": "안방으로 이동",
"input_from": ["step_2"]
}
]
}
On-device request:
{
"method": "submitWorkflow",
"workflowName": "device_intent_workflow",
"source": "cloud_a2a",
"subTasks": [
{
"taskMethod": "moveToRoom",
"roomName": "거실"
},
{
"taskMethod": "startAirCleaning",
"roomName": "거실",
"dependsOnPrevious": true
},
{
"taskMethod": "moveToRoom",
"roomName": "안방",
"dependsOnPrevious": true
}
]
}
DeviceAgent 내부 실행:
TaskManager.submitWorkflow(...)가 workflow를 등록한다.- 첫 subtask 실행 직전에
moveToRoomadapter가MapManager로 room id/position을 resolve한다. MovingLocationManager.move(...)가 이동을 시작한다.- 도착 callback이 오면 subtask 1을
COMPLETED로 표시한다. - subtask 2 실행 직전에
CleaningTransaction,MapManager, device policy를 다시 확인한다. - 청정 시작이 가능하면 기존 cleaning manager를 통해 실행한다.
- 실패하면
TaskReasonContract에 맞춘 reason event를 발생시킨다.
7. 업체 전달 포인트
DeviceAgent/SoC 담당 업체에는 아래를 명확히 요청해야 한다.
| 요청 | 이유 |
|---|---|
| Cloud에서 내려온 task method와 기존 token/function handler의 1:1 또는 1:N mapping 표 | 기존 음성 조건 판단을 우회하지 않기 위해 |
| 각 task method별 실행 직전 조건 체크 위치 | 1번 task 완료 후 상태가 바뀌는 문제를 해결하기 위해 |
reason_code와 legacy error/status code mapping |
Cloud replan 판단을 안정화하기 위해 |
DevicePlanningContextProvider의 rooms/current room/battery/map 필드 보강 |
Cloud가 불가능한 plan을 처음부터 줄이기 위해 |
| workflow/subtask callback 기준 | 다음 task 시작 시점을 정확히 잡기 위해 |
| instrumented test와 dumpsys evidence | 실제 단말에서 queue/event/context가 동작하는지 확인하기 위해 |
8. 남은 공백
현재 문서화된 구조는 DeviceAgent 앱 내부 도메인 중심이다. 아직 full AOSP 관점의 init.rc, Binder service 등록, HAL/AIDL, SELinux, partition 배치까지는 검증하지 않았다.
따라서 다음 단계는 둘로 나뉜다.
- 단기: DeviceAgent task/domain adapter를 완성하고 fake/instrumented test로 workflow event를 검증한다.
- 중기: SoC/AOSP 빌드 산출물 관점에서 DeviceAgent가 어떤 partition, permission, service boundary로 배치되는지 별도 분석한다.