DeepSeek Harness: إعدادات الإضافة: Config و Schemastery

آخر تحديث: 2026-08-31

الإعدادات هي "مقبول التحكم" للإضافة — مفاتيح API، مهلات الانتظار، مفاتيح الميزات، هذه المُعاملات الخاصة بالبيئة لا يجب أن تكون مُرمّزة بثبات بل تُخرج عبر نظام إعدادات. Schemastery هو إطار الإعدادات التصريحي في Cordis: عرّف مرة، واحصل تلقائياً على أمان الأنواع ونماذج واجهة المستخدم والتحقق والتوثيق.

💡 نصيحة: الفلسفة الأساسية لـ Schemastery هي "التصريح كتوثيق" — تُعرّف هيكل الإعدادات بـ Schema، والإطار يُولّد تلقائياً نماذج واجهة الويب ومنطق التحقق. تغيير الإعدادات لا يتطلب تغيير الكود.

📋 المتطلبات المسبقة: أكمل 15-define-tool.md، قادر على كتابة أدوات أساسية

1. ما ستتعلمه

إعادة التحميل السريع للتكوين


2. نظام الإعدادات التصريحي Schemastery

(1) المفهوم الأساسي

Schemastery هي مكتبة تعريف Schema المدمجة في Cordis، مُستلهمة من Zod و JSON Schema، لكن مصممة خصيصاً للإعدادات التفاعلية.

TYPESCRIPT
import { Schema } from '@deepseek-ai/cordis'

export const Config = Schema.object({
  apiKey: Schema.string().required().description('API key for the service'),
  maxRetries: Schema.number().default(3).description('Maximum retry attempts'),
  debug: Schema.boolean().default(false).description('Enable debug logging')
})

(2) المقارنة مع JSON Schema

البُعد Schemastery JSON Schema
الصيغة API قابلة للسلسلة كائن JSON
استنتاج الأنواع ✅ تلقائي ❌ يدوي
نماذج واجهة المستخدم ✅ مُولّدة تلقائياً ❌ تحتاج أدوات إضافية
القيم الافتراضية .default() حقل default
الأوصاف .description() حقل description
التحقق مدققات قابلة للسلسلة pattern/min/max إلخ

(3) ▶ مثال 3

TYPESCRIPT
export const Config = Schema.object({
  apiKey: Schema.string().required(),
  maxRetries: Schema.number().default(3)
})

export const name = 'my-plugin'

export function apply(ctx: Context) {
  // نوع ctx.config يُستنتج تلقائياً
  ctx.logger.info(`API key: ${ctx.config.apiKey}`)
  ctx.logger.info(`Max retries: ${ctx.config.maxRetries}`)
}

الإطار يتحقق من قيم الإعدادات التي يُقدمها المستخدم ويُحقنها في ctx.config.


3. أنواع Schema

(1) ▶ مثال 1

TYPESCRIPT
Schema.string()                           // أي سلسلة
Schema.string().required()                // مطلوب
Schema.string().default('hello')          // قيمة افتراضية
Schema.string().description('Your name')  // وصف
Schema.string().pattern(/^[a-z]+$/)       // تحقق بالتعابير النمطية
Schema.string().min(1).max(100)           // حدود الطول

(2) ▶ مثال 2

TYPESCRIPT
Schema.number()                    // أي عدد
Schema.number().default(0)         // قيمة افتراضية
Schema.number().min(0).max(100)    // حدود النطاق
Schema.number().step(1)            // خطوة (لشرائح واجهة المستخدم)
Schema.integer()                   // عدد صحيح

(3) Schema.boolean

TYPESCRIPT
Schema.boolean()                   // منطقي
Schema.boolean().default(false)    // افتراضي false

(4) Schema.object

TYPESCRIPT
Schema.object({
  host: Schema.string().default('localhost'),
  port: Schema.number().default(5432),
  ssl: Schema.boolean().default(false)
})

(5) Schema.array

TYPESCRIPT
Schema.array(Schema.string())                          // مصفوفة سلاسل
Schema.array(Schema.string()).default([])              // افتراضي مصفوفة فارغة
Schema.array(Schema.object({                           // مصفوفة كائنات
  name: Schema.string().required(),
  url: Schema.string().required()
}))

(6) Schema.union / Schema.const

TYPESCRIPT
// قيم تعداد
Schema.union(['read', 'write', 'execute'])

// ثابت
Schema.const('fixed-value')

// تعداد مع أوصاف
Schema.union([
  Schema.const('read').description('Read-only access'),
  Schema.const('write').description('Read and write access'),
  Schema.const('execute').description('Full access')
])

(7) Schema.dict

TYPESCRIPT
// نوع القاموس
Schema.dict(
  Schema.string(),           // نوع القيمة
  Schema.string()            // نوع المفتاح (اختياري)
)

4. المُعدّلات القابلة للسلسلة

(1) .required()

يُعلّم كمطلوب. عندما لا يُوفّره المستخدم، يُبلغ الإطار عن خطأ ويمنع التحميل.

