스펙들 3
탐색 1.0.2 문서
섹션 12
현재 페이지 17
1.0.2 ko public

스펙

RAWP

Current RAWP specification.

9. Edge Node API (사용자 접점 통신 규약)

본 장은 사용자가 원격지에서 UI(웹 대시보드, 모바일 앱, 챗봇 게이트웨이 등)를 통해 마스터 서버(Master Server)에 접속하여 로컬 클라이언트(Local Client)를 제어하기 위한 Northbound API를 정의한다.

아키텍처 정의 (3-Tier):

[Edge Node (User UI)] ↔ (Edge API) ↔ [Master Server] ↔ (RAWP/Southbound) ↔ [Local Client]

9.1. Edge Node 인증 및 권한 (Authentication)

엣지 노드는 마스터 서버의 로컬 클라이언트 인증 방식(Pairing Token)과 분리된 OIDC(OpenID Connect) 기반 사용자 인증 체계를 사용한다. 세부 로그인 방법(지원 프로바이더, 허용 흐름 등)은 마스터 서버가 Discovery 엔드포인트를 통해 공개하고, 엣지 노드가 이를 조회하여 협상한다. 모든 Edge API 요청은 Authorization: Bearer {access_token} 헤더를 포함해야 한다 (MUST).

9.1.1. 인증 구성 Discovery

엣지 노드는 로그인 UI를 구성하기 전에 마스터 서버의 인증 구성을 조회해야 한다 (MUST).

Endpoint: GET /v1/edge/auth/configuration (Master Server 제공, 인증 불필요)

Response (200 OK):

{
  "issuer": "String (필수, OIDC Issuer URL. 예: 'https://auth.example.com')",
  "authorization_endpoint": "String (필수, OIDC Authorization Endpoint URL)",
  "token_endpoint": "String (필수, OIDC Token Endpoint URL)",
  "userinfo_endpoint": "String (선택, OIDC UserInfo Endpoint URL)",
  "end_session_endpoint": "String (선택, OIDC End Session Endpoint URL)",
  "supported_flows": [
    "String (필수, 지원하는 OIDC 인증 흐름 목록. 아래 열거 값)"
  ],
  "supported_scopes": [
    "String (필수, 허용하는 OIDC Scope 목록. 최소 'openid' 포함)"
  ],
  "client_id": "String (필수, 엣지 노드가 사용할 OIDC Client ID)",
  "redirect_uris": ["String (필수, 허용되는 Redirect URI 패턴 목록)"]
}

supported_flows 열거 값:

설명
authorization_code Authorization Code Flow (PKCE 필수). 브라우저 기반 엣지 노드의 기본 흐름.
authorization_code_with_device Device Authorization Grant (RFC 8628). 브라우저가 없는 환경(TV, CLI 등).

마스터 서버는 최소 authorization_code를 지원해야 한다 (MUST).

9.1.2. Authorization Code Flow (PKCE)

브라우저 기반 엣지 노드의 표준 인증 흐름이다. RFC 7636(PKCE)을 필수 적용한다 (MUST).

흐름:

  1. 엣지 노드가 code_verifier(최소 43자 랜덤 문자열)를 생성하고, SHA-256 해시하여 code_challenge를 만든다.
  2. 엣지 노드가 사용자를 authorization_endpoint로 리디렉트한다:
{authorization_endpoint}?
  response_type=code
  &client_id={client_id}
  &redirect_uri={redirect_uri}
  &scope=openid {추가_scope}
  &state={csrf_state}
  &code_challenge={code_challenge}
  &code_challenge_method=S256
  1. 사용자가 인증을 완료하면, OIDC 프로바이더가 redirect_uricodestate를 반환한다.
  2. 엣지 노드가 state를 검증한 후, 마스터 서버의 토큰 교환 엔드포인트를 호출한다.

9.1.3. 토큰 교환

엣지 노드가 OIDC Authorization Code를 마스터 서버의 Access/Refresh Token으로 교환한다. 마스터 서버는 OIDC 프로바이더에 코드를 검증하고, 자체 토큰을 발급한다.

Endpoint: POST /v1/edge/auth/token (Master Server 제공)

Request:

{
  "grant_type": "String (필수, 'authorization_code')",
  "code": "String (필수, OIDC Authorization Code)",
  "redirect_uri": "String (필수, 인증 요청 시 사용한 redirect_uri와 동일해야 함)",
  "code_verifier": "String (필수, PKCE code_verifier)"
}

Response (200 OK):

