← Docs hub

A2A Text E2E Console

이 페이지는 실기기 E2E 검증에서 음성 입력만 테스트용 텍스트로 대체하기 위한 콘솔이다. 목적은 STT 품질을 검증하는 것이 아니라, on-device bridge, Cloud A2A planner, DeviceAgent TaskManager, callback/replan 경계를 빠르게 반복 검증하는 것이다.

A2A Text E2E Console Flow

테스트 콘솔

Public 페이지는 안내와 진입점이다. 로컬 콘솔 열기를 누르면 local shim이 직접 제공하는 same-origin 실행 화면으로 전환된다. 실제 API 호출은 로컬 실행 화면에서만 수행하므로 Chrome의 Local Network Access 권한 팝업에 의존하지 않는다.

검증 경계

구간 처리 방식 이유
음성/STT 입력 텍스트로 대체 개발/검증 반복 속도 확보
AWS Lambda 배포 local Lambda shim 배포 지연 없이 현재 소스의 lambda_handler 검증
on-device ForegroundService 실기기 경로 Cloud request 생성, 멀티턴, bridge 동작을 실제 코드로 확인
DeviceAgent TaskManager 실기기 경로 submitWorkflow, queue, executor, callback을 실제로 확인
callback/replan 실기기 callback + local shim 정상 event와 requires_cloud_decision event를 분리 검증

실행 순서

  1. 로컬 Cloud repo에서 shim을 실행한다.
python3 -m gemini.a2a.tools.local_lambda_shim \
  --host 127.0.0.1 \
  --port 18080 \
  --device-id <device-id> \
  --adb-serial <adb-serial> \
  --console-dir "$LLMWIKI_HOME/apps/a2a-text-console" \
  --enable-adb-text \
  --validation-mode direct_gemini

현재 실기기 검증에서는 아래 값을 기준으로 둔다. 핵심은 Local shim URLOn-device Cloud API URL의 기준 주체가 다르다는 점이다.

같은 개발 PC의 브라우저에서 공개 콘솔을 연 뒤 로컬 콘솔 열기를 누르면 http://127.0.0.1:18080/console/로 이동한다. shim UI와 API가 같은 origin이므로 공개 HTTPS 페이지에서 private network HTTP API를 직접 fetch하지 않는다.

필드 설명
Local shim URL http://127.0.0.1:18080 브라우저가 호출하는 local shim 주소. 같은 PC 브라우저 기준 기본값
On-device Cloud API URL http://127.0.0.1:18080 adb reverse tcp:18080 tcp:18080 기준으로 기기 안에서 다시 호출할 Cloud API 주소
ADB serial 자동 수신 현재 UI에서는 확인용이다. shim 시작 인자 --adb-serial/console-bootstrap에서 수신한다.
Device ID 자동 수신 shim 시작 인자 --device-id를 수신한다. /text 직접 Cloud 호출용이며 on-device 전송은 기기 내부 serial을 사용한다.
Session ID a2a-text-e2e-manual 수동 E2E 재현용 session id

URL에는 http://를 포함한다. 콘솔은 스킴이 빠진 입력도 http://로 보정하지만, 수동 curl이나 다른 테스트 도구에서는 127.0.0.1:18080처럼 스킴이 빠진 값이 실패 원인이 될 수 있다.

개발용 shim은 기본적으로 bearer token을 요구하지 않는다. 대신 무인증 모드는 127.0.0.1 또는 localhost bind에서만 시작할 수 있다. /console-bootstrapADB serial, Device ID 같은 실행 정보만 제공하고 토큰을 발급하지 않는다. 외부 인터페이스에서 인증 없이 실행하려 하면 shim 시작 단계에서 거절된다.

공개 페이지의 Shim 확인은 cross-origin health fetch를 반복하지 않고 로컬 실행 화면으로 이동한다. 따라서 사이트 권한 초기화, Local Network Access 허용, 수동 shim token 입력은 필요하지 않다.

기기에서 local shim을 직접 192.168.10.6 같은 LAN 주소로 호출한다고 가정하지 않는다. 현재 검증 경로는 아래처럼 adb reverse로 닫는다.

adb -s 192.168.123.116:5555 reverse tcp:18080 tcp:18080
adb -s 192.168.123.116:5555 shell setprop persist.sys.debug.maumai.text_input_enabled 1

On-device Cloud API URL은 broadcast extra로 한 turn에 전달한다. 현재 구현은 이 값을 process 전역 override로 보관하므로 테스트 종료 후 MaumAi process를 재시작해 override를 제거해야 한다. persistent Cloud URL property를 상시 설정하면 실제 음성도 계속 local shim을 호출하므로 기본 실행 절차에서는 사용하지 않는다.

