From 8150d4697e6fc3d7af0718d3d60a178a5bb57448 Mon Sep 17 00:00:00 2001 From: toki Date: Fri, 10 Jul 2026 20:09:33 +0900 Subject: [PATCH] =?UTF-8?q?docs(agent-roadmap):=20usage-token-log-ops-mvp?= =?UTF-8?q?=20=EB=A7=88=EC=9D=BC=EC=8A=A4=ED=86=A4=20=EB=B0=8F=20SDD?= =?UTF-8?q?=EB=A5=BC=20=EC=95=84=EC=B9=B4=EC=9D=B4=EB=B8=8C=ED=95=98?= =?UTF-8?q?=EA=B3=A0=20=EA=B4=80=EB=A0=A8=20spec=20=EA=B0=B1=EC=8B=A0?= =?UTF-8?q?=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit usage-token-log-ops-mvp 마일스톤 완료에 따라 roadmap 파일들을 archive로 이동하고, PHASE.md와 agent-spec 문서를 현재 구현 상태로 동기화한다 --- .../milestones/usage-token-log-ops-mvp.md | 42 ++++++++++++------- .../usage-token-log-ops-mvp/SDD.md | 0 .../PHASE.md | 6 +-- agent-spec/index.md | 2 +- agent-spec/input/openai-compatible-surface.md | 24 +++++++++++ agent-spec/runtime/edge-node-execution.md | 17 ++++++++ .../runtime/provider-pool-config-refresh.md | 5 +++ 7 files changed, 76 insertions(+), 20 deletions(-) rename agent-roadmap/{ => archive}/phase/operational-observability-provider-management/milestones/usage-token-log-ops-mvp.md (75%) rename agent-roadmap/{ => archive}/sdd/operational-observability-provider-management/usage-token-log-ops-mvp/SDD.md (100%) diff --git a/agent-roadmap/phase/operational-observability-provider-management/milestones/usage-token-log-ops-mvp.md b/agent-roadmap/archive/phase/operational-observability-provider-management/milestones/usage-token-log-ops-mvp.md similarity index 75% rename from agent-roadmap/phase/operational-observability-provider-management/milestones/usage-token-log-ops-mvp.md rename to agent-roadmap/archive/phase/operational-observability-provider-management/milestones/usage-token-log-ops-mvp.md index 7ab3764..528c854 100644 --- a/agent-roadmap/phase/operational-observability-provider-management/milestones/usage-token-log-ops-mvp.md +++ b/agent-roadmap/archive/phase/operational-observability-provider-management/milestones/usage-token-log-ops-mvp.md @@ -14,7 +14,7 @@ IOP는 완성된 사용자/테넌트 관리 시스템을 소유하지 않고, ## 상태 -[계획] +[완료] ## 승격 조건 @@ -51,26 +51,36 @@ IOP는 완성된 사용자/테넌트 관리 시스템을 소유하지 않고, 운영자가 OpenAI-compatible token 사용량을 외부 principal id 또는 내부 alias 단위로 빠르게 확인하기 위한 Prometheus/Grafana 중심 capability를 묶는다. -- [ ] [identity-scope] OpenAI-compatible 호출 주체는 `metadata.user`가 아니라 IOP bearer token의 운영 매핑으로 판별하고, IOP는 사용자/테넌트 모델이 아닌 `principal_ref` 참조값만 소유하는 기준이 정리되어 있다. -- [ ] [token-alias] Edge-owned 운영 설정 또는 secret reference에서 `token_ref -> principal_ref/internal_alias` 매핑을 관리하고, Grafana에는 내부 alias와 token reference만 노출하는 기준이 정리되어 있다. +- [x] [identity-scope] OpenAI-compatible 호출 주체는 `metadata.user`가 아니라 IOP bearer token의 운영 매핑으로 판별하고, IOP는 사용자/테넌트 모델이 아닌 `principal_ref` 참조값만 소유하는 기준이 정리되어 있다. +- [x] [token-alias] Edge-owned 운영 설정 또는 secret reference에서 `token_ref -> principal_ref/internal_alias` 매핑을 관리하고, Grafana에는 내부 alias와 token reference만 노출하는 기준이 정리되어 있다. - [x] [token-issue-skill] 프로젝트용 운영 skill이 `principal_ref` 또는 내부 id를 등록하면 raw IOP token을 생성하고, raw token은 한 번만 운영자에게 전달하며, tracked 파일에는 token reference 또는 hash만 남기는 기준이 정리되어 있다. -- [ ] [openai-scope] 1차 측정 범위가 OpenAI-compatible 호출로 제한되고, CLI usage status, A2A, local-only adapter usage, request-level ledger는 후속 범위로 분리되어 있다. -- [ ] [passthrough-safe] pure `passthrough` 응답 body에는 IOP sideband field/event를 추가하지 않고, Edge 내부 관측만으로 usage metric을 emit하는 기준이 정리되어 있다. -- [ ] [token-breakdown] `input`, `output`, provider-reported `reasoning`, provider-reported `cached_input` token type과 provider-reported/unavailable source 표시 기준이 정리되어 있다. -- [ ] [reasoning-observed] provider가 reasoning token을 별도 보고하지 않으면 token 추정치를 만들지 않고, reasoning 관측 여부와 character count만 보조 metric으로 남기는 기준이 정리되어 있다. -- [ ] [prometheus-metrics] Prometheus metric 이름과 label cardinality 기준이 정리되어 있다. request_id, session_id, raw token, raw prompt/response, provider token은 label에 넣지 않는다. -- [ ] [grafana-surface] Control Plane/Client dashboard를 만들지 않고 Grafana dashboard/query를 1차 조회 표면으로 쓰는 기준이 정리되어 있다. -- [ ] [limit-followup] 사용자별 token 제한은 2차 후속 축으로 분리하고, 1차 metric이 daily/monthly warn/reject 정책에 재사용될 수 있는 기준이 정리되어 있다. +- [x] [openai-scope] 1차 측정 범위가 OpenAI-compatible 호출로 제한되고, CLI usage status, A2A, local-only adapter usage, request-level ledger는 후속 범위로 분리되어 있다. +- [x] [passthrough-safe] pure `passthrough` 응답 body에는 IOP sideband field/event를 추가하지 않고, Edge 내부 관측만으로 usage metric을 emit하는 기준이 정리되어 있다. +- [x] [token-breakdown] `input`, `output`, provider-reported `reasoning`, provider-reported `cached_input` token type과 provider-reported/unavailable source 표시 기준이 정리되어 있다. +- [x] [reasoning-observed] provider가 reasoning token을 별도 보고하지 않으면 token 추정치를 만들지 않고, reasoning 관측 여부와 character count만 보조 metric으로 남기는 기준이 정리되어 있다. +- [x] [prometheus-metrics] Prometheus metric 이름과 label cardinality 기준이 정리되어 있다. request_id, session_id, raw token, raw prompt/response, provider token은 label에 넣지 않는다. +- [x] [grafana-surface] Control Plane/Client dashboard를 만들지 않고 Grafana dashboard/query를 1차 조회 표면으로 쓰는 기준이 정리되어 있다. +- [x] [limit-followup] 사용자별 token 제한은 2차 후속 축으로 분리하고, 1차 metric이 daily/monthly warn/reject 정책에 재사용될 수 있는 기준이 정리되어 있다. ## 완료 리뷰 -- 상태: 없음 -- 요청일: 없음 -- 완료 근거: 기능 Task가 아직 충족되지 않았다. +- 상태: 통과 +- 요청일: 2026-07-10 +- 완료 근거: 같은 Milestone task group의 archive `complete.log` 3개가 PASS `Roadmap Completion`으로 기능 Task 9개를 확인했고, 기존 완료 Task `token-issue-skill`은 [openai-usage-token-issue/SKILL.md](../../../../agent-ops/skills/project/openai-usage-token-issue/SKILL.md)와 관련 git evidence로 확인했다. 종료 감사에서 관련 코드/계약/spec/test를 재확인했고 남은 차단 항목은 없다. +- 완료 evidence: + - [identity_alias_auth complete.log](../../../../agent-task/archive/2026/07/m-usage-token-log-ops-mvp/01_identity_alias_auth/complete.log) - `identity-scope`, `token-alias` + - [usage_metrics complete.log](../../../../agent-task/archive/2026/07/m-usage-token-log-ops-mvp/02+01_usage_metrics/complete.log) - `openai-scope`, `passthrough-safe`, `token-breakdown`, `reasoning-observed`, `prometheus-metrics` + - [grafana_rollup_docs complete.log](../../../../agent-task/archive/2026/07/m-usage-token-log-ops-mvp/03+02_grafana_rollup_docs/complete.log) - `grafana-surface`, `limit-followup` +- 종료 감사: + - Spec sync: updated - [openai-compatible-surface.md](../../../../agent-spec/input/openai-compatible-surface.md), [provider-pool-config-refresh.md](../../../../agent-spec/runtime/provider-pool-config-refresh.md), [edge-node-execution.md](../../../../agent-spec/runtime/edge-node-execution.md), [index.md](../../../../agent-spec/index.md) + - 검증: `go test -count=1 ./packages/go/config ./apps/edge/internal/openai ./apps/edge/internal/service ./apps/node/internal/adapters/openai_compat ./apps/node/internal/adapters/vllm` PASS + - 검증: `rg --fixed-strings "sum by (principal_alias, token_type)" docs/openai-usage-grafana.md`와 daily/monthly `increase()` query 확인 PASS + - 참고: `go test -count=1 ./...`는 local root filesystem `/tmp` 공간 부족과 `/config` mount의 `mkdir -m 0000` 동작 때문에 환경성 실패가 있었고, Milestone 직접 범위 테스트는 통과했다. +- 남은 차단 항목: 없음 - 리뷰 필요: - - [ ] 사용자가 완료 결과를 확인했다 - - [ ] archive 이동을 승인했다 -- 리뷰 코멘트: 없음 + - [x] 사용자가 완료 결과를 확인했다 + - [x] archive 이동을 승인했다 +- 리뷰 코멘트: `sync-milestone-workstate`와 `complete-milestone` 기준으로 SDD gate, 관련 파일/git evidence, spec sync, Phase/current 라벨을 함께 확인했다. ## 범위 제외 diff --git a/agent-roadmap/sdd/operational-observability-provider-management/usage-token-log-ops-mvp/SDD.md b/agent-roadmap/archive/sdd/operational-observability-provider-management/usage-token-log-ops-mvp/SDD.md similarity index 100% rename from agent-roadmap/sdd/operational-observability-provider-management/usage-token-log-ops-mvp/SDD.md rename to agent-roadmap/archive/sdd/operational-observability-provider-management/usage-token-log-ops-mvp/SDD.md diff --git a/agent-roadmap/phase/operational-observability-provider-management/PHASE.md b/agent-roadmap/phase/operational-observability-provider-management/PHASE.md index 20a2e34..62f5be5 100644 --- a/agent-roadmap/phase/operational-observability-provider-management/PHASE.md +++ b/agent-roadmap/phase/operational-observability-provider-management/PHASE.md @@ -32,9 +32,9 @@ provider 확장 Phase에서 검증한 Ollama, vLLM, SGLang, Lemonade 같은 추 - 경로: [model-group-long-context-admission](../../archive/phase/operational-observability-provider-management/milestones/model-group-long-context-admission.md) - 요약: model group의 단일 context window 계약을 유지하면서 입력 기준 long-context 요청을 별도 slot으로 admission하고, long 요청이 찬 provider와 queue 앞 long 요청이 normal 요청을 불필요하게 막지 않도록 라우팅 정책을 완료했다. -- [계획] 사용자별 OpenAI-compatible 토큰 측정 MVP - - 경로: [usage-token-log-ops-mvp](milestones/usage-token-log-ops-mvp.md) - - 요약: OpenAI-compatible 호출을 IOP bearer token 기반 `principal_ref`/alias로 귀속하고, provider/user-facing 표면을 넓히지 않은 채 input/output/reasoning token 사용량을 Prometheus metric으로 측정해 Grafana에서 ROI 판단의 1차 근거로 본다. +- [완료] 사용자별 OpenAI-compatible 토큰 측정 MVP + - 경로: [usage-token-log-ops-mvp](../../archive/phase/operational-observability-provider-management/milestones/usage-token-log-ops-mvp.md) + - 요약: OpenAI-compatible 호출을 IOP bearer token 기반 `principal_ref`/alias로 귀속하고, pure passthrough body를 유지한 채 input/output/reasoning/cached token 사용량을 Prometheus metric으로 측정해 Grafana 조회 기준과 후속 제한 정책 재사용 기준까지 정리했다. - [스케치] 요청 실행 로그와 Usage Ledger 기반 - 경로: [request-execution-log-usage-ledger-foundation](milestones/request-execution-log-usage-ledger-foundation.md) diff --git a/agent-spec/index.md b/agent-spec/index.md index 0a78579..eae7243 100644 --- a/agent-spec/index.md +++ b/agent-spec/index.md @@ -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, 외부 `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` | +| `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/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 4443d8c..38bad5d 100644 --- a/agent-spec/input/openai-compatible-surface.md +++ b/agent-spec/input/openai-compatible-surface.md @@ -21,9 +21,21 @@ source_evidence: - type: code path: apps/edge/internal/openai/run_result.go notes: RunEvent stream을 OpenAI-compatible result로 수집 + - type: code + path: apps/edge/internal/openai/principal.go + notes: principal token hash auth와 authenticated principal metadata 구성 + - type: code + path: apps/edge/internal/openai/usage_metrics.go + notes: OpenAI-compatible request/token/reasoning Prometheus metric emit - type: test path: apps/edge/internal/openai/server_test.go notes: OpenAI-compatible route, provider-pool, workspace, tool handling 검증 + - type: test + path: apps/edge/internal/openai/usage_metrics_test.go + notes: usage metric label, token breakdown, passthrough usage regression 검증 + - type: docs + path: docs/openai-usage-grafana.md + notes: Grafana query와 daily/monthly rollup 조회 가이드 --- # 스펙: OpenAI-Compatible 입력 표면 @@ -48,6 +60,9 @@ Edge가 OpenAI-compatible HTTP 요청을 받아 내부 `adapter + target` 실행 | Chat Completions response mode | OpenAI-compatible provider route는 `metadata.iop_response_mode` 생략 시 `passthrough`로 동작하고, 명시적으로 `passthrough+sideband` 또는 `transformed`를 선택할 수 있다. | | provider raw passthrough | `passthrough`는 provider status/header/body bytes를 기존 Edge-Node tunnel로 relay하고 pure response body에 IOP sideband를 섞지 않는다. | | sideband extension | `passthrough+sideband`는 provider body와 IOP route/usage/assembled observation을 명시적 extension stream/envelope로 함께 노출하며 provider-original byte identity로 표시하지 않는다. | +| 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이며 Control Plane/Client dashboard와 request-level ledger는 후속 범위다. | | Responses API | `/v1/responses`는 현재 string input의 non-streaming 요청만 지원한다. | | strict output | strict output이 켜져 있으면 XML completion contract 기반 instruction 또는 prompt prefix를 추가할 수 있다. | | tool call 처리 | Chat Completions `tools`는 provider native metadata 복원 또는 text tool-call synthesis/validation 경로를 사용한다. | @@ -99,11 +114,17 @@ sequenceDiagram - run metadata에는 `openai_model`, `openai_stream`, `strict_output`, `estimated_input_tokens`, `context_class`가 들어갈 수 있다. - provider tunnel metadata에는 response mode와 routing context가 들어가고, sideband mode는 route/usage/assembled observation을 확장 surface로 만든다. - 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 값만 사용한다. +- `request_id`, `session_id`, raw bearer token, provider token, raw prompt/response는 metric label에 넣지 않는다. +- provider body usage와 provider tunnel `USAGE` frame이 모두 있으면 body input/output을 우선하고 proto-only reasoning/cached input을 보조로 병합해 중복 집계를 피한다. ## 검증 - `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'` +- `rg --fixed-strings "sum by (principal_alias, token_type)" docs/openai-usage-grafana.md` - `make test-openai-ollama` - provider별 실제 runtime smoke는 환경별 agent-test/dev 또는 dev-corp profile을 따른다. @@ -121,9 +142,12 @@ sequenceDiagram - caller가 `metadata.iop_principal_*`를 보내도 authenticated context 값이 overwrite한다. - `openai.principal_tokens[]` 변경은 restart-required로 분류된다. - principal token auth가 실패하면 legacy `openai.bearer_token`이 unmapped fallback으로 동작한다. +- provider가 별도 reasoning token을 보고하지 않으면 reasoning text를 token으로 추정하지 않는다. +- Grafana guide는 metric 조회 예시이며 billing, chargeback, long-term ledger, 사용자별 제한 enforcement의 source of truth가 아니다. ## 변경 기록 - 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-10: principal token 기반 usage metering, Prometheus metric, Grafana query guide, reasoning/cached token breakdown을 Milestone completion evidence 기준으로 반영. diff --git a/agent-spec/runtime/edge-node-execution.md b/agent-spec/runtime/edge-node-execution.md index 2dc5388..727ea26 100644 --- a/agent-spec/runtime/edge-node-execution.md +++ b/agent-spec/runtime/edge-node-execution.md @@ -18,12 +18,24 @@ source_evidence: - type: code path: apps/node/internal/node/node.go notes: Node transport handler, adapter 실행, cancel, command, config refresh 처리 + - type: code + path: apps/node/internal/adapters/openai_compat/openai_compat.go + notes: OpenAI-compatible provider usage payload를 RuntimeEvent usage로 변환 + - type: code + path: apps/node/internal/adapters/vllm/vllm.go + notes: vLLM usage payload의 reasoning/cached token 변환 - type: test path: apps/edge/internal/transport/server_test.go notes: Edge transport server 단위 검증 - type: test path: apps/node/internal/node/node_test.go notes: Node 실행 처리 단위 검증 + - type: test + path: apps/node/internal/adapters/openai_compat/openai_compat_test.go + notes: OpenAI-compatible provider usage breakdown 검증 + - type: test + path: apps/node/internal/adapters/vllm/vllm_test.go + notes: vLLM usage breakdown 검증 --- # 스펙: Edge-Node 실행 경로 @@ -43,6 +55,7 @@ Edge와 Node 사이에 현재 구현된 실행 기능을 기능 단위로 정리 | adapter 실행 | Node가 `RunRequest.adapter`로 adapter instance를 찾고 adapter `Execute`를 호출한다. admission은 adapter `Capabilities().MaxConcurrency` 기준이다. | | 실행 이벤트 스트림 | Node adapter가 낸 start, delta, reasoning_delta, complete, error, cancelled 이벤트를 `RunEvent`로 Edge에 relay한다. | | provider raw tunnel | Edge가 `ProviderTunnelRequest`를 보내면 Node가 provider HTTP/SSE response를 열고 ordered `ProviderTunnelFrame`으로 status/header/body/end/error/usage 후보를 relay한다. | +| usage breakdown relay | `RunEvent.usage`와 `ProviderTunnelFrame.usage`는 provider가 보고한 input/output/reasoning/cached input token count를 Edge 관측 계층으로 전달한다. | | terminal event 합성 | adapter가 terminal event 없이 종료하면 Node가 terminal event를 합성한다. | | run cancel | Edge가 `CancelRequest`를 보내면 Node run manager가 active run context를 cancel한다. | | logical session 종료 | adapter가 `SessionTerminator`를 구현한 경우 `TERMINATE_SESSION`으로 session을 종료한다. 모든 adapter 공통 기능은 아니다. | @@ -143,6 +156,7 @@ sequenceDiagram - `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에 합쳐지지 않는다. +- `Usage.reasoning_tokens`와 `Usage.cached_input_tokens`는 provider가 별도 보고한 경우에만 채워지는 optional breakdown이다. - Node local DB는 기본 `file:iop.db?cache=shared&mode=rwc`로 열린다. - heartbeat는 Edge와 Node transport 양쪽에서 30초 interval, 45초 wait 기준을 사용한다. @@ -150,6 +164,7 @@ sequenceDiagram - `go test ./apps/edge/internal/transport ./apps/edge/internal/service ./apps/edge/internal/node` - `go test ./apps/node/internal/transport ./apps/node/internal/node ./apps/node/internal/router ./apps/node/internal/adapters ./apps/node/internal/store` +- `go test ./apps/node/internal/adapters/openai_compat ./apps/node/internal/adapters/vllm` - `make test-e2e` - Edge-Node와 OpenAI 보조 smoke를 함께 실행한다. runtime path 변경 시 사용자 흐름 검증을 대체하지 않는다. ## 한계와 주의사항 @@ -158,9 +173,11 @@ sequenceDiagram - `TERMINATE_SESSION`은 모든 adapter에 공통으로 보장되는 기능이 아니다. - Node store는 전역 query/audit API가 아니다. 상위 운영 이력은 별도 설계가 필요하다. - provider raw tunnel은 기존 socket 위 request-bound stream이다. 별도 Node stream server나 Edge의 provider direct access 경로가 아니다. +- usage breakdown은 provider-reported 값만 전달한다. provider가 보고하지 않은 reasoning token을 Node나 Edge가 추정하지 않는다. ## 변경 기록 - 2026-07-07: 현재 코드, 계약, README 기준으로 bootstrap spec 작성. - 2026-07-07: 기능 목록 중심으로 축소하고 주요 흐름을 Mermaid sequence diagram으로 정리. - 2026-07-08: Provider raw tunnel 실행 흐름과 passthrough event/data 경계를 현재 계약 기준으로 반영. +- 2026-07-10: `RunEvent.usage`/`ProviderTunnelFrame.usage`의 input/output/reasoning/cached input breakdown 전달 기준을 반영. diff --git a/agent-spec/runtime/provider-pool-config-refresh.md b/agent-spec/runtime/provider-pool-config-refresh.md index c1e11d5..a3f3f1d 100644 --- a/agent-spec/runtime/provider-pool-config-refresh.md +++ b/agent-spec/runtime/provider-pool-config-refresh.md @@ -51,6 +51,7 @@ Edge 설정에서 provider-pool이 어떻게 모델 실행 후보를 고르고, | mutable apply | 적용 가능한 변경은 Edge `Cfg`, `NodeStore`, service/input model catalog, OpenAI long-context threshold를 copy-on-write로 교체한다. | | Node config refresh push | 변경이 있으면 Edge가 연결된 Node에 node-specific `NodeConfigRefreshRequest`를 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 label 후보를 제공한다. | ## 범위 @@ -90,6 +91,8 @@ sequenceDiagram - provider `enabled=false`는 dispatch pool에서 제외하지만 adapter process lifecycle 변경을 의미하지 않는다. - provider capacity, priority, max queue, queue timeout, enabled toggle, model generation policy는 live apply 대상으로 분류된다. - 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[]` 변경은 credential/hash 변경으로 보고 restart-required로 분류된다. - refresh result는 changed nodes/providers/models와 restart-required paths를 stable non-nil slice로 보고한다. ## 검증 @@ -108,8 +111,10 @@ sequenceDiagram - no-change apply는 runtime snapshot을 교체하지만 Node push는 생략한다. - `NodeRuntimeConfig.concurrency`는 legacy metadata이며 provider-pool admission의 node-wide capacity로 쓰지 않는다. - credential, private endpoint, bearer token 원문은 tracked config/docs/spec에 남기지 않는다. +- principal token mapping은 완성된 사용자/테넌트 source of truth가 아니라 외부 `principal_ref` 또는 내부 alias에 대한 얇은 운영 매핑이다. ## 변경 기록 - 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 기준을 반영.