> ## Documentation Index
> Fetch the complete documentation index at: https://lousho.com/llms.txt
> Use this file to discover all available pages before exploring further.

# المزوّدون

`LLMProvider` هو ما يولّد به الوكيل ردوده. تأتي الـ SDK بمزوّدين لـ OpenAI وAnthropic وOpenRouter وOllama (كل منهم يستند إلى حزمة نظيرة اختيارية، انظر [التثبيت](/ar/installation#حزم-المزوّدين)) وبمزوّد وهمي حتمي للاختبارات. حدِّد المزوّد بسلسلة نصية بصيغة `provider/model`، أو مرِّر كائن مزوّد (instance).

```ts theme={null}
import { resolveProvider, LLMProviderRegistry } from '@lousho/build-ai-agent';

// The convenient way — reads the credential from the environment
const openai = resolveProvider('openai/gpt-4o-mini');       // OPENAI_API_KEY
const anthropic = resolveProvider('anthropic/claude-sonnet-5'); // ANTHROPIC_API_KEY
const openrouter = resolveProvider('openrouter/openai/gpt-4o-mini'); // OPENROUTER_API_KEY
const ollama = resolveProvider('ollama/llama3.1');           // OLLAMA_BASE_URL

// Or construct a provider directly via the registry
const custom = LLMProviderRegistry.create('openai', {
  apiKey: process.env.OPENAI_API_KEY,
  defaultModel: 'gpt-4o-mini',
});
```

## اختيار المزوّد في `createAgent()`

يقبل `createAgent()` واحدًا فقط مما يلي:

1. **`model: 'provider/model'`** - يُحلّ بواسطة `resolveProvider()`؛ ويأتي المفتاح من متغير البيئة المتعارف عليه للمزوّد (انظر [بيانات اعتماد المزوّدين](/ar/configuration#بيانات-اعتماد-المزوّدين)).
2. **`provider: <LLMProvider>`** - مزوّدك الخاص، أو مزوّد مدمج مضبوط، أو مزوّد وهمي. يمكنك أيضًا تمرير `model` (معرّف مجرد مثل `'gpt-4o'`): فيصبح نموذج هذا الوكيل، ويتقدّم على النموذج الافتراضي للمزوّد.
3. **لا هذا ولا ذاك** - يُحلّ من البيئة: `LOUSHO_MODEL` (سلسلة `provider/model`) إن كان مضبوطًا، وإلا فأول الموجود من `OPENAI_API_KEY` و`ANTHROPIC_API_KEY` و`OPENROUTER_API_KEY` و`OLLAMA_BASE_URL`. وإذا لم يكن أي منها مضبوطًا رمى خطأً يسرد الحلول.

```ts theme={null}
import { createAgent, createMockProvider, resolveProvider } from '@lousho/build-ai-agent';

const fromString = createAgent({ model: 'anthropic/claude-sonnet-5' });
const fromInstance = createAgent({ provider: resolveProvider('openai/gpt-4o-mini'), model: 'gpt-4o' });
const offline = createAgent({ provider: createMockProvider({ responses: ['Hi! How can I help?'] }) });
```

أخطاء سوء الإعداد تبيّن طريقة إصلاحها: المفتاح الناقص يُذكر معه اسم المتغير، والبادئة غير المعروفة تُسرد معها البادئات المدعومة ويُقترح أقربها، والحزمة النظيرة الناقصة يُطبع معها أمر `npm install` الدقيق.

### إعادة المحاولة والنماذج الاحتياطية

يعيد `createAgent()` محاولة استدعاء النموذج الفاشل (تجاوز حدّ المعدّل، انتهاء المهلة، خطأ شبكة، خطأ 5xx) مرتين افتراضيًا، ومع `fallbackModels` ينتقل إلى النموذج التالي حين يستمر فشل الاستدعاء:

```ts theme={null}
import { createAgent } from '@lousho/build-ai-agent';

const agent = createAgent({
  model: 'openai/gpt-4o-mini',
  retry: { maxRetries: 3 }, // or false
  fallbackModels: ['anthropic/claude-3-5-haiku-latest', 'openrouter/meta-llama/llama-3.1-70b-instruct'],
});
```

تُحلّ سلسلة `model` وكل نموذج احتياطي مع تعطيل إعادة المحاولة الخاصة بحزمة `ai`، فتكون `retry` طبقة إعادة المحاولة الوحيدة. أما كائن `provider` فلا يُغلَّف إلا حين تضبط `retry`. يبلّغ `agent.stream()` عن الحدثين `provider.retry` و`provider.fallback`. التفاصيل في [إعادة المحاولة والبديل الاحتياطي للمزوّد](/ar/configuration#إعادة-المحاولة-والبديل-الاحتياطي-لدى-المزوّد).

## أي نموذج يعمل؟

بالترتيب: `settings.model` الخاص بالوكيل (يُضبط بـ `AgentBuilder.setSettings({ model })`، أو بـ `model` إلى جانب `provider` في `createAgent()`)، ثم النموذج الذي بُني به المزوّد (`resolveProvider('openai/gpt-4o-mini')`، أو `provider.model` في ملف مواصفات، أو `defaultModel`)، ثم النموذج الافتراضي المدمج في المزوّد. لا يوجد نموذج احتياطي مثبَّت في الشيفرة.

## الإدخال متعدد الوسائط

`Message.content` سلسلة نصية أو قائمة أجزاء: `{ type: 'text', text }`، و`{ type: 'image', image, mimeType? }` (عنوان `http(s)`، أو عنوان `data:`، أو البايتات على هيئة `Uint8Array`) و`{ type: 'file', data, mimeType, filename? }`. تقبل `agent.send()` و`agent.stream()` و`session.send()` / `stream()` و`t.send()` في التقييمات و`send()` في خطّاف React كلها قيمة من نوع `AgentInput`: سلسلة نصية، أو قائمة أجزاء (تُرسَل كرسالة مستخدم واحدة)، أو `Message[]` (تُمرَّر كما هي). ويقبل `AgentExecutor.execute()` الرسائل نفسها في `input`:

```ts theme={null}
import { readFileSync } from 'node:fs';
import { AgentBuilder, AgentExecutor, createAgent, resolveProvider, textOf, type Message } from '@lousho/build-ai-agent';

const agent = AgentBuilder.create().setName('vision').setPrompt('Describe images briefly.').build();
const input: Message[] = [
  {
    role: 'user',
    content: [
      { type: 'text', text: 'What is in these pictures?' },
      { type: 'image', image: 'https://example.com/cat.png' },
      { type: 'image', image: new Uint8Array(readFileSync('dog.png')), mimeType: 'image/png' },
    ],
  },
];

const result = await AgentExecutor.execute({ agent, input, provider: resolveProvider('openai/gpt-4o-mini') });
console.log(textOf(input[0]), '->', result.text); // textOf(): the text parts of a message

// The same through the public API: parts become one user message.
const answer = await createAgent({ prompt: 'Describe images briefly.', model: 'openai/gpt-4o-mini' }).send([
  { type: 'text', text: 'What is in this picture?' },
  { type: 'image', image: 'https://example.com/cat.png' },
]);
console.log(answer.text);
```

* **الصور** تصل إلى النموذج ضمن رسائل `user` مع كل المزوّدين المدمجين (مع Anthropic وOllama تنزّل حزمة `ai` الصورة من عنوانها أولًا). اختر نموذجًا يدعم الرؤية: Ollama يتجاهل الصور مع نموذج نصي فقط، وOpenRouter يرفضها معه.
* **الملفات** لا يرسلها المزوّدون المدمجون، على أي إصدار رئيسي من `ai`: يُرسَل جزء الملف كملاحظة نصية (`[file report.pdf (application/pdf) not sent]`) ويحذّر المزوّد مرة واحدة. الصنف الفرعي من مزوّد يقبل نموذجه الملفات يضبط `protected readonly acceptsFileParts = true` ليرسلها كأجزاء ملفات بصيغة `ai` v4.
* رسائل `system` و`assistant` و`tool` تُرسَل بأجزائها النصية.
* كل ما يقرأ نص الرسائل يستخدم `textOf()`: `estimateTokens()` (يُحتسب كل جزء صورة أو ملف 1,000 رمز ثابتة)، وضغط السياق، وأشرطة تسجيل `recordReplay()` (التي تخزّن النص وبصمة كل صورة أو ملف، أو عنوانه) و`mockModel()`. يحفظ `FileSessionStore` البايتات بترميز base64 (`{ "$bytes": "..." }`) ويعيد تحميلها على هيئة `Uint8Array`؛ ويفعل `SqliteStore` (للجلسات ونقاط الحفظ) الشيء نفسه.

## أصناف المزوّدين

| التصدير | الوصف |
| - | - |
| `resolveProvider('p/model')` | يبني مزوّدًا حقيقيًا من بيانات الاعتماد في البيئة. |
| `LLMProviderRegistry` | سجل مصانع المزوّدين: `create(type, config)`، `register(type, factory)`، `has(type)`. |
| `OpenAIProvider`, `AnthropicProvider`, `OllamaProvider`, `OpenRouterProvider` | أصناف المزوّدين. انظر [examples/openrouter](https://github.com/LinuxDevil/agent-sdk/blob/main/examples/openrouter) للميزات الخاصة بـ OpenRouter. |
| `createMockProvider()`, `MockLLMProvider` | ردود جاهزة للعروض التوضيحية؛ يحاكي استدعاء أداة حين تذكر الرسالة اسم أداة. |
| `mockModel(script)` | مزوّد للاختبارات يتبع نصًّا معدًّا مسبقًا ويتحقق منه (من `/testing`)؛ انظر [الاختبار](/ar/testing). |
| `withRetry()`, `withFallback()` | يعيدان محاولة الإخفاقات العابرة مع تراجع زمني، وينتقلان إلى المزوّد التالي؛ انظر [إعادة المحاولة والبديل الاحتياطي للمزوّد](/ar/configuration#إعادة-المحاولة-والبديل-الاحتياطي-لدى-المزوّد). |

لاستخدام خدمة خلفية أخرى، نفّذ الواجهة `LLMProvider` (`name` و`generate()` و`stream()` و`supportsTools()` و`supportsStreaming()` و`getModels()`، واختياريًا `defaultModel`) ومرِّر الكائن بوصفه `provider`، أو سجّل مصنعًا بـ `LLMProviderRegistry.register(name, factory)`.

## إصدارات Vercel AI SDK

المزوّدون المدمجون مهايئات فوق Vercel AI SDK (`ai`). ما يعمل اليوم على كل إصدار رئيسي:

| `ai` | `generate()` | `stream()` | ملاحظات |
| - | - | - | - |
| v4 (`^4.3.19`) | نعم | نعم | كل ما في هذه الوثائق. |
| v6 (`^6.0.0`), v7 (`^7.0.0`) | نعم، عبر طبقة توافق | نعم، عبر الطبقة نفسها | Ollama يحتاج إلى تثبيت zod 4 (أدناه). |

نطاقات الاعتماديات النظيرة تقبل الإصدارات الرئيسية الثلاثة. قرِن كلًّا منها بحزم المزوّدين المناسبة له:

| `ai` | `@ai-sdk/openai`, `@ai-sdk/anthropic` | حزمة Ollama |
| - | - | - |
| `^4.3.19` | `^0.0.42` أو `^1.0.0` | `ollama-ai-provider@^1.2.0` |
| `^6.0.0` | `^3.0.0` | `ollama-ai-provider-v2@^3.0.0` |
| `^7.0.0` | `^4.0.0` | `ollama-ai-provider-v2@^4.0.0` |

تلميح التثبيت لحزمة مزوّد ناقصة و`lousho doctor` يذكران الإصدار المناسب لنسخة `ai` المثبَّتة لديك، وينبّه `lousho doctor` إلى الزوج غير المتوافق (مثلًا `ai` 7 مع `@ai-sdk/openai` 1.x). يحمّل `OllamaProvider` الحزمة `ollama-ai-provider` على `ai` 4 والحزمة `ollama-ai-provider-v2` على `ai` 6/7؛ وحزمة v2 تعتمد اعتمادًا نظيرًا على zod 4، وهو ما تقبله الـ SDK، فثبّت zod 4 معها (مشاريع zod 3 تستخدم Ollama مع `ai` 4). ينشئ `lousho init` هيكل المشروع بـ `ai@^7.0.0` مع `@ai-sdk/*@^4.0.0` لـ OpenAI وAnthropic وOpenRouter، وبـ `ai@^4.3.19` لـ Ollama.

يستخدم OpenRouter الحزمة `@ai-sdk/openai` موجَّهة إلى عنوان OpenRouter الأساسي. ابتداءً من `@ai-sdk/openai` 2، يستهدف الاستدعاء الافتراضي `openai(modelId)` واجهة Responses API، التي لا ينفّذها OpenRouter، ولذلك يطلب `OpenRouterProvider` نموذج Chat Completions (`provider.chat(modelId)`) على كل إصدار رئيسي؛ وهو يعمل على `ai` 4 و6 و7 مع الاقتران المذكور أعلاه.

يأخذ `OllamaProvider` عنوان الخادم الأساسي (`baseURL`، أو `OLLAMA_BASE_URL` في حالة `resolveProvider()`) ويُلحق `/api` بالمضيف المجرد، كما تتوقعه حزمتا Ollama كلتاهما: `http://host:11434` و`http://host:11434/` يصبحان `http://host:11434/api`. العنوان الذي ينتهي أصلًا بـ `/api` (أو `/api/`)، أو فيه أي مسار آخر مثل بادئة وكيل عكسي، يُستخدم كما هو.

يختار `generate()` و`stream()` شكل الاستدعاء بحسب وحدة `ai` المثبَّتة: حين تصدّر `stepCountIs` (الإصدار v5 وما بعده)، يُرسَل الطلب بشكل v6/v7 وتُقرأ النتيجة وتُحوَّل إلى `GenerateResult` أو `StreamResult` نفسيهما:

* تتحوّل الرسائل إلى كائنات `ModelMessage`: وسائط استدعاء الأداة تصبح `input` الخاص به، ونتيجة الأداة تصبح `output` (`json` أو `text`، و`error-json` أو `error-text` حين تفشل الأداة)، و`mimeType` في جزء الصورة أو الملف يصبح `mediaType`. تبقى رسائل النظام في مواضعها (`allowSystemInMessages`).
* يُرسَل `maxTokens` باسم `maxOutputTokens`، والخطوة الواحدة بالشكل `stopWhen: stepCountIs(1)`، والأدوات باسم `inputSchema` (مخطط zod كما هو، ومخطط JSON Schema عبر `jsonSchema()`) دون `execute`، و`responseFormat` على هيئة `output` بوضع JSON لا يمسّ نص الرد.
* يأتي الاستهلاك من `inputTokens` / `outputTokens` / `totalTokens`، مع `cachedInputTokens` من `inputTokenDetails.cacheReadTokens` و`reasoningTokens` من `outputTokenDetails.reasoningTokens`.
* يقرأ `stream()` المجرى `fullStream` الخاص بـ AI SDK على أي من الإصدارين الرئيسيين ويحوّله إلى القطع (chunks) نفسها: `text-delta` (في v6/v7 الحقل `text`، وفي v4 الحقل `textDelta`)، و`tool-call` (الاستدعاء الكامل الذي يرسله v6/v7 بعد `tool-input-start`/`-delta`/`-end`، أو استدعاء يُجمَّع من ذلك الإدخال حين لا يرسل النموذج استدعاءً كاملًا)، و`finish` مع سبب الانتهاء الذي تعطيه AI SDK والاستهلاك المذكور أعلاه (في v6/v7 الحقل `totalUsage`). جزء `error` يجعل المجرى يُرفض بخطئه، على v4 أيضًا (كان v4 ينهي مجرى كهذا بسبب الانتهاء `error`)، وجزء `abort` يرفضه بسبب الإشارة. تغيّرات الاستدلال الجزئية (deltas) يُبلَّغ عنها قطعًا من النوع `reasoning-delta` وتظهر أحداثًا `reasoning.*` (انظر [الاستدلال](/ar/reasoning)).

على v6/v7 يجب أن يأتي النموذج من حزمة مزوّد خاصة بذلك الإصدار الرئيسي (الجدول أعلاه)؛ فحزم `0.0.x`/`1.x` تنتج نماذج يرفضها `ai` v7. تُرسَل أجزاء الصور كأجزاء `image`، وهي ما يقبله `ai` v7 مع تحذير إهمال لكل جزء (`globalThis.AI_SDK_LOG_WARNINGS = false` يوقف تحذيرات `ai`). الإصدار `ai` v5 غير مدعوم.

## أين يعمل كل مزوّد

كل المزوّدين يعملون على Node. هدف النشر `cloudflare-worker` يدعم `mock` و`openai` و`anthropic`؛ أما `ollama` و`openrouter` فيحتاجان إلى الهدف `node-server` أو `docker` (انظر [النشر](/ar/deployment#cloudflare-worker)).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.