{
  "access_token": "String (필수, 마스터 서버 발급 Bearer 토큰)",
  "refresh_token": "String (필수, 갱신용 토큰)",
  "token_type": "String (필수, 'Bearer')",
  "expires_in": "Number (필수, access_token 만료까지 초)",
  "user_id": "String (필수, 인증된 사용자 식별자)",
  "id_token": "String (선택, OIDC ID Token. 마스터가 전달하는 경우)"
}

에러 응답 (401 Unauthorized):

{
  "error_code": "String (필수, 'INVALID_CODE' | 'CODE_EXPIRED' | 'INVALID_REDIRECT_URI' | 'PKCE_MISMATCH')",
  "message": "String (필수, 휴먼 리더블 에러 메시지)"
}

9.1.4. 토큰 갱신 및 폐기

토큰 갱신: §3.4.4의 POST /v1/edge/auth/refresh를 사용한다.

토큰 폐기 (로그아웃): §3.4.4의 POST /v1/edge/auth/revoke를 사용한다. OIDC end_session_endpoint가 Discovery에 포함된 경우, 엣지 노드는 마스터 토큰 폐기와 함께 OIDC 세션도 종료해야 한다 (SHOULD).

§3.4.3의 Refresh Token Rotation 및 Replay 감지 규칙이 Edge 인증에도 동일하게 적용된다 (MUST).

9.2. 로컬 머신(Node) 풀 관리 및 상태 모니터링

사용자 계정에 바인딩된 로컬 클라이언트 목록과 현재 상태를 조회한다.

9.2.1. 연결된 노드 목록 조회

Endpoint: GET /v1/edge/nodes

Response (200 OK):

{
  "nodes": [
    {
      "node_id": "String (필수, 클라이언트 식별자)",
      "device_name": "String (필수, 등록 시 제공된 이름)",
      "status": "String (필수, 'online' | 'busy' | 'offline')",
      "last_seen": "String (필수, ISO 8601, 마스터 서버와 마지막 통신 시각)",
      "capabilities": [
        "String (선택, 로컬 머신이 지원하는 기능 목록. §4.1.6에서 동기화된 최신 값 반영)"
      ],
      "active_sessions_count": "Number (필수)",
      "config_versions": {
        "limits": "Number (선택, 현재 보유 중인 Resource Limits config_version)",
        "capabilities": "Number (선택, 현재 보유 중인 Capabilities config_version)"
      }
    }
  ]
}

9.2.2. 로컬 머신별 사용량 및 지표 (Metrics)

해당 노드에서 발생한 세션들의 누적/실시간 사용량을 조회한다.

Endpoint: GET /v1/edge/nodes/{node_id}/metrics

Query Parameters: ?period=today (선택, 'today', 'week', 'month')

Response (200 OK):

{
  "node_id": "String (필수)",
  "period": "String (필수)",
  "aggregated_usage": {
    "total_input_tokens": "Number",
    "total_output_tokens": "Number",
    "estimated_cost": "Number (USD 기준)",
    "total_tool_invocations": "Number"
  },
  "health": {
    "uptime_seconds": "Number",
    "last_error": "String (선택, 최근 발생한 치명적 에러)"
  }
}

9.2.3. 노드 설정 조회 (Node Configuration Lookup)

엣지 노드가 특정 로컬 머신의 현재 설정 상태를 조회한다.

Endpoint: GET /v1/edge/nodes/{node_id}/config

Response (200 OK):

{
  "node_id": "String (필수)",
  "limits": {
    "config_version": "Number (필수)",
    "effective_at": "String (필수, ISO 8601)",
    "limits": {
      "rate_limit": "Number",
      "max_frame_size": "Number",
      "reattach_window": "Number",
      "max_buffer_size": "Number",
      "buffer_overflow_policy": "String"
    }
  },
  "capabilities": {
    "config_version": "Number (필수)",
    "effective_at": "String (필수, ISO 8601)",
    "capabilities": ["String"]
  }
}

이 엔드포인트는 Pull 방식으로 최신 설정을 확인하기 위한 것이다. 실시간 Push 알림은 §9.4.4를 참조한다.

9.3. 엣지 세션(Edge Session) 라이프사이클 관리

엣지 노드는 마스터 서버를 통해 특정 로컬 머신에 새로운 세션을 생성하거나 기존 세션을 조회할 수 있다.

9.3.1. 원격 세션 생성 (Edge → Master)

사용자가 특정 로컬 머신을 선택하여 대화를 시작할 때 호출한다.

Endpoint: POST /v1/edge/nodes/{node_id}/sessions

Request:

{
  "agent_name": "String (필수, 실행할 에이전트)",
  "workspace_path": "String (선택, 작업 디렉토리)"
}

Response (201 Created):

{
  "session_id": "String (필수, UUID v4)",
  "edge_ws_ticket": "String (필수, 엣지용 WSS 연결 티켓. 1회용)",
  "status": "String (필수, 'INIT' | 'RUNNING')",
  "pinned_config_versions": {
    "limits": "Number (필수, 이 세션에 바인딩된 Resource Limits config_version)",
    "capabilities": "Number (필수, 이 세션에 바인딩된 Capabilities config_version)"
  }
}

동작 원리: 이 요청을 받은 마스터 서버는 즉시 대상 로컬 머신의 POST /v1/session/init (본 스펙 §5.1)을 호출하여 로컬 세션을 확보한 뒤 응답해야 한다.

9.3.2. 활성 세션 목록 조회

사용자 계정에 귀속된 모든 세션의 현재 상태를 조회한다.

Endpoint: GET /v1/edge/sessions

Query Parameters:

파라미터 타입 필수 설명
status String 선택 세션 상태 필터. 'INIT', 'RUNNING', 'DETACHED' 중 하나. 미지정 시 모든 상태의 세션을 반환.
node_id String 선택 특정 노드에 귀속된 세션만 필터링.

Response (200 OK):

{
  "sessions": [
    {
      "session_id": "String (필수, UUID v4)",
      "node_id": "String (필수, 세션이 실행 중인 로컬 클라이언트 식별자)",
      "agent_name": "String (필수, 실행 중인 에이전트 이름)",
      "status": "String (필수, 'INIT' | 'RUNNING' | 'DETACHED')",
      "created_at": "String (필수, ISO 8601, 세션 생성 시각)",
      "last_activity_at": "String (필수, ISO 8601, 마지막 이벤트 수신 시각)",
      "pinned_config_versions": {
        "limits": "Number (필수, 이 세션에 바인딩된 Resource Limits config_version)",
        "capabilities": "Number (필수, 이 세션에 바인딩된 Capabilities config_version)"
      }
    }
  ]
}

pinned_config_versions를 통해 엣지 노드는 각 세션이 어떤 시점의 설정으로 동작 중인지를 목록 수준에서 확인할 수 있다. 노드의 현재 config_versions(§9.2.1)와 비교하면, 세션이 최신 설정인지 이전 설정인지를 즉시 판별할 수 있다. TERMINATED 상태의 세션은 이미 종료되었으므로 목록에 포함하지 않는다 (MUST NOT). 종료된 세션의 이력 조회가 필요한 경우 별도의 세션 이력 API를 통해 제공한다.

9.4. 엣지 데이터 평면 (Edge WebSocket 통신)

엣지 노드는 발급받은 티켓을 사용하여 마스터 서버와 WSS를 연결하며, 마스터 서버는 이 연결을 대상 로컬 머신과 투명하게 중계(Transparent Proxy)한다.

Connection URI: wss://{master_host}/v1/edge/ws/stream?ticket={edge_ws_ticket}&session_id={session_id}

9.4.1. 프로토콜 투명성 (Protocol Transparency)

엣지 노드와 마스터 서버 간의 WSS 통신은 RAWP-DPS 1.0.1 규격을 완전히 동일하게 사용한다 (MUST).

엣지 노드는 본 스펙 §6의 control.* 이벤트(사용자 프롬프트, 인터랙션 응답 등)를 마스터 서버로 발송하며, 마스터는 이를 로컬 머신으로 포워딩한다.

엣지 노드는 로컬 머신이 발송한 agent.*, tool.*, session.* 이벤트를 마스터 서버를 통해 수신하여 사용자 UI에 렌더링한다.

9.4.2. 마스터 서버의 중계 및 개입 규칙

마스터 서버는 단순한 파이프 역할을 넘어 다음의 제어 책임을 가진다:

라우팅: 엣지 노드의 발신 프레임을 올바른 로컬 머신의 소켓으로 전달.

사용량 집계: 중계되는 session.usage 이벤트를 인터셉트하여 데이터베이스에 누적 저장 (§9.2.2 지표 제공용).

파일 검색 중계: control.file.search, control.file.search.cancel, session.file.candidates 이벤트는 중계 대상에 포함된다. session.file.candidatessession.usage와 달리 인터셉트 없이 단순 포워딩 대상이다.

보안 필터링: 엣지 노드가 허가되지 않은 control.prompt.request 내장 도구(e.g., 로컬 시스템 파괴성 명령어)를 전송하려 할 경우, 마스터 서버 단에서 프레임을 드롭하고 엣지 노드에 session.error를 반환해야 한다 (MUST).