TYPESCRIPT
apiKey: Schema.string().required()

(2) .default(value)

يُعيّن قيمة افتراضية. عندما لا يُوفّره المستخدم، تُستخدم القيمة الافتراضية بدون خطأ.

TYPESCRIPT
maxRetries: Schema.number().default(3)
timeout: Schema.number().default(30000)

(3) .description(text)

يُضيف وصفاً لعنصر إعدادات، يُعرض في واجهة الويب كنص تلميح لتسميات النموذج.

TYPESCRIPT
apiKey: Schema.string().required()
  .description('API key obtained from the service dashboard')

(4) .min() / .max()

حدود النطاق الرقمي أو طول السلسلة:

TYPESCRIPT
port: Schema.number().min(1).max(65535).default(8080)
name: Schema.string().min(1).max(50)

(5) .pattern()

تحقق بالتعابير النمطية:

TYPESCRIPT
email: Schema.string().pattern(/^[^@]+@[^@]+\.[^@]+$/)
  .description('Valid email address')

(6) .step()

خطوة عددية، تؤثر على دقة شريحة واجهة المستخدم:

TYPESCRIPT
timeout: Schema.number().min(1000).max(300000).step(1000).default(30000)

(7) الاستخدام المُجمّع

TYPESCRIPT
const Config = Schema.object({
  apiKey: Schema.string()
    .required()
    .pattern(/^sk-[a-zA-Z0-9]+$/)
    .description('DeepSeek API key (starts with sk-)'),
  
  maxTokens: Schema.number()
    .min(1).max(32768)
    .default(4096)
    .description('Maximum tokens per request'),
  
  model: Schema.union(['deepseek-chat', 'deepseek-reasoner'])
    .default('deepseek-chat')
    .description('Model to use'),
  
  temperature: Schema.number()
    .min(0).max(2).step(0.1)
    .default(0.7)
    .description('Sampling temperature')
})

5. الإعدادات المتداخلة

(1) الكائنات المتداخلة

TYPESCRIPT
const Config = Schema.object({
  database: Schema.object({
    host: Schema.string().default('localhost'),
    port: Schema.number().default(5432),
    name: Schema.string().required(),
    ssl: Schema.boolean().default(false)
  }).default({ host: 'localhost', port: 5432, ssl: false }),

  cache: Schema.object({
    enabled: Schema.boolean().default(true),
    ttl: Schema.number().default(3600).description('Cache TTL in seconds')
  }).default({ enabled: true, ttl: 3600 })
})

(2) التداخل العميق

TYPESCRIPT
const Config = Schema.object({
  llm: Schema.object({
    provider: Schema.union(['deepseek', 'openai']).default('deepseek'),
    deepseek: Schema.object({
      apiKey: Schema.string().required(),
      model: Schema.string().default('deepseek-chat')
    }),
    openai: Schema.object({
      apiKey: Schema.string(),
      endpoint: Schema.string().default('https://api.openai.com/v1')
    })
  })
})

(3) Schema قابل لإعادة الاستخدام

TYPESCRIPT
const ConnectionSchema = Schema.object({
  host: Schema.string().default('localhost'),
  port: Schema.number().default(5432),
  timeout: Schema.number().default(5000)
})

const Config = Schema.object({
  primary: ConnectionSchema.description('Primary connection'),
  replica: ConnectionSchema.description('Replica connection')
})

6. عرض الإعدادات في صفحة إعدادات واجهة الويب

(1) توليد النماذج تلقائياً

Config المُعرّف بـ Schemastery يُولّد تلقائياً نماذج في صفحة إعدادات واجهة الويب:

نوع Schema عنصر واجهة المستخدم
Schema.string() حقل إدخال نصي
Schema.number() حقل إدخال رقمي / شريحة
Schema.boolean() مفتاح تبديل
Schema.union() قائمة منسدلة
Schema.array() مُحرّر قوائم
Schema.object() لوحة مُجمّعة
Schema.dict() مُحرّر مفتاح-قيمة

(2) عرض الوصف

وصف .description() لكل حقل يظهر كنص تلميح أسفل الإدخال:

TEXT 📖 للعرض فقط
┌─────────────────────────────────────────┐
│ API Key                                 │
│ [sk-xxxxxxxxxxxxxxx                   ] │
│ DeepSeek API key (starts with sk-)      │
├─────────────────────────────────────────┤
│ Max Tokens                              │
│ [4096                                 ] │
│ Maximum tokens per request              │
└─────────────────────────────────────────┘

(3) ملاحظات التحقق

عندما لا يتطابق إدخال المستخدم مع Schema، تعرض واجهة المستخدم ملاحظات فورية:

TEXT 📖 للعرض فقط
┌─────────────────────────────────────────┐
│ API Key                                 │
│ [invalid-key                          ] │
│ ❌ Must match pattern: /^sk-[a-zA-Z0-9]+$/ │
└─────────────────────────────────────────┘

