
شنو كيدير Underclass
Underclass هو proxy محلي كيجمع بزاف ديال اشتراكات ChatGPT/Codex وGitHub Copilot فـ endpoint واحد متوافق مع OpenAI. العملاء كيتواصلو مع المسارات المألوفة ديال /v1/*، بينما Underclass كيختار اشتراك مؤهل، كيتبع حالة الحصة، وكيفوّت الطلبات للخدمة المناسبة.
هاد الشي مفيد ملي كيكون لكل اشتراك quota خاص به. بلا ما تبقى تبدّل الحسابات يدوياً كل مرة يوصل واحد منها للحد ديالو، تقدر تحط الحسابات فـ pool مشترك. الحساب اللي سالات حصتو كيدخل فحالة تبريد، وكيرجع أوتوماتيكياً للدوران من بعد ما كتعاود نافذة الحصة تتصفّر.
Underclass مصمم باش يتصرف بحال مزوّد واحد عندو موارد كافية، مع الحفاظ على صحة الحسابات، وثبات الجلسات، وفعالية cache ديال الـ prompts.
المزايا الرئيسية
- واجهة API متوافقة مع OpenAI: العملاء يقدرو يستعملو
/v1/responsesو/v1/chat/completionsو/v1/models. - Backends متعددة: الـ pool يقدر يضم حسابات ChatGPT/Codex، أو حسابات GitHub Copilot، أو بجوج.
- جلسات ثابتة: الطلبات اللي فيها
prompt_cache_keyأوpromptCacheKeyكتبقى مرتبطة بنفس الاشتراك إلا كان هاد الشي ممكن. - تبريد أوتوماتيكي: ردود الحصة كتنحي الحساب من الدوران حتى تسالي نافذة إعادة المحاولة ديالو.
- ردود سريعة عند الامتلاء: إلا كانت جميع الحسابات المؤهلة لنموذج معيّن فحالة تبريد، Underclass كيرجع
429ومعاه أقرب قيمة متاحة ديالRetry-Afterبلا ما يبقى كيسنّى فالطابور بلا نهاية. - اختيار الأقل فالطلبات الجارية: حسابات Codex وCopilot المؤهلة كيتنافسو فـ pool مسطّح، مع التصفية حسب كتالوج النماذج ديال كل backend.
- حالة مستمرة: الحسابات، وكتالوجات النماذج، وبيانات الاعتماد، والروابط الثابتة كيبقاو محفوظين من بعد إعادة التشغيل.
- واجهة ويب إدارية: زِد ودبّر الحسابات، بدّل كتالوجات النماذج، وعاين آخر 200 طلب.
- مراقبة منظمة: كل رد فيه
x-request-id، والـ logs كيبينو label ديال الحساب اللي خدم كل طلب.
تثبيت وتشغيل Underclass
الخيار 1: التشغيل من مشروع Rust
من داخل المستودع، ولّد أسرار منفصلة لعملاء API وللواجهة الإدارية، ومن بعد شغّل الخادم:
UNDERCLASS_PROXY_KEY="$(openssl rand -hex 32)" \
UNDERCLASS_UI_TOKEN="$(openssl rand -hex 32)" \
cargo run -- serve
المستمع الافتراضي هو http://127.0.0.1:8080، وواجهة الويب متاحة فالرابط الجذري:
http://127.0.0.1:8080/
حفظ القيمتين اللي تولدو فـ password manager ولا فملف ديال أسرار وقت التشغيل. مفتاح الـ proxy كيخوّل الطلبات لـ /v1/*، بينما token ديال الواجهة كيخوّل العمليات الإدارية. Underclass ما كيكتبش هاد القيم فالتشخيصات.
الخيار 2: التشغيل باستعمال Nix
المستودع حتى هو Nix flake. شغّل الـ proxy بلا ما تثبّتو:
nix run github:ghuntley/underclass -- serve
باش تثبّت الحزمة فـ profile ديال Nix، استعمل:
nix profile install github:ghuntley/underclass
فالتطوير، دخل للـ shell المرفوق وشغّل الاختبارات:
nix develop --no-pure-eval
cargo test
الخيار --no-pure-eval ضروري للـ shell ديال تطوير devenv. ماشي ضروري مع nix run ولا nix profile install.
إضافة الحسابات للـ Pool
- حلّ
http://127.0.0.1:8080/. - لسّق القيمة المضبوطة فـ
UNDERCLASS_UI_TOKEN. - اختار Add account.
- اختار يا إما ChatGPT / Codex يا إما GitHub Copilot.
- حلّ رابط تخويل الجهاز اللي بان، ودخل كود الجهاز.
- تسنّى حتى يكمل الإعداد. Underclass كيعطي للحساب label فيه عنوان البريد الإلكتروني ولا اسم المستخدم ديالو.
- عاود نفس العملية لكل اشتراك بغيتي يشارك فـ pool.
الواجهة تقدر حتى تفعّل الحسابات أو تعطّلها أو تحيدها أو تعاود تسجيل الدخول فيها. الحساب المعطّل كيبقى مضبوط، ولكن ما كيتختارش للطلبات.
الربط مع OpenCode
Underclass فيه الأمر connect اللي كيزيد مزوّد Underclass لـ OpenCode:
cargo run -- connect
افتراضياً، الأمر كيحدّث إعدادات OpenCode العامة فـ ~/.config/opencode/. كيدمج كتلة المزوّد فـ opencode.json ولا opencode.jsonc، وكيكتب بيانات الاعتماد فـ auth.json، وكيصايب نسخ احتياطية. العملية idempotent، يعني تقدر تعاود تشغّلها بأمان.
شغّل OpenCode بنموذج مكشوف من طرف الـ pool:
opencode --provider underclass --model underclass/gpt-5.5
باش تكتب إعدادات محلية ديال المشروع، زِد --project:
cargo run -- connect --project
عاين الإعدادات المدموجة بلا ما تكتب حتى ملف:
cargo run -- connect --dry-run
حيد التكامل اللي تولّد ملي ما تبقاش محتاجو:
cargo run -- connect --remove
الأمر كيقبل حتى --base-url و--api-key و--model و--no-default-model ملي كتحتاج تخصّص إعدادات المزوّد اللي غادي تتولّد.
استعمال API المتوافق مع OpenAI
أي عميل متوافق يقدر يستعمل الـ proxy إلى ضبطتي عنوان الأساس ديالو على مستمع Underclass، ومرّرتي مفتاح الـ proxy كـ bearer token.
عرض النماذج المتاحة
curl http://127.0.0.1:8080/v1/models \
-H "Authorization: Bearer $UNDERCLASS_PROXY_KEY"
نقطة نهاية النماذج كترجّع كاتالوگ موحّد بحدود مدموجة. الكاتالوگ مهيّأ بعائلات نماذج Codex الموثّقة وباللائحة الحيّة ديال نماذج Copilot. وحيت الكاتالوگ مخزّن كبيانات، يمكن تعديلو من خلال الواجهة ولا واجهة الإدارة بلا ما يتبدّل كود البروكسي.
صيفط إكمال ديال محادثة
curl http://127.0.0.1:8080/v1/chat/completions \
-H "Authorization: Bearer $UNDERCLASS_PROXY_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5.5",
"messages": [
{"role": "user", "content": "Explain sticky session routing."}
]
}'
البروكسي كيدعم حتى POST /v1/responses. بجوج المسارات ديال الطلبات كيبعثو النتائج بشكل متدفّق عبر الحساب المختار. منين كيبدا البث، أي عطب من الخدمة الفوقية كيدوز كما هو، وما كيتعاودش إرسال طلب تكمّل منّو شي حاجة بلا ما يبان.
فهم التوجيه والتحويل عند العطب
كيفاش كتخدم الجلسات اللاصقة
إلا كان الطلب فيه prompt_cache_key ولا promptCacheKey، Underclass كيربط داك القيمة باشتراك واحد. OpenCode يقدر يصيفط معرّف الجلسة ديالو منين كتكون setCacheKey: true مفعّلة. الربط كيبقى 24 ساعة وكيبقى حتى من بعد إعادة تشغيل البروكسي.
إلا بدا الحساب المعيّن كيدخل فحالة التبريد، Underclass كيعطي الأولوية لإعادة ربط الجلسة بحساب آخر ف نفس الواجهة الخلفية. هاد التصميم كيساعد يحافظ على فوائد ذاكرة التخزين المؤقت ديال الطلبات الفوقية، وفنفس الوقت كيسمح بالتعافي من استنفاد الحصة.
التعامل مع الحصة والمصادقة
ردّ الحصة، بما فيه ردود 429 ولا ردود حدود الاستعمال ذات الصلة، كيدخل الحساب فحالة التبريد. Underclass كيستعمل قيمة Retry-After ديال الخدمة الفوقية إلا كانت متوفّرة، ولا مدة تبريد مخصّصة للواجهة الخلفية إلا ما كانتش. الحسابات اللي فالتبريد كتولي مؤهّلة من جديد أوتوماتيكياً ملي كتسالي مدة التبريد.
فحالة ردّ فوقي 401، Underclass كيدير تحديث واحد للتوكن وكيعاود المحاولة مرة وحدة. إلا بقات المصادقة فاشلة، الحساب كيحتاج تسجيل دخول جديد.
امتلاء المجموعة
إلا ما كان حتى حساب مؤهّل للنموذج المطلوب، Underclass ما كيبقّاش حابس الطلب فالطابور. كيرجّع فوراً 429 وكيبلّغ على أقرب وقت معروف لإعادة الضبط عبر Retry-After.
إعداد البروكسي
يمكن تحطّ الإعدادات الاختيارية الدائمة فـ ~/.config/underclass/config.toml:
bind = "127.0.0.1:8080"
proxy_key = "replace-with-a-client-secret"
ui_token = "replace-with-an-admin-secret"
codex_cooldown_secs = 1800
copilot_cooldown_secs = 1800
مدة التبريد الافتراضية لكل واجهة خلفية هي 1,800 ثانية ملي الخدمة الفوقية ما كتوفّرش مدة لإعادة المحاولة.
المتغيّرات البيئية كتغلب قيم الإعدادات المقابلة:
UNDERCLASS_BINDUNDERCLASS_PROXY_KEYUNDERCLASS_UI_TOKEN
فالاختبارات مع خدمات وهمية، استعمل UNDERCLASS_CODEX_UPSTREAM وUNDERCLASS_COPILOT_UPSTREAM. القيم الافتراضية ديالهم كتشير لنقاط النهاية الفوقية الحقيقية.
Underclass كيخزّن بيانات الاعتماد، والروابط اللاصقة، والمفاتيح المُنشأة، وكاتالوگ النماذج فـ ~/.local/share/underclass/pool.db. مسح قاعدة البيانات هادي كيرجّع الحالة المحلية كاملة للصفر.
نصائح تشغيل متقدّمة
فحص السجلات وربط الطلبات
كل ردّ كيتعالج فيه x-request-id. السجلات منظّمة ويقدر الإخراج ديالها يكون بصيغة JSON ولا بصيغة مهيّأة عبر --log-format json ولا --log-format pretty. استعمل RUST_LOG للتحكّم فالتصفية.
ملي كيتحط preflight قدّام Underclass، أي UUIDv4 صالح متصيفط فـ x-request-id كيبقى محفوظ فالرد، وسجلات التوجيه، وسجلات إعادة المحاولة، وتاريخ الطلبات. المعرّفات غير الصالحة، والمكرّرة، والفارغة، والناقصة، ولا اللي ماشي v4 كيتعوّضو. المعرّف غير كيساعد فالربط؛ وما كيثبتش الصلاحية ولا الفحص.
تدبير كاتالوگ النماذج بحذر
الأهلية للتوجيه وكتلة نماذج OpenCode كيتبعو الكاتالوگ المخزّن. استعمل الواجهة الويب ولا واجهة API الإدارية ديال الكاتالوگ باش تفحص ولا تعدّل تعيينات نماذج الواجهات الخلفية. معرّفات النماذج المجهولة كدوز لـ Codex، وهاد الشي كيخلّي نماذج Codex الجديدة تخدم بلا إصدار جديد للبروكسي.
خلّي الخدمة خاصة افتراضياً
Underclass كيسمع فـ localhost افتراضياً. خليك على هاد الإعداد إلا كان الولوج عن بُعد مقصود ومحمي. البروكسي ما كيسجّلش توكنات الولوج، ولا توكنات التحديث، ولا ترويسات التفويض، ولا نصوص الطلبات، ولكن تسميات الحسابات كيبانو فالسجلات والواجهة.
- ما تديرش
pool.dbولا ملفات*.bakالمُنشأة فالمستودع. - حمي توكن الواجهة بوحدو على مفتاح بروكسي الزبون.
- خلّي
auth.jsonاللي كيُنشئو OpenCode خاص؛ Underclass كيكتبو بصلاحيات0600. - استعمل نفقاً آمناً ولا حماية مقصودة ومماثلة قبل ما تعرّض الخدمة خارج localhost.
شغّل Underclass على NixOS
الـ flake كيصدّر وحدة NixOS. إعداد الخدمة يقدر يفعّل Underclass، ويربطو محلياً، ويحمل الأسرار من ملف بيئي وقت التشغيل، ويضبط مدد التبريد ديال الواجهات الخلفية:
{
inputs.underclass.url = "github:ghuntley/underclass";
outputs = { nixpkgs, underclass, ... }: {
nixosConfigurations.my-host = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
underclass.nixosModules.default
{
services.underclass = {
enable = true;
bindAddress = "127.0.0.1:8080";
environmentFile = "/run/secrets/underclass.env";
settings = {
codex_cooldown_secs = 1800;
copilot_cooldown_secs = 1800;
};
};
}
];
};
};
}
ملفّ بيئة التشغيل يگدر يحتافظ بالأسرار بلا ما يتحطّو فـمخزن Nix:
UNDERCLASS_PROXY_KEY=sk-underclass-replace-me
UNDERCLASS_UI_TOKEN=replace-me
الموديول كيستعمل مستخدم ديناميكي، وكيخزّن المعطيات الدائمة فـ/var/lib/underclass، وكيربط افتراضياً غير مع localhost، وكيخلّي الجدار الناري مسدود. فعّل services.underclass.openFirewall غير ملي كتكون باغي عن قصد تربط الخدمة من خارج localhost.
طوّر واختبر المشروع
بني المشروع وشغّل مجموعة الاختبارات باستعمال Cargo:
cargo build
cargo test
المشروع كيجمع بين اختبارات الوحدات، واختبارات الخصائص ديال Hegel، واختبارات من البداية للنهاية. النواة ديال التجميع والصحة متزامنة وكتستعمل ساعة محقونة، بينما السلوك غير المتزامن مخلي فالحدود. المزوّدين الجدد كيطبّقو السمة provider::Backend وكيتسجلو مع التطبيق.
لخلفية معمارية، راجع سجلات قرارات المعمارية ديال المشروع. نموذج التوجيه مشروح فـADR 0010، بينما ربط الطلبات بين البروكسيات مغطّى فـADR 0012.
الخلاصة
Underclass كتحوّل بزاف ديال اشتراكات ChatGPT/Codex وGitHub Copilot لخدمة محلية وحدة متوافقة مع OpenAI. التوجيه اللاصق، والاسترجاع الأوتوماتيكي من فترة التبريد، واختيار الحسابات حسب الموديل، والسلوك اللي كيفشل بسرعة ملي كيكون التشبّع، كينقصو تبديل الحسابات يدوياً مع الحفاظ على سلوك متوقّع للعميل. شغّل السيرفر، زِد الحسابات من خلال واجهة الويب، نفّذ underclass connect، ووجّه OpenCode أو أي عميل آخر متوافق للنقطة النهائية الناتجة.
