스펙들 3
탐색 1.0.3 문서
섹션 12
현재 페이지 22
1.0.3 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)API Key 두 가지 인증 방식을 지원하며, 세부 구성은 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. OIDC 흐름 지원 시 필수)",
  "authorization_endpoint": "String (조건부 필수, OIDC Authorization Endpoint URL. OIDC 흐름 지원 시 필수)",
  "token_endpoint": "String (필수, 토큰 교환 Endpoint URL)",
  "userinfo_endpoint": "String (선택, OIDC UserInfo Endpoint URL)",
  "end_session_endpoint": "String (선택, OIDC End Session Endpoint URL)",
  "supported_edge_auth_methods": [
    "String (필수, 지원하는 인증 흐름 목록. 아래 열거 값)"
  ],
  "supported_scopes": [
    "String (조건부 필수, 허용하는 OIDC Scope 목록. OIDC 흐름 지원 시 필수, 최소 'openid' 포함)"
  ],
  "client_id": "String (조건부 필수, 엣지 노드가 사용할 OIDC Client ID. OIDC 흐름 지원 시 필수)",
  "redirect_uris": [
    "String (조건부 필수, 허용되는 Redirect URI 패턴 목록. OIDC 흐름 지원 시 필수)"
  ],
  "api_key_endpoint": "String (조건부 필수, API Key 인증 엔드포인트 URL. api_key 흐름 지원 시 필수)"
}

supported_edge_auth_methods 열거 값:

설명
authorization_code Authorization Code Flow (PKCE 필수). 브라우저 기반 엣지 노드의 기본 흐름.
authorization_code_with_device Device Authorization Grant (RFC 8628). 브라우저가 없는 환경(TV, CLI 등).
api_key API Key 기반 인증. 사전 발급된 API Key로 일회성 토큰을 발급받아 인증하는 흐름 (§9.1.5).

