Skip to content

التخزين

جميع البيانات ذات الحالة في Triggerfish تتدفق عبر تجريد StorageProvider موحد. لا تُنشئ أي وحدة آلية تخزين خاصة بها -- كل مكون يحتاج إلى استمرارية يأخذ StorageProvider كتبعية. هذا التصميم يجعل الواجهات الخلفية قابلة للتبديل دون لمس منطق الأعمال ويبقي جميع الاختبارات سريعة وحتمية.

واجهة StorageProvider

typescript
interface StorageProvider {
  /** استرجاع قيمة بالمفتاح. يُعيد null إذا لم يُوجد. */
  get(key: string): Promise<StorageValue | null>;

  /** تخزين قيمة في مفتاح. يكتب فوق أي قيمة موجودة. */
  set(key: string, value: StorageValue): Promise<void>;

  /** حذف مفتاح. لا عملية إذا لم يكن المفتاح موجوداً. */
  delete(key: string): Promise<void>;

  /** سرد جميع المفاتيح المطابقة لبادئة اختيارية. */
  list(prefix?: string): Promise<string[]>;

  /** حذف جميع المفاتيح. استخدم بحذر. */
  clear(): Promise<void>;
}

StorageValue هو سلسلة نصية. جميع البيانات المُهيكلة (الجلسات، سجلات

النسب، التكوين) تُسلسل إلى JSON قبل التخزين وتُعاد هيكلتها عند القراءة. هذا يبقي الواجهة بسيطة ومستقلة عن الواجهة الخلفية. :::

التنفيذات

الواجهة الخلفيةحالة الاستخدامالاستمراريةالتكوين
MemoryStorageProviderالاختبار، الجلسات المؤقتةلا يوجد (تُفقد عند إعادة التشغيل)لا حاجة لتكوين
SqliteStorageProviderالافتراضي للمستوى الشخصيSQLite WAL في ~/.triggerfish/data/triggerfish.dbبدون تكوين
واجهات خلفية مؤسسيةالمستوى المؤسسييديرها العميلPostgres, S3، أو واجهات أخرى

MemoryStorageProvider

يُستخدم في جميع الاختبارات للسرعة والحتمية. البيانات موجودة فقط في الذاكرة وتُفقد عند خروج العملية. كل مجموعة اختبار تُنشئ MemoryStorageProvider جديد، مما يضمن عزل الاختبارات وقابليتها للإعادة.

SqliteStorageProvider

الافتراضي لعمليات النشر على المستوى الشخصي. يستخدم SQLite في وضع WAL (Write-Ahead Logging) للوصول المتزامن للقراءة وأمان ضد الأعطال. تقع قاعدة البيانات في:

~/.triggerfish/data/triggerfish.db

لا يتطلب SQLite تكويناً، ولا عملية خادم، ولا شبكة. ملف واحد يخزن جميع حالة Triggerfish. توفر حزمة @db/sqlite لـ Deno الربط، الذي يتطلب صلاحية --allow-ffi.

يسمح وضع SQLite WAL لقراء متعددين بالوصول لقاعدة البيانات بشكل متزامن مع

كاتب واحد. هذا مهم لـ Gateway، الذي قد يقرأ حالة الجلسة بينما يكتب الوكيل نتائج الأداة. :::

واجهات خلفية مؤسسية

يمكن لعمليات النشر المؤسسية توصيل واجهات تخزين خلفية خارجية (Postgres, S3، إلخ.) بدون تغييرات في الكود. أي تنفيذ لواجهة StorageProvider يعمل. تُكوّن الواجهة الخلفية في triggerfish.yaml.

مفاتيح بمساحات أسماء

جميع المفاتيح في نظام التخزين منظمة بمساحات أسماء ببادئة تحدد نوع البيانات. هذا يمنع التصادمات ويجعل من الممكن الاستعلام والاحتفاظ والتطهير حسب الفئة.

مساحة الاسمنمط المفتاحالوصف
sessions:sessions:sess_abc123حالة الجلسة (سجل المحادثة، البيانات الوصفية)
taint:taint:sess_abc123مستوى taint الجلسة
lineage:lineage:lin_789xyzسجلات نسب البيانات (تتبع المنشأ)
audit:audit:2025-01-29T10:23:45Z:hook_pre_outputإدخالات سجل التدقيق
cron:cron:job_daily_reportحالة مهام cron وسجل التنفيذ
notifications:notifications:notif_456قائمة انتظار الإشعارات
exec:exec:run_789سجل بيئة تنفيذ الوكيل
skills:skills:skill_weatherبيانات وصفية للمهارات المُثبتة
config:config:v3لقطات التكوين

