iop/apps/edge/README.md
toki 92042bb2a3 feat: edge node registry, opsconsole, CLI persistent, and e2e smoke updates
- Refactor edge node registry and store for improved management
- Update opsconsole console, events, and status components
- Enhance edge service and transport layers
- Improve CLI persistent adapter and output filter
- Update e2e smoke test script
- Update project and testing domain rules
- Update Makefile and documentation
2026-05-19 09:39:58 +09:00

9.5 KiB

edge — Edge Execution Group Controller

여러 Node를 하나의 로컬 실행 그룹으로 묶고, IOP 내부 TCP/protobuf 프로토콜을 통해 adapter execution 요청과 이벤트 스트림을 중계한다.

Edge는 현재 단계에서 OpenAI-compatible HTTP API gateway가 아니라 Node registry, node configuration, runtime routing, stream relay를 검증하는 백엔드 실행 그룹 컨트롤러다. 외부 HTTP 호환 계층은 node/transport 경계가 안정화된 뒤 별도 표면으로 추가한다.

현재 상태: 초기 구현 node 등록/레지스트리/transport와 edge 콘솔 기반 수동 통신 테스트가 구현되어 있다.

내부 경계

edge-local ops console은 최종 API가 아니라 diagnostic surface다. ops console의 / 명령은 직접 transport를 다루지 않고 apps/edge/internal/service를 호출한다. 이후 HTTP/API handler가 추가되면 같은 service를 호출하고, ops console은 필요하면 수동 테스트 도구로만 남긴다.

ops console은 edge-local diagnostic surface이고, HTTP/API는 central/remote management surface다.

현재 edge 내부 흐름은 다음처럼 나뉜다.

  • internal/transport: node TCP/protobuf 연결, register handshake, protobuf message 수신
  • internal/node: node registry와 사전 등록 node store
  • internal/service: SubmitRun, TerminateSession, UsageStatus, ListNodes, ResolveNode
  • internal/events: RunEvent, EdgeNodeEvent in-process publish/subscribe fanout
  • cmd/edge: serve/console CLI 진입점과 console 출력 포맷

실행 요청과 이벤트는 같은 TCP 연결을 공유하지만, 메시지 타입과 내부 파이프라인은 분리한다. RunRequest, CancelRequest, NodeCommandRequest는 edge가 node에 보내는 command/request 계열이고, RunEvent, EdgeNodeEvent는 node와 edge 내부에서 발생한 event 계열이다.

원격 CLI adapter bin shell 사용자 흐름 검증

사용자 실행 파이프라인 검증의 기준은 make test-e2e나 smoke 통과가 아니라, 사람이 하듯이 bin/edge.shbin/node.sh를 각각 실행하고 edge console에서 메시지와 command를 직접 보내 결과가 edge 화면에 표시되는지 확인하는 것이다. make test-e2e 명령은 scripts/e2e-smoke.sh를 실행하는 보조 smoke이며, 최소 생존 확인에는 쓸 수 있지만 완료 기준을 대체하지 않는다. 실제 외부 프로필(예: gemini)을 보조 smoke로 테스트하려면 IOP_E2E_PROFILE=gemini make test-e2e와 같이 환경 변수를 지정한다.

수동으로 실행하려면 아래 과정을 따른다.

bin/edge.sh는 edge 서버를 열고 입력 프롬프트를 제공한다. bin/node.sh는 원격 edge 주소로 접속해 등록한 뒤, edge에서 보낸 RunRequestadapter + target 실행으로 처리한다. 테스트 파라미터는 configs/edge.yaml, configs/node.yaml에 하드코딩한다.

전제 조건: configs/edge.yamlconsole.target이 가리키는 CLI profile command가 node 호스트에서 실행 가능해야 한다. 기본 예시는 opencode이며, claude, claude-tui, gemini, codex, cline-dgx 등으로 바꿀 수 있다.

같은 cli 어댑터 안에 claude, claude-tui, gemini, codex, opencode, cline profile을 포함할 수 있다. 예를 들어 claudeclaude -p 기반 one-shot profile로 두고, claude-tuipersistent: true, terminal: true, mode: "persistent-lazy"로 첫 요청 시 일반 Claude Code TUI 세션을 띄운다. gemini --approval-mode yolo -p <prompt>, codex exec --dangerously-bypass-approvals-and-sandbox, cline -y --json --config /config/.cline/profiles/ollama-dgx <prompt>처럼 headless 조합도 설정할 수 있다. opencodemode: "opencode-sse" profile로 opencode serve의 HTTP/SSE 인터페이스를 사용하며, args의 --model, --dangerously-skip-permissions, --title 등은 그대로 유지하면 된다.

