General API와 Coding Plan이 서로 다른 엔드포인트와 사용량 경계를 유지하도록 프로필, credential route, provider mapping, full-cycle 검증을 함께 반영한다.
21 KiB
21 KiB
| spec_doc_type | spec_id | status | source_evidence | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| spec | runtime/provider-pool-config-refresh | 부분 |
|
스펙: Provider Pool과 Config Refresh
목적
Edge 설정에서 provider-pool이 어떻게 모델 실행 후보를 고르고, 어떤 설정 변경이 재시작 없이 반영되는지 설명한다.
기능 목록
| 기능 | 설명 |
|---|---|
| model catalog | models[].id는 외부 OpenAI-compatible model key이자 provider-pool ModelGroupKey다. |
| usage attribution policy | models[].usage_attribution은 `provider |
| provider mapping | models[].providers는 provider id를 실제 served model name으로 매핑한다. |
| node provider catalog | nodes[].providers[]는 Node 아래 resource/provider catalog이며 provider id는 Edge config에서 전역 유일해야 한다. |
| config validation | config load가 provider id 참조, served model membership, numeric bounds, long-context budget을 검증한다. |
| provider 후보 필터링 | dispatch는 dispatch-ready connection을 가진 Node의 provider 후보 중 catalog match, enabled, healthy/available, capacity 조건을 만족하는 후보만 사용한다. protocol profile capability(messages, chat, responses, streaming, tool_calling, count_tokens, models)는 operation별 admission에 사용된다. |
| provider 전역 capacity/priority dispatch | node_id + provider_id lease가 여러 model group의 일반·long in-flight를 합산한다. available 후보 중 낮은 in-flight를 고르고 동률이면 낮은 priority와 round-robin을 적용한다. |
| provider-pool 공통 queue policy | Edge root provider_pool.max_queue가 모든 model group의 전체 pending 상한을, queue_timeout_ms가 각 pending request timeout을 소유한다. |
| global queue 재평가 | lease 반환, capacity/priority/enabled refresh, disconnect/reconnect 뒤 global enqueue 순서에서 현재 dispatch 가능한 가장 이른 waiter부터 candidate를 다시 구성한다. |
| provider snapshot | 일반·long in-flight는 provider lease state, queued 값은 Edge queue에서 해당 provider를 후보로 포함하는 고유 pending request pressure에서 계산한다. offline provider는 catalog identity를 유지하고 effective 수치를 0으로 보고한다. |
| mixed provider execution path | 같은 model group의 OpenAI-compatible provider와 Ollama/CLI/native provider를 같은 후보군으로 두며, 선택된 provider capability로 passthrough 또는 normalized 실행 경로를 결정한다. OpenAI-compatible provider는 openai_chat, anthropic_messages, 또는 openai_responses driver로 해석된다. |
| long-context admission | estimated input token이 threshold 이상이면 context_class=long으로 분류하고, provider long slot이 있으면 일반 capacity slot과 함께 점유한다. |
| config refresh dry-run/apply | loopback admin HTTP POST /refresh가 candidate config를 dry-run 또는 apply한다. |
| refresh classification | listener, Edge identity, bootstrap path, adapter structural 변경 등은 restart-required로 분류한다. |
| Stream Evidence Gate config | openai.stream_evidence_gate provides runtime activation, request-total/strategy fault recovery caps, ingress snapshot bounds, and per-filter capability/enforcement/Unicode hold policy; it is currently restart-required. |
| mutable apply | 적용 가능한 변경은 Edge Cfg, NodeStore, service/input model catalog, OpenAI long-context threshold를 copy-on-write로 교체한다. |
| Node config refresh push | 변경이 있으면 Edge가 dispatch-ready Node에 node-specific NodeConfigRefreshRequest를 push한다. accepted지만 pending인 Node는 register response config를 적용한 뒤 ready가 될 때까지 push 대상이 아니다. |
| Node registry swap | Node는 refresh payload로 새 adapter registry를 만들고 router registry를 swap한다. old registry stop은 active run이 있으면 drain 이후로 지연한다. |
| principal token mapping config | openai.principal_tokens[]는 raw token 없이 token_ref, token_hash_sha256, principal_ref, optional alias를 관리하고 OpenAI usage metering의 principal/token label 후보를 제공한다. 같은 principal에 여러 token entry를 둘 수 있다. |
| credential mode switch | credential_plane.enabled selects managed projection/lease ownership and requires every credential-bearing hop to use TLS plus externally mounted issuer/recipient/keyring material. |
| managed/legacy exclusivity | Managed mode rejects static principal mappings, legacy bearer/provider-auth forwarding, configured provider credential headers/env/args, and endpoint user-info. Legacy mode retains request-time openai.provider_auth compatibility. |
| managed route binding | An authenticated projection route binds slot, profile, upstream model, selector, credential revision, route revision, and generation before provider-pool admission and lease acquisition. |
| provider auth forwarding config | In legacy mode only, openai.provider_auth forwards a caller-supplied raw provider token to the selected compatible provider tunnel header. |
| Seulgivibe provider aliases | seulgivibe_claude, seulgivibe_openai provider type은 runtime adapter type을 openai_compat로 정규화하고, 명시 provider label이 없으면 canonical Seulgivibe alias를 Node payload provider label로 보존한다. |
범위
- 포함: Edge config load/default/validation, Stream Evidence Gate 설정, provider-pool dispatch, queue admission, long-context admission, config refresh classification/apply, Node config refresh payload.
- 제외: 개별 adapter의 provider API 호출 세부, OpenAI HTTP request/response shape, Control Plane credential lifecycle API details, private credential contents.
주요 흐름
sequenceDiagram
participant Caller
participant Service as Edge service
participant Queue as Provider queue
participant Node
Caller->>Service: SubmitRun(model)
Service->>Queue: dispatch-ready provider 후보 선택(capacity + priority)
Queue-->>Service: selected provider + served target
alt selected provider supports OpenAI-compatible call
Service->>Node: ProviderTunnelRequest(adapter, served target)
else selected provider is Ollama/CLI/native
Service->>Node: RunRequest(adapter, served target)
end
participant Operator
participant Refresh as Config refresh
Operator->>Refresh: POST /refresh(apply)
Refresh->>Refresh: load, validate, classify
Refresh->>Node: NodeConfigRefreshRequest
계약
iop.edge-config-runtime-refresh:agent-contract/inner/edge-config-runtime-refresh.mdiop.edge-node-runtime-wire:agent-contract/inner/edge-node-runtime-wire.md- proto 원문:
proto/iop/runtime.proto
설정/데이터/이벤트
long_context_threshold_tokens기본 예시는100000이고 0 이하 값은 config load에서 거부된다.credential_plane.enabled=truerequires Edge-Node server TLS, an enabled TLS Control Plane connector, and OpenAI ingress TLS when enabled. The Edge cannot combine managed mode withopenai.bearer_token,openai.principal_tokens[],openai.provider_auth, or static provider credential sources.- Node managed mode requires Edge transport TLS,
recipient_key_id/recipient private-key path, issuer key id/public-key path, and a bounded replay cache. All cert/key/keyring values are external file references and credential-plane changes are restart-required. protocol_profilesis the top-level catalog of custom overlays. AProtocolProfileConfsuppliesbase,driver,base_url, operation paths,auth,capabilities,model_mapping, andextensions;baseinheritance is separate from legacy provider-type normalization.nodes[].providers[].profileselects a catalog entry. Config normalization resolves that selection (or a legacy type alias) into the runtime-onlyRuntimeProfilesnapshot; the source YAML remains a selector plus catalog, not a per-model overlay.- Profile catalog and provider-selector changes are restart-required. Snapshot immutability describes loaded runtime state and does not make those changes live-applicable.
ConcreteProtocolProfile.MapModel(model)은 provider의 model alias 정규화를 수행한다. provider가 model mapping을 정의하면 IOP externalmodelkey를 provider served target으로 변환한다.ConcreteProtocolProfile.ResolveOperationURL(op)returns the complete resolved upstream URL. Absolute operation URLs are returned unchanged, while relative operation paths are joined once to the normalized base URL; the listed/v1/...values are operation-path inputs, not return values.- Built-in GLM profiles:
glm(General API,https://api.z.ai/api/paas/v4) andglm_coding(Coding Plan,https://api.z.ai/api/coding/paas/v4) are independent identities sharing theopenai_chatdriver, Bearer auth, andmodels/chat/streaming/tool_callingcapabilities. Neither declares theresponsesoperation or capability. Endpoint selection is driven by external model IDs mapped to distinct provider IDs, never by an extra request field. No automatic fallback exists between the two profiles; selecting one profile routes to one endpoint exclusively. Both are comment-only in the example config and disabled by default. Coding Plan usage is subject to current Z.AI subscription terms. validOperationsByDriver는 driver별 허용 operation의 closed set이다.openai_chat은models,chat_completions,responses,count_tokens를 허용한다.anthropic_messages는models,messages,count_tokens를 허용한다.openai_responses는models,responses,count_tokens를 허용한다.openai.stream_evidence_gate.enabled기본값은false다. request fault recovery는 0..3, strategy cap은 request-total 이하, ingress snapshot은 1..16777216 bytes이며 설정 변경은 restart-required다.filters[].hold_evidence_runesis bounded1..65536and defaults to 500. Forrepeat_guardit controls the Unicode pending/look-behind evidence window, not a time-based release or a cross-request retention period.- Blocking repeat capability admission is re-resolved for the actual provider/path while the request-start filter policy, history snapshot, recovery ordinals, and temperature candidate order remain generation-stable across provider switches.
provider_pool.max_queue는 0/생략 시 기본값16,queue_timeout_ms는 생략 시30000이고 명시적 0은 timeout 없음이다. canonical root key가 없을 때만 서로 같은 legacy provider queue pair를 승격하며 값이 다르면 load를 거부한다.nodes[].providers[].capacity와long_context_capacity는 provider resource 속성이고 같은 provider를 공유하는 model alias가 합산 점유한다.total_context_tokens는 runtime ledger가 아니라context_window_tokens * long_context_capacity정적 validation 값이다.models[].usage_attribution은 생략 시provider, 명시값은provider|model_group만 허용한다. 변경은 model catalog policy 변경으로 live apply되며models["<id>"].usage_attribution경로로 보고한다.- provider
enabled=false는 dispatch pool에서 제외하지만 adapter process lifecycle 변경을 의미하지 않는다. - accepted registration은 provider candidate를 바로 복구하지 않는다. Node가 config 적용과 handler 설치 뒤 ready ack를 받아야 해당 generation이 candidate, connected snapshot, refresh push 대상이 되며 이 transition이 stranded provider-pool waiter를 재평가한다.
- provider capacity, long-context capacity, priority, enabled toggle, root queue policy와 model generation policy는 live apply 대상으로 분류된다. apply는 기존 lease를 보존하고 이후 admission 및 모든 관련 waiter의 live candidate/deadline을 새 값으로 재평가한다.
- Edge listener, control plane, openai/a2a listener, bootstrap artifact path, node 추가/삭제, node token/alias, adapter 설정 변경은 restart-required 대상이다.
openai.principal_tokens[]는token_ref와token_hash_sha256중복을 거부하고, raw token 원문은 tracked config에 저장하지 않는다.- 여러
openai.principal_tokens[]entry가 같은principal_ref를 공유할 수 있으며, 이때token_ref가 앱/통합/용도별 사용량 분해 기준이다. openai.principal_tokens[]변경은 credential/hash 변경으로 보고 restart-required로 분류된다.- In legacy mode,
openai.provider_auth.enabled=trueresolves omitted fields tofrom_header=X-IOP-Provider-Authorization,target_header=Authorization,scheme=Bearer, andrequired=true. Managed mode rejects the setting and caller-supplied legacy provider credentials. - Seulgivibe provider catalog는 top-level
models[]의 정적 provider mapping을 source of truth로 사용한다. provider/modelsendpoint는 IOP catalog source가 아니다. models[]는 mixed provider group과 Ollama-only group을 모두 표현할 수 있다. Ollama는 후보에서 제외하지 않고capacity/priority로 운영자가 낮은 동시성과 낮은 선호도를 표현한다.- refresh result는 changed nodes/providers/models와 restart-required paths를 stable non-nil slice로 보고한다.
검증
go test ./packages/go/configgo test ./apps/edge/internal/configrefreshgo test ./apps/edge/internal/servicego test ./apps/edge/internal/nodego test ./apps/node/internal/adapters ./apps/node/internal/nodego test ./apps/edge/internal/bootstrap -run '^TestActualNodeReconnectReadyPumpsQueuedWaiterExactlyOnce$'./scripts/e2e-provider-capacity-smoke.sh
한계와 주의사항
- provider health는 현재 config/provider snapshot 기반이다. 모든 runtime에 대한 active health probe가 완성된 것은 아니다.
- refresh admin API는 operator-local 표면이다. 접근 제어 없이 public interface에 노출하지 않는다.
- Stream Evidence Gate의 request-local lifecycle과 지원 OpenAI 경로는
agent-spec/runtime/stream-evidence-gate.md에서 관리한다. - adapter structural 변경은 contract상 restart-required로 분류된다. Node handler가 registry swap을 지원하더라도 Edge refresh classifier가 허용한 변경만 apply해야 한다.
- no-change apply는 runtime snapshot을 교체하지만 Node push는 생략한다.
NodeRuntimeConfig.concurrency는 legacy metadata이며 provider-pool admission의 node-wide capacity로 쓰지 않는다.- provider가 full인 상태는 일시적인 queue block이지만, disconnect/disable로 live candidate가 모두 사라지면 waiter는 기존 queue timeout까지 남지 않고 unavailable로 종료된다.
- credential, private endpoint, bearer token 원문은 tracked config/docs/spec에 남기지 않는다.
- TLS private keys, the at-rest keyring, issuer private key, Node recipient private key, lease envelopes, and slot plaintext must remain external/runtime-only and must not appear in refresh reports, logs, metrics, or task artifacts.
- principal token mapping은 완성된 사용자/테넌트 source of truth가 아니라 외부
principal_ref또는 내부 alias에 대한 얇은 운영 매핑이다. - Seulgivibe provider endpoint와 raw user token은 환경별 private config 또는 request-time header로 주입해야 하며 tracked 예시에 실제 값을 남기지 않는다.
변경 기록
- 2026-07-07: 현재 코드, 계약, config 예시 기준으로 bootstrap spec 작성.
- 2026-07-07: 기능 목록 중심으로 축소하고 주요 흐름을 Mermaid sequence diagram으로 정리.
- 2026-07-10: OpenAI usage metering용 principal token hash mapping config와 restart-required 기준을 반영.
- 2026-07-11: Seulgivibe OpenAI-compatible provider aliases, provider auth forwarding config, static catalog 기준을 현재 코드/계약/테스트 기준으로 반영.
- 2026-07-12: Model Group Mixed Provider Dispatch 종료 검토 기준으로 mixed provider group과 Ollama-only group, capacity/priority 가중 예시를 반영.
- 2026-07-18: 저장소 구조 분해 뒤 config, provider resolution/admission, split test의
source_evidence를 현재 경로로 동기화. - 2026-07-22: pending accepted connection과 dispatch-ready connection을 구분하고, ready ack 뒤에만 provider candidate 복구·refresh push·queued waiter pump가 일어나는 현재 동작을 반영.
- 2026-07-22: root provider-pool queue policy, cross-model provider lease, global queue 재평가, refresh lease 보존과 connectivity 기반 snapshot 의미를 현재 구현·계약·테스트 기준으로 동기화.
- 2026-07-28: Stream Evidence Gate 설정 기본값·상한·restart-required 분류와 runtime spec 포인터를 반영.
- 2026-07-31: model별 provider-default/model-group opt-in attribution policy와 live-apply refresh 분류를 반영했다.
- 2026-08-01: protocol profile catalog/selector ownership, runtime-only profile resolution, and restart-required refresh semantics were synchronized with config source.
- 2026-08-02: Synchronized the managed credential mode switch, TLS/key prerequisites, legacy-auth exclusion, projected route binding, and restart-required credential-plane classification with current validation/runtime source.
- 2026-08-02: Added the
glm_codingbuilt-in profile alongsideglm(General API), both exposing onlymodels+chat_completionswith Bearer auth and no Responses. Endpoint selection is driven by external model IDs mapped to distinct provider IDs. No automatic fallback between General API and Coding Plan. Both are comment-only in the example config and disabled by default. Coding Plan usage is subject to current Z.AI subscription terms.