--- spec_doc_type: spec spec_id: runtime/edge-node-execution status: 부분 source_evidence: - type: contract path: agent-contract/inner/edge-node-runtime-wire.md notes: Edge-Node register, run stream, cancel, node command, config refresh wire 계약 - type: code path: proto/iop/runtime.proto notes: RunRequest, RunEvent, CancelRequest, NodeCommandRequest, RegisterRequest, NodeConfigPayload 원문 - type: code path: apps/edge/internal/transport/server.go notes: Edge TCP proto-socket server, node register handshake, event relay - type: code path: apps/edge/internal/service/run_dispatch.go notes: surface-neutral SubmitRun, provider tunnel dispatch, cancel request 생성 - type: code path: apps/node/internal/node/node.go notes: Node transport handler, adapter 실행, cancel, command, config refresh 처리 - type: test path: apps/edge/internal/transport/server_test.go notes: Edge transport server 단위 검증 - type: test path: apps/node/internal/node/node_test.go notes: Node 실행 처리 단위 검증 --- # 스펙: Edge-Node 실행 경로 ## 목적 Edge와 Node 사이에 현재 구현된 실행 기능을 기능 단위로 정리한다. 코드 배치 규칙이나 도메인별 작업 지침은 domain rule을 따른다. ## 기능 목록 | 기능 | 설명 | |------|------| | Node token 등록 | Node가 Edge TCP proto-socket endpoint에 연결한 뒤 `RegisterRequest.token`으로 등록한다. | | Node config payload 전달 | Edge가 token에 매칭되는 node record를 찾아 `NodeConfigPayload`를 `RegisterResponse`에 담아 내려준다. | | 등록 실패 처리 | unknown token, duplicate connection, config payload build failure를 register response와 node lifecycle event로 표현한다. | | 실행 요청 전달 | Edge service가 `SubmitRun` 요청을 `RunRequest`로 만들어 선택된 Node에 보낸다. 명시 node가 없고 연결 node가 1개면 single-node fallback을 사용한다. | | adapter 실행 | Node가 `RunRequest.adapter`로 adapter instance를 찾고 adapter `Execute`를 호출한다. admission은 adapter `Capabilities().MaxConcurrency` 기준이다. | | 실행 이벤트 스트림 | Node adapter가 낸 start, delta, reasoning_delta, complete, error, cancelled 이벤트를 `RunEvent`로 Edge에 relay한다. | | provider raw tunnel | Edge가 `ProviderTunnelRequest`를 보내면 Node가 provider HTTP/SSE response를 열고 ordered `ProviderTunnelFrame`으로 status/header/body/end/error/usage 후보를 relay한다. | | terminal event 합성 | adapter가 terminal event 없이 종료하면 Node가 terminal event를 합성한다. | | run cancel | Edge가 `CancelRequest`를 보내면 Node run manager가 active run context를 cancel한다. | | logical session 종료 | adapter가 `SessionTerminator`를 구현한 경우 `TERMINATE_SESSION`으로 session을 종료한다. 모든 adapter 공통 기능은 아니다. | | Node command | capabilities, transport status, usage status, session list, ollama API 계열 조회/제어성 command를 실행 요청과 분리해 처리한다. | | Node local run store | Node가 run id, adapter, target, session id, background, status, timestamps, error를 SQLite에 기록한다. | | Edge event fanout | Edge event bus가 run event와 node lifecycle event를 in-process subscriber에게 fanout한다. | ## 범위 - 포함: Edge-Node TCP/protobuf transport, register handshake, run/cancel/command, provider raw tunnel, Node adapter execution, Edge event bus fanout, Node local run store. - 제외: OpenAI-compatible/A2A HTTP request shape, Control Plane 운영 wire, provider-pool config refresh 상세, durable global history/audit. ## 주요 흐름 ### Node 등록 ```mermaid sequenceDiagram participant Node participant EdgeTransport as Edge transport participant NodeStore as Edge NodeStore Node->>EdgeTransport: TCP connect Node->>EdgeTransport: RegisterRequest(token) EdgeTransport->>NodeStore: token으로 NodeRecord 조회 alt token valid EdgeTransport->>EdgeTransport: NodeConfigPayload 생성 EdgeTransport-->>Node: RegisterResponse(accepted=true, config) EdgeTransport->>EdgeTransport: live registry 등록 else token invalid or duplicate EdgeTransport-->>Node: RegisterResponse(accepted=false, reason) end ``` ### 실행 요청과 이벤트 ```mermaid sequenceDiagram participant Caller participant EdgeService as Edge service participant EdgeTransport as Edge transport participant Node participant Adapter Caller->>EdgeService: SubmitRun(adapter, target, input) EdgeService->>EdgeService: Node 선택 EdgeService->>EdgeTransport: RunRequest EdgeTransport->>Node: RunRequest Node->>Node: adapter instance resolve Node->>Adapter: Execute(spec) Adapter-->>Node: RuntimeEvent(delta/start/complete) Node-->>EdgeTransport: RunEvent EdgeTransport-->>Caller: run stream ``` ### Provider raw tunnel ```mermaid sequenceDiagram participant OpenAI as Edge OpenAI surface participant EdgeService as Edge service participant Node participant Provider OpenAI->>EdgeService: SubmitProviderTunnel EdgeService->>Node: ProviderTunnelRequest Node->>Provider: HTTP/SSE request Provider-->>Node: status/header/body Node-->>EdgeService: ProviderTunnelFrame sequence EdgeService-->>OpenAI: request-bound frame stream ``` ### 취소와 session 종료 ```mermaid sequenceDiagram participant EdgeService as Edge service participant Node participant Adapter alt cancel run EdgeService->>Node: CancelRequest(CANCEL_RUN, run_id) Node->>Node: active run context cancel else terminate session EdgeService->>Node: CancelRequest(TERMINATE_SESSION, adapter, target, session_id) Node->>Adapter: TerminateSession(target, session_id) end ``` ## 계약 - `iop.edge-node-runtime-wire`: `agent-contract/inner/edge-node-runtime-wire.md` - proto 원문: `proto/iop/runtime.proto` ## 설정/데이터/이벤트 - Edge의 node source of truth는 `configs/edge.yaml`과 `packages/go/config`의 `nodes[]` 구조다. - `RunEvent`는 adapter execution stream이고, `EdgeNodeEvent`는 node lifecycle/control event다. - `ProviderTunnelFrame.body`는 OpenAI-compatible provider passthrough의 source of truth이며 `RunEvent.delta`나 Edge event bus payload로 보내지 않는다. - `ProviderTunnelFrame.usage`와 `metadata`는 sideband observation 후보이며 pure passthrough body에 합쳐지지 않는다. - Node local DB는 기본 `file:iop.db?cache=shared&mode=rwc`로 열린다. - heartbeat는 Edge와 Node transport 양쪽에서 30초 interval, 45초 wait 기준을 사용한다. ## 검증 - `go test ./apps/edge/internal/transport ./apps/edge/internal/service ./apps/edge/internal/node` - `go test ./apps/node/internal/transport ./apps/node/internal/node ./apps/node/internal/router ./apps/node/internal/adapters ./apps/node/internal/store` - `make test-e2e` - Edge-Node와 OpenAI 보조 smoke를 함께 실행한다. runtime path 변경 시 사용자 흐름 검증을 대체하지 않는다. ## 한계와 주의사항 - mTLS helper는 존재하지만 현재 Edge-Node transport 설정에는 연결되어 있지 않다. - `TERMINATE_SESSION`은 모든 adapter에 공통으로 보장되는 기능이 아니다. - Node store는 전역 query/audit API가 아니다. 상위 운영 이력은 별도 설계가 필요하다. - provider raw tunnel은 기존 socket 위 request-bound stream이다. 별도 Node stream server나 Edge의 provider direct access 경로가 아니다. ## 변경 기록 - 2026-07-07: 현재 코드, 계약, README 기준으로 bootstrap spec 작성. - 2026-07-07: 기능 목록 중심으로 축소하고 주요 흐름을 Mermaid sequence diagram으로 정리. - 2026-07-08: Provider raw tunnel 실행 흐름과 passthrough event/data 경계를 현재 계약 기준으로 반영.