OpenCode의 일반 Chat 요청을 GPT provider가 거부한 뒤 재시도 가능한 오류로 왜곡해 벤치가 장시간 정체됐다. 선택된 protocol profile에 맞춰 출력 토큰 필드를 정규화하고 upstream 400을 비재시도 validation 오류로 유지한다.
693 lines
29 KiB
YAML
693 lines
29 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
|
|
cert: "/run/secrets/iop/edge.crt"
|
|
key: "/run/secrets/iop/edge.key"
|
|
ca: "/run/secrets/iop/credential-plane-ca.crt"
|
|
peer_role: "node"
|
|
|
|
# Legacy source-selection example (active below): credential_plane is false,
|
|
# and the OpenAI section may opt into bearer_token, principal_tokens, or
|
|
# provider_auth without changing the IOP Authorization/provider-token boundary.
|
|
#
|
|
# Managed source-selection example (comment-only, secret-free): set this block
|
|
# to enabled: true, keep the OpenAI legacy auth fields empty/disabled, enable
|
|
# the edge-node TLS, Control Plane mTLS, and OpenAI HTTPS blocks in this file,
|
|
# then restart the Edge. Key fields remain deployment file paths, never values.
|
|
credential_plane:
|
|
# Omitted or false keeps the legacy credential mode. In legacy mode,
|
|
# openai.bearer_token, openai.principal_tokens, and openai.provider_auth may
|
|
# be used. Set enabled to true only after the secure Control Plane path and
|
|
# OpenAI HTTPS listener below are ready.
|
|
#
|
|
# Managed mode accepts only Control Plane principal projections and
|
|
# credential leases. It rejects all configured or caller-supplied legacy
|
|
# credential sources and never falls back to them while the projection or
|
|
# lease path is unavailable. Enabling, disabling, or rolling back this mode
|
|
# is restart-required; config refresh does not partially apply the change.
|
|
enabled: false
|
|
lease_ttl_seconds: 30
|
|
lease_cache_size: 256
|
|
|
|
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
|
|
tls:
|
|
enabled: false
|
|
cert: "/run/secrets/iop/edge.crt"
|
|
key: "/run/secrets/iop/edge.key"
|
|
ca: "/run/secrets/iop/credential-plane-ca.crt"
|
|
server_name: "control-plane.internal"
|
|
peer_role: "control-plane"
|
|
|
|
# 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: "openai_compat"
|
|
session_id: "a2a"
|
|
timeout_sec: 120
|
|
bearer_token: ""
|
|
|
|
openai:
|
|
enabled: false
|
|
# HTTPS is mandatory when credential_plane.enabled is true.
|
|
tls:
|
|
enabled: false
|
|
cert: "/run/secrets/iop/edge-openai.crt"
|
|
key: "/run/secrets/iop/edge-openai.key"
|
|
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
|
|
# In managed credential mode, keep bearer_token, principal_tokens, and
|
|
# provider_auth empty/disabled. The dedicated legacy provider credential
|
|
# header is rejected before routing and is never forwarded upstream.
|
|
# The selected provider determines the execution path: OpenAI-compatible
|
|
# providers use passthrough, while native inference providers use normalized
|
|
# execution. Caller metadata does not select the route or response shape.
|
|
node: ""
|
|
# Stable provider identity for direct/fallback OpenAI dispatch attribution.
|
|
# Required when openai.enabled=true. A legacy model_routes entry can override
|
|
# it with its own provider_id; adapter text is never used as this identity.
|
|
provider_id: ""
|
|
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
|
|
# stream_evidence_gate configures request-local Recovery Coordinator, ingress snapshot limits,
|
|
# and optional caller-neutral semantic output filters.
|
|
# enabled: route supported Chat Completions, normalized Responses, and provider tunnel passthrough
|
|
# through the streamgate request runtime instead of the legacy eager-write path (default: false).
|
|
# max_request_fault_recovery: request fault recovery cap (0..3, default: 3). Explicit 0 disables recovery.
|
|
# max_strategy_fault_recovery: strategy fault recovery cap (0..max_request_fault_recovery, default: inherits request limit).
|
|
# max_ingress_snapshot_bytes: ingress snapshot size limit in bytes (1..16777216 [16 MiB], default: 16777216).
|
|
stream_evidence_gate:
|
|
enabled: false
|
|
environment: dev # dev | dev-corp; request-start selector snapshot
|
|
max_request_fault_recovery: 0
|
|
max_strategy_fault_recovery: 0
|
|
max_ingress_snapshot_bytes: 16777216
|
|
# filters are disabled by omission. Each policy has one unique filter kind:
|
|
# repeat_guard (request-local history plus Unicode rolling/current-stream
|
|
# inspection), schema_gate (only when metadata.scheme is present), or
|
|
# provider_error (error-event lifecycle observation only; matching and
|
|
# retry semantics belong to a follow-up task). Repeat evidence and
|
|
# observations retain fingerprints/counts/offsets, never prompt, output,
|
|
# reasoning, tool arguments, or results. A provider must advertise
|
|
# the configured capability in lifecycle_capabilities only when a blocking
|
|
# policy is enabled. Selectors may refine enablement/enforcement by
|
|
# environment, model_group, model, or provider; caller/agent identity is not
|
|
# a selector.
|
|
# filters:
|
|
# - filter: repeat_guard
|
|
# enforcement: blocking # blocking | observe_only
|
|
# capability: output.repeat_guard
|
|
# hold_evidence_runes: 500
|
|
# timeout_ms: 5000
|
|
# - filter: schema_gate
|
|
# enforcement: blocking
|
|
# capability: output.schema_gate
|
|
# - filter: provider_error
|
|
# enforcement: blocking
|
|
# capability: output.provider_error
|
|
# selectors:
|
|
# - type: provider # environment | model_group | model | provider
|
|
# key: "provider-id"
|
|
# enabled: true
|
|
|
|
# === Protocol Profiles (optional) ===
|
|
# protocol_profiles is the top-level reusable catalog of protocol profile
|
|
# overlays. It combines immutable built-in profiles (openai, gemini,
|
|
# anthropic, glm, kimi, minimax_chat, minimax_messages, mimo_chat,
|
|
# mimo_messages, grok, seulgi_chat, seulgi_messages)
|
|
# with operator-defined custom overlays. Each entry is keyed by a stable
|
|
# profile id and may extend a built-in or another custom profile via the
|
|
# Base field. Resolution happens once at config load into immutable
|
|
# ConcreteProtocolProfile snapshots carried onto each provider.
|
|
#
|
|
# Built-in profile ids (selectable via nodes[].providers[].profile or
|
|
# normalized from the legacy provider type):
|
|
# openai — openai_chat driver, https://api.openai.com/v1
|
|
# gemini — openai_chat driver, https://generativelanguage.googleapis.com/v1beta/openai
|
|
# anthropic — anthropic_messages driver, https://api.anthropic.com + /v1/messages
|
|
# glm — openai_chat driver, https://api.z.ai/api/paas/v4
|
|
# glm_coding — openai_chat driver, https://api.z.ai/api/coding/paas/v4 (Coding Plan)
|
|
# Coding Plan uses the same Bearer contract as General API but a
|
|
# distinct endpoint and subscription quota. It is not enabled by
|
|
# default. See official usage policy:
|
|
# https://docs.z.ai/legal-agreement/subscription-terms
|
|
# https://docs.z.ai/devpack/usage-policy
|
|
# - Must be used only for supported tooling / personal use or with
|
|
# separate provider authorization.
|
|
# - Proxy, shared, or production redistribution without authorization
|
|
# is prohibited.
|
|
# - No automatic fallback exists between General API and Coding Plan;
|
|
# selecting one profile routes to one endpoint exclusively.
|
|
# kimi — openai_chat driver, https://api.moonshot.cn/v1
|
|
# minimax_chat — openai_chat driver, https://api.minimax.io/v1
|
|
# minimax_messages — anthropic_messages driver, https://api.minimax.io/anthropic
|
|
# mimo_chat — openai_chat driver, https://api.xiaomimimo.com/v1 (pay-go)
|
|
# mimo_messages — anthropic_messages driver, https://api.xiaomimimo.com/anthropic (pay-go)
|
|
# grok — openai_chat driver, https://api.x.ai/v1
|
|
# seulgi_chat — openai_chat driver, Seulgi GPT OpenAI-compatible
|
|
# seulgi_messages — anthropic_messages driver, Seulgi Claude native Messages
|
|
#
|
|
# === GLM General API / Coding Plan example (comment-only, not enabled) ===
|
|
# Z.AI Coding Plan uses the same Bearer contract as General API but a distinct
|
|
# endpoint and subscription quota. Endpoint selection is driven by external
|
|
# model IDs, not by an extra request field. Both profiles expose only
|
|
# models + chat_completions with Bearer auth and must never be mapped under
|
|
# the same external model ID when endpoint/quota isolation is required.
|
|
#
|
|
# No automatic fallback exists between General API and Coding Plan;
|
|
# selecting one profile routes to one endpoint exclusively.
|
|
# Coding Plan may only be enabled for use allowed by current Z.AI terms
|
|
# (https://docs.z.ai/legal-agreement/subscription-terms).
|
|
#
|
|
# models:
|
|
# - id: "glm-5.1-api"
|
|
# providers:
|
|
# glm-api: "glm-5.1"
|
|
# - id: "glm-5.1-coding"
|
|
# providers:
|
|
# glm-coding: "glm-5.1"
|
|
# nodes:
|
|
# - id: "node-glm-example"
|
|
# providers:
|
|
# - id: "glm-api"
|
|
# type: "openai_api"
|
|
# category: "api"
|
|
# profile: "glm"
|
|
# models: ["glm-5.1"]
|
|
# capacity: 1
|
|
# - id: "glm-coding"
|
|
# type: "openai_api"
|
|
# category: "api"
|
|
# profile: "glm_coding"
|
|
# models: ["glm-5.1"]
|
|
# capacity: 1
|
|
#
|
|
# When endpoint/quota isolation is required, keep glm-5.1-api and glm-5.1-coding
|
|
# as separate external model IDs mapping to distinct provider IDs.
|
|
# Do not place both providers under the same external model id.
|
|
# Do not put raw credential values here; use managed credential slots instead.
|
|
#
|
|
# Example custom overlay extending the openai built-in:
|
|
# protocol_profiles:
|
|
# my-openai-proxy:
|
|
# base: "openai"
|
|
# base_url: "https://my-proxy.example.invalid/v1"
|
|
# auth:
|
|
# header: "Authorization"
|
|
# scheme: "Bearer"
|
|
#
|
|
# Each nodes[].providers[] entry may set profile to select a catalog entry.
|
|
# A provider endpoint overrides only that provider's cloned profile base URL;
|
|
# it never mutates the built-in catalog. MiMo plan-specific URLs should be set
|
|
# explicitly as provider endpoints instead of being guessed from the pay-go URL.
|
|
# When profile is empty, the provider type is used for legacy alias
|
|
# normalization (e.g. vllm/openai_api → openai, seulgivibe_claude →
|
|
# seulgi_messages).
|
|
|
|
# === 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).
|
|
# nodes[].providers[].category — "api" or "local_inference".
|
|
# nodes[].providers[].endpoint / base_url — provider transport 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: "ollama"
|
|
target: "qwen3.6:35b"
|
|
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"
|
|
# Defaults to provider. Set model_group only when every candidate is
|
|
# operator-approved as the same logical model for query-time rollup.
|
|
usage_attribution: "model_group"
|
|
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"
|
|
# Omitted usage_attribution defaults to actual-provider attribution.
|
|
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: 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).
|
|
# Provider-First example (recommended):
|
|
- id: "node-example-01"
|
|
alias: "example-node"
|
|
token: "<node-token>"
|
|
providers:
|
|
# 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
|
|
# response_stall_timeout_ms: 60000 # omitted → uses documented default
|
|
# 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
|
|
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"
|
|
#
|
|
# === Operator-owned workspace example (commented) ===
|
|
# workspaces[] is the operator-owned bounded capability catalog for this
|
|
# node. Each entry is keyed by a globally unique ref, declares allowed
|
|
# operations (read, list, write, delete, command), command templates, the
|
|
# environment variable allowlist, and byte/time limits. Each enabled read,
|
|
# write, list, and command operation requires its effective positive bound:
|
|
# max_read_bytes, max_write_bytes, max_output_bytes, and (for command)
|
|
# max_command_timeout_ms. Platform is the closed "darwin" or "linux" set;
|
|
# every non-empty catalog entry must match the selected Node host exactly
|
|
# before its root is opened. Windows and unknown hosts fail closed. Roots are
|
|
# absolute clean paths other than "/".
|
|
# Refs must be globally unique across all nodes. An empty workspaces slice
|
|
# is backward-compatible.
|
|
#
|
|
# workspace_ref in execution_presets[].single_request references one of
|
|
# these entries by ref. Raw roots and command templates never enter execution
|
|
# presets, caller-visible responses, provider requests, or public metadata.
|
|
# Edge delivers the catalog through the dedicated Node-private config payload.
|
|
# Catalog changes are restart-required and never alter an active request.
|
|
#
|
|
# workspaces:
|
|
# - ref: "ws-operator-project-root"
|
|
# platform: "darwin"
|
|
# root: "/Users/operator/projects/iop-workspace"
|
|
# operations:
|
|
# - "read"
|
|
# - "list"
|
|
# - "write"
|
|
# - "delete"
|
|
# - "command"
|
|
# commands:
|
|
# - id: "find-go-files"
|
|
# executable: "/usr/bin/find"
|
|
# args:
|
|
# - "/Users/operator/projects/iop-workspace"
|
|
# - "-name"
|
|
# - "*.go"
|
|
# - id: "read-file"
|
|
# executable: "/usr/bin/cat"
|
|
# args: []
|
|
# environment_allowlist:
|
|
# - "IOP_ENV"
|
|
# - "HOME"
|
|
# max_read_bytes: 1048576
|
|
# max_write_bytes: 524288
|
|
# max_output_bytes: 8388608
|
|
# max_command_timeout_ms: 30000
|
|
# - ref: "ws-operator-linux-root"
|
|
# platform: "linux"
|
|
# root: "/srv/iop/workspace"
|
|
# operations:
|
|
# - "read"
|
|
# - "list"
|
|
# - "write"
|
|
# max_read_bytes: 1048576
|
|
# max_write_bytes: 524288
|
|
# max_output_bytes: 8388608
|
|
#
|
|
# === Caller-workspace hybrid preset example (commented) ===
|
|
# Agent-facing aliases use an unmarked light preset plus admitted caller tools.
|
|
# Do not add single_request or a raw workspace path to this preset; the caller's
|
|
# workspace_tools alternative binds the caller-opened workspace at request time.
|
|
# Keep the fixed Node-owned form on a different public alias; never point both
|
|
# ownership modes at the same preset.
|
|
# models:
|
|
# - id: "gpt-hybrid"
|
|
# display_name: "GPT Hybrid (caller workspace)"
|
|
# execution_preset: "preset-caller-gpt-hybrid"
|
|
# - id: "gpt-hybrid-fixed"
|
|
# display_name: "GPT Hybrid (fixed workspace)"
|
|
# execution_preset: "preset-fixed-gpt-hybrid"
|
|
# execution_presets:
|
|
# - id: "preset-caller-gpt-hybrid"
|
|
# selector:
|
|
# model: "gpt-5.6-terra"
|
|
# options:
|
|
# reasoning_effort: "high"
|
|
# allowed_modes: ["light"]
|
|
# routes:
|
|
# light:
|
|
# stages:
|
|
# - role: "local"
|
|
# model: "ornith-fast"
|
|
# - role: "review"
|
|
# model: "gpt-5.6-terra"
|
|
# options:
|
|
# reasoning_effort: "high"
|
|
# workspace_tools:
|
|
# - name: "opencode-bash"
|
|
# operations:
|
|
# prepare:
|
|
# tool_name: "bash"
|
|
# creates_parents: true
|
|
# schema_matcher:
|
|
# type: "object"
|
|
# properties:
|
|
# command: { type: "string" }
|
|
# argument_map:
|
|
# path: "path"
|
|
# command: "command"
|
|
# argv:
|
|
# - "python3"
|
|
# - "-c"
|
|
# - "import json,os,sys; os.makedirs(sys.argv[1], exist_ok=True); print(json.dumps(dict(prepared=True)))"
|
|
# - "{path}"
|
|
# result_matcher: { status: "success" }
|
|
# read:
|
|
# tool_name: "bash"
|
|
# schema_matcher:
|
|
# type: "object"
|
|
# properties:
|
|
# command: { type: "string" }
|
|
# argument_map:
|
|
# path: "path"
|
|
# command: "command"
|
|
# argv:
|
|
# - "python3"
|
|
# - "-c"
|
|
# - "import json,sys; print(json.dumps(dict(content=open(sys.argv[1], encoding='utf-8').read())))"
|
|
# - "{path}"
|
|
# result_matcher: { status: "success" }
|
|
# write:
|
|
# tool_name: "bash"
|
|
# creates_parents: true
|
|
# schema_matcher:
|
|
# type: "object"
|
|
# properties:
|
|
# command: { type: "string" }
|
|
# argument_map:
|
|
# path: "path"
|
|
# content: "content"
|
|
# command: "command"
|
|
# argv:
|
|
# - "python3"
|
|
# - "-c"
|
|
# - "import json,os,sys; p=sys.argv[1]; d=os.path.dirname(p); d and os.makedirs(d, exist_ok=True); open(p, 'w', encoding='utf-8').write(sys.argv[2]); print(json.dumps(dict(written=True)))"
|
|
# - "{path}"
|
|
# - "{content}"
|
|
# result_matcher: { status: "success" }
|
|
# delete:
|
|
# tool_name: "bash"
|
|
# schema_matcher:
|
|
# type: "object"
|
|
# properties:
|
|
# command: { type: "string" }
|
|
# argument_map:
|
|
# path: "path"
|
|
# command: "command"
|
|
# argv:
|
|
# - "python3"
|
|
# - "-c"
|
|
# - "import json,os,shutil,sys; p=sys.argv[1]; shutil.rmtree(p) if os.path.isdir(p) and not os.path.islink(p) else os.remove(p); print(json.dumps(dict(deleted=True)))"
|
|
# - "{path}"
|
|
# result_matcher: { status: "success" }
|
|
#
|
|
# === Fixed single-request preset example (commented) ===
|
|
# execution_presets[] entry with operator-owned fixed single-request policy.
|
|
# Live-apply on refresh; affects only new request snapshots.
|
|
# execution_presets:
|
|
# - id: "preset-fixed-gpt-hybrid"
|
|
# selector:
|
|
# model: "gpt-5.6-terra"
|
|
# options:
|
|
# reasoning_effort: "high"
|
|
# allowed_modes:
|
|
# - "light"
|
|
# routes:
|
|
# light:
|
|
# stages:
|
|
# - role: "plan"
|
|
# model: "gpt-5.6-terra"
|
|
# options:
|
|
# reasoning_effort: "high"
|
|
# - role: "work"
|
|
# model: "ornith-fast"
|
|
# - role: "review"
|
|
# model: "gpt-5.6-terra"
|
|
# options:
|
|
# reasoning_effort: "high"
|
|
# single_request:
|
|
# workspace_ref: "<opaque-workspace-ref>" # never a raw path or credential
|
|
# limits:
|
|
# wall_clock_ms: 1800000 # 30 minutes (max)
|
|
# timeout_ms: 600000 # 10 minutes per stage (max)
|
|
# max_tool_iterations: 64 # per stage
|
|
# max_output_bytes: 16777216 # 16 MiB per stage
|
|
# stages:
|
|
# plan:
|
|
# model: "gpt-5.6-terra"
|
|
# options:
|
|
# reasoning_effort: "high"
|
|
# work:
|
|
# model: "ornith-fast"
|
|
# review:
|
|
# model: "gpt-5.6-terra"
|
|
# options:
|
|
# reasoning_effort: "high"
|
|
# templates:
|
|
# plan_file: "templates/plan.md" # relative to this edge.yaml
|
|
# review_file: "templates/review.md" # relative to this edge.yaml
|