실행 순서:

  1. edge 호스트에서 configs/edge.yamlserver.listen, nodes[].token을 확인한다. 예시 설정은 console.adapter=cli, console.target=opencode, console.session_id=default를 사용한다.
  2. node 호스트에서 configs/node.yamltransport.edge_addr를 edge 호스트 주소로, transport.token을 edge token과 같게 맞춘다.
  3. edge 호스트의 9090/tcp 포트를 node 호스트에서 접근 가능하게 연다.
  4. edge 호스트에서 ./bin/edge.sh
  5. node 호스트에서 ./bin/node.sh — edge 포트가 열릴 때까지 최대 30초 기다린 뒤, edge에서 받은 입력을 선택된 adapter + target으로 실행한다.
  6. edge 콘솔에서 /nodes로 node 등록을 확인한다.
  7. (선택 사항) node가 여러 대일 경우 /node <id|alias>로 대상을 선택한다. 1대일 경우 자동 선택된다.
  8. edge 콘솔의 edge> 프롬프트에 메시지를 입력한다.
  9. 각 메시지마다 [edge] sent, [node{index}-evt] start, 비어 있지 않은 [node{index}-msg], [node{index}-evt] complete가 edge 화면에 표시되는지 확인한다.
  10. node 로컬 출력에 생성된 [node-message] payload가 edge console의 [node{index}-msg] 출력에 모두 표시되었는지 확인한다. complete event만으로 정상 판정하지 않는다.
  11. 같은 session에서 두 번째 메시지를 보내 같은 흐름이 다시 표시되는지 확인한다.
  12. edge 콘솔에서 /capabilities, /transport, /sessions 등 command를 입력하고 [node-{alias}-<command>] 결과가 edge 화면에 도착하는지 확인한다. persistent profile이면 /terminate-session도 확인한다.
  13. edge 콘솔에서 /exit 또는 quit로 종료한다.

기준 출력 예시:

edge> /nodes
  test-node (test-node)

edge> Convert token iop_manual_one and reply only with converted token
[edge] sent run_id=manual-... node=test-node adapter=cli target=fake-cli session=default background=false
[node0-evt] start run_id=manual-...
[node0-msg] IOP_MANUAL_ONE_OK
[node0-msg] IOP_MANUAL_ONE_TAIL
[node0-evt] complete run_id=manual-... detail="idle-timeout"

edge> Convert token iop_manual_two and reply only with converted token
[edge] sent run_id=manual-... node=test-node adapter=cli target=fake-cli session=default background=false
[node0-evt] start run_id=manual-...
[node0-msg] IOP_MANUAL_TWO_OK
[node0-msg] IOP_MANUAL_TWO_TAIL
[node0-evt] complete run_id=manual-... detail="idle-timeout"

edge> /capabilities
[node0-capabilities] target=fake-cli session=default
  adapter = cli
  max_concurrency = 4
  targets = fake-cli

edge> /transport
[node0-transport] target=fake-cli session=default
  adapter = cli
  connected = true
  node_id = test-node
  session_id = default
  target = fake-cli

edge> /sessions
[node0-sessions] target=fake-cli session=default
  count = 1
  sessions = persistent:fake-cli/default

edge> /terminate-session
terminated session default node=test-node

Console 명령

명령 설명
/nodes 연결된 node 목록 확인. 선택된 node는 *로 표시됨.
/node <id|alias> 요청을 보낼 명시적 node 선택
/session <id> 현재 console이 사용할 logical session 변경
/background on|off background 실행 모드 토글 (on: 응답 기다리지 않음)
/terminate-session 현재 adapter/target/session_id의 worker process 종료
/status 현재 선택된 target/profile의 사용량(Usage Status) 조회
/capabilities 현재 선택된 adapter의 지원 target 등 capability 조회
/sessions 현재 선택된 adapter의 logical session 목록 조회
/transport 현재 선택된 node의 transport/runtime 상태 조회
/exit 콘솔 종료

/capabilities, /sessions, /transportNodeCommandResponse.result 맵을 그대로 키 정렬 순서로 출력한다. adapter가 명령을 지원하지 않거나 응답을 비워둔 경우 명시적인 unsupported / empty-payload 메시지가 출력된다.

멀티포인트 라우팅 (Multi-Point Routing)

edge는 여러 대의 node가 동시에 연결된 환경을 지원한다.

  • 명시적 선택: /node <alias> 또는 /node <node_id> 명령으로 특정 node를 고정할 수 있다.
  • Single-node Fallback: 연결된 node가 정확히 1개일 때는 선택 없이도 해당 node가 자동 지정된다.
  • Ambiguous Error: node가 2개 이상일 때 node 선택 없이 메시지를 보내면 에러가 발생하며 선택을 요구한다.
  • Node-aware Events: 모든 이벤트와 메시지 출력에 [node-{alias}-...] 접두어가 붙어 출처를 식별할 수 있다.
  • Lifecycle Events: node 등록/연결 해제는 실행 스트림과 분리된 EdgeNodeEvent로 인식하며, 콘솔에서는 connected/disconnected 이벤트와 reason을 출력한다.

Transport 1개 · Logical Session 여러 개

edge-node transport 연결은 node id당 1개 TCP 연결만 유지한다. 그 연결 위에서 edge는 session_id를 지정해 node의 cli adapter가 관리하는 개별 worker process에 접근한다. 같은 codex profile이라도 session_id가 다르면 독립적인 장수 process다.

  • cancel run: 현재 run 중단, session process 유지
  • terminate session: session process 명시 종료 (/terminate-session 또는 CancelAction_TERMINATE_SESSION)

프롬프트 없이 TCP/protobuf edge 서버만 실행하려면 기존처럼 go run ./apps/edge/cmd/edge serve -c configs/edge.yaml를 사용한다.

bin/node.sh의 edge 대기 시간은 IOP_NODE_WAIT_TIMEOUT, 확인 간격은 IOP_NODE_WAIT_INTERVAL, 접속 주소는 IOP_EDGE_ADDR 환경 변수로 임시 override할 수 있다.