On-device Cloud API URL이 빠지면 /device-text broadcast 자체는 성공해도 기기 안에서 기존 Cloud endpoint를 호출할 수 있다. 이 경우 로컬 shim 기준의 planner/TaskManager workflow 검증이 되지 않고 “요청을 처리할 수 없습니다” 같은 fallback 응답으로 보일 수 있다.

  1. 테스트 페이지를 열고 로컬 콘솔 열기를 누른다.
https://sk-intellix-wiki.pages.dev/a2a-text-console/
-> http://127.0.0.1:18080/console/
  1. 발화를 입력하고 On-device로 텍스트 보내기를 누른다.

/device-text의 HTTP 202 Accepted는 ADB broadcast 전송이 접수됐다는 뜻이다. Planner 또는 TaskManager 성공이 아니다. 같은 request_idlambda_response가 trace에 나타나기 전에는 다음 발화를 보내지 않는다.

  1. 기기 logcat과 local shim 로그에서 아래를 확인한다.
USE_TEXT_INPUT
Cloud orchestration request context
Cloud orchestration response
device_workflow_requests
Cloud device workflow submitted
DeviceCommunicator onTaskEvent
request_kind=task_event

2026-07-24 실기기 검증에서 확인된 완료 기준:

TextInputTestReceiver -> ForegroundService USE_TEXT_INPUT
recognizedText=공간4 갔다가 공간1로 가서 청정하고 스테이션 복귀해줄래?
selectedRoutes=[ODL, ODL, ODL, ODL, ODL, ODL]
activeSkill=multi_step_device_workflow
device_workflow_requests[0].method=submitWorkflow
step_move_room_1 targetRoom=공간4 areaId=4 positionId=4
step_clean_room_1 targetRoom=공간4
step_move_room_2 targetRoom=공간1 areaId=1 positionId=1
step_clean_room_2 targetRoom=공간1
step_return_station taskMethod=returnToStation
eventName=COMPLETED
taskState=COMPLETED
workflowDelta.status=completed

2026-07-26 상대시간 예약 E2E

60분 뒤에 고정청정 시작해줘를 동일한 request_id로 두 번 전송해 다음 경계를 실기기에서 확인했다.

Cloud SCH: relative_delay_seconds=3600
Cloud case-2: trigger.relative_delay_ms=3600000
On-device: triggerAtMs = now + relativeDelayMs
DeviceAgent: method=scheduleTask, scheduleId=scheduled-4
Duplicate request: deduplicated=true, scheduleId=scheduled-4
TTS: 60분 뒤에 고정 청정 시작하도록 예약했어요.

첫 요청은 /llm/invoke 한 번과 SCHEDULED record 한 건을 만들었다. shim의 짧은 중복 차단 시간이 지난 뒤 같은 요청을 다시 보내 Cloud 추론이 한 번 더 수행돼도, DeviceAgent는 request_id로 기존 record를 반환하고 새 schedule을 만들지 않았다. 재부팅 후 getScheduledTasks로 같은 scheduleId가 복원된 것도 확인했다.

예약 조회 과정에서는 command envelope의 source=API가 record filter로 복사돼 source=CLOUD 예약을 숨기는 결함이 발견됐다. 수정 후에는 payload에 명시적 source filter가 없을 때 envelope source를 조회 조건으로 사용하지 않는다. 명시한 payload filter는 그대로 유지한다.

검증 종료 후 scheduled-3, scheduled-4cancelScheduledTask로 취소했으며, state=SCHEDULED 조회 결과가 빈 배열임을 확인했다. 자동 due scheduler property는 기본 비활성 상태로 유지했으므로 이번 검증은 등록, 영속화, 재부팅 복원, 조회, 취소, 멱등성까지의 증거이며 실제 due 실행 증거는 아니다.

직접 Cloud shim으로 보내는 버튼

Cloud shim에 직접 보내기는 on-device를 우회해 /text로 보낸다. 이 버튼은 planner/Gemini/Lambda local path만 확인할 때 사용한다. 실기기 bridge 검증에는 On-device로 텍스트 보내기를 사용한다.

Planning Trace 패널

콘솔은 local shim의 /trace를 주기적으로 조회해 현재 A2A 판단 과정을 보여준다.

확인 가능한 항목:

DEVICE CONTEXT · PLANNER SNAPSHOT은 raw DeviceAgent payload가 아니라 Cloud Planner에 전달된 allowlist projection을 표시한다. 위치·도킹, 배터리, 이동, 청정, 공기질 등급, TaskManager active task, 공간 목록, 현재 사용 가능한 capability를 확인할 수 있다. 좌표, raw prompt, unrestricted task result, reason_params 같은 내부 데이터는 trace에 복사하지 않는다.

