# API Reference (ํ•œ๊ตญ์–ด) ๐ŸŒ **Languages:** ๐Ÿ‡บ๐Ÿ‡ธ [English](../../../../reference/API_REFERENCE.md) ยท ๐Ÿ‡ช๐Ÿ‡น [am](../../../am/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ธ๐Ÿ‡ฆ [ar](../../../ar/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฆ๐Ÿ‡ฟ [az](../../../az/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ง๐Ÿ‡ฌ [bg](../../../bg/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ง๐Ÿ‡ฉ [bn](../../../bn/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡จ๐Ÿ‡ฟ [cs](../../../cs/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฉ๐Ÿ‡ฐ [da](../../../da/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฉ๐Ÿ‡ช [de](../../../de/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฌ๐Ÿ‡ท [el](../../../el/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ช๐Ÿ‡ธ [es](../../../es/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ช๐Ÿ‡ช [et](../../../et/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ท [fa](../../../fa/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ซ๐Ÿ‡ฎ [fi](../../../fi/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ซ๐Ÿ‡ท [fr](../../../fr/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ช [ga](../../../ga/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ณ [gu](../../../gu/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ณ๐Ÿ‡ฌ [ha](../../../ha/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ฑ [he](../../../he/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ณ [hi](../../../hi/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ญ๐Ÿ‡ท [hr](../../../hr/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ญ๐Ÿ‡บ [hu](../../../hu/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฆ๐Ÿ‡ฒ [hy](../../../hy/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ฉ [id](../../../id/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ณ๐Ÿ‡ฌ [ig](../../../ig/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฎ๐Ÿ‡น [it](../../../it/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฏ๐Ÿ‡ต [ja](../../../ja/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฌ๐Ÿ‡ช [ka](../../../ka/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฐ๐Ÿ‡ญ [km](../../../km/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ณ [kn](../../../kn/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฑ๐Ÿ‡น [lt](../../../lt/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฑ๐Ÿ‡ป [lv](../../../lv/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ณ [ml](../../../ml/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ณ [mr](../../../mr/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฒ๐Ÿ‡พ [ms](../../../ms/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฒ๐Ÿ‡น [mt](../../../mt/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฒ๐Ÿ‡ฒ [my](../../../my/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ณ๐Ÿ‡ต [ne](../../../ne/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ณ๐Ÿ‡ฑ [nl](../../../nl/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ณ๐Ÿ‡ด [no](../../../no/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ณ [or](../../../or/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ณ [pa](../../../pa/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ต๐Ÿ‡ญ [phi](../../../phi/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ต๐Ÿ‡ฑ [pl](../../../pl/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ต๐Ÿ‡น [pt](../../../pt/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ง๐Ÿ‡ท [pt-BR](../../../pt-BR/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ท๐Ÿ‡ด [ro](../../../ro/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ท๐Ÿ‡บ [ru](../../../ru/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฑ๐Ÿ‡ฐ [si](../../../si/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ธ๐Ÿ‡ฐ [sk](../../../sk/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ธ๐Ÿ‡ฎ [sl](../../../sl/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ท๐Ÿ‡ธ [sr](../../../sr/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ธ๐Ÿ‡ช [sv](../../../sv/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฐ๐Ÿ‡ช [sw](../../../sw/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ณ [ta](../../../ta/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ณ [te](../../../te/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡น๐Ÿ‡ญ [th](../../../th/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡น๐Ÿ‡ท [tr](../../../tr/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡บ๐Ÿ‡ฆ [uk-UA](../../../uk-UA/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ต๐Ÿ‡ฐ [ur](../../../ur/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡บ๐Ÿ‡ฟ [uz](../../../uz/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ป๐Ÿ‡ณ [vi](../../../vi/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ณ๐Ÿ‡ฌ [yo](../../../yo/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡จ๐Ÿ‡ณ [zh-CN](../../../zh-CN/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡น๐Ÿ‡ผ [zh-TW](../../../zh-TW/docs/reference/API_REFERENCE.md) --- ๐ŸŒ **Languages:** ๐Ÿ‡บ๐Ÿ‡ธ [English](../../../../reference/API_REFERENCE.md) ยท ๐Ÿ‡ช๐Ÿ‡น [am](../../../am/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ธ๐Ÿ‡ฆ [ar](../../../ar/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฆ๐Ÿ‡ฟ [az](../../../az/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ง๐Ÿ‡ฌ [bg](../../../bg/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ง๐Ÿ‡ฉ [bn](../../../bn/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡จ๐Ÿ‡ฟ [cs](../../../cs/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฉ๐Ÿ‡ฐ [da](../../../da/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฉ๐Ÿ‡ช [de](../../../de/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฌ๐Ÿ‡ท [el](../../../el/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ช๐Ÿ‡ธ [es](../../../es/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ช๐Ÿ‡ช [et](../../../et/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ท [fa](../../../fa/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ซ๐Ÿ‡ฎ [fi](../../../fi/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ซ๐Ÿ‡ท [fr](../../../fr/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ช [ga](../../../ga/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ณ [gu](../../../gu/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ณ๐Ÿ‡ฌ [ha](../../../ha/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ฑ [he](../../../he/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ณ [hi](../../../hi/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ญ๐Ÿ‡ท [hr](../../../hr/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ญ๐Ÿ‡บ [hu](../../../hu/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฆ๐Ÿ‡ฒ [hy](../../../hy/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ฉ [id](../../../id/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ณ๐Ÿ‡ฌ [ig](../../../ig/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฎ๐Ÿ‡น [it](../../../it/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฏ๐Ÿ‡ต [ja](../../../ja/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฌ๐Ÿ‡ช [ka](../../../ka/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฐ๐Ÿ‡ญ [km](../../../km/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ณ [kn](../../../kn/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฑ๐Ÿ‡น [lt](../../../lt/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฑ๐Ÿ‡ป [lv](../../../lv/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ณ [ml](../../../ml/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ณ [mr](../../../mr/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฒ๐Ÿ‡พ [ms](../../../ms/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฒ๐Ÿ‡น [mt](../../../mt/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฒ๐Ÿ‡ฒ [my](../../../my/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ณ๐Ÿ‡ต [ne](../../../ne/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ณ๐Ÿ‡ฑ [nl](../../../nl/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ณ๐Ÿ‡ด [no](../../../no/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ณ [or](../../../or/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ณ [pa](../../../pa/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ต๐Ÿ‡ญ [phi](../../../phi/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ต๐Ÿ‡ฑ [pl](../../../pl/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ต๐Ÿ‡น [pt](../../../pt/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ง๐Ÿ‡ท [pt-BR](../../../pt-BR/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ท๐Ÿ‡ด [ro](../../../ro/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ท๐Ÿ‡บ [ru](../../../ru/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฑ๐Ÿ‡ฐ [si](../../../si/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ธ๐Ÿ‡ฐ [sk](../../../sk/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ธ๐Ÿ‡ฎ [sl](../../../sl/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ท๐Ÿ‡ธ [sr](../../../sr/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ธ๐Ÿ‡ช [sv](../../../sv/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฐ๐Ÿ‡ช [sw](../../../sw/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ณ [ta](../../../ta/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ฎ๐Ÿ‡ณ [te](../../../te/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡น๐Ÿ‡ญ [th](../../../th/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡น๐Ÿ‡ท [tr](../../../tr/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡บ๐Ÿ‡ฆ [uk-UA](../../../uk-UA/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ต๐Ÿ‡ฐ [ur](../../../ur/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡บ๐Ÿ‡ฟ [uz](../../../uz/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ป๐Ÿ‡ณ [vi](../../../vi/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡ณ๐Ÿ‡ฌ [yo](../../../yo/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡จ๐Ÿ‡ณ [zh-CN](../../../zh-CN/docs/reference/API_REFERENCE.md) ยท ๐Ÿ‡น๐Ÿ‡ผ [zh-TW](../../../zh-TW/docs/reference/API_REFERENCE.md) OmniRoute API์˜ ํ•ต์‹ฌ ์ฐธ์กฐ ๋ฌธ์„œ์ž…๋‹ˆ๋‹ค. ๊ณต๊ฐœ `/v1` ์ธํ„ฐํŽ˜์ด์Šค์™€ ๊ฐ€์žฅ ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ๊ด€๋ฆฌ ์—”๋“œํฌ์ธํŠธ๋ฅผ ๋‹ค๋ฃน๋‹ˆ๋‹ค. ์ „์ฒด ๋‚ด์šฉ์€ ๊ธฐ๊ณ„ ํŒ๋… ๊ฐ€๋Šฅํ•œ [`docs/openapi.yaml`](../openapi.yaml)๊ณผ `src/app/api/` ์•„๋ž˜์˜ ๋ผ์šฐํŠธ ํŠธ๋ฆฌ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”. --- ## ๋ชฉ์ฐจ - [์ฑ„ํŒ… ์™„์„ฑ](#chat-completions) - [๋…์  ๊ด€๋ฆฌํ˜• ์„ธ์…˜ ์ž„๋Œ€](#exclusive-managed-session-leases) - [์ž„๋ฒ ๋”ฉ](#embeddings) - [์ด๋ฏธ์ง€ ์ƒ์„ฑ](#image-generation) - [๋ฌธ์„œ OCR](#document-ocr) - [๋ชจ๋ธ ๋ชฉ๋ก](#list-models) - [์ œ๊ณต์ž ํ”Œ๋Ÿฌ๊ทธ์ธ ๋งค๋‹ˆํŽ˜์ŠคํŠธ](#provider-plugin-manifest) - [ํ˜ธํ™˜์„ฑ ์—”๋“œํฌ์ธํŠธ](#compatibility-endpoints) - [Files API](#files-api) - [Batches API](#batches-api) - [Search API](#search-api) - [WebSocket ์ŠคํŠธ๋ฆฌ๋ฐ](#websocket-streaming) - [ํ• ๋‹น๋Ÿ‰ ๋ฐ ๋ฌธ์ œ ๋ณด๊ณ ](#quotas--issues-reporting) - [์‹œ๋งจํ‹ฑ ์บ์‹œ](#semantic-cache) - [๋Œ€์‹œ๋ณด๋“œ ๋ฐ ๊ด€๋ฆฌ](#dashboard--management) - [์ฝค๋ณด ๊ด€๋ฆฌ](#combo-management) - [์›นํ›„ํฌ](#webhooks) - [๋“ฑ๋ก๋œ ํ‚ค(์ž๋™ ๊ด€๋ฆฌ)](#registered-keys-auto-management) - [์—์ด์ „ํŠธ ํ”„๋กœํ† ์ฝœ](#agents-protocol) - [๊ด€๋ฆฌ ํ”„๋ก์‹œ](#management-proxies) - [๋ณต์›๋ ฅ(ํ™•์žฅ)](#resilience-extended) - [์Šคํ‚ฌ](#skills) - [๋ฉ”๋ชจ๋ฆฌ](#memory) - [MCP ์„œ๋ฒ„](#mcp-server) - [A2A ์„œ๋ฒ„](#a2a-server) - [ํด๋ผ์šฐ๋“œ, ํ‰๊ฐ€ ๋ฐ ๊ฒ€์ฆ](#cloud-evals--assess) - [์š”์ฒญ ์ฒ˜๋ฆฌ](#request-processing) - [์ธ์ฆ](#authentication) --- ## ์ฑ„ํŒ… ์™„์„ฑ ```bash POST /v1/chat/completions Authorization: Bearer your-api-key Content-Type: application/json { "model": "cc/claude-opus-4-6", "messages": [ {"role": "user", "content": "๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•˜์„ธ์š”..."} ], "stream": true } ``` ### ์‚ฌ์šฉ์ž ์ง€์ • ํ—ค๋” | ํ—ค๋” | ๋ฐฉํ–ฅ | ์„ค๋ช… | | ------------------------ | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `X-OmniRoute-No-Cache` | ์š”์ฒญ | ์บ์‹œ๋ฅผ ์šฐํšŒํ•˜๋ ค๋ฉด `true`๋กœ ์„ค์ • | | `x-omniroute-no-memory` | ์š”์ฒญ | ์ด ์š”์ฒญ์—์„œ ๋ฉ”๋ชจ๋ฆฌ ๋ฐ ์Šคํ‚ฌ ์ฃผ์ž…์„ ๊ฑด๋„ˆ๋›ฐ๋ ค๋ฉด `true`๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค(no-cache์™€ ๋™์ผํ•˜๊ฒŒ ๋™์ž‘ํ•˜๋ฉฐ, ํ˜ธ์ถœ๋ณ„ ํ† ํฐ/๋น„์šฉ ์˜ค๋ฒ„ํ—ค๋“œ๋ฅผ ๋ฐฉ์ง€ํ•จ) | | `X-OmniRoute-Progress` | ์š”์ฒญ | ์ง„ํ–‰ ์ด๋ฒคํŠธ๋ฅผ ๋ฐ›์œผ๋ ค๋ฉด `true`๋กœ ์„ค์ • | | `X-Session-Id` | ์š”์ฒญ | ์™ธ๋ถ€ ์„ธ์…˜ ์„ ํ˜ธ๋„๋ฅผ ์œ„ํ•œ ๊ณ ์ • ์„ธ์…˜ ํ‚ค | | `x_session_id` | ์š”์ฒญ | ๋ฐ‘์ค„ ๋ณ€ํ˜•๋„ ํ—ˆ์šฉ๋จ(์ง์ ‘ HTTP) | | `X-OmniRoute-Session-Id` | ์š”์ฒญ | ํ˜ธ์ถœ์ž๊ฐ€ ์ œ๊ณตํ•˜๋Š” ์„ธ์…˜/๋Œ€ํ™” ํƒœ๊ทธ(๋ฉ”๋ชจ๋ฆฌ์—๋„ ์ „๋‹ฌ๋จ). ์ง€์ •๋œ ๊ฒฝ์šฐ ์„ธ์…˜๋ณ„ ๋น„์šฉ ๊ท€์†์„ ์œ„ํ•ด `call_logs.session_tag`์— ๊ทธ๋Œ€๋กœ ์ €์žฅ๋จ(#8249) โ€” ์ง€์ •๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ์ ˆ๋Œ€ ์ƒ์„ฑ๋˜์ง€ ์•Š์Œ | | `Idempotency-Key` | ์š”์ฒญ | ์ค‘๋ณต ์ œ๊ฑฐ ํ‚ค(5์ดˆ ๋ฒ”์œ„) | | `X-Request-Id` | ์š”์ฒญ | ๋Œ€์ฒด ์ค‘๋ณต ์ œ๊ฑฐ ํ‚ค | | `X-OmniRoute-Cache` | ์‘๋‹ต | `HIT` ๋˜๋Š” `MISS`(๋น„์ŠคํŠธ๋ฆฌ๋ฐ) | | `X-OmniRoute-Idempotent` | ์‘๋‹ต | ์ค‘๋ณต ์ œ๊ฑฐ๋œ ๊ฒฝ์šฐ `true` | | `X-OmniRoute-Progress` | ์‘๋‹ต | ์ง„ํ–‰ ์ƒํ™ฉ ์ถ”์ ์ด ํ™œ์„ฑํ™”๋œ ๊ฒฝ์šฐ `enabled` | | `X-OmniRoute-Session-Id` | ์‘๋‹ต | OmniRoute์—์„œ ์‚ฌ์šฉํ•œ ์œ ํšจ ์„ธ์…˜ ID | | `X-OmniRoute-Request-Id` | ์‘๋‹ต | ์š”์ฒญ ์ƒ๊ด€๊ด€๊ณ„ ID(์•Œ๋ ค์ง„ ๊ฒฝ์šฐ) | | `X-OmniRoute-Version` | ์‘๋‹ต | OmniRoute ๋นŒ๋“œ ๋ฒ„์ „(ํ•ญ์ƒ ํฌํ•จ๋จ) | | `X-OmniRoute-Cost-Saved` | ์‘๋‹ต | HIT์œผ๋กœ ์ธํ•ด ์บ์‹œ๊ฐ€ ์ ˆ๊ฐํ•œ USD ๊ธˆ์•ก(์บ์‹œ ์ ์ค‘ ์‹œ์—๋งŒ ํ•ด๋‹น) | | `X-OmniRoute-Decision` | ์‘๋‹ต | ๋ผ์šฐํŒ… ์ถ”์ : `strategy=; provider=; latency_ms=`(``์€ ์ฝค๋ณด ์ „๋žต์ด๋ฉฐ, ๋น„์ฝค๋ณด ์š”์ฒญ์˜ ๊ฒฝ์šฐ `single`) โ€” ์™„๋ฃŒ ์‘๋‹ต์— ํ•ญ์ƒ ํฌํ•จ๋จ | > Nginx ์ฐธ๊ณ : ๋ฐ‘์ค„ ํ—ค๋”(์˜ˆ: `x_session_id`)๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ `underscores_in_headers on;`์„ ํ™œ์„ฑํ™”ํ•˜์„ธ์š”. > **๋น„์šฉ ํ…”๋ ˆ๋ฉ”ํŠธ๋ฆฌ ํ—ค๋”:** ๋น„์ŠคํŠธ๋ฆฌ๋ฐ ์„ฑ๊ณต ์‘๋‹ต์—๋Š” `X-OmniRoute-*` ๋น„์šฉ ํ…”๋ ˆ๋ฉ”ํŠธ๋ฆฌ ์„ธํŠธ๋„ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. ์ด ์„ธํŠธ์—๋Š” `X-OmniRoute-Response-Cost`(USD, ์†Œ์ˆ˜์  ์ดํ•˜ 10์ž๋ฆฌ ๊ณ ์ •; ๋ฌด๋ฃŒ/๊ฐ€๊ฒฉ ๋ฏธ์ฑ…์ • ์‹œ `0.0000000000`), `X-OmniRoute-Tokens-In` / `X-OmniRoute-Tokens-Out`, `X-OmniRoute-Model`, `X-OmniRoute-Provider`, `X-OmniRoute-Latency-Ms`, `X-OmniRoute-Cache-Hit`, `X-OmniRoute-Fallback-Attempts`(0๋ณด๋‹ค ํฐ ๊ฒฝ์šฐ์—๋งŒ)์™€ `X-OmniRoute-Request-Id` ๋ฐ `X-OmniRoute-Version`์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ํ—ค๋”๋Š” ์ฑ„ํŒ… ์™„์„ฑ, `/v1/responses`, `/v1/messages`๋ฟ๋งŒ ์•„๋‹ˆ๋ผ **๋ฏธ๋””์–ด ์—”๋“œํฌ์ธํŠธ**์ธ `/v1/embeddings`, `/v1/images/generations`, `/v1/audio/speech`, `/v1/audio/transcriptions`, `/v1/rerank`, `/v1/videos/generations`, `/v1/music/generations`, `/v1/moderations`(๋น„์šฉ์€ ํ•ญ์ƒ `0`)์—์„œ๋„ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค. ๋ฏธ๋””์–ด ๋น„์šฉ์€ ๊ฐ€๊ฒฉ ์ •๋ณด๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ๋ชจ๋‹ฌ๋ฆฌํ‹ฐ๋ณ„(์ด๋ฏธ์ง€๋‹น, ์ดˆ๋‹น, ๋ฌธ์ž๋‹น, ๊ฒ€์ƒ‰ ๋‹จ์œ„๋‹น)๋กœ ๊ณ„์‚ฐ๋˜๋ฉฐ, ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒฝ์šฐ `0`์œผ๋กœ ์ฒ˜๋ฆฌ๋ฉ๋‹ˆ๋‹ค(์žฅ์•  ํ—ˆ์šฉ). > **์บ์‹œ ์ ์ค‘ ๋น„์šฉ ์˜๋ฏธ:** ์‹œ๋งจํ‹ฑ ์บ์‹œ ์ ์ค‘(`X-OmniRoute-Cache-Hit: true`) ์‹œ์—๋Š” ์—…์ŠคํŠธ๋ฆผ ํ˜ธ์ถœ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ `X-OmniRoute-Response-Cost`๋Š” `0.0000000000`์ž…๋‹ˆ๋‹ค(์ ์ค‘ ๊ฒฐ๊ณผ ์ œ๊ณต์— ๋”ฐ๋ฅธ **์ฆ๋ถ„** ๋น„์šฉ). ์›๋ž˜ ๋ฐœ์ƒํ–ˆ๊ฑฐ๋‚˜ ๋ฐœ์ƒํ–ˆ์„ ๋น„์šฉ์€ `X-OmniRoute-Cost-Saved`์— ๋ณ„๋„๋กœ ๋ณด๊ณ ๋ฉ๋‹ˆ๋‹ค. ์ฒญ๊ตฌ ์‹œ์Šคํ…œ์—์„œ๋Š” `X-OmniRoute-Response-Cost`๋ฅผ ํ•ฉ์‚ฐํ•ด์•ผ ํ•˜๋ฉฐ(์บ์‹œ ์ ์ค‘ ๋น„์šฉ์€ ์—†์Œ), ์บ์‹œ ๋ถ„์„์—์„œ๋Š” `X-OmniRoute-Cost-Saved`๋ฅผ ์ง‘๊ณ„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ## ๋…์  ๊ด€๋ฆฌํ˜• ์„ธ์…˜ ์ž„๋Œ€ ๋…์  ๊ด€๋ฆฌํ˜• ์„ธ์…˜ ์ž„๋Œ€๋Š” ์„ ํƒ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ ์ค‘๋ฆฝ์  ๋ผ์šฐํŒ… ๊ณ„์•ฝ์ž…๋‹ˆ๋‹ค. ํ•˜๋‚˜์˜ ํ™œ์„ฑ ์†Œ์œ ์ž๊ฐ€ ์ ๊ฒฉ OmniRoute ์—ฐ๊ฒฐ ํ•˜๋‚˜๋ฅผ ์ ์œ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋ชจ๋ธ์„ ์ž„๋Œ€ํ•˜๊ฑฐ๋‚˜, OAuth๋ฅผ ์š”๊ตฌํ•˜๊ฑฐ๋‚˜, ํŠน์ • ํด๋ผ์ด์–ธํŠธ๋ฅผ ์‹๋ณ„ํ•˜๊ฑฐ๋‚˜, ํŠน์ • ๊ณต๊ธ‰์ž๋ฅผ ์š”๊ตฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ธ์ฆ์— ์‚ฌ์šฉํ•˜๋Š” API ํ‚ค์—๋Š” `lease:exclusive` ๋ฒ”์œ„์™€ ๋ช…์‹œ์ ์ธ ๋น„์–ด ์žˆ์ง€ ์•Š์€ `allowedConnections` ๋ชฉ๋ก์ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ณ€๊ฒฝ ๊ฒฝ๊ณ„๋Š” ํ‚ค ์ƒ์„ฑ ๋ฐ ๋ถ€๋ถ„ ์—…๋ฐ์ดํŠธ ์‹œ ๋‘ ํ•„๋“œ๊ฐ€ ํ•จ๊ป˜ ์กด์žฌํ•˜๋„๋ก ๊ฐ•์ œํ•ฉ๋‹ˆ๋‹ค. ```http POST /api/v1/session-leases Authorization: Bearer Content-Type: application/json X-OmniRoute-Lease-Owner: vlo_<43-base64url-characters> {"action":"acquire","model":"glm/glm-4.6"} ``` ์„ฑ๊ณตํ•œ ํš๋“, ๊ฐฑ์‹  ๋ฐ ํ•ด์ œ ์‘๋‹ต์€ ํƒ€์ž„์Šคํƒฌํ”„, `state`, ์ •ํ™•ํ•œ ์–‘์˜ `generation`์„ ๋…ธ์ถœํ•˜์ง€๋งŒ, ์„ ํƒ๋œ ์—ฐ๊ฒฐ์ด๋‚˜ ์ž๊ฒฉ ์ฆ๋ช…์€ ์ ˆ๋Œ€ ๋…ธ์ถœํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ฐฑ์‹  ๋ฐ ํ•ด์ œ ์‹œ์—๋Š” JSON ๋ณธ๋ฌธ์— generation์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ```json { "action": "renew", "generation": 1 } ``` ```json { "action": "release", "generation": 1, "reason": "OWNER_EXIT" } ``` ํ™œ์„ฑ ์ž„๋Œ€ ์†Œ์œ ์ž๋Š” ํ˜„์žฌ ๋ฐ”์ธ๋”ฉ์— ๋Œ€ํ•ด ๊ฐœ์ธ์ •๋ณด ๋ณดํ˜ธ์— ์•ˆ์ „ํ•œ ํ‘œ์‹œ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์š”์ฒญํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ```json { "action": "status", "generation": 1 } ``` ```json { "state": "ACTIVE", "generation": 1, "acquiredAt": "2026-08-28T12:00:00.000Z", "renewedAt": "2026-08-28T12:00:30.000Z", "expiresAt": "2026-08-28T12:02:30.000Z", "connection": { "displayName": "Primary Codex", "provider": "codex" } } ``` ์ด ์„ ํƒ์  ์ƒํƒœ ์ž‘์—…์€ ํ•˜๋‚˜์˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํŠธ๋žœ์žญ์…˜์—์„œ ๋ถˆํˆฌ๋ช…ํ•œ ์†Œ์œ ์ž, ์ธ์ฆ๋œ ๊ด€๋ฆฌํ˜• API ํ‚ค ๋ฐ ์ •ํ™•ํ•œ ํ™œ์„ฑ generation์œผ๋กœ ๋ณดํ˜ธ๋ฉ๋‹ˆ๋‹ค. `displayName`์€ ๊ตฌ์„ฑ๋œ ์—ฐ๊ฒฐ ์ด๋ฆ„์—์„œ ์•ž๋’ค ๊ณต๋ฐฑ๋งŒ ์ œ๊ฑฐํ•œ ๊ฐ’์ด๋ฉฐ, ์•ˆ์ „ํ•œ ๊ตฌ์„ฑ ์ด๋ฆ„์ด ์—†์œผ๋ฉด `null`์ž…๋‹ˆ๋‹ค. OmniRoute๋Š” ์ด๋ฉ”์ผ์ด๋‚˜ ์ƒ์„ฑ๋œ ๊ณ„์ • ID๋ฅผ ๋Œ€์‹  ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ณต๊ธ‰์ž ๊ฐ’์€ ๋ฏผ๊ฐํ•˜์ง€ ์•Š์€ ํ‘œ์‹œ ๋ ˆ์ด๋ธ”์ด๋ฉฐ, ์ƒ์„ฑ๋œ ํ˜ธํ™˜ ๊ณต๊ธ‰์ž ์‹๋ณ„์ž๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ์ž๊ฒฉ ์ฆ๋ช…, ํ† ํฐ, ์ฟ ํ‚ค, ์›์‹œ ์—ฐ๊ฒฐ ๋˜๋Š” API ํ‚ค ID, ์†Œ์œ ์ž ํ•ด์‹œ, ํŽœ์‹ฑ ๋น„๋ฐ€ ๊ฐ’ ๋ฐ ๋‚ด๋ถ€ ๋ผ์šฐํŒ… ๋ฐ์ดํ„ฐ๋Š” ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. ์ž˜๋ชป๋œ ํ‚ค, ์ž˜๋ชป๋œ ์†Œ์œ ์ž, ์˜ค๋ž˜๋œ generation, ์กด์žฌํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ๋งŒ๋ฃŒ๋˜๊ฑฐ๋‚˜ ํ•ด์ œ๋˜๊ฑฐ๋‚˜ ๋ฌดํšจํ™”๋œ ์กฐํšŒ๋Š” ๋ชจ๋‘ ์—ฐ๊ฒฐ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์—†์ด ๋™์ผํ•œ `409 LEASE_FENCE_STALE` ์˜ค๋ฅ˜๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์šฉ๋Ÿ‰ ๋Œ€๊ธฐ ์‘๋‹ต์„ ๋ฐ›์€ ํด๋ผ์ด์–ธํŠธ์—๋Š” ๊ฒ€์‚ฌํ•  ์ˆ˜ ์žˆ๋Š” ํ™œ์„ฑ ๋ฐ”์ธ๋”ฉ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋ผ์šฐํŒ…์ด ํ™œ์„ฑ ์ž„๋Œ€๋ฅผ ์ „ํ™˜ํ•  ๋•Œ๋Š” ๋™์ผํ•œ generation์ด ๊ณ„์† ์œ ํšจํ•˜๋ฉฐ, ์ƒํƒœ ์กฐํšŒ๋Š” ์ด์ „ ๋ฐ”์ธ๋”ฉ์ด ์•„๋‹Œ ์ƒˆ ๋ฐ”์ธ๋”ฉ์„ ์›์ž์ ์œผ๋กœ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ํš๋“, ๊ฐฑ์‹ , ํ•ด์ œ ๋ฐ ๋Œ€๊ธฐ ์‘๋‹ต์€ ๊ธฐ์กด ํ˜•์‹์„ ์œ ์ง€ํ•˜๋ฏ€๋กœ ๊ธฐ์กด ํด๋ผ์ด์–ธํŠธ์—๋Š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ์—†์Šต๋‹ˆ๋‹ค. ์ด ์„œ๋ฒ„ ๊ณ„์•ฝ์€ ๊ธฐ๋ณธ OpenAI Codex `/status`๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ˜„์žฌ ๊ธฐ๋ณธ Codex๋Š” ๋ชจ๋ธ ๊ณต๊ธ‰์ž์™€ ๊ธฐ๋ณธ ์ œ๊ณต ์ธ์ฆ/๊ณ„์ • ์ƒํƒœ๋ฅผ ๋ณด๊ณ ํ•˜์ง€๋งŒ ์ž„์˜์˜ ์‚ฌ์šฉ์ž ์ง€์ • ๊ณต๊ธ‰์ž ๊ณ„์ • ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋Š” ๋ Œ๋”๋งํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ–ฅํ›„ ํด๋ผ์ด์–ธํŠธ ํ†ตํ•ฉ์—์„œ๋Š” ์ด ์ž‘์—…์„ ํ˜ธ์ถœํ•˜๊ณ  `connection.displayName`์„ ํ‘œ์‹œํ•  ๋ฐฉ๋ฒ•์„ ๊ฒฐ์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ๋ชจ๋“  ๊ด€๋ฆฌํ˜• ์ถ”๋ก  ์š”์ฒญ์€ ๋‘ ์ œ์–ด ํ—ค๋”๋ฅผ ๋ชจ๋‘ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ```http X-OmniRoute-Lease-Owner: vlo_<43-base64url-characters> X-OmniRoute-Lease-Generation: 1 ``` ์ •ํ™•ํ•œ ์†Œ์œ ์ž, generation, ํ™œ์„ฑ ์—ฐ๊ฒฐ ๋ฐ ์ธ์ฆ๋œ API ํ‚ค๋Š” ์ง€์›๋˜๋Š” ๊ฐ ์—…์ŠคํŠธ๋ฆผ ์‹œ๋„ ์ง์ „์— ํŽœ์‹ฑ๋ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํ‚ค๊ฐ€ ๋™์ผํ•œ ์—ฐ๊ฒฐ์„ ํ—ˆ์šฉํ•˜๋”๋ผ๋„ ํ•ด๋‹น ํ‚ค๋ฅผ ์‚ฌ์šฉํ•ด ์†Œ์œ ์ž์™€ generation์„ ์žฌ์‚ฌ์šฉํ•˜๋ฉด ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค. ์›์‹œ ์†Œ์œ ์ž ๊ฐ’์€ ์˜๊ตฌ ์ €์žฅ๋˜๊ฑฐ๋‚˜, ๋กœ๊ทธ์— ๊ธฐ๋ก๋˜๊ฑฐ๋‚˜, ์š”์ฒญ ์Šค๋ƒ…์ƒท์— ๋ณด์กด๋˜๊ฑฐ๋‚˜, ์—…์ŠคํŠธ๋ฆผ์œผ๋กœ ์ „๋‹ฌ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ผ์‹œ์ ์ธ ๊ฒฝํ•ฉ์ด ๋ฐœ์ƒํ•˜๋ฉด HTTP `429`๊ฐ€ `Retry-After` ๋ฐ ๋‹ค์Œ ๋‚ด์šฉ๊ณผ ํ•จ๊ป˜ ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค. ```json { "state": "WAITING_FOR_CAPACITY", "error": { "type": "lease_error", "code": "LEASE_CAPACITY_UNAVAILABLE" }, "reason": "NO_FREE_ELIGIBLE_CONNECTION", "retryAfter": 30 } ``` ์ด ์‘๋‹ต์€ ์ผ๋ฐ˜ ์ ๊ฒฉ ์ง‘ํ•ฉ์ด ๋น„์–ด ์žˆ์ง€ ์•Š์•˜์œผ๋ฉฐ ๋ชจ๋“  ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ํ›„๋ณด๊ฐ€ ๋‹ค๋ฅธ ์†Œ์œ ์ž์˜ ํ™œ์„ฑ ์ž„๋Œ€์— ์˜ํ•ด ์ ์œ ๋˜์—ˆ๋‹ค๋Š” ์˜๋ฏธ์ผ ๋ฟ์ž…๋‹ˆ๋‹ค. ์ง€์›๋˜์ง€ ์•Š๋Š” ๋ชจ๋ธ/๊ณต๊ธ‰์ž, ์ •์ฑ… ๋ถˆ์ผ์น˜, ์ฟจ๋‹ค์šด, ํ• ๋‹น๋Ÿ‰, ์ƒํƒœ ๋ฐ ๊ธฐํƒ€ ์ผ๋ฐ˜์ ์ธ ์ ๊ฒฉ์„ฑ ์‹คํŒจ์—๋Š” ๊ธฐ์กด OmniRoute ์‘๋‹ต์ด ๊ทธ๋Œ€๋กœ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค. ### `x-omniroute-compression` ์š”์ฒญ๋ณ„ ์••์ถ• ๊ณ„ํš ์žฌ์ •์˜์ž…๋‹ˆ๋‹ค. ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๊ฐ€์žฅ ๋†’์œผ๋ฉฐ ๋ผ์šฐํŒ… ์กฐํ•ฉ ์žฌ์ •์˜, ํ™œ์„ฑ ํ”„๋กœํ•„, ์ž๋™ ํŠธ๋ฆฌ๊ฑฐ ๋ฐ ํŒจ๋„์˜ Default๋ณด๋‹ค ์šฐ์„ ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ’์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. | ๊ฐ’ | ํšจ๊ณผ | | ------------- | -------------------------------------------------------------------------------------- | | `off` | ์ด ์š”์ฒญ์—๋Š” ์••์ถ•์„ ์ ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. | | `default` | ํŒจ๋„์—์„œ ํŒŒ์ƒ๋œ Default ํ”„๋กœํ•„์ž…๋‹ˆ๋‹ค(ํ™œ์„ฑ ํ”„๋กœํ•„์„ ๋ฌด์‹œํ•จ). | | `engine:` | ํ™œ์„ฑํ™”๋œ ๊ฒฝ์šฐ ๋‹จ์ผ ์—”์ง„์ž…๋‹ˆ๋‹ค(์˜ˆ: `engine:rtk`). | | `` | ๋จผ์ € ์ด๋ฆ„์œผ๋กœ ๋Œ€์†Œ๋ฌธ์ž ๊ตฌ๋ถ„ ์—†์ด ์ผ์น˜์‹œํ‚ค๊ณ , ๊ทธ๋‹ค์Œ id๋กœ ์ผ์น˜์‹œํ‚ค๋Š” ๋ช…๋ช…๋œ ์กฐํ•ฉ์ž…๋‹ˆ๋‹ค. | ์ฐธ๊ณ : - ์•Œ ์ˆ˜ ์—†๋Š” ๊ฐ’์€ ๋ฌด์‹œ๋˜๋ฉฐ ์š”์ฒญ์€ ์ ˆ๋Œ€ ๊ฑฐ๋ถ€๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ•ด์„์€ ์ผ๋ฐ˜์ ์ธ ์—ฐ์‚ฐ์ž ์šฐ์„ ์ˆœ์œ„์— ๋”ฐ๋ผ ๊ณ„์† ์ง„ํ–‰๋ฉ๋‹ˆ๋‹ค. - ์—ฌ๋Ÿฌ ์กฐํ•ฉ์ด ๊ฐ™์€ ์ด๋ฆ„์„ ๊ณต์œ ํ•˜๋Š” ๊ฒฝ์šฐ ๊ฒฐ์ •๋ก ์ ์œผ๋กœ ์ผ์น˜์‹œํ‚ค๋ ค๋ฉด ์กฐํ•ฉ์˜ **id**๋ฅผ ์ „๋‹ฌํ•˜์‹ญ์‹œ์˜ค. - ์ด๋ฆ„์ด `off` ๋˜๋Š” `default`์ธ ์กฐํ•ฉ์€ ์ด๋ฆ„์œผ๋กœ ์„ ํƒํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ํ•ด๋‹น ํ‚ค์›Œ๋“œ๊ฐ€ ๋จผ์ € ํ•ด์„๋˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์กฐํ•ฉ์€ id๋กœ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค. - ๋งˆ์Šคํ„ฐ ์••์ถ• ์Šค์œ„์น˜๋Š” ์ ˆ๋Œ€์ ์ธ ๊ฒŒ์ดํŠธ์ž…๋‹ˆ๋‹ค. ์••์ถ•์ด ์ „์—ญ์ ์œผ๋กœ ๋น„ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์œผ๋ฉด ์ด ํ—ค๋”๋กœ ํ™œ์„ฑํ™”ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ ์šฉ๋œ ๊ณ„ํš์€ ์‘๋‹ต ํ—ค๋”์— ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค. ``` X-OmniRoute-Compression: ; source= ``` ์—ฌ๊ธฐ์„œ ``๋Š” `request-header`, `routing-override`, `active-profile`, `auto-trigger`, `default` ๋˜๋Š” `off` ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. --- ## ์ž„๋ฒ ๋”ฉ ```bash POST /v1/embeddings Authorization: Bearer your-api-key Content-Type: application/json { "model": "nebius/Qwen/Qwen3-Embedding-8B", "input": "The food was delicious" } ``` ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ œ๊ณต์—…์ฒด: Nebius, OpenAI, Mistral, Together AI, Fireworks, NVIDIA, **OpenRouter**, Jina AI. ์นดํƒˆ๋กœ๊ทธ ID๋Š” `provider/model` ํ˜•์‹์ž…๋‹ˆ๋‹ค(์˜ˆ: `jina-ai/jina-embeddings-v5-omni-small`). ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์— ํ‘œ์‹œ๋˜๋Š” Jina ๋ชจ๋ธ ID๋งŒ์œผ๋กœ๋„(์˜ˆ: `jina-embeddings-v5-text-small`, `jina-reranker-v3.5`) ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Jina์˜ ์ž„๋ฒ ๋”ฉ/์žฌ์ˆœ์œ„ํ™”/๋ถ„๋ฅ˜/๋ถ„ํ• ์€ ๋จผ์ € ๋Œ€์‹œ๋ณด๋“œ์˜ `jina-ai` ์ž๊ฒฉ ์ฆ๋ช…์„ ์‚ฌ์šฉํ•˜๋ฉฐ, ๋Œ€์‹œ๋ณด๋“œ ํ‚ค๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ์—๋งŒ `JINA_AI_API_KEY`๋ฅผ ๋Œ€์ฒด ์ˆ˜๋‹จ์œผ๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. `jina-reader` ์นด๋“œ๋Š” Reader / `r.jina.ai` ์ „์šฉ์ด๋ฉฐ(`POST /v1/web/fetch`), ์ž„๋ฒ ๋”ฉ์ด๋‚˜ ์žฌ์ˆœ์œ„ํ™”์—๋Š” ์‚ฌ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ฉ€ํ‹ฐ๋ชจ๋‹ฌ ์ง€์›์„ ๋ช…์‹œํ•˜๋Š” ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ๋ชจ๋ธ์€ ์ œ๊ณต์—…์ฒด์— ์ข…์†๋˜์ง€ ์•Š๋Š” ๊ตฌ์กฐํ™”๋œ ํ•ญ๋ชฉ๋„ ์ตœ๋Œ€ 32๊ฐœ๊นŒ์ง€ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋ฏธ๋””์–ด ํ•ญ๋ชฉ ์œ ํ˜•์€ `text`, `image`, `audio`, `video`, `document`์ž…๋‹ˆ๋‹ค. ํ•ด๋‹น ๋ฏธ๋””์–ด์˜ `source`๋Š” `{"type":"url","url":"https://..."}` ๋˜๋Š” `{"type":"base64","data":"...","media_type":"..."}`์ž…๋‹ˆ๋‹ค. Jina v5 Omni(`jina-ai/jina-embeddings-v5-omni-small`, `jina-ai/jina-embeddings-v5-omni-nano`, ๊ทธ๋ฆฌ๊ณ  ์ œํ’ˆ๊ตฐ ๋ณ„์นญ `jina-ai/jina-embeddings-v5-omni` โ†’ omni-small)๋Š” Jina์˜ ๋„ค์ดํ‹ฐ๋ธŒ EmbeddingsV5Request ๋ฌธ์„œ๋„ ํ—ˆ์šฉํ•˜๋ฉฐ, ์ด๋ฅผ `https://api.jina.ai/v1/embeddings`๋กœ **๋ณ€๊ฒฝ ์—†์ด ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค**: ```json { "model": "jina-ai/jina-embeddings-v5-omni-small", "task": "retrieval.query", "normalized": true, "input": [ { "text": "a red bicycle" }, { "image": "https://example.com/bike.png" }, { "content": [{ "text": "caption" }, { "image": "data:image/png;base64,..." }] } ] } ``` ๋„ค์ดํ‹ฐ๋ธŒ `{ image | audio | video | pdf }` ๊ฐ’์€ ๊ณต๊ฐœ HTTPS URL, `data:` URI ๋˜๋Š” ์›์‹œ base64์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. OmniRoute๋Š” ์ด๋Ÿฌํ•œ ๊ฐ์ฒด๋ฅผ ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ํ•˜๊ฑฐ๋‚˜ ๋„ค์ดํ‹ฐ๋ธŒ ์ด๋ฏธ์ง€ URL์„ ๊ฐ€์ ธ์˜ค์ง€ ์•Š์œผ๋ฉฐ, Jina๊ฐ€ ๊ณต๊ฐœ ๋ฏธ๋””์–ด๋ฅผ ์ง์ ‘ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. ์ถ”๊ฐ€ Jina ํ•„๋“œ(`task`, `normalized`, `truncate`, `embedding_type`)๋„ ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค. ํ…์ŠคํŠธ ์ „์šฉ Jina SKU๋Š” ์—ฌ์ „ํžˆ ํ…์ŠคํŠธ๊ฐ€ ์•„๋‹Œ ๋ฌธ์„œ๋ฅผ ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค. ๋ณด์•ˆ ๋ฐ ์ „์†ก ์ œํ•œ: - ์›๊ฒฉ ๋ฏธ๋””์–ด URL์€ ๊ณต๊ฐœ HTTPS์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ‘œ์ค€ `{type,source:url}` ํ•ญ๋ชฉ์€ ์„œ๋ฒ„ ์ธก์—์„œ ๊ฐ€์ ธ์˜จ ํ›„(๋ฆฌ๋””๋ ‰์…˜ ์žฌ๊ฒ€์ฆ, ์‹œ๊ฐ„ ์ œํ•œ, ํฌ๊ธฐ ์ œํ•œ, ๊ณต๊ฐœ DNS, ์—ฐ๊ฒฐ ๊ณ ์ •) ์ œ๊ณต์—…์ฒด ํ˜ธ์ถœ ์ „์— ์ธ๋ผ์ธ์œผ๋กœ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. Jina ๋„ค์ดํ‹ฐ๋ธŒ `{image:"https://..."}` ํ•ญ๋ชฉ์€ ๋™์ผํ•œ ๊ณต๊ฐœ HTTPS ๊ฒ€์‚ฌ๋ฅผ ๊ฑฐ์นœ ๋’ค ๊ทธ๋Œ€๋กœ ์ „๋‹ฌ๋˜๋ฉฐ, Jina๊ฐ€ URL์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. - ์ธ๋ผ์ธ base64 ๋ฏธ๋””์–ด๋Š” ํ•ญ๋ชฉ๋‹น ๋””์ฝ”๋”ฉ ํ›„ 8 MiB, ์š”์ฒญ ์ „์ฒด์—์„œ ๋””์ฝ”๋”ฉ ํ›„ 16 MiB๋กœ ์ œํ•œ๋ฉ๋‹ˆ๋‹ค. ์ œ๊ณต์—…์ฒด ๋ณ€ํ™˜(ํ‘œ์ค€ ํ•ญ๋ชฉ์€ ๋ณ€๊ฒฝ ์—†์ด ์ „๋‹ฌ๋˜์ง€ ์•Š์Œ): - Jina ๋ฉ€ํ‹ฐ๋ชจ๋‹ฌ ๋ชจ๋ธ: ๊ฐ ์ตœ์ƒ์œ„ ํ•ญ๋ชฉ์€ ์ธ๋ผ์ธ ๋ฏธ๋””์–ด์— ๋ฐ์ดํ„ฐ URI๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•˜๋‚˜์˜ ๋ชจ๋‹ฌ๋ฆฌํ‹ฐ ํ‚ค ๊ฐ์ฒด(`text` / `image` / `audio` / `video` / `pdf`)๊ฐ€ ๋˜๋ฉฐ, ์ตœ์ƒ์œ„ ํ•ญ๋ชฉ๋‹น ํ•˜๋‚˜์˜ ๋ฒกํ„ฐ๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. - Gemini Embedding 2 ์ œํ’ˆ๊ตฐ: ํ•˜๋‚˜์˜ ์ตœ์ƒ์œ„ ๋ฐฐ์—ด์€ `content.parts`(`text` ๋˜๋Š” `inline_data`)๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋‹จ์ผ ๋„ค์ดํ‹ฐ๋ธŒ `models/{model}:embedContent` ์š”์ฒญ์ด ๋ฉ๋‹ˆ๋‹ค. - ๋ช…์‹œ์ ์ธ ๋ชจ๋‹ฌ๋ฆฌํ‹ฐ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋Š” ์•Œ ์ˆ˜ ์—†๋Š”/๋™์  ๋ชจ๋ธ์€ ๊ตฌ์กฐํ™”๋œ ์ž…๋ ฅ์„ HTTP 400์œผ๋กœ ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค. ```json { "model": "jina-ai/jina-embeddings-v5-omni-small", "input": [ { "type": "text", "text": "A red bicycle" }, { "type": "image", "source": { "type": "url", "url": "https://example.com/bicycle.png" } } ], "dimensions": 512, "encoding_format": "float" } ``` ์ง€์›๋˜์ง€ ์•Š๋Š” ๋ชจ๋ธ/๋ชจ๋‹ฌ๋ฆฌํ‹ฐ ์กฐํ•ฉ์€ ํ•ญ๋ชฉ์„ ๊ฐ•์ œ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๋Œ€์‹  HTTP 400์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๋ ˆ๊ฑฐ์‹œ ๋ฌธ์ž์—ด/ํ† ํฐ ์š”์ฒญ์˜ ์ž…๋ ฅ ์ด์™ธ ํ™•์žฅ ํ•„๋“œ๋Š” ์ด์ „๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋ณ€๊ฒฝ ์—†์ด ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค. ```bash # ๋ชจ๋“  ์ž„๋ฒ ๋”ฉ ๋ชจ๋ธ ๋‚˜์—ด GET /v1/embeddings ``` --- ## ์ด๋ฏธ์ง€ ์ƒ์„ฑ ```bash POST /v1/images/generations Authorization: Bearer your-api-key Content-Type: application/json { "model": "openai/gpt-image-2", "prompt": "์‚ฐ ๋„ˆ๋จธ๋กœ ํŽผ์ณ์ง€๋Š” ์•„๋ฆ„๋‹ค์šด ์ผ๋ชฐ", "size": "1024x1024" } ``` ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ œ๊ณต์ž: OpenAI (GPT Image 2), xAI (Grok Image), Together AI (FLUX), Fireworks AI, Nebius (FLUX), Hyperbolic, NanoBanana, **OpenRouter**, SD WebUI (๋กœ์ปฌ), ComfyUI (๋กœ์ปฌ). ```bash # ๋ชจ๋“  ์ด๋ฏธ์ง€ ๋ชจ๋ธ ๋‚˜์—ด GET /v1/images/generations ``` --- ## ๋ฌธ์„œ OCR ```bash POST /v1/ocr Authorization: Bearer your-api-key Content-Type: application/json { "model": "mistral/mistral-ocr-latest", "document": { "type": "document_url", "document_url": "https://example.com/invoice.pdf" } } ``` `model`์€ `provider/model` ์ ‘๋‘์‚ฌ๋ฅผ ํ†ตํ•ด OCR ์ œ๊ณต์ž๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค. ์ œ๊ณต์ž ์ ‘๋‘์‚ฌ๊ฐ€ ์—†๋Š” ๋ชจ๋ธ ID(์˜ˆ: `mistral-ocr-latest`)๋Š” ๋“ฑ๋ก๋œ ์ œ๊ณต์ž๋กœ ํ™•์ธ๋˜๋ฉฐ, `model`์„ ์ƒ๋žตํ•˜๋ฉด ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ Mistral(`mistral-ocr-latest`)์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ๋“ฑ๋ก๋œ ์ œ๊ณต์ž(`open-sse/config/ocrRegistry.ts`): | ์ œ๊ณต์ž ID | ๋ชจ๋ธ ID | `model` ๊ฐ’ | ์ฐธ๊ณ  | | ----------------------------- | -------------------- | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | | `mistral` | `mistral-ocr-latest` | `mistral/mistral-ocr-latest` (๋˜๋Š” `mistral-ocr-latest`) | ๋™๊ธฐ์‹ โ€” ๋‹จ์ผ ์—…์ŠคํŠธ๋ฆผ ํ˜ธ์ถœ์˜ ์‘๋‹ต์ด ์ง์ ‘ ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค. | | `azure-document-intelligence` | `prebuilt-read` | `azure-document-intelligence/prebuilt-read` | ๋น„๋™๊ธฐ ์—…์ŠคํŠธ๋ฆผ(`analyze` + ํด๋ง) โ€” ์•„๋ž˜๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”. | | `vertex-deepseek-ocr` | `deepseek-ocr-maas` | `vertex-deepseek-ocr/deepseek-ocr-maas` | Vertex AI์˜ `openapi/chat/completions` ํŒŒํŠธ๋„ˆ ์—”๋“œํฌ์ธํŠธ๋ฅผ ํ†ตํ•œ ๋™๊ธฐ์‹ ๋ฐฉ์‹ โ€” ์ธ์ฆ/URL์€ ์•„๋ž˜๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”. | ์„ธ ์ œ๊ณต์ž ๋ชจ๋‘ ๋™์ผํ•œ Mistral ํ˜•์‹์˜ ๋ณธ๋ฌธ์œผ๋กœ ์‘๋‹ตํ•ฉ๋‹ˆ๋‹ค. ```json { "pages": [{ "index": 0, "markdown": "# ์ถ”์ถœ๋œ ํ…์ŠคํŠธ..." }], "model": "mistral-ocr-latest", "usage_info": { "pages_processed": 1 } } ``` ### Azure Document Intelligence ํด๋ง ํ๋ฆ„ Azure Document Intelligence์˜ `analyze` API๋Š” ๋น„๋™๊ธฐ์‹์ž…๋‹ˆ๋‹ค. ์ดˆ๊ธฐ ์š”์ฒญ์€ ๋ณธ๋ฌธ ๋Œ€์‹  `Operation-Location` ํ—ค๋”๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ, ๊ฒฐ๊ณผ๋ฅผ ์–ป์œผ๋ ค๋ฉด ํด๋งํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ•ธ๋“ค๋Ÿฌ (`open-sse/handlers/ocr.ts`)๋Š” ํ•ด๋‹น URL์„ 1์ดˆ๋งˆ๋‹ค ์ตœ๋Œ€ 30ํšŒ ํด๋งํ•˜๊ณ , `ok`๊ฐ€ ์•„๋‹Œ ํด๋ง ์‘๋‹ต์ด๋‚˜ `"failed"` ์ƒํƒœ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์ฆ‰์‹œ ์‹คํŒจ ์ฒ˜๋ฆฌํ•˜๋ฉฐ(ํด๋ง์„ ๊ณ„์†ํ•˜์ง€ ์•Š์Œ), ์‹œ๋„ ํšŸ์ˆ˜๋ฅผ ๋ชจ๋‘ ์†Œ์ง„ํ•œ ํ›„์—๋„ ์ž‘์—…์ด ๊ณ„์† ์‹คํ–‰ ์ค‘์ด๋ฉด `504`๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ตœ์ข… Azure ์‘๋‹ต์€ ํ˜ธ์ถœ์ž์—๊ฒŒ ๋ฐ˜ํ™˜๋˜๊ธฐ ์ „์— Mistral์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ ๋™์ผํ•œ `pages`/`markdown` ํ˜•์‹์œผ๋กœ ์ •๊ทœํ™”๋˜๋ฏ€๋กœ, ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ์—์„œ ์ œ๊ณต์ž๋ณ„๋กœ ๋ณ„๋„ ์ฒ˜๋ฆฌํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ### Vertex AI DeepSeek OCR ์ธ์ฆ ๋ฐ ์—”๋“œํฌ์ธํŠธ ํ™•์ธ `vertex-deepseek-ocr`์€ ์ฑ„ํŒ…/์ด๋ฏธ์ง€ ํŠธ๋ž˜ํ”ฝ์— ๋Œ€ํ•ด OmniRoute๊ฐ€ ์ด๋ฏธ ์ง€์›ํ•˜๋Š” ๊ฒƒ๊ณผ ๋™์ผํ•œ Vertex AI ์ธ์ฆ(`open-sse/executors/vertex.ts`)์„ ์žฌ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์—ฐ๊ฒฐ์˜ API ํ‚ค๋Š” Service Account JSON ์ž๊ฒฉ ์ฆ๋ช…(JWT bearer ํ๋ฆ„์„ ํ†ตํ•ด ์ˆ˜๋ช…์ด ์งง์€ OAuth ์•ก์„ธ์Šค ํ† ํฐ์œผ๋กœ ๊ตํ™˜๋จ)์ด๊ฑฐ๋‚˜, ๋ฐœ๊ธ‰ ์™„๋ฃŒ๋œ OAuth ์•ก์„ธ์Šค ํ† ํฐ(๊ทธ๋Œ€๋กœ ์‚ฌ์šฉ๋จ)์ž…๋‹ˆ๋‹ค. ์—…์ŠคํŠธ๋ฆผ ์—”๋“œํฌ์ธํŠธ URL์€ ์—ฐ๊ฒฐ์˜ ํ”„๋กœ์ ํŠธ์™€ ๋ฆฌ์ „์œผ๋กœ ๊ตฌ์„ฑ๋˜๋Š” Vertex์˜ ๋ฒ”์šฉ `openapi/chat/completions` ํŒŒํŠธ๋„ˆ ์—”๋“œํฌ์ธํŠธ์ž…๋‹ˆ๋‹ค. ๋ช…์‹œ์ ์ธ `providerSpecificData.project`/`providerSpecificData.region`์ด ํ•ญ์ƒ ์šฐ์„ ํ•˜๋ฉฐ, ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ํ”„๋กœ์ ํŠธ๋Š” Service Account JSON์˜ `project_id`์—์„œ ๊ฐ€์ ธ์˜ค๊ณ  ๋ฆฌ์ „์€ ๊ธฐ๋ณธ์ ์œผ๋กœ `us-central1`๋กœ ์„ค์ •๋ฉ๋‹ˆ๋‹ค. ๋‘ ํ™•์ธ ์ž‘์—… ๋ชจ๋‘ `open-sse/handlers/ocr.ts` (`resolveVertexOcrAccessToken`, `resolveVertexOcrBaseUrl`)์—์„œ ์ˆ˜ํ–‰๋˜๋ฉฐ, `handleOcr`์— ์ „๋‹ฌํ•˜๊ธฐ ์ „์— `src/app/api/v1/ocr/route.ts`์—์„œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. --- ## ๋ชจ๋ธ ๋ชฉ๋ก ์กฐํšŒ ```bash GET /v1/models Authorization: Bearer your-api-key โ†’ OpenAI ํ˜•์‹์œผ๋กœ ๋ชจ๋“  ์ฑ„ํŒ…, ์ž„๋ฒ ๋”ฉ ๋ฐ ์ด๋ฏธ์ง€ ๋ชจ๋ธ๊ณผ ์กฐํ•ฉ์„ ๋ฐ˜ํ™˜ ``` ### ๋ชจ๋ธ ID ์ ‘๋‘์‚ฌ (`?prefix=`) ๋Œ€๋ถ€๋ถ„์˜ ๋ชจ๋ธ์€ **์ œ๊ณต์ž ์ ‘๋‘์‚ฌ** ์•„๋ž˜์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ์–ด๋–ค ์ ‘๋‘์‚ฌ๋ฅผ ์‚ฌ์šฉํ• ์ง€๋Š” `MODELS_CATALOG_PREFIX_MODE` ๊ธฐ๋Šฅ ํ”Œ๋ž˜๊ทธ๋กœ ์ œ์–ดํ•˜๋ฉฐ, ์ฟผ๋ฆฌ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด **์š”์ฒญ๋ณ„๋กœ** ์žฌ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋‹ค๋ฅธ ๋ชจ๋“  ์‚ฌ์šฉ์ž์˜ ์„œ๋ฒ„ ์ „์ฒด ์„ค์ •์„ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  ๊น”๋”ํ•œ ๋ชฉ๋ก์„ ์›ํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ์— ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ```bash GET /v1/models?prefix=alias # ๋ชจ๋ธ๋‹น ํ•˜๋‚˜์˜ ID โ€” ์งง์€ ๋ณ„์นญ ์ ‘๋‘์‚ฌ GET /v1/models?prefix=dual # ๋‘ ํ˜•์‹ ๋ชจ๋‘(์„œ๋ฒ„ ๊ธฐ๋ณธ๊ฐ’) GET /v1/models?prefix=canonical # ์ „์ฒด ์ œ๊ณต์ž ID ์ ‘๋‘์‚ฌ๋งŒ ``` | ๋ชจ๋“œ | ์ถœ๋ ฅ | ์ฐธ๊ณ  | | ----------- | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `dual` | `cc/claude-sonnet-4-6` **๋ฐ** `claude/claude-sonnet-4-6` | **๊ธฐ๋ณธ๊ฐ’์ž…๋‹ˆ๋‹ค.** ๋‘ ID ๋ชจ๋‘ ๋™์ผํ•œ ๋ชจ๋ธ๋กœ ๋ผ์šฐํŒ…๋˜๋ฉฐ, ๋‘ ํ˜•์‹ ์ค‘ ํ•˜๋‚˜๋ฅผ ํ•˜๋“œ์ฝ”๋”ฉํ•œ ํด๋ผ์ด์–ธํŠธ ์„ค์ •์ด ๊ณ„์† ์ž‘๋™ํ•˜๋„๋ก ์œ ์ง€๋ฉ๋‹ˆ๋‹ค. ์นดํƒˆ๋กœ๊ทธ ํฌ๊ธฐ๊ฐ€ ๋Œ€๋žต ๋‘ ๋ฐฐ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. | | `alias` | `cc/claude-sonnet-4-6` | ๋ชจ๋ธ๋‹น ํ•˜๋‚˜์˜ ํ•ญ๋ชฉ์ž…๋‹ˆ๋‹ค. ๊ณ ์œ ํ•œ ๋ณ„์นญ์ด ์—†๋Š” ์ œ๊ณต์ž๋„ ํ•ด๋‹น ํ•ญ๋ชฉ์„ ๊ณ„์† ์ถœ๋ ฅํ•˜๋ฏ€๋กœ ๋ˆ„๋ฝ๋˜๋Š” ๊ฒƒ์€ ์—†์Šต๋‹ˆ๋‹ค. | | `canonical` | `claude/claude-sonnet-4-6` | ์ „์ฒด ์ œ๊ณต์ž ID ์ ‘๋‘์‚ฌ ์•„๋ž˜์— ๋ชจ๋ธ๋‹น ํ•˜๋‚˜์˜ ํ•ญ๋ชฉ์„ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค. ๊ณ ์œ ํ•œ ๋ณ„์นญ์ด ์—†๋Š” ์ œ๊ณต์ž(์˜ˆ: `antigravity/โ€ฆ`, `agy/โ€ฆ`)๋„ ์—ฌ๊ธฐ์—์„œ ๋‹จ์ผ ID๋ฅผ ์ถœ๋ ฅํ•˜๋ฏ€๋กœ ๋ˆ„๋ฝ๋˜๋Š” ๊ฒƒ์€ ์—†์Šต๋‹ˆ๋‹ค. | `dual` ๋ชจ๋“œ ๋ฏธ๋Ÿฌ๋Š” ์ฟผ๋ฆฌ ๋งค๊ฐœ๋ณ€์ˆ˜ ์—†์ด๋„ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ID๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” `parent` ํ•„๋“œ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋ชจ๋ธ ์„ ํƒ๊ธฐ๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ๋Š” `?prefix=alias`๋ฅผ ์š”์ฒญํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” [OmniCopilot VS Code ํ™•์žฅ ํ”„๋กœ๊ทธ๋žจ](../guides/VSCODE-COPILOT.md)์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ### ๋น„์‚ฌ๊ณ  ๋ชจ๋ธ ๋ณ€ํ˜• ์‚ฌ๊ณ  ๊ธฐ๋Šฅ์„ ์ง€์›ํ•˜๋Š” Claude ๋ชจ๋ธ์˜ ๊ฒฝ์šฐ `/v1/models`๋Š” ID ์•ž์— `claude-3-omniroute-no-thinking/`์ด ๋ถ™์€ **๋น„์‚ฌ๊ณ ** ๋ณ€ํ˜•๋„ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค. ``` claude-3-omniroute-no-thinking// ``` ์ด ID๋ฅผ ์„ ํƒํ•˜๋ฉด(์˜ˆ: ํ•ญ์ƒ `thinking` ๋ธ”๋ก์„ ์ฒจ๋ถ€ํ•˜๋Š” Claude Code ์„ค์ •์—์„œ) ์ถ”๋ก ์ด ์–ต์ œ๋œ ์‹ค์ œ `/`๋กœ ๋‹ค์‹œ ํ•ด์„๋ฉ๋‹ˆ๋‹ค. `/v1/messages` ๊ฒฝ๋กœ์—์„œ๋Š” `thinking:{type:"disabled"}`๊ฐ€ ์ ์šฉ๋˜๊ณ , `/v1/chat/completions` ๊ฒฝ๋กœ์—์„œ๋Š” `reasoning`/`reasoning_effort` ํ•„๋“œ๊ฐ€ ์ œ๊ฑฐ๋ฉ๋‹ˆ๋‹ค. ์ด ๋ณ€ํ˜•์€ ์‚ฌ๊ณ  ๊ธฐ๋Šฅ์„ ์ง€์›ํ•˜๋ฉด์„œ **๋™์‹œ์—** `disabled`๋ฅผ ์ค€์ˆ˜ํ•˜๋Š” Claude ๊ณ„์—ด ๋ชจ๋ธ์—๋งŒ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค(๋”ฐ๋ผ์„œ ์˜ˆ๋ฅผ ๋“ค์–ด `disabled`๋ฅผ ๊ฑฐ๋ถ€ํ•˜๊ณ  ์ ์‘ํ˜• ๋ชจ๋“œ๋งŒ ์ง€์›ํ•˜๋Š” ๋ชจ๋ธ์€ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค). ์šด์˜์ž๋Š” `ModelSpec.noThinkingAlias`๋ฅผ ํ†ตํ•ด ๋ชจ๋ธ๋ณ„๋กœ ์ด ๋ณ€ํ˜•์„ ๊ฐ•์ œ๋กœ ํ™œ์„ฑํ™”ํ•˜๊ฑฐ๋‚˜ ๋น„ํ™œ์„ฑํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. --- ## ์ œ๊ณต์ž ํ”Œ๋Ÿฌ๊ทธ์ธ ๋งค๋‹ˆํŽ˜์ŠคํŠธ ```bash GET /api/v1/provider-plugin-manifest ``` Bifrost, CLIProxyAPI ๋ฐ ํ–ฅํ›„ ์‚ฌ์ด๋“œ์นด ๋ผ์šฐํ„ฐ์—์„œ ์‚ฌ์šฉํ•˜๋Š” JSON ์•ˆ์ „ ์ œ๊ณต์ž ํ”Œ๋Ÿฌ๊ทธ์ธ ๋งค๋‹ˆํŽ˜์ŠคํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์‘๋‹ต์€ TypeScript ์ œ๊ณต์ž ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์—์„œ ์ƒ์„ฑ๋˜๋ฉฐ OAuth ํด๋ผ์ด์–ธํŠธ ์‹œํฌ๋ฆฟ, ๋Ÿฐํƒ€์ž„ ํ™˜๊ฒฝ ํ•ด์„, ์‹คํ–‰์ž ํ•จ์ˆ˜, ์š”์ฒญ ํ—ค๋” ๋ฐ ๊ณ„์ • ๋ฐ์ดํ„ฐ๋Š” ์˜๋„์ ์œผ๋กœ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. ์‚ฌ์ด๋“œ์นด๊ฐ€ ๋ณ„๋„ ํ”„๋กœ์„ธ์Šค๋กœ ์‹คํ–‰๋˜์–ด `open-sse/config/providerPluginManifestRegistry.ts`๋ฅผ ์ง์ ‘ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ ์ด ์—”๋“œํฌ์ธํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”. --- ## ํ˜ธํ™˜์„ฑ ์—”๋“œํฌ์ธํŠธ | ๋ฉ”์„œ๋“œ | ๊ฒฝ๋กœ | ํ˜•์‹ | | ------ | ----------------------------------------- | -------------------------------- | | POST | `/v1/chat/completions` | OpenAI | | POST | `/v1/messages` | Anthropic | | POST | `/v1/responses` | OpenAI Responses | | POST | `/v1/embeddings` | OpenAI | | POST | `/v1/images/generations` | OpenAI Images | | POST | `/v1/images/edits` | OpenAI Images(ํŽธ์ง‘/์ธํŽ˜์ธํŒ…) | | POST | `/v1/videos/generations` | OpenAI ์Šคํƒ€์ผ ๋น„๋””์˜ค ์ƒ์„ฑ | | POST | `/v1/music/generations` | OpenAI ์Šคํƒ€์ผ ์Œ์•… ์ƒ์„ฑ | | POST | `/v1/audio/transcriptions` | OpenAI Audio(STT) | | POST | `/v1/audio/speech` | OpenAI TTS(์˜ค๋””์˜ค ๋ณธ๋ฌธ ๋ฐ˜ํ™˜) | | POST | `/v1/rerank` | Cohere/Voyage ์Šคํƒ€์ผ ์žฌ์ˆœ์œ„ํ™” | | POST | `/v1/classify` | Jina ๋ถ„๋ฅ˜(`api.jina.ai`) | | POST | `/v1/segment` | Jina ์„ธ๊ทธ๋จผํ„ฐ(`segment.jina.ai`) | | POST | `/v1/moderations` | OpenAI Moderations | | GET | `/v1/models` | OpenAI | | POST | `/v1/messages/count_tokens` | Anthropic | | GET | `/v1beta/models` | Gemini | | POST | `/v1beta/models/{...path}` | Gemini generateContent | | POST | `/v1/api/chat` | Ollama | | GET | `/api/v1/vscode/{token}/` | OpenAI ์นดํƒˆ๋กœ๊ทธ ๋ณ„์นญ | | GET | `/api/v1/vscode/{token}/models` | OpenAI ๋ชจ๋ธ ๋ณ„์นญ | | POST | `/api/v1/vscode/{token}/chat/completions` | OpenAI ํ† ํฐํ™” ๋ณ„์นญ | | POST | `/api/v1/vscode/{token}/responses` | OpenAI Responses ํ† ํฐํ™” ๋ณ„์นญ | | POST | `/api/v1/vscode/{token}/api/chat` | Ollama ํ† ํฐํ™” ๋ณ„์นญ | | GET | `/api/v1/vscode/{token}/api/tags` | Ollama ํƒœ๊ทธ ํ† ํฐํ™” ๋ณ„์นญ | ๋ชจ๋“  POST ๋ผ์šฐํŠธ๋Š” `Bearer your-api-key` + Zod๋กœ ๊ฒ€์ฆ๋œ JSON ๋ณธ๋ฌธ(`v1RerankSchema`, `v1ModerationSchema`, `v1AudioSpeechSchema` ๋“ฑ, `src/shared/validation/schemas.ts` ์ฐธ์กฐ)์ด๋ผ๋Š” ๋™์ผํ•œ ํ˜•์‹์„ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค. ์Šคํ‚ค๋งˆ ๊ฒ€์ฆ์— ์‹คํŒจํ•˜๋ฉด 4xx๊ฐ€ ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค. `Authorization: Bearer ...`๋ฅผ ์ฒจ๋ถ€ํ•  ์ˆ˜ ์—†๋Š” ํด๋ผ์ด์–ธํŠธ๋ฅผ ์œ„ํ•ด OmniRoute๋Š” ์ฟผ๋ฆฌ ๋ฌธ์ž์—ด ํ˜ธํ™˜ ๋ฐฉ์‹(`?token=...`, `?apiKey=...`, `?api_key=...`, `?key=...`)์ด๋‚˜ ์•„๋ž˜์— ์„ค๋ช…๋œ ์ „์šฉ `/api/v1/vscode/{token}/...` ์—”๋“œํฌ์ธํŠธ๋ฅผ ํ†ตํ•ด URL์˜ API ํ‚ค๋„ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค. ```bash # ์žฌ์ˆœ์œ„ํ™” POST /v1/rerank { "model": "jina-ai/jina-reranker-v3.5", "query": "...", "documents": ["..."] } # Jina ๋ถ„๋ฅ˜(Foundation API ์ž๊ฒฉ ์ฆ๋ช…) POST /v1/classify { "model": "jina-embeddings-v5-text-small", "input": ["..."], "labels": ["a", "b"] } # Jina ์„ธ๊ทธ๋จผํ„ฐ POST /v1/segment { "content": "...", "return_chunks": true } # Jina ๊ฒ€์ƒ‰(s.jina.ai; ์ œ๊ณต์ž ๋ณ„์นญ: jina-search, jina-ai, jina) POST /v1/search { "query": "...", "provider": "jina-search" } # ์กฐ์ • POST /v1/moderations { "model": "omni-moderation-latest", "input": "..." } # TTS โ€” audio/mpeg(๋˜๋Š” ์š”์ฒญ๋œ ํ˜•์‹) ๋ณธ๋ฌธ ๋ฐ˜ํ™˜ POST /v1/audio/speech { "model": "openai/tts-1", "input": "Hello", "voice": "alloy" } # ์ด๋ฏธ์ง€ ํŽธ์ง‘(multipart) POST /v1/images/edits -F image=@input.png -F prompt="..." -F mask=@mask.png # ๋น„๋””์˜ค/์Œ์•… ์ƒ์„ฑ(์ œ๊ณต์ž ์ ‘๋‘์‚ฌ๊ฐ€ ๋ถ™์€ ๋ชจ๋ธ ID) POST /v1/videos/generations { "model": "runway/gen-3", "prompt": "..." } POST /v1/music/generations { "model": "suno/v3.5", "prompt": "..." } ``` ### ์ „์šฉ ์ œ๊ณต์ž ๋ผ์šฐํŠธ ```bash POST /v1/providers/{provider}/chat/completions POST /v1/providers/{provider}/embeddings POST /v1/providers/{provider}/images/generations ``` ์ œ๊ณต์ž ์ ‘๋‘์‚ฌ๊ฐ€ ์—†์œผ๋ฉด ์ž๋™์œผ๋กœ ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค. ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๋ชจ๋ธ์€ `400`์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. --- ## Files API ๋ฐฐ์น˜ ์ž…๋ ฅ/์ถœ๋ ฅ ๋ฐ ํŒŒ์ผ ์šฉ๋„๋ณ„ ์—…๋กœ๋“œ๋ฅผ ์œ„ํ•œ OpenAI ํ˜ธํ™˜ ํŒŒ์ผ ์—”๋“œํฌ์ธํŠธ์ž…๋‹ˆ๋‹ค. | ๋ฉ”์„œ๋“œ | ๊ฒฝ๋กœ | ์„ค๋ช… | | ------ | ------------------------ | ----------------------------------------------------------------------------------------------------------- | | POST | `/v1/files` | ํŒŒ์ผ ์—…๋กœ๋“œ(multipart: `file`, `purpose`, `expires_after[anchor]`, `expires_after[seconds]`) โ€” ์ตœ๋Œ€ 512 MiB | | GET | `/v1/files` | ์ธ์ฆ๋œ API ํ‚ค์˜ ํŒŒ์ผ ๋ชฉ๋ก ์กฐํšŒ | | GET | `/v1/files/[id]` | ํŒŒ์ผ์˜ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์กฐํšŒ | | DELETE | `/v1/files/[id]` | ํŒŒ์ผ ์‚ญ์ œ | | GET | `/v1/files/[id]/content` | ์›์‹œ ํŒŒ์ผ ๋ณธ๋ฌธ์„ ์ŠคํŠธ๋ฆฌ๋ฐํ•˜์—ฌ ๋ฐ˜ํ™˜ | **์ธ์ฆ:** Bearer API ํ‚ค โ€” ํŒŒ์ผ์€ `getApiKeyRequestScope`๋ฅผ ํ†ตํ•ด API ํ‚ค๋ณ„๋กœ ๋ฒ”์œ„๊ฐ€ ์ง€์ •๋ฉ๋‹ˆ๋‹ค. ํ‚ค๋Š” ์ž์‹ ์˜ ํŒŒ์ผ๋งŒ ์กฐํšŒ, ๋‹ค์šด๋กœ๋“œ ๋ฐ ์‚ญ์ œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ‚ค๊ฐ€ ์—†๋Š” ๋Œ€์‹œ๋ณด๋“œ ์„ธ์…˜์€ ์ „์ฒด ์ธ์Šคํ„ด์Šค๋ฅผ ์กฐํšŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์†Œ์œ ์ž๊ฐ€ ์—†๋Š” ํŒŒ์ผ(์ต๋ช… ๋˜๋Š” ๋Œ€์‹œ๋ณด๋“œ ์„ธ์…˜ ์—…๋กœ๋“œ)์€ ๋ชจ๋“  ๋น„์„ธ์…˜ ํ˜ธ์ถœ์ž์˜ ์ ‘๊ทผ์ด ๊ฑฐ๋ถ€๋ฉ๋‹ˆ๋‹ค. `GET /v1/files`๋Š” `REQUIRE_API_KEY=false`์ธ ๊ฒฝ์šฐ์—๋„ ๋ชจ๋“  ํ…Œ๋„ŒํŠธ์˜ ํŒŒ์ผ์„ ๋‚˜์—ดํ•˜๋Š” ๋Œ€์‹ , ์ต๋ช… ํ˜ธ์ถœ์ž ๋ฐ ์ œ๊ณต๋˜์—ˆ์ง€๋งŒ ํ™•์ธ๋˜์ง€ ์•Š๋Š” ํ‚ค์— ๋Œ€ํ•ด `401`์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค (GHSA-m3hp-hq9g-fpmv, GHSA-2jm2-mpx8-6523). --- ## Batches API OpenAI ํ˜ธํ™˜ ๋ฐฐ์น˜ ์ฒ˜๋ฆฌ์ž…๋‹ˆ๋‹ค. | ๋ฉ”์„œ๋“œ | ๊ฒฝ๋กœ | ์„ค๋ช… | | ------ | ------------------------- | ----------------------------------------------------------------------------------------------- | | POST | `/v1/batches` | ๋ฐฐ์น˜ ์ƒ์„ฑ โ€” `v1BatchCreateSchema`๋กœ ๋ณธ๋ฌธ ๊ฒ€์ฆ(`input_file_id`, `endpoint`, `completion_window`) | | GET | `/v1/batches` | ๋ฐฐ์น˜ ๋ชฉ๋ก ์กฐํšŒ | | GET | `/v1/batches/[id]` | ๋ฐฐ์น˜ ์ƒํƒœ + `request_counts` ์กฐํšŒ | | DELETE | `/v1/batches/[id]` | ์™„๋ฃŒ/์‹คํŒจํ•œ ๋ฐฐ์น˜ ์‚ญ์ œ | | POST | `/v1/batches/[id]/cancel` | ์ง„ํ–‰ ์ค‘์ธ ๋ฐฐ์น˜ ์ทจ์†Œ | **์ธ์ฆ:** Bearer API ํ‚ค. ๋ฐฐ์น˜๋Š” ํŒŒ์ผ๊ณผ ๋™์ผํ•œ 3๊ฐ€์ง€ ๊ทœ์น™์— ๋”ฐ๋ผ API ํ‚ค๋ณ„๋กœ ๋ฒ”์œ„๊ฐ€ ์ง€์ •๋ฉ๋‹ˆ๋‹ค. ์ž์‹ ์˜ ํ‚ค์— ์†ํ•œ ํ•ญ๋ชฉ๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜๊ณ , ๋Œ€์‹œ๋ณด๋“œ ์„ธ์…˜์€ ์ธ์Šคํ„ด์Šค ์ „์ฒด์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์†Œ์œ ์ž๊ฐ€ null์ธ ๋ ˆ์ฝ”๋“œ๋Š” ๋ชจ๋“  ๋น„์„ธ์…˜ ํ˜ธ์ถœ์ž์˜ ์ ‘๊ทผ์ด ๊ฑฐ๋ถ€๋ฉ๋‹ˆ๋‹ค(์กฐํšŒ, ์‚ญ์ œ, ์ทจ์†Œ ๋ฐ ์ƒ์„ฑ ์‹œ `input_file_id` ํ™•์ธ). `GET /v1/batches`๋Š” `REQUIRE_API_KEY=false`์ธ ๊ฒฝ์šฐ์—๋„ ์ต๋ช… ํ˜ธ์ถœ์ž์—๊ฒŒ `401`์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. --- ## ๊ฒ€์ƒ‰ API ์›น/๊ฒ€์ƒ‰ ์ œ๊ณต์ž ์ถ”์ƒํ™”(Tavily, Brave, Exa, Serper ๋“ฑ). | ๋ฉ”์„œ๋“œ | ๊ฒฝ๋กœ | ์„ค๋ช… | | ------ | ---------------------- | ------------------------------------------------------------------ | | GET | `/v1/search` | ๊ตฌ์„ฑ๋œ ๊ฒ€์ƒ‰ ์ œ๊ณต์ž ๋ฐ ๊ธฐ๋Šฅ ๋ชฉ๋ก ์กฐํšŒ | | POST | `/v1/search` | ๊ฒ€์ƒ‰ ์ฟผ๋ฆฌ ์‹คํ–‰ โ€” ๋ณธ๋ฌธ์€ `v1SearchSchema`๋กœ ๊ฒ€์ฆ๋˜๋ฉฐ ์บ์‹ฑ/๋ณ‘ํ•ฉ ์ง€์› | | GET | `/v1/search/analytics` | ์ œ๊ณต์ž๋ณ„ ์ ์ค‘๋ฅ /์ง€์—ฐ ์‹œ๊ฐ„/์บ์‹œ ํ†ต๊ณ„ | **์ธ์ฆ:** Bearer API ํ‚ค(`extractApiKey` + `isValidApiKey`). ๊ฒ€์ƒ‰ ์ •์ฑ…์€ `enforceApiKeyPolicy`๋ฅผ ํ†ตํ•ด ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. --- ## ์›น ๊ฐ€์ ธ์˜ค๊ธฐ API ๊ตฌ์„ฑ๋œ ์›น ๊ฐ€์ ธ์˜ค๊ธฐ ์ œ๊ณต์ž(Firecrawl, Jina Reader, Tavily Extract, TinyFish Fetch, Nimble Extract)๋ฅผ ํ†ตํ•ด URL์—์„œ ์ฝ˜ํ…์ธ ๋ฅผ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค. | ๋ฉ”์„œ๋“œ | ๊ฒฝ๋กœ | ์„ค๋ช… | | ------ | --------------- | ------------------------------------------------------------ | | POST | `/v1/web/fetch` | URL ๊ฐ€์ ธ์˜ค๊ธฐ/์Šคํฌ๋ ˆ์ดํ•‘ โ€” ๋ณธ๋ฌธ์€ `v1WebFetchSchema`๋กœ ๊ฒ€์ฆ๋จ | **์ธ์ฆ:** Bearer API ํ‚ค(`extractApiKey` + `isValidApiKey`). ์ •์ฑ…์€ `enforceApiKeyPolicy`๋ฅผ ํ†ตํ•ด ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. **ํ• ๋‹น๋Ÿ‰ ์ธ์‹ ํด๋ฐฑ(#8297):** ๋ช…์‹œ์ ์ธ `provider`๊ฐ€ ์ง€์ •๋˜์ง€ ์•Š์œผ๋ฉด ํ’€ (`firecrawl` โ†’ `jina-reader` โ†’ `tavily-search` โ†’ `tinyfish` โ†’ `nimble-search`)์„ ๊ณ ์ •๋œ ์šฐ์„ ์ˆœ์œ„ ์ˆœ์„œ(์„ ์ˆœ์œ„ ์šฐ์„  ์†Œ์ง„)๋กœ ์ˆœํšŒํ•ฉ๋‹ˆ๋‹ค. ์†๋„ ์ œํ•œ์— ๊ฑธ๋ ธ์ง€๋งŒ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๋Š” ์ œ๊ณต์ž๋Š” ์š”์ฒญ์„ ์ฆ‰์‹œ ์ค‘๋‹จ์‹œํ‚ค๋Š” ๋Œ€์‹  ๊ฑด๋„ˆ๋›ฐ๋ฉฐ, ์žฌ์‹œ๋„ ๊ฐ€๋Šฅ/ํ• ๋‹น๋Ÿ‰ ๊ด€๋ จ ์—…์ŠคํŠธ๋ฆผ ์‹คํŒจ (HTTP 429๋Š” ํ•ญ์ƒ ํ•ด๋‹น; Firecrawl/Tavily/TinyFish์˜ ํ• ๋‹น๋Ÿ‰ ๋ฐฉ์‹ ๋ฌด๋ฃŒ ํ‹ฐ์–ด์—์„œ๋Š” 402/403๋„ ํ•ด๋‹น โ€” Jina Reader์—๋Š” ์ ์šฉ๋˜์ง€ ์•Š์œผ๋ฉฐ, ์ผ๋ฐ˜์ ์ธ 400 ์ž˜๋ชป๋œ ์š”์ฒญ์—๋Š” ์ ˆ๋Œ€ ์ ์šฉ๋˜์ง€ ์•Š์Œ)๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์š”์ฒญ ์‹œ์ ์— ์•„์ง ์‹œ๋„ํ•˜์ง€ ์•Š์€ ๋‹ค์Œ ์ž๊ฒฉ ์ฆ๋ช… ๋ณด์œ  ์ œ๊ณต์ž๋กœ ๋„˜์–ด๊ฐ‘๋‹ˆ๋‹ค. ํ’€์˜ ๋ชจ๋“  ์ œ๊ณต์ž๊ฐ€ ์†Œ์ง„๋˜๋ฉด ์—”๋“œํฌ์ธํŠธ๋Š” ์ด์ „์˜ ์ผ๋ฐ˜์ ์ธ `400` ๋Œ€์‹  ๋‹จ์ผ `429` (`Retry-After` ํ—ค๋” ํฌํ•จ)๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๋ช…์‹œ์ ์ธ `provider`๊ฐ€ ์š”์ฒญ๋œ ๊ฒฝ์šฐ์—๋Š” ์ž๋™ ํด๋ฐฑ์ด **์—†์Šต๋‹ˆ๋‹ค**. ์†๋„ ์ œํ•œ์— ๊ฑธ๋ฆฌ๊ฑฐ๋‚˜ ์‹คํŒจํ•œ ๋ช…์‹œ์  ์ œ๊ณต์ž๋Š” ์ž์ฒด ์˜ค๋ฅ˜๋ฅผ ๊ทธ๋Œ€๋กœ ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค(์†๋„ ์ œํ•œ์ด๋ฉด `429`, ๊ทธ ์™ธ์—๋Š” ์—…์ŠคํŠธ๋ฆผ ์ƒํƒœ ์ฝ”๋“œ). --- ## WebSocket ์ŠคํŠธ๋ฆฌ๋ฐ ```bash GET /v1/ws?handshake=1 ``` WebSocket ์—…๊ทธ๋ ˆ์ด๋“œ ํ•ธ๋“œ์…ฐ์ดํฌ๋ฅผ ๊ฒ€์ฆํ•˜๊ณ  ์œ ์„  ํ”„๋กœํ† ์ฝœ ์˜ˆ์‹œ ๋ฉ”์‹œ์ง€(`request`, `cancel`)๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์‹ค์ œ WS ํ”„๋ ˆ์ž„์€ Next.js ๋ผ์šฐํŠธ ํ…Œ์ด๋ธ” ์™ธ๋ถ€์˜ ๋ฒˆ๋“ค๋œ WS ์„œ๋ฒ„์—์„œ ์ฒ˜๋ฆฌ๋ฉ๋‹ˆ๋‹ค. **์ธ์ฆ:** ํ•ธ๋“œ์…ฐ์ดํฌ ์ค‘ Bearer API ํ‚ค. ### WebSocket์„ ํ†ตํ•œ Responses API(codex ์ „์šฉ) ```bash # HTTP API์™€ ๋™์ผํ•œ ํ˜ธ์ŠคํŠธ:ํฌํŠธ(๊ธฐ๋ณธ๊ฐ’ 20128)๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์—ฐ๊ฒฐ์„ ์—…๊ทธ๋ ˆ์ด๋“œํ•ฉ๋‹ˆ๋‹ค. wscat -c "ws://localhost:20128/v1/responses?api_key=" # (๋˜๋Š”: -H "Authorization: Bearer ") # ์ฒซ ๋ฒˆ์งธ ํ”„๋ ˆ์ž„์€ ๋ฐ˜๋“œ์‹œ response.create์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค. { "type": "response.create", "model": "gpt-5.5", "input": [ { "role": "user", "content": "hi" } ] } ``` WebSocket์„ ํ†ตํ•œ Responses API ํ”„๋ก์‹œ๋Š” **`codex`์—๋งŒ ๋…์ ์ ์œผ๋กœ ์—ฐ๊ฒฐ**๋ฉ๋‹ˆ๋‹ค(ChatGPT ๋ฐฑ์—”๋“œ). ์ด ํ”„๋ก์‹œ๋Š” API/๋Œ€์‹œ๋ณด๋“œ์™€ ๋™์ผํ•œ ํฌํŠธ์—์„œ `/v1/responses`, `/responses`, `/api/v1/responses` ๊ฒฝ๋กœ๋ฅผ ์ˆ˜์‹ ํ•ฉ๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ `response.create` ํ”„๋ ˆ์ž„์—์„œ ๋‚ด๋ถ€ `codex-responses-ws` ๋ธŒ๋ฆฌ์ง€๋ฅผ ํ†ตํ•ด ์ธ์ฆ ๋ฐ ์ค€๋น„ํ•˜๊ณ , codex OAuth ์—ฐ๊ฒฐ์„ ์„ ํƒํ•œ ํ›„ `wreq-js` ์ „์†ก ๊ณ„์ธต์„ ํ†ตํ•ด `wss://chatgpt.com/backend-api/codex/responses`๋กœ ํ„ฐ๋„๋งํ•ฉ๋‹ˆ๋‹ค. **codex๊ฐ€ ์•„๋‹Œ ๋ชจ๋ธ์€ ๊ฑฐ๋ถ€๋ฉ๋‹ˆ๋‹ค**(`codex_ws_provider_required`). ํ• ๋‹น๋Ÿ‰ ๊ณต์œ  ๋ผ์šฐํŒ…์—๋Š” `model: "qtSd//codex/"`์„ ์‚ฌ์šฉํ•˜์„ธ์š”. ๊ตฌํ˜„ ์œ„์น˜๋Š” `app/server-ws.mjs` + `scripts/dev/responses-ws-proxy.mjs` + `src/app/api/internal/codex-responses-ws/route.ts`์ž…๋‹ˆ๋‹ค. **์ธ์ฆ:** ํ•ธ๋“œ์…ฐ์ดํฌ ์ค‘ Bearer API ํ‚ค. ๋ฒˆ๋“ค๋œ HTTP ์„œ๋ฒ„(`server-ws.mjs`)๊ฐ€ ํ™œ์„ฑ ์ง„์ž…์ ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(`app/server-ws.mjs`๊ฐ€ ์žˆ์œผ๋ฉด ๊ธฐ๋ณธ์ ์œผ๋กœ ํ™œ์„ฑ ์ง„์ž…์ ์ž…๋‹ˆ๋‹ค). #### ๋ชจ๋ธ ID: `codex/` ์ ‘๋‘์‚ฌ ์—†์ด ChatGPT ๊ธฐ๋ณธ ID ์‚ฌ์šฉ OpenAI **Codex CLI**๋Š” `supports_websockets = true`์ผ ๋•Œ ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ๋ชจ๋ธ ์ด๋ฆ„์„ ๊ฒ€์ฆํ•˜๊ณ  `codex/gpt-5.5`์™€ ๊ฐ™์€ **์ œ๊ณต์ž ์ ‘๋‘์‚ฌ๊ฐ€ ๋ถ™์€ ID๋ฅผ ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค** (`The 'codex/gpt-5.5' model is not supported when using Codex with a ChatGPT account`). **๊ธฐ๋ณธ** ID(์˜ˆ: `gpt-5.5`)๋ฅผ ์ „์†กํ•˜์„ธ์š”. OmniRoute์˜ ๋ธŒ๋ฆฌ์ง€๋Š” codex ์ „์šฉ์ด๋ฏ€๋กœ ์—…์ŠคํŠธ๋ฆผ์œผ๋กœ ํ„ฐ๋„๋งํ•˜๊ธฐ ์ „์— ๊ธฐ๋ณธ ID๋ฅผ codex ๋ชจ๋ธ๋กœ ๋‹ค์‹œ ํ•ด์„ํ•ฉ๋‹ˆ๋‹ค(`resolveCodexWsModelInfo`). ์ด๋Š” ๊ธฐ๋ณธ `gpt-5.5`๊ฐ€ HTTP๋ฅผ ํ†ตํ•ด์„œ๋Š” ๋‹ค๋ฅธ ์ œ๊ณต์ž๋กœ ๋ผ์šฐํŒ…๋  ์ˆ˜ ์žˆ์Œ์—๋„ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. #### OpenAI Codex CLI ๊ตฌ์„ฑ WebSocket์„ ์ง€์›ํ•˜๋Š” ์‚ฌ์šฉ์ž ์ง€์ • ์ œ๊ณต์ž๋ฅผ `~/.codex/config.toml`์— ์ถ”๊ฐ€ํ•˜์—ฌ Codex CLI๊ฐ€ OmniRoute๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋„๋ก ์„ค์ •ํ•˜์„ธ์š”(๊ธฐ์กด ๊ตฌ์„ฑ์„ ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š์œผ๋ ค๋ฉด ๋ณ„๋„์˜ `CODEX_HOME`์„ ์‚ฌ์šฉํ•˜์„ธ์š”). ```toml model = "gpt-5.5" # ๊ธฐ๋ณธ ID โ€” "codex/gpt-5.5"๊ฐ€ ์•„๋‹˜ model_provider = "omniroute" [model_providers.omniroute] name = "OmniRoute (WS)" base_url = "http://localhost:20128/v1" # ํ›„ํ–‰ ์Šฌ๋ž˜์‹œ ์—†์Œ; WS URL์€ ์—ฌ๊ธฐ์—์„œ ํŒŒ์ƒ๋จ(ํ”„๋กœ๋•์…˜์—์„œ๋Š” https/wss ์‚ฌ์šฉ) wire_api = "responses" # 2026๋…„ 2์›” ์ดํ›„ ์œ ์ผํ•˜๊ฒŒ ์ง€์›๋˜๋Š” ๊ฐ’ supports_websockets = true # Responses-over-WS ์ „์†ก ๊ณ„์ธต ํ™œ์„ฑํ™” env_key = "OMNIROUTE_API_KEY" # OmniRoute API ํ‚ค๋ฅผ ๋ณด๊ด€ํ•จ(Bearer) ``` ```bash export OMNIROUTE_API_KEY=sk-... # OmniRoute API ํ‚ค(REQUIRE_API_KEY=false์ด๋ฉด ์•„๋ฌด ํ‚ค๋‚˜ ์‚ฌ์šฉ ๊ฐ€๋Šฅ) codex exec "Responda apenas: PONG" ``` CLI๋Š” `base_url + /responses`๋ฅผ WebSocket์œผ๋กœ ์—…๊ทธ๋ ˆ์ด๋“œํ•˜๋ฉฐ OmniRoute๋Š” ์ด๋ฅผ ์„ ํƒ๋œ codex OAuth ์—ฐ๊ฒฐ๋กœ ํ„ฐ๋„๋งํ•ฉ๋‹ˆ๋‹ค. ๋กœ์ปฌ ์„œ๋ฒ„๋ฅผ ๋Œ€์ƒ์œผ๋กœ ์—”๋“œํˆฌ์—”๋“œ ๊ฒ€์ฆ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ChatGPT๊ฐ€ `codex.rate_limits` + `response.created`๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ  ์™„๋ฃŒ ๊ฒฐ๊ณผ๋ฅผ ์ŠคํŠธ๋ฆฌ๋ฐํ•ฉ๋‹ˆ๋‹ค. --- ## ํ• ๋‹น๋Ÿ‰ ๋ฐ ๋ฌธ์ œ ๋ณด๊ณ  | ๋ฉ”์„œ๋“œ | ๊ฒฝ๋กœ | ์„ค๋ช… | | ------ | ------------------- | ----------------------------------------------------------------------------- | | GET | `/v1/quotas/check` | ๋“ฑ๋ก๋œ ํ‚ค๋ฅผ ๋ฐœ๊ธ‰ํ•˜๊ธฐ ์ „์— `provider` + `accountId`์˜ ํ• ๋‹น๋Ÿ‰์„ ์‚ฌ์ „ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค | | POST | `/v1/issues/report` | ํ• ๋‹น๋Ÿ‰/ํ‚ค ๋ฐœ๊ธ‰ ์‹คํŒจ๋ฅผ GitHub์— ๋ณด๊ณ ํ•ฉ๋‹ˆ๋‹ค(`GITHUB_ISSUES_REPO` + ํ† ํฐ ํ•„์š”) | **์ธ์ฆ:** Bearer API ํ‚ค(`isAuthenticated`). --- ## ์…€ํ”„์„œ๋น„์Šค ์‚ฌ์šฉ๋Ÿ‰ ์กฐํšŒ(`/api/usage/om-usage`) ๋ชจ๋“  API ํ‚ค๋Š” ๊ด€๋ฆฌ ์ธ์ฆ ์—†์ด **์ž์ฒด** ์‚ฌ์šฉ๋Ÿ‰๊ณผ ํ• ๋‹น๋Ÿ‰์„ ์กฐํšŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ(CLI, OmniCopilot ํŒจ๋„)๋Š” ์ด ์—”๋“œํฌ์ธํŠธ๋ฅผ ์‚ฌ์šฉํ•ด ํ‚ค ๋ณด์œ ์ž์—๊ฒŒ ์ง€์ถœ์•ก์„ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค. ```bash # ํ…์ŠคํŠธ ํ˜•์‹(๊ธฐ์กด ๊ณ„์•ฝ โ€” ํ„ฐ๋ฏธ๋„์šฉ ์ผ๋ฐ˜ ํ…์ŠคํŠธ) curl -H "Authorization: Bearer " \ http://localhost:20128/api/usage/om-usage # ๊ตฌ์กฐํ™”๋œ ํ˜•์‹ โ€” UI์—์„œ ์‚ฌ์šฉํ•˜๋Š” ํ˜•์‹ curl -H "Authorization: Bearer " \ "http://localhost:20128/api/usage/om-usage?format=json" ``` ํ‚ค์—๋Š” **`allowUsageCommand`**๊ฐ€ ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(๊ธฐ๋ณธ๊ฐ’์€ ๋น„ํ™œ์„ฑํ™”์ด๋ฉฐ, ๋Œ€์‹œ๋ณด๋“œ์˜ API ํ‚ค ๊ด€๋ฆฌ์ž๊ฐ€ ํ‚ค๋ณ„๋กœ ์ด๋ฅผ ์ „ํ™˜ํ•ฉ๋‹ˆ๋‹ค). ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์ง€ ์•Š์œผ๋ฉด ์—”๋“œํฌ์ธํŠธ๊ฐ€ `403`์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. `?format=json`์€ ํ˜ธ์ถœ์ž๊ฐ€ ๊ฑฐ๋ถ€ ์‘๋‹ต์—์„œ ๋ฐ์ดํ„ฐ ํ•„๋“œ๋ฅผ ์ฝ์ง€ ์•Š๋„๋ก ํŒ๋ณ„ ๊ฐ€๋Šฅํ•œ ๊ตฌ์กฐ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์„ฑ๊ณต ์‹œ: ```jsonc { "allowed": true, // ํ‚ค์—์„œ ํ‚ค๋ณ„ ์‚ฌ์šฉ๋Ÿ‰ ํ•œ๋„(์ผ๊ฐ„/์ฃผ๊ฐ„ USD)๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ์„ค์ •ํ•œ ๊ฒฝ์šฐ์—๋งŒ ์กด์žฌ: "personal": { "dailySpentUsd": 1.25, "dailyLimitUsd": 5, "dailyResetAtIso": "โ€ฆ", "weeklySpentUsd": 8, "weeklyLimitUsd": 20, "weeklyResetAtIso": "โ€ฆ" /* โ€ฆ */, }, // ์„ ํƒํ•œ ์ œ๊ณต์ž์˜ ํ• ๋‹น๋Ÿ‰ ์Šค๋ƒ…์ƒท. ์•„์ง ์บ์‹œ๋œ ํ•ญ๋ชฉ์ด ์—†์œผ๋ฉด null: "provider": { "connectionId": "โ€ฆ", "provider": "claude", "plan": "โ€ฆ", "quotas": {/* โ€ฆ */}, }, // UI์—์„œ ์—ฌ๋Ÿฌ ์ œ๊ณต์ž๋ฅผ ๋‚˜๋ž€ํžˆ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ชจ๋“  ์—ฐ๊ฒฐ์˜ ์Šค๋ƒ…์ƒท ์ œ๊ณต: "providers": [ { "connectionId": "โ€ฆ", "provider": "claude" /* โ€ฆ */ }, { "provider": "codex" /* โ€ฆ */ }, ], } ``` ๊ฑฐ๋ถ€ ์‹œ(`401`: ์ž˜๋ชป๋œ ํ‚ค / `403`: ํ—ˆ์šฉ๋˜์ง€ ์•Š์Œ), ๋™์ผํ•œ ๊ฒฝ๋กœ๊ฐ€ `{ "allowed": false, "error": { "message": "โ€ฆ" } }`๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. `personal`/`provider`๊ฐ€ ์กด์žฌํ•˜์ง€๋งŒ ๋น„์–ด ์žˆ๋Š” ์ƒํƒœ(ํ‚ค๋Š” ํ—ˆ์šฉ๋˜์—ˆ์œผ๋‚˜ ์•„์ง ํ™•์ธ๋œ ์ •๋ณด๊ฐ€ ์—†์Œ)๋Š” ๊ฑฐ๋ถ€ ์ƒํƒœ์™€ ๋‹ค๋ฅด๋ฉฐ, JSON ํ˜•์‹๋งŒ ์ด ๋‘˜์„ ๊ตฌ๋ถ„ํ•ฉ๋‹ˆ๋‹ค. **์ธ์ฆ:** `isValidApiKey`๋กœ ๊ฒ€์ฆ๋œ ํ˜ธ์ถœ์ž ๋ณธ์ธ์˜ Bearer API ํ‚ค์ž…๋‹ˆ๋‹ค. ์ด๋Š” `requireManagementAuth`๋กœ ๊ณ„์† ๋ณดํ˜ธ๋˜๋Š” ๊ด€๋ฆฌ ์ธํ„ฐํŽ˜์ด์Šค(`/api/keys/โ€ฆ`)๊ฐ€ _์•„๋‹™๋‹ˆ๋‹ค_. --- ## ์‹œ๋งจํ‹ฑ ์บ์‹œ ```bash # ์บ์‹œ ํ†ต๊ณ„ ์กฐํšŒ GET /api/cache/stats # ๋ชจ๋“  ์บ์‹œ ์‚ญ์ œ DELETE /api/cache/stats ``` ์‘๋‹ต ์˜ˆ์‹œ: ```json { "semanticCache": { "memorySize": 42, "memoryMaxSize": 500, "dbSize": 128, "hitRate": 0.65 }, "idempotency": { "activeKeys": 3, "windowMs": 5000 } } ``` ### ์ง€์—ฐ ์‹œ๊ฐ„์— ๋ฏธ์น˜๋Š” ์˜ํ–ฅ ์‹œ๋งจํ‹ฑ ์บ์‹œ HIT ์‹œ **์—…์ŠคํŠธ๋ฆผ ํ˜ธ์ถœ ์—†์ด** ์บ์‹œ์—์„œ ์‘๋‹ต์„ ์ œ๊ณตํ•˜๋ฏ€๋กœ, ๋ณด๊ณ ๋˜๋Š” `X-OmniRoute-Response-Latency`๋Š” ์›๋ž˜ ์—…์ŠคํŠธ๋ฆผ ์ง€์—ฐ ์‹œ๊ฐ„๊ณผ ๊ด€๊ณ„์—†์ด ๊ฑฐ์˜ 0์— ๊ฐ€๊น์Šต๋‹ˆ๋‹ค. ์ง€์—ฐ ์‹œ๊ฐ„์— ๋ฏผ๊ฐํ•œ ํด๋ผ์ด์–ธํŠธ(๋ฒค์น˜๋งˆํ‚น, p50/p99 ๋ชจ๋‹ˆํ„ฐ๋ง)๋Š” `X-OmniRoute-Cache-Latency` ์‘๋‹ต ํ—ค๋”๋ฅผ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. | ๊ฐ’ | ์˜๋ฏธ | | ----------- | --------------------------------------------------------------- | | `synthetic` | ์บ์‹œ์—์„œ ์ œ๊ณต๋œ ์‘๋‹ต์ด๋ฉฐ, ์ง€์—ฐ ์‹œ๊ฐ„์€ ์‹ค์ œ ์—…์ŠคํŠธ๋ฆผ ์‹œ๊ฐ„์ด ์•„๋‹˜ | | _(์—†์Œ)_ | ์‹ค์ œ ์—…์ŠคํŠธ๋ฆผ ํ˜ธ์ถœ์—์„œ ์ œ๊ณต๋œ ์‘๋‹ต | ### ํ‚ค๋ณ„ ์บ์‹œ ์šฐํšŒ API ํ‚ค๋Š” `cacheDefaultMode`๋ฅผ ํ†ตํ•ด ์‹œ๋งจํ‹ฑ ์บ์‹œ ์ฝ๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋„๋ก ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. | ๊ฐ’ | ๋™์ž‘ | | -------- | ------------------------------------------------ | | `legacy` | ์ผ๋ฐ˜์ ์ธ ์บ์‹œ ๋™์ž‘(๊ธฐ๋ณธ๊ฐ’) | | `bypass` | ์บ์‹œ ์กฐํšŒ๋ฅผ ์™„์ „ํžˆ ๊ฑด๋„ˆ๋›ฐ๊ณ  ํ•ญ์ƒ ์—…์ŠคํŠธ๋ฆผ์„ ํ˜ธ์ถœ | ํ‚ค ์ƒ์„ฑ ์‹œ(`POST /api/keys`) ์„ค์ •ํ•˜๊ฑฐ๋‚˜ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(`PATCH /api/keys/[id]`). ```json { "cacheDefaultMode": "bypass" } ``` ### ์š”์ฒญ๋ณ„ ์šฐํšŒ ๋ชจ๋“  ์š”์ฒญ์€ ํ‚ค ์„ค์ •๊ณผ ๊ด€๊ณ„์—†์ด ์บ์‹œ๋ฅผ ์šฐํšŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ``` X-OmniRoute-No-Cache: true ``` --- ## ๋Œ€์‹œ๋ณด๋“œ ๋ฐ ๊ด€๋ฆฌ ๊ด€๋ฆฌ ๋ผ์šฐํŠธ(๊ณต๊ฐœ ์ธ์ฆ/๋กœ๊ทธ์ธ์„ ์ œ์™ธํ•œ `/api/*`)๋Š” ์ผ๋ฐ˜ ์ถ”๋ก  API ํ‚ค๋กœ **์ธ์ฆ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค**. ์ž๊ฒฉ ์ฆ๋ช… ์œ ํ˜•, ๋ฒ”์œ„ ๋ฐ curl ์˜ˆ์‹œ๋Š” ๋‹ค์Œ์„ ์ฐธ์กฐํ•˜์„ธ์š”. [๊ด€๋ฆฌ ์ธ์ฆ](../guides/MANAGEMENT-AUTH.md). ### ์ธ์ฆ | ์—”๋“œํฌ์ธํŠธ | ๋ฉ”์„œ๋“œ | ์„ค๋ช… | | ----------------------------- | ------- | --------------------- | | `/api/auth/login` | POST | ๋กœ๊ทธ์ธ | | `/api/auth/logout` | POST | ๋กœ๊ทธ์•„์›ƒ | | `/api/settings/require-login` | GET/PUT | ๋กœ๊ทธ์ธ ํ•„์ˆ˜ ์—ฌ๋ถ€ ์ „ํ™˜ | ### ๊ณต๊ธ‰์ž ๊ด€๋ฆฌ | ์—”๋“œํฌ์ธํŠธ | ๋ฉ”์„œ๋“œ | ์„ค๋ช… | | ---------------------------- | --------------------- | ------------------------------------------------------------------------------------------ | | `/api/providers` | GET/POST | ๊ณต๊ธ‰์ž ๋ชฉ๋ก ์กฐํšŒ/์ƒ์„ฑ | | `/api/providers/[id]` | GET/PUT/DELETE | ๊ณต๊ธ‰์ž ๊ด€๋ฆฌ | | `/api/providers/[id]/test` | POST | ๊ณต๊ธ‰์ž ์—ฐ๊ฒฐ ํ…Œ์ŠคํŠธ | | `/api/providers/[id]/models` | GET | ๊ณต๊ธ‰์ž ๋ชจ๋ธ ๋ชฉ๋ก ์กฐํšŒ | | `/api/providers/validate` | POST | ๊ณต๊ธ‰์ž ๊ตฌ์„ฑ ๊ฒ€์ฆ | | `/api/providers/bulk` | POST | ๋‹จ์ผ ๊ณต๊ธ‰์ž์˜ API ํ‚ค ์ผ๊ด„ ์ถ”๊ฐ€ | | `/api/providers/import` | POST | ํŒŒ์‹ฑ๋œ CSV/JSON ํŒŒ์ผ์—์„œ ์—ฌ๋Ÿฌ ์œ ํ˜•์˜ ๊ณต๊ธ‰์ž ๋ชฉ๋ก ๊ฐ€์ ธ์˜ค๊ธฐ(#6836), ํ–‰๋ณ„ ๋ถ€๋ถ„ ์‹คํŒจ ๊ฒฐ๊ณผ ์ œ๊ณต | | `/api/provider-nodes*` | ๋‹ค์–‘ํ•จ | ๊ณต๊ธ‰์ž ๋…ธ๋“œ ๊ด€๋ฆฌ | | `/api/provider-models` | GET/POST/PATCH/DELETE | ์‚ฌ์šฉ์ž ์ง€์ • ๋ชจ๋ธ(์ถ”๊ฐ€, ์—…๋ฐ์ดํŠธ, ์ˆจ๊ธฐ๊ธฐ/ํ‘œ์‹œ, ์‚ญ์ œ) | ### OAuth ํ๋ฆ„ | ์—”๋“œํฌ์ธํŠธ | ๋ฉ”์„œ๋“œ | ์„ค๋ช… | | -------------------------------- | ------ | -------------- | | `/api/oauth/[provider]/[action]` | ๋‹ค์–‘ํ•จ | ๊ณต๊ธ‰์ž๋ณ„ OAuth | ### ๋ผ์šฐํŒ… ๋ฐ ๊ตฌ์„ฑ | ์—”๋“œํฌ์ธํŠธ | ๋ฉ”์„œ๋“œ | ์„ค๋ช… | | --------------------- | -------- | -------------------------- | | `/api/models/alias` | GET/POST | ๋ชจ๋ธ ๋ณ„์นญ | | `/api/models/catalog` | GET | ๊ณต๊ธ‰์ž ๋ฐ ์œ ํ˜•๋ณ„ ๋ชจ๋“  ๋ชจ๋ธ | | `/api/combos*` | ๋‹ค์–‘ํ•จ | ์ฝค๋ณด ๊ด€๋ฆฌ | | `/api/keys*` | ๋‹ค์–‘ํ•จ | API ํ‚ค ๊ด€๋ฆฌ | | `/api/pricing` | GET | ๋ชจ๋ธ ์š”๊ธˆ | ### ์‚ฌ์šฉ๋Ÿ‰ ๋ฐ ๋ถ„์„ | ์—”๋“œํฌ์ธํŠธ | ๋ฉ”์„œ๋“œ | ์„ค๋ช… | | -------------------------------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/api/usage/history` | GET | ์‚ฌ์šฉ๋Ÿ‰ ๊ธฐ๋ก | | `/api/usage/logs` | GET | ์‚ฌ์šฉ๋Ÿ‰ ๋กœ๊ทธ | | `/api/usage/request-logs` | GET | ์š”์ฒญ ์ˆ˜์ค€ ๋กœ๊ทธ | | `/api/usage/[connectionId]` | GET | ์—ฐ๊ฒฐ๋ณ„ ์‚ฌ์šฉ๋Ÿ‰ | | `/api/usage/token-limits` | GET/POST/DELETE | API ํ‚ค๋ณ„ ํ† ํฐ ํ•œ๋„ ์˜ˆ์‚ฐ | | `/api/usage/model-latency-stats` | GET | ๊ณต๊ธ‰์ž/๋ชจ๋ธ๋ณ„ ์ด๋™ ์ง€์—ฐ ์‹œ๊ฐ„ ์ง‘๊ณ„(avg/p50/p95/p99, ์„ฑ๊ณต๋ฅ ); ํ•„ํ„ฐ: `windowHours`/`minSamples`/`maxRows`/`provider`/`model` (#6873) | | `/api/usage/cache-health` | GET | `call_logs`์— ๋Œ€ํ•œ ํ”„๋กฌํ”„ํŠธ ์บ์‹œ ์ƒํƒœ ์š”์•ฝ โ€” ์“ฐ๊ธฐ/์ฝ๊ธฐ ๋น„์œจ, p50/p90/p99 ์“ฐ๊ธฐ ํฌ๊ธฐ ๋ถ„ํฌ, ๋Œ€๋Ÿ‰ ์“ฐ๊ธฐ ์ง‘์ค‘๋„, ๋ชจ๋ธ๋ณ„ ๋ถ„์„ ๋ฐ `healthy`/`degraded`/`thrash`/`no-data` ํŒ์ •; ์ฟผ๋ฆฌ ๋งค๊ฐœ๋ณ€์ˆ˜ `range` (`1h`\|`24h`\|`7d`\|`30d`, ๊ธฐ๋ณธ๊ฐ’ `24h`) ๋ฐ ์„ ํƒ์  `model` (#8827) | ### ์„ค์ • | ์—”๋“œํฌ์ธํŠธ | ๋ฉ”์„œ๋“œ | ์„ค๋ช… | | ------------------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `/api/settings` | GET/PUT/PATCH | ์ผ๋ฐ˜ ์„ค์ • | | `/api/settings/proxy` | GET/PUT | ๋„คํŠธ์›Œํฌ ํ”„๋ก์‹œ ๊ตฌ์„ฑ | | `/api/settings/proxy/test` | POST | ํ”„๋ก์‹œ ์—ฐ๊ฒฐ ํ…Œ์ŠคํŠธ | | `/api/settings/ip-filter` | GET/PUT | IP ํ—ˆ์šฉ ๋ชฉ๋ก/์ฐจ๋‹จ ๋ชฉ๋ก | | `/api/settings/thinking-budget` | GET/PUT | ์‚ฌ๊ณ /์ถ”๋ก  **์š”์ฒญ** ์žฌ์ž‘์„ฑ ๋ชจ๋“œ(passthrough / auto-strip / custom / adaptive). ์••์ถ•๊ณผ๋Š” ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค. [THINKING_BUDGET.md](../guides/THINKING_BUDGET.md)๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”. | | `/api/settings/system-prompt` | GET/PUT | ์ „์—ญ ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ | | `/api/settings/compression` | GET/PUT | ์ „์—ญ ์••์ถ• ๊ตฌ์„ฑ | | `/api/settings/purge-request-history` | POST | ์š”์ฒญ ๋กœ๊ทธ ํ–‰ ๋ฐ ๋กœ์ปฌ ํ˜ธ์ถœ ๋กœ๊ทธ ์•„ํ‹ฐํŒฉํŠธ ์‚ญ์ œ | ### ์ปจํ…์ŠคํŠธ ๋ฐ ์••์ถ• | ์—”๋“œํฌ์ธํŠธ | ๋ฉ”์„œ๋“œ | ์„ค๋ช… | | -------------------------------------- | -------------- | ------------------------------------------------------------ | | `/api/compression/preview` | POST | off/lite/standard/aggressive/ultra/RTK/stacked ์••์ถ• ๋ฏธ๋ฆฌ๋ณด๊ธฐ | | `/api/compression/language-packs` | GET | ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ Caveman ์–ธ์–ด ํŒฉ ๋ชฉ๋ก | | `/api/compression/rules` | GET | Caveman ๊ทœ์น™ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ๋ชฉ๋ก | | `/api/context/caveman/config` | GET/PUT | Caveman ์ „์šฉ ์„ค์ • ๋ณ„์นญ | | `/api/context/rtk/config` | GET/PUT | ์‚ฌ์šฉ์ž ์ง€์ • ํ•„ํ„ฐ ๋ฐ ์›์‹œ ์ถœ๋ ฅ ๋ณด์กด์„ ํฌํ•จํ•œ RTK ์ „์šฉ ์„ค์ • | | `/api/context/rtk/filters` | GET | RTK ํ•„ํ„ฐ ์นดํƒˆ๋กœ๊ทธ ๋ฐ ์‚ฌ์šฉ์ž ์ง€์ • ํ•„ํ„ฐ ์ง„๋‹จ | | `/api/context/rtk/test` | POST | ํ…์ŠคํŠธ ํŽ˜์ด๋กœ๋“œ๋ฅผ ๋Œ€์ƒ์œผ๋กœ RTK ๋ฏธ๋ฆฌ๋ณด๊ธฐ/ํ…Œ์ŠคํŠธ ์‹คํ–‰ | | `/api/context/rtk/raw-output/[id]` | GET | ํฌ์ธํ„ฐ ID๋กœ ๋ณด์กด๋œ ๋ฏผ๊ฐ ์ •๋ณด ์ œ๊ฑฐ ์›์‹œ ์ถœ๋ ฅ ์ฝ๊ธฐ | | `/api/context/combos` | GET/POST | ์••์ถ• ์กฐํ•ฉ ๋ชฉ๋ก/์ƒ์„ฑ | | `/api/context/combos/[id]` | GET/PUT/DELETE | ์••์ถ• ์กฐํ•ฉ ์ƒ์„ธ ์ •๋ณด/์—…๋ฐ์ดํŠธ/์‚ญ์ œ | | `/api/context/combos/[id]/assignments` | GET/PUT | ๋ผ์šฐํŒ… ์กฐํ•ฉ์— ์••์ถ• ์กฐํ•ฉ ํ• ๋‹น | | `/api/context/analytics` | GET | ์••์ถ• ๋ถ„์„ ๋ณ„์นญ | ### ๋ชจ๋‹ˆํ„ฐ๋ง | ์—”๋“œํฌ์ธํŠธ | ๋ฉ”์„œ๋“œ | ์„ค๋ช… | | ------------------------------------ | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `/api/sessions` | GET | ํ™œ์„ฑ ์„ธ์…˜ ์ถ”์  | | `/api/rate-limits` | GET | ๊ณ„์ •๋ณ„ ์š”์ฒญ ํ•œ๋„ | | `/api/monitoring/health` | GET | ์ƒํƒœ ํ™•์ธ + ์ œ๊ณต์ž ์š”์•ฝ(`catalogCount`, `configuredCount`, `activeCount`, `monitoredCount`). ๊ด€๋ฆฌ ๋ณด๊ธฐ์—๋Š” `credentialHealth`๊ฐ€ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” ํ”„๋กœ๋ธŒ ์บ์‹œ ์Šค์นผ๋ผ, `failed>0`์ธ ๊ฒฝ์šฐ์˜ `failedConnections`, ๊ทธ๋ฆฌ๊ณ  `staleDbNonOkCount`(๊ฒŒ์ด์ง€๊ฐ€ ์•„๋‹Œ SQLite ๊ณ ์ • `test_status`)๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค. [MONITORING_GUIDE.md](../ops/MONITORING_GUIDE.md#credentialhealth-probe-cache-vs-sqlite-test_status)๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”. | | `/api/cache/stats` | GET/DELETE | ์บ์‹œ ํ†ต๊ณ„ / ์ง€์šฐ๊ธฐ | | `/api/modality-bridge/stats` | GET | ๋ฉ”๋ชจ๋ฆฌ ๋‚ด `attempts`, ์„ฑ๊ณต ํšŸ์ˆ˜/`bridged`, ์‹คํŒจ ํšŸ์ˆ˜, ์บ์‹œ ์ ์ค‘ ํšŸ์ˆ˜, `totalLatencyMs`, `latencySamples`, ์ƒ˜ํ”Œ ์ˆ˜๋ฅผ ๋ถ„๋ชจ๋กœ ๊ณ„์‚ฐํ•œ `averageLatencyMs`, ๋งˆ์ง€๋ง‰ ์‚ฌ์šฉ ์‹œ๊ฐ„(์žฌ์‹œ์ž‘ ์‹œ ์ดˆ๊ธฐํ™”, ๊ด€๋ฆฌ ์ธ์ฆ ํ•„์š”) | | `/api/modality-bridge/video/runtime` | GET | ๊ด€๋ฆฌ ์ธ์ฆ/ํ”„๋กœ๋ธŒ ์ „์— ์—„๊ฒฉํ•œ ์‹ ๋ขฐ๋œ ๋ฃจํ”„๋ฐฑ ๊ฒ€์‚ฌ ์ˆ˜ํ–‰, ์ •์ œ๋œ FFmpeg/ffprobe ๊ฐ€์šฉ์„ฑ ๋ฐ ๋ฒ„์ „(`no-store`) | | `/api/modality-bridge/video/extract` | POST | ๋‚ด๋ถ€ ์ธ์ฆ๋œ ์‹ ๋ขฐ ๋ฃจํ”„๋ฐฑ ๋ฐ”์ดํŠธ ๋ธŒ๋กœ์ปค. ์ž…๋ ฅ 50 MiB, ์ œํ•œ๋œ ํ/์ถœ๋ ฅ 32 MiB, ์šฉ๋Ÿ‰ ์ดˆ๊ณผ ์‹œ `503`, ์—ฐ๊ฒฐ ํ•ด์ œ ์‹œ `499`, ๊ธฐํ•œ ์ดˆ๊ณผ ์‹œ `504`. ๊ณต๊ฐœ ์—…๋กœ๋“œ API๊ฐ€ ์•„๋‹˜ | ### ๋ฐฑ์—… ๋ฐ ๋‚ด๋ณด๋‚ด๊ธฐ/๊ฐ€์ ธ์˜ค๊ธฐ | ์—”๋“œํฌ์ธํŠธ | ๋ฉ”์„œ๋“œ | ์„ค๋ช… | | --------------------------- | ------ | ----------------------------------------- | | `/api/db-backups` | GET | ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ฐฑ์—… ๋ชฉ๋ก ์กฐํšŒ | | `/api/db-backups` | PUT | ์ˆ˜๋™ ๋ฐฑ์—… ์ƒ์„ฑ | | `/api/db-backups` | POST | ํŠน์ • ๋ฐฑ์—…์—์„œ ๋ณต์› | | `/api/db-backups/export` | GET | ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ .sqlite ํŒŒ์ผ๋กœ ๋‹ค์šด๋กœ๋“œ | | `/api/db-backups/import` | POST | ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ๊ต์ฒดํ•  .sqlite ํŒŒ์ผ ์—…๋กœ๋“œ | | `/api/db-backups/exportAll` | GET | ์ „์ฒด ๋ฐฑ์—…์„ .tar.gz ์•„์นด์ด๋ธŒ๋กœ ๋‹ค์šด๋กœ๋“œ | ### ํด๋ผ์šฐ๋“œ ๋™๊ธฐํ™” | ์—”๋“œํฌ์ธํŠธ | ๋ฉ”์„œ๋“œ | ์„ค๋ช… | | ---------------------- | ------ | -------------------- | | `/api/sync/cloud` | ๋‹ค์–‘ํ•จ | ํด๋ผ์šฐ๋“œ ๋™๊ธฐํ™” ์ž‘์—… | | `/api/sync/initialize` | POST | ๋™๊ธฐํ™” ์ดˆ๊ธฐํ™” | | `/api/cloud/*` | ๋‹ค์–‘ํ•จ | ํด๋ผ์šฐ๋“œ ๊ด€๋ฆฌ | ### ํ„ฐ๋„ | ์—”๋“œํฌ์ธํŠธ | ๋ฉ”์„œ๋“œ | ์„ค๋ช… | | -------------------------- | ------ | --------------------------------------------------------------------- | | `/api/tunnels/cloudflared` | GET | ๋Œ€์‹œ๋ณด๋“œ์šฉ Cloudflare Quick Tunnel ์„ค์น˜/๋Ÿฐํƒ€์ž„ ์ƒํƒœ ์กฐํšŒ | | `/api/tunnels/cloudflared` | POST | Cloudflare Quick Tunnel ํ™œ์„ฑํ™” ๋˜๋Š” ๋น„ํ™œ์„ฑํ™”(`action=enable/disable`) | | `/api/tunnels/ngrok` | GET | ๋Œ€์‹œ๋ณด๋“œ์šฉ ngrok Tunnel ๋Ÿฐํƒ€์ž„ ์ƒํƒœ ์กฐํšŒ | | `/api/tunnels/ngrok` | POST | ngrok Tunnel ํ™œ์„ฑํ™” ๋˜๋Š” ๋น„ํ™œ์„ฑํ™”(`action=enable/disable`) | ### CLI ๋„๊ตฌ | ์—”๋“œํฌ์ธํŠธ | ๋ฉ”์„œ๋“œ | ์„ค๋ช… | | ---------------------------------- | ------ | ----------------- | | `/api/cli-tools/claude-settings` | GET | Claude CLI ์ƒํƒœ | | `/api/cli-tools/codex-settings` | GET | Codex CLI ์ƒํƒœ | | `/api/cli-tools/droid-settings` | GET | Droid CLI ์ƒํƒœ | | `/api/cli-tools/openclaw-settings` | GET | OpenClaw CLI ์ƒํƒœ | | `/api/cli-tools/runtime/[toolId]` | GET | ์ผ๋ฐ˜ CLI ๋Ÿฐํƒ€์ž„ | CLI ์‘๋‹ต์—๋Š” `installed`, `runnable`, `command`, `commandPath`, `runtimeMode`, `reason`์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. ### ACP ์—์ด์ „ํŠธ | ์—”๋“œํฌ์ธํŠธ | ๋ฉ”์„œ๋“œ | ์„ค๋ช… | | ----------------- | ------ | -------------------------------------------------------------- | | `/api/acp/agents` | GET | ๊ฐ์ง€๋œ ๋ชจ๋“  ์—์ด์ „ํŠธ(๊ธฐ๋ณธ ์ œ๊ณต + ์‚ฌ์šฉ์ž ์ •์˜)์™€ ์ƒํƒœ ๋ชฉ๋ก ์กฐํšŒ | | `/api/acp/agents` | POST | ์‚ฌ์šฉ์ž ์ •์˜ ์—์ด์ „ํŠธ ์ถ”๊ฐ€ ๋˜๋Š” ๊ฐ์ง€ ์บ์‹œ ์ƒˆ๋กœ ๊ณ ์นจ | | `/api/acp/agents` | DELETE | `id` ์ฟผ๋ฆฌ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์‚ฌ์šฉ์ž ์ •์˜ ์—์ด์ „ํŠธ ์ œ๊ฑฐ | GET ์‘๋‹ต์—๋Š” `agents[]`(id, name, binary, version, installed, protocol, isCustom)์™€ `summary`(total, installed, notFound, builtIn, custom)๊ฐ€ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. ### ๋ณต์›๋ ฅ ๋ฐ ์†๋„ ์ œํ•œ | ์—”๋“œํฌ์ธํŠธ | ๋ฉ”์„œ๋“œ | ์„ค๋ช… | | --------------------------------- | --------- | -------------------------------------------------------------------------------------------------- | | `/api/resilience` | GET/PATCH | ์š”์ฒญ ๋Œ€๊ธฐ์—ด, ์—ฐ๊ฒฐ ์ฟจ๋‹ค์šด, ์ œ๊ณต์ž ์ฐจ๋‹จ๊ธฐ ๋ฐ ๋Œ€๊ธฐ ์„ค์ • ์กฐํšŒ/์—…๋ฐ์ดํŠธ | | `/api/resilience/reset` | POST | ์ œ๊ณต์ž ํšŒ๋กœ ์ฐจ๋‹จ๊ธฐ ์žฌ์„ค์ • | | `/api/resilience/model-cooldowns` | GET | ํ™œ์„ฑํ™”๋œ (์ œ๊ณต์ž, ์—ฐ๊ฒฐ, ๋ชจ๋ธ)๋ณ„ ์ž ๊ธˆ ๋ชฉ๋ก์„ ๋‚จ์€ ์‹œ๊ฐ„์ˆœ์œผ๋กœ ์กฐํšŒ | | `/api/resilience/model-cooldowns` | DELETE | ๋ชจ๋ธ ์ž ๊ธˆ ํ•ด์ œ โ€” ๋ณธ๋ฌธ์— `{provider, model}`์„ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ๋ชจ๋“  ํ•ญ๋ชฉ์„ ์‚ญ์ œํ•˜๋ ค๋ฉด `{all: true}` ์‚ฌ์šฉ | | `/api/rate-limits` | GET | ๊ณ„์ •๋ณ„ ์†๋„ ์ œํ•œ ์ƒํƒœ | | `/api/rate-limit` | GET | ์ „์—ญ ์†๋„ ์ œํ•œ ๊ตฌ์„ฑ | > ๋„ค ๊ฐœ์˜ `/api/resilience/*` ๊ฒฝ๋กœ๋Š” ๋ชจ๋‘ **๊ด€๋ฆฌ ์ธ์ฆ**(`requireManagementAuth`)์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ œ๊ณต์ž ์ฐจ๋‹จ๊ธฐ, ์—ฐ๊ฒฐ ์ฟจ๋‹ค์šด, ๋ชจ๋ธ ์ž ๊ธˆ ๊ฐ„์˜ ์ฐจ์ด์— ๋Œ€ํ•œ ์ „์ฒด ์„ค๋ช…์€ [๋ณต์›๋ ฅ(ํ™•์žฅ)](#resilience-extended)์„ ์ฐธ์กฐํ•˜์„ธ์š”. ### ํ‰๊ฐ€ | ์—”๋“œํฌ์ธํŠธ | ๋ฉ”์„œ๋“œ | ์„ค๋ช… | | ------------ | -------- | --------------------------------- | | `/api/evals` | GET/POST | ํ‰๊ฐ€ ์Šค์œ„ํŠธ ๋ชฉ๋ก ์กฐํšŒ / ํ‰๊ฐ€ ์‹คํ–‰ | ### ์ •์ฑ… | ์—”๋“œํฌ์ธํŠธ | ๋ฉ”์„œ๋“œ | ์„ค๋ช… | | --------------- | --------------- | ---------------- | | `/api/policies` | GET/POST/DELETE | ๋ผ์šฐํŒ… ์ •์ฑ… ๊ด€๋ฆฌ | ### ๊ทœ์ • ์ค€์ˆ˜ | ์—”๋“œํฌ์ธํŠธ | ๋ฉ”์„œ๋“œ | ์„ค๋ช… | | --------------------------- | ------ | ----------------------------- | | `/api/compliance/audit-log` | GET | ๊ทœ์ • ์ค€์ˆ˜ ๊ฐ์‚ฌ ๋กœ๊ทธ(์ตœ๊ทผ N๊ฐœ) | ### v1beta(Gemini ํ˜ธํ™˜) | ์—”๋“œํฌ์ธํŠธ | ๋ฉ”์„œ๋“œ | ์„ค๋ช… | | -------------------------- | ------ | ----------------------------------- | | `/v1beta/models` | GET | Gemini ํ˜•์‹์œผ๋กœ ๋ชจ๋ธ ๋ชฉ๋ก ์กฐํšŒ | | `/v1beta/models/{...path}` | POST | Gemini `generateContent` ์—”๋“œํฌ์ธํŠธ | ์ด๋Ÿฌํ•œ ์—”๋“œํฌ์ธํŠธ๋Š” ๋„ค์ดํ‹ฐ๋ธŒ Gemini SDK ํ˜ธํ™˜์„ฑ์„ ์š”๊ตฌํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ๋ฅผ ์œ„ํ•ด Gemini์˜ API ํ˜•์‹์„ ๊ทธ๋Œ€๋กœ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค. ### ๋‚ด๋ถ€ / ์‹œ์Šคํ…œ API | ์—”๋“œํฌ์ธํŠธ | ๋ฉ”์„œ๋“œ | ์„ค๋ช… | | ------------------------ | ------ | ------------------------------------------- | | `/api/init` | GET | ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ดˆ๊ธฐํ™” ํ™•์ธ(์ตœ์ดˆ ์‹คํ–‰ ์‹œ ์‚ฌ์šฉ) | | `/api/tags` | GET | Ollama ํ˜ธํ™˜ ๋ชจ๋ธ ํƒœ๊ทธ(Ollama ํด๋ผ์ด์–ธํŠธ์šฉ) | | `/api/restart` | POST | ์ •์ƒ์ ์ธ ์„œ๋ฒ„ ์žฌ์‹œ์ž‘ ์‹คํ–‰ | | `/api/shutdown` | POST | ์ •์ƒ์ ์ธ ์„œ๋ฒ„ ์ข…๋ฃŒ ์‹คํ–‰ | | `/api/system/env/repair` | POST | OAuth ์ œ๊ณต์ž ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๋ณต๊ตฌ | > **์ฐธ๊ณ :** ์ด๋Ÿฌํ•œ ์—”๋“œํฌ์ธํŠธ๋Š” ์‹œ์Šคํ…œ ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉ๋˜๊ฑฐ๋‚˜ Ollama ํด๋ผ์ด์–ธํŠธ์™€์˜ ํ˜ธํ™˜์„ฑ์„ ์œ„ํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ์ตœ์ข… ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ํ˜ธ์ถœํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ### OAuth ํ™˜๊ฒฝ ๋ณต๊ตฌ _(v3.6.1+)_ ```bash POST /api/system/env/repair Content-Type: application/json { "provider": "claude-code" } ``` ํŠน์ • ์ œ๊ณต์ž์˜ ๋ˆ„๋ฝ๋˜๊ฑฐ๋‚˜ ์†์ƒ๋œ OAuth ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ๋ณต๊ตฌํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ```json { "success": true, "repaired": ["CLAUDE_CODE_OAUTH_CLIENT_ID", "CLAUDE_CODE_OAUTH_CLIENT_SECRET"], "backupPath": "/home/user/.omniroute/backups/env-repair-2026-04-11.bak" } ``` --- ## ์˜ค๋””์˜ค ์ „์‚ฌ ```bash POST /v1/audio/transcriptions Authorization: Bearer your-api-key Content-Type: multipart/form-data ``` ๊ตฌ์„ฑ๋œ STT ์ œ๊ณต์ž๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์˜ค๋””์˜ค ํŒŒ์ผ์„ ์ „์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ ๊ฒฝ๋กœ ์„ธ๊ทธ๋จผํŠธ๋Š” ๊ธฐ๋ณธ ์ œ๊ณต์ž(`openai/โ€ฆ`, `deepgram/โ€ฆ`)๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๊ณต๊ธ‰์—…์ฒด์˜ ๋ชจ๋ธ์„ ๋‹ค์‹œ ์ œ๊ณตํ•˜๋Š” ๊ฒŒ์ดํŠธ์›จ์ด๋Š” ์ •๊ทœํ™”๋œ ID๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค (`openrouter/deepgram/nova-3`). **์š”์ฒญ:** ```bash curl -X POST http://localhost:20128/v1/audio/transcriptions \ -H "Authorization: Bearer your-api-key" \ -F "file=@recording.mp3" \ -F "model=openai/whisper-1" ``` **์‘๋‹ต:** ```json { "text": "Hello, this is the transcribed audio content.", "task": "transcribe", "language": "en", "duration": 12.5 } ``` **๋ชจ๋ธ ID ์˜ˆ์‹œ:** `openai/whisper-1`(OpenAI ํ‚ค ํ•„์š”), `openrouter/deepgram/nova-3`(OpenRouter ํ‚ค ํ•„์š”), `deepgram/nova-3`(๊ธฐ๋ณธ Deepgram ํ‚ค ํ•„์š”). ์ •๊ทœํ™”๋˜์ง€ ์•Š์€ `deepgram/nova-3` ์š”์ฒญ์€ OpenRouter๋ฅผ ์‚ฌ์šฉํ•˜์ง€ **์•Š์Šต๋‹ˆ๋‹ค**. **์ง€์› ํ˜•์‹:** `mp3`, `wav`, `m4a`, `flac`, `ogg`, `webm`. --- ## Ollama ํ˜ธํ™˜์„ฑ Ollama์˜ API ํ˜•์‹์„ ์‚ฌ์šฉํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ์˜ ๊ฒฝ์šฐ: ```bash # ์ฑ„ํŒ… ์—”๋“œํฌ์ธํŠธ(Ollama ํ˜•์‹) POST /v1/api/chat # ๋ชจ๋ธ ๋ชฉ๋ก(Ollama ํ˜•์‹) GET /api/tags ``` ์š”์ฒญ์€ Ollama ํ˜•์‹๊ณผ ๋‚ด๋ถ€ ํ˜•์‹ ๊ฐ„์— ์ž๋™์œผ๋กœ ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค. ## ํ† ํฐํ™”๋œ VS Code / ํ—ค๋” ์—†๋Š” ๋ณ„์นญ ํ†ตํ•ฉ์—์„œ `Authorization` ํ—ค๋”๋ฅผ ์‚ฝ์ž…ํ•  ์ˆ˜ ์—†์–ด API ํ‚ค๋ฅผ ๊ธฐ๋ณธ URL์— ํฌํ•จํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ๋‹ค์Œ ๋ณ„์นญ์„ ์‚ฌ์šฉํ•˜์„ธ์š”. ```bash # OpenAI ์Šคํƒ€์ผ ์นดํƒˆ๋กœ๊ทธ ๋ณ„์นญ GET /api/v1/vscode/{token}/ GET /api/v1/vscode/{token}/models # OpenAI ์Šคํƒ€์ผ ์ฑ„ํŒ… ๋ณ„์นญ POST /api/v1/vscode/{token}/chat/completions POST /api/v1/vscode/{token}/responses # Ollama ์Šคํƒ€์ผ ๋ณ„์นญ POST /api/v1/vscode/{token}/api/chat GET /api/v1/vscode/{token}/api/tags ``` ์˜ˆ์‹œ: ```bash curl https://your-host.example/api/v1/vscode/YOUR_API_KEY/models curl -X POST https://your-host.example/api/v1/vscode/YOUR_API_KEY/chat/completions \ -H "Content-Type: application/json" \ -d '{"model":"auto","messages":[{"role":"user","content":"hello"}]}' ``` ์ฐธ๊ณ : - ํ† ํฐํ™”๋œ ๋ณ„์นญ์€ `/v1/*` ๋ฐ `/api/tags`์™€ ๋™์ผํ•œ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ์‘๋‹ต ํ˜•์‹์€ ๋™์ผํ•˜๊ฒŒ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค. - ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์‚ฌ์šฉ์ž ์ง€์ • ํ—ค๋”๋ฅผ ์ง€์›ํ•˜๋Š” ๊ฒฝ์šฐ ํ•ญ์ƒ `Authorization: Bearer ...`๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. - URL ๊ธฐ๋ฐ˜ ํ† ํฐ์€ OmniRoute ์™ธ๋ถ€์˜ ๋ฆฌ๋ฒ„์Šค ํ”„๋ก์‹œ ๋กœ๊ทธ, ๋ธŒ๋ผ์šฐ์ € ๊ธฐ๋ก ๋ฐ ํ…”๋ ˆ๋ฉ”ํŠธ๋ฆฌ์— ๋‚˜ํƒ€๋‚  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ๊ธฐ๋ณธ ์ธ์ฆ ๋ฐฉ์‹์ด ์•„๋‹Œ ํ˜ธํ™˜์„ฑ ์˜ต์…˜์œผ๋กœ ์ทจ๊ธ‰ํ•˜์„ธ์š”. --- ## ํ…”๋ ˆ๋ฉ”ํŠธ๋ฆฌ ```bash # ์ง€์—ฐ ์‹œ๊ฐ„ ํ…”๋ ˆ๋ฉ”ํŠธ๋ฆฌ ์š”์•ฝ ๊ฐ€์ ธ์˜ค๊ธฐ(์ œ๊ณต์ž๋ณ„ p50/p95/p99) GET /api/telemetry/summary ``` **์‘๋‹ต:** ```json { "providers": { "claudeCode": { "p50": 245, "p95": 890, "p99": 1200, "count": 150 }, "github": { "p50": 180, "p95": 620, "p99": 950, "count": 320 } } } ``` --- ## ์˜ˆ์‚ฐ ```bash # ๋ชจ๋“  API ํ‚ค์˜ ์˜ˆ์‚ฐ ์ƒํƒœ ๊ฐ€์ ธ์˜ค๊ธฐ GET /api/usage/budget # ์˜ˆ์‚ฐ ์„ค์ • ๋˜๋Š” ์—…๋ฐ์ดํŠธ POST /api/usage/budget Content-Type: application/json { "apiKeyId": "key-123", "dailyLimitUsd": 5.00, "weeklyLimitUsd": 30.00, "monthlyLimitUsd": 100.00, "warningThreshold": 0.8, "resetInterval": "monthly" } ``` > **์Šคํ‚ค๋งˆ ์ฐธ๊ณ  ์‚ฌํ•ญ** (`setBudgetSchema`): `apiKeyId`๋Š” ํ•„์ˆ˜์ด๋ฉฐ, `dailyLimitUsd`, `weeklyLimitUsd`, `monthlyLimitUsd` ์ค‘ ํ•˜๋‚˜ ์ด์ƒ์ด 0๋ณด๋‹ค ์ปค์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์„ ํƒ์  ํ•„๋“œ: `warningThreshold`(0~1), `resetInterval`(`daily` | `weekly` | `monthly`), `resetTime`(`HH:MM`). ๋ ˆ๊ฑฐ์‹œ `{keyId, limit, period}` ํ˜•์‹์„ ์‚ฌ์šฉํ•˜๋ฉด `400 Bad Request`๊ฐ€ ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค. ## ํ† ํฐ ํ•œ๋„ API ํ‚ค๋ณ„ **ํ† ํฐ** ์˜ˆ์‚ฐ์ž…๋‹ˆ๋‹ค(์œ„์˜ USD ๊ธฐ๋ฐ˜ ์˜ˆ์‚ฐ๊ณผ๋Š” ๋ณ„๊ฐœ). ์š”์ฒญ ๊ฒฝ๋กœ์—์„œ ์ธ๋ผ์ธ์œผ๋กœ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. ํ‚ค์˜ ํ˜„์žฌ ๊ธฐ๊ฐ„ ์‚ฌ์šฉ๋Ÿ‰์ด ํ•œ๋„์— ๋„๋‹ฌํ•˜๋ฉด ์š”์ฒญ์ด `429 Too Many Requests`๋กœ ๊ฑฐ๋ถ€๋ฉ๋‹ˆ๋‹ค. ํ•œ๋„๋Š” ํŠน์ • `model`, `provider`์— ์ง€์ •ํ•˜๊ฑฐ๋‚˜ ํ‚ค ์ „์ฒด์— `global`๋กœ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜๋‚˜์˜ ์š”์ฒญ์— ์—ฌ๋Ÿฌ ํ•œ๋„๊ฐ€ ์ผ์น˜ํ•˜๋ฉด ๊ฐ€์žฅ ์ œํ•œ์ ์ธ ํ•œ๋„๊ฐ€ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. ```bash # ํ‚ค์˜ ํ† ํฐ ํ•œ๋„ ๋ชฉ๋ก ์กฐํšŒ(ํ˜„์žฌ ๊ธฐ๊ฐ„์˜ ์‹ค์‹œ๊ฐ„ ์‚ฌ์šฉ๋Ÿ‰ ํฌํ•จ) GET /api/usage/token-limits?apiKeyId=key-123 # ํ† ํฐ ํ•œ๋„ ์ƒ์„ฑ ๋˜๋Š” ์—…๋ฐ์ดํŠธ POST /api/usage/token-limits Content-Type: application/json { "apiKeyId": "key-123", "scopeType": "model", "scopeValue": "openai/gpt-4o", "tokenLimit": 1000000, "resetInterval": "monthly", "enabled": true } # id๋กœ ํ† ํฐ ํ•œ๋„ ์‚ญ์ œ DELETE /api/usage/token-limits?id=tl-abc ``` > **์Šคํ‚ค๋งˆ ์ฐธ๊ณ  ์‚ฌํ•ญ** (`setTokenLimitSchema`): `apiKeyId`์™€ `scopeType`(`model` | `provider` | `global`)์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค. `scopeType`์ด `global`์ด ์•„๋‹Œ ๊ฒฝ์šฐ `scopeValue`๊ฐ€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค(์˜ˆ: `model` ๋ฒ”์œ„์—๋Š” ๋ชจ๋ธ ID, `provider` ๋ฒ”์œ„์—๋Š” ์ œ๊ณต์ž ID). `tokenLimit`๋Š” ์–‘์˜ ์ •์ˆ˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค(๋ฌธ์ž์—ด์—์„œ ๊ฐ•์ œ ๋ณ€ํ™˜๋จ). ์„ ํƒ ์‚ฌํ•ญ: `id`(์ƒ์„ฑ ์‹œ ์ƒ๋žตํ•˜๊ณ  ์—…๋ฐ์ดํŠธ ์‹œ ์ง€์ •), `resetInterval`(`daily` | `weekly` | `monthly`, ๊ธฐ๋ณธ๊ฐ’ `monthly`), `resetTime`(`HH:MM`), `enabled`(๊ธฐ๋ณธ๊ฐ’ `true`). `GET` ์‘๋‹ต์—์„œ๋Š” ๊ฐ ํ•œ๋„์— `tokensUsed`, `remaining`, `windowStart`, `periodStartAt`, `nextResetAt`๊ฐ€ ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๊ด€๋ฆฌ ํด๋ž˜์Šค ์—”๋“œํฌ์ธํŠธ์ž…๋‹ˆ๋‹ค(์ธ์ฆ์€ authz ํŒŒ์ดํ”„๋ผ์ธ์—์„œ ์ค‘์•™ ์ง‘์ค‘์‹์œผ๋กœ ์ ์šฉ๋จ). ## ์š”์ฒญ ์ฒ˜๋ฆฌ 1. ํด๋ผ์ด์–ธํŠธ๊ฐ€ `/v1/*`๋กœ ์š”์ฒญ์„ ์ „์†กํ•ฉ๋‹ˆ๋‹ค 2. ๋ผ์šฐํŠธ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ `handleChat`, `handleEmbedding`, `handleAudioTranscription` ๋˜๋Š” `handleImageGeneration`์„ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค 3. ๋ชจ๋ธ์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค(์ง์ ‘ ์ง€์ •ํ•œ ์ œ๊ณต์ž/๋ชจ๋ธ ๋˜๋Š” ๋ณ„์นญ/์ฝค๋ณด) 4. ๊ณ„์ • ๊ฐ€์šฉ์„ฑ ํ•„ํ„ฐ๋ง์„ ์‚ฌ์šฉํ•˜์—ฌ ๋กœ์ปฌ DB์—์„œ ์ž๊ฒฉ ์ฆ๋ช…์„ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค 5. ์ฑ„ํŒ…์˜ ๊ฒฝ์šฐ `handleChatCore`๊ฐ€ ์˜๋ฏธ๋ก ์ /์„œ๋ช… ์บ์‹œ๋ฅผ ํ™•์ธํ•˜๊ณ  ์ฝค๋ณด ์••์ถ• ์„ค์ •์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค 6. ํ™œ์„ฑํ™”๋œ ๊ฒฝ์šฐ ์ œ๊ณต์ž ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ ์ „์— ์„ ์ œ์  ์••์ถ•์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค(`lite`, Caveman, RTK ๋˜๋Š” ์Šคํƒ ๋ฐฉ์‹) 7. ์ œ๊ณต์ž ์‹คํ–‰๊ธฐ๊ฐ€ ์—…์ŠคํŠธ๋ฆผ ์š”์ฒญ์„ ์ „์†กํ•ฉ๋‹ˆ๋‹ค 8. ์‘๋‹ต์„ ํด๋ผ์ด์–ธํŠธ ํ˜•์‹์œผ๋กœ ๋‹ค์‹œ ๋ณ€ํ™˜ํ•˜๊ฑฐ๋‚˜(์ฑ„ํŒ…), ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค(์ž„๋ฒ ๋”ฉ/์ด๋ฏธ์ง€/์˜ค๋””์˜ค) 9. ์‚ฌ์šฉ๋Ÿ‰, ์••์ถ• ๋ถ„์„ ๋ฐ ์š”์ฒญ ๋กœ๊ทธ๋ฅผ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค 10. ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ ์ฝค๋ณด ๊ทœ์น™์— ๋”ฐ๋ผ ํด๋ฐฑ์„ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค ์ „์ฒด ์•„ํ‚คํ…์ฒ˜ ์ฐธ๊ณ  ๋ฌธ์„œ: [`ARCHITECTURE.md`](../architecture/ARCHITECTURE.md) --- ## ์ฝค๋ณด ๊ด€๋ฆฌ ์ƒ์œ„ ์ˆ˜์ค€์˜ ๋ผ์šฐํŒ… ์ฝค๋ณด(`/api/combos*`์—์„œ ์ด๋ฏธ ์š”์•ฝ๋จ)๋Š” ๋ชจ๋ธ ID ํŒจํ„ด๊ณผ 1:1๋กœ ๋งคํ•‘ํ•  ์ˆ˜๋„ ์žˆ์–ด, OpenAI ์Šคํƒ€์ผ์˜ ๋ชจ๋ธ ID๋ฅผ ์ฝค๋ณด๋กœ ํˆฌ๋ช…ํ•˜๊ฒŒ ๋ฆฌ๋””๋ ‰์…˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. | ๋ฉ”์„œ๋“œ | ๊ฒฝ๋กœ | ์„ค๋ช… | | ------ | -------------------------------- | ------------------------------------------------------------------------- | | GET | `/api/model-combo-mappings` | ๋ชจ๋“  ๋ชจ๋ธโ†’์ฝค๋ณด ๋งคํ•‘ ์กฐํšŒ | | POST | `/api/model-combo-mappings` | ๋งคํ•‘ ์ƒ์„ฑ โ€” ๋ณธ๋ฌธ: `{pattern, comboId, priority?, enabled?, description?}` | | GET | `/api/model-combo-mappings/[id]` | ๋‹จ์ผ ๋งคํ•‘ ์กฐํšŒ | | PUT | `/api/model-combo-mappings/[id]` | ๊ธฐ์กด ๋งคํ•‘์˜ ํ•„๋“œ ์—…๋ฐ์ดํŠธ | | DELETE | `/api/model-combo-mappings/[id]` | ๋งคํ•‘ ์‚ญ์ œ | **์ธ์ฆ:** ๊ด€๋ฆฌ ์„ธ์…˜/API ํ‚ค(`requireManagementAuth`). --- ## ์›นํ›… OmniRoute ์ด๋ฒคํŠธ(์š”์ฒญ ์™„๋ฃŒ, ํ• ๋‹น๋Ÿ‰ ์†Œ์ง„, ํ‚ค ๊ต์ฒด ๋“ฑ)์— ๋Œ€ํ•œ ์•„์›ƒ๋ฐ”์šด๋“œ ์›นํ›… ๊ตฌ๋…์ž…๋‹ˆ๋‹ค. | ๋ฉ”์„œ๋“œ | ๊ฒฝ๋กœ | ์„ค๋ช… | | ------ | ------------------------- | ---------------------------------------------------------------- | | GET | `/api/webhooks` | ์›นํ›… ๋ชฉ๋ก ์กฐํšŒ(์‹œํฌ๋ฆฟ์€ `...` ํ˜•์‹์œผ๋กœ ๋งˆ์Šคํ‚น๋จ) | | POST | `/api/webhooks` | ์›นํ›… ์ƒ์„ฑ โ€” ๋ณธ๋ฌธ: `{url, events?: ["*"], secret?, description?}` | | GET | `/api/webhooks/[id]` | ์›นํ›… ์กฐํšŒ | | PUT | `/api/webhooks/[id]` | url/events/secret/description ์—…๋ฐ์ดํŠธ | | DELETE | `/api/webhooks/[id]` | ์›นํ›… ์ œ๊ฑฐ | | POST | `/api/webhooks/[id]/test` | ์›นํ›… URL๋กœ ํ…Œ์ŠคํŠธ ํŽ˜์ด๋กœ๋“œ๋ฅผ ์ „์†กํ•˜๊ณ  ์ „๋‹ฌ ์ƒํƒœ ๋ฐ˜ํ™˜ | **์ธ์ฆ:** ๊ด€๋ฆฌ ์„ธ์…˜/API ํ‚ค(`requireManagementAuth`). --- ## ๋“ฑ๋ก๋œ ํ‚ค(์ž๋™ ๊ด€๋ฆฌ) ์ž๋™ ํ‚ค ๊ด€๋ฆฌ ํ•˜์œ„ ์‹œ์Šคํ…œ์—์„œ ๊ธฐ๋ฐ˜ ์ œ๊ณต์ž/๊ณ„์ •์— ๋Œ€ํ•ด ์ผ๋ณ„/์‹œ๊ฐ„๋ณ„ ํ• ๋‹น๋Ÿ‰์„ ์ ์šฉํ•˜์—ฌ API ํ‚ค๋ฅผ ๋ฐœ๊ธ‰ํ•˜๊ณ  ๊ต์ฒดํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. | ๋ฉ”์„œ๋“œ | ๊ฒฝ๋กœ | ์„ค๋ช… | | ------ | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | GET | `/api/v1/registered-keys` | ๋“ฑ๋ก๋œ ํ‚ค ๋ชฉ๋ก ์กฐํšŒ(๋งˆ์Šคํ‚น๋œ ์ ‘๋‘์‚ฌ๋งŒ ํ‘œ์‹œ) | | POST | `/api/v1/registered-keys` | ์ƒˆ ๋“ฑ๋ก ํ‚ค ๋ฐœ๊ธ‰ โ€” ๋ณธ๋ฌธ: `{name, provider?, accountId?, idempotencyKey?, expiresAt?, dailyBudget?, hourlyBudget?}`. ์›๋ณธ ํ‚ค๋Š” **ํ•œ ๋ฒˆ๋งŒ** ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค. ํ• ๋‹น๋Ÿ‰์œผ๋กœ ์ธํ•ด ๊ฑฐ๋ถ€๋˜๋ฉด `429`๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. | | GET | `/api/v1/registered-keys/[id]` | ๋“ฑ๋ก๋œ ํ‚ค์˜ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์กฐํšŒ(์›๋ณธ ํ‚ค ์ž๋ฃŒ ์ œ์™ธ) | | DELETE | `/api/v1/registered-keys/[id]` | ๋“ฑ๋ก๋œ ํ‚ค ํ๊ธฐ | | POST | `/api/v1/registered-keys/[id]/revoke` | ๋ช…์‹œ์  ํ๊ธฐ ์—”๋“œํฌ์ธํŠธ(DELETE์™€ ๋™์ผํ•œ ํšจ๊ณผ) | **์ธ์ฆ:** Bearer API ํ‚ค(`isAuthenticated`). `/v1/quotas/check` ๋ฐ `/v1/issues/report`๋„ ์ฐธ์กฐํ•˜์„ธ์š”. --- ## ์—์ด์ „ํŠธ ํ”„๋กœํ† ์ฝœ OmniRoute ์‚ฌ์šฉ์ž๋ฅผ ๋Œ€์‹ ํ•ด ์›๊ฒฉ์œผ๋กœ ์‹คํ–‰๋˜๋Š” ํด๋ผ์šฐ๋“œ ์—์ด์ „ํŠธ ์ž‘์—…(Claude Code, Codex Cloud, OpenHands ๋“ฑ)์ž…๋‹ˆ๋‹ค. | ๋ฉ”์„œ๋“œ | ๊ฒฝ๋กœ | ์„ค๋ช… | | ------ | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | | GET | `/api/v1/agents/tasks` | ์ž‘์—… ๋ชฉ๋ก โ€” ์„ ํƒ์  `?provider=`, `?status=`, `?limit=`(1~500, ๊ธฐ๋ณธ๊ฐ’ 50) | | POST | `/api/v1/agents/tasks` | ์ž‘์—… ์ƒ์„ฑ โ€” ๋ณธ๋ฌธ์€ `CreateCloudAgentTaskSchema`(`providerId`, `prompt`, `source`, `options?`)๋กœ ๊ฒ€์ฆ๋ฉ๋‹ˆ๋‹ค. ์ž‘์—… ์—”๋ฒŒ๋กœํ”„์™€ ํ•จ๊ป˜ `201`์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค | | DELETE | `/api/v1/agents/tasks?id=...` | ์ž‘์—… ์‚ญ์ œ | | GET | `/api/v1/agents/tasks/[id]` | ์ž‘์—… ์กฐํšŒ โ€” `external_id`๊ฐ€ ์„ค์ •๋œ ๊ฒฝ์šฐ ์—…์ŠคํŠธ๋ฆผ ํด๋ผ์šฐ๋“œ ์—์ด์ „ํŠธ์—์„œ ์ƒํƒœ๋ฅผ ๋™๊ธฐ์‹์œผ๋กœ ์ƒˆ๋กœ ๊ณ ์นฉ๋‹ˆ๋‹ค | | POST | `/api/v1/agents/tasks/[id]` | ๊ตฌ๋ถ„๋œ ์ž‘์—…: `{action: "approve"}`, `{action: "message", message}` ๋˜๋Š” `{action: "cancel"}` | | DELETE | `/api/v1/agents/tasks/[id]` | id๋กœ ํŠน์ • ์ž‘์—… ์‚ญ์ œ | > **์ธ์ฆ:** ๋ชจ๋“  ๋ฉ”์„œ๋“œ์— ๊ด€๋ฆฌ ์ธ์ฆ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค(`requireCloudAgentManagementAuth`). v3.8.0 ์ด์ „์—๋Š” ์ธ์ฆ์ด ํ•„์š”ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ํ˜ธํ™˜์„ฑ์„ ๊นจ๋œจ๋ฆฌ๋Š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ์€ ์ปค๋ฐ‹ `588a0333`์„ ์ฐธ์กฐํ•˜์„ธ์š”. ```bash # Claude Code ํด๋ผ์šฐ๋“œ ์ž‘์—… ์ƒ์„ฑ curl -X POST http://localhost:20128/api/v1/agents/tasks \ -H "Authorization: Bearer your-management-key" \ -H "Content-Type: application/json" \ -d '{"providerId":"claude-code-cloud","prompt":"Fix the failing test","source":{"repo":"...","branch":"..."}}' ``` --- ## ๊ด€๋ฆฌ ํ”„๋ก์‹œ ํ”„๋กœ๋ฐ”์ด๋”, ๊ณ„์ • ๋˜๋Š” ์ „์—ญ์— ํ• ๋‹นํ•  ์ˆ˜ ์žˆ๋Š” ์•„์›ƒ๋ฐ”์šด๋“œ HTTP(S)/SOCKS ํ”„๋ก์‹œ์ž…๋‹ˆ๋‹ค. | ๋ฉ”์„œ๋“œ | ๊ฒฝ๋กœ | ์„ค๋ช… | | ------ | -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | | GET | `/api/v1/management/proxies` | ํ”„๋ก์‹œ ๋ชฉ๋ก ์กฐํšŒ(`?id=`๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ•˜๋‚˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ , `?id=&where_used=1`์„ ์‚ฌ์šฉํ•˜๋ฉด ํ• ๋‹น ๊ทธ๋ž˜ํ”„๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค) | | POST | `/api/v1/management/proxies` | ํ”„๋ก์‹œ ์ƒ์„ฑ โ€” ๋ณธ๋ฌธ์€ `createProxyRegistrySchema`๋กœ ๊ฒ€์ฆ๋ฉ๋‹ˆ๋‹ค | | PATCH | `/api/v1/management/proxies` | ํ”„๋ก์‹œ ์—…๋ฐ์ดํŠธ โ€” ๋ณธ๋ฌธ์€ `updateProxyRegistrySchema`๋กœ ๊ฒ€์ฆ๋ฉ๋‹ˆ๋‹ค(`id` ํ•„์š”) | | DELETE | `/api/v1/management/proxies?id=...&force=1` | ํ”„๋ก์‹œ ์‚ญ์ œ(ํ• ๋‹น์„ ํ•ด์ œํ•˜๋ ค๋ฉด `force=1` ์‚ฌ์šฉ) | | GET | `/api/v1/management/proxies/assignments` | ํ• ๋‹น ๋ชฉ๋ก โ€” `proxy_id`, `scope`, `scope_id`๋กœ ํ•„ํ„ฐ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฐ๊ฒฐ์˜ ํ™œ์„ฑ ํ”„๋ก์‹œ๋ฅผ ํ™•์ธํ•˜๋ ค๋ฉด `resolve_connection_id=`๋ฅผ ์ „๋‹ฌํ•˜์„ธ์š” | | PUT | `/api/v1/management/proxies/assignments` | ํ• ๋‹น โ€” ๋ณธ๋ฌธ์€ `proxyAssignmentSchema`(`{scope, scopeId?, proxyId?}`)๋กœ ๊ฒ€์ฆ๋ฉ๋‹ˆ๋‹ค. ๋””์ŠคํŒจ์ฒ˜ ์บ์‹œ๋ฅผ ์ง€์›๋‹ˆ๋‹ค | | PUT | `/api/v1/management/proxies/bulk-assign` | ์ผ๊ด„ ํ• ๋‹น โ€” ๋ณธ๋ฌธ์€ `bulkProxyAssignmentSchema`(`{scope, scopeIds[], proxyId?}`)๋กœ ๊ฒ€์ฆ๋ฉ๋‹ˆ๋‹ค | | GET | `/api/v1/management/proxies/health?hours=24` | ์ผ์ • ๊ธฐ๊ฐ„์˜ ํ”„๋ก์‹œ ์ƒํƒœ ์ง‘๊ณ„(์„ฑ๊ณต/์‹คํŒจ ํšŸ์ˆ˜, ์ง€์—ฐ ์‹œ๊ฐ„) | **์ธ์ฆ:** ๋ชจ๋“  ๋ผ์šฐํŠธ์— ๊ด€๋ฆฌ ์„ธ์…˜/API ํ‚ค๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค(`requireManagementAuth`). > ์ž‘์—… ์„ค๋ช…์˜ `POST /api/v1/management/proxies/[id]/assignments` ๋ฐ `POST /api/v1/management/proxies/[id]/health`๋Š” ์œ„์— ํ‘œ์‹œ๋œ ํ”Œ๋žซ `/assignments` ๋ฐ `/health` ๋ผ์šฐํŠธ์—์„œ ์ฒ˜๋ฆฌ๋ฉ๋‹ˆ๋‹ค. ์ฝ”๋“œ๋ฒ ์ด์Šค์—๋Š” id๋ณ„ ํ•˜์œ„ ๋ผ์šฐํŠธ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. --- ## ๋ณต์›๋ ฅ(ํ™•์žฅ) OmniRoute๋Š” ์„œ๋กœ ๋…๋ฆฝ์ ์ธ ์„ธ ๊ฐ€์ง€ ์ผ์‹œ์  ์žฅ์•  ๋Œ€์‘ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜ ๊ด€๋ฆฌ ์—”๋“œํฌ์ธํŠธ๋ฅผ ํ†ตํ•ด ์šด์˜์ž๋Š” ํ•ด๋‹น ์ƒํƒœ๋ฅผ ์กฐํšŒํ•˜๊ณ  ์žฌ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. | ๋ฒ”์œ„ | ์ƒํƒœ ์ €์žฅ์†Œ | ์กฐํšŒ | ์žฌ์„ค์ • / ํ•ด์ œ | | ------------- | ------------------------------------ | ----------------------------------------- | ----------------------------------------------------- | | ๊ณต๊ธ‰์ž ์ฐจ๋‹จ๊ธฐ | `domain_circuit_breakers` + ์ธ๋ฉ”๋ชจ๋ฆฌ | `/api/monitoring/health` | `POST /api/resilience/reset` | | ์—ฐ๊ฒฐ ์ฟจ๋‹ค์šด | ๊ณต๊ธ‰์ž ์—ฐ๊ฒฐ์˜ `rateLimitedUntil` | `/api/rate-limits`, `/api/providers/[id]` | (์ง€์—ฐ ๋ฐฉ์‹์œผ๋กœ ๋‹ค์‹œ ํ™œ์„ฑํ™”๋จ. ๊ณต๊ธ‰์ž PUT์„ ํ†ตํ•ด ํ•ด์ œ) | | ๋ชจ๋ธ ์ž ๊ธˆ | ์ธ๋ฉ”๋ชจ๋ฆฌ ๋ชจ๋ธ ๊ฐ€์šฉ์„ฑ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ | `GET /api/resilience/model-cooldowns` | `DELETE /api/resilience/model-cooldowns` | `PATCH /api/resilience`๋Š” `providerBreaker.oauth` ๋ฐ `providerBreaker.apikey`์—์„œ ๊ณต๊ธ‰์ž ์ฐจ๋‹จ๊ธฐ ์žฌ์ •์˜๋ฅผ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ฐ ํ”„๋กœํ•„์€ `degradationThreshold`, `failureThreshold`, `resetTimeoutMs`๋ฅผ ์ง€์›ํ•˜๋ฉฐ, ๋™์ผํ•œ ํ•„๋“œ๋ฅผ ๋Œ€์‹œ๋ณด๋“œ โ†’ ์„ค์ • โ†’ ๋ณต์›๋ ฅ์—์„œ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ```bash # ๋‹จ์ผ ๋ชจ๋ธ ์ž ๊ธˆ ํ•ด์ œ curl -X DELETE http://localhost:20128/api/resilience/model-cooldowns \ -H "Cookie: auth_token=..." \ -H "Content-Type: application/json" \ -d '{"provider":"openai","model":"gpt-4o-mini"}' # ๋ชจ๋“  ์ž ๊ธˆ ์‚ญ์ œ curl -X DELETE http://localhost:20128/api/resilience/model-cooldowns \ -H "Cookie: auth_token=..." \ -d '{"all":true}' ``` ์ „์ฒด ๊ฐœ๋… ์„ค๋ช…๊ณผ ์ฐจ๋‹จ๊ธฐ ๊ธฐ๋ณธ๊ฐ’์€ [`CLAUDE.md`](../../CLAUDE.md) โ†’ "๋ณต์›๋ ฅ ๋Ÿฐํƒ€์ž„ ์ƒํƒœ"๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”. --- ## ์Šคํ‚ฌ ์‚ฌ์šฉ์ž ์ •์˜ ์‹คํ–‰ ๊ฐ€๋Šฅ ํ•ธ๋“ค๋Ÿฌ์™€ ๋งˆ์ผ“ํ”Œ๋ ˆ์ด์Šค ํ†ตํ•ฉ์„ ํ†ตํ•ด OmniRoute๋ฅผ ํ™•์žฅํ•˜๋Š” ์Šคํ‚ฌ ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค. | ๋ฉ”์„œ๋“œ | ๊ฒฝ๋กœ | ์„ค๋ช… | | ------ | --------------------------------- | --------------------------------------------------------------------------------------------------------------------- | | GET | `/api/skills` | ์„ค์น˜๋œ ์Šคํ‚ฌ ๋ชฉ๋ก โ€” `?q=`, `?mode=on\|off\|auto`, `?source=skillsmp\|skillssh\|local`๋กœ ํ•„ํ„ฐ๋ง ๊ฐ€๋Šฅ, ํŽ˜์ด์ง€๋„ค์ด์…˜ ์ง€์› | | GET | `/api/skills/[id]` | ์Šคํ‚ฌ ํ•˜๋‚˜ ์กฐํšŒ | | PUT | `/api/skills/[id]` | ์Šคํ‚ฌ ์—…๋ฐ์ดํŠธ(name, description, mode, schema, handler, tags) | | DELETE | `/api/skills/[id]` | ์Šคํ‚ฌ ์ œ๊ฑฐ | | POST | `/api/skills/install` | ์›์‹œ ๋งค๋‹ˆํŽ˜์ŠคํŠธ์—์„œ ์Šคํ‚ฌ ์„ค์น˜ โ€” ๋ณธ๋ฌธ: `{name, version, description, schema:{input, output}, handlerCode, apiKeyId?}` | | GET | `/api/skills/executions` | ์ตœ๊ทผ ์Šคํ‚ฌ ์‹คํ–‰ ๋ชฉ๋ก(์ž…๋ ฅ/์ถœ๋ ฅ/์‹คํ–‰ ์‹œ๊ฐ„์ด ํฌํ•จ๋œ ๊ฐ์‚ฌ ์ถ”์ ) | | GET | `/api/skills/marketplace?q=...` | SkillsMP ๋งˆ์ผ“ํ”Œ๋ ˆ์ด์Šค์—์„œ ๊ฒ€์ƒ‰/์ธ๊ธฐ ๋ชฉ๋ก ์กฐํšŒ(`skillsmpApiKey` ์„ค์ • ํ•„์š”) | | POST | `/api/skills/marketplace/install` | SkillsMP์—์„œ id๋กœ ์Šคํ‚ฌ ์„ค์น˜ | | GET | `/api/skills/skillssh?q=&limit=` | skills.sh ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ๊ฒ€์ƒ‰ | | POST | `/api/skills/skillssh/install` | skills.sh์—์„œ id๋กœ ์Šคํ‚ฌ ์„ค์น˜ | **์ธ์ฆ:** ๊ด€๋ฆฌ ์„ธ์…˜/API ํ‚ค. ๋งˆ์ผ“ํ”Œ๋ ˆ์ด์Šค ๊ฒ€์ƒ‰ ๊ฒฝ๋กœ๋Š” ๊ด€๋ฆฌ ์ธ์ฆ ๋˜๋Š” Bearer API ํ‚ค(`isAuthenticated`)๋ฅผ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค. --- ## ๋ฉ”๋ชจ๋ฆฌ API ํ‚ค/์„ธ์…˜๋ณ„๋กœ ๋ฒ”์œ„๊ฐ€ ์ง€์ •๋˜๋Š” ์˜๊ตฌ ๋Œ€ํ™”/์‚ฌ์‹ค ๋ฉ”๋ชจ๋ฆฌ ์ €์žฅ์†Œ์ž…๋‹ˆ๋‹ค. | ๋ฉ”์„œ๋“œ | ๊ฒฝ๋กœ | ์„ค๋ช… | | ------ | -------------------- | --------------------------------------------------------------------------------------------------------- | | GET | `/api/memory` | ๋ฉ”๋ชจ๋ฆฌ ๋ชฉ๋ก โ€” `?apiKeyId=`, `?type=`, `?sessionId=`, `?q=`, `offset/limit` ๋˜๋Š” `page/limit` ํŽ˜์ด์ง€๋„ค์ด์…˜ | | POST | `/api/memory` | ๋ฉ”๋ชจ๋ฆฌ ์ƒ์„ฑ โ€” Zod๋กœ ๊ฒ€์ฆ๋˜๋Š” ๋ณธ๋ฌธ: `{content, key, type?, sessionId?, apiKeyId?, metadata?, expiresAt?}` | | GET | `/api/memory/[id]` | ๋‹จ์ผ ๋ฉ”๋ชจ๋ฆฌ ์กฐํšŒ | | DELETE | `/api/memory/[id]` | ๋ฉ”๋ชจ๋ฆฌ ์‚ญ์ œ | | GET | `/api/memory/health` | ๋ฉ”๋ชจ๋ฆฌ ํ•˜์œ„ ์‹œ์Šคํ…œ ์ƒํƒœ(DB ์—ฐ๊ฒฐ, ์ž„๋ฒ ๋”ฉ ๋ฐฑ์—”๋“œ, ๋ฒกํ„ฐ ์ธ๋ฑ์Šค ์ƒํƒœ) | **์ธ์ฆ:** ๊ด€๋ฆฌ ์„ธ์…˜/API ํ‚ค(`requireManagementAuth`). `type` ์—ด๊ฑฐํ˜•: `FACTUAL`, `EPISODIC`, `SEMANTIC`, `PROCEDURAL`(`src/lib/memory/types.ts`์˜ `MemoryType` ์ฐธ์กฐ). --- ## MCP ์„œ๋ฒ„ OmniRoute์—๋Š” 3๊ฐ€์ง€ ์ „์†ก ๋ฐฉ์‹(stdio, SSE, streamable-http)๊ณผ ๋ฒ”์œ„๊ฐ€ ์ง€์ •๋œ ๋„๊ตฌ๋ฅผ ์ง€์›ํ•˜๋Š” Model Context Protocol ์„œ๋ฒ„๊ฐ€ ๋‚ด์žฅ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์˜ ๋Œ€์‹œ๋ณด๋“œ ์—”๋“œํฌ์ธํŠธ๋Š” ์ƒํƒœ/๊ฐ์‚ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ณ  HTTP ์ „์†ก์„ ํ”„๋ก์‹œํ•ฉ๋‹ˆ๋‹ค. | ๋ฉ”์„œ๋“œ | ๊ฒฝ๋กœ | ์„ค๋ช… | | ------ | ---------------------- | ------------------------------------------------------------------------------------------------ | -------------------- | | GET | `/api/mcp/status` | ํ•˜ํŠธ๋น„ํŠธ, ์ „์†ก ๋ฐฉ์‹, ์˜จ๋ผ์ธ ์ƒํƒœ, ๋งˆ์ง€๋ง‰ ํ˜ธ์ถœ, ์ƒ์œ„ ๋„๊ตฌ, 24์‹œ๊ฐ„ ์„ฑ๊ณต๋ฅ  | | GET | `/api/mcp/tools` | `name`, `description`, `scopes`, `phase`, `auditLevel`, `sourceEndpoints`๊ฐ€ ํฌํ•จ๋œ MCP ๋„๊ตฌ ๋ชฉ๋ก | | GET | `/api/mcp/sse` | SSE ์ „์†ก์šฉ SSE ์ŠคํŠธ๋ฆผ ์—ด๊ธฐ(MCP๊ฐ€ ๋น„ํ™œ์„ฑํ™”๋˜์—ˆ๊ฑฐ๋‚˜ ์ „์†ก ๋ฐฉ์‹์ด ์ผ์น˜ํ•˜์ง€ ์•Š์œผ๋ฉด `503` ๋ฐ˜ํ™˜) | | POST | `/api/mcp/sse` | SSE ์ „์†ก์„ ํ†ตํ•ด JSON-RPC ํ”„๋ ˆ์ž„ ์ „์†ก | | GET | `/api/mcp/stream` | Streamable HTTP ์ „์†ก์˜ SSE ์ธก ์—ด๊ธฐ(์„œ๋ฒ„์—์„œ ์‹œ์ž‘๋˜๋Š” ๋ฉ”์‹œ์ง€) | | POST | `/api/mcp/stream` | Streamable HTTP ์ „์†ก์„ ํ†ตํ•ด JSON-RPC ํ”„๋ ˆ์ž„ ์ „์†ก | | DELETE | `/api/mcp/stream` | Streamable HTTP ์„ธ์…˜ ์ข…๋ฃŒ | | GET | `/api/mcp/audit` | ๊ฐ์‚ฌ ๋กœ๊ทธ ์กฐํšŒ โ€” `?limit=`, `?offset=`, `?tool=`, `?success=true | false`, `?apiKeyId=` | | GET | `/api/mcp/audit/stats` | ์ง‘๊ณ„๋œ ๊ฐ์‚ฌ ํ†ต๊ณ„(์ด๊ณ„, ์„ฑ๊ณต๋ฅ , ํ‰๊ท  ์†Œ์š” ์‹œ๊ฐ„, ์ƒ์œ„ ๋„๊ตฌ) | **์ธ์ฆ:** `sse`/`stream` ์ „์†ก์€ MCP ์ „์šฉ ์ธ์ฆ ๋ฐฉ์‹(`mcp` ๋ฒ”์œ„๊ฐ€ ์žˆ๋Š” Bearer API ํ‚ค)์„ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค. `status`/`tools`/`audit*` ๊ฒฝ๋กœ๋Š” ๋Œ€์‹œ๋ณด๋“œ์—์„œ ์ฝ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(๋Œ€์‹œ๋ณด๋“œ ํ˜ธ์ŠคํŠธ์— ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ ์™ธ์— ์ถ”๊ฐ€ ์ธ์ฆ์€ ํ•„์š”ํ•˜์ง€ ์•Š์Œ). > ๋‘ HTTP ์ „์†ก ๋ชจ๋‘ `settings.mcpEnabled` ๋ฐ `settings.mcpTransport`์— ์˜ํ•ด ์ œ์–ด๋ฉ๋‹ˆ๋‹ค. ์ „์†ก ๋ฐฉ์‹์ด ์ผ์น˜ํ•˜์ง€ ์•Š์œผ๋ฉด `400`, MCP๊ฐ€ ๋น„ํ™œ์„ฑํ™”๋œ ์ƒํƒœ์ด๋ฉด `503`์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. --- ## A2A ์„œ๋ฒ„ OmniRoute๋Š” A2A(Agent-to-Agent) JSON-RPC 2.0 ์—”๋“œํฌ์ธํŠธ์™€ ๊ฒ€์‚ฌ/๋Œ€์‹œ๋ณด๋“œ์šฉ REST ๋ž˜ํผ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ### JSON-RPC ```bash POST /a2a Authorization: Bearer your-api-key # OMNIROUTE_API_KEY๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ์„ ํƒ ์‚ฌํ•ญ Content-Type: application/json { "jsonrpc": "2.0", "id": 1, "method": "message/send", "params": { "skill": "smart-routing", "messages": [{"role": "user", "content": "Route this coding task"}] } } ``` ์ง€์›๋˜๋Š” ๋ฉ”์„œ๋“œ(๋ชจ๋‘ `settings.a2aEnabled`์— ์˜ํ•ด ์ œ์–ด๋จ): | ๋ฉ”์„œ๋“œ | ์„ค๋ช… | | ---------------- | ------------------------------------------------------ | | `message/send` | ๋™๊ธฐ์‹ ์Šคํ‚ฌ ์‹คํ–‰; `{task, artifacts, metadata}`๋ฅผ ๋ฐ˜ํ™˜ | | `message/stream` | ๋™์ผํ•œ ์Šคํ‚ฌ ์„ธํŠธ์˜ ์ŠคํŠธ๋ฆฌ๋ฐ SSE ์‹คํ–‰ | | `tasks/get` | `taskId`๋กœ ํƒœ์Šคํฌ ์กฐํšŒ | | `tasks/cancel` | `taskId`๋กœ ํƒœ์Šคํฌ ์ทจ์†Œ | ๊ธฐ๋ณธ ์ œ๊ณต ์Šคํ‚ฌ: `smart-routing`, `quota-management`, `provider-discovery`, `cost-analysis`, `health-report`. ### ์—์ด์ „ํŠธ ์นด๋“œ ```bash GET /.well-known/agent.json ``` ๊ณต๊ฐœ A2A ์—์ด์ „ํŠธ ์นด๋“œ(์ด๋ฆ„, ์„ค๋ช…, ๊ธฐ๋Šฅ, ์Šคํ‚ฌ ์นดํƒˆ๋กœ๊ทธ, ์ธ์ฆ ์ฒด๊ณ„)๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ, ๊ณต๊ฐœ์ ์œผ๋กœ 1์‹œ๊ฐ„ ๋™์•ˆ ์บ์‹œ๋ฉ๋‹ˆ๋‹ค. ์ธ์ฆ์€ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ### REST ํ—ฌํผ | ๋ฉ”์„œ๋“œ | ๊ฒฝ๋กœ | ์„ค๋ช… | | ------ | ---------------------------- | ---------------------------------------------------------------------------------------------------------------- | | GET | `/api/a2a/status` | A2A ํ™œ์„ฑํ™” ์—ฌ๋ถ€ + ํƒœ์Šคํฌ ํ†ต๊ณ„ + ์บ์‹œ๋œ ์—์ด์ „ํŠธ ์นด๋“œ ์š”์•ฝ | | GET | `/api/a2a/tasks` | ํƒœ์Šคํฌ ๋ชฉ๋ก โ€” `?state=submitted\|working\|completed\|failed\|cancelled`, `?skill=`, `?limit=` (โ‰ค200), `?offset=` | | POST | `/api/a2a/tasks` | (REST ํ—ฌํผ๋กœ ๊ตฌํ˜„๋˜์ง€ ์•Š์Œ โ€” JSON-RPC `message/send`๋ฅผ ํ†ตํ•ด ์ƒ์„ฑ) | | GET | `/api/a2a/tasks/[id]` | ๋‹จ์ผ ํƒœ์Šคํฌ ์กฐํšŒ | | POST | `/api/a2a/tasks/[id]/cancel` | ํƒœ์Šคํฌ ์ทจ์†Œ | **์ธ์ฆ:** REST ํ—ฌํผ๋Š” ๊ด€๋ฆฌ ์ธ์ฆ ์—†์ด ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค(๋Œ€์‹œ๋ณด๋“œ์—์„œ ์ฝ๊ธฐ ๊ฐ€๋Šฅ). JSON-RPC `/a2a` ๊ฒฝ๋กœ๋Š” ์„ค์ •๋œ ๊ฒฝ์šฐ Bearer `OMNIROUTE_API_KEY`๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. --- ## ํด๋ผ์šฐ๋“œ, ํ‰๊ฐ€ ๋ฐ ์ง„๋‹จ | ๋ฉ”์„œ๋“œ | ๊ฒฝ๋กœ | ์„ค๋ช… | | ------ | ------------------------------- | ------------------------------------------------------------------------------------------------- | ----------------------------- | ----------------------------------- | | POST | `/api/cloud/auth` | Bearer ํ‚ค๋ฅผ ๊ฒ€์ฆํ•˜๊ณ  ํด๋ผ์šฐ๋“œ ๋™๊ธฐํ™” ํด๋ผ์ด์–ธํŠธ์šฉ์œผ๋กœ ๋งˆ์Šคํ‚น๋œ ์ œ๊ณต์ž ์—ฐ๊ฒฐ + ๋ชจ๋ธ ๋ณ„์นญ ๋ฐ˜ํ™˜ | | POST | `/api/cloud/credentials/update` | ํด๋ผ์šฐ๋“œ์™€ ๋™๊ธฐํ™”๋œ ์ œ๊ณต์ž์˜ ์•”ํ˜ธํ™”๋œ ์ž๊ฒฉ ์ฆ๋ช… ์—…๋ฐ์ดํŠธ | | POST | `/api/cloud/model/resolve` | ๋กœ์ปฌ ๋ผ์šฐํŒ… ํ…Œ์ด๋ธ”์„ ์‚ฌ์šฉํ•˜์—ฌ ๋…ผ๋ฆฌ์  ๋ชจ๋ธ ID๋ฅผ ๊ตฌ์ฒด์ ์ธ ์ œ๊ณต์ž/๋ชจ๋ธ๋กœ ํ•ด์„ | | GET | `/api/cloud/models/alias` | ํด๋ผ์šฐ๋“œ ๋™๊ธฐํ™”์— ๋…ธ์ถœ๋˜๋Š” ๋ชจ๋ธ ๋ณ„์นญ ๋ชฉ๋ก | | GET | `/api/assess` | ์ตœ์‹  ์ง„๋‹จ ๋ถ„๋ฅ˜ ๊ฒฐ๊ณผ ์ฝ๊ธฐ(์ œ๊ณต์ž/๋ชจ๋ธ๋ณ„) | | POST | `/api/assess` | ์ง„๋‹จ ์‹คํ–‰ โ€” ๋ณธ๋ฌธ: `{scope: {type:"all"} | {type:"provider", providerId} | {type:"model", modelId}, trigger?}` | | GET | `/api/evals` | ๊ธฐ๋ณธ ์ œ๊ณต ํ‰๊ฐ€ ์Šค์œ„ํŠธ + ์ตœ์‹  ์‹คํ–‰ ๋ชฉ๋ก | | POST | `/api/evals` | ํ‰๊ฐ€ ์‹คํ–‰ ํŠธ๋ฆฌ๊ฑฐ | | POST | `/api/evals/suites` | ์‚ฌ์šฉ์ž ์ง€์ • ํ‰๊ฐ€ ์Šค์œ„ํŠธ ์ƒ์„ฑ โ€” `evalSuiteSaveSchema`๋กœ ๋ณธ๋ฌธ ๊ฒ€์ฆ | | GET | `/api/evals/suites/[id]` | ์‚ฌ์šฉ์ž ์ง€์ • ํ‰๊ฐ€ ์Šค์œ„ํŠธ ์กฐํšŒ | **์ธ์ฆ:** `/api/cloud/auth`๋Š” Bearer ํ‚ค๋ฅผ ์ง์ ‘ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค. ๊ทธ ์™ธ `/api/cloud/*`, `/api/evals/*`, `/api/assess` ๊ฒฝ๋กœ์—๋Š” ๊ด€๋ฆฌ ์„ธ์…˜/API ํ‚ค๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. `/api/assess` POST๋Š” ํŒ๋ณ„ ์œ ๋‹ˆ์˜จ ๋ฒ”์œ„ ์Šคํ‚ค๋งˆ์™€ ํ•จ๊ป˜ `validateBody`๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. --- ## ACP(Agent Client Protocol) ๊ด€๋ฆฌ ์ž์‹ ํ”„๋กœ์„ธ์Šค๋กœ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์—”๋“œํฌ์ธํŠธ๋Š” ACP ์—์ด์ „ํŠธ ๊ฐ์ง€ ๋ฐ ์‚ฌ์šฉ์ž ์ง€์ • ์—์ด์ „ํŠธ ๋“ฑ๋ก์„ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. | ๋ฉ”์„œ๋“œ | ๊ฒฝ๋กœ | ์„ค๋ช… | | ------ | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | GET | `/api/acp/agents` | ์„ค์น˜ ์ƒํƒœ, ๋ฒ„์ „, ๋ฐ”์ด๋„ˆ๋ฆฌ๋ฅผ ํฌํ•จํ•˜์—ฌ ์•Œ๋ ค์ง„ ๋ชจ๋“  CLI ์—์ด์ „ํŠธ(๊ธฐ๋ณธ ์ œ๊ณต + ์‚ฌ์šฉ์ž ์ง€์ •) ๋ชฉ๋ก ์กฐํšŒ | | POST | `/api/acp/agents` | ์‚ฌ์šฉ์ž ์ง€์ • ACP ์—์ด์ „ํŠธ ๋“ฑ๋ก ๋˜๋Š” ์บ์‹œ ์ƒˆ๋กœ ๊ณ ์นจ โ€” ๋ณธ๋ฌธ: `{id, name, binary, versionCommand, providerAlias, spawnArgs, protocol}` ๋˜๋Š” `{action: "refresh"}` | | DELETE | `/api/acp/agents` | ์‚ฌ์šฉ์ž ์ง€์ • ACP ์—์ด์ „ํŠธ ์ œ๊ฑฐ โ€” ์ฟผ๋ฆฌ ๋งค๊ฐœ๋ณ€์ˆ˜: `?id=` | **์‘๋‹ต ์˜ˆ์‹œ** (`GET /api/acp/agents`): ```json { "agents": [ { "id": "claude", "name": "Claude Code CLI", "binary": "claude", "version": "1.0.45", "installed": true, "protocol": "stdio", "providerAlias": "claude", "isCustom": false }, { "id": "my-custom-cli", "name": "My Custom CLI", "installed": false, "protocol": "stdio", "providerAlias": "my-provider", "isCustom": true } ], "cacheTtlMs": 60000, "cacheAge": 1234 } ``` **์ธ์ฆ:** ๊ด€๋ฆฌ ์„ธ์…˜(๋Œ€์‹œ๋ณด๋“œ `auth_token` ์ฟ ํ‚ค) ๋˜๋Š” ๊ด€๋ฆฌ ๋ฒ”์œ„ API ํ‚ค๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ [ACP ํ”„๋ ˆ์ž„์›Œํฌ](../frameworks/ACP.md)๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”. --- ## ๋ถ„์„ ๋ฐ ๊ด€์ธก ๊ฐ€๋Šฅ์„ฑ ๋ผ์šฐํŒ…, ์••์ถ• ๋ฐ ์ œ๊ณต์ž ๋‹ค์–‘์„ฑ์„ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๊ธฐ ์œ„ํ•œ ์‹ค์‹œ๊ฐ„ ๋ถ„์„ ์—”๋“œํฌ์ธํŠธ์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์—”๋“œํฌ์ธํŠธ๋Š” `/dashboard/analytics/*` ํŽ˜์ด์ง€๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ### ์ž๋™ ๋ผ์šฐํŒ… ๋ถ„์„ | ๋ฉ”์„œ๋“œ | ๊ฒฝ๋กœ | ์„ค๋ช… | | ------ | ------------------------------------ | -------------------------------------------------------------------- | | GET | `/api/analytics/auto-routing` | ์ž๋™ ๋ผ์šฐํŒ… ํ†ต๊ณ„ ์ง‘๊ณ„: ์ด ํ˜ธ์ถœ ์ˆ˜, ์ „๋žต ๋ถ„ํฌ, ํ‹ฐ์–ด ๋ถ„ํฌ, ์ƒ์œ„ ์ œ๊ณต์ž | | GET | `/api/analytics/auto-routing?days=7` | ๊ธฐ๊ฐ„๋ณ„ ํ†ต๊ณ„(๊ธฐ๋ณธ๊ฐ’ 24์‹œ๊ฐ„) | **์‘๋‹ต ์˜ˆ์‹œ**: ```json { "window": "24h", "totalCalls": 1234, "strategyBreakdown": { "rules": 800, "cost": 200, "latency": 150, "sla-aware": 50, "lkgp": 34 }, "tierBreakdown": { "ultra": 100, "pro": 500, "standard": 400, "free": 234 }, "topProviders": [ { "provider": "openai", "calls": 500, "avgLatencyMs": 850 }, { "provider": "anthropic", "calls": 300, "avgLatencyMs": 1200 } ] } ``` ### ์••์ถ• ๋ถ„์„ | ๋ฉ”์„œ๋“œ | ๊ฒฝ๋กœ | ์„ค๋ช… | | ------ | ---------------------------- | ----------------------------------------------------------------- | | GET | `/api/analytics/compression` | ์••์ถ• ํ†ต๊ณ„ ์ง‘๊ณ„: ์ ˆ๊ฐ๋œ ํ† ํฐ ์ˆ˜, ์ ˆ๊ฐ๋ฅ (%), ๋ชจ๋“œ ๋ถ„ํฌ, ์—”์ง„ ์‚ฌ์šฉ๋Ÿ‰ | **์‘๋‹ต ์˜ˆ์‹œ**: ```json { "window": "24h", "totalOriginalTokens": 5000000, "totalCompressedTokens": 3500000, "totalSavings": 1500000, "savingsPct": 30.0, "modeBreakdown": { "lite": 400, "standard": 600, "aggressive": 100, "ultra": 50, "rtk": 84 }, "engineBreakdown": { "caveman": 800, "rtk": 434 } } ``` ### ์ œ๊ณต์ž ๋‹ค์–‘์„ฑ ์ถ”์  | ๋ฉ”์„œ๋“œ | ๊ฒฝ๋กœ | ์„ค๋ช… | | ------ | -------------------------- | ---------------------------------------------------------------------------- | | GET | `/api/analytics/diversity` | ์„€๋„Œ ์—”ํŠธ๋กœํ”ผ ๊ธฐ๋ฐ˜ ๋‹ค์–‘์„ฑ ์ถ”์ : ์ œ๊ณต์ž ๋ถ„์‚ฐ๋„๋ฅผ ์ธก์ •ํ•˜์—ฌ ๋‹จ์ผ ์žฅ์•  ์ง€์  ๋ฐฉ์ง€ | **์‘๋‹ต ์˜ˆ์‹œ**: ```json { "window": "24h", "shannonEntropy": 2.45, "maxEntropy": 3.17, "diversityRatio": 0.77, "providerUsage": { "openai": 0.4, "anthropic": 0.25, "google": 0.2, "kiro": 0.15 }, "warnings": ["OpenAI accounts for 40% of traffic โ€” consider diversifying"] } ``` **์ธ์ฆ:** ๊ด€๋ฆฌ ์„ธ์…˜ ๋˜๋Š” ๊ด€๋ฆฌ ๋ฒ”์œ„ API ํ‚ค๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. --- ## ๊ด€๋ฆฌ์ž ์ž‘์—… ์šด์˜ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ ๊ด€๋ฆฌ์ž ์ „์šฉ ์—”๋“œํฌ์ธํŠธ์ž…๋‹ˆ๋‹ค. | ๋ฉ”์„œ๋“œ | ๊ฒฝ๋กœ | ์„ค๋ช… | | ------ | ------------------------ | ----------------------------------------------------------------------------------------- | | GET | `/api/admin/concurrency` | ํ˜„์žฌ ๋™์‹œ ์‹คํ–‰ ์ œํ•œ ์กฐํšŒ(์ „์—ญ + ์ œ๊ณต์ž๋ณ„) | | POST | `/api/admin/concurrency` | ๋™์‹œ ์‹คํ–‰ ์ œํ•œ ์—…๋ฐ์ดํŠธ โ€” ๋ณธ๋ฌธ: `{global?: number, perProvider?: Record}` | **์ธ์ฆ:** ๊ด€๋ฆฌ์ž ๋ฒ”์œ„๊ฐ€ ์žˆ๋Š” ๊ด€๋ฆฌ ์„ธ์…˜์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. --- ## CLI ๋„๊ตฌ ๊ด€๋ฆฌ OmniRoute์™€ ํ†ตํ•ฉ๋˜๋Š” CLI ๋„๊ตฌ(antigravity, commandCode, devin-cli ๋“ฑ)๋ฅผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์ „์ฒด ๋ชฉ๋ก์€ [์ œ๊ณต์ž ์ฐธ์กฐ](./PROVIDER_REFERENCE.md)๋ฅผ ํ™•์ธํ•˜์„ธ์š”. | ๋ฉ”์„œ๋“œ | ๊ฒฝ๋กœ | ์„ค๋ช… | | ------ | --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | | GET | `/api/cli-tools/all-statuses` | ๋ชจ๋“  CLI ๋„๊ตฌ์˜ ์ƒํƒœ(์„ค์น˜ ์—ฌ๋ถ€, ๋ฒ„์ „, ๋งˆ์ง€๋ง‰ ํ™•์ธ ์‹œ๊ฐ) | | GET | `/api/cli-tools/status` | ๋‹จ์ผ CLI ๋„๊ตฌ์˜ ์ƒ์„ธ ์ƒํƒœ(`?tool=` ์ฟผ๋ฆฌ) | | POST | `/api/cli-tools/apply` | ๋„๊ตฌ์— ๋Œ€ํ•ด ์ƒ์„ฑ๋œ ๊ตฌ์„ฑ์„ ๊ธฐ๋ก(`dryRun`์œผ๋กœ ๋ฏธ๋ฆฌ๋ณด๊ธฐ, ์ปจํ…Œ์ด๋„ˆ ํ™˜๊ฒฝ์—์„œ๋Š” `422` + `containerEphemeralTarget` ๋ฐ˜ํ™˜, `migration`์€ ๋ ˆ๊ฑฐ์‹œ Codex YAML์„ ๋ช…์‹œ) | | GET | `/api/cli-tools/backups` | CLI ๋„๊ตฌ ๊ตฌ์„ฑ ๋ฐฑ์—… ๋ชฉ๋ก ์กฐํšŒ | | POST | `/api/cli-tools/backups` | ๋ชจ๋“  CLI ๋„๊ตฌ ๊ตฌ์„ฑ์˜ ๋ฐฑ์—… ์ƒ์„ฑ | | POST | `/api/cli-tools/backups` | ๋ณต์›: ๋™์ผํ•œ ์—”๋“œํฌ์ธํŠธ์˜ ๋ณธ๋ฌธ์— `{tool, backupId}`๋ฅผ ํฌํ•จํ•˜๋ฉด ํ•ด๋‹น ๋ฐฑ์—…์„ ๋ณต์› | | GET | `/api/cli-tools/antigravity-mitm` | Antigravity MITM ํ”„๋ก์‹œ ์ƒํƒœ("antigravity-mitm" CLI ๋„๊ตฌ) | | POST | `/api/cli-tools/antigravity-mitm/alias` | antigravity-mitm ๋ณ„์นญ ๊ตฌ์„ฑ | **์ธ์ฆ:** ๊ด€๋ฆฌ ์„ธ์…˜์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. --- ## ์—์ด์ „ํŠธ ์Šคํ‚ฌ AI ์—์ด์ „ํŠธ ์Šคํ‚ฌ(์—์ด์ „ํŠธ์šฉ์ด๋ผ๋Š” ์ ์„ ์ œ์™ธํ•˜๋ฉด OpenAI์˜ ์‚ฌ์šฉ์ž ์ง€์ • GPT์™€ ์œ ์‚ฌ)์„ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. | ๋ฉ”์„œ๋“œ | ๊ฒฝ๋กœ | ์„ค๋ช… | | ------ | ---------------------------- | ------------------------------------------------------------------------------------------ | | GET | `/api/agent-skills` | ๋ชจ๋“  ์—์ด์ „ํŠธ ์Šคํ‚ฌ ๋ชฉ๋ก ์กฐํšŒ(๊ธฐ๋ณธ ์ œ๊ณต + ์‚ฌ์šฉ์ž ์ง€์ •) | | GET | `/api/agent-skills/[id]` | ํŠน์ • ์—์ด์ „ํŠธ ์Šคํ‚ฌ ์กฐํšŒ | | POST | `/api/agent-skills` | ์‚ฌ์šฉ์ž ์ง€์ • ์—์ด์ „ํŠธ ์Šคํ‚ฌ ์ƒ์„ฑ โ€” ๋ณธ๋ฌธ: `{name, description, prompt, model?, temperature?}` | | PUT | `/api/agent-skills/[id]` | ์‚ฌ์šฉ์ž ์ง€์ • ์—์ด์ „ํŠธ ์Šคํ‚ฌ ์—…๋ฐ์ดํŠธ | | DELETE | `/api/agent-skills/[id]` | ์‚ฌ์šฉ์ž ์ง€์ • ์—์ด์ „ํŠธ ์Šคํ‚ฌ ์‚ญ์ œ | | GET | `/api/agent-skills/[id]/raw` | ์›์‹œ ํ”„๋กฌํ”„ํŠธ + ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์กฐํšŒ(์‹คํ–‰ํ•˜์ง€ ์•Š์Œ) | | POST | `/api/agent-skills/generate` | ์ž์—ฐ์–ด ์„ค๋ช…์„ ๊ธฐ๋ฐ˜์œผ๋กœ AI๋ฅผ ์‚ฌ์šฉํ•ด ์ƒˆ ์Šคํ‚ฌ ์ƒ์„ฑ | **์ธ์ฆ:** ๊ด€๋ฆฌ ์„ธ์…˜ ๋˜๋Š” ๊ด€๋ฆฌ ๋ฒ”์œ„๊ฐ€ ์žˆ๋Š” API ํ‚ค๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. --- ## ์บ์‹œ ๊ด€๋ฆฌ ์‹œ๋งจํ‹ฑ ์บ์‹œ์™€ ์ถ”๋ก  ์บ์‹œ๋ฅผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. | ๋ฉ”์„œ๋“œ | ๊ฒฝ๋กœ | ์„ค๋ช… | | ------ | ---------------------- | --------------------------------------------------------------------------------------------------- | | GET | `/api/cache` | ์บ์‹œ ๊ฐœ์š”: ์ „์ฒด ํ•ญ๋ชฉ ์ˆ˜, ์ ์ค‘๋ฅ , ๋””์Šคํฌ ์‚ฌ์šฉ๋Ÿ‰ | | GET | `/api/cache/entries` | ์บ์‹œ๋œ ํ•ญ๋ชฉ ๋ชฉ๋ก ์กฐํšŒ(ํŽ˜์ด์ง€๋„ค์ด์…˜ ์ง€์›) | | DELETE | `/api/cache/entries` | ์บ์‹œ ํ•ญ๋ชฉ ์‚ญ์ œ(์ฟผ๋ฆฌ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ํ•„ํ„ฐ๋ง) | | GET | `/api/cache/stats` | ์ƒ์„ธ ์บ์‹œ ํ†ต๊ณ„(์ œ๊ณต์ž๋ณ„, ๋ชจ๋ธ๋ณ„) | | GET | `/api/cache/reasoning` | ์ถ”๋ก  ์บ์‹œ ์ƒํƒœ(์ถ”๋ก  ์žฌ์ƒ์šฉ) | | DELETE | `/api/cache/reasoning` | ์ถ”๋ก  ์บ์‹œ ์‚ญ์ œ โ€” ์ฟผ๋ฆฌ ๋งค๊ฐœ๋ณ€์ˆ˜: `?toolCallId=`(๋‹จ์ผ), `?provider=

