diff --git a/.env.dev-corp.example b/.env.dev-corp.example index f9aab3f..89d812b 100644 --- a/.env.dev-corp.example +++ b/.env.dev-corp.example @@ -11,6 +11,7 @@ IOP_EDGE_METRICS_PORT=19102 IOP_WEB_PORT=13002 IOP_PROMETHEUS_PORT=19112 IOP_PROMETHEUS_CONFIG=./configs/prometheus/prometheus.dev-corp.yml +IOP_PROMETHEUS_RETENTION_TIME=400d IOP_GRAFANA_BIND=127.0.0.1 IOP_GRAFANA_PORT=19122 IOP_GRAFANA_ADMIN_USER=admin diff --git a/.env.dev.example b/.env.dev.example index efeaf5d..ffc76bb 100644 --- a/.env.dev.example +++ b/.env.dev.example @@ -11,6 +11,7 @@ IOP_EDGE_METRICS_PORT=19101 IOP_WEB_PORT=13001 IOP_PROMETHEUS_PORT=19111 IOP_PROMETHEUS_CONFIG=./configs/prometheus/prometheus.dev.yml +IOP_PROMETHEUS_RETENTION_TIME=400d IOP_GRAFANA_BIND=127.0.0.1 IOP_GRAFANA_PORT=19121 IOP_GRAFANA_ADMIN_USER=admin diff --git a/.env.example b/.env.example index b65050c..c64a24f 100644 --- a/.env.example +++ b/.env.example @@ -8,6 +8,7 @@ IOP_EDGE_NODE_PORT=19090 IOP_EDGE_METRICS_PORT=19092 IOP_WEB_PORT=13000 IOP_PROMETHEUS_PORT=19110 +IOP_PROMETHEUS_RETENTION_TIME=400d IOP_GRAFANA_BIND=127.0.0.1 IOP_GRAFANA_PORT=19120 IOP_GRAFANA_ADMIN_USER=admin diff --git a/agent-roadmap/phase/routing-policy-model-orchestration/milestones/openai-compatible-provider-passthrough-contract-sync.md b/agent-roadmap/archive/phase/routing-policy-model-orchestration/milestones/openai-compatible-provider-passthrough-contract-sync.md similarity index 92% rename from agent-roadmap/phase/routing-policy-model-orchestration/milestones/openai-compatible-provider-passthrough-contract-sync.md rename to agent-roadmap/archive/phase/routing-policy-model-orchestration/milestones/openai-compatible-provider-passthrough-contract-sync.md index 91ae64b..0953808 100644 --- a/agent-roadmap/phase/routing-policy-model-orchestration/milestones/openai-compatible-provider-passthrough-contract-sync.md +++ b/agent-roadmap/archive/phase/routing-policy-model-orchestration/milestones/openai-compatible-provider-passthrough-contract-sync.md @@ -2,8 +2,8 @@ ## 위치 -- Roadmap: [ROADMAP.md](../../../ROADMAP.md) -- Phase: [PHASE.md](../PHASE.md) +- Roadmap: [ROADMAP.md](../../../../ROADMAP.md) +- Phase: [PHASE.md](../../../../phase/routing-policy-model-orchestration/PHASE.md) ## 목표 @@ -12,7 +12,7 @@ OpenAI-compatible provider 경로를 request `model`이 가리키는 provider ca ## 상태 -[검토중] +[완료] ## 승격 조건 @@ -68,15 +68,15 @@ vLLM, vLLM-MLX, Lemonade, SGLang, Seulgivibe 같은 OpenAI-compatible provider ## 완료 리뷰 -- 상태: 검토중 +- 상태: 통과 - 요청일: 2026-07-14 -- 완료 근거: `provider-error`, `policy-priority`는 local fake provider/fixture 기반 회귀 테스트와 `GOCACHE=/tmp/iop-go-cache go test ./apps/edge/internal/openai ./apps/edge/internal/service ./apps/node/internal/adapters/openai_compat` 통과로 충족했다. `devcorp-smoke`는 사용자 승인 동등 환경인 dev gx10에서 direct provider와 IOP dev Edge 경유 모두 `chat_template_kwargs.enable_thinking=false` streaming smoke가 HTTP 200, first content 약 0.1s, reasoning chunk 0개, finish_reason `stop`으로 통과했고 Edge 로그가 `provider_id=gx10-vllm`, `execution_path=provider_tunnel`을 기록했다. +- 완료 근거: `provider-error`, `policy-priority`는 local fake provider/fixture 기반 회귀 테스트와 `GOCACHE=/tmp/iop-go-cache go test ./apps/edge/internal/openai ./apps/edge/internal/service ./apps/node/internal/adapters/openai_compat` 통과로 충족했다. `devcorp-smoke`는 사용자 승인 동등 환경인 dev gx10에서 direct provider와 IOP dev Edge 경유 모두 `chat_template_kwargs.enable_thinking=false` streaming smoke가 HTTP 200, first content 약 0.1s, reasoning chunk 0개, finish_reason `stop`으로 통과했고 Edge 로그가 `provider_id=gx10-vllm`, `execution_path=provider_tunnel`을 기록했다. 2026-07-14 종료 감사에서 selector surface 검색, 대상 Go 테스트, 전체 `go test ./...`, `git diff --check`가 통과했고 agent-spec 동기화를 완료했다. - 검토 항목: - [x] 모든 기능 Task와 Task별 검증 evidence가 `Roadmap Completion` 또는 완료 리뷰 수동 검증 evidence에 남아 있다. - [x] SDD Evidence Map이 최종 검증 evidence와 일치한다. - [x] dev gx10 smoke 결과가 문서화되어 있다. - agent-ui 상태 반영: 해당 없음 -- 리뷰 코멘트: 남은 완료 차단 항목 없음. `[완료]` 전환과 archive는 별도 Milestone 종료 검토 흐름에서 처리한다. +- 리뷰 코멘트: 남은 완료 차단 항목 없음. Spec sync: Spec updated ([openai-compatible-surface](../../../../../agent-spec/input/openai-compatible-surface.md), [index](../../../../../agent-spec/index.md)). ## 범위 제외 diff --git a/agent-roadmap/sdd/routing-policy-model-orchestration/openai-compatible-provider-passthrough-contract-sync/SDD.md b/agent-roadmap/archive/sdd/routing-policy-model-orchestration/openai-compatible-provider-passthrough-contract-sync/SDD.md similarity index 95% rename from agent-roadmap/sdd/routing-policy-model-orchestration/openai-compatible-provider-passthrough-contract-sync/SDD.md rename to agent-roadmap/archive/sdd/routing-policy-model-orchestration/openai-compatible-provider-passthrough-contract-sync/SDD.md index de64b34..86100fe 100644 --- a/agent-roadmap/sdd/routing-policy-model-orchestration/openai-compatible-provider-passthrough-contract-sync/SDD.md +++ b/agent-roadmap/archive/sdd/routing-policy-model-orchestration/openai-compatible-provider-passthrough-contract-sync/SDD.md @@ -3,7 +3,7 @@ ## 위치 - Milestone: [Milestone 문서](../../../phase/routing-policy-model-orchestration/milestones/openai-compatible-provider-passthrough-contract-sync.md) -- Phase: [PHASE.md](../../../phase/routing-policy-model-orchestration/PHASE.md) +- Phase: [PHASE.md](../../../../phase/routing-policy-model-orchestration/PHASE.md) ## 상태 @@ -30,8 +30,8 @@ | 영역 | 기준 | 메모 | |------|------|------| | Roadmap | [Milestone 문서](../../../phase/routing-policy-model-orchestration/milestones/openai-compatible-provider-passthrough-contract-sync.md) | 목표, 범위, 기능 Task, 완료 evidence 기준 | -| Outer Contract | [openai-compatible-api.md](../../../../agent-contract/outer/openai-compatible-api.md) | OpenAI-compatible public request/response 계약 | -| Inner Wire Contract | [edge-node-runtime-wire.md](../../../../agent-contract/inner/edge-node-runtime-wire.md) | Edge-Node provider tunnel body/frame 책임 | +| Outer Contract | [openai-compatible-api.md](../../../../../agent-contract/outer/openai-compatible-api.md) | OpenAI-compatible public request/response 계약 | +| Inner Wire Contract | [edge-node-runtime-wire.md](../../../../../agent-contract/inner/edge-node-runtime-wire.md) | Edge-Node provider tunnel body/frame 책임 | | Code | `apps/edge/internal/openai`, `apps/edge/internal/service`, `apps/node/internal/adapters/openai_compat` | 구현 source of truth | | External Provider | dev-corp Spark Ornith/vLLM provider 또는 dev gx10 Ornith/vLLM provider | provider-native field passthrough smoke 대상. 사용자가 dev gx10 동등 검증을 허용했다. | | User Decision | 현재 사용자 설계 의도 | `model` 기반 route, metadata known-key read-only 발췌, provider-native payload 보존 | @@ -50,7 +50,7 @@ ## Interface Contract -- 계약 원문: [openai-compatible-api.md](../../../../agent-contract/outer/openai-compatible-api.md) +- 계약 원문: [openai-compatible-api.md](../../../../../agent-contract/outer/openai-compatible-api.md) - 입력: - `model`: route/provider capability 선택의 1차 source of truth - `messages` 또는 `input`: endpoint별 OpenAI-compatible request payload diff --git a/agent-roadmap/phase/routing-policy-model-orchestration/PHASE.md b/agent-roadmap/phase/routing-policy-model-orchestration/PHASE.md index 2524bf9..1f857ba 100644 --- a/agent-roadmap/phase/routing-policy-model-orchestration/PHASE.md +++ b/agent-roadmap/phase/routing-policy-model-orchestration/PHASE.md @@ -28,9 +28,9 @@ IOP의 OpenAI-compatible, A2A, IOP native 입력 표면에서 들어온 요청 - 경로: [model-group-mixed-provider-dispatch](../../archive/phase/routing-policy-model-orchestration/milestones/model-group-mixed-provider-dispatch.md) - 요약: model group provider pool에서 OpenAI-compatible provider와 Ollama/CLI 같은 normalized provider를 같은 후보군으로 두고, 기존 capacity+priority 선택 뒤 OpenAI-compatible 지원 provider는 모두 passthrough, native provider는 normalized 실행 경로로 자동 결정한다. -- [검토중] OpenAI-compatible Provider Passthrough 계약 동기화 - - 경로: [openai-compatible-provider-passthrough-contract-sync](milestones/openai-compatible-provider-passthrough-contract-sync.md) - - 요약: 사용자 설계 의도에 맞춰 `model` 기반 provider capability routing을 source of truth로 두고, OpenAI-compatible provider의 provider-native payload를 Edge allowlist 없이 raw tunnel로 보존하며, metadata는 IOP known-key를 read-only로 발췌하는 container로만 정리한다. +- [완료] OpenAI-compatible Provider Passthrough 계약 동기화 + - 경로: [openai-compatible-provider-passthrough-contract-sync](../../archive/phase/routing-policy-model-orchestration/milestones/openai-compatible-provider-passthrough-contract-sync.md) + - 요약: 사용자 설계 의도에 맞춰 `model` 기반 provider capability routing을 source of truth로 두고, OpenAI-compatible provider의 provider-native payload를 Edge allowlist 없이 raw tunnel로 보존하며, metadata는 IOP known-key를 read-only로 발췌하는 container로만 정리했다. 종료 감사에서 code audit, local Go tests, spec sync를 통과해 archive했다. - [스케치] OpenAI-compatible 하이브리드 라우팅과 컨텍스트 최적화 - 경로: [openai-compatible-hybrid-routing-context-optimization](milestones/openai-compatible-hybrid-routing-context-optimization.md) diff --git a/agent-spec/index.md b/agent-spec/index.md index eae7243..465a2a3 100644 --- a/agent-spec/index.md +++ b/agent-spec/index.md @@ -24,7 +24,7 @@ AI agent가 작업 전에 읽는 지도이기도 하지만, 사람도 "지금 - 실행 경로: Edge와 Node 사이의 등록, 실행, 이벤트, provider raw tunnel, 취소, command 흐름은 `runtime/edge-node-execution`에서 본다. - 런타임 라우팅/설정: provider-pool, `models[]`, `nodes[].providers[]`, live config refresh는 `runtime/provider-pool-config-refresh`에서 본다. -- 외부 HTTP 입력: OpenAI-compatible 호출, response mode/raw tunnel은 `input/openai-compatible-surface`, A2A JSON-RPC 호출은 `input/a2a-json-rpc-surface`에서 본다. +- 외부 HTTP 입력: OpenAI-compatible 호출, model-driven raw tunnel은 `input/openai-compatible-surface`, A2A JSON-RPC 호출은 `input/a2a-json-rpc-surface`에서 본다. - 운영 제어: Control Plane, Edge enrollment, fleet/edge status, Flutter Client 상태 소비는 `control/control-plane-operations`에서 본다. ## 스펙 목록 @@ -33,7 +33,7 @@ AI agent가 작업 전에 읽는 지도이기도 하지만, 사람도 "지금 |----|------|-----------|------|-----------| | `runtime/edge-node-execution` | 부분 | Edge-Node TCP/protobuf transport, Node 등록, run/cancel/command, provider raw tunnel, adapter 실행, Node local run store를 확인할 때 | `agent-spec/runtime/edge-node-execution.md` | `agent-contract/inner/edge-node-runtime-wire.md`, `apps/edge/internal/service/run_dispatch.go`, `apps/node/internal/node/node.go` | | `runtime/provider-pool-config-refresh` | 부분 | `models[]`, `nodes[].providers[]`, provider-pool dispatch, long-context admission, Edge/Node config refresh를 확인할 때 | `agent-spec/runtime/provider-pool-config-refresh.md` | `agent-contract/inner/edge-config-runtime-refresh.md`, `packages/go/config/config.go`, `apps/edge/internal/configrefresh/classify.go` | -| `input/openai-compatible-surface` | 부분 | `/v1/models`, `/v1/chat/completions`, `/v1/responses`, OpenAI-compatible auth/metadata/workspace/tool handling, response mode/raw tunnel, usage metric, 외부 `model` route를 확인할 때 | `agent-spec/input/openai-compatible-surface.md` | `agent-contract/outer/openai-compatible-api.md`, `apps/edge/internal/openai/chat_handler.go`, `apps/edge/internal/openai/stream.go`, `apps/edge/internal/openai/usage_metrics.go` | +| `input/openai-compatible-surface` | 부분 | `/v1/models`, `/v1/chat/completions`, `/v1/responses`, OpenAI-compatible auth/metadata/workspace/tool handling, model-driven raw tunnel, usage metric, 외부 `model` route를 확인할 때 | `agent-spec/input/openai-compatible-surface.md` | `agent-contract/outer/openai-compatible-api.md`, `apps/edge/internal/openai/chat_handler.go`, `apps/edge/internal/openai/stream.go`, `apps/edge/internal/openai/usage_metrics.go` | | `input/a2a-json-rpc-surface` | 부분 | Edge A2A JSON-RPC, `message/send`, `tasks/get`, `tasks/cancel`, A2A task store와 bearer auth를 확인할 때 | `agent-spec/input/a2a-json-rpc-surface.md` | `agent-contract/outer/a2a-json-rpc-api.md`, `apps/edge/internal/input/a2a/server.go`, `apps/edge/internal/input/a2a/task_store.go` | | `control/control-plane-operations` | 부분 | Control Plane-Edge wire, Client-Control Plane wire, Control Plane HTTP Edge/fleet status view, Flutter Client status consumer를 확인할 때 | `agent-spec/control/control-plane-operations.md` | `agent-contract/inner/control-plane-edge-wire.md`, `agent-contract/inner/client-control-plane-wire.md`, `apps/control-plane/internal/wire/edge_server.go` | diff --git a/agent-spec/input/openai-compatible-surface.md b/agent-spec/input/openai-compatible-surface.md index 9c415c7..48a8319 100644 --- a/agent-spec/input/openai-compatible-surface.md +++ b/agent-spec/input/openai-compatible-surface.md @@ -14,7 +14,7 @@ source_evidence: notes: Chat Completions request validation, route dispatch, tool/reasoning 정책 - type: code path: apps/edge/internal/openai/stream.go - notes: Chat Completions streaming, provider raw tunnel passthrough, sideband/transformed response mode 처리 + notes: Chat Completions streaming, provider raw tunnel passthrough 처리 - type: code path: apps/edge/internal/openai/responses_handler.go notes: Responses API request validation, metadata/workspace 처리, non-stream completion @@ -60,14 +60,14 @@ Edge가 OpenAI-compatible HTTP 요청을 받아 내부 `adapter + target` 실행 | legacy route 변환 | legacy route는 외부 `model`을 route entry의 `adapter`, `target`, `node`, `session_id`, queue policy로 변환한다. | | metadata/workspace 처리 | `metadata.workspace`는 `RunRequest.workspace`로 분리하고, 일반 metadata는 최대 16개 string key/value만 허용한다. | | Chat Completions | `/v1/chat/completions`는 non-streaming과 streaming SSE를 지원한다. | -| Chat Completions response mode | provider-pool model group route는 `metadata.iop_response_mode` 생략 시 `passthrough`로 동작하고, 명시적 selector는 값과 무관하게 거부한다. direct legacy provider route는 명시적 `passthrough+sideband` extension을 지원하며 `transformed`는 거부한다. | -| provider raw passthrough | `passthrough`는 provider status/header/body bytes를 기존 Edge-Node tunnel로 relay하고 pure response body에 IOP sideband를 섞지 않는다. | -| sideband extension | direct legacy provider route의 `passthrough+sideband`는 provider body와 IOP route/usage/assembled observation을 명시적 extension stream/envelope로 함께 노출한다. Responses `passthrough+sideband`는 응답 `metadata` 또는 `event: iop.sideband`를 확장 지점으로 사용한다. 둘 다 provider-original byte identity로 표시하지 않는다. | +| model-driven response path | request `model`이 가리키는 provider capability가 provider raw tunnel 또는 normalized RunEvent path를 결정한다. caller metadata는 route나 response shape를 선택하지 않는다. | +| provider raw passthrough | `passthrough`는 provider status/header/body bytes를 기존 Edge-Node tunnel로 relay하고 pure response body에 IOP 확장 envelope를 섞지 않는다. | +| provider-native field 보존 | provider raw tunnel route는 `model` served target rewrite와 auth/header 처리 외에 selected provider가 지원하는 OpenAI-compatible 표준 field와 provider extension field를 보존한다. | | OpenAI usage metering | Edge는 OpenAI-compatible request terminal status와 provider-reported `input`, `output`, `reasoning`, `cached_input` token usage를 Prometheus counter로 집계한다. | | reasoning observation metric | provider가 reasoning token을 보고하지 않고 reasoning text만 관측되면 token 추정 없이 관측 횟수와 character count 보조 metric만 emit한다. | | Grafana usage surface | 1차 조회 표면은 Prometheus/Grafana query guide이며 daily/monthly rollup, usage origin breakdown, operator-managed cloud price baseline, cloud-equivalent cost, avoided-cost ROI 기준을 문서로 제공한다. Control Plane/Client dashboard와 request-level ledger는 후속 범위다. | | Responses API | normalized(non-provider) `/v1/responses`는 string input의 non-streaming 요청만 지원한다. provider model group route는 `/v1/responses`를 raw passthrough로 provider `POST /v1/responses`에 전달한다. | -| Responses provider passthrough | provider-pool model group route의 `/v1/responses`는 `metadata.iop_response_mode` 명시를 거부하고, 생략 시 `model`만 served target으로 rewrite해 unknown/Codex field와 `stream:true` raw SSE를 provider로 relay한다. direct legacy provider route의 명시적 `passthrough+sideband`는 non-stream 응답의 top-level `metadata` 또는 streaming `event: iop.sideband`를 확장 지점으로 사용한다. usage metric은 endpoint=`responses`, response_mode=`passthrough` 또는 direct sideband route의 `passthrough+sideband`, model_group=request alias로 집계한다. | +| Responses provider passthrough | provider-pool model group route와 direct OpenAI-compatible provider route의 `/v1/responses`는 provider raw tunnel을 사용한다. Edge는 `model`만 served target으로 rewrite하고 unknown/Codex field와 `stream:true` raw SSE를 provider로 relay한다. usage metric은 endpoint=`responses`, response_mode=`passthrough`, model_group=request alias로 집계한다. | | strict output | strict output이 켜져 있으면 XML completion contract 기반 instruction 또는 prompt prefix를 추가할 수 있다. | | tool call 처리 | Chat Completions `tools`는 provider native metadata 복원 또는 text tool-call synthesis/validation 경로를 사용한다. | | cancel 전파 | HTTP caller timeout/cancel이 cancel-worthy error이면 Node `CancelRun`으로 전파한다. | @@ -88,13 +88,13 @@ sequenceDiagram Caller->>OpenAI: chat/responses request(model) OpenAI->>OpenAI: auth, metadata, route 검증 - alt provider route + passthrough mode + alt selected provider supports OpenAI-compatible passthrough OpenAI->>Service: SubmitProviderTunnel(ProviderPool/direct) Service->>Runtime: ProviderTunnelRequest Runtime-->>Service: ProviderTunnelFrame stream Service-->>OpenAI: tunnel frames - OpenAI-->>Caller: provider-original bytes or sideband extension - else transformed/normalized path + OpenAI-->>Caller: provider status/header/body bytes + else selected provider uses normalized execution OpenAI->>Service: SubmitRun(adapter/target or ProviderPool) Service->>Runtime: RunRequest Runtime-->>Service: RunEvent stream @@ -116,10 +116,9 @@ sequenceDiagram - provider-pool model group은 capacity + priority + availability 기준으로 provider candidate를 먼저 선택하고, 선택된 provider가 OpenAI-compatible 호출 방식을 지원하면 raw tunnel passthrough로 dispatch한다. Ollama/CLI/native provider가 선택되면 normalized `RunRequest` path로 dispatch한다. - `openai.provider_auth`는 provider tunnel forwarding rule만 저장하고 raw provider token 값은 request-time header에서만 읽는다. inbound IOP `Authorization` header를 provider token source로 재사용하지 않는다. - OpenAI request의 `metadata.workspace`는 absolute path가 필요한 route에서만 필수 검증된다. -- provider-pool model group Chat Completions와 Responses request는 `metadata.iop_response_mode`를 명시하면 `passthrough`, `passthrough+sideband`, `transformed`, unknown 모두 거부한다. 생략하면 `passthrough`다. -- direct legacy provider route는 `metadata.iop_response_mode` 생략 또는 `passthrough`를 raw tunnel로 처리하고, `passthrough+sideband`를 extension surface로 지원한다. provider tunnel route의 `transformed`는 지원하지 않는다. +- Chat Completions와 Responses request는 caller metadata로 provider raw tunnel과 normalized response shape를 선택하지 않는다. route/provider capability만 실행 경로를 결정한다. - run metadata에는 `openai_model`, `openai_stream`, `strict_output`, `estimated_input_tokens`, `context_class`가 들어갈 수 있다. -- provider tunnel metadata에는 response mode와 routing context가 들어가고, direct sideband mode는 route/usage/assembled observation을 확장 surface로 만든다. +- provider tunnel metadata에는 routing context와 관측 후보가 들어갈 수 있으며, provider body에는 합쳐지지 않는다. - Node complete event metadata의 `openai_tool_calls`와 `openai_text_tool_fallback`은 response tool call 복원에 쓰인다. - usage metric은 `iop_openai_requests_total`, `iop_openai_usage_tokens_total`, `iop_openai_reasoning_observed_total`, `iop_openai_reasoning_chars_total`로 emit된다. - usage label은 `edge_id`, `principal_ref`, `principal_alias`, `token_ref`, `model_group`, `endpoint`, `response_mode`, `status`, `usage_source`, `token_type`처럼 낮은 cardinality 값만 사용한다. @@ -131,7 +130,7 @@ sequenceDiagram - `go test ./apps/edge/internal/openai` - `go test ./apps/edge/internal/service` -- `go test ./apps/edge/internal/openai -run 'Sideband|UsageMetrics|ToolValidation|Dispatch|Reasoning|Retry'` +- `go test ./apps/edge/internal/openai -run 'Tunnel|UsageMetrics|ToolValidation|Dispatch|Reasoning|Retry'` - `rg --fixed-strings "cloud_equivalent_cost" docs/openai-usage-grafana.md` - `make test-openai-ollama` - provider별 실제 runtime smoke는 환경별 agent-test/dev 또는 dev-corp profile을 따른다. @@ -142,10 +141,8 @@ sequenceDiagram - `/v1/completions`는 제공하지 않는다. - OpenAI-compatible request에 provider/Ollama 전용 root field를 추가하지 않는다. - workspace는 prompt 본문에 섞지 않고 metadata에서 분리한다. -- pure `passthrough` body는 provider-original byte stream이며 IOP sideband나 transformed label을 포함하지 않는다. -- direct legacy provider route의 `passthrough+sideband`와 non-provider normalized route의 `transformed`는 provider-original byte identity로 취급하지 않는다. -- provider-pool model group route는 `metadata.iop_response_mode`를 request selector로 받지 않는다. -- direct legacy Responses provider route의 `passthrough+sideband`는 Chat Completions sideband envelope를 쓰지 않는다. non-streaming JSON object 응답은 `metadata` object를 병합하고, streaming 응답은 `event: iop.sideband`를 끼운다. +- pure `passthrough` body는 provider-original byte stream이며 IOP 확장 envelope나 normalized label을 포함하지 않는다. +- provider route와 non-provider normalized route의 차이는 selected provider capability에서 파생되며 caller metadata selector로 고르지 않는다. - text tool-call synthesis는 요청 `tools[]` schema를 기준으로만 수행한다. 자연어 추론으로 tool call을 만들지 않는다. - private token이나 endpoint 원문은 tracked spec/docs에 남기지 않는다. - `metadata.user`는 identity source가 아니며 사용되지 않는다. @@ -160,11 +157,11 @@ sequenceDiagram - 2026-07-07: 현재 코드와 OpenAI-compatible 계약 기준으로 bootstrap spec 작성. - 2026-07-07: 기능 목록 중심으로 축소하고 주요 흐름을 Mermaid sequence diagram으로 정리. -- 2026-07-08: Chat Completions provider raw tunnel, response mode, sideband/transformed semantics를 현재 코드와 계약 기준으로 반영. +- 2026-07-08: Chat Completions provider raw tunnel과 normalized execution semantics를 현재 코드와 계약 기준으로 반영. - 2026-07-10: principal token 기반 usage metering, Prometheus metric, Grafana query guide, reasoning/cached token breakdown을 Milestone completion evidence 기준으로 반영. - 2026-07-10: 일별 Usage 비용/ROI 리포트 MVP 종료 검토에서 daily/monthly rollup, usage origin breakdown, cloud-equivalent cost, avoided-cost ROI 문서 표면을 반영. - 2026-07-11: provider model group `/v1/responses` raw passthrough 동작(모델 rewrite, unknown/Codex field 보존, streaming relay, provider auth forwarding)과 endpoint=`responses` usage metric label을 현재 코드 기준으로 반영. -- 2026-07-11: Responses provider route의 명시적 `passthrough+sideband` 동작을 반영. non-stream은 응답 `metadata`, stream은 `event: iop.sideband`를 확장 지점으로 사용한다. +- 2026-07-11: Responses provider route의 provider raw tunnel 동작을 반영했다. - 2026-07-11: provider auth forwarding과 Seulgivibe OpenAI-compatible provider family surface를 종료 검토 기준으로 보강. -- 2026-07-12: provider-pool model group route에서 명시적 `metadata.iop_response_mode`를 거부하고, direct legacy provider route에서만 sideband extension selector를 유지하는 현재 surface를 반영. - 2026-07-12: Model Group Mixed Provider Dispatch 종료 검토 기준으로 selected provider capability 기반 passthrough/normalized 실행 경로를 반영. +- 2026-07-14: OpenAI-compatible Provider Passthrough 계약 동기화 종료 검토 기준으로 caller-facing response selector 설명을 제거하고, `model` 기반 route와 provider-native field 보존 기준을 반영. diff --git a/agent-spec/runtime/edge-node-execution.md b/agent-spec/runtime/edge-node-execution.md index 3123b10..f13da3f 100644 --- a/agent-spec/runtime/edge-node-execution.md +++ b/agent-spec/runtime/edge-node-execution.md @@ -156,7 +156,7 @@ sequenceDiagram - Edge의 node source of truth는 `configs/edge.yaml`과 `packages/go/config`의 `nodes[]` 구조다. - `RunEvent`는 adapter execution stream이고, `EdgeNodeEvent`는 node lifecycle/control event다. - `ProviderTunnelFrame.body`는 OpenAI-compatible provider passthrough의 source of truth이며 `RunEvent.delta`나 Edge event bus payload로 보내지 않는다. -- `ProviderTunnelFrame.usage`와 `metadata`는 sideband observation 후보이며 pure passthrough body에 합쳐지지 않는다. +- `ProviderTunnelFrame.usage`와 `metadata`는 관측 후보이며 pure passthrough body에 합쳐지지 않는다. - provider-pool mixed dispatch에서 `ProviderTunnelRequest`와 `RunRequest` 중 어느 wire를 사용할지는 selected provider capability에서 파생되며, client request metadata selector로 결정하지 않는다. - `Usage.reasoning_tokens`와 `Usage.cached_input_tokens`는 provider가 별도 보고한 경우에만 채워지는 optional breakdown이다. - Node local DB는 기본 `file:iop.db?cache=shared&mode=rwc`로 열린다. diff --git a/agent-test/dev/inventory.yaml b/agent-test/dev/inventory.yaml index 8f44479..c3bd1ac 100644 --- a/agent-test/dev/inventory.yaml +++ b/agent-test/dev/inventory.yaml @@ -350,10 +350,10 @@ model: expected_long_context_capacity: 2 validation_basis: Same Lemonade llama.cpp backend and current Ornith Q5 runtime validated --kv-unified with auto slots reporting n_ctx 262144; Qwen still needs smoke validation after it is reloaded. separation_note: These alignment rules are for the dev Qwen3.6 provider pool only. Gemma4 and DiffusionGemma use separate provider/model profiles and must not inherit Qwen parser/template/context assumptions. - response_mode: + provider_passthrough: default: pure_passthrough - selector: metadata.iop_response_mode omitted or passthrough - verification: Chat Completions streaming probe returned HTTP 200 with no X-IOP-Response-Mode header and no iop.sideband marker; the same endpoint with metadata.iop_response_mode=passthrough+sideband returned X-IOP-Response-Mode=passthrough+sideband and iop.sideband, confirming mode separation. + selector: none; request model/provider capability determines passthrough vs normalized execution + verification: Chat Completions streaming probe returned HTTP 200 through the provider tunnel with provider body preserved and no IOP response envelope injected. provider_pool_routing: observed_at: "2026-07-09" caller_shape: Pi-compatible OpenAI Chat Completions streaming requests to provider/model iop/qwen3.6:35b diff --git a/configs/edge.yaml b/configs/edge.yaml index eaa328e..294660f 100644 --- a/configs/edge.yaml +++ b/configs/edge.yaml @@ -82,11 +82,9 @@ openai: # target_header: "Authorization" # scheme: "Bearer" # required: true - # Provider-pool model group routes do not accept metadata.iop_response_mode - # as a caller selector. The selected provider determines the execution path: - # OpenAI-compatible providers use passthrough, Ollama/CLI/native providers use - # normalized execution. Direct legacy provider routes may still opt into the - # documented passthrough+sideband extension per request metadata. + # 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: "" diff --git a/docker-compose.yml b/docker-compose.yml index ca18818..0744370 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -99,6 +99,7 @@ services: command: - "--config.file=/etc/prometheus/prometheus.yml" - "--storage.tsdb.path=/prometheus" + - "--storage.tsdb.retention.time=${IOP_PROMETHEUS_RETENTION_TIME:-400d}" - "--web.enable-lifecycle" ports: - "${IOP_PROMETHEUS_BIND:-127.0.0.1}:${IOP_PROMETHEUS_PORT:-19110}:9090"