shim은 main_router_api._compact_device_context_for_planner()와 동일한 projection을 trace에 넣는다. 따라서 이 패널에 값이 없으면 UI 마스킹으로 추정하지 않고, Planner 입력에서 해당 section이 freshness 또는 allowlist 기준으로 제외됐는지 확인해야 한다.

이 패널의 목적은 규칙을 계속 추가하는 것이 아니라, 실제 발화가 어느 경계에서 실패했는지를 분리하는 것이다.

TaskManager Live Flow

Planner 응답의 steps와 TaskManager callback의 workflow_deltaworkflow_idstep_id로 합성해 단계별 상태를 표시한다.

callback 단계 표시
STARTED workflow 실행 중
WORKFLOW_STEP_STARTED 해당 단계 pulse, 현재 단계 표시
WORKFLOW_STEP_COMPLETED 해당 단계 완료, 진행률 증가
FAILED 실패 단계와 reason 표시
CANCELLED 취소 단계 표시
COMPLETED 전체 완료, 진행률 100%

콘솔은 1.2초 주기로 shim process의 전역 trace cursor를 읽는다. Planner 응답에는 request_id/session_id가 있지만 후속 DeviceAgent callback에는 이 값이 비어 있을 수 있으므로, callback 수집 자체는 요청 필터를 사용하지 않는다. 대신 workflow 상태 합성은 workflow_id/step_id로 수행한다. 여러 batch나 기기를 같은 shim에 동시에 연결하면 event가 함께 보일 수 있으므로 현재 수동 검증은 단일 기기 기준으로 사용한다.

Token Ledger

Console은 router_usagerouter_usage_breakdown을 받아 다음을 표시한다.

TaskManager가 이동·청정·대기하는 시간 자체는 모델 token을 소비하지 않는다. 정상 callback은 deterministic workflow state update로 처리하며, failure, timeout, 사용자 판단처럼 replan 경계가 열린 경우에만 추가 모델 호출이 발생한다. 세부 실측값과 계산 기준은 TaskManager Live Monitor에서 본다.

보이는 현상 우선 확인할 곳 의미
NoneType / models 오류 local shim process env Gemini API key 없이 planner를 호출함
selected_routes=STT_NULL planner/cue/axis 발화 의미축이 낮게 잡힘
selected_routes=ODL인데 device_task_requests 없음 capability/Task contract 라우팅은 됐지만 실행 contract 생성 실패
device_workflow_blocked=ROOM_CONTEXT_REQUIRED device_context.map.rooms 현재 공간 목록이 Cloud에 전달되지 않음
device_task_requests는 있는데 기기 미동작 on-device bridge / DeviceAgent logcat Cloud contract 수신 이후 실행 문제

현재 context 조회형 발화

아래 발화는 새 기능 실행이 아니라 voice_context.device_context snapshot을 설명해야 한다.

너 공기질 데이터 뭐 가지고 있어?
나무야 지금 너 어디에 있어?

이 계열은 planner가 정상 동작하면 ODL의 현재 기기 상태 조회로 처리되는 것이 맞다. 단, 디버깅 중 planner가 보수적으로 STT_NULL을 반환해도 발화가 명확히 “현재 기기 자신/context”를 묻고 device_context가 존재하면 runtime에서 device_context_summary로 복구한다. 이 복구는 일반 공기질 질문이나 일반 대화를 keyword만으로 ODL 처리하기 위한 장치가 아니다.

SK token 기반 복합 실행

기존 on-device 기능의 사전 체크가 중요한 기능은 TaskManager 직접 taskMethod보다 legacy token step으로 전달한다.

예:

공간4로 이동해서 바이탈사인 켜줘

Cloud compiler 결과:

[
  {
    "task_type": "device_intent_step",
    "token_text": "<sk_100>(position=공간4)<sk_end>",
    "wait_policy": "completed"
  },
  {
    "task_type": "device_intent_step",
    "token_text": "<sk_45>()<sk_end>",
    "depends_on": ["step_move_room_1"],
    "wait_policy": "submitted"
  }
]

SK_45는 on-device FunctionCallHandler의 바이탈사인 분기를 타므로 배터리/스테이션/기존 청정/이동 정지 조건을 기존 제품 로직대로 검사한다.

Excel batch 확장 방향

수동 콘솔이 안정화되면 기존 A2A full-test와 같은 방식으로 Excel/CSV runner를 붙인다.

xlsx/csv row
-> /device-text
-> on-device ForegroundService
-> Cloud planner
-> TaskManager submitWorkflow
-> callback/log evidence
-> result workbook

batch runner의 산출물은 row별로 utterance, expected_family, planner_family, workflow_id, submit_status, callback_status, replan_required, log_evidence를 기록한다.

관련 문서

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