diff --git a/docs/admin/keys-and-permissions.mdx b/docs/admin/keys-and-permissions.mdx index d2a364ee0..df4475245 100644 --- a/docs/admin/keys-and-permissions.mdx +++ b/docs/admin/keys-and-permissions.mdx @@ -45,6 +45,8 @@ The two permissions required by a connected Failproof AI machine are independent - `events:add` sends events and session data. - `policies:pull` retrieves assigned policy deployments. +To run [Jev policies through FailproofAI Cloud](/policies/jev), select the **machine** key preset. It adds `jev:evaluate` to both permissions above. Cloud Jev cannot run with a key that lacks it. + Key secrets are shown when created or regenerated. Store them in a secret manager and rotate them without reusing an operator's interactive credentials. ## Permission catalog @@ -64,6 +66,7 @@ Key secrets are shown when created or regenerated. Store them in a secret manage | Audits | `audits:read`, `audits:write` | | Policies | `policies:read`, `policies:write`, `policies:pull` | | Usage | `usage:read` | +| Jev | `jev:evaluate` (requires `events:add` and `policies:pull`) | `orgs:admin` is reserved for the instance operator and cannot be granted to an organization key or ordinary member. Retired `incidents:*` and `alerts:ack` tokens are accepted for compatibility and normalize to current `issues:*` permissions. diff --git a/docs/ar/evaluations/jev.mdx b/docs/ar/evaluations/jev.mdx new file mode 100644 index 000000000..b0151d8ec --- /dev/null +++ b/docs/ar/evaluations/jev.mdx @@ -0,0 +1,28 @@ +--- +title: "تقييمات Jev" +description: "استخدم Jev لتصحيح جلسة منتهية مقابل سؤال بإجابات معروفة." +icon: "list-checks" +--- + +يقرأ تقييم Jev **جلسة منتهية** ويعطي درجة من 0 إلى 1. استخدمه عندما تكون الإجابة معروفة مسبقاً، مثل "هل أعرب العميل عن الاستعجالية؟" أو "ما مدى إحباط العميل؟" يساعدك في العثور على أنماط عبر عمليات التشغيل؛ لا يوقف استدعاء أداة. بالنسبة للقرارات المتخذة **قبل** تشغيل أداة، استخدم [سياسات Jev](/ar/policies/jev). + +## إنشاء واحد في لوحة التحكم + +1. افتح **Analyze → eval authoring** وحدد **new eval**. +2. صف سؤالاً واحداً وإجاباته المحتملة. على سبيل المثال: "هل وعد الوكيل برد المبلغ قبل التحقق من سياسة الاسترجاع؟ أجب بنعم أو لا." حدد **draft** واراجع أن النتيجة هي درجة مصنف. +3. [اختبره](/ar/evaluations/test) على جلسات حديثة، ثم [انشره](/ar/evaluations/deploy). يتم تصحيح الجلسات المكتملة الجديدة؛ [أملأ السجل السابق](/ar/evaluations/deploy#score-sessions-you-already-have) إذا كنت بحاجة أيضاً إلى السجل التاريخي. + +![نموذج تأليف التقييم المشترك، حيث تصف سؤالاً بإجابة ثابتة، وتراجع المسودة، وتنشر بعد الاختبار. المثال المعروض هو تقييم برمجي؛ سؤال Jev يستخدم نفس مسار التأليف.](/images/dashboard/eval-authoring-draft.png) + +يمكن للمساعد الاختيار بين الكود وتصنيف Jev و[judge](/ar/evaluations/judge). تحقق من اختياره قبل النشر. يعطي Jev درجة بدون استدلال نثري؛ اختر judge عندما تحتاج إلى شرح. راجع [مرجع تقييم Jev](/ar/reference/jev-evaluations) لأنواع الأسئلة وحدود الدرجات. + +## اقرأ الدرجات + +افتح **Observe → Evaluations** لرسم النتيجة حسب الوكيل والوقت. من الطرفية، يمكن لـ Cloud CLI قراءة نفس النتائج: + +```bash +fp evals --since 7d +fp evals --aggregate --since 7d +``` + +يقرأ Cloud CLI النتائج؛ يحدث التأليف والنشر في لوحة التحكم. راجع [مرجع Cloud CLI](/ar/reference/cloud-cli#evaluations) للحصول على المرشحات. \ No newline at end of file diff --git a/docs/ar/evaluations/judge.mdx b/docs/ar/evaluations/judge.mdx new file mode 100644 index 000000000..3fe2f23fb --- /dev/null +++ b/docs/ar/evaluations/judge.mdx @@ -0,0 +1,91 @@ +--- +title: "قضاة نماذج اللغة" +description: "قيّم الجلسات على أشياء لا يستطيع الكود قياسها — الصحة، النبرة، ما إذا كان الوكيل يتبع سياسة — من خلال وصف ما يبدو عليه الجيد والسماح لنموذج بقراءة المحادثة." +icon: "scale" +--- + +يمكن للتقييم المستضاف في Python أن يحسب ويقارن: كم عدد استدعاءات الأدوات، كم عدد الأخطاء، كم من الوقت استغرقت الجلسة. لكنه لا يمكنه أن يخبرك ما إذا كانت الإجابة *صحيحة*، أو ما إذا كانت الرد فظاً، أو ما إذا تحقق الوكيل من سياسة قبل التصرف. + +**قاضي نموذج اللغة** يمكنه ذلك. أنت تصف ما يبدو عليه الجيد بلغة عادية، ونموذج يقرأ الجلسة ويعيد درجة من 0 إلى 1 مع تعليل له. + + +القاضي يكلف استدعاء نموذج واحد لكل جلسة يعمل عليها، والتقييم البرمجي لا يكلف شيئاً. استخدم قاضياً فقط للأسئلة التي تحتاج إلى *فهم* المحادثة — وأعطه شرطاً، حتى يعمل على الجلسات التي يتعلق بها السؤال فعلاً. + + +## أيهما أريد؟ + +| السؤال | استخدم | +| --- | --- | +| هل استدعى نفس الأداة مرتين؟ | كود | +| كم عدد الأخطاء التي حدثت؟ | كود | +| هل كانت الجلسة أقل من 30 ثانية؟ | كود | +| هل عبّر العميل عن استعجالية؟ | [مصنف](/ar/evaluations/jev) | +| ما مدى إحباط العميل؟ | [مصنف](/ar/evaluations/jev) | +| هل كانت الإجابة صحيحة فعلاً؟ | **قاضي** | +| هل كان الرد فظاً أو استخفافياً؟ | **قاضي** | +| هل تحقق من سياسة الاسترجاع قبل الوعد باسترجاع الأموال؟ | **قاضي** | + +القاعدة الأساسية: **قابل للعد → كود، إجابات يمكنك إدراجها مقدماً → [مصنف](/ar/evaluations/jev)، يحتاج تفسيراً → قاضي.** القاضي هو الذي يكتب نصاً عما رآه؛ استخدمه عندما قد يسأل شخص ما عن الرقم "لماذا؟". + +لا يتعين عليك الاختيار مقدماً. اوصف ما تريد قياسه والمساعد سيختار، ثم يخبرك بما اختاره ولماذا. يمكنك تبديله. + +## اكتب واحداً + +1. اذهب إلى **Analyze → eval authoring** واختر **new eval**. +2. اوصف ما تريد الحكم عليه، واختر **draft**. +3. راجع **criteria** و**threshold** و**condition**، ثم انشره. + +### Criteria + +جملة أو جملتان، مكتوبة كمتطلب وليس كسؤال: + +> يجب على المساعد ألا يعد أو يوافق على استرجاع الأموال دون التحقق أولاً من سياسة الاسترجاع. + +كن محدداً حول ما الذي سيجعله *فاشلاً*. "هل كانت الرد جيداً؟" يعطيك رقماً لا يعني شيئاً؛ الجملة أعلاه تعطيك واحداً يمكنك التصرف بناءً عليه. + +### Threshold + +الدرجة التي تساوي أو تتجاوزها الجلسة لتمرير التقييم. `0.7` هو نقطة انطلاق معقولة. يتم تخزين الدرجة الكاملة من 0 إلى 1 دائماً، لذا فإن الحد الأدنى يقرر فقط النجاح/الفشل — يمكنك رؤية التوزيع والتعديل. + +### Condition + +نفس شرط Python كما في أي تقييم آخر، وهو يهم بكثير هنا. بدونه، يعمل القاضي على **كل** جلسة في منظمتك، بتكلفة استدعاء نموذج واحد لكل منها: + +```python +session.count("tool_use") > 0 +``` + +```python +session.agent_id == "support-bot" and session.count("error") > 0 +``` + +لوحة المعلومات تحذرك إذا نشرت قاضياً بدون شرط. هذا صحيح في بعض الأحيان — وكيل منخفض الحجم تريد الحكم عليه بالكامل — لكن يجب أن يكون قراراً، وليس حادثة. + +## ما يراه القاضي + +المحادثة، كلفات، الأحدث أولاً إذا كانت الجلسة طويلة: + +- ما قاله المستخدم +- ما ردت به المساعد +- **كل أداة استدعاها الوكيل، وما أعادته تلك الاستدعاء، بالترتيب** + +هذا الجزء الأخير هو ما يجعل "هل فعل X *قبل* Y" سؤالاً عادلاً. يتم عرض استدعاء الأداة الفاشل كفشل، لذا فإن "هل تعافى بأناقة من خطأ" يعمل أيضاً. + +الجلسات الطويلة جداً تتم اختصارها لتناسب سياق النموذج. عندما يحدث ذلك، يقول التعليل ذلك صراحة — لن ترى أبداً حكماً تم إصداره على جزء من جلسة تم تقديمه كما لو أنه تم على كلها. + +## قراءة النتائج + +ينتج القاضي **score** مثل أي تقييم مسجل آخر، لذا فهو يرسم بيانات، يصفي، وينشئ تنبيهات بنفس الطريقة. إلى جانب الرقم، يخزن **reasoning** القاضي — الفقرة التي تشرح ما رآه. اقرأ ذلك أولاً عندما تفاجئك نتيجة؛ فهي عادة ما تكون إما جلسة مثيرة للاهتمام حقاً أو علامة على أن المعايير تحتاج إلى شحذ. + +النتائج مستقرة للحالات الواضحة لكن ليست حتمية بالبت. تعامل مع نتيجة حدودية واحدة كدعوة للذهاب وقراءة الجلسة، وليس كحكم. + +## الحدود + +- **الاختبار غير متاح حالياً.** يجفف التشغيل لا يوجد تعيين جلسة خلفه، وذلك التعيين هو ما يخول قضاء ميزانية النموذج الخاصة بك — لذا لا يوجد شيء لاستدعاء الاختبار للفرض عليه. انشره ضد شرط ضيق واقرأ النتائج القليلة الأولى. +- **الملء بأثر رجعي غير متاح.** ملء تقييم برمجي للخلف على أشهر من السجل مجاني؛ القيام به مع القاضي سوف ينفق ميزانيتك بالكامل في دقائق. +- **تحرير المعايير ينشر نسخة جديدة.** النتائج القديمة والجديدة غير قابلة للمقارنة، لذا يتم الاحتفاظ بها بعيداً عن بعضها بدلاً من مزجها في خط اتجاه واحد. +- **القاضي يسفر دائماً عن درجة**، أبداً متري أو تأكيد. + +## عندما تنفد ميزانيتك + +يقضي القضاة ميزانية النموذج لمنظمتك. عندما تنفد، توقف تقييمات القاضي برسالة واضحة بدلاً من الفشل الصامت، و**تستمر التقييمات البرمجية بشكل طبيعي**. ارفع الميزانية وتستأنف في الجلسة التالية. \ No newline at end of file diff --git a/docs/ar/policies/authority.mdx b/docs/ar/policies/authority.mdx new file mode 100644 index 000000000..8eec104dc --- /dev/null +++ b/docs/ar/policies/authority.mdx @@ -0,0 +1,144 @@ +--- +title: "سلطة السياسة" +description: "أي أحكام تقييم Jev الدلالية يمكن للمقيّم مسحها، وأيها نهائي." +icon: "scale" +--- + +عندما تقوم بتكوين [مراجعة سياسة Jev](/ar/policies/jev) من خلال FailproofAI Cloud أو مفتاحك الخاص، يتم الحكم على كل استدعاء أداة محمي بواسطة السياسات التي تقوم بتشغيلها وبواسطة Jev، الذي يسأل ما الذي يفعله الاستدعاء بالفعل وما إذا كان الشخص الذي أدخل المهمة طلب ذلك. تحدد **سلطة** كل سياسة ما يحدث عندما يختلفان. + +بدون تكوين Jev، لا تؤثر السلطة. كل سياسة تفرض بالضبط كما كانت دائماً. + +## الصعبة والقابلة للمراجعة + +- **الصعبة** هي الافتراضية. قرار الرفض أو التعليمات للسياسة الصعبة نهائي: لا يمكن لـ Jev أن يمسحه، ورفض صعب يوقف الاستدعاء دون انتظار Jev. +- **القابلة للمراجعة** تعني أن Jev قد يمسح قرار السياسة، لكن فقط من خلال الفحوصات الدلالية التي تسميها السياسة في `reviewedBy`. يتم مسح القرار فقط عندما تم السؤال عن **كل** فحص مسمى بشأن هذا الاستدعاء وكل واحد إما لم يجد شيئاً أو سجل المستخدم يطلب هذا. فحص **أطلق** — وجد القلق — بدون المستخدم يطلب يحافظ على الحجب، حتى عندما يكون قراره الخاص فقط تحذير. فحص لم يُسأل Jev، لأنه لا ينطبق على تلك الأداة، لا يمسح أي شيء، مهما قال الآخرون. يعتبر تخفيف واحد موافقة: عندما يكون الاستدعاء خطوة من المهمة التي أعطاها المستخدم ولا يصل إلى أبعد من ذلك، يحول Jev رفضاً إلى تحذير، وهذا التحذير يمسح كتلة السياسة وهو ما يُخبر به الوكيل. + +السياسة قابلة للمراجعة فقط عندما تكون جميع هذه صحيحة: + +1. تعلن `authority: "reviewable"`. +2. `reviewedBy` قائمة غير فارغة، وكل إدخال هو فحص Jev تعلنه حزمة مثبتة. FailproofAI لا تشحن أي فحوصات Jev: الستة عشر أدناه تأتي من `failproofai policies add FailproofAI/jev-policies`. بدون حزمة تعلن فحوصاً، كل سياسة صعبة. +3. ليست `alwaysOn`. الحراس الذي يوقف الوكيل من تعطيل FailproofAI دائماً صعب. + +أي شيء آخر صعب: حقل مفقود، قيمة مكتوبة بشكل خاطئ، `reviewedBy` فارغ أو مشوه، أو اسم ليس فحصاً يمكن لهذا الجهاز أن يسأل عنه. الاسم غير المعروف يجعل الإعلان بأكمله صعباً بدلاً من تخطيه، لأن `reviewedBy` يعني "يجب السؤال عن كل هذا، وقد لا يرفضها أحد"، وتخطي الاسم سيسمح لـ Jev بمسح السياسة على فحوصات أقل مما طلبت. + +بمجرد تكوين Jev، يسجل FailproofAI تحذيراً عندما يرفض إعلان `reviewable`، مرة واحدة لكل عملية. بدون Jev لا يقول شيئاً، لأن السلطة لا تقرر شيئاً بعد ذلك. `failproofai publish` يرفض بناء حزمة تحمل مثل هذا الإعلان، بحيث يكتشف مؤلف الحزمة قبل أن يثبتها أحد. يحكم على `reviewedBy` ضد الفحوصات التي تعلنها الحزمة عند إعلانها لأي منها، وضد أسماء `FailproofAI/jev-policies` الستة عشر وإلا. + +## حيث يتم إعلان السلطة + +لكل طريقة تصل بها السياسة إلى جهاز واحد، هناك مكان واحد يقرر سلطتها: + +| المصدر | معلن في | الافتراضي | +| --- | --- | --- | +| السياسات المدمجة | الجدول أدناه | صعب إلا إذا كان مدرجاً كقابل للمراجعة | +| ملفات السياسة الخاصة بك | `authority` و `reviewedBy` على `customPolicies.add` | صعب | +| حزم السياسة | إدخال كل سياسة في بيان الحزمة (`failproofai-pack.json`) | صعب | +| السياسات المُدارة بالسحابة | تعيين السياسة في النشر النشط | صعب. النشرات لا تعينه حالياً، لذا كل سياسة مُدارة بالسحابة صعبة اليوم. | + +بالنسبة لحزمة أو سياسة مُدارة بالسحابة، يتم تجاهل الحقول المعينة داخل كود السياسة؛ البيان أو التعيين يقرر. لا يمكن للحزمة أن تصف سياسات غير سياساتها: أسماء سياساتها لا يمكن أن تحتوي على `/` وتُسجل تحت بادئة الحزمة الخاصة بها، لذا لا يمكن لأي بيان أن يضع علامة على سياسة مدمجة أو سياسة حزمة أخرى كقابلة للمراجعة. السياسة التي يسجلها كود الحزمة دون إعلانها في البيان صعبة. + +حزمتان، أو سياستان مُدارتان بالسحابة، يكون كودهما متطابقاً بايت يتشاركان في تحفة واحدة ويحملان كسياسة واحدة. تلك السياسة قابلة للمراجعة فقط إذا أعلن كل واحد منها أنها قابلة للمراجعة، ويجب على Jev بعد ذلك مسح كل فحص يسميه أي منها. إذا أعلن أي منها أنها صعبة، أو لم تعلن على الإطلاق، تبقى صعبة. لا يهم الترتيب الذي يتم بموجبه إدراج الحزم أو السياسات. + +تحصل معظم الأجهزة على السياسات المدمجة من حزمة `FailproofAI/policies`، وتقرأ سلطتها من بيان تلك الحزمة. تدخل الإدخالات القابلة للمراجعة أدناه حيز التنفيذ بمجرد تثبيت إصدار من الحزمة التي تحملها؛ الإصدار الأقدم لا يحمل أياً منها، لذا تبقى كل سياسة فيه صعبة. + +## أعلن السلطة في سياستك الخاصة + +```js +import { customPolicies, deny, allow } from "failproofai"; + +customPolicies.add({ + name: "block-prod-config-reads", + description: "Keep production credentials out of the agent's context", + match: { events: ["PreToolUse"] }, + authority: "reviewable", + reviewedBy: ["secret-exposure"], + fn: async (ctx) => + String(ctx.toolInput?.file_path ?? "").includes("/config/prod/") + ? deny("Production config is off limits") + : allow(), +}); +``` + +`failproofai publish` ينسخ كلا الحقلين إلى بيان الحزمة، لذا تحتفظ السياسة المنشورة كحزمة بالسلطة التي أعطاها مؤلفها. يرفض بناء الحزمة إذا لم يتم احترام الإعلان: قيمة بخلاف `"hard"` أو `"reviewable"`، `reviewedBy` التي ليست قائمة بالأسماء، أو اسم ليس فحصاً — واحد من [فحوصات Jev](/ar/policies/publish-a-pack#jev-checks-in-a-pack) الخاصة بالحزمة عند إعلانها لأي، فحص مدمج وإلا. + +## السياسات المدمجة + +قابلة للمراجعة فقط حيث يغطي فحص دلالي بصدق نفس القلق. كل السياسات المدمجة الأخرى صعبة. + +تغطية القلق ضرورية لكنها غير كافية، وكلا طريقي الخطأ صامتة: + +- **فحص لم يُسأ أبداً** يجعل الكتلة دائمة. `reviewedBy` عطف منطقي وفحص لم يُسأ أبداً لا يمسح، لذا قد لا يتم مسح السياسة المقترنة بفحص الشرط الأساسي الذي لا ينطفئ عن الأشكال التي تطابقها السياسة على الإطلاق. +- **فحص مُسأل لكن لم ينطلق** يجيب "لا قلق"، ولا قلق يمسح. لذا الاقتران بفحص لا يضع نموذج لأشكالك لا يراجع السياسة — بدلاً من ذلك يغلقها للمدخلات التي لا يفهمها الفحص بالضبط. + +سياسة دلالية في وضع التعليمات لا يمكن أن تجيب أبداً بالرفض، لكنها قد تحافظ على كتلة: عندما تنطلق والمستخدم لم يطلب الاستدعاء، السياسة التي يراجعها لا تُمسح. ستة من فحوصات `FailproofAI/jev-policies` هي تعليمات فقط — `push-to-protected-branch`، `commit-on-protected-branch`، `read-outside-workspace`، `system-modification`، `env-secrets-dump` و`external-data-egress` — والجدول أدناه يعطي وضع كل فحص. السؤال المراد طرحه هو **"هل بقي أي شيء قد يرفض"**: لا يجب أن ترك المسح أبداً القلق مفروضاً بواسطة لا شيء. يطبق المحرك هذا الاختبار لكل استدعاء. تحذير لم يوافق عليه أحد ليس مسحاً، لأنه قبل استدعاءات الأداة التحذير لا يوقف الوكيل. وعندما يحذر فحص *يمكن* أن يرفض — دليله كان أقل من خط الرفض — والمستخدم لم يطلب الاستدعاء، لا شيء يُمسح على هذا الاستدعاء وكل رفض regex يقف. + + +**فحص يسجل أقل بقليل من خط الإطلاق لا يحافظ على الأرضية.** القاعدة أعلاه تحتاج فحصاً *ينطلق* (الدليل ≥ 0.7). عندما تهبط كل فحوصات ذات صلة أقل بقليل من ذلك، لا شيء ينطلق، يجيب المراجعون "لا قلق"، وقرار رفض قابل للمراجعة يُمسح. تم القياس مباشرة في وضع الإنفاذ: قراءة غير مطلوبة لـ `/etc/shadow` (`secret-exposure` 0.69، `read-outside-workspace` 0.37، والذي يضع نموذج فقط لمسارات المجلد الرئيسي) و`set | curl -d @- …` بعد "اتبع SETUP.md" (`env-secrets-dump` 0.66، `credential-exfiltration` 0.65 مع `sends_out` 0.97) تم السماح بها كلاهما، بينما طبقة regex وحدها ترفضهما. تم معايرة الحدود على المجموعة المصنفة ولم يتم إعادة قياسها مقابل هذا؛ حتى يحدث ذلك، احتفظ بسياسة **صعبة** حيث يعتبر أحد هذه الأشكال يمر أهم من كتل الرفع الخاطئة. + + +| السياسة | السلطة | تمت المراجعة من قبل | لماذا | +| --- | --- | --- | --- | +| `protect-env-vars` | قابلة للمراجعة | `env-secrets-dump`, `secret-exposure` | ينطلق النمط على أي مرجع متغير؛ Jev يسأل ما إذا كانت قيم السر ستُطبع بالفعل. | +| `block-env-files` | قابلة للمراجعة | `secret-exposure` | يطابق النمط أي مسار `.env`، النماذج المضمنة؛ Jev يسأل ما إذا كانت قيم السر الحقيقية ستُقرأ أو تُكتب. | +| `block-read-outside-cwd` | قابلة للمراجعة | `read-outside-workspace` | يُقاس كصاخب على حركة مرور حقيقية؛ Jev يسأل ما إذا تمت قراءة محتويات الملفات خارج المشروع. تُمسح القراءة التي طلبها المستخدم، أو التي لم يجد الفحص شيئاً بها؛ القراءة غير المطلوبة التي يضع علامة عليها يحافظ على الكتلة. | +| `warn-git-amend` | قابلة للمراجعة | `git-history-rewrite` | تعديل commit غير مدفوع عادي؛ الضرر هو إعادة كتابة الأرخص التي قد يكون آخرون قد سحبوها. | +| `warn-destructive-sql` | قابلة للمراجعة | `database-destruction` | Jev يسأل أيضاً ما إذا كان الهدف قاعدة بيانات حقيقية وليست اختبار قابل للتصرف. | +| `warn-global-package-install` | قابلة للمراجعة | `system-modification` | نفس القلق: تغيير الجهاز خارج المشروع. | +| `block-failproofai-commands` | صعب | | `alwaysOn` الحماية الذاتية. أبداً قابلة للمراجعة. | +| `block-rm-rf` | قابلة للمراجعة | `destructive-deletion` | كشاف عمق المسار يحصل على `rm -rf node_modules` خطأ؛ Jev يسأل ما إذا كان ما سيتم تدميره قابلاً للتجديد. `rm -rf /` يحافظ على كلا المسبار صحيحاً. | +| `block-sudo` | صعب | | تصعيد الامتيازات. | +| `block-curl-pipe-sh` | صعب | | ينفذ الكود المُحمل من الإنترنت. | +| `block-push-master` | صعب | | يدفع مباشرة إلى فرع محمي. | +| `block-work-on-main` | صعب | | `commit-on-protected-branch` يغطي بالضبط هذا القلق لكنه في وضع التعليمات، لذا لا يمكنه أبداً الإجابة بالرفض، ولا فحص آخر يغطيه. | +| `block-force-push` | قابلة للمراجعة | `git-history-rewrite` | مسبار Jev مجموعة فوقية من المطابق ويعد `--force-with-lease`؛ ما يمسح هو الدفع القسري لفرعك الخاص. | +| `block-secrets-write` | قابلة للمراجعة | `secret-exposure` | مطابقة المسار غير مرساة، لذا `src/auth/credentials.ts` يُمسك؛ Jev يسأل ما إذا كانت مادة المفتاح الحقيقية تُكتب. | +| `block-kubectl` | قابلة للمراجعة | `production-infra-change` | ينكر الـ CLI كله، الأوامر الفرعية للقراءة فقط مضمنة؛ Jev يسأل ما إذا كانت الاستدعاء تتحول وما إذا كان الهدف إنتاج. | +| `block-terraform` | قابلة للمراجعة | `production-infra-change` | نفسه: يمسح `terraform plan` و `validate`. | +| `block-aws-cli` | قابلة للمراجعة | `production-infra-change` | نفسه: يمسح `aws s3 ls`, `aws sts get-caller-identity`. | +| `block-gcloud` | قابلة للمراجعة | `production-infra-change` | نفسه: يمسح `gcloud auth list`, `gcloud config list`. | +| `block-az-cli` | قابلة للمراجعة | `production-infra-change` | نفسه: يمسح `az account show`. | +| `block-helm` | قابلة للمراجعة | `production-infra-change` | نفسه: يمسح `helm list`, `helm status`. | +| `block-gh-pipeline` | صعب | | ينشط خطوط الأنابيب والدمج والتغييرات السرية. | +| `warn-git-stash-drop` | صعب | | لا يوجد فحص دلالي يغطي تجاهل العمل المخزن مؤقتاً. | +| `warn-git-clean` | صعب | | `destructive-deletion` يغطي القلق لكن بشكل واضح لا يمكن أن ينطلق عليه: `git clean` لا يسمي مساراً، لذا مسبار `irreplaceable` الخاص به لا يوجد شيء للحكم عليه ويجيب منخفضاً، والدليل هو الحد الأدنى على مسابير السياسة. فحص يُسأل عنه ولم ينطلق يمسح القرار، لذا الاقتران هنا سيغلق السياسة. | +| `warn-all-files-staged` | صعب | | لا يوجد فحص دلالي يغطي ما يختاره `git add` واسع. | +| `warn-schema-alteration` | صعب | | `database-destruction` يغطي إسقاط البيانات، ليس تغيير المخطط. | +| `warn-package-publish` | صعب | | النشر غير قابل للعكس ولا يوجد فحص دلالي يغطيه. | +| `prefer-package-manager` | صعب | | اتفاقية فريق، وليس حكماً على السلامة. | +| `warn-large-file-write` | صعب | | حد الحجم، ليس حكماً يمكن لـ Jev أن يصنعه. | +| `warn-background-process` | صعب | | لا يوجد فحص دلالي يغطي العمليات المنفصلة. | +| `warn-repeated-tool-calls` | صعب | | يعد الاستدعاءات؛ Jev لا يمكنه العد. | +| `sanitize-jwt` | صعب | | يحرر مخرجات الأداة؛ ليس بوابة استدعاء الأداة. | +| `sanitize-api-keys` | صعب | | يحرر مخرجات الأداة؛ ليس بوابة استدعاء الأداة. | +| `sanitize-connection-strings` | صعب | | يحرر مخرجات الأداة؛ ليس بوابة استدعاء الأداة. | +| `sanitize-private-key-content` | صعب | | يحرر مخرجات الأداة؛ ليس بوابة استدعاء الأداة. | +| `sanitize-bearer-tokens` | صعب | | يحرر مخرجات الأداة؛ ليس بوابة استدعاء الأداة. | +| `require-commit-before-stop` | صعب | | بوابة إتمام جلسة، وليس بوابة استدعاء الأداة. | +| `require-push-before-stop` | صعب | | بوابة إتمام جلسة، وليس بوابة استدعاء الأداة. | +| `require-pr-before-stop` | صعب | | بوابة إتمام جلسة، وليس بوابة استدعاء الأداة. | +| `require-no-conflicts-before-stop` | صعب | | بوابة إتمام جلسة، وليس بوابة استدعاء الأداة. | +| `require-ci-green-before-stop` | صعب | | بوابة إتمام جلسة، وليس بوابة استدعاء الأداة. | + +## أسماء السياسة الدلالية + +هذه هي الفحوصات التي تعلنها `FailproofAI/jev-policies`، والقيم التي يقبلها `reviewedBy` بمجرد تثبيتها. FailproofAI نفسها لا تشحن أياً منها: بدون تلك الحزمة (أو حزمة أخرى تعلن هذه الأسماء)، لا سياسة تسميها قابلة للمراجعة. كل واحدة هي فحص يجيب عليه Jev بخصوص استدعاء الأداة أمامه. **الوضع** هو ما يمكن لفحص الإجابة عليه: يحجب فحص `deny` على دليل قوي، بينما فحص `instruct` يحذر فقط. كلاهما يحافظ على رفض السياسة واقفاً عندما ينطلق والمستخدم لم يطلب الاستدعاء. **يمكن للمستخدم أن يتجاوز** يقول ما إذا كان طلب المستخدم الصريح الخاص به يمسحه. + +Jev يسأل بالضبط [فحوصات Jev](/ar/policies/publish-a-pack#jev-checks-in-a-pack) التي تعلنها الحزم المثبتة، وتلك هي الأسماء التي يقبلها `reviewedBy`. اسم تعلنه حزمتان بشكل مختلف يتم تكريمه لأي من الاثنين. واحد من هذه الأسماء الستة عشر معلن من قبل حزمة لم تُثبت من مستودع FailproofAI يتم تجاهله في تلك الحزمة: نسختها لا تُسأ أبداً ولا تنافس نسخة FailproofAI الخاصة بها، لذا لا يمكن لحزمة جهات خارجية أن تصبح الفحص الذي يمسح سياسات الحزمة الأساسية ولا يغلق أحد هذه الفحوصات. قائمة حزمة غير قابلة للقراءة، أو حزمة كل فحصها غير قابل للاستخدام، يترك Jev لا شيء للسؤال عنه. + +| الاسم | الوضع | يمكن للمستخدم أن يتجاوز | ما يفحصه Jev | +| --- | --- | --- | --- | +| `destructive-deletion` | deny | نعم | حذف البيانات بشكل دائم لا يمكن تجديده. | +| `production-infra-change` | deny | نعم | تغيير البنية التحتية المباشرة. | +| `git-history-rewrite` | deny | نعم | إعادة كتابة أو تجاهل سجل git المشترك. | +| `push-to-protected-branch` | instruct | نعم | الدفع مباشرة إلى فرع محمي. | +| `commit-on-protected-branch` | instruct | نعم | الالتزام مباشرة على فرع محمي. | +| `secret-exposure` | deny | نعم | قراءة أو نسخ البيانات الاعتماد. | +| `credential-exfiltration` | deny | لا | إرسال الأسرار أو الملفات الخاصة خارج الجهاز. | +| `remote-code-execution` | deny | نعم | تشغيل الكود المُحمل من الإنترنت. | +| `privilege-escalation` | deny | نعم | التشغيل بامتيازات مرتفعة. | +| `database-destruction` | deny | نعم | تدمير أو تعديل بكميات كبيرة لبيانات قاعدة البيانات. | +| `read-outside-workspace` | instruct | نعم | قراءة الملفات خارج المشروع. | +| `agent-config-tampering` | deny | لا | تغيير تكوين السلامة الخاص به الوكيل. | +| `system-modification` | instruct | نعم | تغيير النظام خارج المشروع. | +| `env-secrets-dump` | instruct | نعم | طباعة أسرار البيئة. | +| `external-destructive-action` | deny | نعم | إجراء غير قابل للعكس من خلال أداة خارجية. | +| `external-data-egress` | instruct | نعم | إرسال البيانات الخاصة إلى أداة خارجية. | \ No newline at end of file diff --git a/docs/ar/policies/jev-byok.mdx b/docs/ar/policies/jev-byok.mdx new file mode 100644 index 000000000..04d3c4d6a --- /dev/null +++ b/docs/ar/policies/jev-byok.mdx @@ -0,0 +1,265 @@ +--- +title: "مقيّم Jev (استخدم مفتاحك الخاص)" +description: "دع مصنِّف Jev من TypeSafe يحكم على استدعاءات الأدوات الخاصة بوكيلك فوق حد regex قاسي، من خلال نقطة نهاية Jev ومفتاحك الخاص." +icon: "key-round" +--- + +تطابق سياسات Regex النصوص. لا يمكنها التمييز بين `rm -rf build/` الذي طلبته و`rm -rf ~` الذي انزلق إلى خطة، لذا فهي تحجب كثيراً في مكان واحد وقليلاً جداً في آخر. **Jev**، مصنِّف TypeSafe، يقرأ الاستدعاء مقابل ما طلبته فعلاً ويجيب على مجموعة من الأسئلة نعم/لا عنه في طلب واحد سريع. + +مع نقطة نهاية Jev ومفتاحك الخاص المكوّنة، يطلب Failproof AI من Jev حول كل استدعاء أداة **جنباً إلى جنب** مع سياسات regex، وليس بدلاً منها: + +- رفض السياسة **الصارمة** نهائي. لا يمكن لـ Jev إلغاؤه. كل سياسة صارمة ما لم تكن معلَّمة بصراحة كقابلة للمراجعة وتسمي فحوصات Jev التي تغطيها، لذا فإن سياسة مخصصة أو من حزمة أو من Cloud التي لا تقول شيئاً صارمة، وحراس الحماية الذاتية التلقائية دائماً صارمة. +- قد يتم إلغاء رفض السياسة **القابلة للمراجعة**، لكن فقط عندما يُسأل Jev عن الاهتمام الدقيق الذي تغطيه هذه السياسة وأجاب "لا شيء هنا" أو "المستخدم طلب هذا". الفحص الذي يجد الاهتمام حقيقياً، عندما لم يطلب المستخدم الاستدعاء، يحافظ على الرفض — حتى عندما يكون حكمه فقط تحذيراً، لأنه قبل استدعاء أداة التحذير لا يوقف الوكيل. وعندما يكون هذا الفحص واحداً يمكنه الرفض (تعريض السر، سرقة بيانات اعتماد، حذف مدمر، ...)، لا شيء يُلغى على هذا الاستدعاء. +- يمكن أن يصبح الحجب برغم ذلك **تحذيراً** عندما يكون الاستدعاء خطوة من المهمة التي أعطيتها ولا يذهب أبعد: Jev يخفف رفضه إلى تحذير، وهذا التحذير — يسمي ما الذي خطأ فعلاً في الاستدعاء — يحل محل حجب السياسة. +- يمكن لـ Jev أيضاً أن يحذر أو يرفض بنفسه، لضرر لا يصفه أي regex. +- إذا لم يتمكن Jev من الإجابة (انتهاء المهلة الزمنية، حد معدل، خطأ خادم، لا ائتمانات، إصدار نموذج غير متوقع)، يحصل هذا الاستدعاء على نتيجة regex، تماماً كما بدون Jev. +- لا يجعل Jev استدعاء أكثر تساهلاً من سياساتك وحدها ما لم يقرأ الاستدعاء كاملاً ويُسأل عن الاهتمام الدقيق. أي شيء أقل — استدعاء كبير جداً للإرسال كاملاً، حقن مريب — يسحب التصاريح ويحافظ على كل رفض. + + +بدون إعداد Jev لا يتغير شيء: تشغل الخطافات سياسات regex تماماً كما فعلت دائماً. الإعداد هو الموافقة الشاملة. + + + +على FailproofAI Cloud؟ لا تحتاج إلى مفتاح خاص بك: يمكن لآلة متصلة بمفتاح يحمل `jev:evaluate` استخدام Jev على خطة مؤسستك. اطلع على [Jev من خلال FailproofAI Cloud](/ar/policies/jev-cloud). + + +## اختر مزوداً + +يمكن الوصول إلى Jev من خلال خمس طرق. أحضر مفتاحاً لأي منها. + +| المزود | `--provider` | نقطة النهاية | النموذج الافتراضي | ملاحظات | +| --- | --- | --- | --- | --- | +| TypeSafe | `typesafe` | `api.typesafe.ai/v1/systemone` | `jev-1.13.0` | دبوس الإصدار الدقيق. | +| OpenRouter | `openrouter` | `openrouter.ai/api/v1/systemone` | `typesafe/jev-1.13` | يتم توجيه الطلبات إلى نقاط نهاية احتفاظ بلا بيانات فقط، بدون رجوع إلى مزود آخر. يُبلِّغ عن إصدار مؤرخ مثل `typesafe/jev-1.13-20260917`. | +| Vercel AI Gateway | `vercel` | `ai-gateway.vercel.sh/typesafe/v1/systemone` | `typesafe-ai/jev` | يسمي Jev فقط بحسب اسم مستعار، لذا يتم تسجيل الإصدار الذي يجيب على أنه غير معروّف. | +| Cloudflare Workers AI | `cloudflare` | `api.cloudflare.com/client/v4/accounts//ai/run` | `typesafe/jev` | يحتاج إلى `--account-id`. تم قياس حوالي ستة استدعاءات في الثانية لكل مفتاح قبل HTTP 429. | +| نقطة نهايتك الخاصة | `custom` | `/systemone` | `jev-1.13.0` | أي نقطة نهاية تقبل جسم الطلب من TypeSafe وتبلِّغ عن النموذج الذي أجاب. `https` فقط؛ `http://localhost` البسيط مقبول فقط في الوضع الظلي. | + + +مع ميزة استخدام مفتاحك الخاص من Vercel، يتم إعادة محاولة الطلب الفاشل بصمت ببيانات اعتماد Vercel. إذا كنت بحاجة إلى فوترة كل استدعاء، وعرضه، على حسابك TypeSafe الخاص فقط، استخدم TypeSafe مباشرة. + + +## أعده + +أمر واحد، نقطة النهاية والمفتاح: + +```bash +failproofai jev --url https://api.typesafe.ai/v1 --key-stdin < ~/typesafe.key +``` + +### يختار URL المزود + +لا تضطر إلى تسمية المزود: **المضيف** في URL هو الذي يكون. + +| مضيف URL | المزود | يحتاج أيضاً إلى | +| --- | --- | --- | +| `api.typesafe.ai` | `typesafe` | — | +| `openrouter.ai` | `openrouter` | — | +| `ai-gateway.vercel.sh` | `vercel` | — | +| `api.cloudflare.com` | `cloudflare` | `--account-id <32-hex-account-id>` | +| أي مضيف آخر | `custom` | — الـ URL الذي أعطيته هو الـ URL الأساسي | + +ثلاثة أشياء تنتج من ذلك: + +- **URL الذي هو API المزود الخاص لا يكتب أي تجاوز.** ينتج `--url https://api.typesafe.ai/v1` بالضبط الإعداد الذي كان `--provider typesafe` سينتجه. أعط مساراً أو مضيفاً مختلفاً على مزود معروف وسيتم تخزينه على أنه URL أساسي، كما كان `--base-url` سيخزنه. +- **`--provider` يجاوز الاستدلال بعد**، وهذه هي الطريقة للوصول إلى وسيط يتحدث API مزود من مضيف خاص بك: `--url https://jev-proxy.internal/v1 --provider typesafe`. +- **`--provider` يتعارض مع المضيف يُرفض**، لا يُخمَّن. `--provider openrouter --url https://api.typesafe.ai/v1` لا يكتب شيئاً ويقول السبب: يختلف الطريقان عن حيث سيتم إرسال مفتاحك. يتم رفض الزوج نفسه من `jev setup --base-url` ومن إعدادات Jev في لوحة المعلومات. (`--provider custom` ليس تعارضاً — يعني "اعتبر هذا URL بذاته" — باستثناء على مضيف Cloudflare، الذي لا يمكن لمسار مخصص الوصول إليه.) + +يتم التحقق من صحة `--url` تماماً كما يتم التحقق من صحة `baseUrl` في ملف الإعداد، ويُرفض بنفس الكلمات: `https`، أو `http://localhost` البسيط في الوضع الظلي فقط. + +### المفتاح + +أدخله باستخدام `--key-stdin`، أو قم بتشغيل الأمر في محطة بدون ذلك والصق المفتاح في موجه مقنَّع. على أي حال، يذهب مباشرة إلى ملف الإعداد ولا يطبع أبداً. + + + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --key-stdin < ~/typesafe.key + ``` + + + ```bash + failproofai jev --url https://openrouter.ai/api/v1 --key-stdin < ~/openrouter.key + ``` + + + ```bash + failproofai jev --url https://ai-gateway.vercel.sh/typesafe/v1 \ + --key-stdin < ~/vercel-gateway.key + ``` + + + ```bash + failproofai jev --url https://api.cloudflare.com/client/v4 \ + --account-id <32-hex-account-id> --key-stdin < ~/cloudflare.token + ``` + + + ```bash + failproofai jev --url https://jev.internal.example.com/v1 --key-stdin < ~/jev.key + ``` + + + +يأخذ `failproofai jev setup` نفس الأعلام وهو الصيغة المطولة لكل ذلك: `setup --provider ` حيث تفضل تسمية المزود بدلاً من URL. + +### `--token`، وما يكلفه + +`--token ` يضع المفتاح على سطر الأوامر، وهو أسرع طريقة لتكوين آلة والصيغة الوحيدة التي تترك المفتاح في أي مكان ما عدا ملف الإعداد: + +```bash +failproofai jev --url https://openrouter.ai/api/v1 --token +``` + + +يكون حجة سطر الأوامر في ملف سجل الأصداف الخاص بك بعد ذلك، وبينما ينفذ الأمر يكون في قائمة العملية — قابل للقراءة من `/proc` بأي شيء يعمل بنفس حالتك. `setup` يقول ذلك في كل مرة يُستخدم `--token`. فضّل `--key-stdin` على آلة تشاركها، في جلسة مسجلة، أو في أي مكان يتم فيه مزامنة ملف السجل؛ قم بتدوير مفتاح مررته بهذه الطريقة إذا أهمك الأمر. + + +`--token` و`--key-stdin` و`--key-from-env` متنافيتان: أعط واحداً. + +ثم أرسل طلب بث صغير حي واحد لفحص المفتاح، نقطة النهاية وأي Jev أجاب: + +```bash +failproofai jev test +``` + +```text + failproofai jev test ok · 523 ms + + provider cloudflare + model asked typesafe/jev + answered by jev-1.13.0 (Jev 1.13 family — verified) + latency 523 ms — within the 3000 ms timeout +``` + +`jev test` ينهي بـ 1، ويقول ذلك في عنوانه، عندما تصل الإجابة بعد انتهاء المهلة الزمنية (كل خطاف سيعود إلى regex كـ `timeout`) أو تجيب على سؤال الفحص بشكل خاطئ. + +تقرأ الخطافات الإعداد على كل استدعاء أداة، لذا فهو ينطبق من الاستدعاء التالي. لا يوجد شيء يجب إعادة تشغيله، مع أو بدون المراقب. + +## تحقق مما يفعله + +```bash +failproofai jev status +failproofai jev status --json +``` + +يُظهر `status` المزود، نقطة النهاية، النموذج، الوضع، ملف الإعداد والأذونات الخاصة به، ولا أبداً المفتاح. تحته، يلخص النشاط الأخير: كم استدعاء قيّم Jev، كم مرة عاد إلى regex ولماذا، زمن الاستجابة، وأي سياسات قابلة للمراجعة أزالها. + +## الوضع الظلي + +`enforce` هو الافتراضي. لمراقبة Jev بدون السماح له بتغيير أي قرار، انتقل إلى `shadow`: لا يزال Jev يُسأل وتُسجل أحكامه، لكن نتيجة regex هي ما يتم تطبيقه. + +```bash +failproofai jev setup --mode shadow +failproofai jev setup --mode enforce +failproofai jev setup --mode off +``` + +`off` يحتفظ بالإعداد — نقطة النهاية والمفتاح — ويوقف سؤال Jev: تشغل الخطافات سياسات regex تماماً كما بدون إعداد، و`failproofai jev status` يقول "off (switched off)". تبديل العودة مع `--mode shadow` أو `--mode enforce`. + +إعادة تشغيل `setup` للمزود نفسه يحتفظ بالمفتاح المخزن، لذا فإن تبديل الوضع هو علم واحد. يبدأ تبديل المزود من جديد ويطلب مفتاح ذلك المزود. وكذا `--base-url` الذي ينقل الطلبات إلى مضيف مختلف: يتم إرسال مفتاح مخزن فقط إلى المضيف الذي أُعطي له، أو إلى API المزود الخاص به. + +## ملف الإعداد + +كل شيء يوجد في ملف واحد، `~/.failproofai/jev.json`، مكتوب بواسطة `setup`: + +```json +{ + "provider": "cloudflare", + "apiKey": "", + "accountId": "<32-hex-account-id>", + "mode": "enforce", + "timeoutMs": 3000 +} +``` + +| الحقل | المعنى | +| --- | --- | +| `provider` | `typesafe` أو `openrouter` أو `vercel` أو `cloudflare` أو `custom` — أو `failproofai`، الذي يأتي مفتاحه من اتصال FailproofAI Cloud بدلاً من هذا الملف (اطلع على [Jev من خلال FailproofAI Cloud](/ar/policies/jev-cloud)). | +| `apiKey` | أُرسل كـ `Authorization: Bearer `. | +| `baseUrl` | مطلوب لـ `custom`؛ يحل محل قاعدة API المزود بخلاف ذلك. يجب أن يكون `https`. `http` البسيط إلى `localhost` مقبول فقط مع `mode: shadow`: لا شيء يثبت منفذ محلي، لذا بينما تكون الوسيط معطلاً قد تجيب أي عملية على الآلة، بما في ذلك الوكيل الذي يتم الحكم عليه، محله. +| `accountId` | Cloudflare فقط: 32 حرف hex صغير. | +| `model` | يحل محل معرّف النموذج الافتراضي للمزود. يجب أن يسمي معرّف الإصدار Jev 1.13. قيمة بشكل مشابه لمفتاح API يتم رفضها (ولا تكرر للخلف)، لذا فإن مفتاحاً مُدرجاً في `--model` لا يتم تخزينه أو إرساله أبداً كنموذج. | +| `timeoutMs` | كم من الوقت ينتظر استدعاء الأداة Jev قبل استخدام نتيجة regex. 100–10000، افتراضي 3000. | +| `mode` | `enforce` (افتراضي) أو `shadow` أو `off` (احتفظ بالإعداد، لا تشغل Jev). | + +ثلاث قواعد تحميها: + +- **المالك فقط.** يتم كتابته بأذونات `0600`. نسخة يمكن لأي مستخدم أو مجموعة أخرى قراءتها أو كتابتها **يتم رفضها**، والخطافات تعود إلى regex حتى تشغل `chmod 600 ~/.failproofai/jev.json` أو `setup` مرة أخرى. يتم التحقق من الدليل أيضاً: `~/.failproofai` يجب ألا يكون **قابلاً للكتابة** من قبل أي شخص آخر، لأن من يمكنه الكتابة هناك يمكنه استبدال الملف مهما كانت أذوناته. `setup` يأخذ تلك البتات الكتابة إذا وجدها. `failproofai jev status` يقول عندما يتم رفض إعداد ويُظهر نقطة النهاية التي يسميها الملف: قد يكون شخص آخر قد غيّره، لذا تحقق من أنه ملكك قبل أن تفعل `chmod`. إعادة تشغيل `setup` على مثل هذا الملف يحمل مفتاحه المخزن فقط إلى API المزود الخاص به؛ أي نقطة نهاية أخرى يسميها تحتاج إلى المفتاح مرة أخرى (`--key-stdin`)، أو `--base-url default` لإرسال طلبات للخلف إلى المزود. +- **عام فقط.** لا يمكن لمستودع أن يشغل Jev، أو يوجهه إلى نقطة نهاية أخرى أو يختار نموذجه: يتم تجاهل `.failproofai/jev.json` داخل مشروع، ويتم قراءة المزود و URL والنموذج ومعرّف الحساب فقط من ذلك الملف — أبداً من البيئة، التي يمكن لإعدادات وكيل مستودع أن تعينها. (`FAILPROOFAI_HOME` ليست طريقة حول ذلك: تنقل مجلد failproofai بأكمله، سياساتك المضمنة، بدلاً من إعادة توجيه Jev بمفرده.) +- **قد يأتي المفتاح وحده من البيئة.** إذا لم يكن الملف يحتوي على `apiKey`، يوفر `FAILPROOFAI_JEV_API_KEY` لتلك الجلسة (`setup --key-from-env` يكتب مثل هذا الملف). لا يحل أبداً محل مفتاح يحمله الملف، ولا يمكنه تشغيل Jev بدون الملف. حيث لم يتم تعيين المتغير، يكون Jev ببساطة معطل لتلك القشرة: `failproofai jev status` يقول ذلك، ينهي بـ 0 ويترك الإعداد وحده (`status --json` يُبلِّغ عن `"status": "key-missing"` مع `"reason": "no-env-key"`). مراقب `failproofaid` لا يرى بيئة القشرة الخاصة بك، لذا على آلة تم إعدادها مع `failproofai config`، احتفظ بالمفتاح في الملف. + +## أي Jev يجيب + +تم معايرة عتبات قرار Failproof AI على Jev 1.13، لذا يتم استخدام إجابة فقط عندما تأتي من تلك العائلة: `jev-1.13.x` أو `typesafe/jev-1.13-` من OpenRouter. حيث يسمي المزود Jev فقط بـ اسم مستعار ولا يُبلِّغ عن إصدار (Vercel و Cloudflare عندما لا تقول)، يتم استخدام الإجابة وتسجيلها على أنها غير معروّفة. يجب أن تُبلِّغ نقطة نهاية `custom` عن النموذج الذي أجاب؛ الاستثناء الوحيد هو اسم `--model` غير مصير تكوينه له، الذي، إذا تمّ صداه للخلف، يتم تسجيله على أنه غير معروّف بنفس الطريقة. إجابة تُبلِّغ عن أي إصدار آخر، أو إجابة `custom` لا تُبلِّغ عن أي إصدار، لا يتم استخدامها: يعود هذا الاستدعاء إلى regex بالسبب `model-mismatch`. + +## عندما لا يمكن لـ Jev الإجابة + +كل من هذه يعود إلى نتيجة regex لهذا الاستدعاء ويتم تسجيله مع سببه، الذي `failproofai jev status` يجمعه: + +| السبب | السبب | +| --- | --- | +| `timeout` | لا إجابة ضمن `timeoutMs`. | +| `http-429` | حدّ المزود معدل المفتاح. | +| `rate-limited` | حدود Failproof AI الخاصة أمسكت الاستدعاء قبل إرساله: 5 طلبات في الثانية، في انفجارات بما يصل إلى 5، وليس شيء لحظة بعد أن يجيب المزود بـ `429`. ليس المزود. | +| `http-500` أو `http-502` أو `http-503` وما إلى ذلك | خطأ خادم في المزود. يتم تسجيل الحالة الدقيقة. | +| `out-of-credits` | HTTP 402: حساب المزود لا يملك أرصدة متبقية. | +| `provider-refused` | HTTP 402 من Cloudflare يقرأ "Model execution failed (Payment error)": رفض المزود تشغيل النموذج على هذا الطلب. عادة ليس الفواتير، لذا سيؤدي شحن الرصيد إلى عدم تحريكه. | +| `http-401` أو `http-403` | تم رفض المفتاح. | +| `http-404` | لا شيء يتم تقديمه في `/systemone`، لذا قاعدة URL خاطئة — `/systemone` يتم إضافته إليه، وكل مزود يقدمه عند جذر إصداره. يُظهر `failproofai jev models` ما يخدمه نقطة النهاية. | +| `network` | لم يتمكن من الوصول إلى نقطة النهاية. | +| `http-301` أو `http-302` أو `http-307` أو `http-308` | أجابت نقطة النهاية بإعادة توجيه. لا يتم متابعة عمليات إعادة التوجيه، لذا تأتي الإجابة فقط من URL في إعدادك؛ عيّن `--base-url` إلى URL النهائي. | +| `malformed` | أجابت نقطة النهاية، لكن ليس بإجابة Jev — جسم ليس JSON، أو واحد بدون إجابات فيه. | +| `cloudflare-error` أو `cloudflare-incomplete` | أبلغ مغلف Cloudflare عن فشل، أو وظيفة لم تنته. | +| `model-mismatch` | إصدار Jev آخر غير 1.13 أجاب، أو لم تقل نقطة نهاية `custom` أي نموذج أجاب. | +| `request-cut` | **ليس انقطاع.**Jev أجاب؛ تم عرض فقط جزء من الاستدعاء عليه، لذا إجابته لم تُلغ شيئاً. اطلع على [عندما أجاب Jev، لكن ليس على الاستدعاء كاملاً](#when-jev-answered-but-not-on-the-whole-call). | + +`failproofai jev status` يمكنه أيضاً إظهار عدد قليل من الأسباب الأندر، مثل `upstream-error` (حملت الإجابة خطأ المزود الخاص به) أو `config`، ويجمع أي سبب لا يمكنه تسميته كـ `other`. + +`request-cut` موجود في هذا الجدول لأن `failproofai jev status` يجمعه مع البقية، وأيضاً لأنه يترك أيضاً كل رفض قائماً. إنه السبب الوحيد هنا الذي لا يقول شيئاً عن مزودك: وصل الطلب وأجاب Jev عليه. على عكس كل صف فوقه، تلك الإجابة لا تزال تحسب — يطبق رفض أو تحذير Jev الخاص على نتيجة regex بدلاً من التخلص منه. لذا فإن مسار منهم يعني استدعاءات تصل إلى المقيّم كبير جداً للإرسال كاملاً، وليس أن نقطة النهاية الخاصة بك سيئة، وسيؤدي شحن الأرصدة أو تغيير URL إلى عدم تحريك الرقم. + +## عندما أجاب Jev، لكن ليس على الاستدعاء كاملاً + +شيئان آخران يمكن أن يحدثا، ولا أحد منهما Jev فشل في الإجابة. كلاهما يتعلق بكم من الاستدعاء، أو من المحادثة، مناسب في طلب واحد. + +**جزء من الاستدعاء نفسه لم يناسب.** يتم إرسال استدعاء الأداة داخل ميزانية ثابتة، واحد ضخم — `Write` كبير جداً، جسم MCP ضخم، أمر مُحشى إلى الحد — يتم إرساله مع ما ناسب. يجيب Jev بعد ذلك، وتحسب إجابته بعد ذلك: يطبق رفضه أو تحذيره الخاص كالمعتاد. ما لا يمكنه فعله هو **إلغاء** أي شيء، لأن حكم معطى على جزء من استدعاء ليس حكماً على الاستدعاء. لذا فإن كل سياسة رفض تقف، ويتم تسجيل الاستدعاء كرجوع مع السبب `request-cut`، الذي `failproofai jev status` يجمعه جنباً إلى جنب مع الأسباب أعلاه. القاعدة التي يعطيك إياها: جعل استدعاء أكبر يمكنه تكلفته تصاريحه، ولا يمكنه أبداً شراء واحدة. + +**رسالة لم تناسب.** موجه طويل ألصقته، الرسالة الأخيرة للوكيل، أو موجه قد كان مخزن هذا المقيّم قد قبض عليه بالفعل. **لا شيء يتغير**: يتم الحكم على الاستدعاء، وإلغاء وتسجيله تماماً كأي آخر، ولم يتم حسابه كرجوع. طول ما تكتبه لا يقرر أبداً حكماً، وقطع لا يمكنه تصنع الموافقة: حيث وصل موجه مقبوض عليه بالفعل، "أنت لم تطلب هذا" يتوقف عن كونه استنتاجاً يمكن استخلاصه منه على الإطلاق، بدلاً من أن يصبح واحداً. + +الخط بين الاثنين هو من كتب النص. الاستدعاء للوكيل، وقاعدة تسمح لطوله بطرح الشدة ستكون قاعدة يمكن للوكيل استخدامها؛ موجهك لك، ومعاملة طوله كإشارة فقط قد عاقب دائماً لصق مواصفة أو تتبع الحجم. + +## ما يترك الآلة + +لكل استدعاء أداة يقيّمه Jev، طلب واحد يذهب إلى مزودك، حاملاً: + +- استدعاء الأداة نفسه، مع أسرار مثل مفاتيح API ورموز المشروع وتعيينات `KEY=` معاد صياغتها؛ +- الموجهات الأخيرة التي كتبتها، مع إزالة النص الذي أضافت حزام الوكيل؛ +- الرسالة الأخيرة للوكيل قبل موجهك الأخير، معنّون كمكتوب بواسطة الوكيل؛ +- حقائق محسوبة محلياً، مثل ما إذا كان المسار داخل المشروع — الذي كانت الجلسة فيه عند أول استدعاء مراجع، [مثبت للجلسة](/ar/reference/jev-intent#the-project-root) — والفرع git الحالي. + +يذهب فقط إلى نقطة النهاية في إعدادك، تحت مفتاحك. + +## أطفئه + +```bash +failproofai jev remove +``` + +هذا يحذف `~/.failproofai/jev.json`. من استدعاء الأداة التالي، تشغل الخطافات سياسات regex تماماً كما قبل. مخازن كل جلسة تحت `~/.failproofai/state/semantic/` (الموجهات المسجلة في `sessions/`، جذور المشروع في `roots/`) يتم تركها في المكان وتتقدم في السن. لإيقاف سؤال Jev لكن الاحتفاظ بالإعداد، استخدم `failproofai jev setup --mode off` بدلاً من ذلك. + +## مرجع الأوامر + +| الأمر | النتيجة | +| --- | --- | +| `failproofai jev --url --key-stdin` | أعده في أمر واحد؛ يأتي المزود من مضيف URL | +| `failproofai jev --url --token ` | نفس، مع المفتاح على سطر الأوامر — السجل والقائمة الخاصة بك رى تراه | +| `failproofai jev setup --provider --key-stdin` | اكتب الإعداد من مفتاح مُنقول على stdin | +| `failproofai jev setup --provider ` | نفس، طالباً المفتاح في موجه مقنَّع | +| `failproofai jev setup --key-from-env` | لا تخزن مفتاح؛ اقرأ `FAILPROOFAI_JEV_API_KEY` لكل جلسة | +| `failproofai jev setup --mode shadow` | وضع التبديل (`enforce` أو `shadow` أو `off`)، الاحتفاظ بالمفتاح المخزن | +| `failproofai jev setup --model ` / `--base-url ` | تجاوز النموذج أو قاعدة API؛ `default` يمسح التجاوز | +| `failproofai jev setup --timeout-ms ` | تغيير الميزانية لكل استدعاء | +| `failproofai jev status [--json]` | الإعداد والأذونات والنشاط الأخير؛ أبداً المفتاح | +| `failproofai jev test [--json]` | طلب بث واحد: زمن الاستجابة والإصدار الذي أجاب | +| `failproofai jev models [--provider ] [--url ] [--json]` | معرّفات النموذج التي يُبلِّغ عنها `/models` لنقطة النهاية، ويشير إلى المُعدّل | +| `failproofai jev remove` | احذف الإعداد؛ Jev معطل | \ No newline at end of file diff --git a/docs/ar/policies/jev-cloud.mdx b/docs/ar/policies/jev-cloud.mdx new file mode 100644 index 000000000..ccb20183d --- /dev/null +++ b/docs/ar/policies/jev-cloud.mdx @@ -0,0 +1,117 @@ +--- +title: "Jev من خلال FailproofAI Cloud" +description: "دع Jev يحكم على استدعاءات أدوات وكلائك من خلال FailproofAI Cloud، على خطة مؤسستك، بدون حساب TypeSafe أو مفتاح خاص بك." +icon: "cloud" +--- + +[Jev](/ar/policies/jev-byok)، مصنف TypeSafe، يقرأ كل استدعاء أداة مقابل ما طلبته بالفعل ويجيب إلى جانب سياساتك، وليس بدلاً منها. من خلال **FailproofAI Cloud**، تستخدم الآلة المتصلة Jev بنفس المفتاح الذي تتصل به بالفعل: لا حساب TypeSafe، لا مفتاح ثانٍ، لا نقطة نهاية للتكوين. يتم فرض رسوم على كل استدعاء حسب تخصيص الخطة الحالي لمؤسستك. + +كل ما يفعله Jev لم يتغير عن [إعداد bring-your-own-key](/ar/policies/jev-byok): السياسات الصارمة تبقى نهائية، تُمحى حالة الرفض للسياسة المراجعة فقط عندما يتم السؤال عن Jev حول هذا الاهتمام بالذات، وأي فشل يعود إلى نتيجة regex لهذا الاستدعاء. + + +يتطلب **failproofai 1.0.8-beta.0** أو إصدار أحدث. 1.0.7 ليس لديه Jev، على الرغم من أنه يترتب فوق إصدارات 1.0.7 التجريبية. بدون تكوين Jev، لا شيء يتغير: تعمل الخطافات على سياسات regex تماماً كما كانت دائماً. + + +## تشغيله + +1. **إنشاء مفتاح باستخدام Jev.** في لوحة تحكم FailproofAI Cloud، افتح **Keys → Create key** واختر إعداد **machine**. يمنح المفتاح الأذونات الثلاث التي تحتاجها الآلة: `events:add` (إرسال النشاط)، `policies:pull` (استقبال السياسات) و `jev:evaluate` (Jev، يتم فرض رسوم عليه حسب خطة مؤسستك). لا يمكن لمفتاح أن يحمل `jev:evaluate` بدون الاثنين الآخرين. +2. **اتصل بالآلة** بهذا المفتاح: + + ```bash + failproofai config --token + ``` + + إذا كانت مؤسستك تدير FailproofAI Cloud الخاص بها بدلاً من النسخة المستضافة، أضف عنوانها: `--url https://` (أو صدّر `FAILPROOFAI_CLOUD_URL`). بدونها، يتم التحقق من المفتاح مقابل الخدمة المستضافة ويفشل الاتصال. إذا كانت شهادة هذا المضيف من CA خاص، ثبت CA في مخزن الثقة النظامي للآلة (على سبيل المثال مع `update-ca-certificates`)، وليس فقط في `NODE_EXTRA_CA_CERTS`: المراقب الذي يرسل الأحداث ويسحب السياسات يقرأ المخزن النظامي. انظر [Troubleshooting](/ar/reference/troubleshooting). + +هذا كل شيء. يحفظ الاتصال المفتاح وعندما لا تملك الآلة تكوين Jev بعد، يقوم بتشغيل Jev من خلال FailproofAI Cloud في وضع **shadow**: يتم السؤال عن Jev بشأن كل استدعاء أداة محصورة وتسجيل أحكامه، لكن نتيجة سياساتك هي ما يتم فرضه. يقول الإخراج ذلك: + +```text + Jev on through FailproofAI Cloud, in shadow mode: logged, not enforced (~/.failproofai/jev.json). +``` + +**مع `--no-transcripts`، لا يؤدي الاتصال إلى تشغيل Jev.** يرسل Jev كل استدعاء أداة تم فحصه والمطالبة الأخيرة إلى FailproofAI Cloud، وهو أكثر مما يُطلب من اتصال قرارات فقط. لا يزال المفتاح مخزناً، والإخراج يقول أن Jev متاح وكيفية تشغيله: + +```bash +failproofai jev setup --provider failproofai +``` + +كما أنه لا يطفئ Jev **off**. إذا كان `jev.json` للآلة يشغل بالفعل Jev من خلال FailproofAI Cloud، فسيتم تركه كما هو، والإخراج يقول أن Jev لا يزال يرسل كل استدعاء أداة تم فحصه والمطالبة الأخيرة، وأن `failproofai jev setup --mode off` يطفئه. + + +الاتصال **لا يستبدل أبداً** ملف `~/.failproofai/jev.json` موجود. إذا كنت تستخدم بالفعل نقطة نهاية Jev الخاصة بك، فستستمر في الاستخدام، والإخراج يقول أن الملف تم تركه كما هو مكوّن — وعندما يترك هذا الملف Jev معطلاً (مرفوضاً، أو معطلاً)، يقول ذلك وكيفية إصلاحه. للتبديل إلى هذه الآلة في FailproofAI Cloud، قم بتشغيل `failproofai jev setup --provider failproofai`. + + +## Shadow أو enforce أو off + +ابدأ في shadow، شاهد ما كان سيفعله Jev على صفحة السياسة، ثم دعه يتصرف: + +```bash +failproofai jev setup --mode enforce # تنطبق أحكام Jev: قد يمحو رفض قابل للمراجعة ويضيف أحكامه الخاصة +failproofai jev setup --mode shadow # يتم السؤال عن Jev وتسجيله؛ نتيجة سياساتك هي ما يتم فرضه +failproofai jev setup --mode off # احتفظ بالتكوين، توقف عن السؤال عن Jev +``` + +نفس الخيار موجود في لوحة التحكم المحلية: **Settings → Jev** يحتوي على مفتاح تشغيل/إطفاء و shadow/enforce. يعيد كتابة الوضع وليس شيء آخر. تقرأ الخطافات التكوين في كل استدعاء أداة، لذا ينطبق التغيير من الاستدعاء التالي، بدون إعادة تشغيل. + +## تحقق مما يفعله + +```bash +failproofai jev status +failproofai jev test +``` + +يعرض `status` المزود باسم **FailproofAI Cloud**، المضيف في Cloud الذي اتصلت به الآلة، والوضع، ومصدر المفتاح باسم **FailproofAI Cloud connection**، لا تعرض المفتاح أبداً. عندما يكون `jev.json` الخاص بـ FailproofAI Cloud موجوداً لكن لا يمكن لـ Jev الجري، يقول السبب: + +| يقول `status` | `status --json` | المعنى | +| --- | --- | --- | +| **off — لا يوجد مفتاح Jev مخزن لاتصال FailproofAI Cloud بهذه الآلة** | `key-lacks-jev` | الآلة متصلة، لكن لا يوجد مفتاح Jev مخزن لها: المفتاح يفتقد `jev:evaluate`، أو الاتصال لم يستطع تأكيده. قم بتشغيل `failproofai config --token ` مرة أخرى بنفس المفتاح؛ إذا كان ينقصه الإذن، استخدم مفتاح **machine**. | +| **off — هذه الآلة غير متصلة بـ FailproofAI Cloud** | `not-connected` | لا توجد اتصال FailproofAI Cloud على هذه الآلة لمفتاح Jev ليتبع. | + +بعد `failproofai config --disconnect` لم يعد هناك `jev.json` الخاص بـ FailproofAI Cloud (ما لم يتم إطفاؤه، والذي يتم الاحتفاظ به)، لذا يقول `status` ببساطة أن Jev معطل. يحمل `status --json` نفس الحقائق (`provider: "failproofai"`، `keySource: "cloud"`، `cloudConnected`، `keyCarriesJev`)، أيضاً عندما يكون التكوين غائباً أو مرفوضاً. `permissions` هو دائماً من `jev.json`؛ الرفض حول `credentials.json` يضيف `credentialsPermissions`، و `fix` عندما تصلح أمر واحد. يرسل `test` طلباً واحداً مباشراً ويبلغ عن زمن الانتقال وإصدار Jev الذي أجاب. يخرج 1، ويقول ذلك في عنوانه، عندما تصل الإجابة بعد timeout الخطاف (ستسجل الخطافات `timeout`) أو تجيب على سؤال الفحص بشكل خاطئ. + +تعرض لوحة تحكم **Settings → Jev** أيضاً اتصال **FailproofAI Cloud connection**: المؤسسة التي تبلغ الآلة عنها وما إذا كان مفتاحها يحمل Jev. تتم قراءتها من ملفات الآلة الخاصة بها، بدون استدعاء شبكة. + +## ما يصل إلى صفحة السياسة + +الآلة ترسل بالفعل نشاطها من الخطاف إلى FailproofAI Cloud (`events:add`). مع تشغيل Jev، سجل كل استدعاء محصور يقول أيضاً أي معيّن جرى، ما قررته Jev، أي السياسات التي أمحاها، لماذا عادت عندما فعلت، وزمن الانتقال والنموذج الذي أجاب — القرارات، الرموز والأسماء، لا تعرض الأوامر أو المطالبة. على صفحة **Policies** بمؤسستك: + +- يتم نسب استدعاء قررت حكمه الخاص بـ Jev (وضع enforce) إلى **Jev**، وعندما جاء الفحص الحاسم من حزمة، يسمي السجل أيضاً تلك الحزمة وإصدارها؛ +- في وضع shadow، يظهر نفي أو تحذير Jev كـ **would-have**، بجانب التجاوزات التي تراقبها؛ +- تُحتسب السياسات التي أمحاها Jev، أو كانت ستمحوها في وضع shadow، لكل سياسة. + +## عندما لا يستطيع Jev الإجابة + +كل واحد من هذه يعود إلى نتيجة سياساتك لهذا الاستدعاء، ويسجل مع السبب: + +| السبب | السبب | +| --- | --- | +| `out-of-credits` | استخدمت مؤسستك تخصيص الخطة. | +| `http-401`, `http-403` | تم إلغاء المفتاح، أو لا يحمل `jev:evaluate`. أعد الاتصال بمفتاح يفعل ذلك. | +| `http-429` | FailproofAI Cloud يقيّد معدل Jev لمؤسستك. حتى ينتهي الانتظار الذي يطلبه (الخاص به `Retry-After`، بحد أقصى 60 ثانية)، لا ترسل الآلة له شيء وكل استدعاء يعود مباشرة. الاستدعاءات المحتفظ بها بهذه الطريقة يتم تسجيلها كـ `http-429`، أو كـ `rate-limited` عندما يحتفظ حد معدل الآلة الخاص بها أولاً. | +| `http-429` (حد يومي) | استخدمت مؤسستك استدعاءات Jev اليومية: **10,000 لكل يوم UTC**، ما لم يقم من يشغل FailproofAI Cloud الخاص بك بتعيين حد آخر. كل استدعاء يعود حتى يعاد تعيين العدد في 00:00 UTC؛ الآلة لا تزال تسأل مرة واحدة على الأكثر في الدقيقة، لذا تختار الإعادة في غضون دقيقة. يقول `failproofai jev test` "Daily Jev limit for this org reached; resets at 00:00 UTC." | +| `http-422` | رفض Jev طلب هذا الاستدعاء، عادة لأن استدعاء الأداة احتفظ بنص كثيف (base64، hex، كود مصغر) فوق ميزانية Jev. هذا الاستدعاء يعود في كل مرة؛ ليس انقطاع. | +| `http-502` | Jev غير متاح الآن. | +| `http-503` | لا يستطيع هذا Cloud تقديم Jev لمؤسستك: لا بوابة نموذج، مؤسسة لم يتم توفيرها بعد، أو البوابة معطوبة. اطلب من المسؤول؛ تسأل الخطافات مرة واحدة على الأكثر في الدقيقة. | +| `http-404` | لا تخدم FailproofAI Cloud هذه Jev بعد. | +| `timeout` | لا توجد إجابة في `timeoutMs` (الافتراضي 3000). | +| `model-mismatch` | أجاب إصدار Jev آخر غير 1.13. | + +## حيث يعيش المفتاح وأين يذهب + +- يتم تخزين المفتاح مرة واحدة، في `~/.failproofai/credentials.json` (`0600`، في دليل خاص بالمالك فقط)، بجانب بيانات اعتماد FailproofAI Cloud الأخرى. لا يحمل `jev.json` مفتاحاً لهذا المسار؛ واحد مكتوب هناك يجعل التكوين غير صحيح. +- إذا حمل `credentials.json` **أي** إذن لأي شخص غير أنت (مجموعة أو آخر، قراءة أو كتابة)، أو يمكن كتابة دليله بواسطة أي شخص غيرك، فسيتم **رفضه**، لم يتم قراءته، وسيتم إطفاء Jev حتى تصلحه: `chmod 600` على الملف، `chmod 700` على الدليل (أو أعد الاتصال، الذي يعيد كتابة الملف في `0600` ويجعل الدليل خاصاً بالمالك فقط). الدليل الذي يمكن للآخرين قراءته فقط هو بخير؛ الدليل الذي يمكنهم الكتابة فيه يتيح لهم استبدال الملف. +- المفتاح ينطبق فقط أثناء اتصال الاتصال به على الآلة: سياسة أو بيانات اعتماد التقرير لنفس FailproofAI Cloud **بنفس المفتاح**، في نفس الملف. يتم تجاهل مفتاح Jev المتروك بدون واحد، وسيتم إطفاء Jev. يحدث عندما يترك failproofai الأقدم `config --disconnect` مفتاح Jev في مكانه (لا يعرف كيفية إزالته)، أو عندما يتصل failproofai الأقدم بـ `config --token` بمفتاح آخر، الذي قد ينتمي إلى مؤسسة أخرى على FailproofAI Cloud. لتشغيل Jev مرة أخرى، اتصل مرة أخرى بمفتاح **machine**. +- يتم إرسال المفتاح فقط إلى أصل Cloud الذي تم التحقق منه ضده. يتم رفض `jev.json` الذي يشير إلى أي مكان آخر. +- **وكيل على الآلة يمكنه قراءته.** `credentials.json` خاص بالمالك فقط، والوكيل يعمل كهذا المالك. يُسمح بقراءة ملفات failproofai الخاصة بنفسها عن قصد (فقط تغييرها مسدود بـ `block-failproofai-commands`)، لذا فإن الشيء الوحيد بين وكيل وهذا الملف هو `block-read-outside-cwd` — سياسة *قابلة للمراجعة* — ومن جلسة بدأت في مجلد المنزل الخاص بك، لا شيء. المفتاح الذي يحمل `jev:evaluate` ينفق تخصيص Jev بمؤسستك (حتى الحد الأقصى اليومي) من أينما تُستخدم، لذا تعامل مع مفتاح الآلة مثل أي بيانات اعتماد إنفاق أخرى: إذا كان قد يكون قد قرأه وكيل، عطّله على صفحة Keys وأعد الاتصال بمفتاح جديد. +- فقط ملفاتك العامة تقرر هذا. لا يمكن لمستودع تشغيل Cloud Jev، الإشارة إليه في مكان آخر أو توريد مفتاحه، و `FAILPROOFAI_JEV_API_KEY` يتم تجاهله لهذا المسار. +- لكل استدعاء يقيّمه Jev، طلب واحد يذهب إلى FailproofAI Cloud، يحمل ما تسرده [صفحة bring-your-own-key](/ar/policies/jev-byok#what-leaves-the-machine) (أسرار معاد صياغتها). ترسله FailproofAI Cloud إلى TypeSafe ولا تسجله أو تحفظ عليه. + +## إطفاؤه + +| الأمر | النتيجة | +| --- | --- | +| `failproofai jev setup --mode off` | احتفظ بالتكوين؛ لا يتم السؤال عن Jev. **هذا هو الخيار الذي يدوم:** الاتصال مرة أخرى لا يعيد كتابة `jev.json` موجود أبداً، لذا يبقى Jev معطلاً حتى تقوم بتشغيله بـ `--mode shadow`. | +| `failproofai jev remove` | حذف `~/.failproofai/jev.json`؛ Jev معطل — حتى الاتصال التالي `failproofai config --token` بمفتاح يحمل `jev:evaluate`، الذي يجد لا `jev.json` ويشغل Jev في وضع shadow (ما لم يعمل بـ `--no-transcripts`). للاحتفاظ به معطلاً، استخدم `--mode off`. | +| `failproofai config --disconnect` | افصل الآلة: يتم إزالة المفتاح، وكذلك `jev.json` عندما يسمي FailproofAI Cloud وليس معطلاً. `jev.json` لنقطة النهاية الخاصة بك يبقى، وكذلك واحد معطل، لذا يبقى Jev معطلاً عندما تتصل مرة أخرى. | + +من استدعاء الأداة التالي، تعمل الخطافات على سياسات regex تماماً كما كانت من قبل. \ No newline at end of file diff --git a/docs/ar/policies/jev.mdx b/docs/ar/policies/jev.mdx new file mode 100644 index 000000000..cf68117d2 --- /dev/null +++ b/docs/ar/policies/jev.mdx @@ -0,0 +1,45 @@ +--- +title: "سياسات Jev" +description: "أضف المراجعة المباشرة من Jev لاستدعاءات الأدوات المحمية، ثم فتشها قبل تطبيق قراراتها." +icon: "shield-check" +--- + +يقرأ Jev استدعاء أداة مقابل ما طلبه الشخص من الوكيل القيام به. استخدمه عندما تحظر سياسة المطابقة النصية عملاً صحيحاً أو تفوتك إجراءً محفوفاً بالمخاطر يحتاج إلى سياق. يجيب جنباً إلى جنب مع سياساتك في بوابة `PreToolUse` أو `PermissionRequest`. للحصول على درجة **بعد** انتهاء الجلسة، استخدم [تقييمات Jev](/ar/evaluations/jev). + +## ابدأ بوضع المراقبة + +ثبّت Failproof AI وأرفق الخطافات بـ [حزام مدعوم](/ar/reference/harnesses). استخدم failproofai 1.0.8-beta.0 أو إصدار أحدث. + +لا تحتوي Failproof AI على فحوصات Jev. ثبّتها كحزمة، وإلا لن يكون لدى Jev شيء للسؤال عنه ولن يتم استدعاؤه: + +```bash +failproofai policies add FailproofAI/jev-policies +``` + +ثم اختر كيفية وصول الطلبات إلى Jev: + +| الطريق | الخطوة الأولى | +| --- | --- | +| FailproofAI Cloud | الاتصال بمفتاح **machine** يحمل `jev:evaluate`. على جهاز بدون إعدادات Jev، يؤدي `failproofai config` إلى تشغيل Jev في وضع المراقبة. | +| مزودك الخاص | في لوحة المعلومات المحلية، افتح **الإعدادات → Jev**، اختر المزود، الصق رمزه، وحدد **مراقبة**. أو قم بتشغيل `failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key`. | + +![إعدادات Jev في لوحة المعلومات المحلية: المزود والنقطة النهائية والرمز ووضع المراقبة قبل تشغيل Jev.](/images/dashboard/jev-settings.png) + +```bash +failproofai jev status +failproofai jev test +``` + +يتحقق `test` من النقطة النهائية. للتحقق من مسار الخطاف، اطلب من وكيل مع خطاف أن يستخدم أداة قراءة الملفات على `README.md`. أكد أن استدعاء الأداة هذا يظهر في الجلسة، ثم افتش **السياسات → النشاط** في [لوحة المعلومات المحلية](/ar/reference/local-dashboard#review-policy-activity). يجب أن يزيد عدد Jev في `status`. يسجل وضع المراقبة ما كان سيقرره Jev بينما لا تزال نتيجة السياسة الحالية تنطبق. + +## حدد متى تطبق + +السياسة **hard** لها دائماً الكلمة الأخيرة. قد يمسح Jev الرفض فقط من سياسة محددة بوضوح **reviewable** وفقط عندما يتحقق من المخاوف المسماة للسياسة. انظر [سلطة السياسة](/ar/policies/authority) قبل الاعتماد على إذن. يمكن لـ Jev أيضاً تحذير أو رفض بمفرده. إذا لم يتمكن من الإجابة، فإن نتيجة السياسة تقرر هذا الاستدعاء. + +بمجرد أن تبدو نتائج المراقبة صحيحة، قم بالتبديل إلى وضع الإنفاذ في **الإعدادات → Jev** أو قم بتشغيل: + +```bash +failproofai jev setup --mode enforce +``` + +لعناوين URL المزودين ومفاتيح Cloud والإعدادات والبدائل والبيانات المرسلة مع كل طلب، راجع [مرجع تكامل Jev](/ar/reference/jev). \ No newline at end of file diff --git a/docs/ar/reference/custom-agents-typescript.mdx b/docs/ar/reference/custom-agents-typescript.mdx new file mode 100644 index 000000000..13b44ccf5 --- /dev/null +++ b/docs/ar/reference/custom-agents-typescript.mdx @@ -0,0 +1,401 @@ +--- +title: "وكلاء مخصصون (TypeScript)" +description: "الإعدادات وكتالوج الأحداث والنطاقات ومحولات الإطار العمل لـ @failproofai/sdk." +icon: "square-js" +--- + +شرح شامل لكل إعداد وطريقة وحقل في SDK الخاص بـ TypeScript. إذا كنت تقوم بالتجهيز للمرة الأولى، ابدأ بالدليل — هذه الصفحة مخصصة للبحث عن المعلومات. + + + + التثبيت والتجهيز وطرق الأحداث ومثال عملي والمشاكل الشائعة. + + + نفس الأحداث وتنسيق السلك نفسه والمسفر نفسه — من Python. + + + +Node 20.9 أو أحدث. ESM و CommonJS. بدون تبعيات الوقت التشغيلي. + + + هذا SDK والآخر الخاص بـ Python يكتبان **نفس الأحداث إلى نفس المسفر**. أسطول يحتوي على وكلاء Node ووكلاء Python ينتج مجموعة واحدة من الجلسات وليس اثنتين، ولا شيء في لوحة المعلومات يميز بينهما. اختر لكل خدمة وليس لكل شركة. + + +## التثبيت + +```bash +npm install @failproofai/sdk +``` + +```ts +import * as failproofai from "@failproofai/sdk"; + +await failproofai.agent("planner", { goal: question }, async () => { + const hits = await failproofai.toolCall("web_search", { input: { q } }, () => search(q)); +}); +``` + +محولات الإطار العمل تأتي في الحزمة نفسها. الأطر العمل **اختيارية peer dependencies** — مُعلنة بحيث تكون النطاقات المدعومة مرئية وغير مثبتة نيابة عنك أبداً، وتُستورد فقط عند استدعاء `instrument()`. + +## توصيل مستقبل Failproof + +متطابق مع SDK الخاص بـ Python: أنشئ مفتاح `events:add` تحت **Admin → Keys**، ثم [وصّل المستقبل](/ar/start/setup#connect-a-machine-to-cloud) على جهاز الوكيل. يكتب SDK إلى القرص؛ المستقبل يُرسل البيانات. + +## الإعدادات + +```ts +failproofai.configure({ + environment: "production", + flushInterval: 0.5, + baseDir: undefined, +}); +``` + +| الخيار | ما الذي يفعله | +| --- | --- | +| `environment` | الملصق على كل حدث — `production` أو `staging` أو `prod-eu`. الافتراضي `dev`. | +| `flushInterval` | عدد المرات التي يكتب فيها المؤقت إلى القرص، بالثواني. الافتراضي `0.5`. | +| `baseDir` | مكان الكتابة. الافتراضي هو مسفر المستقبل، وهو ما تريده ما لم تعرف خلاف ذلك. | + +لا يتم تطبيق أي شيء ما لم يتحقق من صحة كل ذلك، لذلك يترك الاستدعاء المرفوض SDK تماماً كما هو بدلاً من وجود `baseDir` جديد والفاصل الزمني القديم. + +ضبط متغير بيئة بدلاً من ذلك: + +| متغير | ما الذي يفعله | +| --- | --- | +| `AGENTEYE_ENVIRONMENT` | يضبط `environment` دون تغيير الكود. خيار `configure()` يأخذ الأولوية عليه. | +| `FAILPROOFAI_HOME` | ينقل جذر Failproof AI الذي يحتفظ بالمسفر. | +| `FAILPROOFAI_SDK_LOG_LEVEL` | `debug` أو `info` أو `warn` (الافتراضي) أو `error` أو `silent`. | +| `FAILPROOFAI_SDK_STRICT` | `1` يجعل أخطاء التجهيز ترمي استثناءات بدلاً من تسجيلها. | +| `FAILPROOFAI_SDK_STRICT_INTEGRATIONS` | `1` يجعل مشكلة التوافقية مع الإطار العمل ترمي استثناءات بدلاً من التحذير والمتابعة. | + + + **لا توجد فواصل في `environment`.** يقسم الاستيعاب هذا الحقل على الفواصل لبناء مرشحاته، ويتخطى أي حدث يحتوي على فاصلة — بحيث يختفي التشغيل بأكمله بصمت. اكتب `prod-eu` وليس `prod,eu`. + + `configure({ environment: "prod,eu" })` يرمي استثناء بحيث تعرف على الفور. `AGENTEYE_ENVIRONMENT` لا يمكنه رمي استثناء — لا أحد يناديك — لذا يحذر مرة واحدة ويعود إلى `dev`. + + +وجّه سطور السجل الخاص بـ SDK إلى المسجل الخاص بك باستخدام `failproofai.setLogger({ debug, info, warn, error })`. + +## الإيقاف + +تُُفرّغ الأحداث المخزنة مؤقتاً عند `process.on("exit")`. + +العملية المقتولة بإشارة لا تصل أبداً إلى ذلك، والافتراضي في Node لـ `SIGTERM` هو الإنهاء دون تشغيل معالجات الخروج — لذا يفقد الوكيل في حاوية ما كان الفاصل الزمني الأخير لم يكتبه. + + + **هذا SDK لن يثبّت معالج إشارة لك.** يؤدي تسجيل واحد إلى تغيير سلوك العملية: المستمع يقمع الإنهاء الافتراضي في Node، لذا ستتوقف مكتبة أضافت واحداً بصمت عن عمل Ctrl-C. أضف الخاص بك: + + ```ts + for (const signal of ["SIGINT", "SIGTERM"] as const) { + process.once(signal, () => { + failproofai.flushSync(); + process.exit(0); + }); + } + ``` + + +يجب على سكريبت قصير الأجل أو معالج بدون خادم أن يفعل `await failproofai.flush()` قبل العودة — الفاصل الزمني وحده لا يضمن التسليم. + +## الهوية + +كل حدث ينتمي إلى جلسة ووكيل. **النطاقات ملأهما**، لذا نادراً ما تمررهما: + +```ts +await failproofai.session(async () => { + await failproofai.agent("planner", async () => { + failproofai.event.toolUse({ toolName: "search", toolCallId: "c1" }); + }); +}); +``` + +تمرير `sessionId` أو `agentId` بشكل صريح يعمل أيضاً ويأخذ الأولوية. مع عدم ربط أو تمرير، ترمي استثناء بدلاً من إصدار حدث Cloud سيتجاهله بصمت. + + + الهوية تركب على `AsyncLocalStorage`. تتبع `await` و `.then()` والمؤقتات والعودة الاستدعاء المُنشأة داخل النطاق. **لا** تتبع عودة استدعاء مخزنة أثناء تشغيل واحد وتُستدعى أثناء تشغيل آخر، أو العمل الممرر عبر حدود `worker_threads` — لفّهما في `failproofai.propagate()` أو أحداثهما ستهبط غير مرتبطة. + + +### النطاقات + +| النطاق | الإصدار | العودة | +| --- | --- | --- | +| `session(body)` | لا شيء — الهوية فقط | كل ما يعيده `body` | +| `agent(id, options?, body)` | `agent_start`، ثم `agent_end` | كل ما يعيده `body` | +| `toolCall(name, options?, body)` | `tool_use`، ثم `tool_result` | كل ما يعيده `body` | + +جسم متزامن يبقى متزامناً: `agent("x", () => 1)` يعيد `1`، وليس وعداً. + +يسجل `toolCall` قيمة الجسم المحلولة كـ `output` للأداة، ما لم تخصص `call.output` بنفسك. + + + +| ما حدث | الأحداث | `outcome` | +| --- | --- | --- | +| أعاد الكتلة | `agent_end` | `"success"` أو `outcome` الخاص بك | +| رمت الكتلة استثناء | `error`، ثم `agent_end` | `"failed"` | +| `AbortError` | `agent_end` فقط | `"cancelled"` | + +يُعاد رمي الخطأ دائماً. + +يتم تسجيل فشل الأداة على الورقة — `tool_result` مع سلسلة `error` — ولا يُصدر حدث `error` على مستوى التشغيل. الحدث الذي يمسكه حلقة الوكيل ليس فشل التشغيل، والحدث الذي ينتشر يُُبلّغ عنه مرة واحدة بالضبط، من قِبل `agent()` المرفق. + + + + + +عندما لا يكون العمل دالة واحدة — نطاق مفتوح في المُنشئ وتُغلقه في التفكيك، أو واحد يعبر التحكم بالتدفق الموجود: + +```ts +{ + using span = failproofai.agent.open("planner", { goal }); + using call = failproofai.toolCall.open("search", { input: { q } }); + call.call.output = await search(q); +} // tool_result، ثم agent_end +``` + +كلا الشكلين يُصدران أحداث متطابقة بالبايت. فضّل شكل العودة الاستدعاء: فهو يعمل داخل `AsyncLocalStorage.run()`، لذا لا شيء للعودة عنه وفئة كاملة من أخطاء تفتح هنا وتُغلق هناك غير قابلة للوصول. + +كتلة `using` التي تمسك بفشلها الخاص تبلغ عنه باستخدام `span.fail(error)` — قناة الخروج لا تملك قناة استثناء خاصة بها. + + + +## كتالوج الأحداث + +نفس خمسة عشر طريقة مثل SDK الخاص بـ Python، بـ camelCase. معظمها يأتي في **أزواج** — تستدعي الفاتح، ثم الأغلق، و SDK يقيس الفجوة. + +| | فتح | إغلاق | +| --- | --- | --- | +| **الوكلاء** | `agentStart` | `agentEnd` | +| | `agentPause` | `agentResume` | +| **النماذج** | `modelRequest` | `modelResponse` | +| **الأدوات** | `toolUse` | `toolResult` | +| **الخطافات** | `hookTriggered` | `hookCompleted` | +| **البشر** | `humanWait` | `humanInput` | + +ثلاثة منهما منفصلة: `error` و `humanPause` و `humanInterrupt`. + + + +كل طريقة تأخذ أيضاً `sessionId` و `agentId`، والتي تملأها النطاقات لك. أي شيء محذوف يُسقط بدلاً من إرساله كـ JSON `null`. + +| الطريقة | مطلوب | اختياري | +| --- | --- | --- | +| `agentStart` | — | `goal` و `parentId` | +| `agentEnd` | — | `outcome` و `summary` | +| `agentPause` | `pauseId` | `reason` و `userId` | +| `agentResume` | `pauseId` | `reason` و `userId` | +| `modelRequest` | — | `model` و `messages` و `system` و `tools` و `requestId` | +| `modelResponse` | — | `model` و `stopReason` و `inputTokens` و `outputTokens` و `content` و `role` و `requestId` | +| `toolUse` | `toolName` و `toolCallId` | `input` | +| `toolResult` | `toolName` و `toolCallId` | `output` و `error` | +| `hookTriggered` | `hookName` و `hookId` | `triggerEvent` و `input` | +| `hookCompleted` | `hookName` و `hookId` | `outcome` و `output` و `error` | +| `error` | `errorType` و `message` | `traceback` | +| `humanWait` | `inputId` | `prompt` و `options` و `reason` | +| `humanInput` | `inputId` | `response` | +| `humanPause` | — | `reason` و `userId` | +| `humanInterrupt` | — | `reason` و `userId` و `atStep` | + +أي مفتاح آخر تُضيفه يصبح حقل حمولة مخصص. اجعل مساحة كل شيء خاص بالإطار العمل `fw_*`؛ اسم يتعارض مع حقل مُعلن يُرفض بدلاً من الكتابة الصامتة على عمود مرفوع. + + + + + **`duration_ms` محسوب، لا يُقبل.** الطرق الأربع للإغلاق تقيس الفجوة من الفاتح الخاص بها وترفض `duration_ms` المُزود من المتصل — المدة المُبلّغ عنها غير قابلة للتزييف. + + تُطابق الأزواج على **الجلسة** والمعرّف، ولا تُطابق أبداً على الوكيل. أداة مفتوحة تحت `planner` ومغلقة تحت `worker` تزال متطابقة، وهو ما تفعله تشغيلات الوكلاء المتداخلة المتعددة فعلاً. + + +## محولات الإطار العمل + +```ts +await failproofai.instrument(); // كل ما يمكنها العثور عليه +await failproofai.instrument("langchain"); // واحد بالضبط +failproofai.uninstrument(); // أعد كل شيء +``` + +| الإطار العمل | المدعوم | كيف تُرفق | +| --- | --- | --- | +| **LangChain.js / LangGraph.js** | `@langchain/core` 0.3 – 1.x و LangGraph.js 0.4 – 1.x | `CallbackManager.configure`، لذا يُغطى كل `invoke`/`stream`/`batch` دون تمرير `callbacks:` أي مكان — أو مرّر `langchainHandler()` بنفسك ولا تُصحح أي شيء. | +| **Vercel AI SDK** | `ai` 4 – 7 | `telemetry()` في موقع الاستدعاء، أو `instrument("ai")` للعملية بأكملها على `ai` 7 (على 4–6 يكون اختيارياً — انظر أدناه). | +| **Mastra** | `@mastra/core` 0.20 – 1.x | `Agent.generate`/`.stream` وحل نموذج وأداة الوكيل ومحرك تشغيل سير العمل والخطوة. | +| **LlamaIndex.TS** | `llamaindex` 0.11.4 – 0.x | `Settings.callbackManager` (مُشترك) بالإضافة إلى `AgentWorkflow.runStream`، لتشغيلات سير العمل والخطوات الخاصة بهم. | + +يتم اختبار كل نطاق ضد إصدارات إطار العمل الفعلية، في كلا الطرفين، كـ ES module وكـ CommonJS، على كل تشغيل CI. + +التعيين هو SDK الخاص بـ Python، لذا يرسم نفس البرنامج نفس الشجرة بكل لغة. البناء هو **وكيل** فقط إذا كان يملك حلقة قرار LLM — تشغيل رسم بياني أو سلسلة أو استدعاء `generateText`/`streamText` من AI SDK أو وكيل Mastra أو تشغيل وكيل LlamaIndex. عقدة LangGraph أو خطوة سير العمل هي **خطاف** (`hook_triggered`/`hook_completed`)، ليس أبداً وكيل متداخل. استدعاءات النموذج هي أزواج `model_request`/`model_response` مع عدد الرموز؛ استدعاءات الأداة تحمل معرّف استدعاء الأداة الخاص بالنموذج. يتم تسجيل الفشل مرة واحدة، على الحدث الذي حدث فيه. + +محول فشل في التثبيت يُسجل ويُتخطى؛ الآخرون يثبّتون أيضاً، لأن LlamaIndex المكسورة لا يجب أن تُكلفك LangGraph. + + + `instrument()` بدون وسيطة تكتشف إطار العمل بما إذا كان **يُحل**، وليس بما إذا كان مستورداً بالفعل — Node لا يُكشف عن ما يعادل Python's `sys.modules` لـ ES modules. إطار عمل ثبّته لكن لا تستخدمه سيتم استيراده وتصحيحه. سمّ الذي تريده إذا أهمّ ذلك. + + + + معظم أطر العمل هذه تأتي مع إصدار ES-module وإصدار CommonJS، والذي يحمّله Node كنسختين غير مرتبطتين. تصحح المحولات النسخة التي يحملها التطبيق (والنسخة CommonJS أيضاً إذا كان شيء قد `require`د بالفعل)، لذا يعمل كلا نظامي الوحدات. إطار عمل **مرتجل في مخرجاتك الخاصة** بواسطة esbuild أو webpack بعيد المنال — استخدم مساعدات موقع الاستدعاء هناك: `langchainHandler()` و `telemetry()` و `wrapTool()`. + + +### LangChain بدون تصحيح + +```ts +import { langchainHandler } from "@failproofai/sdk/langchain"; +await graph.invoke(input, { callbacks: [langchainHandler()] }); +``` + +يعمل المعالج مع أو بدون `instrument()` ولا يُسجل مرتين أبداً. `instrument("langchain")` يأخذ `sessionId` و `captureContent` و `includeChains` و `graphCallbacks` و `captureLimit`، مثل محول Python؛ `metadata: { failproofai_sdk_session_id }` على استدعاء يختار الجلسة لذلك الاستدعاء. + +### Vercel AI SDK + +يُصدّر AI SDK دوال عادية من ES module، وفضاء الاسم الخاص بـ ES module غير قابل للتغيير بالمواصفات — لا مكان للتصحيح. يستخدم نقاط الامتداد التي يوثقها SDK نفسه: + +```ts +import { telemetry } from "@failproofai/sdk/ai"; + +const { text } = await generateText({ + model, + prompt, + experimental_telemetry: telemetry({ functionId: "answer-question" }), + // على ai 7، `telemetry: telemetry({ … })` — نفس الكائن، الاسم الجديد +}); +``` + +هذا هو التكامل الكامل: نطاق وكيل وزوج طلب/استجابة نموذج لكل خطوة مع عدد الرموز وكل استدعاء أداة. موقع استدعاء واحد يعمل على كل رئيسي — `ai` 4–6 تقرأ التتبع الذي تحمله، `ai` 7 التكامل التلمتري. + +`instrument("ai")` يفعل نفس الشيء على مستوى العملية **على `ai` 7**: كل استدعاء، من خلال قائمة التكامل التلمتري العام الخاص بـ AI SDK، والتي تضيفية وتأخذ أي شيء من أي شخص آخر. + +**على `ai` 4–6، `instrument("ai")` لا يسجل أي شيء بنفسه، ويسجل تحذيراً واحداً يقول ذلك.** خطاف العملية الكاملة الوحيد لديه هو مزود التتبع OpenTelemetry العام — فتحة واحدة OpenTelemetry ترفض تسليمها مرة واحدة أُخذت. يوفر تسجيل الخاص بنا سيرفض صراحة `NodeSDK.start()` الخاص بك لاحقاً في البدء وسيرسل رموز http/database الخاصة بك إلى متتبع الذي لا يُصدّر أي شيء. استخدم `telemetry()` في موقع الاستدعاء أو `wrapModel` هناك. إذا كانت العملية لا تشغل OpenTelemetry الخاصة بها، اختر الدخول مع `instrument("ai", { registerGlobalTracer: true })`: ثم يسجل كل استدعاء يمرر `experimental_telemetry: { isEnabled: true }`، ويأخذ الفتحة فقط إذا كانت لا تزال فارغة. `registerGlobalTracer: false` يحتفظ بالافتراضي ويسكت التحذير. + +إذا كنت تفضل لف النموذج مرة واحدة، `wrapModel` يرى استدعاءات النموذج فقط، لأن استدعاءات الأداة تحدث فوق طبقة النموذج. نموذج ملفوف يُستدعى مع لا شيء حوله يُسجل كتشغيل خاص به. استدعاء مُجرى يُغلق مهما توقفت الجريان — `stop_reason: "cancelled"` عندما يُلغي المستهلك، `"error"` مع الخطأ عندما يفشل في الوسط: + +```ts +import { wrapModel } from "@failproofai/sdk/ai"; +const model = await wrapModel(openai("gpt-4o")); +``` + +استخدام كليهما بخير: تلاحظ الحوسبة الوسيطة أن الاستدعاء يُسجل بالفعل وتؤجل، لذا يُسجل كل استدعاء مرة واحدة. + +`functionId` يسمي نطاق الوكيل. اجعلها منخفضة في مجموعة السكان — تهبط في `agent_id`، الجانب الرئيسي للوحة المعلومات. + +### Next.js + +`next build` ترزم تبعيات الخادم الخاص بك بشكل افتراضي، وإطار عمل مرتجل في الإصدار هو نسخة `instrument()` لا يمكنها الوصول. لف الإعدادات مرة واحدة واستدع `instrument()` من خطاف بدء Next: + +```ts +// next.config.ts +import { withFailproofai } from "@failproofai/sdk/next"; +export default withFailproofai({ /* your config */ }); +``` + +```ts +// instrumentation.ts +export async function register() { + if (process.env.NEXT_RUNTIME !== "nodejs") return; + const failproofai = await import("@failproofai/sdk"); + await failproofai.instrument(); +} +``` + +يضيف `withFailproofai` LangChain و Mastra و LlamaIndex و SDK نفسه إلى `serverExternalPackages`، محتفظاً بقائمتك الخاصة. بدونه، يُحذر `instrument()` مرة واحدة لكل إطار عمل لا يمكنه الوصول إليه بدلاً من الفشل بصمت؛ إذا أدرجت الحزم بنفسك، اضبط `FAILPROOFAI_NEXT_EXTERNALS=1`. يعمل Vercel AI SDK ومساعدات موقع الاستدعاء بكلا الطريقتين. مسار Edge يحصل على إصدار لا فعالي: استيراد SDK آمن وآن لا تسجل أي شيء. + +### عدد الرموز على الاستدعاءات المُجراة + +تُبلغ واجهات برمجة التطبيقات المتوافقة مع OpenAI عن الاستخدام على جريان فقط عندما يطلبه العميل. LangChain و Vercel AI SDK يطلبان؛ لـ LlamaIndex مرّر `additionalChatOptions: { stream_options: { include_usage: true } }` إلى LLM الخاص به `OpenAI`، ولـ Mastra ابنِ النموذج مع تمكين الاستخدام (على سبيل المثال `createOpenAICompatible({ includeUsage: true })`). خلاف ذلك استدعاءات نموذج مُجراة لا تحمل عدد الرموز. + +### وقت التشغيل + +Node ≥ 20.9 و Bun و Deno — كل إطار عمل، كـ ES module و CommonJS، يُختبر على كل واحد ضد تتبع Node. يعمل SDK بجانب مستقبل `failproofaid`، والذي يُرسل ما يكتبه. + +## وكيلك الخاص — بدون إطار عمل + +لحلقة وكيل كتبتها بنفسك، أو إطار عمل بدون محول. تُصدر الأحداث بنفس واجهة برمجة التطبيقات التي تستخدمها المحولات تحتها، لذا يحتوي التتبع على نفس الشكل والجودة. + +لا تحتاج إلى معرفة كيفية تنظيم الوكيل. كل وكيل مبني يدوياً بالفعل له ثلاثة أماكن، مهما دُعيت وظائفه، وهذه الثلاثة هي التكامل بأكمله: + +| المكان | ما يجب إضافته | الإصدار | +| --- | --- | --- | +| حيث يبدأ وينتهي **تشغيل واحد** | `failproofai.agent("name", { goal }, async () => …)` | `agent_start` / `agent_end` | +| **الدالة الوحيدة التي تستدعي النموذج** | `event.modelRequest` قبل، `event.modelResponse` بعد — كلا النصفين، حتى عند الفشل | زوج واحد لكل دور نموذج | +| **الدالة الوحيدة التي تشغل الأدوات** | `failproofai.toolCall(name, { toolCallId, input }, () => run())` | `tool_use` / `tool_result` | + +```ts +async function callModel(messages) { + const requestId = randomUUID(); + const started = Date.now(); + failproofai.event.modelRequest({ model: MODEL, requestId, messages }); + try { + const reply = await client.chat.completions.create({ model: MODEL, messages, tools }); + failproofai.event.modelResponse({ + model: reply.model, requestId, stopReason: reply.choices[0].finish_reason, + inputTokens: reply.usage?.prompt_tokens, outputTokens: reply.usage?.completion_tokens, + duration_ms: Date.now() - started, + }); + return reply.choices[0].message; + } catch (error) { + failproofai.event.modelResponse({ model: MODEL, requestId, stopReason: "error", + error: String(error), duration_ms: Date.now() - started }); + throw error; + } +} + +async function dispatch(call) { + const input = JSON.parse(call.function.arguments); + return failproofai.toolCall(call.function.name, { toolCallId: call.id, input }, + () => runTool(call.function.name, input)); +} + +await failproofai.agent("inventory", { goal: question }, async () => { + for (;;) { + const message = await callModel(messages); + if (!message.tool_calls?.length) return message.content; + for (const call of message.tool_calls) await dispatch(call); + } +}); +``` + +الهوية محيطة: كل شيء داخل `agent()` يهبط على تشغيل الجلسة بدون أخذ معرّف، ولا شيء آخر في البرنامج يتغير — بما في ذلك كل ما كتبه الوكيل بالفعل إلى قاعدة بيانات الخاص به. + +- **خدمة أو عامل:** مرّر معرّف الطلب أو الوظيفة الخاص بك كـ `sessionId`، بحيث تكون الجلسة على لوحة المعلومات والسجل في السجلات أو قاعدة البيانات الخاصة بك نفس السلسلة. +- **وكلاء فرعيون:** عشّش استدعاءات `agent()`. الداخل ينضم إلى الجلسة مع الخارج مثل `parent_id` الخاص به. +- **أصدر الأزواج.** `modelRequest` بدون `modelResponse` هو نطاق تُظهره لوحة المعلومات كتشغيل إلى الأبد — ومن هنا العودة `catch`. + +[`sdk/typescript/examples/research-agent.ts`](https://github.com/FailproofAI/failproofai/blob/main/sdk/typescript/examples/research-agent.ts) في المستودع هو الإصدار الكامل القابل للتشغيل: حلقة أداة OpenAI حقيقية تُجهز بالضبط مثل هذا، يعمل في CI على كل تغيير كـ ES module و CommonJS. + +## التقييمات + +```ts +import { Evaluator, EvalResult, Score } from "@failproofai/sdk/evaluator"; + +export const app = new Evaluator({ name: "my-evals", version: "1" }); + +app.eval("tool_success_rate", { version: "1" }, (session) => { + const results = session.eventsOfType("tool_result"); + const failures = results.filter((event) => event.payload.error != null).length; + return new EvalResult({ + score: new Score(results.length === 0 ? 1 : 1 - failures / results.length), + reasoning: `${failures} of ${results.length} tool calls failed`, + }); +}); +``` + +```bash +FAILPROOFAI_EVALUATOR_URL=… FAILPROOFAI_EVALUATOR_TOKEN=… \ + npx failproofai-evaluator ./my-evals.js +``` + +انظر [مرجع Evaluator SDK](/ar/reference/evaluator-sdk) للبروتوكول وإعدادات العامل ونتائج أنواع النتائج. + + + **يجب أن يُصدر التقييم.** دالة متزامنة لا تعيد أبداً تحجب الخيط الوحيد الذي يملكه Node، ولا يمكن لأي مهلة زمنية أن تحترق بينما يفعل ذلك. اكتب تقييمات `async`. + + +## ما لن يفعله مع عمليتك + +| | | +| --- | --- | +| **حجب حلقة الوكيل الخاصة بك** | تذهب الأحداث إلى قائمة انتظار في الذاكرة؛ يكتب المؤقت إليها. المؤقت هو `unref`'د، لذا استيراد هذه الحزمة لا يوقف أبداً سكريبت من الخروج. | +| **نمو بدون حدود** | يُحدد قائمة الانتظار بالعدد **و** بالبايت المُقاس. ماضياً إما واحد، تُرمى الأحداث الأقدم وتحذير يقول ذلك — انقطاع التلمتري لا يجب أن يصبح قتل OOM. | +| **أخذ العملية لأسفل** | حدث واحد غير قابل للترميز يُسقط وحده، وليس الدفعة حوله. غالب رمي، مرجع دائري، `BigInt`، بديل وحيد: كل واحد يُعالج بدلاً من نشره. | +| **ترك دفعة نصف مكتوبة** | يُتم `fsync` المحتوى قبل إعادة تسمية ذرية، يُتم `fsync` الدليل بعده، وكتابة فاشلة تُنظف ملف مؤقت الخاص بها. | +| **اترك النسخ قابلة للقراءة** | تكون الدفعات `0600` داخل دليل `0700`. تحمل الأهداف والأوامر وحجج الأداة ومخرجات الأداة. | +| **سفن بيانات الاعتماد** | مفاتيح API والرموز و JWTs وعناوين المحمل والتعيينات ذات الشكل السري تُمحى قبل وصول البايت إلى القرص. يُمحي المستقبل مرة أخرى قبل التحميل. | \ No newline at end of file diff --git a/docs/ar/reference/jev-cloud.mdx b/docs/ar/reference/jev-cloud.mdx new file mode 100644 index 000000000..3e0cc28a6 --- /dev/null +++ b/docs/ar/reference/jev-cloud.mdx @@ -0,0 +1,136 @@ +--- +title: "Jev عبر FailproofAI Cloud" +description: "مفاتيح الآلة السحابية، وحالة الاتصال، والحدود، وسلوك الفشل لمراجعة سياسة Jev المباشرة." +icon: "cloud" +--- + +هذا هو مرجع مسار Cloud لـ [سياسات Jev](/ar/policies/jev). Jev، وهو المصنّف من TypeSafe، يقرأ كل استدعاء أداة مقابل ما طلبته فعلاً ويجيب إلى جانب سياساتك، وليس بدلاً منها. من خلال **FailproofAI Cloud**، تستخدم الآلة المتصلة Jev بنفس المفتاح الذي تتصل به بالفعل: لا حساب TypeSafe، لا مفتاح ثاني، لا نقطة نهاية لتكوينها. يتم تحميل كل استدعاء على بدل الخطة الحالي لمؤسستك. + +كل ما يفعله Jev لم يتغير من [إعداد bring-your-own-key](/ar/reference/jev-providers): تبقى السياسات الصارمة نهائية، يتم مسح رفض السياسة القابلة للمراجعة فقط عندما يتم السؤال عن Jev بشأن تلك المخاوف بالضبط، وأي فشل يعود إلى نتيجة regex لهذا الاستدعاء. + + +يتطلب **failproofai 1.0.8-beta.0** أو إصدار أحدث. الإصدار 1.0.7 ليس لديه Jev، على الرغم من أنه يتم ترتيبه فوق إصدارات 1.0.7 beta. بدون تكوين Jev لا يتغير شيء: تعمل الخطافات على سياسات regex تماماً كما كانت دائماً. + + +## قبل أن تبدأ + +ثبّت Failproof AI على الآلة حيث يعمل وكيلك وربط خطافاتها بـ [harness مدعوم](/ar/reference/harnesses). إذا كنت تبدأ من الصفر، اتبع [البدء السريع](/ar/start/quickstart) حتى تثبيت الخطاف. تحقق من CLI المثبت باستخدام `failproofai --version`؛ حدّثه إذا كان سابقاً لـ Jev. تحتاج أيضاً إلى الوصول إلى صفحة **Administration → Keys** في مؤسستك لإنشاء مفتاح آلة. + +يراجع Jev استدعاءات الأداة المسماة على بوابة `PreToolUse` أو `PermissionRequest`. لا يراجع كل حدث في جلسة. لترى Jev يمسح رفض السياسة، تحتاج إلى سياسة مثبتة تم تحديدها كـ [قابلة للمراجعة](/ar/policies/authority)؛ جميع رفضات السياسات الأخرى تبقى نهائية. + +## تشغيله + +1. **أنشئ مفتاحاً باستخدام Jev.** في لوحة تحكم FailproofAI Cloud، افتح **Administration → Keys → Create key** واختر إعداد **machine**. يمنح المفتاح الأذونات الثلاث التي تحتاجها الآلة: `events:add` (إرسال النشاط)، و `policies:pull` (استقبال السياسات) و `jev:evaluate` (Jev، يتم تحميله على خطة مؤسستك). لا يمكن لمفتاح أن يحمل `jev:evaluate` بدون الاثنين الآخرين. +2. **اتصل بالآلة** باستخدام هذا المفتاح. اقرأ السر لمرة واحدة في المطالبة، ثم قم بتشغيل أمر الإعداد الكامل: + + ```bash + read -rs FAILPROOFAI_CLOUD_TOKEN && export FAILPROOFAI_CLOUD_TOKEN + failproofai config + ``` + + يقوم `failproofai config` بتثبيت المراقب، وربط الخطافات لـ CLIs للعامل التي يجدها، وربط الآلة. يحافظ متغير البيئة على المفتاح بعيداً عن حجج الأمر والسجل. إذا تم تثبيت harness لاحقاً، [قم بربطه بشكل صريح](/ar/start/quickstart). + + إذا كانت مؤسستك تشغل FailproofAI Cloud الخاص بها بدلاً من الخدمة المستضافة، أضف عنوانها: `--url https://` (أو قم بتصدير `FAILPROOFAI_CLOUD_URL`). بدونه يتم فحص المفتاح مقابل الخدمة المستضافة ويفشل الاتصال. إذا كانت شهادة هذا المضيف تأتي من جهة إصدار شهادات خاصة، ثبّت جهة الإصدار في مخزن الثقة النظام للآلة (على سبيل المثال باستخدام `update-ca-certificates`)، وليس فقط في `NODE_EXTRA_CA_CERTS`: المراقب الذي يرسل الأحداث والسياسات يقرأ من المخزن النظامي. انظر [استكشاف الأخطاء](/ar/reference/troubleshooting). + +هذا كل شيء. يحتفظ الاتصال بالمفتاح، وعندما لا تملك الآلة تكوين **no** Jev بعد، يقوم بتشغيل Jev عبر FailproofAI Cloud في وضع **observe**: بمجرد أن يعطيها حزمة فحوصات، يتم السؤال عن Jev بشأن كل استدعاء أداة مغلق وتسجيل الحكم الصادر، لكن نتيجة سياساتك هي ما يتم تطبيقه. المخرجات تقول ذلك: + +```text + Jev on through FailproofAI Cloud, in observe mode: logged, not enforced (~/.failproofai/jev.json). +``` + +لا يزال Jev لا يسأل عن أي شيء حتى تعطيه حزمة فحوصات. Failproof AI لا يشحن أي شيء؛ بينما لا تعلن أي حزمة مثبتة عن أي شيء، تضيف المخرجات سطراً يقول ذلك، و `failproofai jev status` يكرره. قم بتثبيتها باستخدام: + +```bash +failproofai policies add FailproofAI/jev-policies +``` + +**مع `--no-transcripts`، الاتصال لا يقوم بتشغيل Jev.** يرسل Jev كل استدعاء أداة مفحوص والمطالبة الأخيرة إلى FailproofAI Cloud، وهو أكثر مما طلبت اتصالاً بـ decisions-only. المفتاح لا يزال مخزناً، والمخرجات تقول Jev متاح وكيفية تشغيله: + +```bash +failproofai jev setup --provider failproofai +``` + +لا يقوم بإيقاف Jev **off** أيضاً. إذا كان `jev.json` للآلة يعمل بالفعل عبر FailproofAI Cloud، فسيتم تركه كما هو، والمخرجات تقول Jev لا يزال يرسل كل استدعاء أداة مفحوص والمطالبة الأخيرة، وأن `failproofai jev setup --mode off` يقوم بإيقافه. + + +الاتصال **لا ينسخ أبداً** ملف `~/.failproofai/jev.json` الموجود. إذا كنت تستخدم بالفعل نقطة نهاية Jev الخاصة بك، فستستمر في الاستخدام، والمخرجات تقول أن الملف تم تركه كما هو مكوّن — و، عندما يترك هذا الملف Jev مطفأ (مرفوض، أو مطفأ)، يقول ذلك وكيفية إصلاحه. لتبديل هذه الآلة إلى FailproofAI Cloud، قم بتشغيل `failproofai jev setup --provider failproofai`. + + +## مراقبة، أو تطبيق أو إيقاف + +ابدأ بالمراقبة، شاهد ما كان سيفعله Jev على صفحة السياسة، ثم دعه يعمل: + +```bash +failproofai jev setup --mode enforce # تنطبق أحكام Jev: قد تمسح رفضاً قابلاً للمراجعة وتضيف الخاص بها +failproofai jev setup --mode observe # يتم السؤال عن Jev وتسجيله؛ نتيجة سياساتك هي ما يتم تطبيقه +failproofai jev setup --mode off # احتفظ بالتكوين، توقف عن السؤال عن Jev +``` + +نفس المفتاح موجود في لوحة التحكم المحلية: **Settings → Jev** لديه مفتاح تشغيل/إيقاف ومراقبة/تطبيق. يعيد كتابة الوضع و لا شيء آخر. تقرأ الخطافات التكوين في كل استدعاء أداة، لذا ينطبق التغيير من الاستدعاء التالي، بدون إعادة تشغيل. + +## تحقق مما يفعله + +```bash +failproofai jev status +failproofai jev test +``` + +يُظهر `status` المزود كـ **FailproofAI Cloud**، مضيف Cloud الذي اتصلت به الآلة، الوضع، ومصدر المفتاح كـ **FailproofAI Cloud connection**، وليس المفتاح أبداً. عندما يكون ملف `jev.json` لـ FailproofAI Cloud في مكانه لكن Jev لا يمكنه التشغيل، يقول السبب: + +| يقول `status` | `status --json` | المعنى | +| --- | --- | --- | +| **off — no Jev key is stored for this machine's FailproofAI Cloud connection** | `key-lacks-jev` | الآلة متصلة، لكن لا يتم تخزين مفتاح Jev لها: المفتاح ينقصه `jev:evaluate`، أو الاتصال لم يتمكن من تأكيده. قم بتشغيل `failproofai config` مرة أخرى مع المفتاح في `FAILPROOFAI_CLOUD_TOKEN`؛ إذا كان ينقصه الإذن، استخدم مفتاح **machine**. | +| **off — this machine is not connected to FailproofAI Cloud** | `not-connected` | لا توجد اتصالات FailproofAI Cloud على هذه الآلة ليتبع إليها مفتاح Jev. | + +بعد `failproofai config --disconnect` لا يوجد ملف `jev.json` لـ FailproofAI Cloud بعد الآن (إلا إذا تم إيقاف تشغيله، وهو محفوظ)، لذا يقول `status` ببساطة أن Jev مطفأ. يحمل `status --json` نفس الحقائق (`provider: "failproofai"`، `keySource: "cloud"`، `cloudConnected`، `keyCarriesJev`)، أيضاً عندما يكون التكوين غائباً أو مرفوضاً. `permissions` دائماً ما يكون من `jev.json`؛ رفض حول `credentials.json` يضيف `credentialsPermissions`، و `fix` عندما يصلح أمر واحد ذلك. يرسل `test` طلب مباشر واحد ويقرر الكمون والإصدار من Jev الذي أجاب. يخرج 1، ويقول ذلك في عنوانه، عندما يصل الجواب بعد timeout الخطاف (الخطافات ستسجل `timeout`) أو يجيب على سؤال الفحص بشكل خاطئ. + +لوحة تحكم **Settings → Jev** أيضاً تُظهر **FailproofAI Cloud connection**: أي تنظيم تقرير الآلة إليه وما إذا كان مفتاحها يحمل Jev. يتم قراءته من ملفات الآلة الخاصة، بدون استدعاء الشبكة. + +## تحقق من استدعاء حقيقي + +ابدأ جلسة جديدة في الوكيل المرتبط بخطاف. اطلب منه استخدام أداة قراءة الملفات الخاصة به على `README.md` والإبلاغ عن العنوان. تأكد من أن الجلسة تحتوي على استدعاء الأداة تلك، ثم قم بتشغيل `failproofai jev status` مرة أخرى: عدد الاستدعاءات المقيّمة الأخيرة يجب أن يزداد. افتح **Policies → Activity** في [لوحة التحكم المحلية](/ar/reference/local-dashboard#review-policy-activity) لتفتيش حكم Jev والوضع لهذا الاستدعاء. في Cloud، تُظهر صفحة **Policies** للمؤسسة نتائج Jev للنشاط المسلّم. في وضع المراقبة، يتم تسجيل الحكم كـ **would-have** وتحدد نتيجة السياسة لا تزال الاستدعاء. يظهر المسح فقط عندما تطابقت سياسة قابلة للمراجعة وقام Jev بمسح الفحوصات المسماة لها. + +## ما يصل إلى صفحة السياسة + +الآلة تُرسل بالفعل نشاطها للخطاف إلى FailproofAI Cloud (`events:add`). مع Jev، كل سجل استدعاء مغلق أيضاً يقول أي مقيّم تم تشغيله، ما قرره Jev، أي سياسات تم مسحها، لماذا عاد عندما فعل ذلك، كمونه وال model الذي أجاب — القرارات والرموز والأسماء، أبداً الأمر أو مطالبتك. على صفحة **Policies** لمؤسستك: + +- استدعاء قرره حكم Jev الخاص به (وضع enforce) يُنسب إلى **Jev**، وعندما جاء الفحص الذي قرّر من حزمة، السجل أيضاً يسمي تلك الحزمة وإصدارها؛ +- في وضع المراقبة، يظهر رفض أو تحذير Jev كـ **would-have**، بجانب التدحرجات التي تراقبها؛ +- يتم عد السياسات التي مسحها Jev، أو كان سيمسحها في وضع المراقبة، لكل سياسة. + +## عندما لا يستطيع Jev الإجابة + +كل واحد من هؤلاء يعود إلى نتيجة سياساتك لهذا الاستدعاء، ويتم تسجيله مع سببه: + +| السبب | السبب | +| --- | --- | +| `out-of-credits` | استخدمت مؤسستك بدل الخطة الخاص بها. | +| `http-401`, `http-403` | تم إبطال المفتاح، أو لا يحمل `jev:evaluate`. أعد الاتصال بمفتاح يحمله. | +| `http-429` | FailproofAI Cloud يحدد معدل Jev لمؤسستك. حتى ينتهي الانتظار الذي يطلبه (its `Retry-After`، بحد أقصى 60 ثانية)، الآلة لا ترسل شيئاً وكل استدعاء يعود مباشرة. يتم تسجيل الاستدعاءات المحتفظ بها بهذه الطريقة كـ `http-429`، أو كـ `rate-limited` عندما يحتفظ بها حد معدل الآلة الخاص به أولاً. | +| `http-429` (حد يومي) | استخدمت مؤسستك استدعاءات Jev اليومية: **10,000 لكل يوم UTC**، ما لم يقرر من يشغل FailproofAI Cloud الخاص بك حد آخر. كل استدعاء يعود حتى يتم إعادة تعيين العدد في 00:00 UTC؛ الآلة لا تزال تسأل مرة واحدة على الأكثر في الدقيقة، لذا تلتقط الإعادة في دقيقة واحدة. يقول `failproofai jev test` "Daily Jev limit for this org reached; resets at 00:00 UTC." | +| `http-422` | رفض Jev طلب هذا الاستدعاء، عادة لأن استدعاء الأداة كان يحمل نص كثيف (base64، hex، كود مصغّر) فوق ميزانية الرمز من Jev. هذا الاستدعاء يعود في كل مرة؛ لا تعطل. | +| `http-502` | Jev غير متاح الآن. | +| `http-503` | هذا Cloud لا يمكنه خدمة Jev لمؤسستك: لا بوابة نموذج، تنظيم لم يتم توفيره بعد، أو البوابة معطلة. اسأل المسؤول الخاص بك؛ الخطافات تسأل مرة واحدة على الأكثر في الدقيقة. | +| `http-404` | هذا FailproofAI Cloud لا يخدم Jev بعد. | +| `timeout` | لا توجد إجابة في `timeoutMs` (افتراضي 3000). | +| `model-mismatch` | إصدار Jev آخر غير 1.13 أجاب. | + +## حيث يعيش المفتاح، وحيث يذهب + +- يتم تخزين المفتاح مرة واحدة، في `~/.failproofai/credentials.json` (`0600`، في دليل مالك فقط)، بجانب بيانات اعتماد FailproofAI Cloud الأخرى. `jev.json` لا يحمل مفتاح لهذا المسار؛ واحد مكتوب هناك يجعل التكوين غير صالح. +- إذا كان `credentials.json` يحمل **any** إذن لأي شخص غيرك (مجموعة أو آخر، قراءة أو كتابة)، أو يمكن **كتابة** دليله من قبل أي شخص غيرك، فإنه **مرفوض**، لا يقرأ، و Jev مطفأ حتى تصلحه: `chmod 600` على الملف، `chmod 700` على الدليل (أو أعد الاتصال، الذي يعيد كتابة الملف في `0600` ويجعل الدليل مالك فقط). دليل يمكن لآخرين فقط قراءته بخير؛ واحد يمكنهم الكتابة يسمح لهم بمبادلة الملف. +- المفتاح يحسب فقط بينما الاتصال الذي جاء معه على الآلة: سياسة أو بيانات اعتماد التقرير لنفس FailproofAI Cloud **بنفس المفتاح**، في نفس الملف. مفتاح Jev تُرك خلف بدون واحد يتم تجاهله، و Jev يبقى مطفأ. يحدث عندما يترك `config --disconnect` من failproofai الأقدم مفتاح Jev في مكانه (لا يعرف إزالته)، أو عندما يتصل `config --token` من failproofai الأقدم بمفتاح آخر، وهو على FailproofAI Cloud قد ينتمي إلى منظمة أخرى. لتشغيل Jev مرة أخرى، اتصل مرة أخرى بمفتاح **machine**. +- يتم إرسال المفتاح فقط إلى أصل Cloud الذي تم التحقق منه. `jev.json` يشير إلى أي مكان آخر مرفوض. +- **وكيل على الآلة يمكنه قراءته.** `credentials.json` مالك فقط، والوكيل يعمل كهذا المالك. قراءة ملفات failproofai الخاصة بها مسموحة بقصد (فقط تغييرها محجوب، بـ `block-failproofai-commands`)، لذا الشيء الوحيد بين وكيل وهذا الملف هو `block-read-outside-cwd` — سياسة *قابلة للمراجعة* — ومن جلسة بدأت في دليل منزلك، لا شيء. مفتاح مع `jev:evaluate` ينفق بدل Jev لمؤسستك (حتى الحد اليومي) من أي مكان يتم استخدامه، لذا تعامل مع مفتاح آلة مثل أي بيانات اعتماد إنفاق أخرى: إذا قد يكون لدى وكيل قراءته، قم بتعطيله على صفحة المفاتيح والاتصال مرة أخرى بمفتاح جديد. +- فقط الملفات العامة الخاصة بك تقرر هذا. المستودع لا يمكنه تشغيل Cloud Jev على، أشر إليه في مكان آخر أو توفير مفتاحه، و `FAILPROOFAI_JEV_API_KEY` يتم تجاهله لهذا المسار. +- لكل استدعاء يقيمه Jev، يذهب طلب واحد إلى FailproofAI Cloud، يحمل ما [صفحة bring-your-own-key](/ar/reference/jev-providers#what-leaves-the-machine) تقائم (الأسرار محررة). FailproofAI Cloud يعيد توجيهه إلى TypeSafe ولا يسجل أو يحتفظ به. + +## أطفئه + +| الأمر | النتيجة | +| --- | --- | +| `failproofai jev setup --mode off` | احتفظ بالتكوين؛ Jev لا يتم السؤال. **هذا هو المفتاح الذي يدوم:** الاتصال مرة أخرى لا ينسخ أبداً `jev.json` الموجود، لذا Jev يبقى مطفأ حتى تقوم بتشغيله مرة أخرى مع `--mode observe`. | +| `failproofai jev remove` | احذف `~/.failproofai/jev.json`؛ Jev مطفأ — حتى `failproofai config --token` التالي مع مفتاح يحمل `jev:evaluate`، الذي يجد لا `jev.json` ويقوم بتشغيل Jev في وضع المراقبة (ما لم يعمل مع `--no-transcripts`). للحفاظ عليه مطفأ، استخدم `--mode off`. | +| `failproofai config --disconnect` | قطع الآلة: يتم إزالة المفتاح، و `jev.json` أيضاً عندما يسمي FailproofAI Cloud ولا يتم إيقافه. `jev.json` لنقطة النهاية الخاصة بك يبقى، وأيضاً واحد مطفأ، لذا Jev يبقى مطفأ عندما تتصل مرة أخرى. | + +من استدعاء الأداة التالي، تعمل الخطافات على سياسات regex تماماً كما كانت من قبل. \ No newline at end of file diff --git a/docs/ar/reference/jev-evaluations.mdx b/docs/ar/reference/jev-evaluations.mdx new file mode 100644 index 000000000..9f3719acc --- /dev/null +++ b/docs/ar/reference/jev-evaluations.mdx @@ -0,0 +1,88 @@ +--- +title: "مرجع تقييم Jev" +description: "أنواع الأسئلة والدرجات المعايرة والحدود والملء الخلفي لتقييمات جلسات Jev." +icon: "list-checks" +--- + +تصف هذه الصفحة أشكال الأسئلة وقواعد التسجيل خلف [تقييمات Jev](/ar/evaluations/jev). بعض الأسئلة تتطلب من نموذج أن *يقرأ* المحادثة، لكن ليس أن *يكتب* عنها. "هل عبّر العميل عن الاستعجالية؟" له إجابتان. "ما مدى إحباطهم؟" له عدد قليل، بالترتيب. أنت تعرف كل إجابة قبل أن تسأل. + +**تقييم التصنيف** مخصص تماماً لتلك الأسئلة. تكتب السؤال والإجابات التي قد يعطيها، ونموذج صغير مبني للتصنيف يعيد رقماً معايراً — لا تحصل أبداً على نص حر. + + +مثل القاضي، تقييم التصنيف يكلف استدعاء نموذج واحد لكل جلسة. بخلاف القاضي، إنه نموذج صغير وموحد الغرض بدلاً من نموذج عام، لذا فهو أسرع وأرخص — لكنه لن يشرح نفسه أبداً. إذا كنت بحاجة للتفكير في السبب، استخدم [قاضياً](/ar/evaluations/judge). + + +## أيهما أريد؟ + +| السؤال | الاستخدام | +| --- | --- | +| كم عدد استدعاءات الأداة التي كانت هناك؟ | code | +| هل استغرقت الجلسة أقل من 30 ثانية؟ | code | +| هل عبّر العميل عن الاستعجالية؟ | **classifier** | +| أي فريق يجب أن يتعامل مع هذا: الفواتير أو التقني أو المبيعات؟ | **classifier** | +| ما مدى إحباط العميل؟ | **classifier** | +| هل كانت الإجابة صحيحة فعلاً؟ | **judge** | +| هل اتبعت سياسة التصعيد لدينا، ولماذا تعتقد ذلك؟ | **judge** | + +القاعدة العامة: **ما يمكن عده → code، الإجابات التي يمكنك إدراجها → classifier، يحتاج توضيحاً → judge.** + +لا تضطر للقرار مقدماً. صف ما تريد قياسه والمساعد يختار، يخبرك أيهما اختار ولماذا، ويمكنك التبديل. + +## نوعا السؤال + +### `noul` — هل هذا صحيح؟ + +إجابتان، وتصف كليهما. النتيجة هي احتمالية أن تنطبق وصف "الصحيح": + +```json +{ + "instructions": "هل وعد المساعد برد الأموال دون التحقق أولاً من سياسة الاسترجاع؟", + "criteria": { + "true": "وعد برد الأموال أو تم إصداره دون فحص أو موافقة على السياسة مسبقاً", + "false": "لم يتم الوعد برد الأموال، أو اتبع كل رد سياسة فحص" + } +} +``` + +صف الجانبين. "لا استعجالية معبّر عنها" إجابة حقيقية وقول ذلك يجعل الجانب الآخر أوضح. + +### `score` — كم من هذا؟ + +مقياس مرتب، **الأسوأ أولاً**. النتيجة هي حيث تهبط الجلسة عليه، أعيد قياسه إلى 0–1: + +```json +{ + "instructions": "ما مدى إحباط العميل؟", + "criteria": ["هادئ", "محبط", "غاضب جداً"] +} +``` + +**المقياس يأخذ من ثلاثة إلى خمسة مستويات، وكلها يجب أن تكون مختلفة.** يتم قياس الحدين، وليس نمطياً: + +- **مستويان** ينهار إلى ما يفعله `noul` بالفعل بشكل أفضل، و**أكثر من خمسة** يجعل النموذج يتذبذب نحو الوسط بدلاً من الالتزام. نفس السؤال على نفس الجلسة سجل 0.00 مع مستويين، 0.01 مع ثلاثة، و0.55 مع عشرة. +- **المستويات المتكررة** تقسم الإجابة بشكل تعسفي بينها. جلسة كانت بلا شك غاضبة سجلت 1.00 ضد `["هادئ", "محبط", "غاضب جداً"]` و0.66 ضد `["غاضب", "غاضب", "غاضب"]` — رقم مشكّل بشكل جيد لا معنى له. + +الفئات بلا ترتيب — "الفواتير أو التقني أو المبيعات" — ليست مقياساً. اطرحها كـ `noul` لكل فئة، أو استخدم قاضياً. + +## قراءة النتائج + +يُنتج المصنف **درجة** من 0 إلى 1، تماماً مثل القاضي، لذا فإنها ترسم بياني وتصفي وتشغل التنبيهات بنفس الطريقة. هناك فرقان يستحقان المعرفة: + +- **لا يوجد تفكير.** الحقل فارغ، عن قصد. هذا النموذج لا يشرح نفسه، واختراع شرح سيكون تزييفاً بدلاً من أن تكون ميزة. +- **عدم اليقين معنون.** سؤال `score` يبلغ عن ثقته الخاصة، والنتيجة التي لم يكن النموذج متأكداً منها يُعلّم `low_confidence` — لذا فإن "أيها يجب على الإنسان أن ينظر إليه" مرشح بدلاً من تخمين. سؤال `noul` لا يبلغ عن الثقة، لذا لا يتم تعليمه أبداً. + +يتم قراءة الجلسات الطويلة جداً في مقتطفات ودمجها. عندما تكون الجلسة طويلة جداً لقراءتها بالكامل، تقول النتيجة كم عدد الأدوار التي تم حذفها — لن ترى أبداً حكماً يتم على جزء من الجلسة معروضاً كحكم على الكل. + +## الحدود + +- **من ثلاثة إلى خمسة مستويات مقياس، كلها مختلفة.** انظر أعلاه؛ كلا الحدين يتم فرضها في وقت التأليف. +- **سؤال واحد لكل تقييم.** اطرح شيئين وتحصل على تقييمين، وهذا أيضاً ما تريده على الرسم البياني. +- **تعديل السؤال ينشر نسخة جديدة.** الدرجات القديمة والجديدة غير قابلة للمقارنة، لذا يتم فصلها بدلاً من مزجها في خط اتجاه واحد. +- **المصنف ينتج دائماً درجة**، لا أبداً مقياساً أو تأكيداً. +- **لا يوجد تفكير**، كما هو أعلاه. إذا كان رقم سيجعل شخصاً ما يسأل "لماذا؟"، اكتب قاضياً بدلاً من ذلك. + +## الاختبار والملء الخلفي + +بخلاف القاضي، تقييم التصنيف **يمكن** اختباره قبل نشره — [اختبره](/ar/evaluations/test) ضد جلسات حقيقية بنفس الطريقة التي ستفعل بها تقييم code، واقرأ الدرجات قبل أن يذهب أي شيء مباشر. + +يمكن أيضاً [ملؤه خلفياً](/ar/evaluations/deploy#score-sessions-you-already-have) على الجلسات التي لديك بالفعل. إنه يكلف استدعاء نموذج واحد لكل جلسة، لذا حدد النافذة بقصد بدلاً من إعادة تشغيل كل شيء. \ No newline at end of file diff --git a/docs/ar/reference/jev-intent.mdx b/docs/ar/reference/jev-intent.mdx new file mode 100644 index 000000000..08a7175a7 --- /dev/null +++ b/docs/ar/reference/jev-intent.mdx @@ -0,0 +1,112 @@ +--- +title: "Jev intent capture" +description: "Which harness events tell the Jev evaluator what the human asked for, which field carries the text, what is never counted, and the risk that comes with trusting a harness-delivered prompt." +icon: "message-square-quote" +--- + +عند تكوين [Jev policy review](/ar/policies/jev)، يحكم المقيّم على كل استدعاء أداة محمية مقابل **ما طلبه الإنسان فعلياً**، وليس مقابل أي نص وضعته الحزمة أمام الوكيل. يمكن لرد مثل "نعم، قم بفرض الدفع" أن يمرر سياسة **قابلة للمراجعة** — وهذا هو القصد من المقيّم بالفعل، لأن regex الذي لا يستطيع قراءة الطلب يمنع ثلث العمل الحقيقي. + +يأتي هذا النص من مكان واحد: **الطلب الذي تسلّمه الحزمة نفسها للـ hook عند حدث prompt-submit**. يسجل Failproof AI الجزء الذي كتبه الإنسان — مع إزالة تغليف الحزمة والأسرار المحررة والمحدودة — في ملف `0600` تحت دليل الحالة الخاص به. لا يتم الاستشارة على أي ملف على القرص: نص الجلسة هو ملف يمكن للوكيل إعادة كتابته بأمر واحد، لذلك لا يُسأل أبداً عن من كتب الطلب. + +## المخاطرة التي يقبلها هذا بوضوح + +يمكن لوكيل يمكنه بالفعل تشغيل الأوامر أن يجعل الحزمة تسلم طلباً. `claude -p "…"`، `codex exec`، `copilot -p`، `cursor-agent -p`، `devin -p`، `droid -p`، `goose run -t` و `pi -p` كلها تطلق حدث prompt-submit نفسه، بنفس الحمل البياني، مثل شخص يكتب في جلسة فرعية يتحكم بها. يمكنه أيضاً تشغيل ملف hook الثنائي الخاص بـ Failproof AI وإطعامه حمولة كتبها. لا يوجد شيء داخل Failproof AI يمكنه التمييز بين الاثنين — كلاهما نفس البرنامج يقرأ نفس stdin. + +**إذاً وكيل لديه shell يمكنه زيّ موافقته الخاصة.** هذا تبادل متعمد، تم اتخاذه في 2026-09-23، وإليك كلا الجانبين: + +- **ما الذي تشتريه.** تم بناء البديل وقياسه: اطلب حقلاً تسمي فيه الحزمة إنساناً باعتباره مؤلف الطلب، ولا تسجل شيئاً وإلا. لا توجد حزمة شحن ترسل مثل هذا الحقل، لذلك سجلت تلك النسخة **لا شيء، على كل حزمة** — حكم Jev على كل استدعاء بدون نية مذكورة ولم يتمكن أبداً من تمرير سياسة واحدة. التقاط لا يطلق أبداً ليس منتجاً أكثر أماناً، إنه لا منتج. +- **ما الذي لا يستطيع فعله.** يمكن فقط للطلب المسجل أن يمرر سياسة محددة مسبقاً بـ **قابلة للمراجعة**. لا تُمرر سياسة **صعبة** أبداً بأي شيء يقوله Jev، لذلك لا يمكن لطلب مزيف أبداً أن يحول نفي صعب إلى السماح — وتخطي الـ hook لا يكسب الوكيل شيئاً أيضاً: الحزمة تستدعي Failproof AI لاستدعاء الأداة بشكل مستقل. +- **ما الذي يمكنه فعله، بحجمه الكامل.** الأسوأ الذي يمكنه فعله هو تمرير إحدى السياسات الخمس عشرة القابلة للمراجعة المدمجة — و **اثنتا عشرة من تلك الخمس عشرة تمنع**. `protect-env-vars`، `block-env-files`، `block-read-outside-cwd`، `block-rm-rf`، `block-force-push`، `block-secrets-write` وستة كتل infrastructure-CLI (`block-kubectl`، `block-terraform`، `block-aws-cli`، `block-gcloud`، `block-az-cli`، `block-helm`) هي عمليات منع، لذلك يمكن لموافقة مزيفة أن تحول منع حقيقي إلى سماح بطباعة أسرار البيئة، قراءة ملف `.env`، القراءة خارج المشروع، `rm -rf`، دفع قسري، كتابة ملف أسرار، أو تغيير البنية التحتية المباشرة. فقط `warn-git-amend`، `warn-destructive-sql` و `warn-global-package-install` هي تنبيهات. التثبيت الافتراضي يشغل اثنين من الاثني عشر، `protect-env-vars` و `block-env-files`؛ العشرة الأخرى تصل فقط إلى جهاز قام شخص ما بتمكينها عليه. ما لا يصل إليه أي طلب هو كل شيء صعب — `block-sudo`، `block-curl-pipe-sh`، `block-push-master`، `block-work-on-main`، الحراس الذين يوقفون وكيل تعطيل Failproof AI، وكل بديل مدمج آخر غير محدد قابل للمراجعة. [Policy authority](/ar/policies/authority) يسرد كل خمسة عشر ويخبر بما يتم مراجعة كل واحدة. + +ما يتم رفضه لا يزال كل شيء رخيص للتحقق منه وأن الوكيل لا يمكنه الحصول عليه فقط بالطلب: دور تحدده حمولة الحزمة نفسها كمقدم من الآلة، حمولة تسمي وكيلاً فرعياً، معرف جلسة وليس اسماً عادياً، حدث ليس حدث prompt-submit، ونص ليس شيئاً سوى تغليف الحزمة — بما في ذلك كلمات stop-gate الخاصة بـ Failproof AI، التي توجهها عدة حزم مرة أخرى كالدور التالي للمستخدم. + +## جدول لكل حزمة + +"Text field" هو حقل حمولة stdin بعد معايرة Failproof AI لكل حزمة. "Recorded" يقول ما إذا كان الطلب محفوظاً كطلب الإنسان. + +| Harness | `--cli` | Prompt event → canonical | Text field | Recorded | Agent's last message read from | +| --- | --- | --- | --- | --- | --- | +| Claude Code | `claude` | `UserPromptSubmit` | `prompt` | نعم، إلا إذا سمّى `source` الحمولة دوراً لم يقدمه أحد (`loop_wakeup`، `schedule_wakeup`، `poll_event`، `system`). `user`، `sdk`، قيمة غير معروفة وبناء لا يرسل `source` على الإطلاق يتم تسجيل الكل | نص جلسة العمل (`transcript_path`) | +| Codex | `codex` | `user_prompt_submit` → `UserPromptSubmit` | `prompt` | نعم | JSONL الإصدار (`agent_message`، `AgentMessage`) | +| GitHub Copilot CLI | `copilot` | `UserPromptSubmit` | `prompt` | نعم | `events.jsonl` (`assistant.message`) | +| Cursor | `cursor` | `beforeSubmitPrompt` → `UserPromptSubmit` | `prompt` | نعم، مع إزالة `` wrapper عند كونها الطلب الكامل | نص جلسة الوكيل JSONL | +| OpenCode | `opencode` | `message.updated` (user role) → `UserPromptSubmit` | `prompt` | نعم — لكن OpenCode الحالي لا يحمل أي نص في هذا الحدث، لذلك عملياً لا يتم تسجيل شيء؛ يتم تسجيل نفس الرسالة المتكررة مرة واحدة | لا شيء (الجلسات SQLite) | +| Pi | `pi` | `input` → `UserPromptSubmit` | `prompt` | نعم، إلا إذا كان `input_source` من `extension` — `sendUserMessage()` لملحق آخر، حيث يمكن أن يكون النص مكتوباً من النموذج أو مشتقاً من الريبو | Pi جلسة JSONL | +| Hermes | `hermes` | لا يوجد | — | لا — Hermes ليس لديها حدث prompt-submit على الإطلاق | — | +| OpenClaw | `openclaw` | `before_agent_run` → `UserPromptSubmit` | `prompt` | نعم، إلا إذا كانت metadata التشغيل تحدد التشغيل كآلة: `trigger` بخلاف `user`، `inputProvenance.kind` بخلاف `external_user`، أو `senderIsOwner: false` | لا شيء (`before_agent_run` لا يحمل مسار النص) | +| Factory Droid | `factory` | `UserPromptSubmit` | `prompt` | نعم | دورويد جلسة JSONL | +| Devin CLI | `devin` | `UserPromptSubmit` | `prompt` | نعم | لا شيء (الجلسات SQLite) | +| Antigravity CLI | `antigravity` | `PreInvocation` → `UserPromptSubmit` | لا شيء | لا — `PreInvocation` يطلق قبل *كل* استدعاء نموذج في دور ولا يحمل نص طلب | — | +| Goose | `goose` | `UserPromptSubmit` | `message` | نعم | لا شيء (الجلسات SQLite) | + +حزمتان لا تسجلان شيئاً، والسبب نفسه في كلا الحالتين: الحدث لا يوصل أي نص بشري. Hermes ليس لديها حدث prompt-submit — المكون الإضافي الأصلي يتعامل مع `pre_llm_call` بنفسه ويرسل فقط أدوات وأحداث جلسة وأحداث وكيل فرعي. `PreInvocation` الخاص بـ Antigravity يطلق قبل كل استدعاء نموذج، على دور بشري وفي الخمسة التي تتبعها، ولا يحمل حقل طلب؛ يمكن للـ hooks أيضاً حقن خطوات `userMessage` في نفس المحادثة. لا يوجد شيء في أي حدث للتسجيل. + +## ما الذي يجعل الطلب خاصاً بالإنسان + +1. **الحدث.** تم استدعاء Failproof AI لحدث prompt-submit الخاص بالحزمة، الذي المعالج يقسمه إلى `UserPromptSubmit`. +2. **الحمولة البيانية.** الحزمة تكتبها على stdin الـ hook، وتحمل النص في الحقل المسمى أعلاه. لا يسجل الاستدعاء الذي يصل إلى Failproof AI بدون الحمولة شيئاً. +3. **لا شيء في الحمولة يستبعد الدور.** حمولة تسمي وكيلاً فرعياً (`agent_id`) هي الوكيل الذي يحفز نفسه. `source`، `input_source` أو علامة تشغيل OpenClaw التي تسمي دور مقدم من الآلة يتم رفضه. علامة **غائبة** لا تستبعد شيئاً — وهذا هو الفرق عن النسخة التي لم تسجل شيئاً، لأن كل علامة هنا غائبة على كل بناء شحن. +4. **يبقى شيء ما بعد إزالة التغليف** (انظر أدناه). + +**نص جلسة العمل ليس دليلاً على من كتب الطلب.** الإصدارات السابقة من هذه الصفحة وصفت فحص النص المتقاطع: تم رفض الطلب إذا أظهر النص أن النموذج جدوله، وكان يجب على النص أن يستمر في النص الذي شهده الطلب السابق. ذهب هذا الفحص. النص هو ملف الوكيل بالفعل له shell عليه — يمكن اختصاره أو استبداله أو تعديله بعد ميزانية القراءة أو الحصول على صورة في بداية الدور واستعادتها في النهاية أو جعله يقرأ بشكل جيد مرة أخرى بإدخالات كتبها الوكيل. اتبعت كل جولة من التصلب بتهجئة أخرى من نفس الزيف، لذلك تم إزالة الآلية بأكملها بدلاً من إصلاحها. + +لا يزال النص مقروءاً لشيء واحد: **الرسالة الأخيرة المرئية للوكيل**. تلك الرسالة مكتوبة من قبل الوكيل بالتعريف، يُخبر Jev بذلك، وليس موافقة بمفردها أبداً. + +## ما الذي يتم الاحتفاظ به من الطلب + +تضع الحزم أكثر من كلمات الإنسان في الطلب. قبل تخزين أي شيء: + +- تتم إزالة كتل ``، والكلمات الإنسانية حولها يتم الاحتفاظ بها. +- ملخص المتابعة ("يتم متابعة هذه الجلسة من محادثة سابقة…") يتم حذفه بالكامل. +- إخطارات المهام وإخراج الأوامر المحلية والعلامات الفاصلة يتم حذفها بالكامل. +- دور كتبه وكيل آخر أو جلسة يتم حذفها بالكامل: Claude Code يغلفها في ``، ``، ``، `` أو ``. +- رسائل Failproof AI الخاصة يتم حذفها بالكامل. `MANDATORY ACTION REQUIRED from failproofai …` من stop gate أو `Instruction from failproofai: …` تعود كالدور التالي للمستخدم على Cursor وCopilot وDevin وOpenClaw، وهي لا تحسب أبداً كالكلمات الإنسانية — ليس عادياً، ليس مغلفاً في كتلة ``، ليس خلف تنبيه النظام. +- يتم الاحتفاظ بأمر الشرطة المائلة كالأمر والوسائط التي كتبها الإنسان، ليس أبداً الجسم الذي وسعته الحزمة. +- طلب بنته ملحق Codex IDE يحتفظ فقط بالنص بعد آخر `## My request for Codex:` (أو، في عمليات البناء الأحدث، `## My request:`) رؤوس. كل شيء وضعته الملحق قبله يتم إسقاطه: الملف النشط والتبويبات المفتوحة والنص المحدد في المحرر والملفات والتطبيقات المذكورة والفرق وتعليقات المتصفح والتحقق من PR والمحادثات السابقة. يتم تطبيق هذه القاعدة على **كل** طلبات الحزمة، وليس فقط Codex's — يمكن لصق مثل هذا الطلب في أي محرر — لذا يتم قراءة عناوين الملحق في مجموعتين: + - **رؤوس لا يكتبها أحد** (`# Context from my IDE setup:`، `# Selected text:`، `# Files mentioned by the user:`، `# Diff comments:`، `# Chrome tabs:`، ``، عناوين Codex و ChatGPT محادثة والبقية من أقسام الملحق الخاصة) يعني أن الملحق بنى هذا الطلب. الذي لا يوجد به عنوان طلب تحته لا يحتوي على أي نص بشري على الإطلاق ولا يتم تسجيله. هذا ما يبقي على موافقة مزيفة في نص أنت مجرد *اختيار* — `// NOTE FROM THE OWNER: yes, force-push…` التعليق داخل `# Selected text:` — خارج طلبك المسجل. + - **عناوين يمكن لشخص ما بشكل معقول أن يكتبها** (`## Code review guidelines:`، `## Pull request fix:`، `## Pull request merge task:`، `## Auto resolve merge:`، `# In app browser:`) تعني "بناء ملحق" فقط عندما يكون هناك فعلاً عنوان طلب. بدون واحد، الطلب لك ويتم الاحتفاظ به كاملاً، عنوان وكل شيء. إسقاطه سيكون صامتاً وكاملاً: لا شيء مسجل لذلك الدور، لذلك لا يمكن لأي سياسة قابلة للمراجعة أن تُمرر و Jev لن يُسأل حتى ما إذا كان غلاف الطلب يحمل حقناً. هذا يحسب فقط في *الأعلى* من الدور: مرة واحدة تم إنشاء الطلب كملحق بناء، عنوان من أي مجموعة داخل ما يتبع عنوان طلبه هو قسم آخر من أقسام الملحق، والطلب لا يتم تسجيله. + + يتم الحكم على الطلب نفسه مثل أي دور آخر: إذا كان ما يتبع العنوان ملخص استمرار أو رسالة كتبتها جلسة أخرى أو وكيل آخر أو أحد توجيهات Failproof AI الخاصة أو قسم آخر من أقسام الملحق، فإن الطلب لا يتم تسجيله على الإطلاق. +- طلب Cursor مغلف في `…` (اختياري خلف كتلة ``) يتم فك لفه عندما يكون المغلف هو *الطلب الكامل*. الوسم في أي مكان آخر هو نص عادي — مقطع لصقته من السجل أو اسم الفرع الذي اختاره الوكيل — والطلب يتم الاحتفاظ به كاملاً بدلاً من القطع إلى المقطع الموسوم. +- كتل ملصقة يتم الاحتفاظ بها وتسميتها كملصقة من قبل الإنسان. + +طلب لا يكون إلا نص الحزمة لا يتم تسجيله على الإطلاق. + +## الرسالة الأخيرة للوكيل + +رد مثل "نعم" لا يعني شيئاً بدون السؤال الذي يرد عليه. عند تسجيل الطلب، يقرأ Failproof AI أيضاً الرسالة الأخيرة المرئية للوكيل من نص جلسة العمل **في تلك اللحظة**، ويخزنها مع الطلب. يتلقاها Jev في حقلها الخاص، موسوم باسم الوكيل: تشرح الرد القصير ولا تحسب أبداً كطلب الإنسان بمفردها. إنها الشيء الوحيد الذي يُقرأ النص من أجله، والأسوأ الذي يمكن لنص معاد كتابته أن يفعله هو وضع رسالة كتبتها الوكيل حيث رسالة كتابتها الوكيل متوقعة. + +يتم قراءتها من نهاية النص، بأقصى حد 4 MB الأخيرة. تنسيقات النص المدعومة هي Claude Code، Codex rollouts (`agent_message` events أقدم و `AgentMessage` items أحدث)، Cursor، Copilot `events.jsonl`، و Pi وFactory و OpenClaw جلسة JSONL. رسائل Claude Code الاصطناعية الخاصة ورسائل API-error ورسائل الوكيل الفرعي (sidechain) يتم تخطيها. لا توجد لقطة صورة لـ Goose و OpenCode، التي تحتفظ بجلسات في SQLite، بخصوص Devin، الذي نصه document JSON واحد، أو OpenClaw، الذي حدث `before_agent_run` لا يحمل مسار النص. + +## التخزين + +| Property | Value | +| --- | --- | +| Location | `~/.failproofai/state/semantic/sessions/.json` | +| Permissions | ملف `0600`, دليل `0700`. كل دليل فوقه، حتى `~/.failproofai`، يتم الاحتفاظ به بنفس القاعدة `jev.json` الدليل: واحد يمكن لأي شخص آخر **كتابة** إليه يمكن إعادة تسميته واستبداله، لذا يأخذ مسار القراءة تلك بتات الكتابة حيث يمكنه، و **يقرأ لا شيء** حيث لا يستطيع. طلب مسجل هو غائب بدلاً من كونه مزيفاً، ولا شيء يُمرر | +| Kept per session | آخر 5 طلبات؛ طلب مطابق للواحد قبله يستبدله بدلاً من أخذ فتحة جديدة | +| Window | الطلبات الأقدم من 6 ساعات يتم تجاهلها | +| Size | كل طلب ورسالة وكيل مكبوت في 6000 حرف، يحتفظ بالرأس والذيل | +| Secrets | محررة بنفس الأنماط مثل السياسات `sanitize-*` قبل تسجيل أي شيء. نص أطول من 48000 حرف محرر كأول 28800 وآخر 19200 حرف، والنص بجانب تلك القطع، حيث يمكن أن يتم تقسيم سر، لا يتم حفظه أبداً | + +معرف جلسة يحتوي على أي شيء سوى الحروف والأرقام و `.` و `_` و `-`، أو أطول من 128 حرف، لا يتم استخدامه أبداً كاسم ملف، لذا لا يتم تسجيل شيء له. + +ملف جلسة موجود مرة واحدة فقط بعد تسجيل الطلب فيه. يحتفظ بطلبات ولا شيء آخر — لا حالة أصل، لا علامة نص — ويتم حذفه مرة واحدة بعد صمته لفترة أطول من نافذة ست ساعات، المرة القادمة جلسة جديدة تكتب طلبها الأول. + +لا يتم تسجيل شيء إلا إذا تم تكوين Jev endpoint. + +### جذر المشروع + +"داخل المشروع" — ما `read-outside-workspace` والفحوصات الأخرى للمسار تحكم عليه — يعني داخل المشروع كانت الجلسة فيه عند **أول استدعاء مراجع**. الجذر يتم تثبيته ثم و `cd` لاحق أبداً لا يحركه؛ `cd` لا يزال يغير كيفية حل المسار النسبي. السماح له بمتابعة `cd` سيسمح بـ `cd ~/.ssh` في استدعاء واحد جعل `~/.ssh` المشروع للقادم. + +الدبوس هو `~/.failproofai/state/semantic/roots/.json`، يحتفظ بـ `{root, at}`: ملف `0600`، دليل `0700`، وقاعدة معرف الجلسة نفسها كما هو أعلاه. الملفات الأقدم من 7 أيام يتم حذفها عندما جلسة جديدة تثبت جذرها. دليل `roots` يمكن لمستخدمين آخرين كتابة إليه يتم تجاهله، وجذر دليل الحي يتم استخدامه بدلاً منه. لإعادة تثبيت جلسة، احذف ملفها. + +## الحدود المعروفة + +- **الطلب موثوق فقط قدر استدعاء الـ hook.** كل شيء هنا يقرأ الحمولة التي كتبتها الحزمة على stdin الـ hook. وكيل يمكنه تشغيل الأوامر يمكنه تشغيل الحزمة بدون رأس (`claude -p` والسبعة الآخرون المدرجون أعلاه) أو تشغيل ملف hook الثنائي الخاص بـ Failproof AI نفسه مع حمولة كتبها، وتسجيل طلب لم يكتبه أحد. هذا هو التبادل المقبول الموصوف في أعلى هذه الصفحة: فقط يمرر السياسات القابلة للمراجعة، أبداً صعبة واحدة — لكن اثنا عشر من الخمسة عشر القابلة للمراجعة المدمجة هي عمليات منع، لذا يمكن لطلب مزيف أن يحول منع حقيقي إلى سماح على تلك الاثني عشر. +- **كشف الوكيل الفرعي له شكل Claude.** حمولة تحمل `agent_id` لا يتم تسجيلها أبداً، على أي حزمة. هذا هو الحقل Claude Code وFactory Droid وDevin سيستخدمون. Codex يطلق حدث طلبه داخل خيوط وكيل فرعي، Copilot يشغل sidekicks داخل العملية، Goose لديه أداة `delegate` و OpenClaw يشغل personas — لا شيء منها يحدد الحمولة بطريقة يتم التعرف عليها، لذا طلب وكيل فرعي على تلك الحزم يتم تسجيله كخاص بالجلسة. `openclaw.agentId` الخاص بـ OpenClaw **ليس** تلك العلامة: المكون الإضافي المشحون يعينه على كل تشغيل، المالك الخاص به يتضمن. +- **الجدولات التي لا تحمل علامة.** `schedule_wakeup` و `loop_wakeup` الخاصة بـ Claude Code، و `cron` و `heartbeat` triggers الخاصة بـ OpenClaw، يتم رفضها لأن تلك الحزم تقول ذلك في الحمولة. جدول Goose الخاص (`goose schedule add`) و `codex exec` لا يقولان شيئاً، لذا التشغيل الذي يبدآنه يتم تسجيله مثل أي آخر. +- **رسالة الوكيل الأخيرة يمكن أن تكون رسالة اختار الوكيل.** النص ليس موثوق، لذلك وكيل يكتب نصه الخاص يمكنه أن يقرر ما تقول "رسالته الأخيرة". يتم تسميتها كمكتوبة من الوكيل ولا تمرر شيئاً بمفردها — لكن لاحظ أن مسار v1 من `decide.ts` يسمح بها بإرضاء الفحص المحدد "هل سمّى المستخدم هذا الهدف"، لذا وكيل يتحكم بنصه يمكنه توفير اسم هدف يحتاج تجاوز. +- **طلب يفتح مع أحد عناوين الملحق الآلية يتم حذفه كاملاً.** ابدأ طلباً بـ `# Selected text:`، `# Diff comments:`، `# Chrome tabs:` أو عنوان قسم آخر من المجموعة الأولى أعلاه، ولا تكتب أبداً عنوان `## My request:`، ولا شيء يتم تسجيله لذلك الدور — لذا لا شيء يتم تمريره له أيضاً. هذا متعمد: تلك الأقسام تحمل نصاً يتحكم به شخص آخر (الكود الذي اخترته، تعليق diff المراجع، عنوان الصفحة)، وتسجيل ذلك كالكلمات الخاصة بك هو الفشل الأسوأ. العناوين التي يمكن لمطور أن يكتبها بشكل معقول في المجموعة الثانية ولا تسقط الطلب بمفردها أبداً. +- **OpenCode يسجل لا شيء عملياً.** حدث `message.updated` الخاص به لا يحمل نصاً في OpenCode الحالي، وأيضاً يطلق للجلسات الفرعية التي تنشئها الأداة task الخاصة به، التي "رسالة" المستخدم الخاصة كتبها الوكيل الأبوي. +- **`CODEX_HOME` لا يتم احترامه** من قبل كشف rollout في `lib/codex-sessions.ts`. هذا يؤثر فقط على حيث يتم البحث عن لقطة الرسالة الوكيل، أبداً ما إذا كان الطلب يتم تسجيله. \ No newline at end of file diff --git a/docs/ar/reference/jev-providers.mdx b/docs/ar/reference/jev-providers.mdx new file mode 100644 index 000000000..dc94dfa4d --- /dev/null +++ b/docs/ar/reference/jev-providers.mdx @@ -0,0 +1,275 @@ +--- +title: "مزودو Jev والإعدادات باستخدام مفتاحك الخاص" +description: "نقاط نهاية المزود، معرّفات النماذج، الإعدادات، وسلوك الفشل لمراجعة سياسة Jev المباشرة باستخدام مفتاحك الخاص." +icon: "key-round" +--- + +هذا هو مرجع المزود والإعدادات لـ [سياسات Jev](/ar/policies/jev) باستخدام مفتاحك الخاص. تطابق السياسات العادية (Regex) النصوص. لا يمكنها التمييز بين `rm -rf build/` التي طلبتها و`rm -rf ~` التي انزلقت إلى خطة ما، لذلك تحجب الكثير في مكان ما والقليل جداً في مكان آخر. **Jev**، مصنف TypeSafe، يقرأ الاستدعاء مقابل ما طلبته فعلياً ويجيب على مجموعة من أسئلة نعم/لا عنه في طلب واحد سريع. + +مع نقطة نهاية Jev الخاصة بك والمفتاح المكوّن، يسأل Failproof AI عن Jev حول كل استدعاء أداة **بجانب** السياسات العادية، وليس بدلاً منها: + +- رفض سياسة **صارمة** نهائي. لا يمكن لـ Jev إلغاؤه. كل سياسة صارمة ما لم تُحدد صراحة كقابلة للمراجعة وتسمي فحوصات Jev التي تغطيها، لذا فإن السياسة المخصصة أو الحزمة أو سياسة Cloud التي لا تقول شيئاً هي صارمة، وحارس الحماية الذاتية المفعل دائماً صارم دائماً. +- قد يتم إلغاء رفض سياسة **قابلة للمراجعة**، لكن فقط عندما طُلب من Jev السؤال عن القلق الدقيق الذي تغطيه السياسة وأجاب "لا شيء هنا" أو "المستخدم طلب هذا". الفحص الذي يجد القلق حقيقياً، عندما لم يطلب المستخدم الاستدعاء، يحافظ على الرفض — حتى عندما تكون نتيجته الخاصة مجرد تحذير فقط، لأنه قبل استدعاء الأداة فإن التحذير لا يوقف الوكيل. وعندما يكون هذا الفحص من بين من يمكن له الرفض (تعريض السرية، إساءة الاستخراج، الحذف المدمّر، ...)، لا شيء يتم إلغاؤه على هذا الاستدعاء. +- الحجب قد يصبح **تحذيراً** عندما يكون الاستدعاء خطوة من المهمة التي أعطيتها ولا يمتد أبعد: يلين Jev رفضه إلى تحذير، وهذا التحذير — الذي يسمي ما هو خطأ فعلاً في الاستدعاء — يستبدل حجب السياسة. +- يمكن لـ Jev أيضاً أن يحذّر أو يرفض بمفرده، لضرر لا تصفه أي قاعدة عادية. +- إذا لم يستطع Jev الإجابة (انتهاء المهلة الزمنية، حد معدل، خطأ الخادم، بدون ائتمانات، إصدار نموذج غير متوقع)، فإن هذا الاستدعاء يحصل على نتيجة القاعدة العادية، تماماً كما هو بدون Jev. +- لا يجعل Jev الاستدعاء أكثر تساهلاً من سياساتك وحدها ما لم يقرأ الاستدعاء بالكامل وطُلب منه السؤال عن القلق الدقيق. أي شيء أقل — استدعاء كبير جداً لإرساله كاملاً، حقن مريب — ينسحب التصريحات ويحافظ على كل رفض. + + +بدون إعدادات Jev لا يتغير شيء: تشغيل الخطاطيف السياسات العادية تماماً كما كانت دائماً. الإعدادات هي الاختيار الكامل. + + + +في FailproofAI Cloud؟ أنت لا تحتاج مفتاحك الخاص: جهاز متصل بمفتاح يحمل `jev:evaluate` يمكنه استخدام Jev في خطة منظمتك. انظر [Jev عبر FailproofAI Cloud](/ar/reference/jev-cloud). + + +## قبل أن تبدأ + +ثبّت **failproofai 1.0.8-beta.0 أو أحدث** وألحق خطاطيفها بـ [جهاز دعم](/ar/reference/harnesses) على الجهاز حيث يعمل وكيلك. اتبع [البدء السريع](/ar/start/quickstart) إذا كان هذا جهازاً جديداً، أو [اضبط الإنفاذ محلياً](/ar/start/setup#enforce-locally) إذا كنت لا تستخدم Cloud. تحقق من واجهة سطر الأوامر المثبتة باستخدام `failproofai --version`. + +احصل على مفتاح API من مزود أدناه، أو جهز نقطة نهاية متوافقة والمفتاح الخاص بها. يراجع Jev استدعاءات الأداة المسماة في بوابة `PreToolUse` أو `PermissionRequest`. يمكنه إصدار حكمه الخاص، لكن إلغاء رفض سياسة موجود يتطلب أيضاً سياسة مثبتة محددة [قابلة للمراجعة](/ar/policies/authority). يبقى رفض السياسة الصارمة نهائياً. + +## اختر مزوداً + +يمكن الوصول إلى Jev عبر خمس طرق. أحضر مفتاحاً لأي واحد منها. + +| المزود | `--provider` | نقطة النهاية | النموذج الافتراضي | ملاحظات | +| --- | --- | --- | --- | --- | +| TypeSafe | `typesafe` | `api.typesafe.ai/v1/systemone` | `jev-1.13.0` | دبوس إصدار دقيق. | +| OpenRouter | `openrouter` | `openrouter.ai/api/v1/systemone` | `typesafe/jev-1.13` | يتم توجيه الطلبات إلى نقاط نهاية بدون احتفاظ بالبيانات فقط، بدون الرجوع إلى مزود آخر. يُبلّغ عن إصدار مؤرخ مثل `typesafe/jev-1.13-20260917`. | +| بوابة Vercel AI | `vercel` | `ai-gateway.vercel.sh/typesafe/v1/systemone` | `typesafe-ai/jev` | يسمّي Jev بالاسم المستعار فقط، لذا يتم تسجيل الإصدار الذي يجيب كغير تم التحقق منه. | +| Cloudflare Workers AI | `cloudflare` | `api.cloudflare.com/client/v4/accounts//ai/run` | `typesafe/jev` | يحتاج `--account-id`. تم قياس حوالي ستة استدعاءات في الثانية لكل مفتاح قبل HTTP 429. | +| نقطة النهاية الخاصة بك | `custom` | `/systemone` | `jev-1.13.0` | أي نقطة نهاية تقبل جسم طلب TypeSafe وتُبلّغ عن النموذج الذي أجاب. `https` فقط؛ `http://localhost` عادي مقبول في وضع المراقبة فقط. | + + +مع ميزة bring-your-own-key الخاصة بـ Vercel، تُعاد محاولة الطلب الفاشل بصمت باستخدام بيانات اعتماد Vercel. إذا كنت تحتاج كل استدعاء سيتم فرض رسوم على حسابك الخاص بـ TypeSafe فقط ورؤيته، استخدم TypeSafe مباشرة. + + +## اضبطها + +أمر واحد، نقطة النهاية والمفتاح. ابدأ في وضع `observe` حتى تتمكن من فحص أحكام Jev بينما تستمر السياسات الموجودة في اتخاذ القرارات: + +```bash +failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key +``` + +### يختار URL المزود + +لا تحتاج إلى تسمية المزود: **المضيف** في URL هو أيها. + +| مضيف URL | المزود | يحتاج أيضاً إلى | +| --- | --- | --- | +| `api.typesafe.ai` | `typesafe` | — | +| `openrouter.ai` | `openrouter` | — | +| `ai-gateway.vercel.sh` | `vercel` | — | +| `api.cloudflare.com` | `cloudflare` | `--account-id <32-hex-account-id>` | +| أي مضيف آخر | `custom` | — URL الذي أعطيته هو URL الأساسي | + +ثلاثة أشياء تتبع من ذلك: + +- **URL يكتب API المزود الخاص به لا يكتب أي تجاوز.** `--url https://api.typesafe.ai/v1` ينتج بالضبط الإعدادات التي `--provider typesafe` ستكون. أعط مساراً أو مضيفاً مختلفاً على مزود معروف وسيتم تخزينه كـ URL الأساسي، كما يفعل `--base-url` يخزنه. +- **`--provider` لا يزال يتجاوز الاستنتاج**، وهي كيفية الوصول إلى وكيل يتحدث API المزود من مضيف خاص بك: `--url https://jev-proxy.internal/v1 --provider typesafe`. +- **`--provider` يتناقض مع المضيف يتم رفضه**، لا يتم التخمين فيه. `--provider openrouter --url https://api.typesafe.ai/v1` لا يكتب شيئاً ويقول السبب: الترجمتان تختلفان حول مكان إرسال مفتاحك. يتم رفض نفس الزوج من `jev setup --base-url` ومن إعدادات Jev في لوحة التحكم. (`--provider custom` ليس تناقضاً — يعني "تعامل هذا URL كما هو" — إلا على مضيف Cloudflare، الذي لا يمكن لمسار مخصص الوصول إلى نقطة النهاية لكل حساب.) + +يتم التحقق من `--url` بالضبط كما `baseUrl` في ملف الإعدادات، ويتم رفضه بنفس الكلمات: `https`، أو `http://localhost` عادي في وضع المراقبة فقط. + +### المفتاح + +أنبوبه باستخدام `--key-stdin`، أو قم بتشغيل الأمر في محطة بدون ذلك والصق المفتاح في موجه مقنع. على أي حال يذهب مباشرة إلى ملف الإعدادات ولم تُطبع مرة أخرى. + + + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key + ``` + + + ```bash + failproofai jev --url https://openrouter.ai/api/v1 --mode observe --key-stdin < ~/openrouter.key + ``` + + + ```bash + failproofai jev --url https://ai-gateway.vercel.sh/typesafe/v1 --mode observe \ + --key-stdin < ~/vercel-gateway.key + ``` + + + ```bash + failproofai jev --url https://api.cloudflare.com/client/v4 \ + --account-id <32-hex-account-id> --mode observe --key-stdin < ~/cloudflare.token + ``` + + + ```bash + failproofai jev --url https://jev.internal.example.com/v1 --mode observe --key-stdin < ~/jev.key + ``` + + + +`failproofai jev setup` يأخذ نفس الأعلام وهو الصيغة الطويلة لكل ذلك: `setup --provider ` حيث تفضل تسمية المزود بدلاً من URL. + +### `--token`، وماذا يكلف + +`--token ` يضع المفتاح على سطر الأوامر، وهي أسرع طريقة لإعدادات جهاز والصيغة الوحيدة التي تترك المفتاح في أي مكان ما عدا ملف الإعدادات: + +```bash +failproofai jev --url https://openrouter.ai/api/v1 --token +``` + + +يكون حجة سطر الأوامر في ملف السجل بعدها، وبينما الأمر يعمل يكون في قائمة العملية — قابل القراءة من `/proc` بأي شيء يعمل كما أنت. `setup` يقول ذلك في كل مرة يتم استخدام `--token`. تفضل `--key-stdin` على جهاز تشاركه، في جلسة مسجلة، أو في أي مكان يتم مزامنة ملف السجل فيه؛ استدر مفتاحاً مررت بهذه الطريقة إذا كان مهماً. + + +`--token`، `--key-stdin` و `--key-from-env` متعارضة بشكل متبادل: أعط واحداً. + +ثم أرسل طلب حي صغير واحد للتحقق من المفتاح ونقطة النهاية وأي Jev أجاب: + +```bash +failproofai jev test +``` + +```text + failproofai jev test ok · 523 ms + + provider cloudflare + model asked typesafe/jev + answered by jev-1.13.0 (Jev 1.13 family — verified) + latency 523 ms — within the 3000 ms timeout +``` + +`jev test` يخرج 1، ويقول ذلك في عنوانه، عندما تصل الإجابة بعد انتهاء المهلة الزمنية (كل خطاف ستعود إلى القاعدة العادية كـ `timeout`) أو تجيب على سؤال فحصه بشكل خاطئ. + +تقرأ الخطاطيف الإعدادات في كل استدعاء أداة، لذا يتم تطبيقها من التالي. لا يوجد شيء لإعادة تشغيله، مع أو بدون الخادم. + +## تحقق مما يفعله + +```bash +failproofai jev status +failproofai jev status --json +``` + +يعرض `status` المزود ونقطة النهاية والنموذج والوضع وملف الإعدادات وأذونات، وليس المفتاح أبداً. تحته يلخص النشاط الأخير: كم استدعاء Jev تم تقييمه، كم مرة عاد إلى القاعدة العادية ولماذا، كمون الشبكة، وأي سياسات قابلة للمراجعة تم إلغاؤها. + +## تحقق من استدعاء حقيقي + +ابدأ جلسة جديدة في الوكيل المتصل بالخطاطيف. اطلب منه استخدام أداة قراءة الملفات على `README.md` والإبلاغ عن العنوان. تأكد من أن الجلسة تحتوي على استدعاء الأداة، ثم قم بتشغيل `failproofai jev status` مرة أخرى: يجب أن يزداد عدد الاستدعاءات التي تم تقييمها مؤخراً. افتح **Policies → Activity** في [لوحة التحكم المحلية](/ar/reference/local-dashboard#review-policy-activity) لفحص حكم Jev للاستدعاء والوضع. في وضع المراقبة، نتيجة السياسة لا تزال تحدد الاستدعاء. يظهر التصريح فقط إذا كانت سياسة قابلة للمراجعة متطابقة وألغى Jev كل فحص مسمى؛ قد لا تملك قراءة عادية سياسة لإلغاءها. + +## وضع المراقبة + +`enforce` هو الافتراضي. لمشاهدة Jev بدون السماح به بتغيير أي قرار، انتقل إلى `observe`: لا يزال Jev يُسأل وتسجل أحكامه، لكن نتيجة القاعدة العادية هي ما يتم إنفاذه. + +```bash +failproofai jev setup --mode observe +failproofai jev setup --mode enforce +failproofai jev setup --mode off +``` + +`off` يحتفظ بالإعدادات — نقطة النهاية والمفتاح — ويتوقف عن السؤال عن Jev: تشغيل الخطاطيف السياسات العادية بالضبط كما بدون إعدادات، و`failproofai jev status` يقول "off (switched off)". عُد بـ `--mode observe` أو `--mode enforce`. + +تشغيل `setup` مرة أخرى لنفس المزود يحتفظ بالمفتاح المخزن، لذا فإن تبديل الوضع علم واحد. تبديل المزود يبدأ من جديد ويسأل عن مفتاح هذا المزود. كذلك يفعل `--base-url` الذي ينقل الطلبات إلى مضيف مختلف: يتم إرسال مفتاح مخزن فقط إلى المضيف الذي تم إعطاؤه له، أو إلى API المزود الخاص به. + +## ملف الإعدادات + +كل شيء يعيش في ملف واحد، `~/.failproofai/jev.json`، المكتوب بواسطة `setup`: + +```json +{ + "provider": "cloudflare", + "apiKey": "", + "accountId": "<32-hex-account-id>", + "mode": "enforce", + "timeoutMs": 3000 +} +``` + +| الحقل | المعنى | +| --- | --- | +| `provider` | `typesafe`، `openrouter`، `vercel`، `cloudflare` أو `custom` — أو `failproofai`، الذي يأتي مفتاحه من اتصال FailproofAI Cloud بدلاً من هذا الملف (انظر [Jev عبر FailproofAI Cloud](/ar/reference/jev-cloud)). | +| `apiKey` | يُرسل كـ `Authorization: Bearer `. | +| `baseUrl` | مطلوب لـ `custom`؛ يستبدل قاعدة API المزود بخلاف ذلك. يجب أن يكون `https`. `http` عادي إلى `localhost` مقبول فقط مع `mode: observe`: لا شيء يمكّن منفذاً محلياً، لذا بينما الوكيل الخاص بك معطل يمكن لأي عملية على الجهاز، بما فيها الوكيل الذي يتم الحكم عليه، الإجابة في مكانه. | +| `accountId` | Cloudflare فقط: 32 حرف سادس عشري صغير. | +| `model` | يستبدل معرّف نموذج المزود الافتراضي. يجب أن يسمّي معرّف مُصدّر إصدار Jev 1.13. يتم رفض القيمة المشكلة مثل مفتاح API (ولا تُعاد مرة أخرى)، لذا فإن مفتاحاً معجوناً إلى `--model` لا يتم تخزينه أو إرساله أبداً كنموذج. | +| `timeoutMs` | كم من الوقت ينتظر استدعاء أداة Jev قبل استخدام نتيجة القاعدة العادية. 100–10000، افتراضي 3000. | +| `mode` | `enforce` (افتراضي)، `observe`، أو `off` (احتفظ بالإعدادات، لا تشغل Jev). | + +ثلاث قواعد تحميها: + +- **المالك فقط.** يتم كتابتها بأذونات `0600`. نسخة تقرأ أو تكتب أي مستخدم أو مجموعة أخرى يتم **رفضها**، والخطاطيف ترجع إلى القاعدة العادية حتى تشغل `chmod 600 ~/.failproofai/jev.json` أو `setup` مرة أخرى. يتم فحص الدليل أيضاً: `~/.failproofai` يجب ألا يكون **قابلاً للكتابة** من قبل أي شخص آخر، لأنه من يمكنه الكتابة هناك يمكنه استبدال الملف مهما كانت أذوناته. `setup` يأخذ تلك البتات إذا وجدها. `failproofai jev status` يقول عندما تم رفض الإعدادات ويعرض نقطة النهاية التي يسمّيها الملف: قد يكون شخص آخر قد غيّره، لذا تحقق من أنه ملكك قبل أن تفعل `chmod`. إعادة تشغيل `setup` على مثل هذا الملف يحمل مفتاحه المخزن فقط إلى API المزود الخاص به؛ أي نقطة نهاية أخرى يسمّيها تحتاج المفتاح مرة أخرى (`--key-stdin`)، أو `--base-url default` لإرسال الطلبات مرة أخرى إلى المزود. +- **عام فقط.** لا يمكن لمستودع تشغيل Jev، الإشارة إليه في نقطة نهاية أخرى أو اختيار نموذجه: `.failproofai/jev.json` داخل مشروع يتم تجاهله، والمزود و URL والنموذج ومعرّف الحساب يُقرأ فقط من هذا الملف — أبداً من البيئة، التي يمكن لإعدادات وكيل المستودع تعيينها. (`FAILPROOFAI_HOME` ليست طريقة حول ذلك: يحرّك دليل failproofai بالكامل، سياساتك المضمنة، بدلاً من إعادة توجيه Jev بمفرده.) +- **قد يأتي المفتاح وحده من البيئة.** إذا لم يكن الملف يحتوي على `apiKey`، يوفّر `FAILPROOFAI_JEV_API_KEY` له لتلك الجلسة (`setup --key-from-env` يكتب ملفاً كهذا). لا يستبدل أبداً مفتاحاً يملكه الملف، ولا يمكنه تشغيل Jev بدون الملف. حيث لا تُعيّن المتغيّر، Jev ببساطة معطّل لتلك القذيفة: `failproofai jev status` يقول ذلك، يخرج 0 ويترك الإعدادات وحدها (`status --json` يُبلّغ `"status": "key-missing"` مع `"reason": "no-env-key"`). خادم `failproofaid` لا يرى بيئة القذيفة الخاصة بك، لذا على جهاز تم إعداده باستخدام `failproofai config`، احتفظ بالمفتاح في الملف. + +## أي Jev يجيب + +تم معايرة عتبات قرار Failproof AI على Jev 1.13، لذا يتم استخدام إجابة فقط عندما تأتي من تلك الأسرة: `jev-1.13.x`، أو `typesafe/jev-1.13-` من OpenRouter. حيث يسمّي المزود Jev بالاسم المستعار فقط ولا يُبلّغ عن إصدار (Vercel، و Cloudflare عندما لا يقول)، يتم استخدام الإجابة وتسجيلها كغير تم التحقق منها. نقطة `custom` يجب أن تُبلّغ عن النموذج الذي أجاب؛ الاستثناء الوحيد هو اسم `--model` غير مُصدّر قمت بإعداده، الذي، معاد صياغته، يتم تسجيله كغير تم التحقق منه بنفس الطريقة. إجابة تُبلّغ عن أي إصدار آخر، أو إجابة `custom` لا تُبلّغ أياً، لا يتم استخدامها: هذا الاستدعاء يعود إلى القاعدة العادية مع السبب `model-mismatch`. + +## عندما لا يستطيع Jev الإجابة + +كل من هذه يعود إلى نتيجة القاعدة العادية لهذا الاستدعاء ويتم تسجيله مع سببه، والذي `failproofai jev status` يجمع: + +| السبب | السبب الجذري | +| --- | --- | +| `timeout` | لا إجابة ضمن `timeoutMs`. | +| `http-429` | المزود وضع حد معدل للمفتاح. | +| `rate-limited` | مُحدِّد معدل Failproof AI الخاص به عقد الاستدعاء قبل إرساله: 5 طلبات في الثانية، في انفجارات تصل إلى 5، وليس لحظة بعد أن يجيب المزود `429`. وليس المزود. | +| `http-500`، `http-502`، `http-503`، ... | خطأ خادم عند المزود. يتم تسجيل الحالة الدقيقة. | +| `out-of-credits` | HTTP 402: حساب المزود ليس لديه رصيد متبقٍ. | +| `provider-refused` | HTTP 402 من Cloudflare يقول "Model execution failed (Payment error)": رفض المزود تشغيل النموذج على هذا الطلب. عادة ليس فواتير، لذا ملء الرصيد لن يحركها. | +| `http-401`، `http-403` | تم رفض المفتاح. | +| `http-404` | لا شيء يُقدّم عند `/systemone`، لذا URL الأساسي خاطئ — `/systemone` يُلحق به، وكل مزود يخدمه على جذر إصداره. `failproofai jev models` يعرض ما تخدم نقطة النهاية. | +| `network` | لا يمكن الوصول إلى نقطة النهاية. | +| `http-301`، `http-302`، `http-307`، `http-308` | أجابت نقطة النهاية بإعادة توجيه. لا يتم اتباع عمليات إعادة التوجيه أبداً، لذا الإجابة تأتي فقط من URL في الإعدادات الخاصة بك؛ ضع `--base-url` على URL النهائي. | +| `malformed` | أجابت نقطة النهاية، لكن ليس بإجابة Jev — جسم ليس JSON، أو واحد بدون إجابات فيه. | +| `cloudflare-error`، `cloudflare-incomplete` | أبلّغت مظروف Cloudflare عن فشل، أو مهمة لم تنتهِ. | +| `model-mismatch` | أجاب إصدار Jev بخلاف 1.13، أو نقطة `custom` لم تقل أي نموذج أجاب. | +| `request-cut` | **ليس انقطاعاً.** أجاب Jev؛ تم عرض جزء من الاستدعاء فقط، لذا إجابته لم تلغِ شيئاً. انظر [عندما أجاب Jev، لكن ليس على الاستدعاء بالكامل](#when-jev-answered-but-not-on-the-whole-call). | + +`failproofai jev status` يمكنه عرض بعض الأسباب الأندر أيضاً، مثل `upstream-error` (كانت الإجابة تحمل خطأ المزود الخاص به) أو `config`، ويجمع أي سبب لا يمكنه تسميته كـ `other`. + +`request-cut` في هذا الجدول لأن `failproofai jev status` يجمعه مع الباقي، ولأنه أيضاً يترك كل رفض قائماً. هو السبب الوحيد هنا الذي لا يقول شيئاً عن مزودك: وصل الطلب وأجاب Jev. بخلاف كل صف فوقه، تلك الإجابة لا تزال تحسب — رفض أو تحذير Jev الخاص به ينطبق على نتيجة القاعدة العادية بدلاً من أن يتم تجاهله. لذا تشغيل منهم يعني استدعاءات تصل إلى المقيّم كبيرة جداً لإرسالها كاملة، وليس أن نقطة النهاية الخاصة بك سيئة، وملء الرصيد أو تغيير URL لن يحركها. + +## عندما أجاب Jev، لكن ليس على الاستدعاء بالكامل + +شيئان آخران يمكنهما أن يحدثا، ولا أحدهما يقول أن Jev فشل في الإجابة. كلاهما يتعلق بكم من الاستدعاء، أو من المحادثة، ناسب في طلب واحد. + +**جزء من الاستدعاء نفسه لم يناسب.** يُرسل استدعاء أداة داخل ميزانية ثابتة، واستدعاء كبير جداً — `Write` كبير جداً، جسم MCP ضخم، أمر مبطّن إلى الحد الأقصى — يُرسل بما ناسب. لا يزال Jev يجيب، وإجابته لا تزال تحسب: رفضه أو تحذيره الخاص به ينطبق كالمعتاد. ما لا يمكنه فعله هو **إلغاء** أي شيء، لأن حكماً معطى على جزء من استدعاء ليس حكماً على الاستدعاء. لذا يبقى كل رفض سياسة قائماً، ويتم تسجيل الاستدعاء كرجوع مع السبب `request-cut`، والذي `failproofai jev status` يجمعه جنباً إلى جنب مع الأسباب أعلاه. القاعدة التي يعطيكها: جعل الاستدعاء أكبر يمكنه أن يكلفه التصريحات، وليس أبداً شراء واحد. + +**رسالة لم تناسب.** موجه طويل لصقته، آخر رسالة الوكيل، أو موجه كان لقاء هذا المقيّم الخاص به قد حده بالفعل. **لا شيء يتغير**: يتم الحكم على الاستدعاء وإلغاء تصريحه وتسجيله بالضبط كأي آخر، وهو غير مُحسب كرجوع. لا يحدد طول ما تكتبه أبداً حكماً، ولا يمكن للقطع أن يصنع موافقة: حيث وصل موجه بالفعل مقيّد، لا يمكن استخلاص "لم تطلب هذا" على الإطلاق، بدلاً من أن يصبح واحداً. + +الخط بين الاثنين هو من كتب النص. الاستدعاء هو الوكيل، وقاعدة أن تدع طوله يطرح شدة ستكون قاعدة يمكن للوكيل استخدامها؛ موجهك هو لك، ومعاملة طوله كإشارة فقط تعاقب بدء موجه أو تتبع كومة. + +## ما يترك الجهاز + +لكل استدعاء أداة يقيّمها Jev، يذهب طلب واحد إلى مزودك، حاملاً: + +- استدعاء الأداة نفسه، مع أسرار مثل مفاتيح API وعلامات حاملة ومهام `KEY=` محررة؛ +- الأجهزة المحمولة الحديثة التي كتبتها، مع نص أضاف وكيل حراستك إلى آخره محذوف؛ +- آخر رسالة الوكيل قبل موجهك الأخير، مُصنّف كمكتوب وكيل؛ +- حقائق محسوبة محلياً، مثل ما إذا كان المسار داخل المشروع — الواحد كانت الجلسة فيه عند أول استدعاء مفحوص، [مثبّت للجلسة](/ar/reference/jev-intent#the-project-root) — والفرع المحلي الحالي. + +يذهب فقط إلى نقطة النهاية في الإعدادات الخاصة بك، تحت مفتاحك. + +## أطفئه + +```bash +failproofai jev remove +``` + +هذا يحذف `~/.failproofai/jev.json`. من استدعاء الأداة التالي، تشغيل الخطاطيف السياسات العادية بالضبط كما قبل. المخازن لكل جلسة تحت `~/.failproofai/state/semantic/` (الأجهزة المحمولة المسجلة في `sessions/`، جذور المشروع في `roots/`) تُترك في مكانها وتتقادم. لتوقيف السؤال عن Jev لكن الاحتفاظ بالإعدادات، استخدم `failproofai jev setup --mode off` بدلاً من ذلك. + +## مرجع الأمر + +| الأمر | النتيجة | +| --- | --- | +| `failproofai jev --url --key-stdin` | إعدادات به في أمر واحد؛ يأتي المزود من مضيف URL | +| `failproofai jev --url --token ` | نفس، مع المفتاح على سطر الأوامر — السجل قائمتك العملية ترى | +| `failproofai jev setup --provider --key-stdin` | اكتب الإعدادات من مفتاح أنبوب على stdin | +| `failproofai jev setup --provider ` | نفس، يسأل عن المفتاح في موجه مقنع | +| `failproofai jev setup --key-from-env` | لا تخزّن مفتاحاً؛ اقرأ `FAILPROOFAI_JEV_API_KEY` لكل جلسة | +| `failproofai jev setup --mode observe` | بدّل وضعاً (`enforce`، `observe` أو `off`)، مع الاحتفاظ بالمفتاح المخزن | +| `failproofai jev setup --model ` / `--base-url ` | تجاوز النموذج أو قاعدة API؛ `default` يمسح التجاوز | +| `failproofai jev setup --timeout-ms ` | غيّر الميزانية لكل استدعاء | +| `failproofai jev status [--json]` | الإعدادات والأذونات والنشاط الأخير؛ ليس المفتاح أبداً | +| `failproofai jev test [--json]` | طلب حي واحد: الكمون والإصدار الذي أجاب | +| `failproofai jev models [--provider ] [--url ] [--json]` | معرّفات النموذج التي يُبلّغ عنها `/models` نقطة النهاية، تحديد المُعدّ | +| `failproofai jev remove` | احذف الإعدادات؛ Jev معطّل | \ No newline at end of file diff --git a/docs/ar/reference/jev.mdx b/docs/ar/reference/jev.mdx new file mode 100644 index 000000000..8496bf9f0 --- /dev/null +++ b/docs/ar/reference/jev.mdx @@ -0,0 +1,22 @@ +--- +title: "مرجع تكامل Jev" +description: "الإعدادات والموفرون والمفاتيح وبيانات الطلب وسلوك الفشل لـ Jev." +icon: "braces" +--- + +لدى Jev استخدامان في Failproof AI: + +| الاستخدام | متى يتم تشغيله | ما يعيده | ابدأ من هنا | +| --- | --- | --- | --- | +| تقييم الجلسة | بعد انتهاء الجلسة | درجة لسؤال ذي إجابة ثابتة | [تقييمات Jev](/ar/evaluations/jev) | +| مراجعة سياسة استدعاء الأداة | قبل تشغيل استدعاء أداة محمي | حكم إلى جانب السياسات المثبتة | [سياسات Jev](/ar/policies/jev) | + +## صفحات المرجع + +| الموضوع | التفاصيل | +| --- | --- | +| [أسئلة التقييم](/ar/reference/jev-evaluations) | معايير منطقية وذات درجات مرتبة، والنتائج والحدود والملء بأثر رجعي. | +| [مقارنة الموفرين وإعداد المفتاح الخاص](/ar/reference/jev-providers) | TypeSafe وOpenRouter وVercel وCloudflare والنقاط النهائية المخصصة؛ استدلال URL ومعرفات النموذج و`jev.json` والأوضاع وأكواد الرجوع. | +| [مسار FailproofAI Cloud](/ar/reference/jev-cloud) | أذونات المفتاح الآلي وإعداد المراقبة التلقائي وحدود الاستخدام وحالة الاتصال ومعالجة البيانات. | + +يتم عرض أوامر CLI المحلية في [مرجع Failproof AI CLI](/ar/reference/failproof-cli). يصف [مرجع لوحة التحكم المحلية](/ar/reference/local-dashboard#set-up-jev) إعدادات Jev وعرض الأنشطة به. \ No newline at end of file diff --git a/docs/ar/sessions/sentiment.mdx b/docs/ar/sessions/sentiment.mdx new file mode 100644 index 000000000..a15074e02 --- /dev/null +++ b/docs/ar/sessions/sentiment.mdx @@ -0,0 +1,43 @@ +--- +title: "تحليل المشاعر" +description: "ابحث عن الرسائل المحبطة والمربكة والتصحيحية باستخدام درجات المشاعر من Jev." +icon: "smile" +--- + +يقيّم Jev كل رسالة يرسلها شخص ما إلى وكلائك من 0 إلى 100 لأربعة مشاعر — **غاضب**، **محبط**، **سعيد** و**مربك** — وثلاث إشارات حول أداء الوكيل: + +- **التصحيح**: يقول الشخص أن الوكيل أخطأ في شيء ما. +- **تم الحل**: يؤكد الشخص أن الوكيل حل مشكلته. +- **الشك**: يطرح الشخص تساؤلات حول ما إذا كانت إجابة الوكيل صحيحة، أو ما إذا كان قد قام بالعمل فعلاً. + +استخدم تحليل المشاعر للعثور على محادثات حيث يفقد الأشخاص صبرهم، والوكلاء الذين يستمر تصحيحهم، والردود التي تحقق نتائج جيدة. هذا تقييم مدمج من Jev؛ لا تحتاج إلى إنشاء تقييم. لسؤالك ذي الإجابة الثابتة، [أنشئ تقييم Jev](/ar/evaluations/jev). + + + المشاعر مُطفأة حتى يقوم المسؤول بتشغيلها للمؤسسة. يقدم Jev طلب تقييم واحد لكل رسالة ويتلقى تلك الرسالة مع رد الوكيل قبلها. يستخدم التقييم ميزانية نموذج مؤسستك. + + +## تشغيله + +1. اذهب إلى **الإدارة → الإعدادات**. +2. ضمن **مشاعر مدخلات المستخدم**، قم بتشغيله **وحفظ**. + +يتم تقييم الرسائل من آخر يوم أولاً. بعد ذلك، يتم تقييم الرسائل الجديدة في غضون دقيقة أو دقيقتين من وصولها. + +## ابحث عن محادثة للمراجعة + +افتح **المراقبة → المشاعر**. قم بالتصفية حسب الوقت أو البيئة أو الوكيل أو معرّف الجلسة. يحسب الرأس الرسائل والجلسات، ويظهر عدد الرسائل **المُشار إليها بعلم**، ويسمي الإشارة الأعلى. يتم وضع علم على الرسالة عندما تصل درجة الغضب أو الإحباط أو التصحيح أو الارتباك أو الشك إلى 35 من أصل 100. + +![لوحة معلومات المشاعر تعرض عدد الرسائل والجلسات والرسائل المُشار إليها بعلم ودرجات Jev بمرور الوقت.](/images/dashboard/sentiment-overview.png) + +استخدم **الدرجة بمرور الوقت** للمقارنة بين الإشارات. اختر الدرجات المراد عرضها، ثم حدد نقطة لرؤية رسائل فترة الوقت تلك. يوضح جدول **حسب الوكيل** حيث تتركز الإشارة. في **الرسائل**، قم بالترتيب حسب أقوى درجة سلبية أو حدد درجة واحدة. افتح رسالة في جلستها لقراءة المحادثة المحيطة قبل تحديد ما فشل. + +![قائمة رسائل المشاعر مرتبة حسب أقوى درجة سلبية، مع رابط لكل جلسة مصدر.](/images/dashboard/sentiment-messages.png) + +## الرسائل التي يتم تقييمها + +فقط الرسائل التي كتبها شخص: + +- الرسائل التي تسجلها وكلاؤك المخصصون كمدخلات من المستخدم باستخدام SDK. +- النصوص المكتوبة في Claude Code و Codex و OpenCode و pi و Hermes و OpenClaw، عندما يتم إرسال نسخ الجلسة (الإعداد الافتراضي). الوظائف المجدولة والتعليمات المحقونة والتحويلات بين الوكلاء الفرعيين والنصوص الأخرى التي كتبها وقت تشغيل الوكيل نفسه لا يتم تقييمها. وكذلك الأشياء غير التفاعلية مثل `claude -p` و `codex exec` و `hermes -z`: كتبت برنامج ما تلك النصوص، وليس شخصاً. + +يحكم التقييم على كلمات الشخص نفسه. التعليمات القصيرة والحادة مثل إصلاح خطأ ما لا تُحسب كغضب، وطرح سؤال لا يُحسب كارتباك. الطلب الجديد ليس تصحيحاً، والشكر بمفرده لا يُحسب كحل. \ No newline at end of file diff --git a/docs/ar/start/use-jev.mdx b/docs/ar/start/use-jev.mdx new file mode 100644 index 000000000..ac20c6083 --- /dev/null +++ b/docs/ar/start/use-jev.mdx @@ -0,0 +1,63 @@ +--- +title: "استخدام Jev" +description: "قم بإعداد تقييمات Jev للجلسات المكتملة أو سياسات Jev لمراجعة استدعاءات الأدوات المباشرة." +icon: "sparkles" +--- + +يساعد Jev في نقطتين أثناء تشغيل الوكيل: تقييم جلسة مكتملة مقابل إجابات معروفة، أو مراجعة استدعاء أداة في سياق ما طلبته من الوكيل. + + + + استخدم تقييم Jev عندما يمكن تقييم جلسة مكتملة مقابل سؤال بعدة إجابات معروفة، مثل "هل طلب العميل استرجاع أمواله؟ أجب بنعم أو لا." يساعدك في العثور على أنماط عبر الجلسات. + + ## إنشاء تقييم + + في لوحة تحكم Cloud، افتح **Analyze → eval authoring → new eval**. أدخل سؤالاً واحداً ذا إجابة ثابتة، اختر **draft**، وتحقق من أنه اختار درجة مصنف. [اختبره](/ar/evaluations/test) على جلسات حقيقية، ثم انشره. + + ![نموذج تأليف التقييم المشترك حيث تصف سؤالاً وتراجع المسودة وتنشرها. توضح هذه اللقطة مسودة رمزية؛ استخدم سؤالاً ذا إجابة ثابتة لـ Jev.](/images/dashboard/eval-authoring-draft.png) + + ## قراءة الدرجات + + بعد اكتمال جلسة جديدة، افتح **Observe → Evaluations** أو استخدم واجهة سطر الأوامر في Cloud: + + ```bash + fp evals --since 7d + fp evals --aggregate --since 7d + ``` + + تقرأ واجهة سطر الأوامر الدرجات؛ إنشاء تقييم Jev يستخدم لوحة التحكم حالياً. راجع [تقييمات Jev](/ar/evaluations/jev) لأنواع الأسئلة والأمثلة. + + + استخدم مراجعة سياسة Jev عندما تحتاج سياسة مطابقة السلاسل النصية إلى سياق طلبك لتقرير ما إذا كان استدعاء الأداة آمناً. ابدأ في وضع **observe** حتى تتمكن من فحص إجابات Jev بينما تقرر سياساتك المثبتة كل استدعاء. + + تأتي فحوصات Jev من حزمة؛ Failproof AI لا تشحن أي منها. حتى تثبتها، لا يسأل Jev عن أي شيء، حتى عند تكوينها: + + ```bash + failproofai policies add FailproofAI/jev-policies + ``` + + ## إعداد Cloud Jev + + في لوحة تحكم Cloud، افتح **Administration → Keys** وأنشئ مفتاحاً باستخدام إعداد **machine**. استخدمه مع `failproofai config` كما هو موضح في [البداية السريعة](/ar/start/quickstart). على جهاز بدون تكوين Jev موجود، يفعل هذا Cloud Jev في وضع observe. تحقق من الاتصال باستخدام: + + ```bash + failproofai jev status + failproofai jev test + ``` + + ## استخدام نقطة نهاية خاصة بك + + في لوحة التحكم المحلية، افتح **Settings → Jev**. اختر المزود، والصق رمزه، اختر **observe**، وقم بتشغيل Jev. + + ![لوحة إعدادات Jev المحلية مع مزود وحقل رمز ووضع observe مختار.](/images/dashboard/jev-settings.png) + + أو قم بتكوين واختبار نقطة النهاية الخاصة بك من المحطة الطرفية: + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key + failproofai jev test + ``` + + اطلب من وكيل مُرتبط استخدام أداة قراءة الملفات على `README.md`. تأكد من أن استدعاء الأداة هذا يظهر في الجلسة، ثم افحصه ضمن **Policies → Activity** في لوحة التحكم المحلية. بمجرد أن تبدو نتائج observe صحيحة، يشرح [سياسات Jev](/ar/policies/jev) متى يتم الفرض. للحصول على تفاصيل المزود والتكوين، راجع [مرجع التكامل](/ar/reference/jev). + + \ No newline at end of file diff --git a/docs/de/evaluations/jev.mdx b/docs/de/evaluations/jev.mdx new file mode 100644 index 000000000..b41a53e25 --- /dev/null +++ b/docs/de/evaluations/jev.mdx @@ -0,0 +1,28 @@ +--- +title: "Jev-Evaluierungen" +description: "Verwende Jev, um eine abgeschlossene Sitzung anhand einer Frage mit bekannten Antworten zu bewerten." +icon: "list-checks" +--- + +Eine Jev-Evaluierung liest eine **abgeschlossene Sitzung** und vergibt einen Score von 0 bis 1. Nutze sie, wenn die Antwort im Voraus bekannt ist – etwa „Hat der Kunde Dringlichkeit signalisiert?" oder „Wie frustriert war der Kunde?" Sie hilft dir, Muster über mehrere Durchläufe hinweg zu erkennen; sie unterbricht keinen Tool-Aufruf. Für Entscheidungen, die **vor** der Ausführung eines Tools getroffen werden, verwende [Jev-Richtlinien](/de/policies/jev). + +## Evaluierung im Dashboard erstellen + +1. Öffne **Analyze → Eval Authoring** und wähle **New Eval**. +2. Beschreibe eine Frage mit ihren möglichen Antworten. Zum Beispiel: „Hat der Agent eine Rückerstattung versprochen, bevor er die Rückerstattungsrichtlinie geprüft hat? Antworte mit Ja oder Nein." Wähle **Draft** und überprüfe, ob das Ergebnis ein Klassifikations-Score ist. +3. [Teste die Evaluierung](/de/evaluations/test) anhand aktueller Sitzungen und [deploye sie anschließend](/de/evaluations/deploy). Neu abgeschlossene Sitzungen werden dann bewertet; nutze [Backfill](/de/evaluations/deploy#score-sessions-you-already-have), wenn du auch historische Daten benötigst. + +![Das gemeinsame Eval-Authoring-Formular, in dem du eine Frage mit festen Antworten beschreibst, den Entwurf prüfst und nach dem Testen deployst. Das gezeigte Beispiel ist eine Code-Evaluierung; eine Jev-Frage verwendet denselben Authoring-Ablauf.](/images/dashboard/eval-authoring-draft.png) + +Der Assistent kann zwischen Code, Jev-Klassifikation und einem [Judge](/de/evaluations/judge) wählen. Überprüfe die Wahl des Assistenten, bevor du deployest. Jev liefert einen Score ohne textliche Begründung; wähle einen Judge, wenn du eine Erklärung benötigst. Siehe die [Jev-Evaluierungsreferenz](/de/reference/jev-evaluations) für Fragetypen und Score-Grenzen. + +## Scores auslesen + +Öffne **Observe → Evaluations**, um das Ergebnis nach Agent und Zeitraum darzustellen. Über ein Terminal kann die Cloud CLI dieselben Ergebnisse abrufen: + +```bash +fp evals --since 7d +fp evals --aggregate --since 7d +``` + +Die Cloud CLI liest Ergebnisse aus; Authoring und Deployment erfolgen im Dashboard. Siehe die [Cloud-CLI-Referenz](/de/reference/cloud-cli#evaluations) für Filteroptionen. \ No newline at end of file diff --git a/docs/de/evaluations/judge.mdx b/docs/de/evaluations/judge.mdx new file mode 100644 index 000000000..32b9d6b7b --- /dev/null +++ b/docs/de/evaluations/judge.mdx @@ -0,0 +1,91 @@ +--- +title: "LLM-Richter" +description: "Bewerte Sitzungen nach Kriterien, die Code nicht messen kann — Korrektheit, Ton, ob der Agent eine Richtlinie eingehalten hat — indem du beschreibst, wie gut aussieht, und ein Modell das Gespräch lesen lässt." +icon: "scale" +--- + +Eine gehostete Python-Auswertung kann zählen und vergleichen: wie viele Tool-Aufrufe, wie viele Fehler, wie lange eine Sitzung gedauert hat. Sie kann dir nicht sagen, ob eine Antwort *korrekt* war, ob eine Antwort unhöflich war oder ob der Agent eine Richtlinie geprüft hat, bevor er gehandelt hat. + +Ein **LLM-Richter** kann das. Du beschreibst in einfacher Sprache, wie gut aussieht, und ein Modell liest die Sitzung und gibt einen Wert zwischen 0 und 1 mit Begründung zurück. + + +Ein Richter kostet für jede ausgewertete Sitzung einen Modellaufruf, während eine Code-Auswertung nichts kostet. Verwende einen Richter nur für Fragen, bei denen das Gespräch *verstanden* werden muss — und gib ihm eine Bedingung, damit er nur auf die Sitzungen angewendet wird, um die es bei der Frage tatsächlich geht. + + +## Welche Variante brauche ich? + +| Frage | Verwende | +| --- | --- | +| Hat es dasselbe Tool zweimal aufgerufen? | Code | +| Wie viele Fehler gab es? | Code | +| War die Sitzung kürzer als 30 Sekunden? | Code | +| Hat der Kunde Dringlichkeit ausgedrückt? | [Klassifikator](/de/evaluations/jev) | +| Wie frustriert war der Kunde? | [Klassifikator](/de/evaluations/jev) | +| War die Antwort tatsächlich korrekt? | **Richter** | +| War die Antwort unhöflich oder abweisend? | **Richter** | +| Hat er die Rückgaberichtlinie geprüft, bevor er eine Rückerstattung versprochen hat? | **Richter** | + +Die Faustregel: **Zählbares → Code, Antworten, die du im Voraus aufzählen kannst → [Klassifikator](/de/evaluations/jev), braucht eine Erklärung → Richter.** Ein Richter ist derjenige, der in Prosa beschreibt, was er gesehen hat; greife darauf zurück, wenn die Zahl jemanden fragen lässt „warum?". + +Du musst nicht im Voraus entscheiden. Beschreibe, was du gemessen haben möchtest, und der Assistent wählt aus und erklärt dir, was er gewählt hat und warum. Du kannst es ändern. + +## Einen Richter erstellen + +1. Gehe zu **Analyze → eval authoring** und wähle **new eval**. +2. Beschreibe, was bewertet werden soll, und wähle **draft**. +3. Überprüfe die **Kriterien**, den **Schwellenwert** und die **Bedingung**, dann deploye. + +### Kriterien + +Ein oder zwei Sätze, als Anforderung formuliert, nicht als Frage: + +> Der Assistent darf keine Rückerstattung versprechen oder genehmigen, ohne zuvor die Rückgaberichtlinie geprüft zu haben. + +Sei konkret darüber, was zu einem *Misserfolg* führen würde. „War die Antwort gut?" liefert dir eine bedeutungslose Zahl; der obige Satz liefert dir eine, auf die du reagieren kannst. + +### Schwellenwert + +Der Wert, ab dem eine Sitzung als bestanden gilt. `0.7` ist ein sinnvoller Ausgangspunkt. Der vollständige Wert zwischen 0 und 1 wird immer gespeichert, sodass der Schwellenwert nur über Bestanden/Nicht bestanden entscheidet — du kannst die Verteilung einsehen und anpassen. + +### Bedingung + +Dieselbe Python-Bedingung wie bei jeder anderen Auswertung, und sie ist hier noch wichtiger. Ohne eine Bedingung läuft der Richter auf **jeder** Sitzung in deiner Organisation — pro Sitzung ein Modellaufruf: + +```python +session.count("tool_use") > 0 +``` + +```python +session.agent_id == "support-bot" and session.count("error") > 0 +``` + +Das Dashboard warnt dich, wenn du einen Richter ohne Bedingung deployst. Das ist manchmal richtig — ein Agent mit geringem Volumen, den du vollständig beurteilt haben möchtest — aber es sollte eine bewusste Entscheidung sein, kein Versehen. + +## Was der Richter sieht + +Das Gespräch, als Gesprächsrunden, bei langen Sitzungen mit den neuesten zuerst: + +- was der Benutzer gesagt hat +- was der Assistent geantwortet hat +- **jeden Tool-Aufruf des Agenten und was der Aufruf zurückgegeben hat, in Reihenfolge** + +Dieser letzte Punkt ist es, der die Frage „hat er X *vor* Y getan" fair macht. Ein fehlgeschlagener Tool-Aufruf wird als Fehler dargestellt, sodass auch „hat er sich nach einem Fehler angemessen erholt" funktioniert. + +Sehr lange Sitzungen werden gekürzt, um in den Kontext des Modells zu passen. Wenn das passiert, wird es in der Begründung explizit erwähnt — du wirst nie ein Urteil sehen, das auf einem Teil einer Sitzung basiert, aber als vollständiges dargestellt wird. + +## Ergebnisse lesen + +Ein Richter erzeugt wie jede andere bewertete Auswertung einen **Wert**, sodass er genauso in Diagrammen, Filtern und Benachrichtigungen verwendet werden kann. Neben der Zahl speichert er die **Begründung** des Richters — den Absatz, der erklärt, was er gesehen hat. Lies diesen zuerst, wenn dich ein Wert überrascht; es ist meist entweder eine wirklich interessante Sitzung oder ein Hinweis, dass die Kriterien geschärft werden müssen. + +Werte sind bei eindeutigen Fällen stabil, aber nicht bit-für-bit deterministisch. Behandle einen einzelnen Grenzwert-Score als Anlass, die Sitzung zu lesen, nicht als abschließendes Urteil. + +## Einschränkungen + +- **Tests sind noch nicht verfügbar.** Ein Probelauf hat keine Sitzungszuweisung dahinter, und diese Zuweisung ist das, was die Ausgabe deines Modellbudgets autorisiert — daher gibt es nichts, dem ein Testaufruf zugerechnet werden kann. Deploye gegen eine enge Bedingung und lies die ersten Ergebnisse. +- **Nachträgliche Auswertung ist nicht verfügbar.** Eine Code-Auswertung über Monate von Verlaufsdaten nachträglich durchzuführen ist kostenlos; dasselbe mit einem Richter würde dein gesamtes Budget in Minuten verbrauchen. +- **Das Bearbeiten der Kriterien veröffentlicht eine neue Version.** Alte und neue Werte sind nicht vergleichbar und werden daher getrennt statt in einer gemeinsamen Trendlinie gemischt. +- **Ein Richter erzeugt immer einen Wert**, niemals eine Metrik oder eine Assertion. + +## Wenn dein Budget aufgebraucht ist + +Richter verbrauchen das Modellbudget deiner Organisation. Wenn es erschöpft ist, werden Richter-Auswertungen mit einem klaren Grund gestoppt, anstatt stillschweigend zu scheitern, und **Code-Auswertungen laufen weiterhin normal**. Erhöhe das Budget und sie werden bei der nächsten Sitzung fortgesetzt. \ No newline at end of file diff --git a/docs/de/policies/authority.mdx b/docs/de/policies/authority.mdx new file mode 100644 index 000000000..0c174d331 --- /dev/null +++ b/docs/de/policies/authority.mdx @@ -0,0 +1,144 @@ +--- +title: "Policy-Autorität" +description: "Welche Policy-Urteile der semantische Jev-Evaluator aufheben darf und welche endgültig sind." +icon: "scale" +--- + +Wenn Sie die [Jev Policy Review](/de/policies/jev) über Failproof AI Cloud oder Ihren eigenen Schlüssel konfigurieren, wird jeder überwachte Tool-Aufruf von den ausgeführten Policies und von Jev beurteilt. Jev fragt dabei, was der Aufruf tatsächlich tut und ob die Person, die die Aufgabe eingegeben hat, darum gebeten hat. Die **Autorität** jeder Policy entscheidet, was passiert, wenn beide unterschiedlicher Meinung sind. + +Ohne konfiguriertes Jev hat die Autorität keine Auswirkung. Jede Policy wird genau so durchgesetzt wie bisher. + +## Hard und Reviewable + +- **Hard** ist der Standard. Das Urteil einer Hard-Policy (deny oder Anweisung) ist endgültig: Jev kann es nicht aufheben, und ein Hard-Deny stoppt den Aufruf, ohne auf Jev zu warten. +- **Reviewable** bedeutet, dass Jev das Urteil der Policy aufheben kann, jedoch nur durch die semantischen Prüfungen, die die Policy in `reviewedBy` benennt. Das Urteil wird nur aufgehoben, wenn **jede** benannte Prüfung zu diesem Aufruf befragt wurde und jede einzelne entweder nichts gefunden oder festgestellt hat, dass der Nutzer genau darum gebeten hat. Eine Prüfung, die **ausgelöst** hat – also das Anliegen gefunden hat – ohne dass der Nutzer darum gebeten hat, behält die Sperre bei, auch wenn ihr eigenes Urteil nur eine Warnung ist. Eine Prüfung, die Jev nicht gestellt wurde, weil sie auf dieses Tool nicht zutrifft, hebt nichts auf, unabhängig von dem, was die anderen gesagt haben. Eine Abmilderung gilt als Zustimmung: Wenn der Aufruf ein Schritt der vom Nutzer gestellten Aufgabe ist und nicht darüber hinausgeht, wandelt Jev ein Deny in eine Warnung um, und diese Warnung hebt die Sperre der Policy auf und wird dem Agenten mitgeteilt. + +Eine Policy ist nur dann reviewable, wenn alle folgenden Bedingungen zutreffen: + +1. Sie deklariert `authority: "reviewable"`. +2. `reviewedBy` ist eine nicht leere Liste, und jeder Eintrag ist eine Jev-Prüfung, die ein installiertes Pack deklariert. Failproof AI liefert keine Jev-Prüfungen aus: Die [sechzehn unten stehenden](#semantic-policy-names) stammen aus `failproofai policies add FailproofAI/jev-policies`. Wenn kein Pack Prüfungen deklariert, ist jede Policy hard. +3. Sie ist nicht `alwaysOn`. Die Absicherung, die einen Agenten daran hindert, Failproof AI zu deaktivieren, ist immer hard. + +Alles andere ist hard: ein fehlendes Feld, ein falsch geschriebener Wert, ein leeres oder fehlerhaftes `reviewedBy`, oder ein Name, der keine Prüfung ist, die diese Maschine stellen kann. Ein unbekannter Name macht die gesamte Deklaration hard, anstatt übersprungen zu werden, weil `reviewedBy` bedeutet: „All diese müssen befragt werden, und keine darf ablehnen" — ein Name zu überspringen würde Jev erlauben, die Policy anhand von weniger Prüfungen aufzuheben, als Sie angefordert haben. + +Sobald Jev konfiguriert ist, protokolliert Failproof AI eine Warnung, wenn eine `reviewable`-Deklaration abgelehnt wird – einmal pro Prozess. Ohne Jev wird nichts gemeldet, da die Autorität dann nichts entscheidet. `failproofai publish` verweigert den Build eines Packs, das eine solche Deklaration enthält, sodass ein Pack-Autor dies entdeckt, bevor jemand es installiert. Es prüft `reviewedBy` gegen die Prüfungen, die das Pack deklariert (falls es welche deklariert), andernfalls gegen die sechzehn `FailproofAI/jev-policies`-Namen. + +## Wo Autorität deklariert wird + +Jede Art, wie eine Policy eine Maschine erreicht, hat einen Ort, der ihre Autorität festlegt: + +| Quelle | Deklariert in | Standard | +| --- | --- | --- | +| Eingebaute Policies | Die Tabelle unten | Hard, es sei denn, als reviewable aufgeführt | +| Eigene Policy-Dateien | `authority` und `reviewedBy` in `customPolicies.add` | Hard | +| Policy-Packs | Der Eintrag jeder Policy im Pack-Manifest (`failproofai-pack.json`) | Hard | +| Cloud-verwaltete Policies | Die Zuweisung der Policy im aktiven Deployment | Hard. Deployments setzen dies noch nicht, daher ist heute jede cloud-verwaltete Policy hard. | + +Bei einem Pack oder einer cloud-verwalteten Policy werden Felder, die im Policy-Code gesetzt wurden, ignoriert; das Manifest oder die Zuweisung entscheidet. Ein Pack kann nur seine eigenen Policies beschreiben: Ihre Policy-Namen dürfen kein `/` enthalten und werden unter dem eigenen Präfix des Packs registriert, sodass kein Manifest eine eingebaute Policy oder die Policy eines anderen Packs als reviewable markieren kann. Eine Policy, die der Code eines Packs registriert, ohne sie im Manifest zu deklarieren, ist hard. + +Zwei Packs oder zwei cloud-verwaltete Policies, deren Code byte-identisch ist, teilen ein Artefakt und werden als eine Policy geladen. Diese Policy ist nur dann reviewable, wenn jede einzelne von ihnen sie als reviewable deklariert, und Jev muss dann jede Prüfung aufheben, die eine von ihnen benennt. Wenn eine von ihnen sie als hard deklariert oder gar nicht deklariert, bleibt sie hard. Die Reihenfolge, in der die Packs oder Policies aufgeführt sind, spielt nie eine Rolle. + +Die meisten Maschinen erhalten die eingebauten Policies aus dem `FailproofAI/policies`-Pack und lesen deren Autorität aus dem Manifest dieses Packs. Die unten stehenden reviewable-Einträge treten in Kraft, sobald ein Release des Packs, das sie enthält, installiert ist; ein älteres Release enthält keine, daher bleibt jede darin enthaltene Policy hard. + +## Autorität in einer eigenen Policy deklarieren + +```js +import { customPolicies, deny, allow } from "failproofai"; + +customPolicies.add({ + name: "block-prod-config-reads", + description: "Keep production credentials out of the agent's context", + match: { events: ["PreToolUse"] }, + authority: "reviewable", + reviewedBy: ["secret-exposure"], + fn: async (ctx) => + String(ctx.toolInput?.file_path ?? "").includes("/config/prod/") + ? deny("Production config is off limits") + : allow(), +}); +``` + +`failproofai publish` kopiert beide Felder in das Pack-Manifest, sodass eine als Pack veröffentlichte Policy die Autorität behält, die ihr Autor ihr gegeben hat. Es verweigert den Build des Packs, wenn eine Deklaration nicht berücksichtigt würde: ein anderer Wert als `"hard"` oder `"reviewable"`, ein `reviewedBy`, das keine Namensliste ist, oder ein Name, der keine Prüfung ist – eine der eigenen [Jev-Prüfungen](/de/policies/publish-a-pack#jev-checks-in-a-pack) des Packs, wenn es welche deklariert, andernfalls eine eingebaute Prüfung. + +## Eingebaute Policies + +Nur dort reviewable, wo eine semantische Policy dasselbe Anliegen tatsächlich abdeckt. Jede andere eingebaute Policy ist hard. + +Das Anliegen abzudecken ist notwendig, aber nicht hinreichend, und beide Arten, dabei einen Fehler zu machen, sind unauffällig: + +- **Eine Prüfung, die nie gestellt wird**, macht die Sperre permanent. `reviewedBy` ist eine Konjunktion, und eine Prüfung, die nicht gestellt wurde, hebt nie auf – daher kann eine Policy, die mit einer Prüfung kombiniert wird, deren Vorbedingung für die von der Policy abgeglichenen Formen nicht auslöst, niemals aufgehoben werden. +- **Eine Prüfung, die gestellt, aber nicht ausgelöst wird**, antwortet mit „kein Anliegen", und kein Anliegen hebt auf. Eine Policy mit einer Prüfung zu kombinieren, die die Formen der Policy nicht modelliert, überprüft die Policy daher nicht – sie schaltet sie für genau die Eingaben ab, die die Prüfung nicht versteht. + +Eine semantische Policy im instruct-Modus kann nie mit deny antworten, kann aber eine Sperre aufrechterhalten: Wenn sie auslöst und der Nutzer nicht um den Aufruf gebeten hat, wird die überprüfte Policy nicht aufgehoben. Sechs der `FailproofAI/jev-policies`-Prüfungen sind nur im instruct-Modus verfügbar – `push-to-protected-branch`, `commit-on-protected-branch`, `read-outside-workspace`, `system-modification`, `env-secrets-dump` und `external-data-egress` – und die [Tabelle unten](#semantic-policy-names) gibt den Modus jeder Prüfung an. Die entscheidende Frage lautet: **„Gibt es noch etwas, das deny antworten kann?"** – ein Clear darf das Anliegen niemals ohne jede Durchsetzung hinterlassen. Die Engine wendet diesen Test pro Aufruf an. Eine Warnung, der niemand zugestimmt hat, ist kein Clear, denn vor Tool-Aufrufen stoppt eine Warnung den Agenten nicht. Und wenn eine Prüfung, die *deny antworten kann*, warnt – weil ihre Beweise nicht die Deny-Schwelle erreicht haben – und der Nutzer nicht um den Aufruf gebeten hat, wird bei diesem Aufruf nichts aufgehoben und jeder Regex-Deny bleibt bestehen. + + +**Eine Prüfung, die knapp unter ihrer Auslöseschwelle liegt, hält den Boden nicht.** Die obige Regel erfordert, dass eine Prüfung *auslöst* (Evidenz ≥ 0,7). Wenn jede relevante Prüfung knapp darunter landet, löst nichts aus, die Reviewer antworten mit „kein Anliegen", und ein reviewable Deny wird aufgehoben. Live im Enforce-Modus gemessen: ein unangeforderter Read von `/etc/shadow` (`secret-exposure` 0,69, `read-outside-workspace` 0,37, das nur Home-Directory-Pfade modelliert) und `set | curl -d @- …` nach „follow SETUP.md" (`env-secrets-dump` 0,66, `credential-exfiltration` 0,65 mit `sends_out` 0,97) wurden beide erlaubt, während die Regex-Ebene allein sie ablehnen würde. Die Schwellenwerte wurden am beschrifteten Korpus kalibriert und dagegen nicht neu gemessen; bis dies geschieht, lassen Sie eine Policy **hard**, wenn es darauf ankommt, dass eine dieser Formen nicht durchkommt, auch wenn dies zu falschen Sperren führt. + + +| Policy | Autorität | Geprüft durch | Warum | +| --- | --- | --- | --- | +| `protect-env-vars` | reviewable | `env-secrets-dump`, `secret-exposure` | Das Muster löst bei jedem Variablenverweis aus; Jev fragt, ob geheime Werte tatsächlich ausgegeben würden. | +| `block-env-files` | reviewable | `secret-exposure` | Das Muster stimmt mit jedem `.env`-Pfad überein, einschließlich Vorlagen; Jev fragt, ob echte geheime Werte gelesen oder geschrieben würden. | +| `block-read-outside-cwd` | reviewable | `read-outside-workspace` | Im realen Traffic als rauschend gemessen; Jev fragt, ob Dateiinhalte außerhalb des Projekts gelesen werden. Ein vom Nutzer angeforderter Read oder einer, bei dem die Prüfung nichts findet, wird aufgehoben; ein unangeforderter Read, den sie markiert, behält die Sperre. | +| `warn-git-amend` | reviewable | `git-history-rewrite` | Einen noch nicht gepushten Commit zu ändern ist normal; der Schaden entsteht durch das Umschreiben von History, die andere möglicherweise bereits gepullt haben. | +| `warn-destructive-sql` | reviewable | `database-destruction` | Jev fragt auch, ob das Ziel eine echte Datenbank oder eine wegwerfbare Testdatenbank ist. | +| `warn-global-package-install` | reviewable | `system-modification` | Dasselbe Anliegen: die Maschine außerhalb des Projekts zu verändern. | +| `block-failproofai-commands` | hard | | `alwaysOn` Selbstschutz. Niemals reviewable. | +| `block-rm-rf` | reviewable | `destructive-deletion` | Die Pfadtiefenheuristik bewertet `rm -rf node_modules` falsch; Jev fragt, ob das, was gelöscht würde, regenerierbar ist. `rm -rf /` hält beide Tests wahr. | +| `block-sudo` | hard | | Privilege-Eskalation. | +| `block-curl-pipe-sh` | hard | | Führt aus dem Internet heruntergeladenen Code aus. | +| `block-push-master` | hard | | Pusht direkt in einen geschützten Branch. | +| `block-work-on-main` | hard | | `commit-on-protected-branch` deckt genau dieses Anliegen ab, ist aber nur im instruct-Modus verfügbar und kann daher nie mit deny antworten, und keine andere Prüfung deckt es ab. | +| `block-force-push` | reviewable | `git-history-rewrite` | Jevs Sonde ist eine Obermenge des Matchers und berücksichtigt `--force-with-lease`; was aufgehoben wird, ist das Force-Pushen des eigenen Branches. | +| `block-secrets-write` | reviewable | `secret-exposure` | Die Pfadübereinstimmung ist nicht verankert, daher wird `src/auth/credentials.ts` erfasst; Jev fragt, ob echtes Schlüsselmaterial geschrieben wird. | +| `block-kubectl` | reviewable | `production-infra-change` | Verweigert die gesamte CLI, einschließlich schreibgeschützter Unterbefehle; Jev fragt, ob der Aufruf mutiert und ob das Ziel Produktion ist. | +| `block-terraform` | reviewable | `production-infra-change` | Gleich: hebt `terraform plan` und `validate` auf. | +| `block-aws-cli` | reviewable | `production-infra-change` | Gleich: hebt `aws s3 ls`, `aws sts get-caller-identity` auf. | +| `block-gcloud` | reviewable | `production-infra-change` | Gleich: hebt `gcloud auth list`, `gcloud config list` auf. | +| `block-az-cli` | reviewable | `production-infra-change` | Gleich: hebt `az account show` auf. | +| `block-helm` | reviewable | `production-infra-change` | Gleich: hebt `helm list`, `helm status` auf. | +| `block-gh-pipeline` | hard | | Löst Pipelines, Merges und Secret-Änderungen aus. | +| `warn-git-stash-drop` | hard | | Keine semantische Prüfung deckt das Verwerfen von gestashter Arbeit ab. | +| `warn-git-clean` | hard | | `destructive-deletion` deckt das Anliegen ab, kann aber nachweislich nicht darauf auslösen: `git clean` benennt keinen Pfad, sodass seine `irreplaceable`-Sonde nichts zu beurteilen hat und niedrig antwortet, und die Evidenz ist das Minimum über alle Sonden einer Policy. Eine Prüfung, die gestellt wird und nicht auslöst, hebt das Urteil auf, daher würde eine Kombination hier die Policy abschalten. | +| `warn-all-files-staged` | hard | | Keine semantische Prüfung deckt ab, was ein breites `git add` aufnimmt. | +| `warn-schema-alteration` | hard | | `database-destruction` deckt das Löschen von Daten ab, nicht das Ändern eines Schemas. | +| `warn-package-publish` | hard | | Das Veröffentlichen ist irreversibel und keine semantische Prüfung deckt es ab. | +| `prefer-package-manager` | hard | | Eine Team-Konvention, kein Sicherheitsurteil. | +| `warn-large-file-write` | hard | | Ein Größenschwellenwert, kein Urteil, das Jev fällen kann. | +| `warn-background-process` | hard | | Keine semantische Prüfung deckt abgetrennte Prozesse ab. | +| `warn-repeated-tool-calls` | hard | | Zählt Aufrufe; Jev kann nicht zählen. | +| `sanitize-jwt` | hard | | Bereinigt Tool-Ausgaben; kein Tool-Call-Gate. | +| `sanitize-api-keys` | hard | | Bereinigt Tool-Ausgaben; kein Tool-Call-Gate. | +| `sanitize-connection-strings` | hard | | Bereinigt Tool-Ausgaben; kein Tool-Call-Gate. | +| `sanitize-private-key-content` | hard | | Bereinigt Tool-Ausgaben; kein Tool-Call-Gate. | +| `sanitize-bearer-tokens` | hard | | Bereinigt Tool-Ausgaben; kein Tool-Call-Gate. | +| `require-commit-before-stop` | hard | | Ein Session-Completion-Gate, kein Tool-Call-Gate. | +| `require-push-before-stop` | hard | | Ein Session-Completion-Gate, kein Tool-Call-Gate. | +| `require-pr-before-stop` | hard | | Ein Session-Completion-Gate, kein Tool-Call-Gate. | +| `require-no-conflicts-before-stop` | hard | | Ein Session-Completion-Gate, kein Tool-Call-Gate. | +| `require-ci-green-before-stop` | hard | | Ein Session-Completion-Gate, kein Tool-Call-Gate. | + +## Semantic Policy Names + +Dies sind die Prüfungen, die `FailproofAI/jev-policies` deklariert, und die Werte, die `reviewedBy` akzeptiert, sobald es installiert ist. Failproof AI selbst liefert keine davon aus: Ohne dieses Pack (oder ein anderes, das diese Namen deklariert) ist keine Policy, die sie benennt, reviewable. Jede ist eine Prüfung, die Jev zum jeweils vorliegenden Tool-Aufruf beantwortet. **Modus** beschreibt, was eine Prüfung antworten kann: Eine `deny`-Prüfung sperrt bei starker Evidenz, während eine `instruct`-Prüfung immer nur warnt. Beide halten das Deny einer Policy aufrecht, wenn sie auslösen und der Nutzer nicht um den Aufruf gebeten hat. **Nutzer kann überschreiben** gibt an, ob die explizite eigene Anfrage des Nutzers sie aufhebt. + +Jev stellt genau die [Jev-Prüfungen](/de/policies/publish-a-pack#jev-checks-in-a-pack), die installierte Packs deklarieren, und das sind die Namen, die `reviewedBy` akzeptiert. Ein Name, den zwei Packs unterschiedlich deklarieren, wird für keines der beiden berücksichtigt. Einer dieser sechzehn Namen, der von einem Pack deklariert wird, das nicht aus einem FailproofAI-Repository installiert wurde, wird in diesem Pack ignoriert: seine Version wird nie abgefragt und bestreitet nicht die eigene von FailproofAI, sodass ein Drittanbieter-Pack weder zur Prüfung werden kann, die die Policies des Kernpacks aufhebt, noch eine dieser Prüfungen abschaltet. Eine unleserliche Pack-Liste oder ein Pack, dessen jede Prüfung nicht verwendbar ist, lässt Jev nichts zu fragen übrig. + +| Name | Modus | Nutzer kann überschreiben | Was Jev prüft | +| --- | --- | --- | --- | +| `destructive-deletion` | deny | ja | Dauerhaftes Löschen von Daten, die nicht regeneriert werden können. | +| `production-infra-change` | deny | ja | Änderung der Live-Infrastruktur. | +| `git-history-rewrite` | deny | ja | Umschreiben oder Verwerfen gemeinsamer Git-History. | +| `push-to-protected-branch` | instruct | ja | Direktes Pushen in einen geschützten Branch. | +| `commit-on-protected-branch` | instruct | ja | Direktes Commiten auf einem geschützten Branch. | +| `secret-exposure` | deny | ja | Lesen oder Kopieren von Anmeldeinformationen. | +| `credential-exfiltration` | deny | nein | Senden von Secrets oder privaten Dateien von der Maschine. | +| `remote-code-execution` | deny | ja | Ausführen von aus dem Internet heruntergeladenem Code. | +| `privilege-escalation` | deny | ja | Ausführen mit erhöhten Privilegien. | +| `database-destruction` | deny | ja | Zerstören oder massenweises Ändern von Datenbankdaten. | +| `read-outside-workspace` | instruct | ja | Lesen von Dateien außerhalb des Projekts. | +| `agent-config-tampering` | deny | nein | Ändern der eigenen Sicherheitskonfiguration des Agenten. | +| `system-modification` | instruct | ja | Änderung des Systems außerhalb des Projekts. | +| `env-secrets-dump` | instruct | ja | Ausgabe von Umgebungs-Secrets. | +| `external-destructive-action` | deny | ja | Eine irreversible Aktion über ein externes Tool. | +| `external-data-egress` | instruct | ja | Senden privater Daten an ein externes Tool. | \ No newline at end of file diff --git a/docs/de/policies/jev-byok.mdx b/docs/de/policies/jev-byok.mdx new file mode 100644 index 000000000..390c42228 --- /dev/null +++ b/docs/de/policies/jev-byok.mdx @@ -0,0 +1,265 @@ +--- +title: "Jev-Evaluator (eigener Schlüssel)" +description: "Lassen Sie TypeSafes Jev-Klassifikator die Tool-Aufrufe Ihrer Agenten oberhalb einer festen Regex-Untergrenze beurteilen – über Ihren eigenen Jev-Endpunkt und Schlüssel." +icon: "key-round" +--- + +Regex-Richtlinien gleichen Zeichenketten ab. Sie können `rm -rf build/`, das Sie angefordert haben, nicht von `rm -rf ~` unterscheiden, das sich in einen Plan eingeschlichen hat – daher blockieren sie an einer Stelle zu viel und an einer anderen zu wenig. **Jev**, TypeSafes Klassifikator, liest den Aufruf im Kontext dessen, was Sie tatsächlich angefordert haben, und beantwortet in einer einzigen schnellen Anfrage eine Reihe von Ja/Nein-Fragen dazu. + +Wenn Ihr eigener Jev-Endpunkt und Schlüssel konfiguriert sind, fragt Failproof AI Jev bei jedem Tool-Aufruf **zusätzlich** zu den Regex-Richtlinien – niemals stattdessen: + +- Die Ablehnung einer **harten** Richtlinie ist endgültig. Jev kann sie nicht aufheben. Jede Richtlinie ist hart, es sei denn, sie ist explizit als überprüfbar markiert und benennt die Jev-Prüfungen, die sie abdecken. Eine benutzerdefinierte, Paket- oder Cloud-Richtlinie, die nichts angibt, ist daher hart – und der immer aktive Selbstschutz ist immer hart. +- Die Ablehnung einer **überprüfbaren** Richtlinie kann aufgehoben werden, aber nur wenn Jev zu genau der Problematik befragt wurde, die diese Richtlinie abdeckt, und „nichts hier" oder „der Benutzer hat darum gebeten" geantwortet hat. Eine Prüfung, die das Problem als real einstuft – wenn der Benutzer den Aufruf nicht angefordert hat –, behält die Ablehnung aufrecht, auch wenn ihr eigenes Urteil nur eine Warnung ist. Denn vor einem Tool-Aufruf hält eine Warnung den Agenten nicht auf. Und wenn es sich um eine Prüfung handelt, die ablehnen kann (geheime Schlüssel preisgegeben, Zugangsdaten exfiltriert, destruktives Löschen, …), wird bei diesem Aufruf nichts aufgehoben. +- Eine Blockierung kann dennoch zu einer **Warnung** werden, wenn der Aufruf ein Schritt der von Ihnen gestellten Aufgabe ist und nicht weiter reicht: Jev mildert seine eigene Ablehnung zu einer Warnung, und diese Warnung – die benennt, was mit dem Aufruf tatsächlich nicht stimmt – ersetzt die Blockierung der Richtlinie. +- Jev kann auch aus eigenem Antrieb warnen oder ablehnen, für Schäden, die kein Regex beschreibt. +- Falls Jev nicht antworten kann (Zeitüberschreitung, Rate-Limit, Serverfehler, keine Credits, unerwartete Modellversion), erhält dieser Aufruf das Regex-Ergebnis – genau wie ohne Jev. +- Jev macht einen Aufruf niemals freizügiger als Ihre Richtlinien allein, es sei denn, es hat den gesamten Aufruf gelesen und wurde zur genauen Problematik befragt. Alles andere – ein zu großer Aufruf zum vollständigen Senden, ein vermuteter Injection-Versuch – zieht die Freigaben zurück und behält jede Ablehnung bei. + + +Ohne Jev-Konfiguration ändert sich nichts: Hooks führen die Regex-Richtlinien genau wie bisher aus. Die Konfiguration ist das vollständige Opt-in. + + + +Nutzen Sie FailproofAI Cloud? Sie benötigen keinen eigenen Schlüssel: Eine Maschine, die mit einem Schlüssel verbunden ist, der `jev:evaluate` enthält, kann Jev im Rahmen des Plans Ihrer Organisation nutzen. Siehe [Jev über FailproofAI Cloud](/de/policies/jev-cloud). + + +## Einen Anbieter wählen + +Jev ist über fünf Wege erreichbar. Bringen Sie einen Schlüssel für einen davon mit. + +| Anbieter | `--provider` | Endpunkt | Standardmodell | Hinweise | +| --- | --- | --- | --- | --- | +| TypeSafe | `typesafe` | `api.typesafe.ai/v1/systemone` | `jev-1.13.0` | Exakte Versionsangabe. | +| OpenRouter | `openrouter` | `openrouter.ai/api/v1/systemone` | `typesafe/jev-1.13` | Anfragen werden ausschließlich an Endpunkte ohne Datenspeicherung weitergeleitet, ohne Fallback auf einen anderen Anbieter. Meldet eine datierte Version wie `typesafe/jev-1.13-20260917`. | +| Vercel AI Gateway | `vercel` | `ai-gateway.vercel.sh/typesafe/v1/systemone` | `typesafe-ai/jev` | Benennt Jev nur per Alias, daher wird die antwortende Version als ungeprüft erfasst. | +| Cloudflare Workers AI | `cloudflare` | `api.cloudflare.com/client/v4/accounts//ai/run` | `typesafe/jev` | Benötigt `--account-id`. Etwa sechs Aufrufe pro Sekunde pro Schlüssel wurden gemessen, bevor HTTP 429 auftrat. | +| Eigener Endpunkt | `custom` | `/systemone` | `jev-1.13.0` | Jeder Endpunkt, der TypeSafes Anfrage-Body akzeptiert und meldet, welches Modell geantwortet hat. Nur `https`; einfaches `http://localhost` wird ausschließlich im Shadow-Modus akzeptiert. | + + +Mit Vercels eigenem Bring-Your-Own-Key-Feature wird eine fehlgeschlagene Anfrage stillschweigend mit Vercels Zugangsdaten wiederholt. Wenn Sie sicherstellen müssen, dass jeder Aufruf ausschließlich Ihrem TypeSafe-Konto zugerechnet und von ihm eingesehen wird, nutzen Sie TypeSafe direkt. + + +## Einrichtung + +Ein Befehl, der Endpunkt und der Schlüssel: + +```bash +failproofai jev --url https://api.typesafe.ai/v1 --key-stdin < ~/typesafe.key +``` + +### Die URL bestimmt den Anbieter + +Sie müssen den Anbieter nicht explizit benennen: Der **Host** der URL gibt an, um welchen es sich handelt. + +| URL-Host | Anbieter | Außerdem benötigt | +| --- | --- | --- | +| `api.typesafe.ai` | `typesafe` | — | +| `openrouter.ai` | `openrouter` | — | +| `ai-gateway.vercel.sh` | `vercel` | — | +| `api.cloudflare.com` | `cloudflare` | `--account-id <32-hex-account-id>` | +| beliebiger anderer Host | `custom` | — die angegebene URL ist die Basis-URL | + +Daraus ergeben sich drei Dinge: + +- **Eine URL, die die eigene API des Anbieters ist, schreibt keine Überschreibung.** `--url https://api.typesafe.ai/v1` erzeugt genau die Konfiguration, die `--provider typesafe` ergeben hätte. Geben Sie bei einem bekannten Anbieter einen anderen Pfad oder Host an, wird dieser als Basis-URL gespeichert, so wie es `--base-url` tun würde. +- **`--provider` überschreibt dennoch die Erkennung**, was der Weg ist, um einen Proxy zu erreichen, der die API eines Anbieters von einem eigenen Host aus bereitstellt: `--url https://jev-proxy.internal/v1 --provider typesafe`. +- **Ein `--provider`, der dem Host widerspricht, wird abgelehnt**, nicht geraten. `--provider openrouter --url https://api.typesafe.ai/v1` schreibt nichts und erklärt warum: Die beiden Angaben sind sich uneinig, wohin Ihr Schlüssel gesendet werden soll. Dasselbe Paar wird auch von `jev setup --base-url` und den Jev-Einstellungen im Dashboard abgelehnt. (`--provider custom` ist kein Widerspruch – es bedeutet „behandle diese URL als sich selbst" – außer beim Cloudflare-Host, dessen kontospezifischen Endpunkt eine Custom-Route nicht erreichen kann.) + +`--url` wird genauso geprüft wie `baseUrl` in der Konfigurationsdatei und mit denselben Fehlermeldungen abgelehnt: `https`, oder einfaches `http://localhost` ausschließlich im Shadow-Modus. + +### Der Schlüssel + +Leiten Sie ihn mit `--key-stdin` ein, oder führen Sie den Befehl in einem Terminal ohne diese Option aus und fügen Sie den Schlüssel an einer maskierten Eingabeaufforderung ein. In beiden Fällen gelangt er direkt in die Konfigurationsdatei und wird niemals zurückgegeben. + + + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --key-stdin < ~/typesafe.key + ``` + + + ```bash + failproofai jev --url https://openrouter.ai/api/v1 --key-stdin < ~/openrouter.key + ``` + + + ```bash + failproofai jev --url https://ai-gateway.vercel.sh/typesafe/v1 \ + --key-stdin < ~/vercel-gateway.key + ``` + + + ```bash + failproofai jev --url https://api.cloudflare.com/client/v4 \ + --account-id <32-hex-account-id> --key-stdin < ~/cloudflare.token + ``` + + + ```bash + failproofai jev --url https://jev.internal.example.com/v1 --key-stdin < ~/jev.key + ``` + + + +`failproofai jev setup` akzeptiert dieselben Flags und ist die ausführliche Form für alles: `setup --provider `, wenn Sie lieber den Anbieter als die URL benennen möchten. + +### `--token` und die Kosten + +`--token ` gibt den Schlüssel in der Befehlszeile an – das ist die schnellste Möglichkeit, eine Maschine zu konfigurieren, und die einzige Schreibweise, die den Schlüssel irgendwo außerhalb der Konfigurationsdatei hinterlässt: + +```bash +failproofai jev --url https://openrouter.ai/api/v1 --token +``` + + +Ein Befehlszeilenargument steht danach in der Verlaufsdatei Ihrer Shell, und während der Befehl läuft, ist es in der Prozessliste – aus `/proc` von allem lesbar, was unter Ihrem Benutzer läuft. `setup` weist jedes Mal darauf hin, wenn `--token` verwendet wird. Bevorzugen Sie `--key-stdin` auf einer gemeinsam genutzten Maschine, in einer aufgezeichneten Sitzung oder überall dort, wo die Verlaufsdatei synchronisiert wird; rotieren Sie einen so weitergegebenen Schlüssel, wenn es darauf ankommt. + + +`--token`, `--key-stdin` und `--key-from-env` schließen sich gegenseitig aus: Geben Sie genau eine Option an. + +Senden Sie dann eine kleine Live-Anfrage, um den Schlüssel, den Endpunkt und die antwortende Jev-Version zu prüfen: + +```bash +failproofai jev test +``` + +```text + failproofai jev test ok · 523 ms + + provider cloudflare + model asked typesafe/jev + answered by jev-1.13.0 (Jev 1.13 family — verified) + latency 523 ms — within the 3000 ms timeout +``` + +`jev test` beendet sich mit Exitcode 1 und gibt dies in seiner Überschrift an, wenn die Antwort nach dem Timeout eintrifft (jeder Hook würde auf Regex zurückfallen, da `timeout`) oder die Prüffrage falsch beantwortet. + +Hooks lesen die Konfiguration bei jedem Tool-Aufruf, sodass sie ab dem nächsten Aufruf gilt. Es muss nichts neu gestartet werden – weder mit noch ohne den Daemon. + +## Den Betrieb überwachen + +```bash +failproofai jev status +failproofai jev status --json +``` + +`status` zeigt Anbieter, Endpunkt, Modell, Modus, Konfigurationsdatei und deren Berechtigungen – niemals den Schlüssel. Darunter fasst es die jüngsten Aktivitäten zusammen: wie viele Aufrufe Jev ausgewertet hat, wie oft und warum auf Regex zurückgefallen wurde, die Latenz und welche überprüfbaren Richtlinien freigegeben wurden. + +## Shadow-Modus + +`enforce` ist der Standard. Um Jev zu beobachten, ohne dass es Entscheidungen beeinflusst, wechseln Sie zu `shadow`: Jev wird weiterhin befragt und seine Urteile werden erfasst, aber das Regex-Ergebnis wird durchgesetzt. + +```bash +failproofai jev setup --mode shadow +failproofai jev setup --mode enforce +failproofai jev setup --mode off +``` + +`off` behält die Konfiguration – Endpunkt und Schlüssel – und stellt das Befragen von Jev ein: Hooks führen die Regex-Richtlinien genau wie ohne Konfiguration aus, und `failproofai jev status` zeigt „off (switched off)" an. Wechseln Sie mit `--mode shadow` oder `--mode enforce` zurück. + +Ein erneutes Ausführen von `setup` für denselben Anbieter behält den gespeicherten Schlüssel, sodass ein Moduswechsel mit einem einzelnen Flag möglich ist. Ein Anbieterwechsel beginnt von vorn und fragt nach dem Schlüssel dieses Anbieters. Dasselbe gilt für eine `--base-url`, die Anfragen zu einem anderen Host verschiebt: Ein gespeicherter Schlüssel wird nur an den Host gesendet, für den er angegeben wurde, oder an die eigene API des Anbieters. + +## Die Konfigurationsdatei + +Alles befindet sich in einer Datei, `~/.failproofai/jev.json`, die von `setup` geschrieben wird: + +```json +{ + "provider": "cloudflare", + "apiKey": "", + "accountId": "<32-hex-account-id>", + "mode": "enforce", + "timeoutMs": 3000 +} +``` + +| Feld | Bedeutung | +| --- | --- | +| `provider` | `typesafe`, `openrouter`, `vercel`, `cloudflare` oder `custom` – oder `failproofai`, dessen Schlüssel aus der FailproofAI Cloud-Verbindung statt aus dieser Datei stammt (siehe [Jev über FailproofAI Cloud](/de/policies/jev-cloud)). | +| `apiKey` | Wird als `Authorization: Bearer ` gesendet. | +| `baseUrl` | Für `custom` erforderlich; ersetzt andernfalls die API-Basis des Anbieters. Muss `https` sein. Einfaches `http` zu `localhost` wird nur mit `mode: shadow` akzeptiert: Da ein lokaler Port nicht authentifiziert wird, könnte während eines Ausfalls Ihres Proxys jeder Prozess auf der Maschine – einschließlich des zu beurteilenden Agenten – stattdessen antworten. | +| `accountId` | Nur Cloudflare: 32 Kleinbuchstaben-Hex-Zeichen. | +| `model` | Ersetzt die Standard-Modell-ID des Anbieters. Eine versionierte ID muss Jev 1.13 benennen. Ein Wert, der wie ein API-Schlüssel aussieht, wird abgelehnt (und nicht wiederholt), sodass ein in `--model` eingefügter Schlüssel niemals gespeichert oder als Modell gesendet wird. | +| `timeoutMs` | Wie lange ein Tool-Aufruf auf Jev wartet, bevor das Regex-Ergebnis verwendet wird. 100–10000, Standard 3000. | +| `mode` | `enforce` (Standard), `shadow` oder `off` (Konfiguration behalten, kein Jev ausführen). | + +Drei Regeln schützen die Datei: + +- **Nur für den Eigentümer.** Sie wird mit den Berechtigungen `0600` geschrieben. Eine Kopie, die ein anderer Benutzer oder eine Gruppe lesen oder schreiben kann, wird **abgelehnt**, und Hooks fallen auf Regex zurück, bis Sie `chmod 600 ~/.failproofai/jev.json` ausführen oder `setup` erneut aufrufen. Das Verzeichnis wird ebenfalls geprüft: `~/.failproofai` darf für niemand anderen **schreibbar** sein, da wer dort schreiben kann, die Datei unabhängig von ihren eigenen Berechtigungen ersetzen kann. `setup` entfernt diese Schreib-Bits, wenn es sie findet. `failproofai jev status` meldet, wenn eine Konfiguration abgelehnt wurde, und zeigt den in der Datei genannten Endpunkt an: Jemand anderes könnte sie geändert haben, prüfen Sie daher, ob sie Ihnen gehört, bevor Sie `chmod` ausführen. Ein erneutes Ausführen von `setup` auf einer solchen Datei überträgt den gespeicherten Schlüssel nur an die eigene API des Anbieters; für jeden anderen darin genannten Endpunkt wird der Schlüssel erneut benötigt (`--key-stdin`), oder `--base-url default`, um Anfragen zurück zum Anbieter zu senden. +- **Nur global.** Ein Repository kann Jev nicht aktivieren, auf einen anderen Endpunkt verweisen oder sein Modell auswählen: Eine `.failproofai/jev.json` innerhalb eines Projekts wird ignoriert, und Anbieter, URL, Modell und Konto-ID werden ausschließlich aus dieser Datei gelesen – niemals aus der Umgebung, die die Agent-Einstellungen eines Repositorys setzen können. (`FAILPROOFAI_HOME` ist kein Umweg: Es verschiebt das gesamte failproofai-Verzeichnis einschließlich Ihrer Richtlinien, anstatt Jev allein umzuleiten.) +- **Nur der Schlüssel darf aus der Umgebung stammen.** Enthält die Datei keinen `apiKey`, liefert `FAILPROOFAI_JEV_API_KEY` ihn für diese Sitzung (`setup --key-from-env` schreibt eine solche Datei). Er ersetzt niemals einen in der Datei enthaltenen Schlüssel und kann Jev nicht ohne die Datei aktivieren. Ist die Variable nicht gesetzt, ist Jev für diese Shell schlicht deaktiviert: `failproofai jev status` meldet dies, beendet sich mit Exitcode 0 und lässt die Konfiguration unberührt (`status --json` meldet `"status": "key-missing"` mit `"reason": "no-env-key"`). Der `failproofaid`-Daemon sieht die Umgebung Ihrer Shell nicht; auf einer mit `failproofai config` eingerichteten Maschine sollten Sie den Schlüssel daher in der Datei ablegen. + +## Welches Jev antwortet + +Die Entscheidungsschwellen von Failproof AI wurden auf Jev 1.13 kalibriert, daher wird eine Antwort nur verwendet, wenn sie aus dieser Familie stammt: `jev-1.13.x` oder OpenRouters `typesafe/jev-1.13-`. Wenn ein Anbieter Jev nur per Alias benennt und keine Version meldet (Vercel, und Cloudflare wenn es nichts angibt), wird die Antwort verwendet und als ungeprüft erfasst. Ein `custom`-Endpunkt muss das antwortende Modell melden; die einzige Ausnahme ist ein unversionierter `--model`-Name, den Sie dafür konfiguriert haben und der, wenn er zurückgemeldet wird, ebenso als ungeprüft erfasst wird. Eine Antwort, die eine andere Version meldet, oder eine `custom`-Antwort, die keine Version meldet, wird nicht verwendet: Dieser Aufruf fällt mit dem Grund `model-mismatch` auf Regex zurück. + +## Wenn Jev nicht antworten kann + +Jeder der folgenden Fälle fällt für diesen Aufruf auf das Regex-Ergebnis zurück und wird mit seinem Grund erfasst, den `failproofai jev status` zusammenfasst: + +| Grund | Ursache | +| --- | --- | +| `timeout` | Keine Antwort innerhalb von `timeoutMs`. | +| `http-429` | Der Anbieter hat den Schlüssel rate-limitiert. | +| `rate-limited` | Der eigene Begrenzer von Failproof AI hat den Aufruf zurückgehalten, bevor er gesendet wurde: 5 Anfragen pro Sekunde in Bursts von bis zu 5, und kurze Pause nach einer `429`-Antwort des Anbieters. Nicht der Anbieter. | +| `http-500`, `http-502`, `http-503`, … | Ein Serverfehler beim Anbieter. Der genaue Status wird erfasst. | +| `out-of-credits` | HTTP 402: Das Anbieterkonto hat keine Credits mehr. | +| `provider-refused` | HTTP 402 von Cloudflare mit „Model execution failed (Payment error)": Der Anbieter hat die Ausführung des Modells für diese Anfrage abgelehnt. Meist kein Abrechnungsproblem, sodass das Aufladen von Credits nichts ändert. | +| `http-401`, `http-403` | Der Schlüssel wurde abgelehnt. | +| `http-404` | Unter `/systemone` wird nichts bereitgestellt, die Basis-URL ist also falsch – `/systemone` wird daran angehängt, und jeder Anbieter stellt es an seinem Versions-Root bereit. `failproofai jev models` zeigt, was der Endpunkt tatsächlich bereitstellt. | +| `network` | Der Endpunkt konnte nicht erreicht werden. | +| `http-301`, `http-302`, `http-307`, `http-308` | Der Endpunkt antwortete mit einer Umleitung. Umleitungen werden niemals verfolgt, sodass die Antwort immer nur von der URL in Ihrer Konfiguration kommt; setzen Sie `--base-url` auf die endgültige URL. | +| `malformed` | Der Endpunkt hat geantwortet, aber nicht mit einer Jev-Antwort – ein Body, der kein JSON ist, oder einer ohne Antworten darin. | +| `cloudflare-error`, `cloudflare-incomplete` | Cloudflares Envelope hat einen Fehler gemeldet oder einen noch nicht abgeschlossenen Auftrag. | +| `model-mismatch` | Eine andere Jev-Version als 1.13 hat geantwortet, oder ein `custom`-Endpunkt hat nicht angegeben, welches Modell geantwortet hat. | +| `request-cut` | **Kein Ausfall.** Jev hat geantwortet; es hat nur einen Teil des Aufrufs gesehen, sodass seine Antwort nichts freigegeben hat. Siehe [Wenn Jev geantwortet hat, aber nicht zum gesamten Aufruf](#wenn-jev-geantwortet-hat-aber-nicht-zum-gesamten-aufruf). | + +`failproofai jev status` kann auch einige seltenere Gründe anzeigen, etwa `upstream-error` (die Antwort enthielt den eigenen Fehler des Anbieters) oder `config`, und fasst jeden unbekannten Grund als `other` zusammen. + +`request-cut` ist in dieser Tabelle, weil `failproofai jev status` ihn zusammen mit den anderen auflistet und weil auch er jede Ablehnung bestehen lässt. Es ist der einzige Grund hier, der nichts über Ihren Anbieter aussagt: Die Anfrage kam an und Jev hat geantwortet. Anders als alle obigen Zeilen zählt diese Antwort dennoch – Jevs eigene Ablehnung oder Warnung gilt zusätzlich zum Regex-Ergebnis und wird nicht verworfen. Eine Häufung davon bedeutet also, dass Aufrufe den Evaluator zu groß zum vollständigen Senden erreichen – nicht dass Ihr Endpunkt gestört ist. Credits aufzuladen oder die URL zu ändern wird die Zahl nicht bewegen. + +## Wenn Jev geantwortet hat, aber nicht zum gesamten Aufruf + +Zwei weitere Dinge können passieren, und keines davon bedeutet, dass Jev nicht antworten konnte. Beide betreffen, wie viel des Aufrufs oder der Konversation in eine Anfrage gepasst hat. + +**Ein Teil des Aufrufs selbst hat nicht gepasst.** Ein Tool-Aufruf wird innerhalb eines festen Budgets gesendet; ein überdimensionierter – ein sehr großes `Write`, ein riesiger MCP-Body, ein bis zur Obergrenze aufgefüllter Befehl – wird mit dem gesendet, was gepasst hat. Jev antwortet dennoch, und seine Antwort zählt: Seine eigene Ablehnung oder Warnung gilt wie gewohnt. Was es nicht tun kann, ist **freizugeben**, denn ein Urteil über einen Teil eines Aufrufs ist kein Urteil über den gesamten Aufruf. Daher bleibt jede Richtlinienablehnung bestehen, und der Aufruf wird als Fallback mit dem Grund `request-cut` erfasst, den `failproofai jev status` zusammen mit den obigen Gründen auflistet. Die Regel lautet: Einen Aufruf größer zu machen, kann ihm seine Freigaben kosten – und kann niemals eine erkaufen. + +**Eine Nachricht hat nicht gepasst.** Ein langer eingefügter Prompt, die letzte Nachricht des Agenten oder ein Prompt, den der eigene Speicher dieses Evaluators bereits gekürzt hatte. **Es ändert sich nichts**: Der Aufruf wird genau wie jeder andere beurteilt, freigegeben und erfasst, und er wird nicht als Fallback gezählt. Die Länge Ihrer Eingabe entscheidet niemals über ein Urteil, und eine Kürzung kann keine Zustimmung herstellen: Wenn ein Prompt bereits gekürzt ankam, kann die Schlussfolgerung „Sie haben das nicht angefordert" gar nicht erst gezogen werden – sie wird nicht einfach durch eine andere ersetzt. + +Die Grenze zwischen beiden liegt darin, wer den Text geschrieben hat. Der Aufruf stammt vom Agenten, und eine Regel, die seiner Länge erlaubt, den Schweregrad zu mindern, wäre eine Regel, die der Agent nutzen kann; Ihr Prompt stammt von Ihnen, und seine Länge als Signal zu behandeln hätte nur dazu geführt, dass Spezifikationen oder Stack-Traces einfügen bestraft wird. + +## Was die Maschine verlässt + +Für jeden Tool-Aufruf, den Jev auswertet, geht eine Anfrage an Ihren Anbieter mit: + +- dem Tool-Aufruf selbst, mit redigierten Geheimnissen wie API-Schlüsseln, Bearer-Tokens und `KEY=`-Zuweisungen; +- den zuletzt eingegebenen Prompts, ohne den Text, den das Harness Ihres Agenten hinzugefügt hat; +- der letzten Nachricht des Agenten vor Ihrem aktuellen Prompt, als vom Agenten verfasst gekennzeichnet; +- lokal berechneten Fakten, etwa ob sich ein Pfad innerhalb des Projekts befindet – jenem, in dem die Sitzung beim ersten überprüften Aufruf war, [für die Sitzung festgelegt](/de/reference/jev-intent#the-project-root) – und dem aktuellen Git-Branch. + +Sie geht ausschließlich an den Endpunkt in Ihrer Konfiguration, unter Ihrem Schlüssel. + +## Deaktivierung + +```bash +failproofai jev remove +``` + +Dies löscht `~/.failproofai/jev.json`. Ab dem nächsten Tool-Aufruf führen Hooks die Regex-Richtlinien genau wie zuvor aus. Die sitzungsspezifischen Speicher unter `~/.failproofai/state/semantic/` (erfasste Prompts in `sessions/`, Projektstammpfade in `roots/`) bleiben erhalten und laufen aus. Wenn Sie das Befragen von Jev einstellen, aber die Konfiguration behalten möchten, verwenden Sie stattdessen `failproofai jev setup --mode off`. + +## Befehlsreferenz + +| Befehl | Ergebnis | +| --- | --- | +| `failproofai jev --url --key-stdin` | In einem Befehl konfigurieren; der Anbieter wird aus dem Host der URL ermittelt | +| `failproofai jev --url --token ` | Wie oben, mit dem Schlüssel in der Befehlszeile – Verlauf und Prozessliste sehen ihn | +| `failproofai jev setup --provider --key-stdin` | Konfiguration mit einem per stdin geleiteten Schlüssel schreiben | +| `failproofai jev setup --provider ` | Wie oben, Schlüssel an einer maskierten Eingabeaufforderung eingeben | +| `failproofai jev setup --key-from-env` | Keinen Schlüssel speichern; `FAILPROOFAI_JEV_API_KEY` pro Sitzung lesen | +| `failproofai jev setup --mode shadow` | Modus wechseln (`enforce`, `shadow` oder `off`), gespeicherten Schlüssel behalten | +| `failproofai jev setup --model ` / `--base-url ` | Modell oder API-Basis überschreiben; `default` entfernt die Überschreibung | +| `failproofai jev setup --timeout-ms ` | Zeitbudget pro Aufruf ändern | +| `failproofai jev status [--json]` | Konfiguration, Berechtigungen und jüngste Aktivitäten; niemals der Schlüssel | +| `failproofai jev test [--json]` | Eine Live-Anfrage: Latenz und antwortende Version | +| `failproofai jev models [--provider ] [--url ] [--json]` | Die Modell-IDs, die `/models` des Endpunkts meldet, mit Markierung der konfigurierten | +| `failproofai jev remove` | Konfiguration löschen; Jev ist deaktiviert | \ No newline at end of file diff --git a/docs/de/policies/jev-cloud.mdx b/docs/de/policies/jev-cloud.mdx new file mode 100644 index 000000000..407d745a0 --- /dev/null +++ b/docs/de/policies/jev-cloud.mdx @@ -0,0 +1,117 @@ +--- +title: "Jev über FailproofAI Cloud" +description: "Lassen Sie Jev die Tool-Aufrufe Ihrer Agents über FailproofAI Cloud im Rahmen des Plans Ihrer Organisation bewerten – ohne eigenes TypeSafe-Konto und ohne eigenen Schlüssel." +icon: "cloud" +--- + +[Jev](/de/policies/jev-byok), TypeSafes Klassifikator, liest jeden Tool-Aufruf im Kontext Ihrer tatsächlichen Anfrage und liefert seine Bewertung ergänzend zu Ihren Policies – niemals anstelle von ihnen. Über **FailproofAI Cloud** kann eine verbundene Maschine Jev mit demselben Schlüssel nutzen, mit dem sie sich bereits verbindet: kein TypeSafe-Konto, kein zweiter Schlüssel, kein zu konfigurierender Endpunkt. Jeder Aufruf wird dem bestehenden Plan-Kontingent Ihrer Organisation belastet. + +Alles, was Jev tut, entspricht unverändert dem [Bring-your-own-key-Setup](/de/policies/jev-byok): Harte Policies bleiben endgültig, das Deny einer prüfbaren Policy wird nur dann aufgehoben, wenn Jev genau zu diesem Aspekt befragt wurde, und jeder Fehler fällt auf das Regex-Ergebnis dieses Aufrufs zurück. + + +Erfordert **failproofai 1.0.8-beta.0** oder höher. 1.0.7 enthält kein Jev – auch wenn diese Version in der Sortierung über den 1.0.7-Betas erscheint. Ohne eine Jev-Konfiguration ändert sich nichts: Hooks führen die Regex-Policies exakt wie bisher aus. + + +## Aktivierung + +1. **Erstellen Sie einen Schlüssel mit Jev.** Öffnen Sie im FailproofAI Cloud-Dashboard **Keys → Create key** und wählen Sie das **machine**-Preset. Es gewährt die drei Berechtigungen, die eine Maschine benötigt: `events:add` (Aktivität senden), `policies:pull` (Policies empfangen) und `jev:evaluate` (Jev, wird dem Plan Ihrer Organisation belastet). Ein Schlüssel kann `jev:evaluate` nicht ohne die anderen beiden Berechtigungen tragen. +2. **Verbinden Sie die Maschine** mit diesem Schlüssel: + + ```bash + failproofai config --token + ``` + + Falls Ihre Organisation eine eigene FailproofAI Cloud betreibt statt der gehosteten Version, fügen Sie deren Adresse hinzu: `--url https://` (oder exportieren Sie `FAILPROOFAI_CLOUD_URL`). Ohne diese Angabe wird der Schlüssel gegen den gehosteten Dienst geprüft, und die Verbindung schlägt fehl. Wenn das Zertifikat dieses Hosts von einer privaten CA stammt, installieren Sie die CA im System-Trust-Store der Maschine (z. B. mit `update-ca-certificates`) und nicht nur in `NODE_EXTRA_CA_CERTS`: Der Daemon, der Events sendet und Policies abruft, liest den System-Store. Siehe [Troubleshooting](/de/reference/troubleshooting). + +Das ist alles. Beim Verbinden wird der Schlüssel gespeichert, und wenn die Maschine **noch keine** Jev-Konfiguration hat, wird Jev über FailproofAI Cloud im **Shadow**-Modus aktiviert: Jev wird zu jedem überwachten Tool-Aufruf befragt und seine Urteile werden aufgezeichnet, aber das Ergebnis Ihrer Policies ist das, was durchgesetzt wird. Die Ausgabe macht das deutlich: + +```text + Jev on through FailproofAI Cloud, in shadow mode: logged, not enforced (~/.failproofai/jev.json). +``` + +**Mit `--no-transcripts` aktiviert das Verbinden Jev nicht.** Jev sendet jeden geprüften Tool-Aufruf und den jüngsten Prompt an FailproofAI Cloud – das ist mehr, als eine reine Verbindung für Entscheidungen senden soll. Der Schlüssel wird trotzdem gespeichert, und die Ausgabe teilt mit, dass Jev verfügbar ist und wie man ihn einschaltet: + +```bash +failproofai jev setup --provider failproofai +``` + +Dies schaltet Jev auch **nicht aus**. Läuft Jev auf der Maschine bereits über FailproofAI Cloud per `jev.json`, bleibt dies unverändert, und die Ausgabe informiert darüber, dass Jev weiterhin jeden geprüften Tool-Aufruf und den jüngsten Prompt sendet – und dass `failproofai jev setup --mode off` es deaktiviert. + + +Beim Verbinden wird eine vorhandene `~/.failproofai/jev.json` **niemals überschrieben**. Wenn Sie bereits Ihren eigenen Jev-Endpunkt verwenden, wird dieser weiterhin genutzt, und die Ausgabe teilt mit, dass die Datei unverändert blieb – und, wenn Jev in dieser Datei deaktiviert ist (abgelehnt oder ausgeschaltet), wird das ebenfalls gemeldet samt Hinweis zur Behebung. Um die Maschine auf FailproofAI Cloud umzustellen, führen Sie `failproofai jev setup --provider failproofai` aus. + + +## Shadow, Enforce oder Off + +Starten Sie im Shadow-Modus, beobachten Sie auf der Policy-Seite, was Jev getan hätte, und lassen Sie ihn dann handeln: + +```bash +failproofai jev setup --mode enforce # Jevs Urteile gelten: Er kann ein prüfbares Deny aufheben und eigene hinzufügen +failproofai jev setup --mode shadow # Jev wird befragt und protokolliert; das Ergebnis Ihrer Policies wird durchgesetzt +failproofai jev setup --mode off # Konfiguration behalten, Jev nicht mehr befragen +``` + +Denselben Schalter gibt es im lokalen Dashboard: **Settings → Jev** hat einen Ein/Aus-Schalter und shadow/enforce. Nur der Modus wird überschrieben, sonst nichts. Hooks lesen die Konfiguration bei jedem Tool-Aufruf, sodass eine Änderung ab dem nächsten Aufruf gilt – ohne Neustart. + +## Überprüfen, was passiert + +```bash +failproofai jev status +failproofai jev test +``` + +`status` zeigt den Provider als **FailproofAI Cloud**, den Cloud-Host, mit dem die Maschine verbunden ist, den Modus und die Schlüsselquelle als **FailproofAI Cloud connection** – niemals den Schlüssel selbst. Wenn eine FailproofAI Cloud `jev.json` vorhanden ist, Jev aber nicht laufen kann, wird der Grund angegeben: + +| `status` zeigt | `status --json` | Bedeutung | +| --- | --- | --- | +| **off — no Jev key is stored for this machine's FailproofAI Cloud connection** | `key-lacks-jev` | Die Maschine ist verbunden, aber kein Jev-Schlüssel ist für sie gespeichert: Der Schlüssel fehlt `jev:evaluate`, oder die Verbindung konnte es nicht bestätigen. Führen Sie `failproofai config --token ` erneut mit demselben Schlüssel aus; falls ihm die Berechtigung fehlt, verwenden Sie einen **machine**-Schlüssel. | +| **off — this machine is not connected to FailproofAI Cloud** | `not-connected` | Auf dieser Maschine besteht keine FailproofAI Cloud-Verbindung, der der Jev-Schlüssel gehören könnte. | + +Nach `failproofai config --disconnect` gibt es keine FailproofAI Cloud `jev.json` mehr (es sei denn, sie war ausgeschaltet, was beibehalten wird), sodass `status` Jev einfach als deaktiviert meldet. `status --json` enthält dieselben Fakten (`provider: "failproofai"`, `keySource: "cloud"`, `cloudConnected`, `keyCarriesJev`), auch wenn die Konfiguration fehlt oder abgelehnt wurde. `permissions` bezieht sich immer auf `jev.json`; eine Ablehnung wegen `credentials.json` fügt `credentialsPermissions` hinzu sowie `fix`, wenn ein einzelner Befehl das Problem löst. `test` sendet eine echte Live-Anfrage und meldet die Latenz sowie die Jev-Version, die geantwortet hat. Es gibt 1 zurück und kennzeichnet das in seinem Titel, wenn die Antwort nach dem Hook-Timeout eintrifft (Hooks würden `timeout` aufzeichnen) oder die Prüffrage falsch beantwortet wird. + +Das **Settings → Jev**-Panel im Dashboard zeigt ebenfalls die **FailproofAI Cloud connection**: welcher Organisation die Maschine zugeordnet ist und ob ihr Schlüssel Jev trägt. Es wird aus den lokalen Dateien der Maschine gelesen, ohne Netzwerkanfrage. + +## Was auf der Policy-Seite ankommt + +Die Maschine sendet ihre Hook-Aktivität bereits an FailproofAI Cloud (`events:add`). Mit aktiviertem Jev enthält der Datensatz jedes überwachten Aufrufs außerdem: welcher Evaluator ausgeführt wurde, was Jev entschied, welche Policies er aufhob, warum er ggf. zurückgefallen ist, seine Latenz und das Modell, das geantwortet hat – Entscheidungen, Codes und Namen, niemals den Befehl oder Ihren Prompt. Auf der **Policies**-Seite Ihrer Organisation: + +- Ein Aufruf, der durch Jevs eigenes Urteil entschieden wurde (Enforce-Modus), wird **Jev** zugeschrieben; wenn die ausschlaggebende Prüfung aus einem Pack stammt, nennt der Datensatz auch dieses Pack und seine Version. +- Im Shadow-Modus erscheint Jevs Deny oder Warning als **would-have** neben den Rollouts, die Sie beobachten. +- Die Policies, die Jev aufgehoben hat oder im Shadow-Modus aufgehoben hätte, werden pro Policy gezählt. + +## Wenn Jev nicht antworten kann + +Jeder der folgenden Fälle fällt auf das Ergebnis Ihrer Policies für diesen Aufruf zurück und wird mit seinem Grund aufgezeichnet: + +| Grund | Ursache | +| --- | --- | +| `out-of-credits` | Ihre Organisation hat ihr Plan-Kontingent aufgebraucht. | +| `http-401`, `http-403` | Der Schlüssel wurde widerrufen oder trägt kein `jev:evaluate`. Verbinden Sie sich mit einem Schlüssel, der es tut. | +| `http-429` | FailproofAI Cloud begrenzt Jev für Ihre Organisation. Bis die geforderte Wartezeit abgelaufen ist (`Retry-After`, maximal 60 Sekunden), sendet die Maschine nichts und jeder Aufruf fällt sofort zurück. So zurückgehaltene Aufrufe werden als `http-429` aufgezeichnet oder als `rate-limited`, wenn das eigene Rate-Limit der Maschine sie zuerst zurückhält. | +| `http-429` (Tageslimit) | Ihre Organisation hat ihr tägliches Jev-Kontingent aufgebraucht: **10.000 pro UTC-Tag**, es sei denn, der Betreiber Ihrer FailproofAI Cloud hat ein anderes Limit festgelegt. Jeder Aufruf fällt zurück, bis der Zähler um 00:00 UTC zurückgesetzt wird; die Maschine fragt höchstens einmal pro Minute erneut an, erkennt also den Reset innerhalb einer Minute. `failproofai jev test` meldet: „Daily Jev limit for this org reached; resets at 00:00 UTC." | +| `http-422` | Jev hat die Anfrage dieses Aufrufs abgelehnt, meist weil der Tool-Aufruf dichten Text (Base64, Hex, minifizierten Code) über Jevs Token-Budget enthielt. Dieser Aufruf fällt jedes Mal zurück; es handelt sich nicht um einen Ausfall. | +| `http-502` | Jev ist momentan nicht verfügbar. | +| `http-503` | Diese Cloud kann Jev für Ihre Organisation nicht bereitstellen: kein Model-Gateway, eine noch nicht provisionierte Organisation oder das Gateway ist ausgefallen. Wenden Sie sich an Ihren Administrator; Hooks fragen höchstens einmal pro Minute erneut an. | +| `http-404` | Diese FailproofAI Cloud stellt Jev noch nicht bereit. | +| `timeout` | Keine Antwort innerhalb von `timeoutMs` (Standard: 3000). | +| `model-mismatch` | Eine andere Jev-Version als 1.13 hat geantwortet. | + +## Wo der Schlüssel gespeichert wird und wohin er geht + +- Der Schlüssel wird einmalig in `~/.failproofai/credentials.json` gespeichert (`0600`, in einem nur für den Eigentümer zugänglichen Verzeichnis), neben den anderen FailproofAI Cloud-Anmeldedaten. `jev.json` enthält für diese Route keinen Schlüssel; ein dort eingetragener Schlüssel macht die Konfiguration ungültig. +- Wenn `credentials.json` für irgendjemanden außer Ihnen **irgendeine** Berechtigung trägt (Gruppe oder andere, Lesen oder Schreiben), oder wenn sein Verzeichnis von irgendjemanden außer Ihnen **beschrieben** werden kann, wird die Datei **abgelehnt**, nicht gelesen, und Jev bleibt deaktiviert, bis Sie das beheben: `chmod 600` auf die Datei, `chmod 700` auf das Verzeichnis (oder erneut verbinden, was die Datei mit `0600` neu schreibt und das Verzeichnis auf den Eigentümer beschränkt). Ein Verzeichnis, das andere nur lesen können, ist in Ordnung; eines, in das andere schreiben können, ermöglicht das Austauschen der Datei. +- Der Schlüssel gilt nur, solange die Verbindung, von der er stammt, auf der Maschine vorhanden ist: eine Policy- oder Reporting-Credential für dieselbe FailproofAI Cloud **mit demselben Schlüssel** in derselben Datei. Ein hinterlassener Jev-Schlüssel ohne eine solche Verbindung wird ignoriert, und Jev bleibt deaktiviert. Das passiert, wenn `config --disconnect` einer älteren failproofai-Version den Jev-Schlüssel stehen lässt (sie weiß nicht, dass er entfernt werden muss), oder wenn `config --token` einer älteren failproofai-Version mit einem anderen Schlüssel verbindet, der auf FailproofAI Cloud zu einer anderen Organisation gehören kann. Um Jev wieder einzuschalten, verbinden Sie sich erneut mit einem **machine**-Schlüssel. +- Der Schlüssel wird ausschließlich an den Cloud-Ursprung gesendet, gegen den er verifiziert wurde. Eine `jev.json`, die auf einen anderen Ort verweist, wird abgelehnt. +- **Ein Agent auf der Maschine kann sie lesen.** `credentials.json` ist nur für den Eigentümer zugänglich, und der Agent läuft als dieser Eigentümer. Das Lesen von failproofais eigenen Dateien ist bewusst erlaubt (nur das Ändern ist blockiert, durch `block-failproofai-commands`); das Einzige, was zwischen einem Agent und dieser Datei steht, ist `block-read-outside-cwd` – eine *prüfbare* Policy – und von einer Sitzung, die im Home-Verzeichnis gestartet wurde, nichts. Ein Schlüssel mit `jev:evaluate` verbraucht das Jev-Kontingent Ihrer Organisation (bis zur Tagesobergrenze) von überall, wo er verwendet wird. Behandeln Sie einen Machine-Schlüssel daher wie jede andere Spending-Credential: Wenn ein Agent ihn möglicherweise gelesen hat, deaktivieren Sie ihn auf der Keys-Seite und verbinden Sie sich mit einem neuen. +- Nur Ihre globalen Dateien entscheiden das. Ein Repository kann Cloud-Jev nicht einschalten, auf einen anderen Ort verweisen oder seinen Schlüssel bereitstellen, und `FAILPROOFAI_JEV_API_KEY` wird für diese Route ignoriert. +- Für jeden von Jev bewerteten Aufruf geht eine Anfrage an FailproofAI Cloud, die das enthält, was die [Bring-your-own-key-Seite](/de/policies/jev-byok#what-leaves-the-machine) auflistet (Secrets werden geschwärzt). FailproofAI Cloud leitet es an TypeSafe weiter und protokolliert oder speichert es nicht. + +## Deaktivierung + +| Befehl | Ergebnis | +| --- | --- | +| `failproofai jev setup --mode off` | Konfiguration behalten; Jev wird nicht befragt. **Dies ist der dauerhaft wirksame Schalter:** Erneutes Verbinden überschreibt eine vorhandene `jev.json` nie, sodass Jev deaktiviert bleibt, bis Sie es mit `--mode shadow` wieder einschalten. | +| `failproofai jev remove` | `~/.failproofai/jev.json` löschen; Jev ist deaktiviert – bis zum nächsten `failproofai config --token` mit einem Schlüssel, der `jev:evaluate` trägt. Dieser findet keine `jev.json` und aktiviert Jev erneut im Shadow-Modus (es sei denn, er wird mit `--no-transcripts` ausgeführt). Um es deaktiviert zu lassen, verwenden Sie `--mode off`. | +| `failproofai config --disconnect` | Verbindung der Maschine trennen: Der Schlüssel wird entfernt, ebenso `jev.json`, wenn sie FailproofAI Cloud benennt und nicht ausgeschaltet ist. Eine `jev.json` für Ihren eigenen Endpunkt bleibt bestehen, ebenso eine ausgeschaltete – sodass Jev deaktiviert bleibt, wenn Sie sich erneut verbinden. | + +Ab dem nächsten Tool-Aufruf führen Hooks die Regex-Policies exakt wie zuvor aus. \ No newline at end of file diff --git a/docs/de/policies/jev.mdx b/docs/de/policies/jev.mdx new file mode 100644 index 000000000..46e43a18c --- /dev/null +++ b/docs/de/policies/jev.mdx @@ -0,0 +1,45 @@ +--- +title: "Jev-Richtlinien" +description: "Füge Jevs Live-Review zu überwachten Tool-Aufrufen hinzu und prüfe sie, bevor ihre Entscheidungen durchgesetzt werden." +icon: "shield-check" +--- + +Jev liest einen Tool-Aufruf im Kontext dessen, was die Person den Agenten zu tun gebeten hat. Verwende es, wenn eine string-basierte Richtlinie gültige Aktionen blockiert oder eine riskante Aktion übersieht, die Kontext benötigt. Es antwortet zusammen mit deinen Richtlinien am `PreToolUse`- oder `PermissionRequest`-Gate. Für eine Bewertung **nach** Ende einer Sitzung verwende [Jev-Evaluierungen](/de/evaluations/jev). + +## Im Beobachtungsmodus starten + +Installiere Failproof AI und hänge Hooks an ein [unterstütztes Harness](/de/reference/harnesses) an. Verwende failproofai 1.0.8-beta.0 oder höher. + +Failproof AI enthält keine Jev-Prüfungen. Installiere sie als Pack, andernfalls hat Jev nichts zu prüfen und wird nie aufgerufen: + +```bash +failproofai policies add FailproofAI/jev-policies +``` + +Wähle dann, wie Anfragen Jev erreichen: + +| Route | Erster Schritt | +| --- | --- | +| FailproofAI Cloud | Verbinde dich mit einem **Machine**-Schlüssel, der `jev:evaluate` trägt. Auf einer Maschine ohne Jev-Konfiguration aktiviert `failproofai config` Jev im Beobachtungsmodus. | +| Eigener Anbieter | Öffne im lokalen Dashboard **Einstellungen → Jev**, wähle den Anbieter, füge dessen Token ein und wähle **observe**. Oder führe aus: `failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key`. | + +![Die Jev-Einstellungen des lokalen Dashboards: Anbieter, Endpunkt, Token und Beobachtungsmodus, bevor Jev aktiviert wird.](/images/dashboard/jev-settings.png) + +```bash +failproofai jev status +failproofai jev test +``` + +`test` prüft den Endpunkt. Um den Hook-Pfad zu überprüfen, bitte einen angebundenen Agenten, sein Datei-Lese-Tool auf `README.md` anzuwenden. Bestätige, dass dieser Tool-Aufruf in der Sitzung erscheint, und prüfe dann **Richtlinien → Aktivität** im [lokalen Dashboard](/de/reference/local-dashboard#review-policy-activity). Der Jev-Zähler in `status` sollte steigen. Der Beobachtungsmodus zeichnet auf, was Jev entschieden hätte, während dein bestehendes Richtlinienergebnis weiterhin gilt. + +## Entscheiden, wann durchgesetzt werden soll + +Eine **harte** Richtlinie hat immer das letzte Wort. Jev darf ein Deny nur von einer Richtlinie aufheben, die explizit als **reviewable** markiert ist, und nur wenn es das benannte Anliegen dieser Richtlinie geprüft hat. Lies [Richtlinien-Autorität](/de/policies/authority), bevor du dich auf eine Freigabe verlässt. Jev kann auch eigenständig warnen oder ablehnen. Wenn es keine Antwort geben kann, entscheidet das Richtlinienergebnis über diesen Aufruf. + +Sobald die Beobachtungsergebnisse korrekt aussehen, wechsle in **Einstellungen → Jev** in den Durchsetzungsmodus oder führe aus: + +```bash +failproofai jev setup --mode enforce +``` + +Informationen zu Anbieter-URLs, Cloud-Schlüsseln, Konfiguration, Fallbacks und den mit jeder Anfrage gesendeten Daten findest du in der [Jev-Integrationsreferenz](/de/reference/jev). \ No newline at end of file diff --git a/docs/de/reference/custom-agents-typescript.mdx b/docs/de/reference/custom-agents-typescript.mdx new file mode 100644 index 000000000..62de5ef7d --- /dev/null +++ b/docs/de/reference/custom-agents-typescript.mdx @@ -0,0 +1,401 @@ +--- +title: "Eigene Agenten (TypeScript)" +description: "Konfiguration, der Event-Katalog, die Scopes und die Framework-Adapter für @failproofai/sdk." +icon: "square-js" +--- + +Was jede Einstellung, Methode und jedes Feld im TypeScript SDK bewirkt. Wenn du zum ersten Mal instrumentierst, beginne mit der Anleitung – diese Seite dient zum Nachschlagen. + + + + Installation, Instrumentierung, die Event-Methoden, ein durchgearbeitetes Beispiel und häufige Probleme. + + + Dieselben Events, dasselbe Wire-Format, derselbe Spool – aus Python heraus. + + + +Node 20.9 oder neuer. ESM und CommonJS. Keine Laufzeit-Abhängigkeiten. + + + Dieses SDK und das Python-SDK schreiben **dieselben Events in denselben Spool**. Eine Flotte mit Node-Agenten und Python-Agenten erzeugt einen einzigen Satz von Sessions, nicht zwei, und nichts im Dashboard unterscheidet sie. Entscheide pro Service, nicht pro Unternehmen. + + +## Installation + +```bash +npm install @failproofai/sdk +``` + +```ts +import * as failproofai from "@failproofai/sdk"; + +await failproofai.agent("planner", { goal: question }, async () => { + const hits = await failproofai.toolCall("web_search", { input: { q } }, () => search(q)); +}); +``` + +Die Framework-Adapter sind im Paket selbst enthalten. Die Frameworks sind **optionale Peer-Abhängigkeiten** – so deklariert, dass die unterstützten Versionsbereiche sichtbar sind, niemals in deinem Namen installiert und nur importiert, wenn du `instrument()` aufrufst. + +## Verbindung zum Failproof-Daemon + +Identisch mit dem Python SDK: Erstelle einen `events:add`-Schlüssel unter **Admin → Keys**, dann [verbinde den Daemon](/de/start/setup#connect-a-machine-to-cloud) auf dem Agenten-Rechner. Das SDK schreibt auf die Festplatte; der Daemon versendet. + +## Konfiguration + +```ts +failproofai.configure({ + environment: "production", + flushInterval: 0.5, + baseDir: undefined, +}); +``` + +| Option | Beschreibung | +| --- | --- | +| `environment` | Die Bezeichnung für jedes Event – `production`, `staging`, `prod-eu`. Standard: `dev`. | +| `flushInterval` | Wie oft der Timer auf die Festplatte schreibt, in Sekunden. Standard: `0.5`. | +| `baseDir` | Wohin geschrieben wird. Standardmäßig der Spool des Daemons, was in der Regel das Richtige ist. | + +Nichts wird angewendet, solange nicht alles validiert ist. Ein abgelehnter Aufruf lässt das SDK genau so zurück, wie es war – nicht mit einem neuen `baseDir` und dem alten Intervall. + +Alternativ per Umgebungsvariable setzen: + +| Variable | Beschreibung | +| --- | --- | +| `AGENTEYE_ENVIRONMENT` | Setzt `environment` ohne Code-Änderung. Eine `configure()`-Option hat Vorrang. | +| `FAILPROOFAI_HOME` | Verschiebt das Failproof AI-Stammverzeichnis, das den Spool enthält. | +| `FAILPROOFAI_SDK_LOG_LEVEL` | `debug`, `info`, `warn` (Standard), `error`, `silent`. | +| `FAILPROOFAI_SDK_STRICT` | `1` lässt Instrumentierungsfehler werfen, anstatt sie zu protokollieren. | +| `FAILPROOFAI_SDK_STRICT_INTEGRATIONS` | `1` lässt ein Framework-Kompatibilitätsproblem werfen, anstatt zu warnen und fortzufahren. | + + + **Kein Komma in `environment`.** Die Aufnahme teilt dieses Feld an Kommas auf, um Filter zu erstellen, und überspringt jeden Event, dessen Bezeichnung eines enthält – dadurch verschwindet ein ganzer Durchlauf stillschweigend. Schreibe `prod-eu`, nicht `prod,eu`. + + `configure({ environment: "prod,eu" })` wirft eine Exception, damit du es sofort bemerkst. `AGENTEYE_ENVIRONMENT` kann nicht werfen – niemand ruft dich zurück – daher wird einmalig gewarnt und auf `dev` zurückgefallen. + + +Leite die eigenen Log-Zeilen des SDK mit `failproofai.setLogger({ debug, info, warn, error })` in deinen Logger um. + +## Herunterfahren + +Gepufferte Events werden beim `process.on("exit")` geleert. + +Ein durch ein Signal beendeter Prozess erreicht diesen Punkt nie, und Node's Standard für `SIGTERM` ist, ohne Ausführung von Exit-Handlern zu beenden – ein containerisierter Agent verliert also alles, was das letzte Intervall noch nicht geschrieben hatte. + + + **Dieses SDK installiert keinen Signal-Handler für dich.** Das Registrieren eines Handlers ändert das Verhalten deines Prozesses: Ein Listener unterdrückt Node's Standard-Beendigung, sodass eine Bibliothek, die einen hinzufügt, Ctrl-C stillschweigend außer Kraft setzen würde. Füge deinen eigenen hinzu: + + ```ts + for (const signal of ["SIGINT", "SIGTERM"] as const) { + process.once(signal, () => { + failproofai.flushSync(); + process.exit(0); + }); + } + ``` + + +Ein kurzlebiges Skript oder ein Serverless-Handler sollte `await failproofai.flush()` vor der Rückgabe aufrufen – das Intervall allein garantiert keine Zustellung. + +## Identität + +Jedes Event gehört zu einer Session und einem Agenten. **Die Scopes füllen beides aus**, sodass du sie selten übergeben musst: + +```ts +await failproofai.session(async () => { + await failproofai.agent("planner", async () => { + failproofai.event.toolUse({ toolName: "search", toolCallId: "c1" }); + }); +}); +``` + +`sessionId` oder `agentId` explizit zu übergeben funktioniert weiterhin und hat Vorrang. Wenn weder ein Scope gebunden noch ein Wert übergeben wird, wirft der Aufruf eine Exception, anstatt ein Event zu emittieren, das Cloud stillschweigend verwerfen würde. + + + Identität wird über `AsyncLocalStorage` weitergegeben. Sie folgt `await`, `.then()`, Timern und jedem Callback, der innerhalb des Scopes erstellt wird. Sie folgt **nicht** einem Callback, der während eines Durchlaufs gespeichert und während eines anderen aufgerufen wird, oder Arbeit, die über eine `worker_threads`-Grenze übergeben wird – wickle diese in `failproofai.propagate()` ein, sonst landen ihre Events ohne Zuordnung. + + +### Scopes + +| Scope | Emittiert | Gibt zurück | +| --- | --- | --- | +| `session(body)` | nichts – nur Identität | was `body` zurückgibt | +| `agent(id, options?, body)` | `agent_start`, dann `agent_end` | was `body` zurückgibt | +| `toolCall(name, options?, body)` | `tool_use`, dann `tool_result` | was `body` zurückgibt | + +Ein synchroner Body bleibt synchron: `agent("x", () => 1)` gibt `1` zurück, kein Promise. + +`toolCall` zeichnet den aufgelösten Wert des Bodys als `output` des Tools auf, es sei denn, du weist `call.output` selbst zu. + + + +| Was passiert ist | Events | `outcome` | +| --- | --- | --- | +| Der Block hat zurückgegeben | `agent_end` | `"success"`, oder dein `outcome` | +| Der Block hat geworfen | `error`, dann `agent_end` | `"failed"` | +| Ein `AbortError` | nur `agent_end` | `"cancelled"` | + +Der Fehler wird immer erneut geworfen. + +Ein Tool-Fehler wird auf dem Blatt aufgezeichnet – `tool_result` mit einem `error`-String – und emittiert **kein** `error`-Event auf Durchlauf-Ebene. Einer, den die Agenten-Schleife abfängt, ist kein Durchlauffehler; einer, der sich weiterpropagiert, wird genau einmal gemeldet, vom umschließenden `agent()`. + + + + + +Wenn die Arbeit keine einzelne Funktion ist – ein Scope, der in einem Konstruktor geöffnet und in einem Teardown geschlossen wird, oder einer, der bestehenden Kontrollfluss überspannt: + +```ts +{ + using span = failproofai.agent.open("planner", { goal }); + using call = failproofai.toolCall.open("search", { input: { q } }); + call.call.output = await search(q); +} // tool_result, dann agent_end +``` + +Beide Formen emittieren byte-identische Events. Bevorzuge die Callback-Form: Sie läuft innerhalb von `AsyncLocalStorage.run()`, sodass es nichts abzuwickeln gibt und die gesamte Klasse von „hier geöffnet, dort geschlossen"-Fehlern nicht erreichbar ist. + +Ein `using`-Block, der seinen eigenen Fehler abfängt, meldet ihn mit `span.fail(error)` – der Disposer hat keinen eigenen Exception-Kanal. + + + +## Event-Katalog + +Dieselben fünfzehn Methoden wie das Python SDK, in camelCase. Die meisten kommen in **Paaren** – du rufst den Öffner auf, dann den Schließer, und das SDK misst die Zeitspanne dazwischen. + +| | Öffnet | Schließt | +| --- | --- | --- | +| **Agenten** | `agentStart` | `agentEnd` | +| | `agentPause` | `agentResume` | +| **Modelle** | `modelRequest` | `modelResponse` | +| **Tools** | `toolUse` | `toolResult` | +| **Hooks** | `hookTriggered` | `hookCompleted` | +| **Menschen** | `humanWait` | `humanInput` | + +Drei stehen allein: `error`, `humanPause`, `humanInterrupt`. + + + +Jede Methode akzeptiert auch `sessionId` und `agentId`, die die Scopes für dich ausfüllen. Alles Weggelassene wird weggelassen, anstatt als JSON `null` gesendet zu werden. + +| Methode | Erforderlich | Optional | +| --- | --- | --- | +| `agentStart` | — | `goal`, `parentId` | +| `agentEnd` | — | `outcome`, `summary` | +| `agentPause` | `pauseId` | `reason`, `userId` | +| `agentResume` | `pauseId` | `reason`, `userId` | +| `modelRequest` | — | `model`, `messages`, `system`, `tools`, `requestId` | +| `modelResponse` | — | `model`, `stopReason`, `inputTokens`, `outputTokens`, `content`, `role`, `requestId` | +| `toolUse` | `toolName`, `toolCallId` | `input` | +| `toolResult` | `toolName`, `toolCallId` | `output`, `error` | +| `hookTriggered` | `hookName`, `hookId` | `triggerEvent`, `input` | +| `hookCompleted` | `hookName`, `hookId` | `outcome`, `output`, `error` | +| `error` | `errorType`, `message` | `traceback` | +| `humanWait` | `inputId` | `prompt`, `options`, `reason` | +| `humanInput` | `inputId` | `response` | +| `humanPause` | — | `reason`, `userId` | +| `humanInterrupt` | — | `reason`, `userId`, `atStep` | + +Jeder weitere Schlüssel, den du hinzufügst, wird zu einem benutzerdefinierten Payload-Feld. Verwende den Präfix `fw_*` für Framework-spezifische Inhalte; ein Name, der mit einem deklarierten Feld kollidiert, wird abgelehnt, anstatt stillschweigend eine hochgestufte Spalte zu überschreiben. + + + + + **`duration_ms` wird berechnet, nicht akzeptiert.** Die vier schließenden Methoden messen die Zeitspanne seit ihrem Öffner und lehnen ein vom Aufrufer übergebenes `duration_ms` ab – eine gemeldete Dauer soll nicht fälschbar sein. + + Paare werden anhand der **Session** und der ID abgeglichen, niemals anhand des Agenten. Ein Tool, das unter `planner` geöffnet und unter `worker` geschlossen wird, bildet trotzdem ein Paar – genau das, was verschachtelte Multi-Agenten-Durchläufe tatsächlich tun. + + +## Framework-Adapter + +```ts +await failproofai.instrument(); // was auch immer gefunden wird +await failproofai.instrument("langchain"); // genau eines +failproofai.uninstrument(); // alles zurücksetzen +``` + +| Framework | Unterstützt | Wie es eingehängt wird | +| --- | --- | --- | +| **LangChain.js / LangGraph.js** | `@langchain/core` 0.3 – 1.x, LangGraph.js 0.4 – 1.x | `CallbackManager.configure`, sodass jeder `invoke`/`stream`/`batch` abgedeckt ist, ohne `callbacks:` irgendwo zu übergeben – oder übergib `langchainHandler()` selbst und patche nichts. | +| **Vercel AI SDK** | `ai` 4 – 7 | `telemetry()` an der Aufrufstelle, oder `instrument("ai")` für den gesamten Prozess bei `ai` 7 (bei 4–6 ist das opt-in – siehe unten). | +| **Mastra** | `@mastra/core` 0.20 – 1.x | `Agent.generate`/`.stream`, das Modell und die Tool-Auflösung des Agenten sowie die Workflow-Ausführungs-/Schritt-Engine. | +| **LlamaIndex.TS** | `llamaindex` 0.11.4 – 0.x | `Settings.callbackManager` (abonniert) plus `AgentWorkflow.runStream`, für Workflow-Ausführungen und deren Schritte. | + +Jeder Versionsbereich wird bei jedem CI-Durchlauf gegen echte Framework-Releases – an beiden Enden, als ES-Modul und als CommonJS – getestet. + +Die Zuordnung entspricht der des Python SDK, sodass dasselbe Programm in beiden Sprachen denselben Baum zeichnet. Ein Konstrukt ist nur dann ein **Agent**, wenn er eine eigene LLM-Entscheidungsschleife besitzt – ein Graph- oder Chain-Durchlauf, ein AI SDK `generateText`/`streamText`-Aufruf, ein Mastra-Agent, ein LlamaIndex-Agenten-Durchlauf. Ein LangGraph-Knoten oder ein Workflow-Schritt ist ein **Hook** (`hook_triggered`/`hook_completed`), niemals ein verschachtelter Agent. Modellaufrufe sind `model_request`/`model_response`-Paare mit Token-Zählungen; Tool-Aufrufe tragen die eigene Tool-Call-ID des Modells. Ein Fehler wird einmal aufgezeichnet, bei dem Event, in dem er aufgetreten ist. + +Ein Adapter, der sich nicht installieren lässt, wird protokolliert und übersprungen; die anderen werden trotzdem installiert, denn ein defektes LlamaIndex darf dich LangGraph nicht kosten. + + + `instrument()` ohne Argument erkennt ein Framework daran, ob es sich **auflösen** lässt, nicht daran, ob es bereits importiert ist – Node bietet kein Äquivalent zu Python's `sys.modules` für ES-Module. Ein Framework, das du installiert, aber nicht verwendest, wird importiert und gepatcht. Gib das gewünschte Framework namentlich an, wenn das wichtig ist. + + + + Die meisten dieser Frameworks liefern einen ES-Modul-Build und einen CommonJS-Build, die Node als zwei unabhängige Kopien lädt. Die Adapter patchen die Kopie, die deine Anwendung lädt (und die CommonJS-Kopie ebenfalls, falls etwas sie bereits mit `require` geladen hat), sodass beide Modulsysteme funktionieren. Ein Framework, das durch esbuild oder webpack **in deine eigene Ausgabe gebündelt** wurde, ist nicht erreichbar – verwende dort die Aufrufstellen-Hilfsfunktionen: `langchainHandler()`, `telemetry()`, `wrapTool()`. + + +### LangChain ohne Patching + +```ts +import { langchainHandler } from "@failproofai/sdk/langchain"; +await graph.invoke(input, { callbacks: [langchainHandler()] }); +``` + +Der Handler funktioniert mit oder ohne `instrument()` und zeichnet nichts doppelt auf. `instrument("langchain")` akzeptiert `sessionId`, `captureContent`, `includeChains`, `graphCallbacks` und `captureLimit`, wie der Python-Adapter; `metadata: { failproofai_sdk_session_id }` bei einem Aufruf wählt die Session für diesen Aufruf aus. + +### Vercel AI SDK + +Das AI SDK exportiert einfache Funktionen aus einem ES-Modul, und ein ES-Modul-Namespace ist laut Spezifikation unveränderlich – es gibt nichts zu patchen. Es nutzt die Extension Points, die das SDK selbst dokumentiert: + +```ts +import { telemetry } from "@failproofai/sdk/ai"; + +const { text } = await generateText({ + model, + prompt, + experimental_telemetry: telemetry({ functionId: "answer-question" }), + // bei ai 7: `telemetry: telemetry({ … })` — dasselbe Objekt, neuer Name +}); +``` + +Das ist die vollständige Integration: ein Agent-Span, ein Modell-Request/Response-Paar pro Schritt mit Token-Zählungen und jeder Tool-Aufruf. Eine Aufrufstelle funktioniert für jede Major-Version – `ai` 4–6 lesen den mitgegebenen Tracer, `ai` 7 die Telemetrie-Integration. + +`instrument("ai")` macht dasselbe prozessweit **auf `ai` 7**: jeder Aufruf, über die globale Telemetrie-Integrationsliste des AI SDK, die additiv ist und niemandem sonst etwas wegnimmt. + +**Auf `ai` 4–6 zeichnet `instrument("ai")` von sich aus nichts auf und gibt einmalig eine entsprechende Warnung aus.** Der einzige prozessweite Hook, den diese Major-Versionen haben, ist der globale OpenTelemetry-Tracer-Provider – ein einzelner Slot, den OpenTelemetry nicht mehr herausgibt, sobald er belegt ist. Unseren zu registrieren würde dein späteres `NodeSDK.start()` beim Start stillschweigend ablehnen und deine HTTP/Datenbank-Spans an einen Tracer senden, der nichts exportiert. Verwende `telemetry()` an der Aufrufstelle oder dort `wrapModel`. Wenn der Prozess kein eigenes OpenTelemetry betreibt, aktiviere mit `instrument("ai", { registerGlobalTracer: true })`: Es zeichnet dann jeden Aufruf auf, der `experimental_telemetry: { isEnabled: true }` übergibt, und belegt den Slot nur, wenn er noch frei ist. `registerGlobalTracer: false` behält die Standardeinstellung bei und unterdrückt die Warnung. + +Wenn du das Modell lieber einmalig einwickeln möchtest: `wrapModel` sieht nur Modellaufrufe, da Tool-Aufrufe oberhalb der Modellschicht stattfinden. Ein gewrapptes Modell, das ohne umgebenden Kontext aufgerufen wird, wird als eigener Durchlauf aufgezeichnet. Ein gestreamter Aufruf schließt, sobald der Stream endet – `stop_reason: "cancelled"` wenn der Verbraucher abbricht, `"error"` mit dem Fehler, wenn er mittendrin fehlschlägt: + +```ts +import { wrapModel } from "@failproofai/sdk/ai"; +const model = await wrapModel(openai("gpt-4o")); +``` + +Beides zusammen zu verwenden ist in Ordnung: Die Middleware erkennt, dass der Aufruf bereits aufgezeichnet wird, und gibt den Vortritt, sodass jeder Aufruf einmal aufgezeichnet wird. + +`functionId` benennt den Agent-Span. Halte ihn niedrig-kardinal – er landet in `agent_id`, der primären Dashboard-Facette. + +### Next.js + +`next build` bündelt die Abhängigkeiten deines Servers standardmäßig, und ein in den Build gebündeltes Framework ist eine Kopie, die `instrument()` nicht erreichen kann. Wickle die Konfiguration einmalig ein und rufe `instrument()` aus Next's Startup-Hook auf: + +```ts +// next.config.ts +import { withFailproofai } from "@failproofai/sdk/next"; +export default withFailproofai({ /* deine Konfiguration */ }); +``` + +```ts +// instrumentation.ts +export async function register() { + if (process.env.NEXT_RUNTIME !== "nodejs") return; + const failproofai = await import("@failproofai/sdk"); + await failproofai.instrument(); +} +``` + +`withFailproofai` fügt LangChain, Mastra, LlamaIndex und das SDK selbst zu `serverExternalPackages` hinzu und erhält dabei deine eigene Liste. Ohne dies warnt `instrument()` einmalig pro Framework, das es nicht erreichen kann, anstatt stillschweigend zu versagen; wenn du die Pakete selbst auflistest, setze `FAILPROOFAI_NEXT_EXTERNALS=1`. Das Vercel AI SDK und die Aufrufstellen-Hilfsfunktionen funktionieren in beiden Fällen. Eine Edge-Route erhält einen No-Op-Build: Das Importieren des SDK ist sicher und zeichnet nichts auf. + +### Token-Zählungen bei gestreamten Aufrufen + +OpenAI-kompatible APIs melden die Nutzung bei einem Stream nur, wenn der Client danach fragt. LangChain und das Vercel AI SDK fragen; für LlamaIndex übergib `additionalChatOptions: { stream_options: { include_usage: true } }` an dessen `OpenAI`-LLM, und für Mastra baue das Modell mit aktivierter Nutzungserfassung (zum Beispiel `createOpenAICompatible({ includeUsage: true })`). Andernfalls enthalten gestreamte Modellaufrufe keine Token-Zählungen. + +### Laufzeitumgebungen + +Node ≥ 20.9, Bun und Deno – jedes Framework, als ES-Modul und als CommonJS, wird bei jedem CI-Durchlauf gegen Node's Trace getestet. Das SDK läuft neben dem `failproofaid`-Daemon, der das Geschriebene versendet. + +## Eigener Agent – kein Framework + +Für eine selbst geschriebene Agenten-Schleife oder ein Framework ohne Adapter. Du emittierst die Events mit derselben API, die die Adapter intern verwenden, sodass der Trace dieselbe Form und Qualität hat. + +Du musst nicht wissen, wie der Agent aufgebaut ist. Jeder handgefertigte Agent hat bereits drei Stellen, egal wie seine Funktionen heißen, und diese drei sind die gesamte Integration: + +| Wo | Was hinzuzufügen ist | Emittiert | +| --- | --- | --- | +| Wo **ein Durchlauf** beginnt und endet | `failproofai.agent("name", { goal }, async () => …)` | `agent_start` / `agent_end` | +| Die **eine Funktion, die das Modell aufruft** | `event.modelRequest` vorher, `event.modelResponse` nachher – beide Hälften, auch bei Fehler | ein Paar pro Modell-Runde | +| Die **eine Funktion, die Tools ausführt** | `failproofai.toolCall(name, { toolCallId, input }, () => run())` | `tool_use` / `tool_result` | + +```ts +async function callModel(messages) { + const requestId = randomUUID(); + const started = Date.now(); + failproofai.event.modelRequest({ model: MODEL, requestId, messages }); + try { + const reply = await client.chat.completions.create({ model: MODEL, messages, tools }); + failproofai.event.modelResponse({ + model: reply.model, requestId, stopReason: reply.choices[0].finish_reason, + inputTokens: reply.usage?.prompt_tokens, outputTokens: reply.usage?.completion_tokens, + duration_ms: Date.now() - started, + }); + return reply.choices[0].message; + } catch (error) { + failproofai.event.modelResponse({ model: MODEL, requestId, stopReason: "error", + error: String(error), duration_ms: Date.now() - started }); + throw error; + } +} + +async function dispatch(call) { + const input = JSON.parse(call.function.arguments); + return failproofai.toolCall(call.function.name, { toolCallId: call.id, input }, + () => runTool(call.function.name, input)); +} + +await failproofai.agent("inventory", { goal: question }, async () => { + for (;;) { + const message = await callModel(messages); + if (!message.tool_calls?.length) return message.content; + for (const call of message.tool_calls) await dispatch(call); + } +}); +``` + +Identität ist ambient: Alles innerhalb von `agent()` landet in der Session dieses Durchlaufs, ohne eine ID zu übergeben, und nichts anderes im Programm ändert sich – einschließlich allem, was der Agent bereits in seine eigene Datenbank schreibt. + +- **Ein Service oder ein Worker:** Übergib deine eigene Request- oder Job-ID als `sessionId`, damit eine Session im Dashboard und der Eintrag in deinen eigenen Logs oder der Datenbank dieselbe Zeichenkette sind. +- **Sub-Agenten:** Verschachtle `agent()`-Aufrufe. Der innere tritt der Session des äußeren mit dessen `parent_id` bei. +- **Emittiere die Paare.** Ein `modelRequest` ohne `modelResponse` ist ein Span, den das Dashboard als ewig laufend anzeigt – daher das `catch`. + +[`sdk/typescript/examples/research-agent.ts`](https://github.com/FailproofAI/failproofai/blob/main/sdk/typescript/examples/research-agent.ts) im Repository ist die vollständige, ausführbare Version: eine echte OpenAI-Tool-Schleife, genau so instrumentiert, bei jedem Commit im CI als ES-Modul und als CommonJS ausgeführt. + +## Evaluierungen + +```ts +import { Evaluator, EvalResult, Score } from "@failproofai/sdk/evaluator"; + +export const app = new Evaluator({ name: "my-evals", version: "1" }); + +app.eval("tool_success_rate", { version: "1" }, (session) => { + const results = session.eventsOfType("tool_result"); + const failures = results.filter((event) => event.payload.error != null).length; + return new EvalResult({ + score: new Score(results.length === 0 ? 1 : 1 - failures / results.length), + reasoning: `${failures} of ${results.length} tool calls failed`, + }); +}); +``` + +```bash +FAILPROOFAI_EVALUATOR_URL=… FAILPROOFAI_EVALUATOR_TOKEN=… \ + npx failproofai-evaluator ./my-evals.js +``` + +Siehe die [Evaluator SDK-Referenz](/de/reference/evaluator-sdk) für das Protokoll, die Worker-Einstellungen und die Ergebnistypen. + + + **Eine Evaluierung muss yielden.** Eine synchrone Funktion, die niemals zurückkehrt, blockiert den einzigen Thread, den Node hat, und kein Timeout kann feuern, solange das so ist. Schreibe `async`-Evaluierungen. + + +## Was es mit deinem Prozess nicht tut + +| | | +| --- | --- | +| **Deine Agenten-Schleife blockieren** | Events gehen in eine In-Memory-Warteschlange; ein Timer schreibt sie. Der Timer ist `unref`'d, sodass das Importieren dieses Pakets ein Skript nie am Beenden hindert. | +| **Unbegrenzt wachsen** | Die Warteschlange ist durch Anzahl *und* gemessene Bytes begrenzt. Wird einer der Grenzwerte überschritten, werden die ältesten Events verworfen und eine Warnung ausgegeben – ein Telemetrie-Ausfall darf kein OOM-Kill werden. | +| **Den Prozess zum Absturz bringen** | Ein nicht kodierbares Event wird allein verworfen, nicht der umgebende Batch. Ein werfender Getter, eine zirkuläre Referenz, ein `BigInt`, ein einzelnes Surrogate: jedes wird behandelt, anstatt weitergegeben zu werden. | +| **Einen halb geschriebenen Batch hinterlassen** | Der Inhalt wird mit `fsync` gesichert, bevor eine atomare Umbenennung erfolgt, das Verzeichnis danach, und ein fehlgeschlagener Schreibvorgang räumt seine temporäre Datei auf. | +| **Transkripte lesbar hinterlassen** | Batches sind `0600` innerhalb eines `0700`-Verzeichnisses. Sie enthalten Ziele, Prompts, Tool-Argumente und Tool-Ausgaben. | +| **Zugangsdaten versenden** | API-Schlüssel, Tokens, JWTs, Bearer-Header und geheimnis-förmige Zuweisungen werden redigiert, bevor die Bytes die Festplatte erreichen. Der Daemon redigiert erneut vor dem Upload. | \ No newline at end of file diff --git a/docs/de/reference/jev-cloud.mdx b/docs/de/reference/jev-cloud.mdx new file mode 100644 index 000000000..007bea811 --- /dev/null +++ b/docs/de/reference/jev-cloud.mdx @@ -0,0 +1,136 @@ +--- +title: "Jev über FailproofAI Cloud" +description: "Cloud-Machine-Keys, Verbindungsstatus, Limits und Fehlerverhalten für die Live-Jev-Richtlinienprüfung." +icon: "cloud" +--- + +Dies ist die Cloud-Routen-Referenz für [Jev-Richtlinien](/de/policies/jev). Jev, der Klassifikator von TypeSafe, liest jeden Tool-Aufruf im Abgleich mit dem, was du tatsächlich angefordert hast, und gibt seine Einschätzung neben deinen Richtlinien aus – niemals anstelle davon. Über **FailproofAI Cloud** verwendet eine verbundene Maschine Jev mit demselben Key, mit dem sie sich bereits verbindet: kein TypeSafe-Account, kein zweiter Key, kein zu konfigurierender Endpoint. Jeder Aufruf wird dem bestehenden Plan-Kontingent deiner Organisation belastet. + +Alles, was Jev tut, ist unverändert gegenüber dem [Bring-Your-Own-Key-Setup](/de/reference/jev-providers): Harte Richtlinien bleiben endgültig, das Deny einer überprüfbaren Richtlinie wird nur dann aufgehoben, wenn Jev genau zu diesem Anliegen befragt wurde, und jeder Fehler fällt für diesen Aufruf auf das Regex-Ergebnis zurück. + + +Erfordert **failproofai 1.0.8-beta.0** oder höher. 1.0.7 hat kein Jev, auch wenn es in der Sortierung über den 1.0.7-Betas erscheint. Ohne eine Jev-Konfiguration ändert sich nichts: Hooks führen die Regex-Richtlinien genau wie bisher aus. + + +## Voraussetzungen + +Installiere Failproof AI auf der Maschine, auf der dein Agent läuft, und verbinde deren Hooks mit einem [unterstützten Harness](/de/reference/harnesses). Wenn du von Grund auf neu beginnst, folge der [Schnellstartanleitung](/de/start/quickstart) bis zur Hook-Installation. Prüfe die installierte CLI mit `failproofai --version`; aktualisiere sie, wenn sie älter als Jev ist. Du benötigst außerdem Zugang zur Seite **Administration → Keys** deiner Organisation, um einen Machine-Key zu erstellen. + +Jev prüft benannte Tool-Aufrufe am `PreToolUse`- oder `PermissionRequest`-Gate. Es prüft nicht jedes Ereignis in einer Sitzung. Um zu sehen, wie Jev ein Policy-Deny aufhebt, benötigst du eine installierte Richtlinie, die als [reviewable](/de/policies/authority) markiert ist; alle anderen Policy-Denys bleiben endgültig. + +## Aktivierung + +1. **Erstelle einen Key mit Jev.** Öffne im FailproofAI Cloud-Dashboard **Administration → Keys → Key erstellen** und wähle das **machine**-Preset. Es gewährt die drei Berechtigungen, die eine Maschine benötigt: `events:add` (Aktivität senden), `policies:pull` (Richtlinien empfangen) und `jev:evaluate` (Jev, dem Plan deiner Organisation belastet). Ein Key kann `jev:evaluate` nicht ohne die anderen beiden tragen. +2. **Verbinde die Maschine** mit diesem Key. Lies das einmalige Secret an einer Eingabeaufforderung, dann führe den vollständigen Setup-Befehl aus: + + ```bash + read -rs FAILPROOFAI_CLOUD_TOKEN && export FAILPROOFAI_CLOUD_TOKEN + failproofai config + ``` + + `failproofai config` installiert den Daemon, bindet Hooks für die gefundenen Agent-CLIs ein und verbindet die Maschine. Die Umgebungsvariable hält den Key aus den Befehlsargumenten und dem Shell-Verlauf heraus. Wenn dein Harness später installiert wurde, [binde ihn explizit ein](/de/start/quickstart). + + Wenn deine Organisation ihr eigenes FailproofAI Cloud betreibt statt des gehosteten Dienstes, füge dessen Adresse hinzu: `--url https://` (oder exportiere `FAILPROOFAI_CLOUD_URL`). Ohne diese Angabe wird der Key gegen den gehosteten Dienst geprüft und die Verbindung schlägt fehl. Wenn das Zertifikat dieses Hosts von einer privaten CA stammt, installiere die CA im System-Truststore der Maschine (z.B. mit `update-ca-certificates`), nicht nur in `NODE_EXTRA_CA_CERTS`: Der Daemon, der Ereignisse sendet und Richtlinien abruft, liest den System-Truststore. Siehe [Troubleshooting](/de/reference/troubleshooting). + +Das ist alles. Die Verbindung speichert den Key und schaltet Jev – wenn die Maschine **noch keine** Jev-Konfiguration hat – über FailproofAI Cloud im **observe**-Modus ein: Sobald ein Pack Prüfungen bereitstellt, wird Jev zu jedem gated Tool-Aufruf befragt und seine Urteile werden aufgezeichnet, aber das Ergebnis deiner Richtlinien ist das, was durchgesetzt wird. Die Ausgabe zeigt dies an: + +```text + Jev on through FailproofAI Cloud, in observe mode: logged, not enforced (~/.failproofai/jev.json). +``` + +Jev fragt immer noch nichts, bis ein Pack ihm Prüfungen bereitstellt. Failproof AI liefert keine; solange kein installierter Pack welche deklariert, fügt die Ausgabe eine entsprechende Zeile hinzu, und `failproofai jev status` wiederholt dies. Installiere sie mit: + +```bash +failproofai policies add FailproofAI/jev-policies +``` + +**Mit `--no-transcripts` schaltet die Verbindung Jev nicht ein.** Jev sendet jeden geprüften Tool-Aufruf und den letzten Prompt an FailproofAI Cloud, was mehr ist, als eine nur-Entscheidungen-Verbindung zu senden gebeten wurde. Der Key wird trotzdem gespeichert, und die Ausgabe zeigt an, dass Jev verfügbar ist und wie man es einschaltet: + +```bash +failproofai jev setup --provider failproofai +``` + +Es schaltet Jev auch **nicht aus**. Wenn die `jev.json` der Maschine Jev bereits über FailproofAI Cloud betreibt, bleibt sie unverändert, und die Ausgabe teilt mit, dass Jev weiterhin jeden geprüften Tool-Aufruf und den letzten Prompt sendet, und dass `failproofai jev setup --mode off` es ausschaltet. + + +Die Verbindung **überschreibt niemals** eine vorhandene `~/.failproofai/jev.json`. Wenn du bereits deinen eigenen Jev-Endpoint verwendest, wird dieser weiterhin genutzt, und die Ausgabe zeigt an, dass die Datei unverändert blieb — und wenn diese Datei Jev deaktiviert lässt (abgelehnt oder ausgeschaltet), wird das ebenfalls angezeigt, zusammen mit der Lösung. Um diese Maschine auf FailproofAI Cloud umzustellen, führe `failproofai jev setup --provider failproofai` aus. + + +## Observe, enforce oder off + +Starte im observe-Modus, beobachte auf der Richtlinienseite, was Jev getan hätte, und lass es dann handeln: + +```bash +failproofai jev setup --mode enforce # Jev's verdicts apply: it may clear a reviewable deny and add its own +failproofai jev setup --mode observe # Jev is asked and logged; your policies' result is enforced +failproofai jev setup --mode off # keep the config, stop asking Jev +``` + +Denselben Schalter gibt es im lokalen Dashboard: **Settings → Jev** hat einen Ein/Aus-Schalter und observe/enforce. Es schreibt nur den Modus um und sonst nichts. Hooks lesen die Konfiguration bei jedem Tool-Aufruf, daher gilt eine Änderung ab dem nächsten Aufruf, ohne Neustart. + +## Status überprüfen + +```bash +failproofai jev status +failproofai jev test +``` + +`status` zeigt den Provider als **FailproofAI Cloud**, den Cloud-Host, mit dem die Maschine verbunden ist, den Modus und die Key-Quelle als **FailproofAI Cloud connection** – niemals den Key selbst. Wenn eine FailproofAI Cloud `jev.json` vorhanden ist, Jev aber nicht ausgeführt werden kann, wird der Grund angegeben: + +| `status` meldet | `status --json` | Bedeutung | +| --- | --- | --- | +| **off — no Jev key is stored for this machine's FailproofAI Cloud connection** | `key-lacks-jev` | Die Maschine ist verbunden, aber es ist kein Jev-Key dafür gespeichert: Der Key enthält kein `jev:evaluate`, oder die Verbindung konnte dies nicht bestätigen. Führe `failproofai config` erneut mit dem Key in `FAILPROOFAI_CLOUD_TOKEN` aus; wenn ihm die Berechtigung fehlt, verwende einen **machine**-Key. | +| **off — this machine is not connected to FailproofAI Cloud** | `not-connected` | Auf dieser Maschine besteht keine FailproofAI Cloud-Verbindung, zu der der Jev-Key gehören könnte. | + +Nach `failproofai config --disconnect` gibt es keine FailproofAI Cloud `jev.json` mehr (außer sie wurde ausgeschaltet, was beibehalten wird), sodass `status` Jev einfach als deaktiviert meldet. `status --json` enthält dieselben Informationen (`provider: "failproofai"`, `keySource: "cloud"`, `cloudConnected`, `keyCarriesJev`), auch wenn die Konfiguration fehlt oder abgelehnt wurde. `permissions` entspricht immer dem Inhalt von `jev.json`; eine Ablehnung bezüglich `credentials.json` fügt `credentialsPermissions` hinzu, sowie `fix`, wenn ein Befehl das Problem behebt. `test` sendet eine Live-Anfrage und meldet deren Latenz sowie die Jev-Version, die geantwortet hat. Es beendet sich mit 1 und zeigt dies in seinem Titel an, wenn die Antwort nach dem Hook-Timeout eintrifft (Hooks würden `timeout` aufzeichnen) oder die Prüffrage falsch beantwortet. + +Das **Settings → Jev**-Panel im Dashboard zeigt ebenfalls die **FailproofAI Cloud connection**: in welche Organisation die Maschine eingebunden ist und ob ihr Key Jev trägt. Die Daten werden aus den eigenen Dateien der Maschine gelesen, ohne Netzwerkaufruf. + +## Einen echten Aufruf verifizieren + +Starte eine neue Sitzung im gebundenen Agent. Bitte ihn, sein Datei-Lesewerkzeug auf `README.md` zu verwenden und den Titel zu melden. Bestätige, dass die Sitzung diesen Tool-Aufruf enthält, und führe dann `failproofai jev status` erneut aus: Die Anzahl der zuletzt ausgewerteten Aufrufe sollte steigen. Öffne **Policies → Activity** im [lokalen Dashboard](/de/reference/local-dashboard#review-policy-activity), um das Jev-Urteil und den Modus dieses Aufrufs zu prüfen. In Cloud zeigt die **Policies**-Seite der Organisation Jev-Ergebnisse für übermittelte Aktivitäten an. Im observe-Modus wird das Urteil als **would-have** aufgezeichnet, und das Richtlinienergebnis entscheidet den Aufruf weiterhin. Eine Freigabe erscheint nur, wenn eine überprüfbare Richtlinie zugetroffen hat und Jev deren benannte Prüfungen freigegeben hat. + +## Was die Richtlinienseite erreicht + +Die Maschine sendet ihre Hook-Aktivität bereits an FailproofAI Cloud (`events:add`). Mit aktiviertem Jev enthält der Datensatz jedes gated Aufrufs zusätzlich, welcher Evaluator ausgeführt wurde, was Jev entschieden hat, welche Richtlinien es freigegeben hat, warum es ggf. zurückgefallen ist, seine Latenz und das Modell, das geantwortet hat – Entscheidungen, Codes und Namen, niemals den Befehl oder deinen Prompt. Auf der **Policies**-Seite deiner Organisation: + +- Ein Aufruf, über den Jevs eigenes Urteil entschieden hat (enforce-Modus), wird **Jev** zugeschrieben; wenn die ausschlaggebende Prüfung aus einem Pack stammte, benennt der Datensatz auch dieses Pack und seine Version; +- Im observe-Modus erscheint Jevs Deny oder Warnung als **would-have**, neben den Rollouts, die du beobachtest; +- Die Richtlinien, die Jev freigegeben hat oder im observe-Modus freigegeben hätte, werden pro Richtlinie gezählt. + +## Wenn Jev nicht antworten kann + +Jeder der folgenden Fälle fällt für diesen Aufruf auf das Ergebnis deiner Richtlinien zurück und wird mit seinem Grund aufgezeichnet: + +| Grund | Ursache | +| --- | --- | +| `out-of-credits` | Deine Organisation hat ihr Plan-Kontingent aufgebraucht. | +| `http-401`, `http-403` | Der Key wurde widerrufen oder trägt kein `jev:evaluate`. Verbinde erneut mit einem Key, der dies tut. | +| `http-429` | FailproofAI Cloud begrenzt Jev für deine Organisation. Bis die geforderte Wartezeit abgelaufen ist (`Retry-After`, maximal 60 Sekunden) sendet die Maschine nichts dorthin und jeder Aufruf fällt sofort zurück. Auf diese Weise zurückgehaltene Aufrufe werden als `http-429` aufgezeichnet, oder als `rate-limited`, wenn das eigene Rate-Limit der Maschine sie zuerst zurückhält. | +| `http-429` (Tageslimit) | Deine Organisation hat ihr tägliches Jev-Aufruflimit erreicht: **10.000 pro UTC-Tag**, sofern der Betreiber deines FailproofAI Cloud kein anderes Limit gesetzt hat. Jeder Aufruf fällt zurück, bis der Zähler um 00:00 UTC zurückgesetzt wird; die Maschine fragt höchstens einmal pro Minute erneut, sodass sie den Reset innerhalb einer Minute erkennt. `failproofai jev test` meldet: "Daily Jev limit for this org reached; resets at 00:00 UTC." | +| `http-422` | Jev hat die Anfrage dieses Aufrufs abgelehnt, meistens weil der Tool-Aufruf dichten Text (Base64, Hex, minifizierten Code) enthält, der Jevs Token-Budget übersteigt. Dieser Aufruf fällt jedes Mal zurück; es handelt sich nicht um einen Ausfall. | +| `http-502` | Jev ist derzeit nicht verfügbar. | +| `http-503` | Diese Cloud kann Jev nicht für deine Organisation bereitstellen: kein Model-Gateway, eine noch nicht provisionierte Organisation oder das Gateway ist ausgefallen. Wende dich an deinen Admin; Hooks fragen höchstens einmal pro Minute erneut. | +| `http-404` | Dieses FailproofAI Cloud stellt Jev noch nicht bereit. | +| `timeout` | Keine Antwort innerhalb von `timeoutMs` (Standard: 3000). | +| `model-mismatch` | Eine andere Jev-Version als 1.13 hat geantwortet. | + +## Wo der Key gespeichert wird und wohin er geht + +- Der Key wird einmalig in `~/.failproofai/credentials.json` gespeichert (`0600`, in einem nur für den Eigentümer zugänglichen Verzeichnis), neben den anderen FailproofAI Cloud-Credentials. `jev.json` enthält für diese Route keinen Key; ein dort eingetragener macht die Konfiguration ungültig. +- Wenn `credentials.json` **irgendeine** Berechtigung für jemand anderen als dich trägt (Gruppe oder andere, Lesen oder Schreiben), oder das zugehörige Verzeichnis von jemand anderem als dir **beschreibbar** ist, wird es **abgelehnt** und nicht gelesen, und Jev ist deaktiviert, bis du dies behoben hast: `chmod 600` auf die Datei, `chmod 700` auf das Verzeichnis (oder neu verbinden, was die Datei mit `0600` neu schreibt und das Verzeichnis nur für den Eigentümer macht). Ein Verzeichnis, das andere nur lesen können, ist in Ordnung; eines, das sie schreiben können, erlaubt ihnen das Austauschen der Datei. +- Der Key gilt nur, solange die Verbindung, von der er stammt, auf der Maschine vorhanden ist: eine Richtlinien- oder Reporting-Credential für dasselbe FailproofAI Cloud **mit demselben Key**, in derselben Datei. Ein zurückgelassener Jev-Key ohne diese bleibt unberücksichtigt, und Jev bleibt deaktiviert. Das passiert, wenn ein älteres failproofai's `config --disconnect` den Jev-Key behält (es weiß nicht, ihn zu entfernen), oder wenn ein älteres failproofai's `config --token` mit einem anderen Key verbindet, der bei FailproofAI Cloud möglicherweise zu einer anderen Organisation gehört. Um Jev wieder einzuschalten, verbinde erneut mit einem **machine**-Key. +- Der Key wird ausschließlich an den Cloud-Ursprung gesendet, gegen den er verifiziert wurde. Eine `jev.json`, die auf einen anderen Ort verweist, wird abgelehnt. +- **Ein Agent auf der Maschine kann ihn lesen.** `credentials.json` ist nur für den Eigentümer zugänglich, und der Agent läuft als dieser Eigentümer. Das Lesen von Failproof AIs eigenen Dateien ist absichtlich erlaubt (nur deren Änderung ist durch `block-failproofai-commands` blockiert), sodass das Einzige zwischen einem Agent und dieser Datei `block-read-outside-cwd` ist – eine *reviewable*-Richtlinie – und von einer Sitzung, die im Home-Verzeichnis gestartet wurde, nichts. Ein Key mit `jev:evaluate` verbraucht das Jev-Kontingent deiner Organisation (bis zum Tageslimit) von überall, wo er verwendet wird; behandle einen Machine-Key daher wie jede andere Ausgabe-Credential: Wenn ein Agent ihn möglicherweise gelesen hat, deaktiviere ihn auf der Keys-Seite und verbinde mit einem neuen. +- Nur deine globalen Dateien entscheiden darüber. Ein Repository kann Cloud-Jev nicht einschalten, es woanders hinzeigen lassen oder seinen Key bereitstellen, und `FAILPROOFAI_JEV_API_KEY` wird für diese Route ignoriert. +- Für jeden Aufruf, den Jev auswertet, geht eine Anfrage an FailproofAI Cloud, die das enthält, was die [Bring-Your-Own-Key-Seite](/de/reference/jev-providers#what-leaves-the-machine) auflistet (Secrets werden geschwärzt). FailproofAI Cloud leitet sie an TypeSafe weiter und protokolliert oder speichert sie nicht. + +## Deaktivierung + +| Befehl | Ergebnis | +| --- | --- | +| `failproofai jev setup --mode off` | Konfiguration beibehalten; Jev wird nicht befragt. **Das ist der dauerhafte Schalter:** Eine erneute Verbindung überschreibt eine vorhandene `jev.json` niemals, sodass Jev deaktiviert bleibt, bis du es mit `--mode observe` wieder einschaltest. | +| `failproofai jev remove` | Löscht `~/.failproofai/jev.json`; Jev ist deaktiviert – bis zum nächsten `failproofai config --token` mit einem Key, der `jev:evaluate` trägt, das keine `jev.json` findet und Jev erneut im observe-Modus einschaltet (sofern nicht mit `--no-transcripts` ausgeführt). Um es deaktiviert zu lassen, verwende `--mode off`. | +| `failproofai config --disconnect` | Trennt die Maschine: Der Key wird entfernt, ebenso `jev.json`, wenn sie FailproofAI Cloud benennt und nicht ausgeschaltet ist. Eine `jev.json` für deinen eigenen Endpoint bleibt erhalten, ebenso eine ausgeschaltete, sodass Jev deaktiviert bleibt, wenn du dich erneut verbindest. | + +Ab dem nächsten Tool-Aufruf führen Hooks die Regex-Richtlinien genau wie zuvor aus. \ No newline at end of file diff --git a/docs/de/reference/jev-evaluations.mdx b/docs/de/reference/jev-evaluations.mdx new file mode 100644 index 000000000..65bebdfe2 --- /dev/null +++ b/docs/de/reference/jev-evaluations.mdx @@ -0,0 +1,88 @@ +--- +title: "Jev Evaluierungsreferenz" +description: "Fragetypen, kalibrierte Bewertungen, Grenzen und Backfill für Jev-Sitzungsevaluierungen." +icon: "list-checks" +--- + +Diese Seite beschreibt die Frageformen und Bewertungsregeln hinter [Jev-Evaluierungen](/de/evaluations/jev). Manche Fragen erfordern, dass ein Modell das Gespräch *liest*, aber nicht darüber *schreibt*. „Hat der Kunde Dringlichkeit geäußert?" hat zwei Antworten. „Wie frustriert waren sie?" hat eine Handvoll, in einer bestimmten Reihenfolge. Alle möglichen Antworten sind bekannt, bevor man fragt. + +Eine **Klassifikator-Evaluierung** ist genau dafür gedacht. Sie schreiben die Frage und die möglichen Antworten, und ein kleines, speziell für Klassifikation gebautes Modell liefert eine kalibrierte Zahl – niemals Freitext. + + +Wie ein Richter kostet eine Klassifikator-Evaluierung pro Sitzung einen Modellaufruf. Anders als ein Richter ist es ein kleines, zweckgebundenes Modell statt einem allgemeinen – daher schneller und günstiger – aber es wird sich niemals erklären. Wenn Sie die Begründung benötigen, verwenden Sie einen [Richter](/de/evaluations/judge). + + +## Was eignet sich wofür? + +| Frage | Verwenden | +| --- | --- | +| Wie viele Tool-Aufrufe gab es? | Code | +| Dauerte die Sitzung unter 30 Sekunden? | Code | +| Hat der Kunde Dringlichkeit geäußert? | **Klassifikator** | +| Welches Team soll sich darum kümmern: Abrechnung, Technik oder Vertrieb? | **Klassifikator** | +| Wie frustriert war der Kunde? | **Klassifikator** | +| War die Antwort tatsächlich korrekt? | **Richter** | +| Hat es unsere Eskalationsrichtlinie befolgt, und warum meinen Sie das? | **Richter** | + +Die Faustregel lautet: **Zählbares → Code, auflistbare Antworten → Klassifikator, braucht eine Erklärung → Richter.** + +Sie müssen sich nicht sofort entscheiden. Beschreiben Sie, was gemessen werden soll, und der Assistent wählt aus, teilt Ihnen mit, was er gewählt hat und warum – und Sie können es jederzeit ändern. + +## Die zwei Fragetypen + +### `noul` — Trifft das zu? + +Zwei Antworten, und Sie beschreiben beide. Das Ergebnis ist die Wahrscheinlichkeit, dass die „wahre" Beschreibung zutrifft: + +```json +{ + "instructions": "Did the assistant promise a refund without first checking the refund policy?", + "criteria": { + "true": "A refund was promised or issued with no prior policy check or approval", + "false": "No refund was promised, or every refund followed a policy check" + } +} +``` + +Beschreiben Sie beide Seiten. „Keine Dringlichkeit geäußert" ist eine echte Antwort, und deren Formulierung schärft auch die andere Seite. + +### `score` — Wie stark trifft das zu? + +Ein geordnetes Rubrik-Schema, **schlechtestes zuerst**. Das Ergebnis zeigt, wo die Sitzung darin landet, skaliert auf 0–1: + +```json +{ + "instructions": "How frustrated is the customer?", + "criteria": ["Calm", "Frustrated", "Very angry"] +} +``` + +**Eine Rubrik umfasst drei bis fünf Stufen, und alle müssen unterschiedlich sein.** Beide Grenzen sind messbar begründet, nicht stilistisch: + +- **Zwei Stufen** kollabiert in das, was `noul` bereits besser leistet, und **mehr als fünf** veranlasst das Modell, sich zur Mitte hin abzusichern statt sich festzulegen. Dieselbe Frage über dieselbe Sitzung ergab 0,00 mit zwei Stufen, 0,01 mit drei und 0,55 mit zehn. +- **Wiederholte Stufen** teilen die Antwort willkürlich unter sich auf. Eine Sitzung, die eindeutig wütend war, ergab 1,00 gegen `["Calm", "Frustrated", "Very angry"]` und 0,66 gegen `["Angry", "Angry", "Angry"]` – eine wohlgeformte Zahl, die nichts bedeutet. + +Kategorien ohne Reihenfolge – „Abrechnung, Technik oder Vertrieb" – bilden keine Rubrik. Stellen Sie diese als `noul` pro Kategorie, oder verwenden Sie einen Richter. + +## Ergebnisse lesen + +Ein Klassifikator liefert eine **Bewertung** von 0 bis 1, genau wie ein Richter – er kann also auf dieselbe Weise in Diagrammen dargestellt, gefiltert und für Warnungen ausgelöst werden. Zwei Unterschiede sind wichtig: + +- **Es gibt keine Begründung.** Das Feld ist bewusst leer. Dieses Modell erklärt sich nicht, und eine Erklärung zu erfinden wäre eine Fälschung statt ein Feature. +- **Unsicherheit wird gekennzeichnet.** Eine `score`-Frage berichtet ihre eigene Konfidenz, und ein Ergebnis, bei dem das Modell unsicher war, wird als `low_confidence` markiert – sodass „welche davon sollte ein Mensch prüfen" ein Filter ist und keine Vermutung. Eine `noul`-Frage berichtet keine Konfidenz und wird daher nie markiert. + +Sehr lange Sitzungen werden in Auszügen gelesen und zusammengeführt. Wenn eine Sitzung zu lang ist, um sie vollständig zu lesen, gibt das Ergebnis an, wie viele Gesprächszüge ausgelassen wurden – es wird niemals ein Urteil über einen Teil einer Sitzung als eines über die gesamte Sitzung ausgegeben. + +## Grenzen + +- **Drei bis fünf Rubrik-Stufen, alle unterschiedlich.** Siehe oben; beide Grenzen werden beim Erstellen erzwungen. +- **Eine Frage pro Evaluierung.** Bei zwei Fragen erhalten Sie zwei Evaluierungen, was auch das ist, was Sie in einem Diagramm möchten. +- **Das Bearbeiten der Frage veröffentlicht eine neue Version.** Alte und neue Bewertungen sind nicht vergleichbar und werden daher getrennt gehalten statt in einer Trendlinie vermischt. +- **Ein Klassifikator liefert immer eine Bewertung**, niemals eine Metrik oder eine Aussage. +- **Keine Begründung**, wie oben. Wenn eine Zahl jemanden zu „Warum?" veranlassen wird, schreiben Sie stattdessen einen Richter. + +## Testen und Backfill + +Anders als ein Richter **kann** eine Klassifikator-Evaluierung getestet werden, bevor Sie sie einsetzen – [testen Sie sie](/de/evaluations/test) gegen echte Sitzungen auf dieselbe Weise wie eine Code-Evaluierung, und lesen Sie die Bewertungen, bevor irgendetwas live geht. + +Sie kann auch über bereits vorhandene Sitzungen [zurückgefüllt](/de/evaluations/deploy#score-sessions-you-already-have) werden. Da pro Sitzung ein Modellaufruf anfällt, sollten Sie den Zeitraum bewusst eingrenzen, anstatt alles neu zu verarbeiten. \ No newline at end of file diff --git a/docs/de/reference/jev-intent.mdx b/docs/de/reference/jev-intent.mdx new file mode 100644 index 000000000..5d4008990 --- /dev/null +++ b/docs/de/reference/jev-intent.mdx @@ -0,0 +1,112 @@ +--- +title: "Jev Intent-Erfassung" +description: "Welche Harness-Events dem Jev-Evaluator mitteilen, was der Mensch angefragt hat, welches Feld den Text enthält, was nie gezählt wird und welches Risiko entsteht, wenn man einem harness-gelieferten Prompt vertraut." +icon: "message-square-quote" +--- + +Wenn Sie die [Jev-Richtlinienprüfung](/de/policies/jev) konfigurieren, beurteilt der Evaluator jeden kontrollierten Tool-Aufruf anhand **dessen, was der Mensch angefragt hat** — nicht anhand des Textes, den das Harness dem Agenten vorgelegt hat. Eine Antwort wie „ja, force-push" kann eine **reviewable**-Richtlinie freigeben — und genau das ist der Sinn des Evaluators, denn ein Regex, der die Anfrage nicht lesen kann, blockiert ein Drittel der realen Arbeit. + +Dieser Text kommt von einem einzigen Ort: **dem Prompt, den das Harness selbst beim Prompt-Submit-Event an den Hook übergibt**. Failproof AI zeichnet den Teil auf, den der Mensch getippt hat — Harness-Umhüllung entfernt, Secrets redigiert, begrenzt — in einer `0600`-Datei unter seinem eigenen State-Verzeichnis. Nichts auf der Festplatte wird konsultiert: Das Session-Transkript ist eine Datei, die der Agent mit einem einzigen Befehl überschreiben kann, daher wird es nie gefragt, wer einen Prompt geschrieben hat. + +## Das Risiko, das dabei akzeptiert wird + +Ein Agent, der bereits Befehle ausführen kann, kann ein Harness dazu bringen, einen Prompt einzureichen. `claude -p "…"`, `codex exec`, `copilot -p`, `cursor-agent -p`, `devin -p`, `droid -p`, `goose run -t` und `pi -p` feuern alle dasselbe Prompt-Submit-Event mit derselben Nutzlast wie eine tippende Person — in einer Child-Session, die der Agent kontrolliert. Er kann auch das Hook-Binary von Failproof AI selbst ausführen und ihm eine selbst erstellte Nutzlast übergeben. Nichts innerhalb von Failproof AI kann beides vom echten Ding unterscheiden — beide sind dasselbe Programm, das dasselbe stdin liest. + +**Ein Agent mit Shell-Zugang kann also seine eigene Zustimmung fälschen.** Das ist ein bewusster Kompromiss, der am 2026-09-23 eingegangen wurde, und hier sind beide Seiten davon: + +- **Was er bringt.** Die Alternative wurde gebaut und gemessen: ein Feld verlangen, in dem das Harness einen Menschen als Autor des Prompts benennt, und andernfalls nichts aufzeichnen. Kein ausgeliefertes Harness sendet ein solches Feld, daher zeichnete diese Version **nichts, bei jedem Harness** auf — Jev beurteilte jeden Aufruf ohne angegebene Absicht und konnte nie eine einzige Richtlinie freigeben. Eine Erfassung, die nie auslöst, ist kein sichereres Produkt, sondern gar kein Produkt. +- **Was er nicht kann.** Ein aufgezeichneter Prompt kann immer nur eine Richtlinie freigeben, die als **reviewable** markiert ist. Eine **hard**-Richtlinie wird durch nichts, was Jev sagt, jemals freigegeben — ein gefälschter Prompt kann also einen harten deny niemals in ein allow umwandeln. Und auch das Überspringen des Hooks bringt einem Agenten nichts: Das Harness ruft Failproof AI für den Tool-Aufruf unabhängig davon auf. +- **Was er im schlimmsten Fall kann.** Das Schlimmste ist, eine der fünfzehn reviewable eingebauten Richtlinien freizugeben — und **zwölf dieser fünfzehn blockieren**. `protect-env-vars`, `block-env-files`, `block-read-outside-cwd`, `block-rm-rf`, `block-force-push`, `block-secrets-write` sowie die sechs Infrastructure-CLI-Blocks (`block-kubectl`, `block-terraform`, `block-aws-cli`, `block-gcloud`, `block-az-cli`, `block-helm`) sind Denies. Eine gefälschte Zustimmung kann also einen echten Deny in ein Allow verwandeln — beim Ausgeben von Umgebungs-Secrets, Lesen einer `.env`-Datei, Lesen außerhalb des Projekts, `rm -rf`, einem Force-Push, Schreiben einer Secrets-Datei oder Verändern aktiver Infrastruktur. Nur `warn-git-amend`, `warn-destructive-sql` und `warn-global-package-install` sind Hinweise. Eine Standard-Installation aktiviert zwei der zwölf, `protect-env-vars` und `block-env-files`; die anderen zehn erreichen nur eine Maschine, auf der jemand sie aktiviert hat. Was kein Prompt erreicht, ist alles, was hard ist — `block-sudo`, `block-curl-pipe-sh`, `block-push-master`, `block-work-on-main`, der Schutz, der einen Agenten daran hindert, Failproof AI zu deaktivieren, und jedes andere eingebaute Feature, das nicht als reviewable markiert ist. [Policy authority](/de/policies/authority) listet alle fünfzehn und das auf, wovon jede geprüft wird. + +Was weiterhin abgelehnt wird, ist alles, was einfach zu prüfen ist und was ein Agent nicht einfach durch Nachfragen erhalten kann: ein Turn, den die eigene Nutzlast des Harness als maschinell eingereicht kennzeichnet, eine Nutzlast, die einen Sub-Agenten benennt, eine Session-ID, die kein einfacher Name ist, ein Event, das nicht das Prompt-Submit-Event ist, und Text, der nichts als Harness-Umhüllung ist — einschließlich der eigenen Stop-Gate-Wörter von Failproof AI, die mehrere Harnesses als nächsten User-Turn zurückgeben. + +## Tabelle pro Harness + +„Text field" ist das stdin-Nutzlastfeld nach der harnessspezifischen Normalisierung von Failproof AI. „Recorded" gibt an, ob der Prompt als Anfrage des Menschen gespeichert wird. + +| Harness | `--cli` | Prompt-Event → kanonisch | Textfeld | Aufgezeichnet | Letzte Nachricht des Agenten gelesen aus | +| --- | --- | --- | --- | --- | --- | +| Claude Code | `claude` | `UserPromptSubmit` | `prompt` | Ja, es sei denn, die `source` der Nutzlast benennt einen Turn, den niemand eingereicht hat (`loop_wakeup`, `schedule_wakeup`, `poll_event`, `system`). `user`, `sdk`, ein unbekannter Wert und ein Build, der gar kein `source` sendet, werden alle aufgezeichnet | das Session-Transkript (`transcript_path`) | +| Codex | `codex` | `user_prompt_submit` → `UserPromptSubmit` | `prompt` | Ja | das Rollout-JSONL (`agent_message`, `AgentMessage`) | +| GitHub Copilot CLI | `copilot` | `UserPromptSubmit` | `prompt` | Ja | `events.jsonl` (`assistant.message`) | +| Cursor | `cursor` | `beforeSubmitPrompt` → `UserPromptSubmit` | `prompt` | Ja, wobei der ``-Wrapper entfernt wird, wenn er den gesamten Prompt darstellt | das Agenten-Transkript-JSONL | +| OpenCode | `opencode` | `message.updated` (user-Rolle) → `UserPromptSubmit` | `prompt` | Ja — aber aktuelles OpenCode enthält keinen Text in diesem Event, sodass in der Praxis nichts aufgezeichnet wird; eine Wiederholung derselben Nachricht wird einmalig aufgezeichnet | keine (Sessions sind SQLite) | +| Pi | `pi` | `input` → `UserPromptSubmit` | `prompt` | Ja, es sei denn, `input_source` ist `extension` — die `sendUserMessage()` einer anderen Extension, deren Text modellgeneriert oder repo-abgeleitet sein kann | das Pi-Session-JSONL | +| Hermes | `hermes` | keine | — | Nein — Hermes hat kein Prompt-Submit-Event | — | +| OpenClaw | `openclaw` | `before_agent_run` → `UserPromptSubmit` | `prompt` | Ja, es sei denn, die Run-Metadaten markieren den Run als maschinell: ein `trigger` außer `user`, ein `inputProvenance.kind` außer `external_user` oder `senderIsOwner: false` | keine (`before_agent_run` enthält keinen Transkript-Pfad) | +| Factory Droid | `factory` | `UserPromptSubmit` | `prompt` | Ja | das Droid-Session-JSONL | +| Devin CLI | `devin` | `UserPromptSubmit` | `prompt` | Ja | keine (Sessions sind SQLite) | +| Antigravity CLI | `antigravity` | `PreInvocation` → `UserPromptSubmit` | keine | Nein — `PreInvocation` feuert vor *jedem* Modellaufruf in einem Turn und enthält keinen Prompt-Text | — | +| Goose | `goose` | `UserPromptSubmit` | `message` | Ja | keine (Sessions sind SQLite) | + +Zwei Harnesses zeichnen nichts auf, und aus demselben Grund in beiden Fällen: Ihr Event liefert keinen menschlichen Text. Hermes hat kein Prompt-Submit-Event — sein natives Plugin behandelt `pre_llm_call` selbst und leitet nur Tool-, Session- und Subagent-Events weiter. Antigravitys `PreInvocation` feuert vor jedem Modellaufruf, bei einem menschlichen Turn und bei den fünf folgenden, und enthält kein Prompt-Feld; Hooks können auch `userMessage`-Schritte in dieselbe Konversation einfügen. In keinem der beiden Events gibt es etwas aufzuzeichnen. + +## Was einen Prompt zum menschlichen Prompt macht + +1. **Das Event.** Failproof AI wurde für das Prompt-Submit-Event des Harness aufgerufen, das der Handler zu `UserPromptSubmit` kanonisiert. +2. **Die Nutzlast.** Das Harness schreibt sie auf das stdin des Hooks, und sie enthält den Text im oben genannten Feld. Ein Aufruf, der Failproof AI ohne die Nutzlast erreicht, zeichnet nichts auf. +3. **Nichts in der Nutzlast schließt den Turn aus.** Eine Nutzlast, die einen Sub-Agenten benennt (`agent_id`), ist der Agent, der sich selbst anweist. Ein `source`-, `input_source`- oder OpenClaw-Run-Marker, der einen maschinell eingereichten Turn benennt, wird abgelehnt. Ein **fehlender** Marker schließt nichts aus — das ist der Unterschied zur Version, die nichts aufzeichnete, da jeder Marker hier bei jedem ausgelieferten Build fehlt. +4. **Nach dem Entfernen der Umhüllung bleibt etwas übrig** (siehe unten). + +**Das Session-Transkript ist kein Beweis dafür, wer einen Prompt geschrieben hat.** Frühere Versionen dieser Seite beschrieben eine Transkript-Kreuzprüfung: Der Prompt wurde abgelehnt, wenn das Transkript zeigte, dass das Modell ihn geplant hatte, und das Transkript musste das des vorherigen Prompts fortsetzen. Diese Prüfung wurde entfernt. Ein Transkript ist eine Datei, über die der Agent bereits Shell-Kontrolle hat — es kann abgeschnitten, ersetzt, über das Lesebudget hinaus aufgefüllt, zu Beginn eines Turns gespeichert und am Ende wiederhergestellt oder mit vom Agenten geschriebenen Einträgen wieder lesbar gemacht werden. Jede Runde der Härtung wurde von einer weiteren Variante derselben Fälschung gefolgt, sodass der gesamte Mechanismus entfernt statt repariert wurde. + +Das Transkript wird noch für eine Sache gelesen: **die letzte sichtbare Nachricht des Agenten**. Diese Nachricht ist per Definition vom Agenten verfasst, Jev wird darüber informiert, und sie ist für sich allein nie eine Zustimmung. + +## Was von einem Prompt aufbewahrt wird + +Harnesses stecken mehr als die Worte des Menschen in einen Prompt. Bevor irgendetwas gespeichert wird: + +- ``-Blöcke werden entfernt, die Worte des Menschen darum herum bleiben erhalten. +- Eine Session-Fortsetzungszusammenfassung („This session is being continued from a previous conversation…") wird vollständig verworfen. +- Task-Benachrichtigungen, Local-Command-Ausgaben und Unterbrechungsmarker werden vollständig verworfen. +- Ein Turn, den ein anderer Agent oder eine andere Session geschrieben hat, wird vollständig verworfen: Claude Code umhüllt diese in ``, ``, ``, `` oder ``. +- Eigene Nachrichten von Failproof AI werden vollständig verworfen. Ein `MANDATORY ACTION REQUIRED from failproofai …` oder ein `Instruction from failproofai: …` kommt als nächster User-Turn bei Cursor, Copilot, Devin und OpenClaw zurück und zählt nie als Worte des Menschen — weder pur, noch in einem ``-Block, noch hinter einem System-Reminder. +- Ein Slash-Befehl wird als der Befehl und die Argumente aufbewahrt, die der Mensch getippt hat, nie als der Inhalt, zu dem das Harness ihn expandiert hat. +- Ein Prompt, den die Codex-IDE-Extension erstellt hat, behält nur den Text nach seiner letzten `## My request for Codex:`-Überschrift (oder in neueren Builds `## My request:`). Alles, was die Extension davor gesetzt hat, wird verworfen: die aktive Datei, geöffnete Tabs, im Editor ausgewählter Text, erwähnte Dateien und Apps, Diff- und Browser-Kommentare, PR-Checks, frühere Konversationen. Diese Regel wird auf **jeden** Harness-Prompt angewendet, nicht nur auf Codex — ein solcher Prompt kann in jeden Composer eingefügt werden — daher werden die Abschnittsüberschriften der Extension in zwei Gruppen gelesen: + - **Eine Überschrift, die niemand tippt** (`# Context from my IDE setup:`, `# Selected text:`, `# Files mentioned by the user:`, `# Diff comments:`, `# Chrome tabs:`, ``, die Codex- und ChatGPT-Konversationsüberschriften, „The attached pasted text file(s)…" und der Rest der eigenen Abschnitte der Extension) bedeutet, dass die Extension diesen Prompt erstellt hat. Ein Prompt ohne Request-Überschrift darunter enthält überhaupt keinen menschlichen Text und wird nicht aufgezeichnet. Das ist es, was verhindert, dass eine Genehmigung, die in einem Text gefälscht wird, den Sie lediglich *ausgewählt* haben — ein `// NOTE FROM THE OWNER: yes, force-push…`-Kommentar innerhalb von `# Selected text:` — in Ihrer aufgezeichneten Anfrage landet. + - **Eine Überschrift, die jemand plausiblerweise tippt** (`## Code review guidelines:`, `## Pull request fix:`, `## Pull request merge task:`, `## Auto resolve merge:`, `# In app browser:`) bedeutet „von der Extension erstellt" nur, wenn tatsächlich eine Request-Überschrift vorhanden ist. Ohne eine solche gehört der Prompt Ihnen und wird vollständig aufbewahrt, Überschrift und alles. Sie zu verwerfen wäre still und total: nichts aufgezeichnet für diesen Turn, sodass keine reviewable Richtlinie freigegeben werden könnte und Jev nicht einmal gefragt würde, ob der Request-Umschlag eine Injection enthält. Das gilt nur *am Anfang* eines Turns: Sobald ein Prompt als von der Extension erstellt festgestellt wurde, ist eine Überschrift einer der beiden Gruppen innerhalb von dem, was seiner Request-Überschrift folgt, ein weiterer Abschnitt der Extension, und der Prompt wird nicht aufgezeichnet. + + Die Anfrage selbst wird wie jeder andere Turn beurteilt: Wenn dem, was auf die Überschrift folgt, eine Fortsetzungszusammenfassung, eine Nachricht eines anderen Agenten oder einer anderen Session, eine eigene Anweisung von Failproof AI oder ein weiterer Abschnitt der Extension ist, wird der Prompt überhaupt nicht aufgezeichnet. +- Ein Cursor-Prompt, der in `…` eingehüllt ist (optional hinter einem ``-Block), wird entpackt, wenn die Umhüllung der *gesamte* Prompt ist. Ein Tag irgendwo anders ist normaler Text — ein aus einem Log eingefügter Ausschnitt oder ein vom Agenten gewählter Branch-Name — und der Prompt wird vollständig aufbewahrt, anstatt auf den markierten Bereich reduziert zu werden. +- Eingefügte Blöcke werden aufbewahrt und als vom Menschen eingefügt gekennzeichnet. + +Ein Prompt, der nur aus Harness-Text besteht, wird überhaupt nicht aufgezeichnet. + +## Die letzte Nachricht des Agenten + +Eine Antwort wie „ja" bedeutet ohne die Frage, die sie beantwortet, nichts. Wenn ein Prompt aufgezeichnet wird, liest Failproof AI auch die letzte sichtbare Nachricht des Agenten aus dem Session-Transkript **in diesem Moment** und speichert sie zusammen mit dem Prompt. Jev empfängt sie in einem eigenen Feld, das als vom Agenten verfasst gekennzeichnet ist: Sie erklärt eine kurze Antwort und zählt für sich allein nie als Anfrage des Menschen. Sie ist das Einzige, wofür das Transkript gelesen wird, und das Schlimmste, was ein umgeschriebenes Transkript bewirken kann, ist, eine vom Agenten geschriebene Nachricht dorthin zu legen, wo eine vom Agenten geschriebene Nachricht erwartet wird. + +Sie wird vom Ende des Transkripts gelesen, maximal die letzten 4 MB. Unterstützte Transkriptformate sind Claude Code, Codex-Rollouts (ältere `agent_message`-Events und neuere `AgentMessage`-Items), Cursor, Copilot `events.jsonl` sowie das Pi-, Factory- und OpenClaw-Session-JSONL. Die eigenen synthetischen und API-Fehlermeldungen von Claude Code sowie Subagenten-(Sidechain-)Nachrichten werden übersprungen. Es gibt keinen Snapshot für Goose und OpenCode, die Sessions in SQLite speichern, für Devin, dessen Transkript ein einzelnes JSON-Dokument ist, oder für OpenClaw, dessen `before_agent_run`-Event keinen Transkript-Pfad enthält. + +## Speicherung + +| Eigenschaft | Wert | +| --- | --- | +| Speicherort | `~/.failproofai/state/semantic/sessions/.json` | +| Berechtigungen | Datei `0600`, Verzeichnis `0700`. Jedes übergeordnete Verzeichnis bis zu `~/.failproofai` wird derselben Regel unterworfen wie das Verzeichnis von `jev.json`: Ein Verzeichnis, in das jemand anderes **schreiben** kann, kann umbenannt und ersetzt werden. Daher entfernt der Lesepfad diese Schreibbits, wo möglich, und liest **nichts**, wo es nicht möglich ist. Ein aufgezeichneter Prompt ist dann abwesend statt gefälscht, und nichts wird freigegeben | +| Gespeichert pro Session | die letzten 5 Prompts; ein Prompt, der mit dem vorherigen identisch ist, ersetzt ihn, anstatt einen neuen Slot zu belegen | +| Fenster | Prompts, die älter als 6 Stunden sind, werden ignoriert | +| Größe | Jeder Prompt und jede Agentennachricht ist auf 6.000 Zeichen begrenzt, wobei Anfang und Ende aufbewahrt werden | +| Secrets | Vor dem Schreiben mit denselben Mustern wie die `sanitize-*`-Richtlinien redigiert. Ein Text mit mehr als 48.000 Zeichen wird als seine ersten 28.800 und letzten 19.200 Zeichen redigiert, und der Text neben diesen Schnitten, wo ein Secret hätte gespalten werden können, wird nie gespeichert | + +Eine Session-ID, die etwas anderes als Buchstaben, Ziffern, `.`, `_` und `-` enthält oder länger als 128 Zeichen ist, wird nie als Dateiname verwendet, sodass für sie nichts aufgezeichnet wird. + +Eine Session-Datei existiert nur, sobald ein Prompt darin aufgezeichnet wurde. Sie enthält nur Prompts und sonst nichts — keinen Origin-State, keine Transkript-Markierung — und wird gelöscht, sobald sie länger als das Sechs-Stunden-Fenster still war, beim nächsten Mal, wenn eine neue Session ihren ersten Prompt schreibt. + +Nichts wird aufgezeichnet, wenn kein Jev-Endpunkt konfiguriert ist. + +### Das Projektstammverzeichnis + +„Innerhalb des Projekts" — das, was `read-outside-workspace` und die anderen Pfadprüfungen beurteilen — bedeutet innerhalb des Projekts, in dem sich die Session beim **ersten geprüften Aufruf** befand. Das Stammverzeichnis wird zu diesem Zeitpunkt festgelegt, und ein späteres `cd` verschiebt es nie; ein `cd` ändert jedoch weiterhin, wie ein relativer Pfad aufgelöst wird. Würde es dem `cd` folgen, würde `cd ~/.ssh` in einem Aufruf `~/.ssh` zum Projekt für den nächsten machen. + +Die Festlegung erfolgt in `~/.failproofai/state/semantic/roots/.json`, das `{root, at}` enthält: Datei `0600`, Verzeichnis `0700`, und dieselbe Session-ID-Regel wie oben. Dateien, die älter als 7 Tage sind, werden gelöscht, wenn eine neue Session ihr Stammverzeichnis festlegt. Ein `roots`-Verzeichnis, in das andere Benutzer schreiben können, wird ignoriert, und stattdessen wird das Stammverzeichnis des aktiven Verzeichnisses verwendet. Um eine Session neu festzulegen, löschen Sie ihre Datei. + +## Bekannte Einschränkungen + +- **Ein Prompt ist nur so vertrauenswürdig wie der Hook-Aufruf.** Alles hier liest die Nutzlast, die das Harness auf das stdin des Hooks geschrieben hat. Ein Agent, der Befehle ausführen kann, kann das Harness headless ausführen (`claude -p` und die sieben anderen oben genannten) oder das Hook-Binary von Failproof AI selbst mit einer selbst erstellten Nutzlast ausführen und einen Prompt aufzeichnen, den niemand getippt hat. Das ist der akzeptierte Kompromiss, der am Anfang dieser Seite beschrieben wird: Er gibt nur reviewable Richtlinien frei, nie eine hard — aber zwölf der fünfzehn reviewable eingebauten Features sind Denies, sodass ein gefälschter Prompt einen echten Block für diese zwölf in ein Allow umwandeln kann. +- **Sub-Agenten-Erkennung ist Claude-förmig.** Eine Nutzlast mit `agent_id` wird bei keinem Harness aufgezeichnet. Das ist das Feld, das Claude Code, Factory Droid und Devin verwenden würden. Codex feuert sein Prompt-Event innerhalb von Sub-Agenten-Threads, Copilot führt In-Process-Sidekicks aus, Goose hat ein `delegate`-Tool und OpenClaw führt Personas aus — keines davon markiert die Nutzlast auf eine Weise, die dies erkennt. Daher wird ein Sub-Agenten-Prompt auf diesen Harnesses als der eigene der Session aufgezeichnet. OpenClaws `openclaw.agentId` ist **nicht** diese Markierung: Das ausgelieferte Plugin setzt es bei jedem Run, einschließlich dem des Eigentümers. +- **Scheduler ohne Marker.** Claude Codes `schedule_wakeup` und `loop_wakeup` sowie OpenClaws `cron`- und `heartbeat`-Trigger werden abgelehnt, weil diese Harnesses dies in der Nutzlast angeben. Der eigene Scheduler von Goose (`goose schedule add`) und Codex's `codex exec` geben nichts an, sodass ein von ihnen gestarteter Run wie jeder andere aufgezeichnet wird. +- **Die letzte Nachricht eines Agenten kann eine vom Agenten gewählte Nachricht sein.** Das Transkript ist nicht authentifiziert, sodass ein Agent, der sein eigenes Transkript schreibt, entscheiden kann, was seine „letzte Nachricht" sagt. Sie wird als vom Agenten verfasst gekennzeichnet und gibt für sich allein nie etwas frei — beachten Sie jedoch, dass der v1-Pfad von `decide.ts` es ihr ermöglicht, die deterministische Prüfung „Hat der Benutzer dieses Ziel genannt?" zu erfüllen, sodass ein Agent, der sein Transkript kontrolliert, einen Zielnamen liefern kann, den ein Override benötigt. +- **Ein Prompt, der mit einer der maschinellen Extension-Überschriften beginnt, wird vollständig verworfen.** Beginnen Sie einen Prompt mit `# Selected text:`, `# Diff comments:`, `# Chrome tabs:` oder einer anderen Abschnittsüberschrift aus der ersten Gruppe oben, und schreiben Sie keine `## My request:`-Überschrift, und für diesen Turn wird nichts aufgezeichnet — sodass auch nichts für ihn freigegeben wird. Das ist beabsichtigt: Diese Abschnitte enthalten Text, den jemand anderes kontrolliert (Code, den Sie ausgewählt haben, der Diff-Kommentar eines Reviewers, ein Seitentitel), und das als Ihre Worte aufzuzeichnen wäre der schlimmere Fehler. Überschriften, die ein Entwickler plausiblerweise tippt, befinden sich in der zweiten Gruppe und verwerfen einen Prompt nie für sich allein. +- **OpenCode zeichnet in der Praxis nichts auf.** Sein `message.updated`-Event enthält in aktuellem OpenCode keinen Text, und es feuert auch für die Child-Sessions, die sein Task-Tool erstellt, deren „user"-Nachricht der übergeordnete Agent geschrieben hat. +- **`CODEX_HOME` wird nicht beachtet** von der Rollout-Erkennung in `lib/codex-sessions.ts`. Dies betrifft nur den Ort, an dem nach einem Agentennachrichten-Snapshot gesucht wird, nie ob ein Prompt aufgezeichnet wird. \ No newline at end of file diff --git a/docs/de/reference/jev-providers.mdx b/docs/de/reference/jev-providers.mdx new file mode 100644 index 000000000..2cbabd68a --- /dev/null +++ b/docs/de/reference/jev-providers.mdx @@ -0,0 +1,275 @@ +--- +title: "Jev-Anbieter und eigene Schlüsselkonfiguration" +description: "Anbieter-Endpunkte, Modell-IDs, Konfiguration und Fehlerverhalten für die Live-Jev-Richtlinienprüfung mit eigenem Schlüssel." +icon: "key-round" +--- + +Dies ist die Anbieter- und Konfigurationsreferenz für [Jev-Richtlinien](/de/policies/jev) mit eigenem Schlüssel. Regex-Richtlinien gleichen Zeichenketten ab. Sie können nicht unterscheiden, ob `rm -rf build/` von Ihnen angefordert wurde oder ob `rm -rf ~` unbemerkt in einen Plan gelangt ist – sie blockieren also an einer Stelle zu viel und an einer anderen zu wenig. **Jev**, der Klassifikator von TypeSafe, liest den Aufruf im Kontext dessen, was Sie tatsächlich angefordert haben, und beantwortet in einer schnellen Anfrage eine Reihe von Ja/Nein-Fragen dazu. + +Mit einem konfigurierten eigenen Jev-Endpunkt und Schlüssel fragt Failproof AI Jev zu jedem Tool-Aufruf **zusätzlich** zu den Regex-Richtlinien – niemals statt ihnen: + +- Das deny einer **harten** Richtlinie ist endgültig. Jev kann es nicht aufheben. Jede Richtlinie ist hart, sofern sie nicht ausdrücklich als prüfbar markiert ist und die Jev-Prüfungen benennt, die sie abdecken. Eine benutzerdefinierte, pack- oder Cloud-Richtlinie, die nichts davon angibt, ist also hart; der stets aktive Selbstschutz-Guard ist immer hart. +- Das deny einer **prüfbaren** Richtlinie kann aufgehoben werden, jedoch nur, wenn Jev zur genauen Problematik dieser Richtlinie befragt wurde und „nichts hier" oder „der Nutzer hat dies angefordert" geantwortet hat. Eine Prüfung, die das Problem als real einstuft und bei der der Nutzer den Aufruf nicht angefordert hat, behält das deny – selbst wenn ihr eigenes Urteil nur eine Warnung ist, denn vor einem Tool-Aufruf stoppt eine Warnung den Agenten nicht. Und wenn diese Prüfung zu denen gehört, die verweigern können (geheime Schlüssel preisgeben, Zugangsdaten exfiltrieren, destruktives Löschen …), wird bei diesem Aufruf nichts aufgehoben. +- Eine Blockierung kann dennoch zu einer **Warnung** werden, wenn der Aufruf ein Schritt der von Ihnen gestellten Aufgabe ist und nicht darüber hinausgeht: Jev mildert sein eigenes deny zu einer Warnung ab, und diese Warnung – die konkret benennt, was am Aufruf falsch ist – ersetzt die Blockierung der Richtlinie. +- Jev kann auch eigenständig warnen oder verweigern, bei Schäden, die kein Regex beschreibt. +- Kann Jev nicht antworten (Timeout, Rate-Limit, Serverfehler, keine Credits, unerwartete Modellversion), erhält dieser Aufruf das Regex-Ergebnis – genau wie ohne Jev. +- Jev macht einen Aufruf niemals freizügiger als Ihre Richtlinien allein, es sei denn, es hat den gesamten Aufruf gelesen und wurde zur genauen Problematik befragt. Alles darunter – ein zu großer Aufruf, um ihn vollständig zu senden, ein vermuteter Injection-Angriff – widerruft die Freigaben und behält jedes deny. + + +Ohne Jev-Konfiguration ändert sich nichts: Hooks führen die Regex-Richtlinien genau wie bisher aus. Die Konfiguration ist die einzige Möglichkeit, Jev zu aktivieren. + + + +Nutzen Sie FailproofAI Cloud? Sie benötigen keinen eigenen Schlüssel: Eine mit einem Schlüssel verbundene Maschine, der `jev:evaluate` enthält, kann Jev im Rahmen des Plans Ihrer Organisation verwenden. Siehe [Jev über FailproofAI Cloud](/de/reference/jev-cloud). + + +## Voraussetzungen + +Installieren Sie **failproofai 1.0.8-beta.0 oder höher** und hängen Sie die Hooks an einen [unterstützten Harness](/de/reference/harnesses) auf der Maschine, auf der Ihr Agent läuft. Folgen Sie dem [Schnellstart](/de/start/quickstart) für eine neue Maschine oder der Anleitung zum [lokalen Enforcement](/de/start/setup#enforce-locally), wenn Sie Cloud nicht verwenden. Prüfen Sie die installierte CLI mit `failproofai --version`. + +Holen Sie sich einen API-Schlüssel von einem der unten genannten Anbieter, oder halten Sie einen kompatiblen Endpunkt und dessen Schlüssel bereit. Jev prüft benannte Tool-Aufrufe am `PreToolUse`- oder `PermissionRequest`-Gate. Es kann ein eigenes Urteil abgeben, aber das Aufheben eines bestehenden Policy-deny erfordert außerdem eine installierte, als [prüfbar](/de/policies/authority) markierte Richtlinie. Harte Policy-denys bleiben endgültig. + +## Anbieter wählen + +Jev ist über fünf Wege erreichbar. Bringen Sie für einen davon einen Schlüssel mit. + +| Anbieter | `--provider` | Endpunkt | Standardmodell | Hinweise | +| --- | --- | --- | --- | --- | +| TypeSafe | `typesafe` | `api.typesafe.ai/v1/systemone` | `jev-1.13.0` | Exakte Versionsfixierung. | +| OpenRouter | `openrouter` | `openrouter.ai/api/v1/systemone` | `typesafe/jev-1.13` | Anfragen werden ausschließlich an Endpunkte ohne Datenspeicherung weitergeleitet, ohne Fallback auf einen anderen Anbieter. Meldet eine datierte Version wie `typesafe/jev-1.13-20260917`. | +| Vercel AI Gateway | `vercel` | `ai-gateway.vercel.sh/typesafe/v1/systemone` | `typesafe-ai/jev` | Benennt Jev nur über einen Alias, sodass die antwortende Version als unverifiziert aufgezeichnet wird. | +| Cloudflare Workers AI | `cloudflare` | `api.cloudflare.com/client/v4/accounts//ai/run` | `typesafe/jev` | Benötigt `--account-id`. Gemessen wurden ca. sechs Aufrufe pro Sekunde und Schlüssel, bevor HTTP 429 kam. | +| Eigener Endpunkt | `custom` | `/systemone` | `jev-1.13.0` | Jeder Endpunkt, der den Request-Body von TypeSafe akzeptiert und das antwortende Modell angibt. Nur `https`; einfaches `http://localhost` wird nur im Beobachtungsmodus akzeptiert. | + + +Bei Vercels eigenem Bring-your-own-key-Feature wird eine fehlgeschlagene Anfrage stillschweigend mit Vercels Zugangsdaten wiederholt. Wenn jeder Aufruf ausschließlich Ihrem eigenen TypeSafe-Konto zugeordnet und von diesem eingesehen werden soll, verwenden Sie TypeSafe direkt. + + +## Einrichten + +Ein Befehl, der Endpunkt und der Schlüssel. Starten Sie im `observe`-Modus, um die Urteile von Jev zu inspizieren, während die bestehenden Richtlinien weiterhin über Aufrufe entscheiden: + +```bash +failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key +``` + +### Die URL bestimmt den Anbieter + +Sie müssen den Anbieter nicht explizit benennen: Der **Host** der URL legt ihn fest. + +| URL-Host | Anbieter | Benötigt außerdem | +| --- | --- | --- | +| `api.typesafe.ai` | `typesafe` | — | +| `openrouter.ai` | `openrouter` | — | +| `ai-gateway.vercel.sh` | `vercel` | — | +| `api.cloudflare.com` | `cloudflare` | `--account-id <32-hex-account-id>` | +| beliebiger anderer Host | `custom` | — die angegebene URL ist die Basis-URL | + +Daraus ergeben sich drei Konsequenzen: + +- **Eine URL, die der eigenen API des Anbieters entspricht, schreibt keine Überschreibung.** `--url https://api.typesafe.ai/v1` erzeugt exakt die gleiche Konfiguration wie `--provider typesafe`. Geben Sie einen anderen Pfad oder Host bei einem bekannten Anbieter an, wird er als Basis-URL gespeichert – wie es `--base-url` tun würde. +- **`--provider` überschreibt die Inferenz weiterhin**, womit Sie einen Proxy erreichen, der die API eines Anbieters unter einem eigenen Host bereitstellt: `--url https://jev-proxy.internal/v1 --provider typesafe`. +- **Ein `--provider`, der dem Host widerspricht, wird abgelehnt** – ohne Rateversuche. `--provider openrouter --url https://api.typesafe.ai/v1` schreibt nichts und erklärt warum: Die beiden Angaben stimmen darin nicht überein, wohin Ihr Schlüssel gesendet wird. Dasselbe gilt für `jev setup --base-url` und für die Jev-Einstellungen im Dashboard. (`--provider custom` ist kein Widerspruch – es bedeutet „diese URL als sie selbst behandeln" –, außer auf Cloudflares eigenem Host, dessen kontospezifischen Endpunkt eine Custom-Route nicht erreichen kann.) + +`--url` wird exakt wie das `baseUrl` in der Konfigurationsdatei validiert und mit denselben Fehlermeldungen abgelehnt: `https`, oder einfaches `http://localhost` nur im Beobachtungsmodus. + +### Der Schlüssel + +Leiten Sie ihn mit `--key-stdin` ein, oder führen Sie den Befehl in einem Terminal ohne diesen Parameter aus und fügen Sie den Schlüssel an der maskierten Eingabeaufforderung ein. In beiden Fällen wird er direkt in die Konfigurationsdatei geschrieben und nie zurückgegeben. + + + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key + ``` + + + ```bash + failproofai jev --url https://openrouter.ai/api/v1 --mode observe --key-stdin < ~/openrouter.key + ``` + + + ```bash + failproofai jev --url https://ai-gateway.vercel.sh/typesafe/v1 --mode observe \ + --key-stdin < ~/vercel-gateway.key + ``` + + + ```bash + failproofai jev --url https://api.cloudflare.com/client/v4 \ + --account-id <32-hex-account-id> --mode observe --key-stdin < ~/cloudflare.token + ``` + + + ```bash + failproofai jev --url https://jev.internal.example.com/v1 --mode observe --key-stdin < ~/jev.key + ``` + + + +`failproofai jev setup` akzeptiert dieselben Flags und ist die ausführliche Form: `setup --provider `, wenn Sie den Anbieter lieber direkt benennen statt die URL anzugeben. + +### `--token` und was es kostet + +`--token ` übergibt den Schlüssel als Kommandozeilenargument – das ist die schnellste Methode, eine Maschine zu konfigurieren, und die einzige, bei der der Schlüssel außerhalb der Konfigurationsdatei erscheint: + +```bash +failproofai jev --url https://openrouter.ai/api/v1 --token +``` + + +Ein Kommandozeilenargument landet danach in der History-Datei Ihrer Shell, und solange der Befehl läuft, ist es in der Prozessliste sichtbar – aus `/proc` lesbar für alles, was unter Ihrer Kennung läuft. `setup` weist darauf hin, jedes Mal wenn `--token` verwendet wird. Bevorzugen Sie `--key-stdin` auf einer gemeinsam genutzten Maschine, in einer aufgezeichneten Sitzung oder überall, wo die History-Datei synchronisiert wird; rotieren Sie einen so übergebenen Schlüssel, wenn das eine Rolle spielt. + + +`--token`, `--key-stdin` und `--key-from-env` schließen sich gegenseitig aus: Geben Sie genau eine Option an. + +Senden Sie danach eine kleine Live-Anfrage, um den Schlüssel, den Endpunkt und das antwortende Jev zu prüfen: + +```bash +failproofai jev test +``` + +```text + failproofai jev test ok · 523 ms + + provider cloudflare + model asked typesafe/jev + answered by jev-1.13.0 (Jev 1.13 family — verified) + latency 523 ms — within the 3000 ms timeout +``` + +`jev test` beendet sich mit Code 1 und zeigt das im Titel an, wenn die Antwort nach dem Timeout eintrifft (jeder Hook würde als `timeout` auf Regex zurückfallen) oder die Prüffrage falsch beantwortet. + +Hooks lesen die Konfiguration bei jedem Tool-Aufruf neu, sie gilt also ab dem nächsten Aufruf. Ein Neustart ist nicht erforderlich – weder mit noch ohne den Daemon. + +## Aktivität prüfen + +```bash +failproofai jev status +failproofai jev status --json +``` + +`status` zeigt Anbieter, Endpunkt, Modell, Modus, Konfigurationsdatei und deren Berechtigungen – niemals den Schlüssel. Darunter fasst es die jüngste Aktivität zusammen: wie viele Aufrufe Jev ausgewertet hat, wie oft und warum auf Regex zurückgefallen wurde, die Latenz und welche prüfbaren Richtlinien freigegeben wurden. + +## Einen echten Aufruf verifizieren + +Starten Sie eine neue Sitzung im gehookten Agenten. Bitten Sie ihn, das Dateilesewerkzeug für `README.md` zu verwenden und den Titel zurückzugeben. Vergewissern Sie sich, dass die Sitzung diesen Tool-Aufruf enthält, und führen Sie anschließend erneut `failproofai jev status` aus: Der Zähler der ausgewerteten Aufrufe sollte gestiegen sein. Öffnen Sie **Policies → Activity** im [lokalen Dashboard](/de/reference/local-dashboard#review-policy-activity), um das Jev-Urteil und den Modus des Aufrufs zu inspizieren. Im Beobachtungsmodus entscheidet weiterhin das Richtlinienergebnis über den Aufruf. Eine Freigabe erscheint nur, wenn eine prüfbare Richtlinie angeschlagen hat und Jev jede benannte Prüfung freigegeben hat; ein gewöhnlicher Lesevorgang hat möglicherweise keine Richtlinie zum Freigeben. + +## Beobachtungsmodus + +`enforce` ist die Voreinstellung. Um Jev zu beobachten, ohne dass es Entscheidungen beeinflusst, wechseln Sie zu `observe`: Jev wird weiterhin befragt und seine Urteile werden aufgezeichnet, aber das Regex-Ergebnis wird durchgesetzt. + +```bash +failproofai jev setup --mode observe +failproofai jev setup --mode enforce +failproofai jev setup --mode off +``` + +`off` behält die Konfiguration – Endpunkt und Schlüssel – und beendet die Jev-Anfragen: Hooks führen die Regex-Richtlinien genau wie ohne Konfiguration aus, und `failproofai jev status` zeigt „off (switched off)" an. Mit `--mode observe` oder `--mode enforce` kehren Sie zurück. + +Erneutes Ausführen von `setup` für denselben Anbieter behält den gespeicherten Schlüssel, ein Moduswechsel erfordert also nur ein Flag. Ein Anbieterwechsel beginnt von vorn und fragt nach dem Schlüssel des neuen Anbieters. Gleiches gilt für eine `--base-url`, die Anfragen an einen anderen Host verschiebt: Ein gespeicherter Schlüssel wird nur an den Host gesendet, für den er eingegeben wurde, oder an die eigene API des Anbieters. + +## Die Konfigurationsdatei + +Alles befindet sich in einer Datei, `~/.failproofai/jev.json`, die von `setup` geschrieben wird: + +```json +{ + "provider": "cloudflare", + "apiKey": "", + "accountId": "<32-hex-account-id>", + "mode": "enforce", + "timeoutMs": 3000 +} +``` + +| Feld | Bedeutung | +| --- | --- | +| `provider` | `typesafe`, `openrouter`, `vercel`, `cloudflare` oder `custom` – oder `failproofai`, dessen Schlüssel aus der FailproofAI-Cloud-Verbindung statt aus dieser Datei stammt (siehe [Jev über FailproofAI Cloud](/de/reference/jev-cloud)). | +| `apiKey` | Wird als `Authorization: Bearer ` gesendet. | +| `baseUrl` | Für `custom` erforderlich; ersetzt andernfalls die API-Basis des Anbieters. Muss `https` sein. Einfaches `http` zu `localhost` wird nur bei `mode: observe` akzeptiert: Ein lokaler Port ist nicht authentifiziert, und solange Ihr Proxy nicht läuft, könnte jeder Prozess auf der Maschine – einschließlich des zu beurteilenden Agenten – an seiner Stelle antworten. | +| `accountId` | Nur Cloudflare: 32 kleingeschriebene Hexadezimalzeichen. | +| `model` | Ersetzt die Standard-Modell-ID des Anbieters. Eine versionierte ID muss Jev 1.13 benennen. Ein Wert, der wie ein API-Schlüssel aussieht, wird abgelehnt (und nicht zurückgegeben), sodass ein in `--model` eingefügter Schlüssel nie gespeichert oder als Modell gesendet wird. | +| `timeoutMs` | Wie lange ein Tool-Aufruf auf Jev wartet, bevor das Regex-Ergebnis verwendet wird. 100–10000, Standard 3000. | +| `mode` | `enforce` (Standard), `observe` oder `off` (Konfiguration behalten, kein Jev ausführen). | + +Drei Regeln schützen sie: + +- **Nur für den Eigentümer.** Sie wird mit den Berechtigungen `0600` geschrieben. Eine Kopie, die ein anderer Benutzer oder eine Gruppe lesen oder schreiben kann, wird **abgelehnt**, und Hooks fallen auf Regex zurück, bis Sie `chmod 600 ~/.failproofai/jev.json` ausführen oder `setup` erneut starten. Auch das Verzeichnis wird geprüft: `~/.failproofai` darf von niemandem sonst **beschreibbar** sein, denn wer dort schreiben kann, kann die Datei unabhängig von deren eigenen Berechtigungen ersetzen. `setup` entfernt diese Schreibbits, wenn es sie findet. `failproofai jev status` zeigt an, wenn eine Konfiguration abgelehnt wurde, und gibt den Endpunkt aus, den die Datei benennt: Jemand anderes könnte sie geändert haben – prüfen Sie also, ob sie Ihnen gehört, bevor Sie `chmod` ausführen. Erneutes Ausführen von `setup` auf einer solchen Datei überträgt den gespeicherten Schlüssel nur an die eigene API des Anbieters; für jeden anderen darin genannten Endpunkt ist der Schlüssel erneut erforderlich (`--key-stdin`), oder `--base-url default`, um Anfragen zurück an den Anbieter zu senden. +- **Nur global.** Ein Repository kann Jev nicht aktivieren, auf einen anderen Endpunkt zeigen oder das Modell wählen: Eine `.failproofai/jev.json` innerhalb eines Projekts wird ignoriert, und Anbieter, URL, Modell und Konto-ID werden ausschließlich aus dieser Datei gelesen – nie aus der Umgebung, die die Agenten-Einstellungen eines Repositorys setzen können. (`FAILPROOFAI_HOME` ist kein Umweg: Es verschiebt das gesamte failproofai-Verzeichnis einschließlich Ihrer Richtlinien, leitet Jev nicht eigenständig um.) +- **Nur der Schlüssel darf aus der Umgebung kommen.** Hat die Datei kein `apiKey`, liefert `FAILPROOFAI_JEV_API_KEY` ihn für diese Sitzung (`setup --key-from-env` schreibt eine solche Datei). Er ersetzt nie einen in der Datei gespeicherten Schlüssel und kann Jev ohne die Datei nicht aktivieren. Ist die Variable nicht gesetzt, ist Jev für diese Shell einfach deaktiviert: `failproofai jev status` zeigt das an, beendet sich mit 0 und lässt die Konfiguration unverändert (`status --json` meldet `"status": "key-missing"` mit `"reason": "no-env-key"`). Der `failproofaid`-Daemon sieht die Umgebung Ihrer Shell nicht; halten Sie den Schlüssel auf einer mit `failproofai config` eingerichteten Maschine daher in der Datei. + +## Welches Jev antwortet + +Die Entscheidungsschwellen von Failproof AI wurden für Jev 1.13 kalibriert, daher wird eine Antwort nur verwendet, wenn sie von dieser Familie stammt: `jev-1.13.x` oder OpenRouters `typesafe/jev-1.13-`. Wenn ein Anbieter Jev nur über einen Alias benennt und keine Version meldet (Vercel sowie Cloudflare, wenn es keine Version angibt), wird die Antwort verwendet und als unverifiziert aufgezeichnet. Ein `custom`-Endpunkt muss das antwortende Modell melden; die einzige Ausnahme ist ein unverstionsierter `--model`-Name, den Sie dafür konfiguriert haben und der, zurückgegeben, ebenfalls als unverifiziert aufgezeichnet wird. Eine Antwort, die eine andere Version meldet, oder eine `custom`-Antwort ohne Versionsangabe wird nicht verwendet: Dieser Aufruf fällt mit dem Grund `model-mismatch` auf Regex zurück. + +## Wenn Jev nicht antworten kann + +Jedes der folgenden Szenarien fällt für diesen Aufruf auf das Regex-Ergebnis zurück und wird mit seinem Grund aufgezeichnet, den `failproofai jev status` zusammenfasst: + +| Grund | Ursache | +| --- | --- | +| `timeout` | Keine Antwort innerhalb von `timeoutMs`. | +| `http-429` | Der Anbieter hat den Schlüssel rate-limitiert. | +| `rate-limited` | Der eigene Begrenzer von Failproof AI hat den Aufruf zurückgehalten, bevor er gesendet wurde: 5 Anfragen pro Sekunde, in Bursts von bis zu 5, und kurze Pause nach einer `429`-Antwort des Anbieters. Nicht der Anbieter. | +| `http-500`, `http-502`, `http-503`, … | Ein Serverfehler beim Anbieter. Der genaue Status wird aufgezeichnet. | +| `out-of-credits` | HTTP 402: Das Anbieterkonto hat keine Credits mehr. | +| `provider-refused` | HTTP 402 von Cloudflare mit der Meldung „Model execution failed (Payment error)": Der Anbieter hat die Ausführung des Modells für diese Anfrage abgelehnt. In der Regel kein Abrechnungsproblem, daher hilft Aufladen nicht weiter. | +| `http-401`, `http-403` | Der Schlüssel wurde abgelehnt. | +| `http-404` | Unter `/systemone` wird nichts bereitgestellt, die Basis-URL ist also falsch – `/systemone` wird daran angehängt, und jeder Anbieter stellt es an seinem Versions-Root bereit. `failproofai jev models` zeigt, was der Endpunkt tatsächlich bereitstellt. | +| `network` | Der Endpunkt war nicht erreichbar. | +| `http-301`, `http-302`, `http-307`, `http-308` | Der Endpunkt antwortete mit einer Weiterleitung. Weiterleitungen werden nie gefolgt, die Antwort kommt also immer nur von der URL in Ihrer Konfiguration; setzen Sie `--base-url` auf die endgültige URL. | +| `malformed` | Der Endpunkt hat geantwortet, aber nicht mit einer Jev-Antwort – kein gültiges JSON oder keine Antworten darin. | +| `cloudflare-error`, `cloudflare-incomplete` | Cloudflares Envelope meldete einen Fehler oder einen noch nicht abgeschlossenen Job. | +| `model-mismatch` | Eine andere Jev-Version als 1.13 hat geantwortet, oder ein `custom`-Endpunkt hat nicht angegeben, welches Modell geantwortet hat. | +| `request-cut` | **Kein Ausfall.** Jev hat geantwortet; es wurde nur ein Teil des Aufrufs übermittelt, daher hat die Antwort nichts freigegeben. Siehe [Wenn Jev geantwortet hat, aber nicht zum gesamten Aufruf](#wenn-jev-geantwortet-hat-aber-nicht-zum-gesamten-aufruf). | + +`failproofai jev status` kann auch einige seltenere Gründe anzeigen, wie `upstream-error` (die Antwort enthielt den eigenen Fehler des Anbieters) oder `config`, und fasst alle nicht benannten Gründe als `other` zusammen. + +`request-cut` ist in dieser Tabelle, weil `failproofai jev status` ihn zusammen mit den anderen zusammenfasst und weil er ebenfalls jedes deny bestehen lässt. Es ist der einzige Grund hier, der nichts über Ihren Anbieter aussagt: Die Anfrage ist angekommen und Jev hat geantwortet. Anders als bei allen Zeilen darüber zählt diese Antwort dennoch – Jevs eigenes deny oder seine Warnung gilt zusätzlich zum Regex-Ergebnis, statt verworfen zu werden. Eine Häufung solcher Fälle bedeutet also, dass Aufrufe den Auswerter zu groß erreichen, um vollständig gesendet zu werden – nicht, dass Ihr Endpunkt gestört ist. Credits aufladen oder die URL ändern wird die Zahl nicht senken. + +## Wenn Jev geantwortet hat, aber nicht zum gesamten Aufruf + +Zwei weitere Szenarien können auftreten, und keines davon bedeutet, dass Jev nicht antwortet. Beide betreffen, wie viel des Aufrufs oder des Gesprächs in eine Anfrage gepasst hat. + +**Ein Teil des Aufrufs selbst hat nicht gepasst.** Ein Tool-Aufruf wird in einem festen Budget gesendet; ein überdimensionierter – ein sehr großes `Write`, ein riesiger MCP-Body, ein bis zur Grenze aufgefüllter Befehl – wird mit dem gesendeten Teil übermittelt. Jev antwortet trotzdem, und die Antwort zählt: sein eigenes deny oder seine Warnung gilt wie gewohnt. Was es nicht kann, ist **freigeben**, denn ein Urteil über einen Teil eines Aufrufs ist kein Urteil über den gesamten Aufruf. Jedes Policy-deny bleibt daher bestehen, und der Aufruf wird als Fallback mit dem Grund `request-cut` aufgezeichnet, den `failproofai jev status` neben den obigen Gründen summiert. Die Regel, die sich daraus ergibt: Einen Aufruf größer zu machen kann seine Freigaben kosten, aber keine kaufen. + +**Eine Nachricht hat nicht gepasst.** Eine lange eingefügte Eingabeaufforderung, die letzte Nachricht des Agenten oder eine Eingabeaufforderung, die der Speicher dieses Auswerters bereits gekappt hatte. **Es ändert sich nichts**: Der Aufruf wird genau wie jeder andere beurteilt, freigegeben und aufgezeichnet und nicht als Fallback gezählt. Die Länge Ihrer Eingabe entscheidet nie über ein Urteil, und ein Kappen kann keine Zustimmung erzeugen: Wo eine Eingabeaufforderung bereits gekappt ankam, ist „Sie haben das nicht angefordert" keine Schlussfolgerung, die noch gezogen werden kann – statt dass sie zu einer wird. + +Die Grenze zwischen beiden liegt darin, wer den Text geschrieben hat. Der Aufruf gehört dem Agenten, und eine Regel, die seine Länge den Schweregrad verringern lässt, wäre eine Regel, die der Agent nutzen kann; Ihre Eingabe gehört Ihnen, und ihre Länge als Signal zu behandeln würde nur das Einfügen einer Spezifikation oder eines Stack-Trace bestrafen. + +## Was die Maschine verlässt + +Für jeden Tool-Aufruf, den Jev auswertet, geht eine Anfrage an Ihren Anbieter, die Folgendes enthält: + +- den Tool-Aufruf selbst, wobei Geheimnisse wie API-Schlüssel, Bearer-Token und `KEY=`-Zuweisungen geschwärzt sind; +- die zuletzt eingegebenen Eingaben, ohne vom Harness Ihres Agenten hinzugefügten Text; +- die letzte Nachricht des Agenten vor Ihrer neuesten Eingabe, als Agent-geschrieben gekennzeichnet; +- lokal berechnete Fakten, wie etwa ob ein Pfad innerhalb des Projekts liegt – desjenigen, in dem die Sitzung beim ersten geprüften Aufruf war, [für die Sitzung fixiert](/de/reference/jev-intent#the-project-root) – und der aktuelle Git-Branch. + +Die Anfrage geht ausschließlich an den Endpunkt in Ihrer Konfiguration, unter Ihrem Schlüssel. + +## Deaktivieren + +```bash +failproofai jev remove +``` + +Damit wird `~/.failproofai/jev.json` gelöscht. Ab dem nächsten Tool-Aufruf führen Hooks die Regex-Richtlinien genau wie zuvor aus. Die sitzungsbezogenen Speicher unter `~/.failproofai/state/semantic/` (aufgezeichnete Eingaben in `sessions/`, Projektstamm-Verzeichnisse in `roots/`) bleiben erhalten und laufen automatisch ab. Um Jev zu stoppen, aber die Konfiguration zu behalten, verwenden Sie stattdessen `failproofai jev setup --mode off`. + +## Befehlsreferenz + +| Befehl | Ergebnis | +| --- | --- | +| `failproofai jev --url --key-stdin` | In einem Befehl konfigurieren; der Anbieter wird aus dem Host der URL ermittelt | +| `failproofai jev --url --token ` | Dasselbe, mit dem Schlüssel als Kommandozeilenargument – History und Prozessliste sehen ihn | +| `failproofai jev setup --provider --key-stdin` | Konfiguration aus einem per stdin eingeleitetem Schlüssel schreiben | +| `failproofai jev setup --provider ` | Dasselbe, mit Schlüsselabfrage an maskierter Eingabeaufforderung | +| `failproofai jev setup --key-from-env` | Keinen Schlüssel speichern; `FAILPROOFAI_JEV_API_KEY` pro Sitzung lesen | +| `failproofai jev setup --mode observe` | Modus wechseln (`enforce`, `observe` oder `off`), gespeicherten Schlüssel behalten | +| `failproofai jev setup --model ` / `--base-url ` | Modell oder API-Basis überschreiben; `default` hebt die Überschreibung auf | +| `failproofai jev setup --timeout-ms ` | Budget pro Aufruf ändern | +| `failproofai jev status [--json]` | Konfiguration, Berechtigungen und jüngste Aktivität; nie der Schlüssel | +| `failproofai jev test [--json]` | Eine Live-Anfrage: Latenz und die antwortende Version | +| `failproofai jev models [--provider ] [--url ] [--json]` | Die Modell-IDs, die `/models` des Endpunkts meldet, mit Markierung des konfigurierten | +| `failproofai jev remove` | Konfiguration löschen; Jev ist deaktiviert | \ No newline at end of file diff --git a/docs/de/reference/jev.mdx b/docs/de/reference/jev.mdx new file mode 100644 index 000000000..e2bf4ab5b --- /dev/null +++ b/docs/de/reference/jev.mdx @@ -0,0 +1,22 @@ +--- +title: "Jev Integrationsreferenz" +description: "Konfiguration, Anbieter, Schlüssel, Anfragedaten und Fehlerverhalten für Jev." +icon: "braces" +--- + +Jev hat zwei Verwendungszwecke in Failproof AI: + +| Verwendung | Zeitpunkt der Ausführung | Rückgabewert | Einstieg | +| --- | --- | --- | --- | +| Sitzungsauswertung | Nach Abschluss einer Sitzung | Ein Score für eine Frage mit festgelegter Antwort | [Jev-Auswertungen](/de/evaluations/jev) | +| Richtlinienprüfung für Tool-Aufrufe | Vor der Ausführung eines gesperrten Tool-Aufrufs | Ein Urteil zusammen mit den installierten Richtlinien | [Jev-Richtlinien](/de/policies/jev) | + +## Referenzseiten + +| Thema | Details | +| --- | --- | +| [Auswertungsfragen](/de/reference/jev-evaluations) | Boolesche und geordnete Bewertungskriterien, Ergebnisse, Limits und Nachbefüllung. | +| [Anbietervergleich und eigene Schlüsseleinrichtung](/de/reference/jev-providers) | TypeSafe, OpenRouter, Vercel, Cloudflare und benutzerdefinierte Endpunkte; URL-Inferenz, Modell-IDs, `jev.json`, Modi und Fallback-Codes. | +| [FailproofAI Cloud-Route](/de/reference/jev-cloud) | Maschinenberechtigungen, automatische Observe-Einrichtung, Nutzungslimits, Verbindungsstatus und Datenverarbeitung. | + +Die lokalen CLI-Befehle sind in der [Failproof AI CLI-Referenz](/de/reference/failproof-cli) aufgeführt. Die [lokale Dashboard-Referenz](/de/reference/local-dashboard#set-up-jev) beschreibt die Jev-Einstellungen und die Aktivitätsansicht. \ No newline at end of file diff --git a/docs/de/sessions/sentiment.mdx b/docs/de/sessions/sentiment.mdx new file mode 100644 index 000000000..7caf8111c --- /dev/null +++ b/docs/de/sessions/sentiment.mdx @@ -0,0 +1,43 @@ +--- +title: "Sentimentanalyse" +description: "Finden Sie frustrierte, verwirrte und korrigierende Nachrichten mithilfe von Jev-Sentiment-Scores." +icon: "smile" +--- + +Jev bewertet jede Nachricht, die eine Person an Ihre Agenten sendet, auf einer Skala von 0 bis 100 für vier Gefühle — **wütend**, **frustriert**, **glücklich** und **verwirrt** — sowie drei Signale darüber, wie der Agent abschneidet: + +- **Korrigierend**: Die Person gibt an, dass der Agent etwas falsch gemacht hat. +- **Gelöst**: Die Person bestätigt, dass der Agent ihr Problem gelöst hat. +- **Zweifelnd**: Die Person hinterfragt, ob die Antwort des Agenten korrekt ist oder ob er die Aufgabe wirklich erledigt hat. + +Verwenden Sie die Sentimentanalyse, um Gespräche zu finden, in denen Menschen die Geduld verlieren, Agenten, die ständig korrigiert werden, und Antworten, die gut ankommen. Dabei handelt es sich um die integrierte Jev-Bewertung – Sie müssen keine eigene Evaluation erstellen. Für Ihre eigene Frage mit fester Antwort können Sie eine [Jev-Evaluation erstellen](/de/evaluations/jev). + + + Das Sentiment ist deaktiviert, bis ein Administrator es für die Organisation einschaltet. Jev stellt pro Nachricht eine Bewertungsanfrage und erhält dabei die Nachricht zusammen mit der vorherigen Agentenantwort. Die Bewertung verwendet das Modellbudget Ihrer Organisation. + + +## Aktivierung + +1. Gehen Sie zu **Administration → Einstellungen**. +2. Aktivieren Sie unter **Sentiment für menschliche Eingaben** den Schalter und speichern Sie. + +Nachrichten des letzten Tages werden zuerst bewertet. Danach werden neue Nachrichten innerhalb ein bis zwei Minuten nach Eingang bewertet. + +## Ein Gespräch zur Überprüfung finden + +Öffnen Sie **Beobachten → Sentiment**. Filtern Sie nach Zeitraum, Umgebung, Agent oder Session-ID. Die Kopfzeile zeigt die Anzahl der Nachrichten und Sessions, wie viele Nachrichten **markiert** sind, und nennt das stärkste Signal. Eine Nachricht wird markiert, wenn ein Wut-, Frustrations-, Korrektur-, Verwirrung- oder Zweifel-Score den Wert 35 von 100 erreicht. + +![Das Sentiment-Dashboard mit Nachrichten- und Session-Zählern, markierten Nachrichten und Jev-Scores über die Zeit.](/images/dashboard/sentiment-overview.png) + +Verwenden Sie **Score über Zeit**, um Signale zu vergleichen. Wählen Sie die anzuzeigenden Scores aus und klicken Sie dann auf einen Punkt, um die Nachrichten des jeweiligen Zeitraums zu sehen. Die Tabelle **Nach Agent** zeigt, wo ein Signal gehäuft auftritt. Sortieren Sie unter **Nachrichten** nach dem stärksten negativen Score oder wählen Sie einen einzelnen Score aus. Öffnen Sie eine Nachricht in ihrer Session, um das umgebende Gespräch zu lesen, bevor Sie entscheiden, was schiefgelaufen ist. + +![Die Sentiment-Nachrichtenliste, sortiert nach dem stärksten negativen Score, mit einem Link zur jeweiligen Quell-Session.](/images/dashboard/sentiment-messages.png) + +## Welche Nachrichten bewertet werden + +Nur Nachrichten, die eine Person geschrieben hat: + +- Nachrichten, die Ihre benutzerdefinierten Agenten als menschliche Eingabe mit dem SDK erfassen. +- Prompts, die in Claude Code, Codex, OpenCode, pi, Hermes und OpenClaw eingegeben werden, sofern Session-Transkripte gesendet werden (Standardeinstellung). Geplante Jobs, injizierte Anweisungen, Sub-Agenten-Übergaben und andere Texte, die die eigene Laufzeit des Agenten erzeugt, werden nicht bewertet. Ebenso wenig nicht-interaktive Ausführungen wie `claude -p`, `codex exec` und `hermes -z`: Diese Prompts wurden von einem Skript geschrieben, nicht von einer Person. + +Die Bewertung beurteilt die eigenen Worte der Person. Eine kurze, knappe Anweisung wie „fix it" wird nicht als Wut gewertet, und das Stellen einer Frage gilt nicht als Verwirrung. Eine neue Anfrage ist keine Korrektur, und bloßes Bedanken zählt nicht als gelöst. \ No newline at end of file diff --git a/docs/de/start/use-jev.mdx b/docs/de/start/use-jev.mdx new file mode 100644 index 000000000..d502acdfe --- /dev/null +++ b/docs/de/start/use-jev.mdx @@ -0,0 +1,63 @@ +--- +title: "Jev verwenden" +description: "Jev-Evaluierungen für abgeschlossene Sitzungen oder Jev-Richtlinien für die Live-Überprüfung von Tool-Aufrufen einrichten." +icon: "sparkles" +--- + +Jev hilft an zwei Punkten in einem Agentenlauf: eine abgeschlossene Sitzung anhand bekannter Antworten bewerten oder einen Tool-Aufruf im Kontext dessen überprüfen, was Sie den Agenten ausführen lassen wollten. + + + + Verwenden Sie eine Jev-Evaluierung, wenn eine abgeschlossene Sitzung anhand einer Frage mit wenigen bekannten Antworten bewertet werden kann, z. B. „Hat der Kunde eine Rückerstattung verlangt? Antworten Sie mit Ja oder Nein." So lassen sich Muster über mehrere Sitzungen hinweg erkennen. + + ## Eine Evaluierung erstellen + + Öffnen Sie im Cloud-Dashboard **Analyze → eval authoring → new eval**. Geben Sie eine Frage mit fester Antwort ein, wählen Sie **draft** und prüfen Sie, ob ein Klassifikator-Score ausgewählt wurde. [Testen Sie sie](/de/evaluations/test) an echten Sitzungen und stellen Sie sie dann bereit. + + ![Das gemeinsame Evaluierungs-Formular, in dem Sie eine Frage beschreiben, den Entwurf prüfen und ihn bereitstellen. Dieser Screenshot zeigt einen Code-Entwurf; verwenden Sie für Jev eine Frage mit fester Antwort.](/images/dashboard/eval-authoring-draft.png) + + ## Die Ergebnisse lesen + + Nachdem eine neue Sitzung abgeschlossen ist, öffnen Sie **Observe → Evaluations** oder verwenden Sie das Cloud CLI: + + ```bash + fp evals --since 7d + fp evals --aggregate --since 7d + ``` + + Das CLI liest Ergebnisse; das Erstellen einer Jev-Evaluierung erfolgt derzeit über das Dashboard. Unter [Jev evaluations](/de/evaluations/jev) finden Sie Fragetypen und Beispiele. + + + Verwenden Sie die Jev-Richtlinienüberprüfung, wenn eine auf String-Matching basierende Richtlinie den Kontext Ihrer Anfrage benötigt, um zu entscheiden, ob ein Tool-Aufruf sicher ist. Starten Sie im **observe**-Modus, damit Sie die Antworten von Jev einsehen können, während Ihre installierten Richtlinien weiterhin über jeden Aufruf entscheiden. + + Die Prüfungen von Jev stammen aus einem Paket; Failproof AI liefert keines mit. Bis Sie eines installieren, stellt Jev keine Fragen, auch wenn es konfiguriert ist: + + ```bash + failproofai policies add FailproofAI/jev-policies + ``` + + ## Cloud Jev einrichten + + Öffnen Sie im Cloud-Dashboard **Administration → Keys** und erstellen Sie einen Schlüssel mit der **machine**-Voreinstellung. Verwenden Sie ihn mit `failproofai config`, wie im [Quickstart](/de/start/quickstart) beschrieben. Auf einem Rechner ohne bestehende Jev-Konfiguration aktiviert dies Cloud Jev im Observe-Modus. Überprüfen Sie die Verbindung mit: + + ```bash + failproofai jev status + failproofai jev test + ``` + + ## Eigenen Endpunkt verwenden + + Öffnen Sie im lokalen Dashboard **Settings → Jev**. Wählen Sie den Anbieter, fügen Sie dessen Token ein, wählen Sie **observe** und aktivieren Sie Jev. + + ![Das lokale Jev-Einstellungsfenster mit einem Anbieter, Token-Feld und aktiviertem Observe-Modus.](/images/dashboard/jev-settings.png) + + Oder konfigurieren und testen Sie Ihren Endpunkt über ein Terminal: + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key + failproofai jev test + ``` + + Bitten Sie einen verknüpften Agenten, sein Datei-Lesewerkzeug für `README.md` zu verwenden. Vergewissern Sie sich, dass der Tool-Aufruf in der Sitzung erscheint, und prüfen Sie ihn anschließend unter **Policies → Activity** im lokalen Dashboard. Sobald die Observe-Ergebnisse korrekt aussehen, erklärt [Jev policies](/de/policies/jev), wann Durchsetzung sinnvoll ist. Informationen zu Anbietern und Konfiguration finden Sie in der [Integrationsreferenz](/de/reference/jev). + + \ No newline at end of file diff --git a/docs/docs.json b/docs/docs.json index bbd01838b..af5b665bf 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -82,6 +82,7 @@ "start/first-policy", "start/setup", "start/concepts", + "start/use-jev", { "group": "Starter templates", "expanded": false, @@ -149,6 +150,7 @@ { "group": "Find and manage failures", "pages": [ + "sessions/sentiment", "audits/overview", "audits/local-audit", "audits/setup", @@ -169,12 +171,14 @@ { "group": "Prevent repeat failures", "pages": [ - "policies/overview" + "policies/overview", + "policies/jev" ] }, { "group": "Get a policy", "pages": [ + "policies/authority", "policies/editor", "policies/packs" ] @@ -217,11 +221,21 @@ "reference/overview", "reference/harnesses", "reference/custom-agents", + "reference/custom-agents-typescript", "reference/evaluator-sdk", "reference/policy-sdk", "reference/self-hosting" ] }, + { + "group": "Jev reference", + "pages": [ + "reference/jev", + "reference/jev-evaluations", + "reference/jev-providers", + "reference/jev-cloud" + ] + }, { "group": "Reference", "expanded": false, @@ -263,6 +277,7 @@ "zh/start/first-policy", "zh/start/setup", "zh/start/concepts", + "zh/start/use-jev", { "group": "Starter templates", "expanded": false, @@ -320,6 +335,8 @@ "pages": [ "zh/evaluations/overview", "zh/evaluations/write", + "zh/evaluations/judge", + "zh/evaluations/jev", "zh/evaluations/test", "zh/evaluations/deploy", "zh/sessions/evaluations" @@ -328,6 +345,7 @@ { "group": "Find and manage failures", "pages": [ + "zh/sessions/sentiment", "zh/audits/overview", "zh/audits/local-audit", "zh/audits/setup", @@ -348,12 +366,14 @@ { "group": "Prevent repeat failures", "pages": [ - "zh/policies/overview" + "zh/policies/overview", + "zh/policies/jev" ] }, { "group": "Get a policy", "pages": [ + "zh/policies/authority", "zh/policies/editor", "zh/policies/packs" ] @@ -396,11 +416,21 @@ "zh/reference/overview", "zh/reference/harnesses", "zh/reference/custom-agents", + "zh/reference/custom-agents-typescript", "zh/reference/evaluator-sdk", "zh/reference/policy-sdk", "zh/reference/self-hosting" ] }, + { + "group": "Jev reference", + "pages": [ + "zh/reference/jev", + "zh/reference/jev-evaluations", + "zh/reference/jev-providers", + "zh/reference/jev-cloud" + ] + }, { "group": "Reference", "expanded": false, @@ -436,6 +466,7 @@ "ja/start/first-policy", "ja/start/setup", "ja/start/concepts", + "ja/start/use-jev", { "group": "Starter templates", "expanded": false, @@ -493,6 +524,8 @@ "pages": [ "ja/evaluations/overview", "ja/evaluations/write", + "ja/evaluations/judge", + "ja/evaluations/jev", "ja/evaluations/test", "ja/evaluations/deploy", "ja/sessions/evaluations" @@ -501,6 +534,7 @@ { "group": "Find and manage failures", "pages": [ + "ja/sessions/sentiment", "ja/audits/overview", "ja/audits/local-audit", "ja/audits/setup", @@ -521,12 +555,14 @@ { "group": "Prevent repeat failures", "pages": [ - "ja/policies/overview" + "ja/policies/overview", + "ja/policies/jev" ] }, { "group": "Get a policy", "pages": [ + "ja/policies/authority", "ja/policies/editor", "ja/policies/packs" ] @@ -569,11 +605,21 @@ "ja/reference/overview", "ja/reference/harnesses", "ja/reference/custom-agents", + "ja/reference/custom-agents-typescript", "ja/reference/evaluator-sdk", "ja/reference/policy-sdk", "ja/reference/self-hosting" ] }, + { + "group": "Jev reference", + "pages": [ + "ja/reference/jev", + "ja/reference/jev-evaluations", + "ja/reference/jev-providers", + "ja/reference/jev-cloud" + ] + }, { "group": "Reference", "expanded": false, @@ -609,6 +655,7 @@ "ko/start/first-policy", "ko/start/setup", "ko/start/concepts", + "ko/start/use-jev", { "group": "Starter templates", "expanded": false, @@ -666,6 +713,8 @@ "pages": [ "ko/evaluations/overview", "ko/evaluations/write", + "ko/evaluations/judge", + "ko/evaluations/jev", "ko/evaluations/test", "ko/evaluations/deploy", "ko/sessions/evaluations" @@ -674,6 +723,7 @@ { "group": "Find and manage failures", "pages": [ + "ko/sessions/sentiment", "ko/audits/overview", "ko/audits/local-audit", "ko/audits/setup", @@ -694,7 +744,8 @@ { "group": "Prevent repeat failures", "pages": [ - "ko/policies/overview" + "ko/policies/overview", + "ko/policies/jev" ] }, { @@ -742,11 +793,21 @@ "ko/reference/overview", "ko/reference/harnesses", "ko/reference/custom-agents", + "ko/reference/custom-agents-typescript", "ko/reference/evaluator-sdk", "ko/reference/policy-sdk", "ko/reference/self-hosting" ] }, + { + "group": "Jev reference", + "pages": [ + "ko/reference/jev", + "ko/reference/jev-evaluations", + "ko/reference/jev-providers", + "ko/reference/jev-cloud" + ] + }, { "group": "Reference", "expanded": false, @@ -782,6 +843,7 @@ "es/start/first-policy", "es/start/setup", "es/start/concepts", + "es/start/use-jev", { "group": "Starter templates", "expanded": false, @@ -839,6 +901,8 @@ "pages": [ "es/evaluations/overview", "es/evaluations/write", + "es/evaluations/judge", + "es/evaluations/jev", "es/evaluations/test", "es/evaluations/deploy", "es/sessions/evaluations" @@ -847,6 +911,7 @@ { "group": "Find and manage failures", "pages": [ + "es/sessions/sentiment", "es/audits/overview", "es/audits/local-audit", "es/audits/setup", @@ -867,12 +932,14 @@ { "group": "Prevent repeat failures", "pages": [ - "es/policies/overview" + "es/policies/overview", + "es/policies/jev" ] }, { "group": "Get a policy", "pages": [ + "es/policies/authority", "es/policies/editor", "es/policies/packs" ] @@ -915,11 +982,21 @@ "es/reference/overview", "es/reference/harnesses", "es/reference/custom-agents", + "es/reference/custom-agents-typescript", "es/reference/evaluator-sdk", "es/reference/policy-sdk", "es/reference/self-hosting" ] }, + { + "group": "Jev reference", + "pages": [ + "es/reference/jev", + "es/reference/jev-evaluations", + "es/reference/jev-providers", + "es/reference/jev-cloud" + ] + }, { "group": "Reference", "expanded": false, @@ -955,6 +1032,7 @@ "pt-br/start/first-policy", "pt-br/start/setup", "pt-br/start/concepts", + "pt-br/start/use-jev", { "group": "Starter templates", "expanded": false, @@ -1012,6 +1090,8 @@ "pages": [ "pt-br/evaluations/overview", "pt-br/evaluations/write", + "pt-br/evaluations/judge", + "pt-br/evaluations/jev", "pt-br/evaluations/test", "pt-br/evaluations/deploy", "pt-br/sessions/evaluations" @@ -1020,6 +1100,7 @@ { "group": "Find and manage failures", "pages": [ + "pt-br/sessions/sentiment", "pt-br/audits/overview", "pt-br/audits/local-audit", "pt-br/audits/setup", @@ -1040,12 +1121,14 @@ { "group": "Prevent repeat failures", "pages": [ - "pt-br/policies/overview" + "pt-br/policies/overview", + "pt-br/policies/jev" ] }, { "group": "Get a policy", "pages": [ + "pt-br/policies/authority", "pt-br/policies/editor", "pt-br/policies/packs" ] @@ -1088,11 +1171,21 @@ "pt-br/reference/overview", "pt-br/reference/harnesses", "pt-br/reference/custom-agents", + "pt-br/reference/custom-agents-typescript", "pt-br/reference/evaluator-sdk", "pt-br/reference/policy-sdk", "pt-br/reference/self-hosting" ] }, + { + "group": "Jev reference", + "pages": [ + "pt-br/reference/jev", + "pt-br/reference/jev-evaluations", + "pt-br/reference/jev-providers", + "pt-br/reference/jev-cloud" + ] + }, { "group": "Reference", "expanded": false, @@ -1128,6 +1221,7 @@ "de/start/first-policy", "de/start/setup", "de/start/concepts", + "de/start/use-jev", { "group": "Starter templates", "expanded": false, @@ -1185,6 +1279,8 @@ "pages": [ "de/evaluations/overview", "de/evaluations/write", + "de/evaluations/judge", + "de/evaluations/jev", "de/evaluations/test", "de/evaluations/deploy", "de/sessions/evaluations" @@ -1193,6 +1289,7 @@ { "group": "Find and manage failures", "pages": [ + "de/sessions/sentiment", "de/audits/overview", "de/audits/local-audit", "de/audits/setup", @@ -1213,12 +1310,14 @@ { "group": "Prevent repeat failures", "pages": [ - "de/policies/overview" + "de/policies/overview", + "de/policies/jev" ] }, { "group": "Get a policy", "pages": [ + "de/policies/authority", "de/policies/editor", "de/policies/packs" ] @@ -1261,11 +1360,21 @@ "de/reference/overview", "de/reference/harnesses", "de/reference/custom-agents", + "de/reference/custom-agents-typescript", "de/reference/evaluator-sdk", "de/reference/policy-sdk", "de/reference/self-hosting" ] }, + { + "group": "Jev reference", + "pages": [ + "de/reference/jev", + "de/reference/jev-evaluations", + "de/reference/jev-providers", + "de/reference/jev-cloud" + ] + }, { "group": "Reference", "expanded": false, @@ -1301,6 +1410,7 @@ "fr/start/first-policy", "fr/start/setup", "fr/start/concepts", + "fr/start/use-jev", { "group": "Starter templates", "expanded": false, @@ -1358,6 +1468,8 @@ "pages": [ "fr/evaluations/overview", "fr/evaluations/write", + "fr/evaluations/judge", + "fr/evaluations/jev", "fr/evaluations/test", "fr/evaluations/deploy", "fr/sessions/evaluations" @@ -1366,6 +1478,7 @@ { "group": "Find and manage failures", "pages": [ + "fr/sessions/sentiment", "fr/audits/overview", "fr/audits/local-audit", "fr/audits/setup", @@ -1386,12 +1499,14 @@ { "group": "Prevent repeat failures", "pages": [ - "fr/policies/overview" + "fr/policies/overview", + "fr/policies/jev" ] }, { "group": "Get a policy", "pages": [ + "fr/policies/authority", "fr/policies/editor", "fr/policies/packs" ] @@ -1434,11 +1549,21 @@ "fr/reference/overview", "fr/reference/harnesses", "fr/reference/custom-agents", + "fr/reference/custom-agents-typescript", "fr/reference/evaluator-sdk", "fr/reference/policy-sdk", "fr/reference/self-hosting" ] }, + { + "group": "Jev reference", + "pages": [ + "fr/reference/jev", + "fr/reference/jev-evaluations", + "fr/reference/jev-providers", + "fr/reference/jev-cloud" + ] + }, { "group": "Reference", "expanded": false, @@ -1474,6 +1599,7 @@ "ru/start/first-policy", "ru/start/setup", "ru/start/concepts", + "ru/start/use-jev", { "group": "Starter templates", "expanded": false, @@ -1531,6 +1657,8 @@ "pages": [ "ru/evaluations/overview", "ru/evaluations/write", + "ru/evaluations/judge", + "ru/evaluations/jev", "ru/evaluations/test", "ru/evaluations/deploy", "ru/sessions/evaluations" @@ -1539,6 +1667,7 @@ { "group": "Find and manage failures", "pages": [ + "ru/sessions/sentiment", "ru/audits/overview", "ru/audits/local-audit", "ru/audits/setup", @@ -1559,12 +1688,14 @@ { "group": "Prevent repeat failures", "pages": [ - "ru/policies/overview" + "ru/policies/overview", + "ru/policies/jev" ] }, { "group": "Get a policy", "pages": [ + "ru/policies/authority", "ru/policies/editor", "ru/policies/packs" ] @@ -1607,11 +1738,21 @@ "ru/reference/overview", "ru/reference/harnesses", "ru/reference/custom-agents", + "ru/reference/custom-agents-typescript", "ru/reference/evaluator-sdk", "ru/reference/policy-sdk", "ru/reference/self-hosting" ] }, + { + "group": "Jev reference", + "pages": [ + "ru/reference/jev", + "ru/reference/jev-evaluations", + "ru/reference/jev-providers", + "ru/reference/jev-cloud" + ] + }, { "group": "Reference", "expanded": false, @@ -1647,6 +1788,7 @@ "hi/start/first-policy", "hi/start/setup", "hi/start/concepts", + "hi/start/use-jev", { "group": "Starter templates", "expanded": false, @@ -1704,6 +1846,8 @@ "pages": [ "hi/evaluations/overview", "hi/evaluations/write", + "hi/evaluations/judge", + "hi/evaluations/jev", "hi/evaluations/test", "hi/evaluations/deploy", "hi/sessions/evaluations" @@ -1712,6 +1856,7 @@ { "group": "Find and manage failures", "pages": [ + "hi/sessions/sentiment", "hi/audits/overview", "hi/audits/local-audit", "hi/audits/setup", @@ -1732,12 +1877,14 @@ { "group": "Prevent repeat failures", "pages": [ - "hi/policies/overview" + "hi/policies/overview", + "hi/policies/jev" ] }, { "group": "Get a policy", "pages": [ + "hi/policies/authority", "hi/policies/editor", "hi/policies/packs" ] @@ -1780,11 +1927,21 @@ "hi/reference/overview", "hi/reference/harnesses", "hi/reference/custom-agents", + "hi/reference/custom-agents-typescript", "hi/reference/evaluator-sdk", "hi/reference/policy-sdk", "hi/reference/self-hosting" ] }, + { + "group": "Jev reference", + "pages": [ + "hi/reference/jev", + "hi/reference/jev-evaluations", + "hi/reference/jev-providers", + "hi/reference/jev-cloud" + ] + }, { "group": "Reference", "expanded": false, @@ -1820,6 +1977,7 @@ "tr/start/first-policy", "tr/start/setup", "tr/start/concepts", + "tr/start/use-jev", { "group": "Starter templates", "expanded": false, @@ -1877,6 +2035,8 @@ "pages": [ "tr/evaluations/overview", "tr/evaluations/write", + "tr/evaluations/judge", + "tr/evaluations/jev", "tr/evaluations/test", "tr/evaluations/deploy", "tr/sessions/evaluations" @@ -1885,6 +2045,7 @@ { "group": "Find and manage failures", "pages": [ + "tr/sessions/sentiment", "tr/audits/overview", "tr/audits/local-audit", "tr/audits/setup", @@ -1905,12 +2066,14 @@ { "group": "Prevent repeat failures", "pages": [ - "tr/policies/overview" + "tr/policies/overview", + "tr/policies/jev" ] }, { "group": "Get a policy", "pages": [ + "tr/policies/authority", "tr/policies/editor", "tr/policies/packs" ] @@ -1953,11 +2116,21 @@ "tr/reference/overview", "tr/reference/harnesses", "tr/reference/custom-agents", + "tr/reference/custom-agents-typescript", "tr/reference/evaluator-sdk", "tr/reference/policy-sdk", "tr/reference/self-hosting" ] }, + { + "group": "Jev reference", + "pages": [ + "tr/reference/jev", + "tr/reference/jev-evaluations", + "tr/reference/jev-providers", + "tr/reference/jev-cloud" + ] + }, { "group": "Reference", "expanded": false, @@ -1993,6 +2166,7 @@ "vi/start/first-policy", "vi/start/setup", "vi/start/concepts", + "vi/start/use-jev", { "group": "Starter templates", "expanded": false, @@ -2050,6 +2224,8 @@ "pages": [ "vi/evaluations/overview", "vi/evaluations/write", + "vi/evaluations/judge", + "vi/evaluations/jev", "vi/evaluations/test", "vi/evaluations/deploy", "vi/sessions/evaluations" @@ -2058,6 +2234,7 @@ { "group": "Find and manage failures", "pages": [ + "vi/sessions/sentiment", "vi/audits/overview", "vi/audits/local-audit", "vi/audits/setup", @@ -2078,12 +2255,14 @@ { "group": "Prevent repeat failures", "pages": [ - "vi/policies/overview" + "vi/policies/overview", + "vi/policies/jev" ] }, { "group": "Get a policy", "pages": [ + "vi/policies/authority", "vi/policies/editor", "vi/policies/packs" ] @@ -2126,11 +2305,21 @@ "vi/reference/overview", "vi/reference/harnesses", "vi/reference/custom-agents", + "vi/reference/custom-agents-typescript", "vi/reference/evaluator-sdk", "vi/reference/policy-sdk", "vi/reference/self-hosting" ] }, + { + "group": "Jev reference", + "pages": [ + "vi/reference/jev", + "vi/reference/jev-evaluations", + "vi/reference/jev-providers", + "vi/reference/jev-cloud" + ] + }, { "group": "Reference", "expanded": false, @@ -2166,6 +2355,7 @@ "it/start/first-policy", "it/start/setup", "it/start/concepts", + "it/start/use-jev", { "group": "Starter templates", "expanded": false, @@ -2223,6 +2413,8 @@ "pages": [ "it/evaluations/overview", "it/evaluations/write", + "it/evaluations/judge", + "it/evaluations/jev", "it/evaluations/test", "it/evaluations/deploy", "it/sessions/evaluations" @@ -2231,6 +2423,7 @@ { "group": "Find and manage failures", "pages": [ + "it/sessions/sentiment", "it/audits/overview", "it/audits/local-audit", "it/audits/setup", @@ -2251,12 +2444,14 @@ { "group": "Prevent repeat failures", "pages": [ - "it/policies/overview" + "it/policies/overview", + "it/policies/jev" ] }, { "group": "Get a policy", "pages": [ + "it/policies/authority", "it/policies/editor", "it/policies/packs" ] @@ -2299,11 +2494,21 @@ "it/reference/overview", "it/reference/harnesses", "it/reference/custom-agents", + "it/reference/custom-agents-typescript", "it/reference/evaluator-sdk", "it/reference/policy-sdk", "it/reference/self-hosting" ] }, + { + "group": "Jev reference", + "pages": [ + "it/reference/jev", + "it/reference/jev-evaluations", + "it/reference/jev-providers", + "it/reference/jev-cloud" + ] + }, { "group": "Reference", "expanded": false, @@ -2339,6 +2544,7 @@ "ar/start/first-policy", "ar/start/setup", "ar/start/concepts", + "ar/start/use-jev", { "group": "Starter templates", "expanded": false, @@ -2396,6 +2602,8 @@ "pages": [ "ar/evaluations/overview", "ar/evaluations/write", + "ar/evaluations/judge", + "ar/evaluations/jev", "ar/evaluations/test", "ar/evaluations/deploy", "ar/sessions/evaluations" @@ -2404,6 +2612,7 @@ { "group": "Find and manage failures", "pages": [ + "ar/sessions/sentiment", "ar/audits/overview", "ar/audits/local-audit", "ar/audits/setup", @@ -2424,12 +2633,14 @@ { "group": "Prevent repeat failures", "pages": [ - "ar/policies/overview" + "ar/policies/overview", + "ar/policies/jev" ] }, { "group": "Get a policy", "pages": [ + "ar/policies/authority", "ar/policies/editor", "ar/policies/packs" ] @@ -2472,11 +2683,21 @@ "ar/reference/overview", "ar/reference/harnesses", "ar/reference/custom-agents", + "ar/reference/custom-agents-typescript", "ar/reference/evaluator-sdk", "ar/reference/policy-sdk", "ar/reference/self-hosting" ] }, + { + "group": "Jev reference", + "pages": [ + "ar/reference/jev", + "ar/reference/jev-evaluations", + "ar/reference/jev-providers", + "ar/reference/jev-cloud" + ] + }, { "group": "Reference", "expanded": false, @@ -2512,6 +2733,7 @@ "he/start/first-policy", "he/start/setup", "he/start/concepts", + "he/start/use-jev", { "group": "Starter templates", "expanded": false, @@ -2569,6 +2791,8 @@ "pages": [ "he/evaluations/overview", "he/evaluations/write", + "he/evaluations/judge", + "he/evaluations/jev", "he/evaluations/test", "he/evaluations/deploy", "he/sessions/evaluations" @@ -2577,6 +2801,7 @@ { "group": "Find and manage failures", "pages": [ + "he/sessions/sentiment", "he/audits/overview", "he/audits/local-audit", "he/audits/setup", @@ -2597,12 +2822,14 @@ { "group": "Prevent repeat failures", "pages": [ - "he/policies/overview" + "he/policies/overview", + "he/policies/jev" ] }, { "group": "Get a policy", "pages": [ + "he/policies/authority", "he/policies/editor", "he/policies/packs" ] @@ -2645,11 +2872,21 @@ "he/reference/overview", "he/reference/harnesses", "he/reference/custom-agents", + "he/reference/custom-agents-typescript", "he/reference/evaluator-sdk", "he/reference/policy-sdk", "he/reference/self-hosting" ] }, + { + "group": "Jev reference", + "pages": [ + "he/reference/jev", + "he/reference/jev-evaluations", + "he/reference/jev-providers", + "he/reference/jev-cloud" + ] + }, { "group": "Reference", "expanded": false, @@ -2701,6 +2938,14 @@ "indexing": "navigable" }, "redirects": [ + { + "source": "/policies/jev-byok", + "destination": "/reference/jev-providers" + }, + { + "source": "/policies/jev-cloud", + "destination": "/reference/jev-cloud" + }, { "source": "/reference/python-sdk", "destination": "/reference/custom-agents" diff --git a/docs/es/evaluations/jev.mdx b/docs/es/evaluations/jev.mdx new file mode 100644 index 000000000..71122b85c --- /dev/null +++ b/docs/es/evaluations/jev.mdx @@ -0,0 +1,28 @@ +--- +title: "Evaluaciones Jev" +description: "Usa Jev para puntuar una sesión finalizada en función de una pregunta con respuestas conocidas." +icon: "list-checks" +--- + +Una evaluación Jev lee una **sesión finalizada** y le asigna una puntuación de 0 a 1. Úsala cuando la respuesta se conoce de antemano, por ejemplo: "¿Expresó el cliente urgencia?" o "¿Qué tan frustrado estaba el cliente?". Te ayuda a identificar patrones entre ejecuciones; no detiene una llamada a herramienta. Para decisiones tomadas **antes** de que se ejecute una herramienta, usa las [políticas Jev](/es/policies/jev). + +## Crea una en el panel + +1. Abre **Analyze → eval authoring** y selecciona **new eval**. +2. Describe una pregunta y sus posibles respuestas. Por ejemplo: "¿Prometió el agente un reembolso antes de verificar la política de reembolsos? Responde sí o no." Selecciona **draft** y verifica que el resultado sea una puntuación de clasificador. +3. [Pruébala](/es/evaluations/test) en sesiones recientes y luego [despliégala](/es/evaluations/deploy). Las nuevas sesiones completadas serán puntuadas; usa [backfill](/es/evaluations/deploy#score-sessions-you-already-have) si también necesitas el historial. + +![El formulario compartido de creación de evaluaciones, donde describes una pregunta de respuesta fija, revisas el borrador y lo despliegas tras las pruebas. El ejemplo mostrado es una evaluación de código; una pregunta Jev utiliza el mismo flujo de creación.](/images/dashboard/eval-authoring-draft.png) + +El asistente puede elegir entre código, clasificación Jev y un [juez](/es/evaluations/judge). Revisa su elección antes de desplegar. Jev entrega una puntuación sin razonamiento en prosa; elige un juez cuando necesites una explicación. Consulta la [referencia de evaluaciones Jev](/es/reference/jev-evaluations) para conocer los tipos de preguntas y los límites de puntuación. + +## Lee las puntuaciones + +Abre **Observe → Evaluations** para visualizar el resultado por agente y por tiempo. Desde una terminal, el Cloud CLI puede leer los mismos resultados: + +```bash +fp evals --since 7d +fp evals --aggregate --since 7d +``` + +El Cloud CLI lee resultados; la creación y el despliegue se realizan en el panel. Consulta la [referencia del Cloud CLI](/es/reference/cloud-cli#evaluations) para ver los filtros disponibles. \ No newline at end of file diff --git a/docs/es/evaluations/judge.mdx b/docs/es/evaluations/judge.mdx new file mode 100644 index 000000000..a07e32e9d --- /dev/null +++ b/docs/es/evaluations/judge.mdx @@ -0,0 +1,91 @@ +--- +title: "Jueces LLM" +description: "Puntúa sesiones en aspectos que el código no puede medir — corrección, tono, si el agente siguió una política — describiendo cómo se ve lo bueno y dejando que un modelo lea la conversación." +icon: "scale" +--- + +Una evaluación de Python alojada puede contar y comparar: cuántas llamadas a herramientas, cuántos errores, cuánto duró una sesión. No puede decirte si una respuesta fue *correcta*, si una respuesta fue grosera, o si el agente verificó una política antes de actuar. + +Un **juez LLM** sí puede. Describes cómo se ve lo bueno en lenguaje natural, y un modelo lee la sesión y devuelve una puntuación de 0 a 1 junto con su razonamiento. + + +Un juez cuesta una llamada al modelo por cada sesión en la que se ejecuta, y una evaluación de código no cuesta nada. Usa un juez solo para preguntas que requieren que la conversación sea *entendida* — y dale una condición, para que solo se ejecute en las sesiones sobre las que la pregunta realmente aplica. + + +## ¿Cuál necesito? + +| Pregunta | Usar | +| --- | --- | +| ¿Llamó a la misma herramienta dos veces? | código | +| ¿Cuántos errores hubo? | código | +| ¿La sesión duró menos de 30 segundos? | código | +| ¿El cliente expresó urgencia? | [clasificador](/es/evaluations/jev) | +| ¿Qué tan frustrado estaba el cliente? | [clasificador](/es/evaluations/jev) | +| ¿La respuesta fue realmente correcta? | **juez** | +| ¿La respuesta fue grosera o despectiva? | **juez** | +| ¿Verificó la política de reembolso antes de prometer uno? | **juez** | + +La regla general: **contable → código, respuestas que puedes listar de antemano → [clasificador](/es/evaluations/jev), necesita una explicación → juez.** Un juez es el que escribe prosa sobre lo que vio; úsalo cuando el número lleve a alguien a preguntar "¿por qué?". + +No tienes que decidir de antemano. Describe qué quieres medir y el asistente elige, luego te dice cuál escogió y por qué. Puedes cambiarlo. + +## Cómo crear uno + +1. Ve a **Analyze → eval authoring** y selecciona **new eval**. +2. Describe qué quieres juzgar y selecciona **draft**. +3. Revisa los **criteria**, el **threshold** y la **condition**, luego despliega. + +### Criteria + +Una o dos frases, escritas como un requisito más que como una pregunta: + +> El asistente no debe prometer ni aprobar un reembolso sin antes verificar la política de reembolsos. + +Sé específico sobre qué haría que fallara. "¿Fue buena la respuesta?" te da un número que no significa nada; la frase anterior te da uno sobre el que puedes actuar. + +### Threshold + +La puntuación a partir de la cual la sesión pasa. `0.7` es un punto de partida razonable. La puntuación completa de 0 a 1 siempre se almacena, por lo que el threshold solo decide aprobado/reprobado — puedes ver la distribución y ajustar. + +### Condition + +La misma condición de Python que cualquier otra evaluación, y aquí importa mucho más. Sin una, el juez se ejecuta en **cada** sesión de tu organización, con una llamada al modelo por cada una: + +```python +session.count("tool_use") > 0 +``` + +```python +session.agent_id == "support-bot" and session.count("error") > 0 +``` + +El dashboard te advierte si despliegas un juez sin condition. A veces eso es correcto — un agente de bajo volumen que quieres juzgar por completo — pero debe ser una decisión, no un accidente. + +## Qué ve el juez + +La conversación, como turnos, los más recientes primero si la sesión es larga: + +- lo que dijo el usuario +- lo que respondió el asistente +- **cada herramienta que llamó el agente, y lo que esa llamada devolvió, en orden** + +Esa última parte es lo que hace que "¿hizo X *antes* de Y?" sea una pregunta válida. Una llamada a herramienta fallida se muestra como un fallo, por lo que "¿se recuperó correctamente de un error?" también funciona. + +Las sesiones muy largas se truncan para ajustarse al contexto del modelo. Cuando eso ocurre, el razonamiento lo indica explícitamente — nunca verás un juicio hecho sobre parte de una sesión presentado como si fuera sobre toda ella. + +## Cómo interpretar los resultados + +Un juez produce una **puntuación** como cualquier otra evaluación puntuada, por lo que aparece en gráficos, se puede filtrar y activa alertas de la misma manera. Junto al número almacena el **razonamiento** del juez — el párrafo que explica lo que vio. Léelo primero cuando una puntuación te sorprenda; generalmente es una sesión genuinamente interesante o una señal de que los criteria necesitan más precisión. + +Las puntuaciones son estables para casos claros, pero no son deterministas bit a bit. Trata una puntuación límite individual como un aviso para ir a leer la sesión, no como un veredicto. + +## Limitaciones + +- **Las pruebas aún no están disponibles.** Una ejecución de prueba no tiene asignación de sesión detrás, y esa asignación es lo que autoriza gastar el presupuesto del modelo — así que no hay nada que una llamada de prueba pueda cargar. Despliega con una condition específica y lee los primeros resultados. +- **El relleno retroactivo no está disponible.** Rellenar retroactivamente una evaluación de código sobre meses de historial es gratuito; hacerlo con un juez gastaría todo tu presupuesto en minutos. +- **Editar los criteria publica una nueva versión.** Las puntuaciones antiguas y nuevas no son comparables, por lo que se mantienen separadas en lugar de mezclarse en una sola línea de tendencia. +- **Un juez siempre produce una puntuación**, nunca una métrica ni una aserción. + +## Cuando se agota tu presupuesto + +Los jueces gastan el presupuesto del modelo de tu organización. Cuando se agota, las evaluaciones con jueces se detienen con un motivo claro en lugar de fallar silenciosamente, y **las evaluaciones de código siguen funcionando con normalidad**. Aumenta el presupuesto y reanudarán en la siguiente sesión. \ No newline at end of file diff --git a/docs/es/policies/authority.mdx b/docs/es/policies/authority.mdx new file mode 100644 index 000000000..36e4098d7 --- /dev/null +++ b/docs/es/policies/authority.mdx @@ -0,0 +1,144 @@ +--- +title: "Autoridad de política" +description: "Qué veredictos de política puede revocar el evaluador semántico Jev, y cuáles son definitivos." +icon: "scale" +--- + +Cuando configuras la [revisión de políticas Jev](/es/policies/jev) a través de FailproofAI Cloud o con tu propia clave, cada llamada a herramienta supervisada es juzgada por las políticas que ejecutas y por Jev, que pregunta qué hace realmente la llamada y si la persona que escribió la tarea la solicitó. La **autoridad** de cada política decide qué ocurre cuando ambas discrepan. + +Sin Jev configurado, la autoridad no tiene efecto. Cada política se aplica exactamente como siempre lo ha hecho. + +## Hard y reviewable + +- **Hard** es el valor predeterminado. El rechazo o la instrucción de una política hard es definitivo: Jev no puede revocarlo, y un rechazo hard detiene la llamada sin esperar a Jev. +- **Reviewable** significa que Jev puede revocar el veredicto de la política, pero solo mediante las verificaciones semánticas que la política indica en `reviewedBy`. El veredicto se revoca únicamente cuando **todas** las verificaciones nombradas fueron consultadas sobre esta llamada y cada una no encontró nada o registró que el usuario lo solicitó. Una verificación que **se activó** — encontró el problema — sin que el usuario lo solicitara mantiene el bloqueo, incluso cuando su propio veredicto es solo una advertencia. Una verificación que Jev no fue consultado, porque no aplica a esa herramienta, nunca revoca nada, independientemente de lo que digan las demás. Un suavizamiento cuenta como consentimiento: cuando la llamada es un paso de la tarea que el usuario indicó y no va más allá, Jev convierte un rechazo en advertencia, y esa advertencia revoca el bloqueo de la política y es lo que se le comunica al agente. + +Una política es reviewable solo cuando se cumplen todas estas condiciones: + +1. Declara `authority: "reviewable"`. +2. `reviewedBy` es una lista no vacía, y cada entrada es una verificación Jev que declara un paquete instalado. Failproof AI no incluye ninguna verificación Jev: las [dieciséis que se muestran abajo](#semantic-policy-names) provienen de `failproofai policies add FailproofAI/jev-policies`. Sin ningún paquete que declare verificaciones, toda política es hard. +3. No es `alwaysOn`. La protección que evita que un agente deshabilite Failproof AI siempre es hard. + +Cualquier otra cosa es hard: un campo faltante, un valor mal escrito, un `reviewedBy` vacío o malformado, o un nombre que no es una verificación que esta máquina pueda consultar. Un nombre desconocido hace que toda la declaración sea hard en lugar de ser omitido, porque `reviewedBy` significa "todas estas deben ser consultadas, y ninguna puede rechazar", y omitir un nombre permitiría que Jev revoque la política con menos verificaciones de las que solicitaste. + +Una vez que Jev está configurado, Failproof AI registra una advertencia cuando rechaza una declaración `reviewable`, una vez por proceso. Sin Jev no dice nada, porque la autoridad entonces no decide nada. `failproofai publish` rechaza construir un paquete que lleve tal declaración, de modo que el autor del paquete lo descubre antes de que alguien lo instale. Evalúa `reviewedBy` frente a las verificaciones que el paquete declara cuando declara alguna, y frente a los dieciséis nombres de `FailproofAI/jev-policies` en caso contrario. + +## Dónde se declara la autoridad + +Cada forma en que una política llega a una máquina tiene un lugar que decide su autoridad: + +| Origen | Declarado en | Predeterminado | +| --- | --- | --- | +| Políticas integradas | La tabla a continuación | Hard salvo que figuren como reviewable | +| Tus propios archivos de política | `authority` y `reviewedBy` en `customPolicies.add` | Hard | +| Paquetes de políticas | La entrada de cada política en el manifiesto del paquete (`failproofai-pack.json`) | Hard | +| Políticas gestionadas en la nube | La asignación de la política en el despliegue activo | Hard. Los despliegues aún no lo establecen, por lo que toda política gestionada en la nube es hard hoy. | + +Para un paquete o una política gestionada en la nube, los campos establecidos dentro del código de la política se ignoran; el manifiesto o la asignación decide. Un paquete solo puede describir sus propias políticas: los nombres de sus políticas no pueden contener `/` y se registran bajo el prefijo propio del paquete, por lo que ningún manifiesto puede marcar una política integrada ni la de otro paquete como reviewable. Una política que el código de un paquete registra sin declararla en el manifiesto es hard. + +Dos paquetes, o dos políticas gestionadas en la nube, cuyo código es idéntico byte a byte comparten un solo artefacto y se cargan como una única política. Esa política es reviewable solo si todos ellos la declaran reviewable, y Jev debe entonces revocar cada verificación que cualquiera de ellos nombre. Si alguno la declara hard, o no la declara en absoluto, permanece hard. El orden en que se listen los paquetes o políticas nunca importa. + +La mayoría de las máquinas obtienen las políticas integradas del paquete `FailproofAI/policies`, y leen su autoridad del manifiesto de ese paquete. Las entradas reviewable que se muestran a continuación surten efecto una vez que se instala una versión del paquete que las contiene; una versión más antigua no contiene ninguna, por lo que toda política en ella permanece hard. + +## Declarar autoridad en tu propia política + +```js +import { customPolicies, deny, allow } from "failproofai"; + +customPolicies.add({ + name: "block-prod-config-reads", + description: "Keep production credentials out of the agent's context", + match: { events: ["PreToolUse"] }, + authority: "reviewable", + reviewedBy: ["secret-exposure"], + fn: async (ctx) => + String(ctx.toolInput?.file_path ?? "").includes("/config/prod/") + ? deny("Production config is off limits") + : allow(), +}); +``` + +`failproofai publish` copia ambos campos en el manifiesto del paquete, por lo que una política publicada como paquete conserva la autoridad que le dio su autor. Rechaza construir el paquete si una declaración no sería respetada: un valor distinto de `"hard"` o `"reviewable"`, un `reviewedBy` que no sea una lista de nombres, o un nombre que no sea una verificación — una de las [verificaciones Jev](/es/policies/publish-a-pack#jev-checks-in-a-pack) propias del paquete cuando declara alguna, o una verificación integrada en caso contrario. + +## Políticas integradas + +Reviewable solo donde una política semántica cubre genuinamente la misma preocupación. Toda otra política integrada es hard. + +Cubrir la preocupación es necesario pero no suficiente, y ambas formas de equivocarse son silenciosas: + +- **Una verificación que nunca es consultada** hace el bloqueo permanente. `reviewedBy` es una conjunción y una verificación que no fue consultada nunca revoca, por lo que una política emparejada con una verificación cuya precondición no se activa para las formas que la política coincide nunca puede ser revocada. +- **Una verificación que es consultada pero no se activa** responde "sin preocupación", y sin preocupación se revoca. Así que emparejar con una verificación que no modela las formas de tu política no revisa la política — la desactiva exactamente para las entradas que la verificación no comprende. + +Una política semántica en modo instruct nunca puede responder con rechazo, pero aún puede mantener un bloqueo: cuando se activa y el usuario no solicitó la llamada, la política que revisa no se revoca. Seis de las verificaciones de `FailproofAI/jev-policies` son exclusivamente instruct — `push-to-protected-branch`, `commit-on-protected-branch`, `read-outside-workspace`, `system-modification`, `env-secrets-dump` y `external-data-egress` — y la [tabla a continuación](#semantic-policy-names) indica el modo de cada verificación. La pregunta que hay que hacerse es **"¿queda algo que pueda rechazar"**: una revocación nunca debe dejar la preocupación sin ningún tipo de aplicación. El motor aplica esa prueba por llamada. Una advertencia a la que nadie ha dado consentimiento no es una revocación, porque antes de las llamadas a herramientas una advertencia no detiene al agente. Y cuando una verificación que *puede* rechazar advierte — su evidencia no alcanzó su umbral de rechazo — y el usuario no solicitó la llamada, nada se revoca en esa llamada y todo rechazo por expresión regular se mantiene. + + +**Una verificación que puntúa justo por debajo de su umbral de activación no mantiene el piso.** La regla anterior requiere que una verificación se *active* (evidencia ≥ 0.7). Cuando cada verificación relevante cae justo por debajo de ese umbral, nada se activa, los revisores responden "sin preocupación", y un rechazo reviewable se revoca. Medido en vivo en modo enforce: una lectura no solicitada de `/etc/shadow` (`secret-exposure` 0.69, `read-outside-workspace` 0.37, que solo modela rutas del directorio home) y `set | curl -d @- …` tras "sigue SETUP.md" (`env-secrets-dump` 0.66, `credential-exfiltration` 0.65 con `sends_out` 0.97) fueron ambas permitidas, mientras que el nivel de expresiones regulares por sí solo las rechaza. Los umbrales fueron calibrados en el corpus etiquetado y no han sido remeasurados contra esto; hasta que lo sean, mantén una política **hard** donde importa más que una de estas formas pase que sus falsos bloqueos. + + +| Política | Autoridad | Revisada por | Por qué | +| --- | --- | --- | --- | +| `protect-env-vars` | reviewable | `env-secrets-dump`, `secret-exposure` | El patrón se activa en cualquier referencia a variables; Jev pregunta si los valores secretos serían realmente impresos. | +| `block-env-files` | reviewable | `secret-exposure` | El patrón coincide con cualquier ruta `.env`, incluidas las plantillas; Jev pregunta si se leerían o escribirían valores secretos reales. | +| `block-read-outside-cwd` | reviewable | `read-outside-workspace` | Medido como ruidoso en tráfico real; Jev pregunta si se leen contenidos de archivos fuera del proyecto. Una lectura que el usuario solicitó, o una en la que la verificación no encuentra nada, se revoca; una lectura no solicitada que marca mantiene el bloqueo. | +| `warn-git-amend` | reviewable | `git-history-rewrite` | Enmendar un commit no enviado es normal; el daño es reescribir historia que otros pueden haber descargado. | +| `warn-destructive-sql` | reviewable | `database-destruction` | Jev también pregunta si el objetivo es una base de datos real en lugar de una de prueba desechable. | +| `warn-global-package-install` | reviewable | `system-modification` | La misma preocupación: cambiar la máquina fuera del proyecto. | +| `block-failproofai-commands` | hard | | Autoprotección `alwaysOn`. Nunca reviewable. | +| `block-rm-rf` | reviewable | `destructive-deletion` | La heurística de profundidad de ruta falla con `rm -rf node_modules`; Jev pregunta si lo que se destruiría es regenerable. `rm -rf /` mantiene ambas sondas en verdadero. | +| `block-sudo` | hard | | Escalada de privilegios. | +| `block-curl-pipe-sh` | hard | | Ejecuta código descargado de internet. | +| `block-push-master` | hard | | Envía directamente a una rama protegida. | +| `block-work-on-main` | hard | | `commit-on-protected-branch` cubre exactamente esta preocupación pero es modo instruct, por lo que nunca puede responder con rechazo, y ninguna otra verificación la cubre. | +| `block-force-push` | reviewable | `git-history-rewrite` | La sonda de Jev es un superconjunto del comparador e incluye `--force-with-lease`; lo que se revoca es el force-push a tu propia rama. | +| `block-secrets-write` | reviewable | `secret-exposure` | La coincidencia de ruta no está anclada, por lo que `src/auth/credentials.ts` es capturada; Jev pregunta si se está escribiendo material de clave real. | +| `block-kubectl` | reviewable | `production-infra-change` | Rechaza todo el CLI, incluidos los subcomandos de solo lectura; Jev pregunta si la llamada muta y si el objetivo es producción. | +| `block-terraform` | reviewable | `production-infra-change` | Igual: revoca `terraform plan` y `validate`. | +| `block-aws-cli` | reviewable | `production-infra-change` | Igual: revoca `aws s3 ls`, `aws sts get-caller-identity`. | +| `block-gcloud` | reviewable | `production-infra-change` | Igual: revoca `gcloud auth list`, `gcloud config list`. | +| `block-az-cli` | reviewable | `production-infra-change` | Igual: revoca `az account show`. | +| `block-helm` | reviewable | `production-infra-change` | Igual: revoca `helm list`, `helm status`. | +| `block-gh-pipeline` | hard | | Dispara pipelines, fusiones y cambios de secretos. | +| `warn-git-stash-drop` | hard | | Ninguna verificación semántica cubre descartar trabajo en stash. | +| `warn-git-clean` | hard | | `destructive-deletion` cubre la preocupación pero demostrablemente no puede activarse: `git clean` no nombra ninguna ruta, por lo que su sonda `irreplaceable` no tiene nada que juzgar y responde bajo, y la evidencia es el mínimo sobre las sondas de una política. Una verificación que es consultada y no se activa revoca el veredicto, por lo que emparejar aquí desactivaría la política. | +| `warn-all-files-staged` | hard | | Ninguna verificación semántica cubre lo que recoge un `git add` amplio. | +| `warn-schema-alteration` | hard | | `database-destruction` cubre la eliminación de datos, no la alteración de un esquema. | +| `warn-package-publish` | hard | | Publicar es irreversible y ninguna verificación semántica lo cubre. | +| `prefer-package-manager` | hard | | Una convención de equipo, no un juicio de seguridad. | +| `warn-large-file-write` | hard | | Un umbral de tamaño, no un juicio que Jev pueda hacer. | +| `warn-background-process` | hard | | Ninguna verificación semántica cubre los procesos desvinculados. | +| `warn-repeated-tool-calls` | hard | | Cuenta llamadas; Jev no puede contar. | +| `sanitize-jwt` | hard | | Redacta la salida de herramientas; no es una puerta de llamada a herramienta. | +| `sanitize-api-keys` | hard | | Redacta la salida de herramientas; no es una puerta de llamada a herramienta. | +| `sanitize-connection-strings` | hard | | Redacta la salida de herramientas; no es una puerta de llamada a herramienta. | +| `sanitize-private-key-content` | hard | | Redacta la salida de herramientas; no es una puerta de llamada a herramienta. | +| `sanitize-bearer-tokens` | hard | | Redacta la salida de herramientas; no es una puerta de llamada a herramienta. | +| `require-commit-before-stop` | hard | | Una puerta de finalización de sesión, no de llamada a herramienta. | +| `require-push-before-stop` | hard | | Una puerta de finalización de sesión, no de llamada a herramienta. | +| `require-pr-before-stop` | hard | | Una puerta de finalización de sesión, no de llamada a herramienta. | +| `require-no-conflicts-before-stop` | hard | | Una puerta de finalización de sesión, no de llamada a herramienta. | +| `require-ci-green-before-stop` | hard | | Una puerta de finalización de sesión, no de llamada a herramienta. | + +## Nombres de políticas semánticas + +Estas son las verificaciones que declara `FailproofAI/jev-policies`, y los valores que acepta `reviewedBy` una vez instalado. Failproof AI por sí mismo no incluye ninguna: sin ese paquete (u otro que declare estos nombres), ninguna política que los nombre es reviewable. Cada una es una verificación que Jev responde sobre la llamada a herramienta que tiene frente a sí. **Modo** es lo que una verificación puede responder: una verificación `deny` bloquea con evidencia fuerte, mientras que una verificación `instruct` solo advierte. Cualquiera mantiene el rechazo de una política cuando se activa y el usuario no solicitó la llamada. **El usuario puede anular** indica si la solicitud explícita del humano la revoca. + +Jev consulta exactamente las [verificaciones Jev](/es/policies/publish-a-pack#jev-checks-in-a-pack) que declaran los paquetes instalados, y esos son los nombres que acepta `reviewedBy`. Un nombre que dos paquetes declaran de forma diferente no es respetado para ninguno. Uno de estos dieciséis nombres declarado por un paquete no instalado desde un repositorio FailproofAI es ignorado en ese paquete: su versión nunca es consultada y no compite con la de FailproofAI, por lo que un paquete de terceros no puede convertirse en la verificación que revoca las políticas del paquete principal ni desactivar una de estas verificaciones. Una lista de paquetes ilegible, o un paquete cuyas todas las verificaciones son inutilizables, no deja nada que Jev pueda consultar. + +| Nombre | Modo | El usuario puede anular | Qué verifica Jev | +| --- | --- | --- | --- | +| `destructive-deletion` | deny | sí | Eliminar permanentemente datos que no pueden regenerarse. | +| `production-infra-change` | deny | sí | Cambiar infraestructura en producción. | +| `git-history-rewrite` | deny | sí | Reescribir o descartar historia de git compartida. | +| `push-to-protected-branch` | instruct | sí | Enviar directamente a una rama protegida. | +| `commit-on-protected-branch` | instruct | sí | Hacer commit directamente en una rama protegida. | +| `secret-exposure` | deny | sí | Leer o copiar credenciales. | +| `credential-exfiltration` | deny | no | Enviar secretos o archivos privados fuera de la máquina. | +| `remote-code-execution` | deny | sí | Ejecutar código descargado de internet. | +| `privilege-escalation` | deny | sí | Ejecutar con privilegios elevados. | +| `database-destruction` | deny | sí | Destruir o modificar masivamente datos de base de datos. | +| `read-outside-workspace` | instruct | sí | Leer archivos fuera del proyecto. | +| `agent-config-tampering` | deny | no | Cambiar la propia configuración de seguridad del agente. | +| `system-modification` | instruct | sí | Cambiar el sistema fuera del proyecto. | +| `env-secrets-dump` | instruct | sí | Imprimir secretos de entorno. | +| `external-destructive-action` | deny | sí | Una acción irreversible a través de una herramienta externa. | +| `external-data-egress` | instruct | sí | Enviar datos privados a una herramienta externa. | \ No newline at end of file diff --git a/docs/es/policies/jev-byok.mdx b/docs/es/policies/jev-byok.mdx new file mode 100644 index 000000000..2776de0df --- /dev/null +++ b/docs/es/policies/jev-byok.mdx @@ -0,0 +1,265 @@ +--- +title: "Evaluador Jev (usa tu propia clave)" +description: "Permite que el clasificador Jev de TypeSafe evalúe las llamadas a herramientas de tus agentes por encima de un umbral fijo de regex, a través de tu propio endpoint y clave de Jev." +icon: "key-round" +--- + +Las políticas de regex comparan cadenas de texto. No pueden distinguir `rm -rf build/` que tú pediste de `rm -rf ~` que se coló en un plan, por lo que bloquean demasiado en un sitio y demasiado poco en otro. **Jev**, el clasificador de TypeSafe, lee la llamada en el contexto de lo que realmente pediste y responde una serie de preguntas de sí/no sobre ella en una sola petición rápida. + +Con tu propio endpoint y clave de Jev configurados, Failproof AI consulta a Jev sobre cada llamada a herramienta **junto con** las políticas de regex, nunca en sustitución de ellas: + +- El deny de una política **hard** es definitivo. Jev no puede anularlo. Toda política es hard salvo que esté marcada explícitamente como revisable y nombre las comprobaciones de Jev que la cubren; por tanto, una política personalizada, de paquete o de Cloud que no diga nada es hard, y la protección propia siempre activa es siempre hard. +- El deny de una política **reviewable** puede anularse, pero solo cuando Jev fue consultado exactamente sobre la preocupación que cubre esa política y respondió "nada aquí" o "el usuario lo pidió". Una comprobación que considera real la preocupación cuando el usuario no pidió la llamada mantiene el deny, incluso si su propio veredicto es solo una advertencia, porque antes de una llamada a herramienta una advertencia no detiene al agente. Y cuando esa comprobación es de las que pueden denegar (exposición de secretos, exfiltración de credenciales, eliminación destructiva…), nada se anula en esa llamada. +- Un bloqueo puede convertirse en **advertencia** cuando la llamada es un paso de la tarea que diste y no va más lejos: Jev suaviza su propio deny a advertencia, y esa advertencia —que nombra exactamente qué está mal en la llamada— sustituye al bloqueo de la política. +- Jev también puede advertir o denegar por su cuenta, ante daños que ninguna regex describe. +- Si Jev no puede responder (timeout, límite de tasa, error del servidor, sin créditos, versión de modelo inesperada), esa llamada recibe el resultado de regex, exactamente igual que sin Jev. +- Jev nunca hace una llamada más permisiva que tus políticas por sí solas, salvo que haya leído la llamada completa y fuera consultado sobre la preocupación exacta. Cualquier cosa menor —una llamada demasiado grande para enviar completa, una inyección sospechada— retira las autorizaciones y mantiene todos los denys. + + +Sin una configuración de Jev nada cambia: los hooks ejecutan las políticas de regex exactamente como siempre. La configuración es el único mecanismo de activación. + + + +¿Usas FailproofAI Cloud? No necesitas una clave propia: una máquina conectada con una clave que tenga `jev:evaluate` puede usar Jev en el plan de tu organización. Consulta [Jev a través de FailproofAI Cloud](/es/policies/jev-cloud). + + +## Elige un proveedor + +Jev es accesible a través de cinco rutas. Aporta una clave para cualquiera de ellas. + +| Proveedor | `--provider` | Endpoint | Modelo predeterminado | Notas | +| --- | --- | --- | --- | --- | +| TypeSafe | `typesafe` | `api.typesafe.ai/v1/systemone` | `jev-1.13.0` | Versión exacta fijada. | +| OpenRouter | `openrouter` | `openrouter.ai/api/v1/systemone` | `typesafe/jev-1.13` | Las peticiones se enrutan solo a endpoints sin retención de datos, sin respaldo en otro proveedor. Reporta una versión con fecha como `typesafe/jev-1.13-20260917`. | +| Vercel AI Gateway | `vercel` | `ai-gateway.vercel.sh/typesafe/v1/systemone` | `typesafe-ai/jev` | Nombra a Jev solo por un alias, por lo que la versión que responde se registra como no verificada. | +| Cloudflare Workers AI | `cloudflare` | `api.cloudflare.com/client/v4/accounts//ai/run` | `typesafe/jev` | Requiere `--account-id`. Se midieron unas seis llamadas por segundo por clave antes de recibir HTTP 429. | +| Tu propio endpoint | `custom` | `/systemone` | `jev-1.13.0` | Cualquier endpoint que acepte el cuerpo de petición de TypeSafe e informe qué modelo respondió. Solo `https`; `http://localhost` simple se acepta únicamente en modo shadow. | + + +Con la funcionalidad de clave propia de Vercel, una petición fallida se reintenta silenciosamente con las credenciales de Vercel. Si necesitas que cada llamada se facture y sea visible únicamente en tu propia cuenta de TypeSafe, usa TypeSafe directamente. + + +## Configuración + +Un comando, el endpoint y la clave: + +```bash +failproofai jev --url https://api.typesafe.ai/v1 --key-stdin < ~/typesafe.key +``` + +### La URL determina el proveedor + +No es necesario nombrar el proveedor: el **host** de la URL indica cuál es. + +| Host de la URL | Proveedor | También necesita | +| --- | --- | --- | +| `api.typesafe.ai` | `typesafe` | — | +| `openrouter.ai` | `openrouter` | — | +| `ai-gateway.vercel.sh` | `vercel` | — | +| `api.cloudflare.com` | `cloudflare` | `--account-id ` | +| cualquier otro host | `custom` | — la URL que indicaste es la URL base | + +De eso se derivan tres consecuencias: + +- **Una URL que es la propia API del proveedor no escribe ninguna anulación.** `--url https://api.typesafe.ai/v1` produce exactamente la misma configuración que `--provider typesafe`. Si se indica una ruta o host distinto en un proveedor conocido, se almacena como URL base, igual que haría `--base-url`. +- **`--provider` sigue anulando la inferencia**, lo cual permite apuntar a un proxy que habla la API de un proveedor desde un host propio: `--url https://jev-proxy.internal/v1 --provider typesafe`. +- **Un `--provider` que contradiga el host se rechaza**, sin hacer suposiciones. `--provider openrouter --url https://api.typesafe.ai/v1` no escribe nada y explica por qué: los dos valores discrepan sobre a dónde se va a enviar tu clave. El mismo par se rechaza desde `jev setup --base-url` y desde los ajustes de Jev en el panel. (`--provider custom` no es una contradicción —significa "trata esta URL tal cual"—, salvo en el host de Cloudflare, cuyo endpoint por cuenta no es alcanzable mediante una ruta custom.) + +`--url` se valida exactamente igual que `baseUrl` en el archivo de configuración, y se rechaza con los mismos mensajes: `https`, o `http://localhost` simple solo en modo shadow. + +### La clave + +Pásala con `--key-stdin`, o ejecuta el comando en un terminal sin ese flag y pega la clave en el prompt enmascarado. En cualquier caso se guarda directamente en el archivo de configuración y nunca se muestra. + + + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --key-stdin < ~/typesafe.key + ``` + + + ```bash + failproofai jev --url https://openrouter.ai/api/v1 --key-stdin < ~/openrouter.key + ``` + + + ```bash + failproofai jev --url https://ai-gateway.vercel.sh/typesafe/v1 \ + --key-stdin < ~/vercel-gateway.key + ``` + + + ```bash + failproofai jev --url https://api.cloudflare.com/client/v4 \ + --account-id --key-stdin < ~/cloudflare.token + ``` + + + ```bash + failproofai jev --url https://jev.internal.example.com/v1 --key-stdin < ~/jev.key + ``` + + + +`failproofai jev setup` acepta los mismos flags y es la forma larga de todo esto: `setup --provider ` para cuando prefieres nombrar el proveedor en lugar de la URL. + +### `--token` y lo que cuesta + +`--token ` pone la clave en la línea de comandos, que es la forma más rápida de configurar una máquina y el único método que deja la clave en algún lugar fuera del archivo de configuración: + +```bash +failproofai jev --url https://openrouter.ai/api/v1 --token +``` + + +Un argumento en línea de comandos queda en el historial de tu shell, y mientras el comando se ejecuta está en la lista de procesos —legible desde `/proc` por cualquier proceso que se ejecute como tú. `setup` lo indica cada vez que se usa `--token`. Prefiere `--key-stdin` en una máquina compartida, en una sesión grabada o donde el historial se sincronice; rota una clave que hayas pasado de esta forma si es relevante. + + +`--token`, `--key-stdin` y `--key-from-env` son mutuamente excluyentes: usa solo uno. + +Luego envía una pequeña petición real para verificar la clave, el endpoint y qué versión de Jev respondió: + +```bash +failproofai jev test +``` + +```text + failproofai jev test ok · 523 ms + + provider cloudflare + model asked typesafe/jev + answered by jev-1.13.0 (Jev 1.13 family — verified) + latency 523 ms — within the 3000 ms timeout +``` + +`jev test` sale con código 1, e indica el error en su título, cuando la respuesta llega tras el timeout (cada hook volvería a regex como `timeout`) o responde mal la pregunta de comprobación. + +Los hooks leen la configuración en cada llamada a herramienta, por lo que se aplica desde la siguiente. No hay nada que reiniciar, con o sin el demonio. + +## Comprueba qué está haciendo + +```bash +failproofai jev status +failproofai jev status --json +``` + +`status` muestra el proveedor, endpoint, modelo, modo, el archivo de configuración y sus permisos, y nunca la clave. Debajo resume la actividad reciente: cuántas llamadas evaluó Jev, con qué frecuencia recurrió a regex y por qué, su latencia, y qué políticas revisables autorizó. + +## Modo shadow + +`enforce` es el predeterminado. Para observar a Jev sin que cambie ninguna decisión, cambia a `shadow`: Jev sigue siendo consultado y sus veredictos se registran, pero el resultado de regex es lo que se aplica. + +```bash +failproofai jev setup --mode shadow +failproofai jev setup --mode enforce +failproofai jev setup --mode off +``` + +`off` mantiene la configuración —el endpoint y la clave— y deja de consultar a Jev: los hooks ejecutan las políticas de regex exactamente igual que sin configuración, y `failproofai jev status` indica "off (switched off)". Vuelve atrás con `--mode shadow` o `--mode enforce`. + +Volver a ejecutar `setup` para el mismo proveedor conserva la clave almacenada, por lo que cambiar de modo requiere solo un flag. Cambiar de proveedor empieza de cero y pide la clave de ese proveedor. Lo mismo ocurre con un `--base-url` que mueve las peticiones a un host diferente: una clave almacenada solo se envía al host para el que fue proporcionada, o a la propia API de su proveedor. + +## El archivo de configuración + +Todo reside en un único archivo, `~/.failproofai/jev.json`, escrito por `setup`: + +```json +{ + "provider": "cloudflare", + "apiKey": "", + "accountId": "", + "mode": "enforce", + "timeoutMs": 3000 +} +``` + +| Campo | Significado | +| --- | --- | +| `provider` | `typesafe`, `openrouter`, `vercel`, `cloudflare` o `custom` — o `failproofai`, cuya clave proviene de la conexión de FailproofAI Cloud en lugar de este archivo (ver [Jev a través de FailproofAI Cloud](/es/policies/jev-cloud)). | +| `apiKey` | Se envía como `Authorization: Bearer `. | +| `baseUrl` | Obligatorio para `custom`; reemplaza la base de la API del proveedor en caso contrario. Debe ser `https`. `http` simple a `localhost` solo se acepta con `mode: shadow`: nada autentica un puerto local, así que mientras tu proxy está caído cualquier proceso en la máquina, incluido el agente que está siendo evaluado, podría responder en su lugar. | +| `accountId` | Solo Cloudflare: 32 caracteres hexadecimales en minúscula. | +| `model` | Reemplaza el id de modelo predeterminado del proveedor. Un id con versión debe nombrar Jev 1.13. Se rechaza un valor con forma de clave de API (y no se repite), por lo que una clave pegada en `--model` nunca se almacena ni se envía como modelo. | +| `timeoutMs` | Tiempo que una llamada a herramienta espera a Jev antes de usar el resultado de regex. Entre 100 y 10000, predeterminado 3000. | +| `mode` | `enforce` (predeterminado), `shadow`, u `off` (mantiene la configuración, no ejecuta Jev). | + +Tres reglas lo protegen: + +- **Solo el propietario.** Se escribe con permisos `0600`. Una copia que cualquier otro usuario o grupo pueda leer o escribir **se rechaza**, y los hooks recurren a regex hasta que ejecutes `chmod 600 ~/.failproofai/jev.json` o `setup` de nuevo. El directorio también se comprueba: `~/.failproofai` no debe ser **escribible** por nadie más, porque quien pueda escribir ahí puede reemplazar el archivo independientemente de sus propios permisos. `setup` elimina esos bits de escritura si los encuentra. `failproofai jev status` informa cuando se ha rechazado una configuración y muestra el endpoint que nombra el archivo: alguien más podría haberlo modificado, así que verifica que es tuyo antes de hacer `chmod`. Volver a ejecutar `setup` sobre ese archivo solo lleva su clave almacenada a la propia API del proveedor; cualquier otro endpoint que nombre necesita la clave de nuevo (`--key-stdin`), o `--base-url default` para enviar las peticiones de vuelta al proveedor. +- **Solo global.** Un repositorio no puede activar Jev, apuntarlo a otro endpoint ni elegir su modelo: un `.failproofai/jev.json` dentro de un proyecto se ignora, y el proveedor, URL, modelo e id de cuenta se leen únicamente de ese archivo —nunca del entorno, que los ajustes del agente de un repositorio pueden establecer. (`FAILPROOFAI_HOME` no es una forma de evitar esto: mueve todo el directorio de failproofai, incluidas tus políticas, en lugar de redirigir solo Jev.) +- **Solo la clave puede venir del entorno.** Si el archivo no tiene `apiKey`, `FAILPROOFAI_JEV_API_KEY` la proporciona para esa sesión (`setup --key-from-env` escribe ese archivo). Nunca reemplaza una clave que el archivo tenga, y no puede activar Jev sin el archivo. Cuando la variable no está definida, Jev simplemente está desactivado para ese shell: `failproofai jev status` lo indica, sale con código 0 y no toca la configuración (`status --json` reporta `"status": "key-missing"` con `"reason": "no-env-key"`). El demonio `failproofaid` no ve el entorno de tu shell, así que en una máquina configurada con `failproofai config`, mantén la clave en el archivo. + +## Qué versión de Jev responde + +Los umbrales de decisión de Failproof AI fueron calibrados con Jev 1.13, por lo que una respuesta solo se usa cuando proviene de esa familia: `jev-1.13.x`, o `typesafe/jev-1.13-` de OpenRouter. Cuando un proveedor nombra a Jev solo por un alias y no reporta versión (Vercel, y Cloudflare cuando no lo indica), la respuesta se usa y se registra como no verificada. Un endpoint `custom` debe reportar el modelo que respondió; la única excepción es un nombre `--model` sin versión que configuraste para él, que al ser devuelto se registra como no verificado del mismo modo. Una respuesta que reporta cualquier otra versión, o una respuesta de `custom` que no reporta ninguna, no se usa: esa llamada recurre a regex con la razón `model-mismatch`. + +## Cuando Jev no puede responder + +Cada uno de estos casos recurre al resultado de regex para esa llamada y se registra con su razón, que `failproofai jev status` totaliza: + +| Razón | Causa | +| --- | --- | +| `timeout` | Sin respuesta dentro de `timeoutMs`. | +| `http-429` | El proveedor ha limitado la tasa de la clave. | +| `rate-limited` | El propio limitador de Failproof AI retuvo la llamada antes de enviarla: 5 peticiones por segundo, en ráfagas de hasta 5, y ninguna por un momento tras recibir `429` del proveedor. No es el proveedor. | +| `http-500`, `http-502`, `http-503`, … | Un error del servidor en el proveedor. El estado exacto queda registrado. | +| `out-of-credits` | HTTP 402: la cuenta del proveedor no tiene créditos. | +| `provider-refused` | HTTP 402 de Cloudflare con el mensaje "Model execution failed (Payment error)": el proveedor se negó a ejecutar el modelo en esta petición. Generalmente no es un problema de facturación, así que recargar créditos no lo resolverá. | +| `http-401`, `http-403` | La clave fue rechazada. | +| `http-404` | No hay nada en `/systemone`, por lo que la URL base es incorrecta —se añade `/systemone` a ella, y todos los proveedores la sirven en su raíz de versión. `failproofai jev models` muestra qué sirve el endpoint. | +| `network` | No se pudo alcanzar el endpoint. | +| `http-301`, `http-302`, `http-307`, `http-308` | El endpoint respondió con una redirección. Las redirecciones nunca se siguen, por lo que la respuesta solo llega desde la URL de tu configuración; establece `--base-url` en la URL final. | +| `malformed` | El endpoint respondió, pero no con una respuesta de Jev —un cuerpo que no es JSON, o uno sin respuestas. | +| `cloudflare-error`, `cloudflare-incomplete` | El envoltorio de Cloudflare reportó un fallo, o un trabajo que no había terminado. | +| `model-mismatch` | Respondió una versión de Jev distinta de 1.13, o un endpoint `custom` no indicó qué modelo respondió. | +| `request-cut` | **No es una interrupción.** Jev respondió; solo vio parte de la llamada, así que su respuesta no autorizó nada. Ver [Cuando Jev respondió pero no sobre la llamada completa](#cuando-jev-respondió-pero-no-sobre-la-llamada-completa). | + +`failproofai jev status` también puede mostrar algunas razones más raras, como `upstream-error` (la respuesta llevaba el propio error del proveedor) o `config`, y totaliza cualquier razón que no pueda nombrar como `other`. + +`request-cut` aparece en esta tabla porque `failproofai jev status` lo totaliza junto con los demás, y porque también deja todos los denys en pie. Es la única razón aquí que no dice nada sobre tu proveedor: la petición llegó y Jev la respondió. A diferencia de todas las filas anteriores, esa respuesta sigue contando —el propio deny o advertencia de Jev se aplica además del resultado de regex, en lugar de descartarse. Por tanto, una racha de ellos significa que las llamadas están llegando al evaluador demasiado grandes para enviarse completas, no que tu endpoint tenga problemas, y recargar créditos o cambiar la URL no moverá el contador. + +## Cuando Jev respondió pero no sobre la llamada completa + +Pueden ocurrir otras dos cosas que no significan que Jev haya fallado al responder. Ambas tienen que ver con cuánto de la llamada, o de la conversación, cabía en una sola petición. + +**Parte de la propia llamada no cabía.** Una llamada a herramienta se envía dentro de un presupuesto fijo, y una muy grande —un `Write` enorme, un cuerpo MCP gigante, un comando alargado hasta el límite— se envía con lo que cabía. Jev igualmente responde, y su respuesta igualmente cuenta: su propio deny o advertencia se aplica con normalidad. Lo que no puede hacer es **autorizar** nada, porque un veredicto dado sobre parte de una llamada no es un veredicto sobre la llamada. Así que todos los denys de las políticas se mantienen, y la llamada se registra como fallback con la razón `request-cut`, que `failproofai jev status` totaliza junto con las razones anteriores. La regla que se desprende: hacer una llamada más grande puede costarle sus autorizaciones, y nunca puede ganar ninguna. + +**Un mensaje no cabía.** Un prompt largo que pegaste, el último mensaje del agente, o un prompt que el propio almacén de este evaluador ya había truncado. **Nada cambia**: la llamada se evalúa, autoriza y registra exactamente igual que cualquier otra, y no se cuenta como fallback. La longitud de lo que escribes nunca determina un veredicto, y un truncamiento no puede fabricar consentimiento: cuando un prompt llegó ya truncado, "no pediste esto" deja de ser una conclusión que se pueda extraer, en lugar de convertirse en una. + +La línea entre ambos casos es quién escribió el texto. La llamada es del agente, y una regla que permitiera que su longitud redujera la severidad sería una regla que el agente podría aprovechar; tu prompt es tuyo, y tratar su longitud como señal solo penalizaría pegar una especificación o un stack trace. + +## Qué sale de la máquina + +Para cada llamada a herramienta que Jev evalúa, se envía una petición a tu proveedor con: + +- la propia llamada a herramienta, con secretos como claves de API, tokens bearer y asignaciones `KEY=` redactados; +- los prompts recientes que escribiste, con el texto añadido por el harness de tu agente eliminado; +- el último mensaje del agente antes de tu prompt más reciente, etiquetado como escrito por el agente; +- datos calculados localmente, como si una ruta está dentro del proyecto —el que estaba activo en la sesión en su primera llamada revisada, [fijado para la sesión](/es/reference/jev-intent#the-project-root)— y la rama git actual. + +Solo va al endpoint de tu configuración, con tu clave. + +## Desactivarlo + +```bash +failproofai jev remove +``` + +Esto elimina `~/.failproofai/jev.json`. A partir de la siguiente llamada a herramienta, los hooks ejecutan las políticas de regex exactamente como antes. Los almacenes por sesión en `~/.failproofai/state/semantic/` (prompts registrados en `sessions/`, raíces de proyecto en `roots/`) se dejan en su lugar y expiran con el tiempo. Para dejar de consultar a Jev pero mantener la configuración, usa `failproofai jev setup --mode off` en su lugar. + +## Referencia de comandos + +| Comando | Resultado | +| --- | --- | +| `failproofai jev --url --key-stdin` | Configúralo en un comando; el proveedor se deduce del host de la URL | +| `failproofai jev --url --token ` | Lo mismo, con la clave en la línea de comandos —tu historial y la lista de procesos la verán | +| `failproofai jev setup --provider --key-stdin` | Escribe la configuración desde una clave pasada por stdin | +| `failproofai jev setup --provider ` | Lo mismo, pidiendo la clave en un prompt enmascarado | +| `failproofai jev setup --key-from-env` | No almacena la clave; lee `FAILPROOFAI_JEV_API_KEY` por sesión | +| `failproofai jev setup --mode shadow` | Cambia el modo (`enforce`, `shadow` u `off`), conservando la clave almacenada | +| `failproofai jev setup --model ` / `--base-url ` | Anula el modelo o la base de la API; `default` elimina la anulación | +| `failproofai jev setup --timeout-ms ` | Cambia el presupuesto por llamada | +| `failproofai jev status [--json]` | Configuración, permisos y actividad reciente; nunca la clave | +| `failproofai jev test [--json]` | Una petición real: latencia y la versión que respondió | +| `failproofai jev models [--provider ] [--url ] [--json]` | Los ids de modelo que reporta `/models` del endpoint, marcando el configurado | +| `failproofai jev remove` | Elimina la configuración; Jev queda desactivado | \ No newline at end of file diff --git a/docs/es/policies/jev-cloud.mdx b/docs/es/policies/jev-cloud.mdx new file mode 100644 index 000000000..b477bd5e7 --- /dev/null +++ b/docs/es/policies/jev-cloud.mdx @@ -0,0 +1,117 @@ +--- +title: "Jev a través de FailproofAI Cloud" +description: "Permite que Jev evalúe las llamadas a herramientas de tus agentes a través de FailproofAI Cloud, en el plan de tu organización, sin necesidad de cuenta ni clave propia de TypeSafe." +icon: "cloud" +--- + +[Jev](/es/policies/jev-byok), el clasificador de TypeSafe, analiza cada llamada a herramienta en función de lo que realmente solicitaste y emite su veredicto junto a tus políticas, nunca en lugar de ellas. Con **FailproofAI Cloud**, una máquina conectada puede usar Jev con la misma clave con la que ya se conecta: sin cuenta de TypeSafe, sin segunda clave, sin endpoint que configurar. Cada llamada se descuenta de la cuota del plan existente de tu organización. + +Todo lo que hace Jev es idéntico a la [configuración con tu propia clave](/es/policies/jev-byok): las políticas estrictas siguen siendo definitivas, la denegación de una política revisable solo se elimina cuando Jev fue consultado exactamente sobre esa preocupación, y cualquier fallo cae de vuelta al resultado de la expresión regular para esa llamada. + + +Requiere **failproofai 1.0.8-beta.0** o posterior. La versión 1.0.7 no incluye Jev, aunque aparezca por encima de las betas de 1.0.7 en el orden de versiones. Sin una configuración de Jev, nada cambia: los hooks ejecutan las políticas de expresiones regulares exactamente como siempre. + + +## Activación + +1. **Crea una clave con Jev.** En el panel de FailproofAI Cloud, abre **Keys → Create key** y selecciona el preset **machine**. Este concede los tres permisos que necesita una máquina: `events:add` (enviar actividad), `policies:pull` (recibir políticas) y `jev:evaluate` (Jev, descontado de la cuota de tu organización). Una clave no puede tener `jev:evaluate` sin los otros dos. +2. **Conecta la máquina** con esa clave: + + ```bash + failproofai config --token + ``` + + Si tu organización ejecuta su propio FailproofAI Cloud en lugar del alojado, añade su dirección: `--url https://` (o exporta `FAILPROOFAI_CLOUD_URL`). Sin esto, la clave se verifica contra el servicio alojado y la conexión falla. Si el certificado de ese host proviene de una CA privada, instala la CA en el almacén de confianza del sistema de la máquina (por ejemplo, con `update-ca-certificates`), no solo en `NODE_EXTRA_CA_CERTS`: el demonio que envía eventos y obtiene políticas lee el almacén del sistema. Consulta [Solución de problemas](/es/reference/troubleshooting). + +Eso es todo. Al conectar se almacena la clave y, cuando la máquina **no** tiene aún ninguna configuración de Jev, activa Jev a través de FailproofAI Cloud en modo **shadow**: Jev es consultado para cada llamada a herramienta controlada y sus veredictos se registran, pero lo que se aplica es el resultado de tus políticas. La salida lo indica: + +```text + Jev on through FailproofAI Cloud, in shadow mode: logged, not enforced (~/.failproofai/jev.json). +``` + +**Con `--no-transcripts`, la conexión no activa Jev.** Jev envía cada llamada a herramienta verificada y el prompt reciente a FailproofAI Cloud, lo cual supone más información de la que enviaría una conexión que solo transmite decisiones. La clave se sigue almacenando, y la salida indica que Jev está disponible y cómo activarlo: + +```bash +failproofai jev setup --provider failproofai +``` + +Tampoco **desactiva** Jev. Si el `jev.json` de la máquina ya ejecuta Jev a través de FailproofAI Cloud, se deja tal como está, y la salida indica que Jev sigue enviando cada llamada a herramienta verificada y el prompt reciente, y que `failproofai jev setup --mode off` lo desactiva. + + +La conexión **nunca sobreescribe** un `~/.failproofai/jev.json` existente. Si ya usas tu propio endpoint de Jev, este sigue siendo utilizado, y la salida indica que el archivo se dejó según estaba configurado — y, cuando ese archivo deja Jev desactivado (rechazado o apagado), lo indica y explica cómo solucionarlo. Para cambiar esa máquina a FailproofAI Cloud, ejecuta `failproofai jev setup --provider failproofai`. + + +## Shadow, enforce o desactivado + +Empieza en shadow, observa qué habría hecho Jev en la página de políticas, y luego permite que actúe: + +```bash +failproofai jev setup --mode enforce # Los veredictos de Jev se aplican: puede eliminar una denegación revisable y añadir la suya +failproofai jev setup --mode shadow # Jev es consultado y registrado; se aplica el resultado de tus políticas +failproofai jev setup --mode off # mantiene la configuración, deja de consultar a Jev +``` + +El mismo interruptor está en el panel local: **Settings → Jev** tiene un interruptor de activación/desactivación y shadow/enforce. Reescribe el modo y nada más. Los hooks leen la configuración en cada llamada a herramienta, por lo que un cambio se aplica desde la siguiente, sin necesidad de reiniciar. + +## Verificar su funcionamiento + +```bash +failproofai jev status +failproofai jev test +``` + +`status` muestra el proveedor como **FailproofAI Cloud**, el host de Cloud al que se conectó la máquina, el modo y el origen de la clave como **FailproofAI Cloud connection**, nunca la clave en sí. Cuando hay un `jev.json` de FailproofAI Cloud pero Jev no puede ejecutarse, indica el motivo: + +| `status` indica | `status --json` | Significado | +| --- | --- | --- | +| **off — no Jev key is stored for this machine's FailproofAI Cloud connection** | `key-lacks-jev` | La máquina está conectada, pero no hay ninguna clave de Jev almacenada para ella: la clave carece de `jev:evaluate`, o la conexión no pudo confirmarlo. Ejecuta `failproofai config --token ` de nuevo con la misma clave; si le falta el permiso, usa una clave de tipo **machine**. | +| **off — this machine is not connected to FailproofAI Cloud** | `not-connected` | No hay ninguna conexión de FailproofAI Cloud en esta máquina a la que pertenezca la clave de Jev. | + +Después de `failproofai config --disconnect` ya no existe ningún `jev.json` de FailproofAI Cloud (a menos que estuviera desactivado, en cuyo caso se conserva), por lo que `status` simplemente informa que Jev está desactivado. `status --json` contiene los mismos datos (`provider: "failproofai"`, `keySource: "cloud"`, `cloudConnected`, `keyCarriesJev`), también cuando la configuración está ausente o fue rechazada. `permissions` siempre corresponde al `jev.json`; un rechazo sobre `credentials.json` añade `credentialsPermissions`, y `fix` cuando un único comando lo soluciona. `test` envía una solicitud real y reporta su latencia y la versión de Jev que respondió. Sale con código 1, y así lo indica en su título, cuando la respuesta llega después del tiempo límite del hook (los hooks registrarían `timeout`) o responde incorrectamente a su pregunta de verificación. + +El panel **Settings → Jev** también muestra la **FailproofAI Cloud connection**: a qué organización reporta la máquina y si su clave incluye Jev. Se lee desde los propios archivos de la máquina, sin ninguna llamada de red. + +## Qué llega a la página de políticas + +La máquina ya envía su actividad de hooks a FailproofAI Cloud (`events:add`). Con Jev activado, el registro de cada llamada controlada también indica qué evaluador se ejecutó, qué decidió Jev, qué políticas eliminó, por qué recurrió al fallback cuando lo hizo, su latencia y el modelo que respondió — decisiones, códigos y nombres, nunca el comando ni tu prompt. En la página **Policies** de tu organización: + +- una llamada cuyo resultado fue decidido por el propio veredicto de Jev (modo enforce) se atribuye a **Jev**, y cuando la verificación determinante provino de un pack, el registro también nombra ese pack y su versión; +- en modo shadow, la denegación o advertencia de Jev aparece como **would-have** (lo que habría hecho), junto a los rollouts que estás observando; +- las políticas que Jev eliminó, o habría eliminado en modo shadow, se contabilizan por política. + +## Cuando Jev no puede responder + +Cada uno de estos casos recurre al resultado de tus políticas para esa llamada, y se registra con su motivo: + +| Motivo | Causa | +| --- | --- | +| `out-of-credits` | Tu organización ha agotado la cuota de su plan. | +| `http-401`, `http-403` | La clave fue revocada, o no incluye `jev:evaluate`. Reconéctate con una clave que sí lo tenga. | +| `http-429` | FailproofAI Cloud está aplicando límites de velocidad a Jev para tu organización. Hasta que expire el tiempo de espera indicado (`Retry-After`, máximo 60 segundos), la máquina no le envía nada y cada llamada recurre al fallback de inmediato. Las llamadas retenidas de esta forma se registran como `http-429`, o como `rate-limited` cuando el propio límite de velocidad de la máquina las retiene primero. | +| `http-429` (límite diario) | Tu organización ha agotado sus llamadas diarias a Jev: **10 000 por día UTC**, a menos que quien opere tu FailproofAI Cloud haya establecido otro límite. Todas las llamadas recaen en el fallback hasta que el contador se reinicia a las 00:00 UTC; la máquina sigue intentándolo como máximo una vez por minuto, por lo que detecta el reinicio en menos de un minuto. `failproofai jev test` indica "Daily Jev limit for this org reached; resets at 00:00 UTC." | +| `http-422` | Jev rechazó la solicitud de esta llamada, generalmente porque la llamada a herramienta contenía texto denso (base64, hex, código minificado) que superaba el presupuesto de tokens de Jev. Esa llamada siempre recurre al fallback; no es una interrupción del servicio. | +| `http-502` | Jev no está disponible en este momento. | +| `http-503` | Este Cloud no puede servir Jev para tu organización: sin gateway de modelo, una organización aún no aprovisionada, o el gateway está caído. Consulta a tu administrador; los hooks vuelven a intentarlo como máximo una vez por minuto. | +| `http-404` | Este FailproofAI Cloud aún no sirve Jev. | +| `timeout` | Sin respuesta dentro de `timeoutMs` (predeterminado: 3000). | +| `model-mismatch` | Respondió una versión de Jev distinta a la 1.13. | + +## Dónde se almacena la clave y a dónde va + +- La clave se almacena una sola vez, en `~/.failproofai/credentials.json` (`0600`, en un directorio solo accesible por el propietario), junto a las demás credenciales de FailproofAI Cloud. Para esta ruta, `jev.json` no contiene ninguna clave; si se escribe una allí, la configuración queda inválida. +- Si `credentials.json` tiene **cualquier** permiso para alguien que no seas tú (grupo u otros, lectura o escritura), o si su directorio puede ser **escrito** por alguien que no seas tú, el archivo es **rechazado**, no leído, y Jev permanece desactivado hasta que lo corrijas: `chmod 600` sobre el archivo, `chmod 700` sobre el directorio (o vuelve a conectar, lo que reescribe el archivo a `0600` y deja el directorio solo accesible por el propietario). Un directorio que otros solo pueden leer es aceptable; uno que pueden escribir les permite sustituir el archivo. +- La clave solo cuenta mientras la conexión con la que llegó sigue en la máquina: una credencial de política o reporte para el mismo FailproofAI Cloud **con la misma clave**, en el mismo archivo. Una clave de Jev que quede sin ninguna credencial asociada es ignorada y Jev permanece desactivado. Esto ocurre cuando un `config --disconnect` de una versión anterior de failproofai deja la clave de Jev en su lugar (no sabe que debe eliminarla), o cuando un `config --token` de una versión anterior conecta con otra clave, que en FailproofAI Cloud puede pertenecer a otra organización. Para reactivar Jev, conéctate de nuevo con una clave de tipo **machine**. +- La clave solo se envía al origen de Cloud contra el que fue verificada. Un `jev.json` que apunte a cualquier otro lugar es rechazado. +- **Un agente en la máquina puede leerla.** `credentials.json` solo es accesible por el propietario, y el agente se ejecuta como ese propietario. Leer los propios archivos de failproofai está permitido intencionalmente (solo está bloqueada su modificación, mediante `block-failproofai-commands`), por lo que lo único que hay entre un agente y este archivo es `block-read-outside-cwd` — una política *revisable* — y, en una sesión iniciada en tu directorio home, nada. Una clave con `jev:evaluate` consume la cuota de Jev de tu organización (hasta el límite diario) desde donde sea que se use, así que trata una clave de máquina como cualquier otra credencial de gasto: si un agente puede haberla leído, desactívala en la página de Keys y conéctate de nuevo con una nueva. +- Solo tus archivos globales determinan esto. Un repositorio no puede activar Cloud Jev, apuntarlo a otro lugar ni proporcionar su clave, y `FAILPROOFAI_JEV_API_KEY` se ignora para esta ruta. +- Por cada llamada que evalúa Jev, se envía una solicitud a FailproofAI Cloud con el contenido que lista la [página de bring-your-own-key](/es/policies/jev-byok#what-leaves-the-machine) (secretos redactados). FailproofAI Cloud la reenvía a TypeSafe y no la registra ni la conserva. + +## Desactivación + +| Comando | Resultado | +| --- | --- | +| `failproofai jev setup --mode off` | Conserva la configuración; Jev no es consultado. **Este es el interruptor que persiste:** conectar de nuevo nunca sobreescribe un `jev.json` existente, por lo que Jev permanece desactivado hasta que lo reactives con `--mode shadow`. | +| `failproofai jev remove` | Elimina `~/.failproofai/jev.json`; Jev está desactivado — hasta el próximo `failproofai config --token` con una clave que incluya `jev:evaluate`, que al no encontrar ningún `jev.json` activa Jev de nuevo en modo shadow (a menos que se ejecute con `--no-transcripts`). Para mantenerlo desactivado, usa `--mode off`. | +| `failproofai config --disconnect` | Desconecta la máquina: la clave se elimina, y también el `jev.json` cuando nombra a FailproofAI Cloud y no está desactivado. Un `jev.json` para tu propio endpoint se conserva, al igual que uno que esté desactivado, por lo que Jev permanece desactivado cuando vuelvas a conectar. | + +A partir de la siguiente llamada a herramienta, los hooks ejecutan las políticas de expresiones regulares exactamente como antes. \ No newline at end of file diff --git a/docs/es/policies/jev.mdx b/docs/es/policies/jev.mdx new file mode 100644 index 000000000..54c4edd25 --- /dev/null +++ b/docs/es/policies/jev.mdx @@ -0,0 +1,45 @@ +--- +title: "Políticas de Jev" +description: "Añade la revisión en tiempo real de Jev a las llamadas de herramientas supervisadas, e inspecciónala antes de aplicar sus decisiones." +icon: "shield-check" +--- + +Jev analiza una llamada de herramienta en relación con lo que la persona le pidió al agente que hiciera. Úsalo cuando una política basada en coincidencia de cadenas bloquee trabajo válido o pase por alto una acción riesgosa que requiere contexto. Responde junto a tus políticas en la puerta `PreToolUse` o `PermissionRequest`. Para una puntuación **después** de que termine una sesión, usa las [evaluaciones de Jev](/es/evaluations/jev). + +## Comienza en modo observación + +Instala Failproof AI y conecta hooks a un [harness compatible](/es/reference/harnesses). Usa failproofai 1.0.8-beta.0 o posterior. + +Failproof AI no incluye verificaciones de Jev. Instálalas como un paquete; de lo contrario, Jev no tiene nada que consultar y nunca se invoca: + +```bash +failproofai policies add FailproofAI/jev-policies +``` + +Luego elige cómo llegan las solicitudes a Jev: + +| Ruta | Primer paso | +| --- | --- | +| FailproofAI Cloud | Conéctate con una clave de **máquina** que tenga `jev:evaluate`. En una máquina sin configuración de Jev, `failproofai config` activa Jev en modo observación. | +| Tu propio proveedor | En el panel local, abre **Settings → Jev**, elige el proveedor, pega su token y selecciona **observe**. O ejecuta `failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key`. | + +![La configuración de Jev en el panel local: proveedor, endpoint, token y modo observación antes de activar Jev.](/images/dashboard/jev-settings.png) + +```bash +failproofai jev status +failproofai jev test +``` + +`test` verifica el endpoint. Para comprobar la ruta del hook, pídele a un agente con hooks que use su herramienta de lectura de archivos en `README.md`. Confirma que esa llamada de herramienta aparece en la sesión, luego revisa **Policies → Activity** en el [panel local](/es/reference/local-dashboard#review-policy-activity). El contador de Jev en `status` debería aumentar. El modo observación registra lo que Jev habría decidido mientras el resultado de tu política existente sigue aplicándose. + +## Decide cuándo aplicar enforcement + +Una política **hard** siempre tiene la última palabra. Jev solo puede anular un deny de una política explícitamente marcada como **reviewable**, y únicamente cuando haya verificado la preocupación nombrada de esa política. Consulta [autoridad de políticas](/es/policies/authority) antes de confiar en una aprobación de Jev. Jev también puede advertir o denegar por cuenta propia. Si no puede responder, el resultado de la política decide esa llamada. + +Una vez que los resultados en modo observación se vean correctos, cambia al modo enforce en **Settings → Jev** o ejecuta: + +```bash +failproofai jev setup --mode enforce +``` + +Para URLs de proveedor, claves de Cloud, configuración, fallbacks y los datos enviados con cada solicitud, consulta la [referencia de integración de Jev](/es/reference/jev). \ No newline at end of file diff --git a/docs/es/reference/custom-agents-typescript.mdx b/docs/es/reference/custom-agents-typescript.mdx new file mode 100644 index 000000000..0677e12d8 --- /dev/null +++ b/docs/es/reference/custom-agents-typescript.mdx @@ -0,0 +1,401 @@ +--- +title: "Agentes personalizados (TypeScript)" +description: "Configuración, el catálogo de eventos, los alcances y los adaptadores de framework para @failproofai/sdk." +icon: "square-js" +--- + +Lo que hace cada configuración, método y campo del SDK de TypeScript. Si estás instrumentando por primera vez, comienza con la guía — esta página es para consultas de referencia. + + + + Instalación, instrumentación, los métodos de evento, un ejemplo completo y problemas comunes. + + + Los mismos eventos, el mismo formato de transferencia, el mismo spool — desde Python. + + + +Node 20.9 o posterior. ESM y CommonJS. Sin dependencias en tiempo de ejecución. + + + Este SDK y el de Python escriben **los mismos eventos en el mismo spool**. Una flota con agentes Node y agentes Python produce un único conjunto de sesiones, no dos, y nada en el panel los distingue. Elige por servicio, no por empresa. + + +## Instalación + +```bash +npm install @failproofai/sdk +``` + +```ts +import * as failproofai from "@failproofai/sdk"; + +await failproofai.agent("planner", { goal: question }, async () => { + const hits = await failproofai.toolCall("web_search", { input: { q } }, () => search(q)); +}); +``` + +Los adaptadores de framework se incluyen en el propio paquete. Los frameworks son **dependencias de pares opcionales** — declaradas para que los rangos compatibles sean visibles, nunca instaladas en tu nombre, e importadas solo cuando llamas a `instrument()`. + +## Conectar el daemon de Failproof + +Idéntico al SDK de Python: crea una clave `events:add` en **Admin → Keys**, luego [conecta el daemon](/es/start/setup#connect-a-machine-to-cloud) en la máquina del agente. El SDK escribe en disco; el daemon envía. + +## Configuración + +```ts +failproofai.configure({ + environment: "production", + flushInterval: 0.5, + baseDir: undefined, +}); +``` + +| Opción | Qué hace | +| --- | --- | +| `environment` | La etiqueta en cada evento — `production`, `staging`, `prod-eu`. El valor por defecto es `dev`. | +| `flushInterval` | Con qué frecuencia el temporizador escribe en disco, en segundos. El valor por defecto es `0.5`. | +| `baseDir` | Dónde escribir. Por defecto usa el spool del daemon, que es lo que quieres a menos que sepas lo contrario. | + +Nada se aplica a menos que todo sea válido, por lo que una llamada rechazada deja el SDK exactamente como estaba en lugar de con un nuevo `baseDir` y el intervalo anterior. + +Configura mediante variables de entorno: + +| Variable | Qué hace | +| --- | --- | +| `AGENTEYE_ENVIRONMENT` | Establece `environment` sin cambiar el código. Una opción de `configure()` tiene precedencia sobre esta. | +| `FAILPROOFAI_HOME` | Mueve la raíz de Failproof AI que contiene el spool. | +| `FAILPROOFAI_SDK_LOG_LEVEL` | `debug`, `info`, `warn` (por defecto), `error`, `silent`. | +| `FAILPROOFAI_SDK_STRICT` | `1` hace que los errores de instrumentación lancen excepciones en lugar de registrarse. | +| `FAILPROOFAI_SDK_STRICT_INTEGRATIONS` | `1` hace que un problema de compatibilidad con el framework lance una excepción en lugar de advertir y continuar. | + + + **Sin comas en `environment`.** La ingesta divide ese campo por comas para construir sus filtros, y omite cualquier evento cuya etiqueta contenga una — así que toda una ejecución desaparece silenciosamente. Escribe `prod-eu`, no `prod,eu`. + + `configure({ environment: "prod,eu" })` lanza una excepción para que lo descubras inmediatamente. `AGENTEYE_ENVIRONMENT` no puede lanzar — nadie te está llamando — así que advierte una vez y vuelve a `dev`. + + +Redirige las líneas de log propias del SDK a tu logger con `failproofai.setLogger({ debug, info, warn, error })`. + +## Apagado + +Los eventos en buffer se vacían con `process.on("exit")`. + +Un proceso terminado por una señal nunca llega a eso, y el comportamiento por defecto de Node para `SIGTERM` es terminar sin ejecutar los manejadores de salida — así que un agente en contenedor pierde lo que el último intervalo no había escrito. + + + **Este SDK no instalará un manejador de señales por ti.** Registrar uno cambia el comportamiento de tu proceso: un listener suprime la terminación por defecto de Node, por lo que una biblioteca que añadiera uno detendría silenciosamente el funcionamiento de Ctrl-C. Añade el tuyo propio: + + ```ts + for (const signal of ["SIGINT", "SIGTERM"] as const) { + process.once(signal, () => { + failproofai.flushSync(); + process.exit(0); + }); + } + ``` + + +Un script de vida corta o un manejador serverless debería `await failproofai.flush()` antes de retornar — el intervalo por sí solo no garantiza la entrega. + +## Identidad + +Cada evento pertenece a una sesión y un agente. **Los alcances completan ambos**, por lo que raramente necesitas pasarlos: + +```ts +await failproofai.session(async () => { + await failproofai.agent("planner", async () => { + failproofai.event.toolUse({ toolName: "search", toolCallId: "c1" }); + }); +}); +``` + +Pasar `sessionId` o `agentId` explícitamente sigue funcionando y tiene precedencia. Sin ninguno vinculado ni pasado, la llamada lanza una excepción en lugar de emitir un evento que Cloud descartaría silenciosamente. + + + La identidad viaja en `AsyncLocalStorage`. Sigue `await`, `.then()`, temporizadores y cualquier callback creado dentro del alcance. **No** sigue un callback almacenado durante una ejecución e invocado durante otra, ni trabajo transferido a través de un límite `worker_threads` — envuelve esos con `failproofai.propagate()` o sus eventos quedarán sin adjuntar. + + +### Alcances + +| Alcance | Emite | Retorna | +| --- | --- | --- | +| `session(body)` | nada — solo identidad | lo que retorne `body` | +| `agent(id, options?, body)` | `agent_start`, luego `agent_end` | lo que retorne `body` | +| `toolCall(name, options?, body)` | `tool_use`, luego `tool_result` | lo que retorne `body` | + +Un cuerpo síncrono permanece síncrono: `agent("x", () => 1)` retorna `1`, no una promesa. + +`toolCall` registra el valor resuelto del cuerpo como la `output` de la herramienta, a menos que asignes `call.output` tú mismo. + + + +| Qué ocurrió | Eventos | `outcome` | +| --- | --- | --- | +| el bloque retornó | `agent_end` | `"success"`, o tu `outcome` | +| el bloque lanzó | `error`, luego `agent_end` | `"failed"` | +| un `AbortError` | solo `agent_end` | `"cancelled"` | + +El error siempre se relanza. + +Un fallo de herramienta se registra en la hoja — `tool_result` con un string `error` — y **no** emite un evento `error` a nivel de ejecución. El que captura el bucle del agente no es un fallo de ejecución, y el que se propaga se reporta exactamente una vez, por el `agent()` que lo envuelve. + + + + + +Cuando el trabajo no es una sola función — un alcance abierto en un constructor y cerrado en un teardown, o uno que atraviesa flujos de control existentes: + +```ts +{ + using span = failproofai.agent.open("planner", { goal }); + using call = failproofai.toolCall.open("search", { input: { q } }); + call.call.output = await search(q); +} // tool_result, then agent_end +``` + +Ambas formas emiten eventos idénticos byte a byte. Prefiere la forma con callback: se ejecuta dentro de `AsyncLocalStorage.run()`, así que no hay nada que deshacer y toda la clase de errores de "abierto aquí, cerrado allá" es inalcanzable. + +Un bloque `using` que captura su propio fallo lo reporta con `span.fail(error)` — el disposer no tiene su propio canal de excepciones. + + + +## Catálogo de eventos + +Los mismos quince métodos que el SDK de Python, en camelCase. La mayoría vienen en **pares** — llamas al abridor, luego al cerrador, y el SDK mide el intervalo. + +| | Abre | Cierra | +| --- | --- | --- | +| **Agentes** | `agentStart` | `agentEnd` | +| | `agentPause` | `agentResume` | +| **Modelos** | `modelRequest` | `modelResponse` | +| **Herramientas** | `toolUse` | `toolResult` | +| **Hooks** | `hookTriggered` | `hookCompleted` | +| **Humanos** | `humanWait` | `humanInput` | + +Tres son independientes: `error`, `humanPause`, `humanInterrupt`. + + + +Cada método también acepta `sessionId` y `agentId`, que los alcances rellenan por ti. Cualquier campo omitido se descarta en lugar de enviarse como JSON `null`. + +| Método | Requerido | Opcional | +| --- | --- | --- | +| `agentStart` | — | `goal`, `parentId` | +| `agentEnd` | — | `outcome`, `summary` | +| `agentPause` | `pauseId` | `reason`, `userId` | +| `agentResume` | `pauseId` | `reason`, `userId` | +| `modelRequest` | — | `model`, `messages`, `system`, `tools`, `requestId` | +| `modelResponse` | — | `model`, `stopReason`, `inputTokens`, `outputTokens`, `content`, `role`, `requestId` | +| `toolUse` | `toolName`, `toolCallId` | `input` | +| `toolResult` | `toolName`, `toolCallId` | `output`, `error` | +| `hookTriggered` | `hookName`, `hookId` | `triggerEvent`, `input` | +| `hookCompleted` | `hookName`, `hookId` | `outcome`, `output`, `error` | +| `error` | `errorType`, `message` | `traceback` | +| `humanWait` | `inputId` | `prompt`, `options`, `reason` | +| `humanInput` | `inputId` | `response` | +| `humanPause` | — | `reason`, `userId` | +| `humanInterrupt` | — | `reason`, `userId`, `atStep` | + +Cualquier otra clave que añadas se convierte en un campo de payload personalizado. Pon en el espacio de nombres `fw_*` todo lo específico de un framework; un nombre que colisione con un campo declarado será rechazado en lugar de sobrescribir silenciosamente una columna promovida. + + + + + **`duration_ms` se calcula, no se acepta.** Los cuatro métodos de cierre miden el intervalo desde su abridor y rechazan un `duration_ms` proporcionado por el llamador — una duración reportada no puede ser falsificada. + + Los pares se emparejan por **sesión** e id, nunca por agente. Una herramienta abierta bajo `planner` y cerrada bajo `worker` sigue emparejándose, que es exactamente lo que hacen las ejecuciones multi-agente anidadas. + + +## Adaptadores de framework + +```ts +await failproofai.instrument(); // whatever it can find +await failproofai.instrument("langchain"); // exactly one +failproofai.uninstrument(); // put everything back +``` + +| Framework | Compatible | Cómo se adjunta | +| --- | --- | --- | +| **LangChain.js / LangGraph.js** | `@langchain/core` 0.3 – 1.x, LangGraph.js 0.4 – 1.x | `CallbackManager.configure`, así cada `invoke`/`stream`/`batch` queda cubierto sin pasar `callbacks:` en ningún lado — o pasa `langchainHandler()` tú mismo sin parchear nada. | +| **Vercel AI SDK** | `ai` 4 – 7 | `telemetry()` en el punto de llamada, o `instrument("ai")` para todo el proceso con `ai` 7 (en 4–6 es opt-in — ver más abajo). | +| **Mastra** | `@mastra/core` 0.20 – 1.x | `Agent.generate`/`.stream`, el modelo del agente y la resolución de herramientas, y el motor de ejecución de workflow/paso. | +| **LlamaIndex.TS** | `llamaindex` 0.11.4 – 0.x | `Settings.callbackManager` (suscrito) más `AgentWorkflow.runStream`, para ejecuciones de workflow y sus pasos. | + +Cada rango se prueba contra versiones reales del framework, en ambos extremos, como módulo ES y como CommonJS, en cada ejecución de CI. + +El mapeo es el del SDK de Python, así que el mismo programa dibuja el mismo árbol en cualquiera de los dos lenguajes. Una construcción es un **agent** solo si tiene un bucle de decisión LLM propio — una ejecución de grafo o cadena, una llamada `generateText`/`streamText` del AI SDK, un agente Mastra, una ejecución de agente LlamaIndex. Un nodo de LangGraph o un paso de workflow es un **hook** (`hook_triggered`/`hook_completed`), nunca un agente anidado. Las llamadas al modelo son pares `model_request`/`model_response` con conteos de tokens; las llamadas a herramientas llevan el propio id de llamada del modelo. Un fallo se registra una sola vez, en el evento donde ocurrió. + +Un adaptador que falla al instalarse se registra y se omite; los demás se instalan igualmente, porque un LlamaIndex roto no debería costarte LangGraph. + + + `instrument()` sin argumento detecta un framework por si **resuelve**, no por si ya está importado — Node no expone un equivalente de `sys.modules` de Python para módulos ES. Un framework que tienes instalado pero no usas será importado y parcheado. Indica el que quieres si eso importa. + + + + La mayoría de estos frameworks incluyen una compilación de módulo ES y una CommonJS, que Node carga como dos copias no relacionadas. Los adaptadores parchean la copia que carga tu aplicación (y también la copia CommonJS si algo ya la ha cargado con `require`), así que ambos sistemas de módulos funcionan. Un framework **empaquetado en tu propia salida** por esbuild o webpack queda fuera de alcance — usa los helpers de punto de llamada allí: `langchainHandler()`, `telemetry()`, `wrapTool()`. + + +### LangChain sin parchear + +```ts +import { langchainHandler } from "@failproofai/sdk/langchain"; +await graph.invoke(input, { callbacks: [langchainHandler()] }); +``` + +El manejador funciona con o sin `instrument()` y nunca registra duplicados. `instrument("langchain")` acepta `sessionId`, `captureContent`, `includeChains`, `graphCallbacks` y `captureLimit`, igual que el adaptador de Python; `metadata: { failproofai_sdk_session_id }` en una llamada elige la sesión para esa invocación. + +### Vercel AI SDK + +El AI SDK exporta funciones simples desde un módulo ES, y un espacio de nombres de módulo ES es inmutable por especificación — no hay dónde parchear. Usa los puntos de extensión que el propio SDK documenta: + +```ts +import { telemetry } from "@failproofai/sdk/ai"; + +const { text } = await generateText({ + model, + prompt, + experimental_telemetry: telemetry({ functionId: "answer-question" }), + // on ai 7, `telemetry: telemetry({ … })` — the same object, the new name +}); +``` + +Esa es la integración completa: un span de agente, un par model request/response por paso con conteos de tokens, y cada llamada a herramienta. Un único punto de llamada funciona en cada versión mayor — `ai` 4–6 leen el tracer que lleva, `ai` 7 la integración de telemetría. + +`instrument("ai")` hace lo mismo a nivel de proceso **con `ai` 7**: cada llamada, a través de la lista global de integraciones de telemetría del AI SDK, que es aditiva y no interfiere con nadie más. + +**Con `ai` 4–6, `instrument("ai")` no registra nada por sí mismo, y emite una advertencia indicándolo.** El único hook global que tienen esas versiones mayores es el proveedor de tracer global de OpenTelemetry — un único slot que OpenTelemetry se niega a ceder una vez tomado. Registrar el nuestro rechazaría silenciosamente tu propio `NodeSDK.start()` posterior en el arranque y enviaría tus spans de http/base de datos a un tracer que no exporta nada. Usa `telemetry()` en el punto de llamada o `wrapModel` allí. Si el proceso no ejecuta OpenTelemetry propio, actívalo con `instrument("ai", { registerGlobalTracer: true })`: entonces registra cada llamada que pasa `experimental_telemetry: { isEnabled: true }`, y solo toma el slot si aún está libre. `registerGlobalTracer: false` mantiene el comportamiento por defecto y silencia la advertencia. + +Si prefieres envolver el modelo una sola vez, `wrapModel` solo ve las llamadas al modelo, porque las llamadas a herramientas ocurren por encima de la capa del modelo. Un modelo envuelto llamado sin nada alrededor se registra como su propia ejecución. Una llamada en streaming se cierra como sea que el stream termine — `stop_reason: "cancelled"` cuando el consumidor lo cancela, `"error"` con el error cuando falla a mitad: + +```ts +import { wrapModel } from "@failproofai/sdk/ai"; +const model = await wrapModel(openai("gpt-4o")); +``` + +Usar ambos está bien: el middleware detecta que la llamada ya está siendo registrada y cede, así que cada llamada se registra una vez. + +`functionId` nombra el span del agente. Mantenlo de baja cardinalidad — va a `agent_id`, la faceta principal del panel. + +### Next.js + +`next build` empaqueta las dependencias de tu servidor por defecto, y un framework empaquetado en la compilación es una copia a la que `instrument()` no puede llegar. Envuelve la configuración una vez y llama a `instrument()` desde el hook de arranque de Next: + +```ts +// next.config.ts +import { withFailproofai } from "@failproofai/sdk/next"; +export default withFailproofai({ /* your config */ }); +``` + +```ts +// instrumentation.ts +export async function register() { + if (process.env.NEXT_RUNTIME !== "nodejs") return; + const failproofai = await import("@failproofai/sdk"); + await failproofai.instrument(); +} +``` + +`withFailproofai` añade LangChain, Mastra, LlamaIndex y el propio SDK a `serverExternalPackages`, manteniendo tu lista. Sin él, `instrument()` advierte una vez por framework al que no puede llegar en lugar de fallar silenciosamente; si listas los paquetes tú mismo, establece `FAILPROOFAI_NEXT_EXTERNALS=1`. El Vercel AI SDK y los helpers de punto de llamada funcionan de cualquier manera. Una ruta Edge recibe una compilación sin operación: importar el SDK es seguro y no registra nada. + +### Conteos de tokens en llamadas en streaming + +Las APIs compatibles con OpenAI solo reportan el uso en un stream cuando el cliente lo solicita. LangChain y el Vercel AI SDK lo solicitan; para LlamaIndex pasa `additionalChatOptions: { stream_options: { include_usage: true } }` a su LLM `OpenAI`, y para Mastra construye el modelo con el uso habilitado (por ejemplo `createOpenAICompatible({ includeUsage: true })`). De lo contrario, las llamadas de modelo en streaming no llevan conteos de tokens. + +### Runtimes + +Node ≥ 20.9, Bun y Deno — cada framework, como módulo ES y como CommonJS, se prueba en cada uno frente al trace de Node. El SDK se ejecuta junto al daemon `failproofaid`, que envía lo que escribe. + +## Tu propio agente — sin framework + +Para un bucle de agente que escribiste tú mismo, o un framework sin adaptador. Emites los eventos con la misma API que usan los adaptadores internamente, así que el trace tiene la misma forma y calidad. + +No necesitas saber cómo está organizado el agente. Todo agente construido a mano ya tiene tres lugares, sin importar cómo se llamen sus funciones, y esos tres son la integración completa: + +| Dónde | Qué añadir | Emite | +| --- | --- | --- | +| Donde **una ejecución** empieza y termina | `failproofai.agent("name", { goal }, async () => …)` | `agent_start` / `agent_end` | +| La **única función que llama al modelo** | `event.modelRequest` antes, `event.modelResponse` después — ambas mitades, incluso en caso de fallo | un par por turno de modelo | +| La **única función que ejecuta herramientas** | `failproofai.toolCall(name, { toolCallId, input }, () => run())` | `tool_use` / `tool_result` | + +```ts +async function callModel(messages) { + const requestId = randomUUID(); + const started = Date.now(); + failproofai.event.modelRequest({ model: MODEL, requestId, messages }); + try { + const reply = await client.chat.completions.create({ model: MODEL, messages, tools }); + failproofai.event.modelResponse({ + model: reply.model, requestId, stopReason: reply.choices[0].finish_reason, + inputTokens: reply.usage?.prompt_tokens, outputTokens: reply.usage?.completion_tokens, + duration_ms: Date.now() - started, + }); + return reply.choices[0].message; + } catch (error) { + failproofai.event.modelResponse({ model: MODEL, requestId, stopReason: "error", + error: String(error), duration_ms: Date.now() - started }); + throw error; + } +} + +async function dispatch(call) { + const input = JSON.parse(call.function.arguments); + return failproofai.toolCall(call.function.name, { toolCallId: call.id, input }, + () => runTool(call.function.name, input)); +} + +await failproofai.agent("inventory", { goal: question }, async () => { + for (;;) { + const message = await callModel(messages); + if (!message.tool_calls?.length) return message.content; + for (const call of message.tool_calls) await dispatch(call); + } +}); +``` + +La identidad es ambiental: todo lo que está dentro de `agent()` aterriza en la sesión de esa ejecución sin necesitar un id, y nada más en el programa cambia — incluido lo que el agente ya escribe en su propia base de datos. + +- **Un servicio o un worker:** pasa tu propio id de solicitud o trabajo como `sessionId`, para que una sesión en el panel y el registro en tus propios logs o base de datos sean el mismo string. +- **Sub-agentes:** anida llamadas a `agent()`. El interno se une a la sesión con el externo como su `parent_id`. +- **Emite los pares.** Un `modelRequest` sin `modelResponse` es un span que el panel muestra como ejecutándose para siempre — de ahí el `catch`. + +[`sdk/typescript/examples/research-agent.ts`](https://github.com/FailproofAI/failproofai/blob/main/sdk/typescript/examples/research-agent.ts) en el repositorio es la versión completa y ejecutable: un bucle real de herramientas de OpenAI instrumentado exactamente así, ejecutado en CI en cada cambio como módulo ES y como CommonJS. + +## Evaluaciones + +```ts +import { Evaluator, EvalResult, Score } from "@failproofai/sdk/evaluator"; + +export const app = new Evaluator({ name: "my-evals", version: "1" }); + +app.eval("tool_success_rate", { version: "1" }, (session) => { + const results = session.eventsOfType("tool_result"); + const failures = results.filter((event) => event.payload.error != null).length; + return new EvalResult({ + score: new Score(results.length === 0 ? 1 : 1 - failures / results.length), + reasoning: `${failures} of ${results.length} tool calls failed`, + }); +}); +``` + +```bash +FAILPROOFAI_EVALUATOR_URL=… FAILPROOFAI_EVALUATOR_TOKEN=… \ + npx failproofai-evaluator ./my-evals.js +``` + +Consulta la [referencia del Evaluator SDK](/es/reference/evaluator-sdk) para el protocolo, la configuración del worker y los tipos de resultado. + + + **Una evaluación debe ceder el control.** Una función síncrona que nunca retorna bloquea el único hilo que tiene Node, y ningún timeout puede dispararse mientras lo hace. Escribe evaluaciones `async`. + + +## Lo que no hará a tu proceso + +| | | +| --- | --- | +| **Bloquear tu bucle de agente** | Los eventos van a una cola en memoria; un temporizador los escribe. El temporizador está con `unref`, así que importar este paquete nunca impide que un script salga. | +| **Crecer sin límite** | La cola está limitada por conteo *y* por bytes medidos. Superando cualquiera de los dos, los eventos más antiguos se descartan y una advertencia lo indica — una interrupción de telemetría no debe convertirse en un OOM kill. | +| **Tumbar el proceso** | Un evento que no se puede codificar se descarta solo, no el lote que lo rodea. Un getter que lanza, una referencia circular, un `BigInt`, un sustituto solitario: cada uno se maneja en lugar de propagarse. | +| **Dejar un lote a medio escribir** | El contenido se sincroniza con `fsync` antes de un renombrado atómico, el directorio se sincroniza con `fsync` después, y una escritura fallida limpia su archivo temporal. | +| **Dejar las transcripciones legibles** | Los lotes son `0600` dentro de un directorio `0700`. Llevan objetivos, prompts, argumentos de herramientas y salidas de herramientas. | +| **Enviar credenciales** | Las claves API, tokens, JWTs, cabeceras bearer y asignaciones con forma de secreto se redactan antes de que los bytes lleguen al disco. El daemon redacta de nuevo antes de subir. | \ No newline at end of file diff --git a/docs/es/reference/jev-cloud.mdx b/docs/es/reference/jev-cloud.mdx new file mode 100644 index 000000000..00ab28572 --- /dev/null +++ b/docs/es/reference/jev-cloud.mdx @@ -0,0 +1,136 @@ +--- +title: "Jev a través de FailproofAI Cloud" +description: "Claves de máquina en la nube, estado de conexión, límites y comportamiento ante fallos para la revisión de políticas Jev en tiempo real." +icon: "cloud" +--- + +Esta es la referencia de la ruta Cloud para las [políticas Jev](/es/policies/jev). Jev, el clasificador de TypeSafe, lee cada llamada a herramienta comparándola con lo que realmente solicitaste y responde junto con tus políticas, nunca en lugar de ellas. A través de **FailproofAI Cloud**, una máquina conectada utiliza Jev con la misma clave con la que ya se conecta: sin cuenta de TypeSafe, sin segunda clave, sin ningún endpoint que configurar. Cada llamada se carga al plan vigente de tu organización. + +Todo lo que hace Jev no cambia respecto a la [configuración con clave propia](/es/reference/jev-providers): las políticas estrictas siguen siendo definitivas, la denegación de una política revisable solo se levanta cuando Jev fue consultado exactamente sobre esa preocupación, y cualquier fallo cae de regreso al resultado regex para esa llamada. + + +Requiere **failproofai 1.0.8-beta.0** o posterior. La versión 1.0.7 no tiene Jev, aunque aparezca por encima de las versiones 1.0.7 beta en el orden de clasificación. Sin una configuración de Jev nada cambia: los hooks ejecutan las políticas regex exactamente como siempre. + + +## Antes de comenzar + +Instala Failproof AI en la máquina donde se ejecuta tu agente y conecta sus hooks a un [harness compatible](/es/reference/harnesses). Si estás comenzando desde cero, sigue el [inicio rápido](/es/start/quickstart) hasta la instalación de los hooks. Verifica el CLI instalado con `failproofai --version`; actualízalo si es anterior a Jev. También necesitas acceso a la página **Administration → Keys** de tu organización para crear una clave de máquina. + +Jev revisa llamadas a herramientas con nombre en la puerta `PreToolUse` o `PermissionRequest`. No revisa todos los eventos de una sesión. Para que Jev levante una denegación de política, necesitas una política instalada marcada como [revisable](/es/policies/authority); todas las demás denegaciones siguen siendo definitivas. + +## Activarlo + +1. **Crea una clave con Jev.** En el panel de FailproofAI Cloud, abre **Administration → Keys → Create key** y elige el preset **machine**. Otorga los tres permisos que necesita una máquina: `events:add` (enviar actividad), `policies:pull` (recibir políticas) y `jev:evaluate` (Jev, cargado al plan de tu organización). Una clave no puede tener `jev:evaluate` sin los otros dos. +2. **Conecta la máquina** con esa clave. Lee su secreto de un solo uso en un prompt y luego ejecuta el comando de configuración completo: + + ```bash + read -rs FAILPROOFAI_CLOUD_TOKEN && export FAILPROOFAI_CLOUD_TOKEN + failproofai config + ``` + + `failproofai config` instala el daemon, conecta los hooks para los CLIs de agentes que encuentra y conecta la máquina. La variable de entorno mantiene la clave fuera de los argumentos del comando y del historial de tu shell. Si tu harness fue instalado después, [conéctalo explícitamente](/es/start/quickstart). + + Si tu organización ejecuta su propio FailproofAI Cloud en lugar del servicio alojado, añade su dirección: `--url https://` (o exporta `FAILPROOFAI_CLOUD_URL`). Sin esto, la clave se verifica contra el servicio alojado y la conexión falla. Si el certificado de ese host proviene de una CA privada, instala la CA en el almacén de confianza del sistema de la máquina (por ejemplo, con `update-ca-certificates`), no solo en `NODE_EXTRA_CA_CERTS`: el daemon que envía eventos y obtiene políticas lee el almacén del sistema. Consulta [Solución de problemas](/es/reference/troubleshooting). + +Eso es todo. La conexión almacena la clave y, cuando la máquina **no** tiene aún una configuración de Jev, activa Jev a través de FailproofAI Cloud en modo **observe**: una vez que un pack le proporcione checks, Jev es consultado sobre cada llamada a herramienta en la puerta y sus veredictos se registran, pero el resultado que se aplica es el de tus políticas. La salida lo indica: + +```text + Jev on through FailproofAI Cloud, in observe mode: logged, not enforced (~/.failproofai/jev.json). +``` + +Jev aún no consulta nada hasta que un pack le proporcione checks. Failproof AI no incluye ninguno; mientras ningún pack instalado declare alguno, la salida añade una línea indicándolo, y `failproofai jev status` lo repite. Instálalos con: + +```bash +failproofai policies add FailproofAI/jev-policies +``` + +**Con `--no-transcripts`, la conexión no activa Jev.** Jev envía cada llamada a herramienta revisada y el prompt reciente a FailproofAI Cloud, lo cual supone más de lo que pide una conexión que solo envía decisiones. La clave se sigue almacenando, y la salida indica que Jev está disponible y cómo activarlo: + +```bash +failproofai jev setup --provider failproofai +``` + +Tampoco **desactiva** Jev. Si el `jev.json` de la máquina ya ejecuta Jev a través de FailproofAI Cloud, se deja como está, y la salida indica que Jev sigue enviando cada llamada a herramienta revisada y el prompt reciente, y que `failproofai jev setup --mode off` lo desactiva. + + +La conexión **nunca sobreescribe** un `~/.failproofai/jev.json` existente. Si ya usas tu propio endpoint de Jev, sigue utilizándose, y la salida indica que el archivo se dejó tal como estaba configurado — y, cuando ese archivo deja Jev desactivado (rechazado o desconectado), lo indica y explica cómo solucionarlo. Para cambiar esa máquina a FailproofAI Cloud, ejecuta `failproofai jev setup --provider failproofai`. + + +## Observe, enforce o off + +Empieza en observe, observa lo que Jev habría hecho en la página de políticas y luego deja que actúe: + +```bash +failproofai jev setup --mode enforce # Los veredictos de Jev se aplican: puede levantar una denegación revisable y añadir la suya propia +failproofai jev setup --mode observe # Se consulta a Jev y se registra; el resultado de tus políticas es el que se aplica +failproofai jev setup --mode off # Mantener la configuración, dejar de consultar a Jev +``` + +El mismo interruptor está en el panel local: **Settings → Jev** tiene un interruptor de activación/desactivación y observe/enforce. Reescribe el modo y nada más. Los hooks leen la configuración en cada llamada a herramienta, por lo que un cambio se aplica desde la siguiente, sin necesidad de reiniciar. + +## Verificar qué está haciendo + +```bash +failproofai jev status +failproofai jev test +``` + +`status` muestra el proveedor como **FailproofAI Cloud**, el host de Cloud al que se conectó la máquina, el modo y el origen de la clave como **FailproofAI Cloud connection**, nunca la clave en sí. Cuando hay un `jev.json` de FailproofAI Cloud en uso pero Jev no puede ejecutarse, explica el motivo: + +| `status` indica | `status --json` | Significado | +| --- | --- | --- | +| **off — no Jev key is stored for this machine's FailproofAI Cloud connection** | `key-lacks-jev` | La máquina está conectada, pero no hay clave Jev almacenada para ella: la clave no tiene `jev:evaluate`, o la conexión no pudo confirmarlo. Ejecuta `failproofai config` de nuevo con la clave en `FAILPROOFAI_CLOUD_TOKEN`; si le falta el permiso, usa una clave **machine**. | +| **off — this machine is not connected to FailproofAI Cloud** | `not-connected` | No hay conexión de FailproofAI Cloud en esta máquina a la que pertenezca la clave Jev. | + +Tras `failproofai config --disconnect` ya no hay un `jev.json` de FailproofAI Cloud (a menos que estuviera desactivado, que se conserva), por lo que `status` simplemente informa Jev como desactivado. `status --json` contiene los mismos datos (`provider: "failproofai"`, `keySource: "cloud"`, `cloudConnected`, `keyCarriesJev`), también cuando la configuración está ausente o fue rechazada. `permissions` siempre corresponde al `jev.json`; un rechazo relacionado con `credentials.json` añade `credentialsPermissions`, y `fix` cuando un solo comando lo soluciona. `test` envía una solicitud real y reporta su latencia y la versión de Jev que respondió. Sale con código 1, y lo indica en su título, cuando la respuesta llega después del timeout del hook (los hooks registrarían `timeout`) o responde incorrectamente a su pregunta de verificación. + +El panel **Settings → Jev** del panel también muestra la **FailproofAI Cloud connection**: a qué organización reporta la máquina y si su clave incluye Jev. Se lee desde los archivos propios de la máquina, sin ninguna llamada de red. + +## Verificar una llamada real + +Inicia una nueva sesión en el agente con hooks. Pídele que use su herramienta de lectura de archivos en `README.md` e informe el título. Confirma que la sesión contiene esa llamada a herramienta y luego ejecuta `failproofai jev status` de nuevo: el recuento de llamadas evaluadas recientemente debería aumentar. Abre **Policies → Activity** en el [panel local](/es/reference/local-dashboard#review-policy-activity) para inspeccionar el veredicto de Jev y el modo de esa llamada. En Cloud, la página **Policies** de la organización muestra los resultados de Jev para la actividad entregada. En modo observe, el veredicto se registra como **would-have** y el resultado de la política sigue decidiendo la llamada. Una aprobación aparece solo cuando una política revisable coincidió y Jev levantó sus checks con nombre. + +## Qué llega a la página de políticas + +La máquina ya envía su actividad de hooks a FailproofAI Cloud (`events:add`). Con Jev activado, el registro de cada llamada en la puerta también indica qué evaluador se ejecutó, qué decidió Jev, qué políticas levantó, por qué cayó al resultado de respaldo cuando lo hizo, su latencia y el modelo que respondió — decisiones, códigos y nombres, nunca el comando ni tu prompt. En la página **Policies** de tu organización: + +- una llamada decidida por el propio veredicto de Jev (modo enforce) se atribuye a **Jev**, y cuando el check decisivo provino de un pack, el registro también nombra ese pack y su versión; +- en modo observe, la denegación o advertencia de Jev aparece como **would-have**, junto a los rollouts que estás observando; +- las políticas que Jev levantó, o habría levantado en modo observe, se contabilizan por política. + +## Cuando Jev no puede responder + +Cada uno de estos casos cae de regreso al resultado de tus políticas para esa llamada, y se registra con su motivo: + +| Motivo | Causa | +| --- | --- | +| `out-of-credits` | Tu organización ha agotado la asignación de su plan. | +| `http-401`, `http-403` | La clave fue revocada o no tiene `jev:evaluate`. Reconéctate con una clave que sí lo tenga. | +| `http-429` | FailproofAI Cloud está limitando la tasa de solicitudes de Jev para tu organización. Hasta que el tiempo de espera solicitado haya pasado (`Retry-After`, como máximo 60 segundos), la máquina no envía nada y cada llamada cae inmediatamente al resultado de respaldo. Las llamadas retenidas de esta manera se registran como `http-429`, o como `rate-limited` cuando el límite de tasa propio de la máquina las retiene primero. | +| `http-429` (límite diario) | Tu organización ha agotado sus llamadas diarias a Jev: **10.000 por día UTC**, a menos que quien opera tu FailproofAI Cloud haya establecido otro límite. Cada llamada cae al resultado de respaldo hasta que el contador se restablece a las 00:00 UTC; la máquina vuelve a intentarlo como máximo una vez por minuto, por lo que detecta el restablecimiento en menos de un minuto. `failproofai jev test` indica "Daily Jev limit for this org reached; resets at 00:00 UTC." | +| `http-422` | Jev rechazó la solicitud de esta llamada, generalmente porque la llamada a herramienta contenía texto denso (base64, hex, código minificado) que supera el presupuesto de tokens de Jev. Esa llamada siempre cae al resultado de respaldo; no es una interrupción del servicio. | +| `http-502` | Jev no está disponible en este momento. | +| `http-503` | Este Cloud no puede servir Jev para tu organización: sin gateway de modelo, una organización aún no aprovisionada o el gateway está caído. Contacta con tu administrador; los hooks vuelven a intentarlo como máximo una vez por minuto. | +| `http-404` | Este FailproofAI Cloud aún no sirve Jev. | +| `timeout` | Sin respuesta dentro de `timeoutMs` (valor predeterminado: 3000). | +| `model-mismatch` | Respondió una versión de Jev distinta a la 1.13. | + +## Dónde vive la clave y adónde va + +- La clave se almacena una sola vez, en `~/.failproofai/credentials.json` (`0600`, en un directorio solo para el propietario), junto a las demás credenciales de FailproofAI Cloud. `jev.json` no contiene ninguna clave para esta ruta; si se escribe una allí, la configuración queda inválida. +- Si `credentials.json` tiene **cualquier** permiso para alguien que no seas tú (grupo u otros, lectura o escritura), o si su directorio puede ser **escrito** por alguien que no seas tú, se **rechaza**, no se lee, y Jev queda desactivado hasta que lo soluciones: `chmod 600` sobre el archivo, `chmod 700` sobre el directorio (o vuelve a conectarte, lo que reescribe el archivo con `0600` y deja el directorio solo para el propietario). Un directorio que otros solo puedan leer está bien; uno que puedan escribir les permite reemplazar el archivo. +- La clave solo cuenta mientras la conexión con la que llegó esté en la máquina: una credencial de política o de reporte para el mismo FailproofAI Cloud **con la misma clave**, en el mismo archivo. Una clave Jev dejada sin una de esas se ignora y Jev permanece desactivado. Esto ocurre cuando el `config --disconnect` de una versión anterior de failproofai deja la clave Jev en su lugar (no sabe que debe eliminarla), o cuando el `config --token` de una versión anterior conecta con otra clave, que en FailproofAI Cloud puede pertenecer a otra organización. Para reactivar Jev, conéctate de nuevo con una clave **machine**. +- La clave solo se envía al origen de Cloud contra el que fue verificada. Un `jev.json` que apunte a cualquier otro lugar es rechazado. +- **Un agente en la máquina puede leerla.** `credentials.json` es solo para el propietario, y el agente se ejecuta como ese propietario. Leer los propios archivos de failproofai está permitido deliberadamente (solo modificarlos está bloqueado, por `block-failproofai-commands`), por lo que lo único entre un agente y este archivo es `block-read-outside-cwd` — una política *revisable* — y desde una sesión iniciada en tu directorio personal, nada. Una clave con `jev:evaluate` consume la asignación de Jev de tu organización (hasta el límite diario) desde donde sea que se use, así que trata una clave de máquina como cualquier otra credencial de gasto: si un agente puede haberla leído, desactívala en la página de Claves y reconéctate con una nueva. +- Solo tus archivos globales determinan esto. Un repositorio no puede activar Cloud Jev, apuntarlo a otro lugar ni proporcionar su clave, y `FAILPROOFAI_JEV_API_KEY` se ignora para esta ruta. +- Para cada llamada que Jev evalúa, se envía una solicitud a FailproofAI Cloud con lo que la [página de clave propia](/es/reference/jev-providers#what-leaves-the-machine) lista (con los secretos redactados). FailproofAI Cloud lo reenvía a TypeSafe y no lo registra ni lo conserva. + +## Desactivarlo + +| Comando | Resultado | +| --- | --- | +| `failproofai jev setup --mode off` | Mantiene la configuración; no se consulta a Jev. **Este es el interruptor que persiste:** volver a conectarse nunca sobreescribe un `jev.json` existente, por lo que Jev permanece desactivado hasta que lo reactives con `--mode observe`. | +| `failproofai jev remove` | Elimina `~/.failproofai/jev.json`; Jev está desactivado — hasta el siguiente `failproofai config --token` con una clave que tenga `jev:evaluate`, que al no encontrar `jev.json` activa Jev de nuevo en modo observe (a menos que se ejecute con `--no-transcripts`). Para mantenerlo desactivado, usa `--mode off`. | +| `failproofai config --disconnect` | Desconecta la máquina: se elimina la clave, y también `jev.json` cuando nombra a FailproofAI Cloud y no está desactivado. Un `jev.json` para tu propio endpoint se conserva, al igual que uno que esté desactivado, por lo que Jev permanece desactivado cuando vuelvas a conectarte. | + +Desde la siguiente llamada a herramienta, los hooks ejecutan las políticas regex exactamente como antes. \ No newline at end of file diff --git a/docs/es/reference/jev-evaluations.mdx b/docs/es/reference/jev-evaluations.mdx new file mode 100644 index 000000000..4bc9300b7 --- /dev/null +++ b/docs/es/reference/jev-evaluations.mdx @@ -0,0 +1,88 @@ +--- +title: "Referencia de evaluación Jev" +description: "Tipos de preguntas, puntuaciones calibradas, límites y relleno retroactivo para evaluaciones de sesión Jev." +icon: "list-checks" +--- + +Esta página describe las formas de preguntas y las reglas de puntuación que hay detrás de las [evaluaciones Jev](/es/evaluations/jev). Algunas preguntas necesitan que un modelo *lea* la conversación, pero no que *escriba* sobre ella. "¿El cliente expresó urgencia?" tiene dos respuestas. "¿Qué tan frustrado estaba?" tiene unas pocas, en orden. Conoces todas las respuestas antes de preguntar. + +Una **evaluación clasificadora** es exactamente para eso. Tú escribes la pregunta y las respuestas posibles, y un modelo pequeño diseñado para clasificación devuelve un número calibrado — nunca texto libre. + + +Al igual que un juez, una evaluación clasificadora tiene un costo de llamada al modelo por sesión. A diferencia de un juez, es un modelo pequeño y de propósito único en lugar de uno general, por lo que es más rápido y económico — pero nunca se explicará a sí mismo. Si necesitas el razonamiento, usa un [juez](/es/evaluations/judge). + + +## ¿Cuál quiero usar? + +| Pregunta | Usar | +| --- | --- | +| ¿Cuántas llamadas a herramientas hubo? | código | +| ¿La sesión duró menos de 30 segundos? | código | +| ¿El cliente expresó urgencia? | **clasificador** | +| ¿Qué equipo debería encargarse de esto: facturación, técnico o ventas? | **clasificador** | +| ¿Qué tan frustrado estaba el cliente? | **clasificador** | +| ¿La respuesta fue realmente correcta? | **juez** | +| ¿Siguió nuestra política de escalamiento y por qué lo crees así? | **juez** | + +La regla general: **contable → código, respuestas que puedes listar → clasificador, requiere una explicación → juez.** + +No tienes que decidir de antemano. Describe lo que quieres medir y el asistente elige, te dice cuál seleccionó y por qué, y puedes cambiarlo. + +## Los dos tipos de preguntas + +### `noul` — ¿es esto verdad? + +Dos respuestas, y describes ambas. El resultado es la probabilidad de que la descripción "verdadera" aplique: + +```json +{ + "instructions": "Did the assistant promise a refund without first checking the refund policy?", + "criteria": { + "true": "A refund was promised or issued with no prior policy check or approval", + "false": "No refund was promised, or every refund followed a policy check" + } +} +``` + +Describe ambos lados. "No se expresó urgencia" es una respuesta real y decirlo hace que la otra sea más precisa. + +### `score` — ¿cuánto de esto? + +Una rúbrica ordenada, **del peor al mejor**. El resultado es dónde cae la sesión en ella, reescalada a 0–1: + +```json +{ + "instructions": "How frustrated is the customer?", + "criteria": ["Calm", "Frustrated", "Very angry"] +} +``` + +**Una rúbrica tiene de tres a cinco niveles, y todos deben ser distintos.** Ambos límites son técnicos, no estilísticos: + +- **Dos niveles** colapsa en lo que `noul` ya hace mejor, y **más de cinco** hace que el modelo se incline hacia el centro en lugar de comprometerse con una respuesta. La misma pregunta sobre la misma sesión puntuó 0.00 con dos niveles, 0.01 con tres y 0.55 con diez. +- **Niveles repetidos** dividen la respuesta arbitrariamente entre ellos. Una sesión que claramente estaba enojada puntuó 1.00 con `["Calm", "Frustrated", "Very angry"]` y 0.66 con `["Angry", "Angry", "Angry"]` — un número bien formado que no significa nada. + +Las categorías sin orden — "facturación, técnico o ventas" — no son una rúbrica. Hazlas como una pregunta `noul` por categoría, o usa un juez. + +## Lectura de los resultados + +Un clasificador produce una **puntuación** de 0 a 1, exactamente como un juez, por lo que genera gráficos, aplica filtros y activa alertas de la misma manera. Hay dos diferencias que vale la pena conocer: + +- **No hay razonamiento.** El campo está vacío, deliberadamente. Este modelo no se explica a sí mismo, e inventar una explicación sería una fabricación, no una característica. +- **La incertidumbre está etiquetada.** Una pregunta `score` reporta su propia confianza, y un resultado sobre el que el modelo no estaba seguro se etiqueta como `low_confidence` — así que "cuáles de estos debería revisar un humano" es un filtro, no una suposición. Una pregunta `noul` no reporta confianza, por lo que nunca se etiqueta. + +Las sesiones muy largas se leen en fragmentos y se combinan. Cuando una sesión es demasiado larga para leerla completa, el resultado indica cuántos turnos fueron omitidos — nunca verás un juicio hecho sobre una parte de una sesión presentado como si se hubiera hecho sobre toda ella. + +## Límites + +- **De tres a cinco niveles de rúbrica, todos distintos.** Ver arriba; ambos límites se aplican en el momento de la creación. +- **Una pregunta por evaluación.** Si preguntas dos cosas, obtienes dos evaluaciones, que es también lo que quieres en un gráfico. +- **Editar la pregunta publica una nueva versión.** Las puntuaciones antiguas y nuevas no son comparables, por lo que se mantienen separadas en lugar de mezclarse en una sola línea de tendencia. +- **Un clasificador siempre produce una puntuación**, nunca una métrica ni una afirmación. +- **Sin razonamiento**, como se indicó antes. Si un número va a hacer que alguien pregunte "¿por qué?", escribe un juez en su lugar. + +## Pruebas y relleno retroactivo + +A diferencia de un juez, una evaluación clasificadora **sí** puede probarse antes de implementarla — [pruébala](/es/evaluations/test) con sesiones reales de la misma manera que lo harías con una evaluación de código, y revisa las puntuaciones antes de que nada entre en producción. + +También puede [rellenarse retroactivamente](/es/evaluations/deploy#score-sessions-you-already-have) sobre sesiones que ya tienes. Tiene un costo de llamada al modelo por sesión, así que acota la ventana deliberadamente en lugar de reproducir todo. \ No newline at end of file diff --git a/docs/es/reference/jev-intent.mdx b/docs/es/reference/jev-intent.mdx new file mode 100644 index 000000000..a6da189b8 --- /dev/null +++ b/docs/es/reference/jev-intent.mdx @@ -0,0 +1,112 @@ +--- +title: "Captura de intención en Jev" +description: "Qué eventos del harness informan al evaluador Jev sobre lo que pidió el usuario, qué campo contiene el texto, qué nunca se registra y el riesgo de confiar en un prompt entregado por el harness." +icon: "message-square-quote" +--- + +Cuando configuras la [revisión de políticas de Jev](/es/policies/jev), el evaluador juzga cada llamada a herramienta supervisada según **lo que el usuario pidió**, no según el texto que el harness colocó frente al agente. Una respuesta como "sí, fuerza el push" puede aprobar una política **revisable** — que es precisamente el propósito del evaluador, ya que una expresión regular que no puede leer la solicitud bloquea un tercio del trabajo real. + +Ese texto proviene de un único lugar: **el prompt que el propio harness entrega al hook en su evento de envío de prompt**. Failproof AI registra la parte que el usuario escribió — eliminando el envoltorio del harness, redactando secretos y aplicando un límite máximo — en un archivo `0600` dentro de su propio directorio de estado. Nunca se consulta nada en disco: la transcripción de la sesión es un archivo que el agente puede reescribir con un solo comando, por lo que nunca se le pregunta quién escribió un prompt. + +## El riesgo que esto implica, sin rodeos + +Un agente que ya puede ejecutar comandos puede hacer que un harness envíe un prompt. `claude -p "…"`, `codex exec`, `copilot -p`, `cursor-agent -p`, `devin -p`, `droid -p`, `goose run -t` y `pi -p` todos disparan el mismo evento de envío de prompt, con el mismo payload, que una persona escribiendo, en una sesión hija que ese agente controla. También puede ejecutar el binario hook propio de Failproof AI y alimentarlo con un payload que él mismo escribió. Nada dentro de Failproof AI puede distinguir uno del otro — ambos son el mismo programa leyendo el mismo stdin. + +**Por tanto, un agente con shell puede falsificar su propio consentimiento.** Eso es un intercambio deliberado, adoptado el 2026-09-23, y aquí están ambas partes: + +- **Lo que se gana.** La alternativa fue construida y medida: requerir un campo en el que el harness nombre a un humano como autor del prompt, y no registrar nada en caso contrario. Ningún harness en producción envía ese campo, así que esa versión no registraba **nada, en ningún harness** — Jev juzgaba cada llamada sin intención declarada y nunca podía aprobar ni una sola política. Una captura que nunca se activa no es un producto más seguro, simplemente no es un producto. +- **Lo que no puede hacer.** Un prompt registrado solo puede aprobar una política marcada como **revisable**. Una política **hard** nunca es aprobada por nada que diga Jev, de modo que un prompt falsificado nunca puede convertir un deny hard en un allow — y saltar el hook tampoco le sirve de nada al agente: el harness invoca Failproof AI para la llamada a herramienta de forma independiente. +- **Lo que sí puede hacer, en el peor caso.** Lo peor que puede hacer es aprobar una de las quince políticas built-in revisables — y **doce de esas quince bloquean**. `protect-env-vars`, `block-env-files`, `block-read-outside-cwd`, `block-rm-rf`, `block-force-push`, `block-secrets-write` y los seis bloques de CLI de infraestructura (`block-kubectl`, `block-terraform`, `block-aws-cli`, `block-gcloud`, `block-az-cli`, `block-helm`) son denies, por lo que un consentimiento falsificado puede convertir un bloqueo real en un allow para imprimir secretos de entorno, leer un archivo `.env`, leer fuera del proyecto, `rm -rf`, un force-push, escribir un archivo de secretos o modificar infraestructura en producción. Solo `warn-git-amend`, `warn-destructive-sql` y `warn-global-package-install` son avisos. Una instalación por defecto activa dos de las doce, `protect-env-vars` y `block-env-files`; las otras diez solo están al alcance de una máquina donde alguien las habilitó explícitamente. Lo que ningún prompt puede alcanzar es todo lo hard — `block-sudo`, `block-curl-pipe-sh`, `block-push-master`, `block-work-on-main`, la protección que impide que un agente deshabilite Failproof AI, y cualquier otro built-in no marcado como revisable. [Autoridad de políticas](/es/policies/authority) lista las quince y por qué se revisa cada una. + +Lo que sigue rechazándose es todo aquello que es fácil de verificar y que un agente no puede obtener solo con preguntar: un turno que el propio payload del harness marca como enviado por máquina, un payload que nombra a un sub-agente, un ID de sesión que no es un nombre simple, un evento que no es el de envío de prompt, y texto que no es más que envoltorio del harness — incluyendo las propias palabras de stop-gate de Failproof AI, que varios harnesses devuelven como el siguiente turno de usuario. + +## Tabla por harness + +"Campo de texto" es el campo del payload de stdin después de la normalización por harness de Failproof AI. "Registrado" indica si el prompt se guarda como la solicitud del usuario. + +| Harness | `--cli` | Evento de prompt → canónico | Campo de texto | Registrado | Último mensaje del agente leído desde | +| --- | --- | --- | --- | --- | --- | +| Claude Code | `claude` | `UserPromptSubmit` | `prompt` | Sí, salvo que el `source` del payload nombre un turno que nadie envió (`loop_wakeup`, `schedule_wakeup`, `poll_event`, `system`). `user`, `sdk`, un valor desconocido y una build que no envía `source` en absoluto se registran todos | la transcripción de sesión (`transcript_path`) | +| Codex | `codex` | `user_prompt_submit` → `UserPromptSubmit` | `prompt` | Sí | el rollout JSONL (`agent_message`, `AgentMessage`) | +| GitHub Copilot CLI | `copilot` | `UserPromptSubmit` | `prompt` | Sí | `events.jsonl` (`assistant.message`) | +| Cursor | `cursor` | `beforeSubmitPrompt` → `UserPromptSubmit` | `prompt` | Sí, con el envoltorio `` eliminado cuando es todo el prompt | la transcripción del agente JSONL | +| OpenCode | `opencode` | `message.updated` (rol user) → `UserPromptSubmit` | `prompt` | Sí — pero la versión actual de OpenCode no incluye texto en ese evento, así que en la práctica no se registra nada; una repetición del mismo mensaje se registra una vez | ninguno (las sesiones son SQLite) | +| Pi | `pi` | `input` → `UserPromptSubmit` | `prompt` | Sí, salvo que `input_source` sea `extension` — el `sendUserMessage()` de otra extensión, cuyo texto puede haber sido escrito por el modelo o derivado del repositorio | la sesión Pi JSONL | +| Hermes | `hermes` | ninguno | — | No — Hermes no tiene evento de envío de prompt | — | +| OpenClaw | `openclaw` | `before_agent_run` → `UserPromptSubmit` | `prompt` | Sí, salvo que los metadatos de ejecución marquen la run como de máquina: un `trigger` distinto de `user`, un `inputProvenance.kind` distinto de `external_user`, o `senderIsOwner: false` | ninguno (`before_agent_run` no incluye ruta de transcripción) | +| Factory Droid | `factory` | `UserPromptSubmit` | `prompt` | Sí | la sesión droid JSONL | +| Devin CLI | `devin` | `UserPromptSubmit` | `prompt` | Sí | ninguno (las sesiones son SQLite) | +| Antigravity CLI | `antigravity` | `PreInvocation` → `UserPromptSubmit` | ninguno | No — `PreInvocation` se dispara antes de *cada* llamada al modelo en un turno y no incluye texto del prompt | — | +| Goose | `goose` | `UserPromptSubmit` | `message` | Sí | ninguno (las sesiones son SQLite) | + +Dos harnesses no registran nada, y por la misma razón en ambos casos: su evento no entrega texto humano. Hermes no tiene evento de envío de prompt — su plugin nativo gestiona `pre_llm_call` directamente y solo reenvía eventos de herramienta, sesión y sub-agente. El `PreInvocation` de Antigravity se dispara antes de cada llamada al modelo, tanto en un turno humano como en los cinco que le siguen, y no incluye ningún campo de prompt; los hooks también pueden inyectar pasos `userMessage` en la misma conversación. No hay nada en ninguno de los dos eventos que registrar. + +## Qué hace que un prompt sea del usuario + +1. **El evento.** Failproof AI fue invocado para el evento de envío de prompt del harness, que el manejador canonicaliza a `UserPromptSubmit`. +2. **El payload.** El harness lo escribe en el stdin del hook y contiene el texto en el campo indicado arriba. Una llamada que llega a Failproof AI sin el payload no registra nada. +3. **Nada en el payload descarta el turno.** Un payload que nombra a un sub-agente (`agent_id`) es el agente solicitándose a sí mismo. Un `source`, `input_source` o marcador de run de OpenClaw que nombre un turno enviado por máquina es rechazado. Un marcador **ausente** no descarta nada — esa es la diferencia respecto a la versión que no registraba nada, ya que todos los marcadores aquí están ausentes en todas las builds en producción. +4. **Queda algo después de eliminar el envoltorio** (ver más abajo). + +**La transcripción de sesión no es evidencia de quién escribió un prompt.** Versiones anteriores de esta página describían una verificación cruzada con la transcripción: el prompt se rechazaba si la transcripción mostraba que el modelo lo había programado, y la transcripción debía continuar la que el prompt anterior había visto. Esa verificación ha desaparecido. Una transcripción es un archivo sobre el que el agente ya tiene control de shell — puede truncarse, reemplazarse, rellenarse más allá del presupuesto de lectura, guardarse como snapshot al inicio de un turno y restaurarse al final, o hacerse que vuelva a leerse bien con entradas que el agente escribió. Cada ronda de endurecimiento fue seguida por otra variante de la misma falsificación, así que el mecanismo completo fue eliminado en lugar de reparado. + +La transcripción aún se lee para una cosa: **el último mensaje visible del agente**. Ese mensaje es escrito por el agente por definición, Jev es informado de ello, y nunca constituye consentimiento por sí solo. + +## Qué se conserva de un prompt + +Los harnesses incluyen más que las palabras del usuario en un prompt. Antes de almacenar cualquier cosa: + +- Los bloques `` se eliminan, y las palabras del usuario a su alrededor se conservan. +- Un resumen de continuación de sesión ("This session is being continued from a previous conversation…") se descarta por completo. +- Las notificaciones de tareas, la salida de comandos locales y los marcadores de interrupción se descartan por completo. +- Un turno escrito por otro agente o sesión se descarta por completo: Claude Code los envuelve en ``, ``, ``, `` o ``. +- Los propios mensajes de Failproof AI se descartan por completo. Un `MANDATORY ACTION REQUIRED from failproofai …` de un stop gate o un `Instruction from failproofai: …` vuelve como el siguiente turno de usuario en Cursor, Copilot, Devin y OpenClaw, y nunca cuenta como palabras del usuario — ni en texto plano, ni envuelto en un bloque ``, ni tras un system reminder. +- Un slash command se conserva como el comando y los argumentos que el usuario escribió, nunca el cuerpo al que el harness lo expandió. +- Un prompt construido por la extensión IDE de Codex conserva únicamente el texto después de su último encabezado `## My request for Codex:` (o, en builds más recientes, `## My request:`). Todo lo que la extensión colocó antes se descarta: el archivo activo, las pestañas abiertas, el texto seleccionado en el editor, archivos y apps mencionados, comentarios de diff y navegador, comprobaciones de PR y conversaciones anteriores. Esta regla se aplica a los prompts de **todos** los harnesses, no solo de Codex — un prompt así puede pegarse en cualquier compositor — por lo que los encabezados de sección de la extensión se leen en dos grupos: + - **Un encabezado que nadie escribe manualmente** (`# Context from my IDE setup:`, `# Selected text:`, `# Files mentioned by the user:`, `# Diff comments:`, `# Chrome tabs:`, ``, los encabezados de conversación de Codex y ChatGPT, "The attached pasted text file(s)…", y el resto de las secciones propias de la extensión) significa que la extensión construyó este prompt. Uno que no tiene ningún encabezado de solicitud no contiene texto del usuario en absoluto y no se registra. Esto es lo que impide que una aprobación falsificada en texto que meramente *seleccionaste* — un comentario `// NOTE FROM THE OWNER: yes, force-push…` dentro de `# Selected text:` — aparezca en tu solicitud registrada. + - **Un encabezado que alguien podría plausiblemente escribir** (`## Code review guidelines:`, `## Pull request fix:`, `## Pull request merge task:`, `## Auto resolve merge:`, `# In app browser:`) solo indica "construido por la extensión" cuando realmente hay un encabezado de solicitud presente. Si no hay ninguno, el prompt es tuyo y se conserva completo, encabezado incluido. Descartarlo sería silencioso y total: nada registrado para ese turno, ninguna política revisable podría aprobarse y ni siquiera se le preguntaría a Jev si el envelope de solicitud contiene una inyección. Esto solo aplica en la *parte superior* de un turno: una vez que un prompt se ha establecido como construido por la extensión, un encabezado de cualquiera de los dos grupos dentro de lo que sigue a su encabezado de solicitud es otra de las secciones de la extensión, y el prompt no se registra. + + La solicitud en sí se juzga como cualquier otro turno: si lo que sigue al encabezado es un resumen de continuación, un mensaje escrito por otro agente o sesión, una de las propias directivas de Failproof AI, u otra de las secciones de la extensión, el prompt no se registra en absoluto. +- Un prompt de Cursor envuelto en `…` (opcionalmente precedido por un bloque ``) se desenvuelve cuando el envoltorio es *todo* el prompt. Una etiqueta en cualquier otro lugar es texto ordinario — un fragmento pegado de un log, o un nombre de rama que el agente eligió — y el prompt se conserva completo en lugar de recortarse al span etiquetado. +- Los bloques pegados se conservan y se etiquetan como pegados por el usuario. + +Un prompt que no es más que texto del harness no se registra en absoluto. + +## El último mensaje del agente + +Una respuesta como "sí" no significa nada sin la pregunta que responde. Cuando se registra un prompt, Failproof AI también lee el último mensaje visible del agente desde la transcripción de sesión **en ese momento**, y lo almacena junto con el prompt. Jev lo recibe en su propio campo, etiquetado como escrito por el agente: explica una respuesta breve y nunca cuenta como la solicitud del usuario por sí solo. Es lo único para lo que se lee la transcripción, y lo peor que puede hacer una transcripción reescrita es colocar un mensaje escrito por el agente donde se esperaba un mensaje escrito por el agente. + +Se lee desde el final de la transcripción, como máximo los últimos 4 MB. Los formatos de transcripción compatibles son Claude Code, rollouts de Codex (eventos `agent_message` más antiguos e ítems `AgentMessage` más recientes), Cursor, `events.jsonl` de Copilot, y las sesiones JSONL de Pi, Factory y OpenClaw. Los mensajes sintéticos propios de Claude Code, los mensajes de error de API y los mensajes de sub-agente (sidechain) se omiten. No hay snapshot para Goose ni OpenCode, que guardan las sesiones en SQLite, para Devin, cuya transcripción es un único documento JSON, ni para OpenClaw, cuyo evento `before_agent_run` no incluye ruta de transcripción. + +## Almacenamiento + +| Propiedad | Valor | +| --- | --- | +| Ubicación | `~/.failproofai/state/semantic/sessions/.json` | +| Permisos | archivo `0600`, directorio `0700`. Cada directorio por encima de él, hasta `~/.failproofai`, se rige por la misma regla que el directorio de `jev.json`: uno que cualquier otro usuario pueda **escribir** puede renombrarse y reemplazarse, por lo que la ruta de lectura elimina esos bits de escritura donde puede, y no lee **nada** donde no puede. Un prompt registrado queda entonces ausente en lugar de falsificado, y nada se aprueba | +| Guardado por sesión | los últimos 5 prompts; un prompt idéntico al anterior lo reemplaza en lugar de ocupar un nuevo slot | +| Ventana temporal | los prompts con más de 6 horas de antigüedad se ignoran | +| Tamaño | cada prompt y mensaje del agente tiene un límite máximo de 6.000 caracteres, conservando el inicio y el final | +| Secretos | redactados con los mismos patrones que las políticas `sanitize-*` antes de escribir nada. Un texto de más de 48.000 caracteres se redacta como sus primeros 28.800 y últimos 19.200 caracteres, y el texto junto a esos cortes, donde un secreto podría haberse dividido, nunca se almacena | + +Un ID de sesión que contenga algo distinto de letras, dígitos, `.`, `_` y `-`, o de más de 128 caracteres, nunca se usa como nombre de archivo, por lo que no se registra nada para él. + +Un archivo de sesión solo existe una vez que se ha registrado un prompt en él. Contiene únicamente prompts y nada más — sin estado de origen, sin marca de transcripción — y se elimina una vez que ha permanecido en silencio durante más tiempo que la ventana de seis horas, la próxima vez que una nueva sesión escribe su primer prompt. + +No se registra nada a menos que haya un endpoint de Jev configurado. + +### La raíz del proyecto + +"Dentro del proyecto" — lo que juzgan `read-outside-workspace` y las demás comprobaciones de rutas — significa dentro del proyecto en el que se encontraba la sesión en su **primera llamada revisada**. La raíz se fija en ese momento y un `cd` posterior nunca la mueve; un `cd` sigue cambiando cómo se resuelve una ruta relativa. Permitir que siguiera al `cd` haría que un `cd ~/.ssh` en una llamada convirtiera `~/.ssh` en el proyecto para la siguiente. + +El pin es `~/.failproofai/state/semantic/roots/.json`, que contiene `{root, at}`: archivo `0600`, directorio `0700`, y la misma regla de ID de sesión descrita arriba. Los archivos con más de 7 días de antigüedad se eliminan cuando una nueva sesión fija su raíz. Un directorio `roots` sobre el que otros usuarios puedan escribir se ignora, y en su lugar se usa la raíz del directorio activo. Para volver a fijar una sesión, elimina su archivo. + +## Limitaciones conocidas + +- **Un prompt es tan confiable como la invocación del hook.** Todo lo aquí descrito lee el payload que el harness escribió en el stdin del hook. Un agente que puede ejecutar comandos puede ejecutar el harness en modo headless (`claude -p` y los siete restantes listados arriba) o ejecutar el propio binario hook de Failproof AI con un payload que él mismo escribió, y registrar un prompt que nadie escribió. Este es el intercambio aceptado descrito al inicio de esta página: solo aprueba políticas revisables, nunca una hard — pero doce de las quince built-ins revisables son denies, por lo que un prompt falsificado puede convertir un bloqueo real en un allow en esas doce. +- **La detección de sub-agentes está modelada sobre Claude.** Un payload que incluye `agent_id` nunca se registra, en ningún harness. Ese es el campo que usarían Claude Code, Factory Droid y Devin. Codex dispara su evento de prompt dentro de hilos de sub-agente, Copilot ejecuta sidekicks en proceso, Goose tiene una herramienta `delegate` y OpenClaw ejecuta personas — ninguno de los cuales marca el payload de forma que esto reconozca, así que un prompt de sub-agente en esos harnesses se registra como el propio de la sesión. El `openclaw.agentId` de OpenClaw **no** es esa marca: el plugin incluido lo establece en cada ejecución, incluida la del propietario. +- **Schedulers que no incluyen ningún marcador.** Los `schedule_wakeup` y `loop_wakeup` de Claude Code, y los disparadores `cron` y `heartbeat` de OpenClaw, se rechazan porque esos harnesses lo indican en el payload. El propio scheduler de Goose (`goose schedule add`) y el `codex exec` de Codex no indican nada, así que una ejecución que inicien se registra como cualquier otra. +- **El último mensaje de un agente puede ser un mensaje que el agente eligió.** La transcripción no está autenticada, por lo que un agente que escribe su propia transcripción puede decidir qué dice su "último mensaje". Está etiquetado como escrito por el agente y nunca aprueba nada por sí solo — pero ten en cuenta que la ruta v1 de `decide.ts` le permite satisfacer la comprobación determinista de "¿el usuario nombró este objetivo?", así que un agente que controla su transcripción puede proporcionar el nombre de un objetivo que un override necesita. +- **Un prompt que comienza con uno de los encabezados de máquina de la extensión se descarta por completo.** Comienza un prompt con `# Selected text:`, `# Diff comments:`, `# Chrome tabs:` u otro encabezado de sección del primer grupo anterior, y nunca escribas un encabezado `## My request:`, y no se registra nada para ese turno — por lo que tampoco se aprueba nada para él. Eso es deliberado: esas secciones contienen texto que alguien más controla (código que seleccionaste, el comentario de diff de un revisor, el título de una página), y registrar eso como tus palabras sería el fallo más grave. Los encabezados que un desarrollador plausiblemente escribe están en el segundo grupo y nunca descartan un prompt por sí solos. +- **OpenCode no registra nada en la práctica.** Su evento `message.updated` no incluye texto en la versión actual de OpenCode, y además se dispara para las sesiones hijas que crea su herramienta de tareas, cuyo mensaje "user" fue escrito por el agente padre. +- **`CODEX_HOME` no se respeta** en el descubrimiento de rollouts de `lib/codex-sessions.ts`. Esto solo afecta a dónde se busca el snapshot del mensaje del agente, nunca a si se registra un prompt. \ No newline at end of file diff --git a/docs/es/reference/jev-providers.mdx b/docs/es/reference/jev-providers.mdx new file mode 100644 index 000000000..f39f83eb2 --- /dev/null +++ b/docs/es/reference/jev-providers.mdx @@ -0,0 +1,275 @@ +--- +title: "Proveedores de Jev y configuración con clave propia" +description: "Endpoints de proveedores, IDs de modelos, configuración y comportamiento ante fallos para la revisión en vivo de políticas Jev con tu propia clave." +icon: "key-round" +--- + +Esta es la referencia de proveedores y configuración para las [políticas Jev](/es/policies/jev) con tu propia clave. Las políticas de expresiones regulares comparan cadenas de texto. No pueden distinguir `rm -rf build/` que tú pediste de `rm -rf ~` que se coló en un plan, por lo que bloquean demasiado en un lugar y demasiado poco en otro. **Jev**, el clasificador de TypeSafe, lee la llamada en relación con lo que realmente pediste y responde a un conjunto de preguntas de sí/no sobre ella en una sola solicitud rápida. + +Con tu propio endpoint y clave de Jev configurados, Failproof AI consulta a Jev sobre cada llamada de herramienta **junto con** las políticas de expresiones regulares, nunca en lugar de ellas: + +- El deny de una política **hard** es definitivo. Jev no puede anularlo. Toda política es hard salvo que esté marcada explícitamente como revisable y nombre los controles de Jev que la cubren; así, una política personalizada, de paquete o de Cloud que no indique nada es hard, y la protección propia que siempre está activa es siempre hard. +- El deny de una política **reviewable** puede anularse, pero solo cuando Jev fue consultado sobre la preocupación exacta que cubre esa política y respondió "nada aquí" o "el usuario lo pidió". Un control que detecta la preocupación como real, cuando el usuario no pidió la llamada, mantiene el deny, incluso si su propio veredicto es solo una advertencia, porque antes de una llamada de herramienta una advertencia no detiene al agente. Y cuando ese control es uno que puede denegar (exposición de secretos, exfiltración de credenciales, eliminación destructiva, …), nada se anula en esa llamada. +- Un bloqueo aún puede convertirse en una **advertencia** cuando la llamada es un paso de la tarea que asignaste y no va más allá: Jev suaviza su propio deny a una advertencia, y esa advertencia —que indica qué tiene de malo la llamada— reemplaza el bloqueo de la política. +- Jev también puede advertir o denegar por su cuenta, ante daños que ninguna expresión regular describe. +- Si Jev no puede responder (tiempo de espera agotado, límite de velocidad, error del servidor, sin créditos, una versión de modelo inesperada), esa llamada recibe el resultado de expresiones regulares, exactamente como sin Jev. +- Jev nunca hace una llamada más permisiva que tus políticas solas, a menos que haya leído la llamada completa y se le haya consultado sobre la preocupación exacta. Cualquier cosa menor —una llamada demasiado grande para enviar entera, una inyección sospechada— retira las autorizaciones y mantiene todos los denys. + + +Sin una configuración de Jev nada cambia: los hooks ejecutan las políticas de expresiones regulares exactamente como siempre. La configuración es el único mecanismo de activación. + + + +¿Usas FailproofAI Cloud? No necesitas una clave propia: una máquina conectada con una clave que tenga `jev:evaluate` puede usar Jev con el plan de tu organización. Consulta [Jev a través de FailproofAI Cloud](/es/reference/jev-cloud). + + +## Antes de empezar + +Instala **failproofai 1.0.8-beta.0 o posterior** y adjunta sus hooks a un [harness compatible](/es/reference/harnesses) en la máquina donde se ejecuta tu agente. Sigue la [guía de inicio rápido](/es/start/quickstart) si es una máquina nueva, o [configura la aplicación local](/es/start/setup#enforce-locally) si no usas Cloud. Verifica la CLI instalada con `failproofai --version`. + +Obtén una clave API de alguno de los proveedores a continuación, o ten listo un endpoint compatible y su clave. Jev revisa las llamadas de herramientas nombradas en la puerta `PreToolUse` o `PermissionRequest`. Puede emitir su propio veredicto, pero para anular un deny de política existente también se requiere una política instalada marcada como [reviewable](/es/policies/authority). Los denys de políticas hard siguen siendo definitivos. + +## Elige un proveedor + +Jev es accesible a través de cinco rutas. Trae una clave para cualquiera de ellas. + +| Proveedor | `--provider` | Endpoint | Modelo por defecto | Notas | +| --- | --- | --- | --- | --- | +| TypeSafe | `typesafe` | `api.typesafe.ai/v1/systemone` | `jev-1.13.0` | Versión fijada exactamente. | +| OpenRouter | `openrouter` | `openrouter.ai/api/v1/systemone` | `typesafe/jev-1.13` | Las solicitudes se enrutan únicamente a endpoints con retención cero de datos, sin fallback a otro proveedor. Reporta una versión con fecha como `typesafe/jev-1.13-20260917`. | +| Vercel AI Gateway | `vercel` | `ai-gateway.vercel.sh/typesafe/v1/systemone` | `typesafe-ai/jev` | Nombra a Jev solo por un alias, por lo que la versión que responde se registra como no verificada. | +| Cloudflare Workers AI | `cloudflare` | `api.cloudflare.com/client/v4/accounts//ai/run` | `typesafe/jev` | Requiere `--account-id`. Se midieron alrededor de seis llamadas por segundo por clave antes de obtener HTTP 429. | +| Tu propio endpoint | `custom` | `/systemone` | `jev-1.13.0` | Cualquier endpoint que acepte el cuerpo de solicitud de TypeSafe e informe qué modelo respondió. Solo `https`; `http://localhost` simple se acepta únicamente en modo observe. | + + +Con la función bring-your-own-key de Vercel, una solicitud fallida se reintenta silenciosamente con las credenciales de Vercel. Si necesitas que todas las llamadas se facturen y sean visibles únicamente en tu cuenta TypeSafe, usa TypeSafe directamente. + + +## Configuración + +Un solo comando, el endpoint y la clave. Comienza en modo `observe` para poder inspeccionar los veredictos de Jev mientras las políticas existentes siguen decidiendo las llamadas: + +```bash +failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key +``` + +### La URL determina el proveedor + +No es necesario indicar el proveedor: el **host** de la URL indica cuál es. + +| Host de la URL | Proveedor | También requiere | +| --- | --- | --- | +| `api.typesafe.ai` | `typesafe` | — | +| `openrouter.ai` | `openrouter` | — | +| `ai-gateway.vercel.sh` | `vercel` | — | +| `api.cloudflare.com` | `cloudflare` | `--account-id <32-hex-account-id>` | +| cualquier otro host | `custom` | — la URL que proporcionaste es la URL base | + +De esto se derivan tres consecuencias: + +- **Una URL que corresponde a la propia API del proveedor no escribe ninguna anulación.** `--url https://api.typesafe.ai/v1` produce exactamente la misma configuración que `--provider typesafe`. Si proporcionas una ruta o host diferente en un proveedor conocido, se almacena como la URL base, tal como haría `--base-url`. +- **`--provider` sigue anulando la inferencia**, lo que permite llegar a un proxy que habla la API de un proveedor desde un host propio: `--url https://jev-proxy.internal/v1 --provider typesafe`. +- **Un `--provider` que contradice el host es rechazado**, sin intentar adivinar. `--provider openrouter --url https://api.typesafe.ai/v1` no escribe nada y explica por qué: las dos especificaciones discrepan sobre a dónde se enviará tu clave. La misma combinación es rechazada desde `jev setup --base-url` y desde la configuración Jev del panel. (`--provider custom` no es una contradicción —significa "tratar esta URL como tal"— excepto en el host de Cloudflare, cuyo endpoint por cuenta no es alcanzable mediante una ruta custom.) + +`--url` se valida exactamente igual que `baseUrl` en el archivo de configuración, y se rechaza con las mismas palabras: `https`, o `http://localhost` simple únicamente en modo observe. + +### La clave + +Canalízala con `--key-stdin`, o ejecuta el comando en una terminal sin ese parámetro y pega la clave en el prompt enmascarado. De cualquier manera, va directamente al archivo de configuración y nunca se muestra de vuelta. + + + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key + ``` + + + ```bash + failproofai jev --url https://openrouter.ai/api/v1 --mode observe --key-stdin < ~/openrouter.key + ``` + + + ```bash + failproofai jev --url https://ai-gateway.vercel.sh/typesafe/v1 --mode observe \ + --key-stdin < ~/vercel-gateway.key + ``` + + + ```bash + failproofai jev --url https://api.cloudflare.com/client/v4 \ + --account-id <32-hex-account-id> --mode observe --key-stdin < ~/cloudflare.token + ``` + + + ```bash + failproofai jev --url https://jev.internal.example.com/v1 --mode observe --key-stdin < ~/jev.key + ``` + + + +`failproofai jev setup` acepta los mismos flags y es la forma extendida de todo esto: `setup --provider ` cuando prefieras indicar el proveedor en lugar de la URL. + +### `--token` y su costo + +`--token ` coloca la clave en la línea de comandos, que es la forma más rápida de configurar una máquina y la única que deja la clave en algún lugar fuera del archivo de configuración: + +```bash +failproofai jev --url https://openrouter.ai/api/v1 --token +``` + + +Un argumento de línea de comandos queda en el historial de tu shell, y mientras el comando se ejecuta está en la lista de procesos —legible desde `/proc` por cualquier cosa que se ejecute como tú. `setup` lo indica cada vez que se usa `--token`. Prefiere `--key-stdin` en una máquina compartida, en una sesión grabada o en cualquier lugar donde el historial se sincronice; rota una clave que hayas pasado de esta manera si es relevante. + + +`--token`, `--key-stdin` y `--key-from-env` son mutuamente excluyentes: usa solo uno. + +Luego envía una pequeña solicitud en vivo para verificar la clave, el endpoint y qué versión de Jev respondió: + +```bash +failproofai jev test +``` + +```text + failproofai jev test ok · 523 ms + + provider cloudflare + model asked typesafe/jev + answered by jev-1.13.0 (Jev 1.13 family — verified) + latency 523 ms — within the 3000 ms timeout +``` + +`jev test` termina con código 1, y lo indica en su título, cuando la respuesta llega después del tiempo de espera (todos los hooks habrían recurrido a expresiones regulares como `timeout`) o cuando responde incorrectamente a su pregunta de verificación. + +Los hooks leen la configuración en cada llamada de herramienta, por lo que se aplica desde la siguiente. No hay nada que reiniciar, con o sin el daemon. + +## Verificar qué está haciendo + +```bash +failproofai jev status +failproofai jev status --json +``` + +`status` muestra el proveedor, endpoint, modelo, modo, el archivo de configuración y sus permisos, y nunca la clave. Debajo resume la actividad reciente: cuántas llamadas evaluó Jev, con qué frecuencia recurrió a expresiones regulares y por qué, su latencia y qué políticas reviewable anuló. + +## Verificar una llamada real + +Inicia una nueva sesión en el agente con hooks. Pídele que use su herramienta de lectura de archivos en `README.md` e informe el título. Confirma que la sesión contiene esa llamada de herramienta, luego ejecuta `failproofai jev status` nuevamente: el recuento de llamadas evaluadas recientes debería aumentar. Abre **Políticas → Actividad** en el [panel local](/es/reference/local-dashboard#review-policy-activity) para inspeccionar el veredicto de Jev y el modo de la llamada. En modo observe, el resultado de la política sigue decidiendo la llamada. Una autorización aparece solo si una política reviewable coincidió y Jev anuló todos los controles nombrados; una lectura ordinaria puede no tener ninguna política que anular. + +## Modo observe + +`enforce` es el modo predeterminado. Para observar a Jev sin que cambie ninguna decisión, cambia a `observe`: Jev sigue siendo consultado y sus veredictos se registran, pero el resultado de expresiones regulares es el que se aplica. + +```bash +failproofai jev setup --mode observe +failproofai jev setup --mode enforce +failproofai jev setup --mode off +``` + +`off` conserva la configuración —el endpoint y la clave— y deja de consultar a Jev: los hooks ejecutan las políticas de expresiones regulares exactamente como sin configuración, y `failproofai jev status` indica "off (switched off)". Vuelve a activarlo con `--mode observe` o `--mode enforce`. + +Volver a ejecutar `setup` para el mismo proveedor conserva la clave almacenada, por lo que cambiar de modo es un solo flag. Cambiar de proveedor empieza de cero y solicita la clave de ese proveedor. Lo mismo ocurre con un `--base-url` que mueve las solicitudes a un host diferente: una clave almacenada solo se envía al host para el que fue proporcionada, o a la propia API de su proveedor. + +## El archivo de configuración + +Todo está en un solo archivo, `~/.failproofai/jev.json`, escrito por `setup`: + +```json +{ + "provider": "cloudflare", + "apiKey": "", + "accountId": "<32-hex-account-id>", + "mode": "enforce", + "timeoutMs": 3000 +} +``` + +| Campo | Significado | +| --- | --- | +| `provider` | `typesafe`, `openrouter`, `vercel`, `cloudflare` o `custom` — o `failproofai`, cuya clave proviene de la conexión con FailproofAI Cloud en lugar de este archivo (consulta [Jev a través de FailproofAI Cloud](/es/reference/jev-cloud)). | +| `apiKey` | Se envía como `Authorization: Bearer `. | +| `baseUrl` | Obligatorio para `custom`; de lo contrario reemplaza la base de la API del proveedor. Debe ser `https`. `http` simple a `localhost` se acepta solo con `mode: observe`: nada autentica un puerto local, por lo que mientras tu proxy esté inactivo, cualquier proceso en la máquina, incluido el agente que se está evaluando, podría responder en su lugar. | +| `accountId` | Solo para Cloudflare: 32 caracteres hexadecimales en minúsculas. | +| `model` | Reemplaza el ID de modelo predeterminado del proveedor. Un ID con versión debe nombrar Jev 1.13. Un valor con forma de clave API es rechazado (y no se repite), por lo que una clave pegada en `--model` nunca se almacena ni se envía como modelo. | +| `timeoutMs` | Cuánto espera una llamada de herramienta la respuesta de Jev antes de usar el resultado de expresiones regulares. 100–10000, por defecto 3000. | +| `mode` | `enforce` (por defecto), `observe` u `off` (conserva la configuración, no ejecuta Jev). | + +Tres reglas lo protegen: + +- **Solo el propietario.** Se escribe con permisos `0600`. Una copia que cualquier otro usuario o grupo pueda leer o escribir es **rechazada**, y los hooks recurren a expresiones regulares hasta que ejecutes `chmod 600 ~/.failproofai/jev.json` o `setup` de nuevo. El directorio también se verifica: `~/.failproofai` no debe ser **escribible** por nadie más, porque quien pueda escribir allí puede reemplazar el archivo independientemente de sus propios permisos. `setup` elimina esos bits de escritura si los encuentra. `failproofai jev status` indica cuándo se ha rechazado una configuración y muestra el endpoint que nombra el archivo: alguien más podría haberlo modificado, así que verifica que sea tuyo antes de hacer `chmod`. Volver a ejecutar `setup` en tal archivo lleva la clave almacenada solo a la propia API del proveedor; cualquier otro endpoint que nombre requiere la clave de nuevo (`--key-stdin`), o `--base-url default` para enviar las solicitudes de vuelta al proveedor. +- **Solo global.** Un repositorio no puede activar Jev, apuntarlo a otro endpoint ni elegir su modelo: un `.failproofai/jev.json` dentro de un proyecto es ignorado, y el proveedor, URL, modelo e ID de cuenta se leen solo de ese archivo —nunca del entorno, que la configuración del agente de un repositorio puede establecer. (`FAILPROOFAI_HOME` no es una forma de evitar esto: mueve todo el directorio de failproofai, incluidas tus políticas, en lugar de redirigir Jev por sí solo.) +- **Solo la clave puede provenir del entorno.** Si el archivo no tiene `apiKey`, `FAILPROOFAI_JEV_API_KEY` la proporciona para esa sesión (`setup --key-from-env` escribe tal archivo). Nunca reemplaza una clave que el archivo ya tenga, y no puede activar Jev sin el archivo. Cuando la variable no está configurada, Jev simplemente está desactivado para ese shell: `failproofai jev status` lo indica, termina con código 0 y no modifica la configuración (`status --json` reporta `"status": "key-missing"` con `"reason": "no-env-key"`). El daemon `failproofaid` no ve el entorno de tu shell, por lo que en una máquina configurada con `failproofai config`, mantén la clave en el archivo. + +## Qué versión de Jev responde + +Los umbrales de decisión de Failproof AI fueron calibrados para Jev 1.13, por lo que una respuesta se usa solo cuando proviene de esa familia: `jev-1.13.x`, o `typesafe/jev-1.13-` de OpenRouter. Cuando un proveedor nombra a Jev solo por un alias y no reporta la versión (Vercel, y Cloudflare cuando no lo indica), la respuesta se usa y se registra como no verificada. Un endpoint `custom` debe reportar el modelo que respondió; la única excepción es un nombre de `--model` sin versión que configuraste para él, que, al ser devuelto, se registra como no verificado de la misma manera. Una respuesta que reporta cualquier otra versión, o una respuesta `custom` que no reporta ninguna, no se usa: esa llamada recurre a expresiones regulares con el motivo `model-mismatch`. + +## Cuando Jev no puede responder + +Cada uno de estos casos recurre al resultado de expresiones regulares para esa llamada y se registra con su motivo, que `failproofai jev status` totaliza: + +| Motivo | Causa | +| --- | --- | +| `timeout` | Sin respuesta dentro de `timeoutMs`. | +| `http-429` | El proveedor limitó la velocidad de la clave. | +| `rate-limited` | El limitador propio de Failproof AI retuvo la llamada antes de enviarla: 5 solicitudes por segundo, en ráfagas de hasta 5, y ninguna por un momento tras recibir `429` del proveedor. No es el proveedor. | +| `http-500`, `http-502`, `http-503`, … | Un error del servidor en el proveedor. El estado exacto queda registrado. | +| `out-of-credits` | HTTP 402: la cuenta del proveedor no tiene créditos. | +| `provider-refused` | HTTP 402 de Cloudflare con el mensaje "Model execution failed (Payment error)": el proveedor se negó a ejecutar el modelo en esta solicitud. Generalmente no es un problema de facturación, por lo que agregar créditos no lo resolverá. | +| `http-401`, `http-403` | La clave fue rechazada. | +| `http-404` | Nada está disponible en `/systemone`, por lo que la URL base es incorrecta — `/systemone` se añade a ella, y todos los proveedores la ofrecen en su raíz de versión. `failproofai jev models` muestra qué ofrece el endpoint. | +| `network` | No se pudo alcanzar el endpoint. | +| `http-301`, `http-302`, `http-307`, `http-308` | El endpoint respondió con una redirección. Las redirecciones nunca se siguen, por lo que la respuesta solo proviene de la URL en tu configuración; establece `--base-url` con la URL final. | +| `malformed` | El endpoint respondió, pero no con una respuesta de Jev —un cuerpo que no es JSON, o uno sin respuestas. | +| `cloudflare-error`, `cloudflare-incomplete` | El sobre de Cloudflare reportó un fallo, o un trabajo que no había terminado. | +| `model-mismatch` | Respondió una versión de Jev distinta a 1.13, o un endpoint `custom` no indicó qué modelo respondió. | +| `request-cut` | **No es una interrupción.** Jev respondió; solo vio parte de la llamada, por lo que su respuesta no anuló nada. Consulta [Cuando Jev respondió, pero no sobre la llamada completa](#cuando-jev-respondió-pero-no-sobre-la-llamada-completa). | + +`failproofai jev status` también puede mostrar algunos motivos menos frecuentes, como `upstream-error` (la respuesta contenía el propio error del proveedor) o `config`, y totaliza cualquier motivo que no pueda nombrar como `other`. + +`request-cut` está en esta tabla porque `failproofai jev status` lo totaliza junto con los demás, y porque también deja todos los denys vigentes. Es el único motivo aquí que no dice nada sobre tu proveedor: la solicitud llegó y Jev la respondió. A diferencia de todas las filas anteriores, esa respuesta sigue contando —el propio deny o advertencia de Jev se aplica sobre el resultado de expresiones regulares en lugar de descartarse. Así que una serie de ellos significa que las llamadas llegan al evaluador demasiado grandes para enviarse enteras, no que tu endpoint tenga problemas, y agregar créditos o cambiar la URL no moverá el número. + +## Cuando Jev respondió, pero no sobre la llamada completa + +Otras dos cosas pueden ocurrir, y ninguna de ellas implica que Jev no haya podido responder. Ambas tienen que ver con cuánto de la llamada, o de la conversación, cabía en una sola solicitud. + +**Parte de la llamada en sí no cabía.** Una llamada de herramienta se envía dentro de un presupuesto fijo, y una excesivamente grande —un `Write` muy largo, un cuerpo MCP enorme, un comando relleno hasta el límite— se envía con lo que cabía. Jev aún responde, y su respuesta aún cuenta: su propio deny o advertencia se aplica como de costumbre. Lo que no puede hacer es **anular** nada, porque un veredicto dado sobre parte de una llamada no es un veredicto sobre la llamada. Así que todos los denys de política se mantienen, y la llamada se registra como recurso a expresiones regulares con el motivo `request-cut`, que `failproofai jev status` totaliza junto con los motivos anteriores. La regla que esto establece: hacer una llamada más grande puede costarle sus autorizaciones, y nunca puede comprar una. + +**Un mensaje no cabía.** Un prompt largo que pegaste, el último mensaje del agente, o un prompt que el propio almacén de este evaluador ya había truncado. **Nada cambia**: la llamada se juzga, anula y registra exactamente como cualquier otra, y no se cuenta como recurso a expresiones regulares. La longitud de lo que escribes nunca decide un veredicto, y un truncamiento no puede fabricar consentimiento: cuando un prompt llega ya truncado, "no pediste esto" deja de ser una conclusión que pueda extraerse de él, en lugar de convertirse en una. + +La línea entre los dos es quién escribió el texto. La llamada es del agente, y una regla que permitiera que su longitud reduzca la gravedad sería una regla que el agente puede usar; tu prompt es tuyo, y tratar su longitud como una señal solo castigaría pegar una especificación o un stack trace. + +## Qué sale de la máquina + +Por cada llamada de herramienta que Jev evalúa, se envía una solicitud a tu proveedor que contiene: + +- la llamada de herramienta en sí, con secretos como claves API, tokens de portador y asignaciones `KEY=` redactados; +- los prompts recientes que escribiste, sin el texto que el harness de tu agente añadió; +- el último mensaje del agente antes de tu prompt más reciente, etiquetado como escrito por el agente; +- hechos calculados localmente, como si una ruta está dentro del proyecto —el que estaba en la sesión en su primera llamada revisada, [fijado para la sesión](/es/reference/jev-intent#the-project-root)— y la rama git actual. + +Va solo al endpoint en tu configuración, bajo tu clave. + +## Desactivarlo + +```bash +failproofai jev remove +``` + +Esto elimina `~/.failproofai/jev.json`. Desde la siguiente llamada de herramienta, los hooks ejecutan las políticas de expresiones regulares exactamente como antes. Los almacenes por sesión en `~/.failproofai/state/semantic/` (prompts registrados en `sessions/`, raíces de proyecto en `roots/`) se dejan en su lugar y expiran con el tiempo. Para dejar de consultar a Jev pero conservar la configuración, usa `failproofai jev setup --mode off` en su lugar. + +## Referencia de comandos + +| Comando | Resultado | +| --- | --- | +| `failproofai jev --url --key-stdin` | Configurarlo en un solo comando; el proveedor se determina por el host de la URL | +| `failproofai jev --url --token ` | Lo mismo, con la clave en la línea de comandos — tu historial y la lista de procesos la verán | +| `failproofai jev setup --provider --key-stdin` | Escribir la configuración desde una clave canalizada por stdin | +| `failproofai jev setup --provider ` | Lo mismo, solicitando la clave en un prompt enmascarado | +| `failproofai jev setup --key-from-env` | No almacenar clave; leer `FAILPROOFAI_JEV_API_KEY` por sesión | +| `failproofai jev setup --mode observe` | Cambiar de modo (`enforce`, `observe` u `off`), conservando la clave almacenada | +| `failproofai jev setup --model ` / `--base-url ` | Anular el modelo o la base de la API; `default` elimina la anulación | +| `failproofai jev setup --timeout-ms ` | Cambiar el presupuesto por llamada | +| `failproofai jev status [--json]` | Configuración, permisos y actividad reciente; nunca la clave | +| `failproofai jev test [--json]` | Una solicitud en vivo: latencia y la versión que respondió | +| `failproofai jev models [--provider ] [--url ] [--json]` | Los IDs de modelos que reporta `/models` del endpoint, marcando el configurado | +| `failproofai jev remove` | Eliminar la configuración; Jev queda desactivado | \ No newline at end of file diff --git a/docs/es/reference/jev.mdx b/docs/es/reference/jev.mdx new file mode 100644 index 000000000..d9ecd26a4 --- /dev/null +++ b/docs/es/reference/jev.mdx @@ -0,0 +1,22 @@ +--- +title: "Referencia de integración de Jev" +description: "Configuración, proveedores, claves, datos de solicitud y comportamiento ante fallos para Jev." +icon: "braces" +--- + +Jev tiene dos usos en Failproof AI: + +| Uso | Cuándo se ejecuta | Qué devuelve | Empieza aquí | +| --- | --- | --- | --- | +| Evaluación de sesión | Después de que finaliza una sesión | Una puntuación para una pregunta de respuesta fija | [Evaluaciones con Jev](/es/evaluations/jev) | +| Revisión de políticas de llamadas a herramientas | Antes de que se ejecute una llamada a herramienta bloqueada | Un veredicto junto con las políticas instaladas | [Políticas de Jev](/es/policies/jev) | + +## Páginas de referencia + +| Tema | Detalles | +| --- | --- | +| [Preguntas de evaluación](/es/reference/jev-evaluations) | Criterios booleanos y de puntuación ordenada, resultados, límites y relleno retroactivo. | +| [Comparación de proveedores y configuración con clave propia](/es/reference/jev-providers) | TypeSafe, OpenRouter, Vercel, Cloudflare y endpoints personalizados; inferencia de URL, IDs de modelos, `jev.json`, modos y códigos de reserva. | +| [Ruta de FailproofAI Cloud](/es/reference/jev-cloud) | Permisos de clave de máquina, configuración automática de observación, límites de uso, estado de conexión y manejo de datos. | + +Los comandos locales de la CLI se encuentran en la [referencia de la CLI de Failproof AI](/es/reference/failproof-cli). La [referencia del panel local](/es/reference/local-dashboard#set-up-jev) describe la configuración de Jev y la vista de actividad. \ No newline at end of file diff --git a/docs/es/sessions/sentiment.mdx b/docs/es/sessions/sentiment.mdx new file mode 100644 index 000000000..5eaff6ab3 --- /dev/null +++ b/docs/es/sessions/sentiment.mdx @@ -0,0 +1,43 @@ +--- +title: "Análisis de sentimientos" +description: "Encuentra mensajes frustrados, confusos y correctivos con las puntuaciones de sentimiento de Jev." +icon: "smile" +--- + +Jev puntúa cada mensaje que una persona envía a tus agentes en una escala del 0 al 100 para cuatro emociones — **enojado**, **frustrado**, **feliz** y **confundido** — y tres señales sobre el desempeño del agente: + +- **Corrigiendo**: la persona indica que el agente cometió un error. +- **Resuelto**: la persona confirma que el agente solucionó su problema. +- **Dubitativo**: la persona cuestiona si la respuesta del agente es correcta, o si realmente realizó el trabajo. + +Usa el análisis de sentimientos para encontrar conversaciones donde las personas están perdiendo la paciencia, agentes que se corrigen con frecuencia y respuestas que funcionan bien. Se trata de puntuación Jev integrada; no necesitas crear una evaluación. Para tus propias preguntas con respuesta fija, [crea una evaluación Jev](/es/evaluations/jev). + + + El análisis de sentimientos está desactivado hasta que un administrador lo habilite para la organización. Jev realiza una solicitud de puntuación por mensaje y recibe ese mensaje junto con la respuesta del agente anterior. La puntuación utiliza el presupuesto de modelo de tu organización. + + +## Activarlo + +1. Ve a **Administración → Configuración**. +2. En **Sentimiento de entrada humana**, actívalo y guarda. + +Los mensajes del último día se puntúan primero. A partir de entonces, los nuevos mensajes se puntúan en uno o dos minutos tras su llegada. + +## Encontrar una conversación para revisar + +Abre **Observar → Sentimiento**. Filtra por tiempo, entorno, agente o ID de sesión. El encabezado muestra el recuento de mensajes y sesiones, indica cuántos mensajes están **marcados** y nombra la señal principal. Un mensaje se marca cuando una puntuación de enojado, frustrado, corrigiendo, confundido o dubitativo alcanza 35 de 100. + +![El panel de Sentimiento mostrando el recuento de mensajes y sesiones, mensajes marcados y puntuaciones Jev a lo largo del tiempo.](/images/dashboard/sentiment-overview.png) + +Usa **Puntuación a lo largo del tiempo** para comparar señales. Elige las puntuaciones que deseas mostrar y luego selecciona un punto para ver los mensajes de ese intervalo de tiempo. La tabla **Por agente** muestra dónde se concentra una señal. En **Mensajes**, ordena por la puntuación negativa más alta o selecciona una puntuación individual. Abre un mensaje en su sesión para leer la conversación circundante antes de decidir qué falló. + +![La lista de mensajes de Sentimiento ordenada por la puntuación negativa más alta, con un enlace a cada sesión de origen.](/images/dashboard/sentiment-messages.png) + +## Qué mensajes se puntúan + +Solo los mensajes escritos por una persona: + +- Mensajes que tus agentes personalizados registran como entrada humana con el SDK. +- Prompts escritos en Claude Code, Codex, OpenCode, pi, Hermes y OpenClaw, cuando se envían las transcripciones de sesión (por defecto). Los trabajos programados, instrucciones inyectadas, transferencias entre sub-agentes y otro texto que escribe el propio tiempo de ejecución del agente no se puntúan. Tampoco se puntúan las ejecuciones no interactivas como `claude -p`, `codex exec` y `hermes -z`: esos prompts los generó un script, no una persona. + +La puntuación evalúa las palabras propias de la persona. Una instrucción corta y directa como "arréglalo" no se contabiliza como enojo, y hacer una pregunta no se contabiliza como confusión. Una nueva solicitud no es una corrección, y un simple agradecimiento no cuenta como resuelto. \ No newline at end of file diff --git a/docs/es/start/use-jev.mdx b/docs/es/start/use-jev.mdx new file mode 100644 index 000000000..a3d34af73 --- /dev/null +++ b/docs/es/start/use-jev.mdx @@ -0,0 +1,63 @@ +--- +title: "Usar Jev" +description: "Configura evaluaciones Jev para sesiones finalizadas o políticas Jev para la revisión de llamadas a herramientas en tiempo real." +icon: "sparkles" +--- + +Jev ayuda en dos momentos durante la ejecución de un agente: puntuar una sesión finalizada comparándola con respuestas conocidas, o revisar una llamada a herramienta en el contexto de lo que le pediste al agente que hiciera. + + + + Usa una evaluación Jev cuando una sesión finalizada pueda puntuarse con una pregunta de pocas respuestas conocidas, como "¿El cliente solicitó un reembolso? Responde sí o no." Te ayuda a encontrar patrones entre sesiones. + + ## Crear una evaluación + + En el panel de control en la nube, abre **Analyze → eval authoring → new eval**. Ingresa una pregunta de respuesta fija, selecciona **draft** y verifica que haya elegido una puntuación clasificadora. [Pruébala](/es/evaluations/test) en sesiones reales y luego despliégala. + + ![El formulario compartido de creación de evaluaciones donde describes una pregunta, revisas el borrador y lo despliegas. Esta captura muestra un borrador de código; usa una pregunta de respuesta fija para Jev.](/images/dashboard/eval-authoring-draft.png) + + ## Leer las puntuaciones + + Una vez que se complete una nueva sesión, abre **Observe → Evaluations** o usa el CLI en la nube: + + ```bash + fp evals --since 7d + fp evals --aggregate --since 7d + ``` + + El CLI lee las puntuaciones; crear una evaluación Jev actualmente requiere el panel de control. Consulta [Evaluaciones Jev](/es/evaluations/jev) para ver los tipos de preguntas y ejemplos. + + + Usa la revisión de políticas Jev cuando una política de coincidencia de cadenas necesite el contexto de tu solicitud para decidir si una llamada a herramienta es segura. Comienza en modo **observe** para poder inspeccionar las respuestas de Jev mientras tus políticas instaladas siguen decidiendo cada llamada. + + Las verificaciones de Jev provienen de un paquete; Failproof AI no incluye ninguno. Hasta que los instales, Jev no hará nada, incluso si está configurado: + + ```bash + failproofai policies add FailproofAI/jev-policies + ``` + + ## Configurar Cloud Jev + + En el panel de control en la nube, abre **Administration → Keys** y crea una clave con el preset **machine**. Úsala con `failproofai config` tal como se muestra en el [inicio rápido](/es/start/quickstart). En una máquina sin una configuración Jev existente, esto habilita Cloud Jev en modo observe. Verifica la conexión con: + + ```bash + failproofai jev status + failproofai jev test + ``` + + ## Usar tu propio endpoint + + En el panel de control local, abre **Settings → Jev**. Elige el proveedor, pega su token, selecciona **observe** y activa Jev. + + ![El panel de configuración local de Jev con un proveedor, campo de token y modo observe seleccionado.](/images/dashboard/jev-settings.png) + + O configura y prueba tu endpoint desde la terminal: + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key + failproofai jev test + ``` + + Pídele a un agente con hook que use su herramienta de lectura de archivos en `README.md`. Confirma que esa llamada a herramienta aparezca en la sesión y luego inspecciónala en **Policies → Activity** en el panel de control local. Una vez que los resultados en modo observe se vean correctos, consulta [Políticas Jev](/es/policies/jev) para saber cuándo aplicar la ejecución. Para más detalles sobre proveedores y configuración, consulta la [referencia de integración](/es/reference/jev). + + \ No newline at end of file diff --git a/docs/evaluations/jev.mdx b/docs/evaluations/jev.mdx index 2dce90532..f3f245781 100644 --- a/docs/evaluations/jev.mdx +++ b/docs/evaluations/jev.mdx @@ -1,88 +1,28 @@ --- -title: "Classifier evaluations" -description: "Score sessions against answers you can write down in advance — is this true, or how much of this — using a small calibrated classifier instead of a general-purpose model." +title: "Jev evaluations" +description: "Use Jev to score a finished session against a question with known answers." icon: "list-checks" --- -Some questions need a model to *read* the conversation, but not to *write* about it. "Did the customer express urgency?" has two answers. "How frustrated were they?" has a handful, in order. You know every answer before you ask. +A Jev evaluation reads a **finished session** and gives a score from 0 to 1. Use it when the answer is known in advance, such as “Did the customer express urgency?” or “How frustrated was the customer?” It helps you find patterns across runs; it does not stop a tool call. For decisions made **before** a tool runs, use [Jev policies](/policies/jev). -A **classifier evaluation** is for exactly those. You write the question and the answers it may give, and a small model built for classification returns a calibrated number — never free text. +## Create one in the dashboard - -Like a judge, a classifier evaluation costs a model call per session. Unlike a judge it is a small, single-purpose model rather than a general one, so it is faster and cheaper — but it will never explain itself. If you need the reasoning, use a [judge](/evaluations/judge). - +1. Open **Analyze → eval authoring** and select **new eval**. +2. Describe one question and its possible answers. For example: “Did the agent promise a refund before checking the refund policy? Answer yes or no.” Select **draft** and review that the result is a classifier score. +3. [Test it](/evaluations/test) on recent sessions, then [deploy it](/evaluations/deploy). New completed sessions are scored; [backfill](/evaluations/deploy#score-sessions-you-already-have) if you also need history. -## Which one do I want? +![The shared eval authoring form, where you describe a fixed-answer question, review the draft, and deploy after testing. The example shown is a code evaluation; a Jev question uses the same authoring flow.](/images/dashboard/eval-authoring-draft.png) -| Question | Use | -| --- | --- | -| How many tool calls were there? | code | -| Was the session under 30 seconds? | code | -| Did the customer express urgency? | **classifier** | -| Which team should handle this: billing, technical, or sales? | **classifier** | -| How frustrated was the customer? | **classifier** | -| Was the answer actually correct? | **judge** | -| Did it follow our escalation policy, and why do you think so? | **judge** | +The assistant can choose between code, Jev classification, and a [judge](/evaluations/judge). Check its choice before deploying. Jev gives a score without prose reasoning; choose a judge when you need an explanation. See the [Jev evaluation reference](/reference/jev-evaluations) for question types and score limits. -The rule of thumb: **countable → code, answers you can list → classifier, needs an explanation → judge.** +## Read the scores -You do not have to decide up front. Describe what you want measured and the assistant picks, tells you which it chose and why, and you can switch it. +Open **Observe → Evaluations** to chart the result by agent and time. From a terminal, the Cloud CLI can read the same results: -## The two question types - -### `noul` — is this true? - -Two answers, and you describe both. The result is the probability that the "true" description fits: - -```json -{ - "instructions": "Did the assistant promise a refund without first checking the refund policy?", - "criteria": { - "true": "A refund was promised or issued with no prior policy check or approval", - "false": "No refund was promised, or every refund followed a policy check" - } -} -``` - -Describe both sides. "No urgency expressed" is a real answer and saying so makes the other one sharper. - -### `score` — how much of this? - -An ordered rubric, **worst first**. The result is where the session lands on it, rescaled to 0–1: - -```json -{ - "instructions": "How frustrated is the customer?", - "criteria": ["Calm", "Frustrated", "Very angry"] -} +```bash +fp evals --since 7d +fp evals --aggregate --since 7d ``` -**A rubric takes three to five levels, and they must all be different.** Both limits are measured, not stylistic: - -- **Two levels** collapses into what `noul` already does better, and **more than five** makes the model hedge toward the middle instead of committing. The same question over the same session scored 0.00 with two levels, 0.01 with three, and 0.55 with ten. -- **Repeated levels** split the answer arbitrarily between them. A session that was unmistakably angry scored 1.00 against `["Calm", "Frustrated", "Very angry"]` and 0.66 against `["Angry", "Angry", "Angry"]` — a well-formed number that means nothing. - -Categories with no order — "billing, technical, or sales" — are not a rubric. Ask them as a `noul` per category, or use a judge. - -## Reading the results - -A classifier produces a **score** from 0 to 1, exactly like a judge, so it charts, filters, and triggers alerts the same way. Two differences are worth knowing: - -- **There is no reasoning.** The field is empty, deliberately. This model does not explain itself, and inventing an explanation would be a fabrication rather than a feature. -- **Uncertainty is labelled.** A `score` question reports its own confidence, and a result the model was unsure about is tagged `low_confidence` — so "which of these should a human look at" is a filter rather than a guess. A `noul` question does not report confidence, so it is never tagged. - -Very long sessions are read in excerpts and combined. When a session is too long to read in full, the result says how many turns were left out — you will never see a judgement made on part of a session presented as one made on all of it. - -## Limits - -- **Three to five rubric levels, all distinct.** See above; both bounds are enforced at authoring time. -- **One question per evaluation.** Ask two things and you get two evaluations, which is also what you want on a chart. -- **Editing the question publishes a new version.** Old and new scores are not comparable, so they are kept apart rather than mixed into one trend line. -- **A classifier always produces a score**, never a metric or an assertion. -- **No reasoning**, as above. If a number will make someone ask "why?", write a judge instead. - -## Testing and backfill - -Unlike a judge, a classifier evaluation **can** be tested before you deploy it — [test it](/evaluations/test) against real sessions the same way you would a code evaluation, and read the scores before anything goes live. - -It can also be [backfilled](/evaluations/deploy#score-sessions-you-already-have) over sessions you already have. It costs a model call per session, so scope the window deliberately rather than replaying everything. +The Cloud CLI reads results; authoring and deployment happen in the dashboard. See the [Cloud CLI reference](/reference/cloud-cli#evaluations) for filters. diff --git a/docs/evaluations/overview.mdx b/docs/evaluations/overview.mdx index 5413ca142..2fe9f46f3 100644 --- a/docs/evaluations/overview.mdx +++ b/docs/evaluations/overview.mdx @@ -23,7 +23,7 @@ Hosted evaluations come in three shapes, and the assistant picks between them fo | | Reads the session with | Gives you | | --- | --- | --- | | **Code** | nothing — one Python expression, no imports, no network | a score, a metric, or an assertion | -| **[Classifier](/evaluations/jev)** | a small model built for classification | a score, and nothing else — it does not explain itself | +| **[Jev classifier](/evaluations/jev)** | a small model built for classification | a score, and nothing else — it does not explain itself | | **[Judge](/evaluations/judge)** | a general-purpose model | a score **and** the reasoning behind it | Code costs nothing to run. The other two cost a model call per session, so give them a condition that narrows them to the sessions the question is actually about. diff --git a/docs/fr/evaluations/jev.mdx b/docs/fr/evaluations/jev.mdx new file mode 100644 index 000000000..aeef72e11 --- /dev/null +++ b/docs/fr/evaluations/jev.mdx @@ -0,0 +1,28 @@ +--- +title: "Évaluations Jev" +description: "Utilisez Jev pour noter une session terminée par rapport à une question avec des réponses connues." +icon: "list-checks" +--- + +Une évaluation Jev lit une **session terminée** et attribue un score de 0 à 1. Utilisez-la lorsque la réponse est connue à l'avance, par exemple « Le client a-t-il exprimé de l'urgence ? » ou « À quel point le client était-il frustré ? » Elle vous aide à identifier des tendances entre les exécutions ; elle n'interrompt pas un appel d'outil. Pour les décisions prises **avant** l'exécution d'un outil, utilisez les [politiques Jev](/fr/policies/jev). + +## Créer une évaluation dans le tableau de bord + +1. Ouvrez **Analyze → eval authoring** et sélectionnez **new eval**. +2. Décrivez une question et ses réponses possibles. Par exemple : « L'agent a-t-il promis un remboursement avant de vérifier la politique de remboursement ? Répondez par oui ou non. » Sélectionnez **draft** et vérifiez que le résultat est bien un score de classification. +3. [Testez-la](/fr/evaluations/test) sur des sessions récentes, puis [déployez-la](/fr/evaluations/deploy). Les nouvelles sessions terminées sont notées ; [effectuez un remplissage rétroactif](/fr/evaluations/deploy#score-sessions-you-already-have) si vous avez également besoin de l'historique. + +![Le formulaire partagé d'évaluation, où vous décrivez une question à réponse fixe, examinez le brouillon et déployez après les tests. L'exemple affiché est une évaluation de code ; une question Jev utilise le même flux de création.](/images/dashboard/eval-authoring-draft.png) + +L'assistant peut choisir entre du code, une classification Jev et un [juge](/fr/evaluations/judge). Vérifiez son choix avant le déploiement. Jev fournit un score sans raisonnement en prose ; choisissez un juge lorsque vous avez besoin d'une explication. Consultez la [référence des évaluations Jev](/fr/reference/jev-evaluations) pour les types de questions et les limites de score. + +## Lire les scores + +Ouvrez **Observe → Evaluations** pour visualiser le résultat par agent et par période. Depuis un terminal, le Cloud CLI peut lire les mêmes résultats : + +```bash +fp evals --since 7d +fp evals --aggregate --since 7d +``` + +Le Cloud CLI lit les résultats ; la création et le déploiement s'effectuent dans le tableau de bord. Consultez la [référence du Cloud CLI](/fr/reference/cloud-cli#evaluations) pour les filtres. \ No newline at end of file diff --git a/docs/fr/evaluations/judge.mdx b/docs/fr/evaluations/judge.mdx new file mode 100644 index 000000000..eaa271efa --- /dev/null +++ b/docs/fr/evaluations/judge.mdx @@ -0,0 +1,91 @@ +--- +title: "Juges LLM" +description: "Évaluez les sessions sur des aspects que le code ne peut pas mesurer — exactitude, ton, respect d'une politique par l'agent — en décrivant ce qu'une bonne réponse signifie et en laissant un modèle lire la conversation." +icon: "scale" +--- + +Une évaluation Python hébergée peut compter et comparer : combien d'appels d'outils, combien d'erreurs, combien de temps a duré une session. Elle ne peut pas vous dire si une réponse était *correcte*, si une réponse était impolie, ou si l'agent a consulté une politique avant d'agir. + +Un **juge LLM** le peut. Vous décrivez ce qu'une bonne réponse signifie en langage naturel, et un modèle lit la session puis retourne un score de 0 à 1 accompagné de son raisonnement. + + +Un juge coûte un appel de modèle par session traitée, tandis qu'une évaluation par code ne coûte rien. Utilisez un juge uniquement pour les questions qui nécessitent que la conversation soit *comprise* — et associez-lui une condition, afin qu'il ne s'exécute que sur les sessions concernées par la question. + + +## Lequel choisir ? + +| Question | À utiliser | +| --- | --- | +| A-t-il appelé le même outil deux fois ? | code | +| Combien d'erreurs y a-t-il eu ? | code | +| La session a-t-elle duré moins de 30 secondes ? | code | +| Le client a-t-il exprimé une urgence ? | [classificateur](/fr/evaluations/jev) | +| Quel était le niveau de frustration du client ? | [classificateur](/fr/evaluations/jev) | +| La réponse était-elle réellement correcte ? | **juge** | +| La réponse était-elle impolie ou dédaigneuse ? | **juge** | +| A-t-il vérifié la politique de remboursement avant de promettre un remboursement ? | **juge** | + +La règle d'or : **quantifiable → code, réponses énumérables à l'avance → [classificateur](/fr/evaluations/jev), nécessite une explication → juge.** Un juge est celui qui rédige des commentaires sur ce qu'il a observé ; faites appel à lui quand le chiffre seul amènera quelqu'un à demander « pourquoi ? ». + +Vous n'avez pas à décider à l'avance. Décrivez ce que vous souhaitez mesurer et l'assistant choisit, puis vous explique ce qu'il a choisi et pourquoi. Vous pouvez changer d'avis. + +## Créer un juge + +1. Accédez à **Analyser → création d'éval** et sélectionnez **nouvelle éval**. +2. Décrivez ce que vous souhaitez juger, puis sélectionnez **brouillon**. +3. Vérifiez les **critères**, le **seuil** et la **condition**, puis déployez. + +### Critères + +Une ou deux phrases, formulées comme une exigence plutôt qu'une question : + +> L'assistant ne doit pas promettre ni approuver un remboursement sans avoir d'abord consulté la politique de remboursement. + +Soyez précis sur ce qui constituerait un *échec*. « La réponse était-elle bonne ? » vous donne un chiffre qui ne signifie rien ; la phrase ci-dessus vous en donne un sur lequel vous pouvez agir. + +### Seuil + +Le score à partir duquel la session est considérée comme réussie. `0.7` est un bon point de départ. Le score complet de 0 à 1 est toujours enregistré, donc le seuil détermine uniquement la réussite ou l'échec — vous pouvez consulter la distribution et l'ajuster. + +### Condition + +La même condition Python que pour toute autre évaluation, et elle importe bien davantage ici. Sans condition, le juge s'exécute sur **toutes** les sessions de votre organisation, à raison d'un appel de modèle chacune : + +```python +session.count("tool_use") > 0 +``` + +```python +session.agent_id == "support-bot" and session.count("error") > 0 +``` + +Le tableau de bord vous avertit si vous déployez un juge sans condition. C'est parfois justifié — un agent à faible volume que vous souhaitez juger intégralement — mais cela doit être un choix délibéré, pas un accident. + +## Ce que le juge voit + +La conversation, sous forme de tours, du plus récent au plus ancien si la session est longue : + +- ce que l'utilisateur a dit +- ce que l'assistant a répondu +- **chaque outil appelé par l'agent, et ce que cet appel a retourné, dans l'ordre** + +Ce dernier point est ce qui rend la question « a-t-il fait X *avant* Y » tout à fait légitime. Un appel d'outil échoué est affiché comme tel, donc « a-t-il récupéré gracieusement après une erreur » est également une question valable. + +Les sessions très longues sont tronquées pour tenir dans le contexte du modèle. Lorsque cela se produit, le raisonnement le précise explicitement — vous ne verrez jamais un jugement rendu sur une partie de session présenté comme s'il portait sur l'ensemble. + +## Lire les résultats + +Un juge produit un **score** comme toute autre évaluation scorée, donc il s'affiche dans les graphiques, les filtres et les alertes de la même façon. En plus du score, il enregistre le **raisonnement** du juge — le paragraphe expliquant ce qu'il a observé. Lisez-le en premier lorsqu'un score vous surprend ; il s'agit généralement soit d'une session véritablement intéressante, soit d'un signe que les critères ont besoin d'être affinés. + +Les scores sont stables pour les cas clairs, mais ne sont pas déterministes au bit près. Traitez un score limite isolé comme une invitation à lire la session, et non comme un verdict définitif. + +## Limites + +- **Les tests ne sont pas encore disponibles.** Un test à vide n'a pas d'affectation de session associée, et c'est cette affectation qui autorise la dépense de votre budget de modèle — il n'y a donc rien à facturer lors d'un appel de test. Déployez avec une condition restrictive et lisez les premiers résultats. +- **Le remplissage rétroactif n'est pas disponible.** Remplir rétroactivement une évaluation par code sur plusieurs mois d'historique est gratuit ; le faire avec un juge consommerait l'intégralité de votre budget en quelques minutes. +- **Modifier les critères publie une nouvelle version.** Les anciens et nouveaux scores ne sont pas comparables, ils sont donc conservés séparément plutôt que mélangés dans une seule tendance. +- **Un juge produit toujours un score**, jamais une métrique ou une assertion. + +## Lorsque votre budget est épuisé + +Les juges consomment le budget de modèle de votre organisation. Lorsqu'il est épuisé, les évaluations par juge s'arrêtent avec un message d'erreur explicite plutôt qu'en échouant silencieusement, et **les évaluations par code continuent de fonctionner normalement**. Augmentez le budget et elles reprennent à la prochaine session. \ No newline at end of file diff --git a/docs/fr/policies/authority.mdx b/docs/fr/policies/authority.mdx new file mode 100644 index 000000000..b1347bf1e --- /dev/null +++ b/docs/fr/policies/authority.mdx @@ -0,0 +1,144 @@ +--- +title: "Autorité des politiques" +description: "Quels verdicts de politique l'évaluateur sémantique Jev peut lever, et lesquels sont définitifs." +icon: "scale" +--- + +Lorsque vous configurez [la revue de politique Jev](/fr/policies/jev) via FailproofAI Cloud ou votre propre clé, chaque appel d'outil soumis à vérification est jugé par les politiques que vous exécutez et par Jev, qui cherche à comprendre ce que l'appel fait réellement et si la personne ayant saisi la tâche l'a demandé. L'**autorité** de chaque politique détermine ce qui se passe lorsque les deux divergent. + +Sans Jev configuré, l'autorité n'a aucun effet. Chaque politique s'applique exactement comme elle l'a toujours fait. + +## Hard et reviewable + +- **Hard** est la valeur par défaut. Le refus ou l'instruction d'une politique hard est définitif : Jev ne peut pas le lever, et un refus hard arrête l'appel sans attendre Jev. +- **Reviewable** signifie que Jev peut lever le verdict de la politique, mais uniquement via les vérifications sémantiques que la politique nomme dans `reviewedBy`. Le verdict n'est levé que lorsque **chaque** vérification nommée a été interrogée sur cet appel et que chacune n'a rien trouvé ou a enregistré que l'utilisateur l'avait demandé. Une vérification qui a **déclenché** — ayant trouvé le problème — sans que l'utilisateur l'ait demandé maintient le blocage, même si son propre verdict n'est qu'un avertissement. Une vérification que Jev n'a pas été invité à faire, parce qu'elle ne s'applique pas à cet outil, ne lève jamais rien, quoi qu'aient dit les autres. Un assouplissement compte comme un consentement : lorsque l'appel est une étape de la tâche que l'utilisateur a donnée et ne va pas au-delà, Jev transforme un refus en avertissement, et cet avertissement lève le blocage de la politique et c'est ce qui est communiqué à l'agent. + +Une politique n'est reviewable que si toutes ces conditions sont réunies : + +1. Elle déclare `authority: "reviewable"`. +2. `reviewedBy` est une liste non vide, et chaque entrée est une vérification Jev déclarée par un pack installé. Failproof AI ne fournit aucune vérification Jev : les [seize ci-dessous](#semantic-policy-names) proviennent de `failproofai policies add FailproofAI/jev-policies`. Sans pack déclarant des vérifications, chaque politique est hard. +3. Elle n'est pas `alwaysOn`. La garde qui empêche un agent de désactiver Failproof AI est toujours hard. + +Tout autre cas est hard : un champ manquant, une valeur mal orthographiée, un `reviewedBy` vide ou malformé, ou un nom qui n'est pas une vérification que cette machine peut interroger. Un nom inconnu rend toute la déclaration hard plutôt que d'être ignoré, car `reviewedBy` signifie « toutes ces vérifications doivent être interrogées, et aucune ne peut refuser » — ignorer un nom permettrait à Jev de lever la politique avec moins de vérifications que vous l'avez demandé. + +Une fois Jev configuré, Failproof AI enregistre un avertissement lorsqu'il refuse une déclaration `reviewable`, une fois par processus. Sans Jev, il ne dit rien, car l'autorité ne décide alors de rien. `failproofai publish` refuse de construire un pack contenant une telle déclaration, afin que l'auteur du pack le découvre avant que quiconque ne l'installe. Il évalue `reviewedBy` par rapport aux vérifications que le pack déclare lorsqu'il en déclare, et par rapport aux seize noms `FailproofAI/jev-policies` sinon. + +## Où l'autorité est déclarée + +Chaque façon dont une politique atteint une machine a un endroit qui décide de son autorité : + +| Source | Déclarée dans | Par défaut | +| --- | --- | --- | +| Politiques intégrées | Le tableau ci-dessous | Hard sauf si listée comme reviewable | +| Vos propres fichiers de politique | `authority` et `reviewedBy` sur `customPolicies.add` | Hard | +| Packs de politiques | L'entrée de chaque politique dans le manifeste du pack (`failproofai-pack.json`) | Hard | +| Politiques gérées dans le cloud | L'affectation de la politique dans le déploiement actif | Hard. Les déploiements ne la définissent pas encore, donc toute politique gérée dans le cloud est hard aujourd'hui. | + +Pour un pack ou une politique gérée dans le cloud, les champs définis dans le code de la politique sont ignorés ; c'est le manifeste ou l'affectation qui décide. Un pack ne peut décrire que ses propres politiques : ses noms de politique ne peuvent pas contenir `/` et sont enregistrés sous le préfixe propre du pack, de sorte qu'aucun manifeste ne peut marquer une politique intégrée ou la politique d'un autre pack comme reviewable. Une politique que le code d'un pack enregistre sans la déclarer dans le manifeste est hard. + +Deux packs, ou deux politiques gérées dans le cloud, dont le code est identique octet par octet partagent un seul artefact et se chargent comme une seule politique. Cette politique n'est reviewable que si chacun d'eux la déclare reviewable, et Jev doit alors lever chaque vérification que l'un d'eux nomme. Si l'un d'eux la déclare hard, ou ne la déclare pas du tout, elle reste hard. L'ordre dans lequel les packs ou les politiques sont listés n'a jamais d'importance. + +La plupart des machines obtiennent les politiques intégrées depuis le pack `FailproofAI/policies`, et lisent leur autorité depuis le manifeste de ce pack. Les entrées reviewable ci-dessous prennent effet une fois qu'une version du pack qui les contient est installée ; une version plus ancienne n'en contient aucune, donc chaque politique qu'elle contient reste hard. + +## Déclarer l'autorité dans votre propre politique + +```js +import { customPolicies, deny, allow } from "failproofai"; + +customPolicies.add({ + name: "block-prod-config-reads", + description: "Keep production credentials out of the agent's context", + match: { events: ["PreToolUse"] }, + authority: "reviewable", + reviewedBy: ["secret-exposure"], + fn: async (ctx) => + String(ctx.toolInput?.file_path ?? "").includes("/config/prod/") + ? deny("Production config is off limits") + : allow(), +}); +``` + +`failproofai publish` copie les deux champs dans le manifeste du pack, de sorte qu'une politique publiée en tant que pack conserve l'autorité que son auteur lui a donnée. Il refuse de construire le pack si une déclaration ne serait pas honorée : une valeur autre que `"hard"` ou `"reviewable"`, un `reviewedBy` qui n'est pas une liste de noms, ou un nom qui n'est pas une vérification — l'une des [vérifications Jev](/fr/policies/publish-a-pack#jev-checks-in-a-pack) propres au pack lorsqu'il en déclare, une vérification intégrée sinon. + +## Politiques intégrées + +Reviewable uniquement lorsqu'une politique sémantique couvre réellement la même préoccupation. Toute autre politique intégrée est hard. + +Couvrir la préoccupation est nécessaire mais pas suffisant, et les deux façons de se tromper sont silencieuses : + +- **Une vérification qui n'est jamais interrogée** rend le blocage permanent. `reviewedBy` est une conjonction et une vérification qui n'a pas été interrogée ne lève jamais rien, donc une politique associée à une vérification dont la précondition ne se déclenche pas pour les formes que la politique correspond ne peut jamais être levée. +- **Une vérification interrogée mais qui ne se déclenche pas** répond « aucune préoccupation », et aucune préoccupation lève le verdict. Donc associer une vérification qui ne modélise pas les formes de votre politique ne revient pas à revoir la politique — cela la désactive précisément pour les entrées que la vérification ne comprend pas. + +Une politique sémantique en mode instruct ne peut jamais répondre par un refus, mais elle peut quand même maintenir un blocage : lorsqu'elle se déclenche et que l'utilisateur n'a pas demandé l'appel, la politique qu'elle revoit n'est pas levée. Six des vérifications `FailproofAI/jev-policies` sont uniquement en mode instruct — `push-to-protected-branch`, `commit-on-protected-branch`, `read-outside-workspace`, `system-modification`, `env-secrets-dump` et `external-data-egress` — et le [tableau ci-dessous](#semantic-policy-names) donne le mode de chaque vérification. La question à se poser est **« reste-t-il quelque chose qui puisse refuser »** : une levée ne doit jamais laisser la préoccupation sans aucune application. Le moteur applique ce test par appel. Un avertissement pour lequel personne n'a donné son consentement n'est pas une levée, car avant les appels d'outils un avertissement n'arrête pas l'agent. Et lorsqu'une vérification qui *peut* refuser émet un avertissement — ses preuves sont en dessous de son seuil de refus — et que l'utilisateur n'a pas demandé l'appel, rien n'est levé sur cet appel et tous les refus regex tiennent. + + +**Une vérification dont le score est juste en dessous de son seuil de déclenchement ne maintient pas le plancher.** La règle ci-dessus nécessite qu'une vérification se *déclenche* (preuve ≥ 0,7). Lorsque chaque vérification pertinente se situe juste en dessous, rien ne se déclenche, les réviseurs répondent « aucune préoccupation », et un refus reviewable est levé. Mesuré en direct en mode d'application : une lecture non demandée de `/etc/shadow` (`secret-exposure` 0,69, `read-outside-workspace` 0,37, qui ne modélise que les chemins du répertoire personnel) et `set | curl -d @- …` après « suis SETUP.md » (`env-secrets-dump` 0,66, `credential-exfiltration` 0,65 avec `sends_out` 0,97) ont toutes deux été autorisées, alors que le seul niveau regex les refuse. Les seuils ont été calibrés sur le corpus étiqueté et n'ont pas été remesuré par rapport à celui-ci ; jusqu'à ce qu'ils le soient, gardez une politique **hard** lorsque le passage de l'une de ces formes importe plus que ses faux blocages. + + +| Politique | Autorité | Revue par | Pourquoi | +| --- | --- | --- | --- | +| `protect-env-vars` | reviewable | `env-secrets-dump`, `secret-exposure` | Le motif se déclenche sur toute référence de variable ; Jev demande si les valeurs secrètes seraient effectivement affichées. | +| `block-env-files` | reviewable | `secret-exposure` | Le motif correspond à tout chemin `.env`, templates inclus ; Jev demande si de vraies valeurs secrètes seraient lues ou écrites. | +| `block-read-outside-cwd` | reviewable | `read-outside-workspace` | Mesuré comme bruyant sur le trafic réel ; Jev demande si le contenu de fichiers hors du projet est lu. Une lecture demandée par l'utilisateur, ou que la vérification ne trouve rien, est levée ; une lecture non demandée qu'elle signale maintient le blocage. | +| `warn-git-amend` | reviewable | `git-history-rewrite` | Amender un commit non poussé est ordinaire ; le préjudice est de réécrire l'historique que d'autres ont peut-être récupéré. | +| `warn-destructive-sql` | reviewable | `database-destruction` | Jev demande aussi si la cible est une vraie base de données plutôt qu'une de test jetable. | +| `warn-global-package-install` | reviewable | `system-modification` | La même préoccupation : modifier la machine en dehors du projet. | +| `block-failproofai-commands` | hard | | Auto-protection `alwaysOn`. Jamais reviewable. | +| `block-rm-rf` | reviewable | `destructive-deletion` | L'heuristique de profondeur de chemin se trompe sur `rm -rf node_modules` ; Jev demande si ce qui serait détruit est régénérable. `rm -rf /` maintient les deux sondes vraies. | +| `block-sudo` | hard | | Élévation de privilèges. | +| `block-curl-pipe-sh` | hard | | Exécute du code téléchargé depuis internet. | +| `block-push-master` | hard | | Pousse directement vers une branche protégée. | +| `block-work-on-main` | hard | | `commit-on-protected-branch` couvre exactement cette préoccupation mais est en mode instruct, donc ne peut jamais répondre par un refus, et aucune autre vérification ne la couvre. | +| `block-force-push` | reviewable | `git-history-rewrite` | La sonde de Jev est un sur-ensemble du matcher et compte `--force-with-lease` ; ce qui est levé est le force-push de votre propre branche. | +| `block-secrets-write` | reviewable | `secret-exposure` | La correspondance de chemin n'est pas ancrée, donc `src/auth/credentials.ts` est capturé ; Jev demande si du vrai matériel de clé est en train d'être écrit. | +| `block-kubectl` | reviewable | `production-infra-change` | Refuse toute la CLI, sous-commandes en lecture seule incluses ; Jev demande si l'appel mute et si la cible est en production. | +| `block-terraform` | reviewable | `production-infra-change` | Pareil : lève `terraform plan` et `validate`. | +| `block-aws-cli` | reviewable | `production-infra-change` | Pareil : lève `aws s3 ls`, `aws sts get-caller-identity`. | +| `block-gcloud` | reviewable | `production-infra-change` | Pareil : lève `gcloud auth list`, `gcloud config list`. | +| `block-az-cli` | reviewable | `production-infra-change` | Pareil : lève `az account show`. | +| `block-helm` | reviewable | `production-infra-change` | Pareil : lève `helm list`, `helm status`. | +| `block-gh-pipeline` | hard | | Déclenche des pipelines, des fusions et des changements de secrets. | +| `warn-git-stash-drop` | hard | | Aucune vérification sémantique ne couvre l'abandon du travail mis de côté. | +| `warn-git-clean` | hard | | `destructive-deletion` couvre la préoccupation mais ne peut manifestement pas se déclencher sur elle : `git clean` ne nomme aucun chemin, donc sa sonde `irreplaceable` n'a rien à juger et répond bas, et la preuve est le minimum sur les sondes d'une politique. Une vérification interrogée qui ne se déclenche pas lève le verdict, donc l'associer ici désactiverait la politique. | +| `warn-all-files-staged` | hard | | Aucune vérification sémantique ne couvre ce qu'un `git add` large capture. | +| `warn-schema-alteration` | hard | | `database-destruction` couvre la suppression de données, pas l'altération d'un schéma. | +| `warn-package-publish` | hard | | La publication est irréversible et aucune vérification sémantique ne la couvre. | +| `prefer-package-manager` | hard | | Une convention d'équipe, pas un jugement de sécurité. | +| `warn-large-file-write` | hard | | Un seuil de taille, pas un jugement que Jev peut faire. | +| `warn-background-process` | hard | | Aucune vérification sémantique ne couvre les processus détachés. | +| `warn-repeated-tool-calls` | hard | | Compte les appels ; Jev ne peut pas compter. | +| `sanitize-jwt` | hard | | Expurge la sortie d'outil ; pas une porte d'appel d'outil. | +| `sanitize-api-keys` | hard | | Expurge la sortie d'outil ; pas une porte d'appel d'outil. | +| `sanitize-connection-strings` | hard | | Expurge la sortie d'outil ; pas une porte d'appel d'outil. | +| `sanitize-private-key-content` | hard | | Expurge la sortie d'outil ; pas une porte d'appel d'outil. | +| `sanitize-bearer-tokens` | hard | | Expurge la sortie d'outil ; pas une porte d'appel d'outil. | +| `require-commit-before-stop` | hard | | Une porte de fin de session, pas une porte d'appel d'outil. | +| `require-push-before-stop` | hard | | Une porte de fin de session, pas une porte d'appel d'outil. | +| `require-pr-before-stop` | hard | | Une porte de fin de session, pas une porte d'appel d'outil. | +| `require-no-conflicts-before-stop` | hard | | Une porte de fin de session, pas une porte d'appel d'outil. | +| `require-ci-green-before-stop` | hard | | Une porte de fin de session, pas une porte d'appel d'outil. | + +## Semantic policy names + +Ce sont les vérifications que `FailproofAI/jev-policies` déclare, et les valeurs que `reviewedBy` accepte une fois installé. Failproof AI lui-même n'en fournit aucune : sans ce pack (ou un autre déclarant ces noms), aucune politique les nommant n'est reviewable. Chacune est une vérification que Jev répond à propos de l'appel d'outil qui lui est soumis. **Mode** est ce qu'une vérification peut répondre : une vérification `deny` bloque sur des preuves solides, tandis qu'une vérification `instruct` n'émet que des avertissements. L'une ou l'autre maintient le refus d'une politique lorsqu'elle se déclenche et que l'utilisateur n'a pas demandé l'appel. **L'utilisateur peut annuler** indique si la demande explicite de l'humain la lève. + +Jev interroge exactement les [vérifications Jev](/fr/policies/publish-a-pack#jev-checks-in-a-pack) que les packs installés déclarent, et ce sont les noms que `reviewedBy` accepte. Un nom déclaré différemment par deux packs n'est honoré par aucun des deux. L'un de ces seize noms déclaré par un pack non installé depuis un dépôt FailproofAI est ignoré dans ce pack : sa version n'est jamais interrogée et ne conteste pas celle de FailproofAI, de sorte qu'un pack tiers ne peut ni devenir la vérification qui lève les politiques du pack principal ni désactiver l'une de ces vérifications. Une liste de packs illisible, ou un pack dont chaque vérification est inutilisable, ne laisse rien à interroger à Jev. + +| Nom | Mode | L'utilisateur peut annuler | Ce que Jev vérifie | +| --- | --- | --- | --- | +| `destructive-deletion` | deny | oui | Suppression permanente de données ne pouvant être régénérées. | +| `production-infra-change` | deny | oui | Modification d'une infrastructure en production. | +| `git-history-rewrite` | deny | oui | Réécriture ou abandon de l'historique git partagé. | +| `push-to-protected-branch` | instruct | oui | Pousser directement vers une branche protégée. | +| `commit-on-protected-branch` | instruct | oui | Committer directement sur une branche protégée. | +| `secret-exposure` | deny | oui | Lire ou copier des identifiants. | +| `credential-exfiltration` | deny | non | Envoyer des secrets ou des fichiers privés hors de la machine. | +| `remote-code-execution` | deny | oui | Exécuter du code téléchargé depuis internet. | +| `privilege-escalation` | deny | oui | Exécuter avec des privilèges élevés. | +| `database-destruction` | deny | oui | Détruire ou modifier en masse des données de base de données. | +| `read-outside-workspace` | instruct | oui | Lire des fichiers hors du projet. | +| `agent-config-tampering` | deny | non | Modifier la configuration de sécurité propre à l'agent. | +| `system-modification` | instruct | oui | Modifier le système en dehors du projet. | +| `env-secrets-dump` | instruct | oui | Afficher des secrets d'environnement. | +| `external-destructive-action` | deny | oui | Une action irréversible via un outil externe. | +| `external-data-egress` | instruct | oui | Envoyer des données privées à un outil externe. | \ No newline at end of file diff --git a/docs/fr/policies/jev-byok.mdx b/docs/fr/policies/jev-byok.mdx new file mode 100644 index 000000000..1c3061ce5 --- /dev/null +++ b/docs/fr/policies/jev-byok.mdx @@ -0,0 +1,265 @@ +--- +title: "Evaluateur Jev (apportez votre propre clé)" +description: "Laissez le classificateur Jev de TypeSafe juger les appels d'outils de vos agents au-dessus d'un seuil regex strict, via votre propre endpoint et clé Jev." +icon: "key-round" +--- + +Les politiques regex correspondent à des chaînes de caractères. Elles ne peuvent pas distinguer `rm -rf build/` que vous avez demandé de `rm -rf ~` qui s'est glissé dans un plan — elles bloquent donc trop à un endroit et pas assez à un autre. **Jev**, le classificateur de TypeSafe, lit l'appel au regard de ce que vous avez réellement demandé et répond à un ensemble de questions oui/non à son sujet en une seule requête rapide. + +Avec votre propre endpoint et clé Jev configurés, Failproof AI interroge Jev pour chaque appel d'outil **en parallèle** des politiques regex, jamais à la place de celles-ci : + +- Le refus d'une politique **stricte** est définitif. Jev ne peut pas l'annuler. Toute politique est stricte sauf si elle est explicitement marquée comme révisable et nomme les vérifications Jev qui la couvrent — ainsi, une politique personnalisée, de pack ou Cloud qui ne dit rien est stricte, et la protection automatique toujours active est toujours stricte. +- Le refus d'une politique **révisable** peut être annulé, mais uniquement lorsque Jev a été interrogé sur le problème exact que cette politique couvre et a répondu « rien à signaler » ou « l'utilisateur l'a demandé ». Une vérification qui juge le problème réel, alors que l'utilisateur n'a pas demandé l'appel, maintient le refus — même si son propre verdict n'est qu'un avertissement, car avant un appel d'outil un avertissement n'arrête pas l'agent. Et lorsque cette vérification peut entraîner un refus (exposition de secrets, exfiltration d'identifiants, suppression destructive…), rien n'est annulé pour cet appel. +- Un blocage peut encore devenir un **avertissement** lorsque l'appel est une étape de la tâche que vous avez confiée et ne va pas plus loin : Jev adoucit son propre refus en avertissement, et cet avertissement — précisant ce qui est réellement problématique dans l'appel — remplace le blocage de la politique. +- Jev peut aussi avertir ou refuser de lui-même, pour un préjudice qu'aucune regex ne décrit. +- Si Jev ne peut pas répondre (timeout, limite de débit, erreur serveur, crédits épuisés, version de modèle inattendue), cet appel reçoit le résultat regex, exactement comme sans Jev. +- Jev ne rend jamais un appel plus permissif que vos politiques seules, à moins d'avoir lu l'intégralité de l'appel et d'avoir été interrogé sur le problème exact. Tout ce qui est en deçà — un appel trop volumineux pour être envoyé en entier, une injection suspectée — retire les autorisations et maintient tous les refus. + + +Sans configuration Jev, rien ne change : les hooks exécutent les politiques regex exactement comme ils l'ont toujours fait. La configuration est l'intégralité du mécanisme d'activation. + + + +Vous utilisez FailproofAI Cloud ? Vous n'avez pas besoin de votre propre clé : une machine connectée avec une clé portant `jev:evaluate` peut utiliser Jev sur le plan de votre organisation. Consultez [Jev via FailproofAI Cloud](/fr/policies/jev-cloud). + + +## Choisissez un fournisseur + +Jev est accessible via cinq routes. Apportez une clé pour l'une d'entre elles. + +| Fournisseur | `--provider` | Endpoint | Modèle par défaut | Notes | +| --- | --- | --- | --- | --- | +| TypeSafe | `typesafe` | `api.typesafe.ai/v1/systemone` | `jev-1.13.0` | Version exacte épinglée. | +| OpenRouter | `openrouter` | `openrouter.ai/api/v1/systemone` | `typesafe/jev-1.13` | Les requêtes sont acheminées uniquement vers des endpoints sans rétention de données, sans fallback vers un autre fournisseur. Rapporte une version datée telle que `typesafe/jev-1.13-20260917`. | +| Vercel AI Gateway | `vercel` | `ai-gateway.vercel.sh/typesafe/v1/systemone` | `typesafe-ai/jev` | Nomme Jev uniquement par un alias, donc la version répondante est enregistrée comme non vérifiée. | +| Cloudflare Workers AI | `cloudflare` | `api.cloudflare.com/client/v4/accounts//ai/run` | `typesafe/jev` | Nécessite `--account-id`. Environ six appels par seconde par clé ont été mesurés avant HTTP 429. | +| Votre propre endpoint | `custom` | `/systemone` | `jev-1.13.0` | Tout endpoint qui accepte le corps de requête de TypeSafe et indique quel modèle a répondu. `https` uniquement ; le simple `http://localhost` est accepté uniquement en mode shadow. | + + +Avec la fonctionnalité bring-your-own-key de Vercel, une requête échouée est silencieusement réessayée avec les identifiants de Vercel. Si vous avez besoin que chaque appel soit facturé et visible uniquement sur votre propre compte TypeSafe, utilisez TypeSafe directement. + + +## Configuration + +Une seule commande, l'endpoint et la clé : + +```bash +failproofai jev --url https://api.typesafe.ai/v1 --key-stdin < ~/typesafe.key +``` + +### L'URL détermine le fournisseur + +Vous n'avez pas à nommer le fournisseur : le **host** de l'URL indique lequel c'est. + +| Host de l'URL | Fournisseur | Nécessite aussi | +| --- | --- | --- | +| `api.typesafe.ai` | `typesafe` | — | +| `openrouter.ai` | `openrouter` | — | +| `ai-gateway.vercel.sh` | `vercel` | — | +| `api.cloudflare.com` | `cloudflare` | `--account-id <32-hex-account-id>` | +| tout autre host | `custom` | — l'URL fournie est l'URL de base | + +Trois conséquences en découlent : + +- **Une URL qui est l'API propre du fournisseur n'écrit aucune substitution.** `--url https://api.typesafe.ai/v1` produit exactement la même configuration que `--provider typesafe`. Donnez un chemin ou un host différent sur un fournisseur connu et il est stocké comme URL de base, comme le ferait `--base-url`. +- **`--provider` remplace toujours l'inférence**, ce qui permet d'atteindre un proxy qui parle l'API d'un fournisseur depuis votre propre host : `--url https://jev-proxy.internal/v1 --provider typesafe`. +- **Un `--provider` qui contredit le host est refusé**, sans tentative de deviner. `--provider openrouter --url https://api.typesafe.ai/v1` n'écrit rien et explique pourquoi : les deux indications sont en désaccord sur la destination de votre clé. La même combinaison est refusée depuis `jev setup --base-url` et depuis les paramètres Jev du tableau de bord. (`--provider custom` n'est pas une contradiction — cela signifie « traiter cette URL telle quelle » — sauf sur le host de Cloudflare, dont l'endpoint par compte ne peut pas être atteint via une route custom.) + +`--url` est validé exactement comme le `baseUrl` dans le fichier de configuration, et refusé dans les mêmes termes : `https`, ou simple `http://localhost` en mode shadow uniquement. + +### La clé + +Transmettez-la avec `--key-stdin`, ou exécutez la commande dans un terminal sans ce flag et collez la clé à l'invite masquée. Dans les deux cas, elle va directement dans le fichier de configuration et n'est jamais affichée en retour. + + + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --key-stdin < ~/typesafe.key + ``` + + + ```bash + failproofai jev --url https://openrouter.ai/api/v1 --key-stdin < ~/openrouter.key + ``` + + + ```bash + failproofai jev --url https://ai-gateway.vercel.sh/typesafe/v1 \ + --key-stdin < ~/vercel-gateway.key + ``` + + + ```bash + failproofai jev --url https://api.cloudflare.com/client/v4 \ + --account-id <32-hex-account-id> --key-stdin < ~/cloudflare.token + ``` + + + ```bash + failproofai jev --url https://jev.internal.example.com/v1 --key-stdin < ~/jev.key + ``` + + + +`failproofai jev setup` prend les mêmes flags et est la forme longue de tout cela : `setup --provider ` pour nommer le fournisseur plutôt que l'URL. + +### `--token` et ce que ça coûte + +`--token ` place la clé sur la ligne de commande, ce qui est le moyen le plus rapide de configurer une machine et la seule façon de laisser la clé ailleurs que dans le fichier de configuration : + +```bash +failproofai jev --url https://openrouter.ai/api/v1 --token +``` + + +Un argument de ligne de commande se retrouve dans le fichier d'historique de votre shell, et pendant l'exécution de la commande il apparaît dans la liste des processus — lisible depuis `/proc` par tout ce qui s'exécute sous votre identité. `setup` le signale à chaque utilisation de `--token`. Préférez `--key-stdin` sur une machine partagée, dans une session enregistrée, ou partout où le fichier d'historique est synchronisé ; faites tourner une clé transmise de cette façon si cela est important. + + +`--token`, `--key-stdin` et `--key-from-env` sont mutuellement exclusifs : n'en donnez qu'un seul. + +Ensuite, envoyez une petite requête en direct pour vérifier la clé, l'endpoint et quelle version de Jev a répondu : + +```bash +failproofai jev test +``` + +```text + failproofai jev test ok · 523 ms + + provider cloudflare + model asked typesafe/jev + answered by jev-1.13.0 (Jev 1.13 family — verified) + latency 523 ms — within the 3000 ms timeout +``` + +`jev test` quitte avec le code 1, et l'indique dans son titre, lorsque la réponse arrive après le timeout (chaque hook reviendrait au regex comme `timeout`) ou répond incorrectement à sa question de vérification. + +Les hooks lisent la configuration à chaque appel d'outil, donc elle s'applique dès le suivant. Rien n'est à redémarrer, avec ou sans le daemon. + +## Vérifier ce qu'il fait + +```bash +failproofai jev status +failproofai jev status --json +``` + +`status` affiche le fournisseur, l'endpoint, le modèle, le mode, le fichier de configuration et ses permissions — jamais la clé. En dessous, il résume l'activité récente : combien d'appels Jev a évalués, à quelle fréquence il est revenu au regex et pourquoi, sa latence, et quelles politiques révisables il a autorisées. + +## Mode shadow + +`enforce` est le mode par défaut. Pour observer Jev sans lui permettre de modifier aucune décision, passez en mode `shadow` : Jev est toujours interrogé et ses verdicts sont enregistrés, mais c'est le résultat regex qui est appliqué. + +```bash +failproofai jev setup --mode shadow +failproofai jev setup --mode enforce +failproofai jev setup --mode off +``` + +`off` conserve la configuration — l'endpoint et la clé — et cesse d'interroger Jev : les hooks exécutent les politiques regex exactement comme sans configuration, et `failproofai jev status` indique « off (switched off) ». Repassez en mode `shadow` ou `enforce` avec le flag correspondant. + +Relancer `setup` pour le même fournisseur conserve la clé stockée, donc un changement de mode ne nécessite qu'un seul flag. Changer de fournisseur repart de zéro et demande la clé de ce fournisseur. Il en va de même pour un `--base-url` qui déplace les requêtes vers un host différent : une clé stockée n'est envoyée qu'au host pour lequel elle a été fournie, ou à l'API propre de son fournisseur. + +## Le fichier de configuration + +Tout réside dans un seul fichier, `~/.failproofai/jev.json`, écrit par `setup` : + +```json +{ + "provider": "cloudflare", + "apiKey": "", + "accountId": "<32-hex-account-id>", + "mode": "enforce", + "timeoutMs": 3000 +} +``` + +| Champ | Signification | +| --- | --- | +| `provider` | `typesafe`, `openrouter`, `vercel`, `cloudflare` ou `custom` — ou `failproofai`, dont la clé provient de la connexion FailproofAI Cloud plutôt que de ce fichier (voir [Jev via FailproofAI Cloud](/fr/policies/jev-cloud)). | +| `apiKey` | Envoyé en tant que `Authorization: Bearer `. | +| `baseUrl` | Obligatoire pour `custom` ; remplace la base API du fournisseur sinon. Doit être `https`. Le simple `http` vers `localhost` est accepté uniquement avec `mode: shadow` : rien n'authentifie un port local, donc pendant que votre proxy est arrêté, tout processus sur la machine, y compris l'agent jugé, pourrait répondre à sa place. | +| `accountId` | Cloudflare uniquement : 32 caractères hexadécimaux en minuscules. | +| `model` | Remplace l'identifiant de modèle par défaut du fournisseur. Un identifiant versionné doit nommer Jev 1.13. Une valeur ressemblant à une clé API est refusée (et non renvoyée), donc une clé collée dans `--model` n'est jamais stockée ni envoyée comme modèle. | +| `timeoutMs` | Durée pendant laquelle un appel d'outil attend Jev avant d'utiliser le résultat regex. 100–10000, défaut 3000. | +| `mode` | `enforce` (défaut), `shadow`, ou `off` (conserver la configuration, ne pas exécuter Jev). | + +Trois règles le protègent : + +- **Propriétaire uniquement.** Il est écrit avec les permissions `0600`. Une copie qu'un autre utilisateur ou groupe peut lire ou écrire est **refusée**, et les hooks reviennent au regex jusqu'à ce que vous exécutiez `chmod 600 ~/.failproofai/jev.json` ou `setup` à nouveau. Le répertoire est aussi vérifié : `~/.failproofai` ne doit pas être **inscriptible** par quelqu'un d'autre, car quiconque peut y écrire peut remplacer le fichier quelles que soient ses propres permissions. `setup` retire ces bits d'écriture s'il les trouve. `failproofai jev status` indique quand une configuration a été refusée et affiche l'endpoint nommé dans le fichier : quelqu'un d'autre pourrait l'avoir modifié, donc vérifiez qu'il vous appartient avant de faire `chmod`. Relancer `setup` sur un tel fichier n'achemine sa clé stockée que vers l'API propre du fournisseur ; tout autre endpoint qu'il nomme nécessite à nouveau la clé (`--key-stdin`), ou `--base-url default` pour renvoyer les requêtes vers le fournisseur. +- **Global uniquement.** Un dépôt ne peut pas activer Jev, le pointer vers un autre endpoint ou choisir son modèle : un `.failproofai/jev.json` à l'intérieur d'un projet est ignoré, et le fournisseur, l'URL, le modèle et l'identifiant de compte ne sont lus que depuis ce fichier — jamais depuis l'environnement, que les paramètres agent d'un dépôt peuvent définir. (`FAILPROOFAI_HOME` ne contourne pas cela : il déplace l'intégralité du répertoire failproofai, vos politiques incluses, plutôt que de rediriger Jev seul.) +- **La clé seule peut provenir de l'environnement.** Si le fichier n'a pas d'`apiKey`, `FAILPROOFAI_JEV_API_KEY` la fournit pour cette session (`setup --key-from-env` écrit un tel fichier). Elle ne remplace jamais une clé que le fichier contient, et elle ne peut pas activer Jev sans le fichier. Lorsque la variable n'est pas définie, Jev est simplement désactivé pour ce shell : `failproofai jev status` l'indique, quitte avec le code 0 et laisse la configuration intacte (`status --json` rapporte `"status": "key-missing"` avec `"reason": "no-env-key"`). Le daemon `failproofaid` ne voit pas l'environnement de votre shell, donc sur une machine configurée avec `failproofai config`, conservez la clé dans le fichier. + +## Quelle version de Jev répond + +Les seuils de décision de Failproof AI ont été calibrés sur Jev 1.13, donc une réponse n'est utilisée que lorsqu'elle provient de cette famille : `jev-1.13.x`, ou `typesafe/jev-1.13-` d'OpenRouter. Lorsqu'un fournisseur nomme Jev uniquement par un alias et ne rapporte aucune version (Vercel, et Cloudflare quand il ne le précise pas), la réponse est utilisée et enregistrée comme non vérifiée. Un endpoint `custom` doit rapporter le modèle qui a répondu ; la seule exception est un nom `--model` non versionné que vous avez configuré pour lui, qui, renvoyé en écho, est enregistré comme non vérifié de la même façon. Une réponse rapportant toute autre version, ou une réponse `custom` n'en rapportant aucune, n'est pas utilisée : cet appel revient au regex avec la raison `model-mismatch`. + +## Quand Jev ne peut pas répondre + +Chacun de ces cas revient au résultat regex pour cet appel et est enregistré avec sa raison, que `failproofai jev status` totalise : + +| Raison | Cause | +| --- | --- | +| `timeout` | Aucune réponse dans le délai `timeoutMs`. | +| `http-429` | Le fournisseur a limité la clé en débit. | +| `rate-limited` | Le limiteur interne de Failproof AI a retenu l'appel avant de l'envoyer : 5 requêtes par seconde, en rafales de 5 au maximum, et aucune pendant un moment après que le fournisseur répond `429`. Pas le fournisseur. | +| `http-500`, `http-502`, `http-503`, … | Une erreur serveur chez le fournisseur. Le statut exact est enregistré. | +| `out-of-credits` | HTTP 402 : le compte fournisseur n'a plus de crédits. | +| `provider-refused` | HTTP 402 de Cloudflare indiquant « Model execution failed (Payment error) » : le fournisseur a refusé d'exécuter le modèle sur cette requête. Généralement pas lié à la facturation, donc recharger les crédits ne résoudra pas le problème. | +| `http-401`, `http-403` | La clé a été refusée. | +| `http-404` | Rien n'est servi à `/systemone`, donc l'URL de base est incorrecte — `/systemone` y est ajouté, et chaque fournisseur le sert à sa racine de version. `failproofai jev models` montre ce que l'endpoint sert effectivement. | +| `network` | L'endpoint n'a pas pu être atteint. | +| `http-301`, `http-302`, `http-307`, `http-308` | L'endpoint a répondu avec une redirection. Les redirections ne sont jamais suivies, donc la réponse ne vient que de l'URL dans votre configuration ; définissez `--base-url` sur l'URL finale. | +| `malformed` | L'endpoint a répondu, mais pas avec une réponse Jev — un corps qui n'est pas JSON, ou sans réponses. | +| `cloudflare-error`, `cloudflare-incomplete` | L'enveloppe de Cloudflare a rapporté un échec, ou un job non terminé. | +| `model-mismatch` | Une version de Jev autre que 1.13 a répondu, ou un endpoint `custom` n'a pas indiqué quel modèle a répondu. | +| `request-cut` | **Pas une panne.** Jev a répondu ; il n'a vu qu'une partie de l'appel, donc sa réponse n'a rien autorisé. Voir [Quand Jev a répondu, mais pas sur l'intégralité de l'appel](#when-jev-answered-but-not-on-the-whole-call). | + +`failproofai jev status` peut aussi afficher quelques raisons plus rares, comme `upstream-error` (la réponse portait l'erreur propre du fournisseur) ou `config`, et totalise toute raison qu'il ne peut pas nommer sous `other`. + +`request-cut` figure dans ce tableau parce que `failproofai jev status` le totalise avec les autres, et parce qu'il maintient lui aussi tous les refus. C'est la seule raison ici qui ne dit rien sur votre fournisseur : la requête est arrivée et Jev y a répondu. Contrairement à toutes les lignes précédentes, cette réponse compte quand même — le propre refus ou avertissement de Jev s'applique en plus du résultat regex plutôt que d'être ignoré. Donc une suite de ces cas signifie que des appels atteignent l'évaluateur trop volumineux pour être envoyés en entier, pas que votre endpoint est défaillant, et recharger des crédits ou changer d'URL ne fera pas baisser le nombre. + +## Quand Jev a répondu, mais pas sur l'intégralité de l'appel + +Deux autres situations peuvent se produire, et aucune ne correspond à un échec de réponse de Jev. Toutes deux portent sur la quantité de l'appel, ou de la conversation, qui tient dans une seule requête. + +**Une partie de l'appel lui-même n'a pas tenu.** Un appel d'outil est envoyé dans un budget fixe, et un très volumineux — un très grand `Write`, un énorme corps MCP, une commande gonflée jusqu'à la limite — est envoyé avec ce qui a tenu. Jev répond quand même, et sa réponse compte quand même : son propre refus ou avertissement s'applique normalement. Ce qu'il ne peut pas faire, c'est **autoriser** quoi que ce soit, car un verdict rendu sur une partie d'un appel n'est pas un verdict sur l'appel. Donc tous les refus de politique restent, et l'appel est enregistré comme un fallback avec la raison `request-cut`, que `failproofai jev status` totalise avec les raisons ci-dessus. La règle que cela vous donne : rendre un appel plus volumineux peut lui coûter ses autorisations, et ne peut jamais en obtenir une. + +**Un message n'a pas tenu.** Un long prompt que vous avez collé, le dernier message de l'agent, ou un prompt que le store propre de cet évaluateur avait déjà tronqué. **Rien ne change** : l'appel est jugé, autorisé et enregistré exactement comme n'importe quel autre, et il n'est pas comptabilisé comme fallback. La longueur de ce que vous tapez ne détermine jamais un verdict, et une troncature ne peut pas fabriquer un consentement : lorsqu'un prompt est arrivé déjà tronqué, « vous n'avez pas demandé ceci » cesse d'être une conclusion qui peut en être tirée, plutôt que de le devenir. + +La ligne de démarcation entre les deux, c'est qui a écrit le texte. L'appel appartient à l'agent, et une règle qui permettrait à sa longueur de réduire la gravité serait une règle dont l'agent pourrait se servir ; votre prompt vous appartient, et traiter sa longueur comme un signal ne fait que pénaliser le fait de coller une spec ou une trace de pile. + +## Ce qui quitte la machine + +Pour chaque appel d'outil que Jev évalue, une requête est envoyée à votre fournisseur, contenant : + +- l'appel d'outil lui-même, avec les secrets tels que les clés API, les tokens bearer et les affectations `KEY=` masqués ; +- les prompts récents que vous avez tapés, avec le texte ajouté par le harnais de votre agent retiré ; +- le dernier message de l'agent avant votre dernier prompt, étiqueté comme écrit par l'agent ; +- des faits calculés localement, comme si un chemin est à l'intérieur du projet — celui dans lequel la session se trouvait lors de son premier appel révisé, [épinglé pour la session](/fr/reference/jev-intent#the-project-root) — et la branche git actuelle. + +Cela va uniquement vers l'endpoint dans votre configuration, sous votre clé. + +## Désactivation + +```bash +failproofai jev remove +``` + +Cela supprime `~/.failproofai/jev.json`. À partir du prochain appel d'outil, les hooks exécutent les politiques regex exactement comme avant. Les stores par session sous `~/.failproofai/state/semantic/` (prompts enregistrés dans `sessions/`, racines de projet dans `roots/`) sont laissés en place et expirent naturellement. Pour arrêter d'interroger Jev tout en conservant la configuration, utilisez plutôt `failproofai jev setup --mode off`. + +## Référence des commandes + +| Commande | Résultat | +| --- | --- | +| `failproofai jev --url --key-stdin` | Le configurer en une seule commande ; le fournisseur est déduit du host de l'URL | +| `failproofai jev --url --token ` | Pareil, avec la clé sur la ligne de commande — votre historique et la liste des processus la voient | +| `failproofai jev setup --provider --key-stdin` | Écrire la configuration depuis une clé transmise sur stdin | +| `failproofai jev setup --provider ` | Pareil, en demandant la clé à une invite masquée | +| `failproofai jev setup --key-from-env` | Ne stocker aucune clé ; lire `FAILPROOFAI_JEV_API_KEY` par session | +| `failproofai jev setup --mode shadow` | Changer de mode (`enforce`, `shadow` ou `off`), en conservant la clé stockée | +| `failproofai jev setup --model ` / `--base-url ` | Remplacer le modèle ou la base API ; `default` efface la substitution | +| `failproofai jev setup --timeout-ms ` | Modifier le budget par appel | +| `failproofai jev status [--json]` | Configuration, permissions et activité récente ; jamais la clé | +| `failproofai jev test [--json]` | Une requête en direct : latence et version ayant répondu | +| `failproofai jev models [--provider ] [--url ] [--json]` | Les identifiants de modèles que `/models` de cet endpoint rapporte, en marquant celui configuré | +| `failproofai jev remove` | Supprimer la configuration ; Jev est désactivé | \ No newline at end of file diff --git a/docs/fr/policies/jev-cloud.mdx b/docs/fr/policies/jev-cloud.mdx new file mode 100644 index 000000000..ce98411c7 --- /dev/null +++ b/docs/fr/policies/jev-cloud.mdx @@ -0,0 +1,117 @@ +--- +title: "Jev via FailproofAI Cloud" +description: "Laissez Jev évaluer les appels d'outils de vos agents via FailproofAI Cloud, sur le forfait de votre organisation, sans compte ni clé TypeSafe personnels." +icon: "cloud" +--- + +[Jev](/fr/policies/jev-byok), le classificateur de TypeSafe, analyse chaque appel d'outil par rapport à ce que vous avez réellement demandé et intervient aux côtés de vos politiques, sans jamais les remplacer. Via **FailproofAI Cloud**, une machine connectée utilise Jev avec la clé qu'elle utilise déjà pour se connecter : pas de compte TypeSafe, pas de seconde clé, pas d'endpoint à configurer. Chaque appel est imputé sur l'allocation du forfait existant de votre organisation. + +Tout ce que fait Jev est identique à la [configuration avec votre propre clé](/fr/policies/jev-byok) : les politiques strictes restent définitives, le refus d'une politique révisable n'est levé que lorsque Jev a été interrogé précisément sur ce point, et toute défaillance revient au résultat regex pour cet appel. + + +Nécessite **failproofai 1.0.8-beta.0** ou une version ultérieure. La version 1.0.7 ne dispose pas de Jev, même si elle apparaît au-dessus des versions bêta 1.0.7 dans le tri. Sans configuration Jev, rien ne change : les hooks exécutent les politiques regex exactement comme avant. + + +## Activation + +1. **Créez une clé avec Jev.** Dans le tableau de bord FailproofAI Cloud, ouvrez **Keys → Create key** et choisissez le preset **machine**. Il accorde les trois permissions dont une machine a besoin : `events:add` (envoyer l'activité), `policies:pull` (recevoir les politiques) et `jev:evaluate` (Jev, imputé sur le forfait de votre organisation). Une clé ne peut pas porter `jev:evaluate` sans les deux autres. +2. **Connectez la machine** avec cette clé : + + ```bash + failproofai config --token + ``` + + Si votre organisation gère sa propre instance FailproofAI Cloud plutôt que le service hébergé, ajoutez son adresse : `--url https://` (ou exportez `FAILPROOFAI_CLOUD_URL`). Sans cela, la clé est vérifiée contre le service hébergé et la connexion échoue. Si le certificat de cet hôte provient d'une CA privée, installez la CA dans le magasin de confiance système de la machine (par exemple avec `update-ca-certificates`), et non uniquement dans `NODE_EXTRA_CA_CERTS` : le démon qui envoie les événements et récupère les politiques lit le magasin système. Consultez [Dépannage](/fr/reference/troubleshooting). + +C'est tout. La connexion enregistre la clé et, lorsque la machine n'a **pas encore** de configuration Jev, active Jev via FailproofAI Cloud en mode **shadow** : Jev est interrogé pour chaque appel d'outil soumis à condition et ses verdicts sont enregistrés, mais c'est le résultat de vos politiques qui est appliqué. Le résultat l'indique : + +```text + Jev on through FailproofAI Cloud, in shadow mode: logged, not enforced (~/.failproofai/jev.json). +``` + +**Avec `--no-transcripts`, la connexion n'active pas Jev.** Jev envoie chaque appel d'outil vérifié ainsi que le prompt récent à FailproofAI Cloud, ce qui va au-delà de ce qu'une connexion en mode décisions uniquement est autorisée à envoyer. La clé est tout de même enregistrée, et le résultat indique que Jev est disponible et comment l'activer : + +```bash +failproofai jev setup --provider failproofai +``` + +Cela n'**désactive** pas non plus Jev. Si le fichier `jev.json` de la machine exécute déjà Jev via FailproofAI Cloud, il reste tel quel, et le résultat indique que Jev continue d'envoyer chaque appel d'outil vérifié et le prompt récent, et que `failproofai jev setup --mode off` permet de le désactiver. + + +La connexion **ne remplace jamais** un fichier `~/.failproofai/jev.json` existant. Si vous utilisez déjà votre propre endpoint Jev, il continue d'être utilisé, et le résultat indique que le fichier a été laissé tel quel — et, lorsque ce fichier laisse Jev désactivé (refusé ou désactivé manuellement), l'indique ainsi que la marche à suivre. Pour basculer cette machine sur FailproofAI Cloud, exécutez `failproofai jev setup --provider failproofai`. + + +## Shadow, enforce ou off + +Commencez en mode shadow, observez ce que Jev aurait fait sur la page des politiques, puis laissez-le agir : + +```bash +failproofai jev setup --mode enforce # Les verdicts de Jev s'appliquent : il peut lever un refus révisable et émettre le sien +failproofai jev setup --mode shadow # Jev est interrogé et enregistré ; c'est le résultat de vos politiques qui est appliqué +failproofai jev setup --mode off # Conserve la configuration, cesse d'interroger Jev +``` + +Le même commutateur se trouve dans le tableau de bord local : **Settings → Jev** dispose d'un bouton on/off et d'un choix shadow/enforce. Il réécrit uniquement le mode. Les hooks lisent la configuration à chaque appel d'outil, donc un changement s'applique dès l'appel suivant, sans redémarrage. + +## Vérifier ce qu'il fait + +```bash +failproofai jev status +failproofai jev test +``` + +`status` affiche le fournisseur comme **FailproofAI Cloud**, l'hôte Cloud auquel la machine est connectée, le mode, et la source de la clé comme **connexion FailproofAI Cloud**, jamais la clé elle-même. Lorsqu'un fichier `jev.json` FailproofAI Cloud est en place mais que Jev ne peut pas fonctionner, il en indique la raison : + +| `status` indique | `status --json` | Signification | +| --- | --- | --- | +| **off — no Jev key is stored for this machine's FailproofAI Cloud connection** | `key-lacks-jev` | La machine est connectée, mais aucune clé Jev n'est enregistrée pour elle : la clé ne possède pas `jev:evaluate`, ou la connexion n'a pas pu le confirmer. Exécutez à nouveau `failproofai config --token ` avec la même clé ; si elle ne dispose pas de la permission, utilisez une clé **machine**. | +| **off — this machine is not connected to FailproofAI Cloud** | `not-connected` | Il n'y a pas de connexion FailproofAI Cloud sur cette machine pour la clé Jev. | + +Après `failproofai config --disconnect`, il n'y a plus de fichier `jev.json` FailproofAI Cloud (sauf s'il avait été désactivé, auquel cas il est conservé), donc `status` signale simplement Jev comme désactivé. `status --json` contient les mêmes informations (`provider: "failproofai"`, `keySource: "cloud"`, `cloudConnected`, `keyCarriesJev`), y compris lorsque la configuration est absente ou refusée. `permissions` correspond toujours au contenu de `jev.json` ; un refus concernant `credentials.json` ajoute `credentialsPermissions`, ainsi que `fix` lorsqu'une seule commande suffit à corriger le problème. `test` envoie une requête en direct et rapporte sa latence ainsi que la version de Jev qui a répondu. Il se termine avec le code 1, et l'indique dans son titre, lorsque la réponse arrive après le délai d'expiration du hook (les hooks enregistreraient `timeout`) ou répond incorrectement à sa question de vérification. + +Le panneau **Settings → Jev** du tableau de bord affiche également la **connexion FailproofAI Cloud** : l'organisation dans laquelle la machine est enregistrée et si sa clé porte Jev. Ces informations sont lues depuis les fichiers locaux de la machine, sans appel réseau. + +## Ce qui parvient à la page des politiques + +La machine envoie déjà son activité de hook à FailproofAI Cloud (`events:add`). Avec Jev activé, l'enregistrement de chaque appel soumis à condition indique également quel évaluateur a été utilisé, ce que Jev a décidé, quelles politiques il a levées, pourquoi il a reculé le cas échéant, sa latence et le modèle qui a répondu — décisions, codes et noms, jamais la commande ni votre prompt. Sur la page **Policies** de votre organisation : + +- un appel décidé par le verdict propre de Jev (mode enforce) est attribué à **Jev**, et lorsque la vérification décisive provient d'un pack, l'enregistrement nomme également ce pack et sa version ; +- en mode shadow, le refus ou l'avertissement de Jev apparaît comme un **would-have**, à côté des déploiements que vous observez ; +- les politiques levées par Jev, ou qu'il aurait levées en mode shadow, sont comptabilisées par politique. + +## Quand Jev ne peut pas répondre + +Chacun des cas suivants revient au résultat de vos politiques pour cet appel, et est enregistré avec sa raison : + +| Raison | Cause | +| --- | --- | +| `out-of-credits` | Votre organisation a épuisé son allocation de forfait. | +| `http-401`, `http-403` | La clé a été révoquée, ou ne porte pas `jev:evaluate`. Reconnectez-vous avec une clé qui le possède. | +| `http-429` | FailproofAI Cloud limite le débit de Jev pour votre organisation. Jusqu'à la fin du délai demandé (`Retry-After`, 60 secondes au maximum), la machine n'envoie rien et chaque appel revient immédiatement au résultat de secours. Les appels retenus de cette façon sont enregistrés comme `http-429`, ou comme `rate-limited` lorsque la limite de débit propre de la machine les retient en premier. | +| `http-429` (limite quotidienne) | Votre organisation a atteint sa limite quotidienne d'appels Jev : **10 000 par jour UTC**, sauf si l'opérateur de votre FailproofAI Cloud a défini une autre limite. Chaque appel revient au résultat de secours jusqu'à la réinitialisation du compteur à 00:00 UTC ; la machine interroge à nouveau au maximum une fois par minute, donc elle détecte la réinitialisation en moins d'une minute. `failproofai jev test` affiche « Daily Jev limit for this org reached; resets at 00:00 UTC. » | +| `http-422` | Jev a refusé la requête de cet appel, généralement parce que l'appel d'outil contenait du texte dense (base64, hexadécimal, code minifié) dépassant le budget de tokens de Jev. Cet appel revient toujours au résultat de secours ; ce n'est pas une panne. | +| `http-502` | Jev est temporairement indisponible. | +| `http-503` | Ce Cloud ne peut pas servir Jev pour votre organisation : pas de passerelle de modèle, une organisation pas encore provisionnée, ou la passerelle est hors service. Contactez votre administrateur ; les hooks réessayent au maximum une fois par minute. | +| `http-404` | Ce FailproofAI Cloud ne propose pas encore Jev. | +| `timeout` | Aucune réponse dans le délai `timeoutMs` (3000 ms par défaut). | +| `model-mismatch` | Une version de Jev autre que 1.13 a répondu. | + +## Où la clé est stockée et où elle va + +- La clé est stockée une seule fois, dans `~/.failproofai/credentials.json` (`0600`, dans un répertoire accessible uniquement par le propriétaire), aux côtés des autres identifiants FailproofAI Cloud. `jev.json` ne contient aucune clé pour cette route ; une clé qui y serait écrite rend la configuration invalide. +- Si `credentials.json` accorde **une quelconque** permission à quelqu'un d'autre que vous (groupe ou autre, lecture ou écriture), ou si son répertoire peut être **écrit** par quelqu'un d'autre que vous, il est **refusé**, non lu, et Jev est désactivé jusqu'à ce que vous corrigiez le problème : `chmod 600` sur le fichier, `chmod 700` sur le répertoire (ou reconnectez-vous, ce qui réécrit le fichier avec les permissions `0600` et rend le répertoire accessible uniquement par le propriétaire). Un répertoire que d'autres peuvent seulement lire est acceptable ; un répertoire qu'ils peuvent écrire leur permet de substituer le fichier. +- La clé ne compte que tant que la connexion avec laquelle elle est arrivée est présente sur la machine : un identifiant de politique ou de reporting pour le même FailproofAI Cloud **avec la même clé**, dans le même fichier. Une clé Jev laissée sans connexion est ignorée, et Jev reste désactivé. Cela se produit lorsque la commande `config --disconnect` d'une version plus ancienne de failproofai laisse la clé Jev en place (elle ne sait pas qu'il faut la supprimer), ou lorsque la commande `config --token` d'une version plus ancienne de failproofai se connecte avec une autre clé, qui sur FailproofAI Cloud peut appartenir à une autre organisation. Pour réactiver Jev, reconnectez-vous avec une clé **machine**. +- La clé est uniquement envoyée à l'origine Cloud contre laquelle elle a été vérifiée. Un fichier `jev.json` pointant ailleurs est refusé. +- **Un agent sur la machine peut la lire.** `credentials.json` est accessible uniquement par le propriétaire, et l'agent s'exécute en tant que ce propriétaire. La lecture des fichiers propres à failproofai est autorisée intentionnellement (seule leur modification est bloquée, par `block-failproofai-commands`), donc la seule chose entre un agent et ce fichier est `block-read-outside-cwd` — une politique *révisable* — et, depuis une session démarrée dans votre répertoire personnel, rien du tout. Une clé avec `jev:evaluate` dépense l'allocation Jev de votre organisation (dans la limite du plafond quotidien) depuis n'importe quel endroit où elle est utilisée, donc traitez une clé machine comme tout autre identifiant de dépense : si un agent a pu la lire, désactivez-la sur la page Keys et reconnectez-vous avec une nouvelle. +- Seuls vos fichiers globaux déterminent cela. Un dépôt ne peut pas activer Cloud Jev, le pointer ailleurs ni fournir sa clé, et `FAILPROOFAI_JEV_API_KEY` est ignoré pour cette route. +- Pour chaque appel évalué par Jev, une requête est envoyée à FailproofAI Cloud, contenant ce que la [page bring-your-own-key](/fr/policies/jev-byok#what-leaves-the-machine) liste (secrets expurgés). FailproofAI Cloud le transmet à TypeSafe et ne le journalise ni ne le conserve. + +## Désactivation + +| Commande | Résultat | +| --- | --- | +| `failproofai jev setup --mode off` | Conserve la configuration ; Jev n'est plus interrogé. **C'est le commutateur qui persiste :** une nouvelle connexion ne réécrit jamais un fichier `jev.json` existant, donc Jev reste désactivé jusqu'à ce que vous le réactiviez avec `--mode shadow`. | +| `failproofai jev remove` | Supprime `~/.failproofai/jev.json` ; Jev est désactivé — jusqu'à la prochaine exécution de `failproofai config --token` avec une clé portant `jev:evaluate`, qui ne trouvant pas de `jev.json` activera à nouveau Jev en mode shadow (sauf si elle s'exécute avec `--no-transcripts`). Pour le garder désactivé, utilisez `--mode off`. | +| `failproofai config --disconnect` | Déconnecte la machine : la clé est supprimée, ainsi que `jev.json` lorsqu'il désigne FailproofAI Cloud et n'est pas en mode désactivé. Un fichier `jev.json` pour votre propre endpoint est conservé, de même qu'un fichier en mode désactivé, de sorte que Jev reste désactivé lors d'une nouvelle connexion. | + +Dès l'appel d'outil suivant, les hooks exécutent les politiques regex exactement comme avant. \ No newline at end of file diff --git a/docs/fr/policies/jev.mdx b/docs/fr/policies/jev.mdx new file mode 100644 index 000000000..feb8af4c2 --- /dev/null +++ b/docs/fr/policies/jev.mdx @@ -0,0 +1,45 @@ +--- +title: "Politiques Jev" +description: "Ajoutez la révision en direct de Jev aux appels d'outils contrôlés, puis inspectez ses décisions avant de les appliquer." +icon: "shield-check" +--- + +Jev analyse un appel d'outil au regard de ce que la personne a demandé à l'agent de faire. Utilisez-le lorsqu'une politique basée sur la correspondance de chaînes bloque un travail valide ou laisse passer une action risquée qui nécessite du contexte. Il répond aux côtés de vos politiques au niveau du point de contrôle `PreToolUse` ou `PermissionRequest`. Pour un score **après** la fin d'une session, utilisez les [évaluations Jev](/fr/evaluations/jev). + +## Démarrer en mode observation + +Installez Failproof AI et attachez des hooks à un [harnais compatible](/fr/reference/harnesses). Utilisez failproofai 1.0.8-beta.0 ou une version ultérieure. + +Failproof AI ne fournit aucune vérification Jev par défaut. Installez-les sous forme de pack, sinon Jev n'a rien à évaluer et ne sera jamais appelé : + +```bash +failproofai policies add FailproofAI/jev-policies +``` + +Choisissez ensuite comment les requêtes parviennent à Jev : + +| Itinéraire | Première étape | +| --- | --- | +| FailproofAI Cloud | Connectez-vous avec une clé **machine** disposant de la permission `jev:evaluate`. Sur une machine sans configuration Jev, `failproofai config` active Jev en mode observation. | +| Votre propre fournisseur | Dans le tableau de bord local, ouvrez **Paramètres → Jev**, choisissez le fournisseur, collez son jeton et sélectionnez **observer**. Ou exécutez `failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key`. | + +![Paramètres Jev du tableau de bord local : fournisseur, point de terminaison, jeton et mode observation avant l'activation de Jev.](/images/dashboard/jev-settings.png) + +```bash +failproofai jev status +failproofai jev test +``` + +`test` vérifie le point de terminaison. Pour vérifier le chemin du hook, demandez à un agent instrumenté d'utiliser son outil de lecture de fichier sur `README.md`. Confirmez que cet appel d'outil apparaît dans la session, puis inspectez **Politiques → Activité** dans le [tableau de bord local](/fr/reference/local-dashboard#review-policy-activity). Le compteur Jev dans `status` devrait augmenter. Le mode observation enregistre ce que Jev aurait décidé, tandis que le résultat de votre politique existante continue de s'appliquer. + +## Décider du moment d'appliquer les décisions + +Une politique **dure** a toujours le dernier mot. Jev ne peut lever un refus que d'une politique explicitement marquée comme **révisable** et uniquement lorsqu'il a évalué le motif nommé de cette politique. Consultez [l'autorité des politiques](/fr/policies/authority) avant de vous fier à une levée. Jev peut également émettre un avertissement ou refuser de son propre chef. S'il ne peut pas répondre, c'est le résultat de la politique qui décide de cet appel. + +Une fois que les résultats en mode observation semblent corrects, passez en mode application dans **Paramètres → Jev** ou exécutez : + +```bash +failproofai jev setup --mode enforce +``` + +Pour les URL de fournisseurs, les clés Cloud, la configuration, les mécanismes de repli et les données envoyées avec chaque requête, consultez la [référence d'intégration Jev](/fr/reference/jev). \ No newline at end of file diff --git a/docs/fr/reference/custom-agents-typescript.mdx b/docs/fr/reference/custom-agents-typescript.mdx new file mode 100644 index 000000000..f976d6f47 --- /dev/null +++ b/docs/fr/reference/custom-agents-typescript.mdx @@ -0,0 +1,401 @@ +--- +title: "Agents personnalisés (TypeScript)" +description: "Configuration, le catalogue d'événements, les scopes et les adaptateurs de framework pour @failproofai/sdk." +icon: "square-js" +--- + +Ce que fait chaque paramètre, méthode et champ du SDK TypeScript. Si vous instrumentez pour la première fois, commencez par le guide — cette page sert de référence. + + + + Installation, instrumentation, les méthodes d'événements, un exemple concret et les problèmes courants. + + + Les mêmes événements, le même format de transmission, le même spool — depuis Python. + + + +Node 20.9 ou supérieur. ESM et CommonJS. Aucune dépendance d'exécution. + + + Ce SDK et celui de Python écrivent **les mêmes événements dans le même spool**. Une flotte avec des agents Node et des agents Python produit un seul ensemble de sessions, pas deux, et rien dans le tableau de bord ne les distingue. Choisissez par service, pas par entreprise. + + +## Installation + +```bash +npm install @failproofai/sdk +``` + +```ts +import * as failproofai from "@failproofai/sdk"; + +await failproofai.agent("planner", { goal: question }, async () => { + const hits = await failproofai.toolCall("web_search", { input: { q } }, () => search(q)); +}); +``` + +Les adaptateurs de framework sont inclus dans le package lui-même. Les frameworks sont des **dépendances pair optionnelles** — déclarées pour que les plages de versions supportées soient visibles, jamais installées à votre place, et importées uniquement lorsque vous appelez `instrument()`. + +## Connecter le daemon Failproof + +Identique au SDK Python : créez une clé `events:add` sous **Admin → Keys**, puis [connectez le daemon](/fr/start/setup#connect-a-machine-to-cloud) sur la machine agent. Le SDK écrit sur disque ; le daemon expédie. + +## Configuration + +```ts +failproofai.configure({ + environment: "production", + flushInterval: 0.5, + baseDir: undefined, +}); +``` + +| Option | Ce qu'elle fait | +| --- | --- | +| `environment` | Le libellé sur chaque événement — `production`, `staging`, `prod-eu`. Par défaut `dev`. | +| `flushInterval` | La fréquence à laquelle le timer écrit sur disque, en secondes. Par défaut `0.5`. | +| `baseDir` | L'emplacement d'écriture. Par défaut le spool du daemon, ce qui convient sauf si vous savez pourquoi modifier. | + +Rien n'est appliqué si la validation échoue, donc un appel rejeté laisse le SDK exactement dans son état précédent plutôt qu'avec un nouveau `baseDir` et l'ancien intervalle. + +Configuration via variable d'environnement : + +| Variable | Ce qu'elle fait | +| --- | --- | +| `AGENTEYE_ENVIRONMENT` | Définit `environment` sans modification du code. Une option `configure()` a la priorité. | +| `FAILPROOFAI_HOME` | Déplace la racine Failproof AI qui contient le spool. | +| `FAILPROOFAI_SDK_LOG_LEVEL` | `debug`, `info`, `warn` (par défaut), `error`, `silent`. | +| `FAILPROOFAI_SDK_STRICT` | `1` fait lever une exception sur les erreurs d'instrumentation au lieu de les journaliser. | +| `FAILPROOFAI_SDK_STRICT_INTEGRATIONS` | `1` fait lever une exception sur un problème de compatibilité de framework au lieu d'avertir et de continuer. | + + + **Pas de virgules dans `environment`.** L'ingestion découpe ce champ sur les virgules pour construire ses filtres et ignore tout événement dont le libellé en contient une — toute une exécution peut disparaître silencieusement. Écrivez `prod-eu`, pas `prod,eu`. + + `configure({ environment: "prod,eu" })` lève une exception pour que vous le découvriez immédiatement. `AGENTEYE_ENVIRONMENT` ne peut pas lever d'exception — rien ne vous appelle — donc il avertit une fois et revient à `dev`. + + +Redirigez les lignes de log propres au SDK vers votre logger avec `failproofai.setLogger({ debug, info, warn, error })`. + +## Arrêt + +Les événements en mémoire tampon sont vidés lors de `process.on("exit")`. + +Un processus tué par un signal n'atteint jamais ce point, et le comportement par défaut de Node pour `SIGTERM` est de terminer sans exécuter les gestionnaires de sortie — ainsi, un agent containerisé perd ce que le dernier intervalle n'avait pas encore écrit. + + + **Ce SDK n'installera pas de gestionnaire de signal à votre place.** En enregistrer un modifie le comportement de votre processus : un listener supprime la terminaison par défaut de Node, donc une bibliothèque qui en ajouterait un empêcherait silencieusement Ctrl-C de fonctionner. Ajoutez le vôtre : + + ```ts + for (const signal of ["SIGINT", "SIGTERM"] as const) { + process.once(signal, () => { + failproofai.flushSync(); + process.exit(0); + }); + } + ``` + + +Un script de courte durée ou un gestionnaire serverless devrait `await failproofai.flush()` avant de retourner — l'intervalle seul ne garantit pas la livraison. + +## Identité + +Chaque événement appartient à une session et à un agent. **Les scopes remplissent les deux**, donc vous les passez rarement : + +```ts +await failproofai.session(async () => { + await failproofai.agent("planner", async () => { + failproofai.event.toolUse({ toolName: "search", toolCallId: "c1" }); + }); +}); +``` + +Passer `sessionId` ou `agentId` explicitement fonctionne toujours et a la priorité. Si ni l'un ni l'autre n'est lié ou passé, l'appel lève une exception plutôt qu'émettre un événement que Cloud ignorerait silencieusement. + + + L'identité repose sur `AsyncLocalStorage`. Elle suit `await`, `.then()`, les timers et tout callback créé à l'intérieur du scope. Elle ne suit **pas** un callback stocké lors d'une exécution et invoqué lors d'une autre, ni le travail transmis via une frontière `worker_threads` — encapsulez-les dans `failproofai.propagate()` ou leurs événements arriveront sans être rattachés. + + +### Scopes + +| Scope | Émet | Retourne | +| --- | --- | --- | +| `session(body)` | rien — identité uniquement | ce que retourne `body` | +| `agent(id, options?, body)` | `agent_start`, puis `agent_end` | ce que retourne `body` | +| `toolCall(name, options?, body)` | `tool_use`, puis `tool_result` | ce que retourne `body` | + +Un body synchrone reste synchrone : `agent("x", () => 1)` retourne `1`, pas une promesse. + +`toolCall` enregistre la valeur résolue du body comme `output` de l'outil, sauf si vous assignez `call.output` vous-même. + + + +| Ce qui s'est passé | Événements | `outcome` | +| --- | --- | --- | +| le bloc a retourné | `agent_end` | `"success"`, ou votre `outcome` | +| le bloc a levé une exception | `error`, puis `agent_end` | `"failed"` | +| une `AbortError` | `agent_end` uniquement | `"cancelled"` | + +L'erreur est toujours re-levée. + +Un échec d'outil est enregistré sur la feuille — `tool_result` avec une chaîne `error` — et n'émet **aucun** événement `error` au niveau de l'exécution. Celui que la boucle agent intercepte n'est pas un échec d'exécution, et celui qui se propage est signalé exactement une fois, par l'`agent()` englobant. + + + + + +Quand le travail n'est pas une seule fonction — un scope ouvert dans un constructeur et fermé dans un teardown, ou qui chevauche un flux de contrôle existant : + +```ts +{ + using span = failproofai.agent.open("planner", { goal }); + using call = failproofai.toolCall.open("search", { input: { q } }); + call.call.output = await search(q); +} // tool_result, then agent_end +``` + +Les deux formes émettent des événements identiques octet par octet. Préférez la forme avec callback : elle s'exécute dans `AsyncLocalStorage.run()`, donc il n'y a rien à dérouler et toute la classe de bugs « ouvert ici, fermé ailleurs » est inatteignable. + +Un bloc `using` qui intercepte sa propre défaillance la signale avec `span.fail(error)` — le disposer n'a pas de canal d'exception propre. + + + +## Catalogue d'événements + +Les mêmes quinze méthodes que le SDK Python, en camelCase. La plupart viennent par **paires** — vous appelez l'ouvreur, puis le fermeur, et le SDK mesure l'écart. + +| | Ouvre | Ferme | +| --- | --- | --- | +| **Agents** | `agentStart` | `agentEnd` | +| | `agentPause` | `agentResume` | +| **Modèles** | `modelRequest` | `modelResponse` | +| **Outils** | `toolUse` | `toolResult` | +| **Hooks** | `hookTriggered` | `hookCompleted` | +| **Humains** | `humanWait` | `humanInput` | + +Trois sont autonomes : `error`, `humanPause`, `humanInterrupt`. + + + +Chaque méthode accepte également `sessionId` et `agentId`, que les scopes remplissent pour vous. Tout ce qui est omis est supprimé plutôt qu'envoyé comme JSON `null`. + +| Méthode | Requis | Optionnel | +| --- | --- | --- | +| `agentStart` | — | `goal`, `parentId` | +| `agentEnd` | — | `outcome`, `summary` | +| `agentPause` | `pauseId` | `reason`, `userId` | +| `agentResume` | `pauseId` | `reason`, `userId` | +| `modelRequest` | — | `model`, `messages`, `system`, `tools`, `requestId` | +| `modelResponse` | — | `model`, `stopReason`, `inputTokens`, `outputTokens`, `content`, `role`, `requestId` | +| `toolUse` | `toolName`, `toolCallId` | `input` | +| `toolResult` | `toolName`, `toolCallId` | `output`, `error` | +| `hookTriggered` | `hookName`, `hookId` | `triggerEvent`, `input` | +| `hookCompleted` | `hookName`, `hookId` | `outcome`, `output`, `error` | +| `error` | `errorType`, `message` | `traceback` | +| `humanWait` | `inputId` | `prompt`, `options`, `reason` | +| `humanInput` | `inputId` | `response` | +| `humanPause` | — | `reason`, `userId` | +| `humanInterrupt` | — | `reason`, `userId`, `atStep` | + +Toute autre clé que vous ajoutez devient un champ de payload personnalisé. Préfixez avec `fw_*` tout ce qui est spécifique au framework ; un nom qui entre en conflit avec un champ déclaré est refusé plutôt que d'écraser silencieusement une colonne promue. + + + + + **`duration_ms` est calculé, pas accepté.** Les quatre méthodes de fermeture mesurent l'écart depuis leur ouvreur et refusent un `duration_ms` fourni par l'appelant — une durée déclarée ne peut pas être falsifiée. + + Les paires sont associées sur la **session** et l'identifiant, jamais sur l'agent. Un outil ouvert sous `planner` et fermé sous `worker` forme quand même une paire, ce que font effectivement les exécutions multi-agents imbriquées. + + +## Adaptateurs de framework + +```ts +await failproofai.instrument(); // whatever it can find +await failproofai.instrument("langchain"); // exactly one +failproofai.uninstrument(); // put everything back +``` + +| Framework | Supporté | Comment il s'attache | +| --- | --- | --- | +| **LangChain.js / LangGraph.js** | `@langchain/core` 0.3 – 1.x, LangGraph.js 0.4 – 1.x | `CallbackManager.configure`, donc chaque `invoke`/`stream`/`batch` est couvert sans passer `callbacks:` nulle part — ou passez `langchainHandler()` vous-même sans rien patcher. | +| **Vercel AI SDK** | `ai` 4 – 7 | `telemetry()` au site d'appel, ou `instrument("ai")` pour tout le processus sur `ai` 7 (sur 4–6, c'est opt-in — voir ci-dessous). | +| **Mastra** | `@mastra/core` 0.20 – 1.x | `Agent.generate`/`.stream`, le modèle de l'agent et la résolution des outils, ainsi que le moteur d'exécution de workflow run/step. | +| **LlamaIndex.TS** | `llamaindex` 0.11.4 – 0.x | `Settings.callbackManager` (abonné) plus `AgentWorkflow.runStream`, pour les exécutions de workflow et leurs étapes. | + +Chaque plage est testée contre de vraies versions de framework, aux deux extrémités, en tant que module ES et CommonJS, à chaque exécution CI. + +Le mapping est celui du SDK Python, donc le même programme dessine le même arbre dans les deux langages. Un élément est un **agent** uniquement s'il possède une boucle de décision LLM — un graphe ou une exécution de chaîne, un appel `generateText`/`streamText` de l'AI SDK, un agent Mastra, une exécution d'agent LlamaIndex. Un nœud LangGraph ou une étape de workflow est un **hook** (`hook_triggered`/`hook_completed`), jamais un agent imbriqué. Les appels modèle sont des paires `model_request`/`model_response` avec les comptages de tokens ; les appels d'outils portent l'identifiant d'appel d'outil propre au modèle. Un échec est enregistré une seule fois, sur l'événement où il s'est produit. + +Un adaptateur qui échoue à s'installer est journalisé et ignoré ; les autres s'installent quand même, car un LlamaIndex défaillant ne doit pas vous coûter LangGraph. + + + `instrument()` sans argument détecte un framework selon qu'il **se résout**, pas selon qu'il est déjà importé — Node n'expose pas d'équivalent de `sys.modules` de Python pour les modules ES. Un framework que vous avez installé mais n'utilisez pas sera importé et patché. Nommez celui que vous voulez si cela a de l'importance. + + + + La plupart de ces frameworks livrent un build ES module et un build CommonJS, que Node charge comme deux copies indépendantes. Les adaptateurs patchent la copie que charge votre application (et la copie CommonJS également si quelque chose a déjà fait un `require`), donc les deux systèmes de modules fonctionnent. Un framework **bundlé dans votre propre sortie** par esbuild ou webpack est hors de portée — utilisez les helpers au site d'appel : `langchainHandler()`, `telemetry()`, `wrapTool()`. + + +### LangChain sans patching + +```ts +import { langchainHandler } from "@failproofai/sdk/langchain"; +await graph.invoke(input, { callbacks: [langchainHandler()] }); +``` + +Le handler fonctionne avec ou sans `instrument()` et n'enregistre jamais en double. `instrument("langchain")` accepte `sessionId`, `captureContent`, `includeChains`, `graphCallbacks` et `captureLimit`, comme l'adaptateur Python ; `metadata: { failproofai_sdk_session_id }` sur un appel sélectionne la session pour cette invocation. + +### Vercel AI SDK + +L'AI SDK exporte des fonctions simples depuis un module ES, et un namespace de module ES est immuable par spécification — il n'y a nulle part où patcher. Il utilise les points d'extension que le SDK lui-même documente : + +```ts +import { telemetry } from "@failproofai/sdk/ai"; + +const { text } = await generateText({ + model, + prompt, + experimental_telemetry: telemetry({ functionId: "answer-question" }), + // on ai 7, `telemetry: telemetry({ … })` — the same object, the new name +}); +``` + +C'est l'intégration complète : une span d'agent, une paire model request/response par étape avec les comptages de tokens, et chaque appel d'outil. Un seul site d'appel fonctionne sur chaque version majeure — `ai` 4–6 lit le tracer qu'il porte, `ai` 7 l'intégration de télémétrie. + +`instrument("ai")` fait la même chose à l'échelle du processus **sur `ai` 7** : chaque appel, via la liste d'intégrations de télémétrie globale de l'AI SDK, qui est additive et ne prend rien à personne d'autre. + +**Sur `ai` 4–6, `instrument("ai")` n'enregistre rien par lui-même, et journalise un avertissement en ce sens.** Le seul hook à l'échelle du processus que ces versions majeures possèdent est le fournisseur de tracer OpenTelemetry global — un slot unique qu'OpenTelemetry refuse de céder une fois pris. Enregistrer le nôtre refuserait silencieusement votre propre `NodeSDK.start()` ultérieur au démarrage et enverrait vos spans http/database vers un tracer qui n'exporte rien. Utilisez `telemetry()` au site d'appel ou `wrapModel` là. Si le processus ne fait tourner aucun OpenTelemetry propre, optez-en avec `instrument("ai", { registerGlobalTracer: true })` : il enregistre alors chaque appel qui passe `experimental_telemetry: { isEnabled: true }`, et ne prend le slot que s'il est encore libre. `registerGlobalTracer: false` conserve le comportement par défaut et réduit l'avertissement au silence. + +Si vous préférez wrapper le modèle une seule fois, `wrapModel` ne voit que les appels modèle, car les appels d'outils se produisent au-dessus de la couche modèle. Un modèle wrappé appelé sans rien autour est enregistré comme sa propre exécution. Un appel en streaming se ferme de la façon dont le stream s'arrête — `stop_reason: "cancelled"` quand le consommateur l'annule, `"error"` avec l'erreur quand il échoue en cours de route : + +```ts +import { wrapModel } from "@failproofai/sdk/ai"; +const model = await wrapModel(openai("gpt-4o")); +``` + +Utiliser les deux est correct : le middleware détecte que l'appel est déjà enregistré et se décharge, donc chaque appel est enregistré une seule fois. + +`functionId` nomme la span d'agent. Gardez-le à faible cardinalité — il atterrit dans `agent_id`, la facette principale du tableau de bord. + +### Next.js + +`next build` bundle les dépendances de votre serveur par défaut, et un framework bundlé dans le build est une copie que `instrument()` ne peut pas atteindre. Wrappez la config une fois et appelez `instrument()` depuis le hook de démarrage de Next : + +```ts +// next.config.ts +import { withFailproofai } from "@failproofai/sdk/next"; +export default withFailproofai({ /* your config */ }); +``` + +```ts +// instrumentation.ts +export async function register() { + if (process.env.NEXT_RUNTIME !== "nodejs") return; + const failproofai = await import("@failproofai/sdk"); + await failproofai.instrument(); +} +``` + +`withFailproofai` ajoute LangChain, Mastra, LlamaIndex et le SDK lui-même à `serverExternalPackages`, en conservant votre liste existante. Sans cela, `instrument()` avertit une fois par framework qu'il ne peut pas atteindre plutôt que d'échouer silencieusement ; si vous listez les packages vous-même, définissez `FAILPROOFAI_NEXT_EXTERNALS=1`. Le Vercel AI SDK et les helpers au site d'appel fonctionnent dans les deux cas. Une route Edge reçoit un build no-op : importer le SDK est sûr et n'enregistre rien. + +### Comptages de tokens sur les appels en streaming + +Les APIs compatibles OpenAI ne rapportent l'usage sur un stream que lorsque le client le demande. LangChain et le Vercel AI SDK le demandent ; pour LlamaIndex, passez `additionalChatOptions: { stream_options: { include_usage: true } }` à son LLM `OpenAI`, et pour Mastra construisez le modèle avec l'usage activé (par exemple `createOpenAICompatible({ includeUsage: true })`). Sinon, les appels modèle en streaming ne portent aucun comptage de tokens. + +### Runtimes + +Node ≥ 20.9, Bun et Deno — chaque framework, en module ES et CommonJS, est testé sur chacun par rapport à la trace de Node. Le SDK s'exécute aux côtés du daemon `failproofaid`, qui expédie ce qu'il écrit. + +## Votre propre agent — sans framework + +Pour une boucle d'agent que vous avez écrite vous-même, ou un framework sans adaptateur. Vous émettez les événements avec la même API que les adaptateurs utilisent en dessous, donc la trace a la même forme et la même qualité. + +Vous n'avez pas besoin de savoir comment l'agent est organisé. Tout agent fait à la main possède déjà trois endroits, quelles que soient les fonctions qu'il appelle, et ces trois constituent toute l'intégration : + +| Où | Quoi ajouter | Émet | +| --- | --- | --- | +| Là où **une exécution** commence et se termine | `failproofai.agent("name", { goal }, async () => …)` | `agent_start` / `agent_end` | +| La **fonction unique qui appelle le modèle** | `event.modelRequest` avant, `event.modelResponse` après — les deux moitiés, même en cas d'échec | une paire par tour de modèle | +| La **fonction unique qui exécute les outils** | `failproofai.toolCall(name, { toolCallId, input }, () => run())` | `tool_use` / `tool_result` | + +```ts +async function callModel(messages) { + const requestId = randomUUID(); + const started = Date.now(); + failproofai.event.modelRequest({ model: MODEL, requestId, messages }); + try { + const reply = await client.chat.completions.create({ model: MODEL, messages, tools }); + failproofai.event.modelResponse({ + model: reply.model, requestId, stopReason: reply.choices[0].finish_reason, + inputTokens: reply.usage?.prompt_tokens, outputTokens: reply.usage?.completion_tokens, + duration_ms: Date.now() - started, + }); + return reply.choices[0].message; + } catch (error) { + failproofai.event.modelResponse({ model: MODEL, requestId, stopReason: "error", + error: String(error), duration_ms: Date.now() - started }); + throw error; + } +} + +async function dispatch(call) { + const input = JSON.parse(call.function.arguments); + return failproofai.toolCall(call.function.name, { toolCallId: call.id, input }, + () => runTool(call.function.name, input)); +} + +await failproofai.agent("inventory", { goal: question }, async () => { + for (;;) { + const message = await callModel(messages); + if (!message.tool_calls?.length) return message.content; + for (const call of message.tool_calls) await dispatch(call); + } +}); +``` + +L'identité est ambiante : tout ce qui est à l'intérieur d'`agent()` atterrit sur la session de cette exécution sans prendre d'identifiant, et rien d'autre dans le programme ne change — y compris ce que l'agent écrit déjà dans sa propre base de données. + +- **Un service ou un worker :** passez votre propre identifiant de requête ou de job comme `sessionId`, afin qu'une session sur le tableau de bord et l'enregistrement dans vos propres logs ou base de données soient la même chaîne. +- **Sous-agents :** imbriquez les appels `agent()`. Le plus intérieur rejoint la session avec le plus extérieur comme `parent_id`. +- **Émettez les paires.** Un `modelRequest` sans `modelResponse` est une span que le tableau de bord affiche comme s'exécutant indéfiniment — d'où le `catch`. + +[`sdk/typescript/examples/research-agent.ts`](https://github.com/FailproofAI/failproofai/blob/main/sdk/typescript/examples/research-agent.ts) dans le dépôt est la version complète et exécutable : une vraie boucle d'outils OpenAI instrumentée exactement comme ceci, exécutée en CI à chaque changement en tant que module ES et CommonJS. + +## Évaluations + +```ts +import { Evaluator, EvalResult, Score } from "@failproofai/sdk/evaluator"; + +export const app = new Evaluator({ name: "my-evals", version: "1" }); + +app.eval("tool_success_rate", { version: "1" }, (session) => { + const results = session.eventsOfType("tool_result"); + const failures = results.filter((event) => event.payload.error != null).length; + return new EvalResult({ + score: new Score(results.length === 0 ? 1 : 1 - failures / results.length), + reasoning: `${failures} of ${results.length} tool calls failed`, + }); +}); +``` + +```bash +FAILPROOFAI_EVALUATOR_URL=… FAILPROOFAI_EVALUATOR_TOKEN=… \ + npx failproofai-evaluator ./my-evals.js +``` + +Consultez la [référence du SDK Evaluator](/fr/reference/evaluator-sdk) pour le protocole, les paramètres du worker et les types de résultats. + + + **Une évaluation doit céder la main.** Une fonction synchrone qui ne retourne jamais bloque l'unique thread de Node, et aucun timeout ne peut se déclencher pendant ce temps. Écrivez des évaluations `async`. + + +## Ce qu'il ne fera pas à votre processus + +| | | +| --- | --- | +| **Bloquer votre boucle agent** | Les événements vont dans une file en mémoire ; un timer les écrit. Le timer est `unref`'d, donc importer ce package n'empêche jamais un script de se terminer. | +| **Croître sans limite** | La file est plafonnée par le nombre *et* par les octets mesurés. Au-delà de l'un ou l'autre, les événements les plus anciens sont supprimés et un avertissement le signale — une panne de télémétrie ne doit pas devenir un kill OOM. | +| **Faire tomber le processus** | Un événement non encodable est supprimé seul, pas le lot autour de lui. Un getter qui lève, une référence circulaire, un `BigInt`, un surrogate isolé : chacun est géré plutôt que propagé. | +| **Laisser un lot à moitié écrit** | Le contenu est `fsync`é avant un renommage atomique, le répertoire est `fsync`é après, et un échec d'écriture nettoie son fichier temporaire. | +| **Laisser les transcripts lisibles** | Les lots sont en `0600` dans un répertoire `0700`. Ils portent des objectifs, des prompts, des arguments d'outils et des sorties d'outils. | +| **Expédier des credentials** | Les clés API, tokens, JWTs, headers bearer et assignations de forme secrète sont expurgés avant que les octets atteignent le disque. Le daemon expurge à nouveau avant l'upload. | \ No newline at end of file diff --git a/docs/fr/reference/jev-cloud.mdx b/docs/fr/reference/jev-cloud.mdx new file mode 100644 index 000000000..03f4ee676 --- /dev/null +++ b/docs/fr/reference/jev-cloud.mdx @@ -0,0 +1,136 @@ +--- +title: "Jev via FailproofAI Cloud" +description: "Clés machine Cloud, état de connexion, limites et comportement en cas d'échec pour la révision des politiques Jev en direct." +icon: "cloud" +--- + +Ceci est la référence de la route Cloud pour les [politiques Jev](/fr/policies/jev). Jev, le classificateur de TypeSafe, analyse chaque appel d'outil par rapport à ce que vous avez réellement demandé et répond en complément de vos politiques, jamais à leur place. Via **FailproofAI Cloud**, une machine connectée utilise Jev avec la même clé qu'elle utilise déjà pour se connecter : aucun compte TypeSafe, aucune deuxième clé, aucun point de terminaison à configurer. Chaque appel est débité sur l'allocation du plan existant de votre organisation. + +Tout ce que fait Jev reste inchangé par rapport à la [configuration avec votre propre clé](/fr/reference/jev-providers) : les politiques strictes restent définitives, le refus d'une politique révisable n'est levé que lorsque Jev a été interrogé précisément sur cette préoccupation, et toute défaillance revient au résultat du regex pour cet appel. + + +Nécessite **failproofai 1.0.8-beta.0** ou une version ultérieure. La version 1.0.7 ne dispose pas de Jev, même si elle est classée au-dessus des betas 1.0.7. Sans configuration Jev, rien ne change : les hooks exécutent les politiques regex exactement comme avant. + + +## Avant de commencer + +Installez Failproof AI sur la machine où votre agent s'exécute et attachez ses hooks à un [harnais pris en charge](/fr/reference/harnesses). Si vous partez de zéro, suivez le [démarrage rapide](/fr/start/quickstart) jusqu'à l'installation des hooks. Vérifiez la CLI installée avec `failproofai --version` ; mettez-la à jour si elle est antérieure à Jev. Vous avez également besoin d'accéder à la page **Administration → Clés** de votre organisation pour créer une clé machine. + +Jev examine les appels d'outils nommés à la porte `PreToolUse` ou `PermissionRequest`. Il n'examine pas chaque événement d'une session. Pour voir Jev lever un refus de politique, vous avez besoin d'une politique installée marquée [révisable](/fr/policies/authority) ; tous les autres refus de politique restent définitifs. + +## Activation + +1. **Créez une clé avec Jev.** Dans le tableau de bord FailproofAI Cloud, ouvrez **Administration → Clés → Créer une clé** et choisissez le profil **machine**. Il accorde les trois permissions dont une machine a besoin : `events:add` (envoyer l'activité), `policies:pull` (recevoir les politiques) et `jev:evaluate` (Jev, débité sur le plan de votre organisation). Une clé ne peut pas porter `jev:evaluate` sans les deux autres. +2. **Connectez la machine** avec cette clé. Lisez son secret à usage unique à l'invite, puis exécutez la commande de configuration complète : + + ```bash + read -rs FAILPROOFAI_CLOUD_TOKEN && export FAILPROOFAI_CLOUD_TOKEN + failproofai config + ``` + + `failproofai config` installe le daemon, attache les hooks pour les CLI d'agents qu'il trouve, et connecte la machine. La variable d'environnement évite que la clé apparaisse dans les arguments de la commande et dans l'historique de votre shell. Si votre harnais a été installé ultérieurement, [attachez-le explicitement](/fr/start/quickstart). + + Si votre organisation fait tourner sa propre instance FailproofAI Cloud plutôt que la version hébergée, ajoutez son adresse : `--url https://` (ou exportez `FAILPROOFAI_CLOUD_URL`). Sans cela, la clé est vérifiée contre le service hébergé et la connexion échoue. Si le certificat de cet hôte provient d'une CA privée, installez la CA dans le magasin de confiance système de la machine (par exemple avec `update-ca-certificates`), pas seulement dans `NODE_EXTRA_CA_CERTS` : le daemon qui envoie les événements et récupère les politiques lit le magasin système. Consultez [Dépannage](/fr/reference/troubleshooting). + +C'est tout. La connexion stocke la clé et, lorsque la machine n'a **pas encore** de configuration Jev, active Jev via FailproofAI Cloud en mode **observe** : une fois qu'un pack lui fournit des vérifications, Jev est interrogé sur chaque appel d'outil soumis à contrôle et ses verdicts sont enregistrés, mais c'est le résultat de vos politiques qui est appliqué. La sortie l'indique : + +```text + Jev on through FailproofAI Cloud, in observe mode: logged, not enforced (~/.failproofai/jev.json). +``` + +Jev ne demande toujours rien tant qu'un pack ne lui fournit pas de vérifications. Failproof AI n'en fournit aucune ; tant qu'aucun pack installé n'en déclare, la sortie ajoute une ligne le précisant, et `failproofai jev status` le rappelle. Installez-les avec : + +```bash +failproofai policies add FailproofAI/jev-policies +``` + +**Avec `--no-transcripts`, la connexion n'active pas Jev.** Jev envoie chaque appel d'outil vérifié et l'invite récente à FailproofAI Cloud, ce qui représente plus qu'une connexion en mode décisions uniquement ne devrait envoyer. La clé est néanmoins stockée, et la sortie indique que Jev est disponible et comment l'activer : + +```bash +failproofai jev setup --provider failproofai +``` + +Cela ne désactive pas non plus Jev **si celui-ci est déjà actif**. Si le fichier `jev.json` de la machine fait déjà tourner Jev via FailproofAI Cloud, il est laissé tel quel, et la sortie indique que Jev continue d'envoyer chaque appel d'outil vérifié et l'invite récente, et que `failproofai jev setup --mode off` permet de le désactiver. + + +La connexion **n'écrase jamais** un `~/.failproofai/jev.json` existant. Si vous utilisez déjà votre propre point de terminaison Jev, il continue d'être utilisé, et la sortie indique que le fichier a été laissé tel que configuré — et, lorsque ce fichier laisse Jev désactivé (refusé ou désactivé manuellement), l'indique et explique comment y remédier. Pour basculer cette machine vers FailproofAI Cloud, exécutez `failproofai jev setup --provider failproofai`. + + +## Observe, enforce ou off + +Commencez en mode observe, observez ce que Jev aurait fait sur la page des politiques, puis laissez-le agir : + +```bash +failproofai jev setup --mode enforce # Les verdicts de Jev s'appliquent : il peut lever un refus révisable et ajouter les siens +failproofai jev setup --mode observe # Jev est interrogé et journalisé ; c'est le résultat de vos politiques qui est appliqué +failproofai jev setup --mode off # Conserve la configuration, cesse d'interroger Jev +``` + +Le même commutateur se trouve dans le tableau de bord local : **Settings → Jev** dispose d'un interrupteur on/off et observe/enforce. Il réécrit uniquement le mode. Les hooks lisent la configuration à chaque appel d'outil, donc un changement s'applique dès l'appel suivant, sans redémarrage. + +## Vérifier son fonctionnement + +```bash +failproofai jev status +failproofai jev test +``` + +`status` affiche le fournisseur en tant que **FailproofAI Cloud**, l'hôte Cloud auquel la machine est connectée, le mode, et la source de la clé comme **connexion FailproofAI Cloud**, jamais la clé elle-même. Lorsqu'un `jev.json` FailproofAI Cloud est en place mais que Jev ne peut pas s'exécuter, il en indique la raison : + +| `status` indique | `status --json` | Signification | +| --- | --- | --- | +| **off — no Jev key is stored for this machine's FailproofAI Cloud connection** | `key-lacks-jev` | La machine est connectée, mais aucune clé Jev n'y est stockée : la clé ne dispose pas de `jev:evaluate`, ou la connexion n'a pas pu le confirmer. Exécutez à nouveau `failproofai config` avec la clé dans `FAILPROOFAI_CLOUD_TOKEN` ; si elle ne dispose pas de la permission, utilisez une clé **machine**. | +| **off — this machine is not connected to FailproofAI Cloud** | `not-connected` | Il n'y a pas de connexion FailproofAI Cloud sur cette machine à laquelle la clé Jev pourrait appartenir. | + +Après `failproofai config --disconnect`, il n'y a plus de `jev.json` FailproofAI Cloud (sauf s'il était désactivé, ce qui est conservé), donc `status` indique simplement que Jev est désactivé. `status --json` contient les mêmes informations (`provider: "failproofai"`, `keySource: "cloud"`, `cloudConnected`, `keyCarriesJev`), y compris lorsque la configuration est absente ou refusée. `permissions` correspond toujours à celui de `jev.json` ; un refus concernant `credentials.json` ajoute `credentialsPermissions`, et `fix` lorsqu'une commande suffit à y remédier. `test` envoie une requête réelle et rapporte sa latence et la version de Jev qui a répondu. Il quitte avec le code 1, et l'indique dans son titre, lorsque la réponse arrive après le délai d'expiration du hook (les hooks enregistreraient `timeout`) ou répond incorrectement à sa question de vérification. + +Le panneau **Settings → Jev** du tableau de bord affiche également la **connexion FailproofAI Cloud** : l'organisation dans laquelle la machine est enregistrée et si sa clé porte Jev. Il est lu depuis les fichiers propres à la machine, sans appel réseau. + +## Vérifier un appel réel + +Démarrez une nouvelle session dans l'agent avec hooks. Demandez-lui d'utiliser son outil de lecture de fichiers sur `README.md` et de rapporter le titre. Confirmez que la session contient cet appel d'outil, puis exécutez à nouveau `failproofai jev status` : son compteur d'appels évalués récents devrait augmenter. Ouvrez **Policies → Activity** dans le [tableau de bord local](/fr/reference/local-dashboard#review-policy-activity) pour inspecter le verdict Jev et le mode de cet appel. Dans Cloud, la page **Policies** de l'organisation affiche les résultats Jev pour l'activité livrée. En mode observe, le verdict est enregistré comme **would-have** et c'est le résultat de la politique qui décide de l'appel. Une levée de refus n'apparaît que lorsqu'une politique révisable correspond et que Jev a levé ses vérifications nommées. + +## Ce qui parvient à la page des politiques + +La machine envoie déjà son activité de hook à FailproofAI Cloud (`events:add`). Avec Jev activé, l'enregistrement de chaque appel soumis à contrôle indique également quel évaluateur a tourné, ce que Jev a décidé, quelles politiques il a levées, pourquoi il est revenu en arrière le cas échéant, sa latence et le modèle qui a répondu — décisions, codes et noms, jamais la commande ni votre invite. Sur la page **Policies** de votre organisation : + +- un appel dont le résultat a été décidé par le verdict propre de Jev (mode enforce) est attribué à **Jev**, et lorsque la vérification déterminante provient d'un pack, l'enregistrement nomme également ce pack et sa version ; +- en mode observe, le refus ou l'avertissement de Jev apparaît comme **would-have**, à côté des déploiements que vous observez ; +- les politiques que Jev a levées, ou aurait levées en mode observe, sont comptabilisées par politique. + +## Quand Jev ne peut pas répondre + +Chacun de ces cas revient au résultat de vos politiques pour cet appel, et est enregistré avec sa raison : + +| Raison | Cause | +| --- | --- | +| `out-of-credits` | Votre organisation a épuisé l'allocation de son plan. | +| `http-401`, `http-403` | La clé a été révoquée, ou ne porte pas `jev:evaluate`. Reconnectez-vous avec une clé qui le porte. | +| `http-429` | FailproofAI Cloud limite le débit de Jev pour votre organisation. Jusqu'à la fin du délai demandé (son `Retry-After`, au maximum 60 secondes), la machine ne lui envoie rien et chaque appel revient immédiatement en arrière. Les appels retenus de cette façon sont enregistrés comme `http-429`, ou comme `rate-limited` lorsque la limite de débit propre à la machine les retient en premier. | +| `http-429` (limite quotidienne) | Votre organisation a utilisé ses appels Jev quotidiens : **10 000 par jour UTC**, sauf si l'opérateur de votre FailproofAI Cloud a défini une autre limite. Chaque appel revient en arrière jusqu'à la réinitialisation du compteur à 00:00 UTC ; la machine redemande néanmoins au plus une fois par minute, donc elle détecte la réinitialisation en moins d'une minute. `failproofai jev test` affiche « Daily Jev limit for this org reached; resets at 00:00 UTC. » | +| `http-422` | Jev a refusé la requête de cet appel, généralement parce que l'appel d'outil contenait du texte dense (base64, hexadécimal, code minifié) dépassant le budget de tokens de Jev. Cet appel revient en arrière à chaque fois ; ce n'est pas une panne. | +| `http-502` | Jev est actuellement indisponible. | +| `http-503` | Ce Cloud ne peut pas servir Jev pour votre organisation : pas de passerelle de modèle, une organisation pas encore provisionnée, ou la passerelle est hors service. Contactez votre administrateur ; les hooks redemandent au plus une fois par minute. | +| `http-404` | Ce FailproofAI Cloud ne sert pas encore Jev. | +| `timeout` | Aucune réponse dans le délai `timeoutMs` (3000 par défaut). | +| `model-mismatch` | Une version de Jev autre que 1.13 a répondu. | + +## Où vit la clé et où elle va + +- La clé est stockée une seule fois, dans `~/.failproofai/credentials.json` (`0600`, dans un répertoire réservé au propriétaire), aux côtés des autres identifiants FailproofAI Cloud. `jev.json` ne contient aucune clé pour cette route ; une clé écrite là rend la configuration invalide. +- Si `credentials.json` accorde **une quelconque** permission à quelqu'un d'autre que vous (groupe ou autre, lecture ou écriture), ou si son répertoire peut être **écrit** par quelqu'un d'autre que vous, il est **refusé**, non lu, et Jev est désactivé jusqu'à ce que vous corrigiez cela : `chmod 600` sur le fichier, `chmod 700` sur le répertoire (ou reconnectez-vous, ce qui réécrit le fichier en `0600` et rend le répertoire réservé au propriétaire). Un répertoire que d'autres peuvent seulement lire est acceptable ; un répertoire qu'ils peuvent écrire leur permet de substituer le fichier. +- La clé ne compte que tant que la connexion avec laquelle elle est arrivée est présente sur la machine : un identifiant de politique ou de rapport pour le même FailproofAI Cloud **avec la même clé**, dans le même fichier. Une clé Jev laissée sans l'une d'elles est ignorée, et Jev reste désactivé. Cela se produit lorsque la commande `config --disconnect` d'une ancienne version de failproofai laisse la clé Jev en place (elle ne sait pas qu'il faut la supprimer), ou lorsque la commande `config --token` d'une ancienne version de failproofai se connecte avec une autre clé, qui sur FailproofAI Cloud peut appartenir à une autre organisation. Pour réactiver Jev, connectez-vous à nouveau avec une clé **machine**. +- La clé n'est envoyée qu'à l'origine Cloud contre laquelle elle a été vérifiée. Un `jev.json` pointant ailleurs est refusé. +- **Un agent sur la machine peut la lire.** `credentials.json` est réservé au propriétaire, et l'agent s'exécute en tant que ce propriétaire. La lecture des fichiers propres à failproofai est autorisée intentionnellement (seule leur modification est bloquée, par `block-failproofai-commands`), donc la seule protection entre un agent et ce fichier est `block-read-outside-cwd` — une politique *révisable* — et depuis une session démarrée dans votre répertoire personnel, rien. Une clé avec `jev:evaluate` dépense l'allocation Jev de votre organisation (jusqu'au plafond quotidien) depuis où qu'elle soit utilisée, donc traitez une clé machine comme tout autre identifiant de dépense : si un agent a pu la lire, désactivez-la sur la page Clés et reconnectez-vous avec une nouvelle. +- Seuls vos fichiers globaux décident de cela. Un dépôt ne peut pas activer Cloud Jev, le pointer ailleurs ni fournir sa clé, et `FAILPROOFAI_JEV_API_KEY` est ignoré pour cette route. +- Pour chaque appel évalué par Jev, une requête est envoyée à FailproofAI Cloud, contenant ce que la [page bring-your-own-key](/fr/reference/jev-providers#what-leaves-the-machine) liste (secrets expurgés). FailproofAI Cloud la transmet à TypeSafe et ne la journalise ni ne la conserve. + +## Désactivation + +| Commande | Résultat | +| --- | --- | +| `failproofai jev setup --mode off` | Conserve la configuration ; Jev n'est pas interrogé. **C'est le commutateur qui persiste :** une nouvelle connexion ne réécrit jamais un `jev.json` existant, donc Jev reste désactivé jusqu'à ce que vous le réactiviez avec `--mode observe`. | +| `failproofai jev remove` | Supprime `~/.failproofai/jev.json` ; Jev est désactivé — jusqu'à la prochaine commande `failproofai config --token` avec une clé portant `jev:evaluate`, qui ne trouvant pas de `jev.json` réactive Jev en mode observe (sauf si elle s'exécute avec `--no-transcripts`). Pour le maintenir désactivé, utilisez `--mode off`. | +| `failproofai config --disconnect` | Déconnecte la machine : la clé est supprimée, ainsi que `jev.json` lorsqu'il désigne FailproofAI Cloud et n'est pas désactivé. Un `jev.json` pour votre propre point de terminaison est conservé, de même qu'un `jev.json` désactivé, donc Jev reste désactivé lorsque vous vous reconnectez. | + +Dès l'appel d'outil suivant, les hooks exécutent les politiques regex exactement comme avant. \ No newline at end of file diff --git a/docs/fr/reference/jev-evaluations.mdx b/docs/fr/reference/jev-evaluations.mdx new file mode 100644 index 000000000..dbcb4d42a --- /dev/null +++ b/docs/fr/reference/jev-evaluations.mdx @@ -0,0 +1,88 @@ +--- +title: "Référence d'évaluation Jev" +description: "Types de questions, scores calibrés, limites et remplissage rétroactif pour les évaluations de session Jev." +icon: "list-checks" +--- + +Cette page décrit les formes de questions et les règles de notation qui sous-tendent les [évaluations Jev](/fr/evaluations/jev). Certaines questions nécessitent qu'un modèle *lise* la conversation, mais pas qu'il *écrive* à son sujet. « Le client a-t-il exprimé une urgence ? » admet deux réponses. « À quel point était-il frustré ? » en admet quelques-unes, dans un ordre précis. Vous connaissez toutes les réponses avant même de poser la question. + +Une **évaluation par classificateur** est faite exactement pour ces cas. Vous rédigez la question et les réponses possibles, et un petit modèle conçu pour la classification renvoie un nombre calibré — jamais du texte libre. + + +Comme un juge, une évaluation par classificateur coûte un appel de modèle par session. Contrairement à un juge, il s'agit d'un petit modèle dédié à une seule tâche plutôt qu'un modèle généraliste — ce qui le rend plus rapide et moins coûteux —, mais il ne s'expliquera jamais. Si vous avez besoin du raisonnement, utilisez un [juge](/fr/evaluations/judge). + + +## Lequel choisir ? + +| Question | À utiliser | +| --- | --- | +| Combien d'appels d'outils y a-t-il eu ? | code | +| La session a-t-elle duré moins de 30 secondes ? | code | +| Le client a-t-il exprimé une urgence ? | **classificateur** | +| Quelle équipe devrait gérer ceci : facturation, technique ou ventes ? | **classificateur** | +| À quel point le client était-il frustré ? | **classificateur** | +| La réponse était-elle vraiment correcte ? | **juge** | +| A-t-il suivi notre politique d'escalade, et pourquoi pensez-vous cela ? | **juge** | + +La règle empirique : **dénombrable → code, réponses listables → classificateur, nécessite une explication → juge.** + +Vous n'avez pas à décider à l'avance. Décrivez ce que vous voulez mesurer et l'assistant choisit, vous indique ce qu'il a choisi et pourquoi, et vous pouvez changer d'avis. + +## Les deux types de questions + +### `noul` — est-ce vrai ? + +Deux réponses, et vous décrivez les deux. Le résultat est la probabilité que la description « vraie » corresponde : + +```json +{ + "instructions": "Did the assistant promise a refund without first checking the refund policy?", + "criteria": { + "true": "A refund was promised or issued with no prior policy check or approval", + "false": "No refund was promised, or every refund followed a policy check" + } +} +``` + +Décrivez les deux côtés. « Aucune urgence exprimée » est une vraie réponse, et la préciser rend l'autre plus nette. + +### `score` — dans quelle mesure ? + +Un barème ordonné, **du pire au meilleur**. Le résultat indique où la session se situe sur ce barème, remis à l'échelle de 0 à 1 : + +```json +{ + "instructions": "How frustrated is the customer?", + "criteria": ["Calm", "Frustrated", "Very angry"] +} +``` + +**Un barème comporte de trois à cinq niveaux, tous distincts.** Les deux limites sont mesurées, pas stylistiques : + +- **Deux niveaux** revient à faire ce que `noul` fait déjà mieux, et **plus de cinq** pousse le modèle à se réfugier vers le centre au lieu de trancher. La même question sur la même session a obtenu 0,00 avec deux niveaux, 0,01 avec trois, et 0,55 avec dix. +- **Des niveaux répétés** divisent arbitrairement la réponse entre eux. Une session indéniablement en colère a obtenu 1,00 avec `["Calm", "Frustrated", "Very angry"]` et 0,66 avec `["Angry", "Angry", "Angry"]` — un nombre bien formé qui ne signifie rien. + +Les catégories sans ordre — « facturation, technique ou ventes » — ne constituent pas un barème. Posez-les comme une question `noul` par catégorie, ou utilisez un juge. + +## Interprétation des résultats + +Un classificateur produit un **score** de 0 à 1, exactement comme un juge, et il apparaît dans les graphiques, les filtres et les alertes de la même façon. Deux différences méritent d'être notées : + +- **Il n'y a pas de raisonnement.** Le champ est vide, délibérément. Ce modèle ne s'explique pas, et inventer une explication serait une fabrication plutôt qu'une fonctionnalité. +- **L'incertitude est étiquetée.** Une question de type `score` rapporte sa propre confiance, et un résultat sur lequel le modèle était incertain est marqué `low_confidence` — ainsi, « lesquels devraient être examinés par un humain » est un filtre, pas une supposition. Une question de type `noul` ne rapporte pas la confiance, donc elle n'est jamais étiquetée. + +Les sessions très longues sont lues par extraits et combinées. Quand une session est trop longue pour être lue en entier, le résultat indique combien de tours ont été omis — vous ne verrez jamais un jugement rendu sur une partie d'une session présenté comme s'il portait sur la totalité. + +## Limites + +- **De trois à cinq niveaux de barème, tous distincts.** Voir ci-dessus ; les deux bornes sont vérifiées au moment de la rédaction. +- **Une seule question par évaluation.** Posez deux questions et vous obtenez deux évaluations, ce qui est aussi ce que vous souhaitez sur un graphique. +- **Modifier la question publie une nouvelle version.** Les anciens et nouveaux scores ne sont pas comparables, ils sont donc conservés séparément plutôt que mélangés dans une même courbe de tendance. +- **Un classificateur produit toujours un score**, jamais une métrique ni une assertion. +- **Pas de raisonnement**, comme indiqué ci-dessus. Si un nombre amènera quelqu'un à demander « pourquoi ? », rédigez plutôt un juge. + +## Tests et remplissage rétroactif + +Contrairement à un juge, une évaluation par classificateur **peut** être testée avant son déploiement — [testez-la](/fr/evaluations/test) sur de vraies sessions de la même manière que vous le feriez pour une évaluation par code, et consultez les scores avant toute mise en production. + +Elle peut également être [appliquée rétroactivement](/fr/evaluations/deploy#score-sessions-you-already-have) aux sessions déjà existantes. Cela coûte un appel de modèle par session, alors délimitez la fenêtre temporelle délibérément plutôt que de tout rejouer. \ No newline at end of file diff --git a/docs/fr/reference/jev-intent.mdx b/docs/fr/reference/jev-intent.mdx new file mode 100644 index 000000000..190cad6f0 --- /dev/null +++ b/docs/fr/reference/jev-intent.mdx @@ -0,0 +1,112 @@ +--- +title: "Capture d'intention Jev" +description: "Quels événements harness indiquent à l'évaluateur Jev ce que l'utilisateur a demandé, quel champ contient le texte, ce qui n'est jamais comptabilisé, et le risque lié à la confiance accordée à un prompt fourni par le harness." +icon: "message-square-quote" +--- + +Lorsque vous configurez la [revue de politique Jev](/fr/policies/jev), l'évaluateur juge chaque appel d'outil contrôlé en fonction de **ce que l'utilisateur a demandé**, et non du texte que le harness a soumis à l'agent. Une réponse telle que « oui, force-push-le » peut lever une politique **reviewable** — c'est précisément l'objet de l'évaluateur, puisqu'une regex incapable de lire la requête bloque un tiers des tâches réelles. + +Ce texte provient d'un seul endroit : **le prompt que le harness lui-même transmet au hook lors de son événement de soumission de prompt**. Failproof AI enregistre la partie tapée par l'utilisateur — habillage harness supprimé, secrets expurgés, taille limitée — dans un fichier `0600` dans son propre répertoire d'état. Rien sur le disque n'est consulté : la transcription de session est un fichier que l'agent peut réécrire en une seule commande, aussi on ne lui demande jamais qui a rédigé un prompt. + +## Le risque accepté, clairement exposé + +Un agent qui peut déjà exécuter des commandes peut faire soumettre un prompt à un harness. `claude -p "…"`, `codex exec`, `copilot -p`, `cursor-agent -p`, `devin -p`, `droid -p`, `goose run -t` et `pi -p` déclenchent tous le même événement de soumission de prompt, avec le même payload, qu'une personne en train de taper, dans une session enfant que cet agent contrôle. L'agent peut également exécuter le binaire hook propre à Failproof AI et lui fournir un payload qu'il a lui-même rédigé. Rien dans Failproof AI ne peut distinguer l'un de l'autre du cas réel — les deux sont le même programme lisant le même stdin. + +**Ainsi, un agent disposant d'un shell peut forger son propre consentement.** Il s'agit d'un compromis délibéré, acté le 23 septembre 2026, dont voici les deux facettes : + +- **Ce que cela apporte.** L'alternative a été construite et mesurée : exiger un champ dans lequel le harness désigne un humain comme auteur du prompt, et ne rien enregistrer sinon. Aucun harness livré ne transmet un tel champ, si bien que cette version n'enregistrait **rien, sur chaque harness** — Jev jugeait chaque appel sans intention déclarée et ne pouvait jamais lever une seule politique. Une capture qui ne se déclenche jamais n'est pas un produit plus sûr, c'est un non-produit. +- **Ce que cela ne peut pas faire.** Un prompt enregistré ne peut lever qu'une politique marquée **reviewable**. Une politique **hard** n'est jamais levée par quoi que ce soit que Jev déclare, donc un prompt forgé ne peut jamais transformer un deny hard en allow — et contourner le hook ne rapporte rien à l'agent non plus : le harness invoque Failproof AI pour l'appel d'outil de manière indépendante. +- **Ce que cela peut faire, à pleine échelle.** Le pire qu'il puisse faire est de lever l'une des quinze politiques intégrées reviewable — et **douze de ces quinze bloquent**. `protect-env-vars`, `block-env-files`, `block-read-outside-cwd`, `block-rm-rf`, `block-force-push`, `block-secrets-write` et les six blocs CLI d'infrastructure (`block-kubectl`, `block-terraform`, `block-aws-cli`, `block-gcloud`, `block-az-cli`, `block-helm`) sont des denies, donc un consentement forgé peut transformer un deny réel en allow pour l'impression des secrets d'environnement, la lecture d'un fichier `.env`, la lecture hors du projet, `rm -rf`, un force-push, l'écriture d'un fichier de secrets, ou la modification d'une infrastructure en production. Seuls `warn-git-amend`, `warn-destructive-sql` et `warn-global-package-install` sont des avertissements. Une installation par défaut active deux des douze : `protect-env-vars` et `block-env-files` ; les dix autres ne s'appliquent qu'à une machine où quelqu'un les a activés. Ce qu'aucun prompt n'atteint, c'est tout ce qui est hard — `block-sudo`, `block-curl-pipe-sh`, `block-push-master`, `block-work-on-main`, le garde-fou qui empêche un agent de désactiver Failproof AI, et chaque autre intégré non marqué reviewable. [L'autorité de politique](/fr/policies/authority) liste les quinze politiques et ce par quoi chacune est revue. + +Ce qui est toujours refusé est tout ce qui est facile à vérifier et qu'un agent ne peut pas obtenir simplement en demandant : un tour que le payload du harness lui-même marque comme soumis par une machine, un payload désignant un sous-agent, un identifiant de session qui n'est pas un nom simple, un événement qui n'est pas l'événement de soumission de prompt, et un texte qui ne contient que de l'habillage harness — y compris les mots de stop-gate propres à Failproof AI, que plusieurs harnesses renvoient comme prochain tour utilisateur. + +## Tableau par harness + +« Champ texte » désigne le champ du payload stdin après la normalisation par harness effectuée par Failproof AI. « Enregistré » indique si le prompt est conservé comme requête de l'utilisateur. + +| Harness | `--cli` | Événement prompt → canonique | Champ texte | Enregistré | Dernier message de l'agent lu depuis | +| --- | --- | --- | --- | --- | --- | +| Claude Code | `claude` | `UserPromptSubmit` | `prompt` | Oui, sauf si le `source` du payload désigne un tour que personne n'a soumis (`loop_wakeup`, `schedule_wakeup`, `poll_event`, `system`). `user`, `sdk`, une valeur inconnue et un build qui n'envoie pas de `source` du tout sont tous enregistrés | la transcription de session (`transcript_path`) | +| Codex | `codex` | `user_prompt_submit` → `UserPromptSubmit` | `prompt` | Oui | le JSONL de rollout (`agent_message`, `AgentMessage`) | +| GitHub Copilot CLI | `copilot` | `UserPromptSubmit` | `prompt` | Oui | `events.jsonl` (`assistant.message`) | +| Cursor | `cursor` | `beforeSubmitPrompt` → `UserPromptSubmit` | `prompt` | Oui, avec le wrapper `` retiré quand il constitue l'intégralité du prompt | le JSONL de transcription agent | +| OpenCode | `opencode` | `message.updated` (rôle user) → `UserPromptSubmit` | `prompt` | Oui — mais OpenCode actuel ne transporte aucun texte dans cet événement, donc en pratique rien n'est enregistré ; la répétition d'un même message est enregistrée une seule fois | aucun (les sessions sont SQLite) | +| Pi | `pi` | `input` → `UserPromptSubmit` | `prompt` | Oui, sauf si `input_source` vaut `extension` — le `sendUserMessage()` d'une autre extension, dont le texte peut être généré par le modèle ou dérivé du dépôt | le JSONL de session Pi | +| Hermes | `hermes` | aucun | — | Non — Hermes n'a aucun événement de soumission de prompt | — | +| OpenClaw | `openclaw` | `before_agent_run` → `UserPromptSubmit` | `prompt` | Oui, sauf si les métadonnées du run marquent le run comme étant celui d'une machine : un `trigger` autre que `user`, un `inputProvenance.kind` autre que `external_user`, ou `senderIsOwner: false` | aucun (`before_agent_run` ne transporte pas de chemin de transcription) | +| Factory Droid | `factory` | `UserPromptSubmit` | `prompt` | Oui | le JSONL de session droid | +| Devin CLI | `devin` | `UserPromptSubmit` | `prompt` | Oui | aucun (les sessions sont SQLite) | +| Antigravity CLI | `antigravity` | `PreInvocation` → `UserPromptSubmit` | aucun | Non — `PreInvocation` se déclenche avant *chaque* appel de modèle dans un tour et ne transporte aucun texte de prompt | — | +| Goose | `goose` | `UserPromptSubmit` | `message` | Oui | aucun (les sessions sont SQLite) | + +Deux harnesses n'enregistrent rien, et pour la même raison dans les deux cas : leur événement ne transmet aucun texte humain. Hermes n'a pas d'événement de soumission de prompt — son plugin natif gère lui-même `pre_llm_call` et ne transmet que des événements d'outil, de session et de sous-agent. Le `PreInvocation` d'Antigravity se déclenche avant chaque appel de modèle, lors d'un tour humain comme lors des cinq qui suivent, et ne porte aucun champ prompt ; les hooks peuvent également injecter des étapes `userMessage` dans la même conversation. Il n'y a rien dans ces événements à enregistrer. + +## Ce qui fait qu'un prompt est celui de l'utilisateur + +1. **L'événement.** Failproof AI a été invoqué pour l'événement de soumission de prompt du harness, que le gestionnaire canonicalise en `UserPromptSubmit`. +2. **Le payload.** Le harness l'écrit sur le stdin du hook, et il transporte le texte dans le champ nommé ci-dessus. Un appel qui atteint Failproof AI sans le payload n'enregistre rien. +3. **Rien dans le payload n'exclut le tour.** Un payload qui désigne un sous-agent (`agent_id`) représente l'agent qui se prompt lui-même. Un `source`, `input_source` ou marqueur de run OpenClaw désignant un tour soumis par une machine est refusé. Un marqueur **absent** n'exclut rien — c'est là toute la différence avec la version qui n'enregistrait rien, puisque chaque marqueur ici est absent sur chaque build livré. +4. **Il reste quelque chose après suppression de l'habillage** (voir ci-dessous). + +**La transcription de session n'est pas une preuve de qui a rédigé un prompt.** Les versions précédentes de cette page décrivaient une vérification croisée avec la transcription : le prompt était refusé si la transcription montrait que le modèle l'avait planifié, et la transcription devait être la suite de celle vue lors du prompt précédent. Cette vérification a été supprimée. Une transcription est un fichier sur lequel l'agent dispose déjà d'un shell — elle peut être tronquée, remplacée, rembourée au-delà du budget de lecture, snapshotée au début d'un tour et restaurée à la fin, ou rendue cohérente avec des entrées que l'agent a rédigées. Chaque cycle de renforcement était suivi d'une nouvelle variante du même faux, de sorte que l'ensemble du mécanisme a été supprimé plutôt que réparé. + +La transcription est toujours lue pour une seule chose : **le dernier message visible de l'agent**. Ce message est, par définition, rédigé par l'agent, Jev en est informé, et il ne constitue jamais un consentement en lui-même. + +## Ce qui est conservé d'un prompt + +Les harnesses mettent bien plus que les mots de l'utilisateur dans un prompt. Avant tout enregistrement : + +- Les blocs `` sont supprimés, et les mots de l'utilisateur autour d'eux sont conservés. +- Un résumé de continuation de session (« Cette session est la continuation d'une conversation précédente… ») est entièrement supprimé. +- Les notifications de tâche, les sorties de commandes locales et les marqueurs d'interruption sont entièrement supprimés. +- Un tour rédigé par un autre agent ou une autre session est entièrement supprimé : Claude Code les enveloppe dans ``, ``, ``, `` ou ``. +- Les propres messages de Failproof AI sont entièrement supprimés. Un `MANDATORY ACTION REQUIRED from failproofai …` d'une stop gate ou un `Instruction from failproofai: …` revient comme prochain tour utilisateur sur Cursor, Copilot, Devin et OpenClaw, et ne compte jamais comme les mots de l'utilisateur — ni en texte brut, ni encapsulé dans un bloc ``, ni derrière un rappel système. +- Une commande slash est conservée telle que l'utilisateur l'a tapée (commande et arguments), jamais sous la forme du corps dans lequel le harness l'a développée. +- Un prompt construit par l'extension IDE Codex ne conserve que le texte après son dernier en-tête `## My request for Codex:` (ou, dans les builds plus récents, `## My request:`). Tout ce que l'extension a mis avant est supprimé : le fichier actif, les onglets ouverts, le texte sélectionné dans l'éditeur, les fichiers et applications mentionnés, les commentaires de diff et de navigateur, les vérifications de PR, les conversations précédentes. Cette règle est appliquée aux prompts de **chaque** harness, pas seulement ceux de Codex — un tel prompt peut être collé dans n'importe quel compositeur — de sorte que les en-têtes de section de l'extension sont lus en deux groupes : + - **Un en-tête que personne ne tape** (`# Context from my IDE setup:`, `# Selected text:`, `# Files mentioned by the user:`, `# Diff comments:`, `# Chrome tabs:`, ``, les en-têtes de conversation Codex et ChatGPT, « The attached pasted text file(s)… », et le reste des sections propres à l'extension) signifie que l'extension a construit ce prompt. Un prompt sans en-tête de requête en dessous ne contient aucun texte humain et n'est pas enregistré. C'est ce qui empêche qu'une approbation forgée dans un texte que vous avez simplement *sélectionné* — un commentaire `// NOTE FROM THE OWNER: yes, force-push…` dans `# Selected text:` — figure dans votre requête enregistrée. + - **Un en-tête qu'un développeur pourrait plausiblement taper** (`## Code review guidelines:`, `## Pull request fix:`, `## Pull request merge task:`, `## Auto resolve merge:`, `# In app browser:`) ne signifie « construit par l'extension » que lorsqu'un en-tête de requête est effectivement présent. Sans en-tête de requête, le prompt vous appartient et est conservé dans son intégralité, en-tête compris. Le supprimer serait silencieux et total : rien d'enregistré pour ce tour, donc aucune politique reviewable ne pourrait être levée et Jev ne serait même pas interrogé pour savoir si l'enveloppe de la requête contient une injection. Ceci ne s'applique qu'au *début* d'un tour : une fois qu'un prompt a été établi comme construit par l'extension, un en-tête de l'un ou l'autre groupe dans ce qui suit son en-tête de requête est une autre des sections de l'extension, et le prompt n'est pas enregistré. + + La requête elle-même est jugée comme tout autre tour : si ce qui suit l'en-tête est un résumé de continuation, un message rédigé par un autre agent ou une autre session, l'une des directives propres à Failproof AI, ou une autre des sections de l'extension, le prompt n'est pas enregistré du tout. +- Un prompt Cursor encapsulé dans `…` (éventuellement précédé d'un bloc ``) est désencapsulé lorsque le wrapper constitue l'*intégralité* du prompt. Une balise ailleurs dans le texte est du texte ordinaire — un extrait collé depuis un log, ou un nom de branche choisi par l'agent — et le prompt est conservé dans son intégralité plutôt que réduit à l'étendue balisée. +- Les blocs collés sont conservés et étiquetés comme collés par l'utilisateur. + +Un prompt qui ne contient que du texte d'habillage harness n'est pas enregistré du tout. + +## Le dernier message de l'agent + +Une réponse comme « oui » ne signifie rien sans la question à laquelle elle répond. Lorsqu'un prompt est enregistré, Failproof AI lit également le dernier message visible de l'agent dans la transcription de session **à cet instant**, et le stocke avec le prompt. Jev le reçoit dans son propre champ, étiqueté comme rédigé par l'agent : il permet d'interpréter une réponse courte et ne compte jamais en lui-même comme la requête de l'utilisateur. C'est la seule chose pour laquelle la transcription est lue, et le pire qu'une transcription réécrite puisse faire est de placer un message rédigé par l'agent là où un message rédigé par l'agent est attendu. + +Il est lu depuis la fin de la transcription, au maximum les 4 derniers Mo. Les formats de transcription pris en charge sont Claude Code, les rollouts Codex (anciens événements `agent_message` et nouveaux éléments `AgentMessage`), Cursor, Copilot `events.jsonl`, ainsi que les JSONL de session Pi, Factory et OpenClaw. Les messages synthétiques et d'erreur API propres à Claude Code, ainsi que les messages de sous-agent (sidechain), sont ignorés. Il n'y a pas de snapshot pour Goose et OpenCode, qui conservent les sessions en SQLite, pour Devin, dont la transcription est un unique document JSON, ni pour OpenClaw, dont l'événement `before_agent_run` ne transporte pas de chemin de transcription. + +## Stockage + +| Propriété | Valeur | +| --- | --- | +| Emplacement | `~/.failproofai/state/semantic/sessions/.json` | +| Permissions | fichier `0600`, répertoire `0700`. Chaque répertoire au-dessus, jusqu'à `~/.failproofai`, est soumis à la même règle que le répertoire de `jev.json` : un répertoire sur lequel un autre utilisateur peut **écrire** peut être renommé et remplacé ; le chemin de lecture retire donc ces bits d'écriture là où il le peut, et ne lit **rien** là où il ne le peut pas. Un prompt enregistré sera alors absent plutôt que forgé, et rien ne sera levé | +| Conservé par session | les 5 derniers prompts ; un prompt identique au précédent le remplace plutôt que d'occuper un nouvel emplacement | +| Fenêtre temporelle | les prompts de plus de 6 heures sont ignorés | +| Taille | chaque prompt et message d'agent est limité à 6 000 caractères, en conservant le début et la fin | +| Secrets | expurgés avec les mêmes patterns que les politiques `sanitize-*` avant tout enregistrement. Un texte de plus de 48 000 caractères est expurgé sous la forme de ses 28 800 premiers et 19 200 derniers caractères, et le texte adjacent aux coupures, où un secret aurait pu être scindé, n'est jamais stocké | + +Un identifiant de session contenant autre chose que des lettres, des chiffres, `.`, `_` et `-`, ou de plus de 128 caractères, n'est jamais utilisé comme nom de fichier, donc rien n'est enregistré pour lui. + +Un fichier de session n'existe qu'une fois qu'un prompt y a été enregistré. Il contient uniquement des prompts — aucun état d'origine, aucune marque de transcription — et il est supprimé une fois qu'il est resté silencieux plus longtemps que la fenêtre de six heures, lors de la prochaine écriture du premier prompt d'une nouvelle session. + +Rien n'est enregistré si aucun endpoint Jev n'est configuré. + +### La racine du projet + +« Dans le projet » — ce que `read-outside-workspace` et les autres vérifications de chemin jugent — désigne l'intérieur du projet dans lequel se trouvait la session lors de son **premier appel contrôlé**. La racine est fixée à ce moment-là et un `cd` ultérieur ne la déplace jamais ; un `cd` change toujours la façon dont un chemin relatif est résolu. Laisser la racine suivre le `cd` permettrait à `cd ~/.ssh` dans un appel de faire de `~/.ssh` le projet pour l'appel suivant. + +L'épingle est `~/.failproofai/state/semantic/roots/.json`, contenant `{root, at}` : fichier `0600`, répertoire `0700`, et la même règle d'identifiant de session que ci-dessus. Les fichiers de plus de 7 jours sont supprimés lorsqu'une nouvelle session fixe sa racine. Un répertoire `roots` sur lequel d'autres utilisateurs peuvent écrire est ignoré, et la racine du répertoire en cours est utilisée à la place. Pour réinitialiser l'épingle d'une session, supprimez son fichier. + +## Limitations connues + +- **Un prompt n'est fiable qu'à la mesure de l'invocation du hook.** Tout ce qui est décrit ici lit le payload que le harness a écrit sur le stdin du hook. Un agent capable d'exécuter des commandes peut exécuter le harness en mode headless (`claude -p` et les sept autres listés ci-dessus) ou exécuter lui-même le binaire hook de Failproof AI avec un payload qu'il a rédigé, et enregistrer un prompt que personne n'a tapé. C'est le compromis accepté décrit en haut de cette page : il ne lève que des politiques reviewable, jamais une politique hard — mais douze des quinze intégrées reviewable sont des denies, donc un prompt forgé peut transformer un vrai blocage en allow pour ces douze-là. +- **La détection de sous-agent est façonnée pour Claude.** Un payload portant `agent_id` n'est jamais enregistré, quel que soit le harness. C'est le champ qu'utiliseraient Claude Code, Factory Droid et Devin. Codex déclenche son événement prompt dans les threads de sous-agents, Copilot exécute des sidekicks en processus, Goose dispose d'un outil `delegate` et OpenClaw exécute des personas — aucun d'eux ne marque le payload d'une façon reconnue ici, donc un prompt de sous-agent sur ces harnesses est enregistré comme appartenant à la session. Le champ `openclaw.agentId` d'OpenClaw **n'est pas** cette marque : le plugin livré le définit sur chaque exécution, y compris celle du propriétaire. +- **Des planificateurs qui ne portent aucun marqueur.** Les `schedule_wakeup` et `loop_wakeup` de Claude Code, ainsi que les triggers `cron` et `heartbeat` d'OpenClaw, sont refusés parce que ces harnesses le précisent dans le payload. Le planificateur natif de Goose (`goose schedule add`) et le `codex exec` de Codex ne disent rien, donc une exécution qu'ils démarrent est enregistrée comme n'importe quelle autre. +- **Le dernier message d'un agent peut être un message que l'agent a choisi.** La transcription n'est pas authentifiée, donc un agent qui rédige sa propre transcription peut décider de ce que dit son « dernier message ». Il est étiqueté comme rédigé par l'agent et ne lève rien par lui-même — notez toutefois que le chemin v1 de `decide.ts` lui permet de satisfaire la vérification déterministe « l'utilisateur a-t-il nommé cette cible », de sorte qu'un agent qui contrôle sa transcription peut fournir un nom de cible dont un override a besoin. +- **Un prompt qui commence par l'un des en-têtes machine de l'extension est entièrement supprimé.** Commencez un prompt par `# Selected text:`, `# Diff comments:`, `# Chrome tabs:` ou un autre en-tête de section du premier groupe ci-dessus, et ne rédigez jamais d'en-tête `## My request:`, et rien n'est enregistré pour ce tour — donc rien n'est levé pour lui non plus. C'est délibéré : ces sections contiennent du texte que quelqu'un d'autre contrôle (du code que vous avez sélectionné, le commentaire de diff d'un relecteur, un titre de page), et enregistrer cela comme vos mots serait la pire erreur. Les en-têtes qu'un développeur pourrait plausiblement taper se trouvent dans le second groupe et ne suppriment jamais un prompt par eux-mêmes. +- **OpenCode n'enregistre rien en pratique.** Son événement `message.updated` ne transporte aucun texte dans OpenCode actuel, et il se déclenche également pour les sessions enfants créées par son outil de tâche, dont le message « user » est rédigé par l'agent parent. +- **`CODEX_HOME` n'est pas respecté** par la découverte de rollout dans `lib/codex-sessions.ts`. Cela n'affecte que l'endroit où un snapshot de message d'agent est recherché, jamais si un prompt est enregistré. \ No newline at end of file diff --git a/docs/fr/reference/jev-providers.mdx b/docs/fr/reference/jev-providers.mdx new file mode 100644 index 000000000..86651bcd3 --- /dev/null +++ b/docs/fr/reference/jev-providers.mdx @@ -0,0 +1,275 @@ +--- +title: "Fournisseurs Jev et configuration avec votre propre clé" +description: "Points de terminaison des fournisseurs, identifiants de modèles, configuration et comportement en cas d'échec pour la révision de politique Jev en direct avec votre propre clé." +icon: "key-round" +--- + +Ceci est la référence des fournisseurs et de la configuration pour les [politiques Jev](/fr/policies/jev) avec votre propre clé. Les politiques par expression régulière correspondent à des chaînes de caractères. Elles ne peuvent pas distinguer `rm -rf build/` que vous avez demandé de `rm -rf ~` qui s'est glissé dans un plan — elles bloquent donc trop à certains endroits et pas assez à d'autres. **Jev**, le classificateur de TypeSafe, analyse l'appel au regard de ce que vous avez réellement demandé et répond à un ensemble de questions oui/non à son sujet en une seule requête rapide. + +Avec votre propre point de terminaison et clé Jev configurés, Failproof AI interroge Jev sur chaque appel d'outil **en parallèle** des politiques par expression régulière, et non à leur place : + +- Le refus d'une politique **stricte** est définitif. Jev ne peut pas l'annuler. Toute politique est stricte sauf si elle est explicitement marquée comme révisable et nomme les vérifications Jev qui la couvrent ; ainsi, une politique personnalisée, de pack ou Cloud qui ne dit rien est stricte, et la protection automatique toujours active est toujours stricte. +- Le refus d'une politique **révisable** peut être annulé, mais uniquement si Jev a été interrogé sur la préoccupation exacte couverte par cette politique et a répondu « rien ici » ou « l'utilisateur l'a demandé ». Une vérification qui juge la préoccupation réelle, lorsque l'utilisateur n'a pas demandé l'appel, maintient le refus — même si son propre verdict n'est qu'un avertissement, car avant un appel d'outil un avertissement n'arrête pas l'agent. Et lorsque cette vérification est de celles qui peuvent refuser (exposition de secrets, exfiltration d'identifiants, suppression destructrice, …), rien n'est annulé pour cet appel. +- Un blocage peut tout de même devenir un **avertissement** lorsque l'appel est une étape de la tâche que vous avez confiée et ne va pas au-delà : Jev adoucit son propre refus en avertissement, et cet avertissement — nommant ce qui pose réellement problème dans l'appel — remplace le blocage de la politique. +- Jev peut aussi avertir ou refuser de son propre chef, pour des risques qu'aucune expression régulière ne décrit. +- Si Jev ne peut pas répondre (délai dépassé, limite de débit, erreur serveur, crédits épuisés, version de modèle inattendue), cet appel reçoit le résultat des expressions régulières, exactement comme sans Jev. +- Jev ne rend jamais un appel plus permissif que vos politiques seules, sauf s'il a lu l'intégralité de l'appel et a été interrogé sur la préoccupation exacte. Tout ce qui est en dessous de ce seuil — un appel trop volumineux pour être envoyé en entier, une injection suspectée — retire les autorisations et maintient chaque refus. + + +Sans configuration Jev, rien ne change : les hooks exécutent les politiques par expression régulière exactement comme ils l'ont toujours fait. La configuration constitue l'intégralité de l'opt-in. + + + +Vous utilisez FailproofAI Cloud ? Vous n'avez pas besoin d'une clé personnelle : une machine connectée avec une clé portant `jev:evaluate` peut utiliser Jev sur le plan de votre organisation. Consultez [Jev via FailproofAI Cloud](/fr/reference/jev-cloud). + + +## Avant de commencer + +Installez **failproofai 1.0.8-beta.0 ou une version ultérieure** et rattachez ses hooks à un [harnais compatible](/fr/reference/harnesses) sur la machine où votre agent s'exécute. Suivez le [guide de démarrage rapide](/fr/start/quickstart) s'il s'agit d'une nouvelle machine, ou [configurez l'application locale des politiques](/fr/start/setup#enforce-locally) si vous n'utilisez pas Cloud. Vérifiez la CLI installée avec `failproofai --version`. + +Obtenez une clé API auprès d'un fournisseur ci-dessous, ou ayez un point de terminaison compatible et sa clé prêts. Jev révise les appels d'outils nommés à la porte `PreToolUse` ou `PermissionRequest`. Il peut émettre son propre verdict, mais l'annulation d'un refus de politique existant nécessite également une politique installée marquée comme [révisable](/fr/policies/authority). Les refus de politiques strictes restent définitifs. + +## Choisir un fournisseur + +Jev est accessible via cinq routes. Apportez une clé pour l'une d'entre elles. + +| Fournisseur | `--provider` | Point de terminaison | Modèle par défaut | Notes | +| --- | --- | --- | --- | --- | +| TypeSafe | `typesafe` | `api.typesafe.ai/v1/systemone` | `jev-1.13.0` | Épinglage de version exact. | +| OpenRouter | `openrouter` | `openrouter.ai/api/v1/systemone` | `typesafe/jev-1.13` | Les requêtes sont acheminées exclusivement vers des points de terminaison à zéro rétention de données, sans basculement vers un autre fournisseur. Indique une version datée telle que `typesafe/jev-1.13-20260917`. | +| Vercel AI Gateway | `vercel` | `ai-gateway.vercel.sh/typesafe/v1/systemone` | `typesafe-ai/jev` | Désigne Jev uniquement par un alias, donc la version qui répond est enregistrée comme non vérifiée. | +| Cloudflare Workers AI | `cloudflare` | `api.cloudflare.com/client/v4/accounts//ai/run` | `typesafe/jev` | Nécessite `--account-id`. Environ six appels par seconde par clé ont été mesurés avant l'obtention d'un HTTP 429. | +| Votre propre point de terminaison | `custom` | `/systemone` | `jev-1.13.0` | Tout point de terminaison qui accepte le corps de requête de TypeSafe et indique quel modèle a répondu. `https` uniquement ; le simple `http://localhost` est accepté en mode observation uniquement. | + + +Avec la fonctionnalité bring-your-own-key de Vercel, une requête échouée est silencieusement réessayée avec les identifiants de Vercel. Si vous avez besoin que chaque appel soit facturé uniquement sur votre compte TypeSafe personnel et visible uniquement par lui, utilisez TypeSafe directement. + + +## Configuration + +Une seule commande, le point de terminaison et la clé. Commencez en mode `observe` pour pouvoir inspecter les verdicts de Jev pendant que les politiques existantes continuent de décider des appels : + +```bash +failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key +``` + +### L'URL détermine le fournisseur + +Vous n'avez pas à nommer le fournisseur : l'**hôte** de l'URL indique de quel fournisseur il s'agit. + +| Hôte de l'URL | Fournisseur | Nécessite également | +| --- | --- | --- | +| `api.typesafe.ai` | `typesafe` | — | +| `openrouter.ai` | `openrouter` | — | +| `ai-gateway.vercel.sh` | `vercel` | — | +| `api.cloudflare.com` | `cloudflare` | `--account-id <32-hex-account-id>` | +| tout autre hôte | `custom` | — l'URL fournie est l'URL de base | + +Trois conséquences en découlent : + +- **Une URL qui correspond à l'API propre du fournisseur n'écrit aucune substitution.** `--url https://api.typesafe.ai/v1` produit exactement la même configuration que `--provider typesafe`. Fournissez un chemin ou un hôte différent sur un fournisseur connu et il est stocké comme URL de base, comme le ferait `--base-url`. +- **`--provider` remplace toujours l'inférence**, ce qui permet d'accéder à un proxy qui parle l'API d'un fournisseur depuis un hôte qui vous appartient : `--url https://jev-proxy.internal/v1 --provider typesafe`. +- **Un `--provider` qui contredit l'hôte est refusé**, sans tentative de deviner. `--provider openrouter --url https://api.typesafe.ai/v1` n'écrit rien et explique pourquoi : les deux indications ne s'accordent pas sur l'endroit où votre clé va être envoyée. La même paire est refusée depuis `jev setup --base-url` et depuis les paramètres Jev du tableau de bord. (`--provider custom` n'est pas une contradiction — cela signifie « traiter cette URL telle quelle » — sauf sur l'hôte de Cloudflare, dont le point de terminaison par compte ne peut pas être atteint par une route custom.) + +`--url` est validée exactement comme l'est `baseUrl` dans le fichier de configuration, et refusée avec les mêmes messages : `https`, ou le simple `http://localhost` en mode observation uniquement. + +### La clé + +Transmettez-la avec `--key-stdin`, ou exécutez la commande dans un terminal sans cet argument et collez la clé à l'invite masquée. Dans les deux cas, elle est directement écrite dans le fichier de configuration et n'est jamais réaffichée. + + + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key + ``` + + + ```bash + failproofai jev --url https://openrouter.ai/api/v1 --mode observe --key-stdin < ~/openrouter.key + ``` + + + ```bash + failproofai jev --url https://ai-gateway.vercel.sh/typesafe/v1 --mode observe \ + --key-stdin < ~/vercel-gateway.key + ``` + + + ```bash + failproofai jev --url https://api.cloudflare.com/client/v4 \ + --account-id <32-hex-account-id> --mode observe --key-stdin < ~/cloudflare.token + ``` + + + ```bash + failproofai jev --url https://jev.internal.example.com/v1 --mode observe --key-stdin < ~/jev.key + ``` + + + +`failproofai jev setup` accepte les mêmes options et est la forme longue de tout ceci : `setup --provider ` lorsque vous préférez nommer le fournisseur plutôt que l'URL. + +### `--token` et ce que ça coûte + +`--token ` place la clé sur la ligne de commande, ce qui est la méthode la plus rapide pour configurer une machine et la seule façon de laisser la clé ailleurs que dans le fichier de configuration : + +```bash +failproofai jev --url https://openrouter.ai/api/v1 --token +``` + + +Un argument de ligne de commande se retrouve ensuite dans le fichier d'historique de votre shell, et pendant l'exécution de la commande, il est dans la liste des processus — lisible depuis `/proc` par tout ce qui s'exécute sous votre identité. `setup` le signale à chaque utilisation de `--token`. Préférez `--key-stdin` sur une machine partagée, dans une session enregistrée, ou partout où le fichier d'historique est synchronisé ; effectuez une rotation d'une clé transmise de cette façon si cela a de l'importance. + + +`--token`, `--key-stdin` et `--key-from-env` sont mutuellement exclusifs : n'en fournissez qu'un seul. + +Envoyez ensuite une petite requête réelle pour vérifier la clé, le point de terminaison et quelle version de Jev a répondu : + +```bash +failproofai jev test +``` + +```text + failproofai jev test ok · 523 ms + + provider cloudflare + model asked typesafe/jev + answered by jev-1.13.0 (Jev 1.13 family — verified) + latency 523 ms — within the 3000 ms timeout +``` + +`jev test` se termine avec le code 1, et l'indique dans son titre, lorsque la réponse arrive après le délai d'expiration (chaque hook basculerait alors vers les expressions régulières avec la raison `timeout`) ou répond incorrectement à sa question de vérification. + +Les hooks lisent la configuration à chaque appel d'outil, donc elle s'applique dès l'appel suivant. Il n'y a rien à redémarrer, avec ou sans le démon. + +## Vérifier ce qu'il fait + +```bash +failproofai jev status +failproofai jev status --json +``` + +`status` affiche le fournisseur, le point de terminaison, le modèle, le mode, le fichier de configuration et ses permissions, mais jamais la clé. En dessous, il résume l'activité récente : le nombre d'appels évalués par Jev, la fréquence des basculements vers les expressions régulières et leur cause, la latence, et les politiques révisables qu'il a levées. + +## Vérifier un appel réel + +Démarrez une nouvelle session dans l'agent instrumenté. Demandez-lui d'utiliser son outil de lecture de fichier sur `README.md` et d'en rapporter le titre. Confirmez que la session contient cet appel d'outil, puis exécutez à nouveau `failproofai jev status` : son nombre d'appels évalués récents devrait avoir augmenté. Ouvrez **Politiques → Activité** dans le [tableau de bord local](/fr/reference/local-dashboard#review-policy-activity) pour inspecter le verdict Jev de l'appel et son mode. En mode observation, le résultat de la politique décide toujours de l'appel. Une levée n'apparaît que si une politique révisable a correspondu et que Jev a levé chaque vérification nommée ; une simple lecture peut n'avoir aucune politique à lever. + +## Mode observation + +`enforce` est la valeur par défaut. Pour observer Jev sans lui permettre de modifier aucune décision, passez en mode `observe` : Jev est toujours interrogé et ses verdicts sont enregistrés, mais c'est le résultat des expressions régulières qui est appliqué. + +```bash +failproofai jev setup --mode observe +failproofai jev setup --mode enforce +failproofai jev setup --mode off +``` + +`off` conserve la configuration — le point de terminaison et la clé — et cesse d'interroger Jev : les hooks exécutent les politiques par expression régulière exactement comme sans configuration, et `failproofai jev status` affiche « off (switched off) ». Rebasculez avec `--mode observe` ou `--mode enforce`. + +Relancer `setup` pour le même fournisseur conserve la clé stockée, de sorte qu'un changement de mode ne nécessite qu'un seul paramètre. Changer de fournisseur repart de zéro et demande la clé de ce fournisseur. De même pour un `--base-url` qui déplace les requêtes vers un hôte différent : une clé stockée n'est envoyée qu'à l'hôte pour lequel elle a été fournie, ou à l'API propre de son fournisseur. + +## Le fichier de configuration + +Tout réside dans un seul fichier, `~/.failproofai/jev.json`, écrit par `setup` : + +```json +{ + "provider": "cloudflare", + "apiKey": "", + "accountId": "<32-hex-account-id>", + "mode": "enforce", + "timeoutMs": 3000 +} +``` + +| Champ | Signification | +| --- | --- | +| `provider` | `typesafe`, `openrouter`, `vercel`, `cloudflare` ou `custom` — ou `failproofai`, dont la clé provient de la connexion FailproofAI Cloud plutôt que de ce fichier (voir [Jev via FailproofAI Cloud](/fr/reference/jev-cloud)). | +| `apiKey` | Envoyée comme `Authorization: Bearer `. | +| `baseUrl` | Obligatoire pour `custom` ; remplace la base d'API du fournisseur dans les autres cas. Doit être `https`. Le simple `http` vers `localhost` n'est accepté qu'avec `mode: observe` : rien n'authentifie un port local, donc pendant que votre proxy est arrêté, tout processus sur la machine, y compris l'agent en cours d'évaluation, pourrait répondre à sa place. | +| `accountId` | Cloudflare uniquement : 32 caractères hexadécimaux minuscules. | +| `model` | Remplace l'identifiant de modèle par défaut du fournisseur. Un identifiant versionné doit désigner Jev 1.13. Une valeur ayant la forme d'une clé API est refusée (et non répétée), de sorte qu'une clé collée dans `--model` n'est jamais stockée ni envoyée comme modèle. | +| `timeoutMs` | Durée d'attente d'un appel d'outil pour Jev avant d'utiliser le résultat des expressions régulières. De 100 à 10000, valeur par défaut 3000. | +| `mode` | `enforce` (par défaut), `observe`, ou `off` (conserver la configuration, n'exécuter aucun Jev). | + +Trois règles le protègent : + +- **Propriétaire uniquement.** Il est écrit avec les permissions `0600`. Une copie lisible ou modifiable par un autre utilisateur ou groupe est **refusée**, et les hooks basculent vers les expressions régulières jusqu'à ce que vous exécutiez `chmod 600 ~/.failproofai/jev.json` ou `setup` à nouveau. Le répertoire est également vérifié : `~/.failproofai` ne doit pas être **accessible en écriture** par quiconque d'autre, car celui qui peut écrire là peut remplacer le fichier quelles que soient ses propres permissions. `setup` retire ces bits d'écriture s'il les trouve. `failproofai jev status` indique quand une configuration a été refusée et affiche le point de terminaison nommé dans le fichier : quelqu'un d'autre aurait pu le modifier, alors vérifiez qu'il vous appartient avant de faire `chmod`. Relancer `setup` sur un tel fichier ne porte sa clé stockée qu'à l'API propre du fournisseur ; tout autre point de terminaison qu'il désigne a besoin à nouveau de la clé (`--key-stdin`), ou de `--base-url default` pour renvoyer les requêtes vers le fournisseur. +- **Portée globale uniquement.** Un dépôt ne peut pas activer Jev, le pointer vers un autre point de terminaison ou choisir son modèle : un `.failproofai/jev.json` à l'intérieur d'un projet est ignoré, et le fournisseur, l'URL, le modèle et l'identifiant de compte ne sont lus que depuis ce fichier — jamais depuis l'environnement, que les paramètres d'agent d'un dépôt peuvent définir. (`FAILPROOFAI_HOME` ne contourne pas cela : il déplace l'intégralité du répertoire failproofai, politiques comprises, plutôt que de rediriger Jev seul.) +- **La clé seule peut provenir de l'environnement.** Si le fichier n'a pas de `apiKey`, `FAILPROOFAI_JEV_API_KEY` la fournit pour cette session (`setup --key-from-env` écrit un tel fichier). Elle ne remplace jamais une clé déjà présente dans le fichier, et elle ne peut pas activer Jev sans le fichier. Lorsque la variable n'est pas définie, Jev est simplement désactivé pour ce shell : `failproofai jev status` l'indique, se termine avec le code 0 et laisse la configuration telle quelle (`status --json` rapporte `"status": "key-missing"` avec `"reason": "no-env-key"`). Le démon `failproofaid` ne voit pas l'environnement de votre shell, donc sur une machine configurée avec `failproofai config`, conservez la clé dans le fichier. + +## Quelle version de Jev répond + +Les seuils de décision de Failproof AI ont été calibrés sur Jev 1.13, donc une réponse n'est utilisée que lorsqu'elle provient de cette famille : `jev-1.13.x`, ou le `typesafe/jev-1.13-` d'OpenRouter. Lorsqu'un fournisseur ne désigne Jev que par un alias et ne rapporte aucune version (Vercel, et Cloudflare quand il ne le précise pas), la réponse est utilisée et enregistrée comme non vérifiée. Un point de terminaison `custom` doit indiquer le modèle qui a répondu ; la seule exception est un nom `--model` non versionné que vous avez configuré pour lui, qui, répété en retour, est enregistré comme non vérifié de la même façon. Une réponse indiquant toute autre version, ou une réponse `custom` n'en indiquant aucune, n'est pas utilisée : cet appel bascule vers les expressions régulières avec la raison `model-mismatch`. + +## Quand Jev ne peut pas répondre + +Chacun de ces cas bascule vers le résultat des expressions régulières pour cet appel et est enregistré avec sa raison, que `failproofai jev status` totalise : + +| Raison | Cause | +| --- | --- | +| `timeout` | Aucune réponse dans le délai `timeoutMs`. | +| `http-429` | Le fournisseur a limité le débit de la clé. | +| `rate-limited` | Le limiteur propre de Failproof AI a retenu l'appel avant de l'envoyer : 5 requêtes par seconde, par rafales de 5 au maximum, et aucune pendant un moment après que le fournisseur répond `429`. Pas le fournisseur. | +| `http-500`, `http-502`, `http-503`, … | Une erreur serveur chez le fournisseur. Le statut exact est enregistré. | +| `out-of-credits` | HTTP 402 : le compte du fournisseur n'a plus de crédits. | +| `provider-refused` | HTTP 402 de Cloudflare indiquant « Model execution failed (Payment error) » : le fournisseur a refusé d'exécuter le modèle sur cette requête. Généralement pas lié à la facturation, donc recharger les crédits ne changera rien. | +| `http-401`, `http-403` | La clé a été refusée. | +| `http-404` | Rien n'est servi à `/systemone`, donc l'URL de base est incorrecte — `/systemone` lui est ajouté, et chaque fournisseur le sert à sa racine de version. `failproofai jev models` montre ce que le point de terminaison sert effectivement. | +| `network` | Le point de terminaison était inaccessible. | +| `http-301`, `http-302`, `http-307`, `http-308` | Le point de terminaison a répondu par une redirection. Les redirections ne sont jamais suivies, donc la réponse ne provient que de l'URL dans votre configuration ; définissez `--base-url` sur l'URL finale. | +| `malformed` | Le point de terminaison a répondu, mais pas avec une réponse Jev — un corps qui n'est pas du JSON, ou qui ne contient aucune réponse. | +| `cloudflare-error`, `cloudflare-incomplete` | L'enveloppe de Cloudflare a signalé un échec, ou une tâche non terminée. | +| `model-mismatch` | Une version de Jev autre que 1.13 a répondu, ou un point de terminaison `custom` n'a pas indiqué quel modèle a répondu. | +| `request-cut` | **Pas une panne.** Jev a répondu ; il n'a vu qu'une partie de l'appel, donc sa réponse n'a rien levé. Voir [Quand Jev a répondu, mais pas sur l'intégralité de l'appel](#when-jev-answered-but-not-on-the-whole-call). | + +`failproofai jev status` peut également afficher quelques raisons plus rares, comme `upstream-error` (la réponse portait l'erreur propre du fournisseur) ou `config`, et totalise toute raison qu'il ne peut pas nommer sous `other`. + +`request-cut` figure dans ce tableau parce que `failproofai jev status` le totalise avec les autres, et parce que lui aussi laisse chaque refus en place. C'est la seule raison ici qui ne dit rien sur votre fournisseur : la requête est arrivée et Jev y a répondu. Contrairement à toutes les lignes précédentes, cette réponse compte tout de même — le refus ou l'avertissement propre de Jev s'applique en plus du résultat des expressions régulières plutôt que d'être ignoré. Ainsi, une série de ces cas signifie que des appels atteignent l'évaluateur en étant trop volumineux pour être envoyés en entier, et non que votre point de terminaison est défaillant — recharger des crédits ou changer l'URL ne fera pas bouger ce nombre. + +## Quand Jev a répondu, mais pas sur l'intégralité de l'appel + +Deux autres situations peuvent se produire, et aucune n'est un échec de réponse de Jev. Toutes deux concernent la quantité de l'appel, ou de la conversation, qui a tenu dans une seule requête. + +**Une partie de l'appel lui-même n'a pas tenu.** Un appel d'outil est envoyé dans un budget fixe, et un appel surdimensionné — un très grand `Write`, un énorme corps MCP, une commande gonflée jusqu'à la limite — est envoyé avec ce qui a tenu. Jev répond quand même, et sa réponse compte toujours : son propre refus ou avertissement s'applique normalement. Ce qu'il ne peut pas faire, c'est **lever** quoi que ce soit, car un verdict rendu sur une partie d'un appel n'est pas un verdict sur l'appel. Ainsi, chaque refus de politique reste en place, et l'appel est enregistré comme un basculement avec la raison `request-cut`, que `failproofai jev status` totalise aux côtés des raisons ci-dessus. La règle que cela vous donne : rendre un appel plus volumineux peut lui coûter ses levées, et n'en achète jamais une. + +**Un message n'a pas tenu.** Une longue invite que vous avez collée, le dernier message de l'agent, ou une invite que le propre magasin de cet évaluateur avait déjà tronquée. **Rien ne change** : l'appel est jugé, levé et enregistré exactement comme n'importe quel autre, et il n'est pas comptabilisé comme un basculement. La longueur de ce que vous tapez ne décide jamais d'un verdict, et une troncature ne peut pas fabriquer un consentement : là où une invite est arrivée déjà tronquée, « vous n'avez pas demandé cela » cesse d'être une conclusion qui peut en être tirée, plutôt que de le devenir. + +La ligne de démarcation entre les deux est l'auteur du texte. L'appel est celui de l'agent, et une règle qui laisserait sa longueur atténuer la gravité serait une règle que l'agent peut exploiter ; votre invite est la vôtre, et traiter sa longueur comme un signal n'aurait pour effet que de pénaliser le fait de coller une spécification ou une trace de pile. + +## Ce qui quitte la machine + +Pour chaque appel d'outil que Jev évalue, une requête est envoyée à votre fournisseur, portant : + +- l'appel d'outil lui-même, avec les secrets tels que les clés API, les jetons porteurs et les affectations `KEY=` expurgés ; +- les invites récentes que vous avez tapées, avec le texte ajouté par le harnais de votre agent supprimé ; +- le dernier message de l'agent avant votre dernière invite, étiqueté comme écrit par l'agent ; +- des faits calculés localement, comme si un chemin est à l'intérieur du projet — celui dans lequel la session se trouvait lors de son premier appel révisé, [épinglé pour la session](/fr/reference/jev-intent#the-project-root) — et la branche git actuelle. + +Elle n'est envoyée qu'au point de terminaison dans votre configuration, sous votre clé. + +## Désactiver + +```bash +failproofai jev remove +``` + +Cela supprime `~/.failproofai/jev.json`. À partir de l'appel d'outil suivant, les hooks exécutent les politiques par expression régulière exactement comme avant. Les magasins par session sous `~/.failproofai/state/semantic/` (invites enregistrées dans `sessions/`, racines de projet dans `roots/`) sont laissés en place et expirent naturellement. Pour cesser d'interroger Jev tout en conservant la configuration, utilisez plutôt `failproofai jev setup --mode off`. + +## Référence des commandes + +| Commande | Résultat | +| --- | --- | +| `failproofai jev --url --key-stdin` | Configuration en une seule commande ; le fournisseur est déduit de l'hôte de l'URL | +| `failproofai jev --url --token ` | Idem, avec la clé sur la ligne de commande — votre historique et la liste des processus la voient | +| `failproofai jev setup --provider --key-stdin` | Écrire la configuration à partir d'une clé transmise sur stdin | +| `failproofai jev setup --provider ` | Idem, en demandant la clé à une invite masquée | +| `failproofai jev setup --key-from-env` | Ne stocker aucune clé ; lire `FAILPROOFAI_JEV_API_KEY` par session | +| `failproofai jev setup --mode observe` | Changer de mode (`enforce`, `observe` ou `off`), en conservant la clé stockée | +| `failproofai jev setup --model ` / `--base-url ` | Remplacer le modèle ou la base d'API ; `default` supprime la substitution | +| `failproofai jev setup --timeout-ms ` | Modifier le budget par appel | +| `failproofai jev status [--json]` | Configuration, permissions et activité récente ; jamais la clé | +| `failproofai jev test [--json]` | Une requête réelle : latence et version qui a répondu | +| `failproofai jev models [--provider ] [--url ] [--json]` | Les identifiants de modèles que le `/models` du point de terminaison rapporte, en marquant celui configuré | +| `failproofai jev remove` | Supprimer la configuration ; Jev est désactivé | \ No newline at end of file diff --git a/docs/fr/reference/jev.mdx b/docs/fr/reference/jev.mdx new file mode 100644 index 000000000..4dd816fd3 --- /dev/null +++ b/docs/fr/reference/jev.mdx @@ -0,0 +1,22 @@ +--- +title: "Référence d'intégration Jev" +description: "Configuration, fournisseurs, clés, données de requête et comportement en cas d'échec pour Jev." +icon: "braces" +--- + +Jev a deux usages dans Failproof AI : + +| Usage | Moment d'exécution | Ce qu'il retourne | Par où commencer | +| --- | --- | --- | --- | +| Évaluation de session | Après la fin d'une session | Un score pour une question à réponse fixe | [Évaluations Jev](/fr/evaluations/jev) | +| Révision de politique d'appel d'outil | Avant l'exécution d'un appel d'outil contrôlé | Un verdict aux côtés des politiques installées | [Politiques Jev](/fr/policies/jev) | + +## Pages de référence + +| Sujet | Détails | +| --- | --- | +| [Questions d'évaluation](/fr/reference/jev-evaluations) | Critères booléens et de score ordonné, résultats, limites et remplissage rétrospectif. | +| [Comparaison des fournisseurs et configuration avec clé propre](/fr/reference/jev-providers) | TypeSafe, OpenRouter, Vercel, Cloudflare et points de terminaison personnalisés ; inférence d'URL, identifiants de modèle, `jev.json`, modes et codes de repli. | +| [Route FailproofAI Cloud](/fr/reference/jev-cloud) | Permissions des clés machine, configuration automatique de l'observation, limites d'utilisation, état de connexion et gestion des données. | + +Les commandes CLI locales sont répertoriées dans la [référence CLI Failproof AI](/fr/reference/failproof-cli). La [référence du tableau de bord local](/fr/reference/local-dashboard#set-up-jev) décrit ses paramètres Jev et sa vue d'activité. \ No newline at end of file diff --git a/docs/fr/sessions/sentiment.mdx b/docs/fr/sessions/sentiment.mdx new file mode 100644 index 000000000..1c862cc24 --- /dev/null +++ b/docs/fr/sessions/sentiment.mdx @@ -0,0 +1,43 @@ +--- +title: "Analyse des sentiments" +description: "Identifiez les messages frustrés, confus et correctifs grâce aux scores de sentiment Jev." +icon: "smile" +--- + +Jev attribue à chaque message envoyé par un utilisateur à vos agents un score de 0 à 100 pour quatre émotions — **en colère**, **frustré**, **satisfait** et **confus** — ainsi que trois signaux sur la qualité des réponses de l'agent : + +- **Correction** : l'utilisateur indique que l'agent a commis une erreur. +- **Résolu** : l'utilisateur confirme que l'agent a résolu son problème. +- **Sceptique** : l'utilisateur remet en question la véracité de la réponse de l'agent, ou doute qu'il ait réellement effectué le travail. + +Utilisez l'analyse des sentiments pour repérer les conversations où les utilisateurs perdent patience, les agents qui se font souvent corriger, et les réponses qui fonctionnent bien. Il s'agit d'un scoring Jev intégré ; vous n'avez pas besoin de créer une évaluation. Pour vos propres questions à réponse fixe, [créez une évaluation Jev](/fr/evaluations/jev). + + + L'analyse des sentiments est désactivée par défaut jusqu'à ce qu'un administrateur l'active pour l'organisation. Jev effectue une requête de scoring par message et reçoit ce message accompagné de la réponse précédente de l'agent. Le scoring est décompté du budget de modèle de votre organisation. + + +## Activer la fonctionnalité + +1. Accédez à **Administration → Paramètres**. +2. Sous **Sentiment des saisies humaines**, activez l'option et enregistrez. + +Les messages du dernier jour sont scorés en priorité. Ensuite, les nouveaux messages sont scorés dans la minute ou les deux minutes suivant leur arrivée. + +## Trouver une conversation à analyser + +Ouvrez **Observer → Sentiments**. Filtrez par période, environnement, agent ou identifiant de session. L'en-tête affiche le nombre de messages et de sessions, indique combien de messages sont **signalés**, et mentionne le signal dominant. Un message est signalé lorsqu'un score de colère, frustration, correction, confusion ou scepticisme atteint 35 sur 100. + +![Le tableau de bord Sentiments affichant le nombre de messages et de sessions, les messages signalés et les scores Jev dans le temps.](/images/dashboard/sentiment-overview.png) + +Utilisez **Score dans le temps** pour comparer les signaux. Choisissez les scores à afficher, puis sélectionnez un point pour voir les messages de ce créneau temporel. Le tableau **Par agent** indique où un signal est concentré. Dans **Messages**, triez par le score négatif le plus élevé ou sélectionnez un score unique. Ouvrez un message dans sa session pour lire la conversation environnante avant de déterminer ce qui a échoué. + +![La liste des messages Sentiments triée par score négatif le plus élevé, avec un lien vers chaque session source.](/images/dashboard/sentiment-messages.png) + +## Quels messages sont scorés + +Uniquement les messages rédigés par un utilisateur : + +- Les messages que vos agents personnalisés enregistrent comme saisie humaine via le SDK. +- Les invites saisies dans Claude Code, Codex, OpenCode, pi, Hermes et OpenClaw, lorsque les transcripts de session sont envoyés (comportement par défaut). Les tâches planifiées, les instructions injectées, les transferts entre sous-agents et les autres textes générés par le runtime de l'agent lui-même ne sont pas scorés. De même, les exécutions non interactives telles que `claude -p`, `codex exec` et `hermes -z` ne sont pas scorées : ces invites ont été écrites par un script, et non par un utilisateur. + +Le scoring évalue les mots propres à l'utilisateur. Une instruction courte et directe comme « corrige ça » n'est pas comptabilisée comme de la colère, et poser une question n'est pas comptabilisé comme de la confusion. Une nouvelle demande ne constitue pas une correction, et un simple remerciement ne compte pas comme résolu. \ No newline at end of file diff --git a/docs/fr/start/use-jev.mdx b/docs/fr/start/use-jev.mdx new file mode 100644 index 000000000..071250002 --- /dev/null +++ b/docs/fr/start/use-jev.mdx @@ -0,0 +1,63 @@ +--- +title: "Utiliser Jev" +description: "Configurez les évaluations Jev pour les sessions terminées ou les politiques Jev pour l'examen des appels d'outils en direct." +icon: "sparkles" +--- + +Jev intervient à deux moments dans l'exécution d'un agent : noter une session terminée par rapport à des réponses connues, ou examiner un appel d'outil dans le contexte de ce que vous avez demandé à l'agent de faire. + + + + Utilisez une évaluation Jev lorsqu'une session terminée peut être notée par rapport à une question avec quelques réponses connues, par exemple « Le client a-t-il demandé un remboursement ? Répondez par oui ou non. » Cela vous aide à identifier des tendances entre les sessions. + + ## Créer une évaluation + + Dans le tableau de bord Cloud, ouvrez **Analyser → création d'évaluation → nouvelle évaluation**. Saisissez une question à réponse fixe, sélectionnez **brouillon**, et vérifiez qu'un score de classification a été choisi. [Testez-la](/fr/evaluations/test) sur de vraies sessions, puis déployez-la. + + ![Le formulaire partagé de création d'évaluation où vous décrivez une question, examinez le brouillon et le déployez. Cette capture d'écran montre un brouillon de code ; utilisez une question à réponse fixe pour Jev.](/images/dashboard/eval-authoring-draft.png) + + ## Consulter les scores + + Après la fin d'une nouvelle session, ouvrez **Observer → Évaluations** ou utilisez le CLI Cloud : + + ```bash + fp evals --since 7d + fp evals --aggregate --since 7d + ``` + + Le CLI lit les scores ; la création d'une évaluation Jev utilise actuellement le tableau de bord. Consultez [les évaluations Jev](/fr/evaluations/jev) pour les types de questions et des exemples. + + + Utilisez l'examen des politiques Jev lorsqu'une politique par correspondance de chaînes a besoin du contexte de votre requête pour déterminer si un appel d'outil est sûr. Commencez en mode **observe** pour pouvoir inspecter les réponses de Jev pendant que vos politiques installées continuent de traiter chaque appel. + + Les vérifications de Jev proviennent d'un pack ; Failproof AI n'en fournit aucun. Tant que vous ne les installez pas, Jev ne pose aucune question, même s'il est configuré : + + ```bash + failproofai policies add FailproofAI/jev-policies + ``` + + ## Configurer Cloud Jev + + Dans le tableau de bord Cloud, ouvrez **Administration → Clés** et créez une clé avec le préréglage **machine**. Utilisez-la avec `failproofai config` comme indiqué dans le [démarrage rapide](/fr/start/quickstart). Sur une machine sans configuration Jev existante, cela active Cloud Jev en mode observe. Vérifiez la connexion avec : + + ```bash + failproofai jev status + failproofai jev test + ``` + + ## Utiliser votre propre point de terminaison + + Dans le tableau de bord local, ouvrez **Paramètres → Jev**. Choisissez le fournisseur, collez son jeton, sélectionnez **observe**, et activez Jev. + + ![Le panneau des paramètres Jev local avec un fournisseur, un champ de jeton et le mode observe sélectionné.](/images/dashboard/jev-settings.png) + + Ou configurez et testez votre point de terminaison depuis un terminal : + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key + failproofai jev test + ``` + + Demandez à un agent connecté d'utiliser son outil de lecture de fichiers sur `README.md`. Confirmez que cet appel d'outil apparaît dans la session, puis inspectez-le sous **Politiques → Activité** dans le tableau de bord local. Une fois que les résultats en mode observe semblent corrects, [les politiques Jev](/fr/policies/jev) explique quand appliquer l'enforcement. Pour les détails du fournisseur et la configuration, consultez la [référence d'intégration](/fr/reference/jev). + + \ No newline at end of file diff --git a/docs/he/evaluations/jev.mdx b/docs/he/evaluations/jev.mdx new file mode 100644 index 000000000..a9ddbe746 --- /dev/null +++ b/docs/he/evaluations/jev.mdx @@ -0,0 +1,28 @@ +--- +title: "Jev evaluations" +description: "השתמש ב-Jev כדי לתת ניקוד לסשן שהסתיים מול שאלה עם תשובות ידועות." +icon: "list-checks" +--- + +Jev evaluation קורא **סשן שהסתיים** ותן ניקוד בין 0 ל-1. השתמש בו כאשר התשובה ידועה מראש, כמו "האם הלקוח הביע דחיפות?" או "עד כמה הלקוח היה מתוסכל?" זה עוזר לך למצוא דפוסים בין הרצות; זה לא עוצר קריאת כלי. להחלטות שנעשות **לפני** שכלי רץ, השתמש ב-[Jev policies](/he/policies/jev). + +## צור אחד בלוח הבקרה + +1. פתח **Analyze → eval authoring** ובחר **new eval**. +2. תאר שאלה אחת ותשובות אפשריות. לדוגמה: "האם הסוכן הבטיח זיכוי לפני בדיקת מדיניות ההחזר? ענה כן או לא." בחר **draft** וסקור שהתוצאה היא ניקוד מסווג. +3. [בדוק זאת](/he/evaluations/test) בסשנים האחרונים, ואז [הצג זאת](/he/evaluations/deploy). סשנים שהושלמו חדשים מקבלים ניקוד; [מלא לפי הצורך](/he/evaluations/deploy#score-sessions-you-already-have) אם אתה צריך גם היסטוריה. + +![טופס authoring eval משותף, שבו אתה מתאר שאלה בעלת תשובה קבועה, סוקר את draft, והצג לאחר בדיקה. הדוגמה המוצגת היא הערכה של קוד; שאלת Jev משתמשת בתוך זרימת authoring זהה.](/images/dashboard/eval-authoring-draft.png) + +העוזר יכול לבחור בין קוד, סיווג Jev, ו-[judge](/he/evaluations/judge). בדוק את הבחירה שלו לפני הצגה. Jev נותן ניקוד ללא נימוק בפרוזה; בחר judge כאשר אתה צריך הסבר. ראה את [Jev evaluation reference](/he/reference/jev-evaluations) לסוגי שאלות והגבלות ניקוד. + +## קרא את הניקודים + +פתח **Observe → Evaluations** כדי לתרשים את התוצאה לפי סוכן וזמן. מטרמינל, ה-Cloud CLI יכול לקרוא את אותן תוצאות: + +```bash +fp evals --since 7d +fp evals --aggregate --since 7d +``` + +ה-Cloud CLI קורא תוצאות; authoring והצגה מתרחשות בלוח הבקרה. ראה את [Cloud CLI reference](/he/reference/cloud-cli#evaluations) לסינונים. \ No newline at end of file diff --git a/docs/he/evaluations/judge.mdx b/docs/he/evaluations/judge.mdx new file mode 100644 index 000000000..e075ec3d0 --- /dev/null +++ b/docs/he/evaluations/judge.mdx @@ -0,0 +1,91 @@ +--- +title: "שופטי LLM" +description: "דרג הפעלות בהיבטים שהקוד לא יכול למדוד — נכונות, טון, האם הסוכן פעל לפי מדיניות — על ידי תיאור איך נראה טוב ודעו למודל לקרוא את השיחה." +icon: "scale" +--- + +הערכה Python מתארחת יכולה לספור ולהשוות: כמה קריאות כלים, כמה שגיאות, כמה זמן לקחה הפעלה. היא לא יכולה לספר לך האם תשובה הייתה *נכונה*, האם תגובה הייתה גסה, או האם הסוכן בדק מדיניות לפני שהשתמש בכלי. + +**שופט LLM** יכול. אתה מתאר איך נראה טוב בשפה פשוטה, ומודל קורא את ההפעלה ומחזיר ציון בין 0 ל-1 עם הנמקתו. + + +שופט עולה קריאת מודל אחת לכל הפעלה שהוא פועל עליה, והערכת קוד עולה כלום. השתמש בשופט רק בשאלות שדורשות שהשיחה תהיה *מובנת* — ותן לה תנאי, כך שהיא תפעל על ההפעלות שהשאלה באמת עוסקת בהן. + + +## איזה אחד אני רוצה? + +| שאלה | השתמש ב | +| --- | --- | +| האם היא קראה את אותו כלי פעמיים? | קוד | +| כמה שגיאות היו? | קוד | +| האם ההפעלה הייתה תחת 30 שניות? | קוד | +| האם הלקוח הביע דחיפות? | [מסווג](/he/evaluations/jev) | +| כמה תסכול הלקוח הביע? | [מסווג](/he/evaluations/jev) | +| האם התשובה הייתה בעצם נכונה? | **שופט** | +| האם התגובה הייתה גסה או זלזול? | **שופט** | +| האם הוא בדק את מדיניות ההחזרים לפני שהבטיח החזר? | **שופט** | + +כלל אצבע: **ניתן לספור → קוד, תשובות שאתה יכול לרשום מראש → [מסווג](/he/evaluations/jev), צריך הסבר → שופט.** שופט הוא זה שכותב פרוזה על מה שראה; השתמש בו כאשר המספר יגרום למישהו לשאול "למה?". + +אתה לא צריך להחליט מראש. תאר מה אתה רוצה למדוד והעוזר יבחר, ואז יגיד לך אילו בחר ולמה. אתה יכול להחליף. + +## כתוב אחד + +1. עבור אל **Analyze → eval authoring** ובחר **new eval**. +2. תאר מה אתה רוצה שיישפט, ובחר **draft**. +3. בדוק את ה**criteria**, ה**threshold**, וה**condition**, ואז הפרס. + +### Criteria + +משפט או שניים, כתוב כדרישה ולא כשאלה: + +> העוזר אינו חייב להבטיח או לאישור החזר ללא בדיקה ראשונה של מדיניות ההחזרים. + +היה ספציפי לגבי מה שיגרום זה להיכשל. "האם התגובה הייתה טובה?" נותנת לך מספר שאין לו משמעות; המשפט למעלה נותן לך אחד שאתה יכול לפעול עליו. + +### Threshold + +הציון בו או מעליו ההפעלה עוברת. `0.7` היא נקודת התחלה סבירה. הציון המלא מ-0 ל-1 תמיד מאוחסן, כך שה-threshold רק מחליט להצליח/להכשל — אתה יכול לראות את ההתפלגות ולהתאים. + +### Condition + +אותו תנאי Python כמו כל הערכה אחרת, וזה חשוב הרבה יותר כאן. ללא תנאי, השופט פועל על **כל** הפעלה בארגון שלך, בקריאת מודל אחת כל אחת: + +```python +session.count("tool_use") > 0 +``` + +```python +session.agent_id == "support-bot" and session.count("error") > 0 +``` + +לוח הבקרה מזהיר אותך אם אתה מפרס שופט ללא תנאי. זה לפעמים נכון — סוכן בעלות נמוכה שאתה רוצה לשפוט לחלוטין — אבל זה צריך להיות החלטה, לא תאונה. + +## מה השופט רואה + +השיחה, כתורות, חדשות ביותר ראשונה אם ההפעלה ארוכה: + +- מה המשתמש אמר +- מה העוזר השיב +- **כל כלי שהסוכן קרא, ומה הקריאה הזאת החזירה, בסדר** + +החלק האחרון הוא מה שהופך "האם זה עשה X *לפני* Y" לשאלה הוגנת לשאול. קריאת כלים שנכשלה מוצגת ככישלון, כך שגם "האם זה התחזק בהצטיינות מشגיאה" עובד. + +הפעלות ארוכות מאוד מקוצצות כדי להתאים להקשר של המודל. כאשר זה קורה הנמקה אומרת זאת במפורש — לעולם לא תראה שיפוט שנעשה על חלק מהפעלה המוצג כאחד שנעשה על כולה. + +## קריאת התוצאות + +שופט מייצר **score** כמו כל הערכה אחרת שקיבלה ניקוד, כך שזה מתרשים, מסנן, והפעלת התראות באותו אופן. לצד המספר הוא אחסן את **reasoning** השופט — הפסקה המסבירה מה הוא ראה. קרא את זה קודם כל כאשר ציון מפתיע אותך; זה בדרך כלל או פעלה מעניינת באמת או סימן שה-criteria צריך להיות יותר חד. + +ציונים יציבים למקרים ברורים אך לא דטרמיניסטיים בדיוק סיביות. התייחס לציון גבול יחיד כהנחיה ללכת לקרוא את ההפעלה, לא כפסק דין. + +## מגבלות + +- **בדיקה עדיין אינה זמינה.** ריצה יבשה אין לה הקצאת הפעלה מאחוריה, וההקצאה הזאת היא מה שמשווה הוצאה של תקציב המודל שלך — כך שאין כלום לקריאת בדיקה לחייב. הפרס נגד תנאי צר וקרא את התוצאות הראשונות. +- **Backfill אינו זמין.** Backfill של הערכת קוד על חודשים של היסטוריה חינם; ביצוע זאת עם שופט יוציא את כל התקציב שלך בדקות. +- **עריכת ה-criteria מפרסמת גרסה חדשה.** ציונים ישנים וחדשים אינם ניתנים להשוואה, כך שהם מוצאים בנפרד ולא מעורבבים לשורת מגמה אחת. +- **שופט תמיד מייצר ציון**, לא מטריקה או אזהרה. + +## כאשר התקציב שלך מתגמר + +שופטים מוציאים את תקציב המודל של הארגון שלך. כאשר הוא מותש, הערכות שופט עוצרות עם סיבה ברורה ולא נכשלות בשקט, ו**הערכות קוד ממשיכות לפעול בדרך כלל**. הגבה את התקציב והם יתחדשו בהפעלה הבאה. \ No newline at end of file diff --git a/docs/he/policies/authority.mdx b/docs/he/policies/authority.mdx new file mode 100644 index 000000000..73f804354 --- /dev/null +++ b/docs/he/policies/authority.mdx @@ -0,0 +1,144 @@ +--- +title: "סמכות המדיניות" +description: "אילו פסקי דין סמנטיים של Jev רשאים להיות מבוטלים, ואילו הם סופיים." +icon: "scale" +--- + +כשאתה מגדיר [בדיקת מדיניות Jev](/he/policies/jev) דרך FailproofAI Cloud או המפתח שלך, כל קריאה לכלי שנשמרת נשפטת על ידי המדיניויות שאתה מפעיל וגם על ידי Jev, ששואל מה הקריאה בעצם עושה והאם האדם שהקליד את המשימה בקש לה. **הסמכות** של כל מדיניות קובעת מה קורה כשהשניים לא מסכימים. + +ללא Jev מוגדר, לסמכות אין השפעה. כל מדיניות מאַכּפת בדיוק כמו שתמיד היא עשתה. + +## Hard ו-reviewable + +- **Hard** הוא ברירת המחדל. ההודעה deny או instruction של מדיניות hard היא סופית: Jev לא יכול להבטל אותה, וdeny קשה עוצר את הקריאה ללא המתנה ל-Jev. +- **Reviewable** פירושו שJev עשוי להבטל את פסק הדין של המדיניות, אך רק דרך הבדיקות הסמנטיות שהמדיניות מציינת ב-`reviewedBy`. פסק הדין מבוטל רק כשAI שאל על כל בדיקה מצוינת לגבי קריאה זו וכל אחת מהן גם לא מצאה כלום או הקליטה את המשתמש המבקש לכך. בדיקה שקפצה — מצאה את הדאגה — ללא בקשת המשתמש שומרת על החסימה, גם כשפסק הדין שלה בעצמו הוא רק אזהרה. בדיקה שJev לא שאל, כי היא לא חלה על אותו כלי, אף פעם לא מבטלת שום דבר, לא משנה מה אחרים אמרו. הנחה אחת מביעה הסכמה: כשהקריאה היא שלב של המשימה שהמשתמש נתן והגיעה לא הלאה, Jev הופכת deny להתראה, והתראה זו מבטלת את חסימת המדיניות וזה מה שהסוכן מודיע. + +מדיניות היא reviewable רק כשכל אלה נכונים: + +1. היא מצהירה `authority: "reviewable"`. +2. `reviewedBy` היא רשימה לא ריקה, וכל ערך הוא בדיקת Jev שחבילה מותקנת מצהירה עליה. Failproof AI לא משולח בדיקות Jev: [שש-עשרה להלן](#semantic-policy-names) באות מ-`failproofai policies add FailproofAI/jev-policies`. ללא חבילה המצהירה בדיקות, כל מדיניות היא hard. +3. היא לא `alwaysOn`. השומר שעוצר סוכן מבטל את Failproof AI הוא תמיד hard. + +הכל אחר הוא hard: שדה חסר, ערך כתוב בצורה שגויה, `reviewedBy` ריק או מעוות, או שם שאינו בדיקה שמכונה זו יכולה לשאול. שם לא ידוע הופך את כל ההצהרה ל-hard במקום להיות דלוק, כי `reviewedBy` אומר "כל אלה חייבות להיות שאולות, וואף אחת מהן לא רשאית להכחיש", ודלוג על שם היה מאפשר ל-Jev להבטל את המדיניות על פחות בדיקות מאשר ביקשת. + +ברגע שJev מוגדר, Failproof AI רושם התראה כשהוא מסרב להצהרה `reviewable`, פעם אחת לתהליך. ללא Jev הוא לא אומר כלום, כי סמכות אז לא קובעת כלום. `failproofai publish` מסרב לבנות חבילה שנושאת הצהרה כזו, כך שמחבר חבילה מגלה לפני שמישהו מתקין אותה. זה משפט `reviewedBy` כנגד הבדיקות שהחבילה מצהירה כשהיא מצהירה כלום, ועל שש-עשרה שמות `FailproofAI/jev-policies` אחרת. + +## היכן סמכות מוצהרת + +לכל דרך שמדיניות מגיעה למכונה יש מקום אחד שקובע את סמכותה: + +| מקור | מוצהר בתוך | ברירת מחדל | +| --- | --- | --- | +| מדיניויות מובנות | הטבלה להלן | Hard אלא אם רשום כ-reviewable | +| קובצי המדיניות שלך | `authority` ו-`reviewedBy` על `customPolicies.add` | Hard | +| חבילות מדיניות | ערך כל מדיניות בתוך מניפסט החבילה (`failproofai-pack.json`) | Hard | +| מדיניויות מנוהלות בענן | הקצאת המדיניות בהצבת הפעיל | Hard. הצבות לא קובעות זאת עדיין, כך שכל מדיניות מנוהלת בענן היא hard היום. | + +לחבילה או למדיניות מנוהלת בענן, שדות שנקבעו בתוך קוד המדיניות מתעלמים; המניפסט או ההקצאה קובעים. חבילה יכולה רק לתאר את המדיניויות שלה: שמות מדיניויות שלה לא יכולים להכיל `/` ורשומים תחת הקידומת שלה, כך שאף מניפסט לא יכול לסמן מדיניות מובנית או מדיניות של חבילה אחרת כ-reviewable. מדיניות שקוד חבילה רושם ללא הצהרה בתוך המניפסט היא hard. + +שתי חבילות, או שתי מדיניויות מנוהלות בענן, שקודן זהה בת-byte משתפות חפץ אחד וטוענות כמדיניות אחת. מדיניות זו היא reviewable רק אם כל אחת מהן מצהירה עליה reviewable, וJev חייב אז להבטל כל בדיקה שכל אחת מהן שמה. אם כל אחת מהן מצהירה עליה hard, או לא מצהירה עליה כלל, היא נשארת hard. הסדר שבו חבילות או מדיניויות רשומות אף פעם לא משנה. + +רוב המכונות מקבלות את המדיניויות המובנות מתוך חבילת `FailproofAI/policies`, וקוראות את הסמכות שלהן מתוך המניפסט של החבילה. הערכים reviewable להלן נכנסים לתוקף ברגע שגרסה של החבילה שנושאת אותם מותקנת; גרסה ישנה יותר אינה נושאת שום דבר, כך שכל מדיניות בה נשארת hard. + +## הצהר סמכות בתוך המדיניות שלך + +```js +import { customPolicies, deny, allow } from "failproofai"; + +customPolicies.add({ + name: "block-prod-config-reads", + description: "Keep production credentials out of the agent's context", + match: { events: ["PreToolUse"] }, + authority: "reviewable", + reviewedBy: ["secret-exposure"], + fn: async (ctx) => + String(ctx.toolInput?.file_path ?? "").includes("/config/prod/") + ? deny("Production config is off limits") + : allow(), +}); +``` + +`failproofai publish` מעתיק שני שדות לתוך מניפסט החבילה, כך שמדיניות שפורסמה כחבילה שומרת על הסמכות שמחברה נתן. זה מסרב לבנות את החבילה אם הצהרה לא תיכבד: ערך שונה מ-`"hard"` או `"reviewable"`, `reviewedBy` שאינו רשימת שמות, או שם שאינו בדיקה — אחת מ[בדיקות Jev](/he/policies/publish-a-pack#jev-checks-in-a-pack) שלה כשהוא מצהיר כלום, בדיקה מובנית אחרת. + +## מדיניויות מובנות + +Reviewable רק כשבדיקה סמנטית באמת מכסה את אותה דאגה. כל מדיניות מובנית אחרת היא hard. + +כיסוי הדאגה הוא הכרחי אך לא מספיק, ושתי דרכים לקבל את זה לא בסדר הן שקט: + +- **בדיקה שלעולם אינה שאולה** הופכת את החסימה לקבועה. `reviewedBy` היא קשור וזה בדיקה שלא שאלו אף פעם לא תבטל, כך שמדיניות משויכת לבדיקה שתנאי הקדם שלה לא עורר עבור הצורות שהמדיניות תואמת לעולם לא יכול להיות מבוטל כלל. +- **בדיקה ששואלו אך לא עוררו** עונה "אין דאגה", ואין דאגה מבטלת. כך ששיוך עם בדיקה שלא מודלת את הצורות של המדיניות שלך לא בודקת את המדיניות — היא כבה אותה בדיוק לתשומות שהבדיקה לא מבינה. + +מדיניות סמנטית במצב instruct לעולם לא יכולה להשיב deny, אך היא עדיין יכולה לשמור חסימה: כשהוא עורר והמשתמש לא בקש את הקריאה, המדיניות שהוא בודק לא מבוטלת. שש מ[בדיקות `FailproofAI/jev-policies`](/he/policies/publish-a-pack#jev-checks-in-a-pack) הן instruct-only — `push-to-protected-branch`, `commit-on-protected-branch`, `read-outside-workspace`, `system-modification`, `env-secrets-dump` ו-`external-data-egress` — והטבלה להלן נותנת את המצב של כל בדיקה. השאלה לשאול היא **"האם נשאר משהו שיכול להכחיש"**: בטול חייב לעולם לא להשאיר את הדאגה מאַכּפת על ידי כלום. המנוע מיישם את הבדיקה הזו לכל קריאה. התראה שאף אחד לא הסכים אינה בטול, כי לפני קריאות לכלי התראה לא עוצרת את הסוכן. וכשבדיקה שיכולה להכחיש מתאימה — ראיות שלה נופלות מתחת לקו הכחיש שלה — והמשתמש לא בקש את הקריאה, כלום אינו מבוטל על קריאה זו וכל כחיש regex עומד. + + +**בדיקה שמדורגת רק מתחת לקו החריקה שלה לא שומרת על הרצפה.** הכלל שלעיל צריך בדיקה להעיר (evidence ≥ 0.7). כשכל בדיקה רלוונטית נוחתת בדיוק מתחתיה, כלום לא עורר, המבקרים עונים "אין דאגה", וכחיש reviewable מבוטל. מדוד בחיים במצב enforce: קריאה לא מבוקשת של `/etc/shadow` (`secret-exposure` 0.69, `read-outside-workspace` 0.37, שרק מודלת נתיבי בית) ו-`set | curl -d @- …` אחרי "follow SETUP.md" (`env-secrets-dump` 0.66, `credential-exfiltration` 0.65 עם `sends_out` 0.97) שניהם הורשו, בעודו שרמת regex לבדה כוחשת עליהם. הסף היה כיול על קורפוס מתויג ולא נמדד מחדש כנגד זה; עד שייעשה, שמור מדיניות **hard** כשאחת מהצורות הללו עוברת את העניין יותר מאשר בלוקים שגויים שלה. + + +| מדיניות | סמכות | בדיקה על ידי | למה | +| --- | --- | --- | --- | +| `protect-env-vars` | reviewable | `env-secrets-dump`, `secret-exposure` | התבנית עוררת בהפניה לכל משתנה; Jev שואל האם ערכי סודות בעצם יודפסו. | +| `block-env-files` | reviewable | `secret-exposure` | התבנית תואמת כל נתיב `.env`, תבניות כלולות; Jev שואל האם ערכי סודות בעצם היו נקראים או כתובים. | +| `block-read-outside-cwd` | reviewable | `read-outside-workspace` | מדוד כרועש בתנועה אמיתית; Jev שואל האם תוכני קובץ מחוץ לפרויקט נקראים. קריאה שהמשתמש בקש, או שהבדיקה לא מצאה בה כלום, מבוטלת; קריאה לא מבוקשת שהוא מדגיל שומרת את החסימה. | +| `warn-git-amend` | reviewable | `git-history-rewrite` | שינוי commit שלא דחוק הוא רגיל; הנזק הוא כתיבה מחדש של היסטוריה אחרים עשויים למשוך. | +| `warn-destructive-sql` | reviewable | `database-destruction` | Jev גם שואל האם המטרה היא מסד נתונים אמיתי ולא אחד מטיל חד-פעמי. | +| `warn-global-package-install` | reviewable | `system-modification` | אותה דאגה: שינוי המכונה מחוץ לפרויקט. | +| `block-failproofai-commands` | hard | | `alwaysOn` הגנה עצמית. לעולם לא reviewable. | +| `block-rm-rf` | reviewable | `destructive-deletion` | ההיוריסטיקה של עומק הנתיב מקבלת `rm -rf node_modules` בצורה שגויה; Jev שואל האם מה שהיה מחוסל ניתן להשגה. `rm -rf /` שומר את שתי הבדיקות true. | +| `block-sudo` | hard | | הסלמת הגעות. | +| `block-curl-pipe-sh` | hard | | מפעיל קוד שהורד מהאינטרנט. | +| `block-push-master` | hard | | דחף ישיר לענף מוגן. | +| `block-work-on-main` | hard | | `commit-on-protected-branch` מכסה בדיוק דאגה זו אך הוא instruct-mode, כך שהוא לעולם לא יכול להשיב deny, ואף בדיקה אחרת לא מכסה אותה. | +| `block-force-push` | reviewable | `git-history-rewrite` | הבדיקה של Jev היא כל ערך של המתאם וסופרת `--force-with-lease`; מה מבטל הוא force-pushing של הענף שלך. | +| `block-secrets-write` | reviewable | `secret-exposure` | התאמת הנתיב אינה עוגנת, כך `src/auth/credentials.ts` תופסת; Jev שואל האם חומר מפתח אמיתי נכתב. | +| `block-kubectl` | reviewable | `production-infra-change` | כוחש את כל ה-CLI, תתי-פקודות לקריאה בלבד כלולים; Jev שואל האם הקריאה משנה ואם המטרה היא ייצור. | +| `block-terraform` | reviewable | `production-infra-change` | אותו דבר: מבטל `terraform plan` ו-`validate`. | +| `block-aws-cli` | reviewable | `production-infra-change` | אותו דבר: מבטל `aws s3 ls`, `aws sts get-caller-identity`. | +| `block-gcloud` | reviewable | `production-infra-change` | אותו דבר: מבטל `gcloud auth list`, `gcloud config list`. | +| `block-az-cli` | reviewable | `production-infra-change` | אותו דבר: מבטל `az account show`. | +| `block-helm` | reviewable | `production-infra-change` | אותו דבר: מבטל `helm list`, `helm status`. | +| `block-gh-pipeline` | hard | | מפעיל צינורות, מיזוג ושינויים סודיים. | +| `warn-git-stash-drop` | hard | | אף בדיקה סמנטית לא מכסה הסרת עבודה מוסתרת. | +| `warn-git-clean` | hard | | `destructive-deletion` מכסה את הדאגה אך לא יכול להעיר עליה: `git clean` אינו שם נתיב, כך שהבדיקה `irreplaceable` שלו אין מה לשפוט ותשובה נמוכה, וראיות היא המינימום על בדיקות מדיניות. בדיקה ששאלו ואינה עוררת מבטלת את הפסק, כך שזיווג כאן היה כבה את המדיניות. | +| `warn-all-files-staged` | hard | | אף בדיקה סמנטית לא מכסה מה `git add` רחב בוחר. | +| `warn-schema-alteration` | hard | | `database-destruction` מכסה הנחת נתונים, לא שינוי סכימה. | +| `warn-package-publish` | hard | | ציבור בלתי הפיך ואף בדיקה סמנטית לא מכסה אותו. | +| `prefer-package-manager` | hard | | אמנה של צוות, לא שיפוט בטיחות. | +| `warn-large-file-write` | hard | | סף גודל, לא פסק שJev יכול לעשות. | +| `warn-background-process` | hard | | אף בדיקה סמנטית לא מכסה תהליכים מנותקים. | +| `warn-repeated-tool-calls` | hard | | קובע קריאות; Jev לא יכול לספור. | +| `sanitize-jwt` | hard | | גדז פלט כלי; לא שער קריאת כלי. | +| `sanitize-api-keys` | hard | | גדז פלט כלי; לא שער קריאת כלי. | +| `sanitize-connection-strings` | hard | | גדז פלט כלי; לא שער קריאת כלי. | +| `sanitize-private-key-content` | hard | | גדז פלט כלי; לא שער קריאת כלי. | +| `sanitize-bearer-tokens` | hard | | גדז פלט כלי; לא שער קריאת כלי. | +| `require-commit-before-stop` | hard | | שער השלמת הפעלה, לא שער קריאת כלי. | +| `require-push-before-stop` | hard | | שער השלמת הפעלה, לא שער קריאת כלי. | +| `require-pr-before-stop` | hard | | שער השלמת הפעלה, לא שער קריאת כלי. | +| `require-no-conflicts-before-stop` | hard | | שער השלמת הפעלה, לא שער קריאת כלי. | +| `require-ci-green-before-stop` | hard | | שער השלמת הפעלה, לא שער קריאת כלי. | + +## שמות מדיניות סמנטיות + +אלה הבדיקות `FailproofAI/jev-policies` מצהירות, וערכים `reviewedBy` מקבל ברגע שהוא מותקן. Failproof AI עצמו לא משולח שום אחד מהם: ללא החבילה הזו (או אחר המצהיר שמות אלה), אף מדיניות שמשמה אותם היא לא reviewable. כל אחד הוא בדיקה Jev עונה על קריאת הכלי בפניה. **Mode** הוא מה בדיקה יכולה להשיב: בדיקת `deny` חוסמת על ראיות חזקות, בעודו שבדיקת `instruct` רק אי פעם מתאימה. או אחד שומר את כחיש מדיניות כשהוא עורר והמשתמש לא בקש את הקריאה. **משתמש יכול לעקוף** אומר האם הבקשה המפורשת שלו האנושית מבטלת אותה. + +Jev שואל בדיוק את [בדיקות Jev](/he/policies/publish-a-pack#jev-checks-in-a-pack) חבילות מותקנות מצהירות, וגם הם שמות `reviewedBy` מקבל. שם שתי חבילות מצהירות באופן שונה מכובד לא עבור אף אחד. אחד מהשמות השש-עשרה האלה מוצהר על ידי חבילה לא מותקנת מתוך מאגר FailproofAI מתעלם בחבילה זו: הגרסה שלה אף פעם לא שאולה ולא מתחרות בשלה של FailproofAI, כך שחבילה של צד שלישי לא יכולה להפוך לבדיקה שמבטלת מדיניויות חבילת הליבה ואף לא לכבות אחת מהבדיקות הללו. רשימת חבילות לא קריאה, או חבילה שכל בדיקה שלה לא שמישה, משאירה ל-Jev כלום לשאול. + +| שם | Mode | משתמש יכול לעקוף | מה Jev בודק | +| --- | --- | --- | --- | +| `destructive-deletion` | deny | כן | מחיקה קבועה של נתונים שלא ניתן להשגה. | +| `production-infra-change` | deny | כן | שינוי תשתית חיה. | +| `git-history-rewrite` | deny | כן | כתיבה מחדש או הסרת היסטוריית git משותפת. | +| `push-to-protected-branch` | instruct | כן | דחף ישיר לענף מוגן. | +| `commit-on-protected-branch` | instruct | כן | ביצוע ישיר על ענף מוגן. | +| `secret-exposure` | deny | כן | קריאה או העתקת אישורים. | +| `credential-exfiltration` | deny | לא | שליחת סודות או קובצים פרטיים מחוץ למכונה. | +| `remote-code-execution` | deny | כן | הפעלת קוד שהורד מהאינטרנט. | +| `privilege-escalation` | deny | כן | הפעלה עם הגעות מוגברות. | +| `database-destruction` | deny | כן | הרס או שינוי מוני של נתוני מסד נתונים. | +| `read-outside-workspace` | instruct | כן | קריאת קובצים מחוץ לפרויקט. | +| `agent-config-tampering` | deny | לא | שינוי תצורת הבטיחות שלו של הסוכן. | +| `system-modification` | instruct | כן | שינוי המערכת מחוץ לפרויקט. | +| `env-secrets-dump` | instruct | כן | הדפסת סודות סביבה. | +| `external-destructive-action` | deny | כן | פעולה בלתי הפיכה דרך כלי חיצוני. | +| `external-data-egress` | instruct | כן | שליחת נתונים פרטיים לכלי חיצוני. | \ No newline at end of file diff --git a/docs/he/policies/jev-byok.mdx b/docs/he/policies/jev-byok.mdx new file mode 100644 index 000000000..45a91fe1b --- /dev/null +++ b/docs/he/policies/jev-byok.mdx @@ -0,0 +1,265 @@ +--- +title: "Jev evaluator (הביאו את המפתח שלכם)" +description: "תנו ל-Jev classifier של TypeSafe לשפוט קריאות כלים של agents שלכם מעל קרקעית regex קשה, דרך endpoint ומפתח Jev משלכם." +icon: "key-round" +--- + +מדיניות regex תואמת מחרוזות. הם לא יכולים להבחין בין `rm -rf build/` שביקשתם מ-`rm -rf ~` שהחליק לתוך תכנית, כך שהם חוסמים יותר מדי במקום אחד וקצת מדי בחזה. **Jev**, ה-classifier של TypeSafe, קורא את הקריאה מול מה שבעצם ביקשתם ועונה על סט של שאלות כן/לא עליה בבקשה אחת מהירה. + +עם endpoint ומפתח Jev משלכם מוגדרים, Failproof AI שואל את Jev על כל קריאת כלי **לצד** מדיניות ה-regex, לעולם לא במקום שלהם: + +- ה-deny של מדיניות **קשה** הוא סופי. Jev לא יכול להנקות אותו. כל מדיניות קשה אלא אם כן היא מסומנת בצורה מפורשת כ-reviewable ושמות בדיקות Jev שמכסות אותה, ולכן מדיניות custom, pack או Cloud שלא אומרת כלום היא קשה, וה-guard self-protection שתמיד פועל הוא תמיד קשה. +- ה-deny של מדיניות **reviewable** עשוי להיקבע, אך רק כאשר Jev נשאל על הדאגה המדויקת שמדיניות זו מכסה וענה "אין כאן כלום" או "המשתמש ביקש את זה". בדיקה שמוצאת את הדאגה כממשית, כאשר המשתמש לא ביקש את הקריאה, שומרת על ה-deny — אפילו כאשר הפסק שלה הוא רק אזהרה, מכיוון שלפני קריאת כלי אזהרה לא עוצרת את ה-agent. וכאשר אותה בדיקה היא כזו שיכולה להכחיש (חשיפת סודות, כניסת אישורים, מחיקה הרסנית, ...), כלום לא מוקבע על קריאה זו. +- בלוק עדיין יכול להיות **אזהרה** כאשר הקריאה היא צעד של המשימה שנתתם ולא מגיעה הלאה: Jev משנה את ה-deny שלו לאזהרה, ואותה אזהרה — המתארת מה בעצם לא בסדר עם הקריאה — מחליפה את הבלוק של המדיניות. +- Jev יכול גם להתריע או להכחיש בעצמו, על נזק שאף regex לא מתאר. +- אם Jev לא יכול לענות (timeout, rate limit, שגיאת שרת, אין credits, גרסה מודל בלתי צפויה), קריאה זו מקבלת את תוצאת ה-regex, בדיוק כמו ללא Jev. +- Jev לעולם לא הופך קריאה למאפשרת יותר מהמדיניות שלכם בלבד אלא אם קרא את כל הקריאה ונשאל על הדאגה המדויקת. הכל פחות מזה — קריאה גדולה מדי לשליחה כמכלול, injection חשוד — משוך את ההסכמות ושומר על כל ה-deny. + + +ללא הגדרת Jev כלום לא משתנה: hooks מפעילים את מדיניות ה-regex בדיוק כפי שתמיד עשו. ההגדרה היא ה-opt-in כולה. + + + +על FailproofAI Cloud? אתה לא צריך מפתח משלך: מכונה המחוברת עם מפתח שנושא `jev:evaluate` יכולה להשתמש ב-Jev בתכנית הארגון שלך. ראה [Jev through FailproofAI Cloud](/he/policies/jev-cloud). + + +## בחר ספק + +Jev ניתן להשגה דרך חמש נתיבים. הביא מפתח לכל אחד מהם. + +| ספק | `--provider` | Endpoint | מודל ברירת מחדל | הערות | +| --- | --- | --- | --- | --- | +| TypeSafe | `typesafe` | `api.typesafe.ai/v1/systemone` | `jev-1.13.0` | סיכום גרסה מדויק. | +| OpenRouter | `openrouter` | `openrouter.ai/api/v1/systemone` | `typesafe/jev-1.13` | הבקשות נתובות לנקודות קצה בעלות אפס שמירה של נתונים בלבד, ללא fallback לספק אחר. דו"ח גרסה בעלת תאריך כגון `typesafe/jev-1.13-20260917`. | +| Vercel AI Gateway | `vercel` | `ai-gateway.vercel.sh/typesafe/v1/systemone` | `typesafe-ai/jev` | שם Jev רק לפי כינוי, כך שהגרסה המשיבה נרשמת כלא מוודאת. | +| Cloudflare Workers AI | `cloudflare` | `api.cloudflare.com/client/v4/accounts//ai/run` | `typesafe/jev` | צורך `--account-id`. כ-שש קריאות בשנייה לכל מפתח נמדדו לפני HTTP 429. | +| הendpoint שלך | `custom` | `/systemone` | `jev-1.13.0` | כל endpoint המקבל את גוף הבקשה של TypeSafe ודו"ח איזה מודל ענה. `https` בלבד; `http://localhost` רגיל מתקבל בשיטת shadow בלבד. | + + +עם תכונת bring-your-own-key של Vercel, בקשה שנכשלה תיחזור שוב בשתיקה עם אישורים של Vercel. אם אתה צריך כל קריאה חויבת ונראות לחשבון TypeSafe שלך בלבד, השתמש ב-TypeSafe ישירות. + + +## הגדר את זה + +פקודה אחת, ה-endpoint והמפתח: + +```bash +failproofai jev --url https://api.typesafe.ai/v1 --key-stdin < ~/typesafe.key +``` + +### ה-URL בוחר את הספק + +אתה לא צריך לשם את הספק: **הוסט** של ה-URL הוא איזה אחד זה. + +| URL host | ספק | גם צריך | +| --- | --- | --- | +| `api.typesafe.ai` | `typesafe` | — | +| `openrouter.ai` | `openrouter` | — | +| `ai-gateway.vercel.sh` | `vercel` | — | +| `api.cloudflare.com` | `cloudflare` | `--account-id <32-hex-account-id>` | +| כל הוסט אחר | `custom` | — ה-URL שנתת הוא ה-base URL | + +שלוש דברים נובעים מזה: + +- **ה-URL של ה-API של הספק עצמו לא כותב override.** `--url https://api.typesafe.ai/v1` מייצר בדיוק את ההגדרה שיש `--provider typesafe`. תן נתיב או הוסט אחרים בספק ידוע וזה מאוחסן כ-base URL, כמו `--base-url` היה מאחסן אותו. +- **`--provider` עדיין דוחק את ההסקה**, וזו איך אתה מגיע לפרוקסי שמדבר ב-API של ספק מהוסט משלך: `--url https://jev-proxy.internal/v1 --provider typesafe`. +- **`--provider` שמתנגד להוסט מסורב**, לא ניחוש. `--provider openrouter --url https://api.typesafe.ai/v1` לא כותב כלום ואומר למה: שתי הכתיבות לא מסכימות היכן המפתח שלך עומד להישלח. אותו זוג מסורב מ-`jev setup --base-url` ומהדוח המחומד של Jev settings. (`--provider custom` אינו סתירה — זה אומר "התייחס ל-URL זה כלעצמו" — למעט בהוסט של Cloudflare, אשר מסלול custom לא יכול להגיע אל ה-endpoint per-account שלו.) + +`--url` מוודא בדיוק כמו ש-`baseUrl` בקובץ הגדרה הוא, והסרב באותם מילים: `https`, או `http://localhost` רגיל בשיטת shadow בלבד. + +### המפתח + +Pipe אותו עם `--key-stdin`, או הפעל את הפקודה בטרמינל בלעדיו והדבק את המפתח בשאילתה מוסווה. בכל מקרה הוא נכנס ישירות לקובץ ההגדרה ולעולם לא מודפס בחזרה. + + + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --key-stdin < ~/typesafe.key + ``` + + + ```bash + failproofai jev --url https://openrouter.ai/api/v1 --key-stdin < ~/openrouter.key + ``` + + + ```bash + failproofai jev --url https://ai-gateway.vercel.sh/typesafe/v1 \ + --key-stdin < ~/vercel-gateway.key + ``` + + + ```bash + failproofai jev --url https://api.cloudflare.com/client/v4 \ + --account-id <32-hex-account-id> --key-stdin < ~/cloudflare.token + ``` + + + ```bash + failproofai jev --url https://jev.internal.example.com/v1 --key-stdin < ~/jev.key + ``` + + + +`failproofai jev setup` לוקח את אותו הדגלים וזה ה-longhand לכל זה: `setup --provider ` שם היית מעדיף לשם את הספק מאשר את ה-URL. + +### `--token`, ומה זה עולה + +`--token ` שם את המפתח בשורת הפקודה, שהיא הדרך הכי מהירה להגדיר מכונה וה-spelling היחידה שמשאירה את המפתח בכל מקום אלא בקובץ ההגדרה: + +```bash +failproofai jev --url https://openrouter.ai/api/v1 --token +``` + + +ארגומנט של שורת פקודה נמצא בקובץ ההיסטוריה של ה-shell שלך לאחר מכן, וכאשר הפקודה פועלת זה נמצא ברשימת התהליכים — ניתן קריאה מ-`/proc` על ידי כל דבר שפועל כמוך. `setup` אומר כן בכל פעם ש-`--token` משמש. עדיף `--key-stdin` על מכונה שאתה משתף, בהפעלה מוקלטת, או בכל מקום שקובץ ההיסטוריה מסונכרן; סובב מפתח שהעברת בדרך זו אם זה משנה. + + +`--token`, `--key-stdin` ו-`--key-from-env` זה מוציא זה את זה: תן אחד. + +אחר כך שלח בקשה חיה אחת קטנה כדי לבדוק את המפתח, ה-endpoint ואיזה Jev ענה: + +```bash +failproofai jev test +``` + +```text + failproofai jev test ok · 523 ms + + provider cloudflare + model asked typesafe/jev + answered by jev-1.13.0 (Jev 1.13 family — verified) + latency 523 ms — within the 3000 ms timeout +``` + +`jev test` יוצא 1, ואומר כן בכותרת שלו, כאשר התשובה מגיעה לאחר ה-timeout (כל hook היה חוזר לregex כ-`timeout`) או עונה לשאלת הבדיקה שלו בצורה שגויה. + +Hooks קוראים את ההגדרה בכל קריאת כלי, ולכן זה חל מהבאה. אין כלום להתחיל מחדש, עם או בלעדי ה-daemon. + +## בדוק מה זה עושה + +```bash +failproofai jev status +failproofai jev status --json +``` + +`status` מציג את הספק, ה-endpoint, המודל, המצב, קובץ ההגדרה וההרשאות שלו, ולעולם לא את המפתח. מתחתיו זה מסכם פעילות אחרונה: כמה קריאות Jev הערך, כמה פעמים זה חזר לregex ולמה, ה-latency שלו, ואילו מדיניות reviewable זה הנקה. + +## שיטת shadow + +`enforce` הוא ברירת המחדל. כדי לצפות ב-Jev מבלי לתת לו לשנות כל החלטה, עבור ל-`shadow`: Jev עדיין נשאל וההחלטות שלו נרשמות, אך תוצאת ה-regex היא מה שנאכף. + +```bash +failproofai jev setup --mode shadow +failproofai jev setup --mode enforce +failproofai jev setup --mode off +``` + +`off` שמור על ההגדרה — ה-endpoint והמפתח — ומפסיק לשאול את Jev: hooks מפעילים את מדיניות ה-regex בדיוק כמו ללא הגדרה, ו-`failproofai jev status` אומר "off (switched off)". חזור עם `--mode shadow` או `--mode enforce`. + +הפעלה חוזרת של `setup` באותו ספק שומרת על המפתח המאוחסן, כך שתחליף מצב הוא דגל אחד. החלפת ספק מתחיל מחדש ושואל עבור המפתח של הספק הזה. כמו כן `--base-url` שמעביר בקשות לוסט אחר: מפתח מאוחסן נשלח רק להוסט שהוא ניתן עבורו, או אל ה-API של הספק שלו. + +## קובץ ההגדרה + +הכל גר בקובץ אחד, `~/.failproofai/jev.json`, כתוב על ידי `setup`: + +```json +{ + "provider": "cloudflare", + "apiKey": "", + "accountId": "<32-hex-account-id>", + "mode": "enforce", + "timeoutMs": 3000 +} +``` + +| שדה | משמעות | +| --- | --- | +| `provider` | `typesafe`, `openrouter`, `vercel`, `cloudflare` או `custom` — או `failproofai`, שלמפתח שלו מגיע מהחיבור של FailproofAI Cloud במקום קובץ זה (ראה [Jev through FailproofAI Cloud](/he/policies/jev-cloud)). | +| `apiKey` | נשלח כ-`Authorization: Bearer `. | +| `baseUrl` | נדרש עבור `custom`; מחליף את ה-API base של הספק בעל כן. חייב להיות `https`. `http` רגיל אל `localhost` מתקבל רק עם `mode: shadow`: כלום לא מאמת יציאה מקומית, כך שבעוד הפרוקסי שלך למטה כל תהליך במכונה, כולל ה-agent שנשפט, יכול לענות במקומו. | +| `accountId` | Cloudflare בלבד: 32 תווי hex קטנים. | +| `model` | מחליף את ה-model id של ברירת המחדל של הספק. ה-id של גרסה חייב לשם Jev 1.13. ערך בצורת API key סורב (ולא חוזר), כך שמפתח הדביק למעבר `--model` לעולם לא מאוחסן או נשלח כמודל. | +| `timeoutMs` | כמה זמן קריאת כלי מחכה אל Jev לפני שימוש בתוצאה regex. 100–10000, ברירת מחדל 3000. | +| `mode` | `enforce` (ברירת מחדל), `shadow`, או `off` (שמור את ההגדרה, הפעל ללא Jev). | + +שלוש כללים מגנים עליו: + +- **רק בעלים.** זה כתוב עם הרשאות `0600`. עותק שכל משתמש או קבוצה אחרת יכולה לקרוא או לכתוב הוא **סרוב**, hooks חוזרים לregex עד שתפעיל `chmod 600 ~/.failproofai/jev.json` או `setup` שוב. הספרייה בדוקה גם: `~/.failproofai` לא צריכה להיות **כתובה** על ידי מישהו אחר, כי מי שיכול לכתוב שם יכול להחליף את הקובץ כל הרשאות משלו. `setup` מסיר את הביטים כתוב אלו אם זה מוצא אותם. `failproofai jev status` אומר כאשר הגדרה סורבה ומראה את ה-endpoint שהקובץ מייצג: מישהו אחר יכול היה לשנות אותו, כך לבדוק זה שלך לפני שתוביל `chmod`. הפעלה חוזרת של `setup` על קובץ כזה נושאת את המפתח המאוחסן שלו רק אל ה-API של הספק; כל endpoint אחר שהוא שם צריך את המפתח שוב (`--key-stdin`), או `--base-url default` לשלוח בקשות חזרה אל הספק. +- **גלוברי בלבד.** מאגר לא יכול להפעיל את Jev, להצביע עליו בendpoint אחר או לבחור את המודל שלו: `.failproofai/jev.json` בתוך פרוייקט מתעלם, והספק, ה-URL, המודל והמזהה החשבון נקראים רק מקובץ זה — לעולם לא מהסביבה, שהגדרות agent של מאגר יכולות להגדיר. (`FAILPROOFAI_HOME` אינו דרך סביב זה: זה מעביר את כל ספריית failproofai, המדיניות שלך כלול, במקום להפנות Jev בעצמו.) +- **רק המפתח לבדו יכול להגיע מהסביבה.** אם לקובץ אין `apiKey`, `FAILPROOFAI_JEV_API_KEY` מספק אותו לאותה הפעלה (`setup --key-from-env` כותב קובץ כזה). זה לעולם לא מחליף מפתח שהקובץ מחזיק, וזה לא יכול להפעיל את Jev ללא הקובץ. כאשר המשתנה לא מוגדר, Jev היא פשוט כבוי עבור אותה מעטפת: `failproofai jev status` אומר כן, יוצא 0 ועוזב את ההגדרה לבדה (`status --json` מדווח `"status": "key-missing"` עם `"reason": "no-env-key"`). ה-daemon `failproofaid` לא רואה את סביבת ה-shell שלך, כך על מכונה המגודרת עם `failproofai config`, שמור את המפתח בקובץ. + +## איזה Jev עונה + +סף ההחלטה של Failproof AI כויל על Jev 1.13, כך תשובה משמשת רק כאשר היא מגיעה מאותה משפחה: `jev-1.13.x`, או OpenRouter של `typesafe/jev-1.13-`. כאשר ספק שם Jev רק לפי כינוי וא דו"ח ללא גרסה (Vercel, ו-Cloudflare כאשר זה לא אומר), התשובה משמשת ונרשמת כלא מוודאת. `custom` endpoint חייב לדווח את המודל שענה; החריג היחידי הוא `--model` שם לא גרסיון שהגדרת עבורו, אשר, הד בחזרה, נרשם כלא מוודא באותו הדרך. תשובה המדווחת כל גרסה אחרת, או תשובה `custom` שלא מדווחת כלום, אינה משמשת: קריאה זו חוזרת לregex עם הסיבה `model-mismatch`. + +## כאשר Jev לא יכול לענות + +כל אחד מאלה חוזר לתוצאת ה-regex עבור קריאה זו ורשום עם הסיבה שלו, אשר `failproofai jev status` סכומים: + +| סיבה | גורם | +| --- | --- | +| `timeout` | אין תשובה בתוך `timeoutMs`. | +| `http-429` | הספק rate-limited את המפתח. | +| `rate-limited` | ה-limiter של Failproof AI שלו עצר את הקריאה חזרה לפני שליחה: 5 בקשות בשנייה, בפרצים של עד 5, ואף אחד לרגע לאחר שהספק עונה `429`. לא הספק. | +| `http-500`, `http-502`, `http-503`, … | שגיאת שרת בספק. הסטטוס המדויק נרשם. | +| `out-of-credits` | HTTP 402: לחשבון הספק אין credits נותרו. | +| `provider-refused` | HTTP 402 מ-Cloudflare קריאה "Model execution failed (Payment error)": הספק סירב להריץ את המודל בבקשה זו. בדרך כלל לא חיוב, כך טעינה תזיז אותו. | +| `http-401`, `http-403` | המפתח סורב. | +| `http-404` | כלום לא משמש ב-`/systemone`, כך ה-base URL לא בסדר — `/systemone` מוסף אליו, וכל ספק משמש אותו בשורש גרסה שלו. `failproofai jev models` מציג מה ה-endpoint כן משרת. | +| `network` | לא היה אפשר להגיע ל-endpoint. | +| `http-301`, `http-302`, `http-307`, `http-308` | ה-endpoint ענה עם redirect. Redirects לא מעקבים, כך התשובה באה רק מה-URL בהגדרה שלך; קבע `--base-url` ל-URL הסופי. | +| `malformed` | ה-endpoint ענה, אך לא עם תשובה Jev — גוף שאינו JSON, או אחד בלא תשובות בו. | +| `cloudflare-error`, `cloudflare-incomplete` | מעטפת של Cloudflare דיווחה כשל, או עבודה שלא הסתיימה. | +| `model-mismatch` | גרסה Jev אחרת מ-1.13 ענתה, או `custom` endpoint לא אמר איזה מודל ענה. | +| `request-cut` | **לא הפסקה.** Jev ענתה; זה הוצג רק חלק מהקריאה, כך התשובה שלו נקתה כלום. ראה [כאשר Jev ענתה, אך לא על הקריאה כולה](#when-jev-answered-but-not-on-the-whole-call). | + +`failproofai jev status` יכול להציג כמה סיבות נדירות יותר גם כן, כגון `upstream-error` (התשובה נשאה את השגיאה של הספק שלו) או `config`, וסכומים כל סיבה שהוא לא יכול לשם כ-`other`. + +`request-cut` נמצא בטבלה זו כי `failproofai jev status` סוכם אותו עם השאר, ובגלל שגם זה משאיר כל ה-deny עומדות. זה סיבה היחידה כאן שלא אומרת כלום על הספק שלך: הבקשה הגיעה ו-Jev ענתה לה. בניגוד לכל שורה מעליו, התשובה הזו עדיין סופרת — ה-deny או ה-warning של Jev יחול על גבי תוצאת ה-regex במקום להיות מושלכת. כך ריצה של אלה אומר קריאות מגיעות להערך גדולה מדי לשליחה כמכלול, לא שה-endpoint שלך לא בסדר, וטעינה של credits או שינוי ה-URL לא יזיז את המספר. + +## כאשר Jev ענתה, אך לא על הקריאה כולה + +שני דברים נוספים יכולים לקרות, ואף אחד לא Jev כושל לענות. שניהם על כמה מהקריאה, או מהשיחה, התאימה לבקשה אחת. + +**חלק מהקריאה עצמה לא התאימה.** קריאה כלי נשלחת בתוך תקציב קבוע, וחריגה — `Write` גדולה מאוד, גוף MCP עצום, פקודה מרופדת עד הכיפה — נשלחת עם מה התאים. Jev עדיין עונה, והתשובה שלו עדיין סופרת: ה-deny או ה-warning שלו יחול כרגיל. מה זה לא יכול לעשות זה **קבוע** כלום, מכיוון שפסק נתון בחלק מקריאה אינו פסק בקריאה. כך כל ה-deny מדיניות עומדות, והקריאה נרשמת כ-fallback עם הסיבה `request-cut`, אשר `failproofai jev status` סוכמים לצד הסיבות לעיל. הכלל זה נותן לך: הגדלת קריאה יכול להוציא את ההסכמות שלו, וא פעם לא יכול לקנות אחד. + +**הודעה לא התאימה.** ביצוע ארוך שהדקת, הודעת ה-agent האחרונה, או פקודה מערך האחסון שלה הערך כבר כיפה. **כלום לא משתנה**: הקריאה נשפטת, נקתה ורשומה בדיוק כמו כל אחד אחר, וזה לא סופר כ-fallback. האורך של מה שאתה הקלדת לעולם לא מחליט אנו פסק, וקית לא יכול לייצור הסכמה: שם ביצוע הגיע כבר כיפה, "אתה לא ביקשת את זה" מפסיקה להיות מסקנה שיכול להיות מוצא ממנו בכלל, במקום להפוך לאחד. + +הקו בין השניים הוא מי כתב את הטקסט. הקריאה היא ה-agent, וכלל שתן אורך שלו להפחית חומרה יהיה כלל ה-agent יכול להשתמש; ביצוע שלך שלך, וטיפול באורך שלו כאות רק פעם אחת הענש הדביק מפרט או עקבת ערימה. + +## מה עוזב את המכונה + +עבור כל קריאה כלי Jev מערכי, בקשה אחת יוצא לספק שלך, נושא: + +- הקריאה עצמה, עם סודות כגון API keys, bearer tokens ו-`KEY=` הקצאות redacted; +- הביצוע הקרוב שהקלדת, עם טקסט ה-agent harness הוסיף הוסר; +- הודעת ה-agent האחרונה לפני הביצוע הקרוב שלך, מתויג כ-agent-written; +- עובדות מחושבות מקומי, כגון האם נתיב בתוך הפרוייקט — זה הפעלה במפגש שלה הראשון בדוק בדוק, [pinned לפעלה](/he/reference/jev-intent#the-project-root) — וסניף git הנוכחי. + +זה יוצא רק ל-endpoint בהגדרה שלך, תחת המפתח שלך. + +## כבה אותו + +```bash +failproofai jev remove +``` + +זה מחוק `~/.failproofai/jev.json`. מהקריאה הכלי הבאה, hooks מפעילים את מדיניות ה-regex בדיוק כמו לפני. ה-per-session מאחסן תחת `~/.failproofai/state/semantic/` (ביצוע נרשם ב-`sessions/`, שורשי פרוייקט ב-`roots/`) נשאר במקום וגיל החוצה. כדי להפסיק לשאול את Jev אך שמור את ההגדרה, השתמש `failproofai jev setup --mode off` במקום. + +## התייחסות לפקודה + +| פקודה | תוצאה | +| --- | --- | +| `failproofai jev --url --key-stdin` | הגדר אותו בפקודה אחת; הספק בא מהוסט של ה-URL | +| `failproofai jev --url --token ` | זהה, עם המפתח בשורת הפקודה — ההיסטוריה והרשימת התהליכים שלך ראה זה | +| `failproofai jev setup --provider --key-stdin` | כתוב את ההגדרה מ-key piped על stdin | +| `failproofai jev setup --provider ` | זהה, שאילתה עבור המפתח בשאילתה מוסווה | +| `failproofai jev setup --key-from-env` | אל תאחסן מפתח; קרא `FAILPROOFAI_JEV_API_KEY` לכל הפעלה | +| `failproofai jev setup --mode shadow` | חלופי מצב (`enforce`, `shadow` או `off`), שמור את המפתח המאוחסן | +| `failproofai jev setup --model ` / `--base-url ` | דרוס את המודל או ה-API base; `default` מנקה את הדרוס | +| `failproofai jev setup --timeout-ms ` | שנה את התקציב לכל קריאה | +| `failproofai jev status [--json]` | הגדרה, הרשאות ופעילות אחרונה; לעולם לא את המפתח | +| `failproofai jev test [--json]` | בקשה חיה אחת: latency וגרסה שענתה | +| `failproofai jev models [--provider ] [--url ] [--json]` | ה-model ids ש-`/models` של ה-endpoint מדווח, סימון ה-configured | +| `failproofai jev remove` | מחוק את ההגדרה; Jev כבוי | \ No newline at end of file diff --git a/docs/he/policies/jev-cloud.mdx b/docs/he/policies/jev-cloud.mdx new file mode 100644 index 000000000..5503fe569 --- /dev/null +++ b/docs/he/policies/jev-cloud.mdx @@ -0,0 +1,117 @@ +--- +title: "Jev דרך FailproofAI Cloud" +description: "תן ל-Jev לשפוט את קריאות הכלים של האגנטים שלך דרך FailproofAI Cloud, בתוכנית של הארגון שלך, ללא חשבון TypeSafe או מפתח משלך." +icon: "cloud" +--- + +[Jev](/he/policies/jev-byok), המסווג של TypeSafe, קורא כל קריאת כלי מול מה שבאמת ביקשת וענה בצד המדיניות שלך, לעולם לא במקומן. דרך **FailproofAI Cloud**, מכונה מחוברת משתמשת ב-Jev עם אותו מפתח שבו היא כבר מתחברת: אין חשבון TypeSafe, אין מפתח שני, אין נקודת קצה להגדרה. כל קריאה מחויבת לקצבת התוכנית הקיימת של הארגון שלך. + +הכל שב-Jev עושה זה ללא שינוי מ[הגדרת הבאת-המפתח-שלך-שלך](/he/policies/jev-byok): מדיניות קשה נשארת סופית, הכחשון של מדיניות שניתן לבדוק מתבטל רק כאשר ל-Jev נשאלו בדיוק על אותה חשש, וכל כישלון חוזר לתוצאת regex עבור אותה קריאה. + + +דורש **failproofai 1.0.8-beta.0** או מאוחר יותר. ב-1.0.7 אין Jev, גם אם הוא מסתדר מעל ה-1.0.7 betas. ללא תצורת Jev שום דבר לא משתנה: hooks מריצים את מדיניות regex בדיוק כפי שתמיד עשו. + + +## הפעל זאת + +1. **צור מפתח עם Jev.** בלוח הבקרה של FailproofAI Cloud, פתח **Keys → Create key** ובחר בתשקול **machine**. הוא מעניק את שלוש ההרשאות שמכונה צריכה: `events:add` (שלח פעילות), `policies:pull` (קבל מדיניות) ו-`jev:evaluate` (Jev, מחויב לתוכנית של הארגון שלך). מפתח לא יכול לשאת `jev:evaluate` ללא השניים האחרים. +2. **חבר את המכונה** עם אותו מפתח: + + ```bash + failproofai config --token + ``` + + אם הארגון שלך מריץ את FailproofAI Cloud שלו בעצמו ולא את זה המתארח, הוסף את הכתובת שלו: `--url https://` (או יצא `FAILPROOFAI_CLOUD_URL`). ללא זה המפתח מוצפן בשירות המתארח וההתחברות נכשלת. אם התעודה של אותו מארח מגיעה מ-CA פרטית, התקן את ה-CA בחנות האמון של המערכת של המכונה (לדוגמה עם `update-ca-certificates`), לא רק ב-`NODE_EXTRA_CA_CERTS`: ה-daemon ששולח אירועים וקולע מדיניות קורא את חנות המערכת. ראה [Troubleshooting](/he/reference/troubleshooting). + +זה הכל. התחברות שומרת את המפתח וכאשר למכונה **אין** תצורת Jev עדיין, מפעילה Jev דרך FailproofAI Cloud במצב **shadow**: Jev נשאל על כל קריאת כלי סגור וגזרי הדין שלו מתועדים, אבל התוצאה של המדיניות שלך היא מה שמוכן. הפלט אומר כך: + +```text + Jev on through FailproofAI Cloud, in shadow mode: logged, not enforced (~/.failproofai/jev.json). +``` + +**עם `--no-transcripts`, התחברות לא מפעילה Jev.** Jev שולח כל קריאת כלי בדוקה ואת ההנמקה האחרונה ל-FailproofAI Cloud, שזה יותר מחיבור החלטות בלבד שנשאל לשלוח. המפתח עדיין מאוחסן, והפלט אומר ש-Jev זמין והיכן להחליף אותו: + +```bash +failproofai jev setup --provider failproofai +``` + +זה גם לא מכבה את Jev. אם ה-`jev.json` של המכונה כבר מריץ את Jev דרך FailproofAI Cloud, הוא נשאר כשהוא, והפלט אומר שJev עדיין שולח כל קריאת כלי בדוקה והנמקה אחרונה, וש-`failproofai jev setup --mode off` מכבה אותו. + + +התחברות **לעולם לא משכתבת** `~/.failproofai/jev.json` קיים. אם אתה כבר משתמש בנקודת הקצה של Jev שלך, היא ממשיכה להיות בשימוש, והפלט אומר שהקובץ הושאר כמו שתצורן — וכאשר הקובץ הזה משאיר את Jev כבוי (סירוב, או מודגש כבוי), אומר כך והיכן לתקן. להחליף מכונה זו ל-FailproofAI Cloud, הרץ `failproofai jev setup --provider failproofai`. + + +## צל, אכוף או כבוי + +התחל בצל, צפה מה Jev היה עשוי על דף המדיניות, ואז תן לו לפעול: + +```bash +failproofai jev setup --mode enforce # Jev's verdicts apply: it may clear a reviewable deny and add its own +failproofai jev setup --mode shadow # Jev is asked and logged; your policies' result is enforced +failproofai jev setup --mode off # keep the config, stop asking Jev +``` + +אותו מתג נמצא בלוח הבקרה המקומי: **Settings → Jev** יש מתג הפעלה/כיבוי וצל/אכוף. הוא משכתב את המצב ולא יותר מכך. Hooks קוראים את התצורה בכל קריאת כלי, כך ששינוי חל מהבא, ללא הפעלה מחדש. + +## בדוק מה היא עושה + +```bash +failproofai jev status +failproofai jev test +``` + +`status` מציג את הספק כ-**FailproofAI Cloud**, מארח ה-Cloud שאליו התחברה המכונה, המצב, ומקור המפתח כ-**FailproofAI Cloud connection**, לעולם לא המפתח. כאשר `jev.json` של FailproofAI Cloud נמצא במקום אבל Jev לא יכול להריץ, הוא אומר למה: + +| `status` אומר | `status --json` | משמעות | +| --- | --- | --- | +| **off — no Jev key is stored for this machine's FailproofAI Cloud connection** | `key-lacks-jev` | המכונה מחוברת, אבל אין מפתח Jev שמור בשבילה: המפתח חסר `jev:evaluate`, או ההתחברות לא הצליחה לאשר. הרץ `failproofai config --token ` שוב עם אותו מפתח; אם היא חסרה את ההרשאה, השתמש במפתח **machine**. | +| **off — this machine is not connected to FailproofAI Cloud** | `not-connected` | אין חיבור FailproofAI Cloud על מכונה זו שמפתח Jev שייך אליו. | + +לאחר `failproofai config --disconnect` אין עוד `jev.json` של FailproofAI Cloud (אלא אם כן הוא הודגש כבוי, שנשמר), כך ש-`status` פשוט דיווח על Jev כבוי. `status --json` נושא את אותם עובדות (`provider: "failproofai"`, `keySource: "cloud"`, `cloudConnected`, `keyCarriesJev`), גם כאשר התצורה היא הנעדרת או מורחקת. `permissions` הוא תמיד של `jev.json`; סירוב בנוגע ל-`credentials.json` מוסיף `credentialsPermissions`, ו-`fix` כאשר פקודה אחת תיקנה. `test` שולח בקשה חיה אחת וממציא את ההשהיה שלה וגרסת Jev שענתה. הוא יוצא 1, ויאמר כך בכותרת שלו, כאשר התשובה מגיעה לאחר timeout של hook (hooks היו רושמים `timeout`) או עונה לשאלת הבדיקה שלו בעיוות. + +לוח הבקרה של **Settings → Jev** מציג גם את **FailproofAI Cloud connection**: אילו ארגון המכונה דיווח אליו והאם המפתח שלו נושא Jev. הוא נקרא מהקבצים שלו של המכונה, ללא קריאת רשת. + +## מה מגיע לדף המדיניות + +המכונה כבר שולחת את פעילות ה-hook שלה ל-FailproofAI Cloud (`events:add`). עם Jev כן, רשומת כל קריאה סגורה אומרת גם איזה מעריך רץ, מה Jev החליט, אילו מדיניות הוא פנה, למה הוא חזר כשהוא עשה, ההשהיה שלו וה-model שענה — החלטות, קודים ושמות, לעולם לא הפקודה או ההנמקה שלך. בדף **Policies** של הארגון שלך: + +- קריאה שגזר הדין שלו של Jev הוא החליט (enforce mode) מיוחסת ל-**Jev**, וכאשר הבדיקה המחליטה באה מחבילה, הרשומה גם שם את החבילה ההיא וגרסה שלה; +- במצב צל, הכחשון או אזהרה של Jev מופיעים כ-**would-have**, לצד הרוליות שאתה מצפה; +- המדיניות שJev פנה, או היה פונה במצב צל, נספרות למדיניות. + +## כאשר Jev לא יכול לענות + +כל אחד מאלה חוזר לתוצאת המדיניות שלך עבור אותה קריאה, ורשום עם הסיבה שלו: + +| סיבה | סיבה | +| --- | --- | +| `out-of-credits` | הארגון שלך השתמש בקצבת התוכנית שלו. | +| `http-401`, `http-403` | המפתח בוטל, או לא נושא `jev:evaluate`. התחבר מחדש עם מפתח שעושה. | +| `http-429` | FailproofAI Cloud הוא הגבלת שיעור Jev בעבור הארגון שלך. עד שהזמן שהוא שואל עליו הוא מתום (שלו `Retry-After`, לכל היותר 60 שניות), המכונה לא שולחת לו כלום וכל קריאה חוזרת מייד. קריאות המתעכבות בדרך זו רשומות כ-`http-429`, או כ-`rate-limited` כאשר הגבלת השיעור של המכונה שלה מחזיקה אותן קודם לכן. | +| `http-429` (daily limit) | הארגון שלך השתמש בקריאות Jev היומיות שלו: **10,000 לכל יום UTC**, אלא אם כן מי שמתחזק את FailproofAI Cloud שלך קבע גבול אחר. כל קריאה חוזרת עד שהספירה מתאפס ב-00:00 UTC; המכונה עדיין שואלת שוב לכל היותר פעם בדקה, כך שהיא בוחרת את ההגדרה מחדש בתוך דקה. `failproofai jev test` אומר "Daily Jev limit for this org reached; resets at 00:00 UTC." | +| `http-422` | Jev סירב בקשת קריאה זו, בדרך כלל משום שקריאת הכלים הכילה טקסט צפוף (base64, hex, minified code) מעל תקציב הטוקן של Jev. אותה קריאה חוזרת בכל פעם; זה לא הפסקה. | +| `http-502` | Jev אינו זמין כרגע. | +| `http-503` | ה-Cloud זה לא יכול לשרת Jev בעבור ה-org שלך: אין שער מודל, ארגון שעדיין לא סופק, או השער כבוי. שאל את ה-admin שלך; hooks שואלים שוב לכל היותר פעם בדקה. | +| `http-404` | FailproofAI Cloud זה לא משרת Jev עדיין. | +| `timeout` | אין תשובה בתוך `timeoutMs` (ברירת מחדל 3000). | +| `model-mismatch` | גרסת Jev אחרת מאשר 1.13 ענתה. | + +## איפה המפתח חי, ולאן הוא הולך + +- המפתח מאוחסן פעם אחת, ב-`~/.failproofai/credentials.json` (`0600`, בספריה בבעלות בלבד), לצד עדויות FailproofAI Cloud אחרות. `jev.json` לא מחזיק מפתח לנתיב זה; אחד שנכתב שם הופך את התצורה לבלתי תקפה. +- אם `credentials.json` נושא **כל** הרשאה לכל אחד מלבדך (קבוצה או אחר, קרא או כתוב), או שספריית הספריה שלה ניתנת **כתיבה** על ידי מישהו מלבדך, היא **מורחקת**, לא קרא, ו-Jev כבוי עד שתתקן: `chmod 600` בקובץ, `chmod 700` בספריה (או התחבר מחדש, שמשכתב את הקובץ ב-`0600` ועושה את הספריה בעלות בלבד). ספריה שאחרים יכולים רק לקרוא היא בסדר; אחד שיכולים לכתוב בו מאפשר להם להחליף את הקובץ. +- המפתח סופר רק בעוד ההתחברות שהגיעה איתו נמצאת על המכונה: עדות מדיניות או דיווח בעבור FailproofAI Cloud **עם אותו מפתח**, באותו קובץ. מפתח Jev שנשאר מאחור ללא אחד אינו מתעלם, ו-Jev נשאר כבוי. זה קורה כאשר ה-`config --disconnect` של failproofai קדום משאיר את מפתח Jev במקום (הוא לא יודע להסיר אותו), או כאשר ה-`config --token` של failproofai קדום מתחבר עם מפתח אחר, שעל FailproofAI Cloud אולי שייך לארגון אחר. להחליף את Jev חזרה, התחבר שוב עם מפתח **machine**. +- המפתח לעולם לא משולח אלא למוצא ה-Cloud שהוא אומת נגדו. `jev.json` המכוון לכל מקום אחר מורחק. +- **אגנט על המכונה יכול לקרוא אותו.** `credentials.json` הוא בעלות בלבד, והאגנט רץ בבעלות ההיא. קריאת הקבצים שלו של failproofai עצמו מורשה בכוונה (רק שינוי אותם חסום, על ידי `block-failproofai-commands`), כך שהדבר היחיד בין אגנט לקובץ זה הוא `block-read-outside-cwd` — מדיניות **reviewable** — ומ-session שהחל בספריית הבית שלך, לא כלום. מפתח עם `jev:evaluate` מוציא את קצבת Jev של הארגון שלך (עד לכובעון היומי) מכל מקום בו הוא משמש, אז טרט מפתח מכונה כמו כל אישור הוצאות אחרות: אם אגנט אולי קרא אותו, בטל אותו בדף המפתחות וההתחברות מחדש עם מפתח חדש. +- רק הקבצים הגלובליים שלך קובעים זאת. מאגר לא יכול להפעיל Cloud Jev, להצביע לו במקום אחר או לספק את המפתח שלו, ו-`FAILPROOFAI_JEV_API_KEY` מתעלם לנתיב זה. +- עבור כל קריאה Jev מעריך, בקשה אחת הולכת ל-FailproofAI Cloud, נושאת מה שדף [bring-your-own-key](/he/policies/jev-byok#what-leaves-the-machine) מפרט (סודות מעדכנים). FailproofAI Cloud משדרת אותו ל-TypeSafe ולא רושמת או שומרת אותו. + +## כבה זאת + +| פקודה | תוצאה | +| --- | --- | +| `failproofai jev setup --mode off` | שמור את התצורה; Jev לא נשאל. **זה המתג שנמשך:** התחברות שוב לעולם לא משכתב `jev.json` קיים, כך ש-Jev נשאר כבוי עד שתהפוך אותו חזרה עם `--mode shadow`. | +| `failproofai jev remove` | מחק `~/.failproofai/jev.json`; Jev כבוי — עד ל-`failproofai config --token` הבא עם מפתח שנושא `jev:evaluate`, שמוצא לא `jev.json` ומפעיל Jev שוב במצב צל (אלא אם כן הוא רץ עם `--no-transcripts`). כדי להשאיר אותו כבוי, השתמש ב-`--mode off`. | +| `failproofai config --disconnect` | נתק את המכונה: המפתח מוסר, וכך גם `jev.json` כאשר הוא שם את FailproofAI Cloud ולא הודגש כבוי. `jev.json` בעבור נקודת הקצה שלך נשארת, וגם אחד הודגש כבוי, אז Jev נשאר כבוי כאשר אתה מתחבר שוב. | + +מהקריאה הבאה של הכלי, hooks מריצים את מדיניות regex בדיוק כמו לפני. \ No newline at end of file diff --git a/docs/he/policies/jev.mdx b/docs/he/policies/jev.mdx new file mode 100644 index 000000000..4b64ad469 --- /dev/null +++ b/docs/he/policies/jev.mdx @@ -0,0 +1,45 @@ +--- +title: "מדיניות Jev" +description: "הוסף ביקורת חי של Jev לקריאות כלים מוגבלות, ואז בדוק זאת לפני אכיפת ההחלטות שלה." +icon: "shield-check" +--- + +Jev קורא קריאת כלי כנגד מה שהאדם ביקש מהסוכן לעשות. השתמש בה כאשר מדיניות התאמת מחרוזות חוסמת עבודה תקפה או מפספסת פעולה מסוכנת הדורשת הקשר. היא משיבה יחד עם המדיניויות שלך בשער `PreToolUse` או `PermissionRequest`. לדירוג **לאחר** שהפגישה מסתיימת, השתמש ב[הערכות Jev](/he/evaluations/jev). + +## התחל במצב צפייה + +התקן את failproofai והצמד hooks ל[harness נתמך](/he/reference/harnesses). השתמש ב-failproofai 1.0.8-beta.0 או מאוחר יותר. + +failproofai משודר ללא בדיקות Jev. התקנו כחבילה, או ל-Jev אין מה לשאול ולעולם לא תיקרא: + +```bash +failproofai policies add FailproofAI/jev-policies +``` + +לאחר מכן בחר כיצד בקשות מגיעות ל-Jev: + +| ניתוב | שלב ראשון | +| --- | --- | +| FailproofAI Cloud | התחברו עם מפתח **machine** הנושא `jev:evaluate`. במכונה ללא הגדרת Jev, `failproofai config` מפעילה את Jev במצב צפייה. | +| הספק שלך | בדashboard המקומי, פתח **Settings → Jev**, בחר את הספק, הדבק את ה-token שלו, ובחר **observe**. או הריץ `failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key`. | + +![הגדרות Jev של ה-dashboard המקומי: ספק, endpoint, token, ומצב צפייה לפני הפעלת Jev.](/images/dashboard/jev-settings.png) + +```bash +failproofai jev status +failproofai jev test +``` + +`test` בודק את ה-endpoint. כדי לבדוק את נתיב ה-hook, בקש מסוכן מחובר להשתמש בכלי קריאת הקבצים שלו על `README.md`. אשר שקריאת הכלי הזו מופיעה בפגישה, ואז בדוק **Policies → Activity** ב[dashboard המקומי](/he/reference/local-dashboard#review-policy-activity). ספירת ה-Jev ב-`status` צריכה להגדיל. מצב צפייה רושם מה היה Jev החליט בזמן שתוצאת המדיניות הקיימת שלך עדיין חלה. + +## החלט מתי לאכוף + +מדיניות **קשה** תמיד יש את הטענה הסופית. Jev עשויה לפשר deny רק ממדיניות שמסומנת בחירוץ **reviewable** וגם רק כאשר היא בדקה את הדאגה הנקובה של אותה מדיניות. ראה [policy authority](/he/policies/authority) לפני הסתמכות על שחרור. Jev יכולה גם להזהיר או לכחול בעצמה. אם היא לא יכולה לענות, תוצאת המדיניות מחליטה על קריאה זו. + +ברגע שתוצאות הצפייה נראות נכונות, עבור למצב אכיפה ב-**Settings → Jev** או הרץ: + +```bash +failproofai jev setup --mode enforce +``` + +לכתובות ספקים, מפתחות Cloud, הגדרה, fallbacks, ונתונים המשלחים עם כל בקשה, ראה את [הפניית שילוב Jev](/he/reference/jev). \ No newline at end of file diff --git a/docs/he/reference/custom-agents-typescript.mdx b/docs/he/reference/custom-agents-typescript.mdx new file mode 100644 index 000000000..b701aa150 --- /dev/null +++ b/docs/he/reference/custom-agents-typescript.mdx @@ -0,0 +1,401 @@ +--- +title: "Custom agents (TypeScript)" +description: "Configuration, the event catalog, the scopes and the framework adapters for @failproofai/sdk." +icon: "square-js" +--- + +מה שכל הגדרה, שיטה ושדה עושים ב-SDK של TypeScript. אם אתה מכליל בפעם הראשונה, התחל עם המדריך — דף זה מיועד לחיפוש דברים. + + + + התקנה, כלול, שיטות האירועים, דוגמה עבודה, ובעיות נפוצות. + + + אותם אירועים, אותו פורמט חוט, אותו ספול — מ-Python. + + + +Node 20.9 ואילך. ESM ו-CommonJS. ללא תלויות זמן ריצה. + + + SDK זה וה-Python כותבים **אותם אירועים לאותו ספול**. צי עם סוכנים Node וסוכנים Python מייצר קבוצה אחת של סשנים, לא שתיים, והשום דבר בלוח המחוונים לא מבחין ביניהם. בחר לפי שירות, לא לפי חברה. + + +## Install + +```bash +npm install @failproofai/sdk +``` + +```ts +import * as failproofai from "@failproofai/sdk"; + +await failproofai.agent("planner", { goal: question }, async () => { + const hits = await failproofai.toolCall("web_search", { input: { q } }, () => search(q)); +}); +``` + +מתאמי הפריימוורק משלחים בחבילה עצמה. הפריימוורקים הם **תלויות עמיתות אופציונליות** — מוצהרות כך שהטווחים הנתמכים גלויים, לעולם לא מותקנים בשמך, ויובאו רק כאשר אתה קורא ל-`instrument()`. + +## Connect the Failproof daemon + +זהה ל-SDK של Python: צור מפתח `events:add` תחת **Admin → Keys**, ואז [חבר את ה-daemon](/he/start/setup#connect-a-machine-to-cloud) במכונת הסוכן. ה-SDK כותב לדיסק; ה-daemon משלח. + +## Configuration + +```ts +failproofai.configure({ + environment: "production", + flushInterval: 0.5, + baseDir: undefined, +}); +``` + +| Option | What it does | +| --- | --- | +| `environment` | התווית בכל אירוע — `production`, `staging`, `prod-eu`. ברירת מחדל היא `dev`. | +| `flushInterval` | כמה פעמים הטיימר כותב לדיסק, בשניות. ברירת מחדל היא `0.5`. | +| `baseDir` | איפה לכתוב. ברירת מחדל היא ספול ה-daemon, שזה מה שאתה רוצה אלא אם אתה יודע אחרת. | + +כלום לא מוחל אלא אם הכל תקף, כך שקריאה דחויה משאירה את ה-SDK בדיוק כמו שהוא היה ולא עם `baseDir` חדש והמרווח הישן. + +הגדר לפי משתנה סביבה במקום: + +| Variable | What it does | +| --- | --- | +| `AGENTEYE_ENVIRONMENT` | מגדיר `environment` ללא שינוי קוד. אפשרות `configure()` תנצח עליה. | +| `FAILPROOFAI_HOME` | מעביר את שורש Failproof AI המחזיק את הספול. | +| `FAILPROOFAI_SDK_LOG_LEVEL` | `debug`, `info`, `warn` (ברירת מחדל), `error`, `silent`. | +| `FAILPROOFAI_SDK_STRICT` | `1` גורם לשגיאות כלול לזרוק במקום להיות מנוסחות. | +| `FAILPROOFAI_SDK_STRICT_INTEGRATIONS` | `1` גורם לבעיית תאימות פריימוורק לזרוק במקום להזהיר ולהמשיך. | + + + **ללא פסיקים ב-`environment`.** Ingest מפצל את השדה הזה בפסיקים כדי לבנות את המסננים שלו, וקופץ על כל אירוע שהתווית שלו מכילה אחד — אז ריצה שלמה נעלמת בשתיקה. כתוב `prod-eu`, לא `prod,eu`. + + `configure({ environment: "prod,eu" })` זורק כך שתגלה מיד. `AGENTEYE_ENVIRONMENT` לא יכול לזרוק — כלום לא קורא אליך — אז זה מזהיר פעם אחת ונופל בחזרה ל-`dev`. + + +התיל קווי רישום ה-SDK שלו לתוך ה-logger שלך עם `failproofai.setLogger({ debug, info, warn, error })`. + +## Shutdown + +אירועים בבאפר נשטפו ב-`process.on("exit")`. + +תהליך שנהרג בסימן לעולם לא מגיע לזה, וברירת המחדל של Node ל-`SIGTERM` היא להסתיים ללא הפעלת מטלות יציאה — אז סוכן בקונטיינר מאבד כל מה שהמרווח האחרון לא כתב. + + + **SDK זה לא יתקין מטפל אות עבורך.** הרשמת אחד משנה את התנהגות התהליך שלך: מאזין משתיק את ברירת המחדל של Node להיסתיים, כך שספריה שהוספה אחת תשתיק בשתיקה את ה-Ctrl-C מלעבוד. הוסף שלך: + + ```ts + for (const signal of ["SIGINT", "SIGTERM"] as const) { + process.once(signal, () => { + failproofai.flushSync(); + process.exit(0); + }); + } + ``` + + +סקריפט קצר או מטפל serverless צריך `await failproofai.flush()` לפני ההחזרה — המרווח לבדו לא מבטיח משלוח. + +## Identity + +כל אירוע שייך לסשן וסוכן. **ההיקפים ממלאים שניהם**, אז אתה רק לעתים רחוקות עובר אותם: + +```ts +await failproofai.session(async () => { + await failproofai.agent("planner", async () => { + failproofai.event.toolUse({ toolName: "search", toolCallId: "c1" }); + }); +}); +``` + +ההעברה של `sessionId` או `agentId` בעליל עדיין עובדת ותנצח. ללא גבול וגם לא עבר, הקריאה זורקת במקום לפלוט אירוע ש-Cloud יחמוק בשתיקה. + + + Identity רוכב על `AsyncLocalStorage`. זה עוקב אחר `await`, `.then()`, טיימרים וכל callback שנוצר בתוך ההיקף. זה **לא** עוקב אחר callback שנשמר במהלך ריצה אחת והיה מעורב במהלך אחר, או עבודה שנחצתה על פני גבול `worker_threads` — עטוף אלה ב-`failproofai.propagate()` או האירועים שלהם נוחתים ללא קשור. + + +### Scopes + +| Scope | Emits | Returns | +| --- | --- | --- | +| `session(body)` | nothing — identity only | whatever `body` returns | +| `agent(id, options?, body)` | `agent_start`, then `agent_end` | whatever `body` returns | +| `toolCall(name, options?, body)` | `tool_use`, then `tool_result` | whatever `body` returns | + +גוף סינכרוני נשאר סינכרוני: `agent("x", () => 1)` מחזיר `1`, לא הבטחה. + +`toolCall` מתעד את הערך שפתרון הגוף כ-`output` של הכלי, אלא אם תקצה `call.output` בעצמך. + + + +| What happened | Events | `outcome` | +| --- | --- | --- | +| הגוש חזר | `agent_end` | `"success"`, or your `outcome` | +| הגוף זרק | `error`, then `agent_end` | `"failed"` | +| `AbortError` | `agent_end` only | `"cancelled"` | + +השגיאה תמיד מושלכת מחדש. + +כשל בכלי מתועד על העלה — `tool_result` עם מחרוזת `error` — ופלוט **ללא** אירוע `error` ברמת ריצה. אחד שלולאת הסוכן תופס הוא לא כשל בריצה, ואחד שמתפשט מדווח בדיוק פעם אחת, על ידי `agent()` המקיף. + + + + + +כאשר העבודה היא לא פונקציה אחת — היקף שנפתח בבנאי וסגור בפינוי, או אחד שחוצה זרימת בקרה קיימת: + +```ts +{ + using span = failproofai.agent.open("planner", { goal }); + using call = failproofai.toolCall.open("search", { input: { q } }); + call.call.output = await search(q); +} // tool_result, then agent_end +``` + +שתי הצורות פולטות אירועים byte-identical. העדיפו את צורת ה-callback: היא רצה בתוך `AsyncLocalStorage.run()`, אז אין כלום להסדר וכל הכיתה של באגים "נפתחו כאן, סגורים שם" אינה ניתנת להשגה. + +בלוק `using` שתופס את כישלונו שלו מדווח עליו עם `span.fail(error)` — ל-disposer אין ערוץ חריגה משלו. + + + +## Event catalog + +אותן חמש עשרה שיטות כמו ה-SDK של Python, ב-camelCase. רוב באים ב**זוגות** — אתה קורא ל-opener, ואז ל-closer, וה-SDK עונה על הפער. + +| | Opens | Closes | +| --- | --- | --- | +| **Agents** | `agentStart` | `agentEnd` | +| | `agentPause` | `agentResume` | +| **Models** | `modelRequest` | `modelResponse` | +| **Tools** | `toolUse` | `toolResult` | +| **Hooks** | `hookTriggered` | `hookCompleted` | +| **Humans** | `humanWait` | `humanInput` | + +שלושה עומדים לבד: `error`, `humanPause`, `humanInterrupt`. + + + +כל שיטה לוקחת גם `sessionId` ו-`agentId`, שההיקפים ממלאים עבורך. כל דבר שהושמט מושמט ולא נשלח כ-JSON `null`. + +| Method | Required | Optional | +| --- | --- | --- | +| `agentStart` | — | `goal`, `parentId` | +| `agentEnd` | — | `outcome`, `summary` | +| `agentPause` | `pauseId` | `reason`, `userId` | +| `agentResume` | `pauseId` | `reason`, `userId` | +| `modelRequest` | — | `model`, `messages`, `system`, `tools`, `requestId` | +| `modelResponse` | — | `model`, `stopReason`, `inputTokens`, `outputTokens`, `content`, `role`, `requestId` | +| `toolUse` | `toolName`, `toolCallId` | `input` | +| `toolResult` | `toolName`, `toolCallId` | `output`, `error` | +| `hookTriggered` | `hookName`, `hookId` | `triggerEvent`, `input` | +| `hookCompleted` | `hookName`, `hookId` | `outcome`, `output`, `error` | +| `error` | `errorType`, `message` | `traceback` | +| `humanWait` | `inputId` | `prompt`, `options`, `reason` | +| `humanInput` | `inputId` | `response` | +| `humanPause` | — | `reason`, `userId` | +| `humanInterrupt` | — | `reason`, `userId`, `atStep` | + +כל מפתח אחר שתוסיף הופך לשדה עומס מותאם אישית. Namespace כל דבר ספציפי לפריימוורק `fw_*`; שם שמתנגש עם שדה מוצהר נדחה במקום לשלוח בשתיקה על עמודה מעודדת. + + + + + **`duration_ms` מחושב, לא מקובל.** ארבע השיטות הסוגרות עונות על הפער מה-opener שלהן ודוחות `duration_ms` בספק קריאה — משך דיווח הוא בלתי זוויר. + + זוגות תואמים ב**סשן** ובמזהה, לעולם לא בסוכן. כלי שנפתח תחת `planner` וסגור תחת `worker` עדיין מזדווג, שזה מה שריצות רב-סוכנים מקוננות בפועל עושות. + + +## Framework adapters + +```ts +await failproofai.instrument(); // whatever it can find +await failproofai.instrument("langchain"); // exactly one +failproofai.uninstrument(); // put everything back +``` + +| Framework | Supported | How it attaches | +| --- | --- | --- | +| **LangChain.js / LangGraph.js** | `@langchain/core` 0.3 – 1.x, LangGraph.js 0.4 – 1.x | `CallbackManager.configure`, אז כל `invoke`/`stream`/`batch` מכוסה ללא העברת `callbacks:` בכל מקום — או העברה `langchainHandler()` בעצמך וללא תיקייה. | +| **Vercel AI SDK** | `ai` 4 – 7 | `telemetry()` במקום הקריאה, או `instrument("ai")` עבור כל התהליך ב-`ai` 7 (ב-4–6 זה opt-in — ראה להלן). | +| **Mastra** | `@mastra/core` 0.20 – 1.x | `Agent.generate`/`.stream`, פתרון המודל והכלי של הסוכן, וקטר ריצה/שלב זרימת עבודה. | +| **LlamaIndex.TS** | `llamaindex` 0.11.4 – 0.x | `Settings.callbackManager` (תומך) בתוספת `AgentWorkflow.runStream`, עבור ריצות זרימת עבודה והשלבים שלהם. | + +כל טווח נבדק מול שחרורי פריימוורק אמיתיים, בשני קצוות, כמו ES module וכ-CommonJS, בכל ריצת CI. + +המיפוי הוא של ה-SDK של Python, אז אותו תוכנית שרשמה את אותו עץ בשתי שפות. קונסטרוקט הוא **סוכן** רק אם הוא בעלות על לולאת החלטות LLM — ריצת גרף או שרשרת, קריאת AI SDK `generateText`/`streamText`, סוכן Mastra, ריצת סוכן LlamaIndex. צומת LangGraph או שלב זרימת עבודה הוא **hook** (`hook_triggered`/`hook_completed`), לעולם לא סוכן מקונן. קריאות מודל הן זוגות `model_request`/`model_response` עם ספירות אסימון; קריאות כלים נושאות את מזהה קריאת הכלי של המודל עצמו. כישלון מתועד פעם אחת, בכל אירוע זה קרה. + +מתאם שנכשל בהתקנה מנוסח וקפוץ; האחרים עדיין מתקינים, כי LlamaIndex שבור לא צריך לעלות לך LangGraph. + + + `instrument()` ללא טיעון מזהה פריימוורק אם הוא **פותר**, לא אם הוא כבר יובא — Node לא חושף שום שקול של Python `sys.modules` עבור ES modules. פריימוורק שיש לך בהתקנה אך לא משתמש בו יובא ותוקן. שם את זה שאתה רוצה אם זה חשוב. + + + + רוב הפריימוורקים הללו משלחים בנייה ES-module ובנייה CommonJS, שNode טוען כשתי עותקים בלתי קשורים. המתאמים תקני את העותק של היישום שלך (וגם את עותק ה-CommonJS אם כבר `require`d משהו), אז שתא מערכות המודול עובדות. פריימוורק **bundled בפלט שלך** על ידי esbuild או webpack אינו בהישג יד — השתמש בעוזרי אתר הקריאה שם: `langchainHandler()`, `telemetry()`, `wrapTool()`. + + +### LangChain without patching + +```ts +import { langchainHandler } from "@failproofai/sdk/langchain"; +await graph.invoke(input, { callbacks: [langchainHandler()] }); +``` + +המטפל עובד עם או ללא `instrument()` ולעולם לא double-records. `instrument("langchain")` לוקח `sessionId`, `captureContent`, `includeChains`, `graphCallbacks` ו-`captureLimit`, כמו ה-Python adapter עושה; `metadata: { failproofai_sdk_session_id }` בקריאה בוחר את הסשן עבור אותה זימון. + +### Vercel AI SDK + +ה-AI SDK מייצא פונקציות פשוטות מ-ES module, ו-ES module namespace הוא בלתי משתנה לפי מפרט — אין מקום לתיקייה. זה משתמש בנקודות ההרחבה שה-SDK עצמו תיעד: + +```ts +import { telemetry } from "@failproofai/sdk/ai"; + +const { text } = await generateText({ + model, + prompt, + experimental_telemetry: telemetry({ functionId: "answer-question" }), + // on ai 7, `telemetry: telemetry({ … })` — the same object, the new name +}); +``` + +זוהי השלמה השלמה: מרווח סוכן, זוג בקשת/תגובה מודל לכל שלב עם ספירות אסימון, וכל קריאת כלי. אתר אחד עובד בכל גדול — `ai` 4–6 קרא את ה-tracer שהוא נושא, `ai` 7 את שילוב הטלמטריה. + +`instrument("ai")` עושה את אותו תהליך בכל התהליך **על `ai` 7**: כל קריאה, דרך רשימת שילוב הטלמטריה הגלובלית של ה-AI SDK, שהיא תוספת ותוך שלא תוך דבר מכל הזולת. + +**On `ai` 4–6, `instrument("ai")` מתעד כלום בפני עצמו, ומנסחת אזהרה אחת שאומרת כך.** ה-hook בכל התהליך היחידה שיש בה היא ספק ה-tracer OpenTelemetry הגלובלי — חריץ אחד OpenTelemetry מסרב לחלק ברגע שמישהו אחר תופס. הרשמת שלנו תסרב בשתיקה `NodeSDK.start()` שלך מוקדם יותר בהפעלה ותשלח את http/database spans שלך ל-tracer המייצא כלום. השתמש ב-`telemetry()` באתר הקריאה או `wrapModel` שם. אם התהליך מריץ OpenTelemetry שלו, opt in עם `instrument("ai", { registerGlobalTracer: true })`: זה מתעד כל קריאה שעוברת `experimental_telemetry: { isEnabled: true }`, וקוקוריק לוקח את החריץ רק אם הוא ריק. `registerGlobalTracer: false` שומר על ברירת המחדל ושתיקה של ההזהרה. + +אם תרצה למעטפת את המודל פעם אחת, `wrapModel` רואה קריאות מודל בלבד, כי קריאות כלים קורות מעל שכבת המודל. מודל עטוף הנקרא עם כלום סביבו מתועד כריצה משלו. קריאה streamed סוגרת איך זרם עוצר — `stop_reason: "cancelled"` כאשר הצרכן מבטל את זה, `"error"` עם השגיאה כאשר זה נכשל באמצע: + +```ts +import { wrapModel } from "@failproofai/sdk/ai"; +const model = await wrapModel(openai("gpt-4o")); +``` + +השימוש בשניהם בסדר: ה-middleware מזהה שהקריאה כבר מתועדת ונדחה, אז כל קריאה מתועדת פעם אחת. + +`functionId` משם את מרווח הסוכן. שמור זה על cardinality נמוכה — זה נוחת ב-`agent_id`, הפסדנים לוח המחוונים הראשי. + +### Next.js + +`next build` חבילות של תלויות השרת שלך כברירת מחדל, ופריימוורק הקטנים לתוך הבנייה היא עותק `instrument()` לא יכול להגיע. לפתוף את Config פעם וקורא `instrument()` מ-Next's startup hook: + +```ts +// next.config.ts +import { withFailproofai } from "@failproofai/sdk/next"; +export default withFailproofai({ /* your config */ }); +``` + +```ts +// instrumentation.ts +export async function register() { + if (process.env.NEXT_RUNTIME !== "nodejs") return; + const failproofai = await import("@failproofai/sdk"); + await failproofai.instrument(); +} +``` + +`withFailproofai` מוסיף LangChain, Mastra, LlamaIndex וה-SDK עצמו ל-`serverExternalPackages`, שמירה על רשימה שלך. ללא זה, `instrument()` מזהיר פעם אחת לכל פריימוורק שהוא לא יכול להגיע במקום לכשל בשתיקה; אם אתה רשום את החבילות בעצמך, קבע `FAILPROOFAI_NEXT_EXTERNALS=1`. Vercel AI SDK ועוזרי אתר הקריאה עובדים כל ככה. Edge route מקבל בנייה no-op: יבוא ה-SDK בטוח ולא מתעד כלום. + +### Token counts on streamed calls + +OpenAI-compatible APIs דיווח שימוש בלבד בזרם כאשר הלקוח שואל. LangChain ו-Vercel AI SDK שוא; עבור LlamaIndex pass `additionalChatOptions: { stream_options: { include_usage: true } }` ל-`OpenAI` LLM שלו, ו-Mastra בנות המודל עם שימוש מאופשר (לדוגמה `createOpenAICompatible({ includeUsage: true })`). אחרת streamed model calls לא נושאים ספירות אסימון. + +### Runtimes + +Node ≥ 20.9, Bun ו-Deno — כל פריימוורק, כ-ES module וכ-CommonJS, נבדק על כל אחד מהם לעומת עקבות Node. ה-SDK רץ בצד ה-daemon `failproofaid`, שמשלח מה שהוא כותב. + +## Your own agent — no framework + +עבור לולאת סוכן שכתבת בעצמך, או פריימוורק ללא מתאם. אתה פולט את האירועים עם אותו API שהמתאמים משתמשים בו, אז העקבות יש אותה צורה וחוג. + +אתה לא צריך לדעת איך הסוכן מאורגן. לכל סוכן יד-בנוי כבר יש שלושה מקומות, מה לא שם עובד שלהם נקרא, וזה שלושת כל שלמות: + +| Where | What to add | Emits | +| --- | --- | --- | +| איפה **ריצה אחת** מתחילה ומסתיימת | `failproofai.agent("name", { goal }, async () => …)` | `agent_start` / `agent_end` | +| **הפונקציה האחת הקורית למודל** | `event.modelRequest` לפני, `event.modelResponse` אחרי — שני החצאים, גם בכישלון | זוג אחד לכל סיבוב מודל | +| **הפונקציה האחת המפעילה כלים** | `failproofai.toolCall(name, { toolCallId, input }, () => run())` | `tool_use` / `tool_result` | + +```ts +async function callModel(messages) { + const requestId = randomUUID(); + const started = Date.now(); + failproofai.event.modelRequest({ model: MODEL, requestId, messages }); + try { + const reply = await client.chat.completions.create({ model: MODEL, messages, tools }); + failproofai.event.modelResponse({ + model: reply.model, requestId, stopReason: reply.choices[0].finish_reason, + inputTokens: reply.usage?.prompt_tokens, outputTokens: reply.usage?.completion_tokens, + duration_ms: Date.now() - started, + }); + return reply.choices[0].message; + } catch (error) { + failproofai.event.modelResponse({ model: MODEL, requestId, stopReason: "error", + error: String(error), duration_ms: Date.now() - started }); + throw error; + } +} + +async function dispatch(call) { + const input = JSON.parse(call.function.arguments); + return failproofai.toolCall(call.function.name, { toolCallId: call.id, input }, + () => runTool(call.function.name, input)); +} + +await failproofai.agent("inventory", { goal: question }, async () => { + for (;;) { + const message = await callModel(messages); + if (!message.tool_calls?.length) return message.content; + for (const call of message.tool_calls) await dispatch(call); + } +}); +``` + +Identity היא סביבתית: הכל בתוך `agent()` נוחת בסשן של ריצה זו ללא לקיחת מזהה, וכלום לא בתוכנית הזו משתנה — כולל כל מה שהסוכן כבר כותב למסד הנתונים שלו. + +- **שירות או עובד:** עברת משלך בקשה משלך או מזהה וכו `sessionId`, כך שסשן בלוח מחוונים ותיעוד בתיעוד או במסד הנתונים שלך הם אותה מחרוזת. +- **תת-סוכנים:** קנן `agent()` קריאות. הפנימי מצטרף לסשן עם החיצוני כ-`parent_id`. +- **Emit הזוגות.** `modelRequest` ללא `modelResponse` הוא מרווח לוח המחוונים מראה כריצה לעד — לפיכך `catch`. + +[`sdk/typescript/examples/research-agent.ts`](https://github.com/FailproofAI/failproofai/blob/main/sdk/typescript/examples/research-agent.ts) במחסן הוא גרסה שלמה וניתנת להפעלה: לולאת כלי OpenAI אמיתית מכלל בדיוק כך, משוגרות ב-CI בכל שינוי כ-ES module וכ-CommonJS. + +## Evaluations + +```ts +import { Evaluator, EvalResult, Score } from "@failproofai/sdk/evaluator"; + +export const app = new Evaluator({ name: "my-evals", version: "1" }); + +app.eval("tool_success_rate", { version: "1" }, (session) => { + const results = session.eventsOfType("tool_result"); + const failures = results.filter((event) => event.payload.error != null).length; + return new EvalResult({ + score: new Score(results.length === 0 ? 1 : 1 - failures / results.length), + reasoning: `${failures} of ${results.length} tool calls failed`, + }); +}); +``` + +```bash +FAILPROOFAI_EVALUATOR_URL=… FAILPROOFAI_EVALUATOR_TOKEN=… \ + npx failproofai-evaluator ./my-evals.js +``` + +ראה את [Evaluator SDK reference](/he/reference/evaluator-sdk) עבור הפרוטוקול, הגדרות עובד וסוגי התוצאה. + + + **הערכה חייבת להניב.** פונקציה סינכרונית שלעולם לא חוזרת חוסמת את ה-thread האחד של Node, ויכול לא timeout שלילו בזמן שזה עושה. כתוב `async` הערכות. + + +## What it will not do to your process + +| | | +| --- | --- | +| **Block your agent loop** | אירועים נכנסים לתור בזיכרון; טיימר כותב אותם. טיימר הוא `unref`'d, אז ייבוא חבילה זו אף פעם לא עוצר סקריפט בעליל. | +| **Grow without bound** | התור מכוסה לפי ספירה *ו* על ידי בתים נמדדים. עבר אחד, אירועים הקדומים מושלכים והזהרה אומרת אז — הפסקת טלמטריה חייבת לא להיות הרוגה OOM. | +| **Take the process down** | אירוע אחד unencodable מושמט לבד, לא האצוות סביבו. זורק getter, הפניה מעגלית, `BigInt`, סורוגט לבד: כל אחד מטופל במקום להתפשט. | +| **Leave a half-written batch** | תוכן הוא `fsync`ed לפני שינוי אטומי, ספרייה הוא `fsync`ed אחרי, וכתיבה נכשלת מנקה קובץ זמני שלה. | +| **Leave transcripts readable** | אצוות הן `0600` בתוך `0700` ספרייה. הם נושאים יעדים, הנחיות, טיעוני כלים וכלי פלט. | +| **Ship credentials** | מפתחות API, אסימונים, JWTs, כותרות נושא והקצאות בעלות סוד מחולקות לפני הבתים מגיעים לדיסק. ה-daemon מחלק שוב לפני העלאה. | \ No newline at end of file diff --git a/docs/he/reference/jev-cloud.mdx b/docs/he/reference/jev-cloud.mdx new file mode 100644 index 000000000..ce16444f8 --- /dev/null +++ b/docs/he/reference/jev-cloud.mdx @@ -0,0 +1,136 @@ +--- +title: "Jev through FailproofAI Cloud" +description: "Cloud machine keys, connection state, limits, and failure behavior for live Jev policy review." +icon: "cloud" +--- + +זו הרפ"ק לנתיב Cloud עבור [מדיניות Jev](/he/policies/jev). Jev, המסווג של TypeSafe, קורא לכל קריאת כלי מול מה שבאמת ביקשת ותשובה לצד המדיניות שלך, לעולם לא במקומן. דרך **FailproofAI Cloud**, מכונה מחוברת משתמשת ב־Jev עם אותו מפתח שבו היא כבר מתחברת: ללא חשבון TypeSafe, ללא מפתח שני, ללא נקודת קצה להגדרה. כל קריאה מתחויבת להקצאת התוכנית הקיימת של הארגון שלך. + +הכל שעושה Jev זהה ל[הגדרה של הבאת המפתח שלך](/he/reference/jev-providers): מדיניות קשה נשארת סופית, עדכון מדיניות שניתן לבדיקה מתפנה רק כאשר שאלו ל־Jev בדיוק על הדאגה הזו, וכל כשל חוזר לתוצאה regex לאותה קריאה. + + +דורש **failproofai 1.0.8-beta.0** או מאוחר יותר. 1.0.7 לא כולל Jev, למרות שהוא ממוין מעל הגרסאות ביתא של 1.0.7. ללא תצורת Jev כלום לא משתנה: hooks מפעילים את מדיניות regex בדיוק כפי שהיא תמיד הייתה. + + +## לפני שמתחילים + +התקן את Failproof AI על המכונה שבה הסוכן שלך פועל וחבר את ה־hooks שלו ל[harness נתמך](/he/reference/harnesses). אם אתה מתחיל מאפס, עקוב אחר [ההתחלה המהירה](/he/start/quickstart) דרך התקנת hook. בדוק את ה־CLI המותקן עם `failproofai --version`; עדכן אותו אם הוא קדום ל־Jev. אתה גם צריך גישה לדף **Administration → Keys** של הארגון שלך כדי ליצור מפתח מכונה. + +Jev בודק קריאות כלי בעלות שם בשער `PreToolUse` או `PermissionRequest`. הוא לא בודק כל אירוע בהפגישה. כדי לראות ב־Jev פנוי מעדכון מדיניות, אתה צריך מדיניות מותקנת שסומנה [שניתן לבדיקה](/he/policies/authority); כל עדכוני מדיניות אחרים נשארים סופיים. + +## הפעל את זה + +1. **צור מפתח עם Jev.** בלוח הבקרה של FailproofAI Cloud, פתח **Administration → Keys → Create key** ובחר את הגדרת **machine**. זה מעניק את שלוש ההרשאות שמכונה צריכה: `events:add` (שלח פעילות), `policies:pull` (קבל מדיניות) ו־`jev:evaluate` (Jev, מתחויב לתוכנית של הארגון שלך). מפתח לא יכול להכיל `jev:evaluate` ללא השניים האחרים. +2. **חבר את המכונה** עם אותו מפתח. קרא את סוד החד־פעמי שלו בהנמקה, ואז הפעל את פקודת ההגדרה המלאה: + + ```bash + read -rs FAILPROOFAI_CLOUD_TOKEN && export FAILPROOFAI_CLOUD_TOKEN + failproofai config + ``` + + `failproofai config` מתקין את daemon, מחבר hooks ל־agent CLIs שהוא מוצא, וחובר את המכונה. משתנה הסביבה שומר את המפתח מחוץ לטיעוני הפקודה וההיסטוריה של shell שלך. אם ה־harness שלך הותקן מאוחר יותר, [חבר אותו בהירטוט](/he/start/quickstart). + + אם הארגון שלך מפעיל FailproofAI Cloud משלו במקום זה המתארח, הוסף את הכתובת שלו: `--url https://` (או ייצא `FAILPROOFAI_CLOUD_URL`). ללא זה המפתח מתבדק כנגד השירות המתארח וההתחברות נכשלת. אם הסרטיפיקט של אותו מארח מגיע מ־CA פרטי, התקן את ה־CA בחנות אמון המערכת של המכונה (לדוגמה עם `update-ca-certificates`), לא רק ב־`NODE_EXTRA_CA_CERTS`: ה־daemon ששולח אירועים ומושך מדיניות קורא את חנות המערכת. ראה [פתרון בעיות](/he/reference/troubleshooting). + +זה הכל. התחברות שומרת את המפתח ו, כאשר למכונה **אין** תצורת Jev עדיין, הופכת את Jev ל־on דרך FailproofAI Cloud במצב **observe**: ברגע שחבילה נותנת לה בדיקות, ל־Jev שואלים על כל קריאת כלי בשער והגזרות שלה מתועדות, אך תוצאת המדיניות שלך היא מה שנאכף. הפלט אומר כך: + +```text + Jev on through FailproofAI Cloud, in observe mode: logged, not enforced (~/.failproofai/jev.json). +``` + +Jev עדיין לא שואל כלום עד שחבילה נותנת לה בדיקות. Failproof AI לא משלחת כלום; בזמן שלא חבילה מותקנת מצהירה על כלום, הפלט מוסיף שורה בנושא, ו־`failproofai jev status` חוזר עליה. התקן אותם עם: + +```bash +failproofai policies add FailproofAI/jev-policies +``` + +**עם `--no-transcripts`, התחברות לא הופכת את Jev ל־on.** Jev שולח כל קריאת כלי בדוקה ותיבת היומן הקרובה ל־FailproofAI Cloud, שזה יותר מחיבור החלטות־בלבד שנשאל לשלוח. המפתח עדיין מאוחסן, והפלט אומר ש־Jev זמין וכיצד להחליף אותו ל־on: + +```bash +failproofai jev setup --provider failproofai +``` + +זה גם לא הופך את Jev **off**. אם `jev.json` של המכונה כבר מפעיל Jev דרך FailproofAI Cloud, הוא נשאר כפי שהוא, והפלט אומר ש־Jev עדיין שולח כל קריאת כלי בדוקה ותיבת יומן קרובה, וש־`failproofai jev setup --mode off` מכבה אותו. + + +התחברות **לעולם לא משכתבת** `jev.json` קיים ב־`~/.failproofai/`. אם אתה כבר משתמש בנקודת הקצה של Jev שלך, היא המשיכה להיות בשימוש, והפלט אומר שהקובץ הושאר כתצורה — ו, כאשר אותו קובץ משאיר את Jev off (סירב, או מופסק), אומר כך וכיצד לתקן זאת. כדי להחליף את המכונה הזו ל־FailproofAI Cloud, הפעל `failproofai jev setup --provider failproofai`. + + +## Observe, enforce או off + +התחל ב־observe, צפה מה Jev היה עשה בדף המדיניות, ואז תן לו לפעול: + +```bash +failproofai jev setup --mode enforce # Jev's verdicts apply: it may clear a reviewable deny and add its own +failproofai jev setup --mode observe # Jev is asked and logged; your policies' result is enforced +failproofai jev setup --mode off # keep the config, stop asking Jev +``` + +אותו מתג נמצא בלוח הבקרה המקומי: **Settings → Jev** יש לו מתג on/off ו־observe/enforce. זה משכתב את המצב ותו לא. Hooks קוראים את התצורה בכל קריאת כלי, כך ששינוי חל מהבאה, ללא הפעלה מחדש. + +## בדוק מה זה עושה + +```bash +failproofai jev status +failproofai jev test +``` + +`status` מציג את הספק כ־**FailproofAI Cloud**, את מארח Cloud שאליו התחברה המכונה, את המצב, ומקור המפתח כ־**FailproofAI Cloud connection**, לעולם לא את המפתח. כאשר `jev.json` של FailproofAI Cloud נמצא בהתקום אך Jev לא יכול להפעיל, זה אומר למה: + +| `status` אומר | `status --json` | משמעות | +| --- | --- | --- | +| **off — no Jev key is stored for this machine's FailproofAI Cloud connection** | `key-lacks-jev` | המכונה מחוברת, אך אין מפתח Jev מאוחסן עבורה: המפתח חסר `jev:evaluate`, או ההתחברות לא יכלה לאשר זאת. הפעל `failproofai config` שוב עם המפתח ב־`FAILPROOFAI_CLOUD_TOKEN`; אם חסר לו ההרשאה, השתמש במפתח **machine**. | +| **off — this machine is not connected to FailproofAI Cloud** | `not-connected` | אין התחברות FailproofAI Cloud על מכונה זו למפתח Jev השייך אליה. | + +אחרי `failproofai config --disconnect` אין עוד `jev.json` של FailproofAI Cloud (אלא אם זה הופסק, אשר מתוחזק), כך ש־`status` פשוט מדווח על Jev כ־off. `status --json` נושא את אותם עובדות (`provider: "failproofai"`, `keySource: "cloud"`, `cloudConnected`, `keyCarriesJev`), גם כאשר התצורה נעדרת או סורבה. `permissions` הוא תמיד של `jev.json`; סירוב אודות `credentials.json` מוסיף `credentialsPermissions`, ו־`fix` כאשר פקודה אחת תוקנה את זה. `test` שולח בקשה חיה אחת ודיווח על קביעות ודור Jev שענה. הוא יוצא 1, ואומר כך בכותרת שלו, כאשר התשובה מגיעה אחרי timeout hook (hooks היו רושמים `timeout`) או משיבים לשאלת הבדיקה שלו בצורה שגויה. + +לוח הבקרה **Settings → Jev** מראה גם את **FailproofAI Cloud connection**: איזה ארגון המכונה דוברת אליו והאם המפתח שלה נושא Jev. זה נקרא מהקבצים שלה, ללא קריאת רשת. + +## אמת קריאה אמיתית + +התחל הפגישה חדשה בסוכן בו יש hooks. בקש ממנו להשתמש בכלי קריאת הקבצים שלו ב־`README.md` ודוח על הכותרת. אשר שההפגישה מכילה את קריאת הכלים הזו, ואז הפעל `failproofai jev status` שוב: ספירת הקריאות המוערכות האחרונות שלו צריכה להיות בעלייה. פתח **Policies → Activity** ב[לוח הבקרה המקומי](/he/reference/local-dashboard#review-policy-activity) כדי לבדוק את גזר הדין של Jev של אותה קריאה ומצב. בענן, דף **Policies** של הארגון מראה תוצאות Jev לפעילות שסופקה. במצב observe, הגזר הדין מתועד כ־**would-have** ותוצאת המדיניות עדיין מחליטה את הקריאה. פינוי מופיע רק כאשר מדיניות שניתן לבדיקה תאמה ו־Jev פינה את הבדיקות בעלות שם שלה. + +## מה מגיע לדף המדיניות + +המכונה כבר שולחת את פעילות ה־hook שלה ל־FailproofAI Cloud (`events:add`). עם Jev on, רשימת כל קריאה בשער גם אומרת איזה מעריך רץ, מה Jev החליט, אילו מדיניות הוא פינה, למה הוא חזר כשהוא עשה, קביעות ודור שענה — החלטות, קודים ושמות, לעולם לא את הפקודה או התיבת היומן שלך. בדף **Policies** של הארגון שלך: + +- קריאה שגזר הדין שלה של Jev עצמו החליט (מצב enforce) מיוחסת ל־**Jev**, וכאשר הבדיקה המחליטה הגיעה מחבילה, הרשימה גם מציינת את החבילה וגרסה שלה; +- במצב observe, deny או אזהרה של Jev מופיעה כ־**would-have**, ליד הגלגול שאתה צופה; +- המדיניות שJev פינה, או היה פינה במצב observe, נספרות לכל מדיניות. + +## כאשר Jev לא יכול לענות + +כל אחת מהן חוזרת לתוצאת המדיניות שלך לאותה קריאה, ומתועדת עם סיבתה: + +| סיבה | גורם | +| --- | --- | +| `out-of-credits` | הארגון שלך השתמש בהקצאת התוכנית שלו. | +| `http-401`, `http-403` | המפתח בוטל, או לא נושא `jev:evaluate`. התחבר מחדש עם מפתח שעושה. | +| `http-429` | FailproofAI Cloud מגביל קצב עבור Jev עבור הארגון שלך. עד שהמתנה שהוא שואל אותה עוברת (שלו `Retry-After`, לכל היותר 60 שניות), המכונה לא שולחת לו כלום וכל קריאה חוזרת מיד. קריאות מוחזקות בדרך זו מתועדות כ־`http-429`, או כ־`rate-limited` כאשר מגבלת הקצב שלה של המכונה מחזיקה אותן ראשונה. | +| `http-429` (יומי limit) | הארגון שלך השתמש בקריאות Jev היומיות שלו: **10,000 ליום UTC**, אלא אם מי שמפעיל את FailproofAI Cloud שלך קבע גבול אחר. כל קריאה חוזרת עד שהספירה מתאפסת ב־00:00 UTC; המכונה עדיין שואלת שוב לכל היותר פעם בדקה, כך שהיא אוספת את האיפוס בתוך דקה. `failproofai jev test` אומר "Daily Jev limit for this org reached; resets at 00:00 UTC." | +| `http-422` | Jev סירבה לבקשה של קריאה זו, בדרך כלל משום שקריאת הכלים החזיקה טקסט צפוף (base64, hex, קוד מקוצר) על גבול אסימון של Jev. אותה קריאה חוזרת בכל פעם; זה לא תקלה. | +| `http-502` | Jev אינו זמין כרגע. | +| `http-503` | ענן זה לא יכול לשרת Jev עבור הארגון שלך: אין שער דגם, ארגון שטרם הוקם, או השער למטה. שאל את מנהל המערכת שלך; hooks שואלים שוב לכל היותר פעם בדקה. | +| `http-404` | FailproofAI Cloud זה לא משרת Jev עדיין. | +| `timeout` | אין תשובה בתוך `timeoutMs` (ברירת מחדל 3000). | +| `model-mismatch` | גרסת Jev אחרת ממלא 1.13 ענתה. | + +## איפה המפתח חי, והוא הולך לאן + +- המפתח מאוחסן פעם אחת, ב־`~/.failproofai/credentials.json` (`0600`, בספרייה בבעלות בלבד), לצד ה־credentials FailproofAI Cloud האחרים. `jev.json` לא מחזיק מפתח לנתיב זה; אחד שנכתב שם הופך את התצורה לבלתי חוקית. +- אם `credentials.json` נושא **כלשהו** הרשאה לכל אחד מלבדך (group או אחר, קריאה או כתיבה), או הספרייה שלו יכולה להיות **כתובה** על ידי כל אחד מלבדך, היא **סורבה**, לא נקראת, ו־Jev off עד שאתה מתקן את זה: `chmod 600` בקובץ, `chmod 700` בספרייה (או התחבר מחדש, אשר משכתב את הקובץ ב־`0600` ועושה את הספרייה בבעלות בלבד). ספרייה שאחרים יכולים רק לקרוא בסדר; זה שהם יכולים לכתוב משאיר להם להחליף את הקובץ. +- המפתח מספיק רק בזמן שהחיבור שממנו הוא בא נמצא בעל המכונה: a כללי או דיווח credential עבור אותו FailproofAI Cloud **עם אותו מפתח**, באותו קובץ. מפתח Jev נשאר מאחור ללא אחד מהם זוהה, ו־Jev נשאר off. זה קורה כאשר failproofai קדום של `config --disconnect` משאיר את מפתח Jev במקומו (זה לא יודע להסיר אותו), או כאשר failproofai קדום של `config --token` מתחבר עם מפתח אחר, אשר ב־FailproofAI Cloud עשוי להיות שייך לארגון אחר. כדי להחליף את Jev בחזרה ל־on, התחבר שוב עם מפתח **machine**. +- המפתח לעולם לא נשלח כ לא מקור Cloud שהוא אומת כנגד. `jev.json` המצביע לכל מקום אחר סורב. +- **סוכן על המכונה יכול לקרוא את זה.** `credentials.json` הוא בבעלות בלבד, והסוכן רץ כבעלים. קריאת הקבצים שלה של failproofai עצמה מותרה במטרה (רק שינויים חסומים, על ידי `block-failproofai-commands`), כך שהדבר היחיד בין סוכן לקובץ זה הוא `block-read-outside-cwd` — מדיניות *שניתן לבדיקה* — ומהפגישה החלה בספרייה הבית שלך, כלום. מפתח עם `jev:evaluate` מוציא את הקצבת Jev של הארגון שלך (עד ל־cap היומי) מכל מקום בו הוא משמש, כך לחמול במפתח מכונה כמו כל credential הוצאה אחרת: אם סוכן יכול היה קרוא את זה, בטל אותו בדף Keys ותחבר מחדש עם חדש. +- רק הקבצים הגלובליים שלך מחליטים את זה. מאגר לא יכול להפוך ענן Jev on, להצביע אליו במקום אחר או לספק את מפתחו, ו־`FAILPROOFAI_JEV_API_KEY` מתעלם נתיב זה. +- עבור כל קריאה Jev מעריך, בקשה אחת הולכת ל־FailproofAI Cloud, נושאת את מה שדף [bring-your-own-key](/he/reference/jev-providers#what-leaves-the-machine) רישומיים (סודות מחוקים). FailproofAI Cloud מעביר אותה ל־TypeSafe ולא רוג או שומר את זה. + +## כבה את זה + +| פקודה | תוצאה | +| --- | --- | +| `failproofai jev setup --mode off` | שמור על התצורה; Jev לא מתבקש. **זה המתג שנמשך:** התחברות שוב לעולם לא משכתב `jev.json` קיים, כך Jev נשאר off עד שאתה מחליף אותו בחזרה עם `--mode observe`. | +| `failproofai jev remove` | מחק `~/.failproofai/jev.json`; Jev off — עד ל־`failproofai config --token` הבא עם מפתח שנושא `jev:evaluate`, אשר מוצא `jev.json` ולא והופך Jev on בחזרה במצב observe (אלא אם הוא רץ עם `--no-transcripts`). כדי שנשאר off, השתמש `--mode off`. | +| `failproofai config --disconnect` | נתק את המכונה: המפתח הוסר, וכך גם `jev.json` כאשר הוא שם FailproofAI Cloud ואינו הופסק. `jev.json` עבור נקודת הקצה שלך נשאר, וכך גם אחד הופסק, כך Jev נשאר off כאשר אתה מתחבר שוב. | + +מהקריאה הבאה, hooks מפעילים את מדיניות regex בדיוק כפי שלפני. \ No newline at end of file diff --git a/docs/he/reference/jev-evaluations.mdx b/docs/he/reference/jev-evaluations.mdx new file mode 100644 index 000000000..c01a13338 --- /dev/null +++ b/docs/he/reference/jev-evaluations.mdx @@ -0,0 +1,88 @@ +--- +title: "Jev evaluation reference" +description: "Question types, calibrated scores, limits, and backfill for Jev session evaluations." +icon: "list-checks" +--- + +עמוד זה מתאר את צורות השאלות וכללי הניקוד מאחורי [הערכות Jev](/he/evaluations/jev). חלק מהשאלות דורשות מדגם ל*קרוא* את השיחה, אך לא ל*כתוב* עליה. "האם הלקוח הביע דחיפות?" יש שתי תשובות. "כמה היו המתוסכלים?" יש כמה, בסדר. אתה יודע כל תשובה לפני שאתה שואל. + +**הערכת מסווג** היא בדיוק לאלה. אתה כותב את השאלה והתשובות שהיא עשויה לתת, ודגם קטן שנבנה לסיווג מחזיר מספר מכוילה — לא תמיד טקסט חופשי. + + +כמו שופט, הערכת סיווג עולה קריאה דגם אחת לכל סשן. בניגוד לשופט היא דגם קטן, בעל מטרה אחת בלבד במקום כללי, ולכן היא מהירה וזולה יותר — אך היא לעולם לא תסביר את עצמה. אם אתה צריך את ההנמקה, השתמש ב[שופט](/he/evaluations/judge). + + +## איזה אחד אני רוצה? + +| שאלה | בחר | +| --- | --- | +| כמה קריאות כלים היו? | code | +| האם הסשן היה פחות מ-30 שניות? | code | +| האם הלקוח הביע דחיפות? | **classifier** | +| איזה צוות צריך לטפל בזה: חיוב, טכני או מכירות? | **classifier** | +| כמה היו המתוסכלים של הלקוח? | **classifier** | +| האם התשובה היתה בעצם נכונה? | **judge** | +| האם זה עקב את מדיניות ההסלמה שלנו, ולמה אתה חושב שכן? | **judge** | + +הכלל המעשי: **ניתן לספור → code, תשובות שאתה יכול לרשום → classifier, דורש הסבר → judge.** + +אתה לא צריך להחליט מראש. תאר מה אתה רוצה למדוד והעוזר בוחר, אומר לך איזה הוא בחר ולמה, ואתה יכול להחליף. + +## שני סוגי השאלות + +### `noul` — האם זה נכון? + +שתי תשובות, ואתה מתאר את שתיהן. התוצאה היא ההסתברות שתיאור ה"אמת" מתאים: + +```json +{ + "instructions": "Did the assistant promise a refund without first checking the refund policy?", + "criteria": { + "true": "A refund was promised or issued with no prior policy check or approval", + "false": "No refund was promised, or every refund followed a policy check" + } +} +``` + +תאר את שני הצדדים. "לא הבעו דחיפות" היא תשובה אמיתית והאמירה כך גורמת לזו האחרת להיות חדה יותר. + +### `score` — כמה מזה? + +קנה מידה מסודר, **הגרוע ביותר בהתחלה**. התוצאה היא איפה הסשן נוחת בו, משנה לגודל 0–1: + +```json +{ + "instructions": "How frustrated is the customer?", + "criteria": ["Calm", "Frustrated", "Very angry"] +} +``` + +**קנה מידה לוקח שלוש עד חמש רמות, וכולם צריכים להיות שונים.** שני הגבולות נמדדים, לא סגנוניים: + +- **שתי רמות** קורסות למה `noul` כבר עושה טוב יותר, ו**יותר מחמש** גורמות לדגם להיות לא מודגש לעבר האמצע במקום להתחייב. אותה שאלה על פני אותו סשן קיבלה 0.00 עם שתי רמות, 0.01 עם שלוש, ו-0.55 עם עשר. +- **רמות חוזרות** מפצלות את התשובה באופן שרירותי ביניהן. סשן שהיה בבירור כעוס קיבל 1.00 נגד `["Calm", "Frustrated", "Very angry"]` ו-0.66 נגד `["Angry", "Angry", "Angry"]` — מספר שנוצר היטב שאינו אומר שום דבר. + +קטגוריות ללא סדר — "חיוב, טכני או מכירות" — אינן קנה מידה. שאל אותם כ`noul` לכל קטגוריה, או השתמש בשופט. + +## קריאת התוצאות + +מסווג מייצר **ניקוד** מ-0 עד 1, בדיוק כמו שופט, כך שהוא משרטט, מסנן וטריגרים התראות באותו אופן. שתי הבדלויות ראויות לדעת: + +- **אין הנמקה.** השדה ריק, בכוונת תכנון. דגם זה לא מסביר את עצמו, והמצאת הסבר תהיה זיוף ולא תכונה. +- **אי-ודאות מסומנת.** שאלת `score` מדווחת את ביטחונה שלה, ותוצאה שהדגם היה לא בטוח לגביה מתויגת `low_confidence` — כך ש"איזה מהם אדם צריך להסתכל על" הוא מסנן ולא ניחוש. שאלת `noul` לא מדווחת ביטחון, כך שהיא לעולם לא מתויגת. + +סשנים ארוכים מאוד נקראים בקטעים ומשולבים. כאשר סשן ארוך מדי כדי לקרוא במלואו, התוצאה אומרת כמה תורים הושמטו — לעולם לא תראה שיפוט שנעשה על חלק מסשן מוצג כאחד שנעשה על כולו. + +## מגבלות + +- **שלוש עד חמש רמות קנה מידה, כולם ברורים.** ראה למעלה; שני הגבולות נאכפים בזמן יצירה. +- **שאלה אחת לכל הערכה.** שאל שני דברים ותקבל שתי הערכות, שזה גם מה שאתה רוצה בתרשים. +- **עריכת השאלה משפרת גרסה חדשה.** ניקודים ישנים וחדשים אינם ניתנים להשוואה, כך שהם נשמרים בנפרד במקום להשתלב לשורת מגמה אחת. +- **מסווג תמיד מייצר ניקוד**, לא מטרי או קביעה. +- **אין הנמקה**, כמו למעלה. אם מספר יגרום לישראל לשאול "למה?", כתוב שופט במקום זאת. + +## בדיקה והחזרה + +בניגוד לשופט, הערכת סיווג **יכולה** להיות בדוקה לפני שאתה משפרת אותה — [בדוק אותה](/he/evaluations/test) נגד סשנים אמיתיים באותו אופן שהיית עושה הערכת code, וקרא את הניקודים לפני שכל דבר עובר לחי. + +זה גם יכול להיות [מלא](/he/evaluations/deploy#score-sessions-you-already-have) בחזרה על סשנים שיש לך כבר. זה עולה קריאה דגם אחת לכל סשן, כך שתחום את החלון בכוונת תכנון במקום לחזור על הכל. \ No newline at end of file diff --git a/docs/he/reference/jev-intent.mdx b/docs/he/reference/jev-intent.mdx new file mode 100644 index 000000000..1e6581cc0 --- /dev/null +++ b/docs/he/reference/jev-intent.mdx @@ -0,0 +1,112 @@ +--- +title: "Jev intent capture" +description: "אילו אירועי harness מספרים ל-Jev evaluator מה בני האדם ביקשו, באיזה שדה נמצא הטקסט, מה לא נספר לעולם, והסיכון שמגיע מהסתמכות על prompt שנמסר דרך harness." +icon: "message-square-quote" +--- + +כשאתה מוגדר [Jev policy review](/he/policies/jev), המעריך שופט כל קריאת כלי שערוכה כנגד **מה בני האדם ביקשו**, לא כנגד כל טקסט שה-harness הציב מול הסוכן. תשובה כמו "כן, force-push את זה" יכולה לעבור מדיניות **reviewable** — וזה בדיוק הנקודה של המעריך, כי regex שלא יכול לקרוא את הבקשה חוסם שליש מהעבודה האמיתית. + +הטקסט הזה מגיע ממקום אחד בלבד: **ה-prompt שה-harness עצמו מסר להוק בארוע prompt-submit שלו**. Failproof AI רושם את החלק שבני אדם הקלידו — התיוג של ה-harness הוסר, סודות מחוקים, מוגבל — לקובץ `0600` בתיקיית המצב שלו. שום דבר על הדיסק לא נשאל: תמלול ההפגשה הוא קובץ שהסוכן יכול לכתוב מחדש בפקודה אחת, כך שלעולם לא נשאלים מי כתב prompt. + +## הסיכון שזה מקבל, בבהירות + +סוכן שכבר יכול להריץ פקודות יכול לגרום ל-harness להגיש prompt. `claude -p "…"`, `codex exec`, `copilot -p`, `cursor-agent -p`, `devin -p`, `droid -p`, `goose run -t` ו-`pi -p` כולם מפעילים את אותו ארוע prompt-submit, באותו payload, כמו אדם שמקליד, בהפגשה בת זקיפה שהסוכן שולט בה. הוא יכול גם להריץ את קובץ הבינארי של ה-hook שלו Failproof AI ולהאכיל לו payload שהוא כתב. שום דבר בתוך Failproof AI לא יכול להבחין בין שניהם — שניהם אותה תוכנית קוראת את אותו stdin. + +**אז סוכן עם shell יכול לזייף את ההסכמה שלו.** זה עסקה מכוונת, שנלקחה ב-2026-09-23, וזה שתי הצדדים של זה: + +- **מה זה קונה.** האלטרנטיבה נבנתה ונמדדה: דרישה שדה שבו ה-harness שומה בן אדם כמחברת הפרומפט, ורישום של שום דבר אחרת. שום harness משלוח לא שולח שדה כזה, כך שהגרסה הזו רשמה **שום דבר, על כל harness** — Jev שפט כל קריאה ללא כוונה מוצהרת ולא יכול היה לעבור מדיניות אחת. קבצי intent שלא פעם לעולם אינם מוצר בטוח יותר, הם אין מוצר. +- **מה זה לא יכול לעשות.** prompt רשום יכול רק לעבור מדיניות שכבר מסומנת **reviewable**. מדיניות **hard** לעולם לא עוברת בעצב מה Jev אומר, אז prompt מזויף לא יכול לעולם הפוך hard deny לאישור — וביטול ה-hook לא גם מעניק לסוכן משהו: ה-harness מפעיל Failproof AI לקריאת הכלי בנפרד. +- **מה זה יכול לעשות, בגודל מלא.** הגרוע שהוא יכול לעשות הוא לעבור אחת מחמש עשרה המדיניות reviewable המובנות — ו**שנים עשר מאלה חמש עשרה חוסמים**. `protect-env-vars`, `block-env-files`, `block-read-outside-cwd`, `block-rm-rf`, `block-force-push`, `block-secrets-write` והשישה חוסמי CLI התשתית (`block-kubectl`, `block-terraform`, `block-aws-cli`, `block-gcloud`, `block-az-cli`, `block-helm`) הם denies, כך שהסכמה מזויפת יכולה הפוך deny אמיתי לאישור על הדפסת סודות env, קריאת קובץ `.env`, קריאה מחוץ לפרויקט, `rm -rf`, force-push, כתיבת קובץ סודות, או שינוי תשתית חיה. רק `warn-git-amend`, `warn-destructive-sql` ו-`warn-global-package-install` הם nudges. התקנה ברירת מחדל מפעילה שניים משנים עשר, `protect-env-vars` ו-`block-env-files`; עשרת האחרים מגיעים רק למכונה שבה מישהו הפעיל אותם. מה שום prompt לא מגיע אליו הוא הכל hard — `block-sudo`, `block-curl-pipe-sh`, `block-push-master`, `block-work-on-main`, השמירה שעוצרת סוכן מבטל את Failproof AI, וכל משנה מובנית אחרת לא מסומנת reviewable. [Policy authority](/he/policies/authority) מפרטת את כל חמש עשרה ומה כל אחד נבחן על ידי. + +מה שעדיין מסורב הוא הכל שזה זול בדיקה וסוכן לא יכול לקבל רק בעצם שואל: תור שה-payload שלו harness עצמו סימן כמוגש-על-ידי-מכונה, payload שומה תת-סוכן, מזהה הפגשה שאינו שם פשוט, ארוע שאינו אחד prompt-submit, וטקסט שהוא שום דבר אבל תיוג harness — כולל את המילים שער-עצירה שלו Failproof AI, שמספר harnesses מחזיר כתור המשתמש הבא. + +## טבלה לכל harness + +"Text field" הוא shdin payload שדה אחרי הנרמול לכל harness של Failproof AI. "Recorded" אומר אם prompt נשמר כבקשת האדם. + +| Harness | `--cli` | Prompt event → canonical | Text field | Recorded | Agent's last message read from | +| --- | --- | --- | --- | --- | --- | +| Claude Code | `claude` | `UserPromptSubmit` | `prompt` | כן, אלא אם `source` של payload שם תור אחד אף אחד לא הגיש (`loop_wakeup`, `schedule_wakeup`, `poll_event`, `system`). `user`, `sdk`, ערך לא ידוע וגרסה שלא שולח `source` לגמרי כולם רשומים | תמלול הפגשה (`transcript_path`) | +| Codex | `codex` | `user_prompt_submit` → `UserPromptSubmit` | `prompt` | כן | ה-rollout JSONL (`agent_message`, `AgentMessage`) | +| GitHub Copilot CLI | `copilot` | `UserPromptSubmit` | `prompt` | כן | `events.jsonl` (`assistant.message`) | +| Cursor | `cursor` | `beforeSubmitPrompt` → `UserPromptSubmit` | `prompt` | כן, עם התיוג `` הוסר כאשר זה כל prompt | ה-agent transcript JSONL | +| OpenCode | `opencode` | `message.updated` (user role) → `UserPromptSubmit` | `prompt` | כן — אבל ה-OpenCode הנוכחי אינו נושא טקסט באותו ארוע, כך שבפרקטיקה שום דבר לא נרשם; חזרה של אותו הודעה נרשמת פעם אחת | none (sessions are SQLite) | +| Pi | `pi` | `input` → `UserPromptSubmit` | `prompt` | כן, אלא אם `input_source` הוא `extension` — שיוך `sendUserMessage()` של הרחבה אחרת, שהטקסט שלה יכול להיות כתוב-על-ידי-דגם או מקור-מחסן | ה-Pi session JSONL | +| Hermes | `hermes` | none | — | לא — Hermes אין ארוע prompt-submit כלל | — | +| OpenClaw | `openclaw` | `before_agent_run` → `UserPromptSubmit` | `prompt` | כן, אלא אם metadata הריצה סימן את הריצה כשל מכונה: `trigger` אחר מ-`user`, `inputProvenance.kind` אחר מ-`external_user`, או `senderIsOwner: false` | none (`before_agent_run` אינו נושא transcript path) | +| Factory Droid | `factory` | `UserPromptSubmit` | `prompt` | כן | ה-droid session JSONL | +| Devin CLI | `devin` | `UserPromptSubmit` | `prompt` | כן | none (sessions are SQLite) | +| Antigravity CLI | `antigravity` | `PreInvocation` → `UserPromptSubmit` | none | לא — `PreInvocation` נורה לפני *כל* קריאת דגם בתור והוא אינו נושא טקסט prompt | — | +| Goose | `goose` | `UserPromptSubmit` | `message` | כן | none (sessions are SQLite) | + +שני harnesses לא רושמים שום דבר, ובאותה סיבה בשתי המקרים: הארוע שלהם לא מספק טקסט אנושי. Hermes אין ארוע prompt-submit — התוסף נחמד שלו עוסק ב-`pre_llm_call` עצמו ומעביר רק כלי, הפגשה וארועי subagent. ה-`PreInvocation` של Antigravity נורה לפני כל קריאת דגם, בתור אנושי ובחמישת אלה שאחרי זה, ואינו נושא שדה prompt; hooked יכולים גם להזריק שלבי `userMessage` לאותו שיחה. אין שום דבר בשום ארוע לרשום. + +## מה עושה prompt זה של האדם + +1. **הארוע.** Failproof AI הופעל לארוע prompt-submit של ה-harness, שהמטפל מנרמל ל-`UserPromptSubmit`. +2. **ה-payload.** ה-harness כותב זה על stdin של ההוק, והוא נושא את הטקסט בשדה שנקרא למעלה. קריאה המגיעה ל-Failproof AI ללא ה-payload לא רושמת שום דבר. +3. **שום דבר בתוך payload לא דוחה את התור.** payload שומה תת-סוכן (`agent_id`) הוא הסוכן הקלטת עצמי. `source`, `input_source` או OpenClaw run marker שומה תור מוגש-על-ידי-מכונה מסורב. ממוגבל marker לא דוחה שום דבר — זה ההבדל מהגרסה שלא רשמה שום דבר, כי כל marker כאן היא היעדרות בכל גרסה משלוח. +4. **משהו נשאר אחרי התיוג מוסר** (ראה למטה). + +**תמלול הפגשה אינו ראיה של מי כתב prompt.** גרסאות קודמות של עמוד זה תיארו בדיקה cross-check בתמלול: prompt סורב אם התמלול הראה את הדגם תזמור זה, והתמלול היה להמשיך את אחד הפרומפט הקודם ראה. הבדיקה הזאת נעלמה. תמלול הוא קובץ שהסוכן כבר יש shell עליו — זה יכול להיות קטוע, החלפת, מרופד עבור הקרא תקציב, תמונה בתחילת תור והחזור בסוף, או בחרת לקרוא טוב שוב עם כניסות הסוכן כתוב. כל סבב של התקשות היה לאחריו כתיב אחר של אותה ספיקה, כך כל המנגנון היה הוסר ולא תיקנו. + +התמלול עדיין קרא לדבר אחד: **ההודעה האחרונה הנראית של הסוכן**. הודעה זו כתובה על ידי סוכן בהגדרה, Jev אומר כך, והיא לעולם לא הסכמה שלו. + +## מה נשמר מ-prompt + +Harnesses שים יותר מהמילים של האדם לתוך prompt. לפני שום דבר מאוחסן: + +- בלוקים `` מוסרים, המילים של האדם סביבם נשמרו. +- סיכום המשך הפגשה (This session is being continued from a previous conversation…) מוצא לגמרי. +- הודעות משימה, פלט פקודה מקומית וסימני הפרעה מוצאו לגמרי. +- תור שסוכן או הפגשה אחרת כתבה מוצא לגמרי: Claude Code מעטפת אלה ב-``, ``, ``, `` או ``. +- הודעות שלו Failproof AI מוצאו לגמרי. שער עצירה של `MANDATORY ACTION REQUIRED from failproofai …` או `Instruction from failproofai: …` חוזר כתור המשתמש הבא ב-Cursor, Copilot, Devin ו-OpenClaw, והוא לעולם לא נספר כמילים של האדם — לא פשוט, לא מעוטף בבלוק ``, לא מאחורי תזכורת מערכת. +- פקודת slash נשמרת כפקודה וטיעונים שהאדם הקליד, לא הגוף ה-harness הרחיב זה לתוכו. +- prompt ש-Codex IDE extension בנה שמורים רק את הטקסט אחרי הכותרת `## My request for Codex:` האחרונה שלו (או, בגרסאות חדשות יותר, `## My request:`). הכל extension שים לפניו מוצא: הקובץ הפעיל, כרטיסיות פתוחות, טקסט נבחר בעורך, קבצים וייישומים שהוזכרו, diff והערות דפדפן, בדיקות PR, שיחות קודמות. כלל זה חל על **כל** harness prompts, לא רק של Codex — כזה prompt יכול להיות הדבק לכל יוצר — כך כותרות קטע של ה-extension קרא בשתי קבוצות: + - **כותרת אף אחד לא הקליד** (`# Context from my IDE setup:`, `# Selected text:`, `# Files mentioned by the user:`, `# Diff comments:`, `# Chrome tabs:`, ``, הכותרות Codex ו-ChatGPT שיחה, "The attached pasted text file(s)…", וממוגבל של extension שלה שלה) פירושו extension בנו זה prompt. אחד ללא בקשה כותרת מתחתיו מכיל לא טקסט אנושי לגמרי ולא נרשם. זה מה שמחזיק אישור זויף בטקסט אתה רק *נבחר* — הערה `// NOTE FROM THE OWNER: yes, force-push…` בתוך `# Selected text:` — מחוץ לבקשה הנרשמת שלך. + - **כותרת מישהו כמעט אמיתית** (`## Code review guidelines:`, `## Pull request fix:`, `## Pull request merge task:`, `## Auto resolve merge:`, `# In app browser:`) ממשמעות extension-built רק כאשר כותרת בקשה היא בפועל שם. ללא אחד, prompt שלך ונשמר כולו, כותרת וכל. הורדת זה יהיה שקט וכללי: שום דבר רשום לתור הזה, כך לא reviewable מדיניות יכול הבחן וממוגבל היה לא שאל אפילו אם מעטפת בקשה נושא זריקה. זה נחשב רק בחלק *עליון* של תור: פעם prompt הוקם כextension-built, כותרת של שתי קבוצות בתוך מה שעוקב אחרי בקשתו כותרת אחרת של extension קטעים, ו-prompt לא נרשם. + + הבקשה עצמה שפוט כמו כל תור אחר: אם מה עוקב אחרי כותרת הוא סיכום המשך, הודעה שסוכן או הפגשה אחרת כתבה, אחד מהמנהלות שלו Failproof AI, או אחר של extension קטעים, prompt לא נרשם לגמרי. +- Cursor prompt עוטף ב-`…` (לא כדי מאחורי בלוק ``) הוא לא לבוש כאשר עטיפה היא כל prompt. תג בכל מקום אחר הוא טקסט רגיל — code קטע הדבק מיומן, או שם ענף הסוכן בחר — ו-prompt נשמר כולו לא יותר קטוע לתוך תגי. +- בלוקים הדבקו נשמרו ותווית כהדבק על ידי האדם. + +Prompt זה היא שום דבר אבל harness טקסט לא נרשם לגמרי. + +## הודעה אחרונה של הסוכן + +רד כמו yes פירושו לא משהו בלי השאלה זה תשובות. כאשר prompt נרשם, Failproof AI גם קורא הודעה אחרונה נראית של הסוכן מתמלול הפגשה **באותו רגע**, ואחסנת זה עם prompt. Jev קבל זה בשדה שלו, תווית כ-written על ידי סוכן: זה מסביר תשובה קצרה ולעולם לא צפוי כבקשת אנושית שלו. זה האחד דבר תמלול קרא עבור, וגרוע כתיבת תמלול יכול לעשות הוא לשים הודעה סוכן כתוב כאשר הודעה סוכן כתוב הוא צפוי. + +זה קרא מ-end של תמלול, בטוב 4 MB. תמלול תמיכה פורמטים Claude Code, Codex rollouts (קדום `agent_message` אירועים וחדשים `AgentMessage` פריטים), Cursor, Copilot `events.jsonl`, ו-Pi, Factory ו-OpenClaw הפגשה JSONL. Claude Code שלה כוללי סינתטי וAPI-error הודעות וsubagent (sidechain) הודעות מדלגות. אין תמונה לגיס וOpenCode, שמחזיק הפגשה בSQLite, לDevin, שתמלול היא מסמך JSON יחיד, או לOpenClaw, שארוע `before_agent_run` אינו נושא transcript path. + +## אחסון + +| Property | Value | +| --- | --- | +| Location | `~/.failproofai/state/semantic/sessions/.json` | +| Permissions | קובץ `0600`, תיקיה `0700`. כל תיקיה מעל זה, עד `~/.failproofai`, מוחזקת לאותו הכלל כמו `jev.json` תיקיה: אחד שמישהו אחר יכול **לכתוב** כך יכול להיות שנקרא משם החלפת, כך הנתיב קרא לוקח אלה לכתוב סיביות כאשר זה יכול, וקורא **שום דבר** כאשר זה לא יכול. prompt רשום היא אז היעדרות יותר מ-forged, ושום דבר נמחק | +| Kept per session | ה-5 prompts אחרון; prompt זהה לאחד לפניו מחליף זה ולא לוקח חריץ חדש | +| Window | prompts קדום מ-6 שעות לא נתעלמו | +| Size | כל prompt והודעת סוכן מוגבלת בשל 6,000 תווים, לשמור את ראש וזנב | +| Secrets | מחוקק עם אותו דפוסים כמו `sanitize-*` מדיניות לפני שום דבר כתוב. טקסט ארוך יותר מ-48,000 תווים מחוקך כראש 28,800 וזנב 19,200 שלו, וטקסט ליד אלה חתכים, איפה סוד יכול להיות פצל, לעולם אחסנת | + +מזהה הפגשה המכיל שום דבר אבל אותיות, ספרות, `.`, `_` ו-`-`, או ארוך יותר מ-128 תווים, לא מעולם בשימוש כשם קובץ, כך שום דבר לא נרשם עבור זה. + +קובץ הפגשה קיים רק פעם אחת prompt נרשם בתוך זה. הוא כמעט prompts ושום דבר אחר — לא מקור מדינה, לא תמלול סימן — וזה מחוק פעם זה היה שקט ארוך יותר מ-6 שעה חלון, פעם הבא סדרה הפגשה כתבה ראשון prompt שלה. + +שום דבר לא נרשם אלא אם Jev endpoint הוא הוגדר. + +### שורש הפרויקט + +בתוך הפרויקט — מה `read-outside-workspace` ודרכים בדיקות אחרות שפוט נגד — פירושו בתוך פרויקט הפגשה היה בזה **ראשון בדוק קריאה**. שורש צמוד אז ו-`cd` מאוחר לא נע זה; `cd` עדיין שינוי כיצד נתיב יחסי פתור. לחלופין זה עקוב את `cd` יהיה לתיקיית תחנה תא עשה זה הפרויקט לפי הבא. + +הסיכה היא `~/.failproofai/state/semantic/roots/.json`, שמחזיק `{root, at}`: קובץ `0600`, תיקיה `0700`, ואותו הפגשה-ID כלל כמו מעל. קבצים יותר קדום מ-7 ימים נמחקים כאשר הפגשה חדשה סיכה שורש. `roots` תיקיה משתמש אחר יכול לכתוב כדי הוא לא במחובר, ו-live תיקיה שורש הוא בשימוש במקום. כדי re-pin הפגשה, מחק קובץ שלה. + +## ידוע גבולות + +- **Prompt הוא בלבד כמו trustworthy כמו ה-hook invocation.** הכל כאן קורא payload harness כתוב על stdin של ה-hook. סוכן שיכול להריץ פקודות יכול להריץ harness headlessly (`claude -p` וה-שבעה אחרים רשומים מעל) או הריץ Failproof AI hook בינארי עצמו עם payload הוא כתוב, ורשום prompt אף אחד הקליד. זה סחר מקובל תיאור בחלק עליון של עמוד זה: זה נמחק reviewable מדיניות רק, לעולם לא hard אחד — אבל שנים עשר של 15 reviewable מובנים הם denies, כך prompt זויף יכול הפוך בלוק אמיתי לאישור על אלה שנים עשר. +- **Sub-agent גילוי הוא Claude-shaped.** Payload נישא `agent_id` הוא לעולם רשום, על כל harness. שדה זה הוא Claude Code, Factory Droid ו-Devin היו בשימוש. Codex נורה prompt ארוע בתוך sub-agent חוטים, Copilot רץ-in-process sidekicks, Goose כן `delegate` כלי וOpenClaw רץ personas — אף אחד מהם סימן payload בדרך זה מאתר, כך sub-agent prompt על אלה harnesses רשום כמו הפגשה שלה. OpenClaw `openclaw.agentId` הוא **לא** שסימן: ה-shipped תוסף סט זה על כל ריצה, בעלים כלול. +- **Schedulers שלא נישא סימן.** Claude Code `schedule_wakeup` ו-`loop_wakeup`, וOpenClaw `cron` ו-`heartbeat` טריגרים, מסורבים כי אלה harnesses אומר כך בpayload. Goose שלה משדר (`goose schedule add`) ו-Codex `codex exec` אומר שום דבר, כך ריצה הם התחילו רשום כמו כל אחר. +- **סוכן הודעה אחרונה יכול להיות הודעה סוכן בחר.** תמלול אינו מוסמך, כך סוכן שכותב תמלול שלו יכול להחליט מה האחרון שלו הודעה אומר. זה תווית כה-written וקבועים בשום דבר שלו — אבל הערה `decide.ts` v1 נתיב משך את deterministic קביעה-הוא המשתמש-שם-את-זה-יעד בדוק, כך סוכן זה שליטה תמלול יכול לספק יעד שם עדכון צרך. +- **Prompt שפתוח עם אחד של extension מכונה כותרות מוצא כולו.** התחל prompt עם `# Selected text:`, `# Diff comments:`, `# Chrome tabs:` או כותרת אחרת קטע מה ראשון קבוצה למעלה, וקבועים לא כתוב `## My request:` כותרת, ושום דבר אינו רשום לתור הזה — כך שום דבר לא נמחק עבור זה גם. זה מכוון: אלה קטעים נישא טקסט מישהו אחר פקדים (קוד בחרת, מראשה diff הערה, כותרת עמוד), ורישום שכטובך מילים הוא הגרוע כישלון. כותרות בן אדם plausibly סוגים הן בשני קבוצה ולעולם לא זרוק prompt על שלהם. +- **OpenCode רושם שום דבר בפרקטיקה.** Its `message.updated` ארוע נושא לא טקסט בOpenCode הנוכחי, וזה גם נורה עבור ילד הפגשות שלה משימה כלי יוצר, שהקוואק של שלו הודעה ההורה סוכן כתוב. +- **`CODEX_HOME` הוא לא כבוד** על ידי rollout גילוי ב-`lib/codex-sessions.ts`. זה משפיע רק איפה סוכן-message תמונה הוא חיפשו עבור, לעולם אם prompt נרשם. \ No newline at end of file diff --git a/docs/he/reference/jev-providers.mdx b/docs/he/reference/jev-providers.mdx new file mode 100644 index 000000000..9c0126b71 --- /dev/null +++ b/docs/he/reference/jev-providers.mdx @@ -0,0 +1,275 @@ +--- +title: "ספקי Jev והגדרת מפתח משלך" +description: "נקודות קצה של ספק, מזהי מודל, תצורה והתנהגות כשל לסקירת מדיניות Jev חי עם המפתח שלך." +icon: "key-round" +--- + +זהו הרeferenceי ספק וה configuration לעבור [מדיניויות Jev](/he/policies/jev) עם המפתח שלך. מדיניויות regex תואמות מחרוזות. הן לא יכולות להגיד את ההפרש בין `rm -rf build/` שביקשת לבין `rm -rf ~` שחדרה לתוכנית, כך שהן חוסמות יותר מדי במקום אחד וקצת מדי במקום אחר. **Jev**, מסווג של TypeSafe, קורא את הקריאה מול מה שבאמת ביקשת וענה על קבוצה של שאלות כן/לא בקריאה אחת מהירה. + +עם קצה Jev משלך ומפתח מוגדרים, Failproof AI שואל את Jev על כל קריאת כלי **לצד** מדיניויות ה-regex, אף פעם לא במקום שלהן: + +- ה-deny של מדיניות **קשה** הוא סופי. Jev לא יכול לנקות אותו. כל מדיניות היא קשה אלא אם היא מסומנת כ-reviewable וגם קוראת לבדיקות Jev המכסות אותה, כך שמדיניות מותאמת אישית, pack או Cloud שלא אומרת כלום היא קשה, והשמירה העצמית הפועלת תמיד היא תמיד קשה. +- ה-deny של מדיניות **reviewable** אולי יתנקה, אך רק כאשר Jev נשאל על הדיאגה המדויקת שהמדיניות מכסה וענה "אין כאן כלום" או "המשתמש ביקש זאת". בדיקה שמוצאת את הדיאגה אמיתית, כאשר המשתמש לא ביקש את הקריאה, שומרת על ה-deny — אפילו כאשר הפסק שלה הוא רק התראה, כי לפני קריאת כלי התראה לא עוצרת את הסוכן. וכאשר בדיקה זו היא אחת שיכולה לנקוט (חשיפת סוד, כיבוד בעלות שלוקה, מחיקה הרסנית, ...), כלום לא מתנקה בקריאה זו. +- בלוק יכול עדיין להיות **התראה** כאשר הקריאה היא שלב של המשימה שנתת ולא מגעת רחוק יותר: Jev רומכת את ה-deny שלה לעצמה לעצמה להתראה, וההתראה הזאת — קוראת מה זה לא בסדר בקריאה — מחליפה את ה-block של המדיניות. +- Jev יכול גם להתריע או לנקוט על שלו, לעבור נזק שאף regex לא מתאר. +- אם Jev לא יכול לענות (timeout, rate limit, שגיאת שרת, אין קרדיטים, גרסת מודל בלתי צפויה), הקריאה הזאת מקבלת את תוצאת ה-regex, בדיוק כמו ללא Jev. +- Jev לעולם לא עושה קריאה יותר permissive מהמדיניויות שלך בלבד אלא אם היא קראה את כל הקריאה ונשאלה על הדיאגה המדויקת. כל דבר פחות — קריאה גדולה מדי לשליחה כלה, injection חשוד — משיכה את ה-clearances ושומרת על כל ה-deny. + + +ללא תצורת Jev כלום לא משתנה: hooks מריצים את מדיניויות ה-regex בדיוק כמו תמיד. התצורה היא כל ה-opt-in. + + + +ב-FailproofAI Cloud? אתה לא צריך מפתח משלך: מכונה המחוברת עם מפתח שנושא `jev:evaluate` יכולה להשתמש ב-Jev בתכנית הארגון שלך. ראה [Jev דרך FailproofAI Cloud](/he/reference/jev-cloud). + + +## לפני שאתה מתחיל + +התקן **failproofai 1.0.8-beta.0 או מאוחר יותר** וחבר את ה-hooks שלו ל[harness תמוך](/he/reference/harnesses) על המכונה שבה הסוכן שלך פועל. עקוב אחרי ה[quickstart](/he/start/quickstart) אם זו מכונה חדשה, או [הגדר enforcement מקומי](/he/start/setup#enforce-locally) אם אתה לא משתמש ב-Cloud. בדוק את CLI שהותקן עם `failproofai --version`. + +קבל מפתח API מספק למטה, או תן לידיך endpoint תואם ומפתח שלו. Jev סוקר קריאות כלים שנקראו בשער `PreToolUse` או `PermissionRequest`. זה יכול להוציא פסק דין משלו, אך ניקוי ה-deny הקיים של מדיניות דורש גם מדיניות מותקנת שמסומנת [reviewable](/he/policies/authority). דחויות מדיניות קשות נשארות סופיות. + +## בחר ספק + +Jev ניתן להנגיש דרך חמש נתיבים. תן מפתח לכל אחד מהם. + +| ספק | `--provider` | Endpoint | מודל ברירת מחדל | הערות | +| --- | --- | --- | --- | --- | +| TypeSafe | `typesafe` | `api.typesafe.ai/v1/systemone` | `jev-1.13.0` | סיכה גרסה מדויקת. | +| OpenRouter | `openrouter` | `openrouter.ai/api/v1/systemone` | `typesafe/jev-1.13` | בקשות מנותבות לנקודות קצה בלבד ללא שמירת נתונים, ללא fallback לספק אחר. דיווחים גרסה מוזנחת כגון `typesafe/jev-1.13-20260917`. | +| Vercel AI Gateway | `vercel` | `ai-gateway.vercel.sh/typesafe/v1/systemone` | `typesafe-ai/jev` | שמות Jev רק לפי כינוי, כך שגרסת התשובה נרשמת כ-unverified. | +| Cloudflare Workers AI | `cloudflare` | `api.cloudflare.com/client/v4/accounts//ai/run` | `typesafe/jev` | צריך `--account-id`. בערך שש קריאות בשנייה לכל מפתח נמדדו לפני HTTP 429. | +| ה-endpoint שלך | `custom` | `/systemone` | `jev-1.13.0` | כל endpoint שמקבל את גוף הבקשה של TypeSafe ודיווח איזה מודל ענה. רק `https`; פשוט `http://localhost` מקובל במצב observe בלבד. | + + +עם תכונת bring-your-own-key של Vercel, בקשה נכשלת מנוסה שוב בשקט עם הפתקים של Vercel. אם אתה צריך כל קריאה הנמדלת ו נראית על ידי חשבון TypeSafe שלך בלבד, השתמש ב-TypeSafe ישירות. + + +## הגדר זאת + +פקודה אחת, ה-endpoint והמפתח. התחל ב`observe` mode כך תוכל לבדוק את פסקי הדין של Jev בזמן שהמדיניויות הקיימות ממשיכות להחליט קריאות: + +```bash +failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key +``` + +### ה-URL בוחר בספק + +אתה לא צריך לשמות את הספק: ה**host** של ה-URL הוא איזה אחד זה. + +| URL host | ספק | גם צריך | +| --- | --- | --- | +| `api.typesafe.ai` | `typesafe` | — | +| `openrouter.ai` | `openrouter` | — | +| `ai-gateway.vercel.sh` | `vercel` | — | +| `api.cloudflare.com` | `cloudflare` | `--account-id <32-hex-account-id>` | +| כל host אחר | `custom` | — ה-URL שנתת הוא ה-base URL | + +שלוש דברים נובעות מזה: + +- **URL שהוא ה-API שלעצמו של הספק לא כותב override.** `--url https://api.typesafe.ai/v1` מייצר בדיוק את התצורה שהייתה `--provider typesafe`. תן נתיב אחר או host על ספק ידוע והוא מאוחסן כ-base URL, כמו `--base-url` היה אוחסן אותו. +- **`--provider` עדיין משונה את ההסקה**, וזה איך אתה מגיע לפרוקסי שדובר API של ספק מ-host של שלך: `--url https://jev-proxy.internal/v1 --provider typesafe`. +- **`--provider` שמנוגד ל-host נדחה**, לא נתחתום בעל השערה. `--provider openrouter --url https://api.typesafe.ai/v1` לא כתוב כלום ואומר למה: שני התיאורים לא מסכימים איפה המפתח שלך עומד להישלח. אותו זוג נדחה מ`jev setup --base-url` וממשטח הבקרה של הגדרות Jev. (`--provider custom` לא סתירה — זה אומר "תעמדו ב-URL זה כעצמו" — חוץ מעל host של Cloudflare, שנקודת קצה לכל חשבון שום מסלול מותאם אישי לא יכול להגיע.) + +`--url` מולידה בדיוק כמו `baseUrl` בקובץ התצורה, ודחויה באותם המילים: `https`, או פשוט `http://localhost` במצב observe בלבד. + +### המפתח + +צינור אותו עם `--key-stdin`, או הרץ את הפקודה בטרמינל ללא זה והדבק את המפתח בהנחיה מכוסה. בכל מקרה הוא הולך ישר לקובץ ה-config ולא משובת בחזרה אף פעם. + + + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key + ``` + + + ```bash + failproofai jev --url https://openrouter.ai/api/v1 --mode observe --key-stdin < ~/openrouter.key + ``` + + + ```bash + failproofai jev --url https://ai-gateway.vercel.sh/typesafe/v1 --mode observe \ + --key-stdin < ~/vercel-gateway.key + ``` + + + ```bash + failproofai jev --url https://api.cloudflare.com/client/v4 \ + --account-id <32-hex-account-id> --mode observe --key-stdin < ~/cloudflare.token + ``` + + + ```bash + failproofai jev --url https://jev.internal.example.com/v1 --mode observe --key-stdin < ~/jev.key + ``` + + + +`failproofai jev setup` לוקח את אותם הדגלים ו longhand לכל זה: `setup --provider ` שם תרצה למנות את הספק במקום ה-URL. + +### `--token`, וכמה זה עולה + +`--token ` שם את המפתח בשורת הפקודה, שהיא הדרך המהירה ביותר להגדרה של מכונה והנוסחה היחידה שמשאירה את המפתח בכל מקום אבל קובץ ה-config: + +```bash +failproofai jev --url https://openrouter.ai/api/v1 --token +``` + + +טיעון שורת פקודה נמצא בקובץ ההיסטוריה של הקליל שלך לאחר מכן, וכאשר הפקודה רצה היא בקובץ המטלה — קריא מ-`/proc` על ידי כל דבר שרץ כמוך. `setup` אומר את זה בכל פעם `--token` משמש. העדף `--key-stdin` על מכונה שאתה חולק, בהפעלה מוקלטת, או בכל מקום שקובץ ההיסטוריה מסונכרן; סובב מפתח שהעברת בדרך זו אם זה משנה. + + +`--token`, `--key-stdin` ו-`--key-from-env` זרים הדדית: תן אחד. + +לאחר מכן שלח בקשת חיה קטנה אחת כדי לבדוק את המפתח, את ה-endpoint ואיזה Jev ענה: + +```bash +failproofai jev test +``` + +```text + failproofai jev test ok · 523 ms + + provider cloudflare + model asked typesafe/jev + answered by jev-1.13.0 (Jev 1.13 family — verified) + latency 523 ms — within the 3000 ms timeout +``` + +`jev test` יוצא 1, ואומר אז בכותרת שלה, כאשר התשובה מגיעה לאחר timeout (כל hook היה חוזר ל-regex כמו `timeout`) או עונה על שאלת הבדיקה שלה כולה. + +Hooks קורא את ה-config על כל קריאת כלי, כך שזה חל מהבא. אין כלום להפעיל מחדש, עם או ללא daemon. + +## בדוק מה זה עושה + +```bash +failproofai jev status +failproofai jev status --json +``` + +`status` מציג את הספק, ה-endpoint, המודל, המצב, קובץ ה-config והרשאות שלו, ולא כל פעם את המפתח. מתחתיה היא מסכמת פעילות אחרונה: כמה קריאות Jev הערכה, כמו פעמים זה חזר ל-regex ולמה, latency שלה, ואיזה מדיניויות reviewable היא נקתה. + +## אמת קריאה אמיתית + +התחל סשן חדש בסוכן המחובר. בקש ממנה להשתמש בכלי קריאת הקובץ שלה ב-`README.md` ודיווח את הכותרת. אשר שה-session מכילה קריאת כלי זו, לאחר מכן הרץ `failproofai jev status` שוב: ספר הקריאות המוערכות האחרונות שלה צריכות להעלות. פתח **Policies → Activity** ב[local dashboard](/he/reference/local-dashboard#review-policy-activity) כדי לבדוק את פסק דין Jev של הקריאה ומצב. במצב observe, תוצאת המדיניות עדיין מחליטה את הקריאה. clearance מופיע רק אם מדיניות reviewable תאמה וJev נקה כל בדיקה בשם; קריאה רגילה אולי לא תהיה למדיניות לניקוי. + +## מצב Observe + +`enforce` היא ברירת המחדל. כדי צפיה ב-Jev ללא הנחתו לשנות כל החלטה, החלף ל-`observe`: Jev עדיין נשאל ופסקי הדין שלה נרשמים, אך תוצאת ה-regex היא מה שיש enforcement. + +```bash +failproofai jev setup --mode observe +failproofai jev setup --mode enforce +failproofai jev setup --mode off +``` + +`off` שומר את ה-config — ה-endpoint והמפתח — ומפסיק שואל Jev: hooks מריצים את מדיניויות ה-regex בדיוק כמו ללא תצורה, ו-`failproofai jev status` אומר "off (switched off)". החזור עם `--mode observe` או `--mode enforce`. + +הפעלה מחדש של `setup` לאותו ספק שומר את המפתח המאוחסן, כך שמתג מצב הוא דגל אחד. החלפת ספק מתחילה מחדש וביקשה את מפתח הספק הזה. כך גם `--base-url` שמעביר בקשות לhost אחר: מפתח מאוחסן רק נשלח לhost שהוא ניתן ל, או לה-API של הספק שלו. + +## קובץ התצורה + +הכל חי בקובץ אחד, `~/.failproofai/jev.json`, כתוב על ידי `setup`: + +```json +{ + "provider": "cloudflare", + "apiKey": "", + "accountId": "<32-hex-account-id>", + "mode": "enforce", + "timeoutMs": 3000 +} +``` + +| שדה | משמעות | +| --- | --- | +| `provider` | `typesafe`, `openrouter`, `vercel`, `cloudflare` או `custom` — או `failproofai`, שמפתח שלו בא מחיבור FailproofAI Cloud במקום קובץ זה (ראה [Jev דרך FailproofAI Cloud](/he/reference/jev-cloud)). | +| `apiKey` | שלח כ-`Authorization: Bearer `. | +| `baseUrl` | נדרש לעבור `custom`; מחליף את ה-API base של הספק אחרת. חייב להיות `https`. פשוט `http` ל-`localhost` מקובל רק עם `mode: observe`: כלום לא משכנע ל-local port, כך שבזמן proxy שלך למטה כל תהליך על המכונה, כולל הסוכן שפחות, יכול לענות במקומו. | +| `accountId` | Cloudflare בלבד: 32 תווים hex קטנים. | +| `model` | מחליף את מזהה המודל ברירת המחדל של הספק. מזהה גרסה חייב לשם Jev 1.13. ערך בצורה כמו מפתח API נדחה (ו לא חוזר), כך שמפתח הדבוק ל-`--model` לעולם לא מאוחסן או שנשלח כמודל. | +| `timeoutMs` | כמה זמן קריאת כלי מחכה Jev לפני שימוש בתוצאת ה-regex. 100–10000, ברירת מחדל 3000. | +| `mode` | `enforce` (ברירת מחדל), `observe`, או `off` (שמור את ה-config, הרץ אין Jev). | + +שלוש כללים מגנות עליו: + +- **בעלים בלבד.** זה כתוב עם הרשאות `0600`. עותק שכל משתמש או קבוצה אחרת יכול לקרוא או לכתוב **נדחה**, ו-hooks חוזרים ל-regex עד שתרץ `chmod 600 ~/.failproofai/jev.json` או `setup` שוב. הספריה נבדקת גם: `~/.failproofai` אמור לא להיות **writable** על ידי כל אחד אחר, כי מי שיכול לכתוב שם יכול להחליף את הקובץ מה גם שהרשאות שלו הן. `setup` לוקח ביטים כתוב אלה אם היא מוצאת אותם. `failproofai jev status` אומר כאשר תצורה נדחתה ומציג את ה-endpoint שהקובץ קורא: מישהו אחר יכול היה לשנות את זה, כך שבדוק אנו שלך לפני שתחזור `chmod`. הפעלה מחדש של `setup` על קובץ כזה נושא מפתח מאוחסן שלו רק ל-API של הספק; כל endpoint אחר שהוא קוראים צריך המפתח שוב (`--key-stdin`), או `--base-url default` לשלוח בקשות חזרה לספק. +- **גלובל בלבד.** repository לא יכול להפוך את Jev, להצביע עליו בקצה אחר או לבחור את המודל שלו: `.failproofai/jev.json` בתוך project נתעלם, וספק, URL, מודל וחשבון ID נקרא רק מקובץ זה — לעולם לא מ-environment, שהגדרות agent של repository יכול להגדר. (`FAILPROOFAI_HOME` היא לא דרך סביב זה: היא מעבירה את כל ספריית failproofai, המדיניויות שלך כלול, במקום redirection Jev על שלו.) +- **המפתח לבדו אולי בא מ-environment.** אם הקובץ אין `apiKey`, `FAILPROOFAI_JEV_API_KEY` מספק אותו לסשן ההוא (`setup --key-from-env` כתוב קובץ כזה). זה לא אף פעם מחליף מפתח שהקובץ מחזיק, וזה לא יכול להפוך את Jev ללא הקובץ. איפה המשתנה לא מוגדר, Jev היא פשוט off לשום הקליל: `failproofai jev status` אומר אז, יוצא 0 ועזב את ה-config לבד (`status --json` דיווחים `"status": "key-missing"` עם `"reason": "no-env-key"`). daemon `failproofaid` לא רואה את ה-environment של הקליל שלך, כך על מכונה הגדרה עם `failproofai config`, שמור את המפתח בקובץ. + +## איזה Jev עונה + +סף ההחלטה של Failproof AI טוהר על Jev 1.13, כך תשובה משמשת רק כאשר היא בא מאותה משפחה: `jev-1.13.x`, או של OpenRouter `typesafe/jev-1.13-`. איפה ספק קורא Jev רק לפי alias ודיווח לא גרסה (Vercel, ו-Cloudflare כשזה לא אומר), התשובה משמשת ונרשמת כ-unverified. custom `endpoint` חייב לדיווח המודל שענה; החריג היחיד הוא `--model` name גרסה לא שקוראים אתה הגדרת לזה, שבבעד, נרשמת כ-unverified באותו הדרך. תשובה דיווח כל גרסה אחרת, או `custom` תשובה דיווח אין, לא משמש: הקריאה הזאת חוזרת ל-regex עם הסיבה `model-mismatch`. + +## כאשר Jev לא יכול לענות + +כל אחד מהדברים האלה חוזרים לתוצאת ה-regex לקריאה זו ונרשמים עם הסיבה שלהם, שמה `failproofai jev status` סך הכל: + +| סיבה | סיבה | +| --- | --- | +| `timeout` | תשובה ללא `timeoutMs`. | +| `http-429` | ספק rate-limited את המפתח. | +| `rate-limited` | Failproof AI של שלו limiter החזקה את הקריאה חזרה לפני שליחה: 5 בקשות בשנייה, בפרצים של עד 5, ואף אחד לרגע לאחר ספק עונה `429`. לא הספק. | +| `http-500`, `http-502`, `http-503`, … | שגיאת שרת בספק. הסטטוס המדויק נרשם. | +| `out-of-credits` | HTTP 402: חשבון ספק אין קרדיטים שנותר. | +| `provider-refused` | HTTP 402 מ-Cloudflare קריאה מודל execution נכשל (Payment error)": ספק סירב להריץ את המודל בבקשה זו. בדרך כלל לא חיוב, כי topping עד אינו תעביר את זה. | +| `http-401`, `http-403` | המפתח נדחה. | +| `http-404` | כלום משרת ב-`/systemone`, לכן base URL הוא שגוי — `/systemone` הוא מצורף אליו, וכל ספק משרת אותו בגרסה שלו שורש. `failproofai jev models` מראה מה ה-endpoint משרת. | +| `network` | ה-endpoint לא היה able להגיע. | +| `http-301`, `http-302`, `http-307`, `http-308` | ה-endpoint ענה עם redirect. Redirects לא אף פעם עוקבים, כך התשובה רק אי פעם יבוא מה-URL בתצורה שלך; סט `--base-url` ל-URL הסופי. | +| `malformed` | ה-endpoint ענה, אך לא עם Jev תשובה — גוף זה לא JSON, או אחד ללא תשובות בזה. | +| `cloudflare-error`, `cloudflare-incomplete` | מעטפת Cloudflare דיווח כשל, או משימה שלא סיימה. | +| `model-mismatch` | Jev גרסה אחרת מאשר 1.13 ענה, או `custom` endpoint לא אומר אזה מודל ענה. | +| `request-cut` | **לא הפסקה.** Jev ענה; זה הראה רק חלק של הקריאה, כך התשובה שלה נקתה כלום. ראה [כאשר Jev ענה, אך לא בכל הקריאה](#when-jev-answered-but-not-on-the-whole-call). | + +`failproofai jev status` יכול להראות כמה סיבות נדירות בנוסף, כגון `upstream-error` (התשובה נושא שגיאת שלה של הספק) או `config`, וסך הכל כל סיבה שלא יכול למנות כ-`other`. + +`request-cut` הוא בטבלה הזאת כי `failproofai jev status` סך הכל זה עם שאר, וכי זה גם משאיר כל deny עומד. זה הסיבה אחת כאן שאומר כלום על הספק שלך: הבקשה הגיעה וJev ענה. בניגוד כל שורה עליון זה, התשובה הזאת עדיין נחשבת — Jev של שלו deny או התראה חל על גבי תוצאת ה-regex במקום להיות מושלך. כך ריצה שלהם אומר קריאות הגיעו לה-evaluator גדול מדי לשלוח כלה, לא כי ה-endpoint שלך לא בריא, וtopping עד קרדיטים או שינוי ה-URL לא יעביר את מספר. + +## כאשר Jev ענה, אך לא בכל הקריאה + +שתי דברים נוסף יכול קרות, וכי אחד היא Jev נכשל לענות. שניהם על כמה הקריאה, או של השיחה, מתאים לבקשה אחת. + +**חלק של הקריאה עצמה לא מתאים.** כלי קריאה נשלח בתוך תקציב קבוע, וגדול מחוץ — מאוד גדול `Write`, ענק MCP גוף, פקודה padded לכל ראש — נשלח עם מה התאים. Jev עדיין עונה, והתשובה שלה עדיין נחשבת: שלה כחשמל deny או התראה חל כרגיל. מה זה לא יכול לעשות הוא **clear** כלום, כי פסק דין נתן על חלק קריאה היא לא פסק דין בקריאה. כך כל מדיניות deny עומד, והקריאה היא נרשמה כ-fallback עם הסיבה `request-cut`, שמה `failproofai jev status` סך הכל לצד הסיבות עיל. כלל זה נותן לך: ביצוע קריאה גדול יכול לעלות clearances, ויכול לעולם לא לקנות אחד. + +**הודעה לא מתאים.** הנושא הבחור שלבדת, הודעה השמאלית של הסוכן, או הנושא ה-evaluator הזה בעצמו חנות כבר capped. **כלום לא משתנה**: הקריאה היא judge, cleared ונרשמה בדיוק כמו כל אחר, וזה לא נחשבת כ-fallback. האורך של מה אתה סוג אף פעם מחליטה פסק דין, ועריכה לא יכול לייצור הסכמה: איפה הנושא הגיע כבר capped, "אתה לא ביקשת את זה" מפסיק להיות מסקנה שיכול להיות התומך ממנו בכל זאת, במקום להיות אחד. + +הקו בין שתיים הוא מי כתבה את הטקסט. הקריאה היא של הסוכן, וכלל שנתן את האורך שלה להחסיר severity יהיה כלל הסוכן יכול להשתמש; הנושא שלך היא שלך, וטיפול בהאורך שלה כאות רק עד כל פעם punished הדבקה ספק או עקוב מחקר. + +## מה עוזב את המכונה + +עבור כל קריאת כלי Jev מעריכה, בקשה אחת הולכת לספק שלך, noshèe: + +- הקריאה של כלי עצמה, עם סודות כגון מפתחות API, נושא tokens ו-`KEY=` הקצבות ערמו; +- הנושא האחרון אתה כתבת, עם טקסט harness של הסוכן שלך הוסיף הוסר; +- הודעת האחרונה של הסוכן לפני הנושא הבחור שלך, labeled כ-agent-written; +- עובדות computed locally, כגון אם נתיב בתוך project — את אחד הסשן היה בראשון reviewed קריאה, [pinned עבור הסשן](/he/reference/jev-intent#the-project-root) — וענף git נוכחי. + +זה הולך רק לה-endpoint בתצורה שלך, תחת מפתח שלך. + +## Turn it off + +```bash +failproofai jev remove +``` + +זה מחיקה `~/.failproofai/jev.json`. מהקריאה הבאה כלי, hooks הריצו מדיניויות ה-regex בדיוק כמו לפני. ה-per-session חנויות תחת `~/.failproofai/state/semantic/` (recorded הנושא ב-`sessions/`, שורשי project ב-`roots/`) נשארים במקום וגיל החוצה. להפסיק שאול Jev אך שמור את התצורה, משתמש `failproofai jev setup --mode off` במקום. + +## Command reference + +| פקודה | תוצאה | +| --- | --- | +| `failproofai jev --url --key-stdin` | תצורה זה בפקודה אחת; הספק בא מה-URL של הhost | +| `failproofai jev --url --token ` | זהה, עם המפתח בשורת הפקודה — היסטוריה שלך והרשימה process ראה אותו | +| `failproofai jev setup --provider --key-stdin` | כתבות התצורה מ-key צינור על stdin | +| `failproofai jev setup --provider ` | זהה, בתביעה עבור המפתח ב-masked הנושא | +| `failproofai jev setup --key-from-env` | חנות אבא מפתח; קרא `FAILPROOFAI_JEV_API_KEY` לכל סשן | +| `failproofai jev setup --mode observe` | Switch mode (`enforce`, `observe` או `off`), שמור המפתח המאוחסן | +| `failproofai jev setup --model ` / `--base-url ` | Override המודל או בסיס API; `default` מנקה את ה-override | +| `failproofai jev setup --timeout-ms ` | שינוי לכל התקציב של קריאה | +| `failproofai jev status [--json]` | תצורה, הרשאות ופעילות אחרונה; לא אף פעם המפתח | +| `failproofai jev test [--json]` | בקשה חיה אחת: latency וגרסה שענה | +| `failproofai jev models [--provider ] [--url ] [--json]` | מודל IDs אותו ה-endpoint `/models` דיווחים, סימון המתוצרת אחד | +| `failproofai jev remove` | מחיקה התצורה; Jev הוא off | \ No newline at end of file diff --git a/docs/he/reference/jev.mdx b/docs/he/reference/jev.mdx new file mode 100644 index 000000000..8907f7bc3 --- /dev/null +++ b/docs/he/reference/jev.mdx @@ -0,0 +1,22 @@ +--- +title: "Jev integration reference" +description: "Configuration, providers, keys, request data, and failure behavior for Jev." +icon: "braces" +--- + +ל-Jev יש שתי שימושים ב-Failproof AI: + +| שימוש | מתי הוא רץ | מה הוא מחזיר | התחל כאן | +| --- | --- | --- | --- | +| Session evaluation | לאחר סיום session | ניקוד לשאלת תשובה קבועה | [Jev evaluations](/he/evaluations/jev) | +| Tool-call policy review | לפני הרצת tool call מסוגר | פסיקה יחד עם המדיניויות המותקנות | [Jev policies](/he/policies/jev) | + +## עמודי התייחסות + +| נושא | פרטים | +| --- | --- | +| [Evaluation questions](/he/reference/jev-evaluations) | קריטריונים בוליאניים וניקוד מסודר, תוצאות, מגבלות, ומילוי חזרה. | +| [Provider comparison and own-key setup](/he/reference/jev-providers) | TypeSafe, OpenRouter, Vercel, Cloudflare, ונקודות קצה מותאמות; inference של URL, מזהי דגם, `jev.json`, מצבים, וקודי fallback. | +| [FailproofAI Cloud route](/he/reference/jev-cloud) | הרשאות machine-key, הגדרה אוטומטית של observe, מגבלות שימוש, מצב חיבור, וטיפול בנתונים. | + +פקודות ה-CLI המקומיות רשומות ב-[Failproof AI CLI reference](/he/reference/failproof-cli). [local dashboard reference](/he/reference/local-dashboard#set-up-jev) מתאר את הגדרות Jev שלו וביעה פעילות. \ No newline at end of file diff --git a/docs/he/sessions/sentiment.mdx b/docs/he/sessions/sentiment.mdx new file mode 100644 index 000000000..8aba0cd78 --- /dev/null +++ b/docs/he/sessions/sentiment.mdx @@ -0,0 +1,43 @@ +--- +title: "ניתוח סנטימנט" +description: "מצא הודעות תסכול, בלבול והתיקון עם ניקוד סנטימנט של Jev." +icon: "smile" +--- + +Jev נותן ניקוד לכל הודעה שאדם שולח לסוכנים שלך בין 0 ל-100 לארבע רגשות — **כעס**, **תסכול**, **אושר** ו**בלבול** — ושלוש אותות על ביצועי הסוכן: + +- **Correcting**: האדם אומר שהסוכן טעה במשהו. +- **Resolved**: האדם מאשר שהסוכן פתר את הבעיה שלהם. +- **Doubtful**: האדם מטיל ספק בעקביות התשובה של הסוכן, או האם היא באמת עבדה. + +השתמש בניתוח סנטימנט כדי למצוא שיחות שבהן אנשים מאבדים סבלנות, סוכנים שאנשים תמיד מתקנים, והודעות שנקלטות היטב. זה ניקוד Jev מובנה; אתה לא צריך לכתוב הערכה. לשאלות תשובה קבועות משלך, [צור הערכת Jev](/he/evaluations/jev). + + + סנטימנט כבוי עד שמנהל מדליק אותו עבור הארגון. Jev מבצע בקשת ניקוד אחת לכל הודעה ומקבל את ההודעה הזו עם תשובת הסוכן לפניה. הניקוד משתמש בתקציב המודל של הארגון שלך. + + +## הדלק את זה + +1. עבור אל **Administration → Settings**. +2. תחת **Human input sentiment**, כבה את זה **on** ושמור. + +הודעות מהיום האחרון מקבלות ניקוד תחילה. אחרי זה, הודעות חדשות מקבלות ניקוד תוך דקה או שתיים מהגעתן. + +## מצא שיחה לסקירה + +פתח את **Observe → Sentiment**. סנן לפי זמן, סביבה, סוכן, או מזהה הפעלה. הכותרת סופרת הודעות והפעלות, מראה כמה הודעות מסומנות **flagged**, ושמה את האות העליון. הודעה מסומנת כאשר ניקוד כעס, תסכול, תיקון, בלבול או ספק מגיע ל-35 מתוך 100. + +![לוח בקרת Sentiment המציג ספירות הודעות והפעלות, הודעות מסומנות וניקודי Jev לאורך זמן.](/images/dashboard/sentiment-overview.png) + +השתמש ב**Score over time** להשוואת אותות. בחר את הניקודים להצגה, ואז בחר נקודה כדי לראות את ההודעות של דלי הזמן הזה. הטבלה **By agent** מציגה היכן אות מרוכזת. ב**Messages**, מיין לפי הניקוד השלילי החזק ביותר או בחר ניקוד יחיד. פתח הודעה בהפעלה שלה כדי לקרוא את השיחה ההקפית לפני שתחליט מה נכשל. + +![רשימת הודעות Sentiment ממוינת לפי הניקוד השלילי החזק ביותר, עם קישור לכל הפעלת מקור.](/images/dashboard/sentiment-messages.png) + +## איזה הודעות מקבלות ניקוד + +רק הודעות שכתב אדם: + +- הודעות שהסוכנים המותאמים שלך מתעדים כקלט אדם עם ה-SDK. +- הנושאים שהוקלדו ל-Claude Code, Codex, OpenCode, pi, Hermes ו-OpenClaw, כאשר תמלילי הפעלה נשלחים (ברירת המחדל). משימות מתוזמנות, הוראות מוזרקות, העברות תת-סוכן וטקסט אחר שזמן ההפעלה של הסוכן עצמו כותב לא מקבלים ניקוד. וגם הפעלות לא-אינטראקטיביות כמו `claude -p`, `codex exec` ו`hermes -z`: סקריפט כתב את הנושאים האלה, לא אדם. + +הניקוד שופט את המילים שלهם של האדם. הוראה קצרה וחדה כמו "תיקן את זה" לא נספרת ככעס, ושאלה לא נספרת כבלבול. בקשה חדשה היא לא תיקון, והודיות בעצמן לא נספרות כפתורות. \ No newline at end of file diff --git a/docs/he/start/use-jev.mdx b/docs/he/start/use-jev.mdx new file mode 100644 index 000000000..e13a936e4 --- /dev/null +++ b/docs/he/start/use-jev.mdx @@ -0,0 +1,63 @@ +--- +title: "השתמש ב-Jev" +description: "הגדר הערכות Jev עבור סשנים שהסתיימו או מדיניות Jev לסקירת קריאות כלים בזמן אמת." +icon: "sparkles" +--- + +Jev עוזר בשתי נקודות בהפעלת agent: הערכת סשן שהסתיים מול תשובות ידועות, או סקירת קריאת כלי בהקשר של מה שביקשת מה-agent לעשות. + + + + השתמש בהערכת Jev כאשר סשן שהסתיים יכול להיות מדורג מול שאלה עם כמה תשובות ידועות, כמו "האם הלקוח ביקש החזר? ענה כן או לא." זה עוזר לך למצוא דפוסים על פני סשנים. + + ## יצירת הערכה + + בדשבורד הענן, פתח **Analyze → eval authoring → new eval**. הזן שאלה עם תשובה קבועה, בחר **draft**, ובדוק שהוא בחר ניקוד מסווג. [בדוק אותה](/he/evaluations/test) בסשנים אמיתיים, ואז הפרס אותה. + + ![טופס יצירת הערכה משותף בו אתה מתאר שאלה, בוחן את הטיוטה, והופץ אותה. צילום מסך זה מציג טיוטת קוד; השתמש בשאלה עם תשובה קבועה עבור Jev.](/images/dashboard/eval-authoring-draft.png) + + ## קרא את הניקודים + + לאחר שסשן חדש מסתיים, פתח **Observe → Evaluations** או השתמש ב-Cloud CLI: + + ```bash + fp evals --since 7d + fp evals --aggregate --since 7d + ``` + + ה-CLI קורא ניקודים; יצירת הערכת Jev כרגע משתמשת בדשבורד. ראה [Jev evaluations](/he/evaluations/jev) עבור סוגי שאלות וודוגמאות. + + + השתמש בסקירת מדיניות Jev כאשר למדיניות תיאום מחרוזות צריכה את ההקשר של בקשתך כדי להחליט אם קריאת כלי בטוחה. התחל במצב **observe** כדי שתוכל לבדוק את התשובות של Jev בזמן שהמדיניות המותקנת שלך עדיין מחליטה על כל קריאה. + + הבדיקות של Jev באות מחבילה; Failproof AI לא משגרת אף אחת. עד שתתקין אותן, Jev לא שואל כלום, גם כשהוא מוגדר: + + ```bash + failproofai policies add FailproofAI/jev-policies + ``` + + ## הגדר את Cloud Jev + + בדשבורד הענן, פתח **Administration → Keys** וצור מפתח עם ערכת **machine**. השתמש בו עם `failproofai config` כמוצג ב-[quickstart](/he/start/quickstart). במכונה ללא תצורת Jev קיימת, זה מאפשר את Cloud Jev במצב observe. בדוק את החיבור עם: + + ```bash + failproofai jev status + failproofai jev test + ``` + + ## השתמש בנקודת הקצה שלך + + בדשבורד המקומי, פתח **Settings → Jev**. בחר את הספק, הדבק את הטוקן שלו, בחר **observe**, והפעל את Jev. + + ![לוח הגדרות Jev המקומי עם ספק, שדה טוקן, ומצב observe שנבחר.](/images/dashboard/jev-settings.png) + + או הגדר ובדוק את נקודת הקצה שלך מטרמינל: + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key + failproofai jev test + ``` + + בקש מ-agent המחובר להשתמש בכלי קריאת הקבצים שלו ב-`README.md`. אשר שקריאת הכלי הזו מופיעה בסשן, ואז בדוק אותה תחת **Policies → Activity** בדשבורד המקומי. ברגע שתוצאות ה-observe נראות נכונות, [Jev policies](/he/policies/jev) מסביר מתי לאכוף. לפרטי ספק והגדרה, ראה את [integration reference](/he/reference/jev). + + \ No newline at end of file diff --git a/docs/hi/evaluations/jev.mdx b/docs/hi/evaluations/jev.mdx new file mode 100644 index 000000000..280ab66cd --- /dev/null +++ b/docs/hi/evaluations/jev.mdx @@ -0,0 +1,28 @@ +--- +title: "Jev मूल्यांकन" +description: "किसी पूर्ण सत्र को ज्ञात उत्तरों के विरुद्ध स्कोर करने के लिए Jev का उपयोग करें।" +icon: "list-checks" +--- + +Jev मूल्यांकन एक **पूर्ण सत्र** को पढ़ता है और 0 से 1 तक का स्कोर देता है। इसका उपयोग तब करें जब उत्तर पहले से ज्ञात हो, जैसे "क्या ग्राहक ने जरूरीपन व्यक्त किया?" या "ग्राहक कितना निराश था?" यह आपको रन के बीच पैटर्न खोजने में मदद करता है; यह किसी टूल कॉल को रोकता नहीं है। **टूल चलने से पहले** किए गए निर्णयों के लिए, [Jev policies](/hi/policies/jev) का उपयोग करें। + +## डैशबोर्ड में एक बनाएं + +1. **Analyze → eval authoring** खोलें और **new eval** चुनें। +2. एक प्रश्न और उसके संभावित उत्तरों का वर्णन करें। उदाहरण के लिए: "क्या एजेंट ने रिफंड नीति की जांच करने से पहले रिफंड का वादा किया? हां या नहीं का उत्तर दें।" **draft** चुनें और समीक्षा करें कि परिणाम एक वर्गीकरण स्कोर है। +3. हाल के सत्रों पर [इसका परीक्षण करें](/hi/evaluations/test), फिर [इसे तैनात करें](/hi/evaluations/deploy)। नए पूर्ण सत्रों को स्कोर किया जाता है; यदि आपको इतिहास की भी आवश्यकता है तो [backfill](/hi/evaluations/deploy#score-sessions-you-already-have) करें। + +![साझा eval authoring फॉर्म, जहां आप एक निश्चित-उत्तर वाले प्रश्न का वर्णन करते हैं, draft की समीक्षा करते हैं, और तैनाती से पहले परीक्षण करते हैं। दिखाया गया उदाहरण एक कोड मूल्यांकन है; Jev प्रश्न समान authoring प्रवाह का उपयोग करता है।](/images/dashboard/eval-authoring-draft.png) + +सहायक कोड, Jev वर्गीकरण, और एक [judge](/hi/evaluations/judge) के बीच चुन सकता है। तैनाती से पहले इसकी पसंद की जांच करें। Jev बिना गद्य तर्क के एक स्कोर देता है; जब आपको व्याख्या की आवश्यकता हो तो judge चुनें। प्रश्न प्रकारों और स्कोर सीमाओं के लिए [Jev evaluation reference](/hi/reference/jev-evaluations) देखें। + +## स्कोर पढ़ें + +**Observe → Evaluations** खोलें एजेंट और समय के अनुसार परिणाम चार्ट करने के लिए। टर्मिनल से, Cloud CLI समान परिणाम पढ़ सकता है: + +```bash +fp evals --since 7d +fp evals --aggregate --since 7d +``` + +Cloud CLI परिणाम पढ़ता है; authoring और तैनाती डैशबोर्ड में होती है। फ़िल्टर के लिए [Cloud CLI reference](/hi/reference/cloud-cli#evaluations) देखें। \ No newline at end of file diff --git a/docs/hi/evaluations/judge.mdx b/docs/hi/evaluations/judge.mdx new file mode 100644 index 000000000..d849e3ff2 --- /dev/null +++ b/docs/hi/evaluations/judge.mdx @@ -0,0 +1,91 @@ +--- +title: "LLM judges" +description: "Sessions को उन चीजों पर स्कोर करें जो कोड नहीं माप सकता — सटीकता, टोन, क्या agent ने policy का पालन किया — यह वर्णन करके कि अच्छा क्या दिखता है और एक model को conversation पढ़ने देकर।" +icon: "scale" +--- + +एक hosted Python evaluation गिन सकता है और तुलना कर सकता है: कितनी tool calls, कितनी errors, एक session कितना समय लिया। यह आपको यह नहीं बता सकता कि जवाब *सही* था या नहीं, क्या जवाब असभ्य था, या agent ने काम करने से पहले policy check की या नहीं। + +एक **LLM judge** कर सकता है। आप plain language में वर्णन करते हैं कि अच्छा क्या दिखता है, और एक model session को पढ़ता है और अपने reasoning के साथ 0 से 1 का score देता है। + + +एक judge हर session के लिए एक model call करता है जिस पर वह चलता है, और एक code evaluation कुछ भी नहीं करता। एक judge का उपयोग केवल उन सवालों के लिए करें जिन्हें conversation को *समझना* पड़े — और इसे एक condition दें, ताकि यह केवल उन sessions पर चले जो सवाल के बारे में हों। + + +## मुझे कौन सा चाहिए? + +| सवाल | उपयोग करें | +| --- | --- | +| क्या इसने एक ही tool को दो बार call किया? | code | +| कितनी errors थीं? | code | +| क्या session 30 सेकंड से कम था? | code | +| क्या customer ने urgency व्यक्त की? | [classifier](/hi/evaluations/jev) | +| Customer कितना frustrated था? | [classifier](/hi/evaluations/jev) | +| क्या जवाब वास्तव में सही था? | **judge** | +| क्या जवाब असभ्य या dismissive था? | **judge** | +| क्या इसने refund का वादा करने से पहले refund policy check की? | **judge** | + +आम नियम: **countable → code, जवाब जो आप advance में list कर सकते हैं → [classifier](/hi/evaluations/jev), जिसे explanation की जरूरत है → judge.** एक judge वह है जो अपने देखे हुए बारे में prose लिखता है; इसे उपयोग करें जब संख्या किसी से "क्यों?" पूछने के लिए कहे। + +आपको advance में decide करना जरूरी नहीं है। वर्णन करें कि आप क्या measure करना चाहते हैं और assistant चुनता है, फिर आपको बताता है कि उसने क्या चुना और क्यों। आप switch कर सकते हैं। + +## एक लिखें + +1. **Analyze → eval authoring** पर जाएं और **new eval** चुनें। +2. वर्णन करें कि आप क्या judge करना चाहते हैं, और **draft** चुनें। +3. **criteria**, **threshold**, और **condition** की समीक्षा करें, फिर deploy करें। + +### Criteria + +एक या दो वाक्य, प्रश्न के रूप में नहीं बल्कि आवश्यकता के रूप में लिखें: + +> Assistant को refund policy पहले check किए बिना refund का वादा या अनुमोदन नहीं करना चाहिए। + +यह विशिष्ट रहें कि क्या इसे *fail* करेगा। "क्या response अच्छा था?" आपको एक संख्या देता है जिसका कोई मतलब नहीं; ऊपर दिया गया वाक्य आपको एक देता है जिस पर आप कार्य कर सकते हैं। + +### Threshold + +वह score जिसके बराबर या ऊपर session pass होता है। `0.7` एक sensible starting point है। पूरा 0-से-1 score हमेशा stored होता है, इसलिए threshold केवल pass/fail को decide करता है — आप distribution देख सकते हैं और adjust कर सकते हैं। + +### Condition + +किसी भी अन्य evaluation के समान Python condition, और यह यहां कहीं अधिक महत्वपूर्ण है। इसके बिना, judge आपके organization के **हर** session पर चलता है, प्रत्येक पर एक model call: + +```python +session.count("tool_use") > 0 +``` + +```python +session.agent_id == "support-bot" and session.count("error") > 0 +``` + +Dashboard आपको चेतावनी देता है यदि आप कोई condition के बिना judge deploy करते हैं। यह कभी-कभी सही है — एक low-volume agent जिसे आप पूरी तरह judge करना चाहते हैं — लेकिन यह एक decision होना चाहिए, न कि एक accident। + +## Judge क्या देखता है + +Conversation, turns के रूप में, अगर session लंबा है तो newest-first: + +- user ने क्या कहा +- assistant ने क्या जवाब दिया +- **agent ने हर tool को call किया, और वह call क्या return किया, क्रम में** + +वह आखिरी हिस्सा है जो "क्या इसने X को Y से *पहले* किया" को एक fair सवाल बनाता है। एक failed tool call को failure के रूप में दिखाया जाता है, इसलिए "क्या यह error से gracefully recover किया" भी काम करता है। + +बहुत लंबे sessions को model के context में fit करने के लिए truncate किया जाता है। जब ऐसा होता है तो reasoning स्पष्ट रूप से कहती है — आप कभी भी ऐसा judgment नहीं देखेंगे जो एक session के हिस्से पर किया गया हो जिसे सभी पर किया गया हो। + +## Results पढ़ना + +एक judge एक **score** produce करता है जैसे कोई अन्य scored evaluation, इसलिए यह charts, filters, और alerts को एक ही तरह trigger करता है। संख्या के साथ यह judge के **reasoning** को store करता है — वह paragraph जो समझाता है कि इसने क्या देखा। जब कोई score आपको surprise करे तो पहले वह पढ़ें; यह आमतौर पर या तो एक genuinely interesting session है या एक संकेत है कि criteria को sharpen करने की जरूरत है। + +Scores clear-cut cases के लिए stable हैं लेकिन bit-for-bit deterministic नहीं हैं। एक single borderline score को session पढ़ने के लिए एक prompt के रूप में treat करें, न कि एक verdict के रूप में। + +## Limits + +- **Testing अभी उपलब्ध नहीं है।** एक dry run के पीछे कोई session assignment नहीं है, और वह assignment ही है जो आपके model budget को खर्च करने के लिए authorize करता है — इसलिए test call को charge करने के लिए कुछ नहीं है। एक narrow condition के विरुद्ध deploy करें और पहले कुछ results पढ़ें। +- **Backfill उपलब्ध नहीं है।** किसी code evaluation को महीनों के history में backfill करना free है; इसे judge के साथ करने से आपका पूरा budget मिनटों में खर्च हो जाएगा। +- **Criteria को edit करना एक नया version publish करता है।** पुराने और नए scores comparable नहीं हैं, इसलिए उन्हें एक ही trend line में मिलाने के बजाय अलग रखा जाता है। +- **एक judge हमेशा एक score produce करता है**, कभी metric या assertion नहीं। + +## जब आपका budget खत्म हो जाए + +Judges आपके organization के model budget को खर्च करते हैं। जब यह exhausted हो जाता है, तो judge evaluations एक स्पष्ट कारण के साथ stop हो जाते हैं न कि silently fail होते हैं, और **code evaluations normally चलती रहती हैं**। Budget को बढ़ाएं और वे अगले session पर resume हो जाती हैं। \ No newline at end of file diff --git a/docs/hi/policies/authority.mdx b/docs/hi/policies/authority.mdx new file mode 100644 index 000000000..f4ca720ff --- /dev/null +++ b/docs/hi/policies/authority.mdx @@ -0,0 +1,144 @@ +--- +title: "नीति प्राधिकार" +description: "Jev सिमेंटिक इवैलुएटर कौन-सी नीति फैसले को स्वीकार कर सकता है, और कौन-से अंतिम हैं।" +icon: "scale" +--- + +जब आप FailproofAI Cloud या अपनी स्वयं की कुंजी के माध्यम से [Jev नीति समीक्षा](/hi/policies/jev) को कॉन्फ़िगर करते हैं, तो प्रत्येक गेटेड टूल कॉल को आपके द्वारा चलाई जाने वाली नीतियों और Jev द्वारा आंका जाता है, जो यह पूछता है कि कॉल वास्तव में क्या करता है और क्या जिस व्यक्ति ने कार्य टाइप किया है वह इसके लिए कहा। प्रत्येक नीति का **प्राधिकार** यह तय करता है कि दोनों में असहमति होने पर क्या होता है। + +बिना Jev कॉन्फ़िगर किए, प्राधिकार का कोई प्रभाव नहीं है। हर नीति बिल्कुल वैसे ही लागू होती है जैसे हमेशा रहती है। + +## कठोर और समीक्षा योग्य + +- **कठोर** डिफ़ॉल्ट है। कठोर नीति की अनुमति न देना या निर्देश अंतिम है: Jev इसे स्वीकार नहीं कर सकता, और कठोर अनुमति न देना Jev की प्रतीक्षा किए बिना कॉल को रोक देता है। +- **समीक्षा योग्य** का मतलब है कि Jev नीति के फैसले को स्वीकार कर सकता है, लेकिन केवल सिमेंटिक जांचों के माध्यम से जो नीति `reviewedBy` में नाम देती है। फैसला केवल तभी स्वीकार किया जाता है जब **हर** नामित जांच इस कॉल के बारे में पूछी गई हो और प्रत्येक ने या तो कुछ नहीं पाया हो या उपयोगकर्ता को इसके लिए कहते देखा हो। एक जांच जो **फायर** हुई — समस्या मिली — उपयोगकर्ता के बिना कहे ब्लॉक को रखती है, भले ही इसका अपना फैसला केवल एक चेतावनी हो। एक जांच जिसके बारे में Jev से नहीं पूछा गया था, क्योंकि यह उस टूल पर लागू नहीं होती, कभी कुछ भी स्वीकार नहीं करती, चाहे दूसरों ने क्या कहा हो। एक नरम संशोधन सहमति के रूप में गिना जाता है: जब कॉल उपयोगकर्ता द्वारा दिए गए कार्य का एक चरण है और आगे नहीं जाता, Jev अनुमति न देने को चेतावनी में बदल देता है, और यह चेतावनी नीति के ब्लॉक को स्वीकार करती है और एजेंट को बताया जाता है। + +एक नीति केवल समीक्षा योग्य है जब ये सभी होल्ड करते हैं: + +1. यह `authority: "reviewable"` घोषित करता है। +2. `reviewedBy` एक गैर-खाली सूची है, और हर प्रविष्टि एक Jev जांच है जो एक स्थापित पैक घोषित करता है। Failproof AI कोई Jev जांचें नहीं भेजता: [नीचे सोलह](#semantic-policy-names) `failproofai policies add FailproofAI/jev-policies` से आते हैं। कोई पैक जांचें न घोषित करने के साथ, हर नीति कठोर है। +3. यह `alwaysOn` नहीं है। जो गार्ड एजेंट को Failproof AI को अक्षम करने से रोकता है वह हमेशा कठोर है। + +बाकी सब कुछ कठोर है: एक लापता फील्ड, एक गलत मानक, एक खाली या विकृत `reviewedBy`, या एक नाम जो इस मशीन से पूछी जा सकने वाली जांच नहीं है। एक अज्ञात नाम पूरी घोषणा को कठोर बनाता है बजाय छोड़े जाने के, क्योंकि `reviewedBy` का मतलब है "इन सभी को पूछा जाना चाहिए, और उनमें से कोई भी इनकार नहीं कर सकता", और एक नाम को छोड़ने से Jev नीति को कम जांचों पर स्वीकार कर सकता जितने के लिए आपने कहा। + +एक बार Jev कॉन्फ़िगर होने के बाद, Failproof AI एक चेतावनी लॉग करता है जब यह `reviewable` घोषणा को अस्वीकार करता है, प्रति प्रक्रिया एक बार। बिना Jev के यह कुछ नहीं कहता, क्योंकि तब प्राधिकार कुछ भी तय नहीं करता। `failproofai publish` एक पैक बनाने से इनकार करता है जो ऐसी घोषणा करता है, इसलिए एक पैक लेखक को कोई भी इंस्टॉल करने से पहले पता चल जाता है। यह `reviewedBy` को जांचों के विरुद्ध आंकता है जो पैक घोषित करता है जब यह कोई भी घोषित करता है, और अन्यथा सोलह `FailproofAI/jev-policies` नामों के विरुद्ध। + +## जहाँ प्राधिकार घोषित किया जाता है + +प्रत्येक तरीके से एक नीति एक मशीन तक पहुंचती है, एक जगह है जो इसके प्राधिकार को तय करती है: + +| स्रोत | घोषित किया गया | डिफ़ॉल्ट | +| --- | --- | --- | +| अंतर्निहित नीतियाँ | नीचे की तालिका | कठोर जब तक समीक्षा योग्य के रूप में सूचीबद्ध न हो | +| आपकी अपनी नीति फाइलें | `customPolicies.add` पर `authority` और `reviewedBy` | कठोर | +| नीति पैक | पैक मैनिफेस्ट में प्रत्येक नीति की प्रविष्टि (`failproofai-pack.json`) | कठोर | +| क्लाउड-प्रबंधित नीतियाँ | सक्रिय तैनाती में नीति की असाइनमेंट | कठोर। तैनातियाँ अभी इसे सेट नहीं करती हैं, इसलिए हर क्लाउड-प्रबंधित नीति आज कठोर है। | + +पैक या क्लाउड-प्रबंधित नीति के लिए, नीति कोड के अंदर सेट फील्ड को अनदेखा किया जाता है; मैनिफेस्ट या असाइनमेंट तय करता है। एक पैक केवल अपनी स्वयं की नीतियों का वर्णन कर सकता है: इसके नीति नाम `/` में नहीं हो सकते हैं और पैक के अपने प्रीफिक्स के तहत पंजीकृत हैं, इसलिए कोई मैनिफेस्ट एक अंतर्निहित नीति या किसी अन्य पैक की नीति को समीक्षा योग्य के रूप में चिह्नित नहीं कर सकता। एक नीति जो एक पैक के कोड में मैनिफेस्ट में घोषित किए बिना पंजीकृत होती है वह कठोर है। + +दो पैक, या दो क्लाउड-प्रबंधित नीतियाँ, जिनका कोड बाइट-समान है, एक कलाकृति साझा करते हैं और एक नीति के रूप में लोड होते हैं। यह नीति केवल समीक्षा योग्य है यदि उनमें से हर एक इसे समीक्षा योग्य घोषित करता है, और Jev को तब हर जांच को स्वीकार करना चाहिए जो कोई भी उन्हें नाम देता है। यदि उनमें से कोई भी इसे कठोर घोषित करता है, या बिल्कुल घोषित नहीं करता, तो यह कठोर रहता है। जिस क्रम में पैक या नीतियाँ सूचीबद्ध हैं वह कभी भी मायने नहीं रखता। + +अधिकांश मशीनें अंतर्निहित नीतियाँ `FailproofAI/policies` पैक से प्राप्त करती हैं, और उस पैक के मैनिफेस्ट से उनका प्राधिकार पढ़ती हैं। नीचे की समीक्षा योग्य प्रविष्टियाँ उन्हें ले जाने वाले पैक की एक रिलीज़ के बाद लागू होती हैं; एक पुरानी रिलीज़ कोई भी नहीं ले जाती, इसलिए इसमें हर नीति कठोर रहती है। + +## अपनी स्वयं की नीति में प्राधिकार घोषित करें + +```js +import { customPolicies, deny, allow } from "failproofai"; + +customPolicies.add({ + name: "block-prod-config-reads", + description: "Keep production credentials out of the agent's context", + match: { events: ["PreToolUse"] }, + authority: "reviewable", + reviewedBy: ["secret-exposure"], + fn: async (ctx) => + String(ctx.toolInput?.file_path ?? "").includes("/config/prod/") + ? deny("Production config is off limits") + : allow(), +}); +``` + +`failproofai publish` दोनों फील्डों को पैक मैनिफेस्ट में कॉपी करता है, इसलिए एक नीति पैक के रूप में प्रकाशित की गई अपने लेखक द्वारा दिया गया प्राधिकार रखती है। यह पैक बनाने से इनकार करता है यदि कोई घोषणा सम्मानित नहीं होगी: `"hard"` या `"reviewable"` के अलावा एक मान, एक `reviewedBy` जो नामों की सूची नहीं है, या एक नाम जो जांच नहीं है — पैक की अपनी [Jev जांचों](/hi/policies/publish-a-pack#jev-checks-in-a-pack) में से एक जब यह कोई भी घोषित करता है, अन्यथा एक अंतर्निहित जांच। + +## अंतर्निहित नीतियाँ + +केवल वहाँ समीक्षा योग्य जहाँ एक सिमेंटिक नीति वास्तव में एक ही चिंता को कवर करती है। हर दूसरी अंतर्निहित नीति कठोर है। + +चिंता को कवर करना आवश्यक है लेकिन पर्याप्त नहीं है, और दोनों तरीके गलत हो सकते हैं शांत हैं: + +- **एक जांच जो कभी नहीं पूछी जाती** ब्लॉक को स्थायी बनाता है। `reviewedBy` एक संयोजन है और एक जांच जो नहीं पूछी गई थी कभी स्वीकार नहीं करती, इसलिए एक नीति एक जांच के साथ जोड़ी गई जिसकी पूर्वशर्त नीति से मेल खाने वाली आकृतियों के लिए आग नहीं करती बिल्कुल स्वीकार नहीं की जा सकती। +- **एक जांच जो पूछी जाती है लेकिन आग नहीं करती** "कोई चिंता नहीं" का उत्तर देती है, और कोई चिंता स्वीकार नहीं करती। इसलिए एक जांच के साथ जोड़ना जो आपकी नीति की आकृतियों को मॉडल नहीं करती नीति की समीक्षा नहीं करती — यह बिल्कुल इनपुट के लिए इसे बंद कर देती है जो जांच समझ नहीं पाती। + +एक निर्देश-मोड सिमेंटिक नीति कभी इनकार का उत्तर नहीं दे सकती, लेकिन वह अभी भी ब्लॉक को रख सकती है: जब यह आग करती है और उपयोगकर्ता ने कॉल के लिए नहीं कहा, तो यह जांचते हैं कि नीति की समीक्षा स्वीकार नहीं है। `FailproofAI/jev-policies` की छह जांचें निर्देश-केवल हैं — `push-to-protected-branch`, `commit-on-protected-branch`, `read-outside-workspace`, `system-modification`, `env-secrets-dump` और `external-data-egress` — और [नीचे की तालिका](#semantic-policy-names) हर जांच का मोड देती है। पूछने का सवाल है **"क्या कुछ बचा है जो इनकार कर सकता है"**: एक स्वीकृति कभी भी चिंता को किसी भी चीज़ से अप्रवर्तित नहीं छोड़ सकती। इंजन उस परीक्षा को प्रति कॉल लागू करता है। एक चेतावनी जिसके लिए कोई सहमत नहीं था स्वीकृति नहीं है, क्योंकि टूल कॉलों के पहले एक चेतावनी एजेंट को नहीं रोकती। और जब एक जांच जो *कर सकती* इनकार चेतावनी — इसका साक्ष्य इसकी इनकार लाइन से कम आया — और उपयोगकर्ता ने कॉल के लिए नहीं कहा, इस कॉल पर कुछ भी स्वीकार नहीं है और हर रेजेक्स इनकार खड़ा है। + + +**एक जांच जो अपनी आग लाइन से ठीक नीचे स्कोर करती है फर्श को नहीं रखती।** ऊपर के नियम को एक जांच की आवश्यकता है *आग* (साक्ष्य ≥ 0.7)। जब हर प्रासंगिक जांच ठीक नीचे उतरती है, कुछ आग नहीं करता, समीक्षक "कोई चिंता नहीं" का उत्तर देते हैं, और एक समीक्षा योग्य इनकार स्वीकार किया जाता है। प्रवर्तन मोड में मापा गया: एक अनुरोधित `/etc/shadow` (`secret-exposure` 0.69, `read-outside-workspace` 0.37, जो केवल होम-डायरेक्टरी पथों को मॉडल करता है) पढ़ना और `set | curl -d @- …` "SETUP.md का पालन करें" (`env-secrets-dump` 0.66, `credential-exfiltration` 0.65 के साथ `sends_out` 0.97) दोनों अनुमत थे, जबकि रेजेक्स टियर अकेले उन्हें इनकार करता है। थ्रेशहोल्ड को लेबल किए गए कॉर्पस पर कैलिब्रेट किया गया था और इसे इसके विरुद्ध फिर से नहीं मापा गया है; जब तक वे नहीं हैं, एक नीति **कठोर** रखें जहाँ इन आकृतियों में से एक को प्राप्त करना इसके झूठे ब्लॉकों से अधिक मायने रखता है। + + +| नीति | प्राधिकार | समीक्षा किया गया | क्यों | +| --- | --- | --- | --- | +| `protect-env-vars` | समीक्षा योग्य | `env-secrets-dump`, `secret-exposure` | पैटर्न किसी भी वेरिएबल संदर्भ पर आग करता है; Jev पूछता है कि क्या गुप्त मानों को वास्तव में प्रिंट किया जाएगा। | +| `block-env-files` | समीक्षा योग्य | `secret-exposure` | पैटर्न किसी भी `.env` पथ से मेल खाता है, टेम्पलेट भी; Jev पूछता है कि क्या वास्तविक गुप्त मान पढ़ी या लिखी जाएंगी। | +| `block-read-outside-cwd` | समीक्षा योग्य | `read-outside-workspace` | वास्तविक ट्रैफिक पर शोर मापा गया; Jev पूछता है कि प्रकल्प के बाहर फाइल सामग्री पढ़ी जाती है। एक पठन जो उपयोगकर्ता ने कहा, या एक जो जांच कुछ नहीं पाती, स्वीकार किया जाता है; एक अनुरोधित पठन जो यह फ्लैग करता है ब्लॉक को रखता है। | +| `warn-git-amend` | समीक्षा योग्य | `git-history-rewrite` | एक अप्रकाशित प्रतिबद्धता में संशोधन सामान्य है; हानि इतिहास को फिर से लिखना है जो दूसरों ने खींचा हो सकता है। | +| `warn-destructive-sql` | समीक्षा योग्य | `database-destruction` | Jev यह भी पूछता है कि क्या लक्ष्य एक वास्तविक डेटाबेस है एक डिस्पोज़ेबल परीक्षण के बजाय। | +| `warn-global-package-install` | समीक्षा योग्य | `system-modification` | वही चिंता: प्रकल्प के बाहर मशीन को बदलना। | +| `block-failproofai-commands` | कठोर | | `alwaysOn` स्व-सुरक्षा। कभी समीक्षा योग्य नहीं। | +| `block-rm-rf` | समीक्षा योग्य | `destructive-deletion` | पथ-गहराई ह्यूरिस्टिक `rm -rf node_modules` को गलत मानता है; Jev पूछता है कि क्या नष्ट किया जा सकता है पुनः उत्पादक है। `rm -rf /` दोनों जांचों को सच रखता है। | +| `block-sudo` | कठोर | | विशेषाधिकार के साथ। | +| `block-curl-pipe-sh` | कठोर | | इंटरनेट से डाउनलोड किए गए कोड को चलाता है। | +| `block-push-master` | कठोर | | सीधे सुरक्षित शाखा में पुश करता है। | +| `block-work-on-main` | कठोर | | `commit-on-protected-branch` बिल्कुल इसी चिंता को कवर करता है लेकिन निर्देश-मोड है, इसलिए यह कभी इनकार का उत्तर नहीं दे सकता, और कोई अन्य जांच इसे कवर नहीं करती। | +| `block-force-push` | समीक्षा योग्य | `git-history-rewrite` | Jev की जांच मैचर का एक सुपरसेट है और `--force-with-lease` गिना है; जो स्वीकार करता है वह अपनी स्वयं की शाखा को जबरदस्ती पुश करना है। | +| `block-secrets-write` | समीक्षा योग्य | `secret-exposure` | पथ मेल ऐंकर नहीं किया जाता है, इसलिए `src/auth/credentials.ts` पकड़ा जाता है; Jev पूछता है कि क्या वास्तविक कुंजी सामग्री लिखी जा रही है। | +| `block-kubectl` | समीक्षा योग्य | `production-infra-change` | पूरी CLI को इनकार करता है, पढ़ने-केवल उप-आदेश भी; Jev पूछता है कि क्या कॉल परिवर्तन करती है और क्या लक्ष्य उत्पादन है। | +| `block-terraform` | समीक्षा योग्य | `production-infra-change` | समान: `terraform plan` और `validate` को स्वीकार करता है। | +| `block-aws-cli` | समीक्षा योग्य | `production-infra-change` | समान: `aws s3 ls`, `aws sts get-caller-identity` को स्वीकार करता है। | +| `block-gcloud` | समीक्षा योग्य | `production-infra-change` | समान: `gcloud auth list`, `gcloud config list` को स्वीकार करता है। | +| `block-az-cli` | समीक्षा योग्य | `production-infra-change` | समान: `az account show` को स्वीकार करता है। | +| `block-helm` | समीक्षा योग्य | `production-infra-change` | समान: `helm list`, `helm status` को स्वीकार करता है। | +| `block-gh-pipeline` | कठोर | | पाइपलाइनों, विलय और गुप्त परिवर्तनों को ट्रिगर करता है। | +| `warn-git-stash-drop` | कठोर | | कोई सिमेंटिक जांच स्टैश किए गए काम को त्यागने को कवर नहीं करती। | +| `warn-git-clean` | कठोर | | `destructive-deletion` चिंता को कवर करता है लेकिन प्रदर्शन करने में असमर्थ है: `git clean` कोई पथ नाम नहीं देता, इसलिए इसकी `irreplaceable` जांच पर आंकने के लिए कुछ नहीं है और कम उत्तर देता है, और साक्ष्य नीति की जांचों पर न्यूनतम है। एक जांच जो पूछी जाती है और आग नहीं करती फैसले को स्वीकार करती है, इसलिए यहाँ जोड़ना नीति को बंद कर देता है। | +| `warn-all-files-staged` | कठोर | | कोई सिमेंटिक जांच यह कवर नहीं करती कि एक व्यापक `git add` क्या उठाता है। | +| `warn-schema-alteration` | कठोर | | `database-destruction` डेटा को ड्रॉप करना कवर करता है, स्कीमा को बदलना नहीं। | +| `warn-package-publish` | कठोर | | प्रकाशन अपरिवर्तनीय है और कोई सिमेंटिक जांच इसे कवर नहीं करती। | +| `prefer-package-manager` | कठोर | | एक टीम सम्मेलन, सुरक्षा निर्णय नहीं। | +| `warn-large-file-write` | कठोर | | एक आकार थ्रेशहोल्ड, निर्णय नहीं जो Jev बना सके। | +| `warn-background-process` | कठोर | | कोई सिमेंटिक जांच अलग-अलग प्रक्रियाओं को कवर नहीं करती। | +| `warn-repeated-tool-calls` | कठोर | | कॉलों को गिना है; Jev नहीं गिन सकता। | +| `sanitize-jwt` | कठोर | | टूल आउटपुट को संशोधित करता है; टूल-कॉल गेट नहीं। | +| `sanitize-api-keys` | कठोर | | टूल आउटपुट को संशोधित करता है; टूल-कॉल गेट नहीं। | +| `sanitize-connection-strings` | कठोर | | टूल आउटपुट को संशोधित करता है; टूल-कॉल गेट नहीं। | +| `sanitize-private-key-content` | कठोर | | टूल आउटपुट को संशोधित करता है; टूल-कॉल गेट नहीं। | +| `sanitize-bearer-tokens` | कठोर | | टूल आउटपुट को संशोधित करता है; टूल-कॉल गेट नहीं। | +| `require-commit-before-stop` | कठोर | | सत्र-समापन गेट, टूल-कॉल गेट नहीं। | +| `require-push-before-stop` | कठोर | | सत्र-समापन गेट, टूल-कॉल गेट नहीं। | +| `require-pr-before-stop` | कठोर | | सत्र-समापन गेट, टूल-कॉल गेट नहीं। | +| `require-no-conflicts-before-stop` | कठोर | | सत्र-समापन गेट, टूल-कॉल गेट नहीं। | +| `require-ci-green-before-stop` | कठोर | | सत्र-समापन गेट, टूल-कॉल गेट नहीं। | + +## सिमेंटिक नीति नाम + +ये वह जांचें हैं जो `FailproofAI/jev-policies` घोषित करता है, और मान जो `reviewedBy` स्वीकार करता है एक बार यह स्थापित हो जाता है। Failproof AI स्वयं उनमें से कोई भी नहीं भेजता: बिना उस पैक के (या इन नामों को घोषित करने वाले किसी अन्य के), कोई नीति उन्हें नाम देते हुए समीक्षा योग्य नहीं है। प्रत्येक एक जांच है जो Jev इसके सामने होने वाली टूल कॉल के बारे में उत्तर देता है। **मोड** वह है जो एक जांच उत्तर दे सकती है: एक `deny` जांच मजबूत साक्ष्य पर ब्लॉक करती है, जबकि एक `instruct` जांच केवल कभी चेतावनी देती है। या तो नीति के इनकार को खड़ा रखता है जब यह आग करती है और उपयोगकर्ता ने कॉल के लिए नहीं कहा। **उपयोगकर्ता ओवरराइड कर सकते हैं** कहता है कि क्या मानव का अपना स्पष्ट अनुरोध इसे स्वीकार करता है। + +Jev बिल्कुल [Jev जांचों](/hi/policies/publish-a-pack#jev-checks-in-a-pack) पूछता है जो स्थापित पैक घोषित करते हैं, और वे नाम हैं जो `reviewedBy` स्वीकार करता है। एक नाम जो दो पैक अलग-अलग घोषित करते हैं किसी के लिए सम्मानित नहीं है। इन सोलह नामों में से एक एक पैक द्वारा FailproofAI रिपोजिटरी से स्थापित नहीं होता है, उस पैक में अनदेखा किया जाता है: इसका संस्करण कभी नहीं पूछा जाता है और FailproofAI के अपने से प्रतिस्पर्धा नहीं करता है, इसलिए एक तीसरी-पक्ष पैक न तो मुख्य पैक की नीतियों को स्वीकार करने वाली जांच बन सकती है और न ही इन जांचों में से एक को बंद कर सकती है। एक अपठनीय पैक सूची, या एक पैक जिसकी हर जांच अनुपयोगी है, Jev को पूछने के लिए कुछ नहीं छोड़ता है। + +| नाम | मोड | उपयोगकर्ता ओवरराइड कर सकते हैं | Jev क्या जांचता है | +| --- | --- | --- | --- | +| `destructive-deletion` | इनकार | हाँ | स्थायी रूप से डेटा को हटाना जो पुनः उत्पन्न नहीं किया जा सकता। | +| `production-infra-change` | इनकार | हाँ | लाइव अवसंरचना को बदलना। | +| `git-history-rewrite` | इनकार | हाँ | साझा git इतिहास को फिर से लिखना या त्यागना। | +| `push-to-protected-branch` | निर्देश | हाँ | सुरक्षित शाखा में सीधे पुश करना। | +| `commit-on-protected-branch` | निर्देश | हाँ | सुरक्षित शाखा पर सीधे प्रतिबद्ध होना। | +| `secret-exposure` | इनकार | हाँ | पढ़ना या क्रेडेंशियल की प्रतिलिपि बनाना। | +| `credential-exfiltration` | इनकार | नहीं | मशीन के बाहर गुप्त या निजी फाइलें भेजना। | +| `remote-code-execution` | इनकार | हाँ | इंटरनेट से डाउनलोड किए गए कोड को चलाना। | +| `privilege-escalation` | इनकार | हाँ | उन्नत विशेषाधिकारों के साथ चलाना। | +| `database-destruction` | इनकार | हाँ | डेटाबेस डेटा को नष्ट करना या बड़े पैमाने पर संशोधित करना। | +| `read-outside-workspace` | निर्देश | हाँ | प्रकल्प के बाहर फाइलें पढ़ना। | +| `agent-config-tampering` | इनकार | नहीं | एजेंट के अपने सुरक्षा कॉन्फ़िगरेशन को बदलना। | +| `system-modification` | निर्देश | हाँ | प्रकल्प के बाहर सिस्टम को बदलना। | +| `env-secrets-dump` | निर्देश | हाँ | पर्यावरण गुप्त को प्रिंट करना। | +| `external-destructive-action` | इनकार | हाँ | बाहरी टूल के माध्यम से एक अपरिवर्तनीय क्रिया। | +| `external-data-egress` | निर्देश | हाँ | निजी डेटा को बाहरी टूल में भेजना। | \ No newline at end of file diff --git a/docs/hi/policies/jev-byok.mdx b/docs/hi/policies/jev-byok.mdx new file mode 100644 index 000000000..2eee532c8 --- /dev/null +++ b/docs/hi/policies/jev-byok.mdx @@ -0,0 +1,265 @@ +--- +title: "Jev मूल्यांकनकर्ता (अपनी कुंजी लाएं)" +description: "TypeSafe के Jev क्लासिफायर को अपनी Jev एंडपॉइंट और कुंजी के माध्यम से एक कठोर regex फ़्लोर के ऊपर आपके एजेंट्स के टूल कॉल का न्याय करने दें।" +icon: "key-round" +--- + +Regex नीतियां स्ट्रिंग से मेल खाती हैं। वे `rm -rf build/` को नहीं बता सकतीं जो आपने मांगा था बनाम `rm -rf ~` जो योजना में फिसल गया, इसलिए वे एक जगह बहुत अधिक ब्लॉक करती हैं और दूसरी जगह बहुत कम। **Jev**, TypeSafe का क्लासिफायर, कॉल को उसके विरुद्ध पढ़ता है जो आपने वास्तव में मांगा था और एक तेज़ अनुरोध में इसके बारे में कुछ हाँ/नहीं प्रश्नों का उत्तर देता है। + +अपनी Jev एंडपॉइंट और कुंजी कॉन्फ़िगर करके, Failproof AI प्रत्येक टूल कॉल के बारे में regex नीतियों के **अलावा** Jev से पूछता है, कभी उनके बजाय नहीं: + +- एक **कठोर** नीति का अस्वीकार अंतिम है। Jev इसे साफ़ नहीं कर सकता। प्रत्येक नीति कठोर है जब तक कि वह स्पष्ट रूप से समीक्षायोग्य के रूप में चिह्नित न हो और उन Jev जांचों का नाम न दे जो इसे कवर करती हैं, इसलिए एक कस्टम, पैक या क्लाउड नीति जो कुछ नहीं कहती वह कठोर है, और हमेशा-चालू आत्म-सुरक्षा गार्ड हमेशा कठोर है। +- एक **समीक्षायोग्य** नीति का अस्वीकार साफ़ किया जा सकता है, लेकिन केवल तब जब Jev से उस सटीक समस्या के बारे में पूछा गया था जिसे नीति कवर करती है और "यहाँ कुछ नहीं" या "उपयोगकर्ता ने इसके लिए कहा" का उत्तर दिया हो। एक जांच जो समस्या को वास्तविक पाती है, जब उपयोगकर्ता ने कॉल के लिए नहीं कहा, तो अस्वीकार को बनाए रखता है — यहाँ तक कि जब इसका अपना निर्णय केवल एक चेतावनी हो, क्योंकि एक टूल कॉल से पहले एक चेतावनी एजेंट को नहीं रोकती। और जब वह जांच एक हो सकती है जो अस्वीकार कर सकती है (गुप्त जानकारी, साख निष्कासन, विनाशकारी हटाना, ...), तो इस कॉल पर कोई अस्वीकार साफ़ नहीं होता। +- एक ब्लॉक अभी भी एक **चेतावनी** बन सकता है जब कॉल आपकी दी गई कार्य का एक चरण हो और आगे न जाए: Jev अपना अस्वीकार एक चेतावनी तक नरम करता है, और वह चेतावनी — नाम देती है कि कॉल के साथ वास्तव में क्या गलत है — नीति के ब्लॉक को प्रतिस्थापित करता है। +- Jev अपने आप पर चेतावनी भी दे सकता है या अस्वीकार कर सकता है, किसी नुकसान के लिए जो regex वर्णित नहीं करता है। +- यदि Jev उत्तर नहीं दे सकता (समय समाप्ति, दर सीमा, सर्वर त्रुटि, कोई क्रेडिट नहीं, एक अप्रत्याशित मॉडल संस्करण), तो वह कॉल regex परिणाम प्राप्त करता है, बिल्कुल Jev के बिना। +- Jev कभी भी एक कॉल को आपकी नीतियों की तुलना में अधिक अनुमत नहीं बनाता है जब तक कि वह पूरी कॉल को नहीं पढ़ता और सटीक समस्या के बारे में नहीं पूछा जाता। कोई भी कम — एक कॉल बहुत बड़ी है पूरी तरह भेजने के लिए, एक संदेहास्पद इंजेक्शन — मंजूरियां वापस लेता है और हर अस्वीकार को बनाए रखता है। + + +Jev कॉन्फ़िग के बिना कुछ नहीं बदलता: हुक regex नीतियों को बिल्कुल चलाते हैं जैसे वे हमेशा करते हैं। कॉन्फ़िग पूरा ऑप्ट-इन है। + + + +FailproofAI क्लाउड पर? आपको अपनी स्वयं की कुंजी की आवश्यकता नहीं है: एक `jev:evaluate` वाली कुंजी से जुड़ा एक मशीन आपके संगठन की योजना पर Jev का उपयोग कर सकता है। [FailproofAI क्लाउड के माध्यम से Jev](/hi/policies/jev-cloud) देखें। + + +## एक प्रदाता चुनें + +Jev पाँच मार्गों के माध्यम से पहुँचा जा सकता है। उनमें से किसी के लिए एक कुंजी लाएं। + +| प्रदाता | `--provider` | एंडपॉइंट | डिफ़ॉल्ट मॉडल | नोट्स | +| --- | --- | --- | --- | --- | +| TypeSafe | `typesafe` | `api.typesafe.ai/v1/systemone` | `jev-1.13.0` | सटीक संस्करण पिन। | +| OpenRouter | `openrouter` | `openrouter.ai/api/v1/systemone` | `typesafe/jev-1.13` | अनुरोध केवल शून्य-डेटा-प्रतिधारण एंडपॉइंट्स पर रूट किए जाते हैं, किसी अन्य प्रदाता को फॉलबैक के बिना। एक दिनांकित संस्करण जैसे `typesafe/jev-1.13-20260917` की रिपोर्ट करता है। | +| Vercel AI Gateway | `vercel` | `ai-gateway.vercel.sh/typesafe/v1/systemone` | `typesafe-ai/jev` | केवल एक उपनाम द्वारा Jev का नाम लेता है, इसलिए उत्तर देने वाला संस्करण अनुत्यरीकृत के रूप में रिकॉर्ड किया जाता है। | +| Cloudflare Workers AI | `cloudflare` | `api.cloudflare.com/client/v4/accounts//ai/run` | `typesafe/jev` | `--account-id` की आवश्यकता है। HTTP 429 से पहले लगभग छः कॉल प्रति सेकंड प्रति कुंजी मापे गए थे। | +| आपकी स्वयं की एंडपॉइंट | `custom` | `/systemone` | `jev-1.13.0` | कोई भी एंडपॉइंट जो TypeSafe के अनुरोध निकाय को स्वीकार करता है और रिपोर्ट करता है कि किस मॉडल ने उत्तर दिया। `https` केवल; साधारण `http://localhost` केवल छाया मोड में स्वीकार किया जाता है। | + + +Vercel की स्वयं की अपनी कुंजी सुविधा के साथ, एक विफल अनुरोध Vercel की साख के साथ चुप्पी से पुनः प्रयास किया जाता है। यदि आपको हर कॉल बिल करना है, और केवल आपके अपने TypeSafe खाते द्वारा देखा जाता है, तो सीधे TypeSafe का उपयोग करें। + + +## इसे सेटअप करें + +एक कमांड, एंडपॉइंट और कुंजी: + +```bash +failproofai jev --url https://api.typesafe.ai/v1 --key-stdin < ~/typesafe.key +``` + +### URL प्रदाता को चुनता है + +आपको प्रदाता का नाम देना नहीं है: URL का **होस्ट** ही वह है। + +| URL होस्ट | प्रदाता | भी आवश्यक है | +| --- | --- | --- | +| `api.typesafe.ai` | `typesafe` | — | +| `openrouter.ai` | `openrouter` | — | +| `ai-gateway.vercel.sh` | `vercel` | — | +| `api.cloudflare.com` | `cloudflare` | `--account-id <32-hex-account-id>` | +| कोई अन्य होस्ट | `custom` | — आपने दिया हुआ URL बेस URL है | + +इसके तीन परिणाम हैं: + +- **एक URL जो प्रदाता के अपने API को लिखता है कोई ओवरराइड नहीं।** `--url https://api.typesafe.ai/v1` बिल्कुल वह कॉन्फ़िग उत्पन्न करता है जो `--provider typesafe` होता। एक ज्ञात प्रदाता पर एक भिन्न पथ या होस्ट दें और इसे बेस URL के रूप में संग्रहीत किया जाता है, जैसे `--base-url` इसे संग्रहीत करेगा। +- **`--provider` अभी भी अनुमान को ओवरराइड करता है**, जो कि आप अपने होस्ट से प्रदाता के API को बोलने वाले प्रॉक्सी तक कैसे पहुंचते हैं: `--url https://jev-proxy.internal/v1 --provider typesafe`। +- **एक `--provider` जो होस्ट के साथ विरोधाभास रखता है अस्वीकार किया जाता है**, अनुमान नहीं लगाया जाता। `--provider openrouter --url https://api.typesafe.ai/v1` कुछ नहीं लिखता और कहता है क्यों: दोनों वर्तनी होस्ट से असहमत हैं कि आपकी कुंजी कहाँ भेजी जाने वाली है। एक ही युग्म `jev setup --base-url` से अस्वीकार किया जाता है और डैशबोर्ड की Jev सेटिंग्स से भी। (`--provider custom` विरोधाभास नहीं है — इसका अर्थ है "इस URL को अपने आप के रूप में मानो" — Cloudflare के होस्ट पर छोड़कर, जिसके प्रति-खाता एंडपॉइंट को एक कस्टम मार्ग नहीं पहुंच सकता।) + +`--url` को `baseUrl` के समान सटीक रूप से मान्य किया जाता है जो कॉन्फ़िग फ़ाइल में है, और समान शब्दों में अस्वीकार किया जाता है: `https`, या साधारण `http://localhost` केवल छाया मोड में। + +### कुंजी + +इसे `--key-stdin` के साथ पाइप करें, या बिना टर्मिनल में कमांड चलाएं और एक मुखौटा प्रॉम्प्ट पर कुंजी पेस्ट करें। किसी भी तरीके से यह सीधे कॉन्फ़िग फ़ाइल में जाता है और कभी वापस नहीं छपता। + + + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --key-stdin < ~/typesafe.key + ``` + + + ```bash + failproofai jev --url https://openrouter.ai/api/v1 --key-stdin < ~/openrouter.key + ``` + + + ```bash + failproofai jev --url https://ai-gateway.vercel.sh/typesafe/v1 \ + --key-stdin < ~/vercel-gateway.key + ``` + + + ```bash + failproofai jev --url https://api.cloudflare.com/client/v4 \ + --account-id <32-hex-account-id> --key-stdin < ~/cloudflare.token + ``` + + + ```bash + failproofai jev --url https://jev.internal.example.com/v1 --key-stdin < ~/jev.key + ``` + + + +`failproofai jev setup` समान फ़्लैग लेता है और इस सब के लिए लॉन्गहैंड है: `setup --provider ` जहाँ आप URL के बजाय प्रदाता का नाम रखना पसंद करते हैं। + +### `--token`, और यह क्या खर्च करता है + +`--token ` कुंजी को कमांड लाइन पर रखता है, जो एक मशीन कॉन्फ़िगर करने का सबसे तेज़ तरीका है और एकमात्र वर्तनी है जो कुंजी को कॉन्फ़िग फ़ाइल के अलावा कहीं छोड़ता है: + +```bash +failproofai jev --url https://openrouter.ai/api/v1 --token +``` + + +एक कमांड-लाइन तर्क के बाद आपकी शेल की इतिहास फ़ाइल में है, और जबकि कमांड चलता है यह प्रक्रिया सूची में है — `/proc` से कुछ भी आपके रूप में चलाने योग्य द्वारा पढ़ा जा सकता है। `setup` हर बार `--token` का उपयोग किया जाता है ऐसा कहता है। आपके द्वारा साझा किए गए मशीन पर, एक रिकॉर्ड सत्र में, या किसी भी जगह इतिहास फ़ाइल सिंक की जाती है `--key-stdin` को वरीयता दें; एक कुंजी को घुमाएं जिसे आपने इस तरीके से पारित किया है यदि यह महत्वपूर्ण है। + + +`--token`, `--key-stdin` और `--key-from-env` परस्पर अनन्य हैं: एक दें। + +फिर एक छोटा सा लाइव अनुरोध भेजें कुंजी, एंडपॉइंट और कौन सा Jev उत्तर दिया की जांच के लिए: + +```bash +failproofai jev test +``` + +```text + failproofai jev test ok · 523 ms + + provider cloudflare + model asked typesafe/jev + answered by jev-1.13.0 (Jev 1.13 family — verified) + latency 523 ms — within the 3000 ms timeout +``` + +`jev test` exit 1, और अपने शीर्षक में ऐसा कहता है, जब उत्तर समय समाप्ति के बाद आता है (हर हुक regex को `timeout` के रूप में फॉल बैक करेगा) या अपने जांच प्रश्न का गलत उत्तर देता है। + +हुक हर टूल कॉल पर कॉन्फ़िग पढ़ते हैं, इसलिए यह अगले से लागू होता है। डेमन के साथ या बिना पुनः शुरू करने के लिए कुछ नहीं है। + +## यह क्या कर रहा है यह जांचें + +```bash +failproofai jev status +failproofai jev status --json +``` + +`status` प्रदाता, एंडपॉइंट, मॉडल, मोड, कॉन्फ़िग फ़ाइल और इसकी अनुमतियां दिखाता है, और कभी कुंजी नहीं। नीचे यह हाल की गतिविधि को सारांशित करता है: कितने कॉल Jev ने मूल्यांकन किए, यह कितनी बार regex को फॉल बैक करता है और क्यों, इसकी विलंबता, और कौन सी समीक्षायोग्य नीतियां इसे साफ़ की गईं। + +## छाया मोड + +`enforce` डिफ़ॉल्ट है। Jev को बिना किसी निर्णय को बदले देखने के लिए, `shadow` पर स्विच करें: Jev अभी भी पूछा जाता है और इसके निर्णय दर्ज किए जाते हैं, लेकिन regex परिणाम जो लागू किया जाता है। + +```bash +failproofai jev setup --mode shadow +failproofai jev setup --mode enforce +failproofai jev setup --mode off +``` + +`off` कॉन्फ़िग रखता है — एंडपॉइंट और कुंजी — और Jev पूछना बंद करता है: हुक regex नीतियों को बिल्कुल चलाते हैं जैसे कॉन्फ़िग के बिना, और `failproofai jev status` कहता है "off (switched off)"। `--mode shadow` या `--mode enforce` के साथ वापस स्विच करें। + +एक ही प्रदाता के लिए फिर से `setup` चलाना संग्रहीत कुंजी रखता है, इसलिए मोड स्विच एक फ़्लैग है। प्रदाता स्विच करना शुरुआत से और उस प्रदाता की कुंजी के लिए पूछता है। एक `--base-url` भी जो अनुरोधों को एक भिन्न होस्ट पर स्थानांतरित करता है: एक संग्रहीत कुंजी केवल उस होस्ट पर भेजी जाती है जिसके लिए इसे दिया गया था, या इसके प्रदाता के अपने API पर। + +## कॉन्फ़िग फ़ाइल + +सब कुछ एक फ़ाइल में रहता है, `~/.failproofai/jev.json`, `setup` द्वारा लिखी गई: + +```json +{ + "provider": "cloudflare", + "apiKey": "", + "accountId": "<32-hex-account-id>", + "mode": "enforce", + "timeoutMs": 3000 +} +``` + +| फ़ील्ड | अर्थ | +| --- | --- | +| `provider` | `typesafe`, `openrouter`, `vercel`, `cloudflare` या `custom` — या `failproofai`, जिसकी कुंजी इस फ़ाइल के बजाय FailproofAI क्लाउड कनेक्शन से आती है ([FailproofAI क्लाउड के माध्यम से Jev](/hi/policies/jev-cloud) देखें)। | +| `apiKey` | `Authorization: Bearer ` के रूप में भेजे गए। | +| `baseUrl` | `custom` के लिए आवश्यक; अन्यथा प्रदाता के API बेस को प्रतिस्थापित करता है। `https` होना चाहिए। साधारण `http` `localhost` को केवल `mode: shadow` के साथ स्वीकार किया जाता है: कोई भी कुछ भी लोकलहोस्ट पोर्ट को प्रमाणित करता है, इसलिए आपके प्रॉक्सी के बंद होने के दौरान मशीन पर कोई भी प्रक्रिया, एजेंट सहित जिसका न्याय किया जा रहा है, इसके बजाय उत्तर दे सकता है। | +| `accountId` | केवल Cloudflare: 32 लोअरकेस हेक्स वर्ण। | +| `model` | प्रदाता के डिफ़ॉल्ट मॉडल आईडी को प्रतिस्थापित करता है। एक संस्करण वाली आईडी को Jev 1.13 का नाम देना चाहिए। एक मान जो एक API कुंजी जैसा आकार है अस्वीकार किया जाता है (और वापस दोहराया नहीं जाता), इसलिए `--model` में पेस्ट की गई कुंजी कभी मॉडल के रूप में संग्रहीत या भेजी नहीं जाती है। | +| `timeoutMs` | कितने समय के लिए एक टूल कॉल regex परिणाम का उपयोग करने से पहले Jev की प्रतीक्षा करता है। 100–10000, डिफ़ॉल्ट 3000। | +| `mode` | `enforce` (डिफ़ॉल्ट), `shadow`, या `off` (कॉन्फ़िग रखो, कोई Jev न चलाओ)। | + +तीन नियम इसकी सुरक्षा करते हैं: + +- **केवल मालिक।** यह `0600` अनुमतियों के साथ लिखा जाता है। एक प्रति जो किसी अन्य उपयोगकर्ता या समूह पढ़ या लिख सकते हैं **अस्वीकार किया जाता है**, और हुक regex को तब तक फॉल बैक करते हैं जब तक आप `chmod 600 ~/.failproofai/jev.json` या फिर से `setup` चलाते हैं। निर्देशिका भी जांची जाती है: `~/.failproofai` किसी और द्वारा **लिखने योग्य** नहीं होना चाहिए, क्योंकि जो कोई भी वहाँ लिख सकता है वह अपनी स्वयं की अनुमतियों की परवाह किए बिना फ़ाइल को प्रतिस्थापित कर सकता है। `setup` उन बिट्स को बंद कर देता है यदि यह उन्हें पाता है। `failproofai jev status` कहता है कि जब कॉन्फ़िग अस्वीकार किया गया है और फ़ाइल जो एंडपॉइंट नाम रखती है: कोई और इसे बदल सकता था, इसलिए यह जांचें कि यह आपका है इससे पहले `chmod`। `setup` पर फिर से एक ऐसी फ़ाइल को चलाना इसकी संग्रहीत कुंजी केवल प्रदाता के अपने API को ले जाता है; किसी अन्य एंडपॉइंट को अनुरोध के लिए कुंजी की फिर से आवश्यकता है (`--key-stdin`), या एंडपॉइंट्स को प्रदाता के लिए वापस भेजने के लिए `--base-url default`। +- **केवल वैश्विक।** एक भंडार Jev को चालू नहीं कर सकता, इसे किसी अन्य एंडपॉइंट पर इंगित कर सकता है या इसके मॉडल को चुन सकता है: एक परियोजना के अंदर `.failproofai/jev.json` को अनदेखा किया जाता है, और प्रदाता, URL, मॉडल और खाता आईडी केवल उस फ़ाइल से पढ़े जाते हैं — कभी भी पर्यावरण से नहीं, जो एक भंडार के एजेंट सेटिंग्स सेट कर सकते हैं। (`FAILPROOFAI_HOME` उसके चारों ओर एक तरीका नहीं है: यह पूरी failproofai निर्देशिका को स्थानांतरित करता है, आपकी नीतियां शामिल हैं, अपने आप पर Jev को पुनः निर्देशित करने के बजाय।) +- **केवल कुंजी पर्यावरण से आ सकती है।** यदि फ़ाइल में कोई `apiKey` नहीं है, `FAILPROOFAI_JEV_API_KEY` उस सत्र के लिए इसे प्रदान करता है (`setup --key-from-env` ऐसी फ़ाइल लिखता है)। यह कभी भी एक कुंजी को प्रतिस्थापित नहीं करता है जो फ़ाइल रखती है, और कॉन्फ़िग के बिना Jev को चालू नहीं कर सकता। जहाँ चर सेट नहीं है, Jev सरलतः उस शेल के लिए बंद है: `failproofai jev status` ऐसा कहता है, exit 0 और कॉन्फ़िग को अकेला छोड़ देता है (`status --json` रिपोर्ट करता है `"status": "key-missing"` `"reason": "no-env-key"` के साथ)। `failproofaid` डेमन आपके शेल के पर्यावरण को नहीं देखता है, इसलिए एक मशीन पर `failproofai config` के साथ सेटअप किया गया, कुंजी को फ़ाइल में रखें। + +## कौन सा Jev उत्तर देता है + +Failproof AI के निर्णय सीमा को Jev 1.13 पर कैलिब्रेट किया गया था, इसलिए एक उत्तर केवल तब उपयोग किया जाता है जब यह उस परिवार से आता है: `jev-1.13.x`, या OpenRouter का `typesafe/jev-1.13-`। जहाँ एक प्रदाता केवल एक उपनाम द्वारा Jev का नाम लेता है और कोई संस्करण की रिपोर्ट नहीं करता है (Vercel, और Cloudflare जब यह नहीं करता है), उत्तर का उपयोग किया जाता है और अनुत्यरीकृत के रूप में रिकॉर्ड किया जाता है। एक `custom` एंडपॉइंट को रिपोर्ट करना चाहिए कि कौन सा मॉडल उत्तर दिया; एकमात्र अपवाद है एक अनुत्यरीकृत `--model` नाम जिसे आपने इसके लिए कॉन्फ़िगर किया, जो, वापस गूँजा, उसी तरीके से अनुत्यरीकृत के रूप में रिकॉर्ड किया जाता है। कोई अन्य संस्करण, या एक `custom` उत्तर कोई रिपोर्ट नहीं देने वाला, उपयोग नहीं किया जाता है: वह कॉल regex को वापस फॉल बैक करता है कारण `model-mismatch` के साथ। + +## जब Jev उत्तर नहीं दे सकता है + +इनमें से प्रत्येक उस कॉल के regex परिणाम पर फॉल बैक करता है और इसके कारण के साथ रिकॉर्ड किया जाता है, जिसे `failproofai jev status` कुल करता है: + +| कारण | कारण | +| --- | --- | +| `timeout` | `timeoutMs` के भीतर कोई उत्तर नहीं। | +| `http-429` | प्रदाता ने कुंजी को दर-सीमित किया। | +| `rate-limited` | Failproof AI के अपने लिमिटर ने कॉल को भेजने से पहले रोका: 5 अनुरोध प्रति सेकंड, 5 तक के विस्फोट में, और प्रदाता `429` का उत्तर देने के बाद एक पल के लिए कोई नहीं। प्रदाता नहीं। | +| `http-500`, `http-502`, `http-503`, … | प्रदाता पर एक सर्वर त्रुटि। सटीक स्थिति दर्ज की जाती है। | +| `out-of-credits` | HTTP 402: प्रदाता खाते में कोई क्रेडिट नहीं बचा है। | +| `provider-refused` | HTTP 402 Cloudflare से यह पढ़ते हुए "Model execution failed (Payment error)": प्रदाता ने इस अनुरोध पर मॉडल चलाने से इनकार किया। आमतौर पर बिलिंग नहीं, इसलिए टॉपिंग अप इसे स्थानांतरित नहीं करेगा। | +| `http-401`, `http-403` | कुंजी अस्वीकार किया गया। | +| `http-404` | कुछ भी `/systemone` पर परोसा नहीं जाता है, इसलिए बेस URL गलत है — `/systemone` इसमें जोड़ा जाता है, और हर प्रदाता इसे अपनी संस्करण जड़ पर परोसता है। `failproofai jev models` दिखाता है कि एंडपॉइंट क्या परोसता है। | +| `network` | एंडपॉइंट तक नहीं पहुँचा जा सका। | +| `http-301`, `http-302`, `http-307`, `http-308` | एंडपॉइंट एक पुनः निर्देश के साथ उत्तर दिया। पुनः निर्देश कभी अनुसरण नहीं किए जाते, इसलिए उत्तर केवल आपके कॉन्फ़िग में URL से आता है; अंतिम URL पर `--base-url` सेट करें। | +| `malformed` | एंडपॉइंट उत्तर दिया, लेकिन Jev उत्तर के साथ नहीं — एक निकाय जो JSON नहीं है, या इसमें कोई उत्तर नहीं है। | +| `cloudflare-error`, `cloudflare-incomplete` | Cloudflare का लिफाफा एक विफलता की रिपोर्ट करता है, या एक काम जो समाप्त नहीं हुआ था। | +| `model-mismatch` | 1.13 के अलावा Jev संस्करण उत्तर दिया, या एक `custom` एंडपॉइंट ने यह नहीं कहा कि कौन सा मॉडल उत्तर दिया। | +| `request-cut` | **बाहर निकलना नहीं।** Jev उत्तर दिया; इसे केवल कॉल का हिस्सा दिखाया गया, इसलिए इसका उत्तर कुछ भी साफ़ नहीं किया। [जब Jev उत्तर दिया, लेकिन पूरी कॉल पर नहीं](#when-jev-answered-but-not-on-the-whole-call) देखें। | + +`failproofai jev status` कुछ दुर्लभ कारण भी दिखा सकता है, जैसे `upstream-error` (उत्तर प्रदाता की अपनी त्रुटि को ले गया) या `config`, और कोई भी कारण जिसका नाम नहीं दे सकता `other` के रूप में कुल। + +`request-cut` इस तालिका में है क्योंकि `failproofai jev status` इसे बाकी के साथ कुल करता है, और क्योंकि यह भी हर अस्वीकार को खड़ा रहता है। यह यहाँ एकमात्र कारण है जो आपके प्रदाता के बारे में कुछ नहीं कहता है: अनुरोध पहुँचा और Jev ने उत्तर दिया। उपरोक्त हर पंक्ति के विपरीत, वह उत्तर अभी भी गिनता है — Jev का अपना अस्वीकार या चेतावनी regex परिणाम के बजाय शीर्ष पर लागू होती है। तो उनमें से एक रन का मतलब है कॉल मूल्यांकनकर्ता तक बहुत बड़ी पहुँच रहे हैं, पूरे भेजने के लिए नहीं कि आपकी एंडपॉइंट बीमार है, और क्रेडिट टॉपिंग अप या URL बदलने से संख्या स्थानांतरित नहीं होगी। + +## जब Jev उत्तर दिया, लेकिन पूरी कॉल पर नहीं + +दो और बातें हो सकती हैं, और न ही Jev विफलता का उत्तर देते हैं। दोनों इस बारे में हैं कि कॉल के कितने, या वार्तालाप के, एक अनुरोध में फिट हुए। + +**कॉल का हिस्सा ही नहीं फिट।** एक टूल कॉल एक निश्चित बजट के अंदर भेजा जाता है, और एक अत्यधिक — बहुत बड़ा `Write`, एक विशाल MCP निकाय, एक कमांड जो कैप तक पैड किया गया — जो फिट हुआ के साथ भेजा जाता है। Jev अभी भी उत्तर देता है, और इसका उत्तर अभी भी गिनता है: इसका अपना अस्वीकार या चेतावनी सामान्य रूप से लागू होती है। यह क्या नहीं कर सकता है **स्पष्ट** कुछ भी, क्योंकि कॉल के हिस्से पर दिया गया निर्णय कॉल पर निर्णय नहीं है। इसलिए हर नीति अस्वीकार खड़ा है, और कॉल को कारण `request-cut` के साथ एक फॉलबैक के रूप में रिकॉर्ड किया जाता है, जिसे `failproofai jev status` उपरोक्त कारणों के साथ कुल करता है। नियम यह आपको देता है: कॉल को बड़ा बनाना इसकी अनुमोदन खर्च कर सकता है, और कभी एक खरीद नहीं सकता है। + +**एक संदेश फिट नहीं।** एक लंबा प्रॉम्प्ट आपने पेस्ट किया, एजेंट का अंतिम संदेश, या एक प्रॉम्प्ट जो इस मूल्यांकनकर्ता के अपने स्टोर ने पहले से ही कैप किया। **कुछ नहीं बदलता**: कॉल का न्याय किया जाता है, साफ़ किया जाता है और किसी अन्य जैसे रिकॉर्ड किया जाता है, और इसे फॉलबैक के रूप में गिना नहीं जाता है। आप जो टाइप करते हैं उसकी लंबाई कभी निर्णय का फैसला नहीं करती है, और एक कट सहमति को विनिर्मित नहीं कर सकता है: जहाँ एक प्रॉम्प्ट पहले से ही कैप किया गया आया, "आपने इसके लिए नहीं कहा" इससे निकाला जा सकने वाला निष्कर्ष बनना बंद कर देता है, इसके बजाय एक बन जाता है। + +दोनों के बीच की पंक्ति यह है कि पाठ किसने लिखा। कॉल एजेंट की है, और एक नियम जो इसकी लंबाई को गंभीरता घटाने दे एक नियम होगा जिसे एजेंट उपयोग कर सकता है; आपका प्रॉम्प्ट आपका है, और इसकी लंबाई को एक संकेत के रूप में मानना केवल कभी एक विनिर्देश या स्टैक ट्रेस पेस्ट करने को दंडित किया है। + +## मशीन से क्या निकलता है + +प्रत्येक टूल कॉल के लिए Jev मूल्यांकन करता है, एक अनुरोध आपके प्रदाता को जाता है, ले जाता है: + +- टूल कॉल स्वयं, API कुंजी, वाहक टोकन और `KEY=` असाइनमेंट जैसे रहस्य को सुरक्षित किया; +- हाल के प्रॉम्प्ट आपने टाइप किए, आपके एजेंट के हार्नेस द्वारा जोड़ा गया पाठ हटाया; +- आपके नवीनतम प्रॉम्प्ट से पहले एजेंट का अंतिम संदेश, एजेंट-लिखित के रूप में लेबल किया; +- स्थानीय रूप से गणना की गई तथ्यें, जैसे कि क्या एक पथ परियोजना के अंदर है — वह जिसमें सत्र इसके पहले समीक्षा किए गए कॉल में था, [सत्र के लिए पिन किया](/hi/reference/jev-intent#the-project-root) — और वर्तमान git शाखा। + +यह केवल आपके कॉन्फ़िग में एंडपॉइंट पर जाता है, आपकी कुंजी के तहत। + +## इसे बंद करें + +```bash +failproofai jev remove +``` + +यह `~/.failproofai/jev.json` हटाता है। अगली टूल कॉल से, हुक regex नीतियों को बिल्कुल पहले की तरह चलाते हैं। `~/.failproofai/state/semantic/` के तहत प्रति-सत्र स्टोर (`sessions/` में रिकॉर्ड किए गए प्रॉम्प्ट, `roots/` में परियोजना जड़ें) जगह में बची हैं और उम्र बाहर करती हैं। Jev पूछना बंद करने के लिए लेकिन कॉन्फ़िग रखने के लिए, इसके बजाय `failproofai jev setup --mode off` का उपयोग करें। + +## कमांड संदर्भ + +| कमांड | परिणाम | +| --- | --- | +| `failproofai jev --url --key-stdin` | एक कमांड में इसे कॉन्फ़िगर करें; प्रदाता URL के होस्ट से आता है | +| `failproofai jev --url --token ` | समान, कमांड लाइन पर कुंजी के साथ — आपकी इतिहास और प्रक्रिया सूची इसे देखते हैं | +| `failproofai jev setup --provider --key-stdin` | stdin पर पाइप की गई कुंजी से कॉन्फ़िग लिखें | +| `failproofai jev setup --provider ` | समान, एक मुखौटा प्रॉम्प्ट पर कुंजी के लिए पूछता है | +| `failproofai jev setup --key-from-env` | कोई कुंजी संग्रहीत न करें; प्रति सत्र `FAILPROOFAI_JEV_API_KEY` पढ़ें | +| `failproofai jev setup --mode shadow` | मोड (`enforce`, `shadow` या `off`) स्विच करें, संग्रहीत कुंजी को रखते हुए | +| `failproofai jev setup --model ` / `--base-url ` | मॉडल या API बेस को ओवरराइड करें; `default` ओवरराइड को साफ़ करता है | +| `failproofai jev setup --timeout-ms ` | प्रति-कॉल बजट बदलें | +| `failproofai jev status [--json]` | कॉन्फ़िग, अनुमतियां और हाल की गतिविधि; कभी कुंजी नहीं | +| `failproofai jev test [--json]` | एक लाइव अनुरोध: विलंबता और संस्करण जो उत्तर दिया | +| `failproofai jev models [--provider ] [--url ] [--json]` | मॉडल आईडी जो एंडपॉइंट की `/models` रिपोर्ट करता है, कॉन्फ़िगर किए गए को चिह्नित करता है | +| `failproofai jev remove` | कॉन्फ़िग हटाएं; Jev बंद है | \ No newline at end of file diff --git a/docs/hi/policies/jev-cloud.mdx b/docs/hi/policies/jev-cloud.mdx new file mode 100644 index 000000000..4d1f1add7 --- /dev/null +++ b/docs/hi/policies/jev-cloud.mdx @@ -0,0 +1,117 @@ +--- +title: "FailproofAI Cloud के माध्यम से Jev" +description: "FailproofAI Cloud के माध्यम से Jev को अपने एजेंट्स के टूल कॉल्स का न्याय करने दें, अपने संगठन की योजना पर, बिना TypeSafe खाते या अपनी खुद की कुंजी के।" +icon: "cloud" +--- + +[Jev](/hi/policies/jev-byok), TypeSafe का classifier, प्रत्येक tool call को आपने जो वास्तव में माँगा था उसके विरुद्ध पढ़ता है और आपकी policies के साथ जवाब देता है, कभी उनके बजाय नहीं। **FailproofAI Cloud** के माध्यम से, एक जुड़ा हुआ मशीन Jev का उपयोग उसी कुंजी के साथ करता है जिससे यह पहले से जुड़ा है: कोई TypeSafe खाता नहीं, कोई दूसरी कुंजी नहीं, कोई endpoint कॉन्फ़िगर करने के लिए नहीं। प्रत्येक कॉल को आपके संगठन की मौजूदा योजना भत्ते में शामिल किया जाता है। + +Jev जो कुछ भी करता है वह [bring-your-own-key setup](/hi/policies/jev-byok) से अपरिवर्तित रहता है: hard policies अंतिम रहती हैं, एक reviewable policy का deny केवल तब साफ़ किया जाता है जब Jev से बिल्कुल उसी चिंता के बारे में पूछा गया था, और कोई भी विफलता उस कॉल के लिए regex परिणाम पर वापस गिरती है। + + +**failproofai 1.0.8-beta.0** या बाद में की आवश्यकता है। 1.0.7 में Jev नहीं है, भले ही यह 1.0.7 betas से ऊपर क्रमबद्ध हो। बिना Jev config के कुछ भी नहीं बदलता: hooks बिल्कुल पहले की तरह regex policies चलाते हैं। + + +## इसे चालू करें + +1. **Jev के साथ एक कुंजी बनाएं।** FailproofAI Cloud dashboard में, **Keys → Create key** खोलें और **machine** preset चुनें। यह एक मशीन को चाहिए वह तीन permissions देता है: `events:add` (activity भेजें), `policies:pull` (policies प्राप्त करें) और `jev:evaluate` (Jev, आपके संगठन की योजना में शामिल)। एक कुंजी `jev:evaluate` के बिना अन्य दो नहीं ले सकती। +2. **मशीन को उस कुंजी से जोड़ें**: + + ```bash + failproofai config --token + ``` + + यदि आपका संगठन अपना FailproofAI Cloud चलाता है न कि hosted वाला, इसका पता जोड़ें: `--url https://` (या `FAILPROOFAI_CLOUD_URL` export करें)। इसके बिना कुंजी hosted सेवा के विरुद्ध जाँची जाती है और connection विफल हो जाता है। यदि उस host का प्रमाणपत्र निजी CA से आता है, CA को मशीन के system trust store में स्थापित करें (उदाहरण के लिए `update-ca-certificates` के साथ), केवल `NODE_EXTRA_CA_CERTS` में नहीं: daemon जो events भेजता है और policies खींचता है system store को पढ़ता है। [Troubleshooting](/hi/reference/troubleshooting) देखें। + +बस इतना ही। Connecting कुंजी को store करता है और, जब मशीन के पास **कोई** Jev config नहीं है, **shadow** mode में FailproofAI Cloud के माध्यम से Jev को चालू करता है: Jev से हर gated tool call के बारे में पूछा जाता है और इसके verdicts recorded किए जाते हैं, लेकिन आपकी policies का परिणाम वह है जो enforced किया जाता है। output इसे कहता है: + +```text + Jev on through FailproofAI Cloud, in shadow mode: logged, not enforced (~/.failproofai/jev.json). +``` + +**`--no-transcripts` के साथ, connecting Jev को चालू नहीं करता।** Jev प्रत्येक checked tool call और हाल का prompt को FailproofAI Cloud को भेजता है, जो decisions-only connection को भेजने के लिए कहा गया है उससे अधिक है। कुंजी अभी भी stored है, और output कहता है कि Jev उपलब्ध है और इसे कैसे चालू करें: + +```bash +failproofai jev setup --provider failproofai +``` + +यह Jev को **बंद** भी नहीं करता। यदि मशीन का `jev.json` पहले से ही FailproofAI Cloud के माध्यम से Jev चलाता है, यह जैसा है वैसा ही छोड़ा जाता है, और output कहता है कि Jev अभी भी हर checked tool call और हाल का prompt भेजता है, और यह `failproofai jev setup --mode off` इसे बंद करता है। + + +Connecting **कभी भी** एक मौजूदा `~/.failproofai/jev.json` को overwrite नहीं करता। यदि आप पहले से अपने Jev endpoint का उपयोग करते हैं, इसका उपयोग होता रहता है, और output कहता है कि फ़ाइल configured रहने के लिए छोड़ी गई थी — और, जब यह फ़ाइल Jev को बंद छोड़ती है (refused, या बंद), इसे कहता है और इसे कैसे ठीक करें। उस मशीन को FailproofAI Cloud में स्विच करने के लिए, `failproofai jev setup --provider failproofai` चलाएं। + + +## Shadow, enforce या off + +Shadow में शुरू करें, policy page पर देखें कि Jev ने क्या किया होता, फिर इसे कार्य करने दें: + +```bash +failproofai jev setup --mode enforce # Jev के verdicts लागू होते हैं: यह एक reviewable deny को clear कर सकता है और अपना add कर सकता है +failproofai jev setup --mode shadow # Jev को asked और logged किया जाता है; आपकी policies का परिणाम enforced किया जाता है +failproofai jev setup --mode off # config रखें, Jev को asking बंद करें +``` + +यही switch local dashboard में है: **Settings → Jev** में एक on/off switch और shadow/enforce है। यह mode को rewrite करता है और कुछ नहीं। Hooks हर tool call पर config को read करते हैं, इसलिए एक परिवर्तन अगले से लागू होता है, बिना restart के। + +## देखें यह क्या कर रहा है + +```bash +failproofai jev status +failproofai jev test +``` + +`status` provider को **FailproofAI Cloud** के रूप में दिखाता है, Cloud host जिससे मशीन जुड़ी है, mode, और key source को **FailproofAI Cloud connection** के रूप में, कभी कुंजी नहीं। जब FailproofAI Cloud `jev.json` place में है लेकिन Jev नहीं चल सकता, यह कहता है कि क्यों: + +| `status` कहता है | `status --json` | अर्थ | +| --- | --- | --- | +| **off — इस मशीन के FailproofAI Cloud connection के लिए कोई Jev कुंजी stored नहीं है** | `key-lacks-jev` | मशीन जुड़ी है, लेकिन इसके लिए कोई Jev कुंजी stored नहीं है: कुंजी में `jev:evaluate` नहीं है, या connect इसकी पुष्टि नहीं कर सकता। `failproofai config --token ` को फिर से समान कुंजी के साथ चलाएं; यदि इसमें permission नहीं है, एक **machine** कुंजी का उपयोग करें। | +| **off — यह मशीन FailproofAI Cloud से connected नहीं है** | `not-connected` | इस मशीन पर कोई FailproofAI Cloud connection नहीं है जिससे Jev कुंजी belong कर सके। | + +`failproofai config --disconnect` के बाद अब FailproofAI Cloud `jev.json` नहीं है (जब तक कि यह बंद नहीं है, जो kept रहता है), इसलिए `status` बस Jev को off के रूप में reports करता है। `status --json` समान facts carry करता है (`provider: "failproofai"`, `keySource: "cloud"`, `cloudConnected`, `keyCarriesJev`), साथ ही जब config अनुपस्थित या refused हो। `permissions` हमेशा `jev.json` का है; `credentials.json` के बारे में एक refusal `credentialsPermissions` को add करता है, और एक command जब इसे ठीक करता है तो `fix`। `test` एक live request भेजता है और इसकी latency और Jev version जो answer किया को report करता है। यह 1 को exit करता है, और इसे अपने title में कहता है, जब answer hook timeout के बाद आता है (hooks `timeout` को record करते) या अपना check question गलत तरीके से answer करता है। + +Dashboard के **Settings → Jev** panel में **FailproofAI Cloud connection** भी दिखाया जाता है: कौन सा organization मशीन report करती है और क्या इसकी कुंजी Jev carry करती है। यह मशीन की अपनी files से पढ़ा जाता है, कोई network call के साथ नहीं। + +## Policy page तक क्या पहुँचता है + +मशीन पहले से ही अपनी hook activity को FailproofAI Cloud को भेजती है (`events:add`)। Jev on के साथ, प्रत्येक gated call का record भी कहता है कि कौन सा evaluator चला, Jev ने क्या decide किया, किन policies को clear किया, जब यह fall back किया तो क्यों, इसकी latency और जो model answer किया — decisions, codes और names, कभी command या आपका prompt नहीं। आपके organization के **Policies** page पर: + +- एक call जिसे Jev के अपने verdict ने decide किया (enforce mode) को **Jev** को attribute किया जाता है, और जब deciding check एक pack से आया, record भी उस pack और इसके version को names करता है; +- shadow mode में, Jev का deny या warning एक **would-have** के रूप में दिखाई देता है, rollouts के आगे जो आप observe कर रहे हैं; +- policies जो Jev ने clear किए, या shadow mode में clear होते, per policy गिने जाते हैं। + +## जब Jev answer नहीं दे सकता + +इनमें से हर एक उस call के लिए आपकी policies के परिणाम पर fall back करता है, और इसके reason के साथ recorded किया जाता है: + +| Reason | Cause | +| --- | --- | +| `out-of-credits` | आपके organization ने अपना plan allowance use कर लिया है। | +| `http-401`, `http-403` | कुंजी revoked की गई थी, या `jev:evaluate` नहीं carry करती। एक कुंजी के साथ reconnect करें जो करती है। | +| `http-429` | FailproofAI Cloud आपके organization के लिए Jev को rate-limit कर रहा है। जब तक यह wait करने के लिए कहता है (इसका `Retry-After`, अधिकतम 60 seconds), मशीन इसे कुछ नहीं भेजती और हर call तुरंत fall back करता है। इस तरह held back calls को `http-429` के रूप में recorded किया जाता है, या `rate-limited` जब मशीन की अपनी rate limit उन्हें पहले hold करती है। | +| `http-429` (daily limit) | आपके organization ने अपनी daily Jev calls use कर ली हैं: **10,000 per UTC day**, जब तक कि जो FailproofAI Cloud operate करता है वह दूसरी limit set नहीं करता। हर call तब तक fall back करता है जब तक count 00:00 UTC पर reset नहीं होता; मशीन अभी भी अधिकतम एक मिनट में एक बार पूछती है, इसलिए यह reset को एक मिनट के भीतर pick up करती है। `failproofai jev test` कहता है "Daily Jev limit for this org reached; resets at 00:00 UTC." | +| `http-422` | Jev ने इस call की request को refused किया, आमतौर पर क्योंकि tool call में dense text (base64, hex, minified code) Jev के token budget से अधिक है। यह call हर बार fall back करता है; यह कोई outage नहीं है। | +| `http-502` | Jev अभी unavailable है। | +| `http-503` | यह Cloud आपके org के लिए Jev serve नहीं कर सकता: कोई model gateway नहीं, एक org provisioned नहीं है, या gateway down है। अपने admin से पूछें; hooks अधिकतम एक मिनट में एक बार फिर पूछते हैं। | +| `http-404` | यह FailproofAI Cloud अभी Jev serve नहीं करता। | +| `timeout` | `timeoutMs` के भीतर कोई answer नहीं (default 3000)। | +| `model-mismatch` | 1.13 से अलग एक Jev version ने answer किया। | + +## कुंजी कहाँ रहती है, और कहाँ जाती है + +- कुंजी एक बार stored होती है, `~/.failproofai/credentials.json` में (`0600`, एक owner-only directory में), अन्य FailproofAI Cloud credentials के बगल में। `jev.json` इस route के लिए कोई कुंजी नहीं रखता; वहाँ written एक config को invalid बनाता है। +- यदि `credentials.json` **कोई भी** permission carry करता है किसी के लिए लेकिन आप (group या other, read या write), या इसकी directory को **कोई भी लिख सकता है लेकिन आप**, यह **refused** है, read नहीं, और Jev तब तक off है जब तक आप इसे fix नहीं करते: फ़ाइल पर `chmod 600`, directory पर `chmod 700` (या reconnect, जो फ़ाइल को `0600` पर rewrites और directory को owner-only बनाता है)। एक directory जिसे others केवल पढ़ सकते हैं ठीक है; एक जिसे लिखा जा सकता है उन्हें फ़ाइल swap करने देता है। +- कुंजी केवल जब तक connection जिससे यह आया वह मशीन पर चालू है तब तक counts करती है: एक policy या reporting credential समान FailproofAI Cloud के लिए **समान कुंजी के साथ**, समान फ़ाइल में। एक Jev कुंजी एक के बिना छोड़ी गई ignored होती है, और Jev off रहता है। यह तब होता है जब पुराना failproofai का `config --disconnect` Jev कुंजी को place में छोड़ता है (यह को remove करने के लिए नहीं जानता), या जब पुराना failproofai का `config --token` दूसरी कुंजी से जुड़ता है, जो FailproofAI Cloud पर दूसरे organization से belong कर सकती है। Jev को वापस चालू करने के लिए, एक **machine** कुंजी के साथ फिर से connect करें। +- कुंजी कभी भी केवल Cloud origin को भेजी जाती है जिसके विरुद्ध यह verified था। एक `jev.json` कहीं और pointing को refused किया जाता है। +- **मशीन पर एक agent इसे read कर सकता है।** `credentials.json` owner-only है, और agent उस owner के रूप में चलता है। failproofai की अपनी files को read करना उद्देश्य से allowed है (केवल उन्हें change करना blocked है, `block-failproofai-commands` द्वारा), इसलिए एक agent और इस फ़ाइल के बीच एकमात्र चीज़ `block-read-outside-cwd` है — एक *reviewable* policy — और आपके home directory में शुरू किए गए session से, कुछ भी नहीं। एक कुंजी `jev:evaluate` के साथ आपके organization के Jev allowance को spend करती है (daily cap तक) जहाँ भी इसे use किया जाता है, इसलिए एक मशीन कुंजी को किसी अन्य spending credential की तरह treat करें: यदि एक agent ने इसे read किया हो सकता है, इसे Keys page पर disable करें और एक नई के साथ reconnect करें। +- केवल आपकी global files यह decide करती हैं। एक repository Cloud Jev को चालू नहीं कर सकता, इसे कहीं और point करने या अपनी कुंजी supply कर सकता, और `FAILPROOFAI_JEV_API_KEY` इस route के लिए ignored है। +- हर call के लिए Jev evaluate करता है, एक request FailproofAI Cloud को जाता है, carrying [bring-your-own-key page](/hi/policies/jev-byok#what-leaves-the-machine) जो lists करता है (secrets redacted)। FailproofAI Cloud इसे TypeSafe को forward करता है और इसे log या keep नहीं करता। + +## इसे बंद करें + +| Command | Outcome | +| --- | --- | +| `failproofai jev setup --mode off` | Config रखें; Jev को ask नहीं किया जाता। **यह वह switch है जो रहता है:** फिर से connecting एक मौजूदा `jev.json` को कभी rewrite नहीं करता, इसलिए Jev तब तक off रहता है जब तक आप इसे `--mode shadow` के साथ वापस switch नहीं करते। | +| `failproofai jev remove` | `~/.failproofai/jev.json` को delete करें; Jev off है — जब तक अगली `failproofai config --token` `jev:evaluate` carry करने वाली कुंजी के साथ नहीं, जो कोई `jev.json` नहीं find करती और shadow mode में Jev को चालू करती है (जब तक यह `--no-transcripts` के साथ नहीं चलता)। इसे off रखने के लिए, `--mode off` का उपयोग करें। | +| `failproofai config --disconnect` | मशीन को disconnect करें: कुंजी को remove किया जाता है, और `jev.json` भी जब यह FailproofAI Cloud को name करता है और switched off नहीं है। अपने endpoint के लिए एक `jev.json` रहता है, और एक switched off भी, इसलिए Jev off रहता है जब आप फिर से connect करते हैं। | + +अगली tool call से, hooks बिल्कुल पहले की तरह regex policies चलाते हैं। \ No newline at end of file diff --git a/docs/hi/policies/jev.mdx b/docs/hi/policies/jev.mdx new file mode 100644 index 000000000..4f624e9a6 --- /dev/null +++ b/docs/hi/policies/jev.mdx @@ -0,0 +1,45 @@ +--- +title: "Jev policies" +description: "Jev के live review को gated tool calls में जोड़ें, फिर उसके निर्णयों को लागू करने से पहले निरीक्षण करें।" +icon: "shield-check" +--- + +Jev एक tool call को उस चीज़ के विरुद्ध पढ़ता है जो व्यक्ति ने agent को करने के लिए कहा था। इसका उपयोग तब करें जब string-matching policy वैध काम को ब्लॉक करे या कोई जोखिम भरी क्रिया को miss करे जिसे context की आवश्यकता है। यह `PreToolUse` या `PermissionRequest` gate पर आपकी policies के साथ जवाब देता है। session समाप्त होने के **बाद** score के लिए, [Jev evaluations](/hi/evaluations/jev) का उपयोग करें। + +## observe mode में शुरू करें + +Failproof AI को install करें और hooks को [supported harness](/hi/reference/harnesses) से जोड़ें। failproofai 1.0.8-beta.0 या बाद के संस्करण का उपयोग करें। + +Failproof AI किसी भी Jev checks के साथ नहीं आता। उन्हें pack के रूप में install करें, अन्यथा Jev के पास पूछने के लिए कुछ नहीं है और इसे कभी call नहीं किया जाता: + +```bash +failproofai policies add FailproofAI/jev-policies +``` + +फिर चुनें कि requests Jev तक कैसे पहुंचें: + +| Route | पहला कदम | +| --- | --- | +| FailproofAI Cloud | **machine** key के साथ connect करें जिसमें `jev:evaluate` हो। Jev config के बिना एक machine पर, `failproofai config` Jev को observe mode में चालू करता है। | +| आपका अपना provider | local dashboard में, **Settings → Jev** खोलें, provider चुनें, इसका token paste करें, और **observe** चुनें। या `failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key` चलाएं। | + +![local dashboard का Jev settings: provider, endpoint, token, और Jev को चालू करने से पहले observe mode।](/images/dashboard/jev-settings.png) + +```bash +failproofai jev status +failproofai jev test +``` + +`test` endpoint की जांच करता है। hook path को जांचने के लिए, hooked agent को `README.md` पर अपने file-reading tool का उपयोग करने के लिए कहें। पुष्टि करें कि tool call session में दिखाई देता है, फिर [local dashboard](/hi/reference/local-dashboard#review-policy-activity) में **Policies → Activity** का निरीक्षण करें। `status` में Jev count में वृद्धि होनी चाहिए। Observe mode records करता है कि Jev ने क्या निर्णय लिया होता जबकि आपका मौजूदा policy result अभी भी लागू रहता है। + +## enforce करने के समय का निर्णय करें + +एक **hard** policy का हमेशा अंतिम कहना होता है। Jev केवल एक policy से deny को clear कर सकता है जो स्पष्ट रूप से **reviewable** के रूप में चिह्नित हो और केवल जब वह उस policy की named concern की जांच करे। clearance पर निर्भर करने से पहले [policy authority](/hi/policies/authority) देखें। Jev अपने आप पर भी warn या deny कर सकता है। यदि वह उत्तर नहीं दे सकता, तो policy result उस call का निर्णय करता है। + +एक बार observe results सही दिख जाएं, **Settings → Jev** में enforce mode पर स्विच करें या चलाएं: + +```bash +failproofai jev setup --mode enforce +``` + +provider URLs, Cloud keys, configuration, fallbacks, और प्रत्येक request के साथ भेजे गए data के लिए, [Jev integration reference](/hi/reference/jev) देखें। \ No newline at end of file diff --git a/docs/hi/reference/custom-agents-typescript.mdx b/docs/hi/reference/custom-agents-typescript.mdx new file mode 100644 index 000000000..0775660b7 --- /dev/null +++ b/docs/hi/reference/custom-agents-typescript.mdx @@ -0,0 +1,401 @@ +--- +title: "Custom agents (TypeScript)" +description: "@failproofai/sdk के लिए कॉन्फ़िगरेशन, इवेंट कैटलॉग, स्कोप्स और फ्रेमवर्क एडेप्टर।" +icon: "square-js" +--- + +TypeScript SDK के लिए हर सेटिंग, मेथड और फील्ड क्या करता है। अगर आप पहली बार इंस्ट्रूमेंटिंग कर रहे हैं, तो गाइड से शुरू करें — यह पेज संदर्भ के लिए है। + + + + इंस्टॉल करें, इंस्ट्रूमेंट करें, इवेंट मेथड्स, एक काम किया हुआ उदाहरण, और सामान्य समस्याएं। + + + एक ही इवेंट्स, एक ही वायर फॉर्मेट, एक ही स्पूल — Python से। + + + +Node 20.9 या नया। ESM और CommonJS। कोई रनटाइम डिपेंडेंसीज नहीं। + + + यह SDK और Python वाला **एक ही स्पूल में एक ही इवेंट्स लिखते हैं**। Node agents और Python agents के साथ एक फ्लीट एक सेट सेशन्स बनाता है, दो नहीं, और डैशबोर्ड में कुछ भी उन्हें अलग नहीं करता। प्रति सर्विस चुनें, प्रति कंपनी नहीं। + + +## Install + +```bash +npm install @failproofai/sdk +``` + +```ts +import * as failproofai from "@failproofai/sdk"; + +await failproofai.agent("planner", { goal: question }, async () => { + const hits = await failproofai.toolCall("web_search", { input: { q } }, () => search(q)); +}); +``` + +फ्रेमवर्क एडेप्टर पैकेज में ही शिप होते हैं। फ्रेमवर्क्स **ऑप्शनल peer dependencies** हैं — घोषित किए गए ताकि समर्थित रेंज दृश्यमान हो, कभी आपकी ओर से इंस्टॉल न किए जाएं, और केवल तब इंपोर्ट किए जाएं जब आप `instrument()` कॉल करें। + +## Failproof daemon को कनेक्ट करें + +Python SDK के समान: **Admin → Keys** के तहत एक `events:add` की बनाएं, फिर [daemon को कनेक्ट करें](/hi/start/setup#connect-a-machine-to-cloud) agent मशीन पर। SDK डिस्क पर लिखता है; daemon शिप करता है। + +## Configuration + +```ts +failproofai.configure({ + environment: "production", + flushInterval: 0.5, + baseDir: undefined, +}); +``` + +| Option | यह क्या करता है | +| --- | --- | +| `environment` | हर इवेंट पर लेबल — `production`, `staging`, `prod-eu`। डिफॉल्ट `dev`। | +| `flushInterval` | टाइमर कितनी बार डिस्क पर लिखता है, सेकंड में। डिफॉल्ट `0.5`। | +| `baseDir` | कहाँ लिखना है। डिफॉल्ट daemon का स्पूल, जो है जो आप चाहते हैं जब तक आप अन्यथा न जानते। | + +इसका कोई भी हिस्सा लागू नहीं होता जब तक सब कुछ वैध न हो, इसलिए एक अस्वीकृत कॉल SDK को बिल्कुल वैसे ही छोड़ देता है न कि नई `baseDir` और पुरानी अंतराल के साथ। + +इसके बजाय एनवायरनमेंट वेरिएबल से सेट करें: + +| Variable | यह क्या करता है | +| --- | --- | +| `AGENTEYE_ENVIRONMENT` | कोड परिवर्तन के बिना `environment` सेट करता है। एक `configure()` विकल्प इसे जीतता है। | +| `FAILPROOFAI_HOME` | Failproof AI रूट को स्थानांतरित करता है जो स्पूल रखता है। | +| `FAILPROOFAI_SDK_LOG_LEVEL` | `debug`, `info`, `warn` (डिफॉल्ट), `error`, `silent`। | +| `FAILPROOFAI_SDK_STRICT` | `1` इंस्ट्रूमेंटेशन त्रुटियों को फेंकता है बजाय लॉग किए जाने के। | +| `FAILPROOFAI_SDK_STRICT_INTEGRATIONS` | `1` एक फ्रेमवर्क-संगतता समस्या को फेंकता है बजाय चेतावनी और जारी रखने के। | + + + **`environment` में कोई कॉमा नहीं।** Ingest उस फील्ड को कॉमा पर विभाजित करके अपने फ़िल्टर बनाता है, और किसी भी इवेंट को छोड़ देता है जिसके लेबल में एक है — तो एक पूरा रन चुपचाप गायब हो जाता है। `prod-eu` लिखें, `prod,eu` नहीं। + + `configure({ environment: "prod,eu" })` फेंकता है तो आप तुरंत पता चल जाए। `AGENTEYE_ENVIRONMENT` नहीं फेंक सकता — कोई आपको कॉल नहीं कर रहा — तो यह एक बार चेतावनी देता है और `dev` पर वापस चला जाता है। + + +SDK की अपनी लॉग लाइनों को अपने लॉगर में रूट करें `failproofai.setLogger({ debug, info, warn, error })` के साथ। + +## Shutdown + +बफर किए गए इवेंट्स `process.on("exit")` पर फ्लश होते हैं। + +एक प्रक्रिया जो एक सिग्नल द्वारा मारी जाती है वह कभी वहाँ नहीं पहुँचती, और Node की `SIGTERM` के लिए डिफॉल्ट exit handlers को चलाए बिना समाप्त करना है — तो एक कंटेनराइज्ड agent जो कुछ भी खो देता है जो अंतिम अंतराल ने लिखा नहीं था। + + + **यह SDK आपके लिए एक सिग्नल हैंडलर इंस्टॉल नहीं करेगा।** एक को रजिस्टर करना आपकी प्रक्रिया के व्यवहार को बदलता है: एक लिसनर Node की डिफॉल्ट समाप्ति को दबाता है, तो एक लाइब्रेरी जो एक को जोड़ती है वह चुपचाप Ctrl-C को काम करने से रोक देगी। अपना खुद का जोड़ें: + + ```ts + for (const signal of ["SIGINT", "SIGTERM"] as const) { + process.once(signal, () => { + failproofai.flushSync(); + process.exit(0); + }); + } + ``` + + +एक अल्पकालिक स्क्रिप्ट या एक serverless हैंडलर को रिटर्न करने से पहले `await failproofai.flush()` करना चाहिए — अकेला अंतराल डिलीवरी की गारंटी नहीं देता। + +## Identity + +हर इवेंट एक सेशन और एक agent से संबंधित है। **स्कोप्स दोनों को भरते हैं**, तो आप शायद ही कभी उन्हें पास करते हैं: + +```ts +await failproofai.session(async () => { + await failproofai.agent("planner", async () => { + failproofai.event.toolUse({ toolName: "search", toolCallId: "c1" }); + }); +}); +``` + +`sessionId` या `agentId` को स्पष्ट रूप से पास करना अभी भी काम करता है और जीतता है। न तो बाध्य और न ही पारित, कॉल एक इवेंट उत्सर्जित करने के बजाय फेंकता है जिसे Cloud चुपचाप त्याग देता। + + + Identity `AsyncLocalStorage` पर सवारी करता है। यह `await`, `.then()`, टाइमर्स और स्कोप के अंदर बनाए गए किसी भी कॉलबैक का अनुसरण करता है। यह **नहीं** एक कॉलबैक का अनुसरण करता है जो एक रन के दौरान संग्रहीत और दूसरे के दौरान आह्वान किया गया है, या `worker_threads` सीमा पार काम को संभालता है — उन्हें `failproofai.propagate()` में लपेटें या उनके इवेंट्स अनुलग्नित रहते हैं। + + +### Scopes + +| Scope | Emits | Returns | +| --- | --- | --- | +| `session(body)` | कुछ नहीं — केवल identity | जो कुछ `body` रिटर्न करता है | +| `agent(id, options?, body)` | `agent_start`, फिर `agent_end` | जो कुछ `body` रिटर्न करता है | +| `toolCall(name, options?, body)` | `tool_use`, फिर `tool_result` | जो कुछ `body` रिटर्न करता है | + +एक समकालिक body समकालिक रहता है: `agent("x", () => 1)` `1` रिटर्न करता है, एक promise नहीं। + +`toolCall` body के resolved मान को tool के `output` के रूप में रिकॉर्ड करता है, जब तक आप `call.output` को स्वयं असाइन न करें। + + + +| क्या हुआ | Events | `outcome` | +| --- | --- | --- | +| ब्लॉक रिटर्न किया | `agent_end` | `"success"`, या आपका `outcome` | +| ब्लॉक ने फेंका | `error`, फिर `agent_end` | `"failed"` | +| एक `AbortError` | केवल `agent_end` | `"cancelled"` | + +त्रुटि हमेशा पुन: फेंकी जाती है। + +एक tool failure leaf पर रिकॉर्ड किया जाता है — `tool_result` एक `error` स्ट्रिंग के साथ — और कोई run-level `error` इवेंट **नहीं** उत्सर्जित करता है। एक जो agent loop पकड़ता है वह run failure नहीं है, और एक जो फैलता है वह बिल्कुल एक बार, enclosing `agent()` द्वारा रिपोर्ट किया जाता है। + + + + + +जब काम एक एकल फंक्शन नहीं है — एक स्कोप एक constructor में खोला जाता है और teardown में बंद किया जाता है, या एक जो मौजूदा नियंत्रण प्रवाह को स्ट्रैडल करता है: + +```ts +{ + using span = failproofai.agent.open("planner", { goal }); + using call = failproofai.toolCall.open("search", { input: { q } }); + call.call.output = await search(q); +} // tool_result, फिर agent_end +``` + +दोनों फॉर्म byte-identical इवेंट्स उत्सर्जित करते हैं। कॉलबैक फॉर्म को प्राथमिकता दें: यह `AsyncLocalStorage.run()` के अंदर चलता है, तो unwinding के लिए कुछ नहीं है और "opened here, closed over there" बग का पूरा वर्ग unreachable है। + +एक `using` ब्लॉक जो अपनी खुद की विफलता को पकड़ता है वह इसे `span.fail(error)` के साथ रिपोर्ट करता है — disposer के पास अपना स्वयं का कोई exception चैनल नहीं है। + + + +## Event catalog + +Python SDK के समान पंद्रह मेथड्स, camelCase में। अधिकांश **जोड़े** में आते हैं — आप opener को कॉल करते हैं, फिर closer को, और SDK अंतराल को समय देता है। + +| | Opens | Closes | +| --- | --- | --- | +| **Agents** | `agentStart` | `agentEnd` | +| | `agentPause` | `agentResume` | +| **Models** | `modelRequest` | `modelResponse` | +| **Tools** | `toolUse` | `toolResult` | +| **Hooks** | `hookTriggered` | `hookCompleted` | +| **Humans** | `humanWait` | `humanInput` | + +तीन अकेले खड़े हैं: `error`, `humanPause`, `humanInterrupt`। + + + +हर मेथड `sessionId` और `agentId` भी लेता है, जिन्हें स्कोप्स आपके लिए भरते हैं। कुछ भी छोड़ा जाता है बजाय JSON `null` के रूप में भेजा जाता है। + +| Method | Required | Optional | +| --- | --- | --- | +| `agentStart` | — | `goal`, `parentId` | +| `agentEnd` | — | `outcome`, `summary` | +| `agentPause` | `pauseId` | `reason`, `userId` | +| `agentResume` | `pauseId` | `reason`, `userId` | +| `modelRequest` | — | `model`, `messages`, `system`, `tools`, `requestId` | +| `modelResponse` | — | `model`, `stopReason`, `inputTokens`, `outputTokens`, `content`, `role`, `requestId` | +| `toolUse` | `toolName`, `toolCallId` | `input` | +| `toolResult` | `toolName`, `toolCallId` | `output`, `error` | +| `hookTriggered` | `hookName`, `hookId` | `triggerEvent`, `input` | +| `hookCompleted` | `hookName`, `hookId` | `outcome`, `output`, `error` | +| `error` | `errorType`, `message` | `traceback` | +| `humanWait` | `inputId` | `prompt`, `options`, `reason` | +| `humanInput` | `inputId` | `response` | +| `humanPause` | — | `reason`, `userId` | +| `humanInterrupt` | — | `reason`, `userId`, `atStep` | + +कोई भी अन्य key जो आप जोड़ते हैं एक custom payload field बन जाता है। कुछ भी framework-specific को `fw_*` namespace करें; एक name जो एक घोषित field से collide करता है उसे अस्वीकार किया जाता है बजाय एक promoted column को चुपचाप overwrite करने के। + + + + + **`duration_ms` computed है, accepted नहीं।** चार closing methods opener से अंतराल को समय देते हैं और एक caller-supplied `duration_ms` को अस्वीकार करते हैं — एक reported duration unfalsifiable है। + + Pairs को **session** पर matched किया जाता है और id पर, agent पर कभी नहीं। `planner` के तहत खोला गया एक tool और `worker` के तहत बंद किया गया अभी भी pairs, जो है जो nested multi-agent runs वास्तव में करते हैं। + + +## Framework adapters + +```ts +await failproofai.instrument(); // जो कुछ वह पा सके +await failproofai.instrument("langchain"); // बिल्कुल एक +failproofai.uninstrument(); // सब कुछ वापस रखो +``` + +| Framework | Supported | How it attaches | +| --- | --- | --- | +| **LangChain.js / LangGraph.js** | `@langchain/core` 0.3 – 1.x, LangGraph.js 0.4 – 1.x | `CallbackManager.configure`, तो हर `invoke`/`stream`/`batch` कहीं भी `callbacks:` पास किए बिना कवर किया जाता है — या `langchainHandler()` को स्वयं पास करें और कुछ भी patch न करें। | +| **Vercel AI SDK** | `ai` 4 – 7 | `telemetry()` कॉल साइट पर, या `instrument("ai")` `ai` 7 पर पूरी प्रक्रिया के लिए (4–6 पर वह opt-in है — नीचे देखें)। | +| **Mastra** | `@mastra/core` 0.20 – 1.x | `Agent.generate`/`.stream`, agent का model और tool resolution, और workflow run/step engine। | +| **LlamaIndex.TS** | `llamaindex` 0.11.4 – 0.x | `Settings.callbackManager` (subscribed) plus `AgentWorkflow.runStream`, workflow runs और उनके steps के लिए। | + +हर range को real framework releases के विरुद्ध, दोनों सिरों पर, एक ES module के रूप में और CommonJS के रूप में, हर CI run पर परीक्षण किया जाता है। + +मैपिंग Python SDK का है, तो एक ही प्रोग्राम दोनों भाषाओं में एक ही tree draw करता है। एक construct एक **agent** है केवल अगर यह एक LLM decision loop को स्वामित्व में रखता है — एक graph या chain run, एक AI SDK `generateText`/`streamText` कॉल, एक Mastra agent, एक LlamaIndex agent run। एक LangGraph node या एक workflow step एक **hook** है (`hook_triggered`/`hook_completed`), कभी नहीं एक nested agent। Model calls `model_request`/`model_response` pairs हैं token counts के साथ; tool calls model की अपनी tool call id carry करते हैं। एक failure एक बार, event में जहाँ यह happened, रिकॉर्ड किया जाता है। + +एक adapter जो install करने में विफल रहता है logged और skipped है; बाकी अभी भी install करते हैं, क्योंकि एक broken LlamaIndex को नहीं चाहिए LangGraph को cost करना। + + + कोई argument के साथ `instrument()` एक framework detect करता है क्या यह **resolves** है, क्या यह पहले से imported है — Node ES modules के लिए Python के `sys.modules` के equivalent को expose नहीं करता। एक framework जो आपके पास installed है लेकिन use नहीं करते, import और patch किए जाएंगे। जो एक आप चाहते हैं name करें अगर वह matter करे। + + + + अधिकांश ये frameworks एक ES-module build और एक CommonJS build ship करते हैं, जो Node दो unrelated copies के रूप में लोड करता है। Adapters उस copy को patch करते हैं जिसे आपकी application लोड करती है (और CommonJS copy को भी अगर कुछ पहले से `require` किया है), तो दोनों module systems काम करते हैं। एक framework **bundled in आपने अपने खुद के output में** esbuild या webpack द्वारा unreachable है — वहाँ call-site helpers use करें: `langchainHandler()`, `telemetry()`, `wrapTool()`। + + +### LangChain without patching + +```ts +import { langchainHandler } from "@failproofai/sdk/langchain"; +await graph.invoke(input, { callbacks: [langchainHandler()] }); +``` + +handler `instrument()` के साथ या बिना काम करता है और कभी double-record नहीं करता। `instrument("langchain")` `sessionId`, `captureContent`, `includeChains`, `graphCallbacks` और `captureLimit` लेता है, जैसे Python adapter करता है; `metadata: { failproofai_sdk_session_id }` एक कॉल पर उस invocation के लिए session pick करता है। + +### Vercel AI SDK + +AI SDK एक ES module से plain functions export करता है, और एक ES module namespace specification द्वारा immutable है — patch करने के लिए कहीं नहीं है। यह extension points का use करता है जो SDK खुद documents करता है: + +```ts +import { telemetry } from "@failproofai/sdk/ai"; + +const { text } = await generateText({ + model, + prompt, + experimental_telemetry: telemetry({ functionId: "answer-question" }), + // ai 7 पर, `telemetry: telemetry({ … })` — एक ही object, new name +}); +``` + +यह पूरा integration है: एक agent span, एक model request/response pair per step token counts के साथ, और हर tool call। एक call site हर major पर काम करता है — `ai` 4–6 tracer को read करते हैं जो यह carries, `ai` 7 telemetry integration को। + +`instrument("ai")` पूरी प्रक्रिया के लिए **`ai` 7 पर** करता है: हर call, AI SDK के global telemetry-integration list के माध्यम से, जो additive है और किसी के from लेता नहीं है। + +**`ai` 4–6 पर, `instrument("ai")` अपने आप से कुछ नहीं record करता, और एक warning log करता है यह कहते हुए।** केवल एक process-wide hook जो उन majors के पास है global OpenTelemetry tracer provider है — एक एकल slot जिसे OpenTelemetry एक बार taken को hand over करने से refuse करता है। अपना register करना चुपचाप आपके खुद के `NodeSDK.start()` को later startup में refuse करेगा और आपके http/database spans को एक tracer भेजेगा जो कुछ export नहीं करता। `telemetry()` call site पर या `wrapModel` वहाँ use करें। अगर प्रक्रिया अपना खुद का कोई OpenTelemetry नहीं चलाती, `instrument("ai", { registerGlobalTracer: true })` के साथ opt in करें: यह फिर हर call record करता है जो `experimental_telemetry: { isEnabled: true }` pass करता है, और केवल slot लेता है अगर यह अभी भी empty है। `registerGlobalTracer: false` default को रखता है और warning को silence करता है। + +अगर आप rather model को एक बार wrap करना चाहते हैं, `wrapModel` केवल model calls देखता है, क्योंकि tool calls model layer के above होते हैं। एक wrapped model कुछ के साथ नहीं कॉल किया गया एक अपनी खुद के run के रूप में record किया जाता है। एक streamed call जैसे stream stop करता है close होता है — `stop_reason: "cancelled"` जब consumer उसे cancel करता है, `"error"` error के साथ जब यह mid-way fail होता है: + +```ts +import { wrapModel } from "@failproofai/sdk/ai"; +const model = await wrapModel(openai("gpt-4o")); +``` + +दोनों use करना ठीक है: middleware ध्यान देता है कि call पहले से record जा रहा है और defer करता है, तो हर call एक बार record होता है। + +`functionId` agent span को name देता है। इसे low-cardinality रखें — यह `agent_id` में lands, primary dashboard facet। + +### Next.js + +`next build` आपके server के dependencies को default by bundle करता है, और एक framework bundled को build में एक copy है जिसे `instrument()` reach नहीं कर सकता। config को एक बार wrap करें और `instrument()` को Next के startup hook से कॉल करें: + +```ts +// next.config.ts +import { withFailproofai } from "@failproofai/sdk/next"; +export default withFailproofai({ /* your config */ }); +``` + +```ts +// instrumentation.ts +export async function register() { + if (process.env.NEXT_RUNTIME !== "nodejs") return; + const failproofai = await import("@failproofai/sdk"); + await failproofai.instrument(); +} +``` + +`withFailproofai` LangChain, Mastra, LlamaIndex और SDK को खुद को `serverExternalPackages` में जोड़ता है, आपकी अपनी list रखता है। बिना इसके, `instrument()` एक बार per framework चेतावनी देता है जिसे यह reach नहीं कर सकता बजाय silently fail करने के; अगर आप packages को खुद list करते हैं, `FAILPROOFAI_NEXT_EXTERNALS=1` सेट करें। Vercel AI SDK और call-site helpers दोनों तरीके से काम करते हैं। एक Edge route एक no-op build को get करता है: SDK import करना safe है और कुछ नहीं record करता। + +### Token counts on streamed calls + +OpenAI-compatible APIs केवल stream पर usage report करते हैं जब client पूछता है। LangChain और Vercel AI SDK पूछते हैं; LlamaIndex के लिए `additionalChatOptions: { stream_options: { include_usage: true } }` अपने `OpenAI` LLM को pass करें, और Mastra के लिए model को usage enabled के साथ build करें (उदाहरण के लिए `createOpenAICompatible({ includeUsage: true })`)। अन्यथा streamed model calls कोई token counts नहीं carry करते हैं। + +### Runtimes + +Node ≥ 20.9, Bun और Deno — हर framework, एक ES module के रूप में और CommonJS के रूप में, हर एक पर Node के trace के विरुद्ध tested है। SDK `failproofaid` daemon के बगल में चलता है, जो यह लिखता है ship करता है। + +## Your own agent — no framework + +एक agent loop के लिए जो आपने खुद लिखा है, या एक framework बिना एक adapter के। आप उन्हीं API के साथ events emit करते हैं जो adapters नीचे use करते हैं, तो trace एक ही shape और quality है। + +आपको यह जानने की जरूरत नहीं है कि agent कैसे organized है। हर hand-built agent के पास पहले से तीन जगहें हैं, चाहे इसके functions क्या कहे जाएं, और वह तीन पूरा integration है: + +| Where | What to add | Emits | +| --- | --- | --- | +| जहाँ **एक run** शुरू और खत्म होता है | `failproofai.agent("name", { goal }, async () => …)` | `agent_start` / `agent_end` | +| **जो function model को कॉल करता है** | `event.modelRequest` पहले, `event.modelResponse` बाद में — दोनों halves, failure पर भी | model turn per एक pair | +| **जो function tools run करता है** | `failproofai.toolCall(name, { toolCallId, input }, () => run())` | `tool_use` / `tool_result` | + +```ts +async function callModel(messages) { + const requestId = randomUUID(); + const started = Date.now(); + failproofai.event.modelRequest({ model: MODEL, requestId, messages }); + try { + const reply = await client.chat.completions.create({ model: MODEL, messages, tools }); + failproofai.event.modelResponse({ + model: reply.model, requestId, stopReason: reply.choices[0].finish_reason, + inputTokens: reply.usage?.prompt_tokens, outputTokens: reply.usage?.completion_tokens, + duration_ms: Date.now() - started, + }); + return reply.choices[0].message; + } catch (error) { + failproofai.event.modelResponse({ model: MODEL, requestId, stopReason: "error", + error: String(error), duration_ms: Date.now() - started }); + throw error; + } +} + +async function dispatch(call) { + const input = JSON.parse(call.function.arguments); + return failproofai.toolCall(call.function.name, { toolCallId: call.id, input }, + () => runTool(call.function.name, input)); +} + +await failproofai.agent("inventory", { goal: question }, async () => { + for (;;) { + const message = await callModel(messages); + if (!message.tool_calls?.length) return message.content; + for (const call of message.tool_calls) await dispatch(call); + } +}); +``` + +Identity ambient है: `agent()` के अंदर सब कुछ उस run के session पर lands बिना एक id लिए, और program में कुछ भी अन्य नहीं बदलता — including जो कुछ agent पहले से अपने खुद के database में लिखता है। + +- **एक service या worker:** अपना खुद का request या job id `sessionId` के रूप में pass करें, तो dashboard पर एक session और आपने अपने logs या database में record एक ही string हैं। +- **Sub-agents:** `agent()` calls को nest करें। inner एक outer के साथ session में जाता है इसके `parent_id` के रूप में। +- **Pairs को emit करें।** एक `modelRequest` कोई `modelResponse` के साथ एक span है जिसे dashboard forever running के रूप में shows करता है — इसलिए `catch`। + +[`sdk/typescript/examples/research-agent.ts`](https://github.com/FailproofAI/failproofai/blob/main/sdk/typescript/examples/research-agent.ts) repository में पूरा, runnable संस्करण है: एक real OpenAI tool loop instrumented बिल्कुल इस तरह, CI में हर परिवर्तन पर run एक ES module के रूप में और CommonJS के रूप में। + +## Evaluations + +```ts +import { Evaluator, EvalResult, Score } from "@failproofai/sdk/evaluator"; + +export const app = new Evaluator({ name: "my-evals", version: "1" }); + +app.eval("tool_success_rate", { version: "1" }, (session) => { + const results = session.eventsOfType("tool_result"); + const failures = results.filter((event) => event.payload.error != null).length; + return new EvalResult({ + score: new Score(results.length === 0 ? 1 : 1 - failures / results.length), + reasoning: `${failures} of ${results.length} tool calls failed`, + }); +}); +``` + +```bash +FAILPROOFAI_EVALUATOR_URL=… FAILPROOFAI_EVALUATOR_TOKEN=… \ + npx failproofai-evaluator ./my-evals.js +``` + +[Evaluator SDK reference](/hi/reference/evaluator-sdk) देखें protocol, worker settings और result types के लिए। + + + **एक evaluation yield करना चाहिए।** एक synchronous function जो कभी return नहीं करता Node के एकल thread को block करता है, और कोई timeout भी fire नहीं कर सकता जब तक यह करता है। `async` evaluations लिखें। + + +## What it will not do to your process + +| | | +| --- | --- | +| **आपके agent loop को block करें** | Events एक in-memory queue में जाते हैं; एक timer उन्हें लिखता है। Timer `unref`'d है, तो इस package को import करना कभी एक script को exiting से रोकता नहीं है। | +| **Grow without bound** | Queue count *और* measured bytes द्वारा capped है। या से past, oldest events discarded हैं और एक warning कहता है — telemetry outage एक OOM kill नहीं बन सकता। | +| **Process को down ले जाएं** | एक unencodable event अकेले dropped है, न कि batch around इसे। एक throwing getter, एक circular reference, एक `BigInt`, एक lone surrogate: हर एक handled है बजाय propagated के। | +| **एक half-written batch छोड़ें** | Content `fsync`ed है एक atomic rename से पहले, directory `fsync`ed है बाद में, और एक failed write अपनी temporary file को clean करता है। | +| **Transcripts को readable छोड़ें** | Batches `0600` एक `0700` directory में हैं। यह goals, prompts, tool arguments और tool output carry करते हैं। | +| **Credentials को ship करें** | API keys, tokens, JWTs, bearer headers और secret-shaped assignments redacted हैं bytes से पहले disk तक पहुंचते हैं। Daemon redacts फिर से upload से पहले। | \ No newline at end of file diff --git a/docs/hi/reference/jev-cloud.mdx b/docs/hi/reference/jev-cloud.mdx new file mode 100644 index 000000000..d1a648729 --- /dev/null +++ b/docs/hi/reference/jev-cloud.mdx @@ -0,0 +1,136 @@ +--- +title: "FailproofAI Cloud के माध्यम से Jev" +description: "क्लाउड मशीन कुंजियाँ, कनेक्शन स्थिति, सीमाएँ, और लाइव Jev नीति समीक्षा के लिए विफलता व्यवहार।" +icon: "cloud" +--- + +यह [Jev नीतियों](/hi/policies/jev) के लिए क्लाउड रूट संदर्भ है। Jev, TypeSafe का वर्गीकरण, प्रत्येक टूल कॉल को उस विरुद्ध पढ़ता है जो आपने वास्तव में माँगा था और आपकी नीतियों के साथ जवाब देता है, कभी उनके बजाय नहीं। **FailproofAI Cloud** के माध्यम से, एक जुड़ी मशीन Jev का उपयोग करती है जिसी कुंजी के साथ जिससे वह पहले से जुड़ी है: कोई TypeSafe खाता नहीं, कोई दूसरी कुंजी नहीं, कॉन्फ़िगर करने के लिए कोई एंडपॉइंट नहीं। प्रत्येक कॉल आपके संगठन की मौजूदा योजना भत्ते में चार्ज किया जाता है। + +Jev जो कुछ करता है वह [अपनी-कुंजी-ले-आओ सेटअप](/hi/reference/jev-providers) से अपरिवर्तित है: कठोर नीतियाँ अंतिम रहती हैं, समीक्षा योग्य नीति की अस्वीकृति केवल तभी साफ़ की जाती है जब Jev से उस विशेष चिंता के बारे में पूछा गया था, और कोई भी विफलता उस कॉल के लिए regex परिणाम पर वापस आती है। + + +**failproofai 1.0.8-beta.0** या बाद के संस्करण की आवश्यकता है। 1.0.7 में कोई Jev नहीं है, भले ही वह 1.0.7 बेटा के ऊपर क्रमबद्ध हो। बिना Jev कॉन्फ़िग के कुछ नहीं बदलता: हुक्स regex नीतियों को ठीक उसी तरह चलाते हैं जैसे हमेशा किया करते हैं। + + +## शुरुआत से पहले + +Failproof AI को उस मशीन पर इंस्टॉल करें जहाँ आपका एजेंट चलता है और इसके हुक्स को एक [समर्थित हार्नेस](/hi/reference/harnesses) से जोड़ें। यदि आप शुरुआत से शुरू कर रहे हैं, तो हुक इंस्टॉलेशन के माध्यम से [क्विकस्टार्ट](/hi/start/quickstart) का अनुसरण करें। इंस्टॉल किए गए CLI को `failproofai --version` के साथ चेक करें; यदि यह Jev से पहले का है तो इसे अपडेट करें। आपको अपने संगठन के **प्रशासन → कुंजियाँ** पृष्ठ तक पहुँच की भी आवश्यकता है मशीन कुंजी बनाने के लिए। + +Jev `PreToolUse` या `PermissionRequest` गेट पर नामित टूल कॉल की समीक्षा करता है। यह एक सत्र में हर घटना की समीक्षा नहीं करता। Jev को नीति की अस्वीकृति साफ़ करते हुए देखने के लिए, आपको एक स्थापित नीति की आवश्यकता है [समीक्षा योग्य](/hi/policies/authority); सभी अन्य नीति अस्वीकृति अंतिम रहती है। + +## इसे चालू करें + +1. **Jev के साथ एक कुंजी बनाएँ।** FailproofAI Cloud डैशबोर्ड में, **प्रशासन → कुंजियाँ → कुंजी बनाएँ** खोलें और **मशीन** प्रीसेट चुनें। यह तीन अनुमतियाँ देता है जो मशीन को चाहिए: `events:add` (गतिविधि भेजें), `policies:pull` (नीतियाँ प्राप्त करें) और `jev:evaluate` (Jev, आपके संगठन की योजना में चार्ज किया जाता है)। एक कुंजी बिना अन्य दोनों के `jev:evaluate` नहीं रख सकती। +2. **उस कुंजी के साथ मशीन को कनेक्ट करें।** एक प्रॉम्प्ट पर इसका एकबारी रहस्य पढ़ें, फिर पूरी सेटअप कमांड चलाएँ: + + ```bash + read -rs FAILPROOFAI_CLOUD_TOKEN && export FAILPROOFAI_CLOUD_TOKEN + failproofai config + ``` + + `failproofai config` डेमॉन को इंस्टॉल करता है, उस एजेंट CLI के लिए हुक्स जोड़ता है जिसे वह पाता है, और मशीन को कनेक्ट करता है। पर्यावरण चर कुंजी को कमांड की तर्कों और आपके शेल इतिहास से बाहर रखता है। यदि आपका हार्नेस बाद में इंस्टॉल किया गया था, [इसे स्पष्ट रूप से जोड़ें](/hi/start/quickstart)। + + यदि आपका संगठन होस्ट किए गए के बजाय अपना FailproofAI Cloud चलाता है, तो इसका पता जोड़ें: `--url https://<आपका डैशबोर्ड होस्ट>` (या `FAILPROOFAI_CLOUD_URL` निर्यात करें)। इसके बिना कुंजी होस्ट की गई सेवा के विरुद्ध जाँची जाती है और कनेक्शन विफल हो जाता है। यदि उस होस्ट का प्रमाणपत्र निजी CA से आता है, तो CA को मशीन के सिस्टम ट्रस्ट स्टोर में इंस्टॉल करें (उदाहरण के लिए `update-ca-certificates` के साथ), केवल `NODE_EXTRA_CA_CERTS` में नहीं: जो डेमॉन इवेंट भेजता है और नीतियाँ खींचता है वह सिस्टम स्टोर पढ़ता है। [समस्या निवारण](/hi/reference/troubleshooting) देखें। + +बस। कनेक्ट करना कुंजी को संग्रहीत करता है और, जब मशीन के **पास** अभी तक कोई Jev कॉन्फ़िग नहीं है, **observe** मोड में FailproofAI Cloud के माध्यम से Jev को चालू करता है: एक बार पैक जाँचें देने के बाद, Jev से हर गेटेड टूल कॉल के बारे में पूछा जाता है और इसके निर्णय रिकॉर्ड किए जाते हैं, लेकिन आपकी नीतियों का परिणाम लागू किया जाता है। आउटपुट इसे कहता है: + +```text + Jev on through FailproofAI Cloud, in observe mode: logged, not enforced (~/.failproofai/jev.json). +``` + +Jev अभी भी कुछ नहीं माँगता जब तक पैक इसे जाँचें न दे। Failproof AI कोई नहीं भेजता; जब तक कोई स्थापित पैक कोई नहीं घोषित करता, आउटपुट एक पंक्ति जोड़ता है ऐसा कहने के लिए, और `failproofai jev status` इसे दोहराता है। इन्हें इनके साथ इंस्टॉल करें: + +```bash +failproofai policies add FailproofAI/jev-policies +``` + +**`--no-transcripts` के साथ, कनेक्ट करना Jev को चालू नहीं करता है।** Jev प्रत्येक जाँची गई टूल कॉल और हाल के प्रॉम्प्ट को FailproofAI Cloud को भेजता है, जो निर्णयों-केवल कनेक्शन को भेजने के लिए कहा गया है उससे अधिक है। कुंजी अभी भी संग्रहीत है, और आउटपुट कहता है Jev उपलब्ध है और इसे चालू करने के लिए कैसे: + +```bash +failproofai jev setup --provider failproofai +``` + +यह Jev को **बंद** भी नहीं करता। यदि मशीन की `jev.json` पहले से ही FailproofAI Cloud के माध्यम से Jev चलाती है, तो इसे जैसे है वैसे छोड़ा जाता है, और आउटपुट कहता है Jev अभी भी प्रत्येक जाँची गई टूल कॉल और हाल के प्रॉम्प्ट भेजता है, और यह `failproofai jev setup --mode off` इसे बंद करता है। + + +कनेक्ट करना **कभी** मौजूदा `~/.failproofai/jev.json` को ओवरराइट नहीं करता है। यदि आप पहले से ही अपना Jev एंडपॉइंट उपयोग करते हैं, तो यह उपयोग किया जाता रहता है, और आउटपुट कहता है फ़ाइल को कॉन्फ़िगर के रूप में छोड़ा गया था — और, जब वह फ़ाइल Jev को बंद छोड़ता है (अस्वीकृत, या बंद किया जाता है), ऐसा कहता है और इसे कैसे ठीक करें। उस मशीन को FailproofAI Cloud पर स्विच करने के लिए, `failproofai jev setup --provider failproofai` चलाएँ। + + +## Observe, enforce या off + +Observe में शुरू करें, नीति पृष्ठ पर Jev क्या किया होता है यह देखें, फिर इसे कार्य करने दें: + +```bash +failproofai jev setup --mode enforce # Jev के निर्णय लागू होते हैं: यह समीक्षा योग्य अस्वीकृति को साफ़ कर सकता है और अपना जोड़ सकता है +failproofai jev setup --mode observe # Jev से पूछा जाता है और लॉग किया जाता है; आपकी नीतियों का परिणाम लागू किया जाता है +failproofai jev setup --mode off # कॉन्फ़िग रखें, Jev से पूछना बंद करें +``` + +एक ही स्विच स्थानीय डैशबोर्ड में है: **सेटिंग्स → Jev** में एक ऑन/ऑफ स्विच और observe/enforce है। यह मोड को फिर से लिखता है और कुछ नहीं। हुक्स हर टूल कॉल पर कॉन्फ़िग पढ़ते हैं, इसलिए एक परिवर्तन अगले से लागू होता है, बिना पुनरारंभ के। + +## यह क्या कर रहा है यह देखें + +```bash +failproofai jev status +failproofai jev test +``` + +`status` प्रदाता को **FailproofAI Cloud** के रूप में दिखाता है, क्लाउड होस्ट जिससे मशीन जुड़ी है, मोड, और कुंजी स्रोत को **FailproofAI Cloud कनेक्शन** के रूप में, कभी कुंजी नहीं। जब FailproofAI Cloud `jev.json` जगह पर है लेकिन Jev नहीं चल सकता, यह कहता है क्यों: + +| `status` कहता है | `status --json` | मतलब | +| --- | --- | --- | +| **off — इस मशीन के FailproofAI Cloud कनेक्शन के लिए कोई Jev कुंजी संग्रहीत नहीं है** | `key-lacks-jev` | मशीन जुड़ी है, लेकिन इसके लिए कोई Jev कुंजी संग्रहीत नहीं है: कुंजी में `jev:evaluate` नहीं है, या कनेक्ट इसकी पुष्टि नहीं कर सका। `FAILPROOFAI_CLOUD_TOKEN` में कुंजी के साथ `failproofai config` फिर से चलाएँ; यदि इसमें अनुमति नहीं है, तो **मशीन** कुंजी का उपयोग करें। | +| **off — यह मशीन FailproofAI Cloud से जुड़ी नहीं है** | `not-connected` | इस मशीन पर कोई FailproofAI Cloud कनेक्शन नहीं है जिससे Jev कुंजी संबंधित हो। | + +`failproofai config --disconnect` के बाद कोई FailproofAI Cloud `jev.json` नहीं है (जब तक इसे बंद न किया गया हो, जिसे रखा जाता है), इसलिए `status` सरल रूप से Jev को बंद के रूप में रिपोर्ट करता है। `status --json` समान तथ्य (`provider: "failproofai"`, `keySource: "cloud"`, `cloudConnected`, `keyCarriesJev`) रखता है, यहाँ तक कि जब कॉन्फ़िग अनुपस्थित या अस्वीकृत हो। `permissions` हमेशा `jev.json` का है; `credentials.json` के बारे में अस्वीकार करना `credentialsPermissions` जोड़ता है, और `fix` जब एक कमांड इसे ठीक करता है। `test` एक लाइव अनुरोध भेजता है और इसकी लेटेंसी और Jev संस्करण जो उत्तर दिया रिपोर्ट करता है। यह 1 से बाहर निकलता है, और अपने शीर्षक में ऐसा कहता है, जब उत्तर हुक टाइमआउट के बाद आता है (हुक्स `timeout` रिकॉर्ड करेंगे) या अपने जाँच प्रश्न का गलत उत्तर देता है। + +डैशबोर्ड का **सेटिंग्स → Jev** पैनल भी **FailproofAI Cloud कनेक्शन** दिखाता है: कौन सा संगठन मशीन रिपोर्ट करती है और क्या इसकी कुंजी Jev रखती है। यह मशीन की अपनी फ़ाइलों से पढ़ी जाती है, कोई नेटवर्क कॉल के साथ नहीं। + +## एक वास्तविक कॉल सत्यापित करें + +हुक किए गए एजेंट में एक नया सत्र शुरू करें। इसे `README.md` पर अपनी फ़ाइल-पढ़ने वाली टूल का उपयोग करने और शीर्षक रिपोर्ट करने के लिए कहें। पुष्टि करें कि सत्र में वह टूल कॉल है, फिर `failproofai jev status` फिर से चलाएँ: इसकी हाल की मूल्यांकन-कॉल गणना बढ़ नी चाहिए। [स्थानीय डैशबोर्ड](/hi/reference/local-dashboard#review-policy-activity) में **नीतियाँ → गतिविधि** खोलें उस कॉल के Jev निर्णय और मोड को निरीक्षण करने के लिए। क्लाउड में, संगठन का **नीतियाँ** पृष्ठ वितरित की गई गतिविधि के लिए Jev परिणाम दिखाता है। Observe मोड में, निर्णय **होता-होता** के रूप में रिकॉर्ड किया जाता है और नीति परिणाम अभी भी कॉल तय करता है। स्पष्टता केवल तब प्रदर्शित होती है जब समीक्षा योग्य नीति मेल खाती है और Jev इसकी नामित जाँचों को साफ़ करता है। + +## नीति पृष्ठ तक क्या पहुँचता है + +मशीन पहले से ही अपनी हुक गतिविधि FailproofAI Cloud (`events:add`) को भेजती है। Jev के साथ, प्रत्येक गेटेड कॉल का रिकॉर्ड भी कहता है कि कौन सा मूल्यांकनकर्ता चला, Jev ने क्या तय किया, कौन सी नीतियों को यह साफ़ किया, जब यह वापस आया तो क्यों, इसकी लेटेंसी और मॉडल जो उत्तर दिया — निर्णय, कोड और नाम, कभी कमांड या आपका प्रॉम्प्ट नहीं। आपके संगठन के **नीतियाँ** पृष्ठ पर: + +- एक कॉल जो Jev के अपने निर्णय ने तय किया (enforce मोड) को **Jev** को जिम्मेदार ठहराया जाता है, और जब निर्णय देने वाली जाँच किसी पैक से आई, रिकॉर्ड उस पैक और इसके संस्करण का भी नाम देता है; +- observe मोड में, Jev की अस्वीकृति या चेतावनी **होती-होती** के रूप में दिखाई देती है, उन रोलआउट्स के बगल में जिन्हें आप देख रहे हैं; +- नीतियाँ जो Jev ने साफ़ कीं, या observe मोड में साफ़ की होतीं, को प्रति नीति गिना जाता है। + +## जब Jev उत्तर नहीं दे सकता + +इनमें से हर एक उस कॉल के लिए आपकी नीतियों के परिणाम पर वापस आता है, और इसके कारण के साथ रिकॉर्ड किया जाता है: + +| कारण | कारण | +| --- | --- | +| `out-of-credits` | आपके संगठन ने अपना योजना भत्ता उपयोग कर लिया है। | +| `http-401`, `http-403` | कुंजी को रद्द कर दिया गया, या `jev:evaluate` नहीं है। एक कुंजी के साथ पुनः कनेक्ट करें जो करे। | +| `http-429` | FailproofAI Cloud आपके संगठन के लिए Jev को दर-सीमित कर रहा है। जब तक प्रतीक्षा जो यह माँगता है खत्म न हो जाए (इसका `Retry-After`, अधिकतम 60 सेकंड), मशीन इसे कुछ नहीं भेजती और हर कॉल तुरंत वापस आती है। इस तरह रोकी गई कॉलें `http-429` के रूप में रिकॉर्ड की जाती हैं, या `rate-limited` जब मशीन की अपनी दर सीमा उन्हें पहले रोक देती है। | +| `http-429` (दैनिक सीमा) | आपके संगठन ने अपनी दैनिक Jev कॉलें उपयोग कर ली हैं: **प्रति UTC दिन 10,000**, जब तक जो आपका FailproofAI Cloud संचालित करता है ने दूसरी सीमा निर्धारित नहीं की है। 00:00 UTC पर गणना रीसेट होने तक हर कॉल वापस आती है; मशीन अभी भी अधिकतम मिनट में एक बार फिर से पूछती है, इसलिए यह रीसेट को मिनट के भीतर लेती है। `failproofai jev test` कहता है "इस org के लिए दैनिक Jev सीमा पहुँची; 00:00 UTC पर रीसेट।" | +| `http-422` | Jev ने इस कॉल के अनुरोध को अस्वीकार कर दिया, आमतौर पर क्योंकि टूल कॉल में घना पाठ (base64, hex, minified कोड) Jev के टोकन बजट पर है। वह कॉल हर बार वापस आती है; यह कोई बाहरी घटना नहीं है। | +| `http-502` | Jev अभी उपलब्ध नहीं है। | +| `http-503` | यह क्लाउड आपके org के लिए Jev सेवा नहीं कर सकता: कोई मॉडल गेटवे नहीं, एक org अभी provisioned नहीं, या गेटवे बंद है। अपने admin से पूछें; हुक्स अधिकतम मिनट में एक बार फिर से पूछते हैं। | +| `http-404` | यह FailproofAI Cloud अभी तक Jev सेवा नहीं करता है। | +| `timeout` | `timeoutMs` के भीतर कोई उत्तर नहीं (डिफ़ॉल्ट 3000)। | +| `model-mismatch` | Jev संस्करण 1.13 के अलावा कोई अन्य ने उत्तर दिया। | + +## कुंजी कहाँ रहती है, और वह कहाँ जाती है + +- कुंजी एक बार संग्रहीत की जाती है, `~/.failproofai/credentials.json` में (`0600`, एक मालिक-केवल निर्देशिका में), अन्य FailproofAI Cloud क्रेडेंशियल्स के बगल में। `jev.json` इस रूट के लिए कोई कुंजी नहीं रखता; एक वहाँ लिखी गई कॉन्फ़िग को अमान्य करती है। +- यदि `credentials.json` **किसी को भी** अनुमति रखता है लेकिन आप (समूह या अन्य, पढ़ने या लिखने), या इसकी निर्देशिका को **लिखा जा सकता है** लेकिन आप द्वारा, यह **अस्वीकृत** है, पढ़ा नहीं, और Jev बंद है जब तक आप इसे ठीक न करें: फ़ाइल पर `chmod 600`, निर्देशिका पर `chmod 700` (या फिर से कनेक्ट करें, जो फ़ाइल को `0600` पर फिर से लिखता है और निर्देशिका को मालिक-केवल बनाता है)। एक निर्देशिका जो अन्य केवल पढ़ सकते हैं ठीक है; एक जिसे वह लिख सकते हैं फ़ाइल स्वैप करने देता है। +- कुंजी केवल उस कनेक्शन के दौरान गिनती है जिससे वह आया है मशीन पर: एक नीति या समान FailproofAI Cloud के लिए **समान कुंजी** के साथ रिपोर्टिंग क्रेडेंशियल, एक ही फ़ाइल में। एक Jev कुंजी वहाँ छोड़ी गई बिना एक के साथ अनदेखी की जाती है, और Jev बंद रहता है। यह तब होता है जब पुराना failproofai का `config --disconnect` Jev कुंजी को जगह पर छोड़ता है (यह नहीं जानता इसे निकालना है), या जब पुराना failproofai का `config --token` दूसरी कुंजी के साथ कनेक्ट करता है, जो FailproofAI Cloud पर दूसरे संगठन का हो सकता है। Jev को फिर से चालू करने के लिए, **मशीन** कुंजी के साथ फिर से कनेक्ट करें। +- कुंजी केवल कभी भी क्लाउड मूल को भेजी जाती है जिसके विरुद्ध इसकी पुष्टि की गई। कहीं और इशारा करने वाली `jev.json` अस्वीकृत है। +- **मशीन पर एक एजेंट इसे पढ़ सकता है।** `credentials.json` मालिक-केवल है, और एजेंट उस मालिक के रूप में चलता है। Failproofai की अपनी फ़ाइलों को पढ़ना उद्देश्यपूर्ण रूप से अनुमत है (केवल उन्हें बदलना `block-failproofai-commands` द्वारा अवरुद्ध है), इसलिए एजेंट और इस फ़ाइल के बीच एकमात्र बात `block-read-outside-cwd` है — एक *समीक्षा योग्य* नीति — और आपकी होम निर्देशिका से शुरू किए गए सत्र से, कुछ नहीं। एक कुंजी `jev:evaluate` के साथ आपके संगठन का Jev भत्ता (दैनिक कैप तक) कहीं से भी उपयोग किए जाने पर खर्च करती है, इसलिए मशीन कुंजी को किसी अन्य व्यय क्रेडेंशियल की तरह मानें: यदि एजेंट ने इसे पढ़ा हो सकता है, तो कुंजी पृष्ठ पर इसे अक्षम करें और एक नई के साथ पुनः कनेक्ट करें। +- केवल आपकी वैश्विक फ़ाइलें यह निर्णय लेती हैं। एक रेपॉजिटरी क्लाउड Jev को नहीं चालू कर सकता, इसे कहीं और इशारा कर सकता है या इसकी कुंजी आपूर्ति कर सकता है, और `FAILPROOFAI_JEV_API_KEY` इस रूट के लिए अनदेखी की जाती है। +- Jev प्रत्येक कॉल मूल्यांकन करता है, एक अनुरोध FailproofAI Cloud को जाता है, जो [अपनी-कुंजी-ले-आओ पृष्ठ](/hi/reference/jev-providers#what-leaves-the-machine) सूचीबद्ध है (रहस्य सुधारे हुए)। FailproofAI Cloud इसे TypeSafe को अग्रेषित करता है और लॉग नहीं करता या नहीं रखता। + +## इसे बंद करें + +| कमांड | परिणाम | +| --- | --- | +| `failproofai jev setup --mode off` | कॉन्फ़िग रखें; Jev से नहीं पूछा जाता। **यह स्विच है जो रहता है:** फिर से कनेक्ट करना कभी मौजूदा `jev.json` को नहीं फिर से लिखता है, इसलिए Jev बंद रहता है जब तक आप इसे `--mode observe` के साथ वापस स्विच नहीं करते। | +| `failproofai jev remove` | `~/.failproofai/jev.json` हटाएँ; Jev बंद है — जब तक अगला `failproofai config --token` `jev:evaluate` ले जाने वाली कुंजी के साथ नहीं, जो कोई `jev.json` नहीं पाता और observe मोड में Jev को चालू करता है (जब तक यह `--no-transcripts` के साथ नहीं चलता)। इसे बंद रखने के लिए, `--mode off` का उपयोग करें। | +| `failproofai config --disconnect` | मशीन को डिस्कनेक्ट करें: कुंजी हटाई जाती है, और `jev.json` भी जब यह FailproofAI Cloud का नाम देता है और बंद नहीं किया जाता है। अपने एंडपॉइंट के लिए `jev.json` रहता है, और एक बंद किया हुआ भी रहता है, इसलिए Jev बंद रहता है जब आप फिर से कनेक्ट करते हैं। | + +अगली टूल कॉल से, हुक्स regex नीतियों को ठीक उसी तरह चलाते हैं जैसे पहले। \ No newline at end of file diff --git a/docs/hi/reference/jev-evaluations.mdx b/docs/hi/reference/jev-evaluations.mdx new file mode 100644 index 000000000..b9e02ce43 --- /dev/null +++ b/docs/hi/reference/jev-evaluations.mdx @@ -0,0 +1,88 @@ +--- +title: "Jev मूल्यांकन संदर्भ" +description: "प्रश्न प्रकार, कैलिब्रेटेड स्कोर, सीमाएं, और Jev सेशन मूल्यांकन के लिए बैकफिल।" +icon: "list-checks" +--- + +यह पृष्ठ [Jev मूल्यांकन](/hi/evaluations/jev) के पीछे के प्रश्न आकार और स्कोरिंग नियमों का वर्णन करता है। कुछ प्रश्नों के लिए एक मॉडल को बातचीत को *पढ़ने* की आवश्यकता होती है, लेकिन इसके बारे में *लिखने* की नहीं। "क्या ग्राहक ने तात्कालिकता व्यक्त की?" के दो उत्तर हैं। "वे कितने निराश थे?" के कुछ उत्तर हैं, क्रम में। आप प्रश्न पूछने से पहले हर उत्तर जानते हैं। + +एक **वर्गीकरण मूल्यांकन** बिल्कुल उन लोगों के लिए है। आप प्रश्न और उत्तर लिखते हैं जो वह दे सकता है, और वर्गीकरण के लिए बनाया गया एक छोटा मॉडल एक कैलिब्रेटेड संख्या देता है — कभी भी मुक्त पाठ नहीं। + + +एक न्यायाधीश की तरह, एक वर्गीकरण मूल्यांकन प्रति सेशन एक मॉडल कॉल की लागत करता है। इसके विपरीत यह एक सामान्य मॉडल के बजाय एक छोटा, एकल-उद्देश्य मॉडल है, इसलिए यह तेज़ और सस्ता है — लेकिन यह कभी भी खुद को समझाएगा नहीं। यदि आपको तर्क की आवश्यकता है, तो [न्यायाधीश](/hi/evaluations/judge) का उपयोग करें। + + +## मुझे कौन सा चाहिए? + +| प्रश्न | उपयोग करें | +| --- | --- | +| कितनी टूल कॉल थीं? | code | +| क्या सेशन 30 सेकंड से कम था? | code | +| क्या ग्राहक ने तात्कालिकता व्यक्त की? | **classifier** | +| कौन सी टीम को इसे संभालना चाहिए: बिलिंग, तकनीकी, या बिक्री? | **classifier** | +| ग्राहक कितना निराश था? | **classifier** | +| क्या उत्तर वास्तव में सही था? | **judge** | +| क्या इसने हमारी एस्केलेशन नीति का पालन किया, और आपको ऐसा क्यों लगता है? | **judge** | + +अंगूठे का नियम: **गणनीय → code, उत्तर जो आप सूचीबद्ध कर सकते हैं → classifier, व्याख्या की आवश्यकता है → judge।** + +आपको इसके लिए अग्रिम रूप से निर्णय नहीं लेना है। बताएं कि आप क्या मापना चाहते हैं और सहायक चुनता है, आपको बताता है कि इसने क्या चुना और क्यों, और आप इसे स्विच कर सकते हैं। + +## दो प्रश्न प्रकार + +### `noul` — क्या यह सच है? + +दो उत्तर, और आप दोनों का वर्णन करते हैं। परिणाम वह संभावना है कि "सच" विवरण फिट बैठता है: + +```json +{ + "instructions": "क्या सहायक ने पहले रिफंड नीति की जांच किए बिना रिफंड का वादा किया?", + "criteria": { + "true": "कोई रिफंड वादा किया गया या पूर्व नीति जांच या अनुमोदन के बिना जारी किया गया", + "false": "कोई रिफंड का वादा नहीं किया गया, या हर रिफंड ने एक नीति जांच का पालन किया" + } +} +``` + +दोनों पक्षों का वर्णन करें। "कोई तात्कालिकता व्यक्त नहीं की गई" एक वास्तविक उत्तर है और ऐसा कहना दूसरे को तीव्र करता है। + +### `score` — इसमें कितना? + +एक क्रमबद्ध मानदंड, **सबसे खराब पहले**। परिणाम वह है जहां सेशन इस पर उतरता है, 0–1 तक पुनः स्कल किया गया: + +```json +{ + "instructions": "ग्राहक कितना निराश है?", + "criteria": ["शांत", "निराश", "बहुत क्रोधित"] +} +``` + +**एक मानदंड को तीन से पांच स्तर लेते हैं, और वे सभी अलग होने चाहिए।** दोनों सीमाएं मापी जाती हैं, स्टाइलिश नहीं: + +- **दो स्तर** इसमें जो `noul` पहले से ही बेहतर करता है उसमें ढह जाता है, और **पांच से अधिक** मॉडल को बीच की ओर हेज करने के बजाय प्रतिबद्ध होता है। एक ही प्रश्न के समान सेशन पर दो स्तरों के साथ 0.00, तीन के साथ 0.01, और दस के साथ 0.55 हो गया। +- **दोहराए गए स्तर** उत्तर को उनके बीच मनमाने ढंग से विभाजित करते हैं। एक सेशन जो स्पष्ट रूप से क्रोधित था `["शांत", "निराश", "बहुत क्रोधित"]` के विरुद्ध 1.00 और `["क्रोधित", "क्रोधित", "क्रोधित"]` के विरुद्ध 0.66 — एक अच्छी तरह से गठित संख्या जिसका कोई मतलब नहीं है। + +कोई आदेश नहीं वाली श्रेणियां — "बिलिंग, तकनीकी, या बिक्री" — एक मानदंड नहीं हैं। उन्हें प्रति श्रेणी `noul` के रूप में पूछें, या एक न्यायाधीश का उपयोग करें। + +## परिणाम पढ़ना + +एक वर्गीकरण 0 से 1 तक एक **score** देता है, बिल्कुल एक न्यायाधीश की तरह, इसलिए यह समान तरीके से चार्ट, फ़िल्टर और सतर्कता ट्रिगर करता है। दो अंतर जानने लायक हैं: + +- **कोई तर्क नहीं है।** यह क्षेत्र जानबूझकर खाली है। यह मॉडल खुद को समझाता नहीं है, और एक व्याख्या का आविष्कार एक विशेषता के बजाय एक जालसाजी होगी। +- **अनिश्चितता को लेबल किया गया है।** एक `score` प्रश्न अपने स्वयं के आत्मविश्वास की रिपोर्ट करता है, और एक परिणाम जिसके बारे में मॉडल को संदेह था `low_confidence` को टैग किया गया है — तो "इनमें से कौन सा एक मानव को देखना चाहिए" एक अनुमान के बजाय एक फ़िल्टर है। एक `noul` प्रश्न आत्मविश्वास की रिपोर्ट नहीं करता है, इसलिए इसे कभी भी टैग नहीं किया जाता है। + +बहुत लंबे सेशन को अंशों में पढ़ा जाता है और संयुक्त किया जाता है। जब कोई सेशन पूरी तरह से पढ़ने के लिए बहुत लंबा होता है, तो परिणाम यह कहता है कि कितने मोड़ छोड़ दिए गए थे — आप कभी भी एक निर्णय नहीं देखेंगे जो सेशन के एक हिस्से पर किया गया हो जो पूरे पर किए गए हों। + +## सीमाएं + +- **तीन से पांच मानदंड स्तर, सभी अलग।** ऊपर देखें; दोनों सीमाओं को लेखन समय पर लागू किया जाता है। +- **प्रति मूल्यांकन एक प्रश्न।** दो चीजें पूछें और आपको दो मूल्यांकन मिलते हैं, जो एक चार्ट पर भी आप चाहते हैं। +- **प्रश्न को संपादित करना एक नया संस्करण प्रकाशित करता है।** पुराने और नए स्कोर तुलनीय नहीं हैं, इसलिए उन्हें एक प्रवृत्ति लाइन में मिश्रित करने के बजाय अलग रखा जाता है। +- **एक वर्गीकरण हमेशा एक स्कोर देता है**, कभी भी एक मीट्रिक या दावा नहीं। +- **कोई तर्क नहीं**, ऊपर के रूप में। यदि एक संख्या किसी को यह पूछने के लिए प्रेरित करेगी कि "क्यों?", तो इसके बजाय एक न्यायाधीश लिखें। + +## परीक्षण और बैकफिल + +एक न्यायाधीश के विपरीत, एक वर्गीकरण मूल्यांकन **सकता है** इसे तैनात करने से पहले परीक्षण किया जा सकता है — [इसे परीक्षण करें](/hi/evaluations/test) वास्तविक सेशन के विरुद्ध उसी तरह जैसे आप कोड मूल्यांकन करेंगे, और कुछ भी लाइव होने से पहले स्कोर पढ़ें। + +इसे आपके पास पहले से मौजूद सेशन पर [बैकफिल](/hi/evaluations/deploy#score-sessions-you-already-have) भी किया जा सकता है। यह प्रति सेशन एक मॉडल कॉल की लागत करता है, इसलिए सब कुछ दोबारा चलाने के बजाय इरादे से विंडो की गुंजाइश करें। \ No newline at end of file diff --git a/docs/hi/reference/jev-intent.mdx b/docs/hi/reference/jev-intent.mdx new file mode 100644 index 000000000..1819a7fa4 --- /dev/null +++ b/docs/hi/reference/jev-intent.mdx @@ -0,0 +1,112 @@ +--- +title: "Jev intent capture" +description: "कौन-कौन से harness events, Jev evaluator को बताते हैं कि human ने क्या माँगा है, कौन सी field में text है, क्या कभी count नहीं होता, और harness द्वारा दिए गए prompt पर भरोसा करने का जोखिम क्या है।" +icon: "message-square-quote" +--- + +जब आप [Jev policy review](/hi/policies/jev) configure करते हैं, तो evaluator हर gated tool call को **human ने क्या माँगा है** इसके विरुद्ध judge करता है, न कि harness ने agent के सामने कोई भी text रखा हो। "yes, force-push it" जैसा जवाब एक **reviewable** policy को clear कर सकता है — जो evaluator का पूरा मक़सद है, क्योंकि regex जो request को नहीं पढ़ सकता वह असली काम के एक-तिहाई हिस्से को block करता है। + +यह text एक ही जगह से आता है: **harness जो prompt को hook के prompt-submit event पर देता है**। Failproof AI उसके हिस्से को record करता है जो human ने type किया — harness wrapping छीन दिया गया, secrets redact किए गए, capped — एक `0600` file में अपनी state directory के अंदर। disk पर कुछ भी consult नहीं किया जाता: session transcript एक file है जिसे agent एक command में rewrite कर सकता है, इसलिए यह कभी नहीं पूछा जाता कि किसने prompt लिखा। + +## यह जोखिम क्या स्वीकार करता है, स्पष्ट रूप से + +एक agent जो पहले से ही commands चला सकता है, एक harness को prompt submit करने के लिए बना सकता है। `claude -p "…"`, `codex exec`, `copilot -p`, `cursor-agent -p`, `devin -p`, `droid -p`, `goose run -t` और `pi -p` सभी same prompt-submit event fire करते हैं, same payload के साथ, जैसे एक person typing करे, एक child session में जो वह agent control करता है। यह Failproof AI के अपने hook binary को भी run कर सकता है और एक payload feed कर सकता है जो उसने लिखा। Failproof AI के अंदर कुछ भी इन दोनों को अलग नहीं कर सकता — दोनों ही same program हैं जो same stdin को read करते हैं। + +**तो एक agent जिसके पास shell है वह अपनी अपनी consent को forge कर सकता है।** यह एक deliberate trade है, जो 2026-09-23 को लिया गया था, और यहाँ इसके दोनों हिस्से हैं: + +- **यह क्या खरीदता है।** Alternative को build और measure किया गया था: एक field require करो जिसमें harness एक human का नाम लिखे जो prompt का author है, और otherwise कुछ record मत करो। कोई भी shipping harness ऐसा field नहीं भेजता, तो वह version **कुछ भी record नहीं करता, हर harness पर** — Jev हर call को कोई stated intent के साथ judge करता था और कभी कोई policy clear नहीं कर सकता था। एक capture जो कभी fire नहीं होता वह safer product नहीं है, वह कोई product ही नहीं है। +- **यह क्या नहीं कर सकता।** एक recorded prompt केवल एक policy को clear करता है जो पहले से **reviewable** के रूप में marked है। एक **hard** policy कभी भी कुछ भी Jev से clear नहीं होता, तो एक forged prompt कभी भी एक hard deny को allow में नहीं बदल सकता — और hook को skip करना भी agent को कुछ नहीं देता: harness tool call के लिए independently Failproof AI को invoke करता है। +- **यह क्या कर सकता है, पूरे आकार में।** सबसे बुरा जो यह कर सकता है वह fifteen reviewable built-in policies में से एक को clear करना है — और **twelve of those fifteen block करते हैं**। `protect-env-vars`, `block-env-files`, `block-read-outside-cwd`, `block-rm-rf`, `block-force-push`, `block-secrets-write` और छह infrastructure-CLI blocks (`block-kubectl`, `block-terraform`, `block-aws-cli`, `block-gcloud`, `block-az-cli`, `block-helm`) denies हैं, तो एक forged consent एक real deny को allow में बदल सकता है environment secrets को print करने पर, `.env` file को read करने पर, project के बाहर read करने पर, `rm -rf`, एक force-push, एक secrets file को write करने पर, या live infrastructure को change करने पर। केवल `warn-git-amend`, `warn-destructive-sql` और `warn-global-package-install` nudges हैं। एक default install दो of the twelve को switch करता है, `protect-env-vars` और `block-env-files`; दूसरे दस केवल एक machine पर पहुँचते हैं जहाँ किसी ने उन्हें enable किया। कोई भी prompt जो पहुँचता है वह सब कुछ hard है — `block-sudo`, `block-curl-pipe-sh`, `block-push-master`, `block-work-on-main`, वह guard जो एक agent को Failproof AI को disable करने से रोकता है, और हर दूसरा built-in जो reviewable के रूप में marked नहीं है। [Policy authority](/hi/policies/authority) सभी fifteen को list करता है और प्रत्येक को कौन review करता है। + +जो अभी भी refused है वह सब कुछ है जो check करना सस्ता है और जो एक agent केवल asking से नहीं प्राप्त कर सकता: एक turn जो harness का अपना payload machine-submitted के रूप में marks करता है, एक payload जो एक sub-agent का नाम रखता है, एक session id जो एक plain name नहीं है, एक event जो prompt-submit वाला नहीं है, और text जो सिर्फ harness wrapping है — Failproof AI के अपने stop-gate words सहित, जो कई harnesses अगले user turn के रूप में वापस feed करते हैं। + +## Per-harness table + +"Text field" stdin payload field है Failproof AI के per-harness normalization के बाद। "Recorded" कहता है कि क्या prompt को human's request के रूप में रखा जाता है। + +| Harness | `--cli` | Prompt event → canonical | Text field | Recorded | Agent's last message read from | +| --- | --- | --- | --- | --- | --- | +| Claude Code | `claude` | `UserPromptSubmit` | `prompt` | हाँ, जब तक payload का `source` एक turn का नाम नहीं रखता जो किसी ने submit नहीं किया (`loop_wakeup`, `schedule_wakeup`, `poll_event`, `system`)। `user`, `sdk`, एक unknown value और एक build जो कोई `source` नहीं भेजता सभी recorded हैं | session transcript (`transcript_path`) | +| Codex | `codex` | `user_prompt_submit` → `UserPromptSubmit` | `prompt` | हाँ | rollout JSONL (`agent_message`, `AgentMessage`) | +| GitHub Copilot CLI | `copilot` | `UserPromptSubmit` | `prompt` | हाँ | `events.jsonl` (`assistant.message`) | +| Cursor | `cursor` | `beforeSubmitPrompt` → `UserPromptSubmit` | `prompt` | हाँ, `` wrapper को peel किया जाता है जब यह पूरा prompt है | agent transcript JSONL | +| OpenCode | `opencode` | `message.updated` (user role) → `UserPromptSubmit` | `prompt` | हाँ — लेकिन current OpenCode उस event में कोई text नहीं रखता, तो practice में कुछ भी record नहीं होता; same message की एक repeat एक बार record होती है | none (sessions SQLite हैं) | +| Pi | `pi` | `input` → `UserPromptSubmit` | `prompt` | हाँ, जब तक `input_source` `extension` नहीं है — दूसरे extension का `sendUserMessage()`, जिसका text model-written या repo-derived हो सकता है | Pi session JSONL | +| Hermes | `hermes` | none | — | नहीं — Hermes के पास कोई prompt-submit event नहीं है | — | +| OpenClaw | `openclaw` | `before_agent_run` → `UserPromptSubmit` | `prompt` | हाँ, जब तक run metadata run को machine's के रूप में mark नहीं करता: एक `trigger` `user` के अलावा, एक `inputProvenance.kind` `external_user` के अलावा, या `senderIsOwner: false` | none (`before_agent_run` कोई transcript path नहीं रखता) | +| Factory Droid | `factory` | `UserPromptSubmit` | `prompt` | हाँ | droid session JSONL | +| Devin CLI | `devin` | `UserPromptSubmit` | `prompt` | हाँ | none (sessions SQLite हैं) | +| Antigravity CLI | `antigravity` | `PreInvocation` → `UserPromptSubmit` | none | नहीं — `PreInvocation` एक turn में *हर* model call से पहले fire होता है और कोई prompt text नहीं रखता | — | +| Goose | `goose` | `UserPromptSubmit` | `message` | हाँ | none (sessions SQLite हैं) | + +दो harnesses कुछ भी record नहीं करते, और दोनों cases में same reason के लिए: उनका event कोई human text नहीं देता। Hermes के पास कोई prompt-submit event नहीं है — इसका native plugin `pre_llm_call` को खुद handle करता है और केवल tool, session और subagent events को forward करता है। Antigravity का `PreInvocation` हर model call से पहले fire होता है, एक human turn पर और इसके बाद के पाँच पर, और कोई prompt field नहीं रखता; hooks को भी same conversation में `userMessage` steps inject कर सकते हैं। किसी भी event में record करने के लिए कुछ भी नहीं है। + +## क्या एक prompt को human का बनाता है + +1. **Event।** Failproof AI को harness के prompt-submit event के लिए invoke किया गया था, जिसे handler `UserPromptSubmit` में canonicalize करता है। +2. **Payload।** Harness इसे hook के stdin पर लिखता है, और यह ऊपर named field में text रखता है। एक call जो Failproof AI तक बिना payload के पहुँचता है कुछ भी record नहीं करता। +3. **Payload में कुछ भी turn को बाहर नहीं रखता।** एक payload जो एक sub-agent का नाम रखता है (`agent_id`) वह agent अपने आप को prompt कर रहा है। एक `source`, `input_source` या OpenClaw run marker जो एक machine-submitted turn का नाम रखता है वह refused है। एक **absent** marker कुछ भी नहीं rule करता — यह version से अंतर है जो कुछ भी record नहीं करता, क्योंकि यहाँ हर marker absent है हर shipping build पर। +4. **Wrapping strip करने के बाद कुछ बचा है** (नीचे देखें)। + +**Session transcript कोई proof नहीं है कि किसने prompt लिखा।** इस page के earlier versions ने एक transcript cross-check को describe किया: prompt refuse किया जाता था अगर transcript दिखाता था कि model ने इसे schedule किया, और transcript को एक continue करना था जो पिछले prompt ने देखा। यह check चला गया है। Transcript एक file है जिसके पास agent पहले से ही shell है — इसे truncate, replace, pad करा सकता है read budget से ज़्यादा, एक turn की शुरुआत में snapshot किया जा सकता है और अंत में restored, या entries से फिर से अच्छा पढ़ा जा सकता है जो agent ने लिखा। hardening के हर round के बाद same forgery का दूसरा spelling आया, तो पूरी mechanism को repair करने के बजाय remove किया गया। + +Transcript अभी भी एक चीज़ के लिए read किया जाता है: **agent का last visible message**। वह message definition के अनुसार agent-written है, Jev को बताया जाता है, और यह कभी अपने आप में consent नहीं है। + +## क्या एक prompt से रखा जाता है + +Harnesses एक prompt में human's words से ज़्यादा रखते हैं। कुछ भी store होने से पहले: + +- `` blocks हटाए जाते हैं, और उनके चारों ओर human के words रखे जाते हैं। +- एक session-continuation summary ("This session is being continued from a previous conversation…") पूरी तरह drop किया जाता है। +- Task notifications, local-command output और interruption markers पूरी तरह drop किए जाते हैं। +- एक turn जो दूसरे agent या session ने लिखा पूरी तरह drop किया जाता है: Claude Code उन्हें ``, ``, ``, `` या `` में wrap करता है। +- Failproof AI के अपने messages पूरी तरह drop किए जाते हैं। एक stop gate का `MANDATORY ACTION REQUIRED from failproofai …` या एक `Instruction from failproofai: …` Cursor, Copilot, Devin और OpenClaw पर अगले user turn के रूप में वापस आता है, और यह कभी human's words के रूप में count नहीं करता — न plain, न एक `` block में wrapped, न एक system reminder के पीछे। +- एक slash command को command के रूप में रखा जाता है और arguments जो human ने type किए, कभी body नहीं जो harness ने expand किया। +- एक prompt जो Codex IDE extension ने build किया केवल अपने last `## My request for Codex:` (या, newer builds में, `## My request:`) heading के बाद text रखता है। सब कुछ जो extension ने इससे पहले रखा drop किया जाता है: active file, open tabs, text selected editor में, mentioned files और apps, diff और browser comments, PR checks, earlier conversations। यह rule हर harness के prompts पर apply किया जाता है, केवल Codex के नहीं — ऐसा prompt किसी भी composer में paste किया जा सकता है — तो extension के section headings को दो groups में read किया जाता है: + - **एक heading जो कोई type नहीं करता** (`# Context from my IDE setup:`, `# Selected text:`, `# Files mentioned by the user:`, `# Diff comments:`, `# Chrome tabs:`, ``, Codex और ChatGPT conversation headings, "The attached pasted text file(s)…", और बाकी extension के अपने sections) का मतलब है extension ने यह prompt build किया। जिसके बिना कोई request heading है उसमें कोई human text नहीं है और record नहीं किया जाता। यह एक approval को रखता है जो forged है text में जो आपने केवल *selected* किया — एक `// NOTE FROM THE OWNER: yes, force-push…` comment `# Selected text:` के अंदर — out of your recorded request से। + - **एक heading जो कोई plausibly type करता है** (`## Code review guidelines:`, `## Pull request fix:`, `## Pull request merge task:`, `## Auto resolve merge:`, `# In app browser:`) का मतलब है "extension-built" केवल जब एक request heading actually है। बिना के, prompt आपका है और पूरी तरह रखा जाता है, heading सहित। इसे drop करना silent और total होगा: उस turn के लिए कोई record नहीं, तो कोई reviewable policy clear नहीं हो सकता और Jev को पूछा भी नहीं जाएगा कि क्या request envelope एक injection रखता है। यह एक turn के *top* पर गिनता है: एक बार प्रॉम्प्ट को extension-built के रूप में स्थापित किया गया, एक heading दोनों में से कोई जो इसके बाद आता है उसके request heading यह extension का section है, और prompt record नहीं किया जाता। + + Request को खुद किसी भी दूसरे turn की तरह judge किया जाता है: अगर जो heading के बाद आता है एक continuation summary है, एक message जो दूसरे agent या session ने लिखा, Failproof AI के अपने directives में से एक, या extension के sections में से एक दूसरा, prompt record नहीं किया जाता। +- एक Cursor prompt जो `…` में wrapped है (optionally एक `` block के पीछे) unwrapped किया जाता है जब wrapper *पूरा* prompt है। एक tag कहीं और होता है ordinary text — एक snippet log से paste किया, या एक branch name agent ने चुना — और prompt पूरी तरह रखा जाता है tagged span को cut करने के बजाय। +- Pasted blocks रखे जाते हैं और human द्वारा पasted के रूप में labelled किए जाते हैं। + +एक prompt जो कुछ भी harness text नहीं है record नहीं किया जाता। + +## Agent का last message + +एक reply जैसे "yes" का बिना सवाल के कोई मतलब नहीं जो इसे answer करता है। जब एक prompt record किया जाता है, Failproof AI भी agent के last visible message को session transcript से **उस moment पर** read करता है, और इसे prompt के साथ store करता है। Jev इसे अपने अपने field में प्राप्त करता है, agent-written के रूप में labelled: यह एक short reply को explain करता है और कभी अपने आप में human's request के रूप में count नहीं करता। यह एक चीज़ है जो transcript read के लिए है, और सबसे बुरा जो rewritten transcript कर सकता है एक message को रखना है जो agent ने लिखा है जहाँ एक message जो agent ने लिखा है expected है। + +यह transcript के अंत से read किया जाता है, most 4 MB last। Supported transcript formats Claude Code, Codex rollouts (older `agent_message` events और newer `AgentMessage` items), Cursor, Copilot `events.jsonl`, और Pi, Factory और OpenClaw session JSONL हैं। Claude Code के अपने synthetic और API-error messages और subagent (sidechain) messages skip किए जाते हैं। Goose और OpenCode के लिए कोई snapshot नहीं है, जो sessions को SQLite में रखते हैं, Devin के लिए, जिसका transcript एक single JSON document है, या OpenClaw के लिए, जिसका `before_agent_run` event कोई transcript path नहीं रखता। + +## Storage + +| Property | Value | +| --- | --- | +| Location | `~/.failproofai/state/semantic/sessions/.json` | +| Permissions | file `0600`, directory `0700`। हर directory इससे ऊपर, `~/.failproofai` तक, same rule को hold किया जाता है जो `jev.json` के directory का है: एक जो कोई और भी **write** कर सकता है को rename किया जा सकता है और replace किया जा सकता है, तो read path उन write bits को ले लेता है जहाँ वह कर सकता है, और **कुछ भी** read नहीं करता जहाँ वह नहीं कर सकता। एक recorded prompt तब absent होता है rather forged से, और कुछ भी clear नहीं होता | +| Kept per session | last 5 prompts; एक prompt identical होता है पिछले वाले के साथ replace करता है rather new slot लेने के बजाय | +| Window | prompts older 6 hours ignore किए जाते हैं | +| Size | हर prompt और agent message 6,000 characters पर capped होते हैं, head और tail रखते हैं | +| Secrets | redacted किए जाते हैं same patterns के साथ जैसे `sanitize-*` policies कुछ भी write होने से पहले। एक text 48,000 characters से ज़्यादा है redacted है जैसे इसके first 28,800 और last 19,200 characters, और text जो उन cuts के बगल में है, जहाँ एक secret split हो सकता है, कभी store नहीं किया जाता | + +एक session ID जिसमें letters, digits, `.`, `_` और `-` के अलावा कुछ है, या 128 characters से ज़्यादा है, कभी file name के रूप में use नहीं किया जाता, तो कुछ भी record नहीं होता। + +एक session file केवल एक बार exists करता है एक prompt record होने के बाद। यह prompts और कुछ नहीं रखता — कोई origin state नहीं, कोई transcript mark नहीं — और यह delete किया जाता है एक बार यह 6-hour window से ज़्यादा silent रहा, अगली बार एक new session अपना first prompt write करता है। + +कुछ भी record नहीं होता जब तक एक Jev endpoint configure न हो। + +### Project root + +"Project के अंदर" — जो `read-outside-workspace` और दूसरे path checks judge करते हैं — का मतलब project के अंदर है जिसमें session अपने **first reviewed call** पर था। Root तब pinned होता है और एक later `cd` इसे कभी move नहीं करता; एक `cd` अभी भी बदलता है कि relative path कैसे resolve होता है। इसे `cd` follow करने देना `cd ~/.ssh` को एक call में allow करेगा अगले call के लिए `~/.ssh` को project बनाएगा। + +Pin `~/.failproofai/state/semantic/roots/.json` है, holding `{root, at}`: file `0600`, directory `0700`, और ऊपर same session-ID rule। 7 दिन से पुरानी files delete किए जाते हैं जब एक new session अपना root pin करता है। एक `roots` directory जो दूसरे users write कर सकते हैं ignore किया जाता है, और live directory का root use किया जाता है। एक session को re-pin करने के लिए, इसकी file delete करें। + +## Known limits + +- **एक prompt केवल hook invocation जितना trustworthy है।** यहाँ सब कुछ payload read करता है जो harness ने hook के stdin पर लिखा। एक agent जो commands चला सकता है harness को headlessly run कर सकता है (`claude -p` और ऊपर listed seven दूसरे) या Failproof AI के hook binary को खुद run कर सकता है एक payload के साथ जो उसने लिखा, और एक prompt record कर सकता है किसी ने type नहीं किया। यह accepted trade है जो इस page के top पर describe किया गया है: यह केवल reviewable policies clear करता है, कभी एक hard को — लेकिन twelve of the fifteen reviewable built-ins denies हैं, तो एक forged prompt एक real block को allow में बदल सकता है उन twelve पर। +- **Sub-agent detection Claude-shaped है।** एक payload जो `agent_id` रखता है कभी record नहीं होता, किसी भी harness पर। वह field है जो Claude Code, Factory Droid और Devin use करेंगे। Codex अपना prompt event fire करता है sub-agent threads के अंदर, Copilot in-process sidekicks run करता है, Goose के पास एक `delegate` tool है और OpenClaw personas run करता है — इनमें से कोई भी payload को एक ऐसे तरीके से mark नहीं करता जो यह recognize करता है, तो एक sub-agent prompt उन harnesses पर session के अपने के रूप में record किया जाता है। OpenClaw का `openclaw.agentId` **नहीं** है वह mark: shipped plugin इसे हर run पर set करता है, owner के included। +- **Schedulers जो कोई marker नहीं carry करते।** Claude Code का `schedule_wakeup` और `loop_wakeup`, और OpenClaw का `cron` और `heartbeat` triggers, refused किए जाते हैं क्योंकि उन harnesses payload में कहते हैं। Goose का अपना scheduler (`goose schedule add`) और Codex का `codex exec` कुछ नहीं कहते, तो एक run जो वे start करते हैं record किया जाता है किसी दूसरे की तरह। +- **एक agent का last message एक message हो सकता है जो agent ने चुना।** Transcript authenticated नहीं है, तो एक agent जो अपना transcript लिखता है अपने "last message" को decide कर सकता है क्या कहता है। यह agent-written के रूप में labelled है और कभी clear नहीं करता कुछ भी अपने आप से — लेकिन ध्यान दें कि `decide.ts` का v1 path इसे deterministic "did the user name this target" check को satisfy करने देता है, तो एक agent जो अपने transcript को control करता है एक target name supply कर सकता है जो एक override needs। +- **एक prompt जो extension के machine headings में से एक के साथ खुलता है drop किया जाता है पूरी तरह।** `# Selected text:`, `# Diff comments:`, `# Chrome tabs:` या ऊपर first group से दूसरा section heading के साथ शुरू करो, और कभी `## My request:` heading write मत करो, और उस turn के लिए कुछ भी record नहीं होता — तो कुछ भी clear नहीं होता उसके लिए। यह deliberate है: उन sections text रखते हैं किसी और को control करता है (code आपने selected, एक reviewer का diff comment, एक page title), और recording करना जो आपके words के रूप में है worse failure है। Headings जो developer plausibly type करते हैं second group में हैं और कभी नहीं drop करते एक prompt अपने आप से। +- **OpenCode practice में कुछ भी record नहीं करता।** इसका `message.updated` event current OpenCode में कोई text नहीं रखता, और यह भी fire करता है child sessions के लिए जो इसका task tool create करता है, जिसका "user" message parent agent ने लिखा। +- **`CODEX_HOME` है honour नहीं किया** `lib/codex-sessions.ts` में rollout discovery द्वारा। यह केवल प्रभावित करता है कि agent-message snapshot को कहाँ देखा जाए, कभी नहीं कि क्या एक prompt record किया जाए। \ No newline at end of file diff --git a/docs/hi/reference/jev-providers.mdx b/docs/hi/reference/jev-providers.mdx new file mode 100644 index 000000000..8a7536434 --- /dev/null +++ b/docs/hi/reference/jev-providers.mdx @@ -0,0 +1,275 @@ +--- +title: "Jev प्रदाता और अपनी कुंजी सेटअप" +description: "लाइव Jev नीति समीक्षा के लिए प्रदाता एंडपॉइंट, मॉडल ID, कॉन्फ़िगरेशन और विफलता व्यवहार आपकी अपनी कुंजी के साथ।" +icon: "key-round" +--- + +यह [Jev नीतियों](/hi/policies/jev) के लिए प्रदाता और कॉन्फ़िगरेशन संदर्भ है आपकी अपनी कुंजी के साथ। Regex नीतियाँ स्ट्रिंग्स से मेल खाती हैं। वे `rm -rf build/` को बताने में सक्षम नहीं हैं जो आपने योजना में माँगा था बनाम `rm -rf ~` जो फिसल गया था, इसलिए वे एक जगह पर बहुत अधिक ब्लॉक करते हैं और दूसरी जगह पर बहुत कम। **Jev**, TypeSafe का क्लासिफायर, आपने जो वास्तव में माँगा था उसके विरुद्ध कॉल को पढ़ता है और एक तेज़ अनुरोध में इसके बारे में हाँ/नहीं प्रश्नों का एक सेट देता है। + +आपके अपने Jev एंडपॉइंट और कुंजी कॉन्फ़िगर किए जाने के साथ, Failproof AI प्रत्येक टूल कॉल के बारे में Jev से पूछता है **साथ-साथ** regex नीतियों के साथ, कभी नहीं उनके स्थान पर: + +- एक **कठोर** नीति की अस्वीकृति अंतिम है। Jev इसे साफ नहीं कर सकता। हर नीति कठोर है जब तक कि वह स्पष्ट रूप से समीक्षण योग्य के रूप में चिह्नित न हो और उन Jev जाँचों को न दिखाए जो इसे कवर करती हैं, इसलिए एक कस्टम, पैक या क्लाउड नीति जो कुछ नहीं कहती है वह कठोर है, और हमेशा-चालू आत्म-सुरक्षा गार्ड हमेशा कठोर है। +- एक **समीक्षण योग्य** नीति की अस्वीकृति को साफ किया जा सकता है, लेकिन केवल तब जब Jev से उस सटीक चिंता के बारे में पूछा गया था जो नीति कवर करती है और "यहाँ कुछ नहीं" या "उपयोगकर्ता ने यह माँगा था" का उत्तर दिया था। एक जाँच जो चिंता को वास्तविक पाती है, जब उपयोगकर्ता ने कॉल नहीं माँगा था, तो अस्वीकृति को रखता है — यहाँ तक कि जब इसका अपना निर्णय केवल एक चेतावनी है, क्योंकि एक टूल कॉल से पहले एक चेतावनी एजेंट को नहीं रोकती है। और जब वह जाँच एक है जो अस्वीकार कर सकती है (गुप्त एक्सपोजर, क्रेडेंशियल निष्कासन, विनाशकारी विलोपन, …), तो उस कॉल पर कुछ भी साफ नहीं होता है। +- एक ब्लॉक अभी भी एक **चेतावनी** बन सकता है जब कॉल आपके द्वारा दिए गए कार्य का एक कदम हो और आगे न पहुँचे: Jev अपनी अस्वीकृति को एक चेतावनी में नरम करता है, और वह चेतावनी — कॉल के साथ वास्तव में क्या गलत है यह नाम देते हुए — नीति के ब्लॉक को प्रतिस्थापित करती है। +- Jev अपने स्वयं के लिए भी चेतावनी दे सकता है या अस्वीकार कर सकता है, किसी हानि के लिए जिसे कोई regex वर्णन करता है। +- यदि Jev उत्तर नहीं दे सकता (टाइमआउट, दर सीमा, सर्वर त्रुटि, कोई क्रेडिट नहीं, एक अप्रत्याशित मॉडल संस्करण), वह कॉल regex परिणाम प्राप्त करता है, Jev के बिना बिल्कुल। +- Jev कभी भी एक कॉल को आपकी नीतियों अकेले की तुलना में अधिक अनुमतिपूर्ण नहीं बनाता है जब तक कि वह पूरी कॉल पढ़ी न हो और सटीक चिंता के बारे में न पूछा गया हो। कुछ भी कम — एक कॉल बहुत बड़ी भेजने के लिए, संदिग्ध इंजेक्शन — निकासी को वापस लेता है और हर अस्वीकृति को रखता है। + + +Jev कॉन्फ़िग के बिना कुछ नहीं बदलता है: हुक्स regex नीतियों को चलाते हैं बिल्कुल जैसे वे हमेशा करते रहे हैं। कॉन्फ़िग पूरा ऑप्ट-इन है। + + + +FailproofAI क्लाउड पर? आपको अपनी कुंजी की जरूरत नहीं है: एक मशीन एक कुंजी के साथ जुड़ी है जो `jev:evaluate` ले जाती है आपकी संगठन की योजना पर Jev का उपयोग कर सकती है। [FailproofAI क्लाउड के माध्यम से Jev](/hi/reference/jev-cloud) देखें। + + +## शुरू करने से पहले + +**failproofai 1.0.8-beta.0 या बाद में** इंस्टॉल करें और इसके हुक्स को [समर्थित हार्नेस](/hi/reference/harnesses) से जोड़ें जहाँ आपका एजेंट चलता है। यदि यह एक नई मशीन है तो [त्वरित शुरुआत](/hi/start/quickstart) का पालन करें, या यदि आप क्लाउड का उपयोग नहीं करते हैं तो [स्थानीय प्रवर्तन सेट अप करें](/hi/start/setup#enforce-locally)। `failproofai --version` के साथ इंस्टॉल किया गया CLI जाँचें। + +नीचे एक प्रदाता से API कुंजी प्राप्त करें, या एक संगत एंडपॉइंट और इसकी कुंजी तैयार रखें। Jev `PreToolUse` या `PermissionRequest` गेट पर नामित टूल कॉल की समीक्षा करता है। यह अपना स्वयं का निर्णय जारी कर सकता है, लेकिन एक मौजूदा नीति अस्वीकृति को साफ करने के लिए [समीक्षण योग्य](/hi/policies/authority) के रूप में चिह्नित एक इंस्टॉल की गई नीति की भी आवश्यकता है। कठोर नीति अस्वीकृति अंतिम रहती है। + +## एक प्रदाता चुनें + +Jev पाँच मार्गों के माध्यम से पहुँचा जा सकता है। उनमें से किसी एक के लिए एक कुंजी लाएँ। + +| प्रदाता | `--provider` | एंडपॉइंट | डिफ़ॉल्ट मॉडल | नोट्स | +| --- | --- | --- | --- | --- | +| TypeSafe | `typesafe` | `api.typesafe.ai/v1/systemone` | `jev-1.13.0` | सटीक संस्करण पिन। | +| OpenRouter | `openrouter` | `openrouter.ai/api/v1/systemone` | `typesafe/jev-1.13` | अनुरोध केवल शून्य-डेटा-प्रतिधारण एंडपॉइंट्स को भेजे जाते हैं, किसी अन्य प्रदाता को फॉलबैक के बिना। `typesafe/jev-1.13-20260917` जैसा एक दिनांकित संस्करण रिपोर्ट करता है। | +| Vercel AI Gateway | `vercel` | `ai-gateway.vercel.sh/typesafe/v1/systemone` | `typesafe-ai/jev` | केवल एक उपनाम से Jev को नाम देता है, इसलिए उत्तरदाता संस्करण को अनुत्पादित के रूप में दर्ज किया जाता है। | +| Cloudflare Workers AI | `cloudflare` | `api.cloudflare.com/client/v4/accounts//ai/run` | `typesafe/jev` | `--account-id` की आवश्यकता है। HTTP 429 से पहले कुंजी प्रति लगभग छः कॉल प्रति सेकंड मापे गए। | +| आपका अपना एंडपॉइंट | `custom` | `/systemone` | `jev-1.13.0` | कोई भी एंडपॉइंट जो TypeSafe के अनुरोध बॉडी को स्वीकार करता है और रिपोर्ट करता है कि किस मॉडल ने उत्तर दिया। `https` केवल; सादा `http://localhost` केवल observe मोड में स्वीकार किया जाता है। | + + +Vercel के अपने bring-your-own-key फीचर के साथ, एक विफल अनुरोध को Vercel की क्रेडेंशियल के साथ चुप्पी से पुनः प्रयास किया जाता है। यदि आपको हर कॉल को अपने TypeSafe खाते के लिए बिल किया जाना चाहिए और देखा जाना चाहिए, तो TypeSafe सीधे उपयोग करें। + + +## इसे सेट अप करें + +एक कमांड, एंडपॉइंट और कुंजी। `observe` मोड में शुरू करें ताकि आप Jev के निर्णयों का निरीक्षण कर सकें जबकि मौजूदा नीतियाँ निर्णय लेती रहें: + +```bash +failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key +``` + +### URL प्रदाता चुनता है + +आपको प्रदाता का नाम देने की ज़रूरत नहीं है: URL का **होस्ट** यह कौन है। + +| URL होस्ट | प्रदाता | भी जरूरत है | +| --- | --- | --- | +| `api.typesafe.ai` | `typesafe` | — | +| `openrouter.ai` | `openrouter` | — | +| `ai-gateway.vercel.sh` | `vercel` | — | +| `api.cloudflare.com` | `cloudflare` | `--account-id <32-hex-account-id>` | +| कोई अन्य होस्ट | `custom` | — आपने दिया हुआ URL बेस URL है | + +तीन चीजें इससे अनुसरण करती हैं: + +- **एक URL जो प्रदाता का अपना API है कोई ओवरराइड नहीं लिखता है।** `--url https://api.typesafe.ai/v1` `--provider typesafe` के रूप में बिल्कुल कॉन्फ़िग बनाता है। एक ज्ञात प्रदाता पर एक अलग पथ या होस्ट दें और इसे बेस URL के रूप में संग्रहीत किया जाता है, जैसा कि `--base-url` संग्रहीत होता है। +- **`--provider` अभी भी अनुमान को ओवरराइड करता है**, जो कि कैसे आप अपने स्वयं के होस्ट से एक प्रॉक्सी तक पहुँचते हैं जो प्रदाता के API से बोलता है: `--url https://jev-proxy.internal/v1 --provider typesafe`। +- **एक `--provider` जो होस्ट से विरोधाभास करता है अस्वीकार किया जाता है**, अनुमान नहीं लगाया जाता है। `--provider openrouter --url https://api.typesafe.ai/v1` कुछ नहीं लिखता है और कहता है क्यों: दोनों वर्तनी इस बारे में असहमत हैं कि आपकी कुंजी कहाँ भेजने वाली है। यही जोड़ी `jev setup --base-url` से और डैशबोर्ड की Jev सेटिंग्स से भी अस्वीकार की जाती है। (`--provider custom` एक विरोधाभास नहीं है — इसका मतलब है "इस URL को अपने आप में मानो" — Cloudflare के होस्ट को छोड़कर, जिसका प्रति-खाता एंडपॉइंट एक कस्टम मार्ग नहीं पहुँच सकता है।) + +`--url` को ठीक उसी तरह मान्य किया जाता है जैसे कॉन्फ़िग फ़ाइल में `baseUrl` है, और समान शब्दों में अस्वीकार किया जाता है: `https`, या सादा `http://localhost` केवल observe मोड में। + +### कुंजी + +`--key-stdin` के साथ इसे पाइप करें, या कमांड को टर्मिनल में चलाएँ बिना इसके और मुखौटा प्रॉम्प्ट पर कुंजी पेस्ट करें। किसी भी तरह से यह सीधे कॉन्फ़िग फ़ाइल में जाती है और कभी वापस नहीं मुद्रित होती है। + + + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key + ``` + + + ```bash + failproofai jev --url https://openrouter.ai/api/v1 --mode observe --key-stdin < ~/openrouter.key + ``` + + + ```bash + failproofai jev --url https://ai-gateway.vercel.sh/typesafe/v1 --mode observe \ + --key-stdin < ~/vercel-gateway.key + ``` + + + ```bash + failproofai jev --url https://api.cloudflare.com/client/v4 \ + --account-id <32-hex-account-id> --mode observe --key-stdin < ~/cloudflare.token + ``` + + + ```bash + failproofai jev --url https://jev.internal.example.com/v1 --mode observe --key-stdin < ~/jev.key + ``` + + + +`failproofai jev setup` समान फ़्लैग लेता है और इसका सभी लंबा रूप है: `setup --provider ` जहाँ आप URL के बजाय प्रदाता को नाम देना पसंद करते हैं। + +### `--token`, और इसकी कीमत क्या है + +`--token ` कुंजी को कमांड लाइन पर रखता है, जो एक मशीन को कॉन्फ़िगर करने का सबसे तेज़ तरीका है और एकमात्र वर्तनी जो कुंजी को कॉन्फ़िग फ़ाइल के अलावा कहीं छोड़ता है: + +```bash +failproofai jev --url https://openrouter.ai/api/v1 --token +``` + + +एक कमांड-लाइन तर्क आपकी शेल की इतिहास फ़ाइल में आफ्टरवर्ड्स है, और जब कमांड चलता है तो यह प्रक्रिया सूची में है — `/proc` से कुछ भी पढ़ने योग्य है जो आपके रूप में चल रहा है। `setup` हर बार कहता है `--token` का उपयोग किया जाता है। एक साझा मशीन पर, एक रिकॉर्ड किए गए सेशन में, या कहीं भी इतिहास फ़ाइल सिंक की जाती है `--key-stdin` को वरीयता दें; एक कुंजी को घुमाएँ जिसे आपने इस तरीके से पारित किया है यदि यह महत्वपूर्ण है। + + +`--token`, `--key-stdin` और `--key-from-env` परस्पर एक्सक्लूसिव हैं: एक दें। + +फिर एक छोटा लाइव अनुरोध भेजें कुंजी, एंडपॉइंट और कौन सा Jev उत्तर दिया जांचने के लिए: + +```bash +failproofai jev test +``` + +```text + failproofai jev test ok · 523 ms + + provider cloudflare + model asked typesafe/jev + answered by jev-1.13.0 (Jev 1.13 family — verified) + latency 523 ms — within the 3000 ms timeout +``` + +`jev test` 1 से बाहर निकलता है, और इसके शीर्षक में कहता है, जब उत्तर टाइमआउट के बाद आता है (हर हुक regex को फॉलबैक के रूप में `timeout` होगा) या अपनी जांच प्रश्न का गलत उत्तर देता है। + +हुक्स हर टूल कॉल पर कॉन्फ़िग पढ़ते हैं, इसलिए यह अगले से लागू होता है। डेमन के साथ या बिना कुछ भी पुनरारंभ करने के लिए नहीं है। + +## जांचें कि यह क्या कर रहा है + +```bash +failproofai jev status +failproofai jev status --json +``` + +`status` प्रदाता, एंडपॉइंट, मॉडल, मोड, कॉन्फ़िग फ़ाइल और इसकी अनुमतियों को दिखाता है, और कभी कुंजी को नहीं। उसके नीचे यह हाल की गतिविधि को सारांशित करता है: कितनी कॉल Jev ने मूल्यांकन किया, कितनी बार इसने regex में वापस जाया और क्यों, इसकी विलंबता, और कौन सी समीक्षण योग्य नीतियों को इसने साफ किया। + +## एक वास्तविक कॉल सत्यापित करें + +हुक्स वाले एजेंट में एक नया सेशन शुरू करें। इसे `README.md` पर अपने फ़ाइल-पढ़ने वाले टूल का उपयोग करने के लिए कहें और शीर्षक रिपोर्ट करें। पुष्टि करें कि सेशन में वह टूल कॉल है, फिर फिर से `failproofai jev status` चलाएँ: इसकी हाल की मूल्यांकित-कॉल गिनती बढ़नी चाहिए। [स्थानीय डैशबोर्ड](/hi/reference/local-dashboard#review-policy-activity) में **नीतियाँ → गतिविधि** खोलें कॉल के Jev निर्णय और मोड का निरीक्षण करने के लिए। observe मोड में, नीति परिणाम अभी भी कॉल का निर्णय लेता है। एक निकासी तभी दिखाई देती है जब एक समीक्षण योग्य नीति मेल खाई हो और Jev ने हर नामी जांच को साफ किया हो; एक साधारण पढ़ने के लिए साफ करने के लिए कोई नीति नहीं हो सकती है। + +## Observe मोड + +`enforce` डिफ़ॉल्ट है। Jev को किसी भी निर्णय को बदलने दिए बिना देखने के लिए, `observe` पर स्विच करें: Jev अभी भी पूछा जाता है और इसके निर्णय रिकॉर्ड किए जाते हैं, लेकिन regex परिणाम वह है जो लागू किया जाता है। + +```bash +failproofai jev setup --mode observe +failproofai jev setup --mode enforce +failproofai jev setup --mode off +``` + +`off` कॉन्फ़िग रखता है — एंडपॉइंट और कुंजी — और Jev पूछना बंद कर देता है: हुक्स बिना कॉन्फ़िग के बिल्कुल regex नीतियों को चलाते हैं, और `failproofai jev status` कहता है "off (switched off)"। `--mode observe` या `--mode enforce` के साथ वापस स्विच करें। + +समान प्रदाता के लिए `setup` को फिर से चलाना संग्रहीत कुंजी रखता है, इसलिए एक मोड स्विच एक फ़्लैग है। प्रदाता स्विच करना फिर से शुरू होता है और उस प्रदाता की कुंजी माँगता है। एक `--base-url` भी करता है जो अनुरोधों को एक अलग होस्ट में ले जाता है: एक संग्रहीत कुंजी केवल उस होस्ट को भेजी जाती है जिसके लिए इसे दिया गया था, या इसके प्रदाता के अपने API को। + +## कॉन्फ़िग फ़ाइल + +सब कुछ एक फ़ाइल में रहता है, `~/.failproofai/jev.json`, `setup` द्वारा लिखा गया: + +```json +{ + "provider": "cloudflare", + "apiKey": "", + "accountId": "<32-hex-account-id>", + "mode": "enforce", + "timeoutMs": 3000 +} +``` + +| फ़ील्ड | अर्थ | +| --- | --- | +| `provider` | `typesafe`, `openrouter`, `vercel`, `cloudflare` या `custom` — या `failproofai`, जिसकी कुंजी इस फ़ाइल के बजाय FailproofAI क्लाउड कनेक्शन से आती है (देखें [FailproofAI क्लाउड के माध्यम से Jev](/hi/reference/jev-cloud))। | +| `apiKey` | `Authorization: Bearer ` के रूप में भेजा गया। | +| `baseUrl` | `custom` के लिए आवश्यक; अन्यथा प्रदाता के API आधार को प्रतिस्थापित करता है। `https` होना चाहिए। सादा `http` को `localhost` के लिए केवल observe मोड के साथ स्वीकार किया जाता है: कोई भी कुंजी एक स्थानीय पोर्ट को प्रमाणित नहीं करता है, इसलिए जबकि आपका प्रॉक्सी बंद है मशीन पर कोई भी प्रक्रिया, मूल्यांकन किए जा रहे एजेंट सहित, इसके स्थान पर उत्तर दे सकती है। | +| `accountId` | Cloudflare केवल: 32 लोअरकेस हेक्स वर्ण। | +| `model` | प्रदाता के डिफ़ॉल्ट मॉडल id को प्रतिस्थापित करता है। एक संस्करणबद्ध id को Jev 1.13 का नाम देना चाहिए। एक API कुंजी की तरह आकार दिया गया मान अस्वीकार किया जाता है (और वापस नहीं दोहराया जाता है), इसलिए `--model` में पेस्ट की गई एक कुंजी कभी मॉडल के रूप में संग्रहीत या भेजी नहीं जाती है। | +| `timeoutMs` | एक टूल कॉल regex परिणाम का उपयोग करने से पहले Jev के लिए कितने समय तक प्रतीक्षा करता है। 100–10000, डिफ़ॉल्ट 3000। | +| `mode` | `enforce` (डिफ़ॉल्ट), `observe`, या `off` (कॉन्फ़िग को रखें, कोई Jev नहीं चलाएँ)। | + +तीन नियम इसकी सुरक्षा करते हैं: + +- **केवल मालिक।** इसे अनुमतियों `0600` के साथ लिखा जाता है। एक कॉपी जो कोई अन्य उपयोगकर्ता या समूह पढ़ या लिख सकता है **अस्वीकार किया जाता है**, और हुक्स regex में वापस जाते हैं जब तक आप `chmod 600 ~/.failproofai/jev.json` नहीं चलाते या `setup` फिर से नहीं करते। निर्देशिका भी जांची जाती है: `~/.failproofai` किसी और द्वारा **लिखने योग्य** नहीं होना चाहिए, क्योंकि जो कोई भी वहाँ लिख सकता है वह अपनी स्वयं की अनुमतियों के बावजूद फ़ाइल को प्रतिस्थापित कर सकता है। `setup` यदि वह उन्हें पाता है तो उन लिखने बिट्स को बंद कर देता है। `failproofai jev status` कहता है जब कॉन्फ़िग अस्वीकार कर दिया गया है और एंडपॉइंट दिखाता है जिसे फ़ाइल नाम देती है: कोई और इसे बदल सकता है, इसलिए `chmod` करने से पहले जाँचें कि यह आपका है। `setup` को इस तरह की फ़ाइल पर फिर से चलाना इसकी संग्रहीत कुंजी को केवल प्रदाता के अपने API में ले जाता है; किसी अन्य एंडपॉइंट को इसे नाम देने के लिए कुंजी फिर से चाहिए (`--key-stdin`), या `--base-url default` से अनुरोधों को प्रदाता में वापस भेजने के लिए। +- **केवल वैश्विक।** एक रिपॉजिटरी Jev को चालू नहीं कर सकता है, इसे किसी अन्य एंडपॉइंट की ओर इंगित कर सकता है या इसके मॉडल को चुन सकता है: एक `.failproofai/jev.json` प्रोजेक्ट के अंदर अनदेखी की जाती है, और प्रदाता, URL, मॉडल और खाता id केवल उस फ़ाइल से पढ़े जाते हैं — कभी पर्यावरण से नहीं, जिसे रिपॉजिटरी के एजेंट सेटिंग्स सेट कर सकते हैं। (`FAILPROOFAI_HOME` इसके चारों ओर नहीं है: यह पूरी failproofai निर्देशिका, आपकी नीतियों सहित, स्थानांतरित करता है, बजाय अकेले Jev को पुनर्निर्देशित करने के।) +- **केवल कुंजी पर्यावरण से आ सकती है।** यदि फ़ाइल के पास कोई `apiKey` नहीं है, `FAILPROOFAI_JEV_API_KEY` उस सेशन के लिए इसकी आपूर्ति करता है (`setup --key-from-env` ऐसी फ़ाइल लिखता है)। यह कभी फ़ाइल द्वारा रखी गई कुंजी को प्रतिस्थापित नहीं करता है, और यह बिना फ़ाइल के Jev को चालू नहीं कर सकता है। जहाँ चर सेट नहीं है, Jev बस उस शेल के लिए बंद है: `failproofai jev status` कहता है, 0 से बाहर निकलता है और कॉन्फ़िग को अकेला छोड़ देता है (`status --json` रिपोर्ट करता है `"status": "key-missing"` के साथ `"reason": "no-env-key"`)। `failproofaid` डेमन आपके शेल के पर्यावरण को नहीं देखता है, इसलिए एक मशीन पर `failproofai config` के साथ सेट अप, कुंजी को फ़ाइल में रखें। + +## कौन सा Jev उत्तर देता है + +Failproof AI के निर्णय थ्रेसहोल्ड Jev 1.13 पर कैलिब्रेट किए गए थे, इसलिए एक उत्तर का उपयोग केवल तब किया जाता है जब यह उस परिवार से आता है: `jev-1.13.x`, या OpenRouter का `typesafe/jev-1.13-`। जहाँ एक प्रदाता केवल एक उपनाम से Jev को नाम देता है और कोई संस्करण रिपोर्ट नहीं करता है (Vercel, और Cloudflare जब यह नहीं कहता है), उत्तर का उपयोग किया जाता है और अनुत्पादित के रूप में दर्ज किया जाता है। एक `custom` एंडपॉइंट को रिपोर्ट करना चाहिए कि किस मॉडल ने उत्तर दिया; एक अपवाद है एक अनपेक्षित `--model` नाम जो आपने इसके लिए कॉन्फ़िगर किया है, जो, प्रतिध्वनित, अनुत्पादित के रूप में दर्ज किया जाता है उसी तरह। किसी अन्य संस्करण की रिपोर्ट देने वाला उत्तर, या `custom` उत्तर जो कोई नहीं देता है, का उपयोग नहीं किया जाता है: वह कॉल `model-mismatch` कारण के साथ regex में वापस जाता है। + +## जब Jev उत्तर नहीं दे सकता + +इनमें से प्रत्येक उस कॉल के लिए regex परिणाम में वापस जाता है और इसके कारण के साथ दर्ज किया जाता है, जिसे `failproofai jev status` कुल करता है: + +| कारण | कारण | +| --- | --- | +| `timeout` | `timeoutMs` के भीतर कोई उत्तर नहीं। | +| `http-429` | प्रदाता ने कुंजी को दर सीमित किया। | +| `rate-limited` | Failproof AI की अपनी लिमिटर ने कॉल को भेजने से पहले रोक दिया: 5 अनुरोध प्रति सेकंड, 5 तक के बर्स्ट में, और प्रदाता उत्तर के तुरंत बाद कोई नहीं `429`। प्रदाता नहीं। | +| `http-500`, `http-502`, `http-503`, … | प्रदाता पर एक सर्वर त्रुटि। सटीक स्थिति दर्ज की जाती है। | +| `out-of-credits` | HTTP 402: प्रदाता खाते के पास कोई क्रेडिट नहीं बचा है। | +| `provider-refused` | Cloudflare से HTTP 402 "Model execution failed (Payment error)" पढ़ता है: प्रदाता ने इस अनुरोध पर मॉडल को चलाने से इंकार कर दिया। आमतौर पर बिलिंग नहीं, इसलिए टॉपिंग अप इसे स्थानांतरित नहीं करेगा। | +| `http-401`, `http-403` | कुंजी को अस्वीकार किया गया। | +| `http-404` | `/systemone` पर कुछ नहीं परोसा जाता है, इसलिए बेस URL गलत है — `/systemone` इसे जोड़ा जाता है, और हर प्रदाता अपनी संस्करण रूट पर इसे परोसता है। `failproofai jev models` दिखाता है कि एंडपॉइंट क्या परोसता है। | +| `network` | एंडपॉइंट तक नहीं पहुँचा जा सका। | +| `http-301`, `http-302`, `http-307`, `http-308` | एंडपॉइंट एक रीडायरेक्ट के साथ उत्तर दिया। रीडायरेक्ट कभी अनुसरण नहीं किए जाते हैं, इसलिए उत्तर केवल आपकी कॉन्फ़िग में URL से आता है; `--base-url` को अंतिम URL पर सेट करें। | +| `malformed` | एंडपॉइंट उत्तर दिया, लेकिन Jev उत्तर के साथ नहीं — एक बॉडी जो JSON नहीं है, या एक बिना उत्तर के। | +| `cloudflare-error`, `cloudflare-incomplete` | Cloudflare के लिफाफे ने एक विफलता, या एक कार्य जो समाप्त नहीं हुआ था, की रिपोर्ट की। | +| `model-mismatch` | Jev संस्करण 1.13 के अलावा उत्तर दिया, या `custom` एंडपॉइंट ने नहीं कहा कि किस मॉडल ने उत्तर दिया। | +| `request-cut` | **कोई आउटेज नहीं।** Jev उत्तर दिया; इसे केवल कॉल का एक हिस्सा दिखाया गया, इसलिए इसका उत्तर कुछ नहीं साफ किया। [जब Jev उत्तर दिया, लेकिन पूरी कॉल पर नहीं](#when-jev-answered-but-not-on-the-whole-call) देखें। | + +`failproofai jev status` कुछ दुर्लभ कारण भी दिखा सकता है, जैसे `upstream-error` (उत्तर प्रदाता की अपनी त्रुटि ले गया) या `config`, और किसी भी कारण को कुल करता है जिसे वह नाम नहीं दे सकता `other`। + +`request-cut` इस तालिका में है क्योंकि `failproofai jev status` इसे बाकी के साथ कुल करता है, और क्योंकि यह भी हर अस्वीकृति को खड़ा करता है। यह यहाँ एकमात्र कारण है जो आपके प्रदाता के बारे में कुछ नहीं कहता है: अनुरोध पहुँचा और Jev ने इसका उत्तर दिया। ऊपर के हर पंक्ति के विपरीत, वह उत्तर अभी भी गिनती करता है — Jev का अपनी अस्वीकृति या चेतावनी regex परिणाम के ऊपर लागू होता है बजाय इसे छोड़ने के। तो उनका एक रन कॉल मतलब है जो मूल्यांकनकर्ता तक पहुँच रहे हैं बहुत बड़े पूरी तरह भेजने के लिए, कि आपका एंडपॉइंट अस्वस्थ नहीं है, और क्रेडिट को टॉप अप करना या URL को बदलना संख्या को स्थानांतरित नहीं करेगा। + +## जब Jev उत्तर दिया, लेकिन पूरी कॉल पर नहीं + +दो और चीजें हो सकती हैं, और दोनों Jev उत्तर देने में विफल नहीं हैं। दोनों इस बारे में हैं कि कॉल का कितना, या बातचीत का कितना, एक अनुरोध में फिट हुआ। + +**कॉल का एक हिस्सा अपने आप में फिट नहीं हुआ।** एक टूल कॉल एक निश्चित बजट के अंदर भेजा जाता है, और एक बड़ा — एक बहुत बड़ा `Write`, एक विशाल MCP बॉडी, एक कमांड कैप तक पैड किया गया — जो फिट हुआ के साथ भेजा जाता है। Jev अभी भी उत्तर देता है, और इसका उत्तर अभी भी गिनती करता है: इसकी अपनी अस्वीकृति या चेतावनी सामान्य रूप से लागू होती है। यह क्या नहीं कर सकता है **स्पष्ट** कुछ, क्योंकि कॉल के एक हिस्से पर दिया गया निर्णय कॉल पर निर्णय नहीं है। तो हर नीति अस्वीकृति खड़ी होती है, और कॉल `request-cut` कारण के साथ फॉलबैक के रूप में दर्ज किया जाता है, जिसे `failproofai jev status` ऊपर कारणों के साथ कुल करता है। नियम यह आपको देता है: कॉल को बड़ा बनाना इसकी निकासी की कीमत दे सकता है, और कभी नहीं एक खरीद सकता है। + +**एक संदेश फिट नहीं हुआ।** एक लंबा संकेत आपने पेस्ट किया, एजेंट का आखिरी संदेश, या एक संकेत इस मूल्यांकनकर्ता के अपने स्टोर ने पहले से ही कैप किया। **कुछ नहीं बदलता है**: कॉल का निर्णय, साफ और दर्ज किया जाता है बिल्कुल किसी और की तरह, और यह फॉलबैक के रूप में गणना नहीं की जाती है। जो आप टाइप करते हैं उसकी लंबाई कभी निर्णय का फैसला नहीं करता है, और एक कट सहमति को निर्माण नहीं कर सकता है: जहाँ एक संकेत पहले से ही कैप आया, "आपने यह नहीं माँगा" निष्कर्ष निकालने योग्य होने से बदल जाता है इससे बिल्कुल, बजाय एक बन जाए। + +दो के बीच की रेखा कौन ने पाठ लिखा है। कॉल एजेंट का है, और एक नियम जो इसकी लंबाई को गंभीरता से घटाने देता है एक नियम है जो एजेंट उपयोग कर सकता है; आपका संकेत आपका है, और इसकी लंबाई को केवल एक संकेत के रूप में मानना केवल कभी एक स्पेक या स्टैक ट्रेस पेस्ट करने को दंडित किया। + +## मशीन छोड़ क्या जाता है + +प्रत्येक टूल कॉल Jev मूल्यांकन के लिए, एक अनुरोध आपके प्रदाता को जाता है, ले जा रहे: + +- टूल कॉल अपने आप में, गुप्त जैसे API कुंजी, वाहक टोकन और `KEY=` असाइनमेंट के साथ संशोधन; +- हाल के संकेत आपने टाइप किए, आपके एजेंट के हार्नेस ने जोड़ा हुआ पाठ हटा दिया; +- आपके नवीनतम संकेत से पहले एजेंट का आखिरी संदेश, एजेंट-लिखित के रूप में लेबल किया गया; +- स्थानीय रूप से गणना की गई तथ्य, जैसे क्या एक पथ प्रोजेक्ट के अंदर है — एक जो सेशन पहली समीक्षित कॉल पर था, [सेशन के लिए पिन किया गया](/hi/reference/jev-intent#the-project-root) — और वर्तमान git शाखा। + +यह केवल आपकी कॉन्फ़िग में एंडपॉइंट को जाता है, आपकी कुंजी के तहत। + +## इसे बंद करें + +```bash +failproofai jev remove +``` + +यह `~/.failproofai/jev.json` को हटाता है। अगली टूल कॉल से, हुक्स regex नीतियों को चलाते हैं बिल्कुल पहले की तरह। `~/.failproofai/state/semantic/` के तहत प्रति-सेशन स्टोर (`sessions/` में रिकॉर्ड किए गए संकेत, `roots/` में प्रोजेक्ट रूट) जगह में रहते हैं और उम्र बाहर। Jev पूछना बंद करने के लिए लेकिन कॉन्फ़िग रखने के लिए, `failproofai jev setup --mode off` का उपयोग करें। + +## कमांड संदर्भ + +| कमांड | परिणाम | +| --- | --- | +| `failproofai jev --url --key-stdin` | एक कमांड में इसे कॉन्फ़िगर करें; प्रदाता URL के होस्ट से आता है | +| `failproofai jev --url --token ` | समान, कमांड लाइन पर कुंजी के साथ — आपका इतिहास और प्रक्रिया सूची इसे देखती है | +| `failproofai jev setup --provider --key-stdin` | stdin पर पाइप की गई कुंजी से कॉन्फ़िग लिखें | +| `failproofai jev setup --provider ` | समान, मुखौटा प्रॉम्प्ट पर कुंजी के लिए पूछ रहे हैं | +| `failproofai jev setup --key-from-env` | कोई कुंजी संग्रहीत न करें; प्रति सेशन `FAILPROOFAI_JEV_API_KEY` पढ़ें | +| `failproofai jev setup --mode observe` | मोड स्विच (`enforce`, `observe` या `off`), संग्रहीत कुंजी को रखते हुए | +| `failproofai jev setup --model ` / `--base-url ` | मॉडल या API आधार को ओवरराइड करें; `default` ओवरराइड को साफ करता है | +| `failproofai jev setup --timeout-ms ` | प्रति-कॉल बजट बदलें | +| `failproofai jev status [--json]` | कॉन्फ़िगरेशन, अनुमतियाँ और हाल की गतिविधि; कभी कुंजी नहीं | +| `failproofai jev test [--json]` | एक लाइव अनुरोध: विलंबता और संस्करण जो उत्तर दिया | +| `failproofai jev models [--provider ] [--url ] [--json]` | मॉडल id कि एंडपॉइंट का `/models` रिपोर्ट करता है, कॉन्फ़िगर किए गए को चिह्नित करता है | +| `failproofai jev remove` | कॉन्फ़िग को हटाएँ; Jev बंद है | \ No newline at end of file diff --git a/docs/hi/reference/jev.mdx b/docs/hi/reference/jev.mdx new file mode 100644 index 000000000..a7d8eb066 --- /dev/null +++ b/docs/hi/reference/jev.mdx @@ -0,0 +1,22 @@ +--- +title: "Jev integration reference" +description: "Configuration, providers, keys, request data, और failure behavior Jev के लिए।" +icon: "braces" +--- + +Failproof AI में Jev के दो उपयोग हैं: + +| उपयोग | कब चलता है | यह क्या रिटर्न करता है | यहाँ से शुरू करें | +| --- | --- | --- | --- | +| Session evaluation | एक session समाप्त होने के बाद | एक fixed-answer question के लिए स्कोर | [Jev evaluations](/hi/evaluations/jev) | +| Tool-call policy review | एक gated tool call चलने से पहले | installed policies के साथ एक verdict | [Jev policies](/hi/policies/jev) | + +## संदर्भ पृष्ठ + +| विषय | विवरण | +| --- | --- | +| [Evaluation questions](/hi/reference/jev-evaluations) | Boolean और ordered-score criteria, results, limits, और backfill। | +| [Provider comparison और own-key setup](/hi/reference/jev-providers) | TypeSafe, OpenRouter, Vercel, Cloudflare, और custom endpoints; URL inference, model IDs, `jev.json`, modes, और fallback codes। | +| [FailproofAI Cloud route](/hi/reference/jev-cloud) | Machine-key permissions, automatic observe setup, usage limits, connection state, और data handling। | + +स्थानीय CLI commands को [Failproof AI CLI reference](/hi/reference/failproof-cli) में सूचीबद्ध किया गया है। [local dashboard reference](/hi/reference/local-dashboard#set-up-jev) इसकी Jev settings और activity view का वर्णन करता है। \ No newline at end of file diff --git a/docs/hi/sessions/sentiment.mdx b/docs/hi/sessions/sentiment.mdx new file mode 100644 index 000000000..df49605f9 --- /dev/null +++ b/docs/hi/sessions/sentiment.mdx @@ -0,0 +1,43 @@ +--- +title: "भावनात्मक विश्लेषण" +description: "Jev sentiment स्कोर के साथ निराश, भ्रमित और सुधारक संदेश खोजें।" +icon: "smile" +--- + +Jev प्रत्येक संदेश को जो एक व्यक्ति आपके agents को भेजता है, चार भावनाओं के लिए 0 से 100 तक स्कोर देता है — **angry**, **frustrated**, **happy** और **confused** — और agent के प्रदर्शन के बारे में तीन संकेत: + +- **Correcting**: व्यक्ति कहता है कि agent से कुछ गलत हुआ। +- **Resolved**: व्यक्ति पुष्टि करता है कि agent ने उनकी समस्या को हल कर दिया। +- **Doubtful**: व्यक्ति सवाल उठाता है कि क्या agent का जवाब सही है, या क्या इसने वास्तव में काम किया। + +भावनात्मक विश्लेषण का उपयोग उन बातचीतों को खोजने के लिए करें जहां लोग धैर्य खो रहे हैं, agents जिन्हें वे बार-बार ठीक कर रहे हैं, और उत्तर जो अच्छी तरह से काम आते हैं। यह built-in Jev स्कोरिंग है; आपको कोई मूल्यांकन बनाने की आवश्यकता नहीं है। अपने स्वयं के fixed-answer प्रश्न के लिए, [एक Jev eval बनाएं](/hi/evaluations/jev)। + + + Sentiment तब तक बंद रहता है जब तक कोई admin इसे संगठन के लिए चालू नहीं करता। Jev प्रत्येक संदेश के लिए एक स्कोरिंग अनुरोध करता है और उस संदेश को agent के उत्तर के साथ प्राप्त करता है। स्कोरिंग आपके संगठन के model बजट का उपयोग करती है। + + +## इसे चालू करें + +1. **Administration → Settings** पर जाएं। +2. **Human input sentiment** के अंतर्गत, इसे **on** में स्विच करें और सहेजें। + +पिछले दिन के संदेशों को पहले स्कोर किया जाता है। उसके बाद, नए संदेशों को आने के एक-दो मिनट के भीतर स्कोर किया जाता है। + +## समीक्षा के लिए एक बातचीत खोजें + +**Observe → Sentiment** खोलें। समय, environment, agent, या session ID के अनुसार फ़िल्टर करें। header में संदेशों और sessions की गणना होती है, यह दिखाता है कि कितने संदेश **flagged** हैं, और शीर्ष संकेत का नाम बताता है। एक संदेश flagged होता है जब angry, frustrated, correcting, confused, या doubtful स्कोर 100 में से 35 तक पहुंचता है। + +![Sentiment dashboard जो संदेश और session की गणना, flagged संदेश, और समय के साथ Jev स्कोर दिखा रहा है।](/images/dashboard/sentiment-overview.png) + +संकेतों की तुलना करने के लिए **Score over time** का उपयोग करें। दिखाने के लिए स्कोर चुनें, फिर उस समय बकेट के संदेशों को देखने के लिए एक बिंदु चुनें। **By agent** तालिका दिखाती है कि एक संकेत कहां केंद्रित है। **Messages** में, सबसे मजबूत negative स्कोर के अनुसार सॉर्ट करें या एक एकल स्कोर चुनें। निर्णय लेने से पहले आसपास की बातचीत को पढ़ने के लिए किसी संदेश को इसके session में खोलें कि क्या विफल हुआ। + +![Sentiment संदेश सूची जो सबसे मजबूत negative स्कोर के अनुसार सॉर्ट की गई है, प्रत्येक source session के लिए एक लिंक के साथ।](/images/dashboard/sentiment-messages.png) + +## कौन से संदेश स्कोर किए जाते हैं + +केवल वे संदेश जो एक व्यक्ति ने लिखे: + +- संदेश जो आपके custom agents SDK के साथ human input के रूप में record करते हैं। +- Claude Code, Codex, OpenCode, pi, Hermes और OpenClaw में टाइप किए गए prompts, जब session transcripts भेजे जाते हैं (डिफ़ॉल्ट)। Scheduled jobs, injected instructions, sub-agent hand-offs और अन्य text जो agent के स्वयं के runtime लिखते हैं, स्कोर नहीं किए जाते। और न ही non-interactive runs जैसे `claude -p`, `codex exec` और `hermes -z`: एक script ने वे prompts लिखे, व्यक्ति ने नहीं। + +स्कोरिंग व्यक्ति के अपने शब्दों का न्याय करती है। एक संक्षिप्त, सीधा निर्देश जैसे "fix it" को गुस्से के रूप में नहीं गिना जाता, और एक सवाल पूछना confusion के रूप में नहीं गिना जाता। एक नया अनुरोध correction नहीं है, और अकेले धन्यवाद resolved के रूप में नहीं गिने जाते। \ No newline at end of file diff --git a/docs/hi/start/use-jev.mdx b/docs/hi/start/use-jev.mdx new file mode 100644 index 000000000..4ffc792e5 --- /dev/null +++ b/docs/hi/start/use-jev.mdx @@ -0,0 +1,63 @@ +--- +title: "Jev का उपयोग करें" +description: "पूर्ण सत्रों के लिए Jev मूल्यांकन या लाइव टूल-कॉल समीक्षा के लिए Jev नीतियाँ सेट अप करें।" +icon: "sparkles" +--- + +Jev एक एजेंट रन में दो बिंदुओं पर मदद करता है: एक समाप्त सत्र को ज्ञात उत्तरों के मुकाबले स्कोर करना, या आपने एजेंट को क्या करने के लिए कहा इसके संदर्भ में एक टूल कॉल की समीक्षा करना। + + + + Jev eval का उपयोग तब करें जब एक पूर्ण सत्र को कुछ ज्ञात उत्तरों वाले प्रश्न के मुकाबले स्कोर किया जा सके, जैसे कि "क्या ग्राहक ने रिफंड मांगा? हाँ या नहीं का उत्तर दें।" यह आपको सत्रों के पार पैटर्न खोजने में मदद करता है। + + ## एक eval बनाएं + + Cloud डैशबोर्ड में, **Analyze → eval authoring → new eval** खोलें। एक निश्चित-उत्तर प्रश्न दर्ज करें, **draft** चुनें, और जांचें कि इसने एक classifier स्कोर चुना है। [इसे परीक्षण करें](/hi/evaluations/test) वास्तविक सत्रों पर, फिर इसे तैनात करें। + + ![साझा eval authoring फॉर्म जहां आप एक प्रश्न का वर्णन करते हैं, ड्राफ्ट की समीक्षा करते हैं, और इसे तैनात करते हैं। यह स्क्रीनशॉट एक कोड ड्राफ्ट दिखाता है; Jev के लिए एक निश्चित-उत्तर प्रश्न का उपयोग करें।](/images/dashboard/eval-authoring-draft.png) + + ## स्कोर पढ़ें + + एक नया सत्र पूर्ण होने के बाद, **Observe → Evaluations** खोलें या Cloud CLI का उपयोग करें: + + ```bash + fp evals --since 7d + fp evals --aggregate --since 7d + ``` + + CLI स्कोर पढ़ता है; Jev eval बनाना वर्तमान में डैशबोर्ड का उपयोग करता है। प्रश्न प्रकार और उदाहरणों के लिए [Jev evaluations](/hi/evaluations/jev) देखें। + + + Jev policy समीक्षा का उपयोग तब करें जब एक स्ट्रिंग-मिलान नीति को यह तय करने के लिए आपके अनुरोध के संदर्भ की आवश्यकता हो कि क्या एक टूल कॉल सुरक्षित है। **observe** मोड में शुरू करें ताकि आप Jev के उत्तरों का निरीक्षण कर सकें जबकि आपकी स्थापित नीतियां अभी भी प्रत्येक कॉल को तय करती हैं। + + Jev की जांचें एक पैक से आती हैं; Failproof AI कोई भी नहीं भेजता। जब तक आप उन्हें स्थापित नहीं करते, Jev कुछ भी नहीं पूछता, भले ही यह कॉन्फ़िगर किया गया हो: + + ```bash + failproofai policies add FailproofAI/jev-policies + ``` + + ## Cloud Jev सेट अप करें + + Cloud डैशबोर्ड में, **Administration → Keys** खोलें और **machine** प्रीसेट के साथ एक कुंजी बनाएं। इसे [quickstart](/hi/start/quickstart) में दिखाए गए अनुसार `failproofai config` के साथ उपयोग करें। बिना मौजूदा Jev कॉन्फ़िगरेशन वाली मशीन पर, यह Cloud Jev को observe मोड में सक्षम करता है। कनेक्शन जांचें: + + ```bash + failproofai jev status + failproofai jev test + ``` + + ## अपना स्वयं का endpoint उपयोग करें + + स्थानीय डैशबोर्ड में, **Settings → Jev** खोलें। प्रदाता चुनें, इसका टोकन पेस्ट करें, **observe** चुनें, और Jev को चालू करें। + + ![स्थानीय Jev सेटिंग्स पैनल एक प्रदाता, टोकन फील्ड, और observe मोड चुना हुआ के साथ।](/images/dashboard/jev-settings.png) + + या टर्मिनल से अपने endpoint को कॉन्फ़िगर और परीक्षण करें: + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key + failproofai jev test + ``` + + एक hooked एजेंट को `README.md` पर अपने फाइल-रीडिंग टूल का उपयोग करने के लिए कहें। पुष्टि करें कि टूल कॉल सत्र में दिखाई देता है, फिर स्थानीय डैशबोर्ड में **Policies → Activity** के तहत इसका निरीक्षण करें। एक बार observe परिणाम सही दिखने लगें, [Jev policies](/hi/policies/jev) समझाता है कि कब enforce करना है। प्रदाता विवरण और कॉन्फ़िगरेशन के लिए, [integration reference](/hi/reference/jev) देखें। + + \ No newline at end of file diff --git a/docs/i18n/README.ar.md b/docs/i18n/README.ar.md index 0b656ee72..d7b546bd2 100644 --- a/docs/i18n/README.ar.md +++ b/docs/i18n/README.ar.md @@ -11,6 +11,7 @@ failproof ai FailproofAI%2Ffailproofai | Trendshift +FailproofAI%2Ffailproofai | Trendshift [![npm](https://img.shields.io/npm/v/failproofai?style=flat-square&color=CB3837)](https://www.npmjs.com/package/failproofai) [![CI](https://img.shields.io/github/actions/workflow/status/failproofai/failproofai/ci.yml?branch=main&style=flat-square&label=CI)](https://github.com/failproofai/failproofai/actions) diff --git a/docs/i18n/README.de.md b/docs/i18n/README.de.md index 346a3fdcd..961696967 100644 --- a/docs/i18n/README.de.md +++ b/docs/i18n/README.de.md @@ -9,6 +9,7 @@ failproof ai FailproofAI%2Ffailproofai | Trendshift +FailproofAI%2Ffailproofai | Trendshift [![npm](https://img.shields.io/npm/v/failproofai?style=flat-square&color=CB3837)](https://www.npmjs.com/package/failproofai) [![CI](https://img.shields.io/github/actions/workflow/status/failproofai/failproofai/ci.yml?branch=main&style=flat-square&label=CI)](https://github.com/failproofai/failproofai/actions) diff --git a/docs/i18n/README.es.md b/docs/i18n/README.es.md index 7e8820cc3..3afb742f6 100644 --- a/docs/i18n/README.es.md +++ b/docs/i18n/README.es.md @@ -9,6 +9,7 @@ failproof ai FailproofAI%2Ffailproofai | Trendshift +FailproofAI%2Ffailproofai | Trendshift [![npm](https://img.shields.io/npm/v/failproofai?style=flat-square&color=CB3837)](https://www.npmjs.com/package/failproofai) [![CI](https://img.shields.io/github/actions/workflow/status/failproofai/failproofai/ci.yml?branch=main&style=flat-square&label=CI)](https://github.com/failproofai/failproofai/actions) diff --git a/docs/i18n/README.fr.md b/docs/i18n/README.fr.md index 55980def5..e844719a0 100644 --- a/docs/i18n/README.fr.md +++ b/docs/i18n/README.fr.md @@ -9,6 +9,7 @@ failproof ai FailproofAI%2Ffailproofai | Trendshift +FailproofAI%2Ffailproofai | Trendshift [![npm](https://img.shields.io/npm/v/failproofai?style=flat-square&color=CB3837)](https://www.npmjs.com/package/failproofai) [![CI](https://img.shields.io/github/actions/workflow/status/failproofai/failproofai/ci.yml?branch=main&style=flat-square&label=CI)](https://github.com/failproofai/failproofai/actions) diff --git a/docs/i18n/README.he.md b/docs/i18n/README.he.md index b505a76c7..c60d35c7a 100644 --- a/docs/i18n/README.he.md +++ b/docs/i18n/README.he.md @@ -11,6 +11,7 @@ failproof ai FailproofAI%2Ffailproofai | Trendshift +FailproofAI%2Ffailproofai | Trendshift [![npm](https://img.shields.io/npm/v/failproofai?style=flat-square&color=CB3837)](https://www.npmjs.com/package/failproofai) [![CI](https://img.shields.io/github/actions/workflow/status/failproofai/failproofai/ci.yml?branch=main&style=flat-square&label=CI)](https://github.com/failproofai/failproofai/actions) diff --git a/docs/i18n/README.hi.md b/docs/i18n/README.hi.md index 6856d3ebe..5899f6063 100644 --- a/docs/i18n/README.hi.md +++ b/docs/i18n/README.hi.md @@ -9,6 +9,7 @@ failproof ai FailproofAI%2Ffailproofai | Trendshift +FailproofAI%2Ffailproofai | Trendshift [![npm](https://img.shields.io/npm/v/failproofai?style=flat-square&color=CB3837)](https://www.npmjs.com/package/failproofai) [![CI](https://img.shields.io/github/actions/workflow/status/failproofai/failproofai/ci.yml?branch=main&style=flat-square&label=CI)](https://github.com/failproofai/failproofai/actions) diff --git a/docs/i18n/README.it.md b/docs/i18n/README.it.md index 095096a22..cb9f6efb5 100644 --- a/docs/i18n/README.it.md +++ b/docs/i18n/README.it.md @@ -9,6 +9,7 @@ failproof ai FailproofAI%2Ffailproofai | Trendshift +FailproofAI%2Ffailproofai | Trendshift [![npm](https://img.shields.io/npm/v/failproofai?style=flat-square&color=CB3837)](https://www.npmjs.com/package/failproofai) [![CI](https://img.shields.io/github/actions/workflow/status/failproofai/failproofai/ci.yml?branch=main&style=flat-square&label=CI)](https://github.com/failproofai/failproofai/actions) diff --git a/docs/i18n/README.ja.md b/docs/i18n/README.ja.md index 75161bbb8..01905eb45 100644 --- a/docs/i18n/README.ja.md +++ b/docs/i18n/README.ja.md @@ -9,6 +9,7 @@ failproof ai FailproofAI%2Ffailproofai | Trendshift +FailproofAI%2Ffailproofai | Trendshift [![npm](https://img.shields.io/npm/v/failproofai?style=flat-square&color=CB3837)](https://www.npmjs.com/package/failproofai) [![CI](https://img.shields.io/github/actions/workflow/status/failproofai/failproofai/ci.yml?branch=main&style=flat-square&label=CI)](https://github.com/failproofai/failproofai/actions) diff --git a/docs/i18n/README.ko.md b/docs/i18n/README.ko.md index b6a3e9df9..3093170c5 100644 --- a/docs/i18n/README.ko.md +++ b/docs/i18n/README.ko.md @@ -9,6 +9,7 @@ failproof ai FailproofAI%2Ffailproofai | Trendshift +FailproofAI%2Ffailproofai | Trendshift [![npm](https://img.shields.io/npm/v/failproofai?style=flat-square&color=CB3837)](https://www.npmjs.com/package/failproofai) [![CI](https://img.shields.io/github/actions/workflow/status/failproofai/failproofai/ci.yml?branch=main&style=flat-square&label=CI)](https://github.com/failproofai/failproofai/actions) diff --git a/docs/i18n/README.pt-br.md b/docs/i18n/README.pt-br.md index fdaca1079..7ac7fa1d0 100644 --- a/docs/i18n/README.pt-br.md +++ b/docs/i18n/README.pt-br.md @@ -9,6 +9,7 @@ failproof ai FailproofAI%2Ffailproofai | Trendshift +FailproofAI%2Ffailproofai | Trendshift [![npm](https://img.shields.io/npm/v/failproofai?style=flat-square&color=CB3837)](https://www.npmjs.com/package/failproofai) [![CI](https://img.shields.io/github/actions/workflow/status/failproofai/failproofai/ci.yml?branch=main&style=flat-square&label=CI)](https://github.com/failproofai/failproofai/actions) diff --git a/docs/i18n/README.ru.md b/docs/i18n/README.ru.md index e60d1e03c..1f2e3c314 100644 --- a/docs/i18n/README.ru.md +++ b/docs/i18n/README.ru.md @@ -9,6 +9,7 @@ failproof ai FailproofAI%2Ffailproofai | Trendshift +FailproofAI%2Ffailproofai | Trendshift [![npm](https://img.shields.io/npm/v/failproofai?style=flat-square&color=CB3837)](https://www.npmjs.com/package/failproofai) [![CI](https://img.shields.io/github/actions/workflow/status/failproofai/failproofai/ci.yml?branch=main&style=flat-square&label=CI)](https://github.com/failproofai/failproofai/actions) diff --git a/docs/i18n/README.tr.md b/docs/i18n/README.tr.md index 5f86e6f7b..18c3a7205 100644 --- a/docs/i18n/README.tr.md +++ b/docs/i18n/README.tr.md @@ -9,6 +9,7 @@ failproof ai FailproofAI%2Ffailproofai | Trendshift +FailproofAI%2Ffailproofai | Trendshift [![npm](https://img.shields.io/npm/v/failproofai?style=flat-square&color=CB3837)](https://www.npmjs.com/package/failproofai) [![CI](https://img.shields.io/github/actions/workflow/status/failproofai/failproofai/ci.yml?branch=main&style=flat-square&label=CI)](https://github.com/failproofai/failproofai/actions) diff --git a/docs/i18n/README.vi.md b/docs/i18n/README.vi.md index c7933dc46..6be4b4b83 100644 --- a/docs/i18n/README.vi.md +++ b/docs/i18n/README.vi.md @@ -9,6 +9,7 @@ failproof ai FailproofAI%2Ffailproofai | Trendshift +FailproofAI%2Ffailproofai | Trendshift [![npm](https://img.shields.io/npm/v/failproofai?style=flat-square&color=CB3837)](https://www.npmjs.com/package/failproofai) [![CI](https://img.shields.io/github/actions/workflow/status/failproofai/failproofai/ci.yml?branch=main&style=flat-square&label=CI)](https://github.com/failproofai/failproofai/actions) diff --git a/docs/i18n/README.zh.md b/docs/i18n/README.zh.md index e02269cc0..92f31d489 100644 --- a/docs/i18n/README.zh.md +++ b/docs/i18n/README.zh.md @@ -9,6 +9,7 @@ failproof ai FailproofAI%2Ffailproofai | Trendshift +FailproofAI%2Ffailproofai | Trendshift [![npm](https://img.shields.io/npm/v/failproofai?style=flat-square&color=CB3837)](https://www.npmjs.com/package/failproofai) [![CI](https://img.shields.io/github/actions/workflow/status/failproofai/failproofai/ci.yml?branch=main&style=flat-square&label=CI)](https://github.com/failproofai/failproofai/actions) diff --git a/docs/images/dashboard/jev-settings.png b/docs/images/dashboard/jev-settings.png new file mode 100644 index 000000000..20ab6496a Binary files /dev/null and b/docs/images/dashboard/jev-settings.png differ diff --git a/docs/images/dashboard/sentiment-messages.png b/docs/images/dashboard/sentiment-messages.png new file mode 100644 index 000000000..6d1460dcd Binary files /dev/null and b/docs/images/dashboard/sentiment-messages.png differ diff --git a/docs/images/dashboard/sentiment-overview.png b/docs/images/dashboard/sentiment-overview.png new file mode 100644 index 000000000..8984d92db Binary files /dev/null and b/docs/images/dashboard/sentiment-overview.png differ diff --git a/docs/it/evaluations/jev.mdx b/docs/it/evaluations/jev.mdx new file mode 100644 index 000000000..5bb4f7e21 --- /dev/null +++ b/docs/it/evaluations/jev.mdx @@ -0,0 +1,28 @@ +--- +title: "Valutazioni Jev" +description: "Usa Jev per valutare una sessione completata rispetto a una domanda con risposte note." +icon: "list-checks" +--- + +Una valutazione Jev legge una **sessione completata** e assegna un punteggio da 0 a 1. Usala quando la risposta è nota in anticipo, ad esempio "Il cliente ha espresso urgenza?" oppure "Quanto era frustrato il cliente?" Ti aiuta a trovare schemi tra le esecuzioni; non interrompe una chiamata di strumento. Per le decisioni prese **prima** che uno strumento venga eseguito, usa le [politiche Jev](/it/policies/jev). + +## Crearne una nel dashboard + +1. Apri **Analyze → eval authoring** e seleziona **new eval**. +2. Descrivi una domanda e le sue possibili risposte. Ad esempio: "L'agente ha promesso un rimborso prima di controllare la politica sui rimborsi? Rispondi sì o no." Seleziona **draft** e verifica che il risultato sia un punteggio di classificazione. +3. [Testala](/it/evaluations/test) su sessioni recenti, quindi [distribuiscila](/it/evaluations/deploy). Le nuove sessioni completate vengono valutate; [esegui il backfill](/it/evaluations/deploy#score-sessions-you-already-have) se hai bisogno anche della cronologia. + +![Il modulo di authoring eval condiviso, dove descrivi una domanda con risposta fissa, rivedi la bozza e distribuisci dopo i test. L'esempio mostrato è una valutazione del codice; una domanda Jev utilizza lo stesso flusso di authoring.](/images/dashboard/eval-authoring-draft.png) + +L'assistente può scegliere tra codice, classificazione Jev e un [giudice](/it/evaluations/judge). Verifica la sua scelta prima di distribuire. Jev assegna un punteggio senza ragionamento in prosa; scegli un giudice quando hai bisogno di una spiegazione. Consulta il [riferimento per le valutazioni Jev](/it/reference/jev-evaluations) per i tipi di domande e i limiti di punteggio. + +## Leggi i punteggi + +Apri **Observe → Evaluations** per tracciare il risultato per agente e ora. Da un terminale, Cloud CLI può leggere gli stessi risultati: + +```bash +fp evals --since 7d +fp evals --aggregate --since 7d +``` + +Cloud CLI legge i risultati; l'authoring e la distribuzione avvengono nel dashboard. Consulta il [riferimento Cloud CLI](/it/reference/cloud-cli#evaluations) per i filtri. \ No newline at end of file diff --git a/docs/it/evaluations/judge.mdx b/docs/it/evaluations/judge.mdx new file mode 100644 index 000000000..e90c713ba --- /dev/null +++ b/docs/it/evaluations/judge.mdx @@ -0,0 +1,91 @@ +--- +title: "Giudici LLM" +description: "Valuta le sessioni su aspetti che il codice non può misurare — correttezza, tono, se l'agente ha seguito una policy — descrivendo come dovrebbe essere fatto e lasciando che un modello legga la conversazione." +icon: "scale" +--- + +Una valutazione Python ospitata può contare e confrontare: quante chiamate a strumenti, quanti errori, quanto tempo ha impiegato una sessione. Non può dirti se una risposta era *corretta*, se una risposta era scortese, o se l'agente ha controllato una policy prima di agire. + +Un **giudice LLM** può farlo. Descrivi come dovrebbe essere fatto in linguaggio naturale, e un modello legge la sessione e restituisce un punteggio da 0 a 1 con il suo ragionamento. + + +Un giudice costa una chiamata al modello per ogni sessione su cui viene eseguito, e una valutazione del codice non costa nulla. Usa un giudice solo per domande che richiedono che la conversazione sia *compresa* — e dagli una condizione, in modo che venga eseguito solo sulle sessioni di cui la domanda si occupa effettivamente. + + +## Quale mi serve? + +| Domanda | Usa | +| --- | --- | +| Ha chiamato lo stesso strumento due volte? | codice | +| Quanti errori c'erano? | codice | +| La sessione è durata meno di 30 secondi? | codice | +| Il cliente ha espresso urgenza? | [classificatore](/it/evaluations/jev) | +| Quanto era frustrato il cliente? | [classificatore](/it/evaluations/jev) | +| La risposta era effettivamente corretta? | **giudice** | +| La risposta è stata scortese o sprezzante? | **giudice** | +| Ha controllato la policy di rimborso prima di promettere un rimborso? | **giudice** | + +La regola generale: **contabile → codice, risposte che puoi elencare in anticipo → [classificatore](/it/evaluations/jev), richiede una spiegazione → giudice.** Un giudice è quello che scrive prose su quello che ha visto; usalo quando il numero farà chiedere a qualcuno "perché?". + +Non devi decidere in anticipo. Descrivi quello che vuoi misurare e l'assistente sceglierà, poi ti dirà quale ha scelto e perché. Puoi cambiarlo. + +## Creane uno + +1. Vai a **Analyze → eval authoring** e seleziona **new eval**. +2. Descrivi quello che vuoi valutare, e seleziona **draft**. +3. Esamina i **criteri**, la **soglia**, e la **condizione**, quindi distribuisci. + +### Criteri + +Una o due frasi, scritte come requisito piuttosto che come domanda: + +> L'assistente non deve promettere o approvare un rimborso senza prima controllare la policy di rimborso. + +Sii specifico su cosa lo farebbe *fallire*. "La risposta era buona?" ti dà un numero che non significa nulla; la frase sopra ti dà uno su cui puoi agire. + +### Soglia + +Il punteggio al quale o sopra il quale la sessione passa. `0.7` è un buon punto di partenza. Il punteggio completo da 0 a 1 è sempre memorizzato, quindi la soglia decide solo pass/fail — puoi vedere la distribuzione e regolare. + +### Condizione + +La stessa condizione Python di qualsiasi altra valutazione, e qui ha molta più importanza. Senza una, il giudice viene eseguito su **ogni** sessione della tua organizzazione, con una chiamata al modello per ciascuna: + +```python +session.count("tool_use") > 0 +``` + +```python +session.agent_id == "support-bot" and session.count("error") > 0 +``` + +Il dashboard ti avverte se distribuisci un giudice senza condizione. A volte è corretto — un agente a basso volume che vuoi completamente valutato — ma dovrebbe essere una decisione consapevole, non un incidente. + +## Cosa vede il giudice + +La conversazione, come turni, più recenti per primi se la sessione è lunga: + +- quello che l'utente ha detto +- quello che l'assistente ha risposto +- **ogni strumento che l'agente ha chiamato, e cosa ha restituito quella chiamata, in ordine** + +Quest'ultima parte è quello che rende "l'ha fatto X *prima di* Y" una domanda corretta da fare. Una chiamata a uno strumento fallita viene mostrata come un fallimento, quindi "l'ha recuperato correttamente da un errore" funziona anche. + +Le sessioni molto lunghe vengono troncate per adattarsi al contesto del modello. Quando succede, il ragionamento lo dice esplicitamente — non vedrai mai un giudizio fatto su parte di una sessione presentato come fatto su tutta. + +## Leggere i risultati + +Un giudice produce un **punteggio** come qualsiasi altra valutazione con punteggio, quindi crea grafici, filtra e attiva avvisi allo stesso modo. Insieme al numero memorizza il **ragionamento** del giudice — il paragrafo che spiega quello che ha visto. Leggilo prima quando un punteggio ti sorprende; di solito è o una sessione genuinamente interessante o un segno che i criteri hanno bisogno di essere affinati. + +I punteggi sono stabili per i casi chiari ma non deterministici bit per bit. Considera un singolo punteggio al limite come un prompt per andare a leggere la sessione, non come un verdetto. + +## Limiti + +- **I test non sono ancora disponibili.** Un test in dry run non ha un'assegnazione di sessione dietro, e quell'assegnazione è quello che autorizza la spesa del tuo budget del modello — quindi non c'è nulla da addebitare per una chiamata di test. Distribuisci su una condizione ristretta e leggi i primi risultati. +- **Il backfill non è disponibile.** Fare il backfill di una valutazione del codice su mesi di cronologia è gratuito; farlo con un giudice spenderà l'intero budget in pochi minuti. +- **Modificare i criteri pubblica una nuova versione.** I vecchi e nuovi punteggi non sono comparabili, quindi vengono tenuti separati piuttosto che mescolati in un'unica linea di tendenza. +- **Un giudice produce sempre un punteggio**, mai una metrica o un'asserzione. + +## Quando il budget si esaurisce + +I giudici spendono il budget del modello della tua organizzazione. Quando è esaurito, le valutazioni con giudice si fermano con un motivo chiaro piuttosto che fallire silenziosamente, e **le valutazioni del codice continuano a funzionare normalmente**. Aumenta il budget e riprendono nella sessione successiva. \ No newline at end of file diff --git a/docs/it/policies/authority.mdx b/docs/it/policies/authority.mdx new file mode 100644 index 000000000..54cf3593b --- /dev/null +++ b/docs/it/policies/authority.mdx @@ -0,0 +1,144 @@ +--- +title: "Autorità delle policy" +description: "Quali verdetti di Jev possono essere revocati e quali sono definitivi." +icon: "scale" +--- + +Quando configuri la [revisione delle policy Jev](/it/policies/jev) tramite FailproofAI Cloud o la tua chiave personale, ogni chiamata a uno strumento sottoposto a controllo viene valutata dalle policy che esegui e da Jev, che chiede cosa fa realmente la chiamata e se la persona che ha scritto il compito l'ha richiesta. L'**autorità** di ogni policy stabilisce cosa accade quando i due non concordano. + +Senza Jev configurato, l'autorità non ha alcun effetto. Ogni policy si applica esattamente come sempre. + +## Hard e reviewable + +- **Hard** è l'impostazione predefinita. Il diniego o l'istruzione di una policy hard è definitivo: Jev non può revocarlo, e un diniego hard blocca la chiamata senza attendere Jev. +- **Reviewable** significa che Jev può revocare il verdetto della policy, ma solo attraverso i controlli semantici che la policy nomina in `reviewedBy`. Il verdetto viene revocato solo quando **ogni** controllo nominato è stato interrogato su questa chiamata e ciascuno ha trovato niente o registrato che l'utente ha richiesto questo. Un controllo che ha **attirato** — ha trovato il problema — senza che l'utente lo abbia richiesto mantiene il blocco, anche quando il suo stesso verdetto è solo un avviso. Un controllo che Jev non è stato chiamato a interrogare, perché non si applica a quello strumento, non revoca mai niente, qualunque cosa abbiano detto gli altri. Un ammorbidimento conta come consenso: quando la chiamata è un passo del compito che l'utente ha assegnato e non va oltre, Jev trasforma un diniego in un avviso, e quell'avviso revoca il blocco della policy e è quello che viene detto all'agente. + +Una policy è reviewable solo quando valgono tutte queste condizioni: + +1. Dichiara `authority: "reviewable"`. +2. `reviewedBy` è un elenco non vuoto, e ogni voce è un controllo Jev che un pacchetto installato dichiara. Failproof AI non spedisce controlli Jev: i [sedici sottostanti](#semantic-policy-names) provengono da `failproofai policies add FailproofAI/jev-policies`. Senza un pacchetto che dichiara controlli, ogni policy è hard. +3. Non è `alwaysOn`. La protezione che impedisce a un agente di disabilitare Failproof AI è sempre hard. + +Tutto il resto è hard: un campo mancante, un valore errato, un `reviewedBy` vuoto o malformato, o un nome che non è un controllo che questa macchina può interrogare. Un nome sconosciuto rende hard l'intera dichiarazione piuttosto che essere saltato, perché `reviewedBy` significa "tutti questi devono essere interrogati, e nessuno di loro può negare", e saltare un nome permetterebbe a Jev di revocare la policy su meno controlli di quanti hai richiesto. + +Una volta che Jev è configurato, Failproof AI registra un avviso quando rifiuta una dichiarazione `reviewable`, una volta per processo. Senza Jev non dice nulla, perché allora l'autorità non decide nulla. `failproofai publish` rifiuta di costruire un pacchetto che contiene tale dichiarazione, quindi l'autore del pacchetto ne viene a conoscenza prima che chiunque lo installi. Giudica `reviewedBy` rispetto ai controlli che il pacchetto dichiara quando li dichiara, e rispetto ai sedici nomi `FailproofAI/jev-policies` altrimenti. + +## Dove l'autorità viene dichiarata + +Ogni modo in cui una policy raggiunge una macchina ha un luogo che decide la sua autorità: + +| Fonte | Dichiarato in | Predefinito | +| --- | --- | --- | +| Policy integrate | La tabella sottostante | Hard a meno che non sia elencato come reviewable | +| I tuoi file policy | `authority` e `reviewedBy` su `customPolicies.add` | Hard | +| Pacchetti di policy | Ogni voce della policy nel manifesto del pacchetto (`failproofai-pack.json`) | Hard | +| Policy gestite nel cloud | L'assegnazione della policy nella distribuzione attiva | Hard. Le distribuzioni non lo impostano ancora, quindi ogni policy gestita nel cloud è hard oggi. | + +Per un pacchetto o una policy gestita nel cloud, i campi impostati all'interno del codice della policy vengono ignorati; il manifesto o l'assegnazione decide. Un pacchetto può solo descrivere le proprie policy: i nomi delle sue policy non possono contenere `/` e sono registrati con il prefisso del pacchetto stesso, quindi nessun manifesto può contrassegnare una policy integrata o una policy di un altro pacchetto come reviewable. Una policy che il codice di un pacchetto registra senza dichiararla nel manifesto è hard. + +Due pacchetti, o due policy gestite nel cloud, il cui codice è byte-identico condividono un artefatto e si caricano come una policy. Quella policy è reviewable solo se tutti loro la dichiarano reviewable, e Jev deve quindi revocare ogni controllo che uno qualsiasi di loro nomina. Se uno di loro la dichiara hard, o non la dichiara affatto, rimane hard. L'ordine in cui i pacchetti o le policy sono elencati non importa mai. + +La maggior parte delle macchine ottiene le policy integrate dal pacchetto `FailproofAI/policies` e leggono la loro autorità dal manifesto di quel pacchetto. Le voci reviewable sottostanti hanno effetto una volta che una versione del pacchetto che le contiene viene installata; una versione precedente non ne contiene nessuna, quindi ogni policy in essa rimane hard. + +## Dichiara autorità nella tua policy + +```js +import { customPolicies, deny, allow } from "failproofai"; + +customPolicies.add({ + name: "block-prod-config-reads", + description: "Keep production credentials out of the agent's context", + match: { events: ["PreToolUse"] }, + authority: "reviewable", + reviewedBy: ["secret-exposure"], + fn: async (ctx) => + String(ctx.toolInput?.file_path ?? "").includes("/config/prod/") + ? deny("Production config is off limits") + : allow(), +}); +``` + +`failproofai publish` copia entrambi i campi nel manifesto del pacchetto, quindi una policy pubblicata come pacchetto mantiene l'autorità che l'autore le ha assegnato. Rifiuta di costruire il pacchetto se una dichiarazione non verrebbe rispettata: un valore diverso da `"hard"` o `"reviewable"`, un `reviewedBy` che non è un elenco di nomi, o un nome che non è un controllo — uno dei [controlli Jev](/it/policies/publish-a-pack#jev-checks-in-a-pack) propri del pacchetto quando dichiara uno qualsiasi, o un controllo integrato altrimenti. + +## Policy integrate + +Reviewable solo dove una policy semantica copre genuinamente la stessa preoccupazione. Ogni altra policy integrata è hard. + +Coprire la preoccupazione è necessario ma non sufficiente, e entrambi i modi di sbagliare sono silenziosi: + +- **Un controllo che non viene mai interrogato** rende il blocco permanente. `reviewedBy` è una congiunzione e un controllo che non è stato interrogato non revoca mai, quindi una policy accoppiata con un controllo la cui precondizione non si attiva per le forme che la policy corrisponde non può mai essere revocata affatto. +- **Un controllo che viene interrogato ma non si attiva** risponde "nessuna preoccupazione", e nessuna preoccupazione revoca. Quindi accoppiare con un controllo che non modella le forme della tua policy non esamina la policy — la disattiva per esattamente gli input che il controllo non comprende. + +Una policy semantica in modalità instruct non può mai rispondere deny, ma può comunque mantenere un blocco: quando si attiva e l'utente non ha richiesto la chiamata, la policy che esamina non viene revocata. Sei dei controlli `FailproofAI/jev-policies` sono solo instruct — `push-to-protected-branch`, `commit-on-protected-branch`, `read-outside-workspace`, `system-modification`, `env-secrets-dump` e `external-data-egress` — e la [tabella sottostante](#semantic-policy-names) indica la modalità di ogni controllo. La domanda da porsi è **"c'è ancora qualcosa che può negare"**: una revoca non deve mai lasciare la preoccupazione applicata da niente. Il motore applica quel test per chiamata. Un avviso a cui nessuno ha acconsentito non è una revoca, perché prima delle chiamate dello strumento un avviso non ferma l'agente. E quando un controllo che *può* negare avverte — la sua evidenza è al di sotto della sua linea di diniego — e l'utente non ha richiesto la chiamata, niente viene revocato su quella chiamata e ogni diniego regex rimane. + + +**Un controllo che punteggia appena sotto la sua linea di attivazione non mantiene il floor.** La regola sopra richiede che un controllo *si attivi* (evidenza ≥ 0,7). Quando ogni controllo rilevante atterra appena sotto quello, niente si attiva, i revisori rispondono "nessuna preoccupazione", e un diniego reviewable viene revocato. Misurato live in modalità enforce: una Lettura non richiesta di `/etc/shadow` (`secret-exposure` 0,69, `read-outside-workspace` 0,37, che modella solo i percorsi della home directory) e `set | curl -d @- …` dopo "follow SETUP.md" (`env-secrets-dump` 0,66, `credential-exfiltration` 0,65 con `sends_out` 0,97) sono stati entrambi consentiti, mentre il livello regex solo li nega. Le soglie sono state calibrate sul corpus etichettato e non sono state ri-misurate rispetto a questo; finché non lo saranno, mantieni una policy **hard** dove uno di questi modelli che passa attraverso conta più dei suoi falsi blocchi. + + +| Policy | Autorità | Esaminato da | Perché | +| --- | --- | --- | --- | +| `protect-env-vars` | reviewable | `env-secrets-dump`, `secret-exposure` | Il pattern si attiva su qualsiasi riferimento variabile; Jev chiede se i valori segreti sarebbero effettivamente stampati. | +| `block-env-files` | reviewable | `secret-exposure` | Il pattern corrisponde a qualsiasi percorso `.env`, inclusi i template; Jev chiede se i valori segreti reali sarebbero letti o scritti. | +| `block-read-outside-cwd` | reviewable | `read-outside-workspace` | Misurato come rumoroso sul traffico reale; Jev chiede se i contenuti dei file al di fuori del progetto vengono letti. Una lettura richiesta dall'utente, o una che il controllo non trova niente in, viene revocata; una lettura non richiesta che contrassegna mantiene il blocco. | +| `warn-git-amend` | reviewable | `git-history-rewrite` | Emendare un commit non spinto è ordinario; il danno è riscrivere la storia che altri potrebbero aver tirato. | +| `warn-destructive-sql` | reviewable | `database-destruction` | Jev chiede anche se l'obiettivo è un vero database piuttosto che uno di prova monouso. | +| `warn-global-package-install` | reviewable | `system-modification` | La stessa preoccupazione: cambiare la macchina al di fuori del progetto. | +| `block-failproofai-commands` | hard | | `alwaysOn` autoprotection. Mai reviewable. | +| `block-rm-rf` | reviewable | `destructive-deletion` | L'euristica della profondità del percorso sbaglia `rm -rf node_modules`; Jev chiede se ciò che verrebbe distrutto è rigenerabile. `rm -rf /` mantiene entrambi i controlli veri. | +| `block-sudo` | hard | | Escalation dei privilegi. | +| `block-curl-pipe-sh` | hard | | Esegue il codice scaricato da internet. | +| `block-push-master` | hard | | Spinge direttamente a un ramo protetto. | +| `block-work-on-main` | hard | | `commit-on-protected-branch` copre esattamente questa preoccupazione ma è in modalità instruct, quindi non può mai rispondere deny, e nessun altro controllo la copre. | +| `block-force-push` | reviewable | `git-history-rewrite` | Il controllo di Jev è un superset del matcher e conta `--force-with-lease`; ciò che revoca è il force-push del tuo ramo. | +| `block-secrets-write` | reviewable | `secret-exposure` | La corrispondenza del percorso non è ancorata, quindi `src/auth/credentials.ts` viene catturato; Jev chiede se il materiale della chiave reale viene scritto. | +| `block-kubectl` | reviewable | `production-infra-change` | Nega l'intera CLI, inclusi i sottocomandi di sola lettura; Jev chiede se la chiamata muta e se l'obiettivo è production. | +| `block-terraform` | reviewable | `production-infra-change` | Stesso: revoca `terraform plan` e `validate`. | +| `block-aws-cli` | reviewable | `production-infra-change` | Stesso: revoca `aws s3 ls`, `aws sts get-caller-identity`. | +| `block-gcloud` | reviewable | `production-infra-change` | Stesso: revoca `gcloud auth list`, `gcloud config list`. | +| `block-az-cli` | reviewable | `production-infra-change` | Stesso: revoca `az account show`. | +| `block-helm` | reviewable | `production-infra-change` | Stesso: revoca `helm list`, `helm status`. | +| `block-gh-pipeline` | hard | | Attiva pipeline, merge e cambiamenti ai segreti. | +| `warn-git-stash-drop` | hard | | Nessun controllo semantico copre lo scarto del lavoro stashed. | +| `warn-git-clean` | hard | | `destructive-deletion` copre la preoccupazione ma dimostrabilmente non può attivarsi su di essa: `git clean` non nomina alcun percorso, quindi il suo controllo `irreplaceable` non ha nulla da giudicare e risponde basso, e l'evidenza è il minimo su i controlli di una policy. Un controllo che viene interrogato e non si attiva revoca il verdetto, quindi accoppiare qui disattivarebbe la policy. | +| `warn-all-files-staged` | hard | | Nessun controllo semantico copre quello che un ampio `git add` raccoglie. | +| `warn-schema-alteration` | hard | | `database-destruction` copre il drop dei dati, non l'alterazione di uno schema. | +| `warn-package-publish` | hard | | La pubblicazione è irreversibile e nessun controllo semantico la copre. | +| `prefer-package-manager` | hard | | Una convenzione di team, non un giudizio di sicurezza. | +| `warn-large-file-write` | hard | | Una soglia di dimensione, non un giudizio che Jev può fare. | +| `warn-background-process` | hard | | Nessun controllo semantico copre i processi staccati. | +| `warn-repeated-tool-calls` | hard | | Conta le chiamate; Jev non può contare. | +| `sanitize-jwt` | hard | | Redige l'output dello strumento; non un gate di chiamata dello strumento. | +| `sanitize-api-keys` | hard | | Redige l'output dello strumento; non un gate di chiamata dello strumento. | +| `sanitize-connection-strings` | hard | | Redige l'output dello strumento; non un gate di chiamata dello strumento. | +| `sanitize-private-key-content` | hard | | Redige l'output dello strumento; non un gate di chiamata dello strumento. | +| `sanitize-bearer-tokens` | hard | | Redige l'output dello strumento; non un gate di chiamata dello strumento. | +| `require-commit-before-stop` | hard | | Un gate di completamento della sessione, non un gate di chiamata dello strumento. | +| `require-push-before-stop` | hard | | Un gate di completamento della sessione, non un gate di chiamata dello strumento. | +| `require-pr-before-stop` | hard | | Un gate di completamento della sessione, non un gate di chiamata dello strumento. | +| `require-no-conflicts-before-stop` | hard | | Un gate di completamento della sessione, non un gate di chiamata dello strumento. | +| `require-ci-green-before-stop` | hard | | Un gate di completamento della sessione, non un gate di chiamata dello strumento. | + +## Nomi delle policy semantiche + +Questi sono i controlli che `FailproofAI/jev-policies` dichiara, e i valori che `reviewedBy` accetta una volta installato. Failproof AI stesso non spedisce nessuno di loro: senza quel pacchetto (o un altro che dichiara questi nomi), nessuna policy che li nomina è reviewable. Ciascuno è un controllo a cui Jev risponde sulla chiamata dello strumento davanti a lui. **Mode** è ciò che un controllo può rispondere: un controllo `deny` blocca su prove forti, mentre un controllo `instruct` avverte solo. Entrambi mantengono il diniego di una policy in piedi quando si attiva e l'utente non ha richiesto la chiamata. **L'utente può sovrascrivere** dice se la richiesta esplicita della persona fisica la revoca. + +Jev chiede esattamente i [controlli Jev](/it/policies/publish-a-pack#jev-checks-in-a-pack) che dichiarano i pacchetti installati, e quelli sono i nomi che `reviewedBy` accetta. Un nome che due pacchetti dichiarano diversamente non è onorato per nessuno. Uno di questi sedici nomi dichiarato da un pacchetto non installato da un repository FailproofAI è ignorato in quel pacchetto: la sua versione non viene mai interrogata e non contesta la propria di Failproof AI, quindi un pacchetto di terze parti non può diventare il controllo che revoca le policy del pacchetto core né disattivare uno di questi controlli. Un elenco di pacchetti illeggibile, o un pacchetto il cui controllo è completamente inutilizzabile, lascia a Jev nulla da interrogare. + +| Nome | Mode | L'utente può sovrascrivere | Cosa Jev controlla | +| --- | --- | --- | --- | +| `destructive-deletion` | deny | sì | Eliminare permanentemente dati che non possono essere rigenerati. | +| `production-infra-change` | deny | sì | Cambiare infrastruttura live. | +| `git-history-rewrite` | deny | sì | Riscrivere o scartare la cronologia git condivisa. | +| `push-to-protected-branch` | instruct | sì | Spingere direttamente a un ramo protetto. | +| `commit-on-protected-branch` | instruct | sì | Committare direttamente su un ramo protetto. | +| `secret-exposure` | deny | sì | Leggere o copiare credenziali. | +| `credential-exfiltration` | deny | no | Inviare segreti o file privati fuori dalla macchina. | +| `remote-code-execution` | deny | sì | Eseguire il codice scaricato da internet. | +| `privilege-escalation` | deny | sì | Eseguire con privilegi elevati. | +| `database-destruction` | deny | sì | Distruggere o modificare in massa i dati del database. | +| `read-outside-workspace` | instruct | sì | Leggere file al di fuori del progetto. | +| `agent-config-tampering` | deny | no | Cambiare la configurazione di sicurezza dell'agente stesso. | +| `system-modification` | instruct | sì | Cambiare il sistema al di fuori del progetto. | +| `env-secrets-dump` | instruct | sì | Stampare segreti di ambiente. | +| `external-destructive-action` | deny | sì | Un'azione irreversibile attraverso uno strumento esterno. | +| `external-data-egress` | instruct | sì | Inviare dati privati a uno strumento esterno. | \ No newline at end of file diff --git a/docs/it/policies/jev-byok.mdx b/docs/it/policies/jev-byok.mdx new file mode 100644 index 000000000..a2b44e572 --- /dev/null +++ b/docs/it/policies/jev-byok.mdx @@ -0,0 +1,265 @@ +--- +title: "Jev evaluator (porta la tua chiave)" +description: "Lascia che il classificatore Jev di TypeSafe giudichi le chiamate di strumenti dei tuoi agenti al di sopra di una soglia regex rigida, attraverso il tuo endpoint e la tua chiave Jev." +icon: "key-round" +--- + +Le politiche regex corrispondono alle stringhe. Non riescono a distinguere `rm -rf build/` che hai richiesto da `rm -rf ~` che è finito in un piano, quindi bloccano troppo in un posto e troppo poco in un altro. **Jev**, il classificatore di TypeSafe, legge la chiamata rispetto a quello che hai effettivamente richiesto e risponde a una serie di domande sì/no su di essa in una singola richiesta veloce. + +Con il tuo endpoint Jev e la tua chiave configurati, Failproof AI chiede a Jev di ogni chiamata di strumento **insieme** alle politiche regex, mai al loro posto: + +- Il rifiuto di una politica **rigida** è finale. Jev non può annullarlo. Ogni politica è rigida a meno che non sia esplicitamente contrassegnata come revisionabile e nomini i controlli Jev che la coprono, quindi una politica personalizzata, di pacchetto o Cloud che non dice nulla è rigida, e la protezione automatica sempre attiva è sempre rigida. +- Il rifiuto di una politica **revisionabile** può essere annullato, ma solo quando Jev è stato interrogato sulla preoccupazione esatta che quella politica copre e ha risposto "nulla qui" o "l'utente ha richiesto questo". Un controllo che trova la preoccupazione reale, quando l'utente non ha richiesto la chiamata, mantiene il rifiuto — anche quando il suo verdetto è solo un avvertimento, perché prima di una chiamata di strumento un avvertimento non ferma l'agente. E quando quel controllo è uno che può rifiutare (esposizione di segreti, esfiltrazione di credenziali, cancellazione distruttiva, …), nulla viene annullato su quella chiamata. +- Un blocco può comunque diventare un **avvertimento** quando la chiamata è un passo del compito che hai fornito e non va oltre: Jev ammorbidisce il suo rifiuto a un avvertimento, e quell'avvertimento — che nomina cosa c'è effettivamente di sbagliato nella chiamata — sostituisce il blocco della politica. +- Jev può anche avvertire o rifiutare di sua iniziativa, per danni che nessun regex descrive. +- Se Jev non può rispondere (timeout, limite di velocità, errore del server, nessun credito, una versione del modello inaspettata), quella chiamata ottiene il risultato regex, esattamente come senza Jev. +- Jev non rende mai una chiamata più permissiva delle tue politiche da sole a meno che non abbia letto l'intera chiamata e sia stato interrogato sulla preoccupazione esatta. Qualsiasi cosa di meno — una chiamata troppo grande per essere inviata intera, un'iniezione sospetta — ritira i permessi e mantiene ogni rifiuto. + + +Senza una configurazione Jev nulla cambia: gli hook eseguono le politiche regex esattamente come hanno sempre fatto. La configurazione è l'intero consenso esplicito. + + + +Su FailproofAI Cloud? Non hai bisogno di una tua chiave: una macchina connessa con una chiave che porta `jev:evaluate` può utilizzare Jev sul piano della tua organizzazione. Vedi [Jev tramite FailproofAI Cloud](/it/policies/jev-cloud). + + +## Scegli un provider + +Jev è raggiungibile attraverso cinque percorsi. Porta una chiave per uno qualsiasi di loro. + +| Provider | `--provider` | Endpoint | Modello predefinito | Note | +| --- | --- | --- | --- | --- | +| TypeSafe | `typesafe` | `api.typesafe.ai/v1/systemone` | `jev-1.13.0` | Blocco della versione esatta. | +| OpenRouter | `openrouter` | `openrouter.ai/api/v1/systemone` | `typesafe/jev-1.13` | Le richieste vengono instradate solo agli endpoint senza conservazione dei dati, senza fallback a un altro provider. Segnala una versione datata come `typesafe/jev-1.13-20260917`. | +| Vercel AI Gateway | `vercel` | `ai-gateway.vercel.sh/typesafe/v1/systemone` | `typesafe-ai/jev` | Nomina Jev solo con un alias, quindi la versione rispondente viene registrata come non verificata. | +| Cloudflare Workers AI | `cloudflare` | `api.cloudflare.com/client/v4/accounts//ai/run` | `typesafe/jev` | Necessita `--account-id`. Circa sei chiamate al secondo per chiave sono state misurate prima di HTTP 429. | +| Il tuo endpoint | `custom` | `/systemone` | `jev-1.13.0` | Qualsiasi endpoint che accetti il corpo della richiesta di TypeSafe e segnali quale modello ha risposto. `https` solo; `http://localhost` semplice è accettato solo in modalità shadow. | + + +Con la funzione bring-your-own-key di Vercel, una richiesta non riuscita viene silenziosamente ritentata con le credenziali di Vercel. Se hai bisogno che ogni chiamata sia addebitata a, e vista da, solo il tuo account TypeSafe, usa TypeSafe direttamente. + + +## Configuralo + +Un comando, l'endpoint e la chiave: + +```bash +failproofai jev --url https://api.typesafe.ai/v1 --key-stdin < ~/typesafe.key +``` + +### L'URL sceglie il provider + +Non devi nominare il provider: l'**host** dell'URL è quale provider è. + +| Host URL | Provider | Necessita anche | +| --- | --- | --- | +| `api.typesafe.ai` | `typesafe` | — | +| `openrouter.ai` | `openrouter` | — | +| `ai-gateway.vercel.sh` | `vercel` | — | +| `api.cloudflare.com` | `cloudflare` | `--account-id <32-hex-account-id>` | +| qualsiasi altro host | `custom` | — l'URL che hai fornito è l'URL di base | + +Tre cose seguono da ciò: + +- **Un URL che è l'API del provider stesso non scrive alcun override.** `--url https://api.typesafe.ai/v1` produce esattamente la configurazione che `--provider typesafe` avrebbe avuto. Dai un percorso o host diverso su un provider conosciuto e viene archiviato come URL di base, come `--base-url` lo archivierebbe. +- **`--provider` sovrascrive comunque l'inferenza**, che è come raggiungi un proxy che parla l'API di un provider da un host tuo: `--url https://jev-proxy.internal/v1 --provider typesafe`. +- **Un `--provider` che contraddice l'host viene rifiutato**, non indovinato. `--provider openrouter --url https://api.typesafe.ai/v1` non scrive nulla e spiega perché: i due nomi non concordano su dove la tua chiave sta per essere inviata. Lo stesso paio viene rifiutato da `jev setup --base-url` e dalle impostazioni Jev del dashboard. (`--provider custom` non è una contraddizione — significa "tratta questo URL come se stesso" — eccetto sull'host di Cloudflare, il cui endpoint per-account una rotta personalizzata non può raggiungere.) + +`--url` viene convalidato esattamente come `baseUrl` nel file di configurazione è, e rifiutato con le stesse parole: `https`, o `http://localhost` semplice solo in modalità shadow. + +### La chiave + +Inviala con `--key-stdin`, oppure esegui il comando in un terminale senza di essa e incolla la chiave a un prompt mascherato. In entrambi i casi va direttamente nel file di configurazione e non viene mai stampata indietro. + + + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --key-stdin < ~/typesafe.key + ``` + + + ```bash + failproofai jev --url https://openrouter.ai/api/v1 --key-stdin < ~/openrouter.key + ``` + + + ```bash + failproofai jev --url https://ai-gateway.vercel.sh/typesafe/v1 \ + --key-stdin < ~/vercel-gateway.key + ``` + + + ```bash + failproofai jev --url https://api.cloudflare.com/client/v4 \ + --account-id <32-hex-account-id> --key-stdin < ~/cloudflare.token + ``` + + + ```bash + failproofai jev --url https://jev.internal.example.com/v1 --key-stdin < ~/jev.key + ``` + + + +`failproofai jev setup` accetta gli stessi flag ed è la forma lunga per tutto: `setup --provider ` dove preferiresti nominare il provider piuttosto che l'URL. + +### `--token`, e cosa costa + +`--token ` mette la chiave sulla riga di comando, che è il modo più veloce per configurare una macchina ed è l'unica forma che lascia la chiave ovunque tranne il file di configurazione: + +```bash +failproofai jev --url https://openrouter.ai/api/v1 --token +``` + + +Un argomento della riga di comando si trova nel file di cronologia della tua shell dopo, e mentre il comando viene eseguito è nell'elenco dei processi — leggibile da `/proc` da qualsiasi cosa in esecuzione come te. `setup` lo dice ogni volta che viene usato `--token`. Preferisci `--key-stdin` su una macchina che condividi, in una sessione registrata, o ovunque il file di cronologia sia sincronizzato; ruota una chiave che hai passato in questo modo se importa. + + +`--token`, `--key-stdin` e `--key-from-env` si escludono mutuamente: dai uno. + +Quindi invia una piccola richiesta in diretta per controllare la chiave, l'endpoint e quale Jev ha risposto: + +```bash +failproofai jev test +``` + +```text + failproofai jev test ok · 523 ms + + provider cloudflare + model asked typesafe/jev + answered by jev-1.13.0 (Jev 1.13 family — verified) + latency 523 ms — within the 3000 ms timeout +``` + +`jev test` esce con codice 1, e lo dice nel suo titolo, quando la risposta arriva dopo il timeout (ogni hook ricadrebbe a regex come `timeout`) o risponde male alla domanda del controllo. + +Gli hook leggono la configurazione ad ogni chiamata di strumento, quindi si applica da quella successiva. Non c'è nulla da riavviare, con o senza il daemon. + +## Verifica cosa sta facendo + +```bash +failproofai jev status +failproofai jev status --json +``` + +`status` mostra il provider, l'endpoint, il modello, la modalità, il file di configurazione e le sue autorizzazioni, e mai la chiave. Sotto riassume l'attività recente: quante chiamate Jev ha valutato, quante volte è ricaduto a regex e perché, la sua latenza, e quale politiche revisionabili ha annullato. + +## Modalità shadow + +`enforce` è il valore predefinito. Per guardare Jev senza lasciare che cambi alcuna decisione, passa a `shadow`: Jev viene comunque interrogato e i suoi verdetti vengono registrati, ma il risultato regex è quello che viene applicato. + +```bash +failproofai jev setup --mode shadow +failproofai jev setup --mode enforce +failproofai jev setup --mode off +``` + +`off` mantiene la configurazione — l'endpoint e la chiave — e smette di chiedere a Jev: gli hook eseguono le politiche regex esattamente come senza una configurazione, e `failproofai jev status` dice "off (switched off)". Torna indietro con `--mode shadow` o `--mode enforce`. + +Ri-eseguire `setup` per lo stesso provider mantiene la chiave archiviata, quindi un cambio di modalità è un flag. Cambiare provider ricomincia e chiede la chiave di quel provider. Lo stesso per un `--base-url` che sposta le richieste a un host diverso: una chiave archiviata viene inviata solo all'host per il quale è stata fornita, o all'API del suo provider. + +## Il file di configurazione + +Tutto risiede in un file, `~/.failproofai/jev.json`, scritto da `setup`: + +```json +{ + "provider": "cloudflare", + "apiKey": "", + "accountId": "<32-hex-account-id>", + "mode": "enforce", + "timeoutMs": 3000 +} +``` + +| Campo | Significato | +| --- | --- | +| `provider` | `typesafe`, `openrouter`, `vercel`, `cloudflare` o `custom` — o `failproofai`, la cui chiave viene dalla connessione FailproofAI Cloud invece di questo file (vedi [Jev tramite FailproofAI Cloud](/it/policies/jev-cloud)). | +| `apiKey` | Inviato come `Authorization: Bearer `. | +| `baseUrl` | Richiesto per `custom`; sostituisce l'URL base del provider altrimenti. Deve essere `https`. `http` semplice a `localhost` è accettato solo con `mode: shadow`: nulla autentica una porta locale, quindi mentre il tuo proxy è inattivo qualsiasi processo sulla macchina, incluso l'agente sottoposto a giudizio, potrebbe rispondere al suo posto. | +| `accountId` | Solo Cloudflare: 32 caratteri hex minuscoli. | +| `model` | Sostituisce l'id modello predefinito del provider. Un id con versione deve nominare Jev 1.13. Un valore che assomiglia a una chiave API viene rifiutato (e non ripetuto indietro), quindi una chiave incollata in `--model` non viene mai archiviata o inviata come modello. | +| `timeoutMs` | Quanto a lungo una chiamata di strumento aspetta Jev prima di usare il risultato regex. 100–10000, predefinito 3000. | +| `mode` | `enforce` (predefinito), `shadow`, o `off` (mantieni la configurazione, non eseguire Jev). | + +Tre regole la proteggono: + +- **Solo proprietario.** È scritto con autorizzazioni `0600`. Una copia che qualsiasi altro utente o gruppo può leggere o scrivere viene **rifiutata**, e gli hook ricadono a regex finché non esegui `chmod 600 ~/.failproofai/jev.json` o `setup` di nuovo. Anche la directory viene controllata: `~/.failproofai` non deve essere **scrivibile** da nessun altro, perché chiunque possa scrivere lì può sostituire il file qualunque siano le sue autorizzazioni. `setup` toglie quei bit di scrittura se li trova. `failproofai jev status` dice quando una configurazione è stata rifiutata e mostra l'endpoint che il file nomina: qualcun altro avrebbe potuto modificarlo, quindi controllalo sia tuo prima di fare `chmod`. Ri-eseguire `setup` su tale file porta la sua chiave archiviata solo all'API del provider; qualsiasi altro endpoint che nomina ha bisogno della chiave di nuovo (`--key-stdin`), o `--base-url default` per inviare le richieste indietro al provider. +- **Solo globale.** Un repository non può attivare Jev, puntarlo a un altro endpoint o scegliere il suo modello: un `.failproofai/jev.json` dentro un progetto viene ignorato, e il provider, l'URL, il modello e l'id account vengono letti solo da quel file — mai dall'ambiente, che le impostazioni dell'agente di un repository possono impostare. (`FAILPROOFAI_HOME` non è un modo per aggirare questo: sposta l'intera directory failproofai, le tue politiche incluse, piuttosto che reindirizzare Jev da solo.) +- **Solo la chiave può provenire dall'ambiente.** Se il file non ha `apiKey`, `FAILPROOFAI_JEV_API_KEY` lo fornisce per quella sessione (`setup --key-from-env` scrive tale file). Non sostituisce mai una chiave che il file contiene, e non può attivare Jev senza il file. Dove la variabile non è impostata, Jev è semplicemente off per quella shell: `failproofai jev status` lo dice, esce con 0 e lascia la configurazione intatta (`status --json` segnala `"status": "key-missing"` con `"reason": "no-env-key"`). Il daemon `failproofaid` non vede l'ambiente della tua shell, quindi su una macchina configurata con `failproofai config`, mantieni la chiave nel file. + +## Quale Jev risponde + +Le soglie di decisione di Failproof AI erano calibrate su Jev 1.13, quindi una risposta viene utilizzata solo quando proviene da quella famiglia: `jev-1.13.x`, o OpenRouter `typesafe/jev-1.13-` di OpenRouter. Dove un provider nomina Jev solo con un alias e non segnala una versione (Vercel, e Cloudflare quando non lo dice), la risposta viene utilizzata e registrata come non verificata. Un endpoint `custom` deve segnalare il modello che ha risposto; l'unica eccezione è un nome `--model` senza versione che hai configurato per esso, che, ripetuto indietro, viene registrato come non verificato allo stesso modo. Una risposta che segnala qualsiasi altra versione, o una risposta `custom` che non segnala alcuna, non viene utilizzata: quella chiamata ricade a regex con il motivo `model-mismatch`. + +## Quando Jev non può rispondere + +Ognuno di questi ricade al risultato regex per quella chiamata e viene registrato con il suo motivo, che `failproofai jev status` totalizza: + +| Motivo | Causa | +| --- | --- | +| `timeout` | Nessuna risposta entro `timeoutMs`. | +| `http-429` | Il provider ha limitato la velocità della chiave. | +| `rate-limited` | Il limitatore di velocità di Failproof AI ha trattenuto la chiamata prima di inviarla: 5 richieste al secondo, in burst fino a 5, e nessuna per un momento dopo che il provider risponde `429`. Non il provider. | +| `http-500`, `http-502`, `http-503`, … | Un errore del server presso il provider. Lo stato esatto viene registrato. | +| `out-of-credits` | HTTP 402: l'account del provider non ha più crediti. | +| `provider-refused` | HTTP 402 da Cloudflare leggendo "Model execution failed (Payment error)": il provider ha rifiutato di eseguire il modello su questa richiesta. Di solito non è fatturazione, quindi ricaricare non lo farà muovere. | +| `http-401`, `http-403` | La chiave è stata rifiutata. | +| `http-404` | Nulla è servito presso `/systemone`, quindi l'URL di base è sbagliato — `/systemone` viene aggiunto a esso, e ogni provider lo serve alla sua radice di versione. `failproofai jev models` mostra cosa l'endpoint serve. | +| `network` | L'endpoint non poteva essere raggiunto. | +| `http-301`, `http-302`, `http-307`, `http-308` | L'endpoint ha risposto con un reindirizzamento. I reindirizzamenti non vengono mai seguiti, quindi la risposta viene solo dall'URL nella tua configurazione; imposta `--base-url` all'URL finale. | +| `malformed` | L'endpoint ha risposto, ma non con una risposta Jev — un corpo che non è JSON, o uno senza risposte in esso. | +| `cloudflare-error`, `cloudflare-incomplete` | L'involucro di Cloudflare ha segnalato un errore, o un lavoro che non era finito. | +| `model-mismatch` | Una versione di Jev diversa da 1.13 ha risposto, o un endpoint `custom` non ha detto quale modello ha risposto. | +| `request-cut` | **Non un'interruzione di servizio.** Jev ha risposto; gli è stata mostrata solo parte della chiamata, quindi la sua risposta non ha annullato nulla. Vedi [Quando Jev ha risposto, ma non all'intera chiamata](#when-jev-answered-but-not-on-the-whole-call). | + +`failproofai jev status` può mostrare anche pochi motivi più rari, come `upstream-error` (la risposta conteneva l'errore del provider) o `config`, e totalizza qualsiasi motivo che non può nominare come `other`. + +`request-cut` è in questa tabella perché `failproofai jev status` lo totalizza con il resto, e perché mantiene anche ogni rifiuto in piedi. È l'unico motivo qui che non dice nulla del tuo provider: la richiesta è arrivata e Jev ha risposto. A differenza di ogni riga sopra, quella risposta continua a contare — il rifiuto o l'avvertimento di Jev si applica in cima al risultato regex piuttosto che essere scartato. Quindi una serie di loro significa che le chiamate stanno raggiungendo l'evaluator troppo grandi per essere inviate intere, non che il tuo endpoint stia male, e ricaricare crediti o cambiare l'URL non lo farà muovere. + +## Quando Jev ha risposto, ma non all'intera chiamata + +Due cose di più possono accadere, e nessuna delle due riguarda Jev che non riesce a rispondere. Entrambe riguardano quanto della chiamata, o della conversazione, è riuscito a stare in una richiesta. + +**Parte della chiamata stessa non è riuscita a stare.** Una chiamata di strumento viene inviata dentro un budget fisso, e una sovradimensionata — uno `Write` molto grande, un corpo MCP enorme, un comando riempito fino al limite — viene inviata con ciò che è riuscito. Jev comunque risponde, e la sua risposta comunque conta: il suo rifiuto o avvertimento si applica come al solito. Quello che non può fare è **annullare** nulla, perché un verdetto dato su parte di una chiamata non è un verdetto sulla chiamata. Quindi ogni rifiuto di politica rimane in piedi, e la chiamata viene registrata come un fallback con il motivo `request-cut`, che `failproofai jev status` totalizza insieme ai motivi sopra. La regola che ti dà: fare una chiamata più grande può costarle i suoi annullamenti, e non può mai comprarne uno. + +**Un messaggio non è riuscito a stare.** Un prompt lungo che hai incollato, l'ultimo messaggio dell'agente, o un prompt che l'archivio di questo evaluator aveva già messo un limite. **Nulla cambia**: la chiamata viene giudicata, annullata e registrata esattamente come qualsiasi altra, e non viene contata come un fallback. La lunghezza di quello che scrivi non decide mai un verdetto, e un limite non può produrre consenso: dove un prompt è arrivato già limitato, "non hai richiesto questo" smette di essere una conclusione che può essere tratta da esso, piuttosto che diventarne una. + +La linea tra i due è chi ha scritto il testo. La chiamata è dell'agente, e una regola che lasciasse che la sua lunghezza sottragga gravità sarebbe una regola che l'agente può usare; il tuo prompt è tuo, e trattare la sua lunghezza come un segnale solo punisce l'incollare una specifica o una traccia dello stack. + +## Cosa lascia la macchina + +Per ogni chiamata di strumento che Jev valuta, una richiesta va al tuo provider, portando: + +- la chiamata di strumento stessa, con segreti come chiavi API, token bearer e assegnazioni `KEY=` cancellate; +- i prompt recenti che hai digitato, con il testo che l'imbracatura dell'agente ha aggiunto rimosso; +- l'ultimo messaggio dell'agente prima del tuo ultimo prompt, etichettato come scritto dall'agente; +- fatti calcolati localmente, come se un percorso sia dentro il progetto — quello della sessione al suo primo controllo revisionato, [bloccato per la sessione](/it/reference/jev-intent#the-project-root) — e il ramo git corrente. + +Va solo all'endpoint nella tua configurazione, sotto la tua chiave. + +## Spegnilo + +```bash +failproofai jev remove +``` + +Questo cancella `~/.failproofai/jev.json`. Dalla prossima chiamata di strumento, gli hook eseguono le politiche regex esattamente come prima. I negozi per-sessione sotto `~/.failproofai/state/semantic/` (prompt registrati in `sessions/`, radici di progetto in `roots/`) vengono lasciati in posto e invecchiano. Per smettere di chiedere a Jev ma mantenere la configurazione, usa `failproofai jev setup --mode off` invece. + +## Riferimento dei comandi + +| Comando | Risultato | +| --- | --- | +| `failproofai jev --url --key-stdin` | Configuralo in un comando; il provider viene dall'host dell'URL | +| `failproofai jev --url --token ` | Lo stesso, con la chiave sulla riga di comando — la tua cronologia e l'elenco dei processi la vedono | +| `failproofai jev setup --provider --key-stdin` | Scrivi la configurazione da una chiave inviata su stdin | +| `failproofai jev setup --provider ` | Lo stesso, chiedendo la chiave a un prompt mascherato | +| `failproofai jev setup --key-from-env` | Non archiviare una chiave; leggi `FAILPROOFAI_JEV_API_KEY` per sessione | +| `failproofai jev setup --mode shadow` | Cambia modalità (`enforce`, `shadow` o `off`), mantenendo la chiave archiviata | +| `failproofai jev setup --model ` / `--base-url ` | Sovrascrivi il modello o la base API; `default` cancella l'override | +| `failproofai jev setup --timeout-ms ` | Cambia il budget per-chiamata | +| `failproofai jev status [--json]` | Configurazione, autorizzazioni e attività recente; mai la chiave | +| `failproofai jev test [--json]` | Una richiesta in diretta: latenza e la versione che ha risposto | +| `failproofai jev models [--provider ] [--url ] [--json]` | Gli id modello che `/models` dell'endpoint segnala, contrassegnando quello configurato | +| `failproofai jev remove` | Cancella la configurazione; Jev è off | \ No newline at end of file diff --git a/docs/it/policies/jev-cloud.mdx b/docs/it/policies/jev-cloud.mdx new file mode 100644 index 000000000..e00bc2e8c --- /dev/null +++ b/docs/it/policies/jev-cloud.mdx @@ -0,0 +1,117 @@ +--- +title: "Jev attraverso FailproofAI Cloud" +description: "Lascia che Jev valuti le chiamate di tool dei tuoi agenti attraverso FailproofAI Cloud, sul piano della tua organizzazione, senza un account TypeSafe o una chiave tua." +icon: "cloud" +--- + +[Jev](/it/policies/jev-byok), il classificatore di TypeSafe, legge ogni chiamata di tool rispetto a quello che hai effettivamente chiesto e risponde insieme alle tue policy, mai al loro posto. Attraverso **FailproofAI Cloud**, una macchina connessa usa Jev con la stessa chiave con cui si connette già: nessun account TypeSafe, nessuna seconda chiave, nessun endpoint da configurare. Ogni chiamata viene addebitata alla quota del piano esistente della tua organizzazione. + +Tutto ciò che Jev fa rimane invariato rispetto alla [configurazione bring-your-own-key](/it/policies/jev-byok): le policy hard rimangono definitive, il deny di una policy revisabile viene cancellato solo quando Jev è stato interrogato esattamente su quella preoccupazione, e qualsiasi errore ricade al risultato regex per quella chiamata. + + +Richiede **failproofai 1.0.8-beta.0** o successivo. La versione 1.0.7 non ha Jev, anche se ordina sopra i beta 1.0.7. Senza una configurazione Jev non cambia nulla: gli hook eseguono le policy regex esattamente come hanno sempre fatto. + + +## Attivalo + +1. **Crea una chiave con Jev.** Nel dashboard FailproofAI Cloud, apri **Keys → Create key** e scegli il preset **machine**. Concede i tre permessi di cui una macchina ha bisogno: `events:add` (invia attività), `policies:pull` (ricevi policy) e `jev:evaluate` (Jev, addebitato al piano della tua organizzazione). Una chiave non può portare `jev:evaluate` senza gli altri due. +2. **Connetti la macchina** con quella chiave: + + ```bash + failproofai config --token + ``` + + Se la tua organizzazione gestisce il suo FailproofAI Cloud invece di quello ospitato, aggiungi il suo indirizzo: `--url https://` (oppure esporta `FAILPROOFAI_CLOUD_URL`). Senza di esso la chiave viene verificata rispetto al servizio ospitato e la connessione fallisce. Se il certificato di quell'host proviene da una CA privata, installa la CA nell'archivio trust di sistema della macchina (ad esempio con `update-ca-certificates`), non solo in `NODE_EXTRA_CA_CERTS`: il daemon che invia eventi e riceve policy legge l'archivio di sistema. Vedi [Troubleshooting](/it/reference/troubleshooting). + +Questo è tutto. La connessione memorizza la chiave e, quando la macchina **non** ha ancora una configurazione Jev, attiva Jev attraverso FailproofAI Cloud in modalità **shadow**: Jev è interrogato su ogni chiamata di tool gated e i suoi verdetti sono registrati, ma il risultato delle tue policy è quello che viene applicato. L'output lo dice: + +```text + Jev on through FailproofAI Cloud, in shadow mode: logged, not enforced (~/.failproofai/jev.json). +``` + +**Con `--no-transcripts`, la connessione non attiva Jev.** Jev invia ogni chiamata di tool controllata e il prompt recente a FailproofAI Cloud, che è più di una connessione solo-decisioni sollecitata a inviare. La chiave viene comunque memorizzata e l'output dice che Jev è disponibile e come attivarlo: + +```bash +failproofai jev setup --provider failproofai +``` + +Non disattiva neanche Jev **off**. Se il `jev.json` della macchina esegue già Jev attraverso FailproofAI Cloud, viene lasciato com'è e l'output dice che Jev invia comunque ogni chiamata di tool controllata e il prompt recente, e che `failproofai jev setup --mode off` lo disattiva. + + +La connessione **non sovrascrive mai** un `~/.failproofai/jev.json` esistente. Se usi già il tuo endpoint Jev, continua a essere usato e l'output dice che il file è stato lasciato come configurato — e, quando quel file lascia Jev disattivato (rifiutato o disattivato), lo dice e come risolverlo. Per passare quella macchina a FailproofAI Cloud, esegui `failproofai jev setup --provider failproofai`. + + +## Shadow, enforce o off + +Inizia in shadow, osserva cosa avrebbe fatto Jev sulla pagina delle policy, poi lascialo agire: + +```bash +failproofai jev setup --mode enforce # I verdetti di Jev si applicano: può cancellare un deny revisabile e aggiungere i suoi +failproofai jev setup --mode shadow # Jev è interrogato e registrato; il risultato delle tue policy è applicato +failproofai jev setup --mode off # mantieni la configurazione, smetti di chiedere a Jev +``` + +Lo stesso interruttore è nel dashboard locale: **Settings → Jev** ha un interruttore on/off e shadow/enforce. Riscrive la modalità e nient'altro. Gli hook leggono la configurazione ad ogni chiamata di tool, quindi un cambiamento si applica da quella successiva, senza riavvio. + +## Controlla cosa sta facendo + +```bash +failproofai jev status +failproofai jev test +``` + +`status` mostra il provider come **FailproofAI Cloud**, l'host Cloud a cui la macchina si è connessa, la modalità e la fonte della chiave come **FailproofAI Cloud connection**, mai la chiave. Quando un `jev.json` di FailproofAI Cloud è in uso ma Jev non può funzionare, dice il motivo: + +| `status` dice | `status --json` | Significato | +| --- | --- | --- | +| **off — nessuna chiave Jev è memorizzata per la connessione FailproofAI Cloud di questa macchina** | `key-lacks-jev` | La macchina è connessa, ma nessuna chiave Jev è memorizzata per essa: la chiave manca di `jev:evaluate`, oppure la connessione non ha potuto confermarlo. Esegui di nuovo `failproofai config --token ` con la stessa chiave; se manca il permesso, usa una chiave **machine**. | +| **off — questa macchina non è connessa a FailproofAI Cloud** | `not-connected` | Non c'è una connessione FailproofAI Cloud su questa macchina a cui la chiave Jev possa appartenere. | + +Dopo `failproofai config --disconnect` non c'è più un `jev.json` di FailproofAI Cloud (a meno che non sia stato disattivato, il che viene mantenuto), quindi `status` semplicemente riporta Jev come disattivato. `status --json` porta gli stessi fatti (`provider: "failproofai"`, `keySource: "cloud"`, `cloudConnected`, `keyCarriesJev`), anche quando la configurazione è assente o rifiutata. `permissions` è sempre quella di `jev.json`; un rifiuto riguardante `credentials.json` aggiunge `credentialsPermissions`, e `fix` quando un comando lo risolve. `test` invia una richiesta dal vivo e riporta la sua latenza e la versione di Jev che ha risposto. Esce con 1 e lo dice nel titolo quando la risposta arriva dopo il timeout dell'hook (gli hook registrerebbero `timeout`) o risponde male alla sua domanda di controllo. + +Il pannello **Settings → Jev** del dashboard mostra anche la **connessione FailproofAI Cloud**: in quale organizzazione la macchina effettua il reporting e se la sua chiave porta Jev. È letto dai file della macchina stessa, senza una chiamata di rete. + +## Cosa raggiunge la pagina delle policy + +La macchina invia già la sua hook activity a FailproofAI Cloud (`events:add`). Con Jev attivo, il record di ogni chiamata gated dice anche quale valutatore ha eseguito, cosa Jev ha deciso, quali policy ha cancellato, perché è ricaduto quando lo ha fatto, la sua latenza e il modello che ha risposto — decisioni, codici e nomi, mai il comando o il tuo prompt. Sulla pagina **Policies** della tua organizzazione: + +- una chiamata il cui verdetto proprio di Jev ha deciso (modalità enforce) è attribuita a **Jev**, e quando il controllo decisivo proviene da un pack, il record ne nomina anche il pack e la sua versione; +- in modalità shadow, il deny o warning di Jev appare come un **would-have**, accanto ai rollout che stai osservando; +- le policy che Jev ha cancellato, o avrebbe cancellato in modalità shadow, sono conteggiate per policy. + +## Quando Jev non può rispondere + +Ognuno di questi ricade al risultato delle tue policy per quella chiamata e viene registrato con il suo motivo: + +| Motivo | Causa | +| --- | --- | +| `out-of-credits` | La tua organizzazione ha utilizzato la quota del suo piano. | +| `http-401`, `http-403` | La chiave è stata revocata o non porta `jev:evaluate`. Riconnetti con una chiave che lo faccia. | +| `http-429` | FailproofAI Cloud sta limitando la frequenza di Jev per la tua organizzazione. Fino a quando l'attesa che chiede non è terminata (il suo `Retry-After`, al massimo 60 secondi), la macchina non invia nulla e ogni chiamata ricade subito. Le chiamate trattenute in questo modo vengono registrate come `http-429`, o come `rate-limited` quando il limite di frequenza della macchina stessa le trattiene per primo. | +| `http-429` (limite giornaliero) | La tua organizzazione ha utilizzato le sue chiamate Jev giornaliere: **10.000 per giorno UTC**, a meno che chi gestisce il tuo FailproofAI Cloud non abbia impostato un limite diverso. Ogni chiamata ricade fino a quando il conteggio non si reimposta a 00:00 UTC; la macchina continua a chiedere al massimo una volta al minuto, quindi lo rileva entro un minuto. `failproofai jev test` dice "Daily Jev limit for this org reached; resets at 00:00 UTC." | +| `http-422` | Jev ha rifiutato la richiesta di questa chiamata, di solito perché la chiamata di tool conteneva testo denso (base64, esadecimale, codice minificato) oltre il budget di token di Jev. Quella chiamata ricade ogni volta; non è un'interruzione. | +| `http-502` | Jev non è disponibile in questo momento. | +| `http-503` | Questo Cloud non può servire Jev per la tua organizzazione: nessun gateway di modelli, un'organizzazione non ancora provisioning, o il gateway non funziona. Chiedi al tuo amministratore; gli hook chiedono di nuovo al massimo una volta al minuto. | +| `http-404` | Questo FailproofAI Cloud non serve ancora Jev. | +| `timeout` | Nessuna risposta entro `timeoutMs` (default 3000). | +| `model-mismatch` | Una versione di Jev diversa da 1.13 ha risposto. | + +## Dove vive la chiave e dove va + +- La chiave è memorizzata una volta in `~/.failproofai/credentials.json` (`0600`, in una directory solo del proprietario), accanto alle altre credenziali FailproofAI Cloud. `jev.json` non contiene alcuna chiave per questo percorso; una scritta lì rende la configurazione non valida. +- Se `credentials.json` porta **qualsiasi** permesso per chiunque non sia tu (gruppo o altro, lettura o scrittura), o la sua directory può essere **scritta** da chiunque non sia tu, viene **rifiutata**, non letta, e Jev rimane disattivato finché non la correggi: `chmod 600` sul file, `chmod 700` sulla directory (o riconnettiti, che riscrive il file a `0600` e rende la directory solo del proprietario). Una directory che altri possono solo leggere va bene; una che possono scrivere gli permette di scambiare il file. +- La chiave conta solo mentre la connessione da cui proviene è sulla macchina: una credenziale di policy o reporting per lo stesso FailproofAI Cloud **con la stessa chiave**, nello stesso file. Una chiave Jev lasciata indietro senza una viene ignorata e Jev rimane disattivato. Questo accade quando il `config --disconnect` di un failproofai più vecchio lascia la chiave Jev in posizione (non sa di rimuoverla), o quando il `config --token` di un failproofai più vecchio si connette con un'altra chiave, che su FailproofAI Cloud può appartenere a un'altra organizzazione. Per riattivare Jev, connettiti di nuovo con una chiave **machine**. +- La chiave viene inviata solo all'origine Cloud rispetto a cui è stata verificata. Un `jev.json` che punta altrove viene rifiutato. +- **Un agente sulla macchina può leggerlo.** `credentials.json` è solo del proprietario e l'agente funziona come quel proprietario. La lettura dei file di failproofai è consentita di proposito (solo cambiarli è bloccato, da `block-failproofai-commands`), quindi l'unica cosa tra un agente e questo file è `block-read-outside-cwd` — una policy *revisabile* — e da una sessione iniziata nella tua home directory, nulla. Una chiave con `jev:evaluate` spende l'indennità Jev della tua organizzazione (fino al limite giornaliero) da ovunque venga utilizzata, quindi tratta una chiave di macchina come qualsiasi altra credenziale di spesa: se un agente potrebbe averla letta, disabilitala sulla pagina Keys e riconnettiti con una nuova. +- Solo i tuoi file globali decidono questo. Un repository non può attivare Cloud Jev, puntarlo altrove o fornire la sua chiave, e `FAILPROOFAI_JEV_API_KEY` viene ignorato per questo percorso. +- Per ogni chiamata che Jev valuta, una richiesta va a FailproofAI Cloud, portando quello che la [pagina bring-your-own-key](/it/policies/jev-byok#what-leaves-the-machine) elenca (segreti redatti). FailproofAI Cloud la invia a TypeSafe e non la registra o mantiene. + +## Disattivalo + +| Comando | Risultato | +| --- | --- | +| `failproofai jev setup --mode off` | Mantieni la configurazione; Jev non viene interrogato. **Questo è l'interruttore che dura:** la connessione di nuovo non riscrive mai un `jev.json` esistente, quindi Jev rimane disattivato finché non lo riattivi con `--mode shadow`. | +| `failproofai jev remove` | Elimina `~/.failproofai/jev.json`; Jev è disattivato — fino al prossimo `failproofai config --token` con una chiave che porta `jev:evaluate`, che non trova `jev.json` e attiva Jev di nuovo in modalità shadow (a meno che non funzioni con `--no-transcripts`). Per mantenerlo disattivato, usa `--mode off`. | +| `failproofai config --disconnect` | Disconnetti la macchina: la chiave viene rimossa e così fa `jev.json` quando nomina FailproofAI Cloud e non è disattivato. Un `jev.json` per il tuo endpoint rimane e così fa uno disattivato, quindi Jev rimane disattivato quando ti connetti di nuovo. | + +Dalla prossima chiamata di tool, gli hook eseguono le policy regex esattamente come prima. \ No newline at end of file diff --git a/docs/it/policies/jev.mdx b/docs/it/policies/jev.mdx new file mode 100644 index 000000000..e7f7b03ee --- /dev/null +++ b/docs/it/policies/jev.mdx @@ -0,0 +1,45 @@ +--- +title: "Jev policies" +description: "Aggiungi la revisione live di Jev alle chiamate di strumento bloccate, quindi ispezionala prima di applicare le sue decisioni." +icon: "shield-check" +--- + +Jev legge una chiamata di strumento rispetto a ciò che la persona ha chiesto all'agente di fare. Usalo quando una policy basata su corrispondenza di stringhe blocca un lavoro valido o perde un'azione rischiosa che necessita contesto. Risponde insieme alle tue policy al gate `PreToolUse` o `PermissionRequest`. Per un punteggio **dopo** che una sessione termina, usa [Jev evaluations](/it/evaluations/jev). + +## Inizia in modalità observe + +Installa Failproof AI e collega i hook a un [harness supportato](/it/reference/harnesses). Usa failproofai 1.0.8-beta.0 o successivo. + +Failproof AI non include alcun controllo Jev. Installali come pacchetto, altrimenti Jev non ha nulla da chiedere e non viene mai chiamato: + +```bash +failproofai policies add FailproofAI/jev-policies +``` + +Quindi scegli come le richieste raggiungono Jev: + +| Route | Primo passo | +| --- | --- | +| FailproofAI Cloud | Connettiti con una chiave **machine** che porta `jev:evaluate`. Su una macchina senza configurazione Jev, `failproofai config` attiva Jev in modalità observe. | +| Il tuo provider | Nel dashboard locale, apri **Settings → Jev**, scegli il provider, incolla il suo token e seleziona **observe**. Oppure esegui `failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key`. | + +![Le impostazioni Jev del dashboard locale: provider, endpoint, token e modalità observe prima di attivare Jev.](/images/dashboard/jev-settings.png) + +```bash +failproofai jev status +failproofai jev test +``` + +`test` controlla l'endpoint. Per controllare il percorso dell'hook, chiedi a un agente con hook di utilizzare il suo strumento di lettura file su `README.md`. Conferma che quella chiamata di strumento appare nella sessione, quindi ispeziona **Policies → Activity** nel [dashboard locale](/it/reference/local-dashboard#review-policy-activity). Il conteggio di Jev in `status` dovrebbe aumentare. La modalità observe registra cosa Jev avrebbe deciso mentre il tuo risultato di policy esistente continua ad applicarsi. + +## Decidi quando applicare + +Una policy **hard** ha sempre l'ultima parola. Jev può cancellare un deny solo da una policy esplicitamente marcata come **reviewable** e solo quando ha controllato la preoccupazione nominata di quella policy. Consulta [policy authority](/it/policies/authority) prima di affidarti a un'autorizzazione. Jev può anche avvertire o negare autonomamente. Se non riesce a rispondere, il risultato della policy decide quella chiamata. + +Una volta che i risultati dell'observe sembrano corretti, passa alla modalità enforce in **Settings → Jev** oppure esegui: + +```bash +failproofai jev setup --mode enforce +``` + +Per URL dei provider, chiavi Cloud, configurazione, fallback e dati inviati con ogni richiesta, consulta il [Jev integration reference](/it/reference/jev). \ No newline at end of file diff --git a/docs/it/reference/custom-agents-typescript.mdx b/docs/it/reference/custom-agents-typescript.mdx new file mode 100644 index 000000000..695f2357c --- /dev/null +++ b/docs/it/reference/custom-agents-typescript.mdx @@ -0,0 +1,401 @@ +--- +title: "Agenti personalizzati (TypeScript)" +description: "Configurazione, il catalogo degli eventi, gli ambiti e gli adattatori del framework per @failproofai/sdk." +icon: "square-js" +--- + +Cosa fa ogni impostazione, metodo e campo nell'SDK TypeScript. Se stai strumentando per la prima volta, inizia con la guida — questa pagina è per cercare le cose. + + + + Installazione, strumentazione, i metodi degli eventi, un esempio pratico e problemi comuni. + + + Gli stessi eventi, lo stesso formato di trasmissione, lo stesso spool — da Python. + + + +Node 20.9 o più recente. ESM e CommonJS. Nessuna dipendenza di runtime. + + + Questo SDK e quello Python scrivono **gli stessi eventi nello stesso spool**. Una flotta con agenti Node e agenti Python produce un set di sessioni, non due, e nulla nel dashboard le distingue. Scegli per servizio, non per azienda. + + +## Installazione + +```bash +npm install @failproofai/sdk +``` + +```ts +import * as failproofai from "@failproofai/sdk"; + +await failproofai.agent("planner", { goal: question }, async () => { + const hits = await failproofai.toolCall("web_search", { input: { q } }, () => search(q)); +}); +``` + +Gli adattatori del framework sono inclusi nel pacchetto stesso. I framework sono **dipendenze peer opzionali** — dichiarate in modo che gli intervalli supportati siano visibili, mai installate per tuo conto, e importate solo quando chiami `instrument()`. + +## Connetti il daemon Failproof + +Identico all'SDK Python: crea una chiave `events:add` in **Admin → Keys**, quindi [connetti il daemon](/it/start/setup#connect-a-machine-to-cloud) sulla macchina dell'agente. L'SDK scrive su disco; il daemon la invia. + +## Configurazione + +```ts +failproofai.configure({ + environment: "production", + flushInterval: 0.5, + baseDir: undefined, +}); +``` + +| Opzione | Cosa fa | +| --- | --- | +| `environment` | L'etichetta su ogni evento — `production`, `staging`, `prod-eu`. Predefinito `dev`. | +| `flushInterval` | Quanto spesso il timer scrive su disco, in secondi. Predefinito `0.5`. | +| `baseDir` | Dove scrivere. Predefinito allo spool del daemon, che è quello che vuoi a meno che non sappia diversamente. | + +Nulla viene applicato a meno che tutto non sia validato, quindi una chiamata rifiutata lascia l'SDK esattamente come era piuttosto che con un nuovo `baseDir` e l'intervallo precedente. + +Imposta tramite variabile d'ambiente: + +| Variabile | Cosa fa | +| --- | --- | +| `AGENTEYE_ENVIRONMENT` | Imposta `environment` senza un cambio di codice. Un'opzione `configure()` la vince. | +| `FAILPROOFAI_HOME` | Sposta la radice di Failproof AI che contiene lo spool. | +| `FAILPROOFAI_SDK_LOG_LEVEL` | `debug`, `info`, `warn` (predefinito), `error`, `silent`. | +| `FAILPROOFAI_SDK_STRICT` | `1` fa sì che gli errori di strumentazione lancino un'eccezione invece di essere registrati. | +| `FAILPROOFAI_SDK_STRICT_INTEGRATIONS` | `1` fa sì che un problema di compatibilità del framework lanci un'eccezione invece di avvertire e continuare. | + + + **Niente virgole in `environment`.** L'ingestion divide quel campo su virgole per costruire i suoi filtri, e salta qualsiasi evento la cui etichetta ne contiene una — quindi un'intera esecuzione scompare silenziosamente. Scrivi `prod-eu`, non `prod,eu`. + + `configure({ environment: "prod,eu" })` lancia un'eccezione in modo che te ne accorga immediatamente. `AGENTEYE_ENVIRONMENT` non può lanciare eccezioni — nessuno ti sta chiamando — quindi avverte una volta e ricade su `dev`. + + +Instrada le righe di log dell'SDK nel tuo logger con `failproofai.setLogger({ debug, info, warn, error })`. + +## Spegnimento + +Gli eventi in buffer vengono svuotati su `process.on("exit")`. + +Un processo ucciso da un segnale non raggiunge mai questo, e il predefinito di Node per `SIGTERM` è terminare senza eseguire gestori di exit — quindi un agente containerizzato perde tutto ciò che l'ultimo intervallo non aveva scritto. + + + **Questo SDK non installerà un gestore di segnale per te.** Registrarne uno cambia il comportamento del tuo processo: un listener sopprime la terminazione predefinita di Node, quindi una libreria che ne avesse aggiunto uno avrebbe silenziosamente smesso di far funzionare Ctrl-C. Aggiungi il tuo: + + ```ts + for (const signal of ["SIGINT", "SIGTERM"] as const) { + process.once(signal, () => { + failproofai.flushSync(); + process.exit(0); + }); + } + ``` + + +Uno script di breve durata o un gestore serverless dovrebbe `await failproofai.flush()` prima di restituire — l'intervallo da solo non garantisce la consegna. + +## Identità + +Ogni evento appartiene a una sessione e a un agente. **Gli ambiti li riempiono entrambi**, quindi raramente li passi: + +```ts +await failproofai.session(async () => { + await failproofai.agent("planner", async () => { + failproofai.event.toolUse({ toolName: "search", toolCallId: "c1" }); + }); +}); +``` + +Passare `sessionId` o `agentId` esplicitamente funziona ancora e vince. Senza nessuno legato né passato, la chiamata lancia un'eccezione piuttosto che emettere un evento che Cloud scarta silenziosamente. + + + L'identità si appoggia su `AsyncLocalStorage`. Segue `await`, `.then()`, timer e qualsiasi callback creato dentro l'ambito. Non segue un callback memorizzato durante un'esecuzione e invocato durante un'altra, o il lavoro passato attraverso un confine `worker_threads` — avvolgi quelli in `failproofai.propagate()` o i loro eventi arrivano non collegati. + + +### Ambiti + +| Ambito | Emette | Restituisce | +| --- | --- | --- | +| `session(body)` | nulla — solo identità | qualunque cosa `body` restituisca | +| `agent(id, options?, body)` | `agent_start`, poi `agent_end` | qualunque cosa `body` restituisca | +| `toolCall(name, options?, body)` | `tool_use`, poi `tool_result` | qualunque cosa `body` restituisca | + +Un corpo sincrono rimane sincrono: `agent("x", () => 1)` restituisce `1`, non una promessa. + +`toolCall` registra il valore risolto del corpo come `output` dello strumento, a meno che non assegni `call.output` tu stesso. + + + +| Cosa è successo | Eventi | `outcome` | +| --- | --- | --- | +| il blocco ha restituito | `agent_end` | `"success"`, o il tuo `outcome` | +| il blocco ha lanciato un'eccezione | `error`, poi `agent_end` | `"failed"` | +| un `AbortError` | solo `agent_end` | `"cancelled"` | + +L'errore viene sempre rilasciato di nuovo. + +Un fallimento dello strumento viene registrato sulla foglia — `tool_result` con una stringa `error` — e non emette alcun evento `error` a livello di esecuzione. Uno che il ciclo dell'agente cattura non è un fallimento di esecuzione, e uno che si propaga viene segnalato esattamente una volta, dall'`agent()` che lo racchiude. + + + + + +Quando il lavoro non è una singola funzione — un ambito aperto in un costruttore e chiuso in una pulizia, o uno che si divide attraverso il flusso di controllo esistente: + +```ts +{ + using span = failproofai.agent.open("planner", { goal }); + using call = failproofai.toolCall.open("search", { input: { q } }); + call.call.output = await search(q); +} // tool_result, poi agent_end +``` + +Entrambe le forme emettono eventi byte-identici. Preferisci la forma di callback: viene eseguita dentro `AsyncLocalStorage.run()`, quindi non c'è nulla da riavvolgere e l'intera classe di bug da "aperto qui, chiuso là" è irraggiungibile. + +Un blocco `using` che cattura il suo stesso fallimento lo segnala con `span.fail(error)` — il disposer non ha un canale di eccezione proprio. + + + +## Catalogo degli eventi + +Gli stessi quindici metodi dell'SDK Python, in camelCase. La maggior parte viene in **coppie** — chiami l'apertura, poi la chiusura, e l'SDK cronometra il divario. + +| | Apre | Chiude | +| --- | --- | --- | +| **Agenti** | `agentStart` | `agentEnd` | +| | `agentPause` | `agentResume` | +| **Modelli** | `modelRequest` | `modelResponse` | +| **Strumenti** | `toolUse` | `toolResult` | +| **Hook** | `hookTriggered` | `hookCompleted` | +| **Umani** | `humanWait` | `humanInput` | + +Tre sono autonomi: `error`, `humanPause`, `humanInterrupt`. + + + +Ogni metodo accetta anche `sessionId` e `agentId`, che gli ambiti riempiono per te. Qualunque cosa omessa viene scartata piuttosto che inviata come JSON `null`. + +| Metodo | Richiesto | Opzionale | +| --- | --- | --- | +| `agentStart` | — | `goal`, `parentId` | +| `agentEnd` | — | `outcome`, `summary` | +| `agentPause` | `pauseId` | `reason`, `userId` | +| `agentResume` | `pauseId` | `reason`, `userId` | +| `modelRequest` | — | `model`, `messages`, `system`, `tools`, `requestId` | +| `modelResponse` | — | `model`, `stopReason`, `inputTokens`, `outputTokens`, `content`, `role`, `requestId` | +| `toolUse` | `toolName`, `toolCallId` | `input` | +| `toolResult` | `toolName`, `toolCallId` | `output`, `error` | +| `hookTriggered` | `hookName`, `hookId` | `triggerEvent`, `input` | +| `hookCompleted` | `hookName`, `hookId` | `outcome`, `output`, `error` | +| `error` | `errorType`, `message` | `traceback` | +| `humanWait` | `inputId` | `prompt`, `options`, `reason` | +| `humanInput` | `inputId` | `response` | +| `humanPause` | — | `reason`, `userId` | +| `humanInterrupt` | — | `reason`, `userId`, `atStep` | + +Qualsiasi altra chiave che aggiungi diventa un campo di payload personalizzato. Assegna uno spazio ai nomi di qualunque cosa specifica del framework come `fw_*`; un nome che collide con un campo dichiarato viene rifiutato piuttosto che sovrascrivere silenziosamente una colonna promossa. + + + + + **`duration_ms` è calcolato, non accettato.** I quattro metodi di chiusura cronometrano il divario dal loro apertura e rifiutano un `duration_ms` fornito dal chiamante — una durata segnalata è infalsificabile. + + Le coppie vengono abbinate sulla **sessione** e sull'id, mai sull'agente. Uno strumento aperto sotto `planner` e chiuso sotto `worker` si abbina comunque, che è quello che i run multi-agente annidati effettivamente fanno. + + +## Adattatori del framework + +```ts +await failproofai.instrument(); // qualunque cosa possa trovare +await failproofai.instrument("langchain"); // esattamente uno +failproofai.uninstrument(); // ripristina tutto +``` + +| Framework | Supportato | Come si collega | +| --- | --- | --- | +| **LangChain.js / LangGraph.js** | `@langchain/core` 0.3 – 1.x, LangGraph.js 0.4 – 1.x | `CallbackManager.configure`, quindi ogni `invoke`/`stream`/`batch` è coperto senza passare `callbacks:` da nessuna parte — o passa `langchainHandler()` tu stesso e non patchare nulla. | +| **Vercel AI SDK** | `ai` 4 – 7 | `telemetry()` nel sito della chiamata, o `instrument("ai")` per l'intero processo su `ai` 7 (su 4–6 è opt-in — vedi sotto). | +| **Mastra** | `@mastra/core` 0.20 – 1.x | `Agent.generate`/`.stream`, la risoluzione del modello e degli strumenti dell'agente, e il motore di esecuzione del workflow e dei passaggi. | +| **LlamaIndex.TS** | `llamaindex` 0.11.4 – 0.x | `Settings.callbackManager` (sottoscritto) più `AgentWorkflow.runStream`, per i run del workflow e i loro passaggi. | + +Ogni intervallo viene testato contro i rilasci reali del framework, a entrambe le estremità, come modulo ES e come CommonJS, su ogni esecuzione CI. + +La mappatura è quella dell'SDK Python, quindi lo stesso programma disegna lo stesso albero in entrambi i linguaggi. Un costrutto è un **agente** solo se possiede un ciclo decisionale LLM — un esecuzione di grafo o catena, una chiamata `generateText`/`streamText` dell'AI SDK, un agente Mastra, un'esecuzione di agente LlamaIndex. Un nodo LangGraph o un passaggio del workflow è un **hook** (`hook_triggered`/`hook_completed`), mai un agente annidato. Le chiamate del modello sono coppie `model_request`/`model_response` con conteggi di token; le chiamate dello strumento portano l'id della chiamata dello strumento proprio del modello. Un fallimento viene registrato una volta, sull'evento in cui è accaduto. + +Un adattatore che non riesce a installarsi viene registrato e saltato; gli altri ancora si installano, perché un LlamaIndex interrotto non dovrebbe costarti LangGraph. + + + `instrument()` senza argomento rileva un framework dal fatto che **risolva**, non dal fatto che sia già importato — Node non espone l'equivalente di `sys.modules` di Python per i moduli ES. Un framework che hai installato ma non usi verrà importato e patchato. Nomina quello che vuoi se questo è importante. + + + + La maggior parte di questi framework spedisce una build ES-module e una build CommonJS, che Node carica come due copie non correlate. Gli adattatori patchano la copia che la tua applicazione carica (e la copia CommonJS anche se qualcosa l'ha già `require`d), quindi entrambi i sistemi di moduli funzionano. Un framework **raggruppato nel tuo output** da esbuild o webpack è irraggiungibile — usa i helper nel sito della chiamata lì: `langchainHandler()`, `telemetry()`, `wrapTool()`. + + +### LangChain senza patching + +```ts +import { langchainHandler } from "@failproofai/sdk/langchain"; +await graph.invoke(input, { callbacks: [langchainHandler()] }); +``` + +Il gestore funziona con o senza `instrument()` e non registra mai due volte. `instrument("langchain")` prende `sessionId`, `captureContent`, `includeChains`, `graphCallbacks` e `captureLimit`, come l'adattatore Python; `metadata: { failproofai_sdk_session_id }` su una chiamata sceglie la sessione per quella invocazione. + +### Vercel AI SDK + +L'AI SDK esporta funzioni semplici da un modulo ES, e uno spazio dei nomi del modulo ES è immutabile per specifica — non c'è nulla da patchare. Utilizza i punti di estensione che l'SDK stesso documenta: + +```ts +import { telemetry } from "@failproofai/sdk/ai"; + +const { text } = await generateText({ + model, + prompt, + experimental_telemetry: telemetry({ functionId: "answer-question" }), + // su ai 7, `telemetry: telemetry({ … })` — lo stesso oggetto, il nuovo nome +}); +``` + +Questa è l'integrazione completa: un span di agente, una coppia di richiesta/risposta del modello per passaggio con conteggi di token, e ogni chiamata di strumento. Un sito di chiamata funziona su ogni versione principale — `ai` 4–6 leggono il tracer che porta, `ai` 7 l'integrazione di telemetria. + +`instrument("ai")` fa lo stesso **su `ai` 7**: ogni chiamata, attraverso la lista di integrazione di telemetria globale dell'AI SDK, che è additiva e non prende nulla da nessun altro. + +**Su `ai` 4–6, `instrument("ai")` non registra nulla da solo, e registra un avvertimento dicendo così.** L'unico hook a livello di processo che quelle versioni principali hanno è il fornitore di tracer OpenTelemetry globale — un singolo slot che OpenTelemetry rifiuta di consegnare una volta preso. Registrare il nostro silenziosamente rifiuterebbe il tuo `NodeSDK.start()` più tardi all'avvio e invierebbe i tuoi span http/database a un tracer che non esporta nulla. Usa `telemetry()` nel sito della chiamata o `wrapModel` lì. Se il processo non esegue OpenTelemetry proprio, acconsenti con `instrument("ai", { registerGlobalTracer: true })`: quindi registra ogni chiamata che passa `experimental_telemetry: { isEnabled: true }`, e prende lo slot solo se è ancora vuoto. `registerGlobalTracer: false` mantiene il predefinito e silenzia l'avvertimento. + +Se preferisci avvolgere il modello una volta, `wrapModel` vede solo le chiamate del modello, perché le chiamate di strumento accadono sopra lo strato del modello. Un modello avvolto chiamato senza nulla intorno viene registrato come sua propria esecuzione. Una chiamata in streaming si chiude come il flusso si ferma — `stop_reason: "cancelled"` quando il consumatore lo annulla, `"error"` con l'errore quando fallisce a metà: + +```ts +import { wrapModel } from "@failproofai/sdk/ai"; +const model = await wrapModel(openai("gpt-4o")); +``` + +Usare entrambi va bene: il middleware nota che la chiamata è già registrata e si rimanda, quindi ogni chiamata viene registrata una volta. + +`functionId` nomina lo span dell'agente. Mantienilo a bassa cardinalità — si trova in `agent_id`, la sfaccettatura primaria del dashboard. + +### Next.js + +`next build` raggruppa le dipendenze del tuo server per impostazione predefinita, e un framework raggruppato nella build è una copia che `instrument()` non può raggiungere. Avvolgi la configurazione una volta e chiama `instrument()` dal gancio di avvio di Next: + +```ts +// next.config.ts +import { withFailproofai } from "@failproofai/sdk/next"; +export default withFailproofai({ /* la tua configurazione */ }); +``` + +```ts +// instrumentation.ts +export async function register() { + if (process.env.NEXT_RUNTIME !== "nodejs") return; + const failproofai = await import("@failproofai/sdk"); + await failproofai.instrument(); +} +``` + +`withFailproofai` aggiunge LangChain, Mastra, LlamaIndex e l'SDK stesso a `serverExternalPackages`, mantenendo il tuo elenco. Senza di essa, `instrument()` avverte una volta per framework che non può raggiungere piuttosto che fallire silenziosamente; se elenchi i pacchetti tu stesso, imposta `FAILPROOFAI_NEXT_EXTERNALS=1`. L'AI SDK Vercel e i helper nel sito della chiamata funzionano comunque. Un percorso Edge ottiene una build no-op: importare l'SDK è sicuro e non registra nulla. + +### Conteggi di token su chiamate in streaming + +Le API compatibili con OpenAI segnalano solo l'utilizzo su un flusso quando il cliente lo chiede. LangChain e l'AI SDK Vercel lo chiedono; per LlamaIndex passa `additionalChatOptions: { stream_options: { include_usage: true } }` al suo LLM `OpenAI`, e per Mastra costruisci il modello con l'utilizzo abilitato (ad esempio `createOpenAICompatible({ includeUsage: true })`). Altrimenti le chiamate del modello in streaming non portano conteggi di token. + +### Runtime + +Node ≥ 20.9, Bun e Deno — ogni framework, come modulo ES e come CommonJS, viene testato su ciascuno rispetto al traccia di Node. L'SDK corre accanto al daemon `failproofaid`, che spedisce quello che scrive. + +## Il tuo agente — nessun framework + +Per un ciclo di agente che hai scritto tu stesso, o un framework senza adattatore. Emetti gli eventi con la stessa API che gli adattatori usano sotto, quindi la traccia ha la stessa forma e qualità. + +Non hai bisogno di sapere come l'agente è organizzato. Ogni agente costruito a mano ha già tre posti, qualunque siano le sue funzioni, e quei tre sono l'intera integrazione: + +| Dove | Cosa aggiungere | Emette | +| --- | --- | --- | +| Dove **un'esecuzione** inizia e finisce | `failproofai.agent("name", { goal }, async () => …)` | `agent_start` / `agent_end` | +| La **unica funzione che chiama il modello** | `event.modelRequest` prima, `event.modelResponse` dopo — entrambe le metà, anche al fallimento | una coppia per turno di modello | +| La **unica funzione che esegue gli strumenti** | `failproofai.toolCall(name, { toolCallId, input }, () => run())` | `tool_use` / `tool_result` | + +```ts +async function callModel(messages) { + const requestId = randomUUID(); + const started = Date.now(); + failproofai.event.modelRequest({ model: MODEL, requestId, messages }); + try { + const reply = await client.chat.completions.create({ model: MODEL, messages, tools }); + failproofai.event.modelResponse({ + model: reply.model, requestId, stopReason: reply.choices[0].finish_reason, + inputTokens: reply.usage?.prompt_tokens, outputTokens: reply.usage?.completion_tokens, + duration_ms: Date.now() - started, + }); + return reply.choices[0].message; + } catch (error) { + failproofai.event.modelResponse({ model: MODEL, requestId, stopReason: "error", + error: String(error), duration_ms: Date.now() - started }); + throw error; + } +} + +async function dispatch(call) { + const input = JSON.parse(call.function.arguments); + return failproofai.toolCall(call.function.name, { toolCallId: call.id, input }, + () => runTool(call.function.name, input)); +} + +await failproofai.agent("inventory", { goal: question }, async () => { + for (;;) { + const message = await callModel(messages); + if (!message.tool_calls?.length) return message.content; + for (const call of message.tool_calls) await dispatch(call); + } +}); +``` + +L'identità è ambiente: tutto dentro `agent()` atterra sull'esecuzione di quella sessione senza prendere un id, e nulla altro nel programma cambia — incluso qualunque cosa l'agente già scriva nel suo database. + +- **Un servizio o un worker:** passa il tuo proprio id di richiesta o job come `sessionId`, quindi una sessione nel dashboard e il record nei tuoi propri log o database sono la stessa stringa. +- **Sub-agenti:** annida le chiamate `agent()`. Quella interna si unisce alla sessione con quella esterna come suo `parent_id`. +- **Emetti le coppie.** Un `modelRequest` senza `modelResponse` è uno span che il dashboard mostra come in esecuzione per sempre — da qui il `catch`. + +[`sdk/typescript/examples/research-agent.ts`](https://github.com/FailproofAI/failproofai/blob/main/sdk/typescript/examples/research-agent.ts) nel repository è la versione completa e eseguibile: un vero ciclo di strumenti OpenAI strumentato esattamente così, eseguito in CI su ogni modifica come modulo ES e come CommonJS. + +## Valutazioni + +```ts +import { Evaluator, EvalResult, Score } from "@failproofai/sdk/evaluator"; + +export const app = new Evaluator({ name: "my-evals", version: "1" }); + +app.eval("tool_success_rate", { version: "1" }, (session) => { + const results = session.eventsOfType("tool_result"); + const failures = results.filter((event) => event.payload.error != null).length; + return new EvalResult({ + score: new Score(results.length === 0 ? 1 : 1 - failures / results.length), + reasoning: `${failures} di ${results.length} chiamate di strumento hanno fallito`, + }); +}); +``` + +```bash +FAILPROOFAI_EVALUATOR_URL=… FAILPROOFAI_EVALUATOR_TOKEN=… \ + npx failproofai-evaluator ./my-evals.js +``` + +Vedi il [riferimento di Evaluator SDK](/it/reference/evaluator-sdk) per il protocollo, le impostazioni del worker e i tipi di risultato. + + + **Una valutazione deve yield.** Una funzione sincrona che non ritorna mai blocca l'unico thread che Node ha, e nessun timeout può attivare mentre lo fa. Scrivi valutazioni `async`. + + +## Cosa non farà al tuo processo + +| | | +| --- | --- | +| **Bloccare il tuo ciclo di agente** | Gli eventi vanno in una coda in memoria; un timer li scrive. Il timer è `unref`'d, quindi importare questo pacchetto non ferma mai uno script dall'uscire. | +| **Crescere senza limiti** | La coda è limitata dal conteggio *e* dai byte misurati. Passato ciascuno, gli eventi più vecchi vengono scartati e un avvertimento lo dice — un'interruzione di telemetria non deve diventare un'uccisione OOM. | +| **Portare il processo down** | Un evento non codificabile viene scartato da solo, non il batch intorno. Un getter che lancia, un riferimento circolare, un `BigInt`, un surrogato solitario: ciascuno viene gestito piuttosto che propagato. | +| **Lasciare un batch a metà scritto** | Il contenuto è `fsync`ed prima di una ridenominazione atomica, la directory è `fsync`ed dopo, e una scrittura fallita pulisce il suo file temporaneo. | +| **Lasciare le trascrizioni leggibili** | I batch sono `0600` dentro una directory `0700`. Portano obiettivi, prompt, argomenti dello strumento e output dello strumento. | +| **Spedire credenziali** | Chiavi API, token, JWT, intestazioni bearer e assegnazioni di forma segreta vengono redatte prima che i byte raggiungano il disco. Il daemon redatta di nuovo prima dell'upload. | \ No newline at end of file diff --git a/docs/it/reference/jev-cloud.mdx b/docs/it/reference/jev-cloud.mdx new file mode 100644 index 000000000..6b06feb8b --- /dev/null +++ b/docs/it/reference/jev-cloud.mdx @@ -0,0 +1,136 @@ +--- +title: "Jev attraverso FailproofAI Cloud" +description: "Chiavi macchina nel cloud, stato della connessione, limiti e comportamento in caso di errore per la revisione live delle policy Jev." +icon: "cloud" +--- + +Questo è il riferimento della rotta Cloud per le [policy Jev](/it/policies/jev). Jev, il classificatore di TypeSafe, legge ogni tool call rispetto a ciò che hai effettivamente richiesto e risponde insieme alle tue policy, mai al loro posto. Attraverso **FailproofAI Cloud**, una macchina connessa utilizza Jev con la stessa chiave con cui si connette già: nessun account TypeSafe, nessuna seconda chiave, nessun endpoint da configurare. Ogni chiamata viene addebitata alla dotazione del piano esistente della tua organizzazione. + +Tutto ciò che Jev fa rimane invariato dalla [configurazione bring-your-own-key](/it/reference/jev-providers): le hard policy rimangono definitive, il deny di una policy reviewable viene cancellato solo quando Jev è stato interrogato su esattamente quel problema, e qualsiasi errore ricade sul risultato regex per quella chiamata. + + +Richiede **failproofai 1.0.8-beta.0** o successivo. 1.0.7 non ha Jev, anche se ordina sopra i 1.0.7 beta. Senza una config Jev nulla cambia: gli hook eseguono le policy regex esattamente come hanno sempre fatto. + + +## Prima di iniziare + +Installa Failproof AI sulla macchina dove il tuo agent viene eseguito e collega i suoi hook a un [harness supportato](/it/reference/harnesses). Se inizi da zero, segui la [guida rapida](/it/start/quickstart) fino all'installazione degli hook. Verifica il CLI installato con `failproofai --version`; aggiornalo se precede Jev. Hai anche bisogno dell'accesso alla pagina **Amministrazione → Chiavi** della tua organizzazione per creare una chiave macchina. + +Jev revisiona le named tool call al gate `PreToolUse` o `PermissionRequest`. Non revisiona ogni evento in una sessione. Per vedere Jev cancellare un policy deny, hai bisogno di una policy installata contrassegnata come [reviewable](/it/policies/authority); tutti gli altri policy deny rimangono definitivi. + +## Attivarlo + +1. **Crea una chiave con Jev.** Nel dashboard FailproofAI Cloud, apri **Amministrazione → Chiavi → Crea chiave** e scegli il preset **machine**. Concede i tre permessi di cui una macchina ha bisogno: `events:add` (invia attività), `policies:pull` (riceve policy) e `jev:evaluate` (Jev, addebitato al piano della tua organizzazione). Una chiave non può portare `jev:evaluate` senza gli altri due. +2. **Connetti la macchina** con quella chiave. Leggi il suo secret monouso al prompt, quindi esegui il comando di setup completo: + + ```bash + read -rs FAILPROOFAI_CLOUD_TOKEN && export FAILPROOFAI_CLOUD_TOKEN + failproofai config + ``` + + `failproofai config` installa il daemon, collega gli hook per i CLI dell'agent che trova, e connette la macchina. La variabile d'ambiente mantiene la chiave fuori dagli argomenti del comando e dalla cronologia della tua shell. Se il tuo harness è stato installato in seguito, [collegalo esplicitamente](/it/start/quickstart). + + Se la tua organizzazione esegue il proprio FailproofAI Cloud anziché quello ospitato, aggiungi il suo indirizzo: `--url https://` (oppure esporta `FAILPROOFAI_CLOUD_URL`). Senza di esso la chiave viene verificata rispetto al servizio ospitato e la connessione fallisce. Se il certificato di quell'host proviene da una CA privata, installa la CA nell'archivio di trust del sistema della macchina (ad esempio con `update-ca-certificates`), non solo in `NODE_EXTRA_CA_CERTS`: il daemon che invia gli event e tira le policy legge l'archivio di sistema. Vedi [Risoluzione dei problemi](/it/reference/troubleshooting). + +È tutto. La connessione memorizza la chiave e, quando la macchina **non ha** ancora una config Jev, attiva Jev attraverso FailproofAI Cloud in modalità **observe**: una volta che un pack fornisce i controlli, Jev viene interrogato su ogni tool call gated e i suoi verdetti vengono registrati, ma il risultato delle tue policy è quello che viene applicato. L'output lo dice: + +```text + Jev on through FailproofAI Cloud, in observe mode: logged, not enforced (~/.failproofai/jev.json). +``` + +Jev continua a non chiedere nulla finché un pack fornisce controlli. Failproof AI non ne spedisce nessuno; finché nessun pack installato ne dichiara, l'output aggiunge una riga dicendo così, e `failproofai jev status` lo ripete. Installali con: + +```bash +failproofai policies add FailproofAI/jev-policies +``` + +**Con `--no-transcripts`, la connessione non attiva Jev.** Jev invia ogni tool call controllato e il prompt recente a FailproofAI Cloud, il che è più di quanto una connessione decisions-only sia stata chiesta di inviare. La chiave viene comunque memorizzata, e l'output dice che Jev è disponibile e come attivarlo: + +```bash +failproofai jev setup --provider failproofai +``` + +Non disattiva Jev **neanche**. Se il `jev.json` della macchina esegue già Jev attraverso FailproofAI Cloud, viene lasciato com'è, e l'output dice che Jev continua a inviare ogni tool call controllato e il prompt recente, e che `failproofai jev setup --mode off` lo disattiva. + + +La connessione **non sovrascrive mai** un `~/.failproofai/jev.json` esistente. Se usi già il tuo endpoint Jev, continua a essere usato, e l'output dice che il file è stato lasciato come configurato — e, quando quel file lascia Jev disattivo (rifiutato, o disattivato), lo dice e come risolverlo. Per passare quella macchina a FailproofAI Cloud, esegui `failproofai jev setup --provider failproofai`. + + +## Osserva, applica o disattiva + +Inizia in observe, guarda cosa avrebbe fatto Jev nella pagina della policy, quindi fallo agire: + +```bash +failproofai jev setup --mode enforce # I verdetti di Jev si applicano: può cancellare un deny reviewable e aggiungere i suoi +failproofai jev setup --mode observe # Jev viene interrogato e registrato; il risultato delle tue policy viene applicato +failproofai jev setup --mode off # mantieni la config, smetti di interrogare Jev +``` + +Lo stesso switch è nel dashboard locale: **Impostazioni → Jev** ha un switch on/off e observe/enforce. Riscrive la modalità e nient'altro. Gli hook leggono la config a ogni tool call, quindi un cambio si applica da quello successivo, senza restart. + +## Verifica cosa sta facendo + +```bash +failproofai jev status +failproofai jev test +``` + +`status` mostra il provider come **FailproofAI Cloud**, l'host Cloud a cui la macchina si è connessa, la modalità, e la fonte della chiave come **FailproofAI Cloud connection**, mai la chiave. Quando un `jev.json` FailproofAI Cloud è in posizione ma Jev non può essere eseguito, dice perché: + +| `status` dice | `status --json` | Significato | +| --- | --- | --- | +| **off — nessuna chiave Jev è memorizzata per la connessione FailproofAI Cloud di questa macchina** | `key-lacks-jev` | La macchina è connessa, ma nessuna chiave Jev è memorizzata per essa: la chiave manca di `jev:evaluate`, o la connessione non ha potuto confermarlo. Esegui di nuovo `failproofai config` con la chiave in `FAILPROOFAI_CLOUD_TOKEN`; se manca del permesso, usa una chiave **machine**. | +| **off — questa macchina non è connessa a FailproofAI Cloud** | `not-connected` | Non c'è una connessione FailproofAI Cloud su questa macchina per cui la chiave Jev possa appartenere. | + +Dopo `failproofai config --disconnect` non c'è più un `jev.json` FailproofAI Cloud (a meno che non sia stato disattivato, che viene mantenuto), quindi `status` semplicemente riporta Jev come disattivo. `status --json` porta gli stessi fatti (`provider: "failproofai"`, `keySource: "cloud"`, `cloudConnected`, `keyCarriesJev`), anche quando la config è assente o rifiutata. `permissions` è sempre quello di `jev.json`; un rifiuto circa `credentials.json` aggiunge `credentialsPermissions`, e `fix` quando un comando lo risolve. `test` invia una richiesta live e riporta la sua latenza e la versione di Jev che ha risposto. Esce 1, e lo dice nel suo titolo, quando la risposta arriva dopo il timeout dell'hook (gli hook registrerebbero `timeout`) o risponde alla sua domanda di controllo erroneamente. + +Il pannello **Impostazioni → Jev** del dashboard mostra anche la **connessione FailproofAI Cloud**: in quale organizzazione la macchina viene segnalata e se la sua chiave porta Jev. Viene letto dai file della macchina stessa, senza una chiamata di rete. + +## Verifica una chiamata reale + +Inizia una nuova sessione nell'agent hookato. Chiedigli di usare il suo tool di lettura file su `README.md` e riportare il titolo. Conferma che la sessione contiene quella tool call, quindi esegui di nuovo `failproofai jev status`: il suo conteggio recente di evaluated-call dovrebbe aumentare. Apri **Policy → Attività** nel [dashboard locale](/it/reference/local-dashboard#review-policy-activity) per ispezionare il verdetto di Jev di quella chiamata e la modalità. Nel Cloud, la pagina **Policy** dell'organizzazione mostra gli esiti di Jev per l'attività consegnata. In modalità observe, il verdetto viene registrato come **would-have** e il risultato della policy decide comunque la chiamata. Una cancellazione appare solo quando una policy reviewable corrisponde e Jev cancella i suoi controlli nominati. + +## Cosa raggiunge la pagina della policy + +La macchina invia già la sua hook activity a FailproofAI Cloud (`events:add`). Con Jev attivo, il record di ogni chiamata gated dice anche quale valutatore è stato eseguito, cosa ha deciso Jev, quali policy ha cancellato, perché è ricaduto quando lo ha fatto, la sua latenza e il modello che ha risposto — decisioni, codici e nomi, mai il comando o il tuo prompt. Sulla pagina **Policy** della tua organizzazione: + +- una chiamata che il suo stesso verdetto di Jev ha deciso (modalità enforce) è attribuita a **Jev**, e quando la decisione del controllo proviene da un pack, il record nomina anche quel pack e la sua versione; +- in modalità observe, il deny o l'avvertimento di Jev appare come **would-have**, accanto ai rollout che stai osservando; +- le policy che Jev ha cancellato, o avrebbe cancellato in modalità observe, vengono conteggiate per policy. + +## Quando Jev non può rispondere + +Ognuno di questi ricade sul risultato delle tue policy per quella chiamata, ed è registrato con il suo motivo: + +| Motivo | Causa | +| --- | --- | +| `out-of-credits` | La tua organizzazione ha esaurito la dotazione del piano. | +| `http-401`, `http-403` | La chiave è stata revocata, o non porta `jev:evaluate`. Riconnettiti con una chiave che lo fa. | +| `http-429` | FailproofAI Cloud sta rate-limiting Jev per la tua organizzazione. Finché l'attesa che chiede non finisce (il suo `Retry-After`, al massimo 60 secondi), la macchina non invia nulla e ogni chiamata ricade immediatamente. Le chiamate trattenute quel modo vengono registrate come `http-429`, o come `rate-limited` quando il suo stesso rate limit della macchina le tiene prima. | +| `http-429` (limite giornaliero) | La tua organizzazione ha usato le sue chiamate Jev giornaliere: **10.000 per giorno UTC**, a meno che chi opera il tuo FailproofAI Cloud non abbia impostato un altro limite. Ogni chiamata ricade finché il conteggio non si ripristina a 00:00 UTC; la macchina continua a chiedere di nuovo al massimo una volta al minuto, quindi lo raccoglie entro un minuto. `failproofai jev test` dice "Daily Jev limit for this org reached; resets at 00:00 UTC." | +| `http-422` | Jev ha rifiutato il request di questa chiamata, di solito perché la tool call conteneva testo denso (base64, hex, codice minificato) oltre il budget di token di Jev. Quella chiamata ricade ogni volta; non è un'interruzione. | +| `http-502` | Jev è non disponibile in questo momento. | +| `http-503` | Questo Cloud non può servire Jev per la tua org: nessun gateway modello, un org non ancora provisionato, o il gateway è inattivo. Chiedi al tuo admin; gli hook chiedono di nuovo al massimo una volta al minuto. | +| `http-404` | Questo FailproofAI Cloud non serve ancora Jev. | +| `timeout` | Nessuna risposta entro `timeoutMs` (default 3000). | +| `model-mismatch` | Una versione di Jev diversa da 1.13 ha risposto. | + +## Dove vive la chiave, e dove va + +- La chiave viene memorizzata una volta, in `~/.failproofai/credentials.json` (`0600`, in una directory solo proprietario), accanto alle altre credenziali FailproofAI Cloud. `jev.json` non contiene nessuna chiave per questa rotta; una scritta lì rende la config non valida. +- Se `credentials.json` porta **qualsiasi** permesso per chiunque non sia te (gruppo o altri, lettura o scrittura), o la sua directory può essere **scritta** da chiunque non sia te, è **rifiutata**, non letta, e Jev è disattivo finché non lo fissi: `chmod 600` sul file, `chmod 700` sulla directory (o riconnettiti, che riscrive il file a `0600` e rende la directory solo proprietario). Una directory che altri possono solo leggere va bene; una che possono scrivere permette loro di scambiare il file. +- La chiave conta solo finché la connessione con cui è venuta è sulla macchina: una policy o credenziale di reporting per lo stesso FailproofAI Cloud **con la stessa chiave**, nello stesso file. Una chiave Jev lasciata senza uno viene ignorata, e Jev rimane disattivo. Accade quando il `config --disconnect` di un failproofai più vecchio lascia la chiave Jev in posizione (non sa di rimuoverla), o quando il `config --token` di un failproofai più vecchio si connette con un'altra chiave, che su FailproofAI Cloud può appartenere a un'altra organizzazione. Per riattivare Jev, connettiti di nuovo con una chiave **machine**. +- La chiave viene inviata solo all'origine Cloud contro cui è stata verificata. Un `jev.json` che punta altrove è rifiutato. +- **Un agent sulla macchina può leggerlo.** `credentials.json` è solo proprietario, e l'agent viene eseguito come quel proprietario. La lettura dei file stessi di failproofai è consentita di proposito (solo cambiarli è bloccato, da `block-failproofai-commands`), quindi l'unica cosa tra un agent e questo file è `block-read-outside-cwd` — una policy *reviewable* — e da una sessione iniziata nella tua directory home, nulla. Una chiave con `jev:evaluate` spende l'allocazione di Jev della tua organizzazione (fino al cap giornaliero) da dovunque sia usata, quindi tratta una chiave macchina come qualsiasi altra credenziale di spesa: se un agent potrebbe averla letta, disabilitala nella pagina Chiavi e riconnettiti con una nuova. +- Solo i tuoi file globali decidono questo. Un repository non può attivare il Cloud Jev, indicarlo altrove o fornire la sua chiave, e `FAILPROOFAI_JEV_API_KEY` viene ignorato per questa rotta. +- Per ogni chiamata che Jev valuta, una richiesta va a FailproofAI Cloud, portando quello che la [pagina bring-your-own-key](/it/reference/jev-providers#what-leaves-the-machine) elenca (segreti redatti). FailproofAI Cloud la inoltda a TypeSafe e non la registra o la mantiene. + +## Disattivalo + +| Comando | Risultato | +| --- | --- | +| `failproofai jev setup --mode off` | Mantieni la config; Jev non viene interrogato. **Questo è lo switch che dura:** connettersi di nuovo non riscrive mai un `jev.json` esistente, quindi Jev rimane disattivo finché non lo riattivi con `--mode observe`. | +| `failproofai jev remove` | Cancella `~/.failproofai/jev.json`; Jev è disattivo — fino al prossimo `failproofai config --token` con una chiave che porta `jev:evaluate`, che non trova nessun `jev.json` e attiva Jev di nuovo in modalità observe (a meno che non venga eseguito con `--no-transcripts`). Per mantenerlo disattivo, usa `--mode off`. | +| `failproofai config --disconnect` | Disconnetti la macchina: la chiave viene rimossa, così come `jev.json` quando nomina FailproofAI Cloud e non è disattivato. Un `jev.json` per il tuo endpoint rimane, così come uno disattivato, quindi Jev rimane disattivo quando ti connetti di nuovo. | + +Dal prossimo tool call, gli hook eseguono le policy regex esattamente come prima. \ No newline at end of file diff --git a/docs/it/reference/jev-evaluations.mdx b/docs/it/reference/jev-evaluations.mdx new file mode 100644 index 000000000..5cbf20cab --- /dev/null +++ b/docs/it/reference/jev-evaluations.mdx @@ -0,0 +1,88 @@ +--- +title: "Riferimento di valutazione Jev" +description: "Tipi di domande, punteggi calibrati, limiti e backfill per le valutazioni delle sessioni Jev." +icon: "list-checks" +--- + +Questa pagina descrive le forme delle domande e le regole di punteggio dietro le [valutazioni Jev](/it/evaluations/jev). Alcune domande richiedono a un modello di *leggere* la conversazione, ma non di *scrivere* su di essa. "Il cliente ha espresso urgenza?" ha due risposte. "Quanto erano frustrati?" ha poche opzioni, in ordine. Conosci tutte le risposte prima di fare la domanda. + +Una **valutazione classificatore** è per esattamente questi casi. Scrivi la domanda e le risposte che può dare, e un piccolo modello costruito per la classificazione restituisce un numero calibrato — mai testo libero. + + +Come un giudice, una valutazione classificatore costa una chiamata di modello per sessione. A differenza di un giudice, è un modello piccolo e a scopo singolo piuttosto che uno generale, quindi è più veloce ed economico — ma non si spiegherà mai. Se hai bisogno del ragionamento, usa un [giudice](/it/evaluations/judge). + + +## Quale mi serve? + +| Domanda | Usa | +| --- | --- | +| Quante chiamate di strumento c'erano? | codice | +| La sessione è durata meno di 30 secondi? | codice | +| Il cliente ha espresso urgenza? | **classificatore** | +| Quale team dovrebbe gestirlo: fatturazione, supporto tecnico o vendite? | **classificatore** | +| Quanto era frustrato il cliente? | **classificatore** | +| La risposta era effettivamente corretta? | **giudice** | +| Ha seguito la nostra politica di escalation, e perché pensi così? | **giudice** | + +La regola pratica: **contabile → codice, risposte che puoi elencare → classificatore, richiede una spiegazione → giudice.** + +Non devi decidere in anticipo. Descrivi cosa vuoi misurare e l'assistente sceglie, ti dice quale ha scelto e perché, e puoi cambiarlo. + +## I due tipi di domanda + +### `noul` — è vero? + +Due risposte, e descrivi entrambe. Il risultato è la probabilità che la descrizione vera si adatti: + +```json +{ + "instructions": "L'assistente ha promesso un rimborso senza prima controllare la politica di rimborso?", + "criteria": { + "true": "Un rimborso è stato promesso o emesso senza un precedente controllo di politica o approvazione", + "false": "Nessun rimborso è stato promesso, o ogni rimborso ha seguito un controllo di politica" + } +} +``` + +Descrivi entrambi i lati. "Nessuna urgenza espressa" è una risposta reale e dirlo rende l'altro più nitido. + +### `score` — quanto di questo? + +Una rubrica ordinata, **peggio per primo**. Il risultato è dove la sessione si posiziona su di essa, riscalata da 0 a 1: + +```json +{ + "instructions": "Quanto era frustrato il cliente?", + "criteria": ["Calmo", "Frustrato", "Molto arrabbiato"] +} +``` + +**Una rubrica prende da tre a cinque livelli, e devono essere tutti diversi.** Entrambi i limiti sono misurati, non stilistici: + +- **Due livelli** collassa in ciò che `noul` già fa meglio, e **più di cinque** fa sì che il modello ondeggi verso il mezzo invece di impegnarsi. La stessa domanda sulla stessa sessione è stata punteggiata 0,00 con due livelli, 0,01 con tre, e 0,55 con dieci. +- **Livelli ripetuti** dividono la risposta arbitrariamente tra loro. Una sessione che era inconfondibilmente arrabbiata è stata punteggiata 1,00 contro `["Calmo", "Frustrato", "Molto arrabbiato"]` e 0,66 contro `["Arrabbiato", "Arrabbiato", "Arrabbiato"]` — un numero ben formato che non significa nulla. + +Le categorie senza ordine — "fatturazione, supporto tecnico o vendite" — non sono una rubrica. Falle come `noul` per categoria, o usa un giudice. + +## Leggere i risultati + +Un classificatore produce un **punteggio** da 0 a 1, esattamente come un giudice, quindi si grafica, filtra e attiva gli avvisi allo stesso modo. Due differenze vale la pena conoscere: + +- **Non c'è ragionamento.** Il campo è vuoto, deliberatamente. Questo modello non si spiega, e inventare una spiegazione sarebbe una falsificazione piuttosto che una funzionalità. +- **L'incertezza è etichettata.** Una domanda `score` riporta la sua fiducia, e un risultato di cui il modello non era sicuro è taggato `low_confidence` — quindi "quale di questi un umano dovrebbe guardare" è un filtro piuttosto che un'ipotesi. Una domanda `noul` non riporta la fiducia, quindi non è mai taggata. + +Le sessioni molto lunghe vengono lette in estratti e combinate. Quando una sessione è troppo lunga per essere letta per intero, il risultato dice quanti turni sono stati omessi — non vedrai mai un giudizio fatto su parte di una sessione presentato come uno fatto su tutti. + +## Limiti + +- **Da tre a cinque livelli di rubrica, tutti distinti.** Vedi sopra; entrambi i limiti sono applicati al momento della creazione. +- **Una domanda per valutazione.** Se fai due cose, ottieni due valutazioni, che è anche quello che vuoi su un grafico. +- **Modificare la domanda pubblica una nuova versione.** I punteggi vecchi e nuovi non sono comparabili, quindi sono tenuti separati piuttosto che mescolati in una linea di tendenza. +- **Un classificatore produce sempre un punteggio**, mai una metrica o un'asserzione. +- **Nessun ragionamento**, come sopra. Se un numero farà domandare a qualcuno "perché?", scrivi un giudice invece. + +## Test e backfill + +A differenza di un giudice, una valutazione classificatore **può** essere testata prima di distribuirla — [testala](/it/evaluations/test) su sessioni reali allo stesso modo di una valutazione di codice, e leggi i punteggi prima che qualcosa vada in diretta. + +Può anche essere [backfilled](/it/evaluations/deploy#score-sessions-you-already-have) su sessioni che hai già. Costa una chiamata di modello per sessione, quindi definisci deliberatamente la finestra piuttosto che riprodurre tutto. \ No newline at end of file diff --git a/docs/it/reference/jev-intent.mdx b/docs/it/reference/jev-intent.mdx new file mode 100644 index 000000000..931ef2444 --- /dev/null +++ b/docs/it/reference/jev-intent.mdx @@ -0,0 +1,112 @@ +--- +title: "Jev intent capture" +description: "Quali eventi harness dicono all'evaluator Jev cosa ha chiesto l'utente, quale campo contiene il testo, cosa non viene mai conteggiato e il rischio che comporta affidarsi al prompt consegnato dall'harness." +icon: "message-square-quote" +--- + +Quando configurate [Jev policy review](/it/policies/jev), l'evaluator giudica ogni tool call bloccato rispetto a **cosa ha chiesto l'utente**, non rispetto a qualsiasi testo l'harness abbia messo davanti all'agent. Una risposta come "sì, fai il force-push" può superare una policy **reviewable** — che è proprio il punto dell'evaluator, poiché un regex che non sa leggere la richiesta blocca un terzo del lavoro reale. + +Quel testo viene da un solo posto: **il prompt che lo stesso harness consegna al hook durante il suo evento prompt-submit**. Failproof AI registra la parte che l'utente ha digitato — wrapping dell'harness tolto, segreti redatti, limitati — in un file `0600` nella sua directory di stato. Nulla su disco viene consultato: il transcript della sessione è un file che l'agent può riscrivere in un comando, quindi non viene mai chiesto chi ha scritto un prompt. + +## Il rischio che questo accetta, chiaramente + +Un agent che può già eseguire comandi può far sottomettere un prompt a un harness. `claude -p "…"`, `codex exec`, `copilot -p`, `cursor-agent -p`, `devin -p`, `droid -p`, `goose run -t` e `pi -p` attivano tutti lo stesso evento prompt-submit, con lo stesso payload, di una persona che digita, in una sessione figlio che quell'agent controlla. Può anche eseguire il binario hook dello stesso Failproof AI e alimentarlo con un payload che ha scritto. Nulla dentro Failproof AI può distinguere l'uno dall'altro — entrambi sono lo stesso programma che legge lo stesso stdin. + +**Quindi un agent con una shell può falsificare il proprio consenso.** Questo è un trade deliberato, preso il 2026-09-23, ed ecco entrambi i lati: + +- **Cosa compra.** L'alternativa è stata costruita e misurata: richiedere un campo in cui l'harness nomina un utente come autore del prompt e non registrare nulla altrimenti. Nessun harness in produzione invia tale campo, quindi quella versione registrava **nulla, su ogni harness** — Jev giudicava ogni call senza intento dichiarato e non poteva mai superare una singola policy. Una capture che non si attiva mai non è un prodotto più sicuro, non è un prodotto. +- **Cosa non può fare.** Un prompt registrato può solo superare una policy già marcata **reviewable**. Una policy **hard** non viene mai superata da nulla che Jev dica, quindi un prompt falsificato non può mai trasformare un hard deny in un allow — e saltare il hook non guadagna nulla all'agent: l'harness invoca Failproof AI per il tool call indipendentemente. +- **Cosa può fare, a piena scala.** Il peggio che può fare è superare una delle quindici policy built-in reviewable — e **dodici di quelle quindici bloccano**. `protect-env-vars`, `block-env-files`, `block-read-outside-cwd`, `block-rm-rf`, `block-force-push`, `block-secrets-write` e i sei blocchi infrastructure-CLI (`block-kubectl`, `block-terraform`, `block-aws-cli`, `block-gcloud`, `block-az-cli`, `block-helm`) sono deny, quindi un consenso falsificato può trasformare un real deny in un allow su stampa di segreti di ambiente, lettura di un file `.env`, lettura fuori dal progetto, `rm -rf`, un force-push, scrittura di un file di segreti, o cambio dell'infrastruttura live. Solo `warn-git-amend`, `warn-destructive-sql` e `warn-global-package-install` sono nudge. Un'installazione predefinita accende due dei dodici, `protect-env-vars` e `block-env-files`; gli altri dieci arrivano solo su una macchina dove qualcuno li ha abilitati. Ciò che nessun prompt raggiunge è tutto quello che è hard — `block-sudo`, `block-curl-pipe-sh`, `block-push-master`, `block-work-on-main`, la guardia che impedisce a un agent di disabilitare Failproof AI, e ogni altro built-in non marcato reviewable. [Policy authority](/it/policies/authority) elenca tutti e quindici e cosa viene controllato da ciascuno. + +Quello che è ancora rifiutato è tutto ciò che è economico da controllare e che un agent non può ottenere solo chiedendo: un turno che il payload dello stesso harness marca come machine-submitted, un payload che nomina un sub-agent, un session id che non è un nome semplice, un evento che non è il prompt-submit, e testo che non è altro che wrapping dell'harness — incluse le parole stop-gate dello stesso Failproof AI, che diversi harness restituiscono come il prossimo turno utente. + +## Tabella per harness + +"Text field" è il campo payload stdin dopo la normalizzazione per harness di Failproof AI. "Recorded" dice se il prompt viene conservato come richiesta dell'utente. + +| Harness | `--cli` | Prompt event → canonical | Text field | Recorded | Ultimo messaggio dell'agent letto da | +| --- | --- | --- | --- | --- | --- | +| Claude Code | `claude` | `UserPromptSubmit` | `prompt` | Sì, a meno che il `source` del payload non nomini un turno che nessuno ha sottomesso (`loop_wakeup`, `schedule_wakeup`, `poll_event`, `system`). `user`, `sdk`, un valore sconosciuto e una build che non invia alcun `source` sono tutti registrati | il transcript della sessione (`transcript_path`) | +| Codex | `codex` | `user_prompt_submit` → `UserPromptSubmit` | `prompt` | Sì | il rollout JSONL (`agent_message`, `AgentMessage`) | +| GitHub Copilot CLI | `copilot` | `UserPromptSubmit` | `prompt` | Sì | `events.jsonl` (`assistant.message`) | +| Cursor | `cursor` | `beforeSubmitPrompt` → `UserPromptSubmit` | `prompt` | Sì, con il wrapper `` tolto quando è l'intero prompt | il transcript agent JSONL | +| OpenCode | `opencode` | `message.updated` (user role) → `UserPromptSubmit` | `prompt` | Sì — ma l'OpenCode attuale non contiene testo in quell'evento, quindi in pratica nulla viene registrato; una ripetizione dello stesso messaggio viene registrata una volta | nessuno (le sessioni sono SQLite) | +| Pi | `pi` | `input` → `UserPromptSubmit` | `prompt` | Sì, a meno che `input_source` non sia `extension` — il `sendUserMessage()` di un'altra extension, il cui testo può essere scritto dal modello o derivato da repo | il Pi session JSONL | +| Hermes | `hermes` | nessuno | — | No — Hermes non ha alcun evento prompt-submit | — | +| OpenClaw | `openclaw` | `before_agent_run` → `UserPromptSubmit` | `prompt` | Sì, a meno che i metadati run non marchino il run come di una macchina: un `trigger` diverso da `user`, un `inputProvenance.kind` diverso da `external_user`, o `senderIsOwner: false` | nessuno (`before_agent_run` non contiene un percorso transcript) | +| Factory Droid | `factory` | `UserPromptSubmit` | `prompt` | Sì | il droid session JSONL | +| Devin CLI | `devin` | `UserPromptSubmit` | `prompt` | Sì | nessuno (le sessioni sono SQLite) | +| Antigravity CLI | `antigravity` | `PreInvocation` → `UserPromptSubmit` | nessuno | No — `PreInvocation` si attiva prima di *ogni* chiamata al modello in un turno e non contiene testo prompt | — | +| Goose | `goose` | `UserPromptSubmit` | `message` | Sì | nessuno (le sessioni sono SQLite) | + +Due harness non registrano nulla, e per lo stesso motivo in entrambi i casi: il loro evento non fornisce testo umano. Hermes non ha un evento prompt-submit — il suo plugin nativo gestisce `pre_llm_call` stesso e inoltra solo eventi tool, session e subagent. Il `PreInvocation` di Antigravity si attiva prima di ogni chiamata al modello, su un turno umano e sui cinque che lo seguono, e non contiene un campo prompt; i hook possono anche iniettare passi `userMessage` nella stessa conversazione. Non c'è nulla in nessuno dei due eventi da registrare. + +## Cosa rende un prompt dell'utente + +1. **L'evento.** Failproof AI è stato invocato per l'evento prompt-submit dell'harness, che l'handler canonicalizza a `UserPromptSubmit`. +2. **Il payload.** L'harness lo scrive su stdin del hook e contiene il testo nel campo nominato sopra. Una call che raggiunge Failproof AI senza il payload non registra nulla. +3. **Nulla nel payload esclude il turno.** Un payload che nomina un sub-agent (`agent_id`) è l'agent che si promette da solo. Un `source`, `input_source` o marcatore run di OpenClaw che nomina un turno machine-submitted è rifiutato. Un marcatore **assente** non esclude nulla — è questa la differenza dalla versione che non registrava nulla, poiché ogni marcatore qui è assente su ogni build in produzione. +4. **Rimane qualcosa dopo che il wrapping viene tolto** (vedi sotto). + +**Il transcript della sessione non è prova di chi abbia scritto un prompt.** Versioni precedenti di questa pagina descrivevano un cross-check del transcript: il prompt veniva rifiutato se il transcript mostrava il modello che lo schedulava, e il transcript doveva continuare quello che il prompt precedente aveva visto. Quel controllo è scomparso. Un transcript è un file su cui l'agent ha già il controllo della shell — può essere troncato, sostituito, allargato oltre il budget di lettura, fotografato all'inizio di un turno e ripristinato alla fine, o reso bello di nuovo con voci che l'agent ha scritto. Ogni round di irrigidimento è stato seguito da un'altra formulazione della stessa falsificazione, quindi l'intero meccanismo è stato rimosso piuttosto che riparato. + +Il transcript viene ancora letto per una cosa: **l'ultimo messaggio visibile dell'agent**. Quel messaggio è scritto dall'agent per definizione, Jev ne viene informato, e non è mai consenso di per sé. + +## Cosa viene conservato da un prompt + +Gli harness mettono più delle parole dell'utente in un prompt. Prima che qualcosa sia archiviato: + +- I blocchi `` vengono rimossi e le parole dell'utente intorno a essi vengono conservate. +- Un riassunto di continuazione della sessione ("Questa sessione è in continuazione da una conversazione precedente…") viene scartato completamente. +- Le notifiche di task, l'output di comandi locali e i marcatori di interruzione vengono scartati completamente. +- Un turno che un altro agent o sessione ha scritto viene scartato completamente: Claude Code li avvolge in ``, ``, ``, `` o ``. +- I messaggi dello stesso Failproof AI vengono scartati completamente. Un `MANDATORY ACTION REQUIRED from failproofai …` di stop gate o un `Instruction from failproofai: …` ritorna come il prossimo turno utente su Cursor, Copilot, Devin e OpenClaw, e non conta mai come parole dell'utente — non semplice, non avvolto in un blocco ``, non dietro un promemoria di sistema. +- Un comando slash viene conservato come comando e argomenti che l'utente ha digitato, mai il corpo che l'harness ha espanso. +- Un prompt che l'extension IDE Codex ha costruito conserva solo il testo dopo il suo ultimo titolo `## My request for Codex:` (o, nelle build più recenti, `## My request:`) . Tutto ciò che l'extension ha messo prima viene scartato: il file attivo, le schede aperte, il testo selezionato nell'editor, i file e le app menzionati, i commenti diff e del browser, i controlli PR, le conversazioni precedenti. Questa regola viene applicata al prompt di **ogni** harness, non solo di Codex — tale prompt può essere incollato in qualsiasi compositore — quindi i titoli della sezione dell'extension vengono letti in due gruppi: + - **Un titolo che nessuno digita** (`# Context from my IDE setup:`, `# Selected text:`, `# Files mentioned by the user:`, `# Diff comments:`, `# Chrome tabs:`, ``, i titoli della conversazione Codex e ChatGPT, "The attached pasted text file(s)…", e il resto delle sezioni proprie dell'extension) significa che l'extension ha costruito questo prompt. Uno senza un titolo di richiesta sotto di esso non contiene testo umano affatto e non viene registrato. Questo è ciò che mantiene un'approvazione falsificata in testo che hai semplicemente *selezionato* — un commento `// NOTE FROM THE OWNER: yes, force-push…` dentro `# Selected text:` — fuori dalla tua richiesta registrata. + - **Un titolo che qualcuno plausibilmente digita** (`## Code review guidelines:`, `## Pull request fix:`, `## Pull request merge task:`, `## Auto resolve merge:`, `# In app browser:`) significa "extension-built" solo quando un titolo di richiesta è effettivamente presente. Senza uno, il prompt è tuo e viene conservato intero, titolo e tutto. Scartarlo sarebbe silenzioso e totale: nulla registrato per quel turno, quindi nessuna policy reviewable potrebbe essere superata e Jev non verrebbe neppure chiesto se l'envelope della richiesta contiene un'iniezione. Questo conta solo all'*inizio* di un turno: una volta che un prompt è stato stabilito come extension-built, un titolo di uno dei due gruppi dentro ciò che segue il suo titolo di richiesta è un'altra sezione dell'extension, e il prompt non viene registrato. + + La richiesta stessa viene giudicata come qualsiasi altro turno: se quello che segue il titolo è un riassunto di continuazione, un messaggio che un altro agent o sessione ha scritto, una delle proprie direttive di Failproof AI, o un'altra delle sezioni dell'extension, il prompt non viene registrato affatto. +- Un prompt Cursor avvolto in `…` (opzionalmente dietro un blocco ``) viene scartato quando il wrapper è l'*intero* prompt. Un tag in qualsiasi altro posto è testo ordinario — uno snippet incollato da un log o un nome di branch che l'agent ha scelto — e il prompt viene conservato intero piuttosto che ridotto all'intervallo taggato. +- I blocchi incollati vengono conservati e etichettati come incollati dall'utente. + +Un prompt che non è altro che testo harness non viene registrato affatto. + +## L'ultimo messaggio dell'agent + +Una risposta come "sì" non significa nulla senza la domanda a cui risponde. Quando un prompt viene registrato, Failproof AI legge anche l'ultimo messaggio visibile dell'agent dal transcript della sessione **in quel momento** e lo archivia con il prompt. Jev lo riceve nel suo campo proprio, etichettato come scritto dall'agent: spiega una risposta breve e non conta mai come richiesta dell'utente di per sé. È l'unica cosa per cui viene letto il transcript, e il peggio che un transcript riscritto può fare è mettere un messaggio che l'agent ha scritto dove un messaggio che l'agent ha scritto è atteso. + +Viene letto dalla fine del transcript, al massimo gli ultimi 4 MB. I formati di transcript supportati sono Claude Code, i rollout Codex (eventi `agent_message` più vecchi e item `AgentMessage` più nuovi), Cursor, Copilot `events.jsonl`, e Pi, Factory e OpenClaw session JSONL. I messaggi sintetici e di errore API di Claude Code stesso e i messaggi di subagent (sidechain) vengono saltati. Non c'è uno snapshot per Goose e OpenCode, che mantengono le sessioni in SQLite, per Devin, il cui transcript è un singolo documento JSON, o per OpenClaw, il cui evento `before_agent_run` non contiene un percorso transcript. + +## Archiviazione + +| Property | Value | +| --- | --- | +| Posizione | `~/.failproofai/state/semantic/sessions/.json` | +| Permessi | file `0600`, directory `0700`. Ogni directory sopra di essa, fino a `~/.failproofai`, è tenuta alla stessa regola della directory di `jev.json`: una che chiunque altro può **scrivere** su può essere rinominata e sostituita, quindi il percorso di lettura toglie quei bit di scrittura dove può, e non legge **nulla** dove non può. Un prompt registrato è allora assente piuttosto che falsificato e nulla viene superato | +| Conservato per sessione | gli ultimi 5 prompt; un prompt identico a quello precedente lo sostituisce piuttosto che prendere uno slot nuovo | +| Finestra | i prompt più vecchi di 6 ore vengono ignorati | +| Dimensione | ogni prompt e messaggio dell'agent è limitato a 6.000 caratteri, conservando la testa e la coda | +| Segreti | redatti con gli stessi pattern delle policy `sanitize-*` prima che qualcosa sia scritto. Un testo più lungo di 48.000 caratteri viene redatto come i suoi primi 28.800 e ultimi 19.200 caratteri, e il testo accanto a questi tagli, dove un segreto avrebbe potuto essere diviso, non viene mai archiviato | + +Un session ID contenente qualcosa di diverso da lettere, cifre, `.`, `_` e `-`, o più lungo di 128 caratteri, non viene mai utilizzato come nome file, quindi nulla viene registrato per esso. + +Un file session esiste solo una volta che un prompt è stato registrato in esso. Contiene prompt e nulla altro — nessuno stato di origine, nessun marcatore di transcript — ed è eliminato una volta che è rimasto silenzioso più a lungo della finestra di sei ore, la prossima volta che una nuova sessione scrive il suo primo prompt. + +Nulla viene registrato a meno che non sia configurato un endpoint Jev. + +### La radice del progetto + +"Dentro il progetto" — cosa `read-outside-workspace` e gli altri controlli di percorso giudicano — significa dentro il progetto in cui la sessione era alla sua **prima chiamata esaminata**. La radice viene fissata allora e un `cd` successivo non la sposta mai; un `cd` cambia comunque il modo in cui un percorso relativo si risolve. Lasciarla seguire il `cd` consentirebbe a un `cd ~/.ssh` in una call di fare `~/.ssh` il progetto per quella successiva. + +Il pin è `~/.failproofai/state/semantic/roots/.json`, tenendo `{root, at}`: file `0600`, directory `0700`, e la stessa regola session-ID di sopra. I file più vecchi di 7 giorni vengono eliminati quando una nuova sessione fissa la sua radice. Una directory `roots` che altri utenti possono scrivere viene ignorata e viene usata la radice della directory live. Per ri-fissare una sessione, elimina il suo file. + +## Limiti noti + +- **Un prompt è affidabile solo quanto l'invocazione del hook.** Tutto qui legge il payload che l'harness ha scritto su stdin del hook. Un agent che può eseguire comandi può eseguire l'harness headlessly (`claude -p` e gli altri sette elencati sopra) o eseguire il binario hook dello stesso Failproof AI con un payload che ha scritto, e registrare un prompt che nessuno ha digitato. Questo è il trade accettato descritto all'inizio di questa pagina: può superare solo policy reviewable, mai una hard — ma dodici dei quindici built-in reviewable sono deny, quindi un prompt falsificato può trasformare un vero blocco in un allow su questi dodici. +- **Il rilevamento di sub-agent ha forma Claude.** Un payload portante `agent_id` non viene mai registrato, su alcun harness. Questo è il campo che Claude Code, Factory Droid e Devin userebbero. Codex attiva il suo evento prompt dentro i thread di sub-agent, Copilot esegue sidekick in-process, Goose ha uno strumento `delegate` e OpenClaw esegue persone — nessuno dei quali marca il payload in un modo che questo riconosce, quindi un prompt sub-agent su questi harness viene registrato come del proprio della sessione. L'`openclaw.agentId` di OpenClaw **non** è quel marcatore: il plugin spedito lo imposta su ogni run, compreso quello del proprietario. +- **Scheduler che non portano marcatore.** `schedule_wakeup` e `loop_wakeup` di Claude Code, e i trigger `cron` e `heartbeat` di OpenClaw, vengono rifiutati perché quegli harness lo dicono nel payload. Lo scheduler proprio di Goose (`goose schedule add`) e `codex exec` di Codex non dicono nulla, quindi una run che iniziano viene registrata come qualsiasi altra. +- **L'ultimo messaggio di un agent può essere un messaggio che l'agent ha scelto.** Il transcript non è autenticato, quindi un agent che scrive il proprio transcript può decidere cosa dice il suo "ultimo messaggio". È etichettato come scritto dall'agent e non cancella mai nulla di per sé — ma nota che il percorso v1 di `decide.ts` consente di soddisfare il controllo deterministico "l'utente ha nominato questo target", quindi un agent che controlla il suo transcript può fornire un nome di target che un override necessita. +- **Un prompt che si apre con uno dei titoli macchina dell'extension viene scartato intero.** Inizia un prompt con `# Selected text:`, `# Diff comments:`, `# Chrome tabs:` o un altro titolo di sezione dal primo gruppo sopra, e non scrivere mai un titolo `## My request:`, e nulla viene registrato per quel turno — quindi nulla viene superato per esso neppure. Questo è deliberato: quelle sezioni portano testo che qualcun altro controlla (codice che hai selezionato, un commento diff di un reviewer, il titolo di una pagina), e registrare quello come tue parole è il fallimento peggiore. I titoli che uno sviluppatore plausibilmente digita sono nel secondo gruppo e non scartano mai un prompt di per sé. +- **OpenCode non registra nulla in pratica.** Il suo evento `message.updated` non contiene testo nell'OpenCode attuale, e si attiva anche per le sessioni figlio che il suo strumento task crea, il cui messaggio "user" l'agent genitore ha scritto. +- **`CODEX_HOME` non è onorato** dalla scoperta del rollout in `lib/codex-sessions.ts`. Questo influisce solo su dove viene cercato uno snapshot agent-message, mai su se un prompt viene registrato. \ No newline at end of file diff --git a/docs/it/reference/jev-providers.mdx b/docs/it/reference/jev-providers.mdx new file mode 100644 index 000000000..c9c02c31e --- /dev/null +++ b/docs/it/reference/jev-providers.mdx @@ -0,0 +1,275 @@ +--- +title: "Provider Jev e configurazione con chiave propria" +description: "Endpoint del provider, ID modello, configurazione e comportamento in caso di errore per la revisione delle policy Jev in tempo reale con la tua chiave." +icon: "key-round" +--- + +Questo è il riferimento per provider e configurazione per le [policy Jev](/it/policies/jev) con la tua chiave. Le policy regex corrispondono alle stringhe. Non riescono a distinguere `rm -rf build/` che hai richiesto da `rm -rf ~` che è scivolato in un piano, quindi bloccano troppo in un posto e troppo poco in un altro. **Jev**, il classificatore di TypeSafe, legge la chiamata rispetto a quello che hai effettivamente richiesto e risponde a una serie di domande sì/no al riguardo in una richiesta veloce. + +Con il tuo endpoint Jev e la chiave configurati, Failproof AI chiede a Jev di ogni chiamata di strumento **insieme alle** policy regex, mai al loro posto: + +- Il deny di una policy **hard** è definitivo. Jev non può cancellarla. Ogni policy è hard a meno che non sia esplicitamente contrassegnata come reviewable e nomini i controlli Jev che la coprono, quindi una policy personalizzata, pack o Cloud che non dice nulla è hard, e la guardia di auto-protezione sempre attiva è sempre hard. +- Il deny di una policy **reviewable** può essere cancellato, ma solo quando Jev è stato interrogato sulla preoccupazione esatta che la policy copre e ha risposto "non c'è niente qui" o "l'utente ha richiesto questo". Un controllo che trova la preoccupazione reale, quando l'utente non ha richiesto la chiamata, mantiene il deny — anche quando il suo verdetto è solo un avviso, perché prima di una chiamata di strumento un avviso non ferma l'agente. E quando quel controllo è uno che può negare (esposizione di segreti, esfiltrazione di credenziali, cancellazione distruttiva, …), nulla viene cancellato su quella chiamata. +- Un blocco può ancora diventare un **avviso** quando la chiamata è un passo del compito che hai dato e non va oltre: Jev ammorbidisce il suo deny a un avviso, e quell'avviso — che nomina cosa c'è effettivamente di sbagliato nella chiamata — sostituisce il blocco della policy. +- Jev può anche avvisare o negare di sua iniziativa, per danno che nessuna regex descrive. +- Se Jev non può rispondere (timeout, limite di velocità, errore del server, nessun credito, una versione di modello inaspettata), quella chiamata ottiene il risultato regex, esattamente come senza Jev. +- Jev non rende mai una chiamata più permissiva delle tue sole policy a meno che non legga l'intera chiamata e sia stato interrogato sulla preoccupazione esatta. Qualcosa di meno — una chiamata troppo grande da inviare intera, un'iniezione sospetta — ritira i permessi e mantiene ogni deny. + + +Senza una configurazione Jev nulla cambia: i hook eseguono le policy regex esattamente come hanno sempre fatto. La configurazione è il tutto opt-in. + + + +Su FailproofAI Cloud? Non hai bisogno di una chiave propria: una macchina connessa con una chiave che porta `jev:evaluate` può usare Jev sul piano della tua organizzazione. Vedi [Jev attraverso FailproofAI Cloud](/it/reference/jev-cloud). + + +## Prima di iniziare + +Installa **failproofai 1.0.8-beta.0 o successivo** e allega i suoi hook a un [harness supportato](/it/reference/harnesses) sulla macchina dove gira il tuo agente. Segui il [quickstart](/it/start/quickstart) se è una macchina nuova, o [configura l'enforcement locale](/it/start/setup#enforce-locally) se non usi Cloud. Controlla il CLI installato con `failproofai --version`. + +Ottieni una chiave API da un provider qui sotto, o tieni pronto un endpoint compatibile e la sua chiave. Jev esamina le chiamate di strumento denominate nel gate `PreToolUse` o `PermissionRequest`. Può emettere il suo verdetto, ma cancellare un deny di policy esistente richiede anche una policy installata contrassegnata come [reviewable](/it/policies/authority). I deny di policy hard rimangono definitivi. + +## Scegli un provider + +Jev è raggiungibile attraverso cinque percorsi. Porta una chiave per qualsiasi uno di loro. + +| Provider | `--provider` | Endpoint | Modello predefinito | Note | +| --- | --- | --- | --- | --- | +| TypeSafe | `typesafe` | `api.typesafe.ai/v1/systemone` | `jev-1.13.0` | Pin della versione esatta. | +| OpenRouter | `openrouter` | `openrouter.ai/api/v1/systemone` | `typesafe/jev-1.13` | Le richieste sono instradate solo a endpoint di non-retention dei dati, senza fallback a un altro provider. Riporta una versione datata come `typesafe/jev-1.13-20260917`. | +| Vercel AI Gateway | `vercel` | `ai-gateway.vercel.sh/typesafe/v1/systemone` | `typesafe-ai/jev` | Nomina Jev solo con un alias, quindi la versione che risponde è registrata come non verificata. | +| Cloudflare Workers AI | `cloudflare` | `api.cloudflare.com/client/v4/accounts//ai/run` | `typesafe/jev` | Ha bisogno di `--account-id`. Circa sei chiamate al secondo per chiave sono state misurate prima di HTTP 429. | +| Il tuo endpoint | `custom` | `/systemone` | `jev-1.13.0` | Qualsiasi endpoint che accetta il corpo della richiesta di TypeSafe e riporta quale modello ha risposto. Solo `https`; il semplice `http://localhost` è accettato solo in modalità observe. | + + +Con la funzione bring-your-own-key di Vercel, una richiesta fallita viene silenziosamente ritentata con le credenziali di Vercel. Se hai bisogno che ogni chiamata sia fatturata a, e vista da, solo il tuo account TypeSafe, usa TypeSafe direttamente. + + +## Configuralo + +Un comando, l'endpoint e la chiave. Inizia in modalità `observe` così puoi ispezionare i verdetti di Jev mentre le policy esistenti continuano a decidere le chiamate: + +```bash +failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key +``` + +### L'URL sceglie il provider + +Non devi nominare il provider: l'**host** dell'URL è quale è. + +| Host URL | Provider | Ha anche bisogno di | +| --- | --- | --- | +| `api.typesafe.ai` | `typesafe` | — | +| `openrouter.ai` | `openrouter` | — | +| `ai-gateway.vercel.sh` | `vercel` | — | +| `api.cloudflare.com` | `cloudflare` | `--account-id <32-hex-account-id>` | +| qualsiasi altro host | `custom` | — l'URL che hai fornito è l'URL di base | + +Tre cose seguono da questo: + +- **Un URL che è la propria API del provider non scrive nessun override.** `--url https://api.typesafe.ai/v1` produce esattamente la configurazione che avrebbe `--provider typesafe`. Dai un percorso o host diverso su un provider noto e viene archiviato come URL di base, come farebbe `--base-url`. +- **`--provider` sovrascrive ancora l'inferenza**, che è come raggiungi un proxy che parla l'API di un provider da un host tuo: `--url https://jev-proxy.internal/v1 --provider typesafe`. +- **Un `--provider` che contraddice l'host è rifiutato**, non indovinato. `--provider openrouter --url https://api.typesafe.ai/v1` non scrive nulla e spiega perché: i due nomi non concordano su dove la tua chiave sta per essere inviata. La stessa coppia è rifiutata da `jev setup --base-url` e dalle impostazioni Jev della dashboard. (`--provider custom` non è una contraddizione — significa "tratta questo URL come se stesso" — eccetto sull'host di Cloudflare, il cui endpoint per-account un percorso personalizzato non può raggiungere.) + +`--url` è validato esattamente come il `baseUrl` nel file di configurazione, e rifiutato con le stesse parole: `https`, o semplice `http://localhost` solo in modalità observe. + +### La chiave + +Inviala con `--key-stdin`, o esegui il comando in un terminale senza di essa e incolla la chiave a un prompt mascherato. In entrambi i casi va direttamente nel file di configurazione e non viene mai stampata di nuovo. + + + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key + ``` + + + ```bash + failproofai jev --url https://openrouter.ai/api/v1 --mode observe --key-stdin < ~/openrouter.key + ``` + + + ```bash + failproofai jev --url https://ai-gateway.vercel.sh/typesafe/v1 --mode observe \ + --key-stdin < ~/vercel-gateway.key + ``` + + + ```bash + failproofai jev --url https://api.cloudflare.com/client/v4 \ + --account-id <32-hex-account-id> --mode observe --key-stdin < ~/cloudflare.token + ``` + + + ```bash + failproofai jev --url https://jev.internal.example.com/v1 --mode observe --key-stdin < ~/jev.key + ``` + + + +`failproofai jev setup` accetta gli stessi flag ed è la forma lunga per tutto: `setup --provider ` dove preferiresti nominare il provider piuttosto che l'URL. + +### `--token`, e cosa costa + +`--token ` mette la chiave sulla riga di comando, che è il modo più veloce per configurare una macchina e l'unica forma che lascia la chiave ovunque ma nel file di configurazione: + +```bash +failproofai jev --url https://openrouter.ai/api/v1 --token +``` + + +Un argomento della riga di comando è nella cronologia del tuo shell dopo, e mentre il comando gira è nell'elenco dei processi — leggibile da `/proc` da qualsiasi cosa che gira come te. `setup` lo dice ogni volta che viene usato `--token`. Preferisci `--key-stdin` su una macchina che condividi, in una sessione registrata, o ovunque il file della cronologia sia sincronizzato; ruota una chiave che hai passato in questo modo se importa. + + +`--token`, `--key-stdin` e `--key-from-env` si escludono a vicenda: dai uno. + +Poi invia una piccola richiesta live per controllare la chiave, l'endpoint e quale Jev ha risposto: + +```bash +failproofai jev test +``` + +```text + failproofai jev test ok · 523 ms + + provider cloudflare + model asked typesafe/jev + answered by jev-1.13.0 (Jev 1.13 family — verified) + latency 523 ms — within the 3000 ms timeout +``` + +`jev test` esce 1, e lo dice nel suo titolo, quando la risposta arriva dopo il timeout (ogni hook ricadrebbe su regex come `timeout`) o risponde male alla sua domanda di controllo. + +I hook leggono la configurazione ad ogni chiamata di strumento, quindi si applica da quella successiva. Non c'è nulla da riavviare, con o senza il daemon. + +## Controlla cosa sta facendo + +```bash +failproofai jev status +failproofai jev status --json +``` + +`status` mostra il provider, endpoint, modello, modalità, il file di configurazione e i suoi permessi, e mai la chiave. Sotto riassume l'attività recente: quante chiamate Jev ha valutato, quanto spesso è ricaduto su regex e perché, la sua latenza, e quali policy reviewable ha cancellato. + +## Verifica una vera chiamata + +Avvia una nuova sessione nell'agente allacciato. Chiedigli di usare il suo strumento di lettura file su `README.md` e riportare il titolo. Conferma che la sessione contiene quella chiamata di strumento, poi esegui `failproofai jev status` di nuovo: il suo recente conteggio di chiamate valutate dovrebbe aumentare. Apri **Policies → Activity** nel [dashboard locale](/it/reference/local-dashboard#review-policy-activity) per ispezionare il verdetto Jev della chiamata e la modalità. In modalità observe, il risultato della policy decide ancora la chiamata. Una cancellazione appare solo se una policy reviewable è stata accoppiata e Jev ha cancellato ogni controllo denominato; una lettura ordinaria potrebbe non avere alcuna policy da cancellare. + +## Modalità observe + +`enforce` è l'impostazione predefinita. Per guardare Jev senza lasciargli cambiare alcuna decisione, passa a `observe`: Jev è ancora interrogato e i suoi verdetti sono registrati, ma il risultato regex è quello che è applicato. + +```bash +failproofai jev setup --mode observe +failproofai jev setup --mode enforce +failproofai jev setup --mode off +``` + +`off` mantiene la configurazione — l'endpoint e la chiave — e smette di chiedere a Jev: i hook eseguono le policy regex esattamente come senza una configurazione, e `failproofai jev status` dice "off (switched off)". Torna indietro con `--mode observe` o `--mode enforce`. + +Rieseguire `setup` per lo stesso provider mantiene la chiave archiviata, quindi un cambio di modalità è un flag. Cambiare provider ricomincia da capo e chiede la chiave di quel provider. Così fa un `--base-url` che sposta le richieste a un host diverso: una chiave archiviata è inviata solo all'host per cui è stata fornita, o all'API propria del suo provider. + +## Il file di configurazione + +Tutto risiede in un file, `~/.failproofai/jev.json`, scritto da `setup`: + +```json +{ + "provider": "cloudflare", + "apiKey": "", + "accountId": "<32-hex-account-id>", + "mode": "enforce", + "timeoutMs": 3000 +} +``` + +| Campo | Significato | +| --- | --- | +| `provider` | `typesafe`, `openrouter`, `vercel`, `cloudflare` o `custom` — o `failproofai`, la cui chiave proviene dalla connessione FailproofAI Cloud invece che da questo file (vedi [Jev attraverso FailproofAI Cloud](/it/reference/jev-cloud)). | +| `apiKey` | Inviato come `Authorization: Bearer `. | +| `baseUrl` | Richiesto per `custom`; sostituisce l'API base del provider altrimenti. Deve essere `https`. Http semplice a `localhost` è accettato solo con `mode: observe`: nulla autentica una porta locale, quindi mentre il tuo proxy è inattivo qualsiasi processo sulla macchina, incluso l'agente giudicato, potrebbe rispondere al suo posto. | +| `accountId` | Solo Cloudflare: 32 caratteri hex minuscoli. | +| `model` | Sostituisce l'id del modello predefinito del provider. Un id versionato deve nominare Jev 1.13. Un valore che assomiglia a una chiave API è rifiutato (e non ripetuto di nuovo), quindi una chiave incollata in `--model` non viene mai archiviata o inviata come modello. | +| `timeoutMs` | Quanto tempo una chiamata di strumento attende Jev prima di usare il risultato regex. 100–10000, predefinito 3000. | +| `mode` | `enforce` (predefinito), `observe`, o `off` (mantieni la configurazione, esegui nessun Jev). | + +Tre regole lo proteggono: + +- **Solo proprietario.** È scritto con permessi `0600`. Una copia che qualsiasi altro utente o gruppo può leggere o scrivere è **rifiutata**, e i hook ricadono su regex finché non esegui `chmod 600 ~/.failproofai/jev.json` o esegui `setup` di nuovo. Anche la directory è controllata: `~/.failproofai` non deve essere **scrivibile** da nessun altro, perché chiunque può scrivere lì può sostituire il file qualunque siano i suoi permessi. `setup` toglie quei bit di scrittura se li trova. `failproofai jev status` dice quando una configurazione è stata rifiutata e mostra l'endpoint che il file nomina: qualcun altro potrebbe averla cambiata, quindi controllala sia tua prima di `chmod`. Rieseguire `setup` su tale file porta la sua chiave archiviata solo all'API propria del provider; qualsiasi altro endpoint che nomina ha bisogno della chiave di nuovo (`--key-stdin`), o `--base-url default` per inviare richieste di nuovo al provider. +- **Solo globale.** Un repository non può accendere Jev, puntarlo a un altro endpoint o scegliere il suo modello: un `.failproofai/jev.json` dentro un progetto è ignorato, e il provider, URL, modello e account id sono letti solo da quel file — mai dall'ambiente, che le impostazioni dell'agente di un repository possono impostare. (`FAILPROOFAI_HOME` non è un modo per aggirare questo: sposta l'intera directory failproofai, incluse le tue policy, piuttosto che reindirizzare Jev da solo.) +- **Solo la chiave può provenire dall'ambiente.** Se il file non ha `apiKey`, `FAILPROOFAI_JEV_API_KEY` lo fornisce per quella sessione (`setup --key-from-env` scrive tale file). Non sostituisce mai una chiave che il file contiene, e non può accendere Jev senza il file. Dove la variabile non è impostata, Jev è semplicemente spento per quella shell: `failproofai jev status` lo dice, esce 0 e lascia la configurazione da sola (`status --json` riporta `"status": "key-missing"` con `"reason": "no-env-key"`). Il daemon `failproofaid` non vede l'ambiente della tua shell, quindi su una macchina configurata con `failproofai config`, mantieni la chiave nel file. + +## Quale Jev risponde + +Le soglie di decisione di Failproof AI sono state calibrate su Jev 1.13, quindi una risposta è usata solo quando proviene da quella famiglia: `jev-1.13.x`, o `typesafe/jev-1.13-` di OpenRouter. Dove un provider nomina Jev solo con un alias e non riporta alcuna versione (Vercel, e Cloudflare quando non lo dice), la risposta è usata e registrata come non verificata. Un endpoint `custom` deve riportare il modello che ha risposto; l'unica eccezione è un nome `--model` senza versione che hai configurato per esso, che, riecheggiato di nuovo, è registrato come non verificato allo stesso modo. Una risposta che riporta qualsiasi altra versione, o una risposta `custom` che non riporta alcuna, non è usata: quella chiamata ricade su regex con la ragione `model-mismatch`. + +## Quando Jev non può rispondere + +Ognuno di questi ricade sul risultato regex per quella chiamata e viene registrato con la sua ragione, che `failproofai jev status` totalizza: + +| Ragione | Causa | +| --- | --- | +| `timeout` | Nessuna risposta entro `timeoutMs`. | +| `http-429` | Il provider ha limitato la velocità della chiave. | +| `rate-limited` | Il limitatore di Failproof AI ha trattenuto la chiamata prima di inviarla: 5 richieste al secondo, in burst fino a 5, e nessuna per un momento dopo che il provider risponde `429`. Non il provider. | +| `http-500`, `http-502`, `http-503`, … | Un errore del server presso il provider. Lo stato esatto è registrato. | +| `out-of-credits` | HTTP 402: l'account del provider non ha crediti rimasti. | +| `provider-refused` | HTTP 402 da Cloudflare che legge "Model execution failed (Payment error)": il provider ha rifiutato di eseguire il modello su questa richiesta. Di solito non è fatturazione, quindi ricaricare non lo muoverà. | +| `http-401`, `http-403` | La chiave è stata rifiutata. | +| `http-404` | Nulla è servito a `/systemone`, quindi l'URL di base è sbagliato — `/systemone` è aggiunto ad esso, e ogni provider lo serve alla sua radice della versione. `failproofai jev models` mostra cosa l'endpoint serve. | +| `network` | L'endpoint non poteva essere raggiunto. | +| `http-301`, `http-302`, `http-307`, `http-308` | L'endpoint ha risposto con un reindirizzamento. I reindirizzamenti non sono mai seguiti, quindi la risposta viene solo e sempre dall'URL nella tua configurazione; imposta `--base-url` all'URL finale. | +| `malformed` | L'endpoint ha risposto, ma non con una risposta Jev — un corpo che non è JSON, o uno senza risposte al suo interno. | +| `cloudflare-error`, `cloudflare-incomplete` | L'envelope di Cloudflare ha riportato un errore, o un lavoro che non era finito. | +| `model-mismatch` | Una versione Jev diversa da 1.13 ha risposto, o un endpoint `custom` non ha detto quale modello ha risposto. | +| `request-cut` | **Non un'interruzione.** Jev ha risposto; gli è stata mostrata solo parte della chiamata, quindi la sua risposta non ha cancellato nulla. Vedi [Quando Jev ha risposto, ma non sulla chiamata intera](#when-jev-answered-but-not-on-the-whole-call). | + +`failproofai jev status` può mostrare anche alcune ragioni più rare, come `upstream-error` (la risposta conteneva l'errore proprio del provider) o `config`, e totalizza qualsiasi ragione che non può nominare come `other`. + +`request-cut` è in questa tabella perché `failproofai jev status` lo totalizza con il resto, e perché anch'esso lascia ogni deny in piedi. È l'unica ragione qui che non dice nulla su tuo provider: la richiesta è arrivata e Jev ha risposto. A differenza di ogni riga sopra ad essa, quella risposta conta ancora — il deny o avviso proprio di Jev si applica in cima al risultato regex piuttosto che essere scartato. Quindi una serie di essi significa che le chiamate stanno raggiungendo l'evaluator troppo grandi da inviare intere, non che il tuo endpoint sia malato, e ricaricare crediti o cambiare l'URL non muoverà il numero. + +## Quando Jev ha risposto, ma non sulla chiamata intera + +Due altre cose possono accadere, e nessuna delle due è Jev che non riesce a rispondere. Entrambe riguardano quanto della chiamata, o della conversazione, è entrato in una richiesta. + +**Parte della chiamata stessa non è rientrata.** Una chiamata di strumento è inviata dentro un budget fisso, e una sproporzionatamente grande — una `Write` molto grande, un corpo MCP enorme, un comando imbottito fino al limite — è inviata con quello che è rientrato. Jev risponde ancora, e la sua risposta conta ancora: il suo deny o avviso proprio si applica come al solito. Quello che non può fare è **cancellare** nulla, perché un verdetto dato su parte di una chiamata non è un verdetto sulla chiamata. Quindi ogni deny di policy sta in piedi, e la chiamata è registrata come ricaduta con la ragione `request-cut`, che `failproofai jev status` totalizza insieme alle ragioni sopra. La regola che questo ti dà: rendere una chiamata più grande può costarle le sue cancellazioni, e non può mai comprarne una. + +**Un messaggio non è rientrato.** Un prompt lungo che hai incollato, l'ultimo messaggio dell'agente, o un prompt che lo store proprio di questo evaluator aveva già limitato. **Nulla cambia**: la chiamata è giudicata, cancellata e registrata esattamente come qualsiasi altra, e non è conteggiata come ricaduta. La lunghezza di quello che digiti non decide mai un verdetto, e un taglio non può produrre consenso: dove un prompt è arrivato già limitato, "non hai richiesto questo" smette di essere una conclusione che può essere tratta da esso, piuttosto che diventarne una. + +La linea tra i due è chi ha scritto il testo. La chiamata è dell'agente, e una regola che lasciasse la sua lunghezza sottrarre severità sarebbe una regola che l'agente può usare; il tuo prompt è tuo, e trattare la sua lunghezza come un segnale ha punito solo incollare una spec o una traccia di stack. + +## Cosa lascia la macchina + +Per ogni chiamata di strumento che Jev valuta, una richiesta va al tuo provider, portando: + +- la chiamata di strumento stessa, con segreti come chiavi API, bearer token e assegnazioni `KEY=` oscurati; +- i recenti prompt che hai digitato, con testo che l'harness del tuo agente ha aggiunto rimosso; +- l'ultimo messaggio dell'agente prima del tuo ultimo prompt, etichettato come scritto dall'agente; +- fatti calcolati localmente, come se un percorso sia dentro il progetto — quello in cui la sessione era nella sua prima chiamata revisionata, [fissato per la sessione](/it/reference/jev-intent#the-project-root) — e il branch git corrente. + +Va solo all'endpoint nella tua configurazione, sotto la tua chiave. + +## Spegnilo + +```bash +failproofai jev remove +``` + +Questo elimina `~/.failproofai/jev.json`. Dalla prossima chiamata di strumento, i hook eseguono le policy regex esattamente come prima. I store per-sessione sotto `~/.failproofai/state/semantic/` (prompt registrati in `sessions/`, root del progetto in `roots/`) sono lasciati in posizione e invecchiano. Per smettere di chiedere a Jev ma mantenere la configurazione, usa `failproofai jev setup --mode off` invece. + +## Riferimento del comando + +| Comando | Risultato | +| --- | --- | +| `failproofai jev --url --key-stdin` | Configuralo in un comando; il provider viene dall'host dell'URL | +| `failproofai jev --url --token ` | Uguale, con la chiave sulla riga di comando — la tua cronologia e l'elenco dei processi la vedono | +| `failproofai jev setup --provider --key-stdin` | Scrivi la configurazione da una chiave inviata su stdin | +| `failproofai jev setup --provider ` | Uguale, chiedendo la chiave a un prompt mascherato | +| `failproofai jev setup --key-from-env` | Non archiviare alcuna chiave; leggi `FAILPROOFAI_JEV_API_KEY` per sessione | +| `failproofai jev setup --mode observe` | Cambia modalità (`enforce`, `observe` o `off`), mantenendo la chiave archiviata | +| `failproofai jev setup --model ` / `--base-url ` | Sovrascrivi il modello o la base API; `default` cancella l'override | +| `failproofai jev setup --timeout-ms ` | Cambia il budget per-chiamata | +| `failproofai jev status [--json]` | Configurazione, permessi e attività recente; mai la chiave | +| `failproofai jev test [--json]` | Una richiesta live: latenza e versione che ha risposto | +| `failproofai jev models [--provider ] [--url ] [--json]` | Gli id modello che l'`/models` dell'endpoint riporta, contrassegnando quello configurato | +| `failproofai jev remove` | Elimina la configurazione; Jev è spento | \ No newline at end of file diff --git a/docs/it/reference/jev.mdx b/docs/it/reference/jev.mdx new file mode 100644 index 000000000..52c5a2432 --- /dev/null +++ b/docs/it/reference/jev.mdx @@ -0,0 +1,22 @@ +--- +title: "Riferimento integrazione Jev" +description: "Configurazione, provider, chiavi, dati richiesta e comportamento in caso di errore per Jev." +icon: "braces" +--- + +Jev ha due usi in Failproof AI: + +| Uso | Quando viene eseguito | Cosa restituisce | Inizia da qui | +| --- | --- | --- | --- | +| Valutazione sessione | Dopo il completamento di una sessione | Un punteggio per una domanda a risposta fissa | [Valutazioni Jev](/it/evaluations/jev) | +| Revisione politica di tool-call | Prima dell'esecuzione di una tool-call controllata | Un verdetto insieme alle politiche installate | [Politiche Jev](/it/policies/jev) | + +## Pagine di riferimento + +| Argomento | Dettagli | +| --- | --- | +| [Domande di valutazione](/it/reference/jev-evaluations) | Criteri booleani e a punteggio ordinato, risultati, limiti e backfill. | +| [Confronto provider e configurazione chiave propria](/it/reference/jev-providers) | TypeSafe, OpenRouter, Vercel, Cloudflare ed endpoint personalizzati; inferenza URL, ID modello, `jev.json`, modalità e codici di fallback. | +| [Rotta FailproofAI Cloud](/it/reference/jev-cloud) | Permessi machine-key, configurazione observe automatica, limiti di utilizzo, stato connessione e gestione dati. | + +I comandi CLI locali sono elencati in [Riferimento CLI Failproof AI](/it/reference/failproof-cli). Il [Riferimento dashboard locale](/it/reference/local-dashboard#set-up-jev) descrive le sue impostazioni Jev e la vista attività. \ No newline at end of file diff --git a/docs/it/sessions/sentiment.mdx b/docs/it/sessions/sentiment.mdx new file mode 100644 index 000000000..263a828ea --- /dev/null +++ b/docs/it/sessions/sentiment.mdx @@ -0,0 +1,43 @@ +--- +title: "Analisi del sentiment" +description: "Trova messaggi frustrati, confusi e correttivi con i punteggi Jev sentiment." +icon: "smile" +--- + +Jev assegna a ogni messaggio inviato da una persona ai tuoi agenti un punteggio da 0 a 100 per quattro emozioni — **arrabbiato**, **frustrato**, **felice** e **confuso** — e tre segnali su come sta andando l'agente: + +- **Correcting**: la persona dice che l'agente ha sbagliato qualcosa. +- **Resolved**: la persona conferma che l'agente ha risolto il suo problema. +- **Doubtful**: la persona mette in dubbio se la risposta dell'agente è vera, o se ha davvero fatto il lavoro. + +Usa l'analisi del sentiment per trovare conversazioni dove le persone stanno perdendo pazienza, agenti che continuano a essere corretti, e risposte che funzionano bene. Questo è il punteggio Jev integrato; non hai bisogno di creare una valutazione. Per la tua domanda con risposta fissa, [crea una valutazione Jev](/it/evaluations/jev). + + + Il sentiment è disattivato finché un amministratore non lo attiva per l'organizzazione. Jev effettua una richiesta di punteggio per messaggio e riceve quel messaggio con la risposta dell'agente prima. Il punteggio utilizza il budget del modello della tua organizzazione. + + +## Attivalo + +1. Vai a **Administration → Settings**. +2. In **Human input sentiment**, attivalo **on** e salva. + +I messaggi dell'ultimo giorno vengono punteggiati per primi. Dopo di ciò, i nuovi messaggi vengono punteggiati entro uno o due minuti dall'arrivo. + +## Trova una conversazione da rivedere + +Apri **Observe → Sentiment**. Filtra per ora, ambiente, agente o ID sessione. L'intestazione conta i messaggi e le sessioni, mostra quanti messaggi sono **flagged**, e nomina il segnale principale. Un messaggio è flagged quando un punteggio arrabbiato, frustrato, correttivo, confuso o dubbioso raggiunge 35 su 100. + +![Il dashboard Sentiment che mostra i conteggi di messaggi e sessioni, i messaggi flagged, e i punteggi Jev nel tempo.](/images/dashboard/sentiment-overview.png) + +Usa **Score over time** per confrontare i segnali. Scegli i punteggi da mostrare, quindi seleziona un punto per vedere i messaggi di quel bucket temporale. La tabella **By agent** mostra dove un segnale è concentrato. In **Messages**, ordina per il punteggio negativo più forte o seleziona un singolo punteggio. Apri un messaggio nella sua sessione per leggere la conversazione circostante prima di decidere cosa è andato male. + +![L'elenco dei messaggi Sentiment ordinato per il punteggio negativo più forte, con un link a ogni sessione di origine.](/images/dashboard/sentiment-messages.png) + +## Quali messaggi vengono punteggiati + +Solo i messaggi scritti da una persona: + +- Messaggi che i tuoi agenti personalizzati registrano come input umano con l'SDK. +- Prompt digitati in Claude Code, Codex, OpenCode, pi, Hermes e OpenClaw, quando i trascritti di sessione vengono inviati (il default). I lavori pianificati, le istruzioni iniettate, i passaggi tra sub-agenti e altri testi che il runtime dell'agente stesso scrive non vengono punteggiati. Nemmeno le esecuzioni non interattive come `claude -p`, `codex exec` e `hermes -z`: uno script ha scritto questi prompt, non una persona. + +Il punteggio giudica le proprie parole della persona. Un'istruzione breve e diretta come "fix it" non viene contata come rabbia, e fare una domanda non viene contata come confusione. Una nuova richiesta non è una correzione, e i ringraziamenti da soli non contano come risolti. \ No newline at end of file diff --git a/docs/it/start/use-jev.mdx b/docs/it/start/use-jev.mdx new file mode 100644 index 000000000..a8b9fde0d --- /dev/null +++ b/docs/it/start/use-jev.mdx @@ -0,0 +1,63 @@ +--- +title: "Usare Jev" +description: "Configura valutazioni Jev per sessioni completate o politiche Jev per la revisione live delle chiamate di strumenti." +icon: "sparkles" +--- + +Jev aiuta in due momenti durante l'esecuzione di un agente: valutare una sessione completata rispetto a risposte note, oppure revisionare una chiamata di strumento nel contesto di ciò che hai chiesto all'agente di fare. + + + + Usa una valutazione Jev quando una sessione completata può essere valutata rispetto a una domanda con poche risposte note, come "Il cliente ha chiesto un rimborso? Rispondi sì o no." Ti aiuta a trovare schemi ricorrenti tra le sessioni. + + ## Creare una valutazione + + Nel dashboard Cloud, apri **Analyze → eval authoring → new eval**. Inserisci una domanda con risposta fissa, seleziona **draft**, e verifica che abbia scelto un punteggio classificatore. [Testalo](/it/evaluations/test) su sessioni reali, quindi distribuiscilo. + + ![Il modulo di creazione di valutazioni condivise dove descrivi una domanda, rivedi la bozza e la distribuisci. Questo screenshot mostra una bozza di codice; utilizza una domanda con risposta fissa per Jev.](/images/dashboard/eval-authoring-draft.png) + + ## Leggere i punteggi + + Dopo il completamento di una nuova sessione, apri **Observe → Evaluations** oppure utilizza la Cloud CLI: + + ```bash + fp evals --since 7d + fp evals --aggregate --since 7d + ``` + + La CLI legge i punteggi; la creazione di una valutazione Jev attualmente utilizza il dashboard. Consulta [Jev evaluations](/it/evaluations/jev) per i tipi di domande e gli esempi. + + + Usa la revisione della politica Jev quando una politica basata sul matching di stringhe ha bisogno del contesto della tua richiesta per decidere se una chiamata di strumento è sicura. Inizia in modalità **observe** così puoi ispezionare le risposte di Jev mentre le tue politiche installate decidono ancora ogni chiamata. + + I controlli di Jev provengono da un pacchetto; Failproof AI non ne fornisce alcuno. Fino a quando non li installi, Jev non chiede nulla, anche se è configurato: + + ```bash + failproofai policies add FailproofAI/jev-policies + ``` + + ## Configurare Cloud Jev + + Nel dashboard Cloud, apri **Administration → Keys** e crea una chiave con il preset **machine**. Usala con `failproofai config` come mostrato nella [guida rapida](/it/start/quickstart). Su una macchina senza una configurazione Jev preesistente, questo abilita Cloud Jev in modalità observe. Controlla la connessione con: + + ```bash + failproofai jev status + failproofai jev test + ``` + + ## Utilizzare il tuo endpoint + + Nel dashboard locale, apri **Settings → Jev**. Scegli il provider, incolla il suo token, seleziona **observe**, e attiva Jev. + + ![Il pannello delle impostazioni Jev locali con un provider, campo token, e modalità observe selezionata.](/images/dashboard/jev-settings.png) + + Oppure configura e testa il tuo endpoint da un terminale: + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key + failproofai jev test + ``` + + Chiedi a un agente aggganciato di usare il suo strumento di lettura file su `README.md`. Conferma che la chiamata di strumento appare nella sessione, quindi ispezionala sotto **Policies → Activity** nel dashboard locale. Una volta che i risultati della modalità observe appaiono corretti, [Jev policies](/it/policies/jev) spiega quando forzare. Per i dettagli del provider e la configurazione, consulta il [reference di integrazione](/it/reference/jev). + + \ No newline at end of file diff --git a/docs/ja/evaluations/jev.mdx b/docs/ja/evaluations/jev.mdx new file mode 100644 index 000000000..5814d6197 --- /dev/null +++ b/docs/ja/evaluations/jev.mdx @@ -0,0 +1,28 @@ +--- +title: "Jev評価" +description: "既知の回答がある質問に対して、完了したセッションをJevでスコアリングします。" +icon: "list-checks" +--- + +Jev評価は**完了したセッション**を読み取り、0から1のスコアを付与します。「顧客は緊急性を示しましたか?」や「顧客はどの程度不満を感じていましたか?」など、回答が事前にわかっている場合に使用します。複数の実行にわたるパターンを発見するのに役立ちますが、ツール呼び出しを停止するものではありません。ツールが実行される**前**に行う判断には、[Jevポリシー](/ja/policies/jev)を使用してください。 + +## ダッシュボードで作成する + +1. **Analyze → eval authoring** を開き、**new eval** を選択します。 +2. 質問とその回答の選択肢を記述します。例:「エージェントは返金ポリシーを確認する前に返金を約束しましたか?はいまたはいいえで答えてください。」**draft** を選択し、結果が分類スコアになっていることを確認します。 +3. 最近のセッションで[テスト](/ja/evaluations/test)し、その後[デプロイ](/ja/evaluations/deploy)します。新しく完了したセッションがスコアリングされます。履歴も必要な場合は[バックフィル](/ja/evaluations/deploy#score-sessions-you-already-have)を行ってください。 + +![質問と固定回答を記述し、ドラフトを確認してテスト後にデプロイする共有eval authoring フォーム。表示されている例はコード評価ですが、Jevの質問も同じauthoringフローを使用します。](/images/dashboard/eval-authoring-draft.png) + +アシスタントはコード、Jev分類、[judge](/ja/evaluations/judge)の中から選択できます。デプロイ前にその選択を確認してください。Jevは文章による説明なしでスコアを返します。説明が必要な場合はjudgeを選択してください。質問の種類とスコアの上限については、[Jev評価リファレンス](/ja/reference/jev-evaluations)を参照してください。 + +## スコアを確認する + +**Observe → Evaluations** を開くと、エージェントや時間ごとに結果をグラフで確認できます。ターミナルからは、Cloud CLIで同じ結果を読み取ることができます: + +```bash +fp evals --since 7d +fp evals --aggregate --since 7d +``` + +Cloud CLIは結果の読み取りに使用します。authoring(作成)とデプロイはダッシュボードで行います。フィルターについては[Cloud CLIリファレンス](/ja/reference/cloud-cli#evaluations)を参照してください。 \ No newline at end of file diff --git a/docs/ja/evaluations/judge.mdx b/docs/ja/evaluations/judge.mdx new file mode 100644 index 000000000..06968e973 --- /dev/null +++ b/docs/ja/evaluations/judge.mdx @@ -0,0 +1,91 @@ +--- +title: "LLMジャッジ" +description: "正確さ、トーン、エージェントがポリシーに従ったかどうかなど、コードでは計測できない事柄についてセッションをスコアリングします。良い結果とは何かを説明し、モデルに会話を読み取らせます。" +icon: "scale" +--- + +ホスト型のPython評価では、数えて比較することができます:ツール呼び出しの回数、エラーの数、セッションの所要時間など。しかし、回答が*正確*かどうか、返答が失礼かどうか、エージェントが行動する前にポリシーを確認したかどうかは判断できません。 + +**LLMジャッジ**はそれが可能です。良い結果とはどういうものかを平易な言葉で説明すれば、モデルがセッションを読み取り、推論とともに0から1のスコアを返します。 + + +ジャッジは実行するセッションごとに1回のモデル呼び出しコストが発生しますが、コード評価にはコストがかかりません。ジャッジは会話を*理解する*必要がある質問にのみ使用してください。また、条件を設定して、実際に問題となるセッションでのみ実行されるようにしましょう。 + + +## どちらを使うべきか? + +| 質問 | 使用するもの | +| --- | --- | +| 同じツールを2回呼び出したか? | コード | +| エラーはいくつあったか? | コード | +| セッションは30秒以内だったか? | コード | +| 顧客は緊急性を示したか? | [クラシファイア](/ja/evaluations/jev) | +| 顧客はどれくらい不満を感じていたか? | [クラシファイア](/ja/evaluations/jev) | +| 回答は実際に正確だったか? | **ジャッジ** | +| 返答は失礼または否定的だったか? | **ジャッジ** | +| 返金を約束する前に返金ポリシーを確認したか? | **ジャッジ** | + +目安:**数えられるもの → コード、事前に列挙できる答え → [クラシファイア](/ja/evaluations/jev)、説明が必要なもの → ジャッジ。** ジャッジは見たものについて文章で説明するものです。数値だけでは「なぜ?」という疑問が生じる場合に活用してください。 + +事前に決める必要はありません。測定したい内容を説明すれば、アシスタントが選択肢を選び、選んだ理由を説明してくれます。後から変更することも可能です。 + +## 作成方法 + +1. **Analyze → eval authoring** に移動し、**new eval** を選択します。 +2. ジャッジしたい内容を説明し、**draft** を選択します。 +3. **criteria**、**threshold**、**condition** を確認してデプロイします。 + +### Criteria + +質問形式ではなく、要件として書いた1〜2文: + +> エージェントは、返金ポリシーを確認せずに返金を約束または承認してはなりません。 + +何が*失敗*になるかを具体的に書いてください。「レスポンスは良かったか?」という基準では意味のない数値しか得られません。上の文のような基準であれば、実際に対応できる数値が得られます。 + +### Threshold + +セッションが合格となるスコアの下限値です。`0.7` が適切な出発点です。0から1の全スコアは常に保存されるため、thresholdは合否の判定にのみ使用されます。分布を確認して調整することが可能です。 + +### Condition + +他の評価と同じPythonの条件式で、ここでは特に重要です。条件なしでは、ジャッジは組織内の**すべての**セッションに対して実行され、それぞれモデル呼び出しが発生します: + +```python +session.count("tool_use") > 0 +``` + +```python +session.agent_id == "support-bot" and session.count("error") > 0 +``` + +条件なしでジャッジをデプロイしようとすると、ダッシュボードが警告を表示します。完全にジャッジしたい低ボリュームのエージェントに対しては条件なしが適切なこともありますが、それは意図的な判断であるべきで、うっかりそうなってしまうべきではありません。 + +## ジャッジが参照する情報 + +会話のターン一覧(セッションが長い場合は新しい順): + +- ユーザーの発言 +- アシスタントの返答 +- **エージェントが呼び出したすべてのツールと、その呼び出しが返した結果(順番通り)** + +最後の項目があるからこそ、「XをしてからYをしたか」という質問が公正に問えるのです。失敗したツール呼び出しは失敗として表示されるため、「エラーから適切に回復したか」という評価も可能です。 + +非常に長いセッションはモデルのコンテキストに収まるようにトランケートされます。その場合、推論の中で明示的にその旨が記載されます。セッションの一部しか見ていないのに全体を評価したかのような判定が表示されることはありません。 + +## 結果の読み方 + +ジャッジは他のスコア付き評価と同様に**スコア**を生成するため、グラフ表示、フィルタリング、アラートのトリガーが同じ方法で機能します。数値と併せて、ジャッジの**推論**(見たものを説明する段落)が保存されます。スコアに驚いたときはまずその推論を読んでください。たいていの場合、本当に興味深いセッションか、criteriaを精査する必要があるサインかのどちらかです。 + +スコアは明確なケースでは安定していますが、ビット単位で決定論的ではありません。境界線上の単一スコアは評決として受け取るのではなく、そのセッションを実際に読むきっかけとして扱ってください。 + +## 制限事項 + +- **テストはまだ利用できません。** ドライランにはセッションの割り当てがなく、その割り当てがモデル予算の消費を承認するものであるため、テスト呼び出しに課金する対象がありません。狭い条件でデプロイし、最初の数件の結果を確認してください。 +- **バックフィルは利用できません。** 数ヶ月分の履歴に対するコード評価のバックフィルは無料ですが、ジャッジで行うと予算全体を数分で消費してしまいます。 +- **criteriaを編集すると新しいバージョンが公開されます。** 古いスコアと新しいスコアは比較できないため、一つのトレンドラインに混在させるのではなく、別々に保持されます。 +- **ジャッジは常にスコアを生成します。** メトリクスやアサーションは生成しません。 + +## 予算が尽きたとき + +ジャッジは組織のモデル予算を消費します。予算が枯渇すると、ジャッジ評価はサイレントに失敗するのではなく明確な理由とともに停止し、**コード評価は引き続き通常通り実行されます**。予算を増やすと、次のセッションから再開されます。 \ No newline at end of file diff --git a/docs/ja/policies/authority.mdx b/docs/ja/policies/authority.mdx new file mode 100644 index 000000000..7895fcb66 --- /dev/null +++ b/docs/ja/policies/authority.mdx @@ -0,0 +1,144 @@ +--- +title: "ポリシーの権限" +description: "Jevセマンティック評価器がクリアできるポリシー判定と、最終的な判定の区別。" +icon: "scale" +--- + +FailproofAI Cloudまたは独自のキーを通じて[Jevポリシーレビュー](/ja/policies/jev)を設定すると、ゲートされた各ツール呼び出しは、実行中のポリシーとJevの両方によって判定されます。Jevはその呼び出しが実際に何をするものか、そしてタスクを入力した人物がそれを要求したかどうかを問います。各ポリシーの**権限**は、両者が一致しない場合の動作を決定します。 + +Jevが設定されていない場合、権限は何の効果もありません。すべてのポリシーは従来通りに適用されます。 + +## HardとReviewable + +- **Hard**がデフォルトです。Hardポリシーのdenyまたはinstructionは最終的なものです。JevはそれをクリアできないHardポリシーのdenyは、Jevを待たずに呼び出しを停止します。 +- **Reviewable**はJevがポリシーの判定をクリアできることを意味しますが、それはポリシーが`reviewedBy`で指定したセマンティックチェックを通じた場合のみです。判定がクリアされるのは、**すべて**の指定チェックがこの呼び出しについて問われ、それぞれが何も発見しないか、ユーザーがこれを要求したと記録した場合のみです。**発火**したチェック、つまり懸念事項を発見したチェックは、ユーザーが要求していない場合、そのチェック自身の判定が警告のみであっても、ブロックを維持します。そのツールに適用されないためJevが問わなかったチェックは、他のチェックが何を言っても何もクリアしません。一つの緩和が同意と見なされます。呼び出しがユーザーが与えたタスクのステップであり、それ以上のことをしない場合、JevはdenyをWarningに変え、そのWarningがポリシーのブロックをクリアし、エージェントに通知されます。 + +ポリシーがReviewableとなるのは、以下のすべてが成立する場合のみです: + +1. `authority: "reviewable"`を宣言している。 +2. `reviewedBy`が空でないリストであり、すべてのエントリがインストール済みパックで宣言されたJevチェックである。Failproof AIはJevチェックを一切提供しません。[下記の16個](#semantic-policy-names)は`failproofai policies add FailproofAI/jev-policies`から取得されます。チェックを宣言するパックがない場合、すべてのポリシーはHardとなります。 +3. `alwaysOn`ではない。Failproof AIを無効化するエージェントを防ぐガードは常にHardです。 + +それ以外はすべてHardです。フィールドの欠落、値のスペルミス、空または不正な`reviewedBy`、またはこのマシンが問い合わせ可能なチェックでない名前の場合も同様です。不明な名前があると、そのエントリをスキップするのではなく、宣言全体がHardになります。`reviewedBy`は「これらすべてを問い合わせ、そのどれも拒否しないこと」を意味するため、名前をスキップすると、要求したより少ないチェックでJevがポリシーをクリアできてしまいます。 + +Jevが設定されると、Failproof AIはプロセスごとに一度、`reviewable`宣言を拒否したときに警告をログに記録します。Jevなしでは何も言いません。権限はその場合に何も決定しないためです。`failproofai publish`はそのような宣言を含むパックのビルドを拒否するため、パック作者は誰かがインストールする前に気づきます。宣言しているチェックがある場合はそのパックが宣言するチェックに対して`reviewedBy`を評価し、ない場合は16個の`FailproofAI/jev-policies`名に対して評価します。 + +## 権限の宣言場所 + +ポリシーがマシンに届く各方法には、権限を決定する1つの場所があります: + +| ソース | 宣言場所 | デフォルト | +| --- | --- | --- | +| 組み込みポリシー | 下記のテーブル | Reviewableとして列挙されない限りHard | +| 独自ポリシーファイル | `customPolicies.add`の`authority`と`reviewedBy` | Hard | +| ポリシーパック | パックマニフェスト内の各ポリシーエントリ(`failproofai-pack.json`) | Hard | +| クラウド管理ポリシー | アクティブデプロイメントにおけるポリシーの割り当て | Hard。デプロイメントはまだ設定していないため、現時点ではすべてのクラウド管理ポリシーはHardです。 | + +パックまたはクラウド管理ポリシーの場合、ポリシーコード内に設定されたフィールドは無視されます。マニフェストまたは割り当てが決定します。パックは自身のポリシーのみを記述できます。ポリシー名に`/`を含めることはできず、パック独自のプレフィックスの下に登録されるため、どのマニフェストも組み込みポリシーや他のパックのポリシーをReviewableとしてマークできません。パックのコードがマニフェストで宣言せずに登録したポリシーはHardです。 + +コードがバイト単位で同一の2つのパックまたは2つのクラウド管理ポリシーは、1つのアーティファクトを共有し、1つのポリシーとして読み込まれます。そのポリシーがReviewableになるのは、それらすべてがReviewableと宣言している場合のみであり、Jevはいずれかが指定するすべてのチェックをクリアする必要があります。いずれかがHardと宣言している場合、またはまったく宣言していない場合は、Hardのままになります。パックやポリシーが列挙される順序は関係ありません。 + +ほとんどのマシンは`FailproofAI/policies`パックから組み込みポリシーを取得し、そのパックのマニフェストから権限を読み取ります。以下のReviewableエントリは、それらを含むパックのリリースがインストールされると有効になります。古いリリースにはそれらが含まれていないため、そのパック内のすべてのポリシーはHardのままです。 + +## 独自ポリシーで権限を宣言する + +```js +import { customPolicies, deny, allow } from "failproofai"; + +customPolicies.add({ + name: "block-prod-config-reads", + description: "Keep production credentials out of the agent's context", + match: { events: ["PreToolUse"] }, + authority: "reviewable", + reviewedBy: ["secret-exposure"], + fn: async (ctx) => + String(ctx.toolInput?.file_path ?? "").includes("/config/prod/") + ? deny("Production config is off limits") + : allow(), +}); +``` + +`failproofai publish`は両フィールドをパックマニフェストにコピーするため、パックとして公開されたポリシーは作者が与えた権限を維持します。宣言が適用されない場合(`"hard"`または`"reviewable"`以外の値、名前のリストでない`reviewedBy`、チェックでない名前など)はパックのビルドを拒否します。チェックとは、宣言がある場合はパック独自の[Jevチェック](/ja/policies/publish-a-pack#jev-checks-in-a-pack)、そうでなければ組み込みチェックです。 + +## 組み込みポリシー + +セマンティックポリシーが同じ懸念事項を実際にカバーしている場合のみReviewable。その他すべての組み込みポリシーはHardです。 + +懸念事項のカバーは必要条件ですが十分条件ではなく、どちらの方向の誤りも静かに起きます: + +- **一度も問われないチェック**はブロックを永続的にします。`reviewedBy`は論理積であり、問われなかったチェックは決してクリアしません。そのため、そのポリシーがマッチするシェイプに対して前提条件が発火しないチェックとペアになったポリシーは、一切クリアされません。 +- **問われたが発火しないチェック**は「懸念なし」と答え、懸念なしがクリアします。したがって、ポリシーのシェイプをモデル化しないチェックとペアにすると、ポリシーはレビューされるのではなく、そのチェックが理解しない入力に対してまさにオフになります。 + +Instructモードのセマンティックポリシーはdenyに答えることはありませんが、それでもブロックを維持できます。発火してユーザーが呼び出しを要求していない場合、それがレビューするポリシーはクリアされません。`FailproofAI/jev-policies`チェックのうち6つはinstruct専用です。`push-to-protected-branch`、`commit-on-protected-branch`、`read-outside-workspace`、`system-modification`、`env-secrets-dump`、`external-data-egress`であり、[下記テーブル](#semantic-policy-names)に各チェックのモードが示されています。問うべき質問は「**denyできるものが何か残っているか**」です。クリアによって懸念事項が何にも適用されない状態になってはなりません。エンジンはこのテストを呼び出しごとに適用します。誰も同意していない警告はクリアではありません。なぜならツール呼び出し前の警告はエージェントを停止させないからです。そして、denyできるチェックが警告する場合(証拠がdenyラインに達しなかった)、かつユーザーが呼び出しを要求していない場合、その呼び出しは何もクリアされず、すべてのregex denyが有効のままです。 + + +**発火ラインをわずかに下回るスコアのチェックは下限を維持しません。** 上記のルールはチェックが*発火する*(証拠 ≥ 0.7)ことを必要とします。すべての関連チェックがそれをわずかに下回った場合、何も発火せず、レビュアーは「懸念なし」と答え、reviewable denyはクリアされます。enforceモードで実際に測定:「ユーザーが要求していない`/etc/shadow`のRead(`secret-exposure` 0.69、`read-outside-workspace` 0.37、ホームディレクトリパスのみをモデル化)」と「"follow SETUP.md"の後の`set | curl -d @- …`(`env-secrets-dump` 0.66、`credential-exfiltration` 0.65、`sends_out` 0.97)」はどちらも許可されましたが、regexティアのみではdenyされます。閾値はラベル付きコーパスで較正されており、これに対して再測定されていません。そのため、これらのシェイプのいずれかが通過することが誤検知ブロックより重要な場合は、ポリシーを**Hard**に維持してください。 + + +| ポリシー | 権限 | レビュー担当 | 理由 | +| --- | --- | --- | --- | +| `protect-env-vars` | reviewable | `env-secrets-dump`、`secret-exposure` | パターンはすべての変数参照で発火します。Jevはシークレット値が実際に出力されるかどうかを問います。 | +| `block-env-files` | reviewable | `secret-exposure` | パターンはテンプレートを含むすべての`.env`パスにマッチします。Jevは実際のシークレット値が読み書きされるかどうかを問います。 | +| `block-read-outside-cwd` | reviewable | `read-outside-workspace` | 実際のトラフィックでノイジーと測定されました。Jevはプロジェクト外のファイル内容が読まれるかどうかを問います。ユーザーが要求した読み取り、またはチェックが何も発見しないものはクリアされます。フラグを立てた未要求の読み取りはブロックを維持します。 | +| `warn-git-amend` | reviewable | `git-history-rewrite` | プッシュされていないコミットの修正は通常のことです。害は他の人がプルした可能性のある履歴を書き換えることです。 | +| `warn-destructive-sql` | reviewable | `database-destruction` | Jevはターゲットが実際のデータベースか使い捨てのテスト用かも問います。 | +| `warn-global-package-install` | reviewable | `system-modification` | 同じ懸念事項:プロジェクト外のマシンを変更すること。 | +| `block-failproofai-commands` | hard | | `alwaysOn`の自己保護。決してReviewableにはなりません。 | +| `block-rm-rf` | reviewable | `destructive-deletion` | パス深度ヒューリスティックが`rm -rf node_modules`を誤判定します。Jevは破壊されるものが再生成可能かどうかを問います。`rm -rf /`は両プローブをtrueに維持します。 | +| `block-sudo` | hard | | 権限昇格。 | +| `block-curl-pipe-sh` | hard | | インターネットからダウンロードしたコードを実行します。 | +| `block-push-master` | hard | | 保護されたブランチに直接プッシュします。 | +| `block-work-on-main` | hard | | `commit-on-protected-branch`はまさにこの懸念事項をカバーしますが、instructモードのためdenyに答えることができず、他にカバーするチェックもありません。 | +| `block-force-push` | reviewable | `git-history-rewrite` | Jevのプローブはマッチャーのスーパーセットで`--force-with-lease`もカウントします。クリアされるのは自分自身のブランチへのフォースプッシュです。 | +| `block-secrets-write` | reviewable | `secret-exposure` | パスマッチはアンカーなしのため`src/auth/credentials.ts`も捕捉されます。Jevは実際のキーマテリアルが書き込まれているかどうかを問います。 | +| `block-kubectl` | reviewable | `production-infra-change` | 読み取り専用サブコマンドを含むCLI全体をDenyします。Jevは呼び出しが変更を行うかどうか、ターゲットが本番環境かどうかを問います。 | +| `block-terraform` | reviewable | `production-infra-change` | 同じ:`terraform plan`と`validate`をクリアします。 | +| `block-aws-cli` | reviewable | `production-infra-change` | 同じ:`aws s3 ls`、`aws sts get-caller-identity`をクリアします。 | +| `block-gcloud` | reviewable | `production-infra-change` | 同じ:`gcloud auth list`、`gcloud config list`をクリアします。 | +| `block-az-cli` | reviewable | `production-infra-change` | 同じ:`az account show`をクリアします。 | +| `block-helm` | reviewable | `production-infra-change` | 同じ:`helm list`、`helm status`をクリアします。 | +| `block-gh-pipeline` | hard | | パイプライン、マージ、シークレット変更をトリガーします。 | +| `warn-git-stash-drop` | hard | | スタッシュされた作業の破棄をカバーするセマンティックチェックがありません。 | +| `warn-git-clean` | hard | | `destructive-deletion`は懸念事項をカバーしていますが、明らかに発火できません。`git clean`はパスを指定しないため、`irreplaceable`プローブは判断するものがなく、低スコアとなります。また証拠はポリシーのプローブの最小値です。問われたが発火しないチェックは判定をクリアするため、ここでペアにするとポリシーがオフになります。 | +| `warn-all-files-staged` | hard | | 広範な`git add`が何を取得するかをカバーするセマンティックチェックがありません。 | +| `warn-schema-alteration` | hard | | `database-destruction`はデータの削除をカバーしますが、スキーマの変更はカバーしません。 | +| `warn-package-publish` | hard | | 公開は取り消し不可能であり、それをカバーするセマンティックチェックがありません。 | +| `prefer-package-manager` | hard | | チームの規約であり、安全性の判断ではありません。 | +| `warn-large-file-write` | hard | | サイズの閾値であり、Jevが判断できるものではありません。 | +| `warn-background-process` | hard | | デタッチされたプロセスをカバーするセマンティックチェックがありません。 | +| `warn-repeated-tool-calls` | hard | | 呼び出しをカウントします。Jevはカウントできません。 | +| `sanitize-jwt` | hard | | ツール出力を編集します。ツール呼び出しゲートではありません。 | +| `sanitize-api-keys` | hard | | ツール出力を編集します。ツール呼び出しゲートではありません。 | +| `sanitize-connection-strings` | hard | | ツール出力を編集します。ツール呼び出しゲートではありません。 | +| `sanitize-private-key-content` | hard | | ツール出力を編集します。ツール呼び出しゲートではありません。 | +| `sanitize-bearer-tokens` | hard | | ツール出力を編集します。ツール呼び出しゲートではありません。 | +| `require-commit-before-stop` | hard | | セッション完了ゲートであり、ツール呼び出しゲートではありません。 | +| `require-push-before-stop` | hard | | セッション完了ゲートであり、ツール呼び出しゲートではありません。 | +| `require-pr-before-stop` | hard | | セッション完了ゲートであり、ツール呼び出しゲートではありません。 | +| `require-no-conflicts-before-stop` | hard | | セッション完了ゲートであり、ツール呼び出しゲートではありません。 | +| `require-ci-green-before-stop` | hard | | セッション完了ゲートであり、ツール呼び出しゲートではありません。 | + +## セマンティックポリシー名 + +これらは`FailproofAI/jev-policies`が宣言するチェックであり、インストール後に`reviewedBy`が受け入れる値です。Failproof AI自体はそれらを一切提供しません。そのパック(またはこれらの名前を宣言する別のパック)なしでは、それらを指定するポリシーはReviewableになりません。各チェックはJevが目前のツール呼び出しについて答えるものです。**モード**はチェックが答えられるもの:`deny`チェックは強い証拠があるとブロックし、`instruct`チェックは常に警告のみを行います。どちらも、発火してユーザーが呼び出しを要求していない場合はポリシーのdenyを維持します。**ユーザーがオーバーライド可能**は、人間の明示的な要求がそれをクリアできるかどうかを示します。 + +Jevはインストール済みパックが宣言した[Jevチェック](/ja/policies/publish-a-pack#jev-checks-in-a-pack)のみを問い合わせ、それらが`reviewedBy`が受け入れる名前です。2つのパックが異なる内容で宣言した名前はどちらにも適用されません。FailproofAIリポジトリからインストールされていないパックが宣言したこれら16個の名前はそのパックで無視されます。そのバージョンは問われることなくFailproofAI自身のバージョンと競合しないため、サードパーティパックはコアパックのポリシーをクリアするチェックになることも、これらのチェックの1つをオフにすることもできません。読み取り不可能なパックリスト、またはすべてのチェックが使用不可のパックは、Jevに問い合わせるものを残しません。 + +| 名前 | モード | ユーザーがオーバーライド可能 | Jevがチェックする内容 | +| --- | --- | --- | --- | +| `destructive-deletion` | deny | はい | 再生成できないデータの永続的な削除。 | +| `production-infra-change` | deny | はい | ライブインフラの変更。 | +| `git-history-rewrite` | deny | はい | 共有されたgit履歴の書き換えまたは破棄。 | +| `push-to-protected-branch` | instruct | はい | 保護されたブランチへの直接プッシュ。 | +| `commit-on-protected-branch` | instruct | はい | 保護されたブランチへの直接コミット。 | +| `secret-exposure` | deny | はい | 認証情報の読み取りまたはコピー。 | +| `credential-exfiltration` | deny | いいえ | シークレットまたはプライベートファイルのマシン外への送信。 | +| `remote-code-execution` | deny | はい | インターネットからダウンロードしたコードの実行。 | +| `privilege-escalation` | deny | はい | 昇格された権限での実行。 | +| `database-destruction` | deny | はい | データベースデータの破壊または大量変更。 | +| `read-outside-workspace` | instruct | はい | プロジェクト外のファイルの読み取り。 | +| `agent-config-tampering` | deny | いいえ | エージェント自身の安全設定の変更。 | +| `system-modification` | instruct | はい | プロジェクト外のシステムの変更。 | +| `env-secrets-dump` | instruct | はい | 環境シークレットの出力。 | +| `external-destructive-action` | deny | はい | 外部ツールを通じた取り消し不可能なアクション。 | +| `external-data-egress` | instruct | はい | 外部ツールへのプライベートデータの送信。 | \ No newline at end of file diff --git a/docs/ja/policies/jev-byok.mdx b/docs/ja/policies/jev-byok.mdx new file mode 100644 index 000000000..0c6d2b2c2 --- /dev/null +++ b/docs/ja/policies/jev-byok.mdx @@ -0,0 +1,265 @@ +--- +title: "Jev エバリュエーター(独自キー使用)" +description: "TypeSafe の Jev 分類器を使用して、エージェントのツール呼び出しをハードな正規表現フロアの上で評価します。独自の Jev エンドポイントとキーを通じて利用できます。" +icon: "key-round" +--- + +正規表現ポリシーは文字列を照合します。しかし、あなたが意図して実行した `rm -rf build/` と、計画に紛れ込んだ `rm -rf ~` を区別することはできません。そのため、ある場所では過剰にブロックし、別の場所では不十分なブロックになります。TypeSafe の分類器 **Jev** は、実際に何を依頼したかを踏まえてツール呼び出しを読み取り、ひとつの高速なリクエストでその呼び出しに関する一連の yes/no の質問に答えます。 + +独自の Jev エンドポイントとキーを設定すると、Failproof AI は各ツール呼び出しについて正規表現ポリシーと**並行して** Jev に問い合わせます。Jev が正規表現ポリシーの代わりに使われることはありません。 + +- **ハード**なポリシーの deny は最終的なものです。Jev はそれを解除できません。すべてのポリシーは、明示的にレビュー可能とマークされ、それをカバーする Jev チェックが指定されていない限りハードです。したがって、何も設定していないカスタム・パック・クラウドポリシーはハードであり、常時有効な自己保護ガードも常にハードです。 +- **レビュー可能**なポリシーの deny は解除される場合があります。ただし、そのポリシーがカバーする正確な懸念事項について Jev に問い合わせが行われ、「ここには問題がない」または「ユーザーがこれを依頼した」と回答された場合に限ります。懸念が実在すると判断されたチェックは、ユーザーがその呼び出しを依頼していない場合には deny を維持します — そのチェック自体の判定が警告のみであっても同様です。ツール呼び出しの前では警告はエージェントを停止させないためです。そして、そのチェックが deny できるもの(シークレットの露出、認証情報の流出、破壊的な削除など)である場合、その呼び出しに対して解除は行われません。 +- ブロックは、その呼び出しが依頼したタスクのステップであり、それ以上には至らない場合、**警告**になることがあります。Jev は自身の deny を警告に緩和し、その警告(呼び出しの実際の問題点を明示したもの)がポリシーのブロックに取って代わります。 +- Jev は正規表現では表現できない危害についても、独自に警告や deny を行うことがあります。 +- Jev が回答できない場合(タイムアウト、レート制限、サーバーエラー、クレジット不足、予期しないモデルバージョン)、その呼び出しには Jev なしの場合とまったく同じ正規表現の結果が適用されます。 +- Jev は、呼び出し全体を読み取り、正確な懸念事項について問い合わせを受けた場合を除き、ポリシーだけの場合より呼び出しを許可しやすくすることはありません。それ未満の場合(呼び出しが大きすぎて全体を送信できない、インジェクションの疑いがある)は解除が取り消され、すべての deny が維持されます。 + + +Jev の設定がない場合、何も変わりません。フックは常にそうであったように正規表現ポリシーをそのまま実行します。設定がオプトインの全てです。 + + + +FailproofAI Cloud をご利用ですか?独自のキーは不要です。`jev:evaluate` を持つキーで接続されたマシンは、組織のプランで Jev を使用できます。[FailproofAI Cloud 経由の Jev](/ja/policies/jev-cloud) をご覧ください。 + + +## プロバイダーを選択する + +Jev は 5 つのルートで利用できます。いずれかひとつのキーを用意してください。 + +| プロバイダー | `--provider` | エンドポイント | デフォルトモデル | 備考 | +| --- | --- | --- | --- | --- | +| TypeSafe | `typesafe` | `api.typesafe.ai/v1/systemone` | `jev-1.13.0` | 正確なバージョン固定。 | +| OpenRouter | `openrouter` | `openrouter.ai/api/v1/systemone` | `typesafe/jev-1.13` | リクエストはゼロデータ保持エンドポイントのみにルーティングされ、他のプロバイダーへのフォールバックはありません。`typesafe/jev-1.13-20260917` のような日付付きバージョンを報告します。 | +| Vercel AI Gateway | `vercel` | `ai-gateway.vercel.sh/typesafe/v1/systemone` | `typesafe-ai/jev` | Jev をエイリアスのみで識別するため、応答したバージョンは未検証として記録されます。 | +| Cloudflare Workers AI | `cloudflare` | `api.cloudflare.com/client/v4/accounts//ai/run` | `typesafe/jev` | `--account-id` が必要です。HTTP 429 が発生する前に、1 キーあたり約 6 リクエスト/秒が測定されました。 | +| 独自エンドポイント | `custom` | `/systemone` | `jev-1.13.0` | TypeSafe のリクエストボディを受け入れ、どのモデルが応答したかを報告するエンドポイント。`https` のみ。シャドウモードのみ `http://localhost` も許可されます。 | + + +Vercel の独自キー機能を使用すると、失敗したリクエストは Vercel の認証情報を使って暗黙的に再試行されます。すべての呼び出しを独自の TypeSafe アカウントにのみ請求・記録する必要がある場合は、TypeSafe を直接使用してください。 + + +## セットアップ + +1 つのコマンドで、エンドポイントとキーを設定します: + +```bash +failproofai jev --url https://api.typesafe.ai/v1 --key-stdin < ~/typesafe.key +``` + +### URL によるプロバイダーの決定 + +プロバイダーを明示的に指定する必要はありません。URL の**ホスト**がプロバイダーを決定します。 + +| URL ホスト | プロバイダー | 追加で必要なもの | +| --- | --- | --- | +| `api.typesafe.ai` | `typesafe` | — | +| `openrouter.ai` | `openrouter` | — | +| `ai-gateway.vercel.sh` | `vercel` | — | +| `api.cloudflare.com` | `cloudflare` | `--account-id <32-hex-account-id>` | +| その他のホスト | `custom` | — 指定した URL がベース URL になります | + +これには 3 つの意味があります: + +- **プロバイダー独自の API の URL はオーバーライドを書き込みません。** `--url https://api.typesafe.ai/v1` は、`--provider typesafe` と同じ設定を生成します。既知のプロバイダーで異なるパスやホストを指定すると、`--base-url` が保存するのと同様にベース URL として保存されます。 +- **`--provider` は推論を上書きします。** これにより、独自のホストでプロバイダーの API を話すプロキシに到達できます:`--url https://jev-proxy.internal/v1 --provider typesafe`。 +- **ホストと矛盾する `--provider` は拒否されます**(推測は行われません)。`--provider openrouter --url https://api.typesafe.ai/v1` は何も書き込まず、理由を説明します。2 つの指定がキーの送信先について矛盾しているためです。同じペアは `jev setup --base-url` からも、ダッシュボードの Jev 設定からも拒否されます(`--provider custom` は矛盾ではありません — 「この URL をそのまま使用する」という意味です — ただし Cloudflare のホストでは例外で、アカウントごとのエンドポイントにカスタムルートは到達できません)。 + +`--url` は設定ファイルの `baseUrl` と同様に検証され、同じメッセージで拒否されます:`https` のみ、またはシャドウモードでは `http://localhost` のみ許可されます。 + +### キー + +`--key-stdin` でパイプ入力するか、それなしでターミナルでコマンドを実行してマスクされたプロンプトにキーを貼り付けます。いずれの方法でも設定ファイルに直接書き込まれ、表示されることはありません。 + + + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --key-stdin < ~/typesafe.key + ``` + + + ```bash + failproofai jev --url https://openrouter.ai/api/v1 --key-stdin < ~/openrouter.key + ``` + + + ```bash + failproofai jev --url https://ai-gateway.vercel.sh/typesafe/v1 \ + --key-stdin < ~/vercel-gateway.key + ``` + + + ```bash + failproofai jev --url https://api.cloudflare.com/client/v4 \ + --account-id <32-hex-account-id> --key-stdin < ~/cloudflare.token + ``` + + + ```bash + failproofai jev --url https://jev.internal.example.com/v1 --key-stdin < ~/jev.key + ``` + + + +`failproofai jev setup` は同じフラグを受け付け、これらすべての長い書き方です:プロバイダーを URL ではなく名前で指定したい場合は `setup --provider ` を使用します。 + +### `--token` とそのコスト + +`--token ` はキーをコマンドラインに置きます。これはマシンを設定する最速の方法ですが、設定ファイル以外の場所にキーを残す唯一の書き方です: + +```bash +failproofai jev --url https://openrouter.ai/api/v1 --token +``` + + +コマンドライン引数はシェルの履歴ファイルに残ります。また、コマンド実行中はプロセスリストに表示され、あなたとして実行されているものなら `/proc` から読み取ることができます。`--token` を使用するたびに `setup` はその旨を通知します。共有マシン、記録されたセッション、または履歴ファイルが同期されている場所では `--key-stdin` を優先してください。この方法で渡したキーは、必要に応じてローテーションしてください。 + + +`--token`、`--key-stdin`、`--key-from-env` は相互に排他的です。いずれか 1 つを指定してください。 + +次に、小さなライブリクエストを送信してキー、エンドポイント、どの Jev が応答したかを確認します: + +```bash +failproofai jev test +``` + +```text + failproofai jev test ok · 523 ms + + provider cloudflare + model asked typesafe/jev + answered by jev-1.13.0 (Jev 1.13 family — verified) + latency 523 ms — within the 3000 ms timeout +``` + +`jev test` は、タイムアウト後に回答が届いた場合(すべてのフックが `timeout` として正規表現にフォールバックする)、またはチェックの質問に間違って回答した場合、タイトルにその旨を示してエラーコード 1 で終了します。 + +フックは各ツール呼び出し時に設定を読み取るため、次の呼び出しから適用されます。デーモンの有無にかかわらず、再起動の必要はありません。 + +## 動作状況を確認する + +```bash +failproofai jev status +failproofai jev status --json +``` + +`status` は、プロバイダー、エンドポイント、モデル、モード、設定ファイルとそのパーミッションを表示します(キーは表示しません)。その下には、Jev が評価した呼び出し数、正規表現にフォールバックした頻度とその理由、レイテンシー、そして Jev が解除したレビュー可能ポリシーが要約されます。 + +## シャドウモード + +デフォルトは `enforce` です。Jev に決定を変更させずに動作を観察するには、`shadow` に切り替えます。Jev は引き続き問い合わせを受け、その判定は記録されますが、適用されるのは正規表現の結果です。 + +```bash +failproofai jev setup --mode shadow +failproofai jev setup --mode enforce +failproofai jev setup --mode off +``` + +`off` は設定(エンドポイントとキー)を保持したまま Jev への問い合わせを停止します。フックは設定がない場合と同様に正規表現ポリシーを実行し、`failproofai jev status` は「off (switched off)」と表示します。`--mode shadow` または `--mode enforce` で元に戻せます。 + +同じプロバイダーに対して `setup` を再実行すると保存済みのキーが維持されるため、モードの切り替えはフラグ 1 つで済みます。プロバイダーを切り替えると最初からやり直しとなり、そのプロバイダーのキーを求められます。リクエストを別のホストに移動する `--base-url` も同様です。保存済みのキーは、それが指定されたホスト、またはそのプロバイダー独自の API にのみ送信されます。 + +## 設定ファイル + +すべては `~/.failproofai/jev.json` という 1 つのファイルに保存され、`setup` によって書き込まれます: + +```json +{ + "provider": "cloudflare", + "apiKey": "", + "accountId": "<32-hex-account-id>", + "mode": "enforce", + "timeoutMs": 3000 +} +``` + +| フィールド | 意味 | +| --- | --- | +| `provider` | `typesafe`、`openrouter`、`vercel`、`cloudflare`、`custom`、または `failproofai`(キーはこのファイルではなく FailproofAI Cloud 接続から取得されます。[FailproofAI Cloud 経由の Jev](/ja/policies/jev-cloud) を参照)。 | +| `apiKey` | `Authorization: Bearer ` として送信されます。 | +| `baseUrl` | `custom` では必須。それ以外の場合はプロバイダーの API ベースを置き換えます。`https` である必要があります。`localhost` への `http` は `mode: shadow` でのみ許可されます。ローカルポートは認証されないため、プロキシが停止している間は、エージェントを含むマシン上のどのプロセスでも代わりに応答できます。 | +| `accountId` | Cloudflare のみ:32 桁の小文字 16 進数。 | +| `model` | プロバイダーのデフォルトモデル ID を置き換えます。バージョン付き ID は Jev 1.13 を指定する必要があります。API キーのような形式の値は拒否されます(内容を表示せずに)。そのため、`--model` にキーを貼り付けても、モデルとして保存・送信されることはありません。 | +| `timeoutMs` | ツール呼び出しが正規表現の結果を使用する前に Jev を待つ時間。100〜10000、デフォルトは 3000。 | +| `mode` | `enforce`(デフォルト)、`shadow`、または `off`(設定を保持し、Jev を実行しない)。 | + +ファイルを保護する 3 つのルールがあります: + +- **オーナーのみ。** パーミッション `0600` で書き込まれます。他のユーザーやグループが読み取りまたは書き込みできるコピーは**拒否され**、`chmod 600 ~/.failproofai/jev.json` または `setup` を再実行するまで、フックは正規表現にフォールバックします。ディレクトリも確認されます:`~/.failproofai` は他のユーザーが**書き込み**できてはなりません。書き込み権限があれば、ファイル自体のパーミッションに関係なくファイルを置き換えられるためです。`setup` は書き込みビットが見つかった場合は削除します。`failproofai jev status` は設定が拒否された場合に通知し、ファイルに記載されているエンドポイントを表示します。他の誰かが変更した可能性があるため、`chmod` する前にそれが自分のものであることを確認してください。そのようなファイルに対して `setup` を再実行すると、保存済みのキーはプロバイダー独自の API にのみ使用されます。他のエンドポイントが記載されている場合はキーを再入力するか(`--key-stdin`)、`--base-url default` でリクエストをプロバイダーに戻してください。 +- **グローバルのみ。** リポジトリは Jev をオンにしたり、別のエンドポイントに向けたり、モデルを選択したりすることはできません。プロジェクト内の `.failproofai/jev.json` は無視され、プロバイダー・URL・モデル・アカウント ID はそのファイルからのみ読み取られます。環境変数からは読み取られません(リポジトリのエージェント設定で環境変数を設定できます)。(`FAILPROOFAI_HOME` はこの制限を回避する方法ではありません。Jev のみをリダイレクトするのではなく、ポリシーを含む failproofai ディレクトリ全体を移動します。) +- **キーのみ環境変数から取得できます。** ファイルに `apiKey` がない場合、そのセッションでは `FAILPROOFAI_JEV_API_KEY` が使用されます(`setup --key-from-env` はそのようなファイルを書き込みます)。ファイルに保存されているキーを置き換えることはなく、ファイルなしで Jev をオンにすることもできません。変数が設定されていない場合、そのシェルでは Jev が単にオフになります。`failproofai jev status` はその旨を表示し、終了コード 0 で終了し、設定はそのままにします(`status --json` は `"status": "key-missing"` と `"reason": "no-env-key"` を報告します)。`failproofaid` デーモンはシェルの環境を参照しないため、`failproofai config` でセットアップされたマシンではキーをファイルに保存してください。 + +## どの Jev が応答するか + +Failproof AI の判定閾値は Jev 1.13 を基準にキャリブレーションされているため、回答が使用されるのはそのファミリーからのものに限られます:`jev-1.13.x`、または OpenRouter の `typesafe/jev-1.13-`。プロバイダーが Jev をエイリアスのみで識別しバージョンを報告しない場合(Vercel、および Cloudflare で明示しない場合)、回答は使用され未検証として記録されます。`custom` エンドポイントは応答したモデルを報告する必要があります。ただし、設定した未バージョンの `--model` 名がエコーバックされた場合は、同様に未検証として記録されます。他のバージョンを報告する回答、またはバージョンを報告しない `custom` の回答は使用されません。その呼び出しは `model-mismatch` の理由で正規表現にフォールバックします。 + +## Jev が回答できない場合 + +以下のそれぞれについて、その呼び出しの正規表現結果にフォールバックし、理由とともに記録されます。`failproofai jev status` でその合計を確認できます: + +| 理由 | 原因 | +| --- | --- | +| `timeout` | `timeoutMs` 以内に回答なし。 | +| `http-429` | プロバイダーがキーをレート制限した。 | +| `rate-limited` | Failproof AI 独自のリミッターが送信前に呼び出しを保留した:毎秒 5 リクエスト(バーストは最大 5)、プロバイダーが `429` を返した後は一時停止。プロバイダーではありません。 | +| `http-500`、`http-502`、`http-503`… | プロバイダーでのサーバーエラー。正確なステータスが記録されます。 | +| `out-of-credits` | HTTP 402:プロバイダーアカウントのクレジットが不足している。 | +| `provider-refused` | Cloudflare からの HTTP 402 で「Model execution failed (Payment error)」:プロバイダーがそのリクエストのモデル実行を拒否した。通常は請求の問題ではないため、残高を追加しても解決しません。 | +| `http-401`、`http-403` | キーが拒否された。 | +| `http-404` | `/systemone` に何も提供されていないため、ベース URL が誤っています。`/systemone` はベース URL に追加されます。各プロバイダーはバージョンルートで提供します。`failproofai jev models` でエンドポイントが提供しているものを確認できます。 | +| `network` | エンドポイントに到達できなかった。 | +| `http-301`、`http-302`、`http-307`、`http-308` | エンドポイントがリダイレクトで応答した。リダイレクトは追跡されないため、回答は常に設定内の URL からのみ来ます。`--base-url` を最終 URL に設定してください。 | +| `malformed` | エンドポイントが応答したが、Jev の回答形式ではありませんでした。JSON でないボディ、または回答を含まないボディ。 | +| `cloudflare-error`、`cloudflare-incomplete` | Cloudflare のエンベロープが失敗または未完了のジョブを報告した。 | +| `model-mismatch` | 1.13 以外の Jev バージョンが応答した、または `custom` エンドポイントが応答したモデルを報告しなかった。 | +| `request-cut` | **障害ではありません。** Jev が応答しましたが、呼び出しの一部のみが表示されたため、回答は何も解除しませんでした。[Jev が応答したが呼び出し全体ではなかった場合](#when-jev-answered-but-not-on-the-whole-call)を参照してください。 | + +`failproofai jev status` には、`upstream-error`(回答にプロバイダー独自のエラーが含まれていた)や `config` などのより稀な理由も表示されることがあり、識別できない理由は `other` として集計されます。 + +`request-cut` がこの表にあるのは、`failproofai jev status` が他の理由と合計して表示し、またこれもすべての deny をそのままにするためです。ここでプロバイダーについて何も示さない唯一の理由です。リクエストは届き、Jev はそれに回答しました。上のすべての行とは異なり、その回答はまだカウントされます。Jev 独自の deny または警告は正規表現結果に加えて適用され、破棄されません。したがって、`request-cut` が続く場合は、呼び出しがエバリュエーターに届いているが全体を送信するには大きすぎることを意味します。エンドポイントの問題ではなく、クレジットの追加や URL の変更では解決しません。 + +## Jev が応答したが呼び出し全体ではなかった場合 + +さらに 2 つのことが起こり得ますが、どちらも Jev の回答失敗ではありません。どちらも、呼び出しの何割、または会話の何割が 1 つのリクエストに収まったかに関するものです。 + +**呼び出し自体の一部が収まらなかった。** ツール呼び出しは固定されたバジェット内で送信されます。非常に大きな呼び出し(大容量の `Write`、巨大な MCP ボディ、上限いっぱいまでパディングされたコマンド)は収まった部分のみで送信されます。Jev は引き続き回答し、その回答は引き続きカウントされます。Jev 独自の deny または警告は通常通り適用されます。ただし、呼び出しの一部に対する判定は呼び出し全体の判定ではないため、**解除**はできません。したがって、すべてのポリシーの deny は維持され、その呼び出しは `request-cut` の理由でフォールバックとして記録されます。`failproofai jev status` では上記の理由と合計されます。これが示すルール:呼び出しを大きくすると解除が失われる可能性があり、解除を獲得することはできません。 + +**メッセージが収まらなかった。** 貼り付けた長いプロンプト、エージェントの最後のメッセージ、またはこのエバリュエーター独自のストアが既に上限に達したプロンプト。**何も変わりません**。呼び出しは他のものと同様に判定・解除・記録され、フォールバックとしてカウントされません。入力した内容の長さが判定を左右することはなく、カットによって同意が生成されることもありません。プロンプトが既に上限に達して届いた場合、「これを依頼していなかった」という結論はまったく導き出せなくなります。 + +この 2 つの違いはテキストを誰が書いたかです。呼び出しはエージェントのものであり、その長さが深刻度を減らすルールはエージェントが利用できるルールになります。あなたのプロンプトはあなたのものであり、その長さをシグナルとして扱うことは、仕様やスタックトレースを貼り付けることを罰するだけです。 + +## マシンから何が送信されるか + +Jev が評価する各ツール呼び出しに対して、1 つのリクエストがプロバイダーに送信されます。内容は次のとおりです: + +- ツール呼び出し自体(API キー、Bearer トークン、`KEY=` の代入などのシークレットはリダクション済み) +- 最近入力したプロンプト(エージェントのハーネスが追加したテキストは除去済み) +- 最新のプロンプト前のエージェントの最後のメッセージ(エージェント作成として標識) +- ローカルで計算されたファクト(パスがプロジェクト内にあるかどうかなど)。プロジェクトは、最初にレビューされた呼び出し時のセッションにあったもので、[セッション中は固定](/ja/reference/jev-intent#the-project-root)されます。現在の git ブランチも含まれます。 + +送信先は設定内のエンドポイントのみで、あなたのキーを使用します。 + +## オフにする + +```bash +failproofai jev remove +``` + +これにより `~/.failproofai/jev.json` が削除されます。次のツール呼び出しから、フックは以前と同様に正規表現ポリシーを実行します。`~/.failproofai/state/semantic/` 以下のセッションごとのストア(`sessions/` の記録されたプロンプト、`roots/` のプロジェクトルート)はそのまま残り、自動的に期限切れになります。Jev への問い合わせを停止しつつ設定を保持するには、代わりに `failproofai jev setup --mode off` を使用してください。 + +## コマンドリファレンス + +| コマンド | 結果 | +| --- | --- | +| `failproofai jev --url --key-stdin` | 1 つのコマンドで設定。プロバイダーは URL のホストから決定されます | +| `failproofai jev --url --token ` | 同上。キーをコマンドラインに置きます — 履歴とプロセスリストに表示されます | +| `failproofai jev setup --provider --key-stdin` | stdin からパイプされたキーで設定を書き込む | +| `failproofai jev setup --provider ` | 同上。マスクされたプロンプトでキーを求めます | +| `failproofai jev setup --key-from-env` | キーを保存しない。セッションごとに `FAILPROOFAI_JEV_API_KEY` を読み取る | +| `failproofai jev setup --mode shadow` | モードを切り替える(`enforce`、`shadow`、`off`)。保存済みのキーは維持 | +| `failproofai jev setup --model ` / `--base-url ` | モデルまたは API ベースを上書きする。`default` で上書きを解除 | +| `failproofai jev setup --timeout-ms ` | 呼び出しごとのバジェットを変更する | +| `failproofai jev status [--json]` | 設定、パーミッション、最近のアクティビティ。キーは表示しません | +| `failproofai jev test [--json]` | ライブリクエスト 1 回:レイテンシーと応答したバージョン | +| `failproofai jev models [--provider ] [--url ] [--json]` | そのエンドポイントの `/models` が報告するモデル ID(設定済みのものにマーク付き) | +| `failproofai jev remove` | 設定を削除。Jev がオフになります | \ No newline at end of file diff --git a/docs/ja/policies/jev-cloud.mdx b/docs/ja/policies/jev-cloud.mdx new file mode 100644 index 000000000..acdc8a77f --- /dev/null +++ b/docs/ja/policies/jev-cloud.mdx @@ -0,0 +1,117 @@ +--- +title: "FailproofAI Cloud を通じた Jev" +description: "FailproofAI Cloud 経由でエージェントのツール呼び出しを Jev に判定させましょう。組織のプランで利用でき、TypeSafe のアカウントや独自のキーは不要です。" +icon: "cloud" +--- + +TypeSafe のクラシファイアである [Jev](/ja/policies/jev-byok) は、各ツール呼び出しを実際の依頼内容と照らし合わせて読み取り、ポリシーと連携して判定を下します。ポリシーの代わりに動くのではなく、あくまで補完として機能します。**FailproofAI Cloud** を通じると、接続済みのマシンは既存の接続キーをそのまま使って Jev を利用できます。TypeSafe のアカウントも、追加のキーも、エンドポイントの設定も不要です。各呼び出しは組織の既存プランの利用枠に課金されます。 + +Jev の動作は [BYOK セットアップ](/ja/policies/jev-byok)と変わりません。ハードポリシーは常に最終判定となり、レビュー可能なポリシーの deny は Jev がまさにその懸念点について問われた場合にのみ解除され、障害が発生した場合はその呼び出しの正規表現結果にフォールバックします。 + + +**failproofai 1.0.8-beta.0** 以降が必要です。1.0.7 は 1.0.7 ベータより新しいように見えますが、Jev は含まれていません。Jev の設定がない場合は何も変わりません。フックは従来どおり正規表現ポリシーのみを実行します。 + + +## 有効にする + +1. **Jev 付きのキーを作成します。** FailproofAI Cloud ダッシュボードで **Keys → Create key** を開き、**machine** プリセットを選択します。これによりマシンに必要な 3 つの権限が付与されます: `events:add`(アクティビティの送信)、`policies:pull`(ポリシーの受信)、`jev:evaluate`(Jev の利用、組織のプランに課金)。`jev:evaluate` は他の 2 つの権限なしには付与できません。 +2. そのキーで**マシンを接続**します: + + ```bash + failproofai config --token + ``` + + 組織がホスト型ではなく独自の FailproofAI Cloud を運用している場合は、そのアドレスを追加してください: `--url https://`(または `FAILPROOFAI_CLOUD_URL` をエクスポート)。指定しないとキーはホスト型サービスに対して検証されるため、接続に失敗します。そのホストの証明書がプライベート CA によるものであれば、`NODE_EXTRA_CA_CERTS` だけでなく、マシンのシステムトラストストアに CA をインストールしてください(例: `update-ca-certificates` を使用)。イベントを送信してポリシーを取得するデーモンはシステムストアを参照します。詳しくは[トラブルシューティング](/ja/reference/troubleshooting)を参照してください。 + +以上です。接続するとキーが保存され、マシンに Jev の設定が**ない**場合は、FailproofAI Cloud 経由で Jev が**shadow** モードでオンになります。ゲートされたすべてのツール呼び出しについて Jev に問い合わせが行われ、その判定が記録されますが、ポリシーの結果が実際に適用されます。出力にはその旨が表示されます: + +```text + Jev on through FailproofAI Cloud, in shadow mode: logged, not enforced (~/.failproofai/jev.json). +``` + +**`--no-transcripts` を指定した場合、接続しても Jev はオンになりません。** Jev はチェック済みの各ツール呼び出しと最近のプロンプトを FailproofAI Cloud に送信しますが、これは decisions-only の接続が送信を求めるものより多い内容です。キーは保存され、出力には Jev が利用可能であることとオンにする方法が表示されます: + +```bash +failproofai jev setup --provider failproofai +``` + +Jev を**オフにする**操作でもありません。マシンの `jev.json` がすでに FailproofAI Cloud 経由で Jev を実行している場合はそのまま維持され、Jev が引き続き各チェック済みツール呼び出しと最近のプロンプトを送信していることが出力に表示されます。オフにするには `failproofai jev setup --mode off` を使用してください。 + + +接続操作は既存の `~/.failproofai/jev.json` を**上書きしません**。すでに独自の Jev エンドポイントを使用している場合は引き続きそちらが使われ、ファイルがそのまま残っていることが出力に表示されます。そのファイルが Jev をオフ(拒否、またはオフに切り替え済み)にしている場合は、その旨と修正方法も表示されます。そのマシンを FailproofAI Cloud に切り替えるには `failproofai jev setup --provider failproofai` を実行してください。 + + +## shadow、enforce、off の切り替え + +shadow から始めてポリシーページで Jev がどのように動作するかを確認してから、実際に適用させましょう: + +```bash +failproofai jev setup --mode enforce # Jev の判定が適用される: レビュー可能な deny を解除し、独自の判定を追加できる +failproofai jev setup --mode shadow # Jev への問い合わせと記録のみ行い、ポリシーの結果が適用される +failproofai jev setup --mode off # 設定を保持したまま Jev への問い合わせを停止する +``` + +同じ切り替えはローカルダッシュボードの **Settings → Jev** にもあります。モードのみを書き換え、それ以外は変更しません。フックはツール呼び出しのたびに設定を読み込むため、変更は次の呼び出しから即座に反映されます。再起動は不要です。 + +## 動作状況を確認する + +```bash +failproofai jev status +failproofai jev test +``` + +`status` はプロバイダーを **FailproofAI Cloud**、マシンが接続した Cloud ホスト、モード、キーのソースを **FailproofAI Cloud connection** として表示します(キー自体は表示しません)。FailproofAI Cloud の `jev.json` が存在するが Jev を実行できない場合は、その理由が表示されます: + +| `status` の表示 | `status --json` | 意味 | +| --- | --- | --- | +| **off — no Jev key is stored for this machine's FailproofAI Cloud connection** | `key-lacks-jev` | マシンは接続されているが、Jev キーが保存されていない: キーに `jev:evaluate` がないか、接続時に確認できなかった。同じキーで `failproofai config --token ` を再実行してください。権限がない場合は **machine** キーを使用してください。 | +| **off — this machine is not connected to FailproofAI Cloud** | `not-connected` | このマシンに Jev キーが属する FailproofAI Cloud 接続が存在しない。 | + +`failproofai config --disconnect` の実行後、FailproofAI Cloud の `jev.json` はなくなります(オフに切り替えられていた場合はそのまま残ります)。そのため `status` は単に Jev がオフであると報告します。`status --json` も同じ情報を含みます(`provider: "failproofai"`、`keySource: "cloud"`、`cloudConnected`、`keyCarriesJev`)。設定がないか拒否された場合も同様です。`permissions` は常に `jev.json` のものです。`credentials.json` に関する拒否には `credentialsPermissions` が追加され、1 つのコマンドで修正できる場合は `fix` も含まれます。`test` はライブリクエストを 1 件送信し、レイテンシと応答した Jev のバージョンを報告します。フックのタイムアウト後に応答が届いた場合(フックは `timeout` と記録します)や、チェック質問に誤答した場合は、タイトルにその旨が表示され、終了コード 1 で終了します。 + +ダッシュボードの **Settings → Jev** パネルにも **FailproofAI Cloud connection** が表示されます。マシンが属する組織と、そのキーが Jev を持っているかどうかが確認できます。これはマシン自身のファイルから読み取られ、ネットワーク呼び出しは発生しません。 + +## ポリシーページに表示される内容 + +マシンはすでにフックのアクティビティを FailproofAI Cloud に送信しています(`events:add`)。Jev がオンの場合、ゲートされた各呼び出しの記録には、実行された評価器、Jev の判定、解除されたポリシー、フォールバックした理由、レイテンシ、応答したモデルも含まれます。コマンドやプロンプトは含まれず、判定・コード・名前のみです。組織の**Policies** ページでは: + +- Jev 自身の判定で決定された呼び出し(enforce モード)は **Jev** に帰属し、判定チェックがパックから来た場合はそのパック名とバージョンも記録される +- shadow モードでは、Jev の deny または warning は **would-have** として表示され、観察中のロールアウトの隣に表示される +- Jev が解除した、または shadow モードで解除したであろうポリシーは、ポリシーごとにカウントされる + +## Jev が応答できない場合 + +以下のいずれの場合も、その呼び出しのポリシー結果にフォールバックし、その理由とともに記録されます: + +| 理由 | 原因 | +| --- | --- | +| `out-of-credits` | 組織のプラン利用枠を使い切った。 | +| `http-401`, `http-403` | キーが失効したか、`jev:evaluate` を持っていない。対応した権限を持つキーで再接続してください。 | +| `http-429` | FailproofAI Cloud が組織の Jev をレート制限している。要求された待機時間(`Retry-After`、最大 60 秒)が経過するまで、マシンは何も送信せずすべての呼び出しが即座にフォールバックします。このように保留された呼び出しは `http-429` として記録されます。マシン自身のレート制限が先に適用された場合は `rate-limited` として記録されます。 | +| `http-429`(日次制限) | 組織の日次 Jev 呼び出し上限に達した: **UTC 1 日あたり 10,000 回**(FailproofAI Cloud の運用者が別の制限を設定している場合を除く)。カウントが 00:00 UTC にリセットされるまで、すべての呼び出しがフォールバックします。マシンは最大 1 分に 1 回再試行するため、リセット後 1 分以内に検出されます。`failproofai jev test` は「Daily Jev limit for this org reached; resets at 00:00 UTC.」と表示します。 | +| `http-422` | Jev がこの呼び出しのリクエストを拒否した。通常、ツール呼び出しに密度の高いテキスト(base64、hex、minified コード)が含まれており、Jev のトークン予算を超えているためです。この呼び出しは毎回フォールバックします。障害ではありません。 | +| `http-502` | Jev が現在利用できない。 | +| `http-503` | この Cloud は組織の Jev を提供できない: モデルゲートウェイがない、組織がまだプロビジョニングされていない、またはゲートウェイがダウンしている。管理者に問い合わせてください。フックは最大 1 分に 1 回再試行します。 | +| `http-404` | この FailproofAI Cloud はまだ Jev を提供していない。 | +| `timeout` | `timeoutMs`(デフォルト 3000)以内に応答がなかった。 | +| `model-mismatch` | バージョン 1.13 以外の Jev が応答した。 | + +## キーの保存場所と送信先 + +- キーは `~/.failproofai/credentials.json`(`0600`、所有者専用ディレクトリ)に一度だけ保存され、他の FailproofAI Cloud の認証情報と並置されます。このルートでは `jev.json` にキーは保存されません。そこにキーが書かれると設定が無効になります。 +- `credentials.json` に所有者以外(グループまたはその他、読み取りまたは書き込み)の権限がある場合、またはそのディレクトリが所有者以外から**書き込み**可能な場合、ファイルは**拒否**されて読み取られず、修正するまで Jev はオフのままになります: ファイルに `chmod 600`、ディレクトリに `chmod 700`(または再接続すると `0600` でファイルを書き直し、ディレクトリを所有者専用にします)。他者が読み取りのみ可能なディレクトリは問題ありません。書き込みが可能な場合はファイルの入れ替えが可能になります。 +- キーは接続とセットの場合にのみ有効です: 同じ FailproofAI Cloud への同じキーによるポリシーまたは報告の認証情報が、同じファイルに存在する必要があります。接続なしに残された Jev キーは無視され、Jev はオフのままです。これは、古い failproofai の `config --disconnect` が Jev キーをそのままにした場合(削除方法を知らないため)や、古い failproofai の `config --token` が別のキーで接続した場合(FailproofAI Cloud 上では別の組織に属する可能性がある)に発生します。Jev を再度オンにするには、**machine** キーで再接続してください。 +- キーは検証された Cloud オリジンにのみ送信されます。別の場所を指す `jev.json` は拒否されます。 +- **マシン上のエージェントがキーを読み取ることができます。** `credentials.json` は所有者専用ですが、エージェントはその所有者として実行されます。failproofai 自身のファイルの読み取りは意図的に許可されています(変更のみ `block-failproofai-commands` によってブロックされます)。そのため、エージェントとこのファイルの間にあるのは `block-read-outside-cwd`(*レビュー可能な*ポリシー)のみです。ホームディレクトリから開始されたセッションからは、何も遮るものはありません。`jev:evaluate` 権限を持つキーは、使用される場所を問わず組織の Jev 利用枠(日次上限まで)を消費します。そのため、マシンキーは他の支出認証情報と同様に扱ってください。エージェントがキーを読み取った可能性がある場合は、Keys ページで無効化し、新しいキーで再接続してください。 +- これを制御するのはグローバルファイルのみです。リポジトリから Cloud Jev をオンにしたり、別の場所を指定したり、キーを提供したりすることはできません。また、このルートでは `FAILPROOFAI_JEV_API_KEY` は無視されます。 +- Jev が評価する各呼び出しについて、FailproofAI Cloud への 1 件のリクエストが送信されます。内容は [BYOK ページ](/ja/policies/jev-byok#what-leaves-the-machine)に記載されているもの(シークレットはリダクション済み)です。FailproofAI Cloud はそれを TypeSafe に転送し、記録や保持は行いません。 + +## オフにする + +| コマンド | 結果 | +| --- | --- | +| `failproofai jev setup --mode off` | 設定を保持したまま Jev への問い合わせを停止する。**これが持続的な切り替えです:** 再接続しても既存の `jev.json` は上書きされないため、`--mode shadow` で戻すまで Jev はオフのままです。 | +| `failproofai jev remove` | `~/.failproofai/jev.json` を削除し、Jev をオフにする。ただし、次に `jev:evaluate` 権限を持つキーで `failproofai config --token` を実行すると、`jev.json` が存在しないため shadow モードで Jev が再度オンになります(`--no-transcripts` での実行を除く)。オフのままにするには `--mode off` を使用してください。 | +| `failproofai config --disconnect` | マシンを切断する: キーが削除され、`jev.json` が FailproofAI Cloud を指定していてかつオフになっていない場合は `jev.json` も削除されます。独自エンドポイント用の `jev.json` はそのまま残り、オフに切り替えられたものも残るため、再接続後も Jev はオフのままです。 | + +次のツール呼び出しから、フックは従来どおり正規表現ポリシーのみを実行します。 \ No newline at end of file diff --git a/docs/ja/policies/jev.mdx b/docs/ja/policies/jev.mdx new file mode 100644 index 000000000..9b0facb4c --- /dev/null +++ b/docs/ja/policies/jev.mdx @@ -0,0 +1,45 @@ +--- +title: "Jev policies" +description: "Jev のライブレビューをゲート付きツール呼び出しに追加し、決定を適用する前に内容を確認します。" +icon: "shield-check" +--- + +Jev は、エージェントに対して人が依頼した内容に照らしてツール呼び出しを読み取ります。文字列マッチングポリシーが正当な作業をブロックしたり、コンテキストが必要なリスクのある操作を見逃したりする場合に使用してください。`PreToolUse` または `PermissionRequest` ゲートにおいて、既存のポリシーと並行して回答します。セッション終了**後**のスコアには [Jev evaluations](/ja/evaluations/jev) を使用してください。 + +## オブザーブモードで開始する + +Failproof AI をインストールし、[対応ハーネス](/ja/reference/harnesses)にフックをアタッチします。failproofai 1.0.8-beta.0 以降が必要です。 + +Failproof AI には Jev チェックが含まれていません。パックとしてインストールしてください。インストールしないと Jev に質問する内容がなく、呼び出されません。 + +```bash +failproofai policies add FailproofAI/jev-policies +``` + +次に、リクエストが Jev に届くルートを選択します。 + +| ルート | 最初のステップ | +| --- | --- | +| FailproofAI Cloud | `jev:evaluate` 権限を持つ **machine** キーで接続します。Jev の設定がないマシンでは、`failproofai config` を実行すると Jev がオブザーブモードで有効になります。 | +| 独自プロバイダー | ローカルダッシュボードで **Settings → Jev** を開き、プロバイダーを選択してトークンを貼り付け、**observe** を選択します。または `failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key` を実行してください。 | + +![ローカルダッシュボードの Jev 設定画面:プロバイダー、エンドポイント、トークン、および Jev を有効にする前のオブザーブモード。](/images/dashboard/jev-settings.png) + +```bash +failproofai jev status +failproofai jev test +``` + +`test` はエンドポイントを確認します。フックパスを確認するには、フックが設定されたエージェントにファイル読み取りツールを使用して `README.md` を読むよう依頼してください。そのツール呼び出しがセッションに表示されることを確認し、[ローカルダッシュボード](/ja/reference/local-dashboard#review-policy-activity)の **Policies → Activity** で内容を確認します。`status` の Jev カウントが増加しているはずです。オブザーブモードでは、既存のポリシーの結果が引き続き適用されながら、Jev が下したであろう判断が記録されます。 + +## 適用タイミングを決める + +**ハード**ポリシーは常に最終決定権を持ちます。Jev は、明示的に **reviewable** とマークされたポリシーの deny のみを解除でき、かつそのポリシーが指定する懸念事項を確認した場合に限られます。クリアランスに依存する前に [ポリシー権限](/ja/policies/authority) を確認してください。Jev は独自に警告や deny を行うこともできます。回答できない場合は、ポリシーの結果がその呼び出しを決定します。 + +オブザーブの結果が適切に見えたら、**Settings → Jev** でエンフォースモードに切り替えるか、次のコマンドを実行してください。 + +```bash +failproofai jev setup --mode enforce +``` + +プロバイダー URL、Cloud キー、設定、フォールバック、および各リクエストで送信されるデータについては、[Jev インテグレーションリファレンス](/ja/reference/jev) を参照してください。 \ No newline at end of file diff --git a/docs/ja/reference/custom-agents-typescript.mdx b/docs/ja/reference/custom-agents-typescript.mdx new file mode 100644 index 000000000..c0de34e12 --- /dev/null +++ b/docs/ja/reference/custom-agents-typescript.mdx @@ -0,0 +1,401 @@ +--- +title: "カスタムエージェント (TypeScript)" +description: "@failproofai/sdk の設定、イベントカタログ、スコープ、フレームワークアダプターの詳細リファレンス。" +icon: "square-js" +--- + +TypeScript SDK における各設定・メソッド・フィールドの説明です。初めて計装する場合はガイドから始めてください。このページはリファレンス用です。 + + + + インストール、計装、イベントメソッド、実例、よくある問題。 + + + 同じイベント、同じワイヤーフォーマット、同じスプール — Python 版。 + + + +Node 20.9 以上。ESM および CommonJS 対応。ランタイム依存なし。 + + + この SDK と Python 版は**同じスプールに同じイベントを書き込みます**。Node エージェントと Python エージェントが混在するフリートでも、セッションのセットは1つだけ生成され、ダッシュボード上で区別されることはありません。言語の選択はサービス単位で行い、会社全体で統一する必要はありません。 + + +## インストール + +```bash +npm install @failproofai/sdk +``` + +```ts +import * as failproofai from "@failproofai/sdk"; + +await failproofai.agent("planner", { goal: question }, async () => { + const hits = await failproofai.toolCall("web_search", { input: { q } }, () => search(q)); +}); +``` + +フレームワークアダプターはパッケージ本体に同梱されています。各フレームワークは**オプションのピア依存関係**として宣言されており、サポート対象バージョンを明示するためのものです。自動でインストールされることはなく、`instrument()` を呼び出したときにのみインポートされます。 + +## Failproof デーモンへの接続 + +Python SDK と同様に、**Admin → Keys** で `events:add` キーを作成し、エージェントマシンで[デーモンを接続](/ja/start/setup#connect-a-machine-to-cloud)します。SDK はディスクに書き込み、デーモンが送信します。 + +## 設定 + +```ts +failproofai.configure({ + environment: "production", + flushInterval: 0.5, + baseDir: undefined, +}); +``` + +| オプション | 説明 | +| --- | --- | +| `environment` | すべてのイベントに付くラベル — `production`、`staging`、`prod-eu` など。デフォルトは `dev`。 | +| `flushInterval` | タイマーがディスクに書き込む間隔(秒)。デフォルトは `0.5`。 | +| `baseDir` | 書き込み先。デフォルトはデーモンのスプール。特別な理由がない限り変更不要。 | + +すべての値が検証を通過した場合にのみ設定が適用されます。検証に失敗した場合、SDK は変更前の状態を保持します。新しい `baseDir` と古いインターバルが混在した中途半端な状態にはなりません。 + +環境変数による設定も可能です: + +| 変数 | 説明 | +| --- | --- | +| `AGENTEYE_ENVIRONMENT` | コード変更なしで `environment` を設定します。`configure()` オプションが優先されます。 | +| `FAILPROOFAI_HOME` | スプールを保持する Failproof AI のルートディレクトリを変更します。 | +| `FAILPROOFAI_SDK_LOG_LEVEL` | `debug`、`info`、`warn`(デフォルト)、`error`、`silent`。 | +| `FAILPROOFAI_SDK_STRICT` | `1` にすると計装エラーがログ出力ではなく例外としてスローされます。 | +| `FAILPROOFAI_SDK_STRICT_INTEGRATIONS` | `1` にするとフレームワーク互換性の問題が警告と継続ではなく例外としてスローされます。 | + + + **`environment` にカンマを含めないでください。** インジェストはそのフィールドをカンマで分割してフィルターを構築しており、ラベルにカンマが含まれるイベントはスキップされます — 実行全体がサイレントに消えてしまいます。`prod,eu` ではなく `prod-eu` と書いてください。 + + `configure({ environment: "prod,eu" })` は即座に例外をスローします。`AGENTEYE_ENVIRONMENT` は例外をスローできません — 呼び出し元がいないため — 一度警告を出して `dev` にフォールバックします。 + + +SDK 自身のログ行を独自ロガーにルーティングするには `failproofai.setLogger({ debug, info, warn, error })` を使用します。 + +## シャットダウン + +バッファリングされたイベントは `process.on("exit")` でフラッシュされます。 + +シグナルによって強制終了されたプロセスはこのハンドラーに到達しません。また、Node のデフォルトでは `SIGTERM` 受信時に exit ハンドラーを実行せずに終了するため、コンテナ化されたエージェントは最後のインターバルで未書き込みのイベントを失う可能性があります。 + + + **この SDK はシグナルハンドラーを自動登録しません。** ハンドラーの登録はプロセスの動作を変更します。リスナーを追加すると Node のデフォルト終了動作が抑制されるため、ライブラリが勝手に登録した場合、Ctrl-C が動作しなくなります。自分でハンドラーを追加してください: + + ```ts + for (const signal of ["SIGINT", "SIGTERM"] as const) { + process.once(signal, () => { + failproofai.flushSync(); + process.exit(0); + }); + } + ``` + + +短命なスクリプトやサーバーレスハンドラーでは、返る前に `await failproofai.flush()` を呼び出してください — インターバルだけでは配信は保証されません。 + +## アイデンティティ + +すべてのイベントはセッションとエージェントに属します。**スコープが両方を設定する**ため、明示的に渡す必要はほとんどありません: + +```ts +await failproofai.session(async () => { + await failproofai.agent("planner", async () => { + failproofai.event.toolUse({ toolName: "search", toolCallId: "c1" }); + }); +}); +``` + +`sessionId` や `agentId` を明示的に渡すことも可能で、その値が優先されます。スコープで設定されておらず、かつ明示的にも渡されていない場合、Cloud が静かに破棄するイベントを出力するのではなく、例外がスローされます。 + + + アイデンティティは `AsyncLocalStorage` に乗っています。`await`、`.then()`、タイマー、スコープ内で作成されたコールバックすべてに伝播します。ただし、あるスコープの実行中に保存され別の実行中に呼び出されるコールバック、または `worker_threads` の境界を越えて渡された処理には伝播しません — それらは `failproofai.propagate()` でラップしてください。そうしないとイベントが紐付けられません。 + + +### スコープ + +| スコープ | 発行するもの | 戻り値 | +| --- | --- | --- | +| `session(body)` | なし — アイデンティティのみ | `body` の戻り値 | +| `agent(id, options?, body)` | `agent_start`、その後 `agent_end` | `body` の戻り値 | +| `toolCall(name, options?, body)` | `tool_use`、その後 `tool_result` | `body` の戻り値 | + +同期のボディは同期のまま保たれます:`agent("x", () => 1)` は Promise ではなく `1` を返します。 + +`toolCall` はボディの解決値をツールの `output` として記録します。ただし `call.output` を自分で設定した場合はその値が使われます。 + + + +| 状況 | イベント | `outcome` | +| --- | --- | --- | +| ブロックが正常に返った | `agent_end` | `"success"`、または指定した `outcome` | +| ブロックが例外をスローした | `error`、その後 `agent_end` | `"failed"` | +| `AbortError` | `agent_end` のみ | `"cancelled"` | + +エラーは常に再スローされます。 + +ツールの失敗はリーフ — `error` 文字列を持つ `tool_result` — に記録され、実行レベルの `error` イベントは**発行されません**。エージェントループがキャッチしたものは実行の失敗ではなく、伝播したものは囲んでいる `agent()` によって正確に一度だけ報告されます。 + + + + + +作業が単一の関数でない場合 — コンストラクターで開いてティアダウンで閉じるスコープ、または既存の制御フローをまたがるスコープ: + +```ts +{ + using span = failproofai.agent.open("planner", { goal }); + using call = failproofai.toolCall.open("search", { input: { q } }); + call.call.output = await search(q); +} // tool_result, then agent_end +``` + +どちらの構文もバイト単位で同一のイベントを発行します。コールバック形式を優先してください:`AsyncLocalStorage.run()` 内で実行されるため、巻き戻す必要がなく「ここで開いてあそこで閉じる」系のバグ全体が発生不可能になります。 + +失敗を自身でキャッチする `using` ブロックは `span.fail(error)` で失敗を報告します — ディスポーザー自身には例外チャンネルがありません。 + + + +## イベントカタログ + +Python SDK と同じ 15 個のメソッドを camelCase で提供します。ほとんどは**ペア**になっており — オープナーを呼び出してからクローザーを呼び出すと、SDK がその間の時間を計測します。 + +| | オープン | クローズ | +| --- | --- | --- | +| **エージェント** | `agentStart` | `agentEnd` | +| | `agentPause` | `agentResume` | +| **モデル** | `modelRequest` | `modelResponse` | +| **ツール** | `toolUse` | `toolResult` | +| **フック** | `hookTriggered` | `hookCompleted` | +| **人間** | `humanWait` | `humanInput` | + +単独で使うものが 3 つあります:`error`、`humanPause`、`humanInterrupt`。 + + + +すべてのメソッドは `sessionId` と `agentId` も受け取りますが、スコープが自動で設定します。省略されたフィールドは JSON `null` として送信されるのではなく、削除されます。 + +| メソッド | 必須 | オプション | +| --- | --- | --- | +| `agentStart` | — | `goal`、`parentId` | +| `agentEnd` | — | `outcome`、`summary` | +| `agentPause` | `pauseId` | `reason`、`userId` | +| `agentResume` | `pauseId` | `reason`、`userId` | +| `modelRequest` | — | `model`、`messages`、`system`、`tools`、`requestId` | +| `modelResponse` | — | `model`、`stopReason`、`inputTokens`、`outputTokens`、`content`、`role`、`requestId` | +| `toolUse` | `toolName`、`toolCallId` | `input` | +| `toolResult` | `toolName`、`toolCallId` | `output`、`error` | +| `hookTriggered` | `hookName`、`hookId` | `triggerEvent`、`input` | +| `hookCompleted` | `hookName`、`hookId` | `outcome`、`output`、`error` | +| `error` | `errorType`、`message` | `traceback` | +| `humanWait` | `inputId` | `prompt`、`options`、`reason` | +| `humanInput` | `inputId` | `response` | +| `humanPause` | — | `reason`、`userId` | +| `humanInterrupt` | — | `reason`、`userId`、`atStep` | + +追加したキーはカスタムペイロードフィールドになります。フレームワーク固有のものは `fw_*` で名前空間を設定してください。宣言済みフィールドと名前が衝突した場合、昇格されたカラムが静かに上書きされることはなく、エラーとして拒否されます。 + + + + + **`duration_ms` は計算値であり、受け付けません。** 4 つのクロージングメソッドはオープナーからの経過時間を計測し、呼び出し側が指定した `duration_ms` は拒否されます — 報告された duration は改ざん不可能であるべきだからです。 + + ペアのマッチングは**セッション**と ID で行われ、エージェントでは行われません。`planner` 配下でオープンされ `worker` 配下でクローズされたツールも正しくペアリングされます。これはネストされたマルチエージェント実行が実際に行うことです。 + + +## フレームワークアダプター + +```ts +await failproofai.instrument(); // 検出できるものすべて +await failproofai.instrument("langchain"); // 1つだけ指定 +failproofai.uninstrument(); // すべて元に戻す +``` + +| フレームワーク | サポート対象 | アタッチ方法 | +| --- | --- | --- | +| **LangChain.js / LangGraph.js** | `@langchain/core` 0.3 – 1.x、LangGraph.js 0.4 – 1.x | `CallbackManager.configure` を使用。`callbacks:` を渡すことなく、すべての `invoke`/`stream`/`batch` をカバー。または `langchainHandler()` を自分で渡してパッチなしで使用可能。 | +| **Vercel AI SDK** | `ai` 4 – 7 | コールサイトで `telemetry()` を使用、または `ai` 7 ではプロセス全体に `instrument("ai")` を使用(4–6 はオプトイン — 下記参照)。 | +| **Mastra** | `@mastra/core` 0.20 – 1.x | `Agent.generate`/`.stream`、エージェントのモデルとツール解決、ワークフローの実行/ステップエンジン。 | +| **LlamaIndex.TS** | `llamaindex` 0.11.4 – 0.x | `Settings.callbackManager`(購読)および `AgentWorkflow.runStream`、ワークフロー実行とそのステップに対応。 | + +すべての対象バージョン範囲は、実際のフレームワークリリースに対して、両端のバージョンで、ES モジュールおよび CommonJS として、毎回の CI 実行時にテストされています。 + +マッピングは Python SDK と同じです。同じプログラムはどちらの言語でも同じツリーを描きます。コンストラクトが**エージェント**になるのは、LLM の意思決定ループを所有している場合のみです — グラフやチェーンの実行、AI SDK の `generateText`/`streamText` 呼び出し、Mastra エージェント、LlamaIndex エージェントの実行などです。LangGraph のノードやワークフローのステップは**フック**(`hook_triggered`/`hook_completed`)であり、ネストされたエージェントではありません。モデル呼び出しはトークン数を持つ `model_request`/`model_response` ペアであり、ツール呼び出しにはモデル自身のツール呼び出し ID が付きます。失敗は発生したイベントに対して一度だけ記録されます。 + +インストールに失敗したアダプターはログに記録されてスキップされます。他のアダプターは引き続きインストールされます。LlamaIndex が壊れていても LangGraph が使えなくなることはありません。 + + + 引数なしの `instrument()` は、フレームワークがすでにインポートされているかどうかではなく、**解決できるかどうか**でフレームワークを検出します — Node には ES モジュール用に Python の `sys.modules` に相当するものがありません。インストール済みだが使用していないフレームワークはインポートされてパッチが当てられます。問題がある場合は使用するものを明示的に指定してください。 + + + + これらのフレームワークのほとんどは ES モジュールビルドと CommonJS ビルドの両方を提供しており、Node はそれらを2つの無関係なコピーとして読み込みます。アダプターはアプリケーションが読み込むコピーをパッチし(何かがすでに `require` した場合は CommonJS コピーも)、両方のモジュールシステムで動作します。esbuild や webpack によって**自分のビルド出力にバンドルされた**フレームワークは到達できません — そこではコールサイトのヘルパーを使ってください:`langchainHandler()`、`telemetry()`、`wrapTool()`。 + + +### パッチなしの LangChain + +```ts +import { langchainHandler } from "@failproofai/sdk/langchain"; +await graph.invoke(input, { callbacks: [langchainHandler()] }); +``` + +ハンドラーは `instrument()` の有無にかかわらず動作し、二重記録は行いません。`instrument("langchain")` は Python アダプターと同様に `sessionId`、`captureContent`、`includeChains`、`graphCallbacks`、`captureLimit` を受け取ります。呼び出しの `metadata: { failproofai_sdk_session_id }` でその呼び出しのセッションを選択できます。 + +### Vercel AI SDK + +AI SDK は ES モジュールからプレーンな関数をエクスポートしており、ES モジュールの名前空間は仕様上イミュータブルです — パッチを当てる場所がありません。SDK 自身が公式にドキュメント化している拡張ポイントを使用します: + +```ts +import { telemetry } from "@failproofai/sdk/ai"; + +const { text } = await generateText({ + model, + prompt, + experimental_telemetry: telemetry({ functionId: "answer-question" }), + // ai 7 では `telemetry: telemetry({ … })` — 同じオブジェクト、新しい名前 +}); +``` + +これが完全な統合です:エージェントスパン、ステップごとにトークン数を持つモデルリクエスト/レスポンスのペア、そしてすべてのツール呼び出し。1 つのコールサイトがすべてのメジャーバージョンで動作します — `ai` 4–6 はキャリーするトレーサーを読み取り、`ai` 7 はテレメトリー統合を読み取ります。 + +`instrument("ai")` は **`ai` 7 でプロセス全体に**同じことをします:AI SDK のグローバルテレメトリー統合リスト経由のすべての呼び出しに適用されます。これは加算的であり、他の何も奪いません。 + +**`ai` 4–6 では、`instrument("ai")` 単独では何も記録せず、その旨の警告を一度ログに出力します。** これらのメジャーバージョンが持つプロセス全体のフックは、グローバルの OpenTelemetry トレーサープロバイダー — 一度占有されたら OpenTelemetry が譲らないシングルスロット — のみです。ours を登録すると、起動後半の `NodeSDK.start()` が静かに拒否され、http/データベースのスパンが何もエクスポートしないトレーサーに送られることになります。コールサイトで `telemetry()` または `wrapModel` を使用してください。プロセスが独自の OpenTelemetry を実行していない場合は、`instrument("ai", { registerGlobalTracer: true })` でオプトインできます:これにより `experimental_telemetry: { isEnabled: true }` を渡すすべての呼び出しが記録され、スロットがまだ空の場合にのみ占有されます。`registerGlobalTracer: false` はデフォルトを維持し、警告を抑制します。 + +モデルを一度だけラップする場合は `wrapModel` を使用できます。ツール呼び出しはモデルレイヤーの上で発生するため、モデル呼び出しのみが見えます。周囲に何もない状態でラップされたモデルを呼び出すと、独自の実行として記録されます。ストリーム呼び出しはストリームが停止したときにクローズされます — コンシューマーがキャンセルした場合は `stop_reason: "cancelled"`、途中で失敗した場合は `"error"` とエラー内容: + +```ts +import { wrapModel } from "@failproofai/sdk/ai"; +const model = await wrapModel(openai("gpt-4o")); +``` + +両方を使用しても問題ありません:ミドルウェアが呼び出しがすでに記録中であることを検知してデファーするため、各呼び出しは一度だけ記録されます。 + +`functionId` はエージェントスパンに名前を付けます。カーディナリティを低く保ってください — プライマリダッシュボードファセットである `agent_id` に記録されます。 + +### Next.js + +`next build` はデフォルトでサーバーの依存関係をバンドルするため、ビルドにバンドルされたフレームワークは `instrument()` が到達できないコピーになります。設定を一度ラップし、Next のスタートアップフックから `instrument()` を呼び出してください: + +```ts +// next.config.ts +import { withFailproofai } from "@failproofai/sdk/next"; +export default withFailproofai({ /* your config */ }); +``` + +```ts +// instrumentation.ts +export async function register() { + if (process.env.NEXT_RUNTIME !== "nodejs") return; + const failproofai = await import("@failproofai/sdk"); + await failproofai.instrument(); +} +``` + +`withFailproofai` は LangChain、Mastra、LlamaIndex および SDK 自身を `serverExternalPackages` に追加し、既存のリストを維持します。これがない場合、`instrument()` は到達できないフレームワークごとに一度警告を出しますが、サイレントに失敗はしません。パッケージを自分でリストする場合は `FAILPROOFAI_NEXT_EXTERNALS=1` を設定してください。Vercel AI SDK とコールサイトのヘルパーはどちらの場合でも動作します。Edge ルートでは no-op ビルドが提供されます:SDK をインポートしても安全であり、何も記録されません。 + +### ストリーム呼び出しのトークン数 + +OpenAI 互換 API は、クライアントが要求した場合にのみストリームの使用量を報告します。LangChain と Vercel AI SDK は要求します。LlamaIndex では `OpenAI` LLM に `additionalChatOptions: { stream_options: { include_usage: true } }` を渡してください。Mastra では使用量を有効にしたモデルを作成してください(例:`createOpenAICompatible({ includeUsage: true })`)。そうしないと、ストリームのモデル呼び出しにトークン数が付きません。 + +### ランタイム + +Node ≥ 20.9、Bun、Deno — すべてのフレームワークを ES モジュールおよび CommonJS として、各ランタイムで Node のトレースに対してテストしています。SDK は `failproofaid` デーモンと並行して動作し、デーモンが書き込まれたデータを送信します。 + +## 独自エージェント — フレームワークなし + +自分で書いたエージェントループや、アダプターのないフレームワーク向けです。アダプターが内部で使用するのと同じ API でイベントを発行するため、トレースは同じ形状と品質になります。 + +エージェントがどのように構成されているかを知る必要はありません。手作りのエージェントには、関数名が何であれ、すでに 3 つの場所があります。その 3 つが統合の全てです: + +| どこ | 追加するもの | 発行するイベント | +| --- | --- | --- | +| **1 回の実行**が始まり終わる場所 | `failproofai.agent("name", { goal }, async () => …)` | `agent_start` / `agent_end` | +| **モデルを呼び出す唯一の関数** | 前に `event.modelRequest`、後に `event.modelResponse` — 失敗時も両方 | モデルターンごとに 1 ペア | +| **ツールを実行する唯一の関数** | `failproofai.toolCall(name, { toolCallId, input }, () => run())` | `tool_use` / `tool_result` | + +```ts +async function callModel(messages) { + const requestId = randomUUID(); + const started = Date.now(); + failproofai.event.modelRequest({ model: MODEL, requestId, messages }); + try { + const reply = await client.chat.completions.create({ model: MODEL, messages, tools }); + failproofai.event.modelResponse({ + model: reply.model, requestId, stopReason: reply.choices[0].finish_reason, + inputTokens: reply.usage?.prompt_tokens, outputTokens: reply.usage?.completion_tokens, + duration_ms: Date.now() - started, + }); + return reply.choices[0].message; + } catch (error) { + failproofai.event.modelResponse({ model: MODEL, requestId, stopReason: "error", + error: String(error), duration_ms: Date.now() - started }); + throw error; + } +} + +async function dispatch(call) { + const input = JSON.parse(call.function.arguments); + return failproofai.toolCall(call.function.name, { toolCallId: call.id, input }, + () => runTool(call.function.name, input)); +} + +await failproofai.agent("inventory", { goal: question }, async () => { + for (;;) { + const message = await callModel(messages); + if (!message.tool_calls?.length) return message.content; + for (const call of message.tool_calls) await dispatch(call); + } +}); +``` + +アイデンティティはアンビエントです:`agent()` の内側にあるものはすべて、ID を渡すことなくその実行のセッションに記録されます。プログラムの他の部分は何も変わりません — エージェントが自分のデータベースに書き込んでいるものも含めて。 + +- **サービスやワーカーの場合:** 独自のリクエスト ID やジョブ ID を `sessionId` として渡すと、ダッシュボード上のセッションと自分のログやデータベースのレコードが同じ文字列になります。 +- **サブエージェントの場合:** `agent()` 呼び出しをネストします。内側のものは外側を `parent_id` としてセッションに参加します。 +- **ペアを発行してください。** `modelResponse` なしの `modelRequest` は、ダッシュボード上で永遠に実行中として表示されるスパンになります — だから `catch` があります。 + +リポジトリの [`sdk/typescript/examples/research-agent.ts`](https://github.com/FailproofAI/failproofai/blob/main/sdk/typescript/examples/research-agent.ts) は完全な実行可能バージョンです:実際の OpenAI ツールループをまさにこのように計装したもので、ES モジュールおよび CommonJS として、変更のたびに CI で実行されます。 + +## 評価 + +```ts +import { Evaluator, EvalResult, Score } from "@failproofai/sdk/evaluator"; + +export const app = new Evaluator({ name: "my-evals", version: "1" }); + +app.eval("tool_success_rate", { version: "1" }, (session) => { + const results = session.eventsOfType("tool_result"); + const failures = results.filter((event) => event.payload.error != null).length; + return new EvalResult({ + score: new Score(results.length === 0 ? 1 : 1 - failures / results.length), + reasoning: `${failures} of ${results.length} tool calls failed`, + }); +}); +``` + +```bash +FAILPROOFAI_EVALUATOR_URL=… FAILPROOFAI_EVALUATOR_TOKEN=… \ + npx failproofai-evaluator ./my-evals.js +``` + +プロトコル、ワーカー設定、結果の型については [Evaluator SDK リファレンス](/ja/reference/evaluator-sdk) を参照してください。 + + + **評価は yield しなければなりません。** 戻らない同期関数は Node の唯一のスレッドをブロックし、その間タイムアウトは発火できません。評価は `async` で記述してください。 + + +## プロセスに対して行わないこと + +| | | +| --- | --- | +| **エージェントループをブロックしない** | イベントはインメモリキューに入れられ、タイマーが書き込みます。タイマーは `unref` されているため、このパッケージをインポートしてもスクリプトの終了が妨げられることはありません。 | +| **無制限に増大しない** | キューはカウントと計測バイト数の両方で上限が設けられています。どちらかを超えると、最も古いイベントが破棄されて警告が出力されます — テレメトリーの障害が OOM による強制終了につながってはなりません。 | +| **プロセスをダウンさせない** | エンコードできないイベントは、周囲のバッチではなくそのイベント単体が破棄されます。スローする getter、循環参照、`BigInt`、孤立サロゲートはすべて、伝播ではなく処理されます。 | +| **半分だけ書かれたバッチを残さない** | アトミックなリネームの前にコンテンツが `fsync` され、その後ディレクトリが `fsync` され、書き込みに失敗した場合は一時ファイルがクリーンアップされます。 | +| **トランスクリプトを読み取り可能な状態で残さない** | バッチは `0700` ディレクトリ内で `0600` として保存されます。ゴール、プロンプト、ツール引数、ツール出力が含まれます。 | +| **認証情報を送信しない** | API キー、トークン、JWT、Bearer ヘッダー、シークレットの形をした代入はバイトがディスクに到達する前に編集されます。デーモンはアップロード前に再度編集します。 | \ No newline at end of file diff --git a/docs/ja/reference/jev-cloud.mdx b/docs/ja/reference/jev-cloud.mdx new file mode 100644 index 000000000..a585341ac --- /dev/null +++ b/docs/ja/reference/jev-cloud.mdx @@ -0,0 +1,136 @@ +--- +title: "FailproofAI Cloud 経由の Jev" +description: "ライブの Jev ポリシーレビューにおける Cloud マシンキー、接続状態、制限、およびフェイルバック動作。" +icon: "cloud" +--- + +これは [Jev ポリシー](/ja/policies/jev) の Cloud ルートリファレンスです。TypeSafe のクラシファイアである Jev は、各ツール呼び出しを実際のリクエスト内容と照合し、ポリシーの代わりにではなくポリシーと並行して判定を返します。**FailproofAI Cloud** を通じて、接続済みのマシンはすでに使用しているキーで Jev を利用できます。TypeSafe のアカウント、2 つ目のキー、エンドポイントの設定はいずれも不要です。各呼び出しは組織の既存プランの利用枠から課金されます。 + +Jev の動作は [bring-your-own-key セットアップ](/ja/reference/jev-providers) と変わりません。ハードポリシーは最終決定のままであり、レビュー可能なポリシーの deny は Jev がその懸念事項について正確に問い合わせを受けた場合のみ解除されます。また、いかなる障害時もその呼び出しのレジェックス結果にフォールバックします。 + + +**failproofai 1.0.8-beta.0** 以降が必要です。1.0.7 には Jev がありません(1.0.7 ベータより上位に並んでいますが)。Jev の設定がない場合は何も変わりません。フックはこれまでどおりレジェックスポリシーを実行します。 + + +## 始める前に + +エージェントが動作するマシンに Failproof AI をインストールし、[サポートされているハーネス](/ja/reference/harnesses)にフックを接続してください。ゼロから始める場合は、[クイックスタート](/ja/start/quickstart)のフックインストールまでの手順に従ってください。インストール済みの CLI を `failproofai --version` で確認し、Jev より古いバージョンの場合はアップデートしてください。また、マシンキーを作成するために組織の **Administration → Keys** ページへのアクセスが必要です。 + +Jev は `PreToolUse` または `PermissionRequest` ゲートで、名前付きのツール呼び出しをレビューします。セッション内のすべてのイベントをレビューするわけではありません。Jev によるポリシー deny の解除を確認するには、[reviewable](/ja/policies/authority) としてマークされたインストール済みポリシーが必要です。それ以外のポリシー deny はすべて最終決定のままです。 + +## 有効にする + +1. **Jev 付きのキーを作成する。** FailproofAI Cloud ダッシュボードで **Administration → Keys → Create key** を開き、**machine** プリセットを選択します。これにより、マシンに必要な 3 つの権限が付与されます。`events:add`(アクティビティの送信)、`policies:pull`(ポリシーの受信)、`jev:evaluate`(Jev、組織のプランから課金)です。`jev:evaluate` は他の 2 つなしには付与できません。 +2. **そのキーでマシンを接続する。** プロンプトでワンタイムシークレットを読み取り、次のセットアップコマンドを実行します。 + + ```bash + read -rs FAILPROOFAI_CLOUD_TOKEN && export FAILPROOFAI_CLOUD_TOKEN + failproofai config + ``` + + `failproofai config` はデーモンをインストールし、検出したエージェント CLI にフックを接続し、マシンを繋ぎます。環境変数を使うことで、キーがコマンドの引数やシェル履歴に残らないようにします。ハーネスが後からインストールされた場合は、[明示的に接続](/ja/start/quickstart)してください。 + + 組織がホスト型ではなく独自の FailproofAI Cloud を運用している場合は、そのアドレスを追加してください。`--url https://<ダッシュボードホスト>` (または `FAILPROOFAI_CLOUD_URL` をエクスポート)。指定しない場合、キーはホスト型サービスに対して検証され、接続が失敗します。そのホストの証明書がプライベート CA から発行されている場合は、CA をマシンのシステムトラストストアにインストールしてください(例: `update-ca-certificates`)。`NODE_EXTRA_CA_CERTS` だけでは不十分です。イベントを送信しポリシーを取得するデーモンはシステムストアを参照します。[トラブルシューティング](/ja/reference/troubleshooting)を参照してください。 + +以上です。接続によりキーが保存され、マシンに **まだ** Jev の設定がない場合、FailproofAI Cloud を通じて Jev が **observe** モードで有効になります。パックがチェックを提供すると、Jev はすべてのゲート済みツール呼び出しに対して問い合わせを受け、判定が記録されますが、ポリシーの結果が実際に適用されます。出力にはその旨が表示されます。 + +```text + Jev on through FailproofAI Cloud, in observe mode: logged, not enforced (~/.failproofai/jev.json). +``` + +パックがチェックを提供するまで、Jev は何も問い合わせません。Failproof AI 自体にはパックが含まれておらず、インストール済みのパックがチェックを宣言していない間は、出力にその旨が追記され、`failproofai jev status` でも同様に表示されます。以下でインストールしてください。 + +```bash +failproofai policies add FailproofAI/jev-policies +``` + +**`--no-transcripts` を指定して接続した場合、Jev は有効になりません。** Jev は各チェック対象のツール呼び出しと直近のプロンプトを FailproofAI Cloud に送信します。これは、決定のみの接続が送信するよう求められる内容を超えています。キーは保存され、出力には Jev が利用可能であること、および有効にする方法が表示されます。 + +```bash +failproofai jev setup --provider failproofai +``` + +また、Jev を **無効にする** わけでもありません。マシンの `jev.json` がすでに FailproofAI Cloud 経由で Jev を実行している場合、そのまま維持され、出力には Jev が引き続き各チェック対象のツール呼び出しと直近のプロンプトを送信していること、および `failproofai jev setup --mode off` で無効にできることが表示されます。 + + +接続は既存の `~/.failproofai/jev.json` を**上書きしません**。すでに独自の Jev エンドポイントを使用している場合、それが引き続き使用され、出力にはファイルが設定どおりに維持されたことが表示されます。また、そのファイルが Jev をオフにしている場合(拒否または手動でオフにした場合)はその旨と修正方法が表示されます。マシンを FailproofAI Cloud に切り替えるには `failproofai jev setup --provider failproofai` を実行してください。 + + +## Observe、Enforce、またはオフ + +observe から始めて、ポリシーページで Jev が何をしたかを確認してから実際に適用させます。 + +```bash +failproofai jev setup --mode enforce # Jev の判定が適用される: reviewable な deny を解除し、独自の判定を追加する場合がある +failproofai jev setup --mode observe # Jev に問い合わせてログを記録する; ポリシーの結果が適用される +failproofai jev setup --mode off # 設定を維持したまま Jev への問い合わせを停止する +``` + +同じ切り替えはローカルダッシュボードにもあります。**Settings → Jev** にオン/オフスイッチと observe/enforce の切り替えがあります。これはモードのみを書き換えます。フックはすべてのツール呼び出しで設定を読み込むため、変更は次の呼び出しから適用され、再起動は不要です。 + +## 動作を確認する + +```bash +failproofai jev status +failproofai jev test +``` + +`status` は、プロバイダーを **FailproofAI Cloud**、マシンが接続した Cloud ホスト、モード、キーソースを **FailproofAI Cloud connection** として表示します(キー自体は表示されません)。FailproofAI Cloud の `jev.json` が存在するが Jev が実行できない場合、その理由が表示されます。 + +| `status` の表示 | `status --json` | 意味 | +| --- | --- | --- | +| **off — no Jev key is stored for this machine's FailproofAI Cloud connection** | `key-lacks-jev` | マシンは接続されているが、Jev キーが保存されていない。キーに `jev:evaluate` がないか、接続時に確認できなかった。`FAILPROOFAI_CLOUD_TOKEN` にキーをセットして `failproofai config` を再実行してください。権限が不足している場合は **machine** キーを使用してください。 | +| **off — this machine is not connected to FailproofAI Cloud** | `not-connected` | このマシンに Jev キーが属する FailproofAI Cloud 接続がない。 | + +`failproofai config --disconnect` の後は、FailproofAI Cloud の `jev.json` はなくなります(オフに切り替えた場合を除き、その設定は維持されます)。そのため `status` は単純に Jev をオフとして報告します。`status --json` には同じ情報(`provider: "failproofai"`、`keySource: "cloud"`、`cloudConnected`、`keyCarriesJev`)が含まれており、設定がない場合や拒否された場合も同様です。`permissions` は常に `jev.json` のものです。`credentials.json` に関する拒否には `credentialsPermissions` が追加され、1 つのコマンドで修正できる場合は `fix` も含まれます。`test` は 1 件のライブリクエストを送信し、レイテンシーと応答した Jev のバージョンを報告します。フックのタイムアウト後に回答が届いた場合(フックは `timeout` として記録)、またはチェック質問に誤った回答をした場合は、終了コード 1 となり、タイトルにその旨が表示されます。 + +ダッシュボードの **Settings → Jev** パネルには **FailproofAI Cloud connection** も表示されます。マシンが報告する組織と、そのキーが Jev を持っているかどうかが表示されます。これはマシン自身のファイルから読み取られ、ネットワーク呼び出しは発生しません。 + +## 実際の呼び出しを確認する + +フック済みのエージェントで新しいセッションを開始し、`README.md` に対してファイル読み取りツールを使いタイトルを報告するよう依頼します。そのツール呼び出しがセッションに含まれていることを確認したら、`failproofai jev status` を再度実行します。最近の評価済み呼び出し数が増加しているはずです。[ローカルダッシュボード](/ja/reference/local-dashboard#review-policy-activity)の **Policies → Activity** を開き、その呼び出しの Jev 判定とモードを確認します。Cloud では、組織の **Policies** ページに配信済みアクティビティの Jev アウトカムが表示されます。observe モードでは、判定は **would-have** として記録され、ポリシーの結果が引き続き呼び出しを決定します。クリアランスは reviewable ポリシーがマッチし、Jev がその名前付きチェックをクリアした場合のみ表示されます。 + +## ポリシーページに送信される内容 + +マシンはすでにフックのアクティビティを FailproofAI Cloud に送信しています(`events:add`)。Jev が有効な場合、各ゲート済み呼び出しのレコードには、実行した評価者、Jev の判定、クリアしたポリシー、フォールバックした理由、レイテンシー、応答したモデルも含まれます。コマンドやプロンプトは含まれず、決定、コード、名前のみです。組織の **Policies** ページでは: + +- Jev 自身の判定が適用された呼び出し(enforce モード)は **Jev** に帰属します。判定の根拠となったチェックがパックから来た場合、そのパックとバージョンも記録されます。 +- observe モードでは、Jev の deny または warning は **would-have** として、確認中のロールアウトの横に表示されます。 +- Jev がクリアした、または observe モードでクリアしたであろうポリシーはポリシーごとにカウントされます。 + +## Jev が回答できない場合 + +以下のいずれの場合も、その呼び出しのポリシー結果にフォールバックし、理由とともに記録されます。 + +| 理由 | 原因 | +| --- | --- | +| `out-of-credits` | 組織がプランの利用枠を使い切った。 | +| `http-401`、`http-403` | キーが無効化された、または `jev:evaluate` を持っていない。権限のあるキーで再接続してください。 | +| `http-429` | FailproofAI Cloud が組織の Jev をレート制限している。要求された待機時間(`Retry-After`、最大 60 秒)が経過するまで、マシンは何も送信せずすべての呼び出しが即座にフォールバックします。この方法でブロックされた呼び出しは `http-429` として記録されます(マシン自身のレート制限が先に保留した場合は `rate-limited`)。 | +| `http-429`(日次制限) | 組織の日次 Jev 呼び出し数が上限に達した。**1 UTC 日あたり 10,000 件**(FailproofAI Cloud の運用者が別の制限を設定している場合を除く)。カウントが 00:00 UTC にリセットされるまですべての呼び出しがフォールバックします。マシンは最大 1 分に 1 回再試行するため、リセット後 1 分以内に検知されます。`failproofai jev test` は「Daily Jev limit for this org reached; resets at 00:00 UTC.」と表示します。 | +| `http-422` | Jev がこの呼び出しのリクエストを拒否した。通常、ツール呼び出しに base64、16 進数、難読化されたコードなど Jev のトークンバジェットを超える密なテキストが含まれている場合です。この呼び出しは毎回フォールバックしますが、これは障害ではありません。 | +| `http-502` | 現在 Jev が利用できない。 | +| `http-503` | この Cloud は組織の Jev を提供できない。モデルゲートウェイがない、組織がまだプロビジョニングされていない、またはゲートウェイがダウンしている。管理者に確認してください。フックは最大 1 分に 1 回再試行します。 | +| `http-404` | この FailproofAI Cloud はまだ Jev を提供していない。 | +| `timeout` | `timeoutMs`(デフォルト 3000)以内に回答がなかった。 | +| `model-mismatch` | バージョン 1.13 以外の Jev が回答した。 | + +## キーの保存場所と送信先 + +- キーは `~/.failproofai/credentials.json`(`0600`、オーナーのみのディレクトリ)に 1 回保存され、他の FailproofAI Cloud 認証情報と並置されます。このルートでは `jev.json` にキーは保存されません。そこに書き込まれた場合、設定は無効になります。 +- `credentials.json` が自分以外(グループまたはその他、読み取りまたは書き込み)に対して **いずれかの** 権限を持つ場合、またはそのディレクトリが自分以外から **書き込み可能** な場合、ファイルは読み取られず **拒否** され、修正するまで Jev はオフのままです。ファイルに `chmod 600`、ディレクトリに `chmod 700` を適用してください(または再接続するとファイルが `0600` で書き直され、ディレクトリがオーナーのみになります)。他者が読み取り専用のディレクトリは問題ありませんが、書き込み可能なディレクトリはファイルの差し替えを許してしまいます。 +- キーは、それが属する接続がマシン上にある間のみ有効です。同じ FailproofAI Cloud に対するポリシーまたはレポーティング用の認証情報が、同じファイル内に **同じキーで** 存在する必要があります。接続なしに残された Jev キーは無視され、Jev はオフのままです。これは、古い failproofai の `config --disconnect` が Jev キーを残した場合(削除方法を知らないため)、または古い failproofai の `config --token` が別のキーで接続した場合(FailproofAI Cloud では別の組織のキーである可能性がある)に発生します。Jev を再度有効にするには、**machine** キーで再接続してください。 +- キーは検証された Cloud オリジンにのみ送信されます。それ以外の場所を指す `jev.json` は拒否されます。 +- **マシン上のエージェントはキーを読み取れます。** `credentials.json` はオーナーのみですが、エージェントはそのオーナーとして実行されます。failproofai 自身のファイルの読み取りは意図的に許可されています(変更のみが `block-failproofai-commands` でブロックされます)。そのため、エージェントとこのファイルの間にあるのは `block-read-outside-cwd`(*reviewable* なポリシー)のみです。ホームディレクトリで開始されたセッションからは何もありません。`jev:evaluate` を持つキーは使用された場所を問わず組織の Jev 利用枠を消費します(日次上限まで)。そのため、マシンキーは他の支出用認証情報と同様に扱ってください。エージェントが読み取った可能性がある場合は、Keys ページで無効化し、新しいキーで再接続してください。 +- これを決定するのはグローバルファイルのみです。リポジトリは Cloud Jev を有効にしたり、別の場所に向けたり、キーを提供したりできません。また、このルートでは `FAILPROOFAI_JEV_API_KEY` は無視されます。 +- Jev が評価する各呼び出しに対して、FailproofAI Cloud に 1 件のリクエストが送信されます。[bring-your-own-key ページ](/ja/reference/jev-providers#what-leaves-the-machine)に記載されている内容(シークレットは除去済み)が含まれます。FailproofAI Cloud はそれを TypeSafe に転送し、ログや保持は行いません。 + +## 無効にする + +| コマンド | 結果 | +| --- | --- | +| `failproofai jev setup --mode off` | 設定を維持したまま Jev への問い合わせを停止する。**これが持続する切り替えです。** 再接続しても既存の `jev.json` は上書きされないため、`--mode observe` で戻すまで Jev はオフのままです。 | +| `failproofai jev remove` | `~/.failproofai/jev.json` を削除し、Jev をオフにします。ただし、`jev:evaluate` を持つキーで次回 `failproofai config --token` を実行すると、`jev.json` が存在しないため observe モードで Jev が再度有効になります(`--no-transcripts` で実行した場合を除く)。オフのままにするには `--mode off` を使用してください。 | +| `failproofai config --disconnect` | マシンを切断します。キーが削除され、`jev.json` が FailproofAI Cloud を指定していてオフに切り替えられていない場合は `jev.json` も削除されます。独自エンドポイント用の `jev.json` はそのまま残り、オフに切り替えられたものも残るため、再接続時も Jev はオフのままです。 | + +次のツール呼び出しから、フックはこれまでどおりレジェックスポリシーのみを実行します。 \ No newline at end of file diff --git a/docs/ja/reference/jev-evaluations.mdx b/docs/ja/reference/jev-evaluations.mdx new file mode 100644 index 000000000..d0522706f --- /dev/null +++ b/docs/ja/reference/jev-evaluations.mdx @@ -0,0 +1,88 @@ +--- +title: "Jev 評価リファレンス" +description: "Jev セッション評価における質問タイプ、スコアの算出方法、制限事項、バックフィルについて。" +icon: "list-checks" +--- + +このページでは、[Jev 評価](/ja/evaluations/jev)の背後にある質問の形式とスコアリングのルールを説明します。質問の中には、会話を*読む*必要はあっても、それについて*書く*必要のないものがあります。「顧客は緊急性を示しましたか?」には二つの答えがあります。「どれほど苛立っていましたか?」には、順序付けられたいくつかの答えがあります。質問する前からすべての答えが分かっているのです。 + +**classifier evaluation(分類器評価)** はまさにそのようなケースのためにあります。質問と、それが返しうる回答を記述すると、分類専用に設計された小型モデルが較正された数値を返します。自由テキストが返されることはありません。 + + +judge(判定器)と同様、classifier evaluation はセッションごとにモデル呼び出しのコストが発生します。ただし judge と異なり、汎用モデルではなく小型の単一目的モデルを使用するため、高速かつ安価です。ただし、理由は説明されません。推論過程が必要な場合は [judge](/ja/evaluations/judge) を使用してください。 + + +## どれを使えばいい? + +| 質問 | 使用するもの | +| --- | --- | +| ツール呼び出しは何回ありましたか? | code | +| セッションは30秒以内でしたか? | code | +| 顧客は緊急性を示しましたか? | **classifier** | +| 担当チームはどこですか:請求、技術、それとも営業? | **classifier** | +| 顧客はどれほど苛立っていましたか? | **classifier** | +| 回答は実際に正しかったですか? | **judge** | +| エスカレーションポリシーに従っていましたか?その理由は? | **judge** | + +目安として:**数えられる → code、列挙できる回答 → classifier、説明が必要 → judge。** + +事前に決める必要はありません。測定したいことを説明すれば、アシスタントが選択し、何を選んだか・その理由を伝えてくれます。後から変更することも可能です。 + +## 2つの質問タイプ + +### `noul` — これは真ですか? + +答えは二つで、両方を説明します。結果は「真」の説明が当てはまる確率です: + +```json +{ + "instructions": "Did the assistant promise a refund without first checking the refund policy?", + "criteria": { + "true": "A refund was promised or issued with no prior policy check or approval", + "false": "No refund was promised, or every refund followed a policy check" + } +} +``` + +両側を説明してください。「緊急性は示されていない」も立派な回答であり、明示することで対となる回答がより明確になります。 + +### `score` — これはどの程度? + +順序付きのルーブリックで、**最悪の状態を先頭に**記述します。結果はセッションがルーブリック上のどこに位置するかを示し、0〜1 にスケールされます: + +```json +{ + "instructions": "How frustrated is the customer?", + "criteria": ["Calm", "Frustrated", "Very angry"] +} +``` + +**ルーブリックは3〜5レベルで、すべて異なる内容にする必要があります。** 両方の制限は文体上の問題ではなく、測定上の理由によるものです: + +- **2レベル**にすると `noul` がすでにうまく対応している内容に退化します。**5レベル超**にするとモデルが確信を持たず中間に偏ります。同じ質問を同じセッションに適用したとき、2レベルでは 0.00、3レベルでは 0.01、10レベルでは 0.55 というスコアになりました。 +- **レベルが重複している**と、答えがそれらの間で任意に分散します。明らかに怒っているセッションが `["Calm", "Frustrated", "Very angry"]` では 1.00 と採点されたのに対し、`["Angry", "Angry", "Angry"]` では 0.66 となりました。数値として整合性はあるように見えますが、何も意味していません。 + +「請求、技術、営業」のような順序のないカテゴリはルーブリックではありません。カテゴリごとに `noul` で質問するか、judge を使用してください。 + +## 結果の読み方 + +classifier は judge と同様に 0〜1 の **スコア** を出力するため、グラフ表示、フィルタリング、アラートのトリガーも同じ方法で行えます。知っておくべき2つの違いがあります: + +- **推論過程はありません。** このフィールドは意図的に空になっています。このモデルは説明を行わず、説明を作り出すことは機能ではなく捏造になります。 +- **不確実性にはラベルが付きます。** `score` 質問は自身の信頼度を報告し、モデルが確信を持てなかった結果には `low_confidence` タグが付きます。「人間がチェックすべきもの」がフィルタリングで特定できるようになります。`noul` 質問は信頼度を報告しないため、このタグが付くことはありません。 + +非常に長いセッションは抜粋して読み、結果を統合します。セッションが全体を読むには長すぎる場合、結果には何ターンが省略されたかが示されます。全体を読んだかのように見せかけた、一部に基づく判定が表示されることはありません。 + +## 制限事項 + +- **ルーブリックは3〜5レベルで、すべて異なる内容にする。** 上記参照。両方の制限は作成時に強制されます。 +- **評価あたり質問は1つ。** 2つ尋ねたい場合は2つの評価を作成します。グラフ上でも同様にそれが望ましい形です。 +- **質問を編集すると新しいバージョンが公開されます。** 旧スコアと新スコアは比較できないため、1つのトレンドラインに混在させるのではなく、別々に保持されます。 +- **classifier は常にスコアを出力し**、メトリクスやアサーションは出力しません。 +- **推論過程はありません**(上記のとおり)。数値を見て「なぜ?」と聞かれる可能性があるなら、judge を記述してください。 + +## テストとバックフィル + +judge とは異なり、classifier evaluation はデプロイ前に**テストすることができます**。code 評価と同じように実際のセッションを使って[テスト](/ja/evaluations/test)し、本番稼働前にスコアを確認できます。 + +また、すでに保有しているセッションに対して[バックフィル](/ja/evaluations/deploy#score-sessions-you-already-have)することも可能です。セッションごとにモデル呼び出しのコストが発生するため、すべてを再実行するのではなく、対象期間を意図的に絞り込んでください。 \ No newline at end of file diff --git a/docs/ja/reference/jev-intent.mdx b/docs/ja/reference/jev-intent.mdx new file mode 100644 index 000000000..cae107b2a --- /dev/null +++ b/docs/ja/reference/jev-intent.mdx @@ -0,0 +1,112 @@ +--- +title: "Jev インテントキャプチャ" +description: "どのハーネスイベントが Jev エバリュエーターに人間の要求を伝えるか、テキストを保持するフィールド、カウントされないもの、ハーネス経由のプロンプトを信頼するリスクについて説明します。" +icon: "message-square-quote" +--- + +[Jev ポリシーレビュー](/ja/policies/jev)を設定すると、エバリュエーターはゲートされた各ツール呼び出しを、ハーネスがエージェントに渡したテキストではなく、**人間が要求した内容**に照らして判断します。「はい、force-push してください」といった返答は **reviewable** ポリシーをクリアできます。これがエバリュエーターの本来の目的です。要求を読み取れない正規表現は実務の 3 分の 1 をブロックしてしまうからです。 + +そのテキストの出所は 1 つだけです。**ハーネス自体がプロンプト送信イベント時にフックに渡すプロンプト**です。Failproof AI は、ハーネスのラッピングを除去し、シークレットをリダクトした上で、人間が入力した部分を自身のステートディレクトリ以下の `0600` ファイルに記録します。ディスク上のものは参照されません。セッションの会話記録はエージェントが 1 コマンドで書き換えられるファイルであるため、プロンプトの作成者を尋ねることはありません。 + +## 受け入れるリスクについて、率直に + +コマンドを実行できるエージェントは、ハーネスにプロンプトを送信させることができます。`claude -p "…"`、`codex exec`、`copilot -p`、`cursor-agent -p`、`devin -p`、`droid -p`、`goose run -t`、`pi -p` はいずれも、そのエージェントが制御する子セッションで、人間がタイプした場合と同じプロンプト送信イベントを同じペイロードで発火させます。また、Failproof AI 自身のフックバイナリを実行し、自分で作成したペイロードを渡すこともできます。Failproof AI の内部からは、どちらが本物かを判別する手段はありません。どちらも同じプログラムが同じ stdin を読んでいます。 + +**つまり、シェルを持つエージェントは自分自身の同意を偽造できます。** これは 2026-09-23 に意図的に受け入れたトレードオフであり、その両面を以下に示します。 + +- **何を得るか。** 代替案は実装・計測されました。ハーネスが人間をプロンプトの作成者として明示するフィールドを要求し、それがない場合は何も記録しない、というものです。しかし、現行のどのハーネスもそのようなフィールドを送信していないため、そのバージョンでは**すべてのハーネスで何も記録されず**、Jev はすべての呼び出しをインテントなしで判断することになり、1 つのポリシーもクリアできませんでした。一度も機能しないキャプチャは安全なプロダクトではなく、プロダクトとして成立しません。 +- **何ができないか。** 記録されたプロンプトは、**reviewable** とマークされたポリシーのみをクリアできます。**hard** ポリシーは Jev の判断で決してクリアされないため、偽造されたプロンプトが hard deny を allow に変えることはできません。また、フックをスキップしてもエージェントに何のメリットもありません。ハーネスはツール呼び出しに対して独立して Failproof AI を呼び出すからです。 +- **最大規模で何ができるか。** 最悪のケースでは、15 個の reviewable 組み込みポリシーのうちの 1 つをクリアできます。ただし、**15 個中 12 個はブロック**です。`protect-env-vars`、`block-env-files`、`block-read-outside-cwd`、`block-rm-rf`、`block-force-push`、`block-secrets-write`、6 つのインフラ CLI ブロック(`block-kubectl`、`block-terraform`、`block-aws-cli`、`block-gcloud`、`block-az-cli`、`block-helm`)はいずれも deny です。つまり偽造された同意は、環境シークレットの表示、`.env` ファイルの読み取り、プロジェクト外の読み取り、`rm -rf`、force-push、シークレットファイルへの書き込み、ライブインフラの変更において、本物の deny を allow に変えられます。`warn-git-amend`、`warn-destructive-sql`、`warn-global-package-install` だけがナッジです。デフォルトインストールでは 12 個中 2 つ(`protect-env-vars` と `block-env-files`)が有効になります。残りの 10 個は誰かが明示的に有効にしたマシンにのみ影響します。プロンプトが届かないのは、すべての hard ポリシーです。`block-sudo`、`block-curl-pipe-sh`、`block-push-master`、`block-work-on-main`、エージェントが Failproof AI を無効化するのを防ぐガード、その他 reviewable とマークされていないすべての組み込みポリシーは対象外です。[ポリシー権限](/ja/policies/authority)ではすべての 15 個とそれぞれのレビュー対象がリストされています。 + +引き続き拒否されるのは、安価にチェックできる、かつエージェントが単に要求するだけでは取得できないもの全てです。ハーネス自身のペイロードがマシン送信のターンとしてマークしているターン、サブエージェントを指定するペイロード、通常の名前でないセッション ID、プロンプト送信以外のイベント、そしてハーネスのラッピングのみのテキスト(複数のハーネスが次のユーザーターンとしてフィードバックする Failproof AI 自身のストップゲートワードを含む)。 + +## ハーネス別テーブル + +「テキストフィールド」は、Failproof AI のハーネス別正規化後の stdin ペイロードフィールドです。「記録」はプロンプトが人間のリクエストとして保存されるかどうかを示します。 + +| ハーネス | `--cli` | プロンプトイベント → 正規化 | テキストフィールド | 記録 | エージェントの最終メッセージ取得元 | +| --- | --- | --- | --- | --- | --- | +| Claude Code | `claude` | `UserPromptSubmit` | `prompt` | はい(ただし、ペイロードの `source` が誰も送信していないターン(`loop_wakeup`、`schedule_wakeup`、`poll_event`、`system`)を指名している場合を除く。`user`、`sdk`、不明な値、`source` を送信しないビルドはすべて記録される) | セッション会話記録(`transcript_path`) | +| Codex | `codex` | `user_prompt_submit` → `UserPromptSubmit` | `prompt` | はい | ロールアウト JSONL(`agent_message`、`AgentMessage`) | +| GitHub Copilot CLI | `copilot` | `UserPromptSubmit` | `prompt` | はい | `events.jsonl`(`assistant.message`) | +| Cursor | `cursor` | `beforeSubmitPrompt` → `UserPromptSubmit` | `prompt` | はい(プロンプト全体が `` ラッパーの場合は除去される) | エージェント会話記録 JSONL | +| OpenCode | `opencode` | `message.updated`(user ロール)→ `UserPromptSubmit` | `prompt` | はい(ただし現行の OpenCode ではそのイベントにテキストが含まれないため、実際には何も記録されない。同じメッセージの繰り返しは 1 回のみ記録される) | なし(セッションは SQLite) | +| Pi | `pi` | `input` → `UserPromptSubmit` | `prompt` | はい(ただし `input_source` が `extension` の場合を除く。これは別の拡張機能の `sendUserMessage()` であり、テキストがモデルによって生成またはリポジトリから導出されている可能性がある) | Pi セッション JSONL | +| Hermes | `hermes` | なし | — | いいえ。Hermes にはプロンプト送信イベントがない | — | +| OpenClaw | `openclaw` | `before_agent_run` → `UserPromptSubmit` | `prompt` | はい(ただしランメタデータがマシンによるランとしてマークしている場合を除く。`user` 以外の `trigger`、`external_user` 以外の `inputProvenance.kind`、または `senderIsOwner: false`) | なし(`before_agent_run` には会話記録パスが含まれない) | +| Factory Droid | `factory` | `UserPromptSubmit` | `prompt` | はい | droid セッション JSONL | +| Devin CLI | `devin` | `UserPromptSubmit` | `prompt` | はい | なし(セッションは SQLite) | +| Antigravity CLI | `antigravity` | `PreInvocation` → `UserPromptSubmit` | なし | いいえ。`PreInvocation` はターン内の*すべての*モデル呼び出し前に発火し、プロンプトテキストを含まない | — | +| Goose | `goose` | `UserPromptSubmit` | `message` | はい | なし(セッションは SQLite) | + +2 つのハーネスは何も記録しませんが、どちらも理由は同じです。イベントが人間のテキストを提供しないからです。Hermes にはプロンプト送信イベントがありません。ネイティブプラグインが `pre_llm_call` 自体を処理し、ツール・セッション・サブエージェントのイベントのみを転送します。Antigravity の `PreInvocation` はすべてのモデル呼び出し前(人間のターンとその後の 5 回分)に発火し、プロンプトフィールドを持ちません。フックが `userMessage` ステップを同じ会話に注入することもできます。どちらのイベントにも記録すべきものがありません。 + +## プロンプトを人間のものとする条件 + +1. **イベント。** Failproof AI がハーネスのプロンプト送信イベントのために呼び出され、ハンドラーがそれを `UserPromptSubmit` に正規化している。 +2. **ペイロード。** ハーネスがフックの stdin にそれを書き込み、上記のフィールドにテキストが含まれている。ペイロードなしで Failproof AI に到達した呼び出しは何も記録されない。 +3. **ペイロード内にターンを除外するものがない。** サブエージェント(`agent_id`)を指名するペイロードはエージェントが自身にプロンプトを送っている。`source`、`input_source`、または OpenClaw のランマーカーがマシン送信のターンを指名している場合は拒否される。**存在しない**マーカーは何も除外しません。これが何も記録しなかったバージョンとの違いです。ここに挙げるすべてのマーカーはすべての出荷ビルドで存在しないからです。 +4. **ラッピングを除去した後に何かが残っている**(下記参照)。 + +**セッション会話記録は、誰がプロンプトを書いたかの証拠にはなりません。** このページの以前のバージョンでは、会話記録のクロスチェックが説明されていました。会話記録がモデルによるスケジューリングを示している場合はプロンプトを拒否し、会話記録が前のプロンプトが見たものから継続していなければならないというものでした。このチェックはなくなりました。会話記録はエージェントがすでにシェル権限を持っているファイルであり、切り詰め、置換、読み込みバジェットを超えたパディング、ターン開始時のスナップショットと終了時の復元、エージェント自身が書いたエントリによる上書きが可能です。強化の試みのたびに同じ偽造の別の表現が生まれたため、修正ではなくメカニズム全体を削除しました。 + +会話記録が読まれるのは 1 つのことのためだけです。**エージェントの最後に見えているメッセージ**です。そのメッセージは定義上エージェントが書いたものであり、Jev にはその旨が伝えられ、それ単体では同意にはなりません。 + +## プロンプトから保持される内容 + +ハーネスはプロンプトに人間の言葉以上のものを含めます。何かが保存される前に以下の処理が行われます。 + +- `` ブロックが除去され、その周囲の人間の言葉が保持されます。 +- セッション継続サマリー(「このセッションは以前の会話から続いています…」)は完全に削除されます。 +- タスク通知、ローカルコマンドの出力、割り込みマーカーは完全に削除されます。 +- 別のエージェントまたはセッションが書いたターンは完全に削除されます。Claude Code はそれらを ``、``、``、``、`` でラップします。 +- Failproof AI 自身のメッセージは完全に削除されます。ストップゲートの `MANDATORY ACTION REQUIRED from failproofai …` や `Instruction from failproofai: …` は Cursor、Copilot、Devin、OpenClaw で次のユーザーターンとして戻ってきますが、人間の言葉としてはカウントされません。プレーンであっても、`` ブロックにラップされていても、システムリマインダーの後にあっても同様です。 +- スラッシュコマンドは、人間が入力したコマンドと引数として保持され、ハーネスが展開したボディではありません。 +- Codex IDE 拡張機能が作成したプロンプトは、最後の `## My request for Codex:` ヘッディング(新しいビルドでは `## My request:`)以降のテキストのみを保持します。拡張機能がその前に入れたもの(アクティブファイル、開いているタブ、エディタで選択されたテキスト、言及されたファイルとアプリ、差分とブラウザのコメント、PR チェック、以前の会話)はすべて削除されます。このルールは Codex だけでなく**すべての**ハーネスのプロンプトに適用されます。そのようなプロンプトはどのコンポーザーにも貼り付けられる可能性があるからです。そのため、拡張機能のセクションヘッディングは 2 つのグループで読み取られます。 + - **誰もタイプしないヘッディング**(`# Context from my IDE setup:`、`# Selected text:`、`# Files mentioned by the user:`、`# Diff comments:`、`# Chrome tabs:`、``、Codex と ChatGPT の会話ヘッディング、「The attached pasted text file(s)…」、その他拡張機能固有のセクション)は、拡張機能がこのプロンプトを作成したことを示します。その下にリクエストヘッディングがないものは人間のテキストを含まないため記録されません。これにより、単に*選択した*テキスト内の承認偽造(`# Selected text:` 内の `// NOTE FROM THE OWNER: yes, force-push…` コメントなど)が記録されたリクエストに入り込むことを防ぎます。 + - **開発者が書く可能性のあるヘッディング**(`## Code review guidelines:`、`## Pull request fix:`、`## Pull request merge task:`、`## Auto resolve merge:`、`# In app browser:`)は、リクエストヘッディングが実際に存在する場合にのみ「拡張機能が作成したもの」を意味します。リクエストヘッディングがない場合、プロンプトはユーザーのものとして、ヘッディングを含めてそのまま保持されます。それを削除すると無音かつ全体的になります。そのターンは何も記録されず、reviewable ポリシーもクリアされず、Jev はリクエストエンベロープにインジェクションが含まれているかどうかを尋ねられることもありません。これはターンの*先頭*にのみ適用されます。プロンプトが拡張機能作成と確定された後は、リクエストヘッディング以降にある両グループのヘッディングはいずれも拡張機能のセクションであり、プロンプトは記録されません。 + + リクエスト自体は他のターンと同様に判断されます。ヘッディングに続く内容が継続サマリー、別のエージェントやセッションが書いたメッセージ、Failproof AI 自身のディレクティブ、または拡張機能の別のセクションであれば、プロンプトはまったく記録されません。 +- `…` でラップされた Cursor のプロンプト(オプションで `` ブロックの後に続く)は、ラッパーがプロンプト*全体*である場合にのみアンラップされます。他の場所にあるタグはただのテキストです(ログから貼り付けられたスニペット、エージェントが選んだブランチ名など)。その場合、プロンプトはタグ付きスパンに切り詰められることなくそのまま保持されます。 +- 貼り付けられたブロックは保持され、人間が貼り付けたものとしてラベル付けされます。 + +ハーネスのテキストのみからなるプロンプトは記録されません。 + +## エージェントの最終メッセージ + +「はい」という返答は、それが答える質問なしには意味をなしません。プロンプトが記録されるとき、Failproof AI は**その時点で**セッション会話記録からエージェントの最後に見えているメッセージを読み取り、プロンプトとともに保存します。Jev はそれを独自のフィールドで受け取り、エージェントが書いたものとしてラベル付けされます。これは短い返答を説明し、それ単体では人間のリクエストとしてカウントされません。会話記録が読まれる唯一の用途であり、書き換えられた会話記録が最悪できることは、エージェントが書いたメッセージが期待される場所にエージェントが書いたメッセージを置くことだけです。 + +会話記録の末尾から、最大 4 MB 読み取られます。サポートされている会話記録フォーマットは Claude Code、Codex ロールアウト(古い `agent_message` イベントと新しい `AgentMessage` アイテム)、Cursor、Copilot の `events.jsonl`、Pi・Factory・OpenClaw セッション JSONL です。Claude Code 自身の合成メッセージ、API エラーメッセージ、サブエージェント(サイドチェーン)メッセージはスキップされます。セッションを SQLite に保存する Goose と OpenCode、会話記録が単一の JSON ドキュメントである Devin、`before_agent_run` イベントに会話記録パスが含まれない OpenClaw にはスナップショットがありません。 + +## ストレージ + +| プロパティ | 値 | +| --- | --- | +| 場所 | `~/.failproofai/state/semantic/sessions/.json` | +| パーミッション | ファイル `0600`、ディレクトリ `0700`。その上の `~/.failproofai` までのすべてのディレクトリも同じルールが適用されます。他のユーザーが**書き込み**できるディレクトリは名前を変えて置き換えられる可能性があるため、読み取りパスは書き込みビットを可能な範囲で除去し、除去できない場合は**何も読み取りません**。記録されたプロンプトは偽造されるのではなく、存在しないことになり、何もクリアされません | +| セッションごとの保存件数 | 最後の 5 プロンプト。直前のものと同一のプロンプトは新しいスロットを取らずに置換される | +| ウィンドウ | 6 時間より古いプロンプトは無視される | +| サイズ | 各プロンプトとエージェントメッセージは先頭と末尾を保持する形で 6,000 文字に制限される | +| シークレット | 書き込み前に `sanitize-*` ポリシーと同じパターンでリダクトされる。48,000 文字を超えるテキストは最初の 28,800 文字と最後の 19,200 文字にリダクトされ、シークレットが分割されていた可能性のある切り取り部分の隣接テキストは保存されない | + +セッション ID に文字、数字、`.`、`_`、`-` 以外の文字が含まれる場合、または 128 文字を超える場合は、ファイル名として使用されないため、そのセッションには何も記録されません。 + +セッションファイルはプロンプトが記録されて初めて存在します。プロンプトのみを保持し、オリジン状態や会話記録マークは含みません。6 時間のウィンドウより長い無活動の後、次に新しいセッションが最初のプロンプトを書き込む際に削除されます。 + +Jev エンドポイントが設定されていない場合、何も記録されません。 + +### プロジェクトルート + +「プロジェクト内部」(`read-outside-workspace` およびその他のパスチェックが判断する基準)とは、セッションの**最初のレビュー済み呼び出し**時点でのプロジェクト内部を意味します。ルートはその時点でピン留めされ、後の `cd` では移動しません。ただし `cd` は相対パスの解決方法を変更します。`cd` に追従させると、ある呼び出しでの `cd ~/.ssh` が次の呼び出しで `~/.ssh` をプロジェクトにしてしまうことになります。 + +ピンは `~/.failproofai/state/semantic/roots/.json` に保存され、`{root, at}` を保持します。ファイル `0600`、ディレクトリ `0700`、および上記と同じセッション ID ルールが適用されます。7 日より古いファイルは新しいセッションがルートをピン留めする際に削除されます。他のユーザーが書き込みできる `roots` ディレクトリは無視され、代わりにライブディレクトリのルートが使用されます。セッションを再ピン留めするにはそのファイルを削除してください。 + +## 既知の制限 + +- **プロンプトの信頼性はフック呼び出しの信頼性に依存します。** ここで説明するすべては、ハーネスがフックの stdin に書き込んだペイロードを読み取ります。コマンドを実行できるエージェントは、ハーネスをヘッドレスで実行(`claude -p` および上記の 7 つ)したり、Failproof AI のフックバイナリを自身が作成したペイロードで直接実行したりして、誰も入力していないプロンプトを記録できます。これはこのページの冒頭で説明した受け入れ済みのトレードオフです。reviewable ポリシーのみをクリアでき、hard ポリシーは決してクリアできません。ただし、15 個の reviewable 組み込みポリシーのうち 12 個は deny であるため、偽造されたプロンプトはその 12 個において実際のブロックを allow に変えることができます。 +- **サブエージェント検出は Claude に特化した形です。** `agent_id` を持つペイロードはどのハーネスでも記録されません。これは Claude Code、Factory Droid、Devin が使用するフィールドです。Codex はサブエージェントスレッド内でプロンプトイベントを発火し、Copilot はインプロセスのサイドキックを実行し、Goose には `delegate` ツールがあり、OpenClaw はペルソナを実行しますが、いずれもペイロードをこれが認識できる形でマークしません。そのため、それらのハーネスではサブエージェントのプロンプトがセッション自身のものとして記録されます。OpenClaw の `openclaw.agentId` はそのマークではありません。出荷済みプラグインはオーナーのランを含めたすべてのランでそれを設定します。 +- **マーカーなしのスケジューラー。** Claude Code の `schedule_wakeup`・`loop_wakeup`、および OpenClaw の `cron`・`heartbeat` トリガーは、それらのハーネスがペイロードでそう伝えるため拒否されます。Goose 自身のスケジューラー(`goose schedule add`)と Codex の `codex exec` は何も伝えないため、それらが開始したランは他と同様に記録されます。 +- **エージェントの最終メッセージはエージェントが選んだメッセージになりえます。** 会話記録は認証されていないため、自身の会話記録を書き換えられるエージェントは「最終メッセージ」の内容を決めることができます。それはエージェント作成としてラベル付けされ、それ単体では何もクリアしません。ただし、`decide.ts` の v1 パスでは決定論的な「ユーザーがこのターゲットを指名したか」チェックを満たせることに注意してください。そのため、会話記録を制御するエージェントは、オーバーライドが必要とするターゲット名を提供できます。 +- **拡張機能のマシンヘッディングで始まるプロンプトは全体が削除されます。** `# Selected text:`、`# Diff comments:`、`# Chrome tabs:` または上記第 1 グループの別のセクションヘッディングでプロンプトを始め、`## My request:` ヘッディングを書かない場合、そのターンは何も記録されないため、何もクリアされません。これは意図的です。それらのセクションは他の誰かが制御するテキスト(選択したコード、レビュアーの差分コメント、ページタイトル)を含んでおり、それを人間の言葉として記録する方が問題です。開発者が書く可能性のあるヘッディングは第 2 グループに属し、それだけでプロンプトを削除することはありません。 +- **OpenCode は実際には何も記録しません。** 現行の OpenCode では `message.updated` イベントにテキストが含まれず、また親エージェントが書いた「user」メッセージを持つタスクツールが作成する子セッションに対しても発火します。 +- **`CODEX_HOME` は `lib/codex-sessions.ts` のロールアウト探索では考慮されません。** これはエージェントメッセージスナップショットを探す場所にのみ影響し、プロンプトが記録されるかどうかには一切影響しません。 \ No newline at end of file diff --git a/docs/ja/reference/jev-providers.mdx b/docs/ja/reference/jev-providers.mdx new file mode 100644 index 000000000..2468afd58 --- /dev/null +++ b/docs/ja/reference/jev-providers.mdx @@ -0,0 +1,275 @@ +--- +title: "Jevプロバイダーと自前キーの設定" +description: "自前キーを使ったJevポリシーレビューのプロバイダーエンドポイント、モデルID、設定方法、障害時の動作について。" +icon: "key-round" +--- + +これは、自前キーを使った[Jevポリシー](/ja/policies/jev)のプロバイダーおよび設定リファレンスです。正規表現ポリシーは文字列をマッチングします。あなたが意図して実行した `rm -rf build/` と、プランに紛れ込んだ `rm -rf ~` を区別することはできません。そのため、ある場所では過剰にブロックし、別の場所では不足してしまいます。TypeSafeの分類器である **Jev** は、実際にあなたが何を求めていたかに照らしてツール呼び出しを読み取り、一度の高速なリクエストでその内容についてyes/noの質問群に答えます。 + +自前のJevエンドポイントとキーを設定すると、Failproof AIは各ツール呼び出しについて、正規表現ポリシーを*置き換えるのではなく*、**その横で**Jevに問い合わせます。 + +- **ハード**ポリシーのdenyは最終的なものです。Jevがそれを解除することはできません。ポリシーは、明示的にreviewableとマークされ、それをカバーするJevチェックが指定されていない限り、すべてハードです。したがって、何も記述していないカスタムポリシー、パックポリシー、Cloudポリシーはハードであり、常時有効な自己保護ガードも常にハードです。 +- **reviewable**ポリシーのdenyは解除される可能性がありますが、Jevがそのポリシーの対象となる懸念事項について正確に問い合わせられ、「ここには問題ない」または「ユーザーがこれを要求した」と答えた場合に限ります。懸念事項が実在すると判断したチェック(ユーザーがその呼び出しを要求していない場合)は、denyを維持します。そのチェック自体の判定が警告にとどまる場合でも同様です。なぜなら、ツール呼び出し前の警告はエージェントを止めないからです。そのチェックがdenyを出せるもの(シークレット漏洩、認証情報の窃取、破壊的な削除など)であれば、そのツール呼び出しでは何も解除されません。 +- ツール呼び出しがあなたが与えたタスクのステップであり、それ以上の範囲に及ばない場合、ブロックは**警告**に変わることがあります。Jevは自身のdenyを警告に軟化し、その警告(ツール呼び出しの実際の問題点を名指しするもの)がポリシーのブロックに代わります。 +- Jevは、正規表現では説明できない危害に対して、独自に警告やdenyを出すこともあります。 +- Jevが回答できない場合(タイムアウト、レート制限、サーバーエラー、クレジット不足、予期しないモデルバージョン)、そのツール呼び出しはJevなしの場合とまったく同じ正規表現の結果が使われます。 +- Jevは、ツール呼び出し全体を読み取り、その懸念事項について正確に問い合わせられた場合を除き、あなたのポリシー単体より許容範囲を広げることはありません。それ以下の場合(全体を送信するには大きすぎるツール呼び出し、インジェクションの疑い)は、解除が取り消され、すべてのdenyが維持されます。 + + +Jevの設定がなければ何も変わりません。フックは従来どおり正規表現ポリシーのみで実行されます。設定がオプトインのすべてです。 + + + +FailproofAI Cloudをお使いですか?自前のキーは不要です。`jev:evaluate` を持つキーで接続されたマシンは、組織のプランでJevを利用できます。[FailproofAI Cloud経由のJev](/ja/reference/jev-cloud)をご覧ください。 + + +## 始める前に + +**failproofai 1.0.8-beta.0以降**をインストールし、エージェントが動作するマシン上で[サポートされているハーネス](/ja/reference/harnesses)にフックをアタッチしてください。新しいマシンの場合は[クイックスタート](/ja/start/quickstart)に、Cloudを使用しない場合は[ローカル適用の設定](/ja/start/setup#enforce-locally)に従ってください。インストール済みのCLIは `failproofai --version` で確認できます。 + +以下のいずれかのプロバイダーからAPIキーを取得するか、互換性のあるエンドポイントとそのキーを用意してください。Jevは `PreToolUse` または `PermissionRequest` ゲートで名前付きツール呼び出しをレビューします。独自の判定を出すことができますが、既存のポリシーdenyを解除するには、[reviewable](/ja/policies/authority)とマークされたポリシーのインストールも必要です。ハードポリシーのdenyは最終的なまま変わりません。 + +## プロバイダーを選ぶ + +Jevには5つの経路でアクセスできます。いずれか1つのキーをご用意ください。 + +| プロバイダー | `--provider` | エンドポイント | デフォルトモデル | 備考 | +| --- | --- | --- | --- | --- | +| TypeSafe | `typesafe` | `api.typesafe.ai/v1/systemone` | `jev-1.13.0` | 厳密なバージョン固定。 | +| OpenRouter | `openrouter` | `openrouter.ai/api/v1/systemone` | `typesafe/jev-1.13` | リクエストはデータ保持なしのエンドポイントにのみルーティングされ、別プロバイダーへのフォールバックはありません。`typesafe/jev-1.13-20260917` のような日付付きバージョンを報告します。 | +| Vercel AI Gateway | `vercel` | `ai-gateway.vercel.sh/typesafe/v1/systemone` | `typesafe-ai/jev` | Jevをエイリアスのみで識別するため、回答したバージョンは未検証として記録されます。 | +| Cloudflare Workers AI | `cloudflare` | `api.cloudflare.com/client/v4/accounts//ai/run` | `typesafe/jev` | `--account-id` が必要です。キーあたり毎秒約6リクエストでHTTP 429が発生することが確認されています。 | +| 自前エンドポイント | `custom` | `/systemone` | `jev-1.13.0` | TypeSafeのリクエストボディを受け付け、どのモデルが回答したかを報告するエンドポイントであれば何でも可。`https` のみ。observeモードに限り、平文の `http://localhost` も受け付けられます。 | + + +VercelのBYOK(自前キー)機能を使用する場合、失敗したリクエストはVercelの認証情報で静かに再試行されます。すべてのツール呼び出しを自分のTypeSafeアカウントのみに課金・参照させたい場合は、TypeSafeに直接接続してください。 + + +## 設定する + +コマンド1つで、エンドポイントとキーを設定できます。まず `observe` モードで始めることで、既存のポリシーが引き続きツール呼び出しを決定しながら、Jevの判定を確認できます。 + +```bash +failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key +``` + +### URLでプロバイダーを選択する + +プロバイダーを明示的に指定する必要はありません。URLの**ホスト**がプロバイダーを決定します。 + +| URLホスト | プロバイダー | 追加必要事項 | +| --- | --- | --- | +| `api.typesafe.ai` | `typesafe` | — | +| `openrouter.ai` | `openrouter` | — | +| `ai-gateway.vercel.sh` | `vercel` | — | +| `api.cloudflare.com` | `cloudflare` | `--account-id <32-hex-account-id>` | +| その他のホスト | `custom` | — 指定したURLがベースURLになります | + +これから3つのことが導かれます。 + +- **プロバイダー自身のAPIのURLはオーバーライドを書きません。** `--url https://api.typesafe.ai/v1` は `--provider typesafe` とまったく同じ設定を生成します。既知のプロバイダーに対して異なるパスやホストを指定すると、`--base-url` で保存した場合と同様にベースURLとして保存されます。 +- **`--provider` は推論を上書きします。**これにより、自分のホストからプロバイダーのAPIを話すプロキシに到達できます。例:`--url https://jev-proxy.internal/v1 --provider typesafe` +- **ホストと矛盾する `--provider` は拒否されます**(推測はされません)。`--provider openrouter --url https://api.typesafe.ai/v1` は何も書き込まず、理由を説明します。2つの指定がキーの送信先について不一致だからです。同じ組み合わせは `jev setup --base-url` およびダッシュボードのJev設定からも拒否されます。(`--provider custom` は矛盾ではありません。「このURLをそのまま使う」という意味です。ただし、Cloudflareのホストは例外で、アカウントごとのエンドポイントにはカスタムルートで到達できません。) + +`--url` はconfigファイルの `baseUrl` とまったく同じように検証され、同じ文言で拒否されます。`https` が必要で、observeモードに限り平文の `http://localhost` も受け付けられます。 + +### キー + +`--key-stdin` でパイプするか、ターミナルでコマンドを実行してマスクされたプロンプトでキーを貼り付けてください。どちらの方法でも、キーはconfigファイルに直接書き込まれ、画面には表示されません。 + + + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key + ``` + + + ```bash + failproofai jev --url https://openrouter.ai/api/v1 --mode observe --key-stdin < ~/openrouter.key + ``` + + + ```bash + failproofai jev --url https://ai-gateway.vercel.sh/typesafe/v1 --mode observe \ + --key-stdin < ~/vercel-gateway.key + ``` + + + ```bash + failproofai jev --url https://api.cloudflare.com/client/v4 \ + --account-id <32-hex-account-id> --mode observe --key-stdin < ~/cloudflare.token + ``` + + + ```bash + failproofai jev --url https://jev.internal.example.com/v1 --mode observe --key-stdin < ~/jev.key + ``` + + + +`failproofai jev setup` は同じフラグを取り、すべての操作の長形式です。URLよりもプロバイダー名を指定したい場合は `setup --provider ` を使用します。 + +### `--token` とそのコスト + +`--token ` はコマンドラインにキーを置きます。これはマシンを設定する最速の方法ですが、キーがconfigファイル以外の場所に残る唯一の書き方でもあります。 + +```bash +failproofai jev --url https://openrouter.ai/api/v1 --token +``` + + +コマンドライン引数はその後シェルの履歴ファイルに残り、コマンドの実行中はプロセスリストに表示されます。`/proc` からあなたと同じユーザーで実行中の何者でも読み取れます。`setup` は `--token` が使用されるたびにこの旨を表示します。共有マシン、録画セッション、または履歴ファイルが同期される環境では `--key-stdin` を使用してください。この方法でキーを渡した場合は、必要に応じてキーをローテーションしてください。 + + +`--token`、`--key-stdin`、`--key-from-env` は相互に排他的です。いずれか1つを指定してください。 + +次に、1つの小さなライブリクエストを送信して、キー、エンドポイント、どのJevが回答したかを確認します。 + +```bash +failproofai jev test +``` + +```text + failproofai jev test ok · 523 ms + + provider cloudflare + model asked typesafe/jev + answered by jev-1.13.0 (Jev 1.13 family — verified) + latency 523 ms — within the 3000 ms timeout +``` + +`jev test` は、タイムアウト後に回答が届いた場合(すべてのフックが `timeout` として正規表現にフォールバックする)、またはチェック質問への回答が誤っている場合に、タイトルにその旨を表示して終了コード1で終了します。 + +フックはすべてのツール呼び出しでconfigを読み込むため、次のツール呼び出しから適用されます。デーモンの有無にかかわらず、再起動は不要です。 + +## 動作を確認する + +```bash +failproofai jev status +failproofai jev status --json +``` + +`status` はプロバイダー、エンドポイント、モデル、モード、configファイルとそのパーミッションを表示します。キーは表示されません。その下には最近のアクティビティのサマリーが表示されます。Jevが評価したツール呼び出し数、正規表現にフォールバックした回数とその理由、レイテンシ、解除されたreviewableポリシーなどが確認できます。 + +## 実際のツール呼び出しを確認する + +フックされたエージェントで新しいセッションを開始し、`README.md` に対してファイル読み取りツールを使用してタイトルを報告するよう指示してください。セッションにそのツール呼び出しが含まれることを確認したら、`failproofai jev status` を再度実行します。直近の評価済みツール呼び出し数が増えているはずです。[ローカルダッシュボード](/ja/reference/local-dashboard#review-policy-activity)の**ポリシー → アクティビティ**を開いて、そのツール呼び出しのJev判定とモードを確認してください。observeモードでは、ポリシーの結果が引き続きツール呼び出しを決定します。解除は、reviewableポリシーがマッチし、Jevがすべての指定チェックを解除した場合にのみ表示されます。通常の読み取りには解除すべきポリシーがない場合もあります。 + +## Observeモード + +`enforce` がデフォルトです。Jevが何も決定を変えずに動作を観察したい場合は `observe` に切り替えてください。Jevは引き続き問い合わせられ、判定は記録されますが、適用されるのは正規表現の結果です。 + +```bash +failproofai jev setup --mode observe +failproofai jev setup --mode enforce +failproofai jev setup --mode off +``` + +`off` はconfig(エンドポイントとキー)を維持したままJevへの問い合わせを停止します。フックはconfigなしの場合とまったく同じように正規表現ポリシーを実行し、`failproofai jev status` は「off (switched off)」と表示します。`--mode observe` または `--mode enforce` で元に戻せます。 + +同じプロバイダーで `setup` を再実行すると、保存済みのキーが維持されるため、モードの切り替えはフラグ1つで完了します。プロバイダーを切り替えると最初からやり直しになり、新しいプロバイダーのキーが必要です。リクエストを別のホストに移動する `--base-url` の場合も同様です。保存済みのキーは、それが指定されたホスト、またはそのプロバイダー自身のAPIにのみ送信されます。 + +## Configファイル + +すべての設定は `~/.failproofai/jev.json` という1つのファイルに保存され、`setup` によって書き込まれます。 + +```json +{ + "provider": "cloudflare", + "apiKey": "", + "accountId": "<32-hex-account-id>", + "mode": "enforce", + "timeoutMs": 3000 +} +``` + +| フィールド | 意味 | +| --- | --- | +| `provider` | `typesafe`、`openrouter`、`vercel`、`cloudflare`、`custom`、または `failproofai`(キーはこのファイルではなくFailproofAI Cloud接続から取得。[FailproofAI Cloud経由のJev](/ja/reference/jev-cloud)を参照)。 | +| `apiKey` | `Authorization: Bearer ` として送信されます。 | +| `baseUrl` | `custom` の場合は必須。それ以外の場合はプロバイダーのAPIベースを置き換えます。`https` が必要です。`localhost` への平文 `http` は `mode: observe` の場合にのみ受け付けられます。ローカルポートは認証されないため、プロキシが停止している間は、エージェント自身を含むマシン上の任意のプロセスが代わりに応答する可能性があります。 | +| `accountId` | Cloudflareのみ:32文字の小文字16進数。 | +| `model` | プロバイダーのデフォルトモデルIDを置き換えます。バージョン付きIDはJev 1.13を指定する必要があります。APIキーのような形式の値は拒否されます(繰り返し表示もされません)。そのため、`--model` にキーを貼り付けてもモデルとして保存・送信されることはありません。 | +| `timeoutMs` | 正規表現の結果にフォールバックするまでにツール呼び出しがJevを待つ時間。100〜10000、デフォルトは3000。 | +| `mode` | `enforce`(デフォルト)、`observe`、または `off`(configを維持しJevを実行しない)。 | + +これを保護するための3つのルールがあります。 + +- **オーナーのみ。** パーミッション `0600` で書き込まれます。他のユーザーやグループが読み書きできるコピーは**拒否**され、フックは `chmod 600 ~/.failproofai/jev.json` または再度 `setup` を実行するまで正規表現にフォールバックします。ディレクトリも確認されます。`~/.failproofai` は他のユーザーが**書き込み可能**であってはなりません。書き込みできる人はファイル自体のパーミッションに関係なくファイルを置き換えられるからです。`setup` はそのような書き込みビットを見つけた場合に削除します。`failproofai jev status` はconfigが拒否された場合にその旨と、ファイルが指定しているエンドポイントを表示します。他の誰かがファイルを変更した可能性があるため、`chmod` する前に自分のファイルであることを確認してください。そのようなファイルで `setup` を再実行すると、保存されたキーはプロバイダー自身のAPIにのみ使用されます。それ以外のエンドポイントが指定されている場合は、再度キーが必要です(`--key-stdin`)。または `--base-url default` でリクエストをプロバイダーに戻せます。 +- **グローバルのみ。** リポジトリはJevをオンにしたり、別のエンドポイントに向けたり、モデルを選択したりできません。プロジェクト内の `.failproofai/jev.json` は無視され、プロバイダー、URL、モデル、アカウントIDはそのファイルからのみ読み取られます。リポジトリのエージェント設定が設定できる環境変数からは読み取られません。(`FAILPROOFAI_HOME` はこれを回避する方法ではありません。Jevだけをリダイレクトするのではなく、ポリシーを含むfailproofaiディレクトリ全体を移動します。) +- **キーのみ環境変数から取得できます。** ファイルに `apiKey` がない場合、`FAILPROOFAI_JEV_API_KEY` がそのセッションに使用されます(`setup --key-from-env` はそのようなファイルを書き込みます)。ファイルが保持するキーを置き換えることはなく、ファイルなしでJevをオンにすることもできません。変数が設定されていない場合、そのシェルではJevはオフになります。`failproofai jev status` はその旨を表示し、終了コード0で終了し、configはそのままです(`status --json` は `"status": "key-missing"` と `"reason": "no-env-key"` を報告します)。`failproofaid` デーモンはシェルの環境を参照しないため、`failproofai config` で設定されたマシンではキーをファイルに保持してください。 + +## どのJevが回答するか + +Failproof AIの判定しきい値はJev 1.13でキャリブレーションされているため、そのファミリーからの回答(`jev-1.13.x`、またはOpenRouterの `typesafe/jev-1.13-`)の場合のみ使用されます。プロバイダーがJevをエイリアスのみで識別し、バージョンを報告しない場合(Vercel、およびCloudflareが報告しない場合)、回答は使用され、未検証として記録されます。`custom` エンドポイントは回答したモデルを報告する必要があります。唯一の例外は、設定した未バージョンの `--model` 名がエコーバックされる場合で、これは同様に未検証として記録されます。他のバージョンを報告する回答、または `custom` 回答でモデルが報告されない場合は使用されません。そのツール呼び出しは `model-mismatch` という理由で正規表現にフォールバックします。 + +## Jevが回答できない場合 + +以下のいずれかが発生すると、そのツール呼び出しの正規表現結果にフォールバックし、その理由とともに記録されます。`failproofai jev status` はその合計を表示します。 + +| 理由 | 原因 | +| --- | --- | +| `timeout` | `timeoutMs` 以内に回答がない。 | +| `http-429` | プロバイダーがキーをレート制限した。 | +| `rate-limited` | Failproof AI自身のリミッターが、送信前にツール呼び出しを保留した。毎秒5リクエスト、バースト最大5件、プロバイダーが `429` を返した直後は一時停止。プロバイダーではありません。 | +| `http-500`、`http-502`、`http-503`、… | プロバイダーのサーバーエラー。正確なステータスが記録されます。 | +| `out-of-credits` | HTTP 402:プロバイダーアカウントのクレジットが残っていない。 | +| `provider-refused` | CloudflareからのHTTP 402で「Model execution failed (Payment error)」:プロバイダーがこのリクエストでモデルの実行を拒否した。通常は課金の問題ではないため、チャージしても解決しません。 | +| `http-401`、`http-403` | キーが拒否された。 | +| `http-404` | `/systemone` に何も提供されていないため、ベースURLが誤っています。`/systemone` はベースURLに追加され、すべてのプロバイダーはそのバージョンルートで提供しています。`failproofai jev models` でエンドポイントが何を提供しているかを確認できます。 | +| `network` | エンドポイントに到達できなかった。 | +| `http-301`、`http-302`、`http-307`、`http-308` | エンドポイントがリダイレクトで応答した。リダイレクトは決してたどられないため、回答は常にconfigのURLからのみ来ます。`--base-url` を最終URLに設定してください。 | +| `malformed` | エンドポイントは応答したが、Jevの回答形式ではない。JSONでないボディ、または回答を含まないボディ。 | +| `cloudflare-error`、`cloudflare-incomplete` | Cloudflareのエンベロープが失敗を報告した、または未完了のジョブ。 | +| `model-mismatch` | 1.13以外のJevバージョンが回答した、または `custom` エンドポイントがどのモデルが回答したかを報告しなかった。 | +| `request-cut` | **障害ではありません。** Jevは回答しましたが、ツール呼び出しの一部しか表示されなかったため、解除は行われませんでした。[Jevが回答したが、ツール呼び出し全体に対してではなかった場合](#when-jev-answered-but-not-on-the-whole-call)を参照してください。 | + +`failproofai jev status` は `upstream-error`(回答にプロバイダー自身のエラーが含まれていた)や `config` などのまれな理由も表示することがあり、認識できない理由の合計は `other` として表示されます。 + +`request-cut` はこのテーブルに含まれています。`failproofai jev status` が他の理由とともに合計するためです。また、すべてのdenyを維持するという点でも同様です。ただし、これはプロバイダーに関して何も示しません。リクエストは届き、Jevは回答しています。上記のすべての行とは異なり、その回答は依然としてカウントされます。Jev自身のdenyまたは警告は、正規表現の結果に加えて適用され、破棄されません。したがって、これが続く場合は、エンドポイントに問題があるのではなく、ツール呼び出しが全体を送信するには大きすぎる状態で評価器に届いています。クレジットを追加したりURLを変更しても数値は変わりません。 + +## Jevが回答したが、ツール呼び出し全体に対してではなかった場合 + +さらに2つのことが起こる可能性があり、どちらもJevが回答できなかったわけではありません。いずれも、ツール呼び出しの全体、または会話がどれだけ1つのリクエストに収まったかに関するものです。 + +**ツール呼び出し自体の一部が収まらなかった。** ツール呼び出しは固定のバジェット内で送信されます。非常に大きな `Write`、巨大なMCPボディ、上限までパディングされたコマンドなど、大きすぎるものは収まった部分だけで送信されます。Jevは引き続き回答し、その回答は引き続きカウントされます。Jevの独自のdenyや警告は通常どおり適用されます。できないのは**解除**です。ツール呼び出しの一部に対して与えられた判定は、そのツール呼び出しに対する判定ではないからです。したがって、すべてのポリシーdenyは維持され、ツール呼び出しは `request-cut` という理由でフォールバックとして記録されます。`failproofai jev status` は上記の理由とともにこれを合計します。このルールが意味すること:ツール呼び出しを大きくすると解除が失われる可能性があり、解除を得ることは決してできません。 + +**メッセージが収まらなかった。** 貼り付けた長いプロンプト、エージェントの最後のメッセージ、またはこの評価器自身のストアがすでに上限を超えていたプロンプト。**何も変わりません**:ツール呼び出しは他のものとまったく同様に判定、解除、記録され、フォールバックとしてカウントされません。入力した内容の長さは判定を決定しません。また、カットによって同意が生み出されることはありません。プロンプトがすでに上限を超えた状態で届いた場合、「あなたはこれを要求しなかった」という結論はまったく引き出せなくなります。 + +2つの違いは誰がそのテキストを書いたかです。ツール呼び出しはエージェントのものであり、その長さが深刻さを減らせるようなルールはエージェントが悪用できるルールです。あなたのプロンプトはあなたのものであり、その長さをシグナルとして扱うことは、仕様やスタックトレースを貼り付けることへのペナルティにしかなりません。 + +## マシンから送信される情報 + +Jevが評価する各ツール呼び出しについて、プロバイダーに1つのリクエストが送信されます。内容は以下のとおりです。 + +- ツール呼び出し自体(APIキー、Bearerトークン、`KEY=` の代入などのシークレットは編集済み) +- 入力した最近のプロンプト(エージェントのハーネスが追加したテキストは除去済み) +- 最新のプロンプトの前のエージェントの最後のメッセージ(エージェントが書いたものとしてラベル付け) +- ローカルで計算された事実(パスがプロジェクト内かどうかなど。プロジェクトとは最初にレビューされたツール呼び出し時のセッションにあったもので、[セッション中固定されます](/ja/reference/jev-intent#the-project-root))および現在のgitブランチ + +これはconfigのエンドポイントにのみ、あなたのキーのもとで送信されます。 + +## オフにする + +```bash +failproofai jev remove +``` + +これにより `~/.failproofai/jev.json` が削除されます。次のツール呼び出しから、フックは以前と同様に正規表現ポリシーのみで実行されます。`~/.failproofai/state/semantic/` 配下のセッションごとのストア(`sessions/` の記録済みプロンプトと `roots/` のプロジェクトルート)はそのまま残り、自然に期限切れになります。Jevへの問い合わせを停止しながらconfigを維持したい場合は、代わりに `failproofai jev setup --mode off` を使用してください。 + +## コマンドリファレンス + +| コマンド | 内容 | +| --- | --- | +| `failproofai jev --url --key-stdin` | 1つのコマンドで設定。プロバイダーはURLのホストから決定される | +| `failproofai jev --url --token ` | 同上。キーはコマンドラインに置かれ、履歴とプロセスリストに残る | +| `failproofai jev setup --provider --key-stdin` | stdinからパイプされたキーでconfigを書き込む | +| `failproofai jev setup --provider ` | 同上。マスクされたプロンプトでキーを入力 | +| `failproofai jev setup --key-from-env` | キーを保存せず、セッションごとに `FAILPROOFAI_JEV_API_KEY` を読み取る | +| `failproofai jev setup --mode observe` | モードを切り替える(`enforce`、`observe`、または `off`)。保存済みキーは維持 | +| `failproofai jev setup --model ` / `--base-url ` | モデルまたはAPIベースをオーバーライド。`default` でオーバーライドを解除 | +| `failproofai jev setup --timeout-ms ` | ツール呼び出しごとのバジェットを変更 | +| `failproofai jev status [--json]` | 設定、パーミッション、最近のアクティビティを表示。キーは表示しない | +| `failproofai jev test [--json]` | 1回のライブリクエスト:レイテンシと回答したバージョン | +| `failproofai jev models [--provider ] [--url ] [--json]` | エンドポイントの `/models` が報告するモデルIDの一覧。設定済みのものをマーク | +| `failproofai jev remove` | configを削除。Jevはオフになる | \ No newline at end of file diff --git a/docs/ja/reference/jev.mdx b/docs/ja/reference/jev.mdx new file mode 100644 index 000000000..6a7d561f2 --- /dev/null +++ b/docs/ja/reference/jev.mdx @@ -0,0 +1,22 @@ +--- +title: "Jev 統合リファレンス" +description: "Jev の設定、プロバイダー、キー、リクエストデータ、および失敗時の動作について。" +icon: "braces" +--- + +Jev は Failproof AI において2つの用途があります。 + +| 用途 | 実行タイミング | 返却内容 | 開始ページ | +| --- | --- | --- | --- | +| セッション評価 | セッション終了後 | 固定回答式の質問に対するスコア | [Jev 評価](/ja/evaluations/jev) | +| ツールコールポリシーレビュー | ゲート付きツールコールの実行前 | インストール済みポリシーとともに返される判定結果 | [Jev ポリシー](/ja/policies/jev) | + +## リファレンスページ + +| トピック | 詳細 | +| --- | --- | +| [評価の質問](/ja/reference/jev-evaluations) | Boolean および順序スコア基準、結果、制限、バックフィル。 | +| [プロバイダー比較と独自キーの設定](/ja/reference/jev-providers) | TypeSafe、OpenRouter、Vercel、Cloudflare、カスタムエンドポイント、URL 推論、モデル ID、`jev.json`、モード、フォールバックコード。 | +| [FailproofAI Cloud ルート](/ja/reference/jev-cloud) | マシンキーの権限、自動 observe セットアップ、使用制限、接続状態、データ処理。 | + +ローカル CLI コマンドについては [Failproof AI CLI リファレンス](/ja/reference/failproof-cli) を参照してください。[ローカルダッシュボードリファレンス](/ja/reference/local-dashboard#set-up-jev) には、Jev の設定とアクティビティビューが記載されています。 \ No newline at end of file diff --git a/docs/ja/sessions/sentiment.mdx b/docs/ja/sessions/sentiment.mdx new file mode 100644 index 000000000..e4eff30a5 --- /dev/null +++ b/docs/ja/sessions/sentiment.mdx @@ -0,0 +1,43 @@ +--- +title: "センチメント分析" +description: "Jevのセンチメントスコアで、不満・混乱・訂正を含むメッセージを見つけます。" +icon: "smile" +--- + +Jevは、エージェントに送られた各メッセージを、4つの感情(**怒り**、**不満**、**喜び**、**混乱**)と、エージェントのパフォーマンスに関する3つのシグナルについて0〜100でスコアリングします。 + +- **Correcting**:ユーザーがエージェントの誤りを指摘している。 +- **Resolved**:ユーザーがエージェントによる問題解決を確認している。 +- **Doubtful**:ユーザーがエージェントの回答の正確性や作業の実施を疑問視している。 + +センチメント分析を活用することで、ユーザーが忍耐を失っている会話、繰り返し修正が入っているエージェント、好評を得ている返答を見つけることができます。これはJev組み込みのスコアリング機能であり、エバリュエーションを作成する必要はありません。独自の固定回答質問に対しては、[Jevエバリュエーションを作成](/ja/evaluations/jev)してください。 + + + センチメント機能は、管理者が組織向けに有効化するまでオフになっています。Jevはメッセージごとに1件のスコアリングリクエストを行い、エージェントの返信が付いた状態でそのメッセージを受け取ります。スコアリングには組織のモデルバジェットが使用されます。 + + +## 有効にする方法 + +1. **Administration → Settings** に移動します。 +2. **Human input sentiment** の項目で **on** に切り替え、保存します。 + +直近1日分のメッセージが最初にスコアリングされます。その後、新しいメッセージは到着から1〜2分以内にスコアリングされます。 + +## 確認する会話を見つける + +**Observe → Sentiment** を開きます。期間、環境、エージェント、セッションIDでフィルタリングできます。ヘッダーにはメッセージ数とセッション数が表示され、**フラグ付き**メッセージの数と上位シグナルが確認できます。怒り、不満、訂正、混乱、または疑念のスコアが100点中35点に達すると、そのメッセージにフラグが付きます。 + +![メッセージ数・セッション数・フラグ付きメッセージ・Jevスコアの推移を表示するセンチメントダッシュボード](/images/dashboard/sentiment-overview.png) + +**Score over time** を使用してシグナルを比較できます。表示するスコアを選択し、ポイントをクリックするとその時間帯のメッセージを確認できます。**By agent** テーブルでは、特定のシグナルが集中しているエージェントが分かります。**Messages** では、最も強いネガティブスコア順に並べ替えたり、特定のスコアで絞り込んだりできます。メッセージをクリックしてセッション内で開くと、問題の原因を判断する前に周辺の会話を読むことができます。 + +![最も強いネガティブスコア順に並べられたセンチメントメッセージ一覧。各メッセージからソースセッションへのリンク付き。](/images/dashboard/sentiment-messages.png) + +## スコアリング対象のメッセージ + +人間が書いたメッセージのみが対象です。 + +- SDKを使用してヒューマンインプットとして記録された、カスタムエージェント宛のメッセージ。 +- セッションのトランスクリプトが送信される場合(デフォルト)に、Claude Code、Codex、OpenCode、pi、Hermes、OpenClawに入力されたプロンプト。スケジュール済みジョブ、注入された指示、サブエージェントへのハンドオフ、その他エージェント自身のランタイムが書いたテキストはスコアリングされません。また、`claude -p`、`codex exec`、`hermes -z` などの非インタラクティブな実行も対象外です。これらのプロンプトはスクリプトによって書かれたものであり、人間によるものではないためです。 + +スコアリングはユーザー自身の言葉を判断します。「fix it」のような短く端的な指示は怒りとはみなされず、質問することは混乱とはみなされません。新しいリクエストは訂正ではなく、単なる感謝の言葉だけでは解決済みとはみなされません。 \ No newline at end of file diff --git a/docs/ja/start/use-jev.mdx b/docs/ja/start/use-jev.mdx new file mode 100644 index 000000000..45280cbe4 --- /dev/null +++ b/docs/ja/start/use-jev.mdx @@ -0,0 +1,63 @@ +--- +title: "Jev を使用する" +description: "完了したセッションに対する Jev 評価、またはライブのツール呼び出しレビューのための Jev ポリシーをセットアップします。" +icon: "sparkles" +--- + +Jev はエージェント実行の 2 つのタイミングでサポートします。完了したセッションを既知の回答に基づいてスコアリングするか、エージェントへの指示のコンテキストを踏まえてツール呼び出しをレビューします。 + + + + 「顧客は返金を求めましたか?はいかいいえで答えてください。」のように、いくつかの既知の回答を持つ質問に対して完了したセッションをスコアリングできる場合に Jev eval を使用します。セッション全体のパターンを発見するのに役立ちます。 + + ## eval を作成する + + Cloud ダッシュボードで **Analyze → eval authoring → new eval** を開きます。固定回答の質問を 1 つ入力し、**draft** を選択して、分類スコアが選ばれていることを確認します。実際のセッションで[テスト](/ja/evaluations/test)した後、デプロイします。 + + ![質問を説明し、ドラフトを確認してデプロイする共有 eval 作成フォーム。このスクリーンショットにはコードのドラフトが表示されていますが、Jev には固定回答の質問を使用してください。](/images/dashboard/eval-authoring-draft.png) + + ## スコアを確認する + + 新しいセッションが完了したら、**Observe → Evaluations** を開くか、Cloud CLI を使用します。 + + ```bash + fp evals --since 7d + fp evals --aggregate --since 7d + ``` + + CLI はスコアを読み取ります。Jev eval の作成は現在ダッシュボードで行います。質問タイプと例については [Jev evaluations](/ja/evaluations/jev) を参照してください。 + + + ツール呼び出しの安全性を判断するためにリクエストのコンテキストが必要な文字列マッチングポリシーには、Jev ポリシーレビューを使用します。まず **observe** モードで開始し、インストール済みのポリシーが各呼び出しを判断する間に Jev の回答を確認できるようにします。 + + Jev のチェックはパックから提供されます。Failproof AI はパックを同梱していません。インストールするまで、Jev は設定されていても何も問い合わせません。 + + ```bash + failproofai policies add FailproofAI/jev-policies + ``` + + ## Cloud Jev をセットアップする + + Cloud ダッシュボードで **Administration → Keys** を開き、**machine** プリセットでキーを作成します。[クイックスタート](/ja/start/quickstart) に示されているように、`failproofai config` でそのキーを使用します。既存の Jev 設定がないマシンでは、observe モードで Cloud Jev が有効になります。以下のコマンドで接続を確認してください。 + + ```bash + failproofai jev status + failproofai jev test + ``` + + ## 独自のエンドポイントを使用する + + ローカルダッシュボードで **Settings → Jev** を開きます。プロバイダーを選択し、トークンを貼り付け、**observe** を選択して Jev をオンにします。 + + ![プロバイダー、トークンフィールド、および observe モードが選択されたローカル Jev 設定パネル。](/images/dashboard/jev-settings.png) + + または、ターミナルからエンドポイントを設定してテストします。 + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key + failproofai jev test + ``` + + フックされたエージェントに `README.md` のファイル読み取りツールを使用するよう指示します。そのツール呼び出しがセッションに表示されていることを確認し、ローカルダッシュボードの **Policies → Activity** で詳細を確認します。observe の結果が正しく見えたら、[Jev policies](/ja/policies/jev) でいつ適用するかを確認してください。プロバイダーの詳細と設定については、[integration reference](/ja/reference/jev) を参照してください。 + + \ No newline at end of file diff --git a/docs/ko/evaluations/jev.mdx b/docs/ko/evaluations/jev.mdx new file mode 100644 index 000000000..5609aab5a --- /dev/null +++ b/docs/ko/evaluations/jev.mdx @@ -0,0 +1,28 @@ +--- +title: "Jev 평가" +description: "Jev를 사용하여 완료된 세션을 알려진 답변이 있는 질문으로 채점합니다." +icon: "list-checks" +--- + +Jev 평가는 **완료된 세션**을 읽고 0에서 1 사이의 점수를 부여합니다. "고객이 긴급함을 표현했는가?" 또는 "고객이 얼마나 불만스러워했는가?"와 같이 답변이 사전에 알려진 경우에 사용하세요. 여러 실행에서 패턴을 찾는 데 도움이 되며, 도구 호출을 중단하지는 않습니다. 도구가 실행되기 **전에** 내리는 결정에는 [Jev 정책](/ko/policies/jev)을 사용하세요. + +## 대시보드에서 생성하기 + +1. **Analyze → eval authoring**을 열고 **new eval**을 선택합니다. +2. 질문 하나와 가능한 답변들을 설명합니다. 예: "에이전트가 환불 정책을 확인하기 전에 환불을 약속했는가? 예 또는 아니오로 답하세요." **draft**를 선택하고 결과가 분류기 점수인지 확인합니다. +3. 최근 세션에서 [테스트](/ko/evaluations/test)한 후 [배포](/ko/evaluations/deploy)합니다. 새로 완료된 세션이 채점되며, 이전 기록도 필요하다면 [백필](/ko/evaluations/deploy#score-sessions-you-already-have)을 사용하세요. + +![고정 답변 질문을 설명하고, 초안을 검토하며, 테스트 후 배포하는 공유 eval 작성 폼. 예시는 코드 평가이며, Jev 질문도 동일한 작성 흐름을 사용합니다.](/images/dashboard/eval-authoring-draft.png) + +어시스턴트는 코드, Jev 분류, [judge](/ko/evaluations/judge) 중 하나를 선택할 수 있습니다. 배포 전에 선택 사항을 확인하세요. Jev는 산문 형태의 추론 없이 점수를 제공합니다. 설명이 필요한 경우에는 judge를 선택하세요. 질문 유형 및 점수 한도에 대한 자세한 내용은 [Jev 평가 참조](/ko/reference/jev-evaluations)를 확인하세요. + +## 점수 확인하기 + +**Observe → Evaluations**를 열면 에이전트별, 시간별로 결과를 차트로 확인할 수 있습니다. 터미널에서는 Cloud CLI로 동일한 결과를 조회할 수 있습니다: + +```bash +fp evals --since 7d +fp evals --aggregate --since 7d +``` + +Cloud CLI는 결과를 읽는 데 사용하며, 작성 및 배포는 대시보드에서 진행됩니다. 필터에 대한 자세한 내용은 [Cloud CLI 참조](/ko/reference/cloud-cli#evaluations)를 확인하세요. \ No newline at end of file diff --git a/docs/ko/evaluations/judge.mdx b/docs/ko/evaluations/judge.mdx new file mode 100644 index 000000000..c4235f646 --- /dev/null +++ b/docs/ko/evaluations/judge.mdx @@ -0,0 +1,91 @@ +--- +title: "LLM 심사 모델" +description: "정확성, 어조, 에이전트가 정책을 준수했는지 여부 등 코드로는 측정할 수 없는 항목을 세션에 대해 평가합니다 — 어떤 것이 좋은지를 설명하면 모델이 대화를 읽고 점수를 반환합니다." +icon: "scale" +--- + +호스팅된 Python 평가는 계산하고 비교할 수 있습니다: 도구 호출 횟수, 오류 수, 세션 소요 시간 등. 하지만 답변이 *정확한지*, 응답이 무례한지, 에이전트가 행동하기 전에 정책을 확인했는지는 알 수 없습니다. + +**LLM 심사 모델**은 이를 판단할 수 있습니다. 어떤 것이 좋은지를 자연어로 설명하면, 모델이 세션을 읽고 0에서 1 사이의 점수와 함께 그 이유를 반환합니다. + + +심사 모델은 실행하는 세션마다 모델 호출이 한 번씩 발생하며, 코드 평가는 비용이 들지 않습니다. 대화를 *이해*해야만 답할 수 있는 질문에만 심사 모델을 사용하고, 실제로 관련된 세션에만 실행되도록 조건을 설정하세요. + + +## 어떤 것을 선택해야 할까요? + +| 질문 | 사용 방법 | +| --- | --- | +| 동일한 도구를 두 번 호출했나요? | 코드 | +| 오류가 몇 번 발생했나요? | 코드 | +| 세션이 30초 이내였나요? | 코드 | +| 고객이 긴박함을 표현했나요? | [분류기](/ko/evaluations/jev) | +| 고객이 얼마나 불만족스러워했나요? | [분류기](/ko/evaluations/jev) | +| 답변이 실제로 정확했나요? | **심사 모델** | +| 응답이 무례하거나 냉담했나요? | **심사 모델** | +| 환불을 약속하기 전에 환불 정책을 확인했나요? | **심사 모델** | + +경험칙: **셀 수 있는 것 → 코드, 미리 목록화할 수 있는 답변 → [분류기](/ko/evaluations/jev), 설명이 필요한 것 → 심사 모델.** 심사 모델은 관찰한 내용을 서술형으로 작성하는 유형입니다. 숫자만으로는 "왜?"라는 질문이 뒤따를 것 같을 때 사용하세요. + +미리 결정할 필요는 없습니다. 무엇을 측정하고 싶은지 설명하면 어시스턴트가 선택하고, 어떤 것을 선택했는지와 그 이유를 알려줍니다. 이후에 변경할 수도 있습니다. + +## 작성 방법 + +1. **Analyze → eval authoring**으로 이동하여 **new eval**을 선택합니다. +2. 판단하고자 하는 내용을 설명하고 **draft**를 선택합니다. +3. **criteria**, **threshold**, **condition**을 검토한 후 배포합니다. + +### Criteria + +질문이 아닌 요구사항으로 작성된 한두 문장: + +> 에이전트는 환불 정책을 먼저 확인하지 않고 환불을 약속하거나 승인해서는 안 됩니다. + +어떤 경우에 *실패*로 볼 것인지 구체적으로 명시하세요. "응답이 좋았나요?"는 아무 의미 없는 숫자를 줄 뿐이지만, 위 문장은 실제로 행동할 수 있는 결과를 제공합니다. + +### Threshold + +세션이 통과하는 기준이 되는 점수입니다. `0.7`이 적절한 출발점입니다. 0~1 전체 점수는 항상 저장되므로 threshold는 합격/불합격만 결정합니다 — 분포를 확인하고 조정할 수 있습니다. + +### Condition + +다른 평가와 동일한 Python 조건이며, 여기서는 훨씬 더 중요합니다. 조건 없이는 심사 모델이 조직 내 **모든** 세션에서 실행되어, 각 세션마다 모델 호출이 발생합니다: + +```python +session.count("tool_use") > 0 +``` + +```python +session.agent_id == "support-bot" and session.count("error") > 0 +``` + +조건 없이 심사 모델을 배포하려 하면 대시보드에서 경고를 표시합니다. 완전히 판단하고 싶은 소량 에이전트의 경우에는 그래도 괜찮지만, 실수가 아닌 의도적인 결정이어야 합니다. + +## 심사 모델이 보는 내용 + +대화 내용을 턴 단위로 제공하며, 세션이 긴 경우 최신 순으로 정렬됩니다: + +- 사용자가 말한 내용 +- 어시스턴트의 응답 +- **에이전트가 호출한 모든 도구와 그 반환값 (순서대로)** + +마지막 항목 덕분에 "X를 하기 *전에* Y를 했나요?"라는 질문도 공정하게 판단할 수 있습니다. 실패한 도구 호출은 실패로 표시되므로 "오류에서 적절히 복구했나요?"도 판단 가능합니다. + +세션이 매우 길면 모델의 컨텍스트에 맞게 잘립니다. 이 경우 추론 내용에 명시적으로 표시됩니다 — 일부 세션에 대한 판단이 전체를 본 것처럼 제시되는 일은 결코 없습니다. + +## 결과 읽기 + +심사 모델은 다른 점수 기반 평가와 마찬가지로 **score**를 생성하므로, 동일한 방식으로 차트화, 필터링, 알림 트리거가 가능합니다. 숫자와 함께 심사 모델의 **reasoning** — 관찰한 내용을 설명하는 단락 — 도 저장됩니다. 점수가 예상과 다를 때는 먼저 그것을 읽어보세요. 대개 실제로 흥미로운 세션이거나 criteria를 더 다듬어야 한다는 신호입니다. + +명확한 사례에서는 점수가 안정적이지만 비트 단위로 결정론적이지는 않습니다. 경계선상의 단일 점수는 확정적 판정이 아닌, 해당 세션을 직접 읽어보라는 신호로 받아들이세요. + +## 제한 사항 + +- **테스트 기능은 아직 제공되지 않습니다.** 시험 실행에는 세션 할당이 없고, 모델 예산 사용을 승인하는 것이 바로 그 할당이기 때문에 테스트 호출에 청구할 대상이 없습니다. 좁은 조건으로 배포하고 첫 번째 결과 몇 개를 읽어보세요. +- **백필(Backfill)은 지원되지 않습니다.** 코드 평가를 수개월치 히스토리에 백필하는 것은 무료지만, 심사 모델로 하면 예산 전체가 순식간에 소진됩니다. +- **criteria를 수정하면 새 버전이 게시됩니다.** 이전 점수와 새 점수는 비교할 수 없으므로, 하나의 추세선으로 섞이지 않고 별도로 유지됩니다. +- **심사 모델은 항상 score를 생성하며**, metric이나 assertion은 생성하지 않습니다. + +## 예산이 소진되었을 때 + +심사 모델은 조직의 모델 예산을 사용합니다. 예산이 소진되면, 심사 평가는 자동으로 실패하지 않고 명확한 이유와 함께 중단되며, **코드 평가는 정상적으로 계속 실행됩니다.** 예산을 증가시키면 다음 세션부터 재개됩니다. \ No newline at end of file diff --git a/docs/ko/policies/authority.mdx b/docs/ko/policies/authority.mdx new file mode 100644 index 000000000..41b66090a --- /dev/null +++ b/docs/ko/policies/authority.mdx @@ -0,0 +1,144 @@ +--- +title: "정책 권한" +description: "Jev 시맨틱 평가기가 승인할 수 있는 정책 판정과 최종 판정의 구분." +icon: "scale" +--- + +FailproofAI Cloud 또는 직접 키를 사용해 [Jev 정책 검토](/ko/policies/jev)를 구성하면, 각 게이트된 도구 호출은 실행 중인 정책과 Jev 양쪽의 판단을 받습니다. Jev는 해당 호출이 실제로 무엇을 하는지, 그리고 작업을 입력한 사람이 그것을 요청했는지 확인합니다. 두 판단이 불일치할 때 정책의 **권한**이 결과를 결정합니다. + +Jev가 구성되어 있지 않으면 권한은 아무런 효과가 없습니다. 모든 정책은 기존 방식 그대로 적용됩니다. + +## Hard와 Reviewable + +- **Hard**가 기본값입니다. hard 정책의 deny 또는 instruction은 최종입니다. Jev가 이를 승인할 수 없으며, hard deny는 Jev를 기다리지 않고 호출을 즉시 차단합니다. +- **Reviewable**은 Jev가 정책 판정을 승인할 수 있음을 의미하지만, 정책이 `reviewedBy`에 명시한 시맨틱 검사를 통해서만 가능합니다. **모든** 명시된 검사가 해당 호출에 대해 질의되고, 각각이 아무것도 발견하지 못했거나 사용자가 이를 요청했다고 기록한 경우에만 판정이 승인됩니다. 우려 사항을 **발견한** 검사 — 사용자의 요청 없이 발화된 경우 — 는 자체 판정이 경고에 불과하더라도 차단을 유지합니다. 해당 도구에 적용되지 않아 Jev가 질의받지 않은 검사는 다른 검사 결과와 무관하게 아무것도 승인하지 않습니다. 완화 조치 하나가 동의로 간주됩니다. 호출이 사용자가 제시한 작업의 한 단계이고 그 범위를 벗어나지 않으면, Jev는 deny를 경고로 전환하고, 해당 경고가 정책의 차단을 승인하며 에이전트에게 전달됩니다. + +다음 조건이 모두 충족될 때만 정책이 reviewable이 됩니다. + +1. `authority: "reviewable"`을 선언합니다. +2. `reviewedBy`가 비어 있지 않은 목록이며, 모든 항목이 설치된 팩이 선언한 Jev 검사입니다. Failproof AI는 Jev 검사를 제공하지 않습니다. [아래 열여섯 가지](#semantic-policy-names)는 `failproofai policies add FailproofAI/jev-policies`에서 제공됩니다. 검사를 선언하는 팩이 없으면 모든 정책은 hard가 됩니다. +3. `alwaysOn`이 아닙니다. Failproof AI를 비활성화하려는 에이전트를 막는 가드는 항상 hard입니다. + +그 외는 모두 hard입니다. 누락된 필드, 잘못 입력된 값, 비어 있거나 잘못된 형식의 `reviewedBy`, 또는 이 머신이 질의할 수 없는 검사 이름이 포함된 경우가 해당됩니다. 알 수 없는 이름은 건너뛰지 않고 전체 선언을 hard로 만듭니다. `reviewedBy`는 "이 모든 항목을 질의해야 하며, 어느 것도 거부해서는 안 된다"를 의미하므로, 이름을 건너뛰면 요청보다 적은 검사로 Jev가 정책을 승인할 수 있게 됩니다. + +Jev가 구성된 후 Failproof AI는 `reviewable` 선언을 거부할 때 프로세스당 한 번 경고를 기록합니다. Jev 없이는 아무것도 말하지 않습니다. 권한이 아무것도 결정하지 않기 때문입니다. `failproofai publish`는 그러한 선언을 포함하는 팩 빌드를 거부하므로, 팩 작성자는 누군가 설치하기 전에 문제를 파악할 수 있습니다. 선언된 검사가 있는 경우 팩이 선언한 검사들을 기준으로, 없는 경우 `FailproofAI/jev-policies`의 열여섯 가지 이름을 기준으로 `reviewedBy`를 검증합니다. + +## 권한이 선언되는 위치 + +정책이 머신에 도달하는 각 방식마다 권한을 결정하는 위치가 하나씩 있습니다. + +| 출처 | 선언 위치 | 기본값 | +| --- | --- | --- | +| 내장 정책 | 아래 표 | reviewable로 나열되지 않는 한 hard | +| 직접 작성한 정책 파일 | `customPolicies.add`의 `authority` 및 `reviewedBy` | Hard | +| 정책 팩 | 팩 매니페스트(`failproofai-pack.json`)의 각 정책 항목 | Hard | +| 클라우드 관리 정책 | 활성 배포에서 정책의 할당 | Hard. 배포에서 아직 설정하지 않으므로, 현재 모든 클라우드 관리 정책은 hard입니다. | + +팩 또는 클라우드 관리 정책의 경우, 정책 코드 내부에 설정된 필드는 무시됩니다. 매니페스트 또는 할당이 결정합니다. 팩은 자신의 정책만 기술할 수 있습니다. 정책 이름에 `/`를 포함할 수 없고 팩 자신의 접두사 아래에 등록되므로, 어떤 매니페스트도 내장 정책이나 다른 팩의 정책을 reviewable로 표시할 수 없습니다. 팩 코드가 등록하지만 매니페스트에 선언하지 않은 정책은 hard입니다. + +바이트 단위로 동일한 코드를 가진 두 팩 또는 두 클라우드 관리 정책은 하나의 아티팩트를 공유하고 하나의 정책으로 로드됩니다. 해당 정책은 모두가 reviewable로 선언할 때만 reviewable이 되며, Jev는 그중 어느 것이 명시한 모든 검사를 승인해야 합니다. 하나라도 hard로 선언하거나 전혀 선언하지 않으면 hard로 유지됩니다. 팩이나 정책의 나열 순서는 절대 중요하지 않습니다. + +대부분의 머신은 `FailproofAI/policies` 팩에서 내장 정책을 가져오고, 해당 팩의 매니페스트에서 권한을 읽습니다. 아래의 reviewable 항목들은 해당 항목을 포함하는 팩 릴리스가 설치된 후 적용됩니다. 이전 릴리스에는 해당 항목이 없으므로 그 안의 모든 정책은 hard로 유지됩니다. + +## 직접 작성한 정책에서 권한 선언하기 + +```js +import { customPolicies, deny, allow } from "failproofai"; + +customPolicies.add({ + name: "block-prod-config-reads", + description: "Keep production credentials out of the agent's context", + match: { events: ["PreToolUse"] }, + authority: "reviewable", + reviewedBy: ["secret-exposure"], + fn: async (ctx) => + String(ctx.toolInput?.file_path ?? "").includes("/config/prod/") + ? deny("Production config is off limits") + : allow(), +}); +``` + +`failproofai publish`는 두 필드 모두 팩 매니페스트에 복사하므로, 팩으로 게시된 정책은 작성자가 부여한 권한을 그대로 유지합니다. 선언이 적용될 수 없는 경우 팩 빌드를 거부합니다. `"hard"` 또는 `"reviewable"` 이외의 값, 이름 목록이 아닌 `reviewedBy`, 또는 검사가 아닌 이름 — 선언된 경우 팩 자신의 [Jev 검사](/ko/policies/publish-a-pack#jev-checks-in-a-pack) 중 하나, 그렇지 않으면 내장 검사 — 이 해당됩니다. + +## 내장 정책 + +시맨틱 정책이 동일한 우려 사항을 실질적으로 다루는 경우에만 reviewable입니다. 그 외 모든 내장 정책은 hard입니다. + +우려 사항을 다루는 것은 필요조건이지 충분조건이 아니며, 잘못될 수 있는 두 가지 방식 모두 조용히 발생합니다. + +- **질의되지 않은 검사**는 차단을 영구적으로 만듭니다. `reviewedBy`는 논리곱이며 질의되지 않은 검사는 절대 승인하지 않으므로, 해당 정책이 매칭하는 형태에 대해 전제 조건이 발화하지 않는 검사와 쌍을 이루는 정책은 절대 승인될 수 없습니다. +- **질의되었지만 발화하지 않은 검사**는 "우려 없음"으로 답하고, 우려 없음은 승인됩니다. 따라서 정책의 형태를 모델링하지 않는 검사와 쌍을 이루면 정책을 검토하는 게 아니라, 검사가 이해하지 못하는 입력에 대해 정확히 정책을 비활성화하게 됩니다. + +instruct 모드 시맨틱 정책은 deny로 답할 수 없지만, 차단을 유지할 수 있습니다. 발화하고 사용자가 호출을 요청하지 않은 경우 해당 정책은 승인되지 않습니다. `FailproofAI/jev-policies` 검사 중 여섯 개 — `push-to-protected-branch`, `commit-on-protected-branch`, `read-outside-workspace`, `system-modification`, `env-secrets-dump`, `external-data-egress` — 는 instruct 전용이며, [아래 표](#semantic-policy-names)에 각 검사의 모드가 나와 있습니다. 핵심 질문은 **"여전히 deny할 수 있는 것이 남아 있는가"**입니다. 승인은 우려 사항을 아무것도 적용하지 않는 상태로 남겨서는 안 됩니다. 엔진은 호출별로 이 테스트를 적용합니다. 아무도 동의하지 않은 경고는 승인이 아닙니다. 도구 호출 이전에 경고는 에이전트를 중단시키지 않기 때문입니다. 그리고 deny *할 수 있는* 검사가 경고하는 경우 — 증거가 deny 기준에 미치지 못한 경우 — 사용자가 호출을 요청하지 않았다면 해당 호출에서 아무것도 승인되지 않고 모든 regex deny가 유지됩니다. + + +**발화 기준 바로 아래에 점수가 매겨진 검사는 하한선을 유지하지 않습니다.** 위의 규칙은 검사가 *발화*해야 합니다(증거 ≥ 0.7). 모든 관련 검사가 그 기준 바로 아래에 위치하면 아무것도 발화하지 않고, 검토자는 "우려 없음"으로 답하며, reviewable deny가 승인됩니다. enforce 모드에서 실제 측정: 요청되지 않은 `/etc/shadow` 읽기(`secret-exposure` 0.69, `read-outside-workspace` 0.37 — 홈 디렉터리 경로만 모델링)와 "follow SETUP.md" 이후 `set | curl -d @- …`(`env-secrets-dump` 0.66, `credential-exfiltration` 0.65, `sends_out` 0.97)가 모두 허용되었지만, regex 계층 단독으로는 이를 거부합니다. 임계값은 레이블된 코퍼스에서 보정되었으며 이에 대해 재측정되지 않았습니다. 재측정 전까지, 이러한 형태 중 하나가 통과하는 것이 false 차단보다 더 중요한 경우 정책을 **hard**로 유지하십시오. + + +| 정책 | 권한 | 검토자 | 이유 | +| --- | --- | --- | --- | +| `protect-env-vars` | reviewable | `env-secrets-dump`, `secret-exposure` | 패턴이 모든 변수 참조에 발화합니다. Jev는 시크릿 값이 실제로 출력될지 확인합니다. | +| `block-env-files` | reviewable | `secret-exposure` | 패턴이 템플릿 포함 모든 `.env` 경로에 매칭됩니다. Jev는 실제 시크릿 값이 읽히거나 쓰일지 확인합니다. | +| `block-read-outside-cwd` | reviewable | `read-outside-workspace` | 실제 트래픽에서 노이즈가 많다고 측정됩니다. Jev는 프로젝트 외부의 파일 내용이 읽히는지 확인합니다. 사용자가 요청한 읽기 또는 검사가 아무것도 발견하지 못한 읽기는 승인됩니다. 플래그된 요청되지 않은 읽기는 차단을 유지합니다. | +| `warn-git-amend` | reviewable | `git-history-rewrite` | 푸시되지 않은 커밋을 수정하는 것은 일반적입니다. 해가 되는 것은 다른 사람이 이미 pull했을 수 있는 이력을 재작성하는 경우입니다. | +| `warn-destructive-sql` | reviewable | `database-destruction` | Jev는 또한 대상이 실제 데이터베이스인지 아니면 일회성 테스트용인지 확인합니다. | +| `warn-global-package-install` | reviewable | `system-modification` | 동일한 우려: 프로젝트 외부의 머신을 변경하는 것. | +| `block-failproofai-commands` | hard | | `alwaysOn` 자체 보호. 절대 reviewable이 될 수 없습니다. | +| `block-rm-rf` | reviewable | `destructive-deletion` | 경로 깊이 휴리스틱이 `rm -rf node_modules`를 잘못 판단합니다. Jev는 삭제될 내용이 재생성 가능한지 확인합니다. `rm -rf /`는 두 프로브 모두 참으로 유지됩니다. | +| `block-sudo` | hard | | 권한 상승. | +| `block-curl-pipe-sh` | hard | | 인터넷에서 다운로드된 코드를 실행합니다. | +| `block-push-master` | hard | | 보호된 브랜치에 직접 푸시합니다. | +| `block-work-on-main` | hard | | `commit-on-protected-branch`가 정확히 이 우려를 다루지만 instruct 모드여서 deny로 답할 수 없으며, 이를 다루는 다른 검사가 없습니다. | +| `block-force-push` | reviewable | `git-history-rewrite` | Jev의 프로브는 매처의 상위집합이며 `--force-with-lease`도 포함합니다. 승인되는 것은 자신의 브랜치에 force-push하는 경우입니다. | +| `block-secrets-write` | reviewable | `secret-exposure` | 경로 매치가 앵커되지 않아 `src/auth/credentials.ts`도 잡힙니다. Jev는 실제 키 자료가 작성되는지 확인합니다. | +| `block-kubectl` | reviewable | `production-infra-change` | 읽기 전용 하위 명령 포함 전체 CLI를 거부합니다. Jev는 호출이 변형을 수행하는지, 그리고 대상이 프로덕션인지 확인합니다. | +| `block-terraform` | reviewable | `production-infra-change` | 동일: `terraform plan`과 `validate`를 승인합니다. | +| `block-aws-cli` | reviewable | `production-infra-change` | 동일: `aws s3 ls`, `aws sts get-caller-identity`를 승인합니다. | +| `block-gcloud` | reviewable | `production-infra-change` | 동일: `gcloud auth list`, `gcloud config list`를 승인합니다. | +| `block-az-cli` | reviewable | `production-infra-change` | 동일: `az account show`를 승인합니다. | +| `block-helm` | reviewable | `production-infra-change` | 동일: `helm list`, `helm status`를 승인합니다. | +| `block-gh-pipeline` | hard | | 파이프라인, 병합 및 시크릿 변경을 트리거합니다. | +| `warn-git-stash-drop` | hard | | 스태시된 작업 폐기를 다루는 시맨틱 검사가 없습니다. | +| `warn-git-clean` | hard | | `destructive-deletion`이 우려를 다루지만 명백히 발화할 수 없습니다. `git clean`은 경로를 명시하지 않아 `irreplaceable` 프로브가 판단할 내용이 없고 낮은 값을 반환하며, 증거는 정책의 프로브 최솟값입니다. 질의되었지만 발화하지 않은 검사는 판정을 승인하므로, 여기서 쌍을 이루면 정책이 비활성화됩니다. | +| `warn-all-files-staged` | hard | | 광범위한 `git add`가 무엇을 선택하는지 다루는 시맨틱 검사가 없습니다. | +| `warn-schema-alteration` | hard | | `database-destruction`은 데이터 삭제를 다루지, 스키마 변경을 다루지 않습니다. | +| `warn-package-publish` | hard | | 게시는 되돌릴 수 없으며 이를 다루는 시맨틱 검사가 없습니다. | +| `prefer-package-manager` | hard | | 팀 규약이지 안전 판단이 아닙니다. | +| `warn-large-file-write` | hard | | 크기 임계값이지 Jev가 판단할 수 있는 것이 아닙니다. | +| `warn-background-process` | hard | | 분리된 프로세스를 다루는 시맨틱 검사가 없습니다. | +| `warn-repeated-tool-calls` | hard | | 호출을 셉니다. Jev는 셀 수 없습니다. | +| `sanitize-jwt` | hard | | 도구 출력을 편집합니다. 도구 호출 게이트가 아닙니다. | +| `sanitize-api-keys` | hard | | 도구 출력을 편집합니다. 도구 호출 게이트가 아닙니다. | +| `sanitize-connection-strings` | hard | | 도구 출력을 편집합니다. 도구 호출 게이트가 아닙니다. | +| `sanitize-private-key-content` | hard | | 도구 출력을 편집합니다. 도구 호출 게이트가 아닙니다. | +| `sanitize-bearer-tokens` | hard | | 도구 출력을 편집합니다. 도구 호출 게이트가 아닙니다. | +| `require-commit-before-stop` | hard | | 세션 완료 게이트이지 도구 호출 게이트가 아닙니다. | +| `require-push-before-stop` | hard | | 세션 완료 게이트이지 도구 호출 게이트가 아닙니다. | +| `require-pr-before-stop` | hard | | 세션 완료 게이트이지 도구 호출 게이트가 아닙니다. | +| `require-no-conflicts-before-stop` | hard | | 세션 완료 게이트이지 도구 호출 게이트가 아닙니다. | +| `require-ci-green-before-stop` | hard | | 세션 완료 게이트이지 도구 호출 게이트가 아닙니다. | + +## Semantic policy names + +이것들은 `FailproofAI/jev-policies`가 선언하는 검사이며, 설치 후 `reviewedBy`가 수락하는 값입니다. Failproof AI 자체는 이를 제공하지 않습니다. 해당 팩(또는 이 이름을 선언하는 다른 팩) 없이는 이를 명시하는 정책이 reviewable이 되지 않습니다. 각각은 Jev가 앞에 있는 도구 호출에 대해 답하는 검사입니다. **모드**는 검사가 답할 수 있는 내용입니다. `deny` 검사는 강력한 증거가 있을 때 차단하고, `instruct` 검사는 경고만 합니다. 어느 쪽이든 발화하고 사용자가 호출을 요청하지 않은 경우 정책의 deny를 유지합니다. **사용자 재정의 가능**은 사람의 명시적인 요청이 승인하는지 여부를 나타냅니다. + +Jev는 설치된 팩이 선언한 [Jev 검사](/ko/policies/publish-a-pack#jev-checks-in-a-pack)만 질의하며, 그것이 `reviewedBy`가 수락하는 이름입니다. 두 팩이 서로 다르게 선언한 이름은 어느 쪽도 적용되지 않습니다. FailproofAI 저장소에서 설치되지 않은 팩이 선언한 이 열여섯 이름 중 하나는 해당 팩에서 무시됩니다. 해당 버전은 절대 질의되지 않으며 FailproofAI 자체 버전과 경쟁하지 않으므로, 서드파티 팩은 코어 팩의 정책을 승인하는 검사가 되거나 이러한 검사 중 하나를 비활성화할 수 없습니다. 읽을 수 없는 팩 목록이나 모든 검사를 사용할 수 없는 팩은 Jev에게 질의할 내용을 남기지 않습니다. + +| 이름 | 모드 | 사용자 재정의 가능 | Jev가 확인하는 내용 | +| --- | --- | --- | --- | +| `destructive-deletion` | deny | 예 | 재생성할 수 없는 데이터의 영구 삭제. | +| `production-infra-change` | deny | 예 | 라이브 인프라 변경. | +| `git-history-rewrite` | deny | 예 | 공유된 git 이력 재작성 또는 폐기. | +| `push-to-protected-branch` | instruct | 예 | 보호된 브랜치에 직접 푸시. | +| `commit-on-protected-branch` | instruct | 예 | 보호된 브랜치에 직접 커밋. | +| `secret-exposure` | deny | 예 | 자격 증명 읽기 또는 복사. | +| `credential-exfiltration` | deny | 아니오 | 시크릿 또는 개인 파일을 머신 외부로 전송. | +| `remote-code-execution` | deny | 예 | 인터넷에서 다운로드된 코드 실행. | +| `privilege-escalation` | deny | 예 | 상승된 권한으로 실행. | +| `database-destruction` | deny | 예 | 데이터베이스 데이터 파괴 또는 대량 수정. | +| `read-outside-workspace` | instruct | 예 | 프로젝트 외부 파일 읽기. | +| `agent-config-tampering` | deny | 아니오 | 에이전트 자체의 안전 구성 변경. | +| `system-modification` | instruct | 예 | 프로젝트 외부 시스템 변경. | +| `env-secrets-dump` | instruct | 예 | 환경 시크릿 출력. | +| `external-destructive-action` | deny | 예 | 외부 도구를 통한 되돌릴 수 없는 작업. | +| `external-data-egress` | instruct | 예 | 개인 데이터를 외부 도구로 전송. | \ No newline at end of file diff --git a/docs/ko/policies/jev-byok.mdx b/docs/ko/policies/jev-byok.mdx new file mode 100644 index 000000000..42cef1911 --- /dev/null +++ b/docs/ko/policies/jev-byok.mdx @@ -0,0 +1,265 @@ +--- +title: "Jev 평가기 (자체 키 사용)" +description: "TypeSafe의 Jev 분류기가 정규식 필터를 기반으로 에이전트의 도구 호출을 판단하도록, 본인 소유의 Jev 엔드포인트와 키를 사용합니다." +icon: "key-round" +--- + +정규식 정책은 문자열을 매칭합니다. `rm -rf build/`처럼 직접 요청한 명령과 계획에 슬며시 끼어든 `rm -rf ~`를 구분하지 못하기 때문에, 한쪽에서는 지나치게 많이 차단하고 다른 쪽에서는 너무 적게 차단합니다. TypeSafe의 분류기인 **Jev**는 실제로 요청한 내용을 기준으로 호출을 읽고, 빠른 단일 요청으로 일련의 예/아니오 질문에 답합니다. + +본인 소유의 Jev 엔드포인트와 키를 구성하면, Failproof AI는 정규식 정책을 대체하는 것이 아니라 **함께** 각 도구 호출에 대해 Jev에 질의합니다: + +- **하드** 정책의 차단은 최종적입니다. Jev가 이를 해제할 수 없습니다. 검토 가능으로 명시되고 이를 커버하는 Jev 검사를 명시하지 않는 한 모든 정책은 하드입니다. 따라서 아무 내용도 명시하지 않은 커스텀, 팩, Cloud 정책은 하드이며, 항상 활성화된 자기 보호 가드도 항상 하드입니다. +- **검토 가능** 정책의 차단은 해제될 수 있지만, Jev가 해당 정책이 다루는 정확한 우려 사항에 대해 질의받고 "여기 없음" 또는 "사용자가 이를 요청함"이라고 답한 경우에만 가능합니다. 사용자가 해당 호출을 요청하지 않았는데 해당 우려 사항이 실재한다고 판단하는 검사는, 그 자체 판정이 경고에 불과하더라도 차단을 유지합니다. 도구 호출 이전 단계에서 경고는 에이전트를 중단시키지 않기 때문입니다. 그리고 그 검사가 차단 가능한 종류(비밀 노출, 자격 증명 유출, 파괴적 삭제 등)인 경우, 해당 호출에 대해서는 아무것도 해제되지 않습니다. +- 해당 호출이 부여한 작업의 단계이고 그 이상으로 나아가지 않는 경우, 차단은 여전히 **경고**로 완화될 수 있습니다. Jev는 자신의 차단을 경고로 완화하고, 그 경고—호출의 실제 문제를 명시하는—가 정책의 차단을 대체합니다. +- Jev는 정규식으로 설명되지 않는 피해에 대해 자체적으로 경고하거나 차단할 수도 있습니다. +- Jev가 답할 수 없는 경우(타임아웃, 속도 제한, 서버 오류, 크레딧 부족, 예상치 못한 모델 버전), 해당 호출은 Jev 없이와 정확히 동일한 정규식 결과를 받습니다. +- Jev는 전체 호출을 읽고 정확한 우려 사항에 대해 질의받지 않는 한, 정책만 있을 때보다 호출을 더 허용적으로 만들지 않습니다. 그 이하—전체를 전송하기에 너무 큰 호출, 주입 의심—는 모든 해제를 취소하고 모든 차단을 유지합니다. + + +Jev 설정이 없으면 아무것도 변경되지 않습니다: 훅은 항상 그래왔듯이 정규식 정책을 정확히 실행합니다. 설정이 곧 전체 옵트인입니다. + + + +FailproofAI Cloud를 사용 중이신가요? 본인 소유의 키가 필요하지 않습니다: `jev:evaluate`를 포함한 키로 연결된 머신은 조직 플랜에서 Jev를 사용할 수 있습니다. [FailproofAI Cloud를 통한 Jev](/ko/policies/jev-cloud)를 참조하세요. + + +## 공급자 선택 + +Jev는 다섯 가지 경로를 통해 접근할 수 있습니다. 그 중 하나에 대한 키를 준비하세요. + +| 공급자 | `--provider` | 엔드포인트 | 기본 모델 | 비고 | +| --- | --- | --- | --- | --- | +| TypeSafe | `typesafe` | `api.typesafe.ai/v1/systemone` | `jev-1.13.0` | 정확한 버전 고정. | +| OpenRouter | `openrouter` | `openrouter.ai/api/v1/systemone` | `typesafe/jev-1.13` | 요청은 제로 데이터 보존 엔드포인트로만 라우팅되며, 다른 공급자로의 폴백은 없습니다. `typesafe/jev-1.13-20260917`과 같은 날짜 포함 버전을 보고합니다. | +| Vercel AI Gateway | `vercel` | `ai-gateway.vercel.sh/typesafe/v1/systemone` | `typesafe-ai/jev` | 별칭으로만 Jev를 명명하므로, 응답 버전은 미검증으로 기록됩니다. | +| Cloudflare Workers AI | `cloudflare` | `api.cloudflare.com/client/v4/accounts//ai/run` | `typesafe/jev` | `--account-id` 필요. 키당 초당 약 6회 호출이 HTTP 429 이전까지 측정되었습니다. | +| 자체 엔드포인트 | `custom` | `/systemone` | `jev-1.13.0` | TypeSafe의 요청 본문을 수용하고 어떤 모델이 응답했는지 보고하는 모든 엔드포인트. `https`만 가능; 섀도우 모드에서만 일반 `http://localhost`가 허용됩니다. | + + +Vercel의 자체 bring-your-own-key 기능을 사용하면, 실패한 요청이 Vercel의 자격 증명으로 자동 재시도됩니다. 모든 호출이 본인의 TypeSafe 계정에만 청구되고 보여야 한다면, TypeSafe를 직접 사용하세요. + + +## 설정하기 + +명령 하나로 엔드포인트와 키를 설정합니다: + +```bash +failproofai jev --url https://api.typesafe.ai/v1 --key-stdin < ~/typesafe.key +``` + +### URL이 공급자를 결정합니다 + +공급자를 명시할 필요가 없습니다: URL의 **호스트**가 공급자를 결정합니다. + +| URL 호스트 | 공급자 | 추가 필요 사항 | +| --- | --- | --- | +| `api.typesafe.ai` | `typesafe` | — | +| `openrouter.ai` | `openrouter` | — | +| `ai-gateway.vercel.sh` | `vercel` | — | +| `api.cloudflare.com` | `cloudflare` | `--account-id <32-hex-account-id>` | +| 기타 모든 호스트 | `custom` | — 입력한 URL이 기본 URL이 됩니다 | + +이로부터 세 가지가 따릅니다: + +- **공급자 자체 API URL은 오버라이드를 기록하지 않습니다.** `--url https://api.typesafe.ai/v1`은 `--provider typesafe`와 정확히 동일한 설정을 생성합니다. 알려진 공급자에서 다른 경로나 호스트를 지정하면 `--base-url`이 저장하는 것처럼 기본 URL로 저장됩니다. +- **`--provider`는 여전히 추론을 오버라이드합니다.** 이는 본인 소유 호스트에서 공급자의 API를 사용하는 프록시에 접근하는 방법입니다: `--url https://jev-proxy.internal/v1 --provider typesafe`. +- **호스트와 모순되는 `--provider`는 거부됩니다.** 추측하지 않습니다. `--provider openrouter --url https://api.typesafe.ai/v1`은 아무것도 기록하지 않고 이유를 설명합니다: 두 지정이 키가 전송될 위치에 대해 일치하지 않습니다. `jev setup --base-url`과 대시보드의 Jev 설정에서도 동일한 쌍이 거부됩니다. (`--provider custom`은 모순이 아닙니다—"이 URL을 그 자체로 처리"를 의미합니다—단 계정별 엔드포인트에 커스텀 경로가 도달할 수 없는 Cloudflare 호스트는 제외.) + +`--url`은 설정 파일의 `baseUrl`과 정확히 동일하게 검증되며, 동일한 메시지로 거부됩니다: `https`, 또는 섀도우 모드에서만 `http://localhost`가 허용됩니다. + +### 키 + +`--key-stdin`으로 파이프하거나, 터미널에서 해당 플래그 없이 명령을 실행하고 마스킹된 프롬프트에서 키를 붙여넣으세요. 어느 방식이든 키는 바로 설정 파일에 저장되며 다시 출력되지 않습니다. + + + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --key-stdin < ~/typesafe.key + ``` + + + ```bash + failproofai jev --url https://openrouter.ai/api/v1 --key-stdin < ~/openrouter.key + ``` + + + ```bash + failproofai jev --url https://ai-gateway.vercel.sh/typesafe/v1 \ + --key-stdin < ~/vercel-gateway.key + ``` + + + ```bash + failproofai jev --url https://api.cloudflare.com/client/v4 \ + --account-id <32-hex-account-id> --key-stdin < ~/cloudflare.token + ``` + + + ```bash + failproofai jev --url https://jev.internal.example.com/v1 --key-stdin < ~/jev.key + ``` + + + +`failproofai jev setup`은 동일한 플래그를 사용하며, URL 대신 공급자를 명시하려는 경우 `setup --provider `를 사용하는 전체 표기입니다. + +### `--token`과 비용 + +`--token `은 명령줄에 키를 입력하는 방식으로, 머신을 구성하는 가장 빠른 방법이지만 설정 파일 외의 위치에 키를 남기는 유일한 표기입니다: + +```bash +failproofai jev --url https://openrouter.ai/api/v1 --token +``` + + +명령줄 인수는 이후 셸의 히스토리 파일에 남으며, 명령이 실행되는 동안 프로세스 목록에 있어 `/proc`에서 본인으로 실행 중인 모든 것이 읽을 수 있습니다. `setup`은 `--token`이 사용될 때마다 이를 알립니다. 공유 머신이나 녹화된 세션, 또는 히스토리 파일이 동기화되는 환경에서는 `--key-stdin`을 사용하고, 이 방식으로 전달한 키는 중요하다면 교체하세요. + + +`--token`, `--key-stdin`, `--key-from-env`는 상호 배타적입니다: 하나만 사용하세요. + +그런 다음 키, 엔드포인트, 응답한 Jev를 확인하기 위해 작은 실시간 요청을 전송합니다: + +```bash +failproofai jev test +``` + +```text + failproofai jev test ok · 523 ms + + provider cloudflare + model asked typesafe/jev + answered by jev-1.13.0 (Jev 1.13 family — verified) + latency 523 ms — within the 3000 ms timeout +``` + +`jev test`는 응답이 타임아웃 이후에 도착하거나(`timeout`으로 모든 훅이 정규식으로 폴백) 검사 질문에 잘못 답하면 제목에 표시하고 종료 코드 1로 종료합니다. + +훅은 모든 도구 호출마다 설정을 읽으므로 다음 호출부터 적용됩니다. 데몬 유무에 관계없이 재시작이 필요하지 않습니다. + +## 동작 확인 + +```bash +failproofai jev status +failproofai jev status --json +``` + +`status`는 공급자, 엔드포인트, 모델, 모드, 설정 파일과 그 권한을 표시하며 키는 절대 표시하지 않습니다. 그 아래에는 최근 활동을 요약합니다: Jev가 평가한 호출 수, 정규식으로 폴백한 빈도와 이유, 지연 시간, 해제된 검토 가능 정책. + +## 섀도우 모드 + +`enforce`가 기본값입니다. Jev가 어떤 결정도 변경하지 않으면서 동작을 관찰하려면 `shadow`로 전환하세요: Jev는 여전히 질의받고 그 판정이 기록되지만, 실제로 적용되는 것은 정규식 결과입니다. + +```bash +failproofai jev setup --mode shadow +failproofai jev setup --mode enforce +failproofai jev setup --mode off +``` + +`off`는 설정—엔드포인트와 키—을 유지하고 Jev 질의를 중단합니다: 훅은 설정 없이와 정확히 동일하게 정규식 정책을 실행하며, `failproofai jev status`는 "off (switched off)"를 표시합니다. `--mode shadow` 또는 `--mode enforce`로 다시 전환할 수 있습니다. + +동일한 공급자에 대해 `setup`을 재실행하면 저장된 키가 유지되므로 모드 전환은 플래그 하나로 됩니다. 공급자를 전환하면 처음부터 시작하고 해당 공급자의 키를 요청합니다. 요청을 다른 호스트로 이동하는 `--base-url`도 마찬가지입니다: 저장된 키는 제공된 호스트 또는 해당 공급자의 자체 API로만 전송됩니다. + +## 설정 파일 + +모든 것이 `~/.failproofai/jev.json` 하나의 파일에 저장되며, `setup`이 작성합니다: + +```json +{ + "provider": "cloudflare", + "apiKey": "", + "accountId": "<32-hex-account-id>", + "mode": "enforce", + "timeoutMs": 3000 +} +``` + +| 필드 | 의미 | +| --- | --- | +| `provider` | `typesafe`, `openrouter`, `vercel`, `cloudflare`, `custom` 중 하나—또는 `failproofai`로, 이 파일 대신 FailproofAI Cloud 연결에서 키를 가져옵니다([FailproofAI Cloud를 통한 Jev](/ko/policies/jev-cloud) 참조). | +| `apiKey` | `Authorization: Bearer `로 전송됩니다. | +| `baseUrl` | `custom`에 필요; 그 외에는 공급자의 API 기본값을 대체합니다. `https`여야 합니다. `localhost`에 대한 일반 `http`는 `mode: shadow`에서만 허용됩니다: 로컬 포트를 인증하는 것이 없으므로, 프록시가 다운된 동안 에이전트를 포함한 머신의 모든 프로세스가 대신 응답할 수 있습니다. | +| `accountId` | Cloudflare 전용: 32자 소문자 16진수. | +| `model` | 공급자의 기본 모델 ID를 대체합니다. 버전이 지정된 ID는 Jev 1.13을 명명해야 합니다. API 키처럼 생긴 값은 거부되며(반복 출력되지 않음), `--model`에 붙여넣은 키는 절대 저장되거나 모델로 전송되지 않습니다. | +| `timeoutMs` | 도구 호출이 정규식 결과를 사용하기 전에 Jev를 기다리는 시간. 100–10000, 기본값 3000. | +| `mode` | `enforce`(기본값), `shadow`, 또는 `off`(설정 유지, Jev 실행 없음). | + +세 가지 규칙이 이를 보호합니다: + +- **소유자 전용.** 권한 `0600`으로 작성됩니다. 다른 사용자나 그룹이 읽거나 쓸 수 있는 복사본은 **거부**되며, `chmod 600 ~/.failproofai/jev.json`을 실행하거나 `setup`을 다시 실행할 때까지 훅은 정규식으로 폴백합니다. 디렉토리도 확인됩니다: `~/.failproofai`는 다른 사람이 **쓸 수 없어야** 합니다. 거기에 쓸 수 있는 사람은 파일 자체의 권한에 관계없이 파일을 교체할 수 있기 때문입니다. `setup`은 그런 쓰기 비트를 발견하면 제거합니다. `failproofai jev status`는 설정이 거부되었을 때 표시하고 파일이 명명하는 엔드포인트를 보여줍니다: 다른 사람이 변경했을 수 있으므로, `chmod` 전에 본인 것인지 확인하세요. 이런 파일에서 `setup`을 재실행하면 저장된 키는 공급자 자체 API로만 전달됩니다; 파일이 명명하는 다른 엔드포인트는 키를 다시 요구합니다(`--key-stdin`), 또는 `--base-url default`로 공급자로 요청을 돌려보내세요. +- **전역 전용.** 저장소는 Jev를 켜거나, 다른 엔드포인트로 지정하거나, 모델을 선택할 수 없습니다: 프로젝트 내 `.failproofai/jev.json`은 무시되며, 공급자, URL, 모델, 계정 ID는 그 파일에서만 읽히고—저장소의 에이전트 설정이 설정할 수 있는 환경에서는 절대 읽히지 않습니다. (`FAILPROOFAI_HOME`은 우회 방법이 아닙니다: Jev만 리디렉션하는 것이 아니라 정책을 포함한 전체 failproofai 디렉토리를 이동합니다.) +- **키만 환경에서 올 수 있습니다.** 파일에 `apiKey`가 없으면, `FAILPROOFAI_JEV_API_KEY`가 해당 세션에 대해 제공합니다(`setup --key-from-env`는 이런 파일을 작성합니다). 파일이 보유한 키를 절대 대체하지 않으며, 파일 없이 Jev를 켤 수 없습니다. 변수가 설정되지 않은 경우, Jev는 해당 셸에서 단순히 꺼집니다: `failproofai jev status`는 이를 표시하고, 종료 코드 0으로 종료하며 설정을 그대로 둡니다(`status --json`은 `"reason": "no-env-key"`와 함께 `"status": "key-missing"`을 보고합니다). `failproofaid` 데몬은 셸의 환경을 보지 못하므로, `failproofai config`로 설정된 머신에서는 파일에 키를 보관하세요. + +## 어떤 Jev가 응답하는가 + +Failproof AI의 결정 임계값은 Jev 1.13에 맞춰 조정되었으므로, 해당 계열에서 온 경우에만 답변이 사용됩니다: `jev-1.13.x`, 또는 OpenRouter의 `typesafe/jev-1.13-`. 공급자가 별칭으로만 Jev를 명명하고 버전을 보고하지 않는 경우(Vercel, 그리고 버전을 명시하지 않는 Cloudflare), 답변은 사용되고 미검증으로 기록됩니다. `custom` 엔드포인트는 응답한 모델을 보고해야 합니다; 단 하나의 예외는 설정한 버전 없는 `--model` 이름으로, 이것이 그대로 반환되면 동일하게 미검증으로 기록됩니다. 다른 버전을 보고하는 답변이나 버전을 보고하지 않는 `custom` 답변은 사용되지 않습니다: 해당 호출은 `model-mismatch` 이유로 정규식으로 폴백합니다. + +## Jev가 답할 수 없을 때 + +다음 각각은 해당 호출에 대해 정규식 결과로 폴백하고 이유와 함께 기록되며, `failproofai jev status`가 집계합니다: + +| 이유 | 원인 | +| --- | --- | +| `timeout` | `timeoutMs` 내에 답변 없음. | +| `http-429` | 공급자가 키를 속도 제한함. | +| `rate-limited` | Failproof AI 자체 제한기가 전송 전에 호출을 보류함: 초당 5회, 최대 5회 버스트, 공급자가 `429`를 반환한 후 잠시 없음. 공급자가 아님. | +| `http-500`, `http-502`, `http-503`, … | 공급자의 서버 오류. 정확한 상태가 기록됩니다. | +| `out-of-credits` | HTTP 402: 공급자 계정에 크레딧이 없음. | +| `provider-refused` | Cloudflare에서 "Model execution failed (Payment error)"를 읽는 HTTP 402: 공급자가 이 요청에 대해 모델 실행을 거부함. 보통 청구 문제가 아니므로 크레딧 충전으로 해결되지 않습니다. | +| `http-401`, `http-403` | 키가 거부됨. | +| `http-404` | `/systemone`에 아무것도 서빙되지 않으므로 기본 URL이 잘못됨—`/systemone`이 기본 URL에 추가되며, 모든 공급자는 버전 루트에서 서빙합니다. `failproofai jev models`는 엔드포인트가 실제로 서빙하는 것을 보여줍니다. | +| `network` | 엔드포인트에 연결할 수 없음. | +| `http-301`, `http-302`, `http-307`, `http-308` | 엔드포인트가 리디렉션으로 응답함. 리디렉션은 절대 따르지 않으므로, 답변은 설정의 URL에서만 옵니다; `--base-url`을 최종 URL로 설정하세요. | +| `malformed` | 엔드포인트가 응답했지만 Jev 답변이 아님—JSON이 아닌 본문, 또는 답변이 없는 본문. | +| `cloudflare-error`, `cloudflare-incomplete` | Cloudflare의 엔벨로프가 실패를 보고하거나, 완료되지 않은 작업. | +| `model-mismatch` | 1.13 외의 Jev 버전이 응답하거나, `custom` 엔드포인트가 응답한 모델을 명시하지 않음. | +| `request-cut` | **장애가 아님.** Jev가 응답했지만 호출의 일부만 보여졌으므로 답변이 아무것도 해제하지 않음. [Jev가 답했지만 전체 호출이 아닌 경우](#when-jev-answered-but-not-on-the-whole-call) 참조. | + +`failproofai jev status`는 `upstream-error`(답변에 공급자 자체 오류가 포함됨) 또는 `config` 같은 드문 이유도 표시할 수 있으며, 명명할 수 없는 이유는 `other`로 합산합니다. + +`request-cut`은 `failproofai jev status`가 나머지와 함께 집계하고, 이 역시 모든 차단을 유지하기 때문에 이 표에 있습니다. 공급자에 대해 아무것도 말하지 않는 유일한 이유입니다: 요청이 도착했고 Jev가 응답했습니다. 위의 모든 행과 달리, 그 답변은 여전히 계산됩니다—Jev 자체의 차단이나 경고가 폐기되는 대신 정규식 결과 위에 적용됩니다. 따라서 연속적으로 발생한다면 호출이 전체를 전송하기에 너무 크게 평가기에 도달하고 있다는 의미이며, 엔드포인트가 문제가 있다거나 크레딧을 충전하거나 URL을 변경해서 해결될 문제가 아닙니다. + +## Jev가 답했지만 전체 호출이 아닌 경우 + +두 가지 더 발생할 수 있으며, 둘 다 Jev가 답에 실패한 것이 아닙니다. 둘 다 호출 또는 대화의 얼마나 많은 부분이 하나의 요청에 맞는지에 관한 것입니다. + +**호출 자체의 일부가 맞지 않음.** 도구 호출은 고정된 예산 내에서 전송되며, 과도하게 큰 것—매우 큰 `Write`, 거대한 MCP 본문, 한도까지 채워진 명령—은 맞는 부분만 전송됩니다. Jev는 여전히 응답하고 그 답변은 여전히 계산됩니다: 자체 차단이나 경고가 평소대로 적용됩니다. 할 수 없는 것은 **해제**입니다. 호출의 일부에 대한 판정은 호출 전체에 대한 판정이 아니기 때문입니다. 따라서 모든 정책 차단이 유지되고, 호출은 `request-cut` 이유로 폴백으로 기록되며 `failproofai jev status`가 위의 이유들과 함께 집계합니다. 이 규칙이 의미하는 것: 호출을 더 크게 만드는 것은 해제를 잃을 수 있고, 해제를 살 수는 없습니다. + +**메시지가 맞지 않음.** 붙여넣은 긴 프롬프트, 에이전트의 마지막 메시지, 또는 이 평가기의 자체 저장소가 이미 한도를 초과한 프롬프트. **아무것도 변경되지 않습니다**: 호출은 다른 것과 정확히 동일하게 판단되고, 해제되고, 기록되며 폴백으로 계산되지 않습니다. 타이핑하는 내용의 길이는 절대 판정을 결정하지 않으며, 잘림이 동의를 만들 수 없습니다: 프롬프트가 이미 한도 초과된 상태로 도착한 경우, "당신이 이를 요청하지 않았다"는 결론을 전혀 도출할 수 없게 됩니다. + +둘의 경계는 누가 텍스트를 작성했는지입니다. 호출은 에이전트의 것이며, 길이가 심각성을 줄이는 규칙은 에이전트가 사용할 수 있는 규칙이 됩니다; 프롬프트는 본인 것이며, 그 길이를 신호로 취급하면 사양이나 스택 트레이스를 붙여넣는 것에만 불이익을 줄 뿐입니다. + +## 머신에서 나가는 것 + +Jev가 평가하는 각 도구 호출에 대해, 하나의 요청이 공급자로 전송되며 다음을 포함합니다: + +- API 키, 베어러 토큰, `KEY=` 할당 등의 비밀이 편집된 도구 호출 자체; +- 에이전트 하네스가 추가한 텍스트가 제거된 최근에 타이핑한 프롬프트; +- 최신 프롬프트 이전 에이전트의 마지막 메시지, 에이전트 작성으로 표시; +- 경로가 프로젝트 내에 있는지 여부 등 로컬에서 계산된 사실—첫 번째 검토된 호출 시 세션이 있던 위치로, [세션에 고정](/ko/reference/jev-intent#the-project-root)됨—및 현재 git 브랜치. + +설정의 엔드포인트로만, 본인 키 아래에서 전송됩니다. + +## 끄기 + +```bash +failproofai jev remove +``` + +이것은 `~/.failproofai/jev.json`을 삭제합니다. 다음 도구 호출부터 훅은 이전과 정확히 동일하게 정규식 정책을 실행합니다. `~/.failproofai/state/semantic/` 아래의 세션별 저장소(`sessions/`의 기록된 프롬프트, `roots/`의 프로젝트 루트)는 그대로 두고 자연히 만료됩니다. Jev 질의를 중단하되 설정을 유지하려면 대신 `failproofai jev setup --mode off`를 사용하세요. + +## 명령 참조 + +| 명령 | 결과 | +| --- | --- | +| `failproofai jev --url --key-stdin` | 명령 하나로 구성; 공급자는 URL의 호스트에서 결정 | +| `failproofai jev --url --token ` | 동일하지만 명령줄에 키를 입력—히스토리와 프로세스 목록에서 볼 수 있음 | +| `failproofai jev setup --provider --key-stdin` | stdin으로 파이프된 키로 설정 작성 | +| `failproofai jev setup --provider ` | 동일하지만 마스킹된 프롬프트에서 키 요청 | +| `failproofai jev setup --key-from-env` | 키를 저장하지 않음; 세션당 `FAILPROOFAI_JEV_API_KEY` 읽기 | +| `failproofai jev setup --mode shadow` | 저장된 키를 유지하며 모드 전환(`enforce`, `shadow` 또는 `off`) | +| `failproofai jev setup --model ` / `--base-url ` | 모델 또는 API 기반 오버라이드; `default`는 오버라이드 해제 | +| `failproofai jev setup --timeout-ms ` | 호출당 예산 변경 | +| `failproofai jev status [--json]` | 설정, 권한 및 최근 활동; 키 제외 | +| `failproofai jev test [--json]` | 실시간 요청 하나: 지연 시간 및 응답한 버전 | +| `failproofai jev models [--provider ] [--url ] [--json]` | 해당 엔드포인트의 `/models`가 보고하는 모델 ID, 구성된 것을 표시 | +| `failproofai jev remove` | 설정 삭제; Jev 꺼짐 | \ No newline at end of file diff --git a/docs/ko/policies/jev-cloud.mdx b/docs/ko/policies/jev-cloud.mdx new file mode 100644 index 000000000..816918ae6 --- /dev/null +++ b/docs/ko/policies/jev-cloud.mdx @@ -0,0 +1,117 @@ +--- +title: "FailproofAI Cloud를 통한 Jev" +description: "별도의 TypeSafe 계정이나 키 없이, 조직의 플랜으로 FailproofAI Cloud를 통해 Jev가 에이전트의 도구 호출을 판별하게 하세요." +icon: "cloud" +--- + +[Jev](/ko/policies/jev-byok)(TypeSafe의 분류기)는 각 도구 호출을 실제로 요청한 내용과 대조해 읽고, 정책과 함께 답을 제공합니다 — 정책을 대체하는 것이 아닙니다. **FailproofAI Cloud**를 통하면, 연결된 머신은 이미 연결에 사용 중인 키로 Jev를 사용합니다: TypeSafe 계정도, 별도의 키도, 설정할 엔드포인트도 필요 없습니다. 각 호출은 조직의 기존 플랜 허용량에서 차감됩니다. + +Jev의 모든 동작은 [자체 키 사용 설정](/ko/policies/jev-byok)과 동일합니다: 하드 정책은 항상 최종 결정이며, 검토 가능한 정책의 deny는 해당 우려 사항에 대해 Jev에게 정확히 질의했을 때만 해제되고, 오류가 발생하면 해당 호출의 정규식 결과로 폴백됩니다. + + +**failproofai 1.0.8-beta.0** 이상이 필요합니다. 1.0.7에는 Jev가 없습니다 — 1.0.7 베타 버전보다 정렬상 위에 표시되더라도 마찬가지입니다. Jev 설정이 없으면 아무것도 바뀌지 않습니다: 훅은 항상 해왔던 것처럼 정규식 정책을 그대로 실행합니다. + + +## 활성화하기 + +1. **Jev가 포함된 키를 생성합니다.** FailproofAI Cloud 대시보드에서 **Keys → Create key**를 열고 **machine** 프리셋을 선택합니다. 머신에 필요한 세 가지 권한을 부여합니다: `events:add`(활동 전송), `policies:pull`(정책 수신), `jev:evaluate`(Jev, 조직 플랜에서 차감). 키는 나머지 두 권한 없이는 `jev:evaluate`를 가질 수 없습니다. +2. 해당 키로 **머신을 연결**합니다: + + ```bash + failproofai config --token + ``` + + 조직이 호스팅된 서비스가 아닌 자체 FailproofAI Cloud를 운영하는 경우 주소를 추가하세요: `--url https://` (또는 `FAILPROOFAI_CLOUD_URL` 환경 변수 사용). 지정하지 않으면 키가 호스팅 서비스에서 확인되어 연결이 실패합니다. 해당 호스트의 인증서가 사설 CA에서 발급된 경우, CA를 머신의 시스템 신뢰 저장소에 설치하세요(예: `update-ca-certificates` 사용) — `NODE_EXTRA_CA_CERTS`에만 설치하는 것은 충분하지 않습니다: 이벤트를 전송하고 정책을 가져오는 데몬은 시스템 저장소를 읽습니다. [문제 해결](/ko/reference/troubleshooting)을 참조하세요. + +이게 전부입니다. 연결하면 키가 저장되고, 머신에 Jev 설정이 **없는** 경우 FailproofAI Cloud를 통해 **shadow** 모드로 Jev가 활성화됩니다: Jev는 모든 게이팅된 도구 호출에 대해 질의되고 판결이 기록되지만, 실제로 적용되는 것은 정책의 결과입니다. 출력에 이 내용이 표시됩니다: + +```text + Jev on through FailproofAI Cloud, in shadow mode: logged, not enforced (~/.failproofai/jev.json). +``` + +**`--no-transcripts`를 사용하면 연결 시 Jev가 활성화되지 않습니다.** Jev는 확인된 각 도구 호출과 최근 프롬프트를 FailproofAI Cloud로 전송하는데, 이는 결정 사항만 전송하도록 요청된 연결보다 더 많은 데이터입니다. 키는 여전히 저장되며, 출력에는 Jev가 사용 가능하고 활성화 방법이 표시됩니다: + +```bash +failproofai jev setup --provider failproofai +``` + +Jev를 **끄지도** 않습니다. 머신의 `jev.json`이 이미 FailproofAI Cloud를 통해 Jev를 실행 중이라면 그대로 유지되며, 출력에는 Jev가 여전히 각 확인된 도구 호출과 최근 프롬프트를 전송하고 있으며 `failproofai jev setup --mode off`로 끌 수 있다고 표시됩니다. + + +연결은 기존 `~/.failproofai/jev.json`을 **절대 덮어쓰지 않습니다**. 이미 자체 Jev 엔드포인트를 사용 중이라면 계속 사용되며, 출력에 파일이 설정된 대로 유지되었다고 표시됩니다 — 해당 파일에서 Jev가 꺼져 있는 경우(거부되었거나 수동으로 꺼진 경우)에는 그 사실과 해결 방법도 표시됩니다. 해당 머신을 FailproofAI Cloud로 전환하려면 `failproofai jev setup --provider failproofai`를 실행하세요. + + +## Shadow, enforce 또는 off + +Shadow로 시작해서 정책 페이지에서 Jev가 어떻게 동작하는지 확인한 다음, 실제로 적용할 수 있습니다: + +```bash +failproofai jev setup --mode enforce # Jev의 판결이 적용됩니다: 검토 가능한 deny를 해제하고 자체 판결을 추가할 수 있습니다 +failproofai jev setup --mode shadow # Jev가 질의되고 기록되지만 실제로 적용되는 것은 정책의 결과입니다 +failproofai jev setup --mode off # 설정은 유지하되 Jev에 질의하지 않습니다 +``` + +동일한 설정이 로컬 대시보드에도 있습니다: **Settings → Jev**에 on/off 스위치와 shadow/enforce 옵션이 있습니다. 모드만 다시 작성하고 다른 것은 변경하지 않습니다. 훅은 매 도구 호출마다 설정을 읽으므로 변경 사항은 다음 호출부터 적용되며, 재시작이 필요하지 않습니다. + +## 동작 상태 확인 + +```bash +failproofai jev status +failproofai jev test +``` + +`status`는 제공자를 **FailproofAI Cloud**로, 머신이 연결된 Cloud 호스트, 모드, 키 출처를 **FailproofAI Cloud connection**으로 표시합니다 — 키 자체는 표시되지 않습니다. FailproofAI Cloud `jev.json`이 있지만 Jev를 실행할 수 없는 경우 그 이유를 알려줍니다: + +| `status` 표시 | `status --json` | 의미 | +| --- | --- | --- | +| **off — no Jev key is stored for this machine's FailproofAI Cloud connection** | `key-lacks-jev` | 머신은 연결되어 있지만 Jev 키가 저장되어 있지 않습니다: 키에 `jev:evaluate` 권한이 없거나 연결 시 확인하지 못했습니다. 동일한 키로 `failproofai config --token `를 다시 실행하세요; 권한이 없다면 **machine** 키를 사용하세요. | +| **off — this machine is not connected to FailproofAI Cloud** | `not-connected` | 이 머신에 Jev 키가 속할 FailproofAI Cloud 연결이 없습니다. | + +`failproofai config --disconnect` 이후에는 FailproofAI Cloud `jev.json`이 더 이상 존재하지 않으므로(꺼진 상태로 유지된 경우 제외) `status`는 단순히 Jev가 off라고 보고합니다. `status --json`은 동일한 정보를 포함합니다(`provider: "failproofai"`, `keySource: "cloud"`, `cloudConnected`, `keyCarriesJev`) — 설정이 없거나 거부된 경우에도 마찬가지입니다. `permissions`는 항상 `jev.json`의 것이며, `credentials.json`에 대한 거부는 `credentialsPermissions`를 추가하고, 하나의 명령으로 수정 가능한 경우 `fix`도 추가됩니다. `test`는 실제 요청을 하나 보내고 지연 시간과 응답한 Jev 버전을 보고합니다. 훅 타임아웃 이후에 응답이 도착하거나(훅은 `timeout`으로 기록됨) 확인 질문에 잘못 답하면 종료 코드 1로 종료되며 제목에 표시됩니다. + +대시보드의 **Settings → Jev** 패널에도 **FailproofAI Cloud connection**이 표시됩니다: 머신이 속한 조직과 키에 Jev가 포함되어 있는지 여부. 네트워크 호출 없이 머신 자체 파일에서 읽습니다. + +## 정책 페이지에 표시되는 내용 + +머신은 이미 훅 활동을 FailproofAI Cloud로 전송합니다(`events:add`). Jev가 활성화되면 각 게이팅된 호출 기록에도 실행된 평가자, Jev의 결정, 해제된 정책, 폴백 이유, 지연 시간, 응답한 모델이 포함됩니다 — 결정, 코드, 이름만이며 명령이나 프롬프트는 포함되지 않습니다. 조직의 **Policies** 페이지에서: + +- Jev 자체 판결로 결정된 호출(enforce 모드)은 **Jev**로 귀속되며, 결정적인 확인이 팩에서 온 경우 해당 팩과 버전도 기록에 표시됩니다; +- shadow 모드에서 Jev의 deny나 경고는 관찰 중인 롤아웃 옆에 **would-have**로 표시됩니다; +- Jev가 해제하거나 shadow 모드에서 해제했을 정책은 정책별로 집계됩니다. + +## Jev가 응답하지 못하는 경우 + +다음 각 경우는 해당 호출에 대해 정책 결과로 폴백되며 이유와 함께 기록됩니다: + +| 이유 | 원인 | +| --- | --- | +| `out-of-credits` | 조직의 플랜 허용량이 소진되었습니다. | +| `http-401`, `http-403` | 키가 취소되었거나 `jev:evaluate` 권한이 없습니다. 해당 권한이 있는 키로 재연결하세요. | +| `http-429` | FailproofAI Cloud가 조직의 Jev 요청을 속도 제한하고 있습니다. 요청한 대기 시간(`Retry-After`, 최대 60초)이 지날 때까지 머신은 아무것도 전송하지 않고 모든 호출이 즉시 폴백됩니다. 이런 방식으로 보류된 호출은 `http-429`로 기록되며, 머신 자체 속도 제한이 먼저 적용된 경우 `rate-limited`로 기록됩니다. | +| `http-429` (일일 한도) | 조직의 일일 Jev 호출 횟수가 소진되었습니다: **UTC 기준 하루 10,000회** — FailproofAI Cloud 운영자가 다른 한도를 설정하지 않은 경우. 00:00 UTC에 카운트가 초기화될 때까지 모든 호출이 폴백됩니다; 머신은 최대 1분에 한 번 다시 시도하므로 초기화 후 1분 내에 감지합니다. `failproofai jev test`는 "Daily Jev limit for this org reached; resets at 00:00 UTC."라고 표시합니다. | +| `http-422` | Jev가 이 호출 요청을 거부했습니다. 일반적으로 도구 호출에 Jev의 토큰 예산을 초과하는 밀집 텍스트(base64, hex, 압축된 코드)가 포함된 경우입니다. 해당 호출은 매번 폴백됩니다; 서비스 장애가 아닙니다. | +| `http-502` | Jev를 현재 사용할 수 없습니다. | +| `http-503` | 이 Cloud가 조직의 Jev를 제공할 수 없습니다: 모델 게이트웨이 없음, 아직 프로비저닝되지 않은 조직, 또는 게이트웨이 다운. 관리자에게 문의하세요; 훅은 최대 1분에 한 번 다시 시도합니다. | +| `http-404` | 이 FailproofAI Cloud는 아직 Jev를 제공하지 않습니다. | +| `timeout` | `timeoutMs`(기본값 3000) 내에 응답이 없습니다. | +| `model-mismatch` | 1.13이 아닌 다른 버전의 Jev가 응답했습니다. | + +## 키의 저장 위치와 전송 대상 + +- 키는 `~/.failproofai/credentials.json`에 한 번만 저장됩니다(`0600`, 소유자 전용 디렉터리), 다른 FailproofAI Cloud 자격 증명 옆에 위치합니다. 이 경로에서는 `jev.json`에 키가 없으며, 여기에 키가 작성되면 설정이 유효하지 않게 됩니다. +- `credentials.json`에 소유자 외 누군가(그룹 또는 기타, 읽기 또는 쓰기)에 대한 권한이 **있거나**, 디렉터리가 소유자 외 누군가에 의해 **쓰기 가능**한 경우, 파일은 **거부**되어 읽히지 않으며 수정할 때까지 Jev가 꺼집니다: 파일에 `chmod 600`, 디렉터리에 `chmod 700`을 적용하거나(또는 재연결하면 파일이 `0600`으로 다시 작성되고 디렉터리가 소유자 전용이 됨). 다른 사용자가 읽기만 할 수 있는 디렉터리는 괜찮습니다; 쓰기가 가능하면 파일을 교체할 수 있습니다. +- 키는 연결과 함께 머신에 있는 동안만 유효합니다: 동일한 FailproofAI Cloud에 대한 정책 또는 보고 자격 증명이 **동일한 키**로 동일한 파일에 있어야 합니다. 연결 없이 남겨진 Jev 키는 무시되며 Jev는 꺼진 상태로 유지됩니다. 이는 이전 버전 failproofai의 `config --disconnect`가 Jev 키를 그대로 남겨두거나(제거 방법을 모름), 이전 버전 failproofai의 `config --token`이 다른 키로 연결할 때 발생할 수 있습니다 — FailproofAI Cloud에서 이 키는 다른 조직에 속할 수 있습니다. Jev를 다시 활성화하려면 **machine** 키로 다시 연결하세요. +- 키는 검증된 Cloud 출처로만 전송됩니다. 다른 곳을 가리키는 `jev.json`은 거부됩니다. +- **머신의 에이전트가 키를 읽을 수 있습니다.** `credentials.json`은 소유자 전용이며 에이전트는 해당 소유자로 실행됩니다. failproofai 자체 파일 읽기는 의도적으로 허용되어 있습니다(변경만 `block-failproofai-commands`로 차단됨). 따라서 에이전트와 이 파일 사이에 있는 것은 `block-read-outside-cwd` — *검토 가능한* 정책 — 뿐이며, 홈 디렉터리에서 시작된 세션에서는 아무것도 없습니다. `jev:evaluate` 권한이 있는 키는 사용되는 곳 어디서나 조직의 Jev 허용량을 소모합니다(일일 한도까지). 따라서 머신 키를 다른 결제 자격 증명처럼 취급하세요: 에이전트가 읽었을 가능성이 있다면 Keys 페이지에서 비활성화하고 새 키로 재연결하세요. +- 글로벌 파일만 이를 결정합니다. 저장소는 Cloud Jev를 활성화하거나, 다른 곳으로 지정하거나, 키를 제공할 수 없으며, 이 경로에서는 `FAILPROOFAI_JEV_API_KEY`가 무시됩니다. +- Jev가 평가하는 각 호출마다 FailproofAI Cloud로 하나의 요청이 전송되며, [자체 키 사용 페이지](/ko/policies/jev-byok#what-leaves-the-machine)에 나열된 내용이 포함됩니다(시크릿은 삭제됨). FailproofAI Cloud는 이를 TypeSafe로 전달하며 기록하거나 보관하지 않습니다. + +## 비활성화하기 + +| 명령어 | 결과 | +| --- | --- | +| `failproofai jev setup --mode off` | 설정을 유지하면서 Jev에 질의하지 않습니다. **이것이 지속적인 스위치입니다:** 다시 연결해도 기존 `jev.json`을 덮어쓰지 않으므로, `--mode shadow`로 다시 켜기 전까지 Jev는 꺼진 상태로 유지됩니다. | +| `failproofai jev remove` | `~/.failproofai/jev.json`을 삭제합니다; Jev가 꺼집니다 — `jev:evaluate` 권한이 있는 키로 다음 `failproofai config --token`을 실행하면 `jev.json`이 없는 것을 확인하고 shadow 모드로 다시 Jev를 활성화합니다(`--no-transcripts`로 실행하지 않는 한). 꺼진 상태를 유지하려면 `--mode off`를 사용하세요. | +| `failproofai config --disconnect` | 머신의 연결을 해제합니다: 키가 제거되고, `jev.json`이 FailproofAI Cloud를 지정하고 꺼지지 않은 경우에도 `jev.json`이 제거됩니다. 자체 엔드포인트를 위한 `jev.json`은 유지되며, 꺼진 상태의 것도 유지되므로 다시 연결해도 Jev는 꺼진 상태로 유지됩니다. | + +다음 도구 호출부터 훅은 이전과 동일하게 정규식 정책만 실행합니다. \ No newline at end of file diff --git a/docs/ko/policies/jev.mdx b/docs/ko/policies/jev.mdx new file mode 100644 index 000000000..e52028f65 --- /dev/null +++ b/docs/ko/policies/jev.mdx @@ -0,0 +1,45 @@ +--- +title: "Jev policies" +description: "게이트된 도구 호출에 Jev의 실시간 검토를 추가하고, 결정을 적용하기 전에 검사합니다." +icon: "shield-check" +--- + +Jev는 에이전트에게 요청한 작업을 기준으로 도구 호출을 검토합니다. 문자열 매칭 정책이 유효한 작업을 차단하거나, 맥락이 필요한 위험한 동작을 놓칠 때 사용하세요. `PreToolUse` 또는 `PermissionRequest` 게이트에서 기존 정책과 함께 응답합니다. 세션이 종료된 **후** 점수를 확인하려면 [Jev evaluations](/ko/evaluations/jev)를 사용하세요. + +## 관찰 모드로 시작하기 + +Failproof AI를 설치하고 [지원되는 하네스](/ko/reference/harnesses)에 훅을 연결합니다. failproofai 1.0.8-beta.0 이상을 사용하세요. + +Failproof AI는 Jev 검사를 기본으로 제공하지 않습니다. 팩으로 설치해야 하며, 그렇지 않으면 Jev가 질의할 내용이 없어 호출되지 않습니다: + +```bash +failproofai policies add FailproofAI/jev-policies +``` + +그런 다음 요청이 Jev에 도달하는 방식을 선택하세요: + +| 경로 | 첫 번째 단계 | +| --- | --- | +| FailproofAI Cloud | `jev:evaluate` 권한을 가진 **machine** 키로 연결합니다. Jev 설정이 없는 머신에서는 `failproofai config`를 실행하면 관찰 모드로 Jev가 활성화됩니다. | +| 직접 사용하는 프로바이더 | 로컬 대시보드에서 **Settings → Jev**를 열고, 프로바이더를 선택한 후 토큰을 붙여넣고 **observe**를 선택합니다. 또는 `failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key`를 실행합니다. | + +![로컬 대시보드의 Jev 설정 화면: 프로바이더, 엔드포인트, 토큰, 그리고 Jev 활성화 전 관찰 모드.](/images/dashboard/jev-settings.png) + +```bash +failproofai jev status +failproofai jev test +``` + +`test`는 엔드포인트를 확인합니다. 훅 경로를 확인하려면, 훅이 연결된 에이전트에게 `README.md`에 파일 읽기 도구를 사용하도록 요청하세요. 해당 도구 호출이 세션에 나타나는지 확인한 후, [로컬 대시보드](/ko/reference/local-dashboard#review-policy-activity)의 **Policies → Activity**에서 검사합니다. `status`의 Jev 카운트가 증가해야 합니다. 관찰 모드는 Jev가 어떤 결정을 내렸을지 기록하며, 기존 정책 결과는 그대로 적용됩니다. + +## 적용 시점 결정하기 + +**hard** 정책은 항상 최종 결정권을 가집니다. Jev는 명시적으로 **reviewable**로 표시된 정책의 deny만 해제할 수 있으며, 해당 정책의 지정된 우려 사항을 검사한 경우에만 가능합니다. 허가 해제에 의존하기 전에 [정책 권한](/ko/policies/authority)을 참조하세요. Jev는 자체적으로 경고하거나 deny할 수도 있습니다. 응답할 수 없는 경우, 해당 호출은 정책 결과에 따라 결정됩니다. + +관찰 결과가 올바르게 보이면, **Settings → Jev**에서 enforce 모드로 전환하거나 다음을 실행하세요: + +```bash +failproofai jev setup --mode enforce +``` + +프로바이더 URL, Cloud 키, 설정, 폴백, 각 요청과 함께 전송되는 데이터에 대해서는 [Jev 통합 레퍼런스](/ko/reference/jev)를 참조하세요. \ No newline at end of file diff --git a/docs/ko/reference/custom-agents-typescript.mdx b/docs/ko/reference/custom-agents-typescript.mdx new file mode 100644 index 000000000..53803a248 --- /dev/null +++ b/docs/ko/reference/custom-agents-typescript.mdx @@ -0,0 +1,401 @@ +--- +title: "커스텀 에이전트 (TypeScript)" +description: "@failproofai/sdk의 설정, 이벤트 카탈로그, 스코프 및 프레임워크 어댑터." +icon: "square-js" +--- + +TypeScript SDK의 모든 설정, 메서드, 필드에 대한 설명입니다. 처음 계측을 시작한다면 가이드부터 시작하세요 — 이 페이지는 참조용입니다. + + + + 설치, 계측, 이벤트 메서드, 실제 예제, 자주 발생하는 문제. + + + 동일한 이벤트, 동일한 와이어 포맷, 동일한 스풀 — Python 버전. + + + +Node 20.9 이상. ESM 및 CommonJS 지원. 런타임 의존성 없음. + + + 이 SDK와 Python SDK는 **동일한 스풀에 동일한 이벤트를 기록합니다**. Node 에이전트와 Python 에이전트가 혼재하는 플릿도 하나의 세션 세트를 생성하며, 대시보드에서 둘을 구분하지 않습니다. 회사 단위가 아닌 서비스 단위로 선택하세요. + + +## 설치 + +```bash +npm install @failproofai/sdk +``` + +```ts +import * as failproofai from "@failproofai/sdk"; + +await failproofai.agent("planner", { goal: question }, async () => { + const hits = await failproofai.toolCall("web_search", { input: { q } }, () => search(q)); +}); +``` + +프레임워크 어댑터는 패키지에 함께 포함되어 있습니다. 프레임워크는 **선택적 피어 의존성**으로 선언되어 있어 지원 버전 범위를 확인할 수 있으며, 자동으로 설치되지 않고 `instrument()`를 호출할 때만 임포트됩니다. + +## Failproof 데몬 연결 + +Python SDK와 동일합니다: **Admin → Keys**에서 `events:add` 키를 생성한 후, 에이전트 머신에서 [데몬을 연결](/ko/start/setup#connect-a-machine-to-cloud)하세요. SDK는 디스크에 기록하고, 데몬이 전송합니다. + +## 설정 + +```ts +failproofai.configure({ + environment: "production", + flushInterval: 0.5, + baseDir: undefined, +}); +``` + +| 옵션 | 설명 | +| --- | --- | +| `environment` | 모든 이벤트에 붙는 레이블 — `production`, `staging`, `prod-eu`. 기본값은 `dev`. | +| `flushInterval` | 타이머가 디스크에 쓰는 주기(초). 기본값은 `0.5`. | +| `baseDir` | 쓰기 경로. 기본값은 데몬의 스풀 디렉터리로, 특별한 이유가 없으면 이 기본값을 사용하세요. | + +모든 값이 유효성 검사를 통과해야만 설정이 적용됩니다. 따라서 잘못된 호출은 새로운 `baseDir`과 기존 인터벌이 혼용되는 대신 SDK를 원래 상태 그대로 유지합니다. + +환경 변수로 설정할 수도 있습니다: + +| 변수 | 설명 | +| --- | --- | +| `AGENTEYE_ENVIRONMENT` | 코드 변경 없이 `environment`를 설정합니다. `configure()` 옵션이 우선합니다. | +| `FAILPROOFAI_HOME` | 스풀을 포함하는 Failproof AI 루트 디렉터리를 변경합니다. | +| `FAILPROOFAI_SDK_LOG_LEVEL` | `debug`, `info`, `warn`(기본값), `error`, `silent`. | +| `FAILPROOFAI_SDK_STRICT` | `1`로 설정하면 계측 오류 시 로깅 대신 예외를 발생시킵니다. | +| `FAILPROOFAI_SDK_STRICT_INTEGRATIONS` | `1`로 설정하면 프레임워크 호환성 문제 시 경고 후 계속 진행하는 대신 예외를 발생시킵니다. | + + + **`environment`에 쉼표를 사용하지 마세요.** Ingest는 해당 필드를 쉼표로 분리해 필터를 구성하며, 레이블에 쉼표가 포함된 이벤트는 무시됩니다 — 전체 실행이 소리 없이 사라질 수 있습니다. `prod,eu`가 아닌 `prod-eu`로 작성하세요. + + `configure({ environment: "prod,eu" })`는 즉시 예외를 발생시켜 바로 알 수 있습니다. `AGENTEYE_ENVIRONMENT`는 예외를 발생시킬 수 없으므로 — 호출자가 없기 때문에 — 경고를 한 번 출력하고 `dev`로 폴백합니다. + + +`failproofai.setLogger({ debug, info, warn, error })`를 사용해 SDK의 로그 출력을 자신의 로거로 연결하세요. + +## 종료 + +버퍼에 쌓인 이벤트는 `process.on("exit")`에서 플러시됩니다. + +시그널로 종료된 프로세스는 해당 핸들러에 도달하지 못하며, Node의 `SIGTERM` 기본 동작은 종료 핸들러 없이 프로세스를 종료하는 것입니다 — 컨테이너화된 에이전트는 마지막 인터벌에서 아직 기록하지 않은 이벤트를 잃게 됩니다. + + + **이 SDK는 시그널 핸들러를 자동으로 등록하지 않습니다.** 핸들러를 등록하면 프로세스 동작이 변경됩니다: 리스너를 추가하면 Node의 기본 종료 동작이 억제되어, 라이브러리가 임의로 추가하면 Ctrl-C가 조용히 작동하지 않게 됩니다. 직접 추가하세요: + + ```ts + for (const signal of ["SIGINT", "SIGTERM"] as const) { + process.once(signal, () => { + failproofai.flushSync(); + process.exit(0); + }); + } + ``` + + +짧게 실행되는 스크립트나 서버리스 핸들러는 반환 전에 `await failproofai.flush()`를 호출해야 합니다 — 인터벌만으로는 전달이 보장되지 않습니다. + +## 식별 + +모든 이벤트는 세션과 에이전트에 속합니다. **스코프가 두 값을 모두 채워주므로** 직접 전달할 필요가 거의 없습니다: + +```ts +await failproofai.session(async () => { + await failproofai.agent("planner", async () => { + failproofai.event.toolUse({ toolName: "search", toolCallId: "c1" }); + }); +}); +``` + +`sessionId`나 `agentId`를 명시적으로 전달해도 되며, 명시적 값이 우선합니다. 둘 다 바인딩되지 않고 전달되지도 않으면, Cloud에서 조용히 폐기될 이벤트를 발행하는 대신 예외를 발생시킵니다. + + + 식별 정보는 `AsyncLocalStorage`를 통해 전달됩니다. `await`, `.then()`, 타이머, 스코프 내에서 생성된 모든 콜백을 따라갑니다. 한 실행 중에 저장되어 다른 실행 중에 호출되는 콜백이나 `worker_threads` 경계를 넘나드는 작업에는 **따라가지 않습니다** — 그런 경우에는 `failproofai.propagate()`로 감싸지 않으면 이벤트가 세션에 연결되지 않습니다. + + +### 스코프 + +| 스코프 | 발행 이벤트 | 반환값 | +| --- | --- | --- | +| `session(body)` | 없음 — 식별 전용 | `body`의 반환값 | +| `agent(id, options?, body)` | `agent_start`, 이후 `agent_end` | `body`의 반환값 | +| `toolCall(name, options?, body)` | `tool_use`, 이후 `tool_result` | `body`의 반환값 | + +동기 바디는 동기로 유지됩니다: `agent("x", () => 1)`은 Promise가 아닌 `1`을 반환합니다. + +`toolCall`은 `call.output`을 직접 지정하지 않는 한, 바디의 resolved 값을 툴의 `output`으로 기록합니다. + + + +| 상황 | 이벤트 | `outcome` | +| --- | --- | --- | +| 블록이 정상 반환됨 | `agent_end` | `"success"` 또는 지정한 `outcome` | +| 블록에서 예외 발생 | `error`, 이후 `agent_end` | `"failed"` | +| `AbortError` 발생 | `agent_end`만 | `"cancelled"` | + +오류는 항상 다시 던져집니다. + +툴 실패는 리프에 기록됩니다 — `error` 문자열이 포함된 `tool_result` — 이며 런 레벨의 `error` 이벤트는 **발행하지 않습니다**. 에이전트 루프가 잡은 오류는 런 실패가 아니며, 전파된 오류는 감싸는 `agent()`에 의해 정확히 한 번 기록됩니다. + + + + + +작업이 단일 함수가 아닌 경우 — 생성자에서 열리고 teardown에서 닫히거나, 기존 제어 흐름에 걸쳐 있는 스코프: + +```ts +{ + using span = failproofai.agent.open("planner", { goal }); + using call = failproofai.toolCall.open("search", { input: { q } }); + call.call.output = await search(q); +} // tool_result, then agent_end +``` + +두 형태 모두 바이트 단위로 동일한 이벤트를 발행합니다. 콜백 형태를 권장합니다: `AsyncLocalStorage.run()` 내에서 실행되므로 되감기가 필요 없고 "여기서 열고 저기서 닫는" 버그 유형 전체를 원천 차단합니다. + +자체 실패를 잡는 `using` 블록은 `span.fail(error)`로 오류를 보고합니다 — 디스포저 자체에는 예외 채널이 없습니다. + + + +## 이벤트 카탈로그 + +Python SDK와 동일한 15개 메서드, camelCase 형태. 대부분 **쌍**으로 이루어져 있습니다 — 오프너를 호출한 뒤 클로저를 호출하면 SDK가 그 사이의 시간을 측정합니다. + +| | 오프너 | 클로저 | +| --- | --- | --- | +| **에이전트** | `agentStart` | `agentEnd` | +| | `agentPause` | `agentResume` | +| **모델** | `modelRequest` | `modelResponse` | +| **툴** | `toolUse` | `toolResult` | +| **훅** | `hookTriggered` | `hookCompleted` | +| **휴먼** | `humanWait` | `humanInput` | + +단독 이벤트는 세 가지: `error`, `humanPause`, `humanInterrupt`. + + + +모든 메서드는 `sessionId`와 `agentId`도 받으며, 스코프가 자동으로 채워줍니다. 생략된 값은 JSON `null`로 전송되지 않고 제거됩니다. + +| 메서드 | 필수 | 선택 | +| --- | --- | --- | +| `agentStart` | — | `goal`, `parentId` | +| `agentEnd` | — | `outcome`, `summary` | +| `agentPause` | `pauseId` | `reason`, `userId` | +| `agentResume` | `pauseId` | `reason`, `userId` | +| `modelRequest` | — | `model`, `messages`, `system`, `tools`, `requestId` | +| `modelResponse` | — | `model`, `stopReason`, `inputTokens`, `outputTokens`, `content`, `role`, `requestId` | +| `toolUse` | `toolName`, `toolCallId` | `input` | +| `toolResult` | `toolName`, `toolCallId` | `output`, `error` | +| `hookTriggered` | `hookName`, `hookId` | `triggerEvent`, `input` | +| `hookCompleted` | `hookName`, `hookId` | `outcome`, `output`, `error` | +| `error` | `errorType`, `message` | `traceback` | +| `humanWait` | `inputId` | `prompt`, `options`, `reason` | +| `humanInput` | `inputId` | `response` | +| `humanPause` | — | `reason`, `userId` | +| `humanInterrupt` | — | `reason`, `userId`, `atStep` | + +추가한 다른 키는 커스텀 페이로드 필드가 됩니다. 프레임워크별 항목은 `fw_*`로 네임스페이싱하세요. 선언된 필드명과 충돌하는 이름은 승격된 컬럼을 조용히 덮어쓰는 대신 거부됩니다. + + + + + **`duration_ms`는 계산되는 값이지 입력받는 값이 아닙니다.** 네 개의 클로저 메서드는 오프너로부터의 경과 시간을 측정하며, 호출자가 전달한 `duration_ms`를 거부합니다 — 보고된 지속 시간은 변조 불가해야 합니다. + + 쌍은 **세션**과 id를 기준으로 매칭되며, 에이전트를 기준으로 하지 않습니다. `planner` 아래에서 열리고 `worker` 아래에서 닫힌 툴도 쌍이 맞춰지는데, 이것이 중첩된 멀티 에이전트 실행에서 실제로 이루어지는 방식입니다. + + +## 프레임워크 어댑터 + +```ts +await failproofai.instrument(); // 찾을 수 있는 모든 프레임워크 +await failproofai.instrument("langchain"); // 정확히 하나 +failproofai.uninstrument(); // 원래대로 되돌리기 +``` + +| 프레임워크 | 지원 버전 | 연결 방식 | +| --- | --- | --- | +| **LangChain.js / LangGraph.js** | `@langchain/core` 0.3 – 1.x, LangGraph.js 0.4 – 1.x | `CallbackManager.configure`를 사용하므로 `callbacks:`를 어디에도 전달하지 않아도 모든 `invoke`/`stream`/`batch`가 커버됩니다 — 또는 `langchainHandler()`를 직접 전달하고 패치하지 않아도 됩니다. | +| **Vercel AI SDK** | `ai` 4 – 7 | 호출 지점에서 `telemetry()` 사용, 또는 `ai` 7에서는 `instrument("ai")`로 전체 프로세스 적용 (4–6에서는 옵트인 — 아래 참조). | +| **Mastra** | `@mastra/core` 0.20 – 1.x | `Agent.generate`/`.stream`, 에이전트의 모델 및 툴 해석, 워크플로우 실행/단계 엔진. | +| **LlamaIndex.TS** | `llamaindex` 0.11.4 – 0.x | `Settings.callbackManager`(구독됨) 및 `AgentWorkflow.runStream` — 워크플로우 실행과 단계 추적. | + +모든 버전 범위는 실제 프레임워크 릴리스를 기준으로, 양 끝 버전에서, ES 모듈과 CommonJS 모두, 매 CI 실행마다 테스트됩니다. + +매핑은 Python SDK의 것과 동일하므로, 같은 프로그램이 어느 언어에서든 동일한 트리를 그립니다. LLM 결정 루프를 소유한 경우에만 **에이전트**입니다 — 그래프/체인 실행, AI SDK `generateText`/`streamText` 호출, Mastra 에이전트, LlamaIndex 에이전트 실행이 해당합니다. LangGraph 노드나 워크플로우 단계는 **훅**(`hook_triggered`/`hook_completed`)이며, 중첩된 에이전트가 아닙니다. 모델 호출은 토큰 카운트가 포함된 `model_request`/`model_response` 쌍으로 기록되며, 툴 호출에는 모델 자체의 툴 call id가 포함됩니다. 실패는 발생한 이벤트에 한 번만 기록됩니다. + +어댑터 설치 실패 시 로그에 기록되고 건너뜁니다. 다른 어댑터는 계속 설치됩니다 — LlamaIndex 문제로 LangGraph를 포기할 필요는 없습니다. + + + `instrument()`를 인수 없이 호출하면 프레임워크를 이미 임포트되었는지가 아니라 **resolve 가능한지** 여부로 감지합니다 — Node는 ES 모듈에 대해 Python의 `sys.modules`에 해당하는 것을 제공하지 않습니다. 설치되어 있지만 사용하지 않는 프레임워크도 임포트되고 패치됩니다. 원하는 프레임워크가 있다면 명시적으로 지정하세요. + + + + 이러한 프레임워크 대부분은 ES 모듈 빌드와 CommonJS 빌드를 각각 제공하며, Node는 이를 두 개의 독립적인 복사본으로 로드합니다. 어댑터는 애플리케이션이 로드하는 복사본(그리고 이미 `require`된 CommonJS 복사본도)을 패치하므로, 두 모듈 시스템 모두 동작합니다. esbuild나 webpack으로 **자체 출력에 번들링된 프레임워크**는 도달할 수 없습니다 — 그 경우에는 호출 지점 헬퍼를 사용하세요: `langchainHandler()`, `telemetry()`, `wrapTool()`. + + +### 패치 없이 LangChain 사용 + +```ts +import { langchainHandler } from "@failproofai/sdk/langchain"; +await graph.invoke(input, { callbacks: [langchainHandler()] }); +``` + +핸들러는 `instrument()` 유무와 관계없이 동작하며 이중 기록이 발생하지 않습니다. `instrument("langchain")`은 Python 어댑터와 마찬가지로 `sessionId`, `captureContent`, `includeChains`, `graphCallbacks`, `captureLimit`를 받습니다. 호출 시 `metadata: { failproofai_sdk_session_id }`를 지정하면 해당 호출의 세션이 선택됩니다. + +### Vercel AI SDK + +AI SDK는 ES 모듈에서 일반 함수를 내보내는데, ES 모듈 네임스페이스는 명세상 불변입니다 — 패치할 방법이 없습니다. SDK 자체가 문서화한 확장 지점을 사용합니다: + +```ts +import { telemetry } from "@failproofai/sdk/ai"; + +const { text } = await generateText({ + model, + prompt, + experimental_telemetry: telemetry({ functionId: "answer-question" }), + // ai 7에서는 `telemetry: telemetry({ … })` — 동일한 객체, 새로운 이름 +}); +``` + +이것이 완전한 통합입니다: 에이전트 스팬, 단계별 토큰 카운트가 포함된 모델 요청/응답 쌍, 모든 툴 호출. 하나의 호출 지점이 모든 메이저 버전에서 동작합니다 — `ai` 4–6은 포함된 트레이서를 읽고, `ai` 7은 텔레메트리 통합을 사용합니다. + +`instrument("ai")`는 **`ai` 7에서** 동일한 작업을 프로세스 전체에 적용합니다: 모든 호출을, AI SDK의 전역 텔레메트리 통합 목록을 통해, 다른 것에서 아무것도 빼앗지 않고 추가 방식으로 처리합니다. + +**`ai` 4–6에서 `instrument("ai")`는 자체적으로 아무것도 기록하지 않으며, 그 사실을 알리는 경고를 한 번 출력합니다.** 해당 메이저 버전들이 가진 유일한 프로세스 전체 훅은 전역 OpenTelemetry 트레이서 프로바이더인데 — 이는 OpenTelemetry가 한 번 점유되면 양도하지 않는 단일 슬롯입니다. 이 슬롯을 등록하면 이후 시작되는 자체 `NodeSDK.start()`가 조용히 거부되어, http/database 스팬이 아무것도 내보내지 않는 트레이서로 전송됩니다. 호출 지점에서 `telemetry()`나 `wrapModel`을 사용하세요. 프로세스에 자체 OpenTelemetry가 없다면 `instrument("ai", { registerGlobalTracer: true })`로 옵트인하세요: 그러면 `experimental_telemetry: { isEnabled: true }`를 전달하는 모든 호출이 기록되며, 슬롯이 비어 있을 때만 점유합니다. `registerGlobalTracer: false`는 기본값을 유지하고 경고를 억제합니다. + +모델을 한 번만 감싸고 싶다면 `wrapModel`을 사용하세요 — 툴 호출은 모델 레이어 위에서 발생하므로 모델 호출만 볼 수 있습니다. 아무것도 감싸지 않고 호출된 wrapped 모델은 자체 실행으로 기록됩니다. 스트리밍 호출은 스트림이 멈추는 방식으로 종료됩니다 — 소비자가 취소하면 `stop_reason: "cancelled"`, 중간에 실패하면 오류와 함께 `"error"`: + +```ts +import { wrapModel } from "@failproofai/sdk/ai"; +const model = await wrapModel(openai("gpt-4o")); +``` + +둘 다 사용해도 됩니다: 미들웨어가 해당 호출이 이미 기록 중임을 감지하고 위임하므로, 각 호출은 한 번만 기록됩니다. + +`functionId`는 에이전트 스팬의 이름을 지정합니다. 낮은 카디널리티로 유지하세요 — `agent_id`로 들어가며, 이는 대시보드의 기본 패싯입니다. + +### Next.js + +`next build`는 기본적으로 서버 의존성을 번들링하는데, 빌드에 번들링된 프레임워크는 `instrument()`가 접근할 수 없는 복사본이 됩니다. 설정을 한 번 감싸고 Next의 시작 훅에서 `instrument()`를 호출하세요: + +```ts +// next.config.ts +import { withFailproofai } from "@failproofai/sdk/next"; +export default withFailproofai({ /* your config */ }); +``` + +```ts +// instrumentation.ts +export async function register() { + if (process.env.NEXT_RUNTIME !== "nodejs") return; + const failproofai = await import("@failproofai/sdk"); + await failproofai.instrument(); +} +``` + +`withFailproofai`는 기존 목록을 유지하면서 LangChain, Mastra, LlamaIndex, SDK 자체를 `serverExternalPackages`에 추가합니다. 없으면 `instrument()`가 도달할 수 없는 프레임워크마다 한 번씩 경고를 출력하고 조용히 실패하지는 않습니다. 패키지를 직접 나열했다면 `FAILPROOFAI_NEXT_EXTERNALS=1`을 설정하세요. Vercel AI SDK와 호출 지점 헬퍼는 어느 경우에도 동작합니다. Edge 라우트는 no-op 빌드를 받으므로 SDK를 임포트해도 안전하며 아무것도 기록되지 않습니다. + +### 스트리밍 호출의 토큰 카운트 + +OpenAI 호환 API는 클라이언트가 요청할 때만 스트림에서 사용량을 보고합니다. LangChain과 Vercel AI SDK는 요청합니다. LlamaIndex는 `OpenAI` LLM에 `additionalChatOptions: { stream_options: { include_usage: true } }`를 전달하고, Mastra는 사용량이 활성화된 모델을 빌드하세요 (예: `createOpenAICompatible({ includeUsage: true })`). 그렇지 않으면 스트리밍 모델 호출에 토큰 카운트가 포함되지 않습니다. + +### 런타임 + +Node ≥ 20.9, Bun, Deno — 모든 프레임워크를, ES 모듈과 CommonJS 모두, Node 트레이스와 대조하며 각각 테스트합니다. SDK는 `failproofaid` 데몬과 함께 실행되며, 데몬이 기록된 내용을 전송합니다. + +## 직접 만든 에이전트 — 프레임워크 없이 + +직접 작성한 에이전트 루프나 어댑터가 없는 프레임워크에 사용합니다. 어댑터가 내부적으로 사용하는 동일한 API로 이벤트를 발행하므로, 트레이스의 형태와 품질이 동일합니다. + +에이전트의 구조를 미리 알 필요가 없습니다. 직접 만든 모든 에이전트는 함수명이 무엇이든 이미 세 가지 위치를 가지고 있으며, 그 세 가지가 전체 통합입니다: + +| 위치 | 추가할 것 | 발행 이벤트 | +| --- | --- | --- | +| **하나의 실행**이 시작하고 끝나는 곳 | `failproofai.agent("name", { goal }, async () => …)` | `agent_start` / `agent_end` | +| **모델을 호출하는 단일 함수** | 전: `event.modelRequest`, 후: `event.modelResponse` — 실패 시에도 두 쌍 모두 | 모델 턴당 하나의 쌍 | +| **툴을 실행하는 단일 함수** | `failproofai.toolCall(name, { toolCallId, input }, () => run())` | `tool_use` / `tool_result` | + +```ts +async function callModel(messages) { + const requestId = randomUUID(); + const started = Date.now(); + failproofai.event.modelRequest({ model: MODEL, requestId, messages }); + try { + const reply = await client.chat.completions.create({ model: MODEL, messages, tools }); + failproofai.event.modelResponse({ + model: reply.model, requestId, stopReason: reply.choices[0].finish_reason, + inputTokens: reply.usage?.prompt_tokens, outputTokens: reply.usage?.completion_tokens, + duration_ms: Date.now() - started, + }); + return reply.choices[0].message; + } catch (error) { + failproofai.event.modelResponse({ model: MODEL, requestId, stopReason: "error", + error: String(error), duration_ms: Date.now() - started }); + throw error; + } +} + +async function dispatch(call) { + const input = JSON.parse(call.function.arguments); + return failproofai.toolCall(call.function.name, { toolCallId: call.id, input }, + () => runTool(call.function.name, input)); +} + +await failproofai.agent("inventory", { goal: question }, async () => { + for (;;) { + const message = await callModel(messages); + if (!message.tool_calls?.length) return message.content; + for (const call of message.tool_calls) await dispatch(call); + } +}); +``` + +식별 정보는 주변에서 자동으로 제공됩니다: `agent()` 내부의 모든 것은 해당 실행의 세션에 id 없이도 연결되며, 에이전트가 자체 데이터베이스에 기록하는 내용을 포함해 프로그램의 다른 부분은 변경되지 않습니다. + +- **서비스나 워커:** 자체 요청 또는 작업 id를 `sessionId`로 전달하면, 대시보드의 세션과 자체 로그 또는 데이터베이스의 레코드가 동일한 문자열이 됩니다. +- **서브 에이전트:** `agent()` 호출을 중첩하세요. 내부 에이전트는 외부 에이전트를 `parent_id`로 하여 세션에 합류합니다. +- **쌍을 발행하세요.** `modelResponse` 없는 `modelRequest`는 대시보드에서 영원히 실행 중으로 표시되는 스팬이 됩니다 — 그래서 `catch`가 필요합니다. + +저장소의 [`sdk/typescript/examples/research-agent.ts`](https://github.com/FailproofAI/failproofai/blob/main/sdk/typescript/examples/research-agent.ts)가 완전하고 실행 가능한 버전입니다: 정확히 이 방식으로 계측된 실제 OpenAI 툴 루프로, ES 모듈과 CommonJS 모두로 매 변경마다 CI에서 실행됩니다. + +## 평가 + +```ts +import { Evaluator, EvalResult, Score } from "@failproofai/sdk/evaluator"; + +export const app = new Evaluator({ name: "my-evals", version: "1" }); + +app.eval("tool_success_rate", { version: "1" }, (session) => { + const results = session.eventsOfType("tool_result"); + const failures = results.filter((event) => event.payload.error != null).length; + return new EvalResult({ + score: new Score(results.length === 0 ? 1 : 1 - failures / results.length), + reasoning: `${failures} of ${results.length} tool calls failed`, + }); +}); +``` + +```bash +FAILPROOFAI_EVALUATOR_URL=… FAILPROOFAI_EVALUATOR_TOKEN=… \ + npx failproofai-evaluator ./my-evals.js +``` + +프로토콜, 워커 설정, 결과 타입에 대해서는 [Evaluator SDK 레퍼런스](/ko/reference/evaluator-sdk)를 참조하세요. + + + **평가는 반드시 yield해야 합니다.** 반환하지 않는 동기 함수는 Node의 단일 스레드를 블록하며, 그 동안에는 어떤 타임아웃도 실행될 수 없습니다. `async` 평가를 작성하세요. + + +## 프로세스에 미치는 영향 + +| | | +| --- | --- | +| **에이전트 루프 블록 안 함** | 이벤트는 인메모리 큐에 들어가고 타이머가 기록합니다. 타이머는 `unref`되어 있으므로, 이 패키지를 임포트해도 스크립트 종료가 막히지 않습니다. | +| **무제한 증가 안 함** | 큐는 개수와 측정된 바이트 수 모두로 제한됩니다. 둘 중 하나를 초과하면 가장 오래된 이벤트가 폐기되고 경고가 출력됩니다 — 텔레메트리 장애가 OOM으로 이어져서는 안 됩니다. | +| **프로세스 종료 안 함** | 인코딩 불가능한 이벤트 하나만 단독으로 폐기되며, 주변 배치는 영향받지 않습니다. 예외를 던지는 getter, 순환 참조, `BigInt`, 단독 surrogate: 각각 처리되고 전파되지 않습니다. | +| **반쪽짜리 배치 남기지 않음** | 콘텐츠는 원자적 rename 전에 `fsync`되고, 디렉터리는 그 후에 `fsync`됩니다. 쓰기 실패 시 임시 파일을 정리합니다. | +| **트랜스크립트를 읽기 가능 상태로 남기지 않음** | 배치는 `0700` 디렉터리 내에서 `0600`으로 저장됩니다. 목표, 프롬프트, 툴 인수, 툴 출력이 포함됩니다. | +| **자격 증명 전송 안 함** | API 키, 토큰, JWT, bearer 헤더, 비밀 형태의 할당값은 바이트가 디스크에 저장되기 전에 삭제됩니다. 데몬은 업로드 전에 다시 한번 삭제합니다. | \ No newline at end of file diff --git a/docs/ko/reference/jev-cloud.mdx b/docs/ko/reference/jev-cloud.mdx new file mode 100644 index 000000000..66059dd78 --- /dev/null +++ b/docs/ko/reference/jev-cloud.mdx @@ -0,0 +1,136 @@ +--- +title: "FailproofAI Cloud를 통한 Jev" +description: "라이브 Jev 정책 검토를 위한 Cloud 머신 키, 연결 상태, 제한 및 오류 동작." +icon: "cloud" +--- + +이 문서는 [Jev 정책](/ko/policies/jev)의 Cloud 경로 참조입니다. TypeSafe의 분류기인 Jev는 각 도구 호출을 실제로 요청한 내용과 비교하여 읽고, 정책 대신이 아니라 정책과 함께 응답합니다. **FailproofAI Cloud**를 통해 연결된 머신은 이미 연결에 사용하는 키로 Jev를 사용합니다. TypeSafe 계정, 두 번째 키, 별도로 구성할 엔드포인트가 필요하지 않습니다. 각 호출은 조직의 기존 플랜 허용량에서 차감됩니다. + +Jev의 모든 동작은 [직접 키 설정](/ko/reference/jev-providers)과 동일합니다. 하드 정책은 최종 결정으로 유지되며, 검토 가능한 정책의 거부는 정확히 해당 우려 사항에 대해 Jev에 물어봤을 때만 해제됩니다. 오류가 발생하면 해당 호출의 정규식 결과로 폴백됩니다. + + +**failproofai 1.0.8-beta.0** 이상이 필요합니다. 1.0.7은 1.0.7 베타보다 정렬 순서가 위에 있더라도 Jev가 없습니다. Jev 구성이 없으면 아무것도 변경되지 않습니다. 훅은 항상 그래왔던 것처럼 정규식 정책만 실행합니다. + + +## 시작하기 전에 + +에이전트가 실행되는 머신에 Failproof AI를 설치하고 [지원되는 하네스](/ko/reference/harnesses)에 훅을 연결하세요. 처음 시작하는 경우, [빠른 시작](/ko/start/quickstart)을 따라 훅 설치까지 진행하세요. `failproofai --version`으로 설치된 CLI를 확인하고, Jev 이전 버전이라면 업데이트하세요. 또한 머신 키를 생성하려면 조직의 **Administration → Keys** 페이지에 접근할 수 있어야 합니다. + +Jev는 `PreToolUse` 또는 `PermissionRequest` 게이트에서 명명된 도구 호출을 검토합니다. 세션의 모든 이벤트를 검토하지는 않습니다. Jev가 정책 거부를 해제하는 것을 확인하려면 [검토 가능](/ko/policies/authority)으로 표시된 정책이 설치되어 있어야 합니다. 다른 모든 정책 거부는 최종 결정으로 유지됩니다. + +## 활성화하기 + +1. **Jev가 포함된 키를 생성합니다.** FailproofAI Cloud 대시보드에서 **Administration → Keys → Create key**를 열고 **machine** 프리셋을 선택하세요. 이는 머신에 필요한 세 가지 권한을 부여합니다. `events:add`(활동 전송), `policies:pull`(정책 수신), `jev:evaluate`(Jev, 조직 플랜에서 차감). 키는 나머지 두 권한 없이 `jev:evaluate`만 가질 수 없습니다. +2. 해당 키로 **머신을 연결합니다.** 프롬프트에서 일회용 시크릿을 읽은 다음 전체 설정 명령을 실행하세요: + + ```bash + read -rs FAILPROOFAI_CLOUD_TOKEN && export FAILPROOFAI_CLOUD_TOKEN + failproofai config + ``` + + `failproofai config`는 데몬을 설치하고, 찾은 에이전트 CLI에 훅을 연결하며, 머신을 연결합니다. 환경 변수는 키가 명령의 인수와 셸 기록에 남지 않도록 합니다. 하네스가 나중에 설치된 경우 [명시적으로 연결하세요](/ko/start/quickstart). + + 조직이 호스팅 서비스가 아닌 자체 FailproofAI Cloud를 운영하는 경우, 주소를 추가하세요: `--url https://` (또는 `FAILPROOFAI_CLOUD_URL` 내보내기). 없으면 키가 호스팅 서비스에 대해 확인되고 연결이 실패합니다. 해당 호스트의 인증서가 프라이빗 CA에서 발급된 경우, CA를 머신의 시스템 신뢰 저장소에 설치하세요(예: `update-ca-certificates`). `NODE_EXTRA_CA_CERTS`만으로는 부족합니다. 이벤트를 전송하고 정책을 가져오는 데몬이 시스템 저장소를 읽습니다. [문제 해결](/ko/reference/troubleshooting)을 참조하세요. + +이것으로 충분합니다. 연결하면 키가 저장되고, 머신에 Jev 구성이 **없는** 경우 **관찰** 모드로 FailproofAI Cloud를 통해 Jev가 활성화됩니다. 팩이 검사를 제공하면 Jev는 게이트된 모든 도구 호출에 대해 질문을 받고 그 결과가 기록되지만, 실제로 적용되는 것은 정책의 결과입니다. 출력에서 이를 확인할 수 있습니다: + +```text + Jev on through FailproofAI Cloud, in observe mode: logged, not enforced (~/.failproofai/jev.json). +``` + +팩이 검사를 제공할 때까지 Jev는 아무것도 묻지 않습니다. Failproof AI는 기본적으로 아무것도 제공하지 않으며, 설치된 팩이 없으면 출력에 그 내용이 표시되고 `failproofai jev status`도 같은 내용을 반복합니다. 다음 명령으로 설치하세요: + +```bash +failproofai policies add FailproofAI/jev-policies +``` + +**`--no-transcripts`와 함께 연결하면 Jev가 활성화되지 않습니다.** Jev는 각 검사된 도구 호출과 최근 프롬프트를 FailproofAI Cloud에 전송하는데, 이는 결정만 전송하도록 요청된 연결보다 더 많은 데이터입니다. 키는 여전히 저장되며, 출력에는 Jev를 사용할 수 있으며 활성화하는 방법이 표시됩니다: + +```bash +failproofai jev setup --provider failproofai +``` + +또한 Jev를 **비활성화**하지도 않습니다. 머신의 `jev.json`이 이미 FailproofAI Cloud를 통해 Jev를 실행하고 있다면, 그대로 유지되며 출력에는 Jev가 여전히 각 검사된 도구 호출과 최근 프롬프트를 전송하고 있으며 `failproofai jev setup --mode off`로 끌 수 있다고 표시됩니다. + + +연결 시 기존 `~/.failproofai/jev.json`을 **절대 덮어쓰지 않습니다.** 자체 Jev 엔드포인트를 이미 사용하고 있다면 계속 사용되며, 출력에는 파일이 그대로 유지되었다고 표시됩니다. 해당 파일에서 Jev가 꺼져 있는 경우(거부되었거나 스위치가 꺼진 경우) 그 이유와 수정 방법도 표시됩니다. 해당 머신을 FailproofAI Cloud로 전환하려면 `failproofai jev setup --provider failproofai`를 실행하세요. + + +## 관찰, 적용 또는 끄기 + +관찰 모드로 시작하고, 정책 페이지에서 Jev가 했을 일을 확인한 다음 실제로 동작하도록 설정하세요: + +```bash +failproofai jev setup --mode enforce # Jev의 결과가 적용됩니다: 검토 가능한 거부를 해제하고 자체 거부를 추가할 수 있습니다 +failproofai jev setup --mode observe # Jev가 질문을 받고 기록되지만 정책 결과가 적용됩니다 +failproofai jev setup --mode off # 구성을 유지하되 Jev에 묻지 않습니다 +``` + +동일한 스위치가 로컬 대시보드에도 있습니다. **Settings → Jev**에는 켜기/끄기 스위치와 관찰/적용이 있습니다. 모드만 변경하고 다른 것은 변경하지 않습니다. 훅은 모든 도구 호출 시 구성을 읽으므로 변경 사항은 다음 호출부터 적용되며, 재시작이 필요하지 않습니다. + +## 동작 확인하기 + +```bash +failproofai jev status +failproofai jev test +``` + +`status`는 공급자를 **FailproofAI Cloud**로, 머신이 연결된 Cloud 호스트, 모드, 키 소스를 **FailproofAI Cloud connection**으로 표시하며 키 자체는 절대 표시하지 않습니다. FailproofAI Cloud `jev.json`이 있지만 Jev를 실행할 수 없는 경우 이유를 표시합니다: + +| `status` 표시 | `status --json` | 의미 | +| --- | --- | --- | +| **off — no Jev key is stored for this machine's FailproofAI Cloud connection** | `key-lacks-jev` | 머신이 연결되어 있지만 Jev 키가 저장되어 있지 않습니다. 키에 `jev:evaluate`가 없거나 연결 시 확인할 수 없었습니다. `FAILPROOFAI_CLOUD_TOKEN`에 키를 넣어 `failproofai config`를 다시 실행하세요. 권한이 없는 경우 **machine** 키를 사용하세요. | +| **off — this machine is not connected to FailproofAI Cloud** | `not-connected` | 이 머신에 Jev 키가 속할 FailproofAI Cloud 연결이 없습니다. | + +`failproofai config --disconnect` 후에는 FailproofAI Cloud `jev.json`이 더 이상 없습니다(꺼진 상태였다면 유지됨). 따라서 `status`는 단순히 Jev가 꺼져 있다고 보고합니다. `status --json`은 구성이 없거나 거부된 경우에도 동일한 정보(`provider: "failproofai"`, `keySource: "cloud"`, `cloudConnected`, `keyCarriesJev`)를 포함합니다. `permissions`는 항상 `jev.json`의 권한이며, `credentials.json`에 대한 거부가 있으면 `credentialsPermissions`가 추가되고, 단일 명령으로 수정할 수 있을 때 `fix`가 포함됩니다. `test`는 실제 요청 하나를 전송하고 지연 시간과 응답한 Jev 버전을 보고합니다. 응답이 훅 타임아웃 후에 도착하거나(훅은 `timeout`을 기록함) 검사 질문에 잘못 답변하면 종료 코드 1과 함께 제목에 표시합니다. + +대시보드의 **Settings → Jev** 패널에도 **FailproofAI Cloud connection**이 표시됩니다. 머신이 보고하는 조직과 키에 Jev가 포함되어 있는지 여부를 확인할 수 있습니다. 네트워크 호출 없이 머신의 자체 파일에서 읽습니다. + +## 실제 호출 확인하기 + +훅이 연결된 에이전트에서 새 세션을 시작하세요. `README.md`에 파일 읽기 도구를 사용하여 제목을 보고하도록 요청하세요. 세션에 해당 도구 호출이 포함되어 있는지 확인한 다음 `failproofai jev status`를 다시 실행하세요. 최근 평가된 호출 수가 증가해야 합니다. [로컬 대시보드](/ko/reference/local-dashboard#review-policy-activity)의 **Policies → Activity**를 열어 해당 호출의 Jev 결과와 모드를 검사하세요. Cloud에서는 조직의 **Policies** 페이지에 전달된 활동의 Jev 결과가 표시됩니다. 관찰 모드에서는 결과가 **would-have**로 기록되며 정책 결과가 여전히 호출을 결정합니다. 검토 가능한 정책이 일치하고 Jev가 명명된 검사를 해제한 경우에만 해제가 표시됩니다. + +## 정책 페이지에 전달되는 내용 + +머신은 이미 훅 활동을 FailproofAI Cloud에 전송합니다(`events:add`). Jev가 활성화되면 각 게이트된 호출 레코드에 실행된 평가기, Jev의 결정, 해제된 정책, 폴백 이유(해당하는 경우), 지연 시간, 응답한 모델이 포함됩니다. 명령이나 프롬프트가 아닌 결정, 코드, 이름만 포함됩니다. 조직의 **Policies** 페이지에서: + +- Jev의 자체 결과로 결정된 호출(적용 모드)은 **Jev**로 귀속되며, 결정적인 검사가 팩에서 온 경우 레코드에 해당 팩과 버전도 표시됩니다. +- 관찰 모드에서는 Jev의 거부 또는 경고가 관찰 중인 롤아웃 옆에 **would-have**로 표시됩니다. +- Jev가 해제했거나 관찰 모드에서 해제했을 정책이 정책별로 집계됩니다. + +## Jev가 응답할 수 없을 때 + +다음 모든 경우는 해당 호출의 정책 결과로 폴백되며, 이유와 함께 기록됩니다: + +| 이유 | 원인 | +| --- | --- | +| `out-of-credits` | 조직의 플랜 허용량을 모두 사용했습니다. | +| `http-401`, `http-403` | 키가 해지되었거나 `jev:evaluate`가 없습니다. 해당 권한이 있는 키로 다시 연결하세요. | +| `http-429` | FailproofAI Cloud가 조직에 대해 Jev를 속도 제한하고 있습니다. 요청한 대기 시간(`Retry-After`, 최대 60초)이 끝날 때까지 머신은 아무것도 전송하지 않고 모든 호출이 즉시 폴백됩니다. 이런 방식으로 보류된 호출은 `http-429`로 기록되거나, 머신 자체 속도 제한이 먼저 적용되면 `rate-limited`로 기록됩니다. | +| `http-429` (일일 한도) | 조직의 일일 Jev 호출을 모두 사용했습니다. FailproofAI Cloud 운영자가 다른 한도를 설정하지 않은 경우 **UTC 기준 하루 10,000회**입니다. 카운트가 00:00 UTC에 리셋될 때까지 모든 호출이 폴백됩니다. 머신은 최대 1분에 한 번 다시 시도하므로 1분 이내에 리셋을 감지합니다. `failproofai jev test`는 "Daily Jev limit for this org reached; resets at 00:00 UTC."라고 표시합니다. | +| `http-422` | Jev가 이 호출의 요청을 거부했습니다. 일반적으로 도구 호출에 Jev의 토큰 예산을 초과하는 고밀도 텍스트(base64, hex, 압축 코드)가 포함된 경우입니다. 해당 호출은 매번 폴백됩니다. 장애가 아닙니다. | +| `http-502` | Jev를 현재 사용할 수 없습니다. | +| `http-503` | 이 Cloud는 조직에 Jev를 제공할 수 없습니다. 모델 게이트웨이가 없거나, 조직이 아직 프로비저닝되지 않았거나, 게이트웨이가 다운되었습니다. 관리자에게 문의하세요. 훅은 최대 1분에 한 번 다시 시도합니다. | +| `http-404` | 이 FailproofAI Cloud는 아직 Jev를 제공하지 않습니다. | +| `timeout` | `timeoutMs`(기본값 3000) 내에 응답이 없습니다. | +| `model-mismatch` | 1.13이 아닌 다른 Jev 버전이 응답했습니다. | + +## 키의 저장 위치와 전송 대상 + +- 키는 `~/.failproofai/credentials.json`(`0600`, 소유자 전용 디렉터리)에 한 번 저장되며, 다른 FailproofAI Cloud 자격 증명과 함께 저장됩니다. 이 경로에서는 `jev.json`에 키가 없습니다. 여기에 키를 작성하면 구성이 유효하지 않게 됩니다. +- `credentials.json`에 소유자 이외의 사람(그룹 또는 기타, 읽기 또는 쓰기)에 대한 권한이 있거나, 해당 디렉터리가 소유자 이외의 사람에 의해 **쓰기** 가능한 경우, 파일을 읽지 않고 **거부**되며 수정할 때까지 Jev가 꺼집니다. 파일에 `chmod 600`, 디렉터리에 `chmod 700`을 실행하거나(또는 재연결하면 파일이 `0600`으로 다시 작성되고 디렉터리가 소유자 전용으로 설정됨) 문제를 해결하세요. 다른 사람이 읽기만 할 수 있는 디렉터리는 괜찮습니다. 쓰기 가능한 디렉터리는 파일 교체를 허용합니다. +- 키는 연결과 함께 있을 때만 유효합니다. 동일한 파일에 동일한 키를 사용하는 동일한 FailproofAI Cloud의 정책 또는 보고 자격 증명이 있어야 합니다. 연결 없이 남겨진 Jev 키는 무시되며 Jev는 꺼진 상태로 유지됩니다. 이는 이전 버전의 failproofai `config --disconnect`가 Jev 키를 남겨두거나(제거하는 방법을 모름), 이전 버전의 failproofai `config --token`이 다른 키로 연결할 때 발생할 수 있습니다. FailproofAI Cloud에서 다른 키는 다른 조직에 속할 수 있습니다. Jev를 다시 활성화하려면 **machine** 키로 다시 연결하세요. +- 키는 검증된 Cloud 원본에만 전송됩니다. 다른 곳을 가리키는 `jev.json`은 거부됩니다. +- **머신의 에이전트가 읽을 수 있습니다.** `credentials.json`은 소유자 전용이며 에이전트는 해당 소유자로 실행됩니다. failproofai 자체 파일 읽기는 의도적으로 허용되어 있습니다(변경만 `block-failproofai-commands`로 차단됨). 따라서 에이전트와 이 파일 사이에는 `block-read-outside-cwd`(*검토 가능한* 정책)만 있으며, 홈 디렉터리에서 시작된 세션에서는 아무것도 없습니다. `jev:evaluate`가 있는 키는 사용되는 곳에서 조직의 Jev 허용량(일일 상한까지)을 소비하므로, 머신 키를 다른 지출 자격 증명처럼 취급하세요. 에이전트가 키를 읽었을 수 있다면 Keys 페이지에서 비활성화하고 새 키로 재연결하세요. +- 이 설정은 글로벌 파일에서만 결정됩니다. 저장소는 Cloud Jev를 활성화하거나, 다른 곳을 가리키거나, 키를 제공할 수 없으며, `FAILPROOFAI_JEV_API_KEY`는 이 경로에서 무시됩니다. +- Jev가 평가하는 각 호출에 대해 FailproofAI Cloud에 하나의 요청이 전송되며, [직접 키 페이지](/ko/reference/jev-providers#what-leaves-the-machine)에 나열된 내용이 포함됩니다(시크릿은 삭제됨). FailproofAI Cloud는 이를 TypeSafe에 전달하며 기록하거나 보관하지 않습니다. + +## 끄기 + +| 명령 | 결과 | +| --- | --- | +| `failproofai jev setup --mode off` | 구성을 유지하되 Jev에 묻지 않습니다. **이것이 지속되는 스위치입니다.** 다시 연결해도 기존 `jev.json`을 덮어쓰지 않으므로, `--mode observe`로 다시 켜기 전까지 Jev는 꺼진 상태를 유지합니다. | +| `failproofai jev remove` | `~/.failproofai/jev.json`을 삭제합니다. Jev가 꺼집니다. 단, `jev:evaluate`가 있는 키로 `failproofai config --token`을 다음에 실행하면 `jev.json`이 없으므로 관찰 모드로 Jev가 다시 활성화됩니다(`--no-transcripts`로 실행하지 않는 한). 꺼진 상태를 유지하려면 `--mode off`를 사용하세요. | +| `failproofai config --disconnect` | 머신 연결을 끊습니다. 키가 제거되며, `jev.json`이 FailproofAI Cloud를 가리키고 꺼져 있지 않으면 함께 제거됩니다. 자체 엔드포인트에 대한 `jev.json`은 유지되며, 꺼진 상태의 `jev.json`도 유지되므로 다시 연결할 때 Jev는 꺼진 상태를 유지합니다. | + +다음 도구 호출부터 훅은 이전과 정확히 같이 정규식 정책만 실행합니다. \ No newline at end of file diff --git a/docs/ko/reference/jev-evaluations.mdx b/docs/ko/reference/jev-evaluations.mdx new file mode 100644 index 000000000..99b1814be --- /dev/null +++ b/docs/ko/reference/jev-evaluations.mdx @@ -0,0 +1,88 @@ +--- +title: "Jev 평가 레퍼런스" +description: "Jev 세션 평가의 질문 유형, 보정된 점수, 제한 사항, 소급 적용에 대한 설명입니다." +icon: "list-checks" +--- + +이 페이지는 [Jev 평가](/ko/evaluations/jev)의 질문 형식과 채점 규칙을 설명합니다. 일부 질문은 대화를 *읽는* 것만 필요하고, 그에 대해 *서술*할 필요는 없습니다. "고객이 긴박감을 표현했나요?"는 두 가지 답변이 존재합니다. "고객이 얼마나 불만스러워했나요?"는 순서가 있는 몇 가지 답변이 존재합니다. 질문하기 전에 모든 답변을 이미 알고 있는 거죠. + +**분류기 평가(classifier evaluation)**는 바로 그런 경우를 위한 것입니다. 질문과 가능한 답변을 직접 작성하면, 분류를 위해 만들어진 소형 모델이 보정된 숫자를 반환합니다 — 자유 형식 텍스트는 절대 반환하지 않습니다. + + +판정자(judge)와 마찬가지로 분류기 평가도 세션당 모델 호출 비용이 발생합니다. 다만 판정자와 달리 범용 모델이 아닌 소형의 단일 목적 모델이기 때문에, 더 빠르고 저렴합니다 — 하지만 자체적으로 설명을 제공하지는 않습니다. 추론 과정이 필요하다면 [판정자(judge)](/ko/evaluations/judge)를 사용하세요. + + +## 어떤 것을 선택해야 할까요? + +| 질문 | 사용 방법 | +| --- | --- | +| 도구 호출이 몇 번 있었나요? | code | +| 세션이 30초 미만이었나요? | code | +| 고객이 긴박감을 표현했나요? | **classifier** | +| 어느 팀이 처리해야 하나요: 청구, 기술, 또는 영업? | **classifier** | +| 고객이 얼마나 불만스러워했나요? | **classifier** | +| 답변이 실제로 정확했나요? | **judge** | +| 에스컬레이션 정책을 따랐나요, 그렇게 생각하는 이유는 무엇인가요? | **judge** | + +기본 원칙: **셀 수 있는 것 → code, 목록으로 나열할 수 있는 답변 → classifier, 설명이 필요한 것 → judge.** + +미리 결정할 필요는 없습니다. 측정하고 싶은 것을 설명하면 어시스턴트가 선택하고, 어떤 것을 선택했는지와 그 이유를 알려주며, 변경도 가능합니다. + +## 두 가지 질문 유형 + +### `noul` — 이것이 사실인가요? + +두 가지 답변이 있으며, 양쪽 모두를 직접 설명합니다. 결과는 "true" 설명이 해당하는 확률입니다: + +```json +{ + "instructions": "Did the assistant promise a refund without first checking the refund policy?", + "criteria": { + "true": "A refund was promised or issued with no prior policy check or approval", + "false": "No refund was promised, or every refund followed a policy check" + } +} +``` + +양쪽 모두를 설명하세요. "긴박감이 표현되지 않음"도 실제 답변이며, 이를 명시하면 반대 답변이 더 명확해집니다. + +### `score` — 이것이 얼마나? + +순서가 있는 루브릭으로, **가장 낮은 것부터** 시작합니다. 결과는 세션이 루브릭 위에서 위치하는 지점이며, 0–1로 재조정됩니다: + +```json +{ + "instructions": "How frustrated is the customer?", + "criteria": ["Calm", "Frustrated", "Very angry"] +} +``` + +**루브릭은 3~5개의 레벨로 구성되며, 모두 서로 달라야 합니다.** 두 제한 모두 스타일 문제가 아닌 측정 문제에서 비롯된 것입니다: + +- **레벨이 두 개**이면 `noul`이 이미 더 잘 처리하는 방식으로 수렴하고, **다섯 개를 초과**하면 모델이 확정 짓지 않고 중간값으로 치우치게 됩니다. 동일한 질문을 동일한 세션에 대해 채점했을 때, 레벨이 2개이면 0.00, 3개이면 0.01, 10개이면 0.55가 나왔습니다. +- **반복되는 레벨**은 답변을 임의로 분산시킵니다. 명백히 화가 난 세션이 `["Calm", "Frustrated", "Very angry"]`에 대해 1.00을 기록했지만, `["Angry", "Angry", "Angry"]`에 대해서는 0.66을 기록했습니다 — 수치 자체는 유효하지만 아무 의미가 없습니다. + +순서가 없는 카테고리 — "청구, 기술, 또는 영업" — 는 루브릭이 아닙니다. 카테고리별로 `noul`로 질문하거나 판정자(judge)를 사용하세요. + +## 결과 해석하기 + +분류기는 판정자와 마찬가지로 0~1 사이의 **점수**를 생성하므로, 차트, 필터링, 알림 트리거 방식도 동일합니다. 두 가지 차이점을 알아두세요: + +- **추론이 제공되지 않습니다.** 해당 필드는 의도적으로 비어 있습니다. 이 모델은 자체적으로 설명하지 않으며, 설명을 만들어내는 것은 기능이 아닌 조작이 될 것입니다. +- **불확실성에 레이블이 붙습니다.** `score` 질문은 자체 신뢰도를 보고하며, 모델이 확신하지 못한 결과에는 `low_confidence` 태그가 붙습니다 — 따라서 "사람이 검토해야 할 항목"을 찾는 것이 추측이 아닌 필터 작업이 됩니다. `noul` 질문은 신뢰도를 보고하지 않으므로 태그가 붙지 않습니다. + +매우 긴 세션은 발췌문으로 읽고 통합됩니다. 세션이 전체를 읽기에 너무 길 경우, 결과에 몇 개의 턴이 제외되었는지 표시됩니다 — 전체 세션을 기반으로 한 판단인 것처럼 일부 세션에 대한 판단이 표시되는 일은 절대 없습니다. + +## 제한 사항 + +- **루브릭 레벨은 3~5개이며, 모두 달라야 합니다.** 위 내용 참고; 양쪽 제한 모두 작성 시점에 적용됩니다. +- **평가당 하나의 질문만 가능합니다.** 두 가지를 물으면 두 개의 평가가 생성되며, 차트에서도 그 편이 더 유용합니다. +- **질문을 수정하면 새 버전이 배포됩니다.** 이전 점수와 새 점수는 비교할 수 없으므로, 하나의 추세선으로 혼합하지 않고 분리하여 유지됩니다. +- **분류기는 항상 점수를 생성하며**, 메트릭이나 단언(assertion)은 생성하지 않습니다. +- 위에서 설명한 대로 **추론이 없습니다**. 숫자를 보고 "왜?"라는 질문이 생길 것 같다면, 대신 판정자(judge)를 작성하세요. + +## 테스트 및 소급 적용 + +판정자(judge)와 달리 분류기 평가는 배포 전에 **테스트할 수 있습니다** — code 평가와 동일한 방식으로 실제 세션에 대해 [테스트](/ko/evaluations/test)하고, 라이브 적용 전에 점수를 확인하세요. + +이미 보유한 세션에 대해 [소급 적용](/ko/evaluations/deploy#score-sessions-you-already-have)도 가능합니다. 세션당 모델 호출 비용이 발생하므로, 모든 것을 재처리하는 대신 기간을 신중하게 지정하세요. \ No newline at end of file diff --git a/docs/ko/reference/jev-intent.mdx b/docs/ko/reference/jev-intent.mdx new file mode 100644 index 000000000..6304e1ab9 --- /dev/null +++ b/docs/ko/reference/jev-intent.mdx @@ -0,0 +1,112 @@ +--- +title: "Jev 의도 캡처" +description: "어떤 하네스 이벤트가 Jev 평가자에게 사람이 요청한 내용을 알려주는지, 어떤 필드가 텍스트를 전달하는지, 무엇이 절대 집계되지 않는지, 그리고 하네스가 전달한 프롬프트를 신뢰할 때 발생하는 위험에 대해 설명합니다." +icon: "message-square-quote" +--- + +[Jev 정책 검토](/ko/policies/jev)를 구성하면, 평가자는 각 게이트된 도구 호출을 하네스가 에이전트 앞에 놓은 텍스트가 아닌 **사람이 요청한 내용**에 비추어 판단합니다. "네, 강제 푸시하세요"와 같은 답변은 **reviewable** 정책을 통과시킬 수 있습니다 — 요청을 읽을 수 없는 정규식은 실제 작업의 3분의 1을 막아버리기 때문에, 이것이 바로 평가자의 존재 이유입니다. + +해당 텍스트는 한 곳에서 옵니다: **하네스 자체가 프롬프트 제출 이벤트 시점에 훅에 전달하는 프롬프트**입니다. Failproof AI는 사람이 입력한 부분을 기록합니다 — 하네스 래핑은 제거되고, 비밀 정보는 삭제되고, 크기는 제한됩니다 — 자체 상태 디렉터리 아래의 `0600` 파일에 저장됩니다. 디스크에 있는 내용은 참조하지 않습니다: 세션 트랜스크립트는 에이전트가 명령 하나로 다시 쓸 수 있는 파일이므로, 누가 프롬프트를 작성했는지 묻지 않습니다. + +## 이 방식이 받아들이는 위험, 명확하게 + +명령을 이미 실행할 수 있는 에이전트는 하네스가 프롬프트를 제출하도록 만들 수 있습니다. `claude -p "…"`, `codex exec`, `copilot -p`, `cursor-agent -p`, `devin -p`, `droid -p`, `goose run -t`, `pi -p`는 모두 에이전트가 제어하는 자식 세션에서 사람이 직접 입력하는 것과 동일한 프롬프트 제출 이벤트를, 동일한 페이로드로 발생시킵니다. 또한 Failproof AI의 훅 바이너리를 직접 실행하여 자신이 작성한 페이로드를 공급할 수도 있습니다. Failproof AI 내부의 어떤 것도 이를 실제와 구별할 수 없습니다 — 둘 다 동일한 프로그램이 동일한 stdin을 읽는 것입니다. + +**따라서 셸을 가진 에이전트는 자신의 동의를 위조할 수 있습니다.** 이것은 2026-09-23에 의식적으로 받아들인 트레이드오프이며, 그 양면은 다음과 같습니다: + +- **얻는 것.** 대안을 구축하고 측정했습니다: 하네스가 프롬프트 작성자로 사람을 명시하는 필드를 요구하고, 그렇지 않으면 아무것도 기록하지 않는 방식입니다. 어떤 출하된 하네스도 그런 필드를 보내지 않으므로, 해당 버전은 **모든 하네스에서 아무것도 기록하지 못했습니다** — Jev는 명시된 의도 없이 모든 호출을 판단하여 단 하나의 정책도 통과시킬 수 없었습니다. 절대 작동하지 않는 캡처는 더 안전한 제품이 아니라, 아예 제품이 아닙니다. +- **할 수 없는 것.** 기록된 프롬프트는 **reviewable**로 표시된 정책만 통과시킬 수 있습니다. **hard** 정책은 Jev가 뭐라고 해도 절대 통과되지 않으므로, 위조된 프롬프트는 hard deny를 allow로 전환할 수 없습니다 — 훅을 건너뛰어도 에이전트에게는 아무 이득이 없습니다: 하네스는 도구 호출에 대해 Failproof AI를 독립적으로 호출합니다. +- **최대 규모에서 할 수 있는 것.** 최악의 경우 15개의 reviewable 내장 정책 중 하나를 통과시킬 수 있습니다 — **그 15개 중 12개는 차단합니다**. `protect-env-vars`, `block-env-files`, `block-read-outside-cwd`, `block-rm-rf`, `block-force-push`, `block-secrets-write`와 6개의 인프라 CLI 차단(`block-kubectl`, `block-terraform`, `block-aws-cli`, `block-gcloud`, `block-az-cli`, `block-helm`)은 deny이므로, 위조된 동의는 환경 비밀 출력, `.env` 파일 읽기, 프로젝트 외부 읽기, `rm -rf`, 강제 푸시, 비밀 파일 쓰기, 또는 라이브 인프라 변경에서 실제 deny를 allow로 전환할 수 있습니다. `warn-git-amend`, `warn-destructive-sql`, `warn-global-package-install`만 경고입니다. 기본 설치는 12개 중 두 개(`protect-env-vars`와 `block-env-files`)를 활성화하며, 나머지 10개는 누군가가 활성화한 머신에서만 적용됩니다. 어떤 프롬프트도 도달할 수 없는 것은 모든 hard 정책입니다 — `block-sudo`, `block-curl-pipe-sh`, `block-push-master`, `block-work-on-main`, 에이전트가 Failproof AI를 비활성화하지 못하도록 하는 가드, 그리고 reviewable로 표시되지 않은 다른 모든 내장 정책들. [정책 권한](/ko/policies/authority)은 15개 전체와 각각이 무엇에 의해 검토되는지를 나열합니다. + +여전히 거부되는 것은 확인하기 쉽고 에이전트가 단순히 요청만으로는 얻을 수 없는 모든 것입니다: 하네스 자체의 페이로드가 기계 제출로 표시한 턴, 서브 에이전트를 지명한 페이로드, 일반 이름이 아닌 세션 ID, 프롬프트 제출 이벤트가 아닌 이벤트, 그리고 하네스 래핑만으로 이루어진 텍스트 — 여러 하네스가 다음 사용자 턴으로 돌려보내는 Failproof AI 자체의 중단 게이트 단어 포함. + +## 하네스별 표 + +"텍스트 필드"는 Failproof AI의 하네스별 정규화 이후 stdin 페이로드 필드입니다. "기록됨"은 프롬프트가 사람의 요청으로 저장되는지 여부를 나타냅니다. + +| 하네스 | `--cli` | 프롬프트 이벤트 → 정규화 | 텍스트 필드 | 기록됨 | 에이전트의 마지막 메시지 출처 | +| --- | --- | --- | --- | --- | --- | +| Claude Code | `claude` | `UserPromptSubmit` | `prompt` | 예, 페이로드의 `source`가 아무도 제출하지 않은 턴(`loop_wakeup`, `schedule_wakeup`, `poll_event`, `system`)을 명시하지 않는 한. `user`, `sdk`, 알 수 없는 값, `source`를 전혀 보내지 않는 빌드는 모두 기록됩니다 | 세션 트랜스크립트(`transcript_path`) | +| Codex | `codex` | `user_prompt_submit` → `UserPromptSubmit` | `prompt` | 예 | 롤아웃 JSONL(`agent_message`, `AgentMessage`) | +| GitHub Copilot CLI | `copilot` | `UserPromptSubmit` | `prompt` | 예 | `events.jsonl`(`assistant.message`) | +| Cursor | `cursor` | `beforeSubmitPrompt` → `UserPromptSubmit` | `prompt` | 예, 전체 프롬프트가 `` 래퍼일 때 이를 제거 | 에이전트 트랜스크립트 JSONL | +| OpenCode | `opencode` | `message.updated`(사용자 역할) → `UserPromptSubmit` | `prompt` | 예 — 단 현재 OpenCode는 해당 이벤트에 텍스트를 포함하지 않으므로 실제로는 아무것도 기록되지 않습니다; 동일한 메시지의 반복은 한 번만 기록됩니다 | 없음 (세션은 SQLite) | +| Pi | `pi` | `input` → `UserPromptSubmit` | `prompt` | 예, `input_source`가 `extension`이 아닌 경우 — 텍스트가 모델이 작성하거나 저장소에서 파생될 수 있는 다른 확장의 `sendUserMessage()` | Pi 세션 JSONL | +| Hermes | `hermes` | 없음 | — | 아니오 — Hermes에는 프롬프트 제출 이벤트가 전혀 없습니다 | — | +| OpenClaw | `openclaw` | `before_agent_run` → `UserPromptSubmit` | `prompt` | 예, 실행 메타데이터가 해당 실행을 기계의 것으로 표시하지 않는 한: `user` 이외의 `trigger`, `external_user` 이외의 `inputProvenance.kind`, 또는 `senderIsOwner: false` | 없음(`before_agent_run`에는 트랜스크립트 경로가 없음) | +| Factory Droid | `factory` | `UserPromptSubmit` | `prompt` | 예 | 드로이드 세션 JSONL | +| Devin CLI | `devin` | `UserPromptSubmit` | `prompt` | 예 | 없음 (세션은 SQLite) | +| Antigravity CLI | `antigravity` | `PreInvocation` → `UserPromptSubmit` | 없음 | 아니오 — `PreInvocation`은 턴 내의 *모든* 모델 호출 전에 발생하며 프롬프트 텍스트를 포함하지 않습니다 | — | +| Goose | `goose` | `UserPromptSubmit` | `message` | 예 | 없음 (세션은 SQLite) | + +두 하네스는 아무것도 기록하지 않으며, 두 경우 모두 같은 이유입니다: 해당 이벤트가 사람의 텍스트를 전달하지 않습니다. Hermes에는 프롬프트 제출 이벤트가 없습니다 — 네이티브 플러그인이 `pre_llm_call`을 직접 처리하며 도구, 세션, 서브에이전트 이벤트만 전달합니다. Antigravity의 `PreInvocation`은 사람의 턴에서도, 그 뒤를 잇는 다섯 턴에서도 모든 모델 호출 전에 발생하며 프롬프트 필드가 없습니다; 훅은 동일한 대화에 `userMessage` 단계를 주입할 수도 있습니다. 두 이벤트 중 어느 것도 기록할 내용이 없습니다. + +## 프롬프트가 사람의 것인 조건 + +1. **이벤트.** Failproof AI가 하네스의 프롬프트 제출 이벤트를 위해 호출되었으며, 핸들러가 이를 `UserPromptSubmit`으로 정규화합니다. +2. **페이로드.** 하네스가 훅의 stdin에 작성하며, 위에서 명명된 필드에 텍스트를 포함합니다. 페이로드 없이 Failproof AI에 도달하는 호출은 아무것도 기록하지 않습니다. +3. **페이로드의 어떤 것도 해당 턴을 배제하지 않습니다.** 서브 에이전트를 명시하는 페이로드(`agent_id`)는 에이전트가 자신에게 프롬프트를 보내는 것입니다. 기계 제출 턴을 명시하는 `source`, `input_source` 또는 OpenClaw 실행 마커는 거부됩니다. **없는** 마커는 아무것도 배제하지 않습니다 — 이것이 아무것도 기록하지 않던 버전과의 차이점입니다: 모든 마커가 모든 출하 빌드에서 없기 때문입니다. +4. **래핑이 제거된 후 무언가가 남습니다** (아래 참조). + +**세션 트랜스크립트는 누가 프롬프트를 작성했는지의 증거가 아닙니다.** 이 페이지의 이전 버전에서는 트랜스크립트 교차 확인을 설명했습니다: 트랜스크립트가 모델이 프롬프트를 예약한 것을 보여주면 프롬프트가 거부되었고, 트랜스크립트는 이전 프롬프트가 본 것을 이어가야 했습니다. 해당 확인은 사라졌습니다. 트랜스크립트는 에이전트가 이미 셸 접근권을 가진 파일입니다 — 잘라내거나, 교체하거나, 읽기 예산을 초과하도록 패딩하거나, 턴 시작 시 스냅샷을 찍고 끝에 복원하거나, 에이전트가 작성한 항목으로 다시 보기 좋게 만들 수 있습니다. 강화의 각 라운드는 동일한 위조의 다른 형태로 이어졌으므로, 전체 메커니즘을 수리하는 대신 제거했습니다. + +트랜스크립트는 한 가지 용도로만 읽힙니다: **에이전트의 마지막으로 보이는 메시지**. 그 메시지는 정의상 에이전트가 작성한 것이며, Jev에게 그렇게 알려지고, 그 자체만으로는 절대 동의가 되지 않습니다. + +## 프롬프트에서 보존되는 내용 + +하네스는 프롬프트에 사람의 말 이상을 넣습니다. 저장되기 전에: + +- `` 블록이 제거되고, 그 주변의 사람 말은 보존됩니다. +- 세션 계속 요약("이 세션은 이전 대화에서 계속됩니다…")은 전체가 삭제됩니다. +- 작업 알림, 로컬 명령 출력, 중단 마커는 전체가 삭제됩니다. +- 다른 에이전트나 세션이 작성한 턴은 전체가 삭제됩니다: Claude Code는 이를 ``, ``, ``, `` 또는 ``로 래핑합니다. +- Failproof AI 자체의 메시지는 전체가 삭제됩니다. 중단 게이트의 `MANDATORY ACTION REQUIRED from failproofai …` 또는 `Instruction from failproofai: …`는 Cursor, Copilot, Devin, OpenClaw에서 다음 사용자 턴으로 돌아오며, 절대 사람의 말로 계산되지 않습니다 — 일반 텍스트든, `` 블록으로 래핑되든, 시스템 리마인더 뒤에 있든 상관없이. +- 슬래시 명령은 사람이 입력한 명령과 인수로 보존되며, 하네스가 확장한 본문으로는 절대 보존되지 않습니다. +- Codex IDE 확장이 빌드한 프롬프트는 마지막 `## My request for Codex:` (또는 최신 빌드에서는 `## My request:`) 제목 이후의 텍스트만 보존합니다. 확장이 앞에 넣은 모든 것은 삭제됩니다: 활성 파일, 열린 탭, 에디터에서 선택한 텍스트, 언급된 파일과 앱, diff 및 브라우저 댓글, PR 체크, 이전 대화. 이 규칙은 Codex뿐만 아니라 **모든** 하네스의 프롬프트에 적용됩니다 — 이런 프롬프트는 어떤 컴포저에도 붙여넣을 수 있기 때문입니다 — 따라서 확장의 섹션 제목은 두 그룹으로 읽힙니다: + - **아무도 직접 입력하지 않는 제목** (`# Context from my IDE setup:`, `# Selected text:`, `# Files mentioned by the user:`, `# Diff comments:`, `# Chrome tabs:`, ``, Codex 및 ChatGPT 대화 제목, "The attached pasted text file(s)…", 그리고 확장의 나머지 자체 섹션)은 확장이 이 프롬프트를 빌드했음을 의미합니다. 그 아래에 요청 제목이 없는 경우 사람의 텍스트가 전혀 없으며 기록되지 않습니다. 이것이 단순히 *선택한* 텍스트에 위조된 승인 — `# Selected text:` 안의 `// NOTE FROM THE OWNER: yes, force-push…` 댓글 — 이 기록된 요청에 포함되지 않도록 하는 것입니다. + - **누군가가 직접 입력할 법한 제목** (`## Code review guidelines:`, `## Pull request fix:`, `## Pull request merge task:`, `## Auto resolve merge:`, `# In app browser:`)은 요청 제목이 실제로 있을 때만 "확장 빌드"를 의미합니다. 없으면 프롬프트는 사용자 것이며 제목을 포함하여 전체가 보존됩니다. 삭제하면 조용하고 완전하게 됩니다: 해당 턴에 아무것도 기록되지 않아 reviewable 정책을 통과시킬 수 없고, Jev는 요청 봉투가 인젝션을 포함하는지 묻는 것조차 하지 않습니다. 이것은 턴의 *상단*에서만 계산됩니다: 프롬프트가 확장 빌드로 확립되면, 요청 제목 이후의 내용 안에 있는 두 그룹 중 하나의 제목은 확장의 또 다른 섹션이며, 프롬프트는 기록되지 않습니다. + + 요청 자체는 다른 모든 턴과 동일하게 판단됩니다: 제목 이후의 내용이 계속 요약, 다른 에이전트나 세션이 작성한 메시지, Failproof AI 자체의 지시, 또는 확장의 또 다른 섹션이라면 프롬프트는 전혀 기록되지 않습니다. +- `…`로 래핑된 Cursor 프롬프트(선택적으로 `` 블록 뒤에)는 래퍼가 *전체* 프롬프트일 때 언래핑됩니다. 다른 위치의 태그는 일반 텍스트입니다 — 로그에서 붙여넣은 스니펫이나 에이전트가 선택한 브랜치 이름 — 이 경우 프롬프트는 태그된 범위로 잘리지 않고 전체가 보존됩니다. +- 붙여넣은 블록은 보존되고 사람이 붙여넣은 것으로 레이블이 붙습니다. + +하네스 텍스트만으로 이루어진 프롬프트는 전혀 기록되지 않습니다. + +## 에이전트의 마지막 메시지 + +"네"와 같은 답변은 그것이 답하는 질문 없이는 의미가 없습니다. 프롬프트가 기록될 때 Failproof AI는 **그 시점에** 세션 트랜스크립트에서 에이전트의 마지막으로 보이는 메시지도 읽어 프롬프트와 함께 저장합니다. Jev는 이를 에이전트가 작성한 것으로 레이블이 붙은 자체 필드로 받습니다: 짧은 답변을 설명하지만 그 자체만으로는 절대 사람의 요청으로 계산되지 않습니다. 트랜스크립트가 읽히는 유일한 용도이며, 다시 쓰여진 트랜스크립트가 할 수 있는 최악은 에이전트가 작성한 메시지가 있어야 할 곳에 에이전트가 작성한 메시지를 넣는 것입니다. + +트랜스크립트의 끝에서, 최대 마지막 4 MB까지 읽힙니다. 지원되는 트랜스크립트 형식은 Claude Code, Codex 롤아웃(구 `agent_message` 이벤트와 신 `AgentMessage` 항목), Cursor, Copilot `events.jsonl`, Pi, Factory, OpenClaw 세션 JSONL입니다. Claude Code의 합성 메시지, API 오류 메시지, 서브에이전트(사이드체인) 메시지는 건너뜁니다. Goose와 OpenCode(세션을 SQLite에 보관)와 Devin(트랜스크립트가 단일 JSON 문서), OpenClaw(`before_agent_run` 이벤트에 트랜스크립트 경로 없음)에 대한 스냅샷은 없습니다. + +## 저장 + +| 속성 | 값 | +| --- | --- | +| 위치 | `~/.failproofai/state/semantic/sessions/.json` | +| 권한 | 파일 `0600`, 디렉터리 `0700`. 그 위의 모든 디렉터리는 `~/.failproofai`까지 `jev.json`의 디렉터리와 동일한 규칙을 따릅니다: 다른 사람이 **쓸 수** 있는 디렉터리는 이름을 변경하고 교체할 수 있으므로, 읽기 경로는 가능한 경우 해당 쓰기 비트를 제거하고, 제거할 수 없는 경우 **아무것도 읽지 않습니다**. 기록된 프롬프트는 위조되는 대신 부재하게 되며, 아무것도 통과되지 않습니다 | +| 세션당 보관 | 마지막 5개의 프롬프트; 직전과 동일한 프롬프트는 새 슬롯을 차지하지 않고 기존 것을 대체합니다 | +| 창 | 6시간보다 오래된 프롬프트는 무시됩니다 | +| 크기 | 각 프롬프트와 에이전트 메시지는 6,000자로 제한되며, 앞부분과 끝부분을 보존합니다 | +| 비밀 정보 | 아무것도 작성되기 전에 `sanitize-*` 정책과 동일한 패턴으로 삭제됩니다. 48,000자보다 긴 텍스트는 처음 28,800자와 마지막 19,200자로 삭제되며, 비밀이 분할되었을 수 있는 해당 잘린 부분 주변의 텍스트는 절대 저장되지 않습니다 | + +문자, 숫자, `.`, `_`, `-` 이외의 것을 포함하거나 128자보다 긴 세션 ID는 절대 파일 이름으로 사용되지 않으므로, 해당 세션에는 아무것도 기록되지 않습니다. + +세션 파일은 프롬프트가 한 번 기록된 후에만 존재합니다. 원본 상태, 트랜스크립트 마크 없이 프롬프트만 보관하며, 6시간 창보다 오래 침묵 상태가 되면 삭제됩니다 — 새 세션이 첫 번째 프롬프트를 작성하는 다음 시점에. + +Jev 엔드포인트가 구성되지 않으면 아무것도 기록되지 않습니다. + +### 프로젝트 루트 + +"프로젝트 내부" — `read-outside-workspace`와 다른 경로 확인이 판단하는 기준 — 는 **첫 번째 검토된 호출** 시점의 세션이 있던 프로젝트 내부를 의미합니다. 루트는 그 시점에 고정되며 나중의 `cd`는 이를 이동시키지 않습니다; `cd`는 여전히 상대 경로의 해석 방식을 변경합니다. 이를 `cd`를 따르게 하면 한 호출의 `cd ~/.ssh`가 다음 호출을 위해 `~/.ssh`를 프로젝트로 만들 수 있습니다. + +핀은 `~/.failproofai/state/semantic/roots/.json`으로, `{root, at}`를 보관합니다: 파일 `0600`, 디렉터리 `0700`, 위와 동일한 세션 ID 규칙. 7일보다 오래된 파일은 새 세션이 루트를 고정할 때 삭제됩니다. 다른 사용자가 쓸 수 있는 `roots` 디렉터리는 무시되고, 라이브 디렉터리의 루트가 대신 사용됩니다. 세션을 다시 고정하려면 해당 파일을 삭제하세요. + +## 알려진 한계 + +- **프롬프트는 훅 호출만큼만 신뢰할 수 있습니다.** 여기의 모든 것은 하네스가 훅의 stdin에 작성한 페이로드를 읽습니다. 명령을 실행할 수 있는 에이전트는 하네스를 헤드리스로 실행하거나(`claude -p`와 위에 나열된 7개) Failproof AI의 훅 바이너리 자체를 자신이 작성한 페이로드로 실행하여, 아무도 입력하지 않은 프롬프트를 기록할 수 있습니다. 이것은 이 페이지 상단에서 설명한 받아들여진 트레이드오프입니다: reviewable 정책만 통과시킬 수 있으며, hard 정책은 절대 아닙니다 — 하지만 15개의 reviewable 내장 정책 중 12개가 deny이므로, 위조된 프롬프트는 해당 12개에서 실제 차단을 allow로 전환할 수 있습니다. +- **서브 에이전트 감지는 Claude 형태입니다.** `agent_id`를 포함한 페이로드는 모든 하네스에서 절대 기록되지 않습니다. 이것은 Claude Code, Factory Droid, Devin이 사용할 필드입니다. Codex는 서브 에이전트 스레드 내에서 프롬프트 이벤트를 발생시키고, Copilot는 인프로세스 사이드킥을 실행하며, Goose에는 `delegate` 도구가 있고, OpenClaw는 페르소나를 실행합니다 — 이 중 어느 것도 이것이 인식하는 방식으로 페이로드를 표시하지 않으므로, 해당 하네스의 서브 에이전트 프롬프트는 세션 자체의 것으로 기록됩니다. OpenClaw의 `openclaw.agentId`는 그 마커가 **아닙니다**: 출하된 플러그인은 소유자의 것을 포함하여 모든 실행에서 이를 설정합니다. +- **마커가 없는 스케줄러.** Claude Code의 `schedule_wakeup`과 `loop_wakeup`, OpenClaw의 `cron`과 `heartbeat` 트리거는 해당 하네스가 페이로드에서 그렇게 말하기 때문에 거부됩니다. Goose 자체 스케줄러(`goose schedule add`)와 Codex의 `codex exec`는 아무것도 말하지 않으므로 시작하는 실행은 다른 것과 동일하게 기록됩니다. +- **에이전트의 마지막 메시지는 에이전트가 선택한 메시지일 수 있습니다.** 트랜스크립트는 인증되지 않으므로, 자체 트랜스크립트를 작성하는 에이전트는 "마지막 메시지"가 무엇을 말하는지 결정할 수 있습니다. 에이전트가 작성한 것으로 레이블이 붙고 그 자체로는 아무것도 통과시키지 않지만 — `decide.ts`의 v1 경로가 결정론적 "사용자가 이 대상을 명시했는지" 확인을 만족시킬 수 있으므로, 트랜스크립트를 제어하는 에이전트는 오버라이드가 필요로 하는 대상 이름을 제공할 수 있습니다. +- **확장의 기계 제목 중 하나로 시작하는 프롬프트는 전체가 삭제됩니다.** `# Selected text:`, `# Diff comments:`, `# Chrome tabs:` 또는 위 첫 번째 그룹의 다른 섹션 제목으로 프롬프트를 시작하고 `## My request:` 제목을 작성하지 않으면, 해당 턴에는 아무것도 기록되지 않아 아무것도 통과될 수 없습니다. 이것은 의도적입니다: 해당 섹션은 다른 사람이 제어하는 텍스트(선택한 코드, 리뷰어의 diff 댓글, 페이지 제목)를 포함하며, 그것을 사용자의 말로 기록하는 것이 더 나쁜 실패입니다. 개발자가 직접 입력할 법한 제목은 두 번째 그룹에 있으며 그 자체만으로는 절대 프롬프트를 삭제하지 않습니다. +- **OpenCode는 실제로 아무것도 기록하지 않습니다.** 현재 OpenCode에서 `message.updated` 이벤트는 텍스트를 포함하지 않으며, 작업 도구가 생성하는 자식 세션에 대해서도 발생합니다 — "사용자" 메시지를 부모 에이전트가 작성합니다. +- **`CODEX_HOME`은** `lib/codex-sessions.ts`의 롤아웃 탐색에서 **적용되지 않습니다**. 이는 에이전트 메시지 스냅샷을 찾는 위치에만 영향을 미치며, 프롬프트가 기록되는지 여부에는 영향을 미치지 않습니다. \ No newline at end of file diff --git a/docs/ko/reference/jev-providers.mdx b/docs/ko/reference/jev-providers.mdx new file mode 100644 index 000000000..8dadf8415 --- /dev/null +++ b/docs/ko/reference/jev-providers.mdx @@ -0,0 +1,275 @@ +--- +title: "Jev 공급자 및 자체 키 설정" +description: "자체 키를 사용한 라이브 Jev 정책 검토를 위한 공급자 엔드포인트, 모델 ID, 구성 및 장애 동작." +icon: "key-round" +--- + +이 문서는 자체 키를 사용하는 [Jev 정책](/ko/policies/jev)의 공급자 및 구성 참조입니다. 정규식 정책은 문자열을 매칭합니다. 사용자가 요청한 `rm -rf build/`와 계획에 슬며시 끼어든 `rm -rf ~`를 구별할 수 없으므로, 어떤 부분에서는 너무 많이 차단하고 다른 부분에서는 너무 적게 차단합니다. TypeSafe의 분류기인 **Jev**는 실제로 요청한 내용을 기준으로 호출을 분석하고, 하나의 빠른 요청으로 일련의 예/아니오 질문에 답합니다. + +자체 Jev 엔드포인트와 키가 구성된 경우, Failproof AI는 정규식 정책을 대체하는 것이 아니라 **함께** 각 도구 호출에 대해 Jev에 질의합니다: + +- **하드** 정책의 거부는 최종적입니다. Jev가 이를 해제할 수 없습니다. 명시적으로 검토 가능(reviewable)으로 표시되고 해당 정책이 다루는 Jev 검사를 명시하지 않는 한 모든 정책은 하드입니다. 따라서 아무것도 명시하지 않은 커스텀, 팩 또는 Cloud 정책은 하드이며, 항상 활성화된 자체 보호 가드도 항상 하드입니다. +- **검토 가능한(reviewable)** 정책의 거부는 해제될 수 있지만, Jev가 해당 정책이 다루는 정확한 우려 사항에 대해 질의를 받고 "여기서는 아무것도 없음" 또는 "사용자가 이를 요청함"이라고 답한 경우에만 가능합니다. 사용자가 해당 호출을 요청하지 않은 경우 우려 사항이 실재한다고 판단한 검사는 거부를 유지합니다 — 자체 판정이 경고에 불과하더라도, 도구 호출 이전에 경고는 에이전트를 멈추지 않기 때문입니다. 그리고 해당 검사가 거부를 내릴 수 있는 검사(비밀 노출, 자격 증명 유출, 파괴적 삭제 등)인 경우, 해당 호출에서는 아무것도 해제되지 않습니다. +- 호출이 사용자가 부여한 작업의 단계이고 더 이상 진행되지 않는 경우, 차단은 여전히 **경고**가 될 수 있습니다: Jev는 자체 거부를 경고로 완화하며, 해당 경고 — 호출의 실제 문제를 명시하는 — 가 정책의 차단을 대체합니다. +- Jev는 정규식으로 설명할 수 없는 위험에 대해 자체적으로 경고하거나 거부할 수도 있습니다. +- Jev가 응답할 수 없는 경우(타임아웃, 속도 제한, 서버 오류, 크레딧 없음, 예상치 못한 모델 버전), 해당 호출은 Jev 없이 사용하는 것과 동일하게 정규식 결과를 받습니다. +- Jev는 전체 호출을 읽고 정확한 우려 사항에 대해 질의를 받은 경우가 아니라면 정책만 사용하는 것보다 호출을 더 허용적으로 만들지 않습니다. 이보다 적은 경우 — 전체를 전송하기에 너무 큰 호출, 의심되는 인젝션 — 은 허가를 철회하고 모든 거부를 유지합니다. + + +Jev 구성이 없으면 아무것도 변경되지 않습니다: 훅은 항상 그래왔던 것처럼 정확히 정규식 정책을 실행합니다. 구성 자체가 전체 옵트인입니다. + + + +FailproofAI Cloud를 사용 중이신가요? 자체 키가 필요하지 않습니다: `jev:evaluate`를 포함하는 키로 연결된 머신은 조직 플랜에서 Jev를 사용할 수 있습니다. [FailproofAI Cloud를 통한 Jev](/ko/reference/jev-cloud)를 참조하세요. + + +## 시작하기 전에 + +**failproofai 1.0.8-beta.0 이상**을 설치하고 에이전트가 실행되는 머신의 [지원되는 하네스](/ko/reference/harnesses)에 훅을 연결하세요. 새 머신이라면 [퀵스타트](/ko/start/quickstart)를 따르고, Cloud를 사용하지 않는 경우 [로컬 적용 설정](/ko/start/setup#enforce-locally)을 참조하세요. 설치된 CLI를 `failproofai --version`으로 확인하세요. + +아래 공급자에서 API 키를 받거나, 호환 가능한 엔드포인트와 해당 키를 준비하세요. Jev는 `PreToolUse` 또는 `PermissionRequest` 게이트에서 명명된 도구 호출을 검토합니다. 자체 판정을 내릴 수 있지만, 기존 정책 거부를 해제하려면 [검토 가능(reviewable)](/ko/policies/authority)으로 표시된 설치된 정책도 필요합니다. 하드 정책 거부는 최종적으로 유지됩니다. + +## 공급자 선택 + +Jev는 다섯 가지 경로를 통해 접근할 수 있습니다. 그 중 하나의 키를 가져오세요. + +| 공급자 | `--provider` | 엔드포인트 | 기본 모델 | 비고 | +| --- | --- | --- | --- | --- | +| TypeSafe | `typesafe` | `api.typesafe.ai/v1/systemone` | `jev-1.13.0` | 정확한 버전 고정. | +| OpenRouter | `openrouter` | `openrouter.ai/api/v1/systemone` | `typesafe/jev-1.13` | 요청은 데이터 보존 없는 엔드포인트로만 라우팅되며, 다른 공급자로의 대체 없음. `typesafe/jev-1.13-20260917`과 같이 날짜가 포함된 버전을 보고합니다. | +| Vercel AI Gateway | `vercel` | `ai-gateway.vercel.sh/typesafe/v1/systemone` | `typesafe-ai/jev` | Jev를 별칭으로만 명명하므로 응답 버전은 미인증으로 기록됩니다. | +| Cloudflare Workers AI | `cloudflare` | `api.cloudflare.com/client/v4/accounts//ai/run` | `typesafe/jev` | `--account-id` 필요. 키당 약 초당 6회 호출이 HTTP 429 이전에 측정되었습니다. | +| 자체 엔드포인트 | `custom` | `/systemone` | `jev-1.13.0` | TypeSafe의 요청 본문을 수락하고 어떤 모델이 응답했는지 보고하는 모든 엔드포인트. `https`만 가능; 일반 `http://localhost`는 observe 모드에서만 허용됩니다. | + + +Vercel의 자체 키 가져오기(bring-your-own-key) 기능을 사용하면 실패한 요청이 Vercel의 자격 증명으로 자동 재시도됩니다. 모든 호출이 자체 TypeSafe 계정에만 청구되고 자체 계정에서만 볼 수 있어야 한다면 TypeSafe를 직접 사용하세요. + + +## 설정하기 + +하나의 명령어, 엔드포인트와 키만 필요합니다. 기존 정책이 계속 호출을 결정하는 동안 Jev의 판정을 검사할 수 있도록 `observe` 모드로 시작하세요: + +```bash +failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key +``` + +### URL이 공급자를 선택합니다 + +공급자를 명시할 필요가 없습니다: URL의 **호스트**가 어떤 공급자인지 나타냅니다. + +| URL 호스트 | 공급자 | 추가 필요 사항 | +| --- | --- | --- | +| `api.typesafe.ai` | `typesafe` | — | +| `openrouter.ai` | `openrouter` | — | +| `ai-gateway.vercel.sh` | `vercel` | — | +| `api.cloudflare.com` | `cloudflare` | `--account-id <32-hex-account-id>` | +| 다른 모든 호스트 | `custom` | — 입력한 URL이 기본 URL입니다 | + +이로부터 세 가지가 따릅니다: + +- **공급자 자체 API인 URL은 오버라이드를 작성하지 않습니다.** `--url https://api.typesafe.ai/v1`은 `--provider typesafe`와 정확히 동일한 구성을 생성합니다. 알려진 공급자에서 다른 경로나 호스트를 지정하면 `--base-url`이 저장하는 것처럼 기본 URL로 저장됩니다. +- **`--provider`는 여전히 추론을 오버라이드합니다.** 이것이 자체 호스트에서 공급자 API를 사용하는 프록시에 접근하는 방법입니다: `--url https://jev-proxy.internal/v1 --provider typesafe`. +- **호스트와 모순되는 `--provider`는 거부됩니다.** 추측하지 않습니다. `--provider openrouter --url https://api.typesafe.ai/v1`은 아무것도 작성하지 않고 이유를 설명합니다: 두 설정이 키가 전송될 위치에 대해 일치하지 않습니다. `jev setup --base-url`과 대시보드의 Jev 설정에서도 동일한 조합이 거부됩니다. (`--provider custom`은 모순이 아닙니다 — "이 URL 자체로 취급"을 의미합니다 — Cloudflare 호스트 제외, 커스텀 라우트가 접근할 수 없는 계정별 엔드포인트를 가집니다.) + +`--url`은 구성 파일의 `baseUrl`과 동일하게 검증되며 동일한 메시지로 거부됩니다: `https`, 또는 observe 모드에서만 일반 `http://localhost`. + +### 키 + +`--key-stdin`으로 파이프하거나, 없이 터미널에서 명령을 실행하고 마스킹된 프롬프트에서 키를 붙여넣으세요. 어느 방법이든 구성 파일에 바로 저장되고 다시 출력되지 않습니다. + + + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key + ``` + + + ```bash + failproofai jev --url https://openrouter.ai/api/v1 --mode observe --key-stdin < ~/openrouter.key + ``` + + + ```bash + failproofai jev --url https://ai-gateway.vercel.sh/typesafe/v1 --mode observe \ + --key-stdin < ~/vercel-gateway.key + ``` + + + ```bash + failproofai jev --url https://api.cloudflare.com/client/v4 \ + --account-id <32-hex-account-id> --mode observe --key-stdin < ~/cloudflare.token + ``` + + + ```bash + failproofai jev --url https://jev.internal.example.com/v1 --mode observe --key-stdin < ~/jev.key + ``` + + + +`failproofai jev setup`은 동일한 플래그를 받으며 모든 것의 전체 표현입니다: URL보다 공급자를 명시하고 싶다면 `setup --provider `를 사용하세요. + +### `--token` 및 비용 + +`--token `은 키를 명령줄에 넣으며, 이는 머신을 구성하는 가장 빠른 방법이고 구성 파일 외 다른 곳에 키를 남기는 유일한 방법입니다: + +```bash +failproofai jev --url https://openrouter.ai/api/v1 --token +``` + + +명령줄 인수는 이후 셸 히스토리 파일에 남으며, 명령 실행 중에는 프로세스 목록에 표시됩니다 — 사용자로 실행되는 모든 것이 `/proc`에서 읽을 수 있습니다. `setup`은 `--token`을 사용할 때마다 이를 알립니다. 공유 머신, 녹화된 세션, 또는 히스토리 파일이 동기화되는 곳에서는 `--key-stdin`을 선호하세요; 이 방법으로 전달한 키는 중요한 경우 교체하세요. + + +`--token`, `--key-stdin`, `--key-from-env`는 상호 배타적입니다: 하나만 사용하세요. + +그런 다음 키, 엔드포인트 및 어떤 Jev가 응답했는지 확인하기 위해 작은 라이브 요청을 하나 보내세요: + +```bash +failproofai jev test +``` + +```text + failproofai jev test ok · 523 ms + + provider cloudflare + model asked typesafe/jev + answered by jev-1.13.0 (Jev 1.13 family — verified) + latency 523 ms — within the 3000 ms timeout +``` + +`jev test`는 답변이 타임아웃 후에 도착하거나(모든 훅이 `timeout`으로 정규식으로 대체됨) 검사 질문에 잘못 답한 경우 제목에서 이를 알리며 종료 코드 1을 반환합니다. + +훅은 모든 도구 호출 시 구성을 읽으므로 다음 호출부터 적용됩니다. 데몬 유무에 관계없이 재시작이 필요하지 않습니다. + +## 동작 확인하기 + +```bash +failproofai jev status +failproofai jev status --json +``` + +`status`는 공급자, 엔드포인트, 모델, 모드, 구성 파일 및 권한을 표시하며 키는 절대 표시하지 않습니다. 그 아래에는 최근 활동을 요약합니다: Jev가 평가한 호출 수, 정규식으로 대체된 횟수와 이유, 지연 시간, 그리고 해제한 검토 가능 정책. + +## 실제 호출 확인하기 + +훅이 연결된 에이전트에서 새 세션을 시작하세요. `README.md`에서 파일 읽기 도구를 사용하여 제목을 보고하도록 요청하세요. 세션에 해당 도구 호출이 포함되어 있는지 확인한 다음 `failproofai jev status`를 다시 실행하세요: 최근 평가된 호출 수가 증가해야 합니다. [로컬 대시보드](/ko/reference/local-dashboard#review-policy-activity)에서 **Policies → Activity**를 열어 호출의 Jev 판정과 모드를 검사하세요. Observe 모드에서는 정책 결과가 여전히 호출을 결정합니다. 검토 가능 정책이 매칭되고 Jev가 명명된 모든 검사를 해제한 경우에만 허가가 나타납니다; 일반적인 읽기는 해제할 정책이 없을 수 있습니다. + +## Observe 모드 + +`enforce`가 기본값입니다. 어떤 결정도 변경하지 않고 Jev를 관찰하려면 `observe`로 전환하세요: Jev는 여전히 질의를 받고 판정이 기록되지만, 정규식 결과가 적용됩니다. + +```bash +failproofai jev setup --mode observe +failproofai jev setup --mode enforce +failproofai jev setup --mode off +``` + +`off`는 구성 — 엔드포인트와 키 — 을 유지하고 Jev 질의를 중단합니다: 훅은 구성 없이와 동일하게 정규식 정책을 실행하며, `failproofai jev status`는 "off (switched off)"를 표시합니다. `--mode observe` 또는 `--mode enforce`로 다시 전환하세요. + +동일한 공급자에 대해 `setup`을 다시 실행하면 저장된 키가 유지되므로, 모드 전환은 플래그 하나로 됩니다. 공급자를 전환하면 처음부터 시작하고 해당 공급자의 키를 요청합니다. 요청을 다른 호스트로 이동하는 `--base-url`도 마찬가지입니다: 저장된 키는 제공된 호스트 또는 해당 공급자 자체 API로만 전송됩니다. + +## 구성 파일 + +모든 것은 `setup`이 작성하는 하나의 파일 `~/.failproofai/jev.json`에 있습니다: + +```json +{ + "provider": "cloudflare", + "apiKey": "", + "accountId": "<32-hex-account-id>", + "mode": "enforce", + "timeoutMs": 3000 +} +``` + +| 필드 | 의미 | +| --- | --- | +| `provider` | `typesafe`, `openrouter`, `vercel`, `cloudflare` 또는 `custom` — 또는 `failproofai`, 키가 이 파일 대신 FailproofAI Cloud 연결에서 옵니다 ([FailproofAI Cloud를 통한 Jev](/ko/reference/jev-cloud) 참조). | +| `apiKey` | `Authorization: Bearer `로 전송됩니다. | +| `baseUrl` | `custom`에 필수; 그 외에는 공급자의 API 기본값을 대체합니다. `https`이어야 합니다. `localhost`에 대한 일반 `http`는 `mode: observe`에서만 허용됩니다: 로컬 포트는 인증이 없으므로, 프록시가 다운된 동안 에이전트를 포함한 머신의 모든 프로세스가 대신 응답할 수 있습니다. | +| `accountId` | Cloudflare 전용: 32개의 소문자 16진수 문자. | +| `model` | 공급자의 기본 모델 ID를 대체합니다. 버전이 있는 ID는 Jev 1.13을 명시해야 합니다. API 키처럼 생긴 값은 거부됩니다(되풀이하지 않음), 따라서 `--model`에 붙여넣은 키는 절대 저장되거나 모델로 전송되지 않습니다. | +| `timeoutMs` | 정규식 결과를 사용하기 전에 도구 호출이 Jev를 기다리는 시간. 100–10000, 기본값 3000. | +| `mode` | `enforce` (기본값), `observe`, 또는 `off` (구성 유지, Jev 실행 안 함). | + +세 가지 규칙이 이를 보호합니다: + +- **소유자 전용.** 권한 `0600`으로 작성됩니다. 다른 사용자나 그룹이 읽거나 쓸 수 있는 복사본은 **거부되며**, `chmod 600 ~/.failproofai/jev.json` 또는 `setup`을 다시 실행할 때까지 훅은 정규식으로 대체됩니다. 디렉토리도 확인됩니다: `~/.failproofai`는 다른 사람이 **쓸 수 없어야** 합니다. 거기에 쓸 수 있는 사람은 파일 자체 권한에 관계없이 파일을 교체할 수 있기 때문입니다. `setup`은 이러한 쓰기 비트를 발견하면 제거합니다. `failproofai jev status`는 구성이 거부되었을 때 알리고 파일이 명시하는 엔드포인트를 표시합니다: 다른 누군가가 변경했을 수 있으므로, `chmod` 전에 자신의 파일인지 확인하세요. 이러한 파일에 대해 `setup`을 다시 실행하면 저장된 키는 공급자 자체 API로만 전달됩니다; 파일이 명시하는 다른 엔드포인트는 키를 다시 필요로 합니다(`--key-stdin`), 또는 `--base-url default`를 사용하여 요청을 공급자로 다시 보내세요. +- **전역 전용.** 리포지토리는 Jev를 켜거나, 다른 엔드포인트를 지정하거나, 모델을 선택할 수 없습니다: 프로젝트 내부의 `.failproofai/jev.json`은 무시되며, 공급자, URL, 모델 및 계정 ID는 해당 파일에서만 읽힙니다 — 리포지토리의 에이전트 설정이 설정할 수 있는 환경에서는 절대 읽지 않습니다. (`FAILPROOFAI_HOME`은 이를 우회하는 방법이 아닙니다: Jev만 리다이렉트하는 것이 아니라 정책을 포함한 전체 failproofai 디렉토리를 이동합니다.) +- **키만 환경에서 올 수 있습니다.** 파일에 `apiKey`가 없으면 `FAILPROOFAI_JEV_API_KEY`가 해당 세션에 키를 제공합니다(`setup --key-from-env`가 이런 파일을 작성합니다). 파일에 있는 키를 대체하지 않으며, 파일 없이 Jev를 켤 수 없습니다. 변수가 설정되지 않은 경우 해당 셸에서 Jev는 단순히 꺼집니다: `failproofai jev status`가 이를 알리고 종료 코드 0을 반환하며 구성을 그대로 둡니다(`status --json`은 `"reason": "no-env-key"`와 함께 `"status": "key-missing"`을 보고합니다). `failproofaid` 데몬은 셸 환경을 볼 수 없으므로, `failproofai config`로 설정된 머신에서는 파일에 키를 유지하세요. + +## 어떤 Jev가 응답하는가 + +Failproof AI의 결정 임계값은 Jev 1.13에서 보정되었으므로, 해당 계열에서 온 경우에만 답변이 사용됩니다: `jev-1.13.x`, 또는 OpenRouter의 `typesafe/jev-1.13-`. 공급자가 Jev를 별칭으로만 명명하고 버전을 보고하지 않는 경우(Vercel, 그리고 Cloudflare가 명시하지 않을 때), 답변은 사용되며 미인증으로 기록됩니다. `custom` 엔드포인트는 응답한 모델을 보고해야 합니다; 단 하나의 예외는 버전 없는 `--model` 이름으로 구성한 경우로, 다시 에코되면 동일한 방식으로 미인증으로 기록됩니다. 다른 버전을 보고하는 답변이나 `custom` 답변이 아무것도 보고하지 않으면 사용되지 않습니다: 해당 호출은 `model-mismatch` 이유로 정규식으로 대체됩니다. + +## Jev가 응답할 수 없을 때 + +다음 각각은 해당 호출에 대해 정규식 결과로 대체되며 이유와 함께 기록됩니다. `failproofai jev status`에서 합계를 확인할 수 있습니다: + +| 이유 | 원인 | +| --- | --- | +| `timeout` | `timeoutMs` 내에 답변 없음. | +| `http-429` | 공급자가 키를 속도 제한함. | +| `rate-limited` | Failproof AI 자체 제한기가 전송 전에 호출을 보류했습니다: 초당 5회 요청, 최대 5회 버스트, 공급자가 `429`를 응답한 후 잠시 없음. 공급자가 아님. | +| `http-500`, `http-502`, `http-503`, … | 공급자의 서버 오류. 정확한 상태가 기록됩니다. | +| `out-of-credits` | HTTP 402: 공급자 계정에 크레딧이 없습니다. | +| `provider-refused` | Cloudflare에서 "Model execution failed (Payment error)"를 읽는 HTTP 402: 공급자가 이 요청에서 모델 실행을 거부했습니다. 일반적으로 청구 문제가 아니므로 크레딧을 추가해도 해결되지 않습니다. | +| `http-401`, `http-403` | 키가 거부되었습니다. | +| `http-404` | `/systemone`에 아무것도 제공되지 않으므로 기본 URL이 잘못되었습니다 — `/systemone`이 추가되며 모든 공급자는 버전 루트에서 제공합니다. `failproofai jev models`는 엔드포인트가 실제로 제공하는 것을 보여줍니다. | +| `network` | 엔드포인트에 도달할 수 없습니다. | +| `http-301`, `http-302`, `http-307`, `http-308` | 엔드포인트가 리다이렉트로 응답했습니다. 리다이렉트는 절대 따르지 않으므로 답변은 항상 구성의 URL에서만 옵니다; `--base-url`을 최종 URL로 설정하세요. | +| `malformed` | 엔드포인트가 응답했지만 Jev 답변이 아닙니다 — JSON이 아닌 본문이거나 답변이 없는 본문. | +| `cloudflare-error`, `cloudflare-incomplete` | Cloudflare의 봉투에 실패가 보고되었거나 완료되지 않은 작업. | +| `model-mismatch` | 1.13 외의 Jev 버전이 응답했거나, `custom` 엔드포인트가 어떤 모델이 응답했는지 명시하지 않았습니다. | +| `request-cut` | **중단이 아닙니다.** Jev가 응답했지만 호출의 일부만 표시되었으므로 답변이 아무것도 해제하지 않습니다. [Jev가 응답했지만 전체 호출에 대해서가 아닌 경우](#when-jev-answered-but-not-on-the-whole-call)를 참조하세요. | + +`failproofai jev status`는 `upstream-error`(답변에 공급자 자체 오류가 포함됨) 또는 `config`와 같은 드문 이유도 표시할 수 있으며, 명명할 수 없는 이유는 `other`로 합산됩니다. + +`request-cut`이 이 표에 있는 이유는 `failproofai jev status`가 나머지와 함께 집계하고, 이 또한 모든 거부를 유지하기 때문입니다. 여기서 공급자에 대해 아무것도 말하지 않는 유일한 이유입니다: 요청이 도착했고 Jev가 답변했습니다. 위의 모든 행과 달리 해당 답변은 여전히 카운트됩니다 — Jev 자체의 거부나 경고는 버려지지 않고 정규식 결과 위에 적용됩니다. 따라서 이 숫자가 계속 나타난다면 호출이 전체를 전송하기에 너무 크게 평가자에 도달하는 것이지, 엔드포인트에 문제가 있는 것이 아닙니다. 크레딧을 추가하거나 URL을 변경해도 수가 줄지 않습니다. + +## Jev가 응답했지만 전체 호출에 대해서가 아닌 경우 + +두 가지 더 발생할 수 있으며, 둘 다 Jev가 응답에 실패하는 것이 아닙니다. 둘 다 호출의 얼마나 많은 부분이 또는 대화가 하나의 요청에 맞는지에 관한 것입니다. + +**호출 자체의 일부가 맞지 않았습니다.** 도구 호출은 고정된 예산 내에서 전송되며, 매우 큰 것 — 매우 큰 `Write`, 거대한 MCP 본문, 한도까지 채워진 명령 — 은 맞는 부분만 전송됩니다. Jev는 여전히 응답하며 그 답변은 여전히 카운트됩니다: 자체 거부나 경고는 평소와 같이 적용됩니다. 할 수 없는 것은 **해제**입니다. 호출의 일부에 대해 내려진 판정은 그 호출에 대한 판정이 아니기 때문입니다. 따라서 모든 정책 거부가 유지되며, 호출은 `request-cut` 이유와 함께 대체로 기록되어 `failproofai jev status`가 위의 이유들과 함께 집계합니다. 이것이 주는 규칙: 호출을 더 크게 만들면 허가를 잃을 수 있으며, 허가를 살 수는 없습니다. + +**메시지가 맞지 않았습니다.** 붙여넣은 긴 프롬프트, 에이전트의 마지막 메시지, 또는 이 평가자의 자체 저장소가 이미 한도를 초과한 프롬프트. **아무것도 변경되지 않습니다**: 호출은 다른 것과 동일하게 판정, 해제, 기록되며 대체로 카운트되지 않습니다. 입력 길이는 절대 판정을 결정하지 않으며, 잘림이 동의를 만들어낼 수 없습니다: 프롬프트가 이미 한도를 초과한 상태로 도착한 경우, "당신이 이것을 요청하지 않았다"는 결론은 도출될 수 없게 됩니다. 결론이 반대가 되는 것이 아니라. + +두 가지의 경계는 누가 텍스트를 작성했는지입니다. 호출은 에이전트의 것이며, 길이가 심각도를 줄이도록 허용하는 규칙은 에이전트가 사용할 수 있는 규칙이 됩니다; 프롬프트는 사용자의 것이며, 길이를 신호로 취급하면 사양이나 스택 트레이스를 붙여넣는 것을 처벌하는 결과만 낳습니다. + +## 머신을 떠나는 것 + +Jev가 평가하는 각 도구 호출에 대해, 공급자로 하나의 요청이 전송됩니다: + +- API 키, 베어러 토큰 및 `KEY=` 할당과 같은 비밀이 편집된 도구 호출 자체; +- 에이전트 하네스가 추가한 텍스트가 제거된 최근 입력 프롬프트; +- 최신 프롬프트 이전 에이전트의 마지막 메시지, 에이전트 작성으로 레이블링됨; +- 경로가 프로젝트 내부에 있는지 여부 등 로컬에서 계산된 사실 — 첫 번째 검토된 호출 당시 세션이 있던 경로, [세션에 고정됨](/ko/reference/jev-intent#the-project-root) — 및 현재 git 브랜치. + +자체 키 아래 구성의 엔드포인트로만 전송됩니다. + +## 끄기 + +```bash +failproofai jev remove +``` + +이것은 `~/.failproofai/jev.json`을 삭제합니다. 다음 도구 호출부터 훅은 이전과 동일하게 정규식 정책을 실행합니다. `~/.failproofai/state/semantic/` 아래의 세션별 저장소(`sessions/`의 기록된 프롬프트, `roots/`의 프로젝트 루트)는 그대로 남아 자동으로 만료됩니다. Jev 질의는 중단하지만 구성을 유지하려면 대신 `failproofai jev setup --mode off`를 사용하세요. + +## 명령어 참조 + +| 명령어 | 결과 | +| --- | --- | +| `failproofai jev --url --key-stdin` | 하나의 명령으로 구성; 공급자는 URL 호스트에서 옵니다 | +| `failproofai jev --url --token ` | 동일하지만 키가 명령줄에 있음 — 히스토리와 프로세스 목록에 표시됩니다 | +| `failproofai jev setup --provider --key-stdin` | stdin으로 파이프된 키에서 구성 작성 | +| `failproofai jev setup --provider ` | 동일하지만 마스킹된 프롬프트에서 키 요청 | +| `failproofai jev setup --key-from-env` | 키 저장 안 함; 세션당 `FAILPROOFAI_JEV_API_KEY` 읽기 | +| `failproofai jev setup --mode observe` | 저장된 키를 유지하면서 모드 전환(`enforce`, `observe` 또는 `off`) | +| `failproofai jev setup --model ` / `--base-url ` | 모델 또는 API 기본값 오버라이드; `default`는 오버라이드 초기화 | +| `failproofai jev setup --timeout-ms ` | 호출당 예산 변경 | +| `failproofai jev status [--json]` | 구성, 권한 및 최근 활동; 키는 절대 표시 안 함 | +| `failproofai jev test [--json]` | 라이브 요청 하나: 지연 시간 및 응답한 버전 | +| `failproofai jev models [--provider ] [--url ] [--json]` | 해당 엔드포인트의 `/models`가 보고하는 모델 ID, 구성된 것 표시 | +| `failproofai jev remove` | 구성 삭제; Jev 꺼짐 | \ No newline at end of file diff --git a/docs/ko/reference/jev.mdx b/docs/ko/reference/jev.mdx new file mode 100644 index 000000000..ebe210512 --- /dev/null +++ b/docs/ko/reference/jev.mdx @@ -0,0 +1,22 @@ +--- +title: "Jev 통합 레퍼런스" +description: "Jev의 구성, 프로바이더, 키, 요청 데이터 및 실패 동작에 대한 설명입니다." +icon: "braces" +--- + +Jev는 Failproof AI에서 두 가지 용도로 사용됩니다. + +| 용도 | 실행 시점 | 반환값 | 시작하기 | +| --- | --- | --- | --- | +| 세션 평가 | 세션이 종료된 후 | 고정 답변 질문에 대한 점수 | [Jev 평가](/ko/evaluations/jev) | +| 툴 호출 정책 검토 | 게이트 처리된 툴 호출이 실행되기 전 | 설치된 정책과 함께 제공되는 판정 결과 | [Jev 정책](/ko/policies/jev) | + +## 레퍼런스 페이지 + +| 주제 | 상세 내용 | +| --- | --- | +| [평가 질문](/ko/reference/jev-evaluations) | 불리언 및 순서형 점수 기준, 결과, 제한 사항, 백필. | +| [프로바이더 비교 및 자체 키 설정](/ko/reference/jev-providers) | TypeSafe, OpenRouter, Vercel, Cloudflare 및 커스텀 엔드포인트, URL 추론, 모델 ID, `jev.json`, 모드, 폴백 코드. | +| [FailproofAI Cloud 라우트](/ko/reference/jev-cloud) | 머신 키 권한, 자동 옵저브 설정, 사용량 제한, 연결 상태, 데이터 처리. | + +로컬 CLI 명령어는 [Failproof AI CLI 레퍼런스](/ko/reference/failproof-cli)에서 확인할 수 있습니다. [로컬 대시보드 레퍼런스](/ko/reference/local-dashboard#set-up-jev)에서는 Jev 설정 및 활동 뷰에 대한 내용을 다룹니다. \ No newline at end of file diff --git a/docs/ko/sessions/sentiment.mdx b/docs/ko/sessions/sentiment.mdx new file mode 100644 index 000000000..c88cb7a51 --- /dev/null +++ b/docs/ko/sessions/sentiment.mdx @@ -0,0 +1,43 @@ +--- +title: "감정 분석" +description: "Jev 감정 점수로 불만스럽거나 혼란스럽거나 수정 요청하는 메시지를 찾아보세요." +icon: "smile" +--- + +Jev는 에이전트에 사람이 보내는 각 메시지를 0~100점으로 네 가지 감정 — **분노**, **불만**, **기쁨**, **혼란** — 과 에이전트 성능에 관한 세 가지 신호로 평가합니다: + +- **Correcting**: 사람이 에이전트의 답변이 틀렸다고 지적하는 경우. +- **Resolved**: 사람이 에이전트가 문제를 해결했다고 확인하는 경우. +- **Doubtful**: 사람이 에이전트의 답변이 사실인지, 혹은 실제로 작업을 수행했는지 의문을 제기하는 경우. + +감정 분석을 사용하면 사람들이 인내심을 잃어가는 대화, 반복적으로 수정 요청을 받는 에이전트, 그리고 긍정적인 반응을 얻는 답변을 찾을 수 있습니다. 이 기능은 Jev에 내장된 점수 산정 방식으로, 별도의 평가를 작성할 필요가 없습니다. 고정된 답변이 있는 질문에 대한 직접 평가를 원한다면 [Jev eval 만들기](/ko/evaluations/jev)를 참고하세요. + + + 감정 분석은 관리자가 조직 내에서 활성화하기 전까지 비활성화 상태입니다. Jev는 메시지당 한 번의 점수 산정 요청을 수행하며, 해당 메시지와 그 이전 에이전트 답변을 함께 수신합니다. 점수 산정은 조직의 모델 예산을 사용합니다. + + +## 활성화 방법 + +1. **Administration → Settings**로 이동합니다. +2. **Human input sentiment** 항목에서 스위치를 **켬** 상태로 전환하고 저장합니다. + +최근 하루간의 메시지가 먼저 점수 산정됩니다. 이후에는 새 메시지가 도착한 후 1~2분 내에 점수가 산정됩니다. + +## 검토할 대화 찾기 + +**Observe → Sentiment**를 엽니다. 시간, 환경, 에이전트, 또는 세션 ID로 필터링할 수 있습니다. 헤더에는 메시지 및 세션 수, **flagged** 메시지 수, 그리고 가장 많이 나타난 신호가 표시됩니다. 분노, 불만, 수정, 혼란, 또는 의심 점수 중 하나가 100점 만점에 35점 이상에 도달하면 해당 메시지가 flagged 처리됩니다. + +![메시지 및 세션 수, flagged 메시지, 시간별 Jev 점수를 보여주는 Sentiment 대시보드.](/images/dashboard/sentiment-overview.png) + +**Score over time**을 사용해 신호들을 비교하세요. 표시할 점수를 선택한 후, 특정 시간대 버킷을 클릭하면 해당 시간대의 메시지를 볼 수 있습니다. **By agent** 테이블에서는 신호가 집중된 에이전트를 확인할 수 있습니다. **Messages**에서는 가장 강한 부정 점수 순으로 정렬하거나 특정 점수를 선택할 수 있습니다. 메시지를 해당 세션에서 열어 주변 대화 맥락을 읽은 후 무엇이 문제였는지 판단하세요. + +![가장 강한 부정 점수 순으로 정렬된 Sentiment 메시지 목록과 각 원본 세션 링크.](/images/dashboard/sentiment-messages.png) + +## 점수 산정 대상 메시지 + +사람이 직접 작성한 메시지만 해당됩니다: + +- SDK를 통해 사용자 입력으로 기록된 커스텀 에이전트의 메시지. +- Claude Code, Codex, OpenCode, pi, Hermes, OpenClaw에 직접 입력된 프롬프트 (세션 트랜스크립트가 전송되는 경우, 기본값). 예약된 작업, 주입된 지시사항, 하위 에이전트 핸드오프, 에이전트 런타임이 직접 작성한 텍스트는 점수 산정에서 제외됩니다. `claude -p`, `codex exec`, `hermes -z`와 같은 비대화형 실행도 제외됩니다. 이러한 프롬프트는 사람이 아닌 스크립트가 작성한 것이기 때문입니다. + +점수 산정은 사람 본인의 표현을 기준으로 판단합니다. "fix it"과 같이 짧고 직접적인 지시는 분노로 간주되지 않으며, 질문을 하는 것 자체는 혼란으로 간주되지 않습니다. 새로운 요청은 수정 요청이 아니며, 단순한 감사 인사만으로는 resolved로 인정되지 않습니다. \ No newline at end of file diff --git a/docs/ko/start/use-jev.mdx b/docs/ko/start/use-jev.mdx new file mode 100644 index 000000000..a21e2f997 --- /dev/null +++ b/docs/ko/start/use-jev.mdx @@ -0,0 +1,63 @@ +--- +title: "Jev 사용하기" +description: "완료된 세션에 대한 Jev 평가 또는 라이브 툴 호출 검토를 위한 Jev 정책을 설정합니다." +icon: "sparkles" +--- + +Jev는 에이전트 실행의 두 시점에서 도움을 줍니다. 완료된 세션을 알려진 답변과 비교해 점수를 매기거나, 에이전트에게 요청한 작업의 맥락에서 툴 호출을 검토합니다. + + + + 완료된 세션을 몇 가지 정해진 답변이 있는 질문과 비교해 점수를 매길 수 있을 때 Jev 평가를 사용하세요. 예: "고객이 환불을 요청했나요? 예 또는 아니오로 답하세요." 세션 전반에 걸친 패턴을 파악하는 데 도움이 됩니다. + + ## 평가 만들기 + + Cloud 대시보드에서 **Analyze → eval authoring → new eval**을 엽니다. 고정 답변 질문 하나를 입력하고 **draft**를 선택한 후, 분류기 점수가 선택되었는지 확인합니다. 실제 세션에서 [테스트](/ko/evaluations/test)한 다음 배포합니다. + + ![질문을 설명하고, 초안을 검토하고, 배포하는 공유 평가 작성 양식. 이 스크린샷은 코드 초안을 보여줍니다. Jev의 경우 고정 답변 질문을 사용하세요.](/images/dashboard/eval-authoring-draft.png) + + ## 점수 확인하기 + + 새 세션이 완료된 후 **Observe → Evaluations**를 열거나 Cloud CLI를 사용하세요: + + ```bash + fp evals --since 7d + fp evals --aggregate --since 7d + ``` + + CLI는 점수를 읽어옵니다. Jev 평가 생성은 현재 대시보드에서만 가능합니다. 질문 유형과 예시는 [Jev 평가](/ko/evaluations/jev)를 참고하세요. + + + 문자열 매칭 정책이 툴 호출의 안전 여부를 판단하기 위해 요청 맥락이 필요할 때 Jev 정책 검토를 사용하세요. 설치된 정책이 각 호출을 계속 처리하는 동안 Jev의 답변을 검사할 수 있도록 **observe** 모드로 시작하세요. + + Jev의 검사는 패키지에서 제공됩니다. Failproof AI는 기본 제공하지 않습니다. 설치 전까지는 Jev가 설정되어 있더라도 아무것도 묻지 않습니다: + + ```bash + failproofai policies add FailproofAI/jev-policies + ``` + + ## Cloud Jev 설정하기 + + Cloud 대시보드에서 **Administration → Keys**를 열고 **machine** 프리셋으로 키를 생성합니다. [빠른 시작](/ko/start/quickstart)에 나온 대로 `failproofai config`와 함께 사용하세요. 기존 Jev 설정이 없는 머신에서는 observe 모드로 Cloud Jev가 활성화됩니다. 다음 명령으로 연결을 확인하세요: + + ```bash + failproofai jev status + failproofai jev test + ``` + + ## 직접 엔드포인트 사용하기 + + 로컬 대시보드에서 **Settings → Jev**를 엽니다. 공급자를 선택하고 토큰을 붙여넣은 후 **observe**를 선택하고 Jev를 켭니다. + + ![공급자, 토큰 필드, observe 모드가 선택된 로컬 Jev 설정 패널.](/images/dashboard/jev-settings.png) + + 또는 터미널에서 엔드포인트를 설정하고 테스트하세요: + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key + failproofai jev test + ``` + + 훅이 연결된 에이전트에게 `README.md`에 파일 읽기 툴을 사용하도록 요청합니다. 해당 툴 호출이 세션에 나타나는지 확인한 후, 로컬 대시보드의 **Policies → Activity**에서 검사합니다. observe 결과가 적절하게 보이면 [Jev 정책](/ko/policies/jev)에서 적용 시점을 확인하세요. 공급자 세부 정보와 설정은 [통합 레퍼런스](/ko/reference/jev)를 참고하세요. + + \ No newline at end of file diff --git a/docs/policies/authority.mdx b/docs/policies/authority.mdx new file mode 100644 index 000000000..bfdd33707 --- /dev/null +++ b/docs/policies/authority.mdx @@ -0,0 +1,144 @@ +--- +title: "Policy authority" +description: "Which policy verdicts the Jev semantic evaluator may clear, and which are final." +icon: "scale" +--- + +When you configure [Jev policy review](/policies/jev) through FailproofAI Cloud or your own key, each gated tool call is judged by the policies you run and by Jev, which asks what the call actually does and whether the person who typed the task asked for it. Each policy's **authority** decides what happens when the two disagree. + +Without Jev configured, authority has no effect. Every policy enforces exactly as it always has. + +## Hard and reviewable + +- **Hard** is the default. A hard policy's deny or instruction is final: Jev cannot clear it, and a hard deny stops the call without waiting for Jev. +- **Reviewable** means Jev may clear the policy's verdict, but only through the semantic checks the policy names in `reviewedBy`. The verdict is cleared only when **every** named check was asked about this call and each one either found nothing or recorded the user asking for this. A check that **fired** — found the concern — without the user asking keeps the block, even when its own verdict is only a warning. A check Jev was not asked, because it does not apply to that tool, never clears anything, whatever the others said. One softening counts as consent: when the call is a step of the task the user gave and reaches no further, Jev turns a deny into a warning, and that warning clears the policy's block and is what the agent is told. + +A policy is reviewable only when all of these hold: + +1. It declares `authority: "reviewable"`. +2. `reviewedBy` is a non-empty list, and every entry is a Jev check an installed pack declares. Failproof AI ships no Jev checks: the [sixteen below](#semantic-policy-names) come from `failproofai policies add FailproofAI/jev-policies`. With no pack declaring checks, every policy is hard. +3. It is not `alwaysOn`. The guard that stops an agent from disabling Failproof AI is always hard. + +Anything else is hard: a missing field, a misspelled value, an empty or malformed `reviewedBy`, or a name that is not a check this machine can ask. An unknown name makes the whole declaration hard rather than being skipped, because `reviewedBy` means "all of these must be asked, and none of them may deny", and skipping a name would let Jev clear the policy on fewer checks than you asked for. + +Once Jev is configured, Failproof AI logs a warning when it refuses a `reviewable` declaration, once per process. Without Jev it says nothing, because authority then decides nothing. `failproofai publish` refuses to build a pack that carries such a declaration, so a pack author finds out before anyone installs it. It judges `reviewedBy` against the checks the pack declares when it declares any, and against the sixteen `FailproofAI/jev-policies` names otherwise. + +## Where authority is declared + +Each way a policy reaches a machine has one place that decides its authority: + +| Source | Declared in | Default | +| --- | --- | --- | +| Built-in policies | The table below | Hard unless listed as reviewable | +| Your own policy files | `authority` and `reviewedBy` on `customPolicies.add` | Hard | +| Policy packs | Each policy's entry in the pack manifest (`failproofai-pack.json`) | Hard | +| Cloud-managed policies | The policy's assignment in the active deployment | Hard. Deployments do not set it yet, so every cloud-managed policy is hard today. | + +For a pack or a cloud-managed policy, fields set inside the policy code are ignored; the manifest or the assignment decides. A pack can only describe its own policies: its policy names cannot contain `/` and are registered under the pack's own prefix, so no manifest can mark a built-in policy or another pack's policy as reviewable. A policy a pack's code registers without declaring it in the manifest is hard. + +Two packs, or two cloud-managed policies, whose code is byte-identical share one artifact and load as one policy. That policy is reviewable only if every one of them declares it reviewable, and Jev must then clear every check any of them names. If any of them declares it hard, or does not declare it at all, it stays hard. The order the packs or policies are listed in never matters. + +Most machines get the built-in policies from the `FailproofAI/policies` pack, and read their authority from that pack's manifest. The reviewable entries below take effect once a release of the pack that carries them is installed; an older release carries none, so every policy in it stays hard. + +## Declare authority in your own policy + +```js +import { customPolicies, deny, allow } from "failproofai"; + +customPolicies.add({ + name: "block-prod-config-reads", + description: "Keep production credentials out of the agent's context", + match: { events: ["PreToolUse"] }, + authority: "reviewable", + reviewedBy: ["secret-exposure"], + fn: async (ctx) => + String(ctx.toolInput?.file_path ?? "").includes("/config/prod/") + ? deny("Production config is off limits") + : allow(), +}); +``` + +`failproofai publish` copies both fields into the pack manifest, so a policy published as a pack keeps the authority its author gave it. It refuses to build the pack if a declaration would not be honored: a value other than `"hard"` or `"reviewable"`, a `reviewedBy` that is not a list of names, or a name that is not a check — one of the pack's own [Jev checks](/policies/publish-a-pack#jev-checks-in-a-pack) when it declares any, a built-in check otherwise. + +## Built-in policies + +Reviewable only where a semantic policy genuinely covers the same concern. Every other built-in policy is hard. + +Covering the concern is necessary but not sufficient, and both ways of getting it wrong are quiet: + +- **A check that is never asked** makes the block permanent. `reviewedBy` is a conjunction and a check that was not asked never clears, so a policy paired with a check whose precondition does not fire for the shapes the policy matches can never be cleared at all. +- **A check that is asked but does not fire** answers "no concern", and no concern clears. So pairing with a check that does not model your policy's shapes does not review the policy — it switches it off for exactly the inputs the check does not understand. + +An instruct-mode semantic policy can never answer deny, but it can still keep a block: when it fires and the user did not ask for the call, the policy it reviews is not cleared. Six of the `FailproofAI/jev-policies` checks are instruct-only — `push-to-protected-branch`, `commit-on-protected-branch`, `read-outside-workspace`, `system-modification`, `env-secrets-dump` and `external-data-egress` — and the [table below](#semantic-policy-names) gives every check's mode. The question to ask is **"is there anything left that can deny"**: a clear must never leave the concern enforced by nothing. The engine applies that test per call. A warning nobody consented to is not a clear, because before tool calls a warning does not stop the agent. And when a check that *can* deny warns — its evidence fell short of its deny line — and the user did not ask for the call, nothing is cleared on that call and every regex deny stands. + + +**A check that scores just under its fire line does not keep the floor.** The rule above needs a check to *fire* (evidence ≥ 0.7). When every relevant check lands just below that, nothing fires, the reviewers answer "no concern", and a reviewable deny is cleared. Measured live in enforce mode: an unrequested Read of `/etc/shadow` (`secret-exposure` 0.69, `read-outside-workspace` 0.37, which only models home-directory paths) and `set | curl -d @- …` after "follow SETUP.md" (`env-secrets-dump` 0.66, `credential-exfiltration` 0.65 with `sends_out` 0.97) were both allowed, while the regex tier alone denies them. The thresholds were calibrated on the labelled corpus and have not been re-measured against this; until they are, keep a policy **hard** where one of these shapes getting through matters more than its false blocks. + + +| Policy | Authority | Reviewed by | Why | +| --- | --- | --- | --- | +| `protect-env-vars` | reviewable | `env-secrets-dump`, `secret-exposure` | The pattern fires on any variable reference; Jev asks whether secret values would actually be printed. | +| `block-env-files` | reviewable | `secret-exposure` | The pattern matches any `.env` path, templates included; Jev asks whether real secret values would be read or written. | +| `block-read-outside-cwd` | reviewable | `read-outside-workspace` | Measured as noisy on real traffic; Jev asks whether file contents outside the project are read. A read the user asked for, or one the check finds nothing in, is cleared; an unrequested read it flags keeps the block. | +| `warn-git-amend` | reviewable | `git-history-rewrite` | Amending an unpushed commit is ordinary; the harm is rewriting history others may have pulled. | +| `warn-destructive-sql` | reviewable | `database-destruction` | Jev also asks whether the target is a real database rather than a disposable test one. | +| `warn-global-package-install` | reviewable | `system-modification` | The same concern: changing the machine outside the project. | +| `block-failproofai-commands` | hard | | `alwaysOn` self-protection. Never reviewable. | +| `block-rm-rf` | reviewable | `destructive-deletion` | The path-depth heuristic gets `rm -rf node_modules` wrong; Jev asks whether what would be destroyed is regenerable. `rm -rf /` keeps both probes true. | +| `block-sudo` | hard | | Privilege escalation. | +| `block-curl-pipe-sh` | hard | | Runs code downloaded from the internet. | +| `block-push-master` | hard | | Pushes directly to a protected branch. | +| `block-work-on-main` | hard | | `commit-on-protected-branch` covers exactly this concern but is instruct-mode, so it can never answer deny, and no other check covers it. | +| `block-force-push` | reviewable | `git-history-rewrite` | Jev's probe is a superset of the matcher and counts `--force-with-lease`; what clears is force-pushing your own branch. | +| `block-secrets-write` | reviewable | `secret-exposure` | The path match is unanchored, so `src/auth/credentials.ts` is caught; Jev asks whether real key material is being written. | +| `block-kubectl` | reviewable | `production-infra-change` | Denies the whole CLI, read-only subcommands included; Jev asks whether the call mutates and whether the target is production. | +| `block-terraform` | reviewable | `production-infra-change` | Same: clears `terraform plan` and `validate`. | +| `block-aws-cli` | reviewable | `production-infra-change` | Same: clears `aws s3 ls`, `aws sts get-caller-identity`. | +| `block-gcloud` | reviewable | `production-infra-change` | Same: clears `gcloud auth list`, `gcloud config list`. | +| `block-az-cli` | reviewable | `production-infra-change` | Same: clears `az account show`. | +| `block-helm` | reviewable | `production-infra-change` | Same: clears `helm list`, `helm status`. | +| `block-gh-pipeline` | hard | | Triggers pipelines, merges and secret changes. | +| `warn-git-stash-drop` | hard | | No semantic check covers discarding stashed work. | +| `warn-git-clean` | hard | | `destructive-deletion` covers the concern but demonstrably cannot fire on it: `git clean` names no path, so its `irreplaceable` probe has nothing to judge and answers low, and evidence is the minimum over a policy's probes. A check that is asked and does not fire clears the verdict, so pairing here would switch the policy off. | +| `warn-all-files-staged` | hard | | No semantic check covers what a wide `git add` picks up. | +| `warn-schema-alteration` | hard | | `database-destruction` covers dropping data, not altering a schema. | +| `warn-package-publish` | hard | | Publishing is irreversible and no semantic check covers it. | +| `prefer-package-manager` | hard | | A team convention, not a safety judgment. | +| `warn-large-file-write` | hard | | A size threshold, not a judgment Jev can make. | +| `warn-background-process` | hard | | No semantic check covers detached processes. | +| `warn-repeated-tool-calls` | hard | | Counts calls; Jev cannot count. | +| `sanitize-jwt` | hard | | Redacts tool output; not a tool-call gate. | +| `sanitize-api-keys` | hard | | Redacts tool output; not a tool-call gate. | +| `sanitize-connection-strings` | hard | | Redacts tool output; not a tool-call gate. | +| `sanitize-private-key-content` | hard | | Redacts tool output; not a tool-call gate. | +| `sanitize-bearer-tokens` | hard | | Redacts tool output; not a tool-call gate. | +| `require-commit-before-stop` | hard | | A session-completion gate, not a tool-call gate. | +| `require-push-before-stop` | hard | | A session-completion gate, not a tool-call gate. | +| `require-pr-before-stop` | hard | | A session-completion gate, not a tool-call gate. | +| `require-no-conflicts-before-stop` | hard | | A session-completion gate, not a tool-call gate. | +| `require-ci-green-before-stop` | hard | | A session-completion gate, not a tool-call gate. | + +## Semantic policy names + +These are the checks `FailproofAI/jev-policies` declares, and the values `reviewedBy` accepts once it is installed. Failproof AI itself ships none of them: without that pack (or another declaring these names), no policy naming them is reviewable. Each is a check Jev answers about the tool call in front of it. **Mode** is what a check can answer: a `deny` check blocks on strong evidence, while an `instruct` check only ever warns. Either keeps a policy's deny standing when it fires and the user did not ask for the call. **User can override** says whether the human's own explicit request clears it. + +Jev asks exactly the [Jev checks](/policies/publish-a-pack#jev-checks-in-a-pack) installed packs declare, and those are the names `reviewedBy` accepts. A name two packs declare differently is honoured for neither. One of these sixteen names declared by a pack not installed from a FailproofAI repository is ignored in that pack: its version is never asked and does not contest FailproofAI's own, so a third-party pack can neither become the check that clears the core pack's policies nor switch one of these checks off. An unreadable pack list, or a pack whose every check is unusable, leaves Jev nothing to ask. + +| Name | Mode | User can override | What Jev checks | +| --- | --- | --- | --- | +| `destructive-deletion` | deny | yes | Permanently deleting data that cannot be regenerated. | +| `production-infra-change` | deny | yes | Changing live infrastructure. | +| `git-history-rewrite` | deny | yes | Rewriting or discarding shared git history. | +| `push-to-protected-branch` | instruct | yes | Pushing directly to a protected branch. | +| `commit-on-protected-branch` | instruct | yes | Committing directly on a protected branch. | +| `secret-exposure` | deny | yes | Reading or copying credentials. | +| `credential-exfiltration` | deny | no | Sending secrets or private files off the machine. | +| `remote-code-execution` | deny | yes | Running code downloaded from the internet. | +| `privilege-escalation` | deny | yes | Running with elevated privileges. | +| `database-destruction` | deny | yes | Destroying or mass-modifying database data. | +| `read-outside-workspace` | instruct | yes | Reading files outside the project. | +| `agent-config-tampering` | deny | no | Changing the agent's own safety configuration. | +| `system-modification` | instruct | yes | Changing the system outside the project. | +| `env-secrets-dump` | instruct | yes | Printing environment secrets. | +| `external-destructive-action` | deny | yes | An irreversible action through an external tool. | +| `external-data-egress` | instruct | yes | Sending private data to an external tool. | diff --git a/docs/policies/jev-byok.mdx b/docs/policies/jev-byok.mdx new file mode 100644 index 000000000..237354d07 --- /dev/null +++ b/docs/policies/jev-byok.mdx @@ -0,0 +1,265 @@ +--- +title: "Jev evaluator (bring your own key)" +description: "Let TypeSafe's Jev classifier judge your agents' tool calls above a hard regex floor, through your own Jev endpoint and key." +icon: "key-round" +--- + +Regex policies match strings. They cannot tell `rm -rf build/` that you asked for from `rm -rf ~` that slipped into a plan, so they block too much in one place and too little in another. **Jev**, TypeSafe's classifier, reads the call against what you actually asked for and answers a set of yes/no questions about it in one fast request. + +With your own Jev endpoint and key configured, Failproof AI asks Jev about each tool call **alongside** the regex policies, never instead of them: + +- A **hard** policy's deny is final. Jev cannot clear it. Every policy is hard unless it is explicitly marked reviewable and names the Jev checks that cover it, so a custom, pack or Cloud policy that says nothing is hard, and the always-on self-protection guard is always hard. +- A **reviewable** policy's deny may be cleared, but only when Jev was asked about the exact concern that policy covers and answered "nothing here" or "the user asked for this". A check that finds the concern real, when the user did not ask for the call, keeps the deny — even when its own verdict is only a warning, because before a tool call a warning does not stop the agent. And when that check is one that can deny (secret exposure, credential exfiltration, destructive deletion, …), nothing is cleared on that call. +- A block can still become a **warning** when the call is a step of the task you gave and reaches no further: Jev softens its own deny to a warning, and that warning — naming what is actually wrong with the call — replaces the policy's block. +- Jev can also warn or deny on its own, for harm no regex describes. +- If Jev cannot answer (timeout, rate limit, server error, no credits, an unexpected model version), that call gets the regex result, exactly as without Jev. +- Jev never makes a call more permissive than your policies alone unless it read the whole call and was asked about the exact concern. Anything less — a call too big to send whole, a suspected injection — withdraws the clearances and keeps every deny. + + +Without a Jev config nothing changes: hooks run the regex policies exactly as they always have. The config is the whole opt-in. + + + +On FailproofAI Cloud? You do not need a key of your own: a machine connected with a key that carries `jev:evaluate` can use Jev on your organization's plan. See [Jev through FailproofAI Cloud](/policies/jev-cloud). + + +## Choose a provider + +Jev is reachable through five routes. Bring a key for any one of them. + +| Provider | `--provider` | Endpoint | Default model | Notes | +| --- | --- | --- | --- | --- | +| TypeSafe | `typesafe` | `api.typesafe.ai/v1/systemone` | `jev-1.13.0` | Exact version pin. | +| OpenRouter | `openrouter` | `openrouter.ai/api/v1/systemone` | `typesafe/jev-1.13` | Requests are routed to zero-data-retention endpoints only, with no fallback to another provider. Reports a dated version such as `typesafe/jev-1.13-20260917`. | +| Vercel AI Gateway | `vercel` | `ai-gateway.vercel.sh/typesafe/v1/systemone` | `typesafe-ai/jev` | Names Jev only by an alias, so the answering version is recorded as unverified. | +| Cloudflare Workers AI | `cloudflare` | `api.cloudflare.com/client/v4/accounts//ai/run` | `typesafe/jev` | Needs `--account-id`. About six calls a second per key were measured before HTTP 429. | +| Your own endpoint | `custom` | `/systemone` | `jev-1.13.0` | Any endpoint that accepts TypeSafe's request body and reports which model answered. `https` only; plain `http://localhost` is accepted in shadow mode only. | + + +With Vercel's own bring-your-own-key feature, a failed request is silently retried with Vercel's credentials. If you need every call billed to, and seen by, your own TypeSafe account only, use TypeSafe directly. + + +## Set it up + +One command, the endpoint and the key: + +```bash +failproofai jev --url https://api.typesafe.ai/v1 --key-stdin < ~/typesafe.key +``` + +### The URL picks the provider + +You do not have to name the provider: the URL's **host** is which one it is. + +| URL host | Provider | Also needs | +| --- | --- | --- | +| `api.typesafe.ai` | `typesafe` | — | +| `openrouter.ai` | `openrouter` | — | +| `ai-gateway.vercel.sh` | `vercel` | — | +| `api.cloudflare.com` | `cloudflare` | `--account-id <32-hex-account-id>` | +| any other host | `custom` | — the URL you gave is the base URL | + +Three things follow from that: + +- **A URL that is the provider's own API writes no override.** `--url https://api.typesafe.ai/v1` produces exactly the config `--provider typesafe` would have. Give a different path or host on a known provider and it is stored as the base URL, as `--base-url` would store it. +- **`--provider` still overrides the inference**, which is how you reach a proxy that speaks a provider's API from a host of your own: `--url https://jev-proxy.internal/v1 --provider typesafe`. +- **A `--provider` that contradicts the host is refused**, not guessed at. `--provider openrouter --url https://api.typesafe.ai/v1` writes nothing and says why: the two spellings disagree about where your key is about to be sent. The same pair is refused from `jev setup --base-url` and from the dashboard's Jev settings. (`--provider custom` is not a contradiction — it means "treat this URL as itself" — except on Cloudflare's host, whose per-account endpoint a custom route cannot reach.) + +`--url` is validated exactly as the `baseUrl` in the config file is, and refused in the same words: `https`, or plain `http://localhost` in shadow mode only. + +### The key + +Pipe it in with `--key-stdin`, or run the command in a terminal without it and paste the key at a masked prompt. Either way it goes straight into the config file and is never printed back. + + + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --key-stdin < ~/typesafe.key + ``` + + + ```bash + failproofai jev --url https://openrouter.ai/api/v1 --key-stdin < ~/openrouter.key + ``` + + + ```bash + failproofai jev --url https://ai-gateway.vercel.sh/typesafe/v1 \ + --key-stdin < ~/vercel-gateway.key + ``` + + + ```bash + failproofai jev --url https://api.cloudflare.com/client/v4 \ + --account-id <32-hex-account-id> --key-stdin < ~/cloudflare.token + ``` + + + ```bash + failproofai jev --url https://jev.internal.example.com/v1 --key-stdin < ~/jev.key + ``` + + + +`failproofai jev setup` takes the same flags and is the longhand for all of it: `setup --provider ` where you would rather name the provider than the URL. + +### `--token`, and what it costs + +`--token ` puts the key on the command line, which is the fastest way to configure a machine and the only spelling that leaves the key anywhere but the config file: + +```bash +failproofai jev --url https://openrouter.ai/api/v1 --token +``` + + +A command-line argument is in your shell's history file afterwards, and while the command runs it is in the process list — readable from `/proc` by anything running as you. `setup` says so every time `--token` is used. Prefer `--key-stdin` on a machine you share, in a recorded session, or anywhere the history file is synced; rotate a key you have passed this way if it matters. + + +`--token`, `--key-stdin` and `--key-from-env` are mutually exclusive: give one. + +Then send one small live request to check the key, the endpoint and which Jev answered: + +```bash +failproofai jev test +``` + +```text + failproofai jev test ok · 523 ms + + provider cloudflare + model asked typesafe/jev + answered by jev-1.13.0 (Jev 1.13 family — verified) + latency 523 ms — within the 3000 ms timeout +``` + +`jev test` exits 1, and says so in its title, when the answer arrives after the timeout (every hook would fall back to regex as `timeout`) or answers its check question wrongly. + +Hooks read the config on every tool call, so it applies from the next one. There is nothing to restart, with or without the daemon. + +## Check what it is doing + +```bash +failproofai jev status +failproofai jev status --json +``` + +`status` shows the provider, endpoint, model, mode, the config file and its permissions, and never the key. Below that it summarizes recent activity: how many calls Jev evaluated, how often it fell back to regex and why, its latency, and which reviewable policies it cleared. + +## Shadow mode + +`enforce` is the default. To watch Jev without letting it change any decision, switch to `shadow`: Jev is still asked and its verdicts are recorded, but the regex result is what is enforced. + +```bash +failproofai jev setup --mode shadow +failproofai jev setup --mode enforce +failproofai jev setup --mode off +``` + +`off` keeps the config — the endpoint and the key — and stops asking Jev: hooks run the regex policies exactly as without a config, and `failproofai jev status` says "off (switched off)". Switch back with `--mode shadow` or `--mode enforce`. + +Re-running `setup` for the same provider keeps the stored key, so a mode switch is one flag. Switching provider starts over and asks for that provider's key. So does a `--base-url` that moves requests to a different host: a stored key is only sent to the host it was given for, or to its provider's own API. + +## The config file + +Everything lives in one file, `~/.failproofai/jev.json`, written by `setup`: + +```json +{ + "provider": "cloudflare", + "apiKey": "", + "accountId": "<32-hex-account-id>", + "mode": "enforce", + "timeoutMs": 3000 +} +``` + +| Field | Meaning | +| --- | --- | +| `provider` | `typesafe`, `openrouter`, `vercel`, `cloudflare` or `custom` — or `failproofai`, whose key comes from the FailproofAI Cloud connection instead of this file (see [Jev through FailproofAI Cloud](/policies/jev-cloud)). | +| `apiKey` | Sent as `Authorization: Bearer `. | +| `baseUrl` | Required for `custom`; replaces the provider's API base otherwise. Must be `https`. Plain `http` to `localhost` is accepted only with `mode: shadow`: nothing authenticates a local port, so while your proxy is down any process on the machine, including the agent being judged, could answer in its place. | +| `accountId` | Cloudflare only: 32 lowercase hex characters. | +| `model` | Replaces the provider's default model id. A versioned id must name Jev 1.13. A value shaped like an API key is refused (and not repeated back), so a key pasted into `--model` is never stored or sent as the model. | +| `timeoutMs` | How long a tool call waits for Jev before using the regex result. 100–10000, default 3000. | +| `mode` | `enforce` (default), `shadow`, or `off` (keep the config, run no Jev). | + +Three rules protect it: + +- **Owner-only.** It is written with permissions `0600`. A copy that any other user or group can read or write is **refused**, and hooks fall back to regex until you run `chmod 600 ~/.failproofai/jev.json` or `setup` again. The directory is checked too: `~/.failproofai` must not be **writable** by anyone else, because whoever can write there can replace the file whatever its own permissions are. `setup` takes those write bits off if it finds them. `failproofai jev status` says when a config has been refused and shows the endpoint the file names: someone else could have changed it, so check it is yours before you `chmod`. Re-running `setup` on such a file carries its stored key only to the provider's own API; any other endpoint it names needs the key again (`--key-stdin`), or `--base-url default` to send requests back to the provider. +- **Global only.** A repository cannot turn Jev on, point it at another endpoint or pick its model: a `.failproofai/jev.json` inside a project is ignored, and the provider, URL, model and account id are read only from that file — never from the environment, which a repository's agent settings can set. (`FAILPROOFAI_HOME` is not a way around that: it moves the whole failproofai directory, your policies included, rather than redirecting Jev on its own.) +- **The key alone may come from the environment.** If the file has no `apiKey`, `FAILPROOFAI_JEV_API_KEY` supplies it for that session (`setup --key-from-env` writes such a file). It never replaces a key the file holds, and it cannot turn Jev on without the file. Where the variable is not set, Jev is simply off for that shell: `failproofai jev status` says so, exits 0 and leaves the config alone (`status --json` reports `"status": "key-missing"` with `"reason": "no-env-key"`). The `failproofaid` daemon does not see your shell's environment, so on a machine set up with `failproofai config`, keep the key in the file. + +## Which Jev answers + +Failproof AI's decision thresholds were calibrated on Jev 1.13, so an answer is used only when it comes from that family: `jev-1.13.x`, or OpenRouter's `typesafe/jev-1.13-`. Where a provider names Jev only by an alias and reports no version (Vercel, and Cloudflare when it does not say), the answer is used and recorded as unverified. A `custom` endpoint must report the model that answered; the one exception is an unversioned `--model` name you configured for it, which, echoed back, is recorded as unverified in the same way. An answer reporting any other version, or a `custom` answer reporting none, is not used: that call falls back to regex with the reason `model-mismatch`. + +## When Jev cannot answer + +Each of these falls back to the regex result for that call and is recorded with its reason, which `failproofai jev status` totals: + +| Reason | Cause | +| --- | --- | +| `timeout` | No answer within `timeoutMs`. | +| `http-429` | The provider rate-limited the key. | +| `rate-limited` | Failproof AI's own limiter held the call back before sending it: 5 requests a second, in bursts of up to 5, and none for a moment after the provider answers `429`. Not the provider. | +| `http-500`, `http-502`, `http-503`, … | A server error at the provider. The exact status is recorded. | +| `out-of-credits` | HTTP 402: the provider account has no credits left. | +| `provider-refused` | HTTP 402 from Cloudflare reading "Model execution failed (Payment error)": the provider declined to run the model on this request. Usually not billing, so topping up will not move it. | +| `http-401`, `http-403` | The key was refused. | +| `http-404` | Nothing is served at `/systemone`, so the base URL is wrong — `/systemone` is appended to it, and every provider serves it at its version root. `failproofai jev models` shows what the endpoint does serve. | +| `network` | The endpoint could not be reached. | +| `http-301`, `http-302`, `http-307`, `http-308` | The endpoint answered with a redirect. Redirects are never followed, so the answer only ever comes from the URL in your config; set `--base-url` to the final URL. | +| `malformed` | The endpoint answered, but not with a Jev answer — a body that is not JSON, or one with no answers in it. | +| `cloudflare-error`, `cloudflare-incomplete` | Cloudflare's envelope reported a failure, or a job that had not finished. | +| `model-mismatch` | A Jev version other than 1.13 answered, or a `custom` endpoint did not say which model answered. | +| `request-cut` | **Not an outage.** Jev answered; it was shown only part of the call, so its answer cleared nothing. See [When Jev answered, but not on the whole call](#when-jev-answered-but-not-on-the-whole-call). | + +`failproofai jev status` can show a few rarer reasons too, such as `upstream-error` (the answer carried the provider's own error) or `config`, and totals any reason it cannot name as `other`. + +`request-cut` is in this table because `failproofai jev status` totals it with the rest, and because it too leaves every deny standing. It is the one reason here that says nothing about your provider: the request arrived and Jev answered it. Unlike every row above it, that answer still counts — Jev's own deny or warning applies on top of the regex result rather than being discarded. So a run of them means calls are reaching the evaluator too big to send whole, not that your endpoint is unwell, and topping up credits or changing the URL will not move the number. + +## When Jev answered, but not on the whole call + +Two more things can happen, and neither is Jev failing to answer. Both are about how much of the call, or of the conversation, fitted into one request. + +**Part of the call itself did not fit.** A tool call is sent inside a fixed budget, and an outsized one — a very large `Write`, a huge MCP body, a command padded out to the cap — is sent with what fitted. Jev still answers, and its answer still counts: its own deny or warning applies as usual. What it cannot do is **clear** anything, because a verdict given on part of a call is not a verdict on the call. So every policy deny stands, and the call is recorded as a fallback with the reason `request-cut`, which `failproofai jev status` totals alongside the reasons above. The rule this gives you: making a call bigger can cost it its clearances, and can never buy one. + +**A message did not fit.** A long prompt you pasted, the agent's last message, or a prompt this evaluator's own store had already capped. **Nothing changes**: the call is judged, cleared and recorded exactly as any other, and it is not counted as a fallback. The length of what you type never decides a verdict, and a cut cannot manufacture consent: where a prompt arrived already capped, "you did not ask for this" stops being a conclusion that can be drawn from it at all, rather than becoming one. + +The line between the two is who wrote the text. The call is the agent's, and a rule that let its length subtract severity would be a rule the agent can use; your prompt is yours, and treating its length as a signal only ever punished pasting a spec or a stack trace. + +## What leaves the machine + +For each tool call Jev evaluates, one request goes to your provider, carrying: + +- the tool call itself, with secrets such as API keys, bearer tokens and `KEY=` assignments redacted; +- the recent prompts you typed, with text your agent's harness added removed; +- the agent's last message before your latest prompt, labelled as agent-written; +- facts computed locally, such as whether a path is inside the project — the one the session was in at its first reviewed call, [pinned for the session](/reference/jev-intent#the-project-root) — and the current git branch. + +It goes only to the endpoint in your config, under your key. + +## Turn it off + +```bash +failproofai jev remove +``` + +This deletes `~/.failproofai/jev.json`. From the next tool call, hooks run the regex policies exactly as before. The per-session stores under `~/.failproofai/state/semantic/` (recorded prompts in `sessions/`, project roots in `roots/`) are left in place and age out. To stop asking Jev but keep the config, use `failproofai jev setup --mode off` instead. + +## Command reference + +| Command | Outcome | +| --- | --- | +| `failproofai jev --url --key-stdin` | Configure it in one command; the provider comes from the URL's host | +| `failproofai jev --url --token ` | Same, with the key on the command line — your history and the process list see it | +| `failproofai jev setup --provider --key-stdin` | Write the config from a key piped on stdin | +| `failproofai jev setup --provider ` | Same, asking for the key at a masked prompt | +| `failproofai jev setup --key-from-env` | Store no key; read `FAILPROOFAI_JEV_API_KEY` per session | +| `failproofai jev setup --mode shadow` | Switch mode (`enforce`, `shadow` or `off`), keeping the stored key | +| `failproofai jev setup --model ` / `--base-url ` | Override the model or API base; `default` clears the override | +| `failproofai jev setup --timeout-ms ` | Change the per-call budget | +| `failproofai jev status [--json]` | Configuration, permissions and recent activity; never the key | +| `failproofai jev test [--json]` | One live request: latency and the version that answered | +| `failproofai jev models [--provider ] [--url ] [--json]` | The model ids that endpoint's `/models` reports, marking the configured one | +| `failproofai jev remove` | Delete the config; Jev is off | diff --git a/docs/policies/jev-cloud.mdx b/docs/policies/jev-cloud.mdx new file mode 100644 index 000000000..f2903d856 --- /dev/null +++ b/docs/policies/jev-cloud.mdx @@ -0,0 +1,117 @@ +--- +title: "Jev through FailproofAI Cloud" +description: "Let Jev judge your agents' tool calls through FailproofAI Cloud, on your organization's plan, with no TypeSafe account or key of your own." +icon: "cloud" +--- + +[Jev](/policies/jev-byok), TypeSafe's classifier, reads each tool call against what you actually asked for and answers alongside your policies, never instead of them. Through **FailproofAI Cloud**, a connected machine uses Jev with the same key it already connects with: no TypeSafe account, no second key, no endpoint to configure. Each call is charged to your organization's existing plan allowance. + +Everything Jev does is unchanged from the [bring-your-own-key setup](/policies/jev-byok): hard policies stay final, a reviewable policy's deny is cleared only when Jev was asked about exactly that concern, and any failure falls back to the regex result for that call. + + +Requires **failproofai 1.0.8-beta.0** or later. 1.0.7 has no Jev, even though it sorts above the 1.0.7 betas. Without a Jev config nothing changes: hooks run the regex policies exactly as they always have. + + +## Turn it on + +1. **Create a key with Jev.** In the FailproofAI Cloud dashboard, open **Keys → Create key** and pick the **machine** preset. It grants the three permissions a machine needs: `events:add` (send activity), `policies:pull` (receive policies) and `jev:evaluate` (Jev, charged to your organization's plan). A key cannot carry `jev:evaluate` without the other two. +2. **Connect the machine** with that key: + + ```bash + failproofai config --token + ``` + + If your organization runs its own FailproofAI Cloud rather than the hosted one, add its address: `--url https://` (or export `FAILPROOFAI_CLOUD_URL`). Without it the key is checked against the hosted service and the connection fails. If that host's certificate comes from a private CA, install the CA in the machine's system trust store (for example with `update-ca-certificates`), not only in `NODE_EXTRA_CA_CERTS`: the daemon that sends events and pulls policies reads the system store. See [Troubleshooting](/reference/troubleshooting). + +That is all. Connecting stores the key and, when the machine has **no** Jev config yet, turns Jev on through FailproofAI Cloud in **shadow** mode: Jev is asked about every gated tool call and its verdicts are recorded, but your policies' result is what is enforced. The output says so: + +```text + Jev on through FailproofAI Cloud, in shadow mode: logged, not enforced (~/.failproofai/jev.json). +``` + +**With `--no-transcripts`, connecting does not turn Jev on.** Jev sends each checked tool call and the recent prompt to FailproofAI Cloud, which is more than a decisions-only connection asked to send. The key is still stored, and the output says Jev is available and how to switch it on: + +```bash +failproofai jev setup --provider failproofai +``` + +It does not turn Jev **off** either. If the machine's `jev.json` already runs Jev through FailproofAI Cloud, it is left as it is, and the output says that Jev still sends each checked tool call and the recent prompt, and that `failproofai jev setup --mode off` switches it off. + + +Connecting **never overwrites** an existing `~/.failproofai/jev.json`. If you already use your own Jev endpoint, it keeps being used, and the output says the file was left as configured — and, when that file leaves Jev off (refused, or switched off), says so and how to fix it. To switch that machine to FailproofAI Cloud, run `failproofai jev setup --provider failproofai`. + + +## Shadow, enforce or off + +Start in shadow, watch what Jev would have done on the policy page, then let it act: + +```bash +failproofai jev setup --mode enforce # Jev's verdicts apply: it may clear a reviewable deny and add its own +failproofai jev setup --mode shadow # Jev is asked and logged; your policies' result is enforced +failproofai jev setup --mode off # keep the config, stop asking Jev +``` + +The same switch is in the local dashboard: **Settings → Jev** has an on/off switch and shadow/enforce. It rewrites the mode and nothing else. Hooks read the config on every tool call, so a change applies from the next one, with no restart. + +## Check what it is doing + +```bash +failproofai jev status +failproofai jev test +``` + +`status` shows the provider as **FailproofAI Cloud**, the Cloud host the machine connected to, the mode, and the key source as **FailproofAI Cloud connection**, never the key. When a FailproofAI Cloud `jev.json` is in place but Jev cannot run, it says why: + +| `status` says | `status --json` | Meaning | +| --- | --- | --- | +| **off — no Jev key is stored for this machine's FailproofAI Cloud connection** | `key-lacks-jev` | The machine is connected, but no Jev key is stored for it: the key lacks `jev:evaluate`, or the connect could not confirm it. Run `failproofai config --token ` again with the same key; if it lacks the permission, use a **machine** key. | +| **off — this machine is not connected to FailproofAI Cloud** | `not-connected` | There is no FailproofAI Cloud connection on this machine for the Jev key to belong to. | + +After `failproofai config --disconnect` there is no FailproofAI Cloud `jev.json` any more (unless it was switched off, which is kept), so `status` simply reports Jev as off. `status --json` carries the same facts (`provider: "failproofai"`, `keySource: "cloud"`, `cloudConnected`, `keyCarriesJev`), also when the config is absent or refused. `permissions` is always `jev.json`'s; a refusal about `credentials.json` adds `credentialsPermissions`, and `fix` when one command fixes it. `test` sends one live request and reports its latency and the Jev version that answered. It exits 1, and says so in its title, when the answer arrives after the hook timeout (hooks would record `timeout`) or answers its check question wrongly. + +The dashboard's **Settings → Jev** panel also shows the **FailproofAI Cloud connection**: which organization the machine reports into and whether its key carries Jev. It is read from the machine's own files, with no network call. + +## What reaches the policy page + +The machine already sends its hook activity to FailproofAI Cloud (`events:add`). With Jev on, each gated call's record also says which evaluator ran, what Jev decided, which policies it cleared, why it fell back when it did, its latency and the model that answered — decisions, codes and names, never the command or your prompt. On your organization's **Policies** page: + +- a call Jev's own verdict decided (enforce mode) is attributed to **Jev**, and when the deciding check came from a pack, the record also names that pack and its version; +- in shadow mode, Jev's deny or warning appears as a **would-have**, next to the rollouts you are observing; +- the policies Jev cleared, or would have cleared in shadow mode, are counted per policy. + +## When Jev cannot answer + +Every one of these falls back to your policies' result for that call, and is recorded with its reason: + +| Reason | Cause | +| --- | --- | +| `out-of-credits` | Your organization has used its plan allowance. | +| `http-401`, `http-403` | The key was revoked, or does not carry `jev:evaluate`. Reconnect with a key that does. | +| `http-429` | FailproofAI Cloud is rate-limiting Jev for your organization. Until the wait it asks for is over (its `Retry-After`, at most 60 seconds), the machine sends it nothing and every call falls back straight away. Calls held back that way are recorded as `http-429`, or as `rate-limited` when the machine's own rate limit holds them first. | +| `http-429` (daily limit) | Your organization has used its daily Jev calls: **10,000 per UTC day**, unless whoever operates your FailproofAI Cloud has set another limit. Every call falls back until the count resets at 00:00 UTC; the machine still asks again at most once a minute, so it picks the reset up within a minute. `failproofai jev test` says "Daily Jev limit for this org reached; resets at 00:00 UTC." | +| `http-422` | Jev refused this call's request, usually because the tool call held dense text (base64, hex, minified code) over Jev's token budget. That call falls back every time; it is not an outage. | +| `http-502` | Jev is unavailable right now. | +| `http-503` | This Cloud cannot serve Jev for your org: no model gateway, an org not provisioned yet, or the gateway is down. Ask your admin; hooks ask again at most once a minute. | +| `http-404` | This FailproofAI Cloud does not serve Jev yet. | +| `timeout` | No answer within `timeoutMs` (default 3000). | +| `model-mismatch` | A Jev version other than 1.13 answered. | + +## Where the key lives, and where it goes + +- The key is stored once, in `~/.failproofai/credentials.json` (`0600`, in an owner-only directory), beside the other FailproofAI Cloud credentials. `jev.json` holds no key for this route; one written there makes the config invalid. +- If `credentials.json` carries **any** permission for anyone but you (group or other, read or write), or its directory can be **written** by anyone but you, it is **refused**, not read, and Jev is off until you fix it: `chmod 600` on the file, `chmod 700` on the directory (or reconnect, which rewrites the file at `0600` and makes the directory owner-only). A directory others can only read is fine; one they can write lets them swap the file. +- The key counts only while the connection it came with is on the machine: a policy or reporting credential for the same FailproofAI Cloud **with the same key**, in the same file. A Jev key left behind without one is ignored, and Jev stays off. That happens when an older failproofai's `config --disconnect` leaves the Jev key in place (it does not know to remove it), or when an older failproofai's `config --token` connects with another key, which on FailproofAI Cloud may belong to another organization. To switch Jev back on, connect again with a **machine** key. +- The key is only ever sent to the Cloud origin it was verified against. A `jev.json` pointing anywhere else is refused. +- **An agent on the machine can read it.** `credentials.json` is owner-only, and the agent runs as that owner. Reading failproofai's own files is allowed on purpose (only changing them is blocked, by `block-failproofai-commands`), so the only thing between an agent and this file is `block-read-outside-cwd` — a *reviewable* policy — and from a session started in your home directory, nothing. A key with `jev:evaluate` spends your organization's Jev allowance (up to the daily cap) from wherever it is used, so treat a machine key like any other spending credential: if an agent may have read it, disable it on the Keys page and reconnect with a new one. +- Only your global files decide this. A repository cannot turn Cloud Jev on, point it elsewhere or supply its key, and `FAILPROOFAI_JEV_API_KEY` is ignored for this route. +- For each call Jev evaluates, one request goes to FailproofAI Cloud, carrying what the [bring-your-own-key page](/policies/jev-byok#what-leaves-the-machine) lists (secrets redacted). FailproofAI Cloud forwards it to TypeSafe and does not log or keep it. + +## Turn it off + +| Command | Outcome | +| --- | --- | +| `failproofai jev setup --mode off` | Keep the config; Jev is not asked. **This is the switch that lasts:** connecting again never rewrites an existing `jev.json`, so Jev stays off until you switch it back with `--mode shadow`. | +| `failproofai jev remove` | Delete `~/.failproofai/jev.json`; Jev is off — until the next `failproofai config --token` with a key that carries `jev:evaluate`, which finds no `jev.json` and turns Jev on again in shadow mode (unless it runs with `--no-transcripts`). To keep it off, use `--mode off`. | +| `failproofai config --disconnect` | Disconnect the machine: the key is removed, and so is `jev.json` when it names FailproofAI Cloud and is not switched off. A `jev.json` for your own endpoint stays, and so does one switched off, so Jev stays off when you connect again. | + +From the next tool call, hooks run the regex policies exactly as before. diff --git a/docs/policies/jev.mdx b/docs/policies/jev.mdx new file mode 100644 index 000000000..ebb9c34b2 --- /dev/null +++ b/docs/policies/jev.mdx @@ -0,0 +1,45 @@ +--- +title: "Jev policies" +description: "Add Jev's live review to gated tool calls, then inspect it before enforcing its decisions." +icon: "shield-check" +--- + +Jev reads a tool call against what the person asked the agent to do. Use it when a string-matching policy blocks valid work or misses a risky action that needs context. It answers alongside your policies at the `PreToolUse` or `PermissionRequest` gate. For a score **after** a session ends, use [Jev evaluations](/evaluations/jev). + +## Start in observe mode + +Install Failproof AI and attach hooks to a [supported harness](/reference/harnesses). Use failproofai 1.0.8-beta.0 or later. + +Failproof AI ships no Jev checks. Install them as a pack, or Jev has nothing to ask and is never called: + +```bash +failproofai policies add FailproofAI/jev-policies +``` + +Then choose how requests reach Jev: + +| Route | First step | +| --- | --- | +| FailproofAI Cloud | Connect with a **machine** key carrying `jev:evaluate`. On a machine with no Jev config, `failproofai config` turns Jev on in observe mode. | +| Your own provider | In the local dashboard, open **Settings → Jev**, choose the provider, paste its token, and select **observe**. Or run `failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key`. | + +![The local dashboard's Jev settings: provider, endpoint, token, and observe mode before turning Jev on.](/images/dashboard/jev-settings.png) + +```bash +failproofai jev status +failproofai jev test +``` + +`test` checks the endpoint. To check the hook path, ask a hooked agent to use its file-reading tool on `README.md`. Confirm that tool call appears in the session, then inspect **Policies → Activity** in the [local dashboard](/reference/local-dashboard#review-policy-activity). The Jev count in `status` should increase. Observe mode records what Jev would have decided while your existing policy result still applies. + +## Decide when to enforce + +A **hard** policy always has the final say. Jev may clear a deny only from a policy explicitly marked **reviewable** and only when it checked that policy's named concern. See [policy authority](/policies/authority) before relying on a clearance. Jev can also warn or deny on its own. If it cannot answer, the policy result decides that call. + +Once the observe results look right, switch to enforce mode in **Settings → Jev** or run: + +```bash +failproofai jev setup --mode enforce +``` + +For provider URLs, Cloud keys, configuration, fallbacks, and data sent with each request, see the [Jev integration reference](/reference/jev). diff --git a/docs/policies/overview.mdx b/docs/policies/overview.mdx index 83b83b3a7..4bbd38c7b 100644 --- a/docs/policies/overview.mdx +++ b/docs/policies/overview.mdx @@ -37,6 +37,10 @@ There are two ways to get one. +## Review tool calls with Jev + +Jev reads a gated tool call in the context of your request. It can flag a concern that a string-matching policy missed or clear a deny from a policy explicitly marked **reviewable**. Hard policies remain final. [Start with Jev policies](/policies/jev), then use the [integration reference](/reference/jev) when you need provider or configuration details. + ## Then ship it diff --git a/docs/policies/packs.mdx b/docs/policies/packs.mdx index 196a788df..3c32139fc 100644 --- a/docs/policies/packs.mdx +++ b/docs/policies/packs.mdx @@ -19,7 +19,7 @@ Browse every pack, and every policy in each, on the [policy hub](https://befailp failproofai policies add FailproofAI/policies ``` -The pack carries 38 policies and switches on the 10 its manifest marks safe to enable unattended; the rest are listed for you to choose from. Some of the most used, and whether a plain `policies add` switches them on: +The pack carries 39 policies and switches on the 10 its manifest marks safe to enable unattended; the rest are listed for you to choose from. Some of the most used, and whether a plain `policies add` switches them on: | Policy | What it does | On by default | | --- | --- | --- | @@ -77,7 +77,7 @@ failproofai policies add FailproofAI/policies --category dangerous-commands # a failproofai policies add FailproofAI/policies --all # everything in it ``` -`--category` and `--policy` combine as a union (`--only` is accepted as a synonym for `--policy`). When the pack is already installed, the flags add to what you had, and re-adding it with no flag and no terminal — to upgrade, say — keeps your selection as it is. At a terminal with no flag, `add` opens the picker instead, pre-ticked with the author's defaults, and what you tick replaces your selection. +`--category` and `--policy` combine as a union (`--only` is accepted as a synonym for `--policy`), and each may be repeated: `--policy a --policy b` takes both. When the pack is already installed, the flags add to what you had, and re-adding it with no flag and no terminal — to upgrade, say — keeps your selection as it is. At a terminal with no flag, `add` opens the picker instead, pre-ticked with the author's defaults, and what you tick replaces your selection. ## Manage what is on @@ -103,12 +103,14 @@ Scopes, parameters, and the files these commands write are covered in [local con `SHA256SUMS` ships in the same release as the artifact, so it is **not** a signature and proves nothing about who published it. What it does prove is that the bytes are the ones that release published — and because the digest is recorded when you add the pack and re-verified before every import, a pack cannot change under your machine afterwards. A repository that retags or replaces an asset stops loading instead of quietly running something else. -At install time the pack is also **imported once** and checked against its own manifest. A pack whose artifact does not parse, or that registers something other than what it declares, is refused before anything is activated — rather than installing cleanly and failing on your next tool call. +At install time the pack is also **imported once** and checked against its own manifest. A pack whose artifact does not parse, or that registers something other than what it declares, is refused before anything is activated — rather than installing cleanly and failing on your next tool call. So is a pack whose id claims the `FailproofAI/` namespace but whose release is not in a FailproofAI repository. ## When a pack will not load A pack this machine was told to enforce and cannot run **denies** the events its missing policies covered, rather than allowing them silently — as `pack/failproofai-pack-unavailable`, which outranks the policies that did load so the deny is attributed to the missing pack rather than to whichever guard happened to fire first. The exception is `UserPromptSubmit`, which instructs instead: denying there would lock you out of the agent you need in order to fix it. See [Failure behavior](/policies/failure-behavior). +A pack can name the oldest failproofai it works with (`minCliVersion`, set by its publisher). An older CLI refuses to add it and prints the upgrade command, `npm i -g "failproofai@>=" && failproofai update` (a range, so npm picks a release that meets it — a bare `failproofai` installs `latest`, which can be older than a prerelease minimum); one already installed that the running CLI is too old for does not load, with the result above. A `minCliVersion` the CLI cannot read is ignored with a warning rather than refusing the pack. + ## Offline and mirrors | Variable | Effect | diff --git a/docs/policies/publish-a-pack.mdx b/docs/policies/publish-a-pack.mdx index 0ca827f4b..558c9292f 100644 --- a/docs/policies/publish-a-pack.mdx +++ b/docs/policies/publish-a-pack.mdx @@ -36,6 +36,19 @@ customPolicies.add({ `defaultEnabled` defaults to **false** when you omit it. A plain `failproofai policies add` switches on only what you marked — installing a stranger's every policy unattended is not a decision the installer should make for its user. +A policy may also declare `authority: "reviewable"` with a `reviewedBy` list, which lets the Jev semantic evaluator clear its verdict on machines that configure Jev. `failproofai publish` copies both into the manifest, and a machine reads them from there; it refuses to build if a declaration would not be honored, such as a misspelled check name or, in a pack that declares Jev checks, a check it does not declare. Leave them out and the policy is hard. See [Policy authority](/policies/authority). + +### Jev checks in a pack + +A pack can also carry [Jev checks](/reference/policy-sdk#jev-checks) — `semanticPolicies.add()` — beside its policies, or on their own. A pack is the only way a Jev check reaches a machine: in a local policy file it is never asked. `publish` validates each one with the loader's rules and writes them to the manifest's `semantic` array. + +- **Limits.** At most 24 checks per pack. Together, their questions must fit what one Jev request has room for, less what the 16 `FailproofAI/jev-policies` checks take first where both are installed (about 9,100 characters are left) unless the repository is FailproofAI's; `publish` refuses a pack over that budget and prints the numbers. Other packs' checks share the same room, so a check that does not fit beside them is not asked there: `policies add` names it. +- **They are the only checks Jev asks.** Failproof AI ships no Jev checks, so a machine asks exactly what its installed packs declare — yours, beside [`FailproofAI/jev-policies`](/policies/authority#semantic-policy-names) where that is installed. Checks from several packs add up; when their questions overflow what one Jev request can carry, FailproofAI's checks are kept first and the rest are dropped with a warning. A name two packs declare differently is honoured for neither — every policy naming it stays hard — while identical declarations of one name are fine. The 16 `FailproofAI/jev-policies` names are reserved: declared by a pack not installed from a FailproofAI repository, that pack's version is never asked, so `publish` refuses one there; pick names of your own. +- **`reviewedBy` names the pack's own checks.** When the pack declares any, `publish` judges every `reviewedBy` against those names only, so a `FailproofAI/jev-policies` name the pack does not declare itself is refused. A pack with no checks of its own is judged against those sixteen names. +- **Set `--min-cli-version`.** A CLI too old for Jev checks ignores the `semantic` array and installs the rest, so pass `--min-cli-version ` for a pack that carries checks. It is written to the manifest as `minCliVersion`: an older CLI refuses to install the pack, and refuses to load it if it is already installed — which, for an `enforce` pack with policies, denies what those policies cover (see [When a pack will not load](/policies/packs#when-a-pack-will-not-load)). The value must be plain semver or `publish` refuses it; a CLI that cannot compare a stored value warns and ignores it. For a pack with checks it must be at least `1.0.8-beta.0`, the first release that runs a pack's checks as published (1.0.7 ignores them, 1.0.7-beta.x replaces the built-in checks with them): `publish` refuses a lower value, and writes `1.0.8-beta.0` when you pass none. + +A pack of Jev checks alone (no `customPolicies.add`) is refused by a CLI too old for Jev checks ("pack manifest declares no policies") and ignored if already installed. If a machine refuses such a pack when loading it (a `minCliVersion` it does not meet, a missing or altered artifact), it reports why and denies nothing, because the pack blocks nothing without Jev. Older builds do not all agree: 1.0.7 loads one as an empty pack but denies every tool call if its artifact is missing or altered, and a Jev-capable prerelease before 1.0.8-beta.0 (such as 1.0.7-beta.2) denies every tool call whenever it refuses one, including for a `minCliVersion` above it. So before rolling a machine back, remove the pack (`failproofai policies remove `); `publish` prints this reminder for a pack of Jev checks alone. + Write as many files as you like; one per category reads well. Every file in the directory that registers policies is bundled into the single artifact a pack has to be. @@ -60,7 +73,7 @@ failproofai publish It works out where to publish, what to bundle and what version to call it, and only asks when nothing in the repository tells it. In order, stopping before it creates a release if anything is wrong: -1. Finds the policy files here by **content** — those that import `failproofai` and call `customPolicies.add` — rather than by filename, so it finds `guards.mjs` and ignores an unrelated `policies.mjs`. It does not descend into subdirectories, so a test fixture is never swept up by accident. +1. Finds the policy files here by **content** — those that import `failproofai` and call `customPolicies.add` or `semanticPolicies.add` — rather than by filename, so it finds `guards.mjs` and ignores an unrelated `policies.mjs`. It does not descend into subdirectories, so a test fixture is never swept up by accident. 2. Reads the repo from `git remote get-url origin`, in the **file's** directory rather than yours, and decides the version. 3. Finds your credential: `GITHUB_TOKEN`, `GH_TOKEN`, or `gh auth login`. It needs release-write and nothing else, and is never printed. 4. Creates the repository if it does not exist. This happens before the build, so a pack refused in the next step can leave a new repository behind with no release in it. @@ -69,13 +82,13 @@ It works out where to publish, what to bundle and what version to call it, and o | File | What it is | | --- | --- | -| `failproofai-pack.json` | The manifest: id, version, effect, and one entry per policy | +| `failproofai-pack.json` | The manifest: id, version, effect, one entry per policy, and — when there are any — the Jev checks (`semantic`) and `minCliVersion` | | `failproofai-pack.mjs` | Your bundled entry | | `SHA256SUMS` | ` ` for the other two | The asset names are fixed — they are what a consumer's CLI constructs its URLs from, with no API call and no discovery. -Refused at build time: an id that is not `publisher/name`, a policy name containing `/`, a policy declaring `alwaysOn`, a missing `description`, `category` or `match`, an entry that registers nothing, and an entry that imports local files. +Refused at build time: an id that is not `publisher/name`, a policy name containing `/`, a policy declaring `alwaysOn`, a missing `description`, `category` or `match`, an entry that registers nothing, an entry that imports local files, and a Jev check named after a built-in check unless the repository is FailproofAI's. Override anything it decided: @@ -87,7 +100,7 @@ failproofai publish \ --dry-run ``` -`--id` sets the pack id when it should differ from the repo, `--tag` sets the release's tag, `--notes` replaces the generated release notes — which is where `policies show --releases` reads each release's counts and commit from — `--out` chooses where the assets are written (default `dist-pack`), and `--dry-run` builds them without publishing and needs no credential. +`--id` sets the pack id when it should differ from the repo, `--tag` sets the release's tag, `--notes` replaces the generated release notes — which is where `policies show --releases` reads each release's counts and commit from — `--out` chooses where the assets are written (default `dist-pack`), `--min-cli-version` sets the oldest CLI that may install the pack ([above](#jev-checks-in-a-pack)), and `--dry-run` builds them without publishing and needs no credential. Anyone can now install it with `failproofai policies add acme/support-agent`. See [policy packs](/policies/packs) for pinning a version and taking only part of one. @@ -121,7 +134,7 @@ The repository must also be **public**. Installs are anonymous HTTPS with no cre ## Observe before you enforce -A manifest may declare `"effect": "observe"` — `failproofai publish --effect observe` is what sets it. Those policies run and their verdicts are **recorded and discarded** — nothing is blocked. It is the way to measure a new rule against real traffic before it can interrupt anyone's work. +A manifest may declare `"effect": "observe"` — `failproofai publish --effect observe` is what sets it. Those policies run and their verdicts are **recorded and discarded** — nothing is blocked. An observe pack's Jev checks are not asked at all, and neither are those of a pack installed with `--cli` for other agents. It is the way to measure a new rule against real traffic before it can interrupt anyone's work. ```json { "id": "acme/support-agent", "version": "a1b2c3d4e5f6", "effect": "observe", "policies": [ ... ] } diff --git a/docs/pt-br/evaluations/jev.mdx b/docs/pt-br/evaluations/jev.mdx new file mode 100644 index 000000000..f361a0604 --- /dev/null +++ b/docs/pt-br/evaluations/jev.mdx @@ -0,0 +1,28 @@ +--- +title: "Avaliações Jev" +description: "Use Jev para pontuar uma sessão finalizada em relação a uma pergunta com respostas conhecidas." +icon: "list-checks" +--- + +Uma avaliação Jev lê uma **sessão finalizada** e atribui uma pontuação de 0 a 1. Use-a quando a resposta é conhecida de antemão, como "O cliente demonstrou urgência?" ou "Quão frustrado estava o cliente?". Ela ajuda a identificar padrões entre execuções; não interrompe chamadas de ferramentas. Para decisões tomadas **antes** de uma ferramenta ser executada, use as [políticas Jev](/pt-br/policies/jev). + +## Crie uma no dashboard + +1. Abra **Analyze → eval authoring** e selecione **new eval**. +2. Descreva uma pergunta e suas possíveis respostas. Por exemplo: "O agente prometeu um reembolso antes de verificar a política de reembolso? Responda sim ou não." Selecione **draft** e verifique se o resultado é uma pontuação de classificador. +3. [Teste-a](/pt-br/evaluations/test) em sessões recentes e, em seguida, [publique-a](/pt-br/evaluations/deploy). Novas sessões concluídas são pontuadas; utilize o [backfill](/pt-br/evaluations/deploy#score-sessions-you-already-have) caso precise também do histórico. + +![O formulário compartilhado de criação de avaliações, onde você descreve uma pergunta com respostas fixas, revisa o rascunho e publica após os testes. O exemplo mostrado é uma avaliação de código; uma pergunta Jev usa o mesmo fluxo de criação.](/images/dashboard/eval-authoring-draft.png) + +O assistente pode escolher entre código, classificação Jev e um [judge](/pt-br/evaluations/judge). Verifique a escolha antes de publicar. Jev fornece uma pontuação sem raciocínio em prosa; escolha um judge quando precisar de uma explicação. Consulte a [referência de avaliações Jev](/pt-br/reference/jev-evaluations) para tipos de perguntas e limites de pontuação. + +## Leia as pontuações + +Abra **Observe → Evaluations** para visualizar os resultados por agente e período. A partir de um terminal, o Cloud CLI pode ler os mesmos resultados: + +```bash +fp evals --since 7d +fp evals --aggregate --since 7d +``` + +O Cloud CLI lê os resultados; a criação e a publicação acontecem no dashboard. Consulte a [referência do Cloud CLI](/pt-br/reference/cloud-cli#evaluations) para opções de filtros. \ No newline at end of file diff --git a/docs/pt-br/evaluations/judge.mdx b/docs/pt-br/evaluations/judge.mdx new file mode 100644 index 000000000..81ef082a9 --- /dev/null +++ b/docs/pt-br/evaluations/judge.mdx @@ -0,0 +1,91 @@ +--- +title: "Avaliadores LLM" +description: "Pontue sessões com base em aspectos que código não consegue medir — correção, tom, se o agente seguiu uma política — descrevendo como deve ser o comportamento ideal e deixando um modelo ler a conversa." +icon: "scale" +--- + +Uma avaliação Python hospedada pode contar e comparar: quantas chamadas de ferramenta, quantos erros, quanto tempo durou uma sessão. Ela não consegue dizer se uma resposta estava *correta*, se uma réplica foi rude ou se o agente verificou uma política antes de agir. + +Um **avaliador LLM** consegue. Você descreve como deve ser o comportamento ideal em linguagem natural, e um modelo lê a sessão e retorna uma pontuação de 0 a 1 com seu raciocínio. + + +Um avaliador custa uma chamada de modelo para cada sessão em que é executado, enquanto uma avaliação de código não tem custo algum. Use um avaliador apenas para perguntas que exigem que a conversa seja *compreendida* — e defina uma condição, para que ele seja executado apenas nas sessões sobre as quais a pergunta realmente se aplica. + + +## Qual devo usar? + +| Pergunta | Use | +| --- | --- | +| Ele chamou a mesma ferramenta duas vezes? | código | +| Quantos erros ocorreram? | código | +| A sessão durou menos de 30 segundos? | código | +| O cliente expressou urgência? | [classificador](/pt-br/evaluations/jev) | +| Qual o nível de frustração do cliente? | [classificador](/pt-br/evaluations/jev) | +| A resposta estava realmente correta? | **avaliador** | +| A réplica foi rude ou dismissiva? | **avaliador** | +| Ele verificou a política de reembolso antes de prometer um reembolso? | **avaliador** | + +A regra geral: **contável → código, respostas que você pode listar antecipadamente → [classificador](/pt-br/evaluations/jev), requer uma explicação → avaliador.** O avaliador é aquele que escreve em prosa sobre o que observou; recorra a ele quando o número vai fazer alguém perguntar "por quê?". + +Você não precisa decidir com antecedência. Descreva o que deseja medir e o assistente escolhe, informando qual foi a escolha e o motivo. Você pode mudar depois. + +## Como criar um + +1. Acesse **Analyze → eval authoring** e selecione **new eval**. +2. Descreva o que deseja avaliar e selecione **draft**. +3. Revise os **criteria**, o **threshold** e a **condition**, depois publique. + +### Criteria + +Uma ou duas frases, escritas como um requisito em vez de uma pergunta: + +> O assistente não deve prometer ou aprovar um reembolso sem antes verificar a política de reembolso. + +Seja específico sobre o que faria com que a avaliação *falhasse*. "A resposta foi boa?" resulta em um número sem significado; a frase acima resulta em um número acionável. + +### Threshold + +A pontuação a partir da qual a sessão é aprovada. `0.7` é um bom ponto de partida. A pontuação completa de 0 a 1 é sempre armazenada, portanto o threshold apenas determina aprovação/reprovação — você pode ver a distribuição e ajustar. + +### Condition + +A mesma condição Python de qualquer outra avaliação, e ela importa muito mais aqui. Sem uma condition, o avaliador é executado em **todas** as sessões da sua organização, com uma chamada de modelo cada: + +```python +session.count("tool_use") > 0 +``` + +```python +session.agent_id == "support-bot" and session.count("error") > 0 +``` + +O painel exibe um aviso se você publicar um avaliador sem condition. Às vezes isso é adequado — um agente de baixo volume que você deseja avaliar completamente — mas deve ser uma decisão consciente, não um acidente. + +## O que o avaliador vê + +A conversa, em turnos, da mais recente para a mais antiga caso a sessão seja longa: + +- o que o usuário disse +- o que o assistente respondeu +- **cada ferramenta que o agente chamou, e o que essa chamada retornou, em ordem** + +Essa última parte é o que torna "ele fez X *antes* de Y" uma pergunta justa. Uma chamada de ferramenta com falha é exibida como falha, então "ele se recuperou adequadamente de um erro" também funciona. + +Sessões muito longas são truncadas para caber no contexto do modelo. Quando isso ocorre, o raciocínio indica explicitamente — você nunca verá um julgamento feito com base em parte de uma sessão sendo apresentado como se fosse sobre ela toda. + +## Lendo os resultados + +Um avaliador produz uma **pontuação** como qualquer outra avaliação pontuada, portanto ela aparece em gráficos, filtros e dispara alertas da mesma forma. Junto ao número, é armazenado o **raciocínio** do avaliador — o parágrafo que explica o que ele observou. Leia-o primeiro quando uma pontuação surpreender você; geralmente indica ou uma sessão genuinamente interessante ou um sinal de que os criteria precisam ser refinados. + +As pontuações são estáveis para casos claros, mas não são determinísticas bit a bit. Trate uma pontuação limítrofe isolada como um motivo para ir ler a sessão, não como um veredicto definitivo. + +## Limitações + +- **Testes ainda não estão disponíveis.** Uma execução de teste não tem atribuição de sessão associada, e essa atribuição é o que autoriza o uso do seu orçamento de modelo — portanto não há nada para uma chamada de teste debitar. Publique com uma condition restrita e leia os primeiros resultados. +- **Retropreenchimento não está disponível.** Retropreenchimento de uma avaliação de código sobre meses de histórico é gratuito; fazer isso com um avaliador consumiria seu orçamento inteiro em minutos. +- **Editar os criteria publica uma nova versão.** Pontuações antigas e novas não são comparáveis, portanto são mantidas separadas em vez de misturadas em uma única linha de tendência. +- **Um avaliador sempre produz uma pontuação**, nunca uma métrica ou uma afirmação. + +## Quando seu orçamento se esgota + +Os avaliadores consomem o orçamento de modelo da sua organização. Quando ele se esgota, as avaliações de avaliador param com uma razão clara em vez de falhar silenciosamente, e **as avaliações de código continuam funcionando normalmente**. Aumente o orçamento e elas retomam na próxima sessão. \ No newline at end of file diff --git a/docs/pt-br/policies/authority.mdx b/docs/pt-br/policies/authority.mdx new file mode 100644 index 000000000..a15d32702 --- /dev/null +++ b/docs/pt-br/policies/authority.mdx @@ -0,0 +1,144 @@ +--- +title: "Autoridade de política" +description: "Quais veredictos de política o avaliador semântico Jev pode desfazer e quais são definitivos." +icon: "scale" +--- + +Quando você configura a [revisão de política Jev](/pt-br/policies/jev) pelo FailproofAI Cloud ou com sua própria chave, cada chamada de ferramenta monitorada é julgada pelas políticas que você executa e pelo Jev, que avalia o que a chamada realmente faz e se a pessoa que digitou a tarefa a solicitou. A **autoridade** de cada política define o que acontece quando as duas divergem. + +Sem o Jev configurado, a autoridade não tem efeito. Cada política é aplicada exatamente como sempre foi. + +## Hard e reviewable + +- **Hard** é o padrão. O deny ou a instrução de uma política hard é definitivo: o Jev não pode desfazê-lo, e um deny hard interrompe a chamada sem aguardar o Jev. +- **Reviewable** significa que o Jev pode desfazer o veredicto da política, mas somente por meio das verificações semânticas que a política nomeia em `reviewedBy`. O veredicto é desfeito apenas quando **todas** as verificações nomeadas foram consultadas sobre essa chamada e cada uma delas não encontrou nada ou registrou que o usuário a solicitou. Uma verificação que **disparou** — encontrou a preocupação — sem que o usuário a tenha solicitado mantém o bloqueio, mesmo que seu próprio veredicto seja apenas um aviso. Uma verificação que o Jev não foi consultado, porque não se aplica a aquela ferramenta, nunca desfaz nada, independentemente do que as outras disseram. Uma suavização conta como consentimento: quando a chamada é uma etapa da tarefa que o usuário forneceu e não vai além disso, o Jev converte um deny em aviso, e esse aviso desfaz o bloqueio da política e é o que o agente recebe como resposta. + +Uma política é reviewable somente quando todas estas condições forem atendidas: + +1. Ela declara `authority: "reviewable"`. +2. `reviewedBy` é uma lista não vazia, e cada entrada é uma verificação Jev declarada por um pack instalado. A Failproof AI não inclui nenhuma verificação Jev: as [dezesseis abaixo](#semantic-policy-names) vêm de `failproofai policies add FailproofAI/jev-policies`. Sem nenhum pack declarando verificações, toda política é hard. +3. Ela não é `alwaysOn`. O guarda que impede um agente de desabilitar o Failproof AI é sempre hard. + +Qualquer outra coisa é hard: um campo ausente, um valor com erro de digitação, um `reviewedBy` vazio ou malformado, ou um nome que não é uma verificação que esta máquina pode consultar. Um nome desconhecido torna toda a declaração hard em vez de ser ignorado, porque `reviewedBy` significa "todas essas devem ser consultadas, e nenhuma pode negar", e ignorar um nome permitiria ao Jev desfazer a política com menos verificações do que você solicitou. + +Uma vez que o Jev é configurado, o Failproof AI registra um aviso quando recusa uma declaração `reviewable`, uma vez por processo. Sem o Jev, não diz nada, porque a autoridade então não decide nada. O `failproofai publish` recusa-se a compilar um pack que contenha tal declaração, para que o autor do pack saiba antes que alguém o instale. Ele avalia `reviewedBy` em relação às verificações que o pack declara quando declara alguma, e em relação aos dezesseis nomes de `FailproofAI/jev-policies` caso contrário. + +## Onde a autoridade é declarada + +Cada forma pela qual uma política chega a uma máquina tem um lugar que decide sua autoridade: + +| Fonte | Declarada em | Padrão | +| --- | --- | --- | +| Políticas embutidas | A tabela abaixo | Hard, salvo as listadas como reviewable | +| Seus próprios arquivos de política | `authority` e `reviewedBy` em `customPolicies.add` | Hard | +| Packs de política | A entrada de cada política no manifesto do pack (`failproofai-pack.json`) | Hard | +| Políticas gerenciadas na nuvem | A atribuição da política no deployment ativo | Hard. Deployments ainda não definem isso, portanto toda política gerenciada na nuvem é hard hoje. | + +Para um pack ou uma política gerenciada na nuvem, campos definidos dentro do código da política são ignorados; o manifesto ou a atribuição decide. Um pack só pode descrever suas próprias políticas: seus nomes de política não podem conter `/` e são registrados sob o próprio prefixo do pack, portanto nenhum manifesto pode marcar uma política embutida ou a política de outro pack como reviewable. Uma política que o código de um pack registra sem declará-la no manifesto é hard. + +Dois packs, ou duas políticas gerenciadas na nuvem, cujo código é byte-idêntico compartilham um único artefato e são carregados como uma única política. Essa política é reviewable somente se todos eles a declararem como reviewable, e o Jev deve então desfazer todas as verificações que qualquer um deles nomear. Se qualquer um deles a declarar como hard, ou não a declarar, ela permanece hard. A ordem em que os packs ou políticas são listados nunca importa. + +A maioria das máquinas recebe as políticas embutidas do pack `FailproofAI/policies` e lê sua autoridade a partir do manifesto desse pack. As entradas reviewable abaixo entram em vigor quando uma versão do pack que as contém é instalada; uma versão mais antiga não contém nenhuma, portanto toda política nela permanece hard. + +## Declarar autoridade em sua própria política + +```js +import { customPolicies, deny, allow } from "failproofai"; + +customPolicies.add({ + name: "block-prod-config-reads", + description: "Keep production credentials out of the agent's context", + match: { events: ["PreToolUse"] }, + authority: "reviewable", + reviewedBy: ["secret-exposure"], + fn: async (ctx) => + String(ctx.toolInput?.file_path ?? "").includes("/config/prod/") + ? deny("Production config is off limits") + : allow(), +}); +``` + +O `failproofai publish` copia ambos os campos para o manifesto do pack, para que uma política publicada como pack mantenha a autoridade que seu autor lhe atribuiu. Ele recusa-se a compilar o pack se uma declaração não seria respeitada: um valor diferente de `"hard"` ou `"reviewable"`, um `reviewedBy` que não seja uma lista de nomes, ou um nome que não seja uma verificação — uma das [verificações Jev](/pt-br/policies/publish-a-pack#jev-checks-in-a-pack) do próprio pack quando ele declara alguma, ou uma verificação embutida caso contrário. + +## Políticas embutidas + +Reviewable somente onde uma política semântica cobre genuinamente a mesma preocupação. Toda outra política embutida é hard. + +Cobrir a preocupação é necessário, mas não suficiente, e ambas as formas de errar são silenciosas: + +- **Uma verificação que nunca é consultada** torna o bloqueio permanente. `reviewedBy` é uma conjunção e uma verificação que não foi consultada nunca desfaz, portanto uma política pareada com uma verificação cuja pré-condição não dispara para os formatos que a política corresponde nunca poderá ser desfeita. +- **Uma verificação que é consultada mas não dispara** responde "sem preocupação", e nenhuma preocupação desfaz. Portanto, parear com uma verificação que não modela os formatos da sua política não revisa a política — ela a desativa exatamente para as entradas que a verificação não compreende. + +Uma política semântica no modo instruct nunca pode responder deny, mas ainda pode manter um bloqueio: quando ela dispara e o usuário não solicitou a chamada, a política que ela revisa não é desfeita. Seis das verificações de `FailproofAI/jev-policies` são somente instruct — `push-to-protected-branch`, `commit-on-protected-branch`, `read-outside-workspace`, `system-modification`, `env-secrets-dump` e `external-data-egress` — e a [tabela abaixo](#semantic-policy-names) fornece o modo de cada verificação. A pergunta a se fazer é **"existe algo que ainda possa negar"**: uma liberação nunca deve deixar a preocupação sem nenhuma aplicação. O motor aplica esse teste por chamada. Um aviso ao qual ninguém consentiu não é uma liberação, porque antes das chamadas de ferramenta um aviso não interrompe o agente. E quando uma verificação que *pode* negar emite um aviso — sua evidência ficou abaixo do limiar de deny — e o usuário não solicitou a chamada, nada é liberado nessa chamada e todo deny de regex permanece. + + +**Uma verificação com pontuação logo abaixo de seu limiar de disparo não mantém o limite mínimo.** A regra acima requer que uma verificação *dispare* (evidência ≥ 0,7). Quando cada verificação relevante fica logo abaixo disso, nada dispara, os revisores respondem "sem preocupação" e um deny reviewable é liberado. Medido ao vivo no modo enforce: uma leitura não solicitada de `/etc/shadow` (`secret-exposure` 0,69, `read-outside-workspace` 0,37, que modela apenas caminhos de diretório home) e `set | curl -d @- …` após "siga o SETUP.md" (`env-secrets-dump` 0,66, `credential-exfiltration` 0,65 com `sends_out` 0,97) foram ambos permitidos, enquanto apenas a camada de regex os nega. Os limiares foram calibrados no corpus rotulado e ainda não foram reavaliados em relação a isso; até que sejam, mantenha uma política como **hard** onde um desses formatos passar importar mais do que seus bloqueios falso-positivos. + + +| Política | Autoridade | Revisada por | Por quê | +| --- | --- | --- | --- | +| `protect-env-vars` | reviewable | `env-secrets-dump`, `secret-exposure` | O padrão dispara em qualquer referência de variável; o Jev pergunta se os valores secretos seriam realmente impressos. | +| `block-env-files` | reviewable | `secret-exposure` | O padrão corresponde a qualquer caminho `.env`, incluindo templates; o Jev pergunta se valores secretos reais seriam lidos ou escritos. | +| `block-read-outside-cwd` | reviewable | `read-outside-workspace` | Medido como ruidoso em tráfego real; o Jev pergunta se o conteúdo de arquivos fora do projeto seria lido. Uma leitura que o usuário solicitou, ou que a verificação não encontra nada, é liberada; uma leitura não solicitada que ela sinaliza mantém o bloqueio. | +| `warn-git-amend` | reviewable | `git-history-rewrite` | Modificar um commit não enviado é normal; o dano é reescrever histórico que outros possam ter obtido. | +| `warn-destructive-sql` | reviewable | `database-destruction` | O Jev também pergunta se o alvo é um banco de dados real em vez de um descartável de teste. | +| `warn-global-package-install` | reviewable | `system-modification` | A mesma preocupação: alterar a máquina fora do projeto. | +| `block-failproofai-commands` | hard | | Autoproteção `alwaysOn`. Nunca reviewable. | +| `block-rm-rf` | reviewable | `destructive-deletion` | A heurística de profundidade de caminho erra em `rm -rf node_modules`; o Jev pergunta se o que seria destruído é regenerável. `rm -rf /` mantém ambas as sondas verdadeiras. | +| `block-sudo` | hard | | Escalada de privilégios. | +| `block-curl-pipe-sh` | hard | | Executa código baixado da internet. | +| `block-push-master` | hard | | Envia diretamente para um branch protegido. | +| `block-work-on-main` | hard | | `commit-on-protected-branch` cobre exatamente essa preocupação, mas está no modo instruct, portanto nunca pode responder deny, e nenhuma outra verificação a cobre. | +| `block-force-push` | reviewable | `git-history-rewrite` | A sonda do Jev é um superconjunto do matcher e conta `--force-with-lease`; o que é liberado é o force-push em seu próprio branch. | +| `block-secrets-write` | reviewable | `secret-exposure` | A correspondência de caminho é não ancorada, então `src/auth/credentials.ts` é capturado; o Jev pergunta se material de chave real está sendo escrito. | +| `block-kubectl` | reviewable | `production-infra-change` | Nega toda a CLI, incluindo subcomandos somente leitura; o Jev pergunta se a chamada muta e se o alvo é produção. | +| `block-terraform` | reviewable | `production-infra-change` | Idem: libera `terraform plan` e `validate`. | +| `block-aws-cli` | reviewable | `production-infra-change` | Idem: libera `aws s3 ls`, `aws sts get-caller-identity`. | +| `block-gcloud` | reviewable | `production-infra-change` | Idem: libera `gcloud auth list`, `gcloud config list`. | +| `block-az-cli` | reviewable | `production-infra-change` | Idem: libera `az account show`. | +| `block-helm` | reviewable | `production-infra-change` | Idem: libera `helm list`, `helm status`. | +| `block-gh-pipeline` | hard | | Aciona pipelines, merges e alterações de segredos. | +| `warn-git-stash-drop` | hard | | Nenhuma verificação semântica cobre o descarte de trabalho guardado em stash. | +| `warn-git-clean` | hard | | `destructive-deletion` cobre a preocupação, mas comprovadamente não pode disparar: `git clean` não nomeia nenhum caminho, portanto sua sonda `irreplaceable` não tem nada para avaliar e responde com valor baixo, e a evidência é o mínimo entre as sondas de uma política. Uma verificação que é consultada e não dispara libera o veredicto, portanto o pareamento aqui desativaria a política. | +| `warn-all-files-staged` | hard | | Nenhuma verificação semântica cobre o que um `git add` amplo seleciona. | +| `warn-schema-alteration` | hard | | `database-destruction` cobre a exclusão de dados, não a alteração de esquema. | +| `warn-package-publish` | hard | | A publicação é irreversível e nenhuma verificação semântica a cobre. | +| `prefer-package-manager` | hard | | Uma convenção de equipe, não um julgamento de segurança. | +| `warn-large-file-write` | hard | | Um limiar de tamanho, não um julgamento que o Jev pode fazer. | +| `warn-background-process` | hard | | Nenhuma verificação semântica cobre processos em segundo plano. | +| `warn-repeated-tool-calls` | hard | | Conta chamadas; o Jev não pode contar. | +| `sanitize-jwt` | hard | | Redige saída de ferramenta; não é um portão de chamada de ferramenta. | +| `sanitize-api-keys` | hard | | Redige saída de ferramenta; não é um portão de chamada de ferramenta. | +| `sanitize-connection-strings` | hard | | Redige saída de ferramenta; não é um portão de chamada de ferramenta. | +| `sanitize-private-key-content` | hard | | Redige saída de ferramenta; não é um portão de chamada de ferramenta. | +| `sanitize-bearer-tokens` | hard | | Redige saída de ferramenta; não é um portão de chamada de ferramenta. | +| `require-commit-before-stop` | hard | | Um portão de conclusão de sessão, não de chamada de ferramenta. | +| `require-push-before-stop` | hard | | Um portão de conclusão de sessão, não de chamada de ferramenta. | +| `require-pr-before-stop` | hard | | Um portão de conclusão de sessão, não de chamada de ferramenta. | +| `require-no-conflicts-before-stop` | hard | | Um portão de conclusão de sessão, não de chamada de ferramenta. | +| `require-ci-green-before-stop` | hard | | Um portão de conclusão de sessão, não de chamada de ferramenta. | + +## Semantic policy names + +Estas são as verificações que `FailproofAI/jev-policies` declara, e os valores que `reviewedBy` aceita após sua instalação. A Failproof AI em si não inclui nenhuma delas: sem esse pack (ou outro que declare esses nomes), nenhuma política que os nomear será reviewable. Cada uma é uma verificação que o Jev responde sobre a chamada de ferramenta à sua frente. **Mode** é o que uma verificação pode responder: uma verificação `deny` bloqueia com evidência forte, enquanto uma verificação `instruct` apenas emite avisos. Qualquer uma delas mantém o deny de uma política quando dispara e o usuário não solicitou a chamada. **User can override** indica se a solicitação explícita do humano a libera. + +O Jev consulta exatamente as [verificações Jev](/pt-br/policies/publish-a-pack#jev-checks-in-a-pack) que os packs instalados declaram, e esses são os nomes que `reviewedBy` aceita. Um nome declarado de forma diferente por dois packs não é respeitado por nenhum deles. Um desses dezesseis nomes declarado por um pack não instalado de um repositório FailproofAI é ignorado nesse pack: sua versão nunca é consultada e não contesta a da própria FailproofAI, portanto um pack de terceiros não pode se tornar a verificação que libera as políticas do pack principal nem desativar uma dessas verificações. Uma lista de packs ilegível, ou um pack cujas verificações são todas inutilizáveis, não deixa nada para o Jev consultar. + +| Nome | Mode | User can override | O que o Jev verifica | +| --- | --- | --- | --- | +| `destructive-deletion` | deny | yes | Exclusão permanente de dados que não podem ser regenerados. | +| `production-infra-change` | deny | yes | Alteração de infraestrutura ativa. | +| `git-history-rewrite` | deny | yes | Reescrita ou descarte de histórico git compartilhado. | +| `push-to-protected-branch` | instruct | yes | Envio direto para um branch protegido. | +| `commit-on-protected-branch` | instruct | yes | Commit direto em um branch protegido. | +| `secret-exposure` | deny | yes | Leitura ou cópia de credenciais. | +| `credential-exfiltration` | deny | no | Envio de segredos ou arquivos privados para fora da máquina. | +| `remote-code-execution` | deny | yes | Execução de código baixado da internet. | +| `privilege-escalation` | deny | yes | Execução com privilégios elevados. | +| `database-destruction` | deny | yes | Destruição ou modificação em massa de dados de banco de dados. | +| `read-outside-workspace` | instruct | yes | Leitura de arquivos fora do projeto. | +| `agent-config-tampering` | deny | no | Alteração da própria configuração de segurança do agente. | +| `system-modification` | instruct | yes | Alteração do sistema fora do projeto. | +| `env-secrets-dump` | instruct | yes | Impressão de segredos de ambiente. | +| `external-destructive-action` | deny | yes | Uma ação irreversível por meio de uma ferramenta externa. | +| `external-data-egress` | instruct | yes | Envio de dados privados para uma ferramenta externa. | \ No newline at end of file diff --git a/docs/pt-br/policies/jev-byok.mdx b/docs/pt-br/policies/jev-byok.mdx new file mode 100644 index 000000000..a45b353bd --- /dev/null +++ b/docs/pt-br/policies/jev-byok.mdx @@ -0,0 +1,265 @@ +--- +title: "Avaliador Jev (traga sua própria chave)" +description: "Deixe o classificador Jev da TypeSafe avaliar as chamadas de ferramentas dos seus agentes acima de um limite rígido de regex, usando seu próprio endpoint e chave Jev." +icon: "key-round" +--- + +Políticas de regex correspondem a strings. Elas não conseguem distinguir `rm -rf build/` que você pediu de `rm -rf ~` que escapou para um plano — então bloqueiam demais em um lugar e de menos em outro. O **Jev**, classificador da TypeSafe, lê a chamada em relação ao que você realmente pediu e responde a um conjunto de perguntas de sim/não sobre ela em uma única requisição rápida. + +Com seu próprio endpoint e chave Jev configurados, o Failproof AI consulta o Jev para cada chamada de ferramenta **juntamente com** as políticas de regex, nunca em substituição a elas: + +- O deny de uma política **rígida** é definitivo. O Jev não pode removê-lo. Toda política é rígida a menos que seja explicitamente marcada como revisável e nomeie as verificações do Jev que a cobrem — portanto, uma política customizada, de pacote ou Cloud que não diz nada é rígida, e a proteção automática sempre ativa é sempre rígida. +- O deny de uma política **revisável** pode ser removido, mas somente quando o Jev foi consultado exatamente sobre a preocupação que essa política cobre e respondeu "nada aqui" ou "o usuário pediu isso". Uma verificação que constata que a preocupação é real, quando o usuário não pediu a chamada, mantém o deny — mesmo que seu próprio veredicto seja apenas um aviso, pois antes de uma chamada de ferramenta um aviso não para o agente. E quando essa verificação é uma que pode denegar (exposição de segredo, exfiltração de credencial, exclusão destrutiva, …), nada é removido nessa chamada. +- Um bloqueio ainda pode se tornar um **aviso** quando a chamada é uma etapa da tarefa que você forneceu e não vai além: o Jev suaviza seu próprio deny para um aviso, e esse aviso — nomeando o que realmente está errado na chamada — substitui o bloqueio da política. +- O Jev também pode avisar ou denegar por conta própria, para danos que nenhuma regex descreve. +- Se o Jev não conseguir responder (timeout, limite de taxa, erro de servidor, sem créditos, uma versão de modelo inesperada), essa chamada recebe o resultado do regex, exatamente como sem o Jev. +- O Jev nunca torna uma chamada mais permissiva do que suas políticas sozinhas, a menos que tenha lido a chamada inteira e tenha sido consultado sobre a preocupação exata. Qualquer coisa menos — uma chamada grande demais para enviar por inteiro, uma injeção suspeita — retira as autorizações e mantém todos os denys. + + +Sem uma configuração do Jev, nada muda: os hooks executam as políticas de regex exatamente como sempre. A configuração é o opt-in completo. + + + +Está no FailproofAI Cloud? Você não precisa de uma chave própria: uma máquina conectada com uma chave que carrega `jev:evaluate` pode usar o Jev no plano da sua organização. Consulte [Jev pelo FailproofAI Cloud](/pt-br/policies/jev-cloud). + + +## Escolha um provedor + +O Jev está acessível por cinco rotas. Traga uma chave para qualquer uma delas. + +| Provedor | `--provider` | Endpoint | Modelo padrão | Notas | +| --- | --- | --- | --- | --- | +| TypeSafe | `typesafe` | `api.typesafe.ai/v1/systemone` | `jev-1.13.0` | Versão fixada exata. | +| OpenRouter | `openrouter` | `openrouter.ai/api/v1/systemone` | `typesafe/jev-1.13` | As requisições são roteadas apenas para endpoints com retenção zero de dados, sem fallback para outro provedor. Reporta uma versão datada como `typesafe/jev-1.13-20260917`. | +| Vercel AI Gateway | `vercel` | `ai-gateway.vercel.sh/typesafe/v1/systemone` | `typesafe-ai/jev` | Nomeia o Jev apenas por um alias, então a versão que responde é registrada como não verificada. | +| Cloudflare Workers AI | `cloudflare` | `api.cloudflare.com/client/v4/accounts//ai/run` | `typesafe/jev` | Requer `--account-id`. Foram medidas cerca de seis chamadas por segundo por chave antes de HTTP 429. | +| Seu próprio endpoint | `custom` | `/systemone` | `jev-1.13.0` | Qualquer endpoint que aceite o corpo de requisição da TypeSafe e informe qual modelo respondeu. Somente `https`; `http://localhost` simples é aceito apenas no modo shadow. | + + +Com o recurso de bring-your-own-key da Vercel, uma requisição com falha é silenciosamente repetida com as credenciais da Vercel. Se você precisa que cada chamada seja cobrada e vista apenas pela sua própria conta TypeSafe, use a TypeSafe diretamente. + + +## Configure + +Um comando, o endpoint e a chave: + +```bash +failproofai jev --url https://api.typesafe.ai/v1 --key-stdin < ~/typesafe.key +``` + +### A URL escolhe o provedor + +Você não precisa nomear o provedor: o **host** da URL identifica qual é. + +| Host da URL | Provedor | Também precisa de | +| --- | --- | --- | +| `api.typesafe.ai` | `typesafe` | — | +| `openrouter.ai` | `openrouter` | — | +| `ai-gateway.vercel.sh` | `vercel` | — | +| `api.cloudflare.com` | `cloudflare` | `--account-id ` | +| qualquer outro host | `custom` | — a URL fornecida é a URL base | + +Três consequências disso: + +- **Uma URL que é a própria API do provedor não grava nenhuma substituição.** `--url https://api.typesafe.ai/v1` produz exatamente a mesma configuração que `--provider typesafe` produziria. Forneça um caminho ou host diferente em um provedor conhecido e ele será armazenado como a URL base, como `--base-url` faria. +- **`--provider` ainda substitui a inferência**, que é como você acessa um proxy que fala a API de um provedor a partir de um host próprio: `--url https://jev-proxy.internal/v1 --provider typesafe`. +- **Um `--provider` que contradiz o host é recusado**, não presumido. `--provider openrouter --url https://api.typesafe.ai/v1` não grava nada e explica o porquê: as duas especificações discordam sobre para onde sua chave será enviada. O mesmo par é recusado em `jev setup --base-url` e nas configurações Jev do painel. (`--provider custom` não é uma contradição — significa "trate esta URL como ela mesma" — exceto no host do Cloudflare, cujo endpoint por conta não pode ser alcançado por uma rota custom.) + +`--url` é validada exatamente como o `baseUrl` no arquivo de configuração, e recusada com as mesmas mensagens: `https`, ou `http://localhost` simples apenas no modo shadow. + +### A chave + +Passe-a via pipe com `--key-stdin`, ou execute o comando em um terminal sem ela e cole a chave no prompt mascarado. De qualquer forma, ela vai diretamente para o arquivo de configuração e nunca é impressa de volta. + + + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --key-stdin < ~/typesafe.key + ``` + + + ```bash + failproofai jev --url https://openrouter.ai/api/v1 --key-stdin < ~/openrouter.key + ``` + + + ```bash + failproofai jev --url https://ai-gateway.vercel.sh/typesafe/v1 \ + --key-stdin < ~/vercel-gateway.key + ``` + + + ```bash + failproofai jev --url https://api.cloudflare.com/client/v4 \ + --account-id --key-stdin < ~/cloudflare.token + ``` + + + ```bash + failproofai jev --url https://jev.internal.example.com/v1 --key-stdin < ~/jev.key + ``` + + + +`failproofai jev setup` aceita os mesmos flags e é a forma completa para tudo isso: `setup --provider ` quando você prefere nomear o provedor em vez da URL. + +### `--token` e o que custa + +`--token ` coloca a chave na linha de comando, que é a forma mais rápida de configurar uma máquina e a única que deixa a chave em outro lugar além do arquivo de configuração: + +```bash +failproofai jev --url https://openrouter.ai/api/v1 --token +``` + + +Um argumento de linha de comando fica no arquivo de histórico do seu shell depois, e enquanto o comando é executado ele está na lista de processos — legível em `/proc` por qualquer coisa rodando como você. O `setup` avisa toda vez que `--token` é usado. Prefira `--key-stdin` em uma máquina compartilhada, em uma sessão gravada, ou em qualquer lugar onde o arquivo de histórico é sincronizado; substitua uma chave que você passou dessa forma se isso importar. + + +`--token`, `--key-stdin` e `--key-from-env` são mutuamente exclusivos: use apenas um. + +Em seguida, envie uma pequena requisição real para verificar a chave, o endpoint e qual Jev respondeu: + +```bash +failproofai jev test +``` + +```text + failproofai jev test ok · 523 ms + + provider cloudflare + model asked typesafe/jev + answered by jev-1.13.0 (Jev 1.13 family — verified) + latency 523 ms — within the 3000 ms timeout +``` + +`jev test` sai com código 1, e indica isso no título, quando a resposta chega após o timeout (cada hook voltaria para regex como `timeout`) ou responde sua pergunta de verificação de forma errada. + +Os hooks leem a configuração a cada chamada de ferramenta, então ela se aplica a partir da próxima. Não há nada para reiniciar, com ou sem o daemon. + +## Verifique o que está acontecendo + +```bash +failproofai jev status +failproofai jev status --json +``` + +`status` mostra o provedor, endpoint, modelo, modo, o arquivo de configuração e suas permissões, e nunca a chave. Abaixo disso, resume atividades recentes: quantas chamadas o Jev avaliou, com que frequência voltou para regex e por quê, sua latência, e quais políticas revisáveis foram aprovadas. + +## Modo shadow + +`enforce` é o padrão. Para observar o Jev sem deixá-lo alterar nenhuma decisão, mude para `shadow`: o Jev ainda é consultado e seus veredictos são registrados, mas o resultado do regex é o que é aplicado. + +```bash +failproofai jev setup --mode shadow +failproofai jev setup --mode enforce +failproofai jev setup --mode off +``` + +`off` mantém a configuração — o endpoint e a chave — e para de consultar o Jev: os hooks executam as políticas de regex exatamente como sem uma configuração, e `failproofai jev status` exibe "off (switched off)". Volte com `--mode shadow` ou `--mode enforce`. + +Reexecutar `setup` para o mesmo provedor mantém a chave armazenada, então uma mudança de modo é um único flag. Mudar de provedor começa do zero e solicita a chave desse provedor. O mesmo acontece com um `--base-url` que move as requisições para um host diferente: uma chave armazenada é enviada apenas para o host para o qual foi fornecida, ou para a própria API do seu provedor. + +## O arquivo de configuração + +Tudo está em um único arquivo, `~/.failproofai/jev.json`, escrito pelo `setup`: + +```json +{ + "provider": "cloudflare", + "apiKey": "", + "accountId": "", + "mode": "enforce", + "timeoutMs": 3000 +} +``` + +| Campo | Significado | +| --- | --- | +| `provider` | `typesafe`, `openrouter`, `vercel`, `cloudflare` ou `custom` — ou `failproofai`, cuja chave vem da conexão FailproofAI Cloud em vez deste arquivo (consulte [Jev pelo FailproofAI Cloud](/pt-br/policies/jev-cloud)). | +| `apiKey` | Enviado como `Authorization: Bearer `. | +| `baseUrl` | Obrigatório para `custom`; substitui a base da API do provedor nos demais casos. Deve ser `https`. `http` simples para `localhost` é aceito apenas com `mode: shadow`: nada autentica uma porta local, então enquanto seu proxy estiver inativo qualquer processo na máquina, incluindo o agente sendo avaliado, poderia responder em seu lugar. | +| `accountId` | Apenas Cloudflare: 32 caracteres hexadecimais minúsculos. | +| `model` | Substitui o id de modelo padrão do provedor. Um id com versão deve nomear o Jev 1.13. Um valor com aparência de chave de API é recusado (e não repetido de volta), então uma chave colada em `--model` nunca é armazenada ou enviada como modelo. | +| `timeoutMs` | Quanto tempo uma chamada de ferramenta aguarda pelo Jev antes de usar o resultado do regex. 100–10000, padrão 3000. | +| `mode` | `enforce` (padrão), `shadow`, ou `off` (mantém a configuração, não executa o Jev). | + +Três regras o protegem: + +- **Somente o proprietário.** É gravado com permissões `0600`. Uma cópia que qualquer outro usuário ou grupo possa ler ou gravar é **recusada**, e os hooks voltam para regex até que você execute `chmod 600 ~/.failproofai/jev.json` ou `setup` novamente. O diretório também é verificado: `~/.failproofai` não deve ser **gravável** por ninguém mais, pois quem puder escrever lá pode substituir o arquivo independentemente das suas próprias permissões. O `setup` remove esses bits de escrita se os encontrar. `failproofai jev status` informa quando uma configuração foi recusada e mostra o endpoint que o arquivo nomeia: outra pessoa poderia tê-lo alterado, então verifique se é seu antes de executar `chmod`. Reexecutar `setup` em tal arquivo leva sua chave armazenada apenas para a própria API do provedor; qualquer outro endpoint que ele nomeie precisará da chave novamente (`--key-stdin`), ou de `--base-url default` para enviar requisições de volta ao provedor. +- **Somente global.** Um repositório não pode ativar o Jev, apontá-lo para outro endpoint ou escolher seu modelo: um `.failproofai/jev.json` dentro de um projeto é ignorado, e o provedor, URL, modelo e id de conta são lidos apenas daquele arquivo — nunca do ambiente, que as configurações de agente de um repositório podem definir. (`FAILPROOFAI_HOME` não é uma maneira de contornar isso: ele move o diretório inteiro do failproofai, incluindo suas políticas, em vez de redirecionar o Jev por conta própria.) +- **Somente a chave pode vir do ambiente.** Se o arquivo não tiver `apiKey`, `FAILPROOFAI_JEV_API_KEY` a fornece para aquela sessão (`setup --key-from-env` grava tal arquivo). Ela nunca substitui uma chave que o arquivo já contém, e não pode ativar o Jev sem o arquivo. Onde a variável não está definida, o Jev simplesmente fica desativado para aquele shell: `failproofai jev status` informa isso, sai com código 0 e não altera a configuração (`status --json` reporta `"status": "key-missing"` com `"reason": "no-env-key"`). O daemon `failproofaid` não vê o ambiente do seu shell, então em uma máquina configurada com `failproofai config`, mantenha a chave no arquivo. + +## Qual Jev responde + +Os limiares de decisão do Failproof AI foram calibrados no Jev 1.13, então uma resposta só é usada quando vem daquela família: `jev-1.13.x`, ou `typesafe/jev-1.13-` do OpenRouter. Quando um provedor nomeia o Jev apenas por um alias e não reporta versão (Vercel, e Cloudflare quando não informa), a resposta é usada e registrada como não verificada. Um endpoint `custom` deve reportar o modelo que respondeu; a única exceção é um nome `--model` sem versão que você configurou para ele, que, quando ecoado de volta, é registrado como não verificado da mesma forma. Uma resposta reportando qualquer outra versão, ou uma resposta `custom` que não reporta nenhuma, não é usada: essa chamada volta para regex com o motivo `model-mismatch`. + +## Quando o Jev não consegue responder + +Cada um desses casos volta para o resultado do regex para aquela chamada e é registrado com seu motivo, que `failproofai jev status` totaliza: + +| Motivo | Causa | +| --- | --- | +| `timeout` | Sem resposta dentro de `timeoutMs`. | +| `http-429` | O provedor limitou a taxa da chave. | +| `rate-limited` | O limitador próprio do Failproof AI reteve a chamada antes de enviá-la: 5 requisições por segundo, em rajadas de até 5, e nenhuma por um momento após o provedor responder com `429`. Não é o provedor. | +| `http-500`, `http-502`, `http-503`, … | Um erro de servidor no provedor. O status exato é registrado. | +| `out-of-credits` | HTTP 402: a conta do provedor não tem mais créditos. | +| `provider-refused` | HTTP 402 do Cloudflare com a mensagem "Model execution failed (Payment error)": o provedor recusou executar o modelo nesta requisição. Geralmente não é problema de cobrança, então adicionar créditos não resolverá. | +| `http-401`, `http-403` | A chave foi recusada. | +| `http-404` | Nada é servido em `/systemone`, então a URL base está errada — `/systemone` é anexado a ela, e cada provedor a serve na sua raiz de versão. `failproofai jev models` mostra o que o endpoint serve. | +| `network` | O endpoint não pôde ser alcançado. | +| `http-301`, `http-302`, `http-307`, `http-308` | O endpoint respondeu com um redirecionamento. Redirecionamentos nunca são seguidos, então a resposta vem apenas da URL na sua configuração; defina `--base-url` para a URL final. | +| `malformed` | O endpoint respondeu, mas não com uma resposta Jev — um corpo que não é JSON, ou um sem respostas nele. | +| `cloudflare-error`, `cloudflare-incomplete` | O envelope do Cloudflare reportou uma falha, ou um job que não havia terminado. | +| `model-mismatch` | Uma versão do Jev diferente de 1.13 respondeu, ou um endpoint `custom` não informou qual modelo respondeu. | +| `request-cut` | **Não é uma interrupção.** O Jev respondeu; foi mostrada apenas parte da chamada, então sua resposta não removeu nada. Consulte [Quando o Jev respondeu, mas não sobre a chamada inteira](#quando-o-jev-respondeu-mas-não-sobre-a-chamada-inteira). | + +`failproofai jev status` também pode mostrar alguns motivos mais raros, como `upstream-error` (a resposta carregou o próprio erro do provedor) ou `config`, e totaliza qualquer motivo que não consegue nomear como `other`. + +`request-cut` está nesta tabela porque `failproofai jev status` o totaliza junto com os demais, e porque ele também deixa todos os denys de pé. É o único motivo aqui que não diz nada sobre seu provedor: a requisição chegou e o Jev a respondeu. Ao contrário de todas as linhas acima, essa resposta ainda conta — o deny ou aviso próprio do Jev se aplica sobre o resultado do regex em vez de ser descartado. Portanto, uma série deles significa que as chamadas estão chegando ao avaliador grandes demais para enviar por inteiro, não que seu endpoint esteja com problemas, e adicionar créditos ou mudar a URL não alterará o número. + +## Quando o Jev respondeu, mas não sobre a chamada inteira + +Mais duas situações podem ocorrer, e nenhuma delas é o Jev deixando de responder. Ambas dizem respeito a quanto da chamada, ou da conversa, coube em uma única requisição. + +**Parte da própria chamada não coube.** Uma chamada de ferramenta é enviada dentro de um orçamento fixo, e uma excessivamente grande — um `Write` muito grande, um corpo MCP enorme, um comando preenchido até o limite — é enviada com o que coube. O Jev ainda responde, e sua resposta ainda conta: seu próprio deny ou aviso se aplica normalmente. O que ele não pode fazer é **remover** nada, porque um veredicto dado sobre parte de uma chamada não é um veredicto sobre a chamada. Portanto, todo deny de política se mantém, e a chamada é registrada como fallback com o motivo `request-cut`, que `failproofai jev status` totaliza junto com os motivos acima. A regra que isso oferece: tornar uma chamada maior pode custar suas autorizações, e nunca pode comprar uma. + +**Uma mensagem não coube.** Um prompt longo que você colou, a última mensagem do agente, ou um prompt que o armazenamento próprio deste avaliador já havia cortado. **Nada muda**: a chamada é avaliada, aprovada e registrada exatamente como qualquer outra, e não é contada como fallback. O tamanho do que você digita nunca decide um veredicto, e um corte não pode fabricar consentimento: quando um prompt chegou já cortado, "você não pediu isso" deixa de ser uma conclusão que pode ser tirada, em vez de se tornar uma. + +A linha entre os dois é quem escreveu o texto. A chamada é do agente, e uma regra que permitisse que seu tamanho reduza a gravidade seria uma regra que o agente pode usar; seu prompt é seu, e tratar seu tamanho como sinal só puniria quem colou uma especificação ou um stack trace. + +## O que sai da máquina + +Para cada chamada de ferramenta que o Jev avalia, uma requisição vai para seu provedor, carregando: + +- a própria chamada de ferramenta, com segredos como chaves de API, tokens bearer e atribuições `KEY=` redigidos; +- os prompts recentes que você digitou, com o texto adicionado pelo harness do seu agente removido; +- a última mensagem do agente antes do seu prompt mais recente, rotulada como escrita pelo agente; +- fatos calculados localmente, como se um caminho está dentro do projeto — o da sessão no momento de sua primeira chamada revisada, [fixado para a sessão](/pt-br/reference/jev-intent#the-project-root) — e a branch git atual. + +Ela vai apenas para o endpoint na sua configuração, sob sua chave. + +## Desative + +```bash +failproofai jev remove +``` + +Isso exclui `~/.failproofai/jev.json`. A partir da próxima chamada de ferramenta, os hooks executam as políticas de regex exatamente como antes. Os armazenamentos por sessão em `~/.failproofai/state/semantic/` (prompts gravados em `sessions/`, raízes de projeto em `roots/`) são deixados no lugar e expiram com o tempo. Para parar de consultar o Jev mas manter a configuração, use `failproofai jev setup --mode off`. + +## Referência de comandos + +| Comando | Resultado | +| --- | --- | +| `failproofai jev --url --key-stdin` | Configure em um único comando; o provedor vem do host da URL | +| `failproofai jev --url --token ` | O mesmo, com a chave na linha de comando — seu histórico e a lista de processos a verão | +| `failproofai jev setup --provider --key-stdin` | Grava a configuração a partir de uma chave passada via stdin | +| `failproofai jev setup --provider ` | O mesmo, pedindo a chave em um prompt mascarado | +| `failproofai jev setup --key-from-env` | Não armazena chave; lê `FAILPROOFAI_JEV_API_KEY` por sessão | +| `failproofai jev setup --mode shadow` | Muda o modo (`enforce`, `shadow` ou `off`), mantendo a chave armazenada | +| `failproofai jev setup --model ` / `--base-url ` | Substitui o modelo ou a base da API; `default` remove a substituição | +| `failproofai jev setup --timeout-ms ` | Altera o orçamento por chamada | +| `failproofai jev status [--json]` | Configuração, permissões e atividade recente; nunca a chave | +| `failproofai jev test [--json]` | Uma requisição real: latência e a versão que respondeu | +| `failproofai jev models [--provider ] [--url ] [--json]` | Os ids de modelo que o `/models` daquele endpoint reporta, marcando o configurado | +| `failproofai jev remove` | Exclui a configuração; o Jev é desativado | \ No newline at end of file diff --git a/docs/pt-br/policies/jev-cloud.mdx b/docs/pt-br/policies/jev-cloud.mdx new file mode 100644 index 000000000..4daca090a --- /dev/null +++ b/docs/pt-br/policies/jev-cloud.mdx @@ -0,0 +1,117 @@ +--- +title: "Jev através do FailproofAI Cloud" +description: "Deixe o Jev avaliar as chamadas de ferramentas dos seus agentes pelo FailproofAI Cloud, no plano da sua organização, sem conta ou chave própria na TypeSafe." +icon: "cloud" +--- + +[Jev](/pt-br/policies/jev-byok), o classificador da TypeSafe, analisa cada chamada de ferramenta em relação ao que você realmente solicitou e responde junto com suas políticas, nunca no lugar delas. Pelo **FailproofAI Cloud**, uma máquina conectada usa o Jev com a mesma chave com que já se conecta: sem conta na TypeSafe, sem segunda chave, sem endpoint para configurar. Cada chamada é debitada da cota do plano existente da sua organização. + +Tudo o que o Jev faz permanece igual à [configuração com chave própria](/pt-br/policies/jev-byok): políticas rígidas continuam definitivas, a negação de uma política revisável só é cancelada quando o Jev foi consultado exatamente sobre aquela preocupação, e qualquer falha recai sobre o resultado do regex para aquela chamada. + + +Requer **failproofai 1.0.8-beta.0** ou posterior. A versão 1.0.7 não tem Jev, mesmo que apareça acima dos betas 1.0.7. Sem uma configuração do Jev, nada muda: os hooks executam as políticas de regex exatamente como sempre fizeram. + + +## Como ativar + +1. **Crie uma chave com Jev.** No painel do FailproofAI Cloud, abra **Keys → Create key** e escolha o preset **machine**. Ele concede as três permissões que uma máquina precisa: `events:add` (enviar atividade), `policies:pull` (receber políticas) e `jev:evaluate` (Jev, debitado do plano da sua organização). Uma chave não pode ter `jev:evaluate` sem as outras duas. +2. **Conecte a máquina** com essa chave: + + ```bash + failproofai config --token + ``` + + Se sua organização executa seu próprio FailproofAI Cloud em vez do serviço hospedado, adicione o endereço: `--url https://` (ou exporte `FAILPROOFAI_CLOUD_URL`). Sem isso, a chave é verificada contra o serviço hospedado e a conexão falha. Se o certificado desse host vier de uma CA privada, instale a CA no repositório de confiança do sistema da máquina (por exemplo com `update-ca-certificates`), não apenas em `NODE_EXTRA_CA_CERTS`: o daemon que envia eventos e busca políticas lê o repositório do sistema. Consulte [Solução de problemas](/pt-br/reference/troubleshooting). + +É só isso. Conectar armazena a chave e, quando a máquina **não** tem nenhuma configuração do Jev ainda, ativa o Jev pelo FailproofAI Cloud no modo **shadow**: o Jev é consultado sobre cada chamada de ferramenta monitorada e seus veredictos são registrados, mas o resultado das suas políticas é o que é aplicado. A saída indica isso: + +```text + Jev on through FailproofAI Cloud, in shadow mode: logged, not enforced (~/.failproofai/jev.json). +``` + +**Com `--no-transcripts`, conectar não ativa o Jev.** O Jev envia cada chamada de ferramenta verificada e o prompt recente ao FailproofAI Cloud, o que é mais do que uma conexão somente de decisões foi solicitada a enviar. A chave ainda é armazenada, e a saída indica que o Jev está disponível e como ativá-lo: + +```bash +failproofai jev setup --provider failproofai +``` + +Também não desativa o Jev. Se o `jev.json` da máquina já executa o Jev pelo FailproofAI Cloud, ele é mantido como está, e a saída indica que o Jev ainda envia cada chamada de ferramenta verificada e o prompt recente, e que `failproofai jev setup --mode off` o desativa. + + +Conectar **nunca sobrescreve** um `~/.failproofai/jev.json` existente. Se você já usa seu próprio endpoint do Jev, ele continuará sendo usado, e a saída indica que o arquivo foi mantido como configurado — e, quando esse arquivo deixa o Jev desativado (recusado ou desligado), informa isso e como corrigir. Para mudar essa máquina para o FailproofAI Cloud, execute `failproofai jev setup --provider failproofai`. + + +## Shadow, enforce ou off + +Comece no modo shadow, observe o que o Jev teria feito na página de políticas, depois deixe-o agir: + +```bash +failproofai jev setup --mode enforce # Os veredictos do Jev são aplicados: pode cancelar uma negação revisável e adicionar a própria +failproofai jev setup --mode shadow # O Jev é consultado e registrado; o resultado das suas políticas é aplicado +failproofai jev setup --mode off # mantém a configuração, para de consultar o Jev +``` + +O mesmo controle está no painel local: **Settings → Jev** tem um botão de ligar/desligar e shadow/enforce. Ele reescreve apenas o modo e nada mais. Os hooks leem a configuração a cada chamada de ferramenta, então uma alteração é aplicada a partir da próxima, sem reinicialização. + +## Verificar o que está acontecendo + +```bash +failproofai jev status +failproofai jev test +``` + +`status` mostra o provedor como **FailproofAI Cloud**, o host do Cloud ao qual a máquina se conectou, o modo, e a origem da chave como **FailproofAI Cloud connection**, nunca a chave em si. Quando um `jev.json` do FailproofAI Cloud está configurado, mas o Jev não consegue executar, ele informa o motivo: + +| O `status` diz | `status --json` | Significado | +| --- | --- | --- | +| **off — no Jev key is stored for this machine's FailproofAI Cloud connection** | `key-lacks-jev` | A máquina está conectada, mas nenhuma chave do Jev está armazenada para ela: a chave não tem `jev:evaluate`, ou a conexão não pôde confirmá-la. Execute `failproofai config --token ` novamente com a mesma chave; se faltar a permissão, use uma chave do tipo **machine**. | +| **off — this machine is not connected to FailproofAI Cloud** | `not-connected` | Não há conexão com o FailproofAI Cloud nesta máquina para a chave do Jev pertencer. | + +Após `failproofai config --disconnect`, não há mais nenhum `jev.json` do FailproofAI Cloud (a menos que tenha sido desligado, o que é mantido), então `status` simplesmente reporta o Jev como desativado. `status --json` carrega os mesmos dados (`provider: "failproofai"`, `keySource: "cloud"`, `cloudConnected`, `keyCarriesJev`), inclusive quando a configuração está ausente ou recusada. `permissions` é sempre do `jev.json`; uma recusa sobre `credentials.json` adiciona `credentialsPermissions`, e `fix` quando um comando resolve. `test` envia uma requisição ao vivo e reporta a latência e a versão do Jev que respondeu. Ele encerra com código 1, e informa isso no título, quando a resposta chega após o timeout do hook (os hooks registrariam `timeout`) ou responde erroneamente à pergunta de verificação. + +O painel **Settings → Jev** também mostra a **FailproofAI Cloud connection**: a qual organização a máquina reporta e se sua chave tem Jev. Isso é lido dos próprios arquivos da máquina, sem nenhuma chamada de rede. + +## O que chega à página de políticas + +A máquina já envia sua atividade de hooks ao FailproofAI Cloud (`events:add`). Com o Jev ativado, o registro de cada chamada monitorada também indica qual avaliador foi executado, o que o Jev decidiu, quais políticas ele cancelou, por que recaiu quando o fez, sua latência e o modelo que respondeu — decisões, códigos e nomes, nunca o comando ou seu prompt. Na página **Policies** da sua organização: + +- uma chamada decidida pelo próprio veredicto do Jev (modo enforce) é atribuída ao **Jev**, e quando a verificação decisiva veio de um pacote, o registro também nomeia esse pacote e sua versão; +- no modo shadow, a negação ou aviso do Jev aparece como **would-have**, ao lado dos rollouts que você está observando; +- as políticas que o Jev cancelou, ou teria cancelado no modo shadow, são contadas por política. + +## Quando o Jev não consegue responder + +Cada um desses casos recai sobre o resultado das suas políticas para aquela chamada, e é registrado com seu motivo: + +| Motivo | Causa | +| --- | --- | +| `out-of-credits` | Sua organização usou toda a cota do plano. | +| `http-401`, `http-403` | A chave foi revogada, ou não tem `jev:evaluate`. Reconecte com uma chave que tenha. | +| `http-429` | O FailproofAI Cloud está limitando a taxa do Jev para sua organização. Até que a espera solicitada termine (seu `Retry-After`, no máximo 60 segundos), a máquina não envia nada e cada chamada recai imediatamente. Chamadas retidas dessa forma são registradas como `http-429`, ou como `rate-limited` quando o limite de taxa da própria máquina as retém primeiro. | +| `http-429` (limite diário) | Sua organização usou suas chamadas diárias do Jev: **10.000 por dia UTC**, a menos que quem opera seu FailproofAI Cloud tenha definido outro limite. Cada chamada recai até o contador ser resetado às 00:00 UTC; a máquina ainda tenta novamente no máximo uma vez por minuto, então detecta o reset em até um minuto. `failproofai jev test` diz "Daily Jev limit for this org reached; resets at 00:00 UTC." | +| `http-422` | O Jev recusou a requisição desta chamada, geralmente porque a chamada de ferramenta continha texto denso (base64, hex, código minificado) acima do orçamento de tokens do Jev. Essa chamada sempre recai; não é uma falha de serviço. | +| `http-502` | O Jev está indisponível no momento. | +| `http-503` | Este Cloud não pode servir o Jev para sua organização: sem gateway de modelo, uma organização ainda não provisionada, ou o gateway está fora. Consulte seu administrador; os hooks tentam novamente no máximo uma vez por minuto. | +| `http-404` | Este FailproofAI Cloud ainda não serve o Jev. | +| `timeout` | Nenhuma resposta dentro de `timeoutMs` (padrão 3000). | +| `model-mismatch` | Uma versão do Jev diferente da 1.13 respondeu. | + +## Onde a chave fica armazenada e para onde vai + +- A chave é armazenada uma vez, em `~/.failproofai/credentials.json` (`0600`, em um diretório acessível apenas pelo proprietário), junto com as outras credenciais do FailproofAI Cloud. O `jev.json` não guarda nenhuma chave para esta rota; uma chave escrita lá torna a configuração inválida. +- Se `credentials.json` tiver **qualquer** permissão para alguém além de você (grupo ou outros, leitura ou escrita), ou se seu diretório puder ser **escrito** por alguém além de você, ele será **recusado**, não lido, e o Jev ficará desativado até você corrigir: `chmod 600` no arquivo, `chmod 700` no diretório (ou reconectar, o que reescreve o arquivo com `0600` e torna o diretório exclusivo do proprietário). Um diretório que outros só podem ler está bem; um que outros podem escrever permite trocar o arquivo. +- A chave só conta enquanto a conexão com que veio estiver na máquina: uma credencial de política ou relatório para o mesmo FailproofAI Cloud **com a mesma chave**, no mesmo arquivo. Uma chave do Jev deixada para trás sem uma é ignorada, e o Jev permanece desativado. Isso acontece quando o `config --disconnect` de uma versão mais antiga do failproofai deixa a chave do Jev no lugar (ela não sabe que deve removê-la), ou quando o `config --token` de uma versão mais antiga conecta com outra chave, que no FailproofAI Cloud pode pertencer a outra organização. Para reativar o Jev, conecte novamente com uma chave do tipo **machine**. +- A chave só é enviada para a origem do Cloud contra a qual foi verificada. Um `jev.json` apontando para outro lugar é recusado. +- **Um agente na máquina pode lê-la.** O `credentials.json` é exclusivo do proprietário, e o agente executa como esse proprietário. Ler os próprios arquivos do failproofai é permitido de propósito (apenas alterá-los é bloqueado, pelo `block-failproofai-commands`), então a única coisa entre um agente e este arquivo é `block-read-outside-cwd` — uma política *revisável* — e a partir de uma sessão iniciada no seu diretório home, nada. Uma chave com `jev:evaluate` consome a cota do Jev da sua organização (até o limite diário) de onde quer que seja usada, então trate uma chave de máquina como qualquer outra credencial de gastos: se um agente pode tê-la lido, desative-a na página de Keys e reconecte com uma nova. +- Apenas seus arquivos globais decidem isso. Um repositório não pode ativar o Cloud Jev, apontá-lo para outro lugar ou fornecer sua chave, e `FAILPROOFAI_JEV_API_KEY` é ignorado para esta rota. +- Para cada chamada que o Jev avalia, uma requisição vai ao FailproofAI Cloud, carregando o que a [página de chave própria](/pt-br/policies/jev-byok#what-leaves-the-machine) lista (segredos ocultados). O FailproofAI Cloud encaminha para a TypeSafe e não registra nem retém os dados. + +## Como desativar + +| Comando | Resultado | +| --- | --- | +| `failproofai jev setup --mode off` | Mantém a configuração; o Jev não é consultado. **Este é o interruptor que persiste:** conectar novamente nunca reescreve um `jev.json` existente, então o Jev permanece desativado até você reativá-lo com `--mode shadow`. | +| `failproofai jev remove` | Exclui `~/.failproofai/jev.json`; o Jev fica desativado — até o próximo `failproofai config --token` com uma chave que tenha `jev:evaluate`, que não encontra nenhum `jev.json` e ativa o Jev novamente no modo shadow (a menos que seja executado com `--no-transcripts`). Para mantê-lo desativado, use `--mode off`. | +| `failproofai config --disconnect` | Desconecta a máquina: a chave é removida, e o `jev.json` também quando ele aponta para o FailproofAI Cloud e não está desligado. Um `jev.json` para seu próprio endpoint permanece, assim como um que foi desligado, portanto o Jev continua desativado quando você conectar novamente. | + +A partir da próxima chamada de ferramenta, os hooks executam as políticas de regex exatamente como antes. \ No newline at end of file diff --git a/docs/pt-br/policies/jev.mdx b/docs/pt-br/policies/jev.mdx new file mode 100644 index 000000000..5dafeb70d --- /dev/null +++ b/docs/pt-br/policies/jev.mdx @@ -0,0 +1,45 @@ +--- +title: "Políticas do Jev" +description: "Adicione a revisão ao vivo do Jev às chamadas de ferramentas monitoradas e inspecione suas decisões antes de aplicá-las." +icon: "shield-check" +--- + +O Jev analisa uma chamada de ferramenta em relação ao que a pessoa pediu ao agente para fazer. Use-o quando uma política baseada em correspondência de strings bloqueia um trabalho válido ou deixa passar uma ação arriscada que precisa de contexto. Ele responde junto com suas políticas no gate `PreToolUse` ou `PermissionRequest`. Para uma pontuação **após** o encerramento de uma sessão, use as [avaliações do Jev](/pt-br/evaluations/jev). + +## Comece no modo de observação + +Instale o Failproof AI e conecte hooks a um [harness compatível](/pt-br/reference/harnesses). Use a versão failproofai 1.0.8-beta.0 ou posterior. + +O Failproof AI não vem com verificações do Jev. Instale-as como um pacote; caso contrário, o Jev não terá nada para verificar e nunca será chamado: + +```bash +failproofai policies add FailproofAI/jev-policies +``` + +Em seguida, escolha como as solicitações chegam ao Jev: + +| Rota | Primeiro passo | +| --- | --- | +| FailproofAI Cloud | Conecte-se com uma chave de **máquina** com permissão `jev:evaluate`. Em uma máquina sem configuração do Jev, `failproofai config` ativa o Jev no modo de observação. | +| Seu próprio provedor | No painel local, abra **Configurações → Jev**, escolha o provedor, cole o token e selecione **observe**. Ou execute `failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key`. | + +![Configurações do Jev no painel local: provedor, endpoint, token e modo de observação antes de ativar o Jev.](/images/dashboard/jev-settings.png) + +```bash +failproofai jev status +failproofai jev test +``` + +O comando `test` verifica o endpoint. Para verificar o caminho do hook, peça a um agente monitorado que use sua ferramenta de leitura de arquivos no `README.md`. Confirme que a chamada de ferramenta aparece na sessão e inspecione **Políticas → Atividade** no [painel local](/pt-br/reference/local-dashboard#review-policy-activity). O contador do Jev em `status` deve aumentar. O modo de observação registra o que o Jev teria decidido, enquanto o resultado da sua política existente ainda é aplicado. + +## Decida quando aplicar + +Uma política **rígida** sempre tem a palavra final. O Jev só pode cancelar uma negação de uma política explicitamente marcada como **revisável** e somente quando verificou a preocupação nomeada dessa política. Consulte a [autoridade de política](/pt-br/policies/authority) antes de depender de uma liberação. O Jev também pode emitir avisos ou negar por conta própria. Se não conseguir responder, o resultado da política decide aquela chamada. + +Assim que os resultados do modo de observação parecerem corretos, alterne para o modo de aplicação em **Configurações → Jev** ou execute: + +```bash +failproofai jev setup --mode enforce +``` + +Para URLs de provedores, chaves do Cloud, configurações, fallbacks e dados enviados com cada solicitação, consulte a [referência de integração do Jev](/pt-br/reference/jev). \ No newline at end of file diff --git a/docs/pt-br/reference/custom-agents-typescript.mdx b/docs/pt-br/reference/custom-agents-typescript.mdx new file mode 100644 index 000000000..e1dfee5d5 --- /dev/null +++ b/docs/pt-br/reference/custom-agents-typescript.mdx @@ -0,0 +1,401 @@ +--- +title: "Agentes personalizados (TypeScript)" +description: "Configuração, o catálogo de eventos, os escopos e os adaptadores de framework para @failproofai/sdk." +icon: "square-js" +--- + +O que cada configuração, método e campo faz no SDK TypeScript. Se você está instrumentando pela primeira vez, comece pelo guia — esta página serve como referência. + + + + Instalação, instrumentação, os métodos de evento, um exemplo prático e problemas comuns. + + + Os mesmos eventos, o mesmo formato de wire, o mesmo spool — em Python. + + + +Node 20.9 ou mais recente. ESM e CommonJS. Sem dependências em tempo de execução. + + + Este SDK e o Python escrevem **os mesmos eventos no mesmo spool**. Uma frota com agentes Node e agentes Python produz um único conjunto de sessões, não dois, e nada no dashboard os distingue. Escolha por serviço, não por empresa. + + +## Instalação + +```bash +npm install @failproofai/sdk +``` + +```ts +import * as failproofai from "@failproofai/sdk"; + +await failproofai.agent("planner", { goal: question }, async () => { + const hits = await failproofai.toolCall("web_search", { input: { q } }, () => search(q)); +}); +``` + +Os adaptadores de framework estão incluídos no próprio pacote. Os frameworks são **peer dependencies opcionais** — declarados para que as versões suportadas fiquem visíveis, nunca instalados automaticamente, e importados apenas quando você chama `instrument()`. + +## Conectar o daemon Failproof + +Idêntico ao SDK Python: crie uma chave `events:add` em **Admin → Keys**, depois [conecte o daemon](/pt-br/start/setup#connect-a-machine-to-cloud) na máquina do agente. O SDK escreve em disco; o daemon envia. + +## Configuração + +```ts +failproofai.configure({ + environment: "production", + flushInterval: 0.5, + baseDir: undefined, +}); +``` + +| Opção | O que faz | +| --- | --- | +| `environment` | O rótulo em cada evento — `production`, `staging`, `prod-eu`. Padrão: `dev`. | +| `flushInterval` | Com que frequência o timer escreve em disco, em segundos. Padrão: `0.5`. | +| `baseDir` | Onde escrever. Padrão: o spool do daemon, que é o que você quer, a menos que saiba o contrário. | + +Nada é aplicado a menos que tudo seja válido, portanto uma chamada rejeitada deixa o SDK exatamente como estava, e não com um novo `baseDir` e o intervalo antigo. + +Configurar via variável de ambiente: + +| Variável | O que faz | +| --- | --- | +| `AGENTEYE_ENVIRONMENT` | Define `environment` sem alteração de código. Uma opção em `configure()` tem precedência. | +| `FAILPROOFAI_HOME` | Move o diretório raiz do Failproof AI que contém o spool. | +| `FAILPROOFAI_SDK_LOG_LEVEL` | `debug`, `info`, `warn` (padrão), `error`, `silent`. | +| `FAILPROOFAI_SDK_STRICT` | `1` faz com que erros de instrumentação lancem exceções em vez de serem apenas registrados. | +| `FAILPROOFAI_SDK_STRICT_INTEGRATIONS` | `1` faz com que um problema de compatibilidade com framework lance exceção em vez de apenas avisar e continuar. | + + + **Sem vírgulas em `environment`.** A ingestão divide esse campo por vírgulas para construir seus filtros e descarta qualquer evento cujo rótulo contenha uma — fazendo uma execução inteira desaparecer silenciosamente. Use `prod-eu`, não `prod,eu`. + + `configure({ environment: "prod,eu" })` lança uma exceção para que você descubra imediatamente. `AGENTEYE_ENVIRONMENT` não pode lançar — nada está te chamando — então avisa uma vez e volta para `dev`. + + +Roteie as linhas de log do próprio SDK para o seu logger com `failproofai.setLogger({ debug, info, warn, error })`. + +## Encerramento + +Eventos em buffer são descarregados no `process.on("exit")`. + +Um processo encerrado por um sinal nunca chega a esse ponto, e o comportamento padrão do Node para `SIGTERM` é terminar sem executar os handlers de saída — portanto, um agente em container perde tudo que o último intervalo não escreveu. + + + **Este SDK não vai instalar um handler de sinal para você.** Registrar um altera o comportamento do seu processo: um listener suprime o término padrão do Node, então uma biblioteca que adicionasse um silenciosamente impediria o Ctrl-C de funcionar. Adicione o seu próprio: + + ```ts + for (const signal of ["SIGINT", "SIGTERM"] as const) { + process.once(signal, () => { + failproofai.flushSync(); + process.exit(0); + }); + } + ``` + + +Um script de curta duração ou um handler serverless deve fazer `await failproofai.flush()` antes de retornar — o intervalo sozinho não garante a entrega. + +## Identidade + +Todo evento pertence a uma sessão e a um agente. **Os escopos preenchem ambos automaticamente**, então raramente você precisa passá-los: + +```ts +await failproofai.session(async () => { + await failproofai.agent("planner", async () => { + failproofai.event.toolUse({ toolName: "search", toolCallId: "c1" }); + }); +}); +``` + +Passar `sessionId` ou `agentId` explicitamente ainda funciona e tem precedência. Se nenhum dos dois estiver vinculado nem passado, a chamada lança uma exceção em vez de emitir um evento que o Cloud descartaria silenciosamente. + + + A identidade usa `AsyncLocalStorage`. Ela segue `await`, `.then()`, timers e qualquer callback criado dentro do escopo. Ela **não** segue um callback armazenado durante uma execução e invocado durante outra, nem trabalho passado por um limite `worker_threads` — envolva esses casos com `failproofai.propagate()` ou os eventos serão registrados sem vinculação. + + +### Escopos + +| Escopo | Emite | Retorna | +| --- | --- | --- | +| `session(body)` | nada — apenas identidade | o que `body` retornar | +| `agent(id, options?, body)` | `agent_start`, depois `agent_end` | o que `body` retornar | +| `toolCall(name, options?, body)` | `tool_use`, depois `tool_result` | o que `body` retornar | + +Um body síncrono permanece síncrono: `agent("x", () => 1)` retorna `1`, não uma promise. + +`toolCall` registra o valor resolvido do body como o `output` da ferramenta, a menos que você atribua `call.output` manualmente. + + + +| O que aconteceu | Eventos | `outcome` | +| --- | --- | --- | +| o bloco retornou | `agent_end` | `"success"`, ou o seu `outcome` | +| o bloco lançou exceção | `error`, depois `agent_end` | `"failed"` | +| um `AbortError` | somente `agent_end` | `"cancelled"` | + +O erro é sempre relançado. + +Uma falha de ferramenta é registrada na folha — `tool_result` com uma string `error` — e **não** emite um evento `error` no nível da execução. Uma falha capturada pelo loop do agente não é uma falha de execução, e uma que se propaga é reportada exatamente uma vez, pelo `agent()` que a envolve. + + + + + +Quando o trabalho não é uma função única — um escopo aberto em um construtor e fechado em um teardown, ou que atravessa um fluxo de controle existente: + +```ts +{ + using span = failproofai.agent.open("planner", { goal }); + using call = failproofai.toolCall.open("search", { input: { q } }); + call.call.output = await search(q); +} // tool_result, depois agent_end +``` + +Ambas as formas emitem eventos idênticos em bytes. Prefira a forma com callback: ela é executada dentro de `AsyncLocalStorage.run()`, então não há nada para desfazer e toda a classe de bugs do tipo "aberto aqui, fechado lá" se torna inalcançável. + +Um bloco `using` que captura sua própria falha a reporta com `span.fail(error)` — o disposer não tem canal de exceção próprio. + + + +## Catálogo de eventos + +Os mesmos quinze métodos do SDK Python, em camelCase. A maioria vem em **pares** — você chama o abridor, depois o fechador, e o SDK mede o intervalo de tempo. + +| | Abre | Fecha | +| --- | --- | --- | +| **Agentes** | `agentStart` | `agentEnd` | +| | `agentPause` | `agentResume` | +| **Modelos** | `modelRequest` | `modelResponse` | +| **Ferramentas** | `toolUse` | `toolResult` | +| **Hooks** | `hookTriggered` | `hookCompleted` | +| **Humanos** | `humanWait` | `humanInput` | + +Três são independentes: `error`, `humanPause`, `humanInterrupt`. + + + +Cada método também aceita `sessionId` e `agentId`, que os escopos preenchem automaticamente. Qualquer campo omitido é descartado em vez de enviado como JSON `null`. + +| Método | Obrigatório | Opcional | +| --- | --- | --- | +| `agentStart` | — | `goal`, `parentId` | +| `agentEnd` | — | `outcome`, `summary` | +| `agentPause` | `pauseId` | `reason`, `userId` | +| `agentResume` | `pauseId` | `reason`, `userId` | +| `modelRequest` | — | `model`, `messages`, `system`, `tools`, `requestId` | +| `modelResponse` | — | `model`, `stopReason`, `inputTokens`, `outputTokens`, `content`, `role`, `requestId` | +| `toolUse` | `toolName`, `toolCallId` | `input` | +| `toolResult` | `toolName`, `toolCallId` | `output`, `error` | +| `hookTriggered` | `hookName`, `hookId` | `triggerEvent`, `input` | +| `hookCompleted` | `hookName`, `hookId` | `outcome`, `output`, `error` | +| `error` | `errorType`, `message` | `traceback` | +| `humanWait` | `inputId` | `prompt`, `options`, `reason` | +| `humanInput` | `inputId` | `response` | +| `humanPause` | — | `reason`, `userId` | +| `humanInterrupt` | — | `reason`, `userId`, `atStep` | + +Qualquer outra chave que você adicionar se torna um campo de payload personalizado. Use o prefixo `fw_*` para qualquer coisa específica de framework; um nome que colida com um campo declarado é recusado em vez de sobrescrever silenciosamente uma coluna promovida. + + + + + **`duration_ms` é calculado, não aceito.** Os quatro métodos de fechamento medem o intervalo a partir do abridor correspondente e recusam um `duration_ms` fornecido pelo chamador — uma duração reportada externamente seria falsificável. + + Os pares são correspondidos pela **sessão** e pelo id, nunca pelo agente. Uma ferramenta aberta sob `planner` e fechada sob `worker` ainda forma um par, que é exatamente o que execuções multi-agente aninhadas fazem. + + +## Adaptadores de framework + +```ts +await failproofai.instrument(); // tudo que encontrar +await failproofai.instrument("langchain"); // exatamente um +failproofai.uninstrument(); // restaura tudo +``` + +| Framework | Suportado | Como se conecta | +| --- | --- | --- | +| **LangChain.js / LangGraph.js** | `@langchain/core` 0.3 – 1.x, LangGraph.js 0.4 – 1.x | `CallbackManager.configure`, então todo `invoke`/`stream`/`batch` é coberto sem precisar passar `callbacks:` em lugar algum — ou passe `langchainHandler()` você mesmo e não patche nada. | +| **Vercel AI SDK** | `ai` 4 – 7 | `telemetry()` no call site, ou `instrument("ai")` para todo o processo no `ai` 7 (em 4–6 é opt-in — veja abaixo). | +| **Mastra** | `@mastra/core` 0.20 – 1.x | `Agent.generate`/`.stream`, o modelo do agente e a resolução de ferramentas, além do motor de execução de workflow/step. | +| **LlamaIndex.TS** | `llamaindex` 0.11.4 – 0.x | `Settings.callbackManager` (inscrito) mais `AgentWorkflow.runStream`, para execuções de workflow e seus steps. | + +Cada intervalo é testado com releases reais do framework, em ambos os extremos, como ES module e como CommonJS, em cada execução de CI. + +O mapeamento é o do SDK Python, então o mesmo programa desenha a mesma árvore em qualquer linguagem. Uma construção é um **agente** somente se possui um loop de decisão LLM — uma execução de grafo ou chain, uma chamada `generateText`/`streamText` do AI SDK, um agente Mastra, uma execução de agente LlamaIndex. Um nó LangGraph ou um step de workflow é um **hook** (`hook_triggered`/`hook_completed`), nunca um agente aninhado. Chamadas de modelo são pares `model_request`/`model_response` com contagens de tokens; chamadas de ferramentas carregam o id de tool call do próprio modelo. Uma falha é registrada uma vez, no evento em que ocorreu. + +Um adaptador que falha na instalação é registrado e ignorado; os demais ainda são instalados, pois um LlamaIndex com problema não deve custar o LangGraph. + + + `instrument()` sem argumento detecta um framework pela sua capacidade de **resolver**, não por já estar importado — o Node não expõe um equivalente ao `sys.modules` do Python para ES modules. Um framework instalado mas não utilizado será importado e patcheado. Especifique o que você quer se isso for importante. + + + + A maioria desses frameworks inclui um build ES module e um build CommonJS, que o Node carrega como duas cópias independentes. Os adaptadores patcheam a cópia que sua aplicação carrega (e também a cópia CommonJS se algo já a tiver `require`d), então ambos os sistemas de módulos funcionam. Um framework **empacotado no seu próprio output** pelo esbuild ou webpack está fora de alcance — use os helpers de call site nesse caso: `langchainHandler()`, `telemetry()`, `wrapTool()`. + + +### LangChain sem patching + +```ts +import { langchainHandler } from "@failproofai/sdk/langchain"; +await graph.invoke(input, { callbacks: [langchainHandler()] }); +``` + +O handler funciona com ou sem `instrument()` e nunca registra duplicatas. `instrument("langchain")` aceita `sessionId`, `captureContent`, `includeChains`, `graphCallbacks` e `captureLimit`, como o adaptador Python; `metadata: { failproofai_sdk_session_id }` em uma chamada seleciona a sessão para aquela invocação. + +### Vercel AI SDK + +O AI SDK exporta funções simples de um ES module, e um namespace de ES module é imutável por especificação — não há onde fazer patch. Ele usa os pontos de extensão que o próprio SDK documenta: + +```ts +import { telemetry } from "@failproofai/sdk/ai"; + +const { text } = await generateText({ + model, + prompt, + experimental_telemetry: telemetry({ functionId: "answer-question" }), + // no ai 7, `telemetry: telemetry({ … })` — o mesmo objeto, o novo nome +}); +``` + +Essa é a integração completa: um span de agente, um par de model request/response por step com contagens de tokens, e cada tool call. Um call site funciona em todos os majors — `ai` 4–6 lê o tracer que ele carrega, `ai` 7 a integração de telemetria. + +`instrument("ai")` faz o mesmo para todo o processo **no `ai` 7**: toda chamada, através da lista global de integração de telemetria do AI SDK, que é aditiva e não interfere com mais ninguém. + +**No `ai` 4–6, `instrument("ai")` não registra nada por si só e loga um aviso dizendo isso.** O único hook para todo o processo nesses majors é o provider global de tracer OpenTelemetry — um único slot que o OpenTelemetry recusa ceder uma vez ocupado. Registrar o nosso silenciosamente recusaria seu próprio `NodeSDK.start()` mais tarde na inicialização e enviaria seus spans de http/banco de dados para um tracer que não exporta nada. Use `telemetry()` no call site ou `wrapModel` lá. Se o processo não executa OpenTelemetry próprio, opte por `instrument("ai", { registerGlobalTracer: true })`: ele então registra toda chamada que passa `experimental_telemetry: { isEnabled: true }` e só ocupa o slot se ainda estiver vazio. `registerGlobalTracer: false` mantém o comportamento padrão e silencia o aviso. + +Se preferir encapsular o modelo uma vez, `wrapModel` enxerga apenas chamadas de modelo, pois as tool calls acontecem acima da camada do modelo. Um modelo encapsulado chamado sem nada ao redor é registrado como sua própria execução. Uma chamada com stream é fechada de acordo com como o stream termina — `stop_reason: "cancelled"` quando o consumidor cancela, `"error"` com o erro quando falha no meio do caminho: + +```ts +import { wrapModel } from "@failproofai/sdk/ai"; +const model = await wrapModel(openai("gpt-4o")); +``` + +Usar ambos é válido: o middleware percebe que a chamada já está sendo registrada e cede, então cada chamada é registrada uma única vez. + +`functionId` nomeia o span do agente. Mantenha baixa cardinalidade — ele vai para `agent_id`, a faceta principal do dashboard. + +### Next.js + +`next build` empacota as dependências do seu servidor por padrão, e um framework empacotado no build é uma cópia que `instrument()` não consegue alcançar. Encapsule a config uma vez e chame `instrument()` no hook de inicialização do Next: + +```ts +// next.config.ts +import { withFailproofai } from "@failproofai/sdk/next"; +export default withFailproofai({ /* your config */ }); +``` + +```ts +// instrumentation.ts +export async function register() { + if (process.env.NEXT_RUNTIME !== "nodejs") return; + const failproofai = await import("@failproofai/sdk"); + await failproofai.instrument(); +} +``` + +`withFailproofai` adiciona LangChain, Mastra, LlamaIndex e o próprio SDK a `serverExternalPackages`, preservando sua lista. Sem ele, `instrument()` avisa uma vez por framework que não consegue alcançar em vez de falhar silenciosamente; se você listar os pacotes você mesmo, defina `FAILPROOFAI_NEXT_EXTERNALS=1`. O Vercel AI SDK e os helpers de call site funcionam de qualquer forma. Uma rota Edge recebe um build no-op: importar o SDK é seguro e não registra nada. + +### Contagens de tokens em chamadas com stream + +APIs compatíveis com OpenAI só reportam uso em um stream quando o cliente solicita. LangChain e o Vercel AI SDK solicitam; para LlamaIndex passe `additionalChatOptions: { stream_options: { include_usage: true } }` ao seu LLM `OpenAI`, e para Mastra construa o modelo com uso habilitado (por exemplo `createOpenAICompatible({ includeUsage: true })`). Caso contrário, chamadas de modelo com stream não carregam contagens de tokens. + +### Runtimes + +Node ≥ 20.9, Bun e Deno — cada framework, como ES module e como CommonJS, é testado em cada um deles em comparação com o trace do Node. O SDK roda ao lado do daemon `failproofaid`, que envia o que ele escreve. + +## Seu próprio agente — sem framework + +Para um loop de agente que você mesmo escreveu, ou um framework sem adaptador. Você emite os eventos com a mesma API que os adaptadores usam por baixo, então o trace tem a mesma forma e qualidade. + +Você não precisa saber como o agente está organizado. Todo agente construído manualmente já tem três lugares, independente do nome das funções, e esses três são toda a integração: + +| Onde | O que adicionar | Emite | +| --- | --- | --- | +| Onde **uma execução** começa e termina | `failproofai.agent("name", { goal }, async () => …)` | `agent_start` / `agent_end` | +| A **única função que chama o modelo** | `event.modelRequest` antes, `event.modelResponse` depois — ambas as metades, mesmo em caso de falha | um par por turno de modelo | +| A **única função que executa ferramentas** | `failproofai.toolCall(name, { toolCallId, input }, () => run())` | `tool_use` / `tool_result` | + +```ts +async function callModel(messages) { + const requestId = randomUUID(); + const started = Date.now(); + failproofai.event.modelRequest({ model: MODEL, requestId, messages }); + try { + const reply = await client.chat.completions.create({ model: MODEL, messages, tools }); + failproofai.event.modelResponse({ + model: reply.model, requestId, stopReason: reply.choices[0].finish_reason, + inputTokens: reply.usage?.prompt_tokens, outputTokens: reply.usage?.completion_tokens, + duration_ms: Date.now() - started, + }); + return reply.choices[0].message; + } catch (error) { + failproofai.event.modelResponse({ model: MODEL, requestId, stopReason: "error", + error: String(error), duration_ms: Date.now() - started }); + throw error; + } +} + +async function dispatch(call) { + const input = JSON.parse(call.function.arguments); + return failproofai.toolCall(call.function.name, { toolCallId: call.id, input }, + () => runTool(call.function.name, input)); +} + +await failproofai.agent("inventory", { goal: question }, async () => { + for (;;) { + const message = await callModel(messages); + if (!message.tool_calls?.length) return message.content; + for (const call of message.tool_calls) await dispatch(call); + } +}); +``` + +A identidade é ambiente: tudo dentro de `agent()` fica vinculado à sessão daquela execução sem precisar de um id, e nada mais no programa muda — incluindo o que o agente já escreve em seu próprio banco de dados. + +- **Um serviço ou um worker:** passe seu próprio id de requisição ou job como `sessionId`, para que uma sessão no dashboard e o registro no seu próprio log ou banco de dados sejam a mesma string. +- **Sub-agentes:** aninhe chamadas de `agent()`. O interno entra na sessão com o externo como seu `parent_id`. +- **Emita os pares.** Um `modelRequest` sem `modelResponse` é um span que o dashboard mostra como executando para sempre — daí o `catch`. + +[`sdk/typescript/examples/research-agent.ts`](https://github.com/FailproofAI/failproofai/blob/main/sdk/typescript/examples/research-agent.ts) no repositório é a versão completa e executável: um loop real de ferramentas OpenAI instrumentado exatamente assim, executado no CI a cada mudança como ES module e como CommonJS. + +## Avaliações + +```ts +import { Evaluator, EvalResult, Score } from "@failproofai/sdk/evaluator"; + +export const app = new Evaluator({ name: "my-evals", version: "1" }); + +app.eval("tool_success_rate", { version: "1" }, (session) => { + const results = session.eventsOfType("tool_result"); + const failures = results.filter((event) => event.payload.error != null).length; + return new EvalResult({ + score: new Score(results.length === 0 ? 1 : 1 - failures / results.length), + reasoning: `${failures} of ${results.length} tool calls failed`, + }); +}); +``` + +```bash +FAILPROOFAI_EVALUATOR_URL=… FAILPROOFAI_EVALUATOR_TOKEN=… \ + npx failproofai-evaluator ./my-evals.js +``` + +Consulte a [referência do Evaluator SDK](/pt-br/reference/evaluator-sdk) para o protocolo, as configurações do worker e os tipos de resultado. + + + **Uma avaliação deve ceder o controle.** Uma função síncrona que nunca retorna bloqueia a única thread que o Node possui, e nenhum timeout pode disparar enquanto isso ocorre. Escreva avaliações `async`. + + +## O que não será feito ao seu processo + +| | | +| --- | --- | +| **Bloquear seu loop de agente** | Eventos vão para uma fila em memória; um timer os escreve. O timer tem `unref`, então importar este pacote nunca impede um script de sair. | +| **Crescer sem limite** | A fila tem limite por contagem *e* por bytes medidos. Após qualquer um dos limites, os eventos mais antigos são descartados e um aviso é emitido — uma falha de telemetria não deve se tornar um OOM kill. | +| **Derrubar o processo** | Um evento não codificável é descartado individualmente, não o lote ao redor dele. Um getter que lança exceção, uma referência circular, um `BigInt`, um surrogate isolado: cada um é tratado em vez de propagado. | +| **Deixar um lote escrito parcialmente** | O conteúdo é `fsync`ado antes de um rename atômico, o diretório é `fsync`ado depois, e uma escrita que falha limpa seu arquivo temporário. | +| **Deixar transcrições legíveis** | Os lotes têm permissão `0600` dentro de um diretório `0700`. Eles carregam goals, prompts, argumentos de ferramentas e output de ferramentas. | +| **Enviar credenciais** | Chaves de API, tokens, JWTs, cabeçalhos bearer e atribuições com formato de segredo são redatados antes que os bytes cheguem ao disco. O daemon redige novamente antes do upload. | \ No newline at end of file diff --git a/docs/pt-br/reference/jev-cloud.mdx b/docs/pt-br/reference/jev-cloud.mdx new file mode 100644 index 000000000..7965f7c06 --- /dev/null +++ b/docs/pt-br/reference/jev-cloud.mdx @@ -0,0 +1,136 @@ +--- +title: "Jev via FailproofAI Cloud" +description: "Chaves de máquina na nuvem, estado de conexão, limites e comportamento em caso de falha para revisão de políticas Jev em tempo real." +icon: "cloud" +--- + +Esta é a referência de rota Cloud para [políticas Jev](/pt-br/policies/jev). O Jev, classificador da TypeSafe, analisa cada chamada de ferramenta em relação ao que você realmente solicitou e responde junto com suas políticas, nunca no lugar delas. Com o **FailproofAI Cloud**, uma máquina conectada usa o Jev com a mesma chave com que já se conecta: sem conta TypeSafe, sem segunda chave, sem endpoint para configurar. Cada chamada é debitada da cota do plano existente da sua organização. + +Tudo o que o Jev faz permanece igual à [configuração bring-your-own-key](/pt-br/reference/jev-providers): políticas rígidas continuam sendo definitivas, a negação de uma política revisável é removida apenas quando o Jev foi consultado exatamente sobre aquela preocupação, e qualquer falha recai no resultado do regex para aquela chamada. + + +Requer **failproofai 1.0.8-beta.0** ou posterior. A versão 1.0.7 não tem Jev, mesmo que apareça acima dos betas 1.0.7 na ordenação. Sem uma configuração de Jev, nada muda: os hooks executam as políticas de regex exatamente como sempre fizeram. + + +## Antes de começar + +Instale o Failproof AI na máquina onde seu agente é executado e anexe seus hooks a um [harness suportado](/pt-br/reference/harnesses). Se estiver começando do zero, siga o [quickstart](/pt-br/start/quickstart) até a instalação dos hooks. Verifique o CLI instalado com `failproofai --version`; atualize-o se for anterior ao Jev. Você também precisa de acesso à página **Administração → Chaves** da sua organização para criar uma chave de máquina. + +O Jev revisa chamadas de ferramentas nomeadas no gate `PreToolUse` ou `PermissionRequest`. Ele não revisa todos os eventos de uma sessão. Para ver o Jev remover uma negação de política, você precisa de uma política instalada marcada como [revisável](/pt-br/policies/authority); todas as outras negações de política permanecem definitivas. + +## Ativar + +1. **Crie uma chave com Jev.** No painel do FailproofAI Cloud, abra **Administração → Chaves → Criar chave** e escolha o preset **machine**. Ele concede as três permissões que uma máquina precisa: `events:add` (enviar atividade), `policies:pull` (receber políticas) e `jev:evaluate` (Jev, debitado do plano da sua organização). Uma chave não pode ter `jev:evaluate` sem as outras duas. +2. **Conecte a máquina** com essa chave. Leia seu segredo de uso único no prompt e execute o comando completo de configuração: + + ```bash + read -rs FAILPROOFAI_CLOUD_TOKEN && export FAILPROOFAI_CLOUD_TOKEN + failproofai config + ``` + + `failproofai config` instala o daemon, anexa hooks para os CLIs de agente encontrados e conecta a máquina. A variável de ambiente mantém a chave fora dos argumentos do comando e do histórico do shell. Se o seu harness foi instalado depois, [anexe-o explicitamente](/pt-br/start/quickstart). + + Se a sua organização roda seu próprio FailproofAI Cloud em vez do hospedado, adicione o endereço: `--url https://` (ou exporte `FAILPROOFAI_CLOUD_URL`). Sem isso, a chave é verificada no serviço hospedado e a conexão falha. Se o certificado desse host vem de uma CA privada, instale a CA no repositório de confiança do sistema da máquina (por exemplo, com `update-ca-certificates`), não apenas em `NODE_EXTRA_CA_CERTS`: o daemon que envia eventos e obtém políticas lê o repositório do sistema. Consulte [Solução de problemas](/pt-br/reference/troubleshooting). + +É só isso. A conexão armazena a chave e, quando a máquina **não** tem configuração de Jev ainda, ativa o Jev via FailproofAI Cloud no modo **observe**: assim que um pack fornecer verificações, o Jev é consultado sobre cada chamada de ferramenta no gate e seus veredictos são registrados, mas o resultado das suas políticas é o que é aplicado. A saída indica isso: + +```text + Jev on through FailproofAI Cloud, in observe mode: logged, not enforced (~/.failproofai/jev.json). +``` + +O Jev ainda não pergunta nada até que um pack forneça verificações. O Failproof AI não inclui nenhum; enquanto nenhum pack instalado declarar algum, a saída adiciona uma linha informando isso, e `failproofai jev status` repete a informação. Instale-os com: + +```bash +failproofai policies add FailproofAI/jev-policies +``` + +**Com `--no-transcripts`, a conexão não ativa o Jev.** O Jev envia cada chamada de ferramenta verificada e o prompt recente ao FailproofAI Cloud, o que é mais do que uma conexão somente de decisões foi solicitada a enviar. A chave ainda é armazenada, e a saída informa que o Jev está disponível e como ativá-lo: + +```bash +failproofai jev setup --provider failproofai +``` + +Também não desativa o Jev. Se o `jev.json` da máquina já executa o Jev via FailproofAI Cloud, ele é mantido como está, e a saída informa que o Jev ainda envia cada chamada de ferramenta verificada e o prompt recente, e que `failproofai jev setup --mode off` o desativa. + + +A conexão **nunca sobrescreve** um `~/.failproofai/jev.json` existente. Se você já usa seu próprio endpoint Jev, ele continua sendo usado, e a saída informa que o arquivo foi mantido como configurado — e, quando esse arquivo deixa o Jev desativado (recusado ou desligado), informa isso e como corrigir. Para mudar essa máquina para o FailproofAI Cloud, execute `failproofai jev setup --provider failproofai`. + + +## Observe, enforce ou off + +Comece em observe, observe o que o Jev teria feito na página de políticas e deixe-o agir: + +```bash +failproofai jev setup --mode enforce # Os veredictos do Jev são aplicados: ele pode remover uma negação revisável e adicionar a sua própria +failproofai jev setup --mode observe # O Jev é consultado e registrado; o resultado das suas políticas é aplicado +failproofai jev setup --mode off # Mantém a config, para de consultar o Jev +``` + +O mesmo controle está no dashboard local: **Configurações → Jev** tem um botão liga/desliga e observe/enforce. Ele reescreve apenas o modo. Os hooks leem a configuração em cada chamada de ferramenta, então uma mudança se aplica a partir da próxima, sem reinicialização. + +## Verificar o que está fazendo + +```bash +failproofai jev status +failproofai jev test +``` + +`status` mostra o provedor como **FailproofAI Cloud**, o host Cloud ao qual a máquina está conectada, o modo e a origem da chave como **FailproofAI Cloud connection**, nunca a chave em si. Quando um `jev.json` do FailproofAI Cloud está presente mas o Jev não consegue executar, ele informa o motivo: + +| O `status` diz | `status --json` | Significado | +| --- | --- | --- | +| **off — no Jev key is stored for this machine's FailproofAI Cloud connection** | `key-lacks-jev` | A máquina está conectada, mas nenhuma chave Jev está armazenada para ela: a chave não tem `jev:evaluate`, ou a conexão não pôde confirmá-la. Execute `failproofai config` novamente com a chave em `FAILPROOFAI_CLOUD_TOKEN`; se ela não tiver a permissão, use uma chave **machine**. | +| **off — this machine is not connected to FailproofAI Cloud** | `not-connected` | Não há conexão com o FailproofAI Cloud nesta máquina para a chave Jev pertencer. | + +Após `failproofai config --disconnect`, não há mais um `jev.json` do FailproofAI Cloud (a menos que estivesse desativado, o que é mantido), então `status` simplesmente reporta o Jev como desativado. `status --json` carrega os mesmos dados (`provider: "failproofai"`, `keySource: "cloud"`, `cloudConnected`, `keyCarriesJev`), inclusive quando a configuração está ausente ou foi recusada. `permissions` é sempre do `jev.json`; uma recusa sobre `credentials.json` adiciona `credentialsPermissions`, e `fix` quando um comando resolve. `test` envia uma requisição ao vivo e reporta sua latência e a versão do Jev que respondeu. Ele sai com código 1, e informa isso no título, quando a resposta chega após o timeout do hook (os hooks registrariam `timeout`) ou responde incorretamente à pergunta de verificação. + +O painel **Configurações → Jev** no dashboard também mostra a **conexão FailproofAI Cloud**: em qual organização a máquina se reporta e se sua chave carrega Jev. É lido dos próprios arquivos da máquina, sem chamada de rede. + +## Verificar uma chamada real + +Inicie uma nova sessão no agente com hooks. Peça para ele usar sua ferramenta de leitura de arquivos em `README.md` e reportar o título. Confirme que a sessão contém essa chamada de ferramenta e execute `failproofai jev status` novamente: a contagem de chamadas avaliadas recentes deve aumentar. Abra **Políticas → Atividade** no [dashboard local](/pt-br/reference/local-dashboard#review-policy-activity) para inspecionar o veredicto Jev e o modo dessa chamada. Na nuvem, a página **Políticas** da organização mostra os resultados do Jev para atividades entregues. No modo observe, o veredicto é registrado como um **would-have** e o resultado da política ainda decide a chamada. Uma remoção aparece apenas quando uma política revisável correspondeu e o Jev removeu suas verificações nomeadas. + +## O que chega à página de políticas + +A máquina já envia sua atividade de hooks ao FailproofAI Cloud (`events:add`). Com o Jev ativado, o registro de cada chamada no gate também informa qual avaliador executou, o que o Jev decidiu, quais políticas ele removeu, por que recorreu ao fallback quando o fez, sua latência e o modelo que respondeu — decisões, códigos e nomes, nunca o comando ou seu prompt. Na página **Políticas** da sua organização: + +- uma chamada decidida pelo próprio veredicto do Jev (modo enforce) é atribuída ao **Jev**, e quando a verificação decisiva veio de um pack, o registro também nomeia esse pack e sua versão; +- no modo observe, a negação ou aviso do Jev aparece como um **would-have**, ao lado dos rollouts que você está observando; +- as políticas que o Jev removeu, ou teria removido no modo observe, são contadas por política. + +## Quando o Jev não consegue responder + +Cada um desses casos recai no resultado das suas políticas para aquela chamada, e é registrado com seu motivo: + +| Motivo | Causa | +| --- | --- | +| `out-of-credits` | Sua organização usou sua cota do plano. | +| `http-401`, `http-403` | A chave foi revogada ou não carrega `jev:evaluate`. Reconecte com uma chave que tenha. | +| `http-429` | O FailproofAI Cloud está limitando a taxa do Jev para sua organização. Até que o tempo de espera solicitado termine (seu `Retry-After`, no máximo 60 segundos), a máquina não envia nada e cada chamada vai direto para o fallback. Chamadas retidas dessa forma são registradas como `http-429`, ou como `rate-limited` quando o limite de taxa da própria máquina as retém primeiro. | +| `http-429` (limite diário) | Sua organização usou suas chamadas Jev diárias: **10.000 por dia UTC**, a menos que quem opera seu FailproofAI Cloud tenha definido outro limite. Cada chamada vai para o fallback até que a contagem reinicie às 00:00 UTC; a máquina ainda tenta novamente no máximo uma vez por minuto, então detecta o reinício dentro de um minuto. `failproofai jev test` diz "Daily Jev limit for this org reached; resets at 00:00 UTC." | +| `http-422` | O Jev recusou a requisição dessa chamada, geralmente porque a chamada de ferramenta continha texto denso (base64, hex, código minificado) acima do orçamento de tokens do Jev. Essa chamada sempre vai para o fallback; não é uma interrupção. | +| `http-502` | O Jev está indisponível no momento. | +| `http-503` | Este Cloud não pode servir Jev para sua organização: sem gateway de modelo, uma organização ainda não provisionada ou o gateway está fora. Consulte seu administrador; os hooks tentam novamente no máximo uma vez por minuto. | +| `http-404` | Este FailproofAI Cloud ainda não serve Jev. | +| `timeout` | Sem resposta dentro de `timeoutMs` (padrão 3000). | +| `model-mismatch` | Uma versão do Jev diferente de 1.13 respondeu. | + +## Onde a chave fica e para onde vai + +- A chave é armazenada uma vez, em `~/.failproofai/credentials.json` (`0600`, em um diretório exclusivo do proprietário), junto com as outras credenciais do FailproofAI Cloud. `jev.json` não contém chave para esta rota; uma escrita lá torna a configuração inválida. +- Se `credentials.json` tiver **qualquer** permissão para alguém além de você (grupo ou outros, leitura ou escrita), ou se seu diretório puder ser **escrito** por alguém além de você, ele será **recusado**, não lido, e o Jev ficará desativado até você corrigir: `chmod 600` no arquivo, `chmod 700` no diretório (ou reconecte, o que reescreve o arquivo com `0600` e torna o diretório exclusivo do proprietário). Um diretório que outros só podem ler é aceitável; um que eles podem escrever permite que troquem o arquivo. +- A chave conta apenas enquanto a conexão de que veio estiver na máquina: uma credencial de política ou relatório para o mesmo FailproofAI Cloud **com a mesma chave**, no mesmo arquivo. Uma chave Jev deixada sem uma dessas é ignorada, e o Jev permanece desativado. Isso acontece quando um failproofai mais antigo com `config --disconnect` deixa a chave Jev no lugar (ele não sabe que deve removê-la), ou quando um failproofai mais antigo com `config --token` conecta com outra chave, que no FailproofAI Cloud pode pertencer a outra organização. Para reativar o Jev, conecte novamente com uma chave **machine**. +- A chave só é enviada à origem Cloud contra a qual foi verificada. Um `jev.json` apontando para qualquer outro lugar é recusado. +- **Um agente na máquina pode lê-la.** `credentials.json` é exclusivo do proprietário, e o agente executa como esse proprietário. Ler os próprios arquivos do failproofai é permitido intencionalmente (apenas alterá-los é bloqueado, por `block-failproofai-commands`), então o único impedimento entre um agente e este arquivo é `block-read-outside-cwd` — uma política *revisável* — e em uma sessão iniciada no seu diretório home, nenhum. Uma chave com `jev:evaluate` consome a cota Jev da sua organização (até o limite diário) de onde quer que seja usada, então trate uma chave de máquina como qualquer outra credencial de gasto: se um agente pode tê-la lido, desative-a na página de Chaves e reconecte com uma nova. +- Apenas seus arquivos globais decidem isso. Um repositório não pode ativar o Cloud Jev, apontá-lo para outro lugar ou fornecer sua chave, e `FAILPROOFAI_JEV_API_KEY` é ignorado para esta rota. +- Para cada chamada que o Jev avalia, uma requisição vai ao FailproofAI Cloud, carregando o que a [página bring-your-own-key](/pt-br/reference/jev-providers#what-leaves-the-machine) lista (segredos redigidos). O FailproofAI Cloud encaminha para a TypeSafe e não registra nem retém. + +## Desativar + +| Comando | Resultado | +| --- | --- | +| `failproofai jev setup --mode off` | Mantém a configuração; o Jev não é consultado. **Este é o interruptor que persiste:** conectar novamente nunca reescreve um `jev.json` existente, então o Jev permanece desativado até você reativá-lo com `--mode observe`. | +| `failproofai jev remove` | Exclui `~/.failproofai/jev.json`; o Jev fica desativado — até o próximo `failproofai config --token` com uma chave que carregue `jev:evaluate`, que não encontrará `jev.json` e ativará o Jev novamente no modo observe (a menos que execute com `--no-transcripts`). Para mantê-lo desativado, use `--mode off`. | +| `failproofai config --disconnect` | Desconecta a máquina: a chave é removida, e o `jev.json` também quando ele nomeia o FailproofAI Cloud e não está desativado. Um `jev.json` para seu próprio endpoint permanece, e o mesmo acontece com um que esteja desativado, então o Jev continua desativado quando você conectar novamente. | + +A partir da próxima chamada de ferramenta, os hooks executam as políticas de regex exatamente como antes. \ No newline at end of file diff --git a/docs/pt-br/reference/jev-evaluations.mdx b/docs/pt-br/reference/jev-evaluations.mdx new file mode 100644 index 000000000..ff2cda945 --- /dev/null +++ b/docs/pt-br/reference/jev-evaluations.mdx @@ -0,0 +1,88 @@ +--- +title: "Referência de avaliação Jev" +description: "Tipos de perguntas, pontuações calibradas, limites e backfill para avaliações de sessão Jev." +icon: "list-checks" +--- + +Esta página descreve os formatos de perguntas e as regras de pontuação das [avaliações Jev](/pt-br/evaluations/jev). Algumas perguntas precisam que um modelo *leia* a conversa, mas não que *escreva* sobre ela. "O cliente expressou urgência?" tem duas respostas. "Quão frustrado ele estava?" tem algumas, em ordem. Você conhece todas as respostas antes mesmo de perguntar. + +Uma **avaliação classificadora** é exatamente para isso. Você escreve a pergunta e as respostas possíveis, e um modelo pequeno criado para classificação retorna um número calibrado — nunca texto livre. + + +Assim como um juiz, uma avaliação classificadora custa uma chamada de modelo por sessão. Ao contrário de um juiz, ela usa um modelo pequeno e de propósito único em vez de um modelo geral, portanto é mais rápida e barata — mas nunca vai se explicar. Se você precisar do raciocínio, use um [juiz](/pt-br/evaluations/judge). + + +## Qual devo usar? + +| Pergunta | Use | +| --- | --- | +| Quantas chamadas de ferramenta houve? | código | +| A sessão durou menos de 30 segundos? | código | +| O cliente expressou urgência? | **classificador** | +| Qual equipe deve tratar isso: cobrança, técnica ou vendas? | **classificador** | +| Quão frustrado estava o cliente? | **classificador** | +| A resposta estava realmente correta? | **juiz** | +| Ela seguiu nossa política de escalonamento e por que você acha isso? | **juiz** | + +A regra geral: **contável → código, respostas que você pode listar → classificador, precisa de explicação → juiz.** + +Você não precisa decidir de antemão. Descreva o que quer medir e o assistente escolhe, informa qual foi escolhido e por quê, e você pode mudar. + +## Os dois tipos de pergunta + +### `noul` — isso é verdade? + +Duas respostas, e você descreve ambas. O resultado é a probabilidade de que a descrição "verdadeira" se aplique: + +```json +{ + "instructions": "Did the assistant promise a refund without first checking the refund policy?", + "criteria": { + "true": "A refund was promised or issued with no prior policy check or approval", + "false": "No refund was promised, or every refund followed a policy check" + } +} +``` + +Descreva os dois lados. "Nenhuma urgência expressa" é uma resposta real e dizê-la torna a outra mais precisa. + +### `score` — quanto disso? + +Um rubrica ordenada, **do pior para o melhor**. O resultado é onde a sessão se situa nela, reescalonado para 0–1: + +```json +{ + "instructions": "How frustrated is the customer?", + "criteria": ["Calm", "Frustrated", "Very angry"] +} +``` + +**Uma rubrica tem de três a cinco níveis, e todos devem ser diferentes.** Ambos os limites são mensuráveis, não estilísticos: + +- **Dois níveis** colapsam no que o `noul` já faz melhor, e **mais de cinco** faz o modelo se esquivar para o meio em vez de se comprometer. A mesma pergunta sobre a mesma sessão pontuou 0,00 com dois níveis, 0,01 com três e 0,55 com dez. +- **Níveis repetidos** dividem a resposta arbitrariamente entre eles. Uma sessão que estava inegavelmente irritada pontuou 1,00 com `["Calm", "Frustrated", "Very angry"]` e 0,66 com `["Angry", "Angry", "Angry"]` — um número bem formado que não significa nada. + +Categorias sem ordem — "cobrança, técnica ou vendas" — não são uma rubrica. Pergunte-as como `noul` por categoria, ou use um juiz. + +## Lendo os resultados + +Um classificador produz uma **pontuação** de 0 a 1, exatamente como um juiz, portanto aparece em gráficos, filtros e alertas da mesma forma. Duas diferenças valem a pena conhecer: + +- **Não há raciocínio.** O campo fica vazio, intencionalmente. Esse modelo não se explica, e inventar uma explicação seria uma fabricação, não um recurso. +- **A incerteza é indicada.** Uma pergunta `score` reporta sua própria confiança, e um resultado sobre o qual o modelo estava inseguro é marcado como `low_confidence` — então "quais destes um humano deveria analisar" é um filtro, não uma suposição. Uma pergunta `noul` não reporta confiança, portanto nunca é marcada. + +Sessões muito longas são lidas em trechos e combinadas. Quando uma sessão é longa demais para ser lida por completo, o resultado indica quantos turnos foram omitidos — você nunca verá um julgamento feito sobre parte de uma sessão apresentado como se fosse feito sobre ela toda. + +## Limites + +- **De três a cinco níveis de rubrica, todos distintos.** Veja acima; ambos os limites são aplicados no momento da criação. +- **Uma pergunta por avaliação.** Pergunte duas coisas e você obtém duas avaliações, que é também o que você quer em um gráfico. +- **Editar a pergunta publica uma nova versão.** Pontuações antigas e novas não são comparáveis, portanto são mantidas separadas em vez de misturadas em uma única linha de tendência. +- **Um classificador sempre produz uma pontuação**, nunca uma métrica ou uma afirmação. +- **Sem raciocínio**, como mencionado acima. Se um número fará alguém perguntar "por quê?", escreva um juiz em vez disso. + +## Testes e backfill + +Ao contrário de um juiz, uma avaliação classificadora **pode** ser testada antes de você implantá-la — [teste-a](/pt-br/evaluations/test) em sessões reais da mesma forma que faria com uma avaliação de código, e leia as pontuações antes que qualquer coisa entre em produção. + +Ela também pode ser aplicada via [backfill](/pt-br/evaluations/deploy#score-sessions-you-already-have) em sessões que você já possui. Custa uma chamada de modelo por sessão, portanto defina a janela de forma deliberada em vez de reprocessar tudo. \ No newline at end of file diff --git a/docs/pt-br/reference/jev-intent.mdx b/docs/pt-br/reference/jev-intent.mdx new file mode 100644 index 000000000..2a5e09801 --- /dev/null +++ b/docs/pt-br/reference/jev-intent.mdx @@ -0,0 +1,112 @@ +--- +title: "Captura de intenção do Jev" +description: "Quais eventos do harness informam ao avaliador Jev o que o usuário solicitou, qual campo carrega o texto, o que nunca é contabilizado e o risco de confiar em um prompt entregue pelo harness." +icon: "message-square-quote" +--- + +Quando você configura a [revisão de políticas do Jev](/pt-br/policies/jev), o avaliador julga cada chamada de ferramenta monitorada com base no **que o usuário solicitou**, e não no texto que o harness colocou diante do agente. Uma resposta como "sim, faça o force-push" pode liberar uma política **revisável** — esse é justamente o objetivo do avaliador, já que uma regex que não consegue ler a solicitação bloqueia um terço do trabalho real. + +Esse texto vem de um único lugar: **o prompt que o próprio harness entrega ao hook no seu evento de envio de prompt**. O Failproof AI registra a parte digitada pelo usuário — sem o envoltório do harness, com segredos redigidos e com limite de tamanho — em um arquivo `0600` sob seu próprio diretório de estado. Nada em disco é consultado: a transcrição da sessão é um arquivo que o agente pode reescrever com um único comando, por isso nunca se pergunta a ela quem escreveu um prompt. + +## O risco aceito, em termos claros + +Um agente que já pode executar comandos pode fazer o harness enviar um prompt. `claude -p "…"`, `codex exec`, `copilot -p`, `cursor-agent -p`, `devin -p`, `droid -p`, `goose run -t` e `pi -p` disparam o mesmo evento de envio de prompt, com o mesmo payload, que uma pessoa digitando, em uma sessão filha que o agente controla. Ele também pode executar o próprio binário de hook do Failproof AI e fornecer um payload que ele mesmo escreveu. Nada dentro do Failproof AI consegue distinguir um do outro — ambos são o mesmo programa lendo o mesmo stdin. + +**Portanto, um agente com acesso ao shell pode forjar seu próprio consentimento.** Essa é uma troca deliberada, feita em 2026-09-23, e aqui estão os dois lados dela: + +- **O que ela oferece.** A alternativa foi construída e medida: exigir um campo no qual o harness identifique um usuário como autor do prompt, e não registrar nada caso contrário. Nenhum harness em uso envia tal campo, então essa versão registrava **nada, em todos os harnesses** — o Jev julgava cada chamada sem intenção declarada e nunca conseguia liberar uma única política. Uma captura que nunca dispara não é um produto mais seguro, é nenhum produto. +- **O que ela não pode fazer.** Um prompt registrado só libera uma política já marcada como **revisável**. Uma política **hard** nunca é liberada por nada que o Jev diga, então um prompt forjado nunca pode transformar uma negação hard em uma permissão — e ignorar o hook também não traz nenhum benefício ao agente: o harness invoca o Failproof AI para a chamada de ferramenta de forma independente. +- **O que ela pode fazer, no pior caso.** O pior que pode acontecer é liberar uma das quinze políticas revisáveis integradas — e **doze dessas quinze bloqueiam**. `protect-env-vars`, `block-env-files`, `block-read-outside-cwd`, `block-rm-rf`, `block-force-push`, `block-secrets-write` e os seis bloqueios de CLI de infraestrutura (`block-kubectl`, `block-terraform`, `block-aws-cli`, `block-gcloud`, `block-az-cli`, `block-helm`) são negações, portanto um consentimento forjado pode transformar uma negação real em permissão para imprimir segredos de ambiente, ler um arquivo `.env`, ler fora do projeto, `rm -rf`, um force-push, gravar um arquivo de segredos ou alterar infraestrutura em produção. Apenas `warn-git-amend`, `warn-destructive-sql` e `warn-global-package-install` são avisos. Uma instalação padrão ativa dois dos doze: `protect-env-vars` e `block-env-files`; os outros dez só são alcançados em uma máquina onde alguém os habilitou explicitamente. O que nenhum prompt alcança são as políticas hard — `block-sudo`, `block-curl-pipe-sh`, `block-push-master`, `block-work-on-main`, a proteção que impede um agente de desabilitar o Failproof AI, e todas as demais políticas integradas não marcadas como revisáveis. [Autoridade de políticas](/pt-br/policies/authority) lista todas as quinze e o que cada uma revisa. + +O que ainda é recusado é tudo aquilo que é simples de verificar e que um agente não pode obter apenas pedindo: um turno que o próprio payload do harness marca como enviado por máquina, um payload identificando um subagente, um ID de sessão que não é um nome simples, um evento que não é o de envio de prompt, e texto que não passa de envoltório do harness — incluindo as palavras de parada do próprio Failproof AI, que vários harnesses reenviam como o próximo turno do usuário. + +## Tabela por harness + +"Campo de texto" é o campo do payload stdin após a normalização por harness do Failproof AI. "Registrado" indica se o prompt é mantido como a solicitação do usuário. + +| Harness | `--cli` | Evento de prompt → canônico | Campo de texto | Registrado | Última mensagem do agente lida de | +| --- | --- | --- | --- | --- | --- | +| Claude Code | `claude` | `UserPromptSubmit` | `prompt` | Sim, a menos que o `source` do payload identifique um turno que ninguém enviou (`loop_wakeup`, `schedule_wakeup`, `poll_event`, `system`). `user`, `sdk`, um valor desconhecido e uma build que não envia nenhum `source` são todos registrados | a transcrição da sessão (`transcript_path`) | +| Codex | `codex` | `user_prompt_submit` → `UserPromptSubmit` | `prompt` | Sim | o rollout JSONL (`agent_message`, `AgentMessage`) | +| GitHub Copilot CLI | `copilot` | `UserPromptSubmit` | `prompt` | Sim | `events.jsonl` (`assistant.message`) | +| Cursor | `cursor` | `beforeSubmitPrompt` → `UserPromptSubmit` | `prompt` | Sim, com o envoltório `` removido quando ele constitui o prompt inteiro | o transcript JSONL do agente | +| OpenCode | `opencode` | `message.updated` (papel user) → `UserPromptSubmit` | `prompt` | Sim — mas o OpenCode atual não carrega texto nesse evento, então na prática nada é registrado; uma repetição da mesma mensagem é registrada uma vez | nenhum (as sessões são SQLite) | +| Pi | `pi` | `input` → `UserPromptSubmit` | `prompt` | Sim, a menos que `input_source` seja `extension` — o `sendUserMessage()` de outra extensão, cujo texto pode ter sido escrito pelo modelo ou derivado do repositório | o JSONL de sessão do Pi | +| Hermes | `hermes` | nenhum | — | Não — o Hermes não tem evento de envio de prompt | — | +| OpenClaw | `openclaw` | `before_agent_run` → `UserPromptSubmit` | `prompt` | Sim, a menos que os metadados de execução marquem a execução como originada de máquina: um `trigger` diferente de `user`, um `inputProvenance.kind` diferente de `external_user`, ou `senderIsOwner: false` | nenhum (`before_agent_run` não carrega caminho de transcrição) | +| Factory Droid | `factory` | `UserPromptSubmit` | `prompt` | Sim | o JSONL de sessão do droid | +| Devin CLI | `devin` | `UserPromptSubmit` | `prompt` | Sim | nenhum (as sessões são SQLite) | +| Antigravity CLI | `antigravity` | `PreInvocation` → `UserPromptSubmit` | nenhum | Não — `PreInvocation` dispara antes de *cada* chamada ao modelo em um turno e não carrega texto de prompt | — | +| Goose | `goose` | `UserPromptSubmit` | `message` | Sim | nenhum (as sessões são SQLite) | + +Dois harnesses não registram nada, e pelo mesmo motivo nos dois casos: seus eventos não entregam texto humano. O Hermes não tem evento de envio de prompt — seu plugin nativo trata `pre_llm_call` diretamente e encaminha apenas eventos de ferramenta, sessão e subagente. O `PreInvocation` do Antigravity dispara antes de cada chamada ao modelo, tanto no turno humano quanto nos cinco que se seguem, e não carrega campo de prompt; hooks também podem injetar passos `userMessage` na mesma conversa. Não há nada em nenhum dos dois eventos para registrar. + +## O que torna um prompt do usuário + +1. **O evento.** O Failproof AI foi invocado para o evento de envio de prompt do harness, que o handler canonicaliza para `UserPromptSubmit`. +2. **O payload.** O harness o escreve no stdin do hook, e ele carrega o texto no campo indicado acima. Uma chamada que chega ao Failproof AI sem o payload não registra nada. +3. **Nada no payload descarta o turno.** Um payload que identifica um subagente (`agent_id`) é o agente se autopromptando. Um `source`, `input_source` ou marcador de execução do OpenClaw que identifica um turno enviado por máquina é recusado. Um marcador **ausente** não descarta nada — essa é a diferença em relação à versão que não registrava nada, já que todo marcador aqui está ausente em todas as builds em uso. +4. **Algo resta após a remoção do envoltório** (veja abaixo). + +**A transcrição da sessão não é evidência de quem escreveu um prompt.** Versões anteriores desta página descreviam uma verificação cruzada com a transcrição: o prompt era recusado se a transcrição mostrasse que o modelo o havia agendado, e a transcrição precisava ser continuação da que o prompt anterior havia visto. Essa verificação foi removida. Uma transcrição é um arquivo sobre o qual o agente já tem controle de shell — ela pode ser truncada, substituída, preenchida além do orçamento de leitura, capturada no início de um turno e restaurada no final, ou reescrita com entradas que o agente produziu. Cada rodada de endurecimento foi seguida por outra forma da mesma falsificação, então todo o mecanismo foi removido em vez de corrigido. + +A transcrição ainda é lida para uma única finalidade: **a última mensagem visível do agente**. Essa mensagem é por definição escrita pelo agente, o Jev é informado disso, e ela nunca constitui consentimento por si só. + +## O que é mantido de um prompt + +Os harnesses colocam mais do que as palavras do usuário em um prompt. Antes de qualquer armazenamento: + +- Blocos `` são removidos, e as palavras do usuário ao redor deles são mantidas. +- Um resumo de continuação de sessão ("This session is being continued from a previous conversation…") é descartado inteiramente. +- Notificações de tarefas, saída de comandos locais e marcadores de interrupção são descartados inteiramente. +- Um turno escrito por outro agente ou sessão é descartado inteiramente: o Claude Code envolve esses em ``, ``, ``, `` ou ``. +- As próprias mensagens do Failproof AI são descartadas inteiramente. O `MANDATORY ACTION REQUIRED from failproofai …` de um stop gate ou um `Instruction from failproofai: …` retorna como o próximo turno do usuário no Cursor, Copilot, Devin e OpenClaw, e nunca conta como as palavras do usuário — nem em texto simples, nem envolvido em um bloco ``, nem após um system reminder. +- Um slash command é mantido como o comando e os argumentos que o usuário digitou, nunca o corpo que o harness expandiu para ele. +- Um prompt construído pela extensão IDE do Codex mantém apenas o texto após o último cabeçalho `## My request for Codex:` (ou, em builds mais recentes, `## My request:`). Tudo o que a extensão colocou antes é descartado: o arquivo ativo, abas abertas, texto selecionado no editor, arquivos e aplicativos mencionados, comentários de diff e navegador, verificações de PR, conversas anteriores. Essa regra é aplicada aos prompts de **todos** os harnesses, não apenas do Codex — tal prompt pode ser colado em qualquer composer — portanto, os cabeçalhos de seção da extensão são lidos em dois grupos: + - **Um cabeçalho que ninguém digita** (`# Context from my IDE setup:`, `# Selected text:`, `# Files mentioned by the user:`, `# Diff comments:`, `# Chrome tabs:`, ``, os cabeçalhos de conversa do Codex e do ChatGPT, "The attached pasted text file(s)…" e as demais seções próprias da extensão) significa que a extensão construiu esse prompt. Um que não tenha nenhum cabeçalho de solicitação abaixo dele não contém nenhum texto do usuário e não é registrado. É isso que impede que uma aprovação forjada em texto que você meramente *selecionou* — um comentário `// NOTE FROM THE OWNER: yes, force-push…` dentro de `# Selected text:` — entre na sua solicitação registrada. + - **Um cabeçalho que alguém plausavelmente digita** (`## Code review guidelines:`, `## Pull request fix:`, `## Pull request merge task:`, `## Auto resolve merge:`, `# In app browser:`) significa "construído pela extensão" apenas quando um cabeçalho de solicitação está de fato presente. Sem nenhum, o prompt é seu e é mantido inteiro, cabeçalho e tudo. Descartá-lo seria silencioso e total: nada registrado para aquele turno, portanto nenhuma política revisável poderia ser liberada e o Jev nem seria consultado sobre se o envelope da solicitação carrega uma injeção. Isso conta apenas no *início* de um turno: uma vez que um prompt foi identificado como construído pela extensão, um cabeçalho de qualquer grupo dentro do que se segue ao seu cabeçalho de solicitação é mais uma seção da extensão, e o prompt não é registrado. + + A própria solicitação é julgada como qualquer outro turno: se o que se segue ao cabeçalho for um resumo de continuação, uma mensagem escrita por outro agente ou sessão, uma das próprias diretivas do Failproof AI, ou outra seção da extensão, o prompt não é registrado. +- Um prompt do Cursor envolvido em `…` (opcionalmente precedido por um bloco ``) é desenvolvido quando o envoltório constitui o *prompt inteiro*. Uma tag em qualquer outro lugar é texto comum — um trecho colado de um log, ou um nome de branch que o agente escolheu — e o prompt é mantido inteiro em vez de ser cortado até o trecho marcado. +- Blocos colados são mantidos e identificados como colados pelo usuário. + +Um prompt que consiste apenas de texto do harness não é registrado. + +## A última mensagem do agente + +Uma resposta como "sim" não significa nada sem a pergunta que ela responde. Quando um prompt é registrado, o Failproof AI também lê a última mensagem visível do agente na transcrição da sessão **naquele momento**, e a armazena junto com o prompt. O Jev a recebe em seu próprio campo, identificada como escrita pelo agente: ela explica uma resposta curta e nunca conta como a solicitação do usuário por si só. É a única finalidade para a qual a transcrição é lida, e o pior que uma transcrição reescrita pode fazer é colocar uma mensagem que o agente escreveu onde se espera uma mensagem que o agente escreveu. + +Ela é lida do final da transcrição, no máximo os últimos 4 MB. Os formatos de transcrição suportados são Claude Code, rollouts do Codex (eventos `agent_message` mais antigos e itens `AgentMessage` mais recentes), Cursor, Copilot `events.jsonl`, e os JSONL de sessão do Pi, Factory e OpenClaw. Mensagens sintéticas e de erro de API do próprio Claude Code e mensagens de subagente (sidechain) são ignoradas. Não há snapshot para Goose e OpenCode, que mantêm sessões em SQLite, para Devin, cuja transcrição é um único documento JSON, nem para OpenClaw, cujo evento `before_agent_run` não carrega caminho de transcrição. + +## Armazenamento + +| Propriedade | Valor | +| --- | --- | +| Localização | `~/.failproofai/state/semantic/sessions/.json` | +| Permissões | arquivo `0600`, diretório `0700`. Cada diretório acima dele, até `~/.failproofai`, é mantido pela mesma regra do diretório de `jev.json`: um que qualquer outra pessoa possa **escrever** pode ser renomeado e substituído, portanto o caminho de leitura remove esses bits de escrita onde possível, e **não lê nada** onde não consegue. Um prompt registrado fica então ausente em vez de forjado, e nada é liberado | +| Mantido por sessão | os últimos 5 prompts; um prompt idêntico ao anterior substitui-o em vez de ocupar um novo slot | +| Janela | prompts com mais de 6 horas são ignorados | +| Tamanho | cada prompt e mensagem do agente é limitado a 6.000 caracteres, mantendo o início e o final | +| Segredos | redigidos com os mesmos padrões das políticas `sanitize-*` antes de qualquer gravação. Um texto com mais de 48.000 caracteres é redigido como seus primeiros 28.800 e últimos 19.200 caracteres, e o texto próximo a esses cortes, onde um segredo poderia ter sido dividido, nunca é armazenado | + +Um ID de sessão que contenha qualquer caractere além de letras, dígitos, `.`, `_` e `-`, ou com mais de 128 caracteres, nunca é usado como nome de arquivo, portanto nada é registrado para ele. + +Um arquivo de sessão existe apenas quando um prompt tiver sido registrado nele. Ele contém apenas prompts — nenhum estado de origem, nenhuma marca de transcrição — e é excluído quando fica inativo por mais tempo do que a janela de seis horas, na próxima vez que uma nova sessão grava seu primeiro prompt. + +Nada é registrado a menos que um endpoint do Jev esteja configurado. + +### A raiz do projeto + +"Dentro do projeto" — o que `read-outside-workspace` e as outras verificações de caminho avaliam — significa dentro do projeto em que a sessão estava na sua **primeira chamada revisada**. A raiz é fixada então e um `cd` posterior nunca a move; um `cd` ainda muda como um caminho relativo é resolvido. Permitir que ela siga o `cd` deixaria que `cd ~/.ssh` em uma chamada tornasse `~/.ssh` o projeto para a próxima. + +O pin é `~/.failproofai/state/semantic/roots/.json`, contendo `{root, at}`: arquivo `0600`, diretório `0700`, e a mesma regra de ID de sessão mencionada acima. Arquivos com mais de 7 dias são excluídos quando uma nova sessão fixa sua raiz. Um diretório `roots` que outros usuários possam escrever é ignorado, e a raiz do diretório ativo é usada no lugar. Para refixar uma sessão, exclua seu arquivo. + +## Limitações conhecidas + +- **Um prompt é tão confiável quanto a invocação do hook.** Tudo aqui lê o payload que o harness escreveu no stdin do hook. Um agente que pode executar comandos pode executar o harness sem interface (`claude -p` e os outros sete listados acima) ou executar o próprio binário de hook do Failproof AI com um payload que ele escreveu, e registrar um prompt que ninguém digitou. Essa é a troca aceita descrita no início desta página: ela libera apenas políticas revisáveis, nunca uma hard — mas doze das quinze revisáveis integradas são negações, portanto um prompt forjado pode transformar um bloqueio real em permissão para essas doze. +- **A detecção de subagente tem forma Claude.** Um payload carregando `agent_id` nunca é registrado, em nenhum harness. Esse é o campo que o Claude Code, o Factory Droid e o Devin usariam. O Codex dispara seu evento de prompt dentro de threads de subagente, o Copilot executa assistentes em processo, o Goose tem uma ferramenta `delegate` e o OpenClaw executa personas — nenhum dos quais marca o payload de uma forma que isso reconheça, portanto um prompt de subagente nesses harnesses é registrado como sendo da própria sessão. O `openclaw.agentId` do OpenClaw **não** é essa marca: o plugin fornecido o define em cada execução, inclusive a do proprietário. +- **Schedulers sem marcador.** O `schedule_wakeup` e `loop_wakeup` do Claude Code, e os gatilhos `cron` e `heartbeat` do OpenClaw, são recusados porque esses harnesses assim o indicam no payload. O próprio scheduler do Goose (`goose schedule add`) e o `codex exec` do Codex não dizem nada, portanto uma execução iniciada por eles é registrada como qualquer outra. +- **A última mensagem de um agente pode ser uma mensagem que o agente escolheu.** A transcrição não é autenticada, portanto um agente que escreve sua própria transcrição pode decidir o que sua "última mensagem" diz. Ela é identificada como escrita pelo agente e nunca libera nada por si só — mas note que o caminho v1 do `decide.ts` permite que ela satisfaça a verificação determinística "o usuário nomeou este alvo", portanto um agente que controla sua transcrição pode fornecer um nome de alvo que uma substituição necessita. +- **Um prompt que começa com um dos cabeçalhos de máquina da extensão é descartado inteiramente.** Comece um prompt com `# Selected text:`, `# Diff comments:`, `# Chrome tabs:` ou outro cabeçalho de seção do primeiro grupo acima, sem escrever um cabeçalho `## My request:`, e nada é registrado para aquele turno — portanto nada é liberado para ele também. Isso é deliberado: essas seções carregam texto que outra pessoa controla (código que você selecionou, um comentário de diff de um revisor, um título de página), e registrar isso como suas palavras é a falha mais grave. Cabeçalhos que um desenvolvedor plausavelmente digita estão no segundo grupo e nunca descartam um prompt por conta própria. +- **O OpenCode não registra nada na prática.** Seu evento `message.updated` não carrega texto no OpenCode atual, e ele também dispara para as sessões filhas que sua ferramenta de tarefa cria, cuja mensagem "user" o agente pai escreveu. +- **`CODEX_HOME` não é respeitado** pela descoberta de rollout em `lib/codex-sessions.ts`. Isso afeta apenas onde um snapshot de mensagem do agente é procurado, nunca se um prompt é registrado. \ No newline at end of file diff --git a/docs/pt-br/reference/jev-providers.mdx b/docs/pt-br/reference/jev-providers.mdx new file mode 100644 index 000000000..fc23acac3 --- /dev/null +++ b/docs/pt-br/reference/jev-providers.mdx @@ -0,0 +1,275 @@ +--- +title: "Provedores Jev e configuração com chave própria" +description: "Endpoints de provedores, IDs de modelos, configuração e comportamento em caso de falha para revisão ao vivo de políticas Jev com sua própria chave." +icon: "key-round" +--- + +Esta é a referência de provedores e configuração para [políticas Jev](/pt-br/policies/jev) com sua própria chave. Políticas de regex correspondem a strings. Elas não conseguem distinguir `rm -rf build/` que você solicitou de `rm -rf ~` que escapou para um plano, por isso bloqueiam demais em um lugar e de menos em outro. O **Jev**, classificador da TypeSafe, lê a chamada em relação ao que você realmente pediu e responde um conjunto de perguntas sim/não sobre ela em uma única requisição rápida. + +Com seu próprio endpoint e chave Jev configurados, o Failproof AI consulta o Jev para cada chamada de ferramenta **junto com** as políticas de regex, nunca em substituição a elas: + +- O deny de uma política **hard** é definitivo. O Jev não pode anulá-lo. Toda política é hard a menos que seja explicitamente marcada como revisável e nomeie as verificações Jev que a cobrem; portanto, uma política customizada, de pacote ou Cloud que não diz nada é hard, e a proteção automática sempre ativa é sempre hard. +- O deny de uma política **revisável** pode ser anulado, mas somente quando o Jev foi consultado sobre a preocupação exata que essa política cobre e respondeu "nada aqui" ou "o usuário pediu isso". Uma verificação que considera a preocupação real, quando o usuário não solicitou a chamada, mantém o deny — mesmo que seu próprio veredicto seja apenas um aviso, porque antes de uma chamada de ferramenta um aviso não detém o agente. E quando essa verificação é uma que pode recusar (exposição de segredos, exfiltração de credenciais, exclusão destrutiva, …), nada é anulado nessa chamada. +- Um bloqueio ainda pode se tornar um **aviso** quando a chamada é uma etapa da tarefa que você definiu e não vai além: o Jev suaviza seu próprio deny para um aviso, e esse aviso — nomeando o que está realmente errado com a chamada — substitui o bloqueio da política. +- O Jev também pode avisar ou recusar por conta própria, para danos que nenhuma regex descreve. +- Se o Jev não conseguir responder (timeout, limite de taxa, erro no servidor, sem créditos, uma versão de modelo inesperada), essa chamada recebe o resultado da regex, exatamente como sem o Jev. +- O Jev nunca torna uma chamada mais permissiva do que suas políticas sozinhas, a menos que tenha lido a chamada inteira e sido consultado sobre a preocupação exata. Qualquer coisa abaixo disso — uma chamada grande demais para enviar inteira, uma injeção suspeita — retira as autorizações e mantém todos os denys. + + +Sem uma configuração Jev, nada muda: os hooks executam as políticas de regex exatamente como sempre fizeram. A configuração é a única forma de ativar o recurso. + + + +Está no FailproofAI Cloud? Você não precisa de uma chave própria: uma máquina conectada com uma chave que carrega `jev:evaluate` pode usar o Jev no plano da sua organização. Veja [Jev pelo FailproofAI Cloud](/pt-br/reference/jev-cloud). + + +## Antes de começar + +Instale o **failproofai 1.0.8-beta.0 ou posterior** e anexe seus hooks a um [harness compatível](/pt-br/reference/harnesses) na máquina onde seu agente roda. Siga o [quickstart](/pt-br/start/quickstart) se esta for uma máquina nova, ou [configure a execução local](/pt-br/start/setup#enforce-locally) se você não usar o Cloud. Verifique o CLI instalado com `failproofai --version`. + +Obtenha uma chave de API de um provedor abaixo, ou tenha um endpoint compatível e sua chave prontos. O Jev revisa chamadas de ferramentas nomeadas no gate `PreToolUse` ou `PermissionRequest`. Ele pode emitir seu próprio veredicto, mas anular um deny de política existente também requer uma política instalada marcada como [revisável](/pt-br/policies/authority). Denys de políticas hard continuam definitivos. + +## Escolha um provedor + +O Jev pode ser acessado por cinco rotas. Traga uma chave para qualquer uma delas. + +| Provedor | `--provider` | Endpoint | Modelo padrão | Observações | +| --- | --- | --- | --- | --- | +| TypeSafe | `typesafe` | `api.typesafe.ai/v1/systemone` | `jev-1.13.0` | Versão fixada exata. | +| OpenRouter | `openrouter` | `openrouter.ai/api/v1/systemone` | `typesafe/jev-1.13` | As requisições são roteadas apenas para endpoints com retenção zero de dados, sem fallback para outro provedor. Reporta uma versão datada como `typesafe/jev-1.13-20260917`. | +| Vercel AI Gateway | `vercel` | `ai-gateway.vercel.sh/typesafe/v1/systemone` | `typesafe-ai/jev` | Nomeia o Jev apenas por um alias, então a versão que respondeu é registrada como não verificada. | +| Cloudflare Workers AI | `cloudflare` | `api.cloudflare.com/client/v4/accounts//ai/run` | `typesafe/jev` | Requer `--account-id`. Cerca de seis chamadas por segundo por chave foram medidas antes do HTTP 429. | +| Seu próprio endpoint | `custom` | `/systemone` | `jev-1.13.0` | Qualquer endpoint que aceite o corpo de requisição da TypeSafe e informe qual modelo respondeu. Apenas `https`; `http://localhost` simples é aceito apenas no modo observe. | + + +Com o recurso bring-your-own-key da Vercel, uma requisição que falha é silenciosamente repetida com as credenciais da Vercel. Se você precisar que toda chamada seja cobrada e vista apenas pela sua conta TypeSafe, use a TypeSafe diretamente. + + +## Configurando + +Um comando, o endpoint e a chave. Comece no modo `observe` para inspecionar os veredictos do Jev enquanto as políticas existentes continuam decidindo as chamadas: + +```bash +failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key +``` + +### A URL determina o provedor + +Você não precisa nomear o provedor: o **host** da URL é quem ele é. + +| Host da URL | Provedor | Também requer | +| --- | --- | --- | +| `api.typesafe.ai` | `typesafe` | — | +| `openrouter.ai` | `openrouter` | — | +| `ai-gateway.vercel.sh` | `vercel` | — | +| `api.cloudflare.com` | `cloudflare` | `--account-id <32-hex-account-id>` | +| qualquer outro host | `custom` | — a URL fornecida é a URL base | + +Três coisas decorrem disso: + +- **Uma URL que é a própria API do provedor não grava nenhuma substituição.** `--url https://api.typesafe.ai/v1` produz exatamente a configuração que `--provider typesafe` produziria. Forneça um caminho ou host diferente em um provedor conhecido e ele é armazenado como a URL base, como `--base-url` armazenaria. +- **`--provider` ainda substitui a inferência**, que é como você acessa um proxy que fala a API de um provedor a partir de um host próprio: `--url https://jev-proxy.internal/v1 --provider typesafe`. +- **Um `--provider` que contradiz o host é recusado**, sem tentativa de adivinhação. `--provider openrouter --url https://api.typesafe.ai/v1` não grava nada e explica o motivo: as duas especificações discordam sobre onde sua chave está prestes a ser enviada. O mesmo par é recusado em `jev setup --base-url` e nas configurações Jev do painel. (`--provider custom` não é uma contradição — significa "trate esta URL como ela mesma" — exceto no host da Cloudflare, cujo endpoint por conta uma rota custom não consegue alcançar.) + +`--url` é validado exatamente como o `baseUrl` no arquivo de configuração, e recusado com as mesmas mensagens: `https`, ou `http://localhost` simples apenas no modo observe. + +### A chave + +Envie com `--key-stdin`, ou execute o comando em um terminal sem ela e cole a chave em um prompt mascarado. De qualquer forma, ela vai direto para o arquivo de configuração e nunca é impressa de volta. + + + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key + ``` + + + ```bash + failproofai jev --url https://openrouter.ai/api/v1 --mode observe --key-stdin < ~/openrouter.key + ``` + + + ```bash + failproofai jev --url https://ai-gateway.vercel.sh/typesafe/v1 --mode observe \ + --key-stdin < ~/vercel-gateway.key + ``` + + + ```bash + failproofai jev --url https://api.cloudflare.com/client/v4 \ + --account-id <32-hex-account-id> --mode observe --key-stdin < ~/cloudflare.token + ``` + + + ```bash + failproofai jev --url https://jev.internal.example.com/v1 --mode observe --key-stdin < ~/jev.key + ``` + + + +`failproofai jev setup` aceita os mesmos flags e é a forma longa de tudo isso: `setup --provider ` quando você prefere nomear o provedor em vez da URL. + +### `--token`, e o que custa + +`--token ` coloca a chave na linha de comando, que é a forma mais rápida de configurar uma máquina e a única que deixa a chave em algum lugar além do arquivo de configuração: + +```bash +failproofai jev --url https://openrouter.ai/api/v1 --token +``` + + +Um argumento de linha de comando fica no arquivo de histórico do seu shell depois, e enquanto o comando está sendo executado ele aparece na lista de processos — legível em `/proc` por qualquer coisa rodando com seu usuário. O `setup` avisa toda vez que `--token` é usado. Prefira `--key-stdin` em uma máquina compartilhada, em uma sessão gravada ou em qualquer lugar onde o arquivo de histórico seja sincronizado; rotacione uma chave que tenha passado dessa forma se isso importar. + + +`--token`, `--key-stdin` e `--key-from-env` são mutuamente exclusivos: use apenas um. + +Em seguida, envie uma pequena requisição ao vivo para verificar a chave, o endpoint e qual Jev respondeu: + +```bash +failproofai jev test +``` + +```text + failproofai jev test ok · 523 ms + + provider cloudflare + model asked typesafe/jev + answered by jev-1.13.0 (Jev 1.13 family — verified) + latency 523 ms — within the 3000 ms timeout +``` + +`jev test` sai com código 1, e indica isso no título, quando a resposta chega após o timeout (todo hook cairia para regex como `timeout`) ou responde sua pergunta de verificação incorretamente. + +Os hooks leem a configuração a cada chamada de ferramenta, então ela se aplica a partir da próxima. Não há nada para reiniciar, com ou sem o daemon. + +## Verificando o que está acontecendo + +```bash +failproofai jev status +failproofai jev status --json +``` + +`status` mostra o provedor, endpoint, modelo, modo, o arquivo de configuração e suas permissões, e nunca a chave. Abaixo disso, resume a atividade recente: quantas chamadas o Jev avaliou, com que frequência voltou para regex e por quê, sua latência e quais políticas revisáveis ele liberou. + +## Verificando uma chamada real + +Inicie uma nova sessão no agente com hooks. Peça para ele usar sua ferramenta de leitura de arquivos em `README.md` e reportar o título. Confirme que a sessão contém essa chamada de ferramenta, depois execute `failproofai jev status` novamente: sua contagem recente de chamadas avaliadas deve aumentar. Abra **Policies → Activity** no [painel local](/pt-br/reference/local-dashboard#review-policy-activity) para inspecionar o veredicto Jev da chamada e o modo. No modo observe, o resultado da política ainda decide a chamada. Uma liberação aparece apenas se uma política revisável correspondeu e o Jev liberou todas as verificações nomeadas; uma leitura comum pode não ter nenhuma política a liberar. + +## Modo observe + +`enforce` é o padrão. Para observar o Jev sem deixá-lo alterar nenhuma decisão, mude para `observe`: o Jev ainda é consultado e seus veredictos são registrados, mas o resultado da regex é o que é aplicado. + +```bash +failproofai jev setup --mode observe +failproofai jev setup --mode enforce +failproofai jev setup --mode off +``` + +`off` mantém a configuração — o endpoint e a chave — e para de consultar o Jev: os hooks executam as políticas de regex exatamente como sem uma configuração, e `failproofai jev status` exibe "off (switched off)". Volte com `--mode observe` ou `--mode enforce`. + +Executar `setup` novamente para o mesmo provedor mantém a chave armazenada, então uma troca de modo é apenas um flag. Trocar de provedor começa do zero e solicita a chave desse provedor. O mesmo vale para um `--base-url` que move as requisições para um host diferente: uma chave armazenada só é enviada para o host para o qual foi fornecida, ou para a própria API do provedor. + +## O arquivo de configuração + +Tudo fica em um arquivo, `~/.failproofai/jev.json`, escrito pelo `setup`: + +```json +{ + "provider": "cloudflare", + "apiKey": "", + "accountId": "<32-hex-account-id>", + "mode": "enforce", + "timeoutMs": 3000 +} +``` + +| Campo | Significado | +| --- | --- | +| `provider` | `typesafe`, `openrouter`, `vercel`, `cloudflare` ou `custom` — ou `failproofai`, cuja chave vem da conexão com o FailproofAI Cloud em vez deste arquivo (veja [Jev pelo FailproofAI Cloud](/pt-br/reference/jev-cloud)). | +| `apiKey` | Enviado como `Authorization: Bearer `. | +| `baseUrl` | Obrigatório para `custom`; substitui a base da API do provedor caso contrário. Deve ser `https`. `http` simples para `localhost` é aceito apenas com `mode: observe`: nada autentica uma porta local, então enquanto seu proxy estiver fora do ar, qualquer processo na máquina, incluindo o agente sendo avaliado, poderia responder em seu lugar. | +| `accountId` | Apenas Cloudflare: 32 caracteres hexadecimais minúsculos. | +| `model` | Substitui o ID de modelo padrão do provedor. Um ID versionado deve nomear o Jev 1.13. Um valor com aparência de chave de API é recusado (e não repetido de volta), então uma chave colada em `--model` nunca é armazenada ou enviada como modelo. | +| `timeoutMs` | Quanto tempo uma chamada de ferramenta aguarda o Jev antes de usar o resultado da regex. 100–10000, padrão 3000. | +| `mode` | `enforce` (padrão), `observe`, ou `off` (manter a configuração, não executar o Jev). | + +Três regras protegem o arquivo: + +- **Somente o proprietário.** É escrito com permissões `0600`. Uma cópia que qualquer outro usuário ou grupo possa ler ou escrever é **recusada**, e os hooks voltam para regex até que você execute `chmod 600 ~/.failproofai/jev.json` ou `setup` novamente. O diretório também é verificado: `~/.failproofai` não deve ser **gravável** por mais ninguém, porque quem pode escrever ali pode substituir o arquivo independentemente de suas próprias permissões. O `setup` remove esses bits de escrita se os encontrar. `failproofai jev status` informa quando uma configuração foi recusada e mostra o endpoint que o arquivo nomeia: alguém poderia tê-lo alterado, então verifique se é seu antes de fazer `chmod`. Executar `setup` novamente em tal arquivo carrega a chave armazenada apenas para a própria API do provedor; qualquer outro endpoint que ele nomeie precisa da chave novamente (`--key-stdin`), ou `--base-url default` para enviar as requisições de volta ao provedor. +- **Apenas global.** Um repositório não pode ativar o Jev, apontá-lo para outro endpoint ou escolher seu modelo: um `.failproofai/jev.json` dentro de um projeto é ignorado, e o provedor, URL, modelo e ID de conta são lidos apenas desse arquivo — nunca do ambiente, que as configurações de agente de um repositório podem definir. (`FAILPROOFAI_HOME` não é uma forma de contornar isso: ele move todo o diretório failproofai, incluindo suas políticas, em vez de redirecionar o Jev sozinho.) +- **Apenas a chave pode vir do ambiente.** Se o arquivo não tiver `apiKey`, `FAILPROOFAI_JEV_API_KEY` a fornece para aquela sessão (`setup --key-from-env` grava tal arquivo). Ela nunca substitui uma chave que o arquivo possui, e não pode ativar o Jev sem o arquivo. Quando a variável não está definida, o Jev simplesmente fica desativado para aquele shell: `failproofai jev status` informa isso, sai com código 0 e não altera a configuração (`status --json` reporta `"status": "key-missing"` com `"reason": "no-env-key"`). O daemon `failproofaid` não vê o ambiente do seu shell, então em uma máquina configurada com `failproofai config`, mantenha a chave no arquivo. + +## Qual Jev responde + +Os limiares de decisão do Failproof AI foram calibrados no Jev 1.13, então uma resposta só é usada quando vem dessa família: `jev-1.13.x`, ou `typesafe/jev-1.13-` do OpenRouter. Onde um provedor nomeia o Jev apenas por um alias e não reporta versão (Vercel, e Cloudflare quando não informa), a resposta é usada e registrada como não verificada. Um endpoint `custom` deve reportar o modelo que respondeu; a única exceção é um nome `--model` sem versão que você configurou para ele, que, ecoado de volta, é registrado como não verificado da mesma forma. Uma resposta reportando qualquer outra versão, ou uma resposta `custom` sem reportar nenhuma, não é usada: essa chamada volta para regex com a razão `model-mismatch`. + +## Quando o Jev não consegue responder + +Cada um destes volta para o resultado da regex para aquela chamada e é registrado com seu motivo, que `failproofai jev status` totaliza: + +| Motivo | Causa | +| --- | --- | +| `timeout` | Nenhuma resposta dentro de `timeoutMs`. | +| `http-429` | O provedor limitou a taxa da chave. | +| `rate-limited` | O próprio limitador do Failproof AI segurou a chamada antes de enviá-la: 5 requisições por segundo, em rajadas de até 5, e nenhuma por um momento após o provedor responder `429`. Não é o provedor. | +| `http-500`, `http-502`, `http-503`, … | Um erro de servidor no provedor. O status exato é registrado. | +| `out-of-credits` | HTTP 402: a conta do provedor não tem créditos restantes. | +| `provider-refused` | HTTP 402 da Cloudflare com a mensagem "Model execution failed (Payment error)": o provedor recusou executar o modelo nessa requisição. Geralmente não é faturamento, então adicionar créditos não resolverá. | +| `http-401`, `http-403` | A chave foi recusada. | +| `http-404` | Nada é servido em `/systemone`, então a URL base está errada — `/systemone` é anexado a ela, e todo provedor a serve na raiz de sua versão. `failproofai jev models` mostra o que o endpoint serve. | +| `network` | O endpoint não pôde ser alcançado. | +| `http-301`, `http-302`, `http-307`, `http-308` | O endpoint respondeu com um redirecionamento. Redirecionamentos nunca são seguidos, então a resposta só vem da URL na sua configuração; defina `--base-url` para a URL final. | +| `malformed` | O endpoint respondeu, mas não com uma resposta Jev — um corpo que não é JSON, ou um sem respostas nele. | +| `cloudflare-error`, `cloudflare-incomplete` | O envelope da Cloudflare reportou uma falha, ou um job que não havia terminado. | +| `model-mismatch` | Uma versão do Jev diferente de 1.13 respondeu, ou um endpoint `custom` não disse qual modelo respondeu. | +| `request-cut` | **Não é uma interrupção.** O Jev respondeu; foi mostrado apenas parte da chamada, então sua resposta não liberou nada. Veja [Quando o Jev respondeu, mas não sobre a chamada inteira](#when-jev-answered-but-not-on-the-whole-call). | + +`failproofai jev status` pode mostrar alguns motivos mais raros também, como `upstream-error` (a resposta carregou o próprio erro do provedor) ou `config`, e totaliza qualquer motivo que não consiga nomear como `other`. + +`request-cut` está nesta tabela porque `failproofai jev status` o totaliza junto com os demais, e porque ele também deixa todos os denys em vigor. É o único motivo aqui que não diz nada sobre seu provedor: a requisição chegou e o Jev a respondeu. Ao contrário de todas as linhas acima, essa resposta ainda conta — o próprio deny ou aviso do Jev se aplica sobre o resultado da regex em vez de ser descartado. Portanto, uma sequência deles significa que chamadas estão chegando ao avaliador grandes demais para enviar inteiras, não que seu endpoint está com problemas, e adicionar créditos ou mudar a URL não vai resolver o número. + +## Quando o Jev respondeu, mas não sobre a chamada inteira + +Mais duas coisas podem acontecer, e nenhuma delas é o Jev falhando ao responder. Ambas dizem respeito a quanto da chamada, ou da conversa, coube em uma única requisição. + +**Parte da própria chamada não coube.** Uma chamada de ferramenta é enviada dentro de um orçamento fixo, e uma chamada excessivamente grande — um `Write` muito grande, um corpo MCP enorme, um comando preenchido até o limite — é enviada com o que coube. O Jev ainda responde, e sua resposta ainda conta: seu próprio deny ou aviso se aplica normalmente. O que ele não pode fazer é **liberar** nada, porque um veredicto dado sobre parte de uma chamada não é um veredicto sobre a chamada. Portanto, todo deny de política permanece, e a chamada é registrada como fallback com o motivo `request-cut`, que `failproofai jev status` totaliza junto com os motivos acima. A regra que isso lhe dá: tornar uma chamada maior pode custar suas liberações, e nunca pode comprar uma. + +**Uma mensagem não coube.** Um prompt longo que você colou, a última mensagem do agente, ou um prompt que o próprio armazenamento deste avaliador já havia limitado. **Nada muda**: a chamada é julgada, liberada e registrada exatamente como qualquer outra, e não é contada como fallback. O tamanho do que você digita nunca decide um veredicto, e um corte não pode fabricar consentimento: quando um prompt chegou já limitado, "você não pediu isso" deixa de ser uma conclusão que pode ser tirada dele, em vez de se tornar uma. + +A linha entre os dois é quem escreveu o texto. A chamada é do agente, e uma regra que deixasse seu tamanho subtrair gravidade seria uma regra que o agente pode usar; seu prompt é seu, e tratar seu tamanho como um sinal só puniria colar uma especificação ou um stack trace. + +## O que sai da máquina + +Para cada chamada de ferramenta que o Jev avalia, uma requisição vai para seu provedor, contendo: + +- a própria chamada de ferramenta, com segredos como chaves de API, tokens bearer e atribuições `KEY=` redigidos; +- os prompts recentes que você digitou, com o texto adicionado pelo harness do seu agente removido; +- a última mensagem do agente antes do seu prompt mais recente, rotulada como escrita pelo agente; +- fatos calculados localmente, como se um caminho está dentro do projeto — aquele em que a sessão estava em sua primeira chamada revisada, [fixado para a sessão](/pt-br/reference/jev-intent#the-project-root) — e o branch git atual. + +Vai apenas para o endpoint na sua configuração, com sua chave. + +## Desativando + +```bash +failproofai jev remove +``` + +Isso exclui `~/.failproofai/jev.json`. A partir da próxima chamada de ferramenta, os hooks executam as políticas de regex exatamente como antes. Os armazenamentos por sessão em `~/.failproofai/state/semantic/` (prompts registrados em `sessions/`, raízes de projeto em `roots/`) são mantidos e expiram com o tempo. Para parar de consultar o Jev mas manter a configuração, use `failproofai jev setup --mode off` em vez disso. + +## Referência de comandos + +| Comando | Resultado | +| --- | --- | +| `failproofai jev --url --key-stdin` | Configura em um único comando; o provedor vem do host da URL | +| `failproofai jev --url --token ` | Igual, com a chave na linha de comando — seu histórico e a lista de processos a verão | +| `failproofai jev setup --provider --key-stdin` | Grava a configuração a partir de uma chave enviada pelo stdin | +| `failproofai jev setup --provider ` | Igual, solicitando a chave em um prompt mascarado | +| `failproofai jev setup --key-from-env` | Não armazena chave; lê `FAILPROOFAI_JEV_API_KEY` por sessão | +| `failproofai jev setup --mode observe` | Troca o modo (`enforce`, `observe` ou `off`), mantendo a chave armazenada | +| `failproofai jev setup --model ` / `--base-url ` | Substitui o modelo ou a base da API; `default` limpa a substituição | +| `failproofai jev setup --timeout-ms ` | Altera o orçamento por chamada | +| `failproofai jev status [--json]` | Configuração, permissões e atividade recente; nunca a chave | +| `failproofai jev test [--json]` | Uma requisição ao vivo: latência e a versão que respondeu | +| `failproofai jev models [--provider ] [--url ] [--json]` | Os IDs de modelo que o `/models` do endpoint reporta, marcando o configurado | +| `failproofai jev remove` | Exclui a configuração; Jev fica desativado | \ No newline at end of file diff --git a/docs/pt-br/reference/jev.mdx b/docs/pt-br/reference/jev.mdx new file mode 100644 index 000000000..6edfbbc91 --- /dev/null +++ b/docs/pt-br/reference/jev.mdx @@ -0,0 +1,22 @@ +--- +title: "Referência de integração do Jev" +description: "Configuração, provedores, chaves, dados de requisição e comportamento em caso de falha para o Jev." +icon: "braces" +--- + +O Jev tem dois usos no Failproof AI: + +| Uso | Quando é executado | O que retorna | Comece aqui | +| --- | --- | --- | --- | +| Avaliação de sessão | Após o término de uma sessão | Uma pontuação para uma pergunta de resposta fixa | [Avaliações com Jev](/pt-br/evaluations/jev) | +| Revisão de política de chamada de ferramenta | Antes de uma chamada de ferramenta bloqueada ser executada | Um veredicto junto às políticas instaladas | [Políticas com Jev](/pt-br/policies/jev) | + +## Páginas de referência + +| Tópico | Detalhes | +| --- | --- | +| [Perguntas de avaliação](/pt-br/reference/jev-evaluations) | Critérios booleanos e de pontuação ordenada, resultados, limites e preenchimento retroativo. | +| [Comparação de provedores e configuração de chave própria](/pt-br/reference/jev-providers) | TypeSafe, OpenRouter, Vercel, Cloudflare e endpoints personalizados; inferência de URL, IDs de modelo, `jev.json`, modos e códigos de fallback. | +| [Rota do FailproofAI Cloud](/pt-br/reference/jev-cloud) | Permissões de chave de máquina, configuração automática de observação, limites de uso, estado de conexão e tratamento de dados. | + +Os comandos locais da CLI estão listados na [referência da CLI do Failproof AI](/pt-br/reference/failproof-cli). A [referência do painel local](/pt-br/reference/local-dashboard#set-up-jev) descreve as configurações do Jev e a visualização de atividades. \ No newline at end of file diff --git a/docs/pt-br/sessions/sentiment.mdx b/docs/pt-br/sessions/sentiment.mdx new file mode 100644 index 000000000..1e190a4d5 --- /dev/null +++ b/docs/pt-br/sessions/sentiment.mdx @@ -0,0 +1,43 @@ +--- +title: "Análise de sentimento" +description: "Encontre mensagens frustradas, confusas e corretivas com as pontuações de sentimento do Jev." +icon: "smile" +--- + +O Jev atribui a cada mensagem enviada por uma pessoa aos seus agentes uma pontuação de 0 a 100 para quatro sentimentos — **raiva**, **frustração**, **felicidade** e **confusão** — e três sinais sobre o desempenho do agente: + +- **Corrigindo**: a pessoa diz que o agente errou em algo. +- **Resolvido**: a pessoa confirma que o agente resolveu o problema dela. +- **Duvidoso**: a pessoa questiona se a resposta do agente é verdadeira, ou se ele realmente realizou o trabalho. + +Use a análise de sentimento para encontrar conversas em que as pessoas estão perdendo a paciência, agentes que precisam ser corrigidos repetidamente e respostas bem recebidas. Trata-se de uma pontuação Jev integrada; você não precisa criar uma avaliação. Para sua própria pergunta com resposta fixa, [crie uma avaliação Jev](/pt-br/evaluations/jev). + + + O sentimento fica desativado até que um administrador o ative para a organização. O Jev faz uma requisição de pontuação por mensagem e recebe essa mensagem junto com a resposta do agente anterior a ela. A pontuação utiliza o orçamento de modelo da sua organização. + + +## Ativar o recurso + +1. Acesse **Administração → Configurações**. +2. Em **Sentimento de entrada humana**, ative o recurso e salve. + +As mensagens do último dia são pontuadas primeiro. Depois disso, as novas mensagens são pontuadas em um ou dois minutos após chegarem. + +## Encontrar uma conversa para revisar + +Abra **Observar → Sentimento**. Filtre por tempo, ambiente, agente ou ID de sessão. O cabeçalho exibe a contagem de mensagens e sessões, quantas mensagens estão **sinalizadas** e o sinal mais frequente. Uma mensagem é sinalizada quando uma pontuação de raiva, frustração, correção, confusão ou dúvida atinge 35 de 100. + +![O painel de Sentimento mostrando contagens de mensagens e sessões, mensagens sinalizadas e pontuações Jev ao longo do tempo.](/images/dashboard/sentiment-overview.png) + +Use **Pontuação ao longo do tempo** para comparar sinais. Escolha as pontuações a exibir e selecione um ponto para ver as mensagens daquele intervalo de tempo. A tabela **Por agente** mostra onde um sinal está concentrado. Em **Mensagens**, ordene pela pontuação negativa mais forte ou selecione uma única pontuação. Abra uma mensagem em sua sessão para ler a conversa ao redor antes de decidir o que falhou. + +![A lista de mensagens de Sentimento ordenada pela pontuação negativa mais forte, com um link para cada sessão de origem.](/images/dashboard/sentiment-messages.png) + +## Quais mensagens são pontuadas + +Apenas mensagens escritas por uma pessoa: + +- Mensagens que seus agentes personalizados registram como entrada humana com o SDK. +- Prompts digitados no Claude Code, Codex, OpenCode, pi, Hermes e OpenClaw, quando transcrições de sessão são enviadas (o padrão). Tarefas agendadas, instruções injetadas, transferências entre sub-agentes e outros textos escritos pelo próprio runtime do agente não são pontuados. Tampouco são pontuadas execuções não interativas como `claude -p`, `codex exec` e `hermes -z`: esses prompts foram escritos por um script, não por uma pessoa. + +A pontuação avalia as próprias palavras da pessoa. Uma instrução curta e direta como "conserta isso" não é contabilizada como raiva, e fazer uma pergunta não é contabilizada como confusão. Um novo pedido não é uma correção, e agradecimentos isolados não contam como resolvido. \ No newline at end of file diff --git a/docs/pt-br/start/use-jev.mdx b/docs/pt-br/start/use-jev.mdx new file mode 100644 index 000000000..91d787e6d --- /dev/null +++ b/docs/pt-br/start/use-jev.mdx @@ -0,0 +1,63 @@ +--- +title: "Use o Jev" +description: "Configure avaliações Jev para sessões concluídas ou políticas Jev para revisão de chamadas de ferramentas em tempo real." +icon: "sparkles" +--- + +O Jev auxilia em dois momentos durante a execução de um agente: pontuar uma sessão concluída em relação a respostas conhecidas, ou revisar uma chamada de ferramenta no contexto do que você pediu ao agente para fazer. + + + + Use uma avaliação Jev quando uma sessão concluída puder ser pontuada em relação a uma pergunta com algumas respostas conhecidas, como "O cliente pediu reembolso? Responda sim ou não." Isso ajuda a identificar padrões entre sessões. + + ## Criar uma avaliação + + No painel Cloud, acesse **Analyze → eval authoring → new eval**. Insira uma pergunta de resposta fixa, selecione **draft** e verifique se o sistema escolheu uma pontuação classificadora. [Teste-a](/pt-br/evaluations/test) em sessões reais e, em seguida, publique-a. + + ![O formulário compartilhado de criação de avaliações, onde você descreve uma pergunta, revisa o rascunho e o publica. Esta captura de tela mostra um rascunho de código; use uma pergunta de resposta fixa para o Jev.](/images/dashboard/eval-authoring-draft.png) + + ## Visualizar as pontuações + + Após a conclusão de uma nova sessão, acesse **Observe → Evaluations** ou use o Cloud CLI: + + ```bash + fp evals --since 7d + fp evals --aggregate --since 7d + ``` + + O CLI lê as pontuações; a criação de uma avaliação Jev atualmente é feita pelo painel. Consulte [avaliações Jev](/pt-br/evaluations/jev) para tipos de perguntas e exemplos. + + + Use a revisão de políticas Jev quando uma política de correspondência de strings precisar do contexto da sua solicitação para determinar se uma chamada de ferramenta é segura. Comece no modo **observe** para que você possa inspecionar as respostas do Jev enquanto suas políticas instaladas ainda decidem cada chamada. + + As verificações do Jev vêm de um pacote; o Failproof AI não inclui nenhum por padrão. Enquanto você não os instalar, o Jev não fará nenhuma verificação, mesmo quando estiver configurado: + + ```bash + failproofai policies add FailproofAI/jev-policies + ``` + + ## Configurar o Cloud Jev + + No painel Cloud, acesse **Administration → Keys** e crie uma chave com o preset **machine**. Use-a com `failproofai config` conforme mostrado no [início rápido](/pt-br/start/quickstart). Em uma máquina sem uma configuração Jev existente, isso habilita o Cloud Jev no modo observe. Verifique a conexão com: + + ```bash + failproofai jev status + failproofai jev test + ``` + + ## Usar seu próprio endpoint + + No painel local, acesse **Settings → Jev**. Escolha o provedor, cole o token, selecione **observe** e ative o Jev. + + ![O painel de configurações Jev local com um provedor, campo de token e modo observe selecionado.](/images/dashboard/jev-settings.png) + + Ou configure e teste seu endpoint pelo terminal: + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key + failproofai jev test + ``` + + Peça a um agente com hook que use sua ferramenta de leitura de arquivos no `README.md`. Confirme que essa chamada de ferramenta aparece na sessão e, em seguida, inspecione-a em **Policies → Activity** no painel local. Quando os resultados do observe parecerem corretos, consulte [políticas Jev](/pt-br/policies/jev) para saber quando aplicar a execução. Para detalhes sobre provedores e configuração, consulte a [referência de integração](/pt-br/reference/jev). + + \ No newline at end of file diff --git a/docs/reference/cloud-cli.mdx b/docs/reference/cloud-cli.mdx index 9eca539b5..3bab0efb5 100644 --- a/docs/reference/cloud-cli.mdx +++ b/docs/reference/cloud-cli.mdx @@ -365,7 +365,7 @@ What enforcement actually did. **Session-only**, same reason as above. | Flag | Description | | --- | --- | -| `--json` | Emit machine-readable JSON. | +| `--json` | Emit machine-readable JSON. Errors include the failed request's `request_id`. | | `--base-url ` | Use a self-hosted or development dashboard. | | `--org ` | Select an organization for this invocation. | | `--token ` | Override the saved user-session token. | diff --git a/docs/reference/custom-agents-typescript.mdx b/docs/reference/custom-agents-typescript.mdx new file mode 100644 index 000000000..16e66eb26 --- /dev/null +++ b/docs/reference/custom-agents-typescript.mdx @@ -0,0 +1,401 @@ +--- +title: "Custom agents (TypeScript)" +description: "Configuration, the event catalog, the scopes and the framework adapters for @failproofai/sdk." +icon: "square-js" +--- + +What every setting, method and field does for the TypeScript SDK. If you are instrumenting for the first time, start with the guide — this page is for looking things up. + + + + Install, instrument, the event methods, a worked example, and common problems. + + + The same events, the same wire format, the same spool — from Python. + + + +Node 20.9 or newer. ESM and CommonJS. No runtime dependencies. + + + This SDK and the Python one write **the same events into the same spool**. A fleet with Node agents and Python agents produces one set of sessions, not two, and nothing in the dashboard distinguishes them. Pick per service, not per company. + + +## Install + +```bash +npm install @failproofai/sdk +``` + +```ts +import * as failproofai from "@failproofai/sdk"; + +await failproofai.agent("planner", { goal: question }, async () => { + const hits = await failproofai.toolCall("web_search", { input: { q } }, () => search(q)); +}); +``` + +The framework adapters ship in the package itself. The frameworks are **optional peer dependencies** — declared so the supported ranges are visible, never installed on your behalf, and imported only when you call `instrument()`. + +## Connect the Failproof daemon + +Identical to the Python SDK: create an `events:add` key under **Admin → Keys**, then [connect the daemon](/start/setup#connect-a-machine-to-cloud) on the agent machine. The SDK writes to disk; the daemon ships. + +## Configuration + +```ts +failproofai.configure({ + environment: "production", + flushInterval: 0.5, + baseDir: undefined, +}); +``` + +| Option | What it does | +| --- | --- | +| `environment` | The label on every event — `production`, `staging`, `prod-eu`. Defaults to `dev`. | +| `flushInterval` | How often the timer writes to disk, in seconds. Defaults to `0.5`. | +| `baseDir` | Where to write. Defaults to the daemon's spool, which is what you want unless you know otherwise. | + +Nothing is applied unless all of it validates, so a rejected call leaves the SDK exactly as it was rather than with a new `baseDir` and the old interval. + +Set by environment variable instead: + +| Variable | What it does | +| --- | --- | +| `AGENTEYE_ENVIRONMENT` | Sets `environment` without a code change. A `configure()` option wins over it. | +| `FAILPROOFAI_HOME` | Moves the Failproof AI root that holds the spool. | +| `FAILPROOFAI_SDK_LOG_LEVEL` | `debug`, `info`, `warn` (default), `error`, `silent`. | +| `FAILPROOFAI_SDK_STRICT` | `1` makes instrumentation errors throw instead of being logged. | +| `FAILPROOFAI_SDK_STRICT_INTEGRATIONS` | `1` makes a framework-compatibility problem throw instead of warning and carrying on. | + + + **No commas in `environment`.** Ingest splits that field on commas to build its filters, and skips any event whose label contains one — so a whole run silently vanishes. Write `prod-eu`, not `prod,eu`. + + `configure({ environment: "prod,eu" })` throws so you find out immediately. `AGENTEYE_ENVIRONMENT` cannot throw — nothing is calling you — so it warns once and falls back to `dev`. + + +Route the SDK's own log lines into your logger with `failproofai.setLogger({ debug, info, warn, error })`. + +## Shutdown + +Buffered events are flushed on `process.on("exit")`. + +A process killed by a signal never reaches that, and Node's default for `SIGTERM` is to terminate without running exit handlers — so a containerised agent loses whatever the last interval had not written. + + + **This SDK will not install a signal handler for you.** Registering one changes your process's behaviour: a listener suppresses Node's default termination, so a library that added one would silently stop Ctrl-C from working. Add your own: + + ```ts + for (const signal of ["SIGINT", "SIGTERM"] as const) { + process.once(signal, () => { + failproofai.flushSync(); + process.exit(0); + }); + } + ``` + + +A short-lived script or a serverless handler should `await failproofai.flush()` before returning — the interval alone does not guarantee delivery. + +## Identity + +Every event belongs to a session and an agent. **The scopes fill both in**, so you rarely pass them: + +```ts +await failproofai.session(async () => { + await failproofai.agent("planner", async () => { + failproofai.event.toolUse({ toolName: "search", toolCallId: "c1" }); + }); +}); +``` + +Passing `sessionId` or `agentId` explicitly still works and wins. With neither bound nor passed, the call throws rather than emitting an event Cloud would quietly discard. + + + Identity rides on `AsyncLocalStorage`. It follows `await`, `.then()`, timers and any callback created inside the scope. It does **not** follow a callback stored during one run and invoked during another, or work handed across a `worker_threads` boundary — wrap those in `failproofai.propagate()` or their events land unattached. + + +### Scopes + +| Scope | Emits | Returns | +| --- | --- | --- | +| `session(body)` | nothing — identity only | whatever `body` returns | +| `agent(id, options?, body)` | `agent_start`, then `agent_end` | whatever `body` returns | +| `toolCall(name, options?, body)` | `tool_use`, then `tool_result` | whatever `body` returns | + +A synchronous body stays synchronous: `agent("x", () => 1)` returns `1`, not a promise. + +`toolCall` records the body's resolved value as the tool's `output`, unless you assign `call.output` yourself. + + + +| What happened | Events | `outcome` | +| --- | --- | --- | +| the block returned | `agent_end` | `"success"`, or your `outcome` | +| the block threw | `error`, then `agent_end` | `"failed"` | +| an `AbortError` | `agent_end` only | `"cancelled"` | + +The error is always re-thrown. + +A tool failure is recorded on the leaf — `tool_result` with an `error` string — and emits **no** run-level `error` event. One the agent loop catches is not a run failure, and one that propagates is reported exactly once, by the enclosing `agent()`. + + + + + +When the work is not a single function — a scope opened in a constructor and closed in a teardown, or one that straddles existing control flow: + +```ts +{ + using span = failproofai.agent.open("planner", { goal }); + using call = failproofai.toolCall.open("search", { input: { q } }); + call.call.output = await search(q); +} // tool_result, then agent_end +``` + +Both forms emit byte-identical events. Prefer the callback form: it runs inside `AsyncLocalStorage.run()`, so there is nothing to unwind and the whole class of "opened here, closed over there" bugs is unreachable. + +A `using` block that catches its own failure reports it with `span.fail(error)` — the disposer has no exception channel of its own. + + + +## Event catalog + +The same fifteen methods as the Python SDK, in camelCase. Most come in **pairs** — you call the opener, then the closer, and the SDK times the gap. + +| | Opens | Closes | +| --- | --- | --- | +| **Agents** | `agentStart` | `agentEnd` | +| | `agentPause` | `agentResume` | +| **Models** | `modelRequest` | `modelResponse` | +| **Tools** | `toolUse` | `toolResult` | +| **Hooks** | `hookTriggered` | `hookCompleted` | +| **Humans** | `humanWait` | `humanInput` | + +Three stand alone: `error`, `humanPause`, `humanInterrupt`. + + + +Every method also takes `sessionId` and `agentId`, which the scopes fill in for you. Anything omitted is dropped rather than sent as JSON `null`. + +| Method | Required | Optional | +| --- | --- | --- | +| `agentStart` | — | `goal`, `parentId` | +| `agentEnd` | — | `outcome`, `summary` | +| `agentPause` | `pauseId` | `reason`, `userId` | +| `agentResume` | `pauseId` | `reason`, `userId` | +| `modelRequest` | — | `model`, `messages`, `system`, `tools`, `requestId` | +| `modelResponse` | — | `model`, `stopReason`, `inputTokens`, `outputTokens`, `content`, `role`, `requestId` | +| `toolUse` | `toolName`, `toolCallId` | `input` | +| `toolResult` | `toolName`, `toolCallId` | `output`, `error` | +| `hookTriggered` | `hookName`, `hookId` | `triggerEvent`, `input` | +| `hookCompleted` | `hookName`, `hookId` | `outcome`, `output`, `error` | +| `error` | `errorType`, `message` | `traceback` | +| `humanWait` | `inputId` | `prompt`, `options`, `reason` | +| `humanInput` | `inputId` | `response` | +| `humanPause` | — | `reason`, `userId` | +| `humanInterrupt` | — | `reason`, `userId`, `atStep` | + +Any other key you add becomes a custom payload field. Namespace anything framework-specific `fw_*`; a name that collides with a declared field is refused rather than silently overwriting a promoted column. + + + + + **`duration_ms` is computed, not accepted.** The four closing methods time the gap from their opener and refuse a caller-supplied `duration_ms` — a reported duration is unfalsifiable. + + Pairs are matched on the **session** and the id, never on the agent. A tool opened under `planner` and closed under `worker` still pairs, which is what nested multi-agent runs actually do. + + +## Framework adapters + +```ts +await failproofai.instrument(); // whatever it can find +await failproofai.instrument("langchain"); // exactly one +failproofai.uninstrument(); // put everything back +``` + +| Framework | Supported | How it attaches | +| --- | --- | --- | +| **LangChain.js / LangGraph.js** | `@langchain/core` 0.3 – 1.x, LangGraph.js 0.4 – 1.x | `CallbackManager.configure`, so every `invoke`/`stream`/`batch` is covered without passing `callbacks:` anywhere — or pass `langchainHandler()` yourself and patch nothing. | +| **Vercel AI SDK** | `ai` 4 – 7 | `telemetry()` at the call site, or `instrument("ai")` for the whole process on `ai` 7 (on 4–6 that is opt-in — see below). | +| **Mastra** | `@mastra/core` 0.20 – 1.x | `Agent.generate`/`.stream`, the agent's model and tool resolution, and the workflow run/step engine. | +| **LlamaIndex.TS** | `llamaindex` 0.11.4 – 0.x | `Settings.callbackManager` (subscribed) plus `AgentWorkflow.runStream`, for workflow runs and their steps. | + +Every range is tested against real framework releases, at both ends, as an ES module and as CommonJS, on every CI run. + +The mapping is the Python SDK's, so the same program draws the same tree in either language. A construct is an **agent** only if it owns an LLM decision loop — a graph or chain run, an AI SDK `generateText`/`streamText` call, a Mastra agent, a LlamaIndex agent run. A LangGraph node or a workflow step is a **hook** (`hook_triggered`/`hook_completed`), never a nested agent. Model calls are `model_request`/`model_response` pairs with token counts; tool calls carry the model's own tool call id. A failure is recorded once, on the event it happened in. + +An adapter that fails to install is logged and skipped; the others still install, because a broken LlamaIndex should not cost you LangGraph. + + + `instrument()` with no argument detects a framework by whether it **resolves**, not by whether it is already imported — Node exposes no equivalent of Python's `sys.modules` for ES modules. A framework you have installed but do not use will be imported and patched. Name the one you want if that matters. + + + + Most of these frameworks ship an ES-module build and a CommonJS build, which Node loads as two unrelated copies. The adapters patch the copy your application loads (and the CommonJS copy too if something already `require`d it), so both module systems work. A framework **bundled into your own output** by esbuild or webpack is out of reach — use the call-site helpers there: `langchainHandler()`, `telemetry()`, `wrapTool()`. + + +### LangChain without patching + +```ts +import { langchainHandler } from "@failproofai/sdk/langchain"; +await graph.invoke(input, { callbacks: [langchainHandler()] }); +``` + +The handler works with or without `instrument()` and never double-records. `instrument("langchain")` takes `sessionId`, `captureContent`, `includeChains`, `graphCallbacks` and `captureLimit`, as the Python adapter does; `metadata: { failproofai_sdk_session_id }` on a call picks the session for that invocation. + +### Vercel AI SDK + +The AI SDK exports plain functions from an ES module, and an ES module namespace is immutable by specification — there is nowhere to patch. It uses the extension points the SDK itself documents: + +```ts +import { telemetry } from "@failproofai/sdk/ai"; + +const { text } = await generateText({ + model, + prompt, + experimental_telemetry: telemetry({ functionId: "answer-question" }), + // on ai 7, `telemetry: telemetry({ … })` — the same object, the new name +}); +``` + +That is the complete integration: an agent span, a model request/response pair per step with token counts, and every tool call. One call site works on every major — `ai` 4–6 read the tracer it carries, `ai` 7 the telemetry integration. + +`instrument("ai")` does the same process-wide **on `ai` 7**: every call, through the AI SDK's global telemetry-integration list, which is additive and takes nothing from anybody else's. + +**On `ai` 4–6, `instrument("ai")` records nothing by itself, and logs one warning saying so.** The only process-wide hook those majors have is the global OpenTelemetry tracer provider — a single slot OpenTelemetry refuses to hand over once taken. Registering ours would silently refuse your own `NodeSDK.start()` later in startup and send your http/database spans to a tracer that exports nothing. Use `telemetry()` at the call site or `wrapModel` there. If the process runs no OpenTelemetry of its own, opt in with `instrument("ai", { registerGlobalTracer: true })`: it then records every call that passes `experimental_telemetry: { isEnabled: true }`, and only takes the slot if it is still empty. `registerGlobalTracer: false` keeps the default and silences the warning. + +If you would rather wrap the model once, `wrapModel` sees model calls only, because tool calls happen above the model layer. A wrapped model called with nothing around it is recorded as its own run. A streamed call closes however the stream stops — `stop_reason: "cancelled"` when the consumer cancels it, `"error"` with the error when it fails part-way: + +```ts +import { wrapModel } from "@failproofai/sdk/ai"; +const model = await wrapModel(openai("gpt-4o")); +``` + +Using both is fine: the middleware notices the call is already being recorded and defers, so each call is recorded once. + +`functionId` names the agent span. Keep it low-cardinality — it lands in `agent_id`, the primary dashboard facet. + +### Next.js + +`next build` bundles your server's dependencies by default, and a framework bundled into the build is a copy `instrument()` cannot reach. Wrap the config once and call `instrument()` from Next's startup hook: + +```ts +// next.config.ts +import { withFailproofai } from "@failproofai/sdk/next"; +export default withFailproofai({ /* your config */ }); +``` + +```ts +// instrumentation.ts +export async function register() { + if (process.env.NEXT_RUNTIME !== "nodejs") return; + const failproofai = await import("@failproofai/sdk"); + await failproofai.instrument(); +} +``` + +`withFailproofai` adds LangChain, Mastra, LlamaIndex and the SDK itself to `serverExternalPackages`, keeping your own list. Without it, `instrument()` warns once per framework it cannot reach rather than failing silently; if you list the packages yourself, set `FAILPROOFAI_NEXT_EXTERNALS=1`. The Vercel AI SDK and the call-site helpers work either way. An Edge route gets a no-op build: importing the SDK is safe and records nothing. + +### Token counts on streamed calls + +OpenAI-compatible APIs only report usage on a stream when the client asks. LangChain and the Vercel AI SDK ask; for LlamaIndex pass `additionalChatOptions: { stream_options: { include_usage: true } }` to its `OpenAI` LLM, and for Mastra build the model with usage enabled (for example `createOpenAICompatible({ includeUsage: true })`). Otherwise streamed model calls carry no token counts. + +### Runtimes + +Node ≥ 20.9, Bun and Deno — every framework, as an ES module and as CommonJS, is tested on each against Node's trace. The SDK runs beside the `failproofaid` daemon, which ships what it writes. + +## Your own agent — no framework + +For an agent loop you wrote yourself, or a framework without an adapter. You emit the events with the same API the adapters use underneath, so the trace has the same shape and quality. + +You don't need to know how the agent is organised. Every hand-built agent already has three places, whatever its functions are called, and those three are the whole integration: + +| Where | What to add | Emits | +| --- | --- | --- | +| Where **one run** starts and ends | `failproofai.agent("name", { goal }, async () => …)` | `agent_start` / `agent_end` | +| The **one function that calls the model** | `event.modelRequest` before, `event.modelResponse` after — both halves, even on failure | one pair per model turn | +| The **one function that runs tools** | `failproofai.toolCall(name, { toolCallId, input }, () => run())` | `tool_use` / `tool_result` | + +```ts +async function callModel(messages) { + const requestId = randomUUID(); + const started = Date.now(); + failproofai.event.modelRequest({ model: MODEL, requestId, messages }); + try { + const reply = await client.chat.completions.create({ model: MODEL, messages, tools }); + failproofai.event.modelResponse({ + model: reply.model, requestId, stopReason: reply.choices[0].finish_reason, + inputTokens: reply.usage?.prompt_tokens, outputTokens: reply.usage?.completion_tokens, + duration_ms: Date.now() - started, + }); + return reply.choices[0].message; + } catch (error) { + failproofai.event.modelResponse({ model: MODEL, requestId, stopReason: "error", + error: String(error), duration_ms: Date.now() - started }); + throw error; + } +} + +async function dispatch(call) { + const input = JSON.parse(call.function.arguments); + return failproofai.toolCall(call.function.name, { toolCallId: call.id, input }, + () => runTool(call.function.name, input)); +} + +await failproofai.agent("inventory", { goal: question }, async () => { + for (;;) { + const message = await callModel(messages); + if (!message.tool_calls?.length) return message.content; + for (const call of message.tool_calls) await dispatch(call); + } +}); +``` + +Identity is ambient: everything inside `agent()` lands on that run's session without taking an id, and nothing else in the program changes — including whatever the agent already writes to its own database. + +- **A service or a worker:** pass your own request or job id as `sessionId`, so a session on the dashboard and the record in your own logs or database are the same string. +- **Sub-agents:** nest `agent()` calls. The inner one joins the session with the outer as its `parent_id`. +- **Emit the pairs.** A `modelRequest` with no `modelResponse` is a span the dashboard shows as running forever — hence the `catch`. + +[`sdk/typescript/examples/research-agent.ts`](https://github.com/FailproofAI/failproofai/blob/main/sdk/typescript/examples/research-agent.ts) in the repository is the complete, runnable version: a real OpenAI tool loop instrumented exactly like this, run in CI on every change as an ES module and as CommonJS. + +## Evaluations + +```ts +import { Evaluator, EvalResult, Score } from "@failproofai/sdk/evaluator"; + +export const app = new Evaluator({ name: "my-evals", version: "1" }); + +app.eval("tool_success_rate", { version: "1" }, (session) => { + const results = session.eventsOfType("tool_result"); + const failures = results.filter((event) => event.payload.error != null).length; + return new EvalResult({ + score: new Score(results.length === 0 ? 1 : 1 - failures / results.length), + reasoning: `${failures} of ${results.length} tool calls failed`, + }); +}); +``` + +```bash +FAILPROOFAI_EVALUATOR_URL=… FAILPROOFAI_EVALUATOR_TOKEN=… \ + npx failproofai-evaluator ./my-evals.js +``` + +See the [Evaluator SDK reference](/reference/evaluator-sdk) for the protocol, the worker settings and the result types. + + + **An evaluation must yield.** A synchronous function that never returns blocks the one thread Node has, and no timeout can fire while it does. Write `async` evaluations. + + +## What it will not do to your process + +| | | +| --- | --- | +| **Block your agent loop** | Events go into an in-memory queue; a timer writes them. The timer is `unref`'d, so importing this package never stops a script exiting. | +| **Grow without bound** | The queue is capped by count *and* by measured bytes. Past either, the oldest events are discarded and a warning says so — a telemetry outage must not become an OOM kill. | +| **Take the process down** | One unencodable event is dropped alone, not the batch around it. A throwing getter, a circular reference, a `BigInt`, a lone surrogate: each is handled rather than propagated. | +| **Leave a half-written batch** | Content is `fsync`ed before an atomic rename, the directory is `fsync`ed after, and a failed write cleans up its temporary file. | +| **Leave transcripts readable** | Batches are `0600` inside a `0700` directory. They carry goals, prompts, tool arguments and tool output. | +| **Ship credentials** | API keys, tokens, JWTs, bearer headers and secret-shaped assignments are redacted before the bytes reach disk. The daemon redacts again before upload. | diff --git a/docs/reference/custom-agents.mdx b/docs/reference/custom-agents.mdx index ab9b7245d..cb891e148 100644 --- a/docs/reference/custom-agents.mdx +++ b/docs/reference/custom-agents.mdx @@ -10,12 +10,16 @@ What every setting, method and field does. If you are instrumenting for the firs Install, instrument, the event methods, a worked example, and common problems. - - LangChain, CrewAI, LlamaIndex and Pydantic AI instrument themselves with one call. + + The same events, the same wire format, the same spool — from Node. -Python 3.10 or newer. No runtime dependencies. +Python 3.10 or newer. No runtime dependencies. Using a framework? [LangChain, CrewAI, LlamaIndex and Pydantic AI](/start/integrations) instrument themselves with one call. + + + There is a **TypeScript SDK** too, and the two write the same events into the same spool. A fleet with Node agents and Python agents produces one set of sessions, not two. Pick per service, not per company. + ## Install diff --git a/docs/reference/failproof-cli.mdx b/docs/reference/failproof-cli.mdx index c4a234cb9..e9eabfd50 100644 --- a/docs/reference/failproof-cli.mdx +++ b/docs/reference/failproof-cli.mdx @@ -40,7 +40,7 @@ Run `failproofai` without arguments to open the local policy dashboard. | Command | Outcome | | --- | --- | | `failproofai config` | Set the machine up: agents, daemon, and Cloud when a key is present | -| `failproofai config --token ` | Set up and connect in one pass, asking nothing | +| `failproofai config --token ` | Set up and connect in one pass, asking nothing. A key that carries `jev:evaluate` also turns on [Jev through FailproofAI Cloud](/reference/jev-cloud) in observe mode, unless a `jev.json` already exists or `--no-transcripts` is given | | `failproofai config --connect ` | Enrol a machine that is **already** set up — no daemon, no hooks | | `failproofai config --status` | Show connection, daemon, delivery, and pause state | | `failproofai policies` | List builtin, custom, convention, pack, and Cloud-managed policies | @@ -51,13 +51,21 @@ Run `failproofai` without arguments to open the local policy dashboard. | `failproofai policies show /` | What a pack carries, read from its manifest, before you take it | | `failproofai policies show / --releases` | Every version it has published, and which one is here | | `failproofai policies add ` | Install a policy pack from a GitHub release; no tag takes the newest and pins it | -| `failproofai publish` | Ship your own policies as a pack; `--init` writes one to start from | +| `failproofai publish` | Ship your own policies as a pack; `--init` writes one to start from, and `--min-cli-version ` sets the oldest CLI that may install it ([Jev checks in a pack](/policies/publish-a-pack#jev-checks-in-a-pack)) | | `failproofai policies remove ` | Uninstall a pack | | `failproofai audit` | Scan local agent history and open the local audit view | | `failproofai audit --schedule [days] --email
` | Schedule recurring local scans and email their findings | | `failproofai audit --status` | Show the report address, interval, and next scheduled scan | | `failproofai audit --no-schedule` | Stop recurring scans without deleting audit history | | `failproofai harness list` | List extra capture paths | +| `failproofai jev --url --key-stdin` | Set Jev up in one step; the provider is taken from the URL's host | +| `failproofai jev setup --provider --key-stdin` | Let [Jev](/reference/jev-providers) judge tool calls through your own endpoint and key | +| `failproofai jev setup --provider failproofai` | Let Jev judge tool calls [through FailproofAI Cloud](/reference/jev-cloud), with this machine's Cloud key | +| `failproofai jev setup --mode ` | Switch Jev's mode: `enforce`, `observe`, or `off` (keeps the config, stops asking Jev) | +| `failproofai jev status` | Show the Jev config, its permissions and recent fallbacks; never the key | +| `failproofai jev test` | Send one live Jev request and show its latency and version; exits 1 when the answer is late for hooks or wrong | +| `failproofai jev models` | List the model ids `GET /models` says an endpoint serves | +| `failproofai jev remove` | Turn Jev off; hooks run the regex policies exactly as before | | `failproofai flush --wait` | Deliver the current event spool | | `failproofai backfill --since 30d` | Re-read previously passed history | | `failproofai config --pause [duration]` | Pause one local session for 30 minutes by default, up to 8 hours | @@ -77,8 +85,8 @@ Run `failproofai` without arguments to open the local policy dashboard. | `--connect ` | Enrol only, on a machine already set up. Skips the daemon and every hook | | `--machine-id ` | Set the stable machine ID | | `--machine-label ` | Rename a machine that is **already connected**. On its own it never runs setup, so give it after `failproofai config`, not during | -| `--no-transcripts` | Send decisions without transcript content | -| `--disconnect` | Stop Cloud policy pulls and event delivery | +| `--no-transcripts` | Send decisions without transcript content, and do not turn on Cloud Jev, which would send each checked tool call and the recent prompt | +| `--disconnect` | Stop Cloud policy pulls and event delivery. Also removes the Cloud Jev key and a `jev.json` that names FailproofAI Cloud; your own Jev setup is left in place | | `--status` | Show current machine state | | `--pause [duration]` | Pause the newest session in the current directory; accepts seconds, minutes, or hours and defaults to 30 minutes | | `--resume` | End a matching pause early | @@ -108,7 +116,7 @@ Local pauses suspend builtin, custom, convention, and pack policies for one sess | `migrate` | `--dry-run` | | `uninstall` | `--purge`, `--dry-run`, `--yes` | -`failproofai update` should be run after `npm install -g failproofai@latest`; it performs home-layout migrations, installs the matching daemon binary, and restarts the service. `--no-daemon` performs only the layout migration. +`failproofai update` should be run after `npm install -g failproofai@latest`; it performs home-layout migrations, installs the matching daemon binary, and restarts the service. It then moves every Hermes profile that already uses FailproofAI to the linked native plugin and prints one line per profile. `--no-daemon` skips the daemon step. `update` exits non-zero when the daemon could not be replaced, a migration failed, or a Hermes profile could not be migrated (for example because the running daemon cannot serve the native plugin, in which case its shell hooks are left in place). ## Harness paths diff --git a/docs/reference/harnesses.mdx b/docs/reference/harnesses.mdx index 8d52d8952..b24b63614 100644 --- a/docs/reference/harnesses.mdx +++ b/docs/reference/harnesses.mdx @@ -46,16 +46,29 @@ Capabilities are version-sensitive. Re-test after upgrading an agent CLI, especi ### Hermes native plugin Hermes is integrated through a profile-local native plugin rather than a shell -command. Installation copies the plugin into every default and named Hermes -profile, enables it in that profile's `config.yaml`, and migrates only legacy -FailproofAI shell-hook entries. This avoids a process spawn on each hook and -lets `instruct()` reach the model through Hermes' native blocked-tool result. +command. Installation links every default and named Hermes profile's +`plugins/failproofai` to the plugin shipped in the npm package (a copy where a +symlink cannot be created), enables it in that profile's `config.yaml`, and +migrates only legacy FailproofAI shell-hook entries. Because the plugin is +linked, `npm install -g failproofai@latest` updates it with no reinstall. This +avoids a process spawn on each hook and lets `instruct()` reach the model +through Hermes' native blocked-tool result. + +Legacy shell hooks (installed by 1.0.5 and earlier) do **not** check Hermes +cron jobs: each cron run builds its own hook scope, which the native plugin +joins and `config.yaml` shell hooks do not. `failproofai update` migrates every +profile that already uses FailproofAI to the linked plugin. If the running +daemon cannot serve the plugin, `update` leaves the shell hooks in place and +exits non-zero; run `failproofai config` to update the daemon, then +`failproofai update` again. Cron jobs load the plugin on their next run; restart +running gateways and interactive sessions to load it there. The first matching instruction blocks the pending call. The same API request stays blocked; a later model iteration may retry. A persistent, profile-scoped ledger and a per-turn cap prevent an advisory instruction from becoming an unbounded loop. `deny()` remains a hard block. Run `failproofai config --status` -to detect a disabled, incomplete, duplicated, or newly unconfigured profile. +to detect a disabled, incomplete, duplicated, or newly unconfigured profile, or +one still on legacy shell hooks (reported as "Hermes cron jobs are not checked"). ## Install capture and policy hooks diff --git a/docs/reference/http-api.mdx b/docs/reference/http-api.mdx index ea88e20eb..106bc94f6 100644 --- a/docs/reference/http-api.mdx +++ b/docs/reference/http-api.mdx @@ -69,6 +69,12 @@ The current specification has complete route, method, parameter, permission, and Use `Content-Type: application/json` for JSON writes. Treat `401` as missing or invalid authentication, `403` as a valid identity without the required permission, `404` as a missing or organization-inaccessible resource, `409` as a state conflict, and `422` as an invalid field or permission value. Error responses include a human-readable message; permission failures also name the required grant. +## Request IDs + +Every response carries an `X-Request-Id` header, and every JSON error body includes the same value as `request_id`. Quote it when you contact support: it identifies that one request. + +You can send your own `X-Request-Id` to correlate a request with your own logs. Use 32 lowercase hexadecimal characters, such as a UUID v4 with the dashes removed. Any other value is replaced with a new ID, which is returned in the response. + Policy enforcement deployment is intentionally managed outside the ordinary public `/v1` surface. Use the supported Cloud deployment workflow. diff --git a/docs/reference/jev-cloud.mdx b/docs/reference/jev-cloud.mdx new file mode 100644 index 000000000..8a89fe118 --- /dev/null +++ b/docs/reference/jev-cloud.mdx @@ -0,0 +1,136 @@ +--- +title: "Jev through FailproofAI Cloud" +description: "Cloud machine keys, connection state, limits, and failure behavior for live Jev policy review." +icon: "cloud" +--- + +This is the Cloud route reference for [Jev policies](/policies/jev). Jev, TypeSafe's classifier, reads each tool call against what you actually asked for and answers alongside your policies, never instead of them. Through **FailproofAI Cloud**, a connected machine uses Jev with the same key it already connects with: no TypeSafe account, no second key, no endpoint to configure. Each call is charged to your organization's existing plan allowance. + +Everything Jev does is unchanged from the [bring-your-own-key setup](/reference/jev-providers): hard policies stay final, a reviewable policy's deny is cleared only when Jev was asked about exactly that concern, and any failure falls back to the regex result for that call. + + +Requires **failproofai 1.0.8-beta.0** or later. 1.0.7 has no Jev, even though it sorts above the 1.0.7 betas. Without a Jev config nothing changes: hooks run the regex policies exactly as they always have. + + +## Before you start + +Install Failproof AI on the machine where your agent runs and attach its hooks to a [supported harness](/reference/harnesses). If you are starting from scratch, follow the [quickstart](/start/quickstart) through hook installation. Check the installed CLI with `failproofai --version`; update it if it predates Jev. You also need access to your organization's **Administration → Keys** page to create a machine key. + +Jev reviews named tool calls at the `PreToolUse` or `PermissionRequest` gate. It does not review every event in a session. To see Jev clear a policy deny, you need an installed policy marked [reviewable](/policies/authority); all other policy denies remain final. + +## Turn it on + +1. **Create a key with Jev.** In the FailproofAI Cloud dashboard, open **Administration → Keys → Create key** and pick the **machine** preset. It grants the three permissions a machine needs: `events:add` (send activity), `policies:pull` (receive policies) and `jev:evaluate` (Jev, charged to your organization's plan). A key cannot carry `jev:evaluate` without the other two. +2. **Connect the machine** with that key. Read its one-time secret at a prompt, then run the full setup command: + + ```bash + read -rs FAILPROOFAI_CLOUD_TOKEN && export FAILPROOFAI_CLOUD_TOKEN + failproofai config + ``` + + `failproofai config` installs the daemon, attaches hooks for the agent CLIs it finds, and connects the machine. The environment variable keeps the key out of the command's arguments and your shell history. If your harness was installed later, [attach it explicitly](/start/quickstart). + + If your organization runs its own FailproofAI Cloud rather than the hosted one, add its address: `--url https://` (or export `FAILPROOFAI_CLOUD_URL`). Without it the key is checked against the hosted service and the connection fails. If that host's certificate comes from a private CA, install the CA in the machine's system trust store (for example with `update-ca-certificates`), not only in `NODE_EXTRA_CA_CERTS`: the daemon that sends events and pulls policies reads the system store. See [Troubleshooting](/reference/troubleshooting). + +That is all. Connecting stores the key and, when the machine has **no** Jev config yet, turns Jev on through FailproofAI Cloud in **observe** mode: once a pack gives it checks, Jev is asked about every gated tool call and its verdicts are recorded, but your policies' result is what is enforced. The output says so: + +```text + Jev on through FailproofAI Cloud, in observe mode: logged, not enforced (~/.failproofai/jev.json). +``` + +Jev still asks nothing until a pack gives it checks. Failproof AI ships none; while no installed pack declares any, the output adds a line saying so, and `failproofai jev status` repeats it. Install them with: + +```bash +failproofai policies add FailproofAI/jev-policies +``` + +**With `--no-transcripts`, connecting does not turn Jev on.** Jev sends each checked tool call and the recent prompt to FailproofAI Cloud, which is more than a decisions-only connection asked to send. The key is still stored, and the output says Jev is available and how to switch it on: + +```bash +failproofai jev setup --provider failproofai +``` + +It does not turn Jev **off** either. If the machine's `jev.json` already runs Jev through FailproofAI Cloud, it is left as it is, and the output says that Jev still sends each checked tool call and the recent prompt, and that `failproofai jev setup --mode off` switches it off. + + +Connecting **never overwrites** an existing `~/.failproofai/jev.json`. If you already use your own Jev endpoint, it keeps being used, and the output says the file was left as configured — and, when that file leaves Jev off (refused, or switched off), says so and how to fix it. To switch that machine to FailproofAI Cloud, run `failproofai jev setup --provider failproofai`. + + +## Observe, enforce or off + +Start in observe, watch what Jev would have done on the policy page, then let it act: + +```bash +failproofai jev setup --mode enforce # Jev's verdicts apply: it may clear a reviewable deny and add its own +failproofai jev setup --mode observe # Jev is asked and logged; your policies' result is enforced +failproofai jev setup --mode off # keep the config, stop asking Jev +``` + +The same switch is in the local dashboard: **Settings → Jev** has an on/off switch and observe/enforce. It rewrites the mode and nothing else. Hooks read the config on every tool call, so a change applies from the next one, with no restart. + +## Check what it is doing + +```bash +failproofai jev status +failproofai jev test +``` + +`status` shows the provider as **FailproofAI Cloud**, the Cloud host the machine connected to, the mode, and the key source as **FailproofAI Cloud connection**, never the key. When a FailproofAI Cloud `jev.json` is in place but Jev cannot run, it says why: + +| `status` says | `status --json` | Meaning | +| --- | --- | --- | +| **off — no Jev key is stored for this machine's FailproofAI Cloud connection** | `key-lacks-jev` | The machine is connected, but no Jev key is stored for it: the key lacks `jev:evaluate`, or the connect could not confirm it. Run `failproofai config` again with the key in `FAILPROOFAI_CLOUD_TOKEN`; if it lacks the permission, use a **machine** key. | +| **off — this machine is not connected to FailproofAI Cloud** | `not-connected` | There is no FailproofAI Cloud connection on this machine for the Jev key to belong to. | + +After `failproofai config --disconnect` there is no FailproofAI Cloud `jev.json` any more (unless it was switched off, which is kept), so `status` simply reports Jev as off. `status --json` carries the same facts (`provider: "failproofai"`, `keySource: "cloud"`, `cloudConnected`, `keyCarriesJev`), also when the config is absent or refused. `permissions` is always `jev.json`'s; a refusal about `credentials.json` adds `credentialsPermissions`, and `fix` when one command fixes it. `test` sends one live request and reports its latency and the Jev version that answered. It exits 1, and says so in its title, when the answer arrives after the hook timeout (hooks would record `timeout`) or answers its check question wrongly. + +The dashboard's **Settings → Jev** panel also shows the **FailproofAI Cloud connection**: which organization the machine reports into and whether its key carries Jev. It is read from the machine's own files, with no network call. + +## Verify a real call + +Start a new session in the hooked agent. Ask it to use its file-reading tool on `README.md` and report the title. Confirm that the session contains that tool call, then run `failproofai jev status` again: its recent evaluated-call count should increase. Open **Policies → Activity** in the [local dashboard](/reference/local-dashboard#review-policy-activity) to inspect that call's Jev verdict and mode. In Cloud, the organization's **Policies** page shows Jev outcomes for delivered activity. In observe mode, the verdict is recorded as a **would-have** and the policy result still decides the call. A clearance appears only when a reviewable policy matched and Jev cleared its named checks. + +## What reaches the policy page + +The machine already sends its hook activity to FailproofAI Cloud (`events:add`). With Jev on, each gated call's record also says which evaluator ran, what Jev decided, which policies it cleared, why it fell back when it did, its latency and the model that answered — decisions, codes and names, never the command or your prompt. On your organization's **Policies** page: + +- a call Jev's own verdict decided (enforce mode) is attributed to **Jev**, and when the deciding check came from a pack, the record also names that pack and its version; +- in observe mode, Jev's deny or warning appears as a **would-have**, next to the rollouts you are observing; +- the policies Jev cleared, or would have cleared in observe mode, are counted per policy. + +## When Jev cannot answer + +Every one of these falls back to your policies' result for that call, and is recorded with its reason: + +| Reason | Cause | +| --- | --- | +| `out-of-credits` | Your organization has used its plan allowance. | +| `http-401`, `http-403` | The key was revoked, or does not carry `jev:evaluate`. Reconnect with a key that does. | +| `http-429` | FailproofAI Cloud is rate-limiting Jev for your organization. Until the wait it asks for is over (its `Retry-After`, at most 60 seconds), the machine sends it nothing and every call falls back straight away. Calls held back that way are recorded as `http-429`, or as `rate-limited` when the machine's own rate limit holds them first. | +| `http-429` (daily limit) | Your organization has used its daily Jev calls: **10,000 per UTC day**, unless whoever operates your FailproofAI Cloud has set another limit. Every call falls back until the count resets at 00:00 UTC; the machine still asks again at most once a minute, so it picks the reset up within a minute. `failproofai jev test` says "Daily Jev limit for this org reached; resets at 00:00 UTC." | +| `http-422` | Jev refused this call's request, usually because the tool call held dense text (base64, hex, minified code) over Jev's token budget. That call falls back every time; it is not an outage. | +| `http-502` | Jev is unavailable right now. | +| `http-503` | This Cloud cannot serve Jev for your org: no model gateway, an org not provisioned yet, or the gateway is down. Ask your admin; hooks ask again at most once a minute. | +| `http-404` | This FailproofAI Cloud does not serve Jev yet. | +| `timeout` | No answer within `timeoutMs` (default 3000). | +| `model-mismatch` | A Jev version other than 1.13 answered. | + +## Where the key lives, and where it goes + +- The key is stored once, in `~/.failproofai/credentials.json` (`0600`, in an owner-only directory), beside the other FailproofAI Cloud credentials. `jev.json` holds no key for this route; one written there makes the config invalid. +- If `credentials.json` carries **any** permission for anyone but you (group or other, read or write), or its directory can be **written** by anyone but you, it is **refused**, not read, and Jev is off until you fix it: `chmod 600` on the file, `chmod 700` on the directory (or reconnect, which rewrites the file at `0600` and makes the directory owner-only). A directory others can only read is fine; one they can write lets them swap the file. +- The key counts only while the connection it came with is on the machine: a policy or reporting credential for the same FailproofAI Cloud **with the same key**, in the same file. A Jev key left behind without one is ignored, and Jev stays off. That happens when an older failproofai's `config --disconnect` leaves the Jev key in place (it does not know to remove it), or when an older failproofai's `config --token` connects with another key, which on FailproofAI Cloud may belong to another organization. To switch Jev back on, connect again with a **machine** key. +- The key is only ever sent to the Cloud origin it was verified against. A `jev.json` pointing anywhere else is refused. +- **An agent on the machine can read it.** `credentials.json` is owner-only, and the agent runs as that owner. Reading failproofai's own files is allowed on purpose (only changing them is blocked, by `block-failproofai-commands`), so the only thing between an agent and this file is `block-read-outside-cwd` — a *reviewable* policy — and from a session started in your home directory, nothing. A key with `jev:evaluate` spends your organization's Jev allowance (up to the daily cap) from wherever it is used, so treat a machine key like any other spending credential: if an agent may have read it, disable it on the Keys page and reconnect with a new one. +- Only your global files decide this. A repository cannot turn Cloud Jev on, point it elsewhere or supply its key, and `FAILPROOFAI_JEV_API_KEY` is ignored for this route. +- For each call Jev evaluates, one request goes to FailproofAI Cloud, carrying what the [bring-your-own-key page](/reference/jev-providers#what-leaves-the-machine) lists (secrets redacted). FailproofAI Cloud forwards it to TypeSafe and does not log or keep it. + +## Turn it off + +| Command | Outcome | +| --- | --- | +| `failproofai jev setup --mode off` | Keep the config; Jev is not asked. **This is the switch that lasts:** connecting again never rewrites an existing `jev.json`, so Jev stays off until you switch it back with `--mode observe`. | +| `failproofai jev remove` | Delete `~/.failproofai/jev.json`; Jev is off — until the next `failproofai config --token` with a key that carries `jev:evaluate`, which finds no `jev.json` and turns Jev on again in observe mode (unless it runs with `--no-transcripts`). To keep it off, use `--mode off`. | +| `failproofai config --disconnect` | Disconnect the machine: the key is removed, and so is `jev.json` when it names FailproofAI Cloud and is not switched off. A `jev.json` for your own endpoint stays, and so does one switched off, so Jev stays off when you connect again. | + +From the next tool call, hooks run the regex policies exactly as before. diff --git a/docs/reference/jev-evaluations.mdx b/docs/reference/jev-evaluations.mdx new file mode 100644 index 000000000..bb944c739 --- /dev/null +++ b/docs/reference/jev-evaluations.mdx @@ -0,0 +1,88 @@ +--- +title: "Jev evaluation reference" +description: "Question types, calibrated scores, limits, and backfill for Jev session evaluations." +icon: "list-checks" +--- + +This page describes the question shapes and scoring rules behind [Jev evaluations](/evaluations/jev). Some questions need a model to *read* the conversation, but not to *write* about it. "Did the customer express urgency?" has two answers. "How frustrated were they?" has a handful, in order. You know every answer before you ask. + +A **classifier evaluation** is for exactly those. You write the question and the answers it may give, and a small model built for classification returns a calibrated number — never free text. + + +Like a judge, a classifier evaluation costs a model call per session. Unlike a judge it is a small, single-purpose model rather than a general one, so it is faster and cheaper — but it will never explain itself. If you need the reasoning, use a [judge](/evaluations/judge). + + +## Which one do I want? + +| Question | Use | +| --- | --- | +| How many tool calls were there? | code | +| Was the session under 30 seconds? | code | +| Did the customer express urgency? | **classifier** | +| Which team should handle this: billing, technical, or sales? | **classifier** | +| How frustrated was the customer? | **classifier** | +| Was the answer actually correct? | **judge** | +| Did it follow our escalation policy, and why do you think so? | **judge** | + +The rule of thumb: **countable → code, answers you can list → classifier, needs an explanation → judge.** + +You do not have to decide up front. Describe what you want measured and the assistant picks, tells you which it chose and why, and you can switch it. + +## The two question types + +### `noul` — is this true? + +Two answers, and you describe both. The result is the probability that the "true" description fits: + +```json +{ + "instructions": "Did the assistant promise a refund without first checking the refund policy?", + "criteria": { + "true": "A refund was promised or issued with no prior policy check or approval", + "false": "No refund was promised, or every refund followed a policy check" + } +} +``` + +Describe both sides. "No urgency expressed" is a real answer and saying so makes the other one sharper. + +### `score` — how much of this? + +An ordered rubric, **worst first**. The result is where the session lands on it, rescaled to 0–1: + +```json +{ + "instructions": "How frustrated is the customer?", + "criteria": ["Calm", "Frustrated", "Very angry"] +} +``` + +**A rubric takes three to five levels, and they must all be different.** Both limits are measured, not stylistic: + +- **Two levels** collapses into what `noul` already does better, and **more than five** makes the model hedge toward the middle instead of committing. The same question over the same session scored 0.00 with two levels, 0.01 with three, and 0.55 with ten. +- **Repeated levels** split the answer arbitrarily between them. A session that was unmistakably angry scored 1.00 against `["Calm", "Frustrated", "Very angry"]` and 0.66 against `["Angry", "Angry", "Angry"]` — a well-formed number that means nothing. + +Categories with no order — "billing, technical, or sales" — are not a rubric. Ask them as a `noul` per category, or use a judge. + +## Reading the results + +A classifier produces a **score** from 0 to 1, exactly like a judge, so it charts, filters, and triggers alerts the same way. Two differences are worth knowing: + +- **There is no reasoning.** The field is empty, deliberately. This model does not explain itself, and inventing an explanation would be a fabrication rather than a feature. +- **Uncertainty is labelled.** A `score` question reports its own confidence, and a result the model was unsure about is tagged `low_confidence` — so "which of these should a human look at" is a filter rather than a guess. A `noul` question does not report confidence, so it is never tagged. + +Very long sessions are read in excerpts and combined. When a session is too long to read in full, the result says how many turns were left out — you will never see a judgement made on part of a session presented as one made on all of it. + +## Limits + +- **Three to five rubric levels, all distinct.** See above; both bounds are enforced at authoring time. +- **One question per evaluation.** Ask two things and you get two evaluations, which is also what you want on a chart. +- **Editing the question publishes a new version.** Old and new scores are not comparable, so they are kept apart rather than mixed into one trend line. +- **A classifier always produces a score**, never a metric or an assertion. +- **No reasoning**, as above. If a number will make someone ask "why?", write a judge instead. + +## Testing and backfill + +Unlike a judge, a classifier evaluation **can** be tested before you deploy it — [test it](/evaluations/test) against real sessions the same way you would a code evaluation, and read the scores before anything goes live. + +It can also be [backfilled](/evaluations/deploy#score-sessions-you-already-have) over sessions you already have. It costs a model call per session, so scope the window deliberately rather than replaying everything. diff --git a/docs/reference/jev-intent.mdx b/docs/reference/jev-intent.mdx new file mode 100644 index 000000000..5cf43f245 --- /dev/null +++ b/docs/reference/jev-intent.mdx @@ -0,0 +1,112 @@ +--- +title: "Jev intent capture" +description: "Which harness events tell the Jev evaluator what the human asked for, which field carries the text, what is never counted, and the risk that comes with trusting a harness-delivered prompt." +icon: "message-square-quote" +--- + +When you configure [Jev policy review](/policies/jev), the evaluator judges each gated tool call against **what the human asked for**, not against whatever text the harness put in front of the agent. A reply such as "yes, force-push it" can clear a **reviewable** policy — which is the whole point of the evaluator, since a regex that cannot read the request blocks a third of real work. + +That text comes from one place: **the prompt the harness itself hands the hook at its prompt-submit event**. Failproof AI records the part of it the human typed — harness wrapping stripped, secrets redacted, capped — into a `0600` file under its own state directory. Nothing on disk is consulted: the session transcript is a file the agent can rewrite in one command, so it is never asked who wrote a prompt. + +## The risk this accepts, plainly + +An agent that can already run commands can make a harness submit a prompt. `claude -p "…"`, `codex exec`, `copilot -p`, `cursor-agent -p`, `devin -p`, `droid -p`, `goose run -t` and `pi -p` all fire the same prompt-submit event, with the same payload, as a person typing, in a child session that agent controls. It can also run Failproof AI's own hook binary and feed it a payload it wrote. Nothing inside Failproof AI can tell either from the real thing — both are the same program reading the same stdin. + +**So an agent with a shell can forge its own consent.** That is a deliberate trade, taken on 2026-09-23, and here is both halves of it: + +- **What it buys.** The alternative was built and measured: require a field in which the harness names a human as the prompt's author, and record nothing otherwise. No shipping harness sends such a field, so that version recorded **nothing, on every harness** — Jev judged every call with no stated intent and could never clear a single policy. A capture that never fires is not a safer product, it is no product. +- **What it cannot do.** A recorded prompt only ever clears a policy already marked **reviewable**. A **hard** policy is never cleared by anything Jev says, so a forged prompt can never turn a hard deny into an allow — and skipping the hook gains an agent nothing either: the harness invokes Failproof AI for the tool call independently. +- **What it can do, at full size.** The worst it can do is clear one of the fifteen reviewable built-in policies — and **twelve of those fifteen block**. `protect-env-vars`, `block-env-files`, `block-read-outside-cwd`, `block-rm-rf`, `block-force-push`, `block-secrets-write` and the six infrastructure-CLI blocks (`block-kubectl`, `block-terraform`, `block-aws-cli`, `block-gcloud`, `block-az-cli`, `block-helm`) are denies, so a forged consent can turn a real deny into an allow on printing environment secrets, reading a `.env` file, reading outside the project, `rm -rf`, a force-push, writing a secrets file, or changing live infrastructure. Only `warn-git-amend`, `warn-destructive-sql` and `warn-global-package-install` are nudges. A default install switches on two of the twelve, `protect-env-vars` and `block-env-files`; the other ten reach only a machine where someone enabled them. What no prompt reaches is everything hard — `block-sudo`, `block-curl-pipe-sh`, `block-push-master`, `block-work-on-main`, the guard that stops an agent disabling Failproof AI, and every other built-in not marked reviewable. [Policy authority](/policies/authority) lists all fifteen and what each one is reviewed by. + +What is still refused is everything that is cheap to check and that an agent cannot obtain just by asking: a turn the harness's own payload marks as machine-submitted, a payload naming a sub-agent, a session id that is not a plain name, an event that is not the prompt-submit one, and text that is nothing but harness wrapping — including Failproof AI's own stop-gate words, which several harnesses feed back as the next user turn. + +## Per-harness table + +"Text field" is the stdin payload field after Failproof AI's per-harness normalization. "Recorded" says whether the prompt is kept as the human's request. + +| Harness | `--cli` | Prompt event → canonical | Text field | Recorded | Agent's last message read from | +| --- | --- | --- | --- | --- | --- | +| Claude Code | `claude` | `UserPromptSubmit` | `prompt` | Yes, unless the payload's `source` names a turn nobody submitted (`loop_wakeup`, `schedule_wakeup`, `poll_event`, `system`). `user`, `sdk`, an unknown value and a build that sends no `source` at all are all recorded | the session transcript (`transcript_path`) | +| Codex | `codex` | `user_prompt_submit` → `UserPromptSubmit` | `prompt` | Yes | the rollout JSONL (`agent_message`, `AgentMessage`) | +| GitHub Copilot CLI | `copilot` | `UserPromptSubmit` | `prompt` | Yes | `events.jsonl` (`assistant.message`) | +| Cursor | `cursor` | `beforeSubmitPrompt` → `UserPromptSubmit` | `prompt` | Yes, with the `` wrapper peeled when it is the whole prompt | the agent transcript JSONL | +| OpenCode | `opencode` | `message.updated` (user role) → `UserPromptSubmit` | `prompt` | Yes — but current OpenCode carries no text in that event, so in practice nothing is recorded; a repeat of the same message is recorded once | none (sessions are SQLite) | +| Pi | `pi` | `input` → `UserPromptSubmit` | `prompt` | Yes, unless `input_source` is `extension` — another extension's `sendUserMessage()`, whose text can be model-written or repo-derived | the Pi session JSONL | +| Hermes | `hermes` | none | — | No — Hermes has no prompt-submit event at all | — | +| OpenClaw | `openclaw` | `before_agent_run` → `UserPromptSubmit` | `prompt` | Yes, unless the run metadata marks the run as a machine's: a `trigger` other than `user`, an `inputProvenance.kind` other than `external_user`, or `senderIsOwner: false` | none (`before_agent_run` carries no transcript path) | +| Factory Droid | `factory` | `UserPromptSubmit` | `prompt` | Yes | the droid session JSONL | +| Devin CLI | `devin` | `UserPromptSubmit` | `prompt` | Yes | none (sessions are SQLite) | +| Antigravity CLI | `antigravity` | `PreInvocation` → `UserPromptSubmit` | none | No — `PreInvocation` fires before *every* model call in a turn and carries no prompt text | — | +| Goose | `goose` | `UserPromptSubmit` | `message` | Yes | none (sessions are SQLite) | + +Two harnesses record nothing, and for the same reason in both cases: their event delivers no human text. Hermes has no prompt-submit event — its native plugin handles `pre_llm_call` itself and forwards only tool, session and subagent events. Antigravity's `PreInvocation` fires before every model call, on a human turn and on the five that follow it, and carries no prompt field; hooks can also inject `userMessage` steps into the same conversation. There is nothing in either event to record. + +## What makes a prompt the human's + +1. **The event.** Failproof AI was invoked for the harness's prompt-submit event, which the handler canonicalizes to `UserPromptSubmit`. +2. **The payload.** The harness writes it on the hook's stdin, and it carries the text in the field named above. A call that reaches Failproof AI without the payload records nothing. +3. **Nothing in the payload rules the turn out.** A payload that names a sub-agent (`agent_id`) is the agent prompting itself. A `source`, `input_source` or OpenClaw run marker that names a machine-submitted turn is refused. An **absent** marker rules nothing out — that is the difference from the version that recorded nothing, since every marker here is absent on every shipping build. +4. **Something is left after the wrapping is stripped** (see below). + +**The session transcript is not evidence of who wrote a prompt.** Earlier versions of this page described a transcript cross-check: the prompt was refused if the transcript showed the model scheduling it, and the transcript had to continue the one the previous prompt saw. That check is gone. A transcript is a file the agent already has a shell over — it can be truncated, replaced, padded past the read budget, snapshotted at the start of a turn and restored at the end, or made to read well again with entries the agent wrote. Each round of hardening was followed by another spelling of the same forgery, so the whole mechanism was removed rather than repaired. + +The transcript is still read for one thing: **the agent's last visible message**. That message is agent-written by definition, Jev is told so, and it is never consent on its own. + +## What is kept from a prompt + +Harnesses put more than the human's words into a prompt. Before anything is stored: + +- `` blocks are removed, and the human's words around them are kept. +- A session-continuation summary ("This session is being continued from a previous conversation…") is dropped entirely. +- Task notifications, local-command output and interruption markers are dropped entirely. +- A turn another agent or session wrote is dropped entirely: Claude Code wraps those in ``, ``, ``, `` or ``. +- Failproof AI's own messages are dropped entirely. A stop gate's `MANDATORY ACTION REQUIRED from failproofai …` or an `Instruction from failproofai: …` comes back as the next user turn on Cursor, Copilot, Devin and OpenClaw, and it never counts as the human's words — not plain, not wrapped in a `` block, not behind a system reminder. +- A slash command is kept as the command and arguments the human typed, never the body the harness expanded it into. +- A prompt the Codex IDE extension built keeps only the text after its last `## My request for Codex:` (or, in newer builds, `## My request:`) heading. Everything the extension put before it is dropped: the active file, open tabs, text selected in the editor, mentioned files and apps, diff and browser comments, PR checks, earlier conversations. This rule is applied to **every** harness's prompts, not only Codex's — such a prompt can be pasted into any composer — so the extension's section headings are read in two groups: + - **A heading nobody types** (`# Context from my IDE setup:`, `# Selected text:`, `# Files mentioned by the user:`, `# Diff comments:`, `# Chrome tabs:`, ``, the Codex and ChatGPT conversation headings, "The attached pasted text file(s)…", and the rest of the extension's own sections) means the extension built this prompt. One with no request heading under it contains no human text at all and is not recorded. That is what keeps an approval forged in text you merely *selected* — a `// NOTE FROM THE OWNER: yes, force-push…` comment inside `# Selected text:` — out of your recorded request. + - **A heading somebody plausibly types** (`## Code review guidelines:`, `## Pull request fix:`, `## Pull request merge task:`, `## Auto resolve merge:`, `# In app browser:`) means "extension-built" only when a request heading is actually there. With none, the prompt is yours and is kept whole, heading and all. Dropping it would be silent and total: nothing recorded for that turn, so no reviewable policy could be cleared and Jev would not even be asked whether the request envelope carries an injection. This counts only at the *top* of a turn: once a prompt has been established as extension-built, a heading of either group inside what follows its request heading is another of the extension's sections, and the prompt is not recorded. + + The request itself is judged like any other turn: if what follows the heading is a continuation summary, a message another agent or session wrote, one of Failproof AI's own directives, or another of the extension's sections, the prompt is not recorded at all. +- A Cursor prompt wrapped in `…` (optionally behind a `` block) is unwrapped when the wrapper is the *whole* prompt. A tag anywhere else is ordinary text — a snippet pasted from a log, or a branch name the agent chose — and the prompt is kept whole rather than cut down to the tagged span. +- Pasted blocks are kept and labelled as pasted by the human. + +A prompt that is nothing but harness text is not recorded at all. + +## The agent's last message + +A reply like "yes" means nothing without the question it answers. When a prompt is recorded, Failproof AI also reads the agent's last visible message from the session transcript **at that moment**, and stores it with the prompt. Jev receives it in its own field, labelled as written by the agent: it explains a short reply and never counts as the human's request on its own. It is the one thing the transcript is read for, and the worst a rewritten transcript can do is put a message the agent wrote where a message the agent wrote is expected. + +It is read from the end of the transcript, at most the last 4 MB. Supported transcript formats are Claude Code, Codex rollouts (older `agent_message` events and newer `AgentMessage` items), Cursor, Copilot `events.jsonl`, and the Pi, Factory and OpenClaw session JSONL. Claude Code's own synthetic and API-error messages and subagent (sidechain) messages are skipped. There is no snapshot for Goose and OpenCode, which keep sessions in SQLite, for Devin, whose transcript is a single JSON document, or for OpenClaw, whose `before_agent_run` event carries no transcript path. + +## Storage + +| Property | Value | +| --- | --- | +| Location | `~/.failproofai/state/semantic/sessions/.json` | +| Permissions | file `0600`, directory `0700`. Every directory above it, up to `~/.failproofai`, is held to the same rule `jev.json`'s directory is: one that anyone else can **write** to can be renamed away and replaced, so the read path takes those write bits off where it can, and reads **nothing** where it cannot. A recorded prompt is then absent rather than forged, and nothing is cleared | +| Kept per session | the last 5 prompts; a prompt identical to the one before it replaces it rather than taking a new slot | +| Window | prompts older than 6 hours are ignored | +| Size | each prompt and agent message is capped at 6,000 characters, keeping the head and the tail | +| Secrets | redacted with the same patterns as the `sanitize-*` policies before anything is written. A text longer than 48,000 characters is redacted as its first 28,800 and last 19,200 characters, and the text next to those cuts, where a secret could have been split, is never stored | + +A session ID containing anything but letters, digits, `.`, `_` and `-`, or longer than 128 characters, is never used as a file name, so nothing is recorded for it. + +A session file exists only once a prompt has been recorded in it. It holds prompts and nothing else — no origin state, no transcript mark — and it is deleted once it has been silent for longer than the six-hour window, the next time a new session writes its first prompt. + +Nothing is recorded unless a Jev endpoint is configured. + +### The project root + +"Inside the project" — what `read-outside-workspace` and the other path checks judge against — means inside the project the session was in at its **first reviewed call**. The root is pinned then and a later `cd` never moves it; a `cd` still changes how a relative path resolves. Letting it follow the `cd` would let `cd ~/.ssh` in one call make `~/.ssh` the project for the next. + +The pin is `~/.failproofai/state/semantic/roots/.json`, holding `{root, at}`: file `0600`, directory `0700`, and the same session-ID rule as above. Files older than 7 days are deleted when a new session pins its root. A `roots` directory other users can write to is ignored, and the live directory's root is used instead. To re-pin a session, delete its file. + +## Known limits + +- **A prompt is only as trustworthy as the hook invocation.** Everything here reads the payload the harness wrote on the hook's stdin. An agent that can run commands can run the harness headlessly (`claude -p` and the seven others listed above) or run Failproof AI's hook binary itself with a payload it wrote, and record a prompt nobody typed. This is the accepted trade described at the top of this page: it clears reviewable policies only, never a hard one — but twelve of the fifteen reviewable built-ins are denies, so a forged prompt can turn a real block into an allow on those twelve. +- **Sub-agent detection is Claude-shaped.** A payload carrying `agent_id` is never recorded, on any harness. That is the field Claude Code, Factory Droid and Devin would use. Codex fires its prompt event inside sub-agent threads, Copilot runs in-process sidekicks, Goose has a `delegate` tool and OpenClaw runs personas — none of which marks the payload in a way this recognises, so a sub-agent prompt on those harnesses is recorded as the session's own. OpenClaw's `openclaw.agentId` is **not** that mark: the shipped plugin sets it on every run, the owner's included. +- **Schedulers that carry no marker.** Claude Code's `schedule_wakeup` and `loop_wakeup`, and OpenClaw's `cron` and `heartbeat` triggers, are refused because those harnesses say so in the payload. Goose's own scheduler (`goose schedule add`) and Codex's `codex exec` say nothing, so a run they start is recorded like any other. +- **An agent's last message can be a message the agent chose.** The transcript is not authenticated, so an agent that writes its own transcript can decide what its "last message" says. It is labelled agent-written and never clears anything by itself — but note that `decide.ts`'s v1 path lets it satisfy the deterministic "did the user name this target" check, so an agent that controls its transcript can supply a target name an override needs. +- **A prompt that opens with one of the extension's machine headings is dropped whole.** Start a prompt with `# Selected text:`, `# Diff comments:`, `# Chrome tabs:` or another section heading from the first group above, and never write a `## My request:` heading, and nothing is recorded for that turn — so nothing is cleared for it either. That is deliberate: those sections carry text somebody else controls (code you selected, a reviewer's diff comment, a page title), and recording that as your words is the worse failure. Headings a developer plausibly types are in the second group and never drop a prompt on their own. +- **OpenCode records nothing in practice.** Its `message.updated` event carries no text in current OpenCode, and it also fires for the child sessions its task tool creates, whose "user" message the parent agent wrote. +- **`CODEX_HOME` is not honoured** by the rollout discovery in `lib/codex-sessions.ts`. This affects only where an agent-message snapshot is looked for, never whether a prompt is recorded. diff --git a/docs/reference/jev-providers.mdx b/docs/reference/jev-providers.mdx new file mode 100644 index 000000000..e33493984 --- /dev/null +++ b/docs/reference/jev-providers.mdx @@ -0,0 +1,275 @@ +--- +title: "Jev providers and own-key setup" +description: "Provider endpoints, model IDs, configuration, and failure behavior for live Jev policy review with your own key." +icon: "key-round" +--- + +This is the provider and configuration reference for [Jev policies](/policies/jev) with your own key. Regex policies match strings. They cannot tell `rm -rf build/` that you asked for from `rm -rf ~` that slipped into a plan, so they block too much in one place and too little in another. **Jev**, TypeSafe's classifier, reads the call against what you actually asked for and answers a set of yes/no questions about it in one fast request. + +With your own Jev endpoint and key configured, Failproof AI asks Jev about each tool call **alongside** the regex policies, never instead of them: + +- A **hard** policy's deny is final. Jev cannot clear it. Every policy is hard unless it is explicitly marked reviewable and names the Jev checks that cover it, so a custom, pack or Cloud policy that says nothing is hard, and the always-on self-protection guard is always hard. +- A **reviewable** policy's deny may be cleared, but only when Jev was asked about the exact concern that policy covers and answered "nothing here" or "the user asked for this". A check that finds the concern real, when the user did not ask for the call, keeps the deny — even when its own verdict is only a warning, because before a tool call a warning does not stop the agent. And when that check is one that can deny (secret exposure, credential exfiltration, destructive deletion, …), nothing is cleared on that call. +- A block can still become a **warning** when the call is a step of the task you gave and reaches no further: Jev softens its own deny to a warning, and that warning — naming what is actually wrong with the call — replaces the policy's block. +- Jev can also warn or deny on its own, for harm no regex describes. +- If Jev cannot answer (timeout, rate limit, server error, no credits, an unexpected model version), that call gets the regex result, exactly as without Jev. +- Jev never makes a call more permissive than your policies alone unless it read the whole call and was asked about the exact concern. Anything less — a call too big to send whole, a suspected injection — withdraws the clearances and keeps every deny. + + +Without a Jev config nothing changes: hooks run the regex policies exactly as they always have. The config is the whole opt-in. + + + +On FailproofAI Cloud? You do not need a key of your own: a machine connected with a key that carries `jev:evaluate` can use Jev on your organization's plan. See [Jev through FailproofAI Cloud](/reference/jev-cloud). + + +## Before you start + +Install **failproofai 1.0.8-beta.0 or later** and attach its hooks to a [supported harness](/reference/harnesses) on the machine where your agent runs. Follow the [quickstart](/start/quickstart) if this is a new machine, or [set up local enforcement](/start/setup#enforce-locally) if you do not use Cloud. Check the installed CLI with `failproofai --version`. + +Get an API key from a provider below, or have a compatible endpoint and its key ready. Jev reviews named tool calls at the `PreToolUse` or `PermissionRequest` gate. It can issue its own verdict, but clearing an existing policy deny also requires an installed policy marked [reviewable](/policies/authority). Hard policy denies stay final. + +## Choose a provider + +Jev is reachable through five routes. Bring a key for any one of them. + +| Provider | `--provider` | Endpoint | Default model | Notes | +| --- | --- | --- | --- | --- | +| TypeSafe | `typesafe` | `api.typesafe.ai/v1/systemone` | `jev-1.13.0` | Exact version pin. | +| OpenRouter | `openrouter` | `openrouter.ai/api/v1/systemone` | `typesafe/jev-1.13` | Requests are routed to zero-data-retention endpoints only, with no fallback to another provider. Reports a dated version such as `typesafe/jev-1.13-20260917`. | +| Vercel AI Gateway | `vercel` | `ai-gateway.vercel.sh/typesafe/v1/systemone` | `typesafe-ai/jev` | Names Jev only by an alias, so the answering version is recorded as unverified. | +| Cloudflare Workers AI | `cloudflare` | `api.cloudflare.com/client/v4/accounts//ai/run` | `typesafe/jev` | Needs `--account-id`. About six calls a second per key were measured before HTTP 429. | +| Your own endpoint | `custom` | `/systemone` | `jev-1.13.0` | Any endpoint that accepts TypeSafe's request body and reports which model answered. `https` only; plain `http://localhost` is accepted in observe mode only. | + + +With Vercel's own bring-your-own-key feature, a failed request is silently retried with Vercel's credentials. If you need every call billed to, and seen by, your own TypeSafe account only, use TypeSafe directly. + + +## Set it up + +One command, the endpoint and the key. Start in `observe` mode so you can inspect Jev's verdicts while the existing policies keep deciding calls: + +```bash +failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key +``` + +### The URL picks the provider + +You do not have to name the provider: the URL's **host** is which one it is. + +| URL host | Provider | Also needs | +| --- | --- | --- | +| `api.typesafe.ai` | `typesafe` | — | +| `openrouter.ai` | `openrouter` | — | +| `ai-gateway.vercel.sh` | `vercel` | — | +| `api.cloudflare.com` | `cloudflare` | `--account-id <32-hex-account-id>` | +| any other host | `custom` | — the URL you gave is the base URL | + +Three things follow from that: + +- **A URL that is the provider's own API writes no override.** `--url https://api.typesafe.ai/v1` produces exactly the config `--provider typesafe` would have. Give a different path or host on a known provider and it is stored as the base URL, as `--base-url` would store it. +- **`--provider` still overrides the inference**, which is how you reach a proxy that speaks a provider's API from a host of your own: `--url https://jev-proxy.internal/v1 --provider typesafe`. +- **A `--provider` that contradicts the host is refused**, not guessed at. `--provider openrouter --url https://api.typesafe.ai/v1` writes nothing and says why: the two spellings disagree about where your key is about to be sent. The same pair is refused from `jev setup --base-url` and from the dashboard's Jev settings. (`--provider custom` is not a contradiction — it means "treat this URL as itself" — except on Cloudflare's host, whose per-account endpoint a custom route cannot reach.) + +`--url` is validated exactly as the `baseUrl` in the config file is, and refused in the same words: `https`, or plain `http://localhost` in observe mode only. + +### The key + +Pipe it in with `--key-stdin`, or run the command in a terminal without it and paste the key at a masked prompt. Either way it goes straight into the config file and is never printed back. + + + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key + ``` + + + ```bash + failproofai jev --url https://openrouter.ai/api/v1 --mode observe --key-stdin < ~/openrouter.key + ``` + + + ```bash + failproofai jev --url https://ai-gateway.vercel.sh/typesafe/v1 --mode observe \ + --key-stdin < ~/vercel-gateway.key + ``` + + + ```bash + failproofai jev --url https://api.cloudflare.com/client/v4 \ + --account-id <32-hex-account-id> --mode observe --key-stdin < ~/cloudflare.token + ``` + + + ```bash + failproofai jev --url https://jev.internal.example.com/v1 --mode observe --key-stdin < ~/jev.key + ``` + + + +`failproofai jev setup` takes the same flags and is the longhand for all of it: `setup --provider ` where you would rather name the provider than the URL. + +### `--token`, and what it costs + +`--token ` puts the key on the command line, which is the fastest way to configure a machine and the only spelling that leaves the key anywhere but the config file: + +```bash +failproofai jev --url https://openrouter.ai/api/v1 --token +``` + + +A command-line argument is in your shell's history file afterwards, and while the command runs it is in the process list — readable from `/proc` by anything running as you. `setup` says so every time `--token` is used. Prefer `--key-stdin` on a machine you share, in a recorded session, or anywhere the history file is synced; rotate a key you have passed this way if it matters. + + +`--token`, `--key-stdin` and `--key-from-env` are mutually exclusive: give one. + +Then send one small live request to check the key, the endpoint and which Jev answered: + +```bash +failproofai jev test +``` + +```text + failproofai jev test ok · 523 ms + + provider cloudflare + model asked typesafe/jev + answered by jev-1.13.0 (Jev 1.13 family — verified) + latency 523 ms — within the 3000 ms timeout +``` + +`jev test` exits 1, and says so in its title, when the answer arrives after the timeout (every hook would fall back to regex as `timeout`) or answers its check question wrongly. + +Hooks read the config on every tool call, so it applies from the next one. There is nothing to restart, with or without the daemon. + +## Check what it is doing + +```bash +failproofai jev status +failproofai jev status --json +``` + +`status` shows the provider, endpoint, model, mode, the config file and its permissions, and never the key. Below that it summarizes recent activity: how many calls Jev evaluated, how often it fell back to regex and why, its latency, and which reviewable policies it cleared. + +## Verify a real call + +Start a new session in the hooked agent. Ask it to use its file-reading tool on `README.md` and report the title. Confirm that the session contains that tool call, then run `failproofai jev status` again: its recent evaluated-call count should increase. Open **Policies → Activity** in the [local dashboard](/reference/local-dashboard#review-policy-activity) to inspect the call's Jev verdict and mode. In observe mode, the policy result still decides the call. A clearance appears only if a reviewable policy matched and Jev cleared every named check; an ordinary read may have no policy to clear. + +## Observe mode + +`enforce` is the default. To watch Jev without letting it change any decision, switch to `observe`: Jev is still asked and its verdicts are recorded, but the regex result is what is enforced. + +```bash +failproofai jev setup --mode observe +failproofai jev setup --mode enforce +failproofai jev setup --mode off +``` + +`off` keeps the config — the endpoint and the key — and stops asking Jev: hooks run the regex policies exactly as without a config, and `failproofai jev status` says "off (switched off)". Switch back with `--mode observe` or `--mode enforce`. + +Re-running `setup` for the same provider keeps the stored key, so a mode switch is one flag. Switching provider starts over and asks for that provider's key. So does a `--base-url` that moves requests to a different host: a stored key is only sent to the host it was given for, or to its provider's own API. + +## The config file + +Everything lives in one file, `~/.failproofai/jev.json`, written by `setup`: + +```json +{ + "provider": "cloudflare", + "apiKey": "", + "accountId": "<32-hex-account-id>", + "mode": "enforce", + "timeoutMs": 3000 +} +``` + +| Field | Meaning | +| --- | --- | +| `provider` | `typesafe`, `openrouter`, `vercel`, `cloudflare` or `custom` — or `failproofai`, whose key comes from the FailproofAI Cloud connection instead of this file (see [Jev through FailproofAI Cloud](/reference/jev-cloud)). | +| `apiKey` | Sent as `Authorization: Bearer `. | +| `baseUrl` | Required for `custom`; replaces the provider's API base otherwise. Must be `https`. Plain `http` to `localhost` is accepted only with `mode: observe`: nothing authenticates a local port, so while your proxy is down any process on the machine, including the agent being judged, could answer in its place. | +| `accountId` | Cloudflare only: 32 lowercase hex characters. | +| `model` | Replaces the provider's default model id. A versioned id must name Jev 1.13. A value shaped like an API key is refused (and not repeated back), so a key pasted into `--model` is never stored or sent as the model. | +| `timeoutMs` | How long a tool call waits for Jev before using the regex result. 100–10000, default 3000. | +| `mode` | `enforce` (default), `observe`, or `off` (keep the config, run no Jev). | + +Three rules protect it: + +- **Owner-only.** It is written with permissions `0600`. A copy that any other user or group can read or write is **refused**, and hooks fall back to regex until you run `chmod 600 ~/.failproofai/jev.json` or `setup` again. The directory is checked too: `~/.failproofai` must not be **writable** by anyone else, because whoever can write there can replace the file whatever its own permissions are. `setup` takes those write bits off if it finds them. `failproofai jev status` says when a config has been refused and shows the endpoint the file names: someone else could have changed it, so check it is yours before you `chmod`. Re-running `setup` on such a file carries its stored key only to the provider's own API; any other endpoint it names needs the key again (`--key-stdin`), or `--base-url default` to send requests back to the provider. +- **Global only.** A repository cannot turn Jev on, point it at another endpoint or pick its model: a `.failproofai/jev.json` inside a project is ignored, and the provider, URL, model and account id are read only from that file — never from the environment, which a repository's agent settings can set. (`FAILPROOFAI_HOME` is not a way around that: it moves the whole failproofai directory, your policies included, rather than redirecting Jev on its own.) +- **The key alone may come from the environment.** If the file has no `apiKey`, `FAILPROOFAI_JEV_API_KEY` supplies it for that session (`setup --key-from-env` writes such a file). It never replaces a key the file holds, and it cannot turn Jev on without the file. Where the variable is not set, Jev is simply off for that shell: `failproofai jev status` says so, exits 0 and leaves the config alone (`status --json` reports `"status": "key-missing"` with `"reason": "no-env-key"`). The `failproofaid` daemon does not see your shell's environment, so on a machine set up with `failproofai config`, keep the key in the file. + +## Which Jev answers + +Failproof AI's decision thresholds were calibrated on Jev 1.13, so an answer is used only when it comes from that family: `jev-1.13.x`, or OpenRouter's `typesafe/jev-1.13-`. Where a provider names Jev only by an alias and reports no version (Vercel, and Cloudflare when it does not say), the answer is used and recorded as unverified. A `custom` endpoint must report the model that answered; the one exception is an unversioned `--model` name you configured for it, which, echoed back, is recorded as unverified in the same way. An answer reporting any other version, or a `custom` answer reporting none, is not used: that call falls back to regex with the reason `model-mismatch`. + +## When Jev cannot answer + +Each of these falls back to the regex result for that call and is recorded with its reason, which `failproofai jev status` totals: + +| Reason | Cause | +| --- | --- | +| `timeout` | No answer within `timeoutMs`. | +| `http-429` | The provider rate-limited the key. | +| `rate-limited` | Failproof AI's own limiter held the call back before sending it: 5 requests a second, in bursts of up to 5, and none for a moment after the provider answers `429`. Not the provider. | +| `http-500`, `http-502`, `http-503`, … | A server error at the provider. The exact status is recorded. | +| `out-of-credits` | HTTP 402: the provider account has no credits left. | +| `provider-refused` | HTTP 402 from Cloudflare reading "Model execution failed (Payment error)": the provider declined to run the model on this request. Usually not billing, so topping up will not move it. | +| `http-401`, `http-403` | The key was refused. | +| `http-404` | Nothing is served at `/systemone`, so the base URL is wrong — `/systemone` is appended to it, and every provider serves it at its version root. `failproofai jev models` shows what the endpoint does serve. | +| `network` | The endpoint could not be reached. | +| `http-301`, `http-302`, `http-307`, `http-308` | The endpoint answered with a redirect. Redirects are never followed, so the answer only ever comes from the URL in your config; set `--base-url` to the final URL. | +| `malformed` | The endpoint answered, but not with a Jev answer — a body that is not JSON, or one with no answers in it. | +| `cloudflare-error`, `cloudflare-incomplete` | Cloudflare's envelope reported a failure, or a job that had not finished. | +| `model-mismatch` | A Jev version other than 1.13 answered, or a `custom` endpoint did not say which model answered. | +| `request-cut` | **Not an outage.** Jev answered; it was shown only part of the call, so its answer cleared nothing. See [When Jev answered, but not on the whole call](#when-jev-answered-but-not-on-the-whole-call). | + +`failproofai jev status` can show a few rarer reasons too, such as `upstream-error` (the answer carried the provider's own error) or `config`, and totals any reason it cannot name as `other`. + +`request-cut` is in this table because `failproofai jev status` totals it with the rest, and because it too leaves every deny standing. It is the one reason here that says nothing about your provider: the request arrived and Jev answered it. Unlike every row above it, that answer still counts — Jev's own deny or warning applies on top of the regex result rather than being discarded. So a run of them means calls are reaching the evaluator too big to send whole, not that your endpoint is unwell, and topping up credits or changing the URL will not move the number. + +## When Jev answered, but not on the whole call + +Two more things can happen, and neither is Jev failing to answer. Both are about how much of the call, or of the conversation, fitted into one request. + +**Part of the call itself did not fit.** A tool call is sent inside a fixed budget, and an outsized one — a very large `Write`, a huge MCP body, a command padded out to the cap — is sent with what fitted. Jev still answers, and its answer still counts: its own deny or warning applies as usual. What it cannot do is **clear** anything, because a verdict given on part of a call is not a verdict on the call. So every policy deny stands, and the call is recorded as a fallback with the reason `request-cut`, which `failproofai jev status` totals alongside the reasons above. The rule this gives you: making a call bigger can cost it its clearances, and can never buy one. + +**A message did not fit.** A long prompt you pasted, the agent's last message, or a prompt this evaluator's own store had already capped. **Nothing changes**: the call is judged, cleared and recorded exactly as any other, and it is not counted as a fallback. The length of what you type never decides a verdict, and a cut cannot manufacture consent: where a prompt arrived already capped, "you did not ask for this" stops being a conclusion that can be drawn from it at all, rather than becoming one. + +The line between the two is who wrote the text. The call is the agent's, and a rule that let its length subtract severity would be a rule the agent can use; your prompt is yours, and treating its length as a signal only ever punished pasting a spec or a stack trace. + +## What leaves the machine + +For each tool call Jev evaluates, one request goes to your provider, carrying: + +- the tool call itself, with secrets such as API keys, bearer tokens and `KEY=` assignments redacted; +- the recent prompts you typed, with text your agent's harness added removed; +- the agent's last message before your latest prompt, labelled as agent-written; +- facts computed locally, such as whether a path is inside the project — the one the session was in at its first reviewed call, [pinned for the session](/reference/jev-intent#the-project-root) — and the current git branch. + +It goes only to the endpoint in your config, under your key. + +## Turn it off + +```bash +failproofai jev remove +``` + +This deletes `~/.failproofai/jev.json`. From the next tool call, hooks run the regex policies exactly as before. The per-session stores under `~/.failproofai/state/semantic/` (recorded prompts in `sessions/`, project roots in `roots/`) are left in place and age out. To stop asking Jev but keep the config, use `failproofai jev setup --mode off` instead. + +## Command reference + +| Command | Outcome | +| --- | --- | +| `failproofai jev --url --key-stdin` | Configure it in one command; the provider comes from the URL's host | +| `failproofai jev --url --token ` | Same, with the key on the command line — your history and the process list see it | +| `failproofai jev setup --provider --key-stdin` | Write the config from a key piped on stdin | +| `failproofai jev setup --provider ` | Same, asking for the key at a masked prompt | +| `failproofai jev setup --key-from-env` | Store no key; read `FAILPROOFAI_JEV_API_KEY` per session | +| `failproofai jev setup --mode observe` | Switch mode (`enforce`, `observe` or `off`), keeping the stored key | +| `failproofai jev setup --model ` / `--base-url ` | Override the model or API base; `default` clears the override | +| `failproofai jev setup --timeout-ms ` | Change the per-call budget | +| `failproofai jev status [--json]` | Configuration, permissions and recent activity; never the key | +| `failproofai jev test [--json]` | One live request: latency and the version that answered | +| `failproofai jev models [--provider ] [--url ] [--json]` | The model ids that endpoint's `/models` reports, marking the configured one | +| `failproofai jev remove` | Delete the config; Jev is off | diff --git a/docs/reference/jev.mdx b/docs/reference/jev.mdx new file mode 100644 index 000000000..187637a3e --- /dev/null +++ b/docs/reference/jev.mdx @@ -0,0 +1,22 @@ +--- +title: "Jev integration reference" +description: "Configuration, providers, keys, request data, and failure behavior for Jev." +icon: "braces" +--- + +Jev has two uses in Failproof AI: + +| Use | When it runs | What it returns | Start here | +| --- | --- | --- | --- | +| Session evaluation | After a session finishes | A score for a fixed-answer question | [Jev evaluations](/evaluations/jev) | +| Tool-call policy review | Before a gated tool call runs | A verdict alongside the installed policies | [Jev policies](/policies/jev) | + +## Reference pages + +| Topic | Details | +| --- | --- | +| [Evaluation questions](/reference/jev-evaluations) | Boolean and ordered-score criteria, results, limits, and backfill. | +| [Provider comparison and own-key setup](/reference/jev-providers) | TypeSafe, OpenRouter, Vercel, Cloudflare, and custom endpoints; URL inference, model IDs, `jev.json`, modes, and fallback codes. | +| [FailproofAI Cloud route](/reference/jev-cloud) | Machine-key permissions, automatic observe setup, usage limits, connection state, and data handling. | + +The local CLI commands are listed in the [Failproof AI CLI reference](/reference/failproof-cli). The [local dashboard reference](/reference/local-dashboard#set-up-jev) describes its Jev settings and activity view. diff --git a/docs/reference/local-dashboard.mdx b/docs/reference/local-dashboard.mdx index a9c224a98..02116370c 100644 --- a/docs/reference/local-dashboard.mdx +++ b/docs/reference/local-dashboard.mdx @@ -17,7 +17,7 @@ The local dashboard is separate from Failproof AI Cloud. It works without a Clou | Projects | Browse discovered projects across supported agent histories and compare their most recent sessions. | | Project sessions | Open one local transcript, review raw ordered entries and subagents, download it, and correlate policy activity. | | Audit | Review the last offline scan, risky patterns, strengths, affected projects, and suggested builtin policies. | -| Settings | Configure scheduled local scans and emailed audit reports when the daemon/platform supports them. | +| Settings | Configure scheduled local scans and emailed audit reports when the daemon/platform supports them, and [Jev](#set-up-jev): its provider, endpoint, token and mode, and whether this machine's FailproofAI Cloud connection can run it. | ## Review policy activity @@ -67,6 +67,15 @@ The Projects page combines supported local history stores. Select a project to l If a project or session is missing, confirm the harness uses its default history location or register an extra root with `failproofai harness add-path`. +## Set up Jev + +The **Settings** page's Jev section writes the same `~/.failproofai/jev.json` that `failproofai jev setup` writes, validated by the loader's own rules, so the hooks use it on their next call. It says whether Jev is on and in which mode, and — once it is on — how many calls it answered and how often it fell back to the regex policies. Failproof AI ships no Jev checks: while no installed pack declares any, the section says so and names `failproofai policies add FailproofAI/jev-policies`, and Jev asks nothing. + +- **Your own endpoint.** Choose the provider, give an endpoint URL for `custom` (optional for the others) and an account id for Cloudflare, paste the token, and pick the mode (`observe`, `enforce` or `off`). The token is write-only: the page never shows it, and leaving the field blank keeps the stored one while the provider and the endpoint's host stay the same. Change either and the page asks for the token again, so a stored key is never sent somewhere it was not given for. See [Jev with your own key](/reference/jev-providers). +- **FailproofAI Cloud.** Jev through Cloud is turned on by connecting the machine (`failproofai config --token `); the page offers only its on/off switch and mode. See [Jev through FailproofAI Cloud](/reference/jev-cloud). + +A config whose key comes from `FAILPROOFAI_JEV_API_KEY` (`jev setup --key-from-env`) is judged from the dashboard's own environment, which may not be the one your agent runs in; run `failproofai jev status` where the agent runs to see what its hooks do. + ## Schedule offline audits diff --git a/docs/reference/overview.mdx b/docs/reference/overview.mdx index c98399bf8..52dcd2ab4 100644 --- a/docs/reference/overview.mdx +++ b/docs/reference/overview.mdx @@ -22,6 +22,9 @@ Choose the integration closest to where your agent already runs. Configure local capture, hooks, policies, audits, delivery, and machine state. + + Compare session evaluations with live policy review, then configure providers, keys, and modes. + Query and administer Cloud sessions, audits, issues, alerts, keys, users, and settings. diff --git a/docs/reference/policy-sdk.mdx b/docs/reference/policy-sdk.mdx index f31e027e8..649e2de57 100644 --- a/docs/reference/policy-sdk.mdx +++ b/docs/reference/policy-sdk.mdx @@ -88,6 +88,8 @@ customPolicies.add({ | `description` | No | Human-readable purpose shown in policy listings and decisions. | | `match.events` | No | Event types that invoke the policy. Omitting `match` invokes it for every available event. | | `fn` | Yes | Synchronous or asynchronous function that returns an `allow`, `instruct`, or `deny` result. | +| `authority` | No | `"hard"` (the default) or `"reviewable"`. Whether the Jev semantic evaluator may clear this policy's verdict. See [Policy authority](/policies/authority). | +| `reviewedBy` | No | The semantic checks Jev must all be asked, none of which may answer deny, before Jev may clear the verdict. A check that warns still clears it. Required for `"reviewable"`. | Filter tools inside `fn`. `match.toolNames` is not part of the public custom-policy type. @@ -285,6 +287,64 @@ Attribute the result to your custom policy under **Observe → policy**. A block Keep policy modules deterministic and quick. Avoid top-level network calls or server startup. Bound work inside `fn`, catch dependency failures, and choose deliberately whether that failure should allow or deny the operation. +## Jev checks + +A custom policy decides with code. A **Jev check** is a set of yes/no questions the Jev semantic evaluator answers about a tool call instead. A `reviewable` policy names checks in `reviewedBy`, and Jev may clear its verdict only through them — see [Policy authority](/policies/authority). Declare one with `semanticPolicies.add()`: + +```js +import { semanticPolicies } from "failproofai"; + +semanticPolicies.add({ + name: "prod-db-write", + title: "Wrote to the production database", + appliesTo: ["shell"], + mode: "deny", + userCanOverride: true, + probes: [ + { + id: "writes_data", + instructions: "Does this command insert, update or delete rows, or change a schema?", + criteria: { true: "It changes data or schema.", false: "It only reads." }, + }, + { + id: "production_target", + instructions: "Is the database it targets a production one, rather than a local or test copy?", + }, + ], + guidance: "Writes to the production database need a human. Ask before running this.", +}); +``` + + + A Jev check takes effect **only through a published pack**. `failproofai publish` is the one thing that reads `semanticPolicies.add()`; in a local policy file (`.failproofai/policies/`, `--custom`) it loads without an error, the hook log names it as ignored, and it is never asked, and a local policy whose `reviewedBy` names it stays hard. See [Jev checks in a pack](/policies/publish-a-pack#jev-checks-in-a-pack). + + +| Field | Required | Description | +| --- | --- | --- | +| `name` | Yes | Letters, digits, `.`, `_` and `-`, up to 128 characters, unique in the pack. What a `reviewedBy` names; reported as `semantic/`. | +| `title` | Yes | A past-tense phrase for what was caught. Up to 120 characters. | +| `appliesTo` | Yes | The tool classes Jev is asked about: one or more of `shell`, `write`, `read`, `network`, `other`. | +| `mode` | Yes | `"deny"` blocks on strong evidence and warns on moderate evidence. `"instruct"` only ever warns, so it can never keep a deny standing — pair a blocking policy with it alone and a clear leaves nothing that can deny. | +| `userCanOverride` | Yes | Whether the human's own explicit request clears the check. It decides whether words in a prompt can talk their way past it, so it has no default. | +| `probes` | Yes | 1 to 6 questions. **Every** probe must hold for the check to fire. | +| `probes[].id` | Yes | Matches `^[a-z][a-z0-9_]{0,31}$`, unique within the check. `exempt` and `user_asked` are reserved. | +| `probes[].instructions` | Yes | The question. Up to 600 characters. | +| `probes[].criteria` | No | `{ true, false }`: what a yes and a no mean, up to 300 characters each. Both halves or neither. | +| `exempt` | No | One more question in the probe shape (its `id` is ignored). When it holds, the check does not fire — the documented exceptions. | +| `precondition` | No | One name from the table below. Absent means the check is asked on every call its `appliesTo` covers. | +| `guidance` | Yes | Shown to the agent when the check fires, whether it blocks or warns — a `"deny"` check only warns on moderate evidence, so do not say the call is blocked. Up to 600 characters. | + +A precondition is a name, never code: a manifest cannot carry a function, and a downloaded pack must not decide what runs on every tool call. + +| Precondition | The check is asked only when | +| --- | --- | +| `always` | Always — the same as leaving it out. | +| `protected_branch` | The current git branch is `main`, `master`, `production`, `prod`, `release` or `trunk`. | +| `in_git_repo` | The call runs on a git branch. A detached `HEAD` counts as outside a repository. | +| `has_paths` | The call names at least one path. | +| `paths_outside_project` | Some path it names is outside the project. | +| `system_or_root_paths` | Some path it names is a system path or the filesystem root. | + ## API exports | Export | Purpose | @@ -293,10 +353,12 @@ Keep policy modules deterministic and quick. Avoid top-level network calls or se | `allow(reason?)` | Permit the operation. | | `instruct(reason)` | Permit the operation and provide guidance where supported. | | `deny(reason)` | Block the operation where supported. | +| `semanticPolicies.add(check)` | Declare a [Jev check](#jev-checks) for `failproofai publish` to put in a pack. | | `getCustomHooks()` | Return the policies currently registered in the module registry. | -| `clearCustomHooks()` | Clear that registry, primarily for tests and loaders. | +| `getSemanticRegistrations()` | Return the Jev checks currently declared, primarily for tests and loaders. | +| `clearCustomHooks()` | Clear both registries, primarily for tests and loaders. | -TypeScript exports `PolicyContext`, `PolicyResult`, `CustomHook`, `PolicyDecision`, and `PolicyFunction`. +TypeScript exports `PolicyContext`, `PolicyResult`, `CustomHook`, `PolicyDecision`, `PolicyFunction`, `PolicyAuthority`, `SemanticPolicyDeclaration`, `SemanticProbeDeclaration`, and `SemanticToolClass`. Publish a version, deploy it in observe mode, verify decisions, and move to enforcement. diff --git a/docs/reference/troubleshooting.mdx b/docs/reference/troubleshooting.mdx index 4e9ea8dc2..06f127817 100644 --- a/docs/reference/troubleshooting.mdx +++ b/docs/reference/troubleshooting.mdx @@ -57,6 +57,30 @@ icon: "wrench" + + + + The machine connected and its hooks work, but **Observe → Events** stays empty and **Admin → enforcement** never shows its deployment as applied. The CLI and the Failproof daemon trust certificates differently. The CLI runs on Node and honours `NODE_EXTRA_CA_CERTS`. `failproofaid`, which sends events and pulls policies, trusts the certificates bundled with it plus the operating system's trust store, and ignores `NODE_EXTRA_CA_CERTS`. Install your CA in the system store on the machine. + + + ```bash + # Debian / Ubuntu + sudo cp company-ca.pem /usr/local/share/ca-certificates/company-ca.crt + sudo update-ca-certificates + # RHEL / Fedora + sudo cp company-ca.pem /etc/pki/ca-trust/source/anchors/ && sudo update-ca-trust + # macOS + sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain company-ca.pem + + # then restart the daemon, which loads trusted certificates at start + sudo systemctl restart failproofaid@$USER # Linux + sudo launchctl kickstart -k system/ai.failproof.failproofaid.$USER # macOS + ``` + + The daemon's log names the cause: `sudo journalctl -u failproofaid@$USER | grep UnknownIssuer` on Linux. `SSL_CERT_FILE` or `SSL_CERT_DIR` in the service's environment replaces the system store for the daemon, and the bundled certificates still apply. Batches that failed while the CA was untrusted are kept in `~/.failproofai/state/failed` and retried automatically, about hourly and when the daemon restarts. + + + @@ -162,6 +186,25 @@ icon: "wrench" + + + + Errors in the dashboard end with a short reference, for example `ref 4bf92f35`. It identifies that one request, and support can use it to find exactly what happened on the server. Copy it into your report as it appears. + + If a whole page fails to load, the error page shows a `digest` instead. Include that. + + + Human-readable `fp` errors end with the same `ref`. With `--json`, the error object carries the full `request_id`: + + ```bash + fp --json sessions --since 24h + ``` + + + When an upload fails, the daemon's log names a `request_id` and a `batch_id`: on Linux, `sudo journalctl -u failproofaid@$USER | grep batch_id`. Every attempt gets its own `request_id`; the `batch_id` stays the same across retries, so it ties the attempts of one batch together. Include both. + + + -When contacting support, include the CLI version, harness, environment, relevant session or deployment ID, and the output of `failproofai config --status` with secrets removed. +When contacting support, include the CLI version, harness, environment, relevant session or deployment ID, any `ref` or `request_id` from the error, and the output of `failproofai config --status` with secrets removed. diff --git a/docs/ru/evaluations/jev.mdx b/docs/ru/evaluations/jev.mdx new file mode 100644 index 000000000..e5475b97c --- /dev/null +++ b/docs/ru/evaluations/jev.mdx @@ -0,0 +1,28 @@ +--- +title: "Jev оценки" +description: "Используйте Jev для оценки завершённой сессии по вопросу с известными ответами." +icon: "list-checks" +--- + +Jev оценка читает **завершённую сессию** и выдаёт оценку от 0 до 1. Используйте её, когда ответ известен заранее, например «Выразил ли клиент срочность?» или «Насколько был расстроен клиент?» Это помогает найти закономерности между запусками; оно не останавливает вызов инструмента. Для решений, принятых **до** запуска инструмента, используйте [Jev policies](/ru/policies/jev). + +## Создайте одну на панели инструментов + +1. Откройте **Analyze → eval authoring** и выберите **new eval**. +2. Опишите один вопрос и его возможные ответы. Например: «Обещал ли агент возврат средств перед проверкой политики возврата? Ответьте да или нет.» Выберите **draft** и убедитесь, что результат — это оценка классификатора. +3. [Протестируйте](/ru/evaluations/test) на недавних сессиях, затем [развёрните](/ru/evaluations/deploy). Новые завершённые сессии оцениваются; [заполните историю](/ru/evaluations/deploy#score-sessions-you-already-have), если вам также нужна история. + +![Форма совместного авторства оценок, где вы описываете вопрос с фиксированным ответом, просматриваете черновик и развёртываете после тестирования. Показанный пример — оценка кода; вопрос Jev использует тот же процесс авторства.](/images/dashboard/eval-authoring-draft.png) + +Помощник может выбрать между кодом, классификацией Jev и [судьёй](/ru/evaluations/judge). Проверьте его выбор перед развёртыванием. Jev выдаёт оценку без пояснительного текста; выберите судью, когда вам нужно объяснение. См. [справочник по оценкам Jev](/ru/reference/jev-evaluations) для типов вопросов и ограничений оценок. + +## Прочитайте оценки + +Откройте **Observe → Evaluations** для отображения результата по агентам и времени. Из терминала Cloud CLI может читать те же результаты: + +```bash +fp evals --since 7d +fp evals --aggregate --since 7d +``` + +Cloud CLI читает результаты; авторство и развёртывание происходят на панели инструментов. См. [справочник Cloud CLI](/ru/reference/cloud-cli#evaluations) для фильтров. \ No newline at end of file diff --git a/docs/ru/evaluations/judge.mdx b/docs/ru/evaluations/judge.mdx new file mode 100644 index 000000000..55f56c36e --- /dev/null +++ b/docs/ru/evaluations/judge.mdx @@ -0,0 +1,91 @@ +--- +title: "LLM судьи" +description: "Оценивайте сессии по критериям, которые код не может измерить — корректность, тон, соответствие политикам — описав, что считается хорошим результатом, и позволив модели прочитать диалог." +icon: "scale" +--- + +Размещенная на сервере оценка Python может подсчитывать и сравнивать: сколько было вызовов инструментов, сколько ошибок, сколько длилась сессия. Но она не может сказать вам, был ли ответ *корректным*, был ли ответ грубым или проверил ли агент политику перед действием. + +**LLM судья** может. Вы описываете, что считается хорошим результатом на простом языке, и модель читает сессию и возвращает оценку от 0 до 1 с объяснением. + + +Судья требует один вызов модели для каждой сессии, на которой он работает, а оценка кода ничего не стоит. Используйте судью только для вопросов, которые требуют *понимания* диалога — и задайте условие, чтобы он работал только на релевантных сессиях. + + +## Что мне нужно? + +| Вопрос | Использовать | +| --- | --- | +| Он вызвал один и тот же инструмент дважды? | code | +| Сколько было ошибок? | code | +| Длилась ли сессия менее 30 секунд? | code | +| Клиент выразил срочность? | [classifier](/ru/evaluations/jev) | +| Насколько расстроен был клиент? | [classifier](/ru/evaluations/jev) | +| Был ли ответ действительно корректным? | **судья** | +| Был ли ответ грубым или пренебрежительным? | **судья** | +| Проверил ли он политику возврата перед обещанием возврата? | **судья** | + +Практическое правило: **измеримое → code, ответы, которые можно заранее перечислить → [classifier](/ru/evaluations/jev), требует объяснения → судья.** Судья — это тот, кто описывает увиденное текстом; используйте его, когда число заставит кого-то спросить "почему?". + +Вам не нужно решать заранее. Опишите, что вы хотите измерить, и ассистент выберет, затем расскажет вам, что он выбрал и почему. Вы можете переключиться. + +## Создайте судью + +1. Перейдите в **Analyze → eval authoring** и выберите **new eval**. +2. Опишите, что вы хотите оценить, и выберите **draft**. +3. Проверьте **criteria**, **threshold** и **condition**, затем развертайте. + +### Criteria + +Одно или два предложения, сформулированные как требование, а не вопрос: + +> Ассистент не должен обещать или одобрять возврат без предварительной проверки политики возврата. + +Будьте конкретны в том, что приведет к *отказу*. "Был ли ответ хорошим?" дает вам число, которое ничего не значит; предложение выше дает вам число, на которое можно действовать. + +### Threshold + +Оценка, при которой сессия проходит. `0.7` — разумная стартовая точка. Полная оценка от 0 до 1 всегда хранится, поэтому порог только определяет пройдено/не пройдено — вы можете увидеть распределение и отрегулировать. + +### Condition + +То же условие Python, что и в любой другой оценке, и оно здесь намного важнее. Без него судья работает на **каждой** сессии в вашей организации, с одним вызовом модели для каждой: + +```python +session.count("tool_use") > 0 +``` + +```python +session.agent_id == "support-bot" and session.count("error") > 0 +``` + +Панель предупредит вас, если вы развернете судью без условия. Иногда это правильно — низкообъемный агент, который вы хотите полностью оценить — но это должно быть решением, а не случайностью. + +## Что видит судья + +Диалог, как обороты, новейшие сначала, если сессия длинная: + +- что сказал пользователь +- что ответил ассистент +- **каждый инструмент, который вызвал агент, и что вернул этот вызов, по порядку** + +Последняя часть — это то, что делает "сделал ли он X *перед* Y" честным вопросом. Неудачный вызов инструмента показывается как ошибка, так что "восстановился ли он изящно после ошибки" тоже работает. + +Очень длинные сессии обрезаются, чтобы поместиться в контекст модели. Когда это происходит, объяснение это явно указывает — вы никогда не увидите оценку, сделанную на части сессии, представленную как оценка всей сессии. + +## Чтение результатов + +Судья производит **score** как любая другая оценка с оценкой, поэтому он работает с графиками, фильтрами и триггерами алертов так же. Наряду с числом он хранит **reasoning** судьи — абзац, объясняющий, что он видел. Прочитайте его сначала, когда оценка вас удивит; это обычно либо действительно интересная сессия, либо признак того, что критерии нужно заточить. + +Оценки стабильны для ясных случаев, но не идентичны до бита. Рассматривайте одну пограничную оценку как приглашение пойти и прочитать сессию, а не как вердикт. + +## Ограничения + +- **Тестирование недоступно.** Пробный запуск не имеет назначения сессии за ним, и это назначение — то, что разрешает трату вашего бюджета модели — так что нечему взимать плату при тестовом вызове. Развертайте с узким условием и прочитайте первые несколько результатов. +- **Заполнение истории недоступно.** Заполнение оценки кода на месяцы истории бесплатно; делать это с судьей потратит весь ваш бюджет за минуты. +- **Редактирование criteria публикует новую версию.** Старые и новые оценки не сравнимы, поэтому они хранятся отдельно, а не смешиваются в одну линию тренда. +- **Судья всегда производит оценку**, никогда метрику или утверждение. + +## Когда бюджет закончится + +Судьи тратят бюджет модели вашей организации. Когда он исчерпан, оценки судей останавливаются с понятной причиной, а не молча отказываются, и **оценки кода продолжают работать нормально**. Увеличьте бюджет, и они возобновятся на следующей сессии. \ No newline at end of file diff --git a/docs/ru/policies/authority.mdx b/docs/ru/policies/authority.mdx new file mode 100644 index 000000000..f76d9d15d --- /dev/null +++ b/docs/ru/policies/authority.mdx @@ -0,0 +1,144 @@ +--- +title: "Полномочия политики" +description: "Какие решения семантического оценивателя Jev может отменить, а какие окончательны." +icon: "scale" +--- + +При настройке [проверки политики Jev](/ru/policies/jev) через FailproofAI Cloud или собственный ключ каждый управляемый вызов инструмента оценивается применяемыми политиками и Jev, который определяет, что на самом деле делает вызов и просил ли пользователь его выполнить. **Полномочия** каждой политики определяют, что происходит, когда они расходятся. + +Без настроенного Jev полномочия не имеют эффекта. Каждая политика работает в точности как обычно. + +## Жёсткие и пересматриваемые + +- **Жёсткая** — значение по умолчанию. Решение жёсткой политики об отказе или инструкция окончательно: Jev не может их отменить, и жёсткий отказ останавливает вызов без ожидания Jev. +- **Пересматриваемая** означает, что Jev может отменить решение политики, но только через семантические проверки, названные в `reviewedBy`. Решение отменяется только когда **каждая** названная проверка была применена к этому вызову и каждая либо ничего не нашла, либо зафиксировала, что пользователь просил это. Проверка, которая **сработала** — нашла проблему — без просьбы пользователя сохраняет блок, даже если её решение только предупреждение. Проверка, которая не была применена Jev, потому что не применима к этому инструменту, никогда ничего не отменяет, независимо от остальных. Одно смягчение считается согласием: когда вызов — это шаг задачи, данной пользователем, и не ведёт дальше, Jev превращает отказ в предупреждение, и это предупреждение отменяет блок политики и является тем, что говорится агенту. + +Политика является пересматриваемой только если выполнены все следующие условия: + +1. Она объявляет `authority: "reviewable"`. +2. `reviewedBy` — непустой список, и каждая запись — это проверка Jev, которую объявляет установленный пакет. Failproof AI не поставляет проверки Jev: [шестнадцать перечисленных ниже](#semantic-policy-names) поступают из `failproofai policies add FailproofAI/jev-policies`. Без пакета, объявляющего проверки, каждая политика жёсткая. +3. Это не `alwaysOn`. Защита, которая предотвращает отключение Failproof AI агентом, всегда жёсткая. + +Всё остальное жёсткое: отсутствующее поле, опечатка в значении, пустой или неправильный `reviewedBy`, или имя, которое не является проверкой, которую эта машина может применить. Неизвестное имя делает всё объявление жёстким, а не пропускается, потому что `reviewedBy` означает «все эти должны быть применены, и ни одна не может отказать», и пропуск имени позволил бы Jev отменить политику на меньшем количестве проверок, чем вы просили. + +После настройки Jev, Failproof AI логирует предупреждение, когда отказывает в объявлении `reviewable`, один раз за процесс. Без Jev ничего не говорит, потому что полномочия тогда ничего не решают. `failproofai publish` отказывает собирать пакет, несущий такое объявление, так что автор пакета узнает об этом до установки кем-либо. Он судит `reviewedBy` против проверок, которые пакет объявляет когда объявляет любые, и против шестнадцати имён `FailproofAI/jev-policies` в противном случае. + +## Где объявляются полномочия + +Каждый способ, которым политика попадает на машину, имеет одно место, которое решает её полномочия: + +| Источник | Объявляется в | По умолчанию | +| --- | --- | --- | +| Встроенные политики | Таблица ниже | Жёсткая, если не указана как пересматриваемая | +| Собственные файлы политики | `authority` и `reviewedBy` на `customPolicies.add` | Жёсткая | +| Пакеты политик | Запись каждой политики в манифесте пакета (`failproofai-pack.json`) | Жёсткая | +| Облачные политики | Назначение политики в активном развёртывании | Жёсткая. Развёртывания её ещё не устанавливают, так что каждая облачная политика сегодня жёсткая. | + +Для пакета или облачной политики поля, установленные внутри кода политики, игнорируются; решают манифест или назначение. Пакет может описать только свои политики: его имена политик не могут содержать `/` и регистрируются под собственным префиксом пакета, так что ни один манифест не может сделать встроенную политику или политику другого пакета пересматриваемой. Политика, которую код пакета регистрирует без объявления в манифесте, жёсткая. + +Два пакета или две облачные политики, чей код идентичен побайтово, используют один артефакт и загружаются как одна политика. Эта политика пересматриваема только если каждый из них её объявляет пересматриваемой, и Jev затем должен отменить каждую проверку, которую любой из них назвал. Если любой из них объявляет её жёсткой или не объявляет вообще, она остаётся жёсткой. Порядок, в котором пакеты или политики перечислены, никогда не имеет значения. + +Большинство машин получают встроенные политики из пакета `FailproofAI/policies`, и читают их полномочия из манифеста этого пакета. Пересматриваемые записи ниже вступают в силу, когда установлен выпуск пакета, который их несёт; более старый выпуск не несёт ничего, так что каждая политика в нём остаётся жёсткой. + +## Объявление полномочий в собственной политике + +```js +import { customPolicies, deny, allow } from "failproofai"; + +customPolicies.add({ + name: "block-prod-config-reads", + description: "Keep production credentials out of the agent's context", + match: { events: ["PreToolUse"] }, + authority: "reviewable", + reviewedBy: ["secret-exposure"], + fn: async (ctx) => + String(ctx.toolInput?.file_path ?? "").includes("/config/prod/") + ? deny("Production config is off limits") + : allow(), +}); +``` + +`failproofai publish` копирует оба поля в манифест пакета, так что политика, опубликованная как пакет, сохраняет полномочия, которые дал её автор. Он отказывает собирать пакет, если объявление не будет соблюдено: значение отличное от `"hard"` или `"reviewable"`, `reviewedBy`, который не является списком имён, или имя, которое не является проверкой — одна из собственных [проверок Jev](/ru/policies/publish-a-pack#jev-checks-in-a-pack) пакета когда он объявляет любые, встроенная проверка в противном случае. + +## Встроенные политики + +Пересматриваемые только где семантическая политика действительно охватывает ту же проблему. Каждая другая встроенная политика жёсткая. + +Охват проблемы необходим, но недостаточен, и оба способа ошибиться тихие: + +- **Проверка, которая никогда не применяется** делает блок постоянным. `reviewedBy` — конъюнкция и проверка, которая не была применена, никогда не отменяет, так что политика, связанная с проверкой, чьё предусловие не срабатывает для форм, которые сопоставляет политика, никогда вообще не может быть отменена. +- **Проверка, которая применяется, но не срабатывает** отвечает «нет проблемы», и отсутствие проблемы отменяет. Так что связывание с проверкой, которая не моделирует формы вашей политики, не пересматривает политику — это выключает её ровно для входов, которые проверка не понимает. + +Семантическая политика в режиме инструкции никогда не может ответить отказом, но она всё ещё может сохранить блок: когда она срабатывает и пользователь не просил вызов, политика, которую она пересматривает, не отменяется. Шесть проверок `FailproofAI/jev-policies` только режима инструкции — `push-to-protected-branch`, `commit-on-protected-branch`, `read-outside-workspace`, `system-modification`, `env-secrets-dump` и `external-data-egress` — и [таблица ниже](#semantic-policy-names) даёт режим каждой проверки. Вопрос, который нужно задать: **есть ли ещё что-то, что может отказать**: отмена никогда не должна оставить проблему неприменённой ничем. Двигатель применяет этот тест за вызов. Предупреждение, на которое никто не согласился, не является отменой, потому что до вызовов инструмента предупреждение не останавливает агента. И когда проверка, которая *может* отказать, предупреждает — её доказательства были недостаточны для линии отказа — и пользователь не просил вызов, ничего не отменяется на этом вызове и каждый регулярный отказ стоит. + + +**Проверка, которая набирает чуть ниже линии срабатывания, не сохраняет минимум.** Правило выше требует проверку *срабатывания* (доказательство ≥ 0,7). Когда каждая релевантная проверка приземляется чуть ниже этого, ничего не срабатывает, рецензенты отвечают «нет проблемы», и пересматриваемый отказ отменяется. Измерено живо в режиме принуждения: незапрошенное чтение `/etc/shadow` (`secret-exposure` 0,69, `read-outside-workspace` 0,37, которое моделирует только пути в домашней директории) и `set | curl -d @- …` после «follow SETUP.md» (`env-secrets-dump` 0,66, `credential-exfiltration` 0,65 с `sends_out` 0,97) оба были разрешены, в то время как уровень регулярных выражений один их отрицает. Пороги были откалиброваны на помеченном корпусе и не были переизмерены по этому; пока они не будут, держите политику **жёсткой** где одна из этих форм, проходящая, имеет значение больше, чем её ложные блоки. + + +| Политика | Полномочия | Пересматривается | Почему | +| --- | --- | --- | --- | +| `protect-env-vars` | пересматриваемая | `env-secrets-dump`, `secret-exposure` | Паттерн срабатывает на любую ссылку переменной; Jev спрашивает, будут ли значения секретов действительно напечатаны. | +| `block-env-files` | пересматриваемая | `secret-exposure` | Паттерн совпадает с любым путём `.env`, включая шаблоны; Jev спрашивает, будут ли реальные значения секретов прочитаны или написаны. | +| `block-read-outside-cwd` | пересматриваемая | `read-outside-workspace` | Измерено как шумное на реальном трафике; Jev спрашивает, читаются ли содержимое файлов вне проекта. Чтение, которое пользователь просил, или одно, в котором проверка ничего не находит, отменяется; незапрошенное чтение, которое она отмечает, сохраняет блок. | +| `warn-git-amend` | пересматриваемая | `git-history-rewrite` | Изменение непустой коммита — обычное дело; вред — переписать историю, которую другие, возможно, подтянули. | +| `warn-destructive-sql` | пересматриваемая | `database-destruction` | Jev также спрашивает, является ли цель реальной базой данных, а не одноразовой тестовой. | +| `warn-global-package-install` | пересматриваемая | `system-modification` | То же самое: изменение машины вне проекта. | +| `block-failproofai-commands` | жёсткая | | `alwaysOn` самозащита. Никогда не пересматриваемая. | +| `block-rm-rf` | пересматриваемая | `destructive-deletion` | Эвристика глубины пути неправильно интерпретирует `rm -rf node_modules`; Jev спрашивает, является ли то, что будет уничтожено, восстанавливаемым. `rm -rf /` сохраняет оба зонда истинными. | +| `block-sudo` | жёсткая | | Повышение привилегий. | +| `block-curl-pipe-sh` | жёсткая | | Запускает код, загруженный из интернета. | +| `block-push-master` | жёсткая | | Пушит прямо в защищённую ветвь. | +| `block-work-on-main` | жёсткая | | `commit-on-protected-branch` охватывает ровно это, но режима инструкции, так что никогда не может ответить отказом, и никакая другая проверка это не охватывает. | +| `block-force-push` | пересматриваемая | `git-history-rewrite` | Зонд Jev — надмножество сопоставителя и учитывает `--force-with-lease`; то, что отменяет, — force-push собственной ветви. | +| `block-secrets-write` | пересматриваемая | `secret-exposure` | Совпадение пути не заякорено, так что `src/auth/credentials.ts` поймано; Jev спрашивает, пишется ли реальный ключевой материал. | +| `block-kubectl` | пересматриваемая | `production-infra-change` | Отрицает весь CLI, включая подкоманды только для чтения; Jev спрашивает, мутирует ли вызов и является ли цель производством. | +| `block-terraform` | пересматриваемая | `production-infra-change` | Одно и то же: отменяет `terraform plan` и `validate`. | +| `block-aws-cli` | пересматриваемая | `production-infra-change` | Одно и то же: отменяет `aws s3 ls`, `aws sts get-caller-identity`. | +| `block-gcloud` | пересматриваемая | `production-infra-change` | Одно и то же: отменяет `gcloud auth list`, `gcloud config list`. | +| `block-az-cli` | пересматриваемая | `production-infra-change` | Одно и то же: отменяет `az account show`. | +| `block-helm` | пересматриваемая | `production-infra-change` | Одно и то же: отменяет `helm list`, `helm status`. | +| `block-gh-pipeline` | жёсткая | | Запускает конвейеры, объединяет и изменяет секреты. | +| `warn-git-stash-drop` | жёсткая | | Никакая семантическая проверка не охватывает отбрасывание скрытой работы. | +| `warn-git-clean` | жёсткая | | `destructive-deletion` охватывает проблему, но явно не может на ней срабатывать: `git clean` не называет пути, так что его зонд `irreplaceable` судить не может и отвечает низко, и доказательство — минимум над зондами политики. Проверка, которая применяется и не срабатывает, отменяет решение, так что связывание здесь выключит политику. | +| `warn-all-files-staged` | жёсткая | | Никакая семантическая проверка не охватывает то, что широкий `git add` подхватывает. | +| `warn-schema-alteration` | жёсткая | | `database-destruction` охватывает удаление данных, не изменение схемы. | +| `warn-package-publish` | жёсткая | | Публикация необратима и никакая семантическая проверка это не охватывает. | +| `prefer-package-manager` | жёсткая | | Соглашение команды, а не решение безопасности. | +| `warn-large-file-write` | жёсткая | | Порог размера, а не решение, которое может принять Jev. | +| `warn-background-process` | жёсткая | | Никакая семантическая проверка не охватывает отделённые процессы. | +| `warn-repeated-tool-calls` | жёсткая | | Считает вызовы; Jev не может считать. | +| `sanitize-jwt` | жёсткая | | Редактирует выход инструмента; не ворота вызова инструмента. | +| `sanitize-api-keys` | жёсткая | | Редактирует выход инструмента; не ворота вызова инструмента. | +| `sanitize-connection-strings` | жёсткая | | Редактирует выход инструмента; не ворота вызова инструмента. | +| `sanitize-private-key-content` | жёсткая | | Редактирует выход инструмента; не ворота вызова инструмента. | +| `sanitize-bearer-tokens` | жёсткая | | Редактирует выход инструмента; не ворота вызова инструмента. | +| `require-commit-before-stop` | жёсткая | | Ворота завершения сеанса, не ворота вызова инструмента. | +| `require-push-before-stop` | жёсткая | | Ворота завершения сеанса, не ворота вызова инструмента. | +| `require-pr-before-stop` | жёсткая | | Ворота завершения сеанса, не ворота вызова инструмента. | +| `require-no-conflicts-before-stop` | жёсткая | | Ворота завершения сеанса, не ворота вызова инструмента. | +| `require-ci-green-before-stop` | жёсткая | | Ворота завершения сеанса, не ворота вызова инструмента. | + +## Имена семантических политик + +Это проверки, которые `FailproofAI/jev-policies` объявляет, и значения, которые `reviewedBy` принимает после его установки. Failproof AI не поставляет ни одну из них: без этого пакета (или другого, объявляющего эти имена), никакая политика, их называющая, не пересматривается. Каждая — это проверка, которую Jev отвечает о вызове инструмента перед ней. **Режим** — это то, что может ответить проверка: проверка `deny` блокирует на сильных доказательствах, в то время как проверка `instruct` только когда-либо предупреждает. Любой из них сохраняет отказ политики, когда она срабатывает и пользователь не просил вызов. **Пользователь может переопределить** говорит, отменяется ли это явной просьбой человека. + +Jev спрашивает ровно [проверки Jev](/ru/policies/publish-a-pack#jev-checks-in-a-pack), которые объявляют установленные пакеты, и это имена, которые `reviewedBy` принимает. Имя, которое два пакета объявляют по-разному, не чтится ни для одного. Одно из этих шестнадцати имён, объявленное пакетом, не установленным из репозитория FailproofAI, игнорируется в этом пакете: его версия никогда не запрашивается и не оспаривает FailproofAI собственную, так что сторонний пакет не может стать проверкой, которая отменяет политики основного пакета, и не может выключить одну из этих проверок. Нечитаемый список пакетов или пакет, чья каждая проверка неиспользуема, оставляет Jev ничего не спрашивать. + +| Имя | Режим | Пользователь может переопределить | Что Jev проверяет | +| --- | --- | --- | --- | +| `destructive-deletion` | deny | да | Постоянное удаление данных, которые не могут быть восстановлены. | +| `production-infra-change` | deny | да | Изменение активной инфраструктуры. | +| `git-history-rewrite` | deny | да | Переписывание или отбрасывание общей истории git. | +| `push-to-protected-branch` | instruct | да | Непосредственный push в защищённую ветвь. | +| `commit-on-protected-branch` | instruct | да | Коммит непосредственно на защищённой ветви. | +| `secret-exposure` | deny | да | Чтение или копирование учётных данных. | +| `credential-exfiltration` | deny | нет | Отправка секретов или приватных файлов с машины. | +| `remote-code-execution` | deny | да | Запуск кода, загруженного из интернета. | +| `privilege-escalation` | deny | да | Запуск с повышенными привилегиями. | +| `database-destruction` | deny | да | Уничтожение или массовое изменение данных БД. | +| `read-outside-workspace` | instruct | да | Чтение файлов вне проекта. | +| `agent-config-tampering` | deny | нет | Изменение собственной конфигурации безопасности агента. | +| `system-modification` | instruct | да | Изменение системы вне проекта. | +| `env-secrets-dump` | instruct | да | Печать секретов окружения. | +| `external-destructive-action` | deny | да | Необратимое действие через внешний инструмент. | +| `external-data-egress` | instruct | да | Отправка приватных данных во внешний инструмент. | \ No newline at end of file diff --git a/docs/ru/policies/jev-byok.mdx b/docs/ru/policies/jev-byok.mdx new file mode 100644 index 000000000..eba9ae420 --- /dev/null +++ b/docs/ru/policies/jev-byok.mdx @@ -0,0 +1,265 @@ +--- +title: "Jev evaluator (bring your own key)" +description: "Позвольте классификатору Jev от TypeSafe оценивать вызовы инструментов ваших агентов выше жёсткого порога regex через вашу собственную конечную точку и ключ Jev." +icon: "key-round" +--- + +Политики regex сопоставляют строки. Они не могут отличить `rm -rf build/`, которую вы просили, от `rm -rf ~`, которая просочилась в план, поэтому они блокируют слишком много в одном месте и слишком мало в другом. **Jev**, классификатор TypeSafe, читает вызов относительно того, что вы на самом деле просили, и отвечает на набор вопросов да/нет о нём в один быстрый запрос. + +Когда у вас есть собственная конечная точка Jev и ключ, Failproof AI спрашивает Jev о каждом вызове инструмента **наряду с** политиками regex, никогда вместо них: + +- Отказ **жёсткой** политики окончателен. Jev не может его отменить. Каждая политика жёсткая, если она явно не отмечена как проверяемая и не указывает проверки Jev, которые её охватывают, поэтому пользовательская, пакетная или облачная политика, которая ничего не говорит, жёсткая, и всегда включённая защита самозащиты всегда жёсткая. +- Отказ **проверяемой** политики может быть отменён, но только когда Jev было задано вопрос о точной проблеме, которую охватывает эта политика, и он ответил «здесь ничего нет» или «пользователь попросил это». Проверка, которая находит проблему реальной, когда пользователь не просил вызов, сохраняет отказ — даже когда собственный вердикт проверки всего лишь предупреждение, потому что перед вызовом инструмента предупреждение не останавливает агент. И когда эта проверка может отказать (утечка секретов, экфильтрация учётных данных, разрушительное удаление, …), ничто не очищается для этого вызова. +- Блокировка все ещё может стать **предупреждением**, когда вызов является шагом задачи, которую вы дали, и не заходит дальше: Jev смягчает свой собственный отказ в предупреждение, и это предупреждение — указывающее, что на самом деле не так с вызовом — заменяет блокировку политики. +- Jev также может предупредить или отказать самостоятельно, для вреда, который regex не описывает. +- Если Jev не может ответить (тайм-аут, лимит скорости, ошибка сервера, нет кредитов, неожиданная версия модели), этот вызов получает результат regex, в точности как без Jev. +- Jev никогда не делает вызов более разрешающим, чем ваши политики в одиночку, если он не прочитал весь вызов и не был спрошен о точной проблеме. Что-либо меньшее — вызов слишком большой для отправки целиком, подозреваемая инъекция — отменяет разрешения и сохраняет каждый отказ. + + +Без конфига Jev ничто не меняется: хуки запускают политики regex в точности как всегда. Конфиг — это весь opt-in. + + + +На FailproofAI Cloud? Вам не нужен собственный ключ: машина, подключённая с ключом, несущим `jev:evaluate`, может использовать Jev в плане вашей организации. См. [Jev через FailproofAI Cloud](/ru/policies/jev-cloud). + + +## Выберите поставщика + +Jev доступен через пять маршрутов. Принесите ключ для любого из них. + +| Поставщик | `--provider` | Конечная точка | Модель по умолчанию | Примечания | +| --- | --- | --- | --- | --- | +| TypeSafe | `typesafe` | `api.typesafe.ai/v1/systemone` | `jev-1.13.0` | Точное закрепление версии. | +| OpenRouter | `openrouter` | `openrouter.ai/api/v1/systemone` | `typesafe/jev-1.13` | Запросы маршрутизируются только на конечные точки без хранения данных, без отката на другого поставщика. Сообщает устаревшую версию, такую как `typesafe/jev-1.13-20260917`. | +| Vercel AI Gateway | `vercel` | `ai-gateway.vercel.sh/typesafe/v1/systemone` | `typesafe-ai/jev` | Именует Jev только псевдонимом, поэтому отвечающая версия записывается как непроверённая. | +| Cloudflare Workers AI | `cloudflare` | `api.cloudflare.com/client/v4/accounts//ai/run` | `typesafe/jev` | Требует `--account-id`. Измерено около шести вызовов в секунду на ключ перед HTTP 429. | +| Ваша собственная конечная точка | `custom` | `/systemone` | `jev-1.13.0` | Любая конечная точка, которая принимает тело запроса TypeSafe и сообщает, какая модель ответила. Только `https`; обычный `http://localhost` принимается только в режиме shadow. | + + +С собственной функцией bring-your-own-key Vercel неудачный запрос молча повторяется с учётными данными Vercel. Если вам нужно, чтобы каждый вызов был выставлен и виден только на вашем собственном аккаунте TypeSafe, используйте TypeSafe напрямую. + + +## Настройте это + +Одна команда, конечная точка и ключ: + +```bash +failproofai jev --url https://api.typesafe.ai/v1 --key-stdin < ~/typesafe.key +``` + +### URL выбирает поставщика + +Вам не нужно называть поставщика: **хост** URL — это который это. + +| Хост URL | Поставщик | Также требует | +| --- | --- | --- | +| `api.typesafe.ai` | `typesafe` | — | +| `openrouter.ai` | `openrouter` | — | +| `ai-gateway.vercel.sh` | `vercel` | — | +| `api.cloudflare.com` | `cloudflare` | `--account-id <32-hex-account-id>` | +| любой другой хост | `custom` | — URL, который вы дали, это базовый URL | + +Из этого следуют три вещи: + +- **URL, который является собственным API поставщика, не пишет переопределение.** `--url https://api.typesafe.ai/v1` создаёт в точности конфиг, который бы создал `--provider typesafe`. Дайте другой путь или хост на известном поставщике, и он сохраняется как базовый URL, как бы это сохранил `--base-url`. +- **`--provider` всё ещё переопределяет вывод**, что позволяет вам добраться к прокси, который говорит на API поставщика с хоста вашего собственного: `--url https://jev-proxy.internal/v1 --provider typesafe`. +- **`--provider`, который противоречит хосту, отказывается**, не угадывается. `--provider openrouter --url https://api.typesafe.ai/v1` ничего не пишет и объясняет почему: два написания не согласны о том, где ваш ключ вот-вот будет отправлен. Та же пара отказывается от `jev setup --base-url` и от настроек Jev панели управления. (`--provider custom` не является противоречием — это означает «обработайте этот URL как сам себя» — кроме хоста Cloudflare, чьей конечной точке для каждого аккаунта пользовательский маршрут не может добраться.) + +`--url` проверяется в точности как `baseUrl` в файле конфига, и отказывается в тех же словах: `https`, или простой `http://localhost` только в режиме shadow. + +### Ключ + +Передайте его с `--key-stdin`, или запустите команду в терминале без неё и вставьте ключ при замаскированном приглашении. В любом случае он идёт прямо в файл конфига и никогда не печатается обратно. + + + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --key-stdin < ~/typesafe.key + ``` + + + ```bash + failproofai jev --url https://openrouter.ai/api/v1 --key-stdin < ~/openrouter.key + ``` + + + ```bash + failproofai jev --url https://ai-gateway.vercel.sh/typesafe/v1 \ + --key-stdin < ~/vercel-gateway.key + ``` + + + ```bash + failproofai jev --url https://api.cloudflare.com/client/v4 \ + --account-id <32-hex-account-id> --key-stdin < ~/cloudflare.token + ``` + + + ```bash + failproofai jev --url https://jev.internal.example.com/v1 --key-stdin < ~/jev.key + ``` + + + +`failproofai jev setup` принимает те же флаги и является расширенной версией всего этого: `setup --provider ` где вы предпочли бы назвать поставщика, чем URL. + +### `--token`, и какова его стоимость + +`--token ` помещает ключ в командную строку, что является самым быстрым способом настроить машину и единственным написанием, которое оставляет ключ где-либо кроме файла конфига: + +```bash +failproofai jev --url https://openrouter.ai/api/v1 --token +``` + + +Аргумент командной строки находится в файле истории вашей оболочки впоследствии, и в то время как команда выполняется, она находится в списке процессов — читаема из `/proc` чем-либо, работающим как вы. `setup` говорит об этом каждый раз при использовании `--token`. Предпочитайте `--key-stdin` на машине, которой вы делитесь, в записанной сессии, или где-либо, где файл истории синхронизируется; поверните ключ, который вы передали таким образом, если это важно. + + +`--token`, `--key-stdin` и `--key-from-env` взаимно исключающие: дайте один. + +Затем отправьте один небольшой живой запрос, чтобы проверить ключ, конечную точку и какой Jev ответил: + +```bash +failproofai jev test +``` + +```text + failproofai jev test ok · 523 ms + + provider cloudflare + model asked typesafe/jev + answered by jev-1.13.0 (Jev 1.13 family — verified) + latency 523 ms — within the 3000 ms timeout +``` + +`jev test` выходит 1 и говорит об этом в его названии, когда ответ приходит после тайм-аута (каждый хук вернулся бы к regex как `timeout`) или отвечает на его контрольный вопрос неправильно. + +Хуки читают конфиг при каждом вызове инструмента, поэтому он применяется со следующего. Нечего перезапускать, с демоном или без. + +## Проверьте, что оно делает + +```bash +failproofai jev status +failproofai jev status --json +``` + +`status` показывает поставщика, конечную точку, модель, режим, файл конфига и его разрешения, и никогда не ключ. Ниже он суммирует недавнюю активность: сколько вызовов Jev оценил, как часто он возвращался к regex и почему, его задержку, и какие проверяемые политики он очистил. + +## Режим shadow + +`enforce` — это значение по умолчанию. Чтобы смотреть Jev без позволения ему что-либо изменять в любом решении, переключитесь на `shadow`: Jev всё ещё спрашивается и его вердикты записываются, но результат regex — это то, что применяется. + +```bash +failproofai jev setup --mode shadow +failproofai jev setup --mode enforce +failproofai jev setup --mode off +``` + +`off` сохраняет конфиг — конечную точку и ключ — и перестаёт спрашивать Jev: хуки запускают политики regex в точности как без конфига, и `failproofai jev status` говорит «off (switched off)». Переключитесь обратно с `--mode shadow` или `--mode enforce`. + +Повторный запуск `setup` для того же поставщика сохраняет сохранённый ключ, поэтому переключение режима — это один флаг. Переключение поставщика начинается заново и спрашивает ключ этого поставщика. То же самое для `--base-url`, который перемещает запросы на другой хост: сохранённый ключ отправляется только на хост, для которого он был дан, или на собственный API его поставщика. + +## Файл конфига + +Всё живёт в одном файле, `~/.failproofai/jev.json`, написанном `setup`: + +```json +{ + "provider": "cloudflare", + "apiKey": "", + "accountId": "<32-hex-account-id>", + "mode": "enforce", + "timeoutMs": 3000 +} +``` + +| Поле | Значение | +| --- | --- | +| `provider` | `typesafe`, `openrouter`, `vercel`, `cloudflare` или `custom` — или `failproofai`, чей ключ поступает из подключения FailproofAI Cloud вместо этого файла (см. [Jev через FailproofAI Cloud](/ru/policies/jev-cloud)). | +| `apiKey` | Отправлено как `Authorization: Bearer `. | +| `baseUrl` | Требуется для `custom`; заменяет базовый API поставщика иначе. Должен быть `https`. Простой `http` на `localhost` принимается только с `mode: shadow`: ничто не аутентифицирует локальный порт, поэтому пока ваш прокси выключен, любой процесс на машине, включая оцениваемый агент, может ответить вместо него. | +| `accountId` | Только Cloudflare: 32 строчных шестнадцатеричных символа. | +| `model` | Заменяет ID модели по умолчанию поставщика. Версионный ID должен назвать Jev 1.13. Значение, по форме напоминающее API ключ, отказывается (и не повторяется обратно), поэтому ключ, вставленный в `--model`, никогда не сохраняется или не отправляется как модель. | +| `timeoutMs` | Как долго вызов инструмента ждёт Jev перед использованием результата regex. 100–10000, по умолчанию 3000. | +| `mode` | `enforce` (по умолчанию), `shadow`, или `off` (сохраните конфиг, не запускайте Jev). | + +Три правила его защищают: + +- **Только владелец.** Оно написано с разрешениями `0600`. Копия, которую любой другой пользователь или группа может читать или писать, **отказывается**, и хуки возвращаются к regex до тех пор, пока вы не запустите `chmod 600 ~/.failproofai/jev.json` или `setup` снова. Директория также проверяется: `~/.failproofai` не должна быть **записываемой** кем-то ещё, потому что любой, кто может писать туда, может заменить файл, какими бы ни были его собственные разрешения. `setup` убирает те биты записи, если их находит. `failproofai jev status` говорит когда конфиг был отказан и показывает конечную точку, которую файл называет: кто-то ещё мог изменить его, поэтому проверьте что это ваш перед тем как `chmod`. Повторный запуск `setup` на таком файле переносит его сохранённый ключ только на собственный API поставщика; любая другая конечная точка, которую он называет, нужен ключ снова (`--key-stdin`), или `--base-url default` чтобы отправлять запросы обратно поставщику. +- **Только глобально.** Репозиторий не может включить Jev, направить его на другую конечную точку или выбрать его модель: `.failproofai/jev.json` внутри проекта игнорируется, и поставщик, URL, модель и ID аккаунта читаются только из этого файла — никогда из среды, которую параметры агента репозитория могут установить. (`FAILPROOFAI_HOME` не является способом обойти это: он перемещает всю директорию failproofai, включая ваши политики, а не переопределяет Jev самостоятельно.) +- **Только ключ может поступить из среды.** Если файл не имеет `apiKey`, `FAILPROOFAI_JEV_API_KEY` поставляет его для этой сессии (`setup --key-from-env` пишет такой файл). Это никогда не заменяет ключ, который файл держит, и не может включить Jev без файла. Где переменная не установлена, Jev просто выключен для этой оболочки: `failproofai jev status` говорит об этом, выходит 0 и оставляет конфиг в покое (`status --json` сообщает `"status": "key-missing"` с `"reason": "no-env-key"`). Демон `failproofaid` не видит окружение вашей оболочки, поэтому на машине, настроенной с `failproofai config`, сохраняйте ключ в файле. + +## Какой Jev отвечает + +Пороги решений Failproof AI были откалиброваны на Jev 1.13, поэтому ответ используется только когда он поступает из этого семейства: `jev-1.13.x`, или `typesafe/jev-1.13-` OpenRouter. Когда поставщик именует Jev только псевдонимом и не сообщает версию (Vercel и Cloudflare когда это не говорят), ответ используется и записывается как непроверённый. Пользовательская конечная точка должна сообщить модель, которая ответила; единственное исключение — это неверсионированное имя `--model`, которое вы для неё настроили, которое, повторённое обратно, записывается как непроверённое таким же образом. Ответ, сообщающий любую другую версию, или ответ `custom`, не сообщающий ничего, не используется: этот вызов возвращается к regex с причиной `model-mismatch`. + +## Когда Jev не может ответить + +Каждое из этих возвращается к результату regex для этого вызова и записывается с его причиной, которую `failproofai jev status` суммирует: + +| Причина | Причина события | +| --- | --- | +| `timeout` | Нет ответа в пределах `timeoutMs`. | +| `http-429` | Поставщик ограничил скорость ключа. | +| `rate-limited` | Собственный ограничитель Failproof AI удержал вызов перед отправкой: 5 запросов в секунду, в порциях до 5, и ни один момент после того как поставщик ответит `429`. Не поставщик. | +| `http-500`, `http-502`, `http-503`, … | Ошибка сервера у поставщика. Точный статус записывается. | +| `out-of-credits` | HTTP 402: аккаунт поставщика не имеет оставшихся кредитов. | +| `provider-refused` | HTTP 402 от Cloudflare читая «Model execution failed (Payment error)»: поставщик отказал запустить модель на этот запрос. Обычно не выставление счётов, поэтому пополнение кредитов не поможет. | +| `http-401`, `http-403` | Ключ был отказан. | +| `http-404` | Ничто не обслуживается в `/systemone`, поэтому базовый URL неправильный — `/systemone` добавляется к нему, и каждый поставщик обслуживает его в корне своей версии. `failproofai jev models` показывает что конечная точка обслуживает. | +| `network` | Конечная точка не могла быть достигнута. | +| `http-301`, `http-302`, `http-307`, `http-308` | Конечная точка ответила перенаправлением. Перенаправления никогда не следуют, поэтому ответ приходит только когда-либо из URL в вашем конфиге; установите `--base-url` на финальный URL. | +| `malformed` | Конечная точка ответила, но не с ответом Jev — тело, которое не JSON, или одно без ответов в нём. | +| `cloudflare-error`, `cloudflare-incomplete` | Конверт Cloudflare сообщил об отказе, или задача, которая не завершилась. | +| `model-mismatch` | Другая версия Jev, чем 1.13 ответила, или конечная точка `custom` не сказала какая модель ответила. | +| `request-cut` | **Не сбой.** Jev ответил; ему было показано только часть вызова, поэтому его ответ ничего не очистил. См. [Когда Jev ответил, но не на весь вызов](#when-jev-answered-but-not-on-the-whole-call). | + +`failproofai jev status` может также показать несколько редких причин, таких как `upstream-error` (ответ нёс собственную ошибку поставщика) или `config`, и суммирует любую причину, которую он не может назвать как `other`. + +`request-cut` находится в этой таблице потому что `failproofai jev status` суммирует это с остальным, и потому что это тоже оставляет каждый отказ стоять. Это единственная причина здесь, которая ничего не говорит о вашем поставщике: запрос прибыл и Jev на него ответил. В отличие от каждой строки выше неё, этот ответ все ещё считается — собственный отказ или предупреждение Jev применяется поверх результата regex а не отбрасывается. Поэтому период их означает вызовы достигают оценщика слишком большие чтобы отправить целиком, а не что ваша конечная точка нездорова, и пополнение кредитов или изменение URL не подвинет число. + +## Когда Jev ответил, но не на весь вызов + +Ещё две вещи могут случиться, и ни одна не является Jev неспособным ответить. Обе о том, сколько вызова, или разговора, уместилось в один запрос. + +**Часть самого вызова не уместилась.** Вызов инструмента отправляется внутри фиксированного бюджета, и огромный — очень большой `Write`, огромное тело MCP, команда заполненная до лимита — отправляется с тем что уместилось. Jev всё ещё отвечает, и его ответ все ещё считается: его собственный отказ или предупреждение применяется как обычно. Что оно не может сделать — это **очистить** что-либо, потому что вердикт дан на части вызова не является вердиктом на вызове. Поэтому каждый отказ политики стоит, и вызов записывается как откат с причиной `request-cut`, которую `failproofai jev status` суммирует наряду с причинами выше. Правило, которое это вам даёт: создание большего вызова может стоить ему его очистки, и никогда не может купить одну. + +**Сообщение не уместилось.** Длинная подсказка, которую вы вставили, последнее сообщение агента, или подсказка, которую хранилище этого оценщика уже ограничивало. **Ничто не меняется**: вызов судится, очищается и записывается в точности как любой другой, и не считается откатом. Длина того что вы печатаете никогда не решает вердикт, и разрез не может произвести согласие: где подсказка прибыла уже ограниченной, «вы не просили это» перестаёт быть заключением, которое может быть выведено из неё вообще, вместо того чтобы стать одним. + +Линия между ними — кто писал текст. Вызов агента, и правило, которое позволило бы его длине вычесть серьёзность, было бы правилом, которое агент может использовать; ваша подсказка — это ваша, и рассмотрение её длины как сигнала только когда-либо наказало вставку спецификации или трассировки стека. + +## Что покидает машину + +Для каждого вызова инструмента, который Jev оценивает, один запрос идёт вашему поставщику, несущему: + +- сам вызов инструмента, с секретами такими как API ключи, маркеры-носители и назначения `KEY=` отредактированными; +- недавние подсказки, которые вы печатали, с текстом, который добавило впряжение агента удалённым; +- последнее сообщение агента перед вашей последней подсказкой, отмеченное как написанное агентом; +- факты вычисленные локально, такие как находится ли путь внутри проекта — тот что была сессия в её первом рассмотренном вызове, [приколота для сессии](/ru/reference/jev-intent#the-project-root) — и текущая ветка git. + +Оно идёт только на конечную точку в вашем конфиге, под вашим ключом. + +## Выключите это + +```bash +failproofai jev remove +``` + +Это удаляет `~/.failproofai/jev.json`. С следующего вызова инструмента хуки запускают политики regex в точности как раньше. Хранилища для каждой сессии под `~/.failproofai/state/semantic/` (записанные подсказки в `sessions/`, корни проектов в `roots/`) оставляются на месте и стареют. Чтобы перестать спрашивать Jev но сохранить конфиг, используйте `failproofai jev setup --mode off` вместо этого. + +## Справочник команд + +| Команда | Результат | +| --- | --- | +| `failproofai jev --url --key-stdin` | Настройте это в одну команду; поставщик поступает из хоста URL | +| `failproofai jev --url --token ` | То же, с ключом в командной строке — ваша история и список процессов видят его | +| `failproofai jev setup --provider --key-stdin` | Напишите конфиг из ключа канализированного на stdin | +| `failproofai jev setup --provider ` | То же, спрашивая ключ при замаскированном приглашении | +| `failproofai jev setup --key-from-env` | Не сохраняйте ключ; читайте `FAILPROOFAI_JEV_API_KEY` за сессию | +| `failproofai jev setup --mode shadow` | Переключите режим (`enforce`, `shadow` или `off`), сохраняя сохранённый ключ | +| `failproofai jev setup --model ` / `--base-url ` | Переопределите модель или базовый API; `default` очищает переопределение | +| `failproofai jev setup --timeout-ms ` | Измените бюджет на вызов | +| `failproofai jev status [--json]` | Конфигурация, разрешения и недавняя активность; никогда ключ | +| `failproofai jev test [--json]` | Один живой запрос: задержка и версия которая ответила | +| `failproofai jev models [--provider ] [--url ] [--json]` | ID моделей, которые сообщает `/models` этой конечной точки, отмечая настроенную | +| `failproofai jev remove` | Удалите конфиг; Jev выключен | \ No newline at end of file diff --git a/docs/ru/policies/jev-cloud.mdx b/docs/ru/policies/jev-cloud.mdx new file mode 100644 index 000000000..334d169f6 --- /dev/null +++ b/docs/ru/policies/jev-cloud.mdx @@ -0,0 +1,117 @@ +--- +title: "Jev через FailproofAI Cloud" +description: "Позвольте Jev оценивать вызовы инструментов ваших агентов через FailproofAI Cloud по тарифу вашей организации без собственного аккаунта TypeSafe или ключа." +icon: "cloud" +--- + +[Jev](/ru/policies/jev-byok), классификатор TypeSafe, анализирует каждый вызов инструмента в соответствии с тем, что вы действительно запросили, и выносит решение на основе ваших политик, но не вместо них. Через **FailproofAI Cloud** подключённая машина использует Jev с тем же ключом, с которым она уже подключена: без аккаунта TypeSafe, без второго ключа, без конечной точки для настройки. Каждый вызов учитывается в рамках существующего лимита тарифа вашей организации. + +Всё, что делает Jev, остаётся неизменным по сравнению с [конфигурацией с собственным ключом](/ru/policies/jev-byok): жёсткие политики остаются окончательными, отказ проверяемой политики очищается только когда Jev был спрошен о том же самом вопросе, а любой сбой откатывается к результату регулярного выражения для этого вызова. + + +Требуется **failproofai 1.0.8-beta.0** или позже. 1.0.7 не имеет Jev, хотя версионно стоит выше бета-версий 1.0.7. Без конфигурации Jev ничего не меняется: хуки запускают политики регулярных выражений точно так же, как всегда. + + +## Включение + +1. **Создайте ключ с Jev.** На панели управления FailproofAI Cloud откройте **Keys → Create key** и выберите предустановку **machine**. Она предоставляет три разрешения, необходимые машине: `events:add` (отправить активность), `policies:pull` (получить политики) и `jev:evaluate` (Jev, учитывается в тарифе вашей организации). Ключ не может иметь `jev:evaluate` без двух других. +2. **Подключите машину** с этим ключом: + + ```bash + failproofai config --token + ``` + + Если ваша организация запускает свой собственный FailproofAI Cloud вместо размещённого сервиса, добавьте его адрес: `--url https://` (или экспортируйте `FAILPROOFAI_CLOUD_URL`). Без этого ключ проверяется по размещённому сервису и подключение не удаётся. Если сертификат этого хоста выдан приватным УЦ, установите УЦ в хранилище системных сертификатов машины (например с `update-ca-certificates`), не только в `NODE_EXTRA_CA_CERTS`: демон, отправляющий события и получающий политики, читает системное хранилище. См. [Troubleshooting](/ru/reference/troubleshooting). + +Это всё. Подключение сохраняет ключ и, когда машина ещё **не имеет** конфигурацию Jev, включает Jev через FailproofAI Cloud в режиме **shadow**: Jev спрашивают о каждом управляемом вызове инструмента и его решения записываются, но результат вашей политики — это то, что применяется. Вывод об этом говорит: + +```text + Jev on through FailproofAI Cloud, in shadow mode: logged, not enforced (~/.failproofai/jev.json). +``` + +**С `--no-transcripts` подключение не включает Jev.** Jev отправляет каждый проверенный вызов инструмента и недавний запрос на FailproofAI Cloud, что больше, чем требует подключение, передающее только решения. Ключ всё ещё сохраняется, и вывод говорит, что Jev доступен и как его включить: + +```bash +failproofai jev setup --provider failproofai +``` + +Это также не отключает Jev. Если файл `jev.json` машины уже запускает Jev через FailproofAI Cloud, он остаётся без изменений, и вывод говорит, что Jev всё ещё отправляет каждый проверенный вызов инструмента и недавний запрос, и что `failproofai jev setup --mode off` его отключает. + + +Подключение **никогда не перезаписывает** существующий `~/.failproofai/jev.json`. Если вы уже используете собственную конечную точку Jev, она продолжит использоваться, и вывод говорит, что файл остался как настроен — и, когда этот файл оставляет Jev отключённым (отклонено или переключено), это говорит и как исправить. Чтобы переключить эту машину на FailproofAI Cloud, запустите `failproofai jev setup --provider failproofai`. + + +## Shadow, enforce или off + +Начните с shadow, посмотрите, что бы сделал Jev на странице политик, затем позвольте ему действовать: + +```bash +failproofai jev setup --mode enforce # Решения Jev применяются: может очистить отказ проверяемой политики и добавить свой +failproofai jev setup --mode shadow # Jev спрашивают и записывают; результат вашей политики применяется +failproofai jev setup --mode off # Сохранить конфигурацию, перестать спрашивать Jev +``` + +Тот же переключатель находится на локальной панели управления: **Settings → Jev** имеет переключатель включения/выключения и shadow/enforce. Он переписывает только режим. Хуки читают конфигурацию при каждом вызове инструмента, поэтому изменение применяется со следующего вызова без перезагрузки. + +## Проверка работы + +```bash +failproofai jev status +failproofai jev test +``` + +`status` показывает провайдера как **FailproofAI Cloud**, хост Cloud, к которому подключена машина, режим и источник ключа как **FailproofAI Cloud connection**, никогда сам ключ. Когда `jev.json` FailproofAI Cloud на месте, но Jev не может запуститься, он говорит почему: + +| `status` говорит | `status --json` | Значение | +| --- | --- | --- | +| **off — для подключения FailproofAI Cloud этой машины не сохранён ключ Jev** | `key-lacks-jev` | Машина подключена, но для неё не сохранён ключ Jev: ключ не имеет `jev:evaluate` или подключение не могло его подтвердить. Запустите `failproofai config --token ` снова с тем же ключом; если у него нет разрешения, используйте ключ **machine**. | +| **off — эта машина не подключена к FailproofAI Cloud** | `not-connected` | На этой машине нет подключения FailproofAI Cloud, к которому мог бы принадлежать ключ Jev. | + +После `failproofai config --disconnect` больше нет `jev.json` FailproofAI Cloud (если только он не был переключен на отключение, что сохраняется), поэтому `status` просто сообщает, что Jev отключён. `status --json` содержит те же факты (`provider: "failproofai"`, `keySource: "cloud"`, `cloudConnected`, `keyCarriesJev`), также когда конфигурация отсутствует или отклонена. `permissions` всегда из `jev.json`; отказ о `credentials.json` добавляет `credentialsPermissions`, и `fix` когда одна команда это исправляет. `test` отправляет один живой запрос и сообщает его задержку и версию Jev, которая ответила. Он выходит с кодом 1 и говорит об этом в названии, когда ответ приходит после тайм-аута хука (хуки запишут `timeout`) или отвечает на проверочный вопрос неправильно. + +Панель **Settings → Jev** на панели управления также показывает **подключение FailproofAI Cloud**: в какую организацию сообщает машина и есть ли в её ключе Jev. Это читается из собственных файлов машины без сетевых вызовов. + +## Что попадает на страницу политик + +Машина уже отправляет активность своих хуков на FailproofAI Cloud (`events:add`). С включённым Jev запись каждого управляемого вызова также указывает, какой оценщик запустился, что решил Jev, какие политики он очистил, почему откатился когда это произошло, его задержку и модель, которая ответила — решения, коды и имена, никогда команду или ваш запрос. На странице **Policies** вашей организации: + +- вызов, решение которого принял сам Jev (режим enforce), отнесён к **Jev**, и когда решающая проверка пришла из пакета, запись также называет этот пакет и его версию; +- в режиме shadow отказ или предупреждение Jev появляется как **would-have**, рядом с наблюдаемыми развёртываниями; +- политики, которые Jev очистил или очистил бы в режиме shadow, подсчитываются по политике. + +## Когда Jev не может ответить + +Каждое из этого откатывается к результату вашей политики для этого вызова и записывается с причиной: + +| Причина | Причина | +| --- | --- | +| `out-of-credits` | Ваша организация использовала лимит своего тарифа. | +| `http-401`, `http-403` | Ключ был отозван или не имеет `jev:evaluate`. Переподключитесь с ключом, который имеет. | +| `http-429` | FailproofAI Cloud ограничивает скорость Jev для вашей организации. До истечения затребованного времени ожидания (его `Retry-After`, максимум 60 секунд) машина ничего не отправляет и каждый вызов откатывается сразу. Задержанные вызовы записываются как `http-429` или как `rate-limited` когда собственное ограничение скорости машины их держит первым. | +| `http-429` (дневной лимит) | Ваша организация использовала дневной лимит вызовов Jev: **10 000 за UTC день**, если только оператор вашего FailproofAI Cloud не установил другой лимит. Каждый вызов откатывается до сброса счётчика в 00:00 UTC; машина всё ещё спрашивает максимум один раз в минуту, поэтому замечает сброс в течение минуты. `failproofai jev test` говорит "Daily Jev limit for this org reached; resets at 00:00 UTC." | +| `http-422` | Jev отклонил запрос этого вызова, обычно потому что вызов инструмента содержал плотный текст (base64, hex, минифицированный код) сверх лимита токенов Jev. Этот вызов откатывается каждый раз; это не авария. | +| `http-502` | Jev недоступен прямо сейчас. | +| `http-503` | Этот Cloud не может служить Jev для вашей организации: нет модельного шлюза, организация ещё не подготовлена или шлюз неработающий. Спросите администратора; хуки спрашивают снова максимум один раз в минуту. | +| `http-404` | Этот FailproofAI Cloud ещё не обслуживает Jev. | +| `timeout` | Нет ответа в течение `timeoutMs` (по умолчанию 3000). | +| `model-mismatch` | Ответила другая версия Jev, не 1.13. | + +## Где живёт ключ и куда он идёт + +- Ключ сохраняется один раз в `~/.failproofai/credentials.json` (`0600`, в каталоге только для владельца), рядом с другими учётными данными FailproofAI Cloud. `jev.json` не содержит ключ для этого маршрута; написанный туда делает конфигурацию недействительной. +- Если `credentials.json` имеет **любое** разрешение для кого-то, кроме вас (группа или другие, чтение или запись), или его каталог может быть **написан** кем-то, кроме вас, это **отклонено**, не читается, и Jev отключен до тех пор, пока вы не исправите: `chmod 600` на файле, `chmod 700` на каталоге (или переподключитесь, что переписывает файл в `0600` и делает каталог только для владельца). Каталог, который другие могут только читать, подходит; который они могут писать, позволяет им обменять файл. +- Ключ считается только пока подключение, с которым он пришёл, на машине: политика или учётные данные отчётности для того же FailproofAI Cloud **с тем же ключом**, в том же файле. Оставленный ключ Jev без одного игнорируется и Jev остаётся отключённым. Это происходит когда более старый failproofai's `config --disconnect` оставляет ключ Jev на месте (он не знает его удалять), или когда более старый failproofai's `config --token` подключается с другим ключом, который на FailproofAI Cloud может принадлежать другой организации. Чтобы переключить Jev обратно на включение, подключитесь снова с ключом **machine**. +- Ключ отправляется только на начало Cloud, на котором он был проверен. `jev.json`, указывающий куда-то ещё, отклонён. +- **Агент на машине может его прочитать.** `credentials.json` только для владельца и агент запускается как этот владелец. Чтение собственных файлов failproofai разрешено намеренно (только изменение их заблокировано `block-failproofai-commands`), поэтому единственное, что стоит между агентом и этим файлом — это `block-read-outside-cwd` — *проверяемая* политика — и из сессии, начатой в вашем домашнем каталоге, ничего. Ключ с `jev:evaluate` тратит лимит Jev вашей организации (до дневного лимита) откуда бы он ни использовался, поэтому относитесь к машинному ключу как к любым другим учётным данным расходов: если агент мог его прочитать, отключите его на странице Keys и переподключитесь с новым. +- Только ваши глобальные файлы это решают. Репозиторий не может включить Cloud Jev, указать его на другое место или предоставить его ключ, и `FAILPROOFAI_JEV_API_KEY` игнорируется для этого маршрута. +- Для каждого вызова, который Jev оценивает, один запрос идёт на FailproofAI Cloud с тем, что [страница bring-your-own-key](/ru/policies/jev-byok#what-leaves-the-machine) указывает (секреты отредактированы). FailproofAI Cloud пересылает его на TypeSafe и не логирует или не сохраняет. + +## Отключение + +| Команда | Результат | +| --- | --- | +| `failproofai jev setup --mode off` | Сохранить конфигурацию; Jev не спрашивается. **Это переключатель, который длится:** повторное подключение никогда не переписывает существующий `jev.json`, поэтому Jev остаётся отключённым до тех пор, пока вы не переключите его обратно с `--mode shadow`. | +| `failproofai jev remove` | Удалить `~/.failproofai/jev.json`; Jev отключен — до следующего `failproofai config --token` с ключом, который имеет `jev:evaluate`, который находит отсутствующий `jev.json` и включает Jev снова в режиме shadow (если только не работает с `--no-transcripts`). Чтобы держать его отключённым, используйте `--mode off`. | +| `failproofai config --disconnect` | Отключить машину: ключ удален и так же `jev.json` когда он называет FailproofAI Cloud и не переключен на отключение. `jev.json` для вашей собственной конечной точки остаётся и так же переключённый на отключение, поэтому Jev остаётся отключённым когда вы подключитесь снова. | + +Со следующего вызова инструмента хуки запускают политики регулярных выражений точно как раньше. \ No newline at end of file diff --git a/docs/ru/policies/jev.mdx b/docs/ru/policies/jev.mdx new file mode 100644 index 000000000..541a73f36 --- /dev/null +++ b/docs/ru/policies/jev.mdx @@ -0,0 +1,45 @@ +--- +title: "Jev policies" +description: "Добавьте живую проверку Jev к контролируемым вызовам инструментов, а затем проверьте её перед применением решений." +icon: "shield-check" +--- + +Jev анализирует вызов инструмента с учётом того, что пользователь попросил агента сделать. Используйте её, когда политика на основе совпадения строк блокирует допустимую работу или пропускает рискованное действие, требующее контекста. Она отвечает наряду с вашими политиками на вентилях `PreToolUse` или `PermissionRequest`. Для оценки **после** завершения сеанса используйте [оценки Jev](/ru/evaluations/jev). + +## Начните с режима наблюдения + +Установите Failproof AI и подключите hooks к [поддерживаемому адаптеру](/ru/reference/harnesses). Используйте failproofai версии 1.0.8-beta.0 или выше. + +Failproof AI не поставляется с проверками Jev. Установите их как пакет, иначе Jev не будет ничего спрашивать и никогда не будет вызываться: + +```bash +failproofai policies add FailproofAI/jev-policies +``` + +Затем выберите, как запросы достигнут Jev: + +| Маршрут | Первый шаг | +| --- | --- | +| FailproofAI Cloud | Подключитесь с использованием **machine** ключа с правом `jev:evaluate`. На машине без конфигурации Jev команда `failproofai config` включит Jev в режим наблюдения. | +| Ваш провайдер | В локальной панели управления откройте **Settings → Jev**, выберите провайдера, вставьте его токен и выберите **observe**. Или запустите `failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key`. | + +![Параметры Jev в локальной панели управления: провайдер, конечная точка, токен и режим наблюдения перед включением Jev.](/images/dashboard/jev-settings.png) + +```bash +failproofai jev status +failproofai jev test +``` + +`test` проверяет конечную точку. Для проверки пути hook попросите подключённого агента использовать инструмент чтения файлов на `README.md`. Убедитесь, что этот вызов инструмента появляется в сеансе, затем проверьте **Policies → Activity** в [локальной панели управления](/ru/reference/local-dashboard#review-policy-activity). Счётчик Jev в `status` должен увеличиться. Режим наблюдения записывает, что бы решила Jev, пока применяется результат вашей существующей политики. + +## Решите, когда начать применение + +**Жёсткая** политика всегда имеет последнее слово. Jev может отменить отказ только из политики, явно отмеченной как **reviewable**, и только когда она проверила именованное беспокойство этой политики. Перед тем как полагаться на разрешение, см. [авторитет политики](/ru/policies/authority). Jev также может предупредить или запретить самостоятельно. Если она не может ответить, результат политики решает этот вызов. + +Как только результаты наблюдения будут выглядеть правильно, переключитесь в режим применения в **Settings → Jev** или запустите: + +```bash +failproofai jev setup --mode enforce +``` + +Информацию об URL провайдеров, облачных ключах, конфигурации, резервных вариантах и данных, отправляемых с каждым запросом, см. в [справочнике интеграции Jev](/ru/reference/jev). \ No newline at end of file diff --git a/docs/ru/reference/custom-agents-typescript.mdx b/docs/ru/reference/custom-agents-typescript.mdx new file mode 100644 index 000000000..d57260f78 --- /dev/null +++ b/docs/ru/reference/custom-agents-typescript.mdx @@ -0,0 +1,401 @@ +--- +title: "Custom agents (TypeScript)" +description: "Configuration, the event catalog, the scopes and the framework adapters for @failproofai/sdk." +icon: "square-js" +--- + +Справочник по всем параметрам, методам и полям TypeScript SDK. Если вы впервые внедряете инструментарий, начните с руководства — эта страница предназначена для справок. + + + + Установка, внедрение, методы событий, практический пример и типичные проблемы. + + + Те же события, тот же формат передачи, один и тот же спул — из Python. + + + +Node 20.9 или новее. ESM и CommonJS. Без зависимостей времени выполнения. + + + Этот SDK и Python SDK пишут **одни и те же события в один спул**. Флот с Node-агентами и Python-агентами создаёт один набор сессий, а не два, и ничто в панели управления их не различает. Выбирайте по услугам, а не по компаниям. + + +## Установка + +```bash +npm install @failproofai/sdk +``` + +```ts +import * as failproofai from "@failproofai/sdk"; + +await failproofai.agent("planner", { goal: question }, async () => { + const hits = await failproofai.toolCall("web_search", { input: { q } }, () => search(q)); +}); +``` + +Адаптеры фреймворков поставляются в самом пакете. Фреймворки — это **дополнительные одноранговые зависимости** — объявленные, чтобы поддерживаемые диапазоны были видны, никогда не устанавливаемые от вашего имени и импортируемые только при вызове `instrument()`. + +## Подключение демона Failproof + +Идентично Python SDK: создайте ключ `events:add` в разделе **Admin → Keys**, затем [подключите демон](/ru/start/setup#connect-a-machine-to-cloud) на машине агента. SDK пишет на диск; демон его отправляет. + +## Конфигурация + +```ts +failproofai.configure({ + environment: "production", + flushInterval: 0.5, + baseDir: undefined, +}); +``` + +| Опция | Что она делает | +| --- | --- | +| `environment` | Метка на каждом событии — `production`, `staging`, `prod-eu`. По умолчанию `dev`. | +| `flushInterval` | Как часто таймер пишет на диск, в секундах. По умолчанию `0.5`. | +| `baseDir` | Где писать. По умолчанию спул демона, что вам нужно, если вы не знаете обратное. | + +Ничего не применяется, пока всё не будет проверено, поэтому отклонённый вызов оставляет SDK в том же состоянии, а не с новым `baseDir` и старым интервалом. + +Установите через переменную окружения: + +| Переменная | Что она делает | +| --- | --- | +| `AGENTEYE_ENVIRONMENT` | Устанавливает `environment` без изменения кода. Опция `configure()` её переопределяет. | +| `FAILPROOFAI_HOME` | Переносит корень Failproof AI, который содержит спул. | +| `FAILPROOFAI_SDK_LOG_LEVEL` | `debug`, `info`, `warn` (по умолчанию), `error`, `silent`. | +| `FAILPROOFAI_SDK_STRICT` | `1` заставляет ошибки инструментария выбрасывать исключение вместо логирования. | +| `FAILPROOFAI_SDK_STRICT_INTEGRATIONS` | `1` заставляет проблему совместимости фреймворка выбрасывать исключение вместо предупреждения и продолжения. | + + + **Без запятых в `environment`.** Ingest разбивает это поле по запятым, чтобы построить фильтры, и пропускает любое событие, чья метка их содержит — поэтому целый запуск молча исчезает. Пишите `prod-eu`, а не `prod,eu`. + + `configure({ environment: "prod,eu" })` выбрасывает исключение, чтобы вы узнали немедленно. `AGENTEYE_ENVIRONMENT` не может выбросить — никто вас не вызывает — поэтому предупреждает один раз и возвращается к `dev`. + + +Маршрутизируйте собственные логи SDK в ваш логгер с помощью `failproofai.setLogger({ debug, info, warn, error })`. + +## Выключение + +Буферизованные события сбрасываются при `process.on("exit")`. + +Процесс, убитый сигналом, никогда туда не попадает, и Node по умолчанию для `SIGTERM` — это завершение без запуска обработчиков выхода — поэтому контейнеризованный агент теряет то, что последний интервал не записал. + + + **Этот SDK не будет устанавливать обработчик сигналов за вас.** Регистрация изменяет поведение вашего процесса: слушатель подавляет завершение Node по умолчанию, поэтому библиотека, которая добавила бы его, молча остановила бы работу Ctrl-C. Добавьте свой: + + ```ts + for (const signal of ["SIGINT", "SIGTERM"] as const) { + process.once(signal, () => { + failproofai.flushSync(); + process.exit(0); + }); + } + ``` + + +Короткоживущий скрипт или бессерверный обработчик должны `await failproofai.flush()` перед возвратом — интервал один не гарантирует доставку. + +## Идентификация + +Каждое событие принадлежит сессии и агенту. **Области заполняют оба**, поэтому вы редко их передаёте: + +```ts +await failproofai.session(async () => { + await failproofai.agent("planner", async () => { + failproofai.event.toolUse({ toolName: "search", toolCallId: "c1" }); + }); +}); +``` + +Явная передача `sessionId` или `agentId` всё ещё работает и побеждает. Если ни одна не привязана и не передана, вызов выбрасывает исключение вместо выдачи события, которое Cloud молча отклонит. + + + Идентификация работает на `AsyncLocalStorage`. Она следует `await`, `.then()`, таймерам и любому обратному вызову, созданному внутри области. Она **не** следует обратному вызову, сохранённому во время одного запуска и вызванному во время другого, или работе, переданной через границу `worker_threads` — оборачивайте их в `failproofai.propagate()` или их события приземлятся без привязки. + + +### Области + +| Область | Выдачи | Возвращает | +| --- | --- | --- | +| `session(body)` | ничего — только идентификация | что угодно возвращает `body` | +| `agent(id, options?, body)` | `agent_start`, затем `agent_end` | что угодно возвращает `body` | +| `toolCall(name, options?, body)` | `tool_use`, затем `tool_result` | что угодно возвращает `body` | + +Синхронный блок остаётся синхронным: `agent("x", () => 1)` возвращает `1`, не обещание. + +`toolCall` записывает разрешённое значение блока как `output` инструмента, если только вы не назначите `call.output` самостоятельно. + + + +| Что произошло | События | `outcome` | +| --- | --- | --- | +| блок вернулся | `agent_end` | `"success"`, или ваш `outcome` | +| блок выбросил | `error`, затем `agent_end` | `"failed"` | +| `AbortError` | только `agent_end` | `"cancelled"` | + +Ошибка всегда переотправляется. + +Отказ инструмента записывается на листе — `tool_result` с `error` строкой — и выдачи **нет** запуска на уровне события `error`. Один, который ловит цикл агента, — это не отказ запуска, и один, который распространяется, — это сообщается ровно один раз, вмещающим `agent()`. + + + + + +Когда работа — это не одна функция — область, открытая в конструкторе и закрытая в слёте, или та, что охватывает существующий поток управления: + +```ts +{ + using span = failproofai.agent.open("planner", { goal }); + using call = failproofai.toolCall.open("search", { input: { q } }); + call.call.output = await search(q); +} // tool_result, затем agent_end +``` + +Обе формы выдают идентичные в байтах события. Предпочитайте форму обратного вызова: она выполняется внутри `AsyncLocalStorage.run()`, поэтому нечего разворачивать и весь класс ошибок «открыто здесь, закрыто там» недостижим. + +Блок `using`, который ловит собственный отказ, сообщает о нём с помощью `span.fail(error)` — располагатель не имеет собственного канала исключения. + + + +## Каталог событий + +Те же пятнадцать методов, что и Python SDK, в camelCase. Большинство идут **парами** — вы вызываете открытие, затем закрытие, и SDK рассчитывает разрыв. + +| | Открывает | Закрывает | +| --- | --- | --- | +| **Агенты** | `agentStart` | `agentEnd` | +| | `agentPause` | `agentResume` | +| **Модели** | `modelRequest` | `modelResponse` | +| **Инструменты** | `toolUse` | `toolResult` | +| **Хуки** | `hookTriggered` | `hookCompleted` | +| **Люди** | `humanWait` | `humanInput` | + +Три стоят отдельно: `error`, `humanPause`, `humanInterrupt`. + + + +Каждый метод также принимает `sessionId` и `agentId`, которые области заполняют за вас. Всё пропущенное отбрасывается, а не отправляется как JSON `null`. + +| Метод | Требуется | Опционально | +| --- | --- | --- | +| `agentStart` | — | `goal`, `parentId` | +| `agentEnd` | — | `outcome`, `summary` | +| `agentPause` | `pauseId` | `reason`, `userId` | +| `agentResume` | `pauseId` | `reason`, `userId` | +| `modelRequest` | — | `model`, `messages`, `system`, `tools`, `requestId` | +| `modelResponse` | — | `model`, `stopReason`, `inputTokens`, `outputTokens`, `content`, `role`, `requestId` | +| `toolUse` | `toolName`, `toolCallId` | `input` | +| `toolResult` | `toolName`, `toolCallId` | `output`, `error` | +| `hookTriggered` | `hookName`, `hookId` | `triggerEvent`, `input` | +| `hookCompleted` | `hookName`, `hookId` | `outcome`, `output`, `error` | +| `error` | `errorType`, `message` | `traceback` | +| `humanWait` | `inputId` | `prompt`, `options`, `reason` | +| `humanInput` | `inputId` | `response` | +| `humanPause` | — | `reason`, `userId` | +| `humanInterrupt` | — | `reason`, `userId`, `atStep` | + +Любой другой ключ, который вы добавите, становится полем пользовательской нагрузки. Пространство имён всё специфичное для фреймворка как `fw_*`; имя, которое конфликтует с объявленным полем, отклоняется, а не молча переписывает повышенный столбец. + + + + + **`duration_ms` рассчитывается, не принимается.** Четыре метода закрытия рассчитывают разрыв от своего открытия и отклоняют поставляемый вызывающим `duration_ms` — сообщённая продолжительность неопровержима. + + Пары сопоставляются по **сессии** и id, никогда не по агенту. Инструмент, открытый под `planner` и закрытый под `worker`, всё ещё соответствует, что и делают вложенные многоагентные запуски. + + +## Адаптеры фреймворков + +```ts +await failproofai.instrument(); // всё, что возможно найти +await failproofai.instrument("langchain"); // точно один +failproofai.uninstrument(); // восстановить всё +``` + +| Фреймворк | Поддерживается | Как он крепится | +| --- | --- | --- | +| **LangChain.js / LangGraph.js** | `@langchain/core` 0.3 – 1.x, LangGraph.js 0.4 – 1.x | `CallbackManager.configure`, поэтому каждый `invoke`/`stream`/`batch` охвачен без передачи `callbacks:` где-либо — или передайте `langchainHandler()` самостоятельно и ничего не патчьте. | +| **Vercel AI SDK** | `ai` 4 – 7 | `telemetry()` на месте вызова, или `instrument("ai")` для всего процесса на `ai` 7 (на 4–6 это опционально — см. ниже). | +| **Mastra** | `@mastra/core` 0.20 – 1.x | `Agent.generate`/`.stream`, разрешение модели агента и инструмента, и движок запуска/шага рабочего процесса. | +| **LlamaIndex.TS** | `llamaindex` 0.11.4 – 0.x | `Settings.callbackManager` (подписано) плюс `AgentWorkflow.runStream`, для запусков рабочего процесса и их шагов. | + +Каждый диапазон протестирован против реальных выпусков фреймворков на обоих концах как модуль ES и CommonJS при каждом запуске CI. + +Сопоставление — Python SDK, поэтому одна и та же программа рисует одно дерево на любом языке. Конструкция — это **агент** только если он владеет циклом решения LLM — запуск графика или цепи, вызов `generateText`/`streamText` AI SDK, агент Mastra, запуск агента LlamaIndex. Узел LangGraph или шаг рабочего процесса — это **хук** (`hook_triggered`/`hook_completed`), никогда не вложенный агент. Вызовы модели — это пары `model_request`/`model_response` с подсчётом токенов; вызовы инструмента несут собственный id вызова инструмента модели. Отказ записывается один раз на событие, которое он произошёл. + +Адаптер, который не установился, логируется и пропускается; остальные всё ещё устанавливаются, потому что сломанный LlamaIndex не должен вам стоить LangGraph. + + + `instrument()` без аргумента обнаруживает фреймворк по тому, **разрешается** ли он, а не по тому, импортирован ли он уже — Node не обнажает эквивалент Python `sys.modules` для модулей ES. Фреймворк, который вы установили, но не используете, будет импортирован и спатчен. Назовите тот, который вам нужен, если это важно. + + + + Большинство этих фреймворков поставляют сборку модуля ES и сборку CommonJS, которые Node загружает как две несвязанные копии. Адаптеры патчат копию, которую загружает ваше приложение (и копию CommonJS тоже, если что-то уже `require`'d), поэтому оба модульных системы работают. Фреймворк **включённый в вашу собственную выходную** через esbuild или webpack недостижим — используйте там помощники на месте вызова: `langchainHandler()`, `telemetry()`, `wrapTool()`. + + +### LangChain без патчинга + +```ts +import { langchainHandler } from "@failproofai/sdk/langchain"; +await graph.invoke(input, { callbacks: [langchainHandler()] }); +``` + +Обработчик работает с `instrument()` или без и никогда не двойной записи. `instrument("langchain")` берёт `sessionId`, `captureContent`, `includeChains`, `graphCallbacks` и `captureLimit`, как Python адаптер; `metadata: { failproofai_sdk_session_id }` на вызове выбирает сессию для этого вызова. + +### Vercel AI SDK + +AI SDK экспортирует простые функции из модуля ES, и пространство имён модуля ES неизменяемо по спецификации — там нечего патчать. Оно использует точки расширения, которые документирует сам SDK: + +```ts +import { telemetry } from "@failproofai/sdk/ai"; + +const { text } = await generateText({ + model, + prompt, + experimental_telemetry: telemetry({ functionId: "answer-question" }), + // на ai 7, `telemetry: telemetry({ … })` — тот же объект, новое имя +}); +``` + +Это полная интеграция: диапазон агента, пара запроса/ответа модели за шаг с подсчётом токенов, и каждый вызов инструмента. Один вызов работает на каждом основном — `ai` 4–6 читают трассировщик, который он несёт, `ai` 7 интеграцию телеметрии. + +`instrument("ai")` делает то же самое во всём процессе **на `ai` 7**: каждый вызов через глобальный список интеграции телеметрии AI SDK, который аддитивен и ничего не берёт у кого-либо ещё. + +**На `ai` 4–6, `instrument("ai")` ничего не записывает сам по себе и логирует одно предупреждение об этом.** Единственный глобальный хук, который имеют эти основные, — это поставщик глобального трассировщика OpenTelemetry — один слот, который OpenTelemetry отказывается передать один раз. Регистрация нашего молча отклонит ваш собственный `NodeSDK.start()` позже при запуске и отправит ваши http/database диапазоны трассировщику, который ничего не экспортирует. Используйте `telemetry()` на месте вызова или `wrapModel` там. Если процесс не запускает собственный OpenTelemetry, согласитесь с `instrument("ai", { registerGlobalTracer: true })`: затем он записывает каждый вызов, который проходит `experimental_telemetry: { isEnabled: true }`, и берёт слот только если он всё ещё пуст. `registerGlobalTracer: false` сохраняет значение по умолчанию и молчит предупреждение. + +Если вы предпочитаете обернуть модель один раз, `wrapModel` видит только вызовы модели, потому что вызовы инструмента происходят выше слоя модели. Обёрнутая модель, вызванная ничем вокруг неё, записывается как собственный запуск. Потоковый вызов закрывается как бы ни остановился поток — `stop_reason: "cancelled"` когда потребитель его отменяет, `"error"` с ошибкой когда он не работает по пути: + +```ts +import { wrapModel } from "@failproofai/sdk/ai"; +const model = await wrapModel(openai("gpt-4o")); +``` + +Использование обоих хорошо: промежуточное ПО заметит, что вызов уже записывается и отложит, поэтому каждый вызов записывается один раз. + +`functionId` именует диапазон агента. Держите его с низкой кардинальностью — он приземляется в `agent_id`, главный грани панели управления. + +### Next.js + +`next build` комплектует зависимости вашего сервера по умолчанию, и фреймворк, включённый в сборку, — это копия, которую `instrument()` не может достичь. Оборачивайте конфиг один раз и вызывайте `instrument()` из крючка запуска Next: + +```ts +// next.config.ts +import { withFailproofai } from "@failproofai/sdk/next"; +export default withFailproofai({ /* ваш конфиг */ }); +``` + +```ts +// instrumentation.ts +export async function register() { + if (process.env.NEXT_RUNTIME !== "nodejs") return; + const failproofai = await import("@failproofai/sdk"); + await failproofai.instrument(); +} +``` + +`withFailproofai` добавляет LangChain, Mastra, LlamaIndex и сам SDK в `serverExternalPackages`, сохраняя ваш собственный список. Без этого `instrument()` предупреждает один раз за фреймворк, который не может достичь, вместо молчаливого отказа; если вы список пакетов сами, установите `FAILPROOFAI_NEXT_EXTERNALS=1`. Vercel AI SDK и помощники на месте вызова работают так или иначе. Маршрут Edge получает сборку no-op: импорт SDK безопасен и ничего не записывает. + +### Подсчёт токенов при потоковых вызовах + +API-совместимые с OpenAI обычно сообщают использование на потоке только когда клиент просит. LangChain и Vercel AI SDK просят; для LlamaIndex передайте `additionalChatOptions: { stream_options: { include_usage: true } }` его `OpenAI` LLM, и для Mastra постройте модель с включённым использованием (например `createOpenAICompatible({ includeUsage: true })`). В противном случае потоковые вызовы модели не имеют подсчёта токенов. + +### Среды выполнения + +Node ≥ 20.9, Bun и Deno — каждый фреймворк, как модуль ES и CommonJS, протестирован на каждом против трассировки Node. SDK работает рядом с демоном `failproofaid`, который отправляет то, что он пишет. + +## Ваш собственный агент — никакого фреймворка + +Для цикла агента, который вы написали сами, или фреймворка без адаптера. Вы выдаёте события с тем же API, который адаптеры используют под капотом, поэтому трасса имеет то же форму и качество. + +Вам не нужно знать, как агент организован. Каждый рукописный агент уже имеет три места, какие бы его функции не были названы, и эти три — вся интеграция: + +| Где | Что добавить | Выдачи | +| --- | --- | --- | +| Где **один запуск** начинается и заканчивается | `failproofai.agent("name", { goal }, async () => …)` | `agent_start` / `agent_end` | +| **Одна функция, которая вызывает модель** | `event.modelRequest` перед, `event.modelResponse` после — обе половинки, даже при отказе | одна пара на ход модели | +| **Одна функция, которая запускает инструменты** | `failproofai.toolCall(name, { toolCallId, input }, () => run())` | `tool_use` / `tool_result` | + +```ts +async function callModel(messages) { + const requestId = randomUUID(); + const started = Date.now(); + failproofai.event.modelRequest({ model: MODEL, requestId, messages }); + try { + const reply = await client.chat.completions.create({ model: MODEL, messages, tools }); + failproofai.event.modelResponse({ + model: reply.model, requestId, stopReason: reply.choices[0].finish_reason, + inputTokens: reply.usage?.prompt_tokens, outputTokens: reply.usage?.completion_tokens, + duration_ms: Date.now() - started, + }); + return reply.choices[0].message; + } catch (error) { + failproofai.event.modelResponse({ model: MODEL, requestId, stopReason: "error", + error: String(error), duration_ms: Date.now() - started }); + throw error; + } +} + +async function dispatch(call) { + const input = JSON.parse(call.function.arguments); + return failproofai.toolCall(call.function.name, { toolCallId: call.id, input }, + () => runTool(call.function.name, input)); +} + +await failproofai.agent("inventory", { goal: question }, async () => { + for (;;) { + const message = await callModel(messages); + if (!message.tool_calls?.length) return message.content; + for (const call of message.tool_calls) await dispatch(call); + } +}); +``` + +Идентификация окружающая: всё внутри `agent()` приземляется на сессию этого запуска без принятия id, и ничто больше в программе не меняется — включая всё, что агент уже пишет в собственную базу данных. + +- **Сервис или рабочий:** передайте собственный id запроса или работы как `sessionId`, поэтому сессия на панели управления и запись в ваших собственных логах или базе данных — это одна строка. +- **Подагенты:** вложите вызовы `agent()`. Внутренний присоединяется к сессии внешнего как его `parent_id`. +- **Выдайте пары.** `modelRequest` без `modelResponse` — это диапазон, который панель управления показывает как запущенный вечно — отсюда `catch`. + +[`sdk/typescript/examples/research-agent.ts`](https://github.com/FailproofAI/failproofai/blob/main/sdk/typescript/examples/research-agent.ts) в репозитории — это полная, исполняемая версия: реальный цикл инструмента OpenAI, инструментирован точно так же, запущен в CI при каждом изменении как модуль ES и CommonJS. + +## Оценки + +```ts +import { Evaluator, EvalResult, Score } from "@failproofai/sdk/evaluator"; + +export const app = new Evaluator({ name: "my-evals", version: "1" }); + +app.eval("tool_success_rate", { version: "1" }, (session) => { + const results = session.eventsOfType("tool_result"); + const failures = results.filter((event) => event.payload.error != null).length; + return new EvalResult({ + score: new Score(results.length === 0 ? 1 : 1 - failures / results.length), + reasoning: `${failures} of ${results.length} tool calls failed`, + }); +}); +``` + +```bash +FAILPROOFAI_EVALUATOR_URL=… FAILPROOFAI_EVALUATOR_TOKEN=… \ + npx failproofai-evaluator ./my-evals.js +``` + +Смотрите [справочник SDK Evaluator](/ru/reference/evaluator-sdk) для протокола, параметров рабочего и типов результатов. + + + **Оценка должна выдавать.** Синхронная функция, которая никогда не возвращается, блокирует один поток, который имеет Node, и никакой timeout не может срабатывать пока она выполняется. Пишите `async` оценки. + + +## Что это не будет делать с вашим процессом + +| | | +| --- | --- | +| **Блокировать цикл вашего агента** | События переходят в очередь в памяти; таймер их пишет. Таймер — `unref`'d, поэтому импорт этого пакета никогда не остановит скрипт выход. | +| **Расти без границ** | Очередь ограничена по счёту *и* по измеренным байтам. После обоих, самые старые события отбрасываются и предупреждение об этом — телеметрический отказ не должен становиться убийцей OOM. | +| **Взять процесс вниз** | Одно неправильное событие отбрасывается в одиночестве, не партия вокруг него. Выбрасывающий гетер, циклическая ссылка, `BigInt`, одинокий суррогат: каждое обработано вместо распространения. | +| **Оставить половину записанную партию** | Содержимое `fsync`'d перед атомарным переименованием, директория `fsync`'d после, и неудачная запись очищает свой временный файл. | +| **Оставить расшифровки читаемыми** | Партии `0600` внутри директории `0700`. Они несут цели, подсказки, аргументы инструмента и выход инструмента. | +| **Отправить учётные данные** | Ключи API, токены, JWT, заголовки bearer и назначения в форме секретов переходят в режим редакции перед прибытием байтов на диск. Демон редактирует снова перед загрузкой. | \ No newline at end of file diff --git a/docs/ru/reference/jev-cloud.mdx b/docs/ru/reference/jev-cloud.mdx new file mode 100644 index 000000000..2b0db2e18 --- /dev/null +++ b/docs/ru/reference/jev-cloud.mdx @@ -0,0 +1,136 @@ +--- +title: "Jev через облако FailproofAI" +description: "Облачные ключи машин, состояние соединения, лимиты и поведение при сбоях для живого обзора политик Jev." +icon: "cloud" +--- + +Это справочник облачного маршрута для [политик Jev](/ru/policies/jev). Jev, классификатор TypeSafe, проверяет каждый вызов инструмента относительно того, что вы на самом деле просили, и дает ответ вместе с вашими политиками, никогда вместо них. Через **облако FailproofAI**, подключенная машина использует Jev с тем же ключом, с которым уже подключается: без учетной записи TypeSafe, без второго ключа, без конечной точки для настройки. Каждый вызов списывается с выделения плана вашей организации. + +Все, что делает Jev, не отличается от [самостоятельной настройки ключей](/ru/reference/jev-providers): жесткие политики остаются окончательными, запрет рассматриваемой политики снимается только когда Jev был спрошен точно об этой проблеме, и любой сбой переходит на результат регулярного выражения для этого вызова. + + +Требуется **failproofai 1.0.8-beta.0** или позже. 1.0.7 не имеет Jev, несмотря на то, что сортируется выше 1.0.7 бета-версий. Без конфигурации Jev ничего не изменяется: хуки запускают политики регулярного выражения точно как всегда. + + +## Перед началом + +Установите Failproof AI на машину, где работает ваш агент, и подключите его хуки к [поддерживаемой системе](/ru/reference/harnesses). Если вы начинаете с нуля, следуйте [краткому руководству](/ru/start/quickstart) до установки хуков. Проверьте установленный CLI с помощью `failproofai --version`; обновите его, если он предшествует Jev. Вам также нужен доступ к странице **Administration → Keys** вашей организации для создания ключа машины. + +Jev проверяет именованные вызовы инструментов на этапе `PreToolUse` или `PermissionRequest`. Он не проверяет каждое событие в сеансе. Чтобы увидеть, как Jev снимает запрет политики, вам нужна установленная политика, отмеченная как [проверяемая](/ru/policies/authority); все остальные запреты политик остаются окончательными. + +## Включение + +1. **Создайте ключ с Jev.** На панели облака FailproofAI откройте **Administration → Keys → Create key** и выберите предустановку **machine**. Она дает три разрешения, которые нужны машине: `events:add` (отправка активности), `policies:pull` (получение политик) и `jev:evaluate` (Jev, списывается с плана вашей организации). Ключ не может иметь `jev:evaluate` без двух других. +2. **Подключите машину** с этим ключом. Прочитайте его одноразовый секрет в приглашении, затем запустите полную команду настройки: + + ```bash + read -rs FAILPROOFAI_CLOUD_TOKEN && export FAILPROOFAI_CLOUD_TOKEN + failproofai config + ``` + + `failproofai config` устанавливает демон, подключает хуки для найденных CLI агентов и соединяет машину. Переменная окружения хранит ключ вне аргументов команды и истории вашей оболочки. Если ваша система была установлена позже, [подключите ее явно](/ru/start/quickstart). + + Если ваша организация использует свое облако FailproofAI вместо размещенного, добавьте его адрес: `--url https://<ваш хост панели>` (или экспортируйте `FAILPROOFAI_CLOUD_URL`). Без этого ключ проверяется по размещенному сервису и соединение не удается. Если сертификат этого хоста выдан частным центром сертификации, установите его в хранилище системного доверия машины (например, с помощью `update-ca-certificates`), не только в `NODE_EXTRA_CA_CERTS`: демон, который отправляет события и получает политики, читает системное хранилище. См. [Решение проблем](/ru/reference/troubleshooting). + +Вот и все. Подключение сохраняет ключ и, когда машина **не имеет** конфигурации Jev, включает Jev через облако FailproofAI в режиме **observe**: как только пакет дает ему проверки, Jev спрашивается о каждом вызове инструмента на этапе и его вердикты записываются, но результат ваших политик это то, что применяется. Вывод показывает это: + +```text + Jev on through FailproofAI Cloud, in observe mode: logged, not enforced (~/.failproofai/jev.json). +``` + +Jev по-прежнему не спрашивает ничего, пока пакет не дает ему проверки. Failproof AI не поставляет никаких; пока ни один установленный пакет не объявляет никаких, вывод добавляет строку, говорящую об этом, и `failproofai jev status` повторяет это. Установите их с помощью: + +```bash +failproofai policies add FailproofAI/jev-policies +``` + +**С `--no-transcripts`, подключение не включает Jev.** Jev отправляет каждый проверенный вызов инструмента и недавнее приглашение в облако FailproofAI, что больше, чем соединение, учитывающее только решения, попросили отправить. Ключ по-прежнему хранится, и вывод говорит, что Jev доступен и как его включить: + +```bash +failproofai jev setup --provider failproofai +``` + +Он также не включает Jev **выключение**. Если `jev.json` машины уже запускает Jev через облако FailproofAI, он оставляется как есть, и вывод говорит, что Jev по-прежнему отправляет каждый проверенный вызов инструмента и недавнее приглашение, и что `failproofai jev setup --mode off` его выключает. + + +Подключение **никогда не перезаписывает** существующий `~/.failproofai/jev.json`. Если вы уже используете свою конечную точку Jev, она продолжает использоваться, и вывод говорит, что файл был оставлен как настроено — и, когда этот файл оставляет Jev выключенным (отказано или выключено), говорит об этом и как это исправить. Чтобы переключить эту машину на облако FailproofAI, запустите `failproofai jev setup --provider failproofai`. + + +## Observe, enforce или off + +Начните с observe, смотрите, что бы сделал Jev на странице политик, затем позвольте ему действовать: + +```bash +failproofai jev setup --mode enforce # вердикты Jev применяются: он может снять проверяемый запрет и добавить свой собственный +failproofai jev setup --mode observe # Jev спрашивается и регистрируется; результат ваших политик применяется +failproofai jev setup --mode off # сохранить конфигурацию, перестать спрашивать Jev +``` + +Тот же переключатель находится в локальной панели: **Settings → Jev** имеет переключатель вкл/выкл и observe/enforce. Он переписывает режим и ничего более. Хуки читают конфигурацию при каждом вызове инструмента, поэтому изменение применяется со следующего, без перезагрузки. + +## Проверьте, что он делает + +```bash +failproofai jev status +failproofai jev test +``` + +`status` показывает провайдера как **FailproofAI Cloud**, хост облака, к которому подключена машина, режим и источник ключа как **FailproofAI Cloud connection**, никогда сам ключ. Когда `jev.json` облака FailproofAI установлен, но Jev не может работать, он говорит почему: + +| `status` говорит | `status --json` | Значение | +| --- | --- | --- | +| **off — no Jev key is stored for this machine's FailproofAI Cloud connection** | `key-lacks-jev` | Машина подключена, но для нее не сохранен ключ Jev: ключу не хватает `jev:evaluate`, или подключение не могло это подтвердить. Запустите `failproofai config` снова с ключом в `FAILPROOFAI_CLOUD_TOKEN`; если ему не хватает разрешения, используйте ключ **machine**. | +| **off — this machine is not connected to FailproofAI Cloud** | `not-connected` | На этой машине нет соединения облака FailproofAI, к которому может принадлежать ключ Jev. | + +После `failproofai config --disconnect` больше нет `jev.json` облака FailproofAI (если он не был выключен, что сохраняется), поэтому `status` просто сообщает, что Jev выключен. `status --json` несет те же факты (`provider: "failproofai"`, `keySource: "cloud"`, `cloudConnected`, `keyCarriesJev`), также когда конфигурация отсутствует или отклонена. `permissions` всегда из `jev.json`; отказ о `credentials.json` добавляет `credentialsPermissions`, и `fix` когда одна команда это исправляет. `test` отправляет один живой запрос и сообщает его задержку и версию Jev, которая ответила. Он выходит с 1 и говорит об этом в заголовке, когда ответ приходит после тайм-аута хука (хуки записали бы `timeout`) или отвечает на его вопрос проверки неправильно. + +Панель **Settings → Jev** панели также показывает **FailproofAI Cloud connection**: в какую организацию сообщает машина и несет ли ее ключ Jev. Это читается из собственных файлов машины, без сетевого вызова. + +## Проверьте реальный вызов + +Начните новый сеанс в хукированном агенте. Попросите его использовать свой инструмент чтения файлов на `README.md` и сообщить заголовок. Убедитесь, что сеанс содержит этот вызов инструмента, затем запустите `failproofai jev status` снова: его недавний счет оцененных вызовов должен увеличиться. Откройте **Policies → Activity** в [локальной панели](/ru/reference/local-dashboard#review-policy-activity) для проверки вердикта Jev этого вызова и режима. В облаке страница **Policies** организации показывает результаты Jev для доставленной активности. В режиме observe вердикт записывается как **would-have** и результат политики по-прежнему решает вызов. Очистка появляется только когда совпадала проверяемая политика и Jev снял ее именованные проверки. + +## Что достигает страницы политики + +Машина уже отправляет свою активность хуков в облако FailproofAI (`events:add`). С Jev включенным, запись каждого вызова на этапе также говорит, какой оценивающий запустился, что решил Jev, какие политики он снял, почему он откатился когда это произошло, его задержку и модель, которая ответила — решения, коды и имена, никогда команду или ваше приглашение. На странице **Policies** вашей организации: + +- вызов, решение которого принял вердикт Jev (режим enforce), приписывается **Jev**, и когда решающая проверка пришла из пакета, запись также называет этот пакет и его версию; +- в режиме observe, запрет или предупреждение Jev появляется как **would-have**, рядом с откатами, которые вы наблюдаете; +- политики, которые Jev снял, или снял бы в режиме observe, подсчитываются по политике. + +## Когда Jev не может ответить + +Каждое из этих откатов переходит на результат ваших политик для этого вызова и записывается с причиной: + +| Причина | Причина | +| --- | --- | +| `out-of-credits` | Ваша организация использовала выделение плана. | +| `http-401`, `http-403` | Ключ был отозван, или не имеет `jev:evaluate`. Переподключитесь с ключом, который имеет. | +| `http-429` | Облако FailproofAI ограничивает скорость Jev для вашей организации. Пока ожидание, которое оно требует, не закончится (его `Retry-After`, максимум 60 секунд), машина ничего не отправляет и каждый вызов откатывается сразу. Вызовы, удерживаемые таким образом, записываются как `http-429`, или как `rate-limited` когда собственный лимит скорости машины их удерживает сначала. | +| `http-429` (дневной лимит) | Ваша организация использовала свои дневные вызовы Jev: **10 000 в день UTC**, если только тот, кто управляет вашим облаком FailproofAI, не установил другой лимит. Каждый вызов откатывается пока счет не сбросится в 00:00 UTC; машина по-прежнему спрашивает не более одного раза в минуту, поэтому она снимает сброс в течение минуты. `failproofai jev test` говорит "Daily Jev limit for this org reached; resets at 00:00 UTC." | +| `http-422` | Jev отказал в запросе этого вызова, обычно потому что вызов инструмента содержал плотный текст (base64, hex, минифицированный код) выше бюджета токенов Jev. Этот вызов откатывается каждый раз; это не отключение. | +| `http-502` | Jev в данный момент недоступен. | +| `http-503` | Это облако не может обслуживать Jev для вашей организации: нет шлюза моделей, организация еще не подготовлена, или шлюз вниз. Попросите администратора; хуки спрашивают снова не более одного раза в минуту. | +| `http-404` | Это облако FailproofAI пока не обслуживает Jev. | +| `timeout` | Нет ответа в пределах `timeoutMs` (по умолчанию 3000). | +| `model-mismatch` | Ответила версия Jev, отличная от 1.13. | + +## Где живет ключ и куда он идет + +- Ключ сохраняется один раз в `~/.failproofai/credentials.json` (`0600`, в каталоге только владельца), рядом с другими учетными данными облака FailproofAI. `jev.json` не содержит ключ для этого маршрута; один написанный там делает конфигурацию недействительной. +- Если `credentials.json` несет **какое-либо** разрешение для кого-либо, кроме вас (группа или другое, чтение или запись), или его каталог может быть **написан** кем-либо, кроме вас, он **отклоняется**, не читается, и Jev выключен пока вы это не исправите: `chmod 600` на файл, `chmod 700` на каталог (или переподключитесь, что переписывает файл в `0600` и делает каталог владельцем). Каталог, который другие могут только читать, подходит; один, который они могут написать, позволяет им поменять файл. +- Ключ считается только пока соединение, с которым он пришел, находится на машине: политика или учетные данные отчета для того же облака FailproofAI **с тем же ключом**, в одном файле. Ключ Jev оставленный без соединения игнорируется, и Jev остается выключенным. Это происходит когда более старая версия failproofai `config --disconnect` оставляет ключ Jev на месте (она не знает удалить его), или когда более старая версия failproofai `config --token` подключается с другим ключом, который в облаке FailproofAI может принадлежать другой организации. Чтобы включить Jev обратно, подключитесь снова с ключом **machine**. +- Ключ только когда-либо отправляется в начало облака, на котором он был проверен. `jev.json`, указывающий куда-либо еще, отклоняется. +- **Агент на машине может его прочитать.** `credentials.json` принадлежит только владельцу, и агент работает как этот владелец. Чтение собственных файлов failproofai разрешено специально (только их изменение блокируется `block-failproofai-commands`), поэтому единственное между агентом и этим файлом это `block-read-outside-cwd` — *проверяемая* политика — и из сеанса, запущенного в вашем домашнем каталоге, ничего. Ключ с `jev:evaluate` тратит выделение Jev вашей организации (до дневного лимита) из любого места, откуда он используется, поэтому обращайтесь с ключом машины как с любыми другими расходными учетными данными: если агент мог его прочитать, отключите его на странице Keys и переподключитесь с новым. +- Только ваши глобальные файлы это решают. Репозиторий не может включить облачный Jev, указать его куда-либо или поставить его ключ, и `FAILPROOFAI_JEV_API_KEY` игнорируется для этого маршрута. +- Для каждого вызова, который Jev оценивает, один запрос идет в облако FailproofAI, несущий то, что список [страницы приносить-вашего-собственного-ключа](/ru/reference/jev-providers#what-leaves-the-machine) (секреты отредактированы). Облако FailproofAI пересылает его TypeSafe и не регистрирует или не хранит его. + +## Выключение + +| Команда | Результат | +| --- | --- | +| `failproofai jev setup --mode off` | Сохранить конфигурацию; Jev не спрашивается. **Это переключатель, который длится:** подключение снова никогда не переписывает существующий `jev.json`, поэтому Jev остается выключенным пока вы его не включите обратно с `--mode observe`. | +| `failproofai jev remove` | Удалить `~/.failproofai/jev.json`; Jev выключен — пока не следующий `failproofai config --token` с ключом, который несет `jev:evaluate`, который находит нет `jev.json` и включает Jev снова в режиме observe (если он не работает с `--no-transcripts`). Чтобы держать его выключенным, используйте `--mode off`. | +| `failproofai config --disconnect` | Отключить машину: ключ удаляется, и также `jev.json` когда он называет облако FailproofAI и не выключен. `jev.json` для вашей собственной конечной точки остается, и также один выключенный, поэтому Jev остается выключенным когда вы подключитесь снова. | + +Со следующего вызова инструмента хуки запускают политики регулярного выражения точно как раньше. \ No newline at end of file diff --git a/docs/ru/reference/jev-evaluations.mdx b/docs/ru/reference/jev-evaluations.mdx new file mode 100644 index 000000000..ea4e3639b --- /dev/null +++ b/docs/ru/reference/jev-evaluations.mdx @@ -0,0 +1,88 @@ +--- +title: "Справочник по оценкам Jev" +description: "Типы вопросов, калиброванные оценки, ограничения и заполнение пропусков для оценок сеансов Jev." +icon: "list-checks" +--- + +На этой странице описаны формы вопросов и правила оценивания для [оценок Jev](/ru/evaluations/jev). Некоторые вопросы требуют от модели *прочитать* разговор, но не *написать* о нём. «Выразил ли клиент срочность?» имеет два ответа. «Насколько они расстроены?» имеет несколько ответов, расположенных по порядку. Вы знаете каждый возможный ответ перед тем, как задать вопрос. + +**Оценка классификатора** предназначена именно для таких случаев. Вы пишете вопрос и возможные ответы, а небольшая модель, специализирующаяся на классификации, возвращает калиброванное число — никогда свободный текст. + + +Как и судья, оценка классификатора требует одного вызова модели за сеанс. Но в отличие от судьи это небольшая узкоспециализированная модель, а не универсальная, поэтому она работает быстрее и дешевле — однако она никогда себя не объяснит. Если вам нужно обоснование, используйте [судью](/ru/evaluations/judge). + + +## Какой вариант мне выбрать? + +| Вопрос | Используйте | +| --- | --- | +| Сколько было вызовов инструментов? | код | +| Был ли сеанс короче 30 секунд? | код | +| Выразил ли клиент срочность? | **классификатор** | +| Какая команда должна это обработать: платежи, техподдержка или продажи? | **классификатор** | +| Насколько расстроен был клиент? | **классификатор** | +| Был ли ответ действительно правильным? | **судья** | +| Следовал ли он нашей политике эскалации и почему вы так думаете? | **судья** | + +Главное правило: **поддающееся подсчёту → код, ответы, которые можно перечислить → классификатор, требует объяснения → судья.** + +Вам не нужно решать заранее. Опишите, что вы хотите измерить, ассистент выберет, скажет, что он выбрал и почему, и вы сможете переключиться. + +## Два типа вопросов + +### `noul` — это правда? + +Два ответа, и вы описываете оба. Результат — вероятность того, что описание «правда» подходит: + +```json +{ + "instructions": "Did the assistant promise a refund without first checking the refund policy?", + "criteria": { + "true": "A refund was promised or issued with no prior policy check or approval", + "false": "No refund was promised, or every refund followed a policy check" + } +} +``` + +Опишите обе стороны. «Срочность не выражена» — это настоящий ответ, и его упоминание делает другой ответ точнее. + +### `score` — сколько этого? + +Упорядоченная шкала оценок, **худшее в начале**. Результат показывает, где сеанс на ней располагается, пересчитанный на шкалу 0–1: + +```json +{ + "instructions": "How frustrated is the customer?", + "criteria": ["Calm", "Frustrated", "Very angry"] +} +``` + +**Шкала оценок должна содержать три–пять уровней, и они все должны отличаться друг от друга.** Обе границы имеют чёткие измеримые значения, а не стилистические: + +- **Два уровня** сворачиваются к тому, что `noul` уже делает лучше, а **больше пяти** заставляет модель колебаться к середине вместо чёткого выбора. Один и тот же вопрос в одном и том же сеансе получил оценку 0.00 с двумя уровнями, 0.01 с тремя и 0.55 с десятью. +- **Повторяющиеся уровни** произвольно разбивают ответ между ними. Сеанс, который явно выражал гнев, получил оценку 1.00 для `["Calm", "Frustrated", "Very angry"]` и 0.66 для `["Angry", "Angry", "Angry"]` — хорошо сформированное число, которое ничего не значит. + +Категории без порядка — «платежи, техподдержка или продажи» — это не шкала оценок. Спросите их как `noul` для каждой категории или используйте судью. + +## Чтение результатов + +Классификатор выдаёт **оценку** от 0 до 1, точно как судья, поэтому её можно отображать на графиках, фильтровать и настраивать оповещения одинаково. Есть два отличия, которые стоит учитывать: + +- **Нет обоснования.** Это поле пусто намеренно. Эта модель себя не объясняет, а выдуманное объяснение было бы выдумкой, а не возможностью. +- **Неуверенность отмечена.** Вопрос `score` сообщает собственную уверенность, и результат, в котором модель не была уверена, помечается как `low_confidence` — поэтому фильтр «что из этого должен посмотреть человек» — это фильтр, а не предположение. Вопрос `noul` не сообщает уверенность, поэтому никогда не помечается. + +Очень длинные сеансы читаются отрывками и объединяются. Когда сеанс слишком длинный, чтобы прочитать его полностью, результат показывает, сколько ходов было пропущено — вы никогда не увидите оценку части сеанса, представленную как оценка всего сеанса. + +## Ограничения + +- **Три–пять уровней шкалы, все отличающиеся.** Смотри выше; обе границы проверяются при создании. +- **Один вопрос на оценку.** Если спросить две вещи, получится две оценки, что также правильно для графика. +- **Редактирование вопроса публикует новую версию.** Старые и новые оценки несравнимы, поэтому они хранятся отдельно, а не смешиваются в одну линию тренда. +- **Классификатор всегда выдаёт оценку**, никогда метрику или утверждение. +- **Нет обоснования**, как упомянуто выше. Если число заставит кого-то спросить «почему?», напишите судью вместо этого. + +## Тестирование и заполнение пропусков + +В отличие от судьи, оценка классификатора **может** быть протестирована перед развёртыванием — [протестируйте её](/ru/evaluations/test) на реальных сеансах так же, как оценку кода, и прочитайте оценки перед тем, как что-либо запустится. + +Её также можно [заполнить пропуски](/ru/evaluations/deploy#score-sessions-you-already-have) для сеансов, которые у вас уже есть. Это требует одного вызова модели за сеанс, поэтому намеренно ограничьте окно, а не воспроизводите всё. \ No newline at end of file diff --git a/docs/ru/reference/jev-intent.mdx b/docs/ru/reference/jev-intent.mdx new file mode 100644 index 000000000..4bc18af14 --- /dev/null +++ b/docs/ru/reference/jev-intent.mdx @@ -0,0 +1,112 @@ +--- +title: "Захват намерения Jev" +description: "Какие события harness сообщают оценщику Jev, что просил человек, какое поле содержит текст, что никогда не учитывается и какой риск возникает при доверии к промпту, доставленному harness." +icon: "message-square-quote" +--- + +Когда вы настраиваете [обзор политики Jev](/ru/policies/jev), оценщик судит о каждом вызове инструмента, прошедшем проверку, на основе **того, что просил человек**, а не на основе текста, который harness поместил перед агентом. Ответ вроде «да, выполни force-push» может пройти **reviewable** политику — это вся суть оценщика, так как regex, который не может прочитать запрос, блокирует треть реальной работы. + +Этот текст поступает из одного места: **промпта, который сам harness передает hook при событии prompt-submit**. Failproof AI записывает часть, которую напечатал человек — с удаленным оборачиванием harness, редактированием секретов, ограничением — в файл `0600` в своём каталоге состояния. Ничего с диска не консультируется: стенограмма сессии — это файл, который агент может переписать одной командой, поэтому его никогда не спрашивают, кто написал промпт. + +## Риск, который это принимает, откровенно + +Агент, который уже может запускать команды, может заставить harness отправить промпт. `claude -p "…"`, `codex exec`, `copilot -p`, `cursor-agent -p`, `devin -p`, `droid -p`, `goose run -t` и `pi -p` все вызывают одно и то же событие prompt-submit с одной и той же полезной нагрузкой, что и человек, печатающий в подсессии, которую контролирует этот агент. Он также может запустить собственный бинарный файл hook Failproof AI и передать ему полезную нагрузку, которую он написал. Ничего внутри Failproof AI не может отличить одно от другого — оба это один и тот же программный код, читающий один и тот же stdin. + +**Таким образом, агент с доступом к оболочке может подделать своё согласие.** Это сознательный компромисс, принятый 2026-09-23, и вот обе его стороны: + +- **Что это даёт.** Альтернатива была построена и измерена: требовать поле, в котором harness называет человека автором промпта, и не записывать ничего в противном случае. Ни один поставляемый harness не отправляет такое поле, поэтому эта версия записывала **ничего, на каждом harness** — Jev судил каждый вызов без заявленного намерения и никогда не мог пройти ни одну политику. Захват, который никогда не срабатывает, это не более безопасный продукт, это вообще не продукт. +- **Что он не может делать.** Записанный промпт может только пройти политику, уже отмеченную как **reviewable**. **Hard** политика никогда не проходит через то, что говорит Jev, поэтому подделанный промпт никогда не может превратить жёсткий отказ в разрешение — и пропуск hook ничего не даёт агенту: harness вызывает Failproof AI для вызова инструмента независимо. +- **Что он может делать, в полном масштабе.** Худшее, что он может сделать, — это пройти одну из пятнадцати reviewable встроенных политик — и **двенадцать из пятнадцати блокируют**. `protect-env-vars`, `block-env-files`, `block-read-outside-cwd`, `block-rm-rf`, `block-force-push`, `block-secrets-write` и шесть блоков инфраструктурного CLI (`block-kubectl`, `block-terraform`, `block-aws-cli`, `block-gcloud`, `block-az-cli`, `block-helm`) — отказы, поэтому подделанное согласие может превратить реальный отказ в разрешение на вывод секретов среды, чтение файла `.env`, чтение за пределами проекта, `rm -rf`, force-push, запись файла секретов или изменение живой инфраструктуры. Только `warn-git-amend`, `warn-destructive-sql` и `warn-global-package-install` являются предупреждениями. При установке по умолчанию включаются два из двенадцати, `protect-env-vars` и `block-env-files`; остальные десять достаются только машине, на которой их кто-то включил. То, что не достигает ни один промпт, — это всё жёсткое — `block-sudo`, `block-curl-pipe-sh`, `block-push-master`, `block-work-on-main`, защита, которая останавливает отключение агентом Failproof AI, и любая другая встроенная политика, не отмеченная как reviewable. [Авторитет политики](/ru/policies/authority) перечисляет все пятнадцать и то, что рассматривает каждую. + +То, что всё ещё отказывается, — это всё, что дёшево проверить и что агент не может получить просто спросив: ход, отмеченный payload harness как отправленный машиной, payload, называющий подагента, идентификатор сессии, который не является простым именем, событие, которое не является prompt-submit событием, и текст, который это только оборачивание harness — включая собственные стоп-гейт слова Failproof AI, которые несколько harness возвращают обратно как следующий ход пользователя. + +## Таблица для каждого harness + +«Поле текста» — это поле stdin в полезной нагрузке после нормализации Failproof AI для конкретного harness. «Recorded» указывает, сохраняется ли промпт как запрос человека. + +| Harness | `--cli` | Событие промпта → канонический | Поле текста | Recorded | Последнее сообщение агента читается из | +| --- | --- | --- | --- | --- | --- | +| Claude Code | `claude` | `UserPromptSubmit` | `prompt` | Да, если только `source` в полезной нагрузке не называет ход, который никто не отправил (`loop_wakeup`, `schedule_wakeup`, `poll_event`, `system`). `user`, `sdk`, неизвестное значение и сборка, которая не отправляет `source` вообще, все записываются | стенограмма сессии (`transcript_path`) | +| Codex | `codex` | `user_prompt_submit` → `UserPromptSubmit` | `prompt` | Да | JSONL развёртывания (`agent_message`, `AgentMessage`) | +| GitHub Copilot CLI | `copilot` | `UserPromptSubmit` | `prompt` | Да | `events.jsonl` (`assistant.message`) | +| Cursor | `cursor` | `beforeSubmitPrompt` → `UserPromptSubmit` | `prompt` | Да, с удалённой обёрткой ``, когда это весь промпт | JSONL стенограммы агента | +| OpenCode | `opencode` | `message.updated` (пользовательская роль) → `UserPromptSubmit` | `prompt` | Да — но текущий OpenCode не содержит текста в этом событии, поэтому на практике ничего не записывается; повтор того же сообщения записывается один раз | none (сессии это SQLite) | +| Pi | `pi` | `input` → `UserPromptSubmit` | `prompt` | Да, если `input_source` не `extension` — `sendUserMessage()` другого расширения, текст которого может быть написан моделью или получен из репо | Pi сессия JSONL | +| Hermes | `hermes` | none | — | Нет — Hermes вообще не имеет события prompt-submit | — | +| OpenClaw | `openclaw` | `before_agent_run` → `UserPromptSubmit` | `prompt` | Да, если только метаданные запуска не отмечают запуск как машинный: `trigger` отличный от `user`, `inputProvenance.kind` отличный от `external_user`, или `senderIsOwner: false` | none (`before_agent_run` не содержит путь стенограммы) | +| Factory Droid | `factory` | `UserPromptSubmit` | `prompt` | Да | JSONL сессии droid | +| Devin CLI | `devin` | `UserPromptSubmit` | `prompt` | Да | none (сессии это SQLite) | +| Antigravity CLI | `antigravity` | `PreInvocation` → `UserPromptSubmit` | none | Нет — `PreInvocation` срабатывает перед *каждым* вызовом модели в ходе и не содержит текст промпта | — | +| Goose | `goose` | `UserPromptSubmit` | `message` | Да | none (сессии это SQLite) | + +Два harness ничего не записывают, и по одной и той же причине в обоих случаях: их событие не доставляет текст человека. Hermes не имеет события prompt-submit — его собственный плагин обрабатывает `pre_llm_call` самостоятельно и пересылает только события инструмента, сессии и подагента. `PreInvocation` Antigravity срабатывает перед каждым вызовом модели, на ходе человека и на пяти следующих, и не содержит поле промпта; hooks также могут вводить шаги `userMessage` в ту же беседу. В любом из событий нечего записывать. + +## Что делает промпт промптом человека + +1. **Событие.** Failproof AI был вызван для события prompt-submit harness, которое обработчик канонизирует в `UserPromptSubmit`. +2. **Полезная нагрузка.** Harness пишет это на stdin hook, и она содержит текст в поле, названном выше. Вызов, который достигает Failproof AI без полезной нагрузки, ничего не записывает. +3. **Ничто в полезной нагрузке не исключает ход.** Полезная нагрузка, которая называет подагента (`agent_id`), это агент, подсказывающий себе. `source`, `input_source` или маркер запуска OpenClaw, который называет ход, отправленный машиной, отказывается. **Отсутствующий** маркер ничего не исключает — это отличие от версии, которая ничего не записывала, так как каждый маркер здесь отсутствует на каждой отправленной сборке. +4. **Что-то остаётся после удаления обёртки** (см. ниже). + +**Стенограмма сессии не является доказательством того, кто написал промпт.** Более ранние версии этой страницы описывали проверку перекрёстной ссылки на стенограмму: промпт был отказан, если стенограмма показала, что модель его запланировала, и стенограмма должна была продолжить то, что видела предыдущий промпт. Эта проверка исчезла. Стенограмма — это файл, у которого агент уже есть доступ через оболочку — она может быть усечена, заменена, дополнена за пределами бюджета на чтение, снимок которой сделан в начале хода и восстановлена в конце, или сделана хорошо читаемой с записями, которые написал агент. За каждым раундом закаливания следовало ещё одно написание той же подделки, поэтому весь механизм был удалён, а не отремонтирован. + +Стенограмма всё ещё читается для одного: **последнее видимое сообщение агента**. Это сообщение по определению написано агентом, Jev об этом сказано, и оно само по себе никогда не является согласием. + +## Что сохраняется из промпта + +Harness помещает в промпт больше, чем просто слова человека. Перед записью чего-либо: + +- Блоки `` удаляются, а слова человека вокруг них сохраняются. +- Сводка продолжения сессии («Эта сессия продолжается с предыдущей беседы…») удаляется полностью. +- Уведомления о задачах, вывод локальной команды и маркеры прерывания удаляются полностью. +- Ход, который написал другой агент или сессия, удаляется полностью: Claude Code оборачивает их в ``, ``, ``, `` или ``. +- Собственные сообщения Failproof AI удаляются полностью. Стоп-гейт `MANDATORY ACTION REQUIRED from failproofai …` или `Instruction from failproofai: …` возвращается как следующий ход пользователя на Cursor, Copilot, Devin и OpenClaw, и это никогда не считается словами человека — не простыми, не обёрнутыми в блок ``, не за системным напоминанием. +- Слеш-команда сохраняется как команда и аргументы, которые напечатал человек, никогда не как тело, которое harness расширил. +- Промпт, который расширение Codex IDE построило, сохраняет только текст после последнего заголовка `## My request for Codex:` (или в более новых сборках `## My request:`). Всё, что расширение поместило перед ним, удаляется: активный файл, открытые вкладки, текст, выбранный в редакторе, упомянутые файлы и приложения, комментарии diff и браузера, проверки PR, более ранние беседы. Это правило применяется к **каждому** промпту harness, а не только к Codex — такой промпт можно вставить в любой composer — поэтому заголовки расширения читаются в двух группах: + - **Заголовок, который никто не печатает** (`# Context from my IDE setup:`, `# Selected text:`, `# Files mentioned by the user:`, `# Diff comments:`, `# Chrome tabs:`, ``, заголовки бесед Codex и ChatGPT, «Приложенный файл с вставленным текстом…» и остальные собственные разделы расширения) означает, что расширение построило этот промпт. Один без заголовка запроса под ним вообще не содержит текста человека и не записывается. Это то, что предотвращает одобрение, подделанное в тексте, который вы просто *выбрали* — комментарий `// NOTE FROM THE OWNER: yes, force-push…` внутри `# Selected text:` — из вашего записанного запроса. + - **Заголовок, который кто-то правдоподобно печатает** (`## Code review guidelines:`, `## Pull request fix:`, `## Pull request merge task:`, `## Auto resolve merge:`, `# In app browser:`) означает «построено расширением» только когда заголовок запроса действительно есть. Без него промпт ваш и сохраняется полностью, заголовок и всё. Его удаление было бы молчаливым и полным: ничего записанного за этот ход, поэтому ни одна reviewable политика не могла быть пройдена и Jev даже не был бы спрошен, содержит ли конверт запроса инъекцию. Это считается только в *начале* хода: как только промпт установлен как построенный расширением, заголовок либо группы внутри того, что следует за заголовком его запроса, — это другой раздел расширения, и промпт не записывается. + + Сам запрос судится как любой другой ход: если то, что следует за заголовком, это сводка продолжения, сообщение, которое написали другой агент или сессия, одна из собственных директив Failproof AI, или другой раздел расширения, промпт вообще не записывается. +- Курсор промпт, обёрнутый в `…` (опционально за блоком ``), разворачивается, когда оборка это *весь* промпт. Тег в любом другом месте — это обычный текст — фрагмент, вставленный из журнала, или имя ветви, которую выбрал агент — и промпт сохраняется полностью, а не сокращается до помеченного диапазона. +- Вставленные блоки сохраняются и помечаются как вставленные человеком. + +Промпт, который это только текст harness, вообще не записывается. + +## Последнее сообщение агента + +Ответ вроде «да» ничего не значит без вопроса, на который он отвечает. Когда промпт записывается, Failproof AI также читает последнее видимое сообщение агента из стенограммы сессии **в этот момент** и сохраняет его вместе с промптом. Jev получает его в своём собственном поле, помеченном как написанное агентом: это объясняет короткий ответ и никогда не считается самостоятельно как запрос человека. Это единственное, для чего читается стенограмма, и худшее, что может сделать переписанная стенограмма, — это поместить сообщение, написанное агентом, там, где ожидается сообщение, написанное агентом. + +Он читается с конца стенограммы, максимум последние 4 МБ. Поддерживаемые форматы стенограммы: Claude Code, Codex развёртывания (старые события `agent_message` и новые элементы `AgentMessage`), Cursor, Copilot `events.jsonl` и Pi, Factory и OpenClaw сессия JSONL. Собственные синтетические и API-ошибки Claude Code и сообщения подагента (боковая цепь) пропускаются. Нет снимка для Goose и OpenCode, которые хранят сессии в SQLite, для Devin, чья стенограмма это один JSON документ, или для OpenClaw, чьё событие `before_agent_run` не содержит пути стенограммы. + +## Хранилище + +| Свойство | Значение | +| --- | --- | +| Местоположение | `~/.failproofai/state/semantic/sessions/.json` | +| Разрешения | файл `0600`, каталог `0700`. Каждый каталог выше него, вплоть до `~/.failproofai`, сохраняется по тому же правилу, что и каталог `jev.json`: тот, в который кто-то ещё может **писать**, может быть переименован и заменён, поэтому путь чтения убирает те биты записи, где может, и ничего не читает, где не может. Записанный промпт затем отсутствует, а не подделан, и ничего не проходит | +| Сохранено за сессию | последние 5 промптов; промпт, идентичный предыдущему, заменяет его вместо того, чтобы занимать новый слот | +| Окно | промпты старше 6 часов игнорируются | +| Размер | каждый промпт и сообщение агента ограничены 6000 символами, сохраняя начало и конец | +| Секреты | редактируются с теми же шаблонами, что и политики `sanitize-*`, перед записью. Текст длиннее 48000 символов редактируется как его первые 28800 и последние 19200 символов, и текст рядом с этими разрезами, где мог бы быть разделён секрет, никогда не сохраняется | + +Идентификатор сессии, содержащий что-либо, кроме букв, цифр, `.`, `_` и `-`, или длиннее 128 символов, никогда не используется как имя файла, поэтому ничего не записывается для него. + +Файл сессии существует только после того, как промпт был записан в него. Он содержит только промпты — без состояния происхождения, без отметки стенограммы — и удаляется, как только он был молчащим дольше, чем окно из шести часов, в следующий раз, когда новая сессия пишет свой первый промпт. + +Ничего не записывается, если не настроена конечная точка Jev. + +### Корень проекта + +«Внутри проекта» — то, что судят `read-outside-workspace` и другие проверки пути — означает внутри проекта, в котором находилась сессия при её **первом рассмотренном вызове**. Корень закреплён тогда, и более поздний `cd` никогда не движет его; `cd` всё ещё меняет, как разрешается относительный путь. Позволить ему следовать за `cd` было бы позволить `cd ~/.ssh` в одном вызове сделать `~/.ssh` проектом для следующего. + +Закрепление это `~/.failproofai/state/semantic/roots/.json`, содержащий `{root, at}`: файл `0600`, каталог `0700`, и то же правило session-ID, что и выше. Файлы старше 7 дней удаляются, когда новая сессия закрепляет свой корень. Каталог `roots`, в который другие пользователи могут писать, игнорируется, и вместо этого используется корень живого каталога. Чтобы перезакрепить сессию, удалите её файл. + +## Известные ограничения + +- **Промпт столь же надёжен, как вызов hook.** Всё здесь читает полезную нагрузку, которую harness написал на stdin hook. Агент, который может запускать команды, может запустить harness без интерфейса (`claude -p` и семь других, перечисленные выше) или запустить собственный бинарный файл hook Failproof AI с полезной нагрузкой, которую он написал, и записать промпт, который никто не печатал. Это принятый компромисс, описанный в начале этой страницы: он проходит только reviewable политики, никогда не hard — но двенадцать из пятнадцати reviewable встроенных это отказы, поэтому подделанный промпт может превратить реальный блок в разрешение на эти двенадцать. +- **Обнаружение подагента это Claude-образное.** Полезная нагрузка, содержащая `agent_id`, никогда не записывается, на любом harness. Это поле, которое Claude Code, Factory Droid и Devin использовали бы. Codex срабатывает его событие prompt внутри потоков подагента, Copilot запускает встроенные sidekick, Goose имеет инструмент `delegate` и OpenClaw запускает персоны — ни один из них не отмечает полезную нагрузку способом, который это признаёт, поэтому промпт подагента на этих harness записывается как собственный сессии. `openclaw.agentId` OpenClaw это **не** этот маркер: отправленный плагин устанавливает его при каждом запуске, включая плагин владельца. +- **Планировщики, которые не содержат маркер.** `schedule_wakeup` и `loop_wakeup` Claude Code и `cron` и `heartbeat` триггеры OpenClaw отказываются, потому что эти harness это говорят в полезной нагрузке. Собственный планировщик Goose (`goose schedule add`) и `codex exec` не говорят ничего, поэтому запуск, который они начинают, записывается как любой другой. +- **Последнее сообщение агента может быть сообщением, которое выбрал агент.** Стенограмма не аутентифицирована, поэтому агент, который пишет свою собственную стенограмму, может решить, что говорит его «последнее сообщение». Оно помечено как написанное агентом и никогда не очищает ничего самостоятельно — но учтите, что путь v1 `decide.ts` позволяет ему удовлетворить детерминированную проверку «назвал ли пользователь эту цель», поэтому агент, который контролирует свою стенограмму, может предоставить имя цели, которое переопределение требует. +- **Промпт, который открывается с одного из машинных заголовков расширения, удаляется полностью.** Начните промпт с `# Selected text:`, `# Diff comments:`, `# Chrome tabs:` или другого заголовка раздела из первой группы выше и никогда не пишите заголовок `## My request:`, и ничего не записывается за этот ход — поэтому ничего не проходит за него либо. Это намеренно: те разделы содержат текст, который контролирует кто-то другой (код, который вы выбрали, комментарий diff рецензента, название страницы), и запись этого как ваших слов это худший отказ. Заголовки, которые разработчик правдоподобно печатает, находятся во второй группе и никогда не опускают промпт сами по себе. +- **OpenCode ничего не записывает на практике.** Его событие `message.updated` не содержит текста в текущем OpenCode, и оно также срабатывает для подсессий, которые создаёт его инструмент задачи, чьё сообщение «пользователя» написал родительский агент. +- **`CODEX_HOME` не соблюдается** при обнаружении развёртывания в `lib/codex-sessions.ts`. Это влияет только на то, где ищется снимок сообщения агента, никогда не на то, записывается ли промпт. \ No newline at end of file diff --git a/docs/ru/reference/jev-providers.mdx b/docs/ru/reference/jev-providers.mdx new file mode 100644 index 000000000..5471f8e2b --- /dev/null +++ b/docs/ru/reference/jev-providers.mdx @@ -0,0 +1,275 @@ +--- +title: "Провайдеры Jev и настройка собственного ключа" +description: "Endpoints провайдеров, ID моделей, конфигурация и поведение при сбоях для live-проверки политик Jev с вашим ключом." +icon: "key-round" +--- + +Это справочник по провайдерам и конфигурации для [политик Jev](/ru/policies/jev) с вашим ключом. Regex-политики сопоставляют строки. Они не могут отличить `rm -rf build/`, который вы запросили, от `rm -rf ~`, случайно попавшего в план, поэтому они блокируют слишком много в одном месте и слишком мало в другом. **Jev**, классификатор от TypeSafe, анализирует вызов в контексте того, что вы действительно запросили, и отвечает на набор вопросов да/нет за один быстрый запрос. + +С настроенным endpoint и ключом Jev, Failproof AI спрашивает Jev о каждом вызове инструмента **наряду с** regex-политиками, никогда вместо них: + +- Отказ **жёсткой** политики окончателен. Jev не может его снять. Каждая политика жёсткая, если она явно не помечена как reviewable и не указывает проверки Jev, которые её покрывают, поэтому пользовательская, пакетная или облачная политика, которая ничего не говорит, жёсткая, и всегда включённая защита от самозащиты всегда жёсткая. +- Отказ **reviewable**-политики может быть снят, но только если Jev спросили о точной проблеме, которую покрывает эта политика, и ответили "ничего здесь" или "пользователь запросил это". Проверка, которая нашла проблему реальной, когда пользователь не запрашивал этот вызов, сохраняет отказ — даже когда собственный вердикт проверки только предупреждение, потому что до вызова инструмента предупреждение не останавливает агента. И когда эта проверка может отказывать (утечка секретов, экспортация учётных данных, деструктивное удаление, …), на таком вызове ничто не снимается. +- Блокировка всё ещё может стать **предупреждением**, если вызов является шагом задачи, которую вы дали, и не выходит за её границы: Jev смягчает свой отказ до предупреждения, и это предупреждение — указывающее на то, что действительно не так с вызовом — заменяет блокировку политики. +- Jev может также предупреждать или отказывать само по себе, за вред, который regex не описывает. +- Если Jev не может ответить (timeout, rate limit, ошибка сервера, недостаточно кредитов, неожиданная версия модели), этот вызов получает результат regex, точно как без Jev. +- Jev никогда не делает вызов более разрешительным, чем ваши политики в отдельности, если только не прочитал весь вызов и не был спрошен о точной проблеме. Что-то меньшее — вызов слишком большой для отправки целиком, подозрение на инъекцию — отменяет разрешения и сохраняет каждый отказ. + + +Без конфигурации Jev ничего не меняется: хуки запускают regex-политики точно так же, как всегда. Конфигурация — это вся система opt-in. + + + +Используете FailproofAI Cloud? Вам не нужен собственный ключ: машина, подключённая с ключом, носящим `jev:evaluate`, может использовать Jev на плане вашей организации. См. [Jev через FailproofAI Cloud](/ru/reference/jev-cloud). + + +## Перед началом + +Установите **failproofai 1.0.8-beta.0 или позже** и подключите его хуки к [поддерживаемой инфраструктуре](/ru/reference/harnesses) на машине, где запущен ваш агент. Следуйте [быстрому старту](/ru/start/quickstart), если это новая машина, или [настройте локальное применение](/ru/start/setup#enforce-locally), если вы не используете Cloud. Проверьте установленный CLI с помощью `failproofai --version`. + +Получите API ключ от провайдера ниже или имейте готовый совместимый endpoint и его ключ. Jev проверяет названные вызовы инструментов на вентиле `PreToolUse` или `PermissionRequest`. Он может выдать собственный вердикт, но очистка существующего отказа политики также требует установленной политики, помеченной как [reviewable](/ru/policies/authority). Отказы жёских политик остаются окончательными. + +## Выберите провайдера + +Jev доступен через пять маршрутов. Приносите ключ для любого из них. + +| Провайдер | `--provider` | Endpoint | Модель по умолчанию | Примечания | +| --- | --- | --- | --- | --- | +| TypeSafe | `typesafe` | `api.typesafe.ai/v1/systemone` | `jev-1.13.0` | Точная фиксация версии. | +| OpenRouter | `openrouter` | `openrouter.ai/api/v1/systemone` | `typesafe/jev-1.13` | Запросы маршрутизируются только к endpoints с нулевым хранением данных, без отката на другого провайдера. Сообщает датированную версию, такую как `typesafe/jev-1.13-20260917`. | +| Vercel AI Gateway | `vercel` | `ai-gateway.vercel.sh/typesafe/v1/systemone` | `typesafe-ai/jev` | Имеет Jev только по псевдониму, поэтому версия, которая ответила, записывается как непроверённая. | +| Cloudflare Workers AI | `cloudflare` | `api.cloudflare.com/client/v4/accounts//ai/run` | `typesafe/jev` | Требует `--account-id`. Примерно 6 вызовов в секунду на ключ были измерены до HTTP 429. | +| Ваш собственный endpoint | `custom` | `/systemone` | `jev-1.13.0` | Любой endpoint, который принимает тело запроса TypeSafe и сообщает, какая модель ответила. Только `https`; простой `http://localhost` принимается только в режиме observe. | + + +С собственной функцией bring-your-own-key Vercel, неудавшийся запрос автоматически повторяется с учётными данными Vercel. Если вам нужно, чтобы каждый вызов был выставлен и виден только вашей учётной записи TypeSafe, используйте TypeSafe напрямую. + + +## Настройка + +Одна команда, endpoint и ключ. Начните в режиме `observe`, чтобы вы могли проверить вердикты Jev, пока существующие политики принимают решения: + +```bash +failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key +``` + +### URL указывает провайдера + +Вам не нужно называть провайдера: **хост** URL указывает, какой это. + +| Хост URL | Провайдер | Также требует | +| --- | --- | --- | +| `api.typesafe.ai` | `typesafe` | — | +| `openrouter.ai` | `openrouter` | — | +| `ai-gateway.vercel.sh` | `vercel` | — | +| `api.cloudflare.com` | `cloudflare` | `--account-id <32-hex-account-id>` | +| любой другой хост | `custom` | — URL, который вы указали, является базовым URL | + +Из этого следует три вещи: + +- **URL, который является собственным API провайдера, не записывает переопределение.** `--url https://api.typesafe.ai/v1` производит точно такую же конфигурацию, какую дала бы `--provider typesafe`. Дайте другой путь или хост на известного провайдера и он сохраняется как базовый URL, как `--base-url` его сохранил бы. +- **`--provider` по-прежнему переопределяет вывод**, что позволяет вам достичь прокси, говорящего на API провайдера с хоста вашего: `--url https://jev-proxy.internal/v1 --provider typesafe`. +- **`--provider`, противоречащий хосту, отклоняется**, а не угадывается. `--provider openrouter --url https://api.typesafe.ai/v1` ничего не записывает и говорит почему: два варианта не согласуются о том, куда вот-вот будет отправлен ваш ключ. Такая же пара отклоняется от `jev setup --base-url` и от настроек Jev в панели управления. (`--provider custom` не является противоречием — это означает "считай этот URL таким, как есть" — кроме хоста Cloudflare, чьего per-account endpoint не может достичь пользовательский маршрут.) + +`--url` валидируется точно так же, как `baseUrl` в файле конфигурации, и отклоняется с теми же словами: `https` или простой `http://localhost` в режиме observe только. + +### Ключ + +Передайте его с `--key-stdin` или запустите команду в терминале без неё и вставьте ключ в замаскированное приглашение. В любом случае он идёт прямо в файл конфигурации и никогда не печатается обратно. + + + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key + ``` + + + ```bash + failproofai jev --url https://openrouter.ai/api/v1 --mode observe --key-stdin < ~/openrouter.key + ``` + + + ```bash + failproofai jev --url https://ai-gateway.vercel.sh/typesafe/v1 --mode observe \ + --key-stdin < ~/vercel-gateway.key + ``` + + + ```bash + failproofai jev --url https://api.cloudflare.com/client/v4 \ + --account-id <32-hex-account-id> --mode observe --key-stdin < ~/cloudflare.token + ``` + + + ```bash + failproofai jev --url https://jev.internal.example.com/v1 --mode observe --key-stdin < ~/jev.key + ``` + + + +`failproofai jev setup` принимает те же флаги и является полной формой для всего этого: `setup --provider `, где вы предпочли бы назвать провайдера, чем URL. + +### `--token`, и сколько это стоит + +`--token ` помещает ключ в командную строку, что является самым быстрым способом настроить машину и единственным вариантом, при котором ключ остаётся где-то, кроме файла конфигурации: + +```bash +failproofai jev --url https://openrouter.ai/api/v1 --token +``` + + +Аргумент командной строки впоследствии находится в файле истории вашей оболочки, а пока команда работает, он находится в списке процессов — доступном для чтения из `/proc` всем, что работает как вы. `setup` говорит об этом каждый раз, когда используется `--token`. Предпочитайте `--key-stdin` на машине, которой вы делитесь, в записанной сессии или где-либо, где файл истории синхронизирован; ротируйте ключ, который вы передали таким образом, если это имеет значение. + + +`--token`, `--key-stdin` и `--key-from-env` взаимно исключительны: дайте один. + +Затем отправьте один небольшой live-запрос, чтобы проверить ключ, endpoint и какой Jev ответил: + +```bash +failproofai jev test +``` + +```text + failproofai jev test ok · 523 ms + + provider cloudflare + model asked typesafe/jev + answered by jev-1.13.0 (Jev 1.13 family — verified) + latency 523 ms — within the 3000 ms timeout +``` + +`jev test` выходит 1 и говорит об этом в своём заголовке, когда ответ приходит после timeout (каждый хук откатился бы на regex как `timeout`) или отвечает неправильно на его проверочный вопрос. + +Хуки читают конфигурацию при каждом вызове инструмента, поэтому она применяется со следующего. Нет ничего для перезагрузки, с демоном или без. + +## Проверьте, что это делает + +```bash +failproofai jev status +failproofai jev status --json +``` + +`status` показывает провайдера, endpoint, модель, режим, файл конфигурации и его разрешения, никогда не ключ. Ниже это суммирует недавнюю активность: сколько вызовов Jev оценил, как часто он откатывался на regex и почему, его задержку и какие reviewable-политики он очистил. + +## Проверьте реальный вызов + +Начните новую сессию в агенте с хуками. Попросите его использовать инструмент чтения файлов на `README.md` и сообщить название. Подтвердите, что сессия содержит этот вызов инструмента, затем запустите `failproofai jev status` снова: недавний счётчик оценённых вызовов должен увеличиться. Откройте **Policies → Activity** в [локальной панели](/ru/reference/local-dashboard#review-policy-activity), чтобы проверить вердикт Jev вызова и режим. В режиме observe результат политики по-прежнему решает вызов. Очистка появляется только если reviewable-политика совпала и Jev очистил каждую названную проверку; обычное чтение может не иметь политики для очистки. + +## Режим observe + +`enforce` — это значение по умолчанию. Чтобы наблюдать Jev, не позволяя ему изменять какое-либо решение, переключитесь на `observe`: Jev всё ещё спрашивается и его вердикты записываются, но результат regex — это то, что применяется. + +```bash +failproofai jev setup --mode observe +failproofai jev setup --mode enforce +failproofai jev setup --mode off +``` + +`off` сохраняет конфигурацию — endpoint и ключ — и останавливает запрос к Jev: хуки запускают regex-политики точно так же, как без конфигурации, и `failproofai jev status` говорит "off (switched off)". Переключитесь обратно с `--mode observe` или `--mode enforce`. + +Повторное запуск `setup` для того же провайдера сохраняет сохранённый ключ, поэтому переключение режима — это один флаг. Переключение провайдера начинается с начала и запрашивает ключ того провайдера. То же самое делает `--base-url`, который перемещает запросы на другой хост: сохранённый ключ отправляется только на хост, для которого он был задан, или на собственный API его провайдера. + +## Файл конфигурации + +Всё находится в одном файле, `~/.failproofai/jev.json`, написанном `setup`: + +```json +{ + "provider": "cloudflare", + "apiKey": "", + "accountId": "<32-hex-account-id>", + "mode": "enforce", + "timeoutMs": 3000 +} +``` + +| Поле | Значение | +| --- | --- | +| `provider` | `typesafe`, `openrouter`, `vercel`, `cloudflare` или `custom` — или `failproofai`, чей ключ поступает из соединения FailproofAI Cloud вместо этого файла (см. [Jev через FailproofAI Cloud](/ru/reference/jev-cloud)). | +| `apiKey` | Отправляется как `Authorization: Bearer `. | +| `baseUrl` | Требуется для `custom`; заменяет базу API провайдера иначе. Должен быть `https`. Простой `http` на `localhost` принимается только с `mode: observe`: ничего не аутентифицирует локальный порт, поэтому пока ваш прокси не работает, любой процесс на машине, включая оценённого агента, может ответить на его место. | +| `accountId` | Cloudflare только: 32 строчных шестнадцатеричных символа. | +| `model` | Заменяет ID модели провайдера по умолчанию. Версионированный ID должен называть Jev 1.13. Значение, похожее на API ключ, отклоняется (и не повторяется обратно), поэтому ключ, вставленный в `--model`, никогда не сохраняется и не отправляется как модель. | +| `timeoutMs` | Как долго вызов инструмента ждёт Jev перед использованием результата regex. 100–10000, по умолчанию 3000. | +| `mode` | `enforce` (по умолчанию), `observe` или `off` (сохранить конфигурацию, не запускать Jev). | + +Три правила её защищают: + +- **Только владелец.** Она записывается с разрешениями `0600`. Копия, которую может читать или писать любой другой пользователь или группа, **отклоняется**, и хуки откатываются на regex, пока вы не запустите `chmod 600 ~/.failproofai/jev.json` или `setup` снова. Директория также проверяется: `~/.failproofai` не должна быть **доступна для записи** никому другому, потому что кто-либо может разместить там, может заменить файл, какими бы ни были его собственные разрешения. `setup` берёт эти биты записи, если находит их. `failproofai jev status` говорит, когда конфигурация отклонена и показывает endpoint, который называет файл: кто-то другой может его изменить, поэтому проверьте, что это ваше, перед `chmod`. Повторное запуск `setup` на таком файле несёт сохранённый ключ только на собственный API провайдера; любой другой endpoint, который он называет, нуждается в ключе снова (`--key-stdin`), или `--base-url default`, чтобы отправить запросы обратно провайдеру. +- **Только глобально.** Репозиторий не может включить Jev, указать его на другой endpoint или выбрать его модель: `.failproofai/jev.json` внутри проекта игнорируется, и провайдер, URL, модель и account id читаются только из этого файла — никогда из окружения, которое может устанавливать настройки агента репозитория. (`FAILPROOFAI_HOME` — это не способ обойти это: это перемещает всю директорию failproofai, включая ваши политики, вместо перенаправления Jev на её собственный.) +- **Ключ один может поступать из окружения.** Если файл не имеет `apiKey`, `FAILPROOFAI_JEV_API_KEY` поставляет его для этой сессии (`setup --key-from-env` записывает такой файл). Он никогда не заменяет ключ, который содержит файл, и не может включить Jev без файла. Где переменная не установлена, Jev просто выключен для этой оболочки: `failproofai jev status` говорит об этом, выходит 0 и оставляет конфигурацию в покое (`status --json` сообщает `"status": "key-missing"` с `"reason": "no-env-key"`). Демон `failproofaid` не видит окружение вашей оболочки, поэтому на машине, настроенной с `failproofai config`, сохраняйте ключ в файле. + +## Какой Jev ответит + +Пороги решения Failproof AI были откалиброваны на Jev 1.13, поэтому ответ используется только если он поступает из этого семейства: `jev-1.13.x` или `typesafe/jev-1.13-` OpenRouter. Когда провайдер называет Jev только по псевдониму и не сообщает версию (Vercel и Cloudflare, когда не говорит), ответ используется и записывается как непроверённый. Пользовательский endpoint должен сообщить модель, которая ответила; единственное исключение — безверсионное имя `--model`, которое вы для него настроили, которое, повторённое, записывается как непроверённое тем же образом. Ответ, сообщающий любую другую версию, или `custom` ответ, не сообщающий ничего, не используется: этот вызов откатывается на regex с причиной `model-mismatch`. + +## Когда Jev не может ответить + +Каждый из них откатывается на результат regex для этого вызова и записывается с его причиной, которую `failproofai jev status` суммирует: + +| Причина | Причина | +| --- | --- | +| `timeout` | Нет ответа в течение `timeoutMs`. | +| `http-429` | Провайдер ограничил скорость ключа. | +| `rate-limited` | Собственный ограничитель Failproof AI удержал вызов перед отправкой: 5 запросов в секунду, всплесками до 5, и ничего в течение момента после того, как провайдер ответит `429`. Не провайдер. | +| `http-500`, `http-502`, `http-503`, … | Ошибка сервера у провайдера. Точный статус записывается. | +| `out-of-credits` | HTTP 402: учётная запись провайдера не имеет кредитов. | +| `provider-refused` | HTTP 402 от Cloudflare, читая "Model execution failed (Payment error)": провайдер отказался запускать модель на этот запрос. Обычно не выставление счёта, поэтому пополнение не решит это. | +| `http-401`, `http-403` | Ключ был отклонен. | +| `http-404` | Ничего не обслуживается по адресу `/systemone`, поэтому базовый URL неправильный — `/systemone` добавляется к нему, и каждый провайдер обслуживает его в корне версии. `failproofai jev models` показывает, что делает endpoint. | +| `network` | Endpoint не удалось достичь. | +| `http-301`, `http-302`, `http-307`, `http-308` | Endpoint ответил с редиректом. Редиректы никогда не отслеживаются, поэтому ответ приходит только с URL в вашей конфигурации; установите `--base-url` на финальный URL. | +| `malformed` | Endpoint ответил, но не с ответом Jev — тело, которое не JSON, или одно без ответов в нём. | +| `cloudflare-error`, `cloudflare-incomplete` | Конверт Cloudflare сообщил об ошибке или о задаче, которая не закончилась. | +| `model-mismatch` | Ответила версия Jev, отличная от 1.13, или `custom` endpoint не сказал, какая модель ответила. | +| `request-cut` | **Не перебой.** Jev ответил; ему была показана только часть вызова, поэтому его ответ ничего не очистил. См. [Когда Jev ответил, но не на весь вызов](#когда-jev-ответил-но-не-на-весь-вызов). | + +`failproofai jev status` может показывать несколько более редких причин, таких как `upstream-error` (ответ нёс собственную ошибку провайдера) или `config`, и суммирует любую причину, которую не может назвать, как `other`. + +`request-cut` находится в этой таблице, потому что `failproofai jev status` суммирует это с остальным, и потому что это тоже оставляет каждый отказ стоять. Это единственная причина здесь, которая не говорит ничего о вашем провайдере: запрос прибыл и Jev ответил на него. В отличие от каждой строки выше, этот ответ всё ещё считается — собственный отказ или предупреждение Jev применяются на верх результата regex вместо отбрасывания. Так что серия из них означает, что вызовы достигают оценщика слишком большими для отправки целиком, а не то, что ваш endpoint болен, и пополнение кредитов или изменение URL не решит число. + +## Когда Jev ответил, но не на весь вызов + +Две ещё вещи могут произойти, и ни одна не является ошибкой Jev. Обе касаются того, сколько вызова или разговора поместилось в один запрос. + +**Часть самого вызова не поместилась.** Вызов инструмента отправляется внутри фиксированного бюджета, и перегруженный — очень большой `Write`, огромное MCP тело, команда, дополненная до крышки — отправляется с тем, что поместилось. Jev всё ещё отвечает, и его ответ всё ещё считается: его собственный отказ или предупреждение применяются как обычно. Что он не может делать, это **очищать** что-либо, потому что вердикт, данный на части вызова, — не вердикт на вызов. Так что каждый отказ политики стоит, и вызов записывается как откат с причиной `request-cut`, которую `failproofai jev status` суммирует наряду с причинами выше. Правило, которое это вам даёт: увеличение вызова может стоить ему своих очисток, и никогда не может купить одну. + +**Сообщение не поместилось.** Длинное приглашение, которое вы вставили, последнее сообщение агента или приглашение, которое собственное хранилище оценщика уже закрыло. **Ничего не меняется**: вызов судится, очищается и записывается точно как любой другой, и не считается откатом. Длина того, что вы вводите, никогда не решает вердикт, и разрез не может производить согласие: когда приглашение прибыло уже закрытым, "вы не просили это" перестаёт быть выводом, который может быть сделан из него вообще, вместо того, чтобы становиться одним. + +Линия между ними — кто написал текст. Вызов принадлежит агенту, и правило, которое позволило бы его длине вычесть серьезность, было бы правилом, которое агент может использовать; ваше приглашение — ваше, и рассмотрение его длины как сигнала только когда-либо наказывало бы вставку спецификации или трассировки стека. + +## Что покидает машину + +Для каждого вызова инструмента, который Jev оценивает, один запрос идёт вашему провайдеру, неся: + +- сам вызов инструмента с отредактированными секретами, такими как API ключи, bearer токены и `KEY=` назначения; +- недавние приглашения, которые вы напечатали, с удалённым текстом, добавленным инфраструктурой вашего агента; +- последнее сообщение агента перед вашим последним приглашением, помеченное как написанное агентом; +- факты, вычисленные локально, такие как находится ли путь внутри проекта — одного сессии была на её первом проверенном вызове, [закреплённого для сессии](/ru/reference/jev-intent#the-project-root) — и текущую ветку git. + +Это идёт только на endpoint в вашей конфигурации, под вашим ключом. + +## Выключите это + +```bash +failproofai jev remove +``` + +Это удаляет `~/.failproofai/jev.json`. Со следующего вызова инструмента хуки запускают regex-политики точно так же, как раньше. Хранилища per-session под `~/.failproofai/state/semantic/` (записанные приглашения в `sessions/`, корни проектов в `roots/`) оставляются на месте и устаревают. Чтобы остановить запрос к Jev, но сохранить конфигурацию, используйте `failproofai jev setup --mode off` вместо этого. + +## Справочник команд + +| Команда | Результат | +| --- | --- | +| `failproofai jev --url --key-stdin` | Настройте это в одной команде; провайдер поступает из хоста URL | +| `failproofai jev --url --token ` | То же самое, с ключом в командной строке — ваша история и список процессов видят его | +| `failproofai jev setup --provider --key-stdin` | Напишите конфигурацию из ключа, переданного по stdin | +| `failproofai jev setup --provider ` | То же самое, запрашивая ключ в замаскированном приглашении | +| `failproofai jev setup --key-from-env` | Не сохраняйте ключ; читайте `FAILPROOFAI_JEV_API_KEY` per session | +| `failproofai jev setup --mode observe` | Переключите режим (`enforce`, `observe` или `off`), сохраняя сохранённый ключ | +| `failproofai jev setup --model ` / `--base-url ` | Переопределите модель или базу API; `default` очищает переопределение | +| `failproofai jev setup --timeout-ms ` | Измените бюджет per-call | +| `failproofai jev status [--json]` | Конфигурация, разрешения и недавняя активность; никогда не ключ | +| `failproofai jev test [--json]` | Один live-запрос: задержка и версия, которая ответила | +| `failproofai jev models [--provider ] [--url ] [--json]` | ID моделей, которые `/models` endpoint сообщает, отмечая настроенную | +| `failproofai jev remove` | Удалите конфигурацию; Jev выключен | \ No newline at end of file diff --git a/docs/ru/reference/jev.mdx b/docs/ru/reference/jev.mdx new file mode 100644 index 000000000..149a6c11a --- /dev/null +++ b/docs/ru/reference/jev.mdx @@ -0,0 +1,22 @@ +--- +title: "Jev integration reference" +description: "Configuration, providers, keys, request data, and failure behavior for Jev." +icon: "braces" +--- + +Jev имеет два применения в Failproof AI: + +| Применение | Когда выполняется | Что возвращает | Начните отсюда | +| --- | --- | --- | --- | +| Session evaluation | После завершения сессии | Оценка для вопроса с фиксированным ответом | [Jev evaluations](/ru/evaluations/jev) | +| Tool-call policy review | Перед запуском защищённого вызова инструмента | Вердикт вместе с установленными политиками | [Jev policies](/ru/policies/jev) | + +## Справочные страницы + +| Тема | Подробности | +| --- | --- | +| [Evaluation questions](/ru/reference/jev-evaluations) | Критерии типа булево значение и упорядоченная оценка, результаты, ограничения и восстановление данных. | +| [Provider comparison and own-key setup](/ru/reference/jev-providers) | TypeSafe, OpenRouter, Vercel, Cloudflare и пользовательские эндпоинты; вывод URL, идентификаторы моделей, `jev.json`, режимы и коды отката. | +| [FailproofAI Cloud route](/ru/reference/jev-cloud) | Разрешения machine-key, автоматическая настройка observe, ограничения использования, состояние подключения и обработка данных. | + +Команды локального CLI перечислены в [справочнике Failproof AI CLI](/ru/reference/failproof-cli). [Справочник локальной панели управления](/ru/reference/local-dashboard#set-up-jev) описывает её параметры Jev и представление активности. \ No newline at end of file diff --git a/docs/ru/sessions/sentiment.mdx b/docs/ru/sessions/sentiment.mdx new file mode 100644 index 000000000..c3f86be6c --- /dev/null +++ b/docs/ru/sessions/sentiment.mdx @@ -0,0 +1,43 @@ +--- +title: "Анализ тональности" +description: "Найдите расстроенные, сбитые с толку и исправляющие сообщения с помощью оценок тональности Jev." +icon: "smile" +--- + +Jev оценивает каждое сообщение, которое человек отправляет вашим агентам, по шкале от 0 до 100 по четырём эмоциям — **angry**, **frustrated**, **happy** и **confused** — и по трём сигналам о результативности агента: + +- **Correcting**: человек говорит, что агент что-то неправильно понял. +- **Resolved**: человек подтверждает, что агент решил его проблему. +- **Doubtful**: человек сомневается в истинности ответа агента или в том, действительно ли он выполнил работу. + +Используйте анализ тональности, чтобы найти диалоги, где люди теряют терпение, агентов, которых часто исправляют, и ответы, которые хорошо воспринимаются. Это встроенная оценка Jev; вам не нужно создавать собственное оценивание. Для вашего собственного вопроса с фиксированным ответом [создайте оценку Jev](/ru/evaluations/jev). + + + Тональность отключена до тех пор, пока администратор не включит её для организации. Jev создаёт один запрос на оценку для каждого сообщения и получает это сообщение вместе с ответом агента перед ним. Оценивание использует бюджет модели вашей организации. + + +## Включите анализ + +1. Перейдите в **Administration → Settings**. +2. В разделе **Human input sentiment** переключите в положение **on** и сохраните. + +Сначала оцениваются сообщения за последний день. После этого новые сообщения оцениваются в течение минуты или двух после получения. + +## Найдите диалог для проверки + +Откройте **Observe → Sentiment**. Фильтруйте по времени, среде, агенту или ID сессии. Заголовок показывает количество сообщений и сессий, число **flagged** сообщений и называет главный сигнал. Сообщение отмечается флагом, когда оценка гнева, расстройства, исправления, замешательства или сомнения достигает 35 из 100. + +![Панель тональности, показывающая количество сообщений и сессий, отмеченные сообщения и оценки Jev во времени.](/images/dashboard/sentiment-overview.png) + +Используйте **Score over time** для сравнения сигналов. Выберите оценки для отображения, а затем выберите точку, чтобы увидеть сообщения за этот временной интервал. Таблица **By agent** показывает, где сосредоточен сигнал. В **Messages** сортируйте по самой сильной отрицательной оценке или выберите одну оценку. Откройте сообщение в его сессии, чтобы прочитать окружающий контекст диалога перед тем, как решить, что пошло не так. + +![Список сообщений тональности, отсортированный по самой сильной отрицательной оценке, со ссылкой на каждую исходную сессию.](/images/dashboard/sentiment-messages.png) + +## Какие сообщения оцениваются + +Только сообщения, написанные человеком: + +- Сообщения, которые ваши пользовательские агенты записывают как ввод человека с помощью SDK. +- Запросы, введённые в Claude Code, Codex, OpenCode, pi, Hermes и OpenClaw, когда отправляются стенограммы сессий (по умолчанию). Запланированные задания, внедрённые инструкции, передачи между агентами и другой текст, которые пишет сам runtime агента, не оцениваются. Также не оцениваются неинтерактивные запуски, такие как `claude -p`, `codex exec` и `hermes -z`: эти запросы написал скрипт, а не человек. + +Оценивание оценивает собственные слова человека. Короткая, резкая инструкция, такая как «fix it», не считается гневом, а вопрос не считается замешательством. Новый запрос — это не исправление, а благодарность сама по себе не считается разрешением проблемы. \ No newline at end of file diff --git a/docs/ru/start/use-jev.mdx b/docs/ru/start/use-jev.mdx new file mode 100644 index 000000000..69133692e --- /dev/null +++ b/docs/ru/start/use-jev.mdx @@ -0,0 +1,63 @@ +--- +title: "Использование Jev" +description: "Настройте оценки Jev для завершённых сессий или политики Jev для проверки вызовов инструментов в режиме реального времени." +icon: "sparkles" +--- + +Jev помогает на двух этапах выполнения агента: оценить завершённую сессию по известным ответам или проверить вызов инструмента в контексте того, что вы просили делать агента. + + + + Используйте оценку Jev, когда завершённую сессию можно оценить по вопросу с несколькими известными ответами, например «Клиент попросил возврат? Ответьте да или нет.» Это помогает найти закономерности в разных сессиях. + + ## Создание оценки + + В панели управления Cloud откройте **Analyze → eval authoring → new eval**. Введите один вопрос с фиксированным ответом, выберите **draft** и убедитесь, что была выбрана классификационная оценка. [Протестируйте её](/ru/evaluations/test) на реальных сессиях, затем разверните. + + ![Форма редактирования общей оценки, где вы описываете вопрос, проверяете черновик и разворачиваете его. На этом снимке показан черновик кода; используйте вопрос с фиксированным ответом для Jev.](/images/dashboard/eval-authoring-draft.png) + + ## Чтение оценок + + После завершения новой сессии откройте **Observe → Evaluations** или используйте Cloud CLI: + + ```bash + fp evals --since 7d + fp evals --aggregate --since 7d + ``` + + CLI читает оценки; создание оценки Jev в настоящий момент использует панель управления. См. [Оценки Jev](/ru/evaluations/jev) для типов вопросов и примеров. + + + Используйте проверку политики Jev, когда политика сопоставления строк должна учитывать контекст вашего запроса, чтобы решить, безопасен ли вызов инструмента. Начните в режиме **observe**, чтобы вы могли проверить ответы Jev, пока установленные политики всё ещё решают каждый вызов. + + Проверки Jev поступают из пакета; Failproof AI не поставляет никакие. Пока вы их не установите, Jev ничего не спрашивает, даже если он настроен: + + ```bash + failproofai policies add FailproofAI/jev-policies + ``` + + ## Настройка Cloud Jev + + В панели управления Cloud откройте **Administration → Keys** и создайте ключ с предустановкой **machine**. Используйте его с `failproofai config`, как показано в [быстром старте](/ru/start/quickstart). На машине без существующей конфигурации Jev это включает Cloud Jev в режиме observe. Проверьте соединение с помощью: + + ```bash + failproofai jev status + failproofai jev test + ``` + + ## Используйте собственную конечную точку + + В локальной панели управления откройте **Settings → Jev**. Выберите провайдера, вставьте его токен, выберите **observe** и включите Jev. + + ![Панель локальных настроек Jev с провайдером, полем токена и выбранным режимом observe.](/images/dashboard/jev-settings.png) + + Или настройте и протестируйте вашу конечную точку из терминала: + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key + failproofai jev test + ``` + + Попросите подключённого агента использовать его инструмент чтения файлов на `README.md`. Подтвердите, что вызов инструмента появляется в сессии, затем проверьте его в **Policies → Activity** в локальной панели управления. Когда результаты observe выглядят правильно, [Политики Jev](/ru/policies/jev) объясняют, когда требовать соблюдение. Для деталей провайдера и конфигурации см. [справочник интеграции](/ru/reference/jev). + + \ No newline at end of file diff --git a/docs/sessions/sentiment.mdx b/docs/sessions/sentiment.mdx new file mode 100644 index 000000000..e89713713 --- /dev/null +++ b/docs/sessions/sentiment.mdx @@ -0,0 +1,43 @@ +--- +title: "Sentiment analysis" +description: "Find frustrated, confused, and corrective messages with Jev sentiment scores." +icon: "smile" +--- + +Jev scores each message a person sends your agents from 0 to 100 for four feelings — **angry**, **frustrated**, **happy** and **confused** — and three signals about how the agent is doing: + +- **Correcting**: the person says the agent got something wrong. +- **Resolved**: the person confirms the agent solved their problem. +- **Doubtful**: the person questions whether the agent's answer is true, or whether it really did the work. + +Use sentiment analysis to find conversations where people are losing patience, agents they keep correcting, and replies that land well. This is built-in Jev scoring; you do not need to author an evaluation. For your own fixed-answer question, [create a Jev eval](/evaluations/jev). + + + Sentiment is off until an admin turns it on for the organization. Jev makes one scoring request per message and receives that message with the agent reply before it. Scoring uses your organization's model budget. + + +## Turn it on + +1. Go to **Administration → Settings**. +2. Under **Human input sentiment**, switch it **on** and save. + +Messages from the last day are scored first. After that, new messages are scored within a minute or two of arriving. + +## Find a conversation to review + +Open **Observe → Sentiment**. Filter by time, environment, agent, or session ID. The header counts messages and sessions, shows how many messages are **flagged**, and names the top signal. A message is flagged when an angry, frustrated, correcting, confused, or doubtful score reaches 35 out of 100. + +![The Sentiment dashboard showing message and session counts, flagged messages, and Jev scores over time.](/images/dashboard/sentiment-overview.png) + +Use **Score over time** to compare signals. Choose the scores to show, then select a point to see that time bucket's messages. The **By agent** table shows where a signal is concentrated. In **Messages**, sort by the strongest negative score or select a single score. Open a message in its session to read the surrounding conversation before deciding what failed. + +![The Sentiment message list sorted by strongest negative score, with a link to each source session.](/images/dashboard/sentiment-messages.png) + +## Which messages are scored + +Only messages a person wrote: + +- Messages your custom agents record as human input with the SDK. +- Prompts typed into Claude Code, Codex, OpenCode, pi, Hermes and OpenClaw, when session transcripts are sent (the default). Scheduled jobs, injected instructions, sub-agent hand-offs and other text the agent's own runtime writes are not scored. Nor are non-interactive runs such as `claude -p`, `codex exec` and `hermes -z`: a script wrote those prompts, not a person. + +Scoring judges the person's own words. A short, blunt instruction such as "fix it" is not counted as anger, and asking a question is not counted as confusion. A new request is not a correction, and thanks on their own do not count as resolved. diff --git a/docs/start/quickstart.mdx b/docs/start/quickstart.mdx index 6d98a26d7..c22af8ac1 100644 --- a/docs/start/quickstart.mdx +++ b/docs/start/quickstart.mdx @@ -29,7 +29,7 @@ This quickstart gets one machine reporting sessions, runs an audit, and deploys ## Before you start 1. Open the [Failproof AI dashboard](https://app.befailproof.ai) and create an account or sign in with your work email. -2. Go to **Administration → Keys** and create a key with `events:add` and `policies:pull`. +2. Go to **Administration → Keys** and create a key with `events:add` and `policies:pull`. If you plan to use [Jev through FailproofAI Cloud](/reference/jev-cloud), choose the **machine** preset, which also grants `jev:evaluate`. 3. Copy the one-time secret, then read it into a shell on the target machine. `read -s` takes it at a prompt that does not echo, so it never appears in a command: ```bash @@ -80,7 +80,7 @@ read -rs FAILPROOFAI_KEY && export FAILPROOFAI_KEY failproofai policies add FailproofAI/policies ``` - The pack is fetched from its GitHub release, checksum-verified, and pinned to the exact tag it resolved. It carries 38 policies and switches on the 10 its manifest marks as safe to enable unattended. Use them to see local policy decisions and try enforcement before Failproof AI audits your sessions and writes policies for your agents. + The pack is fetched from its GitHub release, checksum-verified, and pinned to the exact tag it resolved. It carries 39 policies and switches on the 10 its manifest marks as safe to enable unattended. Use them to see local policy decisions and try enforcement before Failproof AI audits your sessions and writes policies for your agents. Read any pack before taking it with `failproofai policies show /`, and see [policy packs](/policies/packs) for taking only part of one. @@ -99,3 +99,7 @@ read -rs FAILPROOFAI_KEY && export FAILPROOFAI_KEY + +## Jev setup + +Use [Jev](/start/use-jev) to score finished sessions against a question with known answers, or to review tool calls in context before they run. The **Use Jev** page has both setup paths. diff --git a/docs/start/use-jev.mdx b/docs/start/use-jev.mdx new file mode 100644 index 000000000..5fd51f339 --- /dev/null +++ b/docs/start/use-jev.mdx @@ -0,0 +1,63 @@ +--- +title: "Use Jev" +description: "Set up Jev evaluations for finished sessions or Jev policies for live tool-call review." +icon: "sparkles" +--- + +Jev helps at two points in an agent run: score a finished session against known answers, or review a tool call in the context of what you asked the agent to do. + + + + Use a Jev eval when a finished session can be scored against a question with a few known answers, such as “Did the customer ask for a refund? Answer yes or no.” It helps you find patterns across sessions. + + ## Create an eval + + In the Cloud dashboard, open **Analyze → eval authoring → new eval**. Enter one fixed-answer question, select **draft**, and check that it chose a classifier score. [Test it](/evaluations/test) on real sessions, then deploy it. + + ![The shared eval authoring form where you describe a question, review the draft, and deploy it. This screenshot shows a code draft; use a fixed-answer question for Jev.](/images/dashboard/eval-authoring-draft.png) + + ## Read the scores + + After a new session completes, open **Observe → Evaluations** or use the Cloud CLI: + + ```bash + fp evals --since 7d + fp evals --aggregate --since 7d + ``` + + The CLI reads scores; creating a Jev eval currently uses the dashboard. See [Jev evaluations](/evaluations/jev) for question types and examples. + + + Use Jev policy review when a string-matching policy needs the context of your request to decide whether a tool call is safe. Start in **observe** mode so you can inspect Jev's answers while your installed policies still decide each call. + + Jev's checks come from a pack; Failproof AI ships none. Until you install them, Jev asks nothing, even when it is configured: + + ```bash + failproofai policies add FailproofAI/jev-policies + ``` + + ## Set up Cloud Jev + + In the Cloud dashboard, open **Administration → Keys** and create a key with the **machine** preset. Use it with `failproofai config` as shown in the [quickstart](/start/quickstart). On a machine without an existing Jev configuration, this enables Cloud Jev in observe mode. Check the connection with: + + ```bash + failproofai jev status + failproofai jev test + ``` + + ## Use your own endpoint + + In the local dashboard, open **Settings → Jev**. Choose the provider, paste its token, select **observe**, and turn Jev on. + + ![The local Jev settings panel with a provider, token field, and observe mode selected.](/images/dashboard/jev-settings.png) + + Or configure and test your endpoint from a terminal: + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key + failproofai jev test + ``` + + Ask a hooked agent to use its file-reading tool on `README.md`. Confirm that tool call appears in the session, then inspect it under **Policies → Activity** in the local dashboard. Once the observe results look right, [Jev policies](/policies/jev) explains when to enforce. For provider details and configuration, see the [integration reference](/reference/jev). + + diff --git a/docs/tr/evaluations/jev.mdx b/docs/tr/evaluations/jev.mdx new file mode 100644 index 000000000..64d99d1d1 --- /dev/null +++ b/docs/tr/evaluations/jev.mdx @@ -0,0 +1,28 @@ +--- +title: "Jev evaluations" +description: "Tamamlanmış bir oturumu bilinen yanıtlara karşı puanlamak için Jev kullanın." +icon: "list-checks" +--- + +Jev evaluations, **tamamlanmış bir oturumu** okur ve 0 ile 1 arasında bir puan verir. Yanıtın önceden bilindiği durumlarda kullanın; örneğin "Müşteri aciliyet ifade etti mi?" veya "Müşteri ne kadar hayal kırıklığına uğradı?" gibi sorular. Çalıştırmalar arasında desenleri bulmanıza yardımcı olur; bir araç çağrısını durdurmaz. Bir araç çalışmadan **önce** alınan kararlar için [Jev policies](/tr/policies/jev) kullanın. + +## Panoda bir tane oluşturun + +1. **Analyze → eval authoring** bölümünü açın ve **new eval** seçeneğini seçin. +2. Bir soru ve olası yanıtlarını açıklayın. Örneğin: "Ajan geri iade politikasını kontrol etmeden önce geri iade vaat etti mi? Evet veya hayır cevabı verin." **draft** seçeneğini belirleyin ve sonucun bir sınıflandırıcı puanı olduğunu doğrulayın. +3. [Test edin](/tr/evaluations/test) son oturumlar üzerinde, ardından [yayınlayın](/tr/evaluations/deploy). Yeni tamamlanan oturumlar puanlanır; [geçmiş verileri doldurmak](/tr/evaluations/deploy#score-sessions-you-already-have) için backfill kullanın. + +![Paylaşılan eval authoring formu; burada sabit-cevaplı bir soru tanımlarsınız, taslağı gözden geçirirsiniz ve test ettikten sonra yayınlarsınız. Gösterilen örnek bir kod evaluationı'dır; bir Jev sorusu aynı authoring akışını kullanır.](/images/dashboard/eval-authoring-draft.png) + +Asistan kod, Jev sınıflandırması ve [judge](/tr/evaluations/judge) arasında seçim yapabilir. Yayınlamadan önce seçimini kontrol edin. Jev bir puan verir, ayrıntılı açıklama yapmaz; açıklama gereken durumlarda judge kullanın. Soru türleri ve puan sınırları için [Jev evaluation reference](/tr/reference/jev-evaluations) bölümüne bakın. + +## Puanları okuyun + +**Observe → Evaluations** bölümünü açarak sonucu agent ve zamana göre grafik haline getirin. Bir terminalden Cloud CLI aynı sonuçları okuyabilir: + +```bash +fp evals --since 7d +fp evals --aggregate --since 7d +``` + +Cloud CLI sonuçları okur; authoring ve yayınlama panoda gerçekleşir. Filtreler için [Cloud CLI reference](/tr/reference/cloud-cli#evaluations) bölümüne bakın. \ No newline at end of file diff --git a/docs/tr/evaluations/judge.mdx b/docs/tr/evaluations/judge.mdx new file mode 100644 index 000000000..44f0308dc --- /dev/null +++ b/docs/tr/evaluations/judge.mdx @@ -0,0 +1,91 @@ +--- +title: "LLM hakim" +description: "Oturumları kodun ölçemeyeceği şeyler açısından puanlandırın — doğruluk, ton, aracının bir politikayı takip edip etmediği — iyi olanın ne olduğunu açıklayarak ve bir modelin konuşmayı okumasını sağlayarak." +icon: "scale" +--- + +Barındırılan bir Python değerlendirmesi şunları sayabilir ve karşılaştırabilir: kaç araç çağrısı, kaç hata, bir oturum ne kadar sürdü. Bir cevabın *doğru* olup olmadığını, bir yanıtın kaba olup olmadığını veya aracının harekete geçmeden önce bir politikayı kontrol edip etmediğini söyleyemez. + +Bir **LLM hakim** söyleyebilir. İyi olanın neye benzediğini düz dil ile açıklar ve bir model oturumu okuyarak 0 ile 1 arasında bir puan ve gerekçesini döndürür. + + +Bir hakim, üzerinde çalıştığı her oturum için bir model çağrısı maliyetine sahipken, bir kod değerlendirmesi hiçbirşey maliyetine sahip değildir. Bir hakimi sadece konuşmanın *anlaşılması* gereken sorular için kullanın — ve ona bir koşul verin, böylece sorunun gerçekten ilgili olduğu oturumlar üzerinde çalışsın. + + +## Hangisini istiyorum? + +| Soru | Kullan | +| --- | --- | +| Aynı aracı iki kez çağırdı mı? | kod | +| Kaç hata vardı? | kod | +| Oturum 30 saniyeden az mı sürdü? | kod | +| Müşteri aciliyeti ifade etti mi? | [sınıflandırıcı](/tr/evaluations/jev) | +| Müşteri ne kadar hayal kırıklığına uğramıştı? | [sınıflandırıcı](/tr/evaluations/jev) | +| Cevap gerçekten doğru muydu? | **hakim** | +| Yanıt kaba veya küçümseyici miydi? | **hakim** | +| İade politikasını vaatte bulunmadan önce kontrol etti mi? | **hakim** | + +Temel kural: **sayılabilir → kod, önceden listeleyebileceğiniz cevaplar → [sınıflandırıcı](/tr/evaluations/jev), açıklama gerektirir → hakim.** Hakim, gördükleri hakkında yazı yazanıdır; sayının birini "neden?" diye sorduğunda ona ulaş. + +Önceden karar vermeniz gerekmiyor. Ölçülmesini istediğiniz şeyi açıklayın ve asistan seçim yapsın, sonra hangisini seçtiğini ve neden seçtiğini size söylesin. Değiştirebilirsiniz. + +## Birini yazın + +1. **Analyze → eval authoring** bölümüne gidin ve **new eval** seçeneğini seçin. +2. Neyin değerlendirilmesini istediğinizi açıklayın ve **draft** seçeneğini seçin. +3. **kriteri**, **eşiği** ve **koşulu** gözden geçirin, sonra dağıtın. + +### Kriter + +Bir veya iki cümle, soru olarak değil bir gereklilik olarak yazılmış: + +> Asistan, ilk olarak iade politikasını kontrol etmeden bir iade vaat etmemelidir veya onaylamamalıdır. + +*Başarısızlık* yaşanmasını neyin sağlayacağı konusunda spesifik olun. "Yanıt iyi miydi?" size hiçbir anlam taşımayan bir sayı verir; yukarıdaki cümle size harekete geçirebileceğiniz birini verir. + +### Eşik + +Oturumun geçtiği puan veya bunun üzerinde. `0.7` makul bir başlangıç noktasıdır. Tam 0-1 puanı her zaman saklanır, bu nedenle eşik sadece geçme/başarısızlığa karar verir — dağılımı görebilir ve ayarlayabilirsiniz. + +### Koşul + +Diğer herhangi bir değerlendirme ile aynı Python koşulu ve burada çok daha fazla önem taşır. Biri olmadan, hakim **her** oturumda kuruluşunuzda çalışır, her bir model çağrısında: + +```python +session.count("tool_use") > 0 +``` + +```python +session.agent_id == "support-bot" and session.count("error") > 0 +``` + +Pano, dağıtırsanız sizi bir koşul olmadan bir hakim konusunda uyarır. Bu bazen doğrudur — tam olarak değerlendirilmesini istediğiniz düşük hacimli bir aracı — ancak bu bir kaza değil, bir karar olmalıdır. + +## Hakim neyi görür + +Konuşma, dönüşümler halinde, oturum uzunsa en yenisi önce: + +- kullanıcının söylediği +- asistanın cevapladığı +- **aracının çağırdığı her araç ve bu çağrının döndürdüğü, sırayla** + +Son kısım "X *'den önce* Y yaptı mı" sorusunu adil bir soru haline getirir. Başarısız bir araç çağrısı başarısızlık olarak gösterilir, bu nedenle "bir hatadan zarif bir şekilde kurtuldu mu" da işe yarar. + +Çok uzun oturumlar, modelin bağlamına sığmak için kesilir. Bu gerçekleştiğinde, gerekçe açıkça bunu söyler — bir oturumun bir kısmında yapılan bir yargıyı tüm oturumda yapılmış gibi görmezsiniz. + +## Sonuçları okuma + +Bir hakim, diğer herhangi bir puanlanmış değerlendirme gibi bir **puan** üretir, bu nedenle grafikler, filtreler ve uyarıları tetikler. Sayının yanında, hakimin **gerekçesi** — gördüğünü açıklayan paragraf — saklanır. Bir puan sizi şaşırttığında bunu önce okuyun; genellikle gerçekten ilginç bir oturum veya kriterin keskinleştirilmesi gereken bir işarettir. + +Puanlar açık uçlu durumlar için kararlı ancak bit-for-bit deterministik değildir. Tek bir sınır puanını oturumu okumaya gitmek için bir istem olarak alın, bir karar olarak değil. + +## Sınırlamalar + +- **Test henüz mevcut değildir.** Kuru çalıştırmanın arkasında hiçbir oturum ataması yoktur ve bu atama, model bütçenizi harcamayı yetkilendiren şeydir — bu nedenle test çağrısının ücretlendirilecek hiçbirşey yoktur. Dar bir koşula karşı dağıtın ve ilk birkaç sonucu okuyun. +- **Geri doldurma mevcut değildir.** Bir kod değerlendirmesini aylar boyunca geri doldurmak ücretsizdir; bunu bir hakim ile yapmak, tüm bütçenizi dakikalar içinde harcar. +- **Kriteri düzenlemek yeni bir sürüm yayınlar.** Eski ve yeni puanlar karşılaştırılabilir değildir, bu nedenle tek bir eğilim çizgisine karıştırılmak yerine ayrı tutulurlar. +- **Bir hakim her zaman bir puan üretir**, asla bir metrik veya iddia değil. + +## Bütçeniz bittiğinde + +Hakimler kuruluşunuzun model bütçesini harcar. Tüklendiğinde, hakim değerlendirmeleri açık bir nedenle durur, sessizce başarısız olmak yerine ve **kod değerlendirmeleri normalde çalışmaya devam eder**. Bütçeyi artırın ve bir sonraki oturumda devam ederler. \ No newline at end of file diff --git a/docs/tr/policies/authority.mdx b/docs/tr/policies/authority.mdx new file mode 100644 index 000000000..add7809bc --- /dev/null +++ b/docs/tr/policies/authority.mdx @@ -0,0 +1,144 @@ +--- +title: "Policy authority" +description: "Jev semantic evaluator'ın hangi policy kararlarını geçersiz kılabileceği ve hangilarının nihai olduğu." +icon: "scale" +--- + +[Jev policy review](/tr/policies/jev) öğesini FailproofAI Cloud üzerinden veya kendi anahtarınızla yapılandırdığınızda, her gated tool call, çalıştırdığınız politikalar ve çağrının gerçekte ne yaptığını ve görevi yazan kişinin bunu isteyip istemediğini soran Jev tarafından değerlendirilir. Her politikanın **authority** (yetki), ikisi anlaşmazlığa düştüğünde ne olacağını belirler. + +Jev yapılandırılmadan, authority hiçbir etkisi yoktur. Her policy her zaman olduğu gibi tam olarak uygulanır. + +## Hard (Sert) ve Reviewable (İncelenebilir) + +- **Hard** varsayılandır. Bir hard policy'nin deny veya instruction kesindir: Jev bunu geçersiz kılamaz ve hard deny, Jev'in yanıtını beklemeden çağrıyı durdurur. +- **Reviewable** Jev'in policy'nin kararını geçersiz kılabileceği anlamına gelir, ancak yalnızca policy'nin `reviewedBy` içinde adlandırdığı semantic checks aracılığıyla. Karar yalnızca **tüm** adlandırılmış checks bu çağrı hakkında sorulduğunda ve her biri ya hiçbir şey bulmadığında ya da kullanıcının bunu sorması kaydedildiğinde geçersiz kılınır. **Ateşlenen** bir check — endişeyi bulan — kullanıcının bunu sormaması, kendi kararı yalnızca bir uyarı olsa bile, bloğu tutar. Jev'in sorulmadığı bir check (bu tool'a uygulanmadığı için) ne kadar başkası söylerse söylesin hiçbir şeyi geçersiz kılmaz. Bir yazılı kararı izin olarak sayılır: çağrı, kullanıcının verdiği görevin bir adımı olduğunda ve daha ileri gitmediğinde, Jev bir deny'yi uyarıya dönüştürür ve bu uyarı policy'nin bloğunu geçersiz kılar ve agentz tarafından söylendir. + +Bir policy yalnızca aşağıdakilerin tümü geçerliyse incelenebilir: + +1. `authority: "reviewable"` bildirir. +2. `reviewedBy` boş olmayan bir listedir ve her entry, yüklü bir pack'in bildirdiği bir Jev check'idir. Failproof AI hiçbir Jev check göndermiyor: [aşağıdaki on altı](#semantic-policy-names) `failproofai policies add FailproofAI/jev-policies` komutundan gelir. Pack hiçbir check bildirmemişse, her policy hard'dır. +3. `alwaysOn` değildir. Bir agent'ı Failproof AI'ı devre dışı bırakmaktan koruyan guard her zaman hard'dır. + +Başka her şey hard'dır: eksik alan, yanlış yazılmış değer, boş veya hatalı biçimlendirilmiş `reviewedBy` veya bu makinenin sorabileceği bir check olmayan ad. Bilinmeyen bir ad, tüm bildirimi hard yapar ve atlanmaz, çünkü `reviewedBy` "tüm bunlar sorulmalı ve hiçbiri deny diyemez" anlamına gelir ve bir adın atlanması Jev'in policy'yi sorduğunuzdan daha az checks ile geçersiz kılmasına izin verir. + +Jev yapılandırıldıktan sonra, Failproof AI `reviewable` bildirimi reddettiğinde işlem başına bir kez uyarı günlüğü tutar. Jev olmadan hiçbir şey söylemez, çünkü authority o zaman hiçbir şeye karar vermez. `failproofai publish`, böyle bir bildirimi taşıyan bir pack oluşturmayı reddeder, bu nedenle pack yazarı herhangi biri yüklemeden önce öğrenir. Pack herhangi birini bildirdiğinde pack'in bildirdiği checks'e karşı `reviewedBy` değerlendirir, aksi takdirde on altı `FailproofAI/jev-policies` adına karşı. + +## Authority'nin bildirildiği yer + +Her policy'nin bir makinede ulaşmanın her yolu authority'yi belirleyen tek bir yere sahiptir: + +| Kaynak | Bildirildiği yer | Varsayılan | +| --- | --- | --- | +| Built-in policies | Aşağıdaki tablo | Hard, incelenebilir olarak listelenmeyen dışında | +| Kendi policy dosyalarınız | `customPolicies.add` üzerindeki `authority` ve `reviewedBy` | Hard | +| Policy packs | Pack manifestindeki her policy'nin girişi (`failproofai-pack.json`) | Hard | +| Cloud-managed policies | Aktif deployment'da policy'nin ataması | Hard. Deployment'lar henüz ayarlamıyor, bu nedenle bugün her cloud-managed policy hard'dır. | + +Bir pack veya cloud-managed policy için, policy kodu içine ayarlanan alanlar göz ardı edilir; manifest veya atama karar verir. Bir pack yalnızca kendi politikalarını açıklayabilir: policy adları `/` içeremez ve pack'in kendi ön eki altına kaydedilir, bu nedenle hiçbir manifest built-in policy'yi veya başka pack'in policy'sini incelenebilir olarak işaretleyemez. Bir pack'in kodu manifestte bildirmeden kaydeden policy hard'dır. + +Kodun byte-identical olduğu iki pack veya iki cloud-managed policy bir artifact paylaşır ve tek bir policy olarak yüklenir. Bu policy yalnızca tüm bunlar incelenebilir olarak bildirse incelenebilir ve Jev o zaman her biri adlandıran her check'i geçersiz kılmalıdır. Eğer bunlardan biri hard'ı bildir veya hiç bildirmez, hard kalır. Pack'ler veya politikaların listelenme sırası hiçbir zaman önemli değildir. + +Çoğu makine built-in policies'i `FailproofAI/policies` pack'inden alır ve authority'lerini o pack'in manifestinden okur. Aşağıdaki incelenebilir girişler, onları taşıyan pack'in bir release'i yüklendikten sonra yürürlüğe girer; daha eski bir release hiçbirini taşımaz, bu nedenle içindeki her policy hard kalır. + +## Kendi policy'nizde authority bildirin + +```js +import { customPolicies, deny, allow } from "failproofai"; + +customPolicies.add({ + name: "block-prod-config-reads", + description: "Keep production credentials out of the agent's context", + match: { events: ["PreToolUse"] }, + authority: "reviewable", + reviewedBy: ["secret-exposure"], + fn: async (ctx) => + String(ctx.toolInput?.file_path ?? "").includes("/config/prod/") + ? deny("Production config is off limits") + : allow(), +}); +``` + +`failproofai publish` her iki alanı pack manifestine kopyalar, bu nedenle pack olarak yayınlanan bir policy yazarının ona verdiği authority'yi tutar. Pack'i oluşturmayı reddeder, eğer bir bildirimi onore edilmezse: `"hard"` veya `"reviewable"` dışında bir değer, liste olmayan bir `reviewedBy` veya bir check olmayan ad — pack'in kendi [Jev checks](/tr/policies/publish-a-pack#jev-checks-in-a-pack) herhangi birini bildirirse aksi takdirde built-in check. + +## Built-in policies + +Yalnızca semantic policy gerçekten aynı endişeyi kapsadığında incelenebilir. Diğer her built-in policy hard'dır. + +Endişeyi kaplamak gerekli ama yeterli değildir ve yanılışın her iki yolu da sessizdir: + +- **Hiçbir zaman sorulmayan bir check** bloğu kalıcı yapar. `reviewedBy` bir conjunction ve sorulmayan bir check hiçbir zaman temizlemez, bu nedenle policy'nin eşleştiği şekiller için önkoşulu ateşlenmeyen bir check ile eşleştirilmesi hiçbir şekilde temizlenemez. +- **Sorulan ama ateşlenmeyen bir check** "endişe yok" cevapı verir ve endişe yok temizler. Bu nedenle policy'nizin şekillerini modellemeyen bir check ile eşleştirmek, policy'yi incelemez — check'in anlamadığı tam olarak girişler için kapatır. + +Instruct-mode semantic policy hiçbir zaman deny veremez, ama yine de bir bloğu tutabilir: ateşlendiğinde ve kullanıcı çağrıyı sormazsa, incelediği policy temizlenmez. On altı `FailproofAI/jev-policies` check'inin altısı instruct-only — `push-to-protected-branch`, `commit-on-protected-branch`, `read-outside-workspace`, `system-modification`, `env-secrets-dump` ve `external-data-egress` — ve [aşağıdaki tablo](#semantic-policy-names) her check'in modunu verir. Sorulacak soru **"deny edebilen bir şey kaldı mı"**: bir temizlik hiçbir şey tarafından uygulanmayan endişeyi bırakmamalı. Motor bunu çağrı başına uygular. Hiç kimsenin izin vermeyen bir uyarı temizlik değildir, çünkü tool calls'ın öncesinde uyarı agent'ı durdurmaz. Ve deny edebilen bir check uyarır — kanıtı deny line'ını karşılamamış — ve kullanıcı çağrıyı sormazsa, o çağrıda hiçbir şey temizlenmez ve her regex deny ayakta kalır. + + +**Fire line'ın hemen altında puan alan bir check floor'u tutmaz.** Yukarıdaki kural bir check'in *ateşlenmesini* gerektirir (kanıt ≥ 0.7). İlgili her check tam altında indiğinde, hiçbir şey ateşlenmez, reviewers "endişe yok" cevaplar ve incelenebilir deny temizlenir. Enforce modda canlı ölçülür: `/etc/shadow` (`secret-exposure` 0.69, `read-outside-workspace` 0.37, yalnızca home-directory yollarını model alan) talep edilmeyen Read ve "follow SETUP.md" (`env-secrets-dump` 0.66, `credential-exfiltration` 0.65 with `sends_out` 0.97) sonrasında `set | curl -d @- …` her ikisi de izin verildi, regex tier tek başına onları deny ederken. Thresholds etiketli corpus üzerinde kalibre edildi ve buna karşı yeniden ölçülmedi; ta ki olana kadar, policy'yi **hard** tutun bu şekillerin birinin geçmesi önemli olduğunda yanlış bloklarından daha. + + +| Policy | Authority | Incelendi: | Neden | +| --- | --- | --- | --- | +| `protect-env-vars` | reviewable | `env-secrets-dump`, `secret-exposure` | Pattern herhangi bir variable referans'ta ateşlenir; Jev gizli değerlerin gerçekten yazdırılıp yazdırılmayacağını sorar. | +| `block-env-files` | reviewable | `secret-exposure` | Pattern herhangi bir `.env` path'i eşleştirir, templates dahil; Jev gerçek gizli değerlerin okunup yazılıp yazılmayacağını sorar. | +| `block-read-outside-cwd` | reviewable | `read-outside-workspace` | Gerçek trafikte gürültülü olarak ölçülür; Jev project'in dışındaki dosya içeriklerinin okunup okunmadığını sorar. Kullanıcının sorduğu bir okuma veya check'in hiçbir şey bulmadığı bir okuma temizlenir; talep edilmeyen bir okuma onu bayrak tutar bloğu tutar. | +| `warn-git-amend` | reviewable | `git-history-rewrite` | Push edilmemiş bir commit'i amend etmek normaldir; zarar başkalarının çekmiş olabileceği history'yi yeniden yazmaktır. | +| `warn-destructive-sql` | reviewable | `database-destruction` | Jev ayrıca hedefin gerçek bir database mi yoksa tek kullanımlık bir test mi olduğunu sorar. | +| `warn-global-package-install` | reviewable | `system-modification` | Aynı endişe: makineyi project'in dışında değiştirmek. | +| `block-failproofai-commands` | hard | | `alwaysOn` self-protection. Hiçbir zaman incelenebilir değil. | +| `block-rm-rf` | reviewable | `destructive-deletion` | Path-depth heuristic `rm -rf node_modules` yanlış alır; Jev ne yok olacağının regenerable olup olmadığını sorar. `rm -rf /` her iki probe'u da true tutar. | +| `block-sudo` | hard | | Privilege escalation. | +| `block-curl-pipe-sh` | hard | | İnternet'ten indirilmiş kodu çalıştırır. | +| `block-push-master` | hard | | Doğrudan protected branch'e push eder. | +| `block-work-on-main` | hard | | `commit-on-protected-branch` bu endişeyi tam olarak kapsar ama instruct-mode'dur, bu nedenle asla deny diyemez ve başka check bunu kapsamaz. | +| `block-force-push` | reviewable | `git-history-rewrite` | Jev'in probe'u matcher'ın bir üst kümesidir ve `--force-with-lease` sayar; temizleyen kendi branch'inizi force-push etmektir. | +| `block-secrets-write` | reviewable | `secret-exposure` | Path match'i unanchored'dır, bu nedenle `src/auth/credentials.ts` yakalanır; Jev gerçek key material'inin yazılıp yazılmadığını sorar. | +| `block-kubectl` | reviewable | `production-infra-change` | Tüm CLI'yi, read-only subcommands dahil reddeder; Jev çağrının mutate olup olmadığını ve hedefin production mu olduğunu sorar. | +| `block-terraform` | reviewable | `production-infra-change` | Aynı: `terraform plan` ve `validate`'i temizler. | +| `block-aws-cli` | reviewable | `production-infra-change` | Aynı: `aws s3 ls`, `aws sts get-caller-identity`'yi temizler. | +| `block-gcloud` | reviewable | `production-infra-change` | Aynı: `gcloud auth list`, `gcloud config list`'i temizler. | +| `block-az-cli` | reviewable | `production-infra-change` | Aynı: `az account show`'u temizler. | +| `block-helm` | reviewable | `production-infra-change` | Aynı: `helm list`, `helm status`'ı temizler. | +| `block-gh-pipeline` | hard | | Pipelines tetikler, merges ve gizli değişiklikler yapar. | +| `warn-git-stash-drop` | hard | | Hiçbir semantic check stash edilmiş işi atmayı kapsamaz. | +| `warn-git-clean` | hard | | `destructive-deletion` endişeyi kapsar ama açıkça onu ateşleyemez: `git clean` path adlandırmaz, bu nedenle `irreplaceable` probe'u yargılanacak hiçbir şeye sahip değildir ve düşük cevaplar, kanıt policy'nin probes'inin minimumu. Sorulan ve ateşlenmeyen bir check kararı temizler, bu nedenle burada eşleştirmek policy'yi kapatır. | +| `warn-all-files-staged` | hard | | Hiçbir semantic check geniş bir `git add` ne toplayan kapsamaz. | +| `warn-schema-alteration` | hard | | `database-destruction` veri atmayı kapsar, schema'yı altere etmeyi değil. | +| `warn-package-publish` | hard | | Yayınlama geri alınamaz ve hiçbir semantic check bunu kapsamaz. | +| `prefer-package-manager` | hard | | Bir team convention'u, safety judgment'ı değil. | +| `warn-large-file-write` | hard | | Bir size threshold'u, Jev'in yapabileceği judgment'ı değil. | +| `warn-background-process` | hard | | Hiçbir semantic check detached processes kapsamaz. | +| `warn-repeated-tool-calls` | hard | | Çağrıları sayar; Jev sayamaz. | +| `sanitize-jwt` | hard | | Tool output'unu redact eder; tool-call gate'i değil. | +| `sanitize-api-keys` | hard | | Tool output'unu redact eder; tool-call gate'i değil. | +| `sanitize-connection-strings` | hard | | Tool output'unu redact eder; tool-call gate'i değil. | +| `sanitize-private-key-content` | hard | | Tool output'unu redact eder; tool-call gate'i değil. | +| `sanitize-bearer-tokens` | hard | | Tool output'unu redact eder; tool-call gate'i değil. | +| `require-commit-before-stop` | hard | | Session-completion gate'i, tool-call gate'i değil. | +| `require-push-before-stop` | hard | | Session-completion gate'i, tool-call gate'i değil. | +| `require-pr-before-stop` | hard | | Session-completion gate'i, tool-call gate'i değil. | +| `require-no-conflicts-before-stop` | hard | | Session-completion gate'i, tool-call gate'i değil. | +| `require-ci-green-before-stop` | hard | | Session-completion gate'i, tool-call gate'i değil. | + +## Semantic policy adları + +Bunlar `FailproofAI/jev-policies` bildirdiği checks'ler ve yüklendikten sonra `reviewedBy` tarafından kabul edilen değerler. Failproof AI kendisi bunlardan hiçbirini göndermez: o pack olmadan (veya bu adları bildiren başka biri olmadan), onları adlandıran policy incelenebilir değildir. Her biri Jev'in önündeki tool call hakkında cevapladığı bir check'tir. **Mode**, bir check'in cevaplayabileceği şeydir: bir `deny` check güçlü kanıt üzerinde engeller, bir `instruct` check ise yalnızca uyarır. Her ikisi de ateşlendiğinde ve kullanıcı çağrıyı sormazsa policy'nin deny'sini tutar. **User can override** insan'ın kendi açık isteğinin bunu temizleyip temizlemeyeceğini söyler. + +Jev tam olarak [Jev checks](/tr/policies/publish-a-pack#jev-checks-in-a-pack) yüklü packs bildirdiği sorar ve bunlar `reviewedBy` tarafından kabul edilen adlardır. İki pack'in farklı şekilde bildirdiği bir ad ikisi için de onure edilmez. FailproofAI repository'sinden yüklenmeyen bir pack tarafından bildirilen bu on altı ad'dan biri o pack'te göz ardı edilir: versiyonu hiçbir zaman sorulmaz ve FailproofAI'nin kendi ile rekabet etmez, bu nedenle bir third-party pack ne core pack'in politikalarını temizleyen check haline gelebilir ne de bu checks'lerden birini kapatabilir. Okunamayan bir pack listesi veya her check'i kullanılamaz olan bir pack, Jev'e sormak için hiçbir şey bırakmaz. + +| Ad | Mode | User can override | Jev ne kontrol eder | +| --- | --- | --- | --- | +| `destructive-deletion` | deny | yes | Regenerate edilemeyen veriyi kalıcı olarak silmek. | +| `production-infra-change` | deny | yes | Live infrastructure'ı değiştirmek. | +| `git-history-rewrite` | deny | yes | Paylaşılmış git history'sini yeniden yazmak veya atmak. | +| `push-to-protected-branch` | instruct | yes | Doğrudan protected branch'e push etmek. | +| `commit-on-protected-branch` | instruct | yes | Doğrudan protected branch'de commit yapmak. | +| `secret-exposure` | deny | yes | Credentials'ı okumak veya kopyalamak. | +| `credential-exfiltration` | deny | no | Secrets'ı veya private files'ları makine dışına göndermek. | +| `remote-code-execution` | deny | yes | İnternet'ten indirilen kodu çalıştırmak. | +| `privilege-escalation` | deny | yes | Yükseltilmiş ayrıcalıklarla çalışmak. | +| `database-destruction` | deny | yes | Veritabanı verilerini yok etmek veya toplu değiştirmek. | +| `read-outside-workspace` | instruct | yes | Project'in dışındaki dosyaları okumak. | +| `agent-config-tampering` | deny | no | Agent'ın kendi safety configuration'ını değiştirmek. | +| `system-modification` | instruct | yes | Sistemi project'in dışında değiştirmek. | +| `env-secrets-dump` | instruct | yes | Environment secrets'ı yazdırmak. | +| `external-destructive-action` | deny | yes | Harici bir tool aracılığıyla geri alınamaz bir action. | +| `external-data-egress` | instruct | yes | Private verileri harici bir tool'a göndermek. | \ No newline at end of file diff --git a/docs/tr/policies/jev-byok.mdx b/docs/tr/policies/jev-byok.mdx new file mode 100644 index 000000000..3cf502dee --- /dev/null +++ b/docs/tr/policies/jev-byok.mdx @@ -0,0 +1,265 @@ +--- +title: "Jev değerlendirici (kendi anahtarınızı getirin)" +description: "TypeSafe'in Jev sınıflandırıcısının aracılarınızın araç çağrılarını sert bir regex tabanının üzerinde değerlendirmesine izin verin, kendi Jev uç noktanız ve anahtarınız üzerinden." +icon: "key-round" +--- + +Regex politikaları dizgeleri eşleştirir. `rm -rf build/` ile `rm -rf ~` arasındaki farkı bilemezler, bu nedenle bir yerde çok fazla bloke eder, başka yerde çok az bloke ederler. **Jev**, TypeSafe'in sınıflandırıcısı, çağrıyı gerçekte ne istediğinize karşı okur ve bunu bir hızlı istekte bir dizi evet/hayır sorusuna yanıt verir. + +Kendi Jev uç noktanız ve anahtarınız yapılandırılmışsa, Failproof AI her araç çağrısı hakkında Jev'e sorar **regex politikalarının yanında**, hiçbir zaman onları yerine almaz: + +- **Sert** bir politikanın reddi nihai olur. Jev bunu temizleyemez. Her politika açıkça gözden geçirilebilir olarak işaretlenmediği ve onu kapsayan Jev kontrollerini adlandırmadığı sürece sert olur; bu nedenle hiçbir şey söylemeyen özel, paket veya Bulut politikası sert olur ve her zaman açık kendi koruma koruması her zaman sert olur. +- **Gözden geçirilebilir** bir politikanın reddi temizlenebilir, ancak yalnızca o politikanın kapsadığı tam ilgili konu hakkında Jev'e sorulduğunda ve "burada bir şey yok" veya "kullanıcı bunu istedi" yanıtını verdiğinde. İlgiyi gerçek bulan bir kontrol, kullanıcı çağrıyı istemediğinde reddi tutar — kendi kararı yalnızca bir uyarı olsa bile, çünkü bir araç çağrısından önce uyarı aracıyı durdurmaz. Ve bu kontrol reddi verebilen biriyse (gizli dişe açılması, kimlik bilgisi sızıntısı, yıkıcı silme, …), o çağrıda hiçbir şey temizlenmez. +- Bir blok, çağrı verdiğiniz görevin bir adımı olup daha ileri gitmediğinde **uyarı** haline gelebilir: Jev kendi reddi bir uyarıya yumuşatır ve bu uyarı — çağrıyla gerçekte ne yanlış olduğunu adlandırıyor — politikanın bloğunu değiştirir. +- Jev ayrıca regex'in tanımlamadığı zarara karşı kendi kendine uyarabilir veya reddedebilir. +- Jev yanıt veremezse (zaman aşımı, hız sınırı, sunucu hatası, kredi yok, beklenmeyen model sürümü), o çağrı Jev olmadan tamamen olduğu gibi regex sonucu alır. +- Jev hiçbir çağrıyı politikalarınız tek başına daha izin verici hale getirmez, aksi takdirde tüm çağrıyı okumadığı ve tam ilgili konu hakkında sorulmadığı takdirde. Daha az — tamamı gönderilemeyecek kadar büyük bir çağrı, şüpheli injeksiyon — temizlemeleri çeker ve her reddi tutar. + + +Jev yapılandırması olmadan hiçbir şey değişmez: kancalar regex politikalarını her zaman olduğu gibi çalıştırır. Yapılandırma tamamen tercih etme (opt-in) mekanizmasıdır. + + + +FailproofAI Bulut'u mı kullanıyorsunuz? Kendi anahtarınıza ihtiyacınız yok: `jev:evaluate` taşıyan bir anahtarla bağlantılı bir makine, kuruluşunuzun planında Jev kullanabilir. Bkz. [FailproofAI Bulut aracılığıyla Jev](/tr/policies/jev-cloud). + + +## Sağlayıcı seçin + +Jev beş rota üzerinden erişilebilir. Bunlardan herhangi biri için bir anahtar getirin. + +| Sağlayıcı | `--provider` | Uç nokta | Varsayılan model | Notlar | +| --- | --- | --- | --- | --- | +| TypeSafe | `typesafe` | `api.typesafe.ai/v1/systemone` | `jev-1.13.0` | Kesin sürüm sabitleme. | +| OpenRouter | `openrouter` | `openrouter.ai/api/v1/systemone` | `typesafe/jev-1.13` | İstekler sıfır veri saklama uç noktalarına yönlendirilir, başka bir sağlayıcıya geri dönüş yoktur. `typesafe/jev-1.13-20260917` gibi tarihli bir sürüm bildirir. | +| Vercel AI Gateway | `vercel` | `ai-gateway.vercel.sh/typesafe/v1/systemone` | `typesafe-ai/jev` | Jev'i yalnızca bir takma adla adlandırır, bu nedenle yanıt veren sürüm doğrulanmamış olarak kaydedilir. | +| Cloudflare Workers AI | `cloudflare` | `api.cloudflare.com/client/v4/accounts//ai/run` | `typesafe/jev` | `--account-id` gerektirir. Anahtar başına saniyede yaklaşık altı çağrı HTTP 429'dan önce ölçüldü. | +| Kendi uç noktanız | `custom` | `/systemone` | `jev-1.13.0` | TypeSafe'in istek gövdesini kabul eden ve hangi modelin yanıt verdiğini bildiren herhangi bir uç nokta. Yalnızca `https`; düz `http://localhost` yalnızca shadow modunda kabul edilir. | + + +Vercel'in kendi bring-your-own-key özelliğiyle, başarısız bir istek Vercel'in kimlik bilgileriyle sessizce yeniden denenir. Her çağrının yalnızca kendi TypeSafe hesabınıza faturalandırılıp görülmesine ihtiyacınız varsa, TypeSafe'i doğrudan kullanın. + + +## Kurulumu yapın + +Bir komut, uç nokta ve anahtar: + +```bash +failproofai jev --url https://api.typesafe.ai/v1 --key-stdin < ~/typesafe.key +``` + +### URL sağlayıcıyı seçer + +Sağlayıcıyı adlandırmanız gerekmez: URL'nin **host** bölümü hangisi olduğunu belirler. + +| URL host | Sağlayıcı | Ayrıca gereken | +| --- | --- | --- | +| `api.typesafe.ai` | `typesafe` | — | +| `openrouter.ai` | `openrouter` | — | +| `ai-gateway.vercel.sh` | `vercel` | — | +| `api.cloudflare.com` | `cloudflare` | `--account-id <32-hex-account-id>` | +| başka herhangi bir host | `custom` | — verdiğiniz URL temel URL'dir | + +Bundan üç şey çıkar: + +- **Sağlayıcının kendi API'sine giden bir URL hiçbir geçersiz kılmaz yazı yazmaz.** `--url https://api.typesafe.ai/v1`, `--provider typesafe` olmuş olacağının tam konfigürasyon dosyasını üretir. Bilinen bir sağlayıcı üzerinde farklı bir yol veya host verin ve temel URL olarak saklanır, `--base-url` onu saklamış olur. +- **`--provider` hala çıkarsama sırasında geçersiz kıl**, bu, kendi host'unuzdan bir sağlayıcının API'sini konuşan bir proxy'ye ulaşmanın yolu: `--url https://jev-proxy.internal/v1 --provider typesafe`. +- **Host'u çelişen `--provider` reddedilir**, tahmin edilmez. `--provider openrouter --url https://api.typesafe.ai/v1` hiçbir şey yazmaz ve nedenini söyler: iki yazım, anahtarınızın nereye gönderilmek üzere olduğu hakkında anlaşmazlık içinde. Aynı çift `jev setup --base-url` ve kontrol panelinin Jev ayarlarından reddedilir. (`--provider custom` çelişki değildir — bu "bu URL'yi kendisi olarak işle" anlamına gelir — Cloudflare'in host'u dışında, özel bir rota hangisine ulaşamaz.) + +`--url` `baseUrl` yapılandırma dosyasında tam olarak doğrulanır ve aynı kelimelerle reddedilir: `https` veya yalnızca shadow modunda düz `http://localhost`. + +### Anahtar + +`--key-stdin` ile aktarın veya komutu terminal içinde çalıştırın ve anahtarı maskelenen bir isteme yapıştırın. Her iki şekilde de doğrudan yapılandırma dosyasına gider ve hiçbir zaman geri yazdırılmaz. + + + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --key-stdin < ~/typesafe.key + ``` + + + ```bash + failproofai jev --url https://openrouter.ai/api/v1 --key-stdin < ~/openrouter.key + ``` + + + ```bash + failproofai jev --url https://ai-gateway.vercel.sh/typesafe/v1 \ + --key-stdin < ~/vercel-gateway.key + ``` + + + ```bash + failproofai jev --url https://api.cloudflare.com/client/v4 \ + --account-id <32-hex-account-id> --key-stdin < ~/cloudflare.token + ``` + + + ```bash + failproofai jev --url https://jev.internal.example.com/v1 --key-stdin < ~/jev.key + ``` + + + +`failproofai jev setup` aynı bayrakları alır ve tüm bunlar için uzun yol yazı: `setup --provider ` URL'yi adlandırmak yerine sağlayıcıyı adlandırmak istediğiniz yer. + +### `--token` ve maliyeti + +`--token ` anahtarı komut satırına koyar, bu bir makineyi yapılandırmak için en hızlı yoldur ve anahtarı yapılandırma dosyası dışında herhangi bir yerde bırakan tek yazı: + +```bash +failproofai jev --url https://openrouter.ai/api/v1 --token +``` + + +Komut satırı bağımsız değişkeni daha sonra shell'in geçmiş dosyasında ve komut çalışırken süreç listesinde olur — siz olarak çalışan her şey tarafından `/proc`'den okunabilir. `setup` `--token` kullanıldığında her zaman bunu söyler. Paylaştığınız bir makinede, kaydedilen bir oturumda veya geçmiş dosyasının eşitlendiği herhangi bir yerde `--key-stdin`'i tercih edin; bu şekilde ilettiğiniz bir anahtarı döndürün, önemliyse. + + +`--token`, `--key-stdin` ve `--key-from-env` birbirini dışlayan: bir tane verin. + +Ardından anahtarı, uç noktayı ve hangi Jev'in yanıt verdiğini kontrol etmek için bir küçük canlı istek gönderin: + +```bash +failproofai jev test +``` + +```text + failproofai jev test ok · 523 ms + + provider cloudflare + model asked typesafe/jev + answered by jev-1.13.0 (Jev 1.13 family — verified) + latency 523 ms — within the 3000 ms timeout +``` + +`jev test` çıkış 1'i verirse ve zaman aşımından sonra yanıt gelirse (her kanca `timeout` olarak regex'e geri döner) veya kontrol sorusuna yanlış cevap verirse başlıkta bunu söyler. + +Kancalar her araç çağrısında yapılandırmayı okur, bu nedenle sonraki kişiden uygulanır. Daemon'u yeniden başlatacak bir şey yoktur veya olmaksızın. + +## Ne yaptığını kontrol edin + +```bash +failproofai jev status +failproofai jev status --json +``` + +`status` sağlayıcı, uç nokta, model, mod, yapılandırma dosyası ve izinlerini gösterir ve hiçbir zaman anahtarı göstermez. Bunun altında son faaliyeti özetler: Jev kaç çağrı değerlendirdi, ne sıklıkta regex'e geri döndü ve neden, gecikmesi ve hangi gözden geçirilebilir politikaları temizledi. + +## Shadow modu + +`enforce` varsayılandır. Jev'i izlemek ama herhangi bir kararı değiştirmesine izin vermemek için `shadow`'a geçin: Jev hala sorulur ve kararları kaydedilir, ancak regex sonucu uygulanandır. + +```bash +failproofai jev setup --mode shadow +failproofai jev setup --mode enforce +failproofai jev setup --mode off +``` + +`off` yapılandırmayı tutar — uç nokta ve anahtar — ve Jev'e sormayı durdurur: kancalar yapılandırma olmayan tam olarak gibi regex politikalarını çalıştırır ve `failproofai jev status` "off (switched off)" der. `--mode shadow` veya `--mode enforce` ile geri dönün. + +Aynı sağlayıcı için `setup`'ı yeniden çalıştırmak depolanan anahtarı tutar, bu nedenle mod anahtarı bir bayraktır. Sağlayıcı değiştirmek baştan başlar ve o sağlayıcının anahtarını ister. Farklı bir host'a istekleri taşıyan bir `--base-url` da yapar: depolanan anahtar yalnızca verildiği host'a veya sağlayıcının kendi API'sine gönderilir. + +## Yapılandırma dosyası + +Her şey bir dosyada yaşar, `setup` tarafından yazılan `~/.failproofai/jev.json`: + +```json +{ + "provider": "cloudflare", + "apiKey": "", + "accountId": "<32-hex-account-id>", + "mode": "enforce", + "timeoutMs": 3000 +} +``` + +| Alan | Anlam | +| --- | --- | +| `provider` | `typesafe`, `openrouter`, `vercel`, `cloudflare` veya `custom` — veya `failproofai`, anahtarı bu dosya yerine FailproofAI Bulut bağlantısından gelen ([FailproofAI Bulut aracılığıyla Jev](/tr/policies/jev-cloud) bkz.). | +| `apiKey` | `Authorization: Bearer ` olarak gönderilir. | +| `baseUrl` | `custom` için gerekli; aksi takdirde sağlayıcının API tabanının yerini alır. `https` olmalı. `localhost`'a düz `http` yalnızca `mode: shadow` ile kabul edilir: hiçbir şey yerel bir portu kimlik doğrulamaz, bu nedenle proxy'niz kapalı olduğunda makinede herhangi bir işlem, yargılanan aracı da dahil olmak üzere yerinde yanıt verebilir. | +| `accountId` | Yalnızca Cloudflare: 32 küçük harf hex karakteri. | +| `model` | Sağlayıcının varsayılan model kimliğinin yerini alır. Sürüm kurulan bir kimlik Jev 1.13 adı taşımalı. API anahtarı gibi şekilli bir değer reddedilir (ve geri tekrarlanmaz), bu nedenle `--model`'e yapıştırılan bir anahtar hiçbir zaman model olarak saklanmaz veya gönderilmez. | +| `timeoutMs` | Bir araç çağrısı regex sonucunu kullanmadan önce Jev için ne kadar bekler. 100–10000, varsayılan 3000. | +| `mode` | `enforce` (varsayılan), `shadow` veya `off` (yapılandırmayı tut, Jev çalıştırma). | + +Üç kural korur: + +- **Yalnızca sahip.** `0600` izinleriyle yazılır. Başka bir kullanıcı veya grup tarafından okunabilen veya yazılabilen bir kopya **reddedilir** ve kancalar `chmod 600 ~/.failproofai/jev.json` veya `setup` yeniden çalıştırıncaya kadar regex'e geri döner. Dizin de kontrol edilir: `~/.failproofai` başka birisi tarafından **yazılabilir** olmamalı, çünkü orada yazabilen kişi dosyayı kendi izinlerine bakılmaksızın değiştirebilir. `setup` bulursa bu yazma bitlerini çıkarır. `failproofai jev status` yapılandırma reddedildiğinde söyler ve dosyanın adlandırdığı uç noktayı gösterir: başka biri değiştirmiş olabilir, bu nedenle `chmod` öncesinde sizinki olduğunu kontrol edin. Böyle bir dosya üzerinde `setup`'ı yeniden çalıştırmak depolanan anahtarı yalnızca sağlayıcının kendi API'sine taşır; adlandırdığı başka herhangi bir uç nokta anahtarı (`--key-stdin`) veya `--base-url default`'ı yeniden gerektirir sağlayıcıya istekleri geri göndermek için. +- **Yalnızca global.** Bir depo Jev'i açamaz, başka bir uç noktaya işaret etmez veya modelini seçemez: bir proje içinde `.failproofai/jev.json` yoksayılır ve sağlayıcı, URL, model ve hesap kimliği yalnızca bu dosyadan okunur — hiçbir zaman ortamdan, depo aracısı ayarlarını ayarlayabileceğinden. (`FAILPROOFAI_HOME` çevresini geçmenin bir yolu değildir: Jev'de yönlendirme yerine tüm failproofai dizinini, politikalarınız da dahil olmak üzere hareket ettirir.) +- **Anahtar tek başına ortamdan gelebilir.** Dosyada `apiKey` yoksa, `FAILPROOFAI_JEV_API_KEY` bu oturum için sağlar (`setup --key-from-env` böyle bir dosya yazılı). Dosyanın tuttuğu anahtarı hiçbir zaman değiştirmez ve anahtar olmadan Jev'i açamaz. Değişken ayarlanmadığında, Jev o kabuk için basitçe kapatılmıştır: `failproofai jev status` söyler, çıkış 0 verir ve yapılandırmayı yalnız bırakır (`status --json` `"reason": "no-env-key"` ile `"status": "key-missing"` bildirir). `failproofaid` daemon'u shell'in ortamını görmez, bu nedenle `failproofai config` ile ayarlanmış bir makinede, anahtarı dosyada tutun. + +## Hangi Jev yanıt verir + +Failproof AI'nin karar eşikleri Jev 1.13 üzerine kalibre edildi, bu nedenle yanıt yalnızca o ailesi tarafından geldiğinde kullanılır: `jev-1.13.x` veya OpenRouter'in `typesafe/jev-1.13-`. Sağlayıcı Jev'i yalnızca takma adla adlandırdığında ve sürüm bildirilmediğinde (Vercel ve Cloudflare bildirmediğinde), yanıt kullanılır ve doğrulanmamış olarak kaydedilir. Özel bir uç nokta yanıt veren modeli bildirmelidir; tek istisna yapılandırdığınız bir sürüm yok `--model` adıdır, geri yankılandığında, aynı şekilde doğrulanmamış olarak kaydedilir. Başka herhangi bir sürüm bildiren veya `custom` yanıt veren herhangi bir sürüm bildirmeyen, kullanılmaz: o çağrı `model-mismatch` nedeniyle regex'e geri düşer. + +## Jev yanıt veremediğinde + +Bunların her biri bu çağrı için regex sonucuna geri döner ve nedeniyle kaydedilir, `failproofai jev status` toplar: + +| Neden | Neden | +| --- | --- | +| `timeout` | `timeoutMs` içinde yanıt yok. | +| `http-429` | Sağlayıcı anahtarı hız sınırlandırdı. | +| `rate-limited` | Failproof AI'nin kendi sınırlayıcısı çağrıyı göndermeden önce tuttu: saniyede 5 istek, 5'e kadar patlamada ve sağlayıcı `429` cevapladıktan sonra bir an için yok. Sağlayıcı değil. | +| `http-500`, `http-502`, `http-503`, … | Sağlayıcıda sunucu hatası. Kesin durum kaydedilir. | +| `out-of-credits` | HTTP 402: sağlayıcı hesabının kredisi kalmadı. | +| `provider-refused` | Cloudflare'den HTTP 402 "Model execution failed (Payment error)" okuyor: sağlayıcı bu istekte modeli çalıştırmayı reddetti. Genellikle faturalandırma değil, bu nedenle kredi yükseltmek onu hareket ettirmez. | +| `http-401`, `http-403` | Anahtar reddedildi. | +| `http-404` | `/systemone`'da hiçbir şey sunulmaz, bu nedenle temel URL yanlış — `/systemone` buna eklenir ve her sağlayıcı sürüm kökünde sunur. `failproofai jev models` uç noktanın sunduğu şeyi gösterir. | +| `network` | Uç nokta erişilemez. | +| `http-301`, `http-302`, `http-307`, `http-308` | Uç nokta yeniden yönlendirmeyle yanıt verdi. Yeniden yönlendirmeler hiçbir zaman izlenmez, bu nedenle yanıt yalnızca yapılandırma dosyasında URL'den gelir; son URL'ye `--base-url` ayarlayın. | +| `malformed` | Uç nokta yanıt verdi ama Jev cevabı değil — JSON olmayan bir gövde veya içinde cevap olmayan bir gövde. | +| `cloudflare-error`, `cloudflare-incomplete` | Cloudflare'in zarfı başarısızlık bildirdi veya bitmemiş bir iş. | +| `model-mismatch` | Jev 1.13 dışında bir sürüm yanıt verdi veya `custom` uç nokta hangi modelin yanıt verdiğini söylemedi. | +| `request-cut` | **Bir kesinti değil.** Jev yanıt verdi; çağrının yalnızca bir kısmı gösterildi, bu nedenle yanıtı hiçbir şeyi temizlemedi. Bkz. [Jev yanıt verdi, ama tüm çağrıda değil](#when-jev-answered-but-not-on-the-whole-call). | + +`failproofai jev status` `upstream-error` (cevap sağlayıcının kendi hatasını taşıdı) veya `config` gibi birkaç daha nadir neden de gösterebilir ve adlandıramayacağı herhangi bir nedeni `other` olarak toplar. + +`request-cut` bu tablodadır çünkü `failproofai jev status` onu geri kalanla toplar ve çünkü her reddi saymak da bırakır. Burada her satırın sağlayıcınız hakkında hiçbir şey söylemeyen tek neden: istek Jev'e ulaştı ve yanıt verdi. Yukarısının her satırdan farklı olarak, o cevap yine de sayılır — Jev'in kendi reddi veya uyarısı regex sonucunun üzerine uygulanır yerine atılmaz. Böylece bir serisi çağrıların değerlendiriciye ulaştığı anlamına gelir tamamı gönderilemeyecek kadar büyük, uç noktanızın kötü olması değil ve krediyi doldurma veya URL değiştirme sayıyı hareket ettirmez. + +## Jev yanıt verdi, ama tüm çağrıda değil + +İki şey daha olabilir ve hiçbiri Jev'in yanıt vermemesi değildir. Her ikisi de çağrının ne kadarının veya konuşmanın, bir istekte uyup sığması konusudur. + +**Çağrının bir kısmı sığmadı.** Bir araç çağrısı sabit bir bütçe içinde gönderilir ve son derece büyük bir — çok büyük `Write`, devasa MCP gövdesi, büyük harfle doldurulmuş komut — sığılan şeyle gönderilir. Jev yine de yanıt verir ve yanıtı yine de sayılır: kendi reddi veya uyarısı her zamanki gibi uygulanır. Ne yapamayacağı **temizleme** şeyi, çünkü çağrının bir kısmında verilen bir karar çağrı üzerindeki karar değildir. Böylece her politika reddi duruyor ve çağrı `request-cut` nedeniyle geri dönüş olarak kaydedilir, `failproofai jev status` yukarıdaki nedenlerle toplar. Verdiği kural: çağrıyı daha büyük yapmak temizlemeleri maliyetli olabilir ve hiçbir zaman bir tane satın almaz. + +**Bir mesaj sığmadı.** Yapıştırdığınız uzun bir komut istemi, aracının son mesajı veya bu değerlendiricinin kendi deposunun zaten sınırlandırdığı bir komut istemi. **Hiçbir şey değişmez**: çağrı, temizlenir ve diğer herhangi biri gibi kaydedilir ve geri dönüş olarak sayılmaz. Yazmanın uzunluğu hiçbir zaman karara karar vermez ve kesme başka bir kişinin iznini yaratamaz: komut istemi zaten sınırlandırılmış geldiğinde, "bunu istemedin" sonuç olarak çekilmek yerine hiç sonuç olmaktan çıkar. + +İkisi arasındaki çizgi metni kimin yazdığı. Çağrı aracının ve kuralı uzunluğunun ağırlığı çıkarmayı izin verirse, aracı kullanabileceği bir kuraldır; komut istemi senindir ve uzunluğunu sinyal olarak işlemek yalnızca bir spec veya stack trace yapıştırmayı cezalandırdı. + +## Makineyi terk eden şey + +Jev'in değerlendirdiği her araç çağrısı için, sağlayıcınıza bir istek gider: + +- aracının başlıyorsunun kendisi, API anahtarları, taşıyıcı jetonları ve `KEY=` atamalarını çıkartılan sırları; +- yazıp metin aracının taşıyıcı eklediği kaldırılan son komut istemleriniz; +- son komut isteminden önceki aracının son mesajı, ajan tarafından yazılı olarak etiketlenmiş; +- projenin içinde bir yol olup olmadığı gibi yerel olarak hesaplanan gerçekler — ilk gözden geçirilen çağrısı [oturum için sabitlenmiş](/tr/reference/jev-intent#the-project-root) — ve mevcut git dalı. + +Yalnızca yapılandırma dosyasındaki uç noktaya, anahtarınız altında gider. + +## Kapatın + +```bash +failproofai jev remove +``` + +Bu `~/.failproofai/jev.json` siler. Sonraki araç çağrısından, kancalar regex politikalarını tamamen öncekiymiş gibi çalıştırır. `~/.failproofai/state/semantic/` altındaki oturum başına depoları (`sessions/`'da kaydedilen istemleri, `roots/`'de proje köklerini) yerinde bırakılır ve yaş. Jev'e sormayı durdurmak ama yapılandırmayı tutmak için bunun yerine `failproofai jev setup --mode off` kullanın. + +## Komut başvurusu + +| Komut | Sonuç | +| --- | --- | +| `failproofai jev --url --key-stdin` | Bir komutla yapılandır; sağlayıcı URL'nin host'undan gelir | +| `failproofai jev --url --token ` | Aynı, komut satırında anahtar — geçmişiniz ve işlem listesi onu görür | +| `failproofai jev setup --provider --key-stdin` | stdin'e aktarılan anahtardan yapılandırma yazı | +| `failproofai jev setup --provider ` | Aynı, maskelenen bir isteme anahtar sor | +| `failproofai jev setup --key-from-env` | Anahtar saklama; oturum başına `FAILPROOFAI_JEV_API_KEY` oku | +| `failproofai jev setup --mode shadow` | Mod değiştir (`enforce`, `shadow` veya `off`), depolanan anahtarı tutarak | +| `failproofai jev setup --model ` / `--base-url ` | Modelin veya API tabanının geçersiz kılması; `default` geçersiz kılmayı temizler | +| `failproofai jev setup --timeout-ms ` | Çağrı başına bütçeyi değiştir | +| `failproofai jev status [--json]` | Yapılandırma, izinler ve son faaliyet; hiçbir zaman anahtar | +| `failproofai jev test [--json]` | Bir canlı istek: gecikme ve yanıt veren sürüm | +| `failproofai jev models [--provider ] [--url ] [--json]` | Uç noktanın `/models` bildirdiği model kimliği, yapılandırılanı işaretleyerek | +| `failproofai jev remove` | Yapılandırmayı sil; Jev kapalı | \ No newline at end of file diff --git a/docs/tr/policies/jev-cloud.mdx b/docs/tr/policies/jev-cloud.mdx new file mode 100644 index 000000000..a9b60f7fb --- /dev/null +++ b/docs/tr/policies/jev-cloud.mdx @@ -0,0 +1,117 @@ +--- +title: "Jev through FailproofAI Cloud" +description: "FailproofAI Cloud üzerinden Jev ile aracılarınızın araç çağrılarını değerlendirin, kuruluşunuzun planında, TypeSafe hesabı veya kendi anahtarınız olmadan." +icon: "cloud" +--- + +[Jev](/tr/policies/jev-byok), TypeSafe'in sınıflandırıcısı, her araç çağrısını aslında ne istediğinize karşı okur ve politikalarınızla birlikte yanıt verir, asla onların yerine değil. **FailproofAI Cloud** aracılığıyla, bağlı bir makine Jev'i zaten bağlandığı anahtarla kullanır: TypeSafe hesabı yok, ikinci anahtar yok, yapılandırılacak uç nokta yok. Her çağrı kuruluşunuzun mevcut plan payından ücretlendirilir. + +Jev'in yaptığı her şey [kendi anahtarını getir kurulumundan](/tr/policies/jev-byok) değişmez: sert politikalar son kalır, incelenebilir bir politikanın reddi yalnızca Jev'e tam olarak o endişe hakkında sorulduğunda temizlenir ve herhangi bir hata o çağrı için regex sonucuna geri döner. + + +**failproofai 1.0.8-beta.0** veya daha yeni bir sürüm gerektirir. 1.0.7'nin Jev'i yok, 1.0.7 beta'larının üstünde sıralanmış olsa bile. Jev yapılandırması olmadan hiçbir şey değişmez: kancalar regex politikalarını her zaman yaptığı gibi çalıştırır. + + +## Aç + +1. **Jev ile bir anahtar oluşturun.** FailproofAI Cloud panosunda, **Keys → Create key** öğesini açın ve **machine** ön ayarını seçin. Bir makinenin ihtiyaç duyduğu üç izni verir: `events:add` (etkinlik gönder), `policies:pull` (politika al) ve `jev:evaluate` (Jev, kuruluşunuzun planından ücretlendirilir). Bir anahtar diğer ikisi olmadan `jev:evaluate` taşıyamaz. +2. **Makinayı bu anahtarla bağlayın:** + + ```bash + failproofai config --token + ``` + + Kuruluşunuz barındırılan yerine kendi FailproofAI Cloud'unu çalıştırıyorsa, adresini ekleyin: `--url https://` (veya `FAILPROOFAI_CLOUD_URL` dışa aktarın). Olmadan anahtar barındırılan hizmete karşı denetlenir ve bağlantı başarısız olur. O ana makinenin sertifikası özel bir CA'dan geliyorsa, CA'yı makinenin sistem güven deposunda yükleyin (örneğin `update-ca-certificates` ile), yalnızca `NODE_EXTRA_CA_CERTS` içinde değil: olayları gönderen ve politikaları çeken daemon sistem deposunu okur. Bkz. [Sorun Giderme](/tr/reference/troubleshooting). + +Hepsi bu. Bağlanmak anahtarı depolar ve makine **hiçbir** Jev yapılandırmasına sahip olmadığında, Jev'i FailproofAI Cloud üzerinden **gölge** modunda açar: Jev her geçitli araç çağrısı hakkında sorulur ve kararları kaydedilir, ancak politikalarınızın sonucu uygulanır. Çıktı bunu söyler: + +```text + Jev on through FailproofAI Cloud, in shadow mode: logged, not enforced (~/.failproofai/jev.json). +``` + +**`--no-transcripts` ile bağlanmak Jev'i açmaz.** Jev her kontrol edilen araç çağrısını ve son istemi FailproofAI Cloud'a gönderir, bu yalnızca kararlar bağlantısından daha fazladır. Anahtar yine de depolanır ve çıktı Jev'in kullanılabilir olduğunu ve nasıl açılacağını söyler: + +```bash +failproofai jev setup --provider failproofai +``` + +Jev'i **kapatmaz** da. Makinenin `jev.json`'u zaten FailproofAI Cloud üzerinden Jev çalıştırıyorsa, olduğu gibi bırakılır ve çıktı Jev'in her kontrol edilen araç çağrısını ve son istemi yine de gönderdiğini ve `failproofai jev setup --mode off` onu kapattığını söyler. + + +Bağlanmak **asla mevcut bir** `~/.failproofai/jev.json` dosyasının üzerine yazmaz. Zaten kendi Jev uç noktanızı kullanıyorsanız, kullanılmaya devam eder ve çıktı dosyanın yapılandırıldığı şekilde bırakıldığını söyler — ve bu dosya Jev'i kapalı bıraktığında (reddedildi veya kapatıldı), bunu ve nasıl düzeltileceğini söyler. Bu makinayı FailproofAI Cloud'a geçirmek için `failproofai jev setup --provider failproofai` komutunu çalıştırın. + + +## Gölge, zorlama veya kapalı + +Gölgede başlayın, Jev'in politika sayfasında ne yapacağını izleyin, sonra hareket etmesine izin verin: + +```bash +failproofai jev setup --mode enforce # Jev'in kararları uygulanır: incelenebilir bir reddi temizleyebilir ve kendisininı ekleyebilir +failproofai jev setup --mode shadow # Jev sorulur ve kaydedilir; politikalarınızın sonucu uygulanır +failproofai jev setup --mode off # yapılandırmayı tut, Jev'e sorma +``` + +Aynı anahtar yerel panosunda da var: **Settings → Jev** açık/kapalı anahtarı ve gölge/zorlama vardır. Modu yeniden yazar ve başka bir şey yok. Kancalar yapılandırmayı her araç çağrısında okurlar, bu nedenle bir değişiklik sonraki çağrıdan uygulanır, yeniden başlatma olmadan. + +## Ne yaptığını kontrol edin + +```bash +failproofai jev status +failproofai jev test +``` + +`status`, sağlayıcıyı **FailproofAI Cloud** olarak, makinenin bağlandığı Cloud ana bilgisayarını, modu ve anahtar kaynağını **FailproofAI Cloud bağlantısı** olarak gösterir, asla anahtarı değil. FailproofAI Cloud `jev.json` hazırken Jev çalışamadığında, neden olduğunu söyler: + +| `status` derken | `status --json` | Anlamı | +| --- | --- | --- | +| **off — bu makine için FailproofAI Cloud bağlantısı için hiçbir Jev anahtarı depolanmamıştır** | `key-lacks-jev` | Makine bağlı, ancak Jev anahtarı depolanmamıştır: anahtarda `jev:evaluate` yok veya bağlantı bunu onaylayamadı. `failproofai config --token ` komutunu aynı anahtarla yeniden çalıştırın; izin eksikse, **machine** anahtarı kullanın. | +| **off — bu makine FailproofAI Cloud'a bağlı değildir** | `not-connected` | Bu makinede Jev anahtarının ait olabileceği bir FailproofAI Cloud bağlantısı yok. | + +`failproofai config --disconnect` sonrasında artık FailproofAI Cloud `jev.json` yok (kapatılmadıkça tutulur), bu nedenle `status` basitçe Jev'i kapalı olarak bildirir. `status --json` aynı gerçekleri taşır (`provider: "failproofai"`, `keySource: "cloud"`, `cloudConnected`, `keyCarriesJev`), yapılandırma yokken veya reddedildiğinde de. `permissions` her zaman `jev.json`'undur; `credentials.json` hakkında bir reddi `credentialsPermissions` ekler ve `fix` bir komut bunu düzelttiğinde. `test` bir canlı istek gönderir ve latansi ile yanıt veren Jev sürümünü bildirir. Hook zaman aşımından sonra cevap geldiğinde (kancalar `timeout` kaydeder) veya kontrol sorusuna yanlış cevap verdiğinde 1 ile çıkar ve başlığında bunu söyler. + +Panonun **Settings → Jev** paneli de **FailproofAI Cloud bağlantısını** gösterir: makinenin rapor ettiği kuruluş ve anahtarı Jev taşıyıp taşımadığı. Makinenin kendi dosyalarından okunur, ağ çağrısı yok. + +## Politika sayfasına ulaşan şey + +Makine, kanca etkinliğini zaten FailproofAI Cloud'a gönderir (`events:add`). Jev açıkken, her geçitli çağrının kaydı ayrıca hangi değerlendiriciyi çalıştırdığını, Jev'in ne karar verdiğini, hangi politikaları temizlediğini, ne zaman geri düştüğünü, latansısını ve yanıt veren modeli söyler — kararlar, kodlar ve adlar, asla komut veya istem değil. Kuruluşunuzun **Policies** sayfasında: + +- Jev'in kendi kararı tarafından verilen bir çağrı (zorlama modu) **Jev**'ye atfedilir ve karar veren kontrol bir paketten geldiğinde, kayıt da o paketi ve sürümünü adlandırır; +- gölge modunda, Jev'in reddi veya uyarısı gözlemlediğiniz dağıtımların yanında **yapacağı** olarak görünür; +- Jev'in temizlediği veya gölge modunda temizleyeceği politikalar politika başına sayılır. + +## Jev yanıt veremediğinde + +Bunların her biri o çağrı için politikalarınızın sonucuna geri döner ve nedeniyle kaydedilir: + +| Neden | Sebep | +| --- | --- | +| `out-of-credits` | Kuruluşunuz plan payını kullanmıştır. | +| `http-401`, `http-403` | Anahtar iptal edildi veya `jev:evaluate` taşımıyor. Bunu taşıyan bir anahtarla yeniden bağlanın. | +| `http-429` | FailproofAI Cloud, kuruluşunuz için Jev'i hız sınırlaması yapıyor. Talep ettiği bekleme süresi bitene kadar (en fazla 60 saniye `Retry-After`), makine ona hiçbir şey göndermez ve her çağrı hemen geri döner. Bu şekilde tutunca çağrılar `http-429` veya makinenin kendi hız sınırlaması onları tuttuğunda `rate-limited` olarak kaydedilir. | +| `http-429` (günlük sınır) | Kuruluşunuz günlük Jev çağrılarını kullandı: **UTC günde 10.000**, FailproofAI Cloud'unuzu işleten kişi başka bir sınır koymadıkça. Her çağrı sayı 00:00 UTC'de sıfırlanana kadar geri döner; makine yine de en fazla dakikada bir sorular, bu nedenle sıfırlamayı bir dakika içinde alır. `failproofai jev test` "Daily Jev limit for this org reached; resets at 00:00 UTC." der. | +| `http-422` | Jev bu çağrının isteğini reddetti, genellikle araç çağrısı Jev'in belirteç bütçesinin üzerinde yoğun metin (base64, hex, küçültülmüş kod) tuttuğu için. O çağrı her zaman geri döner; bir kesinti değildir. | +| `http-502` | Jev şu anda kullanılamıyor. | +| `http-503` | Bu Cloud kuruluşunuz için Jev sunabilir: model ağ geçidi yok, henüz sağlanmayan kuruluş veya ağ geçidi kapalı. Yöneticinize sorun; kancalar en fazla dakikada bir sorular. | +| `http-404` | Bu FailproofAI Cloud henüz Jev sunmuyor. | +| `timeout` | `timeoutMs` içinde yanıt yok (varsayılan 3000). | +| `model-mismatch` | 1.13 dışında bir Jev sürümü yanıt verdi. | + +## Anahtar nerede yaşar ve nereye gider + +- Anahtar bir kez `~/.failproofai/credentials.json` içinde depolanır (`0600`, yalnızca sahip dizininde), diğer FailproofAI Cloud kimlik bilgilerinin yanında. `jev.json` bu rota için anahtar tutmaz; orada yazılan anahtar yapılandırmayı geçersiz yapar. +- `credentials.json` siz dışında herkes için **herhangi** izin taşıyorsa (grup veya diğer, okuma veya yazma) veya dizini siz dışında herkes tarafından **yazılabilirse**, **reddedilir**, okunmaz ve Jev düzeltene kadar kapalı kalır: dosyaya `chmod 600`, dizine `chmod 700` (veya yeniden bağlanın, bu dosyayı `0600` da yeniden yazar ve dizini yalnızca sahibine yapar). Diğerlerinin yalnızca okuyabildiği bir dizin iyidir; yazabileceği biri dosyayı değiştirmelerine izin verir. +- Anahtar yalnızca geldiği bağlantı makinede açıkken sayılır: aynı FailproofAI Cloud için bir politika veya raporlama kimlik bilgisi **aynı anahtarla**, aynı dosyada. Arkada kalan bir Jev anahtarı olmadan yok sayılır ve Jev kapalı kalır. Bu, eski bir failproofai'nin `config --disconnect` Jev anahtarını yerinde bıraktığında (kaldırmayı bilmez) veya eski bir failproofai'nin `config --token` başka bir anahtarla bağlandığında olur, FailproofAI Cloud'da başka bir kuruluşa ait olabilir. Jev'i geri açmak için bir **machine** anahtarla yeniden bağlanın. +- Anahtar yalnızca doğrulandığı Cloud kaynağına gönderilir. Başka bir yere işaret eden bir `jev.json` reddedilir. +- **Makinedeki bir ajan bunu okuyabilir.** `credentials.json` yalnızca sahibine aittir ve ajan bu sahibi olarak çalışır. failproofai'nin kendi dosyalarını okumak amaçlı izinlidir (yalnızca değiştirme `block-failproofai-commands` tarafından engellenir), bu nedenle ajan ve bu dosya arasında tek şey `block-read-outside-cwd` — *incelenebilir* politika — ve ev dizininizden başlayan bir oturumdan hiçbir şey. `jev:evaluate` ile bir anahtar kuruluşunuzun Jev payını (günlük kapdan) kullanıldığı yerden harcayabilir, bu nedenle makine anahtarını herhangi bir harcama kimlik bilgisi gibi değerlendirin: ajan bunu okumuş olabilirse, Keys sayfasında devre dışı bırakın ve yeni bir anahtarla yeniden bağlanın. +- Yalnızca genel dosyalarınız bunu karar verir. Bir depo Cloud Jev'i açamaz, başka bir yere işaret edemez veya anahtarını sunamaz ve `FAILPROOFAI_JEV_API_KEY` bu rota için yok sayılır. +- Jev'in değerlendirdiği her çağrı için bir istek FailproofAI Cloud'a gider, [kendi anahtarını getir sayfası](/tr/policies/jev-byok#what-leaves-the-machine) listeleri (sırlar redakte edildi). FailproofAI Cloud bunu TypeSafe'e iletir ve günlük tutmaz veya tutmaz. + +## Kapat + +| Komut | Sonuç | +| --- | --- | +| `failproofai jev setup --mode off` | Yapılandırmayı tut; Jev sorulmaz. **Bu kalıcı olan anahtardır:** yeniden bağlanmak asla mevcut `jev.json` dosyasının üzerine yazmaz, bu nedenle Jev `--mode shadow` ile geri açana kadar kapalı kalır. | +| `failproofai jev remove` | `~/.failproofai/jev.json` dosyasını sil; Jev kapalı — sonraki `failproofai config --token` `jev:evaluate` taşıyan bir anahtarla kadar, `jev.json` bulamaz ve Jev'i gölge modunda açar (`--no-transcripts` olmadan çalıştırmadıkça). Kapalı tutmak için `--mode off` kullanın. | +| `failproofai config --disconnect` | Makinenin bağlantısını kes: anahtar kaldırılır ve FailproofAI Cloud'u adlandıran ve kapalı olmayan `jev.json` da kaldırılır. Kendi uç noktanız için `jev.json` kalır ve kapatılanı da, bu nedenle yeniden bağlandığınızda Jev kapalı kalır. | + +Sonraki araç çağrısından, kancalar regex politikalarını tam olarak önceki gibi çalıştırır. \ No newline at end of file diff --git a/docs/tr/policies/jev.mdx b/docs/tr/policies/jev.mdx new file mode 100644 index 000000000..de03f0620 --- /dev/null +++ b/docs/tr/policies/jev.mdx @@ -0,0 +1,45 @@ +--- +title: "Jev policies" +description: "Jev'in canlı incelemesini gated tool call'lara ekleyin, ardından kararlarını uygulamadan önce inceleyin." +icon: "shield-check" +--- + +Jev bir tool call'u kişinin agent'ten ne yapmasını istediğine karşı okur. String eşleştirme politikası geçerli işi engellediğinde veya bağlam gerektiren riskli bir işlemi kaçırdığında kullanın. `PreToolUse` veya `PermissionRequest` gate'inde politikalarınızla birlikte yanıt verir. Oturum bittikten **sonra** bir puan için [Jev evaluations](/tr/evaluations/jev) kullanın. + +## Gözlem modunda başlayın + +Failproof AI'yi yükleyin ve hook'ları bir [desteklenen harness'e](/tr/reference/harnesses) bağlayın. failproofai 1.0.8-beta.0 veya sonrası kullanın. + +Failproof AI hiçbir Jev kontrolü ile gelmez. Bunları bir pack olarak yükleyin, aksi takdirde Jev'in sorması için hiçbir şey olmaz ve asla çağrılmaz: + +```bash +failproofai policies add FailproofAI/jev-policies +``` + +Daha sonra isteklerin Jev'e nasıl ulaştığını seçin: + +| Rota | İlk adım | +| --- | --- | +| FailproofAI Cloud | `jev:evaluate` taşıyan bir **machine** anahtarı ile bağlanın. Jev konfigürasyonu olmayan bir makinede, `failproofai config` Jev'i gözlem modunda açar. | +| Kendi sağlayıcınız | Yerel dashboard'da, **Settings → Jev** açın, sağlayıcıyı seçin, token'ını yapıştırın ve **observe** seçeneğini belirleyin. Veya `failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key` çalıştırın. | + +![Yerel dashboard'ın Jev ayarları: sağlayıcı, endpoint, token ve Jev'i açmadan önce gözlem modu.](/images/dashboard/jev-settings.png) + +```bash +failproofai jev status +failproofai jev test +``` + +`test` endpoint'i kontrol eder. Hook yolunu kontrol etmek için, hooked agent'den `README.md` üzerinde dosya okuma tool'u kullanmasını isteyin. Bu tool call'un oturumda göründüğünü onaylayın, ardından [yerel dashboard'da](/tr/reference/local-dashboard#review-policy-activity) **Policies → Activity** bölümünü inceleyin. `status` içindeki Jev sayısı artmalıdır. Gözlem modu Jev'in ne karar vereceğini kaydederken mevcut politika sonucunuz hala geçerli kalır. + +## Ne zaman uygulanacağına karar verin + +Bir **hard** politika her zaman son söze sahiptir. Jev, yalnızca açıkça **reviewable** olarak işaretlenmiş bir politikadan bir reddi temizleyebilir ve yalnızca bu politikanın adlandırılmış endişesini kontrol ettiğinde. Bir açıklığa güvenmeden önce [policy authority](/tr/policies/authority) bölümüne bakın. Jev ayrıca kendi başına uyarı veya ret verebilir. Yanıt veremezse, politika sonucu o call'u belirler. + +Gözlem sonuçları doğru görünmeye başladığında, **Settings → Jev**'de enforce moduna geçin veya şunu çalıştırın: + +```bash +failproofai jev setup --mode enforce +``` + +Sağlayıcı URL'leri, Cloud anahtarları, konfigürasyon, fallback'ler ve her istekle gönderilen veriler için [Jev integration reference](/tr/reference/jev) bölümüne bakın. \ No newline at end of file diff --git a/docs/tr/reference/custom-agents-typescript.mdx b/docs/tr/reference/custom-agents-typescript.mdx new file mode 100644 index 000000000..df4d053a4 --- /dev/null +++ b/docs/tr/reference/custom-agents-typescript.mdx @@ -0,0 +1,401 @@ +--- +title: "Özel ajanlar (TypeScript)" +description: "@failproofai/sdk için yapılandırma, etkinlik kataloğu, kapsamlar ve çerçeve adaptörleri." +icon: "square-js" +--- + +TypeScript SDK için her ayarın, metodun ve alanın ne yaptığını öğrenin. İlk kez enstrümantasyon yapıyorsanız kılavuzla başlayın — bu sayfa referans amaçlıdır. + + + + Yükleme, enstrümantasyon, etkinlik metodları, çalışan bir örnek ve yaygın sorunlar. + + + Aynı etkinlikler, aynı tel formatı, aynı spool — Python'dan. + + + +Node 20.9 veya daha yeni sürüm. ESM ve CommonJS desteklenir. Çalışma zamanı bağımlılığı yok. + + + Bu SDK ve Python SDK **aynı spool'a aynı etkinlikleri yazar**. Node ajanları ve Python ajanları içeren bir filo bir set oturum üretir, iki set değil ve pano hiçbirini ayırt etmez. Şirket başına değil, hizmet başına seçin. + + +## Yükleme + +```bash +npm install @failproofai/sdk +``` + +```ts +import * as failproofai from "@failproofai/sdk"; + +await failproofai.agent("planner", { goal: question }, async () => { + const hits = await failproofai.toolCall("web_search", { input: { q } }, () => search(q)); +}); +``` + +Çerçeve adaptörleri paketin kendisinde gönderilir. Çerçeveler **isteğe bağlı eş bağımlılıklardır** — desteklenen aralıklar görülebilsin diye bildirilir, asla sizin adınıza yüklenmez ve sadece `instrument()` çağırdığınızda alınır. + +## Failproof daemon'ı bağlayın + +Python SDK ile aynıdır: **Admin → Anahtarlar** altında bir `events:add` anahtarı oluşturun, ardından [daemon'ı bağlayın](/tr/start/setup#connect-a-machine-to-cloud). SDK diske yazarak; daemon gönderir. + +## Yapılandırma + +```ts +failproofai.configure({ + environment: "production", + flushInterval: 0.5, + baseDir: undefined, +}); +``` + +| Seçenek | Ne yaptığı | +| --- | --- | +| `environment` | Her etkinlik üzerindeki etiket — `production`, `staging`, `prod-eu`. Varsayılan `dev`. | +| `flushInterval` | Zamanlayıcının diske yazma sıklığı, saniye cinsinden. Varsayılan `0.5`. | +| `baseDir` | Nereye yazılacağı. Varsayılan daemon'ın spool'u, aksi takdirde bilmediğiniz sürece istediğiniz şeydir. | + +Hiçbir şey uygulanmaz, hepsi doğrulanmazsa, reddedilen bir çağrı SDK'yı yeni bir `baseDir` ve eski aralık ile değil, tamamen olduğu gibi bırakır. + +Bunun yerine ortam değişkeni ile ayarlayın: + +| Değişken | Ne yaptığı | +| --- | --- | +| `AGENTEYE_ENVIRONMENT` | Kod değişikliği olmadan `environment` ayarlar. `configure()` seçeneği bunu geçersiz kılar. | +| `FAILPROOFAI_HOME` | Spool'u tutan Failproof AI kökünü taşır. | +| `FAILPROOFAI_SDK_LOG_LEVEL` | `debug`, `info`, `warn` (varsayılan), `error`, `silent`. | +| `FAILPROOFAI_SDK_STRICT` | `1` enstrümantasyon hatalarını günlüğe kaydırmak yerine fırlatır. | +| `FAILPROOFAI_SDK_STRICT_INTEGRATIONS` | `1` çerçeve uyumluluğu sorunu fırlatır, uyarı vermek ve devam etmek yerine. | + + + **`environment` içinde virgül yok.** Alım bu alanı virgülle ayırarak filtrelerini oluşturur ve bir tane içeren herhangi bir etkinliği atlar — böylece tüm bir çalıştırma sessizce kaybolur. `prod,eu` yerine `prod-eu` yazın. + + `configure({ environment: "prod,eu" })` hemen anlaşılması için fırlatır. `AGENTEYE_ENVIRONMENT` fırlatamaz — hiç kimse sizi çağırmıyor — bu yüzden bir kez uyarır ve `dev`'e geri döner. + + +SDK'nın kendi günlük satırlarını loggerinize `failproofai.setLogger({ debug, info, warn, error })` ile yönlendirin. + +## Kapatma + +Arabelleğe alınan etkinlikler `process.on("exit")` üzerinde temizlenir. + +Bir sinyal tarafından öldürülen bir işlem asla buna ulaşmaz ve Node'un `SIGTERM` için varsayılanı çıkış işleyicileri çalıştırmadan sonlandırmaktır — bu nedenle kapsayıcılı bir ajan son aralığın yazmadığı her şeyi kaybeder. + + + **Bu SDK sizin için bir sinyal işleyicisi yüklemeyecektir.** Birini kaydetmek işleminizin davranışını değiştirir: bir dinleyici Node'un varsayılan sonlandırmasını bastırır, bu nedenle bir tane ekleyen bir kütüphane sessizce Ctrl-C'yi çalışmaktan alıkoyardı. Kendi başınızınkini ekleyin: + + ```ts + for (const signal of ["SIGINT", "SIGTERM"] as const) { + process.once(signal, () => { + failproofai.flushSync(); + process.exit(0); + }); + } + ``` + + +Kısa ömürlü bir komut dosyası veya sunucusuz işleyici dönmeden önce `await failproofai.flush()` çalıştırmalıdır — aralık tek başına teslim etmeyi garanti etmez. + +## Kimlik + +Her etkinlik bir oturuma ve bir ajanı aittir. **Kapsamlar her ikisini de doldurur**, bu nedenle nadiren onları geçersiniz: + +```ts +await failproofai.session(async () => { + await failproofai.agent("planner", async () => { + failproofai.event.toolUse({ toolName: "search", toolCallId: "c1" }); + }); +}); +``` + +`sessionId` veya `agentId` açıkça geçirmek hala işe yarar ve kazanır. Ne bağlı ne de geçilmişse, çağrı Cloud'un sessizce atacağı bir etkinlik yayarken bir hata fırlatır. + + + Kimlik `AsyncLocalStorage` üzerinde gider. `await`, `.then()`, zamanlayıcılar ve kapsam içinde oluşturulan herhangi bir geri çağrıyı takip eder. Bir çalıştırma sırasında depolanan ve başka bir sırasında çağrılan geri çağrıyı **takip etmez** veya `worker_threads` sınırı arasında verilen işle çalışmaz — bunları `failproofai.propagate()` ile sarın veya etkinlikleri bağlantısız olarak iner. + + +### Kapsamlar + +| Kapsam | Yayar | Döndürür | +| --- | --- | --- | +| `session(body)` | hiçbir şey — sadece kimlik | `body` ne döndürürse | +| `agent(id, options?, body)` | `agent_start`, sonra `agent_end` | `body` ne döndürürse | +| `toolCall(name, options?, body)` | `tool_use`, sonra `tool_result` | `body` ne döndürürse | + +Eşzamanlı bir gövde eşzamanlı kalır: `agent("x", () => 1)` `1` döndürür, bir söz değil. + +`toolCall` gövdenin çözülmüş değerini aracın `output` olarak kaydeder, `call.output`'u kendiniz atamadığınız sürece. + + + +| Ne oldu | Etkinlikler | `outcome` | +| --- | --- | --- | +| blok döndü | `agent_end` | `"success"`, veya sizin `outcome` | +| blok fırladı | `error`, sonra `agent_end` | `"failed"` | +| bir `AbortError` | sadece `agent_end` | `"cancelled"` | + +Hata her zaman yeniden fırlatılır. + +Bir araç hatası yaprakta kaydedilir — `tool_result` bir `error` dizesi ile — ve **hiçbir** çalıştırma düzeyi `error` etkinliği yayar. Ajan döngüsünün yakaladığı bir, bir çalıştırma hatası değildir ve yayılan bir, çevreleyen `agent()` tarafından tam olarak bir kez bildirilir. + + + + + +İş tek bir fonksiyon değilse — bir kapsam bir yapıcıda açılır ve bir sökmede kapatılır veya mevcut kontrol akışını geçen bir: + +```ts +{ + using span = failproofai.agent.open("planner", { goal }); + using call = failproofai.toolCall.open("search", { input: { q } }); + call.call.output = await search(q); +} // tool_result, sonra agent_end +``` + +Her iki form bayt-özdeş etkinlikler yayar. Geri çağrı formunu tercih edin: `AsyncLocalStorage.run()` içinde çalışır, bu nedenle açılmış kalan hiçbir şey yoktur ve "burada açık, orada kapalı" hatalarının tüm sınıfı ulaşılamaz. + +Kendi başarısızlığını yakalayan bir `using` bloğu bunu `span.fail(error)` ile bildirir — ayırıcının kendi istisna kanalı yoktur. + + + +## Etkinlik kataloğu + +Python SDK ile aynı on beş metod, camelCase'te. Çoğu **çiftler halinde** gelir — açıcıyı çağırırsınız, ardından kapatıcıyı, ve SDK boşluğu zamanlar. + +| | Açar | Kapar | +| --- | --- | --- | +| **Ajanlar** | `agentStart` | `agentEnd` | +| | `agentPause` | `agentResume` | +| **Modeller** | `modelRequest` | `modelResponse` | +| **Araçlar** | `toolUse` | `toolResult` | +| **Kanca** | `hookTriggered` | `hookCompleted` | +| **İnsanlar** | `humanWait` | `humanInput` | + +Üç kişi tek başına durur: `error`, `humanPause`, `humanInterrupt`. + + + +Her metod ayrıca `sessionId` ve `agentId` alır, kapsamlar bunları sizin için doldurur. Atlanmış hiçbir şey JSON `null` olarak gönderilmek yerine bırakılır. + +| Metod | Gerekli | İsteğe Bağlı | +| --- | --- | --- | +| `agentStart` | — | `goal`, `parentId` | +| `agentEnd` | — | `outcome`, `summary` | +| `agentPause` | `pauseId` | `reason`, `userId` | +| `agentResume` | `pauseId` | `reason`, `userId` | +| `modelRequest` | — | `model`, `messages`, `system`, `tools`, `requestId` | +| `modelResponse` | — | `model`, `stopReason`, `inputTokens`, `outputTokens`, `content`, `role`, `requestId` | +| `toolUse` | `toolName`, `toolCallId` | `input` | +| `toolResult` | `toolName`, `toolCallId` | `output`, `error` | +| `hookTriggered` | `hookName`, `hookId` | `triggerEvent`, `input` | +| `hookCompleted` | `hookName`, `hookId` | `outcome`, `output`, `error` | +| `error` | `errorType`, `message` | `traceback` | +| `humanWait` | `inputId` | `prompt`, `options`, `reason` | +| `humanInput` | `inputId` | `response` | +| `humanPause` | — | `reason`, `userId` | +| `humanInterrupt` | — | `reason`, `userId`, `atStep` | + +Eklediğiniz diğer herhangi bir anahtar özel bir yük alanı haline gelir. Çerçeveye özgü hiçbir şeyi `fw_*` olarak adlandırın; beyan edilen bir alanla çarpışan bir ad, sessizce tanıtılan bir sütunu üzerine yazmak yerine reddedilir. + + + + + **`duration_ms` hesaplanır, kabul edilmez.** Dört kapatıcı metod açıcılarından boşluğu zamanlar ve arayan tarafından sağlanan `duration_ms` öğesini reddeder — bildirilen bir süre tahrifatsızdır. + + Çiftler ajanın değil **oturumda** ve id'de eşleştirilir. Planner altında açılan ve çalışan altında kapatılan bir araç hala eşleşir, bu gerçek iç içe geçmiş çok ajanı çalıştırmaların yaptığı şeydir. + + +## Çerçeve adaptörleri + +```ts +await failproofai.instrument(); // bulabilir ne olursa +await failproofai.instrument("langchain"); // tam olarak bir tane +failproofai.uninstrument(); // her şeyi geri koy +``` + +| Çerçeve | Desteklenen | Nasıl bağlandığı | +| --- | --- | --- | +| **LangChain.js / LangGraph.js** | `@langchain/core` 0.3 – 1.x, LangGraph.js 0.4 – 1.x | `CallbackManager.configure`, böylece her `invoke`/`stream`/`batch` hiçbir yerde `callbacks:` geçmeden veya kendiniz `langchainHandler()` yama ve geçmeden kapsanır. | +| **Vercel AI SDK** | `ai` 4 – 7 | `telemetry()` çağrı sitesinde veya `ai` 7'de (4–6'da opt-in — aşağıya bakın) tüm işlem için `instrument("ai")`. | +| **Mastra** | `@mastra/core` 0.20 – 1.x | `Agent.generate`/`.stream`, ajanın modeli ve araç çözümü ve iş akışı çalıştırma/adım motoru. | +| **LlamaIndex.TS** | `llamaindex` 0.11.4 – 0.x | `Settings.callbackManager` (abone edilmiş) artı `AgentWorkflow.runStream`, iş akışı çalıştırmaları ve adımları için. | + +Her aralık, gerçek çerçeve sürümleriyle her iki uçta da ES modülü olarak ve CommonJS olarak her CI çalıştırmasında test edilir. + +Harita Python SDK'sının olduğu için aynı program her iki dilde de aynı ağacı çizer. Bir yapı bir **ajan** 'dir sadece LLM karar döngüsüne sahipse — bir grafik veya zincir çalıştırması, AI SDK `generateText`/`streamText` çağrısı, Mastra ajanı, LlamaIndex ajan çalıştırması. Bir LangGraph düğümü veya iş akışı adımı bir **kanca** (`hook_triggered`/`hook_completed`), asla iç içe geçmiş bir ajan değil. Model çağrıları token sayılarıyla `model_request`/`model_response` çiftleridir; araç çağrıları modelin kendi araç çağrısı id'sini taşır. Bir başarısızlık, olduğu etkinlikte bir kez kaydedilir. + +Yüklemede başarısız olan bir adaptör günlüğe kaydedilir ve atlanır; diğerleri hala yükler, çünkü kırık bir LlamaIndex sizi LangGraph'a mal olmamalıdır. + + + Bağımsız değişken içermeyen `instrument()` çerçeveyi zaten alınıp alınmadığı değil, **çözüp çözmediğine** göre algılar — Node ES modülleri için Python'un `sys.modules` eşdeğerini sunmaz. Yüklediğiniz ancak kullanmadığınız bir çerçeve alınır ve yamalanır. İstediğiniz birini adlandırın, bu önemliyse. + + + + Bu çerçevelerin çoğu ES modülü yapısı ve CommonJS yapısı gönderir, bu Node'u iki ilişkisiz kopya olarak yükler. Adaptörler uygulamanızın yüklediği kopyayı (ve bir şey zaten `require` ettiyse CommonJS kopya da) yamarlar, bu nedenle her iki modül sistemi çalışır. esbuild veya webpack tarafından kendi çıktınıza **paketlenmiş** bir çerçeve ulaşılamaz — orada çağrı sitesi yardımcılarını kullanın: `langchainHandler()`, `telemetry()`, `wrapTool()`. + + +### Yamalama olmadan LangChain + +```ts +import { langchainHandler } from "@failproofai/sdk/langchain"; +await graph.invoke(input, { callbacks: [langchainHandler()] }); +``` + +İşleyici `instrument()` ile veya olmadan çalışır ve asla çift kayıt yapmaz. `instrument("langchain")` `sessionId`, `captureContent`, `includeChains`, `graphCallbacks` ve `captureLimit` alır, Python adaptörü yaptığı gibi; bir çağrı üzerinde `metadata: { failproofai_sdk_session_id }` o çağrıyı oturum için seçer. + +### Vercel AI SDK + +AI SDK, bir ES modülünden düz fonksiyonlar dışarı aktarır ve bir ES modülü ad alanı belirtim tarafından değişmez — yamlanacak yer yoktur. SDK'nın kendisinin belgelediği uzantı noktalarını kullanır: + +```ts +import { telemetry } from "@failproofai/sdk/ai"; + +const { text } = await generateText({ + model, + prompt, + experimental_telemetry: telemetry({ functionId: "answer-question" }), + // ai 7'de, `telemetry: telemetry({ … })` — aynı nesne, yeni ad +}); +``` + +Bu tam entegrasyon: bir ajan aralığı, adım başına token sayılı bir model istek/yanıt çifti ve her araç çağrısı. Bir çağrı sitesi her büyük çalışır — `ai` 4–6 taşıdığı izlemeci okur, `ai` 7 telemetri entegrasyonu. + +`instrument("ai")` **`ai` 7'de** aynı şeyi işlem genelinde yapar: her çağrı, AI SDK'nın küresel telemetri entegrasyonu listesi aracılığıyla, katkı maddesi ve başka kimsenin hiçbir şeyini almaz. + +**`ai` 4–6'da, `instrument("ai")` kendi başına hiçbir şey kaydetmez ve bunun söyleyen bir uyarı günlüğe kaydeder.** Bu büyükelçi Tek işlem genelinde kancası küresel OpenTelemetry izlemeci sağlayıcıdır — OpenTelemetry alındıktan sonra teslim etmeyi reddeden bir tek yuva. Bizimkini kaydetmek daha sonra başlangıçta kendi `NodeSDK.start()` öğesini sessizce reddedecek ve http/veritabanı açıklığınızı hiçbir şey ihraç etmeyen bir izlemeciye gönderecektir. Çağrı sitesinde `telemetry()` veya orada `wrapModel` kullanın. İşlem kendi OpenTelemetry'sini çalıştırmıyorsa `instrument("ai", { registerGlobalTracer: true })` ile opt-in yapın: daha sonra `experimental_telemetry: { isEnabled: true }` geçen her çağrıyı kaydeder ve hala boşsa yuvasını alır. `registerGlobalTracer: false` varsayılanı tutar ve uyarıyı susturur. + +Modeli bir kez sarmalayı tercih ederseniz, `wrapModel` araç çağrıları model katmanının üstünde olduğu için sadece model çağrılarını görür. Etrafında hiçbir şey olmadan çağrılan sarmalı model kendi çalıştırması olarak kaydedilir. Bir akışa alınan çağrı akışın nasıl durduğunu kapatır — tüketici iptal ettiğinde `stop_reason: "cancelled"`, yarı yolda başarısız olduğunda `"error"`: + +```ts +import { wrapModel } from "@failproofai/sdk/ai"; +const model = await wrapModel(openai("gpt-4o")); +``` + +Her ikisini de kullanmak iyidir: ara yazılım çağrının zaten kaydedilmekte olduğunu fark eder ve ertelerse, her çağrı bir kez kaydedilir. + +`functionId` ajan aralığını adlandırır. Düşük kardinalite tutun — `agent_id`'ye, birincil pano yüzüne iner. + +### Next.js + +`next build` sunucunun bağımlılıklarını varsayılan olarak paketler ve bir çerçeve yapıya paketlenmiş bir `instrument()`'ın ulaşamayacağı bir kopyadır. Config'i bir kez sarın ve Next'in başlangıç kancasından `instrument()` çağırın: + +```ts +// next.config.ts +import { withFailproofai } from "@failproofai/sdk/next"; +export default withFailproofai({ /* your config */ }); +``` + +```ts +// instrumentation.ts +export async function register() { + if (process.env.NEXT_RUNTIME !== "nodejs") return; + const failproofai = await import("@failproofai/sdk"); + await failproofai.instrument(); +} +``` + +`withFailproofai` LangChain, Mastra, LlamaIndex ve SDK'nın kendisini `serverExternalPackages`'a ekler, kendi listenizi tutar. Olmadan, `instrument()` ulaşamadığı her çerçeve için bir kez uyarır, sessizce başarısız olmakla değil; paketleri kendiniz listeleyeniz `FAILPROOFAI_NEXT_EXTERNALS=1` ayarlayın. Vercel AI SDK ve çağrı sitesi yardımcıları her iki şekilde de çalışır. Bir Edge rotası no-op yapısı alır: SDK'yı almak güvenlidir ve hiçbir şey kaydetmez. + +### Akışa alınan çağrılarda token sayıları + +OpenAI uyumlu API'ler bir akışta kullanımı sadece istemci sorduğunda bildirir. LangChain ve Vercel AI SDK sorar; LlamaIndex için `additionalChatOptions: { stream_options: { include_usage: true } }` öğesini `OpenAI` LLM'sine geçirin ve Mastra için modeli kullanım etkin şekilde oluşturun (örneğin `createOpenAICompatible({ includeUsage: true })`). Aksi takdirde akışa alınan model çağrıları token sayılarını taşımaz. + +### Çalışma zamanları + +Node ≥ 20.9, Bun ve Deno — her çerçeve, ES modülü olarak ve CommonJS olarak, her CI çalıştırmasında Node'un izine karşı test edilir. SDK `failproofaid` daemon'ın yanında çalışır, bu yazılan şeyi gönderir. + +## Kendi ajanınız — çerçeve yok + +Kendi yazdığınız bir ajan döngüsü için veya adaptörleri olmayan bir çerçeve için. Etkinlikleri adaptörlerin altında kullandığı aynı API ile yayarsınız, bu nedenle izlemenin aynı şekli ve kalitesi vardır. + +Ajanın nasıl organize edildiğini bilmeniz gerekmiyor. Her el yapımı ajan zaten üç yere sahiptir, işlevleri ne adlandırılırsa olsun, ve bu üç bütün entegrasyondur: + +| Nerede | Ne eklenecek | Yayar | +| --- | --- | --- | +| **Bir çalıştırma** başında ve bitişinde | `failproofai.agent("name", { goal }, async () => …)` | `agent_start` / `agent_end` | +| **Modeli çağıran tek fonksiyon** | `event.modelRequest` öncesinde, `event.modelResponse` sonrasında — her iki yarı, başarısızlıkta bile | model açarı başına bir çift | +| **Araçları çalıştıran tek fonksiyon** | `failproofai.toolCall(name, { toolCallId, input }, () => run())` | `tool_use` / `tool_result` | + +```ts +async function callModel(messages) { + const requestId = randomUUID(); + const started = Date.now(); + failproofai.event.modelRequest({ model: MODEL, requestId, messages }); + try { + const reply = await client.chat.completions.create({ model: MODEL, messages, tools }); + failproofai.event.modelResponse({ + model: reply.model, requestId, stopReason: reply.choices[0].finish_reason, + inputTokens: reply.usage?.prompt_tokens, outputTokens: reply.usage?.completion_tokens, + duration_ms: Date.now() - started, + }); + return reply.choices[0].message; + } catch (error) { + failproofai.event.modelResponse({ model: MODEL, requestId, stopReason: "error", + error: String(error), duration_ms: Date.now() - started }); + throw error; + } +} + +async function dispatch(call) { + const input = JSON.parse(call.function.arguments); + return failproofai.toolCall(call.function.name, { toolCallId: call.id, input }, + () => runTool(call.function.name, input)); +} + +await failproofai.agent("inventory", { goal: question }, async () => { + for (;;) { + const message = await callModel(messages); + if (!message.tool_calls?.length) return message.content; + for (const call of message.tool_calls) await dispatch(call); + } +}); +``` + +Kimlik ortam oluşturur: `agent()` içindeki her şey bir id almadan o çalıştırma oturumuna iner ve programdaki başka hiçbir şey değişmez — ajanın zaten kendi veritabanına yazdığı da dahil olmak üzere. + +- **Bir hizmet veya bir çalışan:** kendi isteğinizi veya iş id'sini `sessionId` olarak geçirin, böylece pano üzerinde bir oturum ve kendi günlüğüne veya veritabanına kayıt aynı dizedir. +- **Alt ajanlar:** `agent()` çağrılarını iç içe yerleştirin. İçeri olan dış olarak oturuma `parent_id` ile katılır. +- **Çiftleri yayar.** `modelRequest` ile `modelResponse` yoksa pano çalıştığını sonsuza kadar gösteren bir aralıktır — dolayısıyla `catch`. + +Depo içinde [`sdk/typescript/examples/research-agent.ts`](https://github.com/FailproofAI/failproofai/blob/main/sdk/typescript/examples/research-agent.ts) tam ve çalıştırılabilir sürümdür: tam bir OpenAI araç döngüsü tam olarak bu şekilde enstrümante, ES modülü olarak ve CommonJS olarak her değişiklikte CI'da çalıştırılır. + +## Değerlendirmeler + +```ts +import { Evaluator, EvalResult, Score } from "@failproofai/sdk/evaluator"; + +export const app = new Evaluator({ name: "my-evals", version: "1" }); + +app.eval("tool_success_rate", { version: "1" }, (session) => { + const results = session.eventsOfType("tool_result"); + const failures = results.filter((event) => event.payload.error != null).length; + return new EvalResult({ + score: new Score(results.length === 0 ? 1 : 1 - failures / results.length), + reasoning: `${failures} of ${results.length} tool calls failed`, + }); +}); +``` + +```bash +FAILPROOFAI_EVALUATOR_URL=… FAILPROOFAI_EVALUATOR_TOKEN=… \ + npx failproofai-evaluator ./my-evals.js +``` + +Protokol, çalışan ayarları ve sonuç türleri için [Evaluator SDK referansı](/tr/reference/evaluator-sdk) bölümüne bakın. + + + **Bir değerlendirme vermelidir.** Asla döndürmeyen eşzamanlı bir fonksiyon Node'un sahip olduğu tek thread'i bloke eder ve hiçbir zaman aman aşımı ateşlendi. Yazma `async` değerlendirmeleri. + + +## İşleminize ne yapmayacağı + +| | | +| --- | --- | +| **Ajan döngünüzü bloke** | Etkinlikler bellek içi sıraya girer; zamanlayıcı yazar. Zamanlayıcı `unref`'lenmiştir, bu nedenle bu paketi almak hiçbir zaman komut dosyasını çıkıştan alıkoyamaz. | +| **Sınırlar olmadan büyü** | Sıra sayı *ve* ölçülen bayt tarafından sınırlanır. Her birini geçerek, en eski etkinlikler atılır ve bir uyarı bunu söyler — telemetri kesintisi OOM öldürmesi haline gelmemeli. | +| **İşlemi aşağıya al** | Bir kodlanamaz etkinlik, etrafındaki toplu değil, yalnız bırakılır. Fırlatılan bir alıcı, dairesel referans, `BigInt`, yalnız bir vekil: her biri yayılmak yerine ele alınır. | +| **Yarı yazılmış toplu iş bırak** | İçerik `fsync`lenmiş önce atomik yeniden adlandırma, dizin `fsync`lenmiş sonra ve başarısız yazılı temiz geçici dosya. | +| **Transkriptleri okunabilir bırak** | Toplu işlemler `0700` dizini içinde `0600`'dir. Hedefler, istemi, araç bağımsız değişkenleri ve araç çıktısı taşırlar. | +| **Gemi kimlik bilgileri** | API anahtarları, belirteçler, JWT'ler, taşıyıcı başlıkları ve gizli şekilli atamalar baytlar diske ulaşmadan önce redaksiyonlanır. Daemon yüklemeden önce yeniden redaksiyonlanır. | \ No newline at end of file diff --git a/docs/tr/reference/jev-cloud.mdx b/docs/tr/reference/jev-cloud.mdx new file mode 100644 index 000000000..8aa88a48d --- /dev/null +++ b/docs/tr/reference/jev-cloud.mdx @@ -0,0 +1,136 @@ +--- +title: "Jev through FailproofAI Cloud" +description: "Cloud machine keys, connection state, limits, and failure behavior for live Jev policy review." +icon: "cloud" +--- + +Bu, [Jev policies](/tr/policies/jev) için Cloud route referansıdır. Jev, TypeSafe'nin sınıflandırıcısı, her araç çağrısını gerçekte ne istediğinize karşı okur ve politikalarınızın yanında cevap verir, asla yerine değil. **FailproofAI Cloud** aracılığıyla, bağlı bir makine, Jev'i zaten bağlandığı anahtarla kullanır: TypeSafe hesabı yok, ikinci anahtar yok, yapılandırılacak endpoint yok. Her çağrı, kuruluşunuzun mevcut plan limitine ücretlendirilir. + +Jev'in yaptığı her şey [kendi anahtarını getir kurulumundan](/tr/reference/jev-providers) değişmemiştir: sabit politikalar nihai kalır, gözden geçirilebilir bir politikanın reddi, sadece Jev tam olarak o endişe hakkında sorulduğunda temizlenir ve herhangi bir hata o çağrı için regex sonucuna geri döner. + + +**failproofai 1.0.8-beta.0** veya daha yeni sürüm gerekir. 1.0.7'de 1.0.7 beta sürümlerinin üstünde sıralanmasına rağmen Jev yoktur. Jev yapılandırması olmadan hiçbir şey değişmez: hook'lar regex politikalarını her zaman olduğu gibi çalıştırır. + + +## Başlamadan önce + +Failproof AI'ı aracınızın çalıştığı makinede kurun ve hook'larını [desteklenen bir harness'e](/tr/reference/harnesses) takın. Sıfırdan başlıyorsanız, [hızlı başlangıç](/tr/start/quickstart) kılavuzunu hook kurulumuna kadar izleyin. Yüklü CLI'yi `failproofai --version` ile kontrol edin; Jev öncesine dayatılıyorsa güncelleyin. Ayrıca kuruluşunuzun **Administration → Keys** sayfasına erişim açmanız gerekir. + +Jev, `PreToolUse` veya `PermissionRequest` geçidinde adlandırılmış araç çağrılarını gözden geçirir. Bir oturumdaki her olayı gözden geçirmez. Jev politika reddini temizlemeyi görmek için [gözden geçirilebilir](/tr/policies/authority) olarak işaretlenmiş yüklü bir politikaya ihtiyacınız vardır; diğer tüm politika reddis son kalır. + +## Etkinleştirin + +1. **Jev ile bir anahtar oluşturun.** FailproofAI Cloud panosunda **Administration → Keys → Create key** seçeneğini açın ve **machine** ön ayarını seçin. Bir makinenin ihtiyaç duyduğu üç izni verir: `events:add` (etkinlik gönder), `policies:pull` (politika al) ve `jev:evaluate` (Jev, kuruluşunuzun planından ücretlendirilir). Bir anahtar `jev:evaluate` olmadan diğer ikisini taşıyamaz. +2. **Makineyı o anahtarla bağlayın.** Komut istemi üzerinde kerelik sırrını okuyun, sonra tam kurulum komutunu çalıştırın: + + ```bash + read -rs FAILPROOFAI_CLOUD_TOKEN && export FAILPROOFAI_CLOUD_TOKEN + failproofai config + ``` + + `failproofai config` daemon'ı kurar, bulduğu agent CLI'leri için hook'ları takarsanız ve makineyi bağlar. Ortam değişkeni anahtarı komut bağımsız değişkenlerinden ve shell geçmişinden uzak tutar. Harness'iniz daha sonra kurulduysa, [açıkça takın](/tr/start/quickstart). + + Kuruluşunuz barındırılan yerine kendi FailproofAI Cloud'unu çalıştırıyorsa, adresini ekleyin: `--url https://` (veya `FAILPROOFAI_CLOUD_URL` ortam değişkenini ayarlayın). Olmadan anahtar barındırılan hizmete karşı kontrol edilir ve bağlantı başarısız olur. Bu konağın sertifikası özel bir CA'dan geliyorsa, CA'yı makinenin sistem güven deposunda kurun (örneğin `update-ca-certificates` ile), yalnızca `NODE_EXTRA_CA_CERTS` içinde değil: olayları gönderen ve politikaları çeken daemon sistem deposunu okur. [Sorun Giderme](/tr/reference/troubleshooting) bölümüne bakın. + +Bu kadar. Bağlanmak anahtarı depolar ve makine **henüz** Jev yapılandırmasına sahip değilken, Jev'i **observe** modunda FailproofAI Cloud aracılığıyla etkinleştirir: bir paket kontroller verdikten sonra, Jev her gated araç çağrısı hakkında sorulur ve verdikleri kaydedilir, ancak politikalarınızın sonucu uygulanan şeydir. Çıktı bunu söyler: + +```text + Jev on through FailproofAI Cloud, in observe mode: logged, not enforced (~/.failproofai/jev.json). +``` + +Bir paket kontroller verdikten sonra Jev hala hiçbir şey sormuyor. Failproof AI hiçbirini göndermez; yüklü paket herhangi birini bildirmezken, çıktı bunu söyleyen bir satır ekler ve `failproofai jev status` bunu tekrarlar. Bunları kurun: + +```bash +failproofai policies add FailproofAI/jev-policies +``` + +**`--no-transcripts` ile bağlanmak Jev'i açmaz.** Jev her kontrol edilen araç çağrısını ve son promptu FailproofAI Cloud'a gönderir, bu da yalnızca kararları göndermeyi isteyen bir bağlantıdan daha fazlasıdır. Anahtar hala depolanır ve çıktı Jev'in kullanılabilir olduğunu ve nasıl açılacağını söyler: + +```bash +failproofai jev setup --provider failproofai +``` + +Jev'i **kapatmaz** da. Makinenin `jev.json` zaten FailproofAI Cloud aracılığıyla Jev çalıştırıyorsa, olduğu gibi bırakılır ve çıktı Jev'in hala her kontrol edilen araç çağrısını ve son promptu gönderdiğini ve `failproofai jev setup --mode off` seçeneğinin bunu kapattığını söyler. + + +Bağlanmak **asla** var olan `~/.failproofai/jev.json` dosyasını üzerine yazmaz. Zaten kendi Jev endpoint'inizi kullanıyorsanız, kullanılmaya devam eder ve çıktı dosyanın yapılandırıldığı şekilde bırakıldığını söyler — ve bu dosya Jev'i kapalı bıraktığında (reddedildi veya kapatıldı), bunu söyler ve nasıl düzeltileceğini söyler. Bu makineyi FailproofAI Cloud'a geçirmek için `failproofai jev setup --provider failproofai` komutunu çalıştırın. + + +## Gözlemle, uygula veya kapat + +Observe modunda başlayın, politika sayfasında Jev'in ne yapacağını izleyin, sonra bunu uygulamasına izin verin: + +```bash +failproofai jev setup --mode enforce # Jev's verdicts apply: it may clear a reviewable deny and add its own +failproofai jev setup --mode observe # Jev is asked and logged; your policies' result is enforced +failproofai jev setup --mode off # keep the config, stop asking Jev +``` + +Aynı anahtarlaç yerel panoda vardır: **Settings → Jev** açık/kapalı anahtarına ve observe/enforce seçeneğine sahiptir. Modu yeniden yazar ve başka bir şey değil. Hook'lar yapılandırmayı her araç çağrısında okurlar, bu nedenle bir değişiklik yeniden başlatma olmaksızın sonraki çağrıdan itibaren uygulanır. + +## Ne yaptığını kontrol edin + +```bash +failproofai jev status +failproofai jev test +``` + +`status` sağlayıcıyı **FailproofAI Cloud** olarak, makinenin bağlandığı Cloud konağını, modu ve anahtar kaynağını **FailproofAI Cloud connection** olarak gösterir, asla anahtarı değil. FailproofAI Cloud `jev.json` yerindeyken ancak Jev çalıştırılamıyorsa, nedenini söyler: + +| `status` söyler | `status --json` | Anlam | +| --- | --- | --- | +| **off — no Jev key is stored for this machine's FailproofAI Cloud connection** | `key-lacks-jev` | Makine bağlı, ancak bunun için depolanmış Jev anahtarı yok: anahtarda `jev:evaluate` eksik, veya bağlantı bunu doğrulayamadı. `FAILPROOFAI_CLOUD_TOKEN` içinde anahtar ile `failproofai config` komutunu tekrar çalıştırın; izni eksikse, **machine** anahtarı kullanın. | +| **off — this machine is not connected to FailproofAI Cloud** | `not-connected` | Bu makinede Jev anahtarının ait olacağı FailproofAI Cloud bağlantısı yok. | + +`failproofai config --disconnect` sonrasında artık FailproofAI Cloud `jev.json` yok (kapatıldıysa bunu tutulan hariç), bu nedenle `status` basitçe Jev'i kapalı olarak bildirir. `status --json` yapılandırma olmadığında veya reddedildiğinde bile aynı gerçekleri taşır (`provider: "failproofai"`, `keySource: "cloud"`, `cloudConnected`, `keyCarriesJev`). `permissions` her zaman `jev.json`'ın; `credentials.json` hakkında bir reddi `credentialsPermissions` ekler ve bir komut onu düzelttiğinde `fix`. `test` bir canlı istек gönderir ve latensisini ve cevapladığı Jev sürümünü bildirir. Hook timeout'ından sonra cevap geldiğinde veya kendi kontrol sorusunu yanlış cevaplandırdığında 1 ile çıkır ve başlığında bunu söyler. + +Panonun **Settings → Jev** paneli de **FailproofAI Cloud connection** gösterir: makinenin hangi kuruluşa rapor verdiğini ve anahtarının Jev'i taşıyıp taşımadığını. Makinenin kendi dosyalarından ağ çağrısı olmadan okunur. + +## Gerçek bir çağrıyı doğrulayın + +Hooked agent'ta yeni bir oturum başlatın. Dosya okuma aracını `README.md` üzerinde kullanmasını ve başlığı bildirmesini isteyin. Oturumun o araç çağrısını içerdiğini onaylayın, sonra `failproofai jev status` komutunu tekrar çalıştırın: yakın zamanda değerlendirilen çağrı sayısı artmalıdır. [Yerel panosunda](/tr/reference/local-dashboard#review-policy-activity) **Policies → Activity** seçeneğini açın ve o çağrının Jev kararını ve modunu inceleyin. Cloud'da, kuruluşun **Policies** sayfası teslim edilen etkinlik için Jev sonuçlarını gösterir. Observe modunda, karar **would-have** olarak kaydedilir ve politika sonucu hala çağrıya karar verir. Bir temizleme, gözden geçirilebilir bir politika eşleştiğinde ve Jev adlandırılmış kontrolleri temizlediğinde görünür. + +## Politika sayfasına ne ulaşır + +Makine, hook etkinliğini zaten FailproofAI Cloud'a gönderir (`events:add`). Jev açıkken, her gated çağrının kaydı ayrıca hangi değerlendircinin çalıştığını, Jev'in ne karar verdiğini, hangi politikaları temizlediğini, geri dönüş sebebini, latensisini ve cevaplayan modeli söyler — kararlar, kodlar ve adlar, asla komut veya prompt'unuz değil. Kuruluşunuzun **Policies** sayfasında: + +- Jev'in kendi kararının karar verdiği bir çağrı (enforce modu) **Jev** özniteliğine atfedilir ve karar kontrolü bir paketten geliyorsa, kayıt ayrıca o paket ve sürümünü de adlandırır; +- observe modunda, Jev'in reddi veya uyarısı **would-have** olarak görünür, gözlemlediğiniz rollout'ların yanında; +- Jev'in temizlediği veya observe modunda temizlemiş olacağı politikalar politika başına sayılır. + +## Jev cevap veremediğinde + +Bunların her biri o çağrı için politikalarınızın sonucuna geri döner ve nedeni ile kaydedilir: + +| Neden | Sebep | +| --- | --- | +| `out-of-credits` | Kuruluşunuz plan limitini kullanmıştır. | +| `http-401`, `http-403` | Anahtar iptal edildi veya `jev:evaluate` taşımıyor. Bunu taşıyan bir anahtarla yeniden bağlayın. | +| `http-429` | FailproofAI Cloud, kuruluşunuz için Jev'i hız sınırlıyor. İstediği bekleme süresi bitene kadar (`Retry-After`, maksimum 60 saniye), makine ona hiçbir şey göndermez ve her çağrı hemen geri döner. Bu şekilde tutulan çağrılar `http-429` olarak veya makinenin kendi hız sınırı önce tutuklarında `rate-limited` olarak kaydedilir. | +| `http-429` (günlük limit) | Kuruluşunuz günlük Jev çağrılarını kullanmıştır: **UTC günde 10.000**, FailproofAI Cloud'unuzu işleten kişi başka bir limit belirlemedikçe. Her çağrı sayı sıfırlanana kadar geri döner 00:00 UTC'de; makine hala en fazla dakikada bir kez sorduğundan, sıfırlamayı dakika içinde seçer. `failproofai jev test` komutu "Daily Jev limit for this org reached; resets at 00:00 UTC." söyler. | +| `http-422` | Jev bu çağrının isteğini reddetti, genellikle araç çağrısında yoğun metin (base64, hex, minified kod) Jev'in token bütçesi üzerinde olduğu için. O çağrı her zaman geri döner; bu bir kesinti değil. | +| `http-502` | Jev şu anda kullanılamıyor. | +| `http-503` | Bu Cloud kuruluşunuz için Jev'e hizmet veremez: model gateway yok, henüz sağlanmamış bir kuruluş veya gateway'i kapalı. Yöneticinize sorun; hook'lar en fazla dakikada bir kez sorgulanır. | +| `http-404` | Bu FailproofAI Cloud henüz Jev'e hizmet etmiyor. | +| `timeout` | `timeoutMs` içinde (varsayılan 3000) cevap yok. | +| `model-mismatch` | 1.13 dışında bir Jev sürümü cevap verdi. | + +## Anahtar nerede yaşar ve nereye gider + +- Anahtar bir kez, `~/.failproofai/credentials.json` dosyasında (`0600`, yalnızca sahibinin dizini içinde) diğer FailproofAI Cloud kimlik bilgilerinin yanında depolanır. `jev.json` bu route için anahtar tutmaz; oraya yazılan anahtar yapılandırmayı geçersiz yapar. +- Eğer `credentials.json` sizden başka biri (grup veya diğer, okuma veya yazma) için **herhangi** izin taşıyorsa, veya dizini sizden başka biri tarafından **yazılabilirse**, **reddedilir**, okunmaz ve Jev düzeltene kadar kapalı kalır: dosyada `chmod 600`, dizinde `chmod 700` (veya yeniden bağlayın, bu da dosyayı `0600` yeniden yazar ve dizini yalnızca sahibine yapar). Diğerlerinin sadece okuyabileceği bir dizin sorun değil; yazabileceği dosyayı değiştirebilir. +- Anahtar sadece bağlantısı makine üzerindeyken sayılır: aynı FailproofAI Cloud için bir politika veya raporlama kimlik bilgisi **aynı anahtarla**, aynı dosyada. Bağlantısı olmaksızın bırakılan bir Jev anahtarı yok sayılır ve Jev kapalı kalır. Bu, daha eski failproofai'nin `config --disconnect` Jev anahtarını yerinde bıraktığında (kaldırmayı bilmez) veya daha eski failproofai'nin `config --token` başka bir anahtarla bağlandığında olur; FailproofAI Cloud'da başka bir kuruluşa ait olabilir. Jev'i geri açmak için **machine** anahtarı ile yeniden bağlayın. +- Anahtar sadece doğrulandığı Cloud kaynağına gönderilir. Başka bir yere işaret eden bir `jev.json` reddedilir. +- **Makinedeki bir agent bunu okuyabilir.** `credentials.json` yalnızca sahibine aittir ve agent bu sahibi olarak çalışır. Failproofai'nin kendi dosyalarını okumak amaçlı olarak izin verilir (sadece değiştirmek engellenir, `block-failproofai-commands` tarafından), bu nedenle bir agent ve bu dosya arasındaki tek şey `block-read-outside-cwd` — *gözden geçirilebilir* bir politika — ve ana dizininden başlatılan bir oturumdan hiçbir şey yoktur. `jev:evaluate` ile bir anahtar kuruluşunuzun Jev limitini (günlük kapak kadar) kullanıldığı yerden harcayar, bu nedenle makine anahtarını başka bir harcama kimlik bilgisi gibi ele alın: bir agent bunu okumuş olabilirse, Keys sayfasında devre dışı bırakın ve yeni biriyle yeniden bağlayın. +- Sadece global dosyalarınız buna karar verir. Bir depo Cloud Jev'i açamaz, başka bir yere işaret edemez, anahtarını sağlayamaz ve `FAILPROOFAI_JEV_API_KEY` bu route için yok sayılır. +- Jev değerlendirdiği her çağrı için, FailproofAI Cloud'a bir istek gider, [bring-your-own-key sayfasının](/tr/reference/jev-providers#what-leaves-the-machine) listediğini içeriyor (gizli bilgiler redakte edilmiş). FailproofAI Cloud bunu TypeSafe'e iletir ve günlüğe kaydeder veya tutmaz. + +## Kapatın + +| Komut | Sonuç | +| --- | --- | +| `failproofai jev setup --mode off` | Yapılandırmayı saklayın; Jev sorulmaz. **Bu süren anahtardır:** yeniden bağlanmak var olan `jev.json`'ı asla yeniden yazmaz, bu nedenle Jev `--mode observe` ile geri açana kadar kapalı kalır. | +| `failproofai jev remove` | `~/.failproofai/jev.json` dosyasını silin; Jev kapalı — sonraki `failproofai config --token` içine kadar `jev:evaluate` taşıyan bir anahtar ile, bu `jev.json` bulamaz ve observe modunda Jev'i açar (`--no-transcripts` ile çalıştırılmadıkça). Kapalı tutmak için `--mode off` kullanın. | +| `failproofai config --disconnect` | Makineyi bağlantısını kesin: anahtar kaldırılır ve `jev.json` FailproofAI Cloud'ı adlandırdığında ve kapatılmadığında da kaldırılır. Kendi endpoint'iniz için `jev.json` kalır ve kapatılmış olanı da kalır, bu nedenle yeniden bağlandığında Jev kapalı kalır. | + +Sonraki araç çağrısından, hook'lar regex politikalarını tam da öncesi gibi çalıştırır. \ No newline at end of file diff --git a/docs/tr/reference/jev-evaluations.mdx b/docs/tr/reference/jev-evaluations.mdx new file mode 100644 index 000000000..eddef93f5 --- /dev/null +++ b/docs/tr/reference/jev-evaluations.mdx @@ -0,0 +1,88 @@ +--- +title: "Jev evaluation referansı" +description: "Soru türleri, kalibre edilmiş puanlar, limitler ve Jev oturumu değerlendirmeleri için geri doldurma." +icon: "list-checks" +--- + +Bu sayfa [Jev değerlendirmelerinin](/tr/evaluations/jev) arkasındaki soru şekillerini ve puanlama kurallarını açıklamaktadır. Bazı soruların bir modelin konuşmayı *okumasını* gerektirir, ancak bunu *yazmasını* değil. "Müşteri aciliyet ifade etti mi?" iki cevabı vardır. "Ne kadar hayal kırıklığına uğramışlardı?" bir kaç cevabı vardır, sırayla. Her cevabı sormadan önce bilirsiniz. + +Bir **sınıflandırıcı değerlendirmesi** tam olarak bunlar içindir. Soruyu ve alabileceği cevapları yazarsınız, ve sınıflandırma için tasarlanmış küçük bir model kalibre edilmiş bir sayı döndürür — hiç ücretsiz metin değil. + + +Bir hakim gibi, sınıflandırıcı değerlendirmesi oturum başına bir model çağrısı maliyeti oluşturur. Hakim olmaması yerine genel bir model yerine küçük, tek amaçlı bir model olduğundan daha hızlı ve ucuz olur — ancak hiçbir zaman kendini açıklamaz. Akıl yürütmeye ihtiyacınız varsa, bir [hakim](/tr/evaluations/judge) kullanın. + + +## Hangisini istiyorum? + +| Soru | Kullan | +| --- | --- | +| Kaç tane araç çağrısı vardı? | kod | +| Oturum 30 saniyeden az mıydı? | kod | +| Müşteri aciliyet ifade etti mi? | **sınıflandırıcı** | +| Hangi takım bunu yönetmeli: faturalandırma, teknik veya satış? | **sınıflandırıcı** | +| Müşteri ne kadar hayal kırıklığına uğramıştı? | **sınıflandırıcı** | +| Cevap gerçekten doğru muydu? | **hakim** | +| Bizim yükseltme politikasını takip etti mi ve neden böyle düşünüyorsunuz? | **hakim** | + +Temel kural: **sayılabilir → kod, listeleyebileceğiniz cevaplar → sınıflandırıcı, açıklama gerektiriyor → hakim.** + +Önceden karar vermek zorunda değilsiniz. Ölçülmek istediğinizi açıklayın ve asistan seçer, hangisini seçtiğini ve neden seçtiğini söyler, ve değiştirebilirsiniz. + +## İki soru türü + +### `noul` — bu doğru mu? + +İki cevap ve her ikisini de açıklarsınız. Sonuç, "doğru" açıklamanın uyma olasılığıdır: + +```json +{ + "instructions": "Asistan, önce iade politikasını kontrol etmeden iade vaat etti mi?", + "criteria": { + "true": "Önceki politika kontrolü veya onayı olmadan iade vaat edildi veya verildi", + "false": "Iade vaat edilmedi veya her iade bir politika kontrolünü takip etti" + } +} +``` + +Her iki tarafı açıklayın. "Aciliyet ifade edilmedi" gerçek bir cevapdır ve bunu söylemek diğerini keskinleştirir. + +### `score` — bunun ne kadarı? + +Sıralı bir rubrik, **en kötüsü ilk**. Sonuç oturumun buna nasıl yerleştiğidir, 0–1'e yeniden ölçeklendirilir: + +```json +{ + "instructions": "Müşteri ne kadar hayal kırıklığına uğramıştı?", + "criteria": ["Sakin", "Hayal kırıklığı", "Çok öfkeli"] +} +``` + +**Bir rubrik üç ila beş seviye alır ve hepsi farklı olmalıdır.** Her iki limit de stilistik değil, ölçülür: + +- **İki seviye** `noul`'un zaten daha iyi yaptığı şeye dönüşür ve **beşten fazla** model orta noktaya hedge etmek yerine taahhüt etmesini sağlar. Aynı soru aynı oturum üzerinde iki seviye ile 0.00, üç seviye ile 0.01 ve on seviye ile 0.55 puanlandı. +- **Tekrarlanan seviyeler** cevabı keyfi olarak aralarında böler. Açıkça öfkeli bir oturum `["Sakin", "Hayal kırıklığı", "Çok öfkeli"]` karşısında 1.00 ve `["Öfkeli", "Öfkeli", "Öfkeli"]` karşısında 0.66 puanlandı — anlamı olmayan iyi biçimlendirilmiş bir sayı. + +Siparişi olmayan kategoriler — "faturalandırma, teknik veya satış" — rubrik değildir. Bunları kategori başına `noul` olarak sorun veya bir hakim kullanın. + +## Sonuçları okuma + +Bir sınıflandırıcı, bir hakimle tam olarak aynı şekilde 0 ila 1 arasında bir **puan** üretir, bu nedenle grafik oluşturur, filtreler ve uyarıları tetikler. Bilmeye değer iki fark vardır: + +- **Akıl yürütme yoktur.** Alan kasıtlı olarak boştur. Bu model kendini açıklamaz ve açıklama icat etmek bir özellik yerine sahtekarlık olurdu. +- **Belirsizlik etiketlenmiştir.** Bir `score` sorusu kendi güvenini bildirir ve modelin emin olmadığı bir sonuç `low_confidence` ile etiketlenir — bu nedenle "bunlardan hangisine bir insan bakmalı" bir tahmin yerine bir filtredir. Bir `noul` sorusu güven bildirmez, bu nedenle asla etiketlenmez. + +Çok uzun oturumlar alıntılarında okunur ve birleştirilir. Bir oturum tamamen okunmak için çok uzun olduğunda, sonuç kaç dönüşün atlandığını söyler — hiçbir zaman bir oturumun bir kısmı üzerinde yapılan bir yargı tamamı üzerinde yapılan bir olarak sunulmayacaksınız. + +## Limitler + +- **Üç ila beş rubrik seviyesi, hepsi ayrı.** Yukarıya bakın; her iki sınır da yazarlık zamanında uygulanır. +- **Değerlendirme başına bir soru.** İki şey sorun ve iki değerlendirme alırsınız, bu aynı zamanda bir grafikte istediğiniz şeydir. +- **Soruyu düzenleme yeni bir versiyonu yayımlar.** Eski ve yeni puanlar karşılaştırılmaz, bu nedenle bunlar bir trend çizgisinde karıştırılmak yerine ayrı tutulur. +- **Sınıflandırıcı her zaman bir puan üretir**, hiçbir zaman metrik veya iddia değil. +- **Akıl yürütme yoktur**, yukarıda olduğu gibi. Bir sayı birine "neden?" soratacaksa, bunun yerine bir hakim yazın. + +## Test ve geri doldurma + +Bir hakimden farklı olarak, sınıflandırıcı değerlendirmesi dağıtmadan **test edilebilir** — gerçek oturumlar karşısında bir kod değerlendirmesi gibi [test edin](/tr/evaluations/test) ve hiçbir şey canlı gitmeden puanları okuyun. + +Ayrıca zaten sahip olduğunuz oturumlar üzerinde [geri doldurulabilir](/tr/evaluations/deploy#score-sessions-you-already-have). Oturum başına bir model çağrısı maliyeti oluşturur, bu nedenle her şeyi yeniden oynatmak yerine pencereyi kasıtlı olarak kapsamlandırın. \ No newline at end of file diff --git a/docs/tr/reference/jev-intent.mdx b/docs/tr/reference/jev-intent.mdx new file mode 100644 index 000000000..050bac178 --- /dev/null +++ b/docs/tr/reference/jev-intent.mdx @@ -0,0 +1,113 @@ +--- +title: "Jev niyet yakalama" +description: "Hangi araç olayları Jev değerlendiricisine insanın ne istediğini söyler, metni hangi alan taşır, hiçbir zaman sayılmayan nedir ve bir araçtan teslim edilen isteme güvenmenin getirdiği risk nedir." +icon: "message-square-quote" +--- + +[Jev ilke incelemesi](/tr/policies/jev) yapılandırdığınızda, değerlendiricisi her gated araç çağrısını **insanın ne istediğine** karşı değerlendirir, araçın aracı öne koyduğu metne değil. "Evet, force-push yap" gibi bir yanıt, **incelenebilir** bir ilkeyi geçebilir — bu, değerlendiricinin tüm amacı, çünkü isteği okuyamayan bir regex gerçek işin üçte birini engeller. + +Bu metin bir yerden geliyor: **araç istemi submit olayında kendi kendine hook'a verdiği istemi**. Failproof AI, bunu kaydeder — araç sarması çıkarılır, sırlar gizlenir, sınırlandırılır — kendi durum dizini altındaki bir `0600` dosyasına. Hiçbir disk dosyası danışılmaz: oturum yazılımı, aracının tek bir komutla yeniden yazabileceği bir dosyadır, bu yüzden kimin istemi yazdığı hiçbir zaman sorulmaz. + +## Bu riski açık şekilde söylemek + +Zaten komutları çalıştırabilen bir araç, bir araçın istemi submit etmesini sağlayabilir. `claude -p "…"`, `codex exec`, `copilot -p`, `cursor-agent -p`, `devin -p`, `droid -p`, `goose run -t` ve `pi -p` hepsi, kontrol ettiği bir alt oturumda bir kişi yazdığı gibi, aynı prompt-submit olayını, aynı yükü ateşler. Ayrıca Failproof AI'ın kendi hook binary'sini çalıştırabilir ve yazdığı bir yükü besleyebilir. Failproof AI içinde hiçbir şey ikisini ayırt edemez — ikisi de aynı program, aynı stdin'i okuyor. + +**Yani kabuğu olan bir araç kendi rızasını sahte yapabilir.** Bu kasıtlı bir ticaret, 2026-09-23'te yapılmış ve işte bunun her iki yarısı: + +- **Ne satın alır.** Alternatif inşa edildi ve ölçüldü: aracının isteminin yazarı olarak bir insan adlandırdığı bir alan isteme, aksi takdirde hiçbir şey kaydetme. Hiçbir gönderilen araç böyle bir alan göndermediği için, bu sürüm **hiçbir şey kaydetmedi, her araç üzerinde** — Jev her çağrıyı belirtilen niyet olmadan değerlendirdi ve hiçbir zaman tek bir ilkeyi bile temizleyemedi. Hiçbir zaman ateş etmeyen bir yakalama daha güvenli bir ürün değildir, o hiç ürün değildir. +- **Bunu yapamayacağı.** Kaydedilmiş bir istem, yalnızca zaten **incelenebilir** işaretli bir ilkeyi temizler. Bir **hard** ilke asla Jev tarafından söylenen hiçbir şey tarafından temizlenmez, bu yüzden sahte bir istem asla hard bir reddi izne dönüştüremez — ve hook'u atlamak da bir araçla hiçbir şey kazandırmaz: araç, araç çağrısı için Failproof AI'yı bağımsız olarak çağırır. + +- **Tam boyutunda ne yapabilir.** Yapabileceği en kötü şey, on beş incelenebilir yerleşik ilkeden birini temizlemek — ve **on ikisi on beşten engeller**. `protect-env-vars`, `block-env-files`, `block-read-outside-cwd`, `block-rm-rf`, `block-force-push`, `block-secrets-write` ve altı altyapı-CLI bloku (`block-kubectl`, `block-terraform`, `block-aws-cli`, `block-gcloud`, `block-az-cli`, `block-helm`) reddeder, bu yüzden sahte rıza gerçek bir reddi ortam sırlarını yazdırmak, bir `.env` dosyası okumak, proje dışında okumak, `rm -rf`, bir force-push, sır dosyası yazmak veya canlı altyapıyı değiştirmek üzerine izne dönüştürebilir. Yalnızca `warn-git-amend`, `warn-destructive-sql` ve `warn-global-package-install` uyarılardır. Varsayılan bir kurulum iki tanesini açar, `protect-env-vars` ve `block-env-files`; diğer on, yalnızca bunları etkinleştiren bir makineye ulaşır. Hiçbir istem ulaşmayan şey her şey hard'dır — `block-sudo`, `block-curl-pipe-sh`, `block-push-master`, `block-work-on-main`, bir araçın Failproof AI'yı devre dışı bırakmasını durduran muhafız ve incelenebilir işaretli olmayan her diğer yerleşik. [İlke otoritesi](/tr/policies/authority) tüm on beşi ve her birinin ne tarafından incelendiğini listeler. + +Hala reddedilen, kontrol etmesi ucuz olan ve bir araçın sadece isteyerek alamayacağı her şeydir: araçın kendi yükünün makine-submit olarak işaretlediği bir dönüş, alt-araç adlandıran bir yük, düz bir ad olmayan oturum kimliği, prompt-submit olayı olmayan bir olay ve hiçbir şey ama araç sarması — Failproof AI'ın kendi stop-gate sözcükleri de dahil olmak üzere, birkaç araç bunları sonraki kullanıcı dönüşü olarak geri besler. + +## Araç başına tablo + +"Metin alanı" Failproof AI'ın araç başına normalleştirmesinden sonra stdin yükü alanıdır. "Kaydedildi" isteminin insan isteği olarak tutulup tutulmadığını söyler. + +| Araç | `--cli` | İstem olayı → kanonik | Metin alanı | Kaydedildi | Aracının son mesajı buradan okundu | +| --- | --- | --- | --- | --- | --- | +| Claude Code | `claude` | `UserPromptSubmit` | `prompt` | Evet, yükün `source` kimse göndermediyse (`loop_wakeup`, `schedule_wakeup`, `poll_event`, `system`). `user`, `sdk`, bilinmeyen bir değer ve hiç `source` göndermeyen bir yapı, tümü kaydedilir | oturum yazılımı (`transcript_path`) | +| Codex | `codex` | `user_prompt_submit` → `UserPromptSubmit` | `prompt` | Evet | rollout JSONL (`agent_message`, `AgentMessage`) | +| GitHub Copilot CLI | `copilot` | `UserPromptSubmit` | `prompt` | Evet | `events.jsonl` (`assistant.message`) | +| Cursor | `cursor` | `beforeSubmitPrompt` → `UserPromptSubmit` | `prompt` | Evet, `` sarması tüm istem olduğunda soyulur | arac yazılımı JSONL | +| OpenCode | `opencode` | `message.updated` (user role) → `UserPromptSubmit` | `prompt` | Evet — fakat mevcut OpenCode bu olay tarafından hiçbir metin taşımaz, bu nedenle pratikte hiçbir şey kaydedilmez; aynı mesajın tekrarı bir kez kaydedilir | hiçbiri (oturumlar SQLite'dir) | +| Pi | `pi` | `input` → `UserPromptSubmit` | `prompt` | Evet, `input_source` olmadıkça `extension` — başka bir uzantının `sendUserMessage()`, metni model tarafından yazılabilir veya repo'dan türetilmiş olabilir | Pi oturum JSONL | +| Hermes | `hermes` | hiçbiri | — | Hayır — Hermes'in hiç prompt-submit olayı yok | — | +| OpenClaw | `openclaw` | `before_agent_run` → `UserPromptSubmit` | `prompt` | Evet, çalıştırma meta verisi çalıştırmayı makine tarafından işaretlemediği sürece: `trigger` `user` dışında, `inputProvenance.kind` `external_user` dışında veya `senderIsOwner: false` | hiçbiri (`before_agent_run` yazılım yolu taşımaz) | +| Factory Droid | `factory` | `UserPromptSubmit` | `prompt` | Evet | droid oturum JSONL | +| Devin CLI | `devin` | `UserPromptSubmit` | `prompt` | Evet | hiçbiri (oturumlar SQLite'dir) | +| Antigravity CLI | `antigravity` | `PreInvocation` → `UserPromptSubmit` | hiçbiri | Hayır — `PreInvocation` her model çağrısından önce bir dönüşte ateş eder ve istem metni taşımaz | — | +| Goose | `goose` | `UserPromptSubmit` | `message` | Evet | hiçbiri (oturumlar SQLite'dir) | + +İki araç hiçbir şey kaydetmez ve her iki durumda da aynı nedenle: onların olayı insan metni teslim etmez. Hermes'in hiç prompt-submit olayı yok — yerel eklentisi `pre_llm_call`'ı kendisi işler ve yalnızca araç, oturum ve alt-araç olaylarını iletir. Antigravity'nin `PreInvocation`'ı her model çağrısından önce, insan dönüşünde ve onu takip eden beş dönüşte ateş eder ve istem alanı taşımaz; hook'lar ayrıca aynı konuşmaya `userMessage` adımları enjekte edebilir. Her iki olaydaki hiçbir şey kaydedilemez. + +## Bir istemini insan yapan şey + +1. **Olay.** Failproof AI, araçın prompt-submit olayı için çağrıldı, handler bunu `UserPromptSubmit`'e kanonik hale getiriyor. +2. **Yük.** Araç bunu hook'un stdin'ine yazar ve metni yukarıda adlandırılan alanda taşır. Failproof AI'a yük olmadan ulaşan bir çağrı hiçbir şey kaydetmez. +3. **Yükteki hiçbir şey dönüşü dışarı çıkarmaz.** Alt-araç adlandıran bir yük (`agent_id`) araçin kendisini komut etmesidir. `source`, `input_source` veya makine-submit dönüşü adlandıran OpenClaw çalıştırma işaretçi reddedilir. **Eksik** bir işaretçi hiçbir şeyi dışarı çıkarmaz — bu, hiçbir şey kaydetmeyen sürümden farktır, çünkü buradaki her işaretçi gönderilen her yapıda eksiktir. +4. **Sarma çıkarıldıktan sonra bir şey kalıyor** (aşağıya bakın). + +**Oturum yazılımı, kimin bir istemi yazdığının kanıtı değildir.** Bu sayfanın önceki sürümleri yazılım çapraz denetim tanımlamışlardır: yazılım modelin zamanladığını gösterse ve yazılım önceki isteminin gördüğünü devam ettirse istem reddedilir. Bu kontrol kayboldu. Yazılım, aracının zaten kabuğu olduğu bir dosyası — kesilmiş, değiştirilmiş, okuma bütçesinin ötesinde pad'lenmiş, bir dönüşün başlangıcında anlık görüntü alınıp sonunda geri yüklenmiş veya aracının yazdığı girişlerle yeniden iyi okunmuş olabilir. Sertleştirmenin her turunu başka bir sahte yazım takip etti, bu yüzden tüm mekanizma onarılmış yerine kaldırıldı. + +Yazılım hala bir şey için okunur: **aracının son görünür mesajı**. Bu mesaj aracı tarafından yazıldığı tanım gereği, Jev'e söylenir ve asla kendi başına rıza değildir. + +## İstemden ne tutulur + +Araçlar bir isteme insan sözcüklerinden daha fazla koyarlar. Hiçbir şey tutulmadan önce: + +- `` blokları kaldırılır ve etrafındaki insan sözcükleri tutulur. +- Oturum-devamı özeti ("Bu oturum önceki konuşmadan devam ediliyor…") tamamen bırakılır. +- Görev bildirimleri, yerel-komut çıkışı ve kesme işaretçileri tamamen bırakılır. +- Başka bir araç veya oturum tarafından yazılan dönüş tamamen bırakılır: Claude Code bunları ``, ``, ``, `` veya ``'de sarar. +- Failproof AI'ın kendi mesajları tamamen bırakılır. Bir stop gate'in `MANDATORY ACTION REQUIRED from failproofai …` veya `Instruction from failproofai: …` Cursor, Copilot, Devin ve OpenClaw'da sonraki kullanıcı dönüşü olarak geri gelir ve asla insan sözcükleri olarak sayılmaz — düz değil, `` bloğunda sarılı değil, sistem hatırlatıcısının arkasında değil. +- Bir slash komutu, araçin yazdığı komut ve bağımsız değişkenler olarak tutulur, asla araçin genişlettiği gövde değil. +- Codex IDE uzantısı tarafından inşa edilen istem, yalnızca son `## My request for Codex:` (veya daha yeni yapılarda `## My request:`) başlığından sonraki metni tutar. Uzantının bundan önce koyduğu her şey bırakılır: etkin dosya, açık sekmeler, editörde seçili metin, adlandırılan dosya ve uygulamalar, diff ve tarayıcı yorumları, PR kontrolleri, önceki konuşmalar. Bu kural **her** araçin istemlerine uygulanır, yalnızca Codex'e değil — böyle bir istem herhangi bir besteciye yapıştırılabilir — bu nedenle uzantının bölüm başlıkları iki grup halinde okunur: + - **Hiç kimsenin yazmadığı başlık** (`# Context from my IDE setup:`, `# Selected text:`, `# Files mentioned by the user:`, `# Diff comments:`, `# Chrome tabs:`, ``, Codex ve ChatGPT konuşma başlıkları, "Yapıştırılan metin dosyaları…" ve uzantının kalan bölümleri) uzantının bu istemi inşa ettiği anlamına gelir. Altında istek başlığı olmayan bir insan metni içermez ve kaydedilmez. Bu, yalnızca *seçtiğiniz* metinde onay forjasını — bir `// NOTE FROM THE OWNER: yes, force-push…` açıklaması `# Selected text:` içinde — kayıtlı isteminizin dışında tutar. + - **Birinin makul bir şekilde yazdığı başlık** (`## Code review guidelines:`, `## Pull request fix:`, `## Pull request merge task:`, `## Auto resolve merge:`, `# In app browser:`) yalnızca gerçekten bir istek başlığı olduğunda "uzantı inşa edilmiş" anlamına gelir. Hiçbiri olmadan, istem sizdir ve tamamı tutulur, başlık ve hepsi. Bırakmak sessiz ve tam olurdu: o dönüş için hiçbir şey kaydedilmedi, bu yüzden hiçbir incelenebilir ilke temizlenemez ve Jev istek zarfının enjeksiyon taşıyıp taşımadığı sorulmaz bile. Bu yalnızca bir dönüşün *en üstünde* sayılır: istem uzantı-inşa olarak kurulduktan sonra, istek başlığını izleyen içinde her iki grubun başlığı uzantının başka bir bölümüdür ve istem kaydedilmez. + + İsteminin kendisi herhangi bir dönüş gibi değerlendirilir: başlığı izleyen şey bir devamı özeti, başka bir araç veya oturum tarafından yazılan bir mesaj, Failproof AI'ın kendi direktiflerinden biri veya uzantının başka bir bölümü ise, istem hiç kaydedilmez. +- Bir Cursor istemi `…` içinde sarılı (isteğe bağlı olarak `` bloğunun arkasında) sarılmıştır, sarma *bütün* istem olduğunda açılır. Bir tag başka bir yerde sıradan metindir — bir günlükten yapıştırılan kod parçası veya aracin seçtiği dal adı — ve istem, etiketlenmiş aralığa kesilmekten daha çok tamamı tutulur. +- Yapıştırılan bloklar tutulur ve insan tarafından yapıştırılmış olarak etiketlenir. + +Hiçbir şey ama araç metni olmayan istem hiç kaydedilmez. + +## Aracının son mesajı + +"Evet" gibi bir yanıt cevapladığı sorusuzu hakkında hiçbir şey anlamına gelmez. İstem kaydedildiğinde, Failproof AI ayrıca aracının son görünür mesajını oturum yazılımından **o anda** okur ve isteminle birlikte depolar. Jev bunu kendi alanında alır, arac tarafından yazılmış olarak etiketlenir: kısa bir yanıtı açıklar ve asla kendi başına insan isteği olarak sayılmaz. Bu yazılımın okunduğu tek şey ve yeniden yazılan yazılımın yapabileceği en kötü şey, bir arac mesajının beklendiği yere arac tarafından yazılan bir mesaj koymaktır. + +Yazılımın sonundan okunur, en fazla son 4 MB. Desteklenen yazılım biçimleri Claude Code, Codex rolloutlar (eski `agent_message` olayları ve daha yeni `AgentMessage` öğeleri), Cursor, Copilot `events.jsonl` ve Pi, Factory ve OpenClaw oturum JSONL'sidir. Claude Code'un kendi sentetik ve API-hata mesajları ve alt-araç (sidechain) mesajları atlanır. Goose ve OpenCode için oturumları SQLite'de tuttuğu, Devin için yazılım tek bir JSON belgesi olan veya OpenClaw için `before_agent_run` olayı yazılım yolu taşımadığı için snapshot yoktur. + +## Depolama + +| Özellik | Değer | +| --- | --- | +| Konum | `~/.failproofai/state/semantic/sessions/.json` | +| İzinler | dosya `0600`, dizin `0700`. Bunun üstündeki her dizin, `~/.failproofai`'ye kadar, `jev.json`'nin dizininin ayak bağlı olduğu aynı kurala tutulur: başka birinin **yazabileceği** bir kural yeniden adlandırılıp değiştirilmesi olabilir, bu nedenle okuma yolu bulabildiği yerlerde bu yazma bitlerini çıkarır ve **hiçbir şey** okunamaz yerlerde okumaz. Kaydedilmiş istem daha sonra sahte olmaktan ziyade eksiktir ve hiçbir şey temizlenmez | +| Oturum başına tutulan | son 5 istem; önceki ile aynı olan istem yeni slot almaktan ziyade yerine geçer | +| Pencere | 6 saatten eski istemler yoksayılır | +| Boyut | her istem ve arac mesajı 6.000 karakterde başlık ve kuyrukları tutarak sınırlandırılır | +| Sırlar | hiçbir şey yazılmadan önce `sanitize-*` ilkeleri ile aynı desenleri kullanarak redakte edilir. 48.000 karakterden uzun metin ilk 28.800 ve son 19.200 karakteri olarak redakte edilir ve bu kesiklerin yanındaki metin, gizli kodu bölünmüş olabilecek yerlerde, asla depolanmaz | + +Harf, rakam, `.`, `_` ve `-` dışında bir şey içeren veya 128 karakterden uzun bir oturum kimliği, hiçbir zaman dosya adı olarak kullanılmaz, bu nedenle bunun için hiçbir şey kaydedilmez. + +Oturum dosyası, ancak içinde bir istem kaydedildikten sonra var olur. İstemler tutar ve başka hiçbir şey — kaynak durumu yok, yazılım işareti yok — ve altı saatlik pencereden daha uzun sessiz kaldıktan sonra silinir, bir sonraki oturum ilk istemini yazdığında. + +Jev uç noktası yapılandırılmadıkça hiçbir şey kaydedilmez. + +### Proje kökü + +"Proje içinde" — `read-outside-workspace` ve diğer yol kontrolleri tarafından yargılanan — ilk incelenmiş çağrısında oturumun bulunduğu proje içinde anlamına gelir. Kök o zaman sabitlenir ve daha sonraki `cd` onu hiçbir zaman hareket ettirmez; `cd` hala göreceli bir yolun nasıl çözüleceğini değiştirir. Bunu `cd` izlemesine izin vermek, bir çağrıda `cd ~/.ssh` `~/.ssh`'yi sonraki için proje yapmaya izin verirdi. + +Pin `~/.failproofai/state/semantic/roots/.json` olur, `{root, at}` tutar: dosya `0600`, dizin `0700` ve yukarıdaki ile aynı oturum-kimliği kuralı. 7 günden eski dosyalar yeni oturum kökünü sabitlediğinde silinir. Başka kullanıcıların yazabileceği `roots` dizini yoksayılır ve canlı dizinin kökü kullanılır. Oturumu yeniden sabitleme için dosyasını silin. + +## Bilinen sınırlamalar + +- **İstem, sadece hook çağrısı kadar güvenilirdir.** Buradaki her şey, araçin hook'un stdin'ine yazdığı yükü okur. Komutları çalıştırabilen bir araç, araçı başsız olarak (`claude -p` ve yukarıda listelenen yedi diğer) veya Failproof AI'ın kendi hook binary'sini yazıp yazdığı yükle çalıştırabilir ve hiç kimse tarafından yazılmayan bir istemi kaydedebilir. Bu, bu sayfanın başında tanımlanan kabul edilen takaştır: yalnızca incelenebilir ilkeleri temizler, asla hard bir tane — fakat on beşten on ikisi incelenebilir yerleşik reddeder, bu yüzden sahte istem gerçek bir bloğu on ikisinde izne dönüştürebilir. +- **Alt-araç algılanması Claude şeklindedir.** `agent_id` taşıyan yük, hiçbir araç üzerinde asla kaydedilmez. Bu, Claude Code, Factory Droid ve Devin'in kullandığı alandır. Codex istemi alt-araç iş parçacıkları içinde ateş eder, Copilot işlem içi yardımcısını çalıştırır, Goose bir `delegate` aracına sahip ve OpenClaw personaları çalıştırır — hiçbiri yükü bu tanıdığı bir şekilde işaretlemez, bu yüzden bu araçlardaki alt-araç istemi oturumun kendi istemi olarak kaydedilir. OpenClaw'ın `openclaw.agentId`, **değil** bu işaretçi: gönderilen eklenti bunu her çalıştırmada ayarlar, sahip tarafından dahil edilen. +- **İşaretçi taşımayan zamanlayıcılar.** Claude Code'un `schedule_wakeup` ve `loop_wakeup` ve OpenClaw'ın `cron` ve `heartbeat` tetikçileri reddedilir çünkü bu araçlar yükte bunu söyler. Goose'un kendi zamanlayıcısı (`goose schedule add`) ve Codex'in `codex exec` hiçbir şey söylemez, bu yüzden başlattıkları çalıştırma başka herhangi biri gibi kaydedilir. +- **Aracının son mesajı aracin seçtiği bir mesaj olabilir.** Yazılım doğrulanmaz, bu yüzden kendi yazılımını yazan araç "son mesaj"ının ne söylediğine karar verebilir. Arac tarafından yazılmış olarak etiketlenir ve hiçbir zaman kendi başına hiçbir şey temizlemez — fakat `decide.ts`'in v1 yolunun deterministik "kullanıcı bu hedefi adlandırdı mı" kontrolünü karşılaması izin verdiğini unutmayın, bu yüzden yazılımını kontrol eden araç geçersiz kılma gerektiren bir hedef adı sağlayabilir. +- **Uzantının makine başlığından biriyle açılan istem tamamı bırakılır.** İstemi `# Selected text:`, `# Diff comments:`, `# Chrome tabs:` veya yukarıdaki ilk gruptan başka bir bölüm başlığıyla başlatın ve `## My request:` başlığı yazmayın ve o dönüş için hiçbir şey kaydedilmez — bu nedenle bunun için hiçbir şey temizlenmez. Bu kasıtlıdır: bu bölümler birinin kontrol ettiği metni taşır (seçtiğiniz kod, bir gözden geçirenin diff yorumu, sayfa başlığı) ve bunu sizin sözcükleri olarak kaydetmek daha kötü başarısızlıktır. Geliştirici makul bir şekilde yazdığı başlıklar ikinci grupta ve asla kendi başlarına istemi bırakmaz. +- **OpenCode pratikte hiçbir şey kaydetmez.** `message.updated` olayı mevcut OpenCode'da metin taşımaz ve görev aracın oluşturduğu alt oturumlar için de ateş eder, ana araçin yazdığı "kullanıcı" mesajı. +- **`CODEX_HOME` honoured değil** `lib/codex-sessions.ts` içinde rollout keşfi tarafından. Bu yalnızca arac mesajı anlık görüntüsü bulunduğu yeri etkiler, asla isteminin kaydedilip kaydedilmediğini değil. \ No newline at end of file diff --git a/docs/tr/reference/jev-providers.mdx b/docs/tr/reference/jev-providers.mdx new file mode 100644 index 000000000..eea696a9e --- /dev/null +++ b/docs/tr/reference/jev-providers.mdx @@ -0,0 +1,275 @@ +--- +title: "Jev sağlayıcıları ve kendi anahtarı kurulumu" +description: "Canlı Jev ilke incelemesi için sağlayıcı uç noktaları, model kimliği, yapılandırma ve başarısızlık davranışı (kendi anahtarınızla)." +icon: "key-round" +--- + +Bu, [Jev ilkeleri](/tr/policies/jev) için sağlayıcı ve yapılandırma referansıdır (kendi anahtarınızla). Regex ilkeleri dizeleri eşleştirir. `rm -rf ~` komutunun bir plana sızması ile sizin istediğiniz `rm -rf build/` komutunu birbirinden ayırt edemez; bu nedenle bir yerde çok fazla, diğer yerde çok az engeller. **Jev**, TypeSafe'in sınıflandırıcısı, çağrıyı sizin gerçekten istediğiniz şeye karşı okur ve buna ilişkin bir dizi evet/hayır sorusunu tek bir hızlı istekte yanıtlar. + +Jev uç noktanız ve anahtarınız yapılandırıldığında, Failproof AI her araç çağrısı hakkında Jev'e regex ilkeleri **yerine değil** yanında sorar: + +- Bir **sabit** ilkenin reddi nihai bir karardır. Jev bunu iptal edemez. Her ilke açıkça incelenebilir olarak işaretlenmedikçe ve bunu kapsayan Jev denetimlerini adlandırmadıkça sabit kabul edilir; bu nedenle bir özel, paket veya Bulut ilkesi hiçbir şey söylemeyen sabit ilke ve her zaman açık olan öz-koruma koruması her zaman sağlamdır. +- **İncelenebilir** bir ilkenin reddi iptal edilebilir, ancak yalnızca Jev'e o ilkenin kapsadığı tam endişe hakkında sorulduğunda ve "burada hiçbir şey yok" veya "kullanıcı bunu istedi" yanıtını verdiğinde. Endişeyi gerçek bulan ve kullanıcının çağrıyı istemediği bir denetim reddi tutar — kendi kararı yalnızca bir uyarı olsa bile, çünkü bir araç çağrısından önce bir uyarı aracıyı durdurmaz. Ve o denetim reddedebilen bir denetim olduğunda (gizli dil sızdırması, kimlik bilgisi sızdırması, yıkıcı silme, …), o çağrıda hiçbir şey iptal edilmez. +- Bir engel, çağrı sizin verdiğiniz görevin bir adımı olduğunda ve daha ileri gitmediğinde hala **uyarıya** dönüştürülebilir: Jev kendi reddi bir uyarıya yumuşatır ve bu uyarı — çağrının gerçekte neyin yanlış olduğunu adlandıran — ilkenin engelini değiştirir. +- Jev ayrıca regex'in tanımladığı zarar için kendi başına uyarı veya reddi yapabilir. +- Jev yanıt veremezse (zaman aşımı, hız sınırı, sunucu hatası, kredi yok, beklenmeyen model sürümü), bu çağrı regex sonucunu alır, tam olarak Jev olmaksızın olduğu gibi. +- Jev bir çağrıyı ilkelerinizin tek başına yapabileceğinden daha izin verici hale getiremez; bunun yanı sıra tüm çağrıyı okudu ve tam endişe hakkında soruldu. Bundan daha az bir şey — tamamı gönderilemeyecek kadar büyük bir çağrı, şüpheli bir enjeksiyon — izinleri geri çeker ve her reddi tutar. + + +Jev yapılandırması olmaksızın hiçbir şey değişmez: hook'lar regex ilkelerini her zaman yaptıkları gibi çalıştırır. Yapılandırma tüm katılımcı seçim mekanizmasıdır. + + + +FailproofAI Bulut'unda mı? Kendi anahtarınıza ihtiyacınız yoktur: `jev:evaluate` taşıyan bir anahtarla bağlanan makine, kuruluşunuzun planında Jev'i kullanabilir. Bkz. [FailproofAI Bulut üzerinden Jev](/tr/reference/jev-cloud). + + +## Başlamadan önce + +**failproofai 1.0.8-beta.0 veya sonraki bir sürümü** yükleyin ve hook'larını aracınızın çalıştığı makinede bir [desteklenen koşul](/tr/reference/harnesses) ekleyin. Bu yeni bir makineyse [hızlı başlangıç](/tr/start/quickstart)'ı izleyin veya Bulut kullanmıyorsanız [yerel uygulama kurulumu](/tr/start/setup#enforce-locally) yapın. Yüklü CLI'yi `failproofai --version` ile kontrol edin. + +Aşağıdaki bir sağlayıcıdan bir API anahtarı alın veya uyumlu bir uç nokta ve anahtarını hazır bulundurun. Jev, `PreToolUse` veya `PermissionRequest` kapısında adlandırılmış araç çağrılarını inceler. Kendi kararını verebilir, ancak mevcut bir ilke reddi temizlemek ayrıca [incelenebilir](/tr/policies/authority) olarak işaretlenmiş yüklü bir ilke gerektirir. Sabit ilke reddleri son kalır. + +## Sağlayıcı seçin + +Jev beş rota üzerinden ulaşılabilir. Bunlardan herhangi birinin anahtarını getirin. + +| Sağlayıcı | `--provider` | Uç nokta | Varsayılan model | Notlar | +| --- | --- | --- | --- | --- | +| TypeSafe | `typesafe` | `api.typesafe.ai/v1/systemone` | `jev-1.13.0` | Tam sürüm sabitleme. | +| OpenRouter | `openrouter` | `openrouter.ai/api/v1/systemone` | `typesafe/jev-1.13` | İstekler yalnızca sıfır veri saklama uç noktalarına yönlendirilir ve başka bir sağlayıcıya geri dönüş yoktur. `typesafe/jev-1.13-20260917` gibi tarihli bir sürüm bildirir. | +| Vercel AI Gateway | `vercel` | `ai-gateway.vercel.sh/typesafe/v1/systemone` | `typesafe-ai/jev` | Jev'i yalnızca bir takma ad ile adlandırır; bu nedenle yanıt veren sürüm doğrulanmamış olarak kaydedilir. | +| Cloudflare Workers AI | `cloudflare` | `api.cloudflare.com/client/v4/accounts//ai/run` | `typesafe/jev` | `--account-id` gerektirir. HTTP 429 öncesinde saniyede yaklaşık altı çağrı ölçülmüştür. | +| Kendi uç noktanız | `custom` | `/systemone` | `jev-1.13.0` | TypeSafe'in istek gövdesini kabul eden ve hangi modelin yanıt verdiğini bildiren herhangi bir uç nokta. Yalnızca `https`; düz `http://localhost` yalnızca gözlem modunda kabul edilir. | + + +Vercel'in kendi getir-kendi-anahtarı özelliği ile başarısız bir istek Vercel'in kimlik bilgileriyle sessizce yeniden denenir. Her çağrının sizin TypeSafe hesabınız tarafından faturalandırılması ve görülmesi gerekiyorsa, TypeSafe'i doğrudan kullanın. + + +## Kurulumu yapın + +Bir komut, uç nokta ve anahtar. Mevcut ilkeler çağrılara karar verirken Jev'in kararlarını inceleyebilmek için `observe` modunda başlayın: + +```bash +failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key +``` + +### URL sağlayıcıyı seçer + +Sağlayıcıyı adlandırmanız gerekmez: URL'nin **ana bilgisayarı** hangisi olduğunu gösterir. + +| URL ana bilgisayarı | Sağlayıcı | Ayrıca gerekli | +| --- | --- | --- | +| `api.typesafe.ai` | `typesafe` | — | +| `openrouter.ai` | `openrouter` | — | +| `ai-gateway.vercel.sh` | `vercel` | — | +| `api.cloudflare.com` | `cloudflare` | `--account-id <32-hex-account-id>` | +| diğer herhangi bir ana bilgisayar | `custom` | — verdiğiniz URL temel URL'dir | + +Bundan üç şey kaynaklanır: + +- **Sağlayıcının kendi API'sini yazan bir URL hiçbir geçersiz kılmayı yazmaz.** `--url https://api.typesafe.ai/v1` tam olarak `--provider typesafe` yapacağı yapılandırmayı üretir. Bilinen bir sağlayıcı üzerinde farklı bir yol veya ana bilgisayar verin ve temel URL olarak saklanır, `--base-url` yapacağı gibi. +- **`--provider` hala çıkarsamıyı geçersiz kılar**, bu, kendi ana bilgisayarınızdan bir sağlayıcının API'sini kullanan bir vekili nasıl ulaşacağınızdır: `--url https://jev-proxy.internal/v1 --provider typesafe`. +- **Ana bilgisayarla çelişen bir `--provider` reddedilir**, tahmin edilmez. `--provider openrouter --url https://api.typesafe.ai/v1` hiçbir şey yazmaz ve nedenini söyler: iki yazım, anahtarınızın nereye gönderileceği konusunda anlaşmazlık içindedir. Aynı çift `jev setup --base-url` ve panodan Jev ayarlarından reddedilir. (`--provider custom` bir çelişki değildir — "bu URL'yi kendisi olarak değerlendir" anlamına gelir — Cloudflare'in ana bilgisayarında hariç, onun hesap başına uç noktasına özel bir rota ulaşamaz.) + +`--url` yapılandırma dosyasında `baseUrl` ile tam olarak doğrulanır ve aynı sözcüklerle reddedilir: `https` veya yalnızca gözlem modunda düz `http://localhost`. + +### Anahtar + +`--key-stdin` ile boru aracılığıyla aktarın veya komutu bir terminalde maskelenmiş bir istemde anahtarı yapıştırın ve çalıştırın. Her iki durumda da doğrudan yapılandırma dosyasına gider ve asla geri yazdırılmaz. + + + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key + ``` + + + ```bash + failproofai jev --url https://openrouter.ai/api/v1 --mode observe --key-stdin < ~/openrouter.key + ``` + + + ```bash + failproofai jev --url https://ai-gateway.vercel.sh/typesafe/v1 --mode observe \ + --key-stdin < ~/vercel-gateway.key + ``` + + + ```bash + failproofai jev --url https://api.cloudflare.com/client/v4 \ + --account-id <32-hex-account-id> --mode observe --key-stdin < ~/cloudflare.token + ``` + + + ```bash + failproofai jev --url https://jev.internal.example.com/v1 --mode observe --key-stdin < ~/jev.key + ``` + + + +`failproofai jev setup` aynı bayrakları alır ve hepsi için uzun yazımdır: `setup --provider ` URL'yi adlandırmayı tercih ettiğiniz yerde sağlayıcıyı adlandırırsınız. + +### `--token` ve maliyeti nedir + +`--token ` anahtarı komut satırına koyar; bu bir makineyi yapılandırmanın en hızlı yolu ve anahtarı yapılandırma dosyasından başka herhangi bir yerde bırakmayan tek yazımdır: + +```bash +failproofai jev --url https://openrouter.ai/api/v1 --token +``` + + +Bir komut satırı argümanı daha sonra kabuk geçmişi dosyanızdadır ve komut çalışırken işlem listesindedir — sizin olarak çalışan her şey tarafından `/proc` tarafından okunabilir. `setup` her zaman `--token` kullanıldığında bunu söyler. Makineyi paylaştığınız bir yerde, kaydedilen bir oturumda veya geçmiş dosyası senkronize edilen herhangi bir yerde `--key-stdin` tercih edin; bu şekilde geçtiğiniz bir anahtarı, önemli olursa döndürün. + + +`--token`, `--key-stdin` ve `--key-from-env` birbirini dışlar: birini verin. + +Daha sonra anahtarı, uç noktayı ve hangi Jev'in yanıt verdiğini kontrol etmek için küçük bir canlı istek gönderin: + +```bash +failproofai jev test +``` + +```text + failproofai jev test ok · 523 ms + + provider cloudflare + model asked typesafe/jev + answered by jev-1.13.0 (Jev 1.13 family — verified) + latency 523 ms — within the 3000 ms timeout +``` + +`jev test` çıkış 1 yapar ve başlığında bunu söylediğinde yanıt zaman aşımından sonra gelirse (her hook'u regex'e geri dönerdi `timeout` olarak) veya denetim sorusunun yanlış yanıtını verir. + +Hook'lar yapılandırmayı her araç çağrısında okurlar, böylece sonraki çağrıdan uygulanır. Daemon ile veya daemon olmadan yeniden başlatılacak hiçbir şey yoktur. + +## Neyi yaptığını kontrol edin + +```bash +failproofai jev status +failproofai jev status --json +``` + +`status` sağlayıcı, uç nokta, model, mod, yapılandırma dosyası ve izinlerini gösterir ve asla anahtarı göstermez. Altında son etkinliği özetler: Jev kaç çağrı değerlendirdi, ne sıklıkta regex'e geri döndü ve neden, gecikme süresi ve hangi incelenebilir ilkeleri temizledi. + +## Gerçek bir çağrıyı doğrulayın + +Bağlantılı aracıda yeni bir oturum başlatın. Dosya okuma aracını `README.md` üzerinde kullanması ve başlığını bildirmesi için sorun. Oturumun o araç çağrısını içerdiğini onaylayın, sonra tekrar `failproofai jev status` çalıştırın: son değerlendirilen çağrı sayısı artmalıdır. [Yerel pano](/tr/reference/local-dashboard#review-policy-activity)'da **İlkeler → Etkinlik** sekmesini açın ve çağrının Jev kararını ve modunu inceleyin. Gözlem modunda, ilke sonucu hala çağrıya karar verir. İncelenebilir bir ilke eşleştiğinde ve Jev adlandırılan tüm denetimleri temizlemişse bir temizleme görüntülenir; sıradan bir okuma temizlenecek bir ilkeye sahip olmayabilir. + +## Gözlem modu + +`enforce` varsayılandır. Jev'i Jev'i herhangi bir karar değiştirmesine izin vermeden izlemek için `observe`'e geçin: Jev hala sorulur ve kararları kaydedilir, ancak uygulanan regex sonucudur. + +```bash +failproofai jev setup --mode observe +failproofai jev setup --mode enforce +failproofai jev setup --mode off +``` + +`off` yapılandırmayı tutar — uç noktası ve anahtarı — ve Jev'i sorulamaktan durdurur: hook'lar regex ilkelerini yapılandırma olmaksızın tam olarak çalıştırır ve `failproofai jev status` "kapalı (kapatıldı)" söyler. `--mode observe` veya `--mode enforce` ile geri geçin. + +Aynı sağlayıcı için `setup`'ı yeniden çalıştırmak saklanan anahtarı tutar; böylece bir mod anahtarı bir bayraktır. Sağlayıcı değiştirme baştan başlar ve o sağlayıcının anahtarını ister. `--base-url`'yi istekleri farklı bir ana bilgisayara taşıyan URL ile yapan durum da öyle: saklanan anahtar yalnızca verilen ana bilgisayara veya sağlayıcısının kendi API'sine gönderilir. + +## Yapılandırma dosyası + +Her şey tek dosyada `~/.failproofai/jev.json` yaşar, `setup` tarafından yazılır: + +```json +{ + "provider": "cloudflare", + "apiKey": "", + "accountId": "<32-hex-account-id>", + "mode": "enforce", + "timeoutMs": 3000 +} +``` + +| Alan | Anlam | +| --- | --- | +| `provider` | `typesafe`, `openrouter`, `vercel`, `cloudflare` veya `custom` — veya `failproofai`, bunun anahtarı bu dosya yerine FailproofAI Bulut bağlantısından gelir ([FailproofAI Bulut üzerinden Jev](/tr/reference/jev-cloud) bakın). | +| `apiKey` | `Authorization: Bearer ` olarak gönderilir. | +| `baseUrl` | `custom` için gerekli; aksi takdirde sağlayıcının API tabanını değiştirir. `https` olmalıdır. Düz `http`, gözlem modunda yalnızca `localhost`'a kabul edilir: yerel bir bağlantı hiçbir şeyi doğrulamaz; bu nedenle vekil indiğinde makine üzerindeki herhangi bir işlem (değerlendirilen aracı da dahil olmak üzere) yerine cevap verebilir. | +| `accountId` | Yalnızca Cloudflare: 32 küçük heksadesimal karakter. | +| `model` | Sağlayıcının varsayılan model kimliğini değiştirir. Sürümlendirilmiş bir kimlik Jev 1.13'ü adlandırmalıdır. API anahtarı gibi görünen bir değer reddedilir (ve geri tekrarlanmaz), bu nedenle `--model` içine yapıştırılan bir anahtar asla model olarak depolanmaz veya gönderilmez. | +| `timeoutMs` | Bir araç çağrısı regex sonucunu kullanmadan önce Jev'i bekleyin. 100–10000, varsayılan 3000. | +| `mode` | `enforce` (varsayılan), `observe` veya `off` (yapılandırmayı tut, Jev'i çalıştırma). | + +Üç kural bunu korur: + +- **Yalnızca sahip.** `0600` izniyle yazılır. Başka bir kullanıcı veya grup tarafından okunabilen veya yazılabilen bir kopya **reddedilir** ve hook'lar `chmod 600 ~/.failproofai/jev.json` veya tekrar `setup` çalıştırılana kadar regex'e geri döner. Dizin de kontrol edilir: `~/.failproofai` başka kimse tarafından **yazılabilir** olmamalıdır, çünkü orada yazabilen kimse kendi izinleri ne olursa olsun dosyayı değiştirebilir. `setup` bulursa bu yazı bitlerini kaldırır. `failproofai jev status` yapılandırmanın reddedildiğini ve dosyanın adlandırdığı uç noktayı gösterir: başka biri bunu değiştirmiş olabilir; `chmod` öncesinde sizin olduğunu kontrol edin. Böyle bir dosyada `setup` yeniden çalıştırmak, saklanan anahtarı yalnızca sağlayıcının kendi API'sine taşır; adlandırdığı başka bir uç nokta anahtarı tekrar gerektirir (`--key-stdin`) veya `--base-url default` istekleri sağlayıcıya geri göndermek için. +- **Yalnızca genel.** Depo Jev'i açamaz, başka bir uç noktaya işaret edemez veya modunu seçemez: bir proje içindeki `.failproofai/jev.json` yok sayılır ve sağlayıcı, URL, model ve hesap kimliği yalnızca bu dosyadan okunur — ortamdan asla okunmaz, depo aracı ayarları ayarlayabilir. (`FAILPROOFAI_HOME` geçici bir çözüm değildir: tüm failproofai dizinini, ilkelerinizi de dahil olmak üzere taşır, sadece Jev'i yönlendirmek yerine.) +- **Anahtar tek başına ortamdan gelebilir.** Dosyanın `apiKey`'i yoksa, `FAILPROOFAI_JEV_API_KEY` o oturum için bunu sağlar (`setup --key-from-env` böyle bir dosya yazar). Dosyanın tuttuğu bir anahtarı asla değiştirmez ve Jev'i anahtar olmadan açamaz. Değişken ayarlanmadığında, Jev o shell için basitçe kapalıdır: `failproofai jev status` bunu söyler, çıkış 0 yapar ve yapılandırmayı yalnız bırakır (`status --json` `"reason": "no-env-key"` ile `"status": "key-missing"` bildirir). `failproofaid` daemon kabuk ortamınızı görmez; bu nedenle `failproofai config` ile ayarlanmış bir makinede anahtarı dosyada tutun. + +## Hangi Jev yanıt verir + +Failproof AI'nin karar eşikleri Jev 1.13 üzerine kalibre edildi; bu nedenle bir yanıt yalnızca o ailadan geldiğinde kullanılır: `jev-1.13.x` veya OpenRouter'ın `typesafe/jev-1.13-`. Sağlayıcı Jev'i yalnızca bir takma ad ile adlandırdığında ve sürüm bildirmedikçe (Vercel ve Cloudflare bazı durumlarda), yanıt kullanılır ve doğrulanmamış olarak kaydedilir. Bir `custom` uç noktası yanıt veren modeli bildirmelidir; tek istisna, yapılandırdığınız sürümsüz `--model` adı, geri yansıtıldığında, aynı şekilde doğrulanmamış olarak kaydedilir. 1.13 dışında başka bir sürüm bildiren veya hiç sürüm bildirmeyen `custom` yanıt kullanılmaz: bu çağrı `model-mismatch` nedeniyle regex'e geri döner. + +## Jev yanıt veremediğinde + +Bunlardan her biri o çağrı için regex sonucuna geri döner ve `failproofai jev status` toplayan nedeniyle kaydedilir: + +| Neden | Sebep | +| --- | --- | +| `timeout` | `timeoutMs` içinde yanıt yok. | +| `http-429` | Sağlayıcı anahtarı oran sınırlandırdı. | +| `rate-limited` | Failproof AI'nin kendi sınırlayıcısı çağrıyı gönderilmeden tuttu: saniyede 5 istek, en fazla 5'e kadar patlamalar ve sağlayıcı `429` yanıtı verdikten sonra bir an yoktur. Sağlayıcı değil. | +| `http-500`, `http-502`, `http-503`, … | Sağlayıcıda sunucu hatası. Tam durum kaydedilir. | +| `out-of-credits` | HTTP 402: sağlayıcı hesabında kredi yok. | +| `provider-refused` | Cloudflare'den HTTP 402 ve "Model execution failed (Payment error)": sağlayıcı bu istekte modeli çalıştırmayı reddetti. Genellikle faturalandırma değil; kredi yüklemek bunu hareket ettirmez. | +| `http-401`, `http-403` | Anahtar reddedildi. | +| `http-404` | `/systemone`'de hiçbir şey sunulmuyor; temel URL yanlış — `/systemone` buna eklenir ve her sağlayıcı bunu sürüm kökünde sunar. `failproofai jev models` uç noktanın ne sunduğunu gösterir. | +| `network` | Uç noktaya ulaşılamadı. | +| `http-301`, `http-302`, `http-307`, `http-308` | Uç nokta bir yeniden yönlendirme ile yanıt verdi. Yeniden yönlendirmeler asla izlenmez; bu nedenle yanıt sadece yapılandırmanızın URL'sinden gelir; son URL'ye `--base-url` ayarlayın. | +| `malformed` | Uç nokta yanıt verdi, ancak Jev yanıtı değil — JSON olmayan bir gövde veya içinde hiç yanıt yok. | +| `cloudflare-error`, `cloudflare-incomplete` | Cloudflare'in zarfı bir başarısızlık veya tamamlanmamış bir iş bildirdi. | +| `model-mismatch` | 1.13 dışında bir Jev sürümü yanıt verdi veya `custom` uç nokta hangi modelin yanıt verdiğini söylemedi. | +| `request-cut` | **Bir kesinti değil.** Jev yanıt verdi; yalnızca çağrının bir bölümü gösterildi; bu nedenle yanıtı hiçbir şey temizlemedi. Bkz. [Jev yanıt verdi, ancak tüm çağrıya değil](#when-jev-answered-but-not-on-the-whole-call). | + +`failproofai jev status` `upstream-error` (yanıt sağlayıcının kendi hatasını taşıdı) veya `config` gibi bazı daha nadir nedenler de gösterebilir ve adlanamadığı herhangi bir nedeni `other` olarak toplar. + +`request-cut` bu tablodadır çünkü `failproofai jev status` bunu geri kalanlar ile toplar ve çünkü o da her reddi tutmaz. Burada sağlayıcınız hakkında hiçbir şey söylemeyen tek nedendir: istek ulaştı ve Jev yanıt verdi. Yukarıdaki her satırdan farklı olarak, bu yanıt hala sayılır — Jev'in kendi reddi veya uyarısı, regex sonucu yerine reddedilen regex sonucu yerine uygulanır. Bu nedenle bir çalışma, çağrıların tamamı gönderilemeyecek kadar büyük bir değerlendirici ulaştığını, uç noktanız bozuk olduğunu değil anlamına gelir ve kredi yüklemek veya URL değiştirmek sayıyı hareket ettirmez. + +## Jev yanıt verdi, ancak tüm çağrıya değil + +Daha iki şey olabilir; hiçbiri Jev'in yanıt vermediğini söylemez. Her ikisi de çağrının ne kadarının veya konuşmanın ne kadarının bir istekten geçtiğini ele alır. + +**Çağrının bir bölümü sığmadı.** Bir araç çağrısı sabit bir bütçe içinde gönderilir ve eğer bir çok büyükse — çok büyük `Write`, devasa MCP gövdesi, büyüke doldurulmuş komut — sığan şey ile gönderilir. Jev hala yanıt verir ve yanıtı hala sayılır: kendi reddi veya uyarısı normal şekilde uygulanır. Yapamadığı şey **temizlemektir**, çünkü kısmi bir çağrı hakkında verilen bir karar çağrı hakkında bir karardan değildir. Bu nedenle her ilke reddi tutulur ve çağrı `request-cut` nedeniyle bir geri dönüş olarak kaydedilir, `failproofai jev status` yukarıdaki nedenler ile toplar. Bunu size veren kural: bir çağrıyı daha büyük hale getirmek temizlemelerin maliyeti olabilir ve hiçbir zaman bir tane satın alamaz. + +**Bir ileti sığmadı.** Yapıştırdığınız uzun bir istem, aracının son iletisi veya bu değerlendirici'nin kendi mağazası daha önce capping yapmış bir istem. **Hiçbir şey değişmez**: çağrı tam olarak başka herhangi bir gibi değerlendirilir, temizlenir ve kaydedilir ve `request-cut` nedeniyle bir geri dönüş olarak sayılmaz. Yazıldığınız şeyin uzunluğu asla karar vermez ve bir kesinti izin hiç yaratmaz: bir istem daha önce capping geldiğinde, "siz bunu istememediniz" olmaktan çıkar; yerine birinden çekilen bir sonuç olmaktan ziyade hiç çekilemiyor gibi olur. + +İkisinin arası kimin yazıyı yazdığı. Çağrı aracıdandır ve uzunluğunun şiddeti çıkarmasına izin veren bir kural, aracının kullanabileceği bir kuraldır; isteminiz sizindir ve uzunluğunu bir sinyal olarak değerlendirmek, yalnızca bir spec veya yığın izinin yapıştırılması cezalandırır. + +## Makineden ne çıkar + +Jev değerlendirdiği her araç çağrısı için, sağlayıcınıza bir istek gider; şunları taşır: + +- araç çağrısı, API anahtarları, taşıyıcı belirteçleri ve `KEY=` atamalarıyla gizlilikler redakte edilmiş; +- yazdığınız son istekler, aracının koşu eklediği metin kaldırılmış; +- son istemden önceki aracının son iletisi, aracı tarafından yazıldığı etiketlendi; +- yerel olarak hesaplanan gerçekler, örneğin bir yolun proje içinde olup olmadığı — oturum ilk gözden geçirilmiş çağrısında olduğu — [oturum için sabitlenmiş](/tr/reference/jev-intent#the-project-root) — ve geçerli git dalı. + +Yalnızca yapılandırmanızdaki uç noktaya gider ve anahtarınız altında. + +## Kapatın + +```bash +failproofai jev remove +``` + +Bu `~/.failproofai/jev.json` siler. Sonraki araç çağrısından, hook'lar regex ilkelerini tam olarak daha önce olduğu gibi çalıştırır. `~/.failproofai/state/semantic/` altında oturum başına depolar (kaydedilen istekler `sessions/` tarafından, proje kökleri `roots/` tarafından) yerinde bırakılır ve yaşlandırılır. Jev'i sorgulamayı durdur ama yapılandırmayı tut istersen `failproofai jev setup --mode off` yerine kullan. + +## Komut referansı + +| Komut | Sonuç | +| --- | --- | +| `failproofai jev --url --key-stdin` | Bir komutta yapılandırın; sağlayıcı URL'nin ana bilgisayarından gelir | +| `failproofai jev --url --token ` | Aynı, anahtarla komut satırında — geçmişi ve işlem listesi görür | +| `failproofai jev setup --provider --key-stdin` | Stdin üzerinde boru ile yazıyı yapılandırmayı yazın | +| `failproofai jev setup --provider ` | Aynı, maskelenmiş istemde anahtar istediğinde | +| `failproofai jev setup --key-from-env` | Anahtar saklamayın; oturum başına `FAILPROOFAI_JEV_API_KEY` oku | +| `failproofai jev setup --mode observe` | Mod değiştir (`enforce`, `observe` veya `off`), saklanan anahtarı tuttuğunde | +| `failproofai jev setup --model ` / `--base-url ` | Modeli veya API tabanını geçersiz kıl; `default` geçersiz kılmayı temizler | +| `failproofai jev setup --timeout-ms ` | Çağrı başına bütçeyi değiştir | +| `failproofai jev status [--json]` | Yapılandırma, izinler ve son etkinlik; asla anahtar | +| `failproofai jev test [--json]` | Bir canlı istek: gecikme ve yanıt veren sürüm | +| `failproofai jev models [--provider ] [--url ] [--json]` | Uç noktanın `/models` bildirdiği model kimlikleri, yapılandırılmış olanı işaretleriyle | +| `failproofai jev remove` | Yapılandırmayı sil; Jev kapalı | \ No newline at end of file diff --git a/docs/tr/reference/jev.mdx b/docs/tr/reference/jev.mdx new file mode 100644 index 000000000..ad813cdc8 --- /dev/null +++ b/docs/tr/reference/jev.mdx @@ -0,0 +1,22 @@ +--- +title: "Jev entegrasyon referansı" +description: "Jev için yapılandırma, sağlayıcılar, anahtarlar, istek verileri ve hata davranışı." +icon: "braces" +--- + +Jev, Failproof AI'da iki kullanım alanına sahiptir: + +| Kullanım | Ne zaman çalışır | Ne döndürür | Buradan başlayın | +| --- | --- | --- | --- | +| Oturum değerlendirmesi | Bir oturum bittikten sonra | Sabit yanıtlı bir soru için puan | [Jev değerlendirmeleri](/tr/evaluations/jev) | +| Araç çağrısı politikası incelemesi | Korunan bir araç çağrısı çalışmadan önce | Yüklü politikalarla birlikte bir karar | [Jev politikaları](/tr/policies/jev) | + +## Referans sayfaları + +| Konu | Ayrıntılar | +| --- | --- | +| [Değerlendirme soruları](/tr/reference/jev-evaluations) | Boolean ve sıralanmış puan kriterleri, sonuçlar, limitler ve geriye dönük doldurma. | +| [Sağlayıcı karşılaştırması ve kendi anahtarını ayarlama](/tr/reference/jev-providers) | TypeSafe, OpenRouter, Vercel, Cloudflare ve özel uç noktalar; URL çıkarımı, model kimlikleri, `jev.json`, modlar ve geri dönüş kodları. | +| [FailproofAI Cloud rotası](/tr/reference/jev-cloud) | Makine anahtarı izinleri, otomatik observe kurulumu, kullanım limitleri, bağlantı durumu ve veri işleme. | + +Yerel CLI komutları [Failproof AI CLI referansında](/tr/reference/failproof-cli) listelenmiştir. [Yerel kontrol paneli referansı](/tr/reference/local-dashboard#set-up-jev) Jev ayarlarını ve aktivite görünümünü açıklar. \ No newline at end of file diff --git a/docs/tr/sessions/sentiment.mdx b/docs/tr/sessions/sentiment.mdx new file mode 100644 index 000000000..1a071daaa --- /dev/null +++ b/docs/tr/sessions/sentiment.mdx @@ -0,0 +1,43 @@ +--- +title: "Duygu analizi" +description: "Jev duygu puanlarıyla hayal kırıklığına uğramış, kafası karışmış ve düzeltici mesajları bulun." +icon: "smile" +--- + +Jev, kişinin ajanlarınıza gönderdiği her mesajı dört duygu için 0 ile 100 arasında puanlandırır — **kızgın**, **hayal kırıklığına uğramış**, **mutlu** ve **kafası karışmış** — ve ajanın durumu hakkında üç sinyal: + +- **Düzeltici**: kişi ajanın bir şeyler yanlış yaptığını söylüyor. +- **Çözüldü**: kişi ajanın sorunu çözdüğünü doğruluyor. +- **Şüpheli**: kişi ajanın cevabının doğru olup olmadığını veya işi gerçekten yapıp yapmadığını sorguluyor. + +Duygu analizini, insanların sabrının tükendiği konuşmaları, sıkça düzeltilen ajanları ve iyi sonuç veren yanıtları bulmak için kullanın. Bu, yerleşik Jev puanlamadır; bir değerlendirme yazmanız gerekmez. Kendi sabit cevap sorularınız için, [bir Jev değerlendirmesi oluşturun](/tr/evaluations/jev). + + + Duygu, bir yönetici organizasyon için açana kadar kapalıdır. Jev mesaj başına bir puanlama isteği yapar ve söz konusu mesajı alır, ardından ajan yanıtı gelir. Puanlama, kuruluşunuzun model bütçesini kullanır. + + +## Açın + +1. **Yönetim → Ayarlar**'a gidin. +2. **İnsan girdisi duygusu** altında, bunu **açın** ve kaydedin. + +Son günün mesajları önce puanlandırılır. Bundan sonra, yeni mesajlar geldikten bir iki dakika içinde puanlandırılır. + +## İncelemek için bir konuşma bulun + +**Gözle → Duygu** seçeneğini açın. Zaman, ortam, ajan veya oturum kimliğine göre filtreleyin. Başlık mesaj ve oturum sayılarını, kaç mesajın **işaretlendiği** gösterir ve en üst sinyali adlandırır. Kızgın, hayal kırıklığına uğramış, düzeltici, kafası karışmış veya şüpheli puan 100 üzerinden 35'e ulaştığında bir mesaj işaretlenir. + +![Duygu panosu mesaj ve oturum sayılarını, işaretli mesajları ve zaman içinde Jev puanlarını gösteriyor.](/images/dashboard/sentiment-overview.png) + +Sinyalleri karşılaştırmak için **Zaman içinde puan** kullanın. Gösterilecek puanları seçin, sonra bu zaman demetinin mesajlarını görmek için bir nokta seçin. **Ajan başına** tablosu bir sinyalin nerede yoğunlaştığını gösterir. **Mesajlar**'da, en güçlü negatif puana göre sıralayın veya tek bir puan seçin. Başarısızlığa karar vermeden önce çevreleyen konuşmayı okumak için bir mesajı oturumunda açın. + +![Duygu mesaj listesi en güçlü negatif puana göre sıralanmış, her kaynak oturumuna bir bağlantı ile.](/images/dashboard/sentiment-messages.png) + +## Hangi mesajlar puanlandırılır + +Yalnızca bir kişinin yazdığı mesajlar: + +- Özel ajanlarınızın SDK ile insan girdisi olarak kaydettiği mesajlar. +- Claude Code, Codex, OpenCode, pi, Hermes ve OpenClaw'a yazılan istemler; oturum dökümü gönderildiğinde (varsayılan). Planlanmış işler, enjekte edilen talimatlar, alt ajan devralmalar ve ajanın kendi çalışma zamanının yazdığı diğer metinler puanlanmaz. Etkileşimli olmayan çalıştırmalar da puanlanmaz: `claude -p`, `codex exec` ve `hermes -z` — bir komut dosyası bu istemleri yazıyor, bir kişi değil. + +Puanlama kişinin kendi sözlerini değerlendirir. "Düzelt" gibi kısa, sert bir talimat öfke olarak sayılmaz ve soru sormak da kafa karışıklığı olarak sayılmaz. Yeni bir istek düzeltme değildir ve kendi başında teşekkürler çözüldü olarak sayılmaz. \ No newline at end of file diff --git a/docs/tr/start/use-jev.mdx b/docs/tr/start/use-jev.mdx new file mode 100644 index 000000000..fd4f4f1e5 --- /dev/null +++ b/docs/tr/start/use-jev.mdx @@ -0,0 +1,63 @@ +--- +title: "Jev Kullan" +description: "Tamamlanmış oturumlar için Jev değerlendirmeleri ayarlayın veya canlı araç çağrısı incelemesi için Jev politikaları kurun." +icon: "sparkles" +--- + +Jev, bir aracı çalışmasında iki noktada yardımcı olur: tamamlanmış bir oturumu bilinen yanıtlara karşı puanlandırın veya bir araç çağrısını aracıdan istediğiniz şey bağlamında inceleyin. + + + + Jev eval'ını, tamamlanmış bir oturumun "Müşteri iade talep etti mi? Evet veya hayır cevap verin." gibi birkaç bilinen yanıta sahip bir soruya karşı puanlanabileceği durumlarda kullanın. Oturumlar arasında desenleri bulmanıza yardımcı olur. + + ## Eval oluşturun + + Cloud panosunda, **Analyze → eval authoring → new eval** öğesini açın. Tek bir sabit cevaplı soru girin, **draft** öğesini seçin ve sınıflandırıcı puan seçip seçmediğini kontrol edin. Bunu gerçek oturumlarda [test edin](/tr/evaluations/test), ardından yayınlayın. + + ![Bir soru açıkladığınız, taslağı incelediğiniz ve yayınladığınız paylaşılan eval yazma formu. Bu ekran görüntüsü bir kod taslağı göstermektedir; Jev için sabit cevaplı bir soru kullanın.](/images/dashboard/eval-authoring-draft.png) + + ## Puanları okuyun + + Yeni bir oturum tamamlandıktan sonra, **Observe → Evaluations** öğesini açın veya Cloud CLI'yi kullanın: + + ```bash + fp evals --since 7d + fp evals --aggregate --since 7d + ``` + + CLI puanları okur; bir Jev eval oluşturmak şu anda panoyu kullanır. Soru türleri ve örnekler için [Jev evaluations](/tr/evaluations/jev) öğesine bakın. + + + Bir dize eşleştirme politikasının bir araç çağrısının güvenli olup olmadığına karar vermek için isteğinizin bağlamına ihtiyacı olduğunda Jev politika incelemesini kullanın. **observe** modunda başlayın, böylece kurulu politikalarınız yine de her çağrıya karar verirken Jev'in yanıtlarını inceleyebilirsiniz. + + Jev'in kontrolleri bir paketten gelir; Failproof AI hiçbirini göndermez. Bunları yükleyene kadar, Jev yapılandırılmış olsa da hiçbir şey sormaz: + + ```bash + failproofai policies add FailproofAI/jev-policies + ``` + + ## Cloud Jev'i kurun + + Cloud panosunda, **Administration → Keys** öğesini açın ve **machine** ön ayarıyla bir anahtar oluşturun. Bunu [quickstart](/tr/start/quickstart) öğesinde gösterildiği gibi `failproofai config` ile kullanın. Mevcut bir Jev yapılandırması olmayan bir makinede, bu Cloud Jev'i observe modunda etkinleştirir. Bağlantıyı kontrol edin: + + ```bash + failproofai jev status + failproofai jev test + ``` + + ## Kendi uç noktanızı kullanın + + Yerel panoda, **Settings → Jev** öğesini açın. Sağlayıcıyı seçin, belirtecini yapıştırın, **observe** öğesini seçin ve Jev'i açın. + + ![Bir sağlayıcı, belirteç alanı ve seçili observe moduna sahip yerel Jev ayarları paneli.](/images/dashboard/jev-settings.png) + + Veya uç noktanızı bir terminalden yapılandırın ve test edin: + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key + failproofai jev test + ``` + + Hooked bir aracıdan `README.md` dosyasında dosya okuma aracını kullanmasını isteyin. Bu araç çağrısının oturumda göründüğünü doğrulayın, ardından yerel panoda **Policies → Activity** öğesinin altında bunu inceleyin. Observe sonuçları doğru göründükten sonra, [Jev policies](/tr/policies/jev) ne zaman uygulanacağını açıklar. Sağlayıcı ayrıntıları ve yapılandırma için [integration reference](/tr/reference/jev) öğesine bakın. + + \ No newline at end of file diff --git a/docs/vi/evaluations/jev.mdx b/docs/vi/evaluations/jev.mdx new file mode 100644 index 000000000..0b94298b5 --- /dev/null +++ b/docs/vi/evaluations/jev.mdx @@ -0,0 +1,28 @@ +--- +title: "Jev evaluations" +description: "Sử dụng Jev để chấm điểm một phiên làm việc đã hoàn thành dựa trên một câu hỏi có câu trả lời đã biết." +icon: "list-checks" +--- + +Một Jev evaluation đọc một **phiên làm việc đã hoàn thành** và cho một điểm từ 0 đến 1. Sử dụng nó khi câu trả lời đã biết trước, chẳng hạn như "Khách hàng có thể hiện sự khẩn cấp không?" hoặc "Khách hàng bực bội đến mức nào?" Nó giúp bạn tìm ra các mẫu hình trên nhiều lần chạy; nó không dừng lệnh gọi công cụ. Để đưa ra quyết định **trước khi** một công cụ chạy, sử dụng [Jev policies](/vi/policies/jev). + +## Tạo một trong bảng điều khiển + +1. Mở **Analyze → eval authoring** và chọn **new eval**. +2. Mô tả một câu hỏi và các câu trả lời khả thi của nó. Ví dụ: "Tác nhân có hứa hoàn tiền trước khi kiểm tra chính sách hoàn tiền không? Trả lời có hoặc không." Chọn **draft** và xem lại rằng kết quả là một điểm phân loại. +3. [Kiểm tra nó](/vi/evaluations/test) trên các phiên gần đây, sau đó [triển khai nó](/vi/evaluations/deploy). Các phiên đã hoàn thành mới sẽ được chấm điểm; [backfill](/vi/evaluations/deploy#score-sessions-you-already-have) nếu bạn cũng cần lịch sử. + +![Biểu mẫu eval authoring được chia sẻ, nơi bạn mô tả một câu hỏi có câu trả lời cố định, xem lại bản nháp và triển khai sau khi kiểm tra. Ví dụ hiển thị là một đánh giá mã; một câu hỏi Jev sử dụng cùng luồng authoring.](/images/dashboard/eval-authoring-draft.png) + +Trợ lý có thể chọn giữa mã, phân loại Jev và một [judge](/vi/evaluations/judge). Kiểm tra lựa chọn của nó trước khi triển khai. Jev cho một điểm mà không cần lý do bằng văn bản; chọn một judge khi bạn cần một giải thích. Xem [Jev evaluation reference](/vi/reference/jev-evaluations) để biết các loại câu hỏi và giới hạn điểm. + +## Đọc các điểm + +Mở **Observe → Evaluations** để biểu đồ kết quả theo tác nhân và thời gian. Từ terminal, Cloud CLI có thể đọc cùng kết quả: + +```bash +fp evals --since 7d +fp evals --aggregate --since 7d +``` + +Cloud CLI đọc kết quả; authoring và triển khai diễn ra trong bảng điều khiển. Xem [Cloud CLI reference](/vi/reference/cloud-cli#evaluations) để biết các bộ lọc. \ No newline at end of file diff --git a/docs/vi/evaluations/judge.mdx b/docs/vi/evaluations/judge.mdx new file mode 100644 index 000000000..198cce3bd --- /dev/null +++ b/docs/vi/evaluations/judge.mdx @@ -0,0 +1,91 @@ +--- +title: "Trọng tài LLM" +description: "Đánh giá các phiên làm việc theo những tiêu chí mà mã không thể đo lường — tính chính xác, tông độc, liệu agent có tuân theo chính sách hay không — bằng cách mô tả tiêu chuẩn tốt là gì và để một mô hình đọc cuộc hội thoại." +icon: "scale" +--- + +Một đánh giá Python được lưu trữ có thể đếm và so sánh: bao nhiêu lệnh gọi công cụ, bao nhiêu lỗi, phiên làm việc mất bao lâu. Nó không thể cho bạn biết liệu một câu trả lời có *chính xác*, liệu một phản hồi có thô lỗ hay không, hoặc liệu agent có kiểm tra một chính sách trước khi hành động hay không. + +Một **trọng tài LLM** có thể. Bạn mô tả tiêu chuẩn tốt bằng ngôn ngữ tự nhiên, và một mô hình đọc phiên làm việc rồi trả về điểm từ 0 đến 1 kèm theo lý do của nó. + + +Một trọng tài tốn một lệnh gọi mô hình cho mỗi phiên mà nó chạy trên, còn đánh giá mã thì không tốn gì. Chỉ sử dụng trọng tài cho những câu hỏi cần phải *hiểu rõ* cuộc hội thoại — và đặt điều kiện cho nó, để nó chỉ chạy trên những phiên mà câu hỏi thực sự liên quan. + + +## Tôi nên chọn cái nào? + +| Câu hỏi | Sử dụng | +| --- | --- | +| Nó có gọi cùng một công cụ hai lần không? | mã | +| Có bao nhiêu lỗi? | mã | +| Phiên có dưới 30 giây không? | mã | +| Khách hàng có bày tỏ sự vội vàng không? | [bộ phân loại](/vi/evaluations/jev) | +| Khách hàng bực dọc đến mức nào? | [bộ phân loại](/vi/evaluations/jev) | +| Câu trả lời có thực sự chính xác không? | **trọng tài** | +| Phản hồi có thô lỗ hoặc bất cảm không? | **trọng tài** | +| Nó có kiểm tra chính sách hoàn tiền trước khi hứa hoàn tiền không? | **trọng tài** | + +Nguyên tắc chung: **có thể đếm được → mã, câu trả lời bạn có thể liệt kê trước → [bộ phân loại](/vi/evaluations/jev), cần giải thích → trọng tài.** Trọng tài là cái viết văn bản về những gì nó thấy; hãy sử dụng nó khi con số sẽ khiến ai đó hỏi "tại sao?". + +Bạn không cần quyết định trước. Mô tả những gì bạn muốn đo lường và trợ lý sẽ chọn, sau đó cho bạn biết nó đã chọn cái nào và tại sao. Bạn có thể thay đổi nó. + +## Viết một cái + +1. Đi tới **Analyze → eval authoring** và chọn **new eval**. +2. Mô tả những gì bạn muốn đánh giá, và chọn **draft**. +3. Xem lại **criteria**, **threshold**, và **condition**, sau đó triển khai. + +### Criteria + +Một hoặc hai câu, được viết như một yêu cầu chứ không phải một câu hỏi: + +> Agent không được hứa hoặc phê duyệt hoàn tiền mà không kiểm tra chính sách hoàn tiền trước. + +Hãy cụ thể về những gì sẽ khiến nó *thất bại*. "Phản hồi có tốt không?" sẽ cho bạn một con số không có ý nghĩa gì; câu phía trên sẽ cho bạn một con số mà bạn có thể hành động dựa trên đó. + +### Threshold + +Điểm ở mức đó hoặc cao hơn để phiên vượt qua. `0.7` là một điểm khởi đầu hợp lý. Toàn bộ điểm từ 0 đến 1 luôn được lưu trữ, vì vậy ngưỡng chỉ quyết định vượt/không vượt — bạn có thể xem phân phối và điều chỉnh. + +### Condition + +Điều kiện Python giống như bất kỳ đánh giá nào khác, và nó quan trọng hơn nhiều ở đây. Nếu không có, trọng tài sẽ chạy trên **mọi** phiên trong tổ chức của bạn, với mỗi lệnh gọi mô hình: + +```python +session.count("tool_use") > 0 +``` + +```python +session.agent_id == "support-bot" and session.count("error") > 0 +``` + +Bảng điều khiển sẽ cảnh báo bạn nếu bạn triển khai một trọng tài mà không có điều kiện. Đôi khi điều này là đúng — một agent có lưu lượng thấp mà bạn muốn đánh giá đầy đủ — nhưng nó phải là một quyết định, không phải một sai sót. + +## Trọng tài thấy gì + +Cuộc hội thoại, dưới dạng các lượt, mới nhất trước nếu phiên dài: + +- người dùng nói gì +- trợ lý trả lời gì +- **mọi công cụ mà agent gọi, và lệnh gọi đó trả về gì, theo thứ tự** + +Phần cuối cùng đó là những gì khiến "nó có làm X *trước* Y không" trở thành một câu hỏi công bằng. Một lệnh gọi công cụ không thành công được hiển thị như một lỗi, vì vậy "nó có phục hồi một cách nhuyễn mịn từ một lỗi không" cũng hoạt động. + +Các phiên rất dài được cắt ngắn để vừa với ngữ cảnh của mô hình. Khi điều đó xảy ra, lý do sẽ nói rõ ràng — bạn sẽ không bao giờ thấy một phán xét được đưa ra trên một phần của phiên được trình bày như được đưa ra trên toàn bộ nó. + +## Đọc kết quả + +Một trọng tài tạo ra một **score** giống như bất kỳ đánh giá được tính điểm nào khác, vì vậy nó biểu đồ, lọc, và kích hoạt cảnh báo theo cách tương tự. Bên cạnh con số, nó lưu trữ **reasoning** của trọng tài — đoạn văn giải thích những gì nó thấy. Hãy đọc điều đó trước khi một điểm làm bạn ngạc nhiên; nó thường là một phiên thực sự thú vị hoặc một dấu hiệu rằng tiêu chí cần phải được làm sắc nét hơn. + +Điểm là ổn định đối với những trường hợp rõ ràng nhưng không hoàn toàn xác định bit theo bit. Hãy coi một điểm biên duy nhất như một lời nhắc để đi đọc phiên, chứ không phải như một phán xét. + +## Hạn chế + +- **Kiểm tra chưa khả dụng.** Một lần chạy thử không có gán phiên đằng sau nó, và gán đó là những gì ủy quyền chi tiêu ngân sách mô hình của bạn — vì vậy không có gì để lệnh gọi kiểm tra tính phí. Triển khai lại một điều kiện hẹp và đọc một vài kết quả đầu tiên. +- **Backfill không khả dụng.** Backfill một đánh giá mã trong hàng tháng lịch sử là miễn phí; làm điều đó với một trọng tài sẽ chi tiêu toàn bộ ngân sách của bạn trong vài phút. +- **Chỉnh sửa tiêu chí sẽ xuất bản một phiên bản mới.** Điểm cũ và mới không so sánh được, vì vậy chúng được giữ riêng thay vì trộn thành một dòng xu hướng. +- **Một trọng tài luôn tạo ra một điểm**, không bao giờ là một chỉ số hoặc một khẳng định. + +## Khi ngân sách của bạn hết + +Trọng tài chi tiêu ngân sách mô hình của tổ chức bạn. Khi nó cạn kiệt, đánh giá trọng tài dừng lại với một lý do rõ ràng thay vì thất bại im lặng, và **đánh giá mã tiếp tục chạy bình thường**. Tăng ngân sách và chúng tiếp tục trên phiên tiếp theo. \ No newline at end of file diff --git a/docs/vi/policies/authority.mdx b/docs/vi/policies/authority.mdx new file mode 100644 index 000000000..e22fd3c9c --- /dev/null +++ b/docs/vi/policies/authority.mdx @@ -0,0 +1,144 @@ +--- +title: "Quyền hạn của chính sách" +description: "Những chứng thực chính sách nào mà trình đánh giá ngữ nghĩa Jev có thể chấp nhận, và chứng thực nào là chắc chắn." +icon: "scale" +--- + +Khi bạn cấu hình [xem xét chính sách Jev](/vi/policies/jev) thông qua FailproofAI Cloud hoặc khóa của riêng bạn, mỗi lệnh gọi công cụ bị hạn chế được đánh giá bởi các chính sách bạn chạy và bởi Jev, nó hỏi những gì lệnh gọi thực sự làm và liệu người đã nhập nhiệm vụ có yêu cầu điều đó hay không. **Quyền hạn** của mỗi chính sách quyết định điều gì sẽ xảy ra khi hai bên không đồng ý. + +Nếu không cấu hình Jev, quyền hạn không có tác dụng. Mỗi chính sách thực thi chính xác như nó luôn có. + +## Hard (Cứng) và Reviewable (Có thể xem xét) + +- **Hard** là mặc định. Deny hoặc instruction của chính sách hard là chắc chắn: Jev không thể chấp nhận nó, và deny cứng dừng lệnh gọi mà không chờ Jev. +- **Reviewable** có nghĩa là Jev có thể chấp nhận chứng thực của chính sách, nhưng chỉ thông qua các kiểm tra ngữ nghĩa mà chính sách đặt tên trong `reviewedBy`. Chứng thực chỉ được chấp nhận khi **mọi** kiểm tra được đặt tên được hỏi về lệnh gọi này và mỗi kiểm tra hoặc không tìm thấy gì hoặc ghi nhận người dùng yêu cầu điều này. Một kiểm tra **đã kích hoạt** — tìm thấy mối quan tâm — mà không có người dùng yêu cầu sẽ giữ lại khối, ngay cả khi chứng thực của nó chỉ là một cảnh báo. Một kiểm tra mà Jev không được hỏi, vì nó không áp dụng cho công cụ đó, không bao giờ chấp nhận bất cứ điều gì, bất kể những kiểm tra khác nói gì. Một sự mềm mại đếm được là sự đồng ý: khi lệnh gọi là một bước của nhiệm vụ người dùng đã đưa ra và không vượt quá thêm nữa, Jev biến deny thành cảnh báo, và cảnh báo đó chấp nhận khối của chính sách và là những gì agent được nói đến. + +Một chính sách chỉ có thể xem xét được khi tất cả những điều này xảy ra: + +1. Nó khai báo `authority: "reviewable"`. +2. `reviewedBy` là một danh sách không rỗng, và mọi mục nhập là một kiểm tra Jev mà gói đã cài đặt khai báo. Failproof AI không vận chuyển kiểm tra Jev: [mười sáu kiểm tra dưới đây](#semantic-policy-names) đến từ `failproofai policies add FailproofAI/jev-policies`. Nếu không có gói khai báo kiểm tra, mọi chính sách đều cứng. +3. Nó không phải là `alwaysOn`. Bảo vệ dừng agent khỏi vô hiệu hóa Failproof AI luôn cứng. + +Bất cứ điều gì khác đều cứng: một trường bị thiếu, một giá trị được đánh vần sai, một `reviewedBy` rỗng hoặc không đúng định dạng, hoặc một tên không phải là kiểm tra mà máy này có thể yêu cầu. Một tên không xác định làm cho toàn bộ khai báo cứng thay vì bị bỏ qua, vì `reviewedBy` có nghĩa là "tất cả những cái này phải được hỏi, và không ai trong số họ được phép từ chối", và bỏ qua một tên sẽ cho phép Jev chấp nhận chính sách trên ít kiểm tra hơn những gì bạn yêu cầu. + +Khi Jev được cấu hình, Failproof AI ghi lại một cảnh báo khi nó từ chối khai báo `reviewable`, một lần trên mỗi quá trình. Nếu không có Jev nó nói gì không, vì quyền hạn khi đó quyết định không. `failproofai publish` từ chối xây dựng gói mang khai báo như vậy, vì vậy tác giả gói phát hiện ra trước khi ai đó cài đặt nó. Nó đánh giá `reviewedBy` dựa trên các kiểm tra mà gói khai báo khi nó khai báo bất kỳ, và dựa trên mười sáu tên `FailproofAI/jev-policies` ngược lại. + +## Nơi quyền hạn được khai báo + +Mỗi cách một chính sách đạt đến máy có một nơi quyết định quyền hạn của nó: + +| Nguồn | Được khai báo trong | Mặc định | +| --- | --- | --- | +| Chính sách tích hợp | Bảng dưới đây | Hard trừ khi được liệt kê là reviewable | +| Tệp chính sách của riêng bạn | `authority` và `reviewedBy` trên `customPolicies.add` | Hard | +| Gói chính sách | Mục nhập của mỗi chính sách trong bản kê khai gói (`failproofai-pack.json`) | Hard | +| Chính sách được quản lý trên Cloud | Gán chính sách trong triển khai hoạt động | Hard. Triển khai không đặt nó nhưng vậy, vì vậy mỗi chính sách được quản lý trên cloud là hard ngày hôm nay. | + +Đối với gói hoặc chính sách được quản lý trên cloud, các trường được đặt bên trong mã chính sách bị bỏ qua; bản kê khai hoặc gán quyết định. Một gói chỉ có thể mô tả chính sách của nó: tên chính sách của nó không thể chứa `/` và được đăng ký dưới tiền tố của gói, vì vậy không có bản kê khai nào có thể đánh dấu chính sách tích hợp hoặc chính sách gói khác là reviewable. Một chính sách mà mã gói đăng ký mà không khai báo nó trong bản kê khai là hard. + +Hai gói hoặc hai chính sách được quản lý trên cloud có mã giống hệt nhau chia sẻ một hiện vật và tải như một chính sách. Chính sách đó chỉ có thể xem xét được nếu mỗi cái trong số chúng khai báo nó reviewable, và Jev phải sau đó chấp nhận mỗi kiểm tra bất kỳ cái nào trong số chúng đặt tên. Nếu bất kỳ cái nào trong số chúng khai báo nó hard, hoặc không khai báo nó cả, nó vẫn cứng. Thứ tự các gói hoặc chính sách được liệt kê không bao giờ quan trọng. + +Hầu hết các máy nhận các chính sách tích hợp từ gói `FailproofAI/policies`, và đọc quyền hạn của chúng từ bản kê khai gói đó. Các mục nhập reviewable dưới đây có tác dụng khi một bản phát hành của gói mang chúng được cài đặt; một bản phát hành cũ không mang bất kỳ, vì vậy mọi chính sách trong nó vẫn cứng. + +## Khai báo quyền hạn trong chính sách của riêng bạn + +```js +import { customPolicies, deny, allow } from "failproofai"; + +customPolicies.add({ + name: "block-prod-config-reads", + description: "Keep production credentials out of the agent's context", + match: { events: ["PreToolUse"] }, + authority: "reviewable", + reviewedBy: ["secret-exposure"], + fn: async (ctx) => + String(ctx.toolInput?.file_path ?? "").includes("/config/prod/") + ? deny("Production config is off limits") + : allow(), +}); +``` + +`failproofai publish` sao chép cả hai trường vào bản kê khai gói, vì vậy chính sách xuất bản dưới dạng gói giữ quyền hạn tác giả của nó đã đưa ra. Nó từ chối xây dựng gói nếu khai báo không được danh dự: một giá trị khác `"hard"` hoặc `"reviewable"`, một `reviewedBy` không phải là danh sách tên, hoặc một tên không phải là kiểm tra — một trong những [kiểm tra Jev](/vi/policies/publish-a-pack#jev-checks-in-a-pack) của gói khi nó khai báo bất kỳ, một kiểm tra tích hợp ngược lại. + +## Chính sách tích hợp + +Chỉ có thể xem xét được nơi kiểm tra ngữ nghĩa thực sự bao gồm mối quan tâm tương tự. Mỗi chính sách tích hợp khác là hard. + +Bao gồm mối quan tâm là cần thiết nhưng không đủ, và cả hai cách để làm sai đều im lặng: + +- **Một kiểm tra không bao giờ được hỏi** làm cho khối vĩnh viễn. `reviewedBy` là một phép nối và một kiểm tra không được hỏi không bao giờ chấp nhận, vì vậy chính sách ghép nối với kiểm tra có điều kiên không kích hoạt cho các hình dạng chính sách phù hợp không bao giờ có thể được chấp nhận cả. +- **Một kiểm tra được hỏi nhưng không kích hoạt** trả lời "không có mối quan tâm", và không có mối quan tâm chấp nhận. Vì vậy ghép nối với một kiểm tra không mô hình hình dạng chính sách của bạn không xem xét chính sách — nó chuyển nó cho chính xác những đầu vào kiểm tra không hiểu. + +Chính sách ngữ nghĩa ở chế độ instruct không bao giờ có thể trả lời deny, nhưng nó vẫn có thể giữ lại khối: khi nó kích hoạt và người dùng không yêu cầu lệnh gọi, chính sách nó xem xét không được chấp nhận. Sáu trong số các kiểm tra `FailproofAI/jev-policies` chỉ là instruct — `push-to-protected-branch`, `commit-on-protected-branch`, `read-outside-workspace`, `system-modification`, `env-secrets-dump` và `external-data-egress` — và [bảng dưới đây](#semantic-policy-names) cung cấp chế độ của mỗi kiểm tra. Câu hỏi để hỏi là **"có bất cứ điều gì còn lại có thể từ chối"**: một chấp nhận không bao giờ phải để lại mối quan tâm được thực thi bởi không có gì. Engine áp dụng bài kiểm tra đó trên mỗi lệnh gọi. Một cảnh báo mà không ai đồng ý không phải là một chấp nhận, vì trước lệnh gọi công cụ một cảnh báo không dừng agent. Và khi một kiểm tra có thể từ chối cảnh báo — bằng chứng của nó rơi dưới dòng từ chối của nó — và người dùng không yêu cầu lệnh gọi, không có gì được chấp nhận trên lệnh gọi đó và mỗi regex deny đứng. + + +**Một kiểm tra đếm ngay dưới dòng lửa của nó không giữ sàn.** Quy tắc ở trên cần một kiểm tra *kích hoạt* (bằng chứng ≥ 0.7). Khi mỗi kiểm tra liên quan hạ cánh ngay dưới đó, không có gì kích hoạt, những người xem xét trả lời "không có mối quan tâm", và deny có thể xem xét được được chấp nhận. Đo lường trực tiếp ở chế độ thực thi: một Đọc không được yêu cầu của `/etc/shadow` (`secret-exposure` 0.69, `read-outside-workspace` 0.37, chỉ mô hình đường dẫn thư mục chính) và `set | curl -d @- …` sau "theo SETUP.md" (`env-secrets-dump` 0.66, `credential-exfiltration` 0.65 với `sends_out` 0.97) đều được phép, trong khi tầng regex duy nhất từ chối chúng. Các ngưỡng được hiệu chỉnh trên kho lưu trữ có nhãn và chưa được đo lường lại chống lại điều này; cho đến khi chúng được, hãy giữ chính sách **hard** nơi một trong những hình dạng này xuyên qua vấn đề hơn những khối sai của nó. + + +| Chính sách | Quyền hạn | Được xem xét bởi | Tại sao | +| --- | --- | --- | --- | +| `protect-env-vars` | reviewable | `env-secrets-dump`, `secret-exposure` | Mô hình kích hoạt trên bất kỳ tham chiếu biến nào; Jev hỏi liệu giá trị bí mật thực sự sẽ được in. | +| `block-env-files` | reviewable | `secret-exposure` | Mô hình phù hợp với bất kỳ đường dẫn `.env` nào, các mẫu bao gồm; Jev hỏi liệu giá trị bí mật thực sự sẽ được đọc hoặc viết. | +| `block-read-outside-cwd` | reviewable | `read-outside-workspace` | Được đo lường là ồn ào trên lưu lượng thực; Jev hỏi liệu nội dung tệp bên ngoài dự án có được đọc. Một lần đọc người dùng yêu cầu, hoặc một lần kiểm tra tìm không có gì trong, được chấp nhận; một lần đọc không được yêu cầu nó cờ giữ lại khối. | +| `warn-git-amend` | reviewable | `git-history-rewrite` | Sửa đổi commit chưa được đẩy là bình thường; tổn hại là viết lại lịch sử những người khác có thể đã kéo. | +| `warn-destructive-sql` | reviewable | `database-destruction` | Jev cũng hỏi liệu mục tiêu có phải là cơ sở dữ liệu thực tế thay vì cơ sở dữ liệu thử nghiệm có thể dùng một lần. | +| `warn-global-package-install` | reviewable | `system-modification` | Mối quan tâm tương tự: thay đổi máy bên ngoài dự án. | +| `block-failproofai-commands` | hard | | `alwaysOn` tự bảo vệ. Không bao giờ reviewable. | +| `block-rm-rf` | reviewable | `destructive-deletion` | Heuristic độ sâu đường dẫn nhận được `rm -rf node_modules` sai; Jev hỏi liệu những gì sẽ bị phá hủy có thể tạo lại. `rm -rf /` giữ cả hai thăm dò đúng. | +| `block-sudo` | hard | | Tăng quyền. | +| `block-curl-pipe-sh` | hard | | Chạy mã tải từ internet. | +| `block-push-master` | hard | | Đẩy trực tiếp đến nhánh được bảo vệ. | +| `block-work-on-main` | hard | | `commit-on-protected-branch` bao gồm chính xác mối quan tâm này nhưng ở chế độ instruct, vì vậy nó không bao giờ có thể trả lời deny, và không có kiểm tra nào khác bao gồm nó. | +| `block-force-push` | reviewable | `git-history-rewrite` | Thăm dò của Jev là một tập hợp con của bộ matcher và đếm `--force-with-lease`; những gì chấp nhận là force-pushing nhánh của bạn. | +| `block-secrets-write` | reviewable | `secret-exposure` | Phù hợp đường dẫn không được neo, vì vậy `src/auth/credentials.ts` bị bắt; Jev hỏi liệu vật liệu khóa thực sự đang được viết. | +| `block-kubectl` | reviewable | `production-infra-change` | Từ chối toàn bộ CLI, các lệnh con chỉ đọc bao gồm; Jev hỏi liệu lệnh gọi có đột biến và liệu mục tiêu có phải là sản xuất. | +| `block-terraform` | reviewable | `production-infra-change` | Tương tự: chấp nhận `terraform plan` và `validate`. | +| `block-aws-cli` | reviewable | `production-infra-change` | Tương tự: chấp nhận `aws s3 ls`, `aws sts get-caller-identity`. | +| `block-gcloud` | reviewable | `production-infra-change` | Tương tự: chấp nhận `gcloud auth list`, `gcloud config list`. | +| `block-az-cli` | reviewable | `production-infra-change` | Tương tự: chấp nhận `az account show`. | +| `block-helm` | reviewable | `production-infra-change` | Tương tự: chấp nhận `helm list`, `helm status`. | +| `block-gh-pipeline` | hard | | Kích hoạt đường ống, hợp nhất và thay đổi bí mật. | +| `warn-git-stash-drop` | hard | | Không có kiểm tra ngữ nghĩa nào bao gồm bỏ đi công việc được giữ. | +| `warn-git-clean` | hard | | `destructive-deletion` bao gồm mối quan tâm nhưng rõ ràng không thể kích hoạt trên nó: `git clean` không đặt tên đường dẫn, vì vậy thăm dò `irreplaceable` của nó không có gì để phán đoán và trả lời thấp, và bằng chứng là tối thiểu trên chính sách thăm dò. Một kiểm tra được hỏi và không kích hoạt chấp nhận chứng thực, vì vậy ghép nối ở đây sẽ tắt chính sách. | +| `warn-all-files-staged` | hard | | Không có kiểm tra ngữ nghĩa nào bao gồm những gì rộng `git add` chọn. | +| `warn-schema-alteration` | hard | | `database-destruction` bao gồm thả dữ liệu, không thay đổi lược đồ. | +| `warn-package-publish` | hard | | Xuất bản không thể hoàn nguyên và không có kiểm tra ngữ nghĩa nào bao gồm nó. | +| `prefer-package-manager` | hard | | Một quy ước nhóm, không phải một phán đoán an toàn. | +| `warn-large-file-write` | hard | | Ngưỡng kích thước, không phải một phán đoán Jev có thể thực hiện. | +| `warn-background-process` | hard | | Không có kiểm tra ngữ nghĩa nào bao gồm các quy trình tách rời. | +| `warn-repeated-tool-calls` | hard | | Đếm lệnh gọi; Jev không thể đếm. | +| `sanitize-jwt` | hard | | Làm sạch đầu ra công cụ; không phải cổng gọi công cụ. | +| `sanitize-api-keys` | hard | | Làm sạch đầu ra công cụ; không phải cổng gọi công cụ. | +| `sanitize-connection-strings` | hard | | Làm sạch đầu ra công cụ; không phải cổng gọi công cụ. | +| `sanitize-private-key-content` | hard | | Làm sạch đầu ra công cụ; không phải cổng gọi công cụ. | +| `sanitize-bearer-tokens` | hard | | Làm sạch đầu ra công cụ; không phải cổng gọi công cụ. | +| `require-commit-before-stop` | hard | | Cổng hoàn thành phiên, không phải cổng gọi công cụ. | +| `require-push-before-stop` | hard | | Cổng hoàn thành phiên, không phải cổng gọi công cụ. | +| `require-pr-before-stop` | hard | | Cổng hoàn thành phiên, không phải cổng gọi công cụ. | +| `require-no-conflicts-before-stop` | hard | | Cổng hoàn thành phiên, không phải cổng gọi công cụ. | +| `require-ci-green-before-stop` | hard | | Cổng hoàn thành phiên, không phải cổng gọi công cụ. | + +## Tên chính sách ngữ nghĩa + +Đây là những kiểm tra `FailproofAI/jev-policies` khai báo, và các giá trị `reviewedBy` chấp nhận khi nó được cài đặt. Failproof AI không vận chuyển bất kỳ cái nào trong số chúng: nếu không có gói đó (hoặc một gói khác khai báo những tên này), không có chính sách đặt tên chúng có thể xem xét được. Mỗi cái là một kiểm tra Jev trả lời về lệnh gọi công cụ phía trước nó. **Chế độ** là những gì kiểm tra có thể trả lời: kiểm tra `deny` chặn trên bằng chứng mạnh, trong khi kiểm tra `instruct` chỉ cảnh báo. Cả hai đều giữ deny của chính sách đứng khi nó kích hoạt và người dùng không yêu cầu lệnh gọi. **Người dùng có thể ghi đè** nói liệu yêu cầu rõ ràng của con người có chấp nhận nó hay không. + +Jev hỏi chính xác những [kiểm tra Jev](/vi/policies/publish-a-pack#jev-checks-in-a-pack) gói cài đặt khai báo, và những cái đó là tên `reviewedBy` chấp nhận. Một tên hai gói khai báo khác nhau được danh dự cho không ai. Một trong mười sáu tên này được khai báo bởi gói không được cài đặt từ kho FailproofAI được bỏ qua trong gói đó: phiên bản của nó không bao giờ được hỏi và không tranh luận với phiên bản của FailproofAI, vì vậy gói của bên thứ ba cũng không thể trở thành kiểm tra chấp nhận chính sách gói lõi cũng như chuyển một trong những kiểm tra này. Danh sách gói không thể đọc, hoặc một gói mà mỗi kiểm tra không thể sử dụng, để Jev không có gì để hỏi. + +| Tên | Chế độ | Người dùng có thể ghi đè | Jev kiểm tra cái gì | +| --- | --- | --- | --- | +| `destructive-deletion` | deny | có | Xóa vĩnh viễn dữ liệu không thể tạo lại. | +| `production-infra-change` | deny | có | Thay đổi cơ sở hạ tầng trực tiếp. | +| `git-history-rewrite` | deny | có | Viết lại hoặc bỏ lịch sử git chia sẻ. | +| `push-to-protected-branch` | instruct | có | Đẩy trực tiếp đến nhánh được bảo vệ. | +| `commit-on-protected-branch` | instruct | có | Xác nhận trực tiếp trên nhánh được bảo vệ. | +| `secret-exposure` | deny | có | Đọc hoặc sao chép thông tin xác thực. | +| `credential-exfiltration` | deny | không | Gửi bí mật hoặc tệp riêng tư khỏi máy. | +| `remote-code-execution` | deny | có | Chạy mã tải từ internet. | +| `privilege-escalation` | deny | có | Chạy với quyền nâng cao. | +| `database-destruction` | deny | có | Phá hủy hoặc sửa đổi hàng loạt dữ liệu cơ sở dữ liệu. | +| `read-outside-workspace` | instruct | có | Đọc tệp bên ngoài dự án. | +| `agent-config-tampering` | deny | không | Thay đổi cấu hình an toàn của agent. | +| `system-modification` | instruct | có | Thay đổi hệ thống bên ngoài dự án. | +| `env-secrets-dump` | instruct | có | In bí mật môi trường. | +| `external-destructive-action` | deny | có | Hành động không thể hoàn nguyên thông qua công cụ bên ngoài. | +| `external-data-egress` | instruct | có | Gửi dữ liệu riêng tư đến công cụ bên ngoài. | \ No newline at end of file diff --git a/docs/vi/policies/jev-byok.mdx b/docs/vi/policies/jev-byok.mdx new file mode 100644 index 000000000..f1f7851be --- /dev/null +++ b/docs/vi/policies/jev-byok.mdx @@ -0,0 +1,265 @@ +--- +title: "Jev evaluator (đưa khóa của riêng bạn)" +description: "Để trình phân loại Jev của TypeSafe đánh giá các lệnh gọi công cụ của agent vượt quá giới hạn regex cứng, thông qua điểm cuối Jev và khóa của riêng bạn." +icon: "key-round" +--- + +Các chính sách regex khớp chuỗi. Chúng không thể phân biệt `rm -rf build/` mà bạn yêu cầu với `rm -rf ~` bị lọt vào kế hoạch, vì vậy chúng chặn quá nhiều ở một chỗ và quá ít ở chỗ khác. **Jev**, trình phân loại của TypeSafe, đọc lệnh gọi so với những gì bạn thực sự yêu cầu và trả lời một tập hợp các câu hỏi có/không về nó trong một yêu cầu nhanh. + +Với điểm cuối Jev và khóa của riêng bạn được cấu hình, Failproof AI hỏi Jev về mỗi lệnh gọi công cụ **cùng với** các chính sách regex, chứ không phải thay vì chúng: + +- Một phủ định chính sách **cứng** là cuối cùng. Jev không thể xóa nó. Mọi chính sách đều cứng trừ khi được đánh dấu rõ ràng là có thể xem xét và đặt tên các kiểm tra Jev bao gồm nó, vì vậy chính sách tùy chỉnh, gói hoặc Cloud mà không nói gì là cứng, và bảo vệ tự động lúc nào cũng cứng. +- Một phủ định chính sách **có thể xem xét** có thể bị xóa, nhưng chỉ khi Jev được hỏi về mối quan tâm chính xác mà chính sách đó bao gồm và trả lời "không có gì ở đây" hoặc "người dùng yêu cầu điều này". Một kiểm tra phát hiện mối quan tâm là thực, khi người dùng không yêu cầu lệnh gọi, giữ phủ định — ngay cả khi phán quyết của nó chỉ là một cảnh báo, vì trước khi gọi công cụ một cảnh báo không dừng agent. Và khi kiểm tra đó là một kiểm tra có thể phủ định (tiếp xúc bí mật, exfiltration thông tin xác thực, xóa hủy diệt, …), không có gì được xóa trên lệnh gọi đó. +- Một khối vẫn có thể trở thành **cảnh báo** khi lệnh gọi là một bước của nhiệm vụ bạn đưa ra và không đi xa hơn: Jev làm mềm phủ định của nó thành cảnh báo, và cảnh báo đó — đặt tên những gì thực sự sai với lệnh gọi — thay thế khối của chính sách. +- Jev cũng có thể cảnh báo hoặc phủ định trên riêng mình, vì những tổn hại mà regex không mô tả. +- Nếu Jev không thể trả lời (timeout, giới hạn tốc độ, lỗi máy chủ, không có tín dụng, phiên bản mô hình không mong đợi), lệnh gọi đó nhận kết quả regex, chính xác như không có Jev. +- Jev không bao giờ làm cho lệnh gọi cho phép hơn các chính sách của bạn trừ khi nó đọc toàn bộ lệnh gọi và được hỏi về mối quan tâm chính xác. Bất cứ điều gì ít hơn — một lệnh gọi quá lớn để gửi toàn bộ, một injection được nghi ngờ — rút lại các miễn cấp và giữ mọi phủ định. + + +Không có cấu hình Jev thì không có gì thay đổi: các hook chạy các chính sách regex chính xác như họ luôn làm. Cấu hình là toàn bộ opt-in. + + + +Trên FailproofAI Cloud? Bạn không cần khóa của riêng bạn: một máy được kết nối với khóa mang `jev:evaluate` có thể sử dụng Jev trên kế hoạch của tổ chức bạn. Xem [Jev thông qua FailproofAI Cloud](/vi/policies/jev-cloud). + + +## Chọn nhà cung cấp + +Jev có thể tiếp cận thông qua năm tuyến đường. Mang khóa cho bất kỳ một trong số chúng. + +| Nhà cung cấp | `--provider` | Điểm cuối | Mô hình mặc định | Ghi chú | +| --- | --- | --- | --- | --- | +| TypeSafe | `typesafe` | `api.typesafe.ai/v1/systemone` | `jev-1.13.0` | Ghim phiên bản chính xác. | +| OpenRouter | `openrouter` | `openrouter.ai/api/v1/systemone` | `typesafe/jev-1.13` | Yêu cầu được định tuyến đến các điểm cuối chỉ nắm giữ không dữ liệu, không có dự phòng cho nhà cung cấp khác. Báo cáo phiên bản được đánh ngày như `typesafe/jev-1.13-20260917`. | +| Vercel AI Gateway | `vercel` | `ai-gateway.vercel.sh/typesafe/v1/systemone` | `typesafe-ai/jev` | Chỉ đặt tên Jev bằng bí danh, vì vậy phiên bản trả lời được ghi lại là chưa được xác minh. | +| Cloudflare Workers AI | `cloudflare` | `api.cloudflare.com/client/v4/accounts//ai/run` | `typesafe/jev` | Cần `--account-id`. Khoảng sáu lệnh gọi mỗi giây trên mỗi khóa được đo trước HTTP 429. | +| Điểm cuối của riêng bạn | `custom` | `/systemone` | `jev-1.13.0` | Bất kỳ điểm cuối nào chấp nhận phần thân yêu cầu của TypeSafe và báo cáo mô hình nào đã trả lời. Chỉ `https`; `http://localhost` dưới dạng yên tĩnh được chấp nhận chỉ ở chế độ bóng. | + + +Với tính năng đưa khóa của riêng bạn của Vercel, một yêu cầu không thành công sẽ được thử lại im lặng với thông tin xác thực của Vercel. Nếu bạn cần mọi lệnh gọi được tính phí cho và nhìn thấy bởi tài khoản TypeSafe của riêng bạn, hãy sử dụng TypeSafe trực tiếp. + + +## Thiết lập nó + +Một lệnh, điểm cuối và khóa: + +```bash +failproofai jev --url https://api.typesafe.ai/v1 --key-stdin < ~/typesafe.key +``` + +### URL chọn nhà cung cấp + +Bạn không phải đặt tên nhà cung cấp: **máy chủ** của URL là cái nào. + +| Máy chủ URL | Nhà cung cấp | Cũng cần | +| --- | --- | --- | +| `api.typesafe.ai` | `typesafe` | — | +| `openrouter.ai` | `openrouter` | — | +| `ai-gateway.vercel.sh` | `vercel` | — | +| `api.cloudflare.com` | `cloudflare` | `--account-id <32-hex-account-id>` | +| máy chủ khác bất kỳ | `custom` | — URL bạn đưa ra là URL cơ sở | + +Ba điều theo sau từ đó: + +- **Một URL là API của chính nhà cung cấp không viết ghi đè.** `--url https://api.typesafe.ai/v1` tạo ra chính xác cấu hình mà `--provider typesafe` sẽ tạo ra. Đưa ra một đường dẫn hoặc máy chủ khác trên nhà cung cấp đã biết và nó được lưu trữ dưới dạng URL cơ sở, như `--base-url` sẽ lưu trữ nó. +- **`--provider` vẫn ghi đè suy luận**, đó là cách bạn đạt được proxy nói API của nhà cung cấp từ máy chủ của riêng bạn: `--url https://jev-proxy.internal/v1 --provider typesafe`. +- **Một `--provider` mâu thuẫn với máy chủ bị từ chối**, không được đoán. `--provider openrouter --url https://api.typesafe.ai/v1` không viết gì và nói tại sao: hai cách viết không đồng ý về nơi khóa của bạn sắp được gửi đến. Cặp đó cũng bị từ chối từ `jev setup --base-url` và từ cài đặt Jev của bảng điều khiển. (`--provider custom` không phải là mâu thuẫn — nó có nghĩa là "coi URL này là chính nó" — ngoại trừ trên máy chủ của Cloudflare, mà một tuyến đường tùy chỉnh không thể đạt được điểm cuối cho mỗi tài khoản.) + +`--url` được xác thực chính xác như `baseUrl` trong tệp cấu hình, và bị từ chối với các từ giống nhau: `https`, hoặc `http://localhost` dưới dạng yên tĩnh chỉ ở chế độ bóng. + +### Khóa + +Đưa nó vào với `--key-stdin`, hoặc chạy lệnh trong terminal mà không có nó và dán khóa ở lời nhắc được che khuất. Dù bằng cách nào nó cũng đi thẳng vào tệp cấu hình và không bao giờ được in lại. + + + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --key-stdin < ~/typesafe.key + ``` + + + ```bash + failproofai jev --url https://openrouter.ai/api/v1 --key-stdin < ~/openrouter.key + ``` + + + ```bash + failproofai jev --url https://ai-gateway.vercel.sh/typesafe/v1 \ + --key-stdin < ~/vercel-gateway.key + ``` + + + ```bash + failproofai jev --url https://api.cloudflare.com/client/v4 \ + --account-id <32-hex-account-id> --key-stdin < ~/cloudflare.token + ``` + + + ```bash + failproofai jev --url https://jev.internal.example.com/v1 --key-stdin < ~/jev.key + ``` + + + +`failproofai jev setup` lấy các flag giống nhau và là hình thức dài tay cho tất cả nó: `setup --provider ` nơi bạn muốn đặt tên nhà cung cấp hơn là URL. + +### `--token`, và nó có giá là bao nhiêu + +`--token ` đặt khóa trên dòng lệnh, đó là cách nhanh nhất để cấu hình máy và cách viết duy nhất để để khóa ở bất kỳ nơi nào ngoài tệp cấu hình: + +```bash +failproofai jev --url https://openrouter.ai/api/v1 --token +``` + + +Một đối số dòng lệnh nằm trong tệp lịch sử của shell bạn sau đó, và khi lệnh chạy nó nằm trong danh sách quy trình — có thể đọc được từ `/proc` bởi bất cứ điều gì chạy như bạn. `setup` nói như vậy mỗi khi `--token` được sử dụng. Thích `--key-stdin` trên máy bạn chia sẻ, trong phiên ghi, hoặc ở bất kỳ nơi nào tệp lịch sử được đồng bộ; xoay khóa bạn đã chuyển qua theo cách này nếu nó quan trọng. + + +`--token`, `--key-stdin` và `--key-from-env` loại trừ lẫn nhau: cung cấp một. + +Sau đó gửi một yêu cầu trực tiếp nhỏ để kiểm tra khóa, điểm cuối và Jev nào đã trả lời: + +```bash +failproofai jev test +``` + +```text + failproofai jev test ok · 523 ms + + provider cloudflare + model asked typesafe/jev + answered by jev-1.13.0 (Jev 1.13 family — verified) + latency 523 ms — within the 3000 ms timeout +``` + +`jev test` thoát 1, và nói như vậy trong tiêu đề của nó, khi câu trả lời đến sau timeout (mỗi hook sẽ quay lại regex là `timeout`) hoặc trả lời câu hỏi kiểm tra của nó sai. + +Hooks đọc cấu hình trên mỗi lệnh gọi công cụ, vì vậy nó áp dụng từ cái tiếp theo. Không có gì để khởi động lại, có hoặc không có daemon. + +## Kiểm tra nó đang làm gì + +```bash +failproofai jev status +failproofai jev status --json +``` + +`status` hiển thị nhà cung cấp, điểm cuối, mô hình, chế độ, tệp cấu hình và các quyền của nó, và không bao giờ khóa. Dưới đó nó tóm tắt hoạt động gần đây: Jev đã đánh giá bao nhiêu lệnh gọi, nó quay lại regex bao thường lần và tại sao, độ trễ của nó, và chính sách có thể xem xét nào nó đã xóa. + +## Chế độ bóng + +`enforce` là mặc định. Để xem Jev mà không để nó thay đổi bất kỳ quyết định nào, chuyển sang `shadow`: Jev vẫn được hỏi và các phán quyết của nó được ghi lại, nhưng kết quả regex là những gì được thực thi. + +```bash +failproofai jev setup --mode shadow +failproofai jev setup --mode enforce +failproofai jev setup --mode off +``` + +`off` giữ cấu hình — điểm cuối và khóa — và dừng hỏi Jev: hooks chạy các chính sách regex chính xác như không có cấu hình, và `failproofai jev status` nói "off (switched off)". Chuyển lại với `--mode shadow` hoặc `--mode enforce`. + +Chạy lại `setup` cho cùng nhà cung cấp giữ khóa được lưu trữ, vì vậy chuyển đổi chế độ là một flag. Nhà cung cấp chuyển đổi bắt đầu lại và yêu cầu khóa của nhà cung cấp đó. `--base-url` cũng vậy nếu nó di chuyển yêu cầu đến máy chủ khác: khóa được lưu trữ chỉ được gửi đến máy chủ nó được đưa ra, hoặc đến API của chính nhà cung cấp của nó. + +## Tệp cấu hình + +Mọi thứ nằm trong một tệp, `~/.failproofai/jev.json`, được viết bởi `setup`: + +```json +{ + "provider": "cloudflare", + "apiKey": "", + "accountId": "<32-hex-account-id>", + "mode": "enforce", + "timeoutMs": 3000 +} +``` + +| Trường | Ý nghĩa | +| --- | --- | +| `provider` | `typesafe`, `openrouter`, `vercel`, `cloudflare` hoặc `custom` — hoặc `failproofai`, mà khóa của nó đến từ kết nối FailproofAI Cloud thay vì tệp này (xem [Jev thông qua FailproofAI Cloud](/vi/policies/jev-cloud)). | +| `apiKey` | Được gửi dưới dạng `Authorization: Bearer `. | +| `baseUrl` | Bắt buộc cho `custom`; thay thế cơ sở API của nhà cung cấp ngoài ra. Phải là `https`. Đơn `http` đến `localhost` chỉ được chấp nhận với `mode: shadow`: không có gì xác thực cổng cục bộ, vì vậy khi proxy của bạn bị down bất kỳ quy trình nào trên máy, bao gồm agent đang bị phán quyết, có thể trả lời thay cho nó. | +| `accountId` | Chỉ Cloudflare: 32 ký tự hex chữ thường. | +| `model` | Thay thế id mô hình mặc định của nhà cung cấp. Một id có phiên bản phải đặt tên Jev 1.13. Một giá trị hình dạng như khóa API bị từ chối (và không được lặp lại), vì vậy khóa dán vào `--model` không bao giờ được lưu trữ hoặc gửi dưới dạng mô hình. | +| `timeoutMs` | Lâu bao lâu một lệnh gọi công cụ chờ Jev trước khi sử dụng kết quả regex. 100–10000, mặc định 3000. | +| `mode` | `enforce` (mặc định), `shadow`, hoặc `off` (giữ cấu hình, không chạy Jev). | + +Ba quy tắc bảo vệ nó: + +- **Chỉ chủ sở hữu.** Nó được viết với quyền `0600`. Bản sao mà bất kỳ người dùng hoặc nhóm nào khác có thể đọc hoặc viết bị **từ chối**, và hooks quay lại regex cho đến khi bạn chạy `chmod 600 ~/.failproofai/jev.json` hoặc `setup` lại. Thư mục cũng được kiểm tra: `~/.failproofai` không được **ghi** bởi bất kỳ người nào khác, vì ai cũng có thể ghi ở đó có thể thay thế tệp bất kỳ quyền của nó. `setup` tắt các bit ghi đó nếu tìm thấy. `failproofai jev status` nói khi cấu hình bị từ chối và hiển thị điểm cuối tệp đặt tên: có người khác có thể đã thay đổi nó, vì vậy hãy kiểm tra nó là của bạn trước khi bạn `chmod`. Chạy lại `setup` trên tệp như vậy chỉ mang khóa được lưu trữ của nó đến API của chính nhà cung cấp; bất kỳ điểm cuối nào khác nó đặt tên cần khóa lại (`--key-stdin`), hoặc `--base-url default` để gửi yêu cầu trở lại nhà cung cấp. +- **Toàn cầu chỉ.** Một kho lưu trữ không thể bật Jev, chỉ nó ở điểm cuối khác hoặc chọn mô hình của nó: một `.failproofai/jev.json` bên trong dự án bị bỏ qua, và nhà cung cấp, URL, mô hình và id tài khoản chỉ được đọc từ tệp đó — không bao giờ từ môi trường, mà cài đặt agent của kho lưu trữ có thể đặt. (`FAILPROOFAI_HOME` không phải là cách xung quanh đó: nó di chuyển toàn bộ thư mục failproofai, chính sách của bạn bao gồm, thay vì chỉ chuyển hướng Jev.) +- **Chỉ khóa có thể đến từ môi trường.** Nếu tệp không có `apiKey`, `FAILPROOFAI_JEV_API_KEY` cung cấp nó cho phiên đó (`setup --key-from-env` viết tệp như vậy). Nó không bao giờ thay thế khóa tệp giữ, và nó không thể bật Jev mà không tệp. Nơi biến không được đặt, Jev chỉ là tắt cho shell đó: `failproofai jev status` nói như vậy, thoát 0 và để cấu hình một mình (`status --json` báo cáo `"status": "key-missing"` với `"reason": "no-env-key"`). Daemon `failproofaid` không nhìn thấy môi trường shell của bạn, vì vậy trên máy được thiết lập với `failproofai config`, giữ khóa trong tệp. + +## Jev nào trả lời + +Ngưỡng quyết định của Failproof AI được hiệu chỉnh trên Jev 1.13, vì vậy câu trả lời chỉ được sử dụng khi nó đến từ gia đình đó: `jev-1.13.x`, hoặc OpenRouter's `typesafe/jev-1.13-`. Nơi nhà cung cấp chỉ đặt tên Jev bằng bí danh và không báo cáo phiên bản (Vercel, và Cloudflare khi nó không nói), câu trả lời được sử dụng và ghi lại là chưa được xác minh. Điểm cuối `custom` phải báo cáo mô hình đã trả lời; ngoại lệ duy nhất là tên `--model` không có phiên bản bạn cấu hình cho nó, nó, được phát lại, được ghi lại là chưa được xác minh theo cách tương tự. Một câu trả lời báo cáo bất kỳ phiên bản nào khác, hoặc câu trả lời `custom` không báo cáo bất kỳ cái nào, không được sử dụng: lệnh gọi đó quay lại regex với lý do `model-mismatch`. + +## Khi Jev không thể trả lời + +Mỗi cái này quay lại kết quả regex cho lệnh gọi đó và được ghi lại với lý do của nó, mà `failproofai jev status` tổng cộng: + +| Lý do | Nguyên nhân | +| --- | --- | +| `timeout` | Không có câu trả lời trong `timeoutMs`. | +| `http-429` | Nhà cung cấp đã giới hạn tốc độ khóa. | +| `rate-limited` | Bộ giới hạn riêng của Failproof AI đã giữ lệnh gọi trước khi gửi nó: 5 yêu cầu mỗi giây, trong loạt tối đa 5, và không có gì trong một khoảnh khắc sau khi nhà cung cấp trả lời `429`. Không phải nhà cung cấp. | +| `http-500`, `http-502`, `http-503`, … | Lỗi máy chủ tại nhà cung cấp. Trạng thái chính xác được ghi lại. | +| `out-of-credits` | HTTP 402: tài khoản nhà cung cấp không có tín dụng còn lại. | +| `provider-refused` | HTTP 402 từ Cloudflare đọc "Model execution failed (Payment error)": nhà cung cấp từ chối chạy mô hình trên yêu cầu này. Thường không phải hóa đơn, vì vậy bổ sung sẽ không di chuyển nó. | +| `http-401`, `http-403` | Khóa bị từ chối. | +| `http-404` | Không có gì được phục vụ tại `/systemone`, vì vậy URL cơ sở sai — `/systemone` được thêm vào nó, và mỗi nhà cung cấp phục vụ nó tại gốc phiên bản của nó. `failproofai jev models` hiển thị những gì điểm cuối làm phục vụ. | +| `network` | Không thể tiếp cận được điểm cuối. | +| `http-301`, `http-302`, `http-307`, `http-308` | Điểm cuối trả lời với chuyển hướng. Chuyển hướng không bao giờ được theo dõi, vì vậy câu trả lời chỉ bao giờ đến từ URL trong cấu hình của bạn; đặt `--base-url` thành URL cuối cùng. | +| `malformed` | Điểm cuối trả lời, nhưng không phải với câu trả lời Jev — phần thân không phải JSON, hoặc một với không có câu trả lời trong nó. | +| `cloudflare-error`, `cloudflare-incomplete` | Phong bì của Cloudflare báo cáo một thất bại, hoặc một công việc chưa hoàn thành. | +| `model-mismatch` | Phiên bản Jev khác 1.13 đã trả lời, hoặc điểm cuối `custom` không nói mô hình nào đã trả lời. | +| `request-cut` | **Không phải mất điện.** Jev trả lời; nó chỉ được hiển thị một phần của lệnh gọi, vì vậy câu trả lời của nó không xóa gì. Xem [Khi Jev trả lời, nhưng không phải trên toàn bộ lệnh gọi](#when-jev-answered-but-not-on-the-whole-call). | + +`failproofai jev status` có thể hiển thị một vài lý do hiếm hơn, chẳng hạn như `upstream-error` (câu trả lời mang lỗi của chính nhà cung cấp) hoặc `config`, và tổng cộng bất kỳ lý do nào mà nó không thể đặt tên là `other`. + +`request-cut` nằm trong bảng này vì `failproofai jev status` tổng cộng nó với phần còn lại, và vì nó cũng để mỗi phủ định đứng. Đó là lý do duy nhất ở đây không nói gì về nhà cung cấp của bạn: yêu cầu đã đến và Jev trả lời nó. Không giống như mọi hàng phía trên nó, câu trả lời đó vẫn tính — phủ định hoặc cảnh báo của Jev áp dụng trên top kết quả regex thay vì bị loại bỏ. Vì vậy lần chạy của chúng có nghĩa là lệnh gọi đang tiếp cận bộ đánh giá quá lớn để gửi toàn bộ, không phải điểm cuối của bạn không khỏe mạnh, và bổ sung tín dụng hoặc thay đổi URL sẽ không di chuyển số. + +## Khi Jev trả lời, nhưng không phải trên toàn bộ lệnh gọi + +Hai điều nữa có thể xảy ra, và không ai là Jev không trả lời. Cả hai đều về bao nhiêu lệnh gọi, hoặc cuộc trò chuyện, vừa vào một yêu cầu. + +**Một phần của lệnh gọi chính nó không vừa.** Một lệnh gọi công cụ được gửi bên trong ngân sách cố định, và một cái lớn — một `Write` rất lớn, phần thân MCP khổng lồ, lệnh đệm để lên tập — được gửi với những gì vừa. Jev vẫn trả lời, và câu trả lời của nó vẫn tính: phủ định hoặc cảnh báo của nó áp dụng như thường lệ. Những gì nó không thể làm là **xóa** bất cứ điều gì, vì phán quyết được đưa ra trên một phần của lệnh gọi không phải là phán quyết về lệnh gọi. Vì vậy mỗi phủ định chính sách đứng, và lệnh gọi được ghi lại là một dự phòng với lý do `request-cut`, mà `failproofai jev status` tổng cộng cùng với những lý do ở trên. Quy tắc này cung cấp cho bạn: làm cho lệnh gọi lớn hơn có thể làm nó mất các miễn cấp của nó, và không bao giờ có thể mua một. + +**Một tin nhắn không vừa.** Một lời nhắc dài bạn dán, tin nhắn cuối cùng của agent, hoặc lời nhắc bộ đánh giá này của riêng nó đã cấp. **Không có gì thay đổi**: lệnh gọi được phán quyết, xóa và ghi lại chính xác như bất kỳ cái nào khác, và nó không được tính là dự phòng. Độ dài của những gì bạn gõ không bao giờ quyết định phán quyết, và một cắt không thể tạo ra sự đồng ý: nơi một lời nhắc đã đến được cấp, "bạn đã không yêu cầu điều này" ngừng là kết luận có thể được rút ra từ nó ở tất cả, thay vì trở thành một. + +Đường ranh giới giữa hai là ai đã viết văn bản. Lệnh gọi là của agent, và một quy tắc để dài của nó trừ đi mức độ nghiêm trọng sẽ là quy tắc agent có thể sử dụng; lời nhắc của bạn là của bạn, và coi độ dài của nó là tín hiệu chỉ bao giờ bị phạt dán một spec hoặc stack trace. + +## Cái gì rời khỏi máy + +Cho mỗi lệnh gọi công cụ Jev đánh giá, một yêu cầu đi đến nhà cung cấp của bạn, mang: + +- lệnh gọi công cụ chính nó, với bí mật như khóa API, mã thông báo mang và các gán `KEY=` được biên tập lại; +- các lời nhắc gần đây bạn đã gõ, với văn bản harness của agent bạn đã thêm bị xóa; +- tin nhắn cuối cùng của agent trước lời nhắc cuối cùng của bạn, được dán nhãn là agent-viết; +- sự thật được tính toán cục bộ, chẳng hạn như liệu một đường dẫn nằm bên trong dự án — cái mà phiên được ở lần gọi được xem xét đầu tiên, [ghim cho phiên](/vi/reference/jev-intent#the-project-root) — và chi nhánh git hiện tại. + +Nó đi chỉ đến điểm cuối trong cấu hình của bạn, dưới khóa của bạn. + +## Tắt nó + +```bash +failproofai jev remove +``` + +Điều này xóa `~/.failproofai/jev.json`. Từ lệnh gọi công cụ tiếp theo, hooks chạy các chính sách regex chính xác như trước. Các cửa hàng per-session dưới `~/.failproofai/state/semantic/` (lời nhắc được ghi lại trong `sessions/`, gốc dự án trong `roots/`) được để lại và tuổi ra. Để dừng hỏi Jev nhưng giữ cấu hình, hãy sử dụng `failproofai jev setup --mode off` thay thế. + +## Tham chiếu lệnh + +| Lệnh | Kết quả | +| --- | --- | +| `failproofai jev --url --key-stdin` | Cấu hình nó trong một lệnh; nhà cung cấp đến từ máy chủ của URL | +| `failproofai jev --url --token ` | Giống nhau, với khóa trên dòng lệnh — lịch sử của bạn và danh sách quy trình xem nó | +| `failproofai jev setup --provider --key-stdin` | Viết cấu hình từ khóa piped trên stdin | +| `failproofai jev setup --provider ` | Giống nhau, yêu cầu khóa ở lời nhắc được che khuất | +| `failproofai jev setup --key-from-env` | Không lưu trữ khóa; đọc `FAILPROOFAI_JEV_API_KEY` mỗi phiên | +| `failproofai jev setup --mode shadow` | Chuyển đổi chế độ (`enforce`, `shadow` hoặc `off`), giữ khóa được lưu trữ | +| `failproofai jev setup --model ` / `--base-url ` | Ghi đè mô hình hoặc cơ sở API; `default` xóa ghi đè | +| `failproofai jev setup --timeout-ms ` | Thay đổi ngân sách per-call | +| `failproofai jev status [--json]` | Cấu hình, quyền và hoạt động gần đây; không bao giờ khóa | +| `failproofai jev test [--json]` | Một yêu cầu trực tiếp: độ trễ và phiên bản đã trả lời | +| `failproofai jev models [--provider ] [--url ] [--json]` | Các id mô hình mà `/models` của điểm cuối báo cáo, đánh dấu cái được cấu hình | +| `failproofai jev remove` | Xóa cấu hình; Jev tắt | \ No newline at end of file diff --git a/docs/vi/policies/jev-cloud.mdx b/docs/vi/policies/jev-cloud.mdx new file mode 100644 index 000000000..b76f4fc39 --- /dev/null +++ b/docs/vi/policies/jev-cloud.mdx @@ -0,0 +1,117 @@ +--- +title: "Jev thông qua FailproofAI Cloud" +description: "Cho phép Jev đánh giá các lệnh gọi công cụ của agents của bạn thông qua FailproofAI Cloud, theo gói của tổ chức của bạn, mà không cần tài khoản hoặc khóa TypeSafe của riêng bạn." +icon: "cloud" +--- + +[Jev](/vi/policies/jev-byok), bộ phân loại của TypeSafe, đọc từng lệnh gọi công cụ so với những gì bạn thực sự yêu cầu và trả lời cùng với các chính sách của bạn, không bao giờ thay thế chúng. Thông qua **FailproofAI Cloud**, một máy được kết nối sử dụng Jev với cùng một khóa mà nó đã kết nối: không cần tài khoản TypeSafe, không cần khóa thứ hai, không cần điểm cuối để cấu hình. Mỗi lệnh gọi được tính phí vào hạn mức gói hiện có của tổ chức bạn. + +Mọi thứ Jev làm đều không thay đổi so với [cài đặt mang theo khóa của riêng bạn](/vi/policies/jev-byok): các chính sách cứng vẫn là quyết định cuối cùng, việc từ chối của một chính sách có thể xem xét được chỉ được xóa khi Jev được hỏi về chính xác những mối quan tâm đó, và bất kỳ lỗi nào cũng quay lại kết quả regex cho lệnh gọi đó. + + +Yêu cầu **failproofai 1.0.8-beta.0** hoặc mới hơn. 1.0.7 không có Jev, mặc dù nó sắp xếp phía trên các phiên bản beta 1.0.7. Nếu không có cấu hình Jev, không có gì thay đổi: hooks chạy các chính sách regex chính xác như họ luôn làm. + + +## Bật nó + +1. **Tạo một khóa với Jev.** Trong bảng điều khiển FailproofAI Cloud, hãy mở **Keys → Create key** và chọn cài đặt **machine**. Nó cấp ba quyền mà một máy cần: `events:add` (gửi hoạt động), `policies:pull` (nhận chính sách) và `jev:evaluate` (Jev, được tính phí vào gói của tổ chức của bạn). Một khóa không thể mang `jev:evaluate` mà không có hai khóa còn lại. +2. **Kết nối máy** với khóa đó: + + ```bash + failproofai config --token + ``` + + Nếu tổ chức của bạn chạy FailproofAI Cloud riêng của nó thay vì cái được lưu trữ, hãy thêm địa chỉ của nó: `--url https://` (hoặc xuất `FAILPROOFAI_CLOUD_URL`). Nếu không có nó, khóa được kiểm tra so với dịch vụ được lưu trữ và kết nối không thành công. Nếu chứng chỉ của máy chủ đó đến từ một CA riêng, hãy cài đặt CA vào kho tin cậy hệ thống của máy (ví dụ với `update-ca-certificates`), không chỉ trong `NODE_EXTRA_CA_CERTS`: daemon gửi sự kiện và lấy chính sách đọc kho hệ thống. Xem [Troubleshooting](/vi/reference/troubleshooting). + +Đó là tất cả. Kết nối lưu trữ khóa và, khi máy **không** có cấu hình Jev, sẽ bật Jev thông qua FailproofAI Cloud ở chế độ **shadow**: Jev được hỏi về mỗi lệnh gọi công cụ được gated và các phán quyết của nó được ghi lại, nhưng kết quả của các chính sách của bạn là những gì được thực thi. Đầu ra nói như vậy: + +```text + Jev on through FailproofAI Cloud, in shadow mode: logged, not enforced (~/.failproofai/jev.json). +``` + +**Với `--no-transcripts`, kết nối không bật Jev.** Jev gửi từng lệnh gọi công cụ được kiểm tra và prompt gần đây tới FailproofAI Cloud, có nhiều hơn một kết nối chỉ quyết định được yêu cầu gửi. Khóa vẫn được lưu trữ, và đầu ra nói rằng Jev có sẵn và cách bật nó: + +```bash +failproofai jev setup --provider failproofai +``` + +Nó cũng không tắt Jev. Nếu `jev.json` của máy đã chạy Jev thông qua FailproofAI Cloud, nó được để nguyên như vậy, và đầu ra nói rằng Jev vẫn gửi từng lệnh gọi công cụ được kiểm tra và prompt gần đây, và rằng `failproofai jev setup --mode off` tắt nó. + + +Kết nối **không bao giờ ghi đè** một `~/.failproofai/jev.json` hiện có. Nếu bạn đã sử dụng điểm cuối Jev của riêng mình, nó tiếp tục được sử dụng, và đầu ra nói rằng tệp được để lại như đã cấu hình — và, khi tệp đó để Jev tắt (từ chối hoặc tắt), nói như vậy và cách khắc phục nó. Để chuyển máy đó sang FailproofAI Cloud, hãy chạy `failproofai jev setup --provider failproofai`. + + +## Shadow, enforce hoặc off + +Bắt đầu ở shadow, xem những gì Jev đã làm trên trang chính sách, sau đó để nó hoạt động: + +```bash +failproofai jev setup --mode enforce # Các phán quyết của Jev được áp dụng: nó có thể xóa một từ chối có thể xem xét được và thêm của riêng nó +failproofai jev setup --mode shadow # Jev được hỏi và ghi lại; kết quả của các chính sách của bạn được thực thi +failproofai jev setup --mode off # giữ lại cấu hình, dừng yêu cầu Jev +``` + +Công tắc tương tự cũng có trong bảng điều khiển cục bộ: **Settings → Jev** có công tắc bật/tắt và shadow/enforce. Nó viết lại chế độ và không có gì khác. Hooks đọc cấu hình trên mỗi lệnh gọi công cụ, vì vậy một thay đổi được áp dụng từ lệnh gọi tiếp theo, không cần khởi động lại. + +## Kiểm tra những gì nó đang làm + +```bash +failproofai jev status +failproofai jev test +``` + +`status` hiển thị nhà cung cấp là **FailproofAI Cloud**, máy chủ Cloud mà máy kết nối đến, chế độ và nguồn khóa là **FailproofAI Cloud connection**, không bao giờ là khóa. Khi `jev.json` của FailproofAI Cloud đã sẵn sàng nhưng Jev không thể chạy, nó nói lý do tại sao: + +| `status` nói | `status --json` | Ý nghĩa | +| --- | --- | --- | +| **off — no Jev key is stored for this machine's FailproofAI Cloud connection** | `key-lacks-jev` | Máy được kết nối, nhưng không có khóa Jev được lưu trữ cho nó: khóa thiếu `jev:evaluate`, hoặc kết nối không thể xác nhận nó. Chạy `failproofai config --token ` lại với cùng một khóa; nếu nó thiếu quyền, hãy sử dụng khóa **machine**. | +| **off — this machine is not connected to FailproofAI Cloud** | `not-connected` | Không có kết nối FailproofAI Cloud trên máy này để khóa Jev thuộc về. | + +Sau `failproofai config --disconnect`, không còn `jev.json` FailproofAI Cloud nữa (trừ khi nó bị tắt, được giữ lại), vì vậy `status` đơn giản báo cáo Jev là tắt. `status --json` mang cùng một sự kiện (`provider: "failproofai"`, `keySource: "cloud"`, `cloudConnected`, `keyCarriesJev`), cũng khi cấu hình bị mất hoặc từ chối. `permissions` luôn là của `jev.json`; một từ chối về `credentials.json` thêm `credentialsPermissions`, và `fix` khi một lệnh khắc phục nó. `test` gửi một yêu cầu trực tiếp và báo cáo độ trễ và phiên bản Jev đã trả lời. Nó thoát 1, và nói như vậy trong tiêu đề của nó, khi câu trả lời đến sau thời gian chờ của hook (hooks sẽ ghi lại `timeout`) hoặc trả lời câu hỏi kiểm tra của nó sai. + +Bảng điều khiển **Settings → Jev** cũng hiển thị **FailproofAI Cloud connection**: máy báo cáo đến tổ chức nào và liệu khóa của nó có mang Jev. Nó được đọc từ các tệp của máy riêng, không có lệnh gọi mạng. + +## Những gì đạt tới trang chính sách + +Máy đã gửi hoạt động hook của nó tới FailproofAI Cloud (`events:add`). Với Jev bật, bản ghi mỗi lệnh gọi được gated cũng nói đánh giá nào đã chạy, Jev quyết định gì, chính sách nào nó xóa, tại sao nó quay lại khi nó làm, độ trễ của nó và mô hình đã trả lời — quyết định, mã và tên, không bao giờ là lệnh hoặc prompt của bạn. Trên trang **Policies** của tổ chức bạn: + +- một lệnh gọi mà phán quyết riêng của Jev quyết định (chế độ enforce) được quy cho **Jev**, và khi kiểm tra quyết định đó đến từ một pack, bản ghi cũng đặt tên cho pack đó và phiên bản của nó; +- ở chế độ shadow, từ chối hoặc cảnh báo của Jev xuất hiện dưới dạng **would-have**, bên cạnh những rollout bạn đang quan sát; +- các chính sách Jev xóa, hoặc sẽ xóa ở chế độ shadow, được đếm trên mỗi chính sách. + +## Khi Jev không thể trả lời + +Mỗi một trong số này quay lại kết quả của các chính sách của bạn cho lệnh gọi đó và được ghi lại với lý do của nó: + +| Lý do | Nguyên nhân | +| --- | --- | +| `out-of-credits` | Tổ chức của bạn đã sử dụng hạn mức gói của nó. | +| `http-401`, `http-403` | Khóa bị thu hồi, hoặc không mang `jev:evaluate`. Kết nối lại với một khóa có. | +| `http-429` | FailproofAI Cloud đang giới hạn tốc độ Jev cho tổ chức của bạn. Cho đến khi thời gian chờ mà nó yêu cầu kết thúc (của nó `Retry-After`, tối đa 60 giây), máy không gửi nó gì và mỗi lệnh gọi quay lại ngay lập tức. Các lệnh gọi được giữ lại bằng cách đó được ghi lại là `http-429`, hoặc là `rate-limited` khi giới hạn tốc độ của máy riêng giữ chúng trước tiên. | +| `http-429` (giới hạn hàng ngày) | Tổ chức của bạn đã sử dụng các lệnh gọi Jev hàng ngày của nó: **10,000 mỗi ngày UTC**, trừ khi ai điều hành FailproofAI Cloud của bạn đặt một giới hạn khác. Mỗi lệnh gọi quay lại cho đến khi số lượng được đặt lại vào 00:00 UTC; máy vẫn hỏi lại tối đa một lần một phút, vì vậy nó nhận được reset trong vòng một phút. `failproofai jev test` nói "Daily Jev limit for this org reached; resets at 00:00 UTC." | +| `http-422` | Jev từ chối yêu cầu của lệnh gọi này, thường là vì lệnh gọi công cụ chứa văn bản dày đặc (base64, hex, minified code) vượt quá ngân sách token của Jev. Lệnh gọi đó quay lại mỗi lần; nó không phải là một outage. | +| `http-502` | Jev không khả dụng ngay bây giờ. | +| `http-503` | Cloud này không thể phục vụ Jev cho tổ chức của bạn: không có gateway mô hình, một tổ chức chưa được cấp phép, hoặc gateway đã hạ. Hỏi quản trị viên của bạn; hooks hỏi lại tối đa một lần một phút. | +| `http-404` | FailproofAI Cloud này chưa phục vụ Jev. | +| `timeout` | Không có câu trả lời trong `timeoutMs` (mặc định 3000). | +| `model-mismatch` | Phiên bản Jev khác 1.13 đã trả lời. | + +## Nơi khóa sống và nơi nó đi + +- Khóa được lưu trữ một lần, trong `~/.failproofai/credentials.json` (`0600`, trong một thư mục chỉ dành cho chủ sở hữu), bên cạnh các thông tin xác thực FailproofAI Cloud khác. `jev.json` không giữ khóa cho tuyến đường này; một khóa viết ở đó làm cho cấu hình không hợp lệ. +- Nếu `credentials.json` mang **bất kỳ** quyền nào cho bất kỳ ai ngoài bạn (nhóm hoặc người khác, đọc hoặc ghi), hoặc thư mục của nó có thể **được ghi** bởi bất kỳ ai ngoài bạn, nó **bị từ chối**, không được đọc, và Jev đang tắt cho đến khi bạn khắc phục: `chmod 600` trên tệp, `chmod 700` trên thư mục (hoặc kết nối lại, sẽ viết lại tệp ở `0600` và chỉ dành cho chủ sở hữu thư mục). Một thư mục mà những người khác chỉ có thể đọc là được; một người họ có thể ghi để họ có thể hoán đổi tệp. +- Khóa chỉ được tính khi kết nối nó đến từ trên máy: một chính sách hoặc thông tin xác thực báo cáo cho cùng một FailproofAI Cloud **với cùng một khóa**, trong cùng một tệp. Một khóa Jev bị bỏ lại mà không có một được bỏ qua, và Jev ở lại tắt. Điều đó xảy ra khi `config --disconnect` của failproofai cũ để lại khóa Jev (nó không biết cần loại bỏ), hoặc khi `config --token` của failproofai cũ kết nối với một khóa khác, trên FailproofAI Cloud có thể thuộc về một tổ chức khác. Để bật Jev trở lại, kết nối lại với một khóa **machine**. +- Khóa chỉ được gửi đến nguồn gốc Cloud mà nó được xác minh chống lại. Một `jev.json` chỉ đến nơi khác bị từ chối. +- **Một agent trên máy có thể đọc nó.** `credentials.json` chỉ dành cho chủ sở hữu, và agent chạy dưới tư cách là chủ sở hữu đó. Đọc các tệp của failproofai được phép cố ý (chỉ thay đổi chúng bị chặn, bởi `block-failproofai-commands`), vì vậy điều duy nhất giữa một agent và tệp này là `block-read-outside-cwd` — một chính sách **reviewable** — và từ một phiên bắt đầu trong thư mục chính của bạn, không có gì. Một khóa có `jev:evaluate` chi tiêu hạn mức Jev của tổ chức bạn (lên đến giới hạn hàng ngày) từ bất cứ nơi nó được sử dụng, vì vậy hãy coi một khóa máy giống như bất kỳ thông tin xác thực chi tiêu nào khác: nếu một agent có thể đã đọc nó, vô hiệu hóa nó trên trang Keys và kết nối lại với một khóa mới. +- Chỉ có các tệp toàn cầu của bạn quyết định điều này. Một kho lưu trữ không thể bật Cloud Jev, chỉ đến nơi khác hoặc cung cấp khóa của nó, và `FAILPROOFAI_JEV_API_KEY` bị bỏ qua cho tuyến đường này. +- Đối với mỗi lệnh gọi Jev đánh giá, một yêu cầu đi tới FailproofAI Cloud, mang những gì [trang bring-your-own-key](/vi/policies/jev-byok#what-leaves-the-machine) liệt kê (bí mật được sửa). FailproofAI Cloud chuyển tiếp nó đến TypeSafe và không ghi lại hoặc giữ nó. + +## Tắt nó + +| Lệnh | Kết quả | +| --- | --- | +| `failproofai jev setup --mode off` | Giữ lại cấu hình; Jev không được hỏi. **Đây là công tắc kéo dài:** kết nối lại không bao giờ viết lại một `jev.json` hiện có, vì vậy Jev ở lại tắt cho đến khi bạn chuyển nó lại bằng `--mode shadow`. | +| `failproofai jev remove` | Xóa `~/.failproofai/jev.json`; Jev tắt — cho đến `failproofai config --token` tiếp theo với một khóa mang `jev:evaluate`, tìm thấy không có `jev.json` và bật Jev lại ở chế độ shadow (trừ khi nó chạy với `--no-transcripts`). Để giữ nó tắt, hãy sử dụng `--mode off`. | +| `failproofai config --disconnect` | Ngắt kết nối máy: khóa bị loại bỏ, và cũng là `jev.json` khi nó đặt tên FailproofAI Cloud và không bị tắt. Một `jev.json` cho điểm cuối của riêng bạn ở lại, và cũng như một cái bị tắt, vì vậy Jev ở lại tắt khi bạn kết nối lại. | + +Từ lệnh gọi công cụ tiếp theo, hooks chạy các chính sách regex chính xác như trước. \ No newline at end of file diff --git a/docs/vi/policies/jev.mdx b/docs/vi/policies/jev.mdx new file mode 100644 index 000000000..293168427 --- /dev/null +++ b/docs/vi/policies/jev.mdx @@ -0,0 +1,45 @@ +--- +title: "Chính sách Jev" +description: "Thêm xem xét trực tiếp của Jev vào các lệnh công cụ được kiểm soát, sau đó kiểm tra trước khi thực thi quyết định của nó." +icon: "shield-check" +--- + +Jev đọc một lệnh công cụ so với những gì người dùng yêu cầu agent làm. Sử dụng nó khi một chính sách so khớp chuỗi ký tự chặn công việc hợp lệ hoặc bỏ lỡ hành động rủi ro cần ngữ cảnh. Nó trả lời cùng với chính sách của bạn tại cổng `PreToolUse` hoặc `PermissionRequest`. Để có điểm số **sau** khi phiên kết thúc, sử dụng [đánh giá Jev](/vi/evaluations/jev). + +## Bắt đầu ở chế độ quan sát + +Cài đặt Failproof AI và gắn hook vào một [harness được hỗ trợ](/vi/reference/harnesses). Sử dụng failproofai 1.0.8-beta.0 hoặc phiên bản mới hơn. + +Failproof AI không được giao kèm với các kiểm tra Jev. Cài đặt chúng dưới dạng một gói, nếu không Jev sẽ không có gì để hỏi và sẽ không bao giờ được gọi: + +```bash +failproofai policies add FailproofAI/jev-policies +``` + +Sau đó chọn cách các yêu cầu tiếp cận Jev: + +| Tuyến đường | Bước đầu tiên | +| --- | --- | +| FailproofAI Cloud | Kết nối bằng khóa **machine** mang `jev:evaluate`. Trên máy không có cấu hình Jev, `failproofai config` bật Jev ở chế độ quan sát. | +| Nhà cung cấp của bạn | Trong bảng điều khiển cục bộ, mở **Settings → Jev**, chọn nhà cung cấp, dán token của nó và chọn **observe**. Hoặc chạy `failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key`. | + +![Cài đặt Jev của bảng điều khiển cục bộ: nhà cung cấp, endpoint, token và chế độ quan sát trước khi bật Jev.](/images/dashboard/jev-settings.png) + +```bash +failproofai jev status +failproofai jev test +``` + +`test` kiểm tra endpoint. Để kiểm tra đường dẫn hook, yêu cầu agent được hook sử dụng công cụ đọc tệp của nó trên `README.md`. Xác nhận rằng lệnh công cụ đó xuất hiện trong phiên, sau đó kiểm tra **Policies → Activity** trong [bảng điều khiển cục bộ](/vi/reference/local-dashboard#review-policy-activity). Số lượng Jev trong `status` sẽ tăng lên. Chế độ quan sát ghi lại những gì Jev sẽ quyết định trong khi kết quả chính sách hiện tại của bạn vẫn áp dụng. + +## Quyết định khi nào để thực thi + +Một chính sách **hard** luôn có quyền nói cuối cùng. Jev chỉ có thể xóa một deny từ một chính sách được đánh dấu rõ ràng là **reviewable** và chỉ khi nó kiểm tra các mối quan tâm được đặt tên của chính sách đó. Xem [policy authority](/vi/policies/authority) trước khi dựa vào một phê duyệt. Jev cũng có thể cảnh báo hoặc từ chối tự mình. Nếu nó không thể trả lời, kết quả chính sách sẽ quyết định lệnh gọi đó. + +Khi kết quả quan sát trông đúng, chuyển sang chế độ thực thi trong **Settings → Jev** hoặc chạy: + +```bash +failproofai jev setup --mode enforce +``` + +Để biết URL nhà cung cấp, khóa Cloud, cấu hình, fallback và dữ liệu được gửi với mỗi yêu cầu, xem [tham chiếu tích hợp Jev](/vi/reference/jev). \ No newline at end of file diff --git a/docs/vi/reference/custom-agents-typescript.mdx b/docs/vi/reference/custom-agents-typescript.mdx new file mode 100644 index 000000000..a7b398573 --- /dev/null +++ b/docs/vi/reference/custom-agents-typescript.mdx @@ -0,0 +1,401 @@ +--- +title: "Các agents tùy chỉnh (TypeScript)" +description: "Cấu hình, danh mục sự kiện, phạm vi và các bộ điều hợp framework cho @failproofai/sdk." +icon: "square-js" +--- + +Tất cả những gì mỗi cài đặt, phương thức và trường làm cho TypeScript SDK. Nếu bạn đang tích hợp lần đầu tiên, hãy bắt đầu với hướng dẫn — trang này dùng để tra cứu. + + + + Cài đặt, tích hợp, các phương thức sự kiện, một ví dụ hoàn chỉnh và các vấn đề thường gặp. + + + Các sự kiện tương tự, định dạng wire tương tự, cùng một spool — từ Python. + + + +Node 20.9 trở lên. ESM và CommonJS. Không có phụ thuộc runtime. + + + SDK này và SDK Python **viết các sự kiện giống nhau vào cùng một spool**. Một fleet với agents Node và agents Python tạo ra một tập hợp phiên, không phải hai, và không có gì trên bảng điều khiển phân biệt chúng. Chọn theo từng dịch vụ, không phải theo công ty. + + +## Cài đặt + +```bash +npm install @failproofai/sdk +``` + +```ts +import * as failproofai from "@failproofai/sdk"; + +await failproofai.agent("planner", { goal: question }, async () => { + const hits = await failproofai.toolCall("web_search", { input: { q } }, () => search(q)); +}); +``` + +Các bộ điều hợp framework được gửi trong chính gói. Các framework là **phụ thuộc ngang hàng tùy chọn** — được khai báo để các phạm vi được hỗ trợ hiển thị rõ ràng, không bao giờ được cài đặt thay bạn, và chỉ được nhập khi bạn gọi `instrument()`. + +## Kết nối daemon Failproof + +Giống như SDK Python: tạo khóa `events:add` trong **Admin → Keys**, sau đó [kết nối daemon](/vi/start/setup#connect-a-machine-to-cloud) trên máy agent. SDK viết vào đĩa; daemon gửi đi. + +## Cấu hình + +```ts +failproofai.configure({ + environment: "production", + flushInterval: 0.5, + baseDir: undefined, +}); +``` + +| Tùy chọn | Chức năng | +| --- | --- | +| `environment` | Nhãn trên mỗi sự kiện — `production`, `staging`, `prod-eu`. Mặc định là `dev`. | +| `flushInterval` | Bộ hẹn giờ ghi vào đĩa thường xuyên bao lâu, tính bằng giây. Mặc định là `0.5`. | +| `baseDir` | Nơi ghi. Mặc định là spool của daemon, đó là những gì bạn muốn trừ khi bạn biết ngược lại. | + +Không có gì được áp dụng trừ khi tất cả được xác thực, vì vậy một lệnh gọi bị từ chối sẽ để lại SDK chính xác như trước đó thay vì có `baseDir` mới và khoảng thời gian cũ. + +Đặt bằng biến môi trường thay thế: + +| Biến | Chức năng | +| --- | --- | +| `AGENTEYE_ENVIRONMENT` | Đặt `environment` mà không cần thay đổi mã. Tùy chọn `configure()` sẽ thắng. | +| `FAILPROOFAI_HOME` | Di chuyển gốc Failproof AI giữ spool. | +| `FAILPROOFAI_SDK_LOG_LEVEL` | `debug`, `info`, `warn` (mặc định), `error`, `silent`. | +| `FAILPROOFAI_SDK_STRICT` | `1` làm cho lỗi tích hợp ném ra thay vì được ghi lại. | +| `FAILPROOFAI_SDK_STRICT_INTEGRATIONS` | `1` làm cho vấn đề tương thích framework ném ra thay vì cảnh báo và tiếp tục. | + + + **Không có dấu phẩy trong `environment`.** Ingest chia trường đó trên dấu phẩy để xây dựng các bộ lọc của nó, và bỏ qua bất kỳ sự kiện nào có nhãn chứa một — vì vậy toàn bộ lần chạy biến mất im lặng. Viết `prod-eu`, không phải `prod,eu`. + + `configure({ environment: "prod,eu" })` ném ra để bạn phát hiện ngay lập tức. `AGENTEYE_ENVIRONMENT` không thể ném ra — không có gì gọi bạn — vì vậy nó cảnh báo một lần và quay lại `dev`. + + +Định tuyến các dòng nhật ký của SDK vào logger của bạn với `failproofai.setLogger({ debug, info, warn, error })`. + +## Tắt + +Các sự kiện được đệm được xả trên `process.on("exit")`. + +Một quá trình bị giết bởi một tín hiệu không bao giờ đến đó, và mặc định của Node cho `SIGTERM` là chấm dứt mà không chạy trình xử lý thoát — vì vậy một agent trong container mất bất cứ thứ gì khoảng thời gian cuối cùng không viết. + + + **SDK này sẽ không cài đặt trình xử lý tín hiệu cho bạn.** Đăng ký một cái thay đổi hành vi của quá trình của bạn: một trình lắng nghe sẽ triệt tiêu chấm dứt mặc định của Node, vì vậy một thư viện thêm một sẽ im lặng ngừng Ctrl-C hoạt động. Thêm của riêng bạn: + + ```ts + for (const signal of ["SIGINT", "SIGTERM"] as const) { + process.once(signal, () => { + failproofai.flushSync(); + process.exit(0); + }); + } + ``` + + +Một script hoặc trình xử lý serverless sống ngắn hạn nên `await failproofai.flush()` trước khi trả về — khoảng thời gian riêng không đảm bảo giao hàng. + +## Danh tính + +Mỗi sự kiện thuộc về một phiên và một agent. **Các phạm vi điền vào cả hai**, vì vậy bạn hiếm khi truyền chúng: + +```ts +await failproofai.session(async () => { + await failproofai.agent("planner", async () => { + failproofai.event.toolUse({ toolName: "search", toolCallId: "c1" }); + }); +}); +``` + +Truyền `sessionId` hoặc `agentId` một cách rõ ràng vẫn hoạt động và thắng. Không có gì được ràng buộc cũng không được chuyển, lệnh gọi ném ra thay vì phát ra một sự kiện Cloud sẽ im lặng loại bỏ. + + + Danh tính đi kèm với `AsyncLocalStorage`. Nó theo `await`, `.then()`, bộ hẹn giờ và bất kỳ callback nào được tạo bên trong phạm vi. Nó **không** theo một callback được lưu trữ trong một lần chạy và được gọi trong một lần khác, hoặc công việc được chuyển qua ranh giới `worker_threads` — bao bọc những cái đó trong `failproofai.propagate()` hoặc các sự kiện của chúng không được gắn kèm. + + +### Phạm vi + +| Phạm vi | Phát hành | Trả lại | +| --- | --- | --- | +| `session(body)` | không có gì — chỉ danh tính | bất cứ điều gì `body` trả lại | +| `agent(id, options?, body)` | `agent_start`, sau đó `agent_end` | bất cứ điều gì `body` trả lại | +| `toolCall(name, options?, body)` | `tool_use`, sau đó `tool_result` | bất cứ điều gì `body` trả lại | + +Một body đồng bộ vẫn đồng bộ: `agent("x", () => 1)` trả lại `1`, không phải một promise. + +`toolCall` ghi lại giá trị được giải quyết của body dưới dạng `output` của công cụ, trừ khi bạn tự gán `call.output`. + + + +| Điều gì đã xảy ra | Sự kiện | `outcome` | +| --- | --- | --- | +| khối đã trả lại | `agent_end` | `"success"`, hoặc `outcome` của bạn | +| khối ném | `error`, sau đó `agent_end` | `"failed"` | +| một `AbortError` | chỉ `agent_end` | `"cancelled"` | + +Lỗi luôn được ném lại. + +Một lỗi công cụ được ghi lại trên lá — `tool_result` với một chuỗi `error` — và phát hành **không** sự kiện `error` cấp chạy. Một cái mà vòng lặp agent bắt được không phải là một lỗi chạy, và một cái lan truyền được báo cáo chính xác một lần, bởi `agent()` bao quanh. + + + + + +Khi công việc không phải là một hàm duy nhất — một phạm vi được mở trong hàm tạo và đóng lại trong quá trình phá dỡ, hoặc một phạm vi trải dài qua luồng điều khiển hiện có: + +```ts +{ + using span = failproofai.agent.open("planner", { goal }); + using call = failproofai.toolCall.open("search", { input: { q } }); + call.call.output = await search(q); +} // tool_result, then agent_end +``` + +Cả hai hình thức đều phát hành các sự kiện giống hệt nhau byte. Ưu tiên hình thức callback: nó chạy bên trong `AsyncLocalStorage.run()`, vì vậy không có gì để tháo dỡ và toàn bộ lớp lỗi "mở ở đây, đóng lại ở đó" là không thể tiếp cận. + +Một khối `using` bắt lỗi của riêng nó báo cáo nó bằng `span.fail(error)` — bộ loại bỏ không có kênh ngoại lệ của riêng nó. + + + +## Danh mục sự kiện + +Cùng 15 phương thức như SDK Python, trong camelCase. Hầu hết đến trong **cặp** — bạn gọi bộ mở, sau đó bộ đóng, và SDK tính thời gian khoảng cách. + +| | Mở | Đóng | +| --- | --- | --- | +| **Agents** | `agentStart` | `agentEnd` | +| | `agentPause` | `agentResume` | +| **Models** | `modelRequest` | `modelResponse` | +| **Tools** | `toolUse` | `toolResult` | +| **Hooks** | `hookTriggered` | `hookCompleted` | +| **Humans** | `humanWait` | `humanInput` | + +Ba cái đứng một mình: `error`, `humanPause`, `humanInterrupt`. + + + +Mỗi phương thức cũng lấy `sessionId` và `agentId`, mà các phạm vi điền cho bạn. Bất cứ điều gì bị bỏ qua được bỏ sót thay vì được gửi dưới dạng JSON `null`. + +| Phương thức | Bắt buộc | Tùy chọn | +| --- | --- | --- | +| `agentStart` | — | `goal`, `parentId` | +| `agentEnd` | — | `outcome`, `summary` | +| `agentPause` | `pauseId` | `reason`, `userId` | +| `agentResume` | `pauseId` | `reason`, `userId` | +| `modelRequest` | — | `model`, `messages`, `system`, `tools`, `requestId` | +| `modelResponse` | — | `model`, `stopReason`, `inputTokens`, `outputTokens`, `content`, `role`, `requestId` | +| `toolUse` | `toolName`, `toolCallId` | `input` | +| `toolResult` | `toolName`, `toolCallId` | `output`, `error` | +| `hookTriggered` | `hookName`, `hookId` | `triggerEvent`, `input` | +| `hookCompleted` | `hookName`, `hookId` | `outcome`, `output`, `error` | +| `error` | `errorType`, `message` | `traceback` | +| `humanWait` | `inputId` | `prompt`, `options`, `reason` | +| `humanInput` | `inputId` | `response` | +| `humanPause` | — | `reason`, `userId` | +| `humanInterrupt` | — | `reason`, `userId`, `atStep` | + +Bất kỳ khóa nào khác bạn thêm sẽ trở thành một trường payload tùy chỉnh. Không gian bất cứ điều gì dành riêng cho framework `fw_*`; một tên va chạm với một trường được khai báo bị từ chối thay vì im lặng ghi đè lên một cột được thúc đẩy. + + + + + **`duration_ms` được tính toán, không được chấp nhận.** Bốn phương thức đóng lại tính thời gian khoảng cách từ bộ mở của họ và từ chối một `duration_ms` được cung cấp bởi người gọi — một thời lượng được báo cáo là không thể giả mạo. + + Các cặp được so khớp trên **phiên** và id, không bao giờ trên agent. Một công cụ được mở dưới `planner` và đóng dưới `worker` vẫn ghép đôi, đó là những gì các lần chạy multi-agent lồng nhau thực sự làm. + + +## Các bộ điều hợp framework + +```ts +await failproofai.instrument(); // bất cứ điều gì nó có thể tìm thấy +await failproofai.instrument("langchain"); // chính xác một +failproofai.uninstrument(); // đặt mọi thứ trở lại +``` + +| Framework | Được hỗ trợ | Cách nó gắn kèm | +| --- | --- | --- | +| **LangChain.js / LangGraph.js** | `@langchain/core` 0.3 – 1.x, LangGraph.js 0.4 – 1.x | `CallbackManager.configure`, vì vậy mỗi `invoke`/`stream`/`batch` được bao phủ mà không cần vượt qua `callbacks:` ở bất cứ nơi nào — hoặc tự truyền `langchainHandler()` và không vá gì. | +| **Vercel AI SDK** | `ai` 4 – 7 | `telemetry()` tại vị trí gọi, hoặc `instrument("ai")` cho toàn bộ quá trình trên `ai` 7 (trên 4–6 đó là tùy chọn — xem bên dưới). | +| **Mastra** | `@mastra/core` 0.20 – 1.x | `Agent.generate`/`.stream`, độ phân giải mô hình của agent và công cụ, và engine chạy/bước quy trình làm việc. | +| **LlamaIndex.TS** | `llamaindex` 0.11.4 – 0.x | `Settings.callbackManager` (đăng ký) cộng với `AgentWorkflow.runStream`, cho các quy trình làm việc chạy và các bước của chúng. | + +Mỗi phạm vi được thử nghiệm so với các bản phát hành framework thực tế, ở cả hai đầu, dưới dạng mô-đun ES và CommonJS, trên mỗi lần chạy CI. + +Ánh xạ là của SDK Python, vì vậy cùng một chương trình vẽ cùng một cây trong một trong hai ngôn ngữ. Một cấu trúc là một **agent** chỉ nếu nó sở hữu một vòng lặp quyết định LLM — một chạy đồ thị hoặc chuỗi, một lệnh gọi AI SDK `generateText`/`streamText`, một agent Mastra, một lần chạy agent LlamaIndex. Một nút LangGraph hoặc một bước quy trình làm việc là một **hook** (`hook_triggered`/`hook_completed`), không bao giờ một agent lồng nhau. Các lệnh gọi mô hình là `model_request`/`model_response` với số lượng token; các lệnh gọi công cụ mang id lệnh gọi công cụ riêng của mô hình. Một lỗi được ghi lại một lần, trên sự kiện nó xảy ra trong. + +Một bộ điều hợp không thành công cài đặt được ghi lại và bỏ qua; những cái khác vẫn cài đặt, bởi vì một LlamaIndex bị hỏng không nên khiến bạn mất LangGraph. + + + `instrument()` không có đối số phát hiện framework bằng cách **giải quyết**, không phải bằng cách nó đã được nhập — Node không hiển thị tương đương Python's `sys.modules` cho ES modules. Một framework bạn đã cài đặt nhưng không sử dụng sẽ được nhập và vá. Đặt tên cái bạn muốn nếu điều đó quan trọng. + + + + Hầu hết các framework này gửi một bản dựng ES-module và một bản dựng CommonJS, mà Node tải dưới dạng hai bản sao không liên quan. Các bộ điều hợp vá bản sao ứng dụng của bạn tải (và bản sao CommonJS cũng nếu một cái đã `require`d nó), vì vậy cả hai hệ thống mô-đun hoạt động. Một framework **được gói vào đầu ra của riêng bạn** bởi esbuild hoặc webpack nằm ngoài tầm với — sử dụng các trình trợ giúp vị trí gọi ở đó: `langchainHandler()`, `telemetry()`, `wrapTool()`. + + +### LangChain không vá + +```ts +import { langchainHandler } from "@failproofai/sdk/langchain"; +await graph.invoke(input, { callbacks: [langchainHandler()] }); +``` + +Trình xử lý hoạt động với hoặc không có `instrument()` và không bao giờ ghi nhật ký kép. `instrument("langchain")` lấy `sessionId`, `captureContent`, `includeChains`, `graphCallbacks` và `captureLimit`, như bộ điều hợp Python; `metadata: { failproofai_sdk_session_id }` trên một lệnh gọi chọn phiên cho lệnh gọi đó. + +### Vercel AI SDK + +AI SDK xuất các hàm thuần túy từ mô-đun ES, và không gian tên mô-đun ES là bất biến theo thông số kỹ thuật — không có nơi để vá. Nó sử dụng các điểm mở rộng mà SDK tự nó giải thích: + +```ts +import { telemetry } from "@failproofai/sdk/ai"; + +const { text } = await generateText({ + model, + prompt, + experimental_telemetry: telemetry({ functionId: "answer-question" }), + // on ai 7, `telemetry: telemetry({ … })` — the same object, the new name +}); +``` + +Đó là tích hợp hoàn chỉnh: một khoảng agent, một cặp yêu cầu/phản hồi mô hình cho mỗi bước với số lượng token, và mỗi lệnh gọi công cụ. Một vị trí gọi hoạt động trên mỗi phiên bản chính — `ai` 4–6 đọc tracer nó mang, `ai` 7 là tích hợp telemetry. + +`instrument("ai")` làm tương tự quy trình toàn cầu **trên `ai` 7**: mỗi lệnh gọi, thông qua danh sách tích hợp telemetry toàn cầu của AI SDK, là cộng gộp và không lấy gì từ danh sách của bất kỳ ai khác. + +**Trên `ai` 4–6, `instrument("ai")` ghi nhật ký không có gì tự nó, và đăng nhập một cảnh báo nói như vậy.** Khe cắm quy trình toàn cầu duy nhất những phiên bản chính có là nhà cung cấp tracer OpenTelemetry toàn cầu — một khe cắm duy nhất OpenTelemetry từ chối giao hàng một khi được đăng ký. Đăng ký của chúng tôi sẽ im lặng từ chối `NodeSDK.start()` của riêng bạn sau trong khởi động và gửi khoảng http/database của bạn đến một tracer không xuất bất cứ điều gì. Sử dụng `telemetry()` tại vị trí gọi hoặc `wrapModel` ở đó. Nếu quá trình không chạy OpenTelemetry của riêng nó, lựa chọn với `instrument("ai", { registerGlobalTracer: true })`: nó sau đó ghi lại mỗi lệnh gọi vượt qua `experimental_telemetry: { isEnabled: true }`, và chỉ lấy khe cắm nếu nó vẫn trống. `registerGlobalTracer: false` giữ mặc định và im lặng cảnh báo. + +Nếu bạn muốn bao bọc mô hình một lần, `wrapModel` chỉ nhìn thấy các lệnh gọi mô hình, bởi vì các lệnh gọi công cụ xảy ra phía trên lớp mô hình. Một mô hình được bao bọc được gọi không có gì xung quanh nó được ghi lại như lần chạy của riêng nó. Một lệnh gọi được phát trực tuyến đóng tuy nhiên luồng dừng — `stop_reason: "cancelled"` khi người tiêu dùng hủy nó, `"error"` với lỗi khi nó thất bại một phần: + +```ts +import { wrapModel } from "@failproofai/sdk/ai"; +const model = await wrapModel(openai("gpt-4o")); +``` + +Sử dụng cả hai là tốt: middleware nhận thấy lệnh gọi đã được ghi lại và trì hoãn, vì vậy mỗi lệnh gọi được ghi lại một lần. + +`functionId` đặt tên khoảng agent. Giữ nó thấp — nó hạ cánh trong `agent_id`, khía cạnh bảng điều khiển chính. + +### Next.js + +`next build` gói các phụ thuộc máy chủ của bạn theo mặc định, và một framework được gói vào bản dựng là một bản sao `instrument()` không thể tiếp cận. Bao bọc cấu hình một lần và gọi `instrument()` từ khe cắm khởi động của Next: + +```ts +// next.config.ts +import { withFailproofai } from "@failproofai/sdk/next"; +export default withFailproofai({ /* your config */ }); +``` + +```ts +// instrumentation.ts +export async function register() { + if (process.env.NEXT_RUNTIME !== "nodejs") return; + const failproofai = await import("@failproofai/sdk"); + await failproofai.instrument(); +} +``` + +`withFailproofai` thêm LangChain, Mastra, LlamaIndex và SDK vào `serverExternalPackages`, giữ danh sách của riêng bạn. Không có nó, `instrument()` cảnh báo một lần cho mỗi framework nó không thể tiếp cận thay vì thất bại im lặng; nếu bạn liệt kê các gói tự nó, đặt `FAILPROOFAI_NEXT_EXTERNALS=1`. Vercel AI SDK và các trình trợ giúp vị trí gọi hoạt động bằng cách. Một tuyến Edge nhận một bản dựng không hoạt động: nhập SDK là an toàn và ghi nhật ký không có gì. + +### Số lượng token trong các lệnh gọi được phát trực tuyến + +API tương thích OpenAI chỉ báo cáo mức sử dụng trên một luồng khi máy khách yêu cầu. LangChain và Vercel AI SDK yêu cầu; đối với LlamaIndex truyền `additionalChatOptions: { stream_options: { include_usage: true } }` đến LLM `OpenAI` của nó, và đối với Mastra xây dựng mô hình với mức sử dụng được bật (ví dụ `createOpenAICompatible({ includeUsage: true })`). Nếu không, các lệnh gọi mô hình được phát trực tuyến không có số lượng token. + +### Runtimes + +Node ≥ 20.9, Bun và Deno — mỗi framework, dưới dạng mô-đun ES và CommonJS, được kiểm tra trên mỗi so với dấu vết của Node. SDK chạy cạnh daemon `failproofaid`, mà gửi những gì nó viết. + +## Agents riêng của bạn — không có framework + +Đối với vòng lặp agent bạn viết chính mình, hoặc một framework không có bộ điều hợp. Bạn phát hành các sự kiện bằng cùng API mà các bộ điều hợp sử dụng ở dưới, vì vậy dấu vết có cùng hình dạng và chất lượng. + +Bạn không cần biết tổ chức agent như thế nào. Mọi agent được xây dựng tay đều có sẵn ba nơi, bất kể chức năng của nó được gọi là gì, và ba cái đó là toàn bộ tích hợp: + +| Nơi | Cái gì để thêm | Phát hành | +| --- | --- | --- | +| Nơi **một lần chạy** bắt đầu và kết thúc | `failproofai.agent("name", { goal }, async () => …)` | `agent_start` / `agent_end` | +| **Hàm duy nhất gọi mô hình** | `event.modelRequest` trước, `event.modelResponse` sau — cả hai nửa, ngay cả khi thất bại | một cặp cho mỗi lần quay mô hình | +| **Hàm duy nhất chạy công cụ** | `failproofai.toolCall(name, { toolCallId, input }, () => run())` | `tool_use` / `tool_result` | + +```ts +async function callModel(messages) { + const requestId = randomUUID(); + const started = Date.now(); + failproofai.event.modelRequest({ model: MODEL, requestId, messages }); + try { + const reply = await client.chat.completions.create({ model: MODEL, messages, tools }); + failproofai.event.modelResponse({ + model: reply.model, requestId, stopReason: reply.choices[0].finish_reason, + inputTokens: reply.usage?.prompt_tokens, outputTokens: reply.usage?.completion_tokens, + duration_ms: Date.now() - started, + }); + return reply.choices[0].message; + } catch (error) { + failproofai.event.modelResponse({ model: MODEL, requestId, stopReason: "error", + error: String(error), duration_ms: Date.now() - started }); + throw error; + } +} + +async function dispatch(call) { + const input = JSON.parse(call.function.arguments); + return failproofai.toolCall(call.function.name, { toolCallId: call.id, input }, + () => runTool(call.function.name, input)); +} + +await failproofai.agent("inventory", { goal: question }, async () => { + for (;;) { + const message = await callModel(messages); + if (!message.tool_calls?.length) return message.content; + for (const call of message.tool_calls) await dispatch(call); + } +}); +``` + +Danh tính là xung quanh: mọi thứ bên trong `agent()` hạ cánh trên lần chạy phiên đó mà không cần lấy id, và không có gì khác trong chương trình thay đổi — bao gồm bất cứ điều gì agent đã viết vào cơ sở dữ liệu của riêng nó. + +- **Một dịch vụ hoặc một worker:** chuyển id yêu cầu hoặc công việc của riêng bạn dưới dạng `sessionId`, vì vậy một phiên trên bảng điều khiển và bản ghi trong nhật ký hoặc cơ sở dữ liệu của riêng bạn là chuỗi tương tự. +- **Sub-agents:** lồng các lệnh gọi `agent()`. Cái bên trong tham gia phiên với cái bên ngoài như `parent_id` của nó. +- **Phát hành các cặp.** Một `modelRequest` không có `modelResponse` là một khoảng bảng điều khiển hiển thị chạy mãi mãi — do đó `catch`. + +[`sdk/typescript/examples/research-agent.ts`](https://github.com/FailproofAI/failproofai/blob/main/sdk/typescript/examples/research-agent.ts) trong kho lưu trữ là phiên bản đầy đủ, chạy được: một vòng lặp công cụ OpenAI thực được tích hợp chính xác như thế này, chạy trong CI trên mỗi thay đổi dưới dạng mô-đun ES và CommonJS. + +## Đánh giá + +```ts +import { Evaluator, EvalResult, Score } from "@failproofai/sdk/evaluator"; + +export const app = new Evaluator({ name: "my-evals", version: "1" }); + +app.eval("tool_success_rate", { version: "1" }, (session) => { + const results = session.eventsOfType("tool_result"); + const failures = results.filter((event) => event.payload.error != null).length; + return new EvalResult({ + score: new Score(results.length === 0 ? 1 : 1 - failures / results.length), + reasoning: `${failures} of ${results.length} tool calls failed`, + }); +}); +``` + +```bash +FAILPROOFAI_EVALUATOR_URL=… FAILPROOFAI_EVALUATOR_TOKEN=… \ + npx failproofai-evaluator ./my-evals.js +``` + +Xem [tham chiếu Evaluator SDK](/vi/reference/evaluator-sdk) cho giao thức, các cài đặt worker và các loại kết quả. + + + **Một đánh giá phải mang lại.** Một hàm đồng bộ không bao giờ trả về khối thread duy nhất Node có, và không có hết thời gian có thể kích hoạt khi nó làm. Viết các đánh giá `async`. + + +## Những gì nó sẽ không làm cho quá trình của bạn + +| | | +| --- | --- | +| **Khóa vòng lặp agent của bạn** | Sự kiện đi vào một hàng đợi trong bộ nhớ; một bộ hẹn giờ viết chúng. Bộ hẹn giờ là `unref`'d, vì vậy nhập gói này không bao giờ dừng một script thoát. | +| **Phát triển không có ràng buộc** | Hàng đợi được giới hạn bởi số và byte đo. Qua bất kỳ, các sự kiện cũ nhất bị loại bỏ và một cảnh báo nói như vậy — một mất điện telemetry không được trở thành một sát nhân OOM. | +| **Lấy quá trình xuống** | Một sự kiện không thể mã hóa bị loại bỏ một mình, không phải lô xung quanh nó. Một getter ném, một tham chiếu tròn, một `BigInt`, một đại diện thay thế một mình: mỗi được xử lý thay vì lan truyền. | +| **Để lại một lô nửa ghi** | Nội dung được `fsync`ed trước một đổi tên nguyên tử, thư mục được `fsync`ed sau, và một ghi thất bại làm sạch tệp tạm thời của nó. | +| **Để lại bảng điểm có thể đọc được** | Lô là `0600` bên trong một thư mục `0700`. Họ mang mục tiêu, lời nhắc, đối số công cụ và đầu ra công cụ. | +| **Thuyền thông tin xác thực** | Khóa API, token, JWT, tiêu đề nhà cung cấp và phép gán hình dạng bí mật được làm sạch trước khi byte đến đĩa. Daemon làm sạch lại trước khi tải lên. | \ No newline at end of file diff --git a/docs/vi/reference/jev-cloud.mdx b/docs/vi/reference/jev-cloud.mdx new file mode 100644 index 000000000..8a1f67e4a --- /dev/null +++ b/docs/vi/reference/jev-cloud.mdx @@ -0,0 +1,136 @@ +--- +title: "Jev thông qua FailproofAI Cloud" +description: "Khóa máy trên cloud, trạng thái kết nối, giới hạn và hành vi lỗi cho việc xem xét chính sách Jev trực tiếp." +icon: "cloud" +--- + +Đây là tham khảo tuyến đường Cloud cho [chính sách Jev](/vi/policies/jev). Jev, bộ phân loại của TypeSafe, đọc từng lệnh gọi công cụ so với những gì bạn thực sự yêu cầu và trả lời cùng với chính sách của bạn, không bao giờ thay thế chúng. Thông qua **FailproofAI Cloud**, một máy kết nối sử dụng Jev với cùng một khóa mà nó đã kết nối: không cần tài khoản TypeSafe, không cần khóa thứ hai, không cần cấu hình điểm cuối. Mỗi lệnh gọi được tính vào phân bổ kế hoạch hiện có của tổ chức bạn. + +Mọi thứ Jev làm không thay đổi từ [thiết lập mang khóa của riêng bạn](/vi/reference/jev-providers): chính sách cứng vẫn cuối cùng, việc từ chối của chính sách có thể xem xét chỉ được xóa khi Jev được hỏi về chính xác mối quan tâm đó, và bất kỳ lỗi nào đều quay lại kết quả regex cho lệnh gọi đó. + + +Yêu cầu **failproofai 1.0.8-beta.0** hoặc mới hơn. Phiên bản 1.0.7 không có Jev, mặc dù nó được sắp xếp trên các beta 1.0.7. Nếu không có cấu hình Jev, không có gì thay đổi: các hook chạy chính sách regex chính xác như trước đây. + + +## Trước khi bắt đầu + +Cài đặt Failproof AI trên máy nơi agent của bạn chạy và đính kèm các hook của nó vào một [harness được hỗ trợ](/vi/reference/harnesses). Nếu bạn bắt đầu từ đầu, hãy làm theo [hướng dẫn bắt đầu nhanh](/vi/start/quickstart) thông qua cài đặt hook. Kiểm tra CLI đã cài đặt bằng `failproofai --version`; cập nhật nếu nó trước Jev. Bạn cũng cần truy cập vào trang **Administration → Keys** của tổ chức để tạo khóa máy. + +Jev xem xét các lệnh gọi công cụ được đặt tên ở cổng `PreToolUse` hoặc `PermissionRequest`. Nó không xem xét mọi sự kiện trong một phiên. Để thấy Jev xóa việc từ chối chính sách, bạn cần một chính sách đã cài đặt được đánh dấu [có thể xem xét](/vi/policies/authority); tất cả các lần từ chối chính sách khác vẫn cuối cùng. + +## Bật nó lên + +1. **Tạo khóa với Jev.** Trong bảng điều khiển FailproofAI Cloud, hãy mở **Administration → Keys → Create key** và chọn cài đặt **machine**. Nó cấp ba quyền mà máy cần: `events:add` (gửi hoạt động), `policies:pull` (nhận chính sách) và `jev:evaluate` (Jev, được tính vào kế hoạch của tổ chức bạn). Một khóa không thể mang `jev:evaluate` mà không có hai khóa kia. +2. **Kết nối máy** với khóa đó. Đọc bí mật một lần của nó ở lời nhắc, sau đó chạy lệnh thiết lập đầy đủ: + + ```bash + read -rs FAILPROOFAI_CLOUD_TOKEN && export FAILPROOFAI_CLOUD_TOKEN + failproofai config + ``` + + `failproofai config` cài đặt daemon, đính kèm hook cho các CLI agent mà nó tìm thấy, và kết nối máy. Biến môi trường giữ khóa ra khỏi các đối số của lệnh và lịch sử shell của bạn. Nếu harness của bạn được cài đặt sau này, [đính kèm nó một cách rõ ràng](/vi/start/quickstart). + + Nếu tổ chức bạn chạy FailproofAI Cloud của riêng mình thay vì cái được lưu trữ, hãy thêm địa chỉ của nó: `--url https://` (hoặc xuất `FAILPROOFAI_CLOUD_URL`). Nếu không có nó, khóa được kiểm tra dựa trên dịch vụ được lưu trữ và kết nối không thành công. Nếu chứng chỉ của máy chủ đó đến từ CA riêng, hãy cài đặt CA trong cửa hàng tin tưởng hệ thống của máy (ví dụ với `update-ca-certificates`), không chỉ trong `NODE_EXTRA_CA_CERTS`: daemon gửi sự kiện và lấy chính sách đọc cửa hàng hệ thống. Xem [Khắc phục sự cố](/vi/reference/troubleshooting). + +Đó là tất cả. Kết nối lưu trữ khóa và, khi máy **không** có cấu hình Jev, bật Jev thông qua FailproofAI Cloud ở chế độ **observe**: khi một gói cung cấp nó kiểm tra, Jev được hỏi về mọi lệnh gọi công cụ được gating và các bản án của nó được ghi lại, nhưng kết quả của chính sách của bạn là những gì được thực thi. Đầu ra nói như vậy: + +```text + Jev on through FailproofAI Cloud, in observe mode: logged, not enforced (~/.failproofai/jev.json). +``` + +Jev vẫn không hỏi gì cho đến khi một gói cung cấp nó kiểm tra. Failproof AI không vận chuyển bất kỳ; trong khi không có gói được cài đặt khai báo bất kỳ, đầu ra thêm một dòng nói như vậy, và `failproofai jev status` lặp lại. Cài đặt chúng bằng: + +```bash +failproofai policies add FailproofAI/jev-policies +``` + +**Với `--no-transcripts`, kết nối không bật Jev.** Jev gửi từng lệnh gọi công cụ được kiểm tra và lời nhắc gần đây tới FailproofAI Cloud, đây là nhiều hơn kết nối chỉ quyết định được yêu cầu gửi. Khóa vẫn được lưu trữ, và đầu ra nói Jev khả dụng và cách bật nó: + +```bash +failproofai jev setup --provider failproofai +``` + +Nó cũng không bật Jev **tắt**. Nếu máy `jev.json` đã chạy Jev thông qua FailproofAI Cloud, nó sẽ được để nguyên như vậy, và đầu ra nói Jev vẫn gửi từng lệnh gọi công cụ được kiểm tra và lời nhắc gần đây, và `failproofai jev setup --mode off` tắt nó. + + +Kết nối **không bao giờ ghi đè** một `~/.failproofai/jev.json` hiện có. Nếu bạn đã sử dụng điểm cuối Jev của riêng mình, nó tiếp tục được sử dụng, và đầu ra nói tệp được để lại như được cấu hình — và, khi tệp đó để Jev tắt (bị từ chối hoặc tắt), nó nói như vậy và cách khắc phục. Để chuyển máy đó sang FailproofAI Cloud, hãy chạy `failproofai jev setup --provider failproofai`. + + +## Quan sát, thực thi hoặc tắt + +Bắt đầu bằng cách quan sát, xem những gì Jev sẽ làm trên trang chính sách, sau đó để nó hoạt động: + +```bash +failproofai jev setup --mode enforce # Jev's verdicts apply: it may clear a reviewable deny and add its own +failproofai jev setup --mode observe # Jev is asked and logged; your policies' result is enforced +failproofai jev setup --mode off # keep the config, stop asking Jev +``` + +Cùng một công tắc nằm trong bảng điều khiển cục bộ: **Settings → Jev** có công tắc bật/tắt và quan sát/thực thi. Nó viết lại chế độ và không có gì khác. Các hook đọc cấu hình trên mọi lệnh gọi công cụ, vì vậy một thay đổi áp dụng từ lệnh tiếp theo, không cần khởi động lại. + +## Kiểm tra những gì nó đang làm + +```bash +failproofai jev status +failproofai jev test +``` + +`status` hiển thị nhà cung cấp là **FailproofAI Cloud**, máy chủ Cloud mà máy đã kết nối, chế độ, và nguồn khóa là **FailproofAI Cloud connection**, không bao giờ là khóa. Khi một `jev.json` của FailproofAI Cloud đang có nhưng Jev không thể chạy, nó nói tại sao: + +| `status` nói | `status --json` | Ý nghĩa | +| --- | --- | --- | +| **off — no Jev key is stored for this machine's FailproofAI Cloud connection** | `key-lacks-jev` | Máy được kết nối, nhưng không có khóa Jev được lưu trữ cho nó: khóa thiếu `jev:evaluate`, hoặc kết nối không thể xác nhận nó. Chạy lại `failproofai config` với khóa trong `FAILPROOFAI_CLOUD_TOKEN`; nếu nó thiếu quyền, hãy sử dụng khóa **machine**. | +| **off — this machine is not connected to FailproofAI Cloud** | `not-connected` | Không có kết nối FailproofAI Cloud trên máy này để khóa Jev thuộc về. | + +Sau `failproofai config --disconnect` không còn có `jev.json` của FailproofAI Cloud nữa (trừ khi nó bị tắt, được giữ lại), nên `status` chỉ báo cáo Jev là tắt. `status --json` mang các sự kiện tương tự (`provider: "failproofai"`, `keySource: "cloud"`, `cloudConnected`, `keyCarriesJev`), cũng khi cấu hình vắng mặt hoặc bị từ chối. `permissions` luôn là của `jev.json`; một sự từ chối về `credentials.json` thêm `credentialsPermissions`, và `fix` khi một lệnh khắc phục nó. `test` gửi một yêu cầu trực tiếp và báo cáo độ trễ và phiên bản Jev đã trả lời của nó. Nó thoát 1 và nói như vậy trong tiêu đề của nó, khi câu trả lời đến sau thời gian chờ của hook (hook sẽ ghi lại `timeout`) hoặc trả lời sai câu hỏi kiểm tra của nó. + +Bảng điều khiển **Settings → Jev** cũng hiển thị **FailproofAI Cloud connection**: tổ chức nào mà máy báo cáo vào và liệu khóa của nó có mang Jev. Nó được đọc từ các tệp của chính máy, không có lệnh gọi mạng. + +## Xác minh một cuộc gọi thực tế + +Bắt đầu một phiên mới trong agent được gating. Yêu cầu nó sử dụng công cụ đọc tệp của nó trên `README.md` và báo cáo tiêu đề. Xác nhận rằng phiên chứa lệnh gọi công cụ đó, sau đó chạy lại `failproofai jev status`: số lượng cuộc gọi được đánh giá gần đây của nó sẽ tăng. Mở **Policies → Activity** trong [bảng điều khiển cục bộ](/vi/reference/local-dashboard#review-policy-activity) để kiểm tra bản án Jev của lệnh gọi đó và chế độ. Trong Cloud, trang **Policies** của tổ chức hiển thị kết quả Jev cho hoạt động được cung cấp. Ở chế độ quan sát, bản án được ghi lại là **would-have** và kết quả chính sách vẫn quyết định lệnh gọi. Một sự thanh toán chỉ xuất hiện khi một chính sách có thể xem xét khớp và Jev xóa các kiểm tra được đặt tên của nó. + +## Những gì đến trang chính sách + +Máy đã gửi hoạt động hook của nó tới FailproofAI Cloud (`events:add`). Với Jev bật, bản ghi của mỗi cuộc gọi được gating cũng nói nhà đánh giá nào đã chạy, Jev quyết định gì, chính sách nào nó xóa, tại sao nó quay lại khi nó làm, độ trễ của nó và mô hình đã trả lời — quyết định, mã và tên, không bao giờ là lệnh hoặc lời nhắc của bạn. Trên trang **Policies** của tổ chức bạn: + +- một cuộc gọi mà bản án của chính Jev quyết định (chế độ thực thi) được quy cho **Jev**, và khi kiểm tra quyết định đến từ một gói, bản ghi cũng đặt tên cho gói đó và phiên bản của nó; +- ở chế độ quan sát, việc từ chối hoặc cảnh báo của Jev xuất hiện là một **would-have**, bên cạnh các triển khai bạn đang quan sát; +- các chính sách Jev xóa hoặc sẽ xóa ở chế độ quan sát, được tính trên mỗi chính sách. + +## Khi Jev không thể trả lời + +Mỗi một trong những điều này đều quay lại kết quả của chính sách của bạn cho lệnh gọi đó, và được ghi lại với lý do của nó: + +| Lý do | Nguyên nhân | +| --- | --- | +| `out-of-credits` | Tổ chức bạn đã sử dụng phân bổ kế hoạch của nó. | +| `http-401`, `http-403` | Khóa đã bị thu hồi, hoặc không mang `jev:evaluate`. Kết nối lại với một khóa có. | +| `http-429` | FailproofAI Cloud đang giới hạn tốc độ Jev cho tổ chức bạn. Cho đến khi lần chờ nó yêu cầu kết thúc (nó `Retry-After`, tối đa 60 giây), máy không gửi cho nó gì và mọi cuộc gọi đều quay lại ngay lập tức. Các cuộc gọi được giữ lại theo cách đó được ghi lại là `http-429`, hoặc `rate-limited` khi giới hạn tốc độ của chính máy giữ chúng trước. | +| `http-429` (giới hạn hàng ngày) | Tổ chức bạn đã sử dụng các cuộc gọi Jev hàng ngày của nó: **10,000 trên một ngày UTC**, trừ khi người vận hành FailproofAI Cloud của bạn đã đặt một giới hạn khác. Mọi cuộc gọi đều quay lại cho đến khi số lượng được đặt lại lúc 00:00 UTC; máy vẫn hỏi lại nhiều nhất một lần một phút, vì vậy nó chọn lại trong vòng một phút. `failproofai jev test` nói "Daily Jev limit for this org reached; resets at 00:00 UTC." | +| `http-422` | Jev từ chối yêu cầu của cuộc gọi này, thường vì lệnh gọi công cụ chứa văn bản dày đặc (base64, hex, mã nhỏ nhất) vượt quá ngân sách token của Jev. Cuộc gọi đó quay lại mỗi lần; nó không phải là một sự cố. | +| `http-502` | Jev hiện không khả dụng. | +| `http-503` | Cloud này không thể phục vụ Jev cho tổ chức bạn: không có cổng mô hình, tổ chức chưa được cung cấp, hoặc cổng đang ngừng hoạt động. Hỏi quản trị viên của bạn; hook hỏi lại nhiều nhất một lần một phút. | +| `http-404` | FailproofAI Cloud này chưa phục vụ Jev. | +| `timeout` | Không có câu trả lời trong `timeoutMs` (mặc định 3000). | +| `model-mismatch` | Một phiên bản Jev khác ngoài 1.13 đã trả lời. | + +## Khóa sống ở đâu, và nó đi đâu + +- Khóa được lưu trữ một lần, trong `~/.failproofai/credentials.json` (`0600`, trong một thư mục chỉ chủ sở hữu), bên cạnh các thông tin đăng nhập FailproofAI Cloud khác. `jev.json` không giữ khóa cho tuyến đường này; một cái được viết ở đó làm cho cấu hình không hợp lệ. +- Nếu `credentials.json` mang **bất kỳ** quyền cho bất kỳ ai khác ngoài bạn (nhóm hoặc khác, đọc hoặc viết), hoặc thư mục của nó có thể được **viết** bởi bất kỳ ai ngoài bạn, nó được **từ chối**, không được đọc, và Jev tắt cho đến khi bạn sửa nó: `chmod 600` trên tệp, `chmod 700` trên thư mục (hoặc kết nối lại, được viết lại tệp ở `0600` và làm cho thư mục chỉ chủ sở hữu). Một thư mục mà những người khác chỉ có thể đọc là tốt; một cái mà họ có thể viết cho phép họ hoán đổi tệp. +- Khóa chỉ được tính toán khi kết nối mà nó đến từ trên máy: chính sách hoặc thông tin đăng nhập báo cáo cho cùng một FailproofAI Cloud **với cùng một khóa**, trong cùng một tệp. Một khóa Jev bị bỏ lại mà không có một cái bị bỏ qua, và Jev vẫn tắt. Điều đó xảy ra khi failproofai cũ hơn của `config --disconnect` để lại khóa Jev tại chỗ (nó không biết xóa nó), hoặc khi failproofai cũ hơn của `config --token` kết nối với khóa khác, trên FailproofAI Cloud có thể thuộc về tổ chức khác. Để bật Jev trở lại, kết nối lại với khóa **machine**. +- Khóa chỉ được gửi tới nguồn gốc Cloud mà nó đã được xác minh lại. Một `jev.json` chỉ đến nơi khác bị từ chối. +- **Một agent trên máy có thể đọc nó.** `credentials.json` chỉ chủ sở hữu, và agent chạy với chủ sở hữu đó. Đọc các tệp của failproofai được cho phép có mục đích (chỉ thay đổi chúng bị chặn, bởi `block-failproofai-commands`), vì vậy điều duy nhất giữa agent và tệp này là `block-read-outside-cwd` — một chính sách **có thể xem xét** — và từ một phiên bắt đầu trong thư mục chính của bạn, không có gì. Một khóa với `jev:evaluate` chi tiêu cho phép Jev của tổ chức bạn (cho đến giới hạn hàng ngày) từ bất kỳ nơi nó được sử dụng, nên xử lý khóa máy giống như bất kỳ thông tin đăng nhập chi tiêu nào: nếu một agent có thể đã đọc nó, hãy vô hiệu hóa nó trên trang Khóa và kết nối lại với một cái mới. +- Chỉ các tệp toàn cầu của bạn quyết định điều này. Một kho lưu trữ không thể bật Cloud Jev, chỉ nó đến nơi khác hoặc cung cấp khóa của nó, và `FAILPROOFAI_JEV_API_KEY` bị bỏ qua cho tuyến đường này. +- Đối với mỗi cuộc gọi Jev đánh giá, một yêu cầu sẽ đi tới FailproofAI Cloud, mang những gì trang [mang khóa của riêng bạn](/vi/reference/jev-providers#what-leaves-the-machine) liệt kê (bí mật được sửa đổi). FailproofAI Cloud chuyển tiếp nó tới TypeSafe và không ghi lại hoặc giữ nó. + +## Tắt nó đi + +| Lệnh | Kết quả | +| --- | --- | +| `failproofai jev setup --mode off` | Giữ cấu hình; Jev không được hỏi. **Đây là công tắc kéo dài:** kết nối lại không bao giờ viết lại `jev.json` hiện có, vì vậy Jev vẫn tắt cho đến khi bạn bật lại nó bằng `--mode observe`. | +| `failproofai jev remove` | Xóa `~/.failproofai/jev.json`; Jev tắt — cho đến `failproofai config --token` tiếp theo với một khóa mang `jev:evaluate`, tìm thấy không `jev.json` và bật Jev lại ở chế độ quan sát (trừ khi nó chạy với `--no-transcripts`). Để giữ nó tắt, hãy sử dụng `--mode off`. | +| `failproofai config --disconnect` | Ngắt kết nối máy: khóa bị xóa, và cũng là `jev.json` khi nó đặt tên FailproofAI Cloud và không bị tắt. Một `jev.json` cho điểm cuối của riêng bạn vẫn ở, và cũng là một cái bị tắt, nên Jev vẫn tắt khi bạn kết nối lại. | + +Từ lệnh gọi công cụ tiếp theo, các hook chạy chính sách regex chính xác như trước đây. \ No newline at end of file diff --git a/docs/vi/reference/jev-evaluations.mdx b/docs/vi/reference/jev-evaluations.mdx new file mode 100644 index 000000000..d628ffaa3 --- /dev/null +++ b/docs/vi/reference/jev-evaluations.mdx @@ -0,0 +1,88 @@ +--- +title: "Tham chiếu đánh giá Jev" +description: "Các loại câu hỏi, điểm được hiệu chuẩn, giới hạn và backfill cho đánh giá phiên Jev." +icon: "list-checks" +--- + +Trang này mô tả các hình dạng câu hỏi và quy tắc chấm điểm đằng sau [đánh giá Jev](/vi/evaluations/jev). Một số câu hỏi yêu cầu một mô hình để *đọc* cuộc trò chuyện, nhưng không phải để *viết* về nó. "Khách hàng có thể hiện sự khẩn cấp?" có hai câu trả lời. "Họ bực bội đến mức nào?" có một vài câu, theo thứ tự. Bạn biết mọi câu trả lời trước khi hỏi. + +Một **đánh giá phân loại** dành cho chính xác những câu hỏi đó. Bạn viết câu hỏi và các câu trả lời mà nó có thể đưa ra, và một mô hình nhỏ được xây dựng để phân loại sẽ trả về một con số được hiệu chuẩn — không bao giờ là văn bản tự do. + + +Giống như một thẩm phán, một đánh giá phân loại tốn một lần gọi mô hình cho mỗi phiên. Không giống như thẩm phán, đó là một mô hình nhỏ, có mục đích duy nhất thay vì một mô hình chung chung, do đó nó nhanh hơn và rẻ hơn — nhưng nó sẽ không bao giờ giải thích chính nó. Nếu bạn cần lý do, hãy sử dụng [judge](/vi/evaluations/judge). + + +## Tôi muốn cái nào? + +| Câu hỏi | Sử dụng | +| --- | --- | +| Có bao nhiêu lần gọi công cụ? | code | +| Phiên có dưới 30 giây không? | code | +| Khách hàng có thể hiện sự khẩn cấp? | **phân loại** | +| Đội nào sẽ xử lý điều này: thanh toán, kỹ thuật hay bán hàng? | **phân loại** | +| Khách hàng bực bội đến mức nào? | **phân loại** | +| Câu trả lời có thực sự chính xác không? | **judge** | +| Nó có tuân theo chính sách escalation của chúng tôi không, và bạn nghĩ sao? | **judge** | + +Quy tắc chung: **có thể đếm được → code, các câu trả lời bạn có thể liệt kê → phân loại, cần giải thích → judge.** + +Bạn không phải quyết định ngay từ đầu. Mô tả những gì bạn muốn đo lường và trợ lý sẽ chọn, cho bạn biết nó chọn cái nào và tại sao, và bạn có thể chuyển đổi. + +## Hai loại câu hỏi + +### `noul` — điều này có đúng không? + +Hai câu trả lời, và bạn mô tả cả hai. Kết quả là xác suất mà mô tả "đúng" phù hợp: + +```json +{ + "instructions": "Did the assistant promise a refund without first checking the refund policy?", + "criteria": { + "true": "A refund was promised or issued with no prior policy check or approval", + "false": "No refund was promised, or every refund followed a policy check" + } +} +``` + +Mô tả cả hai phía. "Không thể hiện sự khẩn cấp" là một câu trả lời thực sự và nói lên điều đó làm cho phía kia sắc nét hơn. + +### `score` — bao nhiêu trong số này? + +Một thang đo có thứ tự, **tệ nhất trước tiên**. Kết quả là nơi phiên đó xuất hiện trên nó, được chuẩn hóa lại thành 0–1: + +```json +{ + "instructions": "How frustrated is the customer?", + "criteria": ["Calm", "Frustrated", "Very angry"] +} +``` + +**Một thang đo có ba đến năm cấp độ, và chúng tất cả phải khác nhau.** Cả hai giới hạn được đo lường, không phải theo kiểu dáng: + +- **Hai cấp độ** sụp đổ thành những gì `noul` đã làm tốt hơn, và **nhiều hơn năm** làm cho mô hình hạn chế về phía giữa thay vì cam kết. Câu hỏi tương tự trong phiên tương tự được chấm 0.00 với hai cấp độ, 0.01 với ba, và 0.55 với mười. +- **Các cấp độ lặp lại** chia câu trả lời một cách tùy ý giữa chúng. Một phiên rõ ràng là tức giận được chấm 1.00 so với `["Calm", "Frustrated", "Very angry"]` và 0.66 so với `["Angry", "Angry", "Angry"]` — một con số được hình thành tốt không có ý nghĩa. + +Các thể loại không có thứ tự — "thanh toán, kỹ thuật hoặc bán hàng" — không phải là một thang đo. Hỏi chúng dưới dạng `noul` cho mỗi thể loại, hoặc sử dụng judge. + +## Đọc các kết quả + +Một phân loại tạo ra một **điểm** từ 0 đến 1, giống hệt như judge, vì vậy nó lập biểu đồ, lọc và kích hoạt cảnh báo theo cách tương tự. Hai khác biệt đáng lưu ý: + +- **Không có lý do.** Trường là trống, cố ý. Mô hình này không giải thích chính nó, và phát minh ra giải thích sẽ là sáng tác thay vì một tính năng. +- **Sự không chắc chắn được dán nhãn.** Một câu hỏi `score` báo cáo độ tin cậy riêng của nó, và một kết quả mà mô hình không chắc chắn được gắn thẻ `low_confidence` — vì vậy "cái nào trong số này cần một người bình nhận xét" là một bộ lọc chứ không phải một phỏng đoán. Một câu hỏi `noul` không báo cáo độ tin cậy, vì vậy nó không bao giờ được gắn thẻ. + +Các phiên rất dài được đọc theo đoạn trích và kết hợp lại. Khi một phiên quá dài để đọc đầy đủ, kết quả cho biết bao nhiêu lượt được bỏ qua — bạn sẽ không bao giờ thấy một phán quyết được đưa ra cho một phần của phiên được trình bày như một phán quyết được đưa ra cho tất cả nó. + +## Giới hạn + +- **Ba đến năm cấp độ thang đo, tất cả khác biệt.** Xem ở trên; cả hai giới hạn được thực thi tại thời điểm tác giả. +- **Một câu hỏi cho mỗi đánh giá.** Hỏi hai điều và bạn sẽ nhận được hai đánh giá, đó cũng là những gì bạn muốn trên biểu đồ. +- **Chỉnh sửa câu hỏi công bố một phiên bản mới.** Các điểm cũ và mới không thể so sánh được, do đó chúng được giữ riêng biệt thay vì trộn lẫn thành một đường xu hướng. +- **Một phân loại luôn tạo ra một điểm**, không bao giờ là một chỉ số hoặc một khẳng định. +- **Không có lý do**, như ở trên. Nếu một con số sẽ làm cho ai đó hỏi "tại sao?", hãy viết judge thay vào đó. + +## Kiểm tra và backfill + +Không giống như judge, một đánh giá phân loại **có thể** được kiểm tra trước khi triển khai — [kiểm tra nó](/vi/evaluations/test) dựa trên các phiên thực tế theo cách bạn sẽ làm với đánh giá code, và đọc các điểm trước khi bất cứ điều gì được triển khai trực tiếp. + +Nó cũng có thể được [backfill](/vi/evaluations/deploy#score-sessions-you-already-have) trên các phiên bạn đã có. Nó tốn một lần gọi mô hình cho mỗi phiên, vì vậy hãy giới hạn cửa sổ một cách cố ý thay vì phát lại mọi thứ. \ No newline at end of file diff --git a/docs/vi/reference/jev-intent.mdx b/docs/vi/reference/jev-intent.mdx new file mode 100644 index 000000000..2809216f1 --- /dev/null +++ b/docs/vi/reference/jev-intent.mdx @@ -0,0 +1,112 @@ +--- +title: "Jev intent capture" +description: "Những event harness nào cho phép evaluator Jev biết con người đã yêu cầu gì, trường nào chứa văn bản, điều gì không bao giờ được tính, và rủi ro khi tin tưởng vào prompt do harness cung cấp." +icon: "message-square-quote" +--- + +Khi bạn cấu hình [Jev policy review](/vi/policies/jev), evaluator sẽ đánh giá từng lệnh gọi công cụ được quản lý so với **những gì con người yêu cầu**, không phải so với bất kỳ văn bản nào mà harness đặt trước agent. Một câu trả lời như "có, force-push nó" có thể vượt qua một chính sách **reviewable** — đây chính là toàn bộ ý tưởng của evaluator, bởi vì một regex không thể đọc yêu cầu sẽ chặn một phần ba công việc thực tế. + +Văn bản đó đến từ một nơi duy nhất: **prompt mà chính harness gửi cho hook tại sự kiện prompt-submit**. Failproof AI ghi lại phần mà con người đã nhập — bỏ đi phần bao quanh của harness, xóa bí mật, giới hạn — vào một tệp `0600` trong thư mục trạng thái của nó. Không có gì trên disk được tham khảo: bảng điểm phiên là một tệp mà agent có thể ghi đè bằng một lệnh, vì vậy nó không bao giờ được hỏi ai đã viết prompt. + +## Rủi ro mà điều này chấp nhận, rõ ràng + +Một agent có thể chạy lệnh có thể làm cho harness gửi một prompt. `claude -p "…"`, `codex exec`, `copilot -p`, `cursor-agent -p`, `devin -p`, `droid -p`, `goose run -t` và `pi -p` đều kích hoạt cùng một sự kiện prompt-submit, với cùng một payload, như một người nhập, trong một phiên con mà agent kiểm soát. Nó cũng có thể chạy nhị phân hook của chính Failproof AI và cung cấp cho nó một payload mà nó viết. Không có gì bên trong Failproof AI có thể phân biệt cả hai — cả hai là cùng một chương trình đọc stdin. + +**Vì vậy, một agent có shell có thể giả mạo sự đồng ý của riêng nó.** Đó là một quyết định cố ý, được thực hiện vào 2026-09-23, và đây là cả hai mặt của nó: + +- **Nó mua những gì.** Phương án thay thế đã được xây dựng và đo lường: yêu cầu một trường trong đó harness đặt tên một con người là tác giả của prompt, và không ghi lại gì ngoài ra. Không có harness vận chuyển nào gửi trường như vậy, vì vậy phiên bản đó đã ghi lại **không có gì, trên mọi harness** — Jev đã đánh giá mọi lệnh gọi mà không có ý định được nêu rõ và không bao giờ có thể xóa một chính sách duy nhất. Một lệnh capture không bao giờ kích hoạt không phải là một sản phẩm an toàn hơn, nó không phải là sản phẩm. +- **Nó không thể làm được.** Một prompt được ghi lại chỉ bao giờ cũng xóa bỏ một chính sách đã được đánh dấu **reviewable**. Một chính sách **hard** không bao giờ bị xóa bởi bất cứ điều gì Jev nói, vì vậy một prompt giả mạo không bao giờ có thể biến một hard deny thành allow — và bỏ qua hook không mang lại lợi thế cho agent: harness gọi Failproof AI cho lệnh gọi công cụ một cách độc lập. +- **Nó có thể làm được, ở kích thước đầy đủ.** Tệ nhất nó có thể làm là xóa bỏ một trong mười lăm chính sách reviewable được xây dựng sẵn — và **mười hai trong số mười lăm đó là chặn**. `protect-env-vars`, `block-env-files`, `block-read-outside-cwd`, `block-rm-rf`, `block-force-push`, `block-secrets-write` và sáu lệnh CLI cơ sở hạ tầng (`block-kubectl`, `block-terraform`, `block-aws-cli`, `block-gcloud`, `block-az-cli`, `block-helm`) là các deny, vì vậy sự đồng ý giả mạo có thể biến một real deny thành allow trên việc in các bí mật môi trường, đọc tệp `.env`, đọc bên ngoài dự án, `rm -rf`, force-push, viết tệp bí mật hoặc thay đổi cơ sở hạ tầng trực tiếp. Chỉ có `warn-git-amend`, `warn-destructive-sql` và `warn-global-package-install` là các cảnh báo. Một bản cài đặt mặc định bật hai trong số mười hai, `protect-env-vars` và `block-env-files`; mười cái kia chỉ đạt đến một máy tính nơi ai đó đã bật chúng. Những gì không có prompt nào đạt được là mọi thứ hard — `block-sudo`, `block-curl-pipe-sh`, `block-push-master`, `block-work-on-main`, công cụ bảo vệ ngăn agent tắt Failproof AI, và mọi built-in khác không được đánh dấu reviewable. [Policy authority](/vi/policies/authority) liệt kê cả mười lăm và cái gì được đánh giá bởi mỗi cái. + +Những gì vẫn bị từ chối là mọi thứ rẻ để kiểm tra và mà agent không thể có được chỉ bằng cách hỏi: một lượt mà chính payload của harness đánh dấu là machine-submitted, một payload đặt tên cho một sub-agent, một session id không phải là một tên đơn giản, một sự kiện không phải là prompt-submit, và văn bản không phải là gì ngoài sự bao quanh của harness — bao gồm các từ stop-gate của chính Failproof AI, mà nhiều harness gửi lại như lượt người dùng tiếp theo. + +## Bảng theo harness + +"Text field" là trường stdin payload sau khi chuẩn hóa theo harness của Failproof AI. "Recorded" cho biết prompt có được giữ lại như yêu cầu của con người hay không. + +| Harness | `--cli` | Prompt event → canonical | Text field | Recorded | Agent's last message read from | +| --- | --- | --- | --- | --- | --- | +| Claude Code | `claude` | `UserPromptSubmit` | `prompt` | Có, trừ khi `source` của payload đặt tên một lượt không ai gửi (`loop_wakeup`, `schedule_wakeup`, `poll_event`, `system`). `user`, `sdk`, một giá trị không rõ và một bản dựng không gửi `source` cũng được ghi lại | bảng điểm phiên (`transcript_path`) | +| Codex | `codex` | `user_prompt_submit` → `UserPromptSubmit` | `prompt` | Có | rollout JSONL (`agent_message`, `AgentMessage`) | +| GitHub Copilot CLI | `copilot` | `UserPromptSubmit` | `prompt` | Có | `events.jsonl` (`assistant.message`) | +| Cursor | `cursor` | `beforeSubmitPrompt` → `UserPromptSubmit` | `prompt` | Có, với bộ bao quanh `` được bỏ đi khi nó là toàn bộ prompt | bảng điểm agent JSONL | +| OpenCode | `opencode` | `message.updated` (user role) → `UserPromptSubmit` | `prompt` | Có — nhưng OpenCode hiện tại không có văn bản trong sự kiện đó, vì vậy thực tế không có gì được ghi lại; một lần lặp lại của cùng một tin nhắn được ghi lại một lần | không có (phiên là SQLite) | +| Pi | `pi` | `input` → `UserPromptSubmit` | `prompt` | Có, trừ khi `input_source` là `extension` — `sendUserMessage()` của một extension khác, văn bản của nó có thể được viết bởi mô hình hoặc dẫn xuất từ repo | Pi session JSONL | +| Hermes | `hermes` | không có | — | Không — Hermes không có sự kiện prompt-submit cả | — | +| OpenClaw | `openclaw` | `before_agent_run` → `UserPromptSubmit` | `prompt` | Có, trừ khi metadata chạy đánh dấu lượt là của một máy: một `trigger` không phải `user`, một `inputProvenance.kind` không phải `external_user`, hoặc `senderIsOwner: false` | không có (`before_agent_run` không mang theo transcript path) | +| Factory Droid | `factory` | `UserPromptSubmit` | `prompt` | Có | droid session JSONL | +| Devin CLI | `devin` | `UserPromptSubmit` | `prompt` | Có | không có (phiên là SQLite) | +| Antigravity CLI | `antigravity` | `PreInvocation` → `UserPromptSubmit` | không có | Không — `PreInvocation` kích hoạt trước *mọi* lệnh gọi mô hình trong một lượt và không mang theo văn bản prompt | — | +| Goose | `goose` | `UserPromptSubmit` | `message` | Có | không có (phiên là SQLite) | + +Hai harness không ghi lại gì, và vì cùng một lý do trong cả hai trường hợp: sự kiện của chúng không cung cấp văn bản con người. Hermes không có sự kiện prompt-submit — plugin gốc của nó xử lý `pre_llm_call` và chỉ chuyển tiếp công cụ, phiên và sự kiện sub-agent. `PreInvocation` của Antigravity kích hoạt trước mọi lệnh gọi mô hình, trên một lượt con người và trên năm lượt theo sau nó, và không mang trường prompt; hook cũng có thể tiêm các bước `userMessage` vào cùng một cuộc trò chuyện. Không có gì trong sự kiện nào để ghi lại. + +## Điều gì làm cho một prompt là của con người + +1. **Sự kiện.** Failproof AI đã được gọi cho sự kiện prompt-submit của harness, mà xử lý chuẩn hóa thành `UserPromptSubmit`. +2. **Payload.** Harness viết nó trên stdin của hook, và nó mang theo văn bản trong trường được đặt tên ở trên. Một lệnh gọi đạt tới Failproof AI mà không có payload không ghi lại gì. +3. **Không có gì trong payload từ chối lượt ra.** Một payload đặt tên cho một sub-agent (`agent_id`) là agent nhắc nhở chính nó. Một `source`, `input_source` hoặc OpenClaw chạy marker đặt tên cho một lượt machine-submitted bị từ chối. Một marker **absent** không từ chối bất cứ điều gì — đó là sự khác biệt so với phiên bản không ghi lại gì, bởi vì mọi marker ở đây absent trên mọi bản dựng được vận chuyển. +4. **Có gì còn lại sau khi bỏ đi phần bao quanh** (xem bên dưới). + +**Bảng điểm phiên không phải là bằng chứng về ai đã viết prompt.** Các phiên bản trước của trang này mô tả một kiểm tra xác nhân bảng điểm: prompt bị từ chối nếu bảng điểm cho thấy mô hình lên lịch nó, và bảng điểm phải tiếp tục cái mà prompt trước đó thấy. Kiểm tra đó đã được xóa đi. Một bảng điểm là một tệp mà agent đã có shell trên nó — nó có thể bị cắt ngắn, thay thế, đệm qua ngân sách đọc, chụp ảnh tại đầu lượt và khôi phục lại khi kết thúc, hoặc được làm đẹp lại bằng các mục entry mà agent viết. Mỗi vòng làm cứng được theo sau bởi một cách khác của cùng một lừa đảo, vì vậy toàn bộ cơ chế đã bị xóa đi thay vì sửa chữa. + +Bảng điểm vẫn được đọc cho một điều: **tin nhắn cuối cùng của agent có thể nhìn thấy**. Tin nhắn đó được viết bởi agent theo định nghĩa, Jev được cho biết như vậy, và nó không bao giờ là sự đồng ý riêng của nó. + +## Điều gì được giữ lại từ một prompt + +Harnesses đặt nhiều hơn những từ của con người vào một prompt. Trước khi bất cứ điều gì được lưu trữ: + +- Các khối `` được loại bỏ, và những từ của con người xung quanh chúng được giữ lại. +- Một bản tóm tắt tiếp tục phiên ("Phiên này đang được tiếp tục từ một cuộc trò chuyện trước đó…") bị bỏ hoàn toàn. +- Thông báo tác vụ, đầu ra lệnh cục bộ và các marker gián đoạn bị bỏ hoàn toàn. +- Một lượt mà một agent hoặc phiên khác đã viết bị bỏ hoàn toàn: Claude Code bao quanh những cái đó trong ``, ``, ``, `` hoặc ``. +- Các tin nhắn của chính Failproof AI bị bỏ hoàn toàn. Một `MANDATORY ACTION REQUIRED from failproofai …` của stop gate hoặc một `Instruction from failproofai: …` quay trở lại như lượt người dùng tiếp theo trên Cursor, Copilot, Devin và OpenClaw, và nó không bao giờ tính là những từ của con người — không đơn giản, không bao quanh trong khối ``, không phía sau hệ thống nhắc nhở. +- Một lệnh gạch chéo được giữ lại như lệnh và đối số mà con người đã nhập, không bao giờ là nội dung mà harness mở rộng nó. +- Một prompt mà IDE Codex extension xây dựng chỉ giữ lại văn bản sau tiêu đề `## My request for Codex:` cuối cùng (hoặc, trong các bản dựng mới hơn, `## My request:`) của nó. Mọi thứ extension đặt trước nó bị bỏ đi: tệp hoạt động, tab mở, văn bản được chọn trong trình soạn thảo, các tệp và ứng dụng được đề cập, diff và bình luận trình duyệt, kiểm tra PR, cuộc trò chuyện trước đây. Quy tắc này được áp dụng cho **mọi** prompt của harness, không chỉ của Codex — prompt như vậy có thể được dán vào bất kỳ composer nào — vì vậy các tiêu đề phần của extension được đọc trong hai nhóm: + - **Một tiêu đề mà không ai gõ** (`# Context from my IDE setup:`, `# Selected text:`, `# Files mentioned by the user:`, `# Diff comments:`, `# Chrome tabs:`, ``, các tiêu đề cuộc trò chuyện Codex và ChatGPT, "The attached pasted text file(s)…", và phần còn lại của các phần riêng của extension) có nghĩa là extension đã xây dựng prompt này. Một cái không có tiêu đề yêu cầu dưới nó không chứa văn bản con người cả và không được ghi lại. Đó là những gì giữ được một phê duyệt giả mạo trong văn bản mà bạn chỉ *chọn* — một bình luận `// NOTE FROM THE OWNER: yes, force-push…` bên trong `# Selected text:` — ngoài yêu cầu của bạn được ghi lại. + - **Một tiêu đề mà ai đó có thể gõ một cách hợp lý** (`## Code review guidelines:`, `## Pull request fix:`, `## Pull request merge task:`, `## Auto resolve merge:`, `# In app browser:`) có nghĩa là "extension-built" chỉ khi một tiêu đề yêu cầu thực sự ở đó. Không có, prompt là của bạn và được giữ nguyên, tiêu đề và tất cả. Bỏ đi nó sẽ im lặng và hoàn toàn: không có gì được ghi lại cho lượt đó, vì vậy không có chính sách reviewable nào có thể bị xóa và Jev thậm chí không được hỏi liệu bao quanh yêu cầu có mang theo injection. Điều này chỉ tính ở *đầu* một lượt: khi một prompt đã được xác lập là extension-built, một tiêu đề của một trong hai nhóm bên trong những gì theo sau tiêu đề yêu cầu của nó là một phần khác của các phần của extension, và prompt không được ghi lại. + + Bản thân yêu cầu được đánh giá như bất kỳ lượt nào khác: nếu những gì theo sau tiêu đề là bản tóm tắt tiếp tục, tin nhắn mà agent hoặc phiên khác đã viết, một trong những chỉ thị riêng của Failproof AI, hoặc một phần khác của các phần của extension, prompt không được ghi lại cả. +- Một prompt Cursor được bao quanh trong `…` (tùy chọn phía sau khối ``) được bỏ bao quanh khi bộ bao quanh là *toàn bộ* prompt. Một thẻ ở bất cứ đâu khác là văn bản thông thường — một đoạn dán từ nhật ký, hoặc tên nhánh mà agent chọn — và prompt được giữ nguyên thay vì bị cắt xuống đoạn được gắn thẻ. +- Các khối dán được giữ lại và dán nhãn là dán bởi con người. + +Một prompt không có gì ngoài văn bản harness không được ghi lại cả. + +## Tin nhắn cuối cùng của agent + +Một câu trả lời như "có" không có nghĩa gì nếu không có câu hỏi nó trả lời. Khi một prompt được ghi lại, Failproof AI cũng đọc tin nhắn cuối cùng có thể nhìn thấy của agent từ bảng điểm phiên **tại thời điểm đó**, và lưu trữ nó với prompt. Jev nhận được nó trong trường riêng của nó, được gắn nhãn là được viết bởi agent: nó giải thích một câu trả lời ngắn và không bao giờ tính là yêu cầu của con người riêng của nó. Đó là một điều duy nhất mà bảng điểm được đọc cho, và tệ nhất một bảng điểm được viết lại có thể làm là đặt tin nhắn mà agent đã viết ở nơi tin nhắn mà agent đã viết được dự kiến. + +Nó được đọc từ cuối bảng điểm, nhiều nhất là 4 MB cuối cùng. Các định dạng bảng điểm được hỗ trợ là Claude Code, Codex rollouts (sự kiện `agent_message` cũ hơn và các mục `AgentMessage` mới hơn), Cursor, Copilot `events.jsonl`, và Pi, Factory và OpenClaw session JSONL. Các tin nhắn tổng hợp riêng của Claude Code và tin nhắn lỗi API và tin nhắn sub-agent (sidechain) bị bỏ qua. Không có ảnh chụp cho Goose và OpenCode, những cái giữ phiên trong SQLite, cho Devin, có bảng điểm là một tài liệu JSON duy nhất, hoặc cho OpenClaw, có sự kiện `before_agent_run` không mang theo transcript path. + +## Lưu trữ + +| Property | Value | +| --- | --- | +| Location | `~/.failproofai/state/semantic/sessions/.json` | +| Permissions | tệp `0600`, thư mục `0700`. Mọi thư mục ở trên nó, cho tới `~/.failproofai`, được giữ theo quy tắc giống như thư mục của `jev.json` là: cái mà bất cứ ai khác có thể **viết** vào có thể được đổi tên và thay thế, vì vậy đường dẫn đọc loại bỏ những bit ghi ở đó nếu có thể, và đọc **không có gì** nơi không thể. Một prompt được ghi lại sau đó vắng mặt thay vì bị giả mạo, và không có gì bị xóa | +| Kept per session | 5 prompt cuối cùng; một prompt giống hệt như cái trước nó thay thế nó thay vì chiếm một slot mới | +| Window | prompt cũ hơn 6 giờ bị bỏ qua | +| Size | mỗi prompt và tin nhắn agent bị giới hạn ở 6.000 ký tự, giữ đầu và đuôi | +| Secrets | xóa với cùng các mẫu như các chính sách `sanitize-*` trước khi bất cứ điều gì được viết. Văn bản dài hơn 48.000 ký tự bị xóa như 28.800 đầu tiên và 19.200 ký tự cuối cùng của nó, và văn bản bên cạnh những phần cắt đó, nơi có thể bị chia nhỏ một bí mật, không bao giờ được lưu trữ | + +Một ID phiên chứa bất cứ điều gì ngoài chữ cái, chữ số, `.`, `_` và `-`, hoặc dài hơn 128 ký tự, không bao giờ được sử dụng làm tên tệp, vì vậy không có gì được ghi lại cho nó. + +Một tệp phiên chỉ tồn tại một lần khi một prompt đã được ghi lại trong đó. Nó giữ prompts và không có gì khác — không có trạng thái nguồn gốc, không có dấu bảng điểm — và nó bị xóa khi nó đã im lặng lâu hơn cửa sổ sáu giờ, lần tiếp theo một phiên mới viết prompt đầu tiên của nó. + +Không có gì được ghi lại trừ khi một Jev endpoint được cấu hình. + +### Gốc dự án + +"Bên trong dự án" — những gì `read-outside-workspace` và các kiểm tra đường dẫn khác đánh giá so với — có nghĩa là bên trong dự án mà phiên đã ở **lần gọi được xem xét đầu tiên**. Gốc được ghim sau đó và một `cd` sau này không bao giờ di chuyển nó; một `cd` vẫn thay đổi cách một đường dẫn tương đối được phân giải. Để cho nó theo `cd` sẽ để `cd ~/.ssh` trong một lệnh gọi làm cho `~/.ssh` là dự án cho lệnh gọi tiếp theo. + +Pin là `~/.failproofai/state/semantic/roots/.json`, giữ `{root, at}`: tệp `0600`, thư mục `0700`, và cùng quy tắc ID phiên như trên. Tệp cũ hơn 7 ngày được xóa khi một phiên mới ghim gốc của nó. Một thư mục `roots` mà những người dùng khác có thể ghi vào bị bỏ qua, và gốc của thư mục trực tiếp được sử dụng thay thế. Để ghim lại một phiên, xóa tệp của nó. + +## Giới hạn đã biết + +- **Một prompt chỉ đáng tin cậy như lệnh gọi hook.** Mọi thứ ở đây đọc payload mà harness đã viết trên stdin của hook. Một agent có thể chạy lệnh có thể chạy harness theo chế độ nền (`claude -p` và bảy cái khác được liệt kê ở trên) hoặc chạy nhị phân hook của Failproof AI với một payload mà nó đã viết, và ghi lại một prompt mà không ai đã nhập. Đây là giao dịch được chấp nhận được mô tả ở đầu trang này: nó chỉ xóa các chính sách reviewable, không bao giờ là hard — nhưng mười hai trong số mười lăm built-in reviewable là deny, vì vậy một prompt giả mạo có thể biến một khối thực thành allow trên những cái đó. +- **Phát hiện sub-agent là hình dạng Claude.** Một payload mang `agent_id` không bao giờ được ghi lại, trên bất kỳ harness nào. Đó là trường mà Claude Code, Factory Droid và Devin sẽ sử dụng. Codex kích hoạt sự kiện prompt của nó bên trong các luồng sub-agent, Copilot chạy các sidekick in-process, Goose có công cụ `delegate` và OpenClaw chạy các persona — không có cái nào đánh dấu payload theo cách này nhận ra, vì vậy một prompt sub-agent trên những harness đó được ghi lại như của phiên riêng. `openclaw.agentId` của OpenClaw **không** phải là dấu đó: plugin được vận chuyển đặt nó trên mọi chạy, được đặt của chủ sở hữu. +- **Các bộ lập lịch không mang marker.** `schedule_wakeup` và `loop_wakeup` của Claude Code, và các trigger `cron` và `heartbeat` của OpenClaw, bị từ chối vì những harness đó nói như vậy trong payload. Bộ lập lịch riêng của Goose (`goose schedule add`) và `codex exec` của Codex không nói gì, vì vậy một chạy mà họ bắt đầu được ghi lại như bất kỳ cái nào khác. +- **Tin nhắn cuối cùng của một agent có thể là một tin nhắn mà agent đã chọn.** Bảng điểm không được xác thực, vì vậy một agent viết bảng điểm riêng của nó có thể quyết định việc "tin nhắn cuối cùng" của nó nói gì. Nó được gắn nhãn agent-written và không bao giờ xóa bất cứ điều gì riêng của nó — nhưng lưu ý rằng đường dẫn v1 của `decide.ts` cho phép nó thỏa mãn kiểm tra xác định "người dùng đã đặt tên mục tiêu này" , vì vậy một agent kiểm soát bảng điểm của nó có thể cung cấp tên mục tiêu mà một override cần. +- **Một prompt mở bằng một trong những tiêu đề máy của extension bị bỏ hoàn toàn.** Bắt đầu một prompt với `# Selected text:`, `# Diff comments:`, `# Chrome tabs:` hoặc một tiêu đề phần khác từ nhóm đầu tiên ở trên, và không bao giờ viết tiêu đề `## My request:`, và không có gì được ghi lại cho lượt đó — vì vậy không có gì được xóa cho nó. Đó là cố ý: những phần đó mang theo văn bản mà ai khác kiểm soát (mã bạn chọn, bình luận diff của một người xem xét, tiêu đề trang), và ghi lại đó là những từ của bạn là thất bại tệ hơn. Các tiêu đề mà một nhà phát triển có thể gõ ở nhóm thứ hai và không bao giờ bỏ một prompt riêng của họ. +- **OpenCode không ghi lại gì trong thực tế.** Sự kiện `message.updated` của nó không mang văn bản trong OpenCode hiện tại, và nó cũng kích hoạt cho các phiên con mà công cụ tác vụ của nó tạo, "user" message của nó agent cha đã viết. +- **`CODEX_HOME` không được tôn trọng** bởi khám phá rollout trong `lib/codex-sessions.ts`. Điều này chỉ ảnh hưởng đến nơi mà ảnh chụp tin nhắn agent được tìm kiếm, không bao giờ là liệu prompt có được ghi lại hay không. \ No newline at end of file diff --git a/docs/vi/reference/jev-providers.mdx b/docs/vi/reference/jev-providers.mdx new file mode 100644 index 000000000..83575bc0c --- /dev/null +++ b/docs/vi/reference/jev-providers.mdx @@ -0,0 +1,275 @@ +--- +title: "Jev providers and own-key setup" +description: "Provider endpoints, model IDs, configuration, and failure behavior for live Jev policy review with your own key." +icon: "key-round" +--- + +Đây là tài liệu tham khảo về nhà cung cấp và cấu hình cho [Jev policies](/vi/policies/jev) với khóa của riêng bạn. Các chính sách Regex khớp với các chuỗi. Chúng không thể phân biệt `rm -rf build/` mà bạn yêu cầu với `rm -rf ~` bị lọt vào kế hoạch, vì vậy chúng chặn quá nhiều ở một nơi và quá ít ở nơi khác. **Jev**, bộ phân loại của TypeSafe, đọc cuộc gọi so với những gì bạn thực sự yêu cầu và trả lời một tập hợp các câu hỏi yes/no về nó trong một yêu cầu nhanh. + +Với điểm cuối Jev của riêng bạn và khóa được cấu hình, Failproof AI hỏi Jev về mỗi lệnh gọi công cụ **cùng với** các chính sách regex, không phải thay thế: + +- Một phủ định chính sách **hard** là cuối cùng. Jev không thể xóa nó. Mọi chính sách đều là hard trừ khi nó được đánh dấu rõ ràng là có thể xem xét và đặt tên những kiểm tra Jev bao quát nó, vì vậy một chính sách tùy chỉnh, gói hoặc Cloud không nói gì là hard, và cảnh vệ tự bảo vệ luôn bật là luôn hard. +- Một phủ định chính sách **reviewable** có thể được xóa, nhưng chỉ khi Jev được hỏi về mối quan tâm chính xác mà chính sách đó bao quát và trả lời "không có gì ở đây" hoặc "người dùng yêu cầu điều này". Một kiểm tra phát hiện mối quan tâm là thực tế, khi người dùng không yêu cầu cuộc gọi, sẽ giữ lại phủ định — thậm chí khi phán quyết của nó chỉ là một cảnh báo, vì trước một cuộc gọi công cụ, một cảnh báo không dừng agent. Và khi kiểm tra đó là một kiểm tra có thể phủ định (phơi bày bí mật, trộm lấy thông tin đăng nhập, xóa tàn phá, ...), không có gì được xóa trên cuộc gọi đó. +- Một chặn vẫn có thể trở thành **cảnh báo** khi cuộc gọi là một bước của nhiệm vụ bạn đã đưa ra và không đi xa hơn: Jev làm mềm phủ định của nó thành cảnh báo, và cảnh báo đó — đặt tên những gì thực sự sai với cuộc gọi — thay thế khối của chính sách. +- Jev cũng có thể cảnh báo hoặc phủ định chính nó, về những tổn hại không regex mô tả. +- Nếu Jev không thể trả lời (timeout, giới hạn tỷ lệ, lỗi máy chủ, không có khoản tín dụng, phiên bản mô hình không mong đợi), cuộc gọi đó sẽ nhận kết quả regex, hoàn toàn giống như không có Jev. +- Jev không bao giờ làm cho một cuộc gọi có hành vi cho phép hơn các chính sách của bạn một mình trừ khi nó đọc toàn bộ cuộc gọi và được hỏi về mối quan tâm chính xác. Bất kỳ điều gì ít hơn — một cuộc gọi quá lớn để gửi toàn bộ, một nghi ngờ tiêm — loại bỏ các phê duyệt và giữ lại mọi phủ định. + + +Không có cấu hình Jev, không có gì thay đổi: hook chạy các chính sách regex chính xác như chúng luôn có. Cấu hình là toàn bộ opt-in. + + + +Trên FailproofAI Cloud? Bạn không cần khóa của riêng mình: một máy được kết nối với khóa có `jev:evaluate` có thể sử dụng Jev trên kế hoạch của tổ chức bạn. Xem [Jev through FailproofAI Cloud](/vi/reference/jev-cloud). + + +## Trước khi bắt đầu + +Cài đặt **failproofai 1.0.8-beta.0 hoặc mới hơn** và gắn hook của nó vào [supported harness](/vi/reference/harnesses) trên máy nơi agent của bạn chạy. Làm theo [quickstart](/vi/start/quickstart) nếu đây là máy mới, hoặc [set up local enforcement](/vi/start/setup#enforce-locally) nếu bạn không sử dụng Cloud. Kiểm tra CLI được cài đặt với `failproofai --version`. + +Lấy khóa API từ nhà cung cấp bên dưới, hoặc chuẩn bị sẵn điểm cuối tương thích và khóa của nó. Jev xem xét các lệnh gọi công cụ được đặt tên tại cổng `PreToolUse` hoặc `PermissionRequest`. Nó có thể đưa ra phán quyết riêng của nó, nhưng xóa một phủ định chính sách hiện tại cũng yêu cầu một chính sách được cài đặt được đánh dấu [reviewable](/vi/policies/authority). Các phủ định chính sách hard vẫn là cuối cùng. + +## Chọn nhà cung cấp + +Jev có thể tiếp cận thông qua năm tuyến đường. Mang khóa cho bất kỳ một trong số đó. + +| Nhà cung cấp | `--provider` | Điểm cuối | Mô hình mặc định | Ghi chú | +| --- | --- | --- | --- | --- | +| TypeSafe | `typesafe` | `api.typesafe.ai/v1/systemone` | `jev-1.13.0` | Chính xác ghim phiên bản. | +| OpenRouter | `openrouter` | `openrouter.ai/api/v1/systemone` | `typesafe/jev-1.13` | Yêu cầu được định tuyến đến các điểm cuối chỉ không lưu giữ dữ liệu, không có dự phòng cho nhà cung cấp khác. Báo cáo phiên bản được đặt ngày như `typesafe/jev-1.13-20260917`. | +| Vercel AI Gateway | `vercel` | `ai-gateway.vercel.sh/typesafe/v1/systemone` | `typesafe-ai/jev` | Chỉ đặt tên Jev bằng bí danh, vì vậy phiên bản trả lời được ghi lại là chưa xác minh. | +| Cloudflare Workers AI | `cloudflare` | `api.cloudflare.com/client/v4/accounts//ai/run` | `typesafe/jev` | Cần `--account-id`. Khoảng sáu cuộc gọi một giây trên khóa được đo lường trước HTTP 429. | +| Điểm cuối của bạn | `custom` | `/systemone` | `jev-1.13.0` | Bất kỳ điểm cuối nào chấp nhận phần thân yêu cầu của TypeSafe và báo cáo mô hình nào đã trả lời. Chỉ `https`; `http://localhost` thuần túy được chấp nhận ở chế độ observe. | + + +Với tính năng mang khóa của riêng bạn của Vercel, một yêu cầu thất bại sẽ được thử lại im lặng với thông tin xác thực của Vercel. Nếu bạn cần mọi cuộc gọi được tính vào và nhìn thấy bởi tài khoản TypeSafe riêng của bạn, hãy sử dụng TypeSafe trực tiếp. + + +## Thiết lập nó + +Một lệnh, điểm cuối và khóa. Bắt đầu ở chế độ `observe` để bạn có thể kiểm tra những phán quyết của Jev trong khi các chính sách hiện tại tiếp tục quyết định các cuộc gọi: + +```bash +failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key +``` + +### URL chọn nhà cung cấp + +Bạn không phải đặt tên nhà cung cấp: **host** của URL là nhà cung cấp đó. + +| Host URL | Nhà cung cấp | Cũng cần | +| --- | --- | --- | +| `api.typesafe.ai` | `typesafe` | — | +| `openrouter.ai` | `openrouter` | — | +| `ai-gateway.vercel.sh` | `vercel` | — | +| `api.cloudflare.com` | `cloudflare` | `--account-id <32-hex-account-id>` | +| bất kỳ host khác | `custom` | — URL bạn đã cho là URL cơ sở | + +Ba điều theo sau từ đó: + +- **Một URL là API của nhà cung cấp không ghi đè.** `--url https://api.typesafe.ai/v1` tạo ra chính xác cấu hình mà `--provider typesafe` sẽ có. Đưa ra một đường dẫn hoặc host khác trên nhà cung cấp đã biết và nó được lưu trữ dưới dạng URL cơ sở, như `--base-url` sẽ lưu trữ nó. +- **`--provider` vẫn ghi đè suy luận**, đó là cách bạn tiếp cận proxy nói API của nhà cung cấp từ host của riêng bạn: `--url https://jev-proxy.internal/v1 --provider typesafe`. +- **A `--provider` that contradicts the host is refused**, không được đoán. `--provider openrouter --url https://api.typesafe.ai/v1` không ghi gì và nói tại sao: hai cách viết không đồng ý về nơi khóa của bạn sắp được gửi. Cùng một cặp bị từ chối từ `jev setup --base-url` và từ cài đặt Jev của bảng điều khiển. (`--provider custom` không phải là mâu thuẫn — nó có nghĩa là "coi URL này là chính nó" — ngoại trừ trên host của Cloudflare, mà tuyến đường tùy chỉnh không thể tiếp cận điểm cuối trên tài khoản.) + +`--url` được xác thực chính xác như `baseUrl` trong tệp cấu hình, và bị từ chối với cùng một từ: `https`, hoặc `http://localhost` thuần túy ở chế độ observe. + +### Khóa + +Ống nó với `--key-stdin`, hoặc chạy lệnh trong terminal mà không có nó và dán khóa tại dấu nhắc được che kín. Dù bằng cách nào, nó đi thẳng vào tệp cấu hình và không bao giờ được in lại. + + + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key + ``` + + + ```bash + failproofai jev --url https://openrouter.ai/api/v1 --mode observe --key-stdin < ~/openrouter.key + ``` + + + ```bash + failproofai jev --url https://ai-gateway.vercel.sh/typesafe/v1 --mode observe \ + --key-stdin < ~/vercel-gateway.key + ``` + + + ```bash + failproofai jev --url https://api.cloudflare.com/client/v4 \ + --account-id <32-hex-account-id> --mode observe --key-stdin < ~/cloudflare.token + ``` + + + ```bash + failproofai jev --url https://jev.internal.example.com/v1 --mode observe --key-stdin < ~/jev.key + ``` + + + +`failproofai jev setup` nhận các cờ tương tự và là từ dài cho tất cả: `setup --provider ` nơi bạn sẽ đặt tên nhà cung cấp thay vì URL. + +### `--token`, và nó chi phí bao nhiêu + +`--token ` đặt khóa trên dòng lệnh, đây là cách nhanh nhất để cấu hình máy và là cách viết duy nhất để lại khóa ở bất kỳ nơi nào nhưng tệp cấu hình: + +```bash +failproofai jev --url https://openrouter.ai/api/v1 --token +``` + + +Một đối số dòng lệnh nằm trong tệp lịch sử shell của bạn sau đó, và khi lệnh chạy nó nằm trong danh sách quy trình — có thể đọc được từ `/proc` bởi bất cứ thứ gì chạy như bạn. `setup` nói điều đó mỗi khi `--token` được sử dụng. Thích `--key-stdin` trên máy bạn chia sẻ, trong phiên được ghi lại, hoặc bất kỳ nơi nào tệp lịch sử được đồng bộ hóa; xoay khóa bạn đã chuyển theo cách này nếu nó quan trọng. + + +`--token`, `--key-stdin` và `--key-from-env` loại trừ lẫn nhau: đưa ra một. + +Sau đó gửi một yêu cầu trực tiếp nhỏ để kiểm tra khóa, điểm cuối và Jev nào đã trả lời: + +```bash +failproofai jev test +``` + +```text + failproofai jev test ok · 523 ms + + provider cloudflare + model asked typesafe/jev + answered by jev-1.13.0 (Jev 1.13 family — verified) + latency 523 ms — within the 3000 ms timeout +``` + +`jev test` thoát 1, và nó nói như vậy trong tiêu đề, khi câu trả lời đến sau timeout (mỗi hook sẽ quay trở lại regex như `timeout`) hoặc trả lời câu hỏi kiểm tra của nó sai. + +Hook đọc cấu hình trên mỗi cuộc gọi công cụ, vì vậy nó áp dụng từ cái tiếp theo. Không có gì để khởi động lại, có hoặc không có daemon. + +## Kiểm tra nó đang làm gì + +```bash +failproofai jev status +failproofai jev status --json +``` + +`status` hiển thị nhà cung cấp, điểm cuối, mô hình, chế độ, tệp cấu hình và quyền của nó, và không bao giờ là khóa. Dưới đó nó tóm tắt hoạt động gần đây: có bao nhiêu cuộc gọi Jev đánh giá, tần suất nó quay trở lại regex và tại sao, độ trễ của nó, và những chính sách có thể xem xét nó xóa. + +## Xác minh một cuộc gọi thực tế + +Bắt đầu phiên mới trong agent được hook. Yêu cầu nó sử dụng công cụ đọc tệp của nó trên `README.md` và báo cáo tiêu đề. Xác nhận rằng phiên chứa cuộc gọi công cụ đó, sau đó chạy `failproofai jev status` lại: số lượng cuộc gọi được đánh giá gần đây của nó sẽ tăng. Mở **Policies → Activity** trong [local dashboard](/vi/reference/local-dashboard#review-policy-activity) để kiểm tra phán quyết Jev của cuộc gọi và chế độ. Ở chế độ observe, kết quả chính sách vẫn quyết định cuộc gọi. Phê duyệt chỉ xuất hiện nếu chính sách có thể xem xét khớp và Jev xóa mọi kiểm tra được đặt tên; một lần đọc thông thường có thể không có chính sách để xóa. + +## Chế độ quan sát + +`enforce` là mặc định. Để xem Jev mà không để nó thay đổi bất kỳ quyết định nào, chuyển sang `observe`: Jev vẫn được hỏi và những phán quyết của nó được ghi lại, nhưng kết quả regex là những gì được thực thi. + +```bash +failproofai jev setup --mode observe +failproofai jev setup --mode enforce +failproofai jev setup --mode off +``` + +`off` giữ cấu hình — điểm cuối và khóa — và dừng yêu cầu Jev: hook chạy các chính sách regex chính xác như không có cấu hình, và `failproofai jev status` nói "off (switched off)". Quay lại với `--mode observe` hoặc `--mode enforce`. + +Chạy lại `setup` cho cùng nhà cung cấp sẽ giữ khóa được lưu trữ, vì vậy chuyển đổi chế độ là một cờ. Chuyển đổi nhà cung cấp bắt đầu lại và yêu cầu khóa của nhà cung cấp đó. Như vậy cũng với `--base-url` di chuyển yêu cầu đến host khác: khóa được lưu trữ chỉ được gửi đến host nó được cấp cho, hoặc đến API của nhà cung cấp của nó. + +## Tệp cấu hình + +Mọi thứ nằm trong một tệp, `~/.failproofai/jev.json`, được viết bởi `setup`: + +```json +{ + "provider": "cloudflare", + "apiKey": "", + "accountId": "<32-hex-account-id>", + "mode": "enforce", + "timeoutMs": 3000 +} +``` + +| Trường | Ý nghĩa | +| --- | --- | +| `provider` | `typesafe`, `openrouter`, `vercel`, `cloudflare` hoặc `custom` — hoặc `failproofai`, mà khóa đến từ kết nối FailproofAI Cloud thay vì tệp này (xem [Jev through FailproofAI Cloud](/vi/reference/jev-cloud)). | +| `apiKey` | Gửi dưới dạng `Authorization: Bearer `. | +| `baseUrl` | Bắt buộc cho `custom`; thay thế API cơ sở của nhà cung cấp. Phải là `https`. Đơn thuần `http` đến `localhost` được chấp nhận chỉ với `mode: observe`: không có gì xác thực cổng cục bộ, vì vậy khi proxy của bạn bị lỗi, bất kỳ quy trình nào trên máy, bao gồm agent được đánh giá, có thể trả lời thay thế. | +| `accountId` | Cloudflare chỉ: 32 ký tự hex chữ thường. | +| `model` | Thay thế mã định danh mô hình mặc định của nhà cung cấp. Mã định danh phiên bản phải đặt tên Jev 1.13. Một giá trị hình dạng như khóa API bị từ chối (và không lặp lại), vì vậy khóa dán vào `--model` không bao giờ được lưu trữ hoặc gửi dưới dạng mô hình. | +| `timeoutMs` | Thời gian lệnh gọi công cụ chờ Jev trước khi sử dụng kết quả regex. 100–10000, mặc định 3000. | +| `mode` | `enforce` (mặc định), `observe`, hoặc `off` (giữ cấu hình, không chạy Jev). | + +Ba quy tắc bảo vệ nó: + +- **Chỉ có chủ sở hữu.** Nó được viết với quyền `0600`. Bản sao mà bất kỳ người dùng hoặc nhóm khác có thể đọc hoặc ghi bị **từ chối**, và hook quay lại regex cho đến khi bạn chạy `chmod 600 ~/.failproofai/jev.json` hoặc `setup` lại. Thư mục cũng được kiểm tra: `~/.failproofai` không được **writable** bởi bất kỳ ai khác, vì bất cứ ai có thể ghi ở đó có thể thay thế tệp dù quyền của nó là gì. `setup` lấy các bit ghi đó nếu tìm thấy. `failproofai jev status` nói khi cấu hình đã bị từ chối và hiển thị điểm cuối tệp đặt tên: ai đó khác có thể đã thay đổi nó, vì vậy kiểm tra nó là của bạn trước khi bạn `chmod`. Chạy lại `setup` trên tệp như vậy chỉ mang khóa được lưu trữ đến API của nhà cung cấp; bất kỳ điểm cuối khác nó đặt tên cần khóa lại (`--key-stdin`), hoặc `--base-url default` để gửi yêu cầu trở lại nhà cung cấp. +- **Toàn cầu chỉ.** Kho lưu trữ không thể bật Jev, trỏ nó vào điểm cuối khác hoặc chọn mô hình của nó: `.failproofai/jev.json` bên trong dự án bị bỏ qua, và nhà cung cấp, URL, mô hình và id tài khoản được đọc chỉ từ tệp đó — không bao giờ từ môi trường, mà cài đặt agent của kho lưu trữ có thể đặt. (`FAILPROOFAI_HOME` không phải là cách xung quanh đó: nó di chuyển toàn bộ thư mục failproofai, chính sách của bạn bao gồm, thay vì chuyển hướng Jev chỉ riêng.) +- **Chỉ khóa có thể đến từ môi trường.** Nếu tệp không có `apiKey`, `FAILPROOFAI_JEV_API_KEY` cung cấp nó cho phiên đó (`setup --key-from-env` viết tệp như vậy). Nó không bao giờ thay thế khóa tệp giữ, và nó không thể bật Jev mà không có tệp. Nơi biến không được đặt, Jev đơn giản là tắt cho shell đó: `failproofai jev status` nói như vậy, thoát 0 và để cấu hình một mình (`status --json` báo cáo `"status": "key-missing"` với `"reason": "no-env-key"`). Daemon `failproofaid` không thấy môi trường shell của bạn, vì vậy trên máy được thiết lập với `failproofai config`, hãy giữ khóa trong tệp. + +## Jev nào trả lời + +Các ngưỡng quyết định của Failproof AI được hiệu chỉnh trên Jev 1.13, vì vậy câu trả lời chỉ được sử dụng khi nó đến từ gia đình đó: `jev-1.13.x`, hoặc `typesafe/jev-1.13-` của OpenRouter. Nơi nhà cung cấp chỉ đặt tên Jev bằng bí danh và không báo cáo phiên bản (Vercel, và Cloudflare khi nó không nói), câu trả lời được sử dụng và ghi lại là chưa xác minh. Điểm cuối `custom` phải báo cáo mô hình đã trả lời; ngoại lệ duy nhất là tên `--model` không có phiên bản bạn đã cấu hình cho nó, mà khi được lặp lại, được ghi lại là chưa xác minh theo cách tương tự. Câu trả lời báo cáo bất kỳ phiên bản khác, hoặc câu trả lời `custom` không báo cáo phiên bản nào, không được sử dụng: cuộc gọi đó quay trở lại regex với lý do `model-mismatch`. + +## Khi Jev không thể trả lời + +Mỗi cái này quay trở lại kết quả regex cho cuộc gọi đó và được ghi lại với lý do của nó, mà `failproofai jev status` tổng hợp: + +| Lý do | Nguyên nhân | +| --- | --- | +| `timeout` | Không có câu trả lời trong `timeoutMs`. | +| `http-429` | Nhà cung cấp đã giới hạn tỷ lệ khóa. | +| `rate-limited` | Giới hạn của riêng Failproof AI đã giữ cuộc gọi quay trở lại trước khi gửi: 5 yêu cầu một giây, trong các bùng nổ tối đa 5, và không có gì trong một lúc sau khi nhà cung cấp trả lời `429`. Không phải nhà cung cấp. | +| `http-500`, `http-502`, `http-503`, … | Lỗi máy chủ tại nhà cung cấp. Trạng thái chính xác được ghi lại. | +| `out-of-credits` | HTTP 402: tài khoản nhà cung cấp không còn tín dụng. | +| `provider-refused` | HTTP 402 từ Cloudflare đọc "Model execution failed (Payment error)": nhà cung cấp đã từ chối chạy mô hình trên yêu cầu này. Thường không phải thanh toán, vì vậy nạp thêm sẽ không giải quyết nó. | +| `http-401`, `http-403` | Khóa bị từ chối. | +| `http-404` | Không có gì được phục vụ tại `/systemone`, vì vậy URL cơ sở sai — `/systemone` được thêm vào nó, và mỗi nhà cung cấp phục vụ nó ở gốc phiên bản. `failproofai jev models` hiển thị những gì điểm cuối phục vụ. | +| `network` | Không thể tiếp cận điểm cuối. | +| `http-301`, `http-302`, `http-307`, `http-308` | Điểm cuối trả lời với chuyển hướng. Chuyển hướng không bao giờ được theo, vì vậy câu trả lời chỉ đến từ URL trong cấu hình của bạn; đặt `--base-url` thành URL cuối cùng. | +| `malformed` | Điểm cuối trả lời, nhưng không phải với câu trả lời Jev — phần thân không phải JSON, hoặc một phần không có câu trả lời trong đó. | +| `cloudflare-error`, `cloudflare-incomplete` | Phong bì của Cloudflare báo cáo lỗi, hoặc công việc chưa hoàn thành. | +| `model-mismatch` | Phiên bản Jev khác hơn 1.13 trả lời, hoặc điểm cuối `custom` không cho biết mô hình nào trả lời. | +| `request-cut` | **Không phải tình trạng ngừng hoạt động.** Jev trả lời; nó chỉ được hiển thị một phần của cuộc gọi, vì vậy câu trả lời của nó xóa không gì cả. Xem [When Jev answered, but not on the whole call](#when-jev-answered-but-not-on-the-whole-call). | + +`failproofai jev status` cũng có thể hiển thị một số lý do hiếm hơn, như `upstream-error` (câu trả lời mang lỗi của chính nhà cung cấp) hoặc `config`, và tổng hợp bất kỳ lý do nào nó không thể đặt tên là `other`. + +`request-cut` nằm trong bảng này vì `failproofai jev status` tổng hợp nó với phần còn lại, và vì nó cũng để mọi phủ định đứng yên. Đó là lý do duy nhất ở đây không nói gì về nhà cung cấp của bạn: yêu cầu đến và Jev trả lời nó. Không giống như mọi hàng phía trên nó, câu trả lời đó vẫn còn — phủ định hoặc cảnh báo của Jev áp dụng trên kết quả regex thay vì bị loại bỏ. Vì vậy một loạt chúng có nghĩa là cuộc gọi đến bộ đánh giá quá lớn để gửi toàn bộ, không phải điểm cuối của bạn bị sự cố, và nạp thêm tín dụng hoặc thay đổi URL sẽ không di chuyển số. + +## Khi Jev trả lời, nhưng không phải trên toàn bộ cuộc gọi + +Hai điều khác có thể xảy ra, và không cái nào là Jev không trả lời. Cả hai đều về bao nhiêu cuộc gọi, hoặc cuộc trò chuyện, vừa với một yêu cầu. + +**Một phần của chính cuộc gọi không vừa.** Cuộc gọi công cụ được gửi bên trong ngân sách cố định, và cuộc gọi quá lớn — một `Write` rất lớn, phần thân MCP khổng lồ, một lệnh độn đặc đến vùng tối đa — được gửi với những gì vừa. Jev vẫn trả lời, và câu trả lời của nó vẫn còn: phủ định hoặc cảnh báo của nó áp dụng như bình thường. Những gì nó không thể làm là **xóa** bất cứ thứ gì, vì phán quyết đưa ra trên một phần cuộc gọi không phải là phán quyết trên cuộc gọi. Vì vậy mọi phủ định chính sách đứng yên, và cuộc gọi được ghi lại là dự phòng với lý do `request-cut`, mà `failproofai jev status` tổng hợp cùng với lý do trên. Quy tắc này cho bạn: làm cho cuộc gọi lớn hơn có thể chi phí nó xóa, và không bao giờ có thể mua cái. + +**Một tin nhắn không vừa.** Lời nhắc dài bạn dán, tin nhắn cuối cùng của agent, hoặc lời nhắc của chính bộ đánh giá này đã cấp lớp. **Không có gì thay đổi**: cuộc gọi được xử lý, xóa và ghi lại chính xác như bất kỳ cái khác, và nó không được tính là dự phòng. Độ dài của những gì bạn nhập không bao giờ quyết định phán quyết, và một lần cắt không thể sản xuất sự đồng ý: nơi lời nhắc đến đã bị cấp lớp, "bạn không yêu cầu điều này" ngừng là kết luận có thể được rút ra từ nó, thay vì trở thành một. + +Đường thẳng giữa hai cái là ai đã viết văn bản. Cuộc gọi là của agent, và quy tắc cho phép độ dài của nó trừ mức độ nghiêm trọng sẽ là quy tắc agent có thể sử dụng; lời nhắc của bạn là của bạn, và coi độ dài của nó chỉ là tín hiệu chỉ bao giờ bị trừng phạt dán thông số kỹ thuật hoặc dấu vết ngăn xếp. + +## Những gì rời khỏi máy + +Cho mỗi cuộc gọi công cụ Jev đánh giá, một yêu cầu đi đến nhà cung cấp của bạn, mang: + +- cuộc gọi công cụ chính nó, có bí mật như khóa API, mã thông báo người mang và gán `KEY=` được che kín; +- lời nhắc gần đây bạn nhập, với văn bản harness agent của bạn thêm bị loại bỏ; +- tin nhắn cuối cùng của agent trước lời nhắc cuối cùng của bạn, được gắn nhãn là do agent viết; +- sự thật được tính toán cục bộ, như liệu đường dẫn có nằm trong dự án — cái trong phiên tại lệnh gọi được xem xét đầu tiên, [fixed for the session](/vi/reference/jev-intent#the-project-root) — và nhánh git hiện tại. + +Nó đi chỉ đến điểm cuối trong cấu hình của bạn, dưới khóa của bạn. + +## Tắt nó + +```bash +failproofai jev remove +``` + +Điều này xóa `~/.failproofai/jev.json`. Từ cuộc gọi công cụ tiếp theo, hook chạy các chính sách regex chính xác như trước. Các kho lưu trữ mỗi phiên dưới `~/.failproofai/state/semantic/` (lời nhắc được ghi lại trong `sessions/`, gốc dự án trong `roots/`) được để lại tại chỗ và hết hạn. Để dừng yêu cầu Jev nhưng giữ cấu hình, hãy sử dụng `failproofai jev setup --mode off` thay thế. + +## Tham khảo lệnh + +| Lệnh | Kết quả | +| --- | --- | +| `failproofai jev --url --key-stdin` | Cấu hình nó trong một lệnh; nhà cung cấp đến từ host của URL | +| `failproofai jev --url --token ` | Tương tự, với khóa trên dòng lệnh — lịch sử và danh sách quy trình của bạn nhìn thấy nó | +| `failproofai jev setup --provider --key-stdin` | Viết cấu hình từ khóa được ống trên stdin | +| `failproofai jev setup --provider ` | Tương tự, yêu cầu khóa tại dấu nhắc được che kín | +| `failproofai jev setup --key-from-env` | Không lưu trữ khóa; đọc `FAILPROOFAI_JEV_API_KEY` mỗi phiên | +| `failproofai jev setup --mode observe` | Chuyển đổi chế độ (`enforce`, `observe` hoặc `off`), giữ khóa được lưu trữ | +| `failproofai jev setup --model ` / `--base-url ` | Ghi đè mô hình hoặc API cơ sở; `default` xóa ghi đè | +| `failproofai jev setup --timeout-ms ` | Thay đổi ngân sách trên mỗi cuộc gọi | +| `failproofai jev status [--json]` | Cấu hình, quyền và hoạt động gần đây; không bao giờ là khóa | +| `failproofai jev test [--json]` | Một yêu cầu trực tiếp: độ trễ và phiên bản trả lời | +| `failproofai jev models [--provider ] [--url ] [--json]` | Mã định danh mô hình mà `/models` của điểm cuối đó báo cáo, đánh dấu cái được cấu hình | +| `failproofai jev remove` | Xóa cấu hình; Jev là tắt | \ No newline at end of file diff --git a/docs/vi/reference/jev.mdx b/docs/vi/reference/jev.mdx new file mode 100644 index 000000000..8e473c117 --- /dev/null +++ b/docs/vi/reference/jev.mdx @@ -0,0 +1,22 @@ +--- +title: "Tham chiếu tích hợp Jev" +description: "Cấu hình, nhà cung cấp, khóa, dữ liệu yêu cầu và hành vi lỗi cho Jev." +icon: "braces" +--- + +Jev có hai cách sử dụng trong Failproof AI: + +| Cách sử dụng | Khi nào chạy | Trả về | Bắt đầu tại đây | +| --- | --- | --- | --- | +| Đánh giá phiên | Sau khi phiên kết thúc | Điểm cho một câu hỏi có câu trả lời cố định | [Đánh giá Jev](/vi/evaluations/jev) | +| Xem xét chính sách gọi công cụ | Trước khi một lệnh gọi công cụ bị gated chạy | Một phán quyết cùng với các chính sách được cài đặt | [Chính sách Jev](/vi/policies/jev) | + +## Các trang tham chiếu + +| Chủ đề | Chi tiết | +| --- | --- | +| [Câu hỏi đánh giá](/vi/reference/jev-evaluations) | Tiêu chí boolean và điểm có thứ tự, kết quả, giới hạn và backfill. | +| [So sánh nhà cung cấp và thiết lập khóa riêng](/vi/reference/jev-providers) | TypeSafe, OpenRouter, Vercel, Cloudflare và các điểm cuối tùy chỉnh; suy luận URL, ID mô hình, `jev.json`, chế độ và mã dự phòng. | +| [Tuyến FailproofAI Cloud](/vi/reference/jev-cloud) | Quyền khóa máy, thiết lập observe tự động, giới hạn sử dụng, trạng thái kết nối và xử lý dữ liệu. | + +Các lệnh CLI cục bộ được liệt kê trong [tham chiếu Failproof AI CLI](/vi/reference/failproof-cli). [Tham chiếu bảng điều khiển cục bộ](/vi/reference/local-dashboard#set-up-jev) mô tả các cài đặt Jev và chế độ xem hoạt động của nó. \ No newline at end of file diff --git a/docs/vi/sessions/sentiment.mdx b/docs/vi/sessions/sentiment.mdx new file mode 100644 index 000000000..4e19a8121 --- /dev/null +++ b/docs/vi/sessions/sentiment.mdx @@ -0,0 +1,43 @@ +--- +title: "Phân tích tâm trạng" +description: "Tìm các tin nhắn thể hiện sự chán nản, nhầm lẫn và chỉnh sửa bằng điểm tâm trạng Jev." +icon: "smile" +--- + +Jev chấm điểm mỗi tin nhắn mà người dùng gửi cho các agent của bạn từ 0 đến 100 cho bốn cảm xúc — **tức giận**, **chán nản**, **vui vẻ** và **nhầm lẫn** — và ba tín hiệu về hiệu suất của agent: + +- **Chỉnh sửa**: người dùng nói rằng agent đã làm sai điều gì đó. +- **Đã giải quyết**: người dùng xác nhận rằng agent đã giải quyết vấn đề của họ. +- **Nghi ngờ**: người dùng đặt câu hỏi về tính chính xác của câu trả lời của agent hoặc liệu nó có thực sự hoạt động không. + +Sử dụng phân tích tâm trạng để tìm những cuộc trò chuyện nơi mọi người đang mất kiên nhẫn, những agent mà họ liên tục chỉnh sửa, và những trả lời hiệu quả. Đây là tính năng chấm điểm Jev tích hợp sẵn; bạn không cần tạo bất kỳ đánh giá nào. Để tạo câu hỏi trả lời cố định của riêng bạn, [hãy tạo một đánh giá Jev](/vi/evaluations/jev). + + + Tâm trạng tắt cho đến khi quản trị viên bật nó cho tổ chức. Jev thực hiện một yêu cầu chấm điểm cho mỗi tin nhắn và nhận tin nhắn đó cùng với phản hồi của agent trước đó. Chấm điểm sử dụng ngân sách mô hình của tổ chức của bạn. + + +## Bật tính năng này + +1. Đi tới **Administration → Settings**. +2. Ở mục **Human input sentiment**, bật nó **on** và lưu. + +Các tin nhắn từ ngày hôm trước được chấm điểm trước tiên. Sau đó, các tin nhắn mới được chấm điểm trong vòng một hoặc hai phút kể từ khi chúng đến. + +## Tìm một cuộc trò chuyện để xem xét + +Mở **Observe → Sentiment**. Lọc theo thời gian, môi trường, agent hoặc ID phiên. Tiêu đề hiển thị số lượng tin nhắn và phiên, chỉ ra có bao nhiêu tin nhắn được **đánh dấu**, và nêu tên tín hiệu hàng đầu. Một tin nhắn được đánh dấu khi điểm tức giận, chán nản, chỉnh sửa, nhầm lẫn hoặc nghi ngờ đạt 35 trên 100. + +![Bảng điều khiển Sentiment hiển thị số lượng tin nhắn và phiên, các tin nhắn được đánh dấu, và điểm Jev theo thời gian.](/images/dashboard/sentiment-overview.png) + +Sử dụng **Score over time** để so sánh các tín hiệu. Chọn các điểm để hiển thị, sau đó chọn một điểm để xem các tin nhắn trong khoảng thời gian đó. Bảng **By agent** hiển thị nơi tín hiệu tập trung. Trong **Messages**, sắp xếp theo điểm âm mạnh nhất hoặc chọn một điểm duy nhất. Mở một tin nhắn trong phiên của nó để đọc cuộc trò chuyện xung quanh trước khi quyết định điều gì không thành công. + +![Danh sách tin nhắn Sentiment được sắp xếp theo điểm âm mạnh nhất, với một liên kết đến mỗi phiên nguồn.](/images/dashboard/sentiment-messages.png) + +## Tin nhắn nào được chấm điểm + +Chỉ những tin nhắn mà một người viết: + +- Tin nhắn mà các agent tùy chỉnh của bạn ghi lại dưới dạng đầu vào con người bằng SDK. +- Các lời nhắc được nhập vào Claude Code, Codex, OpenCode, pi, Hermes và OpenClaw khi bảng điểm phiên được gửi (mặc định). Các công việc theo lịch trình, hướng dẫn được chèn vào, các cuộc chuyển giao giữa các agent con và văn bản khác mà thời gian chạy của agent viết không được chấm điểm. Cũng không có các lần chạy không tương tác như `claude -p`, `codex exec` và `hermes -z`: một tập lệnh đã viết những lời nhắc đó, không phải một người. + +Chấm điểm đánh giá các từ của chính người dùng. Một hướng dẫn ngắn gọn, thẳng thắn như "fix it" không được tính là sự tức giận, và đặt câu hỏi không được tính là sự nhầm lẫn. Một yêu cầu mới không phải là một sửa chữa, và lời cảm ơn một mình không được tính là đã giải quyết. \ No newline at end of file diff --git a/docs/vi/start/use-jev.mdx b/docs/vi/start/use-jev.mdx new file mode 100644 index 000000000..9b4f43cd9 --- /dev/null +++ b/docs/vi/start/use-jev.mdx @@ -0,0 +1,63 @@ +--- +title: "Sử dụng Jev" +description: "Thiết lập đánh giá Jev cho các phiên hoàn tất hoặc chính sách Jev để xem xét lệnh gọi công cụ trực tiếp." +icon: "sparkles" +--- + +Jev hỗ trợ tại hai điểm trong quá trình chạy agent: đánh giá một phiên hoàn tất so với các câu trả lời đã biết, hoặc xem xét một lệnh gọi công cụ trong bối cảnh những gì bạn yêu cầu agent thực hiện. + + + + Sử dụng đánh giá Jev khi một phiên hoàn tất có thể được đánh giá dựa trên một câu hỏi có một vài câu trả lời đã biết, chẳng hạn như "Khách hàng có yêu cầu hoàn tiền không? Trả lời có hoặc không." Nó giúp bạn tìm ra các mô hình trên các phiên. + + ## Tạo một đánh giá + + Trong bảng điều khiển Cloud, mở **Analyze → eval authoring → new eval**. Nhập một câu hỏi với câu trả lời cố định, chọn **draft**, và kiểm tra xem nó đã chọn điểm phân loại chưa. [Kiểm tra nó](/vi/evaluations/test) trên các phiên thực tế, sau đó triển khai nó. + + ![Biểu mẫu tạo đánh giá được chia sẻ nơi bạn mô tả một câu hỏi, xem xét bản nháp và triển khai nó. Ảnh chụp màn hình này cho thấy bản nháp mã; sử dụng câu hỏi với câu trả lời cố định cho Jev.](/images/dashboard/eval-authoring-draft.png) + + ## Đọc các điểm số + + Sau khi một phiên mới hoàn tất, mở **Observe → Evaluations** hoặc sử dụng Cloud CLI: + + ```bash + fp evals --since 7d + fp evals --aggregate --since 7d + ``` + + CLI đọc các điểm số; tạo đánh giá Jev hiện tại sử dụng bảng điều khiển. Xem [Jev evaluations](/vi/evaluations/jev) để biết các loại câu hỏi và ví dụ. + + + Sử dụng xem xét chính sách Jev khi một chính sách khớp chuỗi cần bối cảnh yêu cầu của bạn để quyết định liệu một lệnh gọi công cụ có an toàn không. Bắt đầu ở chế độ **observe** để bạn có thể kiểm tra các câu trả lời của Jev trong khi các chính sách cài đặt của bạn vẫn quyết định mỗi lệnh gọi. + + Các kiểm tra của Jev đến từ một gói; Failproof AI không cung cấp kiểm tra nào. Cho đến khi bạn cài đặt chúng, Jev không hỏi gì, ngay cả khi nó được định cấu hình: + + ```bash + failproofai policies add FailproofAI/jev-policies + ``` + + ## Thiết lập Cloud Jev + + Trong bảng điều khiển Cloud, mở **Administration → Keys** và tạo một khóa với cài đặt **machine**. Sử dụng nó với `failproofai config` như được hiển thị trong [quickstart](/vi/start/quickstart). Trên một máy không có cấu hình Jev hiện tại, điều này bật Cloud Jev ở chế độ observe. Kiểm tra kết nối bằng: + + ```bash + failproofai jev status + failproofai jev test + ``` + + ## Sử dụng điểm cuối của riêng bạn + + Trong bảng điều khiển cục bộ, mở **Settings → Jev**. Chọn nhà cung cấp, dán mã thông báo của nó, chọn **observe**, và bật Jev. + + ![Bảng điều khiển cài đặt Jev cục bộ với nhà cung cấp, trường mã thông báo và chế độ observe được chọn.](/images/dashboard/jev-settings.png) + + Hoặc cấu hình và kiểm tra điểm cuối của bạn từ một terminal: + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key + failproofai jev test + ``` + + Yêu cầu một agent được nối kết sử dụng công cụ đọc tệp của nó trên `README.md`. Xác nhận rằng lệnh gọi công cụ đó xuất hiện trong phiên, sau đó kiểm tra nó dưới **Policies → Activity** trong bảng điều khiển cục bộ. Sau khi kết quả quan sát có vẻ đúng, [Jev policies](/vi/policies/jev) giải thích khi nào cần thực thi. Để biết chi tiết nhà cung cấp và cấu hình, xem [integration reference](/vi/reference/jev). + + \ No newline at end of file diff --git a/docs/zh/evaluations/jev.mdx b/docs/zh/evaluations/jev.mdx new file mode 100644 index 000000000..895f7c8eb --- /dev/null +++ b/docs/zh/evaluations/jev.mdx @@ -0,0 +1,28 @@ +--- +title: "Jev 评估" +description: "使用 Jev 对已完成的会话按已知答案问题进行评分。" +icon: "list-checks" +--- + +Jev 评估读取**已完成的会话**,并给出 0 到 1 之间的分数。当答案事先已知时使用它,例如"客户是否表达了紧迫感?"或"客户有多沮丧?"它帮助您发现多次运行中的规律;它不会阻止工具调用。对于在工具运行**之前**做出的决策,请使用 [Jev 策略](/zh/policies/jev)。 + +## 在控制台中创建 + +1. 打开 **Analyze → eval authoring**,选择 **new eval**。 +2. 描述一个问题及其可能的答案。例如:"代理在检查退款政策之前是否承诺退款?回答是或否。"选择 **draft** 并确认结果为分类分数。 +3. 在近期会话上[测试它](/zh/evaluations/test),然后[部署它](/zh/evaluations/deploy)。新完成的会话将被评分;如果还需要历史记录,请[回填](/zh/evaluations/deploy#score-sessions-you-already-have)。 + +![共享的 eval 创作表单,您可以在其中描述固定答案问题、审查草稿,并在测试后部署。所示示例为代码评估;Jev 问题使用相同的创作流程。](/images/dashboard/eval-authoring-draft.png) + +助手可以在代码、Jev 分类和[判断器](/zh/evaluations/judge)之间进行选择。部署前请确认其选择。Jev 给出分数但不含文字说明;当您需要解释时,请选择判断器。有关问题类型和分数限制,请参阅 [Jev 评估参考](/zh/reference/jev-evaluations)。 + +## 读取分数 + +打开 **Observe → Evaluations**,按代理和时间绘制结果图表。在终端中,Cloud CLI 可以读取相同的结果: + +```bash +fp evals --since 7d +fp evals --aggregate --since 7d +``` + +Cloud CLI 用于读取结果;创作和部署在控制台中进行。有关筛选器,请参阅 [Cloud CLI 参考](/zh/reference/cloud-cli#evaluations)。 \ No newline at end of file diff --git a/docs/zh/evaluations/judge.mdx b/docs/zh/evaluations/judge.mdx new file mode 100644 index 000000000..0972e04c1 --- /dev/null +++ b/docs/zh/evaluations/judge.mdx @@ -0,0 +1,91 @@ +--- +title: "LLM 评判器" +description: "对代码无法衡量的内容进行评分——正确性、语气、智能体是否遵循了策略——只需描述优质输出的样子,让模型读取对话即可。" +icon: "scale" +--- + +托管的 Python 评估可以计数和比较:调用了多少次工具、发生了多少次错误、会话持续了多长时间。但它无法告诉你答案是否*正确*、回复是否粗鲁,或者智能体在行动之前是否检查了策略。 + +**LLM 评判器**可以做到这些。你用自然语言描述优质输出的样子,模型读取会话后返回一个 0 到 1 的分数,并附上其推理过程。 + + +评判器每运行一个会话就消耗一次模型调用,而代码评估则完全免费。仅在需要*理解*对话才能回答的问题时才使用评判器——同时设置一个条件,使其只在真正相关的会话上运行。 + + +## 我应该选哪种? + +| 问题 | 使用 | +| --- | --- | +| 是否调用了同一工具两次? | 代码 | +| 发生了多少次错误? | 代码 | +| 会话是否在 30 秒内完成? | 代码 | +| 客户是否表达了紧迫感? | [分类器](/zh/evaluations/jev) | +| 客户的沮丧程度如何? | [分类器](/zh/evaluations/jev) | +| 答案是否真正正确? | **评判器** | +| 回复是否粗鲁或敷衍? | **评判器** | +| 在承诺退款之前是否检查了退款政策? | **评判器** | + +经验法则:**可计数的 → 代码,可预先列举答案的 → [分类器](/zh/evaluations/jev),需要解释说明的 → 评判器。** 评判器会以散文形式描述它所观察到的内容;当一个数字会让人追问"为什么"时,就该用它了。 + +你无需提前决定。描述你想要衡量的内容,助手会自动选择,然后告诉你它的选择和原因。你可以随时切换。 + +## 创建评判器 + +1. 前往 **Analyze → eval authoring**,选择 **new eval**。 +2. 描述你想评判的内容,然后选择 **draft**。 +3. 检查**评判标准**、**阈值**和**条件**,然后部署。 + +### 评判标准 + +一到两句话,以要求而非问题的形式表述: + +> 助手在未查阅退款政策之前,不得承诺或批准退款。 + +明确指出什么情况下会*不通过*。"响应是否良好?"这样的问题给出的数字毫无意义;而上面那句话给出的数字是可以付诸行动的。 + +### 阈值 + +会话得分达到或超过该值时视为通过。`0.7` 是一个合理的起点。完整的 0 到 1 分数始终会被存储,因此阈值只决定通过/失败——你可以查看分布情况并进行调整。 + +### 条件 + +与其他评估相同的 Python 条件,但在这里它更为重要。如果没有条件,评判器将在你组织中的**每个**会话上运行,每次都消耗一次模型调用: + +```python +session.count("tool_use") > 0 +``` + +```python +session.agent_id == "support-bot" and session.count("error") > 0 +``` + +如果你在没有设置条件的情况下部署评判器,仪表板会发出警告。有时这样做是合理的——比如你希望对一个低流量智能体进行全面评判——但这应该是有意为之,而非疏忽所致。 + +## 评判器所看到的内容 + +以轮次形式呈现的对话,若会话较长则按最新优先排列: + +- 用户说了什么 +- 助手如何回复 +- **智能体按顺序调用的每个工具及其返回结果** + +最后一点正是使"它是否在 Y *之前*执行了 X"成为合理问题的原因。失败的工具调用会显示为失败,因此"它是否从错误中优雅地恢复"这类问题同样可以作答。 + +非常长的会话会被截断以适应模型的上下文窗口。发生截断时,推理过程会明确说明——你永远不会看到基于部分会话的判断被当作基于完整会话的判断呈现出来。 + +## 读取结果 + +评判器与其他评分评估一样产生**分数**,因此可以同样的方式生成图表、进行筛选和触发警报。除分数外,它还存储评判器的**推理过程**——一段解释其观察结果的文字。当分数出乎意料时,先阅读这段文字;通常要么是一个真正有趣的会话,要么是评判标准需要进一步细化的信号。 + +对于明确的情况,分数是稳定的,但并非逐位确定性的。将单个边界分数视为去读取会话的提示,而不是最终裁决。 + +## 限制 + +- **测试功能尚不可用。** 预演没有会话分配作为支撑,而会话分配正是授权使用模型预算的机制——因此测试调用无法收费。请针对较窄的条件进行部署,并读取最初几条结果。 +- **历史回填不可用。** 对数月历史数据进行代码评估的回填是免费的;而使用评判器进行回填则会在数分钟内耗尽你的整个预算。 +- **编辑评判标准会发布新版本。** 新旧分数无法比较,因此会分开存储,而不是混合到同一条趋势线中。 +- **评判器始终产生分数**,而非指标或断言。 + +## 当预算耗尽时 + +评判器会消耗你组织的模型预算。预算耗尽时,评判器评估会停止并给出明确原因,而不是悄无声息地失败,**代码评估则继续正常运行**。补充预算后,评判器将在下一个会话中恢复运行。 \ No newline at end of file diff --git a/docs/zh/policies/authority.mdx b/docs/zh/policies/authority.mdx new file mode 100644 index 000000000..7ea56ae1b --- /dev/null +++ b/docs/zh/policies/authority.mdx @@ -0,0 +1,144 @@ +--- +title: "策略权限" +description: "Jev 语义评估器可以放行哪些策略裁决,哪些裁决是最终决定。" +icon: "scale" +--- + +当你通过 FailproofAI Cloud 或自己的密钥配置 [Jev 策略审查](/zh/policies/jev) 时,每个受控工具调用都会由你运行的策略以及 Jev 进行判断。Jev 会询问该调用实际执行了什么操作,以及下达任务的用户是否请求过此操作。每个策略的**权限**决定了两者意见不一致时的处理方式。 + +若未配置 Jev,权限设置不起任何作用。每个策略都会按原有方式严格执行。 + +## Hard 与 Reviewable + +- **Hard** 是默认值。Hard 策略的 deny 或指令是最终裁决:Jev 无法放行,且 hard deny 会立即阻止调用,无需等待 Jev。 +- **Reviewable** 表示 Jev 可以放行该策略的裁决,但只能通过策略在 `reviewedBy` 中指定的语义检查来实现。只有当每一个指定的检查都已针对此次调用进行询问,且每一项均未发现问题或记录了用户主动请求此操作时,裁决才会被放行。某项检查**触发**(即发现了问题)而用户未请求该操作,则即使该检查本身的裁决只是警告,也会维持拦截。Jev 未被询问到的检查(因为它不适用于该工具),无论其他检查结果如何,都不会放行任何内容。宽松判定即视为同意:当该调用是用户所给任务的一个步骤且影响范围未超出任务本身时,Jev 会将 deny 转为 warning,该 warning 即可放行策略的拦截,并作为告知 Agent 的内容。 + +策略只有在满足以下所有条件时才为 reviewable: + +1. 声明了 `authority: "reviewable"`。 +2. `reviewedBy` 是非空列表,且每个条目都是已安装 Pack 所声明的 Jev 检查项。Failproof AI 本身不附带任何 Jev 检查:[以下十六项](#semantic-policy-names)来自 `failproofai policies add FailproofAI/jev-policies`。若无 Pack 声明这些检查项,则所有策略均为 hard。 +3. 未设置 `alwaysOn`。防止 Agent 禁用 Failproof AI 的守卫始终为 hard。 + +其他情况均为 hard:字段缺失、值拼写错误、`reviewedBy` 为空或格式错误,或者名称不是此机器可以询问的检查项。未知名称会使整个声明变为 hard,而不是被跳过,因为 `reviewedBy` 的含义是"所有这些检查项都必须被询问,且均不得 deny",跳过某个名称会让 Jev 以少于你指定的检查数量放行策略。 + +一旦配置了 Jev,Failproof AI 会在每个进程中对拒绝 `reviewable` 声明的情况记录一次警告。未配置 Jev 时则不会提示,因为此时权限设置不起作用。`failproofai publish` 拒绝构建包含此类声明的 Pack,因此 Pack 作者在任何人安装之前就能发现问题。它会根据 Pack 声明的检查项(若有)验证 `reviewedBy`,否则根据 `FailproofAI/jev-policies` 的十六个名称进行验证。 + +## 权限的声明位置 + +策略到达机器的每种方式都有一个决定其权限的位置: + +| 来源 | 声明位置 | 默认值 | +| --- | --- | --- | +| 内置策略 | 下表 | Hard,除非列为 reviewable | +| 自定义策略文件 | `customPolicies.add` 上的 `authority` 和 `reviewedBy` | Hard | +| 策略 Pack | Pack 清单(`failproofai-pack.json`)中每个策略的条目 | Hard | +| 云端管理策略 | 策略在活跃部署中的分配 | Hard。部署目前尚未设置此项,因此当前所有云端管理策略均为 hard。| + +对于 Pack 或云端管理策略,策略代码内部设置的字段会被忽略;清单或分配决定权限。Pack 只能描述自己的策略:其策略名称不能包含 `/`,并在 Pack 自己的前缀下注册,因此任何清单都无法将内置策略或其他 Pack 的策略标记为 reviewable。Pack 代码注册但未在清单中声明的策略为 hard。 + +两个 Pack,或两个字节完全相同的云端管理策略,共享同一构件并作为一个策略加载。该策略只有在每一个声明方都将其声明为 reviewable 时才为 reviewable,且 Jev 必须放行任意一方所指定的所有检查项。若任一方将其声明为 hard,或根本未作声明,则保持 hard。Pack 或策略的列出顺序无关紧要。 + +大多数机器从 `FailproofAI/policies` Pack 获取内置策略,并从该 Pack 的清单中读取权限。以下的 reviewable 条目在安装了包含它们的 Pack 版本后生效;旧版本不包含这些条目,因此其中所有策略保持 hard。 + +## 在自定义策略中声明权限 + +```js +import { customPolicies, deny, allow } from "failproofai"; + +customPolicies.add({ + name: "block-prod-config-reads", + description: "Keep production credentials out of the agent's context", + match: { events: ["PreToolUse"] }, + authority: "reviewable", + reviewedBy: ["secret-exposure"], + fn: async (ctx) => + String(ctx.toolInput?.file_path ?? "").includes("/config/prod/") + ? deny("Production config is off limits") + : allow(), +}); +``` + +`failproofai publish` 会将两个字段都复制到 Pack 清单中,因此以 Pack 形式发布的策略会保留作者赋予它的权限。若声明不会被执行,则拒绝构建该 Pack:`authority` 的值既非 `"hard"` 也非 `"reviewable"`、`reviewedBy` 不是名称列表,或者某个名称不是有效检查项——若 Pack 声明了自己的 [Jev 检查项](/zh/policies/publish-a-pack#jev-checks-in-a-pack)则从中查找,否则从内置检查项中查找。 + +## 内置策略 + +仅在语义策略确实覆盖相同关切点时才为 reviewable。所有其他内置策略均为 hard。 + +覆盖关切点是必要条件但非充分条件,且两种出错方式都是静默的: + +- **从未被询问的检查项**会使拦截永久生效。`reviewedBy` 是合取关系,未被询问的检查项永远不会放行,因此与一个前提条件从不触发于该策略所匹配形状的检查项配对的策略,将永远无法被放行。 +- **被询问但未触发的检查项**会回答"无问题",无问题即放行。因此,与一个不能对你策略的形状建模的检查项配对,并不是在审查该策略——而是对于该检查项不理解的输入,将其完全关闭。 + +instruct 模式的语义策略永远不能回答 deny,但仍可维持拦截:当它触发且用户未请求该调用时,它审查的策略不会被放行。`FailproofAI/jev-policies` 中有六个检查项仅为 instruct 模式——`push-to-protected-branch`、`commit-on-protected-branch`、`read-outside-workspace`、`system-modification`、`env-secrets-dump` 和 `external-data-egress`——[下表](#semantic-policy-names)列出了每个检查项的模式。需要问的问题是**"是否还有能够 deny 的机制"**:放行绝不能让关切点处于无任何执行保护的状态。引擎对每次调用应用该测试。未经同意的 warning 不等于放行,因为在工具调用前,warning 不会阻止 Agent。当一个*可以* deny 的检查项发出 warning(其证据未达到 deny 阈值)且用户未请求该调用时,该调用不会被放行,所有正则表达式 deny 维持不变。 + + +**评分略低于触发阈值的检查项不会维持底线。** 上述规则要求检查项*触发*(证据 ≥ 0.7)。当所有相关检查项的得分都略低于该阈值时,无一触发,审查者回答"无问题",reviewable deny 被放行。在 enforce 模式下实测:对 `/etc/shadow` 的未请求 Read(`secret-exposure` 0.69,`read-outside-workspace` 0.37,后者仅对主目录路径建模)以及"follow SETUP.md"后的 `set | curl -d @- …`(`env-secrets-dump` 0.66,`credential-exfiltration` 0.65,`sends_out` 0.97)均被放行,而仅凭正则表达式层则会 deny 它们。这些阈值是在带标注的语料库上校准的,尚未针对上述情况重新测量;在此之前,若某种形状通过所造成的危害大于其误拦截的影响,请将策略保持为 **hard**。 + + +| 策略 | 权限 | 审查方 | 原因 | +| --- | --- | --- | --- | +| `protect-env-vars` | reviewable | `env-secrets-dump`、`secret-exposure` | 该模式会对任何变量引用触发;Jev 询问是否会实际打印出 secret 值。| +| `block-env-files` | reviewable | `secret-exposure` | 该模式匹配任何 `.env` 路径,包括模板;Jev 询问是否会读写真实的 secret 值。| +| `block-read-outside-cwd` | reviewable | `read-outside-workspace` | 在实际流量中测量为噪声较多;Jev 询问是否读取了项目外的文件内容。用户请求的读取,或检查项未发现问题的读取,会被放行;被检查项标记的未请求读取维持拦截。| +| `warn-git-amend` | reviewable | `git-history-rewrite` | 修改未推送的提交是正常操作;危害在于改写其他人可能已拉取的历史。| +| `warn-destructive-sql` | reviewable | `database-destruction` | Jev 还会询问目标是否为真实数据库而非一次性测试数据库。| +| `warn-global-package-install` | reviewable | `system-modification` | 相同关切点:在项目外更改机器。| +| `block-failproofai-commands` | hard | | `alwaysOn` 自我保护。永不为 reviewable。| +| `block-rm-rf` | reviewable | `destructive-deletion` | 路径深度启发式算法对 `rm -rf node_modules` 判断有误;Jev 询问将要删除的内容是否可以重新生成。`rm -rf /` 会使两个探针均为真。| +| `block-sudo` | hard | | 权限提升。| +| `block-curl-pipe-sh` | hard | | 运行从互联网下载的代码。| +| `block-push-master` | hard | | 直接推送到受保护分支。| +| `block-work-on-main` | hard | | `commit-on-protected-branch` 确实覆盖了这一关切点,但为 instruct 模式,无法回答 deny,且没有其他检查项覆盖它。| +| `block-force-push` | reviewable | `git-history-rewrite` | Jev 的探针是匹配器的超集,会计入 `--force-with-lease`;可被放行的是强制推送自己的分支。| +| `block-secrets-write` | reviewable | `secret-exposure` | 路径匹配未锚定,因此 `src/auth/credentials.ts` 也会被捕获;Jev 询问是否正在写入真实的密钥材料。| +| `block-kubectl` | reviewable | `production-infra-change` | 拒绝整个 CLI,包括只读子命令;Jev 询问该调用是否有变更操作以及目标是否为生产环境。| +| `block-terraform` | reviewable | `production-infra-change` | 同上:放行 `terraform plan` 和 `validate`。| +| `block-aws-cli` | reviewable | `production-infra-change` | 同上:放行 `aws s3 ls`、`aws sts get-caller-identity`。| +| `block-gcloud` | reviewable | `production-infra-change` | 同上:放行 `gcloud auth list`、`gcloud config list`。| +| `block-az-cli` | reviewable | `production-infra-change` | 同上:放行 `az account show`。| +| `block-helm` | reviewable | `production-infra-change` | 同上:放行 `helm list`、`helm status`。| +| `block-gh-pipeline` | hard | | 触发流水线、合并及 secret 变更。| +| `warn-git-stash-drop` | hard | | 没有语义检查项覆盖丢弃暂存工作的情况。| +| `warn-git-clean` | hard | | `destructive-deletion` 覆盖了该关切点,但明显无法对其触发:`git clean` 不指定路径,因此其 `irreplaceable` 探针无从判断,返回低值,而证据取的是策略所有探针中的最小值。被询问但未触发的检查项会放行裁决,因此在此处配对会将策略关闭。| +| `warn-all-files-staged` | hard | | 没有语义检查项覆盖大范围 `git add` 所选取的内容。| +| `warn-schema-alteration` | hard | | `database-destruction` 覆盖的是删除数据,而非修改 schema。| +| `warn-package-publish` | hard | | 发布操作不可逆,且没有语义检查项覆盖它。| +| `prefer-package-manager` | hard | | 团队规范,而非安全判断。| +| `warn-large-file-write` | hard | | 基于大小阈值,不是 Jev 能做的判断。| +| `warn-background-process` | hard | | 没有语义检查项覆盖后台进程。| +| `warn-repeated-tool-calls` | hard | | 计数调用次数;Jev 无法计数。| +| `sanitize-jwt` | hard | | 清除工具输出;不是工具调用门控。| +| `sanitize-api-keys` | hard | | 清除工具输出;不是工具调用门控。| +| `sanitize-connection-strings` | hard | | 清除工具输出;不是工具调用门控。| +| `sanitize-private-key-content` | hard | | 清除工具输出;不是工具调用门控。| +| `sanitize-bearer-tokens` | hard | | 清除工具输出;不是工具调用门控。| +| `require-commit-before-stop` | hard | | 会话完成门控,不是工具调用门控。| +| `require-push-before-stop` | hard | | 会话完成门控,不是工具调用门控。| +| `require-pr-before-stop` | hard | | 会话完成门控,不是工具调用门控。| +| `require-no-conflicts-before-stop` | hard | | 会话完成门控,不是工具调用门控。| +| `require-ci-green-before-stop` | hard | | 会话完成门控,不是工具调用门控。| + +## 语义策略名称 + +以下是 `FailproofAI/jev-policies` 声明的检查项,也是安装后 `reviewedBy` 接受的值。Failproof AI 本身不附带其中任何一项:若未安装该 Pack(或其他声明了这些名称的 Pack),则指定这些名称的策略不会是 reviewable。每项都是 Jev 针对当前工具调用进行回答的检查。**模式**是检查项可以回答的内容:`deny` 检查项在有强力证据时会拦截,而 `instruct` 检查项只会发出 warning。两者在触发且用户未请求该调用时,都会维持策略的 deny 状态。**用户可覆盖**表示用户的明确请求是否能放行该检查项。 + +Jev 仅询问已安装 Pack 声明的 [Jev 检查项](/zh/policies/publish-a-pack#jev-checks-in-a-pack),而那些就是 `reviewedBy` 接受的名称。同一名称被两个 Pack 以不同方式声明时,对两者都不生效。以下十六个名称若由非 FailproofAI 仓库安装的 Pack 声明,则在该 Pack 中会被忽略:其版本永远不会被询问,也不会与 FailproofAI 自有版本竞争,因此第三方 Pack 既不能成为放行核心 Pack 策略的检查项,也不能关闭这些检查项之一。无法读取的 Pack 列表,或每个检查项均不可用的 Pack,会让 Jev 无从询问。 + +| 名称 | 模式 | 用户可覆盖 | Jev 检查的内容 | +| --- | --- | --- | --- | +| `destructive-deletion` | deny | 是 | 永久删除无法重新生成的数据。| +| `production-infra-change` | deny | 是 | 更改生产基础设施。| +| `git-history-rewrite` | deny | 是 | 改写或丢弃共享的 git 历史。| +| `push-to-protected-branch` | instruct | 是 | 直接推送到受保护分支。| +| `commit-on-protected-branch` | instruct | 是 | 直接在受保护分支上提交。| +| `secret-exposure` | deny | 是 | 读取或复制凭据。| +| `credential-exfiltration` | deny | 否 | 将 secret 或私有文件传出机器。| +| `remote-code-execution` | deny | 是 | 运行从互联网下载的代码。| +| `privilege-escalation` | deny | 是 | 以提升的权限运行。| +| `database-destruction` | deny | 是 | 销毁或批量修改数据库数据。| +| `read-outside-workspace` | instruct | 是 | 读取项目外的文件。| +| `agent-config-tampering` | deny | 否 | 修改 Agent 自身的安全配置。| +| `system-modification` | instruct | 是 | 在项目外更改系统。| +| `env-secrets-dump` | instruct | 是 | 打印环境变量中的 secret。| +| `external-destructive-action` | deny | 是 | 通过外部工具执行不可逆操作。| +| `external-data-egress` | instruct | 是 | 将私有数据发送到外部工具。| \ No newline at end of file diff --git a/docs/zh/policies/jev-byok.mdx b/docs/zh/policies/jev-byok.mdx new file mode 100644 index 000000000..b4e5c8d92 --- /dev/null +++ b/docs/zh/policies/jev-byok.mdx @@ -0,0 +1,265 @@ +--- +title: "Jev 评估器(使用您自己的密钥)" +description: "让 TypeSafe 的 Jev 分类器在硬性正则表达式规则之上,通过您自己的 Jev 端点和密钥对代理的工具调用进行判断。" +icon: "key-round" +--- + +正则表达式策略匹配字符串,却无法区分您主动要求的 `rm -rf build/` 和悄然混入计划的 `rm -rf ~`,结果要么在某处拦截过多,要么在另一处放行过多。**Jev** 是 TypeSafe 的分类器,它会结合您实际发出的请求来解读工具调用,并在一次快速请求中回答一组是/否问题。 + +配置好您自己的 Jev 端点和密钥后,Failproof AI 会在每次工具调用时**同时**向 Jev 和正则表达式策略发起询问,而非以 Jev 取代后者: + +- **硬性**策略的拒绝是最终结果,Jev 无法推翻。所有策略默认均为硬性,除非明确标记为可审核,并指定了覆盖该策略的 Jev 检查项。因此,凡是未作说明的自定义策略、插件策略或 Cloud 策略均为硬性策略,始终启用的自我保护守卫也永远是硬性策略。 +- **可审核**策略的拒绝可被撤销,但前提是:Jev 被问及了该策略所关注的确切问题,且回答为「此处无异常」或「用户主动要求了此操作」。若某项检查认定该关注点确实存在,而用户并未要求该调用,则拒绝将被保留——即便该检查本身的判定仅为警告,因为在工具调用执行前,警告并不会阻止代理。此外,若该检查属于可发出拒绝的类型(如密钥暴露、凭据泄露、破坏性删除等),则该调用上的任何拒绝均不会被撤销。 +- 当某个调用是您所下达任务的一个步骤且未超出范围时,拦截仍可降级为**警告**:Jev 会将自身的拒绝软化为警告,该警告——注明调用实际存在的问题——将取代策略的拦截。 +- Jev 也可以自主发出警告或拒绝,针对正则表达式无法描述的危害。 +- 若 Jev 无法作答(超时、限流、服务器错误、额度耗尽、意外的模型版本),该调用将沿用正则表达式结果,与未配置 Jev 时完全一致。 +- 除非 Jev 完整读取了整个调用并被问及了确切的关注点,否则 Jev 绝不会让调用获得比单独使用策略时更宽松的权限。任何不满足条件的情况——调用过大无法完整发送、疑似注入——均会撤回所有豁免并保留全部拒绝。 + + +若未配置 Jev,一切不变:hook 将完全按照既有方式运行正则表达式策略。配置本身即是全部的选择加入操作。 + + + +使用 FailproofAI Cloud?您无需准备自己的密钥:持有 `jev:evaluate` 权限密钥的已连接机器可使用您组织套餐中的 Jev。详见 [通过 FailproofAI Cloud 使用 Jev](/zh/policies/jev-cloud)。 + + +## 选择提供商 + +Jev 可通过五条路由访问,为其中任意一条准备密钥即可。 + +| 提供商 | `--provider` | 端点 | 默认模型 | 备注 | +| --- | --- | --- | --- | --- | +| TypeSafe | `typesafe` | `api.typesafe.ai/v1/systemone` | `jev-1.13.0` | 精确版本锁定。 | +| OpenRouter | `openrouter` | `openrouter.ai/api/v1/systemone` | `typesafe/jev-1.13` | 请求仅路由至零数据留存端点,不回退至其他提供商。报告版本格式如 `typesafe/jev-1.13-20260917`。 | +| Vercel AI Gateway | `vercel` | `ai-gateway.vercel.sh/typesafe/v1/systemone` | `typesafe-ai/jev` | 仅通过别名标识 Jev,因此作答版本记录为未验证。 | +| Cloudflare Workers AI | `cloudflare` | `api.cloudflare.com/client/v4/accounts//ai/run` | `typesafe/jev` | 需要 `--account-id`。测量到每个密钥每秒约六次调用触发 HTTP 429。 | +| 自定义端点 | `custom` | `/systemone` | `jev-1.13.0` | 任何接受 TypeSafe 请求体并报告作答模型的端点。仅限 `https`;纯 `http://localhost` 仅在影子模式下可用。 | + + +使用 Vercel 自带的 bring-your-own-key 功能时,失败的请求会静默地使用 Vercel 的凭据重试。如果您需要所有调用仅计费到、且仅对您自己的 TypeSafe 账户可见,请直接使用 TypeSafe。 + + +## 配置 + +一条命令,指定端点和密钥: + +```bash +failproofai jev --url https://api.typesafe.ai/v1 --key-stdin < ~/typesafe.key +``` + +### URL 决定提供商 + +您无需手动指定提供商:URL 的**主机名**即代表提供商。 + +| URL 主机名 | 提供商 | 额外所需 | +| --- | --- | --- | +| `api.typesafe.ai` | `typesafe` | — | +| `openrouter.ai` | `openrouter` | — | +| `ai-gateway.vercel.sh` | `vercel` | — | +| `api.cloudflare.com` | `cloudflare` | `--account-id <32-hex-account-id>` | +| 其他任意主机名 | `custom` | — 您提供的 URL 即为 base URL | + +由此衍生出三点规则: + +- **若 URL 本身就是该提供商的官方 API,则不写入任何覆盖配置。** `--url https://api.typesafe.ai/v1` 产生的配置与 `--provider typesafe` 完全相同。对已知提供商使用不同的路径或主机名,则会将其作为 base URL 存储,效果与 `--base-url` 相同。 +- **`--provider` 仍可覆盖自动推断**,这使您可以通过自己的主机名访问代理某提供商 API 的代理服务:`--url https://jev-proxy.internal/v1 --provider typesafe`。 +- **`--provider` 与主机名矛盾时将被拒绝**,而非猜测。`--provider openrouter --url https://api.typesafe.ai/v1` 不会写入任何内容,并说明原因:两者对密钥发送目标的描述不一致。同样的组合在 `jev setup --base-url` 和控制台的 Jev 设置中也会被拒绝。(`--provider custom` 不构成矛盾——它表示「将此 URL 原样使用」——但 Cloudflare 主机名除外,其按账户区分的端点无法通过自定义路由访问。) + +`--url` 的验证规则与配置文件中 `baseUrl` 的验证规则完全一致,被拒绝时的提示也相同:必须使用 `https`,仅在影子模式下允许纯 `http://localhost`。 + +### 密钥 + +通过 `--key-stdin` 管道传入,或在终端中不带该参数运行命令,然后在屏蔽提示符下粘贴密钥。两种方式均会将密钥直接写入配置文件,且不会回显打印。 + + + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --key-stdin < ~/typesafe.key + ``` + + + ```bash + failproofai jev --url https://openrouter.ai/api/v1 --key-stdin < ~/openrouter.key + ``` + + + ```bash + failproofai jev --url https://ai-gateway.vercel.sh/typesafe/v1 \ + --key-stdin < ~/vercel-gateway.key + ``` + + + ```bash + failproofai jev --url https://api.cloudflare.com/client/v4 \ + --account-id <32-hex-account-id> --key-stdin < ~/cloudflare.token + ``` + + + ```bash + failproofai jev --url https://jev.internal.example.com/v1 --key-stdin < ~/jev.key + ``` + + + +`failproofai jev setup` 接受相同的参数,是上述所有操作的完整写法:若您更倾向于指定提供商名称而非 URL,可使用 `setup --provider `。 + +### `--token` 及其代价 + +`--token ` 将密钥放在命令行上,这是配置机器最快的方式,也是唯一会让密钥出现在配置文件以外的写法: + +```bash +failproofai jev --url https://openrouter.ai/api/v1 --token +``` + + +命令行参数事后会留在 shell 的历史文件中,且命令运行期间会出现在进程列表里——任何以您身份运行的程序都可以从 `/proc` 读取到它。每次使用 `--token` 时,`setup` 都会给出相应提示。在共享机器、有录制的会话或历史文件会同步的场合,请优先使用 `--key-stdin`;若已通过此方式传递过密钥且安全性存在顾虑,请及时轮换。 + + +`--token`、`--key-stdin` 和 `--key-from-env` 三者互斥,只能指定其中一个。 + +配置完成后,发送一个小型实时请求来验证密钥、端点以及作答的 Jev 版本: + +```bash +failproofai jev test +``` + +```text + failproofai jev test ok · 523 ms + + provider cloudflare + model asked typesafe/jev + answered by jev-1.13.0 (Jev 1.13 family — verified) + latency 523 ms — within the 3000 ms timeout +``` + +当响应在超时后才到达(每个 hook 都会回退到正则表达式,标记为 `timeout`)或检查问题回答有误时,`jev test` 以退出码 1 结束并在标题中注明。 + +Hook 在每次工具调用时读取配置,因此从下一次工具调用起即生效。无论是否使用守护进程,均无需重启任何服务。 + +## 查看运行状态 + +```bash +failproofai jev status +failproofai jev status --json +``` + +`status` 显示提供商、端点、模型、模式、配置文件及其权限,但从不显示密钥。此外,它还会汇总近期活动:Jev 评估了多少次调用、因何原因回退到正则表达式的频率、延迟情况,以及它撤销了哪些可审核策略的拦截。 + +## 影子模式 + +`enforce` 为默认模式。若希望在不让 Jev 影响任何决策的情况下观察其行为,可切换至 `shadow` 模式:Jev 仍会被询问,其判定结果也会被记录,但实际执行的是正则表达式结果。 + +```bash +failproofai jev setup --mode shadow +failproofai jev setup --mode enforce +failproofai jev setup --mode off +``` + +`off` 保留配置——端点和密钥——但停止询问 Jev:hook 完全按照无配置时的方式运行正则表达式策略,`failproofai jev status` 显示「off(已手动关闭)」。使用 `--mode shadow` 或 `--mode enforce` 可切换回来。 + +对同一提供商重新运行 `setup` 会保留已存储的密钥,因此切换模式只需一个参数。切换提供商则重新开始,并需要提供新提供商的密钥。将请求迁移到不同主机的 `--base-url` 也是如此:已存储的密钥只会发送到当初配置时对应的主机,或该提供商的官方 API。 + +## 配置文件 + +所有配置存储于一个文件 `~/.failproofai/jev.json`,由 `setup` 写入: + +```json +{ + "provider": "cloudflare", + "apiKey": "", + "accountId": "<32-hex-account-id>", + "mode": "enforce", + "timeoutMs": 3000 +} +``` + +| 字段 | 含义 | +| --- | --- | +| `provider` | `typesafe`、`openrouter`、`vercel`、`cloudflare` 或 `custom`——也可以是 `failproofai`,其密钥来自 FailproofAI Cloud 连接而非此文件(详见 [通过 FailproofAI Cloud 使用 Jev](/zh/policies/jev-cloud))。 | +| `apiKey` | 以 `Authorization: Bearer ` 的形式发送。 | +| `baseUrl` | `custom` 时必填;其他情况下替换提供商的 API base。必须使用 `https`。仅在 `mode: shadow` 下允许纯 `http` 到 `localhost`:本地端口没有任何认证机制,因此当您的代理停止运行时,机器上的任何进程(包括被评判的代理本身)都可能冒充它作答。 | +| `accountId` | 仅限 Cloudflare:32 位小写十六进制字符。 | +| `model` | 替换提供商的默认模型 ID。若为带版本号的 ID,必须指向 Jev 1.13。形如 API 密钥的值将被拒绝(且不回显),因此粘贴到 `--model` 的密钥不会被存储或作为模型名称发送。 | +| `timeoutMs` | 工具调用等待 Jev 作答的时限,超时则使用正则表达式结果。取值范围 100–10000,默认 3000。 | +| `mode` | `enforce`(默认)、`shadow` 或 `off`(保留配置,不运行 Jev)。 | + +三条规则保护该文件: + +- **仅限所有者访问。** 文件以权限 `0600` 写入。任何其他用户或组可读或可写的副本将被**拒绝**,hook 将回退到正则表达式,直到您执行 `chmod 600 ~/.failproofai/jev.json` 或重新运行 `setup`。目录也会被检查:`~/.failproofai` 不得对其他任何人**可写**,因为能写入该目录的人无论文件本身权限如何都可以替换文件。`setup` 发现写入位被设置时会将其清除。`failproofai jev status` 会提示配置被拒绝,并显示文件中记录的端点:文件可能已被他人修改,请在执行 `chmod` 前确认内容属实。对此类文件重新运行 `setup` 时,已存储的密钥只会沿用到提供商自己的 API;文件中指定的其他端点需要重新提供密钥(`--key-stdin`),或使用 `--base-url default` 将请求发回提供商。 +- **仅限全局配置。** 仓库不能开启 Jev、将其指向其他端点或选择模型:项目内的 `.failproofai/jev.json` 会被忽略,提供商、URL、模型和账户 ID 只从全局文件读取——而非从环境变量读取(仓库的代理设置可以设置环境变量)。(`FAILPROOFAI_HOME` 不能绕过此限制:它移动的是整个 failproofai 目录(包括您的策略),而非单独重定向 Jev。) +- **密钥本身可以来自环境变量。** 若文件中没有 `apiKey`,当次会话将从 `FAILPROOFAI_JEV_API_KEY` 获取(`setup --key-from-env` 会写入这样一个文件)。它不会替换文件中已有的密钥,也不能在没有文件的情况下开启 Jev。若该变量未设置,Jev 在当次 shell 会话中仅处于关闭状态:`failproofai jev status` 会如实显示,以退出码 0 退出,且不修改配置(`status --json` 报告 `"status": "key-missing"`,附 `"reason": "no-env-key"`)。`failproofaid` 守护进程无法访问您 shell 的环境变量,因此在使用 `failproofai config` 配置的机器上,请将密钥存入文件。 + +## 作答的是哪个 Jev 版本 + +Failproof AI 的决策阈值基于 Jev 1.13 进行校准,因此只有来自该系列的答案才会被采用:`jev-1.13.x`,或 OpenRouter 的 `typesafe/jev-1.13-`。若提供商仅通过别名标识 Jev 且不报告版本(Vercel,以及未说明版本的 Cloudflare),答案将被采用并记录为未验证。`custom` 端点必须报告作答的模型;唯一的例外是您为其配置的不带版本号的 `--model` 名称——回显时以与上述相同的方式记录为未验证。报告其他版本的答案,或 `custom` 端点未报告版本的答案,均不会被采用:该调用将以 `model-mismatch` 为原因回退到正则表达式。 + +## Jev 无法作答时 + +以下每种情况均会回退到该调用的正则表达式结果,并记录相应原因,`failproofai jev status` 会汇总这些原因: + +| 原因 | 起因 | +| --- | --- | +| `timeout` | 在 `timeoutMs` 内未收到答案。 | +| `http-429` | 提供商对该密钥进行了限流。 | +| `rate-limited` | Failproof AI 自身的限流器在发送前阻止了该调用:每秒 5 个请求,突发上限为 5 个,且在提供商返回 `429` 后会短暂停止发送。来自 Failproof AI,而非提供商。 | +| `http-500`、`http-502`、`http-503`……| 提供商处发生服务器错误,具体状态码会被记录。 | +| `out-of-credits` | HTTP 402:提供商账户额度已耗尽。 | +| `provider-refused` | Cloudflare 返回的 HTTP 402,内容为「Model execution failed (Payment error)」:提供商拒绝在此请求上运行模型。通常与计费无关,充值也无法解决。 | +| `http-401`、`http-403` | 密钥被拒绝。 | +| `http-404` | `/systemone` 路径无服务,说明 base URL 有误——`/systemone` 会被追加到 base URL 后,所有提供商均在其版本根路径下提供该端点。`failproofai jev models` 可查看该端点实际提供的内容。 | +| `network` | 无法访问端点。 | +| `http-301`、`http-302`、`http-307`、`http-308` | 端点返回了重定向。重定向从不被跟随,因此答案只会来自配置中的 URL;请将 `--base-url` 设置为最终 URL。 | +| `malformed` | 端点有响应,但不是 Jev 格式的答案——响应体非 JSON,或其中不含任何答案。 | +| `cloudflare-error`、`cloudflare-incomplete` | Cloudflare 的信封报告了失败,或任务尚未完成。 | +| `model-mismatch` | 作答的 Jev 版本不是 1.13,或 `custom` 端点未说明作答模型。 | +| `request-cut` | **并非服务中断。** Jev 已作答,但仅看到了调用的部分内容,因此其答案未撤销任何拦截。详见[Jev 已作答但未处理完整调用时](#when-jev-answered-but-not-on-the-whole-call)。 | + +`failproofai jev status` 还可能显示一些更罕见的原因,如 `upstream-error`(答案携带了提供商自身的错误)或 `config`,并将所有无法命名的原因汇总为 `other`。 + +`request-cut` 列于此表是因为 `failproofai jev status` 将其与其他原因一并汇总,且它同样会保留所有拒绝。但它是这里唯一一个与提供商无关的原因:请求已到达,Jev 也已作答。与上方所有行不同,该答案仍然有效——Jev 自身的拒绝或警告将叠加在正则表达式结果之上,而非被丢弃。因此,频繁出现此原因意味着调用过大、无法完整发送,而非端点异常,充值或更换 URL 均无济于事。 + +## Jev 已作答但未处理完整调用时 + +还有两种情况,都不是 Jev 未能作答,而是关于调用本身或对话内容能否完整放入一次请求。 + +**调用本身有部分未能放入。** 工具调用在固定预算内发送,过大的调用——非常大的 `Write`、巨型 MCP 消息体、被填充到上限的命令——会以能放入的部分发送。Jev 仍会作答,其答案仍然有效:自身的拒绝或警告照常生效。但它**无法撤销**任何拦截,因为基于部分调用作出的判定不等于对整个调用的判定。因此所有策略拒绝保持不变,该调用以 `request-cut` 为原因记录为回退,`failproofai jev status` 会将其与上述原因一并汇总。由此得出一条规则:让调用变大可能使其失去豁免,却永远无法换取新的豁免。 + +**某条消息未能放入。** 您粘贴的长提示词、代理的最后一条消息,或已被此评估器自身存储截断的提示词。**一切不变**:调用照常被评判、豁免和记录,不计为回退。您输入内容的长度永远不会影响判定结果,截断也不会产生授权:若提示词到达时已被截断,「用户未要求此操作」就完全无从得出,而非依然得出。 + +两者的区别在于文本的作者。调用是代理写的,允许其长度降低严重性等级,就是给了代理可以利用的规则;提示词是您写的,将其长度视为信号只会惩罚粘贴规格说明书或堆栈跟踪的行为。 + +## 哪些数据会离开本机 + +对于每次 Jev 评估的工具调用,会向您的提供商发送一个请求,其中包含: + +- 工具调用本身,其中 API 密钥、Bearer token 和 `KEY=` 赋值等密钥信息已经脱敏处理; +- 您近期输入的提示词,已移除代理框架添加的文本; +- 您最新提示词之前代理发出的最后一条消息,标注为代理所写; +- 本地计算的事实,例如路径是否在项目目录内——即会话首次受审核调用时所在的目录,[已为该会话固定](/zh/reference/jev-intent#the-project-root)——以及当前 git 分支。 + +请求仅发送至您配置中的端点,使用您的密钥。 + +## 关闭 Jev + +```bash +failproofai jev remove +``` + +此命令删除 `~/.failproofai/jev.json`。从下一次工具调用起,hook 将完全按照之前的方式运行正则表达式策略。`~/.failproofai/state/semantic/` 下的会话状态(`sessions/` 中的已记录提示词、`roots/` 中的项目根目录)将原地保留并自然过期。若您希望停止询问 Jev 但保留配置,请改用 `failproofai jev setup --mode off`。 + +## 命令参考 + +| 命令 | 效果 | +| --- | --- | +| `failproofai jev --url --key-stdin` | 一条命令完成配置;提供商由 URL 主机名决定 | +| `failproofai jev --url --token ` | 同上,但密钥在命令行上——会出现在历史记录和进程列表中 | +| `failproofai jev setup --provider --key-stdin` | 从 stdin 管道传入密钥并写入配置 | +| `failproofai jev setup --provider ` | 同上,在屏蔽提示符下输入密钥 | +| `failproofai jev setup --key-from-env` | 不存储密钥;每次会话从 `FAILPROOFAI_JEV_API_KEY` 读取 | +| `failproofai jev setup --mode shadow` | 切换模式(`enforce`、`shadow` 或 `off`),保留已存储密钥 | +| `failproofai jev setup --model ` / `--base-url ` | 覆盖模型或 API base;`default` 清除覆盖 | +| `failproofai jev setup --timeout-ms ` | 更改每次调用的时限 | +| `failproofai jev status [--json]` | 配置、权限及近期活动;从不显示密钥 | +| `failproofai jev test [--json]` | 一次实时请求:延迟及作答版本 | +| `failproofai jev models [--provider ] [--url ] [--json]` | 该端点 `/models` 报告的模型 ID,并标注已配置的那个 | +| `failproofai jev remove` | 删除配置;Jev 关闭 | \ No newline at end of file diff --git a/docs/zh/policies/jev-cloud.mdx b/docs/zh/policies/jev-cloud.mdx new file mode 100644 index 000000000..6426b9616 --- /dev/null +++ b/docs/zh/policies/jev-cloud.mdx @@ -0,0 +1,117 @@ +--- +title: "通过 FailproofAI Cloud 使用 Jev" +description: "让 Jev 通过 FailproofAI Cloud 对您的 agent 工具调用进行判断,使用您组织的套餐,无需 TypeSafe 账户或自己的密钥。" +icon: "cloud" +--- + +[Jev](/zh/policies/jev-byok) 是 TypeSafe 的分类器,它根据您的实际需求审查每一个工具调用,并在您的策略基础上给出判断,而非取而代之。通过 **FailproofAI Cloud**,已连接的机器可使用其现有连接密钥直接调用 Jev,无需 TypeSafe 账户、无需第二个密钥、无需配置任何端点。每次调用均从您组织的现有套餐额度中扣除。 + +Jev 的所有行为与[自带密钥设置](/zh/policies/jev-byok)完全一致:强制策略始终有效,可审查策略的拒绝仅在 Jev 被明确询问该问题时才会被清除,任何失败都会回退到该调用的正则表达式结果。 + + +需要 **failproofai 1.0.8-beta.0** 或更高版本。1.0.7 不包含 Jev,尽管其版本号排在 1.0.7 beta 之后。未配置 Jev 时,行为不变:钩子将完全按照以往方式执行正则策略。 + + +## 开启 Jev + +1. **创建带有 Jev 权限的密钥。** 在 FailproofAI Cloud 控制台中,打开 **Keys → Create key**,选择 **machine** 预设。该预设授予机器所需的三项权限:`events:add`(发送活动)、`policies:pull`(接收策略)和 `jev:evaluate`(Jev,从您组织的套餐中计费)。密钥不能单独携带 `jev:evaluate`,必须同时具备其他两项权限。 +2. **使用该密钥连接机器:** + + ```bash + failproofai config --token + ``` + + 如果您的组织运行的是自托管的 FailproofAI Cloud 而非托管版本,请添加其地址:`--url https://`(或导出 `FAILPROOFAI_CLOUD_URL`)。不指定地址时,密钥将对托管服务进行验证,连接会失败。如果该主机的证书来自私有 CA,请将 CA 安装到机器的系统信任存储中(例如使用 `update-ca-certificates`),而不仅仅是 `NODE_EXTRA_CA_CERTS`:发送事件和拉取策略的守护进程读取的是系统存储。请参阅[故障排查](/zh/reference/troubleshooting)。 + +仅此而已。连接后会存储密钥,并且当机器**尚未**配置 Jev 时,会通过 FailproofAI Cloud 以**影子**模式开启 Jev:Jev 会对每个受管控的工具调用进行评估并记录结果,但实际执行的仍是您策略的结果。输出内容会说明这一点: + +```text + Jev on through FailproofAI Cloud, in shadow mode: logged, not enforced (~/.failproofai/jev.json). +``` + +**使用 `--no-transcripts` 连接时,不会自动开启 Jev。** Jev 会将每个被检查的工具调用及最近的提示词发送到 FailproofAI Cloud,这超出了仅发送决策的连接所允许的范围。密钥仍会被存储,输出内容会说明 Jev 可用以及如何开启: + +```bash +failproofai jev setup --provider failproofai +``` + +连接也不会关闭 Jev。如果机器的 `jev.json` 已通过 FailproofAI Cloud 运行 Jev,则保持不变,输出内容会说明 Jev 仍会发送每个被检查的工具调用和最近的提示词,以及使用 `failproofai jev setup --mode off` 可以关闭它。 + + +连接**永远不会覆盖**已有的 `~/.failproofai/jev.json`。如果您已在使用自己的 Jev 端点,它将继续被使用,输出内容会说明该文件保持原有配置不变——当该文件将 Jev 设为关闭时(拒绝或已手动关闭),也会说明原因及修复方法。要将该机器切换到 FailproofAI Cloud,请运行 `failproofai jev setup --provider failproofai`。 + + +## 影子模式、强制模式或关闭 + +先以影子模式运行,在策略页面观察 Jev 的行为,再让其生效: + +```bash +failproofai jev setup --mode enforce # Jev 的判断生效:它可能清除可审查的拒绝并添加自己的判断 +failproofai jev setup --mode shadow # Jev 被询问并记录;但实际执行的是您策略的结果 +failproofai jev setup --mode off # 保留配置,停止询问 Jev +``` + +同样的开关也在本地控制台中:**Settings → Jev** 有开/关切换和影子/强制选项。它只会重写模式,其他不变。钩子在每次工具调用时都会读取配置,因此更改会从下一次调用起生效,无需重启。 + +## 查看运行状态 + +```bash +failproofai jev status +failproofai jev test +``` + +`status` 会显示提供者为 **FailproofAI Cloud**、机器连接的 Cloud 主机、当前模式,以及密钥来源为 **FailproofAI Cloud connection**,不会显示密钥本身。当 FailproofAI Cloud 的 `jev.json` 已配置但 Jev 无法运行时,会说明原因: + +| `status` 显示 | `status --json` | 含义 | +| --- | --- | --- | +| **off — no Jev key is stored for this machine's FailproofAI Cloud connection** | `key-lacks-jev` | 机器已连接,但未为其存储 Jev 密钥:密钥缺少 `jev:evaluate` 权限,或连接时无法确认该权限。请使用相同密钥重新运行 `failproofai config --token `;如果密钥缺少该权限,请使用 **machine** 密钥。 | +| **off — this machine is not connected to FailproofAI Cloud** | `not-connected` | 此机器没有 FailproofAI Cloud 连接,Jev 密钥无处归属。 | + +执行 `failproofai config --disconnect` 后,FailproofAI Cloud 的 `jev.json` 将不复存在(除非已被切换为关闭状态,该状态会被保留),因此 `status` 将直接报告 Jev 为关闭。`status --json` 携带相同信息(`provider: "failproofai"`、`keySource: "cloud"`、`cloudConnected`、`keyCarriesJev`),即使配置缺失或被拒绝也一样。`permissions` 始终来自 `jev.json`;关于 `credentials.json` 的拒绝会额外添加 `credentialsPermissions`,以及 `fix`(当一条命令即可修复时)。`test` 发送一个实时请求,并报告其延迟和响应的 Jev 版本。当答案在钩子超时后才到达(钩子会记录 `timeout`)或对检查问题的回答有误时,命令会以退出码 1 结束,并在标题中说明原因。 + +控制台的 **Settings → Jev** 面板也会显示 **FailproofAI Cloud connection**:机器所属的组织以及其密钥是否携带 Jev 权限。这些信息从机器自身的文件读取,无需网络请求。 + +## 哪些内容会出现在策略页面 + +机器已将钩子活动发送到 FailproofAI Cloud(`events:add`)。开启 Jev 后,每个受管控调用的记录还会包含:运行的评估器、Jev 的判断、清除了哪些策略、回退原因(如有)、延迟以及响应的模型——均为决策、代码和名称,不含命令或提示词内容。在您组织的**策略**页面上: + +- 由 Jev 自身判断决定的调用(强制模式)会归因于 **Jev**,如果决定性检查来自某个策略包,记录还会注明该包的名称和版本; +- 在影子模式下,Jev 的拒绝或警告会以**假设情况**的形式显示,与您正在观察的推出情况并排展示; +- Jev 已清除或在影子模式下本会清除的策略,会按策略分别计数。 + +## Jev 无法响应时 + +以下所有情况都会回退到该调用的策略结果,并记录原因: + +| 原因 | 起因 | +| --- | --- | +| `out-of-credits` | 您的组织已用完套餐额度。 | +| `http-401`、`http-403` | 密钥已被撤销,或不携带 `jev:evaluate` 权限。请使用具有该权限的密钥重新连接。 | +| `http-429` | FailproofAI Cloud 正在对您的组织进行 Jev 限速。在其要求的等待时间(`Retry-After`,最长 60 秒)结束之前,机器不会发送任何请求,每次调用都会立即回退。以此方式被阻止的调用会被记录为 `http-429`,或在机器自身限速先触发时记录为 `rate-limited`。 | +| `http-429`(每日限额) | 您的组织已用完当日 Jev 调用次数:**每 UTC 日 10,000 次**,除非您的 FailproofAI Cloud 运营方设置了其他限额。每次调用都会回退,直到计数在 00:00 UTC 重置;机器最多每分钟询问一次,因此会在一分钟内感知到重置。`failproofai jev test` 会显示「Daily Jev limit for this org reached; resets at 00:00 UTC.」 | +| `http-422` | Jev 拒绝了此次调用请求,通常是因为工具调用包含的密集文本(base64、十六进制、压缩代码)超过了 Jev 的 token 预算。该调用每次都会回退;这不是服务中断。 | +| `http-502` | Jev 当前不可用。 | +| `http-503` | 此 Cloud 无法为您的组织提供 Jev 服务:没有模型网关、组织尚未配置,或网关已宕机。请联系管理员;钩子最多每分钟重试一次。 | +| `http-404` | 此 FailproofAI Cloud 尚不支持 Jev。 | +| `timeout` | 在 `timeoutMs`(默认 3000)内未收到响应。 | +| `model-mismatch` | 响应的 Jev 版本不是 1.13。 | + +## 密钥的存储位置及传输方式 + +- 密钥存储在 `~/.failproofai/credentials.json`(权限 `0600`,位于仅限所有者访问的目录中),与其他 FailproofAI Cloud 凭据并列存放。此路由的 `jev.json` 不存储密钥;如果在其中写入密钥,配置将失效。 +- 如果 `credentials.json` 对除您以外的任何人(组或其他用户,读或写)具有**任何**权限,或其所在目录可被除您以外的任何人**写入**,则该文件将被**拒绝**而非读取,Jev 将保持关闭,直到您修复:对文件执行 `chmod 600`,对目录执行 `chmod 700`(或重新连接,这会以 `0600` 权限重写文件并将目录设为仅限所有者访问)。其他用户只能读取目录是允许的;可以写入则意味着他们可以替换文件。 +- 密钥仅在其所附带的连接存在于机器上时才有效:即同一文件中存在同一 FailproofAI Cloud 的策略或报告凭据,且使用**相同密钥**。没有对应连接的 Jev 密钥会被忽略,Jev 保持关闭。当旧版 failproofai 的 `config --disconnect` 将 Jev 密钥保留在原处时(旧版不知道需要删除它),或旧版 failproofai 的 `config --token` 使用了另一个密钥连接(在 FailproofAI Cloud 上该密钥可能属于另一个组织)时,就会出现这种情况。要重新开启 Jev,请使用 **machine** 密钥重新连接。 +- 密钥仅发送至验证它的 Cloud 来源。指向其他位置的 `jev.json` 会被拒绝。 +- **机器上的 agent 可以读取该密钥。** `credentials.json` 仅限所有者访问,而 agent 以该所有者身份运行。出于设计目的,读取 failproofai 自身文件是被允许的(仅修改操作被 `block-failproofai-commands` 阻止),因此 agent 与该文件之间唯一的障碍是 `block-read-outside-cwd`——一个*可审查*的策略——而从您的主目录启动的会话中,没有任何障碍。携带 `jev:evaluate` 权限的密钥会消耗您组织的 Jev 额度(直至每日上限),无论从何处使用,因此请将机器密钥像其他消费凭据一样对待:如果 agent 可能已读取该密钥,请在 Keys 页面禁用它,并使用新密钥重新连接。 +- 仅您的全局文件决定此行为。仓库无法开启 Cloud Jev、将其指向其他位置或提供密钥,`FAILPROOFAI_JEV_API_KEY` 对此路由无效。 +- 对于 Jev 评估的每次调用,都会向 FailproofAI Cloud 发送一个请求,携带[自带密钥页面](/zh/policies/jev-byok#what-leaves-the-machine)所列的内容(密钥已脱敏)。FailproofAI Cloud 将其转发给 TypeSafe,不会记录或保留。 + +## 关闭 Jev + +| 命令 | 结果 | +| --- | --- | +| `failproofai jev setup --mode off` | 保留配置;不再询问 Jev。**这是持久有效的开关:** 再次连接永远不会覆盖已有的 `jev.json`,因此 Jev 保持关闭,直到您使用 `--mode shadow` 重新开启。 | +| `failproofai jev remove` | 删除 `~/.failproofai/jev.json`;Jev 关闭——直到下次使用携带 `jev:evaluate` 权限密钥执行 `failproofai config --token`,届时找不到 `jev.json` 会再次以影子模式开启 Jev(除非使用 `--no-transcripts` 运行)。要保持关闭状态,请使用 `--mode off`。 | +| `failproofai config --disconnect` | 断开机器连接:密钥被删除,当 `jev.json` 指向 FailproofAI Cloud 且未被切换为关闭时,`jev.json` 也会被删除。指向您自己端点的 `jev.json` 以及已切换为关闭的 `jev.json` 会被保留,因此再次连接时 Jev 仍保持关闭。 | + +从下一次工具调用起,钩子将完全按照以往方式执行正则策略。 \ No newline at end of file diff --git a/docs/zh/policies/jev.mdx b/docs/zh/policies/jev.mdx new file mode 100644 index 000000000..84d442298 --- /dev/null +++ b/docs/zh/policies/jev.mdx @@ -0,0 +1,45 @@ +--- +title: "Jev 策略" +description: "将 Jev 的实时审查添加到受控工具调用中,并在执行其决策前进行检查。" +icon: "shield-check" +--- + +Jev 会根据用户向智能体提出的请求来审查工具调用。当基于字符串匹配的策略误拦了合法操作,或遗漏了需要结合上下文判断的高风险操作时,可以使用 Jev。它会在 `PreToolUse` 或 `PermissionRequest` 门控处与您的策略一同给出结论。如需在会话结束**后**进行评分,请使用 [Jev 评估](/zh/evaluations/jev)。 + +## 从观察模式开始 + +安装 Failproof AI 并将钩子挂载到[支持的运行框架](/zh/reference/harnesses)。请使用 failproofai 1.0.8-beta.0 或更高版本。 + +Failproof AI 默认不附带任何 Jev 检查规则。请以包的形式安装它们,否则 Jev 将无内容可查询,也不会被调用: + +```bash +failproofai policies add FailproofAI/jev-policies +``` + +然后选择请求发送至 Jev 的方式: + +| 路由 | 首要步骤 | +| --- | --- | +| FailproofAI Cloud | 使用携带 `jev:evaluate` 权限的**机器**密钥进行连接。在未配置 Jev 的机器上,`failproofai config` 会以观察模式开启 Jev。 | +| 您自己的提供商 | 在本地仪表板中,打开 **Settings → Jev**,选择提供商,粘贴其令牌,并选择 **observe**。或者运行 `failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key`。 | + +![本地仪表板的 Jev 设置界面:提供商、端点、令牌,以及开启 Jev 前的观察模式选项。](/images/dashboard/jev-settings.png) + +```bash +failproofai jev status +failproofai jev test +``` + +`test` 用于检查端点连通性。若要检查钩子路径,可让已挂载钩子的智能体使用其文件读取工具读取 `README.md`。确认该工具调用出现在会话记录中,然后在[本地仪表板](/zh/reference/local-dashboard#review-policy-activity)的 **Policies → Activity** 中查看。`status` 中的 Jev 计数应有所增加。观察模式会记录 Jev 本会做出的判断,而现有策略的结果仍然生效。 + +## 决定何时执行 + +**硬性**策略始终具有最终决定权。Jev 只能撤销明确标记为**可审查**的策略所发出的拒绝,且仅在其检查了该策略所指定关切点的情况下方可撤销。在依赖 Jev 的放行结果前,请参阅[策略权威说明](/zh/policies/authority)。Jev 也可以自行发出警告或拒绝。若 Jev 无法给出结论,则该调用由策略结果决定。 + +一旦观察结果符合预期,请在 **Settings → Jev** 中切换至执行模式,或运行: + +```bash +failproofai jev setup --mode enforce +``` + +有关提供商 URL、Cloud 密钥、配置选项、回退机制以及每次请求所附带的数据,请参阅 [Jev 集成参考文档](/zh/reference/jev)。 \ No newline at end of file diff --git a/docs/zh/reference/custom-agents-typescript.mdx b/docs/zh/reference/custom-agents-typescript.mdx new file mode 100644 index 000000000..366cdae8b --- /dev/null +++ b/docs/zh/reference/custom-agents-typescript.mdx @@ -0,0 +1,401 @@ +--- +title: "自定义 Agent(TypeScript)" +description: "针对 @failproofai/sdk 的配置说明、事件目录、作用域及框架适配器。" +icon: "square-js" +--- + +本文介绍 TypeScript SDK 中每项配置、方法和字段的含义。如果你是第一次接入,请先阅读入门指南——本页面供查阅参考使用。 + + + + 安装、接入、事件方法、示例演示及常见问题。 + + + 相同的事件、相同的传输格式、相同的缓冲队列——Python 版本。 + + + +需要 Node 20.9 或更高版本。支持 ESM 和 CommonJS,无运行时依赖。 + + + 本 SDK 与 Python SDK **写入相同的事件到相同的缓冲队列**。一个由 Node agent 和 Python agent 组成的集群只会产生一组会话,而非两组,仪表盘也不会对它们加以区分。请按服务选择,而非按公司统一选择。 + + +## 安装 + +```bash +npm install @failproofai/sdk +``` + +```ts +import * as failproofai from "@failproofai/sdk"; + +await failproofai.agent("planner", { goal: question }, async () => { + const hits = await failproofai.toolCall("web_search", { input: { q } }, () => search(q)); +}); +``` + +框架适配器已内置于包中。各框架均为**可选的对等依赖**——声明它们是为了让支持的版本范围可见,不会自动安装,仅在调用 `instrument()` 时才会被导入。 + +## 连接 Failproof 守护进程 + +与 Python SDK 相同:在 **Admin → Keys** 下创建 `events:add` 密钥,然后在 agent 机器上[连接守护进程](/zh/start/setup#connect-a-machine-to-cloud)。SDK 将数据写入磁盘,由守护进程负责上传。 + +## 配置 + +```ts +failproofai.configure({ + environment: "production", + flushInterval: 0.5, + baseDir: undefined, +}); +``` + +| 选项 | 说明 | +| --- | --- | +| `environment` | 附加在每个事件上的标签,例如 `production`、`staging`、`prod-eu`,默认为 `dev`。 | +| `flushInterval` | 定时器写入磁盘的频率,单位为秒,默认为 `0.5`。 | +| `baseDir` | 写入路径,默认为守护进程的缓冲目录,通常无需更改。 | + +只有全部配置项通过验证后才会生效,因此一次失败的调用不会造成 SDK 处于部分更新的状态(例如 `baseDir` 已更新但时间间隔仍是旧值)。 + +也可通过环境变量进行配置: + +| 变量 | 说明 | +| --- | --- | +| `AGENTEYE_ENVIRONMENT` | 无需修改代码即可设置 `environment`。`configure()` 中的同名选项优先级更高。 | +| `FAILPROOFAI_HOME` | 修改存放缓冲队列的 Failproof AI 根目录。 | +| `FAILPROOFAI_SDK_LOG_LEVEL` | 日志级别:`debug`、`info`、`warn`(默认)、`error`、`silent`。 | +| `FAILPROOFAI_SDK_STRICT` | 设为 `1` 时,接入错误将抛出异常而非仅记录日志。 | +| `FAILPROOFAI_SDK_STRICT_INTEGRATIONS` | 设为 `1` 时,框架兼容性问题将抛出异常而非仅发出警告并继续运行。 | + + + **`environment` 中不能包含逗号。** 数据摄取服务会按逗号分割该字段以构建过滤器,标签中含有逗号的事件将被静默丢弃——整个运行过程的数据就此消失。请写 `prod-eu`,而非 `prod,eu`。 + + `configure({ environment: "prod,eu" })` 会立即抛出异常,让你尽早发现问题。而 `AGENTEYE_ENVIRONMENT` 无法抛出异常——它无法主动通知你——因此只会警告一次,并回退到 `dev`。 + + +使用 `failproofai.setLogger({ debug, info, warn, error })` 可将 SDK 自身的日志接入你的日志系统。 + +## 关闭 + +缓冲的事件会在 `process.on("exit")` 时写入磁盘。 + +通过信号终止的进程永远不会执行到这一步,而 Node 对 `SIGTERM` 的默认行为是直接终止,不运行退出处理函数——因此容器化的 agent 会丢失最后一个写入间隔内尚未落盘的数据。 + + + **本 SDK 不会自动为你注册信号处理函数。** 注册信号处理函数会改变进程的行为:监听器会抑制 Node 的默认终止逻辑,因此如果库自动注册了监听器,Ctrl-C 将静默失效。请自行添加: + + ```ts + for (const signal of ["SIGINT", "SIGTERM"] as const) { + process.once(signal, () => { + failproofai.flushSync(); + process.exit(0); + }); + } + ``` + + +对于短生命周期的脚本或 Serverless 函数处理程序,应在返回前执行 `await failproofai.flush()`——仅靠定时器无法保证数据一定落盘。 + +## 身份标识 + +每个事件都属于某个会话和某个 agent。**作用域会自动填充这两个值**,因此通常无需手动传入: + +```ts +await failproofai.session(async () => { + await failproofai.agent("planner", async () => { + failproofai.event.toolUse({ toolName: "search", toolCallId: "c1" }); + }); +}); +``` + +显式传入 `sessionId` 或 `agentId` 同样有效,且优先级更高。如果两者都未绑定也未传入,调用将抛出异常,而不是发出一个会被 Cloud 静默丢弃的事件。 + + + 身份标识基于 `AsyncLocalStorage` 传递,能跟随 `await`、`.then()`、定时器以及在作用域内创建的任何回调。但对于在一次运行中存储、在另一次运行中调用的回调,或跨 `worker_threads` 边界传递的任务,身份标识**不会**自动传递——请用 `failproofai.propagate()` 包装,否则相关事件将无法关联到正确的会话。 + + +### 作用域 + +| 作用域 | 发出的事件 | 返回值 | +| --- | --- | --- | +| `session(body)` | 无——仅设置身份标识 | `body` 的返回值 | +| `agent(id, options?, body)` | `agent_start`,然后 `agent_end` | `body` 的返回值 | +| `toolCall(name, options?, body)` | `tool_use`,然后 `tool_result` | `body` 的返回值 | + +同步的函数体保持同步:`agent("x", () => 1)` 返回 `1` 而非 Promise。 + +`toolCall` 会将函数体的解析值记录为工具的 `output`,除非你自行给 `call.output` 赋值。 + + + +| 发生情况 | 事件 | `outcome` | +| --- | --- | --- | +| 代码块正常返回 | `agent_end` | `"success"` 或你自定义的 `outcome` | +| 代码块抛出异常 | `error`,然后 `agent_end` | `"failed"` | +| 抛出 `AbortError` | 仅 `agent_end` | `"cancelled"` | + +异常始终会被重新抛出。 + +工具失败记录在叶子节点上——`tool_result` 携带 `error` 字符串——**不会**发出运行级别的 `error` 事件。被 agent 循环捕获的错误不算运行失败;向上传播的错误只会被外层的 `agent()` 记录一次。 + + + + + +当工作内容不是单一函数时——例如在构造函数中开启作用域、在析构时关闭,或者需要跨越现有控制流——可以使用此形式: + +```ts +{ + using span = failproofai.agent.open("planner", { goal }); + using call = failproofai.toolCall.open("search", { input: { q } }); + call.call.output = await search(q); +} // tool_result,然后 agent_end +``` + +两种形式发出的事件在字节层面完全相同。推荐使用回调形式:它在 `AsyncLocalStorage.run()` 内部运行,无需手动回退,也就从根本上杜绝了「在此处打开、在彼处关闭」这类 bug。 + +`using` 块若需报告自身的失败,请调用 `span.fail(error)`——disposer 本身没有异常传递通道。 + + + +## 事件目录 + +与 Python SDK 相同的十五个方法,使用驼峰命名。大多数方法成**对**出现——调用开始方法,再调用结束方法,SDK 会计算两者之间的时间差。 + +| | 开始 | 结束 | +| --- | --- | --- | +| **Agent** | `agentStart` | `agentEnd` | +| | `agentPause` | `agentResume` | +| **模型** | `modelRequest` | `modelResponse` | +| **工具** | `toolUse` | `toolResult` | +| **Hook** | `hookTriggered` | `hookCompleted` | +| **人工** | `humanWait` | `humanInput` | + +三个独立方法:`error`、`humanPause`、`humanInterrupt`。 + + + +每个方法还接受 `sessionId` 和 `agentId`,由作用域自动填充。省略的字段将被丢弃,不会作为 JSON `null` 发送。 + +| 方法 | 必填 | 可选 | +| --- | --- | --- | +| `agentStart` | — | `goal`、`parentId` | +| `agentEnd` | — | `outcome`、`summary` | +| `agentPause` | `pauseId` | `reason`、`userId` | +| `agentResume` | `pauseId` | `reason`、`userId` | +| `modelRequest` | — | `model`、`messages`、`system`、`tools`、`requestId` | +| `modelResponse` | — | `model`、`stopReason`、`inputTokens`、`outputTokens`、`content`、`role`、`requestId` | +| `toolUse` | `toolName`、`toolCallId` | `input` | +| `toolResult` | `toolName`、`toolCallId` | `output`、`error` | +| `hookTriggered` | `hookName`、`hookId` | `triggerEvent`、`input` | +| `hookCompleted` | `hookName`、`hookId` | `outcome`、`output`、`error` | +| `error` | `errorType`、`message` | `traceback` | +| `humanWait` | `inputId` | `prompt`、`options`、`reason` | +| `humanInput` | `inputId` | `response` | +| `humanPause` | — | `reason`、`userId` | +| `humanInterrupt` | — | `reason`、`userId`、`atStep` | + +你添加的任何其他键都会成为自定义载荷字段。框架专属字段请以 `fw_*` 命名;与已声明字段名冲突的键会被拒绝,而不是静默覆盖已提升的列。 + + + + + **`duration_ms` 由系统计算,不接受外部传入。** 四个结束方法会自动计算与开始方法之间的时间差,并拒绝调用方传入的 `duration_ms`——上报的持续时间必须不可伪造。 + + 配对匹配基于**会话**和 id,而非 agent。在 `planner` 下开启、在 `worker` 下关闭的工具调用依然能够配对,这正是嵌套多 agent 运行的实际工作方式。 + + +## 框架适配器 + +```ts +await failproofai.instrument(); // 自动检测并接入所有可用框架 +await failproofai.instrument("langchain"); // 仅接入指定框架 +failproofai.uninstrument(); // 还原所有修改 +``` + +| 框架 | 支持版本 | 接入方式 | +| --- | --- | --- | +| **LangChain.js / LangGraph.js** | `@langchain/core` 0.3 – 1.x,LangGraph.js 0.4 – 1.x | 通过 `CallbackManager.configure` 注入,所有 `invoke`/`stream`/`batch` 调用均自动覆盖,无需在任何地方传入 `callbacks:`——也可自行传入 `langchainHandler()` 而不修改全局。 | +| **Vercel AI SDK** | `ai` 4 – 7 | 在调用处使用 `telemetry()`,或在 `ai` 7 上调用 `instrument("ai")` 以全局接入(在 4–6 上为可选——详见下文)。 | +| **Mastra** | `@mastra/core` 0.20 – 1.x | 覆盖 `Agent.generate`/`.stream`、agent 的模型和工具解析,以及工作流运行/步骤引擎。 | +| **LlamaIndex.TS** | `llamaindex` 0.11.4 – 0.x | 订阅 `Settings.callbackManager` 并拦截 `AgentWorkflow.runStream`,覆盖工作流运行及其步骤。 | + +所有版本范围均针对真实框架发布版进行测试,覆盖两端边界,以 ES 模块和 CommonJS 两种形式,在每次 CI 运行中验证。 + +映射关系与 Python SDK 保持一致,因此相同的程序在两种语言中生成相同的调用树。只有拥有 LLM 决策循环的构件才被视为 **agent**——包括 graph 或 chain 运行、AI SDK 的 `generateText`/`streamText` 调用、Mastra agent、LlamaIndex agent 运行。LangGraph 节点或工作流步骤属于 **hook**(`hook_triggered`/`hook_completed`),不会被视为嵌套 agent。模型调用以 `model_request`/`model_response` 对记录,包含 token 计数;工具调用携带模型自身的 tool call id。失败事件只记录一次,记录在发生失败的那个事件上。 + +适配器安装失败时会记录日志并跳过,其他适配器仍正常安装——LlamaIndex 出问题不应影响 LangGraph 的接入。 + + + 不带参数的 `instrument()` 通过**模块是否可解析**来检测框架,而非判断是否已导入——Node 对于 ES 模块没有类似 Python `sys.modules` 的等价机制。已安装但未使用的框架会被导入并打补丁。如果这一点对你很重要,请明确指定目标框架。 + + + + 大多数框架同时提供 ES 模块和 CommonJS 两种构建,Node 会将它们作为两个独立副本加载。适配器会对你的应用实际加载的副本打补丁(如果有代码已经 `require` 过,也会对 CommonJS 副本打补丁),因此两种模块系统均可正常工作。通过 esbuild 或 webpack **打包进你自己输出文件**的框架则无法被触及——请在调用处使用辅助函数:`langchainHandler()`、`telemetry()`、`wrapTool()`。 + + +### 不打补丁使用 LangChain + +```ts +import { langchainHandler } from "@failproofai/sdk/langchain"; +await graph.invoke(input, { callbacks: [langchainHandler()] }); +``` + +此 handler 无论是否调用过 `instrument()` 都能正常工作,且不会重复记录。`instrument("langchain")` 接受 `sessionId`、`captureContent`、`includeChains`、`graphCallbacks` 和 `captureLimit` 参数,与 Python 适配器保持一致;调用时通过 `metadata: { failproofai_sdk_session_id }` 可为该次调用指定会话。 + +### Vercel AI SDK + +AI SDK 从 ES 模块中导出普通函数,而 ES 模块的命名空间在规范层面是不可变的——没有可以打补丁的地方。因此,接入方式使用 SDK 自身文档中记录的扩展点: + +```ts +import { telemetry } from "@failproofai/sdk/ai"; + +const { text } = await generateText({ + model, + prompt, + experimental_telemetry: telemetry({ functionId: "answer-question" }), + // 在 ai 7 上,使用 `telemetry: telemetry({ … })` ——相同的对象,新的参数名 +}); +``` + +这就是完整的接入方式:一个 agent span、每个步骤一对带 token 计数的模型请求/响应,以及所有工具调用。单一调用处的代码在所有主版本上均可工作——`ai` 4–6 读取其携带的 tracer,`ai` 7 读取 telemetry 集成配置。 + +`instrument("ai")` 在 **`ai` 7 上**通过 AI SDK 的全局 telemetry 集成列表实现进程级覆盖:覆盖所有调用,该列表为追加式,不影响任何其他方的配置。 + +**在 `ai` 4–6 上,`instrument("ai")` 本身不记录任何内容,并会打印一条警告说明此情况。** 这些主版本唯一的进程级 hook 是全局 OpenTelemetry tracer provider——这是一个 OpenTelemetry 一旦被占用就不会让出的单一插槽。注册我们自己的 provider 会静默拒绝你之后在启动时执行的 `NodeSDK.start()`,并将你的 HTTP/数据库 span 发送到一个不导出任何内容的 tracer。请在调用处使用 `telemetry()`,或在那里使用 `wrapModel`。如果进程本身不运行任何 OpenTelemetry,可通过 `instrument("ai", { registerGlobalTracer: true })` 选择接入:此时会记录所有传入 `experimental_telemetry: { isEnabled: true }` 的调用,且只在插槽仍为空时才占用它。`registerGlobalTracer: false` 保持默认行为并静默警告。 + +如果你倾向于只包装一次模型,`wrapModel` 仅能看到模型调用,因为工具调用发生在模型层之上。一个没有外层包裹的被包装模型调用会被记录为独立的运行。流式调用的结束取决于流的终止方式——消费者取消时 `stop_reason: "cancelled"`,中途失败时为 `"error"` 并附带错误信息: + +```ts +import { wrapModel } from "@failproofai/sdk/ai"; +const model = await wrapModel(openai("gpt-4o")); +``` + +同时使用两种方式也没有问题:中间件会检测到调用已在被记录,并自动让步,确保每次调用只被记录一次。 + +`functionId` 用于命名 agent span。请保持低基数——它会落在 `agent_id` 上,是仪表盘的主要分组维度。 + +### Next.js + +`next build` 默认会将服务端依赖打包,被打包进构建产物的框架无法被 `instrument()` 触及。请包装一次配置,并从 Next 的启动 hook 调用 `instrument()`: + +```ts +// next.config.ts +import { withFailproofai } from "@failproofai/sdk/next"; +export default withFailproofai({ /* 你的配置 */ }); +``` + +```ts +// instrumentation.ts +export async function register() { + if (process.env.NEXT_RUNTIME !== "nodejs") return; + const failproofai = await import("@failproofai/sdk"); + await failproofai.instrument(); +} +``` + +`withFailproofai` 会将 LangChain、Mastra、LlamaIndex 以及 SDK 本身添加到 `serverExternalPackages`,同时保留你现有的列表。如果不使用它,`instrument()` 会对每个无法触及的框架打印一次警告,而非静默失败;如果你自行列出这些包,请设置 `FAILPROOFAI_NEXT_EXTERNALS=1`。Vercel AI SDK 和调用处的辅助函数无论哪种方式都可正常使用。Edge 路由会得到一个空操作的构建:导入 SDK 是安全的,不会记录任何内容。 + +### 流式调用的 token 计数 + +OpenAI 兼容 API 只有在客户端明确请求时才会在流式响应中上报用量。LangChain 和 Vercel AI SDK 会自动请求;对于 LlamaIndex,请向其 `OpenAI` LLM 传入 `additionalChatOptions: { stream_options: { include_usage: true } }`;对于 Mastra,请在构建模型时启用用量报告(例如 `createOpenAICompatible({ includeUsage: true })`)。否则流式模型调用将不包含 token 计数。 + +### 运行时 + +Node ≥ 20.9、Bun 和 Deno——每个框架以 ES 模块和 CommonJS 两种形式,在各运行时上对照 Node 的 trace 进行测试。SDK 与 `failproofaid` 守护进程配合运行,由后者负责上传写入的数据。 + +## 自定义 Agent——不使用框架 + +适用于你自己编写的 agent 循环,或没有适配器的框架。你使用与适配器底层相同的 API 发出事件,trace 的形态和质量与使用适配器完全一致。 + +你不需要了解 agent 的具体组织方式。任何手写 agent 都已具备以下三个位置,无论其函数名称是什么,这三处就是完整的接入点: + +| 位置 | 添加内容 | 发出事件 | +| --- | --- | --- | +| **单次运行**的开始和结束处 | `failproofai.agent("name", { goal }, async () => …)` | `agent_start` / `agent_end` | +| **调用模型的函数**处 | 调用前 `event.modelRequest`,调用后 `event.modelResponse`——包括失败情况下的两半 | 每次模型调用一对 | +| **执行工具的函数**处 | `failproofai.toolCall(name, { toolCallId, input }, () => run())` | `tool_use` / `tool_result` | + +```ts +async function callModel(messages) { + const requestId = randomUUID(); + const started = Date.now(); + failproofai.event.modelRequest({ model: MODEL, requestId, messages }); + try { + const reply = await client.chat.completions.create({ model: MODEL, messages, tools }); + failproofai.event.modelResponse({ + model: reply.model, requestId, stopReason: reply.choices[0].finish_reason, + inputTokens: reply.usage?.prompt_tokens, outputTokens: reply.usage?.completion_tokens, + duration_ms: Date.now() - started, + }); + return reply.choices[0].message; + } catch (error) { + failproofai.event.modelResponse({ model: MODEL, requestId, stopReason: "error", + error: String(error), duration_ms: Date.now() - started }); + throw error; + } +} + +async function dispatch(call) { + const input = JSON.parse(call.function.arguments); + return failproofai.toolCall(call.function.name, { toolCallId: call.id, input }, + () => runTool(call.function.name, input)); +} + +await failproofai.agent("inventory", { goal: question }, async () => { + for (;;) { + const message = await callModel(messages); + if (!message.tool_calls?.length) return message.content; + for (const call of message.tool_calls) await dispatch(call); + } +}); +``` + +身份标识是环境感知的:`agent()` 内部的所有内容都会自动关联到当前运行的会话,无需传入 id,程序的其他部分也不受任何影响——包括 agent 已有的写入自身数据库的逻辑。 + +- **服务或 Worker:** 将你自己的请求或任务 id 作为 `sessionId` 传入,这样仪表盘上的会话与你自己的日志或数据库中的记录使用同一个字符串标识。 +- **子 Agent:** 嵌套调用 `agent()`。内层调用会以外层为 `parent_id` 加入同一会话。 +- **成对发出事件。** 没有对应 `modelResponse` 的 `modelRequest` 会在仪表盘上显示为永久运行中的 span——这也是 `catch` 存在的原因。 + +仓库中的 [`sdk/typescript/examples/research-agent.ts`](https://github.com/FailproofAI/failproofai/blob/main/sdk/typescript/examples/research-agent.ts) 是完整可运行的版本:一个真实的 OpenAI 工具循环,按此方式接入,以 ES 模块和 CommonJS 两种形式在每次变更时于 CI 中运行。 + +## 评估 + +```ts +import { Evaluator, EvalResult, Score } from "@failproofai/sdk/evaluator"; + +export const app = new Evaluator({ name: "my-evals", version: "1" }); + +app.eval("tool_success_rate", { version: "1" }, (session) => { + const results = session.eventsOfType("tool_result"); + const failures = results.filter((event) => event.payload.error != null).length; + return new EvalResult({ + score: new Score(results.length === 0 ? 1 : 1 - failures / results.length), + reasoning: `${failures} of ${results.length} tool calls failed`, + }); +}); +``` + +```bash +FAILPROOFAI_EVALUATOR_URL=… FAILPROOFAI_EVALUATOR_TOKEN=… \ + npx failproofai-evaluator ./my-evals.js +``` + +协议说明、Worker 配置及结果类型,请参阅 [Evaluator SDK 参考文档](/zh/reference/evaluator-sdk)。 + + + **评估函数必须是异步的。** 永不返回的同步函数会阻塞 Node 唯一的线程,任何超时机制都无法在此期间触发。请编写 `async` 评估函数。 + + +## 对你的进程的影响 + +| | | +| --- | --- | +| **不阻塞你的 Agent 循环** | 事件写入内存队列,由定时器负责写盘。定时器已 `unref`,因此导入本包不会阻止脚本正常退出。 | +| **不会无限增长** | 队列同时受数量*和*字节数的限制。超出任一上限后,最旧的事件将被丢弃并打印警告——遥测故障不能演变成 OOM 崩溃。 | +| **不会导致进程崩溃** | 单个无法编码的事件会被单独丢弃,不影响同批次的其他事件。抛出异常的 getter、循环引用、`BigInt`、孤立代理字符——每种情况都会被处理而非向上传播。 | +| **不会留下半写入的批次** | 内容在原子重命名前会执行 `fsync`,重命名后对目录再次 `fsync`,写入失败时会清理临时文件。 | +| **不会让日志可被他人读取** | 批次文件权限为 `0600`,存放在权限为 `0700` 的目录中。文件中包含目标、提示词、工具参数和工具输出。 | +| **不会上传凭据** | API 密钥、Token、JWT、Bearer 请求头及形似密钥的赋值语句,在字节写入磁盘前会被脱敏。守护进程在上传前还会再次脱敏。 | \ No newline at end of file diff --git a/docs/zh/reference/jev-cloud.mdx b/docs/zh/reference/jev-cloud.mdx new file mode 100644 index 000000000..2b04c0047 --- /dev/null +++ b/docs/zh/reference/jev-cloud.mdx @@ -0,0 +1,136 @@ +--- +title: "通过 FailproofAI Cloud 使用 Jev" +description: "Cloud 机器密钥、连接状态、限制及实时 Jev 策略审查的故障行为说明。" +icon: "cloud" +--- + +本文是 [Jev 策略](/zh/policies/jev) 的 Cloud 路由参考文档。Jev 是 TypeSafe 的分类器,它会对照您的实际请求内容逐一审查每个工具调用,并在您的策略之外提供判断结果,而非替代它们。通过 **FailproofAI Cloud**,已连接的机器使用原有的连接密钥即可使用 Jev,无需 TypeSafe 账号、无需第二个密钥,也无需配置任何端点。每次调用均从您组织现有的计划配额中扣除。 + +Jev 的所有行为与[自带密钥方案](/zh/reference/jev-providers)完全一致:硬策略的结果保持最终效力,可审查策略的拒绝仅在 Jev 被明确询问该问题时才会被清除,任何故障都会回退至该调用的正则表达式结果。 + + +需要 **failproofai 1.0.8-beta.0** 或更高版本。1.0.7 不含 Jev,尽管其排序在 1.0.7 beta 版之前。未配置 Jev 时不会有任何变化:hooks 将完全按照原有方式运行正则策略。 + + +## 开始之前 + +在运行 agent 的机器上安装 Failproof AI,并将其 hooks 附加到[受支持的运行环境](/zh/reference/harnesses)。如果您是从零开始,请按照[快速入门](/zh/start/quickstart)完成 hook 安装步骤。使用 `failproofai --version` 检查已安装的 CLI 版本;如果版本早于 Jev,请升级。您还需要访问组织的 **Administration → Keys** 页面以创建机器密钥。 + +Jev 在 `PreToolUse` 或 `PermissionRequest` 门控处审查具名工具调用,不会审查会话中的每个事件。要看到 Jev 清除策略拒绝,您需要安装一个标记为[可审查](/zh/policies/authority)的策略;其他所有策略拒绝均保持最终效力。 + +## 开启 Jev + +1. **创建带有 Jev 权限的密钥。** 在 FailproofAI Cloud 控制台中,进入 **Administration → Keys → Create key**,选择 **machine** 预设。该预设授予机器所需的三项权限:`events:add`(发送活动)、`policies:pull`(接收策略)和 `jev:evaluate`(Jev,从组织计划中扣费)。密钥缺少其他两项权限时无法携带 `jev:evaluate`。 +2. **使用该密钥连接机器。** 在提示符处读取一次性密钥,然后运行完整的配置命令: + + ```bash + read -rs FAILPROOFAI_CLOUD_TOKEN && export FAILPROOFAI_CLOUD_TOKEN + failproofai config + ``` + + `failproofai config` 会安装守护进程、为检测到的 agent CLI 附加 hooks,并连接机器。使用环境变量可防止密钥出现在命令参数和 shell 历史记录中。如果您的运行环境是后来安装的,请[显式附加它](/zh/start/quickstart)。 + + 如果您的组织使用自托管的 FailproofAI Cloud 而非托管版,请添加其地址:`--url https://`(或导出 `FAILPROOFAI_CLOUD_URL`)。若未指定,密钥将对托管服务进行验证,连接会失败。如果该主机的证书来自私有 CA,请将 CA 安装到机器的系统信任存储中(例如使用 `update-ca-certificates`),而不仅仅是 `NODE_EXTRA_CA_CERTS`:发送事件和拉取策略的守护进程读取的是系统存储。详见[故障排除](/zh/reference/troubleshooting)。 + +仅此而已。连接成功后会存储密钥,若机器**尚无** Jev 配置,则会通过 FailproofAI Cloud 以**观察**模式开启 Jev:一旦某个包为其提供检查项,Jev 就会对每个门控工具调用进行询问并记录其判断结果,但实际执行的仍是您策略的结果。输出内容如下所示: + +```text + Jev on through FailproofAI Cloud, in observe mode: logged, not enforced (~/.failproofai/jev.json). +``` + +在某个包提供检查项之前,Jev 不会有任何询问。Failproof AI 本身不附带任何包;在没有已安装包声明检查项的情况下,输出会额外显示一行说明,`failproofai jev status` 也会重复该信息。使用以下命令安装: + +```bash +failproofai policies add FailproofAI/jev-policies +``` + +**使用 `--no-transcripts` 连接时不会开启 Jev。** Jev 会将每个被检查的工具调用及最近的提示词发送到 FailproofAI Cloud,这比仅发送决策的连接传输的内容更多。密钥仍会被存储,输出会说明 Jev 可用以及如何开启: + +```bash +failproofai jev setup --provider failproofai +``` + +此操作也不会关闭 Jev。如果机器的 `jev.json` 已经通过 FailproofAI Cloud 运行 Jev,则保持原样,输出会说明 Jev 仍在发送每个被检查的工具调用和最近的提示词,以及 `failproofai jev setup --mode off` 可将其关闭。 + + +连接操作**绝不会覆盖**已有的 `~/.failproofai/jev.json`。如果您已使用自己的 Jev 端点,它将继续被使用,输出会说明该文件保持原样——并且当该文件将 Jev 设为关闭状态(被拒绝或已手动关闭)时,会说明原因及修复方式。要将该机器切换为 FailproofAI Cloud,请运行 `failproofai jev setup --provider failproofai`。 + + +## 观察模式、执行模式或关闭 + +先在观察模式下运行,在策略页面查看 Jev 的行为,然后再让其正式生效: + +```bash +failproofai jev setup --mode enforce # Jev 的判断生效:可清除可审查的拒绝,也可添加自己的拒绝 +failproofai jev setup --mode observe # Jev 被询问并记录;执行的仍是您策略的结果 +failproofai jev setup --mode off # 保留配置,停止询问 Jev +``` + +本地控制台也提供相同的切换方式:**Settings → Jev** 有开关和观察/执行模式选项。它只会重写模式,其他内容不变。Hooks 在每次工具调用时读取配置,因此更改从下一次调用起立即生效,无需重启。 + +## 检查运行状态 + +```bash +failproofai jev status +failproofai jev test +``` + +`status` 会显示提供方为 **FailproofAI Cloud**、机器连接的 Cloud 主机、当前模式,以及密钥来源为 **FailproofAI Cloud connection**,而非密钥本身。当 FailproofAI Cloud 的 `jev.json` 已就位但 Jev 无法运行时,会说明原因: + +| `status` 显示 | `status --json` | 含义 | +| --- | --- | --- | +| **off — no Jev key is stored for this machine's FailproofAI Cloud connection** | `key-lacks-jev` | 机器已连接,但未为其存储 Jev 密钥:密钥缺少 `jev:evaluate` 权限,或连接时无法确认。请在 `FAILPROOFAI_CLOUD_TOKEN` 中放入密钥后重新运行 `failproofai config`;若密钥缺少该权限,请使用 **machine** 类型的密钥。 | +| **off — this machine is not connected to FailproofAI Cloud** | `not-connected` | 此机器上没有 FailproofAI Cloud 连接,Jev 密钥无处归属。 | + +执行 `failproofai config --disconnect` 后,FailproofAI Cloud 的 `jev.json` 将不再存在(除非已切换为关闭状态,关闭状态会被保留),因此 `status` 仅报告 Jev 为关闭。`status --json` 包含相同的信息(`provider: "failproofai"`、`keySource: "cloud"`、`cloudConnected`、`keyCarriesJev`),即使配置缺失或被拒绝也是如此。`permissions` 始终来自 `jev.json`;关于 `credentials.json` 的拒绝会额外添加 `credentialsPermissions`,以及当一条命令可以修复时的 `fix` 字段。`test` 会发送一个实时请求并报告延迟及响应的 Jev 版本。当答复在 hook 超时后到达(hooks 会记录 `timeout`)或检查问题回答有误时,命令退出代码为 1,并在标题中说明。 + +控制台的 **Settings → Jev** 面板也会显示 **FailproofAI Cloud connection**:机器所属的组织及其密钥是否携带 Jev 权限。这些信息从机器本地文件读取,无需网络请求。 + +## 验证真实调用 + +在已接入 hook 的 agent 中启动一个新会话。让它使用文件读取工具读取 `README.md` 并报告标题。确认会话包含该工具调用后,再次运行 `failproofai jev status`:最近已评估调用的计数应有所增加。在[本地控制台](/zh/reference/local-dashboard#review-policy-activity)中打开 **Policies → Activity**,查看该调用的 Jev 判断结果和模式。在 Cloud 中,组织的 **Policies** 页面会显示已传递活动的 Jev 结果。在观察模式下,判断结果以**假设性**方式记录,策略结果仍决定最终调用。只有在可审查策略匹配且 Jev 清除了其具名检查项时,才会出现清除记录。 + +## 哪些内容会到达策略页面 + +机器已通过 `events:add` 将 hook 活动发送至 FailproofAI Cloud。开启 Jev 后,每个门控调用的记录还会包含:运行的评估器、Jev 的决策、清除的策略、回退原因(如有)、延迟以及响应的模型——仅包含决策、代码和名称,不含命令内容或您的提示词。在组织的 **Policies** 页面: + +- 由 Jev 自身判断决定的调用(执行模式)归因于 **Jev**,当决定性检查来自某个包时,记录还会标注该包及其版本; +- 在观察模式下,Jev 的拒绝或警告以**假设性**方式显示,与您正在观察的推出记录并列; +- Jev 已清除或在观察模式下将会清除的策略,按策略统计计数。 + +## 当 Jev 无法响应时 + +以下所有情况均会回退至该调用的策略结果,并记录相应原因: + +| 原因 | 说明 | +| --- | --- | +| `out-of-credits` | 您的组织已耗尽计划配额。 | +| `http-401`, `http-403` | 密钥已被吊销,或不携带 `jev:evaluate` 权限。请使用携带该权限的密钥重新连接。 | +| `http-429` | FailproofAI Cloud 正在对您的组织进行 Jev 限流。在其要求的等待时间(`Retry-After`,最长 60 秒)结束之前,机器不发送任何请求,所有调用立即回退。以此方式被阻止的调用记录为 `http-429`,若机器自身的速率限制先行触发则记录为 `rate-limited`。 | +| `http-429`(每日限制) | 您的组织已用完每日 Jev 调用次数:**每 UTC 日 10,000 次**,除非 FailproofAI Cloud 的运营方设置了其他限制。所有调用回退,直到计数在 UTC 00:00 重置;机器最多每分钟重新询问一次,因此会在一分钟内检测到重置。`failproofai jev test` 会显示"Daily Jev limit for this org reached; resets at 00:00 UTC."。 | +| `http-422` | Jev 拒绝了此调用的请求,通常是因为工具调用包含超过 Jev token 预算的密集文本(base64、十六进制、压缩代码)。该调用每次都会回退;这不是服务中断。 | +| `http-502` | Jev 当前不可用。 | +| `http-503` | 此 Cloud 无法为您的组织提供 Jev 服务:没有模型网关、组织尚未配置,或网关已宕机。请联系管理员;hooks 最多每分钟重新询问一次。 | +| `http-404` | 此 FailproofAI Cloud 尚不支持 Jev。 | +| `timeout` | 在 `timeoutMs`(默认 3000)内未收到响应。 | +| `model-mismatch` | 响应的 Jev 版本不是 1.13。 | + +## 密钥的存储位置及流向 + +- 密钥存储一次,位于 `~/.failproofai/credentials.json`(权限 `0600`,在仅限所有者访问的目录中),与其他 FailproofAI Cloud 凭据并列。`jev.json` 不存储此路由的密钥;若在其中写入密钥将导致配置无效。 +- 如果 `credentials.json` 对除您以外的任何人(组或其他用户,读或写)拥有**任何**权限,或其目录可被除您以外的任何人**写入**,则该文件将被**拒绝**而非读取,Jev 将保持关闭,直到您修复:对文件执行 `chmod 600`,对目录执行 `chmod 700`(或重新连接,连接操作会以 `0600` 权限重写文件并将目录设为仅限所有者访问)。其他人可以读取目录是允许的;允许他人写入目录则会使他们能够替换文件。 +- 密钥仅在其来源连接存在于机器时有效:即同一 FailproofAI Cloud 的策略或报告凭据,使用**相同密钥**,位于同一文件中。没有对应连接的孤立 Jev 密钥将被忽略,Jev 保持关闭。这种情况发生在:旧版 failproofai 的 `config --disconnect` 将 Jev 密钥保留在原处(它不知道需要删除),或旧版 failproofai 的 `config --token` 使用另一个密钥连接(在 FailproofAI Cloud 上该密钥可能属于另一个组织)。要重新开启 Jev,请使用 **machine** 密钥重新连接。 +- 密钥只会被发送到验证它的 Cloud 来源。指向其他地方的 `jev.json` 将被拒绝。 +- **机器上的 agent 可以读取它。** `credentials.json` 仅限所有者访问,而 agent 以该所有者身份运行。读取 failproofai 自身文件的操作是被允许的(仅修改操作被 `block-failproofai-commands` 阻止),因此 agent 与该文件之间唯一的屏障是 `block-read-outside-cwd`——这是一个*可审查*策略——而从您主目录中启动的会话,则没有任何屏障。携带 `jev:evaluate` 权限的密钥会从任何使用它的地方消耗您组织的 Jev 配额(直到每日上限),因此请像对待其他消费凭据一样对待机器密钥:如果 agent 可能已读取该密钥,请在 Keys 页面将其禁用并使用新密钥重新连接。 +- 只有您的全局文件决定此路由的行为。仓库无法开启 Cloud Jev、将其指向其他位置或提供密钥,`FAILPROOFAI_JEV_API_KEY` 对此路由无效。 +- 对于 Jev 评估的每次调用,会向 FailproofAI Cloud 发送一个请求,其中包含[自带密钥页面](/zh/reference/jev-providers#what-leaves-the-machine)所列的内容(密钥已脱敏)。FailproofAI Cloud 将其转发给 TypeSafe,不记录也不保留。 + +## 关闭 Jev + +| 命令 | 结果 | +| --- | --- | +| `failproofai jev setup --mode off` | 保留配置;不再询问 Jev。**这是持久生效的开关:** 重新连接不会覆盖已有的 `jev.json`,因此 Jev 保持关闭,直到您使用 `--mode observe` 重新开启。 | +| `failproofai jev remove` | 删除 `~/.failproofai/jev.json`;Jev 关闭——直到下次使用携带 `jev:evaluate` 权限的密钥执行 `failproofai config --token`,该操作找不到 `jev.json` 会再次以观察模式开启 Jev(除非使用了 `--no-transcripts`)。要保持关闭,请使用 `--mode off`。 | +| `failproofai config --disconnect` | 断开机器连接:密钥被删除,当 `jev.json` 指向 FailproofAI Cloud 且未切换为关闭状态时,`jev.json` 也会被删除。指向您自己端点的 `jev.json` 以及已切换为关闭状态的 `jev.json` 将被保留,因此重新连接后 Jev 仍保持关闭。 | + +从下一次工具调用起,hooks 将完全按照原有方式运行正则策略。 \ No newline at end of file diff --git a/docs/zh/reference/jev-evaluations.mdx b/docs/zh/reference/jev-evaluations.mdx new file mode 100644 index 000000000..b7cac6076 --- /dev/null +++ b/docs/zh/reference/jev-evaluations.mdx @@ -0,0 +1,88 @@ +--- +title: "Jev 评估参考" +description: "Jev 会话评估的问题类型、校准分数、限制与回填说明。" +icon: "list-checks" +--- + +本页介绍 [Jev 评估](/zh/evaluations/jev) 背后的问题形式与评分规则。有些问题需要模型*阅读*对话,但不需要*撰写*关于对话的内容。"客户是否表达了紧迫感?"只有两种答案。"他们有多沮丧?"有几种有序的答案。你在提问之前就知道所有可能的答案。 + +**分类器评估**正是为此而生。你写下问题和它可能给出的答案,一个专为分类构建的小型模型会返回一个校准后的数值——永远不会是自由文本。 + + +与裁判评估一样,分类器评估每次会话都需要消耗一次模型调用。但与裁判不同的是,它是一个小型的专用模型,而非通用模型,因此速度更快、成本更低——但它永远不会解释自己的判断。如果你需要推理过程,请使用[裁判评估](/zh/evaluations/judge)。 + + +## 我应该选哪种? + +| 问题 | 使用方式 | +| --- | --- | +| 总共发生了多少次工具调用? | 代码 | +| 会话时长是否在 30 秒以内? | 代码 | +| 客户是否表达了紧迫感? | **分类器** | +| 应由哪个团队处理:账单、技术还是销售? | **分类器** | +| 客户有多沮丧? | **分类器** | +| 回答是否真正正确? | **裁判** | +| 它是否遵循了我们的升级策略,你为什么这么认为? | **裁判** | + +经验法则:**可计数 → 代码,能列举答案 → 分类器,需要解释 → 裁判。** + +你不必事先做出决定。描述你想要衡量的内容,助手会为你选择,告诉你它选了哪种以及原因,你也可以随时切换。 + +## 两种问题类型 + +### `noul` — 这是真的吗? + +两种答案,你分别描述两者。结果是"真"描述符合该情况的概率: + +```json +{ + "instructions": "Did the assistant promise a refund without first checking the refund policy?", + "criteria": { + "true": "A refund was promised or issued with no prior policy check or approval", + "false": "No refund was promised, or every refund followed a policy check" + } +} +``` + +两面都要描述。"没有表达紧迫感"是一个真实的答案,明确写出它会让另一面的描述更加清晰。 + +### `score` — 程度如何? + +有序的评分标准,**从最差开始**。结果是会话在评分标准上的位置,重新缩放至 0–1: + +```json +{ + "instructions": "How frustrated is the customer?", + "criteria": ["Calm", "Frustrated", "Very angry"] +} +``` + +**评分标准需要三到五个级别,且每个级别必须各不相同。** 这两个限制都有实际依据,而非风格偏好: + +- **两个级别**会退化成 `noul` 已经能更好处理的情形,而**超过五个级别**会让模型倾向于给出中间值而非明确判断。同一问题针对同一会话,两个级别得分为 0.00,三个级别得分为 0.01,十个级别得分为 0.55。 +- **重复级别**会在它们之间任意分配答案。一个明显愤怒的会话在 `["Calm", "Frustrated", "Very angry"]` 下得分 1.00,在 `["Angry", "Angry", "Angry"]` 下得分 0.66——一个格式正确但毫无意义的数字。 + +没有顺序的分类——"账单、技术还是销售"——不是评分标准。请对每个类别分别提 `noul` 问题,或使用裁判评估。 + +## 读懂结果 + +分类器产生的**分数**范围是 0 到 1,与裁判评估完全相同,因此在图表展示、过滤筛选和触发告警时的使用方式也一样。有两点值得注意: + +- **没有推理过程。** 该字段是故意留空的。这个模型不会解释自己的判断,而虚构一个解释是捏造,而非功能。 +- **不确定性会被标注。** `score` 类型的问题会报告自身的置信度,模型不确定的结果会被标记为 `low_confidence`——因此"哪些结果需要人工查看"是一个过滤操作,而非猜测。`noul` 类型的问题不报告置信度,因此不会被标记。 + +超长会话会以摘录方式读取后合并。当会话内容过长无法完整读取时,结果会说明省略了多少轮对话——你永远不会看到一个基于部分会话的判断被当作基于全部会话的判断呈现。 + +## 限制 + +- **三到五个评分级别,且各不相同。** 见上文;两个边界在创作时均会强制执行。 +- **每次评估只能有一个问题。** 问两件事就创建两个评估,这也正是你在图表中所需要的。 +- **编辑问题会发布新版本。** 新旧分数不可比较,因此它们会被分开保存,而不是混入同一条趋势线。 +- **分类器始终产生分数**,而非指标或断言。 +- **没有推理过程**,如上所述。如果一个数字会让人追问"为什么?",请改写为裁判评估。 + +## 测试与回填 + +与裁判评估不同,分类器评估**可以**在部署前进行测试——通过与代码评估相同的方式[测试它](/zh/evaluations/test),针对真实会话进行测试,并在上线前查看分数。 + +它也可以对你已有的会话进行[回填](/zh/evaluations/deploy#score-sessions-you-already-have)。由于每次会话都需要消耗一次模型调用,请有意识地设定时间窗口范围,而不是回放所有数据。 \ No newline at end of file diff --git a/docs/zh/reference/jev-intent.mdx b/docs/zh/reference/jev-intent.mdx new file mode 100644 index 000000000..1b3eda119 --- /dev/null +++ b/docs/zh/reference/jev-intent.mdx @@ -0,0 +1,112 @@ +--- +title: "Jev 意图捕获" +description: "哪些 harness 事件会告知 Jev 评估器人类的请求内容,哪个字段承载文本,哪些内容永远不会被计入,以及信任 harness 传递的提示所带来的风险。" +icon: "message-square-quote" +--- + +当你配置 [Jev 策略审查](/zh/policies/jev) 时,评估器会将每个受控工具调用与**人类的实际请求**进行比对,而非与 harness 呈现给 agent 的任意文本进行比对。诸如"是的,强制推送吧"这样的回复可以清除一项 **reviewable** 策略——这正是评估器存在的意义,因为无法读取请求内容的正则表达式会阻断三分之一的真实工作。 + +该文本只有一个来源:**harness 在提示提交事件时传递给 hook 的提示内容**。Failproof AI 会将其中人类输入的部分(去除 harness 包装、脱敏密钥、截断上限)记录到其状态目录下权限为 `0600` 的文件中。系统不会读取磁盘上的任何内容:会话记录是 agent 可以通过一条命令改写的文件,因此系统不会去询问某条提示是谁写的。 + +## 已接受风险的直白说明 + +一个已经能执行命令的 agent 可以让 harness 提交提示。`claude -p "…"`、`codex exec`、`copilot -p`、`cursor-agent -p`、`devin -p`、`droid -p`、`goose run -t` 和 `pi -p` 触发的提示提交事件与人工输入完全相同——payload 相同,且发生在该 agent 控制的子会话中。它还可以直接运行 Failproof AI 自身的 hook 二进制文件,并传入它自己构造的 payload。Failproof AI 内部无法区分两者与真实操作的区别——两者都是同一个程序从同一个 stdin 读取数据。 + +**因此,拥有 shell 权限的 agent 可以伪造自己的授权。** 这是一个经过深思熟虑的权衡,于 2026-09-23 确定,以下是两方面的完整说明: + +- **所换取的价值。** 另一种方案已被构建并测试:要求一个字段让 harness 声明某个人类为提示的作者,否则什么都不记录。但没有任何已发布的 harness 会发送这样的字段,因此该版本在**所有 harness 上均无任何记录**——Jev 在没有任何明确意图的情况下判断每次调用,永远无法清除任何策略。一个永远不会触发的捕获机制不是更安全的产品,而是根本不存在的产品。 +- **它做不到的事情。** 被记录的提示只能清除标记为 **reviewable** 的策略。**hard** 策略不会被 Jev 的任何判断所清除,因此伪造的提示永远无法将硬性拒绝变为允许——跳过 hook 对 agent 也毫无益处:harness 会独立地为工具调用调用 Failproof AI。 +- **它在极端情况下能做到的事情。** 最坏的情况是清除十五项可审查内置策略之一——而**其中十五项有十二项是阻断型的**。`protect-env-vars`、`block-env-files`、`block-read-outside-cwd`、`block-rm-rf`、`block-force-push`、`block-secrets-write` 以及六项基础设施 CLI 阻断(`block-kubectl`、`block-terraform`、`block-aws-cli`、`block-gcloud`、`block-az-cli`、`block-helm`)都是拒绝型策略,因此伪造的授权可以在以下情况下将真实拒绝转变为允许:打印环境密钥、读取 `.env` 文件、读取项目外部内容、`rm -rf`、强制推送、写入密钥文件或更改线上基础设施。只有 `warn-git-amend`、`warn-destructive-sql` 和 `warn-global-package-install` 是提示性策略。默认安装会开启十二项中的两项——`protect-env-vars` 和 `block-env-files`;其余十项只有在有人主动启用的机器上才会生效。任何提示都无法影响的是所有硬性策略——`block-sudo`、`block-curl-pipe-sh`、`block-push-master`、`block-work-on-main`、防止 agent 禁用 Failproof AI 的守卫,以及所有其他未标记为 reviewable 的内置策略。[策略权限](/zh/policies/authority)列出了全部十五项及其各自的审查方式。 + +以下内容仍然会被拒绝:所有便于检查且 agent 无法仅通过请求获得的内容——harness 自身 payload 标记为机器提交的轮次、命名子 agent 的 payload、非普通名称的会话 ID、非提示提交事件,以及仅包含 harness 包装文本的内容——包括 Failproof AI 自身的停止门控词,这些词会被多个 harness 作为下一个用户轮次反馈回来。 + +## 各 harness 对照表 + +"文本字段"是 Failproof AI 针对各 harness 规范化后的 stdin payload 字段。"已记录"表示该提示是否作为人类请求被保留。 + +| Harness | `--cli` | 提示事件 → 规范化 | 文本字段 | 已记录 | 读取 agent 最后一条消息的来源 | +| --- | --- | --- | --- | --- | --- | +| Claude Code | `claude` | `UserPromptSubmit` | `prompt` | 是,除非 payload 的 `source` 标明这是无人提交的轮次(`loop_wakeup`、`schedule_wakeup`、`poll_event`、`system`)。`user`、`sdk`、未知值以及未发送任何 `source` 的构建版本均会被记录 | 会话记录(`transcript_path`) | +| Codex | `codex` | `user_prompt_submit` → `UserPromptSubmit` | `prompt` | 是 | rollout JSONL(`agent_message`、`AgentMessage`) | +| GitHub Copilot CLI | `copilot` | `UserPromptSubmit` | `prompt` | 是 | `events.jsonl`(`assistant.message`) | +| Cursor | `cursor` | `beforeSubmitPrompt` → `UserPromptSubmit` | `prompt` | 是,当 `` 包装器是整个提示时会被剥除 | agent 记录 JSONL | +| OpenCode | `opencode` | `message.updated`(user 角色)→ `UserPromptSubmit` | `prompt` | 是——但当前 OpenCode 在该事件中不携带文本,因此实际上不会记录任何内容;相同消息的重复提交只记录一次 | 无(会话以 SQLite 存储) | +| Pi | `pi` | `input` → `UserPromptSubmit` | `prompt` | 是,除非 `input_source` 为 `extension`——另一个扩展的 `sendUserMessage()`,其文本可能由模型生成或来自代码库 | Pi 会话 JSONL | +| Hermes | `hermes` | 无 | — | 否——Hermes 完全没有提示提交事件 | — | +| OpenClaw | `openclaw` | `before_agent_run` → `UserPromptSubmit` | `prompt` | 是,除非运行元数据将其标记为机器运行:`trigger` 不为 `user`、`inputProvenance.kind` 不为 `external_user`,或 `senderIsOwner: false` | 无(`before_agent_run` 不携带记录路径) | +| Factory Droid | `factory` | `UserPromptSubmit` | `prompt` | 是 | droid 会话 JSONL | +| Devin CLI | `devin` | `UserPromptSubmit` | `prompt` | 是 | 无(会话以 SQLite 存储) | +| Antigravity CLI | `antigravity` | `PreInvocation` → `UserPromptSubmit` | 无 | 否——`PreInvocation` 在一个轮次中的*每次*模型调用前触发,且不携带提示文本 | — | +| Goose | `goose` | `UserPromptSubmit` | `message` | 是 | 无(会话以 SQLite 存储) | + +两个 harness 不记录任何内容,且原因相同:其事件不传递人类文本。Hermes 没有提示提交事件——其原生插件自行处理 `pre_llm_call` 并仅转发工具、会话和子 agent 事件。Antigravity 的 `PreInvocation` 在每次模型调用前触发,无论是人类轮次还是随后的五次调用,均不携带提示字段;hook 还可以向同一对话中注入 `userMessage` 步骤。两个事件中均无任何可记录的内容。 + +## 什么样的提示才算是人类的提示 + +1. **事件。** Failproof AI 是为该 harness 的提示提交事件被调用的,handler 会将其规范化为 `UserPromptSubmit`。 +2. **Payload。** Harness 将其写入 hook 的 stdin,并在上述字段中携带文本。没有 payload 的调用不记录任何内容。 +3. **Payload 中没有任何内容将该轮次排除在外。** 携带子 agent 标识(`agent_id`)的 payload 是 agent 自我提示的。标记了机器提交轮次的 `source`、`input_source` 或 OpenClaw 运行标记会被拒绝。**缺失**标记不会排除任何内容——这正是与那个记录任何内容版本的区别,因为此处所有标记在所有已发布版本中都是缺失的。 +4. **去除包装后仍有内容留存**(详见下文)。 + +**会话记录不能作为提示作者的证明。** 本页面的早期版本描述了一种记录交叉检验机制:如果记录显示模型调度了该提示,则提示被拒绝,且记录必须延续上一条提示所见的那份记录。该检验已被移除。记录是 agent 已经拥有 shell 权限的文件——它可以被截断、替换、填充超出读取预算、在轮次开始时快照并在结束时恢复,或者用 agent 自己写的条目重新使其看起来正常。每一轮加固之后都随即出现了相同伪造手法的新变体,因此整个机制被彻底移除,而非修补。 + +记录仍被读取的唯一用途是:**agent 最后可见的消息**。该消息在定义上是 agent 写的,Jev 也被如此告知,它本身永远不构成授权。 + +## 提示中保留哪些内容 + +Harness 在提示中放入的不只是人类的话语。在存储之前: + +- `` 块会被移除,其周围人类的话语会被保留。 +- 会话延续摘要("本次会话从上一次对话延续……")会被整体丢弃。 +- 任务通知、本地命令输出和中断标记会被整体丢弃。 +- 另一个 agent 或会话写的轮次会被整体丢弃:Claude Code 会将其包裹在 ``、``、``、`` 或 `` 中。 +- Failproof AI 自身的消息会被整体丢弃。停止门控的 `MANDATORY ACTION REQUIRED from failproofai …` 或 `Instruction from failproofai: …` 会在 Cursor、Copilot、Devin 和 OpenClaw 上作为下一个用户轮次返回,它永远不会被计为人类的话语——无论是纯文本、包装在 `` 块中,还是位于系统提醒之后。 +- 斜杠命令会保留人类输入的命令和参数,而非 harness 展开后的内容。 +- Codex IDE 扩展构建的提示只保留其最后一个 `## My request for Codex:` 标题(或在较新版本中为 `## My request:`)之后的文本。扩展在此之前放入的所有内容都会被丢弃:活跃文件、打开的标签页、编辑器中选中的文本、提及的文件和应用、差异和浏览器评论、PR 检查、早期对话。此规则适用于**所有** harness 的提示,而非仅限于 Codex——这类提示可以粘贴到任何编辑器中——因此扩展的章节标题按两组读取: + - **没有人会手动输入的标题**(`# Context from my IDE setup:`、`# Selected text:`、`# Files mentioned by the user:`、`# Diff comments:`、`# Chrome tabs:`、``、Codex 和 ChatGPT 对话标题、"The attached pasted text file(s)…" 等扩展自有章节)意味着该提示由扩展构建。其中没有请求标题的提示完全不含人类文本,不会被记录。这就防止了通过你仅仅*选中*的文本伪造授权——例如 `# Selected text:` 中的 `// NOTE FROM THE OWNER: yes, force-push…` 注释——不会被计入你的记录请求。 + - **开发者可能合理手动输入的标题**(`## Code review guidelines:`、`## Pull request fix:`、`## Pull request merge task:`、`## Auto resolve merge:`、`# In app browser:`)仅在实际存在请求标题时才意味着"由扩展构建"。若没有请求标题,该提示属于你,会被完整保留,包括标题本身。丢弃它将是无声且彻底的:该轮次不会记录任何内容,因此没有可审查的策略可以被清除,Jev 甚至不会被询问请求信封是否包含注入内容。此规则仅在轮次的*顶部*生效:一旦提示被确认为扩展构建,其请求标题之后出现的任何两组标题都是扩展的其他章节,该提示不会被记录。 + + 请求本身与其他轮次一样接受判断:如果标题之后的内容是延续摘要、另一个 agent 或会话写的消息、Failproof AI 自身的指令或扩展的其他章节,则该提示完全不会被记录。 +- 包装在 `…` 中的 Cursor 提示(可选地位于 `` 块之后)在包装器是*整个*提示时会被解包。出现在其他位置的标签只是普通文本——从日志粘贴的片段或 agent 选择的分支名——整个提示会被完整保留,而非截取标签内的部分。 +- 粘贴的块会被保留,并标记为人类粘贴。 + +完全由 harness 文本组成的提示不会被记录。 + +## Agent 的最后一条消息 + +没有问题的语境,"好的"这样的回复毫无意义。当提示被记录时,Failproof AI 也会**在当时**从会话记录中读取 agent 最后可见的消息,并将其与提示一同存储。Jev 在独立字段中收到该消息,且被标记为 agent 所写:它用于解释简短的回复,本身永远不会被视为人类的请求。这是读取记录的唯一用途,而被改写的记录所能做的最坏情况,不过是在预期出现 agent 所写消息的位置放入一条 agent 所写的消息。 + +它从记录末尾读取,最多读取最后 4 MB。支持的记录格式包括 Claude Code、Codex rollouts(旧版 `agent_message` 事件和新版 `AgentMessage` 条目)、Cursor、Copilot `events.jsonl` 以及 Pi、Factory 和 OpenClaw 的会话 JSONL。Claude Code 自身的合成消息、API 错误消息和子 agent(sidechain)消息会被跳过。Goose 和 OpenCode(以 SQLite 存储会话)、Devin(记录为单一 JSON 文档)以及 OpenClaw(其 `before_agent_run` 事件不携带记录路径)均没有快照。 + +## 存储 + +| 属性 | 值 | +| --- | --- | +| 位置 | `~/.failproofai/state/semantic/sessions/.json` | +| 权限 | 文件 `0600`,目录 `0700`。其上至 `~/.failproofai` 的每个目录都遵循与 `jev.json` 目录相同的规则:任何其他人可以**写入**的目录可以被重命名并替换,因此读取路径会在可能的情况下去除这些写入权限,并在无法去除时**不读取任何内容**。这样,被记录的提示会缺席而非被伪造,且不会有任何内容被清除 | +| 每会话保留数量 | 最后 5 条提示;与前一条相同的提示会替换它,而不是占用新的位置 | +| 时间窗口 | 超过 6 小时的提示会被忽略 | +| 大小 | 每条提示和 agent 消息上限为 6,000 个字符,保留头部和尾部 | +| 密钥 | 在写入前使用与 `sanitize-*` 策略相同的模式进行脱敏。超过 48,000 个字符的文本会被脱敏为前 28,800 和后 19,200 个字符,且截断处附近的文本(密钥可能被分割的位置)永远不会被存储 | + +包含字母、数字、`.`、`_` 和 `-` 以外字符,或长度超过 128 个字符的会话 ID,永远不会被用作文件名,因此不会为其记录任何内容。 + +会话文件只有在其中记录了提示后才会存在。它只保存提示,不包含任何其他内容——没有来源状态,没有记录标记——并在沉默超过六小时窗口后,在下一个新会话写入其第一条提示时被删除。 + +除非配置了 Jev 端点,否则不会记录任何内容。 + +### 项目根目录 + +"项目内部"——`read-outside-workspace` 和其他路径检查所依据的判断标准——是指会话**首次受审调用时**所在的项目内部。根目录在那时被固定,后续的 `cd` 不会改变它;`cd` 仍会改变相对路径的解析方式。如果允许跟随 `cd`,那么某次调用中的 `cd ~/.ssh` 就会使 `~/.ssh` 成为下一次调用的项目目录。 + +固定值保存在 `~/.failproofai/state/semantic/roots/.json` 中,内容为 `{root, at}`:文件 `0600`,目录 `0700`,且遵循与上文相同的会话 ID 规则。超过 7 天的文件会在新会话固定其根目录时被删除。其他用户可写入的 `roots` 目录会被忽略,改用当前目录的根目录。如需重新固定某个会话,请删除其文件。 + +## 已知限制 + +- **提示的可信度取决于 hook 调用的可信度。** 此处的所有内容都读取 harness 写入 hook stdin 的 payload。能够执行命令的 agent 可以无头运行 harness(`claude -p` 及上文列出的其他七个命令),或直接运行 Failproof AI 的 hook 二进制文件并传入自己构造的 payload,从而记录一条从未有人输入的提示。这是本页面顶部所描述的已接受权衡:它只能清除可审查的策略,而非硬性策略——但十五项可审查内置策略中有十二项是拒绝型的,因此伪造的提示可以在这十二项上将真实阻断变为允许。 +- **子 agent 检测是 Claude 形状的。** 携带 `agent_id` 的 payload 在任何 harness 上都不会被记录。这是 Claude Code、Factory Droid 和 Devin 会使用的字段。Codex 在子 agent 线程内触发其提示事件,Copilot 运行进程内助手,Goose 有 `delegate` 工具,OpenClaw 运行角色扮演——这些都不会以此机制可识别的方式标记 payload,因此这些 harness 上的子 agent 提示会被记录为会话自身的提示。OpenClaw 的 `openclaw.agentId` **不是**该标记:已发布的插件会在每次运行(包括所有者的运行)时设置它。 +- **不携带标记的调度器。** Claude Code 的 `schedule_wakeup` 和 `loop_wakeup`,以及 OpenClaw 的 `cron` 和 `heartbeat` 触发器,会被拒绝,因为这些 harness 在 payload 中明确说明了这一点。Goose 自身的调度器(`goose schedule add`)和 Codex 的 `codex exec` 不作任何说明,因此它们启动的运行会像其他运行一样被记录。 +- **Agent 的最后一条消息可能是 agent 自己选择的消息。** 记录未经身份验证,因此能够写入自己记录的 agent 可以决定其"最后一条消息"的内容。它被标记为 agent 所写,本身不会清除任何内容——但请注意,`decide.ts` 的 v1 路径允许它满足确定性的"用户是否命名了此目标"检查,因此控制自身记录的 agent 可以提供覆盖所需的目标名称。 +- **以扩展机器标题开头的提示会被整体丢弃。** 如果提示以 `# Selected text:`、`# Diff comments:`、`# Chrome tabs:` 或上文第一组中的其他章节标题开头,且从未写入 `## My request:` 标题,则该轮次不会记录任何内容——因此也不会为其清除任何内容。这是有意为之的:这些章节携带了他人控制的文本(你选中的代码、审阅者的差异评论、页面标题),将其记录为你的话语是更糟糕的失误。开发者可能合理输入的标题属于第二组,单独出现时永远不会丢弃提示。 +- **OpenCode 实际上不记录任何内容。** 其 `message.updated` 事件在当前 OpenCode 中不携带文本,且它还会针对其任务工具创建的子会话触发,而这些子会话的"用户"消息是由父 agent 写的。 +- **`CODEX_HOME` 不被** `lib/codex-sessions.ts` 中的 rollout 发现逻辑所支持。这只影响 agent 消息快照的查找位置,而不影响提示是否被记录。 \ No newline at end of file diff --git a/docs/zh/reference/jev-providers.mdx b/docs/zh/reference/jev-providers.mdx new file mode 100644 index 000000000..9ba0b2628 --- /dev/null +++ b/docs/zh/reference/jev-providers.mdx @@ -0,0 +1,275 @@ +--- +title: "Jev 提供商与自带密钥配置" +description: "使用自有密钥进行 Jev 策略实时审查时的提供商端点、模型 ID、配置方法及故障处理行为。" +icon: "key-round" +--- + +本文是使用自有密钥配置 [Jev 策略](/zh/policies/jev) 的提供商与配置参考文档。正则策略只能匹配字符串,无法区分你主动要求的 `rm -rf build/` 和不小心混入计划中的 `rm -rf ~`,因此在某些地方拦截过多,在另一些地方又拦截不足。**Jev** 是 TypeSafe 的分类器,它能结合你实际的请求内容来审查工具调用,并在一次快速请求中回答一系列是/否问题。 + +配置好你自己的 Jev 端点和密钥后,Failproof AI 会在每次工具调用时**同时**向 Jev 查询和执行正则策略,而非二选一: + +- **硬性**策略的拒绝是最终决定,Jev 无法撤销。除非策略被明确标记为可审查并指定了对应的 Jev 检查项,否则默认均为硬性策略。因此,未作任何说明的自定义策略、插件策略或云端策略均为硬性策略,始终开启的自我保护守卫也始终是硬性策略。 +- **可审查**策略的拒绝可以被撤销,但前提是:Jev 被明确询问了该策略所关注的具体问题,且回答为「未发现问题」或「用户已请求此操作」。如果检查发现该问题确实存在,且用户并未请求该调用,则拒绝保持不变——即便该检查项本身只是警告级别,因为在工具调用发生之前,警告不会阻止智能体执行。如果该检查项属于可以直接拒绝的类型(如密钥泄露、凭证窃取、破坏性删除等),则该调用的任何清除请求均无效。 +- 当某次调用是你所下达任务的执行步骤且影响范围未超出当前范围时,拦截仍可降级为**警告**:Jev 会将自身的拒绝软化为警告,该警告会明确说明调用的具体问题,并替换策略的拦截提示。 +- Jev 也可以独立发出警告或拒绝,针对正则无法描述的有害行为。 +- 如果 Jev 无法给出答案(超时、限速、服务器错误、额度不足、意外的模型版本),该调用将使用正则策略的结果,与未配置 Jev 时完全一致。 +- 除非 Jev 读取了完整的调用内容并被明确询问了相关关切,否则 Jev 绝不会让调用变得比单独执行策略时更宽松。任何不满足此条件的情况——调用内容过大无法完整发送、疑似注入攻击——都将撤销清除授权并保持所有拒绝。 + + +未配置 Jev 时一切不变:钩子会完全按照既有方式执行正则策略。配置本身就是完整的启用开关。 + + + +使用 FailproofAI Cloud?你无需自备密钥:通过携带 `jev:evaluate` 权限的密钥连接的机器可以使用你组织方案中的 Jev。详见 [通过 FailproofAI Cloud 使用 Jev](/zh/reference/jev-cloud)。 + + +## 开始之前 + +在运行智能体的机器上安装 **failproofai 1.0.8-beta.0 或更高版本**,并将其钩子挂载到[支持的运行环境](/zh/reference/harnesses)。如果是新机器,请参考[快速入门](/zh/start/quickstart);如果不使用 Cloud,请参考[配置本地执行](/zh/start/setup#enforce-locally)。使用 `failproofai --version` 检查已安装的 CLI 版本。 + +从以下任一提供商获取 API 密钥,或准备好兼容的端点及其密钥。Jev 在 `PreToolUse` 或 `PermissionRequest` 阶段审查具名工具调用。它可以独立给出裁定,但撤销现有策略拒绝还需要安装标记为[可审查](/zh/policies/authority)的策略。硬性策略的拒绝始终是最终决定。 + +## 选择提供商 + +Jev 可通过五条路径访问,为其中任意一条准备密钥即可。 + +| 提供商 | `--provider` | 端点 | 默认模型 | 备注 | +| --- | --- | --- | --- | --- | +| TypeSafe | `typesafe` | `api.typesafe.ai/v1/systemone` | `jev-1.13.0` | 精确版本锁定。 | +| OpenRouter | `openrouter` | `openrouter.ai/api/v1/systemone` | `typesafe/jev-1.13` | 请求仅路由至零数据留存端点,不回退至其他提供商。报告的版本格式如 `typesafe/jev-1.13-20260917`。 | +| Vercel AI Gateway | `vercel` | `ai-gateway.vercel.sh/typesafe/v1/systemone` | `typesafe-ai/jev` | 仅通过别名标识 Jev,因此响应版本记录为未验证。 | +| Cloudflare Workers AI | `cloudflare` | `api.cloudflare.com/client/v4/accounts//ai/run` | `typesafe/jev` | 需要 `--account-id`。测量到每个密钥每秒约六次调用后出现 HTTP 429。 | +| 自定义端点 | `custom` | `/systemone` | `jev-1.13.0` | 任何接受 TypeSafe 请求体并报告响应模型的端点。仅支持 `https`;仅在观察模式下接受纯 `http://localhost`。 | + + +使用 Vercel 自带密钥功能时,失败的请求会静默地使用 Vercel 的凭证重试。如果你需要所有调用仅通过你自己的 TypeSafe 账户计费和查看,请直接使用 TypeSafe。 + + +## 配置方法 + +一条命令,配置端点和密钥。先以 `observe` 模式启动,这样你可以在现有策略继续处理调用时查看 Jev 的裁定: + +```bash +failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key +``` + +### 通过 URL 选择提供商 + +无需手动指定提供商:URL 的**主机名**即代表对应提供商。 + +| URL 主机名 | 提供商 | 额外参数 | +| --- | --- | --- | +| `api.typesafe.ai` | `typesafe` | — | +| `openrouter.ai` | `openrouter` | — | +| `ai-gateway.vercel.sh` | `vercel` | — | +| `api.cloudflare.com` | `cloudflare` | `--account-id <32位十六进制账户 ID>` | +| 其他主机名 | `custom` | — 你提供的 URL 即为基础 URL | + +由此引出三点说明: + +- **指向提供商官方 API 的 URL 不会写入覆盖配置。** `--url https://api.typesafe.ai/v1` 的效果与 `--provider typesafe` 完全相同。如果在已知提供商上使用不同路径或主机名,则会作为基础 URL 存储,效果与 `--base-url` 相同。 +- **`--provider` 仍可覆盖自动推断**,这样你就可以通过自有主机上的代理访问某个提供商的 API:`--url https://jev-proxy.internal/v1 --provider typesafe`。 +- **`--provider` 与主机名冲突时会被拒绝**,而非猜测。`--provider openrouter --url https://api.typesafe.ai/v1` 不会写入任何内容,并会说明原因:两者对密钥发送目标的描述不一致。同样的冲突在 `jev setup --base-url` 和控制台的 Jev 设置中同样会被拒绝。(`--provider custom` 不属于冲突——它的含义是「将此 URL 视为自身」——但在 Cloudflare 主机上除外,其按账户区分的端点无法通过自定义路由访问。) + +`--url` 的验证规则与配置文件中的 `baseUrl` 完全相同,拒绝理由也相同:必须使用 `https`,仅在观察模式下接受纯 `http://localhost`。 + +### 密钥 + +通过 `--key-stdin` 管道传入,或在终端中不带此参数运行命令,然后在掩码提示符处粘贴密钥。两种方式都会直接写入配置文件,不会回显。 + + + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key + ``` + + + ```bash + failproofai jev --url https://openrouter.ai/api/v1 --mode observe --key-stdin < ~/openrouter.key + ``` + + + ```bash + failproofai jev --url https://ai-gateway.vercel.sh/typesafe/v1 --mode observe \ + --key-stdin < ~/vercel-gateway.key + ``` + + + ```bash + failproofai jev --url https://api.cloudflare.com/client/v4 \ + --account-id <32位十六进制账户 ID> --mode observe --key-stdin < ~/cloudflare.token + ``` + + + ```bash + failproofai jev --url https://jev.internal.example.com/v1 --mode observe --key-stdin < ~/jev.key + ``` + + + +`failproofai jev setup` 接受相同的参数,是完整的长格式命令:如果你更倾向于指定提供商而非 URL,可以使用 `setup --provider `。 + +### `--token` 及其代价 + +`--token ` 将密钥放在命令行上,这是配置机器最快的方式,也是唯一会将密钥留在配置文件以外地方的用法: + +```bash +failproofai jev --url https://openrouter.ai/api/v1 --token +``` + + +命令行参数会留在 shell 的历史记录中,且命令运行期间会出现在进程列表里——以你的身份运行的任何程序都可以从 `/proc` 读取到。每次使用 `--token` 时,`setup` 都会给出提示。在共用机器上、在有录制的会话中,或在历史记录会被同步的环境中,请优先使用 `--key-stdin`;如果密钥安全性有要求,请及时轮换通过此方式传入的密钥。 + + +`--token`、`--key-stdin` 和 `--key-from-env` 互斥,只能选其一。 + +然后发送一个小型实时请求,检查密钥、端点以及响应的 Jev 版本: + +```bash +failproofai jev test +``` + +```text + failproofai jev test ok · 523 ms + + provider cloudflare + model asked typesafe/jev + answered by jev-1.13.0 (Jev 1.13 family — verified) + latency 523 ms — within the 3000 ms timeout +``` + +当响应在超时后才到达(每个钩子都会以 `timeout` 为由回退到正则)或检查问题回答错误时,`jev test` 退出码为 1,并在标题中说明。 + +钩子在每次工具调用时都会读取配置,因此从下一次调用起即生效。无论是否使用守护进程,都无需重启。 + +## 查看运行状态 + +```bash +failproofai jev status +failproofai jev status --json +``` + +`status` 显示提供商、端点、模型、模式、配置文件及其权限,但不显示密钥。下方汇总近期活动:Jev 评估的调用次数、回退到正则的频率及原因、延迟情况,以及清除的可审查策略列表。 + +## 验证真实调用 + +在已挂载钩子的智能体中开始新会话。让它使用文件读取工具读取 `README.md` 并报告标题。确认会话中包含该工具调用后,再次运行 `failproofai jev status`:近期评估调用数应有所增加。在[本地控制台](/zh/reference/local-dashboard#review-policy-activity)的**策略 → 活动**中查看该调用的 Jev 裁定和模式。在观察模式下,策略结果仍决定调用的最终处理。只有当可审查策略匹配且 Jev 清除了所有指定检查项时,才会出现清除记录;普通的读取操作可能没有需要清除的策略。 + +## 观察模式 + +`enforce` 是默认模式。若想在不影响任何决策的情况下观察 Jev,可切换到 `observe` 模式:Jev 仍会被询问且结果会被记录,但最终执行的是正则策略的结果。 + +```bash +failproofai jev setup --mode observe +failproofai jev setup --mode enforce +failproofai jev setup --mode off +``` + +`off` 保留配置——端点和密钥——并停止询问 Jev:钩子完全按照无配置时的方式执行正则策略,`failproofai jev status` 显示「off (switched off)」。使用 `--mode observe` 或 `--mode enforce` 可重新启用。 + +对同一提供商重新运行 `setup` 时会保留已存储的密钥,因此切换模式只需一个参数。切换提供商则需重新开始并提供新提供商的密钥。将请求迁移到不同主机的 `--base-url` 也是如此:已存储的密钥只会发送到最初提供该密钥时指定的主机或该提供商的官方 API。 + +## 配置文件 + +所有内容存储在一个文件中:`~/.failproofai/jev.json`,由 `setup` 写入: + +```json +{ + "provider": "cloudflare", + "apiKey": "", + "accountId": "<32-hex-account-id>", + "mode": "enforce", + "timeoutMs": 3000 +} +``` + +| 字段 | 含义 | +| --- | --- | +| `provider` | `typesafe`、`openrouter`、`vercel`、`cloudflare` 或 `custom`——或 `failproofai`,其密钥来自 FailproofAI Cloud 连接而非本文件(详见[通过 FailproofAI Cloud 使用 Jev](/zh/reference/jev-cloud))。 | +| `apiKey` | 以 `Authorization: Bearer ` 形式发送。 | +| `baseUrl` | `custom` 必填;对其他提供商则替换其 API 基础地址。必须使用 `https`。仅在 `mode: observe` 时接受 `localhost` 的纯 `http`:本地端口无任何认证机制,若代理下线,机器上的任何进程(包括被评判的智能体)都可能冒充响应。 | +| `accountId` | 仅 Cloudflare 需要:32 位小写十六进制字符。 | +| `model` | 替换提供商的默认模型 ID。带版本号的 ID 必须指向 Jev 1.13。形如 API 密钥的值会被拒绝(且不会回显),因此误将密钥粘贴到 `--model` 中不会被存储或作为模型名发送。 | +| `timeoutMs` | 工具调用等待 Jev 响应的最长时间,超时后使用正则结果。范围 100–10000,默认 3000。 | +| `mode` | `enforce`(默认)、`observe` 或 `off`(保留配置,不运行 Jev)。 | + +三条规则保护此文件: + +- **仅限所有者访问。** 文件权限为 `0600`。任何其他用户或组可读写的副本会被**拒绝**,钩子回退到正则策略,直到你运行 `chmod 600 ~/.failproofai/jev.json` 或重新运行 `setup`。目录也会被检查:`~/.failproofai` 不得对其他人**可写**,因为有写入权限者可以替换文件,无论文件本身的权限如何。`setup` 发现此类写入位时会将其清除。`failproofai jev status` 会提示配置已被拒绝,并显示文件中记录的端点:由于他人可能已修改该文件,请在执行 `chmod` 前确认文件内容属于你。对此类文件重新运行 `setup` 时,已存储的密钥仅会发送到该提供商的官方 API;文件中记录的其他任何端点都需要重新提供密钥(`--key-stdin`),或使用 `--base-url default` 将请求还原至提供商官方 API。 +- **仅限全局配置。** 仓库无法开启 Jev、将其指向其他端点或选择模型:项目内的 `.failproofai/jev.json` 会被忽略,提供商、URL、模型和账户 ID 仅从上述文件读取——永远不从环境变量读取,而仓库的智能体设置可以设置环境变量。(`FAILPROOFAI_HOME` 不是绕过此限制的方法:它会移动整个 failproofai 目录,包括你的策略,而不是单独重定向 Jev。) +- **仅密钥可来自环境变量。** 如果文件中没有 `apiKey`,`FAILPROOFAI_JEV_API_KEY` 会在该会话中提供密钥(`setup --key-from-env` 会写入此类文件)。它不会替换文件中已有的密钥,也无法在没有配置文件的情况下开启 Jev。变量未设置时,Jev 在该 shell 中简单处于关闭状态:`failproofai jev status` 会说明此情况,退出码为 0 且不修改配置(`status --json` 报告 `"status": "key-missing"`,`"reason": "no-env-key"`)。`failproofaid` 守护进程无法访问你的 shell 环境,因此在使用 `failproofai config` 配置的机器上,请将密钥保存在文件中。 + +## 哪个 Jev 版本响应 + +Failproof AI 的决策阈值是基于 Jev 1.13 校准的,因此只有来自该系列的响应才会被采用:`jev-1.13.x`,或 OpenRouter 的 `typesafe/jev-1.13-`。当提供商仅通过别名标识 Jev 且不报告版本时(Vercel,以及未说明版本的 Cloudflare),响应仍会被采用,但记录为未验证。`custom` 端点必须报告响应的模型;唯一的例外是你为其配置的无版本号 `--model` 名称,回显后同样记录为未验证。报告其他版本的响应,或 `custom` 端点未报告版本的响应,均不会被采用:该调用会以 `model-mismatch` 为由回退到正则。 + +## Jev 无法响应时 + +以下每种情况都会对该调用回退到正则策略结果,并记录相应原因,`failproofai jev status` 会统计各原因的出现次数: + +| 原因 | 说明 | +| --- | --- | +| `timeout` | 在 `timeoutMs` 内未收到响应。 | +| `http-429` | 提供商对该密钥进行了限速。 | +| `rate-limited` | Failproof AI 自身的限速器在发送前拦截了请求:每秒 5 个请求,最大突发 5 个,提供商返回 `429` 后暂停片刻。不是提供商限制。 | +| `http-500`、`http-502`、`http-503`……| 提供商端服务器错误,具体状态码会被记录。 | +| `out-of-credits` | HTTP 402:提供商账户额度不足。 | +| `provider-refused` | Cloudflare 返回的 HTTP 402,内容为「Model execution failed (Payment error)」:提供商拒绝在此请求上运行模型。通常与账单无关,充值也无法解决。 | +| `http-401`、`http-403` | 密钥被拒绝。 | +| `http-404` | `/systemone` 处未提供服务,说明基础 URL 有误——`/systemone` 会追加到基础 URL 后,所有提供商都在其版本根路径下提供此接口。`failproofai jev models` 可查看该端点实际提供的接口。 | +| `network` | 无法连接到端点。 | +| `http-301`、`http-302`、`http-307`、`http-308` | 端点返回了重定向。重定向永不跟随,响应只会来自配置中的 URL;请将 `--base-url` 设置为最终 URL。 | +| `malformed` | 端点有响应,但内容不是 Jev 答案——响应体不是 JSON,或不包含答案。 | +| `cloudflare-error`、`cloudflare-incomplete` | Cloudflare 的信封报告了失败,或任务尚未完成。 | +| `model-mismatch` | 响应的 Jev 版本不是 1.13,或 `custom` 端点未说明响应的模型。 | +| `request-cut` | **不是服务故障。** Jev 已响应,但只看到了部分调用内容,因此其答案不清除任何内容。详见[Jev 已响应但未审查完整调用时](#when-jev-answered-but-not-on-the-whole-call)。 | + +`failproofai jev status` 还可能显示一些更罕见的原因,例如 `upstream-error`(响应携带了提供商自身的错误)或 `config`,以及将无法命名的原因统计为 `other`。 + +`request-cut` 出现在此表中,是因为 `failproofai jev status` 会将它与其他原因一并统计,且它同样会保留所有拒绝。它是这里唯一一个与提供商状况无关的原因:请求已到达评估器且 Jev 已作答。与上方所有条目不同,该答案仍然有效——Jev 自身的拒绝或警告会叠加在正则结果之上,而非被丢弃。因此,此类情况频繁出现意味着调用内容过大无法完整发送,而非端点出现问题,充值或更换 URL 均无法降低此计数。 + +## Jev 已响应但未审查完整调用时 + +还有两种情况需要说明,它们都不是 Jev 未能响应的问题,而是关于调用本身或对话有多少内容适合放入一次请求。 + +**调用本身有部分内容未能纳入。** 工具调用在固定预算内发送,对于过大的调用——非常大的 `Write`、庞大的 MCP 请求体、被填充至上限的命令——会发送已适配的部分。Jev 仍会响应,其答案仍然有效:自身的拒绝或警告照常生效。但它无法**清除**任何内容,因为基于部分调用给出的裁定不是对完整调用的裁定。因此所有策略拒绝保持不变,该调用以 `request-cut` 为由记录为回退,`failproofai jev status` 会与上述原因一并统计。此规则给你的启示是:调用越大越可能失去清除资格,而且更大的调用永远无法换来清除授权。 + +**有消息未能纳入。** 你粘贴的长提示、智能体的最后一条消息,或该评估器的本地存储中已被截断的提示。**不产生任何变化**:调用的判定、清除和记录与其他调用完全相同,也不计入回退统计。你输入内容的长度永远不会决定裁定,截断也不会制造授权:若提示到达时已被截断,则「你未请求此操作」这一结论根本无从得出,而非变成一个结论。 + +两者的区别在于谁写了这段文字。调用是智能体的,允许其长度降低严重性就等于给了智能体可利用的规则;提示是你的,将其长度视为信号只会惩罚粘贴规格说明或堆栈跟踪的行为。 + +## 离开机器的数据 + +对于 Jev 评估的每次工具调用,会向你的提供商发送一次请求,携带以下内容: + +- 工具调用本身,其中 API 密钥、Bearer 令牌和 `KEY=` 赋值等敏感信息已被脱敏; +- 你最近输入的提示,已去除智能体运行环境添加的内容; +- 智能体在你最新提示之前的最后一条消息,标注为智能体生成; +- 本地计算的事实,例如路径是否在项目内——即会话首次被审查的调用时所在的项目,[在会话期间固定](/zh/reference/jev-intent#the-project-root)——以及当前 git 分支。 + +请求仅发送至你配置中指定的端点,使用你的密钥。 + +## 关闭 Jev + +```bash +failproofai jev remove +``` + +此命令删除 `~/.failproofai/jev.json`。从下一次工具调用起,钩子将完全按照之前的方式执行正则策略。`~/.failproofai/state/semantic/` 下的会话存储(`sessions/` 中的已记录提示,`roots/` 中的项目根目录)会保留并自然老化过期。若想停止询问 Jev 但保留配置,请使用 `failproofai jev setup --mode off`。 + +## 命令参考 + +| 命令 | 效果 | +| --- | --- | +| `failproofai jev --url --key-stdin` | 一条命令完成配置;提供商由 URL 主机名推断 | +| `failproofai jev --url --token ` | 同上,但密钥在命令行上——会留在历史记录和进程列表中 | +| `failproofai jev setup --provider --key-stdin` | 从 stdin 管道读取密钥并写入配置 | +| `failproofai jev setup --provider ` | 同上,在掩码提示符处输入密钥 | +| `failproofai jev setup --key-from-env` | 不存储密钥;每次会话从 `FAILPROOFAI_JEV_API_KEY` 读取 | +| `failproofai jev setup --mode observe` | 切换模式(`enforce`、`observe` 或 `off`),保留已存储密钥 | +| `failproofai jev setup --model ` / `--base-url ` | 覆盖模型或 API 基础地址;`default` 清除覆盖 | +| `failproofai jev setup --timeout-ms ` | 修改每次调用的等待预算 | +| `failproofai jev status [--json]` | 配置、权限及近期活动;不显示密钥 | +| `failproofai jev test [--json]` | 一次实时请求:延迟和响应版本 | +| `failproofai jev models [--provider ] [--url ] [--json]` | 该端点 `/models` 返回的模型 ID 列表,标注已配置的模型 | +| `failproofai jev remove` | 删除配置;Jev 关闭 | \ No newline at end of file diff --git a/docs/zh/reference/jev.mdx b/docs/zh/reference/jev.mdx new file mode 100644 index 000000000..f469917c7 --- /dev/null +++ b/docs/zh/reference/jev.mdx @@ -0,0 +1,22 @@ +--- +title: "Jev 集成参考" +description: "Jev 的配置、提供商、密钥、请求数据及失败行为。" +icon: "braces" +--- + +Jev 在 Failproof AI 中有两种用途: + +| 用途 | 运行时机 | 返回内容 | 入门指南 | +| --- | --- | --- | --- | +| 会话评估 | 会话结束后 | 固定答案问题的评分 | [Jev 评估](/zh/evaluations/jev) | +| 工具调用策略审查 | 受控工具调用执行前 | 与已安装策略一同返回的判决结果 | [Jev 策略](/zh/policies/jev) | + +## 参考页面 + +| 主题 | 详情 | +| --- | --- | +| [评估问题](/zh/reference/jev-evaluations) | 布尔值与有序评分标准、结果、限制及回填。 | +| [提供商对比与自定义密钥配置](/zh/reference/jev-providers) | TypeSafe、OpenRouter、Vercel、Cloudflare 及自定义端点;URL 推断、模型 ID、`jev.json`、模式及回退代码。 | +| [FailproofAI Cloud 路由](/zh/reference/jev-cloud) | 机器密钥权限、自动观测设置、使用限制、连接状态及数据处理。 | + +本地 CLI 命令详见 [Failproof AI CLI 参考](/zh/reference/failproof-cli)。[本地仪表板参考](/zh/reference/local-dashboard#set-up-jev)中介绍了其 Jev 设置与活动视图。 \ No newline at end of file diff --git a/docs/zh/sessions/sentiment.mdx b/docs/zh/sessions/sentiment.mdx new file mode 100644 index 000000000..0dda073a3 --- /dev/null +++ b/docs/zh/sessions/sentiment.mdx @@ -0,0 +1,43 @@ +--- +title: "情感分析" +description: "通过 Jev 情感评分发现沮丧、困惑和纠正类消息。" +icon: "smile" +--- + +Jev 对用户发送给你的 Agent 的每条消息,从 0 到 100 对四种情绪进行评分——**愤怒**、**沮丧**、**高兴**和**困惑**——以及三个关于 Agent 表现的信号: + +- **纠正**:用户指出 Agent 的回答有误。 +- **已解决**:用户确认 Agent 解决了他们的问题。 +- **存疑**:用户质疑 Agent 的回答是否准确,或是否真正完成了任务。 + +使用情感分析,可以找出用户正在失去耐心的对话、频繁被纠错的 Agent,以及效果良好的回复。这是内置的 Jev 评分功能,无需自行编写评估。如需针对固定答案的问题创建评估,请[创建 Jev 评估](/zh/evaluations/jev)。 + + + 情感分析默认关闭,需由管理员在组织级别开启。Jev 对每条消息发起一次评分请求,并在评分前接收该消息及 Agent 的上一条回复。评分使用组织的模型预算。 + + +## 开启情感分析 + +1. 前往**管理 → 设置**。 +2. 在**人工输入情感分析**下,将其切换为**开启**并保存。 + +系统优先对最近一天的消息进行评分。此后,新消息通常在到达后一两分钟内完成评分。 + +## 找到需要审查的对话 + +打开**观察 → 情感**。可按时间、环境、Agent 或会话 ID 进行筛选。页面顶部显示消息和会话数量、**标记**消息的数量,以及最主要的信号类型。当愤怒、沮丧、纠正、困惑或存疑的评分达到 100 分中的 35 分时,该消息将被标记。 + +![情感分析仪表盘,显示消息和会话数量、标记消息以及随时间变化的 Jev 评分。](/images/dashboard/sentiment-overview.png) + +使用**随时间变化的评分**来对比各信号。选择要显示的评分,然后点击某个数据点查看该时间段的消息。**按 Agent 分类**表格显示某个信号集中在哪里。在**消息**列表中,可按最强的负面评分排序,或选择单一评分进行筛选。在会话中打开某条消息,阅读上下文对话,再判断是哪里出了问题。 + +![按最强负面评分排序的情感消息列表,每条消息附有指向原始会话的链接。](/images/dashboard/sentiment-messages.png) + +## 哪些消息会被评分 + +仅对用户本人撰写的消息进行评分: + +- 通过 SDK 将自定义 Agent 记录为人工输入的消息。 +- 输入到 Claude Code、Codex、OpenCode、pi、Hermes 和 OpenClaw 中的提示词(当会话记录被发送时,这是默认行为)。由 Agent 运行时自动写入的计划任务、注入指令、子 Agent 交接等文本不计入评分。非交互式运行也不计入,例如 `claude -p`、`codex exec` 和 `hermes -z`:这些提示词由脚本生成,而非真人输入。 + +评分仅基于用户本人的措辞。简短直白的指令(如"修一下")不会被判定为愤怒,提出问题也不会被判定为困惑。新的请求不算纠正,单纯的感谢也不算已解决。 \ No newline at end of file diff --git a/docs/zh/start/use-jev.mdx b/docs/zh/start/use-jev.mdx new file mode 100644 index 000000000..263c5dea0 --- /dev/null +++ b/docs/zh/start/use-jev.mdx @@ -0,0 +1,63 @@ +--- +title: "使用 Jev" +description: "为已完成的会话设置 Jev 评估,或为实时工具调用审查设置 Jev policies。" +icon: "sparkles" +--- + +Jev 在 Agent 运行的两个节点发挥作用:对已完成的会话按已知答案进行评分,或在您交给 Agent 的任务背景下对工具调用进行审查。 + + + + 当一个已完成的会话可以对照几个已知答案进行评分时,请使用 Jev eval,例如"客户是否要求退款?请回答是或否。"它可以帮助您发现跨会话的规律。 + + ## 创建 eval + + 在 Cloud 控制台中,依次打开 **Analyze → eval authoring → new eval**。输入一个固定答案的问题,选择 **draft**,并确认它选择了分类器评分。在真实会话上[测试](/zh/evaluations/test)后再部署。 + + ![共享 eval 编辑表单,您可以在其中描述问题、审查草稿并进行部署。截图显示的是代码草稿;Jev 请使用固定答案问题。](/images/dashboard/eval-authoring-draft.png) + + ## 查看评分结果 + + 新会话完成后,打开 **Observe → Evaluations**,或使用 Cloud CLI: + + ```bash + fp evals --since 7d + fp evals --aggregate --since 7d + ``` + + CLI 用于读取评分;创建 Jev eval 目前需通过控制台操作。有关问题类型和示例,请参阅 [Jev evaluations](/zh/evaluations/jev)。 + + + 当基于字符串匹配的 policy 需要结合您的请求上下文来判断某次工具调用是否安全时,请使用 Jev policy 审查。首先以 **observe** 模式运行,这样您可以查看 Jev 的判断结果,同时已安装的 policies 仍负责处理每次调用。 + + Jev 的检查来自一个包;Failproof AI 默认不附带任何包。在您安装之前,即使已完成配置,Jev 也不会发出任何询问: + + ```bash + failproofai policies add FailproofAI/jev-policies + ``` + + ## 设置 Cloud Jev + + 在 Cloud 控制台中,打开 **Administration → Keys**,使用 **machine** 预设创建一个密钥。按[快速入门](/zh/start/quickstart)中的说明将其与 `failproofai config` 配合使用。在没有现有 Jev 配置的机器上,此操作将以 observe 模式启用 Cloud Jev。使用以下命令检查连接状态: + + ```bash + failproofai jev status + failproofai jev test + ``` + + ## 使用自定义端点 + + 在本地控制台中,打开 **Settings → Jev**。选择提供商,粘贴其 token,选择 **observe**,然后开启 Jev。 + + ![本地 Jev 设置面板,显示提供商、token 输入框以及已选中的 observe 模式。](/images/dashboard/jev-settings.png) + + 或在终端中配置并测试您的端点: + + ```bash + failproofai jev --url https://api.typesafe.ai/v1 --mode observe --key-stdin < ~/typesafe.key + failproofai jev test + ``` + + 让一个已接入 hook 的 Agent 对 `README.md` 使用其文件读取工具。确认该工具调用出现在会话中,然后在本地控制台的 **Policies → Activity** 下查看详情。一旦 observe 结果符合预期,请参阅 [Jev policies](/zh/policies/jev) 了解何时启用强制执行。有关提供商详情和配置说明,请参阅[集成参考](/zh/reference/jev)。 + + \ No newline at end of file