سياسات الاحتفاظ

لكل مساحة اسم سياسة احتفاظ افتراضية. يمكن لعمليات النشر المؤسسية تخصيصها.

مساحة الاسمالاحتفاظ الافتراضيالمبرر
sessions:30 يوماًسجل المحادثة يتقادم
taint:يطابق احتفاظ الجلسةTaint بلا معنى بدون جلسته
lineage:90 يوماًمدفوع بالامتثال، مسار التدقيق
audit:سنة واحدةمدفوع بالامتثال، قانوني وتنظيمي
cron:30 يوماًسجل التنفيذ لتصحيح الأخطاء
notifications:حتى التسليم + 7 أيامالإشعارات غير المُسلمة يجب أن تستمر
exec:30 يوماًمخرجات التنفيذ لتصحيح الأخطاء
skills:دائمبيانات المهارات المُثبتة يجب ألا تنتهي
config:10 نسخسجل تكوين متدحرج للتراجع

مبادئ التصميم

جميع الوحدات تستخدم StorageProvider

لا تُنشئ أي وحدة في Triggerfish آلية تخزين خاصة بها. إدارة الجلسات، تتبع taint، تسجيل النسب، تسجيل التدقيق، حالة cron، قوائم انتظار الإشعارات، سجل التنفيذ، والتكوين -- كلها تتدفق عبر StorageProvider.

هذا يعني:

  • تبديل الواجهات الخلفية يتطلب تغيير نقطة حقن تبعية واحدة
  • الاختبارات تستخدم MemoryStorageProvider للسرعة -- بدون إعداد SQLite، بدون نظام ملفات
  • يوجد مكان واحد بالضبط لتنفيذ التشفير أثناء الراحة أو النسخ الاحتياطي أو النسخ المتماثل

التسلسل

جميع البيانات المُهيكلة تُسلسل إلى سلاسل JSON قبل التخزين. طبقة التسلسل/إعادة الهيكلة تتعامل مع:

  • كائنات Date (تُسلسل كسلاسل ISO 8601 عبر toISOString()، تُعاد هيكلتها عبر new Date())
  • الأنواع المُوسومة (تُسلسل كقيمتها النصية الأساسية)
  • الكائنات والمصفوفات المتداخلة
typescript
// تخزين جلسة
const session = {
  id: "sess_abc",
  taint: "CONFIDENTIAL",
  createdAt: new Date(),
};
await storage.set("sessions:sess_abc", JSON.stringify(session));

// استرجاع جلسة
const raw = await storage.get("sessions:sess_abc");
if (raw) {
  const session = JSON.parse(raw);
  session.createdAt = new Date(session.createdAt); // استعادة Date
}

الثبات

عمليات الجلسة ثابتة. قراءة جلسة وتعديلها وكتابتها مرة أخرى تُنتج دائماً كائناً جديداً. لا تُعدل الدوال أبداً الكائن المُخزن في مكانه. هذا يتوافق مع مبدأ Triggerfish الأوسع أن الدوال تُعيد كائنات جديدة ولا تُعدل أبداً.

هيكل الدليل

~/.triggerfish/
  config/          # تكوين الوكيل، SPINE.md، TRIGGER.md
  data/            # triggerfish.db (SQLite)
  workspace/       # بيئة تنفيذ الوكيل
    <agent-id>/    # مساحة عمل لكل وكيل (تستمر)
    background/    # مساحات عمل جلسات الخلفية
  skills/          # المهارات المُثبتة
  logs/            # سجلات التدقيق
  secrets/         # مخزن بيانات اعتماد مُشفر

SECURITY يحتوي دليل secrets/ على بيانات اعتماد مُشفرة يديرها تكامل

سلسلة مفاتيح نظام التشغيل. لا تخزن أبداً الأسرار في ملفات التكوين أو في StorageProvider. استخدم سلسلة مفاتيح نظام التشغيل (المستوى الشخصي) أو تكامل الخزنة (المستوى المؤسسي). :::