7. تحقق الإعدادات ورسائل الخطأ

(1) التحقق عند البدء

عند تحميل إضافة، يتحقق الإطار تلقائياً من إعداداتها:

TYPESCRIPT
const Config = Schema.object({
  port: Schema.number().min(1).max(65535)
})

// إعدادات المستخدم: port: -1
// → Error: Invalid config for plugin my-plugin:
//   port: must be >= 1

عند فشل التحقق، لا تُحمّل الإضافة ويُخرج الخطأ في الطرفية.

(2) أمان الأنواع

TypeScript يستنتج نوع ctx.config تلقائياً من تعريف Config:

TYPESCRIPT
const Config = Schema.object({
  apiKey: Schema.string().required(),
  maxRetries: Schema.number().default(3)
})

export function apply(ctx: Context) {
  ctx.config.apiKey     // string ✅
  ctx.config.maxRetries // number ✅
  ctx.config.unknown    // خطأ نوع ❌
}

(3) تحقق مخصص

TYPESCRIPT
const Config = Schema.object({
  startDate: Schema.string().required(),
  endDate: Schema.string().required()
}).validate((value) => {
  if (new Date(value.startDate) > new Date(value.endDate)) {
    throw new Error('startDate must be before endDate')
  }
  return value
})

8. تحديثات الإعدادات الديناميكية

(1) الاستماع لتغييرات الإعدادات

TYPESCRIPT
export function apply(ctx: Context) {
  ctx.on('config/updated', (newConfig) => {
    ctx.logger.info('config updated:', newConfig)
    // ضبط السلوك بناءً على الإعدادات الجديدة
  })
}

(2) سير التحديث السريع

100%
graph LR
    UI[المستخدم يُعدّل الإعدادات] --> VALID[تحقق Schema]
    VALID --> APPLY[تطبيق الإعدادات الجديدة]
    APPLY --> EMIT[إصدار config/updated]
    EMIT --> RELOAD[الإضافة تستجيب للتحديث]

(3) إعدادات تتطلب إعادة التشغيل

بعض تغييرات الإعدادات (مثل أرقام المنافذ أو حقن الاعتماديات) تتطلب إعادة التشغيل:

TYPESCRIPT
export function apply(ctx: Context) {
  ctx.on('config/updated', (config) => {
    if (config.port !== ctx.config.port) {
      ctx.logger.warn('port change requires restart')
    }
  })
}

❓ أسئلة شائعة

س هل يجب تصدير Config بالاسم Config؟
ج نعم، اصطلاح الإطار يبحث عن export const Config. الأسماء الأخرى لن تُعرّف.
س هل يمكنني إضافة عناصر إعدادات ديناميكياً وقت التشغيل؟
ج غير مُوصى به. يجب تعريف Config قبل تحميل الإضافة. إذا احتجت سلوكاً ديناميكياً، استخدم ctx.on('config/updated') للاستجابة لتغييرات الإعدادات.
س كيف أُنظّم عناصر إعدادات كثيرة؟
ج استخدم Schema.object متداخل للتجميع، كل مجموعة بوصف واضح. واجهة الويب تعرض الكائنات المتداخلة كلوحات قابلة للطي.
س كيف أحمي معلومات حساسة مثل مفاتيح API؟
ج Schemastery يدعم المُعدّل .hidden()، الذي يعرض حقل كلمة مرور في واجهة المستخدم: typescript apiKey: Schema.string().required().hidden()
س هل يمكن أن تكون قيم الإعدادات دوالاً؟
ج لا. يجب أن تكون الإعدادات قيماً قابلة للتسلسل بـ JSON (string/number/boolean/object/array). السلوك الوظيفي يجب أن يُنفّذ في apply.
س هل ستتعارض إعدادات إضافات متعددة؟
ج لا. كل إضافة لها نطاق إعدادات مستقل plugins.plugin-name.config، معزول عن بعضها.

📖 ملخص


📝 تمارين

1. ⭐ أساسي: أضف Config لأداة file_count مع defaultPath (سلسلة، الدليل الحالي افتراضياً) و maxDepth (عدد، 10 افتراضياً). تحقق من توليد النموذج في صفحة إعدادات واجهة الويب.

2. ⭐⭐ متوسط: اكتب إضافة إعدادات اتصالات متعددة. Config يحتوي connections (مصفوفة كائنات، كل منها host/port/username/password)، مُعرّفة بـ Schema.object متداخل. تحقق: أخطاء عند فقدان حقول مطلوبة، القيم الافتراضية تملأ بشكل صحيح.

3. ⭐⭐⭐ تحدٍ: أنشئ إعدادات بتحقق مخصص: startDate و endDate يجب أن يحققا startDate < endDate؛ maxRetries يجب أن يكون عدداً صحيحاً موجباً. الاختبار: أدخل قيماً غير صالحة وتأكد أن رسائل خطأ التحقق تُعرض بشكل صحيح في واجهة الويب.

Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%