موفرو النماذج (السحابة)

يدعم ADK-Rust عدة موفري LLM سحابيين من خلال حزمة adk-model. يطبّق جميع الموفّرين سمة Llm، مما يجعلهم قابلين للتبديل في وكلائك.

نظرة عامة

┌─────────────────────────────────────────────────────────────────────┐
│                     Cloud Model Providers                           │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│   • Gemini (Google)    ⭐ Default    - Multimodal, large context    │
│   • OpenAI (GPT-5)    🔥 Popular    - Best ecosystem               │
│   • Anthropic (Claude) 🧠 Smart      - Best reasoning               │
│   • DeepSeek           💭 Thinking   - Chain-of-thought, cheap      │
│   • Groq               ⚡ Ultra-Fast  - Fastest inference           │
│                                                                     │
│   For local/offline models, see:                                    │
│   • Ollama     → ollama.md                                          │
│   • mistral.rs → mistralrs.md                                       │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

مقارنة سريعة

المزوّدالأفضل لـالسرعةالتكلفةالميزة الرئيسية
Geminiالاستخدام العام⚡⚡⚡💰متعدد الوسائط، سياق كبير، تفكير
OpenAIالموثوقية⚡⚡💰💰أفضل منظومة
Anthropicاستدلال معقّد⚡⚡💰💰الأكثر أمانًا والأكثر تفكيرًا
DeepSeekسلسلة التفكير⚡⚡💰وضع التفكير، منخفض التكلفة
Groqالسرعة الحرجة⚡⚡⚡⚡💰أسرع استدلال

الخطوة 1: التثبيت

أضف موفّري الخدمة الذين تحتاج إليهم إلى Cargo.toml:

[dependencies]
# Pick one or more providers:
adk-model = { version = "2.1.0", features = ["gemini"] }        # Google Gemini (default)
adk-model = { version = "2.1.0", features = ["openai"] }        # OpenAI GPT-5
adk-model = { version = "2.1.0", features = ["anthropic"] }     # Anthropic Claude
adk-model = { version = "2.1.0", features = ["deepseek"] }      # DeepSeek
adk-model = { version = "2.1.0", features = ["groq"] }          # Groq (ultra-fast)

# Or all cloud providers at once:
adk-model = { version = "2.1.0", features = ["all-providers"] }

الخطوة 2: تعيين مفتاح API الخاص بك

export GOOGLE_API_KEY="your-key"      # Gemini
export OPENAI_API_KEY="your-key"      # OpenAI
export ANTHROPIC_API_KEY="your-key"   # Anthropic
export DEEPSEEK_API_KEY="your-key"    # DeepSeek
export GROQ_API_KEY="your-key"        # Groq

تطبيع المخططات

يقوم كل موفّر خدمة تلقائيًا بتطبيع مخططات أدوات MCP وقت الطلب. لا تحتاج إلى القيام بأي شيء — إذ يعمل ذلك بشفافية. ولكن إليك ما يحدث خلف الكواليس:

المزوّدمحوّل المخططالسلوك
GeminiGeminiSchemaAdapterصارم: يحلّ $ref، يدمج أدوات الدمج، ويزيل الكلمات المفتاحية غير المدعومة
OpenAI (صارم)OpenAiStrictSchemaAdapterيحافظ على البنية، ويضيف additionalProperties: false
OpenAIOpenAiSchemaAdapterإصلاحات آمنة بالحد الأدنى
AnthropicAnthropicSchemaAdapterتمرير شبه مباشر
DeepSeekGenericSchemaAdapterتحويلات آمنة ومحافظة
OllamaGenericSchemaAdapterتحويلات آمنة ومحافظة

يمكنك الوصول إلى المحوّل برمجيًا عبر سمة Llm:

use adk_core::{Llm, SchemaAdapter};

let adapter = model.schema_adapter();
let normalized = adapter.normalize_schema(raw_schema);

راجع تطبيع المخطط للاطلاع على الوثائق الكاملة.


Gemini (Google) ⭐ الافتراضي

الأفضل لـ: المهام العامة، والمهام متعددة الوسائط، والمستندات الكبيرة