마스터 서버는 최소 authorization_code 또는 api_key 중 하나를 지원해야 한다 (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.1.5. API Key 인증 (API Key Authentication)

OIDC 프로바이더 없이 사전 발급된 API Key로 인증하는 흐름이다. 서버 간 통신, 자동화 파이프라인, CLI 도구 등 브라우저 기반 OIDC 흐름이 적합하지 않은 환경에서 사용한다.

사전 조건: API Key는 마스터 서버의 관리 인터페이스 또는 별도 채널을 통해 사전 발급된다. API Key 발급 절차는 본 프로토콜의 범위 밖이며, 마스터 서버의 구현에 따른다.

인증 흐름:

  1. 엣지 노드가 API Key를 사용하여 **일회성 인증 토큰(one-time token)**을 요청한다.
  2. 마스터 서버가 API Key를 검증하고, 단기 유효(최대 60초)의 일회성 토큰을 발급한다.
  3. 엣지 노드가 일회성 토큰을 마스터 서버의 토큰 교환 엔드포인트에 제출하여 access_token/refresh_token을 발급받는다.
  4. 이후 표준 Bearer 토큰 인증 및 §3.4.3의 갱신 규칙을 따른다.

Step 1: 일회성 토큰 발급

Endpoint: POST {api_key_endpoint} (Discovery의 api_key_endpoint 참조)

Request:

{
  "api_key": "String (필수, 사전 발급된 API Key)"
}

Response (200 OK):

{
  "one_time_token": "String (필수, 일회성 인증 토큰. 최소 64자 랜덤 문자열)",
  "expires_in": "Number (필수, 토큰 유효 기간. 초 단위, 최대 60)"
}

에러 응답 (401 Unauthorized):

{
  "error_code": "String (필수, 'INVALID_API_KEY' | 'API_KEY_EXPIRED' | 'API_KEY_REVOKED')",
  "message": "String (필수, 휴먼 리더블 에러 메시지)"
}

일회성 토큰 규칙:

  • 일회성 토큰은 1회 사용 후 즉시 무효화해야 한다 (MUST). 사용 여부와 관계없이 expires_in 경과 후 만료된다.
  • 마스터 서버는 동일 API Key에 대해 동시에 유효한 일회성 토큰을 최대 1개로 제한해야 한다 (MUST). 새 일회성 토큰 발급 시 기존 미사용 토큰은 즉시 무효화한다.
  • 일회성 토큰은 전송 중 탈취를 방지하기 위해 TLS(HTTPS) 환경에서만 발급해야 한다 (MUST).

Step 2: 토큰 교환

Endpoint: POST /v1/edge/auth/token (§9.1.3과 동일 엔드포인트)

Request:

{
  "grant_type": "String (필수, 'one_time_token')",
  "token": "String (필수, Step 1에서 발급받은 일회성 토큰)"
}

Response (200 OK):

{
  "access_token": "String (필수, 마스터 서버 발급 Bearer 토큰)",
  "refresh_token": "String (필수, 갱신용 토큰)",
  "token_type": "String (필수, 'Bearer')",
  "expires_in": "Number (필수, access_token 만료까지 초)",
  "user_id": "String (필수, API Key에 바인딩된 사용자 식별자)"
}

에러 응답 (401 Unauthorized):

{
  "error_code": "String (필수, 'INVALID_TOKEN' | 'TOKEN_EXPIRED' | 'TOKEN_ALREADY_USED')",
  "message": "String (필수, 휴먼 리더블 에러 메시지)"
}

발급된 access_token/refresh_token은 OIDC 흐름으로 발급된 토큰과 동일한 권한 및 갱신 규칙(§9.1.4, §3.4.3)을 따른다.

보안 고려사항:

  • API Key는 장기 유효 자격 증명이므로, 클라이언트 측에서 안전하게 저장해야 한다 (MUST). 환경 변수, 시크릿 매니저, 암호화된 설정 파일 등 일반 텍스트 노출을 방지하는 저장 방식을 사용한다.
  • 마스터 서버는 API Key 단위로 Rate Limiting을 적용해야 한다 (MUST). §7.3의 Rate Limiting 규칙을 따르되, 일회성 토큰 발급 엔드포인트에는 추가적으로 분당 최대 10회의 요청 제한을 권장한다 (SHOULD).
  • API Key가 유출된 것으로 판단되면, 마스터 서버는 해당 API Key로 발급된 모든 토큰(일회성 토큰, access_token, refresh_token)을 즉시 무효화할 수 있어야 한다 (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.2.4. 노드 에이전트 목록 조회 (Node Agent List)

엣지 노드가 특정 로컬 머신의 에이전트 목록을 마스터 서버를 통해 조회한다.

Endpoint: GET /v1/edge/nodes/{node_id}/agents (Master Server 제공)

Response (200 OK):

{
  "node_id": "String (필수)",
  "agents": ["Object (§4.3의 에이전트 스키마와 동일)"]
}

마스터 서버는 §4.3.1의 에이전트 동기화 프로토콜을 통해 캐시한 에이전트 목록을 반환한다. 캐시가 존재하지 않거나 마스터가 최신 정보를 확보해야 한다고 판단하면, 대상 클라이언트의 GET /v1/agents(§4.3)를 호출하여 갱신한 후 응답해야 한다 (MUST).

에러: 해당 node_id의 노드가 존재하지 않거나 offline 상태이면 404 Not Found를 반환한다.

9.2.5. 노드 세션 목록 조회 (Node Session List)

엣지 노드가 특정 로컬 머신의 세션 목록을 마스터 서버를 통해 조회한다.

Endpoint: GET /v1/edge/nodes/{node_id}/sessions (Master Server 제공)

Response (200 OK):

{
  "node_id": "String (필수)",
  "sessions": ["Object (§5.5의 세션 스키마와 동일)"]
}

마스터 서버는 §5.5의 세션 동기화 프로토콜을 통해 캐시한 해당 노드의 세션 목록을 반환한다. 캐시가 존재하지 않거나 마스터가 최신 정보를 확보해야 한다고 판단하면, 대상 클라이언트의 GET /v1/sessions(§5.5)를 호출하여 갱신한 후 응답해야 한다 (MUST).

§9.3.2와의 차이: §9.3.2(GET /v1/edge/sessions)는 사용자 계정 기준으로 모든 노드에 걸친 전체 세션을 조회하는 반면, 본 엔드포인트는 특정 노드 기준으로 해당 머신의 세션(로컬 세션 포함)을 조회한다.

에러: 해당 node_id의 노드가 존재하지 않거나 offline 상태이면 404 Not Found를 반환한다.

9.2.6. 노드 파일시스템 브라우징 (Node Filesystem Browsing)

엣지 노드가 특정 로컬 머신의 파일시스템을 마스터 서버를 통해 탐색한다. 세션 생성(§9.3.1) 전 workspace_path 선택에 사용한다.

Endpoint: POST /v1/edge/nodes/{node_id}/fs/browse (Master Server 제공)

Request: §4.5의 Request 스키마와 동일하다.

Response (200 OK):

{
  "node_id": "String (필수)",
  "agent_id": "String (필수)",
  "base_path": "String (필수, 루트 모드 시 빈 문자열)",
  "os_type": "String (필수, 'unix' | 'windows')",
  "entries": ["Entry (§4.5의 Entry 스키마와 동일)"],
  "truncated": "Boolean (필수)",
  "total_entries_count": "Number (선택)"
}

마스터 서버는 대상 클라이언트의 POST /v1/fs/browse(§4.5)로 요청을 투명하게 프록시한다. 클라이언트가 반환한 4xx 에러는 그대로 패스스루한다.

에러:

HTTP 상태 error_code 조건
400/403/404 (§4.5 동일) 클라이언트 에러 패스스루
404 NODE_NOT_FOUND 노드 미존재
404 NODE_OFFLINE 노드 오프라인
502 CLIENT_ERROR 클라이언트 5xx 에러
504 CLIENT_TIMEOUT 클라이언트 응답 타임아웃

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

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

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

사용자가 특정 로컬 머신을 선택하여 대화를 시작할 때 호출한다. workspace_path 선택을 위해 §9.2.6의 파일시스템 브라우징을 사전에 사용할 수 있다.

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

Request:

{
  "agent_id": "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_id": "String (필수, 실행 중인 에이전트 식별자)",
      "status": "String (필수, 'INIT' | 'RUNNING' | 'DETACHED')",
      "created_at": "String (필수, ISO 8601, 세션 생성 시각)",
      "last_activity_at": "String (필수, ISO 8601, 마지막 이벤트 수신 시각)",
      "total_turns": "Number (필수, 해당 세션의 총 Turn 수)",
      "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). 종료된 세션의 이력 조회가 필요한 경우 §9.3.3의 턴 히스토리 API를 사용한다.

9.3.3. 세션 턴 히스토리 조회 (Session Turn History)

기존 세션의 대화 이력을 Turn 단위로 페이지네이션하여 조회한다. RAWP-CRS 1.0.1 §2.6(대화 이력 점진적 로딩)에서 클라이언트가 이전 Turn을 점진적으로 로딩할 때 사용한다.

Endpoint: GET /v1/edge/sessions/{session_id}/turns

Query Parameters:

파라미터 타입 필수 설명
limit Number 선택 한 번에 반환할 최대 Turn 수. 기본값 10, 최대 100. 클라이언트의 CRS §2.6.1 N 값과 동일하게 설정한다 (SHOULD).
before String 선택 커서 기반 페이지네이션. 이 값보다 이전의 Turn을 반환한다. 미지정 시 가장 최신 Turn부터 반환한다. §9.3.2의 total_turns로 전체 수를 확인할 수 있다.

Response (200 OK):

{
  "session_id": "String (필수, UUID v4)",
  "turns": [
    {
      "turn_id": "String (필수, Turn 식별자)",
      "turn_index": "Number (필수, 0부터 시작하는 Turn 순서 인덱스)",
      "started_at": "String (필수, ISO 8601, Turn 시작 시각)",
      "ended_at": "String (선택, ISO 8601, Turn 종료 시각. 진행 중이면 null)",
      "user_message": {
        "text": "String (필수, 사용자 입력 텍스트)",
        "file_references": ["Object (선택, 파일 참조 목록)"]
      },
      "frames": [
        "Object[] (필수, 해당 Turn 내 모든 DPS 프레임의 배열. 각 요소는 RAWP-DPS 1.0.1 Envelope 전체)"
      ]
    }
  ],
  "pagination": {
    "has_more": "Boolean (필수, 이전 Turn이 더 존재하는지 여부)",
    "next_cursor": "String (선택, 다음 요청의 before 파라미터에 사용할 커서. has_more가 true일 때 포함)",
    "total_turns": "Number (필수, 해당 세션의 총 Turn 수)"
  }
}

Turn 정렬: turns 배열은 최신 Turn이 먼저 오는 역순(descending)으로 정렬된다 (MUST). 클라이언트는 이를 역순으로 렌더링하여 가장 오래된 Turn이 상단에, 최신 Turn이 하단에 위치하도록 한다.

에러 응답:

상태 코드 조건
404 Not Found 해당 session_id의 세션이 존재하지 않거나 권한이 없는 경우.
400 Bad Request limit가 범위를 초과하거나, before 커서가 유효하지 않은 경우.

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.searchcontrol.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 변경으로 인한 기능 목록 갱신)을 실시간으로 인지할 수 있다.

알림 프레임 구조:

이 알림은 DPS Envelope(RAWP-DPS 1.0.1 §2)과 독립된 Edge 전용 알림 프레임이다. 세션 단위가 아닌 노드 단위의 이벤트이므로 DPS Envelope의 session_id, turn_id, v 필드를 사용하지 않는다. 마스터 서버가 자체적으로 생성하여 엣지 WSS로 발송한다.

{
  "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 값 전파)"
  }
}

엣지 노드는 type 필드로 이 프레임을 DPS 프레임과 구분한다. DPS 프레임은 항상 v 필드가 존재하며, Edge 전용 알림 프레임은 v 필드가 없다.

엣지 노드의 처리 규칙:

  • 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가 활성 상태이면 해당 소켓을 통해 알림이 전달된다.

참조