ci: fix sonarqube config and test suite failures

This commit is contained in:
diegosouzapw 2026-04-06 18:11:09 -03:00
parent 34bcb2b609
commit 5085dcf96f
138 changed files with 23558 additions and 33981 deletions

View file

@ -4,13 +4,9 @@
---
> **Agent-to-Agent Protocol v0.3** — Enables any AI agent to use OmniRoute as an intelligent routing agent via JSON-RPC 2.0.
> **Agent-to-Agent Protocol v0.3**— يتزايد أي وكيل AI من استخدام OmniRoute كوكيل توجيه ذكي عبر JSON-RPC 2.0.
The A2A Server exposes OmniRoute as a **first-class agent** that other agents can discover, delegate tasks to, and collaborate with using the [A2A Protocol](https://google.github.io/A2A/).
---
## الهندسة
يعرض مضيف A2A OmniRoute**وكيلًا من الدرجة الأولى**يمكن لوكلاء الاكتشافات الأخرى وطلب الاتصال به باستخدام [بروتوكول A2A](https://google.github.io/A2A/).---## الهندسة
```
┌──────────────────────────────────────────────────────────────────┐
@ -43,52 +39,48 @@ The A2A Server exposes OmniRoute as a **first-class agent** that other agents ca
### Agent Discovery
Every A2A-compatible agent exposes an **Agent Card** at `/.well-known/agent.json`:
يعرض كل وكيل متوافق مع A2A**بطاقة الوكيل**على `/.well-known/agent.json`:`bash
حليقة http://localhost:20128/.well-known/agent.json`
```bash
curl http://localhost:20128/.well-known/agent.json
```
**Response:**
```json
**إجابة:**```json
{
"name": "OmniRoute",
"description": "Intelligent AI gateway with auto-routing across 50+ providers",
"url": "http://localhost:20128/a2a",
"version": "1.8.1",
"capabilities": {
"streaming": true,
"pushNotifications": false
},
"skills": [
{
"id": "smart-routing",
"name": "Smart Routing",
"description": "Routes prompts through OmniRoute intelligent pipeline",
"tags": ["routing", "llm", "multi-provider", "cost-optimization"],
"examples": [
"Write a hello world in Python",
"Explain quantum computing using the cheapest provider"
]
},
{
"id": "quota-management",
"name": "Quota Management",
"description": "Natural-language queries about provider quotas",
"tags": ["quota", "analytics", "cost"],
"examples": [
"Which provider has the most quota remaining?",
"Suggest a free combo for coding"
]
}
],
"authentication": {
"schemes": ["bearer"],
"apiKeyHeader": "Authorization"
}
"name": "OmniRoute",
"description": "Intelligent AI gateway with auto-routing across 50+ providers",
"url": "http://localhost:20128/a2a",
"version": "1.8.1",
"capabilities": {
"streaming": true,
"pushNotifications": false
},
"skills": [
{
"id": "smart-routing",
"name": "Smart Routing",
"description": "Routes prompts through OmniRoute intelligent pipeline",
"tags": ["routing", "llm", "multi-provider", "cost-optimization"],
"examples": [
"Write a hello world in Python",
"Explain quantum computing using the cheapest provider"
]
},
{
"id": "quota-management",
"name": "Quota Management",
"description": "Natural-language queries about provider quotas",
"tags": ["quota", "analytics", "cost"],
"examples": [
"Which provider has the most quota remaining?",
"Suggest a free combo for coding"
]
}
```
],
"authentication": {
"schemes": ["bearer"],
"apiKeyHeader": "Authorization"
}
}
````
---
@ -96,27 +88,22 @@ curl http://localhost:20128/.well-known/agent.json
### `message/send` — Synchronous Execution
Send a message to a skill and receive the complete response.
```bash
curl -X POST http://localhost:20128/a2a \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_KEY" \
-d '{
أرسل رسالة إلى إحدى المهارات واحصل على الرد الكامل.```bash
حليقة -X POST http://localhost:20128/a2a \
-H "نوع المحتوى: application/json" \
-H "التفويض: حامل YOUR_KEY" \
-د '{
"jsonrpc": "2.0",
"id": "1",
"method": "message/send",
"params": {
"skill": "smart-routing",
"messages": [{"role": "user", "content": "Write a Python hello world"}],
"metadata": {"model": "auto", "combo": "fast-coding"}
"المعرف": "1"،
"الطريقة": "رسالة/إرسال"،
"المعلمات": {
"المهارة": "التوجيه الذكي"،
"messages": [{"role": "user", "content": "اكتب عالم بايثون المرحب"}],
"بيانات التعريف": {"model": "auto"، "combo": "الترميز السريع"}
}
}'
```
}'```
**Response:**
```json
**إجابة:**```json
{
"jsonrpc": "2.0",
"id": "1",
@ -133,36 +120,32 @@ curl -X POST http://localhost:20128/a2a \
}
}
}
```
````
### `message/stream` — SSE Streaming
Same as `message/send` but returns Server-Sent Events for real-time streaming.
```bash
curl -N -X POST http://localhost:20128/a2a \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_KEY" \
-d '{
نفس `الرسالة/الإرسال` ولكنها تُرجع الأحداث المرسلة من العميل للبث في الوقت الحقيقي.`bash
حليقة -N -X POST http://localhost:20128/a2a \
-H "نوع المحتوى: application/json" \
-H "التفويض: حامل YOUR_KEY" \
-د '{
"jsonrpc": "2.0",
"id": "1",
"method": "message/stream",
"params": {
"skill": "smart-routing",
"messages": [{"role": "user", "content": "Explain quantum computing"}]
"المعرف": "1"،
"الطريقة": "رسالة/دفق"،
"المعلمات": {
"المهارة": "التوجيه الذكي"،
"messages": [{"role": "user", "content": "شرح الحوسبة الكمومية"}]
}
}'
```
}'`
**SSE Events:**
```
**أحداث SSE:**```
data: {"jsonrpc":"2.0","method":"message/stream","params":{"task":{"id":"...","state":"working"},"chunk":{"type":"text","content":"Quantum computing..."}}}
: heartbeat 2026-03-04T21:00:00Z
data: {"jsonrpc":"2.0","method":"message/stream","params":{"task":{"id":"...","state":"completed"},"metadata":{...}}}
```
````
### `tasks/get` — Query Task Status
@ -171,7 +154,7 @@ 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"}}'
```
````
### `tasks/cancel` — Cancel a Running Task
@ -188,42 +171,36 @@ curl -X POST http://localhost:20128/a2a \
### `smart-routing`
Routes prompts through OmniRoute's intelligent pipeline with full observability.
تطالب المسارات عبر خط الأنابيب OmniRoute الذكي مع إمكانية المراقبة الكاملة.
**Parameters (in `metadata`):**
**المعلمات (في `البيانات الوصفية`):**
| Parameter | Type | Default | Description |
| --------- | -------- | ------------ | ---------------------------------------------------------------------------------------- |
| `model` | `string` | `"auto"` | Target model (e.g., `claude-sonnet-4`, `gpt-4o`, `auto`) |
| `combo` | `string` | active combo | Specific combo to route through |
| `budget` | `number` | none | Maximum cost in USD for this request |
| `role` | `string` | none | Task role hint: `coding`, `review`, `planning`, `analysis`, `debugging`, `documentation` |
| المعلمة | اكتب | افتراضي | الوصف |
| ---------------- | --------- | ------------------ | ----------------------------------------------------------------------------- |
| `نموذج` | "السلسلة" | `"تلقائي"` | النموذج المستهدف (على سبيل المثال، `clude-sonnet-4`، `gpt-4o`، `auto`) |
| `التحرير والسرد` | "السلسلة" | التحرير والسرد لكم | التحرير والسرد للتوجيه من خلال |
| `الميزانية` | `الرقم` | لا شيء | الحد الأقصى للتكلفة بالدولار الأمريكي هذا الطلب |
| `دور` | "السلسلة" | لا شيء | تلميح مهم: `التميز`، `المراجعة`، `التخطيط`، `التحليل`، `تصحيح سبب`، `التوثيق` |
**Returns:**
**المرتجعات:**
| Field | Description |
| ------------------------------ | --------------------------------------------------------- |
| `artifacts[].content` | The LLM response text |
| `metadata.routing_explanation` | Human-readable explanation of routing decision |
| `metadata.cost_envelope` | Estimated vs actual cost with currency |
| `metadata.resilience_trace` | Array of events (primary_selected, fallback_needed, etc.) |
| `metadata.policy_verdict` | Whether the request was allowed and why |
| | الوصف |
| ------------------------------ | ------------------------------------------------------------------------ | ----------------- |
| `المصنوعات[].content` | نصرد LLM |
| `metadata.routing_explanation` | شرح مفهوم لقرار التوجيه |
| `metadata.cost_envelope` | التكلفة المقدرة مقابل تكلفة التكلفة للعملة |
| `metadata.resilience_trace` | مصفوفة من الأحداث (تم تحديدها بشكل أساسي، والمطلوبة بديلاً، وما إلى ذلك) |
| `metadata.policy_verdict` | ما إذا كان ائداً لها لسبب | ### `إدارة الحصص` |
### `quota-management`
يجيب على استفسارات اللغة الطبيعية حول حصص الموفرين.
Answers natural-language queries about provider quotas.
**أنواع اتفق (المنتهية من محتوى الرسالة):**
**Query types (inferred from message content):**
| Query Pattern | Response Type |
| ---------------------------------------------- | -------------------------------------------------------- |
| Contains `"ranking"`, `"most quota"`, `"best"` | Providers ranked by remaining quota |
| Contains `"free"`, `"suggest"` | Lists free combos or suggests free-tier providers |
| Default | Full quota summary with warnings for low-quota providers |
---
## Task Lifecycle
| نمط | نوع المصدر |
| ------------------------------------------------- | ----------------------------------------- | -------------------- |
| يحتوي على `"التصنيف"`، `"الأكثر حصة"`، `"الأفضل"` | تم ترتيب مقدمي الخدمة حسب الحصص النهائية |
| يحتوي على `"مجاني"`، `"اقتراح"` | يسرد المهرجانات أو المهرجانات المجانية |
| افتراضي | ملخص كامل للحصص مع تحذيرات للحصص المنخفضة | ---## Task Lifecycle |
```
submitted ──→ working ──→ completed
@ -231,21 +208,17 @@ submitted ──→ working ──→ completed
──────────→ cancelled
```
| State | Description |
| ----------- | ----------------------------------------------------- |
| `submitted` | Task created, queued for execution |
| `working` | Skill handler is executing |
| `completed` | Execution succeeded, artifacts available |
| `failed` | Execution failed or task expired (TTL: 5 min default) |
| `cancelled` | Cancelled by client via `tasks/cancel` |
| الدولة | الوصف |
| -------- | ------------------------------------------------------------ |
| `مُقدم` | تم إنشاء المهمة، في قائمة الانتظار للتنفيذ |
| `العمل` | معالج المهارة ينفذ |
| `مكتملة` | البدء في التنفيذ، القطع الأثرية الصعبة |
| `فشل` | فشل التنفيذ أو النهاية إلى النهاية (TTL: 5 بالضغط الافتراضي) |
| `ملغاة` | تم الإلغاء من قبل العميل عبر `المهام/الإلغاء` |
- Terminal states: `completed`, `failed`, `cancelled` (no further transitions)
- Expired tasks in `submitted` or `working` are auto-marked as `failed`
- Tasks are garbage-collected after 2× TTL
---
## Client Examples
- حالات الوحدة الطرفية: `مكتملة`، `فشل`، `ملغى` (لم تحدث عمليات انتقال أخرى)
- يتم وضع العلامة التجارية الجديدة على انتهاء الصلاحية في "المقدمة" أو "الجاري" على أنها "فاشلة".
- يتم جمع المهام المهمة بعد 2 × TTL---## Client Examples
### Python — Orchestrator Agent
@ -541,40 +514,33 @@ func main() {
### 🤖 Use Case 1: Multi-Agent Coding Pipeline
An orchestrator agent delegates code generation to OmniRoute, then passes the output to a review agent.
يقوم وكيل منسق بتفويض إنشاء تعليمات الحظر إلى OmniRoute، ثم يقوم بتمرير الترخيص لوكيل التعديل.```python
تعريف coding_pipeline (المهمة: str): # الخطوة 1: قم بإنشاء الكود عبر OmniRoute A2A
code_result = a2a_send("التوجيه الذكي"، [
{"role": "user"، "content": f"اكتب كود جودة الإنتاج: {task}"}
]، البيانات الوصفية={"model": "auto"، "role": "coding"})
كود = code_result["artifacts"][0]["content"]
```python
def coding_pipeline(task: str):
# Step 1: Generate code via OmniRoute A2A
code_result = a2a_send("smart-routing", [
{"role": "user", "content": f"Write production-quality code: {task}"}
], metadata={"model": "auto", "role": "coding"})
code = code_result["artifacts"][0]["content"]
# الخطوة الثانية: قم بمراجعة الكود عبر OmniRoute A2A (نموذج مختلف)
review_result = a2a_send("التوجيه الذكي"، [
{"role": "user"، "content": f"راجع هذا الرمز بحثًا عن الأخطاء والتحسينات:\n\n{code}"}
]، البيانات الوصفية={"model": "auto"، "role": "review"})
المراجعة = review_result["artifacts"][0]["content"]
# Step 2: Review the code via OmniRoute A2A (different model)
review_result = a2a_send("smart-routing", [
{"role": "user", "content": f"Review this code for bugs and improvements:\n\n{code}"}
], metadata={"model": "auto", "role": "review"})
review = review_result["artifacts"][0]["content"]
# الخطوة 3: التحقق من التكاليف
print(f"تكلفة الكود: ${code_result['metadata']['cost_envelope']['actual']}")
print(f"تكلفة المراجعة: ${review_result['metadata']['cost_envelope']['actual']}")
# Step 3: Check costs
print(f"Code cost: ${code_result['metadata']['cost_envelope']['actual']}")
print(f"Review cost: ${review_result['metadata']['cost_envelope']['actual']}")
return {"code": code, "review": review}
```
إرجاع {"كود": كود، "مراجعة": مراجعة}```
### 💡 Use Case 2: Quota-Aware Agent Swarm
Multiple agents share quota through OmniRoute, using the quota skill to coordinate.
```python
async def quota_aware_agent(agent_name: str, task: str):
# Check quota before starting
quota = a2a_send("quota-management", [
{"role": "user", "content": "Which provider has the most quota remaining?"}
])
print(f"[{agent_name}] {quota['artifacts'][0]['content']}")
يقوم العديد من الوكلاء بمشاركة الحصص من خلال OmniRoute، وذلك باستخدام مهارة الحصص للتنسيق.```python
async def quota_aware_agent(agent_name: str, task: str): # Check quota before starting
quota = a2a_send("quota-management", [
{"role": "user", "content": "Which provider has the most quota remaining?"}
])
print(f"[{agent_name}] {quota['artifacts'][0]['content']}")
# Send request with budget constraint
result = a2a_send("smart-routing", [
@ -591,64 +557,60 @@ async def quota_aware_agent(agent_name: str, task: str):
print(f"[{agent_name}] Free alternatives: {quota['artifacts'][0]['content']}")
return result
```
````
### 📊 Use Case 3: Real-Time Streaming Dashboard
A monitoring agent streams responses and displays progress in real-time.
```typescript
async function streamingDashboard(prompt: string) {
const response = await fetch(`${BASE_URL}/a2a`, {
method: "POST",
headers: { "Content-Type": "application/json", Authorization: `Bearer ${API_KEY}` },
body: JSON.stringify({
jsonrpc: "2.0",
id: "dash-1",
method: "message/stream",
params: { skill: "smart-routing", messages: [{ role: "user", content: prompt }] },
يقوم بالمراقبة ببث الاستجابات ويعرض التقدم في الوقت الفعلي.```typescript
وظيفة غير متزامنة StreamDashboard(prompt: string) {
استجابة ثابتة = انتظار الجلب(`${BASE_URL}/a2a`, {
الطريقة: "POST"،
الرؤوس: { "نوع المحتوى": "application/json"، التفويض: `Bearer ${API_KEY}`
الجسم: JSON.stringify({
جسونربك: "2.0"،
المعرف: "داش-1"،
الطريقة: "رسالة/دفق"،
المعلمات: { المهارة: "التوجيه الذكي"، الرسائل: [{ الدور: "المستخدم"، المحتوى: موجه }] }،
}),
});
let totalChunks = 0;
const reader = response.body!.getReader();
دع مجموع القطع = 0؛
قارئ ثابت = استجابة. الجسم!.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
بينما (صحيح) {
const { تم، القيمة } = انتظار Reader.read();
إذا (تم) كسر؛
for (const line of decoder.decode(value).split("\n")) {
if (line.startsWith("data: ")) {
const event = JSON.parse(line.slice(6));
const state = event.params.task.state;
for (سطر ثابت من decoder.decode(value).split("\n")) {
إذا (line.startsWith("البيانات:")) {
حدث const = JSON.parse(line.slice(6));
حالة ثابتة = Event.params.task.state;
if (state === "working" && event.params.chunk) {
totalChunks++;
process.stdout.write(
`\r[Chunk ${totalChunks}] ${event.params.chunk.content.slice(0, 50)}...`
إذا (الحالة === "العمل" && events.params.chunk) {
TotalChunks++;
عملية.stdout.write(
`\r[قطعة ${totalChunks}] ${event.params.chunk.content.slice(0, 50)}...`
);
}
if (state === "completed") {
const meta = event.params.metadata;
إذا (الحالة === "مكتملة") {
const meta = events.params.metadata;
console.log(
`\n✅ Done | Cost: $${meta?.cost_envelope?.actual || 0} | Route: ${meta?.routing_explanation || "N/A"}`
`\n ✅ تم | التكلفة: $${meta?.cost_envelope?.actual || 0} | الطريق: ${meta?.routing_explanation || "غير متوفر"}`
);
}
if (state === "failed") {
إذا (الحالة === "فشل") {
console.error(`\n❌ Failed: ${event.params.metadata?.error}`);
}
}
}
}
}
```
}```
### 🔁 Use Case 4: Task Polling Pattern
For long-running tasks, poll the task status instead of waiting synchronously.
```python
بالنسبة للمهام طويلة الأمد، قم باستقصاء حالة المهمة بدلاً من الانتظار بشكل متزامن.```python
import time
def poll_task(task_id: str, timeout: int = 60):
@ -678,75 +640,64 @@ def poll_task(task_id: str, timeout: int = 60):
"params": {"taskId": task_id},
})
raise TimeoutError(f"Task {task_id} timed out after {timeout}s")
```
````
---
## Error Codes
| Code | Constant | Meaning |
| ------ | ------------------------ | ---------------------------------------- |
| -32700 | — | Parse error (invalid JSON) |
| -32600 | `INVALID_REQUEST` | Invalid JSON-RPC request or unauthorized |
| -32601 | `METHOD_NOT_FOUND` | Unknown method or skill |
| -32602 | `INVALID_PARAMS` | Missing or invalid parameters |
| -32603 | `INTERNAL_ERROR` | Skill execution failed |
| -32001 | `TASK_NOT_FOUND` | Task ID not found |
| -32002 | `TASK_ALREADY_COMPLETED` | Cannot modify a completed task |
| -32003 | `UNAUTHORIZED` | Invalid or missing API key |
| -32004 | `BUDGET_EXCEEDED` | Request exceeds configured budget |
| -32005 | `PROVIDER_UNAVAILABLE` | No available providers |
| الكود | ثابت | معنى |
| ------ | -------------------------- | --------------------------------- | -------------------- |
| -32700 | — | خطأ في التحليل (JSON غير صالح) |
| -32600 | `طلب_غير صالح` | طلب JSON-RPC غير صالح أو | غير مصرح به |
| -32601 | `METHOD_NOT_FOUND` | طريقة أو مهارة غير معروفة |
| -32602 | `INVALID_PARAMS` | معلمات مفقودة أو غير صالحة |
| -32603 | `خطأ_داخلي` | فشل في تنفيذ المهارة |
| -32001 | `مهمة_لم يتم العثور عليها` | لم يتم العثور على المفتاح الرئيسي |
| -32002 | `المهمة_الجاهزة_مكتملة` | لا يمكن تعديل مهمة مكتملة |
| -32003 | "غير مصرح به" | API الرئيسية غير صالحة أو مفقودة |
| -32004 | `الميزانية_تجاوزت` | التجاوز المدى المكمل |
| -32005 | `PROVIDER_UNAVAILABLE` | لا يوجد مقدمي خيارات الأسهم | ---## Authentication |
---
تتطلب جميع الطلبات `/a2a` رمزًا مميزًا لحاملها عبر الرأس `الإعلان`:`
التفويض: الحامل YOUR_OMNIROUTE_API_KEY`
## Authentication
All `/a2a` requests require a Bearer token via the `Authorization` header:
```
Authorization: Bearer YOUR_OMNIROUTE_API_KEY
```
If no API key is configured on the server (`OMNIROUTE_API_KEY` is empty), authentication is bypassed.
---
إذا لم يتم تكوين أي مفتاح API على الخادم (`OMNIROUTE_API_KEY` فارغ)، فسيتم تجاوز المصادقة.---
## File Structure
```
src/lib/a2a/
├── taskManager.ts # Task lifecycle (create/update/cancel/list), TTL, cleanup
├── taskExecution.ts # Generic task executor with state management
├── streaming.ts # SSE stream formatting, heartbeat, chunk/completion events
├── routingLogger.ts # Routing decision logger (stats, history, retention)
└── skills/
├── smartRouting.ts # Smart routing skill (routes via /v1/chat/completions)
└── quotaManagement.ts # Quota management skill (natural-language quota queries)
````
سرك/ليب/a2a/
├── TaskManager.ts # دورة حياة المهمة (إنشاء/تحديث/إلغاء/قائمة)، TTL، تنظيف
├── TaskExecution.ts # منفذ المهام العامة مع إدارة الحالة
├── Stream.ts # تنسيق دفق SSE، ونبضات القلب، وأحداث القطعة/الإكمال
├── routingLogger.ts # مسجل قرار التوجيه (الإحصائيات والتاريخ والاحتفاظ)
└── المهارات/
├── SmartRouting.ts # مهارة التوجيه الذكي (الطرق عبر /v1/chat/completions)
└── quotaManagement.ts # مهارة إدارة الحصص (استعلامات الحصص باللغة الطبيعية)
src/app/a2a/
└── route.ts # Next.js API route handler (JSON-RPC 2.0 dispatch)
سرك/التطبيق/a2a/
└── Route.ts # معالج مسار واجهة برمجة التطبيقات Next.js (إرسال JSON-RPC 2.0)
open-sse/mcp-server/
└── schemas/a2a.ts # Zod schemas (AgentCard, Task, JSON-RPC, SSE events)
```
مفتوح-SSE/MCP-خادم/
└── schemas/a2a.ts # مخططات Zod (AgentCard، Task، JSON-RPC، أحداث SSE)```
---
## Comparison: MCP vs A2A
| Feature | MCP Server | A2A Server |
| ميزة | خادم MCP | خادم A2A |
| ----------------- | ---------------------------- | ------------------------------------------------- |
| **Protocol** | Model Context Protocol | Agent-to-Agent Protocol v0.3 |
| **Transport** | stdio / HTTP | HTTP (JSON-RPC 2.0) |
| **Discovery** | Tool listing via MCP | `/.well-known/agent.json` |
| **Granularity** | 16 individual tools | 2 high-level skills |
| **Best for** | IDE agents (Cursor, VS Code) | Multi-agent systems (LangChain, CrewAI) |
| **Streaming** | Not supported | SSE via `message/stream` |
| **Task tracking** | No | Full lifecycle (submitted → completed) |
| **Observability** | Audit log per tool call | Cost envelope + resilience trace + policy verdict |
---
|**البروتوكول**| بروتوكول السياق النموذجي | بروتوكول وكيل إلى وكيل v0.3 |
|**النقل**| ستديو / HTTP | HTTP (JSON-RPC 2.0) |
|**الاكتشاف**| قائمة الأدوات عبر MCP | `/.well-known/agent.json` |
|**التفاصيل**| 16 أداة فردية | 2 مهارات عالية المستوى |
|**الأفضل لـ**| وكلاء IDE (المؤشر، كود VS) | أنظمة متعددة الوكلاء (LangChain، CrewAI) |
|**البث**| غير مدعوم | SSE عبر "الرسالة/الدفق" |
|**تتبع المهام**| لا | دورة حياة كاملة (مقدمة → مكتملة) |
|**الملاحظة**| سجل التدقيق لكل استدعاء أداة | مظروف التكلفة + تتبع المرونة + حكم السياسة |---
## الرخصة
Part of [OmniRoute](https://github.com/diegosouzapw/OmniRoute) — MIT License.
جزء من [OmniRoute](https://github.com/diegosouzapw/OmniRoute) - ترخيص معهد ماساتشوستس للتكنولوجيا.
````