أبرز الميزات:

  • 🖼️ دعم أصلي للوسائط المتعددة (الصور، والفيديو، والصوت، PDF)
  • 📚 نافذة سياق تصل إلى مليوني رمز
  • 🧠 وضع التفكير: قائم على المستويات (Gemini 3) وقائم على الميزانية (Gemini 2.5) مع توقيعات الأفكار
  • 💰 أسعار تنافسية
  • ⚡ استدلال سريع

مثال عملي كامل

use adk_rust::prelude::*;
use adk_rust::Launcher;
use std::sync::Arc;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    dotenvy::dotenv().ok();
    
    let api_key = std::env::var("GOOGLE_API_KEY")?;
    let model = GeminiModel::new(&api_key, "gemini-3.7-flash")?;

    let agent = LlmAgentBuilder::new("gemini_assistant")
        .description("Gemini-powered assistant")
        .instruction("You are a helpful assistant powered by Google Gemini. Be concise.")
        .model(Arc::new(model))
        .build()?;

    Launcher::new(Arc::new(agent)).run().await?;
    Ok(())
}

النماذج المتاحة

النموذجالوصفالسياق
gemini-3.7-flashنموذج الوكيل المتوازن الافتراضيمليون رمز
gemini-3.6-flashالجيل المتوازن السابقمليون رمز
gemini-3.5-flash-liteالتوجيه الفعّال من حيث التكلفة والمهام ذات الحجم الكبيرمليون رمز
gemini-3.1-pro-previewالاستدلال المتقدم في المعاينةمليونا رمز

وضع التفكير

تدعم نماذج Gemini 3 التفكير القائم على المستويات، بينما تستخدم Gemini 2.5 التفكير القائم على الميزانية. عند استخدام وضع التفكير مع استدعاء الدوال، تُرجع نماذج Gemini 2.5+ و3.x قيم thoughtSignature التي يجب تكرارها في الأدوار اللاحقة للحفاظ على سياق الاستدلال. يتولى ADK-Rust ذلك تلقائيًا — إذ تتم تسلسلة التوقيعات عند وجودها، ويتم حذفها عندما تكون None.

use adk_gemini::{Gemini, ThinkingLevel};

// Gemini 3: level-based thinking
let response = client.generate_content()
    .with_user_message("Solve this step by step")
    .with_thinking_level(ThinkingLevel::High)
    .with_thoughts_included(true)
    .execute().await?;

// Gemini 2.5: budget-based thinking
let response = client.generate_content()
    .with_user_message("Solve this step by step")
    .with_thinking_budget(2048)
    .with_thoughts_included(true)
    .execute().await?;

مثال على المخرجات

👤 User: What's in this image? [uploads photo of a cat]

🤖 Gemini: I can see a fluffy orange tabby cat sitting on a windowsill. 
The cat appears to be looking outside, with sunlight illuminating its fur. 
It has green eyes and distinctive striped markings typical of tabby cats.

الأفضل لـ: تطبيقات الإنتاج، والأداء الموثوق، والإمكانات الواسعة

أبرز المزايا:

  • 🏆 معيار الصناعة
  • 🔧 استدعاء ممتاز للأدوات والدوال
  • 📖 أفضل توثيق ومنظومة متكاملة
  • 🎯 مخرجات متسقة وقابلة للتنبؤ
  • 📋 مخرجات منظّمة مع فرض مخطط JSON
  • 🧠 التحكم في جهد الاستدلال لنماذج الاستدلال GPT-5.6
  • 🆕 Responses API — عميل مخصص لـ /v1/responses مع ملخصات الاستدلال، وأدوات مدمجة، وحالة من جانب الخادم

مثال عملي كامل

use adk_rust::prelude::*;
use adk_rust::Launcher;
use std::sync::Arc;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    dotenvy::dotenv().ok();
    
    let api_key = std::env::var("OPENAI_API_KEY")?;
    let model = OpenAIClient::new(OpenAIConfig::new(&api_key, "gpt-5.6-terra"))?;

    let agent = LlmAgentBuilder::new("openai_assistant")
        .description("OpenAI-powered assistant")
        .instruction("You are a helpful assistant powered by OpenAI GPT-5. Be concise.")
        .model(Arc::new(model))
        .build()?;

    Launcher::new(Arc::new(agent)).run().await?;
    Ok(())
}