`, ๋˜๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜ ์—†์Œ(์ „์ฒด) | **์ธ์ฆ:** ๊ด€๋ฆฌ ์„ธ์…˜์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. --- ## ๋ฉ”๋ชจ๋ฆฌ ์‹œ์Šคํ…œ ์˜๊ตฌ ๋ฉ”๋ชจ๋ฆฌ(FTS5 + ๋ฒกํ„ฐ ์ž„๋ฒ ๋”ฉ)๋ฅผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. | ๋ฉ”์„œ๋“œ | ๊ฒฝ๋กœ | ์„ค๋ช… | | ------ | ------------------ | --------------------------------------------------------------- | | GET | `/api/memory` | ๋ฉ”๋ชจ๋ฆฌ ํ•ญ๋ชฉ ๋ชฉ๋ก ์กฐํšŒ(๋ฒ”์œ„, ์œ ํ˜•, ๊ฒ€์ƒ‰ ์ฟผ๋ฆฌ๋กœ ํ•„ํ„ฐ๋ง) | | POST | `/api/memory` | ์ƒˆ ๋ฉ”๋ชจ๋ฆฌ ํ•ญ๋ชฉ ์ƒ์„ฑ โ€” ๋ณธ๋ฌธ: `{scope, type, content, metadata?}` | | GET | `/api/memory/[id]` | ํŠน์ • ๋ฉ”๋ชจ๋ฆฌ ํ•ญ๋ชฉ ์กฐํšŒ | | PUT | `/api/memory/[id]` | ๋ฉ”๋ชจ๋ฆฌ ํ•ญ๋ชฉ ์—…๋ฐ์ดํŠธ | | DELETE | `/api/memory/[id]` | ๋ฉ”๋ชจ๋ฆฌ ํ•ญ๋ชฉ ์‚ญ์ œ | | GET | `/api/memory?q=` | ๋ฉ”๋ชจ๋ฆฌ ๊ฒ€์ƒ‰(FTS5 + ๋ฒกํ„ฐ) โ€” ๋™์ผํ•œ ์‘๋‹ต์— ํ†ต๊ณ„ ํฌํ•จ | **์ธ์ฆ:** ๊ด€๋ฆฌ ์„ธ์…˜ ๋˜๋Š” ๊ด€๋ฆฌ ๋ฒ”์œ„ API ํ‚ค๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. --- ## ์›นํ›… ์ด๋ฒคํŠธ์— ๋Œ€ํ•œ ์›นํ›… ๊ตฌ๋…์„ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. | ๋ฉ”์„œ๋“œ | ๊ฒฝ๋กœ | ์„ค๋ช… | | ------ | ------------------------------- | ---------------------------------------------------------- | | GET | `/api/webhooks` | ๋ชจ๋“  ์›นํ›… ๊ตฌ๋… ๋ชฉ๋ก ์กฐํšŒ | | POST | `/api/webhooks` | ์›นํ›… ๊ตฌ๋… ์ƒ์„ฑ โ€” ๋ณธ๋ฌธ: `{url, events[], secret?, active?}` | | GET | `/api/webhooks/[id]` | ํŠน์ • ์›นํ›… ๊ตฌ๋… ์กฐํšŒ | | PUT | `/api/webhooks/[id]` | ์›นํ›… ๊ตฌ๋… ์—…๋ฐ์ดํŠธ | | DELETE | `/api/webhooks/[id]` | ์›นํ›… ๊ตฌ๋… ์‚ญ์ œ | | GET | `/api/webhooks/[id]/deliveries` | ์›นํ›… ์ „์†ก ๊ธฐ๋ก ๋ชฉ๋ก ์กฐํšŒ(์„ฑ๊ณต/์‹คํŒจ ๋กœ๊ทธ) | | POST | `/api/webhooks/[id]/test` | ์›นํ›…์— ํ…Œ์ŠคํŠธ ์ด๋ฒคํŠธ ์ „์†ก | **์ธ์ฆ:** ๊ด€๋ฆฌ ์„ธ์…˜์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ „์ฒด ์ด๋ฒคํŠธ ์œ ํ˜•์€ [์›นํ›… ํ”„๋ ˆ์ž„์›Œํฌ](../frameworks/WEBHOOKS.md)๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”. --- ## Skills ํ”„๋ ˆ์ž„์›Œํฌ Skills(์—์ด์ „ํŠธ ํ™•์žฅ ํ”„๋ ˆ์ž„์›Œํฌ)๋ฅผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. | ๋ฉ”์„œ๋“œ | ๊ฒฝ๋กœ | ์„ค๋ช… | | ------ | ------------------------ | ---------------------------------------------------------------------------------------- | | GET | `/api/skills` | ์„ค์น˜๋œ ๋ชจ๋“  skill(๊ธฐ๋ณธ ์ œ๊ณต + ์‚ฌ์šฉ์ž ์ง€์ •) ๋ชฉ๋ก ์กฐํšŒ | | POST | `/api/skills/install` | ๋กœ์ปฌ ๊ฒฝ๋กœ ๋˜๋Š” URL์—์„œ skill ์„ค์น˜ | | DELETE | `/api/skills/[id]` | skill ์ œ๊ฑฐ | | PUT | `/api/skills/[id]` | skill ํ™œ์„ฑํ™” ๋˜๋Š” ๋น„ํ™œ์„ฑํ™” โ€” ๋ณธ๋ฌธ: `{enabled?: boolean, mode?: "on" \| "off" \| "auto"}` | | POST | `/api/skills/executions` | skill ์‹คํ–‰ โ€” ๋ณธ๋ฌธ: `{skillName, apiKeyId, input?, sessionId?}` | | GET | `/api/skills/executions` | ๋ชจ๋“  skill์˜ ์‹คํ–‰ ๊ธฐ๋ก ์กฐํšŒ (`?apiKeyId=`๋กœ ํ•„ํ„ฐ๋ง) | **์ธ์ฆ:** ๊ด€๋ฆฌ ์„ธ์…˜ ๋˜๋Š” ๊ด€๋ฆฌ ๋ฒ”์œ„ API ํ‚ค๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ [Skills ํ”„๋ ˆ์ž„์›Œํฌ](../frameworks/SKILLS.md)๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”. --- ## ํ”Œ๋Ÿฌ๊ทธ์ธ OmniRoute ํ”Œ๋Ÿฌ๊ทธ์ธ(์„œ๋“œ ํŒŒํ‹ฐ ํ™•์žฅ)์„ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. | ๋ฉ”์„œ๋“œ | ๊ฒฝ๋กœ | ์„ค๋ช… | | ------ | ---------------------------------- | ------------------------------ | | GET | `/api/plugins` | ์„ค์น˜๋œ ํ”Œ๋Ÿฌ๊ทธ์ธ ๋ชฉ๋ก ์กฐํšŒ | | POST | `/api/plugins/marketplace/install` | ๋งˆ์ผ“ํ”Œ๋ ˆ์ด์Šค์—์„œ ํ”Œ๋Ÿฌ๊ทธ์ธ ์„ค์น˜ | | DELETE | `/api/plugins/[name]` | ํ”Œ๋Ÿฌ๊ทธ์ธ ์ œ๊ฑฐ | | POST | `/api/plugins/[name]/activate` | ํ”Œ๋Ÿฌ๊ทธ์ธ ํ™œ์„ฑํ™” | | POST | `/api/plugins/[name]/deactivate` | ํ”Œ๋Ÿฌ๊ทธ์ธ ๋น„ํ™œ์„ฑํ™” | | GET | `/api/plugins/[name]/config` | ํ”Œ๋Ÿฌ๊ทธ์ธ ๊ตฌ์„ฑ ์กฐํšŒ | | PUT | `/api/plugins/[name]/config` | ํ”Œ๋Ÿฌ๊ทธ์ธ ๊ตฌ์„ฑ ์—…๋ฐ์ดํŠธ | **์ธ์ฆ:** ๊ด€๋ฆฌ ์„ธ์…˜์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ [ํ”Œ๋Ÿฌ๊ทธ์ธ ํ”„๋ ˆ์ž„์›Œํฌ](../frameworks/PLUGIN_SDK.md)๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”. --- ## ์„€๋„ ๋ผ์šฐํŒ… ์ œ๊ณต์ž์— ๋Œ€ํ•œ ์„€๋„/A-B ๋น„๊ต๋Š” **๋…๋ฆฝ์ ์ธ REST ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค**. ์ด๋Š” ์ฝค๋ณด ๋ผ์šฐํŒ…์„ ํ†ตํ•ด ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค([Auto-Combo](../routing/AUTO-COMBO.md) ์ฐธ์กฐ). ์ฝค๋ณด๋ณ„ ๋น„๊ต ์ง€ํ‘œ๋Š” `GET /api/combos/metrics`๋ฅผ ํ†ตํ•ด ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค. --- ## ๊ฐ€๋“œ๋ ˆ์ผ ๋Ÿฐํƒ€์ž„ ๊ฐ€๋“œ๋ ˆ์ผ(PII ํƒ์ง€, ํ”„๋กฌํ”„ํŠธ ์ธ์ ์…˜ ํƒ์ง€, ๋น„์ „ ๋ธŒ๋ฆฌ์ง•)์„ ์ ๊ฒ€ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ€๋“œ๋ ˆ์ผ์€ ๋ชจ๋“  ์š”์ฒญ์—์„œ ์‹คํ–‰๋˜๋ฉฐ, ํ˜ธ์ถœ๋ณ„ ์ œ์™ธ๋Š” `x-omniroute-disabled-guardrails` ์š”์ฒญ ํ—ค๋”๋ฅผ ํ†ตํ•ด ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ์ง€์†์ ์œผ๋กœ ์ €์žฅ๋˜๋Š” ํ™œ์„ฑํ™”/๋น„ํ™œ์„ฑํ™” ์ธํ„ฐํŽ˜์ด์Šค๋Š” ์—†์Šต๋‹ˆ๋‹ค. | ๋ฉ”์„œ๋“œ | ๊ฒฝ๋กœ | ์„ค๋ช… | | ------ | ---------------------- | ---------------------------------------------------------------------------------------- | | GET | `/api/guardrails` | ๋“ฑ๋ก๋œ ๊ฐ€๋“œ๋ ˆ์ผ ๋ฐ ํ•ด๋‹น ์ƒํƒœ(์ด๋ฆ„/ํ™œ์„ฑํ™” ์—ฌ๋ถ€/์šฐ์„ ์ˆœ์œ„) ๋ชฉ๋ก ์กฐํšŒ | | POST | `/api/guardrails/test` | ์ƒ˜ํ”Œ ์ž…๋ ฅ์— ๋Œ€ํ•ด ํ˜ธ์ถœ ์ „ ํŒŒ์ดํ”„๋ผ์ธ์„ ํ…Œ์ŠคํŠธ ์‹คํ–‰ โ€” ๋ณธ๋ฌธ: `{input, disabledGuardrails?}` | **์ธ์ฆ:** ๊ด€๋ฆฌ ์„ธ์…˜์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ [๋ณด์•ˆ > ๊ฐ€๋“œ๋ ˆ์ผ](../security/GUARDRAILS.md)์„ ์ฐธ์กฐํ•˜์„ธ์š”. --- --- ## ์ธ์ฆ ๋„ค ๊ฐ€์ง€ ์ž๊ฒฉ ์ฆ๋ช… ๊ณ„์—ด(๋Œ€์‹œ๋ณด๋“œ ์„ธ์…˜, ๋กœ์ปฌ CLI ํ† ํฐ, `oma_live_โ€ฆ` Access Token, ๊ด€๋ฆฌ ๋ฒ”์œ„ API ํ‚ค)๊ณผ ์ด๋“ค์ด ์ถ”๋ก  ํ‚ค์™€ ์–ด๋–ป๊ฒŒ ๋‹ค๋ฅธ์ง€๋Š” [๊ด€๋ฆฌ ์ธ์ฆ](../guides/MANAGEMENT-AUTH.md)์„ ์ฐธ์กฐํ•˜์„ธ์š”. - ๋Œ€์‹œ๋ณด๋“œ ๊ฒฝ๋กœ(`/dashboard/*`)๋Š” `auth_token` ์ฟ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค - ๋กœ๊ทธ์ธ์€ ์ €์žฅ๋œ ๋น„๋ฐ€๋ฒˆํ˜ธ ํ•ด์‹œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ, ์—†์œผ๋ฉด `INITIAL_PASSWORD`๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค - `requireLogin`์€ `/api/settings/require-login`์„ ํ†ตํ•ด ์ „ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค - `/v1/*` ๊ฒฝ๋กœ๋Š” `REQUIRE_API_KEY=true`์ผ ๋•Œ ์„ ํƒ์ ์œผ๋กœ Bearer API ํ‚ค๋ฅผ ์š”๊ตฌํ•ฉ๋‹ˆ๋‹ค - ์ด ๋ฌธ์„œ์—์„œ "๊ด€๋ฆฌ ํ† ํฐ" / "๊ด€๋ฆฌ ๋ฒ”์œ„ API ํ‚ค"๋Š” ํ•ด๋‹น ๊ฐ€์ด๋“œ์— ์„ค๋ช…๋œ ๊ณ„์—ด ์ค‘ ํ•˜๋‚˜๋ฅผ ์˜๋ฏธํ•˜๋ฉฐ, ๋ณ„๋„๋กœ ์ •์˜๋˜์ง€ ์•Š์€ ์ถ”๊ฐ€ ๋น„๋ฐ€ ์œ ํ˜•์„ ์˜๋ฏธํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค > **ํ˜ธํ™˜์„ฑ์„ ๊นจ๋œจ๋ฆฌ๋Š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ(v3.8.0)** โ€” ์ด์ œ `/api/v1/agents/tasks/*` ๋ฐ ์ฟจ๋‹ค์šด ๊ด€๋ฆฌ ์—”๋“œํฌ์ธํŠธ์—๋Š” **๊ด€๋ฆฌ ์ธ์ฆ**(๋Œ€์‹œ๋ณด๋“œ `auth_token` ์ฟ ํ‚ค ๋˜๋Š” ๊ด€๋ฆฌ ๋ฒ”์œ„ API ํ‚ค)์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ด์ „์— ์ธ์ฆ ์—†์ด ์ด๋Ÿฌํ•œ ๊ฒฝ๋กœ๋ฅผ ํ˜ธ์ถœํ•˜๋˜ ํด๋ผ์ด์–ธํŠธ๋Š” `401 Unauthorized`๋ฅผ ๋ฐ›๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ปค๋ฐ‹ `588a0333`(`fix(auth): ์—์ด์ „ํŠธ ๋ฐ ์ฟจ๋‹ค์šด API์— ๊ด€๋ฆฌ ์ธ์ฆ ์š”๊ตฌ`)์„ ์ฐธ์กฐํ•˜์„ธ์š”.