🌐 Languages: 🇺🇸 English · 🇪🇹 am · 🇸🇦 ar · 🇦🇿 az · 🇧🇬 bg · 🇧🇩 bn · 🇧🇦 bs · 🇨🇿 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
Agent-to-Agent Protocol v0.3 — OmniRoute ในฐานะเอเจนต์กำหนดเส้นทางอัจฉริยะ
พื้นผิว A2A มีสองรูปแบบ:
- JSON-RPC 2.0 ที่
POST /a2a(จุดเริ่มต้นมาตรฐาน ซึ่งกำหนดไว้ในsrc/app/a2a/route.ts) - REST ภายใต้
/api/a2a/*สำหรับแดชบอร์ดและเครื่องมือต่าง ๆ (สถานะ รายการงาน การยกเลิก)
งานต่าง ๆ ได้รับการติดตามโดย A2ATaskManager (src/lib/a2a/taskManager.ts, TTL เริ่มต้น 5 นาที) ส่วนสกิลต่าง ๆ จะถูกส่งต่อผ่าน A2A_SKILL_HANDLERS ใน src/lib/a2a/taskExecution.ts
curl http://localhost:20128/.well-known/agent.jsonส่งคืน Agent Card ที่อธิบายความสามารถ สกิล และข้อกำหนดด้านการตรวจสอบสิทธิ์ของ OmniRoute
ฟิลด์ version ของ Agent Card ดึงค่ามาจาก process.env.npm_package_version (ดู src/app/.well-known/agent.json/route.ts:13) จึงซิงค์กับ package.json โดยอัตโนมัติในทุกรีลีส
คำขอทั้งหมดไปยัง /a2a ต้องใช้คีย์ API ผ่านส่วนหัว Authorization:
Authorization: Bearer YOUR_OMNIROUTE_API_KEY
หากไม่มีการกำหนดค่าคีย์ API บนเซิร์ฟเวอร์ ระบบจะข้ามการตรวจสอบสิทธิ์
A2A ควบคุมด้วยสวิตช์ Endpoints → A2A และปิดใช้งานตามค่าเริ่มต้น เมื่อปิดใช้งาน
GET /api/a2a/status จะรายงาน status: "disabled" และ online: false; การเรียก JSON-RPC ไปยัง
POST /a2a จะส่งคืน HTTP 503 พร้อมรหัสข้อผิดพลาด JSON-RPC -32000
ส่งข้อความไปยังสกิลและรอการตอบกลับที่สมบูรณ์
curl -X POST http://localhost:20128/a2a \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_KEY" \
-d '{
"jsonrpc": "2.0",
"id": "1",
"method": "message/send",
"params": {
"skill": "smart-routing",
"messages": [{"role": "user", "content": "Write a hello world in Python"}],
"metadata": {"model": "auto", "combo": "fast-coding"}
}
}'การตอบกลับ:
{
"jsonrpc": "2.0",
"id": "1",
"result": {
"task": { "id": "uuid", "state": "completed" },
"artifacts": [{ "type": "text", "content": "..." }],
"metadata": {
"routing_explanation": "Selected claude-sonnet via provider \"anthropic\" (latency: 1200ms, cost: $0.003)",
"cost_envelope": {
"estimated": 0.005,
"actual": 0.003,
"currency": "USD"
},
"resilience_trace": [
{
"event": "primary_selected",
"provider": "anthropic",
"timestamp": "..."
}
],
"policy_verdict": {
"allowed": true,
"reason": "within budget and quota limits"
}
}
}
}ทำงานเหมือนกับ message/send แต่ส่งคืน Server-Sent Events สำหรับการสตรีมแบบเรียลไทม์
curl -N -X POST http://localhost:20128/a2a \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_KEY" \
-d '{
"jsonrpc": "2.0",
"id": "1",
"method": "message/stream",
"params": {
"skill": "smart-routing",
"messages": [{"role": "user", "content": "Explain quantum computing"}]
}
}'อีเวนต์ SSE:
data: {"jsonrpc":"2.0","method":"message/stream","params":{"task":{"id":"...","state":"working"},"chunk":{"type":"text","content":"..."}}}
: heartbeat 2026-03-03T17:00:00Z
data: {"jsonrpc":"2.0","method":"message/stream","params":{"task":{"id":"...","state":"completed"},"metadata":{...}}}
curl -X POST http://localhost:20128/a2a \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_KEY" \
-d '{"jsonrpc":"2.0","id":"2","method":"tasks/get","params":{"taskId":"TASK_UUID"}}'curl -X POST http://localhost:20128/a2a \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_KEY" \
-d '{"jsonrpc":"2.0","id":"3","method":"tasks/cancel","params":{"taskId":"TASK_UUID"}}'OmniRoute เปิดให้ใช้งานทักษะ A2A จำนวน 6 รายการที่เชื่อมโยงไว้ใน src/lib/a2a/taskExecution.ts::A2A_SKILL_HANDLERS โดยโมดูลของแต่ละทักษะอยู่ใน src/lib/a2a/skills/
| ทักษะ | ID | คำอธิบาย | แท็ก | ตัวอย่าง |
|---|---|---|---|---|
| การกำหนดเส้นทางอัจฉริยะ | smart-routing |
กำหนดเส้นทางพรอมต์ผ่านผู้ให้บริการ/ชุดค่าผสมที่เหมาะสมที่สุดโดยใช้กลไกชุดค่าผสมและการให้คะแนนของ OmniRoute | การกำหนดเส้นทาง, ผู้ให้บริการ | "กำหนดเส้นทางพรอมต์นี้ผ่านโมเดลที่ดีที่สุด" |
| การจัดการโควตา | quota-management |
รายงานสถานะโควตาของผู้ให้บริการแต่ละราย และช่วยผู้เรียกตัดสินใจว่าควรจำกัดอัตรา/สลับผู้ให้บริการเมื่อใด | โควตา, ผู้ให้บริการ | "ตรวจสอบโควตาสำหรับ anthropic" |
| การค้นหาผู้ให้บริการ | provider-discovery |
แสดงรายการผู้ให้บริการที่ติดตั้งไว้ พร้อมความสามารถ สถานะระดับฟรี และสถานะ OAuth | ผู้ให้บริการ, การค้นหา | "มีผู้ให้บริการใดพร้อมใช้งานบ้าง?" |
| การวิเคราะห์ต้นทุน | cost-analysis |
ประมาณการต้นทุนของคำขอ/การสนทนาโดยอ้างอิงจากแค็ตตาล็อกและการใช้งานล่าสุด | ต้นทุน, การใช้งาน | "ประมาณการต้นทุนสำหรับการสนทนานี้" |
| รายงานสถานภาพ | health-report |
รวบรวมสถานะเซอร์กิตเบรกเกอร์ คูลดาวน์ และการล็อกเอาต์ของผู้ให้บริการแต่ละราย | สถานภาพ, ความทนทาน | "แสดงสถานะความพร้อมใช้งานของผู้ให้บริการทั้งหมด" |
| แสดงรายการความสามารถ | list-capabilities |
ส่งคืนแค็ตตาล็อก Agent Skills แบบเต็มจำนวน 45 รายการ (API 23 รายการ + CLI 21 รายการ + การกำหนดค่า 1 รายการ) เป็นตารางมาร์กดาวน์ พร้อม URL ดิบของ SKILL.md สำหรับการแทรกบริบท | แค็ตตาล็อก, การค้นหา, ทักษะ | "แสดงความสามารถทั้งหมดของ OmniRoute" |
ควรรักษา Agent Card ให้สอดคล้องกับแค็ตตาล็อกผู้ให้บริการจริงจำนวน 352 ราย โดยจำนวนผู้ให้บริการและเมทาดาทาเกี่ยวกับการใช้งานฟรี/ไม่ต้องยืนยันตัวตนมีที่มาจากรีจิสทรีขณะรันไทม์
ทักษะ list-capabilities มีประโยชน์เป็นพิเศษสำหรับเอเจนต์ภายนอกที่ต้องการค้นหาว่า OmniRoute เปิดให้ใช้งานอะไรบ้างก่อนส่งคำขอ API โดยจะส่งคืนอาร์ติแฟกต์ตารางมาร์กดาวน์ที่มีโครงสร้าง:
| ID | ชื่อ | หมวดหมู่ | ขอบเขต | เอนด์พอยต์/คำสั่ง | URL ดิบ |
| --- | --- | --- | --- | --- | --- |
| omni-auth | การยืนยันตัวตนและเซสชัน | api | auth | POST /api/auth/login, ... | https://raw.githubusercontent.com/... |
...
แต่ละแถวมีคอลัมน์ rawUrl เพื่อให้เอเจนต์สามารถดึงไฟล์ SKILL.md ฉบับเต็มได้ทันที ฟิลด์ metadata.totalSkills สอดคล้องกับขนาดของแค็ตตาล็อก (ปัจจุบันคือ 45) การนำไปใช้: src/lib/a2a/skills/listCapabilities.ts โปรดดูเพิ่มเติมที่ AGENT-SKILLS.md
ปลายทาง JSON-RPC /a2a คือจุดเข้าสู่ A2A หลัก ปลายทาง REST ด้านล่างให้การเข้าถึงเพิ่มเติมสำหรับแดชบอร์ดและเครื่องมือภายนอก:
| ปลายทาง | เมธอด | คำอธิบาย | การยืนยันตัวตน |
|---|---|---|---|
/api/a2a/status |
GET | สถานะเซิร์ฟเวอร์และสกิลที่ลงทะเบียนไว้ | (สาธารณะ) |
/api/a2a/tasks |
GET | แสดงรายการงานพร้อมตัวกรอง | การจัดการ |
/api/a2a/tasks/[id] |
GET | รับงานตาม ID | การจัดการ |
/api/a2a/tasks/[id]/cancel |
POST | ยกเลิกงานที่กำลังทำงานอยู่ | การจัดการ |
/.well-known/agent.json |
GET | Agent Card (การค้นหา A2A) | (สาธารณะ, แคช 3600s) |
/api/a2a/tasks |
POST | การมอบหมายงานขาเข้าให้กับฟลีต OmniConductor (Conductor PRD RF5) | Bearer เทียบกับ OMNIROUTE_API_KEY + a2aEnabled |
การมอบหมายงาน Conductor ขาเข้า (POST /api/a2a/tasks): เอเจนต์ A2A ภายนอกมอบหมายงานเขียนโค้ดให้กับฟลีต OmniConductor ผ่าน OmniRoute เนื้อหาคำขอ: { skill: "conductor" | "conductor-cli-<profile>", messages: [{role, content}], metadata: { conductor: { repo: { url, base_ref? }, mode?, cli?, model? } } } — มอบหมายได้เฉพาะสกิลของฟลีต Conductor (สกิลที่ประกาศไว้ใน Agent Card) เท่านั้น; จำเป็นต้องระบุ metadata.conductor.repo.url (ฟลีตทำงานกับรีโพ git) เส้นทางนี้จะแปลงเป็น POST /v1/tasks ของฮับโดยใช้ CONDUCTOR_ORCHESTRATOR_TOKEN ฝั่งเซิร์ฟเวอร์ (สำรองด้วย CONDUCTOR_HUB_TOKEN) และส่งคืน 201 { conductor_task_id, state: "submitted" }; สถานะงานจะไหลกลับผ่านมิเรอร์ SSE→A2A (RF1) และดูได้ผ่าน GET /api/a2a/tasks?skill=conductor
-
สร้างไฟล์สกิล:
src/lib/a2a/skills/<your-skill>.tsส่งออกฟังก์ชัน async
(task: A2ATask) => Promise<{ artifacts, metadata }>ให้เป็นไปตามโครงสร้างของสกิลที่มีอยู่ เช่นsmartRouting.ts -
ลงทะเบียนแฮนด์เลอร์: ใน
src/lib/a2a/taskExecution.tsให้เพิ่มรายการลงในA2A_SKILL_HANDLERS:export const A2A_SKILL_HANDLERS = { // ...สกิลที่มีอยู่ "your-skill": async (task) => { const skillModule = await import("./skills/yourSkill"); return skillModule.executeYourSkill(task); }, };
-
แสดงใน Agent Card: ใน
src/app/.well-known/agent.json/route.tsให้เพิ่มต่อท้ายอาร์เรย์skills:{ "id": "your-skill", "name": "สกิลของคุณ", "description": "คำอธิบายสั้น ๆ ที่มุ่งเน้นเจตนา", "tags": ["การกำหนดเส้นทาง", "โควตา"], "examples": ["ตัวอย่างการเรียกใช้ด้วยภาษาธรรมชาติ"] } -
เขียนการทดสอบ:
tests/unit/a2a-<your-skill>.test.tsให้ครอบคลุมทั้งกรณีสำเร็จ + กรณีข้อผิดพลาด -
จัดทำเอกสาร สำหรับสกิลใหม่ในตาราง
Available Skillsของไฟล์นี้
งานจะหมดอายุหลังจาก ttlMinutes (ค่าเริ่มต้น 5 นาที) — กำหนดค่าใน constructor ของ A2ATaskManager ที่ src/lib/a2a/taskManager.ts:82 หากต้องการปรับแต่ง ให้ fork การสร้างอินสแตนซ์ A2ATaskManager และส่งค่าอื่นเข้าไป (เช่น new A2ATaskManager(15) สำหรับ TTL 15 นาที) โดย interval ที่ทำงานเบื้องหลังจะตรวจสอบและกวาดงานที่หมดอายุทุก 60 วินาที
ส่งแล้ว → กำลังทำงาน → เสร็จสมบูรณ์
→ ล้มเหลว
→ ยกเลิกแล้ว
- โดยค่าเริ่มต้น งานจะหมดอายุหลังจาก 5 นาที (ดู TTL ของงาน)
- สถานะสิ้นสุด:
completed,failed,cancelled - บันทึกเหตุการณ์จะติดตามการเปลี่ยนสถานะทุกครั้ง
| รหัส | ความหมาย |
|---|---|
| -32700 | ข้อผิดพลาดในการแยกวิเคราะห์ (JSON ไม่ถูกต้อง) |
| -32600 | คำขอไม่ถูกต้อง / ไม่ได้รับอนุญาต |
| -32601 | ไม่พบเมธอดหรือทักษะ |
| -32602 | พารามิเตอร์ไม่ถูกต้อง |
| -32603 | ข้อผิดพลาดภายใน |
| -32000 | ปิดใช้งาน endpoint A2A |
import requests
resp = requests.post("http://localhost:20128/a2a", json={
"jsonrpc": "2.0", "id": "1",
"method": "message/send",
"params": {
"skill": "smart-routing",
"messages": [{"role": "user", "content": "Hello"}]
}
}, headers={"Authorization": "Bearer YOUR_KEY"})
result = resp.json()["result"]
print(result["artifacts"][0]["content"])
print(result["metadata"]["routing_explanation"])const resp = await fetch("http://localhost:20128/a2a", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer YOUR_KEY",
},
body: JSON.stringify({
jsonrpc: "2.0",
id: "1",
method: "message/send",
params: {
skill: "smart-routing",
messages: [{ role: "user", content: "Hello" }],
},
}),
});
const { result } = await resp.json();
console.log(result.metadata.routing_explanation);