المخرجات المنظّمة (مخطط JSON)

يدعم OpenAI المخرجات JSON المضمونة عبر output_schema. ويوصل ADK-Rust هذا تلقائيًا بـ OpenAI response_format API:

use adk_rust::prelude::*;
use serde_json::json;
use std::sync::Arc;

let model = OpenAIClient::new(OpenAIConfig::new(&api_key, "gpt-5.6-terra"))?;

let agent = LlmAgentBuilder::new("data_extractor")
    .model(Arc::new(model))
    .instruction("Extract person information from the text.")
    .output_schema(json!({
        "type": "object",
        "properties": {
            "name": { "type": "string" },
            "age": { "type": "number" },
            "email": { "type": "string" }
        },
        "required": ["name", "age"]
    }))
    .build()?;

// Response is guaranteed to be valid JSON matching the schema

لتمكين الوضع الصارم مع الكائنات المتداخلة، أدرج additionalProperties: false في كل مستوى:

.output_schema(json!({
    "type": "object",
    "properties": {
        "title": { "type": "string" },
        "metadata": {
            "type": "object",
            "properties": {
                "author": { "type": "string" },
                "tags": { "type": "array", "items": { "type": "string" } }
            },
            "required": ["author"],
            "additionalProperties": false  // Required for nested objects
        }
    },
    "required": ["title", "metadata"],
    "additionalProperties": false  // Auto-injected at root level
}))

جهد الاستدلال

بالنسبة إلى نماذج الاستدلال OpenAI، تحكّم في مقدار جهد الاستدلال الذي يطبّقه النموذج:

use adk_model::openai::{OpenAIClient, OpenAIConfig, OpenAIReasoningEffort};

let config = OpenAIConfig::new(&api_key, "gpt-5.6-terra");
let model = OpenAIClient::new_with_reasoning_effort(
    config,
    OpenAIReasoningEffort::XHigh,
)?;

المفردات الكاملة هي None، Minimal، Low، Medium، High، XHigh، وMax؛ ويعتمد التوفر على النموذج وAPI. يدعم GPT-5.6 Chat Completions ما يصل إلى XHigh؛ استخدم OpenAIResponsesClient من أجل Max. يظل ReasoningEffort ذو القيم الثلاث الأصلية API متاحًا للتوافق مع الإصدارات السابقة.

OpenAI-متوافق مع APIs المحلي

استخدم OpenAIConfig::compatible() للاتصال بالخوادم المحلية (Ollama وvLLM وLM Studio):

// Ollama exposes OpenAI-compatible API at /v1
let config = OpenAIConfig::compatible(
    "not-needed",                      // API key (ignored by Ollama)
    "http://localhost:11434/v1",       // Base URL
    "llama3.2"                         // Model name
);
let model = OpenAIClient::new(config)?;

ملاحظة: يتطلب الإخراج المنظم (output_schema) دعمًا من الواجهة الخلفية. يدعمه OpenAI الأصلي دعمًا كاملًا؛ وقد يكون الدعم محدودًا في الخوادم المحلية.

Gemini عبر نقطة النهاية المتوافقة مع OpenAI

يمكن الوصول إلى نماذج Gemini عبر تنسيق الأسلاك Chat Completions المتوافق مع OpenAI على https://generativelanguage.googleapis.com/v1beta/openai. استخدم الإعداد المسبق OpenAICompatibleConfig::gemini(...) (ضمن ميزة openai) مع GEMINI_API_KEY لتشغيل Gemini عبر العميل المتوافق مع OpenAI نفسه الذي تستخدمه مع كل مزود آخر:

use adk_model::openai_compatible::{OpenAICompatible, OpenAICompatibleConfig};

let api_key = std::env::var("GEMINI_API_KEY")?;
let model = OpenAICompatible::new(
    OpenAICompatibleConfig::gemini(api_key, "gemini-3.5-flash"),
)?;

يدعم هذا المسار المحادثة والبث واستدعاء الدوال والإخراج المنظم، ومستوى جهد الاستدلال (إذ يطابق reasoning_effort في OpenAI مستويات/ميزانيات التفكير في Gemini). تُمرَّر الخيارات الخاصة بـGemini — مثل thinking_config مع include_thoughts، أو cached_content — عبر خريطة extensions["openai"]["extra_body"]["google"] الخاصة بالطلب، التي يدمجها العميل حرفيًا في نص الطلب.

