Files
OmniRoute/docs/i18n/th/docs/reference/API_REFERENCE.md
Diego Rodrigues de Sa e Souza b637350680 fix(docs): re-sync the 65 documentation mirror sets; section-level docs pipeline; drift gate blocking (#13940)
1,104 mirrors rewritten over five passes of run-translation on the 22-source core set: the 14 sources edited since their translation, the 322 mirrors that were still English copies, and the frontmatter the old extractor leaked into the newer locales' bodies. The pipeline now caches per-`## `-section hashes and retranslates only changed sections, never reuses a section that is still English, rebuilds English-copy / leaked mirrors even when the source is unchanged, merges the state on save (parallel runs), and the drift gate (scoped to the core set) is blocking. Final audit: 0 stale, 0 English copies, 0 leaked frontmatter across 1,430 core mirrors.

⚠️ base-red inherited: #12732
2026-09-17 02:55:31 -03:00

186 KiB
Raw Permalink Blame History

API Reference (ไทย)

🌐 Languages: 🇺🇸 English · 🇪🇹 am · 🇸🇦 ar · 🇦🇿 az · 🇧🇬 bg · 🇧🇩 bn · 🇨🇿 cs · 🇩🇰 da · 🇩🇪 de · 🇬🇷 el · 🇪🇸 es · 🇪🇪 et · 🇮🇷 fa · 🇫🇮 fi · 🇫🇷 fr · 🇮🇪 ga · 🇮🇳 gu · 🇳🇬 ha · 🇮🇱 he · 🇮🇳 hi · 🇭🇷 hr · 🇭🇺 hu · 🇦🇲 hy · 🇮🇩 id · 🇳🇬 ig · 🇮🇹 it · 🇯🇵 ja · 🇬🇪 ka · 🇰🇭 km · 🇮🇳 kn · 🇰🇷 ko · 🇱🇹 lt · 🇱🇻 lv · 🇮🇳 ml · 🇮🇳 mr · 🇲🇾 ms · 🇲🇹 mt · 🇲🇲 my · 🇳🇵 ne · 🇳🇱 nl · 🇳🇴 no · 🇮🇳 or · 🇮🇳 pa · 🇵🇭 phi · 🇵🇱 pl · 🇵🇹 pt · 🇧🇷 pt-BR · 🇷🇴 ro · 🇷🇺 ru · 🇱🇰 si · 🇸🇰 sk · 🇸🇮 sl · 🇷🇸 sr · 🇸🇪 sv · 🇰🇪 sw · 🇮🇳 ta · 🇮🇳 te · 🇹🇷 tr · 🇺🇦 uk-UA · 🇵🇰 ur · 🇺🇿 uz · 🇻🇳 vi · 🇳🇬 yo · 🇨🇳 zh-CN · 🇹🇼 zh-TW


🌐 ภาษา: 🇺🇸 English | 🇪🇹 አማርኛ | 🇸🇦 العربية | 🇦🇿 Azərbaycan dili | 🇧🇬 Български | 🇧🇩 বাংলা | 🇨🇿 Čeština | 🇩🇰 Dansk | 🇩🇪 Deutsch | 🇬🇷 Ελληνικά | 🇪🇸 Español | 🇪🇪 Eesti | 🇮🇷 فارسی | 🇫🇮 Suomi | 🇫🇷 Français | 🇮🇪 Gaeilge | 🇮🇳 ગુજરાતી | 🇳🇬 Hausa | 🇮🇱 עברית | 🇮🇳 हिन्दी | 🇭🇷 Hrvatski | 🇭🇺 Magyar | 🇦🇲 Հայերեն | 🇮🇩 Bahasa Indonesia | 🇳🇬 Igbo | 🇮🇹 Italiano | 🇯🇵 日本語 | 🇬🇪 ქართული | 🇰🇭 ខ្មែរ | 🇮🇳 ಕನ್ನಡ | 🇰🇷 한국어 | 🇱🇹 Lietuvių | 🇱🇻 Latviešu | 🇮🇳 മലയാളം | 🇮🇳 मराठी | 🇲🇾 Bahasa Melayu | 🇲🇹 Malti | 🇲🇲 မြန်မာ | 🇳🇵 नेपाली | 🇳🇱 Nederlands | 🇳🇴 Norsk | 🇮🇳 ଓଡ଼ିଆ | 🇮🇳 ਪੰਜਾਬੀ | 🇵🇭 Filipino | 🇵🇱 Polski | 🇵🇹 Português (Portugal) | 🇧🇷 Português (Brasil) | 🇷🇴 Română | 🇷🇺 Русский | 🇱🇰 සිංහල | 🇸🇰 Slovenčina | 🇸🇮 Slovenščina | 🇷🇸 Српски | 🇸🇪 Svenska | 🇰🇪 Kiswahili | 🇮🇳 தமிழ் | 🇮🇳 తెలుగు | 🇹🇭 ไทย | 🇹🇷 Türkçe | 🇺🇦 Українська | 🇵🇰 اردو | 🇺🇿 Oʻzbekcha | 🇻🇳 Tiếng Việt | 🇳🇬 Yorùbá | 🇨🇳 中文 (简体) | 🇹🇼 中文 (繁體)

เอกสารอ้างอิงหลักสำหรับ OmniRoute API ซึ่งครอบคลุมส่วนติดต่อสาธารณะ /v1 และเอนด์พอยต์สำหรับการจัดการที่ใช้งานบ่อยที่สุด โดยมี docs/openapi.yaml ที่เครื่องอ่านได้และโครงสร้างเส้นทางภายใต้ src/app/api/ เป็นแหล่งข้อมูลที่ครอบคลุมทั้งหมด


สารบัญ


การเติมเต็มแชต

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 การตอบกลับ ID เซสชันที่มีผลซึ่ง OmniRoute ใช้
X-OmniRoute-Request-Id การตอบกลับ ID สำหรับเชื่อมโยงคำขอ (เมื่อทราบ)
X-OmniRoute-Version การตอบกลับ เวอร์ชันบิลด์ของ OmniRoute (มีอยู่เสมอ)
X-OmniRoute-Cost-Saved การตอบกลับ จำนวนเงิน USD ที่แคชช่วยประหยัดได้เมื่อเป็น HIT (เฉพาะเมื่อพบข้อมูลในแคช)
X-OmniRoute-Decision การตอบกลับ รายละเอียดการกำหนดเส้นทาง: strategy=<name>; provider=<alias>; latency_ms=<n> (<name> คือกลยุทธ์คอมโบ หรือ 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 (fail-open)

ความหมายของต้นทุนเมื่อแคชฮิต: เมื่อ semantic cache HIT (X-OmniRoute-Cache-Hit: true) จะไม่มีการเรียกไปยัง upstream ดังนั้น X-OmniRoute-Response-Cost จึงเป็น 0.0000000000 (ต้นทุนส่วนเพิ่มในการให้บริการผลลัพธ์ที่แคชฮิต) ต้นทุนเดิม/ต้นทุนที่ควรจะเกิดขึ้นจะถูกรายงานแยกต่างหากใน X-OmniRoute-Cost-Saved ผู้ใช้งานข้อมูลสำหรับการเรียกเก็บเงินควรรวมค่า X-OmniRoute-Response-Cost (แคชฮิตไม่มีค่าใช้จ่าย) ส่วนการวิเคราะห์แคชสามารถรวมค่า X-OmniRoute-Cost-Saved ได้

การเช่าเซสชันที่มีการจัดการแบบเอกสิทธิ์

การเช่าเซสชันที่มีการจัดการแบบเอกสิทธิ์เป็นสัญญาการกำหนดเส้นทางที่ต้องเลือกใช้และไม่ขึ้นกับไคลเอนต์ โดยเจ้าของที่ใช้งานอยู่หนึ่งรายจะครอบครองการเชื่อมต่อ OmniRoute ที่มีสิทธิ์หนึ่งรายการ สัญญานี้ไม่ได้เป็นการเช่าโมเดล ไม่ต้องใช้ OAuth ไม่ระบุไคลเอนต์รายใดรายหนึ่ง และไม่บังคับให้ใช้ผู้ให้บริการรายใดรายหนึ่ง

คีย์ API ที่ใช้ยืนยันตัวตนต้องมีขอบเขต lease:exclusive และรายการ allowedConnections ที่ระบุไว้อย่างชัดเจนและไม่ว่างเปล่า ขอบเขตการเปลี่ยนแปลงฐานข้อมูลจะบังคับใช้ทั้งสองฟิลด์ร่วมกัน ทั้งในระหว่างการสร้างคีย์และการอัปเดตบางส่วน

POST /api/v1/session-leases
Authorization: Bearer <managed-api-key>
Content-Type: application/json
X-OmniRoute-Lease-Owner: vlo_<43-base64url-characters>

{"action":"acquire","model":"glm/glm-4.6"}

การตอบกลับที่สำเร็จสำหรับการขอรับ การต่ออายุ และการปล่อยจะแสดงการประทับเวลา state และค่า generation ที่เป็นจำนวนบวกอย่างถูกต้อง แต่จะไม่เปิดเผยการเชื่อมต่อหรือข้อมูลประจำตัวที่เลือกไว้ การต่ออายุและการปล่อยจะส่งค่า generation ในเนื้อหา JSON:

{ "action": "renew", "generation": 1 }
{ "action": "release", "generation": 1, "reason": "OWNER_EXIT" }

เจ้าของสัญญาเช่าที่ใช้งานอยู่สามารถร้องขอข้อมูลเมตาสำหรับการแสดงผลที่ปลอดภัยต่อความเป็นส่วนตัวของการผูกปัจจุบันได้อย่างชัดเจน:

{ "action": "status", "generation": 1 }
{
  "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 จะไม่ใช้อีเมลหรือข้อมูลระบุตัวตนของบัญชีที่สร้างขึ้นมาแทน ค่า provider เป็นป้ายกำกับสำหรับการแสดงผลที่ไม่ละเอียดอ่อน และจะไม่เป็นตัวระบุ compatible-provider ที่สร้างขึ้น ข้อมูลประจำตัว โทเค็น คุกกี้ ID ดิบของการเชื่อมต่อหรือคีย์ API แฮชเจ้าของ ข้อมูลลับสำหรับการกั้น และข้อมูลการกำหนดเส้นทางภายในจะถูกตัดออก

การค้นหาด้วยคีย์ที่ไม่ถูกต้อง เจ้าของที่ไม่ถูกต้อง generation ที่ล้าสมัย รายการที่ไม่มีอยู่ หมดอายุ ถูกปล่อย หรือถูกทำให้ใช้ไม่ได้ จะส่งคืนข้อผิดพลาด 409 LEASE_FENCE_STALE แบบเดียวกันทั้งหมดโดยไม่มีข้อมูลเมตาของการเชื่อมต่อ ไคลเอนต์ที่ได้รับการตอบกลับให้รอความจุจะไม่มีการผูกที่ใช้งานอยู่ให้ตรวจสอบ เมื่อการกำหนดเส้นทางเปลี่ยนสัญญาเช่าที่ใช้งานอยู่ generation เดิมจะยังคงใช้ได้ และสถานะจะส่งคืนการผูกใหม่แบบอะตอมมิก โดยจะไม่ส่งคืนการผูกเก่า ไคลเอนต์ที่มีอยู่จะไม่เปลี่ยนแปลง เนื่องจากการตอบกลับสำหรับการขอรับ การต่ออายุ การปล่อย และการรอ ยังคงใช้รูปแบบเดิม

สัญญาฝั่งเซิร์ฟเวอร์นี้ไม่เปลี่ยนแปลง /status ของ OpenAI Codex มาตรฐาน ปัจจุบัน Codex มาตรฐานจะรายงานผู้ให้บริการโมเดลและสถานะการยืนยันตัวตน/บัญชีในตัว แต่จะไม่แสดงข้อมูลเมตาของบัญชีผู้ให้บริการแบบกำหนดเองโดยพลการ การผสานรวมไคลเอนต์ในอนาคตต้องเรียกใช้การดำเนินการนี้และตัดสินใจว่าจะแสดง connection.displayName อย่างไร

จากนั้นคำขออนุมานแบบมีการจัดการทุกคำขอจะส่งส่วนหัวควบคุมทั้งสองรายการ:

X-OmniRoute-Lease-Owner: vlo_<43-base64url-characters>
X-OmniRoute-Lease-Generation: 1

เจ้าของ generation การเชื่อมต่อที่ใช้งานอยู่ และคีย์ API ที่ผ่านการยืนยันตัวตน ซึ่งทั้งหมดต้องตรงกันอย่างถูกต้อง จะถูกตรวจสอบกั้นทันทีก่อนความพยายามส่งต่อไปยังต้นทางแต่ละครั้งที่รองรับ การนำเจ้าของและ generation มาใช้ซ้ำกับคีย์อื่นจะล้มเหลว แม้ว่าคีย์นั้นจะอนุญาตการเชื่อมต่อเดียวกันก็ตาม เจ้าของแบบดิบจะไม่ถูกเก็บถาวร บันทึกในล็อก เก็บไว้ในสแนปช็อตคำขอ หรือส่งต่อไปยังต้นทาง

การแย่งใช้ทรัพยากรชั่วคราวจะส่งคืน HTTP 429 พร้อม Retry-After และ:

{
  "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:<id> เอนจินเดียวเมื่อเปิดใช้งาน เช่น engine:rtk
<combo> ชุดแบบมีชื่อ โดยจับคู่จากชื่อก่อน (ไม่แยกตัวพิมพ์เล็ก-ใหญ่) แล้วจึงจับคู่จาก id

หมายเหตุ:

  • ค่าที่ไม่รู้จักจะถูกละเว้น (คำขอจะไม่ถูกปฏิเสธ) โดยการแก้ไขค่าจะดำเนินต่อไปตามลำดับความสำคัญปกติของตัวดำเนินการ
  • หากหลายชุดใช้ชื่อเดียวกัน ให้ส่ง id ของชุดเพื่อให้ได้การจับคู่ที่แน่นอน
  • ชุดที่มีชื่อเป็น off หรือ default จะไม่สามารถเลือกด้วยชื่อได้ (คีย์เวิร์ดเหล่านี้จะถูกตีความก่อน) ให้อ้างอิงชุดดังกล่าวด้วย id
  • สวิตช์หลักของการบีบอัดเป็นข้อจำกัดเด็ดขาด เมื่อปิดใช้งานการบีบอัดในระดับส่วนกลาง ส่วนหัวนี้จะไม่สามารถเปิดใช้งานได้

แผนที่นำไปใช้จะถูกส่งกลับในส่วนหัวการตอบกลับ:

X-OmniRoute-Compression: <mode>; source=<source>

โดย <source> เป็นหนึ่งใน request-header, routing-override, active-profile, auto-trigger, default หรือ off


Embeddings

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

รหัสแค็ตตาล็อกอยู่ในรูปแบบ provider/model (ตัวอย่าง: jina-ai/jina-embeddings-v5-omni-small) รหัสโมเดล Jina แบบไม่มีชื่อผู้ให้บริการที่ปรากฏในรีจิสทรี (ตัวอย่างเช่น 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) ยังรองรับเอกสาร EmbeddingsV5Request แบบเนทีฟของ Jina และ ส่งต่อโดยคงข้อมูลไว้อย่างครบถ้วน ไปยัง https://api.jina.ai/v1/embeddings:

{
  "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 } แบบเนทีฟอาจเป็น URL HTTPS สาธารณะ, URI แบบ data: หรือ base64 ดิบ OmniRoute จะไม่แปลงออบเจ็กต์เหล่านั้นเป็นสตริงหรือดึงข้อมูลจาก URL รูปภาพแบบเนทีฟ — Jina จะดึง สื่อสาธารณะเอง ฟิลด์เพิ่มเติมของ Jina (task, normalized, truncate, embedding_type) จะถูก ส่งต่อ ส่วน SKU ของ Jina ที่รองรับเฉพาะข้อความจะยังคงปฏิเสธเอกสารที่ไม่ใช่ข้อความ

ขอบเขตด้านความปลอดภัยและการรับส่งข้อมูล:

  • URL สื่อระยะไกลต้องเป็น HTTPS สาธารณะ รายการรูปแบบมาตรฐาน {type,source:url} จะถูกดึงข้อมูล ฝั่งเซิร์ฟเวอร์ (ตรวจสอบการเปลี่ยนเส้นทางซ้ำ, กำหนดเวลาหมดอายุ, จำกัดขนาด, ใช้ DNS สาธารณะ, ตรึงการเชื่อมต่อ) และ ฝังไว้ก่อนเรียกผู้ให้บริการ รายการแบบเนทีฟของ Jina {image:"https://..."} จะถูกส่งต่อตามเดิม หลังผ่านการตรวจสอบ HTTPS สาธารณะแบบเดียวกัน โดย Jina จะเป็นผู้ดึง URL
  • สื่อ base64 แบบอินไลน์จำกัดขนาดหลังถอดรหัสไว้ที่ 8 MiB ต่อรายการ และ 16 MiB หลังถอดรหัสสำหรับคำขอทั้งหมด

การแปลงรูปแบบสำหรับผู้ให้บริการ (รายการรูปแบบมาตรฐานจะไม่ถูกส่งต่อโดยไม่มีการเปลี่ยนแปลง):

  • โมเดลหลายสื่อของ Jina: รายการระดับบนสุดแต่ละรายการจะกลายเป็นออบเจ็กต์หนึ่งรายการที่มีคีย์ตามรูปแบบสื่อ (text / image / audio / video / pdf) โดยใช้ URI แบบ data สำหรับสื่ออินไลน์ และให้เวกเตอร์หนึ่งรายการต่อ รายการระดับบนสุด
  • ตระกูล Gemini Embedding 2: อาร์เรย์ระดับบนสุดหนึ่งรายการจะกลายเป็นคำขอแบบเนทีฟ models/{model}:embedContent หนึ่งคำขอ พร้อม content.parts (text หรือ inline_data)
  • โมเดลที่ไม่รู้จัก/แบบไดนามิกซึ่งไม่มีข้อมูลเมตาของรูปแบบสื่ออย่างชัดเจนจะปฏิเสธอินพุตที่มีโครงสร้างด้วย HTTP 400
{
  "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 แทนการบังคับแปลงรายการ ฟิลด์ส่วนขยายที่ไม่ใช่อินพุต ในคำขอแบบสตริง/โทเค็นดั้งเดิมจะยังคงถูกส่งต่อโดยไม่มีการเปลี่ยนแปลง

# แสดงรายการโมเดลการฝังเวกเตอร์ทั้งหมด
GET /v1/embeddings

การสร้างรูปภาพ

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 (ภายในเครื่อง)

# แสดงโมเดลรูปภาพทั้งหมด
GET /v1/images/generations

OCR เอกสาร

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 ใช้เลือกผู้ให้บริการ OCR ผ่านคำนำหน้า provider/model โดยรหัสโมเดลที่ไม่มีคำนำหน้า (เช่น mistral-ocr-latest) จะถูกจับคู่กับผู้ให้บริการที่ลงทะเบียนไว้ และหากไม่ระบุ model ระบบจะใช้ Mistral (mistral-ocr-latest) เป็นค่าเริ่มต้น ผู้ให้บริการที่ลงทะเบียนไว้ (open-sse/config/ocrRegistry.ts):

รหัสผู้ให้บริการ รหัสโมเดล ค่า 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 แบบซิงโครนัส ผ่านปลายทางพาร์ทเนอร์ openapi/chat/completions ของ Vertex AI — ดูการยืนยันตัวตน/URL ด้านล่าง

ผู้ให้บริการทั้งสามรายตอบกลับด้วยเนื้อหารูปแบบเดียวกับ Mistral:

{
  "pages": [{ "index": 0, "markdown": "# ข้อความที่แยกออกมา..." }],
  "model": "mistral-ocr-latest",
  "usage_info": { "pages_processed": 1 }
}

ขั้นตอนการโพลของ Azure Document Intelligence

API analyze ของ Azure Document Intelligence ทำงานแบบอะซิงโครนัส: คำขอเริ่มต้นจะส่งคืนส่วนหัว Operation-Location แทนเนื้อหาการตอบกลับ และจำเป็นต้องโพลเพื่อรับผลลัพธ์ ตัวจัดการ (open-sse/handlers/ocr.ts) จะโพล URL ดังกล่าวทุกหนึ่งวินาที สูงสุด 30 ครั้ง โดยจะหยุดและรายงานความล้มเหลวทันที (ไม่ โพลต่อ) เมื่อการตอบกลับจากการโพลไม่เป็น ok หรือมีสถานะ "failed" และจะส่งคืน 504 หาก การดำเนินการยังคงทำงานอยู่หลังจากใช้จำนวนครั้งที่อนุญาตจนหมดแล้ว การตอบกลับสุดท้ายจาก Azure จะถูก ปรับให้อยู่ในรูปแบบ pages/markdown เดียวกับที่ Mistral ใช้ก่อนส่งคืนให้ ผู้เรียก ดังนั้นโค้ดฝั่งไคลเอนต์จึงไม่จำเป็นต้องจัดการผู้ให้บริการแต่ละรายเป็นกรณีพิเศษ

การยืนยันตัวตนและการกำหนดปลายทางของ Vertex AI DeepSeek OCR

vertex-deepseek-ocr ใช้กลไกการยืนยันตัวตน Vertex AI แบบเดียวกับที่ OmniRoute รองรับอยู่แล้วสำหรับ ทราฟฟิกแชต/รูปภาพ (open-sse/executors/vertex.ts): คีย์ API ของการเชื่อมต่ออาจเป็น ข้อมูลประจำตัว Service Account JSON (ซึ่งจะถูกแลกเป็นโทเค็นการเข้าถึง OAuth แบบอายุสั้นผ่านโฟลว์ JWT-bearer) หรือเป็นโทเค็นการเข้าถึง OAuth ที่ออกไว้แล้วและนำมาใช้ได้ทันที URL ปลายทางของบริการต้นทางคือปลายทางพาร์ทเนอร์ openapi/chat/completions แบบทั่วไปของ Vertex ซึ่งสร้างจากโปรเจกต์และ ภูมิภาคของการเชื่อมต่อ — หากระบุ providerSpecificData.project/providerSpecificData.region ไว้อย่างชัดเจน ค่าดังกล่าวจะมีลำดับความสำคัญเสมอ มิฉะนั้น โปรเจกต์จะถูกดึงมาจาก project_id ของ Service Account JSON และภูมิภาค จะใช้ค่าเริ่มต้นเป็น us-central1 การกำหนดค่าทั้งสองส่วนเกิดขึ้นใน open-sse/handlers/ocr.ts (resolveVertexOcrAccessToken, resolveVertexOcrBaseUrl) และถูกนำไปใช้โดย src/app/api/v1/ocr/route.ts ก่อนส่งต่อไปยัง handleOcr


แสดงรายการโมเดล

GET /v1/models
Authorization: Bearer your-api-key

→ ส่งคืนโมเดลแชต โมเดล embedding และโมเดลรูปภาพทั้งหมด รวมถึงชุดโมเดลผสม ในรูปแบบ OpenAI

คำนำหน้า id ของโมเดล (?prefix=)

โมเดลส่วนใหญ่จะแสดงภายใต้ คำนำหน้าผู้ให้บริการ คำนำหน้าที่คุณได้รับจะถูกควบคุมโดย feature flag MODELS_CATALOG_PREFIX_MODE และสามารถเขียนทับได้ สำหรับแต่ละคำขอ ด้วย พารามิเตอร์ query ซึ่งมีประโยชน์สำหรับไคลเอนต์ที่ต้องการรายการที่เป็นระเบียบโดยไม่ต้องเปลี่ยนการตั้งค่า ทั่วทั้งเซิร์ฟเวอร์สำหรับผู้ใช้อื่นทั้งหมด:

GET /v1/models?prefix=alias        # หนึ่ง id ต่อโมเดล — คำนำหน้า alias แบบสั้น
GET /v1/models?prefix=dual         # ทั้งสองรูปแบบ (ค่าเริ่มต้นของเซิร์ฟเวอร์)
GET /v1/models?prefix=canonical    # เฉพาะคำนำหน้า provider-id แบบเต็ม
โหมด ส่งออก หมายเหตุ
dual cc/claude-sonnet-4-6 และ claude/claude-sonnet-4-6 ค่าเริ่มต้น id ทั้งสองจะกำหนดเส้นทางไปยังโมเดลเดียวกัน โดยคงไว้เพื่อให้การกำหนดค่าไคลเอนต์ที่ฮาร์ดโค้ดรูปแบบใดรูปแบบหนึ่งยังคงทำงานต่อไปได้ ทำให้แค็ตตาล็อกมีขนาดเพิ่มขึ้นประมาณสองเท่า
alias cc/claude-sonnet-4-6 หนึ่งรายการต่อโมเดล ผู้ให้บริการที่ไม่มี alias แยกต่างหากจะยังคงแสดงรายการของตน จึงไม่มีข้อมูลใดสูญหาย
canonical claude/claude-sonnet-4-6 หนึ่งรายการต่อโมเดลภายใต้คำนำหน้า provider-id แบบเต็ม ผู้ให้บริการที่ไม่มี alias แยกต่างหาก (เช่น antigravity/…, agy/…) จะแสดง id เดียวของตนที่นี่ด้วย จึงไม่มีข้อมูลใดสูญหาย

มิเรอร์ในโหมด dual สามารถระบุได้โดยไม่ต้องใช้พารามิเตอร์ query เช่นกัน โดยจะมีฟิลด์ parent ที่ชี้ไปยัง id หลัก

ไคลเอนต์ที่แสดงตัวเลือกโมเดลควรร้องขอ ?prefix=alias ซึ่งเป็นวิธีที่ ส่วนขยาย OmniCopilot สำหรับ VS Code ใช้

ตัวแปรโมเดลแบบไม่ใช้การคิด

สำหรับโมเดล Claude ที่รองรับการคิด /v1/models จะแสดงตัวแปรแบบ ไม่ใช้การคิด ด้วย โดย id จะมีคำนำหน้า claude-3-omniroute-no-thinking/:

claude-3-omniroute-no-thinking/<provider>/<model>

การเลือก id นี้ (เช่น ในการกำหนดค่า Claude Code ที่แนบบล็อก thinking เสมอ) จะถูกแปลงกลับไปเป็น <provider>/<model> จริงโดยปิดการให้เหตุผล กล่าวคือใช้ thinking:{type:"disabled"} บนพาธ /v1/messages หรือตัดฟิลด์ reasoning/reasoning_effort ออกจากพาธ /v1/chat/completions ตัวแปรนี้จะแสดงเฉพาะสำหรับโมเดลในตระกูล Claude ที่รองรับการคิด และ ยอมรับ disabled (ดังนั้น ตัวอย่างเช่น โมเดลแบบ adaptive-only ที่ปฏิเสธ disabled จะไม่ถูกรวมไว้) ผู้ดูแลระบบสามารถบังคับเปิดหรือปิดตัวแปรนี้สำหรับแต่ละโมเดลผ่าน ModelSpec.noThinkingAlias


Manifest ของปลั๊กอินผู้ให้บริการ

GET /api/v1/provider-plugin-manifest

ส่งคืน Manifest ของปลั๊กอินผู้ให้บริการในรูปแบบที่ปลอดภัยสำหรับ JSON ซึ่งใช้โดย Bifrost, CLIProxyAPI และ เราเตอร์ sidecar ในอนาคต การตอบกลับนี้สร้างขึ้นจากรีจิสทรีผู้ให้บริการของ TypeScript และจงใจไม่รวมข้อมูลลับไคลเอนต์ OAuth, การแก้ไขค่าสภาพแวดล้อมขณะรัน, ฟังก์ชัน executor, ส่วนหัวคำขอ และข้อมูลบัญชี

ใช้ endpoint นี้เมื่อ sidecar ทำงานแยกเป็นอีกโปรเซสและไม่สามารถ import open-sse/config/providerPluginManifestRegistry.ts ได้โดยตรง


Endpoint สำหรับความเข้ากันได้

เมธอด พาธ รูปแบบ
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 ที่มี token
POST /api/v1/vscode/{token}/responses นามแฝง OpenAI Responses ที่มี token
POST /api/v1/vscode/{token}/api/chat นามแฝง Ollama ที่มี token
GET /api/v1/vscode/{token}/api/tags นามแฝงแท็ก Ollama ที่มี token

เส้นทาง POST ทั้งหมดใช้โครงสร้างเดียวกัน: Bearer your-api-key + เนื้อหา JSON ที่ผ่านการตรวจสอบด้วย Zod (v1RerankSchema, v1ModerationSchema, v1AudioSpeechSchema ฯลฯ โปรดดู src/shared/validation/schemas.ts) ระบบจะส่งคืน 4xx เมื่อการตรวจสอบ schema ล้มเหลว

สำหรับไคลเอนต์ที่ไม่สามารถแนบ Authorization: Bearer ... ได้ OmniRoute ยังยอมรับ API key ใน URL ผ่านความเข้ากันได้แบบ query string (?token=..., ?apiKey=..., ?api_key=..., ?key=...) หรือผ่าน endpoint เฉพาะ /api/v1/vscode/{token}/... ที่อธิบายไว้ด้านล่าง

# จัดอันดับใหม่
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

# การสร้างวิดีโอ / เพลง (รหัสโมเดลที่มีคำนำหน้าผู้ให้บริการ)
POST /v1/videos/generations { "model": "runway/gen-3", "prompt": "..." }
POST /v1/music/generations  { "model": "suno/v3.5",   "prompt": "..." }

เส้นทางเฉพาะสำหรับผู้ให้บริการ

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 สตรีมเนื้อหาไฟล์ดิบกลับมา

การยืนยันตัวตน: คีย์ API แบบ Bearer — ไฟล์ถูกจำกัดขอบเขตแยกตามคีย์ API ผ่าน getApiKeyRequestScope คีย์หนึ่ง สามารถดู ดาวน์โหลด และลบได้เฉพาะไฟล์ของตนเองเท่านั้น ส่วนเซสชันแดชบอร์ดที่ไม่มีคีย์สามารถอ่านได้ทั้ง อินสแตนซ์ และไฟล์ที่ไม่มีเจ้าของ (อัปโหลดแบบไม่ระบุตัวตนหรือผ่านเซสชันแดชบอร์ด) จะถูกปฏิเสธสำหรับผู้เรียกที่ไม่ใช่ เซสชันทุกราย GET /v1/files จะปฏิเสธผู้เรียกที่ไม่ระบุตัวตน — รวมถึงคีย์ที่ส่งมาแต่ไม่สามารถ ระบุได้ — ด้วย 401 แม้ว่า REQUIRE_API_KEY=false แทนที่จะแสดงรายการไฟล์ของ ผู้เช่าทุกราย (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 ยกเลิกแบตช์ที่กำลังดำเนินการ

การยืนยันตัวตน: คีย์ API แบบ Bearer แบตช์ถูกจำกัดขอบเขตแยกตามคีย์ API ภายใต้กฎสามรูปแบบเดียวกันกับ ไฟล์ ได้แก่ เฉพาะคีย์ของตนเอง เซสชันแดชบอร์ดเข้าถึงได้ทั้งอินสแตนซ์ และระเบียนที่ไม่มีเจ้าของจะถูกปฏิเสธสำหรับ ผู้เรียกที่ไม่ใช่เซสชันทุกราย (การดึงข้อมูล การลบ การยกเลิก และการตรวจสอบ input_file_id ตอนสร้าง) GET /v1/batches จะปฏิเสธผู้เรียกที่ไม่ระบุตัวตนด้วย 401 แม้ว่า REQUIRE_API_KEY=false


Search API

ส่วนเชื่อมโยงแบบนามธรรมสำหรับผู้ให้บริการเว็บ/การค้นหา (Tavily, Brave, Exa, Serper ฯลฯ)

เมธอด พาธ คำอธิบาย
GET /v1/search แสดงรายการผู้ให้บริการค้นหาที่กำหนดค่าไว้พร้อมความสามารถ
POST /v1/search เรียกใช้คำค้นหา — เนื้อหา request ผ่านการตรวจสอบโดย v1SearchSchema รองรับการแคช/การรวมคำขอ
GET /v1/search/analytics สถิติการเรียกสำเร็จ/เวลาแฝง/แคชแยกตามผู้ให้บริการ

การยืนยันตัวตน: คีย์ API แบบ Bearer (extractApiKey + isValidApiKey) มีการบังคับใช้นโยบายการค้นหาผ่าน enforceApiKeyPolicy


Web Fetch API

แยกเนื้อหาจาก URL ผ่านผู้ให้บริการดึงข้อมูลเว็บที่กำหนดค่าไว้ (Firecrawl, Jina Reader, Tavily Extract, TinyFish Fetch, Nimble Extract)

เมธอด พาธ คำอธิบาย
POST /v1/web/fetch ดึง/สแครป URL — เนื้อหา request ผ่านการตรวจสอบโดย v1WebFetchSchema

การยืนยันตัวตน: คีย์ API แบบ Bearer (extractApiKey + isValidApiKey) มีการบังคับใช้นโยบายผ่าน enforceApiKeyPolicy

การถอยไปใช้ตัวเลือกสำรองโดยคำนึงถึงโควตา (#8297): เมื่อไม่ได้ระบุ provider อย่างชัดเจน ระบบจะไล่ pool (firecrawljina-readertavily-searchtinyfishnimble-search) ตามลำดับความสำคัญคงที่ (fill-first) — ผู้ให้บริการที่กำหนดค่าไว้แต่ถูกจำกัดอัตราจะถูกข้าม แทนที่จะยุติ request ทันที และความล้มเหลวจาก upstream ที่ลองใหม่ได้/เกี่ยวข้องกับโควตา (HTTP 429 เสมอ; 402/403 สำหรับระดับฟรีที่มีลักษณะเป็นโควตาของ Firecrawl/Tavily/TinyFish — ไม่ใช้กับ Jina Reader และไม่ใช้กับ bad request 400 ทั่วไป) จะถอยไปยัง ผู้ให้บริการรายถัดไปที่มีข้อมูลประจำตัวและยังไม่เคยลองในขณะประมวลผล request เมื่อผู้ให้บริการทั้งหมดใน pool ใช้งานจนหมด endpoint จะส่งคืน 429 รายการเดียว (พร้อม header Retry-After) แทน 400 ทั่วไปแบบเดิม เมื่อร้องขอ provider อย่างชัดเจน จะไม่มีการถอยไปใช้ตัวเลือกสำรองโดยอัตโนมัติ — ผู้ให้บริการที่ระบุซึ่งถูกจำกัดอัตราหรือล้มเหลว จะแสดงข้อผิดพลาดของตนเอง (429 หากถูกจำกัดอัตรา มิฉะนั้นใช้สถานะจาก upstream)


การสตรีมผ่าน WebSocket

GET /v1/ws?handshake=1

ตรวจสอบ handshake สำหรับการอัปเกรด WebSocket และส่งคืนตัวอย่างข้อความของ wire protocol (request, cancel) ส่วนเฟรม WS จริงจะได้รับการจัดการโดยเซิร์ฟเวอร์ WS ที่รวมมาให้ ซึ่งอยู่นอกตาราง route ของ Next.js

การยืนยันตัวตน: คีย์ API แบบ Bearer ระหว่าง handshake

Responses API ผ่าน WebSocket (เฉพาะ codex)

# โฮสต์:พอร์ตเดียวกับ HTTP API (ค่าเริ่มต้นคือ 20128); อัปเกรดการเชื่อมต่อ:
wscat -c "ws://localhost:20128/v1/responses?api_key=<OMNIROUTE_API_KEY>"
# (หรือ: -H "Authorization: Bearer <OMNIROUTE_API_KEY>")

# เฟรมแรกต้องเป็น response.create:
{ "type": "response.create", "model": "gpt-5.5", "input": [ { "role": "user", "content": "hi" } ] }

พร็อกซี Responses-API-over-WebSocket เชื่อมต่อเฉพาะกับ codex เท่านั้น (แบ็กเอนด์ ChatGPT) โดยรับฟังบนพอร์ตเดียวกับ API/แดชบอร์ดที่พาธ /v1/responses, /responses และ /api/v1/responses เมื่อได้รับเฟรม response.create แรก ระบบจะ ยืนยันตัวตน + เตรียมการผ่านบริดจ์ codex-responses-ws ภายใน เลือก การเชื่อมต่อ OAuth ของ codex และสร้าง tunnel ไปยัง wss://chatgpt.com/backend-api/codex/responses ผ่าน transport wreq-js โมเดลที่ไม่ใช่ codex จะถูกปฏิเสธ (codex_ws_provider_required) สำหรับการกำหนดเส้นทางแบบแบ่งโควตา ให้ใช้ model: "qtSd/<group>/codex/<model>" การทำงานนี้อยู่ใน app/server-ws.mjs + scripts/dev/responses-ws-proxy.mjs + src/app/api/internal/codex-responses-ws/route.ts

การยืนยันตัวตน: คีย์ API แบบ Bearer ระหว่าง handshake เซิร์ฟเวอร์ HTTP ที่รวมมาให้ (server-ws.mjs) ต้องเป็น entrypoint ที่กำลังใช้งานอยู่ (และจะเป็นเช่นนั้นโดยค่าเริ่มต้นเมื่อมี app/server-ws.mjs)

ID โมเดล: ใช้ ID ของ ChatGPT แบบไม่มีคำนำหน้า (ไม่มีคำนำหน้า codex/)

OpenAI Codex CLI จะตรวจสอบชื่อโมเดลฝั่งไคลเอนต์เมื่อ supports_websockets = true และปฏิเสธ ID ที่มีคำนำหน้าผู้ให้บริการ เช่น codex/gpt-5.5 (The 'codex/gpt-5.5' model is not supported when using Codex with a ChatGPT account) ให้ส่ง ID แบบไม่มีคำนำหน้า (เช่น gpt-5.5) บริดจ์ของ OmniRoute รองรับเฉพาะ codex ดังนั้นจึง resolve ID แบบไม่มีคำนำหน้าใหม่เป็นโมเดล codex (resolveCodexWsModelInfo) ก่อนสร้าง tunnel ไปยัง upstream — แม้ว่า gpt-5.5 แบบไม่มีคำนำหน้าจะถูกกำหนดเส้นทางไปยังผู้ให้บริการรายอื่นผ่าน HTTP ในกรณีปกติก็ตาม

การกำหนดค่า OpenAI Codex CLI

กำหนดให้ Codex CLI ชี้ไปยัง OmniRoute โดยเพิ่มผู้ให้บริการแบบกำหนดเองที่รองรับ WebSocket ลงใน ~/.codex/config.toml (ใช้ CODEX_HOME แยกต่างหากเพื่อหลีกเลี่ยงการแก้ไข การกำหนดค่าที่มีอยู่):

model = "gpt-5.5"                 # ID แบบไม่มีคำนำหน้า — ไม่ใช่ "codex/gpt-5.5"
model_provider = "omniroute"

[model_providers.omniroute]
name = "OmniRoute (WS)"
base_url = "http://localhost:20128/v1"   # ไม่มีเครื่องหมายทับท้าย; URL ของ WS จะถูกสร้างขึ้นจากค่านี้ (ใช้ https/wss ในระบบ production)
wire_api = "responses"                    # ค่าที่รองรับเพียงค่าเดียวนับตั้งแต่ ก.พ. 2026
supports_websockets = true                # เปิดใช้งาน transport แบบ Responses-over-WS
env_key = "OMNIROUTE_API_KEY"             # เก็บคีย์ API ของ OmniRoute (Bearer)
export OMNIROUTE_API_KEY=sk-...           # คีย์ API ของ OmniRoute (ใช้คีย์ใดก็ได้หาก REQUIRE_API_KEY=false)
codex exec "Responda apenas: PONG"

CLI จะอัปเกรด base_url + /responses เป็น WebSocket และ OmniRoute จะสร้าง tunnel ไปยัง การเชื่อมต่อ OAuth ของ codex ที่เลือกไว้ ผ่านการตรวจสอบแบบต้นทางถึงปลายทางกับเซิร์ฟเวอร์ภายในแล้ว: ChatGPT ส่งคืน codex.rate_limits + response.created และสตรีมผลลัพธ์จนเสร็จสมบูรณ์


การรายงานโควตาและปัญหา

เมธอด พาธ คำอธิบาย
GET /v1/quotas/check ตรวจสอบโควตาล่วงหน้าสำหรับ provider + accountId ก่อนออกคีย์ที่ลงทะเบียนแล้ว
POST /v1/issues/report รายงานความล้มเหลวในการออกโควตา/คีย์ไปยัง GitHub (ต้องมี GITHUB_ISSUES_REPO + โทเค็น)

การยืนยันตัวตน: คีย์ API แบบ Bearer (isAuthenticated)


การใช้งานแบบบริการตนเอง (/api/usage/om-usage)

คีย์ API ใดๆ สามารถอ่านข้อมูลการใช้งานและโควตาของตนเองได้ โดยไม่ต้องใช้การยืนยันตัวตนสำหรับการจัดการ นี่คือ endpoint ที่ ไคลเอนต์ (CLI, แผง OmniCopilot) ใช้เพื่อแสดงค่าใช้จ่ายให้ผู้ถือคีย์ทราบ

# รูปแบบข้อความ (สัญญาการทำงานแบบเดิม — ข้อความธรรมดาสำหรับเทอร์มินัล)
curl -H "Authorization: Bearer <your-api-key>" \
  http://localhost:20128/api/usage/om-usage

# รูปแบบมีโครงสร้าง — รูปแบบที่ UI ใช้งาน
curl -H "Authorization: Bearer <your-api-key>" \
  "http://localhost:20128/api/usage/om-usage?format=json"

คีย์ต้องเปิดใช้งาน allowUsageCommand (ปิดไว้โดยค่าเริ่มต้น — ตัวจัดการคีย์ API ของแดชบอร์ด ใช้สำหรับเปิดหรือปิดค่านี้แยกตามคีย์) หากไม่ได้เปิดใช้งาน endpoint จะตอบกลับด้วย 403

?format=json จะส่งคืนโครงสร้างแบบจำแนกประเภท เพื่อให้ผู้เรียกไม่อ่านฟิลด์ข้อมูลจาก การปฏิเสธ เมื่อสำเร็จ:

{
  "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 ไม่ได้รับอนุญาต) route เดียวกันจะส่งคืน { "allowed": false, "error": { "message": "…" } }personal/provider ที่มีอยู่แต่ไม่มีข้อมูล (คีย์ได้รับอนุญาต แต่ยังไม่ได้รับข้อมูลใดๆ) เป็นสถานะที่แตกต่างจากการถูกปฏิเสธ และมีเพียงรูปแบบ JSON เท่านั้นที่แยกแยะสถานะเหล่านี้ได้

การยืนยันตัวตน: คีย์ API แบบ Bearer ของผู้เรียกเอง ซึ่งตรวจสอบด้วย isValidApiKey — ส่วนนี้_ไม่ใช่_ พื้นผิวการจัดการ (/api/keys/…) ซึ่งยังคงได้รับการป้องกันด้วย requireManagementAuth


แคชเชิงความหมาย

# รับสถิติแคช
GET /api/cache/stats

# ล้างแคชทั้งหมด
DELETE /api/cache/stats

ตัวอย่างการตอบกลับ:

{
  "semanticCache": {
    "memorySize": 42,
    "memoryMaxSize": 500,
    "dbSize": 128,
    "hitRate": 0.65
  },
  "idempotency": {
    "activeKeys": 3,
    "windowMs": 5000
  }
}

ผลกระทบต่อเวลาแฝง

เมื่อ semantic cache HIT ระบบจะให้บริการการตอบกลับจากแคชโดยไม่มีการเรียก upstream ดังนั้น X-OmniRoute-Response-Latency ที่รายงานจึงใกล้ศูนย์ (ไม่ว่าเวลาแฝงของ upstream เดิมจะเป็นเท่าใดก็ตาม) ไคลเอนต์ที่ไวต่อเวลาแฝง (การทำ benchmark, การเฝ้าติดตาม p50/p99) ควรตรวจสอบส่วนหัวการตอบกลับ X-OmniRoute-Cache-Latency:

ค่า ความหมาย
synthetic ให้บริการการตอบกลับจากแคช เวลาแฝงจึงไม่ใช่เวลาจริงของ upstream
(ไม่มี) การตอบกลับจากการเรียก upstream จริง

การข้ามแคชแยกตามคีย์

คีย์ API สามารถเลือกไม่อ่าน semantic cache ผ่าน cacheDefaultMode:

ค่า ลักษณะการทำงาน
legacy ลักษณะการทำงานของแคชตามปกติ (ค่าเริ่มต้น)
bypass ข้ามการค้นหาแคชทั้งหมด และเรียก upstream เสมอ

กำหนดค่าเมื่อสร้างคีย์ (POST /api/keys) หรืออัปเดต (PATCH /api/keys/[id]):

{ "cacheDefaultMode": "bypass" }

การข้ามแคชแยกตามคำขอ

คำขอใดๆ สามารถข้ามแคชได้โดยไม่ขึ้นกับการตั้งค่าคีย์:

X-OmniRoute-No-Cache: true

แดชบอร์ดและการจัดการ

เส้นทางการจัดการ (/api/* ยกเว้น auth/login สาธารณะ) ไม่ได้รับอนุญาตด้วย คีย์ API สำหรับการอนุมานทั่วไป สำหรับประเภทข้อมูลประจำตัว ขอบเขต และตัวอย่าง curl โปรดดู: การยืนยันตัวตนสำหรับการจัดการ

การยืนยันตัวตน

Endpoint Method Description
/api/auth/login POST เข้าสู่ระบบ
/api/auth/logout POST ออกจากระบบ
/api/settings/require-login GET/PUT เปิด/ปิดการบังคับให้เข้าสู่ระบบ

การจัดการผู้ให้บริการ

Endpoint Method Description
/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* Various การจัดการโหนดของผู้ให้บริการ
/api/provider-models GET/POST/PATCH/DELETE โมเดลแบบกำหนดเอง (เพิ่ม อัปเดต ซ่อน/แสดง ลบ)

ขั้นตอน OAuth

Endpoint Method Description
/api/oauth/[provider]/[action] Various OAuth เฉพาะสำหรับผู้ให้บริการ

การกำหนดเส้นทางและการตั้งค่า

Endpoint Method Description
/api/models/alias GET/POST นามแฝงของโมเดล
/api/models/catalog GET โมเดลทั้งหมดแยกตามผู้ให้บริการ + ประเภท
/api/combos* Various การจัดการคอมโบ
/api/keys* Various การจัดการคีย์ API
/api/pricing GET ราคาของโมเดล

การใช้งานและการวิเคราะห์

Endpoint Method คำอธิบาย
/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 สถิติรวมเวลาแฝงแบบต่อเนื่องแยกตามผู้ให้บริการ/โมเดล (ค่าเฉลี่ย/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)

การตั้งค่า

Endpoint Method คำอธิบาย
/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 โหมดเขียน คำขอ สำหรับการคิด/การให้เหตุผลใหม่ (ส่งผ่าน / ตัดออกอัตโนมัติ / กำหนดเอง / ปรับตามสถานการณ์) ทำงานแยกจากการบีบอัด ดู THINKING_BUDGET.md
/api/settings/system-prompt GET/PUT พรอมต์ระบบส่วนกลาง
/api/settings/compression GET/PUT การกำหนดค่าการบีบอัดส่วนกลาง
/api/settings/purge-request-history POST ล้างแถวบันทึกคำขอและอาร์ติแฟกต์บันทึกการเรียกใช้ภายในเครื่อง

บริบทและการบีบอัด

Endpoint เมธอด คำอธิบาย
/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 นามแฝงสำหรับการวิเคราะห์การบีบอัด

การตรวจสอบระบบ

Endpoint เมธอด คำอธิบาย
/api/sessions GET การติดตามเซสชันที่ใช้งานอยู่
/api/rate-limits GET ขีดจำกัดอัตราคำขอต่อบัญชี
/api/monitoring/health GET การตรวจสอบสถานะระบบ + สรุปผู้ให้บริการ (catalogCount, configuredCount, activeCount, monitoredCount) มุมมองการจัดการประกอบด้วย credentialHealth: ค่าสเกลาร์ของแคชการตรวจสอบ, failedConnections เมื่อ failed>0 และ staleDbNonOkCount (test_status แบบคงค้างของ SQLite ไม่ใช่มาตรวัด) ดู MONITORING_GUIDE.md
/api/cache/stats GET/DELETE สถิติแคช / ล้างแคช
/api/modality-bridge/stats GET ค่า attempts ในหน่วยความจำ, จำนวนที่สำเร็จ/bridged, จำนวนที่ล้มเหลว, จำนวนแคชฮิต, totalLatencyMs, latencySamples, averageLatencyMs ที่คำนวณโดยใช้จำนวนตัวอย่างเป็นตัวหาร และเวลาที่ใช้งานครั้งล่าสุด (รีเซ็ตเมื่อเริ่มระบบใหม่; ต้องมีสิทธิ์การจัดการ)
/api/modality-bridge/video/runtime GET ตรวจสอบลูปแบ็กที่เชื่อถือได้อย่างเข้มงวดก่อนการยืนยันสิทธิ์/การตรวจสอบสำหรับการจัดการ; สถานะความพร้อมใช้งานและเวอร์ชันของ FFmpeg/ffprobe ที่ผ่านการกรองข้อมูลแล้ว (ไม่จัดเก็บ)
/api/modality-bridge/video/extract POST โบรกเกอร์ไบต์ภายในที่ผ่านการยืนยันสิทธิ์และใช้ลูปแบ็กที่เชื่อถือได้; อินพุต 50 MiB, คิวที่จำกัด/เอาต์พุต 32 MiB, 503 เมื่อความจุเต็ม, 499 เมื่อยกเลิกการเชื่อมต่อ, 504 เมื่อเกินกำหนดเวลา; ไม่ใช่ API อัปโหลดสาธารณะ

การสำรองข้อมูลและการส่งออก/นำเข้า

Endpoint Method คำอธิบาย
/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

การซิงค์กับคลาวด์

Endpoint Method คำอธิบาย
/api/sync/cloud Various การดำเนินการซิงค์กับคลาวด์
/api/sync/initialize POST เริ่มต้นการซิงค์
/api/cloud/* Various การจัดการคลาวด์

ทันเนล

Endpoint Method คำอธิบาย
/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

Endpoint Method คำอธิบาย
/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

Endpoint Method คำอธิบาย
/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)

ความทนทานและขีดจำกัดอัตรา

Endpoint Method คำอธิบาย
/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) ดูรายละเอียดทั้งหมดเกี่ยวกับความแตกต่างระหว่างเซอร์กิตเบรกเกอร์ของผู้ให้บริการ ช่วงพักการเชื่อมต่อ และการล็อกโมเดลได้ที่ ความทนทาน (ฉบับขยาย)

การประเมิน

Endpoint Method คำอธิบาย
/api/evals GET/POST แสดงรายการชุดการประเมิน / เรียกใช้การประเมิน

นโยบาย

Endpoint Method คำอธิบาย
/api/policies GET/POST/DELETE จัดการนโยบายการกำหนดเส้นทาง

การปฏิบัติตามข้อกำหนด

Endpoint Method คำอธิบาย
/api/compliance/audit-log GET บันทึกการตรวจสอบการปฏิบัติตามข้อกำหนด (N รายการล่าสุด)

v1beta (เข้ากันได้กับ Gemini)

Endpoint Method คำอธิบาย
/v1beta/models GET แสดงรายการโมเดลในรูปแบบ Gemini
/v1beta/models/{...path} POST Endpoint generateContent ของ Gemini

Endpoint เหล่านี้จำลองรูปแบบ API ของ Gemini สำหรับไคลเอนต์ที่ต้องการความเข้ากันได้กับ Gemini SDK แบบเนทีฟ

API ภายใน / ระบบ

Endpoint Method คำอธิบาย
/api/init GET ตรวจสอบการเริ่มต้นแอปพลิเคชัน (ใช้ในการเรียกใช้ครั้งแรก)
/api/tags GET แท็กโมเดลที่เข้ากันได้กับ Ollama (สำหรับไคลเอ็นต์ Ollama)
/api/restart POST เริ่มกระบวนการรีสตาร์ตเซิร์ฟเวอร์อย่างปลอดภัย
/api/shutdown POST เริ่มกระบวนการปิดเซิร์ฟเวอร์อย่างปลอดภัย
/api/system/env/repair POST ซ่อมแซมตัวแปรสภาพแวดล้อมของผู้ให้บริการ OAuth

หมายเหตุ: Endpoint เหล่านี้ใช้ภายในระบบหรือเพื่อให้เข้ากันได้กับไคลเอ็นต์ Ollama โดยทั่วไปผู้ใช้ปลายทางจะไม่เรียกใช้ Endpoint เหล่านี้โดยตรง

การซ่อมแซมสภาพแวดล้อม OAuth (v3.6.1+)

POST /api/system/env/repair
Content-Type: application/json

{
  "provider": "claude-code"
}

ซ่อมแซมตัวแปรสภาพแวดล้อม OAuth ที่สูญหายหรือเสียหายสำหรับผู้ให้บริการที่ระบุ โดยส่งคืน:

{
  "success": true,
  "repaired": ["CLAUDE_CODE_OAUTH_CLIENT_ID", "CLAUDE_CODE_OAUTH_CLIENT_SECRET"],
  "backupPath": "/home/user/.omniroute/backups/env-repair-2026-04-11.bak"
}

การถอดเสียง

POST /v1/audio/transcriptions
Authorization: Bearer your-api-key
Content-Type: multipart/form-data

ถอดเสียงไฟล์เสียงโดยใช้ผู้ให้บริการ STT ที่กำหนดค่าไว้ เซกเมนต์แรกของพาธ จะเลือกผู้ให้บริการโดยตรง (openai/…, deepgram/…) ส่วนเกตเวย์ที่ นำโมเดลของผู้ให้บริการรายอื่นมาให้บริการอีกทอดหนึ่งจะใช้ ID แบบระบุแหล่งที่มา (openrouter/deepgram/nova-3)

คำขอ:

curl -X POST http://localhost:20128/v1/audio/transcriptions \
  -H "Authorization: Bearer your-api-key" \
  -F "file=@recording.mp3" \
  -F "model=openai/whisper-1"

การตอบกลับ:

{
  "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

สำหรับไคลเอนต์ที่ใช้รูปแบบ API ของ Ollama:

# เอนด์พอยต์แชต (รูปแบบ Ollama)
POST /v1/api/chat

# รายการโมเดล (รูปแบบ Ollama)
GET /api/tags

คำขอจะได้รับการแปลงระหว่างรูปแบบ Ollama และรูปแบบภายในโดยอัตโนมัติ

นามแฝงสำหรับ VS Code แบบมีโทเค็น / ไม่มีส่วนหัว

ใช้นามแฝงเหล่านี้เมื่อการผสานรวมไม่สามารถแทรกส่วนหัว Authorization และจำเป็นต้องฝังคีย์ API ไว้ใน URL ฐาน

# นามแฝงแค็ตตาล็อกสไตล์ 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

ตัวอย่าง:

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 ให้ใช้เป็นตัวเลือกเพื่อความเข้ากันได้ ไม่ใช่โหมดการยืนยันตัวตนเริ่มต้น

เทเลเมทรี

# รับสรุปข้อมูลเทเลเมทรีด้านเวลาแฝง (p50/p95/p99 ต่อผู้ให้บริการ)
GET /api/telemetry/summary

การตอบกลับ:

{
  "providers": {
    "claudeCode": { "p50": 245, "p95": 890, "p99": 1200, "count": 150 },
    "github": { "p50": 180, "p95": 620, "p99": 950, "count": 320 }
  }
}

งบประมาณ

# รับสถานะงบประมาณสำหรับคีย์ 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 ต้องมากกว่าศูนย์ ฟิลด์ที่ไม่บังคับ: warningThreshold (01), resetInterval (daily | weekly | monthly), resetTime (HH:MM) รูปแบบเดิม {keyId, limit, period} จะส่งคืน 400 Bad Request

ขีดจำกัดโทเค็น

งบประมาณ โทเค็น ต่อคีย์ API (แยกจากงบประมาณตาม USD ด้านบน) มีการบังคับใช้โดยตรงในเส้นทางคำขอ: เมื่อการใช้งานของคีย์ในช่วงเวลาปัจจุบันถึงขีดจำกัด คำขอจะถูกปฏิเสธด้วย 429 Too Many Requests ขีดจำกัดสามารถกำหนดขอบเขตให้กับ model หรือ provider ที่เฉพาะเจาะจง หรือใช้แบบ global กับทั้งคีย์ได้ เมื่อมีขีดจำกัดหลายรายการตรงกับคำขอ ระบบจะใช้รายการที่เข้มงวดที่สุด

# แสดงขีดจำกัดโทเค็นของคีย์ (รวมการใช้งานในช่วงเวลาปัจจุบัน)
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) ต้องระบุ scopeValue เว้นแต่ scopeType จะเป็น global (เช่น id ของโมเดลสำหรับขอบเขต model หรือ id ของผู้ให้บริการสำหรับขอบเขต provider) 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. ระบบระบุโมเดล (ผู้ให้บริการ/โมเดลโดยตรง หรือ alias/combo)
  4. เลือกข้อมูลประจำตัวจากฐานข้อมูลภายใน โดยกรองตามความพร้อมใช้งานของบัญชี
  5. สำหรับแชต: handleChatCore ตรวจสอบแคชเชิงความหมาย/ลายเซ็น และระบุการตั้งค่าการบีบอัดของ combo
  6. การบีบอัดเชิงรุกจะทำงานก่อนการแปลงสำหรับผู้ให้บริการเมื่อเปิดใช้งาน (lite, Caveman, RTK หรือแบบซ้อนกัน)
  7. ตัวดำเนินการของผู้ให้บริการส่งคำขอไปยังต้นทาง
  8. การตอบกลับถูกแปลงกลับเป็นรูปแบบของไคลเอนต์ (แชต) หรือส่งคืนตามเดิม (embeddings/images/audio)
  9. ระบบบันทึกการใช้งาน การวิเคราะห์การบีบอัด และบันทึกคำขอ
  10. ระบบใช้ fallback เมื่อเกิดข้อผิดพลาดตามกฎของ combo

ข้อมูลอ้างอิงสถาปัตยกรรมฉบับเต็ม: ARCHITECTURE.md


การจัดการ Combo

combo สำหรับการกำหนดเส้นทางระดับสูงกว่า (ซึ่งสรุปไว้แล้วภายใต้ /api/combos*) ยังสามารถจับคู่แบบ 1:1 จากรูปแบบ id ของโมเดลได้ด้วย ทำให้สามารถเปลี่ยนเส้นทาง id ของโมเดลรูปแบบ OpenAI ไปยัง combo ได้อย่างโปร่งใส

เมธอด พาธ คำอธิบาย
GET /api/model-combo-mappings แสดงรายการการจับคู่ model→combo ทั้งหมด
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 แสดงรายการเว็บฮุก (ข้อมูลลับถูกปิดบังเป็น <prefix>...)
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 key (requireManagementAuth)


คีย์ที่ลงทะเบียน (การจัดการอัตโนมัติ)

ใช้โดยระบบย่อยการจัดการคีย์อัตโนมัติเพื่อออกและหมุนเวียน API key กับผู้ให้บริการ/บัญชีเบื้องหลัง โดยมีโควตารายวัน/รายชั่วโมง

เมธอด พาธ คำอธิบาย
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 key (isAuthenticated) ดูเพิ่มเติมที่ /v1/quotas/check และ /v1/issues/report


โปรโตคอล Agents

งานของ Cloud Agent (Claude Code, Codex Cloud, OpenHands ฯลฯ) ที่ดำเนินการจากระยะไกลในนามของผู้ใช้ OmniRoute

เมธอด พาธ คำอธิบาย
GET /api/v1/agents/tasks แสดงรายการงาน — รองรับ ?provider=, ?status=, ?limit= เป็นตัวเลือก (1500, ค่าเริ่มต้น 50)
POST /api/v1/agents/tasks สร้างงาน — ตรวจสอบ body ด้วย CreateCloudAgentTaskSchema (providerId, prompt, source, options?) ส่งคืน 201 พร้อม task envelope
DELETE /api/v1/agents/tasks?id=... ลบงาน
GET /api/v1/agents/tasks/[id] อ่านงาน — รีเฟรชสถานะจาก Cloud Agent ต้นทางแบบซิงโครนัสเมื่อตั้งค่า 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 API เหล่านี้ไม่ต้องผ่านการยืนยันตัวตน — ดูการเปลี่ยนแปลงที่ไม่รองรับเวอร์ชันก่อนหน้าได้ที่ commit 588a0333

# สร้างงาน 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 สร้างพร็อกซี — ตรวจสอบ body ด้วย createProxyRegistrySchema
PATCH /api/v1/management/proxies อัปเดตพร็อกซี — ตรวจสอบ body ด้วย 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=<id> เพื่อระบุพร็อกซีที่ใช้งานอยู่สำหรับการเชื่อมต่อ
PUT /api/v1/management/proxies/assignments กำหนดใช้งาน — ตรวจสอบ body ด้วย proxyAssignmentSchema ({scope, scopeId?, proxyId?}) และล้างแคชของ dispatcher
PUT /api/v1/management/proxies/bulk-assign กำหนดใช้งานแบบกลุ่ม — ตรวจสอบ body ด้วย bulkProxyAssignmentSchema ({scope, scopeIds[], proxyId?})
GET /api/v1/management/proxies/health?hours=24 สรุปสถานะความพร้อมใช้งานของพร็อกซี (จำนวนครั้งที่สำเร็จ/ล้มเหลว และ latency) ภายในช่วงเวลาที่กำหนด

การยืนยันตัวตน: ทุก route ต้องมี management session/API key (requireManagementAuth)

POST /api/v1/management/proxies/[id]/assignments และ POST /api/v1/management/proxies/[id]/health ที่ระบุในคำอธิบายงาน ให้บริการผ่าน route แบบ flat คือ /assignments และ /health ตามที่แสดงด้านบน — ใน codebase ไม่มี subroute แยกตาม id


ความยืดหยุ่น (เพิ่มเติม)

OmniRoute มีกลไกรับมือความล้มเหลวชั่วคราวที่ทำงานแยกจากกันสามกลไก โดย endpoint สำหรับการจัดการด้านล่างช่วยให้ผู้ดูแลระบบสามารถอ่านและเขียนทับค่าเหล่านี้ได้:

ขอบเขต ที่จัดเก็บสถานะ อ่าน รีเซ็ต / ล้างค่า
เบรกเกอร์ของผู้ให้บริการ 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 โดยฟิลด์เดียวกันนี้ยังแสดงอยู่ใน แดชบอร์ด → การตั้งค่า → ความยืดหยุ่น

# ล้างการล็อกของโมเดลรายการเดียว
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 → "สถานะรันไทม์ด้านความยืดหยุ่น"


สกิล

เฟรมเวิร์กสกิลสำหรับขยาย OmniRoute ด้วย handler แบบกำหนดเองที่เรียกใช้งานได้ พร้อมการเชื่อมต่อกับ marketplace

เมธอด พาธ คำอธิบาย
GET /api/skills แสดงรายการสกิลที่ติดตั้งแล้ว — กรองได้ด้วย ?q=, ?mode=on|off|auto, ?source=skillsmp|skillssh|local และแบ่งหน้า
GET /api/skills/[id] ดึงข้อมูลสกิลหนึ่งรายการ
PUT /api/skills/[id] อัปเดตสกิล (ชื่อ คำอธิบาย โหมด schema handler และแท็ก)
DELETE /api/skills/[id] ถอนการติดตั้งสกิล
POST /api/skills/install ติดตั้งสกิลจาก manifest ดิบ — body: {name, version, description, schema:{input, output}, handlerCode, apiKeyId?}
GET /api/skills/executions แสดงรายการการเรียกใช้สกิลล่าสุด (บันทึกการตรวจสอบพร้อมอินพุต/เอาต์พุต/ระยะเวลา)
GET /api/skills/marketplace?q=... ค้นหา/แสดงรายการยอดนิยมจาก marketplace ของ SkillsMP (ต้องกำหนดค่า skillsmpApiKey)
POST /api/skills/marketplace/install ติดตั้งสกิลด้วย id จาก SkillsMP
GET /api/skills/skillssh?q=&limit= ค้นหาในรีจิสทรี skills.sh
POST /api/skills/skillssh/install ติดตั้งสกิลด้วย id จาก skills.sh

การยืนยันตัวตน: เซสชันการจัดการ/API key เส้นทางค้นหา marketplace รองรับทั้งการยืนยันตัวตนสำหรับการจัดการหรือ Bearer API key (isAuthenticated)


หน่วยความจำ

พื้นที่จัดเก็บหน่วยความจำด้านการสนทนา/ข้อเท็จจริงแบบถาวร โดยมีขอบเขตแยกตาม API key / session

เมธอด พาธ คำอธิบาย
GET /api/memory แสดงรายการหน่วยความจำ — ?apiKeyId=, ?type=, ?sessionId=, ?q=, พร้อมการแบ่งหน้าด้วย offset/limit หรือ page/limit
POST /api/memory สร้างหน่วยความจำ — body ผ่านการตรวจสอบโดย Zod: {content, key, type?, sessionId?, apiKeyId?, metadata?, expiresAt?}
GET /api/memory/[id] เรียกดูหน่วยความจำหนึ่งรายการ
DELETE /api/memory/[id] ลบหน่วยความจำ
GET /api/memory/health สถานะของระบบย่อยหน่วยความจำ (การเชื่อมต่อฐานข้อมูล, แบ็กเอนด์ embeddings, สถานะดัชนีเวกเตอร์)

การยืนยันตัวตน: เซสชันการจัดการ/API key (requireManagementAuth) ค่า enum ของ type: FACTUAL, EPISODIC, SEMANTIC, PROCEDURAL (ดู MemoryType ใน src/lib/memory/types.ts)


เซิร์ฟเวอร์ MCP

OmniRoute มาพร้อมเซิร์ฟเวอร์ Model Context Protocol แบบฝังตัวที่รองรับการรับส่งข้อมูล 3 รูปแบบ (stdio, SSE, streamable-http) และเครื่องมือที่จำกัดตามขอบเขต สิ้นสุดการทำงานของแดชบอร์ดด้านล่างใช้อ่านข้อมูลสถานะ/การตรวจสอบ และทำหน้าที่เป็นพร็อกซีสำหรับการรับส่งข้อมูลผ่าน HTTP

เมธอด พาธ คำอธิบาย
GET /api/mcp/status สัญญาณชีพ, การรับส่งข้อมูล, สถานะออนไลน์, การเรียกใช้ล่าสุด, เครื่องมือยอดนิยม, อัตราความสำเร็จใน 24 ชั่วโมง
GET /api/mcp/tools รายการเครื่องมือ MCP พร้อม name, description, scopes, phase, auditLevel, sourceEndpoints
GET /api/mcp/sse เปิดสตรีม SSE สำหรับการรับส่งข้อมูลแบบ SSE (ส่งคืน 503 หากปิดใช้งาน MCP หรือรูปแบบการรับส่งข้อมูลไม่ตรงกัน)
POST /api/mcp/sse ส่งเฟรม JSON-RPC ผ่านการรับส่งข้อมูลแบบ SSE
GET /api/mcp/stream เปิดฝั่ง SSE ของการรับส่งข้อมูลแบบ Streamable HTTP (ข้อความที่เริ่มส่งจากเซิร์ฟเวอร์)
POST /api/mcp/stream ส่งเฟรม JSON-RPC ผ่านการรับส่งข้อมูลแบบ Streamable HTTP
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 (Bearer API key ที่มีขอบเขต mcp) ส่วนเส้นทาง status/tools/audit* สามารถอ่านได้จากแดชบอร์ด (ไม่ต้องมีการยืนยันตัวตนเพิ่มเติมนอกเหนือจากการเข้าถึงโฮสต์ของแดชบอร์ด)

การรับส่งข้อมูลผ่าน HTTP ทั้งสองรูปแบบถูกควบคุมโดย settings.mcpEnabled และ settings.mcpTransport — หากรูปแบบการรับส่งข้อมูลไม่ตรงกันจะส่งคืน 400 และหากปิดใช้งาน MCP จะส่งคืน 503


เซิร์ฟเวอร์ A2A

OmniRoute เปิดให้ใช้งานเอนด์พอยต์ A2A (Agent-to-Agent) แบบ JSON-RPC 2.0 พร้อม REST wrapper สำหรับการตรวจสอบและการใช้งานแดชบอร์ด

JSON-RPC

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

การ์ดเอเจนต์

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 แปลงรหัสโมเดลเชิงตรรกะเป็นผู้ให้บริการ/โมเดลจริงโดยใช้ตารางการกำหนดเส้นทางภายในเครื่อง
GET /api/cloud/models/alias แสดงรายการนามแฝงโมเดลที่เปิดเผยต่อการซิงค์กับคลาวด์
GET /api/assess อ่านการจัดหมวดหมู่จากการประเมินล่าสุด (แยกตามผู้ให้บริการ/โมเดล)
POST /api/assess เรียกใช้การประเมิน — body: `{scope: {type:"all"} {type:"provider", providerId} {type:"model", modelId}, trigger?}`
GET /api/evals แสดงรายการชุดการประเมินผลในตัว + การเรียกใช้ล่าสุด
POST /api/evals เริ่มการเรียกใช้การประเมินผล
POST /api/evals/suites สร้างชุดการประเมินผลแบบกำหนดเอง — ตรวจสอบ body ด้วย evalSuiteSaveSchema
GET /api/evals/suites/[id] ดึงข้อมูลชุดการประเมินผลแบบกำหนดเอง

การยืนยันตัวตน: /api/cloud/auth ตรวจสอบคีย์ Bearer โดยตรง ส่วนเส้นทาง /api/cloud/*, /api/evals/* และ /api/assess อื่น ๆ ต้องใช้เซสชัน/คีย์ API สำหรับการจัดการ คำขอ POST ไปยัง /api/assess ใช้ validateBody ร่วมกับสคีมาขอบเขตแบบ discriminated union


การจัดการ ACP (Agent Client Protocol)

ในฐานะโปรเซสลูก Endpoint เหล่านี้ใช้จัดการการตรวจหาเอเจนต์ 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=<agentId>

ตัวอย่างการตอบกลับ (GET /api/acp/agents):

{
  "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 key ที่มีขอบเขตการจัดการ

ดูรายละเอียดทั้งหมดได้ที่ เฟรมเวิร์ก ACP


การวิเคราะห์และการสังเกตการณ์

Endpoint การวิเคราะห์แบบเรียลไทม์สำหรับตรวจสอบการกำหนดเส้นทาง การบีบอัด และความหลากหลายของผู้ให้บริการ ซึ่งขับเคลื่อนหน้า /dashboard/analytics/*

การวิเคราะห์การกำหนดเส้นทางอัตโนมัติ

เมธอด พาธ คำอธิบาย
GET /api/analytics/auto-routing สถิติรวมของการกำหนดเส้นทางอัตโนมัติ: จำนวนการเรียกทั้งหมด การกระจายตามกลยุทธ์ การกระจายตามระดับ และผู้ให้บริการอันดับต้น ๆ
GET /api/analytics/auto-routing?days=7 สถิติตามกรอบเวลา (ค่าเริ่มต้น 24 ชั่วโมง)

ตัวอย่างการตอบกลับ:

{
  "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 สถิติรวมของการบีบอัด: โทเค็นที่ประหยัดได้ เปอร์เซ็นต์ที่ประหยัด การกระจายตามโหมด และการใช้งานเอนจิน

ตัวอย่างการตอบกลับ:

{
  "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 การติดตามความหลากหลายโดยอิงค่า Shannon entropy: ป้องกันจุดล้มเหลวเพียงจุดเดียวด้วยการวัดการกระจายตัวของผู้ให้บริการ

ตัวอย่างการตอบกลับ:

{
  "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 key ที่มีขอบเขตการจัดการ


การดำเนินการสำหรับผู้ดูแลระบบ

เอนด์พอยต์สำหรับผู้ดูแลระบบเท่านั้นเพื่อการจัดการด้านการปฏิบัติงาน

เมธอด พาธ คำอธิบาย
GET /api/admin/concurrency อ่านขีดจำกัดการทำงานพร้อมกันในปัจจุบัน (ส่วนกลาง + ต่อผู้ให้บริการ)
POST /api/admin/concurrency อัปเดตขีดจำกัดการทำงานพร้อมกัน — เนื้อหา: {global?: number, perProvider?: Record<string, number>}

การยืนยันตัวตน: ต้องมีเซสชันการจัดการที่มีขอบเขตสิทธิ์ผู้ดูแลระบบ


การจัดการเครื่องมือ CLI

จัดการเครื่องมือ CLI ที่ผสานรวมกับ OmniRoute (antigravity, chipotle, commandCode, devin-cli เป็นต้น) ดูรายการทั้งหมดได้ที่ ข้อมูลอ้างอิงผู้ให้บริการ

เมธอด พาธ คำอธิบาย
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 สถานะพร็อกซี MITM ของ Antigravity (เครื่องมือ CLI "antigravity-mitm")
POST /api/cli-tools/antigravity-mitm/alias กำหนดค่านามแฝงของ antigravity-mitm

การยืนยันตัวตน: ต้องมีเซสชันการจัดการ


ทักษะของเอเจนต์

จัดการทักษะของเอเจนต์ AI (คล้ายกับ GPT แบบกำหนดเองของ OpenAI แต่ใช้สำหรับเอเจนต์)

เมธอด พาธ คำอธิบาย
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=<id> (รายการเดียว) หรือ ?provider=<p> หรือไม่มีพารามิเตอร์ (ทั้งหมด)

การยืนยันตัวตน: ต้องมีเซสชันการจัดการ


ระบบหน่วยความจำ

จัดการหน่วยความจำถาวร (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 ส่งเหตุการณ์ทดสอบไปยังเว็บฮุก

การยืนยันตัวตน: ต้องมีเซสชันการจัดการ

ดูประเภทเหตุการณ์ทั้งหมดได้ที่ เฟรมเวิร์กเว็บฮุก


เฟรมเวิร์ก Skills

จัดการ Skills (เฟรมเวิร์กส่วนขยายแบบเอเจนต์)

เมธอด พาธ คำอธิบาย
GET /api/skills แสดงรายการ Skills ที่ติดตั้งทั้งหมด (ในตัว + กำหนดเอง)
POST /api/skills/install ติดตั้ง Skill จากพาธภายในเครื่องหรือ URL
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 แสดงประวัติการเรียกใช้ของ Skills ทั้งหมด (กรองด้วย ?apiKeyId=)

การยืนยันตัวตน: ต้องใช้เซสชันการจัดการหรือ API key ที่มีขอบเขตการจัดการ

ดูรายละเอียดทั้งหมดได้ที่ เฟรมเวิร์ก Skills


ปลั๊กอิน

จัดการปลั๊กอิน 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 อัปเดตการกำหนดค่าปลั๊กอิน

การยืนยันตัวตน: ต้องใช้เซสชันการจัดการ

ดูรายละเอียดทั้งหมดได้ที่ เฟรมเวิร์ก Plugins


Shadow Routing

การเปรียบเทียบผู้ให้บริการแบบ Shadow / A-B ไม่ใช่ REST surface แบบสแตนด์อโลน — แต่กำหนดค่าผ่าน combo routing (ดู Auto-Combo) เมตริกการเปรียบเทียบแยกตาม combo ให้บริการผ่าน GET /api/combos/metrics


Guardrails

ตรวจสอบ Guardrails ขณะรันไทม์ (การตรวจจับ PII, การตรวจจับ prompt injection, vision bridging) Guardrails จะทำงานกับทุกคำขอ โดยสามารถเลือกไม่ใช้เป็นรายครั้งผ่านเฮดเดอร์คำขอ x-omniroute-disabled-guardrails — ไม่มีพื้นผิวสำหรับเปิด/ปิดแบบคงอยู่

เมธอด พาธ คำอธิบาย
GET /api/guardrails แสดงรายการ Guardrails ที่ลงทะเบียนไว้และสถานะ (ชื่อ / เปิดใช้งาน / ลำดับความสำคัญ)
POST /api/guardrails/test ทดลองรันไปป์ไลน์ก่อนเรียกใช้กับอินพุตตัวอย่าง — บอดี: {input, disabledGuardrails?}

การยืนยันตัวตน: ต้องใช้เซสชันการจัดการ

ดูรายละเอียดทั้งหมดได้ที่ ความปลอดภัย > Guardrails



การยืนยันตัวตน

ดู การยืนยันตัวตนสำหรับการจัดการ สำหรับข้อมูลรับรองทั้งสี่ประเภท (เซสชันแดชบอร์ด, โทเค็น CLI ภายในเครื่อง, oma_live_… Access Token, คีย์ API ที่มีขอบเขตการจัดการ) และความแตกต่างจากคีย์สำหรับการอนุมาน

  • เส้นทางแดชบอร์ด (/dashboard/*) ใช้คุกกี้ auth_token
  • การเข้าสู่ระบบใช้แฮชรหัสผ่านที่บันทึกไว้ โดยใช้ INITIAL_PASSWORD เป็นทางเลือกสำรอง
  • สามารถสลับเปิดหรือปิด requireLogin ผ่าน /api/settings/require-login
  • เส้นทาง /v1/* อาจกำหนดให้ใช้คีย์ API แบบ Bearer เมื่อ REQUIRE_API_KEY=true
  • "โทเค็นการจัดการ" / "คีย์ API ที่มีขอบเขตการจัดการ" ในเอกสารอ้างอิงนี้หมายถึงข้อมูลรับรองประเภทใดประเภทหนึ่งในคู่มือดังกล่าว ไม่ใช่ข้อมูลลับเพิ่มเติมอีกประเภทที่ไม่ได้กำหนดไว้

การเปลี่ยนแปลงที่ไม่เข้ากันย้อนหลัง (v3.8.0) — ขณะนี้ /api/v1/agents/tasks/* และเอนด์พอยต์การจัดการคูลดาวน์ต้องใช้ การยืนยันตัวตนสำหรับการจัดการ (คุกกี้ auth_token ของแดชบอร์ดหรือคีย์ API ที่มีขอบเขตการจัดการ) ไคลเอนต์ที่ก่อนหน้านี้เรียกเส้นทางเหล่านี้โดยไม่มีการยืนยันตัวตนจะได้รับ 401 Unauthorized ดูคอมมิต 588a0333 (fix(auth): require management auth for agent and cooldown APIs)