367 lines
23 KiB
Markdown
367 lines
23 KiB
Markdown
# edge — Edge Execution Group Controller
|
|
|
|
여러 Node를 하나의 로컬 실행 그룹으로 묶고, IOP 내부 TCP/protobuf 프로토콜을 통해 adapter execution 요청과 이벤트 스트림을 중계한다.
|
|
|
|
Edge는 Node registry, node configuration, runtime routing, stream relay를 담당하는 백엔드 실행 그룹 컨트롤러다. 현재는 진단용 ops console과 함께 최소 OpenAI-compatible HTTP API 표면(`/v1/models`, `/v1/chat/completions`, `/v1/responses`)을 제공하며, 이 HTTP 표면은 edge service를 통해 기존 edge-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/openai`: OpenAI-compatible HTTP serving 표면. 외부 `model`은 이 경계에서 내부 `adapter + target`으로 변환된다.
|
|
- `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 계열이다.
|
|
|
|
계약 원문은 Edge-Node runtime wire는 repo root의 `agent-contract/inner/edge-node-runtime-wire.md`, Edge config/runtime refresh는 `agent-contract/inner/edge-config-runtime-refresh.md`를 기준으로 한다.
|
|
|
|
`internal/events.Bus`는 Edge 안의 in-process fanout과 bounded replay를 담당한다. 현재 replay는 늦게 붙은 console/API handler를 위한 최근 이벤트 버퍼이지 durable history가 아니며, Node local SQLite 실행 이력과 다른 책임이다. 전역 이력 저장, audit, query API는 후속 Control Plane/Client 경계에서 별도 설계한다.
|
|
|
|
## 원격 CLI adapter 개발 진단 흐름
|
|
|
|
field 사용자 기본 경로는 `iop-edge`가 제시한 bootstrap 명령으로 Node를 연결하는 흐름이다. `scripts/dev/edge.sh`와 `scripts/dev/node.sh`는 repo 내부 개발 진단 helper이며 공식 사용자 UX로 안내하지 않는다.
|
|
개발 진단의 기준은 `make test-e2e`나 smoke 통과만이 아니라, edge console에서 메시지와 command를 직접 보내 결과가 edge 화면에 표시되는지 확인하는 것이다.
|
|
구체적인 내부 진단 절차는 `agent-ops/skills/project/e2e-smoke/SKILL.md`로 모은다.
|
|
`make test-e2e` 명령은 `scripts/e2e-smoke.sh`를 실행하는 보조 smoke이며, 최소 생존 확인에는 쓸 수 있지만 완료 기준을 대체하지 않는다.
|
|
실제 외부 프로필(예: `antigravity`)을 보조 smoke로 테스트하려면 `IOP_E2E_PROFILE=antigravity make test-e2e`와 같이 환경 변수를 지정한다.
|
|
|
|
**전제 조건**: `configs/edge.yaml`의 `console.target`이 가리키는 CLI profile command가 node 호스트에서 실행 가능해야 한다. 기본 예시는 `opencode`이며, `claude`, `claude-tui`, `antigravity`, `codex`, `cline-dgx` 등으로 바꿀 수 있다.
|
|
|
|
같은 `cli` 어댑터 안에 `claude`, `claude-tui`, `antigravity`, `codex`, `opencode`, `cline` profile을 포함할 수 있다. 예를 들어 `claude`는 `claude -p` 기반 one-shot profile로 두고, `claude-tui`는 `persistent: true`, `terminal: true`, `mode: "persistent-lazy"`로 첫 요청 시 일반 Claude Code TUI 세션을 띄운다. `antigravity`는 `mode: "antigravity-print"`로 `agy --dangerously-skip-permissions --print <prompt>`를 실행하고, 같은 IOP session의 다음 요청은 `agy --conversation <conversation_id> --print <prompt>` 형태로 이어간다. `codex exec --dangerously-bypass-approvals-and-sandbox`, `cline -y --json --config /config/.cline/profiles/ollama-dgx <prompt>`처럼 다른 headless 조합도 설정할 수 있다. `opencode`는 `mode: "opencode-sse"` profile로 `opencode serve`의 HTTP/SSE 인터페이스를 사용하며, args의 `--model`, `--dangerously-skip-permissions`, `--title` 등은 그대로 유지하면 된다.
|
|
|
|
기준 출력 예시:
|
|
|
|
```text
|
|
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
|
|
state = connected
|
|
target = fake-cli
|
|
|
|
edge> /sessions
|
|
[node0-sessions] target=fake-cli session=default
|
|
sessions: 1
|
|
[0] mode=persistent target=fake-cli session=default
|
|
|
|
edge> /terminate-session
|
|
terminated session default node=test-node
|
|
```
|
|
|
|
## Edge CLI
|
|
|
|
운영 호스트에서 `iop-edge` 바이너리는 다음 명령을 제공한다.
|
|
|
|
```bash
|
|
iop-edge serve --config /etc/iop/edge.yaml
|
|
iop-edge console --config /etc/iop/edge.yaml
|
|
iop-edge version
|
|
iop-edge env
|
|
iop-edge config init
|
|
iop-edge config print --config /etc/iop/edge.yaml
|
|
iop-edge config check --config /etc/iop/edge.yaml
|
|
iop-edge config refresh --mode dry-run --config /etc/iop/edge.yaml
|
|
iop-edge config refresh --mode apply --config /etc/iop/edge.yaml
|
|
iop-edge bootstrap pack
|
|
iop-edge node register <node-id>
|
|
iop-edge nodes list
|
|
iop-edge smoke openai --model <model>
|
|
|
|
# host setup (systemd unit, user/group, data dir, config 템플릿 준비)
|
|
sudo iop-edge setup --dry-run --binary /usr/local/bin/iop-edge
|
|
sudo iop-edge setup --enable --start --binary /usr/local/bin/iop-edge
|
|
```
|
|
|
|
Edge 배포 archive는 repo root에서 `make build`로 만든다.
|
|
archive에는 `iop-edge`와 Linux/macOS/Windows arm64/amd64 Node bootstrap용 `artifacts/`가 들어가며, Edge host에서 `config init`과 `node register`를 수행해 현재 host 기준 bootstrap URL을 확정한다.
|
|
Node host는 `node register` 출력에 포함된 OS별 bootstrap 명령 원문을 그대로 실행한다. Linux/macOS는 generated `curl | bash` 명령을 사용하고, Windows native 환경은 generated PowerShell `.ps1` bootstrap과 `Start-IopNode` 함수를 사용한다. Windows에서 bash를 요구하지 않는다.
|
|
기본 bootstrap은 token, artifact URL, Edge address처럼 Node 연결에 필요한 최소값만 전달한다. provider endpoint, capacity, model mapping 같은 추가 설정은 Edge config와 register response의 기본값을 따른다.
|
|
사용자 안내용 bootstrap 명령은 실제 URL과 실제 token이 들어간 완성된 한 줄 명령으로 제공한다. README나 tracked 문서에는 token 원문을 남기지 않는다.
|
|
특정 Node target만 담긴 개발용 package는 `make build NODE_TARGETS="<goos>-<goarch>"`로 만들 수 있다. Edge만 갱신할 때는 `make build-edge && make pack-edge`, Node artifact만 갱신할 때는 `make pack-node-target NODE_TARGET=<goos>-<goarch> && make pack-edge`를 사용한다.
|
|
|
|
`setup`의 `--config` 기본값은 `/etc/iop/edge.yaml`이다. dev 단계 명령(`serve`, `console`, `config init/print/check`, `env`, `node register`)의 root persistent `--config` 기본값은 bundle-local `edge.yaml` (없을 시 executable-adjacent `edge.yaml`, 그 다음 repo dev fallback `configs/edge.yaml`)로 확인된다. 기존 설정 파일은 그대로 두며 `--overwrite-config`를 지정해야 덮어쓴다.
|
|
|
|
## Config Refresh와 Node Reconnect
|
|
|
|
실행 중 Edge config를 바꿀 때는 먼저 후보 `edge.yaml`을 저장하고 `config check`와 refresh dry-run을 통과시킨 뒤 apply한다.
|
|
|
|
```yaml
|
|
refresh:
|
|
enabled: true
|
|
listen: "127.0.0.1:19093"
|
|
```
|
|
|
|
```bash
|
|
iop-edge --config edge.yaml config check
|
|
iop-edge --config edge.yaml config refresh --mode dry-run --addr 127.0.0.1:19093
|
|
iop-edge --config edge.yaml config refresh --mode apply --addr 127.0.0.1:19093
|
|
```
|
|
|
|
refresh admin API는 operator-local 표면이다. 별도 접근 제어 계층 없이 public interface에 열지 않는다.
|
|
|
|
provider capacity, provider mapping, model catalog, Node provider 설정, Node runtime concurrency처럼 runtime mutable로 분류된 변경은 refresh apply 결과가 `applied`로 반환되고 연결된 Node에 새 config payload가 전달된다. listener address, Edge identity, bootstrap artifact dir처럼 live apply가 위험한 변경은 `restart_required`로 보고되며 조용히 적용하지 않는다. invalid YAML이나 검증 실패는 `rejected`로 끝나고 기존 routing/runtime 상태를 유지한다.
|
|
|
|
Node는 최초 연결 성공 이후 Edge transport가 끊기면 기본 `10s` 간격으로 최대 `10`회 재접속을 시도한다. Edge process 재시작이나 일시 단절이 retry window 안에서 회복되면 사용자가 bootstrap 명령을 다시 실행하지 않아도 Node가 재등록된다. retry 한계를 넘으면 Node는 session/runtime을 정리하고 종료 경로를 탄다.
|
|
|
|
## 운영 표면 경계
|
|
|
|
`iop-edge` CLI는 Control Plane이 없거나 아직 연결되지 않은 host에서도 Edge를 설치, 진단, 복구할 수 있게 하는 local/field/fallback interface다. 상시 multi-edge 운영 UI/API는 Control Plane으로 확장하고, CLI를 fleet 운영 화면으로 키우지 않는다.
|
|
|
|
- **Edge-local 필수**: `config init/check/print`, `env`, `setup`, `bootstrap pack`, `node register`, `nodes list`, `smoke`, 단일 Edge `serve`/`console`
|
|
- **Control Plane 기본**: 여러 Edge 연결/health 확인, 팀 운영 UI, 정책/권한/audit, 반복 운영/리포트, fleet-wide command
|
|
- **Shared operation**: Edge 상태 조회, node 및 후속 agent 등록 상태 조회, command 전달, event 수신, run/cancel/status, bootstrap 발급 상태
|
|
|
|
새 command나 운영 기능은 먼저 위 category 중 하나로 분류한다. CLI와 Control Plane에 모두 필요한 작업은 표면별로 registry 변경, run dispatch, command request 로직을 복제하지 않고 `apps/edge/internal/service` 같은 표면 중립 Edge operation boundary로 수렴시킨다. 후속 specialized agent enrollment, remote terminal bridge, Cline 확장도 새 command가 필요하면 이 분류를 먼저 따른다.
|
|
|
|
## 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) 조회. `claude`, `claude-tui`, `codex`, `antigravity` target만 지원. 미지원 target은 에러를 반환한다. |
|
|
| `/capabilities` | 현재 선택된 adapter의 지원 target 등 capability 조회 |
|
|
| `/sessions` | 현재 선택된 adapter의 logical session 목록 조회 |
|
|
| `/transport` | 현재 선택된 node의 transport/runtime 상태 조회 |
|
|
| `/exit` | 콘솔 종료 |
|
|
|
|
`/capabilities`와 `/transport`는 `NodeCommandResponse.result` 맵을 키 정렬 순서로 출력한다. `/sessions`는 `session.N.*` structured key가 있으면 `mode/target/session` 을 행별로 묶은 grouped output으로 표시하고, 없으면 키 정렬 출력으로 fallback한다. `/status`는 `claude`, `claude-tui`, `codex`, `antigravity` target에서만 지원된다. usage limit이 파싱되면 human-readable 형태로, 파싱에 실패하면 `parse_status` 주석과 함께 raw output을 표시한다. 미지원 target(`fake-cli` 등)은 `error: node reported error: status check not supported for target ...`을 반환한다. 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`를 사용한다.
|
|
|
|
## Edge Input Surfaces
|
|
|
|
Edge 외부 입력은 OpenAI-compatible HTTP API와 A2A JSON-RPC HTTP API 두 방식으로 정리한다. 둘 다 Edge에서 받은 외부 요청을 내부 `adapter + target` 실행으로 변환하고, 실제 실행은 `apps/edge/internal/service`와 edge-node transport를 통해 처리한다.
|
|
|
|
### OpenAI-Compatible Serving
|
|
|
|
`configs/edge.yaml`의 `openai` 섹션을 켜면 edge가 별도 HTTP listener를 열고 외부 agent가 OpenAI API 형태로 접속할 수 있다. 1차 구현은 Ollama를 주 테스트 경로로 삼는다.
|
|
|
|
이 표면은 외부 모델 클라이언트 호환을 위한 표준 경로다. Edge/Node 운영 제어, CLI logical session, background run, cancel/terminate-session, capabilities/status/session/transport command, node lifecycle event 같은 IOP 고유 기능은 OpenAI-compatible 요청에 억지로 싣지 않고 IOP native protocol(protobuf-socket) 계열에서 다룬다.
|
|
|
|
외부 프로젝트가 참조할 요청 계약 원문은 repo root의 `agent-contract/outer/openai-compatible-api.md`에 둔다. CLI agent route에서 사용할 workspace는 OpenAI request의 `metadata.workspace`에 둔다. Workspace authoring handoff의 요청 shape도 같은 계약 원문을 기준으로 한다.
|
|
|
|
```yaml
|
|
openai:
|
|
enabled: true
|
|
listen: "0.0.0.0:18081"
|
|
adapter: "ollama"
|
|
target: "qwen3.6:35b-a3b-bf16"
|
|
models:
|
|
- "qwen3.6:35b-a3b-bf16"
|
|
session_id: "cline"
|
|
timeout_sec: 300
|
|
strict_output: true
|
|
strict_stream_buffer: false
|
|
|
|
nodes:
|
|
- id: "node-dgx-01"
|
|
adapters:
|
|
ollama:
|
|
enabled: true
|
|
base_url: "http://ollama-host.local:11434"
|
|
context_size: 262144
|
|
```
|
|
|
|
`openai.target`이 비어 있으면 HTTP 요청의 `model` 값을 내부 target으로 사용한다. 값이 있으면 Cline 같은 외부 agent가 보낸 `model`과 무관하게 YAML의 target으로 고정 라우팅한다.
|
|
|
|
`openai.model_routes`를 설정하면 외부 model id별로 adapter/target을 달리 지정할 수 있다. `/v1/models`는 catalog에 등록된 model id만 노출하고, 매칭된 route는 top-level adapter/target보다 우선한다. `workspace_required: true`는 CLI agent target처럼 호출자가 `metadata.workspace`를 반드시 제공해야 하는 route를 표시한다. fallback route(catalog 미매칭)는 항상 `workspace_required: false`다.
|
|
|
|
```yaml
|
|
openai:
|
|
model_routes:
|
|
- model: "codex"
|
|
adapter: "cli"
|
|
target: "codex"
|
|
workspace_required: true
|
|
- model: "llama3"
|
|
adapter: "ollama"
|
|
target: "llama3:8b"
|
|
```
|
|
|
|
`/v1/chat/completions`는 기본 non-streaming과 streaming SSE 응답을 모두 지원한다. `/v1/responses`는 현재 non-streaming 요청만 지원한다. 두 endpoint 모두 `metadata.workspace`를 run workspace로 전달한다. `metadata`는 OpenAI 표준의 caller-defined string metadata container로 보고, IOP가 특별히 해석하는 key는 `workspace`뿐이다. `/v1/responses`의 `max_output_tokens`, `temperature`, `top_p`, `instructions`, `background`와 `/v1/chat/completions`의 `max_tokens`, `max_completion_tokens`, `temperature`, `top_p`, `think`, `reasoning_effort`, `thinking_token_budget`, `include_reasoning` 등은 OpenAI API처럼 top-level field에 둔다. `metadata.source`, `metadata.cli`, `metadata.inference`, 소비자 전용 metadata wrapper, `options`, `chat_template_kwargs`, `format`, `keep_alive` 같은 provider/Ollama 전용 request field는 지원하지 않는다.
|
|
|
|
```bash
|
|
curl -s http://127.0.0.1:18081/v1/chat/completions \
|
|
-H 'Content-Type: application/json' \
|
|
-d '{"model":"qwen3.6:35b-a3b-bf16","messages":[{"role":"user","content":"hello"}]}'
|
|
```
|
|
|
|
```bash
|
|
curl -s http://127.0.0.1:18081/v1/responses \
|
|
-H 'Content-Type: application/json' \
|
|
-d '{"model":"qwen3.6:35b-a3b-bf16","instructions":"reply briefly","input":"hello","stream":false,"background":false,"max_output_tokens":256,"temperature":0,"top_p":1,"metadata":{"request_id":"example","workspace":"/config/workspace/iop","task_id":"task-123"}}'
|
|
```
|
|
|
|
vLLM 같은 OpenAI-compatible inference server는 `openai_compat` adapter와 `provider: "vllm"` instance로 연결한다. 이 경로는 `/v1/models`, non-streaming/streaming `/v1/chat/completions`, provider header, 표준 top-level request field 전달을 지원하며, Edge의 model route alias를 실제 served model로 매핑한다.
|
|
|
|
#### Model Provider Pool 호환 방향
|
|
|
|
현재 `openai.model_routes`는 외부 model id를 단일 `adapter + target`으로 연결하는 호환 catalog다. 새 provider pool 계약에서는 `models[].id`를 OpenAI-compatible model key이자 queue/routing canonical key로 유지하고, `models[].providers`가 provider id별 실제 served model name을 가리킨다.
|
|
|
|
config/provider pool 변경 계약은 repo root의 `agent-contract/inner/edge-config-runtime-refresh.md`를 기준으로 한다.
|
|
|
|
마이그레이션 기준은 1:1 route를 단일 provider를 가진 `models[]` 항목으로 표현하는 것이다. 기존 Node provider instance 설정(`openai_compat_instances`, legacy `vllm` instance 등)은 provider id, provider type/category, served models, capacity/queue policy를 채우는 입력으로 사용하고, Edge는 선택된 provider의 served model name으로 target을 rewrite한 뒤 Node에는 기존처럼 `adapter + target` 실행 요청을 전달한다. provider pool이 구현되기 전까지 `openai.model_routes`는 fallback/compat 경로로 유지한다.
|
|
|
|
최신 provider pool schema 예시:
|
|
|
|
```yaml
|
|
# models[] 는 top-level Edge config field로, canonical routing key와
|
|
# provider pool mapping을 정의한다.
|
|
models:
|
|
- id: "qwen3.6:35b"
|
|
display_name: "Qwen 3.6 35B"
|
|
providers:
|
|
vllm-gpu: "nvidia/Qwen3.6-35B-A3B-NVFP4"
|
|
ollama-local: "qwen3.6:35b"
|
|
|
|
# nodes[].providers[] 는 provider candidate schema다.
|
|
# models[].providers 의 key 와 매칭되어야 한다.
|
|
nodes:
|
|
- id: "node-gpu-01"
|
|
alias: "gpu-node"
|
|
providers:
|
|
- id: "vllm-gpu"
|
|
type: "vllm"
|
|
category: "api"
|
|
adapter: "openai_compat"
|
|
models:
|
|
- "nvidia/Qwen3.6-35B-A3B-NVFP4"
|
|
capacity: 4
|
|
max_queue: 16
|
|
queue_timeout_ms: 30000
|
|
lifecycle_capabilities:
|
|
- "list_models"
|
|
- id: "ollama-local"
|
|
type: "ollama"
|
|
category: "local_inference"
|
|
adapter: "ollama"
|
|
models:
|
|
- "qwen3.6:35b"
|
|
capacity: 2
|
|
max_queue: 8
|
|
queue_timeout_ms: 30000
|
|
lifecycle_capabilities:
|
|
- "list_models"
|
|
- "load_model"
|
|
- "unload_model"
|
|
- "pull_model"
|
|
```
|
|
|
|
migration 예시 — 기존 route를 provider pool로 이동:
|
|
|
|
```yaml
|
|
# 기존 (legacy)
|
|
openai:
|
|
model_routes:
|
|
- model: "codex"
|
|
adapter: "cli"
|
|
target: "codex"
|
|
|
|
# 위를 provider pool로 표현하면 아래 와 같다.
|
|
models:
|
|
- id: "codex"
|
|
providers:
|
|
cli-codex: "codex"
|
|
|
|
nodes:
|
|
- id: "node-cli-01"
|
|
providers:
|
|
- id: "cli-codex"
|
|
type: "cli"
|
|
category: "cli"
|
|
adapter: "cli"
|
|
models:
|
|
- "codex"
|
|
```
|
|
|
|
### A2A Agent Input
|
|
|
|
A2A JSON-RPC HTTP API는 NomadCode Core나 외부 agent가 Edge 실행 그룹에 작업을 위임하고 `Task` 상태, artifact, cancel/polling을 공유해야 할 때 사용하는 입력 표면이다. OpenAI-compatible API가 단순 모델/chat completion 호환에 맞는 경로라면, A2A는 agent-to-agent 작업 위임과 상태 공유에 맞는 경로다.
|
|
|
|
외부 caller가 참조할 A2A 요청 계약 원문은 repo root의 `agent-contract/outer/a2a-json-rpc-api.md`를 기준으로 한다.
|
|
|
|
1차 지원 범위는 `message/send`, `tasks/get`, `tasks/cancel`이다. `message/stream`, push notification, `tasks/list`는 후속 단계에서 다룬다. 구현은 OpenAI-compatible serving과 같은 Edge input 관리 계층에서 lifecycle/config를 묶고, 내부 실행은 동일하게 `adapter + target`으로 변환한다.
|
|
|
|
#### 설정 예시
|
|
|
|
```yaml
|
|
a2a:
|
|
enabled: true
|
|
listen: "0.0.0.0:8081"
|
|
path: "/a2a"
|
|
node: "node0" # 빈 값이면 단일 연결 node 자동 선택
|
|
adapter: "cli"
|
|
target: "claude"
|
|
session_id: "a2a"
|
|
timeout_sec: 120
|
|
bearer_token: "" # 빈 값이면 auth 비활성화
|
|
```
|
|
|
|
#### 지원 메서드
|
|
|
|
| 메서드 | 설명 |
|
|
|--------|------|
|
|
| `message/send` | 실행 요청. `configuration.blocking=true`(기본)이면 완료까지 대기 후 최종 Task 반환. `false`이면 working Task를 즉시 반환하고 background 수집. |
|
|
| `tasks/get` | task ID로 현재 Task 상태/artifact/history 조회. |
|
|
| `tasks/cancel` | 실행 중인 Task에 cancel 요청. `CANCEL_ACTION_CANCEL_RUN`을 node에 전송. |
|
|
|
|
#### Agent card
|
|
|
|
`GET /.well-known/agent.json`으로 최소 agent metadata를 제공한다.
|