متى تستخدم هذا بدلًا من GeminiModel: بالنسبة إلى ميزات Gemini الأصلية (الأدوات من جهة الخادم، وAPI الخاص بـInteractions، وThinkingConfig الأصلي، وتجربة الاستخدام المُحسّنة أولًا للوسائط المتعددة)، يُفضّل GeminiModel. استخدم الإعداد المسبق المتوافق مع OpenAI عندما تريد عميلًا موحدًا واحدًا عبر المزودين.

أمثلة (تتطلب GEMINI_API_KEY أو GOOGLE_API_KEY):

# Direct client: chat, reasoning effort, extra_body thinking, streaming,
# function calling, structured output.
cargo run -p adk-model --features openai --example gemini_openai_compat

# The same compat client driving a normal LlmAgent in a Runner.
# (Lives in adk-agent: it exercises the agent layer, which sits above adk-model.)
cargo run -p adk-agent --example gemini_openai_compat_agent

API القديم لجهد الاستدلال

لا يزال ReasoningEffort API الأصلي ذو المستويات الثلاثة متاحًا للتوافق:

use adk_model::openai::{OpenAIClient, OpenAIConfig, ReasoningEffort};

let config = OpenAIConfig::new(&api_key, "gpt-5")
    .with_reasoning_effort(ReasoningEffort::High);
let model = OpenAIClient::new(config)?;

المستويات المتاحة: Low (الأسرع)، Medium (متوازن)، High (الأكثر شمولًا).

النماذج المتاحة

النموذجالوصفالسياق
gpt-5.6-terraالخيار الافتراضي المتوازن للوكلاء في بيئة الإنتاج256K رمزًا
gpt-5.6-solالاستدلال والبرمجة الرائدان256K رمزًا
gpt-5.6-lunaأعباء العمل كبيرة الحجم والفعّالة من حيث التكلفة128K tokens
gpt-5.6الاسم المستعار للنموذج الرائد256K tokens

مثال على المخرجات

👤 User: Write a haiku about Rust programming

🤖 GPT-5: Memory so safe,
Ownership guards every byte—
Compiler, my friend.

Anthropic (Claude) 🧠 ذكي

الأفضل لـ: الاستدلال المعقد، والتطبيقات الحساسة للسلامة، والمستندات الطويلة

أبرز الميزات:

  • 🧠 قدرة استثنائية على الاستدلال
  • 🛡️ الأكثر تركيزًا على السلامة
  • 📚 سياق بحجم 200K من الرموز
  • ✍️ جودة كتابة ممتازة

مثال عملي كامل

use adk_rust::prelude::*;
use adk_rust::Launcher;
use std::sync::Arc;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    dotenvy::dotenv().ok();
    
    let api_key = std::env::var("ANTHROPIC_API_KEY")?;
    let model = AnthropicClient::new(AnthropicConfig::new(&api_key, "claude-sonnet-5"))?;

    let agent = LlmAgentBuilder::new("anthropic_assistant")
        .description("Anthropic-powered assistant")
        .instruction("You are a helpful assistant powered by Anthropic Claude. Be concise and thoughtful.")
        .model(Arc::new(model))
        .build()?;

    Launcher::new(Arc::new(agent)).run().await?;
    Ok(())
}

النماذج المتاحة

النموذجالوصفالسياق
claude-sonnet-5ذكاء وتكلفة متوازنان (افتراضي)مليون رمز
claude-opus-5إمكانات رائدةمليون رمز
claude-fable-5العمل الإبداعي الممتاز والطويل1M رمز
claude-haiku-4-5الجيل السابق الفعّال من حيث التكلفة200K رمز

ناتج المثال

👤 User: Explain quantum entanglement to a 10-year-old

🤖 Claude: Imagine you have two magic coins. When you flip them, they always 
land the same way - both heads or both tails - even if one coin is on Earth 
and the other is on the Moon! Scientists call this "entanglement." The coins 
are connected in a special way that we can't see, like invisible best friends 
who always make the same choice at the exact same time.

DeepSeek 💭 التفكير