9.4.3. 다중 접점 동기화 (Multi-device Synchronization)

동일한 session_id에 대해 여러 엣지 노드(예: 모바일 앱과 데스크톱 브라우저 동시 접속)가 연결을 요청할 경우, 마스터 서버는 RAWP-DPS 1.0.1 §2.4의 브로드캐스트 원칙과 동일한 정책을 적용해야 한다 (MUST).

  • 로컬 클라이언트로부터 수신한 모든 DPS 프레임(agent.*, tool.*, session.*)을 해당 세션에 연결된 모든 엣지 WSS로 브로드캐스트해야 한다 (MUST).
  • 엣지 노드가 발송한 control.* 프레임(예: control.prompt.request)도 동일 세션에 연결된 다른 모든 엣지 WSS로 중계해야 한다 (MUST). 이를 통해 엣지 A가 전송한 프롬프트를 엣지 B도 수신하여 표시할 수 있다.
  • 중계 시 message_id 기반 멱등성 처리를 수행하여 발신 엣지에 자신의 프레임이 되돌아오는 것을 방지해야 한다 (MUST).

동시 프롬프트 충돌 처리: 동일 세션에 대해 여러 엣지 노드가 동시에 control.prompt.request를 발송한 경우, 마스터 서버는 message_id 타임스탬프 기준 선착순(first-come)으로 하나만 수락하고, 후발 요청에 대해서는 RAWP-DPS 1.0.1 §7.4.1의 session.error (error_code: "CONCURRENT_PROMPT", fatal: false)를 반환해야 한다 (MUST).

9.4.4. 노드 설정 변경 Push 알림 (Node Config Change Notification)

로컬 클라이언트가 §4.1.5 또는 §4.1.6을 통해 설정을 갱신하면, 마스터 서버는 해당 노드에 연결된 모든 활성 엣지 WSS 소켓에 설정 변경 알림 프레임을 전송해야 한다 (MUST). 이 알림을 통해 엣지 노드는 UI에 반영할 설정 변경(예: capabilities 변경으로 인한 기능 목록 갱신)을 실시간으로 인지할 수 있다.

알림 프레임 구조:

이 알림은 RAWP-DPS 1.0.1의 Envelope 구조(RAWP-DPS §2)를 따르되, 세션 단위가 아닌 노드 단위의 이벤트이므로 session_idturn_id를 포함하지 않는다. 마스터 서버가 자체적으로 생성하여 발송하는 프레임이다.

{
  "v": "rawp-dps-1.0",
  "type": "node.config.changed",
  "message_id": "String (필수, UUID v4)",
  "timestamp": "String (필수, ISO 8601)",
  "payload": {
    "node_id": "String (필수, 설정이 변경된 노드의 식별자)",
    "changed_scope": "String (필수, 'limits' | 'capabilities')",
    "config_version": "Number (필수, 갱신된 스코프의 새 config_version)",
    "reason": "String (선택, 클라이언트가 갱신 요청 시 전달한 reason 값 전파)"
  }
}

엣지 노드의 처리 규칙:

  • node.config.changed 수신 시, 엣지 노드는 changed_scope에 따라 관련된 로컬 캐시를 무효화해야 한다 (MUST).
  • 상세 설정 값이 필요하면 §9.2.3의 GET /v1/edge/nodes/{node_id}/config을 Pull 호출하여 최신 값을 획득한다. 알림 프레임 자체에는 변경된 설정의 전체 값을 포함하지 않는다. 이는 알림 프레임의 크기를 최소화하고, 엣지 노드가 필요한 시점에만 상세 데이터를 가져오도록 하기 위함이다.
  • changed_scope: "capabilities" 수신 시, 엣지 UI가 기능 목록이나 에이전트 지원 기능 표시를 동적으로 갱신하는 경우, Pull 호출 후 UI를 갱신해야 한다 (SHOULD).
  • 활성 세션에는 §4.1.8에 따라 이전 설정이 유지되므로, 현재 진행 중인 세션의 동작을 변경할 필요는 없다.

전송 범위: 마스터 서버는 해당 노드(node_id)에 연결된 모든 엣지 WSS 소켓에 알림을 브로드캐스트한다. 특정 세션의 WSS가 아닌, 해당 노드와 관련된 모든 엣지 연결이 대상이다. 세션 WSS가 아직 연결되지 않았더라도, 해당 노드에 대해 다른 세션의 WSS가 활성 상태이면 해당 소켓을 통해 알림이 전달된다.

참조