- Archive completed subtask plans/code reviews (04, 05+03,04, 07+03) - Add provider_pool_admission_test.go - Update edge config types, load, catalog validation - Update runtime, config refresh, service layers for admission - Update test docs and inventory - Update provider scheduling, resolution, tunnel, status modules
381 lines
14 KiB
YAML
381 lines
14 KiB
YAML
edge:
|
|
id: "edge-example"
|
|
name: "Example Edge"
|
|
|
|
server:
|
|
listen: "0.0.0.0:9090"
|
|
# advertise_host is the host other components (Node bootstrap, OpenAI client)
|
|
# use to reach this edge. Empty means resolve automatically from interfaces.
|
|
advertise_host: ""
|
|
|
|
# bootstrap is the artifact/bootstrap channel iop-edge can render in
|
|
# bootstrap commands and `env` output. Leave artifact_base_url empty until a
|
|
# field channel is provisioned.
|
|
bootstrap:
|
|
artifact_base_url: ""
|
|
|
|
tls:
|
|
enabled: false
|
|
|
|
logging:
|
|
level: "info"
|
|
pretty: true
|
|
# path is the edge log file. Empty falls back to <binary-dir>/logs/edge.log
|
|
# for the bundled dev binary; explicit values win.
|
|
path: ""
|
|
|
|
metrics:
|
|
port: 19092
|
|
|
|
# control_plane connects this Edge to a Control Plane instance.
|
|
# Set enabled: true and wire_addr to the Control Plane TCP endpoint to
|
|
# activate the outbound connector. Leave enabled: false (default) for
|
|
# standalone / local-only Edge deployments.
|
|
control_plane:
|
|
enabled: false
|
|
wire_addr: ""
|
|
reconnect_interval_sec: 5
|
|
|
|
# refresh enables the Edge-local admin API used by `iop-edge config refresh`.
|
|
# Keep it loopback-only unless an operator-specific access control layer is added.
|
|
refresh:
|
|
enabled: false
|
|
listen: "127.0.0.1:19093"
|
|
|
|
# Requests with an estimated input token count at or above this value are
|
|
# classified as long-context for admission policy.
|
|
long_context_threshold_tokens: 100000
|
|
|
|
# provider_pool is the canonical, shared queue policy owner for every provider
|
|
# candidate in the pool. Legacy per-provider max_queue/queue_timeout_ms are
|
|
# compatibility fields only; once provider_pool is set, those legacy values
|
|
# are ignored by effective policy resolution.
|
|
provider_pool:
|
|
max_queue: 16
|
|
queue_timeout_ms: 30000
|
|
|
|
a2a:
|
|
enabled: false
|
|
listen: "0.0.0.0:8081"
|
|
path: "/a2a"
|
|
node: ""
|
|
adapter: "cli"
|
|
session_id: "a2a"
|
|
timeout_sec: 120
|
|
bearer_token: ""
|
|
|
|
openai:
|
|
enabled: false
|
|
listen: "0.0.0.0:18081"
|
|
bearer_token: ""
|
|
# principal_tokens maps IOP bearer-token-operation identities to hashed
|
|
# OpenAI-compatible bearer tokens. Raw tokens are never stored here; only
|
|
# a SHA-256 hash (lowercase hex, 64 chars) of each issued token is kept.
|
|
# When set, callers authenticate via hash match against this list; the
|
|
# legacy single bearer_token above still works as an unmapped fallback.
|
|
# Example (values below are illustrative hashes, not real tokens):
|
|
# principal_tokens:
|
|
# - token_ref: "iop-tok-alice"
|
|
# token_hash_sha256: "<sha256 hex of the issued token>"
|
|
# principal_ref: "user:alice"
|
|
# principal_alias: "alice"
|
|
principal_tokens: []
|
|
# provider_auth forwards a caller-supplied raw provider token to the selected
|
|
# OpenAI-compatible provider tunnel. The raw token is read only from the
|
|
# request header and must not be stored in config, docs, or logs.
|
|
provider_auth:
|
|
enabled: false
|
|
# Defaults when enabled:
|
|
# from_header: "X-IOP-Provider-Authorization"
|
|
# target_header: "Authorization"
|
|
# scheme: "Bearer"
|
|
# required: true
|
|
# The selected provider determines the execution path: OpenAI-compatible
|
|
# providers use passthrough, while Ollama/CLI/native providers use normalized
|
|
# execution. Caller metadata does not select the route or response shape.
|
|
node: ""
|
|
adapter: "ollama"
|
|
target: ""
|
|
models: []
|
|
# Legacy/compatibility model_routes (discouraged for new deploys).
|
|
# model_routes was the adapter/target route catalog that mapped external model
|
|
# ids to adapter + target. It is superseded by the provider-pool approach:
|
|
# 1. Define canonical routing keys with models[].
|
|
# 2. Declare provider candidates with nodes[].providers[].
|
|
# 3. Link them via models[].providers[provider_id] = served_model.
|
|
# For details see the Provider-pool section below.
|
|
# This block is a backward-compat fallback only. New deploys should use
|
|
# top-level models[] + nodes[].providers[].
|
|
session_id: "openai"
|
|
timeout_sec: 120
|
|
strict_output: true
|
|
strict_stream_buffer: false
|
|
|
|
# === Provider-pool (models[] / nodes[].providers[]) — recommended ===
|
|
# Top-level models[] defines canonical routing keys and their provider-pool mapping.
|
|
# Each entry id is the external model id; providers map maps provider id → served model.
|
|
#
|
|
# Example:
|
|
# models:
|
|
# - id: "qwen3.6:35b"
|
|
# display_name: "Qwen 3.6 35B"
|
|
# context_window_tokens: 262144
|
|
# providers:
|
|
# vllm-gpu: "nvidia/Qwen3.6-35B-A3B-NVFP4"
|
|
# ollama-local: "qwen3.6:35b"
|
|
#
|
|
# nodes[].providers[] defines each provider candidate with catalog and execution fields (Provider-First).
|
|
# nodes[].providers[].id is the stable provider identity referenced by models[].providers keys.
|
|
# nodes[].providers[].type — runtime type (vllm, ollama, lemonade, sglang, openai_api,
|
|
# seulgivibe_claude, seulgivibe_openai, cli).
|
|
# nodes[].providers[].category — "api", "cli", or "local_inference".
|
|
# nodes[].providers[].endpoint / base_url / command — type-specific execution fields.
|
|
# nodes[].providers[].models — served model names this provider can serve.
|
|
# nodes[].providers[].health — observed health state string.
|
|
# nodes[].providers[].capacity — provider-pool max concurrent execution slots; 0 is not dispatchable.
|
|
# nodes[].providers[].total_context_tokens — provider runtime total KV/context budget used for
|
|
# long-context admission. Must satisfy total_context_tokens >= context_window_tokens *
|
|
# long_context_capacity for every model group referencing this provider. Live-apply on refresh.
|
|
# nodes[].providers[].long_context_capacity — concurrent long-context slots (context_window-sized
|
|
# requests). Long requests occupy a normal slot and a long slot; 0 means no dedicated long limit.
|
|
# Live-apply on refresh.
|
|
# nodes[].providers[].max_queue — legacy per-provider queue depth (compatibility only).
|
|
# Effective policy is owned by the root provider_pool.max_queue.
|
|
# When provider_pool is set, per-provider values are ignored.
|
|
# nodes[].providers[].queue_timeout_ms — legacy per-provider queue timeout (compatibility only).
|
|
# Effective policy is owned by the root provider_pool.queue_timeout_ms.
|
|
# When provider_pool is set, per-provider values are ignored.
|
|
# nodes[].providers[].lifecycle_capabilities — coarse lifecycle capabilities list.
|
|
# nodes[].providers[].enabled — on/off dispatch switch; omit or true = enabled, false = excluded from
|
|
# dispatch pool. Disabled providers appear in status with status=disabled, capacity=0. Does not
|
|
# stop adapter processes. Classified as live-apply (no restart required) on config refresh.
|
|
|
|
console:
|
|
adapter: "cli"
|
|
target: "codex"
|
|
session_id: "default"
|
|
background: false
|
|
timeout_sec: 240
|
|
|
|
# Top-level models[] defines canonical routing keys and their provider-pool mapping.
|
|
# models[].id is the external model id; providers maps provider id → served model.
|
|
models:
|
|
- id: "qwen3.6:35b"
|
|
display_name: "Qwen 3.6 35B"
|
|
context_window_tokens: 262144
|
|
default_max_tokens: 32768
|
|
min_max_tokens: 32768
|
|
default_thinking_token_budget: 1024
|
|
providers:
|
|
mac-mlx-vllm: "mlx-community/Qwen3.6-35B-A3B-4bit"
|
|
# Same model group can keep a normalized-only Ollama provider as a low
|
|
# capacity/high priority fallback candidate. Clients do not select this
|
|
# execution path; capacity + priority + availability choose the provider.
|
|
ollama-local: "qwen3.6:35b"
|
|
- id: "local-llama3"
|
|
display_name: "Local Llama 3"
|
|
context_window_tokens: 8192
|
|
providers:
|
|
# Ollama-only model groups are valid and run through normalized execution.
|
|
ollama-local: "llama3.1:8b"
|
|
# Example: CLI providers (codex, codex-exec) do not serve models.
|
|
# They are declared in nodes[].providers[] for dispatch, not in models[].
|
|
# - id: "codex-task"
|
|
# providers:
|
|
# codex: "app-server"
|
|
# codex-exec: "exec"
|
|
# Example: Seulgivibe static catalog. Endpoint and raw token values belong to
|
|
# environment-specific private config/request headers, not tracked files.
|
|
# - id: "claude-sonnet-4-5"
|
|
# providers:
|
|
# seulgivibe-claude: "claude-sonnet-4-5"
|
|
# - id: "claude-opus-4-8"
|
|
# providers:
|
|
# seulgivibe-claude: "claude-opus-4-8"
|
|
# - id: "claude-fable-5"
|
|
# providers:
|
|
# seulgivibe-claude: "claude-fable-5"
|
|
# - id: "gpt-5.1"
|
|
# providers:
|
|
# seulgivibe-openai: "gpt-5.1"
|
|
# - id: "gpt-5.5"
|
|
# providers:
|
|
# seulgivibe-openai: "gpt-5.5"
|
|
|
|
nodes:
|
|
# id is the stable node identity; omitting it falls back to an auto UUID (dev only).
|
|
# agent_kind selects the registration kind; omitting it defaults to "generic-node".
|
|
# Allowed values: "generic-node" (default).
|
|
#
|
|
# Provider-First example (recommended):
|
|
- id: "node-example-01"
|
|
alias: "example-node"
|
|
token: "<node-token>"
|
|
agent_kind: "generic-node"
|
|
providers:
|
|
- id: "claude-tui"
|
|
type: "cli"
|
|
category: "cli"
|
|
command: "claude"
|
|
args:
|
|
- "--dangerously-skip-permissions"
|
|
env:
|
|
- "TERM=xterm-256color"
|
|
mode: "persistent-lazy"
|
|
capacity: 1
|
|
- id: "codex"
|
|
type: "cli"
|
|
category: "cli"
|
|
command: "codex"
|
|
args:
|
|
- "app-server"
|
|
mode: "codex-app-server"
|
|
capacity: 1
|
|
- id: "codex-exec"
|
|
type: "cli"
|
|
category: "cli"
|
|
command: "codex"
|
|
args:
|
|
- "exec"
|
|
- "--json"
|
|
resume_args:
|
|
- "exec"
|
|
- "resume"
|
|
- "--json"
|
|
output_format: "codex-json"
|
|
mode: "codex-exec"
|
|
capacity: 1
|
|
# Mac MLX vLLM provider (local GPU inference).
|
|
# Tracked secrets (API key, etc.) are not stored in this file.
|
|
- id: "mac-mlx-vllm"
|
|
type: "openai_api"
|
|
category: "local_inference"
|
|
endpoint: "http://127.0.0.1:8002/v1"
|
|
models:
|
|
- "mlx-community/Qwen3.6-35B-A3B-4bit"
|
|
health: "healthy"
|
|
capacity: 2
|
|
priority: 0
|
|
# Long-context admission budget: total_context_tokens >= 262144 * 1.
|
|
# mac-mlx-vllm runtime KV budget is 262144 (max_kv_size / max_request_tokens),
|
|
# so only one full 262144-window long request fits at a time. long_context_capacity
|
|
# is the long-slot count, not the normal capacity (2); do not conflate them.
|
|
total_context_tokens: 262144
|
|
long_context_capacity: 1
|
|
# Ollama provider kept in the provider pool with explicit low concurrency.
|
|
# It is not removed from mixed groups; operators weight it with capacity
|
|
# and priority instead.
|
|
- id: "ollama-local"
|
|
type: "ollama"
|
|
category: "local_inference"
|
|
base_url: "http://127.0.0.1:11434"
|
|
models:
|
|
- "qwen3.6:35b"
|
|
- "llama3.1:8b"
|
|
health: "healthy"
|
|
capacity: 1
|
|
priority: 50
|
|
# Seulgivibe OpenAI-compatible provider examples. Keep endpoint values
|
|
# illustrative and provide user tokens per request via openai.provider_auth.
|
|
# - id: "seulgivibe-claude"
|
|
# type: "seulgivibe_claude"
|
|
# category: "api"
|
|
# endpoint: "https://seulgivibe.example.invalid/anthropic/v1"
|
|
# models:
|
|
# - "claude-sonnet-4-5"
|
|
# - "claude-opus-4-8"
|
|
# - "claude-fable-5"
|
|
# capacity: 4
|
|
# - id: "seulgivibe-openai"
|
|
# type: "seulgivibe_openai"
|
|
# category: "api"
|
|
# endpoint: "https://seulgivibe.example.invalid/openai/v1"
|
|
# models:
|
|
# - "gpt-5.1"
|
|
# - "gpt-5.5"
|
|
# capacity: 4
|
|
# Legacy adapters configuration (compat override example):
|
|
# adapters:
|
|
# cli:
|
|
# enabled: true
|
|
# profiles:
|
|
# claude-tui:
|
|
# command: "claude"
|
|
# args:
|
|
# - "--dangerously-skip-permissions"
|
|
# env:
|
|
# - "TERM=xterm-256color"
|
|
# persistent: true
|
|
# terminal: true
|
|
# response_idle_timeout_ms: 5000
|
|
# startup_idle_timeout_ms: 5000
|
|
# mode: "persistent-lazy"
|
|
# codex:
|
|
# command: "codex"
|
|
# args:
|
|
# - "app-server"
|
|
# mode: "codex-app-server"
|
|
# codex-exec:
|
|
# command: "codex"
|
|
# args:
|
|
# - "exec"
|
|
# - "--json"
|
|
# resume_args:
|
|
# - "exec"
|
|
# - "resume"
|
|
# - "--json"
|
|
# output_format: "codex-json"
|
|
# mode: "codex-exec"
|
|
runtime:
|
|
concurrency: 1
|
|
|
|
# === Provider-pool example (recommended) ===
|
|
# Full example node with provider pool (Provider-First).
|
|
# nodes[].providers[].id is the stable provider identity referenced by models[].providers keys.
|
|
# nodes:
|
|
# - id: "node-gpu-01"
|
|
# alias: "gpu-node"
|
|
# providers:
|
|
# - id: "vllm-gpu"
|
|
# type: "vllm"
|
|
# category: "api"
|
|
# endpoint: "http://127.0.0.1:8000/v1"
|
|
# models:
|
|
# - "nvidia/Qwen3.6-35B-A3B-NVFP4"
|
|
# health: "healthy"
|
|
# capacity: 4
|
|
# priority: 1
|
|
# request_timeout_ms: 120000
|
|
# lifecycle_capabilities: ["scale_up", "scale_down"]
|
|
# # enabled: false # exclude from dispatch pool (live-apply)
|
|
# - id: "ollama-local"
|
|
# type: "ollama"
|
|
# category: "local_inference"
|
|
# base_url: "http://127.0.0.1:11434"
|
|
# models:
|
|
# - "qwen3.6:35b"
|
|
# health: "healthy"
|
|
# capacity: 2
|
|
# priority: 2
|
|
#
|
|
# === Legacy adapters (compat override example — discouraged for new deploys) ===
|
|
# Only use when explicit adapter instance override or compatibility before compilation is required.
|
|
# - id: "node-vllm-01"
|
|
# alias: "vllm-gpu-node"
|
|
# token: "<node-token>"
|
|
# adapters:
|
|
# openai_compat_instances:
|
|
# - name: "vllm-gpu"
|
|
# enabled: true
|
|
# provider: "vllm"
|
|
# endpoint: "http://127.0.0.1:8000/v1"
|
|
# capacity: 4
|
|
# max_queue: 16
|
|
# queue_timeout_ms: 30000
|
|
# providers:
|
|
# - id: "vllm-gpu-legacy"
|
|
# type: "vllm"
|
|
# category: "api"
|
|
# adapter: "vllm-gpu"
|
|
# models:
|
|
# - "nvidia/Qwen3.6-35B-A3B-NVFP4"
|