الأفضل لـ: حل المشكلات المعقدة، والرياضيات، والبرمجة، ومهام الاستدلال

أبرز المزايا:

  • 💭 وضع التفكير - يعرض استدلال سلسلة الأفكار
  • 💰 فعّال جدًا من حيث التكلفة (أرخص بـ 10 مرات من GPT-4)
  • 🔄 تخزين السياق مؤقتًا للبادئات المتكررة
  • 🧮 قوي في الرياضيات والبرمجة

مثال عملي كامل

use adk_rust::prelude::*;
use adk_rust::Launcher;
use std::sync::Arc;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    dotenvy::dotenv().ok();
    
    let api_key = std::env::var("DEEPSEEK_API_KEY")?;
    
    // Standard chat model
    let model = DeepSeekClient::chat(&api_key)?;
    
    // OR: Reasoning model with thinking mode
    // let model = DeepSeekClient::reasoner(&api_key)?;

    let agent = LlmAgentBuilder::new("deepseek_assistant")
        .description("DeepSeek-powered assistant")
        .instruction("You are a helpful assistant powered by DeepSeek. Be concise.")
        .model(Arc::new(model))
        .build()?;

    Launcher::new(Arc::new(agent)).run().await?;
    Ok(())
}

النماذج المتاحة

النموذجالوصفالميزة الخاصة
deepseek-v4-flashالافتراضي الحاليوكلاء سريعيْن متعدديْ الأغراض
deepseek-v4-proاستدلال متقدمأعمال وكيلية معقدة

مثال على المخرجات (مُستدل مع وضع التفكير)

👤 User: What's 17 × 23?

🤖 DeepSeek: <thinking>
Let me break this down:
17 × 23 = 17 × (20 + 3)
       = 17 × 20 + 17 × 3
       = 340 + 51
       = 391
</thinking>

The answer is 391.

Groq ⚡ فائق السرعة

الأفضل لـ: التطبيقات الفورية، وروبوتات المحادثة، والمهام الحساسة للسرعة

أبرز الميزات:

  • ⚡ أسرع استدلال - أسرع بـ 10 مرات من المنافسين
  • 🔧 تقنية LPU (وحدة معالجة اللغة)
  • 💰 أسعار تنافسية
  • 🦙 يشغّل نماذج LLaMA وMixtral وGemma

مثال عملي كامل

use adk_rust::prelude::*;
use adk_rust::Launcher;
use std::sync::Arc;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    dotenvy::dotenv().ok();
    
    let api_key = std::env::var("GROQ_API_KEY")?;
    let model = GroqClient::new(GroqConfig::gpt_oss_120b(&api_key))?;

    let agent = LlmAgentBuilder::new("groq_assistant")
        .description("Groq-powered assistant")
        .instruction("You are a helpful assistant powered by Groq. Be concise and fast.")
        .model(Arc::new(model))
        .build()?;

    Launcher::new(Arc::new(agent)).run().await?;
    Ok(())
}

النماذج المتاحة

النموذجالطريقةالوصف
openai/gpt-oss-120bGroqClient::new(GroqConfig::gpt_oss_120b(key))الإعداد الافتراضي الحالي للإنتاج
openai/gpt-oss-20bGroqClient::new(GroqConfig::new(key, "openai/gpt-oss-20b"))نموذج GPT-OSS منخفض التكلفة
أي نموذجGroqClient::new(GroqConfig::new(key, "model"))نموذج مخصص

مثال على المخرجات

👤 User: Quick! Name 5 programming languages

🤖 Groq (in 0.2 seconds): 
1. Rust
2. Python
3. JavaScript
4. Go
5. TypeScript

التبديل بين المزوّدين

يطبّق جميع المزوّدين سمة Llm نفسها، لذا فإن التبديل سهل:

use adk_agent::LlmAgentBuilder;
use std::sync::Arc;

// Just change the model - everything else stays the same!
let model: Arc<dyn adk_core::Llm> = Arc::new(
    // Pick one:
    // GeminiModel::new(&api_key, "gemini-3.7-flash")?
    // OpenAIClient::new(OpenAIConfig::new(&api_key, "gpt-5.6-terra"))?
    // AnthropicClient::new(AnthropicConfig::new(&api_key, "claude-sonnet-5"))?
    // DeepSeekClient::chat(&api_key)?
    // GroqClient::new(GroqConfig::gpt_oss_120b(&api_key))?
);

let agent = LlmAgentBuilder::new("assistant")
    .instruction("You are a helpful assistant.")
    .model(model)
    .build()?;

أمثلة

استخدم cargo-adk لإنشاء مشاريع خاصة بالمزوّد مع تبعيات 0.8 مُتحقَّق منها:

cargo adk new gemini_agent --provider gemini
cargo adk new openai_agent --template openai
cargo adk new anthropic_agent --provider anthropic

تُجمَّع المشاريع المُنشأة في CI بواسطة scripts/check-cargo-adk-templates.sh. ويُحافَظ على معرض الأمثلة الكامل في مستودع adk-playground.



السابق: ← الوكلاء الفوريون | التالي: Ollama (محلي) →

ما الذي يحدث للمحتوى الذي لا يستطيع أحد المزوّدين نقله

يمكن لـ Content التعبير عن محتوى يتجاوز ما يقبله أي نقل لمزوّد واحد، ولذلك يتعين على كل محوّل أن يقرر ما الذي سيفعله بالباقي. تُسجَّل هذه القرارات الآن بدلًا من تطبيقها دون إظهارها. ويُصنَّف كل جزء:

الإجراءالمعنى
Convertedمُنقَل إلى موفّر الخدمة بصيغة أصلية مكافئة
Downgradedمُنقَل بصيغة أكثر فقدانًا للمعلومات — مرجع ملف معروض كنص وصفي يمكن للنموذج قراءته، لكنه لا يستطيع جلبه
Omittedلا يتم نقله إطلاقًا

تُصدر حالات التخفيض والحذف تحذيرًا tracing عند تسجيلها، مع ذكر نوع الجزء ونوع MIME والسبب، لذا لا يبقى أيٌّ منهما صامتًا.

لرؤية النتيجة قبل إرسال الطلب:

use adk_core::{Content, Part};
use adk_model::bedrock::convert::report_for_contents;

let content = Content {
    role: "user".to_string(),
    parts: vec![Part::inline_data("audio/wav", vec![0u8; 16])],
};
let report = report_for_contents(std::slice::from_ref(&content));

for omission in report.omitted_parts() {
    println!("{} was dropped: {}", omission.kind, omission.detail);
}

لرفض طلب سيصل إلى النموذج غير مكتمل بدلًا من تلقي إجابة عن مادة لم يرها النموذج مطلقًا:

use adk_core::{Content, Part};
use adk_model::bedrock::convert::report_for_contents;

let content = Content {
    role: "user".to_string(),
    parts: vec![Part::inline_data("video/mp4", vec![0u8; 16])],
};

if let Some(error) = report_for_contents(std::slice::from_ref(&content)).into_error() {
    return Err(error);
}

يغطي into_error حالات الحذف فقط. يظل التخفيض يصل إلى النموذج، ورفضه سيؤدي إلى رفض البديل النصي الموثّق.

ملاحظة: السجل كامل بحكم التصميم. أي جزء يغادر المحوّل دون مصير مسجّل — بما في ذلك أي جزء يُضاف نتيجة تغيير مستقبلي — يُسجّل كحذف مع عبارة صريحة «لا يوجد سبب مسجّل»، ويفشل adk-model/tests/part_conversion_matrix_tests.rs بسببه.

تغطية Bedrock Converse

الجزءالمعالجة
نص، FunctionCall، FunctionResponse، تفكيرConverted
InlineData مع JPEG، PNG، GIF، WebPConverted ككتلة صورة
InlineData مع نوع مستند مدعوم (PDF وما شابه)Converted ككتلة مستند
InlineData مع صوت أو فيديو أو بيانات ثنائية عشوائيةOmitted
FileData لصورة أو مستند مدعومDowngraded إلى نص — يأخذ Converse ‏URIs من S3، وليس URLs عشوائيًا
FileData لأي نوع آخرOmitted
ServerToolCall، ServerToolResponseOmitted — خاص بـ Gemini
نص EmbeddedResource، أو كائن ثنائي من نوع مدعومConverted
كائن ثنائي EmbeddedResource من نوع غير مدعومOmitted