diff --git a/docs/ar/agenteye/alerts.mdx b/docs/ar/agenteye/alerts.mdx new file mode 100644 index 00000000..a6a0353a --- /dev/null +++ b/docs/ar/agenteye/alerts.mdx @@ -0,0 +1,308 @@ +--- +title: "التنبيهات" +description: "توثيق تنبيهات AgentEye." +--- + +تقيّم التنبيهات قاعدة على جدول زمني وتخطرك عند تجاوز حد معين. تحول AgentEye من لوحة تحكم سلبية إلى سطح استدعاء للأمور المهمة: ارتفاع معدل الأخطاء، تراجع الكمون، انخفاض درجات المُقيّم، أو أي حدث مخصص يمكن التعبير عنه كاستعلام ClickHouse. + +يغطي هذا الدليل ماهية التنبيه وأنواع المحفزات الخمسة وقنوات الإخطار الأربع ودورة حياة الحادثة والمعاملات التشغيلية. + +![صفحة التنبيهات: شبكة من بطاقات قواعد التنبيهات، كل واحدة تعرض نوع المحفز ونافذة التقييم والقنوات وشارة الخطورة](/agenteye/images/alerts.png) + +--- + +## المفاهيم + +- **التنبيه** — القاعدة. تحدد *ماذا* يتحقق (المحفز)، *كم مرة* (فترة التقييم)، *متى تُعتبر معطلة* (منطق مركب)، *مدى الاستعجالية* (الخطورة)، و*من/أين يتم الإخطار* (القنوات). +- **الحادثة** — ما يحدث عند تفعيل التنبيه. لكل تنبيه حادثة مفتوحة واحدة على الأكثر في المرة الواحدة. التخطيات المتكررة تحدّث أدلة الحادثة نفسها. يتم حل الحوادث بواسطة المشغّل؛ الحل التلقائي عند توقف القاعدة عن التفعيل مخطط له لكنه غير مفعل حالياً. +- **القناة** — حيث يذهب الإخطار: البريد الإلكتروني أو Slack أو webhook عام أو لوحة التحكم. كل تنبيه يمكن أن يرفق أي مجموعة. + +التنبيهات والحوادث تابعة لمنظمة وتُشاركها جميع مشغلو تلك المنظمة (في نشر أحادي المستأجر يكون ببساطة `default` المدمج). يمكن تعيين الحوادث إلى مشغل فردي للفحص الأولي. + +--- + +## أنواع المحفزات + +خمسة أنواع، لكل منها مواصفات JSON خاصة به. اختر الذي يطابق كيفية وصفك لـ "معطل". نموذج التنبيه الجديد في لوحة التحكم يبني نفس المواصفات لك، بتبديل محرر الشروط ليطابق نوع المحفز الذي تختاره: + +![نموذج التنبيه الجديد، مع الأساسيات (الاسم والوصف والتفعيل) ومنتقي المحفز يعرض عتبة المقياس و SQL المخصص ودرجة التقييم وإخفاقات التقييم والخيارات لكل حدث](/agenteye/images/alert-new.png) + +### 1. `metric_threshold` + +الأبسط. اختر مقياساً من قائمة مغلقة وعاملاً وحداً أدنى ونافذة زمنية. + +| المقياس | ما يحسبه | +|---|---| +| `event_count` | إجمالي الأحداث في النافذة | +| `error_count` | `event_type = 'error'` أو أي حدث فيه `error_type IS NOT NULL` | +| `error_rate` | `error_count / event_count` (0..1) | +| `p95_latency_ms` | `quantile(0.95)(duration_ms)` عبر جميع الأحداث التي لديها `duration_ms` | +| `p99_latency_ms` | `quantile(0.99)(duration_ms)` | +| `token_sum` | `SUM(input_tokens + output_tokens)` | + +العوامل: `>`, `>=`, `<`, `<=`, `==` (تقبل أيضاً كـ `gt`, `gte`, `lt`, `lte`, `eq`). + +مرشحات اختيارية: `environment`, `event_type`. + +مثال على المواصفات: + +```json +{ + "metric": "p95_latency_ms", + "filter": { "environment": "production" }, + "window_secs": 900, + "op": ">", + "value": 5000 +} +``` + +### 2. `custom_sql` + +لأي شيء لا تغطيه المقاييس المحددة مسبقاً. يمر SQL الذي يوفره المشغّل عبر نفس حارس `/queries/run` (SELECT/WITH فقط، بيان واحد، حد أقصى 10,000 صف) قبل أن يشغّله المُرسِل. وضعان: + +- **وضع الصفوف** (بدون `op`/`value`): ينشّط التنبيه بمجرد أن تعود الاستعلام صفاً واحداً على الأقل. +- **وضع القيمة**: يجب أن تسمي الاستعلام عموداً واحداً بـ `metric_value`؛ يقارن المُرسِل `metric_value` في الصف الأول مقابل `value` باستخدام `op`. + +```json +{ + "sql": "SELECT count() AS metric_value FROM agenteye.events WHERE event_type = 'error' AND ts >= now() - INTERVAL 1 HOUR", + "op": ">", + "value": 100 +} +``` + +### 3. `evaluation_score` + +يقرأ `agenteye.evaluations` ويقارن متوسط درجة مسماة عبر نافذة. + +```json +{ + "score_key": "hallucination", + "op": ">", + "value": 0.6, + "window_secs": 3600, + "min_count": 5, + "environment": "production" +} +``` + +يحمي `min_count` من القيم الشاذة أحادية العينة؛ لن ينشّط المُرسِل حتى توجد تقييمات N على الأقل في النافذة. + +### 4. `eval_compound` + +اقبض على تراجع الجودة الذي يظهر فقط عبر *عدة* درجات مُقيّم في وقت واحد. حيث يراقب `evaluation_score` درجة مسماة واحدة، يركّب `eval_compound` عدة شروط درجة تقييم في تنبيه واحد ويجمع نتائجها بمنطق مختار؛ لذلك قاعدة واحدة يمكن أن تعبر عن "ينشّط إذا انخفضت الفائدة **أو** ارتفع الهلوسة"، "ينشّط فقط إذا انخفضت الفائدة **و** كفاءة الأداة معاً"، أو "ينشّط إذا أخفقت **2 على الأقل من** هذه الفحوصات الثلاثة". + +كل شرط يقرأ متوسط درجة مسماة واحدة من `agenteye.evaluations` عبر النافذة المشتركة ويختبرها بعاملها وحدها الخاص. تُجمع النتائج البولية بعد ذلك بـ `combinator`: + +| المُركّب | المنطق | ينشّط عندما | +|---|---|---| +| `"any"` | OR | يخفق شرط واحد على الأقل | +| `"all"` | AND | يخفق كل شرط | +| `{ "at_least": N }` | M من N | يخفق N شروط على الأقل | + +```json +{ + "combinator": { "at_least": 2 }, + "conditions": [ + { "score_key": "hallucination", "op": ">", "value": 0.8 }, + { "score_key": "helpfulness", "op": "<", "value": 0.6 }, + { "score_key": "tone", "op": "<", "value": 0.5 } + ], + "window_secs": 3600, + "min_count": 5, + "environment": "production" +} +``` + +- `combinator`: `"any"`, `"all"`, أو `{ "at_least": N }`. +- `conditions[]`: كل `{ score_key, op, value }`، بنفس العوامل المحفزات الأخرى (`>`, `>=`, `<`, `<=`, `==`). +- `window_secs`: النظرة للخلف المشتركة المطبقة على كل شرط (افتراضي `3600`). +- `min_count`: الحد الأدنى لعدد التقييمات لكل شرط قبل أن يمكن لذلك الشرط أن يخفق؛ الشرط ذو العينات القليلة جداً في النافذة يعتبر "غير مخفق" (افتراضي `1`). +- `environment`: اختياري؛ يقيد كل شرط إلى بيئة واحدة. + +يسجل الدليل في الإخطار متوسط كل شرط المرصود والحد الذي تم اختباره ضده وعدد التقييمات المرصودة وما إذا خفق؛ حتى تتمكن من رؤية بالضبط أي فحوصات انشطت. + +### 5. `per_event` + +لتنبيهات "أي حدث يطابق X وصل". بدون تجميع؛ ينشّط المُرسِل بمجرد أن يرى تطابقاً في نافذة النظرة للخلف. + +```json +{ + "event_type": "error", + "lookback_secs": 60, + "environment": "production", + "tool_name": "bash", + "agent_id": "caa", + "error_type": "TimeoutError", + "message_contains": "vertex-ai timed out" +} +``` + +جميع المرشحات مرتبطة بـ AND؛ أي حقل تتركه غير محدود. + +| الحقل | الغرض | +|---|---| +| `agent_id` | قيد الأخطاء من وكيل معين (الواحد المعروض في صف `/errors`). | +| `error_type` | قيد فئة خطأ محددة (مثل `TimeoutError`) بدلاً من كل خطأ. | +| `message_contains` | تطابق سلسلة نصية غير حساس لحالة الأحرف ضد `payload.message`. مفيد للقبض على وضع فشل محدد واحد (مثل `prompt is too long`) بدون الإخطار بكل خطأ من نفس الوكيل. محدود بـ 200 حرف؛ تطابق كنص حرفي وليس نمط. | + +تلميح: ضع `lookback_secs` لمطابقة تقريبية لـ `eval_interval_secs` الخاص بالتنبيه حتى لا تخطر مرتين عن نفس الحدث. + +**اختصار من `/errors`:** لكل مجموعة خطأ، الصف الممثل في عرض الأخطاء (وقائمة تفاصيل حدث الجلسة لحدث خطأ) لديها زر **+ alert** يفتح `/alerts/new` مملوء مسبقاً بمحفز `per_event` مرتبط بـ `event_type` + بيئة ذلك الصف، بما في ذلك اسم مسبق من `error_type` للحمولة عند وجوده. تختار القنوات والنظرة للخلف بعد ذلك، لكن المطابق مملوء لك. يحتاج المشغّلون إلى `alerts:write` لظهور الزر. + +--- + +## المنطق المركب (M من N) + +لكل تنبيه معاملان صحيحان إضافيان بالإضافة إلى المحفز: + +- `eval_window`: عدد التقييمات الأخيرة التي يتم النظر إليها (افتراضي 1) +- `min_breaches`: كم عدد هذه التي يجب أن تخفق قبل ينشّط التنبيه (افتراضي 1) + +`1 من 1` (الافتراضي) هو "ينشّط عند الإخفاق الأول". `3 من 5` يعني "ينشّط عندما تكون القاعدة قد أخفقت 3 من آخر 5 تقييمات"، مفيد للإشارات المتذبذبة حيث قياس سيء واحد يكون ضجيجاً. يحافظ المُرسِل على مخزن مؤقت دائري لكل تنبيه؛ لا تضطر إلى إدارة حالة. + +--- + +## فترة التقييم + +`eval_interval_secs` يتحكم في عدد مرات تشغيل المُرسِل للقاعدة. محصورة بـ `[30, 86400]`. الإعدادات المحددة مسبقاً في لوحة التحكم: 1م / 5م / 15م / 1س. اختر فترة تطابق سرعة الإشارة الأساسية: تنبيه معدل خطأ 5 دقائق يُقيّم كل 15 ثانية يهدر المعالج؛ تنبيه لكل حدث يحتاج نظرة للخلف قصيرة أو سيسقط بصمت الأحداث بين النقرات. + +--- + +## القنوات + +كل تنبيه يمكن أن يرفق أي مجموعة من هذه الأربع. أوراق اعتماد لكل قناة (رابط Slack webhook، رابط webhook عام + سر التوقيع، المستقبلات الافتراضية للبريد) تُكوّن مرة واحدة في **`/settings`** وتُرجع بالاسم من كل تنبيه. بهذه الطريقة قناة Slack واحدة يمكن أن تخدم تنبيهات عديدة بدون تخزين كل واحدة لنسختها الخاصة من رابط webhook. + +ثلاث أنواع قنوات خارجية (بريد، Slack، webhook) تُحكم أيضاً بمفتاح إيقاف تشغيل عام للمنظمة، `alerts.enabled_channels`. عندما ينشّط تنبيه معلق قناة من نوع ليس في هذه المجموعة، يتخطاها المُرسِل ويسجل صف `alert_notifications` بحالة `skipped_disabled` وهدف `` (مما يتيح لك إيقاف جميع توصيل Slack عام دون تحرير كل قاعدة). قناة لوحة التحكم مسموحة دائماً. انظر [التكوين](#configuration). + +### البريد الإلكتروني + +يعيد استخدام نفس نقل SMTP الذي يشحن رسائل تسجيل الدخول لمرة واحدة. تُحل المستقبلات بالترتيب: + +1. تجاوز `recipients[]` لكل قناة (عندما غير فارغة). +2. إعداد `alerts.email_default_recipients` (مصفوفة من سلاسل البريد الإلكتروني). + +إذا كان SMTP غير مُكوّن فالقناة لا تعمل؛ المُرسِل بعد ذلك يسجل صف `alert_notifications` بهدف `` حتى يجعل سجل التدقيق سوء التكوين مرئياً. + +### Slack + +يرسل رسالة Block Kit إلى [رابط webhook وارد](https://api.slack.com/messaging/webhooks). + +- رابط افتراضي: `alerts.slack_default_webhook` (يُعين في `/settings`). +- تجاوز لكل تنبيه: اضبط `webhook_setting_key` للقناة إلى أي مفتاح إعداد من نوع رابط آخر، مثل `alerts.slack_oncall`, `alerts.slack_costs`. + +يتضمن الرأس رمز خطورة (`:rotating_light:` / `:warning:` / `:bell:`)، والرسالة تحمل زراً يربط بعمق بصفحة الحادثة. + +### Webhook عام + +تكامل JSON-POST لـ PagerDuty أو Opsgenie أو نقطة الإدخال الخاصة بك. شكل الجسد: + +```json +{ + "schema_version": 1, + "event": "alert.firing", + "incident": { "id": "uuid", "url": "https://…/incidents/uuid", "opened_at": "2026-…" }, + "alert": { "id": "uuid", "name": "errors > 50/hr", "severity": "critical" }, + "breach": { "value": 73.0, "summary": "ErrorCount > 50 (observed 73.000)", "evidence": { … } } +} +``` + +عندما يُعين `alerts.webhook_signing_secret`، يتضمن الطلب رأس `X-AgentEye-Signature: sha256=`، HMAC-SHA256 من الجسد باستخدام السر. تحقق من جانب المستقبل قبل الوثوق بالحمولة. + +يحمل الرأس `X-AgentEye-Event` `alert.firing` / `alert.test`. (`alert.resolved` محجوز لميزة الحل التلقائي المخطط لها وليس مُصدراً حالياً.) + +### لوحة التحكم + +بدون توصيل خارجي: التنبيه يكتب ببساطة صف `alert_notifications` يعرضه سطح صفحة الحوادث. مفيد بينما تضبط قاعدة ولا تريد إزعاج نظام خارجي، أو لتنبيهات منخفضة الاستعجالية يفحصها المشغّلون أثناء الفحص الأولي العادي. + +--- + +## دورة حياة الحادثة + +``` +firing ──ack──▶ acknowledged + │ │ + └────────────────────┴───── operator resolve ───▶ resolved +``` + +- **firing** — فتح المُرسِل للتو الحادثة أو كشف إخفاق آخر. يُروّج إخطار الإطلاق بالضبط مرة واحدة (محكوم بطابع زمني `notified_firing_at` على الحادثة). +- **acknowledged** — ضغط المشغّل على *ack* في `/incidents/:id`. الحادثة لا تزال تُعتبر مفتوحة؛ الإخفاقات اللاحقة ستحدّث أدلتها بدون إخطار مجدد. +- **resolved** — ضغط المشغّل على *resolve*. الحل التلقائي عند توقف القاعدة عن الإخفاق مخطط له لكنه غير مفعل حالياً، لذا حادثة مفتوحة تبقى مفتوحة حتى يحلها المشغّل. + +يمكن لحادثة جديدة أن تعيد الفتح على نفس التنبيه في أي وقت بعد حل السابقة. + +**خط زمني النشاط.** كل إجراء على حادثة — مفتوح أو معترف به أو محل — يُسجل في سجل نشاط إلحاقي ويُعرض على خط الزمن *activity* للحادثة، كل إدخال مُسند للمشغّل الذي أداه (بالبريد الإلكتروني) أو **automated** للإجراءات التي قام بها المُرسِل بنفسه (فتح تلقائي عند إخفاق). الاعتراف مشترك: عدة مشغّلين يمكنهم الاعتراف بنفس الحادثة وكل واحد يظهر كإدخال منفصل مُسند. + +تجمع صندوق **الحوادث** الواردة الحوادث المفتوحة حسب الحالة وتتيح لك التصفية حسب الخطورة والمُعيّن: + +![صندوق الحوادث يعرض بطاقات حوادث مرتبطة بتنبيهات وحوادث يدوية برامج خطورة ومُعيّنين](/agenteye/images/incidents.png) + +فتح حادثة يعرض أدلة الإخفاق والمُعيّنين والمشتركين وسجل النشاط المسند وخيط تعليقات: + +![عرض تفاصيل حادثة: التنبيه الأب وملخص الإخفاق والمُعيّنون والمشتركون وسجل النشاط المسند والمحادثة](/agenteye/images/incident-detail.png) + +--- + +## الأذونات المطلوبة + +تأليف *قواعد* التنبيهات والفحص الأولي للـ *حوادث* مسألتان منفصلتان بأذونات منفصلة، حتى تتمكن من منح دوران الاستدعاء وصول الحادثة بدون منحه أيضاً القدرة على إعادة كتابة القواعد. + +- `alerts:read`: اعرض قواعد التنبيهات. +- `alerts:write`: أنشئ أو حرّر أو احذف قواعد التنبيهات وشغّل إخطار اختبار. +- `incidents:read`: اعرض الحوادث. +- `incidents:write`: افتح حوادث يدوية (مجانية) غير مرتبطة بتنبيه. +- `incidents:ack`: اعترف بـ الحوادث وعيّنها وعلّق عليها وحلها. + +> **`alerts:ack` القديم.** المفاتيح والمشغّلون الذين مُنحوا رمز `alerts:ack` الأقدم يستمران في العمل: يُشرّفه كـ `incidents:ack` (ويضمن `incidents:read`)، لذا المشغّلون في الخدمة الحالية يحتفظون بوصولهم بدون إعادة إصدار أوراق اعتماد. أصدر منح جديد بعائلة `incidents:*`. + +امنح على مفاتيح API (`POST /keys`) والمشغّلون (`PUT /users/:id`). تحجم `PermGate` في لوحة التحكم الأزرار ذات الصلة عندما تكون الأذونة مفقودة؛ ستري `// 403` بجانب الإجراء. + +> **منتقي المستقبل للبريد الإلكتروني.** يسرد منتقي المستقبل في محرر التنبيهات أعضاء مؤسستك حتى تختار بالاسم. يُحمّل لأي مشغّل يحمل `alerts:read` أو `alerts:write`؛ عرض دليل فريقك لهذا الغرض **لا** يتطلب `users:read`، والمنتقي يعيد فقط عناوين بريد الأعضاء ليس سجلات المستخدمين الكاملة. + +--- + +## التكوين + +متغيرات البيئة المُستهلكة من قبل المُرسِل: + +| متغير | الافتراضي | الغرض | +|---|---|---| +| `ALERT_WORKERS` | `1` | مهام العمل لكل مثيل خادم. معظم النشريات تحتاج واحد فقط. | +| `ALERT_CLAIM_BATCH` | `16` | أقصى تنبيهات تعالجها نقرة عامل واحدة. | +| `ALERT_POLL_IDLE_SECS` | `5` | نوم العامل عندما تكون الطابور فارغة. | +| `ALERT_REQUEST_TIMEOUT_MS` | `15000` | مهلة زمنية لتقييم كل محفز. | +| `DASHBOARD_URL` | `https://app.befailproof.ai` | الأصل المستخدم لبناء رابط السحر في الإخطارات. اضبط لمضيف لوحة التحكم الخاص بك. | + +بعد فشل التقييم العابر (ClickHouse غير متاح، مهلة استعلام)، يعيد المُرسِل محاولة القاعدة مع التراجع الأسي. بمجرد أن تراكمت قاعدة **5** إخفاقات عابرة متتالية يُعاد جدولتها بفترة طبيعية بدلاً من المتابعة بالتراجع، لذا قاعدة تفشل بثبات تبقى تُقيّم. هذا الحد ثابت وليس قابلاً للضبط من قبل المشغّل. + +إعدادات القناة (مُدارة من `/settings` وليس env): + +- `alerts.email_default_recipients` (`email_list`): مصفوفة JSON من سلاسل البريد الإلكتروني — المستقبلات الافتراضية لقنوات البريد. +- `alerts.slack_default_webhook` (`url`): رابط Slack webhook الوارد الافتراضي. +- `alerts.webhook_default_url` (`url`): رابط webhook عام افتراضي. +- `alerts.webhook_signing_secret` (`secret`): مفتاح HMAC-SHA256. يُعاد دائماً كـ `""` في استجابة GET؛ اكتب قيمة جديدة للتدوير. +- `alerts.enabled_channels` (`channel_set`): مجموعة أنواع القنوات الخارجية على مستوى المنظمة التي يتم توصيلها عند تفعيل تنبيه؛ الافتراضي كل ثلاثة (`email`, `slack`, `webhook`). إزالة نوع هنا توقف عام هذه القناة لكل تنبيه بدون تحرير كل قاعدة. قناة لوحة التحكم تُسلّم دائماً وغير متأثرة بهذا الإعداد. + +--- + +## تحقق من تنبيه جديد + +قبل الاعتماد على تنبيه جديد: + +1. احفظه مفعلاً بقناة إخطار واحد على الأقل. +2. اختر **test** في صفحة تفاصيل التنبيه وأكد أن كل وجهة مُكوّنة تتلقى الإخطار الاصطناعي. +3. بعد أول إخفاق حقيقي، أكد أن الحادثة تظهر تحت **الحوادث** وقيمتها المقاسة تطابق استعلام لوحة التحكم المطابق. + +الحوادث لا تُحل تلقائياً عند توضيح حالة. يجب على المشغّل حلها من صفحة تفاصيل الحادثة. + +--- + +## استكشاف الأخطاء + +| العرض | السبب المحتمل | +|---|---| +| التنبيه لا ينشّط أبداً | `enabled = false`، أو لا قنوات مرفقة، أو استعلام CH الأساسي يعيد 0 صف. استخدم *test* لتأكيد القنوات؛ استخدم `/queries/run` لتأكيد المقياس. | +| إخطار Slack مفقود | `alerts.slack_default_webhook` (أو مفتاح التجاوز لكل تنبيه) غير معين: تحقق `alert_notifications.target` لصفوف ``؛ أو نوع `slack` معطّل عام في `alerts.enabled_channels`: تحقق من صفوف `alert_notifications` بحالة `skipped_disabled` وهدف ``. | +| Generic webhook 401 | المستقبل يتطلب توقيعاً لكن `alerts.webhook_signing_secret` غير معين. تحقق على المستقبل أن HMAC يطابق `hmac_sha256(secret, body)`. | +| بريد "من جميع الإرسالات فشلت" | أوراق اعتماد SMTP خاطئة أو عنوان `from` مرفوض من قبل محولك. نفس السطح الذي يشحن رسائل OTP: إذا عملت تلك فنقل SMTP حسن. | +| تعيد الحادثة الفتح بشكل متكرر | معاملات المركب عدوانية جداً: جرّب رفع `min_breaches` أو `eval_window` حتى ارتفاعات عابرة لا تعيد فتح الحوادث التي حللتها. | \ No newline at end of file diff --git a/docs/ar/agenteye/api-keys.mdx b/docs/ar/agenteye/api-keys.mdx new file mode 100644 index 00000000..7e1c9f75 --- /dev/null +++ b/docs/ar/agenteye/api-keys.mdx @@ -0,0 +1,254 @@ +--- +title: "مفاتيح API" +description: "توثيق مفاتيح API في AgentEye." +--- + +يستخدم AgentEye مفاتيح API دقيقة الحبيبة للتحكم في الوصول إلى الخادم. كل مفتاح يحمل واحدة أو أكثر من الأذونات التي تحدد ما يمكنه فعله. + +--- + +## الأذونات + +يطبق الخادم كتالوج ثابت من الأذونات؛ كل منها يتحكم في مسارات HTTP محددة. يحمل **مفتاح المسؤول** كل منها؛ ويحمل المفتاح ذو النطاق المحدود المجموعة الجزئية التي تمنحها عند الإنشاء. يتم رفض سلاسل الأذونات غير المعروفة عند إنشاء مفتاح. + +> **غير قابلة للتعيين للمفاتيح.** هناك اثنتان من الأذونات الصحيحة والمخصصة للبشر/لوحة التحكم فقط ولا يمكن منحهما لمفتاح API: `orgs:admin` (إدارة المثيل، وهي للمشغل فقط) و `keys:update`. يتم رفض طلب `POST /keys` أو `PATCH /keys/:id` الذي يحاول منح أحدهما باستخدام HTTP 422. راجع صف `keys:update` أدناه لمعرفة السبب في أن مفتاح Bearer قد ينشئ مفاتيح لكن لا يحررها أبداً. + +### استقبال الأحداث والاستعلام عنها + +| الأذن | مسارات HTTP | ما تسمح به | +|---|---|---| +| `events:add` | `POST /events` | استقبال دفعات من الأحداث من جامع. الأذن الوحيدة التي يحتاجها جامع. | +| `events:read` | `GET /events`, `GET /events/latency_aggregate`, `GET /events/environments`, `GET /events/models`, `GET /sessions/:session_id/export` | الاستعلام عن الأحداث وإدراج البيئات المعروفة وإدراج معرفات النماذج المرئية في البيانات (التي تستخدمها عرض النماذج وفلاتر النموذج) وحساب التجميع الكامن للنطاق على خريطة الحرارة / نطاق النسبة المئوية وتصدير جلسة عمل كـ JSONL. تتوفر نقاط نهاية ملخص شريط الفلتر المشترك `GET /events/environments` و `GET /events/models` مع **إما** `events:read` **أو** `evaluations:read`، لذا تعيد استخدام صفحة الجلسات (البوابة `evaluations:read`) نفس ملخص كل منظمة. | + +### الجلسات والتقييمات + +| الأذن | مسارات HTTP | ما تسمح به | +|---|---|---| +| `evaluations:read` | `GET /sessions`, `GET /evaluations`, `GET /evaluations/aggregate`, `GET /evaluations/environments`, `GET /evaluation-jobs` | إدراج الجلسات وقراءة نتائج التقييم وصحة التقييم المطوية المستخدمة من قبل لوحات التحكم وحالة قائمة انتظار عامل وظيفة التقييم. | +| `evaluations:trigger` | `POST /sessions/:session_id/re-evaluate` | ترتيب إعادة تقييم يدوية لجلسة منتهية. | + +### لوحات التحكم + +| الأذن | مسارات HTTP | ما تسمح به | +|---|---|---| +| `dashboards:read` | `GET /dashboards`, `GET /dashboards/:id`, `GET /dashboards/:id/tiles` | إدراج لوحات التحكم وتحميل واحدة وقراءة البلاطات الخاصة بها. | +| `dashboards:write` | `POST /dashboards`, `PUT /dashboards/:id`, `POST /dashboards/:id/tiles`, `PUT /dashboards/:id/tiles/:tile_id`, `DELETE /dashboards/:id/tiles/:tile_id`, `PUT /dashboards/:id/tiles/layout` | إنشاء وتحرير لوحات التحكم وإضافة / تحرير / إزالة البلاطات وإعادة ترتيب شبكة البلاطات. | +| `dashboards:delete` | `DELETE /dashboards/:id` | حذف لوحة تحكم بالكامل (يكون حذف مستوى البلاطة تحت `dashboards:write`). | + +### الاستعلامات المحفوظة (منشئ SQL) + +| الأذن | مسارات HTTP | ما تسمح به | +|---|---|---| +| `queries:read` | `GET /queries`, `GET /queries/:id`, `GET /queries/schema` | إدراج الاستعلامات المحفوظة وتحميل واحد ومراجعة مخطط ClickHouse للقراءة فقط الذي يستهدفه المنشئ. | +| `queries:write` | `POST /queries`, `PUT /queries/:id` | إنشاء وتحرير الاستعلامات المحفوظة. لا تزال SQL موجهة عبر نفس دور القراءة فقط وعمليات `sql_guard` كطلب `queries:run`. | +| `queries:delete` | `DELETE /queries/:id` | حذف استعلام محفوظ. | +| `queries:run` | `POST /queries/run` | تنفيذ SQL محفوظ أو مرتجل ضد دور القراءة فقط المستخدم من قبل المنشئ. | + +### مساعد AI + +| الأذن | مسارات HTTP | ما تسمح به | +|---|---|---| +| `agent:use` | `GET /agent/conversations`, `POST /agent/conversations`, `GET /agent/conversations/:id`, `PATCH /agent/conversations/:id`, `DELETE /agent/conversations/:id`, `PUT /agent/conversations/:id/messages` | الحديث مع مساعد لوحة التحكم AI وإدارة محادثاتك الخاصة (الخاصة). مطلوب على **المستخدم** لرؤية رصيف المساعد؛ مفتاح المساعد نفسه هو `dashboard-assistant` ويتم تثبيته بشكل منفصل (انظر أدناه). | + +### مفاتيح API + +| الأذن | مسارات HTTP | ما تسمح به | +|---|---|---| +| `keys:create` | `POST /keys` | إنشاء مفتاح API ذو نطاق جديد. **لا** تمنح تحرير أذونات مفتاح موجود (هذا هو `keys:update`). | +| `keys:read` | `GET /keys` | إدراج المفاتيح الموجودة. لا يتم إرجاع الأسرار من قبل نقطة النهاية هذه. | +| `keys:update` | `PATCH /keys/:id` | تحرير أذونات مفتاح موجود. أذن **مخصصة للبشر/لوحة التحكم فقط**؛ لا يمكن تعيينها لمفتاح API (قد ينشئ مفتاح Bearer مفاتيح لكن لا يحررها أبداً). | +| `keys:disable` | `POST /keys/:id/disable` | إلغاء مفتاح. لا يمكن إلغاء المفاتيح المحمية (`admin`, `dashboard-assistant`)؛ قم بتدويرها عبر متغير البيئة + إعادة تشغيل. | +| `keys:regenerate` | `POST /keys/:id/regenerate` | تدوير سر المفتاح. لا يمكن إعادة توليد المفاتيح المحمية عبر هذا المسار. | + +### مستخدمو لوحة التحكم + +| الأذن | مسارات HTTP | ما تسمح به | +|---|---|---| +| `users:create` | `POST /users`, `GET /users/defaults` | دعوة مستخدم جديد لوحة تحكم (مشكلة بريد إلكتروني + دخول OTP) وقراءة مجموعة الأذن الافتراضية التي يديرها لوحة التحكم والمستخدمة لتثبيت نموذج الدعوة. | +| `users:read` | `GET /users`, `GET /users/:id` | إدراج المستخدمين وتحميل سجل مستخدم واحد. | +| `users:update` | `PUT /users/:id` | تحرير أذونات المستخدم. تُرسل التحديثات بريداً إلكترونياً لتغيير الأذن للمستخدم المتأثر وتسري مفعولها في طلبهم التالي؛ لا يلزم إعادة دخول. | +| `users:delete` | `DELETE /users/:id`, `POST /users/:id/enable` | تعطيل مستخدم (يلغي جلساته فوراً) وإعادة تمكين مستخدم معطل مسبقاً. | + +هذه الأذونات تدعم صفحة **المستخدمون** في لوحة التحكم، حيث يتم عرض النطاقات الممنوحة لكل عضو كرقائق: + +![صفحة المستخدمون: بطاقة واحدة لكل مستخدم لوحة تحكم مع بريدهم الإلكتروني والأذونات الممنوحة والتحكم في التحرير/التعطيل](/agenteye/images/users.png) + +### الإعدادات التشغيلية + +| الأذن | مسارات HTTP | ما تسمح به | +|---|---|---| +| `settings:read` | `GET /settings`, `GET /settings/schema`, `GET /settings/model-context-windows`, `GET /settings/model-context-windows/resolve` | عرض الإعدادات التشغيلية التي يديرها لوحة التحكم وبيانات وصفية؛ إدراج تجاوزات نافذة سياق لكل نموذج؛ وحل النافذة الفعالة لنموذج. | +| `settings:write` | `PUT /settings/:key`, `PUT /settings/model-context-windows`, `DELETE /settings/model-context-windows` | تحرير الإعدادات التشغيلية وإضافة أو تغيير أو إزالة تجاوزات نافذة السياق لكل نموذج. التغييرات تؤثر على الأحداث الجديدة دون إعادة تشغيل الخادم. | + +![صفحة الإعدادات: إعدادات تشغيلية تديرها لوحة التحكم مثل عمليات تسجيل الدخول المسموح بها وعمر الجلسة/OTP وقابلة للتحرير دون إعادة تشغيل](/agenteye/images/settings.png) + +### التنبيهات والحوادث + +| الأذن | مسارات HTTP | ما تسمح به | +|---|---|---| +| `alerts:read` | `GET /alerts`, `GET /alerts/:id` | عرض تعاريف التنبيهات المكونة. | +| `alerts:write` | `POST /alerts`, `PUT /alerts/:id`, `DELETE /alerts/:id`, `POST /alerts/:id/test` | إنشاء وتحرير وحذف واختبار إطلاق تعاريف التنبيهات. | +| `incidents:read` | `GET /alerts/incidents`, `GET /alerts/incidents/:iid`, `GET /alerts/incidents/:iid/comments`, `GET /alerts/incidents/:iid/subscribers` | عرض الحوادث ومسار الفحص الخاص بها. | +| `incidents:write` | `POST /alerts/:id/incidents` | فتح حادثة يدوياً ضد تنبيه موجود. | +| `incidents:ack` | `POST /alerts/incidents/:iid/ack`, `POST /alerts/incidents/:iid/assign`, `POST /alerts/incidents/:iid/resolve`, `POST /alerts/incidents/:iid/comments`, `POST /alerts/incidents/:iid/subscribe`, `POST /alerts/incidents/:iid/unsubscribe` | الاعتراف بالحوادث وتعيينها وحلها والتعليق عليها. | + +### التدقيق + +| الأذن | مسارات HTTP | ما تسمح به | +|---|---|---| +| `audits:read` | `GET /audits`, `GET /audits/:id`, `GET /audits/:id/runs`, `GET /audits/findings`, `GET /audits/findings/:fid` | عرض تعاريف التدقيق والسجل والنتائج. | +| `audits:write` | `POST /audits`, `PUT /audits/:id`, `DELETE /audits/:id`, `POST /audits/:id/run`, `POST /audits/findings/:fid/status` | إنشاء وتحرير وحذف وتشغيل التدقيقات؛ فحص النتائج (الاعتراف / كتم الصوت / الرفض / الحل / إعادة الفتح / التعيين). | + +> عندما تم شحن التدقيقات، تم توسيع مستقبلي المنح الحاليين على نفس أشكال الأدوار مثل التنبيهات: حصل كل مستخدم ومجموعة أذن تحتفظ بـ `alerts:read` على `audits:read`، وحصل كل حامل `alerts:write` على `audits:write`. **لم** يتم توسيع مفاتيح API الموجودة — امنح `audits:*` لمفتاح بشكل صريح إذا كان يحتاج إلى سطح التدقيق. + +> يتم تحليل منح الرموز `alerts:ack` الموروثة كـ `incidents:ack` بحيث يحتفظ الأطباء بالدوام بالوصول دون إعادة تشغيل. لا يمكن تعيين الرمز من محرر المستخدم لوحة التحكم؛ تقدم المصفوفة `incidents:ack` بدلاً من ذلك. + +> نقطة نهاية منتقي المستقبِل `GET /alerts/recipients` (التي تدرج رسائل البريد الإلكتروني للأعضاء التي يمكن لمحرر التنبيهات إخطارهم) متاحة لحامل **إما** `alerts:read` **أو** `alerts:write`، حيث يمكن لمحرري التنبيهات ملء المنتقي دون منح `users:read`. + +> عارض لوحات التحكم يحتاج إلى **كل من** `dashboards:read` (لتحميل العروض المحفوظة) و `evaluations:read` (يتم حساب مقاييس الصحة من بيانات التقييم). امنح `dashboards:write` لتمكين المستخدم من إنشاء أو تحرير لوحات التحكم، و `dashboards:delete` لإزالتها. + +> `/health` و `/auth/*` (طلب OTP وتحقق OTP وفحص الجلسة وتسجيل الخروج) غير موثقة بالتصميم؛ إنها تدفق تسجيل الدخول وفحص الحيوية. `GET /access-granters` يتطلب مفتاح صحيح لكن بدون أذن محددة، بحيث يمكن لأي مستخدم مسجل دخول أن يرى أي من المسؤولين يمكن الاتصال بهم بشأن تغييرات الوصول. + +--- + +## مجموعات الأذونات + +تسمح لك مجموعات الأذونات بتطبيق دور مسمى بدلاً من اختيار الرموز الفردية يدوياً في كل مرة. بدلاً من تحديد اثني عشر أذن واحد تلو الآخر لكل مستخدم لوحة تحكم أو مفتاح API جديد، تختار مجموعة، وكل شخص معين لها يحمل منحة متسقة وقابلة للمراجعة. يؤدي تحرير مجموعة مخصصة إلى إعادة تطبيق المنحة الجديدة على كل مستخدم معين لها بالفعل، لذا فإن تغيير الدور هو تحرير واحد بدلاً من تمسح كل عضو. + +يتم تثبيت كل منظمة بثلاث مجموعات مدمجة: + +| مجموعة | الأذونات | المقصود ل | +|---|---|---| +| `read-only` | `events:read`, `keys:read`, `users:read`, `evaluations:read`, `dashboards:read`, `queries:read`, `settings:read`, `alerts:read`, `audits:read`, `incidents:read` | الوصول للعرض فقط عبر كل سطح تشغيلي. | +| `standard` | كل شيء في `read-only`، بالإضافة إلى `evaluations:trigger`, `queries:run`, `incidents:ack`, `agent:use` | القراءة فقط بالإضافة إلى إجراءات الطبيب بالدوام اليومية: تشغيل الاستعلامات وإعادة تقييم الجلسات والاعتراف بالحوادث واستخدام مساعد AI. | +| `admin` | كل أذن قابلة للتعيين | التحكم الكامل بالمنظمة. | + +المجموعات الثلاث المدمجة **غير قابلة للتغيير**؛ أسماؤها تعني دائماً نفس الشيء، لذلك من الآمن الإشارة إلى `read-only` و `standard` و `admin` في السياسة والتوجيه. يمكن للمشغل إنشاء **مجموعات مخصصة** إضافية لنمذجة الأدوار الخاصة بمنظمتك (على سبيل المثال، دور "مؤلف لوحة التحكم" أو دور "جامع فقط"). + +يتم عرض المجموعات لوحة التحكم وإدارتها عبر API في `GET /permission-sets` (الإدراج، البوابة من `users:read`) و `POST /permission-sets` / `PUT /permission-sets/:name` / `DELETE /permission-sets/:name` (إنشاء وتحرير وحذف مجموعة مخصصة، البوابة `settings:write`). يتم رفض حذف أو تحرير مجموعة مدمجة. + +عضوية المجموعة هي ما يدعم ميزتين أخريين: + +- **`DEFAULT_USER_PERMISSIONS`** (المنحة المحددة مسبقاً عندما يفتح المسؤول **+ مستخدم جديد**) تفترض المجموعة `standard`. انظر [النشر](/ar/agenteye/deployment). +- **علم `--set`** على `agenteye-orgctl` (إدارة عضو المشغل) يبدأ عضو من مجموعة مسماة، والتي يمكنك بعد ذلك ضبطها بـ `--add` / `--remove`. انظر [إدارة المستأجرين](/ar/agenteye/tenant-management). + +> عندما تتضمن مجموعة أذن غير قابلة للتعيين للمفاتيح (على سبيل المثال مجموعة مخصصة تحمل `keys:update`)، يؤدي تثبيت المفتاح من تلك المجموعة إلى إسقاط الرموز غير القابلة للتعيين؛ سيرفع الخادم خلاف ذلك المفتاح باستخدام HTTP 422. مستخدمو لوحة التحكم لا يخضعون لهذا القيد. + +--- + +## مفتاح المسؤول التمهيدي + +مفتاح المسؤول هو بيانات اعتماد جذر واحدة تسمح للمشغل بإحضار الوصول من لا شيء: به يمكنك سك كل مفتاح مضبوط آخر ودعوة مستخدمي لوحة التحكم الأوائل وتكوين المثيل قبل وجود أي مفتاح آخر. إنه المفتاح الوحيد الذي لا تنشئه عبر واجهة برمجة تطبيقات المفاتيح؛ يتم توفيره من البيئة بحيث يمكن الوصول إلى الخادم في الإقلاع الأول. + +عيّن متغير البيئة `ADMIN_KEY` على الخادم. عند كل بدء تشغيل يقوم الخادم بتحديث أو إدراج هذه القيمة كمفتاح مسؤول بجميع الأذونات. + +للتدوير: غيّر `ADMIN_KEY` إلى سر جديد وأعد تشغيل الخادم. + +--- + +## تحديد نطاق المنظمة + +**يتم إنشاء المنظمات وإدارتها بواسطة مشغل خارج النطاق، وليس عبر واجهة برمجة تطبيقات المفاتيح هذه.** يتم إجراء دورة حياة الكيان والعضو (الإنشاء / إعادة التسمية / الحذف / التطهير لمنظمة؛ إضافة / تحديث / إزالة عضو) باستخدام **`agenteye-orgctl`** CLI التي تعمل داخل حاوية الخادم؛ لا توجد واجهة برمجية HTTP أو زر لوحة تحكم لها. انظر [إدارة المستأجرين](/ar/agenteye/tenant-management). ما **لم يتغير**: **لا تزال مفاتيح API لكل منظمة مضبوطة في لوحة التحكم (أو عبر واجهة برمجة تطبيقات المفاتيح هذه)** بواسطة أعضاء المنظمة. + +في النشر متعدد المنظمات، كل مفتاح ينشئه عضو المنظمة (عبر واجهة برمجة تطبيقات المفاتيح هذه أو صفحة **المفاتيح** لوحة التحكم) ينتمي إلى **منظمة واحدة** ويمكنه فقط قراءة أو كتابة بيانات تلك المنظمة؛ يتم وضع علامة على المنظمة على المفتاح عند الإنشاء وفرضه على كل طلب. المفتاحان التمهيديان هما الاستثناء الوحيد: مفتاح `admin` (المثبت من `ADMIN_KEY`) ومفتاح `dashboard-assistant` (المثبت من `AGENT_API_KEY`) هما **نطاق المثيل** (لا يحملان أي منظمة). تتوثق حاوية لوحة التحكم باستخدام مفتاح `admin` بحيث يمكنها توكيل طلبات لكل منظمة نيابة عن الأعضاء المسجلي الدخول. لا تحتاج عمليات النشر أحادية المستأجر إلى التفكير في هذا؛ تنتمي جميع المفاتيح إلى المنظمة `default` المدمجة. + +--- + +## إنشاء المفاتيح + +استخدم مفتاح المسؤول (أو أي مفتاح بأذن `keys:create`) لإنشاء مفاتيح مضبوطة إضافية. + +### مفتاح جامع (استقبال فقط) + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "prod-collector", + "key": "your-collector-secret", + "permissions": ["events:add"] + }' +``` + +### مفتاح لوحة التحكم (قراءة فقط) + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "dashboard", + "key": "your-dashboard-secret", + "permissions": ["events:read", "keys:read"] + }' +``` + +عندما تنشئ مفتاح عبر واجهة برمجة التطبيقات HTTP، توفر قيمة `key` بنفسك؛ اختر سراً قوياً وخزنه بأمان. (تعمل لوحة التحكم بطريقة أخرى: فهي تُنشئ سراً قوياً لك وتعرضه مرة واحدة عند الإنشاء؛ انظر [إدارة المفاتيح في لوحة التحكم](#key-management-in-the-dashboard).) يؤكد الرد أنه تم إنشاء المفتاح: + +```json +{ + "id": "550e8400-e29b-41d4-a716-446655440000", + "name": "prod-collector", + "permissions": ["events:add"], + "created_at": "2026-04-01T12:00:00Z" +} +``` + +--- + +## إدراج المفاتيح + +```bash +curl -s http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +لا يتم إرجاع أسرار المفاتيح في استجابات الإدراج، فقط المعرفات والأسماء والأذونات. + +--- + +## تعطيل مفتاح + +يؤدي التعطيل إلى إلغاء الوصول فوراً دون حذف سجل المفتاح. + +```bash +curl -s -X POST http://your-server:8080/keys//disable \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +--- + +## إعادة توليد مفتاح + +يُنشئ سراً جديداً لمفتاح موجود. يتم إبطال السر القديم فوراً. + +```bash +curl -s -X POST http://your-server:8080/keys//regenerate \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +تتضمن الاستجابة السر الجديد بصيغة نصية عادية، **معروض مرة واحدة فقط**. + +--- + +## إدارة المفاتيح في لوحة التحكم + +توفر صفحة **المفاتيح** في لوحة التحكم واجهة مستخدم لجميع العمليات أعلاه. تحتاج إلى مفتاح بأذن `keys:read` لعرض القائمة، و `keys:create` / `keys:update` / `keys:disable` / `keys:regenerate` لإجراءات الإنشاء / التحرير / التعطيل / إعادة التوليد على التوالي. يختلف تحرير أذونات المفتاح (`keys:update`) عن إنشاء واحد (`keys:create`)، بحيث يمكنك منح المشغل القدرة على سك المفاتيح دون القدرة على إعادة نطاق الأذونات الموجودة، أو العكس. يغطي مفتاح المسؤول كل هذه. + +عندما تنشئ مفتاح من لوحة التحكم لا توفر السر؛ تُنشئ لوحة التحكم سراً قوياً لك وتعرضه **مرة واحدة** عند الإنشاء. انسخه فوراً وخزنه بأمان؛ لا يتم عرضه أبداً مرة أخرى، تماماً كما هو الحال مع إعادة التوليد. يمكنك بالفعل اختيار أذونات المفتاح مباشرة، أو تثبيتها من مجموعة أذن (انظر أدناه). + +![صفحة مفاتيح API: بطاقة واحدة لكل مفتاح تظهر اسمه والأذونات الممنوحة ووقت الإنشاء، مع إجراءات إعادة التوليد والتعطيل؛ تم وضع علامة على المفاتيح المحمية مثل `admin`](/agenteye/images/api-keys.png) + +--- + +## تخطيط المفاتيح الموصى به + +| مفتاح | الأذونات | يستخدمه | +|---|---|---| +| `admin` (التمهيد عبر متغير البيئة `ADMIN_KEY`) | الكل | العمليات/الإعداد وحاوية لوحة التحكم (يتوثق مع `ADMIN_KEY` ويوكل طلبات المستخدم مع فحوصات الأذن) | +| مفتاح جامع لكل مضيف | `events:add` | جامع على كل جهاز عامل | +| `dashboard-assistant` (التمهيد عبر متغير البيئة `AGENT_API_KEY`) | `events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run` | حاوية مساعد AI، مثبتة تلقائياً، **محمية**؛ لا يمكن تحريرها عبر واجهة برمجة التطبيقات | +| مفتاح قياس مساعد اختياري | `events:add` | أداة قياس المساعد الذاتية، إذا تم تمكينها | + +> **مفتاح المساعد.** يتم **تثبيت مفتاح المساعد تلقائياً** من قبل الخادم من متغير البيئة `AGENT_API_KEY` (نفس السر الذي يعرضه الوكيل كـ `AGENTEYE_API_KEY`)؛ لا توجد خطوة سك مفتاح يدوية ولا يشارك مفتاح المسؤول. أذوناته ثابتة في كود المصدر بحيث لا يمكن توسيع النطاق بسوء الإعدادات: قراءة عبر الأحداث / التقييمات / لوحات التحكم، بالإضافة إلى كتابة لوحات التحكم وقراءة / كتابة / تشغيل الاستعلامات لتدفق تأليف "اطلب من AI كتابة استعلام". لا تزال كل SQL تمر عبر نفس دور القراءة فقط وفحوصات `sql_guard` كاستعلام مكتوب من قبل المستخدم، لذا يوسع هذا سطح **التأليف**، وليس سطح البيانات؛ تبقى العمليات المخربة (`queries:delete`, `dashboards:delete`) عن قصد خارج مفتاح المساعد. مثل مفتاح `admin`، إنها **محمية**: لا يمكن تعطيلها أو إعادة توليدها عبر واجهة برمجة تطبيقات المفاتيح، فقط تدويرها بتغيير `AGENT_API_KEY` وإعادة تشغيل. يحتاج مستخدمو لوحة التحكم **أيضاً** إلى أذن `agent:use` لرؤية واستخدام المساعد. إذا قمت بتمكين القياس الذاتي، امنح المساعد مفتاح `events:add`-only منفصل. \ No newline at end of file diff --git a/docs/ar/agenteye/assistant.mdx b/docs/ar/agenteye/assistant.mdx new file mode 100644 index 00000000..e7ccc6d6 --- /dev/null +++ b/docs/ar/agenteye/assistant.mdx @@ -0,0 +1,199 @@ +--- +title: "مساعد ذكي" +description: "توثيق مساعد AgentEye الذكي." +--- + + +تتضمن لوحة التحكم مساعداً ذكياً **اختيارياً**، وهو لوحة دردشة موضوعة على الحافة اليمنى من لوحة التحكم تجيب على الأسئلة باللغة الطبيعية حول وكلائك ("كيف يتجه الجودة في prod هذا الأسبوع؟"، "أي جلسات حدث فيها خطأ اليوم؟"، "ملخص هذه الجلسة") وعندما يسمح المستخدم بكل إجراء، تقوم بصياغة وحفظ استعلامات SQL ولوحات تحكم نيابة عنهم. كما أنها توفر روابط قابلة للنقر مباشرة إلى الجلسات والاستعلامات ولوحات التحكم ذات الصلة، وتتمتع بـ **الوعي بالصفحة**: اسأل عن "هذه الجلسة" أثناء عرض جلسة وستعرف ما تقصد. + +تظهر الحامل كـ **شريط عمودي رفيع بارتفاع 44 بكسل** بشكل افتراضي: رمز موجه `›_` بالإضافة إلى نقطة صحة ملونة. انقر على الشريط (أو اضغط على `⌘J` / `Ctrl+J`) لتوسيعه إلى لوحة الدردشة الكاملة. اللوحة الموسعة **قابلة لتغيير الحجم** بين 320 و640 بكسل عن طريق سحب حافتها اليسرى؛ يتم تذكر عرضك المفضل عند إعادة تحميل الصفحة. + +يعمل كحاوية **`agent`** داخلية صغيرة (على Claude Agent SDK) لا يمكن للوحة التحكم الوصول إليها إلا. وهو **معطّل بشكل افتراضي** ويبقى مخفياً حتى تقوم بتكوين نقطة نهاية LLM. + +--- + +## ما يمكنه وما لا يمكنه فعله + +- **يقرأ البيانات التشغيلية التي يمكن للمستخدم السائل رؤيتها.** الأحداث والتقييمات والجلسات وقائمة انتظار مهام التقييم والاستعلامات المحفوظة ولوحات التحكم المحفوظة، ذات نطاق محدد لكل طلب لأذونات قراءة المستخدم. تنفذ أدوات القراءة فوراً. +- **الكتابات محمية بموافقة لكل إجراء.** يمكنه تأليف الاستعلامات المحفوظة (`create_saved_query`, `update_saved_query`)، وتشغيل SQL المسودة مقابل الدور للقراءة فقط للتحقق من صحتها (`run_query`)، وتجميع لوحات التحكم من تلك الاستعلامات (`create_dashboard`, `update_dashboard`, `add_query_to_dashboard`). يتوقف كل كتابة مقابل دعوة **الموافقة / الرفض / اطرح سؤالاً** في الدردشة؛ لا يستدعي SDK الأداة حتى ينقر المشغل على الموافقة. **الحذف غير متاح أبداً للمساعد**؛ تبقى العمليات المدمرة مع المشغلين. +- **تمر SQL المسودة عبر نفس التحقق من `sql_guard` والأدوار للقراءة فقط مثل SQL المكتوب من قبل المستخدم** (SELECT/WITH فقط، بدون عبارات متعددة). يتم توجيه الإجراء بناءً على الجداول التي يلمسها الاستعلام: الاستعلامات التي تشير إلى جداول التحليلات (الأحداث والتقييمات والجلسات) تعمل كمستخدم ClickHouse للقراءة فقط في المؤسسة (ذو نطاق محدد لتلك المؤسسة بسياسة صف، مع حد تنفيذ 10 ثوان وحد صف 100 ألف) بينما الاستعلامات التي تلمس جداول علائقية فقط تعمل على دور Postgres للقراءة فقط (10 ثوان، 10 آلاف صف). لا يمكن للمساعد توسيع سطح البيانات؛ يمكنه فقط التأليف على سطح الاستعلامات الذي يتمتع به المشغل بالفعل. +- يستخدم **مفتاح مساعد مخصص** (انظر أدناه) يحتوي على مجموعة أذونات ثابتة؛ حتى لو تصرف النموذج بشكل سيء فإنه لا يمكنه تجاوز تلك الأنطقة. +- يحتاج كل مستخدم لوحة تحكم إلى أذونة **`agent:use`** لرؤية واستخدام المساعد. يتم تصفية الأدوات لكل طلب لمطابقة أذونات البيانات الخاصة بالمستخدم، لذا يحصل مستخدم `events:read` على أدوات الأحداث ولكن لا أدوات `dashboards:write`. + +--- + +## لوحة ذكية الوعي بالصفحة: محرر على `/queries`، دردشة في مكان آخر + +لوحة المساعد على الجانب الأيمن **واعية بالصفحة**. منتقي النموذج والسجل المحادثة ونقطة صحة النموذج ومدخل الدردشة لا تتغير، لكن **شرائح قالب الحالة الفارغة ونص العنصر النائب وأي نقطة نهاية خلفية تصل إليها رسالة المستخدم** تتبدل تلقائياً بناءً على المسار الحالي. تصبح الحامل "مساعد AI لأي صفحة تقف عليها". + +**نقطتا نهاية خلفية، يتم الاختيار لكل صفحة (مع تجاوزات لكل شريحة).** + +| المسار | نقطة النهاية الافتراضية للصفحة | السبب | +| ------------------------------ | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | +| `/queries`, `/queries/new` | `POST /api/agent/compose-sql` (بدون حلقة أداة) | المستخدم يبدأ من جديد؛ ≤1 ثانية SQL أول رمز يُدفق مباشرة إلى المحرر | +| `/queries/` (موجودة) | `POST /api/agent/chat` (مساعد حلقة أداة كاملة)، افتراضي الصفحة | الرسائل المكتوبة بحرية يجب أن تسمح للمستخدم بأن يسأل أي شيء ("شرح هذا"، "ماذا يفعل هذا؟")؛ تختار شرائح إعادة البناء العودة إلى compose-sql عبر نوع كل شريحة | +| كل صفحة أخرى | `POST /api/agent/chat` (مساعد حلقة أداة كاملة) | أدوات القراءة + أدوات كتابة محمية بالموافقة | + +تحمل الشرائح على `/queries/` `kind` صريح حتى تتمكن صفحة واحدة من خلط التدفقين بسلاسة. مجموعة الشريحة الافتراضية هي شريحتا **دردشة** (`شرح الاستعلام على الشاشة`, `ماذا يفعل هذا الاستعلام؟`) بالإضافة إلى خمس شرائح **compose-sql** (`معاملة حسب نطاق التاريخ`، `إضافة مرشح status='error'`، إلخ). تنخفض الرسائل المكتوبة بحرية إلى الافتراضي للصفحة (دردشة)، لذا سؤال مثل "لماذا هذا بطيء جداً؟" يحصل على إجابة نثرية، بينما ينقر على شريحة `معاملة حسب نطاق التاريخ` عبر نقطة النهاية compose وتحرير SQL. + +عندما يعمل المحرر في **وضع التعديل** (يرى `currentSql` غير فارغ لأن المستخدم على `/queries/` أو `/queries/new` مع SQL المقترح محمل بالفعل)، يتحول موجه النظام من "تكوين استعلام جديد" إلى "تعديل SQL المقدم بأقل حد: الحفاظ على اختيار الجدول وأسماء الأعمدة وبنية الصلة والأسماء والمسافات البادئة". يُظهر للنموذج مجموعة منفصلة من الأمثلة المعملة قبل وبعد (معاملة، إضافة مرشح، تحويل إلى دلاء بالساعة)، لذا يسفر النقر على شريحة إعادة البناء عن diff أقلي مقابل SQL للمحرر، وليس إعادة كتابة من الصفر. + +انقر على شريحة compose (أو اكتب بحرية على `/queries/new`) → يدفق SQL إلى رسالة المساعد كـ ` ```sql ` كتلة مسيجة. **في اللحظة التي ينتهي فيها البث، إذا تم تثبيت Monaco على المسار الحالي، يضيء المحرر تلقائياً في عرض diff** (الأصلي على اليسار، المقترح على اليمين، تلميح `▾ AI proposed an edit` في الأعلى، وحبوب **قبول / رفض** أدناه). المستخدم لا يحتاج إلى البحث عن أو النقر على زر `إدراج في المحرر` لرؤية diff. الزر إدراج لا يزال معروضاً تحت كتلة SQL كإعادة تشغيل يدوية (مفيد بعد رفض أو عندما ينقل المستخدم للبعيد والعودة)، وهو يبقى الطريق الوحيد عندما يكون المستخدم على صفحة غير محرر (مثل قائمة الاستعلامات المحفوظة)؛ هناك يخزنها SQL في `sessionStorage` ويتنقل إلى `/queries/new`، حيث يقرأ المحرر المثبت حديثاً المخزن المؤقت عند التثبيت ويفتح نفس عرض diff. + +إذا كان SQL المقترح متطابقاً بالبايت لما هو موجود بالفعل في المحرر (تحرير بلا تأثير)، يتم تخطي الفتح التلقائي؛ لا نفتح diff فارغاً. زر `إدراج في المحرر` هو أيضاً بلا تأثير في تلك الحالة. + +عندما يقبل المستخدم مقترحاً على `/queries/new`، تقرأ الإجراء الأساسي للشريط **`save`** بدلاً من `create`؛ تم تسليم SQL إليهم من قبل المساعد؛ النموذج الذهني هو "إكمال هذا"، وليس "كتابة من الصفر". يتبدل التسمية بمجرد إدراج الحامل SQL ويبقى `save` حتى الانتقال بين الصفحات. على `/queries/` كان الزر يقرأ دائماً `save`؛ لا شيء يتغير هناك. + +خارج `/queries`، تعمل الحامل تماماً كما هي: دردشة كاملة مع بطاقات موافقة الأداة، وعي السياق بالصفحة، والاستشهادات. + +**الأذونات / البوابات.** نقطة النهاية compose بوابة على أذونة `queries:run` لكل مستخدم (قراءة مكافئة؛ لا يزال على المستخدم النقر على قبول وتشغيل، والتشغيل يمر عبر `sql_guard` موجود + توجيه `references_ch_tables` على خادم Rust). نقطة نهاية الدردشة بوابة على `agent:use`. كلاهما لا يزال يتطلب اتصالاً LLM مُكوناً على حاوية `agent`؛ إذا لم يتم تكوين واحد، تعرض الحامل لافتة "المساعد غير مُكون على هذا النشر" على أي من المسارين. + +**الرفضات.** يرفض المحرر أي طلب لا يمكنه رضاه باستعلام تحليلات للقراءة فقط ويصدر `-- REFUSE: ` بدلاً من SQL. يرفض الطلبات التي ستكتب بيانات أو تصل إلى جداول خارج مناظر التحليلات (`api_keys`، `users`، `dashboards`، `saved_queries`، `evaluation_jobs`)، ويرفض طلبات نثرية بحتة ("شرح هذا"، "ماذا يفعل هذا؟") على مسار compose؛ هذه تنتمي إلى مسار الدردشة وتنتج إجابة نثرية هناك. تعرض الحامل سلسلة الرفض كشريحة خطأ حمراء مضمنة في رسالة المساعد؛ لا شيء يُدرج. + +**اختيار النموذج.** مشترك مع مسار الدردشة. منتقي النموذج في رأس الحامل ينطبق على كلا نقطتي النهاية (استدعاء compose يمرر النموذج المختار عبر `resolveModel()` على خدمة الوكيل). عندما يسرد `AGENTEYE_AGENT_MODELS` عدة نماذج، يمكن للمشغلين خلط خيار Haiku-class للمحرر مع خيار Sonnet-class للدردشة؛ يختار المستخدم لكل محادثة. + +**قوالب لكل صفحة.** لكل صفحة قالب خاص بها (العنوان ونص الجسم ونص العنصر النائب وشرائح الاقتراح) حتى تتكيف الحامل مع الصفحة التي تقف عليها. تشير الشرائح المقدمة على مسار معين إلى نفس النوايا التي يُضبط المحرر من أجلها، لذا ينقر على الاقتراح يسفر عن التعديل الذي تتوقعه. + +**تعطيله.** نفس مسار الدردشة: الحامل والمحرر كلاهما بوابة بحاوية `agent` واتصال LLM الخاص به. إذا كنت تريد سلوك دردشة فقط لمستخدم معين، أزل أذونة `queries:run` (التي تعطل أيضاً زر **Run** للمحرر)؛ إذا كنت تريد سلوك محرر فقط، أزل `agent:use` من أدوار المستخدم، ثم أضف مرة أخرى `queries:run` بشكل منفصل حتى يتمكنوا من تنفيذ SQL المكتوب من قبل المؤلف. + +--- + +## تفعيله + +تشحن خدمة `agent` في ملف Docker Compose وفي manifests Kubernetes. لتشغيل المساعد، وفّر **(1)** نقطة نهاية LLM و **(2)** مفتاح البيانات المخصص للمساعد. + +### 1. اختر اتصال LLM + +اختر أحد هذه وعيّن المتغيرات المقابلة على خدمة `agent`: + +**a) Anthropic مباشرة** + +``` +ANTHROPIC_API_KEY=sk-ant-... +``` + +**b) عبر Portkey (موصى به؛ slug كتالوج النموذج، المفتاح فقط)** + +``` +PORTKEY_API_KEY= +AGENTEYE_AGENT_MODEL=@/claude-sonnet-4-6 +``` + +هذا هو المسار الأبسط: في Portkey، قم بإعداد **تكامل Anthropic** (Model Catalog)؛ يحصل على **slug**. أسمِ النموذج كـ `@/` والـ slug يحمل توجيه المزود + الأوراق المالية، لذا **لا توجد حاجة لمفتاح افتراضي**، +فقط مفتاح Portkey الخاص بك. يرسل الوكيل فقط `x-portkey-api-key` ويشير إلى بوابة Portkey؛ يحل Portkey الباقي. (اسم نموذج *عادي* يفشل مع "يُطلب رأس x-portkey-config أو x-portkey-provider header"; بادئة `@slug/` هي ما يجعل key-only تعمل.) لبوابة ذاتية الاستضافة اعيّن `PORTKEY_BASE_URL`. + +تفضل التوجيه لكل طلب بدلاً من slug؟ اعيّن `PORTKEY_VIRTUAL_KEY=` (أو +`PORTKEY_CONFIG=`) مع `AGENTEYE_AGENT_MODEL` عادي. + +**c) أي بوابة متوافقة مع Anthropic أخرى (LiteLLM، ذاتية الاستضافة، ...)** + +``` +ANTHROPIC_BASE_URL=https://your-gateway +# أسطر رأس مفصولة بأسطر جديدة "Name: Value" (ليس JSON): +ANTHROPIC_CUSTOM_HEADERS=x-my-header: value +``` + +**d) Amazon Bedrock / Google Vertex** + +``` +CLAUDE_CODE_USE_BEDROCK=1 # + بيانات اعتماد AWS قياسية في البيئة +# أو +CLAUDE_CODE_USE_VERTEX=1 # + بيانات اعتماد GCP قياسية في البيئة +``` + +اختياري تثبيت النموذج الافتراضي مع `AGENTEYE_AGENT_MODEL` (الافتراضي `claude-sonnet-4-6`). للسماح للمستخدمين **بالاختيار** من عدة نماذج، عيّن `AGENTEYE_AGENT_MODELS` لقائمة بيضاء مفصولة بفواصل (مثل +`@anthropic-prod/claude-opus-4-7,@anthropic-prod/claude-sonnet-4-6`); منتقي نموذج يظهر في رأس الدردشة، ويتم تذكر اختيار كل مستخدم. لا يستدعي الوكيل أبداً نموذج خارج هذه القائمة البيضاء. + +### 2. وفّر مفتاح المساعد + +اختر أي سر عشوائي وسلمه إلى **agent** كـ `AGENTEYE_API_KEY` وإلى **server** كـ `AGENT_API_KEY` (نفس القيمة). عند بدء التشغيل يرشح الخادم كمفتاح مخصص يسمى `dashboard-assistant` مع مجموعة الأذونات الثابتة هذه: `events:read`، `evaluations:read`، `dashboards:read`، `dashboards:write`، `queries:read`، `queries:write`، `queries:run`. لا تُمارس أذونات الكتابة أبداً إلا من خلال أدوات محمية بالموافقة (انظر "ما يمكنه وما لا يمكنه فعله" أعلاه). **لا توجد خطوة صك مفتاح يدوية ولا مفتاح إداري مشمول**. مجموعة الأذونات ثابتة في الخادم، والمفتاح المرشح **محمي**: لا يمكن تعطيله أو إعادة توليده عبر API المفاتيح؛ أدره بتغيير القيمة وإعادة تشغيل الخادم. **لا** تعاد استخدام مفتاح الإدارة/لوحة التحكم. + +```bash +SECRET="$(openssl rand -base64 32)" +# على خدمة الوكيل: +AGENTEYE_API_KEY="$SECRET" +# على خدمة الخادم: +AGENT_API_KEY="$SECRET" +``` + +على Kubernetes يتم ربط هذا نيابة عنك: ضع `AGENTEYE_API_KEY` في سر `agenteye-agent` وـ Deployment الخادم بالفعل يقرأ نفس القيمة كـ `AGENT_API_KEY`. + +### 3. عيّن رمز لوحة التحكم↔agent المشترك + +عيّن نفس `AGENTEYE_AGENT_TOKEN` على **كلا** خدمتي `dashboard` و `agent`. تقدمه لوحة التحكم عند استدعاء خدمة الوكيل الداخلي؛ يرفض الوكيل النداءات بدونه. + +### 4. امنح المستخدمين الوصول + +امنح مشغلي لوحة التحكم ذات الصلة أذونة `agent:use` (انظر [enterprise-docs/api-keys.md](/ar/agenteye/api-keys)). المستخدمون بدونها لا يرون المساعد أبداً. + +بمجرد تعيين نقطة نهاية LLM والمفتاح للقراءة فقط، أعد تشغيل **server** (لزرع المفتاح للقراءة فقط) وخدمة **agent**. تظهر حامل المساعد على الحافة اليمنى لأي مستخدم `agent:use`، مطوية بشكل افتراضي؛ انقر على الشريط أو اضغط على `⌘J` / `Ctrl+J` للتوسيع. + +--- + +## مرجع متغير البيئة + +عيّن على خدمة **`agent`**: + +| المتغير | الغرض | +|---|---| +| `PORTKEY_API_KEY` | المسار عبر Portkey (الوكيل ينشئ اتصال البوابة من هذا) | +| `PORTKEY_VIRTUAL_KEY` | مفتاح Portkey الافتراضي لبيانات اعتماد Anthropic (اختياري إذا كان للمفتاح إعداد افتراضي) | +| `PORTKEY_CONFIG` / `PORTKEY_BASE_URL` | تكوين Portkey المسمى / عنوان URL بوابة Portkey ذات الاستضافة الذاتية (اختياري) | +| `PORTKEY_PROVIDER` | slug مزود Portkey — خيار توجيه ثالث إلى جانب `PORTKEY_VIRTUAL_KEY` / `PORTKEY_CONFIG` (يُستخدم فقط عندما لا يتم تعيين أي منهما) | +| `ANTHROPIC_API_KEY` | وصول Anthropic المباشر (بديل لبوابة / Bedrock / Vertex) | +| `ANTHROPIC_AUTH_TOKEN` | رمز Bearer لبوابة تصادق عبر `Authorization: Bearer` بدلاً من `x-api-key` (اختياري) | +| `ANTHROPIC_BASE_URL` | نقطة نهاية لبوابة غير Portkey | +| `ANTHROPIC_CUSTOM_HEADERS` | رؤوس إضافية لبوابة غير Portkey: أسطر `Name: Value` مفصولة بأسطر جديدة (ليس JSON) | +| `CLAUDE_CODE_USE_BEDROCK` / `CLAUDE_CODE_USE_VERTEX` | المسار عبر Bedrock / Vertex | +| `AGENTEYE_AGENT_MODEL` | معرف النموذج الافتراضي (الافتراضي `claude-sonnet-4-6`) | +| `AGENTEYE_AGENT_MODELS` | قائمة بيضاء مفصولة بفواصل من النماذج التي يمكن للمستخدم الاختيار من بينها في رأس الدردشة. اترك لم يُعيّن لنموذج واحد ثابت. يجب أن يكون الافتراضي أعلاه واحداً من هذه (وإلا يُضاف). | +| `AGENTEYE_AGENT_MAX_CONCURRENCY` | الحد الأقصى من الدردشات المتزامنة لكل pod (الافتراضي 4)؛ الطلبات الزائدة تحصل 429 | +| `AGENTEYE_API_KEY` | مفتاح بيانات المساعد. عيّن **نفس** القيمة مثل `AGENT_API_KEY` للخادم، الذي يرشحه مع مجموعة أذونات ذات نطاق ثابت عند بدء التشغيل (انظر الخطوة 2). | +| `AGENTEYE_AGENT_TOKEN` | السر المشترك مع لوحة التحكم | +| `AGENTEYE_SERVER_URL` | عنوان URL خادم AgentEye (الافتراضي `http://server:8080`) | +| `AGENTEYE_AGENT_ALLOW_NO_ORG` | **تعدد المستأجرين.** معطل بشكل افتراضي (فشل مُغلق): يرفض المساعد طلب `/chat` الذي لا يحمل سياق منظمة مع `400`، لأن كل أداة يعملها ذات نطاق محدد لمنظمة واحدة. تُرسل لوحة التحكم دائماً هذا السياق بمجرد أن تكون واعية بالمنظمة، لذا تترك هذا عادةً لم يُعيّن. عيّن إلى `1` **فقط** أثناء نشر انتقالي حيث لا يزال لوحة التحكم غير واعية بالمنظمة تتحدث إلى وكيل واعٍ بالمنظمة، حتى يعود المساعد إلى منظمة `default` بدلاً من الرفض. امسحه بمجرد هبوط ترقية لوحة التحكم. | +| `AGENTEYE_AGENT_MAX_STEPS` | الحد الأقصى من خطوات استخدام الأداة لكل إجابة (الافتراضي 8) | +| `AGENTEYE_AGENT_TIMEOUT_MS` | انتهاء المهلة الزمنية الكلية لطلب `/chat` (جميع الأدوار + خطوات الأداة)، بالميلي ثانية (الافتراضي 90000)؛ أداة SQL لها حد تنفيذ 10 ثوان الخاص بها | +| `AGENTEYE_AGENT_SELF_TELEMETRY` | `1` لتسجيل أشغال المساعد الخاصة في AgentEye | +| `AGENTEYE_TELEMETRY_API_KEY` | مفتاح `events:add` منفصل فقط للقياس الذاتي | +| `AGENTEYE_AGENT_ENV` | علامة البيئة المطبقة على قياس المساعد الذاتي الخاص به (الافتراضي `prod`) | + +عيّن على خدمة **`dashboard`**: + +| المتغير | الغرض | +|---|---| +| `AGENTEYE_AGENT_URL` | حيث تصل لوحة التحكم إلى خدمة الوكيل. تعيّن manifests Kubernetes والملف المرفق `http://agent:9100`. اترك لم يُعيّن لإخفاء المساعد تماماً. | +| `AGENTEYE_AGENT_TOKEN` | يجب أن يطابق رمز الوكيل | + +--- + +## القياس عن بُعد ورؤية ما يسأل المستخدمون + +محتوى الموجه **يبقى داخل أنظمتك الخاصة** بشكل افتراضي. ثلاث طبقات: + +1. **مخزن المحادثة**: كل موجه وإجابة تُحفظ في قاعدة بيانات AgentEye (لكل مستخدم، خاص)، وقابلة لإعادة التحميل من منتقي السجل للمساعد. هذا هو السجل الدائم لما يسأل المستخدمون. +2. **تحليلات المنتج**: تسجل لوحة التحكم **البيانات الوصفية فقط** (كم مرة يُستخدم المساعد، عدد الأدوات، الزمن الكامن) إلى التحليلات الخاصة بك. نص **الموجه** لا يُدرج أبداً على هذا المسار. +3. **القياس الذاتي (اختياري)**: عيّن `AGENTEYE_AGENT_SELF_TELEMETRY=1` (بالإضافة إلى `AGENTEYE_TELEMETRY_API_KEY` فقط `events:add`) ويسجل المساعد أشغاله الخاصة في AgentEye كوكيل `dashboard-assistant`. تشاهد بعدها مشاركات المستخدمين وتفكير المساعد في نفس عروض الجلسات/الأحداث التي تستخدمها لكل شيء آخر. ملاحظة: تلك الأحداث مرئية لأي شخص لديه `events:read`؛ إذا كان هذا عريضاً جداً، اترك هذا معطلاً. + +--- + +## تعطيله + +أي من هذه يعطل المساعد (تختفي حامل الشريط): + +- ألغِ تعيين `AGENTEYE_AGENT_URL` على لوحة التحكم، **أو** +- اترك نقطة نهاية LLM لم تُكوَّن على الوكيل (لا `ANTHROPIC_API_KEY` / بوابة / Bedrock / Vertex)، **أو** +- لا تنشر خدمة `agent` على الإطلاق. + +--- + +## ملخص الأمان + +- **لا كتابات صامتة**: لا يمكن لأدوات كتابة المساعد (`create_saved_query`، `update_saved_query`، `create_dashboard`، `update_dashboard`، `add_query_to_dashboard`) أن تُنفذ بدون نقرة مشغل صريحة على زر الموافقة في الدردشة؛ بوابة ما قبل الاستدعاء للـ SDK تحجب الأداة حتى تصل موافقة إلى الوكيل عبر قناة خلفية. لا يوجد إعداد يعطل هذه البوابة. +- **نطاق بيانات ثابت وضيق**: يمصادق المساعد على الخادم بمفتاح مخصص تكون مجموعة أذوناته ثابتة في الخادم (`events:read`، `evaluations:read`، `dashboards:read`، `dashboards:write`، `queries:read`، `queries:write`، `queries:run`). الكتابات الوحيدة التي يمكنه تأليفها هي الاستعلامات المحفوظة ولوحات التحكم؛ يرفض الخادم أي شيء خارج هذا النطاق بغض النظر عما يحاول النموذج. +- **لا سطح حذف**: لا يحمل المفتاح أذونة حذف ولا أداة حذف مكشوفة. يحذف المشغلون عبر واجهة مستخدم لوحة التحكم، أبداً المساعد. +- **داخلي فقط**: الوكيل ليس له مسار عام؛ فقط لوحة التحكم يمكنها استدعاؤه، وفقط برمز مشترك. (على Kubernetes، تقيد NetworkPolicy الوكيل إلى الوصول فقط إلى خادم AgentEye ونقطة نهاية LLM.) +- **تحديد النطاق لكل مستخدم**: فقط مستخدمو `agent:use` يحصلون على المساعد، وتُعطى فقط الأدوات المطابقة لأذونات قراءة كل مستخدم. +- **لا HTML خام / لا تسريب الروابط**: تُعرَّض الإجابات كـ markdown معقّم؛ الروابط الخارجية مشطوبة. + +انظر [enterprise-docs/troubleshooting.md](/ar/agenteye/troubleshooting) للمشاكل الشائعة. \ No newline at end of file diff --git a/docs/ar/agenteye/audits.mdx b/docs/ar/agenteye/audits.mdx new file mode 100644 index 00000000..3730df81 --- /dev/null +++ b/docs/ar/agenteye/audits.mdx @@ -0,0 +1,108 @@ +--- +--- +title: "التدقيقات — كشف التحسينات الموكلة" +description: "توثيق تدقيقات AgentEye — كشف التحسينات الموكلة." +--- + + +التدقيقات هي وظائف متكررة تفحص سجلات الوكيل الخاص بك **عبر الجلسات** للعثور على أشياء تستحق التحسين. بينما ينظر التنبيه إلى مقياس واحد تعرفه بالفعل في الوقت الفعلي تقريباً، يقوم التدقيق *بالتحقيق*: وفقاً لجدول زمني تحدده، يقوم بتشغيل مسار سياسة حتمي على النافذة، ثم يطلق **وكيل موثوقية مدعوماً بالذكاء الاصطناعي** على الجلسات — يقوم الوكيل باستعلام البيانات بنفسه، وقراءة النصوص المريبة، و(عند الحاجة) تشغيل سكريبتات تحليل صغيرة، ثم يكتب **توصيات تحسين** مع الأدلة وراء كل واحدة. + +استخدم التدقيقات للإجابة على "ما الذي يجب أن أصلحه أو أحسنه في الوكلاء الخاصين بي؟" — واستخدم التنبيهات للحصول على إخطار فوري عند تجاوز عتبة محددة. يرتبط كل تحسين بالجلسات والاستعلامات الدقيقة وراءه، وينشئ نقرة واحدة تنبيهاً مملوءاً مسبقاً لالتقاط التكرارات. + +سطح لوحة التحكم هو **`//audits`** (الشريط الجانبي → *تحليل* → *التدقيقات*)، محمي بأذونات `audits:read` / `audits:write`. + +--- + +## كيف يعمل التشغيل + +لكل تشغيل طبقتان — قاعدة حتمية وتحقيق موكل. + +### 1. مسار السياسة (حتمي) + +قبل تشغيل أي نموذج، يقوم التدقيق بتنفيذ فهرس صغير من **فحوصات السياسة SQL** على النافذة: استعلامات تجميع محدودة تحدد الأنماط السيئة المعروفة وتقرير *كم عدد* الأحداث / *أي* الجلسات المطابقة — لا تطابق النص نفسه. يتضمن الفهرس: + +- **تسرب السرية/بيانات الاعتماد** في حمولات الأحداث — مفاتح الوصول AWS، مفاتيح API من نوع `sk-…`، مفاتيح PEM الخاصة، رموز JWT / Bearer، وتعيينات بيانات الاعتماد `KEY=…`. +- **علامات حقن المطالب** — "تجاهل التعليمات السابقة"، "كشف نظام المطالبات الخاص بك"، وما شابه ذلك. +- **معلومات تعريف شخصية** — أرقام على شكل SSN (استدلالي). +- **رفض أذونات الأدوات** و**حلقات استدعاء الأدوات الجامحة**. + +يتم الاحتفاظ بنتائج السياسة كنتائج بحث (نوع `policy`) التي **تظهر دائماً** (لا يتم قصها أبداً بواسطة الحد الأقصى لكل تشغيل)، وتُسلم إلى وكيل الذكاء الاصطناعي كتلميحات البداية. لأن هذه الطبقة لا تحتاج إلى نموذج، فإن التدقيق ينتج عنه أهم الإشارات الأمنية حتى لو كان وكيل الذكاء الاصطناعي غير متاح. + +### 2. التحقيق الموكل (الذكاء الاصطناعي) + +ثم يقوم التدقيق بتشغيل **وكيل موثوقية مستقل** (نفس خدمة Agents SDK التي تشغل مساعد لوحة التحكم، مع موجهة خاصة بالتدقيق). يُعطى **نطاق** التدقيق (الوكلاء المحددين × البيئات) و**النافذة الزمنية**، يقوم الوكيل بـ: + +- تشغيل استعلامات SQL للقراءة فقط مقابل جداول التحليلات الخاصة بك، +- قراءة حفنة من نصوص الجلسات التمثيلية، +- كتابة وتشغيل سكريبتات Python قصيرة اختياراً في صندوق فراغ مقفل داخل القرص (بدون شبكة، بدون وصول نظام الملفات، أسرار مخفوفة) للتحليل الذي لا تستطيع SQL التعبير عنه — تجميع الأخطاء، حساب التوزيعات، تنظيف الحمولات التي حصلت عليها بالفعل، +- وتسجيل كل **تحسين** موثق جيداً تجده. + +تعمل من خلال عدة أسطر تحقيق — تجميع الأخطاء، الانجراف مقابل أساس البداية، فشل الهدف في النصوص، إساءة استخدام الأداة، مقايضات الجودة/التكلفة، وفجوات التغطية — على **حساسية** التدقيق (منخفضة / متوسطة / عالية). كل تحسين **يجب أن يستشهد بالأدلة**: معرّفات الجلسة التي فحصها الوكيل فعلاً و/أو SQL الذي قام به. يتحقق الخادم من أن الجلسات المستشهد بها موجودة و**يرفض أي تحسين بدون أدلة باقية**، لذلك يحقق الوكيل ولكن لا يختلق أبداً. + +يحمل كل تحسين: + +- **توصية** (التغيير المحدد الذي يجب إجراؤه — تعديل المطالب، إصلاح مخطط الأداة، سياسة إعادة محاولة، حراسة، تغطية تقييم أكثر)، +- **تأثير متوقع** و**تقدير جهد** (منخفض / متوسط / عالي)، +- **حجم** — `big` (يجب استدعاء المشغل)، `medium` (ينتمي إلى تقرير التشغيل)، أو `small` (سياق لوحة التحكم)، +- **بصمة** مستقرة (من فئة المشكلة + النطاق، *ليس* جلسات هذا التشغيل) بحيث يتم تتبع نفس المشكلة من تشغيل إلى تشغيل حتى مع تغير الأدلة، +- وحيث يمكن لمراقب حتمي بسيط أن يلتقط التكرار، **تنبيه مقترح** يمكنك إنشاؤه بنقرة واحدة. + +> **طبقة الذكاء الاصطناعي اختيارية ولكنها موصى بها.** إذا لم يتم تكوين وكيل ذكاء اصطناعي لخط أنابيب التدقيق، فإن التشغيلات تعمل بشكل عام، تحتفظ بنتائج السياسة، وتقرر بصراحة "التحليل غير متاح" للطبقة الموكلة بدلاً من الإمرار صامتاً. + +### أنماط الفشل + +تصنيف التحسينات إلى **فهرس أنماط الفشل** الدائم في منظمتك (أو اقتراح وضع جديد). تعطي الأنماط الأنماط هوية مستقرة عبر التشغيلات وتتبع التكرار طويل الأفق. + +## دورة حياة الفحص + +على صفحة البحث (`/audits//findings/`): + +| الإجراء | التأثير | +|---|---| +| **acknowledge** | يحافظ على البحث مرئياً لكن يقلل أولويته إلى النصف. | +| **resolve** | يحدده كمثبت. إذا عاد النمط فعلاً لاحقاً، يعيد فتحه كـ **new** — لذا يكون الانحدار مرتفع الصوت، وليس مطوياً صامتاً في التاريخ. | +| **mute** / **dismiss** | قمع دائم: يتم تذكر بصمة النمط ولا تظهر أبداً، حتى عبر التشغيلات. استخدم mute لـ "معروف، مقبول"؛ dismiss لـ "ليس مفيداً". | +| **reopen** | يمسح القمع / الدقة ويعيد ترتيب النمط. | +| **assign** | يوجه البحث إلى مشغل (عضو منظمة) لتولي الملكية. الأولوية وحالة القمع بدون تغيير. | + +يتم التحكم في الضوضاء منخفضة الإشارة لكل تدقيق مع حد أقصى للنتائج لكل تشغيل (`top_k`) على التحسينات الموكلة. تتجاوز نتائج السياسة الحد الأقصى (أنها ذات صلة أمنية وتظهر دائماً). يتم عد أي شيء يقطعه الحد الأقصى في إحصائيات التشغيل — لا يتم إسقاط أي شيء صامتاً. + +## الجدولة + +- **Cadence** (`schedule_interval_secs`): كل ساعة إلى أسبوعياً؛ **يومياً هو الافتراضي**. التدقيقات متعمدة أغلظ من التنبيهات — يفحص التحقيق الموكل النوافذ الكاملة ويعمل لدقائق. +- **النافذة**: إما بحث متجدد ثابت (مثل "كل تشغيل يفحص آخر 7 أيام") أو **منذ آخر تشغيل** (الافتراضي) — يلتقط كل تشغيل من حيث انتهى التشغيل السابق الناجح، مع تداخل صغير بحيث لا تُفقد أحداث الحدود أبداً. +- يتم جدولة التشغيل التالي فترة زمنية كاملة بعد انتهاء التشغيل السابق **يكمل**، لذا فإن التشغيل البطيء لا يكدس أبداً تشغيل ثانٍ متزامن لنفس التدقيق. +- **تشغيل الآن** على صفحة التدقيق يجعله مستحقاً فوراً. + +## اختيار النموذج + +عند إنشاء تدقيق، يمكنك اختيار النموذج الذي يستخدمه التحقيق، من **قائمة النماذج التي قام المشغل بتكوينها** لخدمة الوكيل. مع نموذج واحد مكون، يعرض المنتقى كتسمية توضيحية؛ مع عدة، تختار. تركه بدون تعيين يستخدم الافتراضي المكون. + +## الإخطارات + +عندما يكتشف التشغيل **نتائج جديدة**، يقوم التدقيق بإخطار قنوات المنظمة المكونة — نفس بوابة `alerts.enabled_channels` والإعدادات التي يستخدمها خط أنابيب التنبيهات: + +- **Slack** — ملخص البنود الكبيرة الجديدة ذات الصلة مع ارتباط عميق. +- **البريد الإلكتروني** — **تقرير تدقيق** مصمم يسرد التحسينات الجديدة (أعلى شدة، توصيات لكل عنصر، ارتباط عميق)، مرسل عندما يكون للتدقيق قناة **بريد إلكتروني** مرفقة وهناك نتيجة بحث جديدة واحدة على الأقل. + +لا تعاود إخطار النتائج المتكررة لكن المعروفة. + +## مرجع التكوين + +يتم إدارة تعريفات التدقيق في لوحة التحكم (`/audits/new`) أو عبر API. تتضمن الإعدادات لكل تدقيق جدول التشغيل والنافذة والنطاق (`{"environments": [...], "agent_ids": [...]}`)، والحساسية (`low` / `medium` / `high`)، والقنوات الإخطارية، والحد الأقصى للنتائج لكل تشغيل (`top_k`)، والنموذج (عبر `llm_budget.model`). يتم توثيق إعدادات خادم مستوى المشغل (المهل الزمنية، الصندوق الفراغ، عنوان URL لخدمة الوكيل) في [deployment.md](/ar/agenteye/deployment). + +## API + +جميع النقاط النهائية ذات نطاق منظمة وتتبع مصادقة مفتاح المتحمل القياسية (انظر [api-keys.md](/ar/agenteye/api-keys)). + +| النقطة النهائية | الإذن | الغرض | +|---|---|---| +| `GET /audits` · `POST /audits` | `audits:read` / `audits:write` | سرد / إنشاء تعريفات التدقيق. | +| `GET` / `PUT` / `DELETE /audits/:id` | read / write / write | فحص، تحرير، حذف تدقيق. | +| `POST /audits/:id/run` | `audits:write` | جعل التدقيق مستحقاً فوراً. | +| `GET /audits/:id/runs` | `audits:read` | سجل التشغيل (النافذة، الحالة، الإحصائيات، عدد النتائج). | +| `GET /audits/findings` | `audits:read` | النتائج على مستوى المنظمة، قابلة للتصفية حسب `audit_id`، `status`؛ مرتبة حسب الأولوية. | +| `GET /audits/findings/:fid` | `audits:read` | تفاصيل البحث الكاملة (التوصية، الأدلة، الأولوية). | +| `POST /audits/findings/:fid/status` | `audits:write` | الفحص: `{"action": "ack" \| "mute" \| "dismiss" \| "resolve" \| "reopen" \| "assign"}`. | + +للاطلاع على "التدقيق قيد التشغيل لكن لم يجد شيئاً"، "صندوق الأكواد معطل"، و"بريد التدقيق الإلكتروني لم يتم تسليمه"، انظر [troubleshooting.md](/ar/agenteye/troubleshooting#audits). \ No newline at end of file diff --git a/docs/ar/agenteye/cli-recipes.mdx b/docs/ar/agenteye/cli-recipes.mdx new file mode 100644 index 00000000..b4905661 --- /dev/null +++ b/docs/ar/agenteye/cli-recipes.mdx @@ -0,0 +1,169 @@ +--- +title: "وصفات CLI للوكلاء" +description: "وثائق وصفات AgentEye CLI للوكلاء." +--- + +اسحب بيانات الجلسة والحدث والتقييم (وشغّل إعادة التقييمات) مباشرة من سكريبت أو وكيل ترميز، مع JSON نظيف على stdout يمكن توجيهه مباشرة إلى `jq`. تحول هذه الوصفات بيانات القابلية للملاحظة في AgentEye إلى شيء يمكن لمستخدم المحطة الطرفية أو وكيل ترميز ذكي (Claude Code، Cursor) الاستعلام عنه وأتمتته، دون الحاجة للنقر عبر لوحة التحكم. + +الأنماط أدناه جاهزة للنسخ واللصق في AgentEye CLI (`agenteye`). للتثبيت والمصادقة وقائمة الخيارات الكاملة، انظر [CLI](/ar/agenteye/cli)؛ شغّل `agenteye -h` أو `agenteye -h` للحصول على المساعدة المدمجة. + +## القواعد الذهبية + +1. **تأتي الخيارات العامة *قبل* الأمر.** `agenteye --json sessions` صحيح؛ `agenteye sessions --json` ليس كذلك. الخيارات العامة هي `--json`، `--base-url`، `--org`، `--token`، `--insecure`/`--secure`، `--timeout`، `--quiet`، `--no-color`. +2. **مرّر `--json` كلما حللت المخرجات.** تذهب البيانات إلى **stdout** بصيغة JSON؛ حالة المستخدم والأخطاء تذهب إلى **stderr**، لذا يبقى stdout نظيفاً للتوجيه إلى `jq`. +3. **افرع بناءً على رمز الخروج**، وليس على نص stderr: `0` موافق · `2` حجج سيئة · `3` لا يمكن الوصول إلى لوحة التحكم · `4` لم تسجل الدخول أو انتهت صلاحية الجلسة · `5` صلاحية مفقودة. +4. **اكتشف باستخدام `-h`.** كل أمر يوثق مرشحاته وتنسيقات القيم وشكل JSON. + +## إعداد لمرة واحدة + +```bash +export AGENTEYE_DASHBOARD_URL=https://agenteye.example.com # لتتجنب تكرار --base-url +agenteye login --email you@example.com # الصق الرمز المرسل بالبريد؛ صالح ~24h +``` + +## تأكد من المصادقة قبل القيام بالعمل + +`whoami` لا يرمي أخطاء على جلسة مفقودة أو منتهية الصلاحية؛ بدلاً من ذلك تقارير `logged_in:false`، لذا يمكن للوكيل اختبار حالة المصادقة بأمان. (لا يزال يمكن أن يخرج بقيمة غير صفرية إذا لم تكن هناك عنوان URL أساسي محدد أو كانت لوحة التحكم غير قابلة للوصول.) + +```bash +if [ "$(agenteye --json whoami | jq -r .logged_in)" != "true" ]; then + echo "Not authenticated. Run: agenteye login" >&2; exit 1 +fi +``` + +## ابحث عن الجلسات الفاشلة أو منخفضة الدرجات + +```bash +# جلسات في آخر 24 ساعة حيث فشل التقييم +agenteye --json sessions --since 24h --status error | jq -r '.sessions[].session_id' + +# تقييمات بدرجة <= 0.5 في المساعدة، لوكيل واحد +agenteye --json evals --agent-id checkout-bot --score helpfulness:..0.5 \ + | jq '.evaluations[] | {session_id, scores}' +``` + +تصفية الدرجات موجودة في **`evals`**، وليس `sessions`. `--score KEY:MIN..MAX` قابلة للتكرار ويتم دمجها بـ AND؛ أي حد اختياري (`..0.5` يعني ≤ 0.5، `0.9..` يعني ≥ 0.9). يمكنك تمرير ما يصل إلى 20 مرشح درجة لكل طلب؛ المزيد يرجع HTTP 400. يشارك `sessions` المرشحات `--env`، `--status`، `--agent-id`، `--session-id`، ونطاق الوقت مع `evals`، لكن لا يوجد `--score`. + +## اقرأ جلسة واحدة من البداية إلى النهاية + +لا يوجد أمر `session show` واحد — ادمج مسار الحدث مع التقييم الخاص بالجلسة: + +```bash +# آخر تقييم للجلسة (الحالة والدرجات) +agenteye --json evals --session-id run-001 | jq '.evaluations[0] | {status, scores}' + +# كل حدث في التشغيل (ارفع --limit لقائمة شاملة) +agenteye --json events --session-id run-001 --all --limit 1000 | jq '.events[] | {ts, event_type}' + +# فقط استدعاءات الأداة في جلسة +agenteye --json events --session-id run-001 --event-type tool_use,tool_result --all \ + | jq '.events[].payload' +``` + +## جلب كل شيء (الترقيم) + +النتائج هي الأحدث أولاً ومرقمة بالمؤشر. + +```bash +# طلقة واحدة: جلب ما يصل إلى 500 صف في صفحات 200 صف +agenteye --json events --session-id run-001 --limit 500 --all > events.json + +# الترقيم اليدوي: أرجع next_cursor +page=$(agenteye --json events --limit 100) +cursor=$(echo "$page" | jq -r '.next_cursor // empty') +[ -n "$cursor" ] && agenteye --json events --limit 100 --cursor "$cursor" +``` + +## قلّل المخرجات باستخدام --fields + +قيّد المفاتيح (في الجدول و `--json`) لتقليل ما يجب على الوكيل قراءته. + +```bash +agenteye --json sessions --since 7d --fields session_id,status,scores | jq -c '.sessions[]' +agenteye --json events --session-id run-001 --fields ts,event_type --all +``` + +أسماء الحقول غير المعروفة يتم رفضها (خروج `2`) مع القائمة الصحيحة، طريقة رخيصة لاكتشاف أسماء الحقول. + +## اكتشف قيم المرشح الصحيحة + +```bash +agenteye --json list envs | jq -r '.values[]' # قيم --env +agenteye --json list tools | jq -r '.values[]' # أسماء الأدوات؛ أيضاً agents، models، event_types، ... +agenteye --json list score_filters | jq -r '.values[]' # KEY الصحيح لـ --score KEY:MIN..MAX +``` + +## اختر منظمتك (متعدد المستأجرين) + +إذا كنت تنتمي إلى أكثر من منظمة واحدة، اختر المستأجر النشط عند تسجيل الدخول (يتم حفظه): + +```bash +agenteye login --org acme --email you@corp.com # عيّن المستأجر في نفس خطوة تسجيل الدخول +agenteye --json orgs list | jq -r '.orgs[].org_slug' +agenteye --org globex --json sessions --since 24h # استبدل لأمر واحد +``` + +تسجيل دخول متعدد المنظمات بدون `--org` يخرج بقيمة غير صفرية ويطبع المنظمات للاختيار منها. + +## وفّر مفتاح API لـ SDK/collector + +```bash +# يتم طباعة السر مرة واحدة فقط — مع --json إنه حقل .key +key=$(agenteye --json keys create ci-bot --add events:read.add | jq -r '.key') +agenteye keys regenerate ci-bot --yes # تدوير؛ agenteye keys disable ci-bot --yes للإلغاء +``` + +## قم بتشغيل استعلام محفوظ أو مخصص + +```bash +agenteye --json query run --sql "select count(*) from analytics.events" | jq '.rows' +agenteye --json query run errs --arg prod | jq '.rows' # استعلام محفوظ + موضعي $1 +``` + +## قم بفحص الحادث بشكل غير تفاعلي + +```bash +id=$(agenteye --json incidents list --state firing | jq -r '.incidents[0].id') +agenteye incidents ack "$id" +agenteye incidents assign "$id" you@corp.com +agenteye incidents resolve "$id" --yes +``` + +> الطفرات تتجاوز تلقائياً موجز التأكيد الخاص بهم تحت `--json` أو عندما لا يكون stdin TTY، لذا لا يعلق الوكلاء أبداً؛ مرّر `--yes`/`-y` لتجاوزه بشكل صريح في مكان آخر. + +## معالجة رمز الخروج في سكريبت + +```bash +out=$(agenteye --json sessions --since 1h) || code=$? +case "${code:-0}" in + 0) echo "$out" | jq '.sessions | length' ;; + 4) echo "Session expired - run 'agenteye login'." >&2 ;; + 5) echo "Missing permission (ask an admin for evaluations:read)." >&2 ;; + 3) echo "Dashboard unreachable - check the URL." >&2 ;; + *) echo "Unexpected error (exit ${code})." >&2 ;; +esac +``` + +## أشكال مخرجات JSON + +| الأمر | stdout JSON (مع `--json`) | +|---|---| +| `whoami` | `{"logged_in": true, "id", "email", "is_instance_admin", "active_org", "permissions": [...], "memberships": [...]}` أو `{"logged_in": false}` | +| `orgs list` | `{"active_org", "orgs": [{"org_slug","org_name","permission_set","permissions"}]}` | +| `events` | `{"events": [...], "next_cursor": }` | +| `evals` | `{"evaluations": [...], "next_cursor": }` | +| `sessions` | `{"sessions": [...], "next_cursor": }` | +| `errors` | `{"errors": [...], "next_cursor": }` | +| `list ` | `{"kind", "values": [...]}` | +| `keys list` / `keys create` | `{"keys": [...]}` / `{id, name, permissions, created_at, key}` (يتم عرض `key` مرة واحدة) | +| `query run` | `{columns: [{name,type}], rows: [[...]], truncated, elapsed_ms}` | +| `users list` / `settings list` | `{"users": [...]}` / `{"settings": [...]}` | +| `alerts list` / `incidents list` | `{"alerts": [...]}` / `{"incidents": [...]}` | +| create/update/delete (أي) | كائن المورد، أو `{"deleted": true, "id"}` للحذف | +| فشل (أي، مع `--json`) | `{"error": "...", "exit_code": , "status"?: , "hint"?: "..."}` على stdout | + +- كل عنصر **حدث** (`events`): `id, session_id, agent_id, event_type, ts, payload, environment`. +- كل عنصر **تقييم** (`evals`): `id, session_id, agent_id, environment, status, scores, reasoning, summary, error, attempt_count, duration_ms, completed_at, created_at`. +- كل عنصر **جلسة** (`sessions`): `session_id, agent_id, environment, status, scores, event_count, started_at, last_event_at, first_event_id, last_event_id, latest_evaluation`. + +يقبل `--fields` لكل أمر بدقة أسماء حقول عنصره الخاص — تختلف المجموعة بين `sessions` و `evals`، لذا قد يكون الاسم الصحيح لأحدهما مرفوضاً من الآخر. \ No newline at end of file diff --git a/docs/ar/agenteye/cli-skill.mdx b/docs/ar/agenteye/cli-skill.mdx new file mode 100644 index 00000000..96312e69 --- /dev/null +++ b/docs/ar/agenteye/cli-skill.mdx @@ -0,0 +1,95 @@ +--- +title: "مهارة AgentEye CLI Agent Skill" +description: "توثيق مهارة AgentEye CLI Agent Skill." +--- + + +مهارة **AgentEye CLI** (`agenteye-cli`) هي *مهارة Agent* قابلة للتثبيت تعلّم وكيل الترميز — Claude Code و Codex والأدوات المتوافقة — كيفية تشغيل نشر AgentEye لديك من خلال [`agenteye` CLI](/ar/agenteye/cli) من طلبات باللغة الإنجليزية العادية: *"هل هناك أي شيء معطل اليوم؟"*، *"أعطِ CI مفتاحاً يمكنه فقط دفع الأحداث"*، *"اعترف بحادثة الإطلاق وأسندها إليّ"*. + +**ليست** خدمة أو ملف ثنائي منفصل. إنها حزمة تعليمات صغيرة تعمل فوق CLI الذي قمت بتثبيته بالفعل: ينفذ الوكيل أوامر `agenteye --json …`، ويحلل JSON النظيف، ويجيبك بالنثر. كل شيء يمكنه فعله، يمكنك فعله بنفسك بكتابة نفس الأوامر. + +--- + +## كيف يتعلق بواجهات AgentEye الأخرى + +توفر AgentEye لك أربع طرق للوصول إلى نفس البيانات والتحكم. يكملان بعضهما البعض: + +| الواجهة | ما هي | حيث تعمل | استخدمها عندما | +|---|---|---|---| +| **[CLI](/ar/agenteye/cli)** | مرجع الأوامر والعلامات لـ `agenteye` | محطتك الطرفية | تريد تشغيل أو برمجة أمر معين | +| **[وصفات CLI](/ar/agenteye/cli-recipes)** | أنماط `jq`/خط أنابيب جاهزة للنسخ | محطتك الطرفية / البرامج النصية | تقوم بربط CLI بالأتمتة | +| **مهارة CLI** (هذا المستند) | باب أمامي باللغة الطبيعية على CLI | وكيل الترميز لديك، على محطة العمل الخاصة بك | تريد أن *تسأل فقط* واترك الوكيل يختار الأمر | +| **[مساعد ذكاء اصطناعي داخل لوحة التحكم](/ar/agenteye/assistant)** | دردشة مضمنة في لوحة التحكم | حاوية `agent` داخلية في مجموعتك | تريد أسئلة وأجوبة داخل لوحة التحكم حول بياناتك | + +### مقابل مساعد ذكاء اصطناعي داخل لوحة التحكم — تمييز مهم + +هذه أداتان مختلفتان تماماً بنطاقات تأثير مختلفة جداً: + +- **مساعد ذكاء اصطناعي داخل لوحة التحكم** ([assistant.md](/ar/agenteye/assistant)) هو دردشة مضمنة في لوحة التحكم، مدعومة بحاوية `agent` داخلية. وهو **للقراءة فقط مع التأليف المحمي بالموافقة**: يمكنه صياغة الاستعلامات المحفوظة ولوحات التحكم، لكن كل عملية كتابة تتوقف مقابل نقرة الموافقة الصريحة، ولا تحذف أبداً. يتم التحكم فيه بواسطة إذن `agent:use` وترى فقط البيانات الخاصة بالمنظمة التي تعرضها. +- **مهارة CLI** تعمل على *محطة العمل الخاصة بك* داخل *وكيل الترميز الخاص بك* وتشغل `agenteye` CLI كـ **أنت**. يمكنها تنفيذ **السطح الكامل للـ CLI، بما في ذلك التعديلات** — إنشاء/تدوير/تعطيل مفاتيح API، وتغيير إعدادات المنظمة، وحل الحوادث، وحذف الاستعلامات المحفوظة — مقيدة فقط بأذونات تسجيل دخول CLI الخاص بك. تعاملها بنفس الحذر الذي تتعامل به مع تشغيل تلك الأوامر يدوياً. + +--- + +## المتطلبات الأساسية + +1. **`agenteye` CLI مثبت** وعلى `PATH` (انظر [cli.md](/ar/agenteye/cli) — `pipx install agenteye`). +2. **عنوان URL لوحة التحكم الخاص بك** معين (`AGENTEYE_DASHBOARD_URL`، أو ينقل الوكيل `--base-url`). +3. **جلسة تسجيل دخول**: شغّل `agenteye login` بنفسك أولاً. المهارة **لا تستطيع** إكمال تسجيل دخول رمز لمرة واحدة عبر البريد الإلكتروني لك — ستخبرك بتشغيل `agenteye login` إذا كانت الجلسة مفقودة أو انتهت صلاحيتها (رمز خروج CLI `4`). + +--- + +## تثبيت المهارة + +Agent Skills هي مجلدات تحتوي على `SKILL.md` (بالإضافة إلى مراجع اختيارية). تقوم بتثبيت مهارة `agenteye-cli` بوضع مجلدها حيث يبحث وكيلك عن المهارات: + +- **Claude Code** — انسخ مجلد `agenteye-cli/` إلى `~/.claude/skills/` (متاح في كل مشروع) أو إلى `/.claude/skills/` (مقصور على هذا المستودع). يكتشفها Claude Code تلقائياً؛ تحقق من قائمة `/skills`، أو اسأل سؤالاً يتطابق مع وصفها. +- **Codex (OpenAI)** — يقرأ Codex نفس `SKILL.md`. ملف `agents/openai.yaml` المضمن يعين `allow_implicit_invocation: true`، لذلك يختار Codex المهارة تلقائياً عندما تتطابق المهمة؛ وإلا فاستدعها صراحةً باسم `$agenteye-cli`. + +يتم الحفاظ على المهارة جنباً إلى جنب مع `agenteye` CLI وتوزيعها كجزء من حزمة AgentEye الخاصة بك — إذا لم يكن لديك مجلد `agenteye-cli`، فاتصل بجهة اتصال AgentEye الخاصة بك. لا شيء عنها مقيد: فهي لا تحتاج إلى صورة Docker أو بيانات اعتماد، لأنها تقود فقط CLI العام `agenteye` مقابل لوحة التحكم الخاصة بك. + +--- + +## الأمان — التعديلات لا تطلب موجه عندما ينفذ وكيل CLI + +**اقرأ هذا قبل السماح لوكيل بإجراء تغييرات.** + +يطلب `agenteye` CLI عادةً *"هل أنت متأكد؟"* قبل إجراء مدمر. **يتخطى ذلك الأكيد تلقائياً عندما لا يكون متصلاً بمحطة طرفية — وهو بالضبط كيف يقوم به وكيل ترميز — و `--json` يتخطاه أيضاً.** لذا فإن موجه الأمان **لن** ينطلق للوكيل. + +تمت كتابة المهارة للتعويض: تم تعليمها الإدلاء بالأمر الدقيق الذي ستقوم به والحصول على **موافقتك الصريحة قبل أي تغيير حالة**. حافظ على هذا الانضباط — عندما تقود AgentEye من خلال وكيل، *أنت* خطوة التأكيد. أوامر تغيير الحالة التي يجب الحذر منها: + +- `keys create` / `update` / `disable` / `regenerate` +- `users create` / `update` / `disable` / `enable` +- `settings set` +- `alerts create` / `update` / `delete` / `test` +- أوامر الكتابة `incidents`: `ack` / `assign` / `resolve` / `open` / `comment-add` / `comment-delete` / `subscribe` / `unsubscribe` +- `query create` / `update` / `delete` +- `agent rename` / `delete` +- `orgs switch` + +كل شيء تحت **Observe** (`events`, `sessions`, `evals`, `errors`, `list`, `whoami`, `orgs list/current/perms`) للقراءة فقط ولا يغيّر أي شيء. + +لأن الوكيل يعمل بصفتك **أنت**، فيمكنه فقط فعل ما يُسمح به بواسطة تسجيل دخولك — يتم حل الأذونات **لكل منظمة** (انظر [api-keys.md](/ar/agenteye/api-keys)). أمر تفتقر الإذن له يرجع كود الخروج `5` مع الإذن الدقيق المذكور، حتى يتمكن الوكيل من إخبارك بالضبط ما تطلبه من مسؤول بدلاً من الفشل بغموض. + +--- + +## ما يمكنك السؤال عنه + +تعيّن المهارة القصد باللغة الطبيعية إلى أمر `agenteye` الصحيح، مكتشفة القيم الصحيحة أولاً (`list `, `whoami`) حتى لا تخمّن: + +- *"هل هناك أي شيء معطل / حريق في آخر 24 ساعة؟"* → `errors --since 24h --aggregate`، ثم تحليل. +- *"لماذا فشلت جلسة `run-001`؟"* → `events --session-id run-001 --all` + `evals --session-id run-001`. +- *"كيف تتجه الجودة هذا الأسبوع؟"* → `evals --aggregate --since 7d`، ثم حفر في التشغيلات منخفضة الدرجات. +- *"أعطِ CI مفتاحاً يمكنه فقط دفع الأحداث."* → `keys create ci --add events:add` (تذكر الأمر، ثم تنشئه وتلتقط السر لمرة واحدة). +- *"من لديه وصول؟ اجعل Dana للقراءة فقط."* → `users list` → `users update dana@… --permission-set read-only` (بعد تأكيدك). +- *"اعترف بحادثة الإطلاق وأسندها إليّ."* → `incidents list --state firing` → `incidents ack ` / `incidents assign you@…`. + +للأوامر الدقيقة والعلامات وأشكال JSON وراء هذه، انظر [cli.md](/ar/agenteye/cli) و [cli-recipes.md](/ar/agenteye/cli-recipes). + +--- + +## انظر أيضاً + +- **[CLI](/ar/agenteye/cli)** — مرجع الأمر والعلم الكامل لـ `agenteye`. +- **[وصفات CLI للوكلاء](/ar/agenteye/cli-recipes)** — أنماط `jq` والتعامل مع رموز الخروج جاهزة للنسخ. +- **[مساعد ذكاء اصطناعي](/ar/agenteye/assistant)** — المساعد داخل لوحة التحكم (لا تخلطه مع هذه مهارة الطرفية). +- **[مفاتيح API](/ar/agenteye/api-keys)** — نموذج الأذونات لكل منظمة الذي يحد من ما يمكن للمهارة فعله. \ No newline at end of file diff --git a/docs/ar/agenteye/cli.mdx b/docs/ar/agenteye/cli.mdx new file mode 100644 index 00000000..3f7049c1 --- /dev/null +++ b/docs/ar/agenteye/cli.mdx @@ -0,0 +1,293 @@ +--- +--- +title: "CLI" +description: "توثيق AgentEye CLI." +--- + + +أداة سطر الأوامر AgentEye (`agenteye`) هي عميل طرفي لنشرك على AgentEye. تستعلم عن بيانتك (الجلسات وسجلات الأحداث والتقييمات) وتدير المؤسسة (مفاتيح API والمستخدمون والإعدادات والتنبيهات والحوادث والاستعلامات المحفوظة) — كل ما يفعله لوحة المعلومات، من نص برمجي أو من وكيل ترميز. كل أمر يدعم علم `--json`، لذا يعمل بنفس الفعالية لشخص في موجه أوامر أو لوكيل ترميز (Claude Code أو Cursor) ينفذ أمرًا ويحلل النتيجة. + +> هذه هي أداة **`agenteye` CLI**، وهي أداة مختلفة عن عفريت **collector** (`agenteye-collector`). يتحدث الـ CLI مع **لوحة المعلومات**؛ يرسل المجمع الأحداث إلى الخادم. انظر [تثبيت Collector](/ar/agenteye/collector-installation) للمجمع. + +--- + +## التثبيت + +يتم نشر أداة سطر الأوامر على PyPI العام باسم **`agenteye`**. نظرًا لأن SDK Python من AgentEye يستخدم أيضًا اسم توزيع `agenteye`، قم بتثبيت أداة سطر الأوامر في بيئة **معزولة** (`pipx` أو `uv tool`) حتى لا يتصادم الاثنان في virtualenv واحد: + +```bash +pipx install agenteye +# أو +uv tool install agenteye +``` + +يعمل `pip install agenteye` العادي أيضًا إذا كنت لا تثبت Python SDK في نفس البيئة. تتطلب أداة سطر الأوامر Python 3.10+ ولا تحتاج إلى رمز GitHub؛ إنها حزمة عامة. + +الأمر المثبت هو **`agenteye`**: + +```bash +agenteye --version +agenteye --help +``` + +--- + +## المصادقة + +تتحقق أداة سطر الأوامر من هويتك في **لوحة المعلومات** برمز لمرة واحدة يُرسل عبر البريد الإلكتروني: + +```bash +agenteye login --email you@example.com +# يتم إرسال رمز مكون من 6 أرقام إليك عبر البريد الإلكتروني؛ الصقه في الموجه. +``` + +يتم تخزين رمز الجلسة في `~/.agenteye/cli.json` (قابل للقراءة فقط من قبلك، بصلاحية `0600`) وهو صحيح لمدة 24 ساعة افتراضيًا. عند انتهاء صلاحيته، قم بتشغيل `agenteye login` مرة أخرى. + +```bash +agenteye whoami # اعرض المستخدم الحالي والمنظمة النشطة والصلاحيات +agenteye logout # اسحب الجلسة وامسح الرمز المخزن +``` + +لن يرمي `whoami` أخطاء على جلسة مفقودة أو منتهية الصلاحية — بدلاً من ذلك يبلغ `logged_in: false`، لذا يمكن للنص البرمجي أو الوكيل فحص حالة المصادقة بأمان (قد يخرج بكود غير صفري إذا لم يتم تعيين عنوان URL أساسي أو كانت لوحة المعلومات غير قابلة للوصول). + +**المتطلبات:** يجب أن يُسمح لبريدك الإلكتروني بتسجيل الدخول إلى لوحة المعلومات (اطلب من مسؤول AgentEye)، وأن تكون لوحة المعلومات قابلة للوصول على عنوان URL الأساسي (انظر [التكوين](#configuration)). إذا طلبت رمزًا ولم يصل أي رمز، فمن المحتمل أن بريدك الإلكتروني لم يتم تفعيله بعد لدخول لوحة المعلومات. + +--- + +## اختيار منظمتك (متعدد المستأجرين) + +إذا كان حسابك ينتمي إلى أكثر من منظمة واحدة، اختر النشطة **عند تسجيل الدخول** — يتم حفظها واستخدامها في كل أمر لاحق: + +```bash +agenteye login --org acme # المصادقة وتعيين المستأجر النشط في خطوة واحدة +agenteye orgs list # المنظمات التي يمكنك الوصول إليها (النشطة معلمة) +agenteye orgs switch globex # غيّر الافتراضي المحفوظ +agenteye --org globex sessions # تجاوز أمر واحد +``` + +إذا كنت تنتمي إلى منظمة واحدة فقط، يتم تحديدها تلقائيًا ويمكنك تجاهل `--org` تمامًا. إذا كنت تنتمي إلى عدة منظمات ولم تختر واحدة، تسرد أداة سطر الأوامر المنظمات وتطلب منك إعادة التشغيل مع `--org `. يتم إرسال المنظمة النشطة إلى لوحة المعلومات في كل طلب، وتتم معالجة صلاحياتك **لكل منظمة** — يعرض `agenteye whoami` المنظمة النشطة وصلاحياتك فيها وجميع عضوياتك. + +--- + +## التكوين + +| الإعداد | العلم | متغير البيئة | الافتراضي | +|---|---|---|---| +| عنوان URL الأساسي للوحة المعلومات | `--base-url` | `AGENTEYE_DASHBOARD_URL` | **مطلوب** (لا يوجد افتراضي) | +| المنظمة النشطة/المستأجر | `--org` | `AGENTEYE_ORG` | يتم اختياره عند تسجيل الدخول؛ يحفظ في `~/.agenteye/cli.json` | +| رمز الجلسة | `--token` | `AGENTEYE_CLI_TOKEN` | من `~/.agenteye/cli.json` | +| إخراج JSON | `--json` | `AGENTEYE_CLI_JSON` | قيد الإيقاف | +| تجاوز التحقق من TLS | `--insecure` / `--secure` | `AGENTEYE_INSECURE` | قيد الإيقاف (يحفظ عند تسجيل الدخول) | +| انتظار الطلب (ثانية) | `--timeout` | — | 30 | +| تعطيل قياس المراسلات الاستخدام | _(بلا)_ | `AGENTEYE_ANALYTICS_DISABLED` (أو `DO_NOT_TRACK`) | قيد الإيقاف (قياس المراسلات قيد التشغيل) | + +ترتيب الحل هو **العلم → متغير البيئة → ملف التكوين**. لا يوجد افتراضي؛ يجب أن تشير أداة سطر الأوامر إلى لوحة المعلومات، إما لكل أمر (`--base-url https://agenteye.example.com`) أو مرة واحدة عبر البيئة (يتم حفظه أيضًا بعد `login` الأول): + +```bash +export AGENTEYE_DASHBOARD_URL=https://agenteye.example.com +``` + +دليل التكوين يحترم `AGENTEYE_HOME` (نفس الاتفاقية المستخدمة من قبل SDK والمجمع)؛ إذا تم تعيينه، يعيش `cli.json` في `$AGENTEYE_HOME/cli.json`. + +### TLS ذاتي التوقيع أو داخلي + +إذا كانت لوحة المعلومات مقدمة عبر HTTPS بشهادة ذاتية التوقيع أو داخلية (على سبيل المثال، اسم مضيف موازن التحميل الخام)، يرفضها التحقق من TLS برسالة خطأ `CERTIFICATE_VERIFY_FAILED`. مرر `--insecure` لتجاوز التحقق من الشهادة: + +```bash +agenteye --base-url https://agenteye.internal --insecure login +``` + +يتم **حفظ `--insecure` في `cli.json` عند تسجيل الدخول**، لذا الأوامر اللاحقة تتجاوز التحقق تلقائيًا؛ لا تحتاج إلى تكرار العلم. مرر `--secure` لاستدعاء تم التحقق منه لمرة واحدة، أو لحفظ التحقق مرة أخرى عند تسجيل الدخول التالي. تطبع أداة سطر الأوامر تحذيرًا على stderr قبل أي أمر يتصل بلوحة المعلومات أثناء تعطيل التحقق. يزيل تجاوز التحقق الحماية من هجمات الوسيط؛ تأكد من أنك تثق في مسار الشبكة إلى لوحة المعلومات (VPN أو شبكة فرعية خاصة وما إلى ذلك) قبل الاعتماد على ذلك. + +--- + +## قياس المراسلات والخصوصية + +تُرسل أداة سطر الأوامر **تحليلات استخدام مجهولة** إلى خدمة تحليلات Exosphere (PostHog): الأوامر التي يتم تشغيلها (على سبيل المثال `sessions` أو `keys create`)، ما إذا نجحت، وكم من الوقت استغرقت. تُعلم إشارة الاستخدام هذه بالميزات المحددة الأولويات. + +- **بيانات الوكيل أو الجلسة أو الحدث لا تترك أبدًا البنية التحتية لديك.** يتم الإبلاغ عن استخدام أداة سطر الأوامر فقط: اسم الأمر والأمر الفرعي (على سبيل المثال `keys create`)، **أسماء** الأعلام التي استخدمتها (أبدًا قيمها)، الحالة والمدة — بالإضافة إلى حدث لكل إجراء للطفرات (على سبيل المثال `api_key_created` أو `query_run`) تحمل فقط أسماء ثابتة/تعدادات وعدادات غير دقيقة. عنوان URL لوحة المعلومات ورمز الجلسة والبريد الإلكتروني وتجنب المنظمة وعناصر الموارد و SQL وأسرار المفاتيح وفلاتر الاستعلام **لن تُرسل أبدًا**. يتم التعرف على المشغلين فقط بواسطة معرّف داخلي معتم، وليس أبدًا عبر البريد الإلكتروني. +- **قياس المراسلات مُفعّل افتراضيًا**. لتعطيله، اضبط `AGENTEYE_ANALYTICS_DISABLED=1` في بيئة أداة سطر الأوامر (تحترم أداة سطر الأوامر أيضًا اتفاقية أداة متعددة `DO_NOT_TRACK=1`). +- تُرسل أداة سطر الأوامر مباشرة إلى PostHog (`https://us.i.posthog.com`). **الجهاز الذي يقوم بتشغيل أداة سطر الأوامر** يحتاج إلى وصول خارج إلى هذا المضيف؛ إذا تم حظره، لا يفعل قياس المراسلات شيئًا بسرية (الإرسال محدود بالوقت لذا لا يؤخر أو يكسر الأمر) والـ CLI غير متضرر. + +--- + +## الخيارات العامة والاتفاقيات + +اقرأ هذا مرة واحدة؛ تنطبق على كل أمر. + +- **تأتي الخيارات العامة قبل الأمر.** `agenteye --json sessions` صحيح؛ `agenteye sessions --json` خطأ في الاستخدام. الخيارات العامة هي `--json` و `--base-url` و `--org` و `--token` و `--insecure`/`--secure` و `--timeout` و `--quiet` و `--no-color`. +- **يطبع `--json` JSON نقي إلى stdout، وليس شيء آخر.** تذهب سطور الحالة البشرية والتحذيرات والأخطاء إلى **stderr**، لذا يبقى التقاط stdout `--json` نظيفًا للأنابيب إلى `jq` حتى عندما تظهر سطر الحالة. بدون `--json` تحصل على عرض مربع وملون لعيون البشر. +- **اكتشف باستخدام `--help`.** كل أمر وأمر فرعي به `--help` (و `h-` الاسم المستعار): `agenteye -h` و `agenteye sessions -h` و `agenteye keys create -h`. يسرد المساعدة على المستوى الأعلى أيضًا رموز الخروج والخيارات العامة. لا توجد عملية على سطح قابل للقراءة من قبل الآلة؛ استخدم `--help` لكل أمر، بالإضافة إلى `agenteye query schema` و `agenteye settings schema` الخاص بالمجال لتلك السجلات الاثنين. +- **التأكيدات تتخطى تلقائيًا للنصوص البرمجية والوكلاء.** تطالب أوامر إنشاء/تحديث/حذف بـ "هل أنت متأكد؟" في محطة طرفية تفاعلية، لكن **تتخطاها تلقائيًا تحت `--json` أو في أي وقت لا يكون stdin عبارة عن TTY** — لذا لا تعلق الأجهزة والوكلاء أبدًا. مرر `--yes`/`-y` لتخطيها بشكل صريح. لأن الموجه لن يعمل لوكيل، يجب على الوكيل تأكيد الإجراءات المدمرة مع الإنسان أولاً. +- **الترقيم:** النتائج هي الأحدث أولاً والمُرقمة بالمؤشر. `--limit N` (الاسم المستعار `-n`) تغطي الصفوف و **افتراضيًا 50**؛ `--all` ترقيم تلقائي (في أجزاء من 200 صف) **يصل إلى `--limit`** — لذا `--all` العارية تتوقف عند 50. للاجتياز الكامل مرر حد أعلى صريح عالي: `--all --limit 1000`. يتحكم `--page-size N` في الجزء لكل طلب (كحد أقصى 200)؛ `--cursor ` يستأنف من `next_cursor` للصفحة السابقة. +- **فلاتر الوقت:** `--since` يأخذ نافذة نسبية — `15m` أو `1h` أو `6h` أو `24h` أو `7d` أو `30d` أو `all` (إعدادات لوحة المعلومات). `--from`/`--to` يأخذ طوابع زمنية ISO-8601 UTC صريحة **مع `T` و منطقة زمنية** (على سبيل المثال `2026-06-01T00:00:00Z`) لنطاق مخصص ويتجاوز `--since`؛ القيمة المفصولة بمسافة أو بدون منطقة زمنية هي خطأ استخدام. +- **`--fields a,b,c`** (على `events` و `sessions` و `evals` و `errors`) تقيد الإخراج إلى تلك المفاتيح، للجدول و `--json`. يتم رفض الأسماء غير المعروفة مع القائمة الصحيحة — طريقة رخيصة لاكتشاف أسماء الحقول. +- **`--file payload.json`** (أو `--file -` لقراءة stdin) توفر نص جسم طلب JSON كامل حيث يكون لموارد شكل معقد — على `alerts create/update` و `settings set` و `users create/update`. يستخدم SQL استعلام محفوظ `--sql @file.sql` بدلاً من ذلك. +- **فلاتر متعددة القيم** مفصولة بفواصل → مطابقة كمجموعة (اتحاد داخل عامل تصفية واحد، و AND عبر الفلاتر): `--event-type tool_use,tool_result`. خيارات النقر ليست متغيرة الحجم، لذا `--add a b` فاصل — استخدم `--add a,b` أو كرر العلم (`--add a --add b`) أو اقتبس (`--add "a b"`). + +--- + +## مرجع الأمر + +لدى أداة سطر الأوامر **18 أمر على المستوى الأعلى**. جميع أوامر القراءة تقبل `--json` والخيارات العامة أعلاه؛ قم بتشغيل `agenteye -h` (أو ` -h`) لقائمة الأعلام الشاملة وشكل JSON لأي واحد. + +### الهوية — `login` · `logout` · `whoami` · `orgs` · `version` · `help` + +```bash +agenteye login --email you@example.com [--org acme] # رمز لمرة واحدة يرسل عبر البريد؛ يحفظ الجلسة +agenteye logout # امسح الجلسة المحفوظة على هذه الآلة +agenteye whoami # المستخدم الحالي والمنظمة النشطة والصلاحيات +agenteye version # اطبع إصدار CLI (مثل --version) +agenteye help # مساعدة على المستوى الأعلى (مثل --help) +``` + +يفحص `orgs` وينقل المستأجر النشط: + +```bash +agenteye orgs list # منظماتك + دورك في كل واحدة (النشطة معلمة) +agenteye orgs switch acme # غيّر المنظمة النشطة المحفوظة (حذف الرمز للاختيار من قائمة على TTY) +agenteye orgs current # بطاقة الهوية للمنظمة النشطة +agenteye orgs perms # صلاحياتك في المنظمة النشطة، مجمعة حسب المورد +``` + +### المراقبة (القراءة فقط) — `events` · `sessions` · `evals` · `errors` · `list` + +لا تحتاج أي من هذه إلى تأكيد. فلاتر مشتركة: `--session-id` و `--agent-id` و `--env` (**وليس** `--environment`)، ونطاق الوقت (`--since` / `--from` / `--to`). + +```bash +# events (الاسم المستعار: مسار متعدد الخطوات الخام) — الأحدث أولاً +agenteye --json events --session-id run-001 --event-type tool_use,tool_result --all --limit 1000 +agenteye --json events --since 1h --search timeout --all | jq '.events[].payload' + +# sessions — صف واحد لكل تشغيل وكيل (وقت/بيئة/وكيل/جلسة/حالة؛ لا تصفية نقاط) +agenteye --json sessions --since 24h --status error +agenteye --json sessions --agent-id checkout-bot --env prod --all --limit 1000 + +# evals — نتائج التقييم + الدرجات؛ --score تصفي حسب المقياس، --aggregate تتدحرج +agenteye --json evals --score helpfulness:0.5..0.8 --score tool_efficiency:..0.3 +agenteye --json evals --aggregate --since 7d --env prod # خليط الحالة + إحصائيات نقاط لكل مفتاح + +# errors — أحداث خاطئة؛ --aggregate للعد/الجلسات/الوكلاء/آخر مرة رؤية +agenteye --json errors --since 24h --aggregate +agenteye --json errors --since 24h --error-type timeout --all --limit 1000 + +# list — اكتشف قيم الفلتر الصحيحة قبل أن تصفي +agenteye list envs # أيضًا: agents event_types score_filters models hooks triggers tools error_types +``` + +`--score KEY:MIN..MAX` (على **`evals`**، وليس `sessions`) قابل للتكرار وموحد بـ AND؛ كلا الحدود اختيارية (`..0.5` تعني ≤ 0.5، `0.9..` تعني ≥ 0.9). حتى 20 مرشح درجة لكل طلب. `evals --scores-full` يرجع كائن النقاط الكامل بدلاً من الملخص. لقراءة **جلسة واحدة من البداية إلى النهاية**، ادمج مسار الحدث مع تقييمه: + +```bash +agenteye --json events --session-id run-001 --all --limit 1000 | jq '.events[] | {ts, event_type}' +agenteye --json evals --session-id run-001 # نقاطها + حالتها +``` + +### الإدارة (مراقبة الأذونات) — `keys` · `users` · `settings` · `alerts` · `incidents` + +**`keys`** — مفاتيح API. يتم إنشاء السر محليًا وإرساله إلى الخادم (الذي يحفظ فقط التجزئة) و**يُعرض مرة واحدة** على الإنشاء/إعادة التوليد — احسبه بعد ذلك. مع `--json` يظهر فقط في حقل `key`. مرجع حسب **الاسم**. + +```bash +agenteye keys list # المفاتيح النشطة أولاً، ثم المسحوبة +agenteye keys show ci-bot +agenteye keys create ci-bot --add events:read.add # نطاق لما تحتاجه؛ يطبع السر مرة واحدة +agenteye keys create ops --permission-set standard --remove queries:run # البذرة من قيمة محددة مسبقًا، ثم التقص +agenteye keys update ci-bot --add evaluations:read --yes +agenteye keys regenerate ci-bot --yes # دوّر السر (القديم يتوقف عن العمل) +agenteye keys disable ci-bot --yes # اسحب +``` + +تعمل الأذونات مثل `(permission-set ∪ --add) − --remove`. الرموز هي `slug:action` (على سبيل المثال `events:read`) أو `slug:action.action` لتوسيع عدة على مورد واحد (`events:read.add` → `events:read` و `events:add`). الإعدادات المسبقة: `read-only` و `standard` و `admin`. لا يمكن منح أذونات بشرية فقط (`keys:update`) إلى مفتاح. + +**`users`** — أعضاء المنظمة، مرجع حسب **البريد الإلكتروني** (يُقبل معرف UUID أيضًا). + +```bash +agenteye users list [--active-only] +agenteye users show dev@corp.com +agenteye users create dev@corp.com --permission-set standard +agenteye users update dev@corp.com --add alerts:write --remove queries:delete # يتنبأ ويؤكد +agenteye users disable dev@corp.com --yes # يحتوي على حراس محمية/ذاتية +agenteye users enable dev@corp.com +``` + +**`settings`** — سجل ثابت (تقرأ وتغيير المفاتيح الموجودة؛ لا يمكنك إنشاء مفاتيح جديدة). + +```bash +agenteye settings list # مفتاح · قيمة · نوع · محدّث (أسرار مقنعة) +agenteye settings schema # ما يقبله كل مفتاح (النوع · النطاق · الوصف) +agenteye settings set session_ttl_secs --value 86400 --yes +``` + +**`alerts`** — تعريفات التنبيهات، مرجع حسب **الاسم**. `create` يأخذ NAME موضعي بالإضافة إلى أعلام أو نص جسم طلب JSON كامل عبر `--file`. + +```bash +agenteye alerts list +agenteye alerts show high-errors +agenteye alerts create high-errors --file alert.json # NAME مطلوب (موضعي) +agenteye alerts update high-errors --severity critical --yes +agenteye alerts test high-errors --yes # أرسل إخطار اختبار +agenteye alerts delete high-errors --yes +``` + +**`incidents`** — حوادث التنبيهات، مرجع حسب معرّف (قبول معرفات قصيرة). `show` يطبع سجل النشاط الكامل — اقرأه قبل التصرف. + +```bash +agenteye incidents list --state firing # أيضًا: acknowledged و resolved +agenteye incidents count +agenteye incidents show +agenteye incidents ack +agenteye incidents assign you@corp.com # يجب أن يكون المكلّف مشغلاً +agenteye incidents resolve --yes +agenteye incidents open --alert-id --severity critical # افتح واحدة يدويًا ضد تنبيه +agenteye incidents comment-add "root cause: upstream 5xx" +agenteye incidents comment-list ; agenteye incidents comment-delete +agenteye incidents subscribe ; agenteye incidents unsubscribe ; agenteye incidents subscribers +``` + +### التحليلات والمساعد — `query` · `agent` + +**`query`** — SQL ClickHouse محفوظ بالإضافة إلى عداء ad-hoc. يتم الرجوع للاستعلامات المحفوظة حسب **الاسم**؛ يتم التحقق من SQL من جانب الخادم (SELECT/WITH فقط، انتهاء مهلة البيان، حد الصف). + +```bash +agenteye query schema [TABLE] # تخطيط العمود لعروض التحليلات +agenteye query run --sql "select count(*) from analytics.events" +agenteye query run errs --arg prod --limit 100 # قم بتشغيل استعلام محفوظ + موضعي $1 +agenteye query list ; agenteye query show errs +agenteye query create errs --sql @errs.sql --description "errored events (24h)" +agenteye query update errs --sql @errs.sql --yes ; agenteye query delete errs --yes +``` + +**`agent`** — مساعد لوحة المعلومات المدمج (نفس المحلل المتاح للقراءة فقط الذي يمكنك الدردشة معه في لوحة المعلومات). يتم الرجوع للدردشات بواسطة معرّف دردشة قصير (قرار البادئة). + +```bash +agenteye agent health # هل المساعد قيد الإعدادات/قابل للوصول +agenteye agent models # الطرز التي يمكنك تمريرها إلى --model (الافتراضي معلم) +agenteye agent ask "which agents errored most in the last day?" # يبدأ دردشة؛ يطبع معرف قصير +agenteye agent ask --chat "and which tools did they call?" # متابعة تلك الدردشة +agenteye agent chats ; agenteye agent show +agenteye agent rename --title "error triage" ; agenteye agent delete +``` + +--- + +## رموز الخروج + +| الرمز | المعنى | +|---|---| +| 0 | نجاح | +| 1 | خطأ غير متوقع (على سبيل المثال لوحة المعلومات أرجعت 5xx) | +| 2 | خطأ الاستخدام (وسائط غير صحيحة، أمر/علم مجهول، تصادم الأسماء) | +| 3 | لا يمكن الوصول إلى لوحة المعلومات | +| 4 | غير مسجل الدخول أو انتهت صلاحية الجلسة؛ قم بتشغيل `agenteye login` | +| 5 | مصادق عليه، لكن حسابك يفتقد الأذونات المطلوبة (رسالة الاسم) | +| 6 | المورد المطلوب لم يتم العثور عليه (على سبيل المثال معرف جلسة أو حادثة مجهولة) | + +هذه تجعل أداة سطر الأوامر آمنة للنصوص البرمجية: يمكن للوكيل الترميز أن ينقسم على `4` لمطالبتك بإعادة المصادقة، أو `5` لسطح الأذونات المفقودة. انظر [CLI recipes for agents](/ar/agenteye/cli-recipes) لأنماط معالجة رموز الخروج وأشكال إخراج JSON. + +--- + +## انظر أيضا + +- **[CLI recipes for agents](/ar/agenteye/cli-recipes)** — أنماط استعلام copy-paste و `jq` one-liners و `--fields` الإسقاطات ومعالجة رموز الخروج وأشكال إخراج JSON، مكتوبة لوكلاء الترميز الذين يقودون أداة سطر الأوامر. +- **[AgentEye CLI skill](/ar/agenteye/cli-skill)** — حزم أداة سطر الأوامر هذه كـ Claude Code / Codex *skill* قابل للتثبيت بحيث يقود وكيل ترميز AgentEye من طلبات اللغة الطبيعية. +- **[API Keys](/ar/agenteye/api-keys)** — نموذج الأذونات خلف `keys create --add …`. +- **[AI Assistant](/ar/agenteye/assistant)** — تفعيل المساعد الذي يتحدث إليه `agent ask`. \ No newline at end of file diff --git a/docs/ar/agenteye/collector-installation.mdx b/docs/ar/agenteye/collector-installation.mdx new file mode 100644 index 00000000..bfed8ffd --- /dev/null +++ b/docs/ar/agenteye/collector-installation.mdx @@ -0,0 +1,401 @@ +--- +title: "تثبيت Collector" +description: "توثيق تثبيت AgentEye Collector." +--- + + +يضمن خادم `agenteye-collector` أن تصل بيانات المراقبة (telemetry) لوكلائك إلى AgentEye دون أن يعطل تطبيقك أبداً. يكتب الكود الخاص بك الأحداث إلى دليل محلي ثم ينتقل; يتولى المجمّع المسؤولية من هناك، ويرفع كل ملف خلال ملي ثوان ويبقى صامداً في وجه إعادة التشغيل والانقطاعات الشبكية والأخطاء العابرة في الخادم. تُعاد محاولات الرفع الفاشلة مع تأخير بتراجع أسي (exponential backoff)، وكنس دوري للاسترجاع يعيد قائمة أي شيء تُرك خلفه عند تعطل أو نشر. والنتيجة هي توصيل متين وتجاهل وانطلق (fire-and-forget): يواصل الوكلاء الخاص بك العمل بسرعة كاملة بينما يضمن المجمّع عدم فقدان أي أحداث أثناء النقل. + +من الناحية الميكانيكية، المجمّع هو خادم خفيف الوزن يراقب `$AGENTEYE_HOME/events/` (الافتراضي: `~/.agenteye/events/`) بحثاً عن ملفات `.jsonl` مكتوبة بواسطة Python SDK ويرفعها إلى خادم AgentEye. + +> **تمت إعادة التسمية:** أصبح أمر المجمّع الآن **`agenteye-collector`** (كان يُسمى سابقاً `agenteye`). اسم `agenteye` الأقصر يعود الآن إلى AgentEye CLI. إذا كنت تقوم بترقية تثبيت موجود، انظر [enterprise-docs/collector-migration.md](/ar/agenteye/collector-migration). + +--- + +## المتطلبات الأساسية + +- `AGENTEYE_TOKEN` الخاص بك: رمز الوصول الشخصي لـ GitHub الذي تُنشئه بنفسك (انظر [enterprise-docs/github-token.md](/ar/agenteye/github-token)) +- عنوان URL للخادم ومفتاح API للمجمّع (انظر [enterprise-docs/api-keys.md](/ar/agenteye/api-keys)) + +--- + +## الخيار أ: الملف الثنائي (موصى به) + +ملفات ثنائية ثابتة مجهزة مسبقاً متاحة لـ Linux و macOS و Windows (x86_64 و arm64). حمّل الملف الثنائي لنظامك مباشرة من مستودع `agenteye-enterprise/releases` تحت أحدث علامة إصدار `collector/v`. + +أسماء الأعمال المتاحة: + +| المنصة | الأعمال | +|---|---| +| Linux x86_64 | `agenteye-collector-linux-x86_64` | +| Linux arm64 | `agenteye-collector-linux-arm64` | +| macOS x86_64 | `agenteye-collector-darwin-x86_64` | +| macOS arm64 | `agenteye-collector-darwin-arm64` | +| Windows x86_64 | `agenteye-collector-windows-x86_64.exe` | +| Windows arm64 | `agenteye-collector-windows-arm64.exe` | + +**التحميل باستخدام CLI `gh`** (استبدل الإصدار واختر أعمال منصتك): + +```bash +VERSION=0.0.1-beta.13 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "collector/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-collector-linux-x86_64' + +chmod +x agenteye-collector-linux-x86_64 +sudo mv agenteye-collector-linux-x86_64 /usr/local/bin/agenteye-collector +``` + +**أو باستخدام `curl`:** + +```bash +VERSION=0.0.1-beta.13 +ARTIFACT=agenteye-collector-linux-x86_64 +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + -L "https://github.com/agenteye-enterprise/releases/releases/download/collector%2Fv${VERSION}/${ARTIFACT}" \ + -o agenteye-collector +chmod +x agenteye-collector +sudo mv agenteye-collector /usr/local/bin/agenteye-collector +``` + +--- + +## الخيار ب: Docker + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +docker pull ghcr.io/agenteye-enterprise/collector:beta-latest +``` + +> تنشر إصدارات بيتا الحالية العلامة العائمة `:beta-latest`؛ يتم تعيين `:latest` فقط للإصدارات المستقرة. للنشرات القابلة للتكرار، فضّل علامة إصدار محددة مثل `:v0.0.1-beta.13`. + +**التشغيل:** + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-collector \ + -e AGENTEYE_URL=https://ingest.example.com/events \ + -e AGENTEYE_KEY="$AGENTEYE_KEY" \ + -e AGENTEYE_HOME=/data \ + -v "$HOME/.agenteye:/data" \ + ghcr.io/agenteye-enterprise/collector:beta-latest \ + start +``` + +تعمل الصورة الرسمية كمستخدم غير الجذر، لذا اضبط `AGENTEYE_HOME` بشكل صريح وجهز مجلد الانتظار المضيف له. يشاركك وصل المجلد نفس دليل `~/.agenteye/` الذي يكتب إليه Python SDK على المضيف. إذا كنت قد ضبطت `AGENTEYE_HOME` في مكان آخر على المضيف، جهز ذلك الدليل بدلاً من `$HOME/.agenteye`. + +--- + +## الإعدادات + +يمكن تعيين جميع الخيارات بثلاث طرق (من الأعلى أولويةً أولاً): + +1. علم سطر الأوامر: `agenteye-collector start --url https://...` +2. متغير البيئة: `AGENTEYE_URL=https://...` +3. ملف الإعدادات: `~/.agenteye/config.json` + +### الخيارات المطلوبة + +| الخيار | علم CLI | متغير البيئة | مفتاح config.json | +|---|---|---|---| +| عنوان URL للواجهة الخلفية | `--url ` | `AGENTEYE_URL` | `"url"` | +| مفتاح API | `--key ` | `AGENTEYE_KEY` | `"key"` | + +### الخيارات الاختيارية (مع الافتراضيات) + +| الخيار | علم CLI | متغير البيئة | مفتاح config.json | الافتراضي | +|---|---|---|---|---| +| الحد الأقصى للرفع المتزامن | `--max-concurrent-uploads ` | `AGENTEYE_MAX_CONCURRENT_UPLOADS` | `"max_concurrent_uploads"` | `64` | +| فترة الكنس (ث) | `--sweep-interval ` | `AGENTEYE_SWEEP_INTERVAL` | `"sweep_interval_secs"` | `60` | +| الحد الأدنى لعمر الملف في الكنس (ث) | `--sweep-min-age ` | `AGENTEYE_SWEEP_MIN_AGE` | `"sweep_min_age_secs"` | `120` | +| الحد الأقصى للملفات لكل كنس | `--sweep-max-files ` | `AGENTEYE_SWEEP_MAX_FILES` | `"sweep_max_files"` | `64` | +| الحد الأقصى لمحاولات الرفع | `--max-retries ` | `AGENTEYE_MAX_RETRIES` | `"max_retries"` | `5` | +| تأخير أساس إعادة المحاولة (مللي ث) | `--retry-base-delay ` | `AGENTEYE_RETRY_BASE_DELAY` | `"retry_base_delay_ms"` | `1000` | + +### خيارات mTLS (اختياري) + +بالنسبة للنشرات التي تتطلب TLS المتبادل (mTLS)، يمكن للمجمّع تقديم شهادة عميل أثناء مصافحة TLS. عندما لا يتم تعيين هذه الخيارات، يستخدم المجمّع HTTPS القياسي. + +| الخيار | علم CLI | متغير البيئة | مفتاح config.json | +|---|---|---|---| +| شهادة العميل (PEM) | `--tls-cert ` | `AGENTEYE_TLS_CERT` | `"tls_cert"` | +| المفتاح الخاص للعميل (PEM) | `--tls-key ` | `AGENTEYE_TLS_KEY` | `"tls_key"` | +| شهادة CA مخصصة (PEM) | `--tls-ca ` | `AGENTEYE_TLS_CA` | `"tls_ca"` | + +يجب تعيين `--tls-cert` و `--tls-key` معاً. يجب أن تكون الملفات بصيغة PEM. + +`--tls-ca` مستقل وضروري فقط عندما يقدم خادم AgentEye شهادة TLS لم تصدرها جهة اعتماد موثوقة علناً (على سبيل المثال، موقّعة ذاتياً بواسطة مُصدر `cert-manager` داخل المجموعة عندما لا يكون لديك نطاق DNS حقيقي). يضيف المجمّع الشهادة المرفوعة كنقطة ثقة إضافية؛ تبقى الجذور العامة الموثوقة موثوقة، لذا لا تتأثر النشرات الموجودة. قد يحتوي الملف على شهادة PEM واحدة أو سلسلة كاملة (كتل PEM متعددة متسلسلة). + +**تشغيل المجمّع كـ sidecar في حاوية تطبيقك؟** انظر [enterprise-docs/single-pod-deployment.md](/ar/agenteye/single-pod-deployment) لنمط EKS من النهاية إلى النهاية: حزمة mTLS يتم تسليمها عبر AWS Secrets Manager + Secrets Store CSI Driver + IRSA، مع الدوران التلقائي. + +عند التشغيل في Kubernetes مع نمط تسليم الخدمة السرية، جهز الخدمة السرية للشهادة كمجلد وأشر هذه المسارات إلى الملفات المجهزة: + +```yaml +# مثال: مقطع Deployment للمجمّع +volumes: + - name: mtls-certs + secret: + secretName: agenteye-collector-mtls +containers: + - name: collector + env: + - name: AGENTEYE_TLS_CERT + value: /etc/agenteye/tls/tls.crt + - name: AGENTEYE_TLS_KEY + value: /etc/agenteye/tls/tls.key + # فقط عندما لا تكون شهادة الخادم موثوقة علناً (على سبيل المثال، جهة اعتماد + # موقّعة ذاتياً داخل المجموعة). عادة ما تحمل نفس الخدمة السرية ca.crt إلى جانب + # tls.crt/tls.key. + - name: AGENTEYE_TLS_CA + value: /etc/agenteye/tls/ca.crt + volumeMounts: + - name: mtls-certs + mountPath: /etc/agenteye/tls + readOnly: true +``` + +### مثال `~/.agenteye/config.json` + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "max_concurrent_uploads": 16, + "sweep_interval_secs": 30 +} +``` + +مع mTLS: + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "tls_cert": "/etc/agenteye/tls/tls.crt", + "tls_key": "/etc/agenteye/tls/tls.key" +} +``` + +مع mTLS بالإضافة إلى جهة اعتماد مخصصة (خادم AgentEye موقّع ذاتياً): + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "tls_cert": "/etc/agenteye/tls/tls.crt", + "tls_key": "/etc/agenteye/tls/tls.key", + "tls_ca": "/etc/agenteye/tls/ca.crt" +} +``` + +إذا تم ضبط `AGENTEYE_HOME`، يتم استخدام ذلك الدليل بدلاً من `~/.agenteye`. + +--- + +## الإعداد للمرة الأولى + +بعد التثبيت، جهز المجمّع برقم خادم عنوان URL ومفتاح API: + +```bash +mkdir -p ~/.agenteye +cat > ~/.agenteye/config.json <<'EOF' +{ + "url": "https://ingest.example.com/events", + "key": "YOUR_COLLECTOR_KEY" +} +EOF +``` + +> استخدم `https` لأي نشر يعبر شبكة غير موثوقة بحيث لا يتم إرسال الأحداث بنص عادي. نموذج النص العادي `http://your-server-host:8080/events` مناسب فقط للاختبار المحلي تماماً ضد خادم على نفس المضيف. + +**اختبر الاتصال** (تطبيق الامتصاص الواحد، الخروج بعد استنزاف الأحداث المعلقة): + +```bash +agenteye-collector flush +``` + +يقرّر `flush` تقدمه إلى stdout. عندما يكون مجلد الانتظار فارغاً يطبع `No pending files.` والخروج `0`. خلاف ذلك يطبع سطراً واحداً لكل ملف (`[UPLOADED] ` أو `[FAILED] ()`), متبوعاً بملخص `Done: / uploaded, failed.`. هذا يجعل `flush` فحصاً مفيداً للاستخدام الواحد بأن عنوان URL ومفتاح API وإعدادات TLS الخاصة بك صحيحة قبل بدء الخادم. + +--- + +## التشغيل كخادم + +### مباشر + +```bash +agenteye-collector start +``` + +### الحاوية / Docker + +عندما يشاركك المجمّع والتطبيق حاوية، شغلهما تحت مراقب العملية. الخيار الأبسط هو `supervisord`؛ يأتي في كل توزيع رئيسي، ويعيد تشغيل العمليات المتعطلة، ويعيد توجيه الإشارات، وينتظر الإغلاق البطيء. + +**`Dockerfile`:** + +```Dockerfile +FROM python:3.11-slim + +RUN apt-get update && apt-get install -y --no-install-recommends supervisor \ + && rm -rf /var/lib/apt/lists/* + +# اسحب ملف agenteye-collector الثنائي من الصورة الرسمية. +# ثبّت علامة محددة (:beta-latest للبيتا الحالية، أو علامة :v); +# :latest يتم نشره فقط للإصدارات المستقرة. +COPY --from=ghcr.io/agenteye-enterprise/collector:beta-latest \ + /usr/local/bin/agenteye-collector /usr/local/bin/agenteye-collector + +COPY supervisord.conf /etc/supervisor/conf.d/agenteye.conf +COPY my_agent.py /app/my_agent.py + +CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"] +``` + +**`supervisord.conf`:** + +```ini +[supervisord] +nodaemon=true +user=root + +[program:agenteye-collector] +command=/usr/local/bin/agenteye-collector start +autorestart=true +stopwaitsecs=30 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:app] +command=python /app/my_agent.py +autorestart=unexpected +stopwaitsecs=30 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +``` + +لماذا هذه الإعدادات: + +- `autorestart=true` على agenteye-collector: أعد التشغيل عند أي خروج (تعطل، ذعر، OOM). +- `autorestart=unexpected` على التطبيق: أعد التشغيل فقط عند خروج غير صفري، بحيث لا يحلقة وكيل الاستخدام الواحد الذي يخرج 0. +- `stopwaitsecs=30`: يعطي المجمّع مجالاً لاستنزاف الرفع المعلقة على SIGTERM قبل أن يصعد supervisord إلى SIGKILL. +- `stdout_logfile=/dev/stdout`, `*_maxbytes=0`: بث إخراج كلا البرنامجين إلى حاوية stdout؛ لا توجد ملفات سجل داخل الحاوية. + +مرّر `AGENTEYE_URL` / `AGENTEYE_KEY` (وأي متغيرات بيئة TLS) على `docker run -e` كما هو الحال من قبل؛ يرث supervisord البيئة. + +> **حاويات منفصلة؟** إذا قمت بتشغيل المجمّع كحاوية منفصلة (خدمة Docker Compose, Kubernetes sidecar, إلخ.)، لا تستخدم supervisord؛ سياسة إعادة تشغيل الحاوية runtime تقوم بهذه الوظيفة بالفعل. انظر [enterprise-docs/single-pod-deployment.md](/ar/agenteye/single-pod-deployment) لنمط EKS sidecar. + +**مسبار حيوية Kubernetes** (ينطبق سواء تم تشغيل المجمّع وحده أو تحت supervisord): + +```yaml +livenessProbe: + exec: + command: ["agenteye-collector", "health"] + initialDelaySeconds: 10 + periodSeconds: 30 +``` + +يكتب الخادم الجاري نبضة قلب إلى `$AGENTEYE_HOME/health.json` كل 30 ثانية. يقرأ `agenteye-collector health` ذلك الملف والخروج `0` (صحي) فقط عندما تكون نبضة القلب طازجة وتعمل مهام الرفع بشكل طبيعي؛ يخرج `1` (غير صحي) عندما تكون نبضة القلب أقدم من 90 ثانية (على سبيل المثال، توقف الخادم) أو بينما يتم إعادة تشغيل المراقب والكنس بعد خروج غير متوقع. يتم كتابة نبضة القلب فقط بواسطة `start`, لذا قم بتشغيل المسبار ضد الخادم طويل الأمد وليس الأمر `flush` الواحد. + +### systemd (Linux، موصى به للإنتاج) + +```ini +# /etc/systemd/system/agenteye-collector.service +[Unit] +Description=AgentEye Collector +After=network.target + +[Service] +ExecStart=/usr/local/bin/agenteye-collector start +Restart=on-failure +RestartSec=5 +EnvironmentFile=/etc/agenteye/env + +[Install] +WantedBy=multi-user.target +``` + +أنشئ `/etc/agenteye/env`: + +``` +AGENTEYE_URL=https://ingest.example.com/events +AGENTEYE_KEY=YOUR_COLLECTOR_KEY +``` + +```bash +sudo systemctl daemon-reload +sudo systemctl enable --now agenteye-collector +sudo systemctl status agenteye-collector +``` + +### launchd (macOS) + +```xml + + + + + + Label + ai.befailproof.agenteye-collector + ProgramArguments + + /usr/local/bin/agenteye-collector + start + + EnvironmentVariables + + AGENTEYE_URL + https://ingest.example.com/events + AGENTEYE_KEY + YOUR_COLLECTOR_KEY + + RunAtLoad + + KeepAlive + + + +``` + +```bash +launchctl load ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +``` + +--- + +## ترقية المجمّع + +لا يحدّث المجمّع نفسه. للترقية: + +- **الملف الثنائي:** حمّل أعمال `agenteye-collector--` الجديدة من أحدث إصدار `collector/v` (انظر [الخيار أ](#option-a-binary-recommended))، استبدل `/usr/local/bin/agenteye-collector`، ثم أعد تشغيل الخدمة (`sudo systemctl restart agenteye-collector`, إعادة `launchctl load`، أو إعادة تشغيل مراقبك). +- **Docker:** `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (أو علامة `:v` محددة؛ `:latest` موجودة فقط للإصدارات المستقرة) وأعد إنشاء الحاوية. + +`AGENTEYE_TOKEN` مطلوب لتحميل الملفات الثنائية/الصور الجديدة من مستودع الإصدارات الخاص، لكنه **ليس** ضروري بواسطة الخادم الجاري. + +--- + +## الأوامر الفرعية + +| الأمر | الوصف | +|---|---| +| `agenteye-collector start` | ابدأ الخادم طويل الأمد. عند بدء التشغيل، يقوم بتطبيق امتصاص أي أحداث متبقية من التشغيل السابق، ثم يراقب الملفات الجديدة ويرفعها. يتم إعادة تشغيل المراقب والكنس تلقائياً عند خروج غير متوقع، وتتم كتابة نبضة قلب إلى `health.json` كل 30 ثانية. | +| `agenteye-collector flush` | استخدام واحد: رفع جميع الملفات المعلقة والخروج. يطبع `No pending files.` عندما يكون مجلد الانتظار فارغاً, خلاف ذلك لكل ملف `[UPLOADED]`/`[FAILED]` سجل وملخص `Done: / uploaded, failed.`. | +| `agenteye-collector health` | اقرأ نبضة القلب `health.json` للخادم. الخروج `0` عندما يكون طازجاً وصحياً؛ الخروج `1` عندما تكون نبضة القلب قديمة (أقدم من 90 ثانية) أو تعاد تشغيل المهام. | + +--- + +## تخطيط الدليل + +``` +~/.agenteye/ +├── config.json <- ملف الإعدادات الاختياري +├── events/ <- ملفات .jsonl مكتوبة بواسطة SDK، يتم التقاطها بواسطة المجمّع +└── failed/ <- ملفات فشلت جميع محاولات الرفع +``` + +الملفات في `failed/` لا تُعاد محاولة تلقائياً. لإعادة قائمة متابعتها يدويّاً، انقل الملفات مرة أخرى إلى `events/` وشغّل `agenteye-collector flush`. \ No newline at end of file diff --git a/docs/ar/agenteye/collector-migration.mdx b/docs/ar/agenteye/collector-migration.mdx new file mode 100644 index 00000000..7a299cf2 --- /dev/null +++ b/docs/ar/agenteye/collector-migration.mdx @@ -0,0 +1,168 @@ +--- +title: "الهجرة إلى `agenteye-collector`" +description: "وثائق AgentEye حول الهجرة إلى `agenteye-collector`." +--- + + +الهجرة غير مدمرة: لا تسبب أي توقف للخدمة ولا فقدان بيانات، وتحرر الاسم القصير `agenteye` ل[واجهة سطر أوامر AgentEye](/ar/agenteye/cli) بحيث يمكن لخادم جامع البيانات والواجهة أن يعملا معاً على نفس الجهاز. + +تم **إعادة تسمية ملف التنفيذ من `agenteye` إلى `agenteye-collector`**. الاسم القصير `agenteye` ينتمي الآن إلى واجهة سطر أوامر AgentEye، وهي أداة منفصلة للاستعلام عن الجلسات والأحداث والتقييمات من الطرفية. + +يرشدك هذا الدليل عبر هجرة تثبيت جامع البيانات الموجود. + +--- + +## ما الذي تغير + +| | قبل | بعد | +|---|---|---| +| الأمر / ملف التنفيذ | `agenteye` | `agenteye-collector` | +| مسار التثبيت الافتراضي | `/usr/local/bin/agenteye` | `/usr/local/bin/agenteye-collector` | +| الأوامر الفرعية | `start`, `flush`, `health`, `update` | `start`, `flush`, `health` | +| التحديث الذاتي (`agenteye update`) | مدمج | **محذوف**: قم بتنزيل الملف الثنائي الجديد أو اسحب الصورة الجديدة | +| سكريبت التثبيت (`install.sh`) | مقدم | **محذوف**: قم بتنزيل الملف الثنائي مباشرة (انظر [تثبيت جامع البيانات](/ar/agenteye/collector-installation)) | +| `AGENTEYE_TOKEN` | مطلوب للتنزيل **و** لفحوصات التحديث في الخلفية | مطلوب فقط لتنزيل الملفات الثنائية والصور | + +الإعدادات لم تتغير: نفس `~/.agenteye/config.json`، ونفس متغيرات البيئة `AGENTEYE_URL` / `AGENTEYE_KEY` / `AGENTEYE_HOME` / TLS، ونفس سبول `~/.agenteye/events/`. **لا تحتاج إلى تحرير أي إعدادات.** + +> إذا قمت بتشغيل الملف الثنائي المعاد تسميته تحت الاسم القديم `agenteye`، فإنه لا يزال يعمل لكنه يطبع رسالة تحذير إهمال بسطر واحد على stderr تذكرك بالتبديل إلى `agenteye-collector`. + +--- + +## قبل أن تبدأ + +- **تثبيت `agenteye` الموجود يبقى قيد التشغيل**؛ لا يتعطل شيء في لحظة التحديث. قم بالهجرة بعناية، ثم أزل الملف الثنائي القديم في النهاية فقط. +- اتبع هذا الترتيب لتجنب توقف الخدمة: + 1. ثبّت الملف الثنائي الجديد `agenteye-collector` (أو اسحب الصورة الجديدة). + 2. حدّث تعريف الخدمة / مسبار الصحة / السكريبتات لاستدعاء `agenteye-collector`. + 3. أعد تحميل الخدمة وأعد تشغيلها؛ تحقق من أنها سليمة. + 4. **فقط بعد ذلك** أزل ملف الثنائي القديم `/usr/local/bin/agenteye`. + +--- + +## 1. ثبّت الملف الثنائي الجديد + +قم بتنزيل القطعة الأثرية لنظامك (`agenteye-collector-linux-x86_64`, `agenteye-collector-darwin-arm64`، وما إلى ذلك؛ انظر [تثبيت جامع البيانات → الخيار أ](/ar/agenteye/collector-installation#option-a-binary-recommended) للحصول على القائمة الكاملة) من أحدث إصدار `collector/v` وضعها في `/usr/local/bin/agenteye-collector`. مستخدمو Docker: `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (أو علامة `:v` محددة، وهي مفضلة؛ `:latest` موجودة فقط للإصدارات المستقرة). + +تحقق: + +```bash +agenteye-collector --version +``` + +--- + +## 2. حدّث نشرك + +### systemd (Linux) + +عدّل `/etc/systemd/system/agenteye-collector.service` بحيث يشير `ExecStart` إلى الملف الثنائي الجديد: + +```ini +[Service] +ExecStart=/usr/local/bin/agenteye-collector start +``` + +ثم أعد التحميل والتشغيل: + +```bash +sudo systemctl daemon-reload +sudo systemctl restart agenteye-collector +sudo systemctl status agenteye-collector +``` + +### launchd (macOS) + +> **إعادة تسمية العلامة التجارية:** إذا كان ملف plist الموجود لديك في المسار الأقدم +> `~/Library/LaunchAgents/host.exosphere.agenteye-collector.plist`، أعد تسمية +> الملف إلى `ai.befailproof.agenteye-collector.plist` وغيّر أيضاً قيمة +> `Label` داخل الملف إلى المعرّف الجديد قبل إعادة التحميل. + +في `~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist`، غيّر إدخال `ProgramArguments` الأول من `/usr/local/bin/agenteye` إلى `/usr/local/bin/agenteye-collector`، ثم أعد التحميل: + +```bash +launchctl unload ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +launchctl load ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +``` + +### supervisord + +في كتلة برنامج `supervisord` الخاصة بك، عيّن `command` إلى الملف الثنائي الجديد: + +```ini +[program:agenteye-collector] +command=/usr/local/bin/agenteye-collector start +``` + +ثم `supervisorctl reread && supervisorctl update`. + +### Docker / Kubernetes + +اسحب الصورة الجديدة (`ghcr.io/agenteye-enterprise/collector:beta-latest` أو علامة `:v` محددة، وهي مفضلة؛ `:latest` موجودة فقط للإصدارات المستقرة). نقطة الدخول في الصورة هي بالفعل `agenteye-collector`، لذا فإن نفس أمر `docker run` مع الأمر الفرعي `start` يستمر في العمل بدون أي تغيير. + +**مهم: حدّث مسابير الصحة.** إذا كنت تستخدم مسبار liveness/readiness في Kubernetes (أو أي `docker exec`) ينفذ الملف الثنائي بالاسم، غيّر الأمر إلى `agenteye-collector`: + +```yaml +livenessProbe: + exec: + command: ["agenteye-collector", "health"] +``` + +الصورة الجديدة **لا** تشحن بـ `agenteye` مستعار، لذا فإن مسبار يستدعي `agenteye` سيفشل. حدّث المسبار في نفس الإطلاق مع الصورة الجديدة. + +### Cron / السكريبتات اليدوية + +استبدل أي استدعاء `agenteye start|flush|health` بأمر `agenteye-collector start|flush|health` المطابق. **احذف أي وظائف cron لـ `agenteye update`**؛ هذا الأمر الفرعي لم يعد موجوداً (انظر [الترقيات من الآن فصاعداً](#upgrades-from-now-on)). + +--- + +## 3. أزل الملف الثنائي القديم (الأخير) + +بعد أن تعمل الخدمة على `agenteye-collector` وتُبلّغ عن صحتها: + +```bash +sudo rm /usr/local/bin/agenteye +``` + +هذا مهم خاصة إذا كنت تستخدم أيضاً واجهة سطر أوامر AgentEye، التي تثبت أمرها الخاص `agenteye`؛ ترك ملف جامع البيانات القديم في `/usr/local/bin/agenteye` سيجعل اسم `agenteye` غامضاً على `PATH` الخاص بك. + +--- + +## الترقيات من الآن فصاعداً + +جامع البيانات لم يعد يحدث نفسه. للترقية: + +- **الملف الثنائي:** قم بتنزيل القطعة الأثرية الجديدة لنظامك (على سبيل المثال `agenteye-collector-linux-x86_64`؛ انظر [تثبيت جامع البيانات → الخيار أ](/ar/agenteye/collector-installation#option-a-binary-recommended) للحصول على القائمة الكاملة)، استبدل `/usr/local/bin/agenteye-collector`، وأعد تشغيل الخدمة. +- **Docker:** `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (أو علامة `:v` محددة، وهي مفضلة؛ `:latest` موجودة فقط للإصدارات المستقرة) وأنشئ الحاوية مجدداً. + +لا تزال `AGENTEYE_TOKEN` مطلوبة للتنزيل من مستودع الإصدارات الخاص، لكن الخادم قيد التشغيل لم يعد يحتاج إليها. + +--- + +## تحقق + +```bash +agenteye-collector --version # الملف الثنائي الجديد موجود على PATH +agenteye-collector health # الخروج 0 = سليم +agenteye-collector flush # يرسل أي أحداث في الطابور ويخرج بنظافة +``` + +ثم تأكد من ظهور الأحداث الجديدة في لوحة المعلومات الخاصة بك. + +--- + +## العودة للإصدار السابق + +الهجرة غير مدمرة. إذا كنت بحاجة إلى العودة، وجّه تعريف الخدمة الخاص بك مرة أخرى إلى ملف الثنائي القديم `/usr/local/bin/agenteye` (طالما لم تزله بعد) وأعد التشغيل. سبول الأحداث والإعدادات مشتركة وغير متأثرة. + +--- + +## استكشاف الأخطاء والتحديث + +| الأعراض | السبب | الحل | +|---|---|---| +| `warning: the collector binary is now agenteye-collector …` في كل تشغيل | تستدعي الملف الثنائي تحت اسم `agenteye` القديم | استدعِ `agenteye-collector` بدلاً من ذلك؛ حدّث ملفات الخدمة والسكريبتات. | +| systemd يفشل: `.../agenteye: No such file or directory` | أزلت الملف الثنائي القديم قبل تحديث `ExecStart` | عيّن `ExecStart=/usr/local/bin/agenteye-collector start`، ثم `sudo systemctl daemon-reload`. | +| حاوية Kubernetes تدخل حلقة توقف بعد ترقية الصورة | مسبار liveness لا يزال يشغل `agenteye` | غيّر أمر المسبار إلى `["agenteye-collector", "health"]`. | +| `agenteye: command not found`، لكن `agenteye-collector` يعمل | السكريبتات/الأسماء المستعارة لا تزال تشير إلى الاسم القديم | حدّثها إلى `agenteye-collector`. | +| تشغيل `agenteye` يبدأ الواجهة وليس جامع البيانات | لديك واجهة سطر أوامر AgentEye مثبتة؛ تمتلك `agenteye` | استخدم `agenteye-collector` للخادم وأزل أي ملف جامع بيانات قديم متبقي في `/usr/local/bin/agenteye`. | \ No newline at end of file diff --git a/docs/ar/agenteye/deployment.mdx b/docs/ar/agenteye/deployment.mdx new file mode 100644 index 00000000..3ff58389 --- /dev/null +++ b/docs/ar/agenteye/deployment.mdx @@ -0,0 +1,334 @@ +--- +title: "النشر" +description: "توثيق نشر AgentEye." +--- + +يغطي هذا الدليل نشر خادم AgentEye وعرض لوحة المعلومات في الإنتاج. + +--- + +## نظرة عامة على العمارة + +``` + [ AI agent machines ] [ Your infrastructure ] + + Python SDK + | writes JSONL +----------------------+ + v +--->| PostgreSQL 15+ | + agenteye-collector --HTTP--+ | | (relational store) | + | | +----------------------+ + v | + +--------+ | +----------------------+ + | Server |<------+--->| ClickHouse 24+ | + +--------+ | | (events / analytics) | + ^ | +----------------------+ + API | | + | | +----------------------+ + +-----------+ +- - >| Redis 7+ (optional) | + | Dashboard | +----------------------+ + +-----------+ +``` + +- **Server**: خدمة HTTP بلغة Rust؛ تستقبل دفعات الأحداث، وتكتبها إلى ClickHouse، وتحافظ على الحالة العلائقية في PostgreSQL. +- **Dashboard**: تطبيق Next.js؛ يقرأ ويكتب حصراً عبر API الخادم. +- **agenteye-collector**: مُنتشر على آلات الوكيل، وليس على مضيف الخادم. +- **Postgres 15+**: مطلوب. (تم رفعه من 14 في إصدار متعدد المستأجرين؛ يستخدم مخطط العضوية في المنظمة مفتاح خارجي `ON DELETE SET NULL` بقائمة الأعمدة، وهذا يتطلب Postgres 15+. قم بترقية Postgres قبل نشر هذا الإصدار.) يخزن حالة OLTP: `api_keys`، `users`، `sessions`، `evaluation_jobs` (الطابور)، `dashboards`، `saved_queries`، `otp_codes`، بالإضافة إلى جداول متعددة المستأجرين `orgs`، `org_memberships`، `org_settings`. +- **ClickHouse 24+**: مطلوب. متجر التحليلات لكل حدث مُستقبل. المحرك: `ReplacingMergeTree`، مقسم حسب الشهر، مرتب حسب `(session_id, ts, dedup_key)`. يتصل الخادم عبر `CLICKHOUSE_URL`؛ التكوين الموزع في `deploy/base/clickhouse/` يشحن إعدادات محسنة للأداء لعقدة واحدة. **متطلب متعدد المستأجرين:** يفعّل التكوين الموزع إدارة وصول SQL + `users_without_row_policies_can_read_rows=false` حتى يتمكن الخادم من إنشاء مستخدم ClickHouse واحد للقراءة فقط + سياسة صف واحدة لكل منظمة (حدود العزل المفروضة بواسطة المحرك لمحرر SQL والوكيل الذكي). إذا كنت توفر إعدادات ClickHouse الخاصة بك، فانقل هذه الإعدادات (انظر `deploy/base/clickhouse/configmap.yaml`). +- **Redis 7+**: *اختياري* ذاكرة تخزين مؤقتة مشتركة + خلفية تحديد السعر. يتصل كل من الخادم ولوحة المعلومات عبر `REDIS_URL`. إذا كانت غير موجودة، كلاهما ينحط بأناقة إلى مسارات Postgres فقط. انظر **Redis (ذاكرة تخزين مؤقتة اختيارية)** أدناه. + +--- + +## الخادم + +### استحضار الصورة + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +docker pull ghcr.io/agenteye-enterprise/server:beta-latest +``` + +> الإصدارات الحالية تنشر تحت `beta-latest`؛ `latest` يُسند فقط للإصدارات المستقرة. للإنتاج، ثبّت وسم `:v` محدد؛ انظر [علامات الصور المتاحة](#available-image-tags). + +### متغيرات البيئة + +| المتغير | مطلوب | الافتراضي | الوصف | +|---|---|---|---| +| `DATABASE_URL` | نعم | لا شيء | Postgres DSN. سلسلة اتصال libpq قياسية بصيغة `postgres://`. تدعم `?sslmode=require` ومعاملات libpq الأخرى. يجب ألا تحتوي كلمة المرور على `/`، `+`، أو `=`؛ استخدم `openssl rand -hex` لإنشاء كلمات مرور آمنة للـ URL. | +| `ADMIN_KEY` | لا | لا شيء | مفتاح API للإدارة التمهيدي. تم إدراجه مع جميع الأذونات عند كل بدء تشغيل. قم بالتدوير بتغيير القيمة وإعادة التشغيل. | +| `LISTEN_ADDR` | لا | `0.0.0.0:8080` | عنوان TCP للربط | +| `MAX_BODY_BYTES` | لا | `134217728` (128 MB) | حد أقصى لحجم جسم الطلب | +| `ADMIN_EMAIL` | لا | لا شيء | بريد المسؤول التمهيدي. تم إدراجه مع جميع الأذونات عند كل بدء تشغيل وتم وضع علامة محمية: لا يمكن تعطيله أو تعديل أذوناته عبر لوحة المعلومات/API. لتدوير المسؤول التمهيدي، غيّر `ADMIN_EMAIL` وأعد التشغيل؛ يتم إدراج البريد الجديد كمحمي، والبريد السابق يحتفظ بحمايته حتى يتم حذفها يدويًا في قاعدة البيانات. | +| `ALLOWED_EMAILS` | لا | لا شيء (الكل محظور) | قائمة مفصولة بفواصل من رسائل البريد الإلكتروني المسموحة لإنشاء المستخدمين والدخول. يدعم عناوين دقيقة (`user@example.com`) والنطاقات الموسعة (`*@example.com`). إذا لم يتم التعيين، لا يمكن لأي مستخدمين الإنشاء أو تسجيل الدخول. **بذرة الإقلاع الأولى فقط**: تزرع قائمة منع النطاق الافتراضي للمنظمة عند الإقلاع الأول؛ بعد ذلك تكون صفحة [`//settings`](#operational-settings) لكل منظمة هي مصدر الحقيقة وتغيير متغير env هذا لا يترتب عليه تأثير. | +| `SMTP_HOST` | لا | لا شيء | اسم مضيف خادم SMTP لإرسال رسائل بريد OTP. إذا لم يتم التعيين، يتم تسجيل رموز OTP إلى stdout بدلاً من ذلك. | +| `SMTP_PORT` | لا | `587` | منفذ خادم SMTP | +| `SMTP_USERNAME` | لا | لا شيء | اسم المستخدم للمصادقة على SMTP | +| `SMTP_PASSWORD` | لا | لا شيء | كلمة مرور المصادقة على SMTP | +| `SMTP_FROM` | لا | لا شيء | عنوان البريد الإلكتروني للمرسل لرسائل OTP | +| `SMTP_TLS` | لا | STARTTLS | يُستخدم STARTTLS إلا إذا قمت بإيقافه صراحة: `false` أو `0` يرسل نص عادي (بدون TLS)؛ أي قيمة أخرى — بما في ذلك الإيقاف — تفعّل STARTTLS. | +| `DASHBOARD_URL` | لا | افتراضي مدمج | أصل لوحة المعلومات المستخدم لإنشاء كل من رابط الرسالة السحري للـ OTP وروابط الحوادث السحرية في إخطارات التنبيهات. إذا لم يتم التعيين، يعود إلى افتراضي مدمج (وللـ OTP فقط، إلى أصل مشتق من لوحة المعلومات أولاً). عيّن هذا للإعدادات المقسمة بين النطاقات بحيث تشير كل من رسائل البريد وروابط Slack/الحادث إلى لوحة المعلومات الخاصة بك. انظر **URL رابط البريد السحري** أدناه؛ معظم المشغلين لا يحتاجون إلى تعيين هذا. | +| `SESSION_TTL_SECS` | لا | `86400` (24 h) | مدة جلسة لوحة المعلومات بالثواني. **بذرة الإقلاع الأولى فقط**: عدّل لكل منظمة عبر [`//settings`](#operational-settings) بعد النشر الأول. | +| `OTP_TTL_SECS` | لا | `600` (10 min) | فترة صلاحية رمز OTP بالثواني. **بذرة الإقلاع الأولى فقط**: عدّل لكل منظمة عبر [`//settings`](#operational-settings) بعد النشر الأول. | +| `REDIS_URL` | لا | لا شيء | خلفية اختيارية لذاكرة التخزين المؤقتة المشتركة + تحديد السعر، مثل `redis://redis:6379/0`. عند التعيين، يخزن الخادم عمليات البحث عن المفاتيح المصادقة، و`/models` الكلي لوحة المعلومات، قائمة الجلسات، وجوانب قائمة env؛ كما يحرك حد معدل طلب OTP من PostgreSQL COUNT وإلى Redis INCR. إذا لم يتم التعيين أو غير قابل للوصول، يعمل الخادم بدون الذاكرة المؤقتة (ينخفض حد OTP إلى Postgres، كل نداء ذاكرة تخزين مؤقتة أخرى ينخفض إلى مصدر الحقيقة). انظر **Redis (ذاكرة تخزين مؤقتة اختيارية)** أدناه. | +| `CLICKHOUSE_URL` | **نعم** | لا شيء | URL الأساسي لمثيل ClickHouse، مثل `http://clickhouse:8123`. يطبق الخادم مخطط الأحداث الخاص به على هذه قاعدة البيانات عند كل بدء تشغيل ويرفض الإقلاع إذا لم يتمكن من الوصول إلى ClickHouse. انظر **ClickHouse (متجر التحليلات المطلوب)** أدناه. | +| `CLICKHOUSE_DATABASE` | لا | `agenteye` | اسم قاعدة بيانات ClickHouse (المخطط). ينشئه الخادم عند بدء التشغيل إذا لم يكن موجوداً. | +| `ORG_CH_SECRET` | لا (أحادي المستأجر) / **نعم (متعدد المنظمات)** | افتراضي تطوير | مفتاح HMAC الذي يُستخرج منه كلمة مرور ClickHouse الفريدة لكل منظمة لكل مستأجر. يقوم محرر SQL والوكيل الذكي `run_query` بالتنفيذ كمستخدم ClickHouse الخاص بالمنظمة وقراءة فقط، حيث تفرض سياسة الصف عزل المستأجرين في المحرك. تُقلع عمليات النشر أحادية المستأجر بشكل جيد على الافتراضي المدمج للتطوير؛ **قبل حالة الحصول على منظمة ثانية يجب عليك تعيين قيمة قوية وثابتة**، لأن CLI `agenteye-orgctl org create` يرفض التشغيل على الافتراضي المدمج للتطوير. يؤدي تدويره إلى دون نسب كل مستخدم ClickHouse للمنظمة حتى إعادة التشغيل التالية تعيدها (تشفي المصالحة في وقت الإقلاع هذا تلقائياً). احفظه سراً وبدون تغيير عبر النسخ. يتم الحصول على المنظمات نفسها من قِبل المشغل فقط؛ انظر **المنظمات (تعدد المستأجرين)** أدناه. | +| `DEFAULT_ORG_NAME` | لا | `Default` | اسم العرض المزروع للمنظمة الافتراضية المدمجة. **بذرة الإقلاع الأولى فقط**، وفقط أثناء احتفاظ المنظمة بهويتها العامة المنقولة حديثاً، يتم تطبيقها عند بدء التشغيل، ثم تُتجاهل. بمجرد إعادة تسمية المنظمة (`agenteye-orgctl org rename`) تصبح إعادة التسمية موثوقة وهذا متغير env لا يترتب عليه تأثير آخر. | +| `DEFAULT_ORG_SLUG` | لا | `default` | عنوان URL للمنظمة الافتراضية المدمجة، مسار لوحة المعلومات التي تعيش فيه (`//…`). نفس بذرة الإقلاع الأولى فقط / بكر فقط الدلالات كما `DEFAULT_ORG_NAME`. يجب أن يكون 1-40 أبجديات صغيرة مع شرطات داخلية واحدة وليس [كلمة محفوظة](#organizations-multi-tenancy)؛ يتم تجاهل القيمة غير الصالحة (تحتفظ المنظمة بـ `default`). يسمح لتثبيت أحادي المستأجر بالعرض كـ `/acme` بدلاً من `/default` بدون أي خطوة CLI بعد النشر. | +| `RUST_LOG` | لا | `info` | طراز السجلات (`debug`, `warn`, `error`, `agenteye_server=trace`) | +| `EVALUATOR_ENDPOINT` | لا | لا شيء | URL الأساسي لخدمة المُقيّم الخاصة بك (مثل `http://evaluator:9000`). عند الإيقاف، يكون خط أنابيب التقييم بالكامل بدون عملية؛ لا يتم كتابة صفوف الطابور، لا يتم تشغيل العمال. انظر [أداة التقييم](/ar/agenteye/evaluation-suite). | +| `EVALUATOR_TOKEN` | لا | لا شيء | يُرسل كـ `Authorization: Bearer ` إلى المُقيّم. **يجب أن يساوي نفس القيمة التي يتم تكوين خدمة المُقيّم بها.** اختياري فقط إذا تم تكوين المُقيّم بدون رمز. | +| `EVALUATOR_WORKERS` | لا | `2` | التزامن: عدد مهام العمال لكل مثيل خادم تُرسل التقييمات. آمن للتشغيل عبر عدة خوادم مقسمة بشكل أفقي. | +| `EVALUATOR_CLAIM_BATCH` | لا | `4` | الحد الأقصى لعدد التقييمات التي يطالب بها عامل واحد لكل علامة. يتم إرسال الدفعات **بشكل متزامن**، لذا فإن التزامن الكلي على نقطة نهاية المُقيّم الخاصة بك هو `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH`. | +| `EVALUATOR_POLL_IDLE_SECS` | لا | `2` | المدة التي ينام فيها العامل بين محاولات الإرسال عندما لا يكون هناك شيء مستحق. | +| `EVALUATOR_POLLING_INTERVAL_SECS` | لا | `10` | آخر خط احتياطي لـ (ثواني) لـ `GET /evaluate/{id}` استطلاعات عندما لا يُرجع المُقيّم `next_poll_secs` لكل استجابة ولا يعلن `default_poll_interval_secs` من `GET /config`. | +| `EVALUATOR_REQUEST_TIMEOUT_MS` | لا | `30000` | حد انتظار لكل طلب HTTP ضد المُقيّم (ميلي ثانية). | +| `EVALUATOR_MAX_ATTEMPTS` | لا | `5` | بعد هذا العدد من محاولات الفشل يتم تسجيل التقييم كنهاية `error` (أو `timeout` إذا كانت الأعطال استجابات انتظار). | +| `EVALUATOR_CONFIG_REFRESH_SECS` | لا | `300` (5 min) | عدد مرات إعادة جلب `GET /config` الخادم من المُقيّم. | +| `EVALUATOR_MAX_POLL_DURATION_SECS` | لا | `3600` (1 h) | الحد الأقصى لوقت ساعة الحائط قد تبقى الجلسة في طابور الاستطلاع قبل أن تنهيها AgentEye كـ `timeout`. الحراسة ضد مُقيّم يعود `pending` إلى الأبد. | +| `ALERT_WORKERS` | لا | `1` | التزامن: عدد مهام العمال لكل مثيل خادم التي تقيّم قواعد التنبيهات. انظر [التنبيهات](/ar/agenteye/alerts). | +| `ALERT_CLAIM_BATCH` | لا | `16` | الحد الأقصى لعدد التنبيهات التي يطالب بها عامل واحد لكل علامة. | +| `ALERT_POLL_IDLE_SECS` | لا | `5` | المدة التي ينام فيها عامل التنبيهات عندما يكون الطابور فارغاً. | +| `ALERT_REQUEST_TIMEOUT_MS` | لا | `15000` | مهلة قيمة تقييم لكل زناد (استعلامات ClickHouse + HTTP المسار الخارجي). | +| `ALERT_MAX_ATTEMPTS` | لا | `5` | أعطال عابرة متتالية قبل إعادة جدولة التنبيه في خطته العادية بدلاً من التراجع الأسي. | +| `AUDIT_WORKERS` | لا | `1` | التزامن: عدد مهام العمال لكل مثيل خادم التي تنفذ المراجعات. انظر [المراجعات](/ar/agenteye/audits). | +| `AUDIT_CLAIM_BATCH` | لا | `1` | الحد الأقصى لعدد المراجعات المستحقة التي يطالب بها عامل واحد لكل علامة. التحقيق الوكالي هو حلقة طويلة واحدة، لذا الافتراضي هو 1. | +| `AUDIT_POLL_IDLE_SECS` | لا | `30` | المدة التي ينام فيها عامل المراجعات عندما لا تكون هناك مراجعة مستحقة. | +| `AUDIT_REQUEST_TIMEOUT_MS` | لا | `30000` | مهلة الاستعلام لكل سياسة ضد ClickHouse (ميلي ثانية). | +| `AUDIT_LLM_TIMEOUT_MS` | لا | `1440000` | انتظر استدعاء التحقيق الوكالي لخدمة المساعد الذكي. حلقة عامل كاملة تعمل لدقائق؛ احفظها فوق خاص الوكيل `AGENTEYE_AUDIT_TIMEOUT_MS` بحيث يعود الوكيل بنتائجه الجزئية قبل استسلام الخادم. | +| `AUDIT_MAX_ATTEMPTS` | لا | `5` | أعطال عابرة متتالية قبل إعادة جدولة المراجعة في خطتها العادية بدلاً من التراجع الأسي. | +| `AGENTEYE_AGENT_URL` / `AGENTEYE_AGENT_TOKEN` | لا | — | يستدعي التحقيق الوكالي للمراجعة خدمة المساعد الذكي `agent`، **إعادة استخدام نفس الاتصال مثل المساعد** — لذا عيّن هذان أيضاً على **الخادم** (يفعل البيانات الموزعة/compose). كلاهما يُعيّن ⇒ تُجري المراجعات التحقيق الذكي؛ إما إيقاف ⇒ تُجري المراجعات **سياسة فقط** (يعمل اجتياز السياسة SQL الحتمية)، بغض النظر عن علم العزل `llm_enabled` لكل مراجعة. يجب أن يحتوي الوكيل أيضاً على LLM محكمة — انظر [assistant.md](/ar/agenteye/assistant). | + +**خدمة المساعد الذكي — تدقيق + إعدادات الحماية.** التحقيق الوكالي وحماية Python في الكبسولة محكمة على **خدمة الوكيل** (وليس الخادم)، جميعها على بادئة `AGENTEYE_AUDIT_*` وكلها اختيارية: + +| المتغير | الافتراضي | المعنى | +|---|---|---| +| `AGENTEYE_AUDIT_MAX_STEPS` | `200` | الحد الأقصى لأدوار الوكيل لكل تحقيق. | +| `AGENTEYE_AUDIT_TIMEOUT_MS` | `1200000` | الوقت الفعلي لتحقيق واحد (20 دقيقة). يجب أن يبقى **أقل من** `AUDIT_LLM_TIMEOUT_MS` الخادم. | +| `AGENTEYE_AUDIT_MAX_CONCURRENCY` | `1` | تحقيقات متزامنة لكل كبسولة وكيل (منفصلة عن ميزانية مساعد الدردشة). | +| `AGENTEYE_AUDIT_SANDBOX_TIMEOUT_MS` / `_MEM_MB` / `_CPU_SECS` / `_OUTPUT_MAX_BYTES` / `_SCRIPT_MAX_BYTES` | `20000` / `768` / `10` / `64000` / `64000` | حدود لكل سكريبت لسجن bubblewrap. | + +**متطلب منصة الحماية.** يقوم رمز حماية المراجعة بتشغيل Python النموذج داخل سجن bubblewrap، والذي يحتاج إلى **مساحات أسماء مستخدمين بلا امتيازات**. يجب أن تسمح كبسولة الوكيل بأعلام `clone()` — عيّن `seccompProfile: Unconfined` (k8s) أو `security_opt: [seccomp:unconfined]` (compose) على الوكيل. حيث يعطّل نواة العقدة مساحات الأسماء غير المتمتعة بامتيازات (مثل بعض صور GKE COS)، فشل الفحص المسبق للحماية **والمدقق ينحط إلى SQL فقط تلقائياً** — لا خطأ، فقط `sandbox_available: false` على صحة الوكيل `/health`. + +### تشغيل + +عيّن `DATABASE_URL` و `CLICKHOUSE_URL` في بيئتك (يرفض الخادم الإقلاع بدون ClickHouse)، ثم مررها إلى الكنتاينر: + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-server \ + -e DATABASE_URL="$DATABASE_URL" \ + -e CLICKHOUSE_URL="$CLICKHOUSE_URL" \ + -e ADMIN_KEY="$ADMIN_KEY" \ + -p 8080:8080 \ + ghcr.io/agenteye-enterprise/server:beta-latest +``` + +يقوم الخادم بتشغيل هجرات قاعدة البيانات تلقائياً عند بدء التشغيل؛ لا حاجة لخطوة هجرة منفصلة. + +### فحص الصحة + +``` +GET /health # liveness - always {"status":"ok"} once the process is up +GET /ready # readiness - 200 when Postgres + ClickHouse are reachable, else 503 +``` + +لا توثيق مطلوب. استخدم `/health` لمسابير **liveness** و `/ready` لمسابير **readiness** / load-balancer. `/ready` تفحص المتطلبات الثابتة التي لا يمكن للخادم الخدمة بدونها (Postgres + ClickHouse)، لذا خادم يعمل لكن لا يمكنه الوصول إلى قاعدة بيانته يُؤخذ من الدوران ويظهر كـ `NotReady`؛ يتم الإبلاغ عن Redis لكنه لا يفشل القابلية للجاهزية أبداً. على بيانات Kubernetes الموزعة مسبار الجاهزية موجود بالفعل عند `/ready` ويبقى liveness في `/health`. انظر [enterprise-docs/health-monitoring.md](/ar/agenteye/health-monitoring) للصورة الكاملة، بما في ذلك التنبيهات الاختيارية المدمجة بـ Kubernetes لفشل الكبسولة إلى Slack. + +### رابط البريد السحري + +رسائل بريد تسجيل OTP تحتوي على زر **افتح لوحة المعلومات** بنقرة واحدة. النقر عليه يهبط المستخدم على `/login?token=&email=
`؛ تبادل لوحة المعلومات هذا الزوج لجلسة وإعادة توجيه إلى التطبيق، بدون إعادة إدخال رمز يدوية. يحل الخادم أصل لوحة المعلومات المستخدم لبناء الرابط في ثلاث طبقات: + +1. **رأس `X-AgentEye-Dashboard-Url`**: يُعيّن تلقائياً بواسطة وكيل `/api/auth/otp/request` لوحة المعلومات من أصلها العام. في نشر نفس الأصل (الخادم ولوحة المعلومات يشاركان المضيف خلف ingress واحد يرسل رؤوس الوكيل)، **لا توجد حاجة لأي تكوين**. +2. **متغير بيئة `DASHBOARD_URL`**: عيّن هذا إذا كانت لوحة المعلومات الخاصة بك قابلة للوصول على أصل مختلف عن الذي يراه نقطة نهاية طلب OTP الخادم (تقسيم `api.example.com` / `app.example.com`)، أو إذا كان ingress الخاص بك لا ينتشر المضيف العام إلى كبسولة لوحة المعلومات (بحيث `request.nextUrl.origin` سيحل إلى ربط موسّع مثل `0.0.0.0:3000`). مثال: `DASHBOARD_URL=https://app.example.com`. +3. **الافتراضي**: `https://app.befailproof.ai`، يُستخدم فقط إذا لم يكن أي من الخيارات أعلاه موجوداً. + +يتم التحقق من قيمة الرأس: فقط `https://*` و loopback (`http://localhost*`, `http://127.0.0.1*`) الأصول مقبولة، وعناوين الربط الموسّعة (`0.0.0.0`, `[::]`) مرفوضة حتى مع مخطط `https://`. أي شيء آخر ينسحب إلى الطبقة 2. + +عيّن على مجموعة قيد التشغيل بسطر واحد؛ لا ملف، لا إعادة بناء kustomize: + +```bash +kubectl set env deployment/server -n agenteye \ + DASHBOARD_URL=https://app.example.com +``` + +هذا يُطلق عملية إعادة تشغيل؛ تلتقط الكبسولات الجديدة القيمة عند أول طلب. لاحظ أن الكبس يعيش فقط على الانتشار؛ `kustomize build | kubectl apply` اللاحقة ضد التراكب ستحذفها إلا إذا أضفت متغير البيئة نفسه إلى رقعة `server-env.yaml` للتراكب الخاص بك. + +--- + +## لوحة المعلومات + +### استحضار الصورة + +```bash +docker pull ghcr.io/agenteye-enterprise/dashboard:beta-latest +``` + +### متغيرات البيئة + +| المتغير | مطلوب | الافتراضي | الوصف | +|---|---|---|---| +| `AGENTEYE_SERVER_URL` | نعم | لا شيء | URL الأساسي للخادم، مثل `http://localhost:8080` | +| `AGENTEYE_API_KEY` | نعم | لا شيء | مفتاح API تستخدمه لوحة المعلومات للمصادقة على الخادم. يحتاج إلى جميع الأذونات (يوصى بمفتاح المسؤول). | +| `AE_LOG_LEVEL` | لا | `info` | طراز السجلات من جانب الخادم: `debug`, `info`, `warn`, `error`. عيّن على `debug` لرؤية سطور الطلب/الاستجابة الأعلى وآثار التحقق من الجلسة عند تشخيص المشاكل. | +| `AE_LOG_JSON` | لا | تلقائي | `1` يفرض JSON-per-line output؛ `0` يفرض إخراج قابل للقراءة البشرية. عند الإيقاف، يتم تفعيل JSON تلقائياً إذا كان `NODE_ENV=production`. يوصى بـ JSON في الإنتاج بحيث تحلل السجلات بشكل نظيف مع `jq` أو محمّع السجل. | +| `AE_ANALYTICS_DISABLED` | لا | لا شيء | عيّن على `1`/`true` لتعطيل بيانات وصول المنتج المجهولة لوحة المعلومات. انظر [بيانات التلميح والخصوصية](#telemetry--privacy) أدناه. | +| `REDIS_URL` | لا | لا شيء | خلفية ذاكرة التخزين المؤقتة المشتركة الاختيارية، مثل `redis://redis:6379/0`. عند التعيين، تخزن لوحة المعلومات نتائج `validateSession()` عبر النسخ المتماثلة وتشاركها في ذاكرة التخزين المؤقتة fetch الجديدة لمسارات وكيل التجميع اللطيف / قائمة env. حدود معدل طلب OTP والتحقق من جانب الحافة أيضاً تستخدم Redis عند الوجود (تفشل مفتوحة إذا كانت Redis غير قابلة للوصول؛ حد الخادم الجانبي هو backstop الأمان). انظر **Redis (ذاكرة تخزين مؤقتة اختيارية)** أدناه. | +| `AGENTEYE_AGENT_URL` | لا | لا شيء | URL الأساسي للخدمة اختيارية للمساعد الذكي `agent`، مثل `http://agent:9100`. **اتركها غير معيّنة لإخفاء المساعد بالكامل**: لا فقاعة مساعد تظهر في لوحة المعلومات. انظر [enterprise-docs/assistant.md](/ar/agenteye/assistant). | +| `AGENTEYE_AGENT_TOKEN` | لا | لا شيء | سر مشترك تعرضه لوحة المعلومات لخدمة `agent`. يجب أن يطابق `AGENTEYE_AGENT_TOKEN` محكمة على الوكيل. انظر [enterprise-docs/assistant.md](/ar/agenteye/assistant). | + +### تشغيل + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-dashboard \ + -e AGENTEYE_SERVER_URL="http://your-server-host:8080" \ + -e AGENTEYE_API_KEY="$ADMIN_KEY" \ + -p 3000:3000 \ + ghcr.io/agenteye-enterprise/dashboard:beta-latest +``` + +### بيانات التلميح والخصوصية + +تُرسل لوحة المعلومات **بيانات وصول المنتج المجهولة** إلى خدمة بيانات Exosphere (PostHog): أي صفحات لوحة المعلومات يتم عرضها وحفنة من الإجراءات UI مثل إنشاء مفتاح API أو إعادة تقييم جلسة. تُخبر هذه إشارة الاستخدام أي الميزات ذات الأولوية. + +- **لا توثيق الوكيل أو الجلسة أو الحدث يترك البنية الأساسية الخاصة بك أبداً.** يتم الإبلاغ عن استخدام واجهة مستخدم لوحة المعلومات فقط. يتم تجريد عناوين URL للصفحة من المعرّفات قبل الإرسال، والمشغلون يتم التعريف بهم فقط برقم داخلي معتم، أبداً بالبريد الإلكتروني. +- بيانات التلميح **ممكّنة بشكل افتراضي**. لتعطيلها بالكامل، عيّن `AE_ANALYTICS_DISABLED=1` على كنتاينر لوحة المعلومات وأعد التشغيل. +- تُرسل بيانات التحليلات إلى المسار `/ingest` الخاص بلوحة المعلومات، والتي تعكس لوحة المعلومات إلى PostHog (`https://us.i.posthog.com`). إبقاء الطلبات من الطرف الأول يعني أن مانعات الإعلانات في المتصفح لا تسقطها. **كنتاينر لوحة المعلومات** يحتاج إلى وصول خارج PostHog؛ إذا تم حظره، تفعل بيانات التلميح شيء صامت ولا تتأثر لوحة المعلومات. + +--- + +## المساعد الذكي (اختياري) + +يسمح مساعد ذكي في لوحة المعلومات لفريقك بطرح أسئلة حول بيانات الوكيل الخاصة بهم باللغة الطبيعية (تلخيص الجلسات، صياغة SQL لمحرر `/queries`، وتحويل الاستعلامات المحفوظة إلى بلاط لوحة المعلومات) دون مغادرة لوحة المعلومات. يعمل كـ كنتاينر `agent` داخلي منفصل (على Agents SDK Claude) الذي تستطيع لوحة المعلومات فقط الوصول إليه، ويبقى **معطّل حتى تحكم نقطة نهاية LLM**. + +لتفعيله تعيّن، على خدمة `agent`، اتصال LLM (**Portkey** عبر `PORTKEY_API_KEY` + سلج فهرس نموذج `AGENTEYE_AGENT_MODEL=@/`، Anthropic مباشر عبر `ANTHROPIC_API_KEY`، بوابة أخرى عبر `ANTHROPIC_BASE_URL`، أو Bedrock/Vertex)، مفتاح بيانات **مخصص**، و`AGENTEYE_AGENT_TOKEN` مشترك يطابق لوحة المعلومات. يحتاج مستخدمو لوحة المعلومات بالإضافة إلى أذن `agent:use`. + +لمفتاح بيانات المساعد لا تحك أي شيء بالفعل: اختر سر عشوائي، عيّنه كـ `AGENTEYE_API_KEY` على `agent` **و** كـ `AGENT_API_KEY` على `server`، والخادم يزرعه عند بدء التشغيل بمجموعة أذن ثابتة. دخوله هو قراءة فقط (`events:read`, `evaluations:read`, `dashboards:read`, `queries:read`)، والإضافة يحتوي على نطاقات المصادقة الموافقة (`dashboards:write`, `queries:write`, `queries:run`) حتى يتمكن من صياغة والتحقق من الاستعلامات المحفوظة وبناء بلاط لوحة المعلومات نيابة عن المستخدم؛ كل SQL يعمل عبر دور ClickHouse قراءة فقط للمنظمة، لذا يوسع هذا ما يستطيع المساعد صياغته، وليس ما البيانات التي يمكنه الوصول إليها. النطاقات ثابتة في الكود ولا يمكن توسيعها بالتكوين. هذا المفتاح محمي؛ لا يمكن تعطيله أو إعادة توليده عبر API، فقط تدويره بتغيير القيمة وإعادة التشغيل. لا تعيد استخدام مفتاح المسؤول/لوحة المعلومات لهذا. + +الإعداد الكامل، والمرجع الكامل لمتغير البيئة، وخيارات بيانات التلميح، والنموذج الأمني في **[enterprise-docs/assistant.md](/ar/agenteye/assistant)**. + +--- + +## ClickHouse (متجر التحليلات المطلوب) + +يحافظ ClickHouse على لوحات معلوماتك سريعة في مجلدات الأحداث العالية ويسمح محرر SQL `/queries` بالانضمام عبر الأحداث والتقييمات والجلسات في متجر واحد. إنه متجر القانوني المطلوب لكل حدث مستقبل، وكل نتيجة تقييم نهائية، والمجاميع المشتقة لكل جلسة. يحتوي PostgreSQL على جداول الحالة العلائقية / القابلة للتغيير (api_keys, users, otp_codes, evaluation_jobs, dashboards, saved_queries)؛ توجد السطح التحليلي في ClickHouse لذا استعلامات لوحة المعلومات التجميعية والاستعلامات SQL الخاصة بك يمكن أن تفحص وتنضم إليها بشكل أصلي، بدون رحلات قاعدة بيانات متقاطعة. يرفض الخادم الإقلاع بدون `CLICKHOUSE_URL`. + +### المخطط + +ثلاثة كائنات ClickHouse يتم إنشاؤها عند بدء تشغيل الخادم، كلها idempotent (`CREATE IF NOT EXISTS`): + +- **`agenteye.events`**: `ReplacingMergeTree(ingested_at)`, مقسم بواسطة `toYYYYMM(ts)`, مرتب حسب `(session_id, ts, dedup_key)`. تُسقط إدراجات مكررة (محاولات المجمع) إلى صف واحد في وقت الدمج؛ يحسب الخادم SHA-256 `dedup_key` حتمية لكل حدث بحيث تكون المحاولات الإعادة آمنة. +- **`agenteye.evaluations`**: `ReplacingMergeTree(ingested_at)`, مقسم بواسطة `toYYYYMM(finished_at)`, مرتب حسب `(session_id, finished_at, dedup_key)`. كُتب مرة واحدة لكل نتيجة تقييم نهائية من قبل خط أنابيب المُقيّم. نفس نموذج dedup-key كما `events`. +- **`agenteye.agent_sessions`**: **VIEW** أعلى `agenteye.events`، وليس جدول فعلي. كل عمود مشتق (`started_at = min(ts)`, `last_event_at = max(ts)`, `ended_at = max(if event_type='agent_end', ts, NULL)`, `event_count = count()`, إلخ.). لا إدراج لكل حدث ولا تعبئة خلفية منفصلة؛ يعكس العرض تلقائياً مهما كان في `events`. + +لـ backwards-compat مع الاستعلامات المحفوظة التي تُرجع `analytics.evaluations` / `analytics.sessions`، ينشئ الخادم أيضاً قاعدة بيانات `analytics` ClickHouse برؤى أعلى جداول `agenteye.*`؛ `analytics.events`، `analytics.evaluations`، `analytics.agent_sessions`، `analytics.sessions` جميعها تُحل بشكل صحيح. + +### التكوين + +توزع البيانات docker-compose والـ `deploy/base/clickhouse/` خدمة ClickHouse محكمة لحمل عمل AgentEye الخاص بك: + +- 2 GiB طُلب / 4 GiB حد الذاكرة في التراكب الأساسي المشحون (الحجم لملاءمة عُقد POC/staging الصغيرة)؛ يجب على عملاء الإنتاج تراكب الأعلى — الحد الموصى به هو 2c / 4Gi طلب، 6c / 8Gi حد. `max_server_memory_usage_to_ram_ratio=0.9` +- ذاكرة 5 GiB + ذاكرة غير مضغوطة 8 GiB +- `background_pool_size=16`, `background_merges_mutations_concurrency_ratio=2` +- MergeTree: `parts_to_throw_insert=3000`, `parts_to_delay_insert=1500`, `non_replicated_deduplication_window=1000` +- `local_io_method=auto` (io_uring على kernels المدعومة) +- `fsync_metadata=0`: مقبول لأن هناك على الأقل مرة واحدة ingest + ReplacingMergeTree dedup +- `query_log` ممكّن مع TTL 30 يوم؛ `query_thread_log` محذوف (باهظ عند QPS عالي) +- `max_execution_time=30` لاستعلامات جانب المستخدم +- 100 GiB PVC على قالب StatefulSet (يجب أن تعطّل تراكبات العملاء على فئة تخزين SSD سريع للإنتاج) + +### النسخ الاحتياطية + +يتم التقاط مجموعة البيانات الكاملة الخاصة بك ليلاً في ملف واحد قابل للاستعادة، لذا فقدان مجموعة أو التخزين قابل للاسترجاع. يتم نسخ ClickHouse احتياطياً تلقائياً بواسطة `agenteye-backup` CronJob اليومي، الذي يُلقي كل من PostgreSQL و ClickHouse في مسار واحد. يُقرأ ClickHouse عبر HTTP API الخاصة به: `agenteye.events` و `agenteye.evaluations` يتم إلقاؤها بصيغة ClickHouse الأصلية (تُعاد إنشاء العروض وسياسات الصفوف من قبل الخادم عند بدء التشغيل، لذا فإن بيانات الجدول هي الصورة الكاملة) ومضمن مع Postgres dump في ملف واحد مضغوط يُرفع إلى التخزين الموضوعي الخاص بك. + +يتم تكوين دلو الوجهة وبيانات اعتماد السحابة لكل تراكب. انظر قسم **النسخ الاحتياطية** من [enterprise-docs/kubernetes-deployment.md](/ar/agenteye/kubernetes-deployment) لتكوين المرفع وخطوات الاستعادة. + +--- + +## Redis (ذاكرة تخزين مؤقتة اختيارية) + +Redis هي **اختيارية** ذاكرة تخزين مؤقتة مشتركة + خلفية تحديد السعر المستخدمة من قبل الخادم ولوحة المعلومات. مع نشر Redis و`REDIS_URL` عيّن على كلا الخدمات: + +- **الخادم** يخزن عمليات البحث عن المفاتيح المصادقة، قائمة `/events/environments` + `/evaluations/environments`، لفافة `/events/latency_aggregate` (أثقل استعلام تسأل عنه لوحة المعلومات)، قائمة `/sessions`، وينقل حد معدل طلب OTP من Postgres `COUNT(*)` إلى Redis `INCR + EXPIRE`. +- **لوحة المعلومات** تخزن نتائج `validateSession()` بحيث تُشاركه 10-20 جرعة API المصادقة التي تصدرها حمولة صفحة نموذجية تفحص جلسة واحدة فقط. كما تُحدد معدل طلب OTP والتحقق عند حافة لوحة المعلومات. + +**كل الخدمات تنحط بأناقة إذا كانت Redis غير قابلة للوصول.** كل نداء ذاكرة تخزين مؤقتة يعود `Err` ضمن انتظار مقيد والمتصل ينسحب إلى مصدر الحقيقة (Postgres على الخادم، خادم Rust الأعلى على لوحة المعلومات). حد معدل OTP ينسحب إلى مسار Postgres `COUNT(*)` على الخادم (يُحافظ على خاصية الأمان)؛ حد OTP للحافة لوحة المعلومات يفشل مفتوح أثناء حد الخادم الجانبي لا يزال يحمل. Redis كونه نزولاً يُنحط الزمن الكامن، وليس الصحة. + +### التكوين + +بيانات docker-compose تتضمن بالفعل خدمة Redis ويسيّر `REDIS_URL=redis://redis:6379/0` في الخادم ولوحة المعلومات. لاستخدام Redis خارجي، عيّن `REDIS_URL` إلى نقطة النهاية الخاصة بك وأزل الخدمة `redis` من ملف compose. + +### الذاكرة + الثبات + +صورة Redis الموزعة تعمل مع `--appendonly yes --appendfsync everysec --maxmemory 256mb --maxmemory-policy allkeys-lru`. يعني AOF persistence أن الذاكرة المؤقتة تبقى عبر إعادة تشغيل الكنتاينر؛ `everysec` هو توازن الثبات/الأداء الصحيح لأن فقدان آخر ثانية من كتابات الذاكرة المؤقتة غير مؤذي. يُغطي إجلاء LRU نمو الذاكرة. + +### عندما لا تنشر Redis + +- واحد-instance dev/QA. الذاكرات المؤقتة داخل العملية على الخادم وحده توفر معظم الفائدة لكل نسخة متماثلة؛ Redis يضيف المشاركة عبر النسخ المتماثلة التي لا تحتاجها الإعدادات أحادية-instance. +- تثبيتات هواء-فراغ حيث التكلفة التشغيلية لتشغيل خدمة واحدة أخرى تفوق كسب الزمن الكامن. + +--- + +## Docker Compose (موصى به) + +ملف `docker-compose.yml` متاح في مستودع `agenteye-enterprise/releases`. يجلب Postgres وClickHouse و Redis والخادم ولوحة المعلومات مع أمر واحد. + +```bash +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download \ + --repo agenteye-enterprise/releases \ + --pattern 'docker-compose.yml' \ + --dir ./agenteye +cd agenteye +``` + +**تجاوز الافتراضيات عبر `.env`:** + +``` +# Use URL-safe passwords (no /, +, or = characters). +# Generate with: openssl rand -hex 24 +POSTGRES_PASSWORD=your-db-password +ADMIN_KEY=your-admin-secret + +# Dashboard authentication +ADMIN_EMAIL=admin@yourcompany.com +ALLOWED_EMAILS=*@yourcompany.com + +# SMTP for OTP emails (omit to log OTP codes to stdout) +# SMTP_HOST=smtp.yourprovider.com +# SMTP_PORT=587 +# SMTP_USERNAME=your-smtp-user +# SMTP_PASSWORD=your-smtp-password +# SMTP_FROM=noreply@yourcompany.com + +RUST_LOG=info +``` + +```bash +docker compose up -d +``` + +**التوقف (يحتفظ بمجلد البيانات):** + +```bash +docker compose down +``` + +**التوقف ومسح جميع البيانات:** + +```bash +docker compose down -v +``` + +--- + +## الإعدادات التشغيلية + +مجموعة صغيرة من المقابض التشغيلية التي اعتادت تثبيتها بواسطة متغيرات env قابلة الآن للتحرير لكل منظمة من صفحة **`//settings`** الخاصة بلوحة المعلومات؛ تُنسّق كل منظمة الخاصة بها. التغييرات تسري مفعول ضمن ثواني، بدون إعادة تشغيل وبدون إعادة نشر. + +| الإعداد | متغير env التمهيد | ما تتحكم فيه | +|---|---|---| +| عمليات تسجيل الدخول المسموحة | `ALLOWED_EMAILS` | رسائل البريد الإلكتروني (أو بدلات `*@domain.com`) مسموح بها تلقي OTP وإضافة كمستخدمين | +| أذونات المستخدم الافتراضية | `DEFAULT_USER_PERMISSIONS` | رموز الأذونات المفصولة بفواصل محددة مسبقاً عندما يفتح المسؤول **+ مستخدم جديد**. يجب أن يكون كل رمز أحد السلاسل المدرجة تحت [أذونات مفتاح API](/ar/agenteye/api-keys). يُفقد للإعداد المسبق `standard`: وصول قراءة فقط بالإضافة إلى الإجراءات اليومية في on-call (إعادة تقييم الزناد، تشغيل الاستعلامات، ack الحوادث، استخدام المساعد). | +| عمر الجلسة | `SESSION_TTL_SECS` | مدى اعتبار تسجيل دخول لوحة المعلومات صالح قبل إعادة المصادقة. تُعيد لوحة المعلومات فحص الجلسة الأعلى كل 5 ثواني، بحيث تأخذ تحديث الأذن على `//users` تأثيره على الطلب التالي للمستخدم المتأثر، بدون إعادة تسجيل. | +| عمر أحادي الاستخدام | `OTP_TTL_SECS` | مدى صلاح رابط OTP / سحري | +| قنوات إخطار التنبيهات | `ALERTS_ENABLED_CHANNELS` | قائمة مفصولة بفواصل من أنواع القنوات موزّع التنبيهات مسموح باستخدامها: `email`, `slack`, `webhook`. التكوين لكل تنبيه مصادقٌ على `//alerts/`، لكن موزّع يفلتر كل تسليم خارج من خلال هذه المجموعة؛ قناة معطّلة هنا short-circuits مع `skipped_disabled` audit row. القناة `dashboard` (الإدراج المحلي للمراجعة) دائماً مسموحة. يُفقد لجميع ال \ No newline at end of file diff --git a/docs/ar/agenteye/evaluation-suite.mdx b/docs/ar/agenteye/evaluation-suite.mdx new file mode 100644 index 00000000..5fb62a23 --- /dev/null +++ b/docs/ar/agenteye/evaluation-suite.mdx @@ -0,0 +1,465 @@ +--- +--- +title: "مجموعة التقييم" +description: "توثيق مجموعة التقييم في AgentEye." +--- + + +تقيّم AgentEye جلسات الوكيل المكتملة بإرسال نسخ حدث المعاملة الكاملة عبر POST إلى +**خدمة تقييم واحدة مملوكة للعميل**. تُرجع خدمة التقييم النتائج إما +بصيغة مضمنة أو بإرجاع `job_id` لتستطلعها AgentEye. يتم تخزين النتائج +وعرضها في لوحة التحكم. + +يغطي هذا الدليل: + +1. كيفية الكشف عن إكمال الجلسة. +2. عقد HTTP الذي يجب أن تطبقه خدمة التقييم. +3. تكوين خادم AgentEye. +4. عرض النتائج. +5. استكشاف الأخطاء. + +للحصول على مساعد Python الذي يطبق العقد لك، اطّلع على +[حزمة `agenteye-evaluator` على PyPI](https://pypi.org/project/agenteye-evaluator/). + +--- + +## كيفية العمل + +```text +ingest /events ──▶ AgentEye ──── POST /evaluate ────▶ Evaluator service + (agent_end) server ◀──── done | pending ──── + │ + │ GET /evaluate/{job_id} ─────▶ + │ ◀──── done ────────────── + ▼ + evaluations (terminal results) +``` + +عند إصدار SDK في AgentEye لحدث `agent_end` الخاص بجلسة ما، يجدول الخادم تقييمًا. +ثم يرسل نسخة حدث المعاملة الكاملة إلى خدمة التقييم الخاصة بك، والتي يمكنها: + +- **إرجاع النتيجة بصيغة مضمنة** مع `{"status":"done", "scores":{...}, "reasoning":{...}, "summary":"..."}`. يتم إلحاق + النتيجة بخط زمني التقييم للجلسة. `reasoning` و + `summary` اختيارية. +- **تأجيل** مع `{"status":"pending", "job_id":"abc-123"}`. ثم تستدعي AgentEye + `GET {EVALUATOR_ENDPOINT}/evaluate/abc-123` حتى تُرجع خدمة التقييم الخاصة بك + `{"status":"done", ...}` أو `{"status":"error", "error":"..."}`. + + دورة الاستطلاع لكل وظيفة: قد تتضمن استجابة `pending` + `next_poll_secs` لتجاوز ذلك؛ وإلا تستخدم AgentEye قيمة + `default_poll_interval_secs` من `GET /config`؛ وإلا يعود الخادم إلى + `EVALUATOR_POLLING_INTERVAL_SECS` (الافتراضي 10s). يتم تقييد جميع القيم + إلى [1s, 1h]. + +الجلسات التي لا تصدر أبدًا `agent_end` (على سبيل المثال، عملية وكيل متعطلة) +يمكن أيضًا التقاطها: قد يُرجع `GET /config` الخاص بخدمة التقييم +`{"inactivity_timeout_secs": 1800}`، وستقيّم AgentEye أي جلسة +ظلت خاملة لتلك المدة. اضبط الحقل على `null` أو احذفه لتعطيل +هذا البديل. + +خط الأنابيب هو عدم تشغيل كامل عند عدم تعيين `EVALUATOR_ENDPOINT`. + +يمكن للجلسة أن تتراكم فيها **تقييمات نهائية متعددة بمرور الوقت**: كل +حدث `agent_end` (وكل إعادة تقييم يدوية من لوحة التحكم) يُلحق صف تقييم +جديد. هذه هي الطريقة المدعومة لتقييم محادثة استُؤنفت: ينهي المستخدم وكيلاً، +يعود لاحقًا، يرسل المزيد من الأحداث، +ينهي الوكيل مرة أخرى، وينفذ التقييم الثاني مقابل نسخة المعاملة المحدثة الكاملة. +تُظهر لوحة التحكم أحدث تقييم كعنوان أساسي والتقييمات السابقة +كخط زمني قابل للطي. أثناء تشغيل تقييم واحد لجلسة ما، يتم تجاهل +أحداث `agent_end` الإضافية لتلك الجلسة؛ الحدث التالي بعد انتهاء +التقييم قيد التشغيل سيضع تقييمًا جديدًا في قائمة الانتظار كالمعتاد. + +يعاود البديل الخامل الاشتباك على الجلسات المستأنفة أيضًا: إذا وصلت أحداث جديدة +بعد تقييم نهائي سابق وظلت الجلسة خاملة بعد ذلك +`inactivity_timeout_secs`، يتم وضع تقييم جديد في قائمة الانتظار. + +يتم إعادة محاولة الأخطاء العابرة (5xx, 429, timeouts, أخطاء الشبكة) +مع تراجع أسي حتى `EVALUATOR_MAX_ATTEMPTS`؛ استجابات 4xx نهائية. +من الآمن تشغيل AgentEye مع عدة نسخ خادم موزعة أفقيًا؛ +يتم تقسيم العمل بحيث لا يتم أبدًا إرسال نفس الجلسة مرتين في نفس الوقت. + +--- + +## عقد HTTP + +كل مسار مصرح يستخدم **مصادقة رمز المتحمل**. يجب تكوين نفس القيمة على +كلا الجانبين: + +- خادم AgentEye: متغير بيئي `EVALUATOR_TOKEN` +- خدمة التقييم: مكونة بنفس الطريقة (يقرأ SDK `agenteye-evaluator` + `EVALUATOR_TOKEN` بموجب الاتفاقية) + +إذا لم يتم تعيين `EVALUATOR_TOKEN`، لا يرسل الخادم رأس `Authorization`؛ قد +تقبل خدمة التقييم طلبات مجهولة الهوية بعد ذلك، وهذا حسن لشبكة +داخلية فقط لكن غير موصى به على الإنترنت العام. + +### المسارات التي يجب أن تخدمها خدمة التقييم + +| المسار | الجسد / المعاملات | الاستجابة | +|---|---|---| +| `GET /health` | بدون | `{"status":"ok"}` (مفتوح، بدون مصادقة) | +| `GET /config` | بدون | `{"inactivity_timeout_secs": \| null, "default_poll_interval_secs": \| omitted}` | +| `POST /evaluate` | `EvalRequest` JSON | `{"status":"done", ...}` أو `{"status":"pending", "job_id":"..."}` | +| `GET /evaluate/{id}` | بدون | نفس شكل الاستجابة مثل `/evaluate` | + +### جسم `EvalRequest` الذي يرسله الخادم + +```json +{ + "schema_version": "1", + "session_id": "session-abc123", + "agent_id": "planner", + "environment": "production", + "started_at": "2026-05-10T12:00:00Z", + "ended_at": "2026-05-10T12:05:00Z", + "events": [ + { "id": 1234, "ts": "...", "event_type": "agent_start", "payload": { ... } }, + ... + ] +} +``` + +### أشكال الاستجابة + +**متزامن (منتهي):** + +```json +{ + "status": "done", + "scores": { "helpfulness": 0.85, "tool_efficiency": 0.6 }, + "reasoning": { + "helpfulness": "answered the question directly with citations", + "tool_efficiency": "called list_files three times when one would have done" + }, + "summary": "strong answer quality, weak tool selection" +} +``` + +`reasoning` (خريطة تبرير لكل نتيجة) و `summary` (سرد واحد شامل +فقرة واحدة) كلاهما اختياري. يجب أن تعكس المفاتيح في `reasoning` المفاتيح في `scores`؛ +تُظهر لوحة التحكم كل مدخل مضمنًا تحت +شريط النتيجة الخاص به. تابع خدمات التقييم الأقدم التي تُرجع فقط `scores` تعمل +بدون تغيير؛ `reasoning` و `summary` ببساطة تُقرأ على أنها null و +لا يتم حذف تسهيلات الواجهة المستخدمة المقابلة. + +**غير متزامن (مؤجل):** + +```json +{ "status": "pending", "job_id": "abc-123", "next_poll_secs": 30 } +``` + +`next_poll_secs` اختياري؛ إذا تم حذفه، يعود الخادم إلى +`default_poll_interval_secs` لخدمة التقييم من `/config`، ثم إلى +متغير البيئة الخاص به `EVALUATOR_POLLING_INTERVAL_SECS`. + +**خطأ نهائي من جانب خدمة التقييم:** + +```json +{ "status": "error", "error": "model service unavailable" } +``` + +يعامل الخادم أي جسم 2xx آخر كخطأ بروتوكول وينسجل +`error` نهائي للجلسة. + +--- + +## كتابة خدمة تقييم مع SDK + +تمنحك حزمة Python `agenteye-evaluator` غلافًا FastAPI +مكتوبًا بشكل ثابت يطبق عقد HTTP أعلاه. ثبتها من PyPI: + +```bash +pip install agenteye-evaluator +``` + +خدمة تقييم بحد أدنى من القابلية: + +```python +import os +from agenteye_evaluator import Evaluator, EvalRequest, EvalResponse + +app = Evaluator(token=os.environ["EVALUATOR_TOKEN"]) + +@app.evaluator +def run(req: EvalRequest) -> EvalResponse: + # Inspect req.events (the full session transcript) and return scores. + tool_calls = sum(1 for e in req.events if e.event_type == "tool_use") + return EvalResponse( + scores={"tool_calls": float(tool_calls)}, + reasoning={"tool_calls": f"{tool_calls} tool invocations in the transcript"}, + summary="tight tool loop" if tool_calls < 5 else "agent looped on tools", + ) +``` + +نسخة `app` قابلة للاستدعاء ASGI، لذا يقوم `uvicorn module:app` بتشغيلها. + +لخدمات التقييم التي تحتاج إلى تأجيل عمل مكلف، أرجع `JobPending` +بدلاً من ذلك وسجل معالج `@app.job_lookup`؛ الخادم AgentEye +يستطلع `GET /evaluate/{job_id}` حتى تُرجع حالة نهائية أو يمر +حد `EVALUATOR_MAX_POLL_DURATION_SECS` (الافتراضي 1 ساعة). + +مرجع API الكامل، النمط غير المتزامن، ومخطط الحدث: ملف README الخاص بـ +`agenteye-evaluator` يُشحن داخل كل نسخة من +[صفحة إصدارات agenteye-enterprise](https://github.com/agenteye-enterprise/releases)، +أو يمكنك قراءته على صفحة PyPI للحزمة. + +--- + +## تشغيل خدمة تقييم على Kubernetes + +خدمة التقييم هي **خدمتك**: لا تشحن AgentEye خدمة تقييم افتراضية +في حاوية. تتضمن النسخة مظاهر Kubernetes مرجعية تحت `deploy/examples/evaluator/` +التي يمكنك تطبيقها كما هي بعد استبدال صورتك ورمز متحمل مشترك. + +### 1. تجميع خدمة التقييم الخاصة بك + +ملف Dockerfile الحد الأدنى لخدمة التقييم الخاصة بك: + +```dockerfile +FROM python:3.12-slim +WORKDIR /app +RUN pip install --no-cache-dir agenteye-evaluator uvicorn +COPY my_evaluator.py . +RUN useradd --uid 10001 --create-home --shell /usr/sbin/nologin evaluator \ + && chown -R evaluator:evaluator /app +USER evaluator +EXPOSE 9000 +CMD ["uvicorn", "my_evaluator:app", "--host", "0.0.0.0", "--port", "9000"] +``` + +`runAsNonRoot` (UID 10001) يحافظ على توافق الحاوية مع ملفات تعريف +أمان Pod المقيدة. + +### 2. إنشاء رمز المتحمل المشترك + +```bash +kubectl -n agenteye create secret generic evaluator-token \ + --from-literal=token="$(openssl rand -hex 32)" +``` + +استخدم نفس القيمة مثل `EVALUATOR_TOKEN` على خادم AgentEye. يرسل +الخادم `Authorization: Bearer ` على كل طلب؛ يستخدم SDK +`hmac.compare_digest` للفحص الثابت الوقت ويرفض عدم التطابق +مع HTTP 401. + +### 3. تطبيق مظاهر الأمثلة + +```bash +# Edit deploy/examples/evaluator/deployment.yaml first to point +# `image:` at your registry, then: +kubectl apply -k deploy/examples/evaluator/ +``` + +يتضمن المثال: + +- نشر بـ 2 نسخة مع `runAsNonRoot` ونظام ملفات الجذر للقراءة فقط، + جميع القدرات محذوفة، liveness + readiness على `/health` +- خدمة ClusterIP على المنفذ 9000 +- نموذج `secret.example.yaml` (مستبعد بقصد من + Kustomization؛ أنشئ الرمز الحقيقي خارج النطاق حتى لا يوجد رمز + في git) + +### 4. ربط AgentEye به + +على خادم AgentEye، اضبط: + +```bash +EVALUATOR_ENDPOINT=http://evaluator:9000 +EVALUATOR_TOKEN= +``` + +يُوزع الخادم `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH` +طلبات متزامنة عبر جميع حبات خدمة التقييم (الافتراضيات: `2 × 4 = 8`). +مقياس `replicas` وحدود الموارد لكل حبة بالتزامن مع هذه +عناصر التحكم من جانب الخادم. + +### التحقق + +```bash +kubectl -n agenteye port-forward svc/evaluator 9000:9000 +curl -s http://localhost:9000/health # → {"status":"ok"} +``` + +بعد تشغيل وكيل من البداية إلى النهاية، يجب أن يُرجع `GET /evaluations` +على خادم AgentEye صف بـ `status: "done"` والنتائج التي +أنتجتها خدمة التقييم الخاصة بك. + +--- + +## تكوين خادم AgentEye + +اضبط على عملية الخادم: + +| متغير البيئة | المعنى | +|---|---| +| `EVALUATOR_ENDPOINT` | عنوان URL الأساسي لخدمة التقييم الخاصة بك (`http://evaluator:9000`). لم يتم التعيين = خط الأنابيب معطل. | +| `EVALUATOR_TOKEN` | رمز متحمل. يجب أن تساوي القيمة التي تم تكوين خدمة التقييم بها. | +| `EVALUATOR_WORKERS` | مهام عامل لكل نسخة خادم (الافتراضي 2). | +| `EVALUATOR_CLAIM_BATCH` | صفوف مطالب بة لكل دورة عاملة (الافتراضي 4). تتم معالجة الدفعات **بشكل متزامن**؛ التزامن الفعلي على نقطة نهاية خدمة التقييم الخاصة بك هو `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH`. | +| `EVALUATOR_POLL_IDLE_SECS` | المدة التي تنام بها العامل بين محاولات الإرسال عندما لا يكون التقييم مستحقًا (الافتراضي 2s). | +| `EVALUATOR_POLLING_INTERVAL_SECS` | البديل النهائي لإيقاع `GET /evaluate/{id}` عندما لا يكون كل من `next_poll_secs` لكل استجابة ولا `default_poll_interval_secs` لخدمة التقييم مضبوطًا (الافتراضي 10s). | +| `EVALUATOR_REQUEST_TIMEOUT_MS` | مهلة زمنية لكل طلب (الافتراضي 30000). | +| `EVALUATOR_MAX_ATTEMPTS` | بعد هذا العدد من الأخطاء العابرة يتم تسجيل النتيجة كـ `error` نهائي (الافتراضي 5). | +| `EVALUATOR_CONFIG_REFRESH_SECS` | دورة `GET /config` (الافتراضي 300). | +| `EVALUATOR_MAX_POLL_DURATION_SECS` | أقصى وقت جدار زمني قد تبقى فيه جلسة في قائمة انتظار الاستطلاع قبل إنهاؤها كـ `timeout` (الافتراضي 3600s). يحمي من خدمة تقييم تستمر في إرجاع `pending` للأبد. | + +لتشغيل النقاط التلقائية عبر النسخة الكاملة، جهز سر `agenteye-evaluator` مع كلا المفاتيح المضبوطة. +على مظاهر Kubernetes المجمعة، يقرأ الخادم `EVALUATOR_ENDPOINT` و `EVALUATOR_TOKEN` من +هذا السر الاختياري. أنشئه عبر عملية إدارة الأسرار القياسية في مؤسستك، +ثم أعد تشغيل نشر الخادم لالتقاط التغيير. + +عناصر التحكم في الضبط أعلاه لم تُربط بشكل افتراضي؛ اكشف متغيرات البيئة المقابلة +على حاوية الخادم في مظهر النشر الخاص بك إذا كنت بحاجة إلى تجاوز +الافتراضيات. + +اطّلع على [deployment.md](/ar/agenteye/deployment) لجدول متغيرات البيئة الكامل. + +--- + +## مرجع API + +| الطريقة | المسار | الإذن المطلوب | الغرض | +|---|---|---|---| +| `GET` | `/evaluations` | `evaluations:read` | نتائج نهائية للاستعلام. يدعم `session_id`, `agent_id`, `environment`, `status` (`done`/`error`/`timeout`), `ts_from`, `ts_to`, `cursor`, `limit`, `score_filters`, `latest_per_session`. `limit` افتراضي إلى 50 وقبعة عند 200 (لاحظ أن هذا يختلف عن `/events`، والذي يقبع عند 1000). `environment` يقبل قائمة مفصولة بفواصل (على سبيل المثال `environment=prod,staging`؛ تعمل القيم الفردية أيضًا. مع `latest_per_session=true` تحتوي الاستجابة على صف واحد على الأكثر لكل `session_id` (الأحدث حسب `completed_at`) يستخدمه صفحة قائمة الجلسات لطي خط زمني التقييم الخاص بالجلسة إلى عنوانها الحالي. الافتراضي كاذب (يُرجع السجل الكامل). | +| `GET` | `/evaluations/aggregate` | `evaluations:read` | صحة تقييم مجتمعة لشريحة مفلترة: عد إجمالي، تفصيل done/error/timeout، إحصائيات لكل مفتاح نتيجة (العد/المتوسط/الحد الأدنى/الحد الأقصى/p50 عبر مفاتيح `scores` التعسفية)، وخط زمني محدد بوقت. يقبل **نفس معاملات الفلتر مثل `/evaluations`** بالإضافة إلى `featured_keys` (CSV لمفاتيح النتيجة للاتجاه) و `latest_per_session`. يدعم ميزة لوحات التحكم؛ المقاييس دقيقة على جميع المجموعة المطابقة، لا مأخوذة العينات. | +| `GET` | `/evaluations/environments` | `evaluations:read` | قيم بيئة مميزة من جدول `evaluations`. يستخدم لملء منسدلات الفلتر المحصورة في بيانات التقييم القابلة للقراءة. | +| `GET` | `/evaluation-jobs` | `evaluations:read` | رؤية إلى التقييمات قيد الطيران. الفلتر حسب `status` (`pending`/`polling`). | +| `GET` | `/events` | `events:read` | دفق الأحداث الخام للجلسة. يدعم `session_id`, `agent_id`, `event_type` (CSV), `environment` (CSV), `ts_from`, `ts_to`, `cursor`, `limit`, و `order`. `order` يكون `desc` (الأحدث أولاً، الافتراضي) أو `asc` (الأقدم أولاً)؛ قيمة غير معروفة تعود إلى `desc`. استطلع الصفحات عبر `next_cursor` (معرف حدث) في الاستجابة: أرجعها كـ `cursor` للحصول على الصفحة التالية؛ مع `asc` الصفحة التالية هي الأحداث بعد معرف الهوية، مع `desc` الأحداث قبلها. `limit` افتراضي إلى 50 وقبعة عند 1000. | +| `GET` | `/sessions/:session_id/export` | `events:read` | يُرجع جسم JSON الدقيق الذي ستتلقاه خدمة التقييم لهذه الجلسة، يتم تقديمه كمرفق قابل للتنزيل باسم `session-.json`. مفيد لإعادة تشغيل جلسات الإنتاج عبر `agenteye-evaluator` للاختبار غير المتصل. البايتات متطابقة بايت إلى ما يرسله خط أنابيب خدمة التقييم. | +| `POST` | `/sessions/:session_id/re-evaluate` | `evaluations:trigger` | اضطر لتقييم طازج لجلسة؛ يعمل سواء كان هناك تقييم سابق أم لا. يتم **إلحاق** النتيجة الجديدة بخط زمني تقييم الجلسة بدلاً من الكتابة فوق الجلسة السابقة، لذا تبقى النتائج السابقة مرئية كسجل. يُرجع `202` عند الطلب، `404` لجلسة غير معروفة، `409` إذا كان تقييم قيد الطيران بالفعل. استخدم هذا بعد نشر خدمة تقييم جديدة، أو للجلسات التي لم تصدر أبدًا `agent_end`. | + +### الفلترة حسب نطاق النتيجة: `score_filters` + +يقبل `GET /evaluations` معامل `score_filters` اختياري يضيق +النتائج حسب القيم الرقمية داخل كائن `scores`. المعامل +عبارة عن قائمة مفصولة بفواصل من إدخالات `key:min..max`؛ قد يكون كلا الحدين +محذوفًا. تتحد إدخالات متعددة بـ AND منطقي. الصفوف +حيث يكون المفتاح المسمى غائبًا أو غير رقمي يتم استبعاده. قد يحمل الطلب ما يصل إلى 20 +إدخال فلتر؛ يعود تجاوز ذلك HTTP 400. + +أمثلة: +```text +# helpfulness in [0.5, 0.8] +GET /evaluations?score_filters=helpfulness:0.5..0.8 + +# tool_efficiency at most 0.3 (no lower bound) +GET /evaluations?score_filters=tool_efficiency:..0.3 + +# helpfulness >= 0.5 AND factuality >= 0.9 +GET /evaluations?score_filters=helpfulness:0.5..,factuality:0.9.. +``` + +لكل كائن استجابة `/evaluations` هذه الحقول: + +| الحقل | النوع | الملاحظات | +|---|---|---| +| `evaluation_id` | سلسلة (UUID) | المعرف الكنسي لهذا التقييم النهائي. يحصل كل تقييم نهائي على UUID جديد؛ يمكن للجلسة الواحدة أن تحتفظ بعدة. | +| `id` | سلسلة (UUID) | اسم مستعار للتوافق العكسي يحمل نفس القيمة مثل `evaluation_id`. | +| `session_id` | سلسلة | الجلسة التي انطلقت هذا التقييم عليها. يمكن للجلسة أن تحتوي على تقييمات متعددة في الخط الزمني. | +| `agent_id` | سلسلة | يحدد الوكيل الذي أنتج الجلسة. | +| `environment` | سلسلة | تسمية البيئة المنسوخة من الجلسة. | +| `status` | التعداد | واحد من `"done"`, `"error"`, `"timeout"`. | +| `scores` | كائن \| null | النتائج التي أرجعتها خدمة التقييم الخاصة بك. | +| `reasoning` | كائن \| null | خريطة تبرير اختيارية لكل نتيجة أرجعتها خدمة التقييم الخاصة بك. عادة ما تعكس المفاتيح تلك الموجودة في `scores`. تُظهر لوحة التحكم كل مدخل تحت شريط النتيجة الخاص به. | +| `summary` | سلسلة \| null | سرد اختياري لفقرة واحدة يُرجع من قبل خدمة التقييم الخاصة بك. تُظهر لوحة التحكم هذا فوق تفصيل لكل نتيجة كعنوان التقييم. | +| `error` | سلسلة \| null | معبأ على `"error"` / `"timeout"` فقط. | +| `attempt_count` | عدد صحيح | عدد محاولات الإرسال (≥ 1). | +| `duration_ms` | عدد صحيح \| null | مدة المحاولة الأخيرة. | +| `completed_at` | سلسلة (ISO 8601 UTC) | عندما تم تسجيل النتيجة النهائية. يتم ترتيب النتائج حسب `completed_at` (الأحدث أولاً). | +| `created_at` | سلسلة (ISO 8601 UTC) | يحمل نفس الطابع الزمني مثل `completed_at` (دلالات الكتابة مرة واحدة). | + +--- + +## الأذونات + +| الإذن | الأذونات | +|---|---| +| `evaluations:read` | نتائج التقييم قائمة، عرض النتائج في لوحة التحكم، وتحميل مقاييس صحة لوحة التحكم. | +| `evaluations:trigger` | ضع تقييمًا يدويًا في قائمة الانتظار لجلسة عبر `POST /sessions/:session_id/re-evaluate` أو زر لوحة التحكم لإعادة التقييم. | +| `dashboards:read` | عرض لوحات التحكم المحفوظة (تحتاج أيضًا إلى `evaluations:read` لتحميل مقاييسها). | +| `dashboards:write` | إنشاء وتعديل لوحات التحكم. | +| `dashboards:delete` | حذف لوحات التحكم. | + +المسؤول التمهيدي (`ADMIN_KEY`, `ADMIN_EMAIL`) يتلقى هذه تلقائيًا. + +--- + +## عرض النتائج + +- **`/sessions/`**: خط زمني للأحداث + عمود يميني يعرض + النتائج والأخطاء من محاولة الإرسال. إذا كان مفتاحك يحتوي على + `evaluations:trigger`، يظهر زر **re-evaluate** بجانب زر التصدير، + مفيد للجلسات التي لم تصدر أبدًا `agent_end`، أو لتحديث + النتائج بعد نشر خدمة تقييم جديدة. تستطلع لوحة التحكم النتيجة الجديدة وتحدث العمود الأيمن عند وصوله. +- **`/sessions`**: شبكة جلسة قابلة للفلترة؛ يعرض عمود النتيجة حالة التقييم والنتائج + لكل جلسة على الفور. +- **`/dashboards`**: طرق صحة التقييم المحفوظة (اطّلع على [لوحات التحكم](#dashboards) أدناه). + +![شبكة الجلسات مع حبوب حالة التقييم لكل جلسة وشارات النتيجة المشفرة بالألوان (helpfulness, factuality, tool_efficiency, safety, coherence)](/agenteye/images/sessions-list.png) + +*تعرض شبكة الجلسات حالة التقييم والنتائج لكل عملية تشغيل على الفور؛ تجعل شارات أحمر/كهرمان/أخضر النتائج المنخفضة بارزة.* + +![عرض تفصيل الجلسة مع درجات التقييم وحالة الإرسال في العمود الأيمن](/agenteye/images/session-detail.png) + +*يعرض فتح جلسة الخط الزمني الكامل بجانب درجات التقييم وأي خطأ في المرسل في العمود الأيمن.* + +--- + +## لوحات التحكم + +تسمح صفحة **لوحات التحكم** (`/dashboards`) بحفظ مزيج من فلاتر التقييم +كعرض مسمى وقابل لإعادة الاستخدام ومشاهدة أداء تلك الشريحة من التقييمات +بضربة واحدة. **يتم مشاركة لوحات التحكم عبر مؤسستك بأكملها**؛ +كل شخص لديه `dashboards:read` يرى نفس المجموعة. + +تثبت كل لوحة تحكم: + +- **الفلاتر**: نفس الضوابط الموجودة على صفحة الجلسات: البيئة، الحالة، + الوكيل، نافذة زمنية متدحرجة، وفلاتر نطاق النتيجة (`key:min..max`). +- **تكوين العرض**: مفاتيح النتيجة المراد عرضها، حدود صحة أخضر/كهرمان/أحمر، + اللوحات المراد عرضها، وما إذا كان يجب طي أحدث تقييم لكل جلسة. + +تعرض كل بطاقة عدد الجلسات المطابقة، تفصيل done/error/timeout، +متوسط كل نتيجة متميزة، وخط زمني صغير في الاتجاه. يعرض فتح +لوحة تحكم اللوحات بالحجم الكامل؛ **استخدم الجلسات** تنقلك إلى صفحة الجلسات +مع التصفية المسبقة إلى تلك الشريحة بالضبط. يتم حساب المقاييس +من جانب الخادم على جميع المجموعات المطابقة (عبر `GET /evaluations/aggregate`)، +لذا تكون الأرقام دقيقة بدلاً من المعاينة. + +![لوحة تحكم صحة التقييم مع أشرطة متوسط النتيجة لكل بعد مقيّم، وتفصيل أداة ok مقابل خطأ، وأفضل الأدوات، واتجاه الأحداث في الساعة](/agenteye/images/dashboard-quality.png) + +**الأذونات:** يتطلب العرض كل من `dashboards:read` و `evaluations:read`؛ +ينشئ ويعدل يتطلب `dashboards:write`؛ حذف يتطلب `dashboards:delete`. +يتلقى المسؤول التمهيدي كل هذه تلقائيًا. + +--- + +## استكشاف الأخطاء + +**توجد جلسات لكن لم يتم إنشاء تقييمات.** أكد أن `EVALUATOR_ENDPOINT` +معيّن على عملية الخادم، أن الخادم وخدمة التقييم يشتركان في نفس +قيمة `EVALUATOR_TOKEN`، وأن نقطة نهاية `/health` الخاصة بخدمة التقييم +يمكن الوصول إليها من الخادم. مع عدم تعيين `EVALUATOR_ENDPOINT` خط الأنابيب هو +عدم تشغيل. + +**التقييمات قيد الطيران تتراكم.** استعلم `GET /evaluation-jobs` لعرض +قائمة الانتظار قيد الطيران. فحص `attempt_count`, `next_attempt_at`, و `last_error` +على كل صف. الأسباب الشائعة: خدمة المقيّم غير قابلة للوصول أو تُرجع 5xx +(أعيدت المحاولة مع التراجع)، خطأ في `EVALUATOR_TOKEN` (401 نهائي)، أو +مقيّم غير متزامن يُرجع `pending` إلى الأبد (انظر أدناه). + +**انتهت الجلسات لكن لم يتم تقييم نهائي.** استعلم +`GET /evaluation-jobs?status=polling`؛ قد تبقى النتيجة قيد الطيران. +إذا كانت وظيفة عالقة في `pending`، يواجه الخادم مشكلة في الوصول إلى +خدمة التقييم؛ تحقق من أن خدمة التقييم قيد التشغيل وأن `EVALUATOR_TOKEN` تطابق. + +**`HTTP 401 من خدمة التقييم: رمز متحمل غير صالح`.** `EVALUATOR_TOKEN` +على الخادم لا يتطابق مع القيمة التي تم تكوين خدمة التقييم بها. +يجب أن تكون متطابقة. + +**مقيّم غير متزامن يُرجع `pending` إلى الأبد.** يستطلع الخادم +`GET /evaluate/{job_id}` حتى تُرجع خدمة التقييم `done` أو `error`، أو +حتى `EVALUATOR_MAX_POLL_DURATION_SECS` (الافتراضي 1 ساعة) ينقضي. بعد الحد الأقصى +يتم تسجيل التقييم كـ `timeout` وإزالته من قائمة الانتظار قيد الطيران. +ارفع `EVALUATOR_MAX_POLL_DURATION_SECS` إذا كانت خدمة التقييم الخاصة بك تحتاج بشرعية +إلى وقت أطول من الافتراضي. \ No newline at end of file diff --git a/docs/ar/agenteye/getting-started.mdx b/docs/ar/agenteye/getting-started.mdx new file mode 100644 index 00000000..2ae34b19 --- /dev/null +++ b/docs/ar/agenteye/getting-started.mdx @@ -0,0 +1,236 @@ +--- +--- +title: "البدء مع AgentEye" +description: "وثائق البدء مع AgentEye." +--- + + +يرشدك هذا الدليل خلال إعداد AgentEye كامل: نشر الخادم والشاشة الرئيسية، وتثبيت جامع البيانات على جهاز الوكيل، وتجهيز كود وكيل Python الخاص بك. + +--- + +## ما هو AgentEye؟ + +AgentEye هي **منصة قابلة للاستضافة ذاتياً للمراقبة والتقييم لوكلاء الذكاء الاصطناعي**. تسجل ما يفعله وكلاؤك — في كل خطوة من خطوات التشغيل — وتقيّم تلقائياً جودة كل تشغيل مكتمل، حتى تتمكن من رؤية كيف يتصرف وكلاؤك في الإنتاج واكتشاف التراجعات قبل أن يكتشفها مستخدموك. + +تتدفق البيانات في اتجاه واحد: ينبعث كود الوكيل **الأحداث** عبر **Python SDK** → محل جمع بيانات خفيف الوزن يجمع البيانات وينقلها إلى **الخادم** → يتم تخزين الأحداث والتحليلات في **ClickHouse** (الحالة التشغيلية مثل المؤسسات والمستخدمين ومفاتيح API والشاشات والاستعلامات المحفوظة تعيش في **Postgres**) → تستكشف كل شيء في **الشاشة الرئيسية**. + +ما ستحصل عليه: + +- **الأحداث** — سجل خام لكل خطوة من كل تشغيل وكيل (استدعاءات الأدوات، استدعاءات النموذج، الخطافات، الأخطاء). +- **الجلسات** — تلك الأحداث مدمجة في صف واحد لكل تشغيل، يتم **تقييم كل منها تلقائياً** وتسجيله. +- **التقييمات** — درجات الجودة التي تنتجها خدمات المقيّم الخاصة بك، بحيث يظهر انخفاض الجودة بدون مراجعة يدوية. +- **الاستعلامات والشاشات** — استعلامات ClickHouse SQL المحفوظة على بيانتك، مرسومة في شاشات مشتركة في نطاق المؤسسة. +- **التنبيهات والحوادث** — قواعد العتبة التي تخطرك (بريد إلكتروني، Slack، webhook، في الشاشة) بالإضافة إلى سير عمل الحوادث لفرزها. +- **CLI والمساعد الذكي** — عميل طرفي (`agenteye`) ومساعد في الشاشة للإجابة على الأسئلة باللغة الطبيعية. + +تقوم بتشغيل كل هذا في البنية التحتية الخاصة بك، كمكدس Docker Compose واحد (هذا الدليل) أو تثبيت Kubernetes للإنتاج أو وحدة واحدة في نفس المكان. يعد الجزء المتبقي من هذا الدليل مكدس Compose من النهاية إلى النهاية. + +--- + +## الخطوة 1: المصادقة + +يتم توزيع جميع عناصر AgentEye من منظمة `agenteye-enterprise` على GitHub. بصفتك مطوراً في المؤسسة، يمكنك إنشاء رمز وصول شخصي لـ GitHub الخاص بك. اتبع [enterprise-docs/github-token.md](/ar/agenteye/github-token) للحصول على الخطوات الدقيقة والأذونات المطلوبة. + +```bash +export AGENTEYE_TOKEN= + +# Authenticate Docker against GHCR +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +--- + +## الخطوة 2: نشر الخادم والشاشة الرئيسية + +يستقبل الخادم الأحداث من جامعي البيانات ويجعلها قابلة للاستعلام عنها؛ الشاشة الرئيسية هي المكان الذي تستكشف فيه الأحداث. تعيش الأحداث المدخلة والتحليلات في ClickHouse (متجر التحليلات المطلوب)، بينما يحتفظ Postgres بالحالة التشغيلية مثل المؤسسات والمستخدمين ومفاتيح API والشاشات والاستعلامات المحفوظة. + +**تحميل ملف compose المنشور:** + +```bash +mkdir -p ./agenteye +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + https://raw.githubusercontent.com/agenteye-enterprise/releases/main/docker-compose.yml \ + -o ./agenteye/docker-compose.yml +cd agenteye +``` + +**اضبط أسرارك:** + +أنشئ ملف `.env` حتى لا ينبغي للنشر أن يعمل على بيانات اعتماد `admin` الافتراضية. على الأقل اضبط `ADMIN_KEY` و `POSTGRES_PASSWORD`: + +```bash +POSTGRES_PASSWORD=your-db-password +ADMIN_KEY=your-admin-secret +``` + +قم أيضاً بتصدير `ADMIN_KEY` في الجلسة الحالية حتى تتمكن الخطوات اللاحقة (مثل `curl` في الخطوة 3) من الإشارة إليه مباشرة: + +```bash +export ADMIN_KEY=your-admin-secret +``` + +**ابدأ المكدس:** + +```bash +docker compose up -d +``` + +يضع هذا المكدس الكامل، بما في ذلك متجر تحليلات ClickHouse المطلوب وذاكرة تخزين مؤقت Redis اختيارية، جنباً إلى جنب مع الخادم والشاشة الرئيسية. يجب أن يكون ClickHouse صحياً لبدء الخادم. + +الخادم يستمع الآن على `http://localhost:8080` والشاشة الرئيسية على `http://localhost:3000`. + +لنشر الإنتاج (Postgres مخصص، TLS، proxy عكسي)، انظر [enterprise-docs/deployment.md](/ar/agenteye/deployment). + +--- + +## الخطوة 3: إنشاء مفتاح API لجامع البيانات + +يقوم كل جامع بيانات بالمصادقة باستخدام مفتاح API محدود النطاق. استخدم `ADMIN_KEY` الذي قمت بتعيينه في الخطوة 2 لإنشاء واحد: + +```bash +curl -s -X POST http://localhost:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{"name":"prod-collector","key":"your-collector-secret","permissions":["events:add"]}' +``` + +تقدم قيمة `key` بنفسك؛ استخدمها في تكوين جامع البيانات في الخطوة 4. انظر [enterprise-docs/api-keys.md](/ar/agenteye/api-keys) لإدارة المفاتيح الكاملة. + +--- + +## الخطوة 4: تثبيت جامع البيانات + +على كل جهاز يقوم بتشغيل وكلاء الذكاء الاصطناعي الخاصة بك، قم بتثبيت خدمة جامع البيانات. + +**تحميل الملف الثنائي (Linux x86_64):** + +```bash +VERSION=0.0.1-beta.13 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "collector/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-collector-linux-x86_64' +chmod +x agenteye-collector-linux-x86_64 +sudo mv agenteye-collector-linux-x86_64 /usr/local/bin/agenteye-collector +``` + +> يحمل هذا الملف الثنائي **Linux x86_64**. لـ macOS (Apple Silicon أو Intel) أو Linux arm64 أو إعداد Docker / systemd / launchd، انظر [collector-installation.md](/ar/agenteye/collector-installation)، والذي يسرد التحميل لكل منصة — الأمر أعلاه يثبت ملف ثنائي Linux لن يعمل في أي مكان آخر. + +**التكوين:** + +```bash +mkdir -p ~/.agenteye +cat > ~/.agenteye/config.json </…`). + +- **الاستعلامات** (`//queries`): ابدأ من مكتبة استعلامات محفوظة وقابلة لإعادة الاستخدام على أحداثك والتقييمات (إعدادات مدمجة مسبقاً بالإضافة إلى إعداداتك الخاصة)… + +![مكتبة الاستعلامات المحفوظة: شبكة استعلامات قابلة لإعادة الاستخدام، كل من الإعدادات المسبقة والاستعلامات المخصصة](/agenteye/images/queries.png) + + …ثم افتح واحد في منشئ SQL لتعديله وتشغيله مع النتائج المباشرة: + +![منشئ استعلام SQL يقوم بتشغيل استعلام محفوظ، مع شريط الجانب للمخطط ونبكة النتائج المباشرة](/agenteye/images/query-lab.png) + +- **الشاشات** (`//dashboards`): حدّد الاستعلامات كبلاط خطية أو شريطية أو منطقة أو دائرية في شاشات مشتركة في جميع أنحاء المؤسسة. + +![شاشة مدمجة من الاستعلامات المحفوظة: خط أحداث لكل ساعة وشريط أخطاء حسب النوع ومخطط منطقة زمن انتظار والرموز حسب النموذج](/agenteye/images/dashboard-fleet.png) + +- **التنبيهات** (`//alerts`): ارفع أي عتبة إلى قاعدة الصفحة التي تخطرك بالبريد الإلكتروني أو Slack أو webhook أو في الشاشة. انظر [enterprise-docs/alerts.md](/ar/agenteye/alerts). + +--- + +## الخطوات التالية + +- [النشر](/ar/agenteye/deployment): تعزيز للإنتاج +- [مفاتيح API](/ar/agenteye/api-keys): إدارة الوصول +- [استكشاف الأخطاء](/ar/agenteye/troubleshooting): تشخيص المشاكل \ No newline at end of file diff --git a/docs/ar/agenteye/github-token.mdx b/docs/ar/agenteye/github-token.mdx new file mode 100644 index 00000000..9c7d311b --- /dev/null +++ b/docs/ar/agenteye/github-token.mdx @@ -0,0 +1,132 @@ +--- +title: "إعداد GitHub Token" +description: "توثيق إعداد GitHub Token في AgentEye." +--- + + +GitHub Personal Access Token (PAT) هو بيانات الاعتماد الوحيدة التي تفتح جميع عناصر AgentEye. باستخدام رمز واحد، يمكنك سحب صور Docker وتنزيل ملفات الإصدار وتثبيت عجلات Python، دون الحاجة إلى عمليات تسجيل منفصلة لكل مكون ولا أسرار مشتركة يجب تداولها. يتم توزيع جميع عناصر AgentEye من منظمة `agenteye-enterprise` على GitHub؛ بمجرد أن يتم منح مؤسستك حق الوصول، ينشئ كل مطور أو مشغل رمزه الخاص ويديره بشكل مستقل، بحيث يبقى الوصول قابلاً للتدقيق والإلغاء لكل شخص. + +عيّن الرمز كمتغير بيئة وبيانات اعتماد Docker مرة واحدة لكل آلة: + +```bash +export AGENTEYE_TOKEN= +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +> **ملاحظة اسم المستخدم:** GHCR يتجاهل اسم المستخدم في `docker login` ويتحقق من الهوية بالكامل من خلال الرمز، لذا فإن أي قيمة غير فارغة تعمل. تستخدم هذه الوثائق `-u x` للإيجاز؛ قد تستخدم بيانات النشر التي تنشئ سر image-pull على Kubernetes اسم مستخدم أكثر وصفياً مثل `agenteye-enterprise`. كلاهما مقبول. + +--- + +## الخيار أ: الرمز الكلاسيكي (موصى به) + +الرمز الكلاسيكي هو الخيار الأكثر موثوقية لـ AgentEye، لأن تدفق `docker login` وسحب الصور في GHCR لديه أوسع دعم أكثر اتساقاً للرموز الكلاسيكية. نطاقان يغطيان كل ما تحتاجه (سحب الصور وتنزيل عناصر الإصدار)، لذا تتحقق من الهوية مرة واحدة وتتابع بدون استكشاف أخطاء السجل. أحدهما، `read:packages`، يكون للقراءة فقط حقاً؛ الآخر، `repo`، هو الوحيد من الأنطقة الكلاسيكية التي تمنح الوصول إلى عناصر الإصدار الخاصة، وهو متعمد أن يكون واسعاً — يعرّفه GitHub على أنه تحكم كامل (قراءة وكتابة) للمستودعات الخاصة. + +### 1. إنشاء الرمز + +انتقل إلى **GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic) → Generate new token (classic)**. + +| الحقل | القيمة | +|---|---| +| **Note** | `agenteye-` (مثلاً `agenteye-prod-server`) | +| **Expiration** | عيّن تاريخ انتهاء الصلاحية المناسب لسياستك الأمنية؛ 90 يوماً هو الافتراضي المعقول | + +> **ملاحظة التسمية:** يسمي GitHub هذا الحقل **Note** للرموز الكلاسيكية و**Token name** للرموز الدقيقة. تخدم الاثنتان نفس الغرض: معرّف يمكن قراءته بشرياً للتدقيق والإلغاء لاحقاً. + +### 2. حدد الأنطقة + +| النطاق | السبب في الحاجة إليه | +|---|---| +| `read:packages` | سحب صور Docker من `ghcr.io/agenteye-enterprise/` وتنزيل عناصر الحزم | +| `repo` | قراءة محتويات المستودع الخاصة والملفات الأولية وعناصر الإصدار من `agenteye-enterprise/releases`. هذا هو نطاق GitHub الواسع "تحكم كامل بالمستودعات الخاصة" (قراءة وكتابة)، وليس نطاق للقراءة فقط — إنه ببساطة الوحيد من الأنطقة الكلاسيكية الذي يمنح الوصول إلى عناصر الإصدار الخاصة | + +لا توجد أنطقة أخرى مطلوبة. + +### 3. توليد ونسخ الرمز + +انقر على **Generate token** واحسب القيمة على الفور؛ يُعرض مرة واحدة فقط. خزّنها في مدير الأسرار أو بيئتك. + +--- + +## الخيار ب: الرمز الدقيق + +الرموز الدقيقة تحدد نطاق الوصول إلى مستودعات وأذونات محددة، مما يجعلها أضيق خيار امتياز أقل. اختر هذا المسار عندما تفوض سياسة أمان مؤسستك الرموز الدقيقة. + +> **ملاحظة:** دعم GHCR للرموز الدقيقة أقل اتساقاً من دعم الرموز الكلاسيكية. إذا فشل `docker login` أو `docker pull` بعد اتباع هذه الخطوات، عد إلى رمز كلاسيكي (الخيار أ). + +### 1. إنشاء الرمز + +انتقل إلى **GitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokens → Generate new token**. + +| الحقل | القيمة | +|---|---| +| **Token name** | `agenteye-` (مثلاً `agenteye-prod-server`) | +| **Expiration** | عيّن تاريخ انتهاء الصلاحية المناسب لسياستك الأمنية؛ 90 يوماً هو الافتراضي المعقول | +| **Resource owner** | `agenteye-enterprise` | +| **Repository access** | **Only select repositories** → `agenteye-enterprise/releases` | + +### 2. تعيين أذونات المستودع + +ضمن **Permissions → Repository permissions**، عيّن: + +| الإذن | الوصول | +|---|---| +| **Contents** | للقراءة فقط | +| **Packages** | للقراءة فقط | + +جميع الأذونات الأخرى يمكن أن تبقى **No access**. + +> **ملاحظة:** إذا كانت صور الحاويات (`ghcr.io/agenteye-enterprise/...`) منشورة كحزم على مستوى المنظمة بدلاً من الحزم المرتبطة بالمستودع، قد يفشل تسجيل Docker مع الأذونات ذات النطاق المستودع وحدها. في هذه الحالة، أضف إذن على مستوى المنظمة: **Permissions → Organization permissions → Packages: Read-only**. + +### 3. ما الذي يمنحه كل إذن + +| الإذن | المستخدم في | +|---|---| +| Contents: للقراءة فقط | تنزيل `docker-compose.yml` وملفات الإصدار وعجلات Python من `agenteye-enterprise/releases` | +| Packages: للقراءة فقط | سحب صور Docker من `ghcr.io/agenteye-enterprise/` | + +### 4. توليد ونسخ الرمز + +انقر على **Generate token** واحسب القيمة على الفور؛ يُعرض مرة واحدة فقط. خزّنها في مدير الأسرار أو بيئتك. + +--- + +## تدوير الرمز + +تدوير الرموز على جدول زمني منتظم يحافظ على الوصول قابلاً للتدقيق ويحد من نطاق الضرر إذا تسريب بيانات الاعتماد. يمكن للرموز أيضاً أن تنتهي صلاحيتها أو يتم إلغاؤها في أي وقت، لذا فإن التدوير هو الطريقة الروتينية للبقاء مصرحاً. للقيام بالتدوير: + +1. أنشئ رمزاً جديداً باستخدام الخطوات أعلاه. +2. حدّث `AGENTEYE_TOKEN` في بيئتك أو مدير الأسرار. +3. أعد مصادقة Docker: `echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin` +4. ألغِ الرمز القديم في GitHub → Settings → Developer settings → Personal access tokens، ثم افتح صفحة **Tokens (classic)** أو **Fine-grained tokens** الفرعية التي تطابق نوع الرمز وحذفها. + +--- + +## تحقق من رمزك + +أكّد أن الرمز يعمل قبل توصيله بنشر، حتى تظهر أخطاء المصادقة هنا بدلاً من منتصف النشر. تمارس كل أمر أحد الأنطقة أعلاه: + +```bash +# Packages scope - authenticate Docker against GHCR +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin + +# Contents scope - fetch a raw release file +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + https://raw.githubusercontent.com/agenteye-enterprise/releases/main/docker-compose.yml \ + -o /tmp/agenteye-compose-check.yml +``` + +يؤكد `docker login` الناجح نطاق الحزمة؛ الملف المحمل يؤكد نطاق المحتويات. + +--- + +## استكشاف الأخطاء + +| الأعراض | السبب المحتمل | الحل | +|---|---|---| +| `docker login` يعود 401 | الرمز مفقود `Packages: Read-only` (دقيق) أو `read:packages` (كلاسيكي) | أضف نطاق الحزمة وأعد التوليد | +| `curl` يعود 404 على URLs GitHub الأولية | الرمز مفقود `Contents: Read-only` أو نطاق `repo` | أضف نطاق المحتويات وأعد التوليد | +| `gh release download` يعود 403 | الرمز غير مصرح به لـ `agenteye-enterprise/releases` | تحقق من أن المستودع مدرج في وصول مستودع الرمز الدقيق، أو استخدم رمزاً كلاسيكياً مع نطاق `repo` | +| الرمز مقبول لكن الصور غير موجودة | إذن حزمة على مستوى المنظمة مفقود على الرمز الدقيق | أضف إذن `Packages: Read-only` على مستوى المنظمة | + +للمشاكل المتعلقة بالوصول، اتصل بـ `support@exosphere.host`. \ No newline at end of file diff --git a/docs/ar/agenteye/health-monitoring.mdx b/docs/ar/agenteye/health-monitoring.mdx new file mode 100644 index 00000000..e9679c3c --- /dev/null +++ b/docs/ar/agenteye/health-monitoring.mdx @@ -0,0 +1,102 @@ +--- +--- +title: "مراقبة الصحة" +description: "وثائق مراقبة صحة AgentEye." +--- + + +اعرف متى يكون نشر AgentEye **نفسه** معطلاً أو متدهوراً، وليس فقط عندما تسيء وكلاؤك التصرف. الكشف **أصلي في Kubernetes** وبشكل حاسم، +**مستقل عن AgentEye**: فهو يقرأ حالة الحاوية من مستوى تحكم Kubernetes ويفحص التبعيات الصعبة في AgentEye، لذا فإنه لا يزال ينطلق عندما يكون الخادم أو ClickHouse أو Postgres هو الذي تعطل. + +هناك طبقتان. الأولى مدمجة؛ الثانية اختيارية. + +## 1. الجاهزية التي تدرك التبعيات (مدمجة) + +يعرّض الخادم نقطتي مسبار بمهام مختلفة عن قصد: + +| النقطة | المسبار | الفحوصات | المصادقة | +|---|---|---|---| +| `GET /health` | liveness | العملية حية (`{"status":"ok"}` دائماً) | بدون | +| `GET /ready` | readiness | يمكنها الخدمة فعلاً: **Postgres + ClickHouse** قابلة للوصول | بدون | + +`/ready` تُرجع `200` مع `"status":"ready"` وكل فحص `"ok"` عندما تكون كلا التبعيات الصعبة قابلة للوصول، و`503` مع `"status":"not_ready"` عندما تكون إحداهما غير قابلة للوصول. تحمل كلا الاستجابتين جسماً صغيراً: + +```json +{ "status": "not_ready", + "checks": { "postgres": "ok", "clickhouse": "down", "redis": "not_configured" } } +``` + +Redis عبارة عن ذاكرة تخزين مؤقت اختيارية يتدهور الخادم بدونها، لذا يتم الإبلاغ عنها للمعلومات لكنها **لا تفشل** الجاهزية **أبداً**. تظهر `"ok"` عند تكوين ذاكرة تخزين مؤقت و`"not_configured"` بخلاف ذلك؛ لا تكون **أبداً** `"down"`. + +في بيانات Kubernetes المدرجة، يشير مسبار **الجاهزية** إلى `/ready` و**liveness** يبقى على `/health`. التأثير: خادم *يعمل لكن لا يمكنه الوصول إلى قاعدة البيانات الخاصة به* يتم إزالته من الخدمة ويظهر كـ `NotReady`، وهي حالة يمكن لمراقبة العنقود الخاصة بك (أدناه) أن تنبه عليها، بينما يبقى liveness رخيصاً حتى لا يؤدي خلل التبعية المختصر أبداً إلى إعادة تشغيل الحاوية. يستخدم المسبار عتبة فشل سخية حتى لا يؤدي الخلل المؤقت إلى تذبذب النسخ المتطابقة خارج الدوران. + +## 2. تنبيهات فشل الحاوية مع Robusta (اختيارية) + +[Robusta](https://github.com/robusta-dev/robusta) عبارة عن مراقب أصلي في Kubernetes +يراقب خادم API وينشر فشل الحاويات (`CrashLoopBackOff`، +`OOMKilled`، `ImagePullBackOff`، `Pending`/`NotReady`، `Failed`، الإخلاءات) إلى +Slack. لأنه يراقب مستوى التحكم بدلاً من السؤال عن AgentEye، فإنه ينبه حتى عندما لا يستطيع AgentEye الخدمة على الإطلاق. + +يتم شحن Robusta كإضافة اختيارية في حزمة الإصدار. فعّلها باستخدام مخطط Robusta Helm القياسي وملف القيم الصغير الموضح أدناه: + +1. أضف مستودع المخطط واحصل على **رمز الروبوت** الخاص بـ Slack (`xoxb-…`) للقناة: + + ```bash + helm repo add robusta https://robusta-charts.storage.googleapis.com + helm repo update + ``` + + لأن التكوين أدناه يحافظ على كل شيء داخل العنقود + (`disableCloudRouting: true`)، يأتي الرمز من تطبيق Slack ذاتي الاستضافة: + أنشئ تطبيقاً في `https://api.slack.com/apps`، أضف نطاق الروبوت `chat:write`، + ثبّته على مساحة العمل الخاصة بك، انسخ **Bot User OAuth Token** (`xoxb-…`)، و + ادعُ الروبوت إلى القناة (`/invite @your-app`). + +2. أنشئ `values.yaml` بعلامة لكل نشر (`clusterName`) وقناة Slack الخاصة بك، + محدودة بـ namespace `agenteye`: + + ```yaml + clusterName: "acme-prod" # علامة لكل نشر؛ تظهر على كل تنبيه + enablePrometheusStack: false # تنبيهات انهيار الحاوية فقط؛ لا مكدس متري + disableCloudRouting: true # التسليم إلى Slack مباشرة، داخل العنقود + sinksConfig: + - slack_sink: + name: vendor_slack + slack_channel: "agenteye-fleet-health" + api_key: "REPLACE_WITH_SLACK_BOT_TOKEN" # xoxb-… (فضّل --set أو سر) + scope: + include: + - namespace: [agenteye] # تنبيهات namespace AgentEye فقط؛ احذف للتوسيع + ``` + +3. ثبّت، مع تثبيت `--version` على إصدار مخطط Robusta معروف بأنه جيد + ([releases](https://github.com/robusta-dev/robusta/releases)) حتى لا تثبّت + مخطط لم يتم اختباره: + + ```bash + helm install robusta robusta/robusta \ + --namespace robusta --create-namespace \ + --version \ + -f values.yaml \ + --set sinksConfig[0].slack_sink.api_key=$ROBUSTA_SLACK_TOKEN + ``` + +### ما تبلغ عنه + +- **حالة الحاوية** في Kubernetes (حاوية AgentEye أي واحدة تفشل ولماذا) و**علامة الصورة** لكل حاوية، أي **الإصدار** من المكون الذي يعمل. +- **لا بيانات حدث AgentEye ولا بيانات عملاء** تغادر العنقود أبداً. +- تقيّد القيم المدرجة التنبيهات بـ **namespace `agenteye`**، لذا لا يتم الإبلاغ عن الأحمال غير ذات الصلة في نفس العنقود. + +### مكان واحد لكل نشر + +وجّه كل Robusta لكل نشر إلى **قناة Slack مشتركة واحدة**، لكل منها `clusterName` خاص به. يتم تحديد كل تنبيه بهذه العلامة، لذا تُظهر قناة واحدة صحة أسطول كامل الخاص بك، ويمكنك معرفة النشر الذي تأثر بنظرة واحدة. + +### انقطاعات العنقود الكامل + +لا يمكن لمراقب داخل العنقود بحتة أن يبلغ عن **انقطاع عنقود أو شبكة كاملة** +(ينقطع مع العنقود). إذا كنت بحاجة إلى ذلك، فعّل **Robusta UI sink** الاختيار: عيّن `disableCloudRouting: false` وأضف `robusta_sink` (برمز من `robusta gen-config`) إلى `sinksConfig`. فهي تضيف لوحة معلومات متعددة العناقيد مجمعة وتحدد أي عنقود يتوقف عن الفحص. + +## استكشاف الأخطاء + +انظر قسم **Health Monitoring** في +[enterprise-docs/troubleshooting.md](/ar/agenteye/troubleshooting) للحصول على "عدم وصول التنبيهات" و"الخادم يبقي يتذبذب `NotReady`". \ No newline at end of file diff --git a/docs/ar/agenteye/kubernetes-deployment.mdx b/docs/ar/agenteye/kubernetes-deployment.mdx new file mode 100644 index 00000000..551b9d53 --- /dev/null +++ b/docs/ar/agenteye/kubernetes-deployment.mdx @@ -0,0 +1,786 @@ +--- +title: "دليل نشر Kubernetes" +description: "وثائق دليل نشر AgentEye على Kubernetes." +--- + +يقوم هذا الدليل بنشر مجموعة AgentEye الكاملة على مجموعة Kubernetes مخصصة: + +- **ClickHouse 24.8** -- مخزن تحليلات الأحداث والتقييمات الموثوق (StatefulSet بحجم وحدة تخزين دائمة 100Gi). مطلوب: الخادم يرفض البدء بدونه. +- **PostgreSQL 16** -- مخزن البيانات العلائقية/البيانات الوصفية للمنظمات ومفاتيح API والمستخدمين لوحات المعلومات والاستعلامات المحفوظة والمصادقة (StatefulSet بحجم وحدة تخزين دائمة 50Gi) +- **Redis 7.2** -- ذاكرة تخزين مؤقت مشتركة اختيارية وخادم تحديد المعدل؛ يتدهور الخادم ولوحة المعلومات بشكل أنيق إذا كان غير متاح +- **خادم AgentEye** -- واجهة برمجية Rust لالتقاط الأحداث والتحليلات وإدارة المفاتيح (نسختان من البدائل) +- **لوحة معلومات AgentEye** -- واجهة ويب Next.js (نسختان من البدائل) +- **مساعد AI (خدمة الوكيل)** -- مساعد اختياري للقراءة فقط داخل لوحة المعلومات على المنفذ 9100؛ خامل حتى يتم تكوين نقطة نهاية LLM +- **Traefik (عام)** -- وحدة تحكم الإدخال لحركة المجمع، محمية بـ mTLS +- **Traefik (لوحة المعلومات)** -- وحدة تحكم الإدخال للوحة المعلومات، للشبكة الخاصة فقط/قائمة السماح بـ IP +- **cert-manager** -- شهادات TLS و CA خاص mTLS +- **وظيفة Backup CronJob** -- دمج يومي لـ PostgreSQL + ClickHouse في الساعة 03:00 UTC +- **مراقب تجديد الشهادات** -- تنبيهات عند اقتراب انتهاء صلاحية شهادات العميل + +**الوقت المقدر:** 60-90 دقيقة للنشر الأول. + +بالنسبة لنموذج النشر المدار حيث تتعامل Exosphere مع كل ذلك نيابة عنك، راجع [enterprise-docs/managed-deployment.md](/ar/agenteye/managed-deployment). + +--- + +## المتطلبات الأساسية + +قم بتشغيل كل أمر تحقق قبل البدء. يجب أن تمر كل فحص. + +| المتطلب | الحد الأدنى | أمر التحقق | المتوقع | +|---|---|---|---| +| مجموعة Kubernetes | 1.27+ | `kubectl version` | Server Version >= v1.27 | +| Kustomize (مدمج في kubectl) | Kustomize v1.14+ (يتم شحنه داخل kubectl 1.27+) | `kubectl kustomize --help` | يطبع نص الاستخدام | +| Helm | v3 | `helm version` | `Version:"v3.x.x"` | +| RBAC مسؤول المجموعة | -- | `kubectl auth can-i create namespaces` | `yes` | +| فئة التخزين الافتراضية | -- | `kubectl get storageclass` | صف واحد على الأقل محددة `(default)` | +| دعم LoadBalancer | -- | يعتمد على السحابة (EKS و GKE و AKS جميعها تدعم هذا افتراضياً) | -- | +| GitHub PAT | -- | `echo $AGENTEYE_TOKEN` | غير فارغ (انظر [enterprise-docs/github-token.md](/ar/agenteye/github-token)) | +| openssl | -- | `openssl version` | OpenSSL 1.x أو 3.x | +| دلو التخزين السحابي | -- | لـ PostgreSQL + ClickHouse backups (S3 أو GCS أو Azure Blob) | -- | + +**حجم المجموعة:** 3 عقد على الأقل، 4 vCPU / 8 GB RAM لكل منها. انظر [enterprise-docs/managed-deployment.md](/ar/agenteye/managed-deployment) للمتطلبات الكاملة. + +### قم بتشغيل جميع الفحوصات مرة واحدة + +```bash +echo "--- Prerequisites Check ---" +kubectl version --client -o yaml 2>/dev/null | grep -q gitVersion && echo "PASS: kubectl" || echo "FAIL: kubectl not found" +helm version --short 2>/dev/null | grep -q v3 && echo "PASS: helm v3" || echo "FAIL: helm v3 not found" +kubectl auth can-i create namespaces 2>/dev/null | grep -q yes && echo "PASS: cluster-admin" || echo "FAIL: no cluster-admin" +kubectl get storageclass 2>/dev/null | grep -q default && echo "PASS: default StorageClass" || echo "FAIL: no default StorageClass" +[ -n "$AGENTEYE_TOKEN" ] && echo "PASS: AGENTEYE_TOKEN set" || echo "FAIL: AGENTEYE_TOKEN not set" +openssl version >/dev/null 2>&1 && echo "PASS: openssl" || echo "FAIL: openssl not found" +echo "---" +``` + +### شكل النشر + +يتم توفير **نقطة نهاية الالتقاط** على اسم مضيف تتحكم فيه (على سبيل المثال `ingest.your-company.example`). يطلب cert-manager شهادة TLS موثوقة بشكل علني من Let's Encrypt عبر HTTP-01، لذلك يتحقق المجمعون من شهادة الخادم مقابل مخزن الثقة بالنظام، بدون تثبيت CA لكل عميل. + +تعمل **نقطة نهاية لوحة المعلومات** بنفس الطريقة: يتم توفيرها على اسم مضيف ثانٍ تتحكم فيه (على سبيل المثال `agenteye.your-company.example`) يشير إلى LoadBalancer Traefik للوحة المعلومات، و cert-manager يصدر شهادة Let's Encrypt الخاصة به من خلال LoadBalancer هذا. المتصفحات تحصل على شهادة موثوقة بدون تحذير. + +> **يتم التحقق من إصدار واستجابة الشهادة عبر HTTP-01**، لذلك يجب أن تكون كلا LoadBalancers قابلة للوصول من الإنترنت العام على المنفذ 80. إذا كنت بحاجة إلى تقييد IP للوحة معلومات LoadBalancer، فقم بتنسيق محلل DNS-01 مع الدعم أولاً - وإلا فإن التجديدات تفشل بصمت وتنتهي صلاحية الشهادة. + +--- + +## احصل على البيانات الوصفية + +```bash +git clone https://x:${AGENTEYE_TOKEN}@github.com/agenteye-enterprise/releases.git +cd releases/deploy +``` + +**اختبره:** + +```bash +ls base/kustomization.yaml +``` + +المتوقع: الملف موجود. إذا لم يكن كذلك، فإن الاستنساخ فشل - تحقق من `AGENTEYE_TOKEN` الخاص بك. + +**هيكل المجلد:** + +``` +deploy/ + base/ قاعدة Kustomize مشتركة (جميع موارد K8s) + overlays/ تجاوزات خاصة بالمجموعة (علامات الصور واسم المضيف والموارد) + third-party/ قيم Helm لـ Traefik و cert-manager و (بالاختيار) مراقبة صحة Robusta +``` + +تحتوي **القاعدة** على كل مورد مطلوب لنشر كامل، بما في ذلك شهادات Let's Encrypt لاسمي المضيف العامين اللذين تقوم بتكوينهما في المرحلة 3.1. **تراكب** يصحح القاعدة لبيئة معينة (مثل علامات الصور المخصصة وحدود الموارد وربط env). يحتوي دليل **الجهات الخارجية** على ملفات قيم Helm للبنية التحتية الخارجية. + +> **مراقبة الصحة (اختيارية):** اختبار جاهزية الخادم بالفعل يعكس صحة Postgres + ClickHouse، و `third-party/robusta/` يضيف تنبيهات فشل البروانة المحلية بـ Kubernetes القابلة للاختيار إلى Slack. انظر [enterprise-docs/health-monitoring.md](/ar/agenteye/health-monitoring). + +--- + +## المرحلة 1 - البنية التحتية الخارجية (~30 دقيقة) + +### 1.1 تثبيت cert-manager + +يدير cert-manager شهادات TLS لـ HTTPS و CA الخاص المستخدم لشهادات عملاء mTLS. + +```bash +helm repo add jetstack https://charts.jetstack.io +helm repo update + +helm install cert-manager jetstack/cert-manager \ + --namespace cert-manager --create-namespace \ + --set crds.install=true +``` + +**اختبره:** + +```bash +kubectl get pods -n cert-manager +``` + +المتوقع: 3 بروانات جميعها `Running` -- `cert-manager` و `cert-manager-cainjector` و `cert-manager-webhook`. + +```bash +kubectl get crds | grep cert-manager +``` + +المتوقع: على الأقل `certificates.cert-manager.io` و `clusterissuers.cert-manager.io` و `issuers.cert-manager.io`. + +**إذا فشل:** عادة ما تعني البروانات في `CrashLoopBackOff` عدم تثبيت CRDs. قم بإعادة التشغيل باستخدام `--set crds.install=true`. إذا فشلت بروانات webhook في جاهزية، انتظر 30 ثانية وتحقق مرة أخرى - قد تستغرق بعض الوقت للبدء. + +--- + +### 1.2 تثبيت Traefik - وحدة تحكم الإدخال العامة + +تتعامل هذه النسخة من Traefik مع حركة المجمع على LoadBalancer **خارجي**. يقوم بإنهاء TLS وفرض mTLS (التحقق من شهادة العميل) على نقطة نهاية الالتقاط. + +```bash +helm repo add traefik https://traefik.github.io/charts +helm repo update + +helm install traefik-public traefik/traefik \ + --namespace traefik-public --create-namespace \ + --version 39.0.8 \ + -f third-party/traefik/values-public.yaml +``` + +**اختبره:** + +```bash +kubectl get pods -n traefik-public +``` + +المتوقع: 1 برونة `Running`. + +```bash +kubectl get ingressclass traefik-public +``` + +المتوقع: الفئة IngressClass موجودة (إنها ليست الفئة الافتراضية). + +**إذا فشل:** تحقق من `kubectl describe pod -n traefik-public ` للأخطاء في سحب الصور أو قيود الموارد. + +--- + +### 1.3 تثبيت Traefik - وحدة تحكم لوحة المعلومات + +تخدم نسخة Traefik هذه لوحة المعلومات على LoadBalancer مخصص، مقيدة بقائمة السماح بـ IP. + +> **تشحن آليات قائمة السماح المزدوجة لهذه النسخة.** يستخدم هذا الدليل `values-dashboard.yaml`، والذي يقيد الوصول بحقل `service.loadBalancerSourceRanges` المحمول. يتم توفير `values-internal.yaml` الموازي أيضاً لبيئات AWS التي تفضل التعليق التوضيحي `service.beta.kubernetes.io/aws-load-balancer-source-ranges` بدلاً من ذلك. اختر أحدهما واستخدمه بثبات؛ تفترض الخطوات أدناه `values-dashboard.yaml`. + +**قبل التثبيت**، عدّل `third-party/traefik/values-dashboard.yaml` لتعيين عناوين IP المسموحة بالمصدر. يتحكم حقل `loadBalancerSourceRanges` في عناوين IP التي يمكنها الوصول إلى لوحة المعلومات. بشكل افتراضي، يتم تعيينه على `0.0.0.0/0` (جميع عناوين IP)؛ قيده بـ VPN أو مكتب أو معروف عنوان IP للخروج. + +#### قائمة السماح بعنوان IP واحد + +```yaml +service: + loadBalancerSourceRanges: + - "/32" +``` + +#### قائمة السماح بعناوين IP متعددة + +أضف إدخالاً واحداً لكل عنوان IP أو كتلة CIDR. لاحقة `/32` تطابق عنوان IPv4 واحد؛ كتلة CIDR (على سبيل المثال `/24`) تطابق نطاقاً. يمكنك خلط عناوين IP الفردية والنطاقات بحرية: + +```yaml +service: + loadBalancerSourceRanges: + - "203.0.113.10/32" # office gateway + - "203.0.113.11/32" # backup office gateway + - "198.51.100.0/24" # VPN pool + - "192.0.2.50/32" # on-call engineer home IP +``` + +نصائح عند الحفاظ على القائمة: + +- احفظ إدخالاً واحداً لكل سطر وأضف تعليقاً موجزاً `#` يحدد مالك أو غرض كل عنوان IP؛ هذا ما يستخدمه المشغلون في المستقبل لتحديد ما إذا كان الإدخال لا يزال مطلوباً. +- استخدم دائماً تدوين CIDR. عنوان IP عام مثل `203.0.113.10` يتم رفضه من قبل موفر السحابة؛ استخدم `203.0.113.10/32`. +- بالنسبة إلى نطاقات IPv6، استخدم `/128` المكافئ (عنوان واحد) أو CIDR أكبر، على سبيل المثال `2001:db8::1/128`. لا تدعم جميع موفري السحابة نطاقات مصدر IPv6؛ تحقق من وثائق LoadBalancer لموفرك. +- القائمة هي **OR**: يُسمح بالحركة إذا كان المصدر يطابق أي إدخال. + +بعد تحرير الملف، تابع `helm install` أدناه. إذا كانت وحدة التحكم مثبتة بالفعل، فقم بتشغيل `helm upgrade` بنفس العلامات، أو أصلح الخدمة في وقت التشغيل (القسم التالي). + +#### تحديث قائمة السماح في وقت التشغيل + +يمكنك تغيير عناوين IP المسموحة بدون ترقية Helm بإصلاح الخدمة مباشرة. **يستبدل الإصلاح القائمة بأكملها**؛ قم دائماً بتضمين كل عنوان IP تريد الاحتفاظ به، وليس الآخر الجديد. + +لاستبدال القائمة بمجموعة جديدة من عناوين IP: + +```bash +kubectl patch svc traefik-dashboard -n traefik-dashboard \ + -p '{"spec":{"loadBalancerSourceRanges":["203.0.113.10/32","198.51.100.0/24","192.0.2.50/32"]}}' +``` + +لـ **إضافة** عنوان IP بأمان دون فقدان الإدخالات الموجودة، اقرأ القائمة الحالية أولاً، ثم أصلح بالمجموعة المدمجة: + +```bash +# 1. عرض قائمة السماح الحالية +kubectl get svc traefik-dashboard -n traefik-dashboard \ + -o jsonpath='{.spec.loadBalancerSourceRanges}' + +# 2. إصلاح بالقائمة الكاملة بما في ذلك عنوان IP الجديد +kubectl patch svc traefik-dashboard -n traefik-dashboard \ + -p '{"spec":{"loadBalancerSourceRanges":["/32","/32","/32"]}}' +``` + +> لا يتم الاحتفاظ بالإصلاحات في وقت التشغيل مرة أخرى إلى `values-dashboard.yaml`. للاحتفاظ بالتغيير عبر ترقيات Helm المستقبلية، قم أيضاً بتحديث ملف القيم والالتزام به. + +ثم ثبت: + +```bash +helm install traefik-dashboard traefik/traefik \ + --namespace traefik-dashboard --create-namespace \ + --version 39.0.8 \ + -f third-party/traefik/values-dashboard.yaml +``` + +**اختبره:** + +```bash +kubectl get pods -n traefik-dashboard +``` + +المتوقع: 1 برونة `Running`. + +```bash +kubectl get ingressclass traefik-dashboard +``` + +المتوقع: الفئة IngressClass موجودة. + +--- + +### 1.4 انتظر LoadBalancers + +تحتاج كلا نسختا Traefik إلى عناوين IP خارجية قبل المتابعة. + +```bash +kubectl get svc -n traefik-public +kubectl get svc -n traefik-dashboard +``` + +**اختبره:** كلا الخدمتين تظهران `EXTERNAL-IP` (وليس ``). + +إذا كانت لا تزال قيد الانتظار، راقب التخصيص: + +```bash +kubectl get svc -n traefik-public -w +``` + +اضغط على `Ctrl+C` بمجرد ظهور عنوان IP. عادة ما يستغرق تخصيص عنوان IP 2-5 دقائق. + +**إذا فشل:** عادة ما يعني `` بعد 10 دقائق أن موفر السحابة لا يستطيع توفير LoadBalancer. تحقق من: علامات الشبكة الفرعية (EKS يتطلب `kubernetes.io/role/elb`)، تكوين VPC، حصص الخدمة، وأن التعليق التوضيحي LB الداخلي الصحيح مضبوط للنسخة الداخلية. + +--- + +## المرحلة 2 - إنشاء الأسرار (~10 دقائق) + +يتم إنشاء جميع الأسرار يدويا قبل نشر التطبيق. هذا يضمن عدم ظهور القيم الحساسة في ملفات البيان. + +### 2.1 إنشاء مساحة الأسماء + +```bash +kubectl create namespace agenteye +``` + +**اختبره:** + +```bash +kubectl get namespace agenteye +``` + +المتوقع: الحالة `Active`. + +--- + +### 2.2 سر سحب الصور + +يقوم هذا السر بالمصادقة على `ghcr.io` لسحب صور حاوية AgentEye. انظر [enterprise-docs/github-token.md](/ar/agenteye/github-token) لكيفية إنشاء PAT الخاص بك. + +```bash +kubectl create secret docker-registry agenteye-image-pull \ + --namespace agenteye \ + --docker-server=ghcr.io \ + --docker-username=agenteye-enterprise \ + --docker-password="${AGENTEYE_TOKEN}" +``` + +**اختبره:** + +```bash +kubectl get secret agenteye-image-pull -n agenteye -o jsonpath='{.type}' +``` + +المتوقع: `kubernetes.io/dockerconfigjson`. + +**اختبره (عميق)** - تحقق من أن الرمز يمكنه فعلاً سحب الصور: + +استخدم علامة صورة `server` المثبتة في تراكب `kustomization.yaml` الخاص بك (حالياً `v0.0.1-beta.48` في كل من تراكب `acme` المجمع والنشر الأساسي). استبدل العلامة أدناه بالعلامة التي تنشرها حتى لا ينجرف هذا الفحص عبر الإصدارات: + +```bash +kubectl run test-pull \ + --image=ghcr.io/agenteye-enterprise/server:v0.0.1-beta.48 \ + --overrides='{"spec":{"imagePullSecrets":[{"name":"agenteye-image-pull"}]}}' \ + --restart=Never -n agenteye --command -- echo ok + +# انتظر بضع ثوان للسحب، ثم: +kubectl logs test-pull -n agenteye +kubectl delete pod test-pull -n agenteye +``` + +المتوقع: `ok` مطبوع في السجلات. + +**إذا فشل:** `ErrImagePull` أو `401 Unauthorized` يعني أن PAT غير صحيح أو يفتقد النطاق `read:packages`. أعد التحقق من [enterprise-docs/github-token.md](/ar/agenteye/github-token). + +--- + +### 2.3 بيانات اعتماد PostgreSQL + +```bash +POSTGRES_PASSWORD=$(openssl rand -hex 24) + +kubectl create secret generic agenteye-postgres \ + --namespace agenteye \ + --from-literal=POSTGRES_USER=postgres \ + --from-literal=POSTGRES_PASSWORD="${POSTGRES_PASSWORD}" \ + --from-literal=POSTGRES_DB=agenteye +``` + +> **مهم:** نستخدم `-hex` (وليس `-base64`) لإنشاء كلمة المرور. يمكن لمخرجات Base64 أن تحتوي على `+` و `/` و `=` التي تقسم سلسلة الاتصال `DATABASE_URL`. انظر [enterprise-docs/troubleshooting.md](/ar/agenteye/troubleshooting) للتفاصيل. + +> **قم بتخزين `POSTGRES_PASSWORD` في مدير الأسرار الخاص بك فوراً.** ستحتاجه إذا كنت بحاجة إلى الاستعادة من نسخة احتياطية أو الاتصال بقاعدة البيانات مباشرة. + +**اختبره:** + +```bash +kubectl get secret agenteye-postgres -n agenteye +``` + +المتوقع: السر موجود. + +```bash +kubectl get secret agenteye-postgres -n agenteye \ + -o jsonpath='{.data.POSTGRES_PASSWORD}' | base64 -d | wc -c +``` + +المتوقع: `48` (24 بايت سادس عشر = 48 حرفاً). + +--- + +### 2.4 مفتاح API للإدارة + +```bash +ADMIN_KEY=$(openssl rand -hex 32) + +kubectl create secret generic agenteye-admin-key \ + --namespace agenteye \ + --from-literal=ADMIN_KEY="${ADMIN_KEY}" +``` + +مفتاح الإدارة هو بيانات اعتماد التمهيد. يقوم الخادم بتحديث أو إدراج جميع الأذونات في كل بدء. استخدمه لإنشاء مفاتيح مجمع محدودة في المرحلة 7. انظر [enterprise-docs/api-keys.md](/ar/agenteye/api-keys) لنموذج الأذونات الكامل. + +> **قم بتخزين `ADMIN_KEY` في مدير الأسرار الخاص بك فوراً.** + +**اختبره:** + +```bash +kubectl get secret agenteye-admin-key -n agenteye +``` + +المتوقع: السر موجود. + +--- + +### 2.5 تكوين المصادقة (تسجيل الدخول إلى لوحة المعلومات) + +تستخدم لوحة المعلومات البريد الإلكتروني + OTP لتسجيل دخول المستخدم. بدون هذا السر، يبدأ الخادم بشكل طبيعي ويستمر مسار `ADMIN_KEY` API في العمل، لكن **لا يمكن لأي مستخدم تسجيل الدخول عبر الواجهة**. + +تتم الإشارة إلى جميع المفاتيح كـ `optional: true` في البيان الأساسي، لذا فإن الأسرار الجزئية (أو عدم وجود سر على الإطلاق) جيدة؛ يعود الخادم إلى الافتراضيات الموثقة. جمع كل شيء في سر واحد `agenteye-auth` يجعل سطح المصادقة قابلاً للدوران في مكان واحد. + +```bash +kubectl create secret generic agenteye-auth \ + --namespace agenteye \ + --from-literal=ADMIN_EMAIL="admin@yourcompany.com" \ + --from-literal=ALLOWED_EMAILS="*@yourcompany.com" \ + --from-literal=SMTP_HOST="smtp.yourprovider.com" \ + --from-literal=SMTP_PORT="587" \ + --from-literal=SMTP_USERNAME="your-smtp-user" \ + --from-literal=SMTP_PASSWORD="your-smtp-password" \ + --from-literal=SMTP_FROM="noreply@yourcompany.com" \ + --from-literal=SMTP_TLS="starttls" \ + --from-literal=DEFAULT_ORG_NAME="Acme Corp" \ + --from-literal=DEFAULT_ORG_SLUG="acme" +``` + +| المفتاح | الغرض | +|---|---| +| `ADMIN_EMAIL` | مستخدم إدارة التمهيد. يتم تحديثه أو إدراجه في كل بدء مع جميع الأذونات وحمايته من الحذف/تعديلات الأذونات عبر لوحة المعلومات. بدونه، لا يتم بذر أي مسؤول ويكون أول تسجيل دخول مستحيلاً. | +| `ALLOWED_EMAILS` | قائمة السماح المفصول بينها بفواصل. يدعم عناوين دقيقة (`user@example.com`) وأحرف دومين بدل (`*@example.com`). بدونها، **لا يمكن لأي مستخدم تسجيل الدخول أو إنشاؤه**. | +| `SMTP_HOST`, `SMTP_PORT`, `SMTP_USERNAME`, `SMTP_PASSWORD`, `SMTP_FROM` | مرحل SMTP لإرسال رموز OTP. إذا لم تكن `SMTP_HOST` مضبوطة، يتم تسجيل رموز OTP في stdout الخادم بدلاً من إرسالها بالبريد الإلكتروني (مفيد لاختبارات التحقق الأولى). قدم جميع مفاتيح SMTP معاً لتسليم البريد الإلكتروني الفعلي. | +| `SMTP_TLS` | أحد `starttls` (الافتراضي) أو `tls` أو `none`. | +| `DEFAULT_ORG_NAME`, `DEFAULT_ORG_SLUG` | اختياري. أعط للمنظمة المدمجة `default` اسم عرض ودية وشريحة عنوان URL بحيث تعيش على سبيل المثال في `/acme` بدلاً من `/default`. يتم تطبيقها فقط عند **البدء الأول**؛ بمجرد إعادة تسمية المنظمة باستخدام `agenteye-orgctl org rename` (انظر §7.6) يتم تجاهلها. يجب أن تكون الشريحة 1-40 أحرفاً صغيرة وأرقام مع شرطات داخلية واحدة. اتركهما دون تعيين للاحتفاظ بـ `default` عام. | + +> **قم بتخزين بيانات اعتماد SMTP في مدير الأسرار الخاص بك.** + +**اختبره:** + +```bash +kubectl get secret agenteye-auth -n agenteye \ + -o jsonpath='{.data}' | grep -o '"[A-Z_]*"' | sort -u +``` + +المتوقع: تظهر المفاتيح التي заполнили في الإخراج. + +--- + +### 2.6 مفتاح عزل المنظمة متعددة المستأجرين (اختياري) + +تخطي هذا للنشر بمستأجر واحد؛ يعمل الخادم على بناء مدمج dev افتراضي ويخدم المنظمة الواحدة `default` بشكل جيد. **قبل إنشاء منظمة ثانية**، قم بتعيين `ORG_CH_SECRET` قوي واستقر: كلمة مرور ClickHouse لكل منظمة مشتقة كـ `HMAC(ORG_CH_SECRET, org_id)`، لذا فإن الافتراضي المدمج المعروف بالعام سيؤدي إلى بيانات اعتماد محتملة معروفة لكل منظمة. يرفض أمر `agenteye-orgctl org create` (انظر [§7.6 توفير المنظمات](#76-توفير-المنظمات-متعددة-المستأجرين)) التشغيل بينما الخادم لا يزال في الافتراضي dev المدمج. + +```bash +kubectl create secret generic agenteye-org-ch-secret \ + --namespace agenteye \ + --from-literal=ORG_CH_SECRET="$(openssl rand -base64 48)" + +# جدول الخادم بحيث يلتقط القيمة الجديدة. +kubectl -n agenteye rollout restart deployment/server +``` + +يقرأ الخادم هذا عبر `secretKeyRef` **اختياري**، لذا فإن مجموعة بمستأجر واحد لا تنشئها أبداً بدء الأمر بشكل طبيعي. حافظ على القيمة **مستقرة ومطابقة عبر جميع البدائل**؛ تدويرها يلغي كلمة مرور ClickHouse المشتقة من كل منظمة حتى يعيد التوفيق في وقت البدء تزويد المستخدمين (إعادة تشغيل متدرجة مع القيمة المتسقة في كل مكان يشفيها). انظر `deploy/base/server/secret.example.yaml`. + +> **قم بتخزين `ORG_CH_SECRET` في مدير الأسرار الخاص بك ولا تقوم بتدويره بشكل عرضي.** + +--- + +### 2.7 التحقق من جميع الأسرار + +```bash +kubectl get secrets -n agenteye -o custom-columns='NAME:.metadata.name,TYPE:.type' +``` + +الإخراج المتوقع (من بين أي أسرار افتراضية): + +``` +NAME TYPE +agenteye-admin-key Opaque +agenteye-auth Opaque +agenteye-image-pull kubernetes.io/dockerconfigjson +agenteye-postgres Opaque +agenteye-org-ch-secret Opaque # فقط إذا أكملت §2.6 (متعدد المستأجرين) +``` + +يجب أن تكون الأسرار الأربعة الأساسية (`agenteye-admin-key` و `agenteye-auth` و `agenteye-image-pull` و `agenteye-postgres`) موجودة قبل المتابعة. `agenteye-org-ch-secret` مطلوب فقط لنشرات متعددة المستأجرين (انظر §2.6). + +--- + +## المرحلة 3 - نشر التطبيق (~5 دقائق) + +### 3.1 تكوين اسم المضيف العام + +يحتاج cert-manager إلى اسم المضيف للالتقاط ولوحة المعلومات قبل أن يتمكن من طلب شهادات Let's Encrypt الخاصة به. انسخ القالب وعيّن كلاهما: + +```bash +cp base/certificates/domain.env.example base/certificates/domain.env +# عدّل base/certificates/domain.env وعيّن: +# INGEST_DOMAIN=ingest.your-company.example (يحل إلى LoadBalancer Traefik العام) +# DASHBOARD_DOMAIN=agenteye.your-company.example (يحل إلى LoadBalancer Traefik لوحة المعلومات) +``` + +`domain.env` يتم تجاهله من قبل git؛ يبقى محلياً لكل نشر. بناء kustomize يفشل بصراحة إذا كان أي مفتاح مفقوداً. + +> **يجب أن ينحل DNS أولاً.** لا تضطر إلى الإشارة بـ DNS إلى LoadBalancers حتى الآن (فهي غير موجودة حتى تكتمل المرحلة 1.2)، لكن إصدار ACME في الخطوة 3.2 سيحاول مجدداً حتى يحل كل اسم مضيف إلى LoadBalancer الخاص به. يمكنك إما تعيين DNS الآن (باستخدام أسماء مضيف LoadBalancer المجمعة في المرحلة 1.4) أو المتابعة وإضافة السجلات في المرحلة 4. + +--- + +### 3.2 تطبيق البيانات الوصفية + +قم بتطبيق القاعدة مباشرة لتثبيت جديد، أو تراكب إذا قمت بقطع واحد لهذه البيئة (التراكبات فقط دبابيس علامات الصور و env vars وحدود الموارد؛ يرثون شهادات القاعدة والتوجيه): + +```bash +kubectl apply -k base/ +# أو +kubectl apply -k overlays// +``` + +يتضمن التراكب القاعدة تلقائياً؛ تطبيق واحد، وليس كليهما. + +--- + +### 3.3 انتظر البروانات + +```bash +kubectl wait --for=condition=Ready pod -l 'app in (server,dashboard,postgres,clickhouse)' \ + -n agenteye --timeout=180s +``` + +ينطبق الانتظار على بروانات مستوى البيانات الأساسي. يأتي البروانات `agent` (مساعد AI) و `redis` الاختيارية جنباً إلى جنب معهم؛ المساعد يبقى خاملاً حتى توفر نقطة نهاية LLM الخاصة به (انظر [enterprise-docs/assistant.md](/ar/agenteye/assistant))، و Redis هو ذاكرة تخزين مؤقت أفضل جهد، لذا لا يحتاج أي منهما إلى أن يكون جاهزاً للخدمة لخدمة البلاتفورم حركة. + +**اختبره:** + +```bash +kubectl get pods -n agenteye +``` + +المتوقع (البروانات `agent` و `redis` الاختيارية تظهر أيضاً وتصل إلى `Running`): + +``` +NAME READY STATUS RESTARTS AGE +agent-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +clickhouse-0 1/1 Running 0 ... +dashboard-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +dashboard-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +postgres-0 1/1 Running 0 ... +redis-0 1/1 Running 0 ... +server-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +server-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +``` + +**إذا فشل:** + +| حالة البروانة | السبب المحتمل | أمر التصحيح | +|---|---|---| +| `ImagePullBackOff` | سر سحب صورة سيء أو PAT | `kubectl describe pod -n agenteye` | +| `CrashLoopBackOff` | متغيرات البيئة السيئة (على سبيل المثال DATABASE_URL) | `kubectl logs -n agenteye` | +| `Pending` | وحدة المعالجة المركزية / الذاكرة غير كافية أو بدون عقد | `kubectl describe pod -n agenteye` (تحقق من الأحداث) | + +--- + +### 3.4 التحقق من التخزين + +```bash +kubectl get pvc -n agenteye +``` + +المتوقع، كلاهما بحالة `Bound`: + +| PVC | السعة | ظهره | +|---|---|---| +| `postgres-data-postgres-0` | `50Gi` | مخزن البيانات العلائقية / البيانات الوصفية PostgreSQL | +| `clickhouse-data-clickhouse-0` | `100Gi` | مخزن تحليلات أحداث ClickHouse + التقييمات | + +يظهر أيضاً PVC `redis-data-redis-0` (1Gi) لذاكرة التخزين المؤقت الاختيارية. + +**إذا فشل:** `Pending` يعني أن فئة التخزين لا يمكنها توفير الحجم. تحقق من `kubectl get storageclass` وتأكد من وجود افتراضي. للإنتاج، ضع حجم ClickHouse على فئة تخزين SSD سريعة (على سبيل المثال gp3 على AWS أو pd-ssd على GCP)؛ يعاني معدل النقابة من الأقراص البطيئة. + +--- + +### 3.5 التحقق من الشهادات + +```bash +kubectl get certificates -n agenteye +``` + +المتوقع: 3 شهادات، جميعها `Ready: True`: + +| الاسم | المُصدر | الغرض | +|---|---|---| +| `mtls-ca` | `selfsigned` | CA خاص لإصدار شهادات عملاء mTLS (صحة 10 سنوات) | +| `ingest-tls` | `letsencrypt-prod` | شهادة TLS عام لنقطة نهاية الالتقاط (90 يوماً، تجديد تلقائي) | +| `dashboard-tls` | `letsencrypt-prod` | شهادة TLS عام لوحة المعلومات (90 يوماً، تجديد تلقائي) | + +**إذا لم تكن `ingest-tls` أو `dashboard-tls` جاهزة:** + +`kubectl describe certificate -n agenteye` واقرأ الأحداث. الأسباب الشائعة: + +- **DNS لم تشير بعد إلى LB.** يحل Let's Encrypt اسم المضيف ويضرب المنفذ 80 للتحقق - `INGEST_DOMAIN` يجب أن يحل إلى LoadBalancer العام و `DASHBOARD_DOMAIN` إلى LoadBalancer لوحة المعلومات. حتى ينتشر CNAME / Alias، تبقى الطلب معلقة. بمجرد أن يكون DNS صحيحاً، يحاول cert-manager مجدداً تلقائياً (لا حاجة لحذف الشهادة). +- **اسم المضيف لم يتم استبداله.** إذا كانت `dnsNames` تقرأ بعد `INGEST_DOMAIN_PLACEHOLDER` / `DASHBOARD_DOMAIN_PLACEHOLDER`، فقد تخطيت الخطوة 3.1 - أنشئ `base/certificates/domain.env` وأعد التطبيق. +- **Traefik لوحة المعلومات لا يمكنه خدمة التحدي** (`dashboard-tls` فقط). يجب تثبيت نسخة Traefik من لوحة المعلومات مع ملف القيم المجمع (المرحلة 1.3)، والذي يمكن موفر الإدخال المحدود الذي يخدم حلال HTTP-01 من cert-manager. نسخة مثبتة بدونها تترك التحدي غير قابل للتوجيه والطلب معلق للأبد. + +**إذا لم تكن `mtls-ca` جاهزة:** cert-manager نفسه غير صحي. أعد التحقق من بروانات cert-manager من الخطوة 1.1. + +--- + +### 3.6 التحقق من CronJobs + +```bash +kubectl get cronjobs -n agenteye +``` + +المتوقع: + +| الاسم | الجدول الزمني | الغرض | +|---|---|---| +| `agenteye-backup` | `0 3 * * *` | النسخ الاحتياطية اليومية Postgres + ClickHouse في 03:00 UTC | +| `cert-renewal-check` | `0 3,15 * * *` | تنبيهات انتهاء صلاحية الشهادة في 03:00 و 15:00 UTC | + +--- + +### 3.7 تحقق من بدء الخادم بشكل صحيح + +```bash +kubectl logs -n agenteye -l app=server --tail=20 +``` + +**اختبره:** ابحث عن سطر بدء يشير إلى أن الخادم يستمع على المنفذ 8080. يجب ألا تكون هناك أخطاء في اتصال قاعدة البيانات (يتطلب الخادم وصول PostgreSQL و ClickHouse قبل أن يبلغ عن Ready). + +**إذا فشل:** السبب الأكثر شيوعاً هو `POSTGRES_PASSWORD` يحتوي على أحرف غير آمنة للعنوان الذي ينقسم `DATABASE_URL`. انظر [enterprise-docs/troubleshooting.md](/ar/agenteye/troubleshooting). + +--- + +### 3.8 تحقق من لوحة المعلومات المتصلة بالخادم + +```bash +kubectl logs -n agenteye -l app=dashboard --tail=20 +``` + +**اختبره:** ابحث عن `Ready` في الإخراج بدون أخطاء `ECONNREFUSED` أو ما شابه. + +**إذا فشل:** تحقق من أن خدمة `server` موجودة (`kubectl get svc server -n agenteye`) وأن `AGENTEYE_SERVER_URL` مضبوطة على `http://server:8080` في نشر لوحة المعلومات. + +--- + +## المرحلة 4 - الوصول إلى الشبكة (~5 دقائق) + +### 4.1 استرجع عناوين LoadBalancer + +```bash +PUBLIC_IP=$(kubectl get svc -n traefik-public \ + -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') + +INTERNAL_IP=$(kubectl get svc -n traefik-dashboard \ + -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') +``` + +> على AWS EKS، تُرجع LoadBalancers اسم مضيف بدلاً من عنوان IP. استبدل `.ip` بـ `.hostname` في الأوامر أعلاه. + +**اختبره:** + +```bash +echo "Public (ingest): $PUBLIC_IP" +echo "Internal (dashboard): $INTERNAL_IP" +``` + +كلاهما يجب أن يكون غير فارغ. + +--- + +### 4.2 أشر DNS إلى LoadBalancers + +أنشئ سجلات DNS بحيث تحل أسماء المضيفات من `base/certificates/domain.env` إلى LoadBalancers الخاصة بهم - `INGEST_DOMAIN` إلى LoadBalancer Traefik **العام**، `DASHBOARD_DOMAIN` إلى LoadBalancer Traefik **لوحة المعلومات**: + +- **AWS Route 53:** سجل `A` مع `Alias = Yes`، الهدف = اسم مضيف LoadBalancer. لا تستخدم A → IP عادي؛ عناوين ELB IP تدور. +- **أي موفر آخر:** `CNAME` من اسم المضيف إلى اسم مضيف LoadBalancer. + +تحقق: + +```bash +dig +short ingest.your-company.example +dig +short agenteye.your-company.example +``` + +يجب أن تعود نفس العناوين كـ `$PUBLIC_IP` و `$INTERNAL_IP` على التوالي (أو، على EKS، حل نفس أسماء مضيفات `*.elb.amazonaws.com`). + +بمجرد حل DNS، ينهي cert-manager طلبات ACME المعلقة من المرحلة 3.5 في غضون دقيقة. أعد تشغيل `kubectl get certificates -n agenteye` حتى تظهر كلا `ingest-tls` و `dashboard-tls` `Ready: True`. + +--- + +### 4.3 الوصول إلى نقطة نهاية الالتقاط + +تفرض نقطة نهاية الالتقاط العام TLS متبادل، لذا يجب أن يقدم كل طلب (بما في ذلك `/health`) شهادة عميل. تصدر شهادة عميل أولى في المرحلة 5؛ إذا كان لديك واحدة بالفعل، تحقق من قابلية الوصول الآن: + +```bash +curl -s --cert issued//client.crt \ + --key issued//client.key \ + https://ingest.your-company.example/health +``` + +المتوقع: `{"status":"ok"}`. لا يلزم `-k` - شهادة الخادم تربط إلى CA عام لـ `INGEST_DOMAIN`، لذا فهي صحيحة مقابل مخزن الثقة بالنظام. الوصول إلى نقطة نهاية الالتقاط برمز `INGEST_DOMAIN` (الذي يطابق الشهادة الصادرة)، وليس برمز LoadBalancer الخام IP / اسم المضيف. + +يتم توفير نقطة نهاية لوحة المعلومات على `DASHBOARD_DOMAIN` مع شهادة عام موثوق بها وليست خلف mTLS، لذا لا يلزم `-k` ولا شهادة عميل: + +```bash +curl -s https://agenteye.your-company.example/ -o /dev/null -w '%{http_code}\n' +``` + +الوصول إلى لوحة المعلومات برمز - اسم المضيف، وليس عنوان LoadBalancer الخام - الشهادة مرتبطة بـ `DASHBOARD_DOMAIN`، لذا فإن العنوان الخام يوضح عدم تطابق اسم الشهادة. + +**إذا فشل:** إذا كان curl معلقاً، تحقق من أن LoadBalancer قابل للوصول من جهازك (VPN وعناصر الأمان وقواعد الجدار). يعني خطأ مصادقة `certificate required` على اسم المضيف الالتقاط عدم تقديم شهادة عميل؛ أكمل المرحلة 5 أولاً. يعني خطأ التحقق من TLS على اسم المضيف الالتقاط أن شهادة الخادم لم تنته من الإصدار حتى الآن؛ عد إلى المرحلة 3.5 وحل المشكلة هناك. + +--- + +## المرحلة 5 - إصدار شهادات عملاء mTLS (~10 دقائق لكل مجموعة) + +يتحقق المجمعون مع **عاملين**: شهادة عميل (طبقة النقل، يثبت أن الطلب يأتي من مجموعة مصرح بها) ومفتاح API (طبقة التطبيق، يثبت أن الطلب من مجمع لديه إذن `events:add`). مفتاح مسرب غير مفيد بدون الشهادة؛ شهادة مسروقة غير مفيدة بدون مفتاح صحيح. + +### 5.1 إصدار شهادة + +تحتاج كل مجموعة تشغل مجمعات إلى شهادة عميل خاصة بها. من دليل البيانات الوصفية: + +```bash +cd base/certificates/client-certs +./issue-client-cert.sh +``` + +استبدل `` بمعرّف ذي مغزى (على سبيل المثال `us-east-1-prod` أو `staging`). + +**اختبره:** يطبع الكتاب النصي `==> Done!` ويسرد ملفات الإخراج. + +```bash +kubectl get certificate mtls-client- -n agenteye +``` + +المتوقع: `Ready: True`. + +ملفات الإخراج في `issued//`: + +| الملف | الغرض | +|---|---| +| `client.crt` | شهادة العميل (صحة 90 يوماً) | +| `client.key` | مفتاح خاص العميل | +| `ca.crt` | شهادة CA للتحقق من الخادم | +| `collector-mtls-secret.yaml` | سر Kubernetes جاهز للتطبيق لمجموعة المجمع | + +--- + +### 5.1b توصيل بديل: AWS Secrets Manager + +إذا كان المستهلك للشهادة Kubernetes Pod الذي يحتاج `client.crt` و `client.key` على القرص - الحالة النموذجية عند تشغيل agenteye-collector كـ sidecar في pod التطبيق الخاص بك - ادفع مجموعة الشهادات إلى AWS Secrets Manager. ثم يمكن لـ pod التطبيق تثبيته عبر [Secrets Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/) مع IRSA، وتجديد الشهادة بالكامل بدون أيدي. + +```bash +cd base/certificates/client-certs +export AWS_REGION=us-east-1 # المنطقة حيث يعمل عبء عملك +./issue-client-cert.sh --save-to aws-secrets-manager +``` + +عند إعادة التشغيل (التجديد)، يستدعي الكتاب النصي `PutSecretValue` على نفس السر، لذا يبقى ARN والاسم مستقراً. يختار CSI Driver النسخة الجديدة في استطلاع دورانها التالي ويعيد كتابة الملفات داخل الـ pod. + +**المتطلبات الأساسية:** + +- `aws` CLI v2 موثق في حسابك AWS. +- `jq` مثبت. +- مجموعة متغير البيئة `AWS_REGION`. +- أذونات IAM على هوية المتصل (نطاق `Resource` إلى `arn:aws:secretsmanager:::secret:agenteye/mtls-client/*`): + - `secretsmanager:CreateSecret` + - `secretsmanager:DescribeSecret` + - `secretsmanager:PutSecretValue` + - `secretsmanager:TagResource` + +**ما يفعله الكتاب النصي في هذا الوضع:** + +| الخطوة | الإجراء | +|---|---| +| 1 | يصدر / يعيد استخراج الشهادة عبر cert-manager (نفس الوضع الافتراضي). | +| 2 | استدعاء `DescribeSecret` على `agenteye/mtls-client/` لقرار الإنشاء مقابل التحديث. | +| 3 | عند أول تشغيل: `CreateSecret` بحمول JSON بثلاثة مفاتيح (`client.crt` و `client.key` و `ca.crt`)، وسم `AgentEyeCluster=`. عند عمليات تشغيل لاحقة: `PutSecretValue` لنشر نسخة جديدة؛ الوسم محدث عبر `TagResource`. | +| 4 | حذف `issued//` فقط بعد تحميل ناجح. عند أي فشل، يتم الاحتفاظ بالمجلد حتى تحاول مجدداً. | + +**إذا تم جدولة السر للحذف**، يفشل الكتاب النصي برسالة واضحة يخبرك بتشغيل `aws secretsmanager restore-secret --secret-id agenteye/mtls-client/` قبل إعادة المحاولة. + +للأسلاك الـ pod الكاملة (SecretProviderClass و IRSA و سلوك الدوران و استكشاف الأخطاء) انظر [enterprise-docs/single-pod-deployment.md](/ar/agenteye/single-pod-deployment). + +--- + +### 5.2 تحقق من عمل الشهادة + +اختبر الشهادة الصادرة ضد ingress mTLS: + +```bash +curl -sk --cert issued//client.crt \ + --key issued//client.key \ + https://${PUBLIC_IP}/health +``` + +المتوقع: `{"status":"ok"}` + +**إذا فشل:** + +| خطأ | السبب | الإصلاح | +|---|---|---| +| `certificate required` | لا يتم تقديم الشهادة | تحقق من مسارات الملفات في أم \ No newline at end of file diff --git a/docs/ar/agenteye/managed-deployment.mdx b/docs/ar/agenteye/managed-deployment.mdx new file mode 100644 index 00000000..5153bbff --- /dev/null +++ b/docs/ar/agenteye/managed-deployment.mdx @@ -0,0 +1,171 @@ +--- +title: "النشر المُدار على مجموعة Kubernetes الخاصة بك" +description: "توثيق النشر المُدار لـ AgentEye على مجموعة Kubernetes الخاصة بك." +--- + + +AgentEye هي منصة قابلة للاستضافة الذاتية للملاحظة والتقييم للوكلاء الذكيين وأنماط اللغات الكبيرة. تلتقط جلسات الوكيل واستدعاءات الأدوات وطلبات النموذج والأخطاء، وتحولها إلى تحليلات وتقييمات قابلة للبحث، وتعرض النتائج في لوحة معلومات مع مساعد ذكي قراءة فقط اختياري. + +في نموذج النشر المُدار، تقدم مجموعة Kubernetes مخصصة و Exosphere تقوم بتشغيل المنصة الكاملة بداخلها، وتنشر وتكوّن وتشغّل وتنسخ احتياطياً وتحدّث كل مكون بالنيابة عنك. يحصل فريقك على قيمة المنصة (رؤية الوكيل والتحليلات والتقييم والمساعد الاختياري) دون تشغيل قواعد البيانات أو الشهادات أو الترقيات. تبقى جميع البيانات ضمن حسابك السحابي. + +--- + +## المتطلبات الأساسية + +- **رمز GitHub PAT** لسحب صور الحاويات وتحميل القطع الأثرية (راجع [إعداد رمز GitHub](/ar/agenteye/github-token)) +- **مجموعة Kubernetes مخصصة** (راجع المتطلبات أدناه) +- **حاوية تخزين** للنسخ الاحتياطية من قاعدة البيانات +- **الاتصال بالشبكة**: المنفذ 443 بالداخل إلى موازن حمل المجموعة + +--- + +## الخطوة 1: تجهيز مجموعة Kubernetes مخصصة + +أنشئ مجموعة Kubernetes مخصصة لـ AgentEye. يجب ألا تُشارك مع أحمال عمل أخرى، بحيث تعمل المنصة الكاملة (خدمات التطبيق وقواعس البيانات والتحليلات والتخزين المؤقت) بعزلة دون التأثير على البنية التحتية الموجودة لديك. + +| المتطلب | التفاصيل | +|---|---| +| **التوزيع** | أي Kubernetes متوافق: EKS أو GKE أو AKS أو إدارة ذاتية | +| **الإصدار** | 1.27 أو أحدث | +| **مجموعة العُقد** | الحد الأدنى: **3 عُقد، 4 vCPU / 8 GB RAM لكل منها** (نوى الأغراض العامة القياسية) | +| **التخزين** | StorageClass افتراضي يوفر أحجام الكتل (على سبيل المثال `gp3` على AWS أو `pd-ssd` على GCP) | +| **موازن الحمل** | يجب أن تكون المجموعة قادرة على توفير خدمات LoadBalancer السحابية (افتراضي على EKS و GKE و AKS) | + +> Exosphere تقوم بتثبيت وإدارة كل شيء آخر بداخل المجموعة: متحكمات الدخول وشهادات TLS وقواعد البيانات والتخزين المؤقت والمراقبة ونشر جميع التطبيقات. + +--- + +## الخطوة 2: منح الوصول لفريق AgentEye + +تحتاج Exosphere إلى وصول cluster-admin (أو ما يعادله من RBAC واسع) لإدارة المساحات والتعريفات المورد المخصصة ومتحكمات الدخول وموفري التخزين. + +| المتطلب | التفاصيل | +|---|---| +| **طريقة الوصول** | دور IAM (مفضل لـ EKS/GKE) أو kubeconfig أو وصول قائم على SSO | +| **VPN / bastion** | إذا كان خادم واجهة برمجة تطبيقات Kubernetes خاصاً، قدم بيانات اعتماد VPN أو وصول bastion لفريق عمليات Exosphere | + +--- + +## الخطوة 3: تكوين الاتصال بالشبكة + +يحتاج فريق الشبكة الخاص بك إلى السماح بحركة المرور الواردة على **المنفذ 443** إلى موازنات حمل المجموعة. يقوم النشر بتشغيل اثنين من موازنات الحمل المنفصلة: واحد لاستقبال الأحداث (محمي بـ mTLS) وواحد للوحة المعلومات: + +| حركة المرور | المصدر | الوجهة | الأمان | +|---|---|---|---| +| **استقبال الأحداث** | حاويات المجمِّع في مجموعتك | موازن حمل الاستقبال، المنفذ 443 | mTLS (شهادة العميل) + مفتاح API | +| **لوحة المعلومات** | متصفحات المطورين | موازن حمل لوحة المعلومات، المنفذ 443 | HTTPS على مجالك، تسجيل الدخول بكلمة مرور لمرة واحدة عبر البريد الإلكتروني | + +نقطة الاستقبال محمية بـ TLS المتبادل؛ يجب على المجمِّعات تقديم شهادة عميل صالحة **و** مفتاح API صالح في كل طلب. تعمل لوحة المعلومات على موازن حمل واسم مضيف خاصين بها، مع تقييد تسجيل الدخول إلى عناوين البريد الإلكتروني والنطاقات المسموحة بها. + +**سجلات DNS (مرة واحدة):** يمكنك إنشاء سجلي CNAME ضمن مجال تتحكم فيه — واحد لنقطة الاستقبال وواحد لوحة المعلومات (على سبيل المثال `agenteye.your-company.example`) — موجهاً إلى أسماء مضيفي موازن الحمل الذي توفره Exosphere. ثم تقوم Exosphere بتوفير شهادات TLS الموثوقة علناً لكلا أسماء المضيفين تلقائياً، بما في ذلك التجديدات. + +> **ملاحظة المنفذ 80:** يتحقق إصدار الشهادات الآلي والتجديد على HTTP على المنفذ 80 من كل موازن حمل. إذا كان موقف الأمان الخاص بك يتطلب تقييد موازن حمل لوحة المعلومات على نطاقات IP الشركة، أخبر Exosphere أولاً — نحن نبدل التحقق من الشهادة إلى طريقة قائمة على DNS (سجل DNS إضافي واحد على جانبك) بحيث تستمر التجديدات في العمل خلف التقييد. + +> **الصادرة:** يحتاج عُقد المجموعة إلى الوصول إلى الإنترنت لسحب صور الحاويات من `ghcr.io`. إذا كانت الشبكة الخاصة بك تقيد حركة المرور الصادرة، أدرج في القائمة البيضاء `ghcr.io` أو نسخ الصور احتياطياً إلى السجل الداخلي. + +--- + +## الخطوة 4: توفير حاوية تخزين النسخ الاحتياطية + +يتم تخزين النسخ الاحتياطية من قاعدة البيانات في حاوية تخزين سحابية تمتلكها. + +| المتطلب | التفاصيل | +|---|---| +| **الخدمة** | S3 (AWS) أو GCS (GCP) أو Azure Blob Storage | +| **الوصول** | منح الوصول للكتابة إلى عُقد المجموعة عبر دور IAM لحسابات الخدمات (IRSA على EKS أو Workload Identity على GKE) أو توفير بيانات الاعتماد | +| **الاحتفاظ** | أنت تتحكم في سياسة دورة حياة الحاوية (فترة الاحتفاظ وقواعد الأرشفة). تكتب Exosphere النسخ الاحتياطية؛ تقرر أنت المدة التي تريد الاحتفاظ بها | + +يقوم نسخة احتياطية واحدة يومية بتفريغ PostgreSQL (الحالة العلائقية) و ClickHouse (الأحداث والتقييمات) في أرشيف مضغوط واحد وتحميله إلى حاويتك. تعمل النسخ الاحتياطية أيضاً قبل كل ترقية. + +--- + +## الخطوة 5: تعيين جهة اتصال + +وفِّر شخص واحد أو قناة Slack/Teams على جانبك لمشاكل مستوى المجموعة: صحة العُقدة وحدود حساب السحابة والتغييرات على الشبكة. العمليات اليومية لا تتضمن هذه الجهة الاتصال. + +--- + +## ما ننشره + +بمجرد حصول Exosphere على وصول المجموعة، يتم نشر المكونات التالية وإدارتها نيابة عنك: + +| المكون | الدور | +|---|---| +| **خادم AgentEye** | واجهة برمجة تطبيقات HTTP تستقبل الأحداث من المجمِّعات وتشغّل التحليلات وتوفر البيانات للوحة المعلومات | +| **لوحة المعلومات** | واجهة ويب لعرض جلسات الوكيل واستدعاءات الأدوات وطلبات النموذج والأخطاء؛ تستضيف المساعد الذكي القراءة فقط الاختياري | +| **ClickHouse** | المتجر القانوني المطلوب للأحداث المستقبلة والتحليلات والتقييمات | +| **PostgreSQL** | المتجر العلائقي للمؤسسات ومفاتيح API والمستخدمين لوحات المعلومات والاستعلامات المحفوظة | +| **Redis** | ذاكرة التخزين المؤقت المشتركة الاختيارية وخلفية حد المعدل؛ تتدهور المنصة بأمان إذا كانت غير متاحة | +| **المساعد الذكي (اختياري)** | حاوية مساعد قراءة فقط داخلية؛ تبقى معطلة حتى يتم تكوين نقطة نهاية LLM | +| **متحكمات الدخول** | اثنان من موازنات الحمل (واحد لاستقبال محمي بـ mTLS وواحد لوحة المعلومات) ينهيان TLS بشهادات موثوقة علناً وذاتية التجديد ويفرضان mTLS على نقطة الاستقبال | +| **cert-manager** | يؤتمت توفير شهادات TLS وإصدار شهادات عميل mTLS | +| **مراقبة الشهادات** | تفحص مهمة مجدولة انقضاء الشهادة وتُرسل تنبيهات (على سبيل المثال إلى Slack) عندما تقترب الشهادات من التجديد | + +يقوم العرض المُدار أيضاً بتشغيل خط أنابيب التقييم الخاص بالمنصة، والذي يسجل نشاط الوكيل مقابل معايير التقييم الخاصة بك. راجع [المساعد](/ar/agenteye/assistant) و [مجموعة التقييم](/ar/agenteye/evaluation-suite) لمعرفة ما تقدمه هذه القدرات. + +--- + +## ما نوفره لك + +بعد اكتمال النشر، تتلقى: + +| العنصر | التفاصيل | +|---|---| +| **عنوان URL لوحة المعلومات** | اسم مضيف ضمن مجالك (على سبيل المثال `https://agenteye.your-company.example`)، موفر بشهادة TLS موثوقة علناً وذاتية التجديد. أنت تنشئ CNAME واحد لاسم مضيف موازن الحمل الذي توفره؛ تسجيل الدخول هو بكلمة مرور لمرة واحدة عبر البريد الإلكتروني | +| **نقطة نهاية المجمِّع** | مسار `/events` لاسم المضيف الخاص بالاستقبال (على سبيل المثال `https://ingest.your-company.example/events`)، محمي بـ mTLS | +| **حزمة شهادة العميل** | لكل مجموعة: شهادة عميل ومفتاح خاص وشهادة CA يتم تسليمها كبيان Secret من Kubernetes. طبِّقها مرة واحدة لكل مجموعة | +| **رمز GitHub** | لتحميل ثنائيات المجمِّع وحزم Python SDK | +| **مفاتيح API للمجمِّع** | مفاتيح مجالها بـ `events:add`، واحد لكل نشر مجمِّع | +| **أدلة التثبيت** | أدوات خطوة بخطوة لتثبيت المجمِّع و Python SDK | + +--- + +## ما تفعله بعد الإعداد + +يقتصر العمل الجاري الوحيد على أجهزة الوكيل الخاصة بك، وليس مجموعة AgentEye: + +1. **ثبت المجمِّع** في كل مجموعة Kubernetes التي تشغّل وكلاء ذكيين: اربط شهادة العميل وكوِّن عنوان URL لنقطة النهاية ومفتاح API. راجع [تثبيت المجمِّع](/ar/agenteye/collector-installation). +2. **دمِّج Python SDK** في رمز الوكيل الخاص بك. راجع [Python SDK](/ar/agenteye/python-sdk). +3. **افتح لوحة المعلومات** في متصفحك لعرض نشاط الوكيل. + +لا عمليات مجموعة ولا إدارة قاعدة بيانات ولا تجديدات شهادات ولا ترقيات. + +--- + +## الأمان + +- **البيانات تبقى في حسابك السحابي.** تعمل المجموعة والتخزين وقواعد البيانات في بيئتك. لا توجد بيانات تتجاوز حدودك. +- **أنت تتحكم في الوصول.** المجموعة في حسابك. يمكنك تدقيق أو مراقبة أو سحب وصول Exosphere في أي وقت. تمر جميع العمليات عبر سجل التدقيق السحابي (CloudTrail و GCP Audit Logs وما إلى ذلك). +- **mTLS على استقبال الأحداث.** يتطلب كل طلب مجمِّع شهادة عميل صالحة ومفتاح API. مفتاح مُسرب بلا فائدة بدون الشهادة؛ شهادة مسروقة بلا فائدة بدون مفتاح صالح. +- **التحكم بالوصول إلى لوحة المعلومات.** تعمل لوحة المعلومات على موازن حمل منفصل، منفصل عن استقبال الأحداث، وتسجيل الدخول هو بكلمة مرور لمرة واحدة عبر البريد الإلكتروني مقيدة بعناوين البريد الإلكتروني/النطاقات المسموحة بها. قائمة السماح بنطاق مصدر IP على موازن الحمل متاحة عند الطلب؛ لأن تجديد الشهادات الآلي يجب أن يصل إلى موازن الحمل، Exosphere يقيّد التقييد بالتحقق من الشهادة القائم على DNS بحيث تستمر التجديدات في العمل. +- **شهادات لكل مجموعة.** تتلقى كل مجموعة من مجموعاتك شهادة عميل خاصة بها. إذا تم اختراق مجموعة واحدة، يتم سحب تلك الشهادة بشكل مستقل دون التأثير على الآخرين. + +--- + +## الجدول الزمني للنشر + +| المرحلة | المدة | مشاركتك | +|---|---|---| +| **تجهيز المجموعة** | 1-2 يوم | جهِّز المجموعة ومنح Exosphere الوصول | +| **إعداد المنصة** | 1 يوم | بلا؛ Exosphere تثبت جميع مكونات البنية التحتية | +| **نشر التطبيق** | 1 يوم | بلا؛ Exosphere تنشر الخادم ولوحة المعلومات وتنشئ مفاتيح API | +| **طرح المجمِّع** | 1-3 يوم | ثبت المجمِّعات في مجموعاتك (بتوجيه من Exosphere) | +| **حرق الإنتاج** | 1 أسبوع | بلا؛ Exosphere تراقب وتضبط | + +الإجمالي المعتاد: **~أسبوعين** من البداية إلى جاهزية الإنتاج. + +--- + +## الدعم + +للأسئلة أو المشاكل، اتصل بـ Exosphere على `support@exosphere.host`. + +--- + +## الخطوات التالية + +- [البدء السريع](/ar/agenteye/getting-started): شرح شامل من النهاية إلى النهاية +- [تثبيت المجمِّع](/ar/agenteye/collector-installation): ثبت وكوِّن المجمِّع +- [Python SDK](/ar/agenteye/python-sdk): شغِّل رمز الوكيل الخاص بك +- [مفاتيح API](/ar/agenteye/api-keys): إدارة الوصول والأذونات +- [استكشاف الأخطاء](/ar/agenteye/troubleshooting): المشاكل الشائعة والإصلاحات \ No newline at end of file diff --git a/docs/ar/agenteye/python-sdk.mdx b/docs/ar/agenteye/python-sdk.mdx new file mode 100644 index 00000000..d7892e45 --- /dev/null +++ b/docs/ar/agenteye/python-sdk.mdx @@ -0,0 +1,387 @@ +--- +title: "Python SDK" +description: "وثائق AgentEye Python SDK." +--- + + +يوفر AgentEye Python SDK لك رؤية كاملة حول سلوك وكلائك (كل تشغيل للوكيل، واستدعاء أداة، وطلب نموذج، وخطاف، والتدخل البشري) حتى تتمكن من تصحيح الأخطاء وتدقيقها وتقييمها. يقوم بتطبيق الأداة على كود الوكيل الخاص بك عن طريق كتابة الأحداث المنظمة إلى ملفات JSONL محلية؛ يلتقط الجامع هذه الملفات ويرسلها إلى المنصة تلقائياً. + +--- + +## التثبيت + +قم بتنزيل ملف wheel من GitHub Releases باستخدام `AGENTEYE_TOKEN` الخاص بك. إذا لم تكن لديك رمز حتى الآن، راجع [إعداد رمز GitHub](/ar/agenteye/github-token) لخطوات الإعداد والأذونات المطلوبة. + +**باستخدام `gh` CLI + pip:** + +```bash +VERSION=0.0.1b9 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "python-sdk/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-*.whl' +pip install "agenteye-${VERSION}-py3-none-any.whl" +``` + +**باستخدام `gh` CLI + uv:** + +```bash +VERSION=0.0.1b9 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "python-sdk/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-*.whl' +uv add "./agenteye-${VERSION}-py3-none-any.whl" +``` + +**باستخدام curl (بدون `gh` CLI):** + +```bash +VERSION=0.0.1b9 +curl -fsSL \ + -H "Authorization: Bearer $AGENTEYE_TOKEN" \ + -L \ + "https://github.com/agenteye-enterprise/releases/releases/download/python-sdk%2Fv${VERSION}/agenteye-${VERSION}-py3-none-any.whl" \ + -o "agenteye-${VERSION}-py3-none-any.whl" +pip install "agenteye-${VERSION}-py3-none-any.whl" +``` + +--- + +## البدء السريع + +```python +import agenteye + +agenteye.configure(environment="production") + +agenteye.event.agent_start(session_id="run-001", agent_id="planner", goal="answer user query") + +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", + input={"query": "latest AI research"}, +) + +agenteye.event.tool_result( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", + output={"results": ["..."]}, +) + +agenteye.event.agent_end(session_id="run-001", agent_id="planner", outcome="success") +``` + +--- + +## configure() + +```python +agenteye.configure( + base_dir=None, # Path | str | None. Default: $AGENTEYE_HOME or ~/.agenteye + flush_interval=0.5, # float, seconds between flush cycles + environment=None, # str | None. Deployment environment label +) +``` + +اتصل مرة واحدة قبل أي استدعاء `event.*`. من الآمن حذفه؛ الإعدادات الافتراضية تعمل بشكل جيد. جميع الوسائط حسب الكلمات الرئيسية فقط؛ مررها بالاسم كما هو موضح أعلاه. + +عندما يكون `base_dir` هو `None` (الافتراضي)، يقرأ SDK `$AGENTEYE_HOME` إذا تم تعيينه، +وإلا يعود إلى `~/.agenteye`. هذا يتطابق مع دقة الجامع الخاصة به، +لذا فإن متغير بيئة واحد `AGENTEYE_HOME` يقوم بتكوين مجمع الأحداث المشترك لكل من +SDK والجامع، مطلوب للنشر الجانبي / النشر في حاوية واحدة حيث +يجب أن توافق كلا العمليتين على مسار مجمع الأحداث. + +--- + +## البيئة + +قم بتسمية كل حدث ببيئة نشر (`production` أو `staging` أو `qa` أو `canary` وما إلى ذلك). قم بتعيينه مرة واحدة؛ SDK يرفقه بكل حدث تلقائياً. + +**الخيار 1: عبر `configure()`:** + +```python +agenteye.configure(environment="production") +``` + +**الخيار 2: عبر متغير البيئة:** + +```bash +export AGENTEYE_ENVIRONMENT=production +``` + +**الأولوية:** `configure(environment=...)` يفوز على متغير البيئة. إذا لم يتم تعيين أي منهما، يتم استخدام القيمة الافتراضية `"dev"`. + +تظهر قيمة البيئة كعامل تصفية من الدرجة الأولى في لوحة المراقبة وتُخزن كعمود مفهرس على الخادم للاستعلامات السريعة. + +**قيد:** قيم البيئة **يجب ألا تحتوي على فاصلة حرفية `,`**. تصفية لوحة المراقبة تستخدم تحديد متعدد مفصول بفواصل على السلك (`?environment=prod,staging`)، لذا فإن بيئة باسم `prod,blue` سيتم تقسيمها إلى قيمتين. يتم رفض الأحداث التي تحتوي على بيئات بها فواصل وقت الاستقبال. + +--- + +## مرجع الحدث + +جميع طرق الحدث تتطلب هذين الحقلين: + +| الحقل | النوع | الوصف | +|---|---|---| +| `session_id` | `str` | يحدد تشغيل الوكيل من المستوى الأعلى | +| `agent_id` | `str` | يحدد أي وكيل داخل الجلسة أصدر الحدث | + +تقبل جميع الطرق أيضاً `**kwargs` عشوائية لبيانات وصفية مخصصة (انظر [الحقول المخصصة](#custom-fields)). + +--- + +### `event.agent_start()` + +تُصدر عندما يبدأ الوكيل العمل. + +```python +agenteye.event.agent_start( + session_id="run-001", + agent_id="planner", + goal="answer user query", # str | None + parent_id=None, # str | None - parent agent_id for nested agents +) +``` + +--- + +### `event.agent_end()` + +تُصدر عندما ينتهي الوكيل من العمل. + +```python +agenteye.event.agent_end( + session_id="run-001", + agent_id="planner", + outcome="success", # str | None + summary="Answered query", # str | None +) +``` + +--- + +### `event.tool_use()` + +تُصدر عندما يستدعي الوكيل أداة. اربطها مع `tool_result`؛ SDK يحسب `duration_ms` تلقائياً. + +```python +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="web_search", # str, required + tool_call_id="toolu_01", # str, required - correlation key for the matching tool_result + input={"query": "..."}, # dict | None +) +``` + +--- + +### `event.tool_result()` + +تُصدر عندما تعود أداة. ترتبط مع `tool_use` عبر `tool_call_id`. + +```python +agenteye.event.tool_result( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", # must match the prior tool_use + output={"results": ["..."]}, # Any | None + error=None, # str | None - set if the tool raised + # duration_ms is computed automatically - do not pass it +) +``` + +--- + +### `event.model_request()` + +تُصدر قبل إرسال موجز إلى نموذج لغة كبير. + +```python +agenteye.event.model_request( + session_id="run-001", + agent_id="planner", + model="claude-sonnet-4-6", # str | None + messages=[ # list[dict] | None - conversation turns + {"role": "user", "content": "..."}, + ], + system="You are helpful.", # Any | None - str or list of content blocks + tools=[ # list[dict] | None - tool schemas offered to the model + {"name": "search", "input_schema": {"type": "object"}}, + ], +) +``` + +تقبل إدخالات `messages` إما محتوى نصي عادي `content` أو قائمة كتل محتوى بأسلوب Anthropic. يمكن تمرير معاملات أخذ العينات (`temperature` و`max_tokens` وما إلى ذلك) كـ kwargs إضافية. + +--- + +### `event.model_response()` + +تُصدر عندما يعود نموذج اللغة برد. + +```python +agenteye.event.model_response( + session_id="run-001", + agent_id="planner", + model="claude-sonnet-4-6", # str | None + stop_reason="end_turn", # str | None + input_tokens=1024, # int | None + output_tokens=256, # int | None + content=[ # Any | None - str, or list of content blocks + {"type": "text", "text": "..."}, + ], + role="assistant", # str | None +) +``` + +يقبل `content` إما نص عادي (موفري عام) أو قائمة كتل محتوى بأسلوب Anthropic. استدعاءات الأدوات تعيش داخل `content` كأكتال `{"type": "tool_use", ...}`، بدون حقل `tool_calls` منفصل. + +--- + +### `event.hook_triggered()` + +تُصدر عندما ينطلق خطاف. اربطه مع `hook_completed`؛ SDK يحسب `duration_ms` تلقائياً. + +```python +agenteye.event.hook_triggered( + session_id="run-001", + agent_id="planner", + hook_name="pre_tool_use", # str, required + hook_id="hook-abc", # str, required - correlation key + trigger_event="tool_use", # str | None + input={"tool": "search"}, # Any | None +) +``` + +--- + +### `event.hook_completed()` + +تُصدر عندما ينتهي الخطاف. ترتبط مع `hook_triggered` عبر `hook_id`. + +```python +agenteye.event.hook_completed( + session_id="run-001", + agent_id="planner", + hook_name="pre_tool_use", + hook_id="hook-abc", # must match the prior hook_triggered + outcome="allow", # str | None + output=None, # Any | None + error=None, # str | None + # duration_ms is computed automatically - do not pass it +) +``` + +--- + +### `event.error()` + +تُصدر عندما يحدث خطأ غير معالج. + +```python +agenteye.event.error( + session_id="run-001", + agent_id="planner", + error_type="TimeoutError", # str, required + message="timed out", # str, required + traceback="Traceback...", # str | None +) +``` + +--- + +## أحداث التدخل البشري + +أحداث التدخل البشري تمنحك إشرافاً على اللحظات التي يتدخل فيها شخص في تنفيذ الوكيل (في انتظار الموافقة، أو توفير المدخلات، أو إيقاف مؤقت، أو إيقاف الوكيل). تسمح لك بقياس المدة التي يستغرقها البشر للرد (SDK يحسب `duration_ms` تلقائياً على الأحداث المزاوجة)، وتدقيق من أوقف أو قاطع وكيل، وبناء سير عمل الموافقة والإشراف التي تظهر في لوحة المراقبة. + +### `event.human_wait()` + +تُصدر عندما يوقف الوكيل التنفيذ في انتظار شخص لتوفير مدخل. اربطها مع `human_input`؛ SDK يحسب `duration_ms` تلقائياً (المدة التي استغرقها البشر للرد). + +```python +agenteye.event.human_wait( + session_id="run-001", + agent_id="planner", + input_id="inp-abc", # str, required - correlation key for the matching human_input + prompt="Do you approve this action?", # str | None - the question shown to the human + options=["approve", "reject", "defer"], # list[str] | None - choices presented to the human + reason="approval_required", # str | None - why the agent is waiting +) +``` + +### `event.human_input()` + +تُصدر عندما يوفر شخص مدخل ويستأنف الوكيل. ترتبط مع `human_wait` عبر `input_id`. يتم حساب `duration_ms` تلقائياً ولا يجب تمريره بواسطة المستدعي. + +```python +agenteye.event.human_input( + session_id="run-001", + agent_id="planner", + input_id="inp-abc", # str, required - must match the prior human_wait + response="approve", # str | None - the human's answer (free text or selected option) + # duration_ms is computed automatically - do not pass it +) +``` + +### `event.human_pause()` + +تُصدر عندما يوقف شخص الوكيل مؤقتاً بنشاط (مثلاً عبر تحكم لوحة المراقبة). يتم تعليق الوكيل لكن لا يتم إنهاؤه. + +```python +agenteye.event.human_pause( + session_id="run-001", + agent_id="planner", + reason="user_requested", # str | None + user_id="usr_42", # str | None - who paused the agent +) +``` + +### `event.human_interrupt()` + +تُصدر عندما يوقف شخص الوكيل بنشاط أثناء التنفيذ. بخلاف `human_pause`، يتم إنهاء عمل الوكيل بدلاً من تعليقه. + +```python +agenteye.event.human_interrupt( + session_id="run-001", + agent_id="planner", + reason="output_incorrect", # str | None + user_id="usr_42", # str | None - who interrupted the agent + at_step="tool_use:web_search", # str | None - what the agent was doing when stopped +) +``` + +--- + +## الحقول المخصصة + +أي وسائط كلمات رئيسية إضافية يتم إلحاقها بالحدث بعد الحقول القياسية: + +```python +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="db_query", + tool_call_id="toolu_02", + tenant_id="acme", # custom field + region="us-east-1", # custom field +) +``` + +`timestamp` و`type` و`environment` محجوزة وتثير `ValueError` (`Reserved field names cannot be used as custom fields: [...]`) إذا تم تمريرها كحقول مخصصة. `session_id` و`agent_id` معاملات مطلوبة على كل طريقة حدث ولا يمكن توفيرها مرة ثانية؛ Python يثير `TypeError` إذا فعلت ذلك. قم بتعيين البيئة باستخدام `configure(environment=...)` (أو متغير `AGENTEYE_ENVIRONMENT`) بدلاً من ذلك. + +--- + +## كيفية كتابة الأحداث + +يتم حفظ الأحداث في الذاكرة المؤقتة وتفريغها إلى القرص كل `flush_interval` ثانية (500 مللي ثانية افتراضياً). كل عملية تفريغ تكتب ملف JSONL واحد: + +``` +~/.agenteye/events/event-2026-04-01T12-00-00-000Z.jsonl +``` + +يراقب الجامع هذا المجلد ويرفع الملفات تلقائياً. لا تحتاج إلى إدارة هذه الملفات مباشرة. \ No newline at end of file diff --git a/docs/ar/agenteye/single-pod-deployment.mdx b/docs/ar/agenteye/single-pod-deployment.mdx new file mode 100644 index 00000000..70813c40 --- /dev/null +++ b/docs/ar/agenteye/single-pod-deployment.mdx @@ -0,0 +1,484 @@ +--- +--- +title: "نشر في pod واحد: مجمِّع البيانات + Sidecar التطبيق على EKS" +description: "توثيق نشر AgentEye في pod واحد: مجمِّع البيانات + Sidecar التطبيق على EKS." +--- + +قم بتشغيل تطبيقك ومجمِّع البيانات AgentEye **في نفس Pod الخاص بـ Kubernetes** بحيث لا تعبر بيانات المراقبة حدود الشبكة أبداً أثناء جمعها. تشارك SDK التطبيق الخاص بك ومجمِّع البيانات في ملف حدث واحد داخل Pod، مما يعني نقل بيانات مراقبة منخفض الكمون داخل العملية بدون منفذ localhost معرّض، بدون شبكة خدمات يجب عبورها، وتكون دورة حياة مجمِّع البيانات مرتبطة مباشرة بالحمل الذي يراقبه. شهادة عميل mTLS التي يقدمها مجمِّع البيانات يتم تسليمها مباشرة إلى pod الخاص بك من AWS Secrets Manager، لذا فإن تدوير بيانات الاعتماد لا يتطلب نقل ملفات يدوي من جانبك. + +نموذج sidecar + shared-spool الموصوف هنا غير مرتبط بسحابة معينة؛ يعمل وجود حاويتين تشتركان في ملف حدث `emptyDir` على أي توزيع Kubernetes. فقط مسار تسليم الشهادة في هذا الدليل (AWS Secrets Manager + Secrets Store CSI Driver + IRSA) مخصص لـ AWS / EKS. إذا كنت تعمل في مكان آخر، فاحتفظ بتخطيط Pod والملف وبدّل آلية التثبيت السرية لمنصتك للمرحلة 2 و 3. + +> **متى تستخدم هذا النمط.** اختر single-pod عندما لا يجب أن يتصل تطبيقك عبر حدود الشبكة للوصول إلى مجمِّع البيانات (IPC داخل Pod منخفض الكمون، ربط دورة الحياة الوثيق، عزل Pod لكل مستأجر). لأساطيل التطبيقات المتعددة التي تشارك مجمِّع بيانات واحد لكل عقدة أو لكل مجموعة، انظر إلى [enterprise-docs/kubernetes-deployment.md](/ar/agenteye/kubernetes-deployment) بدلاً من ذلك. + +--- + +## نظرة عامة + +``` +┌──────────────────────────────── Pod ─────────────────────────────────┐ +│ │ +│ ┌──────────────────────┐ ┌──────────────────────┐ │ +│ │ your-app │ │ agenteye-collector │ │ +│ │ (SDK writes JSONL) │ │ (sweeps events/, │ │ +│ │ │ │ uploads over mTLS) │ │ +│ └──────────┬───────────┘ └──────────┬───────────┘ │ +│ │ writes reads │ │ +│ ▼ ▼ │ +│ ┌────────────────────────────────────────────────────┐ │ +│ │ emptyDir: /var/lib/agenteye/{events,failed}/ │ │ +│ │ (AGENTEYE_HOME - shared event spool) │ │ +│ └────────────────────────────────────────────────────┘ │ +│ ▲ │ +│ │ reads cert │ +│ ┌────────┴─────────┐ │ +│ │ CSI (read-only): │ │ +│ │ /etc/agenteye/ │ │ +│ │ tls/client.{crt, │ │ +│ │ key}, ca.crt │ │ +│ └────────┬─────────┘ │ +└───────────────────────────────────────────────────┼──────────────────┘ + │ mounted by + │ Secrets Store CSI + │ (AWS provider + + │ IRSA) + ┌────────┴──────────┐ + │ AWS Secrets │ + │ Manager │ + │ agenteye/mtls- │ + │ client/ │ + └────────┬──────────┘ + ▲ + │ push on issue / + │ renewal + ┌────────┴──────────┐ + │ Exosphere │ + │ delivers the cert │ + │ bundle into your │ + │ Secrets Manager │ + │ on renewal │ + └───────────────────┘ + +Outbound: collector → AGENTEYE_URL (mTLS, using the CSI-mounted cert). +``` + +تدفقان للبيانات، مجلدان: + +- **الأحداث (داخل Pod):** تكتب SDK التطبيق ملفات `.jsonl` إلى ملف `emptyDir` المشترك في `$AGENTEYE_HOME/events/`؛ يقرأها منظف المجمِّع ويرفعها. بدون منفذ localhost، بدون حلقة loopback، نقل نظيف عبر النظام الملفات المشتركة. +- **شهادة mTLS (pod ← cloud):** يثبت Secrets Store CSI Driver حزمة الشهادة من Secrets Manager في حجم للقراءة فقط على `/etc/agenteye/tls/`، مُحدّد لحاوية المجمِّع. + +**طرفان مستقلان:** + +| الطرف | المسؤولية | +|---|---| +| Exosphere | تُصدر شهادة عميل mTLS وتسلّم الحزمة إلى **حسابك** على AWS Secrets Manager تحت اسم مستقر. تعيد نشر الحزمة المجددة في نفس السر قبل انتهاء الصلاحية. | +| أنت | قم بتثبيت Secrets Store CSI Driver، امنح وصول حسابك للخدمة بقراءة السر عبر IRSA، وطبّق بيان Pod. هذا كل شيء. | + +--- + +## المتطلبات الأساسية + +### في حسابك على AWS / مجموعة EKS الخاصة بك + +- مجموعة EKS مع **موفر OIDC** مرتبط بها. أكّد باستخدام: + + ```bash + aws eks describe-cluster --name \ + --query "cluster.identity.oidc.issuer" --output text + ``` + + إذا أرجعت الأوامر عنوان URL `https://oidc.eks.…`، فإن OIDC مُفعّل. إن لم يحدث، قم بربط واحد: + + ```bash + eksctl utils associate-iam-oidc-provider \ + --cluster --approve + ``` + +- [Secrets Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/) و [موفر AWS](https://github.com/aws/secrets-store-csi-driver-provider-aws) مثبتان في المجموعة (انظر § المرحلة 2). + +- AWS CLI v2 و `kubectl` على محطة العمل الخاصة بك. + +### التنسيق مع Exosphere + +قبل النشر، يسلّم Exosphere حزمة عميل mTLS إلى Secrets Manager في حسابك على AWS ويوفر: + +- **اسم السر** (الاتفاقية: `agenteye/mtls-client/`) +- **منطقة AWS** التي يوجد السر فيها +- **عنوان URL لخادم AgentEye** لتكوين المجمِّع به +- **مفتاح API** المجمِّع الخاص بك (انظر [enterprise-docs/api-keys.md](/ar/agenteye/api-keys)) + +--- + +## المرحلة 1: ما يسلّمه Exosphere + +لا تُنشِئ شهادة عميل mTLS بنفسك. تُصدرها Exosphere وتسلّم الحزمة مباشرة إلى Secrets Manager في حسابك على AWS، لذا فإن مادة بيانات الاعتماد الوحيدة التي تصل إلى بيئتك هي السر المنتهي والجاهز للتثبيت. + +ما يصل إلى حسابك: + +| الخاصية | القيمة | +|---|---| +| اسم السر | `agenteye/mtls-client/` (مستقر عبر التجديد) | +| المنطقة | منطقة AWS التي رشحتها لمجموعة EKS الخاصة بك | +| الحمولة | سر JSON واحد بثلاثة مفاتيح (`client.crt`, `client.key`, و `ca.crt`)، يحمل كل منها مادة مشفرة بصيغة PEM | +| الوسم | `AgentEyeCluster=` | + +عند التجديد، يتم تحديث نفس السر في الموقع بإصدار جديد، لذا فإن ARN والاسم لا يتغيران أبداً؛ `SecretProviderClass` وسياسة IAM الخاصة بك تستمر في العمل بدون تغيير. لدورة حياة الشهادة (الصلاحية، وتيرة التجديد، تنبيهات انتهاء الصلاحية) انظر [enterprise-docs/kubernetes-deployment.md](/ar/agenteye/kubernetes-deployment). + +--- + +## المرحلة 2: تثبيت Secrets Store CSI Driver + موفر AWS + +تخطَّ هذه الخطوة إذا كنت تقوم بتشغيل حمل عمل آخر يثبت أسرار AWS عبر CSI. + +```bash +# CSI Driver +helm repo add secrets-store-csi-driver \ + https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts +helm install -n kube-system csi-secrets-store \ + secrets-store-csi-driver/secrets-store-csi-driver \ + --set syncSecret.enabled=true \ + --set enableSecretRotation=true \ + --set rotationPollInterval=1h + +# AWS provider +kubectl apply -f \ + https://raw.githubusercontent.com/aws/secrets-store-csi-driver-provider-aws/main/deployment/aws-provider-installer.yaml +``` + +**تحقق:** + +```bash +kubectl get pods -n kube-system | grep -E 'csi-secrets-store|aws-provider' +``` + +متوقع: `Running` لكل pod. + +> **لماذا `rotationPollInterval=1h`؟** عندما ينشر Exosphere شهادة مجددة، يتم تحديث Secrets Manager في الموقع. يقرأ CSI Driver السر على هذه الفترة ويعيد كتابة الملفات المثبتة. يقرأ المجمِّع ملفات الشهادة مرة واحدة فقط عند بدء التشغيل، لذا فإنه يبدأ تقديم الشهادة المجددة فقط بعد إعادة تشغيل العملية؛ انظر § تجديد الشهادة لمعرفة كيفية تشغيل واحدة. + +--- + +## المرحلة 3: امنح Pod وصول القراءة إلى السر (IRSA) + +### 3.1 إنشاء سياسة IAM + +احفظ بـ `agenteye-mtls-reader-policy.json`: + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "ReadAgentEyeMtlsBundle", + "Effect": "Allow", + "Action": [ + "secretsmanager:GetSecretValue", + "secretsmanager:DescribeSecret" + ], + "Resource": "arn:aws:secretsmanager:::secret:agenteye/mtls-client/-*" + } + ] +} +``` + +استبدل `` و `` و ``. اللاحقة `-*` تطابق لاحقة عشوائية بستة أحرف تضيفها AWS لكل ARN سري. + +أنشئ السياسة: + +```bash +aws iam create-policy \ + --policy-name AgentEyeMtlsReader- \ + --policy-document file://agenteye-mtls-reader-policy.json +``` + +### 3.2 إنشاء دور IAM وربطه بـ ServiceAccount الخاص بـ Pod + +```bash +eksctl create iamserviceaccount \ + --name agenteye-pod \ + --namespace \ + --cluster \ + --role-name AgentEyePodRole- \ + --attach-policy-arn arn:aws:iam:::policy/AgentEyeMtlsReader- \ + --approve +``` + +ينشئ هذا `ServiceAccount` باسم `agenteye-pod` مع تعليق `eks.amazonaws.com/role-arn` يشير إلى الدور الجديد. + +### 3.3 أذونات IAM المطلوبة: ملخص + +| الإذن | النطاق | السبب | +|---|---|---| +| `secretsmanager:GetSecretValue` | `arn:aws:secretsmanager:::secret:agenteye/mtls-client/-*` | يقرأ CSI Driver حزمة الشهادة عند كل تثبيت + دورة تجديد. | +| `secretsmanager:DescribeSecret` | نفسه | يستدعي CSI Driver `DescribeSecret` للكشف عن تغييرات الإصدار بين الاستطلاعات. | + +**لا تمنح** `secretsmanager:PutSecretValue` أو `secretsmanager:UpdateSecret` أو `secretsmanager:DeleteSecret` لـ Pod. يقرأ Pod السر فقط؛ كتابة إصدارات جديدة يتم التعامل معها بواسطة Exosphere عند إصدار الشهادة أو تجديدها. + +إذا تم تشفير السر باستخدام مفتاح KMS مُدار من قبل العميل (ليس مفتاح `aws/secretsmanager` الافتراضي)، امنح أيضاً: + +```json +{ + "Effect": "Allow", + "Action": ["kms:Decrypt"], + "Resource": "arn:aws:kms:::key/", + "Condition": { + "StringEquals": { + "kms:ViaService": "secretsmanager..amazonaws.com" + } + } +} +``` + +--- + +## المرحلة 4: نشر Pod + +### 4.1 SecretProviderClass + +`agenteye-mtls-spc.yaml`: + +```yaml +apiVersion: secrets-store.csi.x-k8s.io/v1 +kind: SecretProviderClass +metadata: + name: agenteye-mtls + namespace: +spec: + provider: aws + parameters: + objects: | + - objectName: "agenteye/mtls-client/" + objectType: "secretsmanager" + jmesPath: + - path: '"client.crt"' + objectAlias: "client.crt" + - path: '"client.key"' + objectAlias: "client.key" + - path: '"ca.crt"' + objectAlias: "ca.crt" +``` + +يخبر كتلة `jmesPath` موفر AWS بتقسيم السر JSON إلى ثلاثة ملفات منفصلة على القرص. الاقتباس في `'"client.crt"'` مطلوب لأن JMESPath يتعامل مع `.` كعامل فرعي. + +```bash +kubectl apply -f agenteye-mtls-spc.yaml +``` + +### 4.2 بيان Pod / Deployment + +**كيف تتحدث الحاويتان مع بعضهما البعض.** لا تتصل SDK AgentEye والمجمِّع عبر مقبس شبكة؛ لا يوجد منفذ HTTP محلي. تكتب SDK دفعات الأحداث كملفات `.jsonl` إلى `$AGENTEYE_HOME/events/`، والمجمِّع يراقب هذا المجلد بشكل مستمر ويرفع كل ملف. بالنسبة لـ sidecar pod هذا يعني: + +- تثبت كلا الحاويتين نفس حجم `emptyDir` في نفس المسار. +- تعيّن كلا الحاويتين `AGENTEYE_HOME` إلى ذلك المسار. +- يجب أن تحتوي صورة التطبيق الخاصة بك على AgentEye SDK مثبت ومُكَوَّن (انظر [enterprise-docs/python-sdk.md](/ar/agenteye/python-sdk)). + +> عند عدم تعيين `AGENTEYE_HOME`، يُوجّه كل من SDK والمجمِّع إلى `~/.agenteye` افتراضياً، والحاويتان لهما دلائل رئيسية مختلفة، لذا ستصلان إلى ملفين منفصلين وسيفشل النقل صامتاً. عيّن `AGENTEYE_HOME` إلى نفس المسار الصريح في **كلا** الحاويتين. يمسك § 4.3 التحقق وصف استكشاف الأخطاء المطابق هذا إذا تم تفويته. + +`agenteye-pod.yaml` (Deployment بنسخة واحدة، قم بالتوسع حسب الحاجة): + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-app-with-collector + namespace: +spec: + replicas: 1 + selector: + matchLabels: + app: my-app-with-collector + template: + metadata: + labels: + app: my-app-with-collector + spec: + serviceAccountName: agenteye-pod + containers: + - name: app + image: + env: + # SDK writes event JSONL files into $AGENTEYE_HOME/events/ + - name: AGENTEYE_HOME + value: /var/lib/agenteye + volumeMounts: + - name: agenteye-spool + mountPath: /var/lib/agenteye + + - name: agenteye-collector + # Pin to a versioned :v tag for production; :beta-latest + # tracks the current beta build (:latest exists only for stable releases). + image: ghcr.io/agenteye-enterprise/collector:beta-latest + args: ["start"] + env: + # Must match the app container's AGENTEYE_HOME so the collector + # sweeps the same directory the SDK writes to. + - name: AGENTEYE_HOME + value: /var/lib/agenteye + - name: AGENTEYE_URL + value: "https://ingest.example.agenteye.com/events" + - name: AGENTEYE_KEY + valueFrom: + secretKeyRef: + name: agenteye-collector-api-key + key: key + - name: AGENTEYE_TLS_CERT + value: /etc/agenteye/tls/client.crt + - name: AGENTEYE_TLS_KEY + value: /etc/agenteye/tls/client.key + # Only when the AgentEye server presents a cert not signed by a + # publicly-trusted CA (e.g. self-signed by an in-cluster issuer + # because you have no real DNS domain). The CSI mount already + # exposes ca.crt alongside the client cert/key. + - name: AGENTEYE_TLS_CA + value: /etc/agenteye/tls/ca.crt + volumeMounts: + - name: agenteye-spool + mountPath: /var/lib/agenteye + - name: agenteye-mtls + mountPath: /etc/agenteye/tls + readOnly: true + livenessProbe: + exec: + command: ["agenteye-collector", "health"] + initialDelaySeconds: 10 + periodSeconds: 30 + + volumes: + # Shared event spool between app and collector. emptyDir is fine: + # events are transient and the collector drains them before pod + # termination on graceful shutdown. + - name: agenteye-spool + emptyDir: {} + # mTLS cert bundle, mounted read-only into the collector only. + - name: agenteye-mtls + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: agenteye-mtls +``` + +السر `agenteye-collector-api-key` يحمل مفتاح API المجمِّع (انظر [enterprise-docs/api-keys.md](/ar/agenteye/api-keys) للإمداد). + +**طبّق:** + +```bash +kubectl apply -f agenteye-pod.yaml +``` + +### 4.3 تحقق + +```bash +# Pod should be Running with 2/2 containers ready +kubectl get pods -n -l app=my-app-with-collector + +# Confirm the cert bundle was mounted +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- ls -l /etc/agenteye/tls/ +``` + +متوقع: `client.crt` و `client.key` و `ca.crt` جميعها موجودة وللقراءة فقط، مملوكة من قبل مستخدم الحاوية. + +**تأكّد من رؤية ملف الأحداث المشترك لكلا الحاويتين:** + +```bash +# In the collector, should show the events/ and failed/ subdirs that +# the collector auto-creates on startup: +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- ls /var/lib/agenteye/ + +# In the app, should show the same directory contents: +kubectl exec -n deploy/my-app-with-collector \ + -c app -- ls /var/lib/agenteye/ +``` + +إذا تباعدت القائمتان، فإن الحجم لم يتم تثبيته في كلا الحاويتين (أو اختلفت `AGENTEYE_HOME`)؛ انظر § استكشاف الأخطاء والإصلاح. + +**اختبار نهاية إلى نهاية:** + +```bash +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- agenteye-collector flush +``` + +متوقع: يرفع المجمِّع أي أحداث في الطابور ويطبع ملخص `Done: N/N uploaded, 0 failed.`. إذا كان الملف فارغاً يطبع `No pending files.` ويخرج بدون التحقق من أي شيء — لذا قم بتشغيل هذا فقط بعد أن يفرغ التطبيق حدثاً واحداً على الأقل. + +لاحظ أن `flush` يخرج برمز غير صفري **فقط** من أجل أعطال الإعداد المحلي: الإعدادات المفقودة (لا URL / مفتاح تم حله) أو شهادة TLS غير قابلة للقراءة / غير قابلة للتحليل (تحقق من § استكشاف الأخطاء والإصلاح). **مفتاح API خاطئ لا يغير كود الخروج** — التحميل يحصل على `401`، يتم نقل الملف إلى `failed/`، والأمر لا يزال يطبع `[FAILED] …` لكل ملف زائد `Done: 0/N uploaded, N failed.` ويخرج `0`. للكشف عن مفتاح سيء أو تحميل مرفوض، اقرأ مخرجات `Done:`/`[FAILED]` أو تحقق من الملفات التي تصل إلى `$AGENTEYE_HOME/failed/`، ليس كود الخروج. + +--- + +## تجديد الشهادة + +شهادة العميل صالحة لمدة 90 يوماً ويتم تجديدها تلقائياً حوالي 15 يوماً قبل انتهاء الصلاحية؛ ينشر Exosphere الحزمة المجددة في نفس سر Secrets Manager. من هناك، يكون التدفق داخل Pod: + +1. الحصول على سر Secrets Manager إصدار `AWSCURRENT` جديد. ARN والاسم لا يتغيران. +2. ضمن `rotationPollInterval` (افتراضياً 1 ساعة؛ انظر § المرحلة 2)، يقرأ CSI Driver الإصدار الجديد ويعيد كتابة الملفات تحت `/etc/agenteye/tls/`. +3. يحمّل المجمِّع ملفات الشهادة **مرة واحدة فقط عند بدء التشغيل**، لذا فإنه يستمر في تقديم الشهادة السابقة حتى إعادة تشغيل العملية. للتبديل إلى المادة المجددة، أعد تشغيل المجمِّع؛ إعادة التشغيل المتحركة كافية: + + ```bash + kubectl rollout restart deploy/my-app-with-collector -n + ``` + + لجعل هذا تلقائياً، أضف sidecar يراقب `/etc/agenteye/tls/` (على سبيل المثال مع `inotifywait`) وينطلق عند تغيير الملفات. + +لأن الشهادة السابقة تبقى صالحة لمدة تقريباً 15 يوماً بعد التجديد، لديك نافذة واسعة لإجراء إعادة التشغيل بدون انقطاع في الاستيعاب. ينشر Exosphere الحزمة المجددة لك؛ الإجراء الروتيني الوحيد من جانبك هو التأكد من إعادة تشغيل المجمِّع ضمن تلك النافذة. + +--- + +## استكشاف الأخطاء والإصلاح + +| العرض | السبب المحتمل | الإصلاح | +|---|---|---| +| Pod عالق في `ContainerCreating`، تُظهر الأحداث `MountVolume.SetUp failed for volume "agenteye-mtls"` | لا يمكن لموفر CSI الوصول إلى Secrets Manager | تحقق من ربط IRSA بشكل صحيح: `kubectl describe sa agenteye-pod -n ` يُظهر تعليق `eks.amazonaws.com/role-arn`. افحص CloudTrail لاستدعاء AssumeRole. | +| خطأ: `AccessDeniedException: not authorized to perform secretsmanager:GetSecretValue` | نطاق سياسة IAM إلى ARN خاطئ | لاحقة ARN السرية عشوائية؛ استخدم `agenteye/mtls-client/-*` مع البدل، ليس ARN الدقيق. | +| خطأ: `ParameterNotFound` من موفر AWS | عدم تطابق اسم السر بين `SecretProviderClass.objects[].objectName` والسر الذي سلّمه Exosphere | تأكّد من الاسم الدقيق مع `aws secretsmanager list-secrets --filters Key=tag-key,Values=AgentEyeCluster`. | +| خطأ `jmesPath`، تم تثبيت ملف واحد فقط | بناء جملة JMESPath | الأرقام في مفاتيح JSON تتطلب اقتباساً مزدوجاً: `'"client.crt"'`، ليس `client.crt`. | +| السجل `tls: bad certificate` بعد التجديد | لم يستطلع CSI Driver الإصدار الجديد حتى الآن، أو لا يزال المجمِّع يعمل مع الشهادة السابقة التي حمّلها عند بدء التشغيل | تأكّد من تحديث الملفات المثبتة (`ls -l /etc/agenteye/tls/`)، ثم أعد تشغيل المجمِّع لتحميلها: `kubectl rollout restart deploy/my-app-with-collector -n `. انظر § تجديد الشهادة. | +| حاوية المجمِّع crashloops مع `no such file or directory: /etc/agenteye/tls/client.crt` | لم يتم ملء الحجم حتى الآن عند بدء التشغيل الأول؛ مسبار بدء التشغيل عدواني جداً | أضف تأخير ابتدائي صغير أو استخدم initContainer ينتظر وجود الملف: `until [ -f /etc/agenteye/tls/client.crt ]; do sleep 1; done`. | +| pod CSI Driver `OOMKilled` | حدود الذاكرة الافتراضية منخفضة جداً للمجموعات التي تحتوي على العديد من SecretProviderClasses | زيادة `--set linux.resources.limits.memory=200Mi` في تثبيت Helm. | +| التطبيق يعمل بشكل نظيف، `agenteye-collector flush` يُبلّغ `No pending files.`، لكن لوحة معلومات AgentEye الخاصة بك لا تظهر أحداث | التطبيق والمجمِّع لا يشتركان في ملف الأحداث | تحقق من (أ) كلا الحاويتين تثبتان نفس `agenteye-spool` emptyDir في نفس المسار، و (ب) كلاهما يعيّن `AGENTEYE_HOME` إلى ذلك المسار. قم بتشغيل الفحصات `ls /var/lib/agenteye/` من § 4.3؛ يجب أن تطابق القوائم. | + +**السجلات المراد الحصول عليها أولاً:** + +```bash +kubectl logs -n kube-system -l app=secrets-store-csi-driver --tail=100 +kubectl logs -n kube-system -l app=csi-secrets-store-provider-aws --tail=100 +kubectl describe pod -n -l app=my-app-with-collector +``` + +--- + +## المرجع: الملفات على القرص في Pod + +يحتوي Pod على مساران للبيانات على القرص: + +### حزمة شهادة mTLS: `/etc/agenteye/tls/` (CSI، قراءة فقط، المجمِّع فقط) + +مثبتة بواسطة Secrets Store CSI Driver من AWS Secrets Manager. + +| الملف | المحتويات | المستخدمة من قبل المجمِّع كـ | +|---|---|---| +| `client.crt` | شهادة عميل مشفرة بصيغة PEM | `AGENTEYE_TLS_CERT` | +| `client.key` | مفتاح خاص مشفر بصيغة PEM | `AGENTEYE_TLS_KEY` | +| `ca.crt` | شهادة CA مشفرة بصيغة PEM | `AGENTEYE_TLS_CA` (اختياري، فقط عندما لا تكون شهادة خادم AgentEye موقعة من قبل CA عام) | + +الثلاثة مثبتة للقراءة فقط ومملوكة من قبل مستخدم الحاوية. يتم إعادة كتابتها بواسطة CSI Driver عند تدوير السر. + +### ملف الأحداث: `$AGENTEYE_HOME/` (emptyDir، قراءة وكتابة مشتركة بين كلا الحاويتين) + +مشترك عبر حجم `emptyDir` باسم `agenteye-spool`. + +| المسار | مكتوب بواسطة | يُقرأ بواسطة | الغرض | +|---|---|---|---| +| `$AGENTEYE_HOME/events/*.jsonl` | التطبيق (AgentEye SDK) | منظف المجمِّع | دفعات الأحداث التي فرغتها SDK، في انتظار التحميل. | +| `$AGENTEYE_HOME/failed/` | المجمِّع (عند فشل التحميل) | أنت (عند تصحيح الأخطاء) | ملفات JSONL لم يتمكن المجمِّع من تحميلها بعد المحاولات. | +| `$AGENTEYE_HOME/config.json` | أنت (اختياري) | المجمِّع | ملف اختياري لإعدادات المجمِّع (بديل لمتغيرات env). | + +يتم إنشاء كل من دلائل `events/` و `failed/` تلقائياً بواسطة المجمِّع عند بدء التشغيل؛ لا يلزم `initContainer`. + +--- + +## الوثائق ذات الصلة + +- [enterprise-docs/collector-installation.md](/ar/agenteye/collector-installation): خيارات ملف المجمِّع الثنائي، مرجع إعدادات mTLS، أوضاع daemon. +- [enterprise-docs/kubernetes-deployment.md](/ar/agenteye/kubernetes-deployment): نشر متعدد الأجهزة، داخليات إصدار الشهادة، تنبيهات دورة الحياة والصلاحية. +- [enterprise-docs/api-keys.md](/ar/agenteye/api-keys): إمداد مفتاح API المجمِّع الذي استهلكته Pod. +- [enterprise-docs/troubleshooting.md](/ar/agenteye/troubleshooting): فهرس استكشاف الأخطاء على مستوى المجموعة. \ No newline at end of file diff --git a/docs/ar/agenteye/tenant-management.mdx b/docs/ar/agenteye/tenant-management.mdx new file mode 100644 index 00000000..31ccfd21 --- /dev/null +++ b/docs/ar/agenteye/tenant-management.mdx @@ -0,0 +1,168 @@ +--- +--- +title: "إدارة المستأجرين (المنظمات والأعضاء)" +description: "وثائق إدارة المستأجرين في AgentEye (المنظمات والأعضاء)." +--- + + +نشر AgentEye واحد يخدم عدة **منظمات** (مستأجرين) معزولة تماماً، لذا يمكن لمثيل واحد استضافة فرق مختلفة أو وحدات أعمال أو عملاء دون تعريض بيانات أي مستأجر واحد للآخر. كل صف من البيانات (الأحداث والتقييمات والجلسات والوحات البيانات والاستعلامات المحفوظة والتنبيهات ومفاتيح API والأعضاء) ينتمي إلى منظمة واحدة بالضبط. يتم فرض العزلة الأساسية في كود التطبيق: كل طلب يقتصر على منظمته بوسائط `org_id` صريحة. على ClickHouse — حيث تعيش الأحداث والتقييمات عالية الحجم — يتم دعم هذا بفرض قوي على مستوى المحرك: كل منظمة تحصل على مستخدم ClickHouse مخصص للقراءة فقط مع سياسة صف لكل منظمة، لذا لا يمكن لحتى استعلام SQL التحليلي غير الموثوق أن يقرأ صفوف مستأجر آخر. على PostgreSQL، يضيف الأمان على مستوى الصف دفاعاً متعدد الطبقات على مسار الاستعلام للقراءة فقط (`/queries/run`)، ليضيق ما يمكن لهذا المسار رؤيته حتى لو كان مرشح على مستوى التطبيق مفقوداً في يوم من الأيام؛ اتصال الكتابة الخاص بالخادم يعمل كمالك الجدول وبالتالي يعمل من خلال نفس نطاق `org_id` على مستوى التطبيق. + +دورة حياة المستأجر يتحكم بها المشغل، بينما كل شيء يفعله الأعضاء يومياً يبقى ذاتي الخدمة في لوحة المعلومات. يتم إنشاء وإدارة المنظمات وعضوياتها باستخدام CLI **`agenteye-orgctl`**، الذي يأتي داخل صورة الخادم ويعمل **داخل حاوية الخادم الموجودة**. يتم إبقاء إنشاء وحذف المستأجرين بشكل متعمد بعيداً عن لوحة المعلومات و HTTP API: لا يوجد **لا HTTP API ولا زر لوحة معلومات** لدورة حياة المستأجر، لذا فهو محمي خلف وصول الكلستر/حاوية shell بدلاً من سطح التطبيق. + +داخل منظمة، يعمل الأعضاء بالكامل في لوحة المعلومات و API: يقومون بالتسجيل والتنقل بين المنظمات التي ينتمون إليها وإدارة مفاتيح API الخاصة بهم وبناء لوحات المعلومات والاستعلامات المحفوظة وتكوين التنبيهات لمنظمتهم. الفصل نظيف: يقوم المشغلون بتوفير وإلغاء تشغيل المستأجرين وأعضائهم عبر CLI؛ يقوم الأعضاء بتشغيل كل شيء داخل مستأجر من خلال واجهة المستخدم. + +> **النشرات أحادية المستأجر لا تحتاج إلى أي من هذا.** يعمل التثبيت أحادي المستأجر بدون أي إجراء من المشغل. جميع البيانات والمستخدمون والمفاتيح يعيشون في منظمة `default` مدمجة يتم توفيرها تلقائياً. تحتاج فقط إلى هذا الدليل عندما تقرر إضافة منظمة ثانية. + +--- + +## المتطلبات الأساسية + +قبل إنشاء **منظمتك الثانية** (لا تحتاج المنظمة المدمجة `default` إلى أي شيء): + +- **PostgreSQL 15+.** مخطط عضوية المنظمة يستخدم مفتاح أجنبي `ON DELETE SET NULL` لقائمة الأعمدة يتطلب PostgreSQL 15+. قم بترقية PostgreSQL قبل توفير منظمة ثانية. +- **`ORG_CH_SECRET` قوي واستقر.** كلمة مرور ClickHouse لكل منظمة مشتقة من `HMAC(ORG_CH_SECRET, org_id)`، لذا فإن القيمة الافتراضية للتطوير المدمجة المعروفة علناً ستؤدي إلى بيانات اعتماد لكل منظمة قابلة للاشتقاق علناً. `agenteye-orgctl org create` **يرفض التشغيل بينما `ORG_CH_SECRET` غير محدد أو مترك في القيمة الافتراضية للتطوير المدمجة**. قم بتعيين قيمتك الخاصة أولاً (انظر [النشر → متغيرات البيئة](/ar/agenteye/deployment) وعلى Kubernetes، [§2.6 من دليل Kubernetes](/ar/agenteye/kubernetes-deployment#26-multi-tenant-org-isolation-key-optional)). احتفظ بها متطابقة عبر جميع نسخ الخادم ولا تدورها بالصدفة؛ تدويرها يترك كل مستخدم ClickHouse لكل منظمة مهجوراً حتى إعادة البدء التالية إعادة توفيرهم. + +--- + +## تشغيل CLI + +يتم شحن `agenteye-orgctl` في **نفس صورة الخادم** (جنباً إلى جنب مع `agenteye-server`). أنت **لا** نشر حاوية منفصلة أو Job أو Deployment؛ قم بتنفيذه داخل حاوية الخادم التي تعمل بالفعل، لذا فهو يقرأ نفس `DATABASE_URL` و `CLICKHOUSE_URL` و `ORG_CH_SECRET` الذي يستخدمه الخادم. + +**Kubernetes:** + +```bash +kubectl -n agenteye exec deploy/server -- agenteye-orgctl +``` + +**Docker Compose:** + +```bash +docker compose exec server agenteye-orgctl +``` + +الأمثلة أدناه تُظهر `agenteye-orgctl ` المجردة للإيجاز؛ ضع بادئة لكل مع أيهما من السطرين أعلاه يطابق نشرك. + +--- + +## مرجع الأوامر + +### المنظمات + +| الأمر | ما يفعله | +|---|---| +| `org create --slug --name ` | إنشاء منظمة جديدة. يرفض التشغيل بينما `ORG_CH_SECRET` غير محدد أو مترك في القيمة الافتراضية للتطوير المدمجة (قم بتعيين قيمتك الخاصة أولاً، انظر المتطلبات الأساسية). يوفر مستخدم ClickHouse للقراءة فقط للمنظمة + سياسة الصف. | +| `org list` | قائمة بجميع المنظمات (slug والاسم وحالة دورة الحياة). | +| `org rename --slug --name ` | غيّر اسم عرض المنظمة. slug (المستخدم في URLs والمفاتيح) لم يتغير. | +| `org delete --slug ` | **حذف ناعم** للمنظمة وحذف مستخدم ClickHouse الخاص بها. البيانات **محتفظ بها**. هذا يلغي الوصول ويحرر بيانات اعتماد ClickHouse لكل منظمة، لكنه لا يمسح الأحداث. قابلة للعكس من قبل المشغل؛ خطوة آمنة أولى قبل التطهير. | +| `org purge --slug ` | **مسح بيانات لا رجوع فيه.** يجب أن تكون المنظمة مُحذوفة بالفعل `delete`. لا يُسمح به مطلقاً على المنظمة المدمجة `default`. استخدم فقط عندما تكون متأكداً من أن بيانات المستأجر يجب أن تُدمر. | + +### الأعضاء + +| الأمر | ما يفعله | +|---|---| +| `member add --org --email [--set ] [--add perm1,perm2] [--remove perm3] [--protected]` | إضافة عضو إلى منظمة. يمكن اختيارياً البدء من مجموعة أذونات مدمجة، ثم إضافة/إزالة أذونات فردية. `--protected` يثبت العضو حتى لا تتمكن لوحة المعلومات من إزالته أو خفض درجته (انظر أدناه). يحصل العضو الجديد على OTP عند أول تسجيل دخول له في لوحة المعلومات. | +| `member list --org ` | قائمة بأعضاء المنظمة. أعمدة الإخراج هي `EMAIL` و `SET` (مجموعة المدمجة التي بدأ العضو منها، أو `-`) و `PROT` (ما إذا كان العضو محمياً) و `PERMISSIONS` (أذوناته الفعلية). البريد الإلكتروني المعروض مع علامة `*` لاحقة هو مسؤول نسخة؛ لديهم وصول إلى كل منظمة. | +| `member update --org --email [--set ...] [--add ...] [--remove ...] [--protected \| --unprotect]` | غيّر أذونات العضو و/أو علامة الحماية. `--set` يستبدل من مجموعة مدمجة؛ `--add` / `--remove` تضبط الأذونات الفردية؛ `--protected` / `--unprotect` تبديل الحماية. تمرير فقط `--protected`/`--unprotect` (بدون علامات منح) يغير الحماية وحدها ويترك الأذونات الموجودة سليمة. | +| `member remove --org --email ` | إزالة عضو من المنظمة. يرفض إذا كان العضو محمياً؛ قم بـ `--unprotect` أولاً. (يمكن لشخص أن يكون عضواً في عدة منظمات؛ هذا يؤثر فقط على المنظمة المسماة.) | + +يمكن لشخص أن يكون عضواً في أكثر من منظمة واحدة مع **أذونات مختلفة** في كل منها، مثل مسؤول في منظمة واحدة وقراءة فقط في منظمة أخرى. يتم إدارة كل عضوية بشكل مستقل لكل منظمة: منح أو تغيير أذونات شخص في منظمة واحدة ليس له تأثير على عضويتهم في أي منظمة أخرى. + +### الأعضاء المحميون (مسؤول منظمة غير قابل للإزالة) + +تضمن الحماية أن المنظمة لا تقفل نفسها عرضياً عن إدارة ذاتية. بشكل افتراضي، يمكن لمسؤولي المنظمة الخاصة بها إضافة وإزالة بعضهم البعض من خلال صفحة المستخدمين ذاتية الخدمة لوحة المعلومات، لذا يمكنهم إزالة آخر مسؤول وترك المنظمة بدون أي شخص قادر على إدارتها. + +![صفحة المستخدمين: بطاقة لكل مستخدم لوحة معلومات ببريده الإلكتروني والأذونات الممنوحة وعناصر التحكم بالتعديل/التعطيل](/agenteye/images/users.png) + +لمنع ذلك، ضع علامة على عضو واحد **محمي**: + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member add --org acme --email owner@acme.example --set admin --protected +``` + +لا يمكن إزالة أو خفض درجة عضو محمي **من خلال لوحة المعلومات**؛ تلك الإجراءات ترجع خطأ. فقط المشغل يمكنه تغييرهم، وفقط عبر هذا CLI: قم بتشغيل `member update --org acme --email owner@acme.example --unprotect` أولاً، ثم أزل أو اخفض الدرجة. هذا يضمن أن كل منظمة تحافظ على مسؤول واحد على الأقل أعضاؤها لا يمكنهم قفله، مع الحفاظ على التحكم في المستأجر بطريقة المشغل. الحماية **لكل منظمة**؛ حماية شخص ما في منظمة واحدة ليس لها تأثير على عضويتهم في منظمة أخرى. + +### مجموعات الأذونات المدمجة + +يقبل `--set` إحدى ثلاث مجموعات مدمجة، مطبقة لكل منظمة: + +| المجموعة | المقصود بها | +|---|---| +| `admin` | وصول كامل داخل المنظمة، بما في ذلك إدارة مفاتيح API والمستخدمين في المنظمة. | +| `standard` | الاستخدام اليومي: استعلامات القراءة والتشغيل وبناء لوحات المعلومات والإقرار بالحوادث. | +| `read-only` | وصول العرض فقط إلى بيانات ولوحات معلومات المنظمة. | + +ابدأ من مجموعة بـ `--set`، ثم قم بالتعديل الدقيق بـ `--add` / `--remove` باستخدام رموز الأذونات الفردية المدرجة في [مفاتيح API](/ar/agenteye/api-keys). رموز الأذونات نفسها متطابقة مع تلك المستخدمة في مفاتيح API. + +--- + +## مثال عملي + +توفير مستأجر `acme` جديد وإضافة أول مسؤول له والسماح له بصك مفتاح ثم إيقاف تشغيل المنظمة. + +**1. إنشاء المنظمة** (يجب أن يكون `ORG_CH_SECRET` محدداً بالفعل لقيمة قوية واستقرار، ليس غير محدد أو القيمة الافتراضية للتطوير المدمجة): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org create --slug acme --name "Acme Corp" +``` + +**2. إضافة أول عضو كمسؤول منظمة:** + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member add --org acme --email alice@acme.example --set admin +``` + +تتلقى Alice كود OTP في المرة الأولى التي تسجل فيها الدخول إلى لوحة المعلومات. من هنا فصاعداً، تعمل بالكامل في واجهة المستخدم تحت بادئة URL الخاصة بمنظمتها (مثلاً `/acme/sessions`). + +**3. صك مفتاح API لكل منظمة (في لوحة المعلومات):** + +المشغل **لا** يصك مفاتيح بيانات لكل منظمة من CLI. تقوم Alice (أو أي عضو منظمة يمتلك `keys:create`) بإنشاء مفاتيح المجمع / لوحة المعلومات لمنظمة `acme` من صفحة **Keys** في لوحة المعلومات. كل مفتاح تنشئه يتم ختمه تلقائياً مع منظمتها ولا يمكن أبداً قراءة أو كتابة بيانات سوى `acme`. انظر [مفاتيح API](/ar/agenteye/api-keys). + +**4. تعديل عضو لاحقاً:** + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member update --org acme --email alice@acme.example --add alerts:write + +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member list --org acme +``` + +**5. حذف ناعم للمنظمة** (إلغاء الوصول + حذف مستخدم ClickHouse الخاص بها؛ البيانات محتفظ بها): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org delete --slug acme +``` + +**6. تطهير المنظمة** (لا رجوع فيه؛ فقط بعد حذف ناعم؛ لا أبداً المنظمة `default`): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org purge --slug acme +``` + +على Docker Compose، استبدل كل بادئة `kubectl -n agenteye exec deploy/server --` بـ `docker compose exec server`. + +--- + +## تقسيم المسؤوليات + +كل شيء يحتاجه عضو المنظمة يومياً هو خدمة ذاتية في لوحة المعلومات و API، محصور تلقائياً إلى منظمتهم الحالية: + +- **مفاتيح API لكل منظمة** يتم إنشاؤها وإدارتها من قبل أعضاء المنظمة في لوحة المعلومات (أو عبر مفاتيح API مع مفتاح يحمل `keys:create`). لا يصك CLI مفاتيح بيانات. انظر [مفاتيح API](/ar/agenteye/api-keys). +- **تبديل المنظمة** مدمج في لوحة المعلومات؛ يتبديل الأعضاء بين المنظمات التي ينتمون إليها من مفتاح المنظمة، وتعيش صفحات نطاق المنظمة تحت `//…`. +- **لوحات المعلومات والاستعلامات المحفوظة والتنبيهات وجميع استخدام البيانات** تحدث بالكامل في واجهة المستخدم و API، محصور إلى منظمة العضو الحالية. + +المشغل، باستخدام `agenteye-orgctl`، يملك فقط **دورة الحياة** للمنظمة والعضو: إنشاء / إعادة تسمية / حذف / تطهير منظمة وإضافة / قائمة / تحديث / إزالة عضو. + +--- + +## انظر أيضاً + +- [النشر](/ar/agenteye/deployment): `ORG_CH_SECRET` وبقية بيئة الخادم. +- [نشر Kubernetes](/ar/agenteye/kubernetes-deployment): §2.6 ينشئ Secret `agenteye-org-ch-secret` قبل أول منظمة متعددة المستأجرين الخاصة بك. +- [مفاتيح API](/ar/agenteye/api-keys): نموذج المفتاح لكل منظمة ورموز الأذونات المستخدمة بـ `--add` / `--remove`. +- [استكشاف الأخطاء](/ar/agenteye/troubleshooting): توفير متعدد المستأجرين ومشاكل عزل ClickHouse. \ No newline at end of file diff --git a/docs/ar/agenteye/troubleshooting.mdx b/docs/ar/agenteye/troubleshooting.mdx new file mode 100644 index 00000000..19452002 --- /dev/null +++ b/docs/ar/agenteye/troubleshooting.mdx @@ -0,0 +1,566 @@ +--- +--- +title: "استكشاف الأخطاء" +description: "توثيق استكشاف أخطاء AgentEye." +--- + + +يوفر هذا الدليل تعيينًا بين الأعراض التي من المحتمل أن تواجهها في الإنتاج والتشخيص الفعلي والإصلاح، بحيث يمكنك حل الحوادث باستخدام الأدوات التي لديك بالفعل، دون الحاجة إلى إعداد بنية مراقبة إضافية. يغطي الخادم والمجمّع والموجة الأمامية والمساعد الذكي وSDK Python والمراقبة الصحية ومراقبة الشهادات والنسخ الاحتياطية والتحليلات المدعومة بـ ClickHouse والاستضافة متعددة المستأجرين. + +صفحات الموجة الأمامية محدودة النطاق بالمنظمة تحت `//…`، وتدفق الأحداث هو منزل المنظمة (`//`). أسماء الصفحات في هذا الدليل (على سبيل المثال `/sessions`، `/queries`) تشير إلى تلك المسارات المحدودة النطاق بالمنظمة. + +--- + +## عرض السجلات + +لا يتضمن AgentEye مجموعة تسجيل أو مراقبة. يكتب كل من الخادم والموجة الأمامية السجلات المنظمة إلى **stdout**، لذا يمكنك قراءتها مباشرة باستخدام `kubectl` أو `docker`؛ لا يلزم محمّع. + +### Kubernetes + +اتبع السجلات الحية للخادم والموجة الأمامية: + +```bash +kubectl logs -n agenteye -l app=server -f --timestamps +kubectl logs -n agenteye -l app=dashboard -f --timestamps +``` + +متغيرات مفيدة: + +| الهدف | الأمر | +|---|---| +| آخر 200 سطر (بدون متابعة) | `kubectl logs -n agenteye -l app=server --tail=200 --timestamps` | +| السجلات من الانهيار السابق | `kubectl logs -n agenteye --previous` | +| تتبع جميع النسخ المتماثلة في نفس الوقت | `kubectl logs -n agenteye -l app=server --max-log-requests=10 -f` | +| Postgres (StatefulSet) | `kubectl logs -n agenteye postgres-0 -f` | + +### Docker Compose + +```bash +docker logs -f agenteye-server +docker logs -f agenteye-dashboard +``` + +### ربط طلب واحد عبر الموجة الأمامية والخادم + +كل طلب موجة أمامية يُوسّم بـ `request_id` ويُنتشر إلى الخادم عبر رأس `x-request-id`. يرد الخادم على رأس الاستجابة وفي كل سطر سجل يصدره لذلك الطلب. لتتبع طلب واحد من البداية إلى النهاية: + +1. التقط المعرّف من رأس الاستجابة، على سبيل المثال: + ```bash + curl -i https://dashboard.example.com/api/events | grep -i x-request-id + # x-request-id: 9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a + ``` +2. ابحث في سجلات كلا الأجهزة عن ذلك المعرّف: + ```bash + REQ=9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a + kubectl logs -n agenteye -l app=dashboard --tail=5000 | grep "$REQ" + kubectl logs -n agenteye -l app=server --tail=5000 | grep "$REQ" + ``` + +سترى خطوط `proxy passthrough`، `withAuth: authorized`، و `upstream response` الخاصة بالموجة الأمامية جنبًا إلى جنب مع زوج `http request received` / `http request completed` الخاص بالخادم، وجميعها تشارك نفس `request_id`. + +### سجلات JSON و `jq` + +عيّن `AE_LOG_JSON=1` على الموجة الأمامية (يكون مُفعّلًا بشكل افتراضي عند `NODE_ENV=production`) لإصدار كائن JSON واحد لكل سطر. ثم صفّي الهيكل: + +```bash +kubectl logs -n agenteye -l app=dashboard --tail=5000 \ + | jq 'select(.level == "warn" or .level == "error")' + +kubectl logs -n agenteye -l app=dashboard --tail=5000 \ + | jq 'select(.route == "POST /api/keys")' +``` + +يُصدر خادم Rust أزواج تتبع `key=value` التي تُعمل بشكل جيد بدون `jq`: + +```bash +kubectl logs -n agenteye -l app=server --tail=5000 | grep 'status=5' # 5xx +kubectl logs -n agenteye -l app=server --tail=5000 | grep 'actor_key_id=' +``` + +### رفع المراجع + +| المكوّن | متغير Env | مثال | +|---|---|---| +| الخادم | `RUST_LOG` | `RUST_LOG=debug` أو `RUST_LOG=agenteye_server=debug,info` | +| الموجة الأمامية | `AE_LOG_LEVEL` | `AE_LOG_LEVEL=debug` | + +`debug` على الخادم يضيف سطر `api key authenticated` لكل مصادقة. `debug` على الموجة الأمامية يضيف خطوط `upstream request` و `session validated` و `proxy passthrough`. + +### احتفاظ السجل + +stdout للحاوية مؤقتة؛ يقوم kubelet بتدوير ملفات السجل (افتراضي ~10 MiB لكل حاوية) ويحتفظ بعدد صغير على القرص. بمجرد حذف pod يتم حذف السجلات. إذا كنت بحاجة إلى احتفاظ أطول أو بحث عبر pod، فوجّه مجموعتك إلى محمّع سجل (Loki, CloudWatch, Cloud Logging, Datadog, إلخ) يتابع `/var/log/containers/`. لا يتطلب AgentEye أو يفرض أي اختيار محدد. + +--- + +## مشاكل المصادقة + +### فشل `docker pull` مع خطأ "غير مصرح" + +تأكد من أنك قمت بمصادقة Docker مقابل GHCR باستخدام `AGENTEYE_TOKEN`: + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +يجب أن يكون للرمز إذن `read:packages` على منظمة `agenteye-enterprise`. اتصل بـ `support@exosphere.host` إذا لم يعمل رمزك. + +### `gh release download` يعيد 404 أو 401 + +- تأكد من أن `AGENTEYE_TOKEN` مُصدَّر في shell: `echo $AGENTEYE_TOKEN` +- تأكد من أنك تستخدم `GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download ...` (قراءات CLI `gh` من `GITHUB_TOKEN`) +- يحتاج الرمز إلى `contents:read` على `agenteye-enterprise/releases` + +--- + +## مشاكل الخادم + +### فشل الخادم مع خطأ "رقم منفذ غير صحيح" + +يحتوي `POSTGRES_PASSWORD` (أو بيانات اعتماد أخرى) على أحرف خاصة لعنوان URL (`/`, `+`, `=`) تكسر تحليل `DATABASE_URL`. أعد إنشاء كلمة المرور باستخدام ترميز سادس عشري: + +```bash +NEW_PASS=$(openssl rand -hex 24) +``` + +ثم حدّث secret Kubernetes وكلمة المرور داخل Postgres (أو أعد إنشاء `.env` لـ Docker Compose)، وأعد تشغيل الخادم. انظر الخطوات الكاملة في [enterprise-docs/kubernetes-deployment.md](/ar/agenteye/kubernetes-deployment) § "بيانات اعتماد PostgreSQL". + +### يخرج الخادم فورًا عند البدء + +تحقق من سجلات الحاوية: + +```bash +docker logs agenteye-server +``` + +الأسباب الشائعة: +- `DATABASE_URL` غير معيّن أو بصيغة خاطئة: سيسجل الخادم الخطأ ويخرج. +- Postgres غير قابل للوصول: تأكد من أن حاوية Postgres أو قاعدة البيانات المدارة تعمل والمضيف/المنفذ صحيح. +- فشلت الترحيلات: تحقق من السجلات بحثًا عن أخطاء SQL. + +### `GET /health` يعيد غير 200 أو يُنتهي انتظار + +قد يكون الخادم لا يزال يعيد الترحيلات عند البدء الأول. انتظر بضع ثوانٍ وأعد المحاولة: + +```bash +curl http://localhost:8080/health +``` + +إذا استمرت المشكلة، تحقق من `docker logs agenteye-server` للأخطاء. + +### `GET /ready` يعيد 503 + +`/ready` هو اختبار الجاهزية: يعيد `503` عندما لا يستطيع الخادم الوصول إلى **Postgres أو ClickHouse**. النص يسمي التبعية الفاشلة: + +```bash +curl -s http://localhost:8080/ready +# {"status":"not_ready","checks":{"postgres":"ok","clickhouse":"down","redis":"ok"}} +``` + +أصلح أي تبعية تُبلغ عنها كـ `down`: هل pod ClickHouse/Postgres يعمل `Running`؟ هل `CLICKHOUSE_URL` / `DATABASE_URL` صحيح وقابل للوصول؟ على Kubernetes يُقرأ pod كـ `NotReady` حتى تتعافى `/ready`؛ هذا متوقع وهو بالضبط الإشارة التي تُنبّه المراقبة الصحية. Redis ليس أبدًا سببًا: يُبلغ عنه لكنه لا يفشل الجاهزية. + +### المجمّع يعيد 401 غير مصرح + +لا يحتوي مفتاح API الخاص بالمجمّع على إذن `events:add`، أو تم تعطيل المفتاح. أنشئ مفتاحًا جديدًا بالإذن الصحيح: + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{"name":"new-collector","permissions":["events:add"]}' +``` + +### أصبحت الطلبات المصرحة بطيئة فجأة (~200ms بدلاً من ~5ms) + +هذا هو عرض Redis أسفل مع تعيين `REDIS_URL`. كل استدعاء ذاكرة تخزين مؤقت ينتهي انتظاره بعد 100 مللي ثانية ثم يسقط إلى Postgres؛ على مسارات المصادقة و OTP الطلب يُحدث اثنين من هذه السقوط. + +تأكد من سجلات الخادم: + +``` +auth cache: L2 get failed error=redis call timed out +``` + +الحل: + +1. `redis-cli -h ping` للتأكد من أن Redis قابل للوصول على شبكة المجموعة. +2. إذا كان Redis معطلاً لفترة وعاد الآن، **أعد تشغيل pod الخادم**. `redis::aio::ConnectionManager` لا يعيد الاتصال بشكل موثوق بعد انقطاع الاتصال الأساسي؛ يختار إعادة تشغيل pod الاتصال الجديد بنظافة. ينطبق نفس الشيء على الموجة الأمامية. +3. إذا كنت لا تريد تشغيل Redis الآن، ألغِ تعيين `REDIS_URL` في النشر وأعد التشغيل. تعمل كلا الخدمتين بدون الذاكرة المؤقتة (يتم الحفاظ على الصحة؛ يعود الاستجابة إلى خط الأساس السابق قبل Redis). + +### يُبلّغ الخادم عن `OTP request rate-limited` في السجلات لكن المستخدم يقول أنه حاول مرة واحدة فقط + +تحقق من ما إذا كان Redis غير قابل للوصول. يستخدم مسار الانحدار `SELECT COUNT(*) FROM otp_codes WHERE created_at > now() - interval '15 minutes'`، الذي يرى صفوف OTP المُنتجة سابقًا. إذا كان المستخدم ينقر على "إعادة إرسال" لمدة ساعة، فقد تحتوي النافذة المدتها 15 دقيقة على ≥5 رموز. حل المشكلة إما بانتظار النافذة لتتجاوز أو بتنفيذ `DELETE FROM otp_codes WHERE user_id = $1 AND created_at > now() - interval '15 minutes'` (وحدة التحكم بالمشغل). + +### غيّرت `ALLOWED_EMAILS` / `SESSION_TTL_SECS` / `OTP_TTL_SECS` وأعدت التشغيل؛ لم يحدث شيء + +متغيرات env هذه **بذور البدء الأول فقط**. بمجرد حصول جدول `settings` على صف لمفتاح المطابقة، يكون هذا الصف هو المصدر الموثوق؛ يُقرأ متغير env مرة واحدة عند البدء الأول ثم يُتجاهل عند كل إعادة تشغيل لاحقة. + +لتغييرها بعد البدء الأول، قم بتسجيل الدخول إلى الموجة الأمامية وحررها تحت `/settings`. يُطبّق التغيير خلال ثوانٍ عبر جميع النسخ المتماثلة؛ لا يلزم إعادة تشغيل. + +إذا كنت بحاجة إلى فرض إعادة بذر من env (نادرة، عادةً مفيدة فقط في التطوير)، `DELETE FROM settings WHERE key = ''` وأعد تشغيل الخادم. ستلتقط عملية التمهيد قيمة متغير env الحالي عند البدء التالي. التحرير عبر `/settings` هو المسار المدعوم في الإنتاج. + +--- + +## مشاكل المجمّع + +### يبدأ المجمّع لكن الأحداث لا تظهر في الموجة الأمامية + +1. تأكد من أن المجمّع يعمل: `systemctl status agenteye-collector` (Linux) أو تحقق من العملية. +2. تأكد من أن `AGENTEYE_URL` يشير إلى `http(s)://your-server-host:8080/events` (ملاحظة: مسار `/events`). +3. قم بتفريغ لمرة واحدة لرؤية الإخراج الفوري: + ```bash + agenteye-collector flush + ``` +4. تحقق من أن Python SDK يكتب الملفات فعلاً: `ls ${AGENTEYE_HOME:-~/.agenteye}/events/` +5. إذا كانت هناك ملفات في `${AGENTEYE_HOME:-~/.agenteye}/failed/`، فالرفعات تفشل. تحقق من سجلات المجمّع للخطأ، على الأرجح 4xx (مفتاح سيء أو عنوان URL) أو مشكلة شبكية. + +### تتراكم الملفات في `$AGENTEYE_HOME/events/` ولم تُرفع + +- قد لا يعمل المجمّع. ابدأه: `agenteye-collector start`؛ يُفرّغ الأحداث الموجودة مسبقًا تلقائيًا عند البدء. +- تحقق من صحة المجمّع: `agenteye-collector health` +- قد يعمل المجمّع لكن لا يستطيع الوصول إلى الخادم. تحقق من قواعد الجدار الناري بين المجمّع وأجهزة الخادم. + +### الملفات في `$AGENTEYE_HOME/failed/` + +تنتقل الملفات إلى `failed/` بعد استنفاد جميع محاولات إعادة المحاولة (افتراضي: 5 محاولات مع تراجع أسي). هذا يعني إما: +- عاد الخادم بخطأ 4xx (مفتاح سيء أو عنوان URL خاطئ أو مشكلة حمل) +- كان الخادم غير قابل للوصول طوال نافذة إعادة المحاولة + +أصلح المشكلة الأساسية، ثم أعد الطابور يدويًا: + +```bash +mv ${AGENTEYE_HOME:-~/.agenteye}/failed/*.jsonl ${AGENTEYE_HOME:-~/.agenteye}/events/ +agenteye-collector flush +``` + +### يُبلّغ المجمّع عن `network error` في كل رفع (فشل مصافحة TLS) + +إذا كان `curl -k` مقابل `AGENTEYE_URL` ينجح لكن ثنائي المجمّع يفشل في كل رفع مع `error sending request for url (...)`، فإن خادم AgentEye يقدم شهادة TLS غير موقعة من قبل CA عام موثوق. + +**مسار الإنتاج** هو اسم مضيف الاستيعاب ACME المُكوّن في `deploy/base/certificates/domain.env` (انظر [`kubernetes-deployment.md`](/ar/agenteye/kubernetes-deployment) المرحلة 3.1 / 4.2). بمجرد أن يُحل `INGEST_DOMAIN` إلى LB Traefik العام وأصدرت cert-manager شهادة Let's Encrypt، يتحقق المجمعون من شهادة الخادم مقابل مخزن الثقة النظامي **بدون الحاجة إلى `AGENTEYE_TLS_CA`**؛ امسحه من إعدادات المجمّع إذا تم تعيينه ضد نشر موقّع ذاتيًا أقدم. + +**العرض: عمل المجمّع أمس، يفشل اليوم بعد فجوة ~90 يوم.** هذا يعني أن النشر لا يزال على جهة الإصدار `selfsigned` القديمة لـ `ingest-tls`. تم تدوير شهادة 90 يوم وملف CA المثبت قديم. أصلح بشكل دائم بتبديل المجموعة إلى جهة إصدار ACME (المرحلة 3.1 من دليل النشر). حل قصير الأجل: أعد استخراج شهادة الخادم الحالية وحدّث `AGENTEYE_TLS_CA`: + +```bash +kubectl get secret ingest-tls-cert -n agenteye \ + -o jsonpath='{.data.tls\.crt}' | base64 -d > /etc/agenteye/server-ca.crt +``` + +```bash +export AGENTEYE_TLS_CA=/etc/agenteye/server-ca.crt +agenteye-collector flush +``` + +يضيف `AGENTEYE_TLS_CA` ثقة إضافية؛ لا تزال الجذور العامة الموثوقة موثوقة. + +### شهادة `ingest-tls` عالقة في `Ready: False` بعد النشر + +```bash +kubectl describe certificate ingest-tls -n agenteye +``` + +انظر إلى `Events` و `Order` / `Challenge` المشار إليهما. الأسباب الشائعة: + +- **DNS غير يحل إلى LB العام.** لا يمكن لمدقق HTTP-01 الوصول إلى `INGEST_DOMAIN`. تحقق باستخدام `dig +short INGEST_DOMAIN`؛ يجب أن يحل إلى نفس عنوان `traefik-public` LoadBalancer `EXTERNAL-IP`. يحاول cert-manager تلقائيًا بمجرد انتشار DNS؛ لا حاجة لحذف الشهادة. +- **منفذ 80 مسدود عند LB / مجموعة الأمان.** يتطلب HTTP-01 أن تكون المنفذ 80 قابلة للوصول من مدققي Let's Encrypt العامين. إذا كان لديك WAF أو SG لأعلى يقيد `:80`، افتحه (تُعيد إعدادات Traefik التوجيه إلى HTTPS، لكن Boulder يتابع إعادة التوجيه ويقبل الاستجابة). +- **`dnsNames` لم يُستبدل.** إذا كان `kubectl get certificate ingest-tls -n agenteye -o jsonpath='{.spec.dnsNames}'` يُظهر `INGEST_DOMAIN_PLACEHOLDER`، فقد تخطيت خطوة `domain.env`؛ أنشئ من `domain.env.example` وأعد التطبيق. +- **معدل محدود بواسطة Let's Encrypt.** تؤدي الطلبات الفاشلة المتكررة لنفس اسم المضيف إلى تفعيل حدود الشهادة المكررة أو التحقق الفاشل. انتظر ساعة واحدة على الأقل قبل إعادة المحاولة؛ تحقق من حالة الطلب للحصول على رسالة حد المعدل الدقيقة. + +### شهادة `dashboard-tls` عالقة في `Ready: False` / المتصفح يُظهر تحذيرًا + +نفس سير التشخيص كما هو الحال مع `ingest-tls` أعلاه (`kubectl describe certificate dashboard-tls -n agenteye`); تنطبق أسباب DNS والمنفذ 80 والعنصر النائب وحد المعدل جميعها، بالإضافة إلى اثنين محددين للموجة الأمامية: + +- **`DASHBOARD_DOMAIN` يحل إلى LoadBalancer الخاطئ.** يجب أن يشير إلى LB Traefik *الموجة الأمامية*، وليس الاستيعاب العام. `dig +short` اسم المضيف والمقارنة مع عنوان LB الموجة الأمامية. +- **لا يستطيع مثيل Traefik الموجة الأمامية خدمة التحدي.** يجب تثبيته باستخدام ملف قيم الموجة الأمامية المُجمّع، الذي يُفعّل موفر Ingress محدود النطاق لحل HTTP-01 الخاص بـ cert-manager. بدونه حل غير قابل للتوجيه والطلب يبقى `pending` إلى الأبد. ارفع مستوى المثيل بالقيم المقدمة؛ ينجز التحدي المعلق بعدها بنفسه. +- **كان LoadBalancer مقيدًا بنطاقات المصدر.** تنطبق النطاقات على المنفذ 80 أيضًا، مما يحجب مدققي Let's Encrypt — الإصدار الأول وكل تجديد ~75 يوم. أعد فتح LB، أو نسق حل DNS-01 مع الدعم قبل قفله. + +بينما يفشل الإصدار، تستمر الموجة الأمامية في خدمة شهادتها السابقة (أو الإصدار الافتراضي للـ ingress في تثبيت جديد) — يتم تدهور الوصول بتحذير متصفح، أبدًا لا يكون معطلاً. + +### CLI لا يزال يتخطى التحقق من TLS بعد حصول الموجة الأمامية على شهادة موثوقة + +يتم الاحتفاظ بـ `--insecure` في `cli.json` عند تسجيل الدخول. بمجرد أن تخدم الموجة الأمامية شهادة موثوقة علنًا، قم بتسجيل الدخول مرة أخرى باستخدام `agenteye --base-url https:// --secure login`؛ يتم حفظ التحقق مرة أخرى وتختفي تحذيرات البدء. + +--- + +## مشاكل الموجة الأمامية + +### لا يمكن تعطيل أو تحرير مستخدم `ADMIN_EMAIL` + +بالتصميم. تُوسّم المستخدم الذي يطابق `ADMIN_EMAIL` كمحمي عند كل بدء خادم: تخفي الموجة الأمامية زر تعطيل هذا الصف، و API يرفض `DELETE /users/:id` و `PUT /users/:id` مقابله مع `403 Forbidden`. يرفض مشغّل قاعدة البيانات أيضًا بيانات `UPDATE` المباشرة التي قد تعطّل الصف المحمي. + +لتدوير admin التمهيد، غيّر `ADMIN_EMAIL` في بيئتك وأعد تشغيل الخادم. يتم upsert البريد الإلكتروني الجديد كمحمي. يحتفظ admin السابق بعلم الحماية حتى يتم مسحه في قاعدة البيانات (عادةً بخير، لأن البريد الإلكتروني السابق لا يزال admin صالحًا حتى تحذفهم صراحةً). + +### لا تُظهر الموجة الأمامية أحداثًا + +1. تأكد من أن عنوان URL الخادم ومفتاح API صحيحان في متغيرات بيئة الموجة الأمامية (`AGENTEYE_SERVER_URL`, `AGENTEYE_API_KEY`). +2. يحتاج مفتاح API الموجة الأمامية إلى إذن `events:read`. +3. تأكد من أن الأحداث تم استيعابها فعلاً: `curl http://your-server:8080/events -H "Authorization: Bearer $ADMIN_KEY"` + +### `/errors` فارغة لكن `/events` تُظهر صفوفًا حمراء + +تُصدر إصدارات SDK الأحدث أعطالاً كأحداث `agent_end` / `tool_result` / `hook_completed` مع `outcome: "error"` في الحمل الثقيل، بدلاً من صف `event_type: "error"` مخصص. تُطابق صفحة `/errors` الآن كليهما: أي صف يرسمه تدفق `/events` باللون الأحمر (صراحةً `event_type='error'`، حمل الثقل `outcome`/`status` في مجموعة الفشل، `is_error: true`، أو حقل `error` صحيح) يظهر على `/errors`. إذا كنت قد شاهدت سابقًا "بدون أخطاء في هذه النافذة" بينما كانت الصفوف الحمراء مرئية على `/events`، فقم بترقية الموجة الأمامية + الخادم معًا (المرشح الموسع هو `errored=true` على `GET /events`) وستتفق العرضتان. + +### `/models` أو `/tools` أو `/hooks` بطيئة أو تفشل في التحميل على نطاقات زمنية عريضة + +**العرض:** على جدول أحداث كبير (ملايين الصفوف)، فتح `/models`، `/tools`، أو `/hooks` — أو توسيع النطاق الزمني إلى `7d`، `30d`، أو `all` — تدور الخرائط ثم تُظهر خطأ تحميل. يسجل الخادم ClickHouse `MEMORY_LIMIT_EXCEEDED` (الرمز 241) أو انتهاء انتظار استعلام لطلب `latency_aggregate`. + +**السبب:** حسبت الإصدارات الأقدم بكثرة صفحات التجميع والتوزيع المرجح مع استعلام قرأ حمل الحدث `payload` الكامل والحالات المقترنة طلب/استجابة مع نوع سريع في الذاكرة. كان ذروة ذاكرة الاستعلام تنمو إذًا مع حجم النافذة، لذا على مستأجر مشغول يمكن نطاق عريض أن يتجاوز سقف الذاكرة لكل استعلام في ClickHouse. + +**الإصلاح:** ارقّ إلى إصدار يتضمن هذا الإصلاح. يقرأ التجميع الآن الأعمدة المُروّجة المضغوطة فقط ويقترن الأحداث بـ تجميع دفق، لذا لا تنمو ذروة الذاكرة مع حمل الثقل الكامل — النوافذ العريضة تبقى ضمن سقف الذاكرة بكثير وتعود في جزء من الوقت. التحسين بالكامل جانب الاستعلام: ينطبق على جميع البيانات الموجودة عند تحميل الصفحة التالي، بدون إعادة استيعاب أو ملء رجعي. + +### فشل تحميل الموجة الأمامية / صفحة فارغة + +تحقق من سجلات حاوية الموجة الأمامية: + +```bash +docker logs agenteye-dashboard +``` + +السبب الأكثر شيوعًا هو `AGENTEYE_SERVER_URL` أو `AGENTEYE_API_KEY` غير موجود أو يشير إلى خادم غير قابل للوصول. + +### تحليلات / بيانات الموجة الأمامية + +ترسل الموجة الأمامية تحليلات الاستخدام المنتج مجهولة إلى PostHog بشكل افتراضي، موجهة عبر مسار `/ingest` الخاص بالموجة الأمامية (عكس بروكسي إلى `https://us.i.posthog.com`). إرسالها من طرف ثالث يعني أن حجب الإعلانات للمتصفح لا يحطمها. هذا مستقل عن الوظيفة الأساسية للموجة الأمامية: + +- **حاوية الموجة الأمامية** (وليس المتصفح) هي ما تصل إلى PostHog. إذا كان وصول الخروج الخاص بها إلى `https://us.i.posthog.com` مسدودًا، فإن البيانات الإحصائية لا تعمل بصمت؛ تعمل الموجة الأمامية بشكل طبيعي ولا يتم السطح عليها أخطاء للمستخدمين. +- لا يتم تضمين بيانات الوكيل أو الجلسة أو الحدث أبدًا، فقط استخدام واجهة المستخدم للموجة الأمامية. +- لتعطيل البيانات الإحصائية بالكامل، عيّن `AE_ANALYTICS_DISABLED=1` على حاوية الموجة الأمامية وأعد التشغيل. انظر [بيانات شخصية و خصوصية](/ar/agenteye/deployment#telemetry--privacy) في دليل النشر. + +### بيانات الأداة الموجة الأمامية / بيانات المستخدم + +ترسل أداة CLI `agenteye` بيانات استخدام مجهولة إلى PostHog بشكل افتراضي: الأوامر التي تعمل وحالة النجاح/الخروج والمدة. هذا مستقل عن وظيفة CLI: + +- **الجهاز الذي يعمل CLI** يصل إلى `https://us.i.posthog.com` مباشرة. إذا كان وصول الخروج الخاص به مسدودًا، فإن البيانات الإحصائية لا تعمل بصمت (الإرسال محدود بالوقت، لذا لا تؤخر أي أمر) و CLI يعمل بشكل طبيعي. +- لا يتم تضمين بيانات الوكيل أو الجلسة أو الحدث أبدًا: **الوسيطات** والقيم العلم (عنوان URL الموجة الأمامية، الرمز، البريد الإلكتروني، معرّفات الجلسة، مرشحات الاستعلام) لم تُرسل أبدًا. +- لتعطيله، عيّن `AGENTEYE_ANALYTICS_DISABLED=1` (أو `DO_NOT_TRACK=1` عبر الأداة) في بيئة CLI. انظر [بيانات شخصية و خصوصية](/ar/agenteye/cli#telemetry--privacy) في دليل CLI. + +--- + +## مشاكل المساعد الذكي + +انظر [enterprise-docs/assistant.md](/ar/agenteye/assistant) للإعداد الكامل. + +### فقاعة المساعد لا تظهر + +تُخفى الفقاعة ما لم **جميع** هذه تحتفظ: + +- المستخدم المسجل دخوله لديه إذن `agent:use`. +- يتم تعيين `AGENTEYE_AGENT_URL` على الموجة الأمامية وخدمة `agent` قابلة للوصول. +- يتم تكوين نقطة نهاية LLM على خدمة `agent` (`ANTHROPIC_API_KEY`، بوابة عبر `ANTHROPIC_BASE_URL`، أو Bedrock/Vertex). بدون تعيينها، يُبلّغ الوكيل عن "غير مُكوّن" وتبقى الفقاعة مخفية. + +تحقق من صحة الوكيل من مضيف الموجة الأمامية: `curl http://agent:9100/health` يجب أن يعيد `{"status":"ok","llm_configured":true,...}`. + +### يقول المساعد أنه لا يستطيع قراءة شيء ما + +يتم بوابة الأدوات لكل مستخدم. إذا كان المستخدم يفتقد `evaluations:read` (أو `events:read`, `dashboards:read`)، فلن يتم عرض الأدوات المطابقة وسيقول المساعد أنه لا يستطيع قراءة تلك البيانات. امنح إذن القراءة ذي الصلة. + +### "مساعد غير مُكوّن" (HTTP 503) عند الإرسال + +لا تحتوي حاوية `agent` على نقطة نهاية LLM مُكوّنة، أو لا يتطابق `AGENTEYE_AGENT_TOKEN` الخاص بالموجة الأمامية مع الوكيل. عيّن كليهما وأعد التشغيل. + +### تبدأ حاوية `agent` أو OOMs تحت التحميل + +تُولّد كل محادثة عملية قصيرة الأجل. تأكد من أن الحاوية تعمل مع عملية init (تستخدم الصورة `tini`؛ في Compose عيّن `init: true`) وأعطها حدود ذاكرة كافية. قلّل `AGENTEYE_AGENT_MAX_STEPS` إذا لزم الأمر. + +--- + +## مشاكل CLI + +### فشل `agenteye` في البدء مع `ModuleNotFoundError: No module named 'click'` + +يمكن لتثبيت جديد لـ CLI `agenteye` في الإصدار **0.1.6** أن ينهار عند البدء مع: + +``` +ModuleNotFoundError: No module named 'click' +``` + +اعتمد 0.1.6 على `click` الذي يتم تثبيته بشكل غير مباشر بواسطة `typer`؛ الإصدارات الحالية من `typer` لم تعد تسحبها، لذا تنتهي بيئة نظيفة فاقدة للحزمة. **ارقّ إلى 0.1.7 أو أحدث**، الذي يعتمد على `click` بشكل مباشر: + +```bash +pipx upgrade agenteye # إذا تم التثبيت باستخدام pipx (أو: pipx install --force agenteye) +uv tool upgrade agenteye # إذا تم التثبيت باستخدام uv +pip install --upgrade agenteye +``` + +انظر [enterprise-docs/cli.md](/ar/agenteye/cli) لتوجيه التثبيت. + +--- + +## مشاكل Python SDK + +### لا تظهر ملفات في `$AGENTEYE_HOME/events/` + +يقوم SDK بتخزين الأحداث مؤقتًا ويُفرّغها كل 500 مللي ثانية بشكل افتراضي. إذا خرجت العملية الخاصة بك قبل التفريغ، قد تُفقد الأحداث. اتصل بـ `agenteye.configure(flush_interval=0.1)` لتفريغ أسرع في البرامج قصيرة الأجل، أو تأكد من أن العملية الخاصة بك تعمل بطول كافٍ لدورة تفريغ. + +إذا تم تعيين `AGENTEYE_HOME`، تحقق من أن SDK يكتب إلى `$AGENTEYE_HOME/events/` وليس `~/.agenteye/events/` (يتطلب SDK ≥ 0.0.1b5). + +### `ValueError: Reserved field names cannot be used as custom fields` + +الأسماء `timestamp`، `type`، و `environment` محجوزة ولا يمكن استخدامها كحقول مخصصة. تمرير أي منها يرفع: + +``` +ValueError: Reserved field names cannot be used as custom fields: [...] +``` + +أعد تسمية حقل مخصص مخالف. لاحظ أن `session_id` و `agent_id` معاملات صريحة لاستدعاء الحدث، وليست حقولاً مخصصة؛ تمرير إما مرة أخرى كحقل مخصص يرفع `TypeError`. + +--- + +## مشاكل مراقبة الصحة + +### لا تصل تنبيهات إلى Slack (Robusta) + +تنبيهات صحة Robusta هي **إضافية اختيارية**؛ لا ترسل أي شيء حتى يتم التثبيت والإشارة إلى قناة Slack. تحقق من الإصدار والحوض الخاص به: + +```bash +kubectl get pods -n robusta # robusta-runner + robusta-forwarder يجب أن تكون Running +kubectl logs -n robusta -l app=robusta-runner --tail=50 +``` + +الأسباب الشائعة: لم يتم تعيين `api_key` / `slack_channel` الخاص بـ Slack (أو تم إلغاء الرمز)؛ `api_key` هو رمز فقط Robusta (`robusta integrations slack`) لكن المجموعة المُجمّعة `disableCloudRouting: true` تحتاج إلى رمز Slack **bot** ذاتي الاستضافة (`xoxb-…`)، أو عيّن `disableCloudRouting: false`؛ حوض `scope` يستبعد namespace الأجهزة الخاصة بك (القيم المُجمّعة النطاق إلى `agenteye`); أو لم يحدث أي فشل حتى الآن. فرض تنبيه اختبار بأخذ جهاز لأسفل: + +```bash +kubectl -n agenteye delete pod -l app=clickhouse # سيتم إعادة إنشاؤه +``` + +انظر [enterprise-docs/health-monitoring.md](/ar/agenteye/health-monitoring#2-pod-failure-alerting-with-robusta-opt-in) للتثبيت والتكوين. + +### الخادم يستمر في الرفرفة `NotReady` + +اختبار الجاهزية يضرب `/ready`، الذي يفشل عندما Postgres أو ClickHouse غير قابل للوصول. إذا دخل الخادم في دورة داخل وخارج `NotReady`، فإن التبعية غير متاحة بشكل متقطع؛ تحقق من أجهزة ClickHouse و Postgres و `CLICKHOUSE_URL` / `DATABASE_URL` الخادم. تأكد ما يقول `/ready`: + +```bash +kubectl -n agenteye exec deploy/server -- sh -c 'curl -s localhost:8080/ready' +``` + +هذا الاختبار متسامح عن قصد (عتبة فشل سخية)، لذا تشير الرفرفة المستمرة إلى مشكلة تبعية حقيقية بدلاً من اختبار عدواني بشكل مفرط. البقاء على المدى الطويل يبقى على `/health`، لذا الرفرفة الجاهزية **لن** تعيد تشغيل الجهاز. + +## مشاكل مراقبة الشهادات + +### CronJob لا يرسل إخطارات Slack + +يتطلب `cert-renewal-check` CronJob عنوان webhook Slack مخزن في Secret. تحقق من أنه موجود: + +```bash +kubectl get secret cert-renewal-notify-config -n agenteye +``` + +إذا كان مفقودًا، أنشئه: + +```bash +kubectl create secret generic cert-renewal-notify-config \ + --namespace agenteye \ + --from-literal=SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL" +``` + +بدون secret، CronJob يعمل لكن يسجل النتائج إلى stdout. تحقق من السجلات باستخدام: + +```bash +kubectl logs -n agenteye -l job-name --tail=50 +``` + +### انتهت صلاحية شهادة العميل قبل استلام إخطار + +يعمل CronJob كل 12 ساعة. إذا لم يكن يعمل، تحقق من حالته: + +```bash +kubectl get cronjob cert-renewal-check -n agenteye +``` + +قم بفحص يدوي: + +```bash +kubectl create job --from=cronjob/cert-renewal-check manual-cert-check -n agenteye +kubectl logs -n agenteye -l job-name=manual-cert-check +``` + +لإعادة إصدار الشهادة منتهية الصلاحية فورًا: + +```bash +cd base/certificates/client-certs +./issue-client-cert.sh +``` + +ثم طبّق `collector-mtls-secret.yaml` المُعاد إنشاؤه في المجموعة(s) التي تشغل المجمعات الخاصة بك وأعد تشغيلها: + +```bash +kubectl apply -f collector-mtls-secret.yaml -n +``` + +--- + +## مشاكل النسخة الاحتياطية + +### فشل `agenteye-backup` مع "No space left on device" + +يُفرّغ `agenteye-backup` CronJob Postgres + ClickHouse في خدش `backup-tmp` `emptyDir` (افتراضي `30Gi`)، ثم **يُرسل بـ تدفق** أرشيف `tar` مباشرة إلى S3 — الأرشيف المضغوط لم تُكتب أبدًا مرة أخرى إلى خدش، لذا الخدش يجب أن يحتفظ فقط بـ *الفريغات الخام*، وليس الفريغات + نسخة أرشيف على القرص الثانية. جهاز مُطرد / `No space left on device` يعني إذًا أن **الفريغات الخام** تتجاوز حجم الخدش (فريغ ClickHouse `events` يهيمن وينمو بمرور الوقت). تحقق من سجلات الوظيفة الفاشلة: + +```bash +kubectl logs -n agenteye -l job-name= +``` + +إصلاح: في التراكب الخاص بك، رفع `backup-tmp` `emptyDir` `sizeLimit` الخاص بـ CronJob فوق إجمالي فريغك الخام، وتأكد من أن القرص الرسالي الجهاز يمكنه فعلاً الاحتفاظ بها (`sizeLimit` غطاء، وليس حجز). إذا تجاوزت الفريغات قرص جهاز واحد، استبدل `emptyDir` بـ PVC (EBS/PD) لـ `backup-tmp`، أو اضغط الفريغات بالمصدر. + +> كتبت الإصدارات الأقدم `.tar.gz` إلى نفس `20Gi` الخدش كالفريغات، لذا `dumps + archive` فاض وتم إطرد الجهاز **قبل** تشغيل الرفع — الذي يبدو أنه فشل S3 لكن هو حقًا قرص. يُزيل الرفع بـ تدفق ذلك التضاعف. + +### فشل `agenteye-backup` في تثبيت `curl` + +تعمل الوظيفة على صورة `postgres:16` وتثبت `curl` عند البدء لفريغ HTTP ClickHouse. على مجموعة بدون خروج إلى مرايا حزمة Debian، تفشل خطوة `apt-get`. إما اسمح بذلك الخروج من جهاز النسخة الاحتياطية، أو اخبز `curl` في صورة نسخة احتياطية مرآة/مخصصة وأشر إليه في التراكب الخاص بك. + +### يعمل `agenteye-backup` لكن لا شيء يصل إلى التخزين + +تُرسل القاعدة `BACKUP_BUCKET` حقيقيًا (`ts-prod-agenteye/backups`) و `agenteye-backup` ServiceAccount. تُرسل الوظيفة **بـ تدفق** الأرشيف إلى S3 (`tar cz … | aws s3 cp - s3://…`). إذا كان جهاز النسخة الاحتياطية بدون وصول كتابة إلى الدلو، الرفع خطأ — ولأن البرنامج يعمل تحت `set -euo pipefail`، فشل أي مكان في ذلك الأنبوب **يفشل** الوظيفة كاملة عند خطوة `upload` بدلاً من عدم عمل صامت (جهاز EXIT trap السيناريو يسجل `backup FAILED during step: upload`). هذا أيضًا الخطوة التي تصل إليها *بعد* إصلاح تفريغ خدش، لذا إذا تم إطراد النسخ الاحتياطية سابقًا عند خطوة الأرشيف، تحقق من الرفع الآن يصل. ابحث في سجلات الوظيفة الفاشلة عن خطأ وصول S3: + +```bash +kubectl logs -n agenteye -l job-name= | grep -iE 's3|upload|denied' +``` + +إصلاح: عيّن `BACKUP_BUCKET` في التراكب الخاص بك إلى دلو تملكه وأضِف التعليق `agenteye-backup` ServiceAccount الموجود بوصول الكتابة (IRSA / Workload Identity / Pod Identity). انظر قسم **النسخ الاحتياطية** من [enterprise-docs/kubernetes-deployment.md](/ar/agenteye/kubernetes-deployment). + +--- + +## التقييمات / الجلسات / الاستعلامات المدعومة بـ ClickHouse + +### شريط جانب صفحة `/queries` فارغ بعد الترقية + +هناك ثلاثة جداول متوقعة (`events`, `evaluations`, `agent_sessions`). إذا كان شريط SchemaBrowser فارغًا بعد الترقية، فقد فشل الخادم في تطبيق DDL ClickHouse عند البدء. تحقق من سجلات الخادم للبحث عن `failed to apply CH DDL statement`: + +```bash +kubectl logs -n agenteye deploy/server | grep -E 'clickhouse|CH DDL' +``` + +السبب الأكثر شيوعًا هو ClickHouse غير قابل للوصول بينما تعمل الترحيلات. يرفض الخادم البدء إذا لم يتمكن من الوصول إلى CH، لذا عادةً ما يكون لجهاز عالق `CrashLoopBackOff` بدلاً من صفحة استعلامات معطلة بصمت، لكن DDL جزئي تطبيق (أحد البيانات OK، التالية 5xx) يترك المخطط نصف بخير. أعد تشغيل جهاز الخادم بعد تحقق من وصول CH: + +```bash +kubectl rollout restart deploy/server -n agenteye +``` + +### لا تظهر تقييمات جديدة في `/sessions` أو `/queries` + +بعد الترقية، تُكتب التقييمات الجديدة إلى ClickHouse، وليس Postgres، وتظهر تحت `/sessions` (محدودة النطاق على `evaluations:read`) وفي `/queries`. إذا لم تظهر: + +1. تأكد من أن خط أنابيب المقيّم مُفعّل (`EVALUATOR_ENDPOINT` معيّن على الخادم) وينتج نتائج نهائية؛ تحقق من خطوط `evaluation_finalized`. +2. تأكد من وصول CH من الخادم: `kubectl exec -n agenteye deploy/server -- curl -fsS http://clickhouse:8123/ping`. +3. اختبر بقعة جدول CH: `kubectl exec -n agenteye clickhouse-0 -- clickhouse-client -q 'SELECT count() FROM agenteye.evaluations'`. + +### فشل الاستعلامات تحت التحميل مع "Memory limit exceeded"، أو تم `OOMKilled` ClickHouse + +**العرض:** تحت تحميل موجة أمامية/استعلام ثقيل، صفحات تحليلية (تدفق الأحداث، `/sessions`، عرض النماذج/المؤخرة، محرر SQL) تبدأ بـ الفشل أو انتهاء الانتظار؛ يرفرف الخادم بـ اختصار `NotReady`; وجهاز ClickHouse يُظهر عدد إعادة تشغيل متزايد. هذا هو **ذاكرة** شبه دائمة، وليس CPU أو قرص. + +**تأكد من أنها ذاكرة** (وليس مشكلة الإنتاجية التي قد تصلح بـ التكرار): + +1. تحقق من جهاز بحثًا عن عمليات قتل خارج الذاكرة: + ```bash + kubectl -n agenteye describe pod clickhouse-0 | grep -iE 'Restart Count|Last State|Reason|OOMKilled' + ``` + `Reason: OOMKilled` / `Exit Code: 137` مع عدد إعادة تشغيل متسلق هو الحكاية. + +2. اسأل ClickHouse ما يرفضه: + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT name, value FROM system.errors WHERE value>0 ORDER BY value DESC" + ``` + عدد كبير `MEMORY_LIMIT_EXCEEDED` هو التوقيع. الرسالة تقرأ *"أقصى: N GiB"* — أن **N هو `0.9 × حد الذاكرة الخاص بـ pod`** (`max_server_memory_usage_to_ram_ratio` في `deploy/base/clickhouse/configmap.yaml`). إذا كانت الأحمال الثقيلة بحاجة إلى أكثر من N، يتم رفضها. + +3. استبعد الأشياء التي *ليست* المشكلة — إذا كانت CPU وعدد الأجزاء والقرص جميعها منخفضة، إضافة نسخ مكررة/تقسيم ستكون تكلفة مهدرة: + ```bash + kubectl -n agenteye top pod clickhouse-0 + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client - \ No newline at end of file diff --git a/docs/de/agenteye/alerts.mdx b/docs/de/agenteye/alerts.mdx new file mode 100644 index 00000000..15ea8156 --- /dev/null +++ b/docs/de/agenteye/alerts.mdx @@ -0,0 +1,308 @@ +--- +title: "Alerts" +description: "AgentEye Alerts Dokumentation." +--- + +Alerts werten eine Regel nach einem Zeitplan aus und benachrichtigen Sie, wenn ein Wert einen Schwellenwert überschreitet. Sie verwandeln AgentEye von einem passiven Dashboard in eine aktive Benachrichtigungsoberfläche für alles, was zählt: plötzliche Fehlerrate-Anstiege, Latenz-Regressionen, Abfälle bei Evaluator-Scores oder beliebige benutzerdefinierte Ereignisse, die Sie als ClickHouse-Abfrage ausdrücken können. + +Diese Anleitung behandelt den Aufbau eines Alerts, die fünf Trigger-Typen, die vier Benachrichtigungskanäle, den Incident-Lebenszyklus und die verfügbaren Konfigurationsparameter. + +![Die Alerts-Seite: ein Raster von Alert-Regel-Karten, jede mit Trigger-Typ, Auswertungsfenster, Kanälen und einem Info-/Warn-/Kritisch-Schweregrad-Badge](/agenteye/images/alerts.png) + +--- + +## Konzepte + +- **Alert** — die Regel. Sie legt fest, *was* geprüft wird (der Trigger), *wie oft* (das Auswertungsintervall), *wann ein Verstoß vorliegt* (Verbundlogik), *wie dringend* (Schweregrad) und *wer/wohin benachrichtigt wird* (Kanäle). +- **Incident** — das Ereignis, das ausgelöst wird, wenn ein Alert feuert. Ein Alert hat maximal einen offenen Incident gleichzeitig. Wiederholte Verstöße aktualisieren die Belege desselben Incidents. Incidents werden von einem Operator aufgelöst; eine automatische Auflösung, wenn die Regel nicht mehr feuert, ist geplant, aber derzeit nicht aktiviert. +- **Channel** — wohin eine Benachrichtigung gesendet wird: E-Mail, Slack, generischer Webhook oder im Dashboard. Jeder Alert kann eine beliebige Kombination davon verwenden. + +Alerts und Incidents gehören zu einer Organisation und werden gemeinsam von den Operatoren dieser Organisation genutzt (in einem Single-Tenant-Deployment ist das einfach die eingebaute `default`-Org). Incidents können zur Triage einem einzelnen Operator zugewiesen werden. + +--- + +## Trigger-Typen + +Fünf Arten, jede mit eigenem JSON-Spec. Wählen Sie diejenige, die am besten beschreibt, was bei Ihnen als „defekt" gilt. Das **Neuer Alert**-Formular im Dashboard erstellt dieselbe Spezifikation für Sie und passt den Bedingungseditor an den gewählten Trigger-Typ an: + +![Das Neuer-Alert-Formular mit den Grundeinstellungen (Name, Beschreibung, aktiviert) und dem Trigger-Picker mit Metrik-Schwellenwert, benutzerdefiniertem SQL, Evaluierungs-Score, Eval-Fehlern und Per-Event-Optionen](/agenteye/images/alert-new.png) + +### 1. `metric_threshold` + +Die einfachste Option. Wählen Sie eine Metrik aus einer festen Liste, einen Operator, einen Schwellenwert und ein Zeitfenster. + +| Metrik | Was gezählt wird | +|---|---| +| `event_count` | Gesamte Ereignisse im Fenster | +| `error_count` | `event_type = 'error'` ODER ein Ereignis mit `error_type IS NOT NULL` | +| `error_rate` | `error_count / event_count` (0..1) | +| `p95_latency_ms` | `quantile(0.95)(duration_ms)` über alle Ereignisse mit einem `duration_ms` | +| `p99_latency_ms` | `quantile(0.99)(duration_ms)` | +| `token_sum` | `SUM(input_tokens + output_tokens)` | + +Operatoren: `>`, `>=`, `<`, `<=`, `==` (auch akzeptiert als `gt`, `gte`, `lt`, `lte`, `eq`). + +Optionale Filter: `environment`, `event_type`. + +Beispiel-Spec: + +```json +{ + "metric": "p95_latency_ms", + "filter": { "environment": "production" }, + "window_secs": 900, + "op": ">", + "value": 5000 +} +``` + +### 2. `custom_sql` + +Für alles, was die vordefinierten Metriken nicht abdecken. Das vom Operator angegebene SQL durchläuft denselben `/queries/run`-Guard (nur SELECT/WITH, einzelne Anweisung, maximal 10.000 Zeilen), bevor der Dispatcher es ausführt. Zwei Modi: + +- **Zeilenmodus** (kein `op`/`value`): Der Alert feuert, sobald die Abfrage mindestens eine Zeile zurückgibt. +- **Wertmodus**: Die Abfrage muss eine Spalte als `metric_value` aliasieren; der Dispatcher vergleicht den `metric_value` der ersten Zeile mit `value` unter Verwendung von `op`. + +```json +{ + "sql": "SELECT count() AS metric_value FROM agenteye.events WHERE event_type = 'error' AND ts >= now() - INTERVAL 1 HOUR", + "op": ">", + "value": 100 +} +``` + +### 3. `evaluation_score` + +Liest `agenteye.evaluations` und vergleicht den Durchschnitt eines benannten Scores über ein Zeitfenster. + +```json +{ + "score_key": "hallucination", + "op": ">", + "value": 0.6, + "window_secs": 3600, + "min_count": 5, + "environment": "production" +} +``` + +`min_count` schützt vor Einzelstichproben-Ausreißern; der Dispatcher feuert erst, wenn mindestens N Evaluierungen im Fenster vorliegen. + +### 4. `eval_compound` + +Erkennt eine Qualitätsregression, die nur über *mehrere* Evaluator-Scores gleichzeitig sichtbar wird. Während `evaluation_score` einen einzelnen benannten Score überwacht, kombiniert `eval_compound` mehrere Evaluierungs-Score-Bedingungen in einem Alert und verknüpft deren Ergebnisse mit einer gewählten Logik. So kann eine Regel ausdrücken: „Feuern, wenn Hilfsbereitschaft sinkt **oder** Halluzination steigt", „Feuern nur, wenn Hilfsbereitschaft **und** Tool-Effizienz beide sinken" oder „Feuern, wenn **mindestens 2 von** diesen drei Prüfungen verletzt sind". + +Jede Bedingung liest den Durchschnitt eines benannten Scores aus `agenteye.evaluations` über das gemeinsame Fenster und prüft ihn mit eigenem Operator und Schwellenwert. Die booleschen Ergebnisse werden dann durch den `combinator` kombiniert: + +| Kombinator | Logik | Feuert, wenn | +|---|---|---| +| `"any"` | OR | mindestens eine Bedingung verletzt ist | +| `"all"` | AND | jede Bedingung verletzt ist | +| `{ "at_least": N }` | M von N | mindestens N Bedingungen verletzt sind | + +```json +{ + "combinator": { "at_least": 2 }, + "conditions": [ + { "score_key": "hallucination", "op": ">", "value": 0.8 }, + { "score_key": "helpfulness", "op": "<", "value": 0.6 }, + { "score_key": "tone", "op": "<", "value": 0.5 } + ], + "window_secs": 3600, + "min_count": 5, + "environment": "production" +} +``` + +- `combinator`: `"any"`, `"all"` oder `{ "at_least": N }`. +- `conditions[]`: jeweils `{ score_key, op, value }`, mit denselben Operatoren wie die anderen Trigger (`>`, `>=`, `<`, `<=`, `==`). +- `window_secs`: der gemeinsame Rückblickzeitraum, der auf jede Bedingung angewandt wird (Standard: `3600`). +- `min_count`: Mindestanzahl von Evaluierungen pro Bedingung, bevor diese Bedingung als verletzt gelten kann; eine Bedingung mit zu wenigen Stichproben im Fenster gilt als „nicht verletzt" (Standard: `1`). +- `environment`: optional; schränkt jede Bedingung auf eine Umgebung ein. + +Die Belege der Benachrichtigung zeichnen den beobachteten Durchschnitt jeder Bedingung, den geprüften Schwellenwert, die Anzahl der gesehenen Evaluierungen und ob ein Verstoß vorlag auf — so können Sie genau sehen, welche Prüfungen ausgelöst haben. + +### 5. `per_event` + +Für Alerts à la „ein Ereignis, das X entspricht, ist eingegangen". Keine Aggregation; der Dispatcher feuert, sobald er im Rückblickfenster eine Übereinstimmung findet. + +```json +{ + "event_type": "error", + "lookback_secs": 60, + "environment": "production", + "tool_name": "bash", + "agent_id": "caa", + "error_type": "TimeoutError", + "message_contains": "vertex-ai timed out" +} +``` + +Alle Filter werden per UND verknüpft; jedes weggelassene Feld ist uneingeschränkt. + +| Feld | Zweck | +|---|---| +| `agent_id` | Auf Fehler eines bestimmten Agenten beschränken (der auf der `/errors`-Zeile angezeigt wird). | +| `error_type` | Auf eine bestimmte Fehlerklasse beschränken (z. B. `TimeoutError`), anstatt jeden Fehler zu erfassen. | +| `message_contains` | Groß-/Kleinschreibung-unabhängige Teilstring-Suche in `payload.message`. Nützlich, um einen bestimmten Fehlermodus zu erfassen (z. B. `prompt is too long`), ohne bei jedem Fehler desselben Agenten zu alarmieren. Auf 200 Zeichen begrenzt; als literaler String abgeglichen, nicht als Muster. | + +Tipp: Setzen Sie `lookback_secs` ungefähr auf den Wert von `eval_interval_secs` des Alerts, damit dasselbe Ereignis nicht doppelt gemeldet wird. + +**Schnellzugriff über `/errors`:** Die repräsentative Zeile jeder Fehlergruppe in der Fehleransicht (und das Session-Ereignisdetail-Panel für ein Fehlerereignis) enthält eine **+ Alert**-Schaltfläche, die `/alerts/new` mit einem `per_event`-Trigger öffnet, der auf `event_type` + Umgebung dieser Zeile vorausgefüllt ist, einschließlich eines aus dem `error_type` des Payloads abgeleiteten Namens, falls vorhanden. Sie wählen noch die Kanäle aus und bestätigen den Rückblickzeitraum, aber der Matcher ist bereits ausgefüllt. Operatoren benötigen `alerts:write`, damit die Schaltfläche angezeigt wird. + +--- + +## Verbundlogik (M von N) + +Jeder Alert hat zusätzlich zum Trigger zwei ganzzahlige Parameter: + +- `eval_window`: wie viele der letzten Auswertungen betrachtet werden (Standard: 1) +- `min_breaches`: wie viele davon verletzt sein müssen, bevor der Alert feuert (Standard: 1) + +`1 von 1` (der Standard) bedeutet „beim ersten Verstoß feuern". `3 von 5` bedeutet „feuern, wenn die Regel bei 3 der letzten 5 Auswertungen verletzt war" — nützlich für unruhige Signale, bei denen ein einzelner schlechter Messwert Rauschen ist. Der Dispatcher verwaltet einen Ringpuffer pro Alert; Sie müssen keinen Zustand selbst pflegen. + +--- + +## Auswertungsintervall + +`eval_interval_secs` steuert, wie oft der Dispatcher Ihre Regel ausführt. Eingegrenzt auf `[30, 86400]`. Voreinstellungen im Dashboard: 1m / 5m / 15m / 1h. Wählen Sie ein Intervall, das zur Dynamik des zugrundeliegenden Signals passt: Ein 5-minütiger Fehlerrate-Alert, der alle 15 Sekunden ausgewertet wird, verschwendet CPU; ein Per-Event-Alert benötigt einen kurzen Rückblickzeitraum, sonst fallen Ereignisse zwischen den Ticks lautlos weg. + +--- + +## Kanäle + +Jeder Alert kann eine beliebige Kombination dieser vier Kanäle verwenden. Kanalspezifische Zugangsdaten (Slack-Webhook-URL, generische Webhook-URL + Signierungsgeheimnis, Standard-E-Mail-Empfänger) werden einmalig in **`/settings`** konfiguriert und von jedem Alert per Schlüssel referenziert. So kann ein Slack-Kanal viele Alerts bedienen, ohne dass jeder seine eigene Kopie der Webhook-URL speichert. + +Die drei externen Kanalarten (E-Mail, Slack, Webhook) werden außerdem durch einen organisationsweiten Kill-Switch, `alerts.enabled_channels`, gesteuert. Wenn ein gefeuerter Alert eine Kanalart angibt, die nicht in diesem Set enthalten ist, überspringt der Dispatcher sie und erstellt einen `alert_notifications`-Eintrag mit Status `skipped_disabled` und Ziel `` (so können Sie z. B. alle Slack-Benachrichtigungen global pausieren, ohne jede Regel bearbeiten zu müssen). Der In-Dashboard-Kanal ist immer aktiv. Siehe [Konfiguration](#configuration). + +### E-Mail + +Verwendet denselben SMTP-Transport wie die OTP-Login-E-Mails. Empfänger werden in dieser Reihenfolge aufgelöst: + +1. Per-Kanal-Überschreibung `recipients[]` (wenn nicht leer). +2. Die Einstellung `alerts.email_default_recipients` (ein Array von E-Mail-Strings). + +Wenn SMTP nicht konfiguriert ist, ist der Kanal inaktiv; der Dispatcher erstellt dennoch einen `alert_notifications`-Eintrag mit Ziel ``, damit der Audit-Trail die Fehlkonfiguration sichtbar macht. + +### Slack + +Sendet eine Block Kit-Nachricht an eine [Incoming-Webhook-URL](https://api.slack.com/messaging/webhooks). + +- Standard-URL: `alerts.slack_default_webhook` (in `/settings` gesetzt). +- Per-Alert-Überschreibung: Setzen Sie `webhook_setting_key` des Kanals auf einen anderen URL-typisierten Einstellungsschlüssel, z. B. `alerts.slack_oncall`, `alerts.slack_costs`. + +Die Kopfzeile enthält ein Schweregrad-Emoji (`:rotating_light:` / `:warning:` / `:bell:`), und die Nachricht enthält eine Schaltfläche, die direkt zur Incident-Seite verlinkt. + +### Generischer Webhook + +Eine JSON-POST-Integration für PagerDuty, Opsgenie oder Ihren eigenen Endpunkt. Body-Struktur: + +```json +{ + "schema_version": 1, + "event": "alert.firing", + "incident": { "id": "uuid", "url": "https://…/incidents/uuid", "opened_at": "2026-…" }, + "alert": { "id": "uuid", "name": "errors > 50/hr", "severity": "critical" }, + "breach": { "value": 73.0, "summary": "ErrorCount > 50 (observed 73.000)", "evidence": { … } } +} +``` + +Wenn `alerts.webhook_signing_secret` gesetzt ist, enthält die Anfrage einen `X-AgentEye-Signature: sha256=`-Header — den HMAC-SHA256 des Body unter Verwendung des Geheimnisses. Verifizieren Sie ihn auf der Empfängerseite, bevor Sie dem Payload vertrauen. + +Der Header `X-AgentEye-Event` enthält `alert.firing` / `alert.test`. (`alert.resolved` ist für die geplante Auto-Auflösungsfunktion reserviert und wird derzeit nicht gesendet.) + +### Im Dashboard + +Keine externe Zustellung: Der Alert schreibt lediglich einen `alert_notifications`-Eintrag, den die Incidents-Seite im Dashboard anzeigt. Nützlich, solange Sie eine Regel verfeinern und kein externes System mit Benachrichtigungen fluten möchten, oder für Alerts mit geringer Dringlichkeit, die Operatoren bei der normalen Triage prüfen. + +--- + +## Incident-Lebenszyklus + +``` +firing ──ack──▶ acknowledged + │ │ + └────────────────────┴───── Operator auflösen ───▶ resolved +``` + +- **firing** — der Dispatcher hat gerade den Incident eröffnet oder einen weiteren Verstoß erkannt. Die Firing-Benachrichtigung wird genau einmal ausgesendet (gesteuert durch den `notified_firing_at`-Zeitstempel am Incident). +- **acknowledged** — ein Operator hat *Ack* auf `/incidents/:id` gedrückt. Der Incident gilt noch als offen; nachfolgende Verstöße aktualisieren seine Belege, ohne erneut zu benachrichtigen. +- **resolved** — ein Operator hat *Auflösen* gedrückt. Die automatische Auflösung, wenn die Regel nicht mehr verletzt wird, ist geplant, aber derzeit nicht aktiviert; ein offener Incident bleibt offen, bis ein Operator ihn auflöst. + +Ein neuer Incident kann nach der Auflösung des vorherigen jederzeit wieder für denselben Alert eröffnet werden. + +**Aktivitätszeitlinie.** Jede Aktion an einem Incident — geöffnet, bestätigt, aufgelöst — wird in einem append-only Aktivitätslog erfasst und auf der *Aktivitäts*-Zeitlinie des Incidents angezeigt. Jeder Eintrag ist dem Operator zugeordnet, der ihn ausgeführt hat (per E-Mail), oder als **automated** markiert für Aktionen, die der Dispatcher eigenständig vorgenommen hat (automatisches Öffnen bei Verstoß). Die Bestätigung ist gemeinsam nutzbar: Mehrere Operatoren können denselben Incident bestätigen, und jede Bestätigung erscheint als separater, zugeordneter Eintrag. + +Der **Incidents**-Posteingang gruppiert offene Incidents nach Status und ermöglicht die Filterung nach Schweregrad und Zuständigem: + +![Der Incidents-Posteingang mit Alert-verknüpften und Ad-hoc-Incident-Karten mit Schweregrad-Badges und Zuständigen](/agenteye/images/incidents.png) + +Das Öffnen eines Incidents zeigt die Verstoßbelege, Zuständige und Abonnenten, die zugeordnete Aktivitätszeitlinie und einen Kommentar-Thread: + +![Eine Incident-Detailansicht: der übergeordnete Alert, Verstoßzusammenfassung, Zuständige, Abonnenten, zugeordnetes Aktivitätslog und Konversation](/agenteye/images/incident-detail.png) + +--- + +## Erforderliche Berechtigungen + +Das Erstellen von Alert-*Regeln* und die Triage von *Incidents* sind getrennte Zuständigkeiten mit separaten Berechtigungen, sodass Sie einem Bereitschaftsdienst Incident-Zugriff geben können, ohne ihm auch die Möglichkeit zu geben, Regeln zu ändern. + +- `alerts:read`: Alert-Regeln anzeigen. +- `alerts:write`: Alert-Regeln erstellen, bearbeiten, löschen und eine Test-Benachrichtigung auslösen. +- `incidents:read`: Incidents anzeigen. +- `incidents:write`: Manuelle (Ad-hoc-)Incidents öffnen, die nicht an einen Alert gebunden sind. +- `incidents:ack`: Incidents bestätigen, zuweisen, kommentieren und auflösen. + +> **Legacy `alerts:ack`.** Schlüssel und Operatoren, denen das ältere `alerts:ack`-Token gewährt wurde, funktionieren weiterhin: Es wird als `incidents:ack` anerkannt (und impliziert `incidents:read`), sodass bestehende Bereitschaftsdienst-Mitglieder ihren Zugriff behalten, ohne Zugangsdaten neu auszustellen. Neue Berechtigungen sollten mit der `incidents:*`-Familie erteilt werden. + +Gewähren auf API-Schlüsseln (`POST /keys`) und Operatoren (`PUT /users/:id`). Das `PermGate` des Dashboards sperrt die entsprechenden Schaltflächen, wenn eine Berechtigung fehlt; neben der Aktion erscheint dann `// 403`. + +> **E-Mail-Empfänger-Auswahl.** Die Empfängerauswahl im Alert-Editor listet die Mitglieder Ihrer Organisation auf, sodass Sie sie nach Namen auswählen können. Sie lädt für jeden Operator mit `alerts:read` oder `alerts:write`; die Anzeige des Team-Verzeichnisses zu diesem Zweck erfordert **nicht** `users:read`, und die Auswahl gibt nur E-Mail-Adressen der Mitglieder zurück, niemals vollständige Benutzerdatensätze. + +--- + +## Konfiguration + +Vom Dispatcher verwendete Umgebungsvariablen: + +| Variable | Standard | Zweck | +|---|---|---| +| `ALERT_WORKERS` | `1` | Worker-Tasks pro Serverinstanz. Die meisten Deployments benötigen nur einen. | +| `ALERT_CLAIM_BATCH` | `16` | Maximale Anzahl von Alerts, die ein einzelner Worker-Tick verarbeitet. | +| `ALERT_POLL_IDLE_SECS` | `5` | Worker-Schlafzeit, wenn die Warteschlange leer ist. | +| `ALERT_REQUEST_TIMEOUT_MS` | `15000` | Timeout pro Trigger-Auswertung. | +| `DASHBOARD_URL` | `https://app.befailproof.ai` | Origin für den Incident-Magic-Link in Benachrichtigungen. Auf Ihren Dashboard-Host setzen. | + +Nach einem vorübergehenden Auswertungsfehler (ClickHouse nicht erreichbar, Query-Timeout) wiederholt der Dispatcher die Regel mit exponentiellem Backoff. Sobald eine Regel **5** aufeinanderfolgende vorübergehende Fehler angesammelt hat, wird sie wieder im normalen Rhythmus neu eingeplant, anstatt weiter zurückzuweichen — so wird eine dauerhaft fehlschlagende Regel weiterhin regelmäßig ausgewertet. Diese Obergrenze ist fest und nicht vom Operator anpassbar. + +Kanaleinstellungen (verwaltet über `/settings`, nicht per Umgebungsvariable): + +- `alerts.email_default_recipients` (`email_list`): JSON-Array von E-Mail-Strings — die Standard-Empfänger für E-Mail-Kanäle. +- `alerts.slack_default_webhook` (`url`): Standard-Slack-Incoming-Webhook-URL. +- `alerts.webhook_default_url` (`url`): Standard-URL für generische Webhooks. +- `alerts.webhook_signing_secret` (`secret`): HMAC-SHA256-Schlüssel. Wird in der GET-Antwort immer als `""` zurückgegeben; geben Sie einen neuen Wert ein, um ihn zu rotieren. +- `alerts.enabled_channels` (`channel_set`): Die organisationsweite Menge externer Kanalarten, die beim Feuern eines Alerts ausgelöst werden; standardmäßig alle drei (`email`, `slack`, `webhook`). Wird eine Art hier entfernt, wird dieser Kanal für jeden Alert global unterdrückt, ohne dass jede Regel bearbeitet werden muss. Der In-Dashboard-Kanal wird immer zugestellt und ist von dieser Einstellung nicht betroffen. + +--- + +## Neuen Alert verifizieren + +Bevor Sie sich auf einen neuen Alert verlassen: + +1. Speichern Sie ihn als aktiviert mit mindestens einem Benachrichtigungskanal. +2. Wählen Sie **Test** auf der Alert-Detailseite und bestätigen Sie, dass jedes konfigurierte Ziel die synthetische Benachrichtigung erhält. +3. Bestätigen Sie nach dem ersten echten Verstoß, dass der Incident unter **Incidents** erscheint und der gemessene Wert mit der entsprechenden Dashboard-Abfrage übereinstimmt. + +Incidents lösen sich nicht automatisch auf, wenn eine Bedingung nicht mehr erfüllt ist. Ein Operator muss sie über die Incident-Detailseite auflösen. + +--- + +## Fehlerbehebung + +| Symptom | Wahrscheinliche Ursache | +|---|---| +| Alert feuert nie | `enabled = false`, keine Kanäle angehängt, oder die zugrundeliegende CH-Abfrage gibt 0 Zeilen zurück. Verwenden Sie *Test*, um Kanäle zu bestätigen; verwenden Sie `/queries/run`, um die Metrik zu prüfen. | +| Slack-Benachrichtigung fehlt | `alerts.slack_default_webhook` (oder der per-Alert-Überschreibungsschlüssel) ist nicht gesetzt: Prüfen Sie `alert_notifications.target` auf ``-Einträge; oder die `slack`-Art ist in `alerts.enabled_channels` global deaktiviert: Prüfen Sie auf `alert_notifications`-Einträge mit Status `skipped_disabled` und Ziel ``. | +| Generischer Webhook 401 | Der Empfänger erwartet eine Signatur, aber `alerts.webhook_signing_secret` ist nicht gesetzt. Überprüfen Sie auf der Empfängerseite, ob der HMAC `hmac_sha256(secret, body)` entspricht. | +| E-Mail "from all sends failed" | SMTP-Zugangsdaten falsch oder die `from`-Adresse wird von Ihrem Relay abgelehnt. Dieselbe Konfiguration wie für OTP-E-Mails: Wenn diese funktionieren, ist der SMTP-Transport in Ordnung. | +| Incident öffnet sich wiederholt | Die Verbundparameter sind zu aggressiv: Versuchen Sie, `min_breaches` oder `eval_window` zu erhöhen, damit vorübergehende Spitzen keine Incidents erneut öffnen, die Sie bereits aufgelöst haben. | \ No newline at end of file diff --git a/docs/de/agenteye/api-keys.mdx b/docs/de/agenteye/api-keys.mdx new file mode 100644 index 00000000..dc319918 --- /dev/null +++ b/docs/de/agenteye/api-keys.mdx @@ -0,0 +1,255 @@ +--- +title: "API Keys" +description: "AgentEye API Keys Dokumentation." +--- + + +AgentEye verwendet fein abgestufte API Keys, um den Zugriff auf den Server zu steuern. Jeder Key trägt eine oder mehrere Berechtigungen, die bestimmen, was er tun darf. + +--- + +## Berechtigungen + +Der Server erzwingt einen festen Katalog von Berechtigungen; jede davon sichert bestimmte HTTP-Routen ab. Ein **Admin-Key** besitzt alle davon; ein scoped Key enthält die Teilmenge, die du bei der Erstellung vergibst. Unbekannte Berechtigungs-Strings werden beim Erstellen eines Keys abgelehnt. + +> **Nicht an Keys zuweisbar.** Zwei gültige Berechtigungen sind ausschließlich für Menschen/Dashboards vorgesehen und können keinem API Key gewährt werden: `orgs:admin` (Instanzverwaltung, die nur Operatoren vorbehalten ist) und `keys:update`. Eine Anfrage an `POST /keys` oder `PATCH /keys/:id`, die versucht, eine dieser beiden zu gewähren, wird mit HTTP 422 abgelehnt. Warum ein Bearer Key zwar Keys erstellen, sie aber nie bearbeiten darf, erläutert die Zeile `keys:update` weiter unten. + +### Events Ingest & Abfrage + +| Berechtigung | HTTP-Routen | Was sie erlaubt | +|---|---|---| +| `events:add` | `POST /events` | Batches von Events eines Collectors einlesen. Die einzige Berechtigung, die ein Collector benötigt. | +| `events:read` | `GET /events`, `GET /events/latency_aggregate`, `GET /events/environments`, `GET /events/models`, `GET /sessions/:session_id/export` | Events abfragen, bekannte Umgebungen auflisten, im Datensatz gesehene Model-Bezeichner auflisten (verwendet von der Models-Ansicht und Model-Filtern), das Latenz-Aggregat berechnen, das die Heatmap/Perzentilbänder antreibt, und eine Session als JSONL exportieren. Die gemeinsamen Filter-Leisten-Facetten-Endpunkte `GET /events/environments` und `GET /events/models` sind mit **entweder** `events:read` **oder** `evaluations:read` erreichbar, sodass die Sessions-Seite (gesichert durch `evaluations:read`) dieselbe pro-Org-Facette wiederverwendet. | + +### Sessions & Evaluierungen + +| Berechtigung | HTTP-Routen | Was sie erlaubt | +|---|---|---| +| `evaluations:read` | `GET /sessions`, `GET /evaluations`, `GET /evaluations/aggregate`, `GET /evaluations/environments`, `GET /evaluation-jobs` | Sessions auflisten, Evaluierungsergebnisse lesen, den zusammengefassten Eval-Zustand für Dashboards abrufen und den Status der Evaluierungs-Job-Warteschlange einsehen. | +| `evaluations:trigger` | `POST /sessions/:session_id/re-evaluate` | Eine Neubewertung für eine abgeschlossene Session manuell in die Warteschlange einreihen. | + +### Dashboards + +| Berechtigung | HTTP-Routen | Was sie erlaubt | +|---|---|---| +| `dashboards:read` | `GET /dashboards`, `GET /dashboards/:id`, `GET /dashboards/:id/tiles` | Dashboards auflisten, eines laden und seine Kacheln lesen. | +| `dashboards:write` | `POST /dashboards`, `PUT /dashboards/:id`, `POST /dashboards/:id/tiles`, `PUT /dashboards/:id/tiles/:tile_id`, `DELETE /dashboards/:id/tiles/:tile_id`, `PUT /dashboards/:id/tiles/layout` | Dashboards erstellen und bearbeiten, Kacheln hinzufügen, bearbeiten oder entfernen sowie das Kachelraster neu anordnen. | +| `dashboards:delete` | `DELETE /dashboards/:id` | Ein gesamtes Dashboard löschen (das Löschen auf Kachelebene liegt unter `dashboards:write`). | + +### Gespeicherte Abfragen (SQL-Composer) + +| Berechtigung | HTTP-Routen | Was sie erlaubt | +|---|---|---| +| `queries:read` | `GET /queries`, `GET /queries/:id`, `GET /queries/schema` | Gespeicherte Abfragen auflisten, eine laden und das schreibgeschützte ClickHouse-Schema inspizieren, auf das der Composer abzielt. | +| `queries:write` | `POST /queries`, `PUT /queries/:id` | Gespeicherte Abfragen erstellen und bearbeiten. SQL wird weiterhin über dieselbe schreibgeschützte Rolle und `sql_guard`-Prüfungen wie ein `queries:run`-Aufruf geleitet. | +| `queries:delete` | `DELETE /queries/:id` | Eine gespeicherte Abfrage löschen. | +| `queries:run` | `POST /queries/run` | Gespeicherte oder ad-hoc SQL gegen die vom Composer verwendete schreibgeschützte Rolle ausführen. | + +### KI-Assistent + +| Berechtigung | HTTP-Routen | Was sie erlaubt | +|---|---|---| +| `agent:use` | `GET /agent/conversations`, `POST /agent/conversations`, `GET /agent/conversations/:id`, `PATCH /agent/conversations/:id`, `DELETE /agent/conversations/:id`, `PUT /agent/conversations/:id/messages` | Mit dem Dashboard-KI-Assistenten sprechen und eigene (private) Konversationen verwalten. Muss dem **Nutzer** zugewiesen sein, damit das Assistenten-Dock sichtbar ist; der eigene Key des Assistenten ist `dashboard-assistant` und wird separat bereitgestellt (siehe unten). | + +### API Keys + +| Berechtigung | HTTP-Routen | Was sie erlaubt | +|---|---|---| +| `keys:create` | `POST /keys` | Einen neuen scoped API Key erstellen. Gewährt **nicht** das Bearbeiten der Berechtigungen eines bestehenden Keys (das ist `keys:update`). | +| `keys:read` | `GET /keys` | Bestehende Keys auflisten. Secrets werden von diesem Endpunkt niemals zurückgegeben. | +| `keys:update` | `PATCH /keys/:id` | Die Berechtigungen eines bestehenden Keys bearbeiten. Eine **ausschließlich für Menschen/Dashboards** vorgesehene Berechtigung; sie kann keinem API Key zugewiesen werden (ein Bearer Key darf Keys erstellen, sie aber niemals bearbeiten). | +| `keys:disable` | `POST /keys/:id/disable` | Einen Key widerrufen. Geschützte Keys (`admin`, `dashboard-assistant`) können nicht deaktiviert werden; rotiere sie über Umgebungsvariable + Neustart. | +| `keys:regenerate` | `POST /keys/:id/regenerate` | Das Secret eines Keys rotieren. Geschützte Keys können über diese Route nicht neu generiert werden. | + +### Dashboard-Nutzer + +| Berechtigung | HTTP-Routen | Was sie erlaubt | +|---|---|---| +| `users:create` | `POST /users`, `GET /users/defaults` | Einen neuen Dashboard-Nutzer einladen (sendet E-Mail + OTP-Login) und den dashboard-konfigurierten Standard-Berechtigungssatz lesen, der zum Vorausfüllen des Einladungsformulars verwendet wird. | +| `users:read` | `GET /users`, `GET /users/:id` | Nutzer auflisten und einen einzelnen Nutzerdatensatz laden. | +| `users:update` | `PUT /users/:id` | Die Berechtigungen eines Nutzers bearbeiten. Änderungen lösen eine E-Mail über die Berechtigungsänderung an den betroffenen Nutzer aus und werden bei seiner nächsten Anfrage wirksam; kein erneutes Einloggen erforderlich. | +| `users:delete` | `DELETE /users/:id`, `POST /users/:id/enable` | Einen Nutzer deaktivieren (widerruft seine Sessions sofort) und einen zuvor deaktivierten Nutzer wieder aktivieren. | + +Diese Berechtigungen bilden die Grundlage der **Users**-Seite im Dashboard, wo die gewährten Scopes jedes Mitglieds als Chips dargestellt werden: + +![Die Users-Seite: eine Karte pro Dashboard-Nutzer mit E-Mail, gewährten Berechtigungen sowie Bearbeiten- und Deaktivieren-Steuerelementen](/agenteye/images/users.png) + +### Betriebseinstellungen + +| Berechtigung | HTTP-Routen | Was sie erlaubt | +|---|---|---| +| `settings:read` | `GET /settings`, `GET /settings/schema`, `GET /settings/model-context-windows`, `GET /settings/model-context-windows/resolve` | Dashboard-verwaltete Betriebseinstellungen und deren Metadaten anzeigen; modellspezifische Kontextfenster-Überschreibungen auflisten; das effektive Fenster für ein Modell auflösen. | +| `settings:write` | `PUT /settings/:key`, `PUT /settings/model-context-windows`, `DELETE /settings/model-context-windows` | Betriebseinstellungen bearbeiten sowie modellspezifische Kontextfenster-Überschreibungen hinzufügen, ändern oder entfernen. Änderungen wirken sich auf neue Events aus, ohne den Server neu starten zu müssen. | + +![Die Settings-Seite: dashboard-verwaltete Betriebseinstellungen wie erlaubte Anmeldemethoden und Session-/OTP-Laufzeiten, ohne Neustart bearbeitbar](/agenteye/images/settings.png) + +### Alerts & Incidents + +| Berechtigung | HTTP-Routen | Was sie erlaubt | +|---|---|---| +| `alerts:read` | `GET /alerts`, `GET /alerts/:id` | Konfigurierte Alert-Definitionen anzeigen. | +| `alerts:write` | `POST /alerts`, `PUT /alerts/:id`, `DELETE /alerts/:id`, `POST /alerts/:id/test` | Alert-Definitionen erstellen, bearbeiten, löschen und testweise auslösen. | +| `incidents:read` | `GET /alerts/incidents`, `GET /alerts/incidents/:iid`, `GET /alerts/incidents/:iid/comments`, `GET /alerts/incidents/:iid/subscribers` | Incidents und deren Triage-Verlauf einsehen. | +| `incidents:write` | `POST /alerts/:id/incidents` | Einen Incident manuell für einen bestehenden Alert öffnen. | +| `incidents:ack` | `POST /alerts/incidents/:iid/ack`, `POST /alerts/incidents/:iid/assign`, `POST /alerts/incidents/:iid/resolve`, `POST /alerts/incidents/:iid/comments`, `POST /alerts/incidents/:iid/subscribe`, `POST /alerts/incidents/:iid/unsubscribe` | Incidents bestätigen, zuweisen, auflösen und kommentieren. | + +### Audits + +| Berechtigung | HTTP-Routen | Was sie erlaubt | +|---|---|---| +| `audits:read` | `GET /audits`, `GET /audits/:id`, `GET /audits/:id/runs`, `GET /audits/findings`, `GET /audits/findings/:fid` | Audit-Definitionen, Ausführungsverlauf und Befunde anzeigen. | +| `audits:write` | `POST /audits`, `PUT /audits/:id`, `DELETE /audits/:id`, `POST /audits/:id/run`, `POST /audits/findings/:fid/status` | Audits erstellen, bearbeiten, löschen und ausführen; Befunde triagieren (bestätigen / stummschalten / abweisen / auflösen / wieder öffnen / zuweisen). | + +> Als Audits eingeführt wurden, wurden bestehende Berechtigungsinhaber analog zu den Rollen bei Alerts erweitert: Jeder Nutzer und jedes Berechtigungs-Set mit `alerts:read` erhielt `audits:read`, und jeder Inhaber von `alerts:write` erhielt `audits:write`. Bestehende API Keys wurden **nicht** erweitert — weise einem Key `audits:*` explizit zu, wenn er die Audit-Oberfläche benötigt. + +> Gespeicherte Grants des veralteten `alerts:ack`-Tokens werden als `incidents:ack` interpretiert, damit On-Caller ohne Neuvergabe weiterhin Zugriff haben. Das Token ist im Dashboard-Nutzer-Editor nicht mehr zuweisbar; die Matrix bietet stattdessen `incidents:ack` an. + +> Der Empfänger-Picker-Endpunkt `GET /alerts/recipients` (der die Mitglieds-E-Mails auflistet, die ein Alert-Editor benachrichtigen kann) ist für Inhaber von **entweder** `alerts:read` **oder** `alerts:write` erreichbar, sodass Alert-Editoren den Picker befüllen können, ohne `users:read` zu benötigen. + +> Ein Dashboard-Betrachter benötigt **sowohl** `dashboards:read` (zum Laden der gespeicherten Ansichten) als auch `evaluations:read` (die Gesundheitsmetriken werden aus Evaluierungsdaten berechnet). Weise `dashboards:write` zu, damit ein Nutzer Dashboards erstellen oder bearbeiten kann, und `dashboards:delete`, um sie zu löschen. + +> `/health` und `/auth/*` (OTP-Anfrage, OTP-Verifizierung, Session-Prüfung, Logout) sind konzeptionell nicht authentifiziert; sie bilden den Login-Flow und den Liveness-Probe. `GET /access-granters` erfordert einen gültigen Key, aber keine bestimmte Berechtigung, sodass jeder eingeloggte Nutzer sehen kann, welche Admins bei Zugriffsänderungen zu kontaktieren sind. + +--- + +## Berechtigungs-Sets + +Berechtigungs-Sets ermöglichen es, eine benannte Rolle anzuwenden, anstatt jedes Mal einzelne Tokens manuell auszuwählen. Statt dutzende Berechtigungen einzeln für jeden neuen Dashboard-Nutzer oder API Key zu wählen, wählst du ein Set, und alle, denen es zugewiesen ist, tragen einen konsistenten, nachvollziehbaren Grant. Das Bearbeiten eines benutzerdefinierten Sets wendet den neuen Grant auf alle bereits zugewiesenen Nutzer erneut an, sodass eine Rollenänderung eine einzige Bearbeitung statt einer Durchsicht aller Mitglieder ist. + +Jede Organisation wird mit drei eingebauten Sets bereitgestellt: + +| Set | Berechtigungen | Vorgesehen für | +|---|---|---| +| `read-only` | `events:read`, `keys:read`, `users:read`, `evaluations:read`, `dashboards:read`, `queries:read`, `settings:read`, `alerts:read`, `audits:read`, `incidents:read` | Nur-Lese-Zugriff auf alle Betriebsoberflächen. | +| `standard` | alles in `read-only`, plus `evaluations:trigger`, `queries:run`, `incidents:ack`, `agent:use` | Nur-Lesen plus die alltäglichen On-Caller-Aktionen: Abfragen ausführen, Sessions neu bewerten, Incidents bestätigen und den KI-Assistenten nutzen. | +| `admin` | alle zuweisbaren Berechtigungen | Vollständige Kontrolle über die Organisation. | + +Die drei eingebauten Sets sind **unveränderlich**; ihre Namen bedeuten immer dasselbe, sodass `read-only`, `standard` und `admin` sicher in Richtlinien und beim Onboarding referenziert werden können. Ein Operator kann zusätzliche **benutzerdefinierte Sets** erstellen, um für deine Organisation spezifische Rollen abzubilden (z. B. eine Rolle als Dashboard-Autor oder eine Collector-only-Rolle). + +Sets sind im Dashboard sichtbar und werden über die API verwaltet: `GET /permission-sets` (auflisten, gesichert durch `users:read`) sowie `POST /permission-sets` / `PUT /permission-sets/:name` / `DELETE /permission-sets/:name` (benutzerdefiniertes Set erstellen, bearbeiten, löschen, gesichert durch `settings:write`). Das Löschen oder Bearbeiten eines eingebauten Sets wird abgelehnt. + +Set-Mitgliedschaft ist die Grundlage für zwei weitere Funktionen: + +- **`DEFAULT_USER_PERMISSIONS`** (der Grant, der vorausgewählt ist, wenn ein Admin **+ neuer Nutzer** öffnet) ist standardmäßig das `standard`-Set. Siehe [Deployment](/de/agenteye/deployment). +- **Das `--set`-Flag** bei `agenteye-orgctl` (Operator-Mitgliederverwaltung) startet ein Mitglied aus einem benannten Set, das du dann mit `--add` / `--remove` feinjustierst. Siehe [Tenant Management](/de/agenteye/tenant-management). + +> Wenn ein Set eine Berechtigung enthält, die nicht Key-zuweisbar ist (z. B. ein benutzerdefiniertes Set mit `keys:update`), lässt das Ableiten eines Keys aus diesem Set die nicht zuweisbaren Tokens weg; andernfalls würde der Server den Key mit HTTP 422 ablehnen. Für Dashboard-Nutzer gilt diese Einschränkung nicht. + +--- + +## Bootstrap-Admin-Key + +Der Admin-Key ist die einzige Root-Berechtigung, die es einem Operator ermöglicht, den Zugriff von Grund auf aufzubauen: Damit kannst du alle anderen scoped Keys erstellen, die ersten Dashboard-Nutzer einladen und die Instanz konfigurieren, bevor irgendein anderer Key existiert. Er ist der einzige Key, den du nicht über die Keys-API erstellst; er wird aus der Umgebung bereitgestellt, damit der Server beim ersten Start erreichbar ist. + +Setze die Umgebungsvariable `ADMIN_KEY` auf dem Server. Bei jedem Start führt der Server einen Upsert dieses Werts als Admin-Key mit allen Berechtigungen durch. + +Zum Rotieren: Ändere `ADMIN_KEY` zu einem neuen Secret und starte den Server neu. + +--- + +## Organisations-Scoping + +**Organisationen selbst werden von einem Operator außerhalb des Bandes erstellt und verwaltet, nicht über diese Keys-API.** Der Lebenszyklus von Orgs und Mitgliedern (Org erstellen / umbenennen / löschen / bereinigen; Mitglied hinzufügen / aktualisieren / entfernen) erfolgt mit dem **`agenteye-orgctl`**-CLI, das innerhalb des Server-Pods läuft; es gibt keine HTTP-API oder Dashboard-Schaltfläche dafür. Siehe [Tenant Management](/de/agenteye/tenant-management). Was sich **nicht** ändert: **Pro-Org-API-Keys werden weiterhin im Dashboard (oder über diese Keys-API)** von Org-Mitgliedern erstellt. + +In einem Multi-Org-Deployment gehört jeder Key, den ein Org-Mitglied erstellt (über diese Keys-API oder die Dashboard-**Keys**-Seite), zu **einer Organisation** und kann nur die Daten dieser Org lesen oder schreiben; die Org wird beim Erstellen auf den Key gestempelt und bei jeder Anfrage durchgesetzt. Die beiden Bootstrap-Keys sind die einzige Ausnahme: Der `admin`-Key (aus `ADMIN_KEY` bereitgestellt) und der `dashboard-assistant`-Key (aus `AGENT_API_KEY` bereitgestellt) sind **instanzweit gültig** (sie tragen keine Org). Der Dashboard-Container authentifiziert sich mit dem `admin`-Key, sodass er pro-Org-Anfragen im Namen eingeloggter Mitglieder proxyen kann. Single-Tenant-Deployments müssen darüber nicht nachdenken; alle Keys gehören zur eingebauten `default`-Org. + +--- + +## Keys erstellen + +Verwende den Admin-Key (oder einen Key mit der Berechtigung `keys:create`), um weitere scoped Keys zu erstellen. + +### Collector-Key (nur Ingest) + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "prod-collector", + "key": "your-collector-secret", + "permissions": ["events:add"] + }' +``` + +### Dashboard-Key (nur Lesen) + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "dashboard", + "key": "your-dashboard-secret", + "permissions": ["events:read", "keys:read"] + }' +``` + +Wenn du einen Key über die HTTP-API erstellst, gibst du den `key`-Wert selbst an; wähle ein starkes Secret und speichere es sicher. (Das Dashboard funktioniert umgekehrt: Es generiert ein starkes Secret für dich und zeigt es einmalig bei der Erstellung an; siehe [Key-Verwaltung im Dashboard](#key-management-in-the-dashboard).) Die Antwort bestätigt, dass der Key erstellt wurde: + +```json +{ + "id": "550e8400-e29b-41d4-a716-446655440000", + "name": "prod-collector", + "permissions": ["events:add"], + "created_at": "2026-04-01T12:00:00Z" +} +``` + +--- + +## Keys auflisten + +```bash +curl -s http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +Key-Secrets werden in Listenantwortern nicht zurückgegeben, nur IDs, Namen und Berechtigungen. + +--- + +## Einen Key deaktivieren + +Das Deaktivieren widerruft den Zugriff sofort, ohne den Key-Datensatz zu löschen. + +```bash +curl -s -X POST http://your-server:8080/keys//disable \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +--- + +## Einen Key neu generieren + +Generiert ein neues Secret für einen bestehenden Key. Das alte Secret wird sofort ungültig. + +```bash +curl -s -X POST http://your-server:8080/keys//regenerate \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +Die Antwort enthält das neue Klartext-Secret, das **nur einmal angezeigt** wird. + +--- + +## Key-Verwaltung im Dashboard + +Die **Keys**-Seite im Dashboard bietet eine Oberfläche für alle oben genannten Operationen. Du benötigst einen Key mit der Berechtigung `keys:read`, um die Liste anzuzeigen, sowie `keys:create` / `keys:update` / `keys:disable` / `keys:regenerate` für die jeweiligen Aktionen zum Erstellen, Bearbeiten, Deaktivieren und Neu-Generieren. Das Bearbeiten der Berechtigungen eines Keys (`keys:update`) ist vom Erstellen eines Keys (`keys:create`) getrennt, sodass du einem Operator die Möglichkeit geben kannst, Keys zu erstellen, ohne bestehende umzuscopieren – oder umgekehrt. Der Admin-Key deckt all das ab. + +Wenn du einen Key über das Dashboard erstellst, gibst du das Secret nicht selbst an; das Dashboard generiert ein starkes Secret für dich und zeigt es **einmalig** bei der Erstellung an. Kopiere es sofort und speichere es sicher; es wird nie wieder angezeigt, genau wie bei einem Neustart. Du kannst die Berechtigungen des Keys dennoch direkt auswählen oder sie aus einem Berechtigungs-Set ableiten (siehe unten). + +![Die API Keys-Seite: eine Karte pro Key mit Name, gewährten Berechtigungen und Erstellungszeit sowie Aktionen zum Neu-Generieren und Deaktivieren; geschützte Keys wie admin sind markiert](/agenteye/images/api-keys.png) + +--- + +## Empfohlenes Key-Layout + +| Key | Berechtigungen | Verwendet von | +|---|---|---| +| `admin` (Bootstrap via `ADMIN_KEY`-Umgebungsvariable) | alle | Ops/Setup und der Dashboard-Container (authentifiziert sich mit `ADMIN_KEY`, proxyt Nutzeranfragen mit Berechtigungsprüfungen) | +| Pro-Host-Collector-Key | `events:add` | Collector auf jedem Agent-Rechner | +| `dashboard-assistant` (Bootstrap via `AGENT_API_KEY`-Umgebungsvariable) | `events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run` | KI-Assistent-Container, automatisch bereitgestellt, **geschützt**; kann nicht über die API bearbeitet werden | +| Assistent-Telemetrie-Key (optional) | `events:add` | KI-Assistent-Selbstinstrumentierung, falls aktiviert | + +> **Assistenten-Key.** Der Key des Assistenten wird vom Server **automatisch bereitgestellt** aus der Umgebungsvariable `AGENT_API_KEY` (dasselbe Secret, das der Agent als `AGENTEYE_API_KEY` präsentiert); es gibt keinen manuellen Key-Erstellungsschritt und keinen Admin-Key, der dabei involviert ist. Seine Berechtigungen sind im Quellcode fest verankert, sodass der Scope durch Fehlkonfiguration nicht erweitert werden kann: Lesen über Events, Evaluierungen und Dashboards, plus Dashboards-Write und Queries-Read/-Write/-Run für den Authoring-Flow von KI-gestützten Abfragen. Alle SQL-Anfragen laufen weiterhin über dieselbe schreibgeschützte Rolle und `sql_guard`-Prüfungen wie eine nutzerverfasste Abfrage, sodass dies die *Authoring-Oberfläche* erweitert, nicht die Datenoberfläche; destruktive Operationen (`queries:delete`, `dashboards:delete`) bleiben absichtlich vom Assistenten-Key ausgeschlossen. Wie der `admin`-Key ist er **geschützt**: Er kann nicht über die Keys-API deaktiviert oder neu generiert werden, sondern nur durch Ändern von `AGENT_API_KEY` und Neustart rotiert werden. Dashboard-*Nutzer* benötigen zusätzlich die Berechtigung `agent:use`, um den Assistenten zu sehen und zu verwenden. Wenn du die Selbstinstrumentierung aktivierst, gib dem Assistenten einen separaten Key mit nur `events:add`. \ No newline at end of file diff --git a/docs/de/agenteye/assistant.mdx b/docs/de/agenteye/assistant.mdx new file mode 100644 index 00000000..1a92972b --- /dev/null +++ b/docs/de/agenteye/assistant.mdx @@ -0,0 +1,204 @@ +--- +title: "KI-Assistent" +description: "Dokumentation des AgentEye KI-Assistenten." +--- + + +Das Dashboard enthält einen optionalen **KI-Assistenten** – ein Chat-Panel, das am rechten Rand des Dashboards angedockt ist und natürlichsprachliche Fragen zu Ihren Agenten beantwortet („Wie entwickelt sich die Qualität in Prod diese Woche?", „Welche Sessions sind heute fehlgeschlagen?", „Fasse diese Session zusammen"). Mit Genehmigung des Benutzers entwirft und speichert er auch SQL-Abfragen und Dashboards. Er verlinkt direkt auf relevante Sessions, Abfragen und Dashboards – und er ist **seitenorientiert**: Fragen Sie nach „dieser Session", während Sie sie gerade ansehen, versteht er den Kontext. + +Das Dock erscheint standardmäßig als schmale **44px breite vertikale Leiste**: ein `›_` Prompt-Symbol plus ein farbiger Status-Punkt. Klicken Sie auf die Leiste (oder drücken Sie `⌘J` / `Ctrl+J`), um das vollständige Chat-Panel zu öffnen. Das geöffnete Panel ist durch Ziehen am linken Rand zwischen 320 und 640 Pixeln **größenveränderbar**; Ihre bevorzugte Breite wird seitenübergreifend gespeichert. + +Er läuft als kleiner interner **`agent`**-Container (auf dem Claude Agent SDK), den nur das Dashboard erreichen kann. Er ist **standardmäßig deaktiviert** und bleibt verborgen, bis Sie einen LLM-Endpunkt konfigurieren. + +--- + +## Was er kann und was nicht + +- **Liest die operativen Daten, die der anfragende Benutzer sehen kann.** Events, Evaluierungen, Sessions, die Evaluierungs-Job-Warteschlange, gespeicherte Abfragen und gespeicherte Dashboards – je Anfrage auf die Leserechte des Benutzers eingeschränkt. Leseoperationen werden sofort ausgeführt. +- **Schreibzugriffe sind durch aktionsspezifische Genehmigungen gesperrt.** Er kann gespeicherte Abfragen erstellen (`create_saved_query`, `update_saved_query`), Entwurfs-SQL gegen die Nur-Lese-Rolle zur Validierung ausführen (`run_query`) sowie Dashboards aus diesen Abfragen zusammenstellen (`create_dashboard`, `update_dashboard`, `add_query_to_dashboard`). Jede Schreiboperation hält mit einem **Genehmigen / Ablehnen / Frage stellen**-Prompt im Chat an; das SDK ruft das Tool erst auf, wenn der Operator auf „Genehmigen" klickt. **Löschoperationen stehen dem Assistenten nie zur Verfügung**; destruktive Aktionen bleiben den Operatoren vorbehalten. +- **Entworfenes SQL durchläuft dieselbe `sql_guard`-Validierung und Nur-Lese-Rollen wie benutzerseitig erstelltes SQL** (nur SELECT/WITH, keine Multi-Statements). Die Ausführung wird danach geroutet, welche Tabellen die Abfrage betrifft: Abfragen, die auf die Analysetabellen (Events, Evaluierungen, Sessions) zugreifen, laufen als Nur-Lese-ClickHouse-Benutzer der Organisation (auf diese Org per Row-Policy eingeschränkt, mit 10s Ausführungslimit und 100k-Zeilen-Limit), während Abfragen, die nur relationale Tabellen betreffen, auf einer Nur-Lese-Postgres-Rolle ausgeführt werden (10s, 10k Zeilen). Der Assistent kann die Datenbasis nicht erweitern – er kann nur über die Abfrageoberfläche arbeiten, die der Operator bereits hat. +- Er verwendet einen **dedizierten Assistenten-Schlüssel** (siehe unten), der mit einem festen Berechtigungsset erstellt wird; selbst bei Fehlfunktion des Modells kann es diese Bereiche nicht überschreiten. +- Jeder Dashboard-Benutzer benötigt die **`agent:use`**-Berechtigung, um den Assistenten zu sehen und zu verwenden. Tools werden je Anfrage entsprechend den eigenen Datenberechtigungen des Benutzers gefiltert: Ein Benutzer mit `events:read` erhält Event-Tools, aber keine `dashboards:write`-Tools. + +--- + +## Seitenorientiertes KI-Dock: Composer auf `/queries`, Chat anderswo + +Das rechte Assistenten-Dock ist **seitenorientiert**. Die Modellauswahl, der Gesprächsverlauf, der Modell-Status-Punkt und die Chat-Eingabe bleiben unverändert, aber die **Vorschlag-Chips im leeren Zustand, der Platzhaltertext und welcher Backend-Endpunkt eine Benutzernachricht verarbeitet** wechseln automatisch basierend auf der aktuellen Route. Das Dock wird zum „KI-Helfer für die Seite, auf der Sie sich gerade befinden". + +**Zwei Backends, seitenweise ausgewählt (mit Chip-spezifischen Überschreibungen).** + +| Route | Seitenstandardes Backend | Begründung | +| ------------------------------ | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | +| `/queries`, `/queries/new` | `POST /api/agent/compose-sql` (keine Tool-Schleife) | Der Benutzer fängt neu an; SQL mit ≤1s bis zum ersten Token direkt in den Editor gestreamt | +| `/queries/` (vorhandene) | `POST /api/agent/chat` (vollständiger Tool-Loop-Assistent), Seitenstandard | Freitext-Nachrichten sollen dem Benutzer erlauben, alles zu fragen („erkläre das", „was macht das?"); Refactoring-Chips wählen per Chip-`kind` wieder compose-sql | +| jede andere Seite | `POST /api/agent/chat` (vollständiger Tool-Loop-Assistent) | Lesetools + genehmigungspflichtige Schreibtools | + +Chips auf `/queries/` tragen ein explizites `kind`, damit eine einzelne Seite beide Abläufe nahtlos kombinieren kann. Das Standard-Chip-Set besteht aus zwei **Chat**-Chips (`explain the query on screen`, `what does this query do?`) sowie fünf **compose-sql**-Chips (`parameterize by date range`, `add a status='error' filter` usw.). Freitext-Nachrichten fallen auf das Seitenstandardverhalten zurück (Chat), sodass eine Frage wie „Warum ist das so langsam?" eine Prosaantwort erhält, während ein Klick auf den `parameterize by date range`-Chip über den Compose-Endpunkt geroutet wird und das SQL bearbeitet. + +Wenn der Composer im **Bearbeitungsmodus** läuft (er sieht ein nicht leeres `currentSql`, weil der Benutzer auf `/queries/` oder `/queries/new` ist und bereits SQL vorgeschlagen wurde), wechselt sein System-Prompt von „erstelle eine neue Abfrage" zu „Modifiziere das bereitgestellte SQL minimal: Tabellenauswahl, Spaltennamen, Join-Struktur, Aliasse und Einrückung beibehalten". Dem Modell werden separate Vorher-/Nachher-Beispiele gezeigt (parametrisieren, Filter hinzufügen, in stündliche Buckets konvertieren), sodass ein Chip-getriggertes Refactoring ein minimales Diff zum SQL des Editors erzeugt – kein komplettes Neuschreiben. + +Auf einen Compose-Chip klicken (oder auf `/queries/new` frei tippen) → Das SQL wird als Fence-Block ` ```sql ` in die Assistentennachricht gestreamt. **In dem Moment, in dem der Stream abgeschlossen ist, und Monaco auf der aktuellen Route eingebunden ist, öffnet der Editor automatisch die Diff-Ansicht** (Original links, Vorschlag rechts, ein `▾ AI proposed an edit`-Hinweis oben, und **Accept / Reject**-Schaltflächen unten). Der Benutzer muss keinen `Insert into editor`-Button suchen oder anklicken, um das Diff zu sehen. Die Insert-Schaltfläche wird weiterhin unterhalb des SQL-Blocks als manuelle Wiederholung angezeigt (nützlich nach einem Ablehnen oder wenn der Benutzer weg- und zurücknavigiert ist) und bleibt der einzige Weg, wenn der Benutzer auf einer Nicht-Editor-Seite ist (z. B. die gespeicherte-Abfragen-Liste); dort legt sie das SQL in `sessionStorage` ab und navigiert zu `/queries/new`, wo der frisch eingebundene Editor das Stash beim Mounten liest und dieselbe Diff-Ansicht öffnet. + +Wenn das vorgeschlagene SQL byteidentisch mit dem bereits im Editor befindlichen ist (ein Null-Edit), wird die automatische Öffnung übersprungen; ein leeres Diff wird nicht angezeigt. Die `Insert into editor`-Schaltfläche ist in diesem Fall ebenfalls wirkungslos. + +Wenn der Benutzer einen Vorschlag auf `/queries/new` akzeptiert, zeigt die primäre Aktion der Toolbar **`save`** statt `create`; das SQL wurde vom Assistenten bereitgestellt; das mentale Modell ist „Abschließen", nicht „von Grund auf schreiben". Das Label wechselt, sobald das Dock SQL einfügt, und bleibt `save` bis zur nächsten Seitennavigation. Auf `/queries/` lautete die Schaltfläche immer `save`; dort ändert sich nichts. + +Außerhalb von `/queries` funktioniert das Dock wie bisher: vollständiger Chat mit Tool-Genehmigungskarten, seitenbasierter Kontextbewusstsein, Zitierlinks. + +**Berechtigungen / Gating.** Der Compose-Endpunkt setzt die benutzerspezifische `queries:run`-Berechtigung voraus (leseartig; der Benutzer muss noch auf „Akzeptieren" und „Ausführen" klicken, und „Ausführen" läuft durch die bestehende `sql_guard`- und `references_ch_tables`-Weiterleitung auf dem Rust-Server). Der Chat-Endpunkt setzt `agent:use` voraus. Beide benötigen eine auf dem `agent`-Container konfigurierte LLM-Verbindung; falls keine konfiguriert ist, zeigt das Dock auf beiden Pfaden ein Banner „Der Assistent ist in dieser Deployment-Umgebung nicht konfiguriert" an. + +**Ablehnungen.** Der Composer lehnt jede Anfrage ab, die er nicht mit einer Nur-Lese-Analyseabfrage erfüllen kann, und gibt `-- REFUSE: ` statt SQL aus. Er lehnt Anfragen ab, die Daten schreiben oder auf Tabellen außerhalb der Analyseviews zugreifen würden (`api_keys`, `users`, `dashboards`, `saved_queries`, `evaluation_jobs`), und er lehnt reine Prosaanfragen ab („explain this", „what does this do?") auf dem Compose-Pfad; diese gehören auf den Chat-Pfad und erhalten dort eine Prosaantwort. Das Dock rendert den Ablehnungstext als roten Inline-Fehler-Chip in der Assistentennachricht; es wird nichts eingefügt. + +**Modellauswahl.** Gemeinsam mit dem Chat-Pfad. Die Modellauswahl im Dock-Header gilt für beide Endpunkte (der Compose-Aufruf gibt das ausgewählte Modell an `resolveModel()` auf dem Agent-Service weiter). Wenn `AGENTEYE_AGENT_MODELS` mehrere Modelle auflistet, können Operatoren für den Composer eine Haiku-Klasse-Option und für den Chat eine Sonnet-Klasse-Option verwenden; der Benutzer wählt pro Unterhaltung. + +**Seitenspezifische Vorlagen.** Jede Seite hat ihre eigene Vorlage (Überschrift, Beschreibungstext, Platzhaltertext und Vorschlag-Chips), sodass sich das Dock an die aktuelle Seite anpasst. Die auf einer Route angebotenen Chips entsprechen denselben Absichten, für die der Composer optimiert ist, sodass ein Klick auf einen Vorschlag die erwartete Bearbeitung erzeugt. + +**Deaktivierung.** Wie beim Chat-Pfad: Dock und Composer sind beide vom `agent`-Container und seiner LLM-Verbindung abhängig. Wenn Sie für einen bestimmten Benutzer nur Chat-Verhalten möchten, entfernen Sie die `queries:run`-Berechtigung (dadurch wird auch die **Run**-Schaltfläche des Editors deaktiviert); wenn Sie nur Composer-Verhalten möchten, entfernen Sie `agent:use` aus den Rollen dieses Benutzers und fügen Sie `queries:run` separat hinzu, damit er weiterhin selbst erstelltes SQL ausführen kann. + +--- + +## Aktivierung + +Der `agent`-Service ist in der Docker-Compose-Datei und den Kubernetes-Manifesten enthalten. Um den Assistenten zu aktivieren, müssen Sie **(1)** einen LLM-Endpunkt und **(2)** den dedizierten Datenschlüssel des Assistenten bereitstellen. + +### 1. LLM-Verbindung wählen + +Wählen Sie eine der folgenden Optionen und setzen Sie die entsprechenden Variablen auf dem `agent`-Service: + +**a) Direkt über Anthropic** + +``` +ANTHROPIC_API_KEY=sk-ant-... +``` + +**b) Über Portkey (empfohlen; Model-Catalog-Slug, nur Schlüssel)** + +``` +PORTKEY_API_KEY= +AGENTEYE_AGENT_MODEL=@/claude-sonnet-4-6 +``` + +Dies ist der einfachste Weg: Richten Sie in Portkey eine **Anthropic-Integration** (Model +Catalog) ein; sie erhält einen **Slug**. Benennen Sie das Modell als `@/`, und der Slug +übernimmt das Provider- und Credential-Routing, sodass **kein virtueller Schlüssel benötigt wird** – +nur Ihr Portkey-API-Schlüssel. Der Agent sendet nur `x-portkey-api-key` und zeigt auf das +Portkey-Gateway; Portkey übernimmt den Rest. (Ein *einfacher* Modellname schlägt fehl mit +„x-portkey-config or x-portkey-provider header is required"; das Präfix `@slug/` ist das, was den schlüsselbasierten Betrieb ermöglicht.) Für ein selbst gehostetes Gateway setzen Sie `PORTKEY_BASE_URL`. + +Bevorzugen Sie Request-spezifisches Routing statt eines Slugs? Setzen Sie `PORTKEY_VIRTUAL_KEY=` (oder +`PORTKEY_CONFIG=`) mit einem einfachen `AGENTEYE_AGENT_MODEL`. + +**c) Jedes andere Anthropic-kompatible Gateway (LiteLLM, selbst gehostet, …)** + +``` +ANTHROPIC_BASE_URL=https://your-gateway +# Newline-delimited "Name: Value" header lines (NOT JSON): +ANTHROPIC_CUSTOM_HEADERS=x-my-header: value +``` + +**d) Amazon Bedrock / Google Vertex** + +``` +CLAUDE_CODE_USE_BEDROCK=1 # + standard AWS credentials in the environment +# or +CLAUDE_CODE_USE_VERTEX=1 # + standard GCP credentials in the environment +``` + +Das Standardmodell kann optional mit `AGENTEYE_AGENT_MODEL` festgelegt werden (Standard: `claude-sonnet-4-6`). Um Benutzern die **Auswahl** zwischen mehreren Modellen zu ermöglichen, setzen Sie `AGENTEYE_AGENT_MODELS` auf eine kommagetrennte Erlaubnisliste (z. B. +`@anthropic-prod/claude-opus-4-7,@anthropic-prod/claude-sonnet-4-6`); dann erscheint eine Modellauswahl im +Chat-Header, und die Wahl jedes Benutzers wird gespeichert. Der Agent ruft nur ein Modell auf dieser Erlaubnisliste auf. + +### 2. Assistenten-Schlüssel bereitstellen + +Wählen Sie ein beliebiges zufälliges Geheimnis und geben Sie es dem **Agent** als `AGENTEYE_API_KEY` und dem **Server** als `AGENT_API_KEY` (denselben Wert). Beim Start legt der Server es als dedizierten Schlüssel namens `dashboard-assistant` mit diesem festen Berechtigungsset an: `events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run`. Die Schreibberechtigungen werden ausschließlich durch genehmigungspflichtige Tools ausgeübt (siehe „Was er kann und was nicht" oben). Es gibt **keinen manuellen Schlüsselerstellungsschritt und keinen Admin-Schlüssel**. Das Berechtigungsset ist im Server festgelegt, und der angelegte Schlüssel ist **geschützt**: Er kann nicht über die Schlüssel-API deaktiviert oder neu generiert werden; rotieren Sie ihn, indem Sie den Wert ändern und den Server neu starten. Verwenden Sie den Admin-/Dashboard-Schlüssel **nicht** wieder. + +```bash +SECRET="$(openssl rand -base64 32)" +# on the agent service: +AGENTEYE_API_KEY="$SECRET" +# on the server service: +AGENT_API_KEY="$SECRET" +``` + +Auf Kubernetes ist dies für Sie eingerichtet: Legen Sie `AGENTEYE_API_KEY` im Secret `agenteye-agent` ab, und das Server-Deployment liest denselben Wert bereits als `AGENT_API_KEY`. + +### 3. Gemeinsamen Dashboard↔Agent-Token setzen + +Setzen Sie dasselbe `AGENTEYE_AGENT_TOKEN` auf **beiden** Services – `dashboard` und `agent`. Das Dashboard präsentiert es beim Aufruf des internen Agent-Service; der Agent lehnt Aufrufe ohne dieses Token ab. + +### 4. Benutzerzugriff gewähren + +Geben Sie den entsprechenden Dashboard-Operatoren die Berechtigung `agent:use` (siehe [enterprise-docs/api-keys.md](/de/agenteye/api-keys)). Benutzer ohne diese Berechtigung sehen den Assistenten nie. + +Sobald ein LLM-Endpunkt und der Nur-Lese-Schlüssel gesetzt sind, starten Sie den **Server** (um den Nur-Lese-Schlüssel anzulegen) und den **Agent**-Service neu. Das Assistenten-Dock erscheint am rechten Rand für jeden `agent:use`-Benutzer, standardmäßig eingeklappt; klicken Sie auf die Leiste oder drücken Sie `⌘J` / `Ctrl+J`, um es zu öffnen. + +--- + +## Referenz der Umgebungsvariablen + +Auf dem **`agent`**-Service setzen: + +| Variable | Zweck | +|---|---| +| `PORTKEY_API_KEY` | Routing über Portkey (der Agent baut die Gateway-Verbindung daraus auf) | +| `PORTKEY_VIRTUAL_KEY` | Portkey Virtual Key für Ihre Anthropic-Zugangsdaten (optional, wenn der Schlüssel eine Standardkonfiguration hat) | +| `PORTKEY_CONFIG` / `PORTKEY_BASE_URL` | Benannte Portkey-Konfiguration / selbst gehostete Portkey-Gateway-URL (optional) | +| `PORTKEY_PROVIDER` | Portkey-Provider-Slug – eine dritte Routing-Option neben `PORTKEY_VIRTUAL_KEY` / `PORTKEY_CONFIG` (nur verwendet, wenn keines davon gesetzt ist) | +| `ANTHROPIC_API_KEY` | Direkter Anthropic-Zugriff (Alternative zu einem Gateway / Bedrock / Vertex) | +| `ANTHROPIC_AUTH_TOKEN` | Bearer-Token für ein Gateway, das über `Authorization: Bearer` statt `x-api-key` authentifiziert (optional) | +| `ANTHROPIC_BASE_URL` | Endpunkt für ein Nicht-Portkey-Gateway | +| `ANTHROPIC_CUSTOM_HEADERS` | Zusätzliche Header für ein Nicht-Portkey-Gateway: zeilengetrennte `Name: Value`-Zeilen (kein JSON) | +| `CLAUDE_CODE_USE_BEDROCK` / `CLAUDE_CODE_USE_VERTEX` | Routing über Bedrock / Vertex | +| `AGENTEYE_AGENT_MODEL` | Standard-Modell-ID (Standard: `claude-sonnet-4-6`) | +| `AGENTEYE_AGENT_MODELS` | Kommagetrennte Erlaubnisliste von Modellen, die der Benutzer im Chat-Header auswählen kann. Nicht gesetzt lassen für ein einzelnes festes Modell. Das obige Standard muss eines davon sein (sonst wird es hinzugefügt). | +| `AGENTEYE_AGENT_MAX_CONCURRENCY` | Maximale gleichzeitige Chats pro Pod (Standard: 4); überschüssige Anfragen erhalten 429 | +| `AGENTEYE_API_KEY` | Datenschlüssel des Assistenten. Denselben Wert wie `AGENT_API_KEY` des Servers setzen, der ihn beim Start mit einem festen, eingeschränkten Berechtigungsset anlegt (siehe Schritt 2). | +| `AGENTEYE_AGENT_TOKEN` | Gemeinsames Geheimnis mit dem Dashboard | +| `AGENTEYE_SERVER_URL` | AgentEye-Server-URL (Standard: `http://server:8080`) | +| `AGENTEYE_AGENT_ALLOW_NO_ORG` | **Mandantenfähigkeit.** Standardmäßig deaktiviert (fail-closed): Der Assistent lehnt eine `/chat`-Anfrage ohne Organisationskontext mit `400` ab, da jedes Tool, das er ausführt, auf eine Org beschränkt ist. Das Dashboard sendet diesen Kontext immer, sobald es org-fähig ist, daher bleibt dies normalerweise ungesetzt. Auf `1` setzen **nur** während einer Übergangsphase, in der ein noch nicht org-fähiges Dashboard mit einem org-fähigen Agent kommuniziert, damit der Assistent auf die `default`-Org zurückfällt statt abzulehnen. Nach dem Dashboard-Upgrade löschen. | +| `AGENTEYE_AGENT_MAX_STEPS` | Maximale Tool-Verwendungsschritte pro Antwort (Standard: 8) | +| `AGENTEYE_AGENT_TIMEOUT_MS` | Gesamter `/chat`-Anfrage-Timeout (alle Modell-Runden + Tool-Schritte) in Millisekunden (Standard: 90000); das SQL-Tool hat ein eigenes 10s-Limit | +| `AGENTEYE_AGENT_SELF_TELEMETRY` | `1`, um die eigenen Ausführungen des Assistenten in AgentEye aufzuzeichnen | +| `AGENTEYE_TELEMETRY_API_KEY` | Separater `events:add`-Only-Schlüssel für die Selbst-Instrumentierung | +| `AGENTEYE_AGENT_ENV` | Umgebungs-Tag für die eigene Selbsttelemetrie des Assistenten (Standard: `prod`) | + +Auf dem **`dashboard`**-Service setzen: + +| Variable | Zweck | +|---|---| +| `AGENTEYE_AGENT_URL` | Wo das Dashboard den Agent-Service erreicht. Die mitgelieferten Kubernetes-Manifeste und die Compose-Datei setzen dies auf `http://agent:9100`. Nicht gesetzt lassen, um den Assistenten vollständig auszublenden. | +| `AGENTEYE_AGENT_TOKEN` | Muss mit dem Token des Agents übereinstimmen | + +--- + +## Telemetrie & was Benutzer fragen + +Prompt-**Inhalte bleiben standardmäßig in Ihren eigenen Systemen**. Drei Ebenen: + +1. **Konversationsspeicher**: Jeder Prompt und jede Antwort wird in Ihrer AgentEye-Datenbank gespeichert (pro Benutzer, privat) und kann über den Verlauf-Umschalter des Assistenten neu geladen werden. Dies ist die dauerhafte Aufzeichnung der Benutzerfragen. +2. **Produkt-Analytics**: Das Dashboard zeichnet **nur Metadaten** auf (wie oft der Assistent verwendet wird, Tool-Anzahl, Latenz) in Ihrer Analytics. Prompt-**Text** wird auf diesem Pfad nie einbezogen. +3. **Selbst-Instrumentierung (optional)**: Setzen Sie `AGENTEYE_AGENT_SELF_TELEMETRY=1` (plus einen `events:add`-Only-`AGENTEYE_TELEMETRY_API_KEY`), und der Assistent zeichnet seine eigenen Ausführungen als `dashboard-assistant`-Agent in AgentEye auf. Sie können dann Benutzer-Prompts und das Reasoning des Assistenten in denselben Sessions/Events-Ansichten beobachten, die Sie für alles andere verwenden. Hinweis: Diese Events sind für jeden mit `events:read` sichtbar; wenn das zu weitgehend ist, lassen Sie dies deaktiviert. + +--- + +## Deaktivierung + +Jede dieser Optionen deaktiviert den Assistenten (die Dock-Leiste verschwindet): + +- `AGENTEYE_AGENT_URL` auf dem Dashboard nicht setzen, **oder** +- den LLM-Endpunkt auf dem Agent unkonfiguriert lassen (kein `ANTHROPIC_API_KEY` / Gateway / Bedrock / Vertex), **oder** +- den `agent`-Service gar nicht deployen. + +--- + +## Sicherheitsübersicht + +- **Keine stillen Schreibvorgänge**: Die Schreibtools des Assistenten (`create_saved_query`, `update_saved_query`, `create_dashboard`, `update_dashboard`, `add_query_to_dashboard`) können ohne expliziten Operator-Klick auf die Genehmigen-Schaltfläche im Chat nicht ausgeführt werden; das Pre-Call-Gate des SDK blockiert das Tool, bis eine Genehmigung über einen Back-Channel beim Agent eingeht. Es gibt keine Einstellung, die dieses Gate deaktiviert. +- **Festes, enges Datenschema**: Der Assistent authentifiziert sich beim Server mit einem dedizierten Schlüssel, dessen Berechtigungsset im Server festgelegt ist (`events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run`). Die einzigen Schreibvorgänge, die er ausführen kann, sind gespeicherte Abfragen und Dashboards; der Server lehnt alles außerhalb dieses Bereichs ab, unabhängig davon, was das Modell versucht. +- **Keine Löschoberfläche**: Der Schlüssel trägt keine Löschberechtigung, und kein Lösch-Tool wird bereitgestellt. Operatoren löschen über die Dashboard-UI, nie über den Assistenten. +- **Nur intern**: Der Agent hat keine öffentliche Route; nur das Dashboard kann ihn aufrufen, und nur mit dem gemeinsamen Token. (In Kubernetes beschränkt eine NetworkPolicy den Agent darauf, nur den AgentEye-Server und den LLM-Endpunkt zu erreichen.) +- **Benutzerbasierte Einschränkung**: Nur `agent:use`-Benutzer erhalten Zugang zum Assistenten, und er erhält nur die Tools, die den Leseberechtigungen jedes Benutzers entsprechen. +- **Kein rohes HTML / keine Link-Exfiltration**: Antworten werden als bereinigtes Markdown gerendert; externe Links werden entschärft. + +Häufige Probleme finden Sie unter [enterprise-docs/troubleshooting.md](/de/agenteye/troubleshooting). \ No newline at end of file diff --git a/docs/de/agenteye/audits.mdx b/docs/de/agenteye/audits.mdx new file mode 100644 index 00000000..6f49fb55 --- /dev/null +++ b/docs/de/agenteye/audits.mdx @@ -0,0 +1,107 @@ +--- +title: "Audits — agentische Verbesserungserkennung" +description: "AgentEye Audits — Dokumentation zur agentischen Verbesserungserkennung." +--- + + +Audits sind wiederkehrende Jobs, die Ihre Agent-Logs **sitzungsübergreifend** durchsuchen, um verbesserungswürdige Stellen zu finden. Während ein Alert eine einzelne, bereits bekannte Kennzahl nahezu in Echtzeit überwacht, *untersucht* ein Audit: Nach einem von Ihnen festgelegten Zeitplan führt er einen deterministischen Policy-Durchlauf über das Zeitfenster aus und setzt anschließend einen **KI-Zuverlässigkeits-Agenten** auf Ihre Sitzungen an — der Agent fragt die Daten selbst ab, liest verdächtige Transkripte und führt (wenn hilfreich) kleine Analyseskripte aus, bevor er **Verbesserungsempfehlungen** mit den jeweiligen Belegen verfasst. + +Nutzen Sie Audits, um die Frage „Was sollte ich in meinen Agents beheben oder verbessern?" zu beantworten — und Alerts, um sofort benachrichtigt zu werden, sobald ein bestimmter Schwellenwert überschritten wird. Jede Verbesserung verweist auf die genauen Sitzungen und Abfragen, die ihr zugrunde liegen, und ein einziger Klick erstellt einen vorbefüllten Alert, um Wiederholungen abzufangen. + +Die Dashboard-Oberfläche befindet sich unter **`//audits`** (Seitenleiste → *analyze* → *audits*) und ist durch die Berechtigungen `audits:read` / `audits:write` geschützt. + +--- + +## Ablauf eines Durchlaufs + +Jeder Durchlauf besteht aus zwei Schichten — einem deterministischen Fundament und einer agentischen Untersuchung. + +### 1. Der Policy-Durchlauf (deterministisch) + +Bevor ein Modell ausgeführt wird, führt der Audit einen kleinen Katalog von **SQL-Policy-Prüfungen** über das Zeitfenster aus: begrenzte Aggregatabfragen, die bekannte Fehlermuster kennzeichnen und melden, *wie viele* Ereignisse / *welche* Sitzungen übereinstimmen — niemals den übereinstimmenden Text selbst. Der Katalog umfasst: + +- **Geheimnis-/Zugangsdaten-Lecks** in Event-Payloads — AWS-Zugriffsschlüssel, `sk-…`-API-Schlüssel, PEM-Privatschlüssel, JWT-/Bearer-Tokens und `KEY=…`-Zugangsdatenzuweisungen. +- **Prompt-Injection-Marker** — „ignore previous instructions", „reveal your system prompt" und Ähnliches. +- **PII** — SSN-artige Nummern (heuristisch). +- **Werkzeugberechtigungs-Ablehnungen** und **unkontrollierte Werkzeugaufruf-Schleifen**. + +Policy-Treffer werden als Findings (Art `policy`) gespeichert, die **immer angezeigt werden** (sie werden nie durch das Durchlaufs-Limit gekürzt) und dem KI-Agenten als erste Anhaltspunkte übergeben. Da diese Schicht kein Modell benötigt, liefert ein Audit seine wichtigsten Sicherheitssignale auch dann, wenn der KI-Agent nicht verfügbar ist. + +### 2. Die agentische Untersuchung (KI) + +Der Audit führt anschließend einen **autonomen Zuverlässigkeits-Agenten** aus (denselben Claude Agent SDK-Dienst, der den Dashboard-Assistenten antreibt, mit einem audit-spezifischen Prompt). Basierend auf dem **Scope** des Audits (ausgewählte Agents × Umgebungen) und dem **Zeitfenster** führt der Agent folgende Schritte durch: + +- Er führt schreibgeschützte SQL-Abfragen gegen Ihre Analytics-Tabellen aus, +- liest eine Handvoll repräsentativer Sitzungstranskripte, +- schreibt und führt optional kurze **Python-Skripte in einer abgesicherten In-Pod-Sandbox** aus (kein Netzwerkzugriff, kein Dateisystemzugriff, Geheimnisse werden entfernt), um Analysen durchzuführen, die SQL nicht ausdrücken kann — Fehler-Clustering, Verteilungsberechnungen, Durchsuchen bereits abgerufener Payloads, +- und dokumentiert jede gut belegte **Verbesserung**, die er findet. + +Er arbeitet sich durch mehrere Untersuchungslinien — Fehler-Clustering, Drift gegenüber einer Basislinie, Zielverfehlung in Transkripten, Werkzeugmissbrauch, Qualitäts-/Kosten-Kompromisse und Abdeckungslücken — entsprechend der **Sensitivität** des Audits (niedrig / mittel / hoch). Jede Verbesserung **muss Belege zitieren**: die Sitzungs-IDs, die der Agent tatsächlich inspiziert hat, und/oder das ausgeführte SQL. Der Server überprüft, ob die zitierten Sitzungen existieren, und **verwirft jede Verbesserung ohne überlebenden Beleg** — der Agent untersucht also, erfindet aber nichts. + +Jede Verbesserung enthält: + +- eine **Empfehlung** (die konkrete Maßnahme — eine Prompt-Anpassung, eine Werkzeugschema-Korrektur, eine Retry-Richtlinie, eine Schutzmaßnahme, mehr Eval-Abdeckung), +- eine **erwartete Wirkung** und eine **Aufwandsschätzung** (niedrig / mittel / hoch), +- eine **Schwere** — `big` (ein Operator sollte benachrichtigt werden), `medium` (gehört in den Durchlaufsbericht) oder `small` (Dashboard-Kontext), +- einen stabilen **Fingerabdruck** (aus der Kategorie + dem Scope des Problems, *nicht* den Sitzungen dieses Durchlaufs), sodass dasselbe Problem von Durchlauf zu Durchlauf verfolgt wird, auch wenn sich die Belege ändern, +- und, falls ein einfacher deterministischer Watcher das Wiederauftreten erkennen könnte, einen **vorgeschlagenen Alert**, den Sie mit einem Klick erstellen können. + +> **Die KI-Schicht ist optional, aber empfohlen.** Wenn kein KI-Agent für die Audit-Pipeline konfiguriert ist, werden Durchläufe trotzdem ausgeführt, die Policy-Findings gespeichert, und für die agentische Schicht wird ehrlich „Analyse nicht verfügbar" gemeldet, anstatt stillschweigend zu bestehen. + +### Fehlermodi + +Verbesserungen werden in den dauerhaften **Fehlermodus-Katalog** Ihrer Organisation eingeordnet (oder schlagen einen neuen Modus vor). Modi geben Mustern eine stabile Identität über Durchläufe hinweg und ermöglichen eine langfristige Wiederauftritts-Verfolgung. + +## Triage-Lebenszyklus + +Auf einer Finding-Seite (`/audits//findings/`): + +| Aktion | Wirkung | +|---|---| +| **acknowledge** | Hält das Finding sichtbar, halbiert aber seine Priorität. | +| **resolve** | Markiert es als behoben. Wenn das Muster später tatsächlich wieder auftritt, wird es als **neu** wieder geöffnet — eine Regression ist also deutlich sichtbar und wird nicht stillschweigend in die Historie eingefaltet. | +| **mute** / **dismiss** | Dauerhafte Unterdrückung: Der Fingerabdruck des Musters wird gespeichert und taucht nie wieder auf, auch nicht über Durchläufe hinweg. Verwenden Sie mute für „bekannt, akzeptiert"; dismiss für „nicht nützlich". | +| **reopen** | Hebt die Unterdrückung/Auflösung auf und stuft das Muster wieder ein. | +| **assign** | Weist das Finding einem Operator (einem Organisationsmitglied) zur Verantwortung zu. Priorität und Unterdrückungsstatus bleiben unverändert. | + +Rauschen mit geringem Signalgehalt wird pro Audit mit einem Finding-Limit pro Durchlauf (`top_k`) für die agentischen Verbesserungen gesteuert. Policy-Findings umgehen das Limit (sie sind sicherheitsrelevant und werden immer angezeigt). Alles, was durch das Limit abgeschnitten wird, zählt in den Statistiken des Durchlaufs — nichts wird stillschweigend verworfen. + +## Zeitplanung + +- **Takt** (`schedule_interval_secs`): stündlich bis wöchentlich; **täglich ist der Standard**. Audits sind bewusst grobkörniger als Alerts — eine agentische Untersuchung scannt ganze Zeitfenster und läuft minutenlang. +- **Fenster**: entweder ein fester rollierender Rückblickzeitraum (z. B. „jeder Durchlauf scannt die letzten 7 Tage") oder **since-last-run** (der Standard) — jeder Durchlauf setzt dort fort, wo der vorherige erfolgreiche endete, mit einer kleinen Überschneidung, damit Grenz-Ereignisse nie verpasst werden. +- Der nächste Durchlauf wird einen vollständigen Intervall nach **Abschluss** des vorherigen geplant, sodass ein langsamer Durchlauf nie einen zweiten gleichzeitigen Durchlauf desselben Audits auslöst. +- **Run now** auf der Audit-Seite macht ihn sofort fällig. + +## Modellauswahl + +Beim Erstellen eines Audits können Sie auswählen, welches Modell die Untersuchung verwendet — aus der **Liste der Modelle, die Ihr Operator für den Agent-Dienst konfiguriert hat**. Bei einem einzigen konfigurierten Modell zeigt die Auswahl es als Beschriftung an; bei mehreren wählen Sie selbst. Ohne Auswahl wird das konfigurierte Standardmodell verwendet. + +## Benachrichtigungen + +Wenn ein Durchlauf **neue** Findings aufdeckt, benachrichtigt der Audit die konfigurierten Kanäle Ihrer Organisation — dieselbe `alerts.enabled_channels`-Steuerung und Einstellungen, die auch die Alert-Pipeline verwendet: + +- **Slack** — eine Zusammenfassung der bedeutenden (`big`) neuen Einträge mit einem Deep-Link. +- **E-Mail** — ein gestalteter **Auditbericht** mit den neuen Verbesserungen (höchste Schwere, Empfehlungen pro Eintrag, Deep-Link), der versendet wird, wenn der Audit einen **E-Mail**-Kanal angehängt hat und mindestens ein neues Finding vorliegt. + +Wiederkehrende, aber bekannte Findings lösen keine erneute Benachrichtigung aus. + +## Konfigurationsreferenz + +Audit-Definitionen werden im Dashboard (`/audits/new`) oder über die API verwaltet. Audit-spezifische Einstellungen umfassen den Zeitplan-Takt und das Fenster, den Scope (`{"environments": [...], "agent_ids": [...]}`), die Sensitivität (`low` / `medium` / `high`), die Benachrichtigungskanäle, das Finding-Limit pro Durchlauf (`top_k`) und das Modell (über `llm_budget.model`). Operator-seitige Servereinstellungen (Timeouts, Sandbox, die Agent-Dienst-URL) sind in [deployment.md](/de/agenteye/deployment) dokumentiert. + +## API + +Alle Endpunkte sind organisations-begrenzt und folgen der Standard-Bearer-Key-Authentifizierung (siehe [api-keys.md](/de/agenteye/api-keys)). + +| Endpunkt | Berechtigung | Zweck | +|---|---|---| +| `GET /audits` · `POST /audits` | `audits:read` / `audits:write` | Audit-Definitionen auflisten / erstellen. | +| `GET` / `PUT` / `DELETE /audits/:id` | read / write / write | Einen Audit inspizieren, bearbeiten, löschen. | +| `POST /audits/:id/run` | `audits:write` | Den Audit sofort fällig machen. | +| `GET /audits/:id/runs` | `audits:read` | Durchlaufshistorie (Fenster, Status, Statistiken, Finding-Anzahl). | +| `GET /audits/findings` | `audits:read` | Organisationsweite Findings, filterbar nach `audit_id`, `status`; nach Priorität sortiert. | +| `GET /audits/findings/:fid` | `audits:read` | Vollständige Finding-Details (Empfehlung, Belege, Priorität). | +| `POST /audits/findings/:fid/status` | `audits:write` | Triage: `{"action": "ack" \| "mute" \| "dismiss" \| "resolve" \| "reopen" \| "assign"}`. | + +Für „Audit wurde ausgeführt, hat aber nichts gefunden", „die Code-Sandbox ist deaktiviert" und „Audit-E-Mail wurde nicht zugestellt" siehe [troubleshooting.md](/de/agenteye/troubleshooting#audits). \ No newline at end of file diff --git a/docs/de/agenteye/cli-recipes.mdx b/docs/de/agenteye/cli-recipes.mdx new file mode 100644 index 00000000..21af03b2 --- /dev/null +++ b/docs/de/agenteye/cli-recipes.mdx @@ -0,0 +1,170 @@ +--- +title: "CLI-Rezepte für Agenten" +description: "AgentEye CLI-Rezepte für die Agenten-Dokumentation." +--- + + +Sitzungs-, Ereignis- und Auswertungsdaten direkt aus einem Skript oder Coding-Agenten abrufen (und erneute Auswertungen auslösen) – mit sauberem JSON auf stdout, das sich direkt in `jq` einleiten lässt. Diese Rezepte machen AgentEyes Observability-Daten für Terminal-Nutzer oder KI-Coding-Agenten (Claude Code, Cursor) abfragbar und automatisierbar, ohne durch das Dashboard klicken zu müssen. + +Die folgenden Muster sind kopierfertig für die AgentEye CLI (`agenteye`). Installation, Authentifizierung und die vollständige Optionsliste finden Sie unter [CLI](/de/agenteye/cli); `agenteye -h` oder `agenteye -h` zeigt die eingebaute Hilfe. + +## Grundregeln + +1. **Globale Optionen kommen *vor* dem Befehl.** `agenteye --json sessions` ist korrekt; `agenteye sessions --json` ist es nicht. Die globalen Optionen sind `--json`, `--base-url`, `--org`, `--token`, `--insecure`/`--secure`, `--timeout`, `--quiet`, `--no-color`. +2. **`--json` angeben, wenn die Ausgabe geparst wird.** Daten gehen als JSON an **stdout**; menschlesbare Status- und Fehlermeldungen gehen an **stderr**, sodass stdout sauber in `jq` weitergeleitet werden kann. +3. **Auf den Exit-Code verzweigen**, nicht auf stderr-Text: `0` OK · `2` ungültige Argumente · `3` Dashboard nicht erreichbar · `4` nicht eingeloggt oder abgelaufen · `5` fehlende Berechtigung. +4. **Mit `-h` erkunden.** Jeder Befehl dokumentiert seine Filter, Werteformate und JSON-Struktur. + +## Einmalige Einrichtung + +```bash +export AGENTEYE_DASHBOARD_URL=https://agenteye.example.com # damit --base-url nicht wiederholt werden muss +agenteye login --email you@example.com # per E-Mail zugesandten Code eingeben; gültig ~24h +``` + +## Authentifizierung prüfen, bevor gearbeitet wird + +`whoami` gibt keinen Fehler bei fehlender oder abgelaufener Sitzung zurück; stattdessen wird `logged_in:false` gemeldet, sodass ein Agent den Auth-Status gefahrlos abfragen kann. (Ein Fehler mit Nicht-Null-Exit ist dennoch möglich, wenn keine Basis-URL gesetzt ist oder das Dashboard nicht erreichbar ist.) + +```bash +if [ "$(agenteye --json whoami | jq -r .logged_in)" != "true" ]; then + echo "Nicht authentifiziert. Ausführen: agenteye login" >&2; exit 1 +fi +``` + +## Fehlgeschlagene oder niedrig bewertete Sitzungen finden + +```bash +# Sitzungen der letzten 24h, deren Auswertung fehlgeschlagen ist +agenteye --json sessions --since 24h --status error | jq -r '.sessions[].session_id' + +# Auswertungen mit Helpfulness-Score <= 0.5 für einen Agenten +agenteye --json evals --agent-id checkout-bot --score helpfulness:..0.5 \ + | jq '.evaluations[] | {session_id, scores}' +``` + +Die Score-Filterung liegt bei **`evals`**, nicht bei `sessions`. `--score KEY:MIN..MAX` ist wiederholbar und wird UND-verknüpft; jede Grenze ist optional (`..0.5` bedeutet ≤ 0.5, `0.9..` bedeutet ≥ 0.9). Pro Anfrage können bis zu 20 Score-Filter übergeben werden; mehr ergibt HTTP 400. `sessions` teilt die Filter `--env`, `--status`, `--agent-id`, `--session-id` und den Zeitbereichsfilter mit `evals`, hat aber kein `--score`. + +## Eine Sitzung vollständig lesen + +Es gibt keinen einzelnen `session show`-Befehl – die Ereignishistorie und die Auswertung der Sitzung werden kombiniert: + +```bash +# die neueste Auswertung der Sitzung (Status + Scores) +agenteye --json evals --session-id run-001 | jq '.evaluations[0] | {status, scores}' + +# alle Ereignisse des Durchlaufs (--limit für vollständigen Durchlauf erhöhen) +agenteye --json events --session-id run-001 --all --limit 1000 | jq '.events[] | {ts, event_type}' + +# nur die Tool-Aufrufe einer Sitzung +agenteye --json events --session-id run-001 --event-type tool_use,tool_result --all \ + | jq '.events[].payload' +``` + +## Alles abrufen (Paginierung) + +Ergebnisse sind nach Datum absteigend sortiert und cursor-paginiert. + +```bash +# in einem Schritt: bis zu 500 Zeilen in 200-Zeilen-Seiten abrufen +agenteye --json events --session-id run-001 --limit 500 --all > events.json + +# manuelles Paging: next_cursor zurückspeisen +page=$(agenteye --json events --limit 100) +cursor=$(echo "$page" | jq -r '.next_cursor // empty') +[ -n "$cursor" ] && agenteye --json events --limit 100 --cursor "$cursor" +``` + +## Ausgabe mit --fields verkleinern + +Die Schlüssel (sowohl in der Tabelle als auch bei `--json`) einschränken, um zu reduzieren, was ein Agent lesen muss. + +```bash +agenteye --json sessions --since 7d --fields session_id,status,scores | jq -c '.sessions[]' +agenteye --json events --session-id run-001 --fields ts,event_type --all +``` + +Unbekannte Feldnamen werden abgelehnt (Exit `2`) und die gültige Liste wird ausgegeben – eine einfache Methode, um Feldnamen zu entdecken. + +## Gültige Filterwerte erkunden + +```bash +agenteye --json list envs | jq -r '.values[]' # Werte für --env +agenteye --json list tools | jq -r '.values[]' # Tool-Namen; auch agents, models, event_types, … +agenteye --json list score_filters | jq -r '.values[]' # gültige KEY-Werte für --score KEY:MIN..MAX +``` + +## Organisation auswählen (Mandantenfähigkeit) + +Wenn Sie mehr als einer Organisation angehören, wählen Sie den aktiven Mandanten beim Login (wird gespeichert): + +```bash +agenteye login --org acme --email you@corp.com # Mandanten im selben Schritt wie den Login setzen +agenteye --json orgs list | jq -r '.orgs[].org_slug' +agenteye --org globex --json sessions --since 24h # für einen Befehl überschreiben +``` + +Ein Multi-Org-Login ohne `--org` endet mit einem Nicht-Null-Exit und gibt die auswählbaren Organisationen aus. + +## Einen API-Key für das SDK/den Collector anlegen + +```bash +# Das Secret wird EINMAL ausgegeben – bei --json ist es das Feld .key +key=$(agenteye --json keys create ci-bot --add events:read.add | jq -r '.key') +agenteye keys regenerate ci-bot --yes # rotieren; agenteye keys disable ci-bot --yes zum Widerrufen +``` + +## Eine gespeicherte oder Ad-hoc-Abfrage ausführen + +```bash +agenteye --json query run --sql "select count(*) from analytics.events" | jq '.rows' +agenteye --json query run errs --arg prod | jq '.rows' # eine gespeicherte Abfrage + ein positionaler $1-Parameter +``` + +## Einen Vorfall nicht-interaktiv triagieren + +```bash +id=$(agenteye --json incidents list --state firing | jq -r '.incidents[0].id') +agenteye incidents ack "$id" +agenteye incidents assign "$id" you@corp.com +agenteye incidents resolve "$id" --yes +``` + +> Mutationen überspringen ihre Bestätigungsaufforderung automatisch bei `--json` oder wenn stdin kein TTY ist, sodass Agenten nie hängen bleiben; `--yes`/`-y` übergeben, um sie an anderen Stellen explizit zu überspringen. + +## Exit-Code-Behandlung in einem Skript + +```bash +out=$(agenteye --json sessions --since 1h) || code=$? +case "${code:-0}" in + 0) echo "$out" | jq '.sessions | length' ;; + 4) echo "Sitzung abgelaufen - 'agenteye login' ausführen." >&2 ;; + 5) echo "Fehlende Berechtigung (Admin nach evaluations:read fragen)." >&2 ;; + 3) echo "Dashboard nicht erreichbar - URL prüfen." >&2 ;; + *) echo "Unerwarteter Fehler (Exit ${code})." >&2 ;; +esac +``` + +## JSON-Ausgabeformate + +| Befehl | stdout JSON (mit `--json`) | +|---|---| +| `whoami` | `{"logged_in": true, "id", "email", "is_instance_admin", "active_org", "permissions": [...], "memberships": [...]}` oder `{"logged_in": false}` | +| `orgs list` | `{"active_org", "orgs": [{"org_slug","org_name","permission_set","permissions"}]}` | +| `events` | `{"events": [...], "next_cursor": }` | +| `evals` | `{"evaluations": [...], "next_cursor": }` | +| `sessions` | `{"sessions": [...], "next_cursor": }` | +| `errors` | `{"errors": [...], "next_cursor": }` | +| `list ` | `{"kind", "values": [...]}` | +| `keys list` / `keys create` | `{"keys": [...]}` / `{id, name, permissions, created_at, key}` (`key` wird einmalig angezeigt) | +| `query run` | `{columns: [{name,type}], rows: [[...]], truncated, elapsed_ms}` | +| `users list` / `settings list` | `{"users": [...]}` / `{"settings": [...]}` | +| `alerts list` / `incidents list` | `{"alerts": [...]}` / `{"incidents": [...]}` | +| create/update/delete (beliebig) | das Ressourcenobjekt, oder `{"deleted": true, "id"}` bei Löschvorgängen | +| Fehler (beliebig, mit `--json`) | `{"error": "...", "exit_code": , "status"?: , "hint"?: "..."}` auf stdout | + +- Jedes **Ereignis**-Element (`events`): `id, session_id, agent_id, event_type, ts, payload, environment`. +- Jedes **Auswertungs**-Element (`evals`): `id, session_id, agent_id, environment, status, scores, reasoning, summary, error, attempt_count, duration_ms, completed_at, created_at`. +- Jedes **Sitzungs**-Element (`sessions`): `session_id, agent_id, environment, status, scores, event_count, started_at, last_event_at, first_event_id, last_event_id, latest_evaluation`. + +Das `--fields`-Argument eines Befehls akzeptiert genau die Feldnamen seines eigenen Elements – die Menge unterscheidet sich zwischen `sessions` und `evals`, sodass ein für eines gültiger Name vom anderen abgelehnt werden kann. \ No newline at end of file diff --git a/docs/de/agenteye/cli-skill.mdx b/docs/de/agenteye/cli-skill.mdx new file mode 100644 index 00000000..086332e5 --- /dev/null +++ b/docs/de/agenteye/cli-skill.mdx @@ -0,0 +1,95 @@ +--- +title: "AgentEye CLI Agent Skill" +description: "AgentEye AgentEye CLI Agent Skill Dokumentation." +--- + + +Der **AgentEye CLI Skill** (`agenteye-cli`) ist ein installierbarer *Agent Skill*, der einem Coding-Agenten — Claude Code, Codex und kompatiblen Tools — beibringt, Ihr AgentEye-Deployment über die [`agenteye` CLI](/de/agenteye/cli) per Freitext zu steuern: *„Läuft heute alles?"*, *„Erstell CI einen Key, der nur Events pushen darf"*, *„Bestätige den aktiven Incident und weise ihn mir zu"*. + +Es handelt sich **nicht** um einen Dienst oder eine separate Binary. Es ist ein kleines Instruktions-Bundle, das auf der bereits installierten CLI aufsetzt: Der Agent ruft `agenteye --json …` auf, parst das saubere JSON und antwortet in Prosa. Alles, was er kann, könnten Sie selbst durch Eingabe derselben Befehle erledigen. + +--- + +## Verhältnis zu den anderen AgentEye-Schnittstellen + +AgentEye bietet vier Wege, auf dieselben Daten und Funktionen zuzugreifen. Sie ergänzen sich gegenseitig: + +| Schnittstelle | Was es ist | Wo es läuft | Wann Sie es verwenden | +|---|---|---|---| +| **[CLI](/de/agenteye/cli)** | Die Befehls- und Flag-Referenz für `agenteye` | Ihr Terminal | Sie möchten einen konkreten Befehl ausführen oder skripten | +| **[CLI-Rezepte](/de/agenteye/cli-recipes)** | Fertige `jq`-/Pipeline-Muster zum Kopieren | Ihr Terminal / Skripte | Sie binden die CLI in Automatisierungen ein | +| **CLI Skill** (dieses Dokument) | Ein natürlichsprachlicher Einstieg in die CLI | Ihr Coding-Agent auf Ihrem Rechner | Sie möchten einfach fragen und den Agenten den passenden Befehl auswählen lassen | +| **[In-Dashboard-KI-Assistent](/de/agenteye/assistant)** | Ein im Dashboard eingebetteter Chat | Ein interner `agent`-Container in Ihrem Cluster | Sie möchten im Dashboard Fragen zu Ihren Daten stellen | + +### vs. dem In-Dashboard-KI-Assistent — ein wichtiger Unterschied + +Das sind zwei grundlegend verschiedene Tools mit sehr unterschiedlichem Wirkungsradius: + +- Der **In-Dashboard-KI-Assistent** ([assistant.md](/de/agenteye/assistant)) ist ein im Dashboard eingebetteter Chat, der von einem internen `agent`-Container betrieben wird. Er ist **lesend plus genehmigungspflichtig beim Schreiben**: Er kann gespeicherte Abfragen und Dashboards entwerfen, aber jede Schreiboperation erfordert Ihre explizite Bestätigung per Klick — gelöscht wird nie. Er ist durch die Berechtigung `agent:use` abgesichert und sieht ausschließlich Daten der Organisation, die Sie gerade betrachten. +- Der **CLI Skill** läuft auf *Ihrem* Rechner innerhalb *Ihres* Coding-Agenten und steuert die `agenteye` CLI als **Sie**. Er kann die **gesamte Oberfläche der CLI nutzen, einschließlich schreibender Operationen** — API-Keys erstellen/rotieren/deaktivieren, Org-Einstellungen ändern, Incidents auflösen, gespeicherte Abfragen löschen — begrenzt nur durch die Berechtigungen Ihres CLI-Logins. Gehen Sie damit genauso sorgfältig um, als würden Sie diese Befehle selbst eintippen. + +--- + +## Voraussetzungen + +1. Die **`agenteye` CLI ist installiert** und im `PATH` (siehe [cli.md](/de/agenteye/cli) — `pipx install agenteye`). +2. Ihre **Dashboard-URL** ist gesetzt (`AGENTEYE_DASHBOARD_URL`, oder der Agent übergibt `--base-url`). +3. Eine **aktive Sitzung**: Führen Sie `agenteye login` selbst aus. Der Skill **kann** den per E-Mail versandten Einmalcode-Login nicht für Sie abschließen — er weist Sie darauf hin, `agenteye login` auszuführen, falls die Sitzung fehlt oder abgelaufen ist (CLI-Exit-Code `4`). + +--- + +## Den Skill installieren + +Agent Skills sind Ordner mit einer `SKILL.md` (plus optionalen Referenzen). Den `agenteye-cli` Skill installieren Sie, indem Sie seinen Ordner dort ablegen, wo Ihr Agent nach Skills sucht: + +- **Claude Code** — Kopieren Sie den Ordner `agenteye-cli/` nach `~/.claude/skills/` (in allen Projekten verfügbar) oder nach `/.claude/skills/` (auf dieses Repository beschränkt). Claude Code erkennt ihn automatisch; prüfen Sie dies mit der `/skills`-Liste oder stellen Sie einfach eine passende Frage. +- **Codex (OpenAI)** — Codex liest dieselbe `SKILL.md`. Die mitgelieferte `agents/openai.yaml` setzt `allow_implicit_invocation: true`, sodass Codex den Skill automatisch auswählt, wenn eine Aufgabe passt; andernfalls rufen Sie ihn explizit als `$agenteye-cli` auf. + +Der Skill wird zusammen mit der `agenteye` CLI gepflegt und als Teil Ihres AgentEye-Pakets ausgeliefert — falls Sie den `agenteye-cli`-Ordner nicht haben, wenden Sie sich an Ihren AgentEye-Kontakt. Er ist vollständig offen zugänglich: Er benötigt kein Docker-Image und keine separaten Anmeldedaten, da er ausschließlich die **öffentliche** `agenteye` CLI gegen Ihr eigenes Dashboard betreibt. + +--- + +## Sicherheit — schreibende Operationen werden NICHT bestätigt, wenn ein Agent die CLI ausführt + +**Lesen Sie dies, bevor Sie einen Agenten Änderungen vornehmen lassen.** + +Die `agenteye` CLI fragt normalerweise *„Sind Sie sicher?"* vor einer destruktiven Aktion. Sie **überspringt diese Bestätigung automatisch, wenn kein Terminal angehängt ist — was genau der Fall ist, wenn ein Coding-Agent sie ausführt — und `--json` überspringt sie ebenfalls.** Der Sicherheits-Prompt wird für den Agenten also **nicht** ausgelöst. + +Der Skill ist so konzipiert, dass er dies ausgleicht: Er ist angewiesen, den genauen Befehl, den er ausführen wird, anzugeben und Ihr explizites **OK vor jeder Zustandsänderung** einzuholen. Halten Sie diese Disziplin ein — wenn Sie AgentEye über einen Agenten steuern, *sind Sie* der Bestätigungsschritt. Die zustandsändernden Befehle, auf die Sie achten sollten: + +- `keys create` / `update` / `disable` / `regenerate` +- `users create` / `update` / `disable` / `enable` +- `settings set` +- `alerts create` / `update` / `delete` / `test` +- die schreibenden `incidents`-Unterbefehle: `ack` / `assign` / `resolve` / `open` / `comment-add` / `comment-delete` / `subscribe` / `unsubscribe` +- `query create` / `update` / `delete` +- `agent rename` / `delete` +- `orgs switch` + +Alles unter **Observe** (`events`, `sessions`, `evals`, `errors`, `list`, `whoami`, `orgs list/current/perms`) ist schreibgeschützt und ändert nichts. + +Da der Agent als **Sie** handelt, kann er nur das tun, wozu Ihr Login berechtigt ist — Berechtigungen werden **pro Organisation** aufgelöst (siehe [api-keys.md](/de/agenteye/api-keys)). Ein Befehl, für den Sie keine Berechtigung haben, gibt Exit-Code `5` mit dem genauen Namen der fehlenden Berechtigung zurück, sodass der Agent Ihnen präzise sagen kann, was Sie von einem Admin anfordern müssen, anstatt undurchsichtig zu scheitern. + +--- + +## Was Sie fragen können + +Der Skill ordnet natürlichsprachliche Absichten dem richtigen `agenteye`-Befehl zu, indem er zunächst gültige Werte ermittelt (`list `, `whoami`) und nicht rät: + +- *„Gibt es aktuell Fehler / Ausfälle in den letzten 24 Stunden?"* → `errors --since 24h --aggregate`, dann eine Aufschlüsselung. +- *„Warum ist Sitzung `run-001` fehlgeschlagen?"* → `events --session-id run-001 --all` + `evals --session-id run-001`. +- *„Wie entwickelt sich die Qualität diese Woche?"* → `evals --aggregate --since 7d`, dann Drill-down in schwach bewertete Läufe. +- *„Erstell CI einen Key, der nur Events pushen darf."* → `keys create ci --add events:add` (gibt den Befehl an, erstellt ihn und speichert das einmalige Secret). +- *„Wer hat Zugriff? Mach Dana zum reinen Lesezugriff."* → `users list` → `users update dana@… --permission-set read-only` (nach Ihrer Bestätigung). +- *„Bestätige den aktiven Incident und weise ihn mir zu."* → `incidents list --state firing` → `incidents ack ` / `incidents assign you@…`. + +Die genauen Befehle, Flags und JSON-Strukturen dahinter finden Sie in [cli.md](/de/agenteye/cli) und [cli-recipes.md](/de/agenteye/cli-recipes). + +--- + +## Siehe auch + +- **[CLI](/de/agenteye/cli)** — vollständige Befehls- und Flag-Referenz für `agenteye`. +- **[CLI-Rezepte für Agenten](/de/agenteye/cli-recipes)** — fertige `jq`-Muster und Exit-Code-Behandlung. +- **[KI-Assistent](/de/agenteye/assistant)** — der In-Dashboard-Assistent (nicht mit diesem Terminal-Skill zu verwechseln). +- **[API-Keys](/de/agenteye/api-keys)** — das organisationsweite Berechtigungsmodell, das den Wirkungsbereich des Skills begrenzt. \ No newline at end of file diff --git a/docs/de/agenteye/cli.mdx b/docs/de/agenteye/cli.mdx new file mode 100644 index 00000000..3770f491 --- /dev/null +++ b/docs/de/agenteye/cli.mdx @@ -0,0 +1,292 @@ +--- +title: "CLI" +description: "AgentEye CLI Dokumentation." +--- + + +Die AgentEye CLI (`agenteye`) ist ein Terminal-Client für Ihre AgentEye-Instanz. Sie fragt Ihre Daten ab (Sitzungen, Ereignisprotokolle, Auswertungen) und verwaltet die Organisation (API-Schlüssel, Benutzer, Einstellungen, Benachrichtigungen, Vorfälle, gespeicherte Abfragen) — alles, was das Dashboard bietet, aus einem Skript oder einem Coding-Agenten heraus. Jeder Befehl unterstützt ein `--json`-Flag, sodass er gleichermaßen für einen Menschen an der Eingabeaufforderung oder für einen Coding-Agenten (Claude Code, Cursor) geeignet ist, der die Ausgabe parsed. + +> Dies ist die **`agenteye` CLI**, ein anderes Werkzeug als der **Collector**-Daemon (`agenteye-collector`). Die CLI kommuniziert mit Ihrem **Dashboard**; der Collector liefert Ereignisse an den Server. Siehe [Collector-Installation](/de/agenteye/collector-installation) für den Collector. + +--- + +## Installation + +Die CLI ist auf dem öffentlichen PyPI als **`agenteye`** veröffentlicht. Da das AgentEye Python SDK ebenfalls den Distributionsnamen `agenteye` verwendet, installieren Sie die CLI in einer **isolierten** Umgebung (`pipx` oder `uv tool`), damit beide nie in einem Virtualenv kollidieren: + +```bash +pipx install agenteye +# oder +uv tool install agenteye +``` + +Ein einfaches `pip install agenteye` funktioniert ebenfalls, solange Sie das Python SDK nicht in dieselbe Umgebung installieren. Die CLI erfordert Python 3.10+ und benötigt kein GitHub-Token; sie ist ein öffentliches Paket. + +Der installierte Befehl lautet **`agenteye`**: + +```bash +agenteye --version +agenteye --help +``` + +--- + +## Authentifizierung + +Die CLI authentifiziert sich beim **Dashboard** mit einem per E-Mail zugesandten Einmalcode: + +```bash +agenteye login --email you@example.com +# Ein 6-stelliger Code wird an Sie gesendet; geben Sie ihn an der Eingabeaufforderung ein. +``` + +Das Sitzungstoken wird in `~/.agenteye/cli.json` gespeichert (nur für Sie lesbar, Modus `0600`) und ist standardmäßig 24 Stunden gültig. Nach Ablauf führen Sie erneut `agenteye login` aus. + +```bash +agenteye whoami # aktuellen Benutzer, aktive Organisation und Berechtigungen anzeigen +agenteye logout # die Sitzung widerrufen und das gespeicherte Token löschen +``` + +`whoami` löst bei einer fehlenden oder abgelaufenen Sitzung keinen Fehler aus — stattdessen wird `logged_in: false` zurückgegeben, damit ein Skript oder Agent den Auth-Status sicher prüfen kann (es kann dennoch mit einem Nicht-Null-Wert beenden, wenn keine Basis-URL gesetzt ist oder das Dashboard nicht erreichbar ist). + +**Voraussetzungen:** Ihre E-Mail-Adresse muss zur Anmeldung am Dashboard berechtigt sein (fragen Sie Ihren AgentEye-Administrator), und das Dashboard muss unter seiner Basis-URL erreichbar sein (siehe [Konfiguration](#configuration)). Wenn Sie einen Code anfordern und keiner ankommt, ist Ihre E-Mail-Adresse wahrscheinlich noch nicht für den Dashboard-Zugriff freigeschaltet. + +--- + +## Organisation auswählen (Multi-Tenant) + +Wenn Ihr Konto zu mehr als einer Organisation gehört, wählen Sie die aktive **beim Login** — sie wird gespeichert und für alle späteren Befehle verwendet: + +```bash +agenteye login --org acme # authentifizieren und den aktiven Mandanten in einem Schritt setzen +agenteye orgs list # die Organisationen, auf die Sie zugreifen können (die aktive ist markiert) +agenteye orgs switch globex # den gespeicherten Standard ändern +agenteye --org globex sessions # für einen einzelnen Befehl überschreiben +``` + +Wenn Sie genau zu einer Organisation gehören, wird diese automatisch ausgewählt und Sie können `--org` vollständig ignorieren. Wenn Sie mehreren angehören und keine auswählen, listet die CLI diese auf und fordert Sie auf, erneut mit `--org ` auszuführen. Die aktive Organisation wird bei jeder Anfrage an das Dashboard gesendet, und Ihre Berechtigungen werden **pro Organisation** aufgelöst — `agenteye whoami` zeigt die aktive Organisation, Ihre Berechtigungen darin und alle Ihre Mitgliedschaften. + +--- + +## Konfiguration + +| Einstellung | Flag | Umgebungsvariable | Standard | +|---|---|---|---| +| Dashboard-Basis-URL | `--base-url` | `AGENTEYE_DASHBOARD_URL` | **erforderlich** (kein Standard) | +| Aktive Organisation/Mandant | `--org` | `AGENTEYE_ORG` | beim Login gewählt; gespeichert in `~/.agenteye/cli.json` | +| Sitzungstoken | `--token` | `AGENTEYE_CLI_TOKEN` | aus `~/.agenteye/cli.json` | +| JSON-Ausgabe | `--json` | `AGENTEYE_CLI_JSON` | aus | +| TLS-Verifizierung überspringen | `--insecure` / `--secure` | `AGENTEYE_INSECURE` | aus (beim Login gespeichert) | +| Anfrage-Timeout (Sekunden) | `--timeout` | — | 30 | +| Nutzungstelemetrie deaktivieren | _(keine)_ | `AGENTEYE_ANALYTICS_DISABLED` (oder `DO_NOT_TRACK`) | aus (Telemetrie aktiv) | + +Die Auflösungsreihenfolge ist **Flag → Umgebungsvariable → Konfigurationsdatei**. Es gibt keinen Standardwert; Sie müssen die CLI auf Ihr Dashboard verweisen, entweder pro Befehl (`--base-url https://agenteye.example.com`) oder einmalig über die Umgebung (wird auch nach Ihrem ersten `login` gespeichert): + +```bash +export AGENTEYE_DASHBOARD_URL=https://agenteye.example.com +``` + +Das Konfigurationsverzeichnis berücksichtigt `AGENTEYE_HOME` (dieselbe Konvention wie beim SDK und Collector); wenn gesetzt, befindet sich `cli.json` unter `$AGENTEYE_HOME/cli.json`. + +### Selbstsignierte oder interne TLS-Zertifikate + +Wenn Ihr Dashboard über HTTPS mit einem selbstsignierten oder internen Zertifikat bereitgestellt wird (z. B. ein reiner Load-Balancer-Hostname), lehnt die TLS-Verifizierung die Verbindung mit einem `CERTIFICATE_VERIFY_FAILED`-Fehler ab. Verwenden Sie `--insecure`, um die Zertifikatsprüfung zu überspringen: + +```bash +agenteye --base-url https://agenteye.internal --insecure login +``` + +`--insecure` wird **beim Login in `cli.json` gespeichert**, sodass spätere Befehle die Prüfung automatisch überspringen; Sie müssen das Flag nicht wiederholen. Verwenden Sie `--secure` für einen einmaligen verifizierten Aufruf oder um die Verifizierung beim nächsten Login wieder zu aktivieren. Die CLI gibt vor jedem Befehl, der das Dashboard kontaktiert, während die Verifizierung deaktiviert ist, eine Warnung auf stderr aus. Das Überspringen der Verifizierung entfernt den Schutz vor Man-in-the-Middle-Angriffen; stellen Sie sicher, dass Sie dem Netzwerkpfad zu Ihrem Dashboard vertrauen (VPN, privates Subnetz usw.), bevor Sie sich darauf verlassen. + +--- + +## Telemetrie & Datenschutz + +Die CLI sendet **anonyme Nutzungsanalysen** an den Analysedienst von Exosphere (PostHog): welche Befehle ausgeführt werden (z. B. `sessions`, `keys create`), ob sie erfolgreich waren und wie lange sie dauerten. Dieses Nutzungssignal dient zur Priorisierung von Funktionen. + +- **Keine Agenten-, Sitzungs- oder Ereignisdaten verlassen jemals Ihre Infrastruktur.** Es wird nur die CLI-Nutzung gemeldet: der Befehls- und Unterbefehls-Name (z. B. `keys create`), die **Namen** der verwendeten Flags (niemals deren Werte), Erfolgs-/Beendigungsstatus und Dauer — plus ein pro-Aktion-Ereignis für Mutationen (z. B. `api_key_created`, `query_run`), das nur statische Namen/Enums und grobe Zählungen enthält. Ihre Dashboard-URL, Ihr Sitzungstoken, Ihre E-Mail, Ihr Organisations-Slug, Ressourcen-IDs, SQL, Schlüsselgeheimnisse und Abfragefilter werden **niemals** gesendet. Betreiber werden nur durch eine opake interne ID identifiziert, niemals durch E-Mail. +- Telemetrie ist **standardmäßig aktiviert**. Um sie zu deaktivieren, setzen Sie `AGENTEYE_ANALYTICS_DISABLED=1` in der Umgebung der CLI (die CLI berücksichtigt auch die Tool-übergreifende Konvention `DO_NOT_TRACK=1`). +- Die CLI sendet direkt an PostHog (`https://us.i.posthog.com`). Der **Rechner, auf dem die CLI läuft**, benötigt ausgehenden Zugriff auf diesen Host; wenn dieser blockiert ist, schlägt die Telemetrie stillschweigend fehl (das Senden ist zeitlich begrenzt, sodass es einen Befehl nie verzögert oder unterbricht) und die CLI ist nicht beeinträchtigt. + +--- + +## Globale Optionen & Konventionen + +Lesen Sie dies einmal; es gilt für jeden Befehl. + +- **Globale Optionen kommen VOR dem Befehl.** `agenteye --json sessions` ist korrekt; `agenteye sessions --json` ist ein Verwendungsfehler. Die globalen Optionen sind `--json`, `--base-url`, `--org`, `--token`, `--insecure`/`--secure`, `--timeout`, `--quiet` und `--no-color`. +- **`--json` gibt reines JSON auf stdout aus, und sonst nichts.** Menschliche Statuszeilen, Warnungen und Fehler gehen an **stderr**, sodass eine `--json`-stdout-Erfassung sauber bleibt, um sie in `jq` zu leiten, selbst wenn eine Statuszeile angezeigt wird. Ohne `--json` erhalten Sie eine eingerahmte, farbige Ansicht für menschliche Augen. +- **Entdecken Sie mit `--help`.** Jeder Befehl und Unterbefehl hat `--help` (und den Alias `-h`): `agenteye -h`, `agenteye sessions -h`, `agenteye keys create -h`. Die oberste Hilfseite listet auch die Exit-Codes und globalen Optionen auf. Es gibt keine globale maschinenlesbare Oberflächenübersicht; verwenden Sie `--help` pro Befehl sowie die domänenspezifischen `agenteye query schema` und `agenteye settings schema` für diese beiden Register. +- **Bestätigungen werden für Skripte und Agenten automatisch übersprungen.** Befehle zum Erstellen/Aktualisieren/Löschen fragen in einem interaktiven Terminal nach Bestätigung, **überspringen diese Aufforderung jedoch automatisch unter `--json` oder wenn stdin kein TTY ist** — sodass Skripte und Agenten nie blockieren. Übergeben Sie `--yes`/`-y`, um sie explizit zu überspringen. Da die Aufforderung für einen Agenten nicht ausgelöst wird, sollte ein Agent destruktive Aktionen zuerst mit dem Menschen bestätigen. +- **Paginierung:** Ergebnisse sind neueste zuerst und cursor-paginiert. `--limit N` (Alias `-n`) begrenzt Zeilen und **ist standardmäßig 50**; `--all` paginiert automatisch (in 200-Zeilen-Blöcken) **bis zu `--limit`** — ein bloßes `--all` stoppt also trotzdem bei 50. Für einen vollständigen Durchlauf übergeben Sie eine hohe explizite Obergrenze: `--all --limit 1000`. `--page-size N` steuert den Chunk pro Anfrage (max. 200); `--cursor ` setzt ab dem `next_cursor` einer vorherigen Seite fort. +- **Zeitfilter:** `--since` nimmt ein relatives Fenster — `15m`, `1h`, `6h`, `24h`, `7d`, `30d` oder `all` (die Voreinstellungen des Dashboards). `--from`/`--to` nehmen explizite ISO-8601 UTC-Zeitstempel **mit `T` und einer Zeitzone** (z. B. `2026-06-01T00:00:00Z`) für einen benutzerdefinierten Bereich und überschreiben `--since`; ein leerzeichengetrennter oder zeitzonenloser Wert ist ein Verwendungsfehler. +- **`--fields a,b,c`** (bei `events`, `sessions`, `evals`, `errors`) beschränkt die Ausgabe auf diese Schlüssel, sowohl für die Tabelle als auch für `--json`. Unbekannte Namen werden mit der gültigen Liste abgelehnt — eine einfache Möglichkeit, Feldnamen zu entdecken. +- **`--file payload.json`** (oder `--file -` zum Lesen von stdin) liefert einen vollständigen JSON-Anforderungskörper, wenn eine Ressource eine komplexe Form hat — bei `alerts create/update`, `settings set` und `users create/update`. Gespeicherte Abfragen in SQL verwenden stattdessen `--sql @file.sql`. +- **Mehrwert-Filter** sind kommagetrennt → als Menge abgeglichen (Union innerhalb eines Filters, AND zwischen Filtern): `--event-type tool_use,tool_result`. Click-Optionen sind nicht variadisch, daher bricht `--add a b` — verwenden Sie `--add a,b`, wiederholen Sie das Flag (`--add a --add b`) oder verwenden Sie Anführungszeichen (`--add "a b"`). + +--- + +## Befehlsreferenz + +Die CLI hat **18 Befehle auf oberster Ebene**. Alle Lesebefehle akzeptieren `--json` und die oben genannten globalen Optionen; führen Sie `agenteye -h` (oder ` -h`) für die vollständige Flag-Liste und JSON-Form eines einzelnen Befehls aus. + +### Identität — `login` · `logout` · `whoami` · `orgs` · `version` · `help` + +```bash +agenteye login --email you@example.com [--org acme] # per E-Mail versandter Einmalcode; speichert die Sitzung +agenteye logout # die gespeicherte Sitzung auf diesem Rechner löschen +agenteye whoami # aktueller Benutzer, aktive Organisation, Berechtigungen +agenteye version # CLI-Version ausgeben (wie --version) +agenteye help # oberste Hilfe (wie --help) +``` + +`orgs` prüft und wechselt den aktiven Mandanten: + +```bash +agenteye orgs list # Ihre Organisationen + Ihre Rolle in jeder (aktive markiert) +agenteye orgs switch acme # die gespeicherte aktive Organisation ändern (Slug weglassen, um auf einem TTY aus einer Liste zu wählen) +agenteye orgs current # Identitätskarte für die aktive Organisation +agenteye orgs perms # Ihre Berechtigungen in der aktiven Organisation, nach Ressource gruppiert +``` + +### Beobachten (nur lesen) — `events` · `sessions` · `evals` · `errors` · `list` + +Keiner dieser Befehle erfordert eine Bestätigung. Gemeinsame Filter: `--session-id`, `--agent-id`, `--env` (**nicht** `--environment`) und der Zeitraum (`--since` / `--from` / `--to`). + +```bash +# events (Alias: der rohe pro-Schritt-Verlauf) — neueste zuerst +agenteye --json events --session-id run-001 --event-type tool_use,tool_result --all --limit 1000 +agenteye --json events --since 1h --search timeout --all | jq '.events[].payload' + +# sessions — eine Zeile pro Agentenlauf (Zeit/Umgebung/Agent/Sitzung/Status; keine Score-Filterung) +agenteye --json sessions --since 24h --status error +agenteye --json sessions --agent-id checkout-bot --env prod --all --limit 1000 + +# evals — Auswertungsergebnisse + Scores; --score filtert nach Metrik, --aggregate fasst zusammen +agenteye --json evals --score helpfulness:0.5..0.8 --score tool_efficiency:..0.3 +agenteye --json evals --aggregate --since 7d --env prod # Statusmix + Score-Statistiken pro Schlüssel + +# errors — fehlerhafte Ereignisse; --aggregate für Zählungen/Sitzungen/Agenten/zuletzt gesehen +agenteye --json errors --since 24h --aggregate +agenteye --json errors --since 24h --error-type timeout --all --limit 1000 + +# list — gültige Filterwerte entdecken, bevor Sie filtern +agenteye list envs # auch: agents event_types score_filters models hooks triggers tools error_types +``` + +`--score KEY:MIN..MAX` (bei **`evals`**, nicht `sessions`) ist wiederholbar und wird AND-verknüpft; jede Grenze ist optional (`..0.5` bedeutet ≤ 0.5, `0.9..` bedeutet ≥ 0.9). Bis zu 20 Score-Filter pro Anfrage. `evals --scores-full` gibt das vollständige Score-Objekt statt der Zusammenfassung zurück. Um **eine Sitzung von Anfang bis Ende** zu lesen, kombinieren Sie den Ereignisverlauf mit seiner Auswertung: + +```bash +agenteye --json events --session-id run-001 --all --limit 1000 | jq '.events[] | {ts, event_type}' +agenteye --json evals --session-id run-001 # Scores + Status +``` + +### Verwalten (berechtigungsgesteuert) — `keys` · `users` · `settings` · `alerts` · `incidents` + +**`keys`** — API-Schlüssel. Das Geheimnis wird lokal generiert, an den Server gesendet (der nur einen Hash speichert) und **einmalig** bei der Erstellung/Regenerierung angezeigt — erfassen Sie es sofort. Mit `--json` erscheint es nur im Feld `key`. Referenziert nach **Name**. + +```bash +agenteye keys list # aktive Schlüssel zuerst, dann widerrufene +agenteye keys show ci-bot +agenteye keys create ci-bot --add events:read.add # auf das Nötigste beschränken; gibt das Geheimnis EINMALIG aus +agenteye keys create ops --permission-set standard --remove queries:run # Voreinstellung setzen, dann anpassen +agenteye keys update ci-bot --add evaluations:read --yes +agenteye keys regenerate ci-bot --yes # das Geheimnis rotieren (das alte funktioniert nicht mehr) +agenteye keys disable ci-bot --yes # widerrufen +``` + +Berechtigungen funktionieren als `(permission-set ∪ --add) − --remove`. Token sind `slug:action` (z. B. `events:read`) oder `slug:action.action`, um mehrere auf einer Ressource zu erweitern (`events:read.add` → `events:read`, `events:add`). Voreinstellungen: `read-only`, `standard`, `admin`. Nur für Menschen bestimmte Berechtigungen (`keys:update`) können einem Schlüssel nicht gewährt werden. + +**`users`** — Organisations-Mitglieder, referenziert nach **E-Mail** (eine UUID-ID wird ebenfalls akzeptiert). + +```bash +agenteye users list [--active-only] +agenteye users show dev@corp.com +agenteye users create dev@corp.com --permission-set standard +agenteye users update dev@corp.com --add alerts:write --remove queries:delete # prognostiziert + bestätigt +agenteye users disable dev@corp.com --yes # hat Schutzmaßnahmen für geschützte/eigene Konten +agenteye users enable dev@corp.com +``` + +**`settings`** — ein festes Register (Sie lesen und ändern vorhandene Schlüssel; Sie können keine neuen erstellen). + +```bash +agenteye settings list # Schlüssel · Wert · Typ · aktualisiert (Geheimnisse maskiert) +agenteye settings schema # was jeder Schlüssel akzeptiert (Typ · Bereich · Beschreibung) +agenteye settings set session_ttl_secs --value 86400 --yes +``` + +**`alerts`** — Alert-Definitionen, referenziert nach **Name**. `create` nimmt einen positionellen NAME plus Flags oder einen vollständigen JSON-Körper über `--file`. + +```bash +agenteye alerts list +agenteye alerts show high-errors +agenteye alerts create high-errors --file alert.json # NAME ist erforderlich (positionell) +agenteye alerts update high-errors --severity critical --yes +agenteye alerts test high-errors --yes # eine Test-Benachrichtigung auslösen +agenteye alerts delete high-errors --yes +``` + +**`incidents`** — Alert-Vorfälle, referenziert nach ID (Kurz-IDs werden akzeptiert). `show` gibt das vollständige Aktivitätsprotokoll aus — lesen Sie es, bevor Sie handeln. + +```bash +agenteye incidents list --state firing # auch: acknowledged, resolved +agenteye incidents count +agenteye incidents show +agenteye incidents ack +agenteye incidents assign you@corp.com # Zugewiesener muss ein Operator sein +agenteye incidents resolve --yes +agenteye incidents open --alert-id --severity critical # manuell gegen einen Alert öffnen +agenteye incidents comment-add "root cause: upstream 5xx" +agenteye incidents comment-list ; agenteye incidents comment-delete +agenteye incidents subscribe ; agenteye incidents unsubscribe ; agenteye incidents subscribers +``` + +### Analyse & Assistent — `query` · `agent` + +**`query`** — gespeichertes ClickHouse SQL plus ein Ad-hoc-Runner. Gespeicherte Abfragen werden nach **Name** referenziert; das SQL wird serverseitig validiert (nur SELECT/WITH, Anweisungs-Timeout, Zeilenlimit). + +```bash +agenteye query schema [TABLE] # Spaltenlayout der Analyseansichten +agenteye query run --sql "select count(*) from analytics.events" +agenteye query run errs --arg prod --limit 100 # eine gespeicherte Abfrage + ein positionelles $1 ausführen +agenteye query list ; agenteye query show errs +agenteye query create errs --sql @errs.sql --description "errored events (24h)" +agenteye query update errs --sql @errs.sql --yes ; agenteye query delete errs --yes +``` + +**`agent`** — der eingebaute Dashboard-Assistent (derselbe schreibgeschützte Analyst, mit dem Sie im Dashboard chatten können). Chats werden nach einer kurzen Chat-ID referenziert (Präfix-Auflösung). + +```bash +agenteye agent health # ist der Assistent konfiguriert/erreichbar +agenteye agent models # Modelle, die Sie an --model übergeben können (Standard markiert) +agenteye agent ask "which agents errored most in the last day?" # startet einen Chat; gibt seine Kurz-ID aus +agenteye agent ask --chat "and which tools did they call?" # diesen Chat fortsetzen +agenteye agent chats ; agenteye agent show +agenteye agent rename --title "error triage" ; agenteye agent delete +``` + +--- + +## Exit-Codes + +| Code | Bedeutung | +|---|---| +| 0 | Erfolg | +| 1 | Unerwarteter Fehler (z. B. das Dashboard hat einen 5xx zurückgegeben) | +| 2 | Verwendungsfehler (ungültige Argumente, unbekannter Befehl/Flag, Namenskollision) | +| 3 | Das Dashboard ist nicht erreichbar | +| 4 | Nicht angemeldet oder Sitzung abgelaufen; führen Sie `agenteye login` aus | +| 5 | Authentifiziert, aber Ihrem Konto fehlt die erforderliche Berechtigung (die Meldung nennt sie) | +| 6 | Die angeforderte Ressource wurde nicht gefunden (z. B. unbekannte Sitzungs- oder Vorfalls-ID) | + +Diese machen die CLI sicher skriptierbar: ein Coding-Agent kann bei einem `4` verzweigen, um Sie zur erneuten Authentifizierung aufzufordern, oder bei einem `5`, um die fehlende Berechtigung anzuzeigen. Siehe [CLI-Rezepte für Agenten](/de/agenteye/cli-recipes) für Exit-Code-Behandlungsmuster und JSON-Ausgabeformen. + +--- + +## Siehe auch + +- **[CLI-Rezepte für Agenten](/de/agenteye/cli-recipes)** — Abfragemuster zum Kopieren und Einfügen, `jq`-Einzeiler, `--fields`-Projektionen, Exit-Code-Behandlung und JSON-Ausgabeformen, geschrieben für Coding-Agenten, die die CLI steuern. +- **[AgentEye CLI Skill](/de/agenteye/cli-skill)** — Diese CLI als installierbaren Claude Code / Codex-*Skill* verpacken, damit ein Coding-Agent AgentEye über einfache Englisch-Anfragen steuert. +- **[API Keys](/de/agenteye/api-keys)** — das Berechtigungsmodell hinter `keys create --add …`. +- **[KI-Assistent](/de/agenteye/assistant)** — den Assistenten aktivieren, mit dem `agent ask` kommuniziert. \ No newline at end of file diff --git a/docs/de/agenteye/collector-installation.mdx b/docs/de/agenteye/collector-installation.mdx new file mode 100644 index 00000000..6e4abee2 --- /dev/null +++ b/docs/de/agenteye/collector-installation.mdx @@ -0,0 +1,401 @@ +--- +title: "Collector-Installation" +description: "Installationsdokumentation für den AgentEye Collector." +--- + + +Der `agenteye-collector`-Daemon stellt sicher, dass die Telemetriedaten Ihrer Agents AgentEye erreichen, ohne Ihre Anwendung jemals zu blockieren. Ihr Code schreibt Ereignisse in ein lokales Verzeichnis und macht weiter; der Collector übernimmt von dort aus, lädt jede Datei innerhalb von Millisekunden hoch und übersteht Neustarts, Netzwerkausfälle und vorübergehende Serverfehler. Fehlgeschlagene Uploads werden mit exponentiellem Backoff wiederholt, und ein periodischer Recovery-Sweep stellt alles wieder in die Warteschlange, was nach einem Absturz oder Deployment zurückgeblieben ist. Das Ergebnis ist eine robuste Fire-and-forget-Übertragung: Ihre Agents laufen weiterhin mit voller Geschwindigkeit, während der Collector sicherstellt, dass keine Ereignisse während der Übertragung verloren gehen. + +Technisch gesehen ist der Collector ein schlanker Daemon, der `$AGENTEYE_HOME/events/` (Standard: `~/.agenteye/events/`) auf `.jsonl`-Dateien überwacht, die vom Python-SDK geschrieben wurden, und diese auf den AgentEye-Server hochlädt. + +> **Umbenannt:** Der Collector-Befehl heißt jetzt **`agenteye-collector`** (früher war es `agenteye`). Der kurze Name `agenteye` gehört nun zur AgentEye-CLI. Wenn Sie eine bestehende Installation aktualisieren, lesen Sie [enterprise-docs/collector-migration.md](/de/agenteye/collector-migration). + +--- + +## Voraussetzungen + +- Ihr `AGENTEYE_TOKEN`: ein GitHub PAT, den Sie selbst generieren (siehe [enterprise-docs/github-token.md](/de/agenteye/github-token)) +- Die Server-URL und ein Collector-API-Schlüssel (siehe [enterprise-docs/api-keys.md](/de/agenteye/api-keys)) + +--- + +## Option A: Binärdatei (empfohlen) + +Vorgefertigte statische Binärdateien sind für Linux, macOS und Windows (x86_64 und arm64) verfügbar. Laden Sie die Binärdatei für Ihre Plattform direkt aus dem Repository `agenteye-enterprise/releases` unter dem neuesten Release-Tag `collector/v` herunter. + +Verfügbare Artefaktnamen: + +| Plattform | Artefakt | +|---|---| +| Linux x86_64 | `agenteye-collector-linux-x86_64` | +| Linux arm64 | `agenteye-collector-linux-arm64` | +| macOS x86_64 | `agenteye-collector-darwin-x86_64` | +| macOS arm64 | `agenteye-collector-darwin-arm64` | +| Windows x86_64 | `agenteye-collector-windows-x86_64.exe` | +| Windows arm64 | `agenteye-collector-windows-arm64.exe` | + +**Download mit der `gh`-CLI** (Version ersetzen und das Artefakt Ihrer Plattform auswählen): + +```bash +VERSION=0.0.1-beta.13 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "collector/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-collector-linux-x86_64' + +chmod +x agenteye-collector-linux-x86_64 +sudo mv agenteye-collector-linux-x86_64 /usr/local/bin/agenteye-collector +``` + +**Oder mit `curl`:** + +```bash +VERSION=0.0.1-beta.13 +ARTIFACT=agenteye-collector-linux-x86_64 +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + -L "https://github.com/agenteye-enterprise/releases/releases/download/collector%2Fv${VERSION}/${ARTIFACT}" \ + -o agenteye-collector +chmod +x agenteye-collector +sudo mv agenteye-collector /usr/local/bin/agenteye-collector +``` + +--- + +## Option B: Docker + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +docker pull ghcr.io/agenteye-enterprise/collector:beta-latest +``` + +> Aktuelle Beta-Builds veröffentlichen den variablen Tag `:beta-latest`; `:latest` wird nur stabilen Releases zugewiesen. Für reproduzierbare Deployments sollten Sie einen festen Versions-Tag wie `:v0.0.1-beta.13` bevorzugen. + +**Ausführen:** + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-collector \ + -e AGENTEYE_URL=https://ingest.example.com/events \ + -e AGENTEYE_KEY="$AGENTEYE_KEY" \ + -e AGENTEYE_HOME=/data \ + -v "$HOME/.agenteye:/data" \ + ghcr.io/agenteye-enterprise/collector:beta-latest \ + start +``` + +Das offizielle Image läuft als Nicht-Root-Benutzer, daher setzen Sie `AGENTEYE_HOME` explizit und mounten Sie den Host-Spool dorthin. Das Volume-Mount teilt dasselbe `~/.agenteye/`-Verzeichnis, in das das Python-SDK auf dem Host schreibt. Wenn Sie `AGENTEYE_HOME` bereits anderswo auf dem Host gesetzt haben, mounten Sie stattdessen dieses Verzeichnis anstelle von `$HOME/.agenteye`. + +--- + +## Konfiguration + +Alle Optionen können auf drei Arten gesetzt werden (höchste Priorität zuerst): + +1. CLI-Flag: `agenteye-collector start --url https://...` +2. Umgebungsvariable: `AGENTEYE_URL=https://...` +3. Konfigurationsdatei: `~/.agenteye/config.json` + +### Pflichtoptionen + +| Option | CLI-Flag | Umgebungsvariable | config.json-Schlüssel | +|---|---|---|---| +| Backend-URL | `--url ` | `AGENTEYE_URL` | `"url"` | +| API-Schlüssel | `--key ` | `AGENTEYE_KEY` | `"key"` | + +### Optionale Einstellungen (mit Standardwerten) + +| Option | CLI-Flag | Umgebungsvariable | config.json-Schlüssel | Standard | +|---|---|---|---|---| +| Max. gleichzeitige Uploads | `--max-concurrent-uploads ` | `AGENTEYE_MAX_CONCURRENT_UPLOADS` | `"max_concurrent_uploads"` | `64` | +| Sweep-Intervall (s) | `--sweep-interval ` | `AGENTEYE_SWEEP_INTERVAL` | `"sweep_interval_secs"` | `60` | +| Minimales Datei-Alter für Sweep (s) | `--sweep-min-age ` | `AGENTEYE_SWEEP_MIN_AGE` | `"sweep_min_age_secs"` | `120` | +| Max. Dateien pro Sweep | `--sweep-max-files ` | `AGENTEYE_SWEEP_MAX_FILES` | `"sweep_max_files"` | `64` | +| Max. Upload-Versuche | `--max-retries ` | `AGENTEYE_MAX_RETRIES` | `"max_retries"` | `5` | +| Basis-Verzögerung für Wiederholung (ms) | `--retry-base-delay ` | `AGENTEYE_RETRY_BASE_DELAY` | `"retry_base_delay_ms"` | `1000` | + +### mTLS-Optionen (optional) + +Für Deployments, die gegenseitiges TLS (mTLS) erfordern, kann der Collector beim TLS-Handshake ein Client-Zertifikat vorlegen. Wenn diese Optionen nicht gesetzt sind, verwendet der Collector Standard-HTTPS. + +| Option | CLI-Flag | Umgebungsvariable | config.json-Schlüssel | +|---|---|---|---| +| Client-Zertifikat (PEM) | `--tls-cert ` | `AGENTEYE_TLS_CERT` | `"tls_cert"` | +| Privater Client-Schlüssel (PEM) | `--tls-key ` | `AGENTEYE_TLS_KEY` | `"tls_key"` | +| Benutzerdefiniertes CA-Zertifikat (PEM) | `--tls-ca ` | `AGENTEYE_TLS_CA` | `"tls_ca"` | + +`--tls-cert` und `--tls-key` müssen zusammen gesetzt werden. Die Dateien müssen PEM-kodiert sein. + +`--tls-ca` ist unabhängig und wird nur benötigt, wenn der AgentEye-Server ein TLS-Zertifikat vorlegt, das nicht von einer öffentlich vertrauenswürdigen CA ausgestellt wurde (z. B. selbstsigniert von einem clustereigenen `cert-manager`-Issuer, wenn Sie keine echte DNS-Domain haben). Der Collector fügt die angegebene CA als zusätzlichen Vertrauensanker hinzu; die öffentlichen Standard-Root-Zertifikate bleiben weiterhin vertrauenswürdig, bestehende Deployments sind daher nicht betroffen. Die Datei kann ein einzelnes PEM-Zertifikat oder eine vollständige Kette (mehrere verkettete PEM-Blöcke) enthalten. + +**Betreiben Sie den Collector als Sidecar in Ihrem Application-Pod?** Lesen Sie [enterprise-docs/single-pod-deployment.md](/de/agenteye/single-pod-deployment) für das vollständige EKS-Muster: mTLS-Bundle über AWS Secrets Manager + Secrets Store CSI Driver + IRSA, mit automatischer Rotation. + +Wenn Sie in Kubernetes mit dem Secret-Übergabe-Muster arbeiten, mounten Sie das Zertifikats-Secret als Volume und verweisen Sie diese Pfade auf die gemounteten Dateien: + +```yaml +# Beispiel: Collector-Deployment-Ausschnitt +volumes: + - name: mtls-certs + secret: + secretName: agenteye-collector-mtls +containers: + - name: collector + env: + - name: AGENTEYE_TLS_CERT + value: /etc/agenteye/tls/tls.crt + - name: AGENTEYE_TLS_KEY + value: /etc/agenteye/tls/tls.key + # Nur wenn das Server-Zertifikat nicht öffentlich vertrauenswürdig ist + # (z. B. clustereigene selbstsignierte CA). Dasselbe Secret enthält + # typischerweise ca.crt neben tls.crt/tls.key. + - name: AGENTEYE_TLS_CA + value: /etc/agenteye/tls/ca.crt + volumeMounts: + - name: mtls-certs + mountPath: /etc/agenteye/tls + readOnly: true +``` + +### Beispiel `~/.agenteye/config.json` + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "max_concurrent_uploads": 16, + "sweep_interval_secs": 30 +} +``` + +Mit mTLS: + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "tls_cert": "/etc/agenteye/tls/tls.crt", + "tls_key": "/etc/agenteye/tls/tls.key" +} +``` + +Mit mTLS und benutzerdefinierter CA (selbstsignierter AgentEye-Server): + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "tls_cert": "/etc/agenteye/tls/tls.crt", + "tls_key": "/etc/agenteye/tls/tls.key", + "tls_ca": "/etc/agenteye/tls/ca.crt" +} +``` + +Wenn `AGENTEYE_HOME` gesetzt ist, wird dieses Verzeichnis anstelle von `~/.agenteye` verwendet. + +--- + +## Ersteinrichtung + +Konfigurieren Sie nach der Installation den Collector mit Ihrer Server-URL und Ihrem API-Schlüssel: + +```bash +mkdir -p ~/.agenteye +cat > ~/.agenteye/config.json <<'EOF' +{ + "url": "https://ingest.example.com/events", + "key": "YOUR_COLLECTOR_KEY" +} +EOF +``` + +> Verwenden Sie `https` für jedes Deployment, das ein nicht vertrauenswürdiges Netzwerk überquert, damit Ereignisse nicht im Klartext gesendet werden. Die Klartextform `http://your-server-host:8080/events` ist nur für rein lokale Tests gegen einen Server auf demselben Host geeignet. + +**Verbindung testen** (einmaliger Flush, beendet sich nach dem Leeren ausstehender Ereignisse): + +```bash +agenteye-collector flush +``` + +`flush` gibt seinen Fortschritt auf stdout aus. Wenn der Spool leer ist, gibt es `No pending files.` aus und beendet sich mit `0`. Andernfalls wird eine Zeile pro Datei ausgegeben (`[UPLOADED] ` oder `[FAILED] ()`), gefolgt von einer `Done: / uploaded, failed.`-Zusammenfassung. Damit ist `flush` eine praktische Einmalprüfung, ob Ihre URL, Ihr Schlüssel und Ihre TLS-Einstellungen korrekt sind, bevor Sie den Daemon starten. + +--- + +## Als Daemon betreiben + +### Direkt + +```bash +agenteye-collector start +``` + +### Container / Docker + +Wenn Collector und Anwendung einen Container teilen, führen Sie beide unter einem Prozess-Supervisor aus. Die einfachste Option ist `supervisord`; es ist in jeder großen Distribution enthalten, startet abgestürzte Prozesse neu, leitet Signale weiter und wartet auf einen sauberen Shutdown. + +**`Dockerfile`:** + +```Dockerfile +FROM python:3.11-slim + +RUN apt-get update && apt-get install -y --no-install-recommends supervisor \ + && rm -rf /var/lib/apt/lists/* + +# Die agenteye-collector-Binärdatei aus dem offiziellen Image beziehen. +# Einen spezifischen Tag angeben (:beta-latest für aktuelle Betas oder einen :v-Tag); +# :latest wird nur für stabile Releases veröffentlicht. +COPY --from=ghcr.io/agenteye-enterprise/collector:beta-latest \ + /usr/local/bin/agenteye-collector /usr/local/bin/agenteye-collector + +COPY supervisord.conf /etc/supervisor/conf.d/agenteye.conf +COPY my_agent.py /app/my_agent.py + +CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"] +``` + +**`supervisord.conf`:** + +```ini +[supervisord] +nodaemon=true +user=root + +[program:agenteye-collector] +command=/usr/local/bin/agenteye-collector start +autorestart=true +stopwaitsecs=30 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:app] +command=python /app/my_agent.py +autorestart=unexpected +stopwaitsecs=30 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +``` + +Begründung dieser Einstellungen: + +- `autorestart=true` beim agenteye-collector: Neustart bei jedem Beenden (Absturz, Panic, OOM). +- `autorestart=unexpected` bei der App: Neustart nur bei nicht-null Exit-Code, damit ein einmaliger Agent, der mit 0 beendet wird, keine Endlosschleife verursacht. +- `stopwaitsecs=30`: Gibt dem Collector Zeit, ausstehende Uploads bei SIGTERM zu beenden, bevor supervisord zu SIGKILL eskaliert. +- `stdout_logfile=/dev/stdout`, `*_maxbytes=0`: Ausgabe beider Programme zum Container-stdout streamen; keine Logdateien innerhalb des Containers. + +Übergeben Sie `AGENTEYE_URL` / `AGENTEYE_KEY` (und alle TLS-Umgebungsvariablen) wie gehabt über `docker run -e`; supervisord erbt die Umgebung. + +> **Separate Container?** Wenn Sie den Collector als eigenständigen Container betreiben (Docker-Compose-Service, Kubernetes-Sidecar usw.), verwenden Sie kein supervisord; die Restart-Policy der Container-Runtime übernimmt diese Aufgabe bereits. Lesen Sie [enterprise-docs/single-pod-deployment.md](/de/agenteye/single-pod-deployment) für das EKS-Sidecar-Muster. + +**Kubernetes Liveness-Probe** (gilt sowohl wenn der Collector allein als auch unter supervisord läuft): + +```yaml +livenessProbe: + exec: + command: ["agenteye-collector", "health"] + initialDelaySeconds: 10 + periodSeconds: 30 +``` + +Der laufende Daemon schreibt alle 30 Sekunden einen Heartbeat in `$AGENTEYE_HOME/health.json`. `agenteye-collector health` liest diese Datei und gibt nur dann `0` (gesund) zurück, wenn der Heartbeat aktuell ist und die Upload-Tasks normal laufen; es gibt `1` (ungesund) zurück, wenn der Heartbeat älter als 90 Sekunden ist (beispielsweise hat der Daemon aufgehört zu laufen) oder während Watcher und Sweeper nach einem unerwarteten Beenden neu starten. Der Heartbeat wird nur durch `start` geschrieben, führen Sie die Probe daher gegen den langlebigen Daemon und nicht gegen den einmaligen `flush`-Befehl aus. + +### systemd (Linux, empfohlen für Produktion) + +```ini +# /etc/systemd/system/agenteye-collector.service +[Unit] +Description=AgentEye Collector +After=network.target + +[Service] +ExecStart=/usr/local/bin/agenteye-collector start +Restart=on-failure +RestartSec=5 +EnvironmentFile=/etc/agenteye/env + +[Install] +WantedBy=multi-user.target +``` + +Erstellen Sie `/etc/agenteye/env`: + +``` +AGENTEYE_URL=https://ingest.example.com/events +AGENTEYE_KEY=YOUR_COLLECTOR_KEY +``` + +```bash +sudo systemctl daemon-reload +sudo systemctl enable --now agenteye-collector +sudo systemctl status agenteye-collector +``` + +### launchd (macOS) + +```xml + + + + + + Label + ai.befailproof.agenteye-collector + ProgramArguments + + /usr/local/bin/agenteye-collector + start + + EnvironmentVariables + + AGENTEYE_URL + https://ingest.example.com/events + AGENTEYE_KEY + YOUR_COLLECTOR_KEY + + RunAtLoad + + KeepAlive + + + +``` + +```bash +launchctl load ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +``` + +--- + +## Collector aktualisieren + +Der Collector aktualisiert sich nicht selbst. So führen Sie ein Upgrade durch: + +- **Binärdatei:** Laden Sie das neue `agenteye-collector--`-Artefakt aus dem neuesten `collector/v`-Release herunter (siehe [Option A](#option-a-binary-recommended)), ersetzen Sie `/usr/local/bin/agenteye-collector` und starten Sie dann den Dienst neu (`sudo systemctl restart agenteye-collector`, erneutes `launchctl load` oder Neustart Ihres Supervisors). +- **Docker:** `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (oder einen festen `:v`-Tag; `:latest` existiert nur für stabile Releases) und den Container neu erstellen. + +`AGENTEYE_TOKEN` wird benötigt, um neue Binärdateien/Images aus dem privaten Releases-Repository herunterzuladen, wird aber vom laufenden Daemon **nicht** benötigt. + +--- + +## Unterbefehle + +| Befehl | Beschreibung | +|---|---| +| `agenteye-collector start` | Startet den langlebigen Daemon. Beim Start werden alle Ereignisse aus einem vorherigen Lauf übertragen, dann werden neue Dateien überwacht und hochgeladen. Watcher und Sweeper starten bei unerwarteten Beenden automatisch neu, und alle 30 Sekunden wird ein Heartbeat in `health.json` geschrieben. | +| `agenteye-collector flush` | Einmalig: Alle ausstehenden Dateien hochladen und beenden. Gibt `No pending files.` aus, wenn der Spool leer ist, andernfalls ein `[UPLOADED]`/`[FAILED]`-Log pro Datei und eine `Done: / uploaded, failed.`-Zusammenfassung. | +| `agenteye-collector health` | Liest den `health.json`-Heartbeat des Daemons. Gibt `0` zurück, wenn aktuell und gesund; gibt `1` zurück, wenn der Heartbeat veraltet ist (älter als 90 s) oder die Tasks neu starten. | + +--- + +## Verzeichnisstruktur + +``` +~/.agenteye/ +├── config.json <- optionale Konfigurationsdatei +├── events/ <- .jsonl-Dateien, die vom SDK geschrieben und vom Collector aufgenommen werden +└── failed/ <- Dateien, bei denen alle Upload-Versuche fehlgeschlagen sind +``` + +Dateien in `failed/` werden nicht automatisch erneut versucht. Um sie manuell wieder in die Warteschlange einzureihen, verschieben Sie sie zurück nach `events/` und führen Sie `agenteye-collector flush` aus. \ No newline at end of file diff --git a/docs/de/agenteye/collector-migration.mdx b/docs/de/agenteye/collector-migration.mdx new file mode 100644 index 00000000..9a187582 --- /dev/null +++ b/docs/de/agenteye/collector-migration.mdx @@ -0,0 +1,167 @@ +--- +title: "Migration zu `agenteye-collector`" +description: "AgentEye-Dokumentation zur Migration zu `agenteye-collector`." +--- + +Die Migration ist nicht-destruktiv: Es gibt keine Ausfallzeiten und keinen Datenverlust. Außerdem wird der kurze Name `agenteye` für die [AgentEye CLI](/de/agenteye/cli) freigegeben, sodass der Collector-Daemon und die CLI auf demselben Rechner koexistieren können. + +Das Collector-Binary wurde **von `agenteye` in `agenteye-collector` umbenannt**. Der kurze Name `agenteye` gehört nun zur AgentEye CLI, einem separaten Werkzeug zum Abfragen von Sessions, Events und Evaluierungen über das Terminal. + +Diese Anleitung führt Sie durch die Migration einer bestehenden Collector-Installation. + +--- + +## Was sich geändert hat + +| | Vorher | Nachher | +|---|---|---| +| Befehl / Binary | `agenteye` | `agenteye-collector` | +| Standard-Installationspfad | `/usr/local/bin/agenteye` | `/usr/local/bin/agenteye-collector` | +| Unterbefehle | `start`, `flush`, `health`, `update` | `start`, `flush`, `health` | +| Selbst-Update (`agenteye update`) | eingebaut | **entfernt**: neues Binary herunterladen oder neues Image pullen | +| Installationsskript (`install.sh`) | vorhanden | **entfernt**: Binary direkt herunterladen (siehe [Collector-Installation](/de/agenteye/collector-installation)) | +| `AGENTEYE_TOKEN` | zum Herunterladen **und** für Hintergrund-Update-Prüfungen erforderlich | nur zum **Herunterladen** von Binaries/Images erforderlich | + +Die Konfiguration bleibt unverändert: dasselbe `~/.agenteye/config.json`, dieselben Umgebungsvariablen `AGENTEYE_URL` / `AGENTEYE_KEY` / `AGENTEYE_HOME` / TLS sowie derselbe `~/.agenteye/events/`-Spool. **Es sind keine Konfigurationsänderungen erforderlich.** + +> Wenn Sie das umbenannte Binary unter dem alten Namen `agenteye` ausführen, funktioniert es weiterhin, gibt aber eine einzeilige Deprecation-Warnung auf stderr aus, die Sie auf den Wechsel zu `agenteye-collector` hinweist. + +--- + +## Bevor Sie beginnen + +- Ihre **bestehende `agenteye`-Installation läuft weiter**; beim Upgrade passiert sofort nichts. Führen Sie die Migration bewusst durch und entfernen Sie das alte Binary zuletzt. +- Halten Sie diese Reihenfolge ein, um Ausfallzeiten zu vermeiden: + 1. Das neue `agenteye-collector`-Binary installieren (oder das neue Image pullen). + 2. Ihre Service-Definition, Health-Probe und Skripte auf `agenteye-collector` umstellen. + 3. Den Service neu laden und starten; prüfen, ob er gesund ist. + 4. **Erst dann** das alte Binary `/usr/local/bin/agenteye` entfernen. + +--- + +## 1. Das neue Binary installieren + +Laden Sie das Artefakt für Ihre Plattform herunter (`agenteye-collector-linux-x86_64`, `agenteye-collector-darwin-arm64` usw.; die vollständige Liste finden Sie unter [Collector-Installation → Option A](/de/agenteye/collector-installation#option-a-binary-recommended)) aus dem neuesten `collector/v`-Release und legen Sie es unter `/usr/local/bin/agenteye-collector` ab. Docker-Nutzer: `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (oder ein gepinnter `:v`-Tag, was bevorzugt wird; `:latest` existiert nur für stabile Releases). + +Überprüfung: + +```bash +agenteye-collector --version +``` + +--- + +## 2. Ihr Deployment aktualisieren + +### systemd (Linux) + +Bearbeiten Sie `/etc/systemd/system/agenteye-collector.service`, sodass `ExecStart` auf das neue Binary zeigt: + +```ini +[Service] +ExecStart=/usr/local/bin/agenteye-collector start +``` + +Dann neu laden und neu starten: + +```bash +sudo systemctl daemon-reload +sudo systemctl restart agenteye-collector +sudo systemctl status agenteye-collector +``` + +### launchd (macOS) + +> **Brand-Umbenennung:** Wenn Ihre bestehende Plist-Datei unter dem älteren Pfad +> `~/Library/LaunchAgents/host.exosphere.agenteye-collector.plist` liegt, benennen Sie +> die Datei in `ai.befailproof.agenteye-collector.plist` um und ändern Sie außerdem den +> `Label`-Wert in der Datei auf den neuen Bezeichner, bevor Sie sie neu laden. + +Ändern Sie in `~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist` den ersten `ProgramArguments`-Eintrag von `/usr/local/bin/agenteye` auf `/usr/local/bin/agenteye-collector` und laden Sie dann neu: + +```bash +launchctl unload ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +launchctl load ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +``` + +### supervisord + +Setzen Sie in Ihrem `supervisord`-Programmblock `command` auf das neue Binary: + +```ini +[program:agenteye-collector] +command=/usr/local/bin/agenteye-collector start +``` + +Dann `supervisorctl reread && supervisorctl update`. + +### Docker / Kubernetes + +Pullen Sie das neue Image (`ghcr.io/agenteye-enterprise/collector:beta-latest` oder ein gepinnter `:v`-Tag, was bevorzugt wird; `:latest` existiert nur für stabile Releases). Der Image-Entrypoint ist bereits `agenteye-collector`, sodass derselbe `docker run`-Befehl mit dem `start`-Unterbefehl ohne Änderungen weiterhin funktioniert. + +**Wichtig: Health-Probes aktualisieren.** Wenn Sie eine Kubernetes-Liveness/Readiness-Probe (oder ein `docker exec`) verwenden, das das Binary namentlich aufruft, ändern Sie den Befehl auf `agenteye-collector`: + +```yaml +livenessProbe: + exec: + command: ["agenteye-collector", "health"] +``` + +Das neue Image liefert **keinen** `agenteye`-Alias, sodass eine Probe, die weiterhin `agenteye` aufruft, fehlschlägt. Aktualisieren Sie die Probe im selben Rollout wie das neue Image. + +### Cron / manuelle Skripte + +Ersetzen Sie alle `agenteye start|flush|health`-Aufrufe durch den entsprechenden `agenteye-collector start|flush|health`-Befehl. **Löschen Sie alle `agenteye update`-Cron-Jobs**; dieser Unterbefehl existiert nicht mehr (siehe [Zukünftige Upgrades](#upgrades-from-now-on)). + +--- + +## 3. Das alte Binary entfernen (zuletzt) + +Sobald der Service auf `agenteye-collector` läuft und als gesund gemeldet wird: + +```bash +sudo rm /usr/local/bin/agenteye +``` + +Dies ist besonders wichtig, wenn Sie auch die AgentEye CLI verwenden, die ihren eigenen `agenteye`-Befehl installiert; das alte Collector-Binary unter `/usr/local/bin/agenteye` zu belassen würde den Namen `agenteye` auf Ihrem `PATH` mehrdeutig machen. + +--- + +## Zukünftige Upgrades + +Der Collector aktualisiert sich nicht mehr selbst. Für Upgrades gilt: + +- **Binary:** Laden Sie das neue Artefakt für Ihre Plattform herunter (z. B. `agenteye-collector-linux-x86_64`; die vollständige Liste finden Sie unter [Collector-Installation → Option A](/de/agenteye/collector-installation#option-a-binary-recommended)), ersetzen Sie `/usr/local/bin/agenteye-collector` und starten Sie den Service neu. +- **Docker:** `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (oder ein gepinnter `:v`-Tag, was bevorzugt wird; `:latest` existiert nur für stabile Releases) und den Container neu erstellen. + +`AGENTEYE_TOKEN` ist weiterhin erforderlich, um aus dem privaten Release-Repository herunterzuladen, aber der laufende Daemon benötigt ihn nicht mehr. + +--- + +## Überprüfung + +```bash +agenteye-collector --version # neues Binary ist im PATH +agenteye-collector health # Exit 0 = gesund +agenteye-collector flush # leert alle gepufferten Events und beendet sich sauber +``` + +Prüfen Sie dann, ob neue Events in Ihrem Dashboard erscheinen. + +--- + +## Rollback + +Die Migration ist nicht-destruktiv. Falls Sie ein Rollback benötigen, verweisen Sie Ihre Service-Definition zurück auf das alte Binary `/usr/local/bin/agenteye` (solange Sie es noch nicht entfernt haben) und starten Sie den Service neu. Der Event-Spool und die Konfiguration werden gemeinsam genutzt und sind nicht betroffen. + +--- + +## Fehlerbehebung + +| Symptom | Ursache | Lösung | +|---|---|---| +| `warning: the collector binary is now agenteye-collector …` bei jedem Aufruf | Das Binary wird unter dem alten Namen `agenteye` aufgerufen | Stattdessen `agenteye-collector` verwenden; Service-Dateien und Skripte aktualisieren. | +| systemd schlägt fehl: `.../agenteye: No such file or directory` | Das alte Binary wurde entfernt, bevor `ExecStart` aktualisiert wurde | `ExecStart=/usr/local/bin/agenteye-collector start` setzen, dann `sudo systemctl daemon-reload`. | +| Kubernetes-Pod crasht nach dem Image-Upgrade in einer Schleife | Liveness-Probe ruft weiterhin `agenteye` auf | Probe-Befehl auf `["agenteye-collector", "health"]` ändern. | +| `agenteye: command not found`, aber `agenteye-collector` funktioniert | Skripte/Aliases referenzieren noch den alten Namen | Diese auf `agenteye-collector` aktualisieren. | +| Das Ausführen von `agenteye` startet die CLI, nicht den Collector | Die AgentEye CLI ist installiert; sie besitzt `agenteye` | `agenteye-collector` für den Daemon verwenden und veraltete Collector-Binaries unter `/usr/local/bin/agenteye` entfernen. | \ No newline at end of file diff --git a/docs/de/agenteye/deployment.mdx b/docs/de/agenteye/deployment.mdx new file mode 100644 index 00000000..cc2e2b7c --- /dev/null +++ b/docs/de/agenteye/deployment.mdx @@ -0,0 +1,427 @@ +--- +title: "Deployment" +description: "AgentEye Deployment-Dokumentation." +--- + +Dieser Leitfaden behandelt das Deployment des AgentEye-Servers und -Dashboards in der Produktionsumgebung. + +--- + +## Architekturübersicht + +``` + [ KI-Agent-Maschinen ] [ Ihre Infrastruktur ] + + Python SDK + | schreibt JSONL +----------------------+ + v +--->| PostgreSQL 15+ | + agenteye-collector --HTTP--+ | | (relationale DB) | + | | +----------------------+ + v | + +--------+ | +----------------------+ + | Server |<------+--->| ClickHouse 24+ | + +--------+ | | (Events / Analytik) | + ^ | +----------------------+ + API | | + | | +----------------------+ + +-----------+ +- - >| Redis 7+ (optional) | + | Dashboard | +----------------------+ + +-----------+ +``` + +- **Server**: Rust-HTTP-Dienst; empfängt Event-Batches, schreibt sie nach ClickHouse und pflegt den relationalen Zustand in PostgreSQL. +- **Dashboard**: Next.js-Webanwendung; liest und schreibt ausschließlich über die Server-API. +- **agenteye-collector**: wird auf Agent-Maschinen deployed, nicht auf dem Server-Host. +- **Postgres 15+**: ERFORDERLICH. (In der Multi-Tenant-Version von 14 auf 15 angehoben; das Org-Membership-Schema verwendet einen spaltenbasierten `ON DELETE SET NULL`-Fremdschlüssel, der Postgres 15+ erfordert. Postgres vor dem Deployment dieser Version aktualisieren.) Speichert OLTP-Zustand: `api_keys`, `users`, `sessions`, `evaluation_jobs` (Warteschlange), `dashboards`, `saved_queries`, `otp_codes` sowie die Multi-Tenant-Tabellen `orgs`, `org_memberships`, `org_settings`. +- **ClickHouse 24+**: ERFORDERLICH. Der Analyse-Datenspeicher für jeden ingested Event. Engine: `ReplacingMergeTree`, nach Monat partitioniert, sortiert nach `(session_id, ts, dedup_key)`. Der Server verbindet sich über `CLICKHOUSE_URL`; die mitgelieferte `deploy/base/clickhouse/` enthält eine leistungsoptimierte Single-Node-Konfiguration. **Multi-Tenant-Anforderung:** Die mitgelieferte Konfiguration aktiviert SQL-Zugriffsverwaltung + `users_without_row_policies_can_read_rows=false`, damit der Server pro Organisation einen schreibgeschützten ClickHouse-Benutzer + eine Row Policy anlegen kann (die engine-seitig erzwungene Isolationsgrenze für den SQL-Editor und den KI-Agenten). Wenn Sie eine eigene ClickHouse-Konfiguration verwenden, übernehmen Sie diese Einstellungen (siehe `deploy/base/clickhouse/configmap.yaml`). +- **Redis 7+**: *optional* gemeinsamer Cache + Rate-Limit-Backend. Server und Dashboard verbinden sich beide über `REDIS_URL`. Fehlt Redis, degradieren beide graceful auf Postgres-only-Pfade. Siehe **Redis (optionaler Cache)** weiter unten. + +--- + +## Server + +### Image pullen + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +docker pull ghcr.io/agenteye-enterprise/server:beta-latest +``` + +> Aktuelle Builds werden unter `beta-latest` veröffentlicht; `latest` wird nur stabilen Releases zugewiesen. Für die Produktion empfiehlt sich ein konkreter `:v`-Tag; siehe [Verfügbare Image-Tags](#available-image-tags). + +### Umgebungsvariablen + +| Variable | Erforderlich | Standard | Beschreibung | +|---|---|---|---| +| `DATABASE_URL` | Ja | keiner | Postgres-DSN. Standard-libpq-Verbindungsstring mit Schema `postgres://`. Unterstützt `?sslmode=require` und andere libpq-Parameter. Das Passwort darf kein `/`, `+` oder `=` enthalten; zum Generieren URL-sicherer Passwörter `openssl rand -hex` verwenden. | +| `ADMIN_KEY` | Nein | keiner | Bootstrap-Admin-API-Schlüssel. Wird bei jedem Start mit allen Berechtigungen upsertet. Rotieren durch Ändern des Werts und Neustart. | +| `LISTEN_ADDR` | Nein | `0.0.0.0:8080` | TCP-Adresse zum Binden | +| `MAX_BODY_BYTES` | Nein | `134217728` (128 MB) | Maximale Request-Body-Größe | +| `ADMIN_EMAIL` | Nein | keiner | E-Mail des Bootstrap-Admin-Benutzers. Wird bei jedem Start mit allen Berechtigungen upsertet und als geschützt markiert: kann nicht deaktiviert oder in der Berechtigung über Dashboard/API geändert werden. Zum Rotieren des Bootstrap-Admins `ADMIN_EMAIL` ändern und neu starten; die neue E-Mail wird als geschützt upsertet, die bisherige behält ihren Schutz bis zur manuellen Bereinigung in der Datenbank. | +| `ALLOWED_EMAILS` | Nein | keiner (alle gesperrt) | Kommagetrennte Liste erlaubter E-Mails für die Benutzererstellung und den Login. Unterstützt exakte Adressen (`user@example.com`) und Domain-Wildcards (`*@example.com`). Wenn nicht gesetzt, können keine Benutzer erstellt werden oder sich anmelden. **Nur beim ersten Start**: Befüllt die Zulassungsliste der Standard-Org beim ersten Start; danach ist die Seite [`//settings`](#operational-settings) jeder Org die maßgebliche Quelle, und Änderungen dieser Umgebungsvariable haben keine Wirkung mehr. | +| `SMTP_HOST` | Nein | keiner | SMTP-Server-Hostname für den Versand von OTP-E-Mails. Wenn nicht gesetzt, werden OTP-Codes stattdessen auf stdout geloggt. | +| `SMTP_PORT` | Nein | `587` | SMTP-Server-Port | +| `SMTP_USERNAME` | Nein | keiner | SMTP-Authentifizierungs-Benutzername | +| `SMTP_PASSWORD` | Nein | keiner | SMTP-Authentifizierungs-Passwort | +| `SMTP_FROM` | Nein | keiner | Absender-E-Mail-Adresse für OTP-E-Mails | +| `SMTP_TLS` | Nein | STARTTLS | STARTTLS wird verwendet, sofern nicht explizit deaktiviert: `false` oder `0` sendet Klartext (kein TLS); jeder andere Wert – auch nicht gesetzt – aktiviert STARTTLS. | +| `DASHBOARD_URL` | Nein | interner Standard | Dashboard-Origin zum Aufbauen des OTP-E-Mail-Magic-Links und der Incident-Magic-Links in Alert-Benachrichtigungen. Wenn nicht gesetzt, wird auf einen internen Standard zurückgegriffen (und bei OTP auch auf den vom Dashboard abgeleiteten Request-Origin). Bei Split-Domain-Setups setzen, damit sowohl E-Mail- als auch Slack-/Incident-Links auf Ihr Dashboard zeigen. Siehe **E-Mail-Magic-Link-URL** weiter unten; die meisten Betreiber müssen dies nicht setzen. | +| `SESSION_TTL_SECS` | Nein | `86400` (24 Std.) | Dashboard-Sitzungsdauer in Sekunden. **Nur beim ersten Start**: Nach dem ersten Deployment pro Org über [`//settings`](#operational-settings) bearbeiten. | +| `OTP_TTL_SECS` | Nein | `600` (10 Min.) | OTP-Code-Gültigkeitsdauer in Sekunden. **Nur beim ersten Start**: Nach dem ersten Deployment pro Org über [`//settings`](#operational-settings) bearbeiten. | +| `REDIS_URL` | Nein | keiner | Optionales gemeinsames Cache- + Rate-Limit-Backend, z. B. `redis://redis:6379/0`. Wenn gesetzt, cached der Server authentifizierte API-Key-Lookups, das `/models`-Aggregat des Dashboards, die Sessions-Liste und das Env-List-Facet; außerdem wird das OTP-Request-Rate-Limiting von Postgres COUNT auf Redis INCR umgestellt. Wenn nicht gesetzt oder nicht erreichbar, läuft der Server ohne Cache (das OTP-Limit fällt auf Postgres zurück, alle anderen Cache-Aufrufe fallen auf die primäre Datenquelle zurück). Siehe **Redis (optionaler Cache)** weiter unten. | +| `CLICKHOUSE_URL` | **Ja** | keiner | Basis-URL der ClickHouse-Instanz, z. B. `http://clickhouse:8123`. Der Server wendet sein Events-Schema bei jedem Start auf diese Datenbank an und verweigert den Start, wenn ClickHouse nicht erreichbar ist. Siehe **ClickHouse (erforderlicher Analyse-Datenspeicher)** weiter unten. | +| `CLICKHOUSE_DATABASE` | Nein | `agenteye` | ClickHouse-Datenbankname (Schema). Der Server legt sie beim Start an, falls sie noch nicht existiert. | +| `ORG_CH_SECRET` | Nein (Single-Tenant) / **Ja (Multi-Org)** | Dev-Standard | HMAC-Schlüssel, aus dem das pro-Tenant ClickHouse-Passwort jeder Organisation abgeleitet wird. SQL-Editor und `run_query` des KI-Agenten werden als eigener schreibgeschützter ClickHouse-Benutzer der Org ausgeführt, dessen Row Policy die Tenant-Isolation in der Engine erzwingt. Single-Tenant-Deployments starten problemlos mit dem eingebauten Dev-Standard; **bevor eine zweite Org angelegt wird, MUSS ein starker, stabiler Wert gesetzt werden**, da das `agenteye-orgctl org create`-CLI die Ausführung auf dem eingebauten Dev-Standard verweigert. Ein Rotieren verwaist alle ClickHouse-Benutzer der Orgs bis zum nächsten Start, der sie automatisch neu provisioniert. Geheim halten und über alle Replikas hinweg unverändert lassen. Die Org-Provisionierung selbst ist Operator-only; siehe **Organisationen (Multi-Tenancy)** weiter unten. | +| `DEFAULT_ORG_NAME` | Nein | `Default` | Anzeigename, der für die eingebaute Standard-Org gesetzt wird. **Nur beim ersten Start**, und nur solange die Org noch ihre frisch migrierte generische Identität trägt; wird beim Start angewendet und danach ignoriert. Sobald Sie die Org umbenennen (`agenteye-orgctl org rename`), ist die Umbenennung maßgeblich und diese Umgebungsvariable hat keine weitere Wirkung. | +| `DEFAULT_ORG_SLUG` | Nein | `default` | URL-Slug für die eingebaute Standard-Org, der Dashboard-Pfad, unter dem sie erreichbar ist (`//…`). Gleiche Erststart-only-/Pristine-only-Semantik wie `DEFAULT_ORG_NAME`. Muss 1–40 Kleinbuchstaben und Ziffern mit einzelnen internen Bindestrichen sein und kein [reserviertes Wort](#organizations-multi-tenancy); ein ungültiger Wert wird ignoriert (die Org behält `default`). Ermöglicht einem Single-Tenant-Install, z. B. als `/acme` statt `/default` zu erscheinen, ohne einen Post-Deploy-CLI-Schritt. | +| `RUST_LOG` | Nein | `info` | Log-Ausführlichkeit (`debug`, `warn`, `error`, `agenteye_server=trace`) | +| `EVALUATOR_ENDPOINT` | Nein | keiner | Basis-URL Ihres Evaluator-Dienstes (z. B. `http://evaluator:9000`). Wenn nicht gesetzt, ist die gesamte Evaluation-Pipeline ein No-op; es werden keine Queue-Zeilen geschrieben und keine Worker gestartet. Siehe [Evaluation Suite](/de/agenteye/evaluation-suite). | +| `EVALUATOR_TOKEN` | Nein | keiner | Wird als `Authorization: Bearer ` an den Evaluator gesendet. **Muss dem gleichen Wert entsprechen, mit dem der Evaluator-Dienst konfiguriert ist.** Nur optional, wenn Ihr Evaluator ohne Token konfiguriert ist. | +| `EVALUATOR_WORKERS` | Nein | `2` | Parallelität: Anzahl der Worker-Tasks pro Server-Instanz, die Evaluierungen dispatchen. Kann sicher über mehrere horizontal skalierte Server hinweg betrieben werden. | +| `EVALUATOR_CLAIM_BATCH` | Nein | `4` | Maximale Anzahl von Evaluierungen, die ein einzelner Worker pro Tick beansprucht. Batches werden **gleichzeitig** dispatcht, sodass die Gesamtparallelität an Ihrem Evaluator-Endpunkt `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH` beträgt. | +| `EVALUATOR_POLL_IDLE_SECS` | Nein | `2` | Wie lange ein Worker zwischen Dispatch-Versuchen schläft, wenn nichts ansteht. | +| `EVALUATOR_POLLING_INTERVAL_SECS` | Nein | `10` | Letzter Fallback-Takt (Sekunden) für `GET /evaluate/{id}`-Polls, wenn der Evaluator weder `next_poll_secs` pro Antwort noch `default_poll_interval_secs` über `GET /config` zurückgibt. | +| `EVALUATOR_REQUEST_TIMEOUT_MS` | Nein | `30000` | Timeout pro HTTP-Request gegen den Evaluator (Millisekunden). | +| `EVALUATOR_MAX_ATTEMPTS` | Nein | `5` | Nach so vielen fehlgeschlagenen Versuchen wird eine Evaluierung als terminaler `error` (oder `timeout`, wenn die Fehler Request-Timeouts waren) aufgezeichnet. | +| `EVALUATOR_CONFIG_REFRESH_SECS` | Nein | `300` (5 Min.) | Wie oft der Server `GET /config` vom Evaluator neu abruft. | +| `EVALUATOR_MAX_POLL_DURATION_SECS` | Nein | `3600` (1 Std.) | Maximale Wanduhrzeittdauer, die eine Sitzung in der Polling-Queue verbleiben kann, bevor AgentEye sie als `timeout` beendet. Schützt vor einem Evaluator, der dauerhaft `pending` zurückgibt. | +| `ALERT_WORKERS` | Nein | `1` | Parallelität: Anzahl der Worker-Tasks pro Server-Instanz, die Alert-Regeln auswerten. Siehe [Alerts](/de/agenteye/alerts). | +| `ALERT_CLAIM_BATCH` | Nein | `16` | Maximale Anzahl von Alerts, die ein einzelner Worker pro Tick beansprucht. | +| `ALERT_POLL_IDLE_SECS` | Nein | `5` | Wie lange ein Alert-Worker schläft, wenn die Queue leer ist. | +| `ALERT_REQUEST_TIMEOUT_MS` | Nein | `15000` | Timeout pro Trigger-Evaluierung (ClickHouse-Abfragen + ausgehende Channel-HTTP-Anfragen). | +| `ALERT_MAX_ATTEMPTS` | Nein | `5` | Aufeinanderfolgende transiente Fehler, bevor ein Alert gemäß seinem normalen Takt statt mit exponentiellem Backoff neu eingeplant wird. | +| `AUDIT_WORKERS` | Nein | `1` | Parallelität: Anzahl der Worker-Tasks pro Server-Instanz, die Audits ausführen. Siehe [Audits](/de/agenteye/audits). | +| `AUDIT_CLAIM_BATCH` | Nein | `1` | Maximale Anzahl fälliger Audits, die ein einzelner Worker pro Tick beansprucht. Eine agentische Untersuchung ist eine lange Schleife, daher ist der Standard 1. | +| `AUDIT_POLL_IDLE_SECS` | Nein | `30` | Wie lange ein Audit-Worker schläft, wenn kein Audit fällig ist. | +| `AUDIT_REQUEST_TIMEOUT_MS` | Nein | `30000` | Timeout pro Policy-Abfrage gegen ClickHouse (Millisekunden). | +| `AUDIT_LLM_TIMEOUT_MS` | Nein | `1440000` | Timeout für den agentischen Untersuchungsaufruf an den KI-Assistenten-Dienst. Ein vollständiger Agent-Loop läuft mehrere Minuten; diesen Wert ÜBER dem eigenen `AGENTEYE_AUDIT_TIMEOUT_MS` des Agenten halten, damit der Agent seine Teilergebnisse zurückgibt, bevor der Server aufgibt. | +| `AUDIT_MAX_ATTEMPTS` | Nein | `5` | Aufeinanderfolgende transiente Fehler, bevor ein Audit gemäß seinem normalen Takt statt mit exponentiellem Backoff neu eingeplant wird. | +| `AGENTEYE_AGENT_URL` / `AGENTEYE_AGENT_TOKEN` | Nein | — | Die agentische Untersuchung des Audits ruft den KI-Assistenten-`agent`-Dienst auf und **nutzt dabei dieselbe Verbindung wie der Assistent** — daher müssen diese beiden Variablen auch auf dem **Server** gesetzt sein (die mitgelieferten Manifests/Compose tun dies). Beide gesetzt ⇒ Audits führen die KI-Untersuchung durch; eine davon nicht gesetzt ⇒ Audits laufen **nur mit Policy** (der deterministische SQL-Policy-Pass läuft trotzdem), unabhängig vom `llm_enabled`-Flag des einzelnen Audits. Der Agent muss außerdem ein LLM konfiguriert haben – siehe [assistant.md](/de/agenteye/assistant). | + +**KI-Assistenten-Dienst — Audit- und Sandbox-Einstellungen.** Die agentische Untersuchung und ihre In-Pod-Python-Sandbox werden auf dem **Agent-Dienst** (nicht dem Server) konfiguriert, alle mit dem Präfix `AGENTEYE_AUDIT_*` und alle optional: + +| Variable | Standard | Bedeutung | +|---|---|---| +| `AGENTEYE_AUDIT_MAX_STEPS` | `200` | Maximale Agent-Turns pro Untersuchung. | +| `AGENTEYE_AUDIT_TIMEOUT_MS` | `1200000` | Wanduhrzeit für eine Untersuchung (20 Min.). Muss **unter** dem `AUDIT_LLM_TIMEOUT_MS` des Servers bleiben. | +| `AGENTEYE_AUDIT_MAX_CONCURRENCY` | `1` | Gleichzeitige Untersuchungen pro Agent-Pod (getrennt vom Budget des Chat-Assistenten). | +| `AGENTEYE_AUDIT_SANDBOX_TIMEOUT_MS` / `_MEM_MB` / `_CPU_SECS` / `_OUTPUT_MAX_BYTES` / `_SCRIPT_MAX_BYTES` | `20000` / `768` / `10` / `64000` / `64000` | Limits pro Script für die Bubblewrap-Sandbox. | + +**Sandbox-Plattformanforderung.** Die Audit-Code-Sandbox führt das Python des Modells in einem Bubblewrap-Jail aus, das **unprivilegierte User-Namespaces** benötigt. Der Agent-Pod muss die `clone()`-Flags erlauben — `seccompProfile: Unconfined` (k8s) oder `security_opt: [seccomp:unconfined]` (Compose) am Agenten setzen. Wenn der Node-Kernel unprivilegierte User-Namespaces deaktiviert (z. B. bei manchen GKE-COS-Images), **schlägt der Sandbox-Preflight fehl und der Auditor degradiert automatisch auf SQL-only** — kein Fehler, nur ein `sandbox_available: false` am `/health`-Endpunkt des Agenten. + +### Starten + +`DATABASE_URL` und `CLICKHOUSE_URL` in Ihrer Umgebung setzen (der Server verweigert den Start ohne ClickHouse), dann in den Container übergeben: + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-server \ + -e DATABASE_URL="$DATABASE_URL" \ + -e CLICKHOUSE_URL="$CLICKHOUSE_URL" \ + -e ADMIN_KEY="$ADMIN_KEY" \ + -p 8080:8080 \ + ghcr.io/agenteye-enterprise/server:beta-latest +``` + +Der Server führt Datenbank-Migrationen beim Start automatisch durch; kein separater Migrationsschritt nötig. + +### Health-Check + +``` +GET /health # Liveness - gibt immer {"status":"ok"} zurück, sobald der Prozess läuft +GET /ready # Readiness - 200 wenn Postgres + ClickHouse erreichbar, sonst 503 +``` + +Keine Authentifizierung erforderlich. `/health` für **Liveness**-Probes und `/ready` für **Readiness**-/Load-Balancer-Probes verwenden. `/ready` prüft die Hard-Dependencies, ohne die der Server nicht funktioniert (Postgres + ClickHouse): Ein Server, der läuft aber seine Datenbank nicht erreichen kann, wird aus der Rotation genommen und als `NotReady` angezeigt; Redis wird gemeldet, schlägt aber nie die Readiness fehl. In den mitgelieferten Kubernetes-Manifests zeigt die Readiness-Probe bereits auf `/ready`, Liveness bleibt auf `/health`. Die vollständige Übersicht einschließlich optionalem Kubernetes-nativem Pod-Fehler-Alerting an Slack findet sich unter [enterprise-docs/health-monitoring.md](/de/agenteye/health-monitoring). + +### E-Mail-Magic-Link-URL + +OTP-Login-E-Mails enthalten einen **Dashboard öffnen**-Button mit einem einzigen Klick. Ein Klick darauf landet den Benutzer auf `/login?token=&email=
`; das Dashboard tauscht dieses Paar gegen eine Sitzung ein und leitet in die App weiter, ohne manuelle Code-Eingabe. Der Server ermittelt den Dashboard-Origin für den Link in drei Stufen: + +1. **`X-AgentEye-Dashboard-Url`-Header**: Wird automatisch vom `/api/auth/otp/request`-Proxy des Dashboards aus dessen eigenem öffentlichen Origin gesetzt. Bei einem Same-Origin-Deployment (Server und Dashboard teilen sich einen Host hinter einem Ingress, der Proxy-Header weiterleitet) **ist keine Konfiguration erforderlich**. +2. **`DASHBOARD_URL`-Umgebungsvariable**: Setzen, wenn Ihr Dashboard auf einem anderen Origin als dem erreichbar ist, den der OTP-Request-Endpunkt des Servers sieht (geteilte `api.example.com` / `app.example.com`), oder wenn Ihr Ingress den öffentlichen Host nicht in den Dashboard-Pod propagiert (sodass `request.nextUrl.origin` sonst auf eine Wildcard-Bind-Adresse wie `0.0.0.0:3000` auflösen würde). Beispiel: `DASHBOARD_URL=https://app.example.com`. +3. **Standard**: `https://app.befailproof.ai`, wird nur verwendet, wenn keines der oben genannten vorhanden ist. + +Der Header-Wert wird validiert: Nur `https://*`- und Loopback-Origins (`http://localhost*`, `http://127.0.0.1*`) werden akzeptiert; Wildcard-Bind-Adressen (`0.0.0.0`, `[::]`) werden auch mit `https://`-Schema abgelehnt. Alles andere fällt auf Stufe 2 zurück. + +Auf einem laufenden Cluster mit einem einzeiligen Befehl setzen; keine Datei, kein Kustomize-Rebuild nötig: + +```bash +kubectl set env deployment/server -n agenteye \ + DASHBOARD_URL=https://app.example.com +``` + +Dies löst ein Rollout aus; die neuen Pods übernehmen den Wert beim ersten Request. Beachten Sie, dass der Override nur auf dem Deployment liegt; ein nachfolgendes `kustomize build | kubectl apply` gegen das Overlay überschreibt ihn, sofern Sie nicht dieselbe Umgebungsvariable in Ihren `server-env.yaml`-Patch des Overlays aufnehmen. + +--- + +## Dashboard + +### Image pullen + +```bash +docker pull ghcr.io/agenteye-enterprise/dashboard:beta-latest +``` + +### Umgebungsvariablen + +| Variable | Erforderlich | Standard | Beschreibung | +|---|---|---|---| +| `AGENTEYE_SERVER_URL` | Ja | keiner | Basis-URL des Servers, z. B. `http://localhost:8080` | +| `AGENTEYE_API_KEY` | Ja | keiner | API-Schlüssel, mit dem sich das Dashboard beim Server authentifiziert. Benötigt alle Berechtigungen (Admin-Schlüssel empfohlen). | +| `AE_LOG_LEVEL` | Nein | `info` | Serverseitige Log-Ausführlichkeit: `debug`, `info`, `warn`, `error`. Auf `debug` setzen, um Upstream-Request-/Response-Zeilen und Session-Validierungs-Traces bei der Fehlersuche zu sehen. | +| `AE_LOG_JSON` | Nein | auto | `1` erzwingt JSON-per-Line-Ausgabe; `0` erzwingt menschenlesbare Ausgabe. Wenn nicht gesetzt, wird JSON automatisch aktiviert, wenn `NODE_ENV=production`. JSON wird in der Produktion empfohlen, damit Logs sauber mit `jq` oder einem Log-Aggregator geparst werden können. | +| `AE_ANALYTICS_DISABLED` | Nein | keiner | Auf `1`/`true` setzen, um die anonyme Produkt-Nutzungstelemetrie des Dashboards zu deaktivieren. Siehe [Telemetrie & Datenschutz](#telemetry--privacy) weiter unten. | +| `REDIS_URL` | Nein | keiner | Optionales gemeinsames Cache-Backend, z. B. `redis://redis:6379/0`. Wenn gesetzt, cached das Dashboard `validateSession()`-Ergebnisse über Replikas hinweg und teilt den Next.js-Fetch-Cache für Latenz-Aggregat-/Env-List-Proxy-Routen. Edge-seitige OTP-Request- und Verify-Rate-Limits nutzen Redis ebenfalls, wenn vorhanden (fail open bei Unerreichbarkeit; das serverseitige Limit ist der Sicherheits-Backstop). Siehe **Redis (optionaler Cache)** weiter unten. | +| `AGENTEYE_AGENT_URL` | Nein | keiner | Basis-URL des optionalen KI-Assistenten-`agent`-Dienstes, z. B. `http://agent:9100`. **Nicht gesetzt lassen, um den Assistenten vollständig auszublenden**: Im Dashboard erscheint dann keine Assistenten-Blase. Siehe [enterprise-docs/assistant.md](/de/agenteye/assistant). | +| `AGENTEYE_AGENT_TOKEN` | Nein | keiner | Gemeinsames Geheimnis, das das Dashboard dem `agent`-Dienst präsentiert. Muss dem auf dem Agenten konfigurierten `AGENTEYE_AGENT_TOKEN` entsprechen. Siehe [enterprise-docs/assistant.md](/de/agenteye/assistant). | + +### Starten + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-dashboard \ + -e AGENTEYE_SERVER_URL="http://your-server-host:8080" \ + -e AGENTEYE_API_KEY="$ADMIN_KEY" \ + -p 3000:3000 \ + ghcr.io/agenteye-enterprise/dashboard:beta-latest +``` + +### Telemetrie & Datenschutz + +Das Dashboard sendet **anonyme Produkt-Nutzungsanalysen** an den Analysedienst von Exosphere (PostHog): welche Dashboard-Seiten aufgerufen werden und einige UI-Aktionen wie das Erstellen eines API-Schlüssels oder das erneute Auswerten einer Sitzung. Dieses Nutzungssignal beeinflusst, welche Funktionen priorisiert werden. + +- **Es verlassen niemals Agent-, Sitzungs- oder Event-Daten Ihre Infrastruktur.** Nur die Dashboard-UI-Nutzung wird gemeldet. Seiten-URLs werden vor dem Senden von Kennungen bereinigt, und Betreiber werden nur durch eine opake interne ID identifiziert, niemals per E-Mail. +- Telemetrie ist **standardmäßig aktiviert**. Um sie vollständig zu deaktivieren, `AE_ANALYTICS_DISABLED=1` am Dashboard-Container setzen und neu starten. +- Analytics werden an den eigenen `/ingest`-Pfad des Dashboards gesendet, den das Dashboard als Reverse Proxy zu PostHog (`https://us.i.posthog.com`) weiterleitet. Durch First-Party-Requests werden diese nicht von Browser-Werbeblockern blockiert. Der **Dashboard-Container** benötigt ausgehenden Zugang zu PostHog; ist dieser blockiert, passiert bei der Telemetrie stillschweigend nichts, und das Dashboard ist nicht beeinträchtigt. + +--- + +## KI-Assistent (optional) + +Ein im Dashboard integrierter KI-Assistent ermöglicht es Ihrem Team, Fragen zu den Agentendaten in natürlicher Sprache zu stellen (Sitzungen zusammenfassen, SQL für den `/queries`-Editor entwerfen und gespeicherte Abfragen in Dashboard-Kacheln verwandeln), ohne das Dashboard zu verlassen. Er läuft als separater interner `agent`-Container (auf dem Claude Agents SDK), der nur vom Dashboard erreichbar ist, und bleibt **deaktiviert, bis Sie einen LLM-Endpunkt konfigurieren**. + +Um ihn zu aktivieren, setzen Sie auf dem `agent`-Dienst eine LLM-Verbindung (**Portkey** über `PORTKEY_API_KEY` + einen Model-Catalog-Slug `AGENTEYE_AGENT_MODEL=@/`, direktes Anthropic über `ANTHROPIC_API_KEY`, ein anderes Gateway über `ANTHROPIC_BASE_URL` oder Bedrock/Vertex), einen **dedizierten** Datenschlüssel und ein gemeinsames `AGENTEYE_AGENT_TOKEN`, das mit dem Dashboard übereinstimmt. Dashboard-Benutzer benötigen zusätzlich die Berechtigung `agent:use`. + +Den Datenschlüssel für den Assistenten müssen Sie nicht manuell erstellen: Wählen Sie ein zufälliges Geheimnis, setzen Sie es als `AGENTEYE_API_KEY` auf dem `agent` **und** als `AGENT_API_KEY` auf dem `server`, und der Server befüllt es beim Start mit einem festen Berechtigungssatz. Der Datenzugriff ist schreibgeschützt (`events:read`, `evaluations:read`, `dashboards:read`, `queries:read`), und er hält zusätzlich genehmigungspflichtige Authoring-Scopes (`dashboards:write`, `queries:write`, `queries:run`), damit er gespeicherte Abfragen entwerfen und validieren sowie Dashboard-Kacheln im Auftrag des Benutzers erstellen kann; der gesamte SQL-Zugriff läuft weiterhin über die schreibgeschützte ClickHouse-Rolle der Org, sodass dies erweitert, was der Assistent erstellen kann, nicht auf welche Daten er zugreifen kann. Die Scopes sind im Code festgelegt und können nicht durch Konfiguration erweitert werden. Dieser Schlüssel ist geschützt; er kann nicht über die API deaktiviert oder neu generiert werden, sondern nur durch Ändern des Werts und Neustart rotiert werden. Den Admin-/Dashboard-Schlüssel niemals dafür wiederverwenden. + +Die vollständige Einrichtung, die komplette Umgebungsvariablenreferenz, Telemetrie-Optionen und das Sicherheitsmodell finden sich in **[enterprise-docs/assistant.md](/de/agenteye/assistant)**. + +--- + +## ClickHouse (erforderlicher Analyse-Datenspeicher) + +ClickHouse hält Ihre Dashboards auch bei hohem Event-Volumen reaktionsschnell und ermöglicht es dem `/queries`-SQL-Editor, Events, Evaluierungen und Sitzungen in einem einzigen Datenspeicher zu verknüpfen. Es ist der erforderliche kanonische Speicher für jeden ingestierten Event, jedes terminale Evaluierungsergebnis und die abgeleiteten Per-Session-Aggregate. PostgreSQL hält die relationalen/mutablen Zustandstabellen (api_keys, users, otp_codes, evaluation_jobs, dashboards, saved_queries); die Analyse-Oberfläche liegt in ClickHouse, damit die Dashboard-Rollups und eigene SQL-Abfragen sie nativ scannen und verknüpfen können, ohne datenbanküberschreitende Round-Trips. Der Server verweigert den Start ohne `CLICKHOUSE_URL`. + +### Schema + +Drei ClickHouse-Objekte werden beim Server-Start erstellt, alle idempotent (`CREATE IF NOT EXISTS`): + +- **`agenteye.events`**: `ReplacingMergeTree(ingested_at)`, partitioniert nach `toYYYYMM(ts)`, sortiert nach `(session_id, ts, dedup_key)`. Doppelte Inserts (Collector-Retries) kollabieren zum Merge-Zeitpunkt auf eine einzige Zeile; der Server berechnet für jeden Event einen deterministischen SHA-256-`dedup_key`, sodass Retries sicher sind. +- **`agenteye.evaluations`**: `ReplacingMergeTree(ingested_at)`, partitioniert nach `toYYYYMM(finished_at)`, sortiert nach `(session_id, finished_at, dedup_key)`. Wird einmal pro terminalem Evaluierungsergebnis von der Evaluator-Pipeline geschrieben. Gleiches Dedup-Key-Modell wie bei `events`. +- **`agenteye.agent_sessions`**: ein **VIEW** über `agenteye.events`, keine physische Tabelle. Jede Spalte ist abgeleitet (`started_at = min(ts)`, `last_event_at = max(ts)`, `ended_at = max(if event_type='agent_end', ts, NULL)`, `event_count = count()` usw.). Kein Per-Event-Upsert und kein separates Backfill; der View spiegelt automatisch, was in `events` steht. + +Für die Rückwärtskompatibilität mit gespeicherten Abfragen, die `analytics.evaluations` / `analytics.sessions` referenzieren, erstellt der Server auch eine `analytics`-ClickHouse-Datenbank mit Views über die `agenteye.*`-Tabellen; `analytics.events`, `analytics.evaluations`, `analytics.agent_sessions`, `analytics.sessions` werden alle korrekt aufgelöst. + +### Konfiguration + +Das mitgelieferte docker-compose und `deploy/base/clickhouse/` liefern einen für AgentEyes Workload optimierten ClickHouse-Dienst: + +- 2 GiB angefordert / 4 GiB Limit Arbeitsspeicher im mitgelieferten Base-Overlay (dimensioniert für kleine POC-/Staging-Nodes); Produktionskunden sollten nach oben skalieren — der empfohlene Mindestwert ist 2c / 4Gi Request, 6c / 8Gi Limit. `max_server_memory_usage_to_ram_ratio=0.9` +- 5 GiB Mark-Cache + 8 GiB unkomprimierter Cache +- `background_pool_size=16`, `background_merges_mutations_concurrency_ratio=2` +- MergeTree: `parts_to_throw_insert=3000`, `parts_to_delay_insert=1500`, `non_replicated_deduplication_window=1000` +- `local_io_method=auto` (io_uring auf unterstützten Kernels) +- `fsync_metadata=0`: akzeptabel wegen At-least-once-Ingest + ReplacingMergeTree-Dedup +- `query_log` aktiviert mit 30-Tage-TTL; `query_thread_log` entfernt (bei hohem QPS teuer) +- `max_execution_time=30` für benutzerseitige Abfragen +- 100 GiB PVC im StatefulSet-Template (Kunden-Overlays SOLLTEN für die Produktion auf eine schnelle SSD-Storage-Klasse umgestellt werden) + +### Backups + +Ihr vollständiger Datensatz wird nächtlich in einem einzelnen wiederherstellbaren Archiv gesichert, sodass ein Cluster- oder Speicherverlust wiederherstellbar ist. ClickHouse wird automatisch durch den täglichen `agenteye-backup`-CronJob gesichert, der PostgreSQL und ClickHouse in einem Durchgang sichert. ClickHouse wird über seine HTTP-API ausgelesen: `agenteye.events` und `agenteye.evaluations` werden im ClickHouse-nativen Format gesichert (die Views und Row Policies werden beim Server-Start neu erstellt, daher sind die Tabellendaten das vollständige Bild) und zusammen mit dem Postgres-Dump in einem einzigen komprimierten Archiv gebündelt, das in Ihren Objektspeicher hochgeladen wird. + +Der Ziel-Bucket und die Cloud-Anmeldedaten werden pro Overlay konfiguriert. Informationen zur Upload-Konfiguration und zu Wiederherstellungsschritten finden sich im Abschnitt **Backups** von [enterprise-docs/kubernetes-deployment.md](/de/agenteye/kubernetes-deployment). + +--- + +## Redis (optionaler Cache) + +Redis ist ein **optionales** gemeinsames Cache- + Rate-Limit-Backend, das von Server und Dashboard genutzt wird. Mit deployed Redis und `REDIS_URL` auf beiden Diensten: + +- **Server** cached authentifizierte API-Key-Lookups, die `/events/environments`- + `/evaluations/environments`-Listen, das `/events/latency_aggregate`-Rollup (die schwerste Abfrage, die das Dashboard pollt), die `/sessions`-Liste und wechselt das OTP-Request-Rate-Limiting von Postgres `COUNT(*)` auf Redis `INCR + EXPIRE`. +- **Dashboard** cached `validateSession()`-Ergebnisse, damit die 10–20 authentifizierten API-Aufrufe eines typischen Seitenladevorgangs alle einen einzigen Upstream-Session-Check teilen. Es begrenzt auch OTP-Request und OTP-Verify am Dashboard-Edge per Rate Limit. + +**Beide Dienste degradieren graceful, wenn Redis nicht erreichbar ist.** Jeder Cache-Aufruf gibt innerhalb eines begrenzten Timeouts `Err` zurück, und der Aufrufer fällt auf die primäre Datenquelle zurück (Postgres auf dem Server, der Upstream-Rust-Server auf dem Dashboard). OTP-Rate-Limiting fällt auf dem Server auf den Postgres-`COUNT(*)`-Pfad zurück (die Sicherheitseigenschaft bleibt erhalten); das Edge-OTP-Limit des Dashboards schlägt fehl auf offen, während das serverseitige Limit weiterhin greift. Ein ausgefallenes Redis verschlechtert die Latenz, nicht die Korrektheit. + +### Konfiguration + +Das docker-compose-Bundle enthält bereits einen Redis-Dienst und verdrahtet `REDIS_URL=redis://redis:6379/0` in Server und Dashboard. Für einen externen Redis `REDIS_URL` auf Ihren Endpunkt setzen und den `redis`-Dienst aus der Compose-Datei entfernen. + +### Arbeitsspeicher + Persistenz + +Das mitgelieferte Redis-Image läuft mit `--appendonly yes --appendfsync everysec --maxmemory 256mb --maxmemory-policy allkeys-lru`. AOF-Persistenz bedeutet, dass der Cache Container-Neustarts überlebt; `everysec` ist die richtige Durability-/Performance-Balance, da der Verlust der letzten Sekunde an Cache-Schreibvorgängen harmlos ist. LRU-Eviction begrenzt das Arbeitsspeicherwachstum. + +### Wann Redis NICHT deployen + +- Single-Instance-Dev/QA. Die In-Process-Caches auf dem Server allein liefern bereits den Großteil des Per-Replica-Vorteils; Redis fügt das Cross-Replica-Sharing hinzu, das Single-Instance-Setups nicht benötigen. +- Air-Gapped-Installationen, bei denen der Betriebsaufwand für einen weiteren Dienst den Latenzgewinn überwiegt. + +--- + +## Docker Compose (empfohlen) + +Eine `docker-compose.yml` ist im Repository `agenteye-enterprise/releases` verfügbar. Sie startet Postgres, ClickHouse, Redis, den Server und das Dashboard mit einem einzigen Befehl. + +```bash +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download \ + --repo agenteye-enterprise/releases \ + --pattern 'docker-compose.yml' \ + --dir ./agenteye +cd agenteye +``` + +**Standardwerte über `.env` überschreiben:** + +``` +# URL-sichere Passwörter verwenden (keine /, +, oder =-Zeichen). +# Generieren mit: openssl rand -hex 24 +POSTGRES_PASSWORD=your-db-password +ADMIN_KEY=your-admin-secret + +# Dashboard-Authentifizierung +ADMIN_EMAIL=admin@yourcompany.com +ALLOWED_EMAILS=*@yourcompany.com + +# SMTP für OTP-E-Mails (weglassen, um OTP-Codes auf stdout zu loggen) +# SMTP_HOST=smtp.yourprovider.com +# SMTP_PORT=587 +# SMTP_USERNAME=your-smtp-user +# SMTP_PASSWORD=your-smtp-password +# SMTP_FROM=noreply@yourcompany.com + +RUST_LOG=info +``` + +```bash +docker compose up -d +``` + +**Stoppen (Daten-Volume bleibt erhalten):** + +```bash +docker compose down +``` + +**Stoppen und alle Daten löschen:** + +```bash +docker compose down -v +``` + +--- + +## Operative Einstellungen + +Eine kleine Gruppe operativer Konfigurationsschalter, die früher durch Umgebungsvariablen fixiert waren, ist jetzt pro Organisation über die **`//settings`**-Seite des Dashboards bearbeitbar; jede Org konfiguriert ihre eigenen. Änderungen treten innerhalb von Sekunden in Kraft, ohne Neustart und ohne erneutes Deployment. + +| Einstellung | Bootstrap-Umgebungsvariable | Beschreibung | +|---|---|---| +| Erlaubte Anmeldungen | `ALLOWED_EMAILS` | E-Mails (oder `*@domain.com`-Wildcards), die berechtigt sind, ein OTP zu erhalten und als Benutzer hinzugefügt zu werden | +| Standard-Benutzerberechtigungen | `DEFAULT_USER_PERMISSIONS` | Kommagetrennte Berechtigungs-Tokens, die vorausgewählt sind, wenn ein Admin **+ neuer Benutzer** öffnet. Jedes Token muss eine der unter [API-Key-Berechtigungen](/de/agenteye/api-keys) aufgelisteten Zeichenketten sein. Standardmäßig das `standard`-Preset: Nur-Lese-Zugriff plus die alltäglichen On-Call-Aktionen (Re-Evaluierungen auslösen, Abfragen ausführen, Incidents bestätigen, den Assistenten nutzen). | +| Sitzungsdauer | `SESSION_TTL_SECS` | Wie lange ein Dashboard-Login gültig bleibt, bevor eine erneute Authentifizierung erforderlich ist. Das Dashboard prüft die Upstream-Sitzung alle 5 Sekunden, sodass eine Berechtigungsaktualisierung unter `//users` beim nächsten Request des betroffenen Benutzers wirksam wird, ohne erneuten Login. | +| Einmalcode-Gültigkeitsdauer | `OTP_TTL_SECS` | Wie lange ein OTP/Magic-Link verwendbar bleibt | +| Alert-Benachrichtigungskanäle | `ALERTS_ENABLED_CHANNELS` | Kommagetrennte Liste von Kanal-Typen, die der Alert-Dispatcher verwenden darf: `email`, `slack`, `webhook`. Die Per-Alert-Konfiguration wird weiterhin unter `//alerts/` vorgenommen, aber der Dispatcher filtert jede ausgehende Zustellung durch diesen Satz; ein hier deaktivierter Kanal wird mit einer `skipped_disabled`-Audit-Zeile kurzgeschlossen. Der `dashboard`-Kanal (der lokale Audit-Insert) ist immer erlaubt. Standardmäßig alle drei aktiv. | + +### Wie der Bootstrap funktioniert + +Einstellungen werden pro Organisation in `org_settings` gespeichert. Beim ersten Start befüllt der Server die fehlenden Zeilen der Standard-Org aus der entsprechenden Umgebungsvariable (oder einem sinnvollen Standard, wenn die Umgebungsvariable nicht gesetzt ist). Danach **ist der gespeicherte Wert die maßgebliche Quelle und die Umgebungsvariable wird ignoriert**; das Ändern der Umgebungsvariable bei einem späteren Neustart hat keinen Einfluss auf den Wert einer aktiven Org, und weitere Orgs starten mit Standardwerten und konfigurieren ihre eigenen. + +Das bedeutet: + +- Für ein neues Deployment die Umgebungsvariablen wie oben angegeben setzen; die Standard-Org liest sie beim ersten Start. +- Um einen Wert später zu ändern, im Dashboard unter `//settings` einloggen und bearbeiten. Die Änderung wird innerhalb von Sekunden über alle Server-Replikas wirksam; kein Neustart nötig. +- Eine Start-Log-Zeile zeigt an, was gesetzt wurde und was bereits vorhanden war, sodass Sie bestätigen können, dass der Bootstrap wirksam war: + + ```text + INFO settings bootstrap: seeded default-org row key=allowed_sign_ins env_var=ALLOWED_EMAILS seeded_from_env=true + ``` + +#### Anmelde-Semantik über Organisationen hinweg + +Eine Sitzung und ein OTP sind global für den Benutzer, nicht für eine einzelne Org, daher gelten bei der Anmeldung zwei Regeln für die Per-Org-Einstellungen: + +- **Sitzungs-/OTP-Dauer**: Die strengste (kürzeste) Dauer unter den Orgs, zu denen der Benutzer gehört, gewinnt. +- **Erlaubte Anmeldungen**: Das Gate verknüpft die Zulassungsliste jeder Org mit der Org-Mitgliedschaft per ODER: Ein Benutzer darf ein OTP anfordern, wenn die Zulassungsliste irgendeiner Org seine E-Mail zulässt **oder** er bereits Mitglied einer Org ist. + +### Berechtigungen + +Der Zugriff auf eine `//settings`-Seite wird durch zwei Berechtigungen gesteuert: + +- `settings:read`: Seite und aktuelle Werte einsehen. +- `settings:write`: Änderungen speichern. + +Der Bootstrap-Admin-Benutzer (aus `ADMIN_EMAIL` gesetzt) erhält beide automatisch zusammen mit allen anderen Berechtigungen. Anderen Benutzern können sie bei Bedarf über `//users` gewährt werden. + +--- + +## Organisationen (Multi-Tenancy) + +Ein einzelnes Deployment kann mehrere isolierte **Organisationen** (Tenants) bedienen; jede Datenzeile gehört genau einer Org, und die Isolation wird in der Datenbank-Engine erzwungen. Ein Single-Tenant-Install benötigt hier nichts; alle Daten liegen in einer eingebauten `default`-Org. (Sie können dieser Org einen freundlicheren Namen und URL-Slug geben, sodass sie z. B. unter `/acme` statt `/default` erreichbar ist, indem Sie `DEFAULT_ORG_NAME` / `DEFAULT_ORG_SLUG` vor dem ersten Start setzen oder sie jederzeit mit `agenteye-orgctl org rename` umbenennen.) + +**Tenant-Provisionierung ist Operator-only.** Organisationen und ihre Mitgliedschaften werden mit der **`agenteye-orgctl`**-CLI erstellt und verwaltet, die **im Server-Image** (neben `agenteye-server`) mitgeliefert wird und **im bestehenden Server-Pod** läuft; es gibt **keinen separaten Pod/Job, keine HTTP-API und keinen Dashboard-Button**. Sie nutzt die `DATABASE_URL`, `CLICKHOUSE_URL` und `ORG_CH_SECRET` des Servers. + +```bash +# Docker Compose - in den laufenden Server-Dienst exec: +docker compose exec server agenteye-orgctl org create --slug acme --name "Acme Corp" +docker compose exec server agenteye-orgctl member add --org acme --email alice@acme.example --set admin + +# Kubernetes - in das laufende Server-Deployment exec: +kubectl -n agenteye exec deploy/server -- agenteye-orgctl org list +``` + +Verfügbare Verben: `org create | list | rename | delete | purge` und `member add | list | update | remove`, mit eingebauten Berechtigungs-Sets `admin`, `standard` und `read-only`. Hinzugefügte Mitglieder erhalten beim ersten Dashboard-Login ein OTP. + +**Vor dem Anlegen einer zweiten Org:** ein starkes, stabiles `ORG_CH_SECRET` setzen (der `org create`-Befehl verweigert die Ausführung auf dem eingebauten Dev-Standard) und sicherstellen, dass Postgres **15+** ist. **Unverändert:** Per-Org-API-Schlüssel werden weiterhin im Dashboard/API von Org-Mitgliedern erstellt; nur der Org-+Mitglieds-Lebenszyklus wurde in die CLI verschoben. Vollständige Befehlsreferenz und ein ausführliches Beispiel: **[enterprise-docs/tenant-management.md](/de/agenteye/tenant-management)**. + +--- + +## Context-Window-Füllung + +Jedes `model_response`-Event zeigt eine **Context-Fill-Pille** — Eingabe- plus Ausgabe-Token als Prozentsatz des Kontextfensters des jeweiligen Modells. Die Bänder sind `healthy` (0–24%), `watch` (25–49%), `compacting` (50–74%) und `reset context` (75–100%). AgentEye löst gängige Modell-IDs automatisch auf, sodass keine initiale Konfiguration erforderlich ist. + +Jedes Modell, das eine Organisation sendet, erscheint unter **Einstellungen → Modell-Kontextfenster**. Benutzer mit `settings:write` können dessen Fenster überschreiben oder ein privates/Proxy-Modell hinzufügen (0–1.000.000 Token); `0` bedeutet „unbekannt" und unterdrückt die Pille. Änderungen werden auf neu ingistierte Events angewendet. Benutzer mit `settings:read` können die Liste einsehen. + +Neue Events erhalten die Füllung ab dem Moment des Upgrades. Um auch **historische** Events (und die Per-Modell-Liste) für ein bestehendes Deployment zu befüllen, führen Sie das einmalige Backfill aus — es wird im Server-Image mitgeliefert (wie `agenteye-orgctl`) und läuft im bestehenden Server-Pod: + +```bash +# Vorschau (gibt die Pro-Org-Mutation aus, ändert nichts): +kubectl -n agenteye exec deploy/server -- agenteye-backfill-context-window --dry-run +# Anwenden: +kubectl -n agenteye exec deploy/server -- agenteye-backfill-context-window +# docker compose: +docker compose exec server agenteye-backfill-context-window +``` + +Es ist idempotent (sicher mehrfach ausführbar) und nutzt `DATABASE_URL` / `CLICKHOUSE_URL` / `REDIS_URL` aus dem Pod. Nach dem Bearbeiten von Modell-Fenstern erneut ausführen, wenn vorhandene Events neu berechnet werden sollen. + +--- + +## Produktionsüberlegungen + +- **Postgres**: Einen verwalteten Postgres-Dienst oder eine dedizierte Instanz mit regelmäßigen Backups verwenden. Die `DATABASE_URL` unterstützt alle Standard-libpq-Parameter, einschließlich `sslmode=require` für verschlüsselte Verbindungen. +- **TLS**: Server und Dashboard hinter einem Reverse Proxy (nginx, Caddy, Traefik) betreiben, der TLS terminiert. +- **Firewall**: Der Server-Port (Standard 8080) sollte nur von Collector-Maschinen und dem Dashboard-Host erreichbar sein, nicht vom öffentlichen Internet. +- **Admin-Schlüssel**: `ADMIN_KEY` auf ein starkes zufälliges Geheimnis setzen. Nach dem Bootstrap dedizierte Scoped-Keys für Collectors und das Dashboard erstellen, statt den Admin-Schlüssel überall zu verwenden. +- **Image-Tags**: In der Produktion auf die Version in Ihren Release-Manifests pinnen (z. B. `server:v0.0.1-beta.48`) statt eines Floating-Tags, um unbeabsichtigte Upgrades zu vermeiden. Aktuelle Beta-Builds werden unter `beta-latest` veröffentlicht; `latest` wird nur stabilen Releases zugewiesen. +- **Health-Monitoring**: Auf Kubernetes verwendet die Readiness-Probe `/ready` (Postgres- + ClickHouse-Erreichbarkeit), während Liveness auf `/health` bleibt. Für flotten-weites „Ist AgentEye selbst verfügbar?"-Alerting an Slack aktivieren Sie das optionale Robusta-Add-on; siehe [enterprise-docs/health-monitoring.md](/de/agenteye/health-monitoring). + +--- + +## Verfügbare Image-Tags + +| Tag | Beschreibung | +|-----|-------------| +| `latest` | Neuestes stabiles Release | +| `beta-latest` | Neuestes Pre-Release (Beta) | +| `v` | Gepinnte Version, z. B. `v0.0.1-beta.48` (für die Produktion empfohlen) | \ No newline at end of file diff --git a/docs/de/agenteye/evaluation-suite.mdx b/docs/de/agenteye/evaluation-suite.mdx new file mode 100644 index 00000000..7bf4b4ce --- /dev/null +++ b/docs/de/agenteye/evaluation-suite.mdx @@ -0,0 +1,357 @@ +--- +title: "Evaluation Suite" +description: "Dokumentation der AgentEye Evaluation Suite." +--- + +AgentEye bewertet abgeschlossene Agent-Sessions, indem das vollständige Event-Transkript per POST an einen **kundeneigenen Evaluator-Service** gesendet wird. Der Evaluator gibt Bewertungen entweder direkt zurück oder liefert eine `job_id`, über die AgentEye per Polling abfragt. Die Ergebnisse werden gespeichert und im Dashboard angezeigt. + +Dieser Leitfaden behandelt: + +1. Wie der Abschluss einer Session erkannt wird. +2. Den HTTP-Vertrag, den der Evaluator implementieren muss. +3. Die Konfiguration des AgentEye-Servers. +4. Die Anzeige von Ergebnissen. +5. Fehlerbehebung. + +Für das Python-Hilfspaket, das den Vertrag für Sie implementiert, siehe das +[`agenteye-evaluator`-Paket auf PyPI](https://pypi.org/project/agenteye-evaluator/). + +--- + +## Funktionsweise + +```text +ingest /events ──▶ AgentEye ──── POST /evaluate ────▶ Evaluator-Service + (agent_end) Server ◀──── done | pending ──── + │ + │ GET /evaluate/{job_id} ─────▶ + │ ◀──── done ────────────── + ▼ + evaluations (terminale Ergebnisse) +``` + +Wenn das AgentEye SDK ein `agent_end`-Event für eine Session ausgibt, plant der Server eine Evaluierung. Anschließend wird das vollständige Event-Transkript per POST an Ihren Evaluator-Service gesendet, der entweder: + +- **Das Ergebnis direkt zurückgibt** mit `{"status":"done", "scores":{...}, "reasoning":{...}, "summary":"..."}`. Das Ergebnis wird an die Evaluierungszeitachse der Session angehängt. `reasoning` und `summary` sind optional. +- **Verschiebt** mit `{"status":"pending", "job_id":"abc-123"}`. AgentEye ruft dann `GET {EVALUATOR_ENDPOINT}/evaluate/abc-123` ab, bis der Evaluator `{"status":"done", ...}` oder `{"status":"error", "error":"..."}` zurückgibt. + + Das Polling-Intervall ist pro Job konfigurierbar: Eine `pending`-Antwort kann `next_poll_secs` enthalten, um es zu überschreiben; andernfalls verwendet AgentEye den Wert `default_poll_interval_secs` aus `GET /config`; andernfalls fällt der Server auf `EVALUATOR_POLLING_INTERVAL_SECS` zurück (Standard: 10 s). Alle Werte werden auf [1 s, 1 h] begrenzt. + +Sessions, die nie ein `agent_end` ausgeben (z. B. bei einem abgestürzten Agent-Prozess), können ebenfalls erfasst werden: `GET /config` des Evaluators kann `{"inactivity_timeout_secs": 1800}` zurückgeben, und AgentEye evaluiert dann jede Session, die so lange inaktiv war. Setzen Sie das Feld auf `null` oder lassen Sie es weg, um diesen Fallback zu deaktivieren. + +Die Pipeline ist vollständig inaktiv, wenn `EVALUATOR_ENDPOINT` nicht gesetzt ist. + +Eine Session kann **im Laufe der Zeit mehrere terminale Evaluierungen ansammeln**: Jedes `agent_end`-Event (und jede manuelle Neubewertung über das Dashboard) hängt eine neue Evaluierungszeile an. Dies ist die unterstützte Methode zur Evaluierung einer fortgesetzten Konversation: Ein Benutzer beendet einen Agent, kommt später wieder, sendet weitere Events, beendet den Agent erneut, und eine zweite Evaluierung wird gegen das vollständig aktualisierte Transkript durchgeführt. Das Dashboard zeigt die aktuellste Evaluierung als Haupteintrag und die früheren als aufklappbare Zeitachse an. Während eine Evaluierung für eine Session läuft, werden weitere `agent_end`-Events für diese Session ignoriert; das nächste nach Abschluss der laufenden Evaluierung stellt wie gewohnt eine neue Evaluierung in die Warteschlange. + +Der Inaktivitäts-Fallback greift auch bei fortgesetzten Sessions: Wenn nach einer vorherigen terminalen Evaluierung neue Events eintreffen und die Session dann länger als `inactivity_timeout_secs` inaktiv bleibt, wird eine neue Evaluierung eingereiht. + +Vorübergehende Fehler (5xx, 429, Timeouts, Netzwerkfehler) werden mit exponentiellem Backoff bis zu `EVALUATOR_MAX_ATTEMPTS` wiederholt; 4xx-Antworten sind terminal. AgentEye kann sicher mit mehreren horizontal skalierten Server-Instanzen betrieben werden; die Arbeit wird so aufgeteilt, dass dieselbe Session niemals zweimal gleichzeitig verarbeitet wird. + +--- + +## HTTP-Vertrag + +Jede authentifizierte Route verwendet **Bearer-Token-Authentifizierung**. Derselbe Wert muss auf beiden Seiten konfiguriert sein: + +- AgentEye-Server: Umgebungsvariable `EVALUATOR_TOKEN` +- Evaluator-Service: identisch konfiguriert (das `agenteye-evaluator`-SDK liest `EVALUATOR_TOKEN` per Konvention) + +Wenn `EVALUATOR_TOKEN` nicht gesetzt ist, sendet der Server keinen `Authorization`-Header; der Evaluator kann dann anonyme Anfragen akzeptieren, was für ein rein internes Netzwerk akzeptabel, im öffentlichen Internet jedoch nicht empfohlen ist. + +### Routen, die der Evaluator bereitstellen muss + +| Route | Body / Parameter | Antwort | +|---|---|---| +| `GET /health` | keine | `{"status":"ok"}` (offen, keine Authentifizierung) | +| `GET /config` | keine | `{"inactivity_timeout_secs": \| null, "default_poll_interval_secs": \| omitted}` | +| `POST /evaluate` | `EvalRequest` JSON | `{"status":"done", ...}` oder `{"status":"pending", "job_id":"..."}` | +| `GET /evaluate/{id}` | keine | gleiche Antwortstruktur wie `/evaluate` | + +### `EvalRequest`-Body, der vom Server gesendet wird + +```json +{ + "schema_version": "1", + "session_id": "session-abc123", + "agent_id": "planner", + "environment": "production", + "started_at": "2026-05-10T12:00:00Z", + "ended_at": "2026-05-10T12:05:00Z", + "events": [ + { "id": 1234, "ts": "...", "event_type": "agent_start", "payload": { ... } }, + ... + ] +} +``` + +### Antwortstrukturen + +**Synchron (done):** + +```json +{ + "status": "done", + "scores": { "helpfulness": 0.85, "tool_efficiency": 0.6 }, + "reasoning": { + "helpfulness": "answered the question directly with citations", + "tool_efficiency": "called list_files three times when one would have done" + }, + "summary": "strong answer quality, weak tool selection" +} +``` + +`reasoning` (eine Begründungszuordnung pro Score) und `summary` (eine zusammenfassende Gesamtdarstellung) sind beide optional. Schlüssel in `reasoning` sollten die Schlüssel in `scores` widerspiegeln; das Dashboard zeigt jeden Eintrag direkt unter seinem Score-Balken an. Ältere Evaluatoren, die nur `scores` zurückgeben, funktionieren weiterhin unverändert; `reasoning` und `summary` werden dann als null gelesen, und die entsprechenden UI-Elemente werden ausgeblendet. + +**Asynchron (verschoben):** + +```json +{ "status": "pending", "job_id": "abc-123", "next_poll_secs": 30 } +``` + +`next_poll_secs` ist optional; wenn weggelassen, fällt der Server auf `default_poll_interval_secs` des Evaluators aus `/config` und dann auf seine eigene Umgebungsvariable `EVALUATOR_POLLING_INTERVAL_SECS` zurück. + +**Terminaler Fehler auf Evaluator-Seite:** + +```json +{ "status": "error", "error": "model service unavailable" } +``` + +Der Server behandelt jeden anderen 2xx-Body als Protokollfehler und zeichnet einen terminalen `error` für die Session auf. + +--- + +## Einen Evaluator mit dem SDK schreiben + +Das Python-Paket `agenteye-evaluator` bietet einen typisierten FastAPI-Wrapper, der den oben beschriebenen HTTP-Vertrag implementiert. Installieren Sie es von PyPI: + +```bash +pip install agenteye-evaluator +``` + +Minimaler Evaluator: + +```python +import os +from agenteye_evaluator import Evaluator, EvalRequest, EvalResponse + +app = Evaluator(token=os.environ["EVALUATOR_TOKEN"]) + +@app.evaluator +def run(req: EvalRequest) -> EvalResponse: + # Inspect req.events (the full session transcript) and return scores. + tool_calls = sum(1 for e in req.events if e.event_type == "tool_use") + return EvalResponse( + scores={"tool_calls": float(tool_calls)}, + reasoning={"tool_calls": f"{tool_calls} tool invocations in the transcript"}, + summary="tight tool loop" if tool_calls < 5 else "agent looped on tools", + ) +``` + +Die `app`-Instanz ist ASGI-kompatibel, sodass `uvicorn module:app` sie ausführt. + +Für Evaluatoren, die aufwändige Arbeit verschieben müssen, geben Sie stattdessen `JobPending` zurück und registrieren Sie einen `@app.job_lookup`-Handler; der AgentEye-Server ruft `GET /evaluate/{job_id}` ab, bis Sie einen terminalen Status zurückgeben oder die Grenze `EVALUATOR_MAX_POLL_DURATION_SECS` (Standard: 1 h) erreicht ist. + +Vollständige API-Referenz, asynchrones Muster und Event-Schema: Die `agenteye-evaluator`-README ist in jedem Release-Tarball auf der +[agenteye-enterprise-Releases-Seite](https://github.com/agenteye-enterprise/releases) enthalten oder auf der PyPI-Seite des Pakets lesbar. + +--- + +## Einen Evaluator auf Kubernetes betreiben + +Der Evaluator ist **Ihr Service**: AgentEye liefert keinen Standard-Evaluator-Container. Das Release enthält Referenz-Kubernetes-Manifeste unter `deploy/examples/evaluator/`, die Sie nach dem Austausch von Image und Bearer-Token direkt anwenden können. + +### 1. Evaluator containerisieren + +Ein minimales Dockerfile für Ihren Evaluator: + +```dockerfile +FROM python:3.12-slim +WORKDIR /app +RUN pip install --no-cache-dir agenteye-evaluator uvicorn +COPY my_evaluator.py . +RUN useradd --uid 10001 --create-home --shell /usr/sbin/nologin evaluator \ + && chown -R evaluator:evaluator /app +USER evaluator +EXPOSE 9000 +CMD ["uvicorn", "my_evaluator:app", "--host", "0.0.0.0", "--port", "9000"] +``` + +`runAsNonRoot` (UID 10001) stellt sicher, dass der Container mit den eingeschränkten Pod Security-Profilen kompatibel ist. + +### 2. Gemeinsamen Bearer-Token erstellen + +```bash +kubectl -n agenteye create secret generic evaluator-token \ + --from-literal=token="$(openssl rand -hex 32)" +``` + +Verwenden Sie denselben Wert als `EVALUATOR_TOKEN` auf dem AgentEye-Server. Der Server sendet bei jeder Anfrage `Authorization: Bearer `; das SDK verwendet `hmac.compare_digest` für eine zeitkonstante Prüfung und weist Abweichungen mit HTTP 401 ab. + +### 3. Beispiel-Manifeste anwenden + +```bash +# Passen Sie zunächst deploy/examples/evaluator/deployment.yaml an, +# um `image:` auf Ihre Registry zu verweisen, dann: +kubectl apply -k deploy/examples/evaluator/ +``` + +Das Beispiel enthält: + +- Ein 2-Replikat-Deployment mit `runAsNonRoot`, schreibgeschütztem Root-Dateisystem, entfernten Capabilities sowie Liveness- und Readiness-Prüfungen auf `/health` +- Einen ClusterIP-Service auf Port 9000 +- Eine `secret.example.yaml`-Vorlage (absichtlich aus der Kustomization ausgeschlossen; erstellen Sie das echte Secret außerhalb des Build-Prozesses, damit kein Token in Git landet) + +### 4. AgentEye damit verbinden + +Setzen Sie auf dem AgentEye-Server: + +```bash +EVALUATOR_ENDPOINT=http://evaluator:9000 +EVALUATOR_TOKEN= +``` + +Der Server verteilt `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH` gleichzeitige Anfragen auf alle Evaluator-Pods (Standardwerte: `2 × 4 = 8`). Skalieren Sie `replicas` und die Ressourcenlimits pro Pod im Einklang mit diesen serverseitigen Einstellungen. + +### Überprüfung + +```bash +kubectl -n agenteye port-forward svc/evaluator 9000:9000 +curl -s http://localhost:9000/health # → {"status":"ok"} +``` + +Nachdem ein Agent vollständig durchgelaufen ist, sollte `GET /evaluations` auf dem AgentEye-Server eine Zeile mit `status: "done"` und den von Ihrem Evaluator erzeugten Scores zurückgeben. + +--- + +## AgentEye-Server konfigurieren + +Setzen Sie folgendes auf dem Server-Prozess: + +| Umgebungsvariable | Bedeutung | +|---|---| +| `EVALUATOR_ENDPOINT` | Basis-URL Ihres Evaluators (`http://evaluator:9000`). Nicht gesetzt = Pipeline deaktiviert. | +| `EVALUATOR_TOKEN` | Bearer-Token. Muss mit dem Wert übereinstimmen, mit dem der Evaluator-Service konfiguriert ist. | +| `EVALUATOR_WORKERS` | Worker-Tasks pro Server-Instanz (Standard: 2). | +| `EVALUATOR_CLAIM_BATCH` | Zeilen, die pro Worker-Tick beansprucht werden (Standard: 4). Batches werden **gleichzeitig** verarbeitet; die effektive Parallelität an Ihrem Evaluator-Endpunkt beträgt `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH`. | +| `EVALUATOR_POLL_IDLE_SECS` | Wartezeit eines Workers zwischen Dispatch-Versuchen, wenn keine Evaluierung fällig ist (Standard: 2 s). | +| `EVALUATOR_POLLING_INTERVAL_SECS` | Letzter Fallback für das `GET /evaluate/{id}`-Intervall, wenn weder `next_poll_secs` aus der Antwort noch `default_poll_interval_secs` des Evaluators gesetzt ist (Standard: 10 s). | +| `EVALUATOR_REQUEST_TIMEOUT_MS` | Timeout pro Anfrage (Standard: 30000). | +| `EVALUATOR_MAX_ATTEMPTS` | Nach dieser Anzahl vorübergehender Fehler wird das Ergebnis als terminaler `error` gespeichert (Standard: 5). | +| `EVALUATOR_CONFIG_REFRESH_SECS` | Intervall für `GET /config` (Standard: 300). | +| `EVALUATOR_MAX_POLL_DURATION_SECS` | Maximale Echtzeit, die eine Session in der Polling-Warteschlange verbleiben darf, bevor sie als `timeout` beendet wird (Standard: 3600 s). Schützt vor einem Evaluator, der dauerhaft `pending` zurückgibt. | + +Um automatisches Scoring für die gesamte Instanz zu aktivieren, stellen Sie das `agenteye-evaluator`-Secret mit beiden gesetzten Schlüsseln bereit. In den mitgelieferten Kubernetes-Manifesten liest der Server `EVALUATOR_ENDPOINT` und `EVALUATOR_TOKEN` aus diesem optionalen Secret. Erstellen Sie es über den Standard-Secret-Management-Prozess Ihrer Organisation und starten Sie dann das Server-Deployment neu, um die Änderung zu übernehmen. + +Die oben genannten Konfigurationsparameter sind standardmäßig nicht verdrahtet; legen Sie die entsprechenden Umgebungsvariablen im Server-Container Ihres Deployment-Manifests fest, wenn Sie die Standardwerte überschreiben möchten. + +Siehe [deployment.md](/de/agenteye/deployment) für die vollständige Tabelle der Umgebungsvariablen. + +--- + +## API-Referenz + +| Methode | Pfad | Erforderliche Berechtigung | Zweck | +|---|---|---|---| +| `GET` | `/evaluations` | `evaluations:read` | Terminale Ergebnisse abfragen. Unterstützt `session_id`, `agent_id`, `environment`, `status` (`done`/`error`/`timeout`), `ts_from`, `ts_to`, `cursor`, `limit`, `score_filters`, `latest_per_session`. `limit` ist standardmäßig 50 und auf 200 begrenzt (abweichend von `/events`, das auf 1000 begrenzt ist). `environment` akzeptiert eine kommagetrennte Liste (z. B. `environment=prod,staging`); Einzelwerte funktionieren weiterhin. Mit `latest_per_session=true` enthält die Antwort höchstens eine Zeile pro `session_id` (die neueste nach `completed_at`), die von der Sessions-Listenseite verwendet wird, um die Evaluierungszeitachse einer Session auf ihren aktuellen Haupteintrag zu reduzieren. Standardmäßig false (gibt den vollständigen Verlauf zurück). | +| `GET` | `/evaluations/aggregate` | `evaluations:read` | Zusammengefasste Eval-Gesundheit für einen gefilterten Bereich: Gesamtanzahl, Aufschlüsselung nach done/error/timeout, statistiken pro Score-Schlüssel (Anzahl/Durchschnitt/Min/Max/P50 über beliebige `scores`-Schlüssel) und eine zeitbasierte Zeitachse. Akzeptiert **dieselben Filterparameter wie `/evaluations`** plus `featured_keys` (CSV der Score-Schlüssel für Trends) und `latest_per_session`. Wird von der Dashboards-Funktion genutzt; Metriken sind exakt über die gesamte Treffermenge, nicht gesampelt. | +| `GET` | `/evaluations/environments` | `evaluations:read` | Distinct-Umgebungswerte aus der `evaluations`-Tabelle. Wird verwendet, um Filter-Dropdowns zu befüllen, die auf evaluierungslesbare Daten beschränkt sind. | +| `GET` | `/evaluation-jobs` | `evaluations:read` | Einsicht in laufende Evaluierungen. Filtern nach `status` (`pending`/`polling`). | +| `GET` | `/events` | `events:read` | Rohe Events einer Session streamen. Unterstützt `session_id`, `agent_id`, `event_type` (CSV), `environment` (CSV), `ts_from`, `ts_to`, `cursor`, `limit` und `order`. `order` ist `desc` (neueste zuerst, Standard) oder `asc` (älteste zuerst); ein unbekannter Wert fällt auf `desc` zurück. Cursor-Paginierung über `next_cursor` der Antwort (eine Event-ID): übergeben Sie diesen als `cursor`, um die nächste Seite zu erhalten; bei `asc` sind das die Events nach dieser ID, bei `desc` die Events davor. `limit` ist standardmäßig 50 und auf 1000 begrenzt. | +| `GET` | `/sessions/:session_id/export` | `events:read` | Gibt den genauen JSON-Body zurück, den der Evaluator für diese Session erhalten würde, als herunterladbare Datei namens `session-.json`. Nützlich zum Wiedergeben von Produktions-Sessions durch `agenteye-evaluator` für Offline-Tests. Die Bytes sind byteidentisch mit dem, was die Evaluator-Pipeline sendet. | +| `POST` | `/sessions/:session_id/re-evaluate` | `evaluations:trigger` | Eine neue Evaluierung für eine Session in die Warteschlange stellen; wird unabhängig davon ausgeführt, ob eine frühere Evaluierung existiert. Das neue Ergebnis wird an die Evaluierungszeitachse der Session **angehängt**, anstatt das vorherige zu überschreiben, sodass frühere Scores als Verlauf sichtbar bleiben. Gibt `202` beim Einreihen zurück, `404` für eine unbekannte Session, `409` wenn eine Evaluierung bereits läuft. Verwenden Sie dies nach dem Deployment eines neuen Evaluators oder für Sessions, die nie `agent_end` ausgegeben haben. | + +### Nach Score-Bereich filtern: `score_filters` + +`GET /evaluations` akzeptiert einen optionalen `score_filters`-Parameter, der Ergebnisse nach numerischen Werten im `scores`-Objekt einschränkt. Der Parameter ist eine kommagetrennte Liste von `key:min..max`-Einträgen; beide Grenzen können weggelassen werden. Mehrere Einträge werden mit logischem UND verknüpft. Zeilen, bei denen der genannte Schlüssel fehlt oder nicht numerisch ist, werden ausgeschlossen. Eine Anfrage darf höchstens 20 Filtereinträge enthalten; bei Überschreitung wird HTTP 400 zurückgegeben. + +Beispiele: +```text +# helpfulness in [0.5, 0.8] +GET /evaluations?score_filters=helpfulness:0.5..0.8 + +# tool_efficiency höchstens 0.3 (keine Untergrenze) +GET /evaluations?score_filters=tool_efficiency:..0.3 + +# helpfulness >= 0.5 UND factuality >= 0.9 +GET /evaluations?score_filters=helpfulness:0.5..,factuality:0.9.. +``` + +Jedes `/evaluations`-Antwortobjekt enthält folgende Felder: + +| Feld | Typ | Hinweise | +|---|---|---| +| `evaluation_id` | string (UUID) | Der kanonische Bezeichner für diese terminale Evaluierung. Jede terminale Evaluierung erhält eine neue UUID; eine einzelne Session kann mehrere haben. | +| `id` | string (UUID) | Abwärtskompatibilitäts-Alias mit demselben Wert wie `evaluation_id`. | +| `session_id` | string | Die Session, gegen die diese Evaluierung durchgeführt wurde. Eine Session kann mehrere Evaluierungen in der Zeitachse haben. | +| `agent_id` | string | Identifiziert den Agent, der die Session erzeugt hat. | +| `environment` | string | Umgebungsbezeichnung, die aus der Session übernommen wird. | +| `status` | enum | Eines von `"done"`, `"error"`, `"timeout"`. | +| `scores` | object \| null | Scores, die von Ihrem Evaluator zurückgegeben wurden. | +| `reasoning` | object \| null | Optionale Begründungszuordnung pro Score, die von Ihrem Evaluator zurückgegeben wurde. Schlüssel spiegeln in der Regel die in `scores` wider. Das Dashboard zeigt jeden Eintrag unter seinem Score-Balken an. | +| `summary` | string \| null | Optionale zusammenfassende Gesamtdarstellung, die von Ihrem Evaluator zurückgegeben wurde. Das Dashboard zeigt diese über der Score-Aufschlüsselung als Hauptüberschrift der Evaluierung an. | +| `error` | string \| null | Nur bei `"error"` / `"timeout"` befüllt. | +| `attempt_count` | integer | Anzahl der Dispatch-Versuche (≥ 1). | +| `duration_ms` | integer \| null | Dauer des letzten Versuchs. | +| `completed_at` | string (ISO 8601 UTC) | Zeitpunkt, zu dem das terminale Ergebnis aufgezeichnet wurde. Ergebnisse sind nach `completed_at` sortiert (neueste zuerst). | +| `created_at` | string (ISO 8601 UTC) | Enthält denselben Zeitstempel wie `completed_at` (write-once-Semantik). | + +--- + +## Berechtigungen + +| Berechtigung | Gewährt | +|---|---| +| `evaluations:read` | Evaluierungsergebnisse auflisten, Scores im Dashboard anzeigen und Dashboard-Gesundheitsmetriken laden. | +| `evaluations:trigger` | Manuell eine Evaluierung für eine Session über `POST /sessions/:session_id/re-evaluate` oder die Schaltfläche zur Neubewertung im Dashboard in die Warteschlange stellen. | +| `dashboards:read` | Gespeicherte Dashboards anzeigen (benötigt zusätzlich `evaluations:read`, um deren Metriken zu laden). | +| `dashboards:write` | Dashboards erstellen und bearbeiten. | +| `dashboards:delete` | Dashboards löschen. | + +Der Bootstrap-Administrator (`ADMIN_KEY`, `ADMIN_EMAIL`) erhält diese Berechtigungen automatisch. + +--- + +## Ergebnisse anzeigen + +- **`/sessions/`**: Ereignis-Zeitachse und eine rechte Seitenleiste mit den Scores der Session sowie etwaigen Fehlern aus dem Dispatch-Versuch. Wenn Ihr Schlüssel `evaluations:trigger` hat, erscheint neben der Export-Schaltfläche eine **Neu bewerten**-Schaltfläche — nützlich für Sessions, die nie `agent_end` ausgegeben haben, oder zum Aktualisieren von Scores nach dem Deployment eines neuen Evaluators. Das Dashboard fragt nach dem neuen Ergebnis und aktualisiert die rechte Seitenleiste, sobald es vorliegt. +- **`/sessions`**: Filterbares Sessions-Raster; die Score-Spalte zeigt den Evaluierungsstatus und die Scores jeder Session auf einen Blick. +- **`/dashboards`**: Gespeicherte Eval-Gesundheitsansichten (siehe [Dashboards](#dashboards) unten). + +![Das Sessions-Raster mit Evaluierungsstatus-Pills pro Session und farbcodierten Score-Badges (helpfulness, factuality, tool_efficiency, safety, coherence)](/agenteye/images/sessions-list.png) + +*Das Sessions-Raster zeigt den Evaluierungsstatus und die Scores jedes Durchlaufs auf einen Blick; rote/gelbe/grüne Badges lassen niedrige Scores sofort ins Auge springen.* + +![Eine Session-Detailansicht mit den Evaluierungsscores und dem Dispatch-Status in der rechten Seitenleiste](/agenteye/images/session-detail.png) + +*Beim Öffnen einer Session werden die vollständige Zeitachse sowie die Evaluierungsscores und etwaige Dispatcher-Fehler in der rechten Seitenleiste angezeigt.* + +--- + +## Dashboards + +Die **Dashboards**-Seite (`/dashboards`) ermöglicht es Ihnen, eine Kombination aus Evaluierungsfiltern als benannte, wiederverwendbare Ansicht zu speichern und den Zustand dieses Evaluierungsausschnitts auf einen Blick zu beobachten. Dashboards werden **organisationsweit geteilt**; alle Personen mit `dashboards:read` sehen dieselbe Sammlung. + +Jedes Dashboard speichert: + +- **Filter**: dieselben Steuerelemente wie auf der Sessions-Seite: Umgebung, Status, Agent, ein rollierendes Zeitfenster und Score-Bereichsfilter (`key:min..max`). +- **Eine Anzeigekonfiguration**: welche Score-Schlüssel hervorgehoben werden sollen, die grünen/gelben/roten Gesundheitsschwellenwerte, welche Panels angezeigt werden und ob auf die neueste Evaluierung pro Session reduziert werden soll. + +Jede Karte zeigt die Anzahl der übereinstimmenden Sessions, eine Aufschlüsselung nach done/error/timeout, den Durchschnitt jedes hervorgehobenen Scores und ein kleines Trend-Sparkline. Beim Öffnen eines Dashboards werden die Panels in voller Größe angezeigt; **„In Sessions öffnen"** führt Sie zur Sessions-Seite mit vorgefiltertem Ausschnitt. Metriken werden serverseitig über den gesamten Trefferbereich berechnet (via `GET /evaluations/aggregate`), sodass die Zahlen exakt und nicht gesampelt sind. + +![Ein Eval-Gesundheits-Dashboard mit durchschnittlichen Score-Balken pro Evaluatordimension, einer Tool-ok-vs.-Fehler-Aufschlüsselung, Top-Tools und einem Events-pro-Stunde-Trend](/agenteye/images/dashboard-quality.png) + +**Berechtigungen:** Zum Anzeigen werden sowohl `dashboards:read` als auch `evaluations:read` benötigt; zum Erstellen und Bearbeiten `dashboards:write`; zum Löschen `dashboards:delete`. Der Bootstrap-Administrator erhält alle diese Berechtigungen automatisch. + +--- + +## Fehlerbehebung + +**Sessions sind vorhanden, aber es werden keine Evaluierungen erstellt.** Stellen Sie sicher, dass `EVALUATOR_ENDPOINT` auf dem Server-Prozess gesetzt ist, dass Server und Evaluator denselben `EVALUATOR_TOKEN`-Wert verwenden und dass der `/health`-Endpunkt des Evaluators vom Server aus erreichbar ist. Wenn `EVALUATOR_ENDPOINT` nicht gesetzt ist, ist die Pipeline inaktiv. + +**Laufende Evaluierungen häufen sich an.** Fragen Sie `GET /evaluation-jobs` ab, um die laufende Warteschlange einzusehen. Überprüfen Sie `attempt_count`, `next_attempt_at` und `last_error` in jeder Zeile. Häufige Ursachen: Evaluator-Service nicht erreichbar oder gibt 5xx zurück (wird mit Backoff wiederholt), falsches `EVALUATOR_TOKEN` (401 ist terminal) oder ein asynchroner Evaluator, der dauerhaft `pending` zurückgibt (siehe unten). + +**Sessions abgeschlossen, aber kein terminales Ergebnis.** Fragen Sie `GET /evaluation-jobs?status=polling` ab; das Ergebnis könnte noch in Bearbeitung sein. Wenn ein Job in `pending` feststeckt, hat der Server Schwierigkeiten, den Evaluator zu erreichen; überprüfen Sie, ob der Evaluator läuft und ob `EVALUATOR_TOKEN` übereinstimmt. + +**`HTTP 401 vom Evaluator: ungültiges Bearer-Token`.** Das `EVALUATOR_TOKEN` auf dem Server stimmt nicht mit dem Wert überein, mit dem der Evaluator-Service konfiguriert ist. Sie müssen identisch sein. + +**Asynchroner Evaluator gibt dauerhaft `pending` zurück.** Der Server fragt `GET /evaluate/{job_id}` ab, bis der Evaluator `done` oder `error` zurückgibt oder bis `EVALUATOR_MAX_POLL_DURATION_SECS` (Standard: 1 h) abläuft. Nach Erreichen des Limits wird die Evaluierung als `timeout` aufgezeichnet und aus der laufenden Warteschlange entfernt. Erhöhen Sie `EVALUATOR_MAX_POLL_DURATION_SECS`, wenn Ihr Evaluator legitim länger als den Standardwert benötigt. \ No newline at end of file diff --git a/docs/de/agenteye/getting-started.mdx b/docs/de/agenteye/getting-started.mdx new file mode 100644 index 00000000..35665e34 --- /dev/null +++ b/docs/de/agenteye/getting-started.mdx @@ -0,0 +1,235 @@ +--- +title: "Erste Schritte mit AgentEye" +description: "AgentEye – Dokumentation für den Einstieg." +--- + + +Diese Anleitung führt Sie durch die vollständige AgentEye-Einrichtung: Server und Dashboard bereitstellen, den Collector auf einem Agent-Rechner installieren und Ihren Python-Agent-Code instrumentieren. + +--- + +## Was ist AgentEye? + +AgentEye ist eine **selbst gehostete Observability- und Evaluierungsplattform für KI-Agenten**. Sie zeichnet auf, was Ihre Agenten tun – jeden Schritt eines Durchlaufs – und bewertet automatisch die Qualität jedes abgeschlossenen Durchlaufs. So können Sie sehen, wie sich Ihre Agenten in der Produktion verhalten, und Regressionen erkennen, bevor Ihre Nutzer davon betroffen sind. + +Die Daten fließen in eine Richtung: Ihr Agent-Code sendet **Events** über das **Python SDK** → ein schlanker **Collector**-Daemon bündelt und übermittelt sie an den **Server** → Events und Analysen werden in **ClickHouse** gespeichert (operativer Zustand wie Organisationen, Nutzer, API-Keys, Dashboards und gespeicherte Abfragen liegt in **Postgres**) → Sie erkunden alles im **Dashboard**. + +Was Sie erhalten: + +- **Events** – der rohe, schrittweise Verlauf jedes Agenten-Durchlaufs (Tool-Aufrufe, Modell-Aufrufe, Hooks, Fehler). +- **Sessions** – diese Events zu einer Zeile pro Durchlauf zusammengefasst, jede **automatisch ausgewertet** und bewertet. +- **Evaluierungen** – Qualitätsbewertungen, die von Ihren eigenen Evaluator-Diensten erzeugt werden, sodass Qualitätseinbrüche ohne manuellen Review sichtbar werden. +- **Abfragen & Dashboards** – gespeicherte ClickHouse-SQL-Abfragen über Ihre Daten, als geteilte, organisationsweite Dashboards dargestellt. +- **Alerts & Incidents** – Schwellenwertregeln, die Sie benachrichtigen (E-Mail, Slack, Webhook, im Dashboard), plus ein Incident-Workflow zur Triage. +- **CLI & KI-Assistent** – ein Terminal-Client (`agenteye`) und ein Dashboard-Assistent, mit dem Sie Fragen in natürlicher Sprache stellen können. + +Sie betreiben alles in Ihrer eigenen Infrastruktur – als einzelner Docker Compose-Stack (diese Anleitung), als produktionsreife Kubernetes-Installation oder als einzelner co-located Pod. Der Rest dieser Anleitung richtet den Compose-Stack von Anfang bis Ende ein. + +--- + +## Schritt 1: Authentifizierung + +Alle AgentEye-Artefakte werden über die GitHub-Organisation `agenteye-enterprise` bereitgestellt. Als Enterprise-Entwickler können Sie einen eigenen GitHub PAT generieren. Folgen Sie [enterprise-docs/github-token.md](/de/agenteye/github-token) für genaue Schritte und erforderliche Berechtigungen. + +```bash +export AGENTEYE_TOKEN= + +# Authenticate Docker against GHCR +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +--- + +## Schritt 2: Server und Dashboard bereitstellen + +Der Server empfängt Events von Collectors und macht sie abfragbar; das Dashboard ist der Ort, an dem Sie sie erkunden. Eingehende Events und Analysen werden in ClickHouse gespeichert (dem erforderlichen Analytics-Store), während Postgres den operativen Zustand wie Organisationen, Nutzer, API-Keys, Dashboards und gespeicherte Abfragen hält. + +**Compose-Datei herunterladen:** + +```bash +mkdir -p ./agenteye +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + https://raw.githubusercontent.com/agenteye-enterprise/releases/main/docker-compose.yml \ + -o ./agenteye/docker-compose.yml +cd agenteye +``` + +**Geheimnisse festlegen:** + +Erstellen Sie eine `.env`-Datei, damit das Deployment nicht mit den Standard-`admin`-Zugangsdaten läuft. Mindestens `ADMIN_KEY` und `POSTGRES_PASSWORD` müssen gesetzt werden: + +```bash +POSTGRES_PASSWORD=your-db-password +ADMIN_KEY=your-admin-secret +``` + +Exportieren Sie `ADMIN_KEY` auch in Ihrer aktuellen Shell, damit spätere Schritte (z. B. das `curl` in Schritt 3) direkt darauf zugreifen können: + +```bash +export ADMIN_KEY=your-admin-secret +``` + +**Stack starten:** + +```bash +docker compose up -d +``` + +Dies startet den vollständigen Stack, einschließlich des erforderlichen ClickHouse-Analytics-Stores und eines optionalen Redis-Caches, zusammen mit Server und Dashboard. ClickHouse muss gesund sein, damit der Server startet. + +Der Server hört nun unter `http://localhost:8080` und das Dashboard unter `http://localhost:3000`. + +Für Produktionsdeployments (eigenes Postgres, TLS, Reverse Proxy) siehe [enterprise-docs/deployment.md](/de/agenteye/deployment). + +--- + +## Schritt 3: API-Key für den Collector erstellen + +Jeder Collector authentifiziert sich mit einem scoped API-Key. Verwenden Sie den in Schritt 2 gesetzten `ADMIN_KEY`, um einen zu erstellen: + +```bash +curl -s -X POST http://localhost:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{"name":"prod-collector","key":"your-collector-secret","permissions":["events:add"]}' +``` + +Den `key`-Wert legen Sie selbst fest; verwenden Sie ihn in der Collector-Konfiguration in Schritt 4. Siehe [enterprise-docs/api-keys.md](/de/agenteye/api-keys) für die vollständige Key-Verwaltung. + +--- + +## Schritt 4: Collector installieren + +Installieren Sie den Collector-Daemon auf jedem Rechner, auf dem Ihre KI-Agenten laufen. + +**Binärdatei herunterladen (Linux x86_64):** + +```bash +VERSION=0.0.1-beta.13 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "collector/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-collector-linux-x86_64' +chmod +x agenteye-collector-linux-x86_64 +sudo mv agenteye-collector-linux-x86_64 /usr/local/bin/agenteye-collector +``` + +> Dies lädt den **Linux x86_64**-Build herunter. Für macOS (Apple Silicon oder Intel), Linux arm64 oder Docker/systemd/launchd-Setup siehe [collector-installation.md](/de/agenteye/collector-installation), das den Download für jede Plattform auflistet – der obige Befehl installiert eine Linux-Binärdatei, die auf anderen Plattformen nicht funktioniert. + +**Konfigurieren:** + +```bash +mkdir -p ~/.agenteye +cat > ~/.agenteye/config.json </…`). + +- **Abfragen** (`//queries`): Starten Sie mit einer Bibliothek gespeicherter, wiederverwendbarer Abfragen über Ihre Events und Evaluierungen (integrierte Vorlagen plus eigene)… + +![Die Bibliothek gespeicherter Abfragen: ein Raster wiederverwendbarer Abfragen, sowohl integrierte Vorlagen als auch eigene](/agenteye/images/queries.png) + + …öffnen Sie dann eine im SQL-Composer, um sie anzupassen und mit Live-Ergebnissen auszuführen: + +![Der SQL-Abfrage-Composer, der eine gespeicherte Abfrage ausführt, mit Schema-Seitenleiste und Live-Ergebnisraster](/agenteye/images/query-lab.png) + +- **Dashboards** (`//dashboards`): Heften Sie Abfragen als Linien-, Balken-, Flächen- oder Kreisdiagramm-Kacheln an geteilte, organisationsweite Dashboards. + +![Ein aus gespeicherten Abfragen erstelltes Dashboard: eine Events-pro-Stunde-Linie, ein Fehler-nach-Typ-Balkendiagramm, ein Latenz-Flächendiagramm und Tokens nach Modell](/agenteye/images/dashboard-fleet.png) + +- **Alerts** (`//alerts`): Erheben Sie beliebige Schwellenwerte zu Benachrichtigungsregeln, die per E-Mail, Slack, Webhook oder im Dashboard informieren. Siehe [enterprise-docs/alerts.md](/de/agenteye/alerts). + +--- + +## Nächste Schritte + +- [Deployment](/de/agenteye/deployment): Produktionsreife Absicherung +- [API Keys](/de/agenteye/api-keys): Zugriff verwalten +- [Troubleshooting](/de/agenteye/troubleshooting): Probleme diagnostizieren \ No newline at end of file diff --git a/docs/de/agenteye/github-token.mdx b/docs/de/agenteye/github-token.mdx new file mode 100644 index 00000000..1c278f37 --- /dev/null +++ b/docs/de/agenteye/github-token.mdx @@ -0,0 +1,131 @@ +--- +title: "GitHub Token Setup" +description: "AgentEye GitHub Token Setup Dokumentation." +--- + +Ein GitHub Personal Access Token (PAT) ist die einzige Zugangsdaten, die alle AgentEye-Artefakte freischaltet. Mit einem einzigen Token können Sie Docker-Images abrufen, Release-Binärdateien herunterladen und Python-Wheels installieren – ohne separate Anmeldungen für einzelne Komponenten und ohne gemeinsam genutzte Secrets, die weitergegeben werden müssen. Alle AgentEye-Artefakte werden über die GitHub-Organisation `agenteye-enterprise` verteilt. Sobald Ihrer Organisation Zugriff gewährt wurde, generiert und rotiert jeder Entwickler oder Operator sein eigenes Token, sodass der Zugriff pro Person nachvollziehbar und widerrufbar bleibt. + +Setzen Sie das Token einmalig pro Maschine als Umgebungsvariable und Docker-Credential: + +```bash +export AGENTEYE_TOKEN= +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +> **Hinweis zum Benutzernamen:** GHCR ignoriert den bei `docker login` angegebenen Benutzernamen und authentifiziert ausschließlich anhand des Tokens – daher funktioniert jeder nicht leere Wert. In dieser Dokumentation wird der Kürze halber `-u x` verwendet. Deployment-Manifeste, die ein Kubernetes-Image-Pull-Secret erstellen, können einen aussagekräftigeren Benutzernamen wie `agenteye-enterprise` verwenden. Beides wird akzeptiert. + +--- + +## Option A: Klassisches Token (Empfohlen) + +Ein klassisches Token ist die zuverlässigste Wahl für AgentEye, da der `docker login`- und Image-Pull-Ablauf von GHCR klassische Tokens am breitesten und konsistentesten unterstützt. Zwei Berechtigungsbereiche decken alles ab, was Sie benötigen (Images abrufen und Release-Assets herunterladen), sodass Sie sich einmalig authentifizieren und ohne Troubleshooting von Registry-Eigenheiten weitermachen können. Einer davon, `read:packages`, ist tatsächlich nur lesend; der andere, `repo`, ist der einzige klassische Bereich, der Zugriff auf private Release-Assets gewährt, und er ist bewusst weit gefasst – GitHub definiert ihn als vollständige Kontrolle (Lesen und Schreiben) über private Repositories. + +### 1. Token erstellen + +Navigieren Sie zu **GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic) → Generate new token (classic)**. + +| Feld | Wert | +|---|---| +| **Note** | `agenteye-` (z. B. `agenteye-prod-server`) | +| **Expiration** | Setzen Sie ein Ablaufdatum entsprechend Ihrer Sicherheitsrichtlinie; 90 Tage sind ein sinnvoller Standardwert | + +> **Hinweis zur Bezeichnung:** GitHub nennt dieses Feld **Note** bei klassischen Tokens und **Token name** bei fein abgestuften Tokens. Beide dienen demselben Zweck: ein für Menschen lesbarer Bezeichner zur späteren Überprüfung und zum Widerruf. + +### 2. Berechtigungsbereiche auswählen + +| Bereich | Warum er benötigt wird | +|---|---| +| `read:packages` | Docker-Images von `ghcr.io/agenteye-enterprise/` abrufen und Paket-Assets herunterladen | +| `repo` | Private Repository-Inhalte, Rohdateien und Release-Assets von `agenteye-enterprise/releases` lesen. Dies ist GitHubs weitgefasster Bereich "Full control of private repositories" (Lesen und Schreiben), kein nur lesender Bereich – er ist schlicht der einzige klassische Bereich, der Zugriff auf private Release-Assets gewährt | + +Keine weiteren Bereiche sind erforderlich. + +### 3. Token generieren und kopieren + +Klicken Sie auf **Generate token** und kopieren Sie den Wert sofort – er wird nur einmal angezeigt. Speichern Sie ihn in Ihrem Secret-Manager oder Ihrer Umgebung. + +--- + +## Option B: Fein abgestuftes Token (Fine-Grained Token) + +Fein abgestufte Tokens begrenzen den Zugriff auf bestimmte Repositories und Berechtigungen und stellen damit die strikteste Option mit geringstem Rechteprinzip dar. Wählen Sie diesen Weg, wenn die Sicherheitsrichtlinie Ihrer Organisation fein abgestufte Tokens vorschreibt. + +> **Hinweis:** Die GHCR-Unterstützung für fein abgestufte Tokens ist weniger konsistent als für klassische Tokens. Wenn `docker login` oder `docker pull` nach diesen Schritten fehlschlägt, verwenden Sie stattdessen ein klassisches Token (Option A). + +### 1. Token erstellen + +Navigieren Sie zu **GitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokens → Generate new token**. + +| Feld | Wert | +|---|---| +| **Token name** | `agenteye-` (z. B. `agenteye-prod-server`) | +| **Expiration** | Setzen Sie ein Ablaufdatum entsprechend Ihrer Sicherheitsrichtlinie; 90 Tage sind ein sinnvoller Standardwert | +| **Resource owner** | `agenteye-enterprise` | +| **Repository access** | **Only select repositories** → `agenteye-enterprise/releases` | + +### 2. Repository-Berechtigungen setzen + +Unter **Permissions → Repository permissions** setzen Sie: + +| Berechtigung | Zugriff | +|---|---| +| **Contents** | Read-only | +| **Packages** | Read-only | + +Alle anderen Berechtigungen können auf **No access** belassen werden. + +> **Hinweis:** Falls die Container-Images (`ghcr.io/agenteye-enterprise/...`) als organisationsweite Pakete statt als repository-verknüpfte Pakete veröffentlicht sind, schlägt der Docker-Login möglicherweise mit ausschließlich repository-bezogenen Berechtigungen fehl. Fügen Sie in diesem Fall eine Berechtigung auf Organisationsebene hinzu: **Permissions → Organization permissions → Packages: Read-only**. + +### 3. Was jede Berechtigung gewährt + +| Berechtigung | Verwendungszweck | +|---|---| +| Contents: Read-only | Herunterladen von `docker-compose.yml`, Release-Binärdateien und Python-Wheels aus `agenteye-enterprise/releases` | +| Packages: Read-only | Abrufen von Docker-Images von `ghcr.io/agenteye-enterprise/` | + +### 4. Token generieren und kopieren + +Klicken Sie auf **Generate token** und kopieren Sie den Wert sofort – er wird nur einmal angezeigt. Speichern Sie ihn in Ihrem Secret-Manager oder Ihrer Umgebung. + +--- + +## Token rotieren + +Das regelmäßige Rotieren von Tokens hält den Zugriff nachvollziehbar und begrenzt den Schaden, falls ein Credential jemals kompromittiert werden sollte. Tokens können auch jederzeit ablaufen oder widerrufen werden, daher ist die Rotation der übliche Weg, um authentifiziert zu bleiben. Zum Rotieren: + +1. Generieren Sie ein neues Token anhand der obigen Schritte. +2. Aktualisieren Sie `AGENTEYE_TOKEN` in Ihrer Umgebung oder Ihrem Secret-Manager. +3. Docker neu authentifizieren: `echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin` +4. Widerrufen Sie das alte Token unter GitHub → Settings → Developer settings → Personal access tokens, öffnen Sie dann die Unterseite **Tokens (classic)** oder **Fine-grained tokens** entsprechend dem Token-Typ und löschen Sie es. + +--- + +## Token überprüfen + +Bestätigen Sie, dass das Token funktioniert, bevor Sie es in ein Deployment einbinden, damit Authentifizierungsfehler hier und nicht mitten im Rollout auftreten. Jeder Befehl prüft einen der oben genannten Bereiche: + +```bash +# Packages scope - Docker gegen GHCR authentifizieren +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin + +# Contents scope - eine Release-Rohdatei abrufen +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + https://raw.githubusercontent.com/agenteye-enterprise/releases/main/docker-compose.yml \ + -o /tmp/agenteye-compose-check.yml +``` + +Ein erfolgreicher `docker login` bestätigt den Packages-Bereich; eine heruntergeladene Datei bestätigt den Contents-Bereich. + +--- + +## Fehlerbehebung + +| Symptom | Wahrscheinliche Ursache | Lösung | +|---|---|---| +| `docker login` gibt 401 zurück | Token fehlt `Packages: Read-only` (fein abgestuft) oder `read:packages` (klassisch) | Paketbereich hinzufügen und neu generieren | +| `curl` gibt 404 für GitHub-Raw-URLs zurück | Token fehlt `Contents: Read-only` oder `repo`-Bereich | Contents-Bereich hinzufügen und neu generieren | +| `gh release download` gibt 403 zurück | Token ist nicht für `agenteye-enterprise/releases` autorisiert | Prüfen Sie, ob das Repository im Repository-Zugriff des fein abgestuften Tokens enthalten ist, oder verwenden Sie ein klassisches Token mit `repo`-Bereich | +| Token akzeptiert, aber Images nicht gefunden | Organisationsweite Paketberechtigung fehlt beim fein abgestuften Token | Berechtigung `Packages: Read-only` auf Organisationsebene hinzufügen | + +Bei Zugriffsproblemen wenden Sie sich an `support@exosphere.host`. \ No newline at end of file diff --git a/docs/de/agenteye/health-monitoring.mdx b/docs/de/agenteye/health-monitoring.mdx new file mode 100644 index 00000000..f45e9872 --- /dev/null +++ b/docs/de/agenteye/health-monitoring.mdx @@ -0,0 +1,94 @@ +--- +title: "Health Monitoring" +description: "AgentEye Health Monitoring Dokumentation." +--- + +Erkennen Sie, wann eine AgentEye-Instanz selbst **ausgefallen oder beeinträchtigt** ist – nicht nur, wenn sich Ihre Agents falsch verhalten. Die Erkennung ist **Kubernetes-nativ** und, entscheidend, **unabhängig von AgentEye**: Sie liest den Pod-Zustand aus der Kubernetes-Control-Plane und prüft die harten Abhängigkeiten von AgentEye, sodass sie auch dann ausgelöst wird, wenn der Server, ClickHouse oder Postgres selbst ausgefallen ist. + +Es gibt zwei Ebenen. Die erste ist eingebaut; die zweite ist optional aktivierbar. + +## 1. Abhängigkeitsbewusste Readiness-Prüfung (eingebaut) + +Der Server stellt zwei Probe-Endpunkte mit bewusst unterschiedlichen Aufgaben bereit: + +| Endpunkt | Probe | Prüft | Auth | +|---|---|---|---| +| `GET /health` | Liveness | Prozess ist am Leben (immer `{"status":"ok"}`) | keine | +| `GET /ready` | Readiness | Kann tatsächlich Anfragen bedienen: **Postgres + ClickHouse** erreichbar | keine | + +`/ready` gibt `200` mit `"status":"ready"` und jede Prüfung als `"ok"` zurück, wenn beide harten Abhängigkeiten erreichbar sind, und `503` mit `"status":"not_ready"`, wenn eine davon nicht erreichbar ist. Beide Antworten enthalten einen kurzen Body: + +```json +{ "status": "not_ready", + "checks": { "postgres": "ok", "clickhouse": "down", "redis": "not_configured" } } +``` + +Redis ist ein optionaler Cache, an dem der Server vorbeifällt, sodass er zwar zur Information gemeldet wird, aber die Readiness **nie** zum Fehlschlag bringt. Es zeigt `"ok"`, wenn ein Cache konfiguriert ist, und `"not_configured"` andernfalls; es ist nie `"down"`. + +In den mitgelieferten Kubernetes-Manifesten zeigt die **Readiness**-Probe auf `/ready`, während **Liveness** auf `/health` bleibt. Die Wirkung: Ein Server, der zwar *läuft, aber seine Datenbank nicht erreichen kann*, wird aus dem Service genommen und als `NotReady` angezeigt – ein Zustand, auf den Ihr Cluster-Monitoring (siehe unten) aufmerksam machen kann – während Liveness günstig bleibt, sodass eine kurze Störung der Abhängigkeit nie einen Pod-Neustart auslöst. Die Probe verwendet einen großzügigen Fehlerschwellenwert, damit ein kurzer Ausreißer Replicas nicht aus der Rotation kippt. + +## 2. Pod-Failure-Benachrichtigung mit Robusta (optional) + +[Robusta](https://github.com/robusta-dev/robusta) ist ein Kubernetes-nativer Monitor, der den API-Server beobachtet und Pod-Fehler (`CrashLoopBackOff`, `OOMKilled`, `ImagePullBackOff`, `Pending`/`NotReady`, `Failed`, Evictions) an Slack sendet. Da er die Control-Plane beobachtet statt AgentEye zu befragen, löst er auch dann Benachrichtigungen aus, wenn AgentEye gar nicht reagieren kann. + +Robusta wird als optionales Add-on im Release-Bundle ausgeliefert. Aktivieren Sie es mit dem Standard-Robusta-Helm-Chart und der unten gezeigten kleinen Values-Datei: + +1. Fügen Sie das Chart-Repo hinzu und holen Sie sich ein Slack-**Bot-Token** (`xoxb-…`) für den gewünschten Channel: + + ```bash + helm repo add robusta https://robusta-charts.storage.googleapis.com + helm repo update + ``` + + Da die folgende Konfiguration alles im Cluster hält + (`disableCloudRouting: true`), stammt das Token von einer selbst gehosteten Slack-App: + Erstellen Sie eine App unter `https://api.slack.com/apps`, fügen Sie den Bot-Scope `chat:write` hinzu, + installieren Sie sie in Ihrem Workspace, kopieren Sie das **Bot User OAuth Token** (`xoxb-…`) und + laden Sie den Bot in den Channel ein (`/invite @your-app`). + +2. Erstellen Sie eine `values.yaml` mit einem deployment-spezifischen Label (`clusterName`) und Ihrem + Slack-Channel, begrenzt auf den `agenteye`-Namespace: + + ```yaml + clusterName: "acme-prod" # deployment-spezifisches Label; erscheint in jeder Benachrichtigung + enablePrometheusStack: false # nur Pod-Crash-Benachrichtigungen; kein Metrics-Stack + disableCloudRouting: true # direkte Zustellung an Slack, im Cluster + sinksConfig: + - slack_sink: + name: vendor_slack + slack_channel: "agenteye-fleet-health" + api_key: "REPLACE_WITH_SLACK_BOT_TOKEN" # xoxb-… (bevorzugt --set oder ein Secret verwenden) + scope: + include: + - namespace: [agenteye] # nur Benachrichtigungen aus dem AgentEye-Namespace; entfernen zum Erweitern + ``` + +3. Installieren Sie es und pinnen Sie `--version` auf ein bekannt gutes Robusta-Chart-Release + ([Releases](https://github.com/robusta-dev/robusta/releases)), damit Sie nie ein ungetestetes Chart installieren: + + ```bash + helm install robusta robusta/robusta \ + --namespace robusta --create-namespace \ + --version \ + -f values.yaml \ + --set sinksConfig[0].slack_sink.api_key=$ROBUSTA_SLACK_TOKEN + ``` + +### Was gemeldet wird + +- Kubernetes-**Pod-Zustand** (welcher AgentEye-Pod ausfällt und warum) sowie der **Image-Tag** jedes Pods, d. h. die laufende Komponenten-**Version**. +- **Keine AgentEye-Ereignisdaten und keine Kundendaten** verlassen jemals den Cluster. +- Die mitgelieferten Values beschränken Benachrichtigungen auf den **`agenteye`-Namespace**, sodass unabhängige Workloads im selben Cluster nicht gemeldet werden. + +### Eine Anlaufstelle für jedes Deployment + +Richten Sie Robusta bei jedem Deployment auf **einen gemeinsamen Slack-Channel**, jeweils mit eigenem `clusterName`. Jede Benachrichtigung ist mit diesem Label versehen, sodass ein einziger Channel den Gesundheitszustand Ihrer gesamten Flotte zeigt und Sie auf einen Blick erkennen, welches Deployment betroffen ist. + +### Vollständige Cluster-Ausfälle + +Ein rein im Cluster laufender Watcher kann einen **vollständigen Cluster- oder Netzwerkausfall** nicht melden (er fällt mit dem Cluster aus). Falls Sie das benötigen, aktivieren Sie den optionalen **Robusta-UI-Sink**: Setzen Sie `disableCloudRouting: false` und fügen Sie einen `robusta_sink` (mit einem Token aus `robusta gen-config`) zu `sinksConfig` hinzu. Damit erhalten Sie ein aggregiertes Multi-Cluster-Dashboard, das jeden Cluster markiert, der aufgehört hat, sich zu melden. + +## Fehlerbehebung + +Weitere Informationen finden Sie im Abschnitt **Health Monitoring** unter +[enterprise-docs/troubleshooting.md](/de/agenteye/troubleshooting) zu den Themen Keine eingehenden Benachrichtigungen und Server kippt ständig auf `NotReady`. \ No newline at end of file diff --git a/docs/de/agenteye/kubernetes-deployment.mdx b/docs/de/agenteye/kubernetes-deployment.mdx new file mode 100644 index 00000000..74c29ed2 --- /dev/null +++ b/docs/de/agenteye/kubernetes-deployment.mdx @@ -0,0 +1,1022 @@ +--- +title: "Kubernetes Deployment Guide" +description: "Dokumentation zum AgentEye Kubernetes Deployment Guide." +--- + + +Diese Anleitung stellt den vollständigen AgentEye-Stack auf einem dedizierten Kubernetes-Cluster bereit: + +- **ClickHouse 24.8** -- der primäre Analytics-Speicher für Events und Evaluierungen (StatefulSet mit 100Gi Persistent Volume). Pflichtkomponente: der Server startet ohne sie nicht. +- **PostgreSQL 16** -- relationaler Metadatenspeicher für Organisationen, API-Keys, Benutzer, Dashboards, gespeicherte Abfragen und Authentifizierung (StatefulSet mit 50Gi Persistent Volume) +- **Redis 7.2** -- optionaler gemeinsamer Cache und Rate-Limit-Backend; Server und Dashboard degradieren gracefully, wenn Redis nicht verfügbar ist +- **AgentEye Server** -- Rust-API für Event-Ingestion, Analytics und Key-Management (2 Replicas) +- **AgentEye Dashboard** -- Next.js-Web-UI (2 Replicas) +- **KI-Assistent (Agent Service)** -- optionaler schreibgeschützter In-Dashboard-Assistent auf Port 9100; inaktiv, bis ein LLM-Endpunkt konfiguriert wird +- **Traefik (öffentlich)** -- Ingress Controller für Collector-Traffic, mTLS-geschützt +- **Traefik (Dashboard)** -- Ingress Controller für das Dashboard, nur per VPN/IP-Allowlist zugänglich +- **cert-manager** -- TLS-Zertifikate und mTLS-CA +- **Backup CronJob** -- tägliches kombiniertes Dump von PostgreSQL + ClickHouse um 03:00 UTC +- **Cert Renewal Monitor** -- Warnhinweise, wenn Client-Zertifikate bald ablaufen + +**Geschätzte Zeit:** 60--90 Minuten für eine Erstbereitstellung. + +Für das verwaltete Bereitstellungsmodell, bei dem Exosphere dies in Ihrem Auftrag übernimmt, siehe [enterprise-docs/managed-deployment.md](/de/agenteye/managed-deployment). + +--- + +## Voraussetzungen + +Führen Sie jeden Prüfbefehl aus, bevor Sie beginnen. Alle Prüfungen müssen erfolgreich sein. + +| Anforderung | Minimum | Prüfbefehl | Erwartet | +|---|---|---|---| +| Kubernetes-Cluster | 1.27+ | `kubectl version` | Server Version >= v1.27 | +| Kustomize (in kubectl enthalten) | Kustomize v1.14+ (in kubectl 1.27+ enthalten) | `kubectl kustomize --help` | Gibt Hilfetext aus | +| Helm | v3 | `helm version` | `Version:"v3.x.x"` | +| cluster-admin RBAC | -- | `kubectl auth can-i create namespaces` | `yes` | +| Standard-StorageClass | -- | `kubectl get storageclass` | Mindestens eine Zeile mit `(default)` | +| LoadBalancer-Unterstützung | -- | Cloud-abhängig (EKS, GKE, AKS unterstützen dies standardmäßig) | -- | +| GitHub PAT | -- | `echo $AGENTEYE_TOKEN` | Nicht leer (siehe [enterprise-docs/github-token.md](/de/agenteye/github-token)) | +| openssl | -- | `openssl version` | OpenSSL 1.x oder 3.x | +| Cloud-Storage-Bucket | -- | Für PostgreSQL + ClickHouse-Backups (S3, GCS oder Azure Blob) | -- | + +**Cluster-Dimensionierung:** Mindestens 3 Nodes, jeweils 4 vCPU / 8 GB RAM. Vollständige Anforderungen unter [enterprise-docs/managed-deployment.md](/de/agenteye/managed-deployment). + +### Alle Prüfungen auf einmal ausführen + +```bash +echo "--- Prerequisites Check ---" +kubectl version --client -o yaml 2>/dev/null | grep -q gitVersion && echo "PASS: kubectl" || echo "FAIL: kubectl not found" +helm version --short 2>/dev/null | grep -q v3 && echo "PASS: helm v3" || echo "FAIL: helm v3 not found" +kubectl auth can-i create namespaces 2>/dev/null | grep -q yes && echo "PASS: cluster-admin" || echo "FAIL: no cluster-admin" +kubectl get storageclass 2>/dev/null | grep -q default && echo "PASS: default StorageClass" || echo "FAIL: no default StorageClass" +[ -n "$AGENTEYE_TOKEN" ] && echo "PASS: AGENTEYE_TOKEN set" || echo "FAIL: AGENTEYE_TOKEN not set" +openssl version >/dev/null 2>&1 && echo "PASS: openssl" || echo "FAIL: openssl not found" +echo "---" +``` + +### Bereitstellungsstruktur + +Der **Ingest-Endpunkt** wird auf einem Hostname Ihrer Wahl bereitgestellt (z. B. `ingest.ihre-firma.example`). cert-manager fordert ein öffentlich vertrauenswürdiges TLS-Zertifikat von Let's Encrypt über HTTP-01 an, sodass Collectors das Server-Zertifikat gegen den System-Trust-Store prüfen – ohne kundenspezifisches CA-Pinning. + +Der **Dashboard-Endpunkt** funktioniert entsprechend: Er wird auf einem zweiten Hostname Ihrer Wahl bereitgestellt (z. B. `agenteye.ihre-firma.example`), der auf den Dashboard-Traefik-LoadBalancer zeigt, und cert-manager stellt das Let's Encrypt-Zertifikat über diesen LoadBalancer aus. Browser erhalten ein vertrauenswürdiges Zertifikat ohne Warnung. + +> **Zertifikatsausstellung und -erneuerung erfolgen über HTTP-01**, daher müssen beide LoadBalancer vom öffentlichen Internet auf Port 80 erreichbar sein. Wenn Sie den Dashboard-LoadBalancer IP-seitig einschränken möchten, koordinieren Sie vorab einen DNS-01-Solver mit dem Support – andernfalls schlagen Erneuerungen lautlos fehl und das Zertifikat läuft ab. + +--- + +## Manifeste abrufen + +```bash +git clone https://x:${AGENTEYE_TOKEN}@github.com/agenteye-enterprise/releases.git +cd releases/deploy +``` + +**Test:** + +```bash +ls base/kustomization.yaml +``` + +Erwartet: Die Datei ist vorhanden. Falls nicht, ist der Clone fehlgeschlagen – überprüfen Sie Ihr `AGENTEYE_TOKEN`. + +**Verzeichnisstruktur:** + +``` +deploy/ + base/ Gemeinsame Kustomize-Basis (alle K8s-Ressourcen) + overlays/ Cluster-spezifische Überschreibungen (Image-Tags, Hostnamen, Ressourcen) + third-party/ Helm-Values für Traefik, cert-manager und (optional) Robusta Health Monitoring +``` + +Die **base** enthält alle Ressourcen für eine vollständige Bereitstellung, einschließlich Let's Encrypt-Zertifikaten für die beiden öffentlichen Hostnamen, die Sie in Phase 3.1 konfigurieren. Ein **Overlay** passt die Basis für eine spezifische Umgebung an (z. B. benutzerdefinierte Image-Tags, Ressourcenlimits, Umgebungsvariablen-Verknüpfung). Das Verzeichnis **third-party** enthält Helm-Values-Dateien für externe Infrastruktur. + +> **Health Monitoring (optional):** Der Readiness-Probe des Servers spiegelt bereits den Zustand von Postgres + ClickHouse wider; `third-party/robusta/` ergänzt optionales, Kubernetes-natives Pod-Failure-Alerting nach Slack. Siehe [enterprise-docs/health-monitoring.md](/de/agenteye/health-monitoring). + +--- + +## Phase 1 -- Drittanbieter-Infrastruktur (~30 Min.) + +### 1.1 cert-manager installieren + +cert-manager verwaltet TLS-Zertifikate für HTTPS und die private CA, die für mTLS-Client-Zertifikate verwendet wird. + +```bash +helm repo add jetstack https://charts.jetstack.io +helm repo update + +helm install cert-manager jetstack/cert-manager \ + --namespace cert-manager --create-namespace \ + --set crds.install=true +``` + +**Test:** + +```bash +kubectl get pods -n cert-manager +``` + +Erwartet: 3 Pods, alle `Running` -- `cert-manager`, `cert-manager-cainjector`, `cert-manager-webhook`. + +```bash +kubectl get crds | grep cert-manager +``` + +Erwartet: mindestens `certificates.cert-manager.io`, `clusterissuers.cert-manager.io`, `issuers.cert-manager.io`. + +**Bei Fehler:** Pods im Status `CrashLoopBackOff` bedeuten in der Regel, dass CRDs nicht installiert wurden. Wiederholen Sie den Befehl mit `--set crds.install=true`. Falls Webhook-Pods den Readiness-Check nicht bestehen, warten Sie 30 Sekunden und prüfen Sie erneut – der Start kann einen Moment dauern. + +--- + +### 1.2 Traefik installieren -- Öffentlicher Ingest Controller + +Diese Traefik-Instanz verarbeitet Collector-Traffic über einen **externen** LoadBalancer. Sie terminiert TLS und erzwingt mTLS (Client-Zertifikat-Verifizierung) am Ingest-Endpunkt. + +```bash +helm repo add traefik https://traefik.github.io/charts +helm repo update + +helm install traefik-public traefik/traefik \ + --namespace traefik-public --create-namespace \ + --version 39.0.8 \ + -f third-party/traefik/values-public.yaml +``` + +**Test:** + +```bash +kubectl get pods -n traefik-public +``` + +Erwartet: 1 Pod `Running`. + +```bash +kubectl get ingressclass traefik-public +``` + +Erwartet: Die IngressClass ist vorhanden (sie ist nicht die Standard-Class). + +**Bei Fehler:** Prüfen Sie `kubectl describe pod -n traefik-public ` auf Image-Pull-Fehler oder Ressourcenengpässe. + +--- + +### 1.3 Traefik installieren -- Dashboard Controller + +Diese Traefik-Instanz stellt das Dashboard über einen dedizierten LoadBalancer bereit, der per IP-Allowlist eingeschränkt ist. + +> **Für diese Instanz werden zwei Allowlist-Mechanismen mitgeliefert.** Diese Anleitung verwendet `values-dashboard.yaml`, das den Zugriff über das portable Feld `service.loadBalancerSourceRanges` einschränkt. Parallel dazu steht `values-internal.yaml` für AWS-Umgebungen zur Verfügung, die stattdessen die Annotation `service.beta.kubernetes.io/aws-load-balancer-source-ranges` bevorzugen. Wählen Sie eine Variante und verwenden Sie sie konsequent; die nachfolgenden Schritte setzen `values-dashboard.yaml` voraus. + +**Vor der Installation** bearbeiten Sie `third-party/traefik/values-dashboard.yaml`, um die erlaubten Quell-IPs festzulegen. Das Feld `loadBalancerSourceRanges` steuert, welche IPs das Dashboard erreichen können. Standardmäßig ist es auf `0.0.0.0/0` (alle IPs) gesetzt; schränken Sie es auf Ihr VPN, Ihr Büro oder bekannte Ausgangs-IPs ein. + +#### Einzelne IP freigeben + +```yaml +service: + loadBalancerSourceRanges: + - "/32" +``` + +#### Mehrere IPs freigeben + +Fügen Sie pro IP oder CIDR-Block einen Eintrag hinzu. Das Suffix `/32` entspricht einer einzelnen IPv4-Adresse; ein CIDR-Block (z. B. `/24`) entspricht einem Bereich. Sie können einzelne IPs und Bereiche beliebig mischen: + +```yaml +service: + loadBalancerSourceRanges: + - "203.0.113.10/32" # Büro-Gateway + - "203.0.113.11/32" # Backup-Büro-Gateway + - "198.51.100.0/24" # VPN-Pool + - "192.0.2.50/32" # Home-IP des On-Call-Engineers +``` + +Hinweise zur Pflege der Liste: + +- Schreiben Sie einen Eintrag pro Zeile und fügen Sie einen kurzen `#`-Kommentar hinzu, der Eigentümer oder Zweck der IP beschreibt; darauf stützen sich zukünftige Betreiber bei der Entscheidung, ob ein Eintrag noch benötigt wird. +- Verwenden Sie immer CIDR-Notation. Eine nackte IP wie `203.0.113.10` wird vom Cloud-Anbieter abgelehnt; verwenden Sie `203.0.113.10/32`. +- Für IPv6-Bereiche nutzen Sie das entsprechende `/128` (Einzeladresse) oder ein größeres CIDR, z. B. `2001:db8::1/128`. Nicht alle Cloud-Anbieter unterstützen IPv6-Quellbereiche; prüfen Sie die LoadBalancer-Dokumentation Ihres Anbieters. +- Die Liste ist eine **ODER**-Verknüpfung: Traffic wird zugelassen, wenn die Quelle einem beliebigen Eintrag entspricht. + +Fahren Sie nach dem Bearbeiten der Datei mit `helm install` unten fort. Wenn der Controller bereits installiert ist, führen Sie `helm upgrade` mit denselben Flags aus oder patchen Sie den Service zur Laufzeit (nächster Abschnitt). + +#### Allowlist zur Laufzeit aktualisieren + +Sie können die erlaubten IPs ohne ein Helm-Upgrade ändern, indem Sie den Service direkt patchen. **Der Patch ersetzt die gesamte Liste**; geben Sie immer alle IPs an, die Sie behalten möchten, nicht nur die neue. + +Um die Liste durch einen neuen IP-Satz zu ersetzen: + +```bash +kubectl patch svc traefik-dashboard -n traefik-dashboard \ + -p '{"spec":{"loadBalancerSourceRanges":["203.0.113.10/32","198.51.100.0/24","192.0.2.50/32"]}}' +``` + +Um eine IP sicher **hinzuzufügen**, ohne bestehende Einträge zu verlieren, lesen Sie zuerst die aktuelle Liste und patchen Sie dann mit dem kombinierten Satz: + +```bash +# 1. Aktuelle Allowlist anzeigen +kubectl get svc traefik-dashboard -n traefik-dashboard \ + -o jsonpath='{.spec.loadBalancerSourceRanges}' + +# 2. Mit vollständiger Liste einschließlich der neuen IP patchen +kubectl patch svc traefik-dashboard -n traefik-dashboard \ + -p '{"spec":{"loadBalancerSourceRanges":["/32","/32","/32"]}}' +``` + +> Laufzeit-Patches werden nicht in `values-dashboard.yaml` zurückgeschrieben. Um die Änderung über zukünftige Helm-Upgrades hinaus zu erhalten, aktualisieren Sie auch die Values-Datei und committen Sie sie. + +Dann installieren: + +```bash +helm install traefik-dashboard traefik/traefik \ + --namespace traefik-dashboard --create-namespace \ + --version 39.0.8 \ + -f third-party/traefik/values-dashboard.yaml +``` + +**Test:** + +```bash +kubectl get pods -n traefik-dashboard +``` + +Erwartet: 1 Pod `Running`. + +```bash +kubectl get ingressclass traefik-dashboard +``` + +Erwartet: Die IngressClass ist vorhanden. + +--- + +### 1.4 Auf LoadBalancer warten + +Beide Traefik-Instanzen benötigen externe IPs, bevor Sie fortfahren können. + +```bash +kubectl get svc -n traefik-public +kubectl get svc -n traefik-dashboard +``` + +**Test:** Beide Services zeigen eine `EXTERNAL-IP` (nicht ``). + +Wenn noch ausstehend, auf Zuweisung warten: + +```bash +kubectl get svc -n traefik-public -w +``` + +Drücken Sie `Ctrl+C`, sobald die IP erscheint. Die IP-Zuweisung dauert in der Regel 2--5 Minuten. + +**Bei Fehler:** `` nach 10 Minuten bedeutet in der Regel, dass der Cloud-Anbieter keinen LoadBalancer bereitstellen kann. Prüfen Sie: Subnet-Tags (EKS erfordert `kubernetes.io/role/elb`), VPC-Konfiguration, Service-Quoten und ob die korrekte interne LB-Annotation für die interne Instanz gesetzt ist. + +--- + +## Phase 2 -- Secrets erstellen (~10 Min.) + +Alle Secrets werden manuell erstellt, bevor die Anwendung bereitgestellt wird. So wird sichergestellt, dass sensible Werte niemals in Manifest-Dateien erscheinen. + +### 2.1 Namespace erstellen + +```bash +kubectl create namespace agenteye +``` + +**Test:** + +```bash +kubectl get namespace agenteye +``` + +Erwartet: Status `Active`. + +--- + +### 2.2 Image-Pull-Secret + +Dieses Secret authentifiziert sich bei `ghcr.io`, um die AgentEye-Container-Images zu pullen. Informationen zur Generierung Ihres PAT finden Sie unter [enterprise-docs/github-token.md](/de/agenteye/github-token). + +```bash +kubectl create secret docker-registry agenteye-image-pull \ + --namespace agenteye \ + --docker-server=ghcr.io \ + --docker-username=agenteye-enterprise \ + --docker-password="${AGENTEYE_TOKEN}" +``` + +**Test:** + +```bash +kubectl get secret agenteye-image-pull -n agenteye -o jsonpath='{.type}' +``` + +Erwartet: `kubernetes.io/dockerconfigjson`. + +**Test (tiefgehend)** -- prüfen Sie, ob das Token tatsächlich Images pullen kann: + +Verwenden Sie den `server`-Image-Tag, der in der `kustomization.yaml` Ihres Overlays festgepinnt ist (aktuell `v0.0.1-beta.48` sowohl im mitgelieferten `acme`-Overlay als auch im Basis-Deployment). Ersetzen Sie den Tag unten durch den tatsächlich bereitgestellten, damit diese Prüfung über Releases hinweg nicht abweicht: + +```bash +kubectl run test-pull \ + --image=ghcr.io/agenteye-enterprise/server:v0.0.1-beta.48 \ + --overrides='{"spec":{"imagePullSecrets":[{"name":"agenteye-image-pull"}]}}' \ + --restart=Never -n agenteye --command -- echo ok + +# Einige Sekunden für den Pull warten, dann: +kubectl logs test-pull -n agenteye +kubectl delete pod test-pull -n agenteye +``` + +Erwartet: `ok` in den Logs. + +**Bei Fehler:** `ErrImagePull` oder `401 Unauthorized` bedeutet, dass das PAT ungültig ist oder den Scope `read:packages` nicht besitzt. Überprüfen Sie [enterprise-docs/github-token.md](/de/agenteye/github-token). + +--- + +### 2.3 PostgreSQL-Zugangsdaten + +```bash +POSTGRES_PASSWORD=$(openssl rand -hex 24) + +kubectl create secret generic agenteye-postgres \ + --namespace agenteye \ + --from-literal=POSTGRES_USER=postgres \ + --from-literal=POSTGRES_PASSWORD="${POSTGRES_PASSWORD}" \ + --from-literal=POSTGRES_DB=agenteye +``` + +> **Wichtig:** Wir verwenden `-hex` (nicht `-base64`) zur Passwortgenerierung. Base64-Ausgaben können `+`, `/` und `=` enthalten, die den `DATABASE_URL`-Connection-String beschädigen. Einzelheiten unter [enterprise-docs/troubleshooting.md](/de/agenteye/troubleshooting). + +> **Speichern Sie `POSTGRES_PASSWORD` sofort in Ihrem Secrets-Manager.** Sie benötigen es, wenn Sie jemals eine Sicherung wiederherstellen oder sich direkt mit der Datenbank verbinden. + +**Test:** + +```bash +kubectl get secret agenteye-postgres -n agenteye +``` + +Erwartet: Das Secret ist vorhanden. + +```bash +kubectl get secret agenteye-postgres -n agenteye \ + -o jsonpath='{.data.POSTGRES_PASSWORD}' | base64 -d | wc -c +``` + +Erwartet: `48` (24 Hex-Bytes = 48 Zeichen). + +--- + +### 2.4 Admin-API-Key + +```bash +ADMIN_KEY=$(openssl rand -hex 32) + +kubectl create secret generic agenteye-admin-key \ + --namespace agenteye \ + --from-literal=ADMIN_KEY="${ADMIN_KEY}" +``` + +Der Admin-Key ist das Bootstrap-Credential. Der Server führt bei jedem Start einen Upsert mit allen Berechtigungen durch. Verwenden Sie ihn, um in Phase 7 Collector-Keys mit eingeschränktem Scope zu erstellen. Das vollständige Berechtigungsmodell finden Sie unter [enterprise-docs/api-keys.md](/de/agenteye/api-keys). + +> **Speichern Sie `ADMIN_KEY` sofort in Ihrem Secrets-Manager.** + +**Test:** + +```bash +kubectl get secret agenteye-admin-key -n agenteye +``` + +Erwartet: Das Secret ist vorhanden. + +--- + +### 2.5 Auth-Konfiguration (Dashboard-Login) + +Das Dashboard verwendet E-Mail + OTP für die Benutzeranmeldung. Ohne dieses Secret startet der Server zwar weiterhin und der `ADMIN_KEY`-API-Pfad funktioniert weiterhin, aber **kein Benutzer kann sich über die UI anmelden**. + +Alle Keys sind in der Basis-Manifest als `optional: true` referenziert, sodass teilweise Secrets (oder gar kein Secret) in Ordnung sind; der Server fällt auf die dokumentierten Standardwerte zurück. Alles in einem einzigen `agenteye-auth`-Secret zu bündeln macht die Auth-Oberfläche an einer einzigen Stelle rotierbar. + +```bash +kubectl create secret generic agenteye-auth \ + --namespace agenteye \ + --from-literal=ADMIN_EMAIL="admin@ihrefirma.com" \ + --from-literal=ALLOWED_EMAILS="*@ihrefirma.com" \ + --from-literal=SMTP_HOST="smtp.ihreanbieter.com" \ + --from-literal=SMTP_PORT="587" \ + --from-literal=SMTP_USERNAME="ihr-smtp-benutzer" \ + --from-literal=SMTP_PASSWORD="ihr-smtp-passwort" \ + --from-literal=SMTP_FROM="noreply@ihrefirma.com" \ + --from-literal=SMTP_TLS="starttls" \ + --from-literal=DEFAULT_ORG_NAME="Beispiel GmbH" \ + --from-literal=DEFAULT_ORG_SLUG="beispiel" +``` + +| Key | Zweck | +|---|---| +| `ADMIN_EMAIL` | Bootstrap-Admin-Benutzer. Wird bei jedem Start mit allen Berechtigungen per Upsert gesetzt und ist vor Löschung/Berechtigungsänderungen über das Dashboard geschützt. Ohne diesen Key wird kein Admin angelegt und die erste Anmeldung ist unmöglich. | +| `ALLOWED_EMAILS` | Kommagetrennte Allowlist. Unterstützt exakte Adressen (`user@example.com`) und Domain-Wildcards (`*@example.com`). Ohne diesen Key **kann sich kein Benutzer anmelden oder angelegt werden**. | +| `SMTP_HOST`, `SMTP_PORT`, `SMTP_USERNAME`, `SMTP_PASSWORD`, `SMTP_FROM` | SMTP-Relay für den Versand von OTP-Codes. Ist `SMTP_HOST` nicht gesetzt, werden OTP-Codes in den Server-stdout geloggt statt per E-Mail versendet (nützlich für erste Boot-Smoke-Tests). Geben Sie alle SMTP-Keys gemeinsam an, um echte E-Mail-Zustellung zu aktivieren. | +| `SMTP_TLS` | Eines von `starttls` (Standard), `tls` oder `none`. | +| `DEFAULT_ORG_NAME`, `DEFAULT_ORG_SLUG` | Optional. Versieht die eingebaute `default`-Organisation mit einem benutzerfreundlichen Anzeigenamen und URL-Slug, sodass sie z. B. unter `/beispiel` statt `/default` erreichbar ist. Wird nur beim **ersten Boot** angewendet; nachdem Sie die Organisation mit `agenteye-orgctl org rename` umbenannt haben (siehe §7.6), werden diese Werte ignoriert. Der Slug muss 1--40 alphanumerische Kleinbuchstaben mit einzelnen internen Bindestrichen enthalten. Lassen Sie beide ungesetzt, um das generische `default` beizubehalten. | + +> **Speichern Sie die SMTP-Zugangsdaten in Ihrem Secrets-Manager.** + +**Test:** + +```bash +kubectl get secret agenteye-auth -n agenteye \ + -o jsonpath='{.data}' | grep -o '"[A-Z_]*"' | sort -u +``` + +Erwartet: Die befüllten Keys erscheinen in der Ausgabe. + +--- + +### 2.6 Multi-Tenant-Org-Isolationskey (optional) + +Überspringen Sie dies für eine Single-Tenant-Bereitstellung; der Server läuft mit einem eingebauten Dev-Standard und bedient die eine `default`-Org problemlos. **Bevor Sie eine zweite Organisation anlegen**, setzen Sie einen starken, stabilen `ORG_CH_SECRET`: Das ClickHouse-Passwort jeder Organisation wird als `HMAC(ORG_CH_SECRET, org_id)` abgeleitet; der öffentlich bekannte Dev-Standard würde öffentlich ableitbare Pro-Org-Zugangsdaten ergeben. Der Befehl `agenteye-orgctl org create` (siehe [§7.6 Organisationen bereitstellen](#76-provision-organizations-multi-tenant)) verweigert die Ausführung, solange der Server noch den eingebauten Dev-Standard verwendet. + +```bash +kubectl create secret generic agenteye-org-ch-secret \ + --namespace agenteye \ + --from-literal=ORG_CH_SECRET="$(openssl rand -base64 48)" + +# Server neu starten, damit er den neuen Wert übernimmt. +kubectl -n agenteye rollout restart deployment/server +``` + +Der Server liest dies über eine **optionale** `secretKeyRef`, sodass ein Single-Tenant-Cluster, der dieses Secret nie anlegt, normal startet. Halten Sie den Wert **stabil und auf allen Replicas identisch**; eine Rotation macht jedes abgeleitete ClickHouse-Passwort einer Organisation ungültig, bis die Boot-Zeit-Reconciliation die Benutzer neu provisioniert (ein Rolling Restart mit konsistentem Wert überall heilt dies). Siehe `deploy/base/server/secret.example.yaml`. + +> **Speichern Sie `ORG_CH_SECRET` in Ihrem Secrets-Manager und rotieren Sie ihn nicht leichtfertig.** + +--- + +### 2.7 Alle Secrets prüfen + +```bash +kubectl get secrets -n agenteye -o custom-columns='NAME:.metadata.name,TYPE:.type' +``` + +Erwartete Ausgabe (neben etwaigen Standard-Secrets): + +``` +NAME TYPE +agenteye-admin-key Opaque +agenteye-auth Opaque +agenteye-image-pull kubernetes.io/dockerconfigjson +agenteye-postgres Opaque +agenteye-org-ch-secret Opaque # nur wenn Sie §2.6 (Multi-Tenant) abgeschlossen haben +``` + +Die vier Kern-Secrets (`agenteye-admin-key`, `agenteye-auth`, `agenteye-image-pull`, `agenteye-postgres`) müssen vorhanden sein, bevor Sie fortfahren. `agenteye-org-ch-secret` ist nur für Multi-Tenant-Bereitstellungen erforderlich (siehe §2.6). + +--- + +## Phase 3 -- Anwendung bereitstellen (~5 Min.) + +### 3.1 Öffentliche Hostnamen konfigurieren + +cert-manager benötigt die Ingest- und Dashboard-Hostnamen, bevor es deren Let's Encrypt-Zertifikate anfordern kann. Kopieren Sie die Vorlage und setzen Sie beide: + +```bash +cp base/certificates/domain.env.example base/certificates/domain.env +# Bearbeiten Sie base/certificates/domain.env und setzen Sie: +# INGEST_DOMAIN=ingest.ihre-firma.example (zeigt auf den öffentlichen Traefik LB) +# DASHBOARD_DOMAIN=agenteye.ihre-firma.example (zeigt auf den Dashboard-Traefik LB) +``` + +`domain.env` ist in gitignore eingetragen und bleibt lokal für jede Bereitstellung. Der Kustomize-Build schlägt lautstark fehl, wenn einer der Keys fehlt. + +> **DNS muss zuerst auflösen.** Sie müssen DNS noch nicht auf die LBs zeigen lassen (sie existieren erst nach Abschluss von Phase 1.2), aber ACME-Ausstellung in Schritt 3.2 wiederholt den Versuch, bis jeder Hostname zu seinem LoadBalancer auflöst. Sie können DNS jetzt einrichten (anhand der in Phase 1.4 erfassten LB-Hostnamen) oder fortfahren und die Einträge in Phase 4 hinzufügen. + +--- + +### 3.2 Manifeste anwenden + +Wenden Sie für eine Neuinstallation direkt die Basis an, oder ein Overlay, wenn Sie eines für diese Umgebung erstellt haben (Overlays pinnen nur Image-Tags, Umgebungsvariablen und Ressourcenlimits; sie erben die Zertifikate und das Routing der Basis): + +```bash +kubectl apply -k base/ +# oder +kubectl apply -k overlays// +``` + +Das Overlay schließt die Basis automatisch ein; wenden Sie nur eines an, nicht beide. + +--- + +### 3.3 Auf Pods warten + +```bash +kubectl wait --for=condition=Ready pod -l 'app in (server,dashboard,postgres,clickhouse)' \ + -n agenteye --timeout=180s +``` + +Der Wait-Befehl ist auf die Kern-Data-Plane-Pods begrenzt. Die optionalen `agent`- (KI-Assistent) und `redis`-Pods starten parallel; der Assistent bleibt inaktiv, bis Sie seinen LLM-Endpunkt angeben (siehe [enterprise-docs/assistant.md](/de/agenteye/assistant)), und Redis ist ein Best-Effort-Cache – keiner von beiden muss Ready sein, damit die Plattform Traffic bedienen kann. + +**Test:** + +```bash +kubectl get pods -n agenteye +``` + +Erwartet (die optionalen `agent`- und `redis`-Pods erscheinen ebenfalls und erreichen `Running`): + +``` +NAME READY STATUS RESTARTS AGE +agent-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +clickhouse-0 1/1 Running 0 ... +dashboard-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +dashboard-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +postgres-0 1/1 Running 0 ... +redis-0 1/1 Running 0 ... +server-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +server-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +``` + +**Bei Fehler:** + +| Pod-Status | Wahrscheinliche Ursache | Debug-Befehl | +|---|---|---| +| `ImagePullBackOff` | Ungültiges Image-Pull-Secret oder PAT | `kubectl describe pod -n agenteye` | +| `CrashLoopBackOff` | Fehlerhafte Umgebungsvariablen (z. B. DATABASE_URL) | `kubectl logs -n agenteye` | +| `Pending` | Unzureichende CPU/Arbeitsspeicher oder keine Nodes verfügbar | `kubectl describe pod -n agenteye` (Events prüfen) | + +--- + +### 3.4 Storage prüfen + +```bash +kubectl get pvc -n agenteye +``` + +Erwartet, beide mit Status `Bound`: + +| PVC | Kapazität | Versorgt | +|---|---|---| +| `postgres-data-postgres-0` | `50Gi` | PostgreSQL relationaler/Metadaten-Speicher | +| `clickhouse-data-clickhouse-0` | `100Gi` | ClickHouse Events + Evaluierungen Analytics-Speicher | + +Ein `redis-data-redis-0` PVC (1Gi) erscheint ebenfalls für den optionalen Cache. + +**Bei Fehler:** `Pending` bedeutet, dass keine StorageClass das Volume provisionieren kann. Prüfen Sie `kubectl get storageclass` und stellen Sie sicher, dass ein Standard vorhanden ist. Für Produktionsumgebungen legen Sie das ClickHouse-Volume in Ihrem Overlay auf eine schnelle SSD-StorageClass (z. B. gp3 auf AWS, pd-ssd auf GCP); der Komprimierungsdurchsatz leidet auf langsamen Festplatten. + +--- + +### 3.5 Zertifikate prüfen + +```bash +kubectl get certificates -n agenteye +``` + +Erwartet: 3 Zertifikate, alle `Ready: True`: + +| Name | Issuer | Zweck | +|---|---|---| +| `mtls-ca` | `selfsigned` | Private CA zur Ausstellung von mTLS-Client-Zertifikaten (10 Jahre Gültigkeit) | +| `ingest-tls` | `letsencrypt-prod` | Öffentliches TLS-Zertifikat für den Ingest-Endpunkt (90 Tage, auto-erneuert) | +| `dashboard-tls` | `letsencrypt-prod` | Öffentliches TLS-Zertifikat für das Dashboard (90 Tage, auto-erneuert) | + +**Wenn `ingest-tls` oder `dashboard-tls` nicht Ready ist:** + +`kubectl describe certificate -n agenteye` und die Events lesen. Die häufigsten Ursachen: + +- **DNS zeigt noch nicht auf den LB.** Let's Encrypt löst den Hostnamen auf und trifft Port 80 zur Validierung -- `INGEST_DOMAIN` muss zum öffentlichen LB auflösen, `DASHBOARD_DOMAIN` zum Dashboard-LB. Bis der CNAME/Alias propagiert ist, bleibt die Order `pending`. Sobald DNS korrekt ist, wiederholt cert-manager automatisch (kein manuelles Löschen des Certificate-Objekts nötig). +- **Hostname nicht ersetzt.** Wenn `dnsNames` noch `INGEST_DOMAIN_PLACEHOLDER` / `DASHBOARD_DOMAIN_PLACEHOLDER` anzeigt, haben Sie Schritt 3.1 übersprungen -- erstellen Sie `base/certificates/domain.env` und wenden Sie erneut an. +- **Dashboard-Traefik kann die Challenge nicht bedienen** (nur `dashboard-tls`). Die Dashboard-Traefik-Instanz muss mit der mitgelieferten Values-Datei installiert werden (Phase 1.2), die den scoped Ingress-Provider aktiviert, der den HTTP-01-Solver von cert-manager bedient. Eine ohne diese Datei installierte Instanz lässt die Challenge unerreichbar und die Order bleibt dauerhaft `pending`. + +**Wenn `mtls-ca` nicht Ready ist:** cert-manager selbst ist ungesund. Prüfen Sie die cert-manager-Pods aus Schritt 1.1. + +--- + +### 3.6 CronJobs prüfen + +```bash +kubectl get cronjobs -n agenteye +``` + +Erwartet: + +| Name | Zeitplan | Zweck | +|---|---|---| +| `agenteye-backup` | `0 3 * * *` | Tägliches Postgres + ClickHouse-Backup um 03:00 UTC | +| `cert-renewal-check` | `0 3,15 * * *` | Zertifikatslaufzeit-Warnungen um 03:00 und 15:00 UTC | + +--- + +### 3.7 Korrekten Server-Start prüfen + +```bash +kubectl logs -n agenteye -l app=server --tail=20 +``` + +**Test:** Suchen Sie nach einer Startzeile, die anzeigt, dass der Server auf Port 8080 lauscht. Es sollten keine Datenbankverbindungsfehler auftreten (der Server erfordert, dass PostgreSQL und ClickHouse erreichbar sind, bevor er Ready meldet). + +**Bei Fehler:** Die häufigste Ursache ist ein `POSTGRES_PASSWORD` mit URL-unsicheren Zeichen, die `DATABASE_URL` beschädigen. Siehe [enterprise-docs/troubleshooting.md](/de/agenteye/troubleshooting). + +--- + +### 3.8 Dashboard-Verbindung zum Server prüfen + +```bash +kubectl logs -n agenteye -l app=dashboard --tail=20 +``` + +**Test:** Suchen Sie nach `Ready` in der Ausgabe ohne `ECONNREFUSED` oder ähnliche Fehler. + +**Bei Fehler:** Prüfen Sie, ob der `server`-Service existiert (`kubectl get svc server -n agenteye`) und ob `AGENTEYE_SERVER_URL` im Dashboard-Deployment auf `http://server:8080` gesetzt ist. + +--- + +## Phase 4 -- Netzwerkzugang (~5 Min.) + +### 4.1 LoadBalancer-Adressen abrufen + +```bash +PUBLIC_IP=$(kubectl get svc -n traefik-public \ + -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') + +INTERNAL_IP=$(kubectl get svc -n traefik-dashboard \ + -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') +``` + +> Auf AWS EKS geben LoadBalancer einen Hostnamen statt einer IP zurück. Ersetzen Sie `.ip` durch `.hostname` in den obigen Befehlen. + +**Test:** + +```bash +echo "Öffentlich (Ingest): $PUBLIC_IP" +echo "Intern (Dashboard): $INTERNAL_IP" +``` + +Beide müssen nicht leer sein. + +--- + +### 4.2 DNS auf die LoadBalancer zeigen + +Erstellen Sie DNS-Einträge, damit die Hostnamen aus `base/certificates/domain.env` auf ihre LoadBalancer auflösen -- `INGEST_DOMAIN` auf den **öffentlichen** Traefik-LB, `DASHBOARD_DOMAIN` auf den **Dashboard**-Traefik-LB: + +- **AWS Route 53:** `A`-Eintrag mit `Alias = Yes`, Ziel = der LB-Hostname. Verwenden Sie kein einfaches A → IP; ELB-IPs rotieren. +- **Alle anderen Anbieter:** `CNAME` vom Hostnamen zum LB-Hostnamen. + +Überprüfen: + +```bash +dig +short ingest.ihre-firma.example +dig +short agenteye.ihre-firma.example +``` + +Sollte dieselben Adressen wie `$PUBLIC_IP` und `$INTERNAL_IP` zurückgeben (oder auf EKS zu denselben `*.elb.amazonaws.com`-Hostnamen auflösen). + +Sobald DNS auflöst, schließt cert-manager die ausstehenden ACME-Orders aus Phase 3.5 innerhalb einer Minute ab. Führen Sie `kubectl get certificates -n agenteye` wiederholt aus, bis sowohl `ingest-tls` als auch `dashboard-tls` `Ready: True` zeigen. + +--- + +### 4.3 Ingest-Endpunkt erreichen + +Der öffentliche Ingest-Endpunkt erzwingt Mutual TLS, sodass jede Anfrage (einschließlich `/health`) ein Client-Zertifikat vorlegen muss. Ihr erstes Client-Zertifikat stellen Sie in Phase 5 aus; wenn Sie bereits eines haben, prüfen Sie jetzt die Erreichbarkeit: + +```bash +curl -s --cert issued//client.crt \ + --key issued//client.key \ + https://ingest.ihre-firma.example/health +``` + +Erwartet: `{"status":"ok"}`. `-k` ist nicht erforderlich -- das Server-Zertifikat verkettet zu einer öffentlichen CA für `INGEST_DOMAIN` und wird gegen den System-Trust-Store validiert. Erreichen Sie den Ingest-Endpunkt über seinen `INGEST_DOMAIN`-Hostnamen (der dem ausgestellten Zertifikat entspricht), nicht über die rohe LoadBalancer-IP/den Hostnamen. + +Der Dashboard-Endpunkt wird auf `DASHBOARD_DOMAIN` mit einem öffentlich vertrauenswürdigen Zertifikat bereitgestellt und ist nicht hinter mTLS, daher sind weder `-k` noch ein Client-Zertifikat erforderlich: + +```bash +curl -s https://agenteye.ihre-firma.example/ -o /dev/null -w '%{http_code}\n' +``` + +Erreichen Sie das Dashboard über seinen Hostnamen, nicht über die rohe LB-Adresse -- das Zertifikat ist an `DASHBOARD_DOMAIN` gebunden, sodass die rohe Adresse einen Zertifikatsnamen-Mismatch anzeigt. + +**Bei Fehler:** Wenn `curl` hängt, prüfen Sie, ob der LB von Ihrem Rechner aus erreichbar ist (VPN, Security Groups, Firewall-Regeln). Ein `certificate required`-Handshake-Fehler am Ingest-Hostnamen bedeutet, dass kein Client-Zertifikat vorgelegt wurde; schließen Sie zuerst Phase 5 ab. Ein TLS-Validierungsfehler am Ingest-Hostnamen bedeutet, dass das Server-Zertifikat noch nicht fertig ausgestellt ist; gehen Sie zurück zu Phase 3.5 und beheben Sie das Problem dort. + +--- + +## Phase 5 -- mTLS-Client-Zertifikate ausstellen (~10 Min. pro Cluster) + +Collectors authentifizieren sich mit **zwei Faktoren**: einem Client-Zertifikat (Transport-Schicht, beweist, dass die Anfrage von einem autorisierten Cluster kommt) und einem API-Key (Anwendungsschicht, beweist, dass die Anfrage von einem Collector mit `events:add`-Berechtigung stammt). Ein durchgesickerter Key ist ohne Zertifikat wertlos; ein gestohlenes Zertifikat ist ohne einen gültigen Key wertlos. + +### 5.1 Zertifikat ausstellen + +Jeder Cluster, der Collectors ausführt, benötigt sein eigenes Client-Zertifikat. Aus dem Manifeste-Verzeichnis: + +```bash +cd base/certificates/client-certs +./issue-client-cert.sh +``` + +Ersetzen Sie `` durch einen aussagekräftigen Bezeichner (z. B. `us-east-1-prod`, `staging`). + +**Test:** Das Skript gibt `==> Done!` aus und listet die Ausgabedateien auf. + +```bash +kubectl get certificate mtls-client- -n agenteye +``` + +Erwartet: `Ready: True`. + +Ausgabedateien in `issued//`: + +| Datei | Zweck | +|---|---| +| `client.crt` | Client-Zertifikat (90 Tage Gültigkeit) | +| `client.key` | Privater Client-Key | +| `ca.crt` | CA-Zertifikat für die Server-Verifizierung | +| `collector-mtls-secret.yaml` | Einsatzbereites Kubernetes-Secret für den Collector-Cluster | + +--- + +### 5.1b Alternatives Delivery: AWS Secrets Manager + +Wenn der Verbraucher des Zertifikats ein Kubernetes-Pod ist, der `client.crt` und `client.key` auf dem Datenträger benötigt -- der typische Fall bei der Ausführung des agenteye-collector als Sidecar in Ihrem Anwendungs-Pod -- übertragen Sie das Zertifikat-Bundle in den AWS Secrets Manager. Der Anwendungs-Pod mountet es dann über den [Secrets Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/) mit IRSA, und die Zertifikats-Rotation erfolgt vollständig automatisch. + +```bash +cd base/certificates/client-certs +export AWS_REGION=us-east-1 # Region, in der Ihre Workload läuft +./issue-client-cert.sh --save-to aws-secrets-manager +``` + +Bei einer erneuten Ausführung (Erneuerung) ruft das Skript `PutSecretValue` auf dem gleichen Secret auf, sodass ARN und Name stabil bleiben. Der CSI Driver übernimmt die neue Version beim nächsten Rotations-Poll und überschreibt die Dateien im Pod. + +**Voraussetzungen:** + +- `aws` CLI v2, authentifiziert für Ihr AWS-Konto. +- `jq` installiert. +- Umgebungsvariable `AWS_REGION` gesetzt. +- IAM-Berechtigungen auf Ihrer Aufrufer-Identität (schränken Sie `Resource` auf `arn:aws:secretsmanager:::secret:agenteye/mtls-client/*` ein): + - `secretsmanager:CreateSecret` + - `secretsmanager:DescribeSecret` + - `secretsmanager:PutSecretValue` + - `secretsmanager:TagResource` + +**Was das Skript in diesem Modus tut:** + +| Schritt | Aktion | +|---|---| +| 1 | Stellt das Zertifikat über cert-manager aus / extrahiert es erneut (wie im Standard-Modus). | +| 2 | Ruft `DescribeSecret` auf `agenteye/mtls-client/` auf, um Erstanlage oder Update zu entscheiden. | +| 3 | Beim ersten Aufruf: `CreateSecret` mit einem dreischlüssigen JSON-Payload (`client.crt`, `client.key`, `ca.crt`), getaggt mit `AgentEyeCluster=`. Bei weiteren Aufrufen: `PutSecretValue` zur Veröffentlichung einer neuen Version; Tag wird per `TagResource` aktualisiert. | +| 4 | Löscht `issued//` erst nach erfolgreichem Upload. Bei Fehler bleibt das Verzeichnis erhalten, damit Sie den Vorgang wiederholen können. | + +**Wenn das Secret zur Löschung vorgemerkt ist**, schlägt das Skript mit einer klaren Fehlermeldung fehl und fordert Sie auf, `aws secretsmanager restore-secret --secret-id agenteye/mtls-client/` auszuführen, bevor Sie es erneut versuchen. + +Vollständige Pod-Verdrahtung (SecretProviderClass, IRSA-Setup, Rotationsverhalten, Fehlersuche) siehe [enterprise-docs/single-pod-deployment.md](/de/agenteye/single-pod-deployment). + +--- + +### 5.2 Funktionsfähigkeit des Zertifikats prüfen + +Testen Sie das ausgestellte Zertifikat gegen den mTLS-Ingress: + +```bash +curl -sk --cert issued//client.crt \ + --key issued//client.key \ + https://${PUBLIC_IP}/health +``` + +Erwartet: `{"status":"ok"}` + +**Bei Fehler:** + +| Fehler | Ursache | Behebung | +|---|---|---| +| `certificate required` | Zertifikat wird nicht vorgelegt | Dateipfade im `curl`-Befehl prüfen | +| `bad certificate` | CA-Mismatch | Prüfen, ob `mtls-ca-issuer` das Zertifikat ausgestellt hat: `kubectl describe certificate mtls-client- -n agenteye` | +| `connection refused` | Falscher Hostname oder LB nicht erreichbar | `/etc/hosts` oder DNS prüfen | + +--- + +### 5.3 An den Collector-Cluster übergeben + +Senden Sie `collector-mtls-secret.yaml` an das Team, das den Collector-Cluster betreibt. Es wendet die Datei an: + +```bash +kubectl apply -f collector-mtls-secret.yaml -n +``` + +Konfigurieren Sie dann den Collector, das Secret zu mounten und die Zertifikatspfade zu verwenden: + +```json +{ + "tls_cert": "/etc/agenteye/tls/client.crt", + "tls_key": "/etc/agenteye/tls/client.key" +} +``` + +Die vollständige Collector-Einrichtung einschließlich Kubernetes-Volume-Mounts finden Sie unter [enterprise-docs/collector-installation.md](/de/agenteye/collector-installation). + +**Test (im Collector-Cluster):** + +```bash +kubectl get secret agenteye-collector-mtls -n +``` + +Erwartet: Das Secret existiert mit 3 Datenschlüsseln (`client.crt`, `client.key`, `ca.crt`). + +--- + +### 5.4 Zertifikat-Lebenszyklus + +| Eigenschaft | Wert | +|---|---| +| Client-Zertifikat-Gültigkeit | 90 Tage | +| Automatische Erneuerung | cert-manager erneuert 15 Tage vor Ablauf | +| CA-Gültigkeit | 10 Jahre | +| Ablaufwarnungen | CronJob warnt 30 Tage vor Ablauf (Phase 6) | + +cert-manager erneuert das Zertifikat automatisch auf dem **AgentEye-Cluster**, aber das erneuerte Zertifikat muss erneut an den Collector-Cluster übergeben werden. Führen Sie `issue-client-cert.sh` erneut aus und wenden Sie `collector-mtls-secret.yaml` erneut an, bevor das alte Zertifikat abläuft. + +Wenn Sie `--save-to aws-secrets-manager` verwenden (siehe § 5.1b), führen Sie denselben Befehl erneut aus. Das Skript ruft `PutSecretValue` auf dem gleichen Secret auf; Pods, die das Secret über den Secrets Store CSI Driver mounten, übernehmen die neue Version beim nächsten Rotations-Poll (Standard: stündlich), ohne Pod-Neustart. + +--- + +### 5.5 Zertifikat widerrufen + +Um den Collector-Zugriff eines Clusters sofort zu sperren: + +```bash +kubectl delete certificate mtls-client- -n agenteye +``` + +**Test:** Der `curl`-Befehl aus Schritt 5.2 schlägt nun mit einem TLS-Handshake-Fehler fehl. + +--- + +## Phase 6 -- Zertifikat-Erneuerungsüberwachung (~2 Min.) + +Ein integrierter CronJob läuft alle 12 Stunden (03:00 und 15:00 UTC) und prüft alle Client-Zertifikate mit dem Label `agenteye.io/cert-type=mtls-client`. Er warnt, wenn ein Zertifikat innerhalb von 30 Tagen abläuft. + +### 6.1 Slack-Benachrichtigungen aktivieren (optional) + +```bash +kubectl create secret generic cert-renewal-notify-config \ + --namespace agenteye \ + --from-literal=SLACK_WEBHOOK_URL="https://hooks.slack.com/services/IHR/WEBHOOK/URL" +``` + +Ohne dieses Secret läuft der CronJob weiterhin und protokolliert den Zertifikatsstatus in stdout. + +**Test:** + +```bash +kubectl get secret cert-renewal-notify-config -n agenteye +``` + +Erwartet: Das Secret ist vorhanden. + +--- + +### 6.2 CronJob testen + +```bash +kubectl create job --from=cronjob/cert-renewal-check test-cert-check -n agenteye + +kubectl wait --for=condition=Complete job/test-cert-check -n agenteye --timeout=60s + +kubectl logs -n agenteye -l job-name=test-cert-check +``` + +Erwartet: Eine Liste von Zertifikaten mit ihrem Ablaufstatus. Wenn der Slack-Webhook konfiguriert ist, prüfen Sie den Slack-Kanal auf die Warnmeldung. + +**Bei Fehler:** Prüfen Sie RBAC -- der ServiceAccount des CronJob benötigt `get, list`-Berechtigungen für cert-manager-Certificate-Ressourcen. Überprüfen mit: `kubectl describe role cert-renewal-check -n agenteye`. + +Test-Job aufräumen: + +```bash +kubectl delete job test-cert-check -n agenteye +``` + +--- + +## Phase 7 -- End-to-End-Verifizierung + +Diese Phase bestätigt, dass die gesamte Pipeline funktioniert: Healthcheck, Key-Erstellung, Event-Ingestion und Dashboard-Anzeige. + +> **Hinweis:** Die folgenden Beispiele erreichen den Ingest-Endpunkt der Einfachheit halber über seine rohe LoadBalancer-Adresse (`${PUBLIC_IP}`), weshalb sie `-k` übergeben; das Server-Zertifikat ist an `INGEST_DOMAIN` gebunden, nicht an die LB-IP, daher wird die Hostname-Prüfung übersprungen. Der Ingest-Endpunkt erzwingt Mutual TLS auf **jedem** Pfad, daher muss jeder Aufruf ebenfalls ein Client-Zertifikat vorlegen (`--cert`/`--key`). Um auch das öffentliche Zertifikat zu validieren, verwenden Sie `https://ingest.ihre-firma.example/...` statt `${PUBLIC_IP}` und lassen Sie `-k` weg. + +### 7.1 Healthcheck + +```bash +curl -sk --cert issued//client.crt \ + --key issued//client.key \ + https://${PUBLIC_IP}/health +``` + +Erwartet: `{"status":"ok"}` mit HTTP 200. + +--- + +### 7.2 Scoped Collector-Keys erstellen + +Der Admin-Key dient dem Bootstrap und der Verwaltung. Erstellen Sie dedizierte `events:add`-Keys für Collectors: + +```bash +COLLECTOR_KEY=$(openssl rand -hex 32) + +curl -sk -X POST https://${PUBLIC_IP}/keys \ + --cert issued//client.crt \ + --key issued//client.key \ + -H "Authorization: Bearer ${ADMIN_KEY}" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "prod-collector", + "key": "'"${COLLECTOR_KEY}"'", + "permissions": ["events:add"] + }' +``` + +**Test:** Die Antwort enthält `"id"`, `"name": "prod-collector"`, `"permissions": ["events:add"]`, `"created_at"`. + +**Test:** Prüfen, ob der Key in der Key-Liste erscheint: + +```bash +curl -sk https://${PUBLIC_IP}/keys \ + --cert issued//client.crt \ + --key issued//client.key \ + -H "Authorization: Bearer ${ADMIN_KEY}" +``` + +Erwartet: `prod-collector` erscheint in der Antwort. + +Die vollständige Key-Management-Referenz finden Sie unter [enterprise-docs/api-keys.md](/de/agenteye/api-keys). + +--- + +### 7.3 Test-Event einspielen + +```bash +echo '{"session_id":"test","agent_id":"smoke-test","type":"test","timestamp":"2026-04-20T00:00:00Z"}' \ + | curl -sk --cert issued//client.crt \ + --key issued//client.key \ + -H "Authorization: Bearer ${COLLECTOR_KEY}" \ + -H "Content-Type: application/x-ndjson" \ + --data-binary @- \ + https://${PUBLIC_IP}/events +``` + +Erwartet: `{"accepted":1,"skipped":0}` mit HTTP 200. + +**Bei Fehler:** + +| HTTP-Status | Ursache | +|---|---| +| 401 | Ungültiger oder fehlender API-Key | +| 403 | Key hat keine `events:add`-Berechtigung | +| TLS-Handshake-Fehler | Client-Zertifikat-Problem -- siehe Phase 5 Fehlersuche | + +--- + +### 7.4 Event im Dashboard prüfen + +Öffnen Sie `https://agenteye.ihre-firma.example` (Ihre `DASHBOARD_DOMAIN`) in einem Browser. Das Zertifikat ist öffentlich vertrauenswürdig, daher gibt es keine Warnung. + +> Wenn der Dashboard-LoadBalancer per IP-Allowlist eingeschränkt ist und Sie keine Verbindung herstellen können, prüfen Sie, ob Ihre IP erlaubt ist: +> ```bash +> kubectl get svc traefik-dashboard -n traefik-dashboard -o jsonpath='{.spec.loadBalancerSourceRanges}' +> ``` +> Beachten Sie, dass Let's Encrypt das Dashboard-Zertifikat über HTTP-01 auf Port 80 erneuert und Source Ranges für den gesamten LoadBalancer gelten -- schränken Sie ihn erst auf Unternehmens-Ranges ein, nachdem Sie einen DNS-01-Solver mit dem Support koordiniert haben, oder Erneuerungen schlagen lautlos fehl. + +**Test:** Das Smoke-Test-Event sollte in der Ereignisliste mit Session `test` und Agent `smoke-test` erscheinen. + +**Bei Fehler:** Dashboard-Logs prüfen (`kubectl logs -n agenteye -l app=dashboard --tail=50`). Prüfen, ob `AGENTEYE_SERVER_URL` und `AGENTEYE_API_KEY` korrekt gesetzt sind. + +--- + +### 7.5 Backup-CronJob testen + +```bash +kubectl create job --from=cronjob/agenteye-backup test-backup -n agenteye + +kubectl wait --for=condition=Complete job/test-backup -n agenteye --timeout=300s + +kubectl logs -n agenteye -l job-name=test-backup +``` + +Erwartet: `Backup created: agenteye-YYYYMMDD-HHMMSS.tar.gz (NNN)` in den Logs; das Archiv bündelt den Postgres-Dump und die ClickHouse-Tabellen. + +> Der S3-Upload-Schritt ist im CronJob bereits verdrahtet und wird ausgeführt, wenn `BACKUP_BUCKET` gesetzt ist (die Basis liefert einen Standard-Bucket-Wert). Er wird nur übersprungen, wenn `BACKUP_BUCKET` leer oder buchstäblich `PLACEHOLDER` ist. Zeigen Sie ihn auf Ihren eigenen Bucket und erteilen Sie dem `agenteye-backup`-ServiceAccount Schreibzugriff, bevor Sie sich darauf verlassen (siehe Abschnitt Backups unten). + +Aufräumen: + +```bash +kubectl delete job test-backup -n agenteye +``` + +--- + +### 7.6 Organisationen bereitstellen (Multi-Tenant) + +Überspringen Sie dies für eine Single-Tenant-Bereitstellung; alle Daten liegen in der eingebauten `default`-Org und nichts hier ist erforderlich. + +Wenn Sie mehrere isolierte Mandanten betreiben, werden Organisationen und ihre Mitgliedschaften mit der **`agenteye-orgctl`**-CLI erstellt. Sie ist **im Server-Image** enthalten (neben `agenteye-server`) und wird **im bestehenden `server`-Deployment mit `kubectl exec` ausgeführt; es gibt keinen separaten Pod, Job oder Deployment und keine HTTP-API oder Dashboard-Schaltfläche für den Mandanten-Lebenszyklus.** Das Ausführen im Server-Pod bedeutet, dass `DATABASE_URL`, `CLICKHOUSE_URL` und `ORG_CH_SECRET` aus §2.6 des Pods wiederverwendet werden. + +> **Voraussetzung:** Schließen Sie §2.6 zuerst ab. `org create` verweigert die Ausführung, solange der Server noch den eingebauten Dev-`ORG_CH_SECRET` verwendet, und der pro-Org ClickHouse-Benutzer, den er provisioniert, hängt davon ab, dass dieses Secret stark und stabil ist. + +**Org erstellen und ersten Admin hinzufügen:** + +kubectl -n agenteye exec deploy/server -- \ + agenteye-org \ No newline at end of file diff --git a/docs/de/agenteye/managed-deployment.mdx b/docs/de/agenteye/managed-deployment.mdx new file mode 100644 index 00000000..b44ec46e --- /dev/null +++ b/docs/de/agenteye/managed-deployment.mdx @@ -0,0 +1,171 @@ +--- +title: "Managed Deployment auf Ihrem Kubernetes-Cluster" +description: "Dokumentation zur AgentEye Managed Deployment auf Ihrem Kubernetes-Cluster." +--- + + +AgentEye ist eine selbst gehostete Observability- und Evaluierungsplattform für KI- und LLM-Agenten. Sie erfasst Agentensitzungen, Tool-Aufrufe, Modellanfragen und Fehler, wandelt diese in durchsuchbare Analysen und Evaluierungen um und stellt die Ergebnisse in einem Dashboard mit einem optionalen schreibgeschützten KI-Assistenten bereit. + +Im Managed-Deployment-Modell stellen Sie einen dedizierten Kubernetes-Cluster zur Verfügung, und Exosphere betreibt die gesamte Plattform darin – Deployment, Konfiguration, Betrieb, Backups und Upgrades aller Komponenten erfolgen in Ihrem Namen. Ihr Team profitiert vom vollen Mehrwert der Plattform (Agenten-Transparenz, Analysen, Evaluierung und der optionale Assistent), ohne Datenbanken, Zertifikate oder Upgrades selbst verwalten zu müssen. Alle Daten verbleiben in Ihrem Cloud-Konto. + +--- + +## Voraussetzungen + +- Ein **GitHub PAT** zum Abrufen von Container-Images und zum Herunterladen von Artefakten (siehe [GitHub Token Setup](/de/agenteye/github-token)) +- Ein **dedizierter Kubernetes-Cluster** (siehe Anforderungen unten) +- Ein **Storage-Bucket** für Datenbank-Backups +- **Netzwerkkonnektivität**: Port 443 eingehend zum Load Balancer des Clusters + +--- + +## Schritt 1: Einen dedizierten Kubernetes-Cluster bereitstellen + +Erstellen Sie einen Kubernetes-Cluster, der ausschließlich für AgentEye vorgesehen ist. Er sollte nicht mit anderen Workloads geteilt werden, damit die gesamte Plattform (Anwendungsdienste, Datenbanken, Analysen und Caching) isoliert läuft, ohne Ihre bestehende Infrastruktur zu beeinträchtigen. + +| Anforderung | Details | +|---|---| +| **Distribution** | Jedes konforme Kubernetes: EKS, GKE, AKS oder selbst verwaltet | +| **Version** | 1.27 oder höher | +| **Node-Pool** | Mindestens: **3 Nodes, je 4 vCPU / 8 GB RAM** (Standard-General-Purpose-Instanzen) | +| **Storage** | Eine Standard-StorageClass, die Block-Volumes bereitstellt (z. B. `gp3` auf AWS, `pd-ssd` auf GCP) | +| **Load Balancer** | Der Cluster muss in der Lage sein, Cloud-LoadBalancer-Services bereitzustellen (Standard bei EKS, GKE, AKS) | + +> Exosphere installiert und verwaltet alles Weitere innerhalb des Clusters: Ingress-Controller, TLS-Zertifikate, Datenbanken, Caching, Monitoring und alle Anwendungs-Deployments. + +--- + +## Schritt 2: Dem AgentEye-Team Zugriff gewähren + +Exosphere benötigt Cluster-Admin-Zugriff (oder gleichwertige umfangreiche RBAC-Berechtigungen), um Namespaces, Custom Resource Definitions, Ingress-Controller und Storage-Provisioner zu verwalten. + +| Anforderung | Details | +|---|---| +| **Zugriffsmethode** | IAM-Rolle (bevorzugt für EKS/GKE), kubeconfig oder SSO-basierter Zugriff | +| **VPN / Bastion** | Falls der Kubernetes-API-Server privat ist, stellen Sie VPN-Zugangsdaten oder Bastion-Zugriff für das Exosphere-Operations-Team bereit | + +--- + +## Schritt 3: Netzwerkkonnektivität konfigurieren + +Ihr Netzwerk-Team muss eingehenden Traffic auf **Port 443** zu den Load Balancern des Clusters erlauben. Das Deployment betreibt zwei separate Load Balancer: einen für die Event-Ingestion (mTLS-geschützt) und einen für das Dashboard: + +| Traffic | Quelle | Ziel | Sicherheit | +|---|---|---|---| +| **Event-Ingestion** | Collector-Pods in Ihren Clustern | Ingest LoadBalancer, Port 443 | mTLS (Client-Zertifikat) + API-Schlüssel | +| **Dashboard** | Entwickler-Browser | Dashboard LoadBalancer, Port 443 | HTTPS auf Ihrer Domain, passwortloser E-Mail-OTP-Login | + +Der Ingest-Endpunkt ist durch Mutual TLS geschützt; Collectors müssen bei jeder Anfrage sowohl ein gültiges Client-Zertifikat **als auch** einen gültigen API-Schlüssel vorweisen. Das Dashboard läuft auf seinem eigenen Load Balancer und Hostnamen, wobei der Login auf Ihre freigeschalteten E-Mail-Adressen/Domains beschränkt ist. + +**DNS-Einträge (einmalig):** Sie erstellen zwei CNAME-Einträge unter einer Domain Ihrer Wahl – einen für den Ingest-Endpunkt und einen für das Dashboard (z. B. `agenteye.ihr-unternehmen.beispiel`) – die auf die von Exosphere bereitgestellten Load-Balancer-Hostnamen verweisen. Exosphere stellt anschließend automatisch öffentlich vertrauenswürdige TLS-Zertifikate für beide Hostnamen bereit, einschließlich der Erneuerung. + +> **Hinweis zu Port 80:** Die automatisierte Zertifikatsausstellung und -erneuerung erfolgt über HTTP auf Port 80 jedes Load Balancers. Falls Ihre Sicherheitsrichtlinien es erfordern, den Dashboard-Load-Balancer auf unternehmenseigene IP-Bereiche zu beschränken, informieren Sie Exosphere im Voraus – wir wechseln dann zur DNS-basierten Zertifikatsvalidierung (ein zusätzlicher DNS-Eintrag auf Ihrer Seite), damit Erneuerungen auch hinter der Einschränkung funktionieren. + +> **Ausgehend:** Cluster-Nodes benötigen Internetzugang, um Container-Images von `ghcr.io` abzurufen. Falls Ihr Netzwerk ausgehenden Traffic einschränkt, nehmen Sie `ghcr.io` in die Allowlist auf oder spiegeln Sie Images in Ihre interne Registry. + +--- + +## Schritt 4: Einen Backup-Storage-Bucket bereitstellen + +Datenbank-Backups werden in einem Cloud-Storage-Bucket gespeichert, der Ihnen gehört. + +| Anforderung | Details | +|---|---| +| **Dienst** | S3 (AWS), GCS (GCP) oder Azure Blob Storage | +| **Zugriff** | Erteilen Sie den Cluster-Nodes Schreibzugriff über IAM-Rolle für Service Accounts (IRSA auf EKS, Workload Identity auf GKE) oder stellen Sie Zugangsdaten bereit | +| **Aufbewahrung** | Sie steuern die Lifecycle-Policy des Buckets (Aufbewahrungszeitraum, Archivierungsregeln). Exosphere schreibt Backups; Sie entscheiden, wie lange diese aufbewahrt werden | + +Ein tägliches Backup sichert sowohl PostgreSQL (relationaler Zustand) als auch ClickHouse (Events und Evaluierungen) in einem komprimierten Archiv und lädt es in Ihren Bucket hoch. Backups werden auch vor jedem Upgrade durchgeführt. + +--- + +## Schritt 5: Einen Ansprechpartner benennen + +Benennen Sie eine Person oder einen Slack/Teams-Kanal auf Ihrer Seite für Probleme auf Cluster-Ebene: Node-Gesundheit, Cloud-Kontolimits, Netzwerkänderungen. Der tägliche Betrieb erfordert diesen Kontakt nicht. + +--- + +## Was wir deployen + +Sobald Exosphere Cluster-Zugriff hat, werden folgende Komponenten für Sie deployed und verwaltet: + +| Komponente | Rolle | +|---|---| +| **AgentEye Server** | HTTP-API, die Events von Collectors empfängt, Analysen ausführt und Daten an das Dashboard liefert | +| **Dashboard** | Web-Interface zur Anzeige von Agentensitzungen, Tool-Aufrufen, Modellanfragen und Fehlern; beherbergt den optionalen schreibgeschützten KI-Assistenten | +| **ClickHouse** | Erforderlicher kanonischer Speicher für aufgenommene Events, Analysen und Evaluierungen | +| **PostgreSQL** | Relationaler Speicher für Organisationen, API-Schlüssel, Benutzer, Dashboards und gespeicherte Abfragen | +| **Redis** | Optionaler gemeinsamer Cache und Rate-Limit-Backend; die Plattform degradiert bei Nichtverfügbarkeit graceful | +| **KI-Assistent (optional)** | Interner schreibgeschützter Assistenten-Container; bleibt deaktiviert, bis ein LLM-Endpunkt konfiguriert ist | +| **Ingress-Controller** | Zwei Load Balancer (einer für mTLS-geschützten Ingest, einer für das Dashboard), die TLS mit öffentlich vertrauenswürdigen, automatisch erneuerten Zertifikaten terminieren und mTLS am Ingest-Endpunkt durchsetzen | +| **cert-manager** | Automatisiert die TLS-Zertifikatsbereitstellung und die Ausstellung von mTLS-Client-Zertifikaten | +| **Zertifikats-Monitoring** | Ein geplanter Job prüft den Ablauf von Zertifikaten und sendet Benachrichtigungen (z. B. an Slack), wenn Zertifikate kurz vor der Erneuerung stehen | + +Das Managed-Angebot betreibt auch die Evaluierungspipeline der Plattform, die Agentenaktivitäten anhand Ihrer Evaluierungskriterien bewertet. Siehe [Assistant](/de/agenteye/assistant) und [Evaluation Suite](/de/agenteye/evaluation-suite) für Details zu diesen Funktionen. + +--- + +## Was wir Ihnen bereitstellen + +Nach Abschluss des Deployments erhalten Sie: + +| Element | Details | +|---|---| +| **Dashboard-URL** | Ein Hostname unter Ihrer Domain (z. B. `https://agenteye.ihr-unternehmen.beispiel`), bereitgestellt mit einem öffentlich vertrauenswürdigen, automatisch erneuerten TLS-Zertifikat. Sie erstellen einen CNAME auf den von uns bereitgestellten Load-Balancer-Hostnamen; der Login erfolgt über passwortlosen E-Mail-OTP | +| **Collector-Endpunkt** | Der `/events`-Pfad des Ingest-Hostnamens (z. B. `https://ingest.ihr-unternehmen.beispiel/events`), mTLS-geschützt | +| **Client-Zertifikatspaket** | Pro Cluster: Client-Zertifikat, privater Schlüssel und CA-Zertifikat, geliefert als Kubernetes-Secret-Manifest. Einmalig pro Cluster anwenden | +| **GitHub PAT** | Zum Herunterladen von Collector-Binärdateien und Python-SDK-Paketen | +| **Collector-API-Schlüssel** | Bereichsbegrenzte Schlüssel mit `events:add`-Berechtigung, einer pro Collector-Deployment | +| **Installationsanleitungen** | Schritt-für-Schritt-Dokumentation für Collector und Python SDK | + +--- + +## Was Sie nach dem Setup tun + +Ihre einzige laufende Arbeit betrifft Ihre eigenen Agent-Maschinen, nicht den AgentEye-Cluster: + +1. **Installieren Sie den Collector** in jedem Kubernetes-Cluster, der KI-Agenten ausführt: Mounten Sie das Client-Zertifikat und konfigurieren Sie die Endpunkt-URL und den API-Schlüssel. Siehe [Collector Installation](/de/agenteye/collector-installation). +2. **Integrieren Sie das Python SDK** in Ihren Agenten-Code. Siehe [Python SDK](/de/agenteye/python-sdk). +3. **Öffnen Sie das Dashboard** in Ihrem Browser, um die Agentenaktivität einzusehen. + +Kein Cluster-Betrieb, kein Datenbankmanagement, keine Zertifikatserneuerungen, keine Upgrades. + +--- + +## Sicherheit + +- **Daten verbleiben in Ihrem Cloud-Konto.** Cluster, Storage und Datenbanken laufen alle in Ihrer Umgebung. Keine Daten verlassen Ihren Perimeter. +- **Sie kontrollieren den Zugriff.** Der Cluster liegt in Ihrem Konto. Sie können den Zugriff von Exosphere jederzeit prüfen, überwachen oder entziehen. Alle Operationen werden im Audit-Log Ihrer Cloud erfasst (CloudTrail, GCP Audit Logs usw.). +- **mTLS bei der Event-Ingestion.** Jede Collector-Anfrage erfordert sowohl ein gültiges Client-Zertifikat als auch einen API-Schlüssel. Ein geleakter Schlüssel ist ohne das Zertifikat wertlos; ein gestohlenes Zertifikat ist ohne einen gültigen Schlüssel nutzlos. +- **Dashboard-Zugangskontrolle.** Das Dashboard läuft auf seinem eigenen Load Balancer, getrennt von der Event-Ingestion, und der Login erfolgt über passwortlosen E-Mail-OTP, beschränkt auf die von Ihnen freigeschalteten E-Mail-Adressen/Domains. Eine IP-Quelladressen-Allowlist am Load Balancer ist auf Anfrage verfügbar; da die automatische Zertifikatserneuerung den Load Balancer erreichen muss, kombiniert Exosphere die Einschränkung mit DNS-basierter Zertifikatsvalidierung, damit Erneuerungen weiterhin funktionieren. +- **Cluster-spezifische Zertifikate.** Jeder Ihrer Cluster erhält ein eigenes Client-Zertifikat. Wird ein Cluster kompromittiert, kann dieses Zertifikat unabhängig widerrufen werden, ohne andere zu beeinträchtigen. + +--- + +## Deployment-Zeitplan + +| Phase | Dauer | Ihre Beteiligung | +|---|---|---| +| **Cluster-Bereitstellung** | 1–2 Tage | Cluster bereitstellen und Exosphere Zugriff gewähren | +| **Plattform-Setup** | 1 Tag | Keine; Exosphere installiert alle Infrastrukturkomponenten | +| **Anwendungs-Deployment** | 1 Tag | Keine; Exosphere deployed Server, Dashboard und erstellt API-Schlüssel | +| **Collector-Rollout** | 1–3 Tage | Collectors in Ihren Clustern installieren (mit Unterstützung durch Exosphere) | +| **Produktions-Burn-in** | 1 Woche | Keine; Exosphere überwacht und optimiert | + +Typische Gesamtdauer: **~2 Wochen** vom Kickoff bis zur Produktionsreife. + +--- + +## Support + +Bei Fragen oder Problemen wenden Sie sich an Exosphere unter `support@exosphere.host`. + +--- + +## Nächste Schritte + +- [Getting Started](/de/agenteye/getting-started): Vollständige End-to-End-Einführung +- [Collector Installation](/de/agenteye/collector-installation): Collector installieren und konfigurieren +- [Python SDK](/de/agenteye/python-sdk): Ihren Agenten-Code instrumentieren +- [API Keys](/de/agenteye/api-keys): Zugriff und Berechtigungen verwalten +- [Troubleshooting](/de/agenteye/troubleshooting): Häufige Probleme und Lösungen \ No newline at end of file diff --git a/docs/de/agenteye/python-sdk.mdx b/docs/de/agenteye/python-sdk.mdx new file mode 100644 index 00000000..c687693c --- /dev/null +++ b/docs/de/agenteye/python-sdk.mdx @@ -0,0 +1,383 @@ +--- +title: "Python SDK" +description: "AgentEye Python SDK Dokumentation." +--- + + +Das AgentEye Python SDK gibt Ihnen vollständige Einsicht in das Verhalten Ihrer Agenten (jeden Agentenlauf, Tool-Aufruf, Modellanfrage, Hook und menschliche Eingriff), damit Sie diese debuggen, auditieren und evaluieren können. Es instrumentiert Ihren Agenten-Code, indem es strukturierte Ereignisse in lokale JSONL-Dateien schreibt; der Collector-Daemon liest diese aus und übermittelt sie automatisch an die Plattform. + +--- + +## Installation + +Laden Sie das Wheel von den GitHub Releases mit Ihrem `AGENTEYE_TOKEN` herunter. Falls Sie noch kein Token besitzen, lesen Sie [GitHub Token Setup](/de/agenteye/github-token) für die Einrichtungsschritte und erforderlichen Berechtigungen. + +**Mit `gh` CLI + pip:** + +```bash +VERSION=0.0.1b9 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "python-sdk/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-*.whl' +pip install "agenteye-${VERSION}-py3-none-any.whl" +``` + +**Mit `gh` CLI + uv:** + +```bash +VERSION=0.0.1b9 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "python-sdk/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-*.whl' +uv add "./agenteye-${VERSION}-py3-none-any.whl" +``` + +**Mit curl (ohne `gh` CLI):** + +```bash +VERSION=0.0.1b9 +curl -fsSL \ + -H "Authorization: Bearer $AGENTEYE_TOKEN" \ + -L \ + "https://github.com/agenteye-enterprise/releases/releases/download/python-sdk%2Fv${VERSION}/agenteye-${VERSION}-py3-none-any.whl" \ + -o "agenteye-${VERSION}-py3-none-any.whl" +pip install "agenteye-${VERSION}-py3-none-any.whl" +``` + +--- + +## Schnellstart + +```python +import agenteye + +agenteye.configure(environment="production") + +agenteye.event.agent_start(session_id="run-001", agent_id="planner", goal="answer user query") + +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", + input={"query": "latest AI research"}, +) + +agenteye.event.tool_result( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", + output={"results": ["..."]}, +) + +agenteye.event.agent_end(session_id="run-001", agent_id="planner", outcome="success") +``` + +--- + +## configure() + +```python +agenteye.configure( + base_dir=None, # Path | str | None. Standard: $AGENTEYE_HOME oder ~/.agenteye + flush_interval=0.5, # float, Sekunden zwischen Flush-Zyklen + environment=None, # str | None. Bezeichnung der Deployment-Umgebung +) +``` + +Einmalig vor einem beliebigen `event.*`-Aufruf aufrufen. Kann weggelassen werden; die Standardwerte funktionieren sofort. Alle Argumente sind nur als Schlüsselwortargumente zulässig; übergeben Sie sie wie oben gezeigt mit Namen. + +Wenn `base_dir` `None` ist (der Standard), liest das SDK `$AGENTEYE_HOME` aus, falls gesetzt, andernfalls wird auf `~/.agenteye` zurückgegriffen. Dies entspricht der eigenen Auflösung des Collectors, sodass eine einzelne `AGENTEYE_HOME`-Umgebungsvariable den gemeinsamen Event-Spool für SDK und Collector konfiguriert – erforderlich für Sidecar- bzw. Single-Pod-Deployments, bei denen beide Prozesse denselben Spool-Pfad verwenden müssen. + +--- + +## Umgebung + +Versehen Sie jedes Ereignis mit einer Deployment-Umgebung (`production`, `staging`, `qa`, `canary` usw.). Einmalig setzen; das SDK hängt sie automatisch an jedes Ereignis an. + +**Option 1: über `configure()`:** + +```python +agenteye.configure(environment="production") +``` + +**Option 2: über Umgebungsvariable:** + +```bash +export AGENTEYE_ENVIRONMENT=production +``` + +**Priorität:** `configure(environment=...)` hat Vorrang vor der Umgebungsvariable. Ist keines von beiden gesetzt, wird standardmäßig `"dev"` verwendet. + +Der Umgebungswert erscheint als erstklassiger Filter im Dashboard und wird als indizierte Spalte auf dem Server für schnelle Abfragen gespeichert. + +**Einschränkung:** Umgebungswerte **dürfen kein literales `,` Komma enthalten**. Die Dashboard-Filter verwenden kommagetrennte Multi-Selects auf der Leitung (`?environment=prod,staging`), sodass eine Umgebung namens `prod,blue` in zwei Werte aufgeteilt würde. Ereignisse mit kommaenthaltenden Umgebungen werden beim Einlesen abgelehnt. + +--- + +## Ereignis-Referenz + +Alle Ereignismethoden erfordern diese zwei Felder: + +| Feld | Typ | Beschreibung | +|---|---|---| +| `session_id` | `str` | Identifiziert den übergeordneten Agentenlauf | +| `agent_id` | `str` | Identifiziert, welcher Agent innerhalb der Sitzung das Ereignis ausgelöst hat | + +Alle Methoden akzeptieren außerdem beliebige `**kwargs` für benutzerdefinierte Metadaten (siehe [Benutzerdefinierte Felder](#custom-fields)). + +--- + +### `event.agent_start()` + +Wird ausgelöst, wenn ein Agent mit der Arbeit beginnt. + +```python +agenteye.event.agent_start( + session_id="run-001", + agent_id="planner", + goal="answer user query", # str | None + parent_id=None, # str | None - agent_id des übergeordneten Agenten bei verschachtelten Agenten +) +``` + +--- + +### `event.agent_end()` + +Wird ausgelöst, wenn ein Agent seine Arbeit abschließt. + +```python +agenteye.event.agent_end( + session_id="run-001", + agent_id="planner", + outcome="success", # str | None + summary="Answered query", # str | None +) +``` + +--- + +### `event.tool_use()` + +Wird ausgelöst, wenn ein Agent ein Tool aufruft. Mit `tool_result` kombinieren; das SDK berechnet `duration_ms` automatisch. + +```python +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="web_search", # str, erforderlich + tool_call_id="toolu_01", # str, erforderlich - Korrelationsschlüssel für das passende tool_result + input={"query": "..."}, # dict | None +) +``` + +--- + +### `event.tool_result()` + +Wird ausgelöst, wenn ein Tool zurückgibt. Korreliert mit `tool_use` über `tool_call_id`. + +```python +agenteye.event.tool_result( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", # muss mit dem vorherigen tool_use übereinstimmen + output={"results": ["..."]}, # Any | None + error=None, # str | None - setzen, wenn das Tool eine Ausnahme ausgelöst hat + # duration_ms wird automatisch berechnet - nicht übergeben +) +``` + +--- + +### `event.model_request()` + +Wird unmittelbar vor dem Senden eines Prompts an ein LLM ausgelöst. + +```python +agenteye.event.model_request( + session_id="run-001", + agent_id="planner", + model="claude-sonnet-4-6", # str | None + messages=[ # list[dict] | None - Gesprächsrunden + {"role": "user", "content": "..."}, + ], + system="You are helpful.", # Any | None - str oder Liste von Content-Blöcken + tools=[ # list[dict] | None - dem Modell angebotene Tool-Schemas + {"name": "search", "input_schema": {"type": "object"}}, + ], +) +``` + +`messages`-Einträge akzeptieren entweder einen einfachen String als `content` oder Anthropic-Stil-Listen von Blöcken als `content`. Sampling-Parameter (`temperature`, `max_tokens` usw.) können als zusätzliche kwargs übergeben werden. + +--- + +### `event.model_response()` + +Wird ausgelöst, wenn das LLM eine Antwort zurückgibt. + +```python +agenteye.event.model_response( + session_id="run-001", + agent_id="planner", + model="claude-sonnet-4-6", # str | None + stop_reason="end_turn", # str | None + input_tokens=1024, # int | None + output_tokens=256, # int | None + content=[ # Any | None - str oder Liste von Content-Blöcken + {"type": "text", "text": "..."}, + ], + role="assistant", # str | None +) +``` + +`content` akzeptiert entweder einen einfachen String (generische Anbieter) oder eine Liste von Anthropic-Stil-Content-Blöcken. Tool-Aufrufe befinden sich in `content` als `{"type": "tool_use", ...}`-Blöcke, ohne separates `tool_calls`-Feld. + +--- + +### `event.hook_triggered()` + +Wird ausgelöst, wenn ein Hook feuert. Mit `hook_completed` kombinieren; das SDK berechnet `duration_ms` automatisch. + +```python +agenteye.event.hook_triggered( + session_id="run-001", + agent_id="planner", + hook_name="pre_tool_use", # str, erforderlich + hook_id="hook-abc", # str, erforderlich - Korrelationsschlüssel + trigger_event="tool_use", # str | None + input={"tool": "search"}, # Any | None +) +``` + +--- + +### `event.hook_completed()` + +Wird ausgelöst, wenn ein Hook abgeschlossen ist. Korreliert mit `hook_triggered` über `hook_id`. + +```python +agenteye.event.hook_completed( + session_id="run-001", + agent_id="planner", + hook_name="pre_tool_use", + hook_id="hook-abc", # muss mit dem vorherigen hook_triggered übereinstimmen + outcome="allow", # str | None + output=None, # Any | None + error=None, # str | None + # duration_ms wird automatisch berechnet - nicht übergeben +) +``` + +--- + +### `event.error()` + +Wird ausgelöst, wenn ein unbehandelter Fehler auftritt. + +```python +agenteye.event.error( + session_id="run-001", + agent_id="planner", + error_type="TimeoutError", # str, erforderlich + message="timed out", # str, erforderlich + traceback="Traceback...", # str | None +) +``` + +--- + +## Human-in-the-Loop-Ereignisse + +Human-in-the-Loop-Ereignisse geben Ihnen Kontrolle über die Momente, in denen eine Person in die Ausführung des Agenten eingreift (Warten auf Genehmigung, Eingabe liefern, Pausieren oder Stoppen des Agenten). Sie ermöglichen es Ihnen, zu messen, wie lange Menschen für eine Antwort benötigen (das SDK berechnet `duration_ms` bei den gepaarten Ereignissen automatisch), zu auditieren, wer einen Agenten pausiert oder unterbrochen hat, sowie Genehmigungs- und Überwachungsworkflows aufzubauen, die im Dashboard sichtbar sind. + +### `event.human_wait()` + +Wird ausgelöst, wenn der Agent die Ausführung anhält, um auf eine menschliche Eingabe zu warten. Mit `human_input` kombinieren; das SDK berechnet `duration_ms` automatisch (wie lange der Mensch für eine Antwort benötigt hat). + +```python +agenteye.event.human_wait( + session_id="run-001", + agent_id="planner", + input_id="inp-abc", # str, erforderlich - Korrelationsschlüssel für das passende human_input + prompt="Do you approve this action?", # str | None - die dem Menschen angezeigte Frage + options=["approve", "reject", "defer"], # list[str] | None - dem Menschen präsentierte Auswahlmöglichkeiten + reason="approval_required", # str | None - warum der Agent wartet +) +``` + +### `event.human_input()` + +Wird ausgelöst, wenn ein Mensch eine Eingabe liefert und der Agent fortsetzt. Korreliert mit `human_wait` über `input_id`. `duration_ms` wird automatisch berechnet und darf nicht vom Aufrufer übergeben werden. + +```python +agenteye.event.human_input( + session_id="run-001", + agent_id="planner", + input_id="inp-abc", # str, erforderlich - muss mit dem vorherigen human_wait übereinstimmen + response="approve", # str | None - die Antwort des Menschen (Freitext oder ausgewählte Option) + # duration_ms wird automatisch berechnet - nicht übergeben +) +``` + +### `event.human_pause()` + +Wird ausgelöst, wenn ein Mensch den Agenten aktiv pausiert (z. B. über eine Dashboard-Steuerung). Der Agent wird angehalten, aber nicht beendet. + +```python +agenteye.event.human_pause( + session_id="run-001", + agent_id="planner", + reason="user_requested", # str | None + user_id="usr_42", # str | None - wer den Agenten pausiert hat +) +``` + +### `event.human_interrupt()` + +Wird ausgelöst, wenn ein Mensch den Agenten während der Ausführung aktiv stoppt. Im Gegensatz zu `human_pause` wird die Arbeit des Agenten beendet statt nur pausiert. + +```python +agenteye.event.human_interrupt( + session_id="run-001", + agent_id="planner", + reason="output_incorrect", # str | None + user_id="usr_42", # str | None - wer den Agenten unterbrochen hat + at_step="tool_use:web_search", # str | None - was der Agent beim Stoppen gerade tat +) +``` + +--- + +## Benutzerdefinierte Felder + +Beliebige zusätzliche Schlüsselwortargumente werden nach den Standardfeldern an das Ereignis angehängt: + +```python +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="db_query", + tool_call_id="toolu_02", + tenant_id="acme", # benutzerdefiniertes Feld + region="us-east-1", # benutzerdefiniertes Feld +) +``` + +`timestamp`, `type` und `environment` sind reserviert und lösen `ValueError` aus (`Reserved field names cannot be used as custom fields: [...]`), wenn sie als benutzerdefinierte Felder übergeben werden. `session_id` und `agent_id` sind Pflichtparameter für jede Ereignismethode und können nicht ein zweites Mal übergeben werden; Python löst `TypeError` aus, wenn Sie es versuchen. Legen Sie die Umgebung stattdessen mit `configure(environment=...)` (oder der `AGENTEYE_ENVIRONMENT`-Variable) fest. + +--- + +## Wie Ereignisse geschrieben werden + +Ereignisse werden prozessintern gepuffert und alle `flush_interval` Sekunden auf die Festplatte geschrieben (Standard 500 ms). Jeder Flush schreibt eine JSONL-Datei: + +``` +~/.agenteye/events/event-2026-04-01T12-00-00-000Z.jsonl +``` + +Der Collector überwacht dieses Verzeichnis und lädt Dateien automatisch hoch. Sie müssen diese Dateien nicht direkt verwalten. \ No newline at end of file diff --git a/docs/de/agenteye/single-pod-deployment.mdx b/docs/de/agenteye/single-pod-deployment.mdx new file mode 100644 index 00000000..c928e80a --- /dev/null +++ b/docs/de/agenteye/single-pod-deployment.mdx @@ -0,0 +1,484 @@ +--- +title: "Single-Pod-Deployment: Collector + Application-Sidecar auf EKS" +description: "AgentEye Single-Pod-Deployment: Dokumentation für Collector + Application-Sidecar auf EKS." +--- + + +Betreiben Sie Ihre Anwendung und den AgentEye-Collector **im selben Kubernetes-Pod**, sodass Telemetriedaten zur Erfassung niemals eine Netzwerkgrenze überschreiten müssen. Das SDK Ihrer Anwendung und der Collector teilen sich einen gemeinsamen In-Pod-Ereignis-Spool, was einen latenzarmen, prozessinternen Telemetrie-Übergabe ohne exponierten localhost-Port, ohne Durchquerung eines Service-Mesh und mit einem direkt an die beobachtete Arbeitslast gebundenen Collector-Lebenszyklus ermöglicht. Das mTLS-Client-Zertifikat, das der Collector vorlegt, wird direkt über AWS Secrets Manager in Ihren Pod geliefert, sodass eine Zertifikatsrotation ohne manuelles Verschieben von Dateien auf Ihrer Seite auskommt. + +Das hier beschriebene Sidecar- und Shared-Spool-Modell ist cloud-agnostisch: Zwei Container, die sich ein `emptyDir`-Ereignis-Spool teilen, funktionieren auf jeder Kubernetes-Distribution. Lediglich der Pfad zur Zertifikatsauslieferung in diesem Leitfaden (AWS Secrets Manager + Secrets Store CSI Driver + IRSA) ist spezifisch für AWS/EKS. Wenn Sie eine andere Umgebung verwenden, behalten Sie das Pod- und Spool-Layout bei und ersetzen Sie den Secret-Mount-Mechanismus aus Phase 2 und 3 durch den Ihrer Plattform. + +> **Wann sollte dieses Muster verwendet werden?** Wählen Sie Single-Pod, wenn Ihre Anwendung den Collector nicht über eine Netzwerkgrenze hinweg ansprechen soll (latenzarme In-Pod-IPC, enge Lebenszyklus-Kopplung, Pod-Isolierung pro Mandant). Für Multi-App-Flotten, die einen gemeinsamen Collector pro Node oder Cluster verwenden, lesen Sie stattdessen [enterprise-docs/kubernetes-deployment.md](/de/agenteye/kubernetes-deployment). + +--- + +## Auf einen Blick + +``` +┌──────────────────────────────── Pod ─────────────────────────────────┐ +│ │ +│ ┌──────────────────────┐ ┌──────────────────────┐ │ +│ │ your-app │ │ agenteye-collector │ │ +│ │ (SDK writes JSONL) │ │ (sweeps events/, │ │ +│ │ │ │ uploads over mTLS) │ │ +│ └──────────┬───────────┘ └──────────┬───────────┘ │ +│ │ writes reads │ │ +│ ▼ ▼ │ +│ ┌────────────────────────────────────────────────────┐ │ +│ │ emptyDir: /var/lib/agenteye/{events,failed}/ │ │ +│ │ (AGENTEYE_HOME - shared event spool) │ │ +│ └────────────────────────────────────────────────────┘ │ +│ ▲ │ +│ │ reads cert │ +│ ┌────────┴─────────┐ │ +│ │ CSI (read-only): │ │ +│ │ /etc/agenteye/ │ │ +│ │ tls/client.{crt, │ │ +│ │ key}, ca.crt │ │ +│ └────────┬─────────┘ │ +└───────────────────────────────────────────────────┼──────────────────┘ + │ mounted by + │ Secrets Store CSI + │ (AWS provider + + │ IRSA) + ┌────────┴──────────┐ + │ AWS Secrets │ + │ Manager │ + │ agenteye/mtls- │ + │ client/ │ + └────────┬──────────┘ + ▲ + │ push on issue / + │ renewal + ┌────────┴──────────┐ + │ Exosphere │ + │ delivers the cert │ + │ bundle into your │ + │ Secrets Manager │ + │ on renewal │ + └───────────────────┘ + +Outbound: collector → AGENTEYE_URL (mTLS, using the CSI-mounted cert). +``` + +Zwei Datenflüsse, zwei Volumes: + +- **Ereignisse (In-Pod):** Das SDK Ihrer Anwendung schreibt `.jsonl`-Dateien in das gemeinsame `emptyDir` unter `$AGENTEYE_HOME/events/`; der Collector-Sweeper liest und lädt sie hoch. Kein localhost-Port, kein Loopback – reine Shared-Filesystem-Übergabe. +- **mTLS-Zertifikat (Pod ← Cloud):** Der Secrets Store CSI Driver bindet das Zertifikats-Bundle aus dem Secrets Manager als schreibgeschütztes Volume unter `/etc/agenteye/tls/` ein, begrenzt auf den Collector-Container. + +**Zwei unabhängige Parteien:** + +| Partei | Verantwortlichkeit | +|---|---| +| Exosphere | Stellt das mTLS-Client-Zertifikat aus und liefert das Bundle in das Secrets Manager **Ihres** AWS-Kontos unter einem stabilen Namen. Veröffentlicht das erneuerte Bundle vor Ablauf erneut in demselben Secret. | +| Sie | Installieren den Secrets Store CSI Driver, gewähren dem ServiceAccount des Pods per IRSA Lesezugriff auf das Secret und wenden das Pod-Manifest an. Das ist alles. | + +--- + +## Voraussetzungen + +### In Ihrem AWS-Konto / EKS-Cluster + +- Ein EKS-Cluster mit einem zugehörigen **OIDC-Provider**. Überprüfen Sie dies mit: + + ```bash + aws eks describe-cluster --name \ + --query "cluster.identity.oidc.issuer" --output text + ``` + + Wenn der Befehl eine `https://oidc.eks.…`-URL zurückgibt, ist OIDC aktiviert. Andernfalls verknüpfen Sie einen: + + ```bash + eksctl utils associate-iam-oidc-provider \ + --cluster --approve + ``` + +- Der [Secrets Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/) und der [AWS-Provider](https://github.com/aws/secrets-store-csi-driver-provider-aws) sind im Cluster installiert (siehe § Phase 2). + +- AWS CLI v2 und `kubectl` auf Ihrer Arbeitsstation. + +### Abstimmung mit Exosphere + +Vor der Bereitstellung liefert Exosphere das mTLS-Client-Bundle in das Secrets Manager Ihres AWS-Kontos und stellt Folgendes bereit: + +- Den **Secret-Namen** (Konvention: `agenteye/mtls-client/`) +- Die **AWS-Region**, in der das Secret gespeichert ist +- Die **AgentEye-Backend-URL** zur Konfiguration des Collectors +- Ihren Collector-**API-Key** (siehe [enterprise-docs/api-keys.md](/de/agenteye/api-keys)) + +--- + +## Phase 1: Was Exosphere liefert + +Sie generieren das mTLS-Client-Zertifikat nicht selbst. Exosphere stellt es aus und liefert das Bundle direkt in das Secrets Manager Ihres AWS-Kontos, sodass das einzige Credential-Material, das in Ihrer Umgebung landet, das fertige, einsatzbereite Secret ist. + +Was in Ihrem Konto ankommt: + +| Eigenschaft | Wert | +|---|---| +| Secret-Name | `agenteye/mtls-client/` (stabil über Erneuerungen hinweg) | +| Region | Die AWS-Region, die Sie für Ihren EKS-Cluster festgelegt haben | +| Payload | Ein einzelnes JSON-Secret mit drei Schlüsseln (`client.crt`, `client.key` und `ca.crt`), die jeweils das PEM-kodierte Material enthalten | +| Tag | `AgentEyeCluster=` | + +Bei der Erneuerung wird dasselbe Secret mit einer neuen Version aktualisiert, sodass ARN und Name sich nie ändern; Ihre `SecretProviderClass` und IAM-Policy bleiben unverändert funktionsfähig. Informationen zum Zertifikatslebenszyklus (Gültigkeit, Erneuerungsrhythmus, Ablaufwarnungen) finden Sie unter [enterprise-docs/kubernetes-deployment.md](/de/agenteye/kubernetes-deployment). + +--- + +## Phase 2: Secrets Store CSI Driver + AWS-Provider installieren + +Überspringen Sie diesen Schritt, wenn Sie bereits eine andere Arbeitslast betreiben, die AWS-Secrets per CSI einbindet. + +```bash +# CSI Driver +helm repo add secrets-store-csi-driver \ + https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts +helm install -n kube-system csi-secrets-store \ + secrets-store-csi-driver/secrets-store-csi-driver \ + --set syncSecret.enabled=true \ + --set enableSecretRotation=true \ + --set rotationPollInterval=1h + +# AWS provider +kubectl apply -f \ + https://raw.githubusercontent.com/aws/secrets-store-csi-driver-provider-aws/main/deployment/aws-provider-installer.yaml +``` + +**Überprüfung:** + +```bash +kubectl get pods -n kube-system | grep -E 'csi-secrets-store|aws-provider' +``` + +Erwartet: `Running` für jeden Pod. + +> **Warum `rotationPollInterval=1h`?** Wenn Exosphere ein erneuertes Zertifikat veröffentlicht, wird Secrets Manager direkt aktualisiert. Der CSI Driver liest das Secret in diesem Intervall erneut und überschreibt die eingebundenen Dateien. Der Collector liest die Zertifikatsdateien einmalig beim Start, sodass er das erneuerte Zertifikat erst nach einem Prozess-Neustart vorlegt; unter § Zertifikatsrotation erfahren Sie, wie Sie diesen auslösen. + +--- + +## Phase 3: Pod-Lesezugriff auf das Secret gewähren (IRSA) + +### 3.1 IAM-Policy erstellen + +Speichern Sie als `agenteye-mtls-reader-policy.json`: + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "ReadAgentEyeMtlsBundle", + "Effect": "Allow", + "Action": [ + "secretsmanager:GetSecretValue", + "secretsmanager:DescribeSecret" + ], + "Resource": "arn:aws:secretsmanager:::secret:agenteye/mtls-client/-*" + } + ] +} +``` + +Ersetzen Sie ``, `` und ``. Das abschließende `-*` entspricht dem sechsstelligen Zufallssuffix, den AWS an jeden Secret-ARN anhängt. + +Policy erstellen: + +```bash +aws iam create-policy \ + --policy-name AgentEyeMtlsReader- \ + --policy-document file://agenteye-mtls-reader-policy.json +``` + +### 3.2 IAM-Rolle erstellen und an den ServiceAccount des Pods binden + +```bash +eksctl create iamserviceaccount \ + --name agenteye-pod \ + --namespace \ + --cluster \ + --role-name AgentEyePodRole- \ + --attach-policy-arn arn:aws:iam:::policy/AgentEyeMtlsReader- \ + --approve +``` + +Dies erstellt einen `ServiceAccount` namens `agenteye-pod` mit der `eks.amazonaws.com/role-arn`-Annotation, die auf die neue Rolle verweist. + +### 3.3 Erforderliche IAM-Berechtigungen: Zusammenfassung + +| Berechtigung | Geltungsbereich | Zweck | +|---|---|---| +| `secretsmanager:GetSecretValue` | `arn:aws:secretsmanager:::secret:agenteye/mtls-client/-*` | CSI Driver liest das Zertifikats-Bundle bei jedem Mount- und Rotations-Tick. | +| `secretsmanager:DescribeSecret` | wie oben | CSI Driver ruft `DescribeSecret` auf, um Versionsänderungen zwischen den Abfragen zu erkennen. | + +**Gewähren Sie dem Pod NICHT** `secretsmanager:PutSecretValue`, `secretsmanager:UpdateSecret` oder `secretsmanager:DeleteSecret`. Der Pod liest das Secret ausschließlich; das Schreiben neuer Versionen übernimmt Exosphere bei der Ausstellung oder Erneuerung des Zertifikats. + +Wenn das Secret mit einem kundenverwalteten KMS-Schlüssel (nicht dem Standard-Schlüssel `aws/secretsmanager`) verschlüsselt ist, gewähren Sie zusätzlich: + +```json +{ + "Effect": "Allow", + "Action": ["kms:Decrypt"], + "Resource": "arn:aws:kms:::key/", + "Condition": { + "StringEquals": { + "kms:ViaService": "secretsmanager..amazonaws.com" + } + } +} +``` + +--- + +## Phase 4: Den Pod bereitstellen + +### 4.1 SecretProviderClass + +`agenteye-mtls-spc.yaml`: + +```yaml +apiVersion: secrets-store.csi.x-k8s.io/v1 +kind: SecretProviderClass +metadata: + name: agenteye-mtls + namespace: +spec: + provider: aws + parameters: + objects: | + - objectName: "agenteye/mtls-client/" + objectType: "secretsmanager" + jmesPath: + - path: '"client.crt"' + objectAlias: "client.crt" + - path: '"client.key"' + objectAlias: "client.key" + - path: '"ca.crt"' + objectAlias: "ca.crt" +``` + +Der `jmesPath`-Block weist den AWS-Provider an, das JSON-Secret in drei separate Dateien auf der Festplatte aufzuteilen. Die Anführungszeichen in `'"client.crt"'` sind erforderlich, weil JMESPath `.` als Teilausdruck-Operator behandelt. + +```bash +kubectl apply -f agenteye-mtls-spc.yaml +``` + +### 4.2 Pod-/Deployment-Manifest + +**Wie die beiden Container miteinander kommunizieren.** Das AgentEye-SDK und der Collector kommunizieren nicht über einen Netzwerk-Socket; es gibt keinen lokalen HTTP-Port. Das SDK schreibt Ereignis-Batches als `.jsonl`-Dateien in `$AGENTEYE_HOME/events/`, und der Collector überwacht dieses Verzeichnis kontinuierlich und lädt jede Datei hoch. Für einen Sidecar-Pod bedeutet das: + +- Beide Container binden dasselbe `emptyDir`-Volume am **gleichen** Pfad ein. +- Beide Container setzen `AGENTEYE_HOME` auf diesen Pfad. +- Ihr Anwendungs-Image muss das AgentEye-SDK installiert und konfiguriert haben (siehe [enterprise-docs/python-sdk.md](/de/agenteye/python-sdk)). + +> Wenn `AGENTEYE_HOME` nicht gesetzt ist, verwenden sowohl das SDK als auch der Collector standardmäßig `~/.agenteye`, und die beiden Container haben unterschiedliche Home-Verzeichnisse, sodass sie auf zwei separate Spools landen würden und die Übergabe lautlos fehlschlägt. Setzen Sie `AGENTEYE_HOME` auf **beiden** Containern auf denselben expliziten Pfad. Die Überprüfung in §4.3 und die entsprechende Zeile im Abschnitt Fehlerbehebung erkennen dies, falls es versäumt wurde. + +`agenteye-pod.yaml` (Deployment mit einem Replikat, nach Bedarf skalierbar): + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-app-with-collector + namespace: +spec: + replicas: 1 + selector: + matchLabels: + app: my-app-with-collector + template: + metadata: + labels: + app: my-app-with-collector + spec: + serviceAccountName: agenteye-pod + containers: + - name: app + image: + env: + # SDK writes event JSONL files into $AGENTEYE_HOME/events/ + - name: AGENTEYE_HOME + value: /var/lib/agenteye + volumeMounts: + - name: agenteye-spool + mountPath: /var/lib/agenteye + + - name: agenteye-collector + # Pin to a versioned :v tag for production; :beta-latest + # tracks the current beta build (:latest exists only for stable releases). + image: ghcr.io/agenteye-enterprise/collector:beta-latest + args: ["start"] + env: + # Must match the app container's AGENTEYE_HOME so the collector + # sweeps the same directory the SDK writes to. + - name: AGENTEYE_HOME + value: /var/lib/agenteye + - name: AGENTEYE_URL + value: "https://ingest.example.agenteye.com/events" + - name: AGENTEYE_KEY + valueFrom: + secretKeyRef: + name: agenteye-collector-api-key + key: key + - name: AGENTEYE_TLS_CERT + value: /etc/agenteye/tls/client.crt + - name: AGENTEYE_TLS_KEY + value: /etc/agenteye/tls/client.key + # Only when the AgentEye server presents a cert not signed by a + # publicly-trusted CA (e.g. self-signed by an in-cluster issuer + # because you have no real DNS domain). The CSI mount already + # exposes ca.crt alongside the client cert/key. + - name: AGENTEYE_TLS_CA + value: /etc/agenteye/tls/ca.crt + volumeMounts: + - name: agenteye-spool + mountPath: /var/lib/agenteye + - name: agenteye-mtls + mountPath: /etc/agenteye/tls + readOnly: true + livenessProbe: + exec: + command: ["agenteye-collector", "health"] + initialDelaySeconds: 10 + periodSeconds: 30 + + volumes: + # Shared event spool between app and collector. emptyDir is fine: + # events are transient and the collector drains them before pod + # termination on graceful shutdown. + - name: agenteye-spool + emptyDir: {} + # mTLS cert bundle, mounted read-only into the collector only. + - name: agenteye-mtls + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: agenteye-mtls +``` + +Das Secret `agenteye-collector-api-key` enthält den API-Key des Collectors (zur Bereitstellung siehe [enterprise-docs/api-keys.md](/de/agenteye/api-keys)). + +**Anwenden:** + +```bash +kubectl apply -f agenteye-pod.yaml +``` + +### 4.3 Überprüfung + +```bash +# Pod sollte mit 2/2 bereiten Containern den Status Running haben +kubectl get pods -n -l app=my-app-with-collector + +# Bestätigen, dass das Zertifikats-Bundle eingebunden wurde +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- ls -l /etc/agenteye/tls/ +``` + +Erwartet: `client.crt`, `client.key`, `ca.crt` sind alle vorhanden, schreibgeschützt und im Besitz des Container-Benutzers. + +**Bestätigen Sie, dass der gemeinsame Ereignis-Spool für beide Container sichtbar ist:** + +```bash +# Im Collector sollten die Unterverzeichnisse events/ und failed/ angezeigt werden, +# die der Collector beim Start automatisch erstellt: +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- ls /var/lib/agenteye/ + +# In der App sollten dieselben Verzeichnisinhalte angezeigt werden: +kubectl exec -n deploy/my-app-with-collector \ + -c app -- ls /var/lib/agenteye/ +``` + +Wenn die beiden Auflistungen voneinander abweichen, ist das Volume nicht in beiden Containern eingebunden (oder `AGENTEYE_HOME` unterscheidet sich); siehe § Fehlerbehebung. + +**End-to-End-Smoke-Test:** + +```bash +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- agenteye-collector flush +``` + +Erwartet: Der Collector lädt alle in der Warteschlange befindlichen Ereignisse hoch und gibt eine Zusammenfassung `Done: N/N uploaded, 0 failed.` aus. Wenn der Spool leer ist, gibt er `No pending files.` aus und beendet sich, ohne etwas zu validieren – führen Sie dies daher erst aus, nachdem Ihre Anwendung mindestens ein Ereignis geflusht hat. + +Beachten Sie, dass `flush` nur bei lokalen Konfigurationsfehlern mit einem Nicht-Null-Exitcode abbricht: fehlende Konfiguration (keine URL/kein Key auflösbar) oder ein unlesbares/nicht parsebares TLS-Zertifikat (siehe § Fehlerbehebung). Ein **falscher API-Key ändert den Exitcode nicht** — der Upload erhält eine `401`-Antwort, die Datei wird nach `failed/` verschoben, und der Befehl gibt dennoch `[FAILED] …` pro Datei sowie `Done: 0/N uploaded, N failed.` aus und beendet sich mit `0`. Um einen falschen Key oder einen abgelehnten Upload zu erkennen, lesen Sie die `Done:`/`[FAILED]`-Ausgabe oder prüfen Sie, ob Dateien in `$AGENTEYE_HOME/failed/` landen, nicht den Exitcode. + +--- + +## Zertifikatsrotation + +Das Client-Zertifikat ist 90 Tage gültig und wird automatisch etwa 15 Tage vor Ablauf erneuert; Exosphere veröffentlicht das erneuerte Bundle dann in dasselbe Secrets Manager-Secret. Danach läuft der In-Pod-Ablauf wie folgt: + +1. Das Secret in Secrets Manager erhält eine neue `AWSCURRENT`-Version. ARN und Name bleiben unverändert. +2. Innerhalb des `rotationPollInterval` (standardmäßig 1h; siehe § Phase 2) liest der CSI Driver die neue Version und überschreibt die Dateien unter `/etc/agenteye/tls/`. +3. Der Collector lädt die Zertifikatsdateien **einmalig beim Start**, sodass er das vorherige Zertifikat weiter vorlegt, bis der Prozess neu gestartet wird. Um zum erneuerten Material zu wechseln, starten Sie den Collector neu; ein Rolling Restart reicht aus: + + ```bash + kubectl rollout restart deploy/my-app-with-collector -n + ``` + + Um dies zu automatisieren, fügen Sie einen Sidecar hinzu, der `/etc/agenteye/tls/` überwacht (z. B. mit `inotifywait`) und den Rollout auslöst, wenn sich die Dateien ändern. + +Da das vorherige Zertifikat nach der Erneuerung noch etwa 15 Tage gültig bleibt, haben Sie ein großzügiges Zeitfenster für den Neustart ohne Unterbrechung der Datenerfassung. Exosphere veröffentlicht das erneuerte Bundle für Sie; die einzige routinemäßige Aktion auf Ihrer Seite besteht darin, sicherzustellen, dass der Collector innerhalb dieses Zeitfensters neu gestartet wird. + +--- + +## Fehlerbehebung + +| Symptom | Wahrscheinliche Ursache | Lösung | +|---|---|---| +| Pod bleibt in `ContainerCreating`, Ereignisse zeigen `MountVolume.SetUp failed for volume "agenteye-mtls"` | CSI-Provider kann Secrets Manager nicht erreichen | Prüfen Sie, ob IRSA korrekt gebunden ist: `kubectl describe sa agenteye-pod -n ` zeigt die `eks.amazonaws.com/role-arn`-Annotation. Prüfen Sie CloudTrail auf den AssumeRole-Aufruf. | +| Fehler: `AccessDeniedException: not authorized to perform secretsmanager:GetSecretValue` | IAM-Policy ist auf den falschen ARN beschränkt | Das Secret-ARN-Suffix ist zufällig; verwenden Sie `agenteye/mtls-client/-*` mit Wildcard, nicht den exakten ARN. | +| Fehler: `ParameterNotFound` vom AWS-Provider | Secret-Name stimmt nicht zwischen `SecretProviderClass.objects[].objectName` und dem von Exosphere gelieferten Secret überein | Bestätigen Sie den genauen Namen mit `aws secretsmanager list-secrets --filters Key=tag-key,Values=AgentEyeCluster`. | +| `jmesPath`-Fehler, nur eine Datei eingebunden | JMESPath-Syntax | Die Punkte in den JSON-Schlüsseln erfordern doppelte Anführungszeichen: `'"client.crt"'`, nicht `client.crt`. | +| Collector-Logs zeigen `tls: bad certificate` nach einer Erneuerung | Der CSI Driver hat die neue Version noch nicht abgefragt, oder der Collector läuft noch mit dem beim Start geladenen vorherigen Zertifikat | Bestätigen Sie, dass die eingebundenen Dateien aktualisiert wurden (`ls -l /etc/agenteye/tls/`), und starten Sie dann den Collector neu, um sie zu laden: `kubectl rollout restart deploy/my-app-with-collector -n `. Siehe § Zertifikatsrotation. | +| Collector-Container crashloopt mit `no such file or directory: /etc/agenteye/tls/client.crt` | Volume beim ersten Start noch nicht befüllt; Startup-Probe zu aggressiv | Fügen Sie eine kurze Anfangsverzögerung hinzu oder verwenden Sie einen Init-Container, der auf das Vorhandensein der Datei wartet: `until [ -f /etc/agenteye/tls/client.crt ]; do sleep 1; done`. | +| CSI-Driver-Pod `OOMKilled` | Standard-Speicherlimits zu niedrig für Cluster mit vielen SecretProviderClasses | Erhöhen Sie `--set linux.resources.limits.memory=200Mi` bei der Helm-Installation. | +| App läuft einwandfrei, `agenteye-collector flush` meldet `No pending files.`, aber das AgentEye-Dashboard zeigt keine Ereignisse | App und Collector teilen sich nicht denselben Ereignis-Spool | Prüfen Sie, ob (a) beide Container dasselbe `agenteye-spool`-emptyDir am selben Pfad einbinden und (b) beide `AGENTEYE_HOME` auf diesen Pfad setzen. Führen Sie die beiden `ls /var/lib/agenteye/`-Prüfungen aus § 4.3 aus; die Auflistungen müssen übereinstimmen. | + +**Zuerst zu prüfende Logs:** + +```bash +kubectl logs -n kube-system -l app=secrets-store-csi-driver --tail=100 +kubectl logs -n kube-system -l app=csi-secrets-store-provider-aws --tail=100 +kubectl describe pod -n -l app=my-app-with-collector +``` + +--- + +## Referenz: Dateien auf dem Pod-Datenträger + +Der Pod hat zwei Datenpfade auf dem Datenträger: + +### mTLS-Zertifikats-Bundle: `/etc/agenteye/tls/` (CSI, schreibgeschützt, nur Collector) + +Eingebunden durch den Secrets Store CSI Driver aus AWS Secrets Manager. + +| Datei | Inhalt | Vom Collector verwendet als | +|---|---|---| +| `client.crt` | PEM-kodiertes Client-Zertifikat | `AGENTEYE_TLS_CERT` | +| `client.key` | PEM-kodierter privater Schlüssel | `AGENTEYE_TLS_KEY` | +| `ca.crt` | PEM-kodiertes CA-Zertifikat | `AGENTEYE_TLS_CA` (optional, nur wenn das AgentEye-Server-Zertifikat nicht öffentlich vertrauenswürdig ist) | + +Alle drei sind schreibgeschützt eingebunden und im Besitz des Container-Benutzers. Sie werden vom CSI Driver bei der Rotation des Secrets neu geschrieben. + +### Ereignis-Spool: `$AGENTEYE_HOME/` (emptyDir, gemeinsam les- und schreibbar für beide Container) + +Geteilt über ein `emptyDir`-Volume namens `agenteye-spool`. + +| Pfad | Geschrieben von | Gelesen von | Zweck | +|---|---|---|---| +| `$AGENTEYE_HOME/events/*.jsonl` | App (AgentEye-SDK) | Collector-Sweeper | Ereignis-Batches, die das SDK geflusht hat und die auf den Upload warten. | +| `$AGENTEYE_HOME/failed/` | Collector (bei Upload-Fehler) | Sie (beim Debugging) | JSONL-Dateien, die der Collector nach Wiederholungsversuchen nicht hochladen konnte. | +| `$AGENTEYE_HOME/config.json` | Sie (optional) | Collector | Optionale Collector-Konfigurationsdatei (Alternative zu Umgebungsvariablen). | + +Sowohl das Unterverzeichnis `events/` als auch `failed/` werden beim Start automatisch vom Collector angelegt; kein `initContainer` erforderlich. + +--- + +## Verwandte Dokumentation + +- [enterprise-docs/collector-installation.md](/de/agenteye/collector-installation): Binäroptionen des Collectors, mTLS-Konfigurationsreferenz, Daemon-Modi. +- [enterprise-docs/kubernetes-deployment.md](/de/agenteye/kubernetes-deployment): Multi-Pod-Deployment, interne Abläufe der Zertifikatsausstellung, Lebenszyklus- und Ablaufwarnungen. +- [enterprise-docs/api-keys.md](/de/agenteye/api-keys): Bereitstellung des vom Pod verwendeten Collector-API-Keys. +- [enterprise-docs/troubleshooting.md](/de/agenteye/troubleshooting): Clusterweiter Fehlerbehebungsindex. \ No newline at end of file diff --git a/docs/de/agenteye/tenant-management.mdx b/docs/de/agenteye/tenant-management.mdx new file mode 100644 index 00000000..39b6ddef --- /dev/null +++ b/docs/de/agenteye/tenant-management.mdx @@ -0,0 +1,167 @@ +--- +title: "Tenant-Verwaltung (Organisationen & Mitglieder)" +description: "AgentEye Dokumentation zur Tenant-Verwaltung (Organisationen & Mitglieder)." +--- + + +Eine einzige AgentEye-Instanz bedient mehrere vollständig isolierte **Organisationen** (Tenants), sodass eine Installation verschiedene Teams, Geschäftsbereiche oder Kunden hosten kann, ohne dass die Daten eines Tenants für einen anderen sichtbar sind. Jede Datenzeile (Ereignisse, Auswertungen, Sitzungen, Dashboards, gespeicherte Abfragen, Alarme, API-Schlüssel und Mitglieder) gehört genau einer Organisation. Die primäre Isolation wird im Anwendungscode erzwungen: Jede Anfrage wird mit expliziten `org_id`-Prädikaten auf die jeweilige Organisation beschränkt. In ClickHouse – wo die ereignis- und auswertungsreichen Daten mit hohem Volumen liegen – wird dies durch eine strikte Engine-seitige Durchsetzung abgesichert: Jede Organisation erhält einen dedizierten, schreibgeschützten ClickHouse-Benutzer mit einer organisationsspezifischen Zeilenrichtlinie, sodass selbst nicht vertrauenswürdiges Analyse-SQL niemals die Zeilen eines anderen Tenants lesen kann. In PostgreSQL fügt Row-Level-Security eine zusätzliche Schutzschicht auf dem schreibgeschützten Abfragepfad (`/queries/run`) hinzu und begrenzt, was dieser Pfad sehen kann, selbst wenn ein Filter auf Anwendungsebene fehlen sollte. Die eigene Schreibverbindung des Servers läuft als Tabelleneigentümer und unterliegt damit demselben `org_id`-Scoping auf Anwendungsebene. + +Der Lebenszyklus von Tenants wird durch Operatoren gesteuert, während alles, was Mitglieder täglich tun, im Dashboard als Self-Service verfügbar bleibt. Organisationen und ihre Mitgliedschaften werden mit der **`agenteye-orgctl`**-CLI erstellt und verwaltet, die im Server-Image enthalten ist und **innerhalb des bestehenden Server-Pods** ausgeführt wird. Die Erstellung und Löschung von Tenants ist bewusst aus dem Dashboard und der HTTP-API herausgehalten: Es gibt **keine HTTP-API und keinen Dashboard-Button** für den Tenant-Lebenszyklus – der Zugriff ist daher hinter dem Cluster-/Pod-Shell-Zugang gesichert und nicht über die Anwendungsoberfläche zugänglich. + +Innerhalb einer Organisation arbeiten Mitglieder vollständig im Dashboard und über die API: Sie melden sich an, wechseln zwischen ihren Organisationen, verwalten ihre eigenen API-Schlüssel, erstellen Dashboards und gespeicherte Abfragen und konfigurieren Alarme für ihre Organisation. Die Trennung ist klar: Operatoren stellen Tenants und deren Mitglieder per CLI bereit und nehmen sie außer Betrieb; Mitglieder steuern alles innerhalb eines Tenants über die Benutzeroberfläche. + +> **Einzelne-Tenant-Installationen benötigen nichts davon.** Eine Single-Tenant-Installation läuft ohne jegliche Operator-Aktion. Alle Daten, Benutzer und Schlüssel befinden sich in einer eingebauten `default`-Organisation, die automatisch bereitgestellt wird. Dieser Leitfaden wird erst relevant, wenn Sie eine zweite Organisation hinzufügen möchten. + +--- + +## Voraussetzungen + +Bevor Sie Ihre **zweite** Organisation anlegen (die eingebaute `default`-Org benötigt nichts): + +- **PostgreSQL 15+.** Das Org-Mitgliedschaftsschema verwendet einen `ON DELETE SET NULL`-Fremdschlüssel mit Spaltenliste, der PostgreSQL 15+ erfordert. Aktualisieren Sie PostgreSQL, bevor Sie eine zweite Organisation bereitstellen. +- **Ein starkes, stabiles `ORG_CH_SECRET`.** Das ClickHouse-Passwort jeder Organisation wird als `HMAC(ORG_CH_SECRET, org_id)` abgeleitet. Ein öffentlich bekannter eingebauter Entwicklungsstandard würde öffentlich ableitbare Anmeldedaten je Organisation ergeben. `agenteye-orgctl org create` **verweigert die Ausführung, solange `ORG_CH_SECRET` nicht gesetzt oder auf dem eingebauten Entwicklungsstandard belassen wird**. Legen Sie zuerst einen eigenen Wert fest (siehe [Deployment → Umgebungsvariablen](/de/agenteye/deployment) und, auf Kubernetes, [§2.6 des Kubernetes-Leitfadens](/de/agenteye/kubernetes-deployment#26-multi-tenant-org-isolation-key-optional)). Halten Sie den Wert über alle Server-Replikate hinweg identisch und rotieren Sie ihn nicht leichtfertig; eine Rotation macht den ClickHouse-Benutzer jeder Organisation verwaist, bis beim nächsten Start eine erneute Bereitstellung erfolgt. + +--- + +## Die CLI ausführen + +`agenteye-orgctl` wird im **gleichen Image wie der Server** mitgeliefert (neben `agenteye-server`). Sie müssen **keinen** separaten Pod, Job oder Deployment dafür erstellen; Sie führen es per `exec` innerhalb des bereits laufenden Server-Pods aus, damit es dasselbe `DATABASE_URL`, `CLICKHOUSE_URL` und `ORG_CH_SECRET` wie der Server verwendet. + +**Kubernetes:** + +```bash +kubectl -n agenteye exec deploy/server -- agenteye-orgctl +``` + +**Docker Compose:** + +```bash +docker compose exec server agenteye-orgctl +``` + +Die folgenden Beispiele zeigen das bare `agenteye-orgctl ` der Kürze halber; stellen Sie jeder Zeile das für Ihre Deployment-Art passende der beiden obigen Präfixe voran. + +--- + +## Befehlsreferenz + +### Organisationen + +| Befehl | Funktion | +|---|---| +| `org create --slug --name ` | Erstellt eine neue Organisation. Verweigert die Ausführung, solange `ORG_CH_SECRET` nicht gesetzt oder auf dem eingebauten Entwicklungsstandard belassen ist (setzen Sie zuerst einen eigenen Wert, siehe Voraussetzungen). Stellt den schreibgeschützten ClickHouse-Benutzer und die Zeilenrichtlinie der Organisation bereit. | +| `org list` | Listet alle Organisationen auf (Slug, Name und Lebenszykluszustand). | +| `org rename --slug --name ` | Ändert den Anzeigenamen einer Organisation. Der Slug (der in URLs und Schlüsseln verwendet wird) bleibt unverändert. | +| `org delete --slug ` | **Soft-Delete** der Organisation und Entfernen ihres ClickHouse-Benutzers. Daten werden **beibehalten**. Dadurch wird der Zugriff entzogen und das organisationsspezifische ClickHouse-Credential freigegeben, ohne Ereignisse zu löschen. Durch Ops reversibel; sicherer erster Schritt vor einer endgültigen Bereinigung. | +| `org purge --slug ` | **Unwiderrufliche Datenlöschung.** Die Organisation muss bereits `delete`d sein. Niemals für die eingebaute `default`-Org zulässig. Nur verwenden, wenn Sie sicher sind, dass die Daten des Tenants vernichtet werden sollen. | + +### Mitglieder + +| Befehl | Funktion | +|---|---| +| `member add --org --email [--set ] [--add perm1,perm2] [--remove perm3] [--protected]` | Fügt ein Mitglied zu einer Organisation hinzu. Optional wird von einem eingebauten Berechtigungssatz gestartet und anschließend werden einzelne Berechtigungen hinzugefügt oder entfernt. `--protected` fixiert das Mitglied, sodass es nicht über das Dashboard entfernt oder herabgestuft werden kann (siehe unten). Das neue Mitglied erhält beim ersten Dashboard-Login ein OTP. | +| `member list --org ` | Listet die Mitglieder der Organisation auf. Die Ausgabespalten sind `EMAIL`, `SET` (der eingebaute Satz, von dem das Mitglied gestartet ist, oder `-`), `PROT` (ob das Mitglied geschützt ist) und `PERMISSIONS` (die effektiven Berechtigungen). Eine E-Mail mit einem nachgestellten `*` kennzeichnet einen Instanz-Admin; dieser hat Zugriff auf alle Organisationen. | +| `member update --org --email [--set ...] [--add ...] [--remove ...] [--protected \| --unprotect]` | Ändert die Berechtigungen eines Mitglieds und/oder dessen Schutzstatus. `--set` ersetzt durch einen eingebauten Satz; `--add` / `--remove` passen einzelne Berechtigungen an; `--protected` / `--unprotect` schalten den Schutz um. Wird nur `--protected`/`--unprotect` übergeben (ohne Grant-Flags), wird ausschließlich der Schutz geändert und bestehende Berechtigungen bleiben unberührt. | +| `member remove --org --email ` | Entfernt ein Mitglied aus der Organisation. Verweigert, wenn das Mitglied geschützt ist; heben Sie zuerst den Schutz mit `--unprotect` auf. (Eine Person kann Mitglied mehrerer Organisationen sein; dies betrifft nur die genannte Organisation.) | + +Eine Person kann Mitglied mehrerer Organisationen mit **unterschiedlichen** Berechtigungen sein, z. B. Admin in einer Organisation und nur lesend in einer anderen. Jede Mitgliedschaft wird unabhängig pro Organisation verwaltet: Das Gewähren oder Ändern von Berechtigungen in einer Organisation hat keinen Einfluss auf die Mitgliedschaft in einer anderen. + +### Geschützte Mitglieder (ein unentfernbarer Org-Admin) + +Der Schutz stellt sicher, dass sich eine Organisation nie versehentlich aus der Selbstverwaltung aussperren kann. Standardmäßig können die Admins einer Organisation sich gegenseitig über die Self-Service-Benutzerseite im Dashboard hinzufügen und entfernen – was dazu führen könnte, dass der letzte Admin entfernt wird und niemand die Organisation mehr verwalten kann. + +![Die Benutzerseite: eine Karte pro Dashboard-Benutzer mit E-Mail, gewährten Berechtigungen und Bearbeitungs-/Deaktivierungssteuerelementen](/agenteye/images/users.png) + +Um dies zu verhindern, markieren Sie ein Mitglied als **geschützt**: + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member add --org acme --email owner@acme.example --set admin --protected +``` + +Ein geschütztes Mitglied **kann nicht über das Dashboard entfernt oder herabgestuft werden**; diese Aktionen geben einen Fehler zurück. Nur ein Operator kann es über diese CLI ändern: Führen Sie zuerst `member update --org acme --email owner@acme.example --unprotect` aus, dann entfernen oder stufen Sie herab. Dies garantiert, dass jede Organisation mindestens einen Admin behält, den ihre eigenen Mitglieder nicht aussperren können, während die Tenant-Kontrolle ausschließlich beim Operator verbleibt. Der Schutz gilt **pro Organisation**; der Schutz einer Person in einer Organisation hat keinen Einfluss auf ihre Mitgliedschaft in einer anderen. + +### Eingebaute Berechtigungssätze + +`--set` akzeptiert einen von drei eingebauten Sätzen, die pro Organisation angewendet werden: + +| Satz | Vorgesehen für | +|---|---| +| `admin` | Vollständiger Zugriff innerhalb der Organisation, einschließlich der Verwaltung der API-Schlüssel und Benutzer der Organisation. | +| `standard` | Tägliche Nutzung: Abfragen lesen und ausführen, Dashboards erstellen, Incidents bestätigen. | +| `read-only` | Nur-Lesen-Zugriff auf die Daten und Dashboards der Organisation. | + +Starten Sie mit `--set` von einem Satz aus und passen Sie ihn dann mit `--add` / `--remove` und den einzelnen Berechtigungs-Tokens aus [API-Schlüssel](/de/agenteye/api-keys) an. Die Berechtigungs-Tokens sind identisch mit denen, die für API-Schlüssel verwendet werden. + +--- + +## Ausführliches Beispiel + +Einen neuen `acme`-Tenant bereitstellen, seinen ersten Admin hinzufügen, ihm ermöglichen, einen Schlüssel zu erstellen, und die Organisation anschließend außer Betrieb nehmen. + +**1. Organisation erstellen** (`ORG_CH_SECRET` muss bereits auf einen starken, stabilen Wert gesetzt sein, nicht ungesetzt oder auf dem eingebauten Entwicklungsstandard): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org create --slug acme --name "Acme Corp" +``` + +**2. Das erste Mitglied als Org-Admin hinzufügen:** + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member add --org acme --email alice@acme.example --set admin +``` + +Alice erhält beim ersten Anmelden im Dashboard ein OTP. Danach arbeitet sie vollständig in der Benutzeroberfläche unter dem URL-Präfix ihrer Organisation (z. B. `/acme/sessions`). + +**3. Einen organisationsspezifischen API-Schlüssel erstellen (im Dashboard):** + +Der Operator erstellt organisationsspezifische Datenschlüssel **nicht** über die CLI. Alice (oder ein anderes Org-Mitglied mit `keys:create`) erstellt Collector-/Dashboard-Schlüssel für die `acme`-Organisation über die **Schlüssel**-Seite im Dashboard. Jeder von ihr erstellte Schlüssel wird automatisch mit ihrer Organisation gestempelt und kann ausschließlich die Daten von `acme` lesen oder schreiben. Siehe [API-Schlüssel](/de/agenteye/api-keys). + +**4. Ein Mitglied nachträglich anpassen:** + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member update --org acme --email alice@acme.example --add alerts:write + +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member list --org acme +``` + +**5. Organisation soft-löschen** (entzieht Zugriff + entfernt den ClickHouse-Benutzer; Daten werden beibehalten): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org delete --slug acme +``` + +**6. Organisation bereinigen** (unwiderruflich; nur nach einem Soft-Delete; niemals die `default`-Org): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org purge --slug acme +``` + +Ersetzen Sie bei Docker Compose jeden `kubectl -n agenteye exec deploy/server --`-Präfix durch `docker compose exec server`. + +--- + +## Aufgabenteilung + +Alles, was ein Org-Mitglied täglich benötigt, steht als Self-Service im Dashboard und in der API zur Verfügung und ist automatisch auf die aktuelle Organisation beschränkt: + +- **Organisationsspezifische API-Schlüssel** werden von Org-Mitgliedern im Dashboard (oder über die Keys-API mit einem Schlüssel, der `keys:create` trägt) erstellt und verwaltet. Die CLI erstellt **keine** Datenschlüssel. Siehe [API-Schlüssel](/de/agenteye/api-keys). +- **Organisations-Wechsel** ist in das Dashboard integriert; Mitglieder wechseln über den Org-Umschalter zwischen ihren Organisationen, und organisations-spezifische Seiten befinden sich unter `//…`. +- **Dashboards, gespeicherte Abfragen, Alarme und die gesamte Datennutzung** finden vollständig in der Benutzeroberfläche und API statt, begrenzt auf die aktuelle Organisation des Mitglieds. + +Der Operator nutzt `agenteye-orgctl` ausschließlich für den Org- und Mitglieds-**Lebenszyklus**: Organisation erstellen / umbenennen / löschen / bereinigen sowie Mitglieder hinzufügen / auflisten / aktualisieren / entfernen. + +--- + +## Siehe auch + +- [Deployment](/de/agenteye/deployment): `ORG_CH_SECRET` und die übrigen Server-Umgebungsvariablen. +- [Kubernetes-Deployment](/de/agenteye/kubernetes-deployment): §2.6 erstellt das `agenteye-org-ch-secret`-Secret vor Ihrer ersten Multi-Tenant-Organisation. +- [API-Schlüssel](/de/agenteye/api-keys): Das organisations-spezifische Schlüsselmodell und die von `--add` / `--remove` verwendeten Berechtigungs-Tokens. +- [Fehlerbehebung](/de/agenteye/troubleshooting): Probleme bei der Multi-Tenant-Bereitstellung und ClickHouse-Isolation. \ No newline at end of file diff --git a/docs/de/agenteye/troubleshooting.mdx b/docs/de/agenteye/troubleshooting.mdx new file mode 100644 index 00000000..b8ae84cf --- /dev/null +++ b/docs/de/agenteye/troubleshooting.mdx @@ -0,0 +1,650 @@ +--- +title: "Fehlerbehebung" +description: "AgentEye-Dokumentation zur Fehlerbehebung." +--- + + +Dieser Leitfaden ordnet die häufigsten Symptome in der Produktionsumgebung einer konkreten Diagnose und Lösung zu, damit Sie Vorfälle mit vorhandenen Werkzeugen beheben können – ohne zusätzliche Observability-Infrastruktur aufbauen zu müssen. Er behandelt Server, Collector, Dashboard, KI-Assistent, Python SDK, Gesundheits- und Zertifikatsüberwachung, Backups, ClickHouse-basierte Analytics und Multi-Tenancy. + +Dashboard-Seiten sind unter `//…` org-scoped, und der Ereignisstrom ist die Org-Startseite (`//`). Seitennamen in diesem Leitfaden (z. B. `/sessions`, `/queries`) beziehen sich auf diese org-scoped Routen. + +--- + +## Logs anzeigen + +AgentEye bündelt keinen Logging- oder Monitoring-Stack. Sowohl der Server als auch das Dashboard schreiben strukturierte Logs nach **stdout**, sodass Sie diese direkt mit `kubectl` oder `docker` lesen können – kein Aggregator erforderlich. + +### Kubernetes + +Live-Logs für Server und Dashboard verfolgen: + +```bash +kubectl logs -n agenteye -l app=server -f --timestamps +kubectl logs -n agenteye -l app=dashboard -f --timestamps +``` + +Nützliche Varianten: + +| Ziel | Befehl | +|---|---| +| Letzte 200 Zeilen (kein Follow) | `kubectl logs -n agenteye -l app=server --tail=200 --timestamps` | +| Logs des vorherigen Absturzes | `kubectl logs -n agenteye --previous` | +| Alle Replikas gleichzeitig verfolgen | `kubectl logs -n agenteye -l app=server --max-log-requests=10 -f` | +| Postgres (StatefulSet) | `kubectl logs -n agenteye postgres-0 -f` | + +### Docker Compose + +```bash +docker logs -f agenteye-server +docker logs -f agenteye-dashboard +``` + +### Eine einzelne Anfrage über Dashboard und Server korrelieren + +Jede Dashboard-Anfrage erhält eine `request_id`, die über den `x-request-id`-Header an den Server weitergeleitet wird. Der Server gibt sie in seinen Antwort-Headern und in jeder Log-Zeile für diese Anfrage wieder aus. Um eine Anfrage von Anfang bis Ende zu verfolgen: + +1. ID aus dem Antwort-Header erfassen, z. B.: + ```bash + curl -i https://dashboard.example.com/api/events | grep -i x-request-id + # x-request-id: 9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a + ``` +2. Logs beider Pods nach dieser ID durchsuchen: + ```bash + REQ=9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a + kubectl logs -n agenteye -l app=dashboard --tail=5000 | grep "$REQ" + kubectl logs -n agenteye -l app=server --tail=5000 | grep "$REQ" + ``` + +Sie sehen die `proxy passthrough`-, `withAuth: authorized`- und `upstream response`-Zeilen des Dashboards zusammen mit dem `http request received` / `http request completed`-Paar des Servers – alle mit derselben `request_id`. + +### JSON-Logs und `jq` + +Setzen Sie `AE_LOG_JSON=1` am Dashboard (standardmäßig aktiviert, wenn `NODE_ENV=production`), um ein JSON-Objekt pro Zeile auszugeben. Dann strukturell filtern: + +```bash +kubectl logs -n agenteye -l app=dashboard --tail=5000 \ + | jq 'select(.level == "warn" or .level == "error")' + +kubectl logs -n agenteye -l app=dashboard --tail=5000 \ + | jq 'select(.route == "POST /api/keys")' +``` + +Der Rust-Server gibt `key=value`-Tracing-Paare aus, die sich gut mit `grep` ohne `jq` durchsuchen lassen: + +```bash +kubectl logs -n agenteye -l app=server --tail=5000 | grep 'status=5' # 5xx +kubectl logs -n agenteye -l app=server --tail=5000 | grep 'actor_key_id=' +``` + +### Ausführlichkeit erhöhen + +| Komponente | Env-Variable | Beispiel | +|---|---|---| +| Server | `RUST_LOG` | `RUST_LOG=debug` oder `RUST_LOG=agenteye_server=debug,info` | +| Dashboard | `AE_LOG_LEVEL` | `AE_LOG_LEVEL=debug` | + +`debug` am Server fügt eine `api key authenticated`-Zeile pro Authentifizierung hinzu. `debug` am Dashboard fügt `upstream request`-, `session validated`- und `proxy passthrough`-Zeilen hinzu. + +### Log-Aufbewahrung + +Container-stdout ist flüchtig; kubelet rotiert Log-Dateien (Standard ca. 10 MiB pro Container) und hält eine kleine Anzahl auf der Festplatte. Sobald ein Pod gelöscht wird, sind die Logs verschwunden. Wenn Sie eine längere Aufbewahrung oder pod-übergreifende Suche benötigen, richten Sie Ihren Cluster auf einen Log-Collector (Loki, CloudWatch, Cloud Logging, Datadog usw.) ein, der `/var/log/containers/` verfolgt. AgentEye schreibt keine bestimmte Lösung vor. + +--- + +## Authentifizierungsprobleme + +### `docker pull` schlägt fehl mit "unauthorized" + +Stellen Sie sicher, dass Sie Docker mit Ihrem `AGENTEYE_TOKEN` gegen GHCR authentifiziert haben: + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +Das Token muss die Berechtigung `read:packages` für die `agenteye-enterprise`-Organisation haben. Kontaktieren Sie `support@exosphere.host`, wenn Ihr Token nicht funktioniert. + +### `gh release download` gibt 404 oder 401 zurück + +- Bestätigen Sie, dass `AGENTEYE_TOKEN` in Ihrer Shell exportiert ist: `echo $AGENTEYE_TOKEN` +- Bestätigen Sie, dass Sie `GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download ...` verwenden (die `gh`-CLI liest `GITHUB_TOKEN`) +- Das Token benötigt `contents:read` auf `agenteye-enterprise/releases` + +--- + +## Server-Probleme + +### Server schlägt fehl mit "invalid port number" + +Das `POSTGRES_PASSWORD` (oder eine andere Anmeldeinformation) enthält URL-Sonderzeichen (`/`, `+`, `=`), die das Parsen der `DATABASE_URL` stören. Generieren Sie das Passwort mit Hex-Kodierung neu: + +```bash +NEW_PASS=$(openssl rand -hex 24) +``` + +Aktualisieren Sie dann das Kubernetes-Secret und das Passwort in Postgres (oder erstellen Sie die `.env` für Docker Compose neu) und starten Sie den Server neu. Siehe die vollständigen Schritte in [enterprise-docs/kubernetes-deployment.md](/de/agenteye/kubernetes-deployment) § "PostgreSQL credentials". + +### Server beendet sich sofort beim Start + +Überprüfen Sie die Container-Logs: + +```bash +docker logs agenteye-server +``` + +Häufige Ursachen: +- `DATABASE_URL` nicht gesetzt oder fehlerhaft: Der Server protokolliert den Fehler und beendet sich. +- Postgres ist nicht erreichbar: Bestätigen Sie, dass der Postgres-Container oder die verwaltete DB läuft und Host/Port korrekt sind. +- Migrationen fehlgeschlagen: Prüfen Sie die Logs auf SQL-Fehler. + +### `GET /health` gibt non-200 zurück oder läuft ab + +Der Server führt beim ersten Start möglicherweise noch Migrationen durch. Warten Sie einige Sekunden und versuchen Sie es erneut: + +```bash +curl http://localhost:8080/health +``` + +Wenn das Problem anhält, prüfen Sie `docker logs agenteye-server` auf Fehler. + +### `GET /ready` gibt 503 zurück + +`/ready` ist der Readiness-Probe: Er gibt `503` zurück, wenn der Server **Postgres oder ClickHouse** nicht erreichen kann. Der Body benennt die fehlschlagende Abhängigkeit: + +```bash +curl -s http://localhost:8080/ready +# {"status":"not_ready","checks":{"postgres":"ok","clickhouse":"down","redis":"ok"}} +``` + +Beheben Sie die als `down` gemeldete Abhängigkeit: Ist der ClickHouse-/Postgres-Pod `Running`? Ist `CLICKHOUSE_URL` / `DATABASE_URL` korrekt und erreichbar? In Kubernetes liest der Pod `NotReady`, bis `/ready` sich erholt; das ist erwartet und genau das Signal, auf das die Gesundheitsüberwachung alarmiert. Redis ist niemals eine Ursache: Es wird gemeldet, verursacht aber keinen Readiness-Fehler. + +### Collector gibt 401 Unauthorized zurück + +Der API-Schlüssel des Collectors hat keine `events:add`-Berechtigung, oder der Schlüssel wurde deaktiviert. Erstellen Sie einen neuen Schlüssel mit der richtigen Berechtigung: + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{"name":"new-collector","permissions":["events:add"]}' +``` + +### Authentifizierte Anfragen sind plötzlich langsam (~200ms statt ~5ms) + +Dies ist das Symptom, wenn Redis ausgefallen ist, während `REDIS_URL` gesetzt ist. Jeder Cache-Aufruf läuft nach 100ms ab und fällt dann auf Postgres zurück; auf Auth- und OTP-Pfaden macht die Anfrage zwei solche Fallbacks. + +Bestätigen in den Server-Logs: + +``` +auth cache: L2 get failed error=redis call timed out +``` + +Lösung: + +1. `redis-cli -h ping` um zu bestätigen, dass Redis im Cluster-Netzwerk erreichbar ist. +2. Wenn Redis kurz ausgefallen war und jetzt wieder läuft, **starten Sie die Server-Pods neu**. Der `redis::aio::ConnectionManager` stellt die Verbindung nach einem Verbindungsabbruch nicht zuverlässig wieder her; ein Pod-Neustart nimmt die neue Verbindung sauber auf. Dasselbe gilt für das Dashboard. +3. Wenn Sie Redis derzeit nicht betreiben möchten, entfernen Sie `REDIS_URL` aus dem Deployment und starten Sie neu. Beide Dienste laufen ohne Cache (Korrektheit bleibt erhalten; Latenz kehrt zum Pre-Redis-Ausgangswert zurück). + +### Server meldet `OTP request rate-limited` in den Logs, aber der Benutzer sagt, er hat es nur einmal versucht + +Prüfen Sie, ob Redis unerreichbar war. Der Fallback-Pfad verwendet `SELECT COUNT(*) FROM otp_codes WHERE created_at > now() - interval '15 minutes'`, der zuvor generierte OTP-Zeilen sieht. Wenn der Benutzer eine Stunde lang auf "Erneut senden" geklickt hat, kann das 15-Minuten-Fenster noch ≥5 Codes enthalten. Lösung: entweder warten, bis das Fenster abläuft, oder `DELETE FROM otp_codes WHERE user_id = $1 AND created_at > now() - interval '15 minutes'` (Operator-Konsole). + +### Ich habe `ALLOWED_EMAILS` / `SESSION_TTL_SECS` / `OTP_TTL_SECS` geändert und neu gestartet; nichts hat sich geändert + +Diese Env-Variablen sind **nur beim ersten Start als Seeds** gedacht. Sobald die `settings`-Tabelle eine Zeile für den entsprechenden Schlüssel hat, ist diese Zeile die Quelle der Wahrheit; die Env-Variable wird nur beim ersten Start gelesen und bei jedem nachfolgenden Neustart ignoriert. + +Um sie nach dem ersten Start zu ändern, melden Sie sich am Dashboard an und bearbeiten Sie sie unter `/settings`. Die Änderung gilt innerhalb von Sekunden für alle Replikas; kein Neustart erforderlich. + +Wenn Sie einen erneuten Seed aus der Env erzwingen müssen (selten, typischerweise nur in der Entwicklung nützlich), führen Sie `DELETE FROM settings WHERE key = ''` aus und starten Sie den Server neu. Der Bootstrap nimmt den aktuellen Env-Variablenwert beim nächsten Start auf. Das Bearbeiten über `/settings` ist der unterstützte Weg in der Produktion. + +--- + +## Collector-Probleme + +### Collector startet, aber Ereignisse erscheinen nicht im Dashboard + +1. Bestätigen Sie, dass der Collector läuft: `systemctl status agenteye-collector` (Linux) oder prüfen Sie den Prozess. +2. Bestätigen Sie, dass `AGENTEYE_URL` auf `http(s)://your-server-host:8080/events` zeigt (Hinweis: `/events`-Pfad). +3. Führen Sie einen einmaligen Flush aus, um sofortige Ausgabe zu sehen: + ```bash + agenteye-collector flush + ``` +4. Prüfen Sie, ob das Python SDK tatsächlich Dateien schreibt: `ls ${AGENTEYE_HOME:-~/.agenteye}/events/` +5. Wenn Dateien in `${AGENTEYE_HOME:-~/.agenteye}/failed/` vorhanden sind, schlagen die Uploads fehl. Prüfen Sie die Collector-Logs auf den Fehler – wahrscheinlich ein 4xx (falscher Schlüssel oder URL) oder ein Netzwerkproblem. + +### Dateien häufen sich in `$AGENTEYE_HOME/events/` an und werden nicht hochgeladen + +- Der Collector läuft möglicherweise nicht. Starten Sie ihn: `agenteye-collector start`; er leert beim Start automatisch vorhandene Ereignisse. +- Collector-Zustand prüfen: `agenteye-collector health` +- Der Collector läuft möglicherweise, kann aber den Server nicht erreichen. Prüfen Sie die Firewall-Regeln zwischen Collector- und Server-Hosts. + +### Dateien in `$AGENTEYE_HOME/failed/` + +Dateien werden nach Erschöpfung aller Wiederholungsversuche (Standard: 5 Versuche mit exponentiellem Backoff) nach `failed/` verschoben. Das bedeutet entweder: +- Der Server hat einen 4xx-Fehler zurückgegeben (falscher Schlüssel, falsche URL oder Payload-Problem) +- Der Server war während des gesamten Wiederholungsfensters nicht erreichbar + +Beheben Sie das zugrunde liegende Problem und stellen Sie dann manuell erneut in die Warteschlange: + +```bash +mv ${AGENTEYE_HOME:-~/.agenteye}/failed/*.jsonl ${AGENTEYE_HOME:-~/.agenteye}/events/ +agenteye-collector flush +``` + +### Collector meldet bei jedem Upload `network error` (TLS-Handshake schlägt fehl) + +Wenn `curl -k` gegen `AGENTEYE_URL` erfolgreich ist, aber das Collector-Binary jeden Upload mit `error sending request for url (...)` fehlschlagen lässt, präsentiert der AgentEye-Server ein TLS-Zertifikat, das nicht von einer öffentlich vertrauenswürdigen CA signiert ist. + +Der **Produktionspfad** ist der ACME-Ingest-Hostname, der in `deploy/base/certificates/domain.env` konfiguriert ist (siehe [`kubernetes-deployment.md`](/de/agenteye/kubernetes-deployment) Phase 3.1 / 4.2). Sobald `INGEST_DOMAIN` auf den öffentlichen Traefik-LB auflöst und cert-manager das Let's Encrypt-Zertifikat ausgestellt hat, verifizieren Collectors das Server-Zertifikat gegen den System-Vertrauensspeicher **ohne `AGENTEYE_TLS_CA`**; entfernen Sie es aus Ihrer Collector-Konfiguration, falls es gegen ein älteres selbstsigniertes Deployment gesetzt war. + +**Symptom: Collector funktionierte gestern, schlägt heute nach ~90 Tagen fehl.** Das bedeutet, dass das Deployment noch den Legacy-`selfsigned`-Aussteller für `ingest-tls` verwendet. Das 90-Tage-Zertifikat wurde rotiert und die gepinnte CA-Datei ist veraltet. Dauerhaft beheben, indem Sie den Cluster auf den ACME-Aussteller umstellen (Phase 3.1 des Deployment-Leitfadens). Kurzfristige Lösung: das aktuelle Server-Zertifikat neu extrahieren und `AGENTEYE_TLS_CA` aktualisieren: + +```bash +kubectl get secret ingest-tls-cert -n agenteye \ + -o jsonpath='{.data.tls\.crt}' | base64 -d > /etc/agenteye/server-ca.crt +``` + +```bash +export AGENTEYE_TLS_CA=/etc/agenteye/server-ca.crt +agenteye-collector flush +``` + +`AGENTEYE_TLS_CA` fügt einen zusätzlichen Vertrauensanker hinzu; die standardmäßigen öffentlichen Roots werden weiterhin vertraut. + +### `ingest-tls`-Zertifikat bleibt nach dem Deploy `Ready: False` + +```bash +kubectl describe certificate ingest-tls -n agenteye +``` + +Schauen Sie sich `Events` und den referenzierten `Order` / `Challenge` an. Häufige Ursachen: + +- **DNS löst nicht auf den öffentlichen LB auf.** Der HTTP-01-Validator kann `INGEST_DOMAIN` nicht erreichen. Mit `dig +short INGEST_DOMAIN` prüfen; es sollte auf dieselbe Adresse wie die `EXTERNAL-IP` des `traefik-public`-LoadBalancers auflösen. cert-manager wiederholt automatisch, sobald DNS propagiert; das Zertifikat muss nicht gelöscht werden. +- **Port 80 am Load Balancer / Security Group blockiert.** HTTP-01 erfordert, dass Port 80 von Let's Encrypts öffentlichen Validatoren erreichbar ist. Wenn ein vorgeschaltetes WAF oder eine SG `:80` einschränkt, öffnen Sie es (die Traefik-Konfiguration leitet zu HTTPS weiter, aber Boulder folgt der Umleitung und akzeptiert die Antwort). +- **`dnsNames` nicht ersetzt.** Wenn `kubectl get certificate ingest-tls -n agenteye -o jsonpath='{.spec.dnsNames}'` `INGEST_DOMAIN_PLACEHOLDER` anzeigt, haben Sie den `domain.env`-Schritt übersprungen; erstellen Sie es aus `domain.env.example` und wenden Sie es erneut an. +- **Rate-Limit von Let's Encrypt.** Wiederholte fehlgeschlagene Orders für denselben Hostnamen lösen die Limits für doppelte Zertifikate oder fehlgeschlagene Validierungen aus. Warten Sie mindestens eine Stunde vor dem erneuten Versuch; prüfen Sie den Order-Status auf die genaue Rate-Limit-Meldung. + +### `dashboard-tls`-Zertifikat bleibt `Ready: False` / Browser zeigt noch eine Warnung + +Gleicher Diagnoseablauf wie bei `ingest-tls` oben (`kubectl describe certificate dashboard-tls -n agenteye`); DNS-, Port-80-, Platzhalter- und Rate-Limit-Ursachen gelten alle, plus zwei Dashboard-spezifische: + +- **`DASHBOARD_DOMAIN` löst auf den falschen LoadBalancer auf.** Es muss auf den *Dashboard*-Traefik-LB zeigen, nicht auf den öffentlichen Ingest-LB. Mit `dig +short` den Hostnamen prüfen und mit der Dashboard-LB-Adresse vergleichen. +- **Die Dashboard-Traefik-Instanz kann die Challenge nicht bereitstellen.** Sie muss mit der gebündelten Dashboard-Values-Datei installiert sein, die einen bereichsbeschränkten Ingress-Provider für den HTTP-01-Solver von cert-manager aktiviert. Ohne ihn ist der Solver nicht erreichbar und der Order bleibt für immer `pending`. Aktualisieren Sie die Instanz mit den bereitgestellten Values; die ausstehende Challenge wird dann von selbst abgeschlossen. +- **Der LoadBalancer war IP-beschränkt.** Source-Ranges gelten auch für Port 80, was Let's Encrypts Validatoren blockiert – sowohl bei der ersten Ausstellung als auch bei jeder ~75-tägigen Erneuerung. Öffnen Sie den LB erneut oder koordinieren Sie einen DNS-01-Solver mit dem Support, bevor Sie ihn sperren. + +Während die Ausstellung fehlschlägt, stellt das Dashboard weiterhin sein vorheriges Zertifikat bereit (oder das Ingress-Standard-Zertifikat bei einer Neuinstallation) – der Zugang ist durch eine Browser-Warnung beeinträchtigt, aber nie unterbrochen. + +### CLI überspringt TLS-Verifizierung noch, nachdem das Dashboard ein vertrauenswürdiges Zertifikat erhalten hat + +`--insecure` wird bei der Anmeldung in `cli.json` gespeichert. Sobald das Dashboard ein öffentlich vertrauenswürdiges Zertifikat bereitstellt, melden Sie sich erneut mit `agenteye --base-url https:// --secure login` an; die Verifizierung wird wieder aktiviert gespeichert und die Startup-Warnung verschwindet. + +--- + +## Dashboard-Probleme + +### `ADMIN_EMAIL`-Benutzer kann nicht deaktiviert oder bearbeitet werden + +Dies ist by Design. Der Benutzer, der `ADMIN_EMAIL` entspricht, wird bei jedem Server-Start als geschützt markiert: Das Dashboard blendet die Deaktivieren-Schaltfläche für diese Zeile aus, und die API lehnt `DELETE /users/:id` und `PUT /users/:id` dagegen mit `403 Forbidden` ab. Ein Datenbank-Trigger lehnt auch direkte `UPDATE`-Anweisungen ab, die die geschützte Zeile deaktivieren würden. + +Um den Bootstrap-Admin zu rotieren, ändern Sie `ADMIN_EMAIL` in Ihrer Umgebung und starten Sie den Server neu. Die neue E-Mail wird als geschützt upserted. Der vorherige Admin behält das geschützte Flag, bis es in der Datenbank gelöscht wird (in der Regel in Ordnung, da die vorherige E-Mail ein gültiger Admin bleibt, bis Sie sie explizit entfernen). + +### Dashboard zeigt keine Ereignisse + +1. Bestätigen Sie, dass die Server-URL und der API-Schlüssel in den Umgebungsvariablen des Dashboards korrekt sind (`AGENTEYE_SERVER_URL`, `AGENTEYE_API_KEY`). +2. Der Dashboard-API-Schlüssel benötigt die Berechtigung `events:read`. +3. Bestätigen Sie, dass tatsächlich Ereignisse aufgenommen wurden: `curl http://your-server:8080/events -H "Authorization: Bearer $ADMIN_KEY"` + +### `/errors` ist leer, aber `/events` zeigt rote Zeilen + +Neuere SDK-Versionen senden Fehler als `agent_end`- / `tool_result`- / `hook_completed`-Ereignisse mit `outcome: "error"` im Payload statt als dedizierte `event_type: "error"`-Zeile. Die `/errors`-Seite erkennt jetzt beides: Jede Zeile, die der `/events`-Stream rot färbt (explizites `event_type='error'`, Payload `outcome`/`status` in der Fehler-Menge, `is_error: true` oder ein wahrer `error`-Feld), erscheint in `/errors`. Wenn Sie zuvor "keine Fehler in diesem Zeitfenster" sahen, während rote Zeilen in `/events` sichtbar waren, aktualisieren Sie Dashboard und Server zusammen (der erweiterte Filter ist `errored=true` auf `GET /events`) und die beiden Ansichten stimmen überein. + +### `/models`, `/tools` oder `/hooks` ist langsam oder schlägt bei breiten Zeitbereichen fehl + +**Symptom:** Bei einer großen Ereignistabelle (Millionen von Zeilen) drehen sich beim Öffnen von `/models`, `/tools` oder `/hooks` – oder beim Erweitern des Zeitbereichs auf `7d`, `30d` oder `all` – die Charts und zeigen dann einen Ladefehler. Der Server protokolliert ein ClickHouse-`MEMORY_LIMIT_EXCEEDED` (Code 241) oder einen Query-Timeout für die `latency_aggregate`-Anfrage. + +**Ursache:** Ältere Builds berechneten die Latenz- und Verteilungs-Rollups dieser Seiten mit einer Abfrage, die den vollständigen rohen Ereignis-`payload` las und Anfrage-/Antwort-Ereignisse mit einem In-Memory-Sortier-und-Join paarte. Der Query-Spitzenspeicher wuchs daher mit der Fenstergröße, sodass bei einem stark ausgelasteten Tenant ein breiter Bereich die Pro-Query-Speichergrenze von ClickHouse überschreiten konnte. + +**Lösung:** Auf einen Build aktualisieren, der diesen Fix enthält. Der Rollup liest jetzt nur die kompakten promoted Columns und paart Ereignisse mit einer Streaming-Aggregation, sodass der Spitzenspeicher nicht mehr mit dem rohen Payload skaliert – breite Fenster bleiben deutlich innerhalb der Speichergrenze und werden in einem Bruchteil der Zeit zurückgegeben. Die Verbesserung ist rein query-seitig: Sie gilt für alle vorhandenen Daten beim nächsten Seitenaufruf, ohne Re-Ingest oder Backfill. + +### Dashboard schlägt beim Laden fehl / leere Seite + +Prüfen Sie die Dashboard-Container-Logs: + +```bash +docker logs agenteye-dashboard +``` + +Die häufigste Ursache ist, dass `AGENTEYE_SERVER_URL` oder `AGENTEYE_API_KEY` fehlt oder auf einen nicht erreichbaren Server zeigt. + +### Dashboard-Analytics / Telemetrie + +Das Dashboard sendet standardmäßig anonyme Produktnutzungs-Analytics an PostHog, geleitet über den eigenen `/ingest`-Pfad des Dashboards (ein Reverse Proxy zu `https://us.i.posthog.com`). Die First-Party-Weiterleitung verhindert, dass Browser-Werbeblocker sie abfangen. Dies ist unabhängig von der Kernfunktionalität des Dashboards: + +- Der **Dashboard-Container** (nicht der Browser) ist derjenige, der PostHog erreicht. Wenn sein ausgehender Zugriff auf `https://us.i.posthog.com` blockiert ist, schlägt die Telemetrie lautlos fehl; das Dashboard funktioniert normal und es werden keine Fehler an Benutzer weitergegeben. +- Es werden niemals Agent-, Sitzungs- oder Ereignisdaten übermittelt, nur Dashboard-UI-Nutzung. +- Um die Telemetrie vollständig zu deaktivieren, setzen Sie `AE_ANALYTICS_DISABLED=1` am Dashboard-Container und starten Sie neu. Siehe [Telemetry & privacy](/de/agenteye/deployment#telemetry--privacy) im Deployment-Leitfaden. + +### CLI-Analytics / Telemetrie + +Die `agenteye`-CLI sendet standardmäßig anonyme Nutzungs-Analytics an PostHog: welche Befehle ausgeführt werden, Erfolgs-/Exit-Status und Dauer. Dies ist unabhängig von der CLI-Funktionalität: + +- Der **Rechner, auf dem die CLI läuft**, erreicht `https://us.i.posthog.com` direkt. Wenn sein ausgehender Zugriff blockiert ist, schlägt die Telemetrie lautlos fehl (das Senden ist zeitlich begrenzt, verzögert also keinen Befehl) und die CLI funktioniert normal. +- Es werden niemals Agent-, Sitzungs- oder Ereignisdaten übermittelt: Befehls-**Argumente und Flag-Werte** (Dashboard-URL, Token, E-Mail, Sitzungs-IDs, Query-Filter) werden niemals gesendet. +- Um es zu deaktivieren, setzen Sie `AGENTEYE_ANALYTICS_DISABLED=1` (oder das tool-übergreifende `DO_NOT_TRACK=1`) in der CLI-Umgebung. Siehe [Telemetry & privacy](/de/agenteye/cli#telemetry--privacy) im CLI-Leitfaden. + +--- + +## KI-Assistent-Probleme + +Siehe [enterprise-docs/assistant.md](/de/agenteye/assistant) für die vollständige Einrichtung. + +### Die Assistent-Blase erscheint nicht + +Die Blase ist ausgeblendet, es sei denn, **alle** folgenden Bedingungen sind erfüllt: + +- Der angemeldete Benutzer hat die Berechtigung `agent:use`. +- `AGENTEYE_AGENT_URL` ist am Dashboard gesetzt und der `agent`-Dienst ist erreichbar. +- Ein LLM-Endpunkt ist am `agent`-Dienst konfiguriert (`ANTHROPIC_API_KEY`, ein Gateway über `ANTHROPIC_BASE_URL` oder Bedrock/Vertex). Ohne Konfiguration meldet der Agent "not configured" und die Blase bleibt ausgeblendet. + +Prüfen Sie den Zustand des Agents vom Dashboard-Host aus: `curl http://agent:9100/health` sollte `{"status":"ok","llm_configured":true,...}` zurückgeben. + +### Der Assistent sagt, er kann etwas nicht lesen + +Tools sind pro Benutzer freigegeben. Wenn einem Benutzer `evaluations:read` (oder `events:read`, `dashboards:read`) fehlt, werden die entsprechenden Tools nicht angeboten und der Assistent sagt, er kann diese Daten nicht lesen. Gewähren Sie die entsprechende Leseberechtigung. + +### "assistant not configured" (HTTP 503) beim Senden + +Der `agent`-Container hat keinen LLM-Endpunkt konfiguriert, oder das `AGENTEYE_AGENT_TOKEN` des Dashboards stimmt nicht mit dem des Agents überein. Setzen Sie beides und starten Sie neu. + +### Der `agent`-Container startet neu / OOMs unter Last + +Jedes Gespräch spawnt einen kurzlebigen Kindprozess. Stellen Sie sicher, dass der Container mit einem Init-Prozess läuft (das Image verwendet `tini`; in Compose setzen Sie `init: true`) und geben Sie ihm ausreichende Speicherlimits. Reduzieren Sie `AGENTEYE_AGENT_MAX_STEPS` bei Bedarf. + +--- + +## CLI-Probleme + +### `agenteye` startet nicht mit `ModuleNotFoundError: No module named 'click'` + +Eine frische Installation der `agenteye`-CLI in Version **0.1.6** kann beim Start abstürzen mit: + +``` +ModuleNotFoundError: No module named 'click' +``` + +0.1.6 verlässt sich darauf, dass `click` indirekt von `typer` installiert wird; aktuelle `typer`-Releases ziehen es nicht mehr rein, sodass einer sauberen Umgebung das Paket fehlt. **Aktualisieren Sie auf 0.1.7 oder neuer**, was direkt von `click` abhängt: + +```bash +pipx upgrade agenteye # wenn mit pipx installiert (oder: pipx install --force agenteye) +uv tool upgrade agenteye # wenn mit uv installiert +pip install --upgrade agenteye +``` + +Siehe [enterprise-docs/cli.md](/de/agenteye/cli) für Installationshinweise. + +--- + +## Python SDK-Probleme + +### Keine Dateien erscheinen in `$AGENTEYE_HOME/events/` + +Das SDK puffert Ereignisse und leert standardmäßig alle 500 ms. Wenn Ihr Prozess vor dem Leeren beendet wird, können Ereignisse verloren gehen. Rufen Sie `agenteye.configure(flush_interval=0.1)` für schnelleres Leeren in kurzlebigen Skripten auf, oder stellen Sie sicher, dass Ihr Prozess lange genug für einen Flush-Zyklus läuft. + +Wenn `AGENTEYE_HOME` gesetzt ist, prüfen Sie, ob das SDK nach `$AGENTEYE_HOME/events/` und nicht nach `~/.agenteye/events/` schreibt (erfordert SDK ≥ 0.0.1b5). + +### `ValueError: Reserved field names cannot be used as custom fields` + +Die Namen `timestamp`, `type` und `environment` sind reserviert und können nicht als benutzerdefinierte Felder verwendet werden. Das Übergeben eines davon löst aus: + +``` +ValueError: Reserved field names cannot be used as custom fields: [...] +``` + +Benennen Sie das betreffende benutzerdefinierte Feld um. Beachten Sie, dass `session_id` und `agent_id` explizite Parameter des Ereignisaufrufs sind, keine benutzerdefinierten Felder; das erneute Übergeben eines davon als benutzerdefiniertes Feld löst `TypeError` aus. + +--- + +## Gesundheitsüberwachungs-Probleme + +### Keine Alerts in Slack ankommen (Robusta) + +Robusta-Gesundheitsalarme sind **opt-in**; es wird nichts gesendet, bis es installiert und auf einen Slack-Kanal ausgerichtet ist. Release und Sink prüfen: + +```bash +kubectl get pods -n robusta # robusta-runner + robusta-forwarder sollten Running sein +kubectl logs -n robusta -l app=robusta-runner --tail=50 +``` + +Häufige Ursachen: der Slack-`api_key` / `slack_channel` wurde nicht gesetzt (oder das Token wurde widerrufen); der `api_key` ist ein Robusta Cloud-Relay-Token (`robusta integrations slack`), aber das gebündelte `disableCloudRouting: true` benötigt ein selbst gehostetes Slack-**Bot-Token** (`xoxb-…`), oder setzen Sie `disableCloudRouting: false`; der Sink-`scope` schließt den Namespace aus, in dem Ihre Pods laufen (die gebündelten Values begrenzen auf `agenteye`); oder es ist noch kein Fehler aufgetreten. Erzwingen Sie einen Test-Alert, indem Sie einen Pod herunterfahren: + +```bash +kubectl -n agenteye delete pod -l app=clickhouse # wird neu erstellt +``` + +Siehe [enterprise-docs/health-monitoring.md](/de/agenteye/health-monitoring#2-pod-failure-alerting-with-robusta-opt-in) für Installation und Konfiguration. + +### Server flattert dauerhaft `NotReady` + +Der Readiness-Probe trifft `/ready`, der fehlschlägt, wenn Postgres oder ClickHouse nicht erreichbar ist. Wenn der Server in und aus `NotReady` wechselt, ist eine Abhängigkeit zeitweise nicht verfügbar; prüfen Sie die ClickHouse- und Postgres-Pods sowie die `CLICKHOUSE_URL` / `DATABASE_URL` des Servers. Prüfen Sie, was `/ready` meldet: + +```bash +kubectl -n agenteye exec deploy/server -- sh -c 'curl -s localhost:8080/ready' +``` + +Dieser Probe ist bewusst tolerant (ein großzügiger Fehlerschwellenwert), daher deutet anhaltendes Flattern auf ein echtes Abhängigkeitsproblem hin und nicht auf einen zu aggressiven Probe. Liveness bleibt auf `/health`, daher führt flatternde Readiness **nicht** zum Neustart des Pods. + +## Zertifikatsüberwachungs-Probleme + +### CronJob sendet keine Slack-Benachrichtigungen + +Der `cert-renewal-check`-CronJob benötigt eine Slack-Webhook-URL, die in einem Secret gespeichert ist. Prüfen Sie, ob es vorhanden ist: + +```bash +kubectl get secret cert-renewal-notify-config -n agenteye +``` + +Falls fehlend, erstellen Sie es: + +```bash +kubectl create secret generic cert-renewal-notify-config \ + --namespace agenteye \ + --from-literal=SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL" +``` + +Ohne das Secret läuft der CronJob noch und protokolliert Ergebnisse nach stdout. Logs prüfen mit: + +```bash +kubectl logs -n agenteye -l job-name --tail=50 +``` + +### Client-Zertifikat ist abgelaufen, bevor eine Benachrichtigung empfangen wurde + +Der CronJob läuft alle 12 Stunden. Wenn er nicht gelaufen ist, prüfen Sie seinen Status: + +```bash +kubectl get cronjob cert-renewal-check -n agenteye +``` + +Eine manuelle Prüfung auslösen: + +```bash +kubectl create job --from=cronjob/cert-renewal-check manual-cert-check -n agenteye +kubectl logs -n agenteye -l job-name=manual-cert-check +``` + +Um das abgelaufene Zertifikat sofort neu auszustellen: + +```bash +cd base/certificates/client-certs +./issue-client-cert.sh +``` + +Dann das neu generierte `collector-mtls-secret.yaml` im/in den Cluster(s) anwenden, auf dem/denen Ihre Collectors laufen, und sie neu starten: + +```bash +kubectl apply -f collector-mtls-secret.yaml -n +``` + +--- + +## Backup-Probleme + +### `agenteye-backup` schlägt fehl mit "No space left on device" + +Der `agenteye-backup`-CronJob dumpt Postgres + ClickHouse in ein `backup-tmp`-`emptyDir`-Scratch-Volume (Standard `30Gi`) und **streamt** dann das `tar`-Archiv direkt zu S3 – das komprimierte Archiv wird niemals zurück auf Scratch geschrieben, sodass Scratch nur die *rohen Dumps* halten muss, nicht Dumps plus eine zweite On-Disk-Archivkopie. Ein evictierter Pod / `No space left on device` bedeutet daher, dass die **rohen Dumps** die Scratch-Größe überschreiten (der ClickHouse-`events`-Dump dominiert und wächst im Laufe der Zeit). Prüfen Sie die Logs des fehlgeschlagenen Jobs: + +```bash +kubectl logs -n agenteye -l job-name= +``` + +Lösung: Erhöhen Sie in Ihrem Overlay das `backup-tmp`-`emptyDir`-`sizeLimit` des CronJobs über Ihre gesamte rohe Dump-Größe und stellen Sie sicher, dass der Knoten den ephemeren Speicher tatsächlich halten kann (`sizeLimit` ist eine Obergrenze, keine Reservierung). Wenn die Dumps die Festplatte eines einzelnen Knotens überschreiten, ersetzen Sie `emptyDir` durch ein PVC (EBS/PD) für `backup-tmp` oder komprimieren Sie die Dumps an der Quelle. + +> Ältere Releases schrieben das `.tar.gz` in denselben `20Gi`-Scratch wie die Dumps, sodass `Dumps + Archiv` ihn überflutete und der Pod **vor** dem Upload evictiert wurde – was wie ein S3-Fehler aussieht, aber eigentlich Festplatte ist. Das Streaming des Uploads beseitigt diese Verdopplung. + +### `agenteye-backup` schlägt beim Installieren von `curl` fehl + +Der Job läuft auf dem `postgres:16`-Image und installiert `curl` beim Start für den ClickHouse-HTTP-Dump. Auf einem Cluster ohne Egress zu den Debian-Paketspiegeln schlägt der `apt-get`-Schritt fehl. Erlauben Sie entweder diesen Egress vom Backup-Pod oder baken Sie `curl` in ein gespiegeltes/benutzerdefiniertes Backup-Image und referenzieren Sie es in Ihrem Overlay. + +### `agenteye-backup` läuft, aber nichts landet im Objektspeicher + +Das Base liefert einen echten `BACKUP_BUCKET` (`ts-prod-agenteye/backups`) und das `agenteye-backup`-ServiceAccount. Der Job **streamt** das Archiv zu S3 (`tar cz … | aws s3 cp - s3://…`). Wenn der Backup-Pod keinen Schreibzugriff auf den Bucket hat, gibt der Upload einen Fehler aus – und da das Skript unter `set -euo pipefail` läuft, **schlägt** ein Fehler irgendwo in dieser Pipe den gesamten Job beim `upload`-Schritt fehl statt lautlos nicht zu funktionieren (der EXIT-Trap des Pods protokolliert `backup FAILED during step: upload`). Dies ist auch der Schritt, den Sie *nach* der Behebung einer Scratch-Space-Eviction erreichen, daher prüfen Sie, ob der Upload jetzt landet. Suchen Sie in den Logs des fehlgeschlagenen Jobs nach dem S3-Zugriffsfehler: + +```bash +kubectl logs -n agenteye -l job-name= | grep -iE 's3|upload|denied' +``` + +Lösung: Setzen Sie in Ihrem Overlay `BACKUP_BUCKET` auf einen Bucket, den Sie besitzen, und versehen Sie das vorhandene `agenteye-backup`-ServiceAccount mit Schreibzugriff (IRSA / Workload Identity / Pod Identity). Siehe den **Backups**-Abschnitt von [enterprise-docs/kubernetes-deployment.md](/de/agenteye/kubernetes-deployment). + +--- + +## ClickHouse-basierte Evaluierungen / Sitzungen / Abfragen + +### Die `/queries`-Seiten-Seitenleiste ist nach dem Upgrade leer + +Drei Tabellen (`events`, `evaluations`, `agent_sessions`) werden erwartet. Wenn die SchemaBrowser-Seitenleiste nach dem Upgrade leer ist, hat der Server die ClickHouse-DDL beim Start nicht angewendet. Prüfen Sie die Server-Logs auf `failed to apply CH DDL statement`: + +```bash +kubectl logs -n agenteye deploy/server | grep -E 'clickhouse|CH DDL' +``` + +Die häufigste Ursache ist, dass ClickHouse während der Migrationen nicht erreichbar ist. Der Server verweigert den Start, wenn er CH nicht erreichen kann, daher hat ein hängender Pod in der Regel einen `CrashLoopBackOff` statt einer lautlos defekten Abfrageseite, aber eine teilweise DDL-Anwendung (eine Anweisung OK, die nächste 5xx) lässt das Schema halb fertig. Starten Sie den Server-Pod neu, nachdem CH als erreichbar bestätigt wurde: + +```bash +kubectl rollout restart deploy/server -n agenteye +``` + +### Neue Evaluierungen erscheinen nicht in `/sessions` oder `/queries` + +Nach dem Upgrade werden neue Evaluierungen in ClickHouse geschrieben, nicht in Postgres, und erscheinen unter `/sessions` (durch `evaluations:read` abgesichert) und in `/queries`. Wenn sie nicht erscheinen: + +1. Bestätigen Sie, dass die Evaluierungs-Pipeline aktiviert ist (`EVALUATOR_ENDPOINT` am Server gesetzt) und terminale Ergebnisse produziert; prüfen Sie auf `evaluation_finalized`-Log-Zeilen. +2. Bestätigen Sie, dass CH vom Server aus erreichbar ist: `kubectl exec -n agenteye deploy/server -- curl -fsS http://clickhouse:8123/ping`. +3. Die CH-Tabelle stichprobenartig prüfen: `kubectl exec -n agenteye clickhouse-0 -- clickhouse-client -q 'SELECT count() FROM agenteye.evaluations'`. + +### Abfragen schlagen unter Last fehl mit "Memory limit exceeded" oder ClickHouse ist `OOMKilled` + +**Symptom:** Bei starker Dashboard-/Query-Last schlagen analytische Seiten (Ereignisstrom, `/sessions`, Models-/Latenz-Ansicht, SQL-Editor) fehl oder laufen ab; der Server flattert kurz `NotReady`; und der ClickHouse-Pod zeigt eine steigende Neustart-Anzahl. Dies ist fast immer ein **Speicher**-Problem, kein CPU- oder Festplattenproblem. + +**Bestätigen Sie, dass es Speicher ist** (kein Durchsatzproblem, das Replikation lösen würde): + +1. Prüfen Sie den Pod auf Out-of-Memory-Kills: + ```bash + kubectl -n agenteye describe pod clickhouse-0 | grep -iE 'Restart Count|Last State|Reason|OOMKilled' + ``` + `Reason: OOMKilled` / `Exit Code: 137` mit steigender Neustart-Anzahl ist das Indiz. + +2. ClickHouse fragen, was es ablehnt: + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT name, value FROM system.errors WHERE value>0 ORDER BY value DESC" + ``` + Eine große `MEMORY_LIMIT_EXCEEDED`-Anzahl ist die Signatur. Die Meldung lautet *"maximum: N GiB"* – dieses **N ist `0,9 × das Speicherlimit des Pods`** (das `max_server_memory_usage_to_ram_ratio` in `deploy/base/clickhouse/configmap.yaml`). Wenn Ihre schweren Lesevorgänge mehr als N benötigen, werden sie abgelehnt. + +3. Schließen Sie aus, was *kein* Problem ist – wenn CPU, Part-Anzahl und Festplatte alle niedrig sind, wäre das Hinzufügen von Replikas/Sharding verschwendete Kosten: + ```bash + kubectl -n agenteye top pod clickhouse-0 + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT table, count() parts FROM system.parts WHERE active AND database='agenteye' GROUP BY table" + ``` + +**Ursache:** Das Speicherlimit des ClickHouse-Pods ist zu klein für das analytische Working Set. Die schwersten Lesevorgänge ziehen die rohe JSON-`payload`-Spalte, führen `JSONExtract*` darüber aus und verwenden `FINAL` – jedes kann mehrere GiB benötigen. Wenn die konfigurierten Caches (`mark_cache_size` + `uncompressed_cache_size`) größer als der Pod sind, verschlimmern sie es: Caches werden gegen dasselbe Budget berechnet und verdrängen den Query-Speicher. + +**Lösung – ClickHouse-Speicher skalieren:** + +1. Erhöhen Sie das ClickHouse-Speicherlimit in Ihrem Overlay, indem Sie die Container-`resources` des `clickhouse`-StatefulSets patchen (derselbe Overlay-Mechanismus wie für die anderen Komponenten). Das nutzbare Server-Budget beträgt `0,9 × Limit`, daher gibt ein `6Gi`-Limit ~5,4 GiB, `16Gi` ~14 GiB. Setzen Sie `requests.memory` auch auf einen echten Boden, damit der Scheduler es reserviert. Das Anwenden **erstellt den CH-Pod neu** (einzelnes Replikat → ~30–60s Analytics-Ausfallzeit); tun Sie es in einem Zeitfenster mit geringem Traffic. +2. Halten Sie die Caches in `deploy/base/clickhouse/configmap.yaml` proportional zum Limit – kleine Caches (ein paar hundert MiB) sind auf einem kleinen Pod sicher; erhöhen Sie sie nur zusammen mit einer entsprechenden Speicherlimit-Erhöhung. Pro-Query-`max_memory_usage` ist explizit im `users.xml`-Profil gesetzt (siehe den Fixed-Node-Abschnitt unten) und wird unter der server-level-Obergrenze (`0,9 × Limit`) gehalten, sodass keine einzelne Query mehr RAM haben kann als der Container. +3. Wenn der Knoten selbst die Obergrenze ist, prüfen Sie den Host-Speicher, den ClickHouse sehen kann: + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT formatReadableSize(value) FROM system.asynchronous_metrics WHERE metric='OSMemoryTotal'" + ``` + Wenn das nur etwas über dem Pod-Limit liegt, verschieben Sie ClickHouse auf einen größeren (speicheroptimierten) Knoten – über einen Node-Selector/Affinity in Ihrem Overlay – bevor Sie das Limit weiter erhöhen. + +**Wenn Sie keinen Speicher hinzufügen können: Queries im RAM halten und schnell abbrechen – nicht auf langsamer Festplatte spilten.** Wenn der Knoten fest und der Pod nicht wachsen kann, begrenzen Sie, was eine einzelne Query verwenden darf (damit eine Query nicht den gesamten Knoten übernehmen kann) und lassen Sie auf einer **langsamen (Nicht-SSD) Datenfestplatte** große Aggregationen/Sortierungen **nicht** auf die Festplatte spillen. Das Spillen auf eine langsame Festplatte ist langsamer als der Client-Read-Timeout des Servers, sodass eine spillende Query ein Dashboard-`500` mitten im Flug zurückgibt, während ClickHouse weiter arbeitet – Queries im RAM zu halten und das seltene über-Budget-Query *schnell* abzulehnen (`MEMORY_LIMIT_EXCEEDED`, unter einer Sekunde) stellt das Laden wieder her. Hinweis auf eine ClickHouse-Tücke beim Anwenden: + +- **Dies sind *Profil*-Einstellungen, und ClickHouse liest `` nur aus `users_config` (`users.xml` / `users.d/*.xml`) – niemals aus `config.d`.** Ein ``-Block in `config.d/agenteye.xml` wird **lautlos ignoriert** (`max_execution_time`, `max_memory_usage` usw. werden einfach nicht angewendet). Die gebündelte Konfiguration liefert sie daher als `users.xml`-Schlüssel auf der `clickhouse-config`-ConfigMap, eingebunden unter `/etc/clickhouse-server/users.d/agenteye.xml`. +- Die mitgelieferten Standardwerte: `max_memory_usage` (Pro-Query-Obergrenze – eine Query kann nicht das gesamte Server-Budget verbrauchen), `max_bytes_before_external_group_by` / `max_bytes_before_external_sort` = **`0` (Spill deaktiviert)**, damit Queries im RAM bleiben statt auf der langsamen Festplatte zu kriechen, und `max_execution_time` (Ausreißer-Wächter, abgestimmt auf den Client-Read-Timeout des Servers). +- **Prüfen Sie, ob sie aktiv sind** (so erkennen Sie auch die config.d-Tücke): + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT name, value FROM system.settings + WHERE name IN ('max_memory_usage','max_bytes_before_external_group_by','max_execution_time')" + ``` + Erwarten Sie einen von Null verschiedenen `max_memory_usage` und `max_bytes_before_external_group_by = 0`. Wenn `max_memory_usage` `0`/Standard liest, wird das Profil nicht angewendet – prüfen Sie, ob die Einstellungen in einem `users.d`-Mount leben, nicht in `config.d`. + +Trade-off: Mit deaktiviertem Spill wird eine Query, deren Working Set `max_memory_usage` überschreitet, **abgelehnt** (`MEMORY_LIMIT_EXCEEDED`) statt langsam abzuschließen – auf einer langsamen Festplatte ist diese schnelle Ablehnung vorzuziehen, da eine spillende Query den Client-Timeout überschreiten und trotzdem scheitern würde. Wenn Ihre Datenfestplatte **schnell (SSD)** ist, können Sie stattdessen die `max_bytes_before_external_*`-Schwellenwerte erhöhen, um großen Queries das Spillen auf die Festplatte und das Abschließen zu ermöglichen. + +--- + +## Multi-Tenancy (Organisationen) + +### Fehler beim Upgrade, das Organisationen aktiviert (gemischte alte/neue Server-Pods) + +**Symptom:** Während eines Rolling-Deploys des org-aktivierenden Release schlagen einige Anfragen fehl: Server-Logs zeigen `there is no unique or exclusion constraint matching the ON CONFLICT specification` auf dem `api_keys`-Pfad, und/oder Alert-/Slack-/Webhook-Kanäle hören während des Rollouts auf zu feuern. + +**Ursache:** Das Upgrade ersetzt den alten instanzweiten eindeutigen Index auf `api_keys(name)` durch organisationsspezifische Partial-Indexes und verschiebt die Alert-Kanal-Einstellungen (und `default_user_permissions`) aus der globalen `settings`-Tabelle in pro-org `org_settings`. Ein **alter** Server-Pod gibt noch `ON CONFLICT (name)` aus (jetzt keine passende Einschränkung) und liest noch Kanal-Konfiguration aus den alten `settings`-Zeilen (jetzt leer). Alte und neue Pods können für diese beiden Pfade nicht sicher koexistieren. + +**Lösung:** Rollen Sie dieses bestimmte Upgrade nicht langsam über gemischte Versionen. Führen Sie einen sauberen Cutover durch: Skalieren Sie den alten Server auf null (oder nutzen Sie ein kurzes Wartungsfenster) und bringen Sie die neue Version zusammen mit ihren Migrationen hoch, anstatt alte und neue Replikas nebeneinander zu betreiben. Normaler Traffic und Ingest werden unmittelbar nach dem Cutover wieder aufgenommen; dies betrifft nur das Versions-Übergangsfenster. + +### Bereitstellung einer Organisation schlägt auf `CREATE USER` / `CREATE ROW POLICY` fehl, oder eine Org kann Daten einer anderen Org lesen + +**Symptom:** Das Erstellen einer Org gibt einen Fehler zurück, der `CREATE USER`, `CREATE ROW POLICY` oder "access management is disabled" erwähnt; oder, schlimmer, Mitglieder einer Org sehen Ereignisse/Evaluierungen einer anderen Org im SQL-Editor oder Assistenten. + +**Ursache:** Die pro-org-Isolation wird durch einen dedizierten ClickHouse-Benutzer + Row Policy pro Org durchgesetzt. Dies erfordert, dass SQL **Access Management** aktiviert und `users_without_row_policies_can_read_rows=false` auf ClickHouse gesetzt ist. Mit deaktiviertem Access Management kann die Bereitstellung den Benutzer/die Policy nicht erstellen; mit dem Row-Policy-Standard bei seinem permissiven Wert liest ein Benutzer, der SELECT aber keine Policy hat, **alle** Zeilen (fail-open). + +**Lösung:** Verwenden Sie die gebündelte `deploy/base/clickhouse/`-Konfiguration, die beides setzt. Wenn Sie Ihre eigene ClickHouse-Konfiguration betreiben, aktivieren Sie SQL Access Management für den server-internen Benutzer und setzen Sie `users_without_row_policies_can_read_rows=false` (siehe `deploy/base/clickhouse/configmap.yaml`), starten Sie dann ClickHouse neu und erstellen Sie die Org mit der `agenteye-orgctl`-CLI neu (siehe [enterprise-docs/tenant-management.md](/de/agenteye/tenant-management)). + +### Org-Benutzer verlieren ClickHouse-Zugriff nach Änderung von `ORG_CH_SECRET` + +**Symptom:** Der SQL-Editor und der KI-Assistent geben plötzlich ClickHouse-Authentifizierungsfehler für jede Organisation zurück, unmittelbar nachdem `ORG_CH_SECRET` geändert wurde oder inkonsistent über Replikas gesetzt war. + +**Ursache:** Das ClickHouse-Passwort jeder Org wird als HMAC von `ORG_CH_SECRET` abgeleitet. Das Rotieren (oder das Ausführen von Replikas mit unterschiedlichen Werten) macht die gespeicherten ClickHouse-Anmeldeinformationen jeder Org ungültig; das abgeleitete Passwort stimmt nicht mehr mit dem bereitgestellten Benutzer überein. + +**Lösung:** Setzen Sie `ORG_CH_SECRET` auf einen einzigen starken Wert **vor** der Bereitstellung einer zweiten Org und halten Sie ihn stabil und identisch auf jedem Server-Replikat. Die Server-Boot-Zeit-Abstimmung stellt beim Start den ClickHouse-Benutzer jeder Org aus dem aktuellen Secret wieder her, sodass ein Server-Neustart über alle Replikas (mit konsistentem Secret) die verwaisten Benutzer heilt. Behandeln Sie den Wert als ein langlebiges Secret; rotieren Sie ihn nicht leichtfertig. Als Sicherheitsnetz gilt: Wenn `ORG_CH_SECRET` beim eingebauten Dev-Standard bleibt (d. h. nicht gesetzt ist), **überspringt** die Boot-Zeit-Abstimmung Nicht-Standard-Organisationen und protokolliert einen Fehler statt ihre ClickHouse-Anmeldeinformationen auf den öffentlich bekannten Dev-Wert umzuschreiben, sodass ein einzelnes Replikat, das ohne das Secret neu startet, die anderen Replikas nicht brechen kann. Setzen Sie das Secret konsistent und starten Sie neu, um diese Orgs bereitzustellen. + +### Der KI-Assistent gibt 400 zurück / weigert sich zu chatten nach Aktivierung von Organisationen + +**Symptom:** Das Assistent-Dock lädt, aber jede Nachricht kommt als Fehler zurück (HTTP `400`), und der Agent protokolliert eine abgelehnte org-lose `/chat`-Anfrage. + +**Ursache:** Der Agent ist org-bewusst und schlägt geschlossen fehl; er lehnt ein `/chat` ab, das keinen Organisationskontext enthält. Dies geschieht während eines Übergangs-Rollouts, bei dem der Agent aktualisiert wurde, aber das Dashboard, das die Anfrage sendet, noch nicht org-bewusst ist. + +**Lösung:** Schließen Sie das Rollout ab, sodass das Dashboard Org-Kontext sendet (der normale Endzustand, kein Flag erforderlich). Um die Lücke zu überbrücken, während ein noch-nicht-org-bewusstes Dashboard mit einem org-bewussten Agent spricht, setzen Sie `AGENTEYE_AGENT_ALLOW_NO_ORG=1` am `agent`-Dienst, sodass er auf die `default`-Org zurückfällt statt abzulehnen, und entfernen Sie es, sobald das Dashboard-Upgrade landet. Siehe die Env-Referenz in [enterprise-docs/assistant.md](/de/agenteye/assistant#environment-variable-reference). + +--- + +## Audits + +### Ein Audit läuft nie (nächster Lauf verschiebt sich ständig, keine Laufhistorie) + +**Symptom:** Die Audit-Seite zeigt *last run: never* an, oder `next run` bewegt sich immer weiter in die Zukunft, ohne dass eine Zeile in der Laufhistorie erscheint. + +**Ursache:** Das Audit ist deaktiviert (deaktivierte Audits haben keinen Warteschlangeneintrag), oder die Audit-Worker des Servers schlagen beim Beanspruchen von Arbeit fehl. + +**Lösung:** Bestätigen Sie, dass das Audit **aktiviert** ist (die Run-Now-Schaltfläche erfordert es). Prüfen Sie dann die Server-Logs auf `audits pipeline started` beim Start und auf `audits:`-Fehler – eine `claim_due failed`-Zeile verweist auf Postgres-Konnektivität. `AUDIT_WORKERS` ist standardmäßig `1`; es muss ≥ 1 sein, damit ein Audit läuft. + +### Audit-Läufe erfolgreich, finden aber nichts + +**Symptom:** Die Laufhistorie zeigt `succeeded` mit `findings: 0`, obwohl `/errors` deutlich Fehler zeigt. + +**Ursache:** Das Scan-Fenster deckt die Fehler nicht ab, oder die Scope-Filter schließen sie aus. + +**Lösung:** Prüfen Sie das Lauf-Zeilenfeld (` \ No newline at end of file diff --git a/docs/docs.json b/docs/docs.json index 0feefb27..56e2c9da 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -26,7 +26,10 @@ "groups": [ { "group": "Getting Started", - "pages": ["introduction", "getting-started"] + "pages": [ + "introduction", + "getting-started" + ] }, { "group": "Core Concepts", @@ -52,7 +55,9 @@ }, { "group": "Tools", - "pages": ["dashboard"] + "pages": [ + "dashboard" + ] }, { "group": "Advanced", @@ -70,7 +75,9 @@ "groups": [ { "group": "Examples", - "pages": ["examples"] + "pages": [ + "examples" + ] } ] } @@ -84,7 +91,10 @@ "groups": [ { "group": "快速开始", - "pages": ["zh/introduction", "zh/getting-started"] + "pages": [ + "zh/introduction", + "zh/getting-started" + ] }, { "group": "核心概念", @@ -102,13 +112,17 @@ "zh/cli/remove-policies", "zh/cli/list-policies", "zh/cli/hook", + "zh/cli/auth", + "zh/cli/audit", "zh/cli/version", "zh/cli/environment-variables" ] }, { "group": "工具", - "pages": ["zh/dashboard"] + "pages": [ + "zh/dashboard" + ] }, { "group": "进阶", @@ -126,7 +140,9 @@ "groups": [ { "group": "示例", - "pages": ["zh/examples"] + "pages": [ + "zh/examples" + ] } ] } @@ -140,7 +156,10 @@ "groups": [ { "group": "はじめに", - "pages": ["ja/introduction", "ja/getting-started"] + "pages": [ + "ja/introduction", + "ja/getting-started" + ] }, { "group": "基本概念", @@ -158,13 +177,17 @@ "ja/cli/remove-policies", "ja/cli/list-policies", "ja/cli/hook", + "ja/cli/auth", + "ja/cli/audit", "ja/cli/version", "ja/cli/environment-variables" ] }, { "group": "ツール", - "pages": ["ja/dashboard"] + "pages": [ + "ja/dashboard" + ] }, { "group": "上級", @@ -182,7 +205,9 @@ "groups": [ { "group": "例", - "pages": ["ja/examples"] + "pages": [ + "ja/examples" + ] } ] } @@ -196,7 +221,10 @@ "groups": [ { "group": "시작하기", - "pages": ["ko/introduction", "ko/getting-started"] + "pages": [ + "ko/introduction", + "ko/getting-started" + ] }, { "group": "핵심 개념", @@ -214,13 +242,17 @@ "ko/cli/remove-policies", "ko/cli/list-policies", "ko/cli/hook", + "ko/cli/auth", + "ko/cli/audit", "ko/cli/version", "ko/cli/environment-variables" ] }, { "group": "도구", - "pages": ["ko/dashboard"] + "pages": [ + "ko/dashboard" + ] }, { "group": "고급", @@ -238,7 +270,9 @@ "groups": [ { "group": "예제", - "pages": ["ko/examples"] + "pages": [ + "ko/examples" + ] } ] } @@ -252,7 +286,10 @@ "groups": [ { "group": "Primeros pasos", - "pages": ["es/introduction", "es/getting-started"] + "pages": [ + "es/introduction", + "es/getting-started" + ] }, { "group": "Conceptos principales", @@ -270,13 +307,17 @@ "es/cli/remove-policies", "es/cli/list-policies", "es/cli/hook", + "es/cli/auth", + "es/cli/audit", "es/cli/version", "es/cli/environment-variables" ] }, { "group": "Herramientas", - "pages": ["es/dashboard"] + "pages": [ + "es/dashboard" + ] }, { "group": "Avanzado", @@ -294,21 +335,26 @@ "groups": [ { "group": "Ejemplos", - "pages": ["es/examples"] + "pages": [ + "es/examples" + ] } ] } ] }, { - "language": "pt-BR", + "language": "pt-br", "tabs": [ { "tab": "Documentação", "groups": [ { "group": "Começando", - "pages": ["pt-br/introduction", "pt-br/getting-started"] + "pages": [ + "pt-br/introduction", + "pt-br/getting-started" + ] }, { "group": "Conceitos principais", @@ -326,13 +372,17 @@ "pt-br/cli/remove-policies", "pt-br/cli/list-policies", "pt-br/cli/hook", + "pt-br/cli/auth", + "pt-br/cli/audit", "pt-br/cli/version", "pt-br/cli/environment-variables" ] }, { "group": "Ferramentas", - "pages": ["pt-br/dashboard"] + "pages": [ + "pt-br/dashboard" + ] }, { "group": "Avançado", @@ -350,7 +400,9 @@ "groups": [ { "group": "Exemplos", - "pages": ["pt-br/examples"] + "pages": [ + "pt-br/examples" + ] } ] } @@ -364,7 +416,10 @@ "groups": [ { "group": "Erste Schritte", - "pages": ["de/introduction", "de/getting-started"] + "pages": [ + "de/introduction", + "de/getting-started" + ] }, { "group": "Kernkonzepte", @@ -382,13 +437,17 @@ "de/cli/remove-policies", "de/cli/list-policies", "de/cli/hook", + "de/cli/auth", + "de/cli/audit", "de/cli/version", "de/cli/environment-variables" ] }, { "group": "Werkzeuge", - "pages": ["de/dashboard"] + "pages": [ + "de/dashboard" + ] }, { "group": "Fortgeschritten", @@ -406,7 +465,9 @@ "groups": [ { "group": "Beispiele", - "pages": ["de/examples"] + "pages": [ + "de/examples" + ] } ] } @@ -420,7 +481,10 @@ "groups": [ { "group": "Démarrage", - "pages": ["fr/introduction", "fr/getting-started"] + "pages": [ + "fr/introduction", + "fr/getting-started" + ] }, { "group": "Concepts clés", @@ -438,13 +502,17 @@ "fr/cli/remove-policies", "fr/cli/list-policies", "fr/cli/hook", + "fr/cli/auth", + "fr/cli/audit", "fr/cli/version", "fr/cli/environment-variables" ] }, { "group": "Outils", - "pages": ["fr/dashboard"] + "pages": [ + "fr/dashboard" + ] }, { "group": "Avancé", @@ -462,7 +530,9 @@ "groups": [ { "group": "Exemples", - "pages": ["fr/examples"] + "pages": [ + "fr/examples" + ] } ] } @@ -476,7 +546,10 @@ "groups": [ { "group": "Начало работы", - "pages": ["ru/introduction", "ru/getting-started"] + "pages": [ + "ru/introduction", + "ru/getting-started" + ] }, { "group": "Основные концепции", @@ -494,13 +567,17 @@ "ru/cli/remove-policies", "ru/cli/list-policies", "ru/cli/hook", + "ru/cli/auth", + "ru/cli/audit", "ru/cli/version", "ru/cli/environment-variables" ] }, { "group": "Инструменты", - "pages": ["ru/dashboard"] + "pages": [ + "ru/dashboard" + ] }, { "group": "Продвинутый", @@ -518,7 +595,9 @@ "groups": [ { "group": "Примеры", - "pages": ["ru/examples"] + "pages": [ + "ru/examples" + ] } ] } @@ -532,7 +611,10 @@ "groups": [ { "group": "शुरू करें", - "pages": ["hi/introduction", "hi/getting-started"] + "pages": [ + "hi/introduction", + "hi/getting-started" + ] }, { "group": "मूल अवधारणाएँ", @@ -550,13 +632,17 @@ "hi/cli/remove-policies", "hi/cli/list-policies", "hi/cli/hook", + "hi/cli/auth", + "hi/cli/audit", "hi/cli/version", "hi/cli/environment-variables" ] }, { "group": "उपकरण", - "pages": ["hi/dashboard"] + "pages": [ + "hi/dashboard" + ] }, { "group": "उन्नत", @@ -574,7 +660,9 @@ "groups": [ { "group": "उदाहरण", - "pages": ["hi/examples"] + "pages": [ + "hi/examples" + ] } ] } @@ -588,7 +676,10 @@ "groups": [ { "group": "Başlangıç", - "pages": ["tr/introduction", "tr/getting-started"] + "pages": [ + "tr/introduction", + "tr/getting-started" + ] }, { "group": "Temel Kavramlar", @@ -606,13 +697,17 @@ "tr/cli/remove-policies", "tr/cli/list-policies", "tr/cli/hook", + "tr/cli/auth", + "tr/cli/audit", "tr/cli/version", "tr/cli/environment-variables" ] }, { "group": "Araçlar", - "pages": ["tr/dashboard"] + "pages": [ + "tr/dashboard" + ] }, { "group": "Gelişmiş", @@ -630,7 +725,9 @@ "groups": [ { "group": "Örnekler", - "pages": ["tr/examples"] + "pages": [ + "tr/examples" + ] } ] } @@ -644,7 +741,10 @@ "groups": [ { "group": "Bắt đầu", - "pages": ["vi/introduction", "vi/getting-started"] + "pages": [ + "vi/introduction", + "vi/getting-started" + ] }, { "group": "Khái niệm cốt lõi", @@ -662,13 +762,17 @@ "vi/cli/remove-policies", "vi/cli/list-policies", "vi/cli/hook", + "vi/cli/auth", + "vi/cli/audit", "vi/cli/version", "vi/cli/environment-variables" ] }, { "group": "Công cụ", - "pages": ["vi/dashboard"] + "pages": [ + "vi/dashboard" + ] }, { "group": "Nâng cao", @@ -686,7 +790,9 @@ "groups": [ { "group": "Ví dụ", - "pages": ["vi/examples"] + "pages": [ + "vi/examples" + ] } ] } @@ -700,7 +806,10 @@ "groups": [ { "group": "Per iniziare", - "pages": ["it/introduction", "it/getting-started"] + "pages": [ + "it/introduction", + "it/getting-started" + ] }, { "group": "Concetti chiave", @@ -718,13 +827,17 @@ "it/cli/remove-policies", "it/cli/list-policies", "it/cli/hook", + "it/cli/auth", + "it/cli/audit", "it/cli/version", "it/cli/environment-variables" ] }, { "group": "Strumenti", - "pages": ["it/dashboard"] + "pages": [ + "it/dashboard" + ] }, { "group": "Avanzato", @@ -742,7 +855,9 @@ "groups": [ { "group": "Esempi", - "pages": ["it/examples"] + "pages": [ + "it/examples" + ] } ] } @@ -756,7 +871,10 @@ "groups": [ { "group": "البداية", - "pages": ["ar/introduction", "ar/getting-started"] + "pages": [ + "ar/introduction", + "ar/getting-started" + ] }, { "group": "المفاهيم الأساسية", @@ -774,13 +892,17 @@ "ar/cli/remove-policies", "ar/cli/list-policies", "ar/cli/hook", + "ar/cli/auth", + "ar/cli/audit", "ar/cli/version", "ar/cli/environment-variables" ] }, { "group": "الأدوات", - "pages": ["ar/dashboard"] + "pages": [ + "ar/dashboard" + ] }, { "group": "متقدم", @@ -798,7 +920,9 @@ "groups": [ { "group": "أمثلة", - "pages": ["ar/examples"] + "pages": [ + "ar/examples" + ] } ] } @@ -812,7 +936,10 @@ "groups": [ { "group": "תחילת עבודה", - "pages": ["he/introduction", "he/getting-started"] + "pages": [ + "he/introduction", + "he/getting-started" + ] }, { "group": "מושגי יסוד", @@ -830,13 +957,17 @@ "he/cli/remove-policies", "he/cli/list-policies", "he/cli/hook", + "he/cli/auth", + "he/cli/audit", "he/cli/version", "he/cli/environment-variables" ] }, { "group": "כלים", - "pages": ["he/dashboard"] + "pages": [ + "he/dashboard" + ] }, { "group": "מתקדם", @@ -854,7 +985,9 @@ "groups": [ { "group": "דוגמאות", - "pages": ["he/examples"] + "pages": [ + "he/examples" + ] } ] } @@ -865,50 +998,828 @@ { "product": "AgentEye", "icon": "eye", - "tabs": [ + "languages": [ { - "tab": "Docs", - "groups": [ + "language": "en", + "tabs": [ { - "group": "Getting started", - "pages": ["agenteye/getting-started", "agenteye/github-token"] - }, + "tab": "Docs", + "groups": [ + { + "group": "Getting started", + "pages": [ + "agenteye/getting-started", + "agenteye/github-token" + ] + }, + { + "group": "Deployment", + "pages": [ + "agenteye/deployment", + "agenteye/managed-deployment", + "agenteye/kubernetes-deployment", + "agenteye/single-pod-deployment", + "agenteye/collector-installation", + "agenteye/collector-migration" + ] + }, + { + "group": "Instrumentation and CLI", + "pages": [ + "agenteye/python-sdk", + "agenteye/cli", + "agenteye/cli-recipes", + "agenteye/cli-skill" + ] + }, + { + "group": "Quality", + "pages": [ + "agenteye/evaluation-suite", + "agenteye/audits", + "agenteye/alerts" + ] + }, + { + "group": "Operations", + "pages": [ + "agenteye/api-keys", + "agenteye/tenant-management", + "agenteye/health-monitoring", + "agenteye/assistant", + "agenteye/troubleshooting" + ] + } + ] + } + ] + }, + { + "language": "zh", + "tabs": [ + { + "tab": "文档", + "groups": [ + { + "group": "Getting started", + "pages": [ + "zh/agenteye/getting-started", + "zh/agenteye/github-token" + ] + }, + { + "group": "Deployment", + "pages": [ + "zh/agenteye/deployment", + "zh/agenteye/managed-deployment", + "zh/agenteye/kubernetes-deployment", + "zh/agenteye/single-pod-deployment", + "zh/agenteye/collector-installation", + "zh/agenteye/collector-migration" + ] + }, + { + "group": "Instrumentation and CLI", + "pages": [ + "zh/agenteye/python-sdk", + "zh/agenteye/cli", + "zh/agenteye/cli-recipes", + "zh/agenteye/cli-skill" + ] + }, + { + "group": "Quality", + "pages": [ + "zh/agenteye/evaluation-suite", + "zh/agenteye/audits", + "zh/agenteye/alerts" + ] + }, + { + "group": "Operations", + "pages": [ + "zh/agenteye/api-keys", + "zh/agenteye/tenant-management", + "zh/agenteye/health-monitoring", + "zh/agenteye/assistant", + "zh/agenteye/troubleshooting" + ] + } + ] + } + ] + }, + { + "language": "ja", + "tabs": [ { - "group": "Deployment", - "pages": [ - "agenteye/deployment", - "agenteye/managed-deployment", - "agenteye/kubernetes-deployment", - "agenteye/single-pod-deployment", - "agenteye/collector-installation", - "agenteye/collector-migration" + "tab": "ドキュメント", + "groups": [ + { + "group": "Getting started", + "pages": [ + "ja/agenteye/getting-started", + "ja/agenteye/github-token" + ] + }, + { + "group": "Deployment", + "pages": [ + "ja/agenteye/deployment", + "ja/agenteye/managed-deployment", + "ja/agenteye/kubernetes-deployment", + "ja/agenteye/single-pod-deployment", + "ja/agenteye/collector-installation", + "ja/agenteye/collector-migration" + ] + }, + { + "group": "Instrumentation and CLI", + "pages": [ + "ja/agenteye/python-sdk", + "ja/agenteye/cli", + "ja/agenteye/cli-recipes", + "ja/agenteye/cli-skill" + ] + }, + { + "group": "Quality", + "pages": [ + "ja/agenteye/evaluation-suite", + "ja/agenteye/audits", + "ja/agenteye/alerts" + ] + }, + { + "group": "Operations", + "pages": [ + "ja/agenteye/api-keys", + "ja/agenteye/tenant-management", + "ja/agenteye/health-monitoring", + "ja/agenteye/assistant", + "ja/agenteye/troubleshooting" + ] + } ] - }, + } + ] + }, + { + "language": "ko", + "tabs": [ { - "group": "Instrumentation and CLI", - "pages": [ - "agenteye/python-sdk", - "agenteye/cli", - "agenteye/cli-recipes", - "agenteye/cli-skill" + "tab": "문서", + "groups": [ + { + "group": "Getting started", + "pages": [ + "ko/agenteye/getting-started", + "ko/agenteye/github-token" + ] + }, + { + "group": "Deployment", + "pages": [ + "ko/agenteye/deployment", + "ko/agenteye/managed-deployment", + "ko/agenteye/kubernetes-deployment", + "ko/agenteye/single-pod-deployment", + "ko/agenteye/collector-installation", + "ko/agenteye/collector-migration" + ] + }, + { + "group": "Instrumentation and CLI", + "pages": [ + "ko/agenteye/python-sdk", + "ko/agenteye/cli", + "ko/agenteye/cli-recipes", + "ko/agenteye/cli-skill" + ] + }, + { + "group": "Quality", + "pages": [ + "ko/agenteye/evaluation-suite", + "ko/agenteye/audits", + "ko/agenteye/alerts" + ] + }, + { + "group": "Operations", + "pages": [ + "ko/agenteye/api-keys", + "ko/agenteye/tenant-management", + "ko/agenteye/health-monitoring", + "ko/agenteye/assistant", + "ko/agenteye/troubleshooting" + ] + } ] - }, + } + ] + }, + { + "language": "es", + "tabs": [ { - "group": "Quality", - "pages": [ - "agenteye/evaluation-suite", - "agenteye/audits", - "agenteye/alerts" + "tab": "Documentación", + "groups": [ + { + "group": "Getting started", + "pages": [ + "es/agenteye/getting-started", + "es/agenteye/github-token" + ] + }, + { + "group": "Deployment", + "pages": [ + "es/agenteye/deployment", + "es/agenteye/managed-deployment", + "es/agenteye/kubernetes-deployment", + "es/agenteye/single-pod-deployment", + "es/agenteye/collector-installation", + "es/agenteye/collector-migration" + ] + }, + { + "group": "Instrumentation and CLI", + "pages": [ + "es/agenteye/python-sdk", + "es/agenteye/cli", + "es/agenteye/cli-recipes", + "es/agenteye/cli-skill" + ] + }, + { + "group": "Quality", + "pages": [ + "es/agenteye/evaluation-suite", + "es/agenteye/audits", + "es/agenteye/alerts" + ] + }, + { + "group": "Operations", + "pages": [ + "es/agenteye/api-keys", + "es/agenteye/tenant-management", + "es/agenteye/health-monitoring", + "es/agenteye/assistant", + "es/agenteye/troubleshooting" + ] + } ] - }, + } + ] + }, + { + "language": "pt-br", + "tabs": [ { - "group": "Operations", - "pages": [ - "agenteye/api-keys", - "agenteye/tenant-management", - "agenteye/health-monitoring", - "agenteye/assistant", - "agenteye/troubleshooting" + "tab": "Documentação", + "groups": [ + { + "group": "Getting started", + "pages": [ + "pt-br/agenteye/getting-started", + "pt-br/agenteye/github-token" + ] + }, + { + "group": "Deployment", + "pages": [ + "pt-br/agenteye/deployment", + "pt-br/agenteye/managed-deployment", + "pt-br/agenteye/kubernetes-deployment", + "pt-br/agenteye/single-pod-deployment", + "pt-br/agenteye/collector-installation", + "pt-br/agenteye/collector-migration" + ] + }, + { + "group": "Instrumentation and CLI", + "pages": [ + "pt-br/agenteye/python-sdk", + "pt-br/agenteye/cli", + "pt-br/agenteye/cli-recipes", + "pt-br/agenteye/cli-skill" + ] + }, + { + "group": "Quality", + "pages": [ + "pt-br/agenteye/evaluation-suite", + "pt-br/agenteye/audits", + "pt-br/agenteye/alerts" + ] + }, + { + "group": "Operations", + "pages": [ + "pt-br/agenteye/api-keys", + "pt-br/agenteye/tenant-management", + "pt-br/agenteye/health-monitoring", + "pt-br/agenteye/assistant", + "pt-br/agenteye/troubleshooting" + ] + } + ] + } + ] + }, + { + "language": "de", + "tabs": [ + { + "tab": "Dokumentation", + "groups": [ + { + "group": "Getting started", + "pages": [ + "de/agenteye/getting-started", + "de/agenteye/github-token" + ] + }, + { + "group": "Deployment", + "pages": [ + "de/agenteye/deployment", + "de/agenteye/managed-deployment", + "de/agenteye/kubernetes-deployment", + "de/agenteye/single-pod-deployment", + "de/agenteye/collector-installation", + "de/agenteye/collector-migration" + ] + }, + { + "group": "Instrumentation and CLI", + "pages": [ + "de/agenteye/python-sdk", + "de/agenteye/cli", + "de/agenteye/cli-recipes", + "de/agenteye/cli-skill" + ] + }, + { + "group": "Quality", + "pages": [ + "de/agenteye/evaluation-suite", + "de/agenteye/audits", + "de/agenteye/alerts" + ] + }, + { + "group": "Operations", + "pages": [ + "de/agenteye/api-keys", + "de/agenteye/tenant-management", + "de/agenteye/health-monitoring", + "de/agenteye/assistant", + "de/agenteye/troubleshooting" + ] + } + ] + } + ] + }, + { + "language": "fr", + "tabs": [ + { + "tab": "Documentation", + "groups": [ + { + "group": "Getting started", + "pages": [ + "fr/agenteye/getting-started", + "fr/agenteye/github-token" + ] + }, + { + "group": "Deployment", + "pages": [ + "fr/agenteye/deployment", + "fr/agenteye/managed-deployment", + "fr/agenteye/kubernetes-deployment", + "fr/agenteye/single-pod-deployment", + "fr/agenteye/collector-installation", + "fr/agenteye/collector-migration" + ] + }, + { + "group": "Instrumentation and CLI", + "pages": [ + "fr/agenteye/python-sdk", + "fr/agenteye/cli", + "fr/agenteye/cli-recipes", + "fr/agenteye/cli-skill" + ] + }, + { + "group": "Quality", + "pages": [ + "fr/agenteye/evaluation-suite", + "fr/agenteye/audits", + "fr/agenteye/alerts" + ] + }, + { + "group": "Operations", + "pages": [ + "fr/agenteye/api-keys", + "fr/agenteye/tenant-management", + "fr/agenteye/health-monitoring", + "fr/agenteye/assistant", + "fr/agenteye/troubleshooting" + ] + } + ] + } + ] + }, + { + "language": "ru", + "tabs": [ + { + "tab": "Документация", + "groups": [ + { + "group": "Getting started", + "pages": [ + "ru/agenteye/getting-started", + "ru/agenteye/github-token" + ] + }, + { + "group": "Deployment", + "pages": [ + "ru/agenteye/deployment", + "ru/agenteye/managed-deployment", + "ru/agenteye/kubernetes-deployment", + "ru/agenteye/single-pod-deployment", + "ru/agenteye/collector-installation", + "ru/agenteye/collector-migration" + ] + }, + { + "group": "Instrumentation and CLI", + "pages": [ + "ru/agenteye/python-sdk", + "ru/agenteye/cli", + "ru/agenteye/cli-recipes", + "ru/agenteye/cli-skill" + ] + }, + { + "group": "Quality", + "pages": [ + "ru/agenteye/evaluation-suite", + "ru/agenteye/audits", + "ru/agenteye/alerts" + ] + }, + { + "group": "Operations", + "pages": [ + "ru/agenteye/api-keys", + "ru/agenteye/tenant-management", + "ru/agenteye/health-monitoring", + "ru/agenteye/assistant", + "ru/agenteye/troubleshooting" + ] + } + ] + } + ] + }, + { + "language": "hi", + "tabs": [ + { + "tab": "दस्तावेज़", + "groups": [ + { + "group": "Getting started", + "pages": [ + "hi/agenteye/getting-started", + "hi/agenteye/github-token" + ] + }, + { + "group": "Deployment", + "pages": [ + "hi/agenteye/deployment", + "hi/agenteye/managed-deployment", + "hi/agenteye/kubernetes-deployment", + "hi/agenteye/single-pod-deployment", + "hi/agenteye/collector-installation", + "hi/agenteye/collector-migration" + ] + }, + { + "group": "Instrumentation and CLI", + "pages": [ + "hi/agenteye/python-sdk", + "hi/agenteye/cli", + "hi/agenteye/cli-recipes", + "hi/agenteye/cli-skill" + ] + }, + { + "group": "Quality", + "pages": [ + "hi/agenteye/evaluation-suite", + "hi/agenteye/audits", + "hi/agenteye/alerts" + ] + }, + { + "group": "Operations", + "pages": [ + "hi/agenteye/api-keys", + "hi/agenteye/tenant-management", + "hi/agenteye/health-monitoring", + "hi/agenteye/assistant", + "hi/agenteye/troubleshooting" + ] + } + ] + } + ] + }, + { + "language": "tr", + "tabs": [ + { + "tab": "Belgeler", + "groups": [ + { + "group": "Getting started", + "pages": [ + "tr/agenteye/getting-started", + "tr/agenteye/github-token" + ] + }, + { + "group": "Deployment", + "pages": [ + "tr/agenteye/deployment", + "tr/agenteye/managed-deployment", + "tr/agenteye/kubernetes-deployment", + "tr/agenteye/single-pod-deployment", + "tr/agenteye/collector-installation", + "tr/agenteye/collector-migration" + ] + }, + { + "group": "Instrumentation and CLI", + "pages": [ + "tr/agenteye/python-sdk", + "tr/agenteye/cli", + "tr/agenteye/cli-recipes", + "tr/agenteye/cli-skill" + ] + }, + { + "group": "Quality", + "pages": [ + "tr/agenteye/evaluation-suite", + "tr/agenteye/audits", + "tr/agenteye/alerts" + ] + }, + { + "group": "Operations", + "pages": [ + "tr/agenteye/api-keys", + "tr/agenteye/tenant-management", + "tr/agenteye/health-monitoring", + "tr/agenteye/assistant", + "tr/agenteye/troubleshooting" + ] + } + ] + } + ] + }, + { + "language": "vi", + "tabs": [ + { + "tab": "Tài liệu", + "groups": [ + { + "group": "Getting started", + "pages": [ + "vi/agenteye/getting-started", + "vi/agenteye/github-token" + ] + }, + { + "group": "Deployment", + "pages": [ + "vi/agenteye/deployment", + "vi/agenteye/managed-deployment", + "vi/agenteye/kubernetes-deployment", + "vi/agenteye/single-pod-deployment", + "vi/agenteye/collector-installation", + "vi/agenteye/collector-migration" + ] + }, + { + "group": "Instrumentation and CLI", + "pages": [ + "vi/agenteye/python-sdk", + "vi/agenteye/cli", + "vi/agenteye/cli-recipes", + "vi/agenteye/cli-skill" + ] + }, + { + "group": "Quality", + "pages": [ + "vi/agenteye/evaluation-suite", + "vi/agenteye/audits", + "vi/agenteye/alerts" + ] + }, + { + "group": "Operations", + "pages": [ + "vi/agenteye/api-keys", + "vi/agenteye/tenant-management", + "vi/agenteye/health-monitoring", + "vi/agenteye/assistant", + "vi/agenteye/troubleshooting" + ] + } + ] + } + ] + }, + { + "language": "it", + "tabs": [ + { + "tab": "Documentazione", + "groups": [ + { + "group": "Getting started", + "pages": [ + "it/agenteye/getting-started", + "it/agenteye/github-token" + ] + }, + { + "group": "Deployment", + "pages": [ + "it/agenteye/deployment", + "it/agenteye/managed-deployment", + "it/agenteye/kubernetes-deployment", + "it/agenteye/single-pod-deployment", + "it/agenteye/collector-installation", + "it/agenteye/collector-migration" + ] + }, + { + "group": "Instrumentation and CLI", + "pages": [ + "it/agenteye/python-sdk", + "it/agenteye/cli", + "it/agenteye/cli-recipes", + "it/agenteye/cli-skill" + ] + }, + { + "group": "Quality", + "pages": [ + "it/agenteye/evaluation-suite", + "it/agenteye/audits", + "it/agenteye/alerts" + ] + }, + { + "group": "Operations", + "pages": [ + "it/agenteye/api-keys", + "it/agenteye/tenant-management", + "it/agenteye/health-monitoring", + "it/agenteye/assistant", + "it/agenteye/troubleshooting" + ] + } + ] + } + ] + }, + { + "language": "ar", + "tabs": [ + { + "tab": "المستندات", + "groups": [ + { + "group": "Getting started", + "pages": [ + "ar/agenteye/getting-started", + "ar/agenteye/github-token" + ] + }, + { + "group": "Deployment", + "pages": [ + "ar/agenteye/deployment", + "ar/agenteye/managed-deployment", + "ar/agenteye/kubernetes-deployment", + "ar/agenteye/single-pod-deployment", + "ar/agenteye/collector-installation", + "ar/agenteye/collector-migration" + ] + }, + { + "group": "Instrumentation and CLI", + "pages": [ + "ar/agenteye/python-sdk", + "ar/agenteye/cli", + "ar/agenteye/cli-recipes", + "ar/agenteye/cli-skill" + ] + }, + { + "group": "Quality", + "pages": [ + "ar/agenteye/evaluation-suite", + "ar/agenteye/audits", + "ar/agenteye/alerts" + ] + }, + { + "group": "Operations", + "pages": [ + "ar/agenteye/api-keys", + "ar/agenteye/tenant-management", + "ar/agenteye/health-monitoring", + "ar/agenteye/assistant", + "ar/agenteye/troubleshooting" + ] + } + ] + } + ] + }, + { + "language": "he", + "tabs": [ + { + "tab": "תיעוד", + "groups": [ + { + "group": "Getting started", + "pages": [ + "he/agenteye/getting-started", + "he/agenteye/github-token" + ] + }, + { + "group": "Deployment", + "pages": [ + "he/agenteye/deployment", + "he/agenteye/managed-deployment", + "he/agenteye/kubernetes-deployment", + "he/agenteye/single-pod-deployment", + "he/agenteye/collector-installation", + "he/agenteye/collector-migration" + ] + }, + { + "group": "Instrumentation and CLI", + "pages": [ + "he/agenteye/python-sdk", + "he/agenteye/cli", + "he/agenteye/cli-recipes", + "he/agenteye/cli-skill" + ] + }, + { + "group": "Quality", + "pages": [ + "he/agenteye/evaluation-suite", + "he/agenteye/audits", + "he/agenteye/alerts" + ] + }, + { + "group": "Operations", + "pages": [ + "he/agenteye/api-keys", + "he/agenteye/tenant-management", + "he/agenteye/health-monitoring", + "he/agenteye/assistant", + "he/agenteye/troubleshooting" + ] + } ] } ] diff --git a/docs/es/agenteye/alerts.mdx b/docs/es/agenteye/alerts.mdx new file mode 100644 index 00000000..5b57aec8 --- /dev/null +++ b/docs/es/agenteye/alerts.mdx @@ -0,0 +1,308 @@ +--- +title: "Alertas" +description: "Documentación de Alertas de AgentEye." +--- + +Las alertas evalúan una regla según un calendario y te notifican cuando algo supera un umbral. Transforman AgentEye de un panel pasivo en una superficie de avisos para lo que realmente importa: picos en la tasa de errores, regresiones de latencia, caídas en la puntuación de los evaluadores o cualquier evento personalizado que puedas expresar como una consulta ClickHouse. + +Esta guía cubre qué es una alerta, los cinco tipos de disparadores, los cuatro canales de notificación, el ciclo de vida de los incidentes y los controles operativos disponibles. + +![La página de Alertas: una cuadrícula de tarjetas de reglas de alerta, cada una mostrando su tipo de disparador, ventana de evaluación, canales y una insignia de severidad informativa/advertencia/crítica](/agenteye/images/alerts.png) + +--- + +## Conceptos + +- **Alerta** — la regla. Define *qué* verificar (el disparador), *con qué frecuencia* (el intervalo de evaluación), *cuándo considerarla rota* (lógica compuesta), *qué tan urgente es* (severidad) y *a quién/dónde notificar* (canales). +- **Incidente** — lo que ocurre cuando una alerta se activa. Una alerta tiene como máximo un incidente abierto a la vez. Los incidentes repetidos actualizan la evidencia del mismo incidente. Los incidentes son resueltos por un operador; la resolución automática cuando la regla deja de activarse está planificada pero aún no está habilitada. +- **Canal** — hacia dónde va una notificación: correo electrónico, Slack, webhook genérico o en el panel. Cada alerta puede combinar cualquier combinación de estos. + +Las alertas e incidentes pertenecen a una organización y se comparten entre los operadores de esa organización (en un despliegue de inquilino único, esto es simplemente la organización `default` integrada). Los incidentes pueden asignarse a un operador individual para su triaje. + +--- + +## Tipos de disparadores + +Cinco tipos, cada uno con su propia especificación JSON. Elige el que mejor describa lo que significa "roto" en tu contexto. El formulario de **nueva alerta** del panel construye la misma especificación, adaptando el editor de condiciones al tipo de disparador que selecciones: + +![El formulario de nueva alerta, con los campos básicos (nombre, descripción, habilitado) y el selector de disparador mostrando las opciones: umbral de métrica, SQL personalizado, puntuación de evaluación, fallos de evaluación y por evento](/agenteye/images/alert-new.png) + +### 1. `metric_threshold` + +El más sencillo. Elige una métrica de una lista cerrada, un operador, un umbral y una ventana de tiempo. + +| Métrica | Qué cuenta | +|---|---| +| `event_count` | Total de eventos en la ventana | +| `error_count` | `event_type = 'error'` O cualquier evento con `error_type IS NOT NULL` | +| `error_rate` | `error_count / event_count` (0..1) | +| `p95_latency_ms` | `quantile(0.95)(duration_ms)` sobre todos los eventos con `duration_ms` | +| `p99_latency_ms` | `quantile(0.99)(duration_ms)` | +| `token_sum` | `SUM(input_tokens + output_tokens)` | + +Operadores: `>`, `>=`, `<`, `<=`, `==` (también aceptados como `gt`, `gte`, `lt`, `lte`, `eq`). + +Filtros opcionales: `environment`, `event_type`. + +Ejemplo de especificación: + +```json +{ + "metric": "p95_latency_ms", + "filter": { "environment": "production" }, + "window_secs": 900, + "op": ">", + "value": 5000 +} +``` + +### 2. `custom_sql` + +Para cualquier cosa que las métricas predefinidas no cubran. El SQL proporcionado por el operador pasa por el mismo guardia `/queries/run` (solo SELECT/WITH, una única sentencia, límite de 10 000 filas) antes de que el despachador lo ejecute. Dos modos: + +- **modo rows** (sin `op`/`value`): la alerta se activa en cuanto la consulta devuelve al menos una fila. +- **modo value**: la consulta debe tener un alias de columna llamado `metric_value`; el despachador compara el `metric_value` de la primera fila con `value` usando `op`. + +```json +{ + "sql": "SELECT count() AS metric_value FROM agenteye.events WHERE event_type = 'error' AND ts >= now() - INTERVAL 1 HOUR", + "op": ">", + "value": 100 +} +``` + +### 3. `evaluation_score` + +Lee `agenteye.evaluations` y compara el promedio de una puntuación con nombre a lo largo de una ventana de tiempo. + +```json +{ + "score_key": "hallucination", + "op": ">", + "value": 0.6, + "window_secs": 3600, + "min_count": 5, + "environment": "production" +} +``` + +`min_count` protege contra valores atípicos de una sola muestra; el despachador no se activará hasta que existan al menos N evaluaciones en la ventana. + +### 4. `eval_compound` + +Detecta una regresión de calidad que solo se manifiesta en *varias* puntuaciones de evaluadores a la vez. Mientras que `evaluation_score` monitorea una única puntuación con nombre, `eval_compound` compone múltiples condiciones de puntuación de evaluación en una sola alerta y combina sus resultados con una lógica elegida; así una sola regla puede expresar "activar si la utilidad cae **o** la alucinación sube", "activar solo si la utilidad **y** la eficiencia de herramientas caen ambas", o "activar si **al menos 2 de** estas tres comprobaciones superan el umbral". + +Cada condición lee el promedio de una puntuación con nombre de `agenteye.evaluations` sobre la ventana compartida y la evalúa con su propio operador y umbral. Los resultados booleanos se combinan luego mediante el `combinator`: + +| Combinador | Lógica | Se activa cuando | +|---|---|---| +| `"any"` | O | al menos una condición supera el umbral | +| `"all"` | Y | todas las condiciones superan el umbral | +| `{ "at_least": N }` | M de N | al menos N condiciones superan el umbral | + +```json +{ + "combinator": { "at_least": 2 }, + "conditions": [ + { "score_key": "hallucination", "op": ">", "value": 0.8 }, + { "score_key": "helpfulness", "op": "<", "value": 0.6 }, + { "score_key": "tone", "op": "<", "value": 0.5 } + ], + "window_secs": 3600, + "min_count": 5, + "environment": "production" +} +``` + +- `combinator`: `"any"`, `"all"` o `{ "at_least": N }`. +- `conditions[]`: cada una como `{ score_key, op, value }`, usando los mismos operadores que los demás disparadores (`>`, `>=`, `<`, `<=`, `==`). +- `window_secs`: el período de retrospección compartido que se aplica a cada condición (por defecto `3600`). +- `min_count`: número mínimo de evaluaciones por condición antes de que esa condición pueda superar el umbral; una condición con muy pocas muestras en la ventana se cuenta como "no superada" (por defecto `1`). +- `environment`: opcional; restringe cada condición a un entorno. + +La evidencia de la notificación registra el promedio observado de cada condición, el umbral contra el que se evaluó, cuántas evaluaciones se vieron y si superó el umbral; así puedes ver exactamente qué comprobaciones se activaron. + +### 5. `per_event` + +Para alertas del tipo "ha llegado algún evento que coincide con X". Sin agregación; el despachador se activa en cuanto detecta una coincidencia en la ventana de retrospección. + +```json +{ + "event_type": "error", + "lookback_secs": 60, + "environment": "production", + "tool_name": "bash", + "agent_id": "caa", + "error_type": "TimeoutError", + "message_contains": "vertex-ai timed out" +} +``` + +Todos los filtros se combinan con AND; cualquier campo que omitas queda sin restricción. + +| Campo | Propósito | +|---|---| +| `agent_id` | Restringe a los errores de un agente específico (el que aparece en la fila `/errors`). | +| `error_type` | Restringe a una clase de error específica (p. ej. `TimeoutError`) en lugar de todos los errores. | +| `message_contains` | Coincidencia de subcadena sin distinción entre mayúsculas y minúsculas contra `payload.message`. Útil para capturar un modo de fallo específico (p. ej. `prompt is too long`) sin alertar por cada error del mismo agente. Limitado a 200 caracteres; se compara como cadena literal, no como patrón. | + +Consejo: establece `lookback_secs` de forma aproximada al `eval_interval_secs` de la alerta para evitar notificaciones duplicadas del mismo evento. + +**Atajo desde `/errors`:** el botón **+ alert** en la fila representativa de cada grupo de errores en la vista de errores (y en el panel de detalle de evento de sesión para un evento de error) abre `/alerts/new` con el disparador `per_event` ya completado con el `event_type` y el entorno de esa fila, incluyendo un nombre derivado del `error_type` del payload cuando está disponible. Aún debes seleccionar los canales y confirmar la retrospección, pero el comparador ya viene rellenado. Los operadores necesitan `alerts:write` para que aparezca el botón. + +--- + +## Lógica compuesta (M de N) + +Cada alerta tiene dos controles enteros adicionales al disparador: + +- `eval_window`: cuántas evaluaciones recientes considerar (por defecto 1) +- `min_breaches`: cuántas de esas deben superar el umbral antes de que la alerta se active (por defecto 1) + +`1 de 1` (el valor por defecto) significa "activar en el primer incumplimiento". `3 de 5` significa "activar cuando la regla haya superado el umbral en 3 de las últimas 5 evaluaciones", útil para señales inestables donde una sola medición incorrecta es ruido. El despachador mantiene un búfer circular por alerta; no tienes que gestionar el estado. + +--- + +## Intervalo de evaluación + +`eval_interval_secs` controla con qué frecuencia el despachador ejecuta tu regla. Limitado al rango `[30, 86400]`. Valores predefinidos en el panel: 1m / 5m / 15m / 1h. Elige un intervalo acorde a la velocidad con que cambia la señal subyacente: una alerta de tasa de error de 5 minutos evaluada cada 15 segundos desperdicia CPU; una alerta por evento necesita una retrospección corta o perderá eventos silenciosamente entre ticks. + +--- + +## Canales + +Cada alerta puede combinar cualquiera de estos cuatro. Las credenciales por canal (URL del webhook de Slack, URL del webhook genérico + secreto de firma, destinatarios de correo predeterminados) se configuran una sola vez en **`/settings`** y se referencian por clave desde cada alerta. De esta forma, un canal de Slack puede servir a muchas alertas sin que cada una almacene su propia copia de la URL del webhook. + +Los tres tipos de canales externos (email, Slack, webhook) también están controlados por un interruptor global a nivel de organización, `alerts.enabled_channels`. Cuando una alerta activada incluye un tipo de canal que no está en este conjunto, el despachador lo omite y registra una fila en `alert_notifications` con estado `skipped_disabled` y destino `` (lo que permite pausar globalmente, por ejemplo, todas las entregas de Slack sin editar cada regla). El canal en el panel siempre está habilitado. Consulta [Configuración](#configuration). + +### Correo electrónico + +Reutiliza el mismo transporte SMTP que envía los correos de inicio de sesión OTP. Los destinatarios se resuelven en este orden: + +1. Anulación `recipients[]` por canal (cuando no está vacío). +2. La configuración `alerts.email_default_recipients` (un array de cadenas de correo). + +Si SMTP no está configurado, el canal no hace nada; el despachador igualmente registra una fila en `alert_notifications` con destino `` para que el registro de auditoría haga visible la mala configuración. + +### Slack + +Envía un mensaje Block Kit a una [URL de webhook entrante](https://api.slack.com/messaging/webhooks). + +- URL predeterminada: `alerts.slack_default_webhook` (configurada en `/settings`). +- Anulación por alerta: establece el `webhook_setting_key` del canal a cualquier otra clave de configuración de tipo URL, p. ej. `alerts.slack_oncall`, `alerts.slack_costs`. + +El encabezado incluye un emoji de severidad (`:rotating_light:` / `:warning:` / `:bell:`), y el mensaje incluye un botón con enlace directo a la página del incidente. + +### Webhook genérico + +Una integración JSON-POST para PagerDuty, Opsgenie o tu propio endpoint de ingesta. Estructura del cuerpo: + +```json +{ + "schema_version": 1, + "event": "alert.firing", + "incident": { "id": "uuid", "url": "https://…/incidents/uuid", "opened_at": "2026-…" }, + "alert": { "id": "uuid", "name": "errors > 50/hr", "severity": "critical" }, + "breach": { "value": 73.0, "summary": "ErrorCount > 50 (observed 73.000)", "evidence": { … } } +} +``` + +Cuando `alerts.webhook_signing_secret` está configurado, la solicitud incluye un encabezado `X-AgentEye-Signature: sha256=`, el HMAC-SHA256 del cuerpo usando el secreto. Verifícalo en el lado receptor antes de confiar en el payload. + +El encabezado `X-AgentEye-Event` contiene `alert.firing` / `alert.test`. (`alert.resolved` está reservado para la función de resolución automática planificada y actualmente no se emite.) + +### En el panel + +Sin entrega externa: la alerta simplemente escribe una fila en `alert_notifications` que la página de incidentes del panel muestra. Útil mientras ajustas una regla y no quieres saturar un sistema externo, o para alertas de baja urgencia que los operadores revisan durante el triaje habitual. + +--- + +## Ciclo de vida del incidente + +``` +firing ──ack──▶ acknowledged + │ │ + └────────────────────┴───── operator resolve ───▶ resolved +``` + +- **firing** — el despachador acaba de abrir el incidente o detectó otro incumplimiento. La notificación de activación se envía exactamente una vez (controlada por la marca de tiempo `notified_firing_at` del incidente). +- **acknowledged** — un operador presionó *ack* en `/incidents/:id`. El incidente sigue considerándose abierto; los incumplimientos posteriores actualizarán su evidencia sin volver a notificar. +- **resolved** — un operador presionó *resolve*. La resolución automática cuando la regla deja de incumplir está planificada pero aún no está habilitada, por lo que un incidente abierto permanece abierto hasta que un operador lo resuelva. + +Un nuevo incidente puede reabrirse en la misma alerta en cualquier momento después de que el anterior haya sido resuelto. + +**Línea de tiempo de actividad.** Cada acción sobre un incidente — apertura, reconocimiento, resolución — se registra en un registro de actividad de solo adición y se muestra en la línea de tiempo de *actividad* del incidente, con cada entrada atribuida al operador que la realizó (por correo electrónico) o a **automated** para las acciones que el despachador tomó por su cuenta (apertura automática ante un incumplimiento). El reconocimiento es compartido: varios operadores pueden reconocer el mismo incidente y cada uno aparece como una entrada separada y atribuida. + +La bandeja de entrada de **Incidents** agrupa los incidentes abiertos por estado y permite filtrar por severidad y responsable asignado: + +![La bandeja de entrada de Incidents mostrando tarjetas de incidentes vinculados a alertas y ad-hoc con insignias de severidad y responsables asignados](/agenteye/images/incidents.png) + +Al abrir un incidente se muestra la evidencia del incumplimiento, los responsables asignados y suscriptores, la línea de tiempo de actividad atribuida y un hilo de comentarios: + +![Vista de detalle de un incidente: la alerta padre, resumen del incumplimiento, responsables asignados, suscriptores, registro de actividad atribuido y conversación](/agenteye/images/incident-detail.png) + +--- + +## Permisos requeridos + +La creación de *reglas* de alerta y el triaje de *incidentes* son responsabilidades separadas con permisos distintos, de modo que puedes dar a una rotación de guardia acceso a incidentes sin también otorgarle la capacidad de reescribir las reglas. + +- `alerts:read`: ver reglas de alerta. +- `alerts:write`: crear, editar, eliminar reglas de alerta y disparar una notificación de prueba. +- `incidents:read`: ver incidentes. +- `incidents:write`: abrir incidentes manuales (ad-hoc) que no están vinculados a una alerta. +- `incidents:ack`: reconocer, asignar, comentar y resolver incidentes. + +> **`alerts:ack` heredado.** Las claves y operadores a los que se otorgó el token anterior `alerts:ack` siguen funcionando: se trata como `incidents:ack` (e implica `incidents:read`), por lo que los operadores de guardia existentes mantienen su acceso sin necesidad de reemitir credenciales. Emite nuevos permisos con la familia `incidents:*`. + +Otorga permisos en claves de API (`POST /keys`) y operadores (`PUT /users/:id`). El `PermGate` del panel bloquea los botones relevantes cuando falta un permiso; verás `// 403` junto a la acción. + +> **Selector de destinatarios de correo.** El selector de destinatarios del editor de alertas lista los miembros de tu organización para que puedas seleccionarlos por nombre. Se carga para cualquier operador que tenga `alerts:read` o `alerts:write`; ver el directorio de tu equipo para este fin **no** requiere `users:read`, y el selector devuelve únicamente las direcciones de correo de los miembros, nunca registros de usuario completos. + +--- + +## Configuración + +Variables de entorno consumidas por el despachador: + +| Variable | Por defecto | Propósito | +|---|---|---| +| `ALERT_WORKERS` | `1` | Tareas de worker por instancia de servidor. La mayoría de los despliegues solo necesitan una. | +| `ALERT_CLAIM_BATCH` | `16` | Máximo de alertas que procesa un único tick de worker. | +| `ALERT_POLL_IDLE_SECS` | `5` | Tiempo de espera del worker cuando la cola está vacía. | +| `ALERT_REQUEST_TIMEOUT_MS` | `15000` | Tiempo límite de evaluación por disparador. | +| `DASHBOARD_URL` | `https://app.befailproof.ai` | Origen usado para construir el enlace mágico al incidente en las notificaciones. Establécelo al host de tu panel. | + +Tras un fallo de evaluación transitorio (ClickHouse inaccesible, tiempo límite de consulta), el despachador reintenta la regla con retroceso exponencial. Una vez que una regla acumula **5** fallos transitorios consecutivos, se reprograma a su cadencia normal en lugar de continuar el retroceso, de modo que una regla que falla persistentemente sigue siendo reevaluada. Este límite es fijo y no es configurable por el operador. + +Configuraciones de canal (administradas desde `/settings`, no como variables de entorno): + +- `alerts.email_default_recipients` (`email_list`): array JSON de cadenas de correo — los destinatarios predeterminados para los canales de correo. +- `alerts.slack_default_webhook` (`url`): URL de webhook entrante de Slack por defecto. +- `alerts.webhook_default_url` (`url`): URL de webhook genérico por defecto. +- `alerts.webhook_signing_secret` (`secret`): clave HMAC-SHA256. Siempre se devuelve como `""` en la respuesta GET; escribe un nuevo valor para rotarla. +- `alerts.enabled_channels` (`channel_set`): el conjunto global de tipos de canales externos que se despachan cuando se activa una alerta; por defecto incluye los tres (`email`, `slack`, `webhook`). Eliminar un tipo aquí suprime globalmente ese canal para cada alerta sin editar cada regla. El canal en el panel siempre se entrega y no se ve afectado por esta configuración. + +--- + +## Verificar una nueva alerta + +Antes de confiar en una nueva alerta: + +1. Guárdala como habilitada con al menos un canal de notificación. +2. Selecciona **test** en la página de detalle de la alerta y confirma que cada destino configurado recibe la notificación sintética. +3. Tras el primer incumplimiento real, confirma que el incidente aparece en **Incidents** y que el valor medido coincide con la consulta correspondiente en el panel. + +Los incidentes no se resuelven automáticamente cuando una condición se normaliza. Un operador debe resolverlos desde la página de detalle del incidente. + +--- + +## Solución de problemas + +| Síntoma | Causa probable | +|---|---| +| La alerta nunca se activa | `enabled = false`, o no hay canales adjuntos, o la consulta CH subyacente devuelve 0 filas. Usa *test* para confirmar los canales; usa `/queries/run` para confirmar la métrica. | +| Falta la notificación de Slack | `alerts.slack_default_webhook` (o la clave de anulación por alerta) no está configurada: verifica en `alert_notifications.target` si hay filas con ``; o el tipo `slack` está deshabilitado globalmente en `alerts.enabled_channels`: busca filas en `alert_notifications` con estado `skipped_disabled` y destino ``. | +| Webhook genérico con 401 | El receptor está requiriendo una firma pero `alerts.webhook_signing_secret` no está configurado. Verifica en el receptor que el HMAC coincida con `hmac_sha256(secret, body)`. | +| Correo con "from all sends failed" | Las credenciales SMTP son incorrectas o tu relay rechaza la dirección `from`. Es la misma superficie que envía los correos OTP: si esos funcionan, el transporte SMTP está bien. | +| El incidente se reabre repetidamente | Los controles compuestos son demasiado agresivos: intenta aumentar `min_breaches` o `eval_window` para que los picos transitorios no vuelvan a abrir incidentes que ya resolviste. | \ No newline at end of file diff --git a/docs/es/agenteye/api-keys.mdx b/docs/es/agenteye/api-keys.mdx new file mode 100644 index 00000000..063bda12 --- /dev/null +++ b/docs/es/agenteye/api-keys.mdx @@ -0,0 +1,254 @@ +--- +title: "Claves de API" +description: "Documentación de claves de API de AgentEye." +--- + +AgentEye utiliza claves de API de grano fino para controlar el acceso al servidor. Cada clave lleva uno o más permisos que determinan qué puede hacer. + +--- + +## Permisos + +El servidor aplica un catálogo fijo de permisos; cada uno controla rutas HTTP específicas. Una **clave de administrador** posee todos ellos; una clave con alcance limitado posee el subconjunto que se le otorga en el momento de creación. Las cadenas de permisos desconocidas se rechazan al crear una clave. + +> **No asignables a claves.** Dos permisos válidos son exclusivos para humanos/panel de control y no se pueden otorgar a una clave de API: `orgs:admin` (administración de instancia, solo para operadores) y `keys:update`. Una solicitud a `POST /keys` o `PATCH /keys/:id` que intente otorgar alguno de ellos es rechazada con HTTP 422. Consulta la fila de `keys:update` a continuación para entender por qué una clave portadora puede crear claves pero nunca editarlas. + +### Ingesta y consulta de eventos + +| Permiso | Rutas HTTP | Qué permite | +|---|---|---| +| `events:add` | `POST /events` | Ingestar lotes de eventos desde un recolector. Es el único permiso que necesita un recolector. | +| `events:read` | `GET /events`, `GET /events/latency_aggregate`, `GET /events/environments`, `GET /events/models`, `GET /sessions/:session_id/export` | Consultar eventos, listar los entornos conocidos, listar los identificadores de modelos presentes en los datos (utilizado por la vista de Modelos y los filtros de modelos), calcular el agregado de latencia que alimenta el mapa de calor / banda de percentil, y exportar una sesión como JSONL. Los endpoints de facetas de la barra de filtros compartida `GET /events/environments` y `GET /events/models` son accesibles con **cualquiera** de los permisos `events:read` **o** `evaluations:read`, por lo que la página de sesiones (con acceso restringido a `evaluations:read`) reutiliza la misma faceta por organización. | + +### Sesiones y evaluaciones + +| Permiso | Rutas HTTP | Qué permite | +|---|---|---| +| `evaluations:read` | `GET /sessions`, `GET /evaluations`, `GET /evaluations/aggregate`, `GET /evaluations/environments`, `GET /evaluation-jobs` | Listar sesiones, leer resultados de evaluación, el estado de salud de evaluación consolidado utilizado por los paneles de control, y el estado de la cola de trabajos del trabajador de evaluación. | +| `evaluations:trigger` | `POST /sessions/:session_id/re-evaluate` | Encolar manualmente una re-evaluación para una sesión finalizada. | + +### Paneles de control + +| Permiso | Rutas HTTP | Qué permite | +|---|---|---| +| `dashboards:read` | `GET /dashboards`, `GET /dashboards/:id`, `GET /dashboards/:id/tiles` | Listar paneles de control, cargar uno y leer sus mosaicos. | +| `dashboards:write` | `POST /dashboards`, `PUT /dashboards/:id`, `POST /dashboards/:id/tiles`, `PUT /dashboards/:id/tiles/:tile_id`, `DELETE /dashboards/:id/tiles/:tile_id`, `PUT /dashboards/:id/tiles/layout` | Crear y editar paneles de control, añadir / editar / eliminar mosaicos, y reorganizar la cuadrícula de mosaicos. | +| `dashboards:delete` | `DELETE /dashboards/:id` | Eliminar un panel de control completo (la eliminación a nivel de mosaico se incluye en `dashboards:write`). | + +### Consultas guardadas (compositor SQL) + +| Permiso | Rutas HTTP | Qué permite | +|---|---|---| +| `queries:read` | `GET /queries`, `GET /queries/:id`, `GET /queries/schema` | Listar consultas guardadas, cargar una e inspeccionar el esquema de ClickHouse de solo lectura al que apunta el compositor. | +| `queries:write` | `POST /queries`, `PUT /queries/:id` | Crear y editar consultas guardadas. El SQL sigue enrutándose a través del mismo rol de solo lectura y las mismas comprobaciones de `sql_guard` que una llamada a `queries:run`. | +| `queries:delete` | `DELETE /queries/:id` | Eliminar una consulta guardada. | +| `queries:run` | `POST /queries/run` | Ejecutar SQL guardado o ad-hoc contra el rol de solo lectura utilizado por el compositor. | + +### Asistente de IA + +| Permiso | Rutas HTTP | Qué permite | +|---|---|---| +| `agent:use` | `GET /agent/conversations`, `POST /agent/conversations`, `GET /agent/conversations/:id`, `PATCH /agent/conversations/:id`, `DELETE /agent/conversations/:id`, `PUT /agent/conversations/:id/messages` | Interactuar con el asistente de IA del panel de control y gestionar tus propias conversaciones (privadas). Requerido en el **usuario** para ver el panel del asistente; la clave propia del asistente es `dashboard-assistant` y se inicializa por separado (ver más abajo). | + +### Claves de API + +| Permiso | Rutas HTTP | Qué permite | +|---|---|---| +| `keys:create` | `POST /keys` | Crear una nueva clave de API con alcance limitado. **No** otorga la capacidad de editar los permisos de una clave existente (eso es `keys:update`). | +| `keys:read` | `GET /keys` | Listar las claves existentes. Los secretos nunca se devuelven en este endpoint. | +| `keys:update` | `PATCH /keys/:id` | Editar los permisos de una clave existente. Permiso **exclusivo para humanos/panel de control**; no se puede asignar a una clave de API (una clave portadora puede crear claves pero nunca editarlas). | +| `keys:disable` | `POST /keys/:id/disable` | Revocar una clave. Las claves protegidas (`admin`, `dashboard-assistant`) no se pueden deshabilitar; rótalas mediante variable de entorno + reinicio. | +| `keys:regenerate` | `POST /keys/:id/regenerate` | Rotar el secreto de una clave. Las claves protegidas no se pueden regenerar a través de esta ruta. | + +### Usuarios del panel de control + +| Permiso | Rutas HTTP | Qué permite | +|---|---|---| +| `users:create` | `POST /users`, `GET /users/defaults` | Invitar a un nuevo usuario al panel de control (genera un correo electrónico + inicio de sesión OTP) y leer el conjunto de permisos predeterminado configurado en el panel que se utiliza para rellenar el formulario de invitación. | +| `users:read` | `GET /users`, `GET /users/:id` | Listar usuarios y cargar el registro de un usuario individual. | +| `users:update` | `PUT /users/:id` | Editar los permisos de un usuario. Las actualizaciones envían un correo electrónico de cambio de permisos al usuario afectado y surten efecto en su próxima solicitud; no se requiere volver a iniciar sesión. | +| `users:delete` | `DELETE /users/:id`, `POST /users/:id/enable` | Deshabilitar un usuario (revoca sus sesiones de inmediato) y volver a habilitar a un usuario previamente deshabilitado. | + +Estos permisos respaldan la página **Usuarios** del panel de control, donde los alcances otorgados a cada miembro se muestran como etiquetas: + +![La página de Usuarios: una tarjeta por usuario del panel con su correo electrónico, permisos otorgados y controles de edición/deshabilitación](/agenteye/images/users.png) + +### Configuración operacional + +| Permiso | Rutas HTTP | Qué permite | +|---|---|---| +| `settings:read` | `GET /settings`, `GET /settings/schema`, `GET /settings/model-context-windows`, `GET /settings/model-context-windows/resolve` | Ver la configuración operacional gestionada desde el panel de control y sus metadatos; listar las sobreescrituras de ventana de contexto por modelo; y resolver la ventana efectiva para un modelo. | +| `settings:write` | `PUT /settings/:key`, `PUT /settings/model-context-windows`, `DELETE /settings/model-context-windows` | Editar la configuración operacional y añadir, modificar o eliminar sobreescrituras de ventana de contexto por modelo. Los cambios afectan a los nuevos eventos sin necesidad de reiniciar el servidor. | + +![La página de Configuración: ajustes operacionales gestionados desde el panel, como inicios de sesión permitidos y tiempos de vida de sesión/OTP, editables sin reiniciar](/agenteye/images/settings.png) + +### Alertas e incidentes + +| Permiso | Rutas HTTP | Qué permite | +|---|---|---| +| `alerts:read` | `GET /alerts`, `GET /alerts/:id` | Ver las definiciones de alertas configuradas. | +| `alerts:write` | `POST /alerts`, `PUT /alerts/:id`, `DELETE /alerts/:id`, `POST /alerts/:id/test` | Crear, editar, eliminar y disparar alertas de prueba. | +| `incidents:read` | `GET /alerts/incidents`, `GET /alerts/incidents/:iid`, `GET /alerts/incidents/:iid/comments`, `GET /alerts/incidents/:iid/subscribers` | Ver incidentes y su historial de clasificación. | +| `incidents:write` | `POST /alerts/:id/incidents` | Abrir un incidente manualmente contra una alerta existente. | +| `incidents:ack` | `POST /alerts/incidents/:iid/ack`, `POST /alerts/incidents/:iid/assign`, `POST /alerts/incidents/:iid/resolve`, `POST /alerts/incidents/:iid/comments`, `POST /alerts/incidents/:iid/subscribe`, `POST /alerts/incidents/:iid/unsubscribe` | Reconocer, asignar, resolver y comentar incidentes. | + +### Auditorías + +| Permiso | Rutas HTTP | Qué permite | +|---|---|---| +| `audits:read` | `GET /audits`, `GET /audits/:id`, `GET /audits/:id/runs`, `GET /audits/findings`, `GET /audits/findings/:fid` | Ver definiciones de auditoría, historial de ejecuciones y hallazgos. | +| `audits:write` | `POST /audits`, `PUT /audits/:id`, `DELETE /audits/:id`, `POST /audits/:id/run`, `POST /audits/findings/:fid/status` | Crear, editar, eliminar y ejecutar auditorías; clasificar hallazgos (reconocer / silenciar / descartar / resolver / reabrir / asignar). | + +> Cuando se lanzaron las Auditorías, los permisos de los titulares existentes se ampliaron con la misma estructura de roles que las alertas: todo usuario y conjunto de permisos que tuviera `alerts:read` obtuvo también `audits:read`, y todo titular de `alerts:write` obtuvo también `audits:write`. Las claves de API existentes **no** se ampliaron — otorga `audits:*` a una clave de forma explícita si necesita acceso a la superficie de auditorías. + +> Los permisos almacenados del token heredado `alerts:ack` se interpretan como `incidents:ack`, de modo que los equipos de guardia conservan el acceso sin necesidad de regenerar claves. El token ya no se puede asignar desde el editor de usuarios del panel de control; la matriz ofrece `incidents:ack` en su lugar. + +> El endpoint del selector de destinatarios `GET /alerts/recipients` (que lista los correos electrónicos de miembros a los que puede notificar un editor de alertas) es accesible para cualquier titular de **cualquiera** de los permisos `alerts:read` **o** `alerts:write`, de modo que los editores de alertas pueden poblar el selector sin necesitar el permiso `users:read`. + +> Un visualizador de paneles necesita **tanto** `dashboards:read` (para cargar las vistas guardadas) como `evaluations:read` (las métricas de salud se calculan a partir de los datos de evaluación). Otorga `dashboards:write` para permitir que un usuario cree o edite paneles, y `dashboards:delete` para eliminarlos. + +> `/health` y `/auth/*` (solicitud OTP, verificación OTP, comprobación de sesión, cierre de sesión) no requieren autenticación por diseño; forman parte del flujo de inicio de sesión y la sonda de disponibilidad. `GET /access-granters` requiere una clave válida pero ningún permiso específico, por lo que cualquier usuario autenticado puede ver qué administradores contactar sobre cambios de acceso. + +--- + +## Conjuntos de permisos + +Los conjuntos de permisos permiten aplicar un rol con nombre en lugar de seleccionar manualmente tokens individuales cada vez. En lugar de elegir una docena de permisos uno a uno para cada nuevo usuario del panel de control o clave de API, seleccionas un conjunto, y todos los asignados a él llevan un permiso consistente y revisable. Editar un conjunto personalizado reaplicará el nuevo permiso a todos los usuarios que ya están asignados a él, por lo que un cambio de rol es una sola edición en lugar de recorrer todos los miembros. + +Cada organización se inicializa con tres conjuntos integrados: + +| Conjunto | Permisos | Destinado para | +|---|---|---| +| `read-only` | `events:read`, `keys:read`, `users:read`, `evaluations:read`, `dashboards:read`, `queries:read`, `settings:read`, `alerts:read`, `audits:read`, `incidents:read` | Acceso de solo lectura a todas las superficies operacionales. | +| `standard` | todo lo de `read-only`, más `evaluations:trigger`, `queries:run`, `incidents:ack`, `agent:use` | Solo lectura más las acciones cotidianas del equipo de guardia: ejecutar consultas, re-evaluar sesiones, reconocer incidentes y usar el asistente de IA. | +| `admin` | todos los permisos asignables | Control total de la organización. | + +Los tres conjuntos integrados son **inmutables**; sus nombres siempre tienen el mismo significado, por lo que `read-only`, `standard` y `admin` son seguros de referenciar en políticas e incorporación de usuarios. Un operador puede crear **conjuntos personalizados** adicionales para modelar roles específicos de su organización (por ejemplo, un rol de "autor de paneles" o un rol de "solo recolector"). + +Los conjuntos están disponibles en el panel de control y se gestionan a través de la API en `GET /permission-sets` (listar, con acceso restringido a `users:read`) y `POST /permission-sets` / `PUT /permission-sets/:name` / `DELETE /permission-sets/:name` (crear, editar, eliminar un conjunto personalizado, con acceso restringido a `settings:write`). Se rechaza la eliminación o edición de un conjunto integrado. + +La pertenencia a conjuntos es lo que respalda otras dos funcionalidades: + +- **`DEFAULT_USER_PERMISSIONS`** (el permiso preseleccionado cuando un administrador abre **+ nuevo usuario**) toma como valor predeterminado el conjunto `standard`. Consulta [Implementación](/es/agenteye/deployment). +- **El indicador `--set`** en `agenteye-orgctl` (gestión de miembros por parte del operador) inicia un miembro desde un conjunto con nombre, que luego puedes ajustar con `--add` / `--remove`. Consulta [Gestión de inquilinos](/es/agenteye/tenant-management). + +> Cuando un conjunto incluye un permiso que no se puede asignar a claves (por ejemplo, un conjunto personalizado que lleva `keys:update`), inicializar una clave desde ese conjunto elimina los tokens no asignables; de lo contrario, el servidor rechazaría la clave con HTTP 422. Los usuarios del panel de control no están sujetos a esa restricción. + +--- + +## Clave de administrador de arranque + +La clave de administrador es la única credencial raíz que permite a un operador establecer el acceso desde cero: con ella puedes generar todas las demás claves con alcance limitado, invitar a los primeros usuarios del panel de control y configurar la instancia antes de que exista cualquier otra clave. Es la única clave que no se crea a través de la API de claves; se aprovisiona desde el entorno para que el servidor sea accesible en el primer arranque. + +Establece la variable de entorno `ADMIN_KEY` en el servidor. En cada inicio, el servidor upserts este valor como una clave de administrador con todos los permisos. + +Para rotar: cambia `ADMIN_KEY` a un nuevo secreto y reinicia el servidor. + +--- + +## Alcance por organización + +**Las organizaciones en sí se crean y gestionan fuera de banda por un operador, no a través de esta API de claves.** El ciclo de vida de organizaciones y miembros (crear / renombrar / eliminar / purgar una organización; añadir / actualizar / eliminar un miembro) se realiza con la CLI **`agenteye-orgctl`** que se ejecuta dentro del pod del servidor; no existe ninguna API HTTP ni botón en el panel de control para ello. Consulta [Gestión de inquilinos](/es/agenteye/tenant-management). Lo que *sí* permanece sin cambios: **las claves de API por organización siguen generándose en el panel de control (o a través de esta API de claves)** por los miembros de la organización. + +En un despliegue multi-organización, cada clave que crea un miembro de la organización (a través de esta API de claves o la página **Claves** del panel de control) pertenece a **una organización** y solo puede leer o escribir los datos de esa organización; la organización queda estampada en la clave en el momento de creación y se aplica en cada solicitud. Las dos claves de arranque son la única excepción: la clave `admin` (inicializada desde `ADMIN_KEY`) y la clave `dashboard-assistant` (inicializada desde `AGENT_API_KEY`) tienen **alcance de instancia** (no llevan ninguna organización). El contenedor del panel de control se autentica con la clave `admin` para poder intermediar solicitudes por organización en nombre de los miembros autenticados. Los despliegues de un solo inquilino no necesitan pensar en esto; todas las claves pertenecen a la organización `default` integrada. + +--- + +## Creación de claves + +Utiliza la clave de administrador (o cualquier clave con permiso `keys:create`) para crear claves adicionales con alcance limitado. + +### Clave de recolector (solo ingesta) + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "prod-collector", + "key": "your-collector-secret", + "permissions": ["events:add"] + }' +``` + +### Clave de panel de control (solo lectura) + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "dashboard", + "key": "your-dashboard-secret", + "permissions": ["events:read", "keys:read"] + }' +``` + +Cuando creas una clave a través de la API HTTP, tú mismo proporcionas el valor de `key`; elige un secreto robusto y guárdalo de forma segura. (El panel de control funciona al revés: genera un secreto robusto por ti y te lo muestra una sola vez en el momento de creación; consulta [Gestión de claves en el panel de control](#key-management-in-the-dashboard).) La respuesta confirma que la clave fue creada: + +```json +{ + "id": "550e8400-e29b-41d4-a716-446655440000", + "name": "prod-collector", + "permissions": ["events:add"], + "created_at": "2026-04-01T12:00:00Z" +} +``` + +--- + +## Listado de claves + +```bash +curl -s http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +Los secretos de las claves no se devuelven en las respuestas de listado; solo se devuelven IDs, nombres y permisos. + +--- + +## Deshabilitar una clave + +Deshabilitar una clave revoca el acceso de inmediato sin eliminar el registro de la clave. + +```bash +curl -s -X POST http://your-server:8080/keys//disable \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +--- + +## Regenerar una clave + +Genera un nuevo secreto para una clave existente. El secreto anterior se invalida de inmediato. + +```bash +curl -s -X POST http://your-server:8080/keys//regenerate \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +La respuesta incluye el nuevo secreto en texto plano, **mostrado una sola vez**. + +--- + +## Gestión de claves en el panel de control + +La página **Claves** del panel de control ofrece una interfaz para todas las operaciones anteriores. Necesitas una clave con permiso `keys:read` para ver la lista, y `keys:create` / `keys:update` / `keys:disable` / `keys:regenerate` para las acciones de crear / editar / deshabilitar / regenerar, respectivamente. Editar los permisos de una clave (`keys:update`) es independiente de crearla (`keys:create`), por lo que puedes otorgar a un operador la capacidad de generar claves sin la capacidad de modificar el alcance de las existentes, o viceversa. La clave de administrador cubre todas estas acciones. + +Cuando creas una clave desde el panel de control no proporcionas el secreto; el panel genera un secreto robusto por ti y lo muestra **una sola vez** en el momento de creación. Cópialo de inmediato y guárdalo de forma segura; nunca se vuelve a mostrar, exactamente igual que con una regeneración. También puedes seleccionar los permisos de la clave directamente o inicializarlos desde un conjunto de permisos (ver más abajo). + +![La página de Claves de API: una tarjeta por clave con su nombre, permisos otorgados y fecha de creación, con acciones de regenerar y deshabilitar; las claves protegidas como `admin` están marcadas](/agenteye/images/api-keys.png) + +--- + +## Disposición recomendada de claves + +| Clave | Permisos | Utilizada por | +|---|---|---| +| `admin` (arranque mediante variable de entorno `ADMIN_KEY`) | todos | Operaciones/configuración, y el contenedor del panel de control (se autentica con `ADMIN_KEY`, intermedia solicitudes de usuarios con comprobaciones de permisos) | +| Clave de recolector por host | `events:add` | Recolector en cada máquina agente | +| `dashboard-assistant` (arranque mediante variable de entorno `AGENT_API_KEY`) | `events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run` | Contenedor del asistente de IA, inicializado automáticamente, **protegido**; no se puede editar a través de la API | +| Clave de telemetría del asistente (opcional) | `events:add` | Autoinstrumentación del asistente de IA, si está habilitada | + +> **Clave del asistente.** La clave del asistente se **inicializa automáticamente** por el servidor desde la variable de entorno `AGENT_API_KEY` (el mismo secreto que el agente presenta como `AGENTEYE_API_KEY`); no hay ningún paso manual de generación de claves ni ninguna clave de administrador involucrada. Sus permisos están fijados en el código fuente para que el alcance no pueda ampliarse por mala configuración: lectura sobre eventos / evaluaciones / paneles de control, más escritura en paneles y lectura / escritura / ejecución de consultas para el flujo de creación de consultas mediante IA. Todo el SQL sigue pasando por el mismo rol de solo lectura y las mismas comprobaciones de `sql_guard` que una consulta escrita por un usuario, por lo que esto amplía la *superficie de creación*, no la superficie de datos; las operaciones destructivas (`queries:delete`, `dashboards:delete`) se excluyen deliberadamente de la clave del asistente. Al igual que la clave `admin`, está **protegida**: no se puede deshabilitar ni regenerar a través de la API de claves; solo se puede rotar cambiando `AGENT_API_KEY` y reiniciando. Los *usuarios* del panel de control además necesitan el permiso `agent:use` para ver y usar el asistente. Si habilitas la autoinstrumentación, proporciona al asistente una clave separada exclusiva para `events:add`. \ No newline at end of file diff --git a/docs/es/agenteye/assistant.mdx b/docs/es/agenteye/assistant.mdx new file mode 100644 index 00000000..ef622c1c --- /dev/null +++ b/docs/es/agenteye/assistant.mdx @@ -0,0 +1,203 @@ +--- +title: "Asistente de IA" +description: "Documentación del asistente de IA de AgentEye." +--- + + +El panel de control incluye un **asistente de IA** opcional: un panel de chat anclado al borde derecho del dashboard que responde preguntas en lenguaje natural sobre tus agentes ("¿cómo evoluciona la calidad en producción esta semana?", "¿qué sesiones dieron error hoy?", "resume esta sesión") y, cuando el usuario autoriza cada acción, redacta y guarda consultas SQL y dashboards en su nombre. Cita enlaces clicables directamente a las sesiones, consultas y dashboards relevantes, y es **consciente del contexto de página**: pregunta sobre "esta sesión" mientras la estás viendo y sabrá a qué te refieres. + +El dock se muestra por defecto como un delgado **rail vertical de 44px**: un glifo de prompt `›_` más un punto de salud con color. Haz clic en el rail (o pulsa `⌘J` / `Ctrl+J`) para expandirlo al panel de chat completo. El panel expandido es **redimensionable** entre 320 y 640 píxeles arrastrando su borde izquierdo; tu anchura preferida se recuerda entre recargas. + +Se ejecuta como un pequeño contenedor interno **`agent`** (sobre el Claude Agent SDK) al que solo el dashboard puede acceder. Está **desactivado por defecto** y permanece oculto hasta que configures un endpoint de LLM. + +--- + +## Qué puede y qué no puede hacer + +- **Lee los datos operacionales que el usuario solicitante puede ver.** Eventos, evaluaciones, sesiones, la cola de trabajos de evaluación, consultas guardadas y dashboards guardados, todos acotados por solicitud a los permisos de lectura del usuario. Las herramientas de lectura se ejecutan de inmediato. +- **Las escrituras están sujetas a aprobación por acción.** Puede crear consultas guardadas (`create_saved_query`, `update_saved_query`), ejecutar SQL borrador contra el rol de solo lectura para validarlo (`run_query`), y ensamblar dashboards a partir de esas consultas (`create_dashboard`, `update_dashboard`, `add_query_to_dashboard`). Cada escritura pausa con un prompt **Aprobar / Rechazar / hacer una pregunta** en el chat; el SDK no llama a la herramienta hasta que el operador hace clic en Aprobar. **El borrado nunca está disponible para el asistente**; las operaciones destructivas quedan en manos de los operadores. +- **El SQL generado pasa por la misma validación `sql_guard` y los mismos roles de solo lectura que el SQL escrito por usuarios** (solo SELECT/WITH, sin multisentencia). La ejecución se enruta según las tablas que toca la consulta: las que referencian las tablas de analítica (eventos, evaluaciones, sesiones) se ejecutan como el usuario ClickHouse de solo lectura de la organización (acotado a esa org mediante una política de filas, con un límite de ejecución de 10s y un límite de 100k filas), mientras que las que solo tocan tablas relacionales se ejecutan en un rol Postgres de solo lectura (10s, 10k filas). El asistente no puede ampliar la superficie de datos; solo puede actuar sobre la superficie de consultas que el operador ya tiene. +- Utiliza una **clave de asistente dedicada** (ver más abajo) inicializada con un conjunto fijo de permisos; aunque el modelo se comporte de forma inesperada, no puede exceder esos alcances. +- Cada usuario del dashboard necesita el permiso **`agent:use`** para ver y usar el asistente. Las herramientas se filtran por solicitud para coincidir con los permisos de datos del propio usuario, de modo que un usuario con `events:read` obtiene herramientas de eventos pero no herramientas `dashboards:write`. + +--- + +## Dock de IA consciente del contexto: compositor en `/queries`, chat en el resto + +El dock de asistente del lado derecho es **consciente del contexto de página**. El selector de modelo, el historial de conversación, el punto de salud del modelo y el campo de entrada del chat no cambian, pero las **chips de plantilla del estado vacío, el texto de marcador de posición y el endpoint backend al que llega el mensaje del usuario** cambian automáticamente según la ruta actual. El dock se convierte en "el ayudante de IA para la página en la que estás". + +**Dos backends, elegidos por página (con sobreescrituras por chip).** + +| Ruta | Backend por defecto de página | Por qué | +| ------------------------------ | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | +| `/queries`, `/queries/new` | `POST /api/agent/compose-sql` (sin bucle de herramientas) | El usuario empieza desde cero; SQL con primer token en ≤1s transmitido directamente al editor | +| `/queries/` (existente) | `POST /api/agent/chat` (asistente con bucle completo de herramientas), predeterminado de página | Los mensajes escritos libremente deben permitir al usuario preguntar cualquier cosa ("explica esto", "¿qué hace esto?"); los chips de refactorización vuelven a compose-sql mediante el atributo kind por chip | +| cualquier otra página | `POST /api/agent/chat` (asistente con bucle completo de herramientas) | Herramientas de lectura + herramientas de escritura con aprobación | + +Los chips en `/queries/` llevan un `kind` explícito para que una sola página pueda mezclar ambos flujos sin problemas. El conjunto de chips predeterminado es dos chips de **chat** (`explica la consulta en pantalla`, `¿qué hace esta consulta?`) más cinco chips de **compose-sql** (`parametrizar por rango de fechas`, `añadir filtro status='error'`, etc.). Los mensajes escritos libremente caen al predeterminado de página (chat), por lo que una pregunta como "¿por qué es tan lento?" obtiene una respuesta en prosa, mientras que hacer clic en el chip `parametrizar por rango de fechas` enruta por el endpoint de composición y edita el SQL. + +Cuando el compositor se ejecuta en **modo de edición** (detecta un `currentSql` no vacío porque el usuario está en `/queries/` o `/queries/new` con SQL propuesto ya cargado), su prompt de sistema cambia de "componer una nueva consulta" a "modificar el SQL proporcionado de forma mínima: preservar la elección de tabla, nombres de columnas, estructura de joins, alias, sangría". El modelo recibe un conjunto separado de ejemplos antes/después trabajados (parametrizar, añadir filtro, convertir a cubos por hora), por lo que una refactorización activada por chip produce un diff mínimo sobre el SQL del editor, no una reescritura desde cero. + +Haz clic en un chip de composición (o escribe libremente en `/queries/new`) → el SQL se transmite al mensaje del asistente como un bloque ` ```sql ` delimitado. **En el momento en que la transmisión finaliza, si Monaco está montado en la ruta actual, el editor se activa automáticamente en vista diff** (original a la izquierda, propuesta a la derecha, una indicación `▾ AI proposed an edit` en la parte superior y píldoras **Accept / Reject** debajo). El usuario no necesita buscar ni hacer clic en un botón `Insert into editor` para ver el diff. El botón de inserción se sigue mostrando debajo del bloque SQL como un disparador manual (útil tras un Rechazo o cuando el usuario ha navegado y ha vuelto), y sigue siendo el único camino cuando el usuario está en una página sin editor (por ejemplo, la lista de consultas guardadas); ahí guarda el SQL en `sessionStorage` y navega a `/queries/new`, donde el editor recién montado lee el almacén al montar y abre la misma vista diff. + +Si el SQL propuesto es byte a byte idéntico a lo que ya hay en el editor (una edición sin cambios), la apertura automática se omite; no mostramos un diff vacío. El botón `Insert into editor` también es un no-op en ese caso. + +Cuando el usuario acepta una sugerencia en `/queries/new`, la acción principal de la barra de herramientas muestra **`save`** en lugar de `create`; el SQL les fue entregado por el asistente; el modelo mental es "finalizar esto", no "escribir desde cero". La etiqueta cambia una vez que el dock inserta SQL y se mantiene como `save` hasta que se navega fuera de la página. En `/queries/` el botón siempre ha mostrado `save`; nada cambia ahí. + +Fuera de `/queries`, el dock funciona exactamente como antes: chat completo con tarjetas de aprobación de herramientas, conciencia de contexto de página, citas. + +**Permisos / control de acceso.** El endpoint de composición requiere el permiso `queries:run` por usuario (equivalente a lectura; el usuario aún debe hacer clic en Aceptar y en Ejecutar, y Ejecutar pasa por el `sql_guard` + enrutamiento `references_ch_tables` existente en el servidor Rust). El endpoint de chat requiere `agent:use`. Ambos siguen requiriendo una conexión LLM configurada en el contenedor `agent`; si no hay ninguna configurada, el dock muestra un banner "el asistente no está configurado en este despliegue" en cualquiera de las rutas. + +**Rechazos.** El compositor rechaza cualquier solicitud que no pueda satisfacer con una consulta de analítica de solo lectura y emite `-- REFUSE: ` en lugar de SQL. Rechaza solicitudes que escribirían datos o accederían a tablas fuera de las vistas de analítica (`api_keys`, `users`, `dashboards`, `saved_queries`, `evaluation_jobs`), y rechaza solicitudes de prosa pura ("explica esto", "¿qué hace esto?") en la ruta de composición; esas pertenecen a la ruta de chat y producen una respuesta en prosa allí. El dock muestra la cadena de rechazo como un chip de error rojo en línea en el mensaje del asistente; nada se inserta. + +**Selección de modelo.** Compartida con la ruta de chat. El selector de modelo en la cabecera del dock aplica a ambos endpoints (la llamada de composición pasa el modelo elegido a `resolveModel()` en el servicio del agente). Cuando `AGENTEYE_AGENT_MODELS` lista varios modelos, los operadores pueden combinar una opción tipo Haiku para el compositor con una opción tipo Sonnet para el chat; el usuario elige por conversación. + +**Plantillas por página.** Cada página tiene su propia plantilla (título, cuerpo, texto de marcador de posición y chips de sugerencia) para que el dock se adapte a la página en la que estás. Los chips que se ofrecen en una ruta determinada mapean a los mismos intents para los que el compositor está ajustado, por lo que hacer clic en una sugerencia produce la edición esperada. + +**Desactivarlo.** Igual que la ruta de chat: el dock y el compositor están ambos controlados por el contenedor `agent` y su conexión LLM. Si quieres comportamiento solo de chat para un usuario en particular, elimina el permiso `queries:run` (que también desactiva el botón **Run** del editor); si quieres comportamiento solo de compositor, elimina `agent:use` de los roles de ese usuario y luego vuelve a añadir `queries:run` por separado para que puedan seguir ejecutando SQL escrito por autores. + +--- + +## Activarlo + +El servicio `agent` viene incluido en el archivo Docker Compose y los manifiestos de Kubernetes. Para activar el asistente, proporciona **(1)** un endpoint de LLM y **(2)** la clave de datos dedicada del asistente. + +### 1. Elegir una conexión LLM + +Elige una de estas opciones y configura las variables correspondientes en el servicio `agent`: + +**a) Anthropic directamente** + +``` +ANTHROPIC_API_KEY=sk-ant-... +``` + +**b) A través de Portkey (recomendado; slug del catálogo de modelos, solo clave)** + +``` +PORTKEY_API_KEY= +AGENTEYE_AGENT_MODEL=@/claude-sonnet-4-6 +``` + +Este es el camino más sencillo: en Portkey, configura una **integración Anthropic** (Model +Catalog); obtendrá un **slug**. Nombra el modelo como `@/` y el slug +lleva el enrutamiento de proveedor y credenciales, por lo que **no se necesita clave virtual**, +solo tu clave API de Portkey. El agente envía solo `x-portkey-api-key` y apunta al +gateway de Portkey; Portkey resuelve el resto. (Un nombre de modelo *sin prefijo* falla con +"x-portkey-config or x-portkey-provider header is required"; el prefijo `@slug/` +es lo que hace funcionar el modo solo-clave.) Para un gateway autohospedado configura `PORTKEY_BASE_URL`. + +¿Prefieres enrutamiento por solicitud en lugar de un slug? Configura `PORTKEY_VIRTUAL_KEY=` (o +`PORTKEY_CONFIG=`) con un `AGENTEYE_AGENT_MODEL` simple. + +**c) Cualquier otro gateway compatible con Anthropic (LiteLLM, autohospedado, …)** + +``` +ANTHROPIC_BASE_URL=https://tu-gateway +# Líneas "Nombre: Valor" delimitadas por salto de línea (NO JSON): +ANTHROPIC_CUSTOM_HEADERS=x-my-header: value +``` + +**d) Amazon Bedrock / Google Vertex** + +``` +CLAUDE_CODE_USE_BEDROCK=1 # + credenciales AWS estándar en el entorno +# o +CLAUDE_CODE_USE_VERTEX=1 # + credenciales GCP estándar en el entorno +``` + +Opcionalmente fija el modelo predeterminado con `AGENTEYE_AGENT_MODEL` (predeterminado `claude-sonnet-4-6`). Para permitir que los usuarios **elijan** entre varios modelos, configura `AGENTEYE_AGENT_MODELS` con una lista de permitidos separada por comas (por ejemplo, `@anthropic-prod/claude-opus-4-7,@anthropic-prod/claude-sonnet-4-6`); aparecerá un selector de modelo en la cabecera del chat y la elección de cada usuario se recordará. El agente solo llama a un modelo de esta lista de permitidos. + +### 2. Proporcionar la clave del asistente + +Elige cualquier secreto aleatorio y dáselo al **agent** como `AGENTEYE_API_KEY` y al **server** como `AGENT_API_KEY` (el mismo valor). Al arrancar, el servidor lo inicializa como una clave dedicada llamada `dashboard-assistant` con este conjunto fijo de permisos: `events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run`. Los permisos de escritura solo se ejercen a través de herramientas con aprobación (ver "Qué puede y qué no puede hacer" más arriba). **No hay paso manual de creación de clave ni se involucra ninguna clave de administrador**. El conjunto de permisos está fijo en el servidor, y la clave inicializada está **protegida**: no puede desactivarse ni regenerarse mediante la API de claves; rótala cambiando el valor y reiniciando el servidor. **No** reutilices la clave de administrador/dashboard. + +```bash +SECRET="$(openssl rand -base64 32)" +# en el servicio agent: +AGENTEYE_API_KEY="$SECRET" +# en el servicio server: +AGENT_API_KEY="$SECRET" +``` + +En Kubernetes esto está cableado para ti: coloca `AGENTEYE_API_KEY` en el secreto `agenteye-agent` y el Deployment del servidor ya lee ese mismo valor como `AGENT_API_KEY`. + +### 3. Configurar el token compartido dashboard↔agent + +Configura el mismo `AGENTEYE_AGENT_TOKEN` en **ambos** servicios: `dashboard` y `agent`. El dashboard lo presenta al llamar al servicio interno del agente; el agente rechaza las llamadas sin él. + +### 4. Conceder acceso a los usuarios + +Da a los operadores del dashboard relevantes el permiso `agent:use` (ver [enterprise-docs/api-keys.md](/es/agenteye/api-keys)). Los usuarios sin él nunca verán el asistente. + +Una vez configurados el endpoint LLM y la clave de solo lectura, reinicia el servicio **server** (para inicializar la clave de solo lectura) y el servicio **agent**. El dock del asistente aparece en el borde derecho para cualquier usuario con `agent:use`, colapsado por defecto; haz clic en el rail o pulsa `⌘J` / `Ctrl+J` para expandirlo. + +--- + +## Referencia de variables de entorno + +Configurar en el servicio **`agent`**: + +| Variable | Propósito | +|---|---| +| `PORTKEY_API_KEY` | Enrutar a través de Portkey (el agente construye la conexión al gateway a partir de esto) | +| `PORTKEY_VIRTUAL_KEY` | Clave virtual de Portkey para tus credenciales Anthropic (opcional si la clave tiene una configuración predeterminada) | +| `PORTKEY_CONFIG` / `PORTKEY_BASE_URL` | Configuración Portkey con nombre / URL de gateway Portkey autohospedado (opcional) | +| `PORTKEY_PROVIDER` | Slug de proveedor Portkey — una tercera opción de enrutamiento junto a `PORTKEY_VIRTUAL_KEY` / `PORTKEY_CONFIG` (solo se usa cuando ninguno de estos está configurado) | +| `ANTHROPIC_API_KEY` | Acceso directo a Anthropic (alternativa a un gateway / Bedrock / Vertex) | +| `ANTHROPIC_AUTH_TOKEN` | Token Bearer para un gateway que autentica mediante `Authorization: Bearer` en lugar de `x-api-key` (opcional) | +| `ANTHROPIC_BASE_URL` | Endpoint para un gateway que no sea Portkey | +| `ANTHROPIC_CUSTOM_HEADERS` | Cabeceras adicionales para un gateway que no sea Portkey: líneas `Nombre: Valor` delimitadas por salto de línea (no JSON) | +| `CLAUDE_CODE_USE_BEDROCK` / `CLAUDE_CODE_USE_VERTEX` | Enrutar a través de Bedrock / Vertex | +| `AGENTEYE_AGENT_MODEL` | ID de modelo predeterminado (predeterminado `claude-sonnet-4-6`) | +| `AGENTEYE_AGENT_MODELS` | Lista de modelos permitidos separada por comas entre los que el usuario puede elegir en la cabecera del chat. Déjalo sin configurar para un modelo único fijo. El predeterminado anterior debe estar en esta lista (si no, se añade). | +| `AGENTEYE_AGENT_MAX_CONCURRENCY` | Máximo de chats concurrentes por pod (predeterminado 4); las solicitudes en exceso reciben 429 | +| `AGENTEYE_API_KEY` | Clave de datos del asistente. Configura el **mismo** valor que el `AGENT_API_KEY` del servidor, que lo inicializa con un conjunto fijo de permisos con alcance limitado al arrancar (ver paso 2). | +| `AGENTEYE_AGENT_TOKEN` | Secreto compartido con el dashboard | +| `AGENTEYE_SERVER_URL` | URL del servidor AgentEye (predeterminado `http://server:8080`) | +| `AGENTEYE_AGENT_ALLOW_NO_ORG` | **Multi-tenancy.** Desactivado por defecto (fallo cerrado): el asistente rechaza una solicitud `/chat` que no lleva contexto de organización con `400`, porque todas las herramientas que ejecuta están acotadas a una org. El dashboard siempre envía ese contexto una vez que es org-consciente, por lo que normalmente se deja sin configurar. Configúralo en `1` **solo** durante una implementación transitional donde un dashboard aún no org-consciente está hablando con un agente org-consciente, para que el asistente recurra a la org `default` en lugar de rechazar. Elimínalo una vez que la actualización del dashboard esté desplegada. | +| `AGENTEYE_AGENT_MAX_STEPS` | Máximo de pasos de uso de herramientas por respuesta (predeterminado 8) | +| `AGENTEYE_AGENT_TIMEOUT_MS` | Tiempo de espera total de la solicitud `/chat` (todos los turnos del modelo + pasos de herramientas), en milisegundos (predeterminado 90000); la herramienta SQL tiene su propio límite de 10s | +| `AGENTEYE_AGENT_SELF_TELEMETRY` | `1` para registrar las propias ejecuciones del asistente en AgentEye | +| `AGENTEYE_TELEMETRY_API_KEY` | Clave separada solo `events:add` para autoinstrumentación | +| `AGENTEYE_AGENT_ENV` | Etiqueta de entorno aplicada a la propia autotelemetría del asistente (predeterminado `prod`) | + +Configurar en el servicio **`dashboard`**: + +| Variable | Propósito | +|---|---| +| `AGENTEYE_AGENT_URL` | Dónde el dashboard accede al servicio agent. Los manifiestos de Kubernetes incluidos y el archivo Compose lo configuran como `http://agent:9100`. Déjalo sin configurar para ocultar el asistente por completo. | +| `AGENTEYE_AGENT_TOKEN` | Debe coincidir con el token del agente | + +--- + +## Telemetría y ver qué preguntan los usuarios + +El **contenido de los prompts permanece dentro de tus propios sistemas** por defecto. Tres capas: + +1. **Almacén de conversaciones**: cada prompt y respuesta se guarda en tu base de datos de AgentEye (por usuario, privado), y se puede recargar desde el selector de historial del asistente. Este es el registro duradero de lo que preguntan los usuarios. +2. **Analítica de producto**: el dashboard registra **solo metadatos** (con qué frecuencia se usa el asistente, conteos de herramientas, latencia) en tu analítica. El **texto** de los prompts nunca se incluye en esta ruta. +3. **Autoinstrumentación (opcional)**: configura `AGENTEYE_AGENT_SELF_TELEMETRY=1` (más un `AGENTEYE_TELEMETRY_API_KEY` solo `events:add`) y el asistente registra sus propias ejecuciones en AgentEye como un agente `dashboard-assistant`. Luego puedes ver los prompts de los usuarios y el razonamiento del asistente en las mismas vistas de sesiones/eventos que usas para todo lo demás. Nota: esos eventos son visibles para cualquiera con `events:read`; si eso es demasiado amplio, déjalo desactivado. + +--- + +## Desactivarlo + +Cualquiera de estas opciones desactiva el asistente (el rail del dock desaparece): + +- Elimina `AGENTEYE_AGENT_URL` en el dashboard, **o** +- Deja el endpoint LLM sin configurar en el agente (sin `ANTHROPIC_API_KEY` / gateway / Bedrock / Vertex), **o** +- No despliegues el servicio `agent` en absoluto. + +--- + +## Resumen de seguridad + +- **Sin escrituras silenciosas**: las herramientas de escritura del asistente (`create_saved_query`, `update_saved_query`, `create_dashboard`, `update_dashboard`, `add_query_to_dashboard`) no pueden ejecutarse sin un clic explícito del operador en el botón Aprobar del chat; la puerta previa a la llamada del SDK bloquea la herramienta hasta que una aprobación llega al agente por un canal secundario. No existe ningún ajuste que desactive esta puerta. +- **Alcance de datos fijo y reducido**: el asistente se autentica en el servidor con una clave dedicada cuyo conjunto de permisos está fijo en el servidor (`events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run`). Las únicas escrituras que puede realizar son consultas guardadas y dashboards; el servidor rechaza cualquier cosa fuera de ese alcance independientemente de lo que intente el modelo. +- **Sin superficie de borrado**: la clave no lleva permiso de borrado y no se expone ninguna herramienta de borrado. Los operadores borran a través de la interfaz del dashboard, nunca mediante el asistente. +- **Solo interno**: el agente no tiene ruta pública; solo el dashboard puede llamarlo, y solo con el token compartido. (En Kubernetes, una NetworkPolicy restringe al agente a alcanzar solo el servidor AgentEye y el endpoint LLM.) +- **Acotado por usuario**: solo los usuarios con `agent:use` obtienen el asistente, y solo recibe las herramientas que coincidan con los permisos de lectura de cada usuario. +- **Sin HTML sin procesar / sin exfiltración de enlaces**: las respuestas se renderizan como markdown saneado; los enlaces externos son neutralizados. + +Consulta [enterprise-docs/troubleshooting.md](/es/agenteye/troubleshooting) para problemas comunes. \ No newline at end of file diff --git a/docs/es/agenteye/audits.mdx b/docs/es/agenteye/audits.mdx new file mode 100644 index 00000000..dbb74b3c --- /dev/null +++ b/docs/es/agenteye/audits.mdx @@ -0,0 +1,107 @@ +--- +title: "Auditorías — detección de mejoras agénticas" +description: "Documentación de Auditorías de AgentEye — detección de mejoras agénticas." +--- + + +Las auditorías son tareas recurrentes que analizan los registros de tu agente **a través de sesiones** para encontrar oportunidades de mejora. Mientras que una alerta vigila en tiempo casi real una métrica que ya conoces, una auditoría *investiga*: según la programación que establezcas, ejecuta un pase de políticas determinista sobre la ventana de tiempo y luego desencadena un **agente de fiabilidad con IA** sobre tus sesiones — el agente consulta los datos directamente, lee transcripciones sospechosas y (cuando resulta útil) ejecuta pequeños scripts de análisis, para finalmente redactar **recomendaciones de mejora** con la evidencia que respalda cada una. + +Usa las auditorías para responder a "¿qué debería corregir o mejorar en mis agentes?" — y las alertas para recibir una notificación en el momento en que se supere un umbral específico. Cada mejora enlaza a las sesiones y consultas exactas que la originaron, y con un solo clic puedes crear una alerta preconfigurada para detectar recurrencias. + +La superficie del panel es **`//audits`** (barra lateral → *analyze* → *audits*), protegida por los permisos `audits:read` / `audits:write`. + +--- + +## Cómo funciona una ejecución + +Cada ejecución tiene dos capas: un nivel determinista de base y una investigación agéntica. + +### 1. El pase de políticas (determinista) + +Antes de que se ejecute cualquier modelo, la auditoría lleva a cabo un catálogo de **verificaciones de políticas SQL** sobre la ventana de tiempo: consultas de agregación acotadas que señalan patrones problemáticos conocidos e informan *cuántos* eventos / *qué* sesiones coincidieron — nunca el texto coincidente en sí. El catálogo incluye: + +- **Filtración de secretos o credenciales** en los payloads de eventos — claves de acceso de AWS, claves de API `sk-…`, claves privadas PEM, tokens JWT / bearer y asignaciones de credenciales `KEY=…`. +- **Marcadores de inyección de prompt** — "ignore previous instructions", "reveal your system prompt" y similares. +- **PII** — números con formato de SSN (heurístico). +- **Denegaciones de permisos de herramientas** y **bucles descontrolados de llamadas a herramientas**. + +Los hallazgos de políticas se persisten como resultados (tipo `policy`) que **siempre aparecen** (nunca son recortados por el límite por ejecución) y se entregan al agente de IA como pistas iniciales. Como esta capa no requiere ningún modelo, una auditoría sigue produciendo sus señales de seguridad más importantes incluso si el agente de IA no está disponible. + +### 2. La investigación agéntica (IA) + +A continuación, la auditoría ejecuta un **agente de fiabilidad autónomo** (el mismo servicio Claude Agent SDK que impulsa el asistente del panel, con un prompt específico para auditorías). Dado el **alcance** de la auditoría (agentes × entornos seleccionados) y la **ventana de tiempo**, el agente: + +- ejecuta consultas SQL de solo lectura contra tus tablas de análisis, +- lee un puñado de transcripciones de sesiones representativas, +- opcionalmente escribe y ejecuta breves **scripts de Python en un sandbox aislado dentro del pod** (sin red, sin acceso al sistema de archivos, secretos depurados) para análisis que SQL no puede expresar — agrupación de errores, cálculo de distribuciones, análisis de payloads ya obtenidos, +- y registra cada **mejora** bien fundamentada que encuentra. + +Trabaja a través de varias líneas de investigación — agrupación de errores, desviación respecto a una línea base, fallos de objetivos en transcripciones, mal uso de herramientas, equilibrios calidad/coste y brechas de cobertura — según la **sensibilidad** de la auditoría (baja / media / alta). Cada mejora **debe citar evidencia**: los IDs de sesión que el agente inspeccionó realmente y/o el SQL que ejecutó. El servidor valida que las sesiones citadas existan y **descarta cualquier mejora sin evidencia superviviente**, de modo que el agente investiga pero nunca inventa. + +Cada mejora incluye: + +- una **recomendación** (el cambio concreto a realizar — un ajuste de prompt, una corrección del esquema de herramienta, una política de reintentos, una salvaguarda, mayor cobertura de evaluación), +- un **impacto esperado** y una estimación de **esfuerzo** (bajo / medio / alto), +- una **magnitud** — `big` (un operador debe ser notificado), `medium` (pertenece al informe de la ejecución) o `small` (contexto del panel), +- una **huella** estable (derivada de la categoría + alcance del problema, *no* de las sesiones de esta ejecución) para que el mismo problema se rastree ejecución tras ejecución aunque la evidencia cambie, +- y, cuando un vigilante determinista simple podría detectar recurrencias, una **alerta sugerida** que puedes crear con un solo clic. + +> **La capa de IA es opcional pero recomendada.** Si no hay ningún agente de IA configurado para la pipeline de auditorías, las ejecuciones igualmente se llevan a cabo, persisten los hallazgos de políticas e informan honestamente que "el análisis no está disponible" para la capa agéntica, en lugar de pasar silenciosamente. + +### Modos de fallo + +Las mejoras se clasifican en el **catálogo de modos de fallo** duradero de tu organización (o proponen un nuevo modo). Los modos otorgan a los patrones una identidad estable entre ejecuciones y permiten el seguimiento de recurrencias a largo plazo. + +## Ciclo de vida del triaje + +En la página de un hallazgo (`/audits//findings/`): + +| Acción | Efecto | +|---|---| +| **acknowledge** | Mantiene el hallazgo visible pero reduce su prioridad a la mitad. | +| **resolve** | Lo marca como resuelto. Si el patrón realmente reaparece más tarde, se reabre como **nuevo** — de modo que una regresión es visible, no se pliega silenciosamente al historial. | +| **mute** / **dismiss** | Supresión duradera: la huella del patrón se recuerda y nunca vuelve a aparecer, incluso entre ejecuciones. Usa mute para "conocido y aceptado"; dismiss para "no es útil". | +| **reopen** | Elimina la supresión / resolución y vuelve a clasificar el patrón. | +| **assign** | Enruta el hallazgo a un operador (un miembro de la organización) como responsable. El estado de prioridad y supresión no cambia. | + +El ruido de baja señal se controla por auditoría con un límite de hallazgos por ejecución (`top_k`) sobre las mejoras agénticas. Los hallazgos de políticas omiten este límite (son relevantes para la seguridad y siempre se muestran). Todo lo que quede fuera del límite se contabiliza en las estadísticas de la ejecución — nada se descarta silenciosamente. + +## Programación + +- **Cadencia** (`schedule_interval_secs`): de horaria a semanal; **diaria por defecto**. Las auditorías son deliberadamente más espaciadas que las alertas — una investigación agéntica escanea ventanas completas y se ejecuta durante minutos. +- **Ventana**: ya sea un periodo de retrovisión fijo (p. ej., "cada ejecución escanea los últimos 7 días") o **desde la última ejecución** (por defecto) — cada ejecución retoma donde terminó la anterior exitosa, con una pequeña superposición para que los eventos en los límites nunca se pierdan. +- La siguiente ejecución se programa un intervalo completo después de que la anterior **finalice**, de modo que una ejecución lenta nunca apila una segunda ejecución concurrente de la misma auditoría. +- **Run now** en la página de la auditoría la hace inmediatamente elegible para ejecutarse. + +## Selección de modelo + +Al crear una auditoría puedes elegir qué modelo usa la investigación, de la **lista de modelos que tu operador ha configurado** para el servicio de agentes. Con un único modelo configurado, el selector lo muestra como leyenda; con varios, puedes elegir. Si se deja sin configurar, se usa el modelo predeterminado configurado. + +## Notificaciones + +Cuando una ejecución genera hallazgos **nuevos**, la auditoría notifica a los canales configurados de tu organización — la misma puerta de `alerts.enabled_channels` y los ajustes que usa la pipeline de alertas: + +- **Slack** — un resumen de los nuevos elementos significativos (`big`) con un enlace directo. +- **Email** — un **informe de auditoría** diseñado que lista las nuevas mejoras (severidad máxima, recomendaciones por elemento, enlace directo), enviado cuando la auditoría tiene un canal de **email** adjunto y hay al menos un nuevo hallazgo. + +Los hallazgos recurrentes pero conocidos no generan nuevas notificaciones. + +## Referencia de configuración + +Las definiciones de auditoría se gestionan en el panel (`/audits/new`) o a través de la API. Los ajustes por auditoría incluyen la cadencia y ventana de programación, el alcance (`{"environments": [...], "agent_ids": [...]}`), la sensibilidad (`low` / `medium` / `high`), los canales de notificación, el límite de hallazgos por ejecución (`top_k`) y el modelo (mediante `llm_budget.model`). Los ajustes del servidor a nivel de operador (tiempos de espera, sandbox, la URL del servicio de agentes) están documentados en [deployment.md](/es/agenteye/deployment). + +## API + +Todos los endpoints tienen alcance de organización y siguen la autenticación estándar por clave bearer (consulta [api-keys.md](/es/agenteye/api-keys)). + +| Endpoint | Permiso | Propósito | +|---|---|---| +| `GET /audits` · `POST /audits` | `audits:read` / `audits:write` | Listar / crear definiciones de auditoría. | +| `GET` / `PUT` / `DELETE /audits/:id` | read / write / write | Inspeccionar, editar, eliminar una auditoría. | +| `POST /audits/:id/run` | `audits:write` | Hacer que la auditoría se ejecute de inmediato. | +| `GET /audits/:id/runs` | `audits:read` | Historial de ejecuciones (ventana, estado, estadísticas, conteo de hallazgos). | +| `GET /audits/findings` | `audits:read` | Hallazgos a nivel de organización, filtrables por `audit_id`, `status`; ordenados por prioridad. | +| `GET /audits/findings/:fid` | `audits:read` | Detalle completo del hallazgo (recomendación, evidencia, prioridad). | +| `POST /audits/findings/:fid/status` | `audits:write` | Triaje: `{"action": "ack" \| "mute" \| "dismiss" \| "resolve" \| "reopen" \| "assign"}`. | + +Para los casos "la auditoría se ejecutó pero no encontró nada", "el sandbox de código está deshabilitado" y "el email de auditoría no se entregó", consulta [troubleshooting.md](/es/agenteye/troubleshooting#audits). \ No newline at end of file diff --git a/docs/es/agenteye/cli-recipes.mdx b/docs/es/agenteye/cli-recipes.mdx new file mode 100644 index 00000000..4cb85f12 --- /dev/null +++ b/docs/es/agenteye/cli-recipes.mdx @@ -0,0 +1,169 @@ +--- +title: "Recetas de CLI para agentes" +description: "Documentación de recetas de CLI de AgentEye para agentes." +--- + +Extrae datos de sesiones, eventos y evaluaciones (y dispara reevaluaciones) directamente desde un script o agente de código, con JSON limpio en stdout que se canaliza directamente a `jq`. Estas recetas convierten los datos de observabilidad de AgentEye en algo que un usuario de terminal o un agente de código con IA (Claude Code, Cursor) puede consultar y automatizar, sin necesidad de navegar por el dashboard. + +Los patrones que se muestran a continuación están listos para copiar y pegar en la CLI de AgentEye (`agenteye`). Para instalación, autenticación y la lista completa de opciones, consulta [CLI](/es/agenteye/cli); ejecuta `agenteye -h` o `agenteye -h` para la ayuda integrada. + +## Reglas de oro + +1. **Las opciones globales van *antes* del comando.** `agenteye --json sessions` es correcto; `agenteye sessions --json` no lo es. Las opciones globales son `--json`, `--base-url`, `--org`, `--token`, `--insecure`/`--secure`, `--timeout`, `--quiet`, `--no-color`. +2. **Usa `--json` siempre que vayas a procesar la salida.** Los datos van a **stdout** como JSON; los mensajes de estado para humanos y los errores van a **stderr**, por lo que stdout permanece limpio para canalizar a `jq`. +3. **Ramifica según el código de salida**, no por el texto de stderr: `0` ok · `2` argumentos incorrectos · `3` no se puede alcanzar el dashboard · `4` no autenticado o sesión expirada · `5` permiso insuficiente. +4. **Explora con `-h`.** Cada comando documenta sus filtros, formatos de valores y estructura JSON. + +## Configuración inicial + +```bash +export AGENTEYE_DASHBOARD_URL=https://agenteye.example.com # para no repetir --base-url +agenteye login --email you@example.com # pega el código enviado por correo; válido ~24h +``` + +## Verificar autenticación antes de trabajar + +`whoami` nunca falla por sesión inexistente o expirada; en su lugar reporta `logged_in:false`, por lo que un agente puede comprobar el estado de autenticación de forma segura. (Puede seguir retornando un código no cero si no hay URL base configurada o el dashboard no está disponible.) + +```bash +if [ "$(agenteye --json whoami | jq -r .logged_in)" != "true" ]; then + echo "Not authenticated. Run: agenteye login" >&2; exit 1 +fi +``` + +## Encontrar sesiones fallidas o con puntuación baja + +```bash +# sesiones en las últimas 24h cuya evaluación arrojó error +agenteye --json sessions --since 24h --status error | jq -r '.sessions[].session_id' + +# evaluaciones con puntuación <= 0.5 en helpfulness, para un agente concreto +agenteye --json evals --agent-id checkout-bot --score helpfulness:..0.5 \ + | jq '.evaluations[] | {session_id, scores}' +``` + +El filtrado por puntuación está en **`evals`**, no en `sessions`. `--score KEY:MIN..MAX` es repetible y se combina con AND; cualquiera de los límites es opcional (`..0.5` significa ≤ 0.5, `0.9..` significa ≥ 0.9). Puedes pasar hasta 20 filtros de puntuación por solicitud; más devuelve HTTP 400. `sessions` comparte los filtros `--env`, `--status`, `--agent-id`, `--session-id` y de rango de tiempo con `evals`, pero no tiene `--score`. + +## Leer una sesión de principio a fin + +No existe un comando único `session show` — combina el historial de eventos con la evaluación de la sesión: + +```bash +# la evaluación más reciente de la sesión (estado + puntuaciones) +agenteye --json evals --session-id run-001 | jq '.evaluations[0] | {status, scores}' + +# todos los eventos de la ejecución (aumenta --limit para un barrido completo) +agenteye --json events --session-id run-001 --all --limit 1000 | jq '.events[] | {ts, event_type}' + +# solo las llamadas a herramientas de una sesión +agenteye --json events --session-id run-001 --event-type tool_use,tool_result --all \ + | jq '.events[].payload' +``` + +## Obtener todo (paginación) + +Los resultados se muestran del más reciente al más antiguo y están paginados por cursor. + +```bash +# de una vez: obtener hasta 500 filas en páginas de 200 +agenteye --json events --session-id run-001 --limit 500 --all > events.json + +# paginación manual: reutiliza next_cursor +page=$(agenteye --json events --limit 100) +cursor=$(echo "$page" | jq -r '.next_cursor // empty') +[ -n "$cursor" ] && agenteye --json events --limit 100 --cursor "$cursor" +``` + +## Reducir la salida con --fields + +Limita las claves (tanto en la tabla como con `--json`) para reducir lo que un agente debe leer. + +```bash +agenteye --json sessions --since 7d --fields session_id,status,scores | jq -c '.sessions[]' +agenteye --json events --session-id run-001 --fields ts,event_type --all +``` + +Los nombres de campo desconocidos son rechazados (salida `2`) con la lista de válidos, una forma económica de descubrir nombres de campo. + +## Descubrir valores válidos de filtros + +```bash +agenteye --json list envs | jq -r '.values[]' # valores para --env +agenteye --json list tools | jq -r '.values[]' # nombres de herramientas; también agents, models, event_types, … +agenteye --json list score_filters | jq -r '.values[]' # KEY válido para --score KEY:MIN..MAX +``` + +## Seleccionar tu organización (multi-tenant) + +Si perteneces a más de una organización, elige el tenant activo al iniciar sesión (se guarda): + +```bash +agenteye login --org acme --email you@corp.com # establece el tenant en el mismo paso que el login +agenteye --json orgs list | jq -r '.orgs[].org_slug' +agenteye --org globex --json sessions --since 24h # sobreescribe para un solo comando +``` + +Un login multi-org sin `--org` termina con código no cero y muestra las organizaciones disponibles. + +## Provisionar una clave API para el SDK/colector + +```bash +# el secreto se muestra UNA SOLA VEZ — con --json está en el campo .key +key=$(agenteye --json keys create ci-bot --add events:read.add | jq -r '.key') +agenteye keys regenerate ci-bot --yes # rotar; agenteye keys disable ci-bot --yes para revocar +``` + +## Ejecutar una consulta guardada o ad-hoc + +```bash +agenteye --json query run --sql "select count(*) from analytics.events" | jq '.rows' +agenteye --json query run errs --arg prod | jq '.rows' # una consulta guardada + un argumento posicional $1 +``` + +## Gestionar un incidente de forma no interactiva + +```bash +id=$(agenteye --json incidents list --state firing | jq -r '.incidents[0].id') +agenteye incidents ack "$id" +agenteye incidents assign "$id" you@corp.com +agenteye incidents resolve "$id" --yes +``` + +> Las mutaciones omiten automáticamente su prompt de confirmación cuando se usa `--json` o cuando stdin no es un TTY, por lo que los agentes nunca quedan bloqueados; usa `--yes`/`-y` para omitirlo explícitamente en otros contextos. + +## Manejo de códigos de salida en un script + +```bash +out=$(agenteye --json sessions --since 1h) || code=$? +case "${code:-0}" in + 0) echo "$out" | jq '.sessions | length' ;; + 4) echo "Session expired - run 'agenteye login'." >&2 ;; + 5) echo "Missing permission (ask an admin for evaluations:read)." >&2 ;; + 3) echo "Dashboard unreachable - check the URL." >&2 ;; + *) echo "Unexpected error (exit ${code})." >&2 ;; +esac +``` + +## Estructuras de la salida JSON + +| Comando | JSON en stdout (con `--json`) | +|---|---| +| `whoami` | `{"logged_in": true, "id", "email", "is_instance_admin", "active_org", "permissions": [...], "memberships": [...]}` o `{"logged_in": false}` | +| `orgs list` | `{"active_org", "orgs": [{"org_slug","org_name","permission_set","permissions"}]}` | +| `events` | `{"events": [...], "next_cursor": }` | +| `evals` | `{"evaluations": [...], "next_cursor": }` | +| `sessions` | `{"sessions": [...], "next_cursor": }` | +| `errors` | `{"errors": [...], "next_cursor": }` | +| `list ` | `{"kind", "values": [...]}` | +| `keys list` / `keys create` | `{"keys": [...]}` / `{id, name, permissions, created_at, key}` (`key` se muestra una sola vez) | +| `query run` | `{columns: [{name,type}], rows: [[...]], truncated, elapsed_ms}` | +| `users list` / `settings list` | `{"users": [...]}` / `{"settings": [...]}` | +| `alerts list` / `incidents list` | `{"alerts": [...]}` / `{"incidents": [...]}` | +| create/update/delete (cualquiera) | el objeto del recurso, o `{"deleted": true, "id"}` para eliminaciones | +| failure (cualquiera, con `--json`) | `{"error": "...", "exit_code": , "status"?: , "hint"?: "..."}` en stdout | + +- Cada elemento **event** (`events`): `id, session_id, agent_id, event_type, ts, payload, environment`. +- Cada elemento **evaluation** (`evals`): `id, session_id, agent_id, environment, status, scores, reasoning, summary, error, attempt_count, duration_ms, completed_at, created_at`. +- Cada elemento **session** (`sessions`): `session_id, agent_id, environment, status, scores, event_count, started_at, last_event_at, first_event_id, last_event_id, latest_evaluation`. + +El parámetro `--fields` de cada comando acepta exactamente los nombres de campo de sus propios elementos — el conjunto difiere entre `sessions` y `evals`, por lo que un nombre válido para uno puede ser rechazado por el otro. \ No newline at end of file diff --git a/docs/es/agenteye/cli-skill.mdx b/docs/es/agenteye/cli-skill.mdx new file mode 100644 index 00000000..fbf128dc --- /dev/null +++ b/docs/es/agenteye/cli-skill.mdx @@ -0,0 +1,95 @@ +--- +title: "Habilidad de Agente CLI AgentEye" +description: "Documentación de la habilidad de Agente CLI AgentEye." +--- + + +La **habilidad CLI de AgentEye** (`agenteye-cli`) es una *Habilidad de Agente* instalable que enseña a un agente de codificación — Claude Code, Codex y herramientas compatibles — a operar tu despliegue de AgentEye a través de la [`agenteye` CLI](/es/agenteye/cli) mediante solicitudes en lenguaje natural: *"¿hay algo roto hoy?"*, *"dale a CI una clave que solo pueda enviar eventos"*, *"reconoce el incidente activo y asígnamelo"*. + +**No** es un servicio ni un binario independiente. Es un pequeño paquete de instrucciones que se apoya en la CLI que ya tienes instalada: el agente ejecuta `agenteye --json …`, analiza el JSON limpio y te responde en prosa. Todo lo que puede hacer, podrías hacerlo tú mismo escribiendo los mismos comandos. + +--- + +## Cómo se relaciona con las demás interfaces de AgentEye + +AgentEye te ofrece cuatro formas de acceder a los mismos datos y controles. Se complementan entre sí: + +| Interfaz | Qué es | Dónde se ejecuta | Úsala cuando | +|---|---|---|---| +| **[CLI](/es/agenteye/cli)** | La referencia de comandos y opciones de `agenteye` | Tu terminal | Quieres ejecutar o automatizar un comando específico | +| **[Recetas de CLI](/es/agenteye/cli-recipes)** | Patrones de `jq`/pipeline listos para copiar | Tu terminal / scripts | Estás integrando la CLI en automatización | +| **Habilidad CLI** (este documento) | Una puerta de entrada en lenguaje natural a la CLI | Tu agente de codificación, en tu estación de trabajo | Quieres *simplemente preguntar* y dejar que el agente elija el comando | +| **[Asistente de IA en el panel](/es/agenteye/assistant)** | Un chat integrado en el panel | Un contenedor `agent` interno en tu clúster | Quieres hacer preguntas sobre tus datos directamente en el panel | + +### vs. el Asistente de IA en el panel — una distinción importante + +Son dos herramientas distintas con radios de acción muy diferentes: + +- El **Asistente de IA en el panel** ([assistant.md](/es/agenteye/assistant)) es un chat integrado en el panel, respaldado por un contenedor `agent` interno. Es **de solo lectura más autoría con aprobación**: puede redactar consultas guardadas y paneles, pero cada escritura se detiene para que hagas clic de aprobación explícita, y nunca elimina nada. Requiere el permiso `agent:use` y solo accede a los datos de la organización que estás viendo. +- La **habilidad CLI** se ejecuta en *tu* estación de trabajo dentro de *tu* agente de codificación y maneja la `agenteye` CLI **como tú**. Puede realizar toda la **superficie de la CLI, incluidas las mutaciones** — crear/rotar/deshabilitar claves de API, cambiar configuración de la organización, resolver incidentes, eliminar consultas guardadas — limitada únicamente por los permisos de tu sesión en la CLI. Trátala exactamente con el mismo cuidado con el que tratarías ejecutar esos comandos manualmente. + +--- + +## Requisitos previos + +1. La **CLI `agenteye` instalada** y disponible en el `PATH` (ver [cli.md](/es/agenteye/cli) — `pipx install agenteye`). +2. La **URL del panel** configurada (`AGENTEYE_DASHBOARD_URL`, o el agente pasa `--base-url`). +3. Una **sesión iniciada**: ejecuta `agenteye login` tú mismo primero. La habilidad **no puede** completar el inicio de sesión con código de un solo uso enviado por correo — te indicará que ejecutes `agenteye login` si la sesión está ausente o caducada (código de salida `4` de la CLI). + +--- + +## Instalación de la habilidad + +Las Habilidades de Agente son carpetas que contienen un `SKILL.md` (más referencias opcionales). Instala la habilidad `agenteye-cli` colocando su carpeta donde tu agente busca habilidades: + +- **Claude Code** — copia la carpeta `agenteye-cli/` en `~/.claude/skills/` (disponible en todos los proyectos) o en `/.claude/skills/` (limitado a ese repositorio). Claude Code la detecta automáticamente; verifica con la lista `/skills`, o simplemente haz una pregunta que coincida con su descripción. +- **Codex (OpenAI)** — Codex lee el mismo `SKILL.md`. El archivo `agents/openai.yaml` incluido establece `allow_implicit_invocation: true`, por lo que Codex selecciona la habilidad automáticamente cuando una tarea coincide; de lo contrario, invócala explícitamente como `$agenteye-cli`. + +La habilidad se mantiene junto con la CLI `agenteye` y se distribuye como parte de tu paquete AgentEye — si no tienes la carpeta `agenteye-cli`, contacta a tu responsable de AgentEye. No hay restricciones de acceso: no necesita ninguna imagen Docker ni credencial, ya que solo maneja la `agenteye` CLI **pública** contra tu propio panel. + +--- + +## Seguridad — las mutaciones NO solicitan confirmación cuando un agente ejecuta la CLI + +**Lee esto antes de permitir que un agente realice cambios.** + +La CLI `agenteye` normalmente pregunta *"¿estás seguro?"* antes de una acción destructiva. **Omite automáticamente esa confirmación siempre que no esté conectada a un terminal — que es exactamente como la ejecuta un agente de codificación — y `--json` también la omite.** Por lo tanto, el aviso de seguridad **no** se activará para el agente. + +La habilidad está diseñada para compensar esto: se le instruye que indique el comando exacto que ejecutará y obtenga tu **confirmación explícita antes de cualquier cambio de estado**. Mantén esa disciplina — cuando manejas AgentEye a través de un agente, *tú* eres el paso de confirmación. Los comandos que modifican estado que debes vigilar: + +- `keys create` / `update` / `disable` / `regenerate` +- `users create` / `update` / `disable` / `enable` +- `settings set` +- `alerts create` / `update` / `delete` / `test` +- los subcomandos de escritura de `incidents`: `ack` / `assign` / `resolve` / `open` / `comment-add` / `comment-delete` / `subscribe` / `unsubscribe` +- `query create` / `update` / `delete` +- `agent rename` / `delete` +- `orgs switch` + +Todo lo que está bajo **Observe** (`events`, `sessions`, `evals`, `errors`, `list`, `whoami`, `orgs list/current/perms`) es de solo lectura y no modifica nada. + +Dado que el agente actúa **como tú**, solo puede hacer lo que tu sesión tiene permitido — los permisos se resuelven **por organización** (ver [api-keys.md](/es/agenteye/api-keys)). Un comando para el que no tienes permiso devuelve el código de salida `5` con el nombre exacto del permiso requerido, por lo que el agente puede indicarte con precisión qué solicitar a un administrador en lugar de fallar de forma opaca. + +--- + +## Qué puedes pedirle + +La habilidad traduce la intención en lenguaje natural al comando `agenteye` correcto, descubriendo primero los valores válidos (`list `, `whoami`) para no adivinar: + +- *"¿Hay algo roto o fallando en las últimas 24 horas?"* → `errors --since 24h --aggregate`, seguido de un desglose. +- *"¿Por qué falló la sesión `run-001`?"* → `events --session-id run-001 --all` + `evals --session-id run-001`. +- *"¿Cómo evoluciona la calidad esta semana?"* → `evals --aggregate --since 7d`, luego profundiza en las ejecuciones con puntuación baja. +- *"Dale a CI una clave que solo pueda enviar eventos."* → `keys create ci --add events:add` (indica el comando, luego lo crea y captura el secreto de un solo uso). +- *"¿Quién tiene acceso? Haz que Dana sea solo lectura."* → `users list` → `users update dana@… --permission-set read-only` (tras confirmar contigo). +- *"Reconoce el incidente activo y asígnamelo."* → `incidents list --state firing` → `incidents ack ` / `incidents assign tu@…`. + +Para los comandos exactos, opciones y estructuras JSON detrás de estos casos, consulta [cli.md](/es/agenteye/cli) y [cli-recipes.md](/es/agenteye/cli-recipes). + +--- + +## Ver también + +- **[CLI](/es/agenteye/cli)** — referencia completa de comandos y opciones para `agenteye`. +- **[Recetas de CLI para agentes](/es/agenteye/cli-recipes)** — patrones de `jq` listos para copiar y manejo de códigos de salida. +- **[Asistente de IA](/es/agenteye/assistant)** — el asistente integrado en el panel (no confundir con esta habilidad de terminal). +- **[Claves de API](/es/agenteye/api-keys)** — el modelo de permisos por organización que delimita lo que la habilidad puede hacer. \ No newline at end of file diff --git a/docs/es/agenteye/cli.mdx b/docs/es/agenteye/cli.mdx new file mode 100644 index 00000000..4c0261c9 --- /dev/null +++ b/docs/es/agenteye/cli.mdx @@ -0,0 +1,292 @@ +--- +title: "CLI" +description: "Documentación del CLI de AgentEye." +--- + + +El CLI de AgentEye (`agenteye`) es un cliente de terminal para tu despliegue de AgentEye. Consulta tus datos (sesiones, registros de eventos, evaluaciones) y administra la organización (claves API, usuarios, configuración, alertas, incidentes, consultas guardadas) — todo lo que hace el dashboard, desde un script o un agente de codificación. Cada comando admite el flag `--json`, por lo que funciona igual de bien para una persona en una terminal o para un agente de codificación (Claude Code, Cursor) que ejecuta comandos y parsea el resultado. + +> Este es el **CLI `agenteye`**, una herramienta distinta del demonio **collector** (`agenteye-collector`). El CLI se comunica con tu **dashboard**; el collector envía eventos al servidor. Consulta [Instalación del Collector](/es/agenteye/collector-installation) para el collector. + +--- + +## Instalación + +El CLI está publicado en PyPI público como **`agenteye`**. Dado que el SDK de Python de AgentEye también usa el nombre de distribución `agenteye`, instala el CLI en un entorno **aislado** (`pipx` o `uv tool`) para que los dos nunca colisionen en un mismo virtualenv: + +```bash +pipx install agenteye +# o +uv tool install agenteye +``` + +Un `pip install agenteye` normal también funciona si no estás instalando el SDK de Python en el mismo entorno. El CLI requiere Python 3.10+ y no necesita ningún token de GitHub; es un paquete público. + +El comando instalado es **`agenteye`**: + +```bash +agenteye --version +agenteye --help +``` + +--- + +## Autenticación + +El CLI se autentica en el **dashboard** con un código de un solo uso enviado por correo: + +```bash +agenteye login --email tu@ejemplo.com +# Se te enviará un código de 6 dígitos por correo; pégalo cuando se te pida. +``` + +El token de sesión se almacena en `~/.agenteye/cli.json` (solo legible por ti, modo `0600`) y es válido por 24 horas de forma predeterminada. Cuando expire, ejecuta `agenteye login` de nuevo. + +```bash +agenteye whoami # muestra el usuario actual, la organización activa y los permisos +agenteye logout # revoca la sesión y borra el token almacenado +``` + +`whoami` nunca falla si la sesión no existe o ha expirado — en su lugar reporta `logged_in: false`, de modo que un script o agente puede verificar el estado de autenticación de forma segura (puede seguir saliendo con código distinto de cero si no hay URL base configurada o el dashboard no es accesible). + +**Requisitos:** tu correo debe tener permiso para iniciar sesión en el dashboard (consúltalo con tu administrador de AgentEye), y el dashboard debe ser accesible en su URL base (ver [Configuración](#configuration)). Si solicitas un código y no llega, probablemente tu correo aún no está habilitado para acceder al dashboard. + +--- + +## Elegir tu organización (multi-tenant) + +Si tu cuenta pertenece a más de una organización, elige la activa **al iniciar sesión** — se guarda y se usa en todos los comandos posteriores: + +```bash +agenteye login --org acme # autenticarse y establecer el tenant activo en un solo paso +agenteye orgs list # las organizaciones a las que tienes acceso (la activa está marcada) +agenteye orgs switch globex # cambiar el predeterminado guardado +agenteye --org globex sessions # sobreescribir para un solo comando +``` + +Si perteneces a exactamente una organización, se selecciona automáticamente y puedes ignorar `--org` por completo. Si perteneces a varias y no eliges ninguna, el CLI las lista y te pide que vuelvas a ejecutar con `--org `. La organización activa se envía al dashboard en cada solicitud, y tus permisos se resuelven **por organización** — `agenteye whoami` muestra la organización activa, tus permisos en ella y todas tus membresías. + +--- + +## Configuración + +| Ajuste | Flag | Variable de entorno | Valor predeterminado | +|---|---|---|---| +| URL base del dashboard | `--base-url` | `AGENTEYE_DASHBOARD_URL` | **requerido** (sin valor predeterminado) | +| Organización/tenant activo | `--org` | `AGENTEYE_ORG` | elegido al iniciar sesión; guardado en `~/.agenteye/cli.json` | +| Token de sesión | `--token` | `AGENTEYE_CLI_TOKEN` | desde `~/.agenteye/cli.json` | +| Salida JSON | `--json` | `AGENTEYE_CLI_JSON` | desactivado | +| Omitir verificación TLS | `--insecure` / `--secure` | `AGENTEYE_INSECURE` | desactivado (guardado al iniciar sesión) | +| Tiempo de espera de solicitud (segundos) | `--timeout` | — | 30 | +| Desactivar telemetría de uso | _(ninguno)_ | `AGENTEYE_ANALYTICS_DISABLED` (o `DO_NOT_TRACK`) | desactivado (telemetría activa) | + +El orden de resolución es **flag → variable de entorno → archivo de configuración**. No hay valor predeterminado; debes apuntar el CLI a tu dashboard, ya sea por comando (`--base-url https://agenteye.ejemplo.com`) o una vez mediante la variable de entorno (también se guarda tras tu primer `login`): + +```bash +export AGENTEYE_DASHBOARD_URL=https://agenteye.ejemplo.com +``` + +El directorio de configuración respeta `AGENTEYE_HOME` (la misma convención usada por el SDK y el collector); si está definido, `cli.json` vive en `$AGENTEYE_HOME/cli.json`. + +### TLS autofirmado o interno + +Si tu dashboard se sirve sobre HTTPS con un certificado autofirmado o interno (por ejemplo, el hostname directo de un balanceador de carga), la verificación TLS lo rechazará con un error `CERTIFICATE_VERIFY_FAILED`. Usa `--insecure` para omitir la verificación de certificado: + +```bash +agenteye --base-url https://agenteye.internal --insecure login +``` + +`--insecure` se **guarda en `cli.json` al iniciar sesión**, por lo que los comandos posteriores omiten la verificación automáticamente; no necesitas repetir el flag. Usa `--secure` para una llamada verificada puntual, o para volver a activar la verificación en tu próximo inicio de sesión. El CLI muestra una advertencia en stderr antes de cualquier comando que contacte al dashboard con la verificación desactivada. Omitir la verificación elimina la protección contra ataques de intermediario; asegúrate de confiar en la ruta de red a tu dashboard (VPN, subred privada, etc.) antes de depender de esto. + +--- + +## Telemetría y privacidad + +El CLI envía **análisis de uso anónimos** al servicio de análisis de Exosphere (PostHog): qué comandos se ejecutan (p. ej., `sessions`, `keys create`), si tuvieron éxito y cuánto tiempo tomaron. Esta señal de uso informa qué funcionalidades se priorizan. + +- **Ningún dato de agentes, sesiones o eventos sale de tu infraestructura.** Solo se reporta el uso del CLI: el nombre del comando y subcomando (p. ej., `keys create`), los **nombres** de los flags que usaste (nunca sus valores), el estado de éxito/salida y la duración — más un evento por acción para mutaciones (p. ej., `api_key_created`, `query_run`) que solo incluye nombres/enumeraciones estáticas y conteos aproximados. Tu URL del dashboard, token de sesión, correo, slug de organización, IDs de recursos, SQL, secretos de claves y filtros de consulta **nunca** se envían. Los operadores se identifican solo por un ID interno opaco, nunca por correo. +- La telemetría está **activada de forma predeterminada**. Para desactivarla, define `AGENTEYE_ANALYTICS_DISABLED=1` en el entorno del CLI (el CLI también respeta la convención `DO_NOT_TRACK=1`). +- El CLI envía directamente a PostHog (`https://us.i.posthog.com`). La **máquina que ejecuta el CLI** necesita acceso saliente a ese host; si está bloqueado, la telemetría no hace nada en silencio (el envío tiene límite de tiempo, por lo que nunca retrasa ni interrumpe un comando) y el CLI no se ve afectado. + +--- + +## Opciones globales y convenciones + +Lee esto una vez; aplica a todos los comandos. + +- **Las opciones globales van ANTES del comando.** `agenteye --json sessions` es correcto; `agenteye sessions --json` es un error de uso. Las opciones globales son `--json`, `--base-url`, `--org`, `--token`, `--insecure`/`--secure`, `--timeout`, `--quiet` y `--no-color`. +- **`--json` imprime JSON puro en stdout, y nada más.** Las líneas de estado para humanos, advertencias y errores van a **stderr**, de modo que una captura de stdout con `--json` permanece limpia para pasar a `jq` incluso cuando se muestra una línea de estado. Sin `--json` obtienes una vista con recuadros y colores para ojos humanos. +- **Descubre con `--help`.** Cada comando y subcomando tiene `--help` (y el alias `-h`): `agenteye -h`, `agenteye sessions -h`, `agenteye keys create -h`. La ayuda de nivel superior también lista los códigos de salida y las opciones globales. No hay un volcado global de superficie legible por máquina; usa `--help` por comando, más los registros específicos de dominio `agenteye query schema` y `agenteye settings schema` para esos dos registros. +- **Las confirmaciones se omiten automáticamente para scripts y agentes.** Los comandos de crear/actualizar/eliminar preguntan "¿estás seguro?" en una terminal interactiva, pero **omiten automáticamente ese prompt con `--json` o cuando stdin no es una TTY** — de modo que los scripts y agentes nunca se bloquean. Usa `--yes`/`-y` para omitirla explícitamente. Como el prompt no se activará para un agente, este debe confirmar las acciones destructivas con el humano primero. +- **Paginación:** los resultados son los más recientes primero y están paginados por cursor. `--limit N` (alias `-n`) limita las filas y **tiene un valor predeterminado de 50**; `--all` pagina automáticamente (en bloques de 200 filas) **hasta `--limit`** — de modo que un `--all` sin más sigue deteniéndose en 50. Para un recorrido completo, pasa un límite alto explícito: `--all --limit 1000`. `--page-size N` controla el bloque por solicitud (máx. 200); `--cursor ` retoma desde el `next_cursor` de una página anterior. +- **Filtros de tiempo:** `--since` acepta una ventana relativa — `15m`, `1h`, `6h`, `24h`, `7d`, `30d` o `all` (los ajustes predefinidos del dashboard). `--from`/`--to` aceptan marcas de tiempo UTC explícitas en ISO-8601 **con `T` y zona horaria** (p. ej., `2026-06-01T00:00:00Z`) para un rango personalizado y anulan `--since`; un valor separado por espacios o sin zona horaria es un error de uso. +- **`--fields a,b,c`** (en `events`, `sessions`, `evals`, `errors`) restringe la salida a esas claves, tanto en la tabla como en `--json`. Los nombres desconocidos se rechazan con la lista válida — una forma sencilla de descubrir nombres de campos. +- **`--file payload.json`** (o `--file -` para leer stdin) proporciona un cuerpo de solicitud JSON completo cuando un recurso tiene una forma compleja — en `alerts create/update`, `settings set` y `users create/update`. El SQL de consultas guardadas usa `--sql @archivo.sql` en su lugar. +- **Los filtros con múltiples valores** están separados por comas → coinciden como un conjunto (unión dentro de un filtro, AND entre filtros): `--event-type tool_use,tool_result`. Las opciones de Click no son variádicas, por lo que `--add a b` falla — usa `--add a,b`, repite el flag (`--add a --add b`) o usa comillas (`--add "a b"`). + +--- + +## Referencia de comandos + +El CLI tiene **18 comandos de nivel superior**. Todos los comandos de lectura aceptan `--json` y las opciones globales anteriores; ejecuta `agenteye -h` (o ` -h`) para la lista exhaustiva de flags y la forma JSON de cualquiera de ellos. + +### Identidad — `login` · `logout` · `whoami` · `orgs` · `version` · `help` + +```bash +agenteye login --email tu@ejemplo.com [--org acme] # código de un uso por correo; guarda la sesión +agenteye logout # borra la sesión guardada en esta máquina +agenteye whoami # usuario actual, organización activa, permisos +agenteye version # imprime la versión del CLI (igual que --version) +agenteye help # ayuda de nivel superior (igual que --help) +``` + +`orgs` inspecciona y cambia el tenant activo: + +```bash +agenteye orgs list # tus organizaciones + tu rol en cada una (la activa está marcada) +agenteye orgs switch acme # cambiar la organización activa guardada (omite el slug para elegir de una lista en una TTY) +agenteye orgs current # tarjeta de identidad de la organización activa +agenteye orgs perms # tus permisos en la organización activa, agrupados por recurso +``` + +### Observar (solo lectura) — `events` · `sessions` · `evals` · `errors` · `list` + +Ninguno de estos requiere confirmación. Filtros compartidos: `--session-id`, `--agent-id`, `--env` (**no** `--environment`) y el rango de tiempo (`--since` / `--from` / `--to`). + +```bash +# events (alias: el rastro sin procesar por paso) — más recientes primero +agenteye --json events --session-id run-001 --event-type tool_use,tool_result --all --limit 1000 +agenteye --json events --since 1h --search timeout --all | jq '.events[].payload' + +# sessions — una fila por ejecución de agente (tiempo/entorno/agente/sesión/estado; sin filtrado por puntuación) +agenteye --json sessions --since 24h --status error +agenteye --json sessions --agent-id checkout-bot --env prod --all --limit 1000 + +# evals — resultados de evaluación + puntuaciones; --score filtra por métrica, --aggregate agrega +agenteye --json evals --score helpfulness:0.5..0.8 --score tool_efficiency:..0.3 +agenteye --json evals --aggregate --since 7d --env prod # mezcla de estados + estadísticas de puntuación por clave + +# errors — eventos con error; --aggregate para conteos/sesiones/agentes/última vez visto +agenteye --json errors --since 24h --aggregate +agenteye --json errors --since 24h --error-type timeout --all --limit 1000 + +# list — descubre valores de filtro válidos antes de filtrar +agenteye list envs # también: agents event_types score_filters models hooks triggers tools error_types +``` + +`--score CLAVE:MIN..MAX` (en **`evals`**, no en `sessions`) es repetible y se combina con AND; cualquiera de los límites es opcional (`..0.5` significa ≤ 0.5, `0.9..` significa ≥ 0.9). Hasta 20 filtros de puntuación por solicitud. `evals --scores-full` devuelve el objeto de puntuación completo en lugar del resumen. Para leer **una sesión de principio a fin**, combina el rastro de eventos con su evaluación: + +```bash +agenteye --json events --session-id run-001 --all --limit 1000 | jq '.events[] | {ts, event_type}' +agenteye --json evals --session-id run-001 # sus puntuaciones + estado +``` + +### Gestionar (con control de permisos) — `keys` · `users` · `settings` · `alerts` · `incidents` + +**`keys`** — claves API. El secreto se genera localmente, se envía al servidor (que almacena solo un hash) y se **muestra una vez** al crear/regenerar — captúralo en ese momento. Con `--json` aparece solo en el campo `key`. Se referencian por **nombre**. + +```bash +agenteye keys list # claves activas primero, luego revocadas +agenteye keys show ci-bot +agenteye keys create ci-bot --add events:read.add # limita al scope que necesitas; imprime el secreto UNA VEZ +agenteye keys create ops --permission-set standard --remove queries:run # empieza con un preset y luego recorta +agenteye keys update ci-bot --add evaluations:read --yes +agenteye keys regenerate ci-bot --yes # rota el secreto (el anterior deja de funcionar) +agenteye keys disable ci-bot --yes # revocar +``` + +Los permisos funcionan como `(permission-set ∪ --add) − --remove`. Los tokens son `slug:acción` (p. ej., `events:read`) o `slug:acción.acción` para expandir varias en un mismo recurso (`events:read.add` → `events:read`, `events:add`). Presets: `read-only`, `standard`, `admin`. Los permisos solo para humanos (`keys:update`) no se pueden otorgar a una clave. + +**`users`** — miembros de la organización, referenciados por **correo electrónico** (también se acepta un id UUID). + +```bash +agenteye users list [--active-only] +agenteye users show dev@empresa.com +agenteye users create dev@empresa.com --permission-set standard +agenteye users update dev@empresa.com --add alerts:write --remove queries:delete # predice + confirma +agenteye users disable dev@empresa.com --yes # tiene guardas de protección/auto-protección +agenteye users enable dev@empresa.com +``` + +**`settings`** — un registro fijo (lees y cambias claves existentes; no puedes crear nuevas). + +```bash +agenteye settings list # clave · valor · tipo · actualizado (secretos enmascarados) +agenteye settings schema # qué acepta cada clave (tipo · rango · descripción) +agenteye settings set session_ttl_secs --value 86400 --yes +``` + +**`alerts`** — definiciones de alertas, referenciadas por **nombre**. `create` toma un NOMBRE posicional más flags o un cuerpo JSON completo mediante `--file`. + +```bash +agenteye alerts list +agenteye alerts show high-errors +agenteye alerts create high-errors --file alert.json # NAME es requerido (posicional) +agenteye alerts update high-errors --severity critical --yes +agenteye alerts test high-errors --yes # lanza una notificación de prueba +agenteye alerts delete high-errors --yes +``` + +**`incidents`** — incidentes de alertas, referenciados por id (se aceptan ids cortos). `show` imprime el registro de actividad completo — léelo antes de actuar. + +```bash +agenteye incidents list --state firing # también: acknowledged, resolved +agenteye incidents count +agenteye incidents show +agenteye incidents ack +agenteye incidents assign tu@empresa.com # el asignado debe ser un operador +agenteye incidents resolve --yes +agenteye incidents open --alert-id --severity critical # abre uno manualmente contra una alerta +agenteye incidents comment-add "causa raíz: 5xx en upstream" +agenteye incidents comment-list ; agenteye incidents comment-delete +agenteye incidents subscribe ; agenteye incidents unsubscribe ; agenteye incidents subscribers +``` + +### Analítica y asistente — `query` · `agent` + +**`query`** — SQL de ClickHouse guardado más un ejecutor ad-hoc. Las consultas guardadas se referencian por **nombre**; el SQL se valida en el servidor (solo SELECT/WITH, tiempo de espera de sentencia, límite de filas). + +```bash +agenteye query schema [TABLA] # diseño de columnas de las vistas de analítica +agenteye query run --sql "select count(*) from analytics.events" +agenteye query run errs --arg prod --limit 100 # ejecuta una consulta guardada + un $1 posicional +agenteye query list ; agenteye query show errs +agenteye query create errs --sql @errs.sql --description "eventos con error (24h)" +agenteye query update errs --sql @errs.sql --yes ; agenteye query delete errs --yes +``` + +**`agent`** — el asistente integrado del dashboard (el mismo analista de solo lectura con el que puedes chatear en el dashboard). Los chats se referencian por un chat-id corto (se resuelve por prefijo). + +```bash +agenteye agent health # si el asistente está configurado/accesible +agenteye agent models # modelos que puedes pasar a --model (el predeterminado marcado) +agenteye agent ask "¿qué agentes tuvieron más errores el último día?" # inicia un chat; imprime su id corto +agenteye agent ask --chat "¿y qué herramientas llamaron?" # continúa ese chat +agenteye agent chats ; agenteye agent show +agenteye agent rename --title "análisis de errores" ; agenteye agent delete +``` + +--- + +## Códigos de salida + +| Código | Significado | +|---|---| +| 0 | Éxito | +| 1 | Error inesperado (p. ej., el dashboard devolvió un 5xx) | +| 2 | Error de uso (argumentos inválidos, comando/flag desconocido, colisión de nombres) | +| 3 | No se puede alcanzar el dashboard | +| 4 | No has iniciado sesión o la sesión ha expirado; ejecuta `agenteye login` | +| 5 | Autenticado, pero tu cuenta carece del permiso requerido (el mensaje lo indica) | +| 6 | El recurso solicitado no fue encontrado (p. ej., sesión o id de incidente desconocido) | + +Esto hace que el CLI sea seguro para usar en scripts: un agente de codificación puede ramificar en un `4` para pedirte que te vuelvas a autenticar, o en un `5` para mostrar el permiso faltante. Consulta [Recetas de CLI para agentes](/es/agenteye/cli-recipes) para patrones de manejo de códigos de salida y formas de salida JSON. + +--- + +## Ver también + +- **[Recetas de CLI para agentes](/es/agenteye/cli-recipes)** — patrones de consulta para copiar y pegar, one-liners de `jq`, proyecciones con `--fields`, manejo de códigos de salida y formas de salida JSON, escritos para agentes de codificación que manejan el CLI. +- **[Skill del CLI de AgentEye](/es/agenteye/cli-skill)** — empaqueta este CLI como un *skill* instalable de Claude Code / Codex para que un agente de codificación maneje AgentEye desde solicitudes en lenguaje natural. +- **[Claves API](/es/agenteye/api-keys)** — el modelo de permisos detrás de `keys create --add …`. +- **[Asistente de IA](/es/agenteye/assistant)** — habilitación del asistente con el que habla `agent ask`. \ No newline at end of file diff --git a/docs/es/agenteye/collector-installation.mdx b/docs/es/agenteye/collector-installation.mdx new file mode 100644 index 00000000..731b42fb --- /dev/null +++ b/docs/es/agenteye/collector-installation.mdx @@ -0,0 +1,401 @@ +--- +title: "Instalación del Collector" +description: "Documentación de instalación del AgentEye Collector." +--- + + +El daemon `agenteye-collector` garantiza que la telemetría de tus agentes llegue a AgentEye sin bloquear nunca tu aplicación. Tu código escribe eventos en un directorio local y continúa su ejecución; el collector toma el control desde ese momento, subiendo cada archivo en milisegundos y sobreviviendo reinicios, interrupciones de red y errores transitorios del servidor. Las subidas fallidas se reintentan con retroceso exponencial, y un barrido periódico de recuperación vuelve a encolar cualquier archivo que haya quedado pendiente tras un fallo o despliegue. El resultado es una entrega durable y de tipo "lanzar y olvidar": tus agentes siguen funcionando a plena velocidad mientras el collector garantiza que ningún evento se pierda en tránsito. + +Mecánicamente, el collector es un daemon ligero que monitorea `$AGENTEYE_HOME/events/` (por defecto: `~/.agenteye/events/`) en busca de archivos `.jsonl` escritos por el SDK de Python y los sube al servidor de AgentEye. + +> **Cambio de nombre:** el comando del collector ahora es **`agenteye-collector`** (antes era `agenteye`). El nombre abreviado `agenteye` ahora pertenece al CLI de AgentEye. Si estás actualizando una instalación existente, consulta [enterprise-docs/collector-migration.md](/es/agenteye/collector-migration). + +--- + +## Requisitos previos + +- Tu `AGENTEYE_TOKEN`: un PAT de GitHub que tú mismo generas (consulta [enterprise-docs/github-token.md](/es/agenteye/github-token)) +- La URL del servidor y una clave de API del collector (consulta [enterprise-docs/api-keys.md](/es/agenteye/api-keys)) + +--- + +## Opción A: Binario (recomendado) + +Hay binarios estáticos precompilados disponibles para Linux, macOS y Windows (x86_64 y arm64). Descarga el binario para tu plataforma directamente desde el repositorio `agenteye-enterprise/releases`, bajo la etiqueta de lanzamiento más reciente `collector/v`. + +Nombres de artefactos disponibles: + +| Plataforma | Artefacto | +|---|---| +| Linux x86_64 | `agenteye-collector-linux-x86_64` | +| Linux arm64 | `agenteye-collector-linux-arm64` | +| macOS x86_64 | `agenteye-collector-darwin-x86_64` | +| macOS arm64 | `agenteye-collector-darwin-arm64` | +| Windows x86_64 | `agenteye-collector-windows-x86_64.exe` | +| Windows arm64 | `agenteye-collector-windows-arm64.exe` | + +**Descargar con el CLI `gh`** (reemplaza la versión y elige el artefacto de tu plataforma): + +```bash +VERSION=0.0.1-beta.13 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "collector/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-collector-linux-x86_64' + +chmod +x agenteye-collector-linux-x86_64 +sudo mv agenteye-collector-linux-x86_64 /usr/local/bin/agenteye-collector +``` + +**O con `curl`:** + +```bash +VERSION=0.0.1-beta.13 +ARTIFACT=agenteye-collector-linux-x86_64 +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + -L "https://github.com/agenteye-enterprise/releases/releases/download/collector%2Fv${VERSION}/${ARTIFACT}" \ + -o agenteye-collector +chmod +x agenteye-collector +sudo mv agenteye-collector /usr/local/bin/agenteye-collector +``` + +--- + +## Opción B: Docker + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +docker pull ghcr.io/agenteye-enterprise/collector:beta-latest +``` + +> Las compilaciones beta actuales publican la etiqueta flotante `:beta-latest`; la etiqueta `:latest` solo se asigna a versiones estables. Para despliegues reproducibles, se recomienda usar una etiqueta de versión fija como `:v0.0.1-beta.13`. + +**Ejecutar:** + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-collector \ + -e AGENTEYE_URL=https://ingest.example.com/events \ + -e AGENTEYE_KEY="$AGENTEYE_KEY" \ + -e AGENTEYE_HOME=/data \ + -v "$HOME/.agenteye:/data" \ + ghcr.io/agenteye-enterprise/collector:beta-latest \ + start +``` + +La imagen oficial se ejecuta como usuario no-root, por lo que debes definir `AGENTEYE_HOME` explícitamente y montar el directorio de cola del host en él. El montaje de volumen comparte el mismo directorio `~/.agenteye/` en el que el SDK de Python escribe en el host. Si ya tienes `AGENTEYE_HOME` configurado en otra ubicación del host, monta ese directorio en lugar de `$HOME/.agenteye`. + +--- + +## Configuración + +Todas las opciones pueden establecerse de tres formas (de mayor a menor prioridad): + +1. Bandera de CLI: `agenteye-collector start --url https://...` +2. Variable de entorno: `AGENTEYE_URL=https://...` +3. Archivo de configuración: `~/.agenteye/config.json` + +### Opciones obligatorias + +| Opción | Bandera CLI | Variable de entorno | Clave en config.json | +|---|---|---|---| +| URL del backend | `--url ` | `AGENTEYE_URL` | `"url"` | +| Clave de API | `--key ` | `AGENTEYE_KEY` | `"key"` | + +### Opciones opcionales (con valores por defecto) + +| Opción | Bandera CLI | Variable de entorno | Clave en config.json | Por defecto | +|---|---|---|---|---| +| Máx. subidas simultáneas | `--max-concurrent-uploads ` | `AGENTEYE_MAX_CONCURRENT_UPLOADS` | `"max_concurrent_uploads"` | `64` | +| Intervalo del barrido (s) | `--sweep-interval ` | `AGENTEYE_SWEEP_INTERVAL` | `"sweep_interval_secs"` | `60` | +| Edad mínima de archivo para barrido (s) | `--sweep-min-age ` | `AGENTEYE_SWEEP_MIN_AGE` | `"sweep_min_age_secs"` | `120` | +| Máx. archivos por barrido | `--sweep-max-files ` | `AGENTEYE_SWEEP_MAX_FILES` | `"sweep_max_files"` | `64` | +| Máx. intentos de subida | `--max-retries ` | `AGENTEYE_MAX_RETRIES` | `"max_retries"` | `5` | +| Retardo base de reintento (ms) | `--retry-base-delay ` | `AGENTEYE_RETRY_BASE_DELAY` | `"retry_base_delay_ms"` | `1000` | + +### Opciones mTLS (opcionales) + +Para despliegues que requieren TLS mutuo (mTLS), el collector puede presentar un certificado de cliente durante el protocolo de enlace TLS. Si no se configuran estas opciones, el collector utiliza HTTPS estándar. + +| Opción | Bandera CLI | Variable de entorno | Clave en config.json | +|---|---|---|---| +| Certificado de cliente (PEM) | `--tls-cert ` | `AGENTEYE_TLS_CERT` | `"tls_cert"` | +| Clave privada del cliente (PEM) | `--tls-key ` | `AGENTEYE_TLS_KEY` | `"tls_key"` | +| Certificado CA personalizado (PEM) | `--tls-ca ` | `AGENTEYE_TLS_CA` | `"tls_ca"` | + +`--tls-cert` y `--tls-key` deben configurarse juntos. Los archivos deben estar codificados en PEM. + +`--tls-ca` es independiente y solo es necesario cuando el servidor de AgentEye presenta un certificado TLS que no ha sido emitido por una CA de confianza pública (por ejemplo, autofirmado por un emisor `cert-manager` dentro del clúster cuando no tienes un dominio DNS real). El collector añade la CA proporcionada como ancla de confianza adicional; las raíces públicas estándar siguen siendo de confianza, por lo que los despliegues existentes no se ven afectados. El archivo puede contener un único certificado PEM o una cadena completa (múltiples bloques PEM concatenados). + +**¿Ejecutas el collector como sidecar en tu pod de aplicación?** Consulta [enterprise-docs/single-pod-deployment.md](/es/agenteye/single-pod-deployment) para ver el patrón completo en EKS: paquete mTLS entregado mediante AWS Secrets Manager + Secrets Store CSI Driver + IRSA, con rotación automática. + +Cuando se ejecuta en Kubernetes con el patrón de transferencia de Secrets, monta el Secret del certificado como un volumen y apunta estas rutas a los archivos montados: + +```yaml +# Ejemplo: fragmento de Deployment del collector +volumes: + - name: mtls-certs + secret: + secretName: agenteye-collector-mtls +containers: + - name: collector + env: + - name: AGENTEYE_TLS_CERT + value: /etc/agenteye/tls/tls.crt + - name: AGENTEYE_TLS_KEY + value: /etc/agenteye/tls/tls.key + # Solo cuando el certificado del servidor no es de confianza pública (por ejemplo, CA + # autofirmada dentro del clúster). El mismo Secret normalmente incluye ca.crt junto + # a tls.crt/tls.key. + - name: AGENTEYE_TLS_CA + value: /etc/agenteye/tls/ca.crt + volumeMounts: + - name: mtls-certs + mountPath: /etc/agenteye/tls + readOnly: true +``` + +### Ejemplo de `~/.agenteye/config.json` + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "max_concurrent_uploads": 16, + "sweep_interval_secs": 30 +} +``` + +Con mTLS: + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "tls_cert": "/etc/agenteye/tls/tls.crt", + "tls_key": "/etc/agenteye/tls/tls.key" +} +``` + +Con mTLS más una CA personalizada (servidor AgentEye autofirmado): + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "tls_cert": "/etc/agenteye/tls/tls.crt", + "tls_key": "/etc/agenteye/tls/tls.key", + "tls_ca": "/etc/agenteye/tls/ca.crt" +} +``` + +Si `AGENTEYE_HOME` está definido, se usará ese directorio en lugar de `~/.agenteye`. + +--- + +## Configuración inicial + +Tras la instalación, configura el collector con la URL de tu servidor y la clave de API: + +```bash +mkdir -p ~/.agenteye +cat > ~/.agenteye/config.json <<'EOF' +{ + "url": "https://ingest.example.com/events", + "key": "YOUR_COLLECTOR_KEY" +} +EOF +``` + +> Usa `https` para cualquier despliegue que atraviese una red no confiable, de modo que los eventos no se envíen en texto plano. El formato en texto plano `http://your-server-host:8080/events` solo es apropiado para pruebas puramente locales contra un servidor en el mismo host. + +**Probar la conexión** (vaciado puntual, finaliza tras drenar los eventos pendientes): + +```bash +agenteye-collector flush +``` + +`flush` reporta su progreso por stdout. Cuando la cola está vacía, imprime `No pending files.` y termina con código `0`. En caso contrario, imprime una línea por archivo (`[UPLOADED] ` o `[FAILED] ()`), seguida de un resumen `Done: / uploaded, failed.`. Esto convierte a `flush` en una verificación puntual muy práctica para comprobar que tu URL, clave y configuración TLS son correctos antes de iniciar el daemon. + +--- + +## Ejecución como daemon + +### Directamente + +```bash +agenteye-collector start +``` + +### Contenedor / Docker + +Cuando el collector y tu aplicación comparten un contenedor, ejecútalos bajo un supervisor de procesos. La opción más sencilla es `supervisord`; está disponible en todas las distribuciones principales, reinicia los procesos que fallen, reenvía señales y espera a un apagado controlado. + +**`Dockerfile`:** + +```Dockerfile +FROM python:3.11-slim + +RUN apt-get update && apt-get install -y --no-install-recommends supervisor \ + && rm -rf /var/lib/apt/lists/* + +# Obtener el binario agenteye-collector desde la imagen oficial. +# Fija una etiqueta específica (:beta-latest para betas actuales, o :v); +# :latest solo se publica para versiones estables. +COPY --from=ghcr.io/agenteye-enterprise/collector:beta-latest \ + /usr/local/bin/agenteye-collector /usr/local/bin/agenteye-collector + +COPY supervisord.conf /etc/supervisor/conf.d/agenteye.conf +COPY my_agent.py /app/my_agent.py + +CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"] +``` + +**`supervisord.conf`:** + +```ini +[supervisord] +nodaemon=true +user=root + +[program:agenteye-collector] +command=/usr/local/bin/agenteye-collector start +autorestart=true +stopwaitsecs=30 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:app] +command=python /app/my_agent.py +autorestart=unexpected +stopwaitsecs=30 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +``` + +Por qué estas configuraciones: + +- `autorestart=true` en agenteye-collector: reinicia ante cualquier salida (fallo, pánico, OOM). +- `autorestart=unexpected` en la aplicación: solo reinicia en caso de salida con código distinto de cero, de modo que un agente puntual que termine con código 0 no entre en bucle. +- `stopwaitsecs=30`: da al collector margen para drenar las subidas pendientes al recibir SIGTERM antes de que supervisord escale a SIGKILL. +- `stdout_logfile=/dev/stdout`, `*_maxbytes=0`: redirige la salida de ambos programas al stdout del contenedor; sin archivos de log dentro del contenedor. + +Pasa `AGENTEYE_URL` / `AGENTEYE_KEY` (y cualquier variable de entorno TLS) con `docker run -e` como de costumbre; supervisord hereda el entorno. + +> **¿Contenedores separados?** Si ejecutas el collector en su propio contenedor (servicio de Docker Compose, sidecar de Kubernetes, etc.), no uses supervisord; la política de reinicio del runtime de contenedores ya se encarga de eso. Consulta [enterprise-docs/single-pod-deployment.md](/es/agenteye/single-pod-deployment) para ver el patrón de sidecar en EKS. + +**Sonda de liveness de Kubernetes** (aplica tanto si el collector se ejecuta solo como bajo supervisord): + +```yaml +livenessProbe: + exec: + command: ["agenteye-collector", "health"] + initialDelaySeconds: 10 + periodSeconds: 30 +``` + +El daemon en ejecución escribe un latido en `$AGENTEYE_HOME/health.json` cada 30 segundos. `agenteye-collector health` lee ese archivo y termina con código `0` (saludable) solo cuando el latido es reciente y las tareas de subida se están ejecutando con normalidad; termina con código `1` (no saludable) cuando el latido tiene más de 90 segundos de antigüedad (por ejemplo, el daemon se ha detenido) o mientras el observador y el barredor se están reiniciando tras una salida inesperada. El latido solo es escrito por `start`, así que ejecuta la sonda contra el daemon de larga duración y no contra el comando puntual `flush`. + +### systemd (Linux, recomendado para producción) + +```ini +# /etc/systemd/system/agenteye-collector.service +[Unit] +Description=AgentEye Collector +After=network.target + +[Service] +ExecStart=/usr/local/bin/agenteye-collector start +Restart=on-failure +RestartSec=5 +EnvironmentFile=/etc/agenteye/env + +[Install] +WantedBy=multi-user.target +``` + +Crea `/etc/agenteye/env`: + +``` +AGENTEYE_URL=https://ingest.example.com/events +AGENTEYE_KEY=YOUR_COLLECTOR_KEY +``` + +```bash +sudo systemctl daemon-reload +sudo systemctl enable --now agenteye-collector +sudo systemctl status agenteye-collector +``` + +### launchd (macOS) + +```xml + + + + + + Label + ai.befailproof.agenteye-collector + ProgramArguments + + /usr/local/bin/agenteye-collector + start + + EnvironmentVariables + + AGENTEYE_URL + https://ingest.example.com/events + AGENTEYE_KEY + YOUR_COLLECTOR_KEY + + RunAtLoad + + KeepAlive + + + +``` + +```bash +launchctl load ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +``` + +--- + +## Actualización del Collector + +El collector no se actualiza a sí mismo. Para actualizarlo: + +- **Binario:** descarga el nuevo artefacto `agenteye-collector--` desde la última versión `collector/v` (consulta [Opción A](#option-a-binary-recommended)), reemplaza `/usr/local/bin/agenteye-collector` y reinicia el servicio (`sudo systemctl restart agenteye-collector`, vuelve a ejecutar `launchctl load`, o reinicia tu supervisor). +- **Docker:** ejecuta `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (o una etiqueta fija `:v`; `:latest` solo existe para versiones estables) y recrea el contenedor. + +`AGENTEYE_TOKEN` es necesario para descargar nuevos binarios/imágenes del repositorio de versiones privado, pero **no** es necesario para el daemon en ejecución. + +--- + +## Subcomandos + +| Comando | Descripción | +|---|---| +| `agenteye-collector start` | Inicia el daemon de larga duración. Al arrancar, vacía cualquier evento que haya quedado de una ejecución anterior, luego monitorea nuevos archivos y los sube. El observador y el barredor se reinician automáticamente ante salidas inesperadas, y se escribe un latido en `health.json` cada 30 segundos. | +| `agenteye-collector flush` | Puntual: sube todos los archivos pendientes y termina. Imprime `No pending files.` cuando la cola está vacía; en caso contrario, un registro `[UPLOADED]`/`[FAILED]` por archivo y un resumen `Done: / uploaded, failed.`. | +| `agenteye-collector health` | Lee el latido `health.json` del daemon. Termina con código `0` cuando está reciente y saludable; termina con código `1` cuando el latido está desactualizado (más de 90s) o las tareas se están reiniciando. | + +--- + +## Estructura de directorios + +``` +~/.agenteye/ +├── config.json <- archivo de configuración opcional +├── events/ <- archivos .jsonl escritos por el SDK, recogidos por el collector +└── failed/ <- archivos que fallaron todos los intentos de subida +``` + +Los archivos en `failed/` no se reintentan automáticamente. Para volver a ponerlos en cola manualmente, muévelos de nuevo a `events/` y ejecuta `agenteye-collector flush`. \ No newline at end of file diff --git a/docs/es/agenteye/collector-migration.mdx b/docs/es/agenteye/collector-migration.mdx new file mode 100644 index 00000000..05769f3e --- /dev/null +++ b/docs/es/agenteye/collector-migration.mdx @@ -0,0 +1,168 @@ +--- +title: "Migración a `agenteye-collector`" +description: "Documentación de AgentEye para migrar a `agenteye-collector`." +--- + +La migración no es destructiva: no genera tiempo de inactividad ni pérdida de datos, y libera el nombre corto `agenteye` para la [CLI de AgentEye](/es/agenteye/cli), de modo que el demonio collector y la CLI puedan coexistir en el mismo equipo. + +El binario del collector ha sido **renombrado de `agenteye` a `agenteye-collector`**. El nombre corto `agenteye` ahora pertenece a la CLI de AgentEye, una herramienta independiente para consultar sesiones, eventos y evaluaciones desde tu terminal. + +Esta guía te orienta en el proceso de migración de una instalación existente del collector. + +--- + +## Qué cambió + +| | Antes | Después | +|---|---|---| +| Comando / binario | `agenteye` | `agenteye-collector` | +| Ruta de instalación predeterminada | `/usr/local/bin/agenteye` | `/usr/local/bin/agenteye-collector` | +| Subcomandos | `start`, `flush`, `health`, `update` | `start`, `flush`, `health` | +| Auto-actualización (`agenteye update`) | integrada | **eliminada**: descarga el nuevo binario o extrae la nueva imagen | +| Script de instalación (`install.sh`) | incluido | **eliminado**: descarga el binario directamente (consulta [Instalación del Collector](/es/agenteye/collector-installation)) | +| `AGENTEYE_TOKEN` | necesario para descargar **y** para comprobaciones de actualización en segundo plano | necesario solo para **descargar** binarios/imágenes | + +La configuración no cambia: el mismo `~/.agenteye/config.json`, las mismas variables de entorno `AGENTEYE_URL` / `AGENTEYE_KEY` / `AGENTEYE_HOME` / TLS, y el mismo spool `~/.agenteye/events/`. **No se requieren cambios en la configuración.** + +> Si ejecutas el binario renombrado con el nombre antiguo `agenteye`, seguirá funcionando, pero imprimirá una advertencia de deprecación de una línea en stderr recordándote que debes cambiar a `agenteye-collector`. + +--- + +## Antes de comenzar + +- Tu **instalación existente de `agenteye` seguirá funcionando**; nada se rompe en el momento en que actualices. Migra de forma deliberada y elimina el binario antiguo al final. +- Sigue este orden para evitar tiempos de inactividad: + 1. Instala el nuevo binario `agenteye-collector` (o extrae la nueva imagen). + 2. Actualiza tu definición de servicio, sondas de salud y scripts para que llamen a `agenteye-collector`. + 3. Recarga y reinicia el servicio; confirma que está en buen estado. + 4. **Solo entonces** elimina el binario antiguo `/usr/local/bin/agenteye`. + +--- + +## 1. Instala el nuevo binario + +Descarga el artefacto para tu plataforma (`agenteye-collector-linux-x86_64`, `agenteye-collector-darwin-arm64`, etc.; consulta [Instalación del Collector → Opción A](/es/agenteye/collector-installation#option-a-binary-recommended) para la lista completa) desde la última versión `collector/v` y colócalo en `/usr/local/bin/agenteye-collector`. Usuarios de Docker: `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (o una etiqueta fija `:v`, que es preferible; `:latest` solo existe para versiones estables). + +Verifica: + +```bash +agenteye-collector --version +``` + +--- + +## 2. Actualiza tu despliegue + +### systemd (Linux) + +Edita `/etc/systemd/system/agenteye-collector.service` para que `ExecStart` apunte al nuevo binario: + +```ini +[Service] +ExecStart=/usr/local/bin/agenteye-collector start +``` + +Luego recarga y reinicia: + +```bash +sudo systemctl daemon-reload +sudo systemctl restart agenteye-collector +sudo systemctl status agenteye-collector +``` + +### launchd (macOS) + +> **Cambio de nombre:** Si tu plist existente se encuentra en la ruta anterior +> `~/Library/LaunchAgents/host.exosphere.agenteye-collector.plist`, renombra +> el archivo a `ai.befailproof.agenteye-collector.plist` y cambia también el +> valor de `Label` dentro del archivo al nuevo identificador antes +> de recargarlo. + +En `~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist`, cambia la primera entrada de `ProgramArguments` de `/usr/local/bin/agenteye` a `/usr/local/bin/agenteye-collector` y luego recarga: + +```bash +launchctl unload ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +launchctl load ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +``` + +### supervisord + +En tu bloque de programa `supervisord`, establece `command` con el nuevo binario: + +```ini +[program:agenteye-collector] +command=/usr/local/bin/agenteye-collector start +``` + +Luego ejecuta `supervisorctl reread && supervisorctl update`. + +### Docker / Kubernetes + +Extrae la nueva imagen (`ghcr.io/agenteye-enterprise/collector:beta-latest` o una etiqueta fija `:v`, que es preferible; `:latest` solo existe para versiones estables). El punto de entrada de la imagen ya es `agenteye-collector`, por lo que el mismo comando `docker run` con el subcomando `start` seguirá funcionando sin ningún cambio. + +**Importante: actualiza las sondas de salud.** Si usas una sonda de liveness/readiness de Kubernetes (o cualquier `docker exec`) que ejecuta el binario por nombre, cambia el comando a `agenteye-collector`: + +```yaml +livenessProbe: + exec: + command: ["agenteye-collector", "health"] +``` + +La nueva imagen **no** incluye un alias `agenteye`, por lo que una sonda que siga llamando a `agenteye` fallará. Actualiza la sonda en el mismo despliegue que la nueva imagen. + +### Cron / scripts manuales + +Reemplaza cualquier invocación de `agenteye start|flush|health` por el comando equivalente `agenteye-collector start|flush|health`. **Elimina cualquier cron job de `agenteye update`**; ese subcomando ya no existe (consulta [Actualizaciones a partir de ahora](#upgrades-from-now-on)). + +--- + +## 3. Elimina el binario antiguo (al final) + +Una vez que el servicio esté ejecutándose con `agenteye-collector` y reportado como saludable: + +```bash +sudo rm /usr/local/bin/agenteye +``` + +Esto es especialmente importante si también usas la CLI de AgentEye, que instala su propio comando `agenteye`; dejar el binario antiguo del collector en `/usr/local/bin/agenteye` haría que el nombre `agenteye` fuera ambiguo en tu `PATH`. + +--- + +## Actualizaciones a partir de ahora + +El collector ya no se actualiza a sí mismo. Para actualizar: + +- **Binario:** descarga el nuevo artefacto para tu plataforma (por ejemplo `agenteye-collector-linux-x86_64`; consulta [Instalación del Collector → Opción A](/es/agenteye/collector-installation#option-a-binary-recommended) para la lista completa), reemplaza `/usr/local/bin/agenteye-collector` y reinicia el servicio. +- **Docker:** ejecuta `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (o una etiqueta fija `:v`, que es preferible; `:latest` solo existe para versiones estables) y vuelve a crear el contenedor. + +`AGENTEYE_TOKEN` sigue siendo necesario para descargar desde el repositorio de versiones privado, pero el demonio en ejecución ya no lo necesita. + +--- + +## Verificar + +```bash +agenteye-collector --version # el nuevo binario está en PATH +agenteye-collector health # código de salida 0 = saludable +agenteye-collector flush # reenvía los eventos en cola y termina correctamente +``` + +Luego confirma que los nuevos eventos aparecen en tu panel de control. + +--- + +## Reversión + +La migración no es destructiva. Si necesitas revertirla, apunta la definición de tu servicio de nuevo al binario antiguo `/usr/local/bin/agenteye` (siempre que aún no lo hayas eliminado) y reinicia. El spool de eventos y la configuración son compartidos y no se ven afectados. + +--- + +## Solución de problemas + +| Síntoma | Causa | Solución | +|---|---|---| +| `warning: the collector binary is now agenteye-collector …` en cada ejecución | Estás invocando el binario con el nombre antiguo `agenteye` | Llama a `agenteye-collector` en su lugar; actualiza los archivos de servicio y scripts. | +| systemd falla: `.../agenteye: No such file or directory` | Eliminaste el binario antiguo antes de actualizar `ExecStart` | Establece `ExecStart=/usr/local/bin/agenteye-collector start` y luego ejecuta `sudo systemctl daemon-reload`. | +| El pod de Kubernetes entra en crash-loop después de actualizar la imagen | La sonda de liveness sigue ejecutando `agenteye` | Cambia el comando de la sonda a `["agenteye-collector", "health"]`. | +| `agenteye: command not found`, pero `agenteye-collector` funciona | Los scripts/alias siguen haciendo referencia al nombre antiguo | Actualízalos a `agenteye-collector`. | +| Ejecutar `agenteye` inicia la CLI, no el collector | Tienes la CLI de AgentEye instalada; esta es propietaria de `agenteye` | Usa `agenteye-collector` para el demonio y elimina cualquier binario antiguo del collector en `/usr/local/bin/agenteye`. | \ No newline at end of file diff --git a/docs/es/agenteye/deployment.mdx b/docs/es/agenteye/deployment.mdx new file mode 100644 index 00000000..fc01acf6 --- /dev/null +++ b/docs/es/agenteye/deployment.mdx @@ -0,0 +1,428 @@ +--- +title: "Despliegue" +description: "Documentación de despliegue de AgentEye." +--- + + +Esta guía cubre el despliegue del servidor y el panel de control de AgentEye en producción. + +--- + +## Visión general de la arquitectura + +``` + [ Máquinas con agentes de IA ] [ Tu infraestructura ] + + Python SDK + | escribe JSONL +----------------------+ + v +--->| PostgreSQL 15+ | + agenteye-collector --HTTP--+ | | (almacén relacional) | + | | +----------------------+ + v | + +--------+ | +----------------------+ + | Server |<------+--->| ClickHouse 24+ | + +--------+ | | (eventos / analítica)| + ^ | +----------------------+ + API | | + | | +----------------------+ + +-----------+ +- - >| Redis 7+ (opcional) | + | Dashboard | +----------------------+ + +-----------+ +``` + +- **Server**: Servicio HTTP en Rust; recibe lotes de eventos, los escribe en ClickHouse y mantiene el estado relacional en PostgreSQL. +- **Dashboard**: Aplicación web en Next.js; lee y escribe exclusivamente a través de la API del servidor. +- **agenteye-collector**: se despliega en las máquinas de los agentes, no en el host del servidor. +- **Postgres 15+**: REQUERIDO. (Elevado desde la versión 14 en la versión multi-tenant; el esquema org-membership utiliza una clave foránea `ON DELETE SET NULL` con lista de columnas, que requiere Postgres 15+. Actualiza Postgres antes de desplegar esta versión.) Almacena el estado OLTP: `api_keys`, `users`, `sessions`, `evaluation_jobs` (cola), `dashboards`, `saved_queries`, `otp_codes`, más las tablas multi-tenant `orgs`, `org_memberships`, `org_settings`. +- **ClickHouse 24+**: REQUERIDO. El almacén analítico para cada evento ingestado. Motor: `ReplacingMergeTree`, particionado por mes, ordenado por `(session_id, ts, dedup_key)`. El servidor se conecta mediante `CLICKHOUSE_URL`; la configuración incluida en `deploy/base/clickhouse/` incluye una configuración de nodo único optimizada para rendimiento. **Requisito multi-tenant:** la configuración incluida habilita la gestión de acceso SQL + `users_without_row_policies_can_read_rows=false` para que el servidor pueda crear un usuario de ClickHouse de solo lectura y una política de filas por organización (el límite de aislamiento impuesto por el motor para el editor SQL y el agente de IA). Si suministras tu propia configuración de ClickHouse, traslada estos ajustes (consulta `deploy/base/clickhouse/configmap.yaml`). +- **Redis 7+**: caché compartida *opcional* + backend de límite de tasa. El servidor y el panel se conectan mediante `REDIS_URL`. Si no está presente, ambos degradan de forma elegante a rutas solo de Postgres. Consulta **Redis (caché opcional)** más abajo. + +--- + +## Servidor + +### Descargar la imagen + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +docker pull ghcr.io/agenteye-enterprise/server:beta-latest +``` + +> Las compilaciones actuales se publican bajo `beta-latest`; `latest` solo se asigna a versiones estables. Para producción, fija una etiqueta específica `:v`; consulta [Etiquetas de imagen disponibles](#available-image-tags). + +### Variables de entorno + +| Variable | Requerida | Valor predeterminado | Descripción | +|---|---|---|---| +| `DATABASE_URL` | Sí | ninguno | DSN de Postgres. Formato de cadena de conexión libpq estándar con esquema `postgres://`. Admite `?sslmode=require` y otros parámetros libpq. La contraseña no debe contener `/`, `+` ni `=`; usa `openssl rand -hex` para generar contraseñas seguras para URLs. | +| `ADMIN_KEY` | No | ninguno | Clave API de administrador de arranque. Se inserta con todos los permisos en cada inicio. Rota cambiando el valor y reiniciando. | +| `LISTEN_ADDR` | No | `0.0.0.0:8080` | Dirección TCP donde escuchar | +| `MAX_BODY_BYTES` | No | `134217728` (128 MB) | Tamaño máximo del cuerpo de la solicitud | +| `ADMIN_EMAIL` | No | ninguno | Correo electrónico del usuario administrador de arranque. Se inserta con todos los permisos en cada inicio y se marca como protegido: no puede deshabilitarse ni modificarse sus permisos desde el panel o la API. Para rotar el administrador de arranque, cambia `ADMIN_EMAIL` y reinicia; el nuevo correo se inserta como protegido, y el anterior conserva su protección hasta que se elimine manualmente en la base de datos. | +| `ALLOWED_EMAILS` | No | ninguno (todos bloqueados) | Lista separada por comas de correos permitidos para crear usuarios e iniciar sesión. Admite direcciones exactas (`user@example.com`) y comodines de dominio (`*@example.com`). Si no se configura, no se puede crear ningún usuario ni iniciar sesión. **Solo para el primer arranque**: inicializa la lista de permitidos de la org predeterminada en el primer arranque; a partir de entonces, la página [`//settings`](#operational-settings) de cada org es la fuente de verdad y cambiar esta variable de entorno no tiene efecto. | +| `SMTP_HOST` | No | ninguno | Nombre del host del servidor SMTP para enviar correos OTP. Si no se configura, los códigos OTP se registran en stdout. | +| `SMTP_PORT` | No | `587` | Puerto del servidor SMTP | +| `SMTP_USERNAME` | No | ninguno | Nombre de usuario de autenticación SMTP | +| `SMTP_PASSWORD` | No | ninguno | Contraseña de autenticación SMTP | +| `SMTP_FROM` | No | ninguno | Dirección de correo del remitente para los correos OTP | +| `SMTP_TLS` | No | STARTTLS | Se usa STARTTLS a menos que lo desactives explícitamente: `false` o `0` envía texto plano (sin TLS); cualquier otro valor, incluido no configurar nada, habilita STARTTLS. | +| `DASHBOARD_URL` | No | valor predeterminado integrado | Origen del panel utilizado para construir tanto el enlace mágico del correo OTP como los enlaces mágicos de incidencias en las notificaciones de alertas. Si no se configura, recurre a un valor predeterminado integrado (y, solo para OTP, al origen derivado de la solicitud del panel primero). Configura esto en despliegues de dominio dividido para que tanto el correo como los enlaces de Slack/incidencias apunten a tu panel. Consulta **URL del enlace mágico del correo** más abajo; la mayoría de los operadores no necesitan configurarlo. | +| `SESSION_TTL_SECS` | No | `86400` (24 h) | Duración de la sesión del panel en segundos. **Solo para el primer arranque**: edita por org desde [`//settings`](#operational-settings) después del primer despliegue. | +| `OTP_TTL_SECS` | No | `600` (10 min) | Período de validez del código OTP en segundos. **Solo para el primer arranque**: edita por org desde [`//settings`](#operational-settings) después del primer despliegue. | +| `REDIS_URL` | No | ninguno | Backend opcional de caché compartida + límite de tasa, p. ej. `redis://redis:6379/0`. Cuando se configura, el servidor almacena en caché las búsquedas de claves API autenticadas, el agregado `/models` del panel, la lista de sesiones y la faceta de lista de entornos; también traslada el límite de tasa de solicitudes OTP de Postgres COUNT a Redis INCR. Si no se configura o no es accesible, el servidor funciona sin caché (el límite OTP recurre a Postgres, y todas las demás llamadas de caché pasan directamente a la fuente de verdad). Consulta **Redis (caché opcional)** más abajo. | +| `CLICKHOUSE_URL` | **Sí** | ninguno | URL base de la instancia ClickHouse, p. ej. `http://clickhouse:8123`. El servidor aplica su esquema de eventos a esta base de datos en cada inicio y se niega a arrancar si no puede alcanzar ClickHouse. Consulta **ClickHouse (almacén analítico requerido)** más abajo. | +| `CLICKHOUSE_DATABASE` | No | `agenteye` | Nombre de la base de datos (esquema) de ClickHouse. El servidor la crea al inicio si no existe. | +| `ORG_CH_SECRET` | No (mono-tenant) / **Sí (multi-org)** | valor de desarrollo predeterminado | Clave HMAC de la que se deriva la contraseña de ClickHouse por tenant de cada organización. El editor SQL y el `run_query` del agente de IA se ejecutan como el usuario de ClickHouse de solo lectura propio de la org, cuya política de filas aplica el aislamiento de tenant en el motor. Los despliegues mono-tenant arrancan correctamente con el valor de desarrollo integrado; **antes de aprovisionar una segunda org DEBES establecer un valor sólido y estable**, ya que el CLI `agenteye-orgctl org create` se niega a ejecutarse con el valor de desarrollo integrado. Rotarlo deja huérfanos los usuarios de ClickHouse de cada org hasta el próximo inicio (la reconciliación en el arranque lo corrige automáticamente). Mantenlo secreto y sin cambios entre réplicas. El aprovisionamiento de orgs es solo para operadores; consulta **Organizaciones (multi-tenancy)** más abajo. | +| `DEFAULT_ORG_NAME` | No | `Default` | Nombre para mostrar inicializado para la org predeterminada integrada. **Solo para el primer arranque**, y solo mientras la org conserve su identidad genérica recién migrada, aplicado al inicio y luego ignorado. Una vez que renombres la org (`agenteye-orgctl org rename`), el nombre es autoritativo y esta variable de entorno no tiene más efecto. | +| `DEFAULT_ORG_SLUG` | No | `default` | Slug de URL para la org predeterminada integrada, la ruta del panel donde reside (`//…`). Misma semántica de solo primer arranque / solo estado inicial que `DEFAULT_ORG_NAME`. Debe tener entre 1 y 40 caracteres alfanuméricos en minúsculas con guiones internos simples y no ser una [palabra reservada](#organizations-multi-tenancy); un valor inválido se ignora (la org mantiene `default`). Permite que una instalación mono-tenant aparezca como p. ej. `/acme` en lugar de `/default` sin ningún paso CLI posterior al despliegue. | +| `RUST_LOG` | No | `info` | Nivel de detalle del registro (`debug`, `warn`, `error`, `agenteye_server=trace`) | +| `EVALUATOR_ENDPOINT` | No | ninguno | URL base de tu servicio evaluador (p. ej. `http://evaluator:9000`). Cuando no se configura, toda la canalización de evaluación es un no-op; no se escriben filas en la cola ni se ejecutan workers. Consulta [Suite de Evaluación](/es/agenteye/evaluation-suite). | +| `EVALUATOR_TOKEN` | No | ninguno | Se envía como `Authorization: Bearer ` al evaluador. **Debe ser igual al valor con el que está configurado el servicio evaluador.** Solo es opcional si tu evaluador está configurado sin token. | +| `EVALUATOR_WORKERS` | No | `2` | Concurrencia: número de tareas worker por instancia del servidor que despachan evaluaciones. Es seguro ejecutar en múltiples servidores escalados horizontalmente. | +| `EVALUATOR_CLAIM_BATCH` | No | `4` | Número máximo de evaluaciones que un único worker reclama por ciclo. Los lotes se despachan **concurrentemente**, por lo que la concurrencia total en tu endpoint evaluador es `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH`. | +| `EVALUATOR_POLL_IDLE_SECS` | No | `2` | Tiempo que un worker duerme entre intentos de despacho cuando no hay nada pendiente. | +| `EVALUATOR_POLLING_INTERVAL_SECS` | No | `10` | Cadencia de respaldo final (en segundos) para los sondeos `GET /evaluate/{id}` cuando el evaluador no devuelve un `next_poll_secs` por respuesta y no anuncia un `default_poll_interval_secs` desde `GET /config`. | +| `EVALUATOR_REQUEST_TIMEOUT_MS` | No | `30000` | Tiempo de espera por solicitud HTTP contra el evaluador (milisegundos). | +| `EVALUATOR_MAX_ATTEMPTS` | No | `5` | Tras este número de intentos fallidos, una evaluación se registra como `error` terminal (o `timeout` si los fallos fueron tiempos de espera de solicitud). | +| `EVALUATOR_CONFIG_REFRESH_SECS` | No | `300` (5 min) | Con qué frecuencia el servidor vuelve a obtener `GET /config` del evaluador. | +| `EVALUATOR_MAX_POLL_DURATION_SECS` | No | `3600` (1 h) | Tiempo máximo de reloj de pared que una sesión puede permanecer en la cola de sondeo antes de que AgentEye la termine como `timeout`. Protege contra un evaluador que devuelve `pending` indefinidamente. | +| `ALERT_WORKERS` | No | `1` | Concurrencia: número de tareas worker por instancia del servidor que evalúan reglas de alerta. Consulta [Alertas](/es/agenteye/alerts). | +| `ALERT_CLAIM_BATCH` | No | `16` | Número máximo de alertas que un único worker reclama por ciclo. | +| `ALERT_POLL_IDLE_SECS` | No | `5` | Tiempo que un worker de alertas duerme cuando la cola está vacía. | +| `ALERT_REQUEST_TIMEOUT_MS` | No | `15000` | Tiempo de espera de evaluación por activación (consultas ClickHouse + HTTP de canal de salida). | +| `ALERT_MAX_ATTEMPTS` | No | `5` | Fallos transitorios consecutivos antes de que una alerta se reprograme a su cadencia normal en lugar de retroceso exponencial. | +| `AUDIT_WORKERS` | No | `1` | Concurrencia: número de tareas worker por instancia del servidor que ejecutan auditorías. Consulta [Auditorías](/es/agenteye/audits). | +| `AUDIT_CLAIM_BATCH` | No | `1` | Número máximo de auditorías pendientes que un único worker reclama por ciclo. Una investigación agéntica es un bucle largo, por eso el valor predeterminado es 1. | +| `AUDIT_POLL_IDLE_SECS` | No | `30` | Tiempo que un worker de auditorías duerme cuando no hay ninguna pendiente. | +| `AUDIT_REQUEST_TIMEOUT_MS` | No | `30000` | Tiempo de espera por consulta de política contra ClickHouse (milisegundos). | +| `AUDIT_LLM_TIMEOUT_MS` | No | `1440000` | Tiempo de espera para la llamada de investigación agéntica al servicio de asistente de IA. Un bucle de agente completo puede durar minutos; mantén este valor POR ENCIMA del `AGENTEYE_AUDIT_TIMEOUT_MS` propio del agente para que el agente devuelva sus hallazgos parciales antes de que el servidor abandone. | +| `AUDIT_MAX_ATTEMPTS` | No | `5` | Fallos transitorios consecutivos antes de que una auditoría se reprograme a su cadencia normal en lugar de retroceso exponencial. | +| `AGENTEYE_AGENT_URL` / `AGENTEYE_AGENT_TOKEN` | No | — | La investigación agéntica de la auditoría llama al servicio `agent` del asistente de IA, **reutilizando la misma conexión que el asistente** — así que configura estos dos también en el **servidor** (los manifiestos/compose incluidos lo hacen). Ambos configurados ⇒ las auditorías ejecutan la investigación de IA; cualquiera sin configurar ⇒ las auditorías ejecutan **solo políticas** (el pase de política SQL determinista aún se ejecuta), independientemente del indicador `llm_enabled` por auditoría. El agente también debe tener un LLM configurado; consulta [assistant.md](/es/agenteye/assistant). | + +**Servicio de asistente de IA: configuración de auditoría y sandbox.** La investigación agéntica y su sandbox de Python en el pod se ajustan en el **servicio agent** (no en el servidor), todos con el prefijo `AGENTEYE_AUDIT_*` y todos opcionales: + +| Variable | Valor predeterminado | Significado | +|---|---|---| +| `AGENTEYE_AUDIT_MAX_STEPS` | `200` | Máximo de turnos del agente por investigación. | +| `AGENTEYE_AUDIT_TIMEOUT_MS` | `1200000` | Tiempo de reloj de pared para una investigación (20 min). Debe mantenerse **por debajo** del `AUDIT_LLM_TIMEOUT_MS` del servidor. | +| `AGENTEYE_AUDIT_MAX_CONCURRENCY` | `1` | Investigaciones concurrentes por pod de agente (independiente del presupuesto del asistente de chat). | +| `AGENTEYE_AUDIT_SANDBOX_TIMEOUT_MS` / `_MEM_MB` / `_CPU_SECS` / `_OUTPUT_MAX_BYTES` / `_SCRIPT_MAX_BYTES` | `20000` / `768` / `10` / `64000` / `64000` | Límites por script para el sandbox de bubblewrap. | + +**Requisito de plataforma del sandbox.** El sandbox de código de auditoría ejecuta el Python del modelo dentro de una jaula bubblewrap, que necesita **espacios de nombres de usuario sin privilegios**. El pod del agente debe permitir los indicadores `clone()` — establece `seccompProfile: Unconfined` (k8s) o `security_opt: [seccomp:unconfined]` (compose) en el agente. Donde el kernel del nodo deshabilita los espacios de nombres de usuario sin privilegios (p. ej., algunas imágenes GKE COS), el sandbox **falla en la verificación previa y el auditor degrada automáticamente a solo SQL** — sin error, solo un `sandbox_available: false` en el `/health` del agente. + +### Ejecutar + +Establece `DATABASE_URL` y `CLICKHOUSE_URL` en tu entorno (el servidor se niega a arrancar sin ClickHouse) y pásalos al contenedor: + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-server \ + -e DATABASE_URL="$DATABASE_URL" \ + -e CLICKHOUSE_URL="$CLICKHOUSE_URL" \ + -e ADMIN_KEY="$ADMIN_KEY" \ + -p 8080:8080 \ + ghcr.io/agenteye-enterprise/server:beta-latest +``` + +El servidor ejecuta las migraciones de base de datos automáticamente al inicio; no se necesita ningún paso de migración separado. + +### Verificación de salud + +``` +GET /health # liveness - siempre {"status":"ok"} una vez que el proceso está activo +GET /ready # readiness - 200 cuando Postgres + ClickHouse son accesibles, sino 503 +``` + +No se requiere autenticación. Usa `/health` para las sondas de **liveness** y `/ready` para las sondas de **readiness** / balanceador de carga. `/ready` verifica las dependencias estrictas sin las que el servidor no puede funcionar (Postgres + ClickHouse), por lo que un servidor que está en ejecución pero no puede alcanzar su base de datos se retira de la rotación y aparece como `NotReady`; Redis se reporta pero nunca falla el readiness. En los manifiestos de Kubernetes incluidos, la sonda de readiness ya apunta a `/ready` y la de liveness se mantiene en `/health`. Consulta [enterprise-docs/health-monitoring.md](/es/agenteye/health-monitoring) para la imagen completa, incluidas las alertas opcionales de Kubernetes a Slack por fallos de pod. + +### URL del enlace mágico del correo + +Los correos de inicio de sesión OTP contienen un botón **abrir el panel** con un solo toque. Al hacer clic, el usuario llega a `/login?token=&email=
`; el panel intercambia ese par por una sesión y redirige a la aplicación, sin necesidad de volver a introducir el código manualmente. El servidor resuelve el origen del panel utilizado para construir el enlace en tres niveles: + +1. **Cabecera `X-AgentEye-Dashboard-Url`**: establecida automáticamente por el proxy `/api/auth/otp/request` del panel desde su propio origen público. En un despliegue de mismo origen (servidor y panel comparten un host detrás de un ingress que reenvía cabeceras proxy), **no se requiere ninguna configuración**. +2. **Variable de entorno `DASHBOARD_URL`**: configúrala si tu panel es accesible en un origen diferente al que ve el endpoint de solicitud OTP del servidor (dominio dividido `api.example.com` / `app.example.com`), o si tu ingress no propaga el host público al pod del panel (de modo que `request.nextUrl.origin` resolvería a una dirección de escucha comodín como `0.0.0.0:3000`). Ejemplo: `DASHBOARD_URL=https://app.example.com`. +3. **Predeterminado**: `https://app.befailproof.ai`, usado solo si ninguno de los anteriores está presente. + +El valor de la cabecera se valida: solo se aceptan orígenes `https://*` y de loopback (`http://localhost*`, `http://127.0.0.1*`), y las direcciones de escucha comodín (`0.0.0.0`, `[::]`) se rechazan incluso con el esquema `https://`. Cualquier otra cosa pasa al nivel 2. + +Configúralo en un clúster en ejecución con un solo comando; sin archivos, sin reconstruir kustomize: + +```bash +kubectl set env deployment/server -n agenteye \ + DASHBOARD_URL=https://app.example.com +``` + +Esto activa un rollout; los nuevos pods recogen el valor en la primera solicitud. Ten en cuenta que el override solo existe en el Deployment; un `kustomize build | kubectl apply` posterior contra el overlay lo eliminará a menos que añadas la misma variable de entorno al parche `server-env.yaml` de tu overlay. + +--- + +## Panel de control + +### Descargar la imagen + +```bash +docker pull ghcr.io/agenteye-enterprise/dashboard:beta-latest +``` + +### Variables de entorno + +| Variable | Requerida | Valor predeterminado | Descripción | +|---|---|---|---| +| `AGENTEYE_SERVER_URL` | Sí | ninguno | URL base del servidor, p. ej. `http://localhost:8080` | +| `AGENTEYE_API_KEY` | Sí | ninguno | Clave API que usa el panel para autenticarse con el servidor. Necesita todos los permisos (se recomienda la clave de administrador). | +| `AE_LOG_LEVEL` | No | `info` | Nivel de detalle del registro del lado del servidor: `debug`, `info`, `warn`, `error`. Establécelo en `debug` para ver líneas de solicitud/respuesta upstream y trazas de validación de sesión al diagnosticar problemas. | +| `AE_LOG_JSON` | No | automático | `1` fuerza salida JSON por línea; `0` fuerza salida legible por humanos. Cuando no se configura, JSON se habilita automáticamente si `NODE_ENV=production`. Se recomienda JSON en producción para que los registros se analicen correctamente con `jq` o un agregador de registros. | +| `AE_ANALYTICS_DISABLED` | No | ninguno | Establece en `1`/`true` para deshabilitar la telemetría anónima de uso del producto del panel. Consulta [Telemetría y privacidad](#telemetry--privacy) más abajo. | +| `REDIS_URL` | No | ninguno | Backend opcional de caché compartida, p. ej. `redis://redis:6379/0`. Cuando se configura, el panel almacena en caché los resultados de `validateSession()` entre réplicas y comparte la caché de fetch de Next.js para las rutas proxy de agregado de latencia y lista de entornos. Los límites de tasa OTP de solicitud y verificación en el borde también usan Redis cuando está disponible (fallando abierto si Redis no es accesible; el límite del lado del servidor es el resguardo de seguridad). Consulta **Redis (caché opcional)** más abajo. | +| `AGENTEYE_AGENT_URL` | No | ninguno | URL base del servicio `agent` de asistente de IA opcional, p. ej. `http://agent:9100`. **Déjalo sin configurar para ocultar completamente el asistente**: no aparece ningún elemento del asistente en el panel. Consulta [enterprise-docs/assistant.md](/es/agenteye/assistant). | +| `AGENTEYE_AGENT_TOKEN` | No | ninguno | Secreto compartido que el panel presenta al servicio `agent`. Debe coincidir con el `AGENTEYE_AGENT_TOKEN` configurado en el agente. Consulta [enterprise-docs/assistant.md](/es/agenteye/assistant). | + +### Ejecutar + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-dashboard \ + -e AGENTEYE_SERVER_URL="http://your-server-host:8080" \ + -e AGENTEYE_API_KEY="$ADMIN_KEY" \ + -p 3000:3000 \ + ghcr.io/agenteye-enterprise/dashboard:beta-latest +``` + +### Telemetría y privacidad + +El panel envía **análisis de uso del producto anónimos** al servicio de análisis de Exosphere (PostHog): qué páginas del panel se visualizan y algunas acciones de la interfaz como crear una clave API o volver a evaluar una sesión. Esta señal de uso informa qué funciones se priorizan. + +- **Ningún dato de agente, sesión ni evento abandona tu infraestructura.** Solo se reporta el uso de la interfaz del panel. Las URLs de las páginas se eliminan de identificadores antes de enviarlas, y los operadores se identifican únicamente por un ID interno opaco, nunca por correo electrónico. +- La telemetría está **habilitada de forma predeterminada**. Para desactivarla completamente, establece `AE_ANALYTICS_DISABLED=1` en el contenedor del panel y reinicia. +- Los análisis se envían a la propia ruta `/ingest` del panel, que el panel reenvía como proxy inverso a PostHog (`https://us.i.posthog.com`). Mantener las solicitudes como first-party significa que los bloqueadores de anuncios del navegador no las descartan. El **contenedor del panel** necesita acceso de salida a PostHog; si está bloqueado, la telemetría no hace nada silenciosamente y el panel no se ve afectado. + +--- + +## Asistente de IA (opcional) + +Un asistente de IA integrado en el panel permite a tu equipo hacer preguntas sobre sus datos de agentes en lenguaje natural (resumiendo sesiones, redactando SQL para el editor `/queries` y convirtiendo consultas guardadas en tiles del panel) sin salir del panel. Se ejecuta como un contenedor `agent` interno separado (sobre el Agents SDK de Claude) que solo el panel puede alcanzar, y permanece **deshabilitado hasta que configures un endpoint de LLM**. + +Para habilitarlo, establece en el servicio `agent` una conexión LLM (**Portkey** mediante `PORTKEY_API_KEY` + un slug de catálogo de modelos `AGENTEYE_AGENT_MODEL=@/`, Anthropic directo mediante `ANTHROPIC_API_KEY`, otra pasarela mediante `ANTHROPIC_BASE_URL`, o Bedrock/Vertex), una clave de datos **dedicada**, y un `AGENTEYE_AGENT_TOKEN` compartido que coincida con el panel. Los usuarios del panel además necesitan el permiso `agent:use`. + +Para la clave de datos del asistente no necesitas crear nada manualmente: elige un secreto aleatorio, establécelo como `AGENTEYE_API_KEY` en el `agent` **y** como `AGENT_API_KEY` en el `server`, y el servidor lo inicializa al arrancar con un conjunto fijo de permisos. Su acceso a los datos es de solo lectura (`events:read`, `evaluations:read`, `dashboards:read`, `queries:read`), y además tiene permisos de autoría con aprobación (`dashboards:write`, `queries:write`, `queries:run`) para que pueda redactar y validar consultas guardadas y construir tiles del panel en nombre del usuario; todo el SQL aún se ejecuta a través del rol de ClickHouse de solo lectura de la org, por lo que esto amplía lo que el asistente puede crear, no los datos a los que puede acceder. Los permisos están fijados en el código y no pueden ampliarse mediante configuración. Esa clave está protegida; no puede deshabilitarse ni regenerarse mediante la API, solo se puede rotar cambiando el valor y reiniciando. Nunca reutilices la clave de administrador/panel para esto. + +La configuración completa, la referencia de variables de entorno, las opciones de telemetría y el modelo de seguridad están en **[enterprise-docs/assistant.md](/es/agenteye/assistant)**. + +--- + +## ClickHouse (almacén analítico requerido) + +ClickHouse mantiene tus paneles ágiles a alto volumen de eventos y permite que el editor SQL `/queries` una eventos, evaluaciones y sesiones en un único almacén. Es el almacén canónico requerido para cada evento ingestado, cada resultado de evaluación terminal y los agregados por sesión derivados. PostgreSQL mantiene las tablas relacionales / de estado mutable (api_keys, users, otp_codes, evaluation_jobs, dashboards, saved_queries); la superficie analítica vive en ClickHouse para que los resúmenes del panel y tus propias consultas SQL puedan escanearla y unirla de forma nativa, sin viajes de ida y vuelta entre bases de datos. El servidor se niega a arrancar sin `CLICKHOUSE_URL`. + +### Esquema + +Al inicio del servidor se crean tres objetos de ClickHouse, todos idempotentes (`CREATE IF NOT EXISTS`): + +- **`agenteye.events`**: `ReplacingMergeTree(ingested_at)`, particionado por `toYYYYMM(ts)`, ordenado por `(session_id, ts, dedup_key)`. Las inserciones duplicadas (reintentos del colector) se colapsan en una sola fila en el momento de la fusión; el servidor calcula un `dedup_key` SHA-256 determinista para cada evento, por lo que los reintentos son seguros. +- **`agenteye.evaluations`**: `ReplacingMergeTree(ingested_at)`, particionado por `toYYYYMM(finished_at)`, ordenado por `(session_id, finished_at, dedup_key)`. Se escribe una vez por resultado de evaluación terminal por el pipeline del evaluador. Mismo modelo de clave de deduplicación que `events`. +- **`agenteye.agent_sessions`**: una **VISTA** sobre `agenteye.events`, no una tabla física. Cada columna se deriva (`started_at = min(ts)`, `last_event_at = max(ts)`, `ended_at = max(if event_type='agent_end', ts, NULL)`, `event_count = count()`, etc.). No hay upsert por evento ni backfill separado; la vista refleja automáticamente lo que hay en `events`. + +Para compatibilidad con versiones anteriores de consultas guardadas que referencian `analytics.evaluations` / `analytics.sessions`, el servidor también crea una base de datos de ClickHouse `analytics` con vistas sobre las tablas `agenteye.*`; `analytics.events`, `analytics.evaluations`, `analytics.agent_sessions`, `analytics.sessions` se resuelven correctamente. + +### Configuración + +El docker-compose incluido y `deploy/base/clickhouse/` incluyen un servicio ClickHouse ajustado para la carga de trabajo de AgentEye: + +- 2 GiB solicitados / 4 GiB de límite de memoria en el overlay base incluido (dimensionado para nodos pequeños de POC/staging); los clientes de producción deben escalar hacia arriba en el overlay: el mínimo recomendado es 2c / 4Gi de solicitud, 6c / 8Gi de límite. `max_server_memory_usage_to_ram_ratio=0.9` +- Caché de marcas de 5 GiB + caché sin comprimir de 8 GiB +- `background_pool_size=16`, `background_merges_mutations_concurrency_ratio=2` +- MergeTree: `parts_to_throw_insert=3000`, `parts_to_delay_insert=1500`, `non_replicated_deduplication_window=1000` +- `local_io_method=auto` (io_uring en kernels compatibles) +- `fsync_metadata=0`: aceptable debido a la ingestión al menos una vez + deduplicación de ReplacingMergeTree +- `query_log` habilitado con TTL de 30 días; `query_thread_log` eliminado (costoso a alto QPS) +- `max_execution_time=30` para consultas del lado del usuario +- PVC de 100 GiB en la plantilla del StatefulSet (los overlays de clientes DEBEN sobrescribir con una clase de almacenamiento SSD rápida para producción) + +### Copias de seguridad + +Todo tu conjunto de datos se captura noche a noche en un único archivo restaurable, por lo que la pérdida de un clúster o almacenamiento es recuperable. ClickHouse se respalda automáticamente mediante el CronJob diario `agenteye-backup`, que vuelca tanto PostgreSQL como ClickHouse en un solo paso. ClickHouse se lee a través de su API HTTP: `agenteye.events` y `agenteye.evaluations` se vuelcan en formato nativo de ClickHouse (las vistas y políticas de filas se recrean por el servidor al inicio, por lo que los datos de la tabla son la imagen completa) y se empaquetan con el volcado de Postgres en un único archivo comprimido que se sube a tu almacenamiento de objetos. + +El bucket de destino y las credenciales de la nube se configuran por overlay. Consulta la sección **Copias de seguridad** de [enterprise-docs/kubernetes-deployment.md](/es/agenteye/kubernetes-deployment) para la configuración de carga y los pasos de restauración. + +--- + +## Redis (caché opcional) + +Redis es un backend de caché compartida + límite de tasa **opcional** utilizado por el servidor y el panel. Con Redis desplegado y `REDIS_URL` configurado en ambos servicios: + +- **El servidor** almacena en caché las búsquedas de claves API autenticadas, las listas `/events/environments` + `/evaluations/environments`, el resumen `/events/latency_aggregate` (la consulta más pesada que sondea el panel), la lista `/sessions`, y cambia el límite de tasa de solicitudes OTP de un `COUNT(*)` de Postgres a un `INCR + EXPIRE` de Redis. +- **El panel** almacena en caché los resultados de `validateSession()` para que las 10-20 llamadas API autenticadas que una carga de página típica realiza compartan una sola verificación de sesión upstream. También limita la tasa de solicitudes OTP y verificación OTP en el borde del panel. + +**Ambos servicios degradan de forma elegante si Redis no es accesible.** Cada llamada de caché devuelve `Err` dentro de un tiempo de espera acotado y el llamador recurre a la fuente de verdad (Postgres en el servidor, el servidor Rust upstream en el panel). El límite de tasa OTP recurre a la ruta `COUNT(*)` de Postgres en el servidor (la propiedad de seguridad se preserva); el límite OTP en el borde del panel falla abierto mientras el límite del lado del servidor sigue vigente. Que Redis esté caído degrada la latencia, no la corrección. + +### Configuración + +El paquete docker-compose ya incluye un servicio Redis y conecta `REDIS_URL=redis://redis:6379/0` al servidor y al panel. Para usar un Redis externo, establece `REDIS_URL` en tu endpoint y elimina el servicio `redis` del archivo compose. + +### Memoria y persistencia + +La imagen Redis incluida se ejecuta con `--appendonly yes --appendfsync everysec --maxmemory 256mb --maxmemory-policy allkeys-lru`. La persistencia AOF significa que la caché sobrevive a los reinicios del contenedor; `everysec` es el equilibrio correcto entre durabilidad y rendimiento porque perder el último segundo de escrituras en caché es inofensivo. La expulsión LRU limita el crecimiento de memoria. + +### Cuándo NO desplegar Redis + +- Desarrollo/QA de instancia única. Las cachés en proceso del servidor por sí solas ofrecen la mayor parte del beneficio por réplica; Redis añade el compartido entre réplicas que las configuraciones de instancia única no necesitan. +- Instalaciones con aislamiento de red donde el coste operativo de ejecutar un servicio más supera la ganancia en latencia. + +--- + +## Docker Compose (recomendado) + +Un `docker-compose.yml` está disponible en el repositorio `agenteye-enterprise/releases`. Levanta Postgres, ClickHouse, Redis, el servidor y el panel con un único comando. + +```bash +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download \ + --repo agenteye-enterprise/releases \ + --pattern 'docker-compose.yml' \ + --dir ./agenteye +cd agenteye +``` + +**Sobrescribe los valores predeterminados mediante `.env`:** + +``` +# Usa contraseñas seguras para URLs (sin caracteres /, +, ni =). +# Genera con: openssl rand -hex 24 +POSTGRES_PASSWORD=your-db-password +ADMIN_KEY=your-admin-secret + +# Autenticación del panel +ADMIN_EMAIL=admin@yourcompany.com +ALLOWED_EMAILS=*@yourcompany.com + +# SMTP para correos OTP (omitir para registrar los códigos OTP en stdout) +# SMTP_HOST=smtp.yourprovider.com +# SMTP_PORT=587 +# SMTP_USERNAME=your-smtp-user +# SMTP_PASSWORD=your-smtp-password +# SMTP_FROM=noreply@yourcompany.com + +RUST_LOG=info +``` + +```bash +docker compose up -d +``` + +**Detener (conserva el volumen de datos):** + +```bash +docker compose down +``` + +**Detener y borrar todos los datos:** + +```bash +docker compose down -v +``` + +--- + +## Configuración operacional + +Un pequeño conjunto de parámetros operacionales que antes estaban fijados por variables de entorno ahora son editables por organización desde la página **`//settings`** del panel; cada org configura la suya propia. Los cambios surten efecto en segundos, sin reinicio ni redespliegue. + +| Configuración | Variable de entorno de arranque | Qué controla | +|---|---|---| +| Inicios de sesión permitidos | `ALLOWED_EMAILS` | Correos (o comodines `*@domain.com`) autorizados a recibir un OTP y añadirse como usuarios | +| Permisos predeterminados del usuario | `DEFAULT_USER_PERMISSIONS` | Tokens de permiso separados por comas preseleccionados cuando un administrador abre **+ nuevo usuario**. Cada token debe ser una de las cadenas listadas en [Permisos de clave API](/es/agenteye/api-keys). Por defecto usa el preset `standard`: acceso de solo lectura más las acciones cotidianas de guardia (activar reevaluaciones, ejecutar consultas, confirmar incidencias, usar el asistente). | +| Duración de la sesión | `SESSION_TTL_SECS` | Cuánto tiempo permanece válido un inicio de sesión en el panel antes de requerir reautenticación. El panel vuelve a verificar la sesión upstream cada 5 segundos, por lo que una actualización de permisos en `//users` surte efecto en la próxima solicitud del usuario afectado, sin necesidad de volver a iniciar sesión. | +| Duración del código de un solo uso | `OTP_TTL_SECS` | Cuánto tiempo permanece utilizable un OTP / enlace mágico | +| Canales de notificación de alertas | `ALERTS_ENABLED_CHANNELS` | Lista separada por comas de tipos de canales que el despachador de alertas puede usar: `email`, `slack`, `webhook`. La configuración por alerta aún se crea en `//alerts/`, pero el despachador filtra cada entrega saliente a través de este conjunto; un canal deshabilitado aquí se interrumpe con una fila de auditoría `skipped_disabled`. El canal `dashboard` (la inserción de auditoría local) siempre está permitido. Por defecto los tres están habilitados. | + +### Cómo funciona el arranque + +La configuración se almacena por organización en `org_settings`. En el primer arranque, el servidor inicializa las filas faltantes de la org predeterminada desde la variable de entorno correspondiente (o un valor predeterminado razonable si la variable no está configurada). A partir de entonces, **el valor almacenado es la fuente de verdad y la variable de entorno se ignora**; cambiar la variable de entorno en un reinicio posterior no afectará el valor de una org activa, y las orgs adicionales comienzan con valores predeterminados y configuran los suyos propios. + +Esto significa: + +- Para un despliegue nuevo, establece las variables de entorno como se muestra arriba y la org predeterminada las leerá en el primer arranque. +- Para cambiar un valor más adelante, inicia sesión en el panel y edítalo en `//settings`. El cambio se aplica en segundos en todas las réplicas del servidor; no se necesita reinicio. +- Una línea de registro al inicio registra qué se inicializó frente a qué ya estaba presente, para que puedas confirmar que el arranque surtió efecto: + + ```text + INFO settings bootstrap: seeded default-org row key=allowed_sign_ins env_var=ALLOWED_EMAILS seeded_from_env=true + ``` + +#### Semántica de inicio de sesión entre organizaciones + +Una sesión y un OTP son globales para el usuario, no para una sola org, por lo que dos reglas reconcilian la configuración por org en el momento del inicio de sesión: + +- **Duración de sesión / OTP**: gana la duración más estricta (más corta) entre las orgs a las que pertenece el usuario. +- **Inicios de sesión permitidos**: la compuerta hace OR de la lista de permitidos de cada org con la membresía de org: un usuario puede solicitar un OTP si la lista de permitidos de cualquier org admite su correo **o** ya es miembro de alguna org. + +### Permisos + +El acceso a una página `//settings` está controlado por dos permisos: + +- `settings:read`: ver la página y los valores actuales. +- `settings:write`: guardar cambios. + +El usuario administrador de arranque (inicializado desde `ADMIN_EMAIL`) obtiene ambos automáticamente junto con todos los demás permisos. Otórgalos a otros usuarios desde `//users` según sea necesario. + +--- + +## Organizaciones (multi-tenancy) + +Un único despliegue puede servir a múltiples **organizaciones** (tenants) aisladas; cada fila de datos pertenece exactamente a una org y el aislamiento se aplica en el motor de base de datos. Una instalación mono-tenant no necesita nada aquí; todos los datos viven en una org `default` integrada. (Puedes dar a esa org un nombre más amigable y un slug de URL para que viva en p. ej. `/acme` en lugar de `/default`, estableciendo `DEFAULT_ORG_NAME` / `DEFAULT_ORG_SLUG` antes del primer arranque, o renombrándola en cualquier momento con `agenteye-orgctl org rename`.) + +**El aprovisionamiento de tenants es solo para operadores.** Las organizaciones y sus membresías se crean y gestionan con el CLI **`agenteye-orgctl`**, que se incluye **dentro de la imagen del servidor** (junto a `agenteye-server`) y se ejecuta **dentro del pod del servidor existente**; no hay **ningún pod/Job separado, ninguna API HTTP y ningún botón en el panel**. Reutiliza el `DATABASE_URL`, `CLICKHOUSE_URL` y `ORG_CH_SECRET` del servidor. + +```bash +# Docker Compose - exec en el servicio del servidor en ejecución: +docker compose exec server agenteye-orgctl org create --slug acme --name "Acme Corp" +docker compose exec server agenteye-orgctl member add --org acme --email alice@acme.example --set admin + +# Kubernetes - exec en el Deployment del servidor en ejecución: +kubectl -n agenteye exec deploy/server -- agenteye-orgctl org list +``` + +Verbos disponibles: `org create | list | rename | delete | purge` y `member add | list | update | remove`, con conjuntos de permisos integrados `admin`, `standard` y `read-only`. Los miembros añadidos reciben un OTP en su primer inicio de sesión en el panel. + +**Antes de crear una segunda org:** establece un `ORG_CH_SECRET` sólido y estable (el comando `org create` se niega a ejecutarse con el valor de desarrollo integrado predeterminado) y asegúrate de que Postgres sea **15+**. **Sin cambios:** las claves API por org aún se crean en el panel/API por los miembros de la org; solo el ciclo de vida de org + miembro se trasladó al CLI. Referencia completa de comandos y un ejemplo detallado: **[enterprise-docs/tenant-management.md](/es/agenteye/tenant-management)**. + +--- + +## Llenado de la ventana de contexto + +Cada evento `model_response` muestra una **píldora de llenado de contexto** — tokens de entrada más salida como porcentaje de la ventana de contexto de ese modelo. Las bandas son `healthy` (0–24%), `watch` (25–49%), `compacting` (50–74%) y `reset context` (75–100%). AgentEye resuelve los IDs de modelos comunes automáticamente, por lo que no se requiere ninguna configuración inicial. + +Cada modelo que envía una organización aparece en **Settings → model context windows**. Los usuarios con `settings:write` pueden sobrescribir su ventana o añadir un modelo privado/proxy (0–1.000.000 tokens); `0` significa "desconocido" y suprime la píldora. Los cambios se aplican a los eventos recién ingestados. Los usuarios con `settings:read` pueden ver la lista. + +Los nuevos eventos obtienen el llenado desde el momento en que actualices. Para también completar los eventos **históricos** (y la lista por modelo) de un despliegue existente, ejecuta el backfill único — se incluye dentro de la imagen del servidor (como `agenteye-orgctl`) y se ejecuta en el pod del servidor existente: + +```bash +# vista previa (imprime la mutación por org, no cambia nada): +kubectl -n agenteye exec deploy/server -- agenteye-backfill-context-window --dry-run +# aplicar: +kubectl -n agenteye exec deploy/server -- agenteye-backfill-context-window +# docker compose: +docker compose exec server agenteye-backfill-context-window +``` + +Es idempotente (seguro de ejecutar varias veces) y reutiliza `DATABASE_URL` / `CLICKHOUSE_URL` / `REDIS_URL` del pod. Vuelve a ejecutarlo después de editar las ventanas de modelos si deseas que los eventos existentes se recalculen. + +--- + +## Consideraciones para producción + +- **Postgres**: Usa un servicio de Postgres administrado o una instancia dedicada con copias de seguridad regulares. El `DATABASE_URL` admite todos los parámetros libpq estándar, incluido `sslmode=require` para conexiones cifradas. +- **TLS**: Coloca el servidor y el panel detrás de un proxy inverso (nginx, Caddy, Traefik) que termine TLS. +- **Firewall**: El puerto del servidor (predeterminado 8080) solo debe ser accesible desde las máquinas del colector y el host del panel, no desde la internet pública. +- **Clave de administrador**: Establece `ADMIN_KEY` como un secreto aleatorio sólido. Después del arranque inicial, crea claves con alcance dedicado para los colectores y el panel en lugar de usar la clave de administrador en todas partes. +- **Etiquetas de imagen**: Fija a la versión en tus manifiestos de lanzamiento (por ejemplo, `server:v0.0.1-beta.48`) en producción en lugar de una etiqueta flotante para evitar actualizaciones no deseadas. Las compilaciones beta actuales se publican bajo `beta-latest`; `latest` solo se asigna a versiones estables. +- **Monitoreo de salud**: En Kubernetes la sonda de readiness usa `/ready` (accesibilidad de Postgres + ClickHouse) mientras la de liveness se mantiene en `/health`. Para alertas a Slack de "¿está AgentEye en funcionamiento?" a nivel de flota, habilita el add-on Robusta opcional; consulta [enterprise-docs/health-monitoring.md](/es/agenteye/health-monitoring). + +--- + +## Etiquetas de imagen disponibles + +| Etiqueta | Descripción | +|-----|-------------| +| `latest` | Última versión estable | +| `beta-latest` | Última versión preliminar (beta) | +| `v` | Versión fijada, p. ej. `v0.0.1-beta.48` (recomendado para producción) | \ No newline at end of file diff --git a/docs/es/agenteye/evaluation-suite.mdx b/docs/es/agenteye/evaluation-suite.mdx new file mode 100644 index 00000000..cea576fe --- /dev/null +++ b/docs/es/agenteye/evaluation-suite.mdx @@ -0,0 +1,358 @@ +--- +title: "Suite de Evaluación" +description: "Documentación de la Suite de Evaluación de AgentEye." +--- + +AgentEye puntúa las sesiones de agente completadas enviando mediante POST la transcripción completa de eventos a un **único servicio evaluador gestionado por el cliente**. El evaluador devuelve las puntuaciones de forma inmediata o entregando un `job_id` para que AgentEye realice consultas periódicas. Los resultados se almacenan y se muestran en el panel de control. + +Esta guía cubre: + +1. Cómo se detecta la finalización de una sesión. +2. El contrato HTTP que debe implementar el evaluador. +3. Configuración del servidor AgentEye. +4. Visualización de resultados. +5. Solución de problemas. + +Para el helper de Python que implementa el contrato por ti, consulta el +[paquete `agenteye-evaluator` en PyPI](https://pypi.org/project/agenteye-evaluator/). + +--- + +## Cómo funciona + +```text +ingest /events ──▶ AgentEye ──── POST /evaluate ────▶ Evaluator service + (agent_end) server ◀──── done | pending ──── + │ + │ GET /evaluate/{job_id} ─────▶ + │ ◀──── done ────────────── + ▼ + evaluations (terminal results) +``` + +Cuando el SDK de AgentEye emite un evento `agent_end` para una sesión, el servidor programa una evaluación. A continuación, envía mediante POST la transcripción completa de eventos a tu servicio evaluador, que puede: + +- **Devolver el resultado de forma inmediata** con `{"status":"done", "scores":{...}, "reasoning":{...}, "summary":"..."}`. El resultado se añade a la línea temporal de evaluaciones de la sesión. `reasoning` y `summary` son opcionales. +- **Diferir** con `{"status":"pending", "job_id":"abc-123"}`. AgentEye entonces llama a `GET {EVALUATOR_ENDPOINT}/evaluate/abc-123` hasta que tu evaluador devuelva `{"status":"done", ...}` o `{"status":"error", "error":"..."}`. + + La cadencia de consulta es por trabajo: una respuesta `pending` puede incluir `next_poll_secs` para sobrescribirla; en caso contrario, AgentEye utiliza el valor `default_poll_interval_secs` de `GET /config`; si tampoco está disponible, el servidor recurre a `EVALUATOR_POLLING_INTERVAL_SECS` (por defecto 10s). Todos los valores se limitan al rango [1s, 1h]. + +Las sesiones que nunca emiten `agent_end` (por ejemplo, un proceso de agente que se ha interrumpido inesperadamente) también pueden procesarse: el `GET /config` del evaluador puede devolver `{"inactivity_timeout_secs": 1800}`, y AgentEye evaluará cualquier sesión que haya estado inactiva durante ese tiempo. Establece el campo a `null` u omítelo para deshabilitar esta opción alternativa. + +El pipeline es completamente no operativo cuando `EVALUATOR_ENDPOINT` no está definido. + +Una sesión puede acumular **múltiples evaluaciones terminales a lo largo del tiempo**: cada evento `agent_end` (y cada re-evaluación manual desde el panel) añade una nueva fila de evaluación. Esta es la forma recomendada de evaluar una conversación reanudada: un usuario finaliza un agente, vuelve más tarde, envía más eventos, finaliza el agente de nuevo, y se ejecuta una segunda evaluación sobre la transcripción completa actualizada. El panel muestra la evaluación más reciente como la principal y las anteriores como una línea temporal desplegable. Mientras se ejecuta una evaluación para una sesión, los eventos `agent_end` adicionales de esa sesión se ignoran; el siguiente que llegue tras completarse la evaluación en curso encolará una nueva evaluación como de costumbre. + +La opción alternativa por inactividad también se activa en sesiones reanudadas: si llegan nuevos eventos tras una evaluación terminal anterior y la sesión vuelve a quedarse inactiva más allá de `inactivity_timeout_secs`, se encola una nueva evaluación. + +Los fallos transitorios (5xx, 429, timeouts, errores de red) se reintentan con retroceso exponencial hasta `EVALUATOR_MAX_ATTEMPTS`; las respuestas 4xx son terminales. AgentEye puede ejecutarse de forma segura con múltiples instancias de servidor escaladas horizontalmente; el trabajo se particiona de modo que la misma sesión nunca se despacha dos veces de forma simultánea. + +--- + +## Contrato HTTP + +Todas las rutas autenticadas utilizan **autenticación con token bearer**. El mismo valor debe configurarse en ambos lados: + +- Servidor AgentEye: variable de entorno `EVALUATOR_TOKEN` +- Servicio evaluador: configurado de la misma forma (el SDK `agenteye-evaluator` lee `EVALUATOR_TOKEN` por convención) + +Si `EVALUATOR_TOKEN` no está definido, el servidor no envía cabecera `Authorization`; el evaluador puede entonces aceptar solicitudes anónimas, lo cual es válido para una red interna, pero no es recomendable en internet público. + +### Rutas que el evaluador debe servir + +| Ruta | Cuerpo / parámetros | Respuesta | +|---|---|---| +| `GET /health` | ninguno | `{"status":"ok"}` (abierta, sin autenticación) | +| `GET /config` | ninguno | `{"inactivity_timeout_secs": \| null, "default_poll_interval_secs": \| omitted}` | +| `POST /evaluate` | JSON `EvalRequest` | `{"status":"done", ...}` o `{"status":"pending", "job_id":"..."}` | +| `GET /evaluate/{id}` | ninguno | misma forma de respuesta que `/evaluate` | + +### Cuerpo `EvalRequest` enviado por el servidor + +```json +{ + "schema_version": "1", + "session_id": "session-abc123", + "agent_id": "planner", + "environment": "production", + "started_at": "2026-05-10T12:00:00Z", + "ended_at": "2026-05-10T12:05:00Z", + "events": [ + { "id": 1234, "ts": "...", "event_type": "agent_start", "payload": { ... } }, + ... + ] +} +``` + +### Formas de respuesta + +**Síncrona (done):** + +```json +{ + "status": "done", + "scores": { "helpfulness": 0.85, "tool_efficiency": 0.6 }, + "reasoning": { + "helpfulness": "answered the question directly with citations", + "tool_efficiency": "called list_files three times when one would have done" + }, + "summary": "strong answer quality, weak tool selection" +} +``` + +`reasoning` (un mapa de justificación por puntuación) y `summary` (una narrativa general de un párrafo) son ambos opcionales. Las claves en `reasoning` deben coincidir con las claves en `scores`; el panel muestra cada entrada debajo de su barra de puntuación correspondiente. Los evaluadores anteriores que solo devuelven `scores` siguen funcionando sin cambios; `reasoning` y `summary` simplemente se leen como null y las correspondientes opciones de la interfaz se omiten. + +**Asíncrona (diferida):** + +```json +{ "status": "pending", "job_id": "abc-123", "next_poll_secs": 30 } +``` + +`next_poll_secs` es opcional; si se omite, el servidor recurre al `default_poll_interval_secs` del evaluador obtenido de `/config`, y luego a su propia variable de entorno `EVALUATOR_POLLING_INTERVAL_SECS`. + +**Error terminal en el evaluador:** + +```json +{ "status": "error", "error": "model service unavailable" } +``` + +El servidor trata cualquier otro cuerpo 2xx como un error de protocolo y registra un `error` terminal para la sesión. + +--- + +## Escribir un evaluador con el SDK + +El paquete Python `agenteye-evaluator` te proporciona un wrapper tipado de FastAPI que implementa el contrato HTTP anterior. Instálalo desde PyPI: + +```bash +pip install agenteye-evaluator +``` + +Evaluador mínimo viable: + +```python +import os +from agenteye_evaluator import Evaluator, EvalRequest, EvalResponse + +app = Evaluator(token=os.environ["EVALUATOR_TOKEN"]) + +@app.evaluator +def run(req: EvalRequest) -> EvalResponse: + # Inspect req.events (the full session transcript) and return scores. + tool_calls = sum(1 for e in req.events if e.event_type == "tool_use") + return EvalResponse( + scores={"tool_calls": float(tool_calls)}, + reasoning={"tool_calls": f"{tool_calls} tool invocations in the transcript"}, + summary="tight tool loop" if tool_calls < 5 else "agent looped on tools", + ) +``` + +La instancia `app` es compatible con ASGI, por lo que `uvicorn module:app` la ejecuta. + +Para evaluadores que necesiten diferir trabajo costoso, devuelve `JobPending` en su lugar y registra un handler `@app.job_lookup`; el servidor AgentEye consulta `GET /evaluate/{job_id}` hasta que devuelvas un estado terminal o se agote el límite `EVALUATOR_MAX_POLL_DURATION_SECS` (por defecto 1 h). + +Referencia completa de la API, patrón asíncrono y esquema de eventos: el README de `agenteye-evaluator` se incluye en cada tarball de versión en la +[página de releases de agenteye-enterprise](https://github.com/agenteye-enterprise/releases), +o puedes consultarlo en la página del paquete en PyPI. + +--- + +## Ejecutar un evaluador en Kubernetes + +El evaluador es **tu servicio**: AgentEye no incluye un contenedor evaluador por defecto. La versión incluye manifiestos de Kubernetes de referencia en `deploy/examples/evaluator/` que puedes aplicar tal cual tras reemplazar tu imagen y un token bearer compartido. + +### 1. Conteneriza tu evaluador + +Un Dockerfile mínimo para tu evaluador: + +```dockerfile +FROM python:3.12-slim +WORKDIR /app +RUN pip install --no-cache-dir agenteye-evaluator uvicorn +COPY my_evaluator.py . +RUN useradd --uid 10001 --create-home --shell /usr/sbin/nologin evaluator \ + && chown -R evaluator:evaluator /app +USER evaluator +EXPOSE 9000 +CMD ["uvicorn", "my_evaluator:app", "--host", "0.0.0.0", "--port", "9000"] +``` + +`runAsNonRoot` (UID 10001) mantiene el contenedor compatible con los perfiles restringidos de Pod Security. + +### 2. Crea el token bearer compartido + +```bash +kubectl -n agenteye create secret generic evaluator-token \ + --from-literal=token="$(openssl rand -hex 32)" +``` + +Usa el mismo valor como `EVALUATOR_TOKEN` en el servidor AgentEye. El servidor envía `Authorization: Bearer ` en cada solicitud; el SDK utiliza `hmac.compare_digest` para una verificación en tiempo constante y rechaza las discrepancias con HTTP 401. + +### 3. Aplica los manifiestos de ejemplo + +```bash +# Edit deploy/examples/evaluator/deployment.yaml first to point +# `image:` at your registry, then: +kubectl apply -k deploy/examples/evaluator/ +``` + +El ejemplo incluye: + +- Un Deployment de 2 réplicas con `runAsNonRoot`, sistema de archivos raíz de solo lectura, todas las capabilities eliminadas, y liveness + readiness en `/health` +- Un Service de tipo ClusterIP en el puerto 9000 +- Una plantilla `secret.example.yaml` (excluida intencionalmente de la Kustomization; crea el secret real fuera de banda para que ningún token acabe en git) + +### 4. Conecta AgentEye al evaluador + +En el servidor AgentEye, define: + +```bash +EVALUATOR_ENDPOINT=http://evaluator:9000 +EVALUATOR_TOKEN= +``` + +El servidor distribuye `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH` solicitudes concurrentes entre todos los pods del evaluador (valores por defecto: `2 × 4 = 8`). Escala `replicas` y los límites de recursos por pod en conjunto con estos parámetros del lado del servidor. + +### Verificación + +```bash +kubectl -n agenteye port-forward svc/evaluator 9000:9000 +curl -s http://localhost:9000/health # → {"status":"ok"} +``` + +Tras ejecutar un agente de extremo a extremo, `GET /evaluations` en el servidor AgentEye debería devolver una fila con `status: "done"` y las puntuaciones que produjo tu evaluador. + +--- + +## Configurar el servidor AgentEye + +Define en el proceso del servidor: + +| Variable de entorno | Significado | +|---|---| +| `EVALUATOR_ENDPOINT` | URL base de tu evaluador (`http://evaluator:9000`). Sin definir = pipeline deshabilitado. | +| `EVALUATOR_TOKEN` | Token bearer. Debe coincidir con el valor con el que está configurado el servicio evaluador. | +| `EVALUATOR_WORKERS` | Tareas worker por instancia de servidor (por defecto 2). | +| `EVALUATOR_CLAIM_BATCH` | Filas reclamadas por ciclo de worker (por defecto 4). Los lotes se procesan de forma **concurrente**; la concurrencia efectiva en tu endpoint evaluador es `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH`. | +| `EVALUATOR_POLL_IDLE_SECS` | Tiempo que un worker duerme entre intentos de despacho cuando no hay ninguna evaluación pendiente (por defecto 2s). | +| `EVALUATOR_POLLING_INTERVAL_SECS` | Reserva final para la cadencia de `GET /evaluate/{id}` cuando no se han definido ni `next_poll_secs` por respuesta ni `default_poll_interval_secs` del evaluador (por defecto 10s). | +| `EVALUATOR_REQUEST_TIMEOUT_MS` | Timeout por solicitud (por defecto 30000). | +| `EVALUATOR_MAX_ATTEMPTS` | Tras este número de fallos transitorios, el resultado se registra como `error` terminal (por defecto 5). | +| `EVALUATOR_CONFIG_REFRESH_SECS` | Cadencia de `GET /config` (por defecto 300). | +| `EVALUATOR_MAX_POLL_DURATION_SECS` | Tiempo máximo en tiempo real que una sesión puede permanecer en la cola de consultas antes de terminarse como `timeout` (por defecto 3600s). Protege contra un evaluador que mantiene devolviendo `pending` indefinidamente. | + +Para activar la puntuación automática en toda la instancia, aprovisiona el Secret de `agenteye-evaluator` con ambas claves definidas. En los manifiestos de Kubernetes incluidos, el servidor lee `EVALUATOR_ENDPOINT` y `EVALUATOR_TOKEN` desde este Secret opcional. Créalo mediante el proceso estándar de gestión de secrets de tu organización y reinicia el Deployment del servidor para aplicar el cambio. + +Los parámetros de ajuste anteriores no están configurados por defecto; expón las variables de entorno correspondientes en el contenedor del servidor en tu manifiesto de Deployment si necesitas sobrescribir los valores predeterminados. + +Consulta [deployment.md](/es/agenteye/deployment) para ver la tabla completa de variables de entorno. + +--- + +## Referencia de la API + +| Método | Ruta | Permiso requerido | Propósito | +|---|---|---|---| +| `GET` | `/evaluations` | `evaluations:read` | Consultar resultados terminales. Acepta `session_id`, `agent_id`, `environment`, `status` (`done`/`error`/`timeout`), `ts_from`, `ts_to`, `cursor`, `limit`, `score_filters`, `latest_per_session`. `limit` tiene un valor por defecto de 50 y está limitado a 200 (nota: esto difiere de `/events`, cuyo límite es 1000). `environment` acepta una lista separada por comas (p. ej. `environment=prod,staging`); los valores individuales también funcionan. Con `latest_per_session=true`, la respuesta contiene como máximo una fila por `session_id` (la más reciente por `completed_at`), utilizada por la página de lista de sesiones para colapsar la línea temporal de evaluaciones de una sesión a su encabezado actual. Por defecto es false (devuelve el historial completo). | +| `GET` | `/evaluations/aggregate` | `evaluations:read` | Estado de salud resumido de las evaluaciones para un subconjunto filtrado: recuento total, desglose done/error/timeout, estadísticas por clave de puntuación (count/avg/min/max/p50 sobre las claves arbitrarias de `scores`), y una línea temporal agrupada por tiempo. Acepta los **mismos parámetros de filtro que `/evaluations`** más `featured_keys` (CSV de claves de puntuación para tendencias) y `latest_per_session`. Impulsa la función de Dashboards; las métricas son exactas sobre todo el conjunto coincidente, no muestreadas. | +| `GET` | `/evaluations/environments` | `evaluations:read` | Valores de entorno distintos de la tabla `evaluations`. Se usa para rellenar los desplegables de filtro con alcance a datos legibles por evaluaciones. | +| `GET` | `/evaluation-jobs` | `evaluations:read` | Visibilidad sobre las evaluaciones en curso. Filtrar por `status` (`pending`/`polling`). | +| `GET` | `/events` | `events:read` | Transmitir los eventos sin procesar de una sesión. Acepta `session_id`, `agent_id`, `event_type` (CSV), `environment` (CSV), `ts_from`, `ts_to`, `cursor`, `limit` y `order`. `order` puede ser `desc` (más reciente primero, por defecto) o `asc` (más antiguo primero); un valor no reconocido recurre a `desc`. Pagina con cursor mediante el `next_cursor` de la respuesta (un id de evento): pásalo como `cursor` para obtener la siguiente página; con `asc` la siguiente página son los eventos posteriores a ese id, con `desc` los anteriores. `limit` tiene un valor por defecto de 50 y está limitado a 1000. | +| `GET` | `/sessions/:session_id/export` | `events:read` | Devuelve exactamente el cuerpo JSON que recibiría el evaluador para esta sesión, servido como archivo adjunto descargable llamado `session-.json`. Útil para reproducir sesiones de producción mediante `agenteye-evaluator` para pruebas sin conexión. Los bytes son idénticos byte a byte a lo que envía el pipeline del evaluador. | +| `POST` | `/sessions/:session_id/re-evaluate` | `evaluations:trigger` | Encolar una evaluación nueva para una sesión; se ejecuta independientemente de si existe una evaluación previa. El nuevo resultado se **añade** a la línea temporal de evaluaciones de la sesión en lugar de sobrescribir la anterior, de modo que las puntuaciones previas permanecen visibles como historial. Devuelve `202` al encolar, `404` para una sesión desconocida, `409` si ya hay una evaluación en curso. Úsalo tras desplegar un nuevo evaluador, o para sesiones que nunca emitieron `agent_end`. | + +### Filtrar por rango de puntuaciones: `score_filters` + +`GET /evaluations` acepta un parámetro opcional `score_filters` que restringe los resultados por valores numéricos dentro del objeto `scores`. El parámetro es una lista separada por comas de entradas `key:min..max`; cualquiera de los límites puede omitirse. Varias entradas se combinan con AND lógico. Las filas donde la clave indicada está ausente o no es numérica se excluyen. Una solicitud puede contener como máximo 20 entradas de filtro; superar ese número devuelve HTTP 400. + +Ejemplos: +```text +# helpfulness in [0.5, 0.8] +GET /evaluations?score_filters=helpfulness:0.5..0.8 + +# tool_efficiency at most 0.3 (no lower bound) +GET /evaluations?score_filters=tool_efficiency:..0.3 + +# helpfulness >= 0.5 AND factuality >= 0.9 +GET /evaluations?score_filters=helpfulness:0.5..,factuality:0.9.. +``` + +Cada objeto de respuesta de `/evaluations` tiene estos campos: + +| Campo | Tipo | Notas | +|---|---|---| +| `evaluation_id` | string (UUID) | El identificador canónico de esta evaluación terminal. Cada evaluación terminal obtiene un nuevo UUID; una única sesión puede tener múltiples. | +| `id` | string (UUID) | Alias de compatibilidad retroactiva que lleva el mismo valor que `evaluation_id`. | +| `session_id` | string | La sesión contra la que se ejecutó esta evaluación. Una sesión puede tener múltiples evaluaciones en la línea temporal. | +| `agent_id` | string | Identifica el agente que produjo la sesión. | +| `environment` | string | Etiqueta de entorno copiada de la sesión. | +| `status` | enum | Uno de `"done"`, `"error"`, `"timeout"`. | +| `scores` | object \| null | Puntuaciones devueltas por tu evaluador. | +| `reasoning` | object \| null | Mapa opcional de justificación por puntuación devuelto por tu evaluador. Las claves normalmente coinciden con las de `scores`. El panel muestra cada entrada debajo de su barra de puntuación. | +| `summary` | string \| null | Narrativa general opcional de un párrafo devuelta por tu evaluador. El panel la muestra encima del desglose por puntuación como el encabezado de la evaluación. | +| `error` | string \| null | Se rellena solo en caso de `"error"` / `"timeout"`. | +| `attempt_count` | integer | Número de intentos de despacho (≥ 1). | +| `duration_ms` | integer \| null | Duración del intento final. | +| `completed_at` | string (ISO 8601 UTC) | Cuándo se registró el resultado terminal. Los resultados se ordenan por `completed_at` (más reciente primero). | +| `created_at` | string (ISO 8601 UTC) | Lleva el mismo timestamp que `completed_at` (semántica de escritura única). | + +--- + +## Permisos + +| Permiso | Concede | +|---|---| +| `evaluations:read` | Listar resultados de evaluaciones, ver puntuaciones en el panel y cargar métricas de salud del panel. | +| `evaluations:trigger` | Encolar manualmente una evaluación para una sesión mediante `POST /sessions/:session_id/re-evaluate` o el botón de re-evaluar del panel. | +| `dashboards:read` | Ver dashboards guardados (también requiere `evaluations:read` para cargar sus métricas). | +| `dashboards:write` | Crear y editar dashboards. | +| `dashboards:delete` | Eliminar dashboards. | + +El administrador de arranque (`ADMIN_KEY`, `ADMIN_EMAIL`) recibe estos permisos automáticamente. + +--- + +## Visualizar resultados + +- **`/sessions/`**: línea temporal de eventos + un panel lateral derecho que muestra las puntuaciones de la sesión y cualquier error del intento de despacho. Si tu clave tiene `evaluations:trigger`, aparece un botón **re-evaluate** junto al botón de exportar, útil para sesiones que nunca emitieron `agent_end`, o para actualizar puntuaciones tras desplegar un nuevo evaluador. El panel consulta el nuevo resultado periódicamente y actualiza el panel lateral cuando está disponible. +- **`/sessions`**: cuadrícula de sesiones filtrable; la columna de puntuación muestra el estado de evaluación y las puntuaciones de cada sesión de un vistazo. +- **`/dashboards`**: vistas guardadas de salud de evaluaciones (consulta [Dashboards](#dashboards) más abajo). + +![La cuadrícula de Sessions con indicadores de estado de evaluación por sesión y distintivos de puntuación con código de color (helpfulness, factuality, tool_efficiency, safety, coherence)](/agenteye/images/sessions-list.png) + +*La cuadrícula de sesiones muestra el estado de evaluación y las puntuaciones de cada ejecución de un vistazo; los distintivos rojo/ámbar/verde hacen destacar las puntuaciones bajas.* + +![Una vista de detalle de sesión con las puntuaciones de evaluación y el estado de despacho en el panel lateral derecho](/agenteye/images/session-detail.png) + +*Al abrir una sesión se muestra su línea temporal completa junto con las puntuaciones de evaluación y cualquier error del dispatcher en el panel lateral.* + +--- + +## Dashboards + +La página **Dashboards** (`/dashboards`) te permite guardar una combinación de filtros de evaluación como una vista reutilizable con nombre y observar el estado de ese subconjunto de evaluaciones de un vistazo. Los dashboards se **comparten en toda tu organización**; todos los que tienen `dashboards:read` ven el mismo conjunto. + +Cada dashboard guarda: + +- **Filtros**: los mismos controles que la página de sesiones: entorno, estado, agente, una ventana de tiempo variable y filtros de rango de puntuaciones (`key:min..max`). +- **Una configuración de visualización**: qué claves de puntuación destacar, los umbrales de salud verde/ámbar/rojo, qué paneles mostrar y si colapsar a la evaluación más reciente por sesión. + +Cada tarjeta muestra el número de sesiones coincidentes, un desglose done/error/timeout, el promedio de cada puntuación destacada y un pequeño sparkline de tendencia. Abrir un dashboard muestra los paneles a tamaño completo; **"open in sessions"** te lleva a la página de sesiones pre-filtrada exactamente a ese subconjunto. Las métricas se calculan en el servidor sobre todo el conjunto coincidente (a través de `GET /evaluations/aggregate`), por lo que los números son exactos en lugar de muestreados. + +![Un dashboard de salud de evaluaciones con barras de puntuación media por dimensión del evaluador, un desglose ok/error de herramientas, las principales herramientas y una tendencia de eventos por hora](/agenteye/images/dashboard-quality.png) + +**Permisos:** la visualización requiere tanto `dashboards:read` como `evaluations:read`; crear y editar requiere `dashboards:write`; eliminar requiere `dashboards:delete`. El administrador de arranque recibe todos estos permisos automáticamente. + +--- + +## Solución de problemas + +**Existen sesiones pero no se crean evaluaciones.** Confirma que `EVALUATOR_ENDPOINT` está definido en el proceso del servidor, que el servidor y el evaluador comparten el mismo valor de `EVALUATOR_TOKEN`, y que el endpoint `/health` del evaluador es accesible desde el servidor. Con `EVALUATOR_ENDPOINT` sin definir, el pipeline es no operativo. + +**Se acumulan evaluaciones en curso.** Consulta `GET /evaluation-jobs` para ver la cola en curso. Inspecciona `attempt_count`, `next_attempt_at` y `last_error` en cada fila. Causas comunes: servicio evaluador inaccesible o devolviendo 5xx (se reintenta con retroceso exponencial), `EVALUATOR_TOKEN` incorrecto (el 401 es terminal), o un evaluador asíncrono que devuelve `pending` indefinidamente (ver más abajo). + +**Las sesiones se completaron pero no hay evaluación terminal.** Consulta `GET /evaluation-jobs?status=polling`; el resultado puede seguir en curso. Si un trabajo está atascado en `pending`, el servidor tiene problemas para llegar al evaluador; comprueba que el evaluador esté activo y que `EVALUATOR_TOKEN` coincida. + +**`HTTP 401 from evaluator: invalid bearer token`.** El `EVALUATOR_TOKEN` en el servidor no coincide con el valor con el que está configurado el servicio evaluador. Deben ser idénticos. + +**El evaluador asíncrono devuelve `pending` indefinidamente.** El servidor consulta `GET /evaluate/{job_id}` hasta que el evaluador devuelve `done` o `error`, o hasta que se agota `EVALUATOR_MAX_POLL_DURATION_SECS` (por defecto 1 h). Tras el límite, la evaluación se registra como `timeout` y se elimina de la cola en curso. Aumenta `EVALUATOR_MAX_POLL_DURATION_SECS` si tu evaluador legítimamente necesita más tiempo que el valor predeterminado. \ No newline at end of file diff --git a/docs/es/agenteye/getting-started.mdx b/docs/es/agenteye/getting-started.mdx new file mode 100644 index 00000000..ec45fd90 --- /dev/null +++ b/docs/es/agenteye/getting-started.mdx @@ -0,0 +1,235 @@ +--- +title: "Primeros pasos con AgentEye" +description: "Documentación de primeros pasos con AgentEye." +--- + + +Esta guía te lleva paso a paso por una configuración completa de AgentEye: despliegue del servidor y el panel de control, instalación del colector en una máquina de agente e instrumentación de tu código de agente Python. + +--- + +## ¿Qué es AgentEye? + +AgentEye es una **plataforma de observabilidad y evaluación autoalojada para agentes de IA**. Registra lo que hacen tus agentes — cada paso de una ejecución — y puntúa automáticamente la calidad de cada ejecución completada, para que puedas ver cómo se comportan tus agentes en producción y detectar regresiones antes de que las noten tus usuarios. + +Los datos fluyen en una sola dirección: tu código de agente emite **eventos** a través del **SDK de Python** → un daemon **colector** ligero los agrupa y los envía al **servidor** → los eventos y analíticas se almacenan en **ClickHouse** (el estado operacional, como organizaciones, usuarios, claves API, paneles de control y consultas guardadas, vive en **Postgres**) → tú exploras todo en el **panel de control**. + +Lo que obtienes: + +- **Eventos** — el rastro en bruto, paso a paso, de cada ejecución de agente (llamadas a herramientas, llamadas a modelos, hooks, errores). +- **Sesiones** — esos eventos agrupados en una fila por ejecución, cada una **evaluada y puntuada automáticamente**. +- **Evaluaciones** — puntuaciones de calidad producidas por tus propios servicios evaluadores, para que las caídas de calidad afloren sin revisión manual. +- **Consultas y paneles** — SQL de ClickHouse guardado sobre tus datos, representado en paneles compartidos con alcance de organización. +- **Alertas e incidentes** — reglas de umbral que te notifican (correo electrónico, Slack, webhook, en el panel) junto con un flujo de trabajo de gestión de incidentes. +- **CLI y asistente de IA** — un cliente de terminal (`agenteye`) y un asistente integrado en el panel para hacer preguntas en lenguaje natural. + +Puedes ejecutarlo todo en tu propia infraestructura: como una pila Docker Compose (esta guía), una instalación de Kubernetes para producción o un único pod colocalizado. El resto de esta guía configura la pila Compose de principio a fin. + +--- + +## Paso 1: Autenticarse + +Todos los artefactos de AgentEye se distribuyen desde la organización GitHub `agenteye-enterprise`. Como desarrollador empresarial, puedes generar tu propio PAT de GitHub. Consulta [enterprise-docs/github-token.md](/es/agenteye/github-token) para ver los pasos exactos y los permisos necesarios. + +```bash +export AGENTEYE_TOKEN= + +# Authenticate Docker against GHCR +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +--- + +## Paso 2: Desplegar el servidor y el panel de control + +El servidor recibe eventos de los colectores y los hace consultables; el panel de control es donde los exploras. Los eventos ingeridos y las analíticas viven en ClickHouse (el almacén de analíticas requerido), mientras que Postgres guarda el estado operacional, como organizaciones, usuarios, claves API, paneles de control y consultas guardadas. + +**Descarga el archivo compose publicado:** + +```bash +mkdir -p ./agenteye +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + https://raw.githubusercontent.com/agenteye-enterprise/releases/main/docker-compose.yml \ + -o ./agenteye/docker-compose.yml +cd agenteye +``` + +**Configura tus secretos:** + +Crea un archivo `.env` para que el despliegue no use la credencial predeterminada `admin`. Como mínimo, define `ADMIN_KEY` y `POSTGRES_PASSWORD`: + +```bash +POSTGRES_PASSWORD=your-db-password +ADMIN_KEY=your-admin-secret +``` + +También exporta `ADMIN_KEY` en tu shell actual para que los pasos siguientes (por ejemplo, el `curl` del Paso 3) puedan referenciarlo directamente: + +```bash +export ADMIN_KEY=your-admin-secret +``` + +**Inicia la pila:** + +```bash +docker compose up -d +``` + +Esto levanta la pila completa, incluyendo el almacén de analíticas ClickHouse requerido y una caché Redis opcional, junto con el servidor y el panel de control. ClickHouse debe estar operativo para que el servidor arranque. + +El servidor estará escuchando en `http://localhost:8080` y el panel de control en `http://localhost:3000`. + +Para despliegues en producción (Postgres personalizado, TLS, proxy inverso), consulta [enterprise-docs/deployment.md](/es/agenteye/deployment). + +--- + +## Paso 3: Crear una clave API para el colector + +Cada colector se autentica con una clave API con alcance específico. Usa el `ADMIN_KEY` que definiste en el Paso 2 para crear una: + +```bash +curl -s -X POST http://localhost:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{"name":"prod-collector","key":"your-collector-secret","permissions":["events:add"]}' +``` + +El valor de `key` lo proporcionas tú mismo; úsalo en la configuración del colector en el Paso 4. Consulta [enterprise-docs/api-keys.md](/es/agenteye/api-keys) para la gestión completa de claves. + +--- + +## Paso 4: Instalar el colector + +En cada máquina que ejecute tus agentes de IA, instala el daemon colector. + +**Descarga el binario (Linux x86_64):** + +```bash +VERSION=0.0.1-beta.13 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "collector/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-collector-linux-x86_64' +chmod +x agenteye-collector-linux-x86_64 +sudo mv agenteye-collector-linux-x86_64 /usr/local/bin/agenteye-collector +``` + +> Esto descarga la compilación para **Linux x86_64**. Para macOS (Apple Silicon o Intel), Linux arm64, o configuración con Docker, systemd o launchd, consulta [collector-installation.md](/es/agenteye/collector-installation), donde se lista la descarga para cada plataforma — el comando anterior instala un binario Linux que no funcionará en otros sistemas. + +**Configura:** + +```bash +mkdir -p ~/.agenteye +cat > ~/.agenteye/config.json </…`). + +- **Queries** (`//queries`): empieza desde una biblioteca de consultas guardadas y reutilizables sobre tus eventos y evaluaciones (tanto presets integrados como los tuyos propios)… + +![La biblioteca de consultas guardadas: una cuadrícula de consultas reutilizables, tanto presets integrados como personalizadas](/agenteye/images/queries.png) + + …luego abre una en el compositor SQL para ajustarla y ejecutarla con resultados en tiempo real: + +![El compositor de consultas SQL ejecutando una consulta guardada, con una barra lateral de esquema y una cuadrícula de resultados en tiempo real](/agenteye/images/query-lab.png) + +- **Dashboards** (`//dashboards`): ancla consultas como mosaicos de línea, barra, área o tarta en paneles compartidos con alcance de organización. + +![Un panel construido a partir de consultas guardadas: una línea de eventos por hora, una barra de errores por tipo, un gráfico de área de latencia y tokens por modelo](/agenteye/images/dashboard-fleet.png) + +- **Alerts** (`//alerts`): convierte cualquier umbral en una regla de notificación que avisa por correo electrónico, Slack, webhook o en el panel. Consulta [enterprise-docs/alerts.md](/es/agenteye/alerts). + +--- + +## Próximos pasos + +- [Despliegue](/es/agenteye/deployment): refuerza para producción +- [Claves API](/es/agenteye/api-keys): gestiona el acceso +- [Solución de problemas](/es/agenteye/troubleshooting): diagnostica incidencias \ No newline at end of file diff --git a/docs/es/agenteye/github-token.mdx b/docs/es/agenteye/github-token.mdx new file mode 100644 index 00000000..1ff47376 --- /dev/null +++ b/docs/es/agenteye/github-token.mdx @@ -0,0 +1,131 @@ +--- +title: "Configuración del Token de GitHub" +description: "Documentación de configuración del Token de GitHub para AgentEye." +--- + +Un Token de Acceso Personal (PAT) de GitHub es la única credencial que desbloquea todos los artefactos de AgentEye. Con un solo token puedes descargar las imágenes Docker, los binarios de las versiones publicadas y los paquetes Python, sin necesidad de iniciar sesión por componente ni de compartir secretos. Todos los artefactos de AgentEye se distribuyen desde la organización `agenteye-enterprise` en GitHub; una vez que se otorga acceso a tu organización, cada desarrollador u operador genera y rota su propio token, lo que mantiene el acceso auditable y revocable por persona. + +Configura el token como variable de entorno y credencial de Docker una vez por máquina: + +```bash +export AGENTEYE_TOKEN= +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +> **Nota sobre el nombre de usuario:** GHCR ignora el nombre de usuario en `docker login` y se autentica exclusivamente mediante el token, por lo que cualquier valor no vacío funciona. En esta documentación se usa `-u x` por brevedad; los manifiestos de despliegue que crean un secreto de extracción de imágenes en Kubernetes pueden utilizar un nombre de usuario más descriptivo, como `agenteye-enterprise`. Ambos son válidos. + +--- + +## Opción A: Token Clásico (Recomendado) + +Un token clásico es la opción más fiable para AgentEye, ya que el flujo de `docker login` e imagen de GHCR tiene el soporte más amplio y consistente para tokens clásicos. Dos alcances cubren todo lo que necesitas (extraer imágenes y descargar artefactos de versiones), de modo que te autenticas una vez y continúas sin tener que resolver problemas del registro. Uno de ellos, `read:packages`, es genuinamente de solo lectura; el otro, `repo`, es el único alcance clásico que concede acceso a artefactos de versiones privadas, y es deliberadamente amplio — GitHub lo define como control total (lectura y escritura) de repositorios privados. + +### 1. Crear el token + +Ve a **GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic) → Generate new token (classic)**. + +| Campo | Valor | +|---|---| +| **Note** | `agenteye-` (p. ej. `agenteye-prod-server`) | +| **Expiration** | Define un vencimiento acorde a tu política de seguridad; 90 días es un valor predeterminado razonable | + +> **Nota sobre la etiqueta:** GitHub denomina este campo **Note** en los tokens clásicos y **Token name** en los tokens de grano fino. Cumplen el mismo propósito: un identificador legible para auditorías y revocaciones posteriores. + +### 2. Seleccionar los alcances + +| Alcance | Por qué es necesario | +|---|---| +| `read:packages` | Extraer imágenes Docker de `ghcr.io/agenteye-enterprise/` y descargar artefactos de paquetes | +| `repo` | Leer contenidos de repositorios privados, archivos sin procesar y artefactos de versiones de `agenteye-enterprise/releases`. Este es el alcance de GitHub definido como "Control total de repositorios privados" (lectura y escritura), no de solo lectura — es simplemente el único alcance clásico que concede acceso a artefactos de versiones privadas | + +No se requieren otros alcances. + +### 3. Generar y copiar el token + +Haz clic en **Generate token** y copia el valor de inmediato; solo se muestra una vez. Guárdalo en tu gestor de secretos o en tu entorno. + +--- + +## Opción B: Token de Grano Fino + +Los tokens de grano fino limitan el acceso a repositorios y permisos específicos, lo que los convierte en la opción de mínimo privilegio más restrictiva. Elige esta ruta cuando la política de seguridad de tu organización exija tokens de grano fino. + +> **Nota:** El soporte de GHCR para tokens de grano fino es menos consistente que para los tokens clásicos. Si `docker login` o `docker pull` falla después de seguir estos pasos, recurre a un token clásico (Opción A). + +### 1. Crear el token + +Ve a **GitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokens → Generate new token**. + +| Campo | Valor | +|---|---| +| **Token name** | `agenteye-` (p. ej. `agenteye-prod-server`) | +| **Expiration** | Define un vencimiento acorde a tu política de seguridad; 90 días es un valor predeterminado razonable | +| **Resource owner** | `agenteye-enterprise` | +| **Repository access** | **Only select repositories** → `agenteye-enterprise/releases` | + +### 2. Configurar los permisos del repositorio + +En **Permissions → Repository permissions**, establece: + +| Permiso | Acceso | +|---|---| +| **Contents** | Read-only | +| **Packages** | Read-only | + +Todos los demás permisos pueden dejarse en **No access**. + +> **Nota:** Si las imágenes de contenedor (`ghcr.io/agenteye-enterprise/...`) se publican como paquetes a nivel de organización en lugar de paquetes vinculados a un repositorio, el inicio de sesión de Docker puede fallar únicamente con permisos de alcance de repositorio. En ese caso, agrega un permiso a nivel de organización: **Permissions → Organization permissions → Packages: Read-only**. + +### 3. Qué concede cada permiso + +| Permiso | Utilizado para | +|---|---| +| Contents: Read-only | Descargar `docker-compose.yml`, binarios de versiones y paquetes Python de `agenteye-enterprise/releases` | +| Packages: Read-only | Extraer imágenes Docker de `ghcr.io/agenteye-enterprise/` | + +### 4. Generar y copiar el token + +Haz clic en **Generate token** y copia el valor de inmediato; solo se muestra una vez. Guárdalo en tu gestor de secretos o en tu entorno. + +--- + +## Rotación de un Token + +Rotar los tokens de forma periódica mantiene el acceso auditable y limita el impacto en caso de que una credencial se filtre. Los tokens también pueden expirar o revocarse en cualquier momento, por lo que la rotación es la forma habitual de mantenerse autenticado. Para rotar: + +1. Genera un nuevo token siguiendo los pasos anteriores. +2. Actualiza `AGENTEYE_TOKEN` en tu entorno o gestor de secretos. +3. Vuelve a autenticar Docker: `echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin` +4. Revoca el token anterior en GitHub → Settings → Developer settings → Personal access tokens, abre la subpágina **Tokens (classic)** o **Fine-grained tokens** según el tipo de token y elimínalo. + +--- + +## Verificar tu Token + +Confirma que el token funciona antes de integrarlo en un despliegue, de modo que los errores de autenticación aparezcan aquí y no a mitad de una puesta en producción. Cada comando ejercita uno de los alcances anteriores: + +```bash +# Packages scope - authenticate Docker against GHCR +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin + +# Contents scope - fetch a raw release file +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + https://raw.githubusercontent.com/agenteye-enterprise/releases/main/docker-compose.yml \ + -o /tmp/agenteye-compose-check.yml +``` + +Un `docker login` exitoso confirma el alcance de paquetes; un archivo descargado correctamente confirma el alcance de contenidos. + +--- + +## Solución de Problemas + +| Síntoma | Causa probable | Solución | +|---|---|---| +| `docker login` devuelve 401 | Token sin `Packages: Read-only` (grano fino) o `read:packages` (clásico) | Agrega el alcance de paquetes y regenera el token | +| `curl` devuelve 404 en URLs de GitHub sin procesar | Token sin `Contents: Read-only` o alcance `repo` | Agrega el alcance de contenidos y regenera el token | +| `gh release download` devuelve 403 | Token no autorizado para `agenteye-enterprise/releases` | Verifica que el repositorio esté incluido en el acceso del token de grano fino, o usa un token clásico con alcance `repo` | +| Token aceptado pero no se encuentran las imágenes | Falta el permiso de paquetes a nivel de organización en el token de grano fino | Agrega el permiso de organización `Packages: Read-only` | + +Para problemas de acceso, contacta a `support@exosphere.host`. \ No newline at end of file diff --git a/docs/es/agenteye/health-monitoring.mdx b/docs/es/agenteye/health-monitoring.mdx new file mode 100644 index 00000000..cff93de6 --- /dev/null +++ b/docs/es/agenteye/health-monitoring.mdx @@ -0,0 +1,124 @@ +--- +title: "Monitoreo de Salud" +description: "Documentación de Monitoreo de Salud de AgentEye." +--- + +Detecta cuándo un despliegue de AgentEye está **caído o degradado**, no solo cuando +tus agentes se comportan de forma incorrecta. La detección es **nativa de Kubernetes** y, de manera crucial, +**independiente de AgentEye**: lee el estado de los pods desde el plano de control de Kubernetes +y verifica las dependencias esenciales de AgentEye, por lo que sigue funcionando cuando el servidor, +ClickHouse o Postgres es lo que está caído. + +Hay dos capas. La primera está integrada; la segunda es opcional. + +## 1. Preparación con conciencia de dependencias (integrada) + +El servidor expone dos endpoints de sonda con funciones deliberadamente distintas: + +| Endpoint | Sonda | Verifica | Autenticación | +|---|---|---|---| +| `GET /health` | liveness | el proceso está vivo (siempre `{"status":"ok"}`) | ninguna | +| `GET /ready` | readiness | puede servir realmente: **Postgres + ClickHouse** accesibles | ninguna | + +`/ready` devuelve `200` con `"status":"ready"` y cada verificación en `"ok"` cuando ambas +dependencias esenciales son accesibles, y `503` con `"status":"not_ready"` cuando +alguna no lo es. Ambas respuestas incluyen un pequeño cuerpo: + +```json +{ "status": "not_ready", + "checks": { "postgres": "ok", "clickhouse": "down", "redis": "not_configured" } } +``` + +Redis es una caché opcional que el servidor puede omitir sin problemas, por lo que se reporta a +modo informativo pero **nunca** hace fallar el readiness. Muestra `"ok"` cuando hay una caché +configurada y `"not_configured"` en caso contrario; nunca aparece como `"down"`. + +En los manifiestos de Kubernetes incluidos, la sonda de **readiness** apunta a `/ready` +y la de **liveness** permanece en `/health`. El efecto: un servidor que está *en ejecución pero +no puede alcanzar su base de datos* se retira del Service y aparece como `NotReady`, +un estado sobre el que el monitoreo de tu clúster (descrito más adelante) puede generar alertas, +mientras que el liveness se mantiene liviano para que un breve problema de dependencia +nunca provoque el reinicio de un pod. La sonda usa un umbral de fallo generoso para que +un problema momentáneo no cause que las réplicas entren y salgan de rotación. + +## 2. Alertas de fallos de pods con Robusta (opcional) + +[Robusta](https://github.com/robusta-dev/robusta) es un monitor nativo de Kubernetes +que observa el servidor de API y envía fallos de pods (`CrashLoopBackOff`, +`OOMKilled`, `ImagePullBackOff`, `Pending`/`NotReady`, `Failed`, desalojos) a +Slack. Como observa el plano de control en lugar de consultar a AgentEye, genera alertas +incluso cuando AgentEye no puede responder en absoluto. + +Robusta se incluye como complemento opcional en el paquete de lanzamiento. Actívalo con el +chart Helm estándar de Robusta y el pequeño archivo de valores que se muestra a continuación: + +1. Agrega el repositorio del chart y obtén un **bot token** de Slack (`xoxb-…`) para el canal: + + ```bash + helm repo add robusta https://robusta-charts.storage.googleapis.com + helm repo update + ``` + + Dado que la configuración siguiente mantiene todo dentro del clúster + (`disableCloudRouting: true`), el token proviene de una aplicación de Slack autoalojada: + crea una aplicación en `https://api.slack.com/apps`, agrega el alcance de bot `chat:write`, + instálala en tu espacio de trabajo, copia el **Bot User OAuth Token** (`xoxb-…`) e + invita al bot al canal (`/invite @your-app`). + +2. Crea un `values.yaml` con una etiqueta por despliegue (`clusterName`) y tu + canal de Slack, limitado al namespace `agenteye`: + + ```yaml + clusterName: "acme-prod" # etiqueta por despliegue; aparece en cada alerta + enablePrometheusStack: false # solo alertas de caída de pods; sin stack de métricas + disableCloudRouting: true # enviar a Slack directamente, dentro del clúster + sinksConfig: + - slack_sink: + name: vendor_slack + slack_channel: "agenteye-fleet-health" + api_key: "REPLACE_WITH_SLACK_BOT_TOKEN" # xoxb-… (preferir --set o un secret) + scope: + include: + - namespace: [agenteye] # solo alertas del namespace AgentEye; eliminar para ampliar + ``` + +3. Instala fijando `--version` a una versión conocida y estable del chart de Robusta + ([versiones](https://github.com/robusta-dev/robusta/releases)) para nunca instalar + un chart sin probar: + + ```bash + helm install robusta robusta/robusta \ + --namespace robusta --create-namespace \ + --version \ + -f values.yaml \ + --set sinksConfig[0].slack_sink.api_key=$ROBUSTA_SLACK_TOKEN + ``` + +### Qué reporta + +- El **estado de los pods** de Kubernetes (qué pod de AgentEye está fallando y por qué) y el + **tag de imagen** de cada pod, es decir, la **versión** del componente en ejecución. +- **Ningún dato de eventos de AgentEye ni dato de clientes** sale jamás del clúster. +- Los valores incluidos restringen las alertas al **namespace `agenteye`**, por lo que las + cargas de trabajo no relacionadas en el mismo clúster no se reportan. + +### Un único lugar para cada despliegue + +Apunta el Robusta de cada despliegue a **un canal de Slack compartido**, cada uno con su +propio `clusterName`. Cada alerta se etiqueta con ese valor, de modo que un solo canal +muestra el estado de toda tu flota y puedes identificar de un vistazo qué despliegue +está afectado. + +### Interrupciones totales del clúster + +Un observador puramente interno al clúster no puede reportar una **interrupción total del clúster +o de la red** (cae junto con el clúster). Si necesitas eso, habilita el **sink de la UI de Robusta** +opcional: establece `disableCloudRouting: false` y agrega un `robusta_sink` (con un +token obtenido de `robusta gen-config`) a `sinksConfig`. Esto añade un panel de control +agregado multiclúster y marca cualquier clúster que deje de registrarse. + +## Solución de problemas + +Consulta la sección **Health Monitoring** de +[enterprise-docs/troubleshooting.md](/es/agenteye/troubleshooting) para los casos de +"no llegan alertas" y "el servidor sigue alternando entre `NotReady`". \ No newline at end of file diff --git a/docs/es/agenteye/kubernetes-deployment.mdx b/docs/es/agenteye/kubernetes-deployment.mdx new file mode 100644 index 00000000..8647dac4 --- /dev/null +++ b/docs/es/agenteye/kubernetes-deployment.mdx @@ -0,0 +1,1084 @@ +--- +title: "Guía de Despliegue en Kubernetes" +description: "Documentación de la guía de despliegue de AgentEye en Kubernetes." +--- + + +Esta guía despliega el stack completo de AgentEye en un clúster de Kubernetes dedicado: + +- **ClickHouse 24.8** -- almacén canónico de análisis de eventos y evaluaciones (StatefulSet con volumen persistente de 100 Gi). Obligatorio: el servidor no arranca sin él. +- **PostgreSQL 16** -- almacén relacional/de metadatos para organizaciones, claves de API, usuarios, paneles, consultas guardadas y autenticación (StatefulSet con volumen persistente de 50 Gi) +- **Redis 7.2** -- caché compartida opcional y backend de límite de tasa; el servidor y el panel degradan con elegancia si no está disponible +- **AgentEye Server** -- API en Rust para ingestión de eventos, análisis y gestión de claves (2 réplicas) +- **AgentEye Dashboard** -- interfaz web en Next.js (2 réplicas) +- **AI assistant (servicio de agente)** -- asistente opcional de solo lectura en el panel en el puerto 9100; inactivo hasta que se configure un endpoint de LLM +- **Traefik (público)** -- controlador de ingreso para el tráfico del colector, protegido con mTLS +- **Traefik (panel)** -- controlador de ingreso para el panel, solo accesible desde VPN/lista de IPs permitidas +- **cert-manager** -- certificados TLS y CA de mTLS +- **Backup CronJob** -- volcado diario combinado de PostgreSQL + ClickHouse a las 03:00 UTC +- **Cert Renewal Monitor** -- alerta cuando los certificados de cliente están próximos a caducar + +**Tiempo estimado:** 60--90 minutos para un primer despliegue. + +Para el modelo de despliegue gestionado donde Exosphere se encarga de todo esto en tu nombre, consulta [enterprise-docs/managed-deployment.md](/es/agenteye/managed-deployment). + +--- + +## Requisitos previos + +Ejecuta cada comando de verificación antes de comenzar. Todas las comprobaciones deben pasar. + +| Requisito | Mínimo | Comando de verificación | Resultado esperado | +|---|---|---|---| +| Clúster de Kubernetes | 1.27+ | `kubectl version` | Server Version >= v1.27 | +| Kustomize (incluido con kubectl) | Kustomize v1.14+ (incluido en kubectl 1.27+) | `kubectl kustomize --help` | Muestra texto de uso | +| Helm | v3 | `helm version` | `Version:"v3.x.x"` | +| cluster-admin RBAC | -- | `kubectl auth can-i create namespaces` | `yes` | +| StorageClass por defecto | -- | `kubectl get storageclass` | Al menos una fila marcada como `(default)` | +| Soporte de LoadBalancer | -- | Depende del proveedor (EKS, GKE, AKS lo soportan por defecto) | -- | +| GitHub PAT | -- | `echo $AGENTEYE_TOKEN` | No vacío (ver [enterprise-docs/github-token.md](/es/agenteye/github-token)) | +| openssl | -- | `openssl version` | OpenSSL 1.x o 3.x | +| Bucket de almacenamiento en la nube | -- | Para copias de seguridad de PostgreSQL + ClickHouse (S3, GCS o Azure Blob) | -- | + +**Dimensionamiento del clúster:** Mínimo 3 nodos, 4 vCPU / 8 GB de RAM cada uno. Consulta [enterprise-docs/managed-deployment.md](/es/agenteye/managed-deployment) para los requisitos completos. + +### Ejecutar todas las comprobaciones a la vez + +```bash +echo "--- Prerequisites Check ---" +kubectl version --client -o yaml 2>/dev/null | grep -q gitVersion && echo "PASS: kubectl" || echo "FAIL: kubectl not found" +helm version --short 2>/dev/null | grep -q v3 && echo "PASS: helm v3" || echo "FAIL: helm v3 not found" +kubectl auth can-i create namespaces 2>/dev/null | grep -q yes && echo "PASS: cluster-admin" || echo "FAIL: no cluster-admin" +kubectl get storageclass 2>/dev/null | grep -q default && echo "PASS: default StorageClass" || echo "FAIL: no default StorageClass" +[ -n "$AGENTEYE_TOKEN" ] && echo "PASS: AGENTEYE_TOKEN set" || echo "FAIL: AGENTEYE_TOKEN not set" +openssl version >/dev/null 2>&1 && echo "PASS: openssl" || echo "FAIL: openssl not found" +echo "---" +``` + +### Estructura del despliegue + +El **endpoint de ingestión** se sirve en un nombre de host que controlas (por ejemplo, `ingest.tu-empresa.example`). cert-manager solicita un certificado TLS de confianza pública a Let's Encrypt mediante HTTP-01, de modo que los colectores verifican el certificado del servidor contra el almacén de confianza del sistema, sin necesidad de anclar una CA por cliente. + +El **endpoint del panel** funciona de la misma manera: se sirve en un segundo nombre de host que controlas (por ejemplo, `agenteye.tu-empresa.example`) apuntando al LoadBalancer de Traefik del panel, y cert-manager emite su certificado Let's Encrypt a través de ese LoadBalancer. Los navegadores obtienen un certificado de confianza sin advertencias. + +> **La emisión y renovación de certificados se validan mediante HTTP-01**, por lo que ambos LoadBalancers deben ser accesibles desde internet en el puerto 80. Si necesitas restringir el LoadBalancer del panel por IP, coordina primero con soporte un solver DNS-01, de lo contrario las renovaciones fallarán silenciosamente y el certificado caducará. + +--- + +## Obtener los manifiestos + +```bash +git clone https://x:${AGENTEYE_TOKEN}@github.com/agenteye-enterprise/releases.git +cd releases/deploy +``` + +**Verificación:** + +```bash +ls base/kustomization.yaml +``` + +Resultado esperado: el archivo existe. Si no existe, la clonación ha fallado -- verifica tu `AGENTEYE_TOKEN`. + +**Estructura de directorios:** + +``` +deploy/ + base/ Base compartida de Kustomize (todos los recursos K8s) + overlays/ Sobreescrituras específicas del clúster (etiquetas de imagen, nombres de host, recursos) + third-party/ Valores de Helm para Traefik, cert-manager y (opcional) monitorización de salud con Robusta +``` + +La **base** contiene todos los recursos necesarios para un despliegue completo, incluidos los certificados Let's Encrypt para los dos nombres de host públicos que configuras en la Fase 3.1. Un **overlay** parchea la base para un entorno específico (por ejemplo, etiquetas de imagen personalizadas, límites de recursos, variables de entorno). El directorio **third-party** contiene archivos de valores de Helm para infraestructura externa. + +> **Monitorización de salud (opcional):** la sonda de disponibilidad del servidor ya refleja el estado de Postgres + ClickHouse, y `third-party/robusta/` añade alertas opcionales de fallo de pod en Kubernetes nativas a Slack. Consulta [enterprise-docs/health-monitoring.md](/es/agenteye/health-monitoring). + +--- + +## Fase 1 -- Infraestructura de terceros (~30 min) + +### 1.1 Instalar cert-manager + +cert-manager gestiona los certificados TLS para HTTPS y la CA privada utilizada para los certificados de cliente mTLS. + +```bash +helm repo add jetstack https://charts.jetstack.io +helm repo update + +helm install cert-manager jetstack/cert-manager \ + --namespace cert-manager --create-namespace \ + --set crds.install=true +``` + +**Verificación:** + +```bash +kubectl get pods -n cert-manager +``` + +Resultado esperado: 3 pods en estado `Running` -- `cert-manager`, `cert-manager-cainjector`, `cert-manager-webhook`. + +```bash +kubectl get crds | grep cert-manager +``` + +Resultado esperado: al menos `certificates.cert-manager.io`, `clusterissuers.cert-manager.io`, `issuers.cert-manager.io`. + +**Si falla:** Los pods en `CrashLoopBackOff` normalmente indican que los CRDs no se instalaron. Vuelve a ejecutar con `--set crds.install=true`. Si los pods del webhook fallan en la verificación de disponibilidad, espera 30 segundos y vuelve a comprobar -- pueden tardar un momento en arrancar. + +--- + +### 1.2 Instalar Traefik -- Controlador de ingestión público + +Esta instancia de Traefik gestiona el tráfico del colector en un LoadBalancer **externo**. Termina TLS y aplica mTLS (verificación de certificado de cliente) en el endpoint de ingestión. + +```bash +helm repo add traefik https://traefik.github.io/charts +helm repo update + +helm install traefik-public traefik/traefik \ + --namespace traefik-public --create-namespace \ + --version 39.0.8 \ + -f third-party/traefik/values-public.yaml +``` + +**Verificación:** + +```bash +kubectl get pods -n traefik-public +``` + +Resultado esperado: 1 pod en estado `Running`. + +```bash +kubectl get ingressclass traefik-public +``` + +Resultado esperado: la IngressClass existe (no es la clase por defecto). + +**Si falla:** Comprueba `kubectl describe pod -n traefik-public ` para errores de descarga de imagen o restricciones de recursos. + +--- + +### 1.3 Instalar Traefik -- Controlador del panel + +Esta instancia de Traefik sirve el panel en un LoadBalancer dedicado, restringido por lista de IPs permitidas. + +> **Esta instancia incluye dos mecanismos de lista de permitidos.** Esta guía utiliza `values-dashboard.yaml`, que restringe el acceso con el campo portable `service.loadBalancerSourceRanges`. También se proporciona un `values-internal.yaml` paralelo para entornos AWS que prefieren la anotación `service.beta.kubernetes.io/aws-load-balancer-source-ranges`. Elige uno y úsalo de forma consistente; los pasos siguientes asumen `values-dashboard.yaml`. + +**Antes de instalar**, edita `third-party/traefik/values-dashboard.yaml` para establecer las IPs de origen permitidas. El campo `loadBalancerSourceRanges` controla qué IPs pueden acceder al panel. Por defecto está configurado como `0.0.0.0/0` (todas las IPs); restrínguelo a tu VPN, oficina o IPs de salida conocidas. + +#### Permitir una sola IP + +```yaml +service: + loadBalancerSourceRanges: + - "/32" +``` + +#### Permitir múltiples IPs + +Añade una entrada por IP o bloque CIDR. Un sufijo `/32` coincide con una sola dirección IPv4; un bloque CIDR (por ejemplo, `/24`) coincide con un rango. Puedes mezclar IPs individuales y rangos libremente: + +```yaml +service: + loadBalancerSourceRanges: + - "203.0.113.10/32" # puerta de enlace de la oficina + - "203.0.113.11/32" # puerta de enlace de oficina de respaldo + - "198.51.100.0/24" # pool de VPN + - "192.0.2.50/32" # IP doméstica del ingeniero de guardia +``` + +Consejos para mantener la lista: + +- Mantén una entrada por línea y añade un comentario `#` breve que identifique el propietario o propósito de cada IP; esto es lo que los futuros operadores usarán para decidir si una entrada sigue siendo necesaria. +- Usa siempre notación CIDR. Una IP sin sufijo como `203.0.113.10` es rechazada por el proveedor de nube; usa `203.0.113.10/32`. +- Para rangos IPv6, usa el equivalente `/128` (dirección única) o un CIDR mayor, por ejemplo `2001:db8::1/128`. No todos los proveedores de nube admiten rangos de origen IPv6; consulta la documentación de LoadBalancer de tu proveedor. +- La lista es un **OR**: el tráfico se permite si el origen coincide con cualquier entrada. + +Después de editar el archivo, procede con `helm install` a continuación. Si el controlador ya está instalado, ejecuta `helm upgrade` con las mismas opciones, o parchea el Service en tiempo de ejecución (sección siguiente). + +#### Actualizar la lista de permitidos en tiempo de ejecución + +Puedes cambiar las IPs permitidas sin actualizar Helm parcheando el Service directamente. **El parche reemplaza la lista completa**; incluye siempre todas las IPs que quieras conservar, no solo la nueva. + +Para reemplazar la lista con un nuevo conjunto de IPs: + +```bash +kubectl patch svc traefik-dashboard -n traefik-dashboard \ + -p '{"spec":{"loadBalancerSourceRanges":["203.0.113.10/32","198.51.100.0/24","192.0.2.50/32"]}}' +``` + +Para **añadir** una IP de forma segura sin perder las entradas existentes, lee primero la lista actual y luego aplica el parche con el conjunto combinado: + +```bash +# 1. Muestra la lista de permitidos actual +kubectl get svc traefik-dashboard -n traefik-dashboard \ + -o jsonpath='{.spec.loadBalancerSourceRanges}' + +# 2. Aplica el parche con la lista completa incluyendo la nueva IP +kubectl patch svc traefik-dashboard -n traefik-dashboard \ + -p '{"spec":{"loadBalancerSourceRanges":["/32","/32","/32"]}}' +``` + +> Los parches en tiempo de ejecución no se persisten en `values-dashboard.yaml`. Para mantener el cambio en futuras actualizaciones de Helm, actualiza también el archivo de valores y confírmalo en el repositorio. + +Luego instala: + +```bash +helm install traefik-dashboard traefik/traefik \ + --namespace traefik-dashboard --create-namespace \ + --version 39.0.8 \ + -f third-party/traefik/values-dashboard.yaml +``` + +**Verificación:** + +```bash +kubectl get pods -n traefik-dashboard +``` + +Resultado esperado: 1 pod en estado `Running`. + +```bash +kubectl get ingressclass traefik-dashboard +``` + +Resultado esperado: la IngressClass existe. + +--- + +### 1.4 Esperar a los LoadBalancers + +Ambas instancias de Traefik necesitan IPs externas antes de continuar. + +```bash +kubectl get svc -n traefik-public +kubectl get svc -n traefik-dashboard +``` + +**Verificación:** Ambos servicios muestran un `EXTERNAL-IP` (no ``). + +Si aún están pendientes, espera a que se asigne: + +```bash +kubectl get svc -n traefik-public -w +``` + +Pulsa `Ctrl+C` cuando aparezca la IP. La asignación de IP suele tardar entre 2 y 5 minutos. + +**Si falla:** `` después de 10 minutos normalmente significa que el proveedor de nube no puede aprovisionar un LoadBalancer. Comprueba: etiquetas de subred (EKS requiere `kubernetes.io/role/elb`), configuración de VPC, cuotas de servicio y que la anotación correcta del LB interno esté configurada para la instancia interna. + +--- + +## Fase 2 -- Crear secretos (~10 min) + +Todos los secretos se crean manualmente antes de desplegar la aplicación. Esto garantiza que los valores sensibles nunca aparezcan en los archivos de manifiesto. + +### 2.1 Crear el namespace + +```bash +kubectl create namespace agenteye +``` + +**Verificación:** + +```bash +kubectl get namespace agenteye +``` + +Resultado esperado: estado `Active`. + +--- + +### 2.2 Secreto de extracción de imagen + +Este secreto autentica con `ghcr.io` para extraer las imágenes de contenedor de AgentEye. Consulta [enterprise-docs/github-token.md](/es/agenteye/github-token) para saber cómo generar tu PAT. + +```bash +kubectl create secret docker-registry agenteye-image-pull \ + --namespace agenteye \ + --docker-server=ghcr.io \ + --docker-username=agenteye-enterprise \ + --docker-password="${AGENTEYE_TOKEN}" +``` + +**Verificación:** + +```bash +kubectl get secret agenteye-image-pull -n agenteye -o jsonpath='{.type}' +``` + +Resultado esperado: `kubernetes.io/dockerconfigjson`. + +**Verificación profunda** -- comprueba que el token puede extraer imágenes realmente: + +Usa la etiqueta de imagen `server` fijada en el `kustomization.yaml` de tu overlay (actualmente `v0.0.1-beta.48` tanto en el overlay `acme` incluido como en el despliegue base). Sustituye la etiqueta en el comando siguiente por la que estés desplegando para que esta comprobación no quede desactualizada entre versiones: + +```bash +kubectl run test-pull \ + --image=ghcr.io/agenteye-enterprise/server:v0.0.1-beta.48 \ + --overrides='{"spec":{"imagePullSecrets":[{"name":"agenteye-image-pull"}]}}' \ + --restart=Never -n agenteye --command -- echo ok + +# Espera unos segundos para la descarga y luego: +kubectl logs test-pull -n agenteye +kubectl delete pod test-pull -n agenteye +``` + +Resultado esperado: `ok` impreso en los logs. + +**Si falla:** `ErrImagePull` o `401 Unauthorized` significa que el PAT no es válido o no tiene el permiso `read:packages`. Revisa [enterprise-docs/github-token.md](/es/agenteye/github-token). + +--- + +### 2.3 Credenciales de PostgreSQL + +```bash +POSTGRES_PASSWORD=$(openssl rand -hex 24) + +kubectl create secret generic agenteye-postgres \ + --namespace agenteye \ + --from-literal=POSTGRES_USER=postgres \ + --from-literal=POSTGRES_PASSWORD="${POSTGRES_PASSWORD}" \ + --from-literal=POSTGRES_DB=agenteye +``` + +> **Importante:** Usamos `-hex` (no `-base64`) para generar la contraseña. La salida en base64 puede contener `+`, `/` y `=`, que rompen la cadena de conexión `DATABASE_URL`. Consulta [enterprise-docs/troubleshooting.md](/es/agenteye/troubleshooting) para más detalles. + +> **Guarda `POSTGRES_PASSWORD` en tu gestor de secretos inmediatamente.** La necesitarás si alguna vez restauras desde una copia de seguridad o te conectas directamente a la base de datos. + +**Verificación:** + +```bash +kubectl get secret agenteye-postgres -n agenteye +``` + +Resultado esperado: el secreto existe. + +```bash +kubectl get secret agenteye-postgres -n agenteye \ + -o jsonpath='{.data.POSTGRES_PASSWORD}' | base64 -d | wc -c +``` + +Resultado esperado: `48` (24 bytes hexadecimales = 48 caracteres). + +--- + +### 2.4 Clave de API de administrador + +```bash +ADMIN_KEY=$(openssl rand -hex 32) + +kubectl create secret generic agenteye-admin-key \ + --namespace agenteye \ + --from-literal=ADMIN_KEY="${ADMIN_KEY}" +``` + +La clave de administrador es la credencial de arranque inicial. El servidor la inserta o actualiza en cada inicio con todos los permisos. Úsala para crear claves de colector con permisos restringidos en la Fase 7. Consulta [enterprise-docs/api-keys.md](/es/agenteye/api-keys) para el modelo completo de permisos. + +> **Guarda `ADMIN_KEY` en tu gestor de secretos inmediatamente.** + +**Verificación:** + +```bash +kubectl get secret agenteye-admin-key -n agenteye +``` + +Resultado esperado: el secreto existe. + +--- + +### 2.5 Configuración de autenticación (inicio de sesión en el panel) + +El panel utiliza email + OTP para el inicio de sesión de usuarios. Sin este secreto, el servidor sigue arrancando y la ruta de API de `ADMIN_KEY` sigue funcionando, pero **ningún usuario puede iniciar sesión a través de la interfaz de usuario**. + +Todas las claves están referenciadas como `optional: true` en el manifiesto base, por lo que los secretos parciales (o ningún secreto) son válidos; el servidor recurre a los valores predeterminados documentados. Agrupar todo en un único secreto `agenteye-auth` permite rotar toda la superficie de autenticación en un solo lugar. + +```bash +kubectl create secret generic agenteye-auth \ + --namespace agenteye \ + --from-literal=ADMIN_EMAIL="admin@tuempresa.com" \ + --from-literal=ALLOWED_EMAILS="*@tuempresa.com" \ + --from-literal=SMTP_HOST="smtp.tuproveedor.com" \ + --from-literal=SMTP_PORT="587" \ + --from-literal=SMTP_USERNAME="tu-usuario-smtp" \ + --from-literal=SMTP_PASSWORD="tu-contraseña-smtp" \ + --from-literal=SMTP_FROM="noreply@tuempresa.com" \ + --from-literal=SMTP_TLS="starttls" \ + --from-literal=DEFAULT_ORG_NAME="Acme Corp" \ + --from-literal=DEFAULT_ORG_SLUG="acme" +``` + +| Clave | Propósito | +|---|---| +| `ADMIN_EMAIL` | Usuario administrador inicial. Se inserta o actualiza en cada inicio con todos los permisos y está protegido contra eliminación/edición de permisos desde el panel. Sin él, no se crea ningún administrador y el primer inicio de sesión es imposible. | +| `ALLOWED_EMAILS` | Lista de permitidos separada por comas. Admite direcciones exactas (`user@example.com`) y comodines de dominio (`*@example.com`). Sin él, **ningún usuario puede iniciar sesión ni ser creado**. | +| `SMTP_HOST`, `SMTP_PORT`, `SMTP_USERNAME`, `SMTP_PASSWORD`, `SMTP_FROM` | Relay SMTP para enviar códigos OTP. Si `SMTP_HOST` no está configurado, los códigos OTP se registran en stdout del servidor en lugar de enviarse por email (útil para pruebas de humo en el primer arranque). Proporciona todas las claves SMTP juntas para el envío real de emails. | +| `SMTP_TLS` | Uno de `starttls` (por defecto), `tls` o `none`. | +| `DEFAULT_ORG_NAME`, `DEFAULT_ORG_SLUG` | Opcional. Asigna un nombre de visualización amigable y un slug de URL a la organización `default` integrada, de modo que viva en, por ejemplo, `/acme` en lugar de `/default`. Se aplica **solo en el primer arranque**; una vez que renombres la organización con `agenteye-orgctl org rename` (ver §7.6) se ignoran. El slug debe tener entre 1 y 40 caracteres alfanuméricos en minúsculas con guiones internos simples. Déjalos sin configurar para mantener el `default` genérico. | + +> **Guarda las credenciales SMTP en tu gestor de secretos.** + +**Verificación:** + +```bash +kubectl get secret agenteye-auth -n agenteye \ + -o jsonpath='{.data}' | grep -o '"[A-Z_]*"' | sort -u +``` + +Resultado esperado: las claves que has configurado aparecen en la salida. + +--- + +### 2.6 Clave de aislamiento de organizaciones multi-tenant (opcional) + +Omite esto para un despliegue de un solo tenant; el servidor funciona con un valor de desarrollo integrado y sirve correctamente a la organización `default`. **Antes de crear una segunda organización**, configura un `ORG_CH_SECRET` fuerte y estable: la contraseña de ClickHouse de cada organización se deriva como `HMAC(ORG_CH_SECRET, org_id)`, de modo que el valor de desarrollo por defecto, que es público, generaría credenciales por organización derivables públicamente. El comando `agenteye-orgctl org create` (ver [§7.6 Aprovisionar organizaciones](#76-provision-organizations-multi-tenant)) se niega a ejecutarse mientras el servidor siga usando el valor de desarrollo integrado. + +```bash +kubectl create secret generic agenteye-org-ch-secret \ + --namespace agenteye \ + --from-literal=ORG_CH_SECRET="$(openssl rand -base64 48)" + +# Reinicia el servidor para que recoja el nuevo valor. +kubectl -n agenteye rollout restart deployment/server +``` + +El servidor lo lee a través de una referencia `secretKeyRef` **opcional**, por lo que un clúster de un solo tenant que nunca lo crea sigue arrancando normalmente. Mantén el valor **estable e idéntico en todas las réplicas**; rotarlo invalida la contraseña de ClickHouse derivada de cada organización hasta que la reconciliación al arrancar vuelva a aprovisionar los usuarios (un reinicio gradual con el valor consistente en todas partes lo soluciona). Consulta `deploy/base/server/secret.example.yaml`. + +> **Guarda `ORG_CH_SECRET` en tu gestor de secretos y no lo rotes sin motivo.** + +--- + +### 2.7 Verificar todos los secretos + +```bash +kubectl get secrets -n agenteye -o custom-columns='NAME:.metadata.name,TYPE:.type' +``` + +Salida esperada (entre los secretos predeterminados): + +``` +NAME TYPE +agenteye-admin-key Opaque +agenteye-auth Opaque +agenteye-image-pull kubernetes.io/dockerconfigjson +agenteye-postgres Opaque +agenteye-org-ch-secret Opaque # solo si completaste §2.6 (multi-tenant) +``` + +Los cuatro secretos principales (`agenteye-admin-key`, `agenteye-auth`, `agenteye-image-pull`, `agenteye-postgres`) deben estar presentes antes de continuar. `agenteye-org-ch-secret` solo es necesario para despliegues multi-tenant (ver §2.6). + +--- + +## Fase 3 -- Desplegar la aplicación (~5 min) + +### 3.1 Configurar los nombres de host públicos + +cert-manager necesita los nombres de host de ingestión y del panel antes de poder solicitar sus certificados Let's Encrypt. Copia la plantilla y configura ambos: + +```bash +cp base/certificates/domain.env.example base/certificates/domain.env +# Edita base/certificates/domain.env y configura: +# INGEST_DOMAIN=ingest.tu-empresa.example (resuelve al LB público de Traefik) +# DASHBOARD_DOMAIN=agenteye.tu-empresa.example (resuelve al LB de Traefik del panel) +``` + +`domain.env` está en el gitignore; permanece local a cada despliegue. La compilación de kustomize falla con un error claro si falta cualquiera de las claves. + +> **El DNS debe resolver primero.** No es necesario apuntar el DNS a los LBs todavía (no existen hasta que se complete la Fase 1.2), pero la emisión de ACME en el paso 3.2 reintentará hasta que cada nombre de host resuelva a su LoadBalancer. Puedes configurar el DNS ahora (usando los nombres de host de LB capturados en la Fase 1.4) o continuar y añadir los registros en la Fase 4. + +--- + +### 3.2 Aplicar los manifiestos + +Aplica la base directamente para una instalación nueva, o un overlay si has creado uno para este entorno (los overlays solo fijan etiquetas de imagen, variables de entorno y límites de recursos; heredan los certificados y el enrutamiento de la base): + +```bash +kubectl apply -k base/ +# o +kubectl apply -k overlays// +``` + +El overlay incluye la base automáticamente; aplica uno, no ambos. + +--- + +### 3.3 Esperar a los pods + +```bash +kubectl wait --for=condition=Ready pod -l 'app in (server,dashboard,postgres,clickhouse)' \ + -n agenteye --timeout=180s +``` + +La espera está limitada a los pods del plano de datos principales. Los pods opcionales `agent` (asistente de IA) y `redis` arrancan junto a ellos; el asistente permanece inactivo hasta que le proporciones su endpoint de LLM (ver [enterprise-docs/assistant.md](/es/agenteye/assistant)), y Redis es una caché de mejor esfuerzo, por lo que ninguno de los dos necesita estar listo para que la plataforma sirva tráfico. + +**Verificación:** + +```bash +kubectl get pods -n agenteye +``` + +Resultado esperado (los pods opcionales `agent` y `redis` también aparecen y alcanzan el estado `Running`): + +``` +NAME READY STATUS RESTARTS AGE +agent-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +clickhouse-0 1/1 Running 0 ... +dashboard-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +dashboard-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +postgres-0 1/1 Running 0 ... +redis-0 1/1 Running 0 ... +server-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +server-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +``` + +**Si falla:** + +| Estado del pod | Causa probable | Comando de diagnóstico | +|---|---|---| +| `ImagePullBackOff` | Secreto de extracción de imagen o PAT incorrecto | `kubectl describe pod -n agenteye` | +| `CrashLoopBackOff` | Variables de entorno incorrectas (por ejemplo, DATABASE_URL) | `kubectl logs -n agenteye` | +| `Pending` | CPU/memoria insuficiente o sin nodos | `kubectl describe pod -n agenteye` (revisa Events) | + +--- + +### 3.4 Verificar el almacenamiento + +```bash +kubectl get pvc -n agenteye +``` + +Resultado esperado, ambos con estado `Bound`: + +| PVC | Capacidad | Respaldo | +|---|---|---| +| `postgres-data-postgres-0` | `50Gi` | Almacén relacional/de metadatos de PostgreSQL | +| `clickhouse-data-clickhouse-0` | `100Gi` | Almacén de análisis de eventos + evaluaciones de ClickHouse | + +También aparece un PVC `redis-data-redis-0` (1 Gi) para la caché opcional. + +**Si falla:** `Pending` significa que ninguna StorageClass puede aprovisionar el volumen. Comprueba `kubectl get storageclass` y asegúrate de que existe una por defecto. Para producción, sobrescribe el volumen de ClickHouse en tu overlay con una StorageClass de SSD rápida (por ejemplo, gp3 en AWS, pd-ssd en GCP); el rendimiento de compactación se degrada en discos lentos. + +--- + +### 3.5 Verificar los certificados + +```bash +kubectl get certificates -n agenteye +``` + +Resultado esperado: 3 certificados, todos con `Ready: True`: + +| Nombre | Emisor | Propósito | +|---|---|---| +| `mtls-ca` | `selfsigned` | CA privada para emitir certificados de cliente mTLS (validez de 10 años) | +| `ingest-tls` | `letsencrypt-prod` | Certificado TLS público para el endpoint de ingestión (90 días, renovación automática) | +| `dashboard-tls` | `letsencrypt-prod` | Certificado TLS público para el panel (90 días, renovación automática) | + +**Si `ingest-tls` o `dashboard-tls` no están listos:** + +Ejecuta `kubectl describe certificate -n agenteye` y lee los Events. Las causas más comunes son: + +- **DNS aún no apunta al LB.** Let's Encrypt resuelve el nombre de host y accede al puerto 80 para validar -- `INGEST_DOMAIN` debe resolver al LB público y `DASHBOARD_DOMAIN` al LB del panel. Hasta que se propague el CNAME/Alias, la orden permanece en `pending`. Una vez que el DNS sea correcto, cert-manager reintentará automáticamente (no es necesario eliminar el Certificate). +- **Nombre de host no sustituido.** Si `dnsNames` sigue mostrando `INGEST_DOMAIN_PLACEHOLDER` / `DASHBOARD_DOMAIN_PLACEHOLDER`, omitiste el paso 3.1 -- crea `base/certificates/domain.env` y vuelve a aplicar. +- **Traefik del panel no puede servir el desafío** (solo `dashboard-tls`). La instancia de Traefik del panel debe instalarse con el archivo de valores incluido (Fase 1.2), que habilita el proveedor de Ingress con alcance limitado que sirve el solver HTTP-01 de cert-manager. Una instancia instalada sin él deja el desafío sin ruta y la orden en `pending` indefinidamente. + +**Si `mtls-ca` no está listo:** cert-manager en sí está en mal estado. Revisa los pods de cert-manager del paso 1.1. + +--- + +### 3.6 Verificar los CronJobs + +```bash +kubectl get cronjobs -n agenteye +``` + +Resultado esperado: + +| Nombre | Programación | Propósito | +|---|---|---| +| `agenteye-backup` | `0 3 * * *` | Copia de seguridad diaria de Postgres + ClickHouse a las 03:00 UTC | +| `cert-renewal-check` | `0 3,15 * * *` | Alertas de caducidad de certificados a las 03:00 y 15:00 UTC | + +--- + +### 3.7 Verificar que el servidor arrancó correctamente + +```bash +kubectl logs -n agenteye -l app=server --tail=20 +``` + +**Verificación:** Busca una línea de inicio que indique que el servidor está escuchando en el puerto 8080. No debe haber errores de conexión a la base de datos (el servidor requiere que tanto PostgreSQL como ClickHouse sean accesibles antes de reportar estado Ready). + +**Si falla:** La causa más común es un `POSTGRES_PASSWORD` que contiene caracteres no seguros para URLs que rompen la `DATABASE_URL`. Consulta [enterprise-docs/troubleshooting.md](/es/agenteye/troubleshooting). + +--- + +### 3.8 Verificar que el panel se conectó al servidor + +```bash +kubectl logs -n agenteye -l app=dashboard --tail=20 +``` + +**Verificación:** Busca `Ready` en la salida sin errores `ECONNREFUSED` ni similares. + +**Si falla:** Comprueba que el Service `server` existe (`kubectl get svc server -n agenteye`) y que `AGENTEYE_SERVER_URL` está configurado como `http://server:8080` en el despliegue del panel. + +--- + +## Fase 4 -- Acceso de red (~5 min) + +### 4.1 Obtener las direcciones de los LoadBalancers + +```bash +PUBLIC_IP=$(kubectl get svc -n traefik-public \ + -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') + +INTERNAL_IP=$(kubectl get svc -n traefik-dashboard \ + -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') +``` + +> En AWS EKS, los LoadBalancers devuelven un nombre de host en lugar de una IP. Reemplaza `.ip` por `.hostname` en los comandos anteriores. + +**Verificación:** + +```bash +echo "Público (ingestión): $PUBLIC_IP" +echo "Interno (panel): $INTERNAL_IP" +``` + +Ambos deben ser no vacíos. + +--- + +### 4.2 Apuntar el DNS a los LoadBalancers + +Crea registros DNS para que los nombres de host de `base/certificates/domain.env` resuelvan a sus LoadBalancers -- `INGEST_DOMAIN` al LB de Traefik **público**, `DASHBOARD_DOMAIN` al LB de Traefik del **panel**: + +- **AWS Route 53:** registro `A` con `Alias = Yes`, destino = el nombre de host del LB. No uses A → IP simple; las IPs de ELB rotan. +- **Cualquier otro proveedor:** `CNAME` desde el nombre de host al nombre de host del LB. + +Verifica: + +```bash +dig +short ingest.tu-empresa.example +dig +short agenteye.tu-empresa.example +``` + +Deben devolver las mismas direcciones que `$PUBLIC_IP` y `$INTERNAL_IP` respectivamente (o, en EKS, resolver a los mismos nombres de host `*.elb.amazonaws.com`). + +Una vez que el DNS resuelva, cert-manager completará las órdenes ACME pendientes de la Fase 3.5 en un minuto. Vuelve a ejecutar `kubectl get certificates -n agenteye` hasta que tanto `ingest-tls` como `dashboard-tls` muestren `Ready: True`. + +--- + +### 4.3 Acceder al endpoint de ingestión + +El endpoint de ingestión público aplica mutual TLS, por lo que cada solicitud (incluyendo `/health`) debe presentar un certificado de cliente. Emites tu primer certificado de cliente en la Fase 5; si ya tienes uno, verifica la accesibilidad ahora: + +```bash +curl -s --cert issued//client.crt \ + --key issued//client.key \ + https://ingest.tu-empresa.example/health +``` + +Resultado esperado: `{"status":"ok"}`. No se necesita `-k` -- el certificado del servidor encadena a una CA pública para `INGEST_DOMAIN`, por lo que se valida contra el almacén de confianza del sistema. Accede al endpoint de ingestión por su nombre de host `INGEST_DOMAIN` (que coincide con el certificado emitido), no por la IP/nombre de host bruto del LoadBalancer. + +El endpoint del panel se sirve en `DASHBOARD_DOMAIN` con un certificado de confianza pública y no está detrás de mTLS, por lo que no se necesita `-k` ni certificado de cliente: + +```bash +curl -s https://agenteye.tu-empresa.example/ -o /dev/null -w '%{http_code}\n' +``` + +Accede al panel por su nombre de host, no por la dirección bruta del LB -- el certificado está vinculado a `DASHBOARD_DOMAIN`, por lo que la dirección bruta mostrará un error de nombre en el certificado. + +**Si falla:** Si `curl` se cuelga, comprueba que el LB es accesible desde tu máquina (VPN, grupos de seguridad, reglas de firewall). Un error de handshake `certificate required` en el nombre de host de ingestión significa que no se presentó ningún certificado de cliente; completa primero la Fase 5. Un error de validación TLS en el nombre de host de ingestión significa que el certificado del servidor aún no ha terminado de emitirse; vuelve a la Fase 3.5 y resuelve el problema allí. + +--- + +## Fase 5 -- Emitir certificados de cliente mTLS (~10 min por clúster) + +Los colectores se autentican con **dos factores**: un certificado de cliente (capa de transporte, demuestra que la solicitud proviene de un clúster autorizado) y una clave de API (capa de aplicación, demuestra que la solicitud es de un colector con permiso `events:add`). Una clave filtrada es inútil sin el certificado; un certificado robado es inútil sin una clave válida. + +### 5.1 Emitir un certificado + +Cada clúster que ejecuta colectores necesita su propio certificado de cliente. Desde el directorio de manifiestos: + +```bash +cd base/certificates/client-certs +./issue-client-cert.sh +``` + +Reemplaza `` con un identificador significativo (por ejemplo, `us-east-1-prod`, `staging`). + +**Verificación:** El script imprime `==> Done!` y lista los archivos de salida. + +```bash +kubectl get certificate mtls-client- -n agenteye +``` + +Resultado esperado: `Ready: True`. + +Archivos de salida en `issued//`: + +| Archivo | Propósito | +|---|---| +| `client.crt` | Certificado de cliente (validez de 90 días) | +| `client.key` | Clave privada del cliente | +| `ca.crt` | Certificado de CA para verificación del servidor | +| `collector-mtls-secret.yaml` | Secret de Kubernetes listo para aplicar en el clúster del colector | + +--- + +### 5.1b Entrega alternativa: AWS Secrets Manager + +Si el consumidor del certificado es un Pod de Kubernetes que necesita `client.crt` y `client.key` en disco -- el caso típico cuando ejecutas el agenteye-collector como sidecar en tu pod de aplicación -- envía el bundle del certificado a AWS Secrets Manager. El pod de la aplicación lo monta entonces mediante el [Secrets Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/) con IRSA, y la rotación del certificado es completamente automática. + +```bash +cd base/certificates/client-certs +export AWS_REGION=us-east-1 # región donde se ejecuta tu carga de trabajo +./issue-client-cert.sh --save-to aws-secrets-manager +``` + +En cada reejecución (renovación), el script llama a `PutSecretValue` en el mismo secreto, de modo que el ARN y el nombre permanecen estables. El CSI Driver recoge la nueva versión en su próximo ciclo de rotación y reescribe los archivos dentro del pod. + +**Requisitos previos:** + +- CLI de `aws` v2 autenticado en tu cuenta de AWS. +- `jq` instalado. +- Variable de entorno `AWS_REGION` configurada. +- Permisos IAM en tu identidad (limita `Resource` a `arn:aws:secretsmanager:::secret:agenteye/mtls-client/*`): + - `secretsmanager:CreateSecret` + - `secretsmanager:DescribeSecret` + - `secretsmanager:PutSecretValue` + - `secretsmanager:TagResource` + +**Lo que hace el script en este modo:** + +| Paso | Acción | +|---|---| +| 1 | Emite o reextrae el certificado mediante cert-manager (igual que el modo por defecto). | +| 2 | Llama a `DescribeSecret` en `agenteye/mtls-client/` para decidir si crear o actualizar. | +| 3 | En la primera ejecución: `CreateSecret` con un payload JSON de tres claves (`client.crt`, `client.key`, `ca.crt`), etiquetado con `AgentEyeCluster=`. En ejecuciones posteriores: `PutSecretValue` para publicar una nueva versión; etiqueta actualizada mediante `TagResource`. | +| 4 | Elimina `issued//` solo después de una carga exitosa. En caso de error, el directorio se conserva para poder reintentar. | + +**Si el secreto está programado para eliminación**, el script falla con un mensaje claro indicándote que ejecutes `aws secretsmanager restore-secret --secret-id agenteye/mtls-client/` antes de reintentar. + +Para la configuración completa del pod (SecretProviderClass, configuración de IRSA, comportamiento de rotación y solución de problemas), consulta [enterprise-docs/single-pod-deployment.md](/es/agenteye/single-pod-deployment). + +--- + +### 5.2 Verificar que el certificado funciona + +Prueba el certificado emitido contra el ingreso mTLS: + +```bash +curl -sk --cert issued//client.crt \ + --key issued//client.key \ + https://${PUBLIC_IP}/health +``` + +Resultado esperado: `{"status":"ok"}` + +**Si falla:** + +| Error | Causa | Solución | +|---|---|---| +| `certificate required` | El certificado no se está presentando | Verifica las rutas de archivo en el comando `curl` | +| `bad certificate` | Discrepancia de CA | Verifica que `mtls-ca-issuer` emitió el certificado: `kubectl describe certificate mtls-client- -n agenteye` | +| `connection refused` | Nombre de host incorrecto o LB no accesible | Comprueba `/etc/hosts` o DNS | + +--- + +### 5.3 Entregar al clúster del colector + +Envía `collector-mtls-secret.yaml` al equipo que opera el clúster del colector. Ellos lo aplican: + +```bash +kubectl apply -f collector-mtls-secret.yaml -n +``` + +Luego configura el colector para montar el secreto y usar las rutas del certificado: + +```json +{ + "tls_cert": "/etc/agenteye/tls/client.crt", + "tls_key": "/etc/agenteye/tls/client.key" +} +``` + +Consulta [enterprise-docs/collector-installation.md](/es/agenteye/collector-installation) para la configuración completa del colector, incluyendo los montajes de volumen de Kubernetes. + +**Verificación (en el clúster del colector):** + +```bash +kubectl get secret agenteye-collector-mtls -n +``` + +Resultado esperado: el secreto existe con 3 claves de datos (`client.crt`, `client.key`, `ca.crt`). + +--- + +### 5.4 Ciclo de vida del certificado + +| Propiedad | Valor | +|---|---| +| Validez del certificado de cliente | 90 días | +| Renovación automática | cert-manager renueva 15 días antes de la caducidad | +| Validez de la CA | 10 años | +| Alertas de caducidad | CronJob alerta 30 días antes de la caducidad (Fase 6) | + +cert-manager renueva automáticamente el certificado en el **clúster de AgentEye**, pero el certificado renovado debe volver a entregarse al clúster del colector. Vuelve a ejecutar `issue-client-cert.sh` y vuelve a aplicar `collector-mtls-secret.yaml` antes de que caduque el certificado antiguo. + +Si estás usando `--save-to aws-secrets-manager` (ver §5.1b), vuelve a ejecutar el mismo comando. El script llama a `PutSecretValue` en el mismo secreto; los pods que montan el secreto mediante el Secrets Store CSI Driver recogen la nueva versión en su próximo ciclo de rotación (por defecto: cada hora), sin necesidad de reiniciar el pod. + +--- + +### 5.5 Revocar un certificado + +Para bloquear inmediatamente el acceso del colector de un clúster: + +```bash +kubectl delete certificate mtls-client- -n agenteye +``` + +**Verificación:** El comando `curl` del paso 5.2 ahora falla con un error de handshake TLS. + +--- + +## Fase 6 -- Monitorización de renovación de certificados (~2 min) + +Un CronJob integrado se ejecuta cada 12 horas (03:00 y 15:00 UTC) y comprueba todos los certificados de cliente etiquetados con `agenteye.io/cert-type=mtls-client`. Alerta cuando algún certificado está a menos de 30 días de caducar. + +### 6.1 Habilitar notificaciones de Slack (opcional) + +```bash +kubectl create secret generic cert-renewal-notify-config \ + --namespace agenteye \ + --from-literal=SLACK_WEBHOOK_URL="https://hooks.slack.com/services/TU/WEBHOOK/URL" +``` + +Sin este secreto, el CronJob sigue ejecutándose y registra el estado de los certificados en stdout. + +**Verificación:** + +```bash +kubectl get secret cert-renewal-notify-config -n agenteye +``` + +Resultado esperado: el secreto existe. + +--- + +### 6.2 Probar el CronJob + +```bash +kubectl create job --from=cronjob/cert-renewal-check test-cert-check -n agenteye + +kubectl wait --for=condition=Complete job/test-cert-check -n agenteye --timeout=60s + +kubectl logs -n agenteye -l job-name=test-cert-check +``` + +Resultado esperado: una lista de certificados con su estado de caducidad. Si el webhook de Slack está configurado, comprueba el canal de Slack para ver el mensaje de alerta. + +**Si falla:** Comprueba el RBAC -- la ServiceAccount del CronJob necesita permisos `get, list` en los recursos Certificate de cert-manager. Verifica con: `kubectl describe role cert-renewal-check -n agenteye`. + +Limpia el job de prueba: + +```bash +kubectl delete job test-cert-check -n agenteye +``` + +--- + +## Fase 7 -- Verificar el funcionamiento end-to-end + +Esta fase confirma que toda la cadena funciona: comprobación de salud, creación de clave, ingestión de eventos y visualización en el panel. + +> **Nota:** Los ejemplos siguientes acceden al endpoint de ingestión por su dirección bruta del LoadBalancer (`${PUBLIC_IP}`) por comodidad, por lo que se pasa `-k`; el certificado del servidor está vinculado a `INGEST_DOMAIN`, no a la IP del LB, por lo que se omite la verificación del nombre de host. El endpoint de ingestión aplica mutual TLS en **todas** las rutas, por lo que cada llamada también debe presentar un certificado de cliente (`--cert`/`--key`). Para validar también el certificado público, apunta a `https://ingest.tu-empresa.example/...` en lugar de `${PUBLIC_IP}` y elimina el `-k`. + +### 7.1 Comprobación de salud + +```bash +curl -sk --cert issued//client.crt \ + --key issued//client.key \ + https://${PUBLIC_IP}/health +``` + +Resultado esperado: `{"status":"ok"}` con HTTP 200. + +--- + +### 7.2 Crear claves de colector con permisos restringidos + +La clave de administrador es para el arranque inicial y la gestión. Crea claves dedicadas con permiso `events:add` para los colectores: + +```bash +COLLECTOR_KEY=$(openssl rand -hex 32) + +curl -sk -X POST https://${PUBLIC_IP}/keys \ + --cert issued//client.crt \ + --key issued//client.key \ + -H "Authorization: Bearer ${ADMIN_KEY}" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "prod-collector", + "key": "'"${COLLECTOR_KEY}"'", + "permissions": ["events:add"] + }' +``` + +**Verificación:** La respuesta incluye `"id"`, `"name": "prod-collector"`, `"permissions": ["events:add"]`, `"created_at"`. + +**Verificación:** Comprueba que la clave aparece en la lista de claves: + +```bash +curl -sk https://${PUBLIC_IP}/keys \ + --cert issued//client.crt \ + --key issued//client.key \ + -H "Authorization: Bearer ${ADMIN_KEY}" +``` + +Resultado esperado: `prod-collector` aparece en la respuesta. + +Consulta [enterprise-docs/api-keys.md](/es/agenteye/api-keys) para la referencia completa de gestión de claves. + +--- + +### 7.3 Ingestar un evento de prueba + +```bash +echo '{"session_id":"test","agent_id":"smoke-test","type":"test","timestamp":"2026-04-20T00:00:00Z"}' \ + | curl -sk --cert issued//client.crt \ + --key issued//client.key \ + -H "Authorization: Bearer ${COLLECTOR_KEY}" \ + -H "Content-Type: application/x-ndjson" \ + --data-binary @- \ + https://${PUBLIC_IP}/events +``` + +Resultado esperado: `{"accepted":1,"skipped":0}` con HTTP 200. + +**Si falla:** + +| Estado HTTP | Causa | +|---|---| +| 401 | Clave de API inválida o ausente | +| 403 | La clave no tiene el permiso `events:add` | +| Error de handshake TLS | Problema con el certificado de cliente -- ver solución de problemas de la Fase 5 | + +--- + +### 7.4 Verificar que el evento aparece en el panel + +Abre `https://agenteye.tu-empresa.example` (tu `DASHBOARD_DOMAIN`) en un navegador. El certificado tiene confianza pública, por lo que no hay advertencias. + +> Si el LoadBalancer del panel está restringido por lista de IPs y no puedes conectarte, verifica que tu IP está permitida: +> ```bash +> kubectl get svc traefik-dashboard -n traefik-dashboard -o jsonpath='{.spec.loadBalancerSourceRanges}' +> ``` +> Ten en cuenta que Let's Encrypt renueva el certificado del panel mediante HTTP-01 en el puerto 80, y los rangos de origen se aplican a todo el LoadBalancer -- antes de restringirlo a rangos corporativos, coordina un solver DNS-01 con soporte o las renovaciones fallarán silenciosamente. + +**Verificación:** El evento de prueba debe aparecer en la lista de eventos con la sesión `test` y el agente `smoke-test`. + +**Si falla:** Comprueba los logs del panel (`kubectl logs -n agenteye -l app=dashboard --tail=50`). Verifica que `AGENTEYE_SERVER_URL` y `AGENTEYE_API_KEY` están configurados correctamente. + +--- + +### 7.5 Probar el CronJob de copia de seguridad + +```bash +kubectl create job --from=cronjob/agenteye-backup test-backup -n agenteye + +kubectl wait --for=condition=Complete job/test-backup -n agenteye --timeout=300s + +kubectl logs -n agenteye -l job-name=test-backup +``` + +Resultado esperado: `Backup created: agenteye-YYYYMMDD-HHMMSS.tar.gz (NNN)` en los logs; el archivo agrupa el volcado de Postgres y las tablas de ClickHouse. + +> El paso de carga a S3 viene integrado en el CronJob y se ejecuta siempre que `BACKUP_BUCKET` esté configurado (la base incluye un valor de bucket por defecto). Solo se omite cuando `BACKUP_BUCKET` está vacío o literalmente es `PLACEHOLDER`. Apúntalo a tu propio bucket y concede al ServiceAccount `agenteye-backup` acceso de escritura antes de confiar en él (ver la sección de Copias de seguridad más abajo). + +Limpieza: + +```bash +kubectl delete job test-backup -n agenteye +``` + +--- + +### 7.6 Aprovisionar organizaciones (multi-tenant) + +Omite esto para un despliegue de un solo tenant; todos los datos viven en la organización `default` integrada y nada aquí es necesario. + +Si ejecutas múltiples tenants aislados, las organizaciones y sus miembros se crean con la CLI **`agenteye-orgctl`**. Esta herramienta se incluye **dentro de la imagen del servidor** (junto a `agenteye-server`) y se ejecuta **dentro del Deployment `server` existente con `kubectl exec`; no hay pod, Job ni Deployment separado, y no hay API HTTP ni botón en el panel para el ciclo de vida del tenant.** Ejecutarla en el pod del servidor significa que reutiliza la `DATABASE_URL`, `CLICKHOUSE_URL` y el `ORG_CH_SECRET` del §2.6 del pod. + +> **Requisito previo:** completa primero el §2.6. `org create` se niega a ejecutarse mientras el servidor siga usando el `ORG_CH_SECRET` de desarrollo integrado, y el usuario de ClickHouse por organización que aprovisiona depende de que ese secreto sea fuerte y estable. + +**Crear una organización y añadir su primer administrador:** + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org create --slug acme --name "Acme Corp" + +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member add --org acme --email alice@acme.example --set admin +``` + +El nuevo miembro recibe un OTP en su primer inicio de sesión en el panel y luego trabaja completamente en la interfaz de usuario bajo el prefijo de URL de la organización (por ejemplo, `/acme/...`). + +**Otros comandos** (se ejecutan de la misma manera con `kubectl -n agenteye exec deploy/server -- agenteye-orgctl …`): + +| Comando | Qué hace | +|---|---| +| `org list` | Lista las organizaciones y su estado. | +| `org rename --slug --name ` | Renombra una organización (el slug no cambia). | +| `org delete --slug ` | Eliminación suave + eliminación del usuario de ClickHouse de la organización; **los datos se conservan**. | +| `org purge --slug ` | Borrado irreversible de datos; la organización debe estar eliminada primero; nunca para la organización `default`. | +| `member list --org ` | Lista los miembros y sus permisos. | +| `member update --org --email [--set ...] [--add ...] [--remove ...]` | Cambia los permisos de un miembro. | +| `member remove --org --email ` | Elimina un miembro de la organización. | + +Los conjuntos de permisos integrados son `admin`, `standard` y `read-only`. **Las claves de API por organización se siguen creando en el panel/API por los miembros de la organización (el §7.2 muestra la API de claves); solo el ciclo de vida de la organización y los miembros es exclusivo para operadores.** Referencia completa y un ejemplo detallado: [enterprise-docs/tenant-management.md](/es/agenteye/tenant-management). + +--- + +## Lista de verificación post-despliegue + +Usa esta lista para confirmar que todo funciona. Cada elemento debe estar comprobado antes de entregar a los colectores. + +- [ ] Todos los pods en estado `Running` en el namespace `agenteye` +- [ ] PVC de PostgreSQL vinculado (50 Gi) y PVC de ClickHouse vinculado (100 Gi) +- [ ] Los 3 certificados con `Ready: True` +- [ ] Ambas IPs de LoadBalancer asignadas +- [ ] DNS o `/etc/hosts` configurado y resolviendo +- [ ] `/health` devuelve HTTP 200 +- [ ] Prueba de certificado mTLS superada (`curl` con certificado de cliente a `/health`) +- [ ] Clave de colector con permisos restringidos creada y probada +- [ ] Evento de prueba ingestado (`accepted: 1`) +- [ ] Evento visible en el panel +- [ ] Certificados de cliente emitidos para cada clúster de colector +- [ ] CronJob de copia de seguridad probado manualmente +- [ ] CronJob de renovación de certificados probado manualmente +- [ ] Webhook de Slack para alertas de certificados configurado (opcional) +- [ ] Bucket de copia de seguridad configurado en el overlay (ver más abajo) +- [ ] Clave de administrador y contraseña de Postgres guardadas en el gestor de secretos + +--- + +## Copias de seguridad + +Un único CronJob `agenteye-backup` se ejecuta diariamente a las 03:00 UTC. Vuelca **ambos** almacenes: PostgreSQL (estado relacional) y ClickHouse (las tablas de análisis `events` + `evaluations`), en un archivo comprimido en el pod, y luego lo carga en el almacenamiento de objetos que configures en tu overlay. + +Cada ejecución produce un objeto, `agenteye-.tar.gz`, que se descomprime en: + +``` +postgres.sql # pg_dump de la base de datos relacional +events.sql # DDL de la tabla events de ClickHouse +events.native # Datos de la tabla events de ClickHouse (formato Native) +evaluations.sql # DDL de la tabla evaluations de ClickHouse +evaluations.native # Datos de la tabla evaluations de ClickHouse +``` + +ClickHouse se lee a través de su API HTTP (el mismo endpoint que usa el servidor), por lo que el job no necesita \ No newline at end of file diff --git a/docs/es/agenteye/managed-deployment.mdx b/docs/es/agenteye/managed-deployment.mdx new file mode 100644 index 00000000..170f170b --- /dev/null +++ b/docs/es/agenteye/managed-deployment.mdx @@ -0,0 +1,171 @@ +--- +title: "Despliegue Administrado en tu Clúster de Kubernetes" +description: "Documentación del despliegue administrado de AgentEye en tu clúster de Kubernetes." +--- + + +AgentEye es una plataforma de observabilidad y evaluación autoalojada para agentes de IA y LLM. Captura sesiones de agentes, llamadas a herramientas, solicitudes a modelos y errores; los convierte en analíticas y evaluaciones con capacidad de búsqueda, y muestra los resultados en un panel con un asistente de IA opcional de solo lectura. + +En el modelo de despliegue administrado, tú proporcionas un clúster de Kubernetes dedicado y Exosphere ejecuta la plataforma completa dentro de él: despliega, configura, opera, respalda y actualiza cada componente en tu nombre. Tu equipo obtiene el valor de la plataforma (visibilidad de agentes, analíticas, evaluación y el asistente opcional) sin necesidad de operar bases de datos, certificados ni actualizaciones. Todos los datos permanecen dentro de tu cuenta de nube. + +--- + +## Requisitos previos + +- Un **PAT de GitHub** para extraer imágenes de contenedor y descargar artefactos (consulta [Configuración del token de GitHub](/es/agenteye/github-token)) +- Un **clúster de Kubernetes dedicado** (consulta los requisitos a continuación) +- Un **bucket de almacenamiento** para copias de seguridad de bases de datos +- **Conectividad de red**: puerto 443 de entrada al balanceador de carga del clúster + +--- + +## Paso 1: Aprovisiona un Clúster de Kubernetes Dedicado + +Crea un clúster de Kubernetes dedicado exclusivamente a AgentEye. No debe compartirse con otras cargas de trabajo, de modo que la plataforma completa (servicios de aplicación, bases de datos, analíticas y caché) se ejecute de forma aislada sin afectar tu infraestructura existente. + +| Requisito | Detalles | +|---|---| +| **Distribución** | Cualquier Kubernetes conforme: EKS, GKE, AKS o autogestionado | +| **Versión** | 1.27 o superior | +| **Pool de nodos** | Mínimo: **3 nodos, 4 vCPU / 8 GB RAM cada uno** (instancias estándar de propósito general) | +| **Almacenamiento** | Una StorageClass predeterminada que aprovisione volúmenes de bloque (p. ej., `gp3` en AWS, `pd-ssd` en GCP) | +| **Balanceador de carga** | El clúster debe poder aprovisionar servicios LoadBalancer en la nube (predeterminado en EKS, GKE, AKS) | + +> Exosphere instala y gestiona todo lo demás dentro del clúster: controladores de ingress, certificados TLS, bases de datos, caché, monitoreo y todos los despliegues de aplicaciones. + +--- + +## Paso 2: Otorga Acceso al Equipo de AgentEye + +Exosphere necesita acceso cluster-admin (o RBAC amplio equivalente) para gestionar namespaces, definiciones de recursos personalizados, controladores de ingress y aprovisionadores de almacenamiento. + +| Requisito | Detalles | +|---|---| +| **Método de acceso** | Rol de IAM (preferido para EKS/GKE), kubeconfig o acceso basado en SSO | +| **VPN / bastión** | Si el servidor de API de Kubernetes es privado, proporciona credenciales de VPN o acceso a bastión para el equipo de operaciones de Exosphere | + +--- + +## Paso 3: Configura la Conectividad de Red + +Tu equipo de red debe permitir el tráfico de entrada en el **puerto 443** hacia los balanceadores de carga del clúster. El despliegue utiliza dos balanceadores de carga separados: uno para la ingesta de eventos (protegido con mTLS) y otro para el panel: + +| Tráfico | Origen | Destino | Seguridad | +|---|---|---|---| +| **Ingesta de eventos** | Pods del colector en tus clústeres | LoadBalancer de ingesta, puerto 443 | mTLS (certificado de cliente) + clave de API | +| **Panel** | Navegadores de desarrolladores | LoadBalancer del panel, puerto 443 | HTTPS en tu dominio, inicio de sesión sin contraseña por OTP de correo electrónico | + +El endpoint de ingesta está protegido por TLS mutuo; los colectores deben presentar un certificado de cliente válido **y** una clave de API válida en cada solicitud. El panel se ejecuta en su propio balanceador de carga y hostname, con el inicio de sesión restringido a las direcciones de correo electrónico/dominios que hayas permitido. + +**Registros DNS (una sola vez):** creas dos registros CNAME bajo un dominio que controlas — uno para el endpoint de ingesta y otro para el panel (p. ej., `agenteye.tu-empresa.ejemplo`) — apuntando a los hostnames del balanceador de carga que proporciona Exosphere. Exosphere aprovisiona entonces certificados TLS de confianza pública para ambos hostnames de forma automática, incluidas las renovaciones. + +> **Nota sobre el puerto 80:** la emisión y renovación automática de certificados se valida mediante HTTP en el puerto 80 de cada balanceador de carga. Si tu postura de seguridad requiere restringir el balanceador de carga del panel a rangos de IP corporativos, infórmalo a Exosphere primero — cambiamos la validación de certificados a un método basado en DNS (un registro DNS adicional de tu parte) para que las renovaciones sigan funcionando detrás de la restricción. + +> **Saliente:** los nodos del clúster necesitan acceso a internet para extraer imágenes de contenedor de `ghcr.io`. Si tu red restringe el tráfico saliente, incluye `ghcr.io` en la lista de permitidos o replica las imágenes en tu registro interno. + +--- + +## Paso 4: Proporciona un Bucket de Almacenamiento para Copias de Seguridad + +Las copias de seguridad de bases de datos se almacenan en un bucket de almacenamiento en la nube que te pertenece. + +| Requisito | Detalles | +|---|---| +| **Servicio** | S3 (AWS), GCS (GCP) o Azure Blob Storage | +| **Acceso** | Concede acceso de escritura a los nodos del clúster mediante rol de IAM para cuentas de servicio (IRSA en EKS, Workload Identity en GKE) o proporciona credenciales | +| **Retención** | Tú controlas la política de ciclo de vida del bucket (período de retención, reglas de archivo). Exosphere escribe las copias de seguridad; tú decides cuánto tiempo conservarlas | + +Una copia de seguridad diaria vuelca tanto PostgreSQL (estado relacional) como ClickHouse (eventos y evaluaciones) en un único archivo comprimido y lo sube a tu bucket. Las copias de seguridad también se ejecutan antes de cada actualización. + +--- + +## Paso 5: Designa un Punto de Contacto + +Proporciona una persona o un canal de Slack/Teams de tu parte para problemas a nivel de clúster: estado de los nodos, límites de cuenta en la nube, cambios de red. Las operaciones cotidianas no involucran este contacto. + +--- + +## Qué Desplegamos + +Una vez que Exosphere tiene acceso al clúster, los siguientes componentes se despliegan y gestionan por ti: + +| Componente | Función | +|---|---| +| **Servidor AgentEye** | API HTTP que recibe eventos de los colectores, ejecuta analíticas y sirve datos al panel | +| **Panel** | Interfaz web para ver sesiones de agentes, llamadas a herramientas, solicitudes a modelos y errores; aloja el asistente de IA opcional de solo lectura | +| **ClickHouse** | Almacén canónico requerido para eventos ingestados, analíticas y evaluaciones | +| **PostgreSQL** | Almacén relacional para organizaciones, claves de API, usuarios, paneles y consultas guardadas | +| **Redis** | Caché compartida opcional y backend de límite de velocidad; la plataforma se degrada de forma controlada si no está disponible | +| **Asistente de IA (opcional)** | Contenedor de asistente interno de solo lectura; permanece deshabilitado hasta que se configure un endpoint de LLM | +| **Controladores de ingress** | Dos balanceadores de carga (uno para ingesta protegida con mTLS, otro para el panel) que terminan TLS con certificados de confianza pública y renovación automática, y aplican mTLS en el endpoint de ingesta | +| **cert-manager** | Automatiza el aprovisionamiento de certificados TLS y la emisión de certificados de cliente mTLS | +| **Monitoreo de certificados** | Un trabajo programado verifica la expiración de certificados y envía alertas (p. ej., a Slack) cuando los certificados se acercan a la renovación | + +La oferta administrada también opera el pipeline de evaluación de la plataforma, que puntúa la actividad de los agentes según tus criterios de evaluación. Consulta [Asistente](/es/agenteye/assistant) y [Suite de Evaluación](/es/agenteye/evaluation-suite) para conocer qué ofrecen estas capacidades. + +--- + +## Qué te Proporcionamos + +Una vez completado el despliegue, recibes: + +| Elemento | Detalles | +|---|---| +| **URL del panel** | Un hostname bajo tu dominio (p. ej., `https://agenteye.tu-empresa.ejemplo`), servido con un certificado TLS de confianza pública y renovación automática. Creas un CNAME hacia el hostname del balanceador de carga que proporcionamos; el inicio de sesión es sin contraseña por OTP de correo electrónico | +| **Endpoint del colector** | La ruta `/events` del hostname de ingesta (p. ej., `https://ingest.tu-empresa.ejemplo/events`), protegido con mTLS | +| **Bundle de certificado de cliente** | Por clúster: certificado de cliente, clave privada y certificado de CA entregados como un manifiesto de Secret de Kubernetes. Aplícalo una vez por clúster | +| **PAT de GitHub** | Para descargar binarios del colector y paquetes del SDK de Python | +| **Claves de API del colector** | Claves con alcance y permiso `events:add`, una por despliegue de colector | +| **Guías de instalación** | Documentación paso a paso para el colector y el SDK de Python | + +--- + +## Qué Haces Después de la Configuración + +Tu único trabajo continuo es en tus propias máquinas de agentes, no en el clúster de AgentEye: + +1. **Instala el colector** en cada clúster de Kubernetes que ejecute agentes de IA: monta el certificado de cliente y configura la URL del endpoint y la clave de API. Consulta [Instalación del Colector](/es/agenteye/collector-installation). +2. **Integra el SDK de Python** en el código de tu agente. Consulta [SDK de Python](/es/agenteye/python-sdk). +3. **Abre el panel** en tu navegador para ver la actividad de los agentes. + +Sin operaciones de clúster, sin gestión de bases de datos, sin renovaciones de certificados, sin actualizaciones. + +--- + +## Seguridad + +- **Los datos permanecen en tu cuenta de nube.** El clúster, el almacenamiento y las bases de datos se ejecutan en tu entorno. Ningún dato sale de tu perímetro. +- **Tú controlas el acceso.** El clúster está en tu cuenta. Puedes auditar, monitorear o revocar el acceso de Exosphere en cualquier momento. Todas las operaciones pasan por el registro de auditoría de tu nube (CloudTrail, GCP Audit Logs, etc.). +- **mTLS en la ingesta de eventos.** Cada solicitud del colector requiere tanto un certificado de cliente válido como una clave de API. Una clave filtrada es inútil sin el certificado; un certificado robado es inútil sin una clave válida. +- **Control de acceso al panel.** El panel se ejecuta en su propio balanceador de carga, separado de la ingesta de eventos, y el inicio de sesión es sin contraseña por OTP de correo electrónico, restringido a las direcciones de correo electrónico/dominios que hayas permitido. Una lista de rangos de IP de origen permitidos en el balanceador de carga está disponible bajo solicitud; dado que la renovación automática de certificados debe alcanzar el balanceador de carga, Exosphere combina la restricción con la validación de certificados basada en DNS para que las renovaciones sigan funcionando. +- **Certificados por clúster.** Cada uno de tus clústeres recibe su propio certificado de cliente. Si un clúster se ve comprometido, ese certificado se revoca de forma independiente sin afectar a los demás. + +--- + +## Cronograma de Despliegue + +| Fase | Duración | Tu participación | +|---|---|---| +| **Aprovisionamiento del clúster** | 1-2 días | Aprovisionar el clúster y conceder acceso a Exosphere | +| **Configuración de la plataforma** | 1 día | Ninguna; Exosphere instala todos los componentes de infraestructura | +| **Despliegue de la aplicación** | 1 día | Ninguna; Exosphere despliega el servidor, el panel y crea las claves de API | +| **Despliegue del colector** | 1-3 días | Instalar colectores en tus clústeres (con orientación de Exosphere) | +| **Rodaje en producción** | 1 semana | Ninguna; Exosphere monitorea y ajusta | + +Total típico: **~2 semanas** desde el inicio hasta producción lista. + +--- + +## Soporte + +Para preguntas o problemas, contacta a Exosphere en `support@exosphere.host`. + +--- + +## Próximos Pasos + +- [Primeros Pasos](/es/agenteye/getting-started): recorrido completo de extremo a extremo +- [Instalación del Colector](/es/agenteye/collector-installation): instalar y configurar el colector +- [SDK de Python](/es/agenteye/python-sdk): instrumentar el código de tu agente +- [Claves de API](/es/agenteye/api-keys): gestionar acceso y permisos +- [Solución de Problemas](/es/agenteye/troubleshooting): problemas comunes y soluciones \ No newline at end of file diff --git a/docs/es/agenteye/python-sdk.mdx b/docs/es/agenteye/python-sdk.mdx new file mode 100644 index 00000000..57a90764 --- /dev/null +++ b/docs/es/agenteye/python-sdk.mdx @@ -0,0 +1,383 @@ +--- +title: "Python SDK" +description: "Documentación del SDK de Python de AgentEye." +--- + + +El SDK de Python de AgentEye te ofrece visibilidad completa sobre el comportamiento de tus agentes (cada ejecución, llamada a herramienta, solicitud al modelo, hook e intervención humana), para que puedas depurarlos, auditarlos y evaluarlos. Instrumenta el código de tu agente escribiendo eventos estructurados en archivos JSONL locales; el daemon recolector los recoge y los envía automáticamente a la plataforma. + +--- + +## Instalación + +Descarga el wheel desde GitHub Releases usando tu `AGENTEYE_TOKEN`. Si aún no tienes un token, consulta [Configuración del token de GitHub](/es/agenteye/github-token) para ver los pasos de configuración y los permisos necesarios. + +**Usando `gh` CLI + pip:** + +```bash +VERSION=0.0.1b9 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "python-sdk/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-*.whl' +pip install "agenteye-${VERSION}-py3-none-any.whl" +``` + +**Usando `gh` CLI + uv:** + +```bash +VERSION=0.0.1b9 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "python-sdk/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-*.whl' +uv add "./agenteye-${VERSION}-py3-none-any.whl" +``` + +**Usando curl (sin `gh` CLI):** + +```bash +VERSION=0.0.1b9 +curl -fsSL \ + -H "Authorization: Bearer $AGENTEYE_TOKEN" \ + -L \ + "https://github.com/agenteye-enterprise/releases/releases/download/python-sdk%2Fv${VERSION}/agenteye-${VERSION}-py3-none-any.whl" \ + -o "agenteye-${VERSION}-py3-none-any.whl" +pip install "agenteye-${VERSION}-py3-none-any.whl" +``` + +--- + +## Inicio rápido + +```python +import agenteye + +agenteye.configure(environment="production") + +agenteye.event.agent_start(session_id="run-001", agent_id="planner", goal="answer user query") + +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", + input={"query": "latest AI research"}, +) + +agenteye.event.tool_result( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", + output={"results": ["..."]}, +) + +agenteye.event.agent_end(session_id="run-001", agent_id="planner", outcome="success") +``` + +--- + +## configure() + +```python +agenteye.configure( + base_dir=None, # Path | str | None. Por defecto: $AGENTEYE_HOME o ~/.agenteye + flush_interval=0.5, # float, segundos entre ciclos de escritura + environment=None, # str | None. Etiqueta del entorno de despliegue +) +``` + +Llama a esta función una sola vez antes de cualquier llamada a `event.*`. Es seguro omitirla; los valores por defecto funcionan sin configuración adicional. Todos los argumentos son solo por nombre (keyword-only); pásalos por nombre tal como se muestra arriba. + +Cuando `base_dir` es `None` (el valor por defecto), el SDK lee `$AGENTEYE_HOME` si está definida; de lo contrario, recurre a `~/.agenteye`. Esto coincide con la resolución propia del recolector, de modo que una única variable de entorno `AGENTEYE_HOME` configura el spool de eventos compartido tanto para el SDK como para el recolector, lo cual es necesario en despliegues sidecar o de pod único donde ambos procesos deben acordar la ruta del spool. + +--- + +## Entorno + +Etiqueta cada evento con un entorno de despliegue (`production`, `staging`, `qa`, `canary`, etc.). Configúralo una sola vez; el SDK lo adjunta automáticamente a cada evento. + +**Opción 1: mediante `configure()`:** + +```python +agenteye.configure(environment="production") +``` + +**Opción 2: mediante variable de entorno:** + +```bash +export AGENTEYE_ENVIRONMENT=production +``` + +**Prioridad:** `configure(environment=...)` tiene precedencia sobre la variable de entorno. Si ninguno está definido, el valor por defecto es `"dev"`. + +El valor del entorno aparece como filtro de primer nivel en el dashboard y se almacena como columna indexada en el servidor para consultas rápidas. + +**Restricción:** los valores de entorno **no deben contener una coma literal `,`**. Los filtros del dashboard utilizan selección múltiple separada por comas en la URL (`?environment=prod,staging`), por lo que un entorno llamado `prod,blue` se dividiría en dos valores. Los eventos con entornos que contienen comas son rechazados durante la ingesta. + +--- + +## Referencia de eventos + +Todos los métodos de evento requieren estos dos campos: + +| Campo | Tipo | Descripción | +|---|---|---| +| `session_id` | `str` | Identifica la ejecución principal del agente | +| `agent_id` | `str` | Identifica qué agente dentro de la sesión emitió el evento | + +Todos los métodos también aceptan `**kwargs` arbitrarios para metadatos personalizados (consulta [Campos personalizados](#custom-fields)). + +--- + +### `event.agent_start()` + +Se emite cuando un agente comienza a trabajar. + +```python +agenteye.event.agent_start( + session_id="run-001", + agent_id="planner", + goal="answer user query", # str | None + parent_id=None, # str | None - agent_id padre para agentes anidados +) +``` + +--- + +### `event.agent_end()` + +Se emite cuando un agente termina su trabajo. + +```python +agenteye.event.agent_end( + session_id="run-001", + agent_id="planner", + outcome="success", # str | None + summary="Answered query", # str | None +) +``` + +--- + +### `event.tool_use()` + +Se emite cuando un agente invoca una herramienta. Empareja con `tool_result`; el SDK calcula automáticamente `duration_ms`. + +```python +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="web_search", # str, obligatorio + tool_call_id="toolu_01", # str, obligatorio - clave de correlación para el tool_result correspondiente + input={"query": "..."}, # dict | None +) +``` + +--- + +### `event.tool_result()` + +Se emite cuando una herramienta devuelve un resultado. Se correlaciona con `tool_use` mediante `tool_call_id`. + +```python +agenteye.event.tool_result( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", # debe coincidir con el tool_use previo + output={"results": ["..."]}, # Any | None + error=None, # str | None - se define si la herramienta lanzó una excepción + # duration_ms se calcula automáticamente - no lo pases +) +``` + +--- + +### `event.model_request()` + +Se emite justo antes de enviar un prompt a un LLM. + +```python +agenteye.event.model_request( + session_id="run-001", + agent_id="planner", + model="claude-sonnet-4-6", # str | None + messages=[ # list[dict] | None - turnos de conversación + {"role": "user", "content": "..."}, + ], + system="You are helpful.", # Any | None - str o lista de bloques de contenido + tools=[ # list[dict] | None - esquemas de herramientas ofrecidas al modelo + {"name": "search", "input_schema": {"type": "object"}}, + ], +) +``` + +Las entradas de `messages` aceptan tanto un `content` de cadena de texto simple como un `content` de lista de bloques al estilo Anthropic. Los parámetros de muestreo (`temperature`, `max_tokens`, etc.) pueden pasarse como kwargs adicionales. + +--- + +### `event.model_response()` + +Se emite cuando el LLM devuelve una respuesta. + +```python +agenteye.event.model_response( + session_id="run-001", + agent_id="planner", + model="claude-sonnet-4-6", # str | None + stop_reason="end_turn", # str | None + input_tokens=1024, # int | None + output_tokens=256, # int | None + content=[ # Any | None - str, o lista de bloques de contenido + {"type": "text", "text": "..."}, + ], + role="assistant", # str | None +) +``` + +`content` acepta tanto una cadena de texto simple (proveedores genéricos) como una lista de bloques de contenido al estilo Anthropic. Las llamadas a herramientas viven dentro de `content` como bloques `{"type": "tool_use", ...}`, sin un campo `tool_calls` separado. + +--- + +### `event.hook_triggered()` + +Se emite cuando se activa un hook. Empareja con `hook_completed`; el SDK calcula automáticamente `duration_ms`. + +```python +agenteye.event.hook_triggered( + session_id="run-001", + agent_id="planner", + hook_name="pre_tool_use", # str, obligatorio + hook_id="hook-abc", # str, obligatorio - clave de correlación + trigger_event="tool_use", # str | None + input={"tool": "search"}, # Any | None +) +``` + +--- + +### `event.hook_completed()` + +Se emite cuando un hook finaliza. Se correlaciona con `hook_triggered` mediante `hook_id`. + +```python +agenteye.event.hook_completed( + session_id="run-001", + agent_id="planner", + hook_name="pre_tool_use", + hook_id="hook-abc", # debe coincidir con el hook_triggered previo + outcome="allow", # str | None + output=None, # Any | None + error=None, # str | None + # duration_ms se calcula automáticamente - no lo pases +) +``` + +--- + +### `event.error()` + +Se emite cuando ocurre un error no controlado. + +```python +agenteye.event.error( + session_id="run-001", + agent_id="planner", + error_type="TimeoutError", # str, obligatorio + message="timed out", # str, obligatorio + traceback="Traceback...", # str | None +) +``` + +--- + +## Eventos de supervisión humana + +Los eventos de supervisión humana te permiten controlar los momentos en que una persona interviene en la ejecución del agente (esperando aprobación, proporcionando información, pausando o deteniendo el agente). Te permiten medir cuánto tiempo tardan los humanos en responder (el SDK calcula automáticamente `duration_ms` en los eventos emparejados), auditar quién pausó o interrumpió un agente, y construir flujos de trabajo de aprobación y supervisión que aparecen en el dashboard. + +### `event.human_wait()` + +Se emite cuando el agente pausa su ejecución para esperar que un humano proporcione información. Empareja con `human_input`; el SDK calcula automáticamente `duration_ms` (el tiempo que tardó el humano en responder). + +```python +agenteye.event.human_wait( + session_id="run-001", + agent_id="planner", + input_id="inp-abc", # str, obligatorio - clave de correlación para el human_input correspondiente + prompt="Do you approve this action?", # str | None - la pregunta mostrada al humano + options=["approve", "reject", "defer"], # list[str] | None - opciones presentadas al humano + reason="approval_required", # str | None - razón por la que el agente está esperando +) +``` + +### `event.human_input()` + +Se emite cuando un humano proporciona información y el agente se reanuda. Se correlaciona con `human_wait` mediante `input_id`. `duration_ms` se calcula automáticamente y no debe ser pasado por el llamante. + +```python +agenteye.event.human_input( + session_id="run-001", + agent_id="planner", + input_id="inp-abc", # str, obligatorio - debe coincidir con el human_wait previo + response="approve", # str | None - la respuesta del humano (texto libre u opción seleccionada) + # duration_ms se calcula automáticamente - no lo pases +) +``` + +### `event.human_pause()` + +Se emite cuando un humano pausa activamente el agente (p. ej., mediante un control del dashboard). El agente queda suspendido pero no finalizado. + +```python +agenteye.event.human_pause( + session_id="run-001", + agent_id="planner", + reason="user_requested", # str | None + user_id="usr_42", # str | None - quién pausó el agente +) +``` + +### `event.human_interrupt()` + +Se emite cuando un humano detiene activamente el agente durante su ejecución. A diferencia de `human_pause`, el trabajo del agente se termina en lugar de suspenderse. + +```python +agenteye.event.human_interrupt( + session_id="run-001", + agent_id="planner", + reason="output_incorrect", # str | None + user_id="usr_42", # str | None - quién interrumpió el agente + at_step="tool_use:web_search", # str | None - qué estaba haciendo el agente cuando fue detenido +) +``` + +--- + +## Campos personalizados + +Cualquier argumento de palabra clave adicional se añade al evento después de los campos estándar: + +```python +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="db_query", + tool_call_id="toolu_02", + tenant_id="acme", # campo personalizado + region="us-east-1", # campo personalizado +) +``` + +`timestamp`, `type` y `environment` son campos reservados y generan un `ValueError` (`Reserved field names cannot be used as custom fields: [...]`) si se pasan como campos personalizados. `session_id` y `agent_id` son parámetros obligatorios en cada método de evento y no pueden suministrarse una segunda vez; Python genera un `TypeError` si lo haces. Define el entorno con `configure(environment=...)` (o la variable `AGENTEYE_ENVIRONMENT`) en su lugar. + +--- + +## Cómo se escriben los eventos + +Los eventos se almacenan en memoria y se vuelcan al disco cada `flush_interval` segundos (500 ms por defecto). Cada volcado escribe un archivo JSONL: + +``` +~/.agenteye/events/event-2026-04-01T12-00-00-000Z.jsonl +``` + +El recolector monitorea este directorio y sube los archivos automáticamente. No necesitas gestionar estos archivos directamente. \ No newline at end of file diff --git a/docs/es/agenteye/single-pod-deployment.mdx b/docs/es/agenteye/single-pod-deployment.mdx new file mode 100644 index 00000000..5a9a7d6a --- /dev/null +++ b/docs/es/agenteye/single-pod-deployment.mdx @@ -0,0 +1,484 @@ +--- +title: "Despliegue en Pod Único: Collector + Application Sidecar en EKS" +description: "Documentación de AgentEye para despliegue en pod único: Collector + Application Sidecar en EKS." +--- + + +Ejecuta tu aplicación y el colector de AgentEye **en el mismo Pod de Kubernetes** para que la telemetría nunca cruce un límite de red durante la recolección. El SDK de tu aplicación y el colector comparten un único spool de eventos dentro del pod, lo que permite una transferencia de telemetría de baja latencia sin necesidad de exponer puertos localhost, sin service mesh que atravesar, y con el ciclo de vida del colector vinculado directamente a la carga de trabajo que monitoriza. El certificado de cliente mTLS que presenta el colector se entrega directamente en tu pod desde AWS Secrets Manager, por lo que la rotación de credenciales no requiere ninguna manipulación manual de archivos de tu parte. + +El modelo sidecar + spool compartido que se describe aquí es agnóstico a la nube; dos contenedores que comparten un spool de eventos `emptyDir` funciona en cualquier distribución de Kubernetes. Solo la ruta de entrega de certificados de esta guía (AWS Secrets Manager + el Secrets Store CSI Driver + IRSA) es específica de AWS / EKS. Si ejecutas en otro entorno, mantén la distribución del pod y el spool y sustituye el mecanismo de montaje de secretos de tu plataforma para las Fases 2 y 3. + +> **Cuándo usar este patrón.** Elige el pod único cuando tu aplicación no deba llamar a través de un límite de red para alcanzar el colector (IPC en pod de baja latencia, acoplamiento estrecho del ciclo de vida, aislamiento de pod por tenant). Para flotas multi-aplicación que comparten un colector por nodo o por clúster, consulta [enterprise-docs/kubernetes-deployment.md](/es/agenteye/kubernetes-deployment) en su lugar. + +--- + +## Resumen + +``` +┌──────────────────────────────── Pod ─────────────────────────────────┐ +│ │ +│ ┌──────────────────────┐ ┌──────────────────────┐ │ +│ │ your-app │ │ agenteye-collector │ │ +│ │ (SDK writes JSONL) │ │ (sweeps events/, │ │ +│ │ │ │ uploads over mTLS) │ │ +│ └──────────┬───────────┘ └──────────┬───────────┘ │ +│ │ writes reads │ │ +│ ▼ ▼ │ +│ ┌────────────────────────────────────────────────────┐ │ +│ │ emptyDir: /var/lib/agenteye/{events,failed}/ │ │ +│ │ (AGENTEYE_HOME - shared event spool) │ │ +│ └────────────────────────────────────────────────────┘ │ +│ ▲ │ +│ │ reads cert │ +│ ┌────────┴─────────┐ │ +│ │ CSI (read-only): │ │ +│ │ /etc/agenteye/ │ │ +│ │ tls/client.{crt, │ │ +│ │ key}, ca.crt │ │ +│ └────────┬─────────┘ │ +└───────────────────────────────────────────────────┼──────────────────┘ + │ mounted by + │ Secrets Store CSI + │ (AWS provider + + │ IRSA) + ┌────────┴──────────┐ + │ AWS Secrets │ + │ Manager │ + │ agenteye/mtls- │ + │ client/ │ + └────────┬──────────┘ + ▲ + │ push on issue / + │ renewal + ┌────────┴──────────┐ + │ Exosphere │ + │ delivers the cert │ + │ bundle into your │ + │ Secrets Manager │ + │ on renewal │ + └───────────────────┘ + +Outbound: collector → AGENTEYE_URL (mTLS, using the CSI-mounted cert). +``` + +Dos flujos de datos, dos volúmenes: + +- **Eventos (en el pod):** el SDK de tu aplicación escribe archivos `.jsonl` en el `emptyDir` compartido en `$AGENTEYE_HOME/events/`; el sweeper del colector los lee y los sube. Sin puerto localhost, sin loopback, transferencia pura mediante sistema de archivos compartido. +- **Certificado mTLS (pod ← nube):** el Secrets Store CSI Driver monta el bundle de certificados desde Secrets Manager en un volumen de solo lectura en `/etc/agenteye/tls/`, con alcance al contenedor del colector. + +**Dos partes independientes:** + +| Parte | Responsabilidad | +|---|---| +| Exosphere | Emite el certificado de cliente mTLS y entrega el bundle en el Secrets Manager de **tu** cuenta de AWS bajo un nombre estable. Vuelve a publicar el bundle renovado en el mismo secreto antes de su expiración. | +| Tú | Instala el Secrets Store CSI Driver, otorga al ServiceAccount del pod acceso de lectura al secreto vía IRSA, y aplica el manifiesto del Pod. Eso es todo. | + +--- + +## Prerequisitos + +### En tu cuenta de AWS / clúster de EKS + +- Un clúster de EKS con un **proveedor OIDC** asociado. Verifica con: + + ```bash + aws eks describe-cluster --name \ + --query "cluster.identity.oidc.issuer" --output text + ``` + + Si el comando devuelve una URL `https://oidc.eks.…`, OIDC está habilitado. Si no, asocia uno: + + ```bash + eksctl utils associate-iam-oidc-provider \ + --cluster --approve + ``` + +- El [Secrets Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/) y el [proveedor de AWS](https://github.com/aws/secrets-store-csi-driver-provider-aws) instalados en el clúster (ver § Fase 2). + +- AWS CLI v2 y `kubectl` en tu estación de trabajo. + +### Coordinación con Exosphere + +Antes de desplegar, Exosphere entrega el bundle de cliente mTLS en el Secrets Manager de tu cuenta de AWS y proporciona: + +- El **nombre del secreto** (convención: `agenteye/mtls-client/`) +- La **región de AWS** donde vive el secreto +- La **URL del backend de AgentEye** para configurar el colector +- Tu **API key** del colector (ver [enterprise-docs/api-keys.md](/es/agenteye/api-keys)) + +--- + +## Fase 1: Lo que entrega Exosphere + +No generas el certificado de cliente mTLS tú mismo. Exosphere lo emite y entrega el bundle directamente en el Secrets Manager de tu cuenta de AWS, de modo que el único material de credenciales que llega a tu entorno es el secreto terminado y listo para montar. + +Lo que llega a tu cuenta: + +| Propiedad | Valor | +|---|---| +| Nombre del secreto | `agenteye/mtls-client/` (estable entre renovaciones) | +| Región | La región de AWS que designaste para tu clúster de EKS | +| Contenido | Un único secreto JSON con tres claves (`client.crt`, `client.key` y `ca.crt`), cada una con el material codificado en PEM | +| Etiqueta | `AgentEyeCluster=` | + +En la renovación, el mismo secreto se actualiza en el lugar con una nueva versión, por lo que el ARN y el nombre nunca cambian; tu `SecretProviderClass` y la política de IAM siguen funcionando sin modificaciones. Para el ciclo de vida del certificado (validez, cadencia de renovación, alertas de expiración), consulta [enterprise-docs/kubernetes-deployment.md](/es/agenteye/kubernetes-deployment). + +--- + +## Fase 2: Instalar el Secrets Store CSI Driver + proveedor de AWS + +Omite este paso si ya ejecutas otra carga de trabajo que monta secretos de AWS vía CSI. + +```bash +# CSI Driver +helm repo add secrets-store-csi-driver \ + https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts +helm install -n kube-system csi-secrets-store \ + secrets-store-csi-driver/secrets-store-csi-driver \ + --set syncSecret.enabled=true \ + --set enableSecretRotation=true \ + --set rotationPollInterval=1h + +# AWS provider +kubectl apply -f \ + https://raw.githubusercontent.com/aws/secrets-store-csi-driver-provider-aws/main/deployment/aws-provider-installer.yaml +``` + +**Verificar:** + +```bash +kubectl get pods -n kube-system | grep -E 'csi-secrets-store|aws-provider' +``` + +Esperado: `Running` para todos los pods. + +> **¿Por qué `rotationPollInterval=1h`?** Cuando Exosphere publica un certificado renovado, Secrets Manager se actualiza en el lugar. El CSI Driver vuelve a leer el secreto en este intervalo y reescribe los archivos montados. El colector lee los archivos de certificado una vez al iniciar, por lo que comienza a presentar el certificado renovado solo tras un reinicio del proceso; consulta § Rotación de certificados para saber cómo activar uno. + +--- + +## Fase 3: Otorgar al pod acceso de lectura al secreto (IRSA) + +### 3.1 Crear la política de IAM + +Guarda como `agenteye-mtls-reader-policy.json`: + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "ReadAgentEyeMtlsBundle", + "Effect": "Allow", + "Action": [ + "secretsmanager:GetSecretValue", + "secretsmanager:DescribeSecret" + ], + "Resource": "arn:aws:secretsmanager:::secret:agenteye/mtls-client/-*" + } + ] +} +``` + +Sustituye ``, `` y ``. El `-*` al final coincide con el sufijo aleatorio de seis caracteres que AWS añade a cada ARN de secreto. + +Crea la política: + +```bash +aws iam create-policy \ + --policy-name AgentEyeMtlsReader- \ + --policy-document file://agenteye-mtls-reader-policy.json +``` + +### 3.2 Crear el rol de IAM y vincularlo al ServiceAccount del pod + +```bash +eksctl create iamserviceaccount \ + --name agenteye-pod \ + --namespace \ + --cluster \ + --role-name AgentEyePodRole- \ + --attach-policy-arn arn:aws:iam:::policy/AgentEyeMtlsReader- \ + --approve +``` + +Esto crea un `ServiceAccount` llamado `agenteye-pod` con la anotación `eks.amazonaws.com/role-arn` apuntando al nuevo rol. + +### 3.3 Permisos de IAM requeridos: resumen + +| Permiso | Alcance | Por qué | +|---|---|---| +| `secretsmanager:GetSecretValue` | `arn:aws:secretsmanager:::secret:agenteye/mtls-client/-*` | El CSI Driver lee el bundle de certificados en cada montaje y tick de rotación. | +| `secretsmanager:DescribeSecret` | el mismo | El CSI Driver llama a `DescribeSecret` para detectar cambios de versión entre sondeos. | + +**No otorgues** `secretsmanager:PutSecretValue`, `secretsmanager:UpdateSecret` ni `secretsmanager:DeleteSecret` al pod. El pod solo lee el secreto; escribir nuevas versiones en él es responsabilidad de Exosphere cuando se emite o renueva el certificado. + +Si el secreto está cifrado con una clave KMS gestionada por el cliente (no la clave predeterminada `aws/secretsmanager`), también otorga: + +```json +{ + "Effect": "Allow", + "Action": ["kms:Decrypt"], + "Resource": "arn:aws:kms:::key/", + "Condition": { + "StringEquals": { + "kms:ViaService": "secretsmanager..amazonaws.com" + } + } +} +``` + +--- + +## Fase 4: Desplegar el Pod + +### 4.1 SecretProviderClass + +`agenteye-mtls-spc.yaml`: + +```yaml +apiVersion: secrets-store.csi.x-k8s.io/v1 +kind: SecretProviderClass +metadata: + name: agenteye-mtls + namespace: +spec: + provider: aws + parameters: + objects: | + - objectName: "agenteye/mtls-client/" + objectType: "secretsmanager" + jmesPath: + - path: '"client.crt"' + objectAlias: "client.crt" + - path: '"client.key"' + objectAlias: "client.key" + - path: '"ca.crt"' + objectAlias: "ca.crt" +``` + +El bloque `jmesPath` indica al proveedor de AWS que divida el secreto JSON en tres archivos separados en disco. Las comillas en `'"client.crt"'` son necesarias porque JMESPath trata `.` como operador de subexpresión. + +```bash +kubectl apply -f agenteye-mtls-spc.yaml +``` + +### 4.2 Manifiesto del Pod / Deployment + +**Cómo se comunican los dos contenedores.** El SDK de AgentEye y el colector no se comunican a través de un socket de red; no hay ningún puerto HTTP local. El SDK escribe lotes de eventos como archivos `.jsonl` en `$AGENTEYE_HOME/events/`, y el colector monitoriza continuamente ese directorio y sube cada archivo. Para un pod sidecar esto significa: + +- Ambos contenedores montan el **mismo** volumen `emptyDir` en la **misma** ruta. +- Ambos contenedores configuran `AGENTEYE_HOME` con esa ruta. +- La imagen de tu aplicación debe tener el SDK de AgentEye instalado y configurado (ver [enterprise-docs/python-sdk.md](/es/agenteye/python-sdk)). + +> Cuando `AGENTEYE_HOME` no está definido, tanto el SDK como el colector usan por defecto `~/.agenteye`, y los dos contenedores tienen distintos directorios home, por lo que aterrizarían en dos spools separados y la transferencia fallaría silenciosamente. Establece `AGENTEYE_HOME` en la misma ruta explícita en **ambos** contenedores. La verificación del §4.3 y la fila correspondiente en Solución de problemas lo detectan si se omite. + +`agenteye-pod.yaml` (Deployment con una réplica, escala según sea necesario): + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-app-with-collector + namespace: +spec: + replicas: 1 + selector: + matchLabels: + app: my-app-with-collector + template: + metadata: + labels: + app: my-app-with-collector + spec: + serviceAccountName: agenteye-pod + containers: + - name: app + image: + env: + # SDK writes event JSONL files into $AGENTEYE_HOME/events/ + - name: AGENTEYE_HOME + value: /var/lib/agenteye + volumeMounts: + - name: agenteye-spool + mountPath: /var/lib/agenteye + + - name: agenteye-collector + # Pin to a versioned :v tag for production; :beta-latest + # tracks the current beta build (:latest exists only for stable releases). + image: ghcr.io/agenteye-enterprise/collector:beta-latest + args: ["start"] + env: + # Must match the app container's AGENTEYE_HOME so the collector + # sweeps the same directory the SDK writes to. + - name: AGENTEYE_HOME + value: /var/lib/agenteye + - name: AGENTEYE_URL + value: "https://ingest.example.agenteye.com/events" + - name: AGENTEYE_KEY + valueFrom: + secretKeyRef: + name: agenteye-collector-api-key + key: key + - name: AGENTEYE_TLS_CERT + value: /etc/agenteye/tls/client.crt + - name: AGENTEYE_TLS_KEY + value: /etc/agenteye/tls/client.key + # Only when the AgentEye server presents a cert not signed by a + # publicly-trusted CA (e.g. self-signed by an in-cluster issuer + # because you have no real DNS domain). The CSI mount already + # exposes ca.crt alongside the client cert/key. + - name: AGENTEYE_TLS_CA + value: /etc/agenteye/tls/ca.crt + volumeMounts: + - name: agenteye-spool + mountPath: /var/lib/agenteye + - name: agenteye-mtls + mountPath: /etc/agenteye/tls + readOnly: true + livenessProbe: + exec: + command: ["agenteye-collector", "health"] + initialDelaySeconds: 10 + periodSeconds: 30 + + volumes: + # Shared event spool between app and collector. emptyDir is fine: + # events are transient and the collector drains them before pod + # termination on graceful shutdown. + - name: agenteye-spool + emptyDir: {} + # mTLS cert bundle, mounted read-only into the collector only. + - name: agenteye-mtls + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: agenteye-mtls +``` + +El Secret `agenteye-collector-api-key` contiene la API key del colector (consulta [enterprise-docs/api-keys.md](/es/agenteye/api-keys) para el aprovisionamiento). + +**Aplicar:** + +```bash +kubectl apply -f agenteye-pod.yaml +``` + +### 4.3 Verificar + +```bash +# El pod debería estar en Running con 2/2 contenedores listos +kubectl get pods -n -l app=my-app-with-collector + +# Confirmar que el bundle de certificados fue montado +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- ls -l /etc/agenteye/tls/ +``` + +Esperado: `client.crt`, `client.key`, `ca.crt` todos presentes y de solo lectura, pertenecientes al usuario del contenedor. + +**Confirmar que el spool de eventos compartido es visible para ambos contenedores:** + +```bash +# En el colector, debería mostrar los subdirectorios events/ y failed/ que +# el colector crea automáticamente al iniciar: +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- ls /var/lib/agenteye/ + +# En la aplicación, debería mostrar el mismo contenido del directorio: +kubectl exec -n deploy/my-app-with-collector \ + -c app -- ls /var/lib/agenteye/ +``` + +Si los dos listados difieren, el volumen no está montado en ambos contenedores (o `AGENTEYE_HOME` es diferente); consulta § Solución de problemas. + +**Prueba de humo de extremo a extremo:** + +```bash +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- agenteye-collector flush +``` + +Esperado: el colector sube cualquier evento en cola e imprime un resumen `Done: N/N uploaded, 0 failed.`. Si el spool está vacío imprime `No pending files.` y sale sin validar nada — así que ejecuta esto solo después de que tu aplicación haya enviado al menos un evento. + +Ten en cuenta que `flush` sale con código distinto de cero **solo** por fallos de configuración local: configuración faltante (sin URL/key resuelta) o un certificado TLS ilegible o malformado (consulta § Solución de problemas). Una **API key incorrecta no cambia el código de salida** — la subida recibe un `401`, el archivo se mueve a `failed/`, y el comando sigue imprimiendo `[FAILED] …` por archivo más `Done: 0/N uploaded, N failed.` y sale con `0`. Para detectar una key incorrecta o una subida rechazada, lee la salida `Done:`/`[FAILED]` o comprueba si hay archivos en `$AGENTEYE_HOME/failed/`, no el código de salida. + +--- + +## Rotación de certificados + +El certificado de cliente tiene una validez de 90 días y se renueva automáticamente unos 15 días antes de su expiración; Exosphere publica entonces el bundle renovado en el mismo secreto de Secrets Manager. A partir de ahí, el flujo dentro del pod es: + +1. El secreto de Secrets Manager obtiene una nueva versión `AWSCURRENT`. El ARN y el nombre no cambian. +2. Dentro del `rotationPollInterval` (1h por defecto; ver § Fase 2), el CSI Driver lee la nueva versión y reescribe los archivos en `/etc/agenteye/tls/`. +3. El colector carga los archivos de certificado **una vez al iniciar**, por lo que sigue presentando el certificado anterior hasta que el proceso se reinicie. Para cambiar al material renovado, reinicia el colector; un reinicio progresivo es suficiente: + + ```bash + kubectl rollout restart deploy/my-app-with-collector -n + ``` + + Para automatizar esto, añade un sidecar que monitorice `/etc/agenteye/tls/` (por ejemplo con `inotifywait`) y active el rollout cuando los archivos cambien. + +Dado que el certificado anterior sigue siendo válido durante aproximadamente 15 días después de la renovación, tienes una amplia ventana para realizar el reinicio sin interrumpir la ingesta. Exosphere publica el bundle renovado por ti; la única acción rutinaria de tu parte es asegurarte de que el colector se reinicie dentro de esa ventana. + +--- + +## Solución de problemas + +| Síntoma | Causa probable | Solución | +|---|---|---| +| Pod atascado en `ContainerCreating`, los eventos muestran `MountVolume.SetUp failed for volume "agenteye-mtls"` | El proveedor CSI no puede alcanzar Secrets Manager | Verifica que IRSA esté correctamente vinculado: `kubectl describe sa agenteye-pod -n ` muestra la anotación `eks.amazonaws.com/role-arn`. Revisa CloudTrail para la llamada AssumeRole. | +| Error: `AccessDeniedException: not authorized to perform secretsmanager:GetSecretValue` | La política de IAM tiene alcance al ARN incorrecto | El sufijo del ARN del secreto es aleatorio; usa `agenteye/mtls-client/-*` con el comodín, no el ARN exacto. | +| Error: `ParameterNotFound` del proveedor de AWS | Discrepancia en el nombre del secreto entre `SecretProviderClass.objects[].objectName` y el secreto que entregó Exosphere | Confirma el nombre exacto con `aws secretsmanager list-secrets --filters Key=tag-key,Values=AgentEyeCluster`. | +| Error de `jmesPath`, solo un archivo montado | Sintaxis JMESPath | Los puntos en las claves JSON requieren comillas dobles: `'"client.crt"'`, no `client.crt`. | +| El colector registra `tls: bad certificate` tras una renovación | El CSI Driver aún no ha sondeado la nueva versión, o el colector sigue ejecutándose con el certificado anterior que cargó al iniciar | Confirma que los archivos montados se han actualizado (`ls -l /etc/agenteye/tls/`), luego reinicia el colector para cargarlos: `kubectl rollout restart deploy/my-app-with-collector -n `. Consulta § Rotación de certificados. | +| El contenedor del colector entra en bucle de reinicios con `no such file or directory: /etc/agenteye/tls/client.crt` | El volumen aún no está poblado en el primer inicio; la sonda de inicio es demasiado agresiva | Añade un pequeño retraso inicial o usa un init container que espere a que el archivo exista: `until [ -f /etc/agenteye/tls/client.crt ]; do sleep 1; done`. | +| El pod CSI Driver muere con `OOMKilled` | Los límites de memoria predeterminados son demasiado bajos para clústeres con muchos SecretProviderClasses | Aumenta con `--set linux.resources.limits.memory=200Mi` en la instalación de Helm. | +| La aplicación funciona correctamente, `agenteye-collector flush` reporta `No pending files.`, pero el dashboard de AgentEye no muestra eventos | La aplicación y el colector no comparten el spool de eventos | Verifica que (a) ambos contenedores monten el mismo `emptyDir` `agenteye-spool` en la misma ruta, y (b) ambos configuren `AGENTEYE_HOME` con esa ruta. Ejecuta las dos comprobaciones `ls /var/lib/agenteye/` del § 4.3; los listados deben coincidir. | + +**Primeros registros a revisar:** + +```bash +kubectl logs -n kube-system -l app=secrets-store-csi-driver --tail=100 +kubectl logs -n kube-system -l app=csi-secrets-store-provider-aws --tail=100 +kubectl describe pod -n -l app=my-app-with-collector +``` + +--- + +## Referencia: archivos en disco en el pod + +El pod tiene dos rutas de datos en disco: + +### Bundle de certificados mTLS: `/etc/agenteye/tls/` (CSI, solo lectura, exclusivo del colector) + +Montado por el Secrets Store CSI Driver desde AWS Secrets Manager. + +| Archivo | Contenido | Usado por el colector como | +|---|---|---| +| `client.crt` | Certificado de cliente codificado en PEM | `AGENTEYE_TLS_CERT` | +| `client.key` | Clave privada codificada en PEM | `AGENTEYE_TLS_KEY` | +| `ca.crt` | Certificado CA codificado en PEM | `AGENTEYE_TLS_CA` (opcional, solo cuando el certificado del servidor AgentEye no es de confianza pública) | + +Los tres se montan de solo lectura y pertenecen al usuario del contenedor. Son reescritos por el CSI Driver cuando rota el secreto. + +### Spool de eventos: `$AGENTEYE_HOME/` (emptyDir, lectura-escritura compartida entre ambos contenedores) + +Compartido mediante un volumen `emptyDir` llamado `agenteye-spool`. + +| Ruta | Escrito por | Leído por | Propósito | +|---|---|---|---| +| `$AGENTEYE_HOME/events/*.jsonl` | Aplicación (SDK de AgentEye) | Sweeper del colector | Lotes de eventos que el SDK ha enviado, en espera de subida. | +| `$AGENTEYE_HOME/failed/` | Colector (en caso de fallo de subida) | Tú (durante depuración) | Archivos JSONL que el colector no pudo subir tras reintentos. | +| `$AGENTEYE_HOME/config.json` | Tú (opcional) | Colector | Archivo de configuración opcional del colector (alternativa a las variables de entorno). | + +Tanto el subdirectorio `events/` como `failed/` son creados automáticamente por el colector al iniciar; no se necesita ningún `initContainer`. + +--- + +## Documentación relacionada + +- [enterprise-docs/collector-installation.md](/es/agenteye/collector-installation): opciones del binario del colector, referencia de configuración mTLS, modos demonio. +- [enterprise-docs/kubernetes-deployment.md](/es/agenteye/kubernetes-deployment): despliegue multi-pod, aspectos internos de la emisión de certificados, ciclo de vida y alertas de expiración. +- [enterprise-docs/api-keys.md](/es/agenteye/api-keys): aprovisionamiento de la API key del colector consumida por el pod. +- [enterprise-docs/troubleshooting.md](/es/agenteye/troubleshooting): índice de solución de problemas a nivel de clúster. \ No newline at end of file diff --git a/docs/es/agenteye/tenant-management.mdx b/docs/es/agenteye/tenant-management.mdx new file mode 100644 index 00000000..29531eae --- /dev/null +++ b/docs/es/agenteye/tenant-management.mdx @@ -0,0 +1,167 @@ +--- +title: "Gestión de Tenants (organizaciones y miembros)" +description: "Documentación de gestión de tenants de AgentEye (organizaciones y miembros)." +--- + + +Un único despliegue de AgentEye sirve a múltiples **organizaciones** (tenants) completamente aisladas, de modo que una sola instancia puede alojar equipos, unidades de negocio o clientes distintos sin exponer los datos de un tenant a otro. Cada fila de datos (eventos, evaluaciones, sesiones, paneles, consultas guardadas, alertas, claves API y miembros) pertenece exactamente a una organización. El aislamiento principal se aplica en el código de la aplicación: cada solicitud está limitada a su organización mediante predicados `org_id` explícitos. En ClickHouse — donde viven los eventos y evaluaciones de alto volumen — esto está respaldado por una aplicación sólida a nivel de motor: cada organización obtiene un usuario ClickHouse de solo lectura dedicado con una política de filas por organización, de modo que incluso el SQL analítico no confiable nunca puede leer las filas de otro tenant. En PostgreSQL, la seguridad a nivel de fila añade defensa en profundidad en la ruta de consulta de solo lectura (`/queries/run`), restringiendo lo que esa ruta puede ver aunque llegara a faltar un filtro a nivel de aplicación; la propia conexión de escritura del servidor se ejecuta como propietario de la tabla y por tanto opera mediante el mismo ámbito `org_id` a nivel de aplicación. + +El ciclo de vida del tenant está controlado por el operador, mientras que todo lo que los miembros hacen en el día a día permanece como autoservicio en el panel. Las organizaciones y sus membresías se crean y gestionan con la CLI **`agenteye-orgctl`**, que se incluye dentro de la imagen del servidor y se ejecuta **dentro del pod del servidor existente**. La creación y eliminación de tenants se mantienen deliberadamente fuera del panel y la API HTTP: **no existe una API HTTP ni un botón en el panel** para el ciclo de vida de los tenants, por lo que está restringido al acceso shell del clúster/pod en lugar de la superficie de la aplicación. + +Dentro de una organización, los miembros trabajan íntegramente en el panel y la API: inician sesión, cambian entre las organizaciones a las que pertenecen, gestionan sus propias claves API, crean paneles y consultas guardadas, y configuran alertas para su organización. La división es clara: los operadores aprovisionan y desactivan tenants y sus miembros a través de la CLI; los miembros gestionan todo dentro de un tenant a través de la interfaz de usuario. + +> **Los despliegues de un solo tenant no necesitan nada de esto.** Una instalación de un solo tenant funciona sin ninguna acción del operador. Todos los datos, usuarios y claves viven en una organización `default` integrada que se aprovisiona automáticamente. Solo necesitas esta guía cuando decides añadir una segunda organización. + +--- + +## Requisitos previos + +Antes de crear tu **segunda** organización (la organización `default` integrada no necesita nada): + +- **PostgreSQL 15+.** El esquema de membresía de organizaciones utiliza una clave foránea `ON DELETE SET NULL` con lista de columnas que requiere PostgreSQL 15+. Actualiza PostgreSQL antes de aprovisionar una segunda organización. +- **Un `ORG_CH_SECRET` robusto y estable.** La contraseña de ClickHouse de cada organización se deriva como `HMAC(ORG_CH_SECRET, org_id)`, por lo que el valor predeterminado de desarrollo integrado, de conocimiento público, produciría credenciales por organización derivables públicamente. `agenteye-orgctl org create` **se niega a ejecutarse mientras `ORG_CH_SECRET` no esté configurado o se deje en el valor predeterminado de desarrollo integrado**. Establece tu propio valor primero (consulta [Despliegue → variables de entorno](/es/agenteye/deployment) y, en Kubernetes, el [§2.6 de la guía de Kubernetes](/es/agenteye/kubernetes-deployment#26-multi-tenant-org-isolation-key-optional)). Mantenlo idéntico en todas las réplicas del servidor y no lo rotes de forma descuidada; rotarlo deja huérfano el usuario ClickHouse de cada organización hasta que el próximo arranque los vuelva a aprovisionar. + +--- + +## Ejecutar la CLI + +`agenteye-orgctl` se incluye en la **misma imagen que el servidor** (junto a `agenteye-server`). **No** despliegas un pod, Job o Deployment separado para ello; lo ejecutas dentro del pod del servidor que ya está en marcha, de modo que lee el mismo `DATABASE_URL`, `CLICKHOUSE_URL` y `ORG_CH_SECRET` que usa el servidor. + +**Kubernetes:** + +```bash +kubectl -n agenteye exec deploy/server -- agenteye-orgctl +``` + +**Docker Compose:** + +```bash +docker compose exec server agenteye-orgctl +``` + +Los ejemplos a continuación muestran el `agenteye-orgctl ` escueto por brevedad; antepón a cada uno la línea correspondiente según tu despliegue. + +--- + +## Referencia de comandos + +### Organizaciones + +| Comando | Qué hace | +|---|---| +| `org create --slug --name ` | Crea una nueva organización. Se niega a ejecutarse mientras `ORG_CH_SECRET` no esté configurado o se deje en el valor predeterminado de desarrollo integrado (establece el tuyo primero, consulta los Requisitos previos). Aprovisiona el usuario ClickHouse de solo lectura de la organización y la política de filas. | +| `org list` | Lista todas las organizaciones (slug, nombre y estado del ciclo de vida). | +| `org rename --slug --name ` | Cambia el nombre para mostrar de una organización. El slug (usado en URLs y claves) no cambia. | +| `org delete --slug ` | **Eliminación lógica** de la organización y borrado de su usuario ClickHouse. Los datos se **conservan**. Esto revoca el acceso y libera la credencial ClickHouse por organización, pero no borra los eventos. Reversible por los operadores; primer paso seguro antes de un purgado. | +| `org purge --slug ` | **Borrado de datos irreversible.** La organización ya debe estar `delete`d. Nunca permitido en la organización `default` integrada. Úsalo solo cuando estés seguro de que los datos del tenant deben destruirse. | + +### Miembros + +| Comando | Qué hace | +|---|---| +| `member add --org --email [--set ] [--add perm1,perm2] [--remove perm3] [--protected]` | Añade un miembro a una organización. Opcionalmente parte de un conjunto de permisos integrado, luego añade/elimina permisos individuales. `--protected` fija al miembro para que el panel no pueda eliminarlo ni degradarlo (ver más abajo). El nuevo miembro recibe un OTP en su primer inicio de sesión en el panel. | +| `member list --org ` | Lista los miembros de la organización. Las columnas de salida son `EMAIL`, `SET` (el conjunto integrado del que partió el miembro, o `-`), `PROT` (si el miembro está protegido) y `PERMISSIONS` (sus permisos efectivos). Un correo electrónico que aparece con un `*` al final es un administrador de instancia; tiene acceso a todas las organizaciones. | +| `member update --org --email [--set ...] [--add ...] [--remove ...] [--protected \| --unprotect]` | Cambia los permisos de un miembro y/o su indicador de protección. `--set` reemplaza desde un conjunto integrado; `--add` / `--remove` ajustan permisos individuales; `--protected` / `--unprotect` activan o desactivan la protección. Pasar solo `--protected`/`--unprotect` (sin indicadores de concesión) cambia únicamente la protección y deja los permisos existentes intactos. | +| `member remove --org --email ` | Elimina un miembro de la organización. Se niega si el miembro está protegido; primero aplica `--unprotect`. (Una persona puede ser miembro de varias organizaciones; esto solo afecta a la organización indicada.) | + +Una persona puede ser miembro de más de una organización con permisos **distintos** en cada una, p. ej., administrador en una organización y de solo lectura en otra. Cada membresía se administra de forma independiente por organización: otorgar o cambiar los permisos de una persona en una organización no tiene ningún efecto sobre su membresía en ninguna otra. + +### Miembros protegidos (un administrador de organización no eliminable) + +La protección garantiza que una organización nunca pueda bloquearse accidentalmente a sí misma en la autogestión. Por defecto, los propios administradores de una organización pueden añadirse y eliminarse mutuamente a través de la página de usuarios de autoservicio del panel, por lo que podrían eliminar al último administrador y dejar la organización sin nadie que la gestione. + +![La página de Usuarios: una tarjeta por usuario del panel con su correo electrónico, permisos concedidos y controles de edición/desactivación](/agenteye/images/users.png) + +Para evitarlo, marca un miembro como **protegido**: + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member add --org acme --email owner@acme.example --set admin --protected +``` + +Un miembro protegido **no puede ser eliminado ni degradado a través del panel**; esas acciones devuelven un error. Solo un operador puede modificarlo, y únicamente a través de esta CLI: ejecuta primero `member update --org acme --email owner@acme.example --unprotect`, luego elimina o degrada. Esto garantiza que cada organización conserve al menos un administrador que sus propios miembros no puedan bloquear, manteniendo el control del tenant exclusivamente en manos del operador. La protección es **por organización**; proteger a alguien en una organización no tiene ningún efecto sobre su membresía en otra. + +### Conjuntos de permisos integrados + +`--set` acepta uno de tres conjuntos integrados, aplicados por organización: + +| Conjunto | Destinado a | +|---|---| +| `admin` | Acceso completo dentro de la organización, incluida la gestión de las claves API y usuarios de la organización. | +| `standard` | Uso cotidiano: leer y ejecutar consultas, crear paneles, reconocer incidentes. | +| `read-only` | Acceso de solo visualización a los datos y paneles de la organización. | + +Parte de un conjunto con `--set`, luego ajusta con `--add` / `--remove` usando los tokens de permisos individuales listados en [Claves API](/es/agenteye/api-keys). Los propios tokens de permisos son idénticos a los utilizados para las claves API. + +--- + +## Ejemplo práctico + +Aprovisiona un nuevo tenant `acme`, añade su primer administrador, permite que genere una clave y luego desactiva la organización. + +**1. Crear la organización** (`ORG_CH_SECRET` ya debe estar configurado con un valor robusto y estable, no sin configurar ni con el valor predeterminado de desarrollo integrado): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org create --slug acme --name "Acme Corp" +``` + +**2. Añadir el primer miembro como administrador de la organización:** + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member add --org acme --email alice@acme.example --set admin +``` + +Alice recibe un OTP la primera vez que inicia sesión en el panel. A partir de entonces trabaja íntegramente en la interfaz de usuario bajo el prefijo de URL de su organización (p. ej., `/acme/sessions`). + +**3. Generar una clave API por organización (en el panel):** + +El operador **no** genera claves de datos por organización desde la CLI. Alice (o cualquier miembro de la organización con `keys:create`) crea claves de colector/panel para la organización `acme` desde la página **Keys** del panel. Cada clave que crea se marca automáticamente con su organización y solo puede leer o escribir datos de `acme`. Consulta [Claves API](/es/agenteye/api-keys). + +**4. Ajustar un miembro posteriormente:** + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member update --org acme --email alice@acme.example --add alerts:write + +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member list --org acme +``` + +**5. Eliminación lógica de la organización** (revoca el acceso y elimina su usuario ClickHouse; los datos se conservan): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org delete --slug acme +``` + +**6. Purgar la organización** (irreversible; solo después de una eliminación lógica; nunca la organización `default`): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org purge --slug acme +``` + +En Docker Compose, reemplaza cada prefijo `kubectl -n agenteye exec deploy/server --` con `docker compose exec server`. + +--- + +## División de responsabilidades + +Todo lo que un miembro de la organización necesita en el día a día es autoservicio en el panel y la API, limitado automáticamente a su organización actual: + +- **Las claves API por organización** son creadas y gestionadas por los miembros de la organización en el panel (o a través de la API de claves con una clave que lleve `keys:create`). La CLI **no** genera claves de datos. Consulta [Claves API](/es/agenteye/api-keys). +- **El cambio de organización** está integrado en el panel; los miembros cambian entre las organizaciones a las que pertenecen desde el selector de organizaciones, y las páginas con ámbito de organización viven bajo `//…`. +- **Los paneles, consultas guardadas, alertas y todo el uso de datos** ocurren íntegramente en la interfaz de usuario y la API, limitados a la organización actual del miembro. + +El operador, usando `agenteye-orgctl`, es responsable únicamente del **ciclo de vida** de la organización y los miembros: crear / renombrar / eliminar / purgar una organización, y añadir / listar / actualizar / eliminar un miembro. + +--- + +## Ver también + +- [Despliegue](/es/agenteye/deployment): `ORG_CH_SECRET` y el resto del entorno del servidor. +- [Despliegue en Kubernetes](/es/agenteye/kubernetes-deployment): el §2.6 crea el Secret `agenteye-org-ch-secret` antes de tu primera organización multi-tenant. +- [Claves API](/es/agenteye/api-keys): el modelo de clave por organización y los tokens de permisos usados por `--add` / `--remove`. +- [Resolución de problemas](/es/agenteye/troubleshooting): aprovisionamiento multi-tenant y problemas de aislamiento en ClickHouse. \ No newline at end of file diff --git a/docs/es/agenteye/troubleshooting.mdx b/docs/es/agenteye/troubleshooting.mdx new file mode 100644 index 00000000..cbadc5e5 --- /dev/null +++ b/docs/es/agenteye/troubleshooting.mdx @@ -0,0 +1,691 @@ +--- +title: "Solución de problemas" +description: "Documentación de solución de problemas de AgentEye." +--- + + +Esta guía mapea los síntomas más frecuentes en producción hacia diagnósticos y soluciones concretas, para que puedas resolver incidentes con las herramientas que ya tienes, sin necesidad de montar infraestructura de observabilidad adicional. Cubre el servidor, el colector, el dashboard, el asistente de IA, el SDK de Python, el monitoreo de salud y certificados, las copias de seguridad, el análisis con ClickHouse y la multi-tenencia. + +Las páginas del dashboard tienen alcance de organización bajo `//…`, y el stream de eventos es la página principal de la organización (`//`). Los nombres de página en esta guía (por ejemplo `/sessions`, `/queries`) se refieren a esas rutas con alcance de organización. + +--- + +## Ver logs + +AgentEye no incluye una pila de logging ni monitoreo. Tanto el servidor como el dashboard escriben logs estructurados en **stdout**, por lo que puedes leerlos directamente con `kubectl` o `docker`; no se necesita ningún agregador. + +### Kubernetes + +Sigue los logs en tiempo real del servidor y del dashboard: + +```bash +kubectl logs -n agenteye -l app=server -f --timestamps +kubectl logs -n agenteye -l app=dashboard -f --timestamps +``` + +Variantes útiles: + +| Objetivo | Comando | +|---|---| +| Últimas 200 líneas (sin seguimiento) | `kubectl logs -n agenteye -l app=server --tail=200 --timestamps` | +| Logs del crash anterior | `kubectl logs -n agenteye --previous` | +| Seguir todas las réplicas a la vez | `kubectl logs -n agenteye -l app=server --max-log-requests=10 -f` | +| Postgres (StatefulSet) | `kubectl logs -n agenteye postgres-0 -f` | + +### Docker Compose + +```bash +docker logs -f agenteye-server +docker logs -f agenteye-dashboard +``` + +### Correlacionar una solicitud individual entre dashboard y servidor + +Cada solicitud del dashboard se etiqueta con un `request_id` y se propaga al servidor mediante la cabecera `x-request-id`. El servidor lo incluye en sus cabeceras de respuesta y en cada línea de log que emite para esa solicitud. Para rastrear una solicitud de extremo a extremo: + +1. Captura el id desde la cabecera de respuesta, por ejemplo: + ```bash + curl -i https://dashboard.example.com/api/events | grep -i x-request-id + # x-request-id: 9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a + ``` +2. Filtra los logs de ambos pods por ese id: + ```bash + REQ=9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a + kubectl logs -n agenteye -l app=dashboard --tail=5000 | grep "$REQ" + kubectl logs -n agenteye -l app=server --tail=5000 | grep "$REQ" + ``` + +Verás las líneas `proxy passthrough`, `withAuth: authorized` y `upstream response` del dashboard junto con el par `http request received` / `http request completed` del servidor, todos compartiendo el mismo `request_id`. + +### Logs JSON y `jq` + +Configura `AE_LOG_JSON=1` en el dashboard (está activado por defecto cuando `NODE_ENV=production`) para emitir un objeto JSON por línea. Luego filtra de forma estructurada: + +```bash +kubectl logs -n agenteye -l app=dashboard --tail=5000 \ + | jq 'select(.level == "warn" or .level == "error")' + +kubectl logs -n agenteye -l app=dashboard --tail=5000 \ + | jq 'select(.route == "POST /api/keys")' +``` + +El servidor en Rust emite pares de trazabilidad `key=value` que funcionan bien con grep sin necesidad de `jq`: + +```bash +kubectl logs -n agenteye -l app=server --tail=5000 | grep 'status=5' # 5xx +kubectl logs -n agenteye -l app=server --tail=5000 | grep 'actor_key_id=' +``` + +### Aumentar el nivel de verbosidad + +| Componente | Variable de entorno | Ejemplo | +|---|---|---| +| Servidor | `RUST_LOG` | `RUST_LOG=debug` o `RUST_LOG=agenteye_server=debug,info` | +| Dashboard | `AE_LOG_LEVEL` | `AE_LOG_LEVEL=debug` | + +`debug` en el servidor añade una línea `api key authenticated` por cada autenticación. `debug` en el dashboard añade líneas `upstream request`, `session validated` y `proxy passthrough`. + +### Retención de logs + +El stdout del contenedor es efímero; kubelet rota los archivos de log (por defecto ~10 MiB por contenedor) y conserva un número reducido en disco. Una vez que el pod se elimina, los logs desaparecen. Si necesitas retención prolongada o búsqueda entre pods, apunta tu clúster a un colector de logs (Loki, CloudWatch, Cloud Logging, Datadog, etc.) que siga `/var/log/containers/`. AgentEye no requiere ni prescribe ninguna opción específica. + +--- + +## Problemas de autenticación + +### `docker pull` falla con "unauthorized" + +Asegúrate de haber autenticado Docker contra GHCR con tu `AGENTEYE_TOKEN`: + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +El token debe tener permiso `read:packages` en la organización `agenteye-enterprise`. Contacta a `support@exosphere.host` si tu token no funciona. + +### `gh release download` devuelve 404 o 401 + +- Confirma que `AGENTEYE_TOKEN` está exportado en tu shell: `echo $AGENTEYE_TOKEN` +- Confirma que estás usando `GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download ...` (la CLI `gh` lee `GITHUB_TOKEN`) +- El token necesita `contents:read` en `agenteye-enterprise/releases` + +--- + +## Problemas del servidor + +### El servidor falla con "invalid port number" + +El `POSTGRES_PASSWORD` (u otra credencial) contiene caracteres especiales de URL (`/`, `+`, `=`) que rompen el análisis de `DATABASE_URL`. Regenera la contraseña usando codificación hexadecimal: + +```bash +NEW_PASS=$(openssl rand -hex 24) +``` + +Luego actualiza el secret de Kubernetes y la contraseña en Postgres (o recrea el `.env` para Docker Compose) y reinicia el servidor. Consulta los pasos completos en [enterprise-docs/kubernetes-deployment.md](/es/agenteye/kubernetes-deployment) § "PostgreSQL credentials". + +### El servidor se cierra inmediatamente al arrancar + +Revisa los logs del contenedor: + +```bash +docker logs agenteye-server +``` + +Causas frecuentes: +- `DATABASE_URL` no está configurado o está mal formado: el servidor registrará el error y saldrá. +- Postgres no es accesible: confirma que el contenedor de Postgres o la base de datos gestionada está en ejecución y que el host/puerto son correctos. +- Las migraciones fallaron: revisa los logs en busca de errores SQL. + +### `GET /health` devuelve un código distinto de 200 o agota el tiempo de espera + +Es posible que el servidor aún esté ejecutando migraciones en el primer arranque. Espera unos segundos y vuelve a intentarlo: + +```bash +curl http://localhost:8080/health +``` + +Si el problema persiste, revisa `docker logs agenteye-server` en busca de errores. + +### `GET /ready` devuelve 503 + +`/ready` es la sonda de preparación: devuelve `503` cuando el servidor no puede alcanzar **Postgres o ClickHouse**. El cuerpo indica la dependencia que falla: + +```bash +curl -s http://localhost:8080/ready +# {"status":"not_ready","checks":{"postgres":"ok","clickhouse":"down","redis":"ok"}} +``` + +Corrige la dependencia que aparece como `down`: ¿el pod de ClickHouse/Postgres está en estado `Running`? ¿Son correctos y accesibles `CLICKHOUSE_URL` / `DATABASE_URL`? En Kubernetes el pod aparece como `NotReady` hasta que `/ready` se recupera; eso es lo esperado y es exactamente la señal sobre la que alerta el monitoreo de salud. Redis nunca es la causa: se reporta pero no falla la preparación. + +### El colector devuelve 401 Unauthorized + +La clave API del colector no tiene permiso `events:add`, o la clave ha sido desactivada. Crea una nueva clave con el permiso correcto: + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{"name":"new-collector","permissions":["events:add"]}' +``` + +### Las solicitudes autenticadas se volvieron lentas de repente (~200ms en lugar de ~5ms) + +Este es el síntoma de que Redis está caído mientras `REDIS_URL` está configurado. Cada llamada a la caché agota el tiempo de espera después de 100ms y recurre a Postgres; en las rutas de autenticación y OTP la solicitud realiza dos de estas recaídas. + +Confirma en los logs del servidor: + +``` +auth cache: L2 get failed error=redis call timed out +``` + +Resolución: + +1. `redis-cli -h ping` para confirmar que Redis es accesible en la red del clúster. +2. Si Redis estuvo caído momentáneamente y ya volvió, **reinicia los pods del servidor**. El `redis::aio::ConnectionManager` no restablece la conexión de forma fiable después de que la conexión subyacente se interrumpe; un reinicio del pod toma la nueva conexión limpiamente. Lo mismo aplica al dashboard. +3. Si por ahora no quieres ejecutar Redis, elimina `REDIS_URL` del despliegue y reinicia. Ambos servicios funcionan sin la caché (la corrección se preserva; la latencia vuelve a la línea base previa a Redis). + +### El servidor reporta `OTP request rate-limited` en los logs pero el usuario dice que solo lo intentó una vez + +Verifica si Redis era inaccesible. La ruta de respaldo usa `SELECT COUNT(*) FROM otp_codes WHERE created_at > now() - interval '15 minutes'`, que ve filas de OTP generadas anteriormente. Si el usuario ha estado haciendo clic repetidamente en "Reenviar" durante una hora, la ventana de 15 minutos puede contener aún ≥5 códigos. Resuélvelo esperando a que la ventana expire o ejecutando `DELETE FROM otp_codes WHERE user_id = $1 AND created_at > now() - interval '15 minutes'` (consola del operador). + +### Cambié `ALLOWED_EMAILS` / `SESSION_TTL_SECS` / `OTP_TTL_SECS` y reinicié; no pasó nada + +Estas variables de entorno son **valores iniciales de primer arranque únicamente**. Una vez que la tabla `settings` tiene una fila para la clave correspondiente, esa fila es la fuente de verdad; la variable de entorno se lee una sola vez en el primer arranque y luego se ignora en cada reinicio posterior. + +Para cambiarlas después del primer arranque, inicia sesión en el dashboard y edítalas en `/settings`. El cambio se aplica en segundos en todas las réplicas; no es necesario reiniciar. + +Si necesitas forzar una re-inicialización desde la variable de entorno (raro, generalmente útil solo en desarrollo), ejecuta `DELETE FROM settings WHERE key = ''` y reinicia el servidor. El proceso de arranque tomará el valor actual de la variable de entorno en el siguiente inicio. Editar via `/settings` es la ruta soportada en producción. + +--- + +## Problemas del colector + +### El colector arranca pero los eventos no aparecen en el dashboard + +1. Confirma que el colector está en ejecución: `systemctl status agenteye-collector` (Linux) o revisa el proceso. +2. Confirma que `AGENTEYE_URL` apunta a `http(s)://your-server-host:8080/events` (nota: la ruta `/events`). +3. Ejecuta un flush único para ver la salida inmediata: + ```bash + agenteye-collector flush + ``` +4. Verifica que el SDK de Python realmente está escribiendo archivos: `ls ${AGENTEYE_HOME:-~/.agenteye}/events/` +5. Si hay archivos en `${AGENTEYE_HOME:-~/.agenteye}/failed/`, las subidas están fallando. Revisa los logs del colector para ver el error, probablemente un 4xx (clave o URL incorrectos) o un problema de red. + +### Los archivos se acumulan en `$AGENTEYE_HOME/events/` y no se suben + +- Es posible que el colector no esté en ejecución. Inícialo: `agenteye-collector start`; automáticamente envía los eventos pre-existentes al arrancar. +- Verifica el estado del colector: `agenteye-collector health` +- El colector puede estar en ejecución pero sin poder llegar al servidor. Revisa las reglas del firewall entre los hosts del colector y el servidor. + +### Archivos en `$AGENTEYE_HOME/failed/` + +Los archivos se mueven a `failed/` después de agotar todos los reintentos (por defecto: 5 intentos con retroceso exponencial). Esto significa que: +- El servidor devolvió un error 4xx (clave incorrecta, URL incorrecta o problema con el payload) +- El servidor no fue accesible durante toda la ventana de reintentos + +Corrige el problema subyacente y luego vuelve a encolar manualmente: + +```bash +mv ${AGENTEYE_HOME:-~/.agenteye}/failed/*.jsonl ${AGENTEYE_HOME:-~/.agenteye}/events/ +agenteye-collector flush +``` + +### El colector reporta `network error` en cada subida (el handshake TLS falla) + +Si `curl -k` contra `AGENTEYE_URL` tiene éxito pero el binario del colector falla en cada subida con `error sending request for url (...)`, el servidor AgentEye está presentando un certificado TLS que no está firmado por una CA de confianza pública. + +La **ruta de producción** es el hostname de ingesta ACME configurado en `deploy/base/certificates/domain.env` (ver [`kubernetes-deployment.md`](/es/agenteye/kubernetes-deployment) Fase 3.1 / 4.2). Una vez que `INGEST_DOMAIN` resuelve al LB público de Traefik y cert-manager ha emitido el certificado de Let's Encrypt, los colectores verifican el certificado del servidor contra el almacén de confianza del sistema **sin necesidad de `AGENTEYE_TLS_CA`**; elimínalo de tu configuración del colector si se configuró para un despliegue anterior con certificado autofirmado. + +**Síntoma: el colector funcionaba ayer, falla hoy después de ~90 días.** Esto significa que el despliegue sigue usando el emisor `selfsigned` heredado para `ingest-tls`. El certificado de 90 días rotó y el archivo de CA fijado está desactualizado. Corrige esto de forma permanente cambiando el clúster al emisor ACME (Fase 3.1 de la guía de despliegue). Solución temporal: vuelve a extraer el certificado actual del servidor y actualiza `AGENTEYE_TLS_CA`: + +```bash +kubectl get secret ingest-tls-cert -n agenteye \ + -o jsonpath='{.data.tls\.crt}' | base64 -d > /etc/agenteye/server-ca.crt +``` + +```bash +export AGENTEYE_TLS_CA=/etc/agenteye/server-ca.crt +agenteye-collector flush +``` + +`AGENTEYE_TLS_CA` añade un ancla de confianza adicional; las raíces públicas estándar siguen siendo de confianza. + +### El certificado `ingest-tls` está atascado en `Ready: False` después del despliegue + +```bash +kubectl describe certificate ingest-tls -n agenteye +``` + +Revisa los `Events` y el `Order` / `Challenge` referenciado. Causas frecuentes: + +- **DNS no resuelve al LB público.** El validador HTTP-01 no puede alcanzar `INGEST_DOMAIN`. Verifica con `dig +short INGEST_DOMAIN`; debería resolver a la misma dirección que el `EXTERNAL-IP` del LoadBalancer `traefik-public`. cert-manager reintenta automáticamente una vez que el DNS se propaga; no es necesario eliminar el Certificate. +- **Puerto 80 bloqueado en el balanceador de carga / grupo de seguridad.** HTTP-01 requiere que el puerto 80 sea accesible desde los validadores públicos de Let's Encrypt. Si tienes un WAF o SG que restringe `:80`, ábrelo (la configuración de Traefik redirige a HTTPS, pero Boulder sigue la redirección y acepta la respuesta). +- **`dnsNames` no sustituido.** Si `kubectl get certificate ingest-tls -n agenteye -o jsonpath='{.spec.dnsNames}'` muestra `INGEST_DOMAIN_PLACEHOLDER`, omitiste el paso de `domain.env`; créalo a partir de `domain.env.example` y vuelve a aplicarlo. +- **Limitado por la tasa de Let's Encrypt.** Los pedidos fallidos repetidos para el mismo hostname activan los límites de certificados duplicados o validaciones fallidas. Espera al menos una hora antes de reintentar; revisa el estado del Order para ver el mensaje exacto del límite de tasa. + +### El certificado `dashboard-tls` está atascado en `Ready: False` / el navegador sigue mostrando una advertencia + +El mismo flujo de diagnóstico que `ingest-tls` anterior (`kubectl describe certificate dashboard-tls -n agenteye`); las causas de DNS, puerto 80, marcador de posición y límite de tasa aplican todas, más dos específicas del dashboard: + +- **`DASHBOARD_DOMAIN` resuelve al LoadBalancer incorrecto.** Debe apuntar al LB de Traefik del *dashboard*, no al de ingesta pública. Haz `dig +short` del hostname y compáralo con la dirección del LB del dashboard. +- **La instancia de Traefik del dashboard no puede servir el challenge.** Debe instalarse con el archivo de valores del dashboard incluido, que habilita un proveedor Ingress con alcance limitado para el solucionador HTTP-01 de cert-manager. Sin él, el solucionador no tiene ruta y el Order permanece `pending` indefinidamente. Actualiza la instancia con los valores proporcionados; el challenge pendiente se completará solo a continuación. +- **El LoadBalancer tenía restricciones de IP.** Los rangos de origen aplican también al puerto 80, lo que bloquea los validadores de Let's Encrypt — tanto en la emisión inicial como en cada renovación cada ~75 días. Vuelve a abrir el LB, o coordina un solucionador DNS-01 con soporte antes de restringirlo. + +Mientras la emisión falla, el dashboard sigue sirviendo su certificado anterior (o el predeterminado del ingress en una instalación nueva) — el acceso se degrada con una advertencia del navegador, nunca se interrumpe. + +### La CLI sigue omitiendo la verificación TLS después de que el dashboard obtuvo un certificado de confianza + +`--insecure` se guarda en `cli.json` al iniciar sesión. Una vez que el dashboard sirve un certificado de confianza pública, vuelve a iniciar sesión con `agenteye --base-url https:// --secure login`; la verificación se guarda nuevamente activada y la advertencia de inicio desaparece. + +--- + +## Problemas del dashboard + +### No se puede deshabilitar ni editar el usuario `ADMIN_EMAIL` + +Por diseño. El usuario que coincide con `ADMIN_EMAIL` se marca como protegido en cada arranque del servidor: el dashboard oculta el botón Deshabilitar para esa fila, y la API rechaza `DELETE /users/:id` y `PUT /users/:id` contra él con `403 Forbidden`. Un trigger de base de datos también rechaza las instrucciones `UPDATE` directas que deshabilitarían la fila protegida. + +Para rotar el administrador de arranque, cambia `ADMIN_EMAIL` en tu entorno y reinicia el servidor. El nuevo correo electrónico se hace upsert como protegido. El administrador anterior conserva el indicador de protección hasta que se elimine en la base de datos (generalmente está bien, ya que el correo anterior sigue siendo un administrador válido hasta que lo elimines explícitamente). + +### El dashboard no muestra eventos + +1. Confirma que la URL del servidor y la clave API son correctas en las variables de entorno del dashboard (`AGENTEYE_SERVER_URL`, `AGENTEYE_API_KEY`). +2. La clave API del dashboard necesita permiso `events:read`. +3. Confirma que los eventos realmente se han ingestado: `curl http://your-server:8080/events -H "Authorization: Bearer $ADMIN_KEY"` + +### `/errors` está vacío pero `/events` muestra filas rojas + +Las versiones más recientes del SDK emiten fallos como eventos `agent_end` / `tool_result` / `hook_completed` con `outcome: "error"` en el payload, en lugar de como una fila dedicada `event_type: "error"`. La página `/errors` ahora coincide con ambos: cualquier fila que el stream de `/events` pinta en rojo (explícito `event_type='error'`, payload `outcome`/`status` en el conjunto de fallos, `is_error: true`, o un campo `error` con valor verdadero) aparece en `/errors`. Si anteriormente veías "no hay errores en esta ventana" mientras había filas rojas en `/events`, actualiza el dashboard + servidor juntos (el filtro ampliado es `errored=true` en `GET /events`) y las dos vistas coincidirán. + +### `/models`, `/tools` o `/hooks` es lento o no carga en rangos de tiempo amplios + +**Síntoma:** en una tabla de eventos grande (millones de filas), abrir `/models`, `/tools` o `/hooks` — o ampliar el rango de tiempo a `7d`, `30d` o `all` — hace que los gráficos giren y luego muestren un error de carga. El servidor registra un `MEMORY_LIMIT_EXCEEDED` de ClickHouse (Código 241) o un timeout de consulta para la solicitud `latency_aggregate`. + +**Causa:** las versiones anteriores calculaban los agregados de latencia y distribución de estas páginas con una consulta que leía el `payload` JSON completo del evento sin procesar y emparejaba eventos de solicitud/respuesta con un ordenamiento y unión en memoria. La memoria máxima de la consulta crecía por tanto con el tamaño de la ventana, así que en un tenant ocupado un rango amplio podía superar el límite de memoria por consulta de ClickHouse. + +**Solución:** actualiza a una versión que incluya esta corrección. El agregado ahora solo lee las columnas compactas promovidas y empareja eventos con una agregación en streaming, por lo que la memoria máxima ya no escala con el payload sin procesar — las ventanas amplias se mantienen dentro del límite de memoria y responden en una fracción del tiempo. La mejora es completamente del lado de la consulta: se aplica a todos los datos existentes en la siguiente carga de página, sin necesidad de re-ingestión ni relleno. + +### El dashboard no carga / página en blanco + +Revisa los logs del contenedor del dashboard: + +```bash +docker logs agenteye-dashboard +``` + +La causa más frecuente es que `AGENTEYE_SERVER_URL` o `AGENTEYE_API_KEY` faltan o apuntan a un servidor inaccesible. + +### Análisis / telemetría del dashboard + +El dashboard envía análisis de uso del producto anónimos a PostHog por defecto, enrutados a través de la propia ruta `/ingest` del dashboard (un proxy inverso a `https://us.i.posthog.com`). Enviarlos de forma directa significa que los bloqueadores de anuncios del navegador no los descartan. Esto es independiente de la funcionalidad principal del dashboard: + +- Es el **contenedor del dashboard** (no el navegador) quien llega a PostHog. Si su acceso saliente a `https://us.i.posthog.com` está bloqueado, la telemetría falla silenciosamente; el dashboard funciona con normalidad y no se muestran errores a los usuarios. +- No se incluyen datos de agentes, sesiones ni eventos; solo el uso de la interfaz del dashboard. +- Para deshabilitar la telemetría por completo, configura `AE_ANALYTICS_DISABLED=1` en el contenedor del dashboard y reinicia. Ver [Telemetry & privacy](/es/agenteye/deployment#telemetry--privacy) en la guía de despliegue. + +### Análisis / telemetría de la CLI + +La CLI `agenteye` envía análisis de uso anónimos a PostHog por defecto: qué comandos se ejecutan, estado de éxito/salida y duración. Esto es independiente de la funcionalidad de la CLI: + +- La **máquina que ejecuta la CLI** llega directamente a `https://us.i.posthog.com`. Si su acceso saliente está bloqueado, la telemetría falla silenciosamente (el envío tiene un límite de tiempo, por lo que nunca retrasa un comando) y la CLI funciona con normalidad. +- No se incluyen datos de agentes, sesiones ni eventos: los **argumentos y valores de flags** del comando (URL del dashboard, token, correo electrónico, IDs de sesión, filtros de consulta) nunca se envían. +- Para deshabilitarla, configura `AGENTEYE_ANALYTICS_DISABLED=1` (o el inter-herramientas `DO_NOT_TRACK=1`) en el entorno de la CLI. Ver [Telemetry & privacy](/es/agenteye/cli#telemetry--privacy) en la guía de la CLI. + +--- + +## Problemas del asistente de IA + +Ver [enterprise-docs/assistant.md](/es/agenteye/assistant) para la configuración completa. + +### La burbuja del asistente no aparece + +La burbuja está oculta a menos que **todo** lo siguiente sea verdad: + +- El usuario conectado tiene el permiso `agent:use`. +- `AGENTEYE_AGENT_URL` está configurado en el dashboard y el servicio `agent` es accesible. +- Hay un endpoint de LLM configurado en el servicio `agent` (`ANTHROPIC_API_KEY`, un gateway via `ANTHROPIC_BASE_URL`, o Bedrock/Vertex). Sin ninguno configurado, el agente reporta "not configured" y la burbuja permanece oculta. + +Verifica el estado del agente desde el host del dashboard: `curl http://agent:9100/health` debería devolver `{"status":"ok","llm_configured":true,...}`. + +### El asistente dice que no puede leer algo + +Las herramientas están restringidas por usuario. Si un usuario no tiene `evaluations:read` (o `events:read`, `dashboards:read`), las herramientas correspondientes no se ofrecen y el asistente dirá que no puede leer esos datos. Otorga el permiso de lectura correspondiente. + +### "assistant not configured" (HTTP 503) al enviar + +El contenedor `agent` no tiene ningún endpoint de LLM configurado, o el `AGENTEYE_AGENT_TOKEN` del dashboard no coincide con el del agente. Configura ambos y reinicia. + +### El contenedor `agent` se reinicia / se queda sin memoria bajo carga + +Cada conversación genera un proceso hijo de corta duración. Asegúrate de que el contenedor se ejecute con un proceso init (la imagen usa `tini`; en Compose configura `init: true`) y dale límites de memoria adecuados. Reduce `AGENTEYE_AGENT_MAX_STEPS` si es necesario. + +--- + +## Problemas de la CLI + +### `agenteye` falla al iniciar con `ModuleNotFoundError: No module named 'click'` + +Una instalación nueva de la CLI `agenteye` en la versión **0.1.6** puede fallar al arrancar con: + +``` +ModuleNotFoundError: No module named 'click' +``` + +La versión 0.1.6 dependía de que `click` estuviera instalado indirectamente por `typer`; las versiones actuales de `typer` ya no lo incluyen, por lo que un entorno limpio termina sin el paquete. **Actualiza a la versión 0.1.7 o superior**, que depende de `click` directamente: + +```bash +pipx upgrade agenteye # si se instaló con pipx (o: pipx install --force agenteye) +uv tool upgrade agenteye # si se instaló con uv +pip install --upgrade agenteye +``` + +Ver [enterprise-docs/cli.md](/es/agenteye/cli) para orientación sobre la instalación. + +--- + +## Problemas del SDK de Python + +### No aparecen archivos en `$AGENTEYE_HOME/events/` + +El SDK almacena eventos en buffer y los vacía cada 500 ms por defecto. Si tu proceso termina antes del flush, los eventos pueden perderse. Llama a `agenteye.configure(flush_interval=0.1)` para un vaciado más rápido en scripts de corta duración, o asegúrate de que tu proceso se ejecute el tiempo suficiente para un ciclo de flush. + +Si `AGENTEYE_HOME` está configurado, verifica que el SDK esté escribiendo en `$AGENTEYE_HOME/events/` y no en `~/.agenteye/events/` (requiere SDK ≥ 0.0.1b5). + +### `ValueError: Reserved field names cannot be used as custom fields` + +Los nombres `timestamp`, `type` y `environment` están reservados y no pueden usarse como campos personalizados. Pasarlos levanta: + +``` +ValueError: Reserved field names cannot be used as custom fields: [...] +``` + +Renombra el campo personalizado que causa el conflicto. Ten en cuenta que `session_id` y `agent_id` son parámetros explícitos de la llamada al evento, no campos personalizados; pasar cualquiera de ellos nuevamente como campo personalizado levanta `TypeError`. + +--- + +## Problemas de monitoreo de salud + +### No llegan alertas a Slack (Robusta) + +Las alertas de salud de Robusta son **opcionales**; no envía nada hasta que se instala y se apunta a un canal de Slack. Verifica el release y su sink: + +```bash +kubectl get pods -n robusta # robusta-runner + robusta-forwarder deben estar Running +kubectl logs -n robusta -l app=robusta-runner --tail=50 +``` + +Causas frecuentes: el `api_key` / `slack_channel` de Slack no fueron configurados (o el token fue revocado); el `api_key` es un token de relay en la nube de Robusta (`robusta integrations slack`) pero el `disableCloudRouting: true` incluido necesita un **bot token** de Slack autohospedado (`xoxb-…`), o configura `disableCloudRouting: false`; el `scope` del sink excluye el namespace donde se ejecutan tus pods (los valores incluidos tienen alcance a `agenteye`); o aún no ha ocurrido ningún fallo. Fuerza una alerta de prueba dejando caer un pod: + +```bash +kubectl -n agenteye delete pod -l app=clickhouse # se recreará +``` + +Ver [enterprise-docs/health-monitoring.md](/es/agenteye/health-monitoring#2-pod-failure-alerting-with-robusta-opt-in) para instalación y configuración. + +### El servidor sigue alternando entre `NotReady` + +La sonda de preparación llega a `/ready`, que falla cuando Postgres o ClickHouse no son accesibles. Si el servidor alterna entre `NotReady`, una dependencia no está disponible de forma intermitente; revisa los pods de ClickHouse y Postgres y los valores de `CLICKHOUSE_URL` / `DATABASE_URL` del servidor. Confirma lo que reporta `/ready`: + +```bash +kubectl -n agenteye exec deploy/server -- sh -c 'curl -s localhost:8080/ready' +``` + +Esta sonda es deliberadamente tolerante (un umbral de fallo generoso), por lo que una alternancia sostenida indica un problema real de dependencia y no una sonda demasiado agresiva. La sonda de actividad permanece en `/health`, por lo que la alternancia de preparación **no** reiniciará el pod. + +## Problemas de monitoreo de certificados + +### El CronJob no envía notificaciones de Slack + +El CronJob `cert-renewal-check` requiere una URL de webhook de Slack almacenada en un Secret. Verifica que exista: + +```bash +kubectl get secret cert-renewal-notify-config -n agenteye +``` + +Si no existe, créalo: + +```bash +kubectl create secret generic cert-renewal-notify-config \ + --namespace agenteye \ + --from-literal=SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL" +``` + +Sin el secret, el CronJob sigue ejecutándose y registra los resultados en stdout. Revisa los logs con: + +```bash +kubectl logs -n agenteye -l job-name --tail=50 +``` + +### El certificado de cliente expiró antes de recibir una notificación + +El CronJob se ejecuta cada 12 horas. Si no ha estado en ejecución, verifica su estado: + +```bash +kubectl get cronjob cert-renewal-check -n agenteye +``` + +Desencadena una verificación manual: + +```bash +kubectl create job --from=cronjob/cert-renewal-check manual-cert-check -n agenteye +kubectl logs -n agenteye -l job-name=manual-cert-check +``` + +Para reemitir el certificado expirado inmediatamente: + +```bash +cd base/certificates/client-certs +./issue-client-cert.sh +``` + +Luego aplica el `collector-mtls-secret.yaml` regenerado en el/los clúster(es) que ejecutan tus colectores y reinícialos: + +```bash +kubectl apply -f collector-mtls-secret.yaml -n +``` + +--- + +## Problemas de copias de seguridad + +### `agenteye-backup` falla con "No space left on device" + +El CronJob `agenteye-backup` vuelca Postgres + ClickHouse en un volumen de trabajo `emptyDir` llamado `backup-tmp` (por defecto `30Gi`), luego **transmite** el archivo `tar` directamente a S3 — el archivo comprimido nunca se escribe de vuelta al espacio de trabajo, por lo que el espacio de trabajo solo necesita contener los *volcados sin procesar*, no los volcados más una segunda copia en disco del archivo. Un pod expulsado / `No space left on device` por tanto significa que los **volcados sin procesar** superan el tamaño del espacio de trabajo (el volcado de `events` de ClickHouse domina y crece con el tiempo). Revisa los logs del job fallido: + +```bash +kubectl logs -n agenteye -l job-name= +``` + +Solución: en tu overlay, aumenta el `sizeLimit` del `emptyDir` `backup-tmp` del CronJob por encima del total de tus volcados sin procesar, y asegúrate de que el almacenamiento efímero del nodo pueda realmente contenerlo (`sizeLimit` es un límite, no una reserva). Si los volcados superan el disco de un solo nodo, reemplaza el `emptyDir` con un PVC (EBS/PD) para `backup-tmp`, o comprime los volcados en el origen. + +> Las versiones anteriores escribían el `.tar.gz` en el *mismo* espacio de trabajo `20Gi` que los volcados, por lo que `volcados + archivo` lo desbordaban y el pod se expulsaba **antes** de que la subida se ejecutara — lo que parece un fallo de S3 pero en realidad es de disco. Transmitir la subida elimina ese doble uso. + +### `agenteye-backup` falla al instalar `curl` + +El job se ejecuta en la imagen `postgres:16` e instala `curl` al arrancar para el volcado HTTP de ClickHouse. En un clúster sin acceso de salida a los espejos de paquetes de Debian, el paso `apt-get` falla. Permite ese acceso de salida desde el pod de backup, o incluye `curl` en una imagen de backup personalizada/espejada y referencíala en tu overlay. + +### `agenteye-backup` se ejecuta pero nada llega al almacenamiento de objetos + +La base incluye un `BACKUP_BUCKET` real (`ts-prod-agenteye/backups`) y el ServiceAccount `agenteye-backup`. El job **transmite** el archivo a S3 (`tar cz … | aws s3 cp - s3://…`). Si el pod de backup no tiene acceso de escritura al bucket, la subida falla — y como el script se ejecuta bajo `set -euo pipefail`, un fallo en cualquier lugar de esa tubería **falla** todo el job en el paso `upload` en lugar de no-op silencioso (el trap EXIT del pod registra `backup FAILED during step: upload`). Este también es el paso al que llegas *después* de corregir una expulsión por espacio de trabajo, por lo que si las copias de seguridad fueron expulsadas anteriormente en el paso de archivo, verifica que la subida ahora funcione. Filtra los logs del job fallido en busca del error de acceso a S3: + +```bash +kubectl logs -n agenteye -l job-name= | grep -iE 's3|upload|denied' +``` + +Solución: en tu overlay configura `BACKUP_BUCKET` con un bucket de tu propiedad y anota el ServiceAccount `agenteye-backup` existente con acceso de escritura (IRSA / Workload Identity / Pod Identity). Ver la sección **Backups** de [enterprise-docs/kubernetes-deployment.md](/es/agenteye/kubernetes-deployment). + +--- + +## Evaluaciones / sesiones / consultas respaldadas por ClickHouse + +### La barra lateral de la página `/queries` está vacía después de actualizar + +Se esperan tres tablas (`events`, `evaluations`, `agent_sessions`). Si la barra lateral del SchemaBrowser está vacía después de la actualización, el servidor no pudo aplicar el DDL de ClickHouse al arrancar. Revisa los logs del servidor en busca de `failed to apply CH DDL statement`: + +```bash +kubectl logs -n agenteye deploy/server | grep -E 'clickhouse|CH DDL' +``` + +La causa más frecuente es que ClickHouse no era accesible mientras se ejecutaban las migraciones. El servidor se niega a arrancar si no puede llegar a CH, por lo que un pod atascado generalmente tiene `CrashLoopBackOff` en lugar de una página de consultas rota silenciosamente, pero una aplicación parcial de DDL (una instrucción OK, las siguientes con 5xx) deja el esquema a medias. Reinicia el pod del servidor después de verificar que CH es accesible: + +```bash +kubectl rollout restart deploy/server -n agenteye +``` + +### Las nuevas evaluaciones no aparecen en `/sessions` o `/queries` + +Después de la actualización, las nuevas evaluaciones se escriben en ClickHouse, no en Postgres, y aparecen en `/sessions` (restringido a `evaluations:read`) y en `/queries`. Si no aparecen: + +1. Confirma que el pipeline del evaluador está habilitado (`EVALUATOR_ENDPOINT` configurado en el servidor) y produciendo resultados finales; busca líneas de log `evaluation_finalized`. +2. Confirma que CH es accesible desde el servidor: `kubectl exec -n agenteye deploy/server -- curl -fsS http://clickhouse:8123/ping`. +3. Verifica puntualmente la tabla CH: `kubectl exec -n agenteye clickhouse-0 -- clickhouse-client -q 'SELECT count() FROM agenteye.evaluations'`. + +### Las consultas fallan bajo carga con "Memory limit exceeded", o ClickHouse recibe `OOMKilled` + +**Síntoma:** bajo carga pesada del dashboard/consultas, las páginas analíticas (el stream de eventos, `/sessions`, la vista de modelos/latencia, el editor SQL) empiezan a fallar o a agotar el tiempo de espera; el servidor alterna brevemente entre `NotReady`; y el pod de ClickHouse muestra un conteo de reinicios creciente. Esto es casi siempre un problema de **memoria**, no de CPU ni de disco. + +**Confirma que es memoria** (no un problema de rendimiento que la replicación resolvería): + +1. Verifica el pod en busca de muertes por falta de memoria: + ```bash + kubectl -n agenteye describe pod clickhouse-0 | grep -iE 'Restart Count|Last State|Reason|OOMKilled' + ``` + `Reason: OOMKilled` / `Exit Code: 137` con un conteo de reinicios creciente es la señal. + +2. Pregunta a ClickHouse qué está rechazando: + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT name, value FROM system.errors WHERE value>0 ORDER BY value DESC" + ``` + Un conteo grande de `MEMORY_LIMIT_EXCEEDED` es la firma. El mensaje dice *"maximum: N GiB"* — ese **N es `0.9 × el límite de memoria del pod`** (el `max_server_memory_usage_to_ram_ratio` en `deploy/base/clickhouse/configmap.yaml`). Si tus lecturas pesadas necesitan más que N, son rechazadas. + +3. Descarta las cosas que *no* son el problema — si la CPU, el conteo de partes y el disco son todos bajos, añadir réplicas/sharding sería un coste desperdiciado: + ```bash + kubectl -n agenteye top pod clickhouse-0 + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT table, count() parts FROM system.parts WHERE active AND database='agenteye' GROUP BY table" + ``` + +**Causa:** el límite de memoria del pod de ClickHouse es demasiado pequeño para el conjunto de trabajo analítico. Las lecturas más pesadas extraen la columna `payload` JSON sin procesar, ejecutan `JSONExtract*` sobre ella y usan `FINAL` — cada una puede necesitar varios GiB. Si las cachés configuradas (`mark_cache_size` + `uncompressed_cache_size`) son más grandes que el pod, se agravan: las cachés se cobran contra el mismo presupuesto y eliminan la memoria de las consultas. + +**Solución — escala la memoria de ClickHouse:** + +1. Aumenta el límite de memoria de ClickHouse en tu overlay parcheando los `resources` del contenedor del StatefulSet `clickhouse` (el mismo mecanismo de overlay usado para los `resources` de los demás componentes). El presupuesto del servidor utilizable es `0.9 × límite`, por lo que un límite de `6Gi` da ~5.4 GiB, `16Gi` da ~14 GiB. Configura también `requests.memory` con un valor base real, para que el planificador lo reserve. Aplicar esto **recrea el pod de CH** (réplica única → ~30–60s de tiempo de inactividad en análisis); hazlo en una ventana de bajo tráfico. +2. Mantén las cachés en `deploy/base/clickhouse/configmap.yaml` proporcionales al límite — las cachés pequeñas (unos pocos cientos de MiB) son seguras en un pod pequeño; solo auméntalas junto con un aumento correspondiente del límite de memoria. El `max_memory_usage` por consulta se configura explícitamente en el perfil `users.xml` (ver la sección de nodo fijo a continuación) y se mantiene por debajo del límite a nivel de servidor (`0.9 × límite`) para que ninguna consulta individual pueda usar *más* RAM que la que tiene el contenedor. +3. Si el nodo en sí es el techo, verifica la memoria del host que ClickHouse puede ver: + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT formatReadableSize(value) FROM system.asynchronous_metrics WHERE metric='OSMemoryTotal'" + ``` + Si eso es solo un poco por encima del límite del pod, mueve ClickHouse a un nodo más grande (optimizado para memoria) — a través de un selector/afinidad de nodo en tu overlay — antes de aumentar más el límite. + +**Cuando no puedes añadir memoria: ejecuta las consultas en RAM y falla rápido — no hagas derrame en un disco lento.** Si el nodo es fijo y el pod no puede crecer, limita lo que cada consulta individual puede usar (para que una consulta no acapare todo el nodo) y, en un **disco de datos lento (no SSD)**, **no** permitas que grandes agregaciones/ordenamientos se derramen al disco. Derramarse a un disco lento es más lento que el timeout de lectura del cliente del servidor, por lo que una consulta con derrame devuelve un `500` del dashboard a mitad de ejecución mientras ClickHouse sigue procesando — mantener las consultas en RAM y rechazar la rara que supera el presupuesto *rápido* (`MEMORY_LIMIT_EXCEEDED`, en menos de un segundo) es lo que restaura la carga. Ten en cuenta un detalle importante de ClickHouse para aplicar esto: + +- **Estas son configuraciones de *perfil*, y ClickHouse solo lee `` desde `users_config` (`users.xml` / `users.d/*.xml`) — nunca desde `config.d`.** Un bloque `` colocado en `config.d/agenteye.xml` es **ignorado silenciosamente** (`max_execution_time`, `max_memory_usage`, etc. simplemente no se aplican). La configuración incluida por tanto las envía como una clave `users.xml` en el ConfigMap `clickhouse-config`, montada en `/etc/clickhouse-server/users.d/agenteye.xml`. +- Los valores por defecto incluidos: `max_memory_usage` (límite por consulta — una consulta no puede consumir todo el presupuesto del servidor), `max_bytes_before_external_group_by` / `max_bytes_before_external_sort` = **`0` (derrame deshabilitado)** para que las consultas permanezcan en RAM en lugar de arrastrarse en el disco lento, y `max_execution_time` (guardia contra consultas desbocadas, alineado con el timeout de lectura del cliente del servidor). +- **Verifica que están activas** (así también detectas el error de config.d): + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT name, value FROM system.settings + WHERE name IN ('max_memory_usage','max_bytes_before_external_group_by','max_execution_time')" + ``` + Espera un `max_memory_usage` distinto de cero y `max_bytes_before_external_group_by = 0`. Si `max_memory_usage` muestra `0`/predeterminado, el perfil no se está aplicando — verifica que la configuración esté en un montaje `users.d`, no en `config.d`. + +Concesión: con el derrame deshabilitado, una consulta cuyo conjunto de trabajo supera `max_memory_usage` es **rechazada** (`MEMORY_LIMIT_EXCEEDED`) en lugar de completarse lentamente — en un disco lento ese rechazo rápido es preferible, porque una consulta con derrame superaría de todas formas el timeout del cliente y fallaría. Si tu disco de datos es **rápido (SSD)**, puedes en cambio aumentar los umbrales `max_bytes_before_external_*` para permitir que las consultas grandes se derramen al disco y se completen. + +--- + +## Multi-tenencia (organizaciones) + +### Errores durante la actualización que habilita organizaciones (pods de servidor mixtos viejo/nuevo) + +**Síntoma:** durante un despliegue progresivo de la versión que habilita organizaciones, algunas solicitudes fallan: los logs del servidor muestran `there is no unique or exclusion constraint matching the ON CONFLICT specification` en la ruta `api_keys`, y/o los canales de alertas/Slack/webhook dejan de dispararse mientras el despliegue está en curso. + +**Causa:** la actualización reemplaza el antiguo índice único de toda la instancia en `api_keys(name)` con índices parciales por organización, y mueve la configuración de canales de alerta (y `default_user_permissions`) fuera de la tabla global `settings` hacia `org_settings` por organización. Un pod de servidor **antiguo** aún emite `ON CONFLICT (name)` (ahora sin restricción coincidente) y aún lee la configuración del canal desde las filas antiguas de `settings` (ahora vacías). Los pods viejos y nuevos no pueden coexistir de forma segura para estas dos rutas. + +**Solución:** no hagas un despliegue progresivo lento de esta actualización específica entre versiones mixtas. Realiza un cambio limpio: escala el servidor antiguo a cero (o usa una breve ventana de mantenimiento) y levanta la nueva versión junto con sus migraciones, en lugar de ejecutar réplicas antiguas y nuevas en paralelo. El tráfico normal y la ingesta se reanudan inmediatamente después del cambio; esto solo afecta la ventana de transición de versión. + +### El provisionamiento de una organización falla en `CREATE USER` / `CREATE ROW POLICY`, o una organización puede leer los datos de otra + +**Síntoma:** crear una organización devuelve un error que menciona `CREATE USER`, `CREATE ROW POLICY` o "access management is disabled"; o, peor, los miembros de una organización ven los eventos/evaluaciones de otra organización en el editor SQL o en el asistente. + +**Causa:** el aislamiento por organización se aplica mediante un usuario de ClickHouse dedicado + política de filas por organización. Esto requiere que la **gestión de acceso** SQL esté habilitada y que `users_without_row_policies_can_read_rows=false` en ClickHouse. Con la gestión de acceso desactivada, el provisionamiento no puede crear el usuario/política; con el valor predeterminado de la política de filas en su valor permisivo, un usuario que tiene SELECT pero ninguna política lee **todas** las filas (fail-open). + +**Solución:** usa la configuración incluida en `deploy/base/clickhouse/`, que configura ambos. Si ejecutas tu propia configuración de ClickHouse, habilita la gestión de acceso SQL en el usuario interno del servidor y configura `users_without_row_policies_can_read_rows=false` (ver `deploy/base/clickhouse/configmap.yaml`), luego reinicia ClickHouse y vuelve a crear la organización con la CLI `agenteye-orgctl` (ver [enterprise-docs/tenant-management.md](/es/agenteye/tenant-management)). + +### Los usuarios de la organización pierden acceso a ClickHouse después de cambiar `ORG_CH_SECRET` + +**Síntoma:** el editor SQL y el asistente de IA de repente devuelven fallos de autenticación de ClickHouse para todas las organizaciones, inmediatamente después de que se cambió `ORG_CH_SECRET` o se configuró de forma inconsistente entre réplicas. + +**Causa:** la contraseña de ClickHouse de cada organización se deriva como un HMAC de `ORG_CH_SECRET`. Rotarla (o ejecutar réplicas con valores diferentes) invalida la credencial de ClickHouse almacenada de cada organización; la contraseña derivada ya no coincide con el usuario provisionado. + +**Solución:** configura `ORG_CH_SECRET` con un valor único y robusto **antes** de provisionar una segunda organización y mantenlo estable e idéntico en todas las réplicas del servidor. La reconciliación al arrancar el servidor vuelve a provisionar el usuario de ClickHouse de cada organización desde el secreto actual al arrancar, por lo que un reinicio del servidor en todas las réplicas (con el secreto consistente) sana los usuarios huérfanos. Trata el valor como un secreto de larga duración; no lo rotas casualmente. Como red de seguridad, si `ORG_CH_SECRET` se deja en el valor de desarrollo predeterminado incorporado (es decir, sin configurar), la reconciliación al arrancar **omite** las organizaciones no predeterminadas y registra un error en lugar de reescribir sus credenciales de ClickHouse al valor de desarrollo conocido públicamente, para que una réplica que reinicia sin el secreto no pueda romper las demás réplicas. Configura el secreto de forma consistente y reinicia para provisionar esas organizaciones. + +### El asistente de IA devuelve 400 / se niega a chatear después de habilitar organizaciones + +**Síntoma:** el dock del asistente carga pero cada mensaje vuelve como un error (HTTP `400`), y el agente registra una solicitud `/chat` sin organización rechazada. + +**Causa:** el agente es consciente de la organización y falla de forma cerrada; rechaza un `/chat` que no lleva contexto de organización. Esto ocurre durante un despliegue de transición donde el agente se ha actualizado pero el dashboard que envía la solicitud aún no es consciente de la organización. + +**Solución:** completa el despliegue para que el dashboard envíe el contexto de la organización (el estado final normal, sin necesidad de ningún flag). Para salvar la brecha mientras un dashboard no consciente de la organización habla con un agente consciente de la organización, configura `AGENTEYE_AGENT_ALLOW_NO_ORG=1` en el servicio `agent` para que recurra a la organización `default` en lugar de rechazar, y elimínalo una vez que la actualización del dashboard aterrice. Ver la referencia de variables de entorno en [enterprise-docs/assistant.md](/es/agenteye/assistant#environment-variable-reference). + +--- + +## Auditorías + +### Una auditoría nunca se ejecuta (la próxima ejecución sigue desplazándose, sin historial de ejecución) + +**Síntoma:** la página de auditoría muestra *última ejecución: nunca*, o `próxima ejecución` sigue moviéndose al futuro sin que aparezca ninguna fila en el historial de ejecución. + +**Causa:** la auditoría está deshabilitada (las auditorías deshabilitadas no tienen entrada en la cola), o los trabajadores de auditoría del servidor están fallando al reclamar trabajo. + +**Solución:** confirma que la auditoría está **habilitada** (el botón ejecutar ahora lo requiere). Luego revisa los logs del servidor en busca de `audits pipeline started` al arrancar y de errores `audits:` — una línea `claim_due failed` apunta a conectividad con Postgres. `AUDIT_WORKERS` por defecto es `1`; debe ser ≥ 1 para que se ejecute cualquier auditoría. + +### Las ejecuciones de auditoría tienen éxito pero no encuentran nada + +**Síntoma:** el historial de ejecución muestra `succeeded` con `findings: 0` aunque `/errors` claramente muestra fallos. + +**Causa:** la ventana de análisis no cubre los fallos, o los filtros de alcance los excluyen. + +**Solución:** verifica la ventana de la ejecución (`window_from → window_to`) contra cuándo ocurrieron los fallos — en el modo `since_last` cada ejecución solo analiza desde la última ejecución exitosa, por lo que los fallos más antiguos solo los ve la *primera* ejecución o una auditoría con ventana `fixed`. Amplía `scope` (entornos / IDs de agente). Las estadísticas de ejecución muestran `policy_hits` (cuántas políticas deterministas se activaron) e `improvements` (cuántas registró la investigación de IA) — si ambos son 0, la ventana/alcance genuinamente no encontró nada. + +### La ejecución dice `analysis_unavailable` y solo produce hallazgos de políticas + +**Síntoma:** las estadísticas de ejecución incluyen `analysis_unavailable` y los únicos hallazgos son `kind: policy`; no aparecen mejoras de IA. + +**Causa:** la investigación agente no pudo ejecutarse: el servidor no puede llegar al servicio de agente (`AGENTEYE_AGENT_URL` / `AGENTEYE_AGENT_TOKEN` no configurados en el **servidor** — la auditoría reutiliza la conexión del asistente), el servicio de asistente no tiene LLM configurado, o la llamada tuvo error/timeout (la cadena `analysis_unavailable` tiene el detalle). El paso de políticas deterministas es el mínimo — siempre se ejecuta — por lo que la auditoría aún tiene éxito con sus hallazgos de seguridad. + +**Solución:** configura `AGENTEYE_AGENT_URL` (p. ej. `http://agent:9100`) y `AGENTEYE_AGENT_TOKEN` en el **servidor** — los mismos valores que ya usa el asistente del dashboard (los manifiestos/compose incluidos ahora los conectan) — y configura un LLM en el servicio de asistente (ver [assistant.md](/es/agenteye/assistant)), luego vuelve a ejecutar. Una investigación grande puede necesitar un `AUDIT_LLM_TIMEOUT_MS` más grande (servidor) — mantenlo por encima del `AGENTEYE_AUDIT_TIMEOUT_MS` del agente. + +### El sandbox de código de auditoría está deshabilitado (`sandbox_available: false`) + +**Síntoma:** el `/health` del agente muestra `sandbox_available: false`, y las ejecuciones de auditoría indican que el sandbox no está disponible; la IA investiga solo con SQL. + +**Causa:** el sandbox bubblewrap en el pod necesita **espacios de nombres de usuario sin privilegios**, que el perfil seccomp del pod o el kernel del nodo está bloqueando. + +**Solución:** configura `seccompProfile: Unconfined` (k8s) o `security_opt: [seccomp:unconfined]` (compose) en el agente, y confirma que el kernel del nodo permite espacios de nombres de usuario sin privilegios (algunas imágenes gestionadas, p. ej. GKE COS, los deshabilitan). Donde no puedas habilitarlo, esto es lo esperado y seguro — el auditor degrada automáticamente a solo SQL. Ver [deployment.md](/es/agenteye/deployment). + +### El informe de auditoría por correo electrónico no se entrega + +**Síntoma:** una auditoría encontró nuevos hallazgos pero no llegó ningún correo electrónico. + +**Causa:** la auditoría no tiene ningún canal de **correo electrónico** adjunto, el correo electrónico está deshabilitado a nivel de organización en `alerts.enabled_channels`, no hay destinatarios, o SMTP no está configurado. + +**Solución:** adjunta un canal de correo electrónico a la auditoría, asegúrate de que `email` esté en `alerts.enabled_channels`, configura destinatarios (en el canal o mediante `alerts.email_default_recipients`), y configura SMTP (el mismo transporte que usan los correos de alertas + OTP). El correo solo se envía cuando una ejecución produce **al menos un** hallazgo nuevo. + +### Un patrón silenciado o descartado conserva su página de hallazgo antigua pero nunca se reclasifica + +**Síntoma:** después de silenciar un hallazgo, las ejecuciones posteriores nunca vuelven a mostrar ese patrón — aunque siga ocurriendo. + +**Causa:** ese es el comportamiento diseñado: silenciar/descartar son supresiones duraderas vinculadas a la huella digital del patrón. + +**Solución:** abre el hallazgo y usa **reopen** para borrar la supresión; la próxima ejecución clasificará el patrón de nuevo. Usa **resolve** (no silenciar) para los patrones "corregidos" sobre los que querrías enterarte si regresan. + +--- + +## Obtener ayuda + +Contacta a `support@exosphere.host` con: +- Tu versión de AgentEye (del tag de la versión) +- Los logs relevantes del contenedor (`docker logs `) +- Una descripción del problema y lo que ya has intentado \ No newline at end of file diff --git a/docs/fr/agenteye/alerts.mdx b/docs/fr/agenteye/alerts.mdx new file mode 100644 index 00000000..3e28ddb9 --- /dev/null +++ b/docs/fr/agenteye/alerts.mdx @@ -0,0 +1,308 @@ +--- +title: "Alertes" +description: "Documentation des alertes AgentEye." +--- + +Les alertes évaluent une règle selon un calendrier et vous notifient lorsqu'un seuil est franchi. Elles transforment AgentEye d'un tableau de bord passif en une surface de notification pour les événements importants : pics du taux d'erreur, régressions de latence, baisses de score d'évaluation, ou tout événement personnalisé exprimable sous forme de requête ClickHouse. + +Ce guide couvre la définition d'une alerte, les cinq types de déclencheurs, les quatre canaux de notification, le cycle de vie des incidents et les paramètres opérationnels. + +![La page Alertes : une grille de cartes de règles d'alerte, chacune affichant son type de déclencheur, la fenêtre d'évaluation, les canaux et un badge de sévérité info/avertissement/critique](/agenteye/images/alerts.png) + +--- + +## Concepts + +- **Alerte** — la règle. Elle définit *ce qu'il faut vérifier* (le déclencheur), *à quelle fréquence* (l'intervalle d'évaluation), *quand considérer qu'il y a un problème* (logique composée), *l'urgence* (sévérité), et *qui/où notifier* (les canaux). +- **Incident** — ce qui se produit lorsqu'une alerte se déclenche. Une alerte ne peut avoir qu'un seul incident ouvert à la fois. Les violations répétées mettent à jour les preuves du même incident. Les incidents sont résolus par un opérateur ; la résolution automatique lorsque la règle cesse de se déclencher est prévue mais pas encore disponible. +- **Canal** — la destination d'une notification : e-mail, Slack, webhook générique ou dans le tableau de bord. Chaque alerte peut associer n'importe quelle combinaison. + +Les alertes et les incidents appartiennent à une organisation et sont partagés entre les opérateurs de cette organisation (dans un déploiement mono-tenant, il s'agit simplement de l'organisation `default` intégrée). Les incidents peuvent être assignés à un opérateur individuel pour le triage. + +--- + +## Types de déclencheurs + +Cinq types, chacun avec sa propre spécification JSON. Choisissez celui qui correspond à votre définition de « dysfonctionnement ». Le formulaire **nouvelle alerte** du tableau de bord génère la même spécification, en adaptant l'éditeur de conditions au type de déclencheur sélectionné : + +![Le formulaire nouvelle alerte, avec les paramètres de base (nom, description, activé) et le sélecteur de déclencheur affichant les options seuil de métrique, SQL personnalisé, score d'évaluation, échecs d'évaluation et par événement](/agenteye/images/alert-new.png) + +### 1. `metric_threshold` + +Le plus simple. Choisissez une métrique dans une liste fermée, un opérateur, un seuil et une fenêtre temporelle. + +| Métrique | Ce qu'elle mesure | +|---|---| +| `event_count` | Total des événements dans la fenêtre | +| `error_count` | `event_type = 'error'` OU tout événement avec `error_type IS NOT NULL` | +| `error_rate` | `error_count / event_count` (0..1) | +| `p95_latency_ms` | `quantile(0.95)(duration_ms)` sur tous les événements ayant un `duration_ms` | +| `p99_latency_ms` | `quantile(0.99)(duration_ms)` | +| `token_sum` | `SUM(input_tokens + output_tokens)` | + +Opérateurs : `>`, `>=`, `<`, `<=`, `==` (également acceptés sous la forme `gt`, `gte`, `lt`, `lte`, `eq`). + +Filtres optionnels : `environment`, `event_type`. + +Exemple de spécification : + +```json +{ + "metric": "p95_latency_ms", + "filter": { "environment": "production" }, + "window_secs": 900, + "op": ">", + "value": 5000 +} +``` + +### 2. `custom_sql` + +Pour tout ce que les métriques prédéfinies ne couvrent pas. Le SQL fourni par l'opérateur passe par le même garde `/queries/run` (SELECT/WITH uniquement, instruction unique, limite de 10 000 lignes) avant que le dispatcher ne l'exécute. Deux modes : + +- **Mode lignes** (sans `op`/`value`) : l'alerte se déclenche dès que la requête retourne au moins une ligne. +- **Mode valeur** : la requête doit aliaser une colonne `metric_value` ; le dispatcher compare `metric_value` de la première ligne à `value` en utilisant `op`. + +```json +{ + "sql": "SELECT count() AS metric_value FROM agenteye.events WHERE event_type = 'error' AND ts >= now() - INTERVAL 1 HOUR", + "op": ">", + "value": 100 +} +``` + +### 3. `evaluation_score` + +Lit `agenteye.evaluations` et compare la moyenne d'un score nommé sur une fenêtre temporelle. + +```json +{ + "score_key": "hallucination", + "op": ">", + "value": 0.6, + "window_secs": 3600, + "min_count": 5, + "environment": "production" +} +``` + +`min_count` protège contre les valeurs aberrantes d'un seul échantillon ; le dispatcher ne se déclenchera pas tant qu'au moins N évaluations n'existent pas dans la fenêtre. + +### 4. `eval_compound` + +Détectez une régression qualitative qui n'apparaît qu'à travers *plusieurs* scores d'évaluation simultanément. Là où `evaluation_score` surveille un seul score nommé, `eval_compound` compose plusieurs conditions de score d'évaluation en une seule alerte et combine leurs résultats avec une logique choisie ; une règle peut ainsi exprimer « déclencher si la pertinence baisse **ou** si les hallucinations augmentent », « déclencher uniquement si la pertinence **et** l'efficacité des outils baissent toutes deux », ou « déclencher si **au moins 2 de** ces trois vérifications sont en infraction ». + +Chaque condition lit la moyenne d'un score nommé depuis `agenteye.evaluations` sur la fenêtre partagée et la teste avec son propre opérateur et seuil. Les résultats booléens sont ensuite combinés par le `combinator` : + +| Combinateur | Logique | Se déclenche quand | +|---|---|---| +| `"any"` | OU | au moins une condition est en infraction | +| `"all"` | ET | toutes les conditions sont en infraction | +| `{ "at_least": N }` | M parmi N | au moins N conditions sont en infraction | + +```json +{ + "combinator": { "at_least": 2 }, + "conditions": [ + { "score_key": "hallucination", "op": ">", "value": 0.8 }, + { "score_key": "helpfulness", "op": "<", "value": 0.6 }, + { "score_key": "tone", "op": "<", "value": 0.5 } + ], + "window_secs": 3600, + "min_count": 5, + "environment": "production" +} +``` + +- `combinator` : `"any"`, `"all"`, ou `{ "at_least": N }`. +- `conditions[]` : chaque `{ score_key, op, value }`, utilisant les mêmes opérateurs que les autres déclencheurs (`>`, `>=`, `<`, `<=`, `==`). +- `window_secs` : la période de rétrolecture partagée appliquée à chaque condition (par défaut `3600`). +- `min_count` : nombre minimum d'évaluations par condition avant que celle-ci puisse être en infraction ; une condition avec trop peu d'échantillons dans la fenêtre est considérée comme « non en infraction » (par défaut `1`). +- `environment` : optionnel ; restreint chaque condition à un environnement. + +Les preuves de la notification enregistrent la moyenne observée de chaque condition, le seuil testé, le nombre d'évaluations vues et si la condition était en infraction ; vous pouvez ainsi voir exactement quelles vérifications ont échoué. + +### 5. `per_event` + +Pour les alertes de type « tout événement correspondant à X est arrivé ». Pas d'agrégation ; le dispatcher se déclenche dès qu'il trouve une correspondance dans la fenêtre de rétrolecture. + +```json +{ + "event_type": "error", + "lookback_secs": 60, + "environment": "production", + "tool_name": "bash", + "agent_id": "caa", + "error_type": "TimeoutError", + "message_contains": "vertex-ai timed out" +} +``` + +Tous les filtres sont combinés avec ET ; tout champ omis est sans contrainte. + +| Champ | Rôle | +|---|---| +| `agent_id` | Restreindre aux erreurs d'un agent spécifique (celui affiché sur la ligne `/errors`). | +| `error_type` | Restreindre à une classe d'erreur spécifique (ex. `TimeoutError`) plutôt qu'à toutes les erreurs. | +| `message_contains` | Correspondance de sous-chaîne insensible à la casse dans `payload.message`. Utile pour cibler un mode d'échec spécifique (ex. `prompt is too long`) sans alerter sur toutes les erreurs du même agent. Limité à 200 caractères ; correspondance en tant que chaîne littérale, pas un motif. | + +Conseil : définissez `lookback_secs` pour qu'il corresponde approximativement à `eval_interval_secs` de l'alerte, afin d'éviter les doubles notifications pour le même événement. + +**Raccourci depuis `/errors` :** le bouton **+ alerte** sur chaque ligne représentative d'un groupe d'erreurs dans la vue des erreurs (et dans le panneau de détail des événements de session pour un événement d'erreur) ouvre `/alerts/new` pré-rempli avec un déclencheur `per_event` basé sur l'`event_type` + l'environnement de cette ligne, avec un nom issu de l'`error_type` du payload lorsque disponible. Vous devez encore choisir les canaux et confirmer la rétrolecture, mais le filtre est déjà renseigné. Les opérateurs ont besoin de `alerts:write` pour que le bouton s'affiche. + +--- + +## Logique composée (M parmi N) + +Chaque alerte dispose de deux paramètres entiers en plus du déclencheur : + +- `eval_window` : combien d'évaluations récentes examiner (par défaut 1) +- `min_breaches` : combien d'entre elles doivent être en infraction avant que l'alerte se déclenche (par défaut 1) + +`1 sur 1` (par défaut) signifie « déclencher à la première infraction ». `3 sur 5` signifie « déclencher lorsque la règle a été en infraction 3 fois sur les 5 dernières évaluations », utile pour les signaux instables où une seule mesure défavorable est du bruit. Le dispatcher maintient un tampon circulaire par alerte ; vous n'avez pas à gérer l'état. + +--- + +## Intervalle d'évaluation + +`eval_interval_secs` contrôle la fréquence à laquelle le dispatcher exécute votre règle. Limité à `[30, 86400]`. Préréglages dans le tableau de bord : 1m / 5m / 15m / 1h. Choisissez un intervalle adapté à la vitesse d'évolution du signal sous-jacent : une alerte sur le taux d'erreur sur 5 minutes évaluée toutes les 15 secondes gaspille du CPU ; une alerte par événement a besoin d'une courte rétrolecture sinon elle manquera silencieusement des événements entre les ticks. + +--- + +## Canaux + +Chaque alerte peut associer n'importe quelle combinaison de ces quatre canaux. Les identifiants par canal (URL du webhook Slack, URL du webhook générique + secret de signature, destinataires e-mail par défaut) sont configurés une seule fois dans **`/settings`** et référencés par clé depuis chaque alerte. Ainsi, un seul canal Slack peut servir plusieurs alertes sans que chacune n'ait besoin de stocker sa propre copie de l'URL du webhook. + +Les trois types de canaux externes (e-mail, Slack, webhook) sont également contrôlés par un interrupteur global à l'organisation, `alerts.enabled_channels`. Lorsqu'une alerte déclenchée associe un type de canal absent de cet ensemble, le dispatcher l'ignore et enregistre une ligne `alert_notifications` avec le statut `skipped_disabled` et la cible `` (vous permettant de mettre en pause globalement, par exemple, toutes les livraisons Slack sans modifier chaque règle). Le canal dans le tableau de bord est toujours autorisé. Voir [Configuration](#configuration). + +### E-mail + +Réutilise le même transport SMTP qui envoie les e-mails de connexion OTP. Les destinataires sont résolus dans l'ordre suivant : + +1. Le remplacement `recipients[]` par canal (lorsque non vide). +2. Le paramètre `alerts.email_default_recipients` (un tableau de chaînes e-mail). + +Si SMTP n'est pas configuré, le canal est inactif ; le dispatcher enregistre tout de même une ligne `alert_notifications` avec la cible `` pour que la piste d'audit rende visible la mauvaise configuration. + +### Slack + +Envoie un message Block Kit à une [URL de webhook entrant](https://api.slack.com/messaging/webhooks). + +- URL par défaut : `alerts.slack_default_webhook` (définie dans `/settings`). +- Remplacement par alerte : définissez `webhook_setting_key` du canal sur n'importe quelle autre clé de paramètre de type URL, ex. `alerts.slack_oncall`, `alerts.slack_costs`. + +L'en-tête inclut un emoji de sévérité (`:rotating_light:` / `:warning:` / `:bell:`), et le message contient un bouton qui renvoie directement à la page de l'incident. + +### Webhook générique + +Une intégration JSON-POST pour PagerDuty, Opsgenie, ou votre propre point d'ingestion. Structure du corps : + +```json +{ + "schema_version": 1, + "event": "alert.firing", + "incident": { "id": "uuid", "url": "https://…/incidents/uuid", "opened_at": "2026-…" }, + "alert": { "id": "uuid", "name": "errors > 50/hr", "severity": "critical" }, + "breach": { "value": 73.0, "summary": "ErrorCount > 50 (observed 73.000)", "evidence": { … } } +} +``` + +Lorsque `alerts.webhook_signing_secret` est défini, la requête inclut un en-tête `X-AgentEye-Signature: sha256=`, le HMAC-SHA256 du corps utilisant le secret. Vérifiez-le côté récepteur avant de faire confiance au payload. + +L'en-tête `X-AgentEye-Event` contient `alert.firing` / `alert.test`. (`alert.resolved` est réservé pour la future fonctionnalité de résolution automatique et n'est pas actuellement émis.) + +### Dans le tableau de bord + +Pas de livraison externe : l'alerte écrit simplement une ligne `alert_notifications` que la page des incidents du tableau de bord affiche. Utile pendant la mise au point d'une règle si vous ne voulez pas spammer un système externe, ou pour les alertes de faible urgence que les opérateurs vérifient lors du triage normal. + +--- + +## Cycle de vie des incidents + +``` +firing ──ack──▶ acknowledged + │ │ + └────────────────────┴───── operator resolve ───▶ resolved +``` + +- **firing** — le dispatcher vient d'ouvrir l'incident ou a détecté une nouvelle infraction. La notification de déclenchement est envoyée exactement une fois (conditionnée par l'horodatage `notified_firing_at` sur l'incident). +- **acknowledged** — un opérateur a appuyé sur *ack* dans `/incidents/:id`. L'incident est toujours considéré comme ouvert ; les infractions suivantes mettront à jour ses preuves sans re-notifier. +- **resolved** — un opérateur a appuyé sur *resolve*. La résolution automatique lorsque la règle cesse d'être en infraction est prévue mais pas encore disponible, donc un incident ouvert reste ouvert jusqu'à ce qu'un opérateur le résolve. + +Un nouvel incident peut se rouvrir sur la même alerte à tout moment après la résolution du précédent. + +**Journal d'activité.** Chaque action sur un incident — ouverture, accusé de réception, résolution — est enregistrée dans un journal d'activité en ajout seul et affichée sur la *timeline d'activité* de l'incident, chaque entrée étant attribuée à l'opérateur qui l'a effectuée (par e-mail) ou à **automated** pour les actions que le dispatcher a prises de lui-même (ouverture automatique lors d'une infraction). L'accusé de réception est partagé : plusieurs opérateurs peuvent acquitter le même incident et chacun apparaît comme une entrée distincte et attribuée. + +La boîte de réception **Incidents** regroupe les incidents ouverts par état et permet de filtrer par sévérité et assigné : + +![La boîte de réception des incidents affichant des cartes d'incidents liés à des alertes et ad hoc avec des badges de sévérité et des assignés](/agenteye/images/incidents.png) + +Ouvrir un incident affiche les preuves de l'infraction, les assignés et abonnés, le journal d'activité attribué et un fil de commentaires : + +![Vue détaillée d'un incident : l'alerte parente, le résumé de l'infraction, les assignés, les abonnés, le journal d'activité attribué et la conversation](/agenteye/images/incident-detail.png) + +--- + +## Permissions requises + +La création de *règles* d'alerte et le triage des *incidents* sont des responsabilités distinctes avec des droits séparés, ce qui vous permet d'accorder à une rotation d'astreinte l'accès aux incidents sans lui donner la capacité de réécrire les règles. + +- `alerts:read` : consulter les règles d'alerte. +- `alerts:write` : créer, modifier, supprimer des règles d'alerte et déclencher une notification de test. +- `incidents:read` : consulter les incidents. +- `incidents:write` : ouvrir des incidents manuels (ad hoc) non liés à une alerte. +- `incidents:ack` : acquitter, assigner, commenter et résoudre des incidents. + +> **Ancien `alerts:ack`.** Les clés et opérateurs auxquels l'ancien jeton `alerts:ack` a été accordé continuent de fonctionner : il est traité comme `incidents:ack` (et implique `incidents:read`), donc les personnes d'astreinte existantes conservent leur accès sans avoir besoin de nouvelles informations d'identification. Émettez les nouveaux droits avec la famille `incidents:*`. + +Accordez sur les clés API (`POST /keys`) et les opérateurs (`PUT /users/:id`). Le `PermGate` du tableau de bord verrouille les boutons concernés lorsqu'une permission manque ; vous verrez `// 403` à côté de l'action. + +> **Sélecteur de destinataires e-mail.** Le sélecteur de destinataires de l'éditeur d'alertes liste les membres de votre organisation pour que vous puissiez les choisir par nom. Il se charge pour tout opérateur disposant de `alerts:read` ou `alerts:write` ; consulter le répertoire de votre équipe à cette fin ne nécessite **pas** `users:read`, et le sélecteur retourne uniquement les adresses e-mail des membres, jamais les enregistrements utilisateur complets. + +--- + +## Configuration + +Variables d'environnement utilisées par le dispatcher : + +| Variable | Défaut | Rôle | +|---|---|---| +| `ALERT_WORKERS` | `1` | Tâches de travail par instance serveur. La plupart des déploiements n'ont besoin que d'une. | +| `ALERT_CLAIM_BATCH` | `16` | Nombre maximum d'alertes traitées par tick de worker. | +| `ALERT_POLL_IDLE_SECS` | `5` | Temps de veille du worker lorsque la file est vide. | +| `ALERT_REQUEST_TIMEOUT_MS` | `15000` | Délai d'expiration de l'évaluation par déclencheur. | +| `DASHBOARD_URL` | `https://app.befailproof.ai` | Origine utilisée pour construire le lien magique vers l'incident dans les notifications. À définir sur votre hôte de tableau de bord. | + +Après un échec d'évaluation transitoire (ClickHouse inaccessible, expiration d'une requête), le dispatcher réessaie la règle avec un backoff exponentiel. Une fois qu'une règle a accumulé **5** échecs transitoires consécutifs, elle est replanifiée à sa cadence normale au lieu de continuer à reculer, de sorte qu'une règle continuellement défaillante continue d'être réévaluée. Ce plafond est fixe et n'est pas configurable par l'opérateur. + +Paramètres des canaux (gérés depuis `/settings`, pas en variables d'environnement) : + +- `alerts.email_default_recipients` (`email_list`) : tableau JSON de chaînes e-mail — les destinataires par défaut pour les canaux e-mail. +- `alerts.slack_default_webhook` (`url`) : URL du webhook entrant Slack par défaut. +- `alerts.webhook_default_url` (`url`) : URL du webhook générique par défaut. +- `alerts.webhook_signing_secret` (`secret`) : clé HMAC-SHA256. Toujours retournée comme `""` dans la réponse GET ; saisissez une nouvelle valeur pour la renouveler. +- `alerts.enabled_channels` (`channel_set`) : l'ensemble des types de canaux externes dispatchés à l'échelle de l'organisation lorsqu'une alerte se déclenche ; par défaut les trois (`email`, `slack`, `webhook`). Supprimer un type ici supprime globalement ce canal pour toutes les alertes sans modifier chaque règle. Le canal dans le tableau de bord est toujours livré et n'est pas affecté par ce paramètre. + +--- + +## Vérifier une nouvelle alerte + +Avant de vous fier à une nouvelle alerte : + +1. Enregistrez-la comme activée avec au moins un canal de notification. +2. Sélectionnez **test** sur la page de détail de l'alerte et confirmez que chaque destination configurée reçoit la notification synthétique. +3. Après la première vraie infraction, confirmez que l'incident apparaît sous **Incidents** et que sa valeur mesurée correspond à la requête du tableau de bord correspondante. + +Les incidents ne se résolvent pas automatiquement lorsqu'une condition s'efface. Un opérateur doit les résoudre depuis la page de détail de l'incident. + +--- + +## Dépannage + +| Symptôme | Cause probable | +|---|---| +| L'alerte ne se déclenche jamais | `enabled = false`, ou aucun canal attaché, ou la requête CH sous-jacente retourne 0 lignes. Utilisez *test* pour confirmer les canaux ; utilisez `/queries/run` pour confirmer la métrique. | +| Notification Slack manquante | `alerts.slack_default_webhook` (ou la clé de remplacement par alerte) n'est pas définie : vérifiez `alert_notifications.target` pour des lignes `` ; ou le type `slack` est globalement désactivé dans `alerts.enabled_channels` : recherchez des lignes `alert_notifications` avec le statut `skipped_disabled` et la cible ``. | +| Webhook générique 401 | Le destinataire exige une signature mais `alerts.webhook_signing_secret` n'est pas défini. Vérifiez côté récepteur que le HMAC correspond à `hmac_sha256(secret, body)`. | +| E-mail contenant tous les envois en échec | Identifiants SMTP incorrects ou l'adresse `from` est rejetée par votre relais. Même surface que celle qui envoie les e-mails OTP : si ceux-ci fonctionnent, le transport SMTP est correct. | +| L'incident se rouvre à répétition | Les paramètres composés sont trop agressifs : essayez d'augmenter `min_breaches` ou `eval_window` pour que les pics transitoires ne rouvrent pas les incidents que vous avez résolus. | \ No newline at end of file diff --git a/docs/fr/agenteye/api-keys.mdx b/docs/fr/agenteye/api-keys.mdx new file mode 100644 index 00000000..531280ef --- /dev/null +++ b/docs/fr/agenteye/api-keys.mdx @@ -0,0 +1,255 @@ +--- +title: "Clés API" +description: "Documentation des clés API AgentEye." +--- + + +AgentEye utilise des clés API à granularité fine pour contrôler l'accès au serveur. Chaque clé est associée à une ou plusieurs permissions qui déterminent ses capacités. + +--- + +## Permissions + +Le serveur applique un catalogue fixe de permissions ; chacune contrôle des routes HTTP spécifiques. Une **clé admin** les possède toutes ; une clé à portée limitée ne possède que le sous-ensemble que vous accordez lors de sa création. Les chaînes de permission inconnues sont rejetées lors de la création d'une clé. + +> **Non assignables aux clés.** Deux permissions valides sont réservées aux humains/au tableau de bord et ne peuvent pas être accordées à une clé API : `orgs:admin` (administration de l'instance, réservée à l'opérateur) et `keys:update`. Toute requête `POST /keys` ou `PATCH /keys/:id` tentant d'accorder l'une ou l'autre est rejetée avec HTTP 422. Voir la ligne `keys:update` ci-dessous pour comprendre pourquoi une clé porteuse peut créer des clés mais jamais les modifier. + +### Ingestion et interrogation des événements + +| Permission | Routes HTTP | Ce qu'elle autorise | +|---|---|---| +| `events:add` | `POST /events` | Ingérer des lots d'événements depuis un collecteur. C'est la seule permission dont un collecteur a besoin. | +| `events:read` | `GET /events`, `GET /events/latency_aggregate`, `GET /events/environments`, `GET /events/models`, `GET /sessions/:session_id/export` | Interroger les événements, lister les environnements connus, lister les identifiants de modèles présents dans les données (utilisés par la vue Modèles et les filtres de modèles), calculer l'agrégat de latence qui alimente la carte thermique / la bande de percentiles, et exporter une session en JSONL. Les endpoints de facettes de la barre de filtres partagée `GET /events/environments` et `GET /events/models` sont accessibles avec **soit** `events:read` **soit** `evaluations:read`, de sorte que la page des sessions (contrôlée par `evaluations:read`) réutilise la même facette par organisation. | + +### Sessions et évaluations + +| Permission | Routes HTTP | Ce qu'elle autorise | +|---|---|---| +| `evaluations:read` | `GET /sessions`, `GET /evaluations`, `GET /evaluations/aggregate`, `GET /evaluations/environments`, `GET /evaluation-jobs` | Lister les sessions, lire les résultats d'évaluation, le bilan d'intégrité des évaluations agrégé utilisé par les tableaux de bord, et l'état de la file d'attente du worker d'évaluation. | +| `evaluations:trigger` | `POST /sessions/:session_id/re-evaluate` | Mettre manuellement en file d'attente une réévaluation pour une session terminée. | + +### Tableaux de bord + +| Permission | Routes HTTP | Ce qu'elle autorise | +|---|---|---| +| `dashboards:read` | `GET /dashboards`, `GET /dashboards/:id`, `GET /dashboards/:id/tiles` | Lister les tableaux de bord, en charger un et lire ses tuiles. | +| `dashboards:write` | `POST /dashboards`, `PUT /dashboards/:id`, `POST /dashboards/:id/tiles`, `PUT /dashboards/:id/tiles/:tile_id`, `DELETE /dashboards/:id/tiles/:tile_id`, `PUT /dashboards/:id/tiles/layout` | Créer et modifier des tableaux de bord, ajouter / modifier / supprimer des tuiles, et réorganiser la grille de tuiles. | +| `dashboards:delete` | `DELETE /dashboards/:id` | Supprimer un tableau de bord entier (la suppression au niveau des tuiles relève de `dashboards:write`). | + +### Requêtes sauvegardées (compositeur SQL) + +| Permission | Routes HTTP | Ce qu'elle autorise | +|---|---|---| +| `queries:read` | `GET /queries`, `GET /queries/:id`, `GET /queries/schema` | Lister les requêtes sauvegardées, en charger une et inspecter le schéma ClickHouse en lecture seule que le compositeur cible. | +| `queries:write` | `POST /queries`, `PUT /queries/:id` | Créer et modifier des requêtes sauvegardées. Le SQL est toujours acheminé via le même rôle en lecture seule et les mêmes vérifications `sql_guard` qu'un appel `queries:run`. | +| `queries:delete` | `DELETE /queries/:id` | Supprimer une requête sauvegardée. | +| `queries:run` | `POST /queries/run` | Exécuter du SQL sauvegardé ou ad hoc contre le rôle en lecture seule utilisé par le compositeur. | + +### Assistant IA + +| Permission | Routes HTTP | Ce qu'elle autorise | +|---|---|---| +| `agent:use` | `GET /agent/conversations`, `POST /agent/conversations`, `GET /agent/conversations/:id`, `PATCH /agent/conversations/:id`, `DELETE /agent/conversations/:id`, `PUT /agent/conversations/:id/messages` | Interagir avec l'assistant IA du tableau de bord et gérer ses propres conversations (privées). Requis pour que l'**utilisateur** voie le panneau de l'assistant ; la clé propre à l'assistant est `dashboard-assistant` et est initialisée séparément (voir ci-dessous). | + +### Clés API + +| Permission | Routes HTTP | Ce qu'elle autorise | +|---|---|---| +| `keys:create` | `POST /keys` | Créer une nouvelle clé API à portée limitée. N'accorde **pas** la modification des permissions d'une clé existante (c'est `keys:update`). | +| `keys:read` | `GET /keys` | Lister les clés existantes. Les secrets ne sont jamais retournés par cet endpoint. | +| `keys:update` | `PATCH /keys/:id` | Modifier les permissions d'une clé existante. Permission **réservée aux humains/au tableau de bord** ; elle ne peut pas être assignée à une clé API (une clé porteuse peut créer des clés mais jamais les modifier). | +| `keys:disable` | `POST /keys/:id/disable` | Révoquer une clé. Les clés protégées (`admin`, `dashboard-assistant`) ne peuvent pas être désactivées ; effectuez leur rotation via la variable d'environnement + redémarrage. | +| `keys:regenerate` | `POST /keys/:id/regenerate` | Faire tourner le secret d'une clé. Les clés protégées ne peuvent pas être régénérées via cette route. | + +### Utilisateurs du tableau de bord + +| Permission | Routes HTTP | Ce qu'elle autorise | +|---|---|---| +| `users:create` | `POST /users`, `GET /users/defaults` | Inviter un nouvel utilisateur du tableau de bord (envoie un e-mail + connexion OTP) et lire l'ensemble de permissions par défaut configuré dans le tableau de bord, utilisé pour pré-remplir le formulaire d'invitation. | +| `users:read` | `GET /users`, `GET /users/:id` | Lister les utilisateurs et charger un enregistrement d'utilisateur unique. | +| `users:update` | `PUT /users/:id` | Modifier les permissions d'un utilisateur. Les mises à jour envoient un e-mail de notification de changement de permissions à l'utilisateur concerné et prennent effet à sa prochaine requête ; aucune reconnexion n'est requise. | +| `users:delete` | `DELETE /users/:id`, `POST /users/:id/enable` | Désactiver un utilisateur (révoque ses sessions immédiatement) et réactiver un utilisateur précédemment désactivé. | + +Ces permissions alimentent la page **Utilisateurs** du tableau de bord, où les scopes accordés à chaque membre sont affichés sous forme de puces : + +![La page Utilisateurs : une carte par utilisateur du tableau de bord avec son e-mail, les permissions accordées, et les contrôles de modification/désactivation](/agenteye/images/users.png) + +### Paramètres opérationnels + +| Permission | Routes HTTP | Ce qu'elle autorise | +|---|---|---| +| `settings:read` | `GET /settings`, `GET /settings/schema`, `GET /settings/model-context-windows`, `GET /settings/model-context-windows/resolve` | Consulter les paramètres opérationnels gérés par le tableau de bord et leurs métadonnées ; lister les surcharges de fenêtre de contexte par modèle ; et résoudre la fenêtre effective pour un modèle. | +| `settings:write` | `PUT /settings/:key`, `PUT /settings/model-context-windows`, `DELETE /settings/model-context-windows` | Modifier les paramètres opérationnels et ajouter, modifier ou supprimer des surcharges de fenêtre de contexte par modèle. Les modifications s'appliquent aux nouveaux événements sans redémarrer le serveur. | + +![La page Paramètres : paramètres opérationnels gérés par le tableau de bord tels que les connexions autorisées et les durées de vie des sessions/OTP, modifiables sans redémarrage](/agenteye/images/settings.png) + +### Alertes et incidents + +| Permission | Routes HTTP | Ce qu'elle autorise | +|---|---|---| +| `alerts:read` | `GET /alerts`, `GET /alerts/:id` | Consulter les définitions d'alertes configurées. | +| `alerts:write` | `POST /alerts`, `PUT /alerts/:id`, `DELETE /alerts/:id`, `POST /alerts/:id/test` | Créer, modifier, supprimer et tester des définitions d'alertes. | +| `incidents:read` | `GET /alerts/incidents`, `GET /alerts/incidents/:iid`, `GET /alerts/incidents/:iid/comments`, `GET /alerts/incidents/:iid/subscribers` | Consulter les incidents et leur historique de triage. | +| `incidents:write` | `POST /alerts/:id/incidents` | Ouvrir manuellement un incident sur une alerte existante. | +| `incidents:ack` | `POST /alerts/incidents/:iid/ack`, `POST /alerts/incidents/:iid/assign`, `POST /alerts/incidents/:iid/resolve`, `POST /alerts/incidents/:iid/comments`, `POST /alerts/incidents/:iid/subscribe`, `POST /alerts/incidents/:iid/unsubscribe` | Accuser réception, assigner, résoudre et commenter des incidents. | + +### Audits + +| Permission | Routes HTTP | Ce qu'elle autorise | +|---|---|---| +| `audits:read` | `GET /audits`, `GET /audits/:id`, `GET /audits/:id/runs`, `GET /audits/findings`, `GET /audits/findings/:fid` | Consulter les définitions d'audits, l'historique des exécutions et les résultats. | +| `audits:write` | `POST /audits`, `PUT /audits/:id`, `DELETE /audits/:id`, `POST /audits/:id/run`, `POST /audits/findings/:fid/status` | Créer, modifier, supprimer et exécuter des audits ; effectuer le triage des résultats (accuser réception / mettre en sourdine / rejeter / résoudre / rouvrir / assigner). | + +> Lors du déploiement des Audits, les bénéficiaires existants ont vu leurs droits élargis selon les mêmes formes de rôles que les alertes : tout utilisateur et ensemble de permissions détenant `alerts:read` a obtenu `audits:read`, et tout détenteur de `alerts:write` a obtenu `audits:write`. Les clés API existantes n'ont **pas** été élargies — accordez `audits:*` à une clé explicitement si elle a besoin de la surface d'audit. + +> Les grants stockés du jeton legacy `alerts:ack` sont interprétés comme `incidents:ack`, afin que les personnes d'astreinte conservent leur accès sans devoir régénérer leur clé. Ce jeton n'est plus assignable depuis l'éditeur d'utilisateurs du tableau de bord ; la matrice propose `incidents:ack` à la place. + +> L'endpoint de sélection des destinataires `GET /alerts/recipients` (qui liste les e-mails des membres qu'un éditeur d'alertes peut notifier) est accessible par un détenteur de **soit** `alerts:read` **soit** `alerts:write`, de sorte que les éditeurs d'alertes peuvent remplir le sélecteur sans disposer de `users:read`. + +> Un lecteur de tableaux de bord a besoin à la fois de `dashboards:read` (pour charger les vues sauvegardées) et de `evaluations:read` (les métriques de santé sont calculées à partir des données d'évaluation). Accordez `dashboards:write` pour permettre à un utilisateur de créer ou modifier des tableaux de bord, et `dashboards:delete` pour les supprimer. + +> `/health` et `/auth/*` (demande OTP, vérification OTP, vérification de session, déconnexion) sont intentionnellement non authentifiés ; ils constituent le flux de connexion et la sonde de disponibilité. `GET /access-granters` requiert une clé valide mais aucune permission spécifique, de sorte que tout utilisateur connecté peut voir quels administrateurs contacter concernant les changements d'accès. + +--- + +## Ensembles de permissions + +Les ensembles de permissions vous permettent d'appliquer un rôle nommé plutôt que de sélectionner manuellement des jetons individuels à chaque fois. Plutôt que de choisir une douzaine de permissions une par une pour chaque nouvel utilisateur du tableau de bord ou clé API, vous sélectionnez un ensemble, et tous les membres qui y sont assignés bénéficient d'un grant cohérent et vérifiable. La modification d'un ensemble personnalisé réapplique le nouveau grant à chaque utilisateur qui y est déjà assigné, de sorte qu'un changement de rôle est une seule modification plutôt qu'un balayage de tous les membres. + +Chaque organisation est initialisée avec trois ensembles intégrés : + +| Ensemble | Permissions | Destiné à | +|---|---|---| +| `read-only` | `events:read`, `keys:read`, `users:read`, `evaluations:read`, `dashboards:read`, `queries:read`, `settings:read`, `alerts:read`, `audits:read`, `incidents:read` | Accès en lecture seule sur toutes les surfaces opérationnelles. | +| `standard` | tout ce qui est dans `read-only`, plus `evaluations:trigger`, `queries:run`, `incidents:ack`, `agent:use` | Lecture seule plus les actions quotidiennes des personnes d'astreinte : exécuter des requêtes, réévaluer des sessions, accuser réception d'incidents et utiliser l'assistant IA. | +| `admin` | toutes les permissions assignables | Contrôle total de l'organisation. | + +Les trois ensembles intégrés sont **immuables** ; leurs noms ont toujours la même signification, de sorte que `read-only`, `standard` et `admin` peuvent être référencés en toute sécurité dans les politiques et l'onboarding. Un opérateur peut créer des **ensembles personnalisés** supplémentaires pour modéliser des rôles spécifiques à votre organisation (par exemple, un rôle « auteur de tableau de bord » ou un rôle « collecteur uniquement »). + +Les ensembles sont accessibles dans le tableau de bord et gérés via l'API sur `GET /permission-sets` (liste, contrôlée par `users:read`) et `POST /permission-sets` / `PUT /permission-sets/:name` / `DELETE /permission-sets/:name` (créer, modifier, supprimer un ensemble personnalisé, contrôlé par `settings:write`). La suppression ou la modification d'un ensemble intégré est refusée. + +L'appartenance à un ensemble est ce qui alimente deux autres fonctionnalités : + +- **`DEFAULT_USER_PERMISSIONS`** (le grant présélectionné lorsqu'un administrateur ouvre **+ nouvel utilisateur**) est par défaut l'ensemble `standard`. Voir [Déploiement](/fr/agenteye/deployment). +- **L'option `--set`** sur `agenteye-orgctl` (gestion des membres par l'opérateur) initialise un membre à partir d'un ensemble nommé, que vous affinez ensuite avec `--add` / `--remove`. Voir [Gestion des locataires](/fr/agenteye/tenant-management). + +> Lorsqu'un ensemble inclut une permission non assignable à une clé (par exemple un ensemble personnalisé portant `keys:update`), l'initialisation d'une clé à partir de cet ensemble supprime les jetons non assignables ; le serveur refuserait sinon la clé avec HTTP 422. Les utilisateurs du tableau de bord ne sont pas soumis à cette restriction. + +--- + +## Clé admin de bootstrap + +La clé admin est l'unique credential racine qui permet à un opérateur de mettre en place l'accès à partir de rien : avec elle, vous pouvez créer toutes les autres clés à portée limitée, inviter les premiers utilisateurs du tableau de bord et configurer l'instance avant qu'aucune autre clé n'existe. C'est la seule clé que vous ne créez pas via l'API des clés ; elle est provisionnée depuis l'environnement afin que le serveur soit accessible au premier démarrage. + +Définissez la variable d'environnement `ADMIN_KEY` sur le serveur. À chaque démarrage, le serveur effectue un upsert de cette valeur comme clé admin avec toutes les permissions. + +Pour effectuer une rotation : modifiez `ADMIN_KEY` avec un nouveau secret et redémarrez le serveur. + +--- + +## Portée des organisations + +**Les organisations elles-mêmes sont créées et gérées hors bande par un opérateur, et non via cette API des clés.** Le cycle de vie des organisations et des membres (créer / renommer / supprimer / purger une organisation ; ajouter / mettre à jour / supprimer un membre) est géré avec le CLI **`agenteye-orgctl`** qui s'exécute dans le pod serveur ; il n'existe pas d'API HTTP ni de bouton dans le tableau de bord pour cela. Voir [Gestion des locataires](/fr/agenteye/tenant-management). Ce qui *reste* inchangé : **les clés API par organisation sont toujours créées dans le tableau de bord (ou via cette API des clés)** par les membres de l'organisation. + +Dans un déploiement multi-organisations, chaque clé créée par un membre d'une organisation (via cette API des clés ou la page **Clés** du tableau de bord) appartient à **une seule organisation** et ne peut lire ou écrire que les données de cette organisation ; l'organisation est estampillée sur la clé à sa création et appliquée à chaque requête. Les deux clés de bootstrap font exception : la clé `admin` (initialisée depuis `ADMIN_KEY`) et la clé `dashboard-assistant` (initialisée depuis `AGENT_API_KEY`) ont une **portée d'instance** (elles ne portent aucune organisation). Le conteneur du tableau de bord s'authentifie avec la clé `admin` afin de pouvoir transmettre les requêtes par organisation au nom des membres connectés. Les déploiements mono-locataire n'ont pas à s'en préoccuper ; toutes les clés appartiennent à l'organisation `default` intégrée. + +--- + +## Création de clés + +Utilisez la clé admin (ou toute clé avec la permission `keys:create`) pour créer des clés à portée limitée supplémentaires. + +### Clé de collecteur (ingestion uniquement) + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "prod-collector", + "key": "your-collector-secret", + "permissions": ["events:add"] + }' +``` + +### Clé de tableau de bord (lecture seule) + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "dashboard", + "key": "your-dashboard-secret", + "permissions": ["events:read", "keys:read"] + }' +``` + +Lorsque vous créez une clé via l'API HTTP, vous fournissez vous-même la valeur `key` ; choisissez un secret fort et conservez-le en sécurité. (Le tableau de bord fonctionne à l'inverse : il génère un secret fort pour vous et l'affiche une seule fois à la création ; voir [Gestion des clés dans le tableau de bord](#key-management-in-the-dashboard).) La réponse confirme que la clé a été créée : + +```json +{ + "id": "550e8400-e29b-41d4-a716-446655440000", + "name": "prod-collector", + "permissions": ["events:add"], + "created_at": "2026-04-01T12:00:00Z" +} +``` + +--- + +## Listage des clés + +```bash +curl -s http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +Les secrets des clés ne sont pas retournés dans les réponses de liste, seulement les identifiants, les noms et les permissions. + +--- + +## Désactivation d'une clé + +La désactivation révoque l'accès immédiatement sans supprimer l'enregistrement de la clé. + +```bash +curl -s -X POST http://your-server:8080/keys//disable \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +--- + +## Régénération d'une clé + +Génère un nouveau secret pour une clé existante. L'ancien secret est invalidé immédiatement. + +```bash +curl -s -X POST http://your-server:8080/keys//regenerate \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +La réponse inclut le nouveau secret en clair, **affiché une seule fois**. + +--- + +## Gestion des clés dans le tableau de bord + +La page **Clés** du tableau de bord fournit une interface utilisateur pour toutes les opérations ci-dessus. Vous avez besoin d'une clé avec la permission `keys:read` pour consulter la liste, et de `keys:create` / `keys:update` / `keys:disable` / `keys:regenerate` pour les actions de création / modification / désactivation / régénération respectivement. La modification des permissions d'une clé (`keys:update`) est distincte de sa création (`keys:create`), ce qui vous permet d'accorder à un opérateur la capacité de créer des clés sans la capacité de modifier la portée des clés existantes, ou vice versa. La clé admin couvre toutes ces opérations. + +Lorsque vous créez une clé depuis le tableau de bord, vous ne fournissez pas le secret ; le tableau de bord génère un secret fort pour vous et l'affiche **une seule fois** à la création. Copiez-le immédiatement et conservez-le en sécurité ; il ne sera plus jamais affiché, exactement comme lors d'une régénération. Vous pouvez néanmoins choisir directement les permissions de la clé, ou les initialiser à partir d'un ensemble de permissions (voir ci-dessous). + +![La page Clés API : une carte par clé affichant son nom, les permissions accordées et la date de création, avec des actions de régénération et de désactivation ; les clés protégées comme `admin` sont marquées](/agenteye/images/api-keys.png) + +--- + +## Organisation recommandée des clés + +| Clé | Permissions | Utilisée par | +|---|---|---| +| `admin` (bootstrap via la variable d'environnement `ADMIN_KEY`) | toutes | Ops/configuration, et le conteneur du tableau de bord (s'authentifie avec `ADMIN_KEY`, transmet les requêtes utilisateurs avec vérification des permissions) | +| Clé de collecteur par hôte | `events:add` | Collecteur sur chaque machine agent | +| `dashboard-assistant` (bootstrap via la variable d'environnement `AGENT_API_KEY`) | `events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run` | Conteneur de l'assistant IA, initialisé automatiquement, **protégé** ; ne peut pas être modifié via l'API | +| Clé de télémétrie de l'assistant (optionnelle) | `events:add` | Auto-instrumentation de l'assistant IA, si activée | + +> **Clé de l'assistant.** La clé de l'assistant est **initialisée automatiquement** par le serveur depuis la variable d'environnement `AGENT_API_KEY` (le même secret que l'agent présente comme `AGENTEYE_API_KEY`) ; il n'y a pas d'étape manuelle de création de clé ni de clé admin impliquée. Ses permissions sont fixées dans le code source afin que la portée ne puisse pas être élargie par une mauvaise configuration : lecture sur les événements / évaluations / tableaux de bord, plus l'écriture sur les tableaux de bord et la lecture / écriture / exécution des requêtes pour le flux de création « Demander à l'IA d'écrire une requête ». Tout le SQL passe toujours par le même rôle en lecture seule et les mêmes vérifications `sql_guard` qu'une requête écrite par un utilisateur, de sorte que cela élargit la *surface de création*, pas la surface de données ; les opérations destructives (`queries:delete`, `dashboards:delete`) sont délibérément absentes de la clé de l'assistant. Comme la clé `admin`, elle est **protégée** : elle ne peut pas être désactivée ou régénérée via l'API des clés, seulement en changeant `AGENT_API_KEY` et en redémarrant. Les *utilisateurs* du tableau de bord ont également besoin de la permission `agent:use` pour voir et utiliser l'assistant. Si vous activez l'auto-instrumentation, donnez à l'assistant une clé séparée avec uniquement `events:add`. \ No newline at end of file diff --git a/docs/fr/agenteye/assistant.mdx b/docs/fr/agenteye/assistant.mdx new file mode 100644 index 00000000..a79baf82 --- /dev/null +++ b/docs/fr/agenteye/assistant.mdx @@ -0,0 +1,195 @@ +--- +title: "Assistant IA" +description: "Documentation de l'assistant IA AgentEye." +--- + +Le tableau de bord intègre un **assistant IA** optionnel — un panneau de conversation ancré sur le bord droit du tableau de bord, qui répond à des questions en langage naturel sur vos agents (« comment évolue la qualité en prod cette semaine ? », « quelles sessions ont généré des erreurs aujourd'hui ? », « résume cette session ») et, lorsque l'utilisateur approuve chaque action, rédige et sauvegarde des requêtes SQL ainsi que des tableaux de bord en son nom. Il cite des liens cliquables renvoyant directement aux sessions, requêtes et tableaux de bord concernés, et il est **conscient du contexte de la page** : posez une question sur « cette session » pendant que vous la consultez, et il sait de quoi vous parlez. + +Par défaut, le dock s'affiche comme un fin **rail vertical de 44px** : un glyphe d'invite `›_` et un point de santé coloré. Cliquez sur le rail (ou appuyez sur `⌘J` / `Ctrl+J`) pour déployer le panneau de conversation complet. Le panneau déployé est **redimensionnable** entre 320 et 640 pixels en faisant glisser son bord gauche ; votre largeur préférée est mémorisée entre les rechargements. + +Il fonctionne comme un petit conteneur **`agent`** interne (reposant sur le Claude Agent SDK) que seul le tableau de bord peut atteindre. Il est **désactivé par défaut** et reste masqué jusqu'à ce que vous configuriez un point de terminaison LLM. + +--- + +## Ce qu'il peut et ne peut pas faire + +- **Lit les données opérationnelles accessibles à l'utilisateur qui pose la question.** Événements, évaluations, sessions, file d'attente des tâches d'évaluation, requêtes sauvegardées et tableaux de bord sauvegardés, filtrés par requête selon les permissions de lecture de l'utilisateur. Les outils de lecture s'exécutent immédiatement. +- **Les écritures sont conditionnées par une approbation individuelle.** Il peut créer des requêtes sauvegardées (`create_saved_query`, `update_saved_query`), exécuter du SQL brouillon contre le rôle en lecture seule pour le valider (`run_query`), et assembler des tableaux de bord à partir de ces requêtes (`create_dashboard`, `update_dashboard`, `add_query_to_dashboard`). Chaque écriture met en pause l'exécution et affiche une invite **Approuver / Rejeter / poser une question** dans le chat ; le SDK n'appelle l'outil qu'une fois que l'opérateur clique sur Approuver. **La suppression n'est jamais disponible pour l'assistant** ; les opérations destructives restent entre les mains des opérateurs. +- **Le SQL rédigé passe par la même validation `sql_guard` et les mêmes rôles en lecture seule que le SQL écrit par l'utilisateur** (SELECT/WITH uniquement, pas de multi-instruction). L'exécution est routée selon les tables référencées : les requêtes portant sur les tables analytiques (events, evaluations, sessions) s'exécutent en tant qu'utilisateur ClickHouse en lecture seule de l'organisation (limité à cette org par une politique de ligne, avec un plafond d'exécution de 10s et un plafond de 100k lignes), tandis que les requêtes ne touchant que des tables relationnelles s'exécutent sur un rôle Postgres en lecture seule (10s, 10k lignes). L'assistant ne peut pas élargir la surface de données ; il ne peut qu'intervenir sur la surface de requêtes déjà accessible à l'opérateur. +- Il utilise une **clé d'assistant dédiée** (voir ci-dessous) initialisée avec un ensemble fixe de permissions ; même si le modèle se comporte mal, il ne peut pas dépasser ces périmètres. +- Chaque utilisateur du tableau de bord doit disposer de la permission **`agent:use`** pour voir et utiliser l'assistant. Les outils sont filtrés par requête pour correspondre aux permissions de données de l'utilisateur : un utilisateur avec `events:read` dispose des outils events, mais pas des outils `dashboards:write`. + +--- + +## Dock IA contextuel : compositeur sur `/queries`, chat ailleurs + +Le dock d'assistant sur le côté droit est **conscient du contexte de la page**. Le sélecteur de modèle, l'historique des conversations, le point de santé du modèle et le champ de saisie du chat restent inchangés, mais **les chips de suggestion de l'état vide, le texte de l'espace réservé et le point de terminaison backend que touche le message d'un utilisateur** basculent automatiquement selon la route actuelle. Le dock devient « l'assistant IA de la page sur laquelle vous vous trouvez ». + +**Deux backends, sélectionnés par page (avec des remplacements par chip).** + +| Route | Backend par défaut de la page | Pourquoi | +| ------------------------------ | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | +| `/queries`, `/queries/new` | `POST /api/agent/compose-sql` (sans boucle d'outils) | L'utilisateur part de zéro ; SQL avec premier token en ≤1s diffusé directement dans l'éditeur | +| `/queries/` (existant) | `POST /api/agent/chat` (assistant avec boucle d'outils complète), page par défaut | Les messages libres doivent permettre à l'utilisateur de tout demander (« explique ça », « qu'est-ce que ça fait ? ») ; les chips de refactorisation repassent par compose-sql via kind par chip | +| toutes les autres pages | `POST /api/agent/chat` (assistant avec boucle d'outils complète) | Outils de lecture + outils d'écriture conditionnés par approbation | + +Les chips sur `/queries/` portent un `kind` explicite pour qu'une même page puisse combiner les deux flux de manière fluide. L'ensemble de chips par défaut comprend deux chips **chat** (`explain the query on screen`, `what does this query do?`) et cinq chips **compose-sql** (`parameterize by date range`, `add a status='error' filter`, etc.). Les messages libres basculent sur le backend par défaut de la page (chat), donc une question comme « pourquoi c'est si lent ? » reçoit une réponse en prose, tandis qu'un clic sur le chip `parameterize by date range` passe par le point de terminaison compose et modifie le SQL. + +Quand le compositeur s'exécute en **mode édition** (il voit un `currentSql` non vide car l'utilisateur est sur `/queries/` ou `/queries/new` avec du SQL proposé déjà chargé), son prompt système bascule de « compose une nouvelle requête » vers « modifie le SQL fourni de façon minimale : préserve le choix des tables, les noms de colonnes, la structure des jointures, les alias, l'indentation ». Le modèle reçoit un ensemble distinct d'exemples résolus avant/après (paramétrer, ajouter un filtre, convertir en buckets horaires), de sorte qu'une refactorisation déclenchée par chip produit un diff minimal par rapport au SQL de l'éditeur, et non une réécriture complète. + +Cliquez sur un chip compose (ou saisissez librement sur `/queries/new`) → le SQL se diffuse dans le message de l'assistant sous forme de bloc ` ```sql ` délimité. **Au moment où le flux se termine, si Monaco est monté sur la route actuelle, l'éditeur s'active automatiquement en vue diff** (original à gauche, proposition à droite, un indicateur `▾ AI proposed an edit` en haut, et des boutons **Accept / Reject** en dessous). L'utilisateur n'a pas besoin de trouver ou de cliquer sur un bouton `Insert into editor` pour voir le diff. Ce bouton est toujours affiché sous le bloc SQL comme déclenchement manuel (utile après un Reject ou quand l'utilisateur a navigué ailleurs puis est revenu), et il reste le seul chemin lorsque l'utilisateur se trouve sur une page sans éditeur (par ex. la liste des requêtes sauvegardées) ; dans ce cas, il stocke le SQL dans `sessionStorage` et navigue vers `/queries/new`, où l'éditeur fraîchement monté lit le stockage au montage et ouvre la même vue diff. + +Si le SQL proposé est identique octet par octet à ce qui est déjà dans l'éditeur (modification sans effet), l'ouverture automatique est ignorée ; on n'affiche pas un diff vide. Le bouton `Insert into editor` est également sans effet dans ce cas. + +Lorsque l'utilisateur accepte une suggestion sur `/queries/new`, l'action principale de la barre d'outils affiche **`save`** plutôt que `create` ; le SQL lui a été proposé par l'assistant ; le modèle mental est « finalise ça », pas « écris depuis zéro ». Le libellé bascule une fois que le dock insère le SQL et reste sur `save` jusqu'à la navigation. Sur `/queries/`, le bouton a toujours affiché `save` ; rien ne change. + +En dehors de `/queries`, le dock fonctionne exactement comme avant : chat complet avec cartes d'approbation d'outils, conscience du contexte de page, citations. + +**Permissions et conditions d'accès.** Le point de terminaison compose est conditionné par la permission `queries:run` par utilisateur (équivalent lecture ; l'utilisateur doit quand même cliquer sur Accepter et Exécuter, et l'exécution passe par le `sql_guard` + le routage `references_ch_tables` existants sur le serveur Rust). Le point de terminaison chat est conditionné par `agent:use`. Les deux nécessitent une connexion LLM configurée sur le conteneur `agent` ; si aucune n'est configurée, le dock affiche une bannière « l'assistant n'est pas configuré sur ce déploiement » sur l'un ou l'autre chemin. + +**Refus.** Le compositeur refuse toute demande qu'il ne peut pas satisfaire avec une requête analytique en lecture seule et émet `-- REFUSE: ` au lieu du SQL. Il refuse les demandes qui écriraient des données ou accéderaient à des tables en dehors des vues analytiques (`api_keys`, `users`, `dashboards`, `saved_queries`, `evaluation_jobs`), et il refuse les demandes purement en prose (« explique ça », « qu'est-ce que ça fait ? ») sur le chemin compose ; celles-ci appartiennent au chemin chat et y produisent une réponse en prose. Le dock rend la chaîne de refus sous forme de chip d'erreur rouge inline dans le message de l'assistant ; rien n'est inséré. + +**Sélection du modèle.** Partagée avec le chemin chat. Le sélecteur de modèle dans l'en-tête du dock s'applique aux deux points de terminaison (l'appel compose transmet le modèle sélectionné à `resolveModel()` sur le service agent). Lorsque `AGENTEYE_AGENT_MODELS` liste plusieurs modèles, les opérateurs peuvent combiner une option de classe Haiku pour le compositeur avec une option de classe Sonnet pour le chat ; l'utilisateur choisit par conversation. + +**Templates par page.** Chaque page possède son propre template (titre, corps de texte, texte d'espace réservé et chips de suggestion) pour que le dock s'adapte à la page sur laquelle vous vous trouvez. Les chips proposées sur une route donnée correspondent aux mêmes intentions pour lesquelles le compositeur est optimisé, de sorte qu'un clic sur une suggestion produit la modification attendue. + +**Désactivation.** Identique au chemin chat : le dock et le compositeur sont tous deux conditionnés par le conteneur `agent` et sa connexion LLM. Si vous souhaitez un comportement chat uniquement pour un utilisateur particulier, supprimez la permission `queries:run` (ce qui désactive également le bouton **Run** de l'éditeur) ; si vous souhaitez un comportement compositeur uniquement, supprimez `agent:use` des rôles de cet utilisateur, puis réajoutez `queries:run` séparément afin qu'il puisse toujours exécuter du SQL écrit par des auteurs. + +--- + +## Activation + +Le service `agent` est fourni dans le fichier Docker Compose et les manifestes Kubernetes. Pour activer l'assistant, fournissez **(1)** un point de terminaison LLM et **(2)** la clé de données dédiée de l'assistant. + +### 1. Choisir une connexion LLM + +Sélectionnez l'une des options suivantes et définissez les variables correspondantes sur le service `agent` : + +**a) Anthropic directement** + +``` +ANTHROPIC_API_KEY=sk-ant-... +``` + +**b) Via Portkey (recommandé ; slug du catalogue de modèles, clé uniquement)** + +``` +PORTKEY_API_KEY= +AGENTEYE_AGENT_MODEL=@/claude-sonnet-4-6 +``` + +C'est le chemin le plus simple : dans Portkey, configurez une **intégration Anthropic** (Catalogue de modèles) ; elle obtient un **slug**. Nommez le modèle comme `@/` et le slug prend en charge le routage du fournisseur et des identifiants, donc **aucune clé virtuelle n'est nécessaire**, seulement votre clé API Portkey. L'agent envoie uniquement `x-portkey-api-key` et pointe vers la passerelle Portkey ; Portkey résout le reste. (Un nom de modèle *simple* échoue avec « x-portkey-config or x-portkey-provider header is required » ; le préfixe `@slug/` est ce qui permet le fonctionnement avec clé seule.) Pour une passerelle auto-hébergée, définissez `PORTKEY_BASE_URL`. + +Vous préférez un routage par requête plutôt qu'un slug ? Définissez `PORTKEY_VIRTUAL_KEY=` (ou `PORTKEY_CONFIG=`) avec un `AGENTEYE_AGENT_MODEL` simple. + +**c) Toute autre passerelle compatible Anthropic (LiteLLM, auto-hébergée, …)** + +``` +ANTHROPIC_BASE_URL=https://your-gateway +# Lignes "Name: Value" délimitées par des sauts de ligne (PAS du JSON) : +ANTHROPIC_CUSTOM_HEADERS=x-my-header: value +``` + +**d) Amazon Bedrock / Google Vertex** + +``` +CLAUDE_CODE_USE_BEDROCK=1 # + identifiants AWS standard dans l'environnement +# ou +CLAUDE_CODE_USE_VERTEX=1 # + identifiants GCP standard dans l'environnement +``` + +Épinglez optionnellement le modèle par défaut avec `AGENTEYE_AGENT_MODEL` (par défaut `claude-sonnet-4-6`). Pour permettre aux utilisateurs de **choisir** parmi plusieurs modèles, définissez `AGENTEYE_AGENT_MODELS` avec une liste autorisée séparée par des virgules (par ex. `@anthropic-prod/claude-opus-4-7,@anthropic-prod/claude-sonnet-4-6`) ; un sélecteur de modèle apparaît alors dans l'en-tête du chat, et le choix de chaque utilisateur est mémorisé. L'agent n'appelle que des modèles figurant dans cette liste autorisée. + +### 2. Fournir la clé de l'assistant + +Choisissez n'importe quel secret aléatoire et transmettez-le à l'**agent** comme `AGENTEYE_API_KEY` et au **serveur** comme `AGENT_API_KEY` (même valeur). Au démarrage, le serveur l'initialise comme clé dédiée nommée `dashboard-assistant` avec cet ensemble fixe de permissions : `events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run`. Les permissions d'écriture ne sont exercées que via des outils conditionnés par approbation (voir « Ce qu'il peut et ne peut pas faire » ci-dessus). **Il n'y a pas d'étape manuelle de création de clé ni de clé admin impliquée.** L'ensemble des permissions est fixé dans le serveur, et la clé initialisée est **protégée** : elle ne peut pas être désactivée ni régénérée via l'API des clés ; pour la faire pivoter, modifiez la valeur et redémarrez le serveur. **Ne réutilisez pas** la clé admin/tableau de bord. + +```bash +SECRET="$(openssl rand -base64 32)" +# sur le service agent : +AGENTEYE_API_KEY="$SECRET" +# sur le service serveur : +AGENT_API_KEY="$SECRET" +``` + +Sur Kubernetes, cela est câblé pour vous : placez `AGENTEYE_API_KEY` dans le secret `agenteye-agent` et le déploiement du serveur lit déjà cette même valeur comme `AGENT_API_KEY`. + +### 3. Définir le token partagé tableau de bord↔agent + +Définissez le même `AGENTEYE_AGENT_TOKEN` à la fois sur les services `dashboard` et `agent`. Le tableau de bord le présente lors des appels au service agent interne ; l'agent rejette les appels sans ce token. + +### 4. Accorder l'accès aux utilisateurs + +Donnez aux opérateurs du tableau de bord concernés la permission `agent:use` (voir [enterprise-docs/api-keys.md](/fr/agenteye/api-keys)). Les utilisateurs sans cette permission ne voient jamais l'assistant. + +Une fois un point de terminaison LLM et la clé en lecture seule configurés, redémarrez le **serveur** (pour initialiser la clé en lecture seule) et le service **agent**. Le dock de l'assistant apparaît sur le bord droit pour tout utilisateur avec `agent:use`, réduit par défaut ; cliquez sur le rail ou appuyez sur `⌘J` / `Ctrl+J` pour le déployer. + +--- + +## Référence des variables d'environnement + +À définir sur le service **`agent`** : + +| Variable | Rôle | +|---|---| +| `PORTKEY_API_KEY` | Routage via Portkey (l'agent construit la connexion à la passerelle à partir de ceci) | +| `PORTKEY_VIRTUAL_KEY` | Clé virtuelle Portkey pour vos identifiants Anthropic (optionnel si la clé a une configuration par défaut) | +| `PORTKEY_CONFIG` / `PORTKEY_BASE_URL` | Configuration Portkey nommée / URL de la passerelle Portkey auto-hébergée (optionnel) | +| `PORTKEY_PROVIDER` | Slug de fournisseur Portkey — une troisième option de routage aux côtés de `PORTKEY_VIRTUAL_KEY` / `PORTKEY_CONFIG` (utilisé uniquement si ni l'un ni l'autre n'est défini) | +| `ANTHROPIC_API_KEY` | Accès direct à Anthropic (alternative à une passerelle / Bedrock / Vertex) | +| `ANTHROPIC_AUTH_TOKEN` | Token Bearer pour une passerelle qui s'authentifie via `Authorization: Bearer` plutôt que `x-api-key` (optionnel) | +| `ANTHROPIC_BASE_URL` | Point de terminaison pour une passerelle non-Portkey | +| `ANTHROPIC_CUSTOM_HEADERS` | En-têtes supplémentaires pour une passerelle non-Portkey : lignes `Name: Value` délimitées par des sauts de ligne (pas du JSON) | +| `CLAUDE_CODE_USE_BEDROCK` / `CLAUDE_CODE_USE_VERTEX` | Routage via Bedrock / Vertex | +| `AGENTEYE_AGENT_MODEL` | Identifiant du modèle par défaut (par défaut `claude-sonnet-4-6`) | +| `AGENTEYE_AGENT_MODELS` | Liste autorisée de modèles séparés par des virgules parmi lesquels l'utilisateur peut choisir dans l'en-tête du chat. Laissez non défini pour un modèle fixe unique. Le modèle par défaut ci-dessus doit en faire partie (sinon il est ajouté). | +| `AGENTEYE_AGENT_MAX_CONCURRENCY` | Nombre maximal de chats simultanés par pod (par défaut 4) ; les requêtes en excès reçoivent un 429 | +| `AGENTEYE_API_KEY` | Clé de données de l'assistant. Définissez la **même** valeur que `AGENT_API_KEY` du serveur, qui l'initialise avec un ensemble fixe de permissions limitées au démarrage (voir étape 2). | +| `AGENTEYE_AGENT_TOKEN` | Secret partagé avec le tableau de bord | +| `AGENTEYE_SERVER_URL` | URL du serveur AgentEye (par défaut `http://server:8080`) | +| `AGENTEYE_AGENT_ALLOW_NO_ORG` | **Multi-tenant.** Désactivé par défaut (fail-closed) : l'assistant rejette une requête `/chat` ne portant aucun contexte d'organisation avec `400`, car chaque outil qu'il exécute est limité à une org. Le tableau de bord envoie toujours ce contexte une fois qu'il est conscient des orgs, donc vous laissez normalement ceci non défini. Définissez à `1` **uniquement** lors d'un déploiement progressif où un tableau de bord non encore conscient des orgs communique avec un agent conscient des orgs, afin que l'assistant revienne à l'org `default` plutôt que de refuser. Supprimez-le une fois la mise à niveau du tableau de bord effectuée. | +| `AGENTEYE_AGENT_MAX_STEPS` | Nombre maximal d'étapes d'utilisation d'outils par réponse (par défaut 8) | +| `AGENTEYE_AGENT_TIMEOUT_MS` | Timeout global de la requête `/chat` (tous les tours de modèle + étapes d'outils), en millisecondes (par défaut 90000) ; l'outil SQL a son propre plafond de 10s | +| `AGENTEYE_AGENT_SELF_TELEMETRY` | `1` pour enregistrer les propres exécutions de l'assistant dans AgentEye | +| `AGENTEYE_TELEMETRY_API_KEY` | Clé dédiée `events:add` uniquement pour l'auto-instrumentation | +| `AGENTEYE_AGENT_ENV` | Tag d'environnement appliqué à la propre télémétrie de l'assistant (par défaut `prod`) | + +À définir sur le service **`dashboard`** : + +| Variable | Rôle | +|---|---| +| `AGENTEYE_AGENT_URL` | Adresse à laquelle le tableau de bord atteint le service agent. Les manifestes Kubernetes et le fichier Compose fournis définissent ceci à `http://agent:9100`. Laissez non défini pour masquer entièrement l'assistant. | +| `AGENTEYE_AGENT_TOKEN` | Doit correspondre au token de l'agent | + +--- + +## Télémétrie et observation de ce que demandent les utilisateurs + +Le **contenu des prompts reste dans vos propres systèmes** par défaut. Trois couches : + +1. **Stockage des conversations** : chaque prompt et réponse est sauvegardé dans votre base de données AgentEye (par utilisateur, privé), et rechargeable depuis le sélecteur d'historique de l'assistant. Il s'agit du registre durable de ce que demandent les utilisateurs. +2. **Analytique produit** : le tableau de bord enregistre **uniquement des métadonnées** (fréquence d'utilisation de l'assistant, nombre d'outils, latence) dans votre système analytique. Le **texte** des prompts n'est jamais inclus sur ce chemin. +3. **Auto-instrumentation (optionnelle)** : définissez `AGENTEYE_AGENT_SELF_TELEMETRY=1` (plus un `AGENTEYE_TELEMETRY_API_KEY` dédié `events:add` uniquement) et l'assistant enregistre ses propres exécutions dans AgentEye comme agent `dashboard-assistant`. Vous pouvez alors observer les prompts des utilisateurs et le raisonnement de l'assistant dans les mêmes vues sessions/events que vous utilisez pour tout le reste. Remarque : ces événements sont visibles par toute personne disposant de `events:read` ; si c'est trop large, laissez ceci désactivé. + +--- + +## Désactivation + +L'une ou l'autre de ces actions désactive l'assistant (le rail du dock disparaît) : + +- Désactiver `AGENTEYE_AGENT_URL` sur le tableau de bord, **ou** +- Laisser le point de terminaison LLM non configuré sur l'agent (pas d'`ANTHROPIC_API_KEY` / passerelle / Bedrock / Vertex), **ou** +- Ne pas déployer le service `agent` du tout. + +--- + +## Résumé de sécurité + +- **Pas d'écritures silencieuses** : les outils d'écriture de l'assistant (`create_saved_query`, `update_saved_query`, `create_dashboard`, `update_dashboard`, `add_query_to_dashboard`) ne peuvent pas s'exécuter sans un clic explicite de l'opérateur sur le bouton Approuver dans le chat ; la porte de pré-appel du SDK bloque l'outil jusqu'à ce qu'une approbation parvienne à l'agent via un canal secondaire. Aucun paramètre ne désactive cette porte. +- **Périmètre de données fixe et restreint** : l'assistant s'authentifie auprès du serveur avec une clé dédiée dont l'ensemble de permissions est fixé dans le serveur (`events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run`). Les seules écritures qu'il peut effectuer concernent les requêtes sauvegardées et les tableaux de bord ; le serveur rejette tout ce qui est en dehors de ce périmètre, quelle que soit la tentative du modèle. +- **Pas de surface de suppression** : la clé ne porte aucune permission de suppression et aucun outil de suppression n'est exposé. Les opérateurs suppriment via l'interface du tableau de bord, jamais via l'assistant. +- **Interne uniquement** : l'agent n'a pas de route publique ; seul le tableau de bord peut l'appeler, et uniquement avec le token partagé. (Sur Kubernetes, une NetworkPolicy restreint l'agent à n'atteindre que le serveur AgentEye et le point de terminaison LLM.) +- **Portée par utilisateur** : seuls les utilisateurs avec `agent:use` ont accès à l'assistant, et seuls les outils correspondant aux permissions de lecture de chaque utilisateur lui sont fournis. +- **Pas de HTML brut / pas d'exfiltration de liens** : les réponses sont rendues en markdown assaini ; les liens externes sont neutralisés. + +Consultez [enterprise-docs/troubleshooting.md](/fr/agenteye/troubleshooting) pour les problèmes courants. \ No newline at end of file diff --git a/docs/fr/agenteye/audits.mdx b/docs/fr/agenteye/audits.mdx new file mode 100644 index 00000000..f062990c --- /dev/null +++ b/docs/fr/agenteye/audits.mdx @@ -0,0 +1,107 @@ +--- +title: "Audits — détection des améliorations agentiques" +description: "AgentEye Audits — documentation sur la détection des améliorations agentiques." +--- + + +Les audits sont des tâches récurrentes qui explorent vos journaux d'agent **entre les sessions** pour identifier ce qui mérite d'être amélioré. Là où une alerte surveille une métrique que vous connaissez déjà en quasi-temps réel, un audit *enquête* : selon un calendrier que vous définissez, il effectue un contrôle de politique déterministe sur la fenêtre temporelle, puis confie vos sessions à un **agent de fiabilité IA** — cet agent interroge les données lui-même, lit les transcriptions suspectes, et (si nécessaire) exécute de petits scripts d'analyse, avant de rédiger des **recommandations d'amélioration** accompagnées des preuves correspondantes. + +Utilisez les audits pour répondre à la question « que dois-je corriger ou améliorer dans mes agents ? » — et les alertes pour être notifié dès qu'un seuil précis est franchi. Chaque amélioration renvoie aux sessions et requêtes exactes qui la sous-tendent, et un seul clic crée une alerte préremplie pour détecter les récurrences. + +La surface du tableau de bord est **`//audits`** (barre latérale → *analyze* → *audits*), soumise aux permissions `audits:read` / `audits:write`. + +--- + +## Fonctionnement d'une exécution + +Chaque exécution comporte deux couches : un socle déterministe et une investigation agentique. + +### 1. Le contrôle de politique (déterministe) + +Avant tout démarrage du modèle, l'audit exécute un petit catalogue de **vérifications SQL par politique** sur la fenêtre : des requêtes agrégées bornées qui signalent les patterns problématiques connus et indiquent *combien* d'événements / *quelles* sessions correspondent — jamais le texte correspondant lui-même. Le catalogue comprend : + +- **Fuite de secrets / identifiants** dans les charges utiles d'événements — clés d'accès AWS, clés API `sk-…`, clés privées PEM, tokens JWT / bearer, et assignations d'identifiants `KEY=…`. +- **Marqueurs d'injection de prompt** — « ignore previous instructions », « reveal your system prompt », et similaires. +- **Données personnelles (PII)** — numéros au format SSN (heuristique). +- **Refus de permission d'outil** et **boucles de cycles d'appels d'outils incontrôlées**. + +Les correspondances de politique sont persistées comme résultats (type `policy`) qui **s'affichent toujours** (ils ne sont jamais écrêtés par le plafond par exécution), et ils sont transmis à l'agent IA comme points de départ. Cette couche ne nécessitant aucun modèle, un audit produit ses signaux de sécurité les plus importants même si l'agent IA est indisponible. + +### 2. L'investigation agentique (IA) + +L'audit lance ensuite un **agent de fiabilité autonome** (le même service Claude Agent SDK qui alimente l'assistant du tableau de bord, avec un prompt spécifique à l'audit). Compte tenu du **périmètre** de l'audit (agents sélectionnés × environnements) et de la **fenêtre temporelle**, l'agent : + +- exécute des requêtes SQL en lecture seule sur vos tables analytiques, +- lit quelques transcriptions de sessions représentatives, +- écrit et exécute optionnellement de courts **scripts Python dans un bac à sable isolé en pod** (pas de réseau, pas d'accès au système de fichiers, secrets supprimés) pour des analyses que SQL ne peut pas exprimer — regroupement d'erreurs, calcul de distributions, parcours des charges utiles déjà récupérées, +- et enregistre chaque **amélioration** bien étayée qu'il découvre. + +Il explore plusieurs axes d'investigation — regroupement d'erreurs, dérive par rapport à une référence, échec d'objectif dans les transcriptions, mauvaise utilisation des outils, compromis qualité/coût, et lacunes de couverture — selon la **sensibilité** de l'audit (faible / moyenne / élevée). Chaque amélioration **doit citer des preuves** : les identifiants de session que l'agent a réellement inspectés et/ou le SQL qu'il a exécuté. Le serveur vérifie que les sessions citées existent et **écarte toute amélioration sans preuve valide**, de sorte que l'agent enquête sans jamais inventer. + +Chaque amélioration comporte : + +- une **recommandation** (le changement concret à apporter — une modification de prompt, une correction de schéma d'outil, une politique de réessai, un garde-fou, une meilleure couverture d'évaluation), +- un **impact attendu** et une estimation de l'**effort** (faible / moyen / élevé), +- une **magnitude** — `big` (un opérateur doit être alerté), `medium` (appartient au rapport d'exécution), ou `small` (contexte du tableau de bord), +- une **empreinte** stable (issue de la catégorie et du périmètre du problème, *pas* des sessions de cette exécution) pour que le même problème soit suivi d'exécution en exécution même si les preuves changent, +- et, lorsqu'un observateur déterministe simple pourrait détecter les récurrences, une **alerte suggérée** que vous pouvez créer en un clic. + +> **La couche IA est optionnelle mais recommandée.** Si aucun agent IA n'est configuré pour le pipeline d'audit, les exécutions se déroulent quand même, les résultats de politique sont persistés, et le rapport indique honnêtement « analyse indisponible » pour la couche agentique plutôt que de passer silencieusement. + +### Modes d'échec + +Les améliorations se classent dans le **catalogue de modes d'échec** durable de votre organisation (ou proposent un nouveau mode). Les modes donnent aux patterns une identité stable entre les exécutions et permettent un suivi des récurrences sur le long terme. + +## Cycle de triage + +Sur une page de résultat (`/audits//findings/`) : + +| Action | Effet | +|---|---| +| **acknowledge** | Garde le résultat visible mais divise sa priorité par deux. | +| **resolve** | Le marque comme corrigé. Si le pattern réapparaît plus tard, il se rouvre comme **nouveau** — une régression est donc visible, pas silencieusement noyée dans l'historique. | +| **mute** / **dismiss** | Suppression durable : l'empreinte du pattern est mémorisée et ne s'affiche plus jamais, même entre les exécutions. Utilisez mute pour « connu, accepté » ; dismiss pour « non utile ». | +| **reopen** | Efface la suppression / résolution et classe de nouveau le pattern. | +| **assign** | Confie le résultat à un opérateur (un membre de l'organisation) pour en assumer la responsabilité. La priorité et l'état de suppression restent inchangés. | + +Le bruit à faible signal est contrôlé par audit avec un plafond de résultats par exécution (`top_k`) sur les améliorations agentiques. Les résultats de politique contournent ce plafond (ils sont pertinents pour la sécurité et toujours affichés). Tout ce qui est écrêté par le plafond est comptabilisé dans les statistiques de l'exécution — rien n'est silencieusement supprimé. + +## Planification + +- **Cadence** (`schedule_interval_secs`) : de toutes les heures à une fois par semaine ; **quotidien par défaut**. Les audits sont délibérément plus grossiers que les alertes — une investigation agentique analyse des fenêtres entières et s'exécute pendant plusieurs minutes. +- **Fenêtre** : soit un historique glissant fixe (p. ex. « chaque exécution analyse les 7 derniers jours »), soit **depuis la dernière exécution** (par défaut) — chaque exécution reprend là où la précédente réussie s'est arrêtée, avec un léger chevauchement pour ne jamais manquer les événements en limite de fenêtre. +- La prochaine exécution est planifiée un intervalle complet après la **fin** de la précédente, de sorte qu'une exécution lente ne provoque jamais une deuxième exécution concurrente du même audit. +- **Run now** sur la page d'audit la déclenche immédiatement. + +## Sélection du modèle + +Lors de la création d'un audit, vous pouvez choisir le modèle utilisé pour l'investigation, parmi la **liste des modèles que votre opérateur a configurés** pour le service d'agent. Avec un seul modèle configuré, le sélecteur l'affiche en légende ; avec plusieurs, vous choisissez. Laisser le champ vide utilise le modèle par défaut configuré. + +## Notifications + +Lorsqu'une exécution fait apparaître de **nouveaux** résultats, l'audit notifie les canaux configurés de votre organisation — le même portail `alerts.enabled_channels` et les mêmes paramètres que ceux utilisés par le pipeline d'alertes : + +- **Slack** — un résumé des nouveaux éléments significatifs (`big`) avec un lien direct. +- **Email** — un **rapport d'audit** structuré listant les nouvelles améliorations (gravité maximale, recommandations par élément, lien direct), envoyé lorsque l'audit dispose d'un canal **email** et qu'il y a au moins un nouveau résultat. + +Les résultats récurrents mais déjà connus ne génèrent pas de nouvelle notification. + +## Référence de configuration + +Les définitions d'audit sont gérées dans le tableau de bord (`/audits/new`) ou via l'API. Les paramètres par audit comprennent la cadence et la fenêtre de planification, le périmètre (`{"environments": [...], "agent_ids": [...]}`), la sensibilité (`low` / `medium` / `high`), les canaux de notification, le plafond de résultats par exécution (`top_k`), et le modèle (via `llm_budget.model`). Les paramètres serveur au niveau de l'opérateur (délais d'attente, bac à sable, URL du service d'agent) sont documentés dans [deployment.md](/fr/agenteye/deployment). + +## API + +Tous les endpoints sont limités à l'organisation et suivent l'authentification standard par clé bearer (voir [api-keys.md](/fr/agenteye/api-keys)). + +| Endpoint | Permission | Objectif | +|---|---|---| +| `GET /audits` · `POST /audits` | `audits:read` / `audits:write` | Lister / créer des définitions d'audit. | +| `GET` / `PUT` / `DELETE /audits/:id` | read / write / write | Consulter, modifier, supprimer un audit. | +| `POST /audits/:id/run` | `audits:write` | Déclencher l'audit immédiatement. | +| `GET /audits/:id/runs` | `audits:read` | Historique des exécutions (fenêtre, statut, statistiques, nombre de résultats). | +| `GET /audits/findings` | `audits:read` | Résultats à l'échelle de l'organisation, filtrables par `audit_id`, `status` ; triés par priorité. | +| `GET /audits/findings/:fid` | `audits:read` | Détail complet du résultat (recommandation, preuves, priorité). | +| `POST /audits/findings/:fid/status` | `audits:write` | Triage : `{"action": "ack" \| "mute" \| "dismiss" \| "resolve" \| "reopen" \| "assign"}`. | + +Pour les cas « l'audit s'est exécuté mais n'a rien trouvé », « le bac à sable de code est désactivé » et « l'email d'audit n'a pas été livré », consultez [troubleshooting.md](/fr/agenteye/troubleshooting#audits). \ No newline at end of file diff --git a/docs/fr/agenteye/cli-recipes.mdx b/docs/fr/agenteye/cli-recipes.mdx new file mode 100644 index 00000000..e8c44782 --- /dev/null +++ b/docs/fr/agenteye/cli-recipes.mdx @@ -0,0 +1,170 @@ +--- +title: "Recettes CLI pour les agents" +description: "Documentation des recettes CLI AgentEye pour les agents." +--- + + +Récupérez les données de sessions, d'événements et d'évaluations (et déclenchez des réévaluations) directement depuis un script ou un agent de codage, avec du JSON propre sur stdout qui se connecte directement à `jq`. Ces recettes transforment les données d'observabilité d'AgentEye en quelque chose qu'un utilisateur en ligne de commande ou un agent de codage IA (Claude Code, Cursor) peut interroger et automatiser, sans avoir à naviguer dans le tableau de bord. + +Les patterns ci-dessous sont prêts à être copiés-collés pour le CLI AgentEye (`agenteye`). Pour l'installation, l'authentification et la liste complète des options, consultez [CLI](/fr/agenteye/cli) ; exécutez `agenteye -h` ou `agenteye -h` pour l'aide intégrée. + +## Règles d'or + +1. **Les options globales se placent *avant* la commande.** `agenteye --json sessions` est correct ; `agenteye sessions --json` ne l'est pas. Les options globales sont `--json`, `--base-url`, `--org`, `--token`, `--insecure`/`--secure`, `--timeout`, `--quiet`, `--no-color`. +2. **Passez `--json` dès que vous analysez la sortie.** Les données vont sur **stdout** au format JSON ; les statuts lisibles et les erreurs vont sur **stderr**, ce qui permet à stdout de rester propre pour être connecté à `jq`. +3. **Basez-vous sur le code de sortie**, pas sur le texte de stderr : `0` ok · `2` arguments incorrects · `3` impossible d'atteindre le tableau de bord · `4` non connecté ou session expirée · `5` permission manquante. +4. **Explorez avec `-h`.** Chaque commande documente ses filtres, formats de valeurs et structure JSON. + +## Configuration initiale + +```bash +export AGENTEYE_DASHBOARD_URL=https://agenteye.example.com # pour éviter de répéter --base-url +agenteye login --email you@example.com # collez le code reçu par e-mail ; valide ~24h +``` + +## Vérifier l'authentification avant de travailler + +`whoami` ne génère jamais d'erreur en cas de session manquante ou expirée ; il renvoie `logged_in:false` à la place, permettant à un agent de sonder l'état d'authentification en toute sécurité. (Il peut quand même se terminer avec un code non nul si aucune URL de base n'est définie ou si le tableau de bord est inaccessible.) + +```bash +if [ "$(agenteye --json whoami | jq -r .logged_in)" != "true" ]; then + echo "Not authenticated. Run: agenteye login" >&2; exit 1 +fi +``` + +## Trouver les sessions en échec ou à faible score + +```bash +# sessions des dernières 24h dont l'évaluation a échoué +agenteye --json sessions --since 24h --status error | jq -r '.sessions[].session_id' + +# évaluations avec un score helpfulness <= 0.5, pour un agent spécifique +agenteye --json evals --agent-id checkout-bot --score helpfulness:..0.5 \ + | jq '.evaluations[] | {session_id, scores}' +``` + +Le filtrage par score s'effectue sur **`evals`**, pas sur `sessions`. `--score KEY:MIN..MAX` est répétable et combiné en AND ; chaque borne est optionnelle (`..0.5` signifie ≤ 0.5, `0.9..` signifie ≥ 0.9). Vous pouvez passer jusqu'à 20 filtres de score par requête ; au-delà, une erreur HTTP 400 est renvoyée. `sessions` partage les filtres `--env`, `--status`, `--agent-id`, `--session-id` et les plages temporelles avec `evals`, mais ne dispose pas de `--score`. + +## Lire une session de bout en bout + +Il n'existe pas de commande unique `session show` — combinez la trace d'événements avec l'évaluation de la session : + +```bash +# la dernière évaluation de la session (statut + scores) +agenteye --json evals --session-id run-001 | jq '.evaluations[0] | {status, scores}' + +# tous les événements du run (augmentez --limit pour un parcours complet) +agenteye --json events --session-id run-001 --all --limit 1000 | jq '.events[] | {ts, event_type}' + +# uniquement les appels d'outils d'une session +agenteye --json events --session-id run-001 --event-type tool_use,tool_result --all \ + | jq '.events[].payload' +``` + +## Tout récupérer (pagination) + +Les résultats sont triés du plus récent au plus ancien et paginés par curseur. + +```bash +# en une fois : récupère jusqu'à 500 lignes en pages de 200 lignes +agenteye --json events --session-id run-001 --limit 500 --all > events.json + +# pagination manuelle : réinjectez next_cursor +page=$(agenteye --json events --limit 100) +cursor=$(echo "$page" | jq -r '.next_cursor // empty') +[ -n "$cursor" ] && agenteye --json events --limit 100 --cursor "$cursor" +``` + +## Réduire la sortie avec --fields + +Limitez les clés (aussi bien dans le tableau que dans `--json`) pour réduire ce qu'un agent doit lire. + +```bash +agenteye --json sessions --since 7d --fields session_id,status,scores | jq -c '.sessions[]' +agenteye --json events --session-id run-001 --fields ts,event_type --all +``` + +Les noms de champs inconnus sont rejetés (sortie `2`) avec la liste des noms valides, un moyen pratique de découvrir les noms de champs. + +## Découvrir les valeurs de filtre valides + +```bash +agenteye --json list envs | jq -r '.values[]' # valeurs pour --env +agenteye --json list tools | jq -r '.values[]' # noms d'outils ; aussi agents, models, event_types, … +agenteye --json list score_filters | jq -r '.values[]' # KEY valide pour --score KEY:MIN..MAX +``` + +## Choisir votre organisation (multi-tenant) + +Si vous appartenez à plusieurs organisations, choisissez le tenant actif lors de la connexion (il est sauvegardé) : + +```bash +agenteye login --org acme --email you@corp.com # définir le tenant en même temps que la connexion +agenteye --json orgs list | jq -r '.orgs[].org_slug' +agenteye --org globex --json sessions --since 24h # remplacer pour une seule commande +``` + +Une connexion multi-org sans `--org` se termine avec un code non nul et affiche les organisations parmi lesquelles choisir. + +## Créer une clé API pour le SDK/collecteur + +```bash +# le secret est affiché UNE SEULE FOIS — avec --json c'est le champ .key +key=$(agenteye --json keys create ci-bot --add events:read.add | jq -r '.key') +agenteye keys regenerate ci-bot --yes # rotation ; agenteye keys disable ci-bot --yes pour révoquer +``` + +## Exécuter une requête sauvegardée ou ad-hoc + +```bash +agenteye --json query run --sql "select count(*) from analytics.events" | jq '.rows' +agenteye --json query run errs --arg prod | jq '.rows' # une requête sauvegardée + un argument positionnel $1 +``` + +## Gérer un incident de manière non interactive + +```bash +id=$(agenteye --json incidents list --state firing | jq -r '.incidents[0].id') +agenteye incidents ack "$id" +agenteye incidents assign "$id" you@corp.com +agenteye incidents resolve "$id" --yes +``` + +> Les mutations ignorent automatiquement leur invite de confirmation sous `--json` ou lorsque stdin n'est pas un TTY, de sorte que les agents ne se bloquent jamais ; passez `--yes`/`-y` pour l'ignorer explicitement ailleurs. + +## Gestion des codes de sortie dans un script + +```bash +out=$(agenteye --json sessions --since 1h) || code=$? +case "${code:-0}" in + 0) echo "$out" | jq '.sessions | length' ;; + 4) echo "Session expired - run 'agenteye login'." >&2 ;; + 5) echo "Missing permission (ask an admin for evaluations:read)." >&2 ;; + 3) echo "Dashboard unreachable - check the URL." >&2 ;; + *) echo "Unexpected error (exit ${code})." >&2 ;; +esac +``` + +## Formats de sortie JSON + +| Commande | JSON sur stdout (avec `--json`) | +|---|---| +| `whoami` | `{"logged_in": true, "id", "email", "is_instance_admin", "active_org", "permissions": [...], "memberships": [...]}` ou `{"logged_in": false}` | +| `orgs list` | `{"active_org", "orgs": [{"org_slug","org_name","permission_set","permissions"}]}` | +| `events` | `{"events": [...], "next_cursor": }` | +| `evals` | `{"evaluations": [...], "next_cursor": }` | +| `sessions` | `{"sessions": [...], "next_cursor": }` | +| `errors` | `{"errors": [...], "next_cursor": }` | +| `list ` | `{"kind", "values": [...]}` | +| `keys list` / `keys create` | `{"keys": [...]}` / `{id, name, permissions, created_at, key}` (`key` affiché une seule fois) | +| `query run` | `{columns: [{name,type}], rows: [[...]], truncated, elapsed_ms}` | +| `users list` / `settings list` | `{"users": [...]}` / `{"settings": [...]}` | +| `alerts list` / `incidents list` | `{"alerts": [...]}` / `{"incidents": [...]}` | +| create/update/delete (tous) | l'objet ressource, ou `{"deleted": true, "id"}` pour les suppressions | +| échec (tous, avec `--json`) | `{"error": "...", "exit_code": , "status"?: , "hint"?: "..."}` sur stdout | + +- Chaque élément **event** (`events`) : `id, session_id, agent_id, event_type, ts, payload, environment`. +- Chaque élément **evaluation** (`evals`) : `id, session_id, agent_id, environment, status, scores, reasoning, summary, error, attempt_count, duration_ms, completed_at, created_at`. +- Chaque élément **session** (`sessions`) : `session_id, agent_id, environment, status, scores, event_count, started_at, last_event_at, first_event_id, last_event_id, latest_evaluation`. + +Le `--fields` de chaque commande accepte exactement les noms de champs de ses propres éléments — l'ensemble diffère entre `sessions` et `evals`, donc un nom valide pour l'un peut être rejeté par l'autre. \ No newline at end of file diff --git a/docs/fr/agenteye/cli-skill.mdx b/docs/fr/agenteye/cli-skill.mdx new file mode 100644 index 00000000..499761f9 --- /dev/null +++ b/docs/fr/agenteye/cli-skill.mdx @@ -0,0 +1,95 @@ +--- +title: "Compétence d'agent CLI AgentEye" +description: "Documentation de la compétence d'agent CLI AgentEye." +--- + + +La **compétence CLI AgentEye** (`agenteye-cli`) est une *compétence d'agent* installable qui apprend à un agent de codage — Claude Code, Codex et les outils compatibles — à exploiter votre déploiement AgentEye via la [`agenteye` CLI](/fr/agenteye/cli) à partir de requêtes en langage naturel : *« est-ce que quelque chose est cassé aujourd'hui ? »*, *« donne à la CI une clé qui peut uniquement pousser des événements »*, *« accuse réception de l'incident en cours et assigne-le-moi »*. + +Il ne s'agit **pas** d'un service ni d'un binaire distinct. C'est un petit paquet d'instructions qui s'appuie sur la CLI que vous avez déjà installée : l'agent exécute `agenteye --json …`, analyse le JSON propre renvoyé et vous répond en langage naturel. Tout ce qu'il peut faire, vous pourriez le faire vous-même en saisissant les mêmes commandes. + +--- + +## Relation avec les autres interfaces AgentEye + +AgentEye vous offre quatre façons d'accéder aux mêmes données et contrôles. Elles se complètent : + +| Interface | Description | Où elle s'exécute | À utiliser quand | +|---|---|---|---| +| **[CLI](/fr/agenteye/cli)** | La référence des commandes et options pour `agenteye` | Votre terminal | Vous souhaitez exécuter ou scripter une commande précise | +| **[Recettes CLI](/fr/agenteye/cli-recipes)** | Modèles `jq`/pipeline à copier-coller | Votre terminal / vos scripts | Vous intégrez la CLI dans une automatisation | +| **Compétence CLI** (ce document) | Une interface en langage naturel pour la CLI | Votre agent de codage, sur votre poste de travail | Vous souhaitez simplement poser une question et laisser l'agent choisir la commande | +| **[Assistant IA intégré au tableau de bord](/fr/agenteye/assistant)** | Un chat intégré au tableau de bord | Un conteneur `agent` interne dans votre cluster | Vous souhaitez poser des questions en langage naturel sur vos données depuis le tableau de bord | + +### Par rapport à l'assistant IA intégré au tableau de bord — une distinction importante + +Ce sont deux outils différents avec des périmètres d'action très différents : + +- L'**assistant IA intégré au tableau de bord** ([assistant.md](/fr/agenteye/assistant)) est un chat intégré au tableau de bord, adossé à un conteneur `agent` interne. Il fonctionne en **lecture seule avec approbation pour toute création** : il peut rédiger des requêtes et des tableaux de bord sauvegardés, mais chaque écriture s'interrompt pour attendre votre approbation explicite, et il ne supprime jamais rien. Il est soumis à la permission `agent:use` et ne voit que les données de l'organisation que vous consultez. +- La **compétence CLI** s'exécute sur *votre* poste de travail, à l'intérieur de *votre* agent de codage, et pilote la CLI `agenteye` en tant que **vous**. Elle peut effectuer l'**ensemble des actions disponibles dans la CLI, y compris les mutations** — créer/faire tourner/désactiver des clés API, modifier les paramètres d'organisation, résoudre des incidents, supprimer des requêtes sauvegardées — dans la seule limite des permissions de votre session CLI. Traitez-la avec exactement autant de précaution que si vous exécutiez ces commandes manuellement. + +--- + +## Prérequis + +1. La **CLI `agenteye` installée** et accessible via `PATH` (voir [cli.md](/fr/agenteye/cli) — `pipx install agenteye`). +2. L'**URL de votre tableau de bord** configurée (`AGENTEYE_DASHBOARD_URL`, ou passée par l'agent via `--base-url`). +3. Une **session active** : exécutez `agenteye login` vous-même au préalable. La compétence **ne peut pas** réaliser à votre place la connexion par code à usage unique envoyé par e-mail — elle vous indiquera d'exécuter `agenteye login` si la session est manquante ou expirée (code de sortie CLI `4`). + +--- + +## Installation de la compétence + +Les compétences d'agent sont des dossiers contenant un fichier `SKILL.md` (plus des références optionnelles). Vous installez la compétence `agenteye-cli` en plaçant son dossier à l'endroit où votre agent recherche les compétences : + +- **Claude Code** — copiez le dossier `agenteye-cli/` dans `~/.claude/skills/` (disponible pour tous les projets) ou dans `/.claude/skills/` (limité à ce dépôt). Claude Code le découvre automatiquement ; vérifiez avec la liste `/skills`, ou posez simplement une question correspondant à sa description. +- **Codex (OpenAI)** — Codex lit le même `SKILL.md`. Le fichier `agents/openai.yaml` fourni définit `allow_implicit_invocation: true`, de sorte que Codex sélectionne automatiquement la compétence lorsqu'une tâche correspond ; sinon, invoquez-la explicitement avec `$agenteye-cli`. + +La compétence est maintenue aux côtés de la CLI `agenteye` et distribuée dans le cadre de votre package AgentEye — si vous ne disposez pas du dossier `agenteye-cli`, contactez votre interlocuteur AgentEye. Rien n'y est verrouillé : elle n'a besoin ni d'image Docker ni d'identifiant, car elle ne fait que piloter la CLI **publique** `agenteye` contre votre propre tableau de bord. + +--- + +## Sécurité — les mutations ne demandent PAS confirmation lorsqu'un agent exécute la CLI + +**Lisez ceci avant d'autoriser un agent à effectuer des modifications.** + +La CLI `agenteye` demande normalement *« êtes-vous sûr ? »* avant une action destructrice. Elle **ignore automatiquement cette confirmation lorsqu'elle n'est pas attachée à un terminal — ce qui correspond exactement à la façon dont un agent de codage l'exécute — et `--json` la passe également.** La demande de confirmation ne se **déclenchera donc pas** pour l'agent. + +La compétence est conçue pour compenser ce comportement : elle est instruite d'indiquer la commande exacte qu'elle va exécuter et d'obtenir votre **accord explicite avant tout changement d'état**. Maintenez cette discipline — lorsque vous pilotez AgentEye via un agent, *c'est vous* qui êtes l'étape de confirmation. Les commandes modifiant l'état à surveiller : + +- `keys create` / `update` / `disable` / `regenerate` +- `users create` / `update` / `disable` / `enable` +- `settings set` +- `alerts create` / `update` / `delete` / `test` +- les sous-commandes `incidents` avec écriture : `ack` / `assign` / `resolve` / `open` / `comment-add` / `comment-delete` / `subscribe` / `unsubscribe` +- `query create` / `update` / `delete` +- `agent rename` / `delete` +- `orgs switch` + +Tout ce qui relève d'**Observe** (`events`, `sessions`, `evals`, `errors`, `list`, `whoami`, `orgs list/current/perms`) est en lecture seule et ne modifie rien. + +L'agent agissant en tant que **vous**, il ne peut effectuer que ce que votre session est autorisée à faire — les permissions sont résolues **par organisation** (voir [api-keys.md](/fr/agenteye/api-keys)). Une commande pour laquelle vous ne disposez pas de la permission retourne le code de sortie `5` avec le nom exact de la permission manquante, ce qui permet à l'agent de vous indiquer précisément ce que vous devez demander à un administrateur, plutôt que d'échouer sans explication. + +--- + +## Ce que vous pouvez lui demander + +La compétence fait correspondre une intention exprimée en langage naturel à la bonne commande `agenteye`, en découvrant d'abord les valeurs valides (`list `, `whoami`) pour ne pas avoir à les deviner : + +- *« Est-ce que quelque chose est cassé / en échec ces dernières 24 heures ? »* → `errors --since 24h --aggregate`, puis une ventilation détaillée. +- *« Pourquoi la session `run-001` a-t-elle échoué ? »* → `events --session-id run-001 --all` + `evals --session-id run-001`. +- *« Comment évolue la qualité cette semaine ? »* → `evals --aggregate --since 7d`, puis exploration des exécutions avec un score faible. +- *« Donne à la CI une clé qui peut uniquement pousser des événements. »* → `keys create ci --add events:add` (elle indique la commande, la crée et capture le secret à usage unique). +- *« Qui a accès ? Passe Dana en lecture seule. »* → `users list` → `users update dana@… --permission-set read-only` (après confirmation de votre part). +- *« Accuse réception de l'incident en cours et assigne-le-moi. »* → `incidents list --state firing` → `incidents ack ` / `incidents assign vous@…`. + +Pour les commandes exactes, les options et les structures JSON sous-jacentes, consultez [cli.md](/fr/agenteye/cli) et [cli-recipes.md](/fr/agenteye/cli-recipes). + +--- + +## Voir aussi + +- **[CLI](/fr/agenteye/cli)** — référence complète des commandes et options pour `agenteye`. +- **[Recettes CLI pour agents](/fr/agenteye/cli-recipes)** — modèles `jq` à copier-coller et gestion des codes de sortie. +- **[Assistant IA](/fr/agenteye/assistant)** — l'assistant intégré au tableau de bord (à ne pas confondre avec cette compétence en terminal). +- **[Clés API](/fr/agenteye/api-keys)** — le modèle de permissions par organisation qui délimite ce que la compétence peut faire. \ No newline at end of file diff --git a/docs/fr/agenteye/cli.mdx b/docs/fr/agenteye/cli.mdx new file mode 100644 index 00000000..9f4805cf --- /dev/null +++ b/docs/fr/agenteye/cli.mdx @@ -0,0 +1,292 @@ +--- +title: "CLI" +description: "Documentation de la CLI AgentEye." +--- + + +La CLI AgentEye (`agenteye`) est un client terminal pour votre déploiement AgentEye. Elle interroge vos données (sessions, journaux d'événements, évaluations) et administre l'organisation (clés API, utilisateurs, paramètres, alertes, incidents, requêtes sauvegardées) — tout ce que fait le tableau de bord, depuis un script ou un agent de codage. Chaque commande accepte un indicateur `--json`, ce qui la rend aussi bien adaptée à une utilisation humaine en ligne de commande qu'à un agent de codage (Claude Code, Cursor) qui l'exécute et analyse le résultat. + +> Il s'agit de la **CLI `agenteye`**, un outil distinct du démon **collecteur** (`agenteye-collector`). La CLI communique avec votre **tableau de bord** ; le collecteur envoie les événements au serveur. Consultez [Installation du collecteur](/fr/agenteye/collector-installation) pour le collecteur. + +--- + +## Installation + +La CLI est publiée sur PyPI public sous le nom **`agenteye`**. Comme le SDK Python AgentEye utilise également le nom de distribution `agenteye`, installez la CLI dans un environnement **isolé** (`pipx` ou `uv tool`) pour éviter tout conflit dans un même virtualenv : + +```bash +pipx install agenteye +# ou +uv tool install agenteye +``` + +Un simple `pip install agenteye` fonctionne également si vous n'installez pas le SDK Python dans le même environnement. La CLI nécessite Python 3.10+ et n'a pas besoin de jeton GitHub ; c'est un paquet public. + +La commande installée est **`agenteye`** : + +```bash +agenteye --version +agenteye --help +``` + +--- + +## Authentification + +La CLI s'authentifie auprès du **tableau de bord** via un code à usage unique envoyé par e-mail : + +```bash +agenteye login --email you@example.com +# Un code à 6 chiffres vous est envoyé par e-mail ; collez-le à l'invite. +``` + +Le jeton de session est stocké dans `~/.agenteye/cli.json` (accessible uniquement par vous, mode `0600`) et est valide 24 heures par défaut. À expiration, relancez `agenteye login`. + +```bash +agenteye whoami # affiche l'utilisateur actuel, l'organisation active et les permissions +agenteye logout # révoque la session et efface le jeton stocké +``` + +`whoami` ne génère jamais d'erreur en cas de session manquante ou expirée — il indique `logged_in: false` à la place, ce qui permet à un script ou agent de vérifier l'état d'authentification sans risque (il peut tout de même retourner un code non nul si aucune URL de base n'est définie ou si le tableau de bord est inaccessible). + +**Prérequis :** votre e-mail doit être autorisé à se connecter au tableau de bord (contactez votre administrateur AgentEye), et le tableau de bord doit être accessible à son URL de base (voir [Configuration](#configuration)). Si vous demandez un code et qu'il n'arrive pas, votre e-mail n'est probablement pas encore activé pour l'accès au tableau de bord. + +--- + +## Choisir son organisation (multi-tenant) + +Si votre compte appartient à plusieurs organisations, choisissez l'organisation active **lors de la connexion** — elle est sauvegardée et utilisée pour toutes les commandes ultérieures : + +```bash +agenteye login --org acme # s'authentifier et définir le tenant actif en une étape +agenteye orgs list # les organisations auxquelles vous avez accès (l'active est signalée) +agenteye orgs switch globex # changer l'organisation par défaut sauvegardée +agenteye --org globex sessions # substitution pour une seule commande +``` + +Si vous n'appartenez qu'à une seule organisation, elle est sélectionnée automatiquement et vous pouvez ignorer `--org` entièrement. Si vous appartenez à plusieurs et n'en choisissez pas, la CLI les liste et vous demande de relancer avec `--org `. L'organisation active est transmise au tableau de bord à chaque requête, et vos permissions sont résolues **par organisation** — `agenteye whoami` affiche l'organisation active, vos permissions dans celle-ci, ainsi que toutes vos appartenances. + +--- + +## Configuration + +| Paramètre | Indicateur | Variable d'environnement | Valeur par défaut | +|---|---|---|---| +| URL de base du tableau de bord | `--base-url` | `AGENTEYE_DASHBOARD_URL` | **requis** (aucune valeur par défaut) | +| Organisation/tenant actif | `--org` | `AGENTEYE_ORG` | choisi à la connexion ; sauvegardé dans `~/.agenteye/cli.json` | +| Jeton de session | `--token` | `AGENTEYE_CLI_TOKEN` | depuis `~/.agenteye/cli.json` | +| Sortie JSON | `--json` | `AGENTEYE_CLI_JSON` | désactivé | +| Ignorer la vérification TLS | `--insecure` / `--secure` | `AGENTEYE_INSECURE` | désactivé (sauvegardé à la connexion) | +| Délai d'attente des requêtes (secondes) | `--timeout` | — | 30 | +| Désactiver la télémétrie d'utilisation | _(aucun)_ | `AGENTEYE_ANALYTICS_DISABLED` (ou `DO_NOT_TRACK`) | désactivé (télémétrie activée) | + +L'ordre de résolution est **indicateur → variable d'environnement → fichier de configuration**. Il n'y a pas de valeur par défaut ; vous devez pointer la CLI vers votre tableau de bord, soit par commande (`--base-url https://agenteye.example.com`), soit une fois via l'environnement (elle est également sauvegardée après votre première `login`) : + +```bash +export AGENTEYE_DASHBOARD_URL=https://agenteye.example.com +``` + +Le répertoire de configuration respecte `AGENTEYE_HOME` (la même convention utilisée par le SDK et le collecteur) ; s'il est défini, `cli.json` se trouve dans `$AGENTEYE_HOME/cli.json`. + +### TLS auto-signé ou interne + +Si votre tableau de bord est servi en HTTPS avec un certificat auto-signé ou interne (par exemple, un nom d'hôte de répartiteur de charge brut), la vérification TLS le rejette avec une erreur `CERTIFICATE_VERIFY_FAILED`. Passez `--insecure` pour ignorer la vérification du certificat : + +```bash +agenteye --base-url https://agenteye.internal --insecure login +``` + +`--insecure` est **sauvegardé dans `cli.json` lors de la connexion**, de sorte que les commandes ultérieures ignorent automatiquement la vérification ; vous n'avez pas à répéter l'indicateur. Passez `--secure` pour un appel vérifié ponctuel, ou pour réactiver la vérification lors de votre prochaine connexion. La CLI affiche un avertissement sur stderr avant toute commande qui contacte le tableau de bord avec la vérification désactivée. L'ignorance de la vérification supprime la protection contre les attaques de type man-in-the-middle ; assurez-vous de faire confiance au chemin réseau vers votre tableau de bord (VPN, sous-réseau privé, etc.) avant de vous en remettre à cette option. + +--- + +## Télémétrie et confidentialité + +La CLI envoie des **analyses d'utilisation anonymes** au service d'analyse d'Exosphere (PostHog) : quelles commandes sont exécutées (p. ex. `sessions`, `keys create`), si elles ont réussi, et combien de temps elles ont pris. Ce signal d'utilisation informe les décisions sur les fonctionnalités à prioriser. + +- **Aucune donnée d'agent, de session ou d'événement ne quitte jamais votre infrastructure.** Seule l'utilisation de la CLI est rapportée : le nom de la commande et de la sous-commande (p. ex. `keys create`), les **noms** des indicateurs utilisés (jamais leurs valeurs), le statut de succès/sortie, et la durée — plus un événement par action pour les mutations (p. ex. `api_key_created`, `query_run`) ne portant que des noms/énumérations statiques et des comptages grossiers. Votre URL de tableau de bord, jeton de session, e-mail, slug d'organisation, identifiants de ressources, SQL, secrets de clés et filtres de requêtes ne sont **jamais** envoyés. Les opérateurs sont identifiés uniquement par un identifiant interne opaque, jamais par e-mail. +- La télémétrie est **activée par défaut**. Pour la désactiver, définissez `AGENTEYE_ANALYTICS_DISABLED=1` dans l'environnement de la CLI (la CLI respecte également la convention cross-outil `DO_NOT_TRACK=1`). +- La CLI envoie directement à PostHog (`https://us.i.posthog.com`). La **machine exécutant la CLI** doit avoir un accès sortant vers cet hôte ; si elle est bloquée, la télémétrie ne fait rien silencieusement (l'envoi est limité dans le temps pour ne jamais retarder ni interrompre une commande) et la CLI n'est pas affectée. + +--- + +## Options globales et conventions + +Lisez ceci une fois ; cela s'applique à toutes les commandes. + +- **Les options globales se placent AVANT la commande.** `agenteye --json sessions` est correct ; `agenteye sessions --json` est une erreur d'utilisation. Les options globales sont `--json`, `--base-url`, `--org`, `--token`, `--insecure`/`--secure`, `--timeout`, `--quiet`, et `--no-color`. +- **`--json` affiche du JSON pur sur stdout, et rien d'autre.** Les lignes de statut humaines, les avertissements et les erreurs vont sur **stderr**, de sorte qu'une capture stdout `--json` reste propre pour être transmise à `jq` même quand une ligne de statut est affichée. Sans `--json`, vous obtenez une vue encadrée et colorisée pour les yeux humains. +- **Découverte avec `--help`.** Chaque commande et sous-commande dispose de `--help` (et de l'alias `-h`) : `agenteye -h`, `agenteye sessions -h`, `agenteye keys create -h`. L'aide de niveau supérieur liste également les codes de sortie et les options globales. Il n'y a pas de surface machine-readable globale ; utilisez `--help` par commande, ainsi que `agenteye query schema` et `agenteye settings schema` spécifiques au domaine pour ces deux registres. +- **Les confirmations sont ignorées automatiquement pour les scripts et les agents.** Les commandes de création/mise à jour/suppression demandent une confirmation dans un terminal interactif, mais **ignorent automatiquement cette invite sous `--json` ou quand stdin n'est pas un TTY** — les scripts et les agents ne restent donc jamais bloqués. Passez `--yes`/`-y` pour l'ignorer explicitement. Comme l'invite ne se déclenche pas pour un agent, celui-ci doit confirmer les actions destructives avec l'humain au préalable. +- **Pagination :** les résultats sont les plus récents en premier et paginés par curseur. `--limit N` (alias `-n`) limite les lignes et **vaut 50 par défaut** ; `--all` pagine automatiquement (par blocs de 200 lignes) **jusqu'à `--limit`** — ainsi un simple `--all` s'arrête toujours à 50. Pour un balayage complet, passez une limite explicite élevée : `--all --limit 1000`. `--page-size N` contrôle le bloc par requête (max 200) ; `--cursor ` reprend depuis le `next_cursor` d'une page précédente. +- **Filtres de temps :** `--since` prend une fenêtre relative — `15m`, `1h`, `6h`, `24h`, `7d`, `30d`, ou `all` (les préréglages du tableau de bord). `--from`/`--to` prennent des horodatages UTC ISO-8601 explicites **avec `T` et un fuseau horaire** (p. ex. `2026-06-01T00:00:00Z`) pour une plage personnalisée et remplacent `--since` ; une valeur séparée par un espace ou sans fuseau horaire est une erreur d'utilisation. +- **`--fields a,b,c`** (sur `events`, `sessions`, `evals`, `errors`) restreint la sortie à ces clés, aussi bien pour le tableau que pour `--json`. Les noms inconnus sont rejetés avec la liste valide — un moyen simple de découvrir les noms de champs. +- **`--file payload.json`** (ou `--file -` pour lire stdin) fournit un corps de requête JSON complet quand une ressource a une forme complexe — sur `alerts create/update`, `settings set`, et `users create/update`. Le SQL de requête sauvegardée utilise plutôt `--sql @file.sql`. +- **Les filtres multi-valeurs** sont séparés par des virgules → correspondance en tant qu'ensemble (union au sein d'un filtre, ET entre les filtres) : `--event-type tool_use,tool_result`. Les options Click ne sont pas variadiques, donc `--add a b` échoue — utilisez `--add a,b`, répétez l'indicateur (`--add a --add b`), ou utilisez des guillemets (`--add "a b"`). + +--- + +## Référence des commandes + +La CLI dispose de **18 commandes de niveau supérieur**. Toutes les commandes de lecture acceptent `--json` et les options globales ci-dessus ; exécutez `agenteye -h` (ou ` -h`) pour la liste exhaustive des indicateurs et la forme JSON de chaque commande. + +### Identité — `login` · `logout` · `whoami` · `orgs` · `version` · `help` + +```bash +agenteye login --email you@example.com [--org acme] # code à usage unique par e-mail ; sauvegarde la session +agenteye logout # efface la session sauvegardée sur cette machine +agenteye whoami # utilisateur actuel, organisation active, permissions +agenteye version # affiche la version de la CLI (identique à --version) +agenteye help # aide de niveau supérieur (identique à --help) +``` + +`orgs` inspecte et change le tenant actif : + +```bash +agenteye orgs list # vos organisations + votre rôle dans chacune (l'active est signalée) +agenteye orgs switch acme # changer l'organisation active sauvegardée (omettez le slug pour choisir depuis une liste sur un TTY) +agenteye orgs current # carte d'identité de l'organisation active +agenteye orgs perms # vos permissions dans l'organisation active, groupées par ressource +``` + +### Observation (lecture seule) — `events` · `sessions` · `evals` · `errors` · `list` + +Aucune de ces commandes ne nécessite de confirmation. Filtres partagés : `--session-id`, `--agent-id`, `--env` (**pas** `--environment`), et la plage de temps (`--since` / `--from` / `--to`). + +```bash +# events (alias : la piste brute par étape) — les plus récents en premier +agenteye --json events --session-id run-001 --event-type tool_use,tool_result --all --limit 1000 +agenteye --json events --since 1h --search timeout --all | jq '.events[].payload' + +# sessions — une ligne par exécution d'agent (temps/env/agent/session/statut ; pas de filtrage par score) +agenteye --json sessions --since 24h --status error +agenteye --json sessions --agent-id checkout-bot --env prod --all --limit 1000 + +# evals — résultats d'évaluation + scores ; --score filtre par métrique, --aggregate regroupe +agenteye --json evals --score helpfulness:0.5..0.8 --score tool_efficiency:..0.3 +agenteye --json evals --aggregate --since 7d --env prod # répartition des statuts + stats de score par clé + +# errors — événements en erreur ; --aggregate pour les comptages/sessions/agents/dernière occurrence +agenteye --json errors --since 24h --aggregate +agenteye --json errors --since 24h --error-type timeout --all --limit 1000 + +# list — découvrir les valeurs de filtre valides avant de filtrer +agenteye list envs # aussi : agents event_types score_filters models hooks triggers tools error_types +``` + +`--score KEY:MIN..MAX` (sur **`evals`**, pas `sessions`) est répétable et combiné en ET ; chaque borne est optionnelle (`..0.5` signifie ≤ 0.5, `0.9..` signifie ≥ 0.9). Jusqu'à 20 filtres de score par requête. `evals --scores-full` retourne l'objet score complet plutôt que le résumé. Pour lire **une session de bout en bout**, combinez la piste d'événements avec son évaluation : + +```bash +agenteye --json events --session-id run-001 --all --limit 1000 | jq '.events[] | {ts, event_type}' +agenteye --json evals --session-id run-001 # ses scores + statut +``` + +### Gestion (soumise aux permissions) — `keys` · `users` · `settings` · `alerts` · `incidents` + +**`keys`** — Clés API. Le secret est généré localement, envoyé au serveur (qui ne stocke qu'un hachage), et **affiché une seule fois** lors de la création/régénération — capturez-le immédiatement. Avec `--json`, il n'apparaît que dans le champ `key`. Référencées par **nom**. + +```bash +agenteye keys list # clés actives d'abord, puis révoquées +agenteye keys show ci-bot +agenteye keys create ci-bot --add events:read.add # limitez aux scopes nécessaires ; affiche le secret UNE SEULE FOIS +agenteye keys create ops --permission-set standard --remove queries:run # initialisez un préréglage, puis affinez +agenteye keys update ci-bot --add evaluations:read --yes +agenteye keys regenerate ci-bot --yes # faire tourner le secret (l'ancien cesse de fonctionner) +agenteye keys disable ci-bot --yes # révoquer +``` + +Les permissions fonctionnent comme `(permission-set ∪ --add) − --remove`. Les jetons sont `slug:action` (p. ex. `events:read`) ou `slug:action.action` pour en développer plusieurs sur une ressource (`events:read.add` → `events:read`, `events:add`). Préréglages : `read-only`, `standard`, `admin`. Les permissions réservées aux humains (`keys:update`) ne peuvent pas être accordées à une clé. + +**`users`** — membres de l'organisation, référencés par **e-mail** (un identifiant UUID est également accepté). + +```bash +agenteye users list [--active-only] +agenteye users show dev@corp.com +agenteye users create dev@corp.com --permission-set standard +agenteye users update dev@corp.com --add alerts:write --remove queries:delete # prédit + confirme +agenteye users disable dev@corp.com --yes # protections de rôle/auto-protection activées +agenteye users enable dev@corp.com +``` + +**`settings`** — un registre fixe (vous lisez et modifiez les clés existantes ; vous ne pouvez pas en créer de nouvelles). + +```bash +agenteye settings list # clé · valeur · type · mise à jour (secrets masqués) +agenteye settings schema # ce que chaque clé accepte (type · plage · description) +agenteye settings set session_ttl_secs --value 86400 --yes +``` + +**`alerts`** — définitions d'alertes, référencées par **nom**. `create` prend un NOM positionnel plus des indicateurs ou un corps JSON complet via `--file`. + +```bash +agenteye alerts list +agenteye alerts show high-errors +agenteye alerts create high-errors --file alert.json # NOM requis (positionnel) +agenteye alerts update high-errors --severity critical --yes +agenteye alerts test high-errors --yes # déclencher une notification de test +agenteye alerts delete high-errors --yes +``` + +**`incidents`** — incidents d'alerte, référencés par identifiant (les identifiants courts sont acceptés). `show` affiche le journal d'activité complet — lisez-le avant d'agir. + +```bash +agenteye incidents list --state firing # aussi : acknowledged, resolved +agenteye incidents count +agenteye incidents show +agenteye incidents ack +agenteye incidents assign you@corp.com # le responsable doit être un opérateur +agenteye incidents resolve --yes +agenteye incidents open --alert-id --severity critical # ouvrir manuellement contre une alerte +agenteye incidents comment-add "root cause: upstream 5xx" +agenteye incidents comment-list ; agenteye incidents comment-delete +agenteye incidents subscribe ; agenteye incidents unsubscribe ; agenteye incidents subscribers +``` + +### Analytique et assistant — `query` · `agent` + +**`query`** — SQL ClickHouse sauvegardé plus un exécuteur ad hoc. Les requêtes sauvegardées sont référencées par **nom** ; le SQL est validé côté serveur (SELECT/WITH uniquement, délai d'expiration des instructions, limite de lignes). + +```bash +agenteye query schema [TABLE] # structure des colonnes des vues analytiques +agenteye query run --sql "select count(*) from analytics.events" +agenteye query run errs --arg prod --limit 100 # exécuter une requête sauvegardée + un $1 positionnel +agenteye query list ; agenteye query show errs +agenteye query create errs --sql @errs.sql --description "errored events (24h)" +agenteye query update errs --sql @errs.sql --yes ; agenteye query delete errs --yes +``` + +**`agent`** — l'assistant intégré du tableau de bord (le même analyste en lecture seule avec lequel vous pouvez discuter dans le tableau de bord). Les conversations sont référencées par un identifiant court (résolution par préfixe). + +```bash +agenteye agent health # l'assistant est-il configuré/accessible +agenteye agent models # modèles que vous pouvez passer à --model (le défaut est indiqué) +agenteye agent ask "which agents errored most in the last day?" # démarre une conversation ; affiche son identifiant court +agenteye agent ask --chat "and which tools did they call?" # continuer cette conversation +agenteye agent chats ; agenteye agent show +agenteye agent rename --title "error triage" ; agenteye agent delete +``` + +--- + +## Codes de sortie + +| Code | Signification | +|---|---| +| 0 | Succès | +| 1 | Erreur inattendue (p. ex. le tableau de bord a retourné un 5xx) | +| 2 | Erreur d'utilisation (arguments invalides, commande/indicateur inconnu, collision de noms) | +| 3 | Impossible d'atteindre le tableau de bord | +| 4 | Non connecté ou session expirée ; exécutez `agenteye login` | +| 5 | Authentifié, mais votre compte n'a pas la permission requise (le message la nomme) | +| 6 | La ressource demandée est introuvable (p. ex. identifiant de session ou d'incident inconnu) | + +Ces codes rendent la CLI sûre à scripter : un agent de codage peut brancher sur un `4` pour vous demander de vous ré-authentifier, ou sur un `5` pour exposer la permission manquante. Consultez [Recettes CLI pour agents](/fr/agenteye/cli-recipes) pour des modèles de gestion des codes de sortie et des formes de sortie JSON. + +--- + +## Voir aussi + +- **[Recettes CLI pour agents](/fr/agenteye/cli-recipes)** — motifs de requêtes prêts à l'emploi, commandes `jq` en une ligne, projections `--fields`, gestion des codes de sortie et formes de sortie JSON, écrits pour les agents de codage pilotant la CLI. +- **[Compétence CLI AgentEye](/fr/agenteye/cli-skill)** — packager cette CLI comme une *compétence* installable Claude Code / Codex pour qu'un agent de codage pilote AgentEye depuis des requêtes en langage naturel. +- **[Clés API](/fr/agenteye/api-keys)** — le modèle de permissions derrière `keys create --add …`. +- **[Assistant IA](/fr/agenteye/assistant)** — activation de l'assistant qu'`agent ask` utilise. \ No newline at end of file diff --git a/docs/fr/agenteye/collector-installation.mdx b/docs/fr/agenteye/collector-installation.mdx new file mode 100644 index 00000000..2919b0a5 --- /dev/null +++ b/docs/fr/agenteye/collector-installation.mdx @@ -0,0 +1,401 @@ +--- +title: "Installation du Collector" +description: "Documentation d'installation du AgentEye Collector." +--- + + +Le daemon `agenteye-collector` garantit que la télémétrie de vos agents parvient à AgentEye sans jamais bloquer votre application. Votre code écrit des événements dans un répertoire local et continue son exécution ; le collector prend en charge le reste, en téléversant chaque fichier en quelques millisecondes et en survivant aux redémarrages, aux pannes réseau et aux erreurs serveur transitoires. Les téléversements échoués sont réessayés avec un backoff exponentiel, et un balayage de récupération périodique remet en file d'attente tout ce qui aurait été laissé en suspens lors d'un crash ou d'un déploiement. Le résultat est une livraison durable en mode « fire-and-forget » : vos agents continuent de tourner à pleine vitesse pendant que le collector s'assure qu'aucun événement n'est perdu en transit. + +Concrètement, le collector est un daemon léger qui surveille `$AGENTEYE_HOME/events/` (par défaut : `~/.agenteye/events/`) pour y détecter les fichiers `.jsonl` écrits par le SDK Python et les téléverser vers le serveur AgentEye. + +> **Renommage :** la commande du collector s'appelle désormais **`agenteye-collector`** (elle s'appelait auparavant `agenteye`). Le nom abrégé `agenteye` appartient maintenant à l'interface en ligne de commande AgentEye. Si vous mettez à jour une installation existante, consultez [enterprise-docs/collector-migration.md](/fr/agenteye/collector-migration). + +--- + +## Prérequis + +- Votre `AGENTEYE_TOKEN` : un PAT GitHub que vous générez vous-même (voir [enterprise-docs/github-token.md](/fr/agenteye/github-token)) +- L'URL du serveur et une clé API pour le collector (voir [enterprise-docs/api-keys.md](/fr/agenteye/api-keys)) + +--- + +## Option A : Binaire (recommandé) + +Des binaires statiques pré-compilés sont disponibles pour Linux, macOS et Windows (x86_64 et arm64). Téléchargez le binaire correspondant à votre plateforme directement depuis le dépôt `agenteye-enterprise/releases`, sous le dernier tag de release `collector/v`. + +Noms des artefacts disponibles : + +| Plateforme | Artefact | +|---|---| +| Linux x86_64 | `agenteye-collector-linux-x86_64` | +| Linux arm64 | `agenteye-collector-linux-arm64` | +| macOS x86_64 | `agenteye-collector-darwin-x86_64` | +| macOS arm64 | `agenteye-collector-darwin-arm64` | +| Windows x86_64 | `agenteye-collector-windows-x86_64.exe` | +| Windows arm64 | `agenteye-collector-windows-arm64.exe` | + +**Téléchargement avec la CLI `gh`** (remplacez la version et choisissez l'artefact correspondant à votre plateforme) : + +```bash +VERSION=0.0.1-beta.13 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "collector/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-collector-linux-x86_64' + +chmod +x agenteye-collector-linux-x86_64 +sudo mv agenteye-collector-linux-x86_64 /usr/local/bin/agenteye-collector +``` + +**Ou avec `curl` :** + +```bash +VERSION=0.0.1-beta.13 +ARTIFACT=agenteye-collector-linux-x86_64 +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + -L "https://github.com/agenteye-enterprise/releases/releases/download/collector%2Fv${VERSION}/${ARTIFACT}" \ + -o agenteye-collector +chmod +x agenteye-collector +sudo mv agenteye-collector /usr/local/bin/agenteye-collector +``` + +--- + +## Option B : Docker + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +docker pull ghcr.io/agenteye-enterprise/collector:beta-latest +``` + +> Les builds bêta actuels publient le tag flottant `:beta-latest` ; `:latest` est réservé aux releases stables. Pour des déploiements reproductibles, privilégiez un tag de version fixe tel que `:v0.0.1-beta.13`. + +**Démarrage :** + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-collector \ + -e AGENTEYE_URL=https://ingest.example.com/events \ + -e AGENTEYE_KEY="$AGENTEYE_KEY" \ + -e AGENTEYE_HOME=/data \ + -v "$HOME/.agenteye:/data" \ + ghcr.io/agenteye-enterprise/collector:beta-latest \ + start +``` + +L'image officielle s'exécute en tant qu'utilisateur non-root ; définissez donc `AGENTEYE_HOME` explicitement et montez le spool de l'hôte sur ce chemin. Le montage de volume partage le même répertoire `~/.agenteye/` dans lequel le SDK Python écrit sur l'hôte. Si vous avez déjà défini `AGENTEYE_HOME` à un autre emplacement sur l'hôte, montez ce répertoire plutôt que `$HOME/.agenteye`. + +--- + +## Configuration + +Toutes les options peuvent être définies de trois manières (par ordre de priorité décroissante) : + +1. Flag CLI : `agenteye-collector start --url https://...` +2. Variable d'environnement : `AGENTEYE_URL=https://...` +3. Fichier de configuration : `~/.agenteye/config.json` + +### Options requises + +| Option | Flag CLI | Variable d'env | Clé config.json | +|---|---|---|---| +| URL du backend | `--url ` | `AGENTEYE_URL` | `"url"` | +| Clé API | `--key ` | `AGENTEYE_KEY` | `"key"` | + +### Options facultatives (avec valeurs par défaut) + +| Option | Flag CLI | Variable d'env | Clé config.json | Valeur par défaut | +|---|---|---|---|---| +| Téléversements simultanés max | `--max-concurrent-uploads ` | `AGENTEYE_MAX_CONCURRENT_UPLOADS` | `"max_concurrent_uploads"` | `64` | +| Intervalle de balayage (s) | `--sweep-interval ` | `AGENTEYE_SWEEP_INTERVAL` | `"sweep_interval_secs"` | `60` | +| Âge min. des fichiers pour le balayage (s) | `--sweep-min-age ` | `AGENTEYE_SWEEP_MIN_AGE` | `"sweep_min_age_secs"` | `120` | +| Fichiers max. par balayage | `--sweep-max-files ` | `AGENTEYE_SWEEP_MAX_FILES` | `"sweep_max_files"` | `64` | +| Tentatives de téléversement max | `--max-retries ` | `AGENTEYE_MAX_RETRIES` | `"max_retries"` | `5` | +| Délai de base entre tentatives (ms) | `--retry-base-delay ` | `AGENTEYE_RETRY_BASE_DELAY` | `"retry_base_delay_ms"` | `1000` | + +### Options mTLS (facultatives) + +Pour les déploiements nécessitant un TLS mutuel (mTLS), le collector peut présenter un certificat client lors de la négociation TLS. Si ces options ne sont pas définies, le collector utilise HTTPS standard. + +| Option | Flag CLI | Variable d'env | Clé config.json | +|---|---|---|---| +| Certificat client (PEM) | `--tls-cert ` | `AGENTEYE_TLS_CERT` | `"tls_cert"` | +| Clé privée client (PEM) | `--tls-key ` | `AGENTEYE_TLS_KEY` | `"tls_key"` | +| Certificat CA personnalisé (PEM) | `--tls-ca ` | `AGENTEYE_TLS_CA` | `"tls_ca"` | + +`--tls-cert` et `--tls-key` doivent être définis ensemble. Les fichiers doivent être encodés en PEM. + +`--tls-ca` est indépendant et n'est nécessaire que lorsque le serveur AgentEye présente un certificat TLS qui n'est pas émis par une CA publiquement reconnue (par exemple, auto-signé par un émetteur `cert-manager` dans le cluster lorsque vous ne disposez pas d'un vrai domaine DNS). Le collector ajoute la CA fournie comme ancre de confiance supplémentaire ; les racines publiques standard restent approuvées, de sorte que les déploiements existants ne sont pas affectés. Le fichier peut contenir un seul certificat PEM ou une chaîne complète (plusieurs blocs PEM concaténés). + +**Vous exécutez le collector en tant que sidecar dans votre pod applicatif ?** Consultez [enterprise-docs/single-pod-deployment.md](/fr/agenteye/single-pod-deployment) pour le schéma EKS de bout en bout : bundle mTLS livré via AWS Secrets Manager + Secrets Store CSI Driver + IRSA, avec rotation automatique. + +Lorsque vous déployez dans Kubernetes avec le pattern de remise de Secret, montez le Secret de certificat en tant que volume et pointez ces chemins vers les fichiers montés : + +```yaml +# Exemple : extrait du Deployment du collector +volumes: + - name: mtls-certs + secret: + secretName: agenteye-collector-mtls +containers: + - name: collector + env: + - name: AGENTEYE_TLS_CERT + value: /etc/agenteye/tls/tls.crt + - name: AGENTEYE_TLS_KEY + value: /etc/agenteye/tls/tls.key + # Uniquement lorsque le certificat serveur n'est pas publiquement approuvé + # (ex. CA auto-signée dans le cluster). Le même Secret porte généralement + # ca.crt aux côtés de tls.crt/tls.key. + - name: AGENTEYE_TLS_CA + value: /etc/agenteye/tls/ca.crt + volumeMounts: + - name: mtls-certs + mountPath: /etc/agenteye/tls + readOnly: true +``` + +### Exemple de `~/.agenteye/config.json` + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "max_concurrent_uploads": 16, + "sweep_interval_secs": 30 +} +``` + +Avec mTLS : + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "tls_cert": "/etc/agenteye/tls/tls.crt", + "tls_key": "/etc/agenteye/tls/tls.key" +} +``` + +Avec mTLS et une CA personnalisée (serveur AgentEye auto-signé) : + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "tls_cert": "/etc/agenteye/tls/tls.crt", + "tls_key": "/etc/agenteye/tls/tls.key", + "tls_ca": "/etc/agenteye/tls/ca.crt" +} +``` + +Si `AGENTEYE_HOME` est défini, ce répertoire est utilisé à la place de `~/.agenteye`. + +--- + +## Configuration initiale + +Après l'installation, configurez le collector avec l'URL de votre serveur et votre clé API : + +```bash +mkdir -p ~/.agenteye +cat > ~/.agenteye/config.json <<'EOF' +{ + "url": "https://ingest.example.com/events", + "key": "YOUR_COLLECTOR_KEY" +} +EOF +``` + +> Utilisez `https` pour tout déploiement traversant un réseau non fiable, afin que les événements ne soient pas transmis en clair. La forme en clair `http://your-server-host:8080/events` n'est appropriée que pour des tests purement locaux contre un serveur sur la même machine. + +**Tester la connexion** (vidage ponctuel, se termine après avoir traité les événements en attente) : + +```bash +agenteye-collector flush +``` + +`flush` rapporte sa progression sur stdout. Lorsque le spool est vide, il affiche `No pending files.` et se termine avec le code `0`. Sinon, il affiche une ligne par fichier (`[UPLOADED] ` ou `[FAILED] ()`), suivie d'un résumé `Done: / uploaded, failed.`. Cela fait de `flush` un outil pratique pour vérifier en une seule passe que votre URL, votre clé et vos paramètres TLS sont corrects avant de démarrer le daemon. + +--- + +## Exécution en tant que daemon + +### Directement + +```bash +agenteye-collector start +``` + +### Conteneur / Docker + +Lorsque le collector et votre application partagent un conteneur, exécutez-les sous un superviseur de processus. L'option la plus simple est `supervisord` ; il est disponible dans toutes les distributions majeures, redémarre les processus qui ont planté, transmet les signaux et attend un arrêt gracieux. + +**`Dockerfile` :** + +```Dockerfile +FROM python:3.11-slim + +RUN apt-get update && apt-get install -y --no-install-recommends supervisor \ + && rm -rf /var/lib/apt/lists/* + +# Récupère le binaire agenteye-collector depuis l'image officielle. +# Épinglez un tag spécifique (:beta-latest pour les bêtas actuels, ou un tag :v) ; +# :latest n'est publié que pour les releases stables. +COPY --from=ghcr.io/agenteye-enterprise/collector:beta-latest \ + /usr/local/bin/agenteye-collector /usr/local/bin/agenteye-collector + +COPY supervisord.conf /etc/supervisor/conf.d/agenteye.conf +COPY my_agent.py /app/my_agent.py + +CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"] +``` + +**`supervisord.conf` :** + +```ini +[supervisord] +nodaemon=true +user=root + +[program:agenteye-collector] +command=/usr/local/bin/agenteye-collector start +autorestart=true +stopwaitsecs=30 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:app] +command=python /app/my_agent.py +autorestart=unexpected +stopwaitsecs=30 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +``` + +Explication de ces paramètres : + +- `autorestart=true` sur agenteye-collector : redémarre à chaque arrêt (crash, panique, OOM). +- `autorestart=unexpected` sur l'app : redémarre uniquement en cas de sortie avec un code non-zéro, afin qu'un agent ponctuel qui se termine avec le code `0` ne boucle pas indéfiniment. +- `stopwaitsecs=30` : laisse au collector le temps de vider les téléversements en attente lors d'un SIGTERM avant que supervisord n'escalade vers SIGKILL. +- `stdout_logfile=/dev/stdout`, `*_maxbytes=0` : redirige la sortie des deux programmes vers le stdout du conteneur, sans fichiers de log à l'intérieur du conteneur. + +Transmettez `AGENTEYE_URL` / `AGENTEYE_KEY` (et les éventuelles variables d'environnement TLS) via `docker run -e` comme précédemment ; supervisord hérite de l'environnement. + +> **Conteneurs séparés ?** Si vous exécutez le collector dans son propre conteneur (service Docker Compose, sidecar Kubernetes, etc.), n'utilisez pas supervisord ; la politique de redémarrage du runtime de conteneurs remplit déjà ce rôle. Consultez [enterprise-docs/single-pod-deployment.md](/fr/agenteye/single-pod-deployment) pour le schéma de sidecar EKS. + +**Sonde de vivacité Kubernetes** (applicable que le collector tourne seul ou sous supervisord) : + +```yaml +livenessProbe: + exec: + command: ["agenteye-collector", "health"] + initialDelaySeconds: 10 + periodSeconds: 30 +``` + +Le daemon en cours d'exécution écrit un heartbeat dans `$AGENTEYE_HOME/health.json` toutes les 30 secondes. `agenteye-collector health` lit ce fichier et se termine avec le code `0` (sain) uniquement lorsque le heartbeat est récent et que les tâches de téléversement fonctionnent normalement ; il se termine avec le code `1` (défaillant) lorsque le heartbeat est antérieur à 90 secondes (par exemple, le daemon s'est arrêté) ou pendant que le watcher et le sweeper redémarrent après un arrêt inattendu. Le heartbeat n'est écrit que par `start`, alors exécutez la sonde contre le daemon long-lived plutôt que contre la commande ponctuelle `flush`. + +### systemd (Linux, recommandé pour la production) + +```ini +# /etc/systemd/system/agenteye-collector.service +[Unit] +Description=AgentEye Collector +After=network.target + +[Service] +ExecStart=/usr/local/bin/agenteye-collector start +Restart=on-failure +RestartSec=5 +EnvironmentFile=/etc/agenteye/env + +[Install] +WantedBy=multi-user.target +``` + +Créez `/etc/agenteye/env` : + +``` +AGENTEYE_URL=https://ingest.example.com/events +AGENTEYE_KEY=YOUR_COLLECTOR_KEY +``` + +```bash +sudo systemctl daemon-reload +sudo systemctl enable --now agenteye-collector +sudo systemctl status agenteye-collector +``` + +### launchd (macOS) + +```xml + + + + + + Label + ai.befailproof.agenteye-collector + ProgramArguments + + /usr/local/bin/agenteye-collector + start + + EnvironmentVariables + + AGENTEYE_URL + https://ingest.example.com/events + AGENTEYE_KEY + YOUR_COLLECTOR_KEY + + RunAtLoad + + KeepAlive + + + +``` + +```bash +launchctl load ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +``` + +--- + +## Mise à jour du Collector + +Le collector ne se met pas à jour automatiquement. Pour effectuer une mise à jour : + +- **Binaire :** téléchargez le nouvel artefact `agenteye-collector--` depuis la dernière release `collector/v` (voir [Option A](#option-a-binary-recommended)), remplacez `/usr/local/bin/agenteye-collector`, puis redémarrez le service (`sudo systemctl restart agenteye-collector`, relancez `launchctl load`, ou redémarrez votre superviseur). +- **Docker :** `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (ou un tag `:v` épinglé ; `:latest` n'existe que pour les releases stables) et recréez le conteneur. + +`AGENTEYE_TOKEN` est nécessaire pour télécharger de nouveaux binaires/images depuis le dépôt de releases privé, mais **n'est pas** requis par le daemon en cours d'exécution. + +--- + +## Sous-commandes + +| Commande | Description | +|---|---| +| `agenteye-collector start` | Démarre le daemon long-lived. Au démarrage, il vide tous les événements restants d'une exécution précédente, puis surveille les nouveaux fichiers et les téléverse. Le watcher et le sweeper redémarrent automatiquement en cas d'arrêt inattendu, et un heartbeat est écrit dans `health.json` toutes les 30 secondes. | +| `agenteye-collector flush` | Ponctuel : téléverse tous les fichiers en attente et se termine. Affiche `No pending files.` lorsque le spool est vide, sinon un journal `[UPLOADED]`/`[FAILED]` par fichier et un résumé `Done: / uploaded, failed.`. | +| `agenteye-collector health` | Lit le heartbeat `health.json` du daemon. Se termine avec le code `0` lorsqu'il est récent et sain ; se termine avec le code `1` lorsque le heartbeat est périmé (antérieur à 90s) ou que les tâches redémarrent. | + +--- + +## Structure des répertoires + +``` +~/.agenteye/ +├── config.json <- fichier de configuration facultatif +├── events/ <- fichiers .jsonl écrits par le SDK, récupérés par le collector +└── failed/ <- fichiers ayant échoué toutes les tentatives de téléversement +``` + +Les fichiers dans `failed/` ne sont pas automatiquement réessayés. Pour les remettre manuellement en file d'attente, déplacez-les vers `events/` et exécutez `agenteye-collector flush`. \ No newline at end of file diff --git a/docs/fr/agenteye/collector-migration.mdx b/docs/fr/agenteye/collector-migration.mdx new file mode 100644 index 00000000..63972f36 --- /dev/null +++ b/docs/fr/agenteye/collector-migration.mdx @@ -0,0 +1,169 @@ +--- +title: "Migration vers `agenteye-collector`" +description: "Documentation AgentEye pour la migration vers `agenteye-collector`." +--- + + +La migration est non-destructive : elle n'entraîne aucune interruption de service ni perte de données, et elle libère le nom court `agenteye` pour l'[interface en ligne de commande AgentEye](/fr/agenteye/cli), permettant ainsi au daemon collecteur et à la CLI de coexister sur la même machine. + +Le binaire du collecteur a été **renommé de `agenteye` en `agenteye-collector`**. Le nom court `agenteye` appartient désormais à la CLI AgentEye, un outil distinct permettant d'interroger les sessions, événements et évaluations depuis votre terminal. + +Ce guide vous accompagne dans la migration d'une installation existante du collecteur. + +--- + +## Ce qui a changé + +| | Avant | Après | +|---|---|---| +| Commande / binaire | `agenteye` | `agenteye-collector` | +| Chemin d'installation par défaut | `/usr/local/bin/agenteye` | `/usr/local/bin/agenteye-collector` | +| Sous-commandes | `start`, `flush`, `health`, `update` | `start`, `flush`, `health` | +| Mise à jour automatique (`agenteye update`) | intégrée | **supprimée** : téléchargez le nouveau binaire ou récupérez la nouvelle image | +| Script d'installation (`install.sh`) | fourni | **supprimé** : téléchargez directement le binaire (voir [Installation du collecteur](/fr/agenteye/collector-installation)) | +| `AGENTEYE_TOKEN` | requis pour le téléchargement **et** les vérifications de mises à jour en arrière-plan | requis uniquement pour **télécharger** les binaires/images | + +La configuration est inchangée : le même fichier `~/.agenteye/config.json`, les mêmes variables d'environnement `AGENTEYE_URL` / `AGENTEYE_KEY` / `AGENTEYE_HOME` / TLS, et le même répertoire de spool `~/.agenteye/events/`. **Aucune modification de configuration n'est requise.** + +> Si vous exécutez le binaire renommé sous l'ancien nom `agenteye`, cela fonctionne toujours, mais un avertissement de dépréciation sur une seule ligne est affiché sur stderr pour vous rappeler de basculer vers `agenteye-collector`. + +--- + +## Avant de commencer + +- Votre **installation `agenteye` existante continue de fonctionner** ; rien ne se casse au moment où vous effectuez la mise à niveau. Procédez à la migration de manière délibérée, puis supprimez l'ancien binaire en dernier. +- Respectez cet ordre pour éviter toute interruption de service : + 1. Installez le nouveau binaire `agenteye-collector` (ou récupérez la nouvelle image). + 2. Mettez à jour votre définition de service / sonde de santé / scripts pour appeler `agenteye-collector`. + 3. Rechargez et redémarrez le service ; confirmez qu'il est opérationnel. + 4. **Seulement ensuite**, supprimez l'ancien binaire `/usr/local/bin/agenteye`. + +--- + +## 1. Installer le nouveau binaire + +Téléchargez l'artefact correspondant à votre plateforme (`agenteye-collector-linux-x86_64`, `agenteye-collector-darwin-arm64`, etc. ; consultez [Installation du collecteur → Option A](/fr/agenteye/collector-installation#option-a-binary-recommended) pour la liste complète) depuis la dernière version `collector/v` et placez-le à l'emplacement `/usr/local/bin/agenteye-collector`. Pour les utilisateurs Docker : `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (ou un tag `:v` épinglé, ce qui est recommandé ; `:latest` n'existe que pour les versions stables). + +Vérification : + +```bash +agenteye-collector --version +``` + +--- + +## 2. Mettre à jour votre déploiement + +### systemd (Linux) + +Modifiez `/etc/systemd/system/agenteye-collector.service` pour que `ExecStart` pointe vers le nouveau binaire : + +```ini +[Service] +ExecStart=/usr/local/bin/agenteye-collector start +``` + +Puis rechargez et redémarrez : + +```bash +sudo systemctl daemon-reload +sudo systemctl restart agenteye-collector +sudo systemctl status agenteye-collector +``` + +### launchd (macOS) + +> **Renommage de marque :** Si votre plist existant se trouve à l'ancien chemin +> `~/Library/LaunchAgents/host.exosphere.agenteye-collector.plist`, renommez +> le fichier en `ai.befailproof.agenteye-collector.plist` et modifiez également la +> valeur `Label` dans le fichier pour utiliser le nouvel identifiant avant +> de recharger. + +Dans `~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist`, remplacez la première entrée `ProgramArguments` de `/usr/local/bin/agenteye` par `/usr/local/bin/agenteye-collector`, puis rechargez : + +```bash +launchctl unload ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +launchctl load ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +``` + +### supervisord + +Dans votre bloc de programme `supervisord`, définissez `command` avec le nouveau binaire : + +```ini +[program:agenteye-collector] +command=/usr/local/bin/agenteye-collector start +``` + +Puis exécutez `supervisorctl reread && supervisorctl update`. + +### Docker / Kubernetes + +Récupérez la nouvelle image (`ghcr.io/agenteye-enterprise/collector:beta-latest` ou un tag `:v` épinglé, ce qui est recommandé ; `:latest` n'existe que pour les versions stables). Le point d'entrée de l'image est déjà `agenteye-collector`, donc la même commande `docker run` avec le sous-commande `start` continue de fonctionner sans modification. + +**Important : mettez à jour les sondes de santé.** Si vous utilisez une sonde de vivacité/disponibilité Kubernetes (ou tout `docker exec`) qui exécute le binaire par son nom, modifiez la commande pour utiliser `agenteye-collector` : + +```yaml +livenessProbe: + exec: + command: ["agenteye-collector", "health"] +``` + +La nouvelle image ne contient **pas** d'alias `agenteye`, donc une sonde qui appelle encore `agenteye` échouera. Mettez à jour la sonde dans le même déploiement que la nouvelle image. + +### Cron / scripts manuels + +Remplacez toutes les invocations `agenteye start|flush|health` par la commande correspondante `agenteye-collector start|flush|health`. **Supprimez toutes les tâches cron `agenteye update`** ; ce sous-commande n'existe plus (voir [Mises à niveau à partir de maintenant](#upgrades-from-now-on)). + +--- + +## 3. Supprimer l'ancien binaire (en dernier) + +Une fois que le service fonctionne avec `agenteye-collector` et signale un état sain : + +```bash +sudo rm /usr/local/bin/agenteye +``` + +Cela est particulièrement important si vous utilisez également la CLI AgentEye, qui installe sa propre commande `agenteye` ; laisser l'ancien binaire du collecteur à `/usr/local/bin/agenteye` rendrait le nom `agenteye` ambigu dans votre `PATH`. + +--- + +## Mises à niveau à partir de maintenant + +Le collecteur ne se met plus à jour automatiquement. Pour effectuer une mise à niveau : + +- **Binaire :** téléchargez le nouvel artefact pour votre plateforme (par exemple `agenteye-collector-linux-x86_64` ; consultez [Installation du collecteur → Option A](/fr/agenteye/collector-installation#option-a-binary-recommended) pour la liste complète), remplacez `/usr/local/bin/agenteye-collector` et redémarrez le service. +- **Docker :** `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (ou un tag `:v` épinglé, ce qui est recommandé ; `:latest` n'existe que pour les versions stables) et recréez le conteneur. + +`AGENTEYE_TOKEN` est toujours requis pour télécharger depuis le dépôt de versions privé, mais le daemon en cours d'exécution n'en a plus besoin. + +--- + +## Vérification + +```bash +agenteye-collector --version # le nouveau binaire est dans le PATH +agenteye-collector health # code de sortie 0 = opérationnel +agenteye-collector flush # transfère les événements en file d'attente et se termine proprement +``` + +Confirmez ensuite que les nouveaux événements apparaissent dans votre tableau de bord. + +--- + +## Retour arrière + +La migration est non-destructive. Si vous devez effectuer un retour arrière, pointez à nouveau votre définition de service vers l'ancien binaire `/usr/local/bin/agenteye` (tant que vous ne l'avez pas encore supprimé) et redémarrez. Le spool d'événements et la configuration sont partagés et non affectés. + +--- + +## Résolution des problèmes + +| Symptôme | Cause | Solution | +|---|---|---| +| `warning: the collector binary is now agenteye-collector …` à chaque exécution | Vous invoquez le binaire sous l'ancien nom `agenteye` | Appelez `agenteye-collector` à la place ; mettez à jour les fichiers de service et les scripts. | +| systemd échoue : `.../agenteye: No such file or directory` | Vous avez supprimé l'ancien binaire avant de mettre à jour `ExecStart` | Définissez `ExecStart=/usr/local/bin/agenteye-collector start`, puis exécutez `sudo systemctl daemon-reload`. | +| Le pod Kubernetes redémarre en boucle après la mise à jour de l'image | La sonde de vivacité exécute encore `agenteye` | Modifiez la commande de la sonde en `["agenteye-collector", "health"]`. | +| `agenteye: command not found`, mais `agenteye-collector` fonctionne | Les scripts/alias référencent encore l'ancien nom | Mettez-les à jour pour utiliser `agenteye-collector`. | +| L'exécution de `agenteye` lance la CLI, pas le collecteur | La CLI AgentEye est installée et possède `agenteye` | Utilisez `agenteye-collector` pour le daemon et supprimez tout ancien binaire du collecteur présent à `/usr/local/bin/agenteye`. | \ No newline at end of file diff --git a/docs/fr/agenteye/deployment.mdx b/docs/fr/agenteye/deployment.mdx new file mode 100644 index 00000000..a6c8ca98 --- /dev/null +++ b/docs/fr/agenteye/deployment.mdx @@ -0,0 +1,428 @@ +--- +title: "Déploiement" +description: "Documentation de déploiement AgentEye." +--- + + +Ce guide couvre le déploiement du serveur et du tableau de bord AgentEye en production. + +--- + +## Vue d'ensemble de l'architecture + +``` + [ Machines des agents IA ] [ Votre infrastructure ] + + Python SDK + | écrit en JSONL +----------------------+ + v +--->| PostgreSQL 15+ | + agenteye-collector --HTTP--+ | | (stockage relationnel)| + | | +----------------------+ + v | + +--------+ | +----------------------+ + | Server |<------+--->| ClickHouse 24+ | + +--------+ | | (événements/analytics)| + ^ | +----------------------+ + API | | + | | +----------------------+ + +-----------+ +- - >| Redis 7+ (optionnel)| + | Dashboard | +----------------------+ + +-----------+ +``` + +- **Server** : service HTTP en Rust ; reçoit les lots d'événements, les écrit dans ClickHouse et maintient l'état relationnel dans PostgreSQL. +- **Dashboard** : application web Next.js ; lit et écrit exclusivement via l'API du serveur. +- **agenteye-collector** : déployé sur les machines des agents, pas sur l'hôte du serveur. +- **Postgres 15+** : REQUIS. (Relevé de 14 lors de la version multi-tenant ; le schéma d'appartenance aux organisations utilise une clé étrangère `ON DELETE SET NULL` avec liste de colonnes, fonctionnalité disponible à partir de Postgres 15+. Mettez à niveau Postgres avant de déployer cette version.) Stocke l'état OLTP : `api_keys`, `users`, `sessions`, `evaluation_jobs` (file d'attente), `dashboards`, `saved_queries`, `otp_codes`, ainsi que les tables multi-tenant `orgs`, `org_memberships`, `org_settings`. +- **ClickHouse 24+** : REQUIS. Le stockage analytique pour chaque événement ingéré. Moteur : `ReplacingMergeTree`, partitionné par mois, ordonné par `(session_id, ts, dedup_key)`. Le serveur se connecte via `CLICKHOUSE_URL` ; la configuration `deploy/base/clickhouse/` fournie embarque une configuration mono-nœud optimisée pour les performances. **Exigence multi-tenant :** la configuration fournie active la gestion des accès SQL + `users_without_row_policies_can_read_rows=false` afin que le serveur puisse créer un utilisateur ClickHouse en lecture seule ainsi qu'une politique de lignes par organisation (frontière d'isolation appliquée par le moteur pour l'éditeur SQL et l'agent IA). Si vous fournissez votre propre configuration ClickHouse, reprenez ces paramètres (voir `deploy/base/clickhouse/configmap.yaml`). +- **Redis 7+** : cache partagé *optionnel* + backend de limitation de débit. Le serveur et le tableau de bord se connectent tous deux via `REDIS_URL`. En l'absence de Redis, les deux dégradent gracieusement vers des chemins Postgres uniquement. Voir **Redis (cache optionnel)** ci-dessous. + +--- + +## Serveur + +### Récupérer l'image + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +docker pull ghcr.io/agenteye-enterprise/server:beta-latest +``` + +> Les builds actuels publient sous `beta-latest` ; `latest` n'est attribué qu'aux versions stables. Pour la production, épinglez un tag spécifique `:v` ; voir [Tags d'image disponibles](#available-image-tags). + +### Variables d'environnement + +| Variable | Requise | Défaut | Description | +|---|---|---|---| +| `DATABASE_URL` | Oui | aucun | DSN Postgres. Chaîne de connexion libpq standard avec le schéma `postgres://`. Prend en charge `?sslmode=require` et d'autres paramètres libpq. Le mot de passe ne doit pas contenir `/`, `+` ou `=` ; utilisez `openssl rand -hex` pour générer des mots de passe sûrs pour les URL. | +| `ADMIN_KEY` | Non | aucun | Clé API d'administration de bootstrap. Insérée ou mise à jour avec toutes les permissions à chaque démarrage. Pour la faire tourner, modifiez la valeur et redémarrez. | +| `LISTEN_ADDR` | Non | `0.0.0.0:8080` | Adresse TCP à écouter | +| `MAX_BODY_BYTES` | Non | `134217728` (128 Mo) | Taille maximale du corps de la requête | +| `ADMIN_EMAIL` | Non | aucun | Email de l'utilisateur administrateur de bootstrap. Inséré ou mis à jour avec toutes les permissions à chaque démarrage et marqué comme protégé : ne peut pas être désactivé ni avoir ses permissions modifiées via le tableau de bord ou l'API. Pour changer l'administrateur de bootstrap, modifiez `ADMIN_EMAIL` et redémarrez ; le nouvel email est inséré/mis à jour comme protégé, et le précédent conserve sa protection jusqu'à ce qu'elle soit manuellement supprimée en base de données. | +| `ALLOWED_EMAILS` | Non | aucun (tout bloqué) | Liste d'emails autorisés, séparés par des virgules, pour la création d'utilisateurs et la connexion. Prend en charge les adresses exactes (`user@example.com`) et les jokers de domaine (`*@example.com`). Si non défini, aucun utilisateur ne peut être créé ni se connecter. **Initialisation au premier démarrage uniquement** : alimente la liste d'autorisation de l'organisation par défaut au premier démarrage ; par la suite, la page [`//settings`](#operational-settings) de chaque organisation fait foi et toute modification de cette variable d'environnement n'a aucun effet. | +| `SMTP_HOST` | Non | aucun | Nom d'hôte du serveur SMTP pour l'envoi des emails OTP. Si non défini, les codes OTP sont journalisés sur stdout à la place. | +| `SMTP_PORT` | Non | `587` | Port du serveur SMTP | +| `SMTP_USERNAME` | Non | aucun | Nom d'utilisateur d'authentification SMTP | +| `SMTP_PASSWORD` | Non | aucun | Mot de passe d'authentification SMTP | +| `SMTP_FROM` | Non | aucun | Adresse email d'expéditeur pour les emails OTP | +| `SMTP_TLS` | Non | STARTTLS | STARTTLS est utilisé sauf désactivation explicite : `false` ou `0` envoie en clair (sans TLS) ; toute autre valeur — y compris non définie — active STARTTLS. | +| `DASHBOARD_URL` | Non | valeur par défaut intégrée | Origine du tableau de bord utilisée pour construire à la fois le lien magique de l'email OTP et les liens magiques d'incident dans les notifications d'alerte. Si non défini, le système utilise une valeur par défaut intégrée (et, pour l'OTP uniquement, l'origine de la requête dérivée du tableau de bord en premier). Définissez cette variable pour les configurations à domaines séparés afin que les liens email et Slack/incident pointent vers votre tableau de bord. Voir **URL du lien magique email** ci-dessous ; la plupart des opérateurs n'ont pas besoin de la définir. | +| `SESSION_TTL_SECS` | Non | `86400` (24 h) | Durée de session du tableau de bord en secondes. **Initialisation au premier démarrage uniquement** : modifiable par organisation via [`//settings`](#operational-settings) après le premier déploiement. | +| `OTP_TTL_SECS` | Non | `600` (10 min) | Durée de validité du code OTP en secondes. **Initialisation au premier démarrage uniquement** : modifiable par organisation via [`//settings`](#operational-settings) après le premier déploiement. | +| `REDIS_URL` | Non | aucun | Backend optionnel de cache partagé + limitation de débit, ex. `redis://redis:6379/0`. Lorsqu'il est défini, le serveur met en cache les recherches de clés API authentifiées, l'agrégat `/models` du tableau de bord, la liste des sessions et la facette de liste d'environnements ; il déplace également la limitation de débit des requêtes OTP de `COUNT` Postgres vers `INCR` Redis. Si non défini ou injoignable, le serveur fonctionne sans cache (la limite OTP revient à Postgres, tous les autres appels de cache se rabattent sur la source de vérité). Voir **Redis (cache optionnel)** ci-dessous. | +| `CLICKHOUSE_URL` | **Oui** | aucun | URL de base de l'instance ClickHouse, ex. `http://clickhouse:8123`. Le serveur applique son schéma d'événements à cette base de données à chaque démarrage et refuse de démarrer s'il ne peut pas atteindre ClickHouse. Voir **ClickHouse (stockage analytique requis)** ci-dessous. | +| `CLICKHOUSE_DATABASE` | Non | `agenteye` | Nom de la base de données (schéma) ClickHouse. Le serveur la crée au démarrage si elle n'existe pas. | +| `ORG_CH_SECRET` | Non (mono-tenant) / **Oui (multi-org)** | valeur de développement par défaut | Clé HMAC à partir de laquelle le mot de passe ClickHouse par tenant de chaque organisation est dérivé. L'éditeur SQL et le `run_query` de l'agent IA s'exécutent en tant qu'utilisateur ClickHouse en lecture seule propre à l'organisation, dont la politique de lignes applique l'isolation des tenants dans le moteur. Les déploiements mono-tenant démarrent correctement avec la valeur de développement par défaut intégrée ; **avant de provisionner une deuxième organisation, vous DEVEZ définir une valeur forte et stable**, car le CLI `agenteye-orgctl org create` refuse de s'exécuter avec la valeur de développement par défaut. La rotation orpheline l'utilisateur ClickHouse de chaque organisation jusqu'au prochain démarrage (le rapprochement au démarrage corrige cela automatiquement). Gardez-la secrète et inchangée sur tous les réplicas. Le provisionnement des organisations est réservé aux opérateurs ; voir **Organisations (multi-tenant)** ci-dessous. | +| `DEFAULT_ORG_NAME` | Non | `Default` | Nom d'affichage initialisé pour l'organisation par défaut intégrée. **Initialisation au premier démarrage uniquement**, et seulement tant que l'organisation conserve son identité générique issue de la migration, appliqué au démarrage puis ignoré. Une fois l'organisation renommée (`agenteye-orgctl org rename`), le renommage fait foi et cette variable d'environnement n'a plus d'effet. | +| `DEFAULT_ORG_SLUG` | Non | `default` | Slug d'URL pour l'organisation par défaut intégrée, le chemin du tableau de bord où elle réside (`//…`). Même sémantique de premier démarrage uniquement / identité vierge que `DEFAULT_ORG_NAME`. Doit comporter entre 1 et 40 caractères alphanumériques minuscules avec des tirets internes simples et ne doit pas être un [mot réservé](#organizations-multi-tenancy) ; une valeur invalide est ignorée (l'organisation conserve `default`). Permet à une installation mono-tenant de s'afficher par exemple en `/acme` au lieu de `/default` sans étape CLI post-déploiement. | +| `RUST_LOG` | Non | `info` | Verbosité des logs (`debug`, `warn`, `error`, `agenteye_server=trace`) | +| `EVALUATOR_ENDPOINT` | Non | aucun | URL de base de votre service d'évaluation (ex. `http://evaluator:9000`). Si non défini, l'ensemble du pipeline d'évaluation est inopérant ; aucune ligne de file d'attente n'est écrite, aucun worker ne s'exécute. Voir [Suite d'évaluation](/fr/agenteye/evaluation-suite). | +| `EVALUATOR_TOKEN` | Non | aucun | Envoyé comme `Authorization: Bearer ` à l'évaluateur. **Doit être égal à la valeur avec laquelle le service évaluateur est configuré.** Optionnel uniquement si votre évaluateur est configuré sans token. | +| `EVALUATOR_WORKERS` | Non | `2` | Concurrence : nombre de tâches worker par instance de serveur qui envoient les évaluations. Sûr à exécuter sur plusieurs serveurs à mise à l'échelle horizontale. | +| `EVALUATOR_CLAIM_BATCH` | Non | `4` | Nombre maximum d'évaluations qu'un seul worker revendique par cycle. Les lots sont envoyés **concurremment**, donc la concurrence totale sur votre endpoint évaluateur est `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH`. | +| `EVALUATOR_POLL_IDLE_SECS` | Non | `2` | Durée de sommeil d'un worker entre les tentatives d'envoi quand rien n'est en attente. | +| `EVALUATOR_POLLING_INTERVAL_SECS` | Non | `10` | Cadence de repli finale (en secondes) pour les sondages `GET /evaluate/{id}` quand l'évaluateur ne retourne pas de `next_poll_secs` par réponse et n'annonce pas de `default_poll_interval_secs` via `GET /config`. | +| `EVALUATOR_REQUEST_TIMEOUT_MS` | Non | `30000` | Délai d'expiration par requête HTTP vers l'évaluateur (en millisecondes). | +| `EVALUATOR_MAX_ATTEMPTS` | Non | `5` | Après ce nombre de tentatives échouées, une évaluation est enregistrée comme `error` terminal (ou `timeout` si les échecs étaient des délais d'expiration de requête). | +| `EVALUATOR_CONFIG_REFRESH_SECS` | Non | `300` (5 min) | Fréquence à laquelle le serveur récupère à nouveau `GET /config` depuis l'évaluateur. | +| `EVALUATOR_MAX_POLL_DURATION_SECS` | Non | `3600` (1 h) | Durée maximale en temps réel pendant laquelle une session peut rester dans la file de sondage avant qu'AgentEye ne la termine en `timeout`. Protège contre un évaluateur qui retourne `pending` indéfiniment. | +| `ALERT_WORKERS` | Non | `1` | Concurrence : nombre de tâches worker par instance de serveur qui évaluent les règles d'alerte. Voir [Alertes](/fr/agenteye/alerts). | +| `ALERT_CLAIM_BATCH` | Non | `16` | Nombre maximum d'alertes qu'un seul worker revendique par cycle. | +| `ALERT_POLL_IDLE_SECS` | Non | `5` | Durée de sommeil d'un worker d'alertes quand la file est vide. | +| `ALERT_REQUEST_TIMEOUT_MS` | Non | `15000` | Délai d'expiration par évaluation de déclenchement (requêtes ClickHouse + HTTP de canal sortant). | +| `ALERT_MAX_ATTEMPTS` | Non | `5` | Échecs transitoires consécutifs avant qu'une alerte soit replanifiée à sa cadence normale plutôt qu'avec un backoff exponentiel. | +| `AUDIT_WORKERS` | Non | `1` | Concurrence : nombre de tâches worker par instance de serveur qui exécutent les audits. Voir [Audits](/fr/agenteye/audits). | +| `AUDIT_CLAIM_BATCH` | Non | `1` | Nombre maximum d'audits échus qu'un seul worker revendique par cycle. Une investigation agentique est une longue boucle, d'où la valeur par défaut de 1. | +| `AUDIT_POLL_IDLE_SECS` | Non | `30` | Durée de sommeil d'un worker d'audits quand aucun audit n'est dû. | +| `AUDIT_REQUEST_TIMEOUT_MS` | Non | `30000` | Délai d'expiration par requête de politique vers ClickHouse (en millisecondes). | +| `AUDIT_LLM_TIMEOUT_MS` | Non | `1440000` | Délai d'expiration pour l'appel d'investigation agentique au service assistant IA. Une boucle d'agent complète dure plusieurs minutes ; maintenez cette valeur AU-DESSUS du propre `AGENTEYE_AUDIT_TIMEOUT_MS` de l'agent afin que l'agent retourne ses résultats partiels avant que le serveur n'abandonne. | +| `AUDIT_MAX_ATTEMPTS` | Non | `5` | Échecs transitoires consécutifs avant qu'un audit soit replanifié à sa cadence normale plutôt qu'avec un backoff exponentiel. | +| `AGENTEYE_AGENT_URL` / `AGENTEYE_AGENT_TOKEN` | Non | — | L'investigation agentique de l'audit appelle le service `agent` d'assistant IA, **en réutilisant la même connexion que l'assistant** — définissez donc ces deux variables sur le **serveur** également (les manifestes/compose fournis le font). Les deux définies ⇒ les audits exécutent l'investigation IA ; l'une ou l'autre non définie ⇒ les audits s'exécutent **en mode politique uniquement** (la passe de politique SQL déterministe s'exécute quand même), indépendamment de l'indicateur `llm_enabled` par audit. L'agent doit également avoir un LLM configuré — voir [assistant.md](/fr/agenteye/assistant). | + +**Service assistant IA — paramètres d'audit et de sandbox.** L'investigation agentique et son sandbox Python en pod sont réglés sur le **service agent** (pas sur le serveur), tous avec le préfixe `AGENTEYE_AUDIT_*` et tous optionnels : + +| Variable | Défaut | Signification | +|---|---|---| +| `AGENTEYE_AUDIT_MAX_STEPS` | `200` | Nombre maximum de tours d'agent par investigation. | +| `AGENTEYE_AUDIT_TIMEOUT_MS` | `1200000` | Durée en temps réel pour une investigation (20 min). Doit rester **inférieure** au `AUDIT_LLM_TIMEOUT_MS` du serveur. | +| `AGENTEYE_AUDIT_MAX_CONCURRENCY` | `1` | Investigations simultanées par pod agent (indépendamment du budget de l'assistant de chat). | +| `AGENTEYE_AUDIT_SANDBOX_TIMEOUT_MS` / `_MEM_MB` / `_CPU_SECS` / `_OUTPUT_MAX_BYTES` / `_SCRIPT_MAX_BYTES` | `20000` / `768` / `10` / `64000` / `64000` | Limites par script pour le sandbox bubblewrap. | + +**Exigence de plateforme pour le sandbox.** Le sandbox de code d'audit exécute le Python du modèle dans une cage bubblewrap, qui nécessite des **espaces de noms utilisateur non privilégiés**. Le pod agent doit autoriser les indicateurs `clone()` — définissez `seccompProfile: Unconfined` (k8s) ou `security_opt: [seccomp:unconfined]` (compose) sur l'agent. Lorsque le noyau du nœud désactive les espaces de noms utilisateur non privilégiés (ex. certaines images GKE COS), le **prévol du sandbox échoue et l'auditeur se dégrade automatiquement en mode SQL uniquement** — pas d'erreur, juste un `sandbox_available: false` sur le `/health` de l'agent. + +### Démarrer + +Définissez `DATABASE_URL` et `CLICKHOUSE_URL` dans votre environnement (le serveur refuse de démarrer sans ClickHouse), puis transmettez-les au conteneur : + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-server \ + -e DATABASE_URL="$DATABASE_URL" \ + -e CLICKHOUSE_URL="$CLICKHOUSE_URL" \ + -e ADMIN_KEY="$ADMIN_KEY" \ + -p 8080:8080 \ + ghcr.io/agenteye-enterprise/server:beta-latest +``` + +Le serveur exécute les migrations de base de données automatiquement au démarrage ; aucune étape de migration séparée n'est nécessaire. + +### Vérification de santé + +``` +GET /health # liveness - toujours {"status":"ok"} une fois le processus démarré +GET /ready # readiness - 200 quand Postgres + ClickHouse sont joignables, sinon 503 +``` + +Aucune authentification requise. Utilisez `/health` pour les sondes de **liveness** et `/ready` pour les sondes de **readiness** / d'équilibreur de charge. `/ready` vérifie les dépendances strictes sans lesquelles le serveur ne peut pas servir (Postgres + ClickHouse), donc un serveur en cours d'exécution mais incapable d'atteindre sa base de données est retiré de la rotation et apparaît comme `NotReady` ; Redis est rapporté mais ne fait jamais échouer la readiness. Dans les manifestes Kubernetes fournis, la sonde de readiness pointe déjà sur `/ready` et la liveness reste sur `/health`. Voir [enterprise-docs/health-monitoring.md](/fr/agenteye/health-monitoring) pour la vue d'ensemble complète, y compris les alertes Slack optionnelles natives Kubernetes sur les défaillances de pods. + +### URL du lien magique email + +Les emails de connexion OTP contiennent un bouton **ouvrir le tableau de bord** en un clic. En cliquant dessus, l'utilisateur arrive sur `/login?token=&email=
` ; le tableau de bord échange cette paire contre une session et redirige vers l'application, sans ressaisie manuelle du code. Le serveur résout l'origine du tableau de bord utilisée pour construire le lien selon trois niveaux : + +1. **En-tête `X-AgentEye-Dashboard-Url`** : défini automatiquement par le proxy `/api/auth/otp/request` du tableau de bord depuis sa propre origine publique. Dans un déploiement sur la même origine (serveur et tableau de bord partagent un hôte derrière un ingress unique qui transfère les en-têtes proxy), **aucune configuration n'est requise**. +2. **Variable d'environnement `DASHBOARD_URL`** : définissez-la si votre tableau de bord est joignable sur une origine différente de celle que voit le endpoint de requête OTP du serveur (configuration `api.example.com` / `app.example.com` séparée), ou si votre ingress ne propage pas l'hôte public dans le pod tableau de bord (de sorte que `request.nextUrl.origin` se résoudrait sinon en une adresse générique comme `0.0.0.0:3000`). Exemple : `DASHBOARD_URL=https://app.example.com`. +3. **Défaut** : `https://app.befailproof.ai`, utilisé uniquement si aucune des options ci-dessus n'est présente. + +La valeur de l'en-tête est validée : seules les origines `https://*` et loopback (`http://localhost*`, `http://127.0.0.1*`) sont acceptées, et les adresses de liaison génériques (`0.0.0.0`, `[::]`) sont rejetées même avec le schéma `https://`. Tout le reste passe au niveau 2. + +Mettez-la à jour sur un cluster en cours d'exécution avec une commande simple ; aucun fichier, aucune reconstruction kustomize : + +```bash +kubectl set env deployment/server -n agenteye \ + DASHBOARD_URL=https://app.example.com +``` + +Cela déclenche un rollout ; les nouveaux pods récupèrent la valeur dès la première requête. Notez que la surcharge ne réside que sur le Deployment ; un `kustomize build | kubectl apply` ultérieur sur l'overlay la supprimera sauf si vous ajoutez la même variable d'environnement au patch `server-env.yaml` de votre overlay. + +--- + +## Tableau de bord + +### Récupérer l'image + +```bash +docker pull ghcr.io/agenteye-enterprise/dashboard:beta-latest +``` + +### Variables d'environnement + +| Variable | Requise | Défaut | Description | +|---|---|---|---| +| `AGENTEYE_SERVER_URL` | Oui | aucun | URL de base du serveur, ex. `http://localhost:8080` | +| `AGENTEYE_API_KEY` | Oui | aucun | Clé API que le tableau de bord utilise pour s'authentifier auprès du serveur. Toutes les permissions sont requises (clé admin recommandée). | +| `AE_LOG_LEVEL` | Non | `info` | Verbosité des logs côté serveur : `debug`, `info`, `warn`, `error`. Définissez sur `debug` pour voir les lignes de requête/réponse amont et les traces de validation de session lors du diagnostic de problèmes. | +| `AE_LOG_JSON` | Non | automatique | `1` force la sortie JSON par ligne ; `0` force la sortie lisible par l'humain. Si non défini, JSON est activé automatiquement si `NODE_ENV=production`. JSON est recommandé en production pour que les logs se parsent proprement avec `jq` ou un agrégateur de logs. | +| `AE_ANALYTICS_DISABLED` | Non | aucun | Définissez sur `1`/`true` pour désactiver la télémétrie anonyme d'utilisation du produit du tableau de bord. Voir [Télémétrie et confidentialité](#telemetry--privacy) ci-dessous. | +| `REDIS_URL` | Non | aucun | Backend de cache partagé optionnel, ex. `redis://redis:6379/0`. Lorsqu'il est défini, le tableau de bord met en cache les résultats de `validateSession()` entre les réplicas et partage le cache de récupération Next.js pour les routes proxy d'agrégat de latence / liste d'environnements. Les limites de débit OTP côté edge pour les requêtes et vérifications utilisent également Redis si présent (avec repli ouvert si Redis est injoignable ; la limite côté serveur est le filet de sécurité). Voir **Redis (cache optionnel)** ci-dessous. | +| `AGENTEYE_AGENT_URL` | Non | aucun | URL de base du service `agent` assistant IA optionnel, ex. `http://agent:9100`. **Laissez-le non défini pour masquer complètement l'assistant** : aucune bulle d'assistant n'apparaît dans le tableau de bord. Voir [enterprise-docs/assistant.md](/fr/agenteye/assistant). | +| `AGENTEYE_AGENT_TOKEN` | Non | aucun | Secret partagé que le tableau de bord présente au service `agent`. Doit correspondre à `AGENTEYE_AGENT_TOKEN` configuré sur l'agent. Voir [enterprise-docs/assistant.md](/fr/agenteye/assistant). | + +### Démarrer + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-dashboard \ + -e AGENTEYE_SERVER_URL="http://your-server-host:8080" \ + -e AGENTEYE_API_KEY="$ADMIN_KEY" \ + -p 3000:3000 \ + ghcr.io/agenteye-enterprise/dashboard:beta-latest +``` + +### Télémétrie et confidentialité + +Le tableau de bord envoie des **analytics anonymes d'utilisation du produit** au service d'analytics d'Exosphere (PostHog) : quelles pages du tableau de bord sont consultées et quelques actions d'interface utilisateur telles que la création d'une clé API ou la réévaluation d'une session. Ce signal d'utilisation oriente la priorisation des fonctionnalités. + +- **Aucune donnée d'agent, de session ou d'événement ne quitte jamais votre infrastructure.** Seule l'utilisation de l'interface du tableau de bord est rapportée. Les URL de pages sont dépouillées de leurs identifiants avant envoi, et les opérateurs ne sont identifiés que par un identifiant interne opaque, jamais par email. +- La télémétrie est **activée par défaut**. Pour la désactiver complètement, définissez `AE_ANALYTICS_DISABLED=1` sur le conteneur du tableau de bord et redémarrez. +- Les analytics sont envoyées vers le propre chemin `/ingest` du tableau de bord, que le tableau de bord reverse-proxy vers PostHog (`https://us.i.posthog.com`). Conserver les requêtes en first-party signifie que les bloqueurs de publicité des navigateurs ne les suppriment pas. Le **conteneur du tableau de bord** a besoin d'un accès sortant vers PostHog ; s'il est bloqué, la télémétrie ne fait rien silencieusement et le tableau de bord n'est pas affecté. + +--- + +## Assistant IA (optionnel) + +Un assistant IA intégré au tableau de bord permet à votre équipe de poser des questions sur leurs données d'agents en langage naturel (résumé de sessions, rédaction de SQL pour l'éditeur `/queries`, et transformation de requêtes sauvegardées en tuiles de tableau de bord) sans quitter le tableau de bord. Il fonctionne comme un conteneur `agent` interne séparé (sur le Claude Agents SDK) que seul le tableau de bord peut atteindre, et reste **désactivé jusqu'à ce que vous configuriez un endpoint LLM**. + +Pour l'activer, définissez sur le service `agent` une connexion LLM (**Portkey** via `PORTKEY_API_KEY` + un slug de catalogue de modèles `AGENTEYE_AGENT_MODEL=@/`, Anthropic direct via `ANTHROPIC_API_KEY`, une autre passerelle via `ANTHROPIC_BASE_URL`, ou Bedrock/Vertex), une clé de données **dédiée**, et un `AGENTEYE_AGENT_TOKEN` partagé correspondant au tableau de bord. Les utilisateurs du tableau de bord ont en outre besoin de la permission `agent:use`. + +Pour la clé de données de l'assistant, vous n'avez rien à créer manuellement : choisissez un secret aléatoire, définissez-le comme `AGENTEYE_API_KEY` sur l'`agent` **et** comme `AGENT_API_KEY` sur le `server`, et le serveur l'initialise au démarrage avec un ensemble de permissions fixe. Son accès aux données est en lecture seule (`events:read`, `evaluations:read`, `dashboards:read`, `queries:read`), et il détient en plus des portées d'authoring avec approbation requise (`dashboards:write`, `queries:write`, `queries:run`) afin qu'il puisse rédiger et valider des requêtes sauvegardées et créer des tuiles de tableau de bord pour le compte de l'utilisateur ; tout le SQL s'exécute quand même via le rôle ClickHouse en lecture seule de l'organisation, donc cela élargit ce que l'assistant peut créer, pas les données auxquelles il peut accéder. Les portées sont fixes dans le code et ne peuvent pas être élargies par configuration. Cette clé est protégée ; elle ne peut pas être désactivée ou régénérée via l'API, uniquement en changeant la valeur et en redémarrant. Ne réutilisez jamais la clé admin/tableau de bord pour cela. + +La configuration complète, la référence complète des variables d'environnement, les options de télémétrie et le modèle de sécurité se trouvent dans **[enterprise-docs/assistant.md](/fr/agenteye/assistant)**. + +--- + +## ClickHouse (stockage analytique requis) + +ClickHouse maintient la réactivité de vos tableaux de bord à des volumes d'événements élevés et permet à l'éditeur SQL `/queries` de joindre événements, évaluations et sessions dans un seul stockage. C'est le stockage canonique requis pour chaque événement ingéré, chaque résultat d'évaluation terminal et les agrégats dérivés par session. PostgreSQL contient les tables d'état relationnel/mutable (api_keys, users, otp_codes, evaluation_jobs, dashboards, saved_queries) ; la surface analytique réside dans ClickHouse afin que les agrégats du tableau de bord et vos propres requêtes SQL puissent les parcourir et les joindre nativement, sans allers-retours entre bases de données. Le serveur refuse de démarrer sans `CLICKHOUSE_URL`. + +### Schéma + +Trois objets ClickHouse sont créés au démarrage du serveur, tous idempotents (`CREATE IF NOT EXISTS`) : + +- **`agenteye.events`** : `ReplacingMergeTree(ingested_at)`, partitionné par `toYYYYMM(ts)`, ordonné par `(session_id, ts, dedup_key)`. Les insertions dupliquées (tentatives du collecteur) se réduisent à une seule ligne à la fusion ; le serveur calcule un `dedup_key` SHA-256 déterministe pour chaque événement, rendant les tentatives sûres. +- **`agenteye.evaluations`** : `ReplacingMergeTree(ingested_at)`, partitionné par `toYYYYMM(finished_at)`, ordonné par `(session_id, finished_at, dedup_key)`. Écrit une fois par résultat d'évaluation terminal par le pipeline d'évaluation. Même modèle de clé de déduplication que `events`. +- **`agenteye.agent_sessions`** : une **VUE** sur `agenteye.events`, pas une table physique. Chaque colonne est dérivée (`started_at = min(ts)`, `last_event_at = max(ts)`, `ended_at = max(if event_type='agent_end', ts, NULL)`, `event_count = count()`, etc.). Pas d'upsert par événement et pas de backfill séparé ; la vue reflète automatiquement ce qui se trouve dans `events`. + +Pour la compatibilité ascendante avec les requêtes sauvegardées qui référencent `analytics.evaluations` / `analytics.sessions`, le serveur crée également une base de données ClickHouse `analytics` avec des vues sur les tables `agenteye.*` ; `analytics.events`, `analytics.evaluations`, `analytics.agent_sessions`, `analytics.sessions` se résolvent tous correctement. + +### Configuration + +Le docker-compose fourni et `deploy/base/clickhouse/` embarquent un service ClickHouse réglé pour la charge de travail d'AgentEye : + +- 2 Gio demandés / 4 Gio limite de mémoire dans l'overlay de base fourni (dimensionné pour les petits nœuds POC/staging) ; les clients en production devraient augmenter — le plancher recommandé est 2c / 4Gi demandé, 6c / 8Gi limite. `max_server_memory_usage_to_ram_ratio=0.9` +- 5 Gio de cache de marque + 8 Gio de cache non compressé +- `background_pool_size=16`, `background_merges_mutations_concurrency_ratio=2` +- MergeTree : `parts_to_throw_insert=3000`, `parts_to_delay_insert=1500`, `non_replicated_deduplication_window=1000` +- `local_io_method=auto` (io_uring sur les noyaux supportés) +- `fsync_metadata=0` : acceptable en raison de l'ingestion au moins une fois + déduplication ReplacingMergeTree +- `query_log` activé avec une TTL de 30 jours ; `query_thread_log` supprimé (coûteux à QPS élevé) +- `max_execution_time=30` pour les requêtes côté utilisateur +- PVC de 100 Gio au template StatefulSet (les overlays clients DEVRAIENT surcharger avec une classe de stockage SSD rapide pour la production) + +### Sauvegardes + +Votre jeu de données complet est capturé chaque nuit dans une archive restaurable unique, de sorte qu'une perte de cluster ou de stockage est récupérable. ClickHouse est sauvegardé automatiquement par le CronJob quotidien `agenteye-backup`, qui vide à la fois PostgreSQL et ClickHouse en un seul passage. ClickHouse est lu via son API HTTP : `agenteye.events` et `agenteye.evaluations` sont vidés au format natif ClickHouse (les vues et politiques de lignes sont recréées par le serveur au démarrage, donc les données de table constituent le tableau complet) et regroupés avec le dump Postgres dans une archive compressée unique téléchargée vers votre stockage objet. + +Le bucket de destination et les identifiants cloud sont configurés par overlay. Voir la section **Sauvegardes** de [enterprise-docs/kubernetes-deployment.md](/fr/agenteye/kubernetes-deployment) pour la configuration de téléchargement et les étapes de restauration. + +--- + +## Redis (cache optionnel) + +Redis est un backend de cache partagé + limitation de débit **optionnel** utilisé par le serveur et le tableau de bord. Avec Redis déployé et `REDIS_URL` défini sur les deux services : + +- **Le serveur** met en cache les recherches de clés API authentifiées, les listes `/events/environments` + `/evaluations/environments`, l'agrégat `/events/latency_aggregate` (la requête la plus lourde que le tableau de bord sonde), la liste `/sessions`, et passe la limitation de débit des requêtes OTP d'un `COUNT(*)` Postgres à un `INCR + EXPIRE` Redis. +- **Le tableau de bord** met en cache les résultats de `validateSession()` afin que les 10-20 appels API authentifiés qu'un chargement de page typique émet partagent tous une seule vérification de session amont. Il limite également le débit des requêtes OTP et des vérifications OTP au niveau de l'edge du tableau de bord. + +**Les deux services dégradent gracieusement si Redis est injoignable.** Chaque appel de cache retourne `Err` dans un délai limité et l'appelant se rabat sur la source de vérité (Postgres sur le serveur, le serveur Rust amont sur le tableau de bord). La limitation de débit OTP se rabat sur le chemin `COUNT(*)` Postgres sur le serveur (la propriété de sécurité est préservée) ; la limite OTP de l'edge du tableau de bord s'ouvre en cas d'échec tandis que la limite côté serveur tient toujours. Une panne Redis dégrade la latence, pas la cohérence. + +### Configuration + +Le bundle docker-compose inclut déjà un service Redis et câble `REDIS_URL=redis://redis:6379/0` dans le serveur et le tableau de bord. Pour utiliser un Redis externe, définissez `REDIS_URL` vers votre endpoint et supprimez le service `redis` du fichier compose. + +### Mémoire et persistance + +L'image Redis fournie s'exécute avec `--appendonly yes --appendfsync everysec --maxmemory 256mb --maxmemory-policy allkeys-lru`. La persistance AOF signifie que le cache survit aux redémarrages de conteneur ; `everysec` est le bon équilibre durabilité/performance car perdre la dernière seconde d'écritures de cache est sans conséquence. L'éviction LRU plafonne la croissance de la mémoire. + +### Quand NE PAS déployer Redis + +- Développement/QA à instance unique. Les caches en cours de processus sur le serveur seul apportent la plupart des bénéfices par réplica ; Redis ajoute le partage inter-réplicas dont les configurations à instance unique n'ont pas besoin. +- Installations air-gapped où le coût opérationnel de faire fonctionner un service supplémentaire l'emporte sur le gain de latence. + +--- + +## Docker Compose (recommandé) + +Un `docker-compose.yml` est disponible dans le dépôt `agenteye-enterprise/releases`. Il lance Postgres, ClickHouse, Redis, le serveur et le tableau de bord avec une seule commande. + +```bash +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download \ + --repo agenteye-enterprise/releases \ + --pattern 'docker-compose.yml' \ + --dir ./agenteye +cd agenteye +``` + +**Surcharger les valeurs par défaut via `.env` :** + +``` +# Utilisez des mots de passe sûrs pour les URL (sans /, + ou =). +# Générez avec : openssl rand -hex 24 +POSTGRES_PASSWORD=your-db-password +ADMIN_KEY=your-admin-secret + +# Authentification du tableau de bord +ADMIN_EMAIL=admin@yourcompany.com +ALLOWED_EMAILS=*@yourcompany.com + +# SMTP pour les emails OTP (omettez pour journaliser les codes OTP sur stdout) +# SMTP_HOST=smtp.yourprovider.com +# SMTP_PORT=587 +# SMTP_USERNAME=your-smtp-user +# SMTP_PASSWORD=your-smtp-password +# SMTP_FROM=noreply@yourcompany.com + +RUST_LOG=info +``` + +```bash +docker compose up -d +``` + +**Arrêter (conserve le volume de données) :** + +```bash +docker compose down +``` + +**Arrêter et effacer toutes les données :** + +```bash +docker compose down -v +``` + +--- + +## Paramètres opérationnels + +Un petit ensemble de paramètres opérationnels qui étaient auparavant fixés par des variables d'environnement sont maintenant modifiables par organisation depuis la page **`//settings`** du tableau de bord ; chaque organisation configure les siens. Les modifications prennent effet en quelques secondes, sans redémarrage ni redéploiement. + +| Paramètre | Variable d'environnement de bootstrap | Ce qu'il contrôle | +|---|---|---| +| Connexions autorisées | `ALLOWED_EMAILS` | Emails (ou jokers `*@domain.com`) autorisés à recevoir un OTP et à être ajoutés comme utilisateurs | +| Permissions utilisateur par défaut | `DEFAULT_USER_PERMISSIONS` | Tokens de permission séparés par des virgules présélectionnés quand un administrateur ouvre **+ nouvel utilisateur**. Chaque token doit être l'une des chaînes listées sous [Permissions des clés API](/fr/agenteye/api-keys). Par défaut, le préréglage `standard` : accès en lecture seule plus les actions quotidiennes d'astreinte (déclencher des réévaluations, exécuter des requêtes, acquitter des incidents, utiliser l'assistant). | +| Durée de vie de la session | `SESSION_TTL_SECS` | Durée pendant laquelle une connexion au tableau de bord reste valide avant une nouvelle authentification. Le tableau de bord revérifie la session amont toutes les 5 secondes, donc une mise à jour des permissions sur `//users` prend effet à la prochaine requête de l'utilisateur concerné, sans reconnexion. | +| Durée de vie du code à usage unique | `OTP_TTL_SECS` | Durée pendant laquelle un OTP / lien magique reste utilisable | +| Canaux de notification d'alerte | `ALERTS_ENABLED_CHANNELS` | Liste de types de canaux séparés par des virgules que le répartiteur d'alertes est autorisé à utiliser : `email`, `slack`, `webhook`. La configuration par alerte est toujours créée sur `//alerts/`, mais le répartiteur filtre chaque livraison sortante à travers cet ensemble ; un canal désactivé ici court-circuite avec une ligne d'audit `skipped_disabled`. Le canal `dashboard` (l'insertion d'audit locale) est toujours autorisé. Par défaut, les trois sont activés. | + +### Fonctionnement du bootstrap + +Les paramètres sont stockés par organisation dans `org_settings`. Au premier démarrage, le serveur initialise les lignes manquantes de l'organisation par défaut à partir de la variable d'environnement correspondante (ou d'une valeur par défaut raisonnable si la variable d'environnement n'est pas définie). Après cela, **la valeur stockée fait foi et la variable d'environnement est ignorée** ; modifier la variable d'environnement lors d'un redémarrage ultérieur n'affectera pas la valeur d'une organisation en production, et les organisations supplémentaires démarrent avec les valeurs par défaut et configurent les leurs. + +Cela signifie : + +- Pour un nouveau déploiement, définissez les variables d'environnement comme indiqué ci-dessus et l'organisation par défaut les lira au premier démarrage. +- Pour modifier une valeur ultérieurement, connectez-vous au tableau de bord et modifiez-la sous `//settings`. La modification s'applique en quelques secondes sur tous les réplicas du serveur ; aucun redémarrage n'est nécessaire. +- Une ligne de log au démarrage enregistre ce qui a été initialisé par rapport à ce qui était déjà présent, afin que vous puissiez confirmer que le bootstrap a pris effet : + + ```text + INFO settings bootstrap: seeded default-org row key=allowed_sign_ins env_var=ALLOWED_EMAILS seeded_from_env=true + ``` + +#### Sémantique de connexion entre organisations + +Une session et un OTP sont globaux à l'utilisateur, pas à une seule organisation, donc deux règles réconcilent les paramètres par organisation au moment de la connexion : + +- **Durée de vie de la session / OTP** : la durée la plus stricte (la plus courte) parmi les organisations auxquelles l'utilisateur appartient l'emporte. +- **Connexions autorisées** : le filtre effectue un OU de la liste d'autorisation de chaque organisation avec l'appartenance à l'organisation : un utilisateur peut demander un OTP si la liste d'autorisation d'une organisation admet son email **ou** s'il est déjà membre d'une organisation. + +### Permissions + +L'accès à une page `//settings` est conditionné par deux permissions : + +- `settings:read` : voir la page et les valeurs actuelles. +- `settings:write` : enregistrer les modifications. + +L'utilisateur administrateur de bootstrap (initialisé depuis `ADMIN_EMAIL`) obtient les deux automatiquement avec toutes les autres permissions. Accordez-les à d'autres utilisateurs depuis `//users` selon les besoins. + +--- + +## Organisations (multi-tenant) + +Un seul déploiement peut servir plusieurs **organisations** (tenants) isolées ; chaque ligne de données appartient exactement à une organisation et l'isolation est appliquée dans le moteur de base de données. Une installation mono-tenant n'a besoin de rien ici ; toutes les données résident dans une organisation `default` intégrée. (Vous pouvez donner à cette organisation un nom plus convivial et un slug d'URL, afin qu'elle réside par exemple en `/acme` plutôt qu'en `/default`, en définissant `DEFAULT_ORG_NAME` / `DEFAULT_ORG_SLUG` avant le premier démarrage, ou en la renommant à tout moment avec `agenteye-orgctl org rename`.) + +**Le provisionnement des tenants est réservé aux opérateurs.** Les organisations et leurs appartenances sont créées et gérées avec le CLI **`agenteye-orgctl`**, qui est livré **à l'intérieur de l'image du serveur** (aux côtés de `agenteye-server`) et s'exécute **à l'intérieur du pod serveur existant** ; il n'y a **pas de pod/Job séparé, pas d'API HTTP et pas de bouton dans le tableau de bord**. Il réutilise le `DATABASE_URL`, `CLICKHOUSE_URL` et `ORG_CH_SECRET` du serveur. + +```bash +# Docker Compose - exec dans le service serveur en cours d'exécution : +docker compose exec server agenteye-orgctl org create --slug acme --name "Acme Corp" +docker compose exec server agenteye-orgctl member add --org acme --email alice@acme.example --set admin + +# Kubernetes - exec dans le Deployment serveur en cours d'exécution : +kubectl -n agenteye exec deploy/server -- agenteye-orgctl org list +``` + +Verbes disponibles : `org create | list | rename | delete | purge` et `member add | list | update | remove`, avec des ensembles de permissions intégrés `admin`, `standard` et `read-only`. Les membres ajoutés reçoivent un OTP lors de leur première connexion au tableau de bord. + +**Avant de créer une deuxième organisation :** définissez un `ORG_CH_SECRET` fort et stable (la commande `org create` refuse de s'exécuter avec la valeur de développement par défaut intégrée) et assurez-vous que Postgres est en **15+**. **Inchangé :** les clés API par organisation sont toujours créées dans le tableau de bord/API par les membres de l'organisation ; seul le cycle de vie des organisations + membres a été déplacé vers le CLI. Référence complète des commandes et exemple concret : **[enterprise-docs/tenant-management.md](/fr/agenteye/tenant-management)**. + +--- + +## Remplissage de la fenêtre de contexte + +Chaque événement `model_response` affiche une **pastille de remplissage de contexte** — les tokens d'entrée plus les tokens de sortie en pourcentage de la fenêtre de contexte de ce modèle. Les bandes sont `healthy` (0-24 %), `watch` (25-49 %), `compacting` (50-74 %) et `reset context` (75-100 %). AgentEye résout automatiquement les identifiants de modèles courants, donc aucune configuration initiale n'est requise. + +Chaque modèle qu'une organisation envoie apparaît sous **Paramètres → fenêtres de contexte des modèles**. Les utilisateurs avec `settings:write` peuvent remplacer sa fenêtre ou ajouter un modèle privé/proxy (0-1 000 000 tokens) ; `0` signifie inconnu et supprime la pastille. Les modifications s'appliquent aux événements nouvellement ingérés. Les utilisateurs avec `settings:read` peuvent consulter la liste. + +Les nouveaux événements obtiennent le remplissage dès le moment où vous mettez à niveau. Pour également renseigner les événements **historiques** (et la liste par modèle) pour un déploiement existant, exécutez le backfill ponctuel — il est livré à l'intérieur de l'image du serveur (comme `agenteye-orgctl`) et s'exécute dans le pod serveur existant : + +```bash +# aperçu (affiche la mutation par organisation, ne change rien) : +kubectl -n agenteye exec deploy/server -- agenteye-backfill-context-window --dry-run +# appliquer : +kubectl -n agenteye exec deploy/server -- agenteye-backfill-context-window +# docker compose : +docker compose exec server agenteye-backfill-context-window +``` + +Il est idempotent (sûr à relancer) et réutilise `DATABASE_URL` / `CLICKHOUSE_URL` / `REDIS_URL` depuis le pod. Relancez-le après avoir modifié les fenêtres de modèles si vous souhaitez que les événements existants soient recalculés. + +--- + +## Considérations de production + +- **Postgres** : Utilisez un service Postgres géré ou une instance dédiée avec des sauvegardes régulières. Le `DATABASE_URL` prend en charge tous les paramètres libpq standard, y compris `sslmode=require` pour les connexions chiffrées. +- **TLS** : Placez le serveur et le tableau de bord derrière un reverse proxy (nginx, Caddy, Traefik) qui termine TLS. +- **Pare-feu** : Le port du serveur (par défaut 8080) ne doit être accessible que depuis les machines de collecteur et l'hôte du tableau de bord, pas depuis l'internet public. +- **Clé admin** : Définissez `ADMIN_KEY` sur un secret aléatoire fort. Après le bootstrap, créez des clés dédiées et restreintes pour les collecteurs et le tableau de bord plutôt que d'utiliser la clé admin partout. +- **Tags d'image** : Épinglez la version dans vos manifestes de release (par exemple, `server:v0.0.1-beta.48`) en production plutôt qu'un tag flottant pour éviter les mises à niveau non intentionnelles. Les builds bêta actuels publient sous `beta-latest` ; `latest` n'est attribué qu'aux versions stables. +- **Surveillance de la santé** : Sur Kubernetes, la sonde de readiness utilise `/ready` (accessibilité Postgres + ClickHouse) tandis que la liveness reste sur `/health`. Pour les alertes Slack à l'échelle de la flotte sur l'état d'AgentEye, activez le module complémentaire Robusta optionnel ; voir [enterprise-docs/health-monitoring.md](/fr/agenteye/health-monitoring). + +--- + +## Tags d'image disponibles + +| Tag | Description | +|-----|-------------| +| `latest` | Dernière version stable | +| `beta-latest` | Dernière pré-version (bêta) | +| `v` | Version épinglée, ex. `v0.0.1-beta.48` (recommandé pour la production) | \ No newline at end of file diff --git a/docs/fr/agenteye/evaluation-suite.mdx b/docs/fr/agenteye/evaluation-suite.mdx new file mode 100644 index 00000000..8470572b --- /dev/null +++ b/docs/fr/agenteye/evaluation-suite.mdx @@ -0,0 +1,357 @@ +--- +title: "Suite d'évaluation" +description: "Documentation de la suite d'évaluation AgentEye." +--- + + +AgentEye évalue les sessions d'agents terminées en envoyant par POST la transcription complète des événements à un **service d'évaluation appartenant au client**. L'évaluateur retourne les scores directement en réponse ou en transmettant un `job_id` qu'AgentEye peut interroger. Les résultats sont stockés et affichés dans le tableau de bord. + +Ce guide couvre : + +1. Comment la fin de session est détectée. +2. Le contrat HTTP que l'évaluateur doit implémenter. +3. La configuration du serveur AgentEye. +4. La consultation des résultats. +5. Le dépannage. + +Pour le module Python qui implémente ce contrat à votre place, consultez le +[package `agenteye-evaluator` sur PyPI](https://pypi.org/project/agenteye-evaluator/). + +--- + +## Fonctionnement + +```text +ingest /events ──▶ AgentEye ──── POST /evaluate ────▶ Service évaluateur + (agent_end) server ◀──── done | pending ──── + │ + │ GET /evaluate/{job_id} ─────▶ + │ ◀──── done ────────────── + ▼ + evaluations (résultats terminaux) +``` + +Lorsque le SDK AgentEye émet un événement `agent_end` pour une session, le serveur planifie une évaluation. Il envoie ensuite par POST la transcription complète des événements à votre service d'évaluation, qui peut : + +- **Retourner le résultat directement** avec `{"status":"done", "scores":{...}, "reasoning":{...}, "summary":"..."}`. Le résultat est ajouté à la chronologie d'évaluation de la session. `reasoning` et `summary` sont facultatifs. +- **Différer** avec `{"status":"pending", "job_id":"abc-123"}`. AgentEye appelle alors `GET {EVALUATOR_ENDPOINT}/evaluate/abc-123` jusqu'à ce que votre évaluateur retourne `{"status":"done", ...}` ou `{"status":"error", "error":"..."}`. + + La cadence d'interrogation est définie par tâche : une réponse `pending` peut inclure `next_poll_secs` pour la remplacer ; sinon AgentEye utilise la valeur `default_poll_interval_secs` de `GET /config` ; à défaut, le serveur revient à `EVALUATOR_POLLING_INTERVAL_SECS` (par défaut 10 s). Toutes les valeurs sont limitées à [1 s, 1 h]. + +Les sessions qui n'émettent jamais `agent_end` (par exemple, un processus d'agent planté) peuvent également être traitées : le `GET /config` de l'évaluateur peut retourner `{"inactivity_timeout_secs": 1800}`, et AgentEye évaluera toute session inactive depuis ce délai. Définissez le champ à `null` ou omettez-le pour désactiver ce mécanisme de secours. + +Le pipeline est entièrement sans effet lorsque `EVALUATOR_ENDPOINT` n'est pas défini. + +Une session peut accumuler **plusieurs évaluations terminales au fil du temps** : chaque événement `agent_end` (et chaque réévaluation manuelle depuis le tableau de bord) ajoute une nouvelle ligne d'évaluation. C'est la méthode recommandée pour évaluer une conversation reprise : un utilisateur termine un agent, revient plus tard, envoie de nouveaux événements, termine à nouveau l'agent, et une deuxième évaluation est exécutée sur la transcription complète mise à jour. Le tableau de bord affiche l'évaluation la plus récente en titre et les évaluations précédentes dans une chronologie rétractable. Pendant qu'une évaluation est en cours pour une session, les événements `agent_end` supplémentaires pour cette session sont ignorés ; le suivant, après la fin de l'évaluation en cours, mettra en file d'attente une nouvelle évaluation normalement. + +Le mécanisme de secours d'inactivité s'applique également aux sessions reprises : si de nouveaux événements arrivent après une évaluation terminale précédente et que la session devient ensuite inactive au-delà de `inactivity_timeout_secs`, une nouvelle évaluation est mise en file d'attente. + +Les échecs transitoires (5xx, 429, délais d'expiration, erreurs réseau) sont réessayés avec un recul exponentiel jusqu'à `EVALUATOR_MAX_ATTEMPTS` ; les réponses 4xx sont terminales. AgentEye peut être exécuté avec plusieurs instances de serveur mises à l'échelle horizontalement ; le travail est partitionné de sorte que la même session ne soit jamais traitée deux fois simultanément. + +--- + +## Contrat HTTP + +Chaque route authentifiée utilise **l'authentification par jeton Bearer**. La même valeur doit être configurée des deux côtés : + +- Serveur AgentEye : variable d'environnement `EVALUATOR_TOKEN` +- Service d'évaluation : configuré de la même manière (le SDK `agenteye-evaluator` lit `EVALUATOR_TOKEN` par convention) + +Si `EVALUATOR_TOKEN` n'est pas défini, le serveur n'envoie pas d'en-tête `Authorization` ; l'évaluateur peut alors accepter des requêtes anonymes, ce qui convient pour un réseau interne uniquement, mais est déconseillé sur l'internet public. + +### Routes que l'évaluateur doit exposer + +| Route | Corps / paramètres | Réponse | +|---|---|---| +| `GET /health` | aucun | `{"status":"ok"}` (ouvert, sans authentification) | +| `GET /config` | aucun | `{"inactivity_timeout_secs": \| null, "default_poll_interval_secs": \| omitted}` | +| `POST /evaluate` | JSON `EvalRequest` | `{"status":"done", ...}` ou `{"status":"pending", "job_id":"..."}` | +| `GET /evaluate/{id}` | aucun | même forme de réponse que `/evaluate` | + +### Corps `EvalRequest` envoyé par le serveur + +```json +{ + "schema_version": "1", + "session_id": "session-abc123", + "agent_id": "planner", + "environment": "production", + "started_at": "2026-05-10T12:00:00Z", + "ended_at": "2026-05-10T12:05:00Z", + "events": [ + { "id": 1234, "ts": "...", "event_type": "agent_start", "payload": { ... } }, + ... + ] +} +``` + +### Formes de réponse + +**Synchrone (done) :** + +```json +{ + "status": "done", + "scores": { "helpfulness": 0.85, "tool_efficiency": 0.6 }, + "reasoning": { + "helpfulness": "answered the question directly with citations", + "tool_efficiency": "called list_files three times when one would have done" + }, + "summary": "strong answer quality, weak tool selection" +} +``` + +`reasoning` (une carte de justification par score) et `summary` (un récit global en un paragraphe) sont tous deux facultatifs. Les clés de `reasoning` doivent correspondre aux clés de `scores` ; le tableau de bord affiche chaque entrée sous sa barre de score. Les évaluateurs plus anciens qui ne retournent que `scores` continuent de fonctionner sans modification ; `reasoning` et `summary` sont simplement lus comme null et les fonctionnalités d'interface correspondantes sont omises. + +**Asynchrone (différé) :** + +```json +{ "status": "pending", "job_id": "abc-123", "next_poll_secs": 30 } +``` + +`next_poll_secs` est facultatif ; s'il est omis, le serveur revient au `default_poll_interval_secs` de l'évaluateur depuis `/config`, puis à sa propre variable d'environnement `EVALUATOR_POLLING_INTERVAL_SECS`. + +**Erreur terminale côté évaluateur :** + +```json +{ "status": "error", "error": "model service unavailable" } +``` + +Le serveur traite tout autre corps 2xx comme une erreur de protocole et enregistre une `error` terminale pour la session. + +--- + +## Écrire un évaluateur avec le SDK + +Le package Python `agenteye-evaluator` vous fournit un wrapper FastAPI typé qui implémente le contrat HTTP ci-dessus. Installez-le depuis PyPI : + +```bash +pip install agenteye-evaluator +``` + +Évaluateur minimal viable : + +```python +import os +from agenteye_evaluator import Evaluator, EvalRequest, EvalResponse + +app = Evaluator(token=os.environ["EVALUATOR_TOKEN"]) + +@app.evaluator +def run(req: EvalRequest) -> EvalResponse: + # Inspectez req.events (la transcription complète de la session) et retournez des scores. + tool_calls = sum(1 for e in req.events if e.event_type == "tool_use") + return EvalResponse( + scores={"tool_calls": float(tool_calls)}, + reasoning={"tool_calls": f"{tool_calls} tool invocations in the transcript"}, + summary="tight tool loop" if tool_calls < 5 else "agent looped on tools", + ) +``` + +L'instance `app` est appelable en ASGI, donc `uvicorn module:app` la démarre. + +Pour les évaluateurs qui ont besoin de différer des traitements coûteux, retournez `JobPending` à la place et enregistrez un gestionnaire `@app.job_lookup` ; le serveur AgentEye interroge `GET /evaluate/{job_id}` jusqu'à ce que vous retourniez un statut terminal ou que le délai `EVALUATOR_MAX_POLL_DURATION_SECS` (par défaut 1 h) soit écoulé. + +Référence complète de l'API, modèle asynchrone et schéma des événements : le README de `agenteye-evaluator` est inclus dans chaque archive de version sur la [page des versions agenteye-enterprise](https://github.com/agenteye-enterprise/releases), ou vous pouvez le consulter sur la page PyPI du package. + +--- + +## Déployer un évaluateur sur Kubernetes + +L'évaluateur est **votre service** : AgentEye ne fournit pas de conteneur d'évaluation par défaut. La version inclut des manifestes Kubernetes de référence sous `deploy/examples/evaluator/` que vous pouvez appliquer tels quels après avoir remplacé votre image et un jeton Bearer partagé. + +### 1. Conteneuriser votre évaluateur + +Un Dockerfile minimal pour votre évaluateur : + +```dockerfile +FROM python:3.12-slim +WORKDIR /app +RUN pip install --no-cache-dir agenteye-evaluator uvicorn +COPY my_evaluator.py . +RUN useradd --uid 10001 --create-home --shell /usr/sbin/nologin evaluator \ + && chown -R evaluator:evaluator /app +USER evaluator +EXPOSE 9000 +CMD ["uvicorn", "my_evaluator:app", "--host", "0.0.0.0", "--port", "9000"] +``` + +`runAsNonRoot` (UID 10001) rend le conteneur compatible avec les profils de sécurité restreints des Pods. + +### 2. Créer le jeton Bearer partagé + +```bash +kubectl -n agenteye create secret generic evaluator-token \ + --from-literal=token="$(openssl rand -hex 32)" +``` + +Utilisez la même valeur que `EVALUATOR_TOKEN` sur le serveur AgentEye. Le serveur envoie `Authorization: Bearer ` à chaque requête ; le SDK utilise `hmac.compare_digest` pour une vérification en temps constant et rejette les discordances avec HTTP 401. + +### 3. Appliquer les manifestes d'exemple + +```bash +# Éditez d'abord deploy/examples/evaluator/deployment.yaml pour pointer +# `image:` vers votre registre, puis : +kubectl apply -k deploy/examples/evaluator/ +``` + +L'exemple comprend : + +- Un Deployment à 2 répliques avec `runAsNonRoot`, système de fichiers racine en lecture seule, toutes les capacités supprimées, liveness + readiness sur `/health` +- Un Service ClusterIP sur le port 9000 +- Un modèle `secret.example.yaml` (intentionnellement exclu de la Kustomization ; créez le vrai secret hors bande afin qu'aucun jeton ne se retrouve dans git) + +### 4. Connecter AgentEye au service + +Sur le serveur AgentEye, définissez : + +```bash +EVALUATOR_ENDPOINT=http://evaluator:9000 +EVALUATOR_TOKEN= +``` + +Le serveur distribue `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH` requêtes concurrentes sur tous les pods de l'évaluateur (valeurs par défaut : `2 × 4 = 8`). Ajustez `replicas` et les limites de ressources par pod en accord avec ces paramètres côté serveur. + +### Vérification + +```bash +kubectl -n agenteye port-forward svc/evaluator 9000:9000 +curl -s http://localhost:9000/health # → {"status":"ok"} +``` + +Après l'exécution complète d'un agent, `GET /evaluations` sur le serveur AgentEye devrait retourner une ligne avec `status: "done"` et les scores produits par votre évaluateur. + +--- + +## Configurer le serveur AgentEye + +À définir sur le processus serveur : + +| Variable d'environnement | Signification | +|---|---| +| `EVALUATOR_ENDPOINT` | URL de base de votre évaluateur (`http://evaluator:9000`). Non définie = pipeline désactivé. | +| `EVALUATOR_TOKEN` | Jeton Bearer. Doit être identique à la valeur configurée sur le service d'évaluation. | +| `EVALUATOR_WORKERS` | Tâches de travail par instance de serveur (par défaut 2). | +| `EVALUATOR_CLAIM_BATCH` | Lignes réclamées par tick de travail (par défaut 4). Les lots sont traités **de manière concurrente** ; la concurrence effective sur votre endpoint d'évaluation est `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH`. | +| `EVALUATOR_POLL_IDLE_SECS` | Durée de veille d'un worker entre les tentatives de distribution lorsqu'aucune évaluation n'est due (par défaut 2 s). | +| `EVALUATOR_POLLING_INTERVAL_SECS` | Dernier recours pour la cadence de `GET /evaluate/{id}` quand ni `next_poll_secs` par réponse ni `default_poll_interval_secs` de l'évaluateur ne sont définis (par défaut 10 s). | +| `EVALUATOR_REQUEST_TIMEOUT_MS` | Délai d'expiration par requête (par défaut 30000). | +| `EVALUATOR_MAX_ATTEMPTS` | Après ce nombre d'échecs transitoires, le résultat est enregistré comme `error` terminal (par défaut 5). | +| `EVALUATOR_CONFIG_REFRESH_SECS` | Cadence de `GET /config` (par défaut 300). | +| `EVALUATOR_MAX_POLL_DURATION_SECS` | Durée maximale en temps réel pendant laquelle une session peut rester dans la file d'interrogation avant d'être terminée avec le statut `timeout` (par défaut 3600 s). Protège contre un évaluateur qui retourne indéfiniment `pending`. | + +Pour activer la notation automatique sur l'ensemble de l'instance, provisionnez le Secret `agenteye-evaluator` avec les deux clés définies. Dans les manifestes Kubernetes fournis, le serveur lit `EVALUATOR_ENDPOINT` et `EVALUATOR_TOKEN` depuis ce Secret optionnel. Créez-le via le processus de gestion des secrets standard de votre organisation, puis redémarrez le Deployment du serveur pour prendre en compte le changement. + +Les paramètres de réglage ci-dessus ne sont pas câblés par défaut ; exposez les variables d'environnement correspondantes sur le conteneur serveur dans votre manifeste Deployment si vous devez remplacer les valeurs par défaut. + +Consultez [deployment.md](/fr/agenteye/deployment) pour le tableau complet des variables d'environnement. + +--- + +## Référence API + +| Méthode | Chemin | Permission requise | Objectif | +|---|---|---|---| +| `GET` | `/evaluations` | `evaluations:read` | Interroger les résultats terminaux. Supporte `session_id`, `agent_id`, `environment`, `status` (`done`/`error`/`timeout`), `ts_from`, `ts_to`, `cursor`, `limit`, `score_filters`, `latest_per_session`. `limit` est par défaut à 50 et plafonné à 200 (à noter, différent de `/events` qui plafonne à 1000). `environment` accepte une liste séparée par des virgules (ex. `environment=prod,staging`) ; les valeurs uniques fonctionnent toujours. Avec `latest_per_session=true`, la réponse contient au plus une ligne par `session_id` (la plus récente par `completed_at`), utilisée par la page de liste des sessions pour réduire la chronologie d'évaluation d'une session à son titre actuel. Par défaut false (retourne l'historique complet). | +| `GET` | `/evaluations/aggregate` | `evaluations:read` | Santé agrégée des évaluations pour une tranche filtrée : nombre total, répartition done/error/timeout, statistiques par clé de score (count/avg/min/max/p50 sur les clés `scores` arbitraires), et une chronologie par intervalle de temps. Accepte les **mêmes paramètres de filtre que `/evaluations`** plus `featured_keys` (CSV de clés de score à suivre) et `latest_per_session`. Alimente la fonctionnalité Dashboards ; les métriques sont exactes sur l'ensemble correspondant, sans échantillonnage. | +| `GET` | `/evaluations/environments` | `evaluations:read` | Valeurs d'environnement distinctes de la table `evaluations`. Utilisé pour remplir les menus déroulants de filtres limités aux données accessibles en lecture d'évaluation. | +| `GET` | `/evaluation-jobs` | `evaluations:read` | Visibilité sur les évaluations en cours. Filtrage par `status` (`pending`/`polling`). | +| `GET` | `/events` | `events:read` | Diffuser les événements bruts d'une session. Supporte `session_id`, `agent_id`, `event_type` (CSV), `environment` (CSV), `ts_from`, `ts_to`, `cursor`, `limit` et `order`. `order` est `desc` (les plus récents en premier, par défaut) ou `asc` (les plus anciens en premier) ; une valeur non reconnue revient à `desc`. Paginez par curseur via le `next_cursor` de la réponse (un id d'événement) : transmettez-le en tant que `cursor` pour obtenir la page suivante ; avec `asc` la page suivante contient les événements après cet id, avec `desc` les événements avant lui. `limit` est par défaut à 50 et plafonné à 1000. | +| `GET` | `/sessions/:session_id/export` | `events:read` | Retourne le corps JSON exact que l'évaluateur recevrait pour cette session, servi en tant que pièce jointe téléchargeable nommée `session-.json`. Utile pour rejouer des sessions de production via `agenteye-evaluator` pour des tests hors ligne. Les octets sont identiques à ce qu'envoie le pipeline d'évaluation. | +| `POST` | `/sessions/:session_id/re-evaluate` | `evaluations:trigger` | Met en file d'attente une nouvelle évaluation pour une session ; s'exécute qu'une évaluation précédente existe ou non. Le nouveau résultat est **ajouté** à la chronologie d'évaluation de la session plutôt que d'écraser le précédent, de sorte que les scores antérieurs restent visibles en tant qu'historique. Retourne `202` à la mise en file d'attente, `404` pour une session inconnue, `409` si une évaluation est déjà en cours. Utilisez-le après le déploiement d'un nouvel évaluateur, ou pour des sessions qui n'ont jamais émis `agent_end`. | + +### Filtrage par plage de score : `score_filters` + +`GET /evaluations` accepte un paramètre optionnel `score_filters` qui restreint les résultats par valeurs numériques dans l'objet `scores`. Le paramètre est une liste séparée par des virgules d'entrées `key:min..max` ; l'une ou l'autre borne peut être omise. Plusieurs entrées se combinent avec un ET logique. Les lignes où la clé nommée est absente ou non numérique sont exclues. Une requête peut contenir au maximum 20 entrées de filtre ; dépasser ce nombre retourne HTTP 400. + +Exemples : +```text +# helpfulness dans [0.5, 0.8] +GET /evaluations?score_filters=helpfulness:0.5..0.8 + +# tool_efficiency au maximum 0.3 (pas de borne inférieure) +GET /evaluations?score_filters=tool_efficiency:..0.3 + +# helpfulness >= 0.5 ET factuality >= 0.9 +GET /evaluations?score_filters=helpfulness:0.5..,factuality:0.9.. +``` + +Chaque objet de réponse `/evaluations` possède ces champs : + +| Champ | Type | Notes | +|---|---|---| +| `evaluation_id` | string (UUID) | L'identifiant canonique de cette évaluation terminale. Chaque évaluation terminale reçoit un nouvel UUID ; une seule session peut en contenir plusieurs. | +| `id` | string (UUID) | Alias de compatibilité ascendante portant la même valeur que `evaluation_id`. | +| `session_id` | string | La session contre laquelle cette évaluation a été exécutée. Une session peut avoir plusieurs évaluations dans la chronologie. | +| `agent_id` | string | Identifie l'agent qui a produit la session. | +| `environment` | string | Étiquette d'environnement copiée depuis la session. | +| `status` | enum | L'une de `"done"`, `"error"`, `"timeout"`. | +| `scores` | object \| null | Scores retournés par votre évaluateur. | +| `reasoning` | object \| null | Carte de justification par score optionnelle retournée par votre évaluateur. Les clés correspondent généralement à celles de `scores`. Le tableau de bord affiche chaque entrée sous sa barre de score. | +| `summary` | string \| null | Récit global optionnel en un paragraphe retourné par votre évaluateur. Le tableau de bord l'affiche au-dessus de la décomposition par score en tant que titre de l'évaluation. | +| `error` | string \| null | Renseigné uniquement pour `"error"` / `"timeout"`. | +| `attempt_count` | integer | Nombre de tentatives de distribution (≥ 1). | +| `duration_ms` | integer \| null | Durée de la dernière tentative. | +| `completed_at` | string (ISO 8601 UTC) | Moment où le résultat terminal a été enregistré. Les résultats sont classés par `completed_at` (les plus récents en premier). | +| `created_at` | string (ISO 8601 UTC) | Porte le même horodatage que `completed_at` (sémantique d'écriture unique). | + +--- + +## Permissions + +| Permission | Accorde | +|---|---| +| `evaluations:read` | Lister les résultats d'évaluation, afficher les scores dans le tableau de bord et charger les métriques de santé du tableau de bord. | +| `evaluations:trigger` | Mettre en file d'attente manuellement une évaluation pour une session via `POST /sessions/:session_id/re-evaluate` ou le bouton de réévaluation du tableau de bord. | +| `dashboards:read` | Afficher les tableaux de bord sauvegardés (nécessite également `evaluations:read` pour charger leurs métriques). | +| `dashboards:write` | Créer et modifier des tableaux de bord. | +| `dashboards:delete` | Supprimer des tableaux de bord. | + +L'administrateur bootstrap (`ADMIN_KEY`, `ADMIN_EMAIL`) reçoit automatiquement toutes ces permissions. + +--- + +## Consulter les résultats + +- **`/sessions/`** : chronologie des événements + un panneau latéral droit affichant les scores de la session et toute erreur issue de la tentative de distribution. Si votre clé dispose de `evaluations:trigger`, un bouton **re-evaluate** apparaît à côté du bouton d'export, utile pour les sessions qui n'ont jamais émis `agent_end`, ou pour rafraîchir les scores après le déploiement d'un nouvel évaluateur. Le tableau de bord interroge le nouveau résultat et met à jour le panneau latéral droit lorsqu'il est disponible. +- **`/sessions`** : grille de sessions filtrable ; la colonne de score affiche le statut d'évaluation et les scores de chaque session en un coup d'œil. +- **`/dashboards`** : vues de santé d'évaluation sauvegardées (voir [Dashboards](#dashboards) ci-dessous). + +![La grille Sessions avec des pastilles de statut d'évaluation par session et des badges de score codés par couleur (helpfulness, factuality, tool_efficiency, safety, coherence)](/agenteye/images/sessions-list.png) + +*La grille des sessions affiche le statut d'évaluation et les scores de chaque exécution en un coup d'œil ; les badges rouge/orange/vert font ressortir les scores faibles.* + +![Une vue détaillée de session avec les scores d'évaluation et le statut de distribution dans le panneau latéral droit](/agenteye/images/session-detail.png) + +*L'ouverture d'une session affiche sa chronologie complète aux côtés des scores d'évaluation et de toute erreur du distributeur dans le panneau latéral droit.* + +--- + +## Dashboards + +La page **Dashboards** (`/dashboards`) vous permet de sauvegarder une combinaison de filtres d'évaluation en tant que vue nommée et réutilisable, et de surveiller l'état de cette tranche d'évaluations en un coup d'œil. Les tableaux de bord sont **partagés dans toute votre organisation** ; toute personne disposant de `dashboards:read` voit le même ensemble. + +Chaque tableau de bord fixe : + +- **Les filtres** : les mêmes contrôles que la page des sessions : environnement, statut, agent, une fenêtre temporelle glissante et des filtres de plage de score (`key:min..max`). +- **Une configuration d'affichage** : quelles clés de score mettre en avant, les seuils de santé vert/orange/rouge, quels panneaux afficher et si l'on doit réduire à la dernière évaluation par session. + +Chaque carte affiche le nombre de sessions correspondantes, une répartition done/error/timeout, la moyenne de chaque score mis en avant et une petite sparkline de tendance. L'ouverture d'un tableau de bord affiche les panneaux en taille réelle ; **"ouvrir dans les sessions"** vous amène sur la page des sessions pré-filtrée sur exactement cette tranche. Les métriques sont calculées côté serveur sur l'ensemble correspondant (via `GET /evaluations/aggregate`), donc les chiffres sont exacts plutôt qu'échantillonnés. + +![Un tableau de bord de santé d'évaluation avec des barres de score moyen par dimension d'évaluateur, une répartition ok/erreur des outils, les principaux outils et une tendance des événements par heure](/agenteye/images/dashboard-quality.png) + +**Permissions :** la consultation nécessite à la fois `dashboards:read` et `evaluations:read` ; la création et la modification nécessitent `dashboards:write` ; la suppression nécessite `dashboards:delete`. L'administrateur bootstrap reçoit toutes ces permissions automatiquement. + +--- + +## Dépannage + +**Des sessions existent mais aucune évaluation n'est créée.** Vérifiez que `EVALUATOR_ENDPOINT` est défini sur le processus serveur, que le serveur et l'évaluateur partagent la même valeur `EVALUATOR_TOKEN`, et que l'endpoint `/health` de l'évaluateur est accessible depuis le serveur. Si `EVALUATOR_ENDPOINT` n'est pas défini, le pipeline est sans effet. + +**Les évaluations en cours s'accumulent.** Interrogez `GET /evaluation-jobs` pour voir la file d'attente en cours. Inspectez `attempt_count`, `next_attempt_at` et `last_error` sur chaque ligne. Causes courantes : service d'évaluation inaccessible ou retournant 5xx (réessayé avec recul), mauvais `EVALUATOR_TOKEN` (401 est terminal), ou évaluateur asynchrone retournant `pending` indéfiniment (voir ci-dessous). + +**Les sessions sont terminées mais aucune évaluation terminale n'existe.** Interrogez `GET /evaluation-jobs?status=polling` ; le résultat peut encore être en cours. Si une tâche est bloquée en `pending`, le serveur a du mal à atteindre l'évaluateur ; vérifiez que l'évaluateur est opérationnel et que `EVALUATOR_TOKEN` correspond. + +**`HTTP 401 from evaluator: invalid bearer token`.** Le `EVALUATOR_TOKEN` sur le serveur ne correspond pas à la valeur configurée sur le service d'évaluation. Ils doivent être identiques. + +**L'évaluateur asynchrone retourne `pending` indéfiniment.** Le serveur interroge `GET /evaluate/{job_id}` jusqu'à ce que l'évaluateur retourne `done` ou `error`, ou jusqu'à l'expiration de `EVALUATOR_MAX_POLL_DURATION_SECS` (par défaut 1 h). Passé ce délai, l'évaluation est enregistrée comme `timeout` et retirée de la file d'attente en cours. Augmentez `EVALUATOR_MAX_POLL_DURATION_SECS` si votre évaluateur a légitimement besoin de plus de temps que la valeur par défaut. \ No newline at end of file diff --git a/docs/fr/agenteye/getting-started.mdx b/docs/fr/agenteye/getting-started.mdx new file mode 100644 index 00000000..5d669ed7 --- /dev/null +++ b/docs/fr/agenteye/getting-started.mdx @@ -0,0 +1,235 @@ +--- +title: "Démarrer avec AgentEye" +description: "Documentation de démarrage avec AgentEye." +--- + + +Ce guide vous accompagne dans une configuration complète d'AgentEye : déploiement du serveur et du tableau de bord, installation du collecteur sur une machine agent, et instrumentation de votre code d'agent Python. + +--- + +## Qu'est-ce qu'AgentEye ? + +AgentEye est une **plateforme d'observabilité et d'évaluation auto-hébergée pour les agents IA**. Elle enregistre ce que font vos agents — chaque étape d'une exécution — et note automatiquement la qualité de chaque exécution terminée, afin que vous puissiez observer le comportement de vos agents en production et détecter les régressions avant vos utilisateurs. + +Les données circulent dans un seul sens : votre code agent émet des **événements** via le **SDK Python** → un daemon **collecteur** léger les regroupe et les envoie au **serveur** → les événements et les analyses sont stockés dans **ClickHouse** (l'état opérationnel, comme les organisations, les utilisateurs, les clés API, les tableaux de bord et les requêtes sauvegardées, est conservé dans **Postgres**) → vous explorez tout depuis le **tableau de bord**. + +Ce que vous obtenez : + +- **Événements** — la trace brute, étape par étape, de chaque exécution d'agent (appels d'outils, appels de modèles, hooks, erreurs). +- **Sessions** — ces événements regroupés en une ligne par exécution, chacune **évaluée et notée automatiquement**. +- **Évaluations** — scores de qualité produits par vos propres services d'évaluation, afin que les baisses de qualité remontent sans révision manuelle. +- **Requêtes et tableaux de bord** — SQL ClickHouse sauvegardé sur vos données, visualisé dans des tableaux de bord partagés à l'échelle de l'organisation. +- **Alertes et incidents** — règles de seuil qui vous notifient (e-mail, Slack, webhook, dans le tableau de bord) et un workflow d'incidents pour les traiter. +- **CLI et assistant IA** — un client terminal (`agenteye`) et un assistant intégré au tableau de bord pour poser des questions en langage naturel. + +Vous faites tourner l'ensemble dans votre propre infrastructure, sous forme d'une stack Docker Compose (ce guide), d'une installation Kubernetes en production, ou d'un pod co-localisé. La suite de ce guide configure la stack Compose de bout en bout. + +--- + +## Étape 1 : S'authentifier + +Tous les artefacts AgentEye sont distribués depuis l'organisation GitHub `agenteye-enterprise`. En tant que développeur entreprise, vous pouvez générer votre propre PAT GitHub. Suivez [enterprise-docs/github-token.md](/fr/agenteye/github-token) pour les étapes exactes et les permissions requises. + +```bash +export AGENTEYE_TOKEN= + +# Authenticate Docker against GHCR +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +--- + +## Étape 2 : Déployer le serveur et le tableau de bord + +Le serveur reçoit les événements des collecteurs et les rend interrogeables ; le tableau de bord est l'endroit où vous les explorez. Les événements ingérés et les analyses résident dans ClickHouse (la base d'analyse requise), tandis que Postgres conserve l'état opérationnel tel que les organisations, les utilisateurs, les clés API, les tableaux de bord et les requêtes sauvegardées. + +**Télécharger le fichier compose publié :** + +```bash +mkdir -p ./agenteye +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + https://raw.githubusercontent.com/agenteye-enterprise/releases/main/docker-compose.yml \ + -o ./agenteye/docker-compose.yml +cd agenteye +``` + +**Définir vos secrets :** + +Créez un fichier `.env` pour que le déploiement ne tourne pas avec le credential `admin` par défaut. Définissez au minimum `ADMIN_KEY` et `POSTGRES_PASSWORD` : + +```bash +POSTGRES_PASSWORD=your-db-password +ADMIN_KEY=your-admin-secret +``` + +Exportez également `ADMIN_KEY` dans votre shell courant pour que les étapes suivantes (par exemple le `curl` de l'étape 3) puissent le référencer directement : + +```bash +export ADMIN_KEY=your-admin-secret +``` + +**Démarrer la stack :** + +```bash +docker compose up -d +``` + +Cela lance la stack complète, incluant la base d'analyse ClickHouse requise et un cache Redis optionnel, aux côtés du serveur et du tableau de bord. ClickHouse doit être opérationnel pour que le serveur puisse démarrer. + +Le serveur écoute désormais sur `http://localhost:8080` et le tableau de bord sur `http://localhost:3000`. + +Pour les déploiements en production (Postgres personnalisé, TLS, reverse proxy), consultez [enterprise-docs/deployment.md](/fr/agenteye/deployment). + +--- + +## Étape 3 : Créer une clé API pour le collecteur + +Chaque collecteur s'authentifie avec une clé API à portée limitée. Utilisez l'`ADMIN_KEY` défini à l'étape 2 pour en créer une : + +```bash +curl -s -X POST http://localhost:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{"name":"prod-collector","key":"your-collector-secret","permissions":["events:add"]}' +``` + +Vous fournissez vous-même la valeur `key` ; utilisez-la dans la configuration du collecteur à l'étape 4. Consultez [enterprise-docs/api-keys.md](/fr/agenteye/api-keys) pour la gestion complète des clés. + +--- + +## Étape 4 : Installer le collecteur + +Sur chaque machine qui exécute vos agents IA, installez le daemon collecteur. + +**Télécharger le binaire (Linux x86_64) :** + +```bash +VERSION=0.0.1-beta.13 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "collector/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-collector-linux-x86_64' +chmod +x agenteye-collector-linux-x86_64 +sudo mv agenteye-collector-linux-x86_64 /usr/local/bin/agenteye-collector +``` + +> Ceci télécharge le build **Linux x86_64**. Pour macOS (Apple Silicon ou Intel), Linux arm64, ou la configuration Docker / systemd / launchd, consultez [collector-installation.md](/fr/agenteye/collector-installation), qui liste les téléchargements pour chaque plateforme — la commande ci-dessus installe un binaire Linux qui ne fonctionnera pas ailleurs. + +**Configurer :** + +```bash +mkdir -p ~/.agenteye +cat > ~/.agenteye/config.json </…`). + +- **Requêtes** (`//queries`) : partez d'une bibliothèque de requêtes sauvegardées et réutilisables sur vos événements et évaluations (préréglages intégrés et les vôtres)… + +![La bibliothèque de requêtes sauvegardées : une grille de requêtes réutilisables, à la fois des préréglages intégrés et des requêtes personnalisées](/agenteye/images/queries.png) + + …puis ouvrez-en une dans le compositeur SQL pour la modifier et l'exécuter avec des résultats en direct : + +![Le compositeur de requêtes SQL exécutant une requête sauvegardée, avec une barre latérale de schéma et une grille de résultats en direct](/agenteye/images/query-lab.png) + +- **Tableaux de bord** (`//dashboards`) : épinglez des requêtes sous forme de tuiles en courbe, barres, aires ou secteurs dans des tableaux de bord partagés à l'échelle de l'organisation. + +![Un tableau de bord construit à partir de requêtes sauvegardées : une courbe d'événements par heure, un graphique en barres d'erreurs par type, un graphique en aires de latence, et les tokens par modèle](/agenteye/images/dashboard-fleet.png) + +- **Alertes** (`//alerts`) : transformez n'importe quel seuil en règle de notification par e-mail, Slack, webhook ou dans le tableau de bord. Consultez [enterprise-docs/alerts.md](/fr/agenteye/alerts). + +--- + +## Étapes suivantes + +- [Déploiement](/fr/agenteye/deployment) : renforcer pour la production +- [Clés API](/fr/agenteye/api-keys) : gérer les accès +- [Dépannage](/fr/agenteye/troubleshooting) : diagnostiquer les problèmes \ No newline at end of file diff --git a/docs/fr/agenteye/github-token.mdx b/docs/fr/agenteye/github-token.mdx new file mode 100644 index 00000000..6bd4787b --- /dev/null +++ b/docs/fr/agenteye/github-token.mdx @@ -0,0 +1,131 @@ +--- +title: "Configuration du token GitHub" +description: "Documentation de configuration du token GitHub pour AgentEye." +--- + +Un token d'accès personnel (PAT) GitHub est le seul identifiant nécessaire pour accéder à tous les artefacts AgentEye. Avec un seul token, vous pouvez récupérer les images Docker, télécharger les binaires de version et installer les wheels Python, sans connexion par composant ni secrets partagés à faire circuler. Tous les artefacts AgentEye sont distribués depuis l'organisation GitHub `agenteye-enterprise` ; une fois l'accès accordé à votre organisation, chaque développeur ou opérateur génère et renouvelle son propre token, ce qui garantit un accès traçable et révocable par personne. + +Définissez le token comme variable d'environnement et identifiant Docker une fois par machine : + +```bash +export AGENTEYE_TOKEN= +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +> **Remarque sur le nom d'utilisateur :** GHCR ignore le nom d'utilisateur fourni à `docker login` et s'authentifie entièrement depuis le token, donc n'importe quelle valeur non vide fonctionne. Cette documentation utilise `-u x` par souci de concision ; les manifestes de déploiement qui créent un secret d'extraction d'image Kubernetes peuvent utiliser un nom d'utilisateur plus descriptif comme `agenteye-enterprise`. Les deux sont acceptés. + +--- + +## Option A : Token classique (recommandée) + +Un token classique est le choix le plus fiable pour AgentEye, car le flux `docker login` et d'extraction d'image de GHCR offre le support le plus large et le plus cohérent pour les tokens classiques. Deux portées couvrent tout ce dont vous avez besoin (extraction d'images et téléchargement d'assets de version), vous vous authentifiez une seule fois et pouvez avancer sans avoir à résoudre des problèmes de registre. L'une d'elles, `read:packages`, est véritablement en lecture seule ; l'autre, `repo`, est la seule portée classique qui accorde l'accès aux assets de version privés, et elle est délibérément large — GitHub la définit comme le contrôle total (lecture et écriture) des dépôts privés. + +### 1. Créer le token + +Accédez à **GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic) → Generate new token (classic)**. + +| Champ | Valeur | +|---|---| +| **Note** | `agenteye-` (ex. : `agenteye-prod-server`) | +| **Expiration** | Définissez une expiration adaptée à votre politique de sécurité ; 90 jours est une valeur par défaut raisonnable | + +> **Remarque sur l'étiquette :** GitHub nomme ce champ **Note** pour les tokens classiques et **Token name** pour les tokens à portée fine. Ils ont le même objectif : un identifiant lisible par l'humain pour faciliter les audits et les révocations ultérieurs. + +### 2. Sélectionner les portées + +| Portée | Raison | +|---|---| +| `read:packages` | Extraction des images Docker depuis `ghcr.io/agenteye-enterprise/` et téléchargement des assets de packages | +| `repo` | Lecture du contenu des dépôts privés, des fichiers bruts et des assets de version depuis `agenteye-enterprise/releases`. Il s'agit de la portée GitHub large intitulée « Full control of private repositories » (lecture et écriture), et non d'une portée en lecture seule — c'est simplement la seule portée classique qui accorde l'accès aux assets de version privés | + +Aucune autre portée n'est requise. + +### 3. Générer et copier le token + +Cliquez sur **Generate token** et copiez la valeur immédiatement ; elle n'est affichée qu'une seule fois. Stockez-la dans votre gestionnaire de secrets ou dans votre environnement. + +--- + +## Option B : Token à portée fine + +Les tokens à portée fine limitent l'accès à des dépôts et des permissions spécifiques, ce qui en fait l'option la plus stricte selon le principe du moindre privilège. Choisissez cette voie lorsque la politique de sécurité de votre organisation impose l'utilisation de tokens à portée fine. + +> **Remarque :** Le support de GHCR pour les tokens à portée fine est moins cohérent que pour les tokens classiques. Si `docker login` ou `docker pull` échoue après avoir suivi ces étapes, revenez à un token classique (Option A). + +### 1. Créer le token + +Accédez à **GitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokens → Generate new token**. + +| Champ | Valeur | +|---|---| +| **Token name** | `agenteye-` (ex. : `agenteye-prod-server`) | +| **Expiration** | Définissez une expiration adaptée à votre politique de sécurité ; 90 jours est une valeur par défaut raisonnable | +| **Resource owner** | `agenteye-enterprise` | +| **Repository access** | **Only select repositories** → `agenteye-enterprise/releases` | + +### 2. Définir les permissions du dépôt + +Sous **Permissions → Repository permissions**, configurez : + +| Permission | Accès | +|---|---| +| **Contents** | Read-only | +| **Packages** | Read-only | + +Toutes les autres permissions peuvent rester sur **No access**. + +> **Remarque :** Si les images de conteneur (`ghcr.io/agenteye-enterprise/...`) sont publiées en tant que packages au niveau de l'organisation plutôt que liés à un dépôt, la connexion Docker peut échouer avec des permissions limitées au dépôt. Dans ce cas, ajoutez une permission au niveau de l'organisation : **Permissions → Organization permissions → Packages: Read-only**. + +### 3. Ce que chaque permission accorde + +| Permission | Utilisée pour | +|---|---| +| Contents: Read-only | Téléchargement de `docker-compose.yml`, des binaires de version et des wheels Python depuis `agenteye-enterprise/releases` | +| Packages: Read-only | Extraction des images Docker depuis `ghcr.io/agenteye-enterprise/` | + +### 4. Générer et copier le token + +Cliquez sur **Generate token** et copiez la valeur immédiatement ; elle n'est affichée qu'une seule fois. Stockez-la dans votre gestionnaire de secrets ou dans votre environnement. + +--- + +## Renouvellement d'un token + +Le renouvellement régulier des tokens maintient l'accès traçable et limite l'impact en cas de fuite d'un identifiant. Les tokens peuvent également expirer ou être révoqués à tout moment, ce qui fait du renouvellement la méthode courante pour rester authentifié. Pour renouveler : + +1. Générez un nouveau token en suivant les étapes ci-dessus. +2. Mettez à jour `AGENTEYE_TOKEN` dans votre environnement ou gestionnaire de secrets. +3. Ré-authentifiez Docker : `echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin` +4. Révoquez l'ancien token dans GitHub → Settings → Developer settings → Personal access tokens, puis ouvrez la sous-page **Tokens (classic)** ou **Fine-grained tokens** correspondant au type du token et supprimez-le. + +--- + +## Vérifier votre token + +Confirmez que le token fonctionne avant de l'intégrer dans un déploiement, afin que les échecs d'authentification apparaissent ici plutôt qu'en cours de déploiement. Chaque commande teste l'une des portées mentionnées ci-dessus : + +```bash +# Packages scope - authenticate Docker against GHCR +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin + +# Contents scope - fetch a raw release file +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + https://raw.githubusercontent.com/agenteye-enterprise/releases/main/docker-compose.yml \ + -o /tmp/agenteye-compose-check.yml +``` + +Un `docker login` réussi confirme la portée packages ; un fichier téléchargé confirme la portée contents. + +--- + +## Résolution des problèmes + +| Symptôme | Cause probable | Correction | +|---|---|---| +| `docker login` retourne 401 | Token sans `Packages: Read-only` (portée fine) ou `read:packages` (classique) | Ajoutez la portée packages et régénérez | +| `curl` retourne 404 sur les URL GitHub brutes | Token sans `Contents: Read-only` ou portée `repo` | Ajoutez la portée contents et régénérez | +| `gh release download` retourne 403 | Token non autorisé pour `agenteye-enterprise/releases` | Vérifiez que le dépôt est inclus dans l'accès aux dépôts du token à portée fine, ou utilisez un token classique avec la portée `repo` | +| Token accepté mais images introuvables | Permission de package au niveau de l'organisation manquante sur le token à portée fine | Ajoutez la permission `Packages: Read-only` au niveau de l'organisation | + +Pour tout problème d'accès, contactez `support@exosphere.host`. \ No newline at end of file diff --git a/docs/fr/agenteye/health-monitoring.mdx b/docs/fr/agenteye/health-monitoring.mdx new file mode 100644 index 00000000..7f61e045 --- /dev/null +++ b/docs/fr/agenteye/health-monitoring.mdx @@ -0,0 +1,95 @@ +--- +title: "Surveillance de l'état de santé" +description: "Documentation de la surveillance de l'état de santé d'AgentEye." +--- + +Sachez quand un déploiement AgentEye est **lui-même** hors service ou dégradé, et pas seulement quand vos agents se comportent mal. La détection est **native Kubernetes** et, point crucial, **indépendante d'AgentEye** : elle lit l'état des pods depuis le plan de contrôle Kubernetes et vérifie les dépendances critiques d'AgentEye, de sorte qu'elle se déclenche même lorsque le serveur, ClickHouse ou Postgres est la cause de la panne. + +Il existe deux niveaux. Le premier est intégré par défaut ; le second est optionnel. + +## 1. Disponibilité tenant compte des dépendances (intégré) + +Le serveur expose deux endpoints de sonde avec des rôles délibérément distincts : + +| Endpoint | Sonde | Vérifie | Auth | +|---|---|---|---| +| `GET /health` | liveness | le processus est actif (toujours `{"status":"ok"}`) | aucune | +| `GET /ready` | readiness | peut réellement servir : **Postgres + ClickHouse** accessibles | aucune | + +`/ready` renvoie `200` avec `"status":"ready"` et chaque vérification à `"ok"` lorsque les deux dépendances critiques sont accessibles, et `503` avec `"status":"not_ready"` lorsque l'une ou l'autre est inaccessible. Les deux réponses comportent un petit corps : + +```json +{ "status": "not_ready", + "checks": { "postgres": "ok", "clickhouse": "down", "redis": "not_configured" } } +``` + +Redis est un cache optionnel que le serveur peut contourner en mode dégradé ; il est donc signalé à titre informatif mais **ne fait jamais** échouer la readiness. Il affiche `"ok"` lorsqu'un cache est configuré et `"not_configured"` dans le cas contraire ; il n'affiche jamais `"down"`. + +Dans les manifestes Kubernetes fournis, la sonde **readiness** pointe vers `/ready` et la sonde **liveness** reste sur `/health`. L'effet est le suivant : un serveur qui *tourne mais ne peut pas atteindre sa base de données* est retiré du Service et apparaît comme `NotReady` — un état sur lequel la surveillance de votre cluster (voir ci-dessous) peut déclencher une alerte — tandis que la liveness reste peu coûteuse, évitant ainsi qu'une brève interruption d'une dépendance ne provoque le redémarrage d'un pod. La sonde utilise un seuil d'échec généreux pour qu'une perturbation momentanée ne fasse pas osciller les réplicas hors de la rotation. + +## 2. Alertes de défaillance de pods avec Robusta (optionnel) + +[Robusta](https://github.com/robusta-dev/robusta) est un moniteur natif Kubernetes qui surveille le serveur API et publie les défaillances de pods (`CrashLoopBackOff`, `OOMKilled`, `ImagePullBackOff`, `Pending`/`NotReady`, `Failed`, évictions) sur Slack. Comme il observe le plan de contrôle plutôt qu'AgentEye lui-même, il émet des alertes même lorsqu'AgentEye ne peut pas répondre du tout. + +Robusta est fourni en tant qu'extension optionnelle dans le bundle de version. Activez-le avec le chart Helm Robusta standard et le petit fichier de valeurs présenté ci-dessous : + +1. Ajoutez le dépôt du chart et obtenez un **token de bot** Slack (`xoxb-…`) pour le canal concerné : + + ```bash + helm repo add robusta https://robusta-charts.storage.googleapis.com + helm repo update + ``` + + Comme la configuration ci-dessous conserve tout en cluster + (`disableCloudRouting: true`), le token provient d'une application Slack auto-hébergée : + créez une application sur `https://api.slack.com/apps`, ajoutez le scope bot `chat:write`, + installez-la dans votre espace de travail, copiez le **Bot User OAuth Token** (`xoxb-…`), puis + invitez le bot dans le canal (`/invite @your-app`). + +2. Créez un fichier `values.yaml` avec un libellé par déploiement (`clusterName`) et votre canal Slack, limité au namespace `agenteye` : + + ```yaml + clusterName: "acme-prod" # libellé par déploiement ; apparaît sur chaque alerte + enablePrometheusStack: false # alertes de crash de pods uniquement ; pas de stack de métriques + disableCloudRouting: true # livraison directe sur Slack, en cluster + sinksConfig: + - slack_sink: + name: vendor_slack + slack_channel: "agenteye-fleet-health" + api_key: "REPLACE_WITH_SLACK_BOT_TOKEN" # xoxb-… (préférer --set ou un secret) + scope: + include: + - namespace: [agenteye] # alertes uniquement pour le namespace AgentEye ; supprimer pour élargir + ``` + +3. Installez en fixant `--version` sur une version connue du chart Robusta + ([versions](https://github.com/robusta-dev/robusta/releases)) afin de ne jamais + installer un chart non testé : + + ```bash + helm install robusta robusta/robusta \ + --namespace robusta --create-namespace \ + --version \ + -f values.yaml \ + --set sinksConfig[0].slack_sink.api_key=$ROBUSTA_SLACK_TOKEN + ``` + +### Ce qui est signalé + +- L'**état des pods** Kubernetes (quel pod AgentEye est en défaillance et pourquoi) ainsi que le **tag d'image** de chaque pod, c'est-à-dire la **version** du composant en cours d'exécution. +- **Aucune donnée d'événement AgentEye ni aucune donnée client** ne quitte jamais le cluster. +- Les valeurs fournies limitent les alertes au **namespace `agenteye`**, de sorte que les autres workloads du même cluster ne sont pas signalés. + +### Un seul endroit pour tous les déploiements + +Pointez le Robusta de chaque déploiement vers **un seul canal Slack partagé**, chacun avec son propre `clusterName`. Chaque alerte est taguée avec ce libellé, de sorte qu'un seul canal affiche l'état de santé de toute votre flotte et que vous puissiez identifier en un coup d'œil quel déploiement est concerné. + +### Pannes totales du cluster + +Un observateur purement en cluster ne peut pas signaler une **panne totale du cluster ou du réseau** (il tombe avec le cluster). Si vous en avez besoin, activez le **sink Robusta UI** optionnel : définissez `disableCloudRouting: false` et ajoutez un `robusta_sink` (avec un token généré par `robusta gen-config`) à `sinksConfig`. Cela ajoute un tableau de bord agrégé multi-cluster et signale tout cluster qui cesse d'envoyer des signaux de vie. + +## Dépannage + +Consultez la section **Surveillance de l'état de santé** de +[enterprise-docs/troubleshooting.md](/fr/agenteye/troubleshooting) pour les cas « aucune +alerte ne parvient » et « le serveur oscille continuellement entre `NotReady` ». \ No newline at end of file diff --git a/docs/fr/agenteye/kubernetes-deployment.mdx b/docs/fr/agenteye/kubernetes-deployment.mdx new file mode 100644 index 00000000..8468ae91 --- /dev/null +++ b/docs/fr/agenteye/kubernetes-deployment.mdx @@ -0,0 +1,1088 @@ +--- +title: "Guide de déploiement Kubernetes" +description: "Documentation du guide de déploiement Kubernetes d'AgentEye." +--- + + +Ce guide déploie la stack complète d'AgentEye sur un cluster Kubernetes dédié : + +- **ClickHouse 24.8** -- store analytique canonique pour les événements et les évaluations (StatefulSet avec volume persistant de 100 Gi). Obligatoire : le serveur refuse de démarrer sans lui. +- **PostgreSQL 16** -- store relationnel/métadonnées pour les organisations, clés API, utilisateurs, tableaux de bord, requêtes sauvegardées et authentification (StatefulSet avec volume persistant de 50 Gi) +- **Redis 7.2** -- cache partagé optionnel et backend de limitation de débit ; le serveur et le tableau de bord se dégradent gracieusement s'il est indisponible +- **Serveur AgentEye** -- API Rust pour l'ingestion d'événements, l'analytique et la gestion des clés (2 réplicas) +- **Tableau de bord AgentEye** -- interface web Next.js (2 réplicas) +- **Assistant IA (service agent)** -- assistant intégré au tableau de bord, en lecture seule, optionnel sur le port 9100 ; inactif tant qu'aucun endpoint LLM n'est configuré +- **Traefik (public)** -- contrôleur d'ingress pour le trafic collecteur, protégé par mTLS +- **Traefik (tableau de bord)** -- contrôleur d'ingress pour le tableau de bord, restreint par VPN/liste d'autorisation d'IP +- **cert-manager** -- certificats TLS et CA mTLS +- **CronJob de sauvegarde** -- dump combiné quotidien de PostgreSQL + ClickHouse à 03:00 UTC +- **Moniteur de renouvellement de certificats** -- alerte lorsque les certificats clients approchent de leur expiration + +**Durée estimée :** 60 à 90 minutes pour un premier déploiement. + +Pour le modèle de déploiement géré où Exosphere s'en charge entièrement en votre nom, voir [enterprise-docs/managed-deployment.md](/fr/agenteye/managed-deployment). + +--- + +## Prérequis + +Exécutez chaque commande de vérification avant de commencer. Chaque vérification doit réussir. + +| Prérequis | Minimum | Commande de vérification | Résultat attendu | +|---|---|---|---| +| Cluster Kubernetes | 1.27+ | `kubectl version` | Server Version >= v1.27 | +| Kustomize (intégré à kubectl) | Kustomize v1.14+ (inclus dans kubectl 1.27+) | `kubectl kustomize --help` | Affiche le texte d'utilisation | +| Helm | v3 | `helm version` | `Version:"v3.x.x"` | +| RBAC cluster-admin | -- | `kubectl auth can-i create namespaces` | `yes` | +| StorageClass par défaut | -- | `kubectl get storageclass` | Au moins une ligne marquée `(default)` | +| Support LoadBalancer | -- | Dépend du cloud (EKS, GKE, AKS le supportent tous par défaut) | -- | +| PAT GitHub | -- | `echo $AGENTEYE_TOKEN` | Non vide (voir [enterprise-docs/github-token.md](/fr/agenteye/github-token)) | +| openssl | -- | `openssl version` | OpenSSL 1.x ou 3.x | +| Bucket de stockage cloud | -- | Pour les sauvegardes PostgreSQL + ClickHouse (S3, GCS ou Azure Blob) | -- | + +**Dimensionnement du cluster :** Minimum 3 nœuds, 4 vCPU / 8 Go de RAM chacun. Voir [enterprise-docs/managed-deployment.md](/fr/agenteye/managed-deployment) pour les exigences complètes. + +### Exécuter toutes les vérifications en une seule fois + +```bash +echo "--- Prerequisites Check ---" +kubectl version --client -o yaml 2>/dev/null | grep -q gitVersion && echo "PASS: kubectl" || echo "FAIL: kubectl not found" +helm version --short 2>/dev/null | grep -q v3 && echo "PASS: helm v3" || echo "FAIL: helm v3 not found" +kubectl auth can-i create namespaces 2>/dev/null | grep -q yes && echo "PASS: cluster-admin" || echo "FAIL: no cluster-admin" +kubectl get storageclass 2>/dev/null | grep -q default && echo "PASS: default StorageClass" || echo "FAIL: no default StorageClass" +[ -n "$AGENTEYE_TOKEN" ] && echo "PASS: AGENTEYE_TOKEN set" || echo "FAIL: AGENTEYE_TOKEN not set" +openssl version >/dev/null 2>&1 && echo "PASS: openssl" || echo "FAIL: openssl not found" +echo "---" +``` + +### Architecture du déploiement + +Le **point de terminaison d'ingestion** est servi sur un nom d'hôte que vous contrôlez (ex. `ingest.votre-entreprise.example`). cert-manager demande un certificat TLS approuvé publiquement auprès de Let's Encrypt via HTTP-01, de sorte que les collecteurs vérifient le certificat serveur par rapport au magasin de confiance du système, sans épinglage de CA par client. + +Le **point de terminaison du tableau de bord** fonctionne de la même façon : il est servi sur un second nom d'hôte que vous contrôlez (ex. `agenteye.votre-entreprise.example`) pointant vers le LoadBalancer Traefik du tableau de bord, et cert-manager émet son certificat Let's Encrypt via ce LoadBalancer. Les navigateurs obtiennent un certificat de confiance sans avertissement. + +> **La délivrance et le renouvellement des certificats se valident via HTTP-01**, donc les deux LoadBalancers doivent être accessibles depuis l'internet public sur le port 80. Si vous devez restreindre l'accès IP au LoadBalancer du tableau de bord, coordonnez d'abord un solveur DNS-01 avec le support — sinon les renouvellements échouent silencieusement et le certificat expire. + +--- + +## Récupérer les manifestes + +```bash +git clone https://x:${AGENTEYE_TOKEN}@github.com/agenteye-enterprise/releases.git +cd releases/deploy +``` + +**Vérification :** + +```bash +ls base/kustomization.yaml +``` + +Résultat attendu : le fichier existe. S'il n'existe pas, le clonage a échoué -- vérifiez votre `AGENTEYE_TOKEN`. + +**Structure des répertoires :** + +``` +deploy/ + base/ Base Kustomize partagée (toutes les ressources K8s) + overlays/ Surcharges spécifiques au cluster (tags d'image, noms d'hôte, ressources) + third-party/ Valeurs Helm pour Traefik, cert-manager et (optionnel) la surveillance santé Robusta +``` + +La **base** contient toutes les ressources nécessaires à un déploiement complet, y compris les certificats Let's Encrypt pour les deux noms d'hôte publics que vous configurez à la Phase 3.1. Un **overlay** surcharge la base pour un environnement spécifique (ex. tags d'image personnalisés, limites de ressources, câblage des variables d'environnement). Le répertoire **third-party** contient les fichiers de valeurs Helm pour l'infrastructure externe. + +> **Surveillance de la santé (optionnel) :** la sonde de disponibilité du serveur reflète déjà la santé de Postgres + ClickHouse, et `third-party/robusta/` ajoute des alertes optionnelles de défaillance de pods Kubernetes-native vers Slack. Voir [enterprise-docs/health-monitoring.md](/fr/agenteye/health-monitoring). + +--- + +## Phase 1 -- Infrastructure tierce (~30 min) + +### 1.1 Installer cert-manager + +cert-manager gère les certificats TLS pour HTTPS et la CA privée utilisée pour les certificats clients mTLS. + +```bash +helm repo add jetstack https://charts.jetstack.io +helm repo update + +helm install cert-manager jetstack/cert-manager \ + --namespace cert-manager --create-namespace \ + --set crds.install=true +``` + +**Vérification :** + +```bash +kubectl get pods -n cert-manager +``` + +Résultat attendu : 3 pods tous `Running` -- `cert-manager`, `cert-manager-cainjector`, `cert-manager-webhook`. + +```bash +kubectl get crds | grep cert-manager +``` + +Résultat attendu : au moins `certificates.cert-manager.io`, `clusterissuers.cert-manager.io`, `issuers.cert-manager.io`. + +**En cas d'échec :** Des pods en `CrashLoopBackOff` indiquent généralement que les CRDs n'ont pas été installés. Relancez avec `--set crds.install=true`. Si les pods webhook échouent à leur sonde de disponibilité, attendez 30 secondes et vérifiez à nouveau -- ils peuvent prendre un moment à démarrer. + +--- + +### 1.2 Installer Traefik -- Contrôleur d'ingestion public + +Cette instance Traefik gère le trafic collecteur sur un LoadBalancer **externe**. Elle termine TLS et applique le mTLS (vérification du certificat client) sur le point de terminaison d'ingestion. + +```bash +helm repo add traefik https://traefik.github.io/charts +helm repo update + +helm install traefik-public traefik/traefik \ + --namespace traefik-public --create-namespace \ + --version 39.0.8 \ + -f third-party/traefik/values-public.yaml +``` + +**Vérification :** + +```bash +kubectl get pods -n traefik-public +``` + +Résultat attendu : 1 pod `Running`. + +```bash +kubectl get ingressclass traefik-public +``` + +Résultat attendu : l'IngressClass existe (ce n'est pas la classe par défaut). + +**En cas d'échec :** Vérifiez `kubectl describe pod -n traefik-public ` pour des erreurs de tirage d'image ou des contraintes de ressources. + +--- + +### 1.3 Installer Traefik -- Contrôleur du tableau de bord + +Cette instance Traefik sert le tableau de bord sur un LoadBalancer dédié, restreint par liste d'autorisation d'IP. + +> **Deux mécanismes de liste d'autorisation sont fournis pour cette instance.** Ce guide utilise `values-dashboard.yaml`, qui restreint l'accès avec le champ portable `service.loadBalancerSourceRanges`. Un `values-internal.yaml` parallèle est également fourni pour les environnements AWS qui préfèrent l'annotation `service.beta.kubernetes.io/aws-load-balancer-source-ranges`. Choisissez l'un et utilisez-le de manière cohérente ; les étapes ci-dessous supposent `values-dashboard.yaml`. + +**Avant d'installer**, modifiez `third-party/traefik/values-dashboard.yaml` pour définir les IP sources autorisées. Le champ `loadBalancerSourceRanges` contrôle quelles IP peuvent accéder au tableau de bord. Par défaut, il est défini à `0.0.0.0/0` (toutes les IP) ; restreignez-le à votre VPN, bureau ou IP de sortie connues. + +#### Autoriser une seule IP + +```yaml +service: + loadBalancerSourceRanges: + - "/32" +``` + +#### Autoriser plusieurs IP + +Ajoutez une entrée par IP ou bloc CIDR. Le suffixe `/32` correspond à une seule adresse IPv4 ; un bloc CIDR (ex. `/24`) correspond à une plage. Vous pouvez mélanger librement des IP individuelles et des plages : + +```yaml +service: + loadBalancerSourceRanges: + - "203.0.113.10/32" # passerelle bureau + - "203.0.113.11/32" # passerelle bureau de secours + - "198.51.100.0/24" # pool VPN + - "192.0.2.50/32" # IP domicile ingénieur d'astreinte +``` + +Conseils pour maintenir la liste : + +- Gardez une entrée par ligne et ajoutez un court commentaire `#` identifiant le propriétaire ou l'objet de chaque IP ; c'est ce que les futurs opérateurs utilisent pour décider si une entrée est toujours nécessaire. +- Utilisez toujours la notation CIDR. Une IP nue comme `203.0.113.10` est rejetée par le fournisseur cloud ; utilisez `203.0.113.10/32`. +- Pour les plages IPv6, utilisez l'équivalent `/128` (adresse unique) ou un CIDR plus grand, ex. `2001:db8::1/128`. Tous les fournisseurs cloud ne supportent pas les plages sources IPv6 ; consultez la documentation LoadBalancer de votre fournisseur. +- La liste est un **OU** : le trafic est autorisé si la source correspond à n'importe quelle entrée. + +Après avoir modifié le fichier, procédez à `helm install` ci-dessous. Si le contrôleur est déjà installé, exécutez `helm upgrade` avec les mêmes options, ou modifiez le Service à l'exécution (section suivante). + +#### Mettre à jour la liste d'autorisation à l'exécution + +Vous pouvez modifier les IP autorisées sans mise à niveau Helm en patchant directement le Service. **Le patch remplace la liste entière** ; incluez toujours chaque IP que vous souhaitez conserver, pas seulement la nouvelle. + +Pour remplacer la liste par un nouvel ensemble d'IP : + +```bash +kubectl patch svc traefik-dashboard -n traefik-dashboard \ + -p '{"spec":{"loadBalancerSourceRanges":["203.0.113.10/32","198.51.100.0/24","192.0.2.50/32"]}}' +``` + +Pour **ajouter** une IP en toute sécurité sans perdre les entrées existantes, lisez d'abord la liste actuelle, puis patchez avec l'ensemble combiné : + +```bash +# 1. Afficher la liste d'autorisation actuelle +kubectl get svc traefik-dashboard -n traefik-dashboard \ + -o jsonpath='{.spec.loadBalancerSourceRanges}' + +# 2. Patcher avec la liste complète incluant la nouvelle IP +kubectl patch svc traefik-dashboard -n traefik-dashboard \ + -p '{"spec":{"loadBalancerSourceRanges":["/32","/32","/32"]}}' +``` + +> Les patches d'exécution ne sont pas répercutés dans `values-dashboard.yaml`. Pour conserver la modification à travers les futures mises à niveau Helm, mettez également à jour le fichier de valeurs et commitez-le. + +Puis installez : + +```bash +helm install traefik-dashboard traefik/traefik \ + --namespace traefik-dashboard --create-namespace \ + --version 39.0.8 \ + -f third-party/traefik/values-dashboard.yaml +``` + +**Vérification :** + +```bash +kubectl get pods -n traefik-dashboard +``` + +Résultat attendu : 1 pod `Running`. + +```bash +kubectl get ingressclass traefik-dashboard +``` + +Résultat attendu : l'IngressClass existe. + +--- + +### 1.4 Attendre les LoadBalancers + +Les deux instances Traefik ont besoin d'IP externes avant de continuer. + +```bash +kubectl get svc -n traefik-public +kubectl get svc -n traefik-dashboard +``` + +**Vérification :** Les deux services affichent une `EXTERNAL-IP` (pas ``). + +Si toujours en attente, surveillez l'attribution : + +```bash +kubectl get svc -n traefik-public -w +``` + +Appuyez sur `Ctrl+C` une fois l'IP apparue. L'attribution d'IP prend généralement 2 à 5 minutes. + +**En cas d'échec :** `` après 10 minutes signifie généralement que le fournisseur cloud ne peut pas provisionner un LoadBalancer. Vérifiez : les tags de sous-réseau (EKS requiert `kubernetes.io/role/elb`), la configuration VPC, les quotas de service, et que l'annotation LB interne correcte est définie pour l'instance interne. + +--- + +## Phase 2 -- Création des secrets (~10 min) + +Tous les secrets sont créés manuellement avant de déployer l'application. Cela garantit que les valeurs sensibles n'apparaissent jamais dans les fichiers de manifeste. + +### 2.1 Créer le namespace + +```bash +kubectl create namespace agenteye +``` + +**Vérification :** + +```bash +kubectl get namespace agenteye +``` + +Résultat attendu : statut `Active`. + +--- + +### 2.2 Secret de tirage d'image + +Ce secret s'authentifie auprès de `ghcr.io` pour tirer les images conteneur d'AgentEye. Voir [enterprise-docs/github-token.md](/fr/agenteye/github-token) pour savoir comment générer votre PAT. + +```bash +kubectl create secret docker-registry agenteye-image-pull \ + --namespace agenteye \ + --docker-server=ghcr.io \ + --docker-username=agenteye-enterprise \ + --docker-password="${AGENTEYE_TOKEN}" +``` + +**Vérification :** + +```bash +kubectl get secret agenteye-image-pull -n agenteye -o jsonpath='{.type}' +``` + +Résultat attendu : `kubernetes.io/dockerconfigjson`. + +**Vérification approfondie** -- vérifier que le token peut réellement tirer des images : + +Utilisez le tag d'image `server` épinglé dans le `kustomization.yaml` de votre overlay (actuellement `v0.0.1-beta.48` dans l'overlay `acme` fourni et le déploiement de base). Substituez le tag ci-dessous par celui que vous déployez pour que cette vérification ne dérive pas entre les versions : + +```bash +kubectl run test-pull \ + --image=ghcr.io/agenteye-enterprise/server:v0.0.1-beta.48 \ + --overrides='{"spec":{"imagePullSecrets":[{"name":"agenteye-image-pull"}]}}' \ + --restart=Never -n agenteye --command -- echo ok + +# Attendez quelques secondes pour le tirage, puis : +kubectl logs test-pull -n agenteye +kubectl delete pod test-pull -n agenteye +``` + +Résultat attendu : `ok` affiché dans les logs. + +**En cas d'échec :** `ErrImagePull` ou `401 Unauthorized` signifie que le PAT est invalide ou manque le scope `read:packages`. Revérifiez [enterprise-docs/github-token.md](/fr/agenteye/github-token). + +--- + +### 2.3 Identifiants PostgreSQL + +```bash +POSTGRES_PASSWORD=$(openssl rand -hex 24) + +kubectl create secret generic agenteye-postgres \ + --namespace agenteye \ + --from-literal=POSTGRES_USER=postgres \ + --from-literal=POSTGRES_PASSWORD="${POSTGRES_PASSWORD}" \ + --from-literal=POSTGRES_DB=agenteye +``` + +> **Important :** Nous utilisons `-hex` (et non `-base64`) pour générer le mot de passe. La sortie Base64 peut contenir des caractères `+`, `/` et `=` qui cassent la chaîne de connexion `DATABASE_URL`. Voir [enterprise-docs/troubleshooting.md](/fr/agenteye/troubleshooting) pour plus de détails. + +> **Stockez `POSTGRES_PASSWORD` dans votre gestionnaire de secrets immédiatement.** Vous en aurez besoin si vous restaurez un jour depuis une sauvegarde ou vous connectez directement à la base de données. + +**Vérification :** + +```bash +kubectl get secret agenteye-postgres -n agenteye +``` + +Résultat attendu : le secret existe. + +```bash +kubectl get secret agenteye-postgres -n agenteye \ + -o jsonpath='{.data.POSTGRES_PASSWORD}' | base64 -d | wc -c +``` + +Résultat attendu : `48` (24 octets hex = 48 caractères). + +--- + +### 2.4 Clé API admin + +```bash +ADMIN_KEY=$(openssl rand -hex 32) + +kubectl create secret generic agenteye-admin-key \ + --namespace agenteye \ + --from-literal=ADMIN_KEY="${ADMIN_KEY}" +``` + +La clé admin est le credential d'amorçage. Le serveur la crée ou la met à jour à chaque démarrage avec toutes les permissions. Utilisez-la pour créer des clés collecteur avec des portées limitées à la Phase 7. Voir [enterprise-docs/api-keys.md](/fr/agenteye/api-keys) pour le modèle de permissions complet. + +> **Stockez `ADMIN_KEY` dans votre gestionnaire de secrets immédiatement.** + +**Vérification :** + +```bash +kubectl get secret agenteye-admin-key -n agenteye +``` + +Résultat attendu : le secret existe. + +--- + +### 2.5 Configuration de l'authentification (connexion au tableau de bord) + +Le tableau de bord utilise email + OTP pour la connexion utilisateur. Sans ce secret, le serveur démarre quand même et le chemin API `ADMIN_KEY` continue de fonctionner, mais **aucun utilisateur ne peut se connecter via l'interface**. + +Toutes les clés sont référencées avec `optional: true` dans le manifeste de base, donc des secrets partiels (ou aucun secret) sont acceptables ; le serveur revient aux valeurs par défaut documentées. Regrouper tout dans un seul secret `agenteye-auth` permet de faire pivoter la surface d'authentification en un seul endroit. + +```bash +kubectl create secret generic agenteye-auth \ + --namespace agenteye \ + --from-literal=ADMIN_EMAIL="admin@votreentreprise.com" \ + --from-literal=ALLOWED_EMAILS="*@votreentreprise.com" \ + --from-literal=SMTP_HOST="smtp.votrefournisseur.com" \ + --from-literal=SMTP_PORT="587" \ + --from-literal=SMTP_USERNAME="votre-utilisateur-smtp" \ + --from-literal=SMTP_PASSWORD="votre-mot-de-passe-smtp" \ + --from-literal=SMTP_FROM="noreply@votreentreprise.com" \ + --from-literal=SMTP_TLS="starttls" \ + --from-literal=DEFAULT_ORG_NAME="Acme Corp" \ + --from-literal=DEFAULT_ORG_SLUG="acme" +``` + +| Clé | Rôle | +|---|---| +| `ADMIN_EMAIL` | Utilisateur admin d'amorçage. Créé ou mis à jour à chaque démarrage avec toutes les permissions, protégé contre la suppression/modification de permissions via le tableau de bord. Sans cette clé, aucun admin n'est initialisé et la première connexion est impossible. | +| `ALLOWED_EMAILS` | Liste d'autorisation séparée par des virgules. Supporte les adresses exactes (`user@example.com`) et les wildcards de domaine (`*@example.com`). Sans elle, **aucun utilisateur ne peut se connecter ou être créé**. | +| `SMTP_HOST`, `SMTP_PORT`, `SMTP_USERNAME`, `SMTP_PASSWORD`, `SMTP_FROM` | Relais SMTP pour l'envoi des codes OTP. Si `SMTP_HOST` n'est pas défini, les codes OTP sont enregistrés dans stdout du serveur au lieu d'être envoyés par email (utile pour les tests de fumée au premier démarrage). Fournissez toutes les clés SMTP ensemble pour une vraie livraison par email. | +| `SMTP_TLS` | L'une des valeurs : `starttls` (par défaut), `tls`, ou `none`. | +| `DEFAULT_ORG_NAME`, `DEFAULT_ORG_SLUG` | Optionnel. Donnez à l'organisation `default` intégrée un nom d'affichage convivial et un slug d'URL pour qu'elle soit accessible à ex. `/acme` au lieu de `/default`. Appliqué **au premier démarrage uniquement** ; une fois que vous renommez l'org avec `agenteye-orgctl org rename` (voir §7.6), ces valeurs sont ignorées. Le slug doit contenir 1 à 40 caractères alphanumériques minuscules avec des tirets internes simples. Laissez les deux non définis pour conserver le `default` générique. | + +> **Stockez les identifiants SMTP dans votre gestionnaire de secrets.** + +**Vérification :** + +```bash +kubectl get secret agenteye-auth -n agenteye \ + -o jsonpath='{.data}' | grep -o '"[A-Z_]*"' | sort -u +``` + +Résultat attendu : les clés que vous avez renseignées apparaissent dans la sortie. + +--- + +### 2.6 Clé d'isolation des orgs multi-tenant (optionnel) + +Ignorez cette section pour un déploiement mono-tenant ; le serveur fonctionne avec une valeur dev par défaut intégrée et sert correctement l'unique org `default`. **Avant de créer une seconde organisation**, définissez un `ORG_CH_SECRET` fort et stable : le mot de passe ClickHouse de chaque org est dérivé comme `HMAC(ORG_CH_SECRET, org_id)`, donc la valeur dev connue publiquement produirait des credentials par org dérivables publiquement. La commande `agenteye-orgctl org create` (voir [§7.6 Provisionner les organisations](#76-provision-organizations-multi-tenant)) refuse de s'exécuter tant que le serveur utilise encore la valeur dev intégrée. + +```bash +kubectl create secret generic agenteye-org-ch-secret \ + --namespace agenteye \ + --from-literal=ORG_CH_SECRET="$(openssl rand -base64 48)" + +# Redémarrer le serveur pour qu'il prenne en compte la nouvelle valeur. +kubectl -n agenteye rollout restart deployment/server +``` + +Le serveur lit cette valeur via un `secretKeyRef` **optionnel**, donc un cluster mono-tenant qui ne la crée jamais démarre normalement. Gardez la valeur **stable et identique sur tous les réplicas** ; la faire pivoter invalide le mot de passe ClickHouse dérivé de chaque org jusqu'à ce que la réconciliation au démarrage reprovisionne les utilisateurs (un redémarrage progressif avec la valeur cohérente partout suffit à réparer). Voir `deploy/base/server/secret.example.yaml`. + +> **Stockez `ORG_CH_SECRET` dans votre gestionnaire de secrets et ne le faites pas pivoter sans réflexion.** + +--- + +### 2.7 Vérifier tous les secrets + +```bash +kubectl get secrets -n agenteye -o custom-columns='NAME:.metadata.name,TYPE:.type' +``` + +Sortie attendue (parmi les secrets par défaut éventuels) : + +``` +NAME TYPE +agenteye-admin-key Opaque +agenteye-auth Opaque +agenteye-image-pull kubernetes.io/dockerconfigjson +agenteye-postgres Opaque +agenteye-org-ch-secret Opaque # uniquement si vous avez complété le §2.6 (multi-tenant) +``` + +Les quatre secrets de base (`agenteye-admin-key`, `agenteye-auth`, `agenteye-image-pull`, `agenteye-postgres`) doivent être présents avant de continuer. `agenteye-org-ch-secret` n'est requis que pour les déploiements multi-tenant (voir §2.6). + +--- + +## Phase 3 -- Déployer l'application (~5 min) + +### 3.1 Configurer les noms d'hôte publics + +cert-manager a besoin des noms d'hôte d'ingestion et de tableau de bord avant de pouvoir demander leurs certificats Let's Encrypt. Copiez le template et définissez les deux : + +```bash +cp base/certificates/domain.env.example base/certificates/domain.env +# Modifiez base/certificates/domain.env et définissez : +# INGEST_DOMAIN=ingest.votre-entreprise.example (résout vers le LB Traefik public) +# DASHBOARD_DOMAIN=agenteye.votre-entreprise.example (résout vers le LB Traefik du tableau de bord) +``` + +`domain.env` est dans le gitignore ; il reste local à chaque déploiement. La compilation kustomize échoue explicitement si l'une ou l'autre clé est manquante. + +> **Le DNS doit résoudre en premier.** Vous n'avez pas à pointer le DNS vers les LBs maintenant (ils n'existent pas tant que la Phase 1.2 n'est pas complète), mais la délivrance ACME à l'étape 3.2 réessaiera jusqu'à ce que chaque nom d'hôte résolve vers son LoadBalancer. Vous pouvez soit définir le DNS maintenant (en utilisant les noms d'hôte LB capturés à la Phase 1.4), soit continuer et ajouter les enregistrements à la Phase 4. + +--- + +### 3.2 Appliquer les manifestes + +Appliquez directement la base pour une nouvelle installation, ou un overlay si vous en avez créé un pour cet environnement (les overlays épinglent seulement les tags d'image, les variables d'environnement et les limites de ressources ; ils héritent des certificats et du routage de la base) : + +```bash +kubectl apply -k base/ +# ou +kubectl apply -k overlays// +``` + +L'overlay inclut automatiquement la base ; appliquez l'un ou l'autre, pas les deux. + +--- + +### 3.3 Attendre les pods + +```bash +kubectl wait --for=condition=Ready pod -l 'app in (server,dashboard,postgres,clickhouse)' \ + -n agenteye --timeout=180s +``` + +L'attente est limitée aux pods du plan de données principal. Les pods optionnels `agent` (assistant IA) et `redis` démarrent en parallèle ; l'assistant reste inactif jusqu'à ce que vous fournissiez son endpoint LLM (voir [enterprise-docs/assistant.md](/fr/agenteye/assistant)), et Redis est un cache au mieux, donc aucun des deux n'a besoin d'être Ready pour que la plateforme serve du trafic. + +**Vérification :** + +```bash +kubectl get pods -n agenteye +``` + +Résultat attendu (les pods optionnels `agent` et `redis` apparaissent également et atteignent l'état `Running`) : + +``` +NAME READY STATUS RESTARTS AGE +agent-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +clickhouse-0 1/1 Running 0 ... +dashboard-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +dashboard-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +postgres-0 1/1 Running 0 ... +redis-0 1/1 Running 0 ... +server-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +server-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +``` + +**En cas d'échec :** + +| Statut du pod | Cause probable | Commande de débogage | +|---|---|---| +| `ImagePullBackOff` | Secret de tirage d'image incorrect ou PAT invalide | `kubectl describe pod -n agenteye` | +| `CrashLoopBackOff` | Variables d'environnement incorrectes (ex. DATABASE_URL) | `kubectl logs -n agenteye` | +| `Pending` | CPU/mémoire insuffisants ou aucun nœud disponible | `kubectl describe pod -n agenteye` (vérifier les Events) | + +--- + +### 3.4 Vérifier le stockage + +```bash +kubectl get pvc -n agenteye +``` + +Résultat attendu, tous deux avec le statut `Bound` : + +| PVC | Capacité | Soutient | +|---|---|---| +| `postgres-data-postgres-0` | `50Gi` | Store relationnel/métadonnées PostgreSQL | +| `clickhouse-data-clickhouse-0` | `100Gi` | Store analytique d'événements + évaluations ClickHouse | + +Un PVC `redis-data-redis-0` (1 Gi) apparaît également pour le cache optionnel. + +**En cas d'échec :** `Pending` signifie qu'aucune StorageClass ne peut provisionner le volume. Vérifiez `kubectl get storageclass` et assurez-vous qu'une valeur par défaut existe. Pour la production, superposez le volume ClickHouse sur une StorageClass SSD rapide (ex. gp3 sur AWS, pd-ssd sur GCP) dans votre overlay ; le débit de compaction souffre sur des disques lents. + +--- + +### 3.5 Vérifier les certificats + +```bash +kubectl get certificates -n agenteye +``` + +Résultat attendu : 3 certificats, tous `Ready: True` : + +| Nom | Émetteur | Rôle | +|---|---|---| +| `mtls-ca` | `selfsigned` | CA privée pour émettre les certificats clients mTLS (validité de 10 ans) | +| `ingest-tls` | `letsencrypt-prod` | Certificat TLS public pour le point de terminaison d'ingestion (90 jours, auto-renouvelé) | +| `dashboard-tls` | `letsencrypt-prod` | Certificat TLS public pour le tableau de bord (90 jours, auto-renouvelé) | + +**Si `ingest-tls` ou `dashboard-tls` n'est pas Ready :** + +Exécutez `kubectl describe certificate -n agenteye` et lisez les Events. Les causes courantes : + +- **Le DNS ne pointe pas encore vers le LB.** Let's Encrypt résout le nom d'hôte et frappe le port 80 pour valider -- `INGEST_DOMAIN` doit résoudre vers le LB public, `DASHBOARD_DOMAIN` vers le LB du tableau de bord. Tant que le CNAME/Alias ne se propage pas, la commande reste `pending`. Une fois le DNS correct, cert-manager réessaie automatiquement (pas besoin de supprimer le Certificate). +- **Nom d'hôte non substitué.** Si `dnsNames` affiche encore `INGEST_DOMAIN_PLACEHOLDER` / `DASHBOARD_DOMAIN_PLACEHOLDER`, vous avez sauté l'étape 3.1 -- créez `base/certificates/domain.env` et réappliquez. +- **Traefik du tableau de bord ne peut pas servir le challenge** (uniquement `dashboard-tls`). L'instance Traefik du tableau de bord doit être installée avec le fichier de valeurs fourni (Phase 1.2), qui active le fournisseur Ingress limité servant le solveur HTTP-01 de cert-manager. Une instance installée sans lui laisse le challenge non routable et la commande `pending` indéfiniment. + +**Si `mtls-ca` n'est pas Ready :** cert-manager lui-même est défaillant. Revérifiez les pods cert-manager de l'étape 1.1. + +--- + +### 3.6 Vérifier les CronJobs + +```bash +kubectl get cronjobs -n agenteye +``` + +Résultat attendu : + +| Nom | Planification | Rôle | +|---|---|---| +| `agenteye-backup` | `0 3 * * *` | Sauvegarde quotidienne Postgres + ClickHouse à 03:00 UTC | +| `cert-renewal-check` | `0 3,15 * * *` | Alertes d'expiration de certificats à 03:00 et 15:00 UTC | + +--- + +### 3.7 Vérifier le démarrage correct du serveur + +```bash +kubectl logs -n agenteye -l app=server --tail=20 +``` + +**Vérification :** Recherchez une ligne de démarrage indiquant que le serveur écoute sur le port 8080. Il ne doit y avoir aucune erreur de connexion à la base de données (le serveur requiert que PostgreSQL et ClickHouse soient accessibles avant de signaler Ready). + +**En cas d'échec :** La cause la plus courante est un `POSTGRES_PASSWORD` contenant des caractères non sûrs pour les URL qui cassent la `DATABASE_URL`. Voir [enterprise-docs/troubleshooting.md](/fr/agenteye/troubleshooting). + +--- + +### 3.8 Vérifier la connexion du tableau de bord au serveur + +```bash +kubectl logs -n agenteye -l app=dashboard --tail=20 +``` + +**Vérification :** Recherchez `Ready` dans la sortie sans erreur `ECONNREFUSED` ou similaire. + +**En cas d'échec :** Vérifiez que le Service `server` existe (`kubectl get svc server -n agenteye`) et que `AGENTEYE_SERVER_URL` est défini à `http://server:8080` dans le déploiement du tableau de bord. + +--- + +## Phase 4 -- Accès réseau (~5 min) + +### 4.1 Récupérer les adresses des LoadBalancers + +```bash +PUBLIC_IP=$(kubectl get svc -n traefik-public \ + -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') + +INTERNAL_IP=$(kubectl get svc -n traefik-dashboard \ + -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') +``` + +> Sur AWS EKS, les LoadBalancers retournent un nom d'hôte au lieu d'une IP. Remplacez `.ip` par `.hostname` dans les commandes ci-dessus. + +**Vérification :** + +```bash +echo "Public (ingestion) : $PUBLIC_IP" +echo "Interne (tableau de bord) : $INTERNAL_IP" +``` + +Les deux doivent être non vides. + +--- + +### 4.2 Pointer le DNS vers les LoadBalancers + +Créez des enregistrements DNS pour que les noms d'hôte de `base/certificates/domain.env` résolvent vers leurs LoadBalancers -- `INGEST_DOMAIN` vers le LB Traefik **public**, `DASHBOARD_DOMAIN` vers le LB Traefik **du tableau de bord** : + +- **AWS Route 53 :** enregistrement `A` avec `Alias = Yes`, cible = le nom d'hôte du LB. N'utilisez pas un simple A → IP ; les IP ELB changent. +- **Tout autre fournisseur :** `CNAME` du nom d'hôte vers le nom d'hôte du LB. + +Vérification : + +```bash +dig +short ingest.votre-entreprise.example +dig +short agenteye.votre-entreprise.example +``` + +Doit retourner les mêmes adresses que `$PUBLIC_IP` et `$INTERNAL_IP` respectivement (ou, sur EKS, résoudre vers les mêmes noms d'hôte `*.elb.amazonaws.com`). + +Une fois le DNS résolu, cert-manager termine les commandes ACME en attente de la Phase 3.5 en moins d'une minute. Relancez `kubectl get certificates -n agenteye` jusqu'à ce que `ingest-tls` et `dashboard-tls` affichent `Ready: True`. + +--- + +### 4.3 Atteindre le point de terminaison d'ingestion + +Le point de terminaison d'ingestion public applique le mutual TLS, donc chaque requête (y compris `/health`) doit présenter un certificat client. Vous émettez votre premier certificat client à la Phase 5 ; si vous en avez déjà un, vérifiez l'accessibilité maintenant : + +```bash +curl -s --cert issued//client.crt \ + --key issued//client.key \ + https://ingest.votre-entreprise.example/health +``` + +Résultat attendu : `{"status":"ok"}`. L'option `-k` n'est pas nécessaire -- le certificat serveur est chaîné à une CA publique pour `INGEST_DOMAIN`, donc il est validé par rapport au magasin de confiance du système. Accédez au point de terminaison d'ingestion par son nom d'hôte `INGEST_DOMAIN` (qui correspond au certificat émis), et non par l'IP/nom d'hôte brut du LoadBalancer. + +Le point de terminaison du tableau de bord est servi sur `DASHBOARD_DOMAIN` avec un certificat de confiance publique et n'est pas derrière mTLS, donc ni `-k` ni certificat client ne sont nécessaires : + +```bash +curl -s https://agenteye.votre-entreprise.example/ -o /dev/null -w '%{http_code}\n' +``` + +Accédez au tableau de bord par son nom d'hôte, pas par l'adresse LB brute -- le certificat est lié à `DASHBOARD_DOMAIN`, donc l'adresse brute affiche une non-correspondance de nom de certificat. + +**En cas d'échec :** Si `curl` se bloque, vérifiez que le LB est accessible depuis votre machine (VPN, groupes de sécurité, règles de pare-feu). Une erreur de handshake `certificate required` sur le nom d'hôte d'ingestion signifie qu'aucun certificat client n'a été présenté ; complétez d'abord la Phase 5. Une erreur de validation TLS sur le nom d'hôte d'ingestion signifie que le certificat serveur n'a pas fini d'être émis ; revenez à la Phase 3.5 et résolvez le problème là-bas. + +--- + +## Phase 5 -- Émettre des certificats clients mTLS (~10 min par cluster) + +Les collecteurs s'authentifient avec **deux facteurs** : un certificat client (couche transport, prouve que la requête provient d'un cluster autorisé) et une clé API (couche application, prouve que la requête provient d'un collecteur avec la permission `events:add`). Une clé compromise est inutile sans le certificat ; un certificat volé est inutile sans une clé valide. + +### 5.1 Émettre un certificat + +Chaque cluster exécutant des collecteurs a besoin de son propre certificat client. Depuis le répertoire des manifestes : + +```bash +cd base/certificates/client-certs +./issue-client-cert.sh +``` + +Remplacez `` par un identifiant significatif (ex. `us-east-1-prod`, `staging`). + +**Vérification :** Le script affiche `==> Done!` et liste les fichiers de sortie. + +```bash +kubectl get certificate mtls-client- -n agenteye +``` + +Résultat attendu : `Ready: True`. + +Fichiers de sortie dans `issued//` : + +| Fichier | Rôle | +|---|---| +| `client.crt` | Certificat client (validité de 90 jours) | +| `client.key` | Clé privée client | +| `ca.crt` | Certificat CA pour la vérification du serveur | +| `collector-mtls-secret.yaml` | Secret Kubernetes prêt à appliquer pour le cluster collecteur | + +--- + +### 5.1b Livraison alternative : AWS Secrets Manager + +Si le consommateur du certificat est un Pod Kubernetes qui a besoin de `client.crt` et `client.key` sur disque -- cas typique lorsque vous exécutez l'agenteye-collector comme sidecar dans votre pod applicatif -- poussez le bundle de certificat dans AWS Secrets Manager. Le pod applicatif le monte ensuite via le [Secrets Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/) avec IRSA, et la rotation des certificats est entièrement automatisée. + +```bash +cd base/certificates/client-certs +export AWS_REGION=us-east-1 # région où votre charge de travail s'exécute +./issue-client-cert.sh --save-to aws-secrets-manager +``` + +Lors d'une ré-exécution (renouvellement), le script appelle `PutSecretValue` sur le même secret, donc l'ARN et le nom restent stables. Le CSI Driver récupère la nouvelle version lors de son prochain cycle de rotation et réécrit les fichiers dans le pod. + +**Prérequis :** + +- CLI `aws` v2 authentifiée sur votre compte AWS. +- `jq` installé. +- Variable d'environnement `AWS_REGION` définie. +- Permissions IAM sur votre identité appelante (limitez `Resource` à `arn:aws:secretsmanager:::secret:agenteye/mtls-client/*`) : + - `secretsmanager:CreateSecret` + - `secretsmanager:DescribeSecret` + - `secretsmanager:PutSecretValue` + - `secretsmanager:TagResource` + +**Ce que fait le script dans ce mode :** + +| Étape | Action | +|---|---| +| 1 | Émet / ré-extrait le certificat via cert-manager (identique au mode par défaut). | +| 2 | Appelle `DescribeSecret` sur `agenteye/mtls-client/` pour décider création ou mise à jour. | +| 3 | Première exécution : `CreateSecret` avec un payload JSON à trois clés (`client.crt`, `client.key`, `ca.crt`), tagué `AgentEyeCluster=`. Exécutions suivantes : `PutSecretValue` pour publier une nouvelle version ; tag rafraîchi via `TagResource`. | +| 4 | Supprime `issued//` uniquement après un téléversement réussi. En cas d'échec, le répertoire est conservé pour permettre une nouvelle tentative. | + +**Si le secret est planifié pour suppression**, le script échoue avec un message clair vous indiquant d'exécuter `aws secretsmanager restore-secret --secret-id agenteye/mtls-client/` avant de réessayer. + +Pour le câblage complet du pod (SecretProviderClass, configuration IRSA, comportement de rotation, dépannage), voir [enterprise-docs/single-pod-deployment.md](/fr/agenteye/single-pod-deployment). + +--- + +### 5.2 Vérifier que le certificat fonctionne + +Testez le certificat émis contre l'ingress mTLS : + +```bash +curl -sk --cert issued//client.crt \ + --key issued//client.key \ + https://${PUBLIC_IP}/health +``` + +Résultat attendu : `{"status":"ok"}` + +**En cas d'échec :** + +| Erreur | Cause | Correction | +|---|---|---| +| `certificate required` | Certificat non présenté | Vérifiez les chemins de fichiers dans la commande `curl` | +| `bad certificate` | Incompatibilité de CA | Vérifiez que `mtls-ca-issuer` a émis le cert : `kubectl describe certificate mtls-client- -n agenteye` | +| `connection refused` | Mauvais nom d'hôte ou LB inaccessible | Vérifiez `/etc/hosts` ou le DNS | + +--- + +### 5.3 Livrer au cluster collecteur + +Envoyez `collector-mtls-secret.yaml` à l'équipe qui opère le cluster collecteur. Ils l'appliquent : + +```bash +kubectl apply -f collector-mtls-secret.yaml -n +``` + +Puis configurez le collecteur pour monter le secret et utiliser les chemins de certificat : + +```json +{ + "tls_cert": "/etc/agenteye/tls/client.crt", + "tls_key": "/etc/agenteye/tls/client.key" +} +``` + +Voir [enterprise-docs/collector-installation.md](/fr/agenteye/collector-installation) pour la configuration complète du collecteur, y compris les montages de volumes Kubernetes. + +**Vérification (dans le cluster collecteur) :** + +```bash +kubectl get secret agenteye-collector-mtls -n +``` + +Résultat attendu : le secret existe avec 3 clés de données (`client.crt`, `client.key`, `ca.crt`). + +--- + +### 5.4 Cycle de vie des certificats + +| Propriété | Valeur | +|---|---| +| Validité du certificat client | 90 jours | +| Auto-renouvellement | cert-manager renouvelle 15 jours avant expiration | +| Validité de la CA | 10 ans | +| Alertes d'expiration | CronJob alerte 30 jours avant expiration (Phase 6) | + +cert-manager renouvelle automatiquement le certificat sur le **cluster AgentEye**, mais le certificat renouvelé doit être re-livré au cluster collecteur. Relancez `issue-client-cert.sh` et ré-appliquez `collector-mtls-secret.yaml` avant l'expiration de l'ancien certificat. + +Si vous utilisez `--save-to aws-secrets-manager` (voir § 5.1b), relancez la même commande. Le script appelle `PutSecretValue` sur le même secret ; les pods montant le secret via le Secrets Store CSI Driver récupèrent la nouvelle version lors de leur prochain cycle de rotation (par défaut : toutes les heures), sans redémarrage de pod requis. + +--- + +### 5.5 Révoquer un certificat + +Pour bloquer immédiatement l'accès du collecteur d'un cluster : + +```bash +kubectl delete certificate mtls-client- -n agenteye +``` + +**Vérification :** La commande `curl` de l'étape 5.2 échoue désormais avec une erreur de handshake TLS. + +--- + +## Phase 6 -- Surveillance du renouvellement de certificats (~2 min) + +Un CronJob intégré s'exécute toutes les 12 heures (03:00 et 15:00 UTC) et vérifie tous les certificats clients étiquetés `agenteye.io/cert-type=mtls-client`. Il alerte quand un certificat est dans les 30 jours avant expiration. + +### 6.1 Activer les notifications Slack (optionnel) + +```bash +kubectl create secret generic cert-renewal-notify-config \ + --namespace agenteye \ + --from-literal=SLACK_WEBHOOK_URL="https://hooks.slack.com/services/VOTRE/WEBHOOK/URL" +``` + +Sans ce secret, le CronJob s'exécute quand même et enregistre le statut des certificats dans stdout. + +**Vérification :** + +```bash +kubectl get secret cert-renewal-notify-config -n agenteye +``` + +Résultat attendu : le secret existe. + +--- + +### 6.2 Tester le CronJob + +```bash +kubectl create job --from=cronjob/cert-renewal-check test-cert-check -n agenteye + +kubectl wait --for=condition=Complete job/test-cert-check -n agenteye --timeout=60s + +kubectl logs -n agenteye -l job-name=test-cert-check +``` + +Résultat attendu : une liste de certificats avec leur statut d'expiration. Si le webhook Slack est configuré, vérifiez le canal Slack pour le message d'alerte. + +**En cas d'échec :** Vérifiez le RBAC -- le ServiceAccount du CronJob a besoin des permissions `get, list` sur les ressources Certificate de cert-manager. Vérifiez avec : `kubectl describe role cert-renewal-check -n agenteye`. + +Nettoyez le job de test : + +```bash +kubectl delete job test-cert-check -n agenteye +``` + +--- + +## Phase 7 -- Vérification de bout en bout + +Cette phase confirme que l'ensemble du pipeline fonctionne : vérification de santé, création de clé, ingestion d'événements et affichage dans le tableau de bord. + +> **Note :** Les exemples ci-dessous atteignent le point de terminaison d'ingestion par son adresse LoadBalancer brute (`${PUBLIC_IP}`) pour des raisons pratiques, d'où l'utilisation de `-k` ; le certificat serveur est lié à `INGEST_DOMAIN`, pas à l'IP du LB, donc la vérification du nom d'hôte est ignorée. Le point de terminaison d'ingestion applique le mutual TLS sur **chaque** chemin, donc chaque appel doit également présenter un certificat client (`--cert`/`--key`). Pour valider également le certificat public, ciblez `https://ingest.votre-entreprise.example/...` au lieu de `${PUBLIC_IP}` et supprimez `-k`. + +### 7.1 Vérification de santé + +```bash +curl -sk --cert issued//client.crt \ + --key issued//client.key \ + https://${PUBLIC_IP}/health +``` + +Résultat attendu : `{"status":"ok"}` avec HTTP 200. + +--- + +### 7.2 Créer des clés collecteur avec portée limitée + +La clé admin est pour l'amorçage et la gestion. Créez des clés `events:add` dédiées pour les collecteurs : + +```bash +COLLECTOR_KEY=$(openssl rand -hex 32) + +curl -sk -X POST https://${PUBLIC_IP}/keys \ + --cert issued//client.crt \ + --key issued//client.key \ + -H "Authorization: Bearer ${ADMIN_KEY}" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "prod-collector", + "key": "'"${COLLECTOR_KEY}"'", + "permissions": ["events:add"] + }' +``` + +**Vérification :** La réponse inclut `"id"`, `"name": "prod-collector"`, `"permissions": ["events:add"]`, `"created_at"`. + +**Vérification :** Confirmez que la clé apparaît dans la liste des clés : + +```bash +curl -sk https://${PUBLIC_IP}/keys \ + --cert issued//client.crt \ + --key issued//client.key \ + -H "Authorization: Bearer ${ADMIN_KEY}" +``` + +Résultat attendu : `prod-collector` apparaît dans la réponse. + +Voir [enterprise-docs/api-keys.md](/fr/agenteye/api-keys) pour la référence complète de gestion des clés. + +--- + +### 7.3 Ingérer un événement de test + +```bash +echo '{"session_id":"test","agent_id":"smoke-test","type":"test","timestamp":"2026-04-20T00:00:00Z"}' \ + | curl -sk --cert issued//client.crt \ + --key issued//client.key \ + -H "Authorization: Bearer ${COLLECTOR_KEY}" \ + -H "Content-Type: application/x-ndjson" \ + --data-binary @- \ + https://${PUBLIC_IP}/events +``` + +Résultat attendu : `{"accepted":1,"skipped":0}` avec HTTP 200. + +**En cas d'échec :** + +| Statut HTTP | Cause | +|---|---| +| 401 | Clé API invalide ou manquante | +| 403 | La clé n'a pas la permission `events:add` | +| Erreur de handshake TLS | Problème de certificat client -- voir le dépannage de la Phase 5 | + +--- + +### 7.4 Vérifier l'événement dans le tableau de bord + +Ouvrez `https://agenteye.votre-entreprise.example` (votre `DASHBOARD_DOMAIN`) dans un navigateur. Le certificat est de confiance publique, donc il n'y a pas d'avertissement. + +> Si le LoadBalancer du tableau de bord est restreint par liste d'autorisation IP et que vous ne pouvez pas vous connecter, vérifiez que votre IP est autorisée : +> ```bash +> kubectl get svc traefik-dashboard -n traefik-dashboard -o jsonpath='{.spec.loadBalancerSourceRanges}' +> ``` +> Gardez à l'esprit que Let's Encrypt renouvelle le certificat du tableau de bord via HTTP-01 sur le port 80, et les plages sources s'appliquent à l'ensemble du LoadBalancer -- avant de le restreindre aux plages d'entreprise, coordonnez un solveur DNS-01 avec le support ou les renouvellements échoueront silencieusement. + +**Vérification :** L'événement de test de fumée doit apparaître dans la liste des événements avec la session `test` et l'agent `smoke-test`. + +**En cas d'échec :** Vérifiez les logs du tableau de bord (`kubectl logs -n agenteye -l app=dashboard --tail=50`). Vérifiez que `AGENTEYE_SERVER_URL` et `AGENTEYE_API_KEY` sont correctement définis. + +--- + +### 7.5 Tester le CronJob de sauvegarde + +```bash +kubectl create job --from=cronjob/agenteye-backup test-backup -n agenteye + +kubectl wait --for=condition=Complete job/test-backup -n agenteye --timeout=300s + +kubectl logs -n agenteye -l job-name=test-backup +``` + +Résultat attendu : `Backup created: agenteye-YYYYMMDD-HHMMSS.tar.gz (NNN)` dans les logs ; l'archive regroupe le dump Postgres et les tables ClickHouse. + +> L'étape de téléversement S3 est intégrée dans le CronJob et s'exécute dès que `BACKUP_BUCKET` est défini (la base fournit une valeur de bucket par défaut). Elle est ignorée uniquement si `BACKUP_BUCKET` est vide ou littéralement `PLACEHOLDER`. Pointez-le vers votre propre bucket et accordez au ServiceAccount `agenteye-backup` un accès en écriture avant de vous y fier (voir la section Sauvegardes ci-dessous). + +Nettoyage : + +```bash +kubectl delete job test-backup -n agenteye +``` + +--- + +### 7.6 Provisionner les organisations (multi-tenant) + +Ignorez cette section pour un déploiement mono-tenant ; toutes les données résident dans l'org `default` intégrée et rien ici n'est requis. + +Si vous exécutez plusieurs tenants isolés, les organisations et leurs membres sont créés avec le CLI **`agenteye-orgctl`**. Il est fourni **dans l'image server** (aux côtés de `agenteye-server`) et vous l'exécutez **dans le Deployment `server` existant avec `kubectl exec`; il n'y a pas de pod, Job ou Deployment séparé, ni d'API HTTP ou de bouton dans le tableau de bord pour le cycle de vie des tenants.** L'exécuter dans le pod serveur signifie qu'il réutilise le `DATABASE_URL`, `CLICKHOUSE_URL` et le `ORG_CH_SECRET` du §2.6 du pod. + +> **Prérequis :** complétez d'abord le §2.6. `org create` refuse de s'exécuter tant que le serveur utilise encore le `ORG_CH_SECRET` dev intégré, et l'utilisateur ClickHouse par org qu'il provisionne dépend de ce secret étant fort et stable. + +**Créer une org et ajouter son premier admin :** + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org create --slug acme --name "Acme Corp" + +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member add --org acme --email alice@acme.example --set admin +``` + +Le nouveau membre reçoit un OTP lors de sa première connexion au tableau de bord et travaille ensuite entièrement dans l'interface sous le préfixe d'URL de l'org (ex. `/acme/...`). + +**Autres commandes** (exécutez-les de la même façon avec `kubectl -n agenteye exec deploy/server -- agenteye-orgctl …`) : + +| Commande | Ce qu'elle fait | +|---|---| +| `org list` | Lister les organisations et leur état. | +| `org rename --slug --name ` | Renommer une org (slug inchangé). | +| `org delete --slug ` | Suppression logique + suppression de l'utilisateur ClickHouse de l'org ; **données conservées**. | +| `org purge --slug ` | Effacement irréversible des données ; l'org doit être `delete`d en premier ; jamais l'org `default`. | +| `member list --org ` | Lister les membres et leurs permissions. | +| `member update --org --email [--set ...] [--add ...] [--remove ...]` | Modifier les permissions d'un membre. | +| `member remove --org --email ` | Retirer un membre de l'organisation. | + +**Vérification :** `org list` affiche l'organisation avec le statut `active`. `member list --org acme` affiche le membre avec les permissions attendues. Connectez-vous au tableau de bord avec l'adresse e-mail du membre et vérifiez que l'interface utilise le préfixe `/acme/` et que les données de l'organisation par défaut ne sont pas visibles. + +--- + +## Dépannage + +Si une étape échoue, collectez d'abord les informations de diagnostic suivantes : + +```bash +# État des pods +kubectl get pods -n agenteye -o wide + +# Événements récents du cluster +kubectl get events -n agenteye --sort-by=.lastTimestamp + +# Logs des applications +kubectl logs -n agenteye -l app=server --tail=200 +kubectl logs -n agenteye -l app=dashboard --tail=200 + +# État des certificats +kubectl describe certificate -n agenteye +``` + +Pour une liste complète des problèmes courants et de leurs solutions, consultez le [guide de dépannage](/fr/agenteye/troubleshooting). + +--- + +## Documentation associée + +| Guide | Description | +|---|---| +| [Déploiement géré](/fr/agenteye/managed-deployment) | Guide de configuration d'un déploiement géré sur votre cluster Kubernetes | +| [Bien démarrer](/fr/agenteye/getting-started) | Procédure complète avec Docker Compose | +| [Déploiement](/fr/agenteye/deployment) | Déploiement Docker, variables d'environnement et configuration | +| [Gestion des tenants](/fr/agenteye/tenant-management) | Provisionnement des organisations et membres avec le CLI `agenteye-orgctl` | +| [Configuration du jeton GitHub](/fr/agenteye/github-token) | Génération du PAT GitHub pour accéder aux artefacts | +| [Installation du collecteur](/fr/agenteye/collector-installation) | Toutes les méthodes d'installation du collecteur | +| [SDK Python](/fr/agenteye/python-sdk) | Référence complète de l'API du SDK | +| [Clés API](/fr/agenteye/api-keys) | Création et gestion des clés API | +| [Dépannage](/fr/agenteye/troubleshooting) | Problèmes courants et solutions | + +--- + +## Support + +Envoyez un e-mail à `support@exosphere.host` pour obtenir de l'aide sur le déploiement. diff --git a/docs/fr/agenteye/managed-deployment.mdx b/docs/fr/agenteye/managed-deployment.mdx new file mode 100644 index 00000000..c130548d --- /dev/null +++ b/docs/fr/agenteye/managed-deployment.mdx @@ -0,0 +1,171 @@ +--- +title: "Déploiement géré sur votre cluster Kubernetes" +description: "Documentation du déploiement géré AgentEye sur votre cluster Kubernetes." +--- + + +AgentEye est une plateforme d'observabilité et d'évaluation auto-hébergée pour les agents IA et LLM. Elle capture les sessions d'agents, les appels d'outils, les requêtes de modèles et les erreurs, les transforme en analyses et évaluations consultables, et présente les résultats dans un tableau de bord avec un assistant IA optionnel en lecture seule. + +Dans le modèle de déploiement géré, vous fournissez un cluster Kubernetes dédié et Exosphere exécute la plateforme complète en son sein — déployant, configurant, opérant, sauvegardant et mettant à jour chaque composant en votre nom. Votre équipe bénéficie de la valeur de la plateforme (visibilité sur les agents, analyses, évaluation et l'assistant optionnel) sans avoir à gérer les bases de données, les certificats ou les mises à jour. Toutes les données restent dans votre compte cloud. + +--- + +## Prérequis + +- Un **GitHub PAT** pour extraire les images de conteneurs et télécharger les artefacts (voir [Configuration du token GitHub](/fr/agenteye/github-token)) +- Un **cluster Kubernetes dédié** (voir les exigences ci-dessous) +- Un **bucket de stockage** pour les sauvegardes de bases de données +- **Connectivité réseau** : port 443 entrant vers le load balancer du cluster + +--- + +## Étape 1 : Provisionner un cluster Kubernetes dédié + +Créez un cluster Kubernetes dédié à AgentEye. Il ne doit pas être partagé avec d'autres charges de travail, afin que la plateforme complète (services applicatifs, bases de données, analyses et mise en cache) s'exécute en isolation sans impacter votre infrastructure existante. + +| Exigence | Détails | +|---|---| +| **Distribution** | Tout Kubernetes conforme : EKS, GKE, AKS, ou autogéré | +| **Version** | 1.27 ou ultérieure | +| **Pool de nœuds** | Minimum : **3 nœuds, 4 vCPU / 8 Go de RAM chacun** (instances standard à usage général) | +| **Stockage** | Une StorageClass par défaut qui provisionne des volumes bloc (ex. `gp3` sur AWS, `pd-ssd` sur GCP) | +| **Load Balancer** | Le cluster doit être capable de provisionner des services LoadBalancer cloud (par défaut sur EKS, GKE, AKS) | + +> Exosphere installe et gère tout le reste à l'intérieur du cluster : contrôleurs d'ingress, certificats TLS, bases de données, mise en cache, monitoring et tous les déploiements applicatifs. + +--- + +## Étape 2 : Accorder l'accès à l'équipe AgentEye + +Exosphere a besoin d'un accès cluster-admin (ou d'un RBAC étendu équivalent) pour gérer les namespaces, les définitions de ressources personnalisées, les contrôleurs d'ingress et les provisionneurs de stockage. + +| Exigence | Détails | +|---|---| +| **Méthode d'accès** | Rôle IAM (recommandé pour EKS/GKE), kubeconfig, ou accès SSO | +| **VPN / bastion** | Si le serveur API Kubernetes est privé, fournissez des identifiants VPN ou un accès bastion pour l'équipe opérationnelle Exosphere | + +--- + +## Étape 3 : Configurer la connectivité réseau + +Votre équipe réseau doit autoriser le trafic entrant sur le **port 443** vers les load balancers du cluster. Le déploiement utilise deux load balancers distincts : l'un pour l'ingestion d'événements (protégé par mTLS) et l'autre pour le tableau de bord : + +| Trafic | Source | Destination | Sécurité | +|---|---|---|---| +| **Ingestion d'événements** | Pods collecteurs dans vos clusters | Load Balancer d'ingestion, port 443 | mTLS (certificat client) + clé API | +| **Tableau de bord** | Navigateurs des développeurs | Load Balancer du tableau de bord, port 443 | HTTPS sur votre domaine, connexion OTP par email sans mot de passe | + +Le point d'entrée d'ingestion est protégé par TLS mutuel ; les collecteurs doivent présenter un certificat client valide **et** une clé API valide à chaque requête. Le tableau de bord s'exécute sur son propre load balancer et nom d'hôte, avec la connexion restreinte aux adresses e-mail/domaines que vous avez autorisés. + +**Enregistrements DNS (une seule fois) :** vous créez deux enregistrements CNAME sous un domaine que vous contrôlez — l'un pour le point d'entrée d'ingestion et l'autre pour le tableau de bord (ex. `agenteye.votre-entreprise.exemple`) — pointant vers les noms d'hôtes des load balancers fournis par Exosphere. Exosphere provisionne ensuite automatiquement des certificats TLS publiquement approuvés pour les deux noms d'hôtes, y compris les renouvellements. + +> **Note sur le port 80 :** l'émission et le renouvellement automatiques des certificats s'effectuent via HTTP sur le port 80 de chaque load balancer. Si votre politique de sécurité nécessite de restreindre le load balancer du tableau de bord aux plages d'adresses IP d'entreprise, informez-en Exosphere au préalable — nous basculons la validation des certificats vers une méthode DNS (un enregistrement DNS supplémentaire de votre côté) afin que les renouvellements continuent de fonctionner derrière la restriction. + +> **Trafic sortant :** les nœuds du cluster ont besoin d'un accès internet pour extraire les images de conteneurs depuis `ghcr.io`. Si votre réseau restreint le trafic sortant, autorisez `ghcr.io` ou copiez les images dans votre registre interne. + +--- + +## Étape 4 : Fournir un bucket de stockage pour les sauvegardes + +Les sauvegardes de bases de données sont stockées dans un bucket de stockage cloud qui vous appartient. + +| Exigence | Détails | +|---|---| +| **Service** | S3 (AWS), GCS (GCP), ou Azure Blob Storage | +| **Accès** | Accordez l'accès en écriture aux nœuds du cluster via un rôle IAM pour les comptes de service (IRSA sur EKS, Workload Identity sur GKE) ou fournissez des identifiants | +| **Rétention** | Vous contrôlez la politique de cycle de vie du bucket (période de rétention, règles d'archivage). Exosphere écrit les sauvegardes ; vous décidez de la durée de conservation | + +Une sauvegarde quotidienne unique exporte à la fois PostgreSQL (état relationnel) et ClickHouse (événements et évaluations) dans une archive compressée et la télécharge dans votre bucket. Les sauvegardes s'exécutent également avant chaque mise à jour. + +--- + +## Étape 5 : Désigner un point de contact + +Désignez une personne ou un canal Slack/Teams de votre côté pour les problèmes au niveau du cluster : santé des nœuds, limites du compte cloud, modifications réseau. Les opérations courantes ne nécessitent pas ce contact. + +--- + +## Ce que nous déployons + +Une fois qu'Exosphere dispose d'un accès au cluster, les composants suivants sont déployés et gérés pour vous : + +| Composant | Rôle | +|---|---| +| **Serveur AgentEye** | API HTTP qui reçoit les événements des collecteurs, exécute les analyses et sert les données au tableau de bord | +| **Tableau de bord** | Interface web pour visualiser les sessions d'agents, les appels d'outils, les requêtes de modèles et les erreurs ; héberge l'assistant IA optionnel en lecture seule | +| **ClickHouse** | Stockage canonique requis pour les événements ingérés, les analyses et les évaluations | +| **PostgreSQL** | Stockage relationnel pour les organisations, les clés API, les utilisateurs, les tableaux de bord et les requêtes sauvegardées | +| **Redis** | Cache partagé optionnel et backend de limitation de débit ; la plateforme se dégrade gracieusement s'il est indisponible | +| **Assistant IA (optionnel)** | Conteneur d'assistant interne en lecture seule ; reste désactivé jusqu'à ce qu'un point d'entrée LLM soit configuré | +| **Contrôleurs d'ingress** | Deux load balancers (l'un pour l'ingestion protégée par mTLS, l'autre pour le tableau de bord) terminant TLS avec des certificats renouvelés automatiquement et publiquement approuvés, et appliquant mTLS sur le point d'entrée d'ingestion | +| **cert-manager** | Automatise le provisionnement des certificats TLS et l'émission des certificats clients mTLS | +| **Surveillance des certificats** | Une tâche planifiée vérifie l'expiration des certificats et envoie des alertes (ex. sur Slack) à l'approche du renouvellement | + +L'offre gérée opère également le pipeline d'évaluation de la plateforme, qui évalue l'activité des agents par rapport à vos critères d'évaluation. Consultez [Assistant](/fr/agenteye/assistant) et [Suite d'évaluation](/fr/agenteye/evaluation-suite) pour en savoir plus sur ces fonctionnalités. + +--- + +## Ce que nous vous fournissons + +Une fois le déploiement terminé, vous recevez : + +| Élément | Détails | +|---|---| +| **URL du tableau de bord** | Un nom d'hôte sous votre domaine (ex. `https://agenteye.votre-entreprise.exemple`), servi avec un certificat TLS renouvelé automatiquement et publiquement approuvé. Vous créez un CNAME vers le nom d'hôte du load balancer que nous fournissons ; la connexion est par OTP email sans mot de passe | +| **Point d'entrée collecteur** | Le chemin `/events` du nom d'hôte d'ingestion (ex. `https://ingest.votre-entreprise.exemple/events`), protégé par mTLS | +| **Bundle de certificat client** | Par cluster : certificat client, clé privée et certificat CA livrés sous forme de manifest Kubernetes Secret. À appliquer une fois par cluster | +| **GitHub PAT** | Pour télécharger les binaires du collecteur et les packages du SDK Python | +| **Clés API collecteur** | Clés à portée limitée avec permission `events:add`, une par déploiement de collecteur | +| **Guides d'installation** | Documentation étape par étape pour le collecteur et le SDK Python | + +--- + +## Ce que vous faites après la configuration + +Votre seul travail continu concerne vos propres machines d'agents, pas le cluster AgentEye : + +1. **Installez le collecteur** dans chaque cluster Kubernetes exécutant des agents IA : montez le certificat client et configurez l'URL du point d'entrée et la clé API. Voir [Installation du collecteur](/fr/agenteye/collector-installation). +2. **Intégrez le SDK Python** dans votre code d'agent. Voir [SDK Python](/fr/agenteye/python-sdk). +3. **Ouvrez le tableau de bord** dans votre navigateur pour visualiser l'activité des agents. + +Aucune opération sur le cluster, aucune gestion de base de données, aucun renouvellement de certificat, aucune mise à jour. + +--- + +## Sécurité + +- **Les données restent dans votre compte cloud.** Le cluster, le stockage et les bases de données s'exécutent tous dans votre environnement. Aucune donnée ne quitte votre périmètre. +- **Vous contrôlez l'accès.** Le cluster est dans votre compte. Vous pouvez auditer, surveiller ou révoquer l'accès d'Exosphere à tout moment. Toutes les opérations passent par le journal d'audit de votre cloud (CloudTrail, GCP Audit Logs, etc.). +- **mTLS sur l'ingestion d'événements.** Chaque requête de collecteur nécessite à la fois un certificat client valide et une clé API. Une clé compromise est inutile sans le certificat ; un certificat volé est inutile sans une clé valide. +- **Contrôle d'accès au tableau de bord.** Le tableau de bord s'exécute sur son propre load balancer, séparé de l'ingestion d'événements, et la connexion est par OTP email sans mot de passe restreinte aux adresses e-mail/domaines que vous avez autorisés. Une liste blanche de plages d'adresses IP sources sur le load balancer est disponible sur demande ; étant donné que le renouvellement automatique des certificats doit accéder au load balancer, Exosphere associe la restriction à la validation des certificats par DNS pour que les renouvellements continuent de fonctionner. +- **Certificats par cluster.** Chacun de vos clusters reçoit son propre certificat client. Si un cluster est compromis, ce certificat est révoqué indépendamment sans affecter les autres. + +--- + +## Calendrier de déploiement + +| Phase | Durée | Votre implication | +|---|---|---| +| **Provisionnement du cluster** | 1-2 jours | Provisionner le cluster et accorder l'accès à Exosphere | +| **Configuration de la plateforme** | 1 jour | Aucune ; Exosphere installe tous les composants d'infrastructure | +| **Déploiement de l'application** | 1 jour | Aucune ; Exosphere déploie le serveur, le tableau de bord et crée les clés API | +| **Déploiement des collecteurs** | 1-3 jours | Installer les collecteurs dans vos clusters (avec les conseils d'Exosphere) | +| **Rodage en production** | 1 semaine | Aucune ; Exosphere surveille et ajuste | + +Durée totale typique : **~2 semaines** du lancement à la mise en production. + +--- + +## Support + +Pour toute question ou problème, contactez Exosphere à l'adresse `support@exosphere.host`. + +--- + +## Prochaines étapes + +- [Démarrage rapide](/fr/agenteye/getting-started) : présentation complète de bout en bout +- [Installation du collecteur](/fr/agenteye/collector-installation) : installer et configurer le collecteur +- [SDK Python](/fr/agenteye/python-sdk) : instrumenter votre code d'agent +- [Clés API](/fr/agenteye/api-keys) : gérer les accès et les permissions +- [Dépannage](/fr/agenteye/troubleshooting) : problèmes courants et solutions \ No newline at end of file diff --git a/docs/fr/agenteye/python-sdk.mdx b/docs/fr/agenteye/python-sdk.mdx new file mode 100644 index 00000000..94f93202 --- /dev/null +++ b/docs/fr/agenteye/python-sdk.mdx @@ -0,0 +1,383 @@ +--- +title: "Python SDK" +description: "Documentation du SDK Python AgentEye." +--- + + +Le SDK Python AgentEye vous offre une visibilité complète sur le comportement de vos agents (chaque exécution d'agent, appel d'outil, requête de modèle, hook et intervention humaine), afin de vous permettre de déboguer, auditer et évaluer vos agents. Il instrumente votre code d'agent en écrivant des événements structurés dans des fichiers JSONL locaux ; le démon collecteur les récupère et les transmet automatiquement à la plateforme. + +--- + +## Installation + +Téléchargez le wheel depuis GitHub Releases en utilisant votre `AGENTEYE_TOKEN`. Si vous ne disposez pas encore d'un token, consultez [Configuration du token GitHub](/fr/agenteye/github-token) pour les étapes de configuration et les permissions requises. + +**Via `gh` CLI + pip :** + +```bash +VERSION=0.0.1b9 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "python-sdk/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-*.whl' +pip install "agenteye-${VERSION}-py3-none-any.whl" +``` + +**Via `gh` CLI + uv :** + +```bash +VERSION=0.0.1b9 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "python-sdk/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-*.whl' +uv add "./agenteye-${VERSION}-py3-none-any.whl" +``` + +**Via curl (sans `gh` CLI) :** + +```bash +VERSION=0.0.1b9 +curl -fsSL \ + -H "Authorization: Bearer $AGENTEYE_TOKEN" \ + -L \ + "https://github.com/agenteye-enterprise/releases/releases/download/python-sdk%2Fv${VERSION}/agenteye-${VERSION}-py3-none-any.whl" \ + -o "agenteye-${VERSION}-py3-none-any.whl" +pip install "agenteye-${VERSION}-py3-none-any.whl" +``` + +--- + +## Démarrage rapide + +```python +import agenteye + +agenteye.configure(environment="production") + +agenteye.event.agent_start(session_id="run-001", agent_id="planner", goal="answer user query") + +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", + input={"query": "latest AI research"}, +) + +agenteye.event.tool_result( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", + output={"results": ["..."]}, +) + +agenteye.event.agent_end(session_id="run-001", agent_id="planner", outcome="success") +``` + +--- + +## configure() + +```python +agenteye.configure( + base_dir=None, # Path | str | None. Défaut : $AGENTEYE_HOME ou ~/.agenteye + flush_interval=0.5, # float, secondes entre chaque cycle de vidage + environment=None, # str | None. Libellé de l'environnement de déploiement +) +``` + +À appeler une seule fois avant tout appel `event.*`. Sans obligation ; les valeurs par défaut fonctionnent directement. Tous les arguments sont uniquement nommés ; passez-les par nom comme indiqué ci-dessus. + +Lorsque `base_dir` vaut `None` (valeur par défaut), le SDK lit `$AGENTEYE_HOME` si cette variable est définie, sinon il utilise `~/.agenteye`. Ce comportement correspond à la résolution propre au collecteur, de sorte qu'une seule variable d'environnement `AGENTEYE_HOME` configure le spool d'événements partagé pour le SDK et le collecteur — requis pour les déploiements en sidecar ou en pod unique où les deux processus doivent s'entendre sur le chemin du spool. + +--- + +## Environnement + +Étiquetez chaque événement avec un environnement de déploiement (`production`, `staging`, `qa`, `canary`, etc.). Définissez-le une seule fois ; le SDK l'associe automatiquement à chaque événement. + +**Option 1 : via `configure()` :** + +```python +agenteye.configure(environment="production") +``` + +**Option 2 : via une variable d'environnement :** + +```bash +export AGENTEYE_ENVIRONMENT=production +``` + +**Priorité :** `configure(environment=...)` est prioritaire sur la variable d'environnement. Si aucun des deux n'est défini, la valeur par défaut est `"dev"`. + +La valeur d'environnement apparaît comme filtre de premier ordre dans le tableau de bord et est stockée en tant que colonne indexée sur le serveur pour des requêtes rapides. + +**Contrainte :** les valeurs d'environnement **ne doivent pas contenir de virgule `,` littérale**. Les filtres du tableau de bord utilisent une sélection multiple séparée par des virgules dans l'URL (`?environment=prod,staging`), de sorte qu'un environnement nommé `prod,blue` serait divisé en deux valeurs. Les événements dont l'environnement contient une virgule sont rejetés à l'ingestion. + +--- + +## Référence des événements + +Toutes les méthodes d'événement requièrent ces deux champs : + +| Champ | Type | Description | +|---|---|---| +| `session_id` | `str` | Identifie l'exécution de l'agent de niveau supérieur | +| `agent_id` | `str` | Identifie l'agent au sein de la session qui a émis l'événement | + +Toutes les méthodes acceptent également des `**kwargs` arbitraires pour des métadonnées personnalisées (voir [Champs personnalisés](#custom-fields)). + +--- + +### `event.agent_start()` + +Émis lorsqu'un agent commence à travailler. + +```python +agenteye.event.agent_start( + session_id="run-001", + agent_id="planner", + goal="answer user query", # str | None + parent_id=None, # str | None - agent_id parent pour les agents imbriqués +) +``` + +--- + +### `event.agent_end()` + +Émis lorsqu'un agent termine son travail. + +```python +agenteye.event.agent_end( + session_id="run-001", + agent_id="planner", + outcome="success", # str | None + summary="Answered query", # str | None +) +``` + +--- + +### `event.tool_use()` + +Émis lorsqu'un agent invoque un outil. À associer avec `tool_result` ; le SDK calcule automatiquement `duration_ms`. + +```python +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="web_search", # str, requis + tool_call_id="toolu_01", # str, requis - clé de corrélation pour le tool_result correspondant + input={"query": "..."}, # dict | None +) +``` + +--- + +### `event.tool_result()` + +Émis lorsqu'un outil retourne un résultat. Se corrèle avec `tool_use` via `tool_call_id`. + +```python +agenteye.event.tool_result( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", # doit correspondre au tool_use précédent + output={"results": ["..."]}, # Any | None + error=None, # str | None - défini si l'outil a levé une exception + # duration_ms est calculé automatiquement - ne pas le passer +) +``` + +--- + +### `event.model_request()` + +Émis juste avant l'envoi d'un prompt à un LLM. + +```python +agenteye.event.model_request( + session_id="run-001", + agent_id="planner", + model="claude-sonnet-4-6", # str | None + messages=[ # list[dict] | None - tours de conversation + {"role": "user", "content": "..."}, + ], + system="You are helpful.", # Any | None - str ou liste de blocs de contenu + tools=[ # list[dict] | None - schémas d'outils proposés au modèle + {"name": "search", "input_schema": {"type": "object"}}, + ], +) +``` + +Les entrées de `messages` acceptent soit un `content` sous forme de chaîne simple, soit un `content` sous forme de liste de blocs au style Anthropic. Les paramètres d'échantillonnage (`temperature`, `max_tokens`, etc.) peuvent être passés en kwargs supplémentaires. + +--- + +### `event.model_response()` + +Émis lorsque le LLM retourne une réponse. + +```python +agenteye.event.model_response( + session_id="run-001", + agent_id="planner", + model="claude-sonnet-4-6", # str | None + stop_reason="end_turn", # str | None + input_tokens=1024, # int | None + output_tokens=256, # int | None + content=[ # Any | None - str ou liste de blocs de contenu + {"type": "text", "text": "..."}, + ], + role="assistant", # str | None +) +``` + +`content` accepte soit une chaîne simple (fournisseurs génériques), soit une liste de blocs de contenu au style Anthropic. Les appels d'outils se trouvent dans `content` sous forme de blocs `{"type": "tool_use", ...}`, sans champ `tool_calls` séparé. + +--- + +### `event.hook_triggered()` + +Émis lorsqu'un hook se déclenche. À associer avec `hook_completed` ; le SDK calcule automatiquement `duration_ms`. + +```python +agenteye.event.hook_triggered( + session_id="run-001", + agent_id="planner", + hook_name="pre_tool_use", # str, requis + hook_id="hook-abc", # str, requis - clé de corrélation + trigger_event="tool_use", # str | None + input={"tool": "search"}, # Any | None +) +``` + +--- + +### `event.hook_completed()` + +Émis lorsqu'un hook se termine. Se corrèle avec `hook_triggered` via `hook_id`. + +```python +agenteye.event.hook_completed( + session_id="run-001", + agent_id="planner", + hook_name="pre_tool_use", + hook_id="hook-abc", # doit correspondre au hook_triggered précédent + outcome="allow", # str | None + output=None, # Any | None + error=None, # str | None + # duration_ms est calculé automatiquement - ne pas le passer +) +``` + +--- + +### `event.error()` + +Émis lorsqu'une erreur non gérée survient. + +```python +agenteye.event.error( + session_id="run-001", + agent_id="planner", + error_type="TimeoutError", # str, requis + message="timed out", # str, requis + traceback="Traceback...", # str | None +) +``` + +--- + +## Événements humain dans la boucle + +Les événements humain dans la boucle vous permettent de superviser les moments où une personne intervient dans l'exécution de l'agent (en attendant une approbation, en fournissant une entrée, en mettant en pause ou en arrêtant l'agent). Ils vous permettent de mesurer le temps de réponse des humains (le SDK calcule automatiquement `duration_ms` sur les événements appariés), d'auditer qui a mis en pause ou interrompu un agent, et de construire des workflows d'approbation et de supervision qui apparaissent dans le tableau de bord. + +### `event.human_wait()` + +Émis lorsque l'agent suspend son exécution pour attendre une entrée humaine. À associer avec `human_input` ; le SDK calcule automatiquement `duration_ms` (le temps que l'humain a mis pour répondre). + +```python +agenteye.event.human_wait( + session_id="run-001", + agent_id="planner", + input_id="inp-abc", # str, requis - clé de corrélation pour le human_input correspondant + prompt="Do you approve this action?", # str | None - la question affichée à l'humain + options=["approve", "reject", "defer"], # list[str] | None - choix présentés à l'humain + reason="approval_required", # str | None - raison de l'attente de l'agent +) +``` + +### `event.human_input()` + +Émis lorsqu'un humain fournit une entrée et que l'agent reprend son exécution. Se corrèle avec `human_wait` via `input_id`. `duration_ms` est calculé automatiquement et ne doit pas être passé par l'appelant. + +```python +agenteye.event.human_input( + session_id="run-001", + agent_id="planner", + input_id="inp-abc", # str, requis - doit correspondre au human_wait précédent + response="approve", # str | None - la réponse de l'humain (texte libre ou option sélectionnée) + # duration_ms est calculé automatiquement - ne pas le passer +) +``` + +### `event.human_pause()` + +Émis lorsqu'un humain met activement l'agent en pause (par exemple via un contrôle du tableau de bord). L'agent est suspendu mais pas arrêté. + +```python +agenteye.event.human_pause( + session_id="run-001", + agent_id="planner", + reason="user_requested", # str | None + user_id="usr_42", # str | None - qui a mis l'agent en pause +) +``` + +### `event.human_interrupt()` + +Émis lorsqu'un humain arrête activement l'agent en cours d'exécution. Contrairement à `human_pause`, le travail de l'agent est terminé plutôt que suspendu. + +```python +agenteye.event.human_interrupt( + session_id="run-001", + agent_id="planner", + reason="output_incorrect", # str | None + user_id="usr_42", # str | None - qui a interrompu l'agent + at_step="tool_use:web_search", # str | None - ce que l'agent faisait au moment de l'arrêt +) +``` + +--- + +## Champs personnalisés + +Tout argument nommé supplémentaire est ajouté à l'événement après les champs standard : + +```python +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="db_query", + tool_call_id="toolu_02", + tenant_id="acme", # champ personnalisé + region="us-east-1", # champ personnalisé +) +``` + +`timestamp`, `type` et `environment` sont réservés et lèvent une `ValueError` (`Reserved field names cannot be used as custom fields: [...]`) s'ils sont passés comme champs personnalisés. `session_id` et `agent_id` sont des paramètres obligatoires sur chaque méthode d'événement et ne peuvent pas être fournis une seconde fois ; Python lève une `TypeError` si vous le faites. Définissez l'environnement avec `configure(environment=...)` (ou la variable `AGENTEYE_ENVIRONMENT`) à la place. + +--- + +## Comment les événements sont écrits + +Les événements sont mis en mémoire tampon dans le processus et vidés sur disque toutes les `flush_interval` secondes (500 ms par défaut). Chaque vidage écrit un fichier JSONL : + +``` +~/.agenteye/events/event-2026-04-01T12-00-00-000Z.jsonl +``` + +Le collecteur surveille ce répertoire et télécharge les fichiers automatiquement. Vous n'avez pas besoin de gérer ces fichiers directement. \ No newline at end of file diff --git a/docs/fr/agenteye/single-pod-deployment.mdx b/docs/fr/agenteye/single-pod-deployment.mdx new file mode 100644 index 00000000..917f9496 --- /dev/null +++ b/docs/fr/agenteye/single-pod-deployment.mdx @@ -0,0 +1,484 @@ +--- +title: "Déploiement Single-Pod : Collector + Sidecar Application sur EKS" +description: "Documentation AgentEye — Déploiement Single-Pod : Collector + Sidecar Application sur EKS." +--- + + +Exécutez votre application et le collector AgentEye **dans le même Pod Kubernetes** afin que la télémétrie ne traverse jamais une frontière réseau pour être collectée. Le SDK de votre application et le collector partagent une file d'événements in-pod unique, ce qui garantit un transfert de télémétrie à faible latence, en mémoire partagée — sans port localhost à exposer, sans service mesh à traverser, et avec le cycle de vie du collector directement lié au workload qu'il observe. Le certificat client mTLS que présente le collector est injecté directement dans votre pod depuis AWS Secrets Manager, de sorte que la rotation des credentials ne nécessite aucune manipulation manuelle de fichiers de votre côté. + +Le modèle sidecar + file partagée décrit ici est agnostique au cloud ; deux conteneurs partageant un `emptyDir` comme file d'événements fonctionnent sur n'importe quelle distribution Kubernetes. Seul le chemin de livraison des certificats dans ce guide (AWS Secrets Manager + le Secrets Store CSI Driver + IRSA) est spécifique à AWS / EKS. Si vous déployez ailleurs, conservez la disposition du pod et de la file, et substituez le mécanisme de montage de secrets de votre plateforme aux phases 2 et 3. + +> **Quand utiliser ce pattern.** Choisissez le single-pod lorsque votre application ne doit pas traverser une frontière réseau pour atteindre le collector (IPC in-pod à faible latence, couplage fort du cycle de vie, isolation par pod et par tenant). Pour les flottes multi-applications partageant un seul collector par nœud ou par cluster, consultez plutôt [enterprise-docs/kubernetes-deployment.md](/fr/agenteye/kubernetes-deployment). + +--- + +## Vue d'ensemble + +``` +┌──────────────────────────────── Pod ─────────────────────────────────┐ +│ │ +│ ┌──────────────────────┐ ┌──────────────────────┐ │ +│ │ your-app │ │ agenteye-collector │ │ +│ │ (SDK writes JSONL) │ │ (sweeps events/, │ │ +│ │ │ │ uploads over mTLS) │ │ +│ └──────────┬───────────┘ └──────────┬───────────┘ │ +│ │ writes reads │ │ +│ ▼ ▼ │ +│ ┌────────────────────────────────────────────────────┐ │ +│ │ emptyDir: /var/lib/agenteye/{events,failed}/ │ │ +│ │ (AGENTEYE_HOME - shared event spool) │ │ +│ └────────────────────────────────────────────────────┘ │ +│ ▲ │ +│ │ reads cert │ +│ ┌────────┴─────────┐ │ +│ │ CSI (read-only): │ │ +│ │ /etc/agenteye/ │ │ +│ │ tls/client.{crt, │ │ +│ │ key}, ca.crt │ │ +│ └────────┬─────────┘ │ +└───────────────────────────────────────────────────┼──────────────────┘ + │ mounted by + │ Secrets Store CSI + │ (AWS provider + + │ IRSA) + ┌────────┴──────────┐ + │ AWS Secrets │ + │ Manager │ + │ agenteye/mtls- │ + │ client/ │ + └────────┬──────────┘ + ▲ + │ push on issue / + │ renewal + ┌────────┴──────────┐ + │ Exosphere │ + │ delivers the cert │ + │ bundle into your │ + │ Secrets Manager │ + │ on renewal │ + └───────────────────┘ + +Outbound: collector → AGENTEYE_URL (mTLS, using the CSI-mounted cert). +``` + +Deux flux de données, deux volumes : + +- **Événements (in-pod) :** le SDK de votre application écrit des fichiers `.jsonl` dans l'`emptyDir` partagé sous `$AGENTEYE_HOME/events/` ; le sweeper du collector les lit et les envoie. Pas de port localhost, pas de loopback — un transfert purement basé sur le système de fichiers partagé. +- **Certificat mTLS (pod ← cloud) :** le Secrets Store CSI Driver monte le bundle de certificats depuis Secrets Manager dans un volume en lecture seule sous `/etc/agenteye/tls/`, limité au conteneur collector. + +**Deux parties indépendantes :** + +| Partie | Responsabilité | +|---|---| +| Exosphere | Émet le certificat client mTLS et livre le bundle dans le Secrets Manager de **votre** compte AWS sous un nom stable. Republié le bundle renouvelé dans le même secret avant expiration. | +| Vous | Installez le Secrets Store CSI Driver, accordez au ServiceAccount du pod un accès en lecture au secret via IRSA, et appliquez le manifeste Pod. C'est tout. | + +--- + +## Prérequis + +### Dans votre compte AWS / cluster EKS + +- Un cluster EKS avec un **fournisseur OIDC** associé. Vérifiez avec : + + ```bash + aws eks describe-cluster --name \ + --query "cluster.identity.oidc.issuer" --output text + ``` + + Si la commande retourne une URL `https://oidc.eks.…`, OIDC est activé. Sinon, associez-en un : + + ```bash + eksctl utils associate-iam-oidc-provider \ + --cluster --approve + ``` + +- Le [Secrets Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/) et le [fournisseur AWS](https://github.com/aws/secrets-store-csi-driver-provider-aws) installés dans le cluster (voir § Phase 2). + +- AWS CLI v2 et `kubectl` sur votre poste de travail. + +### Coordination avec Exosphere + +Avant de déployer, Exosphere livre le bundle client mTLS dans le Secrets Manager de votre compte AWS et vous fournit : + +- Le **nom du secret** (convention : `agenteye/mtls-client/`) +- La **région AWS** dans laquelle réside le secret +- L'**URL du backend AgentEye** à configurer pour le collector +- Votre **clé API** du collector (voir [enterprise-docs/api-keys.md](/fr/agenteye/api-keys)) + +--- + +## Phase 1 : Ce que livre Exosphere + +Vous ne générez pas vous-même le certificat client mTLS. Exosphere l'émet et livre le bundle directement dans le Secrets Manager de votre compte AWS, de sorte que le seul matériel de credentials qui arrive dans votre environnement est le secret terminé, prêt à être monté. + +Ce qui arrive dans votre compte : + +| Propriété | Valeur | +|---|---| +| Nom du secret | `agenteye/mtls-client/` (stable entre les renouvellements) | +| Région | La région AWS que vous avez désignée pour votre cluster EKS | +| Contenu | Un secret JSON unique avec trois clés (`client.crt`, `client.key` et `ca.crt`), chacune contenant le matériel encodé en PEM | +| Tag | `AgentEyeCluster=` | + +Lors du renouvellement, le même secret est mis à jour sur place avec une nouvelle version, de sorte que l'ARN et le nom ne changent jamais ; votre `SecretProviderClass` et votre politique IAM continuent de fonctionner sans modification. Pour le cycle de vie du certificat (validité, cadence de renouvellement, alertes d'expiration), consultez [enterprise-docs/kubernetes-deployment.md](/fr/agenteye/kubernetes-deployment). + +--- + +## Phase 2 : Installer le Secrets Store CSI Driver + le fournisseur AWS + +Ignorez cette étape si vous faites déjà tourner un autre workload qui monte des secrets AWS via CSI. + +```bash +# CSI Driver +helm repo add secrets-store-csi-driver \ + https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts +helm install -n kube-system csi-secrets-store \ + secrets-store-csi-driver/secrets-store-csi-driver \ + --set syncSecret.enabled=true \ + --set enableSecretRotation=true \ + --set rotationPollInterval=1h + +# AWS provider +kubectl apply -f \ + https://raw.githubusercontent.com/aws/secrets-store-csi-driver-provider-aws/main/deployment/aws-provider-installer.yaml +``` + +**Vérification :** + +```bash +kubectl get pods -n kube-system | grep -E 'csi-secrets-store|aws-provider' +``` + +Résultat attendu : `Running` pour chaque pod. + +> **Pourquoi `rotationPollInterval=1h` ?** Lorsqu'Exosphere publie un certificat renouvelé, Secrets Manager est mis à jour sur place. Le CSI Driver relit le secret à cet intervalle et réécrit les fichiers montés. Le collector lit les fichiers de certificats une seule fois au démarrage, donc il commence à présenter le certificat renouvelé uniquement après un redémarrage du processus ; voir § Rotation des certificats pour savoir comment en déclencher un. + +--- + +## Phase 3 : Accorder au pod l'accès en lecture au secret (IRSA) + +### 3.1 Créer la politique IAM + +Enregistrez sous `agenteye-mtls-reader-policy.json` : + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "ReadAgentEyeMtlsBundle", + "Effect": "Allow", + "Action": [ + "secretsmanager:GetSecretValue", + "secretsmanager:DescribeSecret" + ], + "Resource": "arn:aws:secretsmanager:::secret:agenteye/mtls-client/-*" + } + ] +} +``` + +Remplacez ``, `` et ``. Le `-*` final correspond au suffixe aléatoire de six caractères qu'AWS ajoute à chaque ARN de secret. + +Créez la politique : + +```bash +aws iam create-policy \ + --policy-name AgentEyeMtlsReader- \ + --policy-document file://agenteye-mtls-reader-policy.json +``` + +### 3.2 Créer le rôle IAM et le lier au ServiceAccount du pod + +```bash +eksctl create iamserviceaccount \ + --name agenteye-pod \ + --namespace \ + --cluster \ + --role-name AgentEyePodRole- \ + --attach-policy-arn arn:aws:iam:::policy/AgentEyeMtlsReader- \ + --approve +``` + +Cette commande crée un `ServiceAccount` nommé `agenteye-pod` avec l'annotation `eks.amazonaws.com/role-arn` pointant vers le nouveau rôle. + +### 3.3 Récapitulatif des permissions IAM requises + +| Permission | Périmètre | Pourquoi | +|---|---|---| +| `secretsmanager:GetSecretValue` | `arn:aws:secretsmanager:::secret:agenteye/mtls-client/-*` | Le CSI Driver lit le bundle de certificats à chaque montage et à chaque tick de rotation. | +| `secretsmanager:DescribeSecret` | identique | Le CSI Driver appelle `DescribeSecret` pour détecter les changements de version entre les sondages. | + +**N'accordez PAS** `secretsmanager:PutSecretValue`, `secretsmanager:UpdateSecret` ou `secretsmanager:DeleteSecret` au pod. Le pod ne fait que lire le secret ; l'écriture de nouvelles versions est gérée par Exosphere lors de l'émission ou du renouvellement du certificat. + +Si le secret est chiffré avec une clé KMS gérée par le client (et non la clé `aws/secretsmanager` par défaut), accordez également : + +```json +{ + "Effect": "Allow", + "Action": ["kms:Decrypt"], + "Resource": "arn:aws:kms:::key/", + "Condition": { + "StringEquals": { + "kms:ViaService": "secretsmanager..amazonaws.com" + } + } +} +``` + +--- + +## Phase 4 : Déployer le Pod + +### 4.1 SecretProviderClass + +`agenteye-mtls-spc.yaml` : + +```yaml +apiVersion: secrets-store.csi.x-k8s.io/v1 +kind: SecretProviderClass +metadata: + name: agenteye-mtls + namespace: +spec: + provider: aws + parameters: + objects: | + - objectName: "agenteye/mtls-client/" + objectType: "secretsmanager" + jmesPath: + - path: '"client.crt"' + objectAlias: "client.crt" + - path: '"client.key"' + objectAlias: "client.key" + - path: '"ca.crt"' + objectAlias: "ca.crt" +``` + +Le bloc `jmesPath` indique au fournisseur AWS de scinder le secret JSON en trois fichiers distincts sur le disque. Les guillemets dans `'"client.crt"'` sont requis parce que JMESPath traite `.` comme un opérateur de sous-expression. + +```bash +kubectl apply -f agenteye-mtls-spc.yaml +``` + +### 4.2 Manifeste Pod / Deployment + +**Comment les deux conteneurs communiquent.** Le SDK AgentEye et le collector ne communiquent pas via un socket réseau ; il n'y a pas de port HTTP local. Le SDK écrit des lots d'événements sous forme de fichiers `.jsonl` dans `$AGENTEYE_HOME/events/`, et le collector surveille en continu ce répertoire et envoie chaque fichier. Pour un pod sidecar, cela signifie : + +- Les deux conteneurs montent le **même** volume `emptyDir` au **même** chemin. +- Les deux conteneurs définissent `AGENTEYE_HOME` sur ce chemin. +- L'image de votre application doit avoir le SDK AgentEye installé et configuré (voir [enterprise-docs/python-sdk.md](/fr/agenteye/python-sdk)). + +> Lorsque `AGENTEYE_HOME` n'est pas défini, le SDK et le collector utilisent par défaut `~/.agenteye`, et les deux conteneurs ont des répertoires home différents — ils se retrouveraient donc sur deux files séparées et le transfert échouerait silencieusement. Définissez `AGENTEYE_HOME` sur le même chemin explicite sur **les deux** conteneurs. La vérification §4.3 et la ligne correspondante dans le tableau de dépannage permettent de détecter ce cas si vous l'oubliez. + +`agenteye-pod.yaml` (Deployment avec un replica, à faire évoluer selon vos besoins) : + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-app-with-collector + namespace: +spec: + replicas: 1 + selector: + matchLabels: + app: my-app-with-collector + template: + metadata: + labels: + app: my-app-with-collector + spec: + serviceAccountName: agenteye-pod + containers: + - name: app + image: + env: + # SDK writes event JSONL files into $AGENTEYE_HOME/events/ + - name: AGENTEYE_HOME + value: /var/lib/agenteye + volumeMounts: + - name: agenteye-spool + mountPath: /var/lib/agenteye + + - name: agenteye-collector + # Pin to a versioned :v tag for production; :beta-latest + # tracks the current beta build (:latest exists only for stable releases). + image: ghcr.io/agenteye-enterprise/collector:beta-latest + args: ["start"] + env: + # Must match the app container's AGENTEYE_HOME so the collector + # sweeps the same directory the SDK writes to. + - name: AGENTEYE_HOME + value: /var/lib/agenteye + - name: AGENTEYE_URL + value: "https://ingest.example.agenteye.com/events" + - name: AGENTEYE_KEY + valueFrom: + secretKeyRef: + name: agenteye-collector-api-key + key: key + - name: AGENTEYE_TLS_CERT + value: /etc/agenteye/tls/client.crt + - name: AGENTEYE_TLS_KEY + value: /etc/agenteye/tls/client.key + # Only when the AgentEye server presents a cert not signed by a + # publicly-trusted CA (e.g. self-signed by an in-cluster issuer + # because you have no real DNS domain). The CSI mount already + # exposes ca.crt alongside the client cert/key. + - name: AGENTEYE_TLS_CA + value: /etc/agenteye/tls/ca.crt + volumeMounts: + - name: agenteye-spool + mountPath: /var/lib/agenteye + - name: agenteye-mtls + mountPath: /etc/agenteye/tls + readOnly: true + livenessProbe: + exec: + command: ["agenteye-collector", "health"] + initialDelaySeconds: 10 + periodSeconds: 30 + + volumes: + # Shared event spool between app and collector. emptyDir is fine: + # events are transient and the collector drains them before pod + # termination on graceful shutdown. + - name: agenteye-spool + emptyDir: {} + # mTLS cert bundle, mounted read-only into the collector only. + - name: agenteye-mtls + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: agenteye-mtls +``` + +Le Secret `agenteye-collector-api-key` contient la clé API du collector (voir [enterprise-docs/api-keys.md](/fr/agenteye/api-keys) pour le provisionnement). + +**Appliquer :** + +```bash +kubectl apply -f agenteye-pod.yaml +``` + +### 4.3 Vérification + +```bash +# Le pod doit être Running avec 2/2 conteneurs prêts +kubectl get pods -n -l app=my-app-with-collector + +# Confirmer que le bundle de certificats a été monté +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- ls -l /etc/agenteye/tls/ +``` + +Résultat attendu : `client.crt`, `client.key`, `ca.crt` tous présents en lecture seule, appartenant à l'utilisateur du conteneur. + +**Confirmer que la file d'événements partagée est visible par les deux conteneurs :** + +```bash +# Dans le collector, doit afficher les sous-répertoires events/ et failed/ +# que le collector crée automatiquement au démarrage : +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- ls /var/lib/agenteye/ + +# Dans l'application, doit afficher le même contenu de répertoire : +kubectl exec -n deploy/my-app-with-collector \ + -c app -- ls /var/lib/agenteye/ +``` + +Si les deux listings divergent, le volume n'est pas monté dans les deux conteneurs (ou `AGENTEYE_HOME` diffère) ; voir § Dépannage. + +**Test de fumée de bout en bout :** + +```bash +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- agenteye-collector flush +``` + +Résultat attendu : le collector envoie tous les événements en attente et affiche un résumé `Done: N/N uploaded, 0 failed.`. Si la file est vide, il affiche `No pending files.` et se termine sans rien valider — exécutez donc cette commande uniquement après que votre application a vidé au moins un événement. + +Notez que `flush` se termine avec un code non nul **uniquement** pour des défauts de configuration locale : configuration manquante (aucune URL/clé résolue) ou certificat TLS illisible/non parsable (voir § Dépannage). Une **mauvaise clé API ne modifie pas le code de sortie** — l'envoi reçoit un `401`, le fichier est déplacé vers `failed/`, et la commande affiche tout de même `[FAILED] …` par fichier, puis `Done: 0/N uploaded, N failed.` et se termine avec `0`. Pour détecter une mauvaise clé ou un envoi rejeté, lisez la sortie `Done:`/`[FAILED]` ou vérifiez la présence de fichiers dans `$AGENTEYE_HOME/failed/`, et non le code de sortie. + +--- + +## Rotation des certificats + +Le certificat client est valide 90 jours et est renouvelé automatiquement environ 15 jours avant expiration ; Exosphere publie ensuite le bundle renouvelé dans le même secret Secrets Manager. De là, le flux in-pod est le suivant : + +1. Le secret Secrets Manager reçoit une nouvelle version `AWSCURRENT`. L'ARN et le nom sont inchangés. +2. Dans le délai de `rotationPollInterval` (1h par défaut ; voir § Phase 2), le CSI Driver lit la nouvelle version et réécrit les fichiers sous `/etc/agenteye/tls/`. +3. Le collector charge les fichiers de certificats **une seule fois au démarrage**, donc il continue de présenter l'ancien certificat jusqu'au redémarrage du processus. Pour basculer vers le matériel renouvelé, redémarrez le collector ; un rolling restart suffit : + + ```bash + kubectl rollout restart deploy/my-app-with-collector -n + ``` + + Pour automatiser cela, ajoutez un sidecar qui surveille `/etc/agenteye/tls/` (par exemple avec `inotifywait`) et déclenche le rollout lorsque les fichiers changent. + +Comme l'ancien certificat reste valide environ 15 jours après le renouvellement, vous disposez d'une large fenêtre pour effectuer le redémarrage sans interruption de l'ingestion. Exosphere publie le bundle renouvelé pour vous ; la seule action de routine de votre côté est de vous assurer que le collector redémarre dans cette fenêtre. + +--- + +## Dépannage + +| Symptôme | Cause probable | Correction | +|---|---|---| +| Pod bloqué en `ContainerCreating`, les événements montrent `MountVolume.SetUp failed for volume "agenteye-mtls"` | Le fournisseur CSI ne peut pas atteindre Secrets Manager | Vérifiez que l'IRSA est correctement lié : `kubectl describe sa agenteye-pod -n ` affiche l'annotation `eks.amazonaws.com/role-arn`. Vérifiez CloudTrail pour l'appel AssumeRole. | +| Erreur : `AccessDeniedException: not authorized to perform secretsmanager:GetSecretValue` | La politique IAM est limitée au mauvais ARN | Le suffixe d'ARN du secret est aléatoire ; utilisez `agenteye/mtls-client/-*` avec le joker, pas l'ARN exact. | +| Erreur : `ParameterNotFound` du fournisseur AWS | Inadéquation entre le nom du secret dans `SecretProviderClass.objects[].objectName` et le secret livré par Exosphere | Confirmez le nom exact avec `aws secretsmanager list-secrets --filters Key=tag-key,Values=AgentEyeCluster`. | +| Erreur `jmesPath`, un seul fichier monté | Syntaxe JMESPath incorrecte | Les points dans les clés JSON nécessitent des guillemets doubles : `'"client.crt"'`, pas `client.crt`. | +| Le collector journalise `tls: bad certificate` après un renouvellement | Le CSI Driver n'a pas encore sondé la nouvelle version, ou le collector tourne encore avec l'ancien certificat chargé au démarrage | Confirmez que les fichiers montés ont été mis à jour (`ls -l /etc/agenteye/tls/`), puis redémarrez le collector pour les charger : `kubectl rollout restart deploy/my-app-with-collector -n `. Voir § Rotation des certificats. | +| Le conteneur collector crashloope avec `no such file or directory: /etc/agenteye/tls/client.crt` | Volume pas encore peuplé au premier démarrage ; probe de démarrage trop agressive | Ajoutez un délai initial ou utilisez un init container qui attend que le fichier existe : `until [ -f /etc/agenteye/tls/client.crt ]; do sleep 1; done`. | +| Pod CSI Driver en `OOMKilled` | Limites mémoire par défaut trop basses pour les clusters avec de nombreuses SecretProviderClasses | Augmentez avec `--set linux.resources.limits.memory=200Mi` dans l'installation Helm. | +| L'application tourne correctement, `agenteye-collector flush` indique `No pending files.`, mais le tableau de bord AgentEye ne montre aucun événement | L'application et le collector ne partagent pas la file d'événements | Vérifiez que (a) les deux conteneurs montent le même `emptyDir` `agenteye-spool` au même chemin, et (b) les deux définissent `AGENTEYE_HOME` sur ce chemin. Exécutez les deux vérifications `ls /var/lib/agenteye/` du § 4.3 ; les listings doivent correspondre. | + +**Logs à récupérer en premier :** + +```bash +kubectl logs -n kube-system -l app=secrets-store-csi-driver --tail=100 +kubectl logs -n kube-system -l app=csi-secrets-store-provider-aws --tail=100 +kubectl describe pod -n -l app=my-app-with-collector +``` + +--- + +## Référence : fichiers sur le disque dans le pod + +Le pod dispose de deux chemins de données sur le disque : + +### Bundle de certificats mTLS : `/etc/agenteye/tls/` (CSI, lecture seule, collector uniquement) + +Monté par le Secrets Store CSI Driver depuis AWS Secrets Manager. + +| Fichier | Contenu | Utilisé par le collector comme | +|---|---|---| +| `client.crt` | Certificat client encodé PEM | `AGENTEYE_TLS_CERT` | +| `client.key` | Clé privée encodée PEM | `AGENTEYE_TLS_KEY` | +| `ca.crt` | Certificat CA encodé PEM | `AGENTEYE_TLS_CA` (optionnel, uniquement lorsque le certificat serveur AgentEye n'est pas approuvé publiquement) | + +Les trois fichiers sont montés en lecture seule et appartiennent à l'utilisateur du conteneur. Ils sont réécrits par le CSI Driver lors de la rotation du secret. + +### File d'événements : `$AGENTEYE_HOME/` (emptyDir, partagé en lecture-écriture entre les deux conteneurs) + +Partagée via un volume `emptyDir` nommé `agenteye-spool`. + +| Chemin | Écrit par | Lu par | Objectif | +|---|---|---|---| +| `$AGENTEYE_HOME/events/*.jsonl` | Application (SDK AgentEye) | Sweeper du collector | Lots d'événements que le SDK a vidés, en attente d'envoi. | +| `$AGENTEYE_HOME/failed/` | Collector (en cas d'échec d'envoi) | Vous (lors du débogage) | Fichiers JSONL que le collector n'a pas pu envoyer après plusieurs tentatives. | +| `$AGENTEYE_HOME/config.json` | Vous (optionnel) | Collector | Fichier de configuration optionnel du collector (alternative aux variables d'environnement). | + +Les sous-répertoires `events/` et `failed/` sont créés automatiquement par le collector au démarrage ; aucun `initContainer` n'est nécessaire. + +--- + +## Documentation associée + +- [enterprise-docs/collector-installation.md](/fr/agenteye/collector-installation) : options du binaire collector, référence de configuration mTLS, modes daemon. +- [enterprise-docs/kubernetes-deployment.md](/fr/agenteye/kubernetes-deployment) : déploiement multi-pod, détails internes de l'émission des certificats, cycle de vie et alertes d'expiration. +- [enterprise-docs/api-keys.md](/fr/agenteye/api-keys) : provisionnement de la clé API du collector utilisée par le pod. +- [enterprise-docs/troubleshooting.md](/fr/agenteye/troubleshooting) : index de dépannage à l'échelle du cluster. \ No newline at end of file diff --git a/docs/fr/agenteye/tenant-management.mdx b/docs/fr/agenteye/tenant-management.mdx new file mode 100644 index 00000000..834c223c --- /dev/null +++ b/docs/fr/agenteye/tenant-management.mdx @@ -0,0 +1,166 @@ +--- +title: "Gestion des tenants (organisations et membres)" +description: "Documentation AgentEye sur la gestion des tenants (organisations et membres)." +--- + +Un seul déploiement AgentEye sert plusieurs **organisations** (tenants) totalement isolées, ce qui permet à une seule instance d'héberger des équipes, des unités métier ou des clients distincts sans exposer les données d'un tenant à un autre. Chaque ligne de données (événements, évaluations, sessions, tableaux de bord, requêtes sauvegardées, alertes, clés API et membres) appartient à exactement une organisation. L'isolation principale est appliquée dans le code applicatif : chaque requête est limitée à son organisation via des prédicats `org_id` explicites. Sur ClickHouse — où vivent les événements et évaluations à fort volume — cela est renforcé par une isolation au niveau du moteur : chaque organisation reçoit un utilisateur ClickHouse dédié en lecture seule avec une politique de lignes par organisation, de sorte que même du SQL analytique non fiable ne peut jamais lire les lignes d'un autre tenant. Sur PostgreSQL, la sécurité au niveau des lignes (row-level security) ajoute une défense en profondeur sur le chemin de requête en lecture seule (`/queries/run`), limitant ce que ce chemin peut voir même si un filtre au niveau applicatif venait à manquer ; la connexion d'écriture du serveur s'exécute en tant que propriétaire de la table et opère donc via le même filtrage `org_id` au niveau applicatif. + +Le cycle de vie des tenants est contrôlé par les opérateurs, tandis que tout ce que font les membres au quotidien reste en libre-service dans le tableau de bord. Les organisations et leurs adhésions sont créées et gérées avec le CLI **`agenteye-orgctl`**, qui est fourni dans l'image du serveur et s'exécute **à l'intérieur du pod serveur existant**. La création et la suppression de tenants sont délibérément exclues du tableau de bord et de l'API HTTP : il n'existe **ni API HTTP ni bouton dans le tableau de bord** pour le cycle de vie des tenants, de sorte que cela est protégé par un accès shell au cluster/pod plutôt que par la surface applicative. + +Au sein d'une organisation, les membres travaillent entièrement dans le tableau de bord et l'API : ils se connectent, basculent entre les organisations auxquelles ils appartiennent, gèrent leurs propres clés API, créent des tableaux de bord et des requêtes sauvegardées, et configurent des alertes pour leur organisation. La séparation est nette : les opérateurs provisionnent et décommissionnent les tenants et leurs membres via le CLI ; les membres gèrent tout à l'intérieur d'un tenant via l'interface utilisateur. + +> **Les déploiements mono-tenant n'ont besoin de rien de tout cela.** Une installation mono-tenant fonctionne sans aucune action de l'opérateur. Toutes les données, utilisateurs et clés résident dans une organisation `default` intégrée qui est provisionnée automatiquement. Ce guide n'est nécessaire que si vous décidez d'ajouter une deuxième organisation. + +--- + +## Prérequis + +Avant de créer votre **deuxième** organisation (l'organisation `default` intégrée n'a besoin de rien) : + +- **PostgreSQL 15+.** Le schéma d'adhésion aux organisations utilise une clé étrangère `ON DELETE SET NULL` avec liste de colonnes qui requiert PostgreSQL 15+. Mettez à jour PostgreSQL avant de provisionner une deuxième organisation. +- **Un `ORG_CH_SECRET` robuste et stable.** Le mot de passe ClickHouse de chaque organisation est dérivé sous la forme `HMAC(ORG_CH_SECRET, org_id)`. Utiliser la valeur par défaut de développement intégrée — connue publiquement — produirait des identifiants par organisation dérivables publiquement. `agenteye-orgctl org create` **refuse de s'exécuter si `ORG_CH_SECRET` n'est pas défini ou s'il est laissé à la valeur par défaut de développement intégrée**. Définissez d'abord votre propre valeur (voir [Déploiement → variables d'environnement](/fr/agenteye/deployment) et, sur Kubernetes, [§2.6 du guide Kubernetes](/fr/agenteye/kubernetes-deployment#26-multi-tenant-org-isolation-key-optional)). Gardez-la identique sur tous les réplicas du serveur et ne la changez pas à la légère ; la changer orphelise l'utilisateur ClickHouse de chaque organisation jusqu'au prochain démarrage qui les re-provisionne. + +--- + +## Exécution du CLI + +`agenteye-orgctl` est fourni dans la **même image que le serveur** (aux côtés de `agenteye-server`). Vous ne déployez **pas** de pod, Job ou Deployment séparé pour lui ; vous l'exécutez à l'intérieur du pod serveur déjà en cours d'exécution, de sorte qu'il lit les mêmes `DATABASE_URL`, `CLICKHOUSE_URL` et `ORG_CH_SECRET` que le serveur utilise. + +**Kubernetes :** + +```bash +kubectl -n agenteye exec deploy/server -- agenteye-orgctl +``` + +**Docker Compose :** + +```bash +docker compose exec server agenteye-orgctl +``` + +Les exemples ci-dessous montrent le `agenteye-orgctl ` brut par souci de concision ; faites précéder chacun de l'une des deux lignes ci-dessus correspondant à votre déploiement. + +--- + +## Référence des commandes + +### Organisations + +| Commande | Ce qu'elle fait | +|---|---| +| `org create --slug --name ` | Crée une nouvelle organisation. Refuse de s'exécuter si `ORG_CH_SECRET` n'est pas défini ou est laissé à la valeur par défaut de développement intégrée (définissez d'abord la vôtre, voir Prérequis). Provisionne l'utilisateur ClickHouse en lecture seule et la politique de lignes de l'organisation. | +| `org list` | Liste toutes les organisations (slug, nom et état du cycle de vie). | +| `org rename --slug --name ` | Modifie le nom d'affichage d'une organisation. Le slug (utilisé dans les URLs et les clés) reste inchangé. | +| `org delete --slug ` | **Suppression logique** de l'organisation et suppression de son utilisateur ClickHouse. Les données sont **conservées**. Cela révoque l'accès et libère le justificatif ClickHouse par organisation, mais n'efface pas les événements. Réversible par les opérateurs ; première étape sûre avant une purge. | +| `org purge --slug ` | **Effacement irréversible des données.** L'organisation doit déjà avoir été `delete`ée. Jamais autorisé sur l'organisation `default` intégrée. À utiliser uniquement lorsque vous êtes certain que les données du tenant doivent être détruites. | + +### Membres + +| Commande | Ce qu'elle fait | +|---|---| +| `member add --org --email [--set ] [--add perm1,perm2] [--remove perm3] [--protected]` | Ajoute un membre à une organisation. Optionnellement, part d'un ensemble de permissions intégré, puis ajoute/supprime des permissions individuelles. `--protected` épingle le membre pour que le tableau de bord ne puisse pas le supprimer ou le rétrograder (voir ci-dessous). Le nouveau membre reçoit un OTP lors de sa première connexion au tableau de bord. | +| `member list --org ` | Liste les membres de l'organisation. Les colonnes de sortie sont `EMAIL`, `SET` (l'ensemble intégré depuis lequel le membre a démarré, ou `-`), `PROT` (si le membre est protégé) et `PERMISSIONS` (ses permissions effectives). Un email affiché avec un `*` en fin de chaîne est un administrateur d'instance ; il a accès à toutes les organisations. | +| `member update --org --email [--set ...] [--add ...] [--remove ...] [--protected \| --unprotect]` | Modifie les permissions d'un membre et/ou son indicateur de protection. `--set` remplace à partir d'un ensemble intégré ; `--add` / `--remove` ajustent les permissions individuelles ; `--protected` / `--unprotect` basculent la protection. Passer uniquement `--protected`/`--unprotect` (sans indicateurs d'octroi) modifie uniquement la protection et laisse les permissions existantes inchangées. | +| `member remove --org --email ` | Retire un membre de l'organisation. Refuse si le membre est protégé ; utilisez d'abord `--unprotect`. (Une personne peut être membre de plusieurs organisations ; cela n'affecte que l'organisation nommée.) | + +Une personne peut être membre de plus d'une organisation avec des permissions **différentes** dans chacune, par exemple administrateur dans une organisation et en lecture seule dans une autre. Chaque adhésion est administrée indépendamment par organisation : accorder ou modifier les permissions d'une personne dans une organisation n'a aucun effet sur son appartenance à d'autres organisations. + +### Membres protégés (un administrateur d'organisation inamovible) + +La protection garantit qu'une organisation ne peut jamais accidentellement se bloquer hors de son auto-gestion. Par défaut, les administrateurs d'une organisation peuvent s'ajouter et se supprimer mutuellement via la page des utilisateurs en libre-service du tableau de bord, ce qui leur permettrait de supprimer le dernier administrateur et de laisser l'organisation sans personne pour la gérer. + +![La page Utilisateurs : une carte par utilisateur du tableau de bord avec son email, les permissions accordées et les contrôles d'édition/désactivation](/agenteye/images/users.png) + +Pour éviter cela, marquez un membre comme **protégé** : + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member add --org acme --email owner@acme.example --set admin --protected +``` + +Un membre protégé **ne peut pas être supprimé ou rétrogradé via le tableau de bord** ; ces actions renvoient une erreur. Seul un opérateur peut le modifier, et uniquement via ce CLI : exécutez d'abord `member update --org acme --email owner@acme.example --unprotect`, puis supprimez ou rétrogradez. Cela garantit que chaque organisation conserve au moins un administrateur que ses propres membres ne peuvent pas exclure, tout en maintenant le contrôle du tenant uniquement chez les opérateurs. La protection est **par organisation** ; protéger quelqu'un dans une organisation n'a aucun effet sur son adhésion dans une autre. + +### Ensembles de permissions intégrés + +`--set` accepte l'un des trois ensembles intégrés, appliqués par organisation : + +| Ensemble | Destiné à | +|---|---| +| `admin` | Accès complet au sein de l'organisation, y compris la gestion des clés API et des utilisateurs de l'organisation. | +| `standard` | Usage quotidien : lecture et exécution de requêtes, création de tableaux de bord, acquittement d'incidents. | +| `read-only` | Accès en lecture seule aux données et tableaux de bord de l'organisation. | + +Commencez par un ensemble avec `--set`, puis affinez avec `--add` / `--remove` en utilisant les jetons de permission individuels listés dans [Clés API](/fr/agenteye/api-keys). Les jetons de permission sont identiques à ceux utilisés pour les clés API. + +--- + +## Exemple pratique + +Provisionnez un nouveau tenant `acme`, ajoutez son premier administrateur, laissez-le créer une clé, puis décommissionnez l'organisation. + +**1. Créer l'organisation** (`ORG_CH_SECRET` doit déjà être défini avec une valeur robuste et stable, et non non-défini ou à la valeur par défaut de développement intégrée) : + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org create --slug acme --name "Acme Corp" +``` + +**2. Ajouter le premier membre en tant qu'administrateur de l'organisation :** + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member add --org acme --email alice@acme.example --set admin +``` + +Alice reçoit un OTP la première fois qu'elle se connecte au tableau de bord. À partir de là, elle travaille entièrement dans l'interface sous le préfixe URL de son organisation (ex. `/acme/sessions`). + +**3. Créer une clé API par organisation (dans le tableau de bord) :** + +L'opérateur ne crée **pas** de clés de données par organisation depuis le CLI. Alice (ou tout membre de l'organisation disposant de `keys:create`) crée des clés de collecteur/tableau de bord pour l'organisation `acme` depuis la page **Clés** du tableau de bord. Chaque clé qu'elle crée est automatiquement estampillée avec son organisation et ne peut lire ou écrire que les données d'`acme`. Voir [Clés API](/fr/agenteye/api-keys). + +**4. Modifier un membre ultérieurement :** + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member update --org acme --email alice@acme.example --add alerts:write + +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member list --org acme +``` + +**5. Suppression logique de l'organisation** (révoque l'accès et supprime son utilisateur ClickHouse ; données conservées) : + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org delete --slug acme +``` + +**6. Purger l'organisation** (irréversible ; uniquement après une suppression logique ; jamais l'organisation `default`) : + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org purge --slug acme +``` + +Sur Docker Compose, remplacez chaque préfixe `kubectl -n agenteye exec deploy/server --` par `docker compose exec server`. + +--- + +## Répartition des responsabilités + +Tout ce dont un membre de l'organisation a besoin au quotidien est en libre-service dans le tableau de bord et l'API, limité automatiquement à son organisation actuelle : + +- **Les clés API par organisation** sont créées et gérées par les membres de l'organisation dans le tableau de bord (ou via l'API des clés avec une clé portant `keys:create`). Le CLI ne crée **pas** de clés de données. Voir [Clés API](/fr/agenteye/api-keys). +- **Le changement d'organisation** est intégré au tableau de bord ; les membres basculent entre les organisations auxquelles ils appartiennent depuis le sélecteur d'organisation, et les pages limitées à une organisation se trouvent sous `//…`. +- **Les tableaux de bord, les requêtes sauvegardées, les alertes et toute utilisation des données** se font entièrement dans l'interface et l'API, limités à l'organisation actuelle du membre. + +L'opérateur, via `agenteye-orgctl`, est responsable uniquement du **cycle de vie** des organisations et des membres : créer / renommer / supprimer / purger une organisation, et ajouter / lister / mettre à jour / supprimer un membre. + +--- + +## Voir aussi + +- [Déploiement](/fr/agenteye/deployment) : `ORG_CH_SECRET` et le reste de l'environnement du serveur. +- [Déploiement Kubernetes](/fr/agenteye/kubernetes-deployment) : le §2.6 crée le Secret `agenteye-org-ch-secret` avant votre première organisation multi-tenant. +- [Clés API](/fr/agenteye/api-keys) : le modèle de clés par organisation et les jetons de permission utilisés par `--add` / `--remove`. +- [Dépannage](/fr/agenteye/troubleshooting) : provisionnement multi-tenant et problèmes d'isolation ClickHouse. \ No newline at end of file diff --git a/docs/fr/agenteye/troubleshooting.mdx b/docs/fr/agenteye/troubleshooting.mdx new file mode 100644 index 00000000..cd6f600e --- /dev/null +++ b/docs/fr/agenteye/troubleshooting.mdx @@ -0,0 +1,658 @@ +--- +title: "Dépannage" +description: "Documentation de dépannage AgentEye." +--- + + +Ce guide associe les symptômes les plus courants en production à un diagnostic concret et à une solution, afin que vous puissiez résoudre les incidents avec les outils dont vous disposez déjà, sans déployer d'infrastructure d'observabilité supplémentaire. Il couvre le serveur, le collecteur, le tableau de bord, l'assistant IA, le SDK Python, la surveillance de l'état et des certificats, les sauvegardes, les analytics basées sur ClickHouse et la multi-location. + +Les pages du tableau de bord sont délimitées par organisation sous `//…`, et le flux d'événements est la page d'accueil de l'organisation (`//`). Les noms de pages mentionnés dans ce guide (par exemple `/sessions`, `/queries`) font référence à ces routes limitées par organisation. + +--- + +## Consultation des journaux + +AgentEye n'inclut pas de pile de journalisation ou de surveillance. Le serveur et le tableau de bord écrivent tous deux des journaux structurés sur **stdout**, ce qui vous permet de les lire directement avec `kubectl` ou `docker` ; aucun agrégateur n'est nécessaire. + +### Kubernetes + +Suivre les journaux en direct pour le serveur et le tableau de bord : + +```bash +kubectl logs -n agenteye -l app=server -f --timestamps +kubectl logs -n agenteye -l app=dashboard -f --timestamps +``` + +Variantes utiles : + +| Objectif | Commande | +|---|---| +| 200 dernières lignes (sans suivi) | `kubectl logs -n agenteye -l app=server --tail=200 --timestamps` | +| Journaux du crash précédent | `kubectl logs -n agenteye --previous` | +| Suivre tous les réplicas simultanément | `kubectl logs -n agenteye -l app=server --max-log-requests=10 -f` | +| Postgres (StatefulSet) | `kubectl logs -n agenteye postgres-0 -f` | + +### Docker Compose + +```bash +docker logs -f agenteye-server +docker logs -f agenteye-dashboard +``` + +### Corréler une requête unique entre le tableau de bord et le serveur + +Chaque requête du tableau de bord est étiquetée avec un `request_id` et propagée au serveur via l'en-tête `x-request-id`. Le serveur le renvoie dans ses en-têtes de réponse et dans chaque ligne de journal qu'il émet pour cette requête. Pour tracer une requête de bout en bout : + +1. Récupérez l'identifiant depuis l'en-tête de réponse, par exemple : + ```bash + curl -i https://dashboard.example.com/api/events | grep -i x-request-id + # x-request-id: 9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a + ``` +2. Recherchez cet identifiant dans les journaux des deux pods : + ```bash + REQ=9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a + kubectl logs -n agenteye -l app=dashboard --tail=5000 | grep "$REQ" + kubectl logs -n agenteye -l app=server --tail=5000 | grep "$REQ" + ``` + +Vous verrez les lignes `proxy passthrough`, `withAuth: authorized` et `upstream response` du tableau de bord aux côtés de la paire `http request received` / `http request completed` du serveur, toutes partageant le même `request_id`. + +### Journaux JSON et `jq` + +Définissez `AE_LOG_JSON=1` sur le tableau de bord (activé par défaut lorsque `NODE_ENV=production`) pour émettre un objet JSON par ligne. Filtrez ensuite de manière structurée : + +```bash +kubectl logs -n agenteye -l app=dashboard --tail=5000 \ + | jq 'select(.level == "warn" or .level == "error")' + +kubectl logs -n agenteye -l app=dashboard --tail=5000 \ + | jq 'select(.route == "POST /api/keys")' +``` + +Le serveur Rust émet des paires de traçage `key=value` qui se prêtent bien à `grep` sans `jq` : + +```bash +kubectl logs -n agenteye -l app=server --tail=5000 | grep 'status=5' # 5xx +kubectl logs -n agenteye -l app=server --tail=5000 | grep 'actor_key_id=' +``` + +### Augmenter le niveau de verbosité + +| Composant | Variable d'environnement | Exemple | +|---|---|---| +| Serveur | `RUST_LOG` | `RUST_LOG=debug` ou `RUST_LOG=agenteye_server=debug,info` | +| Tableau de bord | `AE_LOG_LEVEL` | `AE_LOG_LEVEL=debug` | + +`debug` sur le serveur ajoute une ligne `api key authenticated` par authentification. `debug` sur le tableau de bord ajoute les lignes `upstream request`, `session validated` et `proxy passthrough`. + +### Rétention des journaux + +Le stdout des conteneurs est éphémère ; kubelet fait tourner les fichiers journaux (par défaut ~10 Mio par conteneur) et en conserve un petit nombre sur disque. Une fois un pod supprimé, ses journaux sont perdus. Si vous avez besoin d'une rétention plus longue ou d'une recherche multi-pods, orientez votre cluster vers un collecteur de journaux (Loki, CloudWatch, Cloud Logging, Datadog, etc.) qui suit les fichiers `/var/log/containers/`. AgentEye ne requiert ni ne recommande de choix particulier. + +--- + +## Problèmes d'authentification + +### `docker pull` échoue avec "unauthorized" + +Assurez-vous d'avoir authentifié Docker auprès de GHCR avec votre `AGENTEYE_TOKEN` : + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +Le jeton doit disposer de la permission `read:packages` sur l'organisation `agenteye-enterprise`. Contactez `support@exosphere.host` si votre jeton ne fonctionne pas. + +### `gh release download` retourne 404 ou 401 + +- Vérifiez que `AGENTEYE_TOKEN` est exporté dans votre shell : `echo $AGENTEYE_TOKEN` +- Vérifiez que vous utilisez `GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download ...` (le CLI `gh` lit `GITHUB_TOKEN`) +- Le jeton nécessite `contents:read` sur `agenteye-enterprise/releases` + +--- + +## Problèmes de serveur + +### Le serveur échoue avec "invalid port number" + +Le `POSTGRES_PASSWORD` (ou une autre information d'identification) contient des caractères spéciaux pour les URL (`/`, `+`, `=`) qui cassent l'analyse de `DATABASE_URL`. Régénérez le mot de passe en encodage hexadécimal : + +```bash +NEW_PASS=$(openssl rand -hex 24) +``` + +Mettez ensuite à jour le secret Kubernetes et le mot de passe dans Postgres (ou recréez le `.env` pour Docker Compose), puis redémarrez le serveur. Consultez les étapes complètes dans [enterprise-docs/kubernetes-deployment.md](/fr/agenteye/kubernetes-deployment) § "PostgreSQL credentials". + +### Le serveur se ferme immédiatement au démarrage + +Vérifiez les journaux du conteneur : + +```bash +docker logs agenteye-server +``` + +Causes courantes : +- `DATABASE_URL` non défini ou malformé : le serveur enregistrera l'erreur et s'arrêtera. +- Postgres inaccessible : vérifiez que le conteneur Postgres ou la base de données gérée est en cours d'exécution et que l'hôte/port sont corrects. +- Échec des migrations : vérifiez les journaux pour des erreurs SQL. + +### `GET /health` retourne non-200 ou expire + +Le serveur est peut-être encore en train d'exécuter des migrations au premier démarrage. Attendez quelques secondes et réessayez : + +```bash +curl http://localhost:8080/health +``` + +Si le problème persiste, vérifiez `docker logs agenteye-server` pour des erreurs. + +### `GET /ready` retourne 503 + +`/ready` est la sonde de disponibilité : elle retourne `503` lorsque le serveur ne peut pas atteindre **Postgres ou ClickHouse**. Le corps indique la dépendance défaillante : + +```bash +curl -s http://localhost:8080/ready +# {"status":"not_ready","checks":{"postgres":"ok","clickhouse":"down","redis":"ok"}} +``` + +Corrigez la dépendance signalée comme `down` : le pod ClickHouse/Postgres est-il `Running` ? `CLICKHOUSE_URL` / `DATABASE_URL` sont-ils corrects et accessibles ? Sur Kubernetes, le pod affiche `NotReady` jusqu'à ce que `/ready` se rétablisse ; c'est attendu et c'est exactement le signal sur lequel la surveillance de l'état génère des alertes. Redis n'est jamais une cause : il est signalé mais ne fait pas échouer la disponibilité. + +### Le collecteur retourne 401 Unauthorized + +La clé API du collecteur n'a pas la permission `events:add`, ou la clé a été désactivée. Créez une nouvelle clé avec la permission correcte : + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{"name":"new-collector","permissions":["events:add"]}' +``` + +### Les requêtes authentifiées sont soudainement lentes (~200ms au lieu de ~5ms) + +C'est le symptôme de Redis hors ligne alors que `REDIS_URL` est défini. Chaque appel au cache expire après 100ms puis se rabat sur Postgres ; sur les chemins d'authentification et OTP, la requête effectue deux de ces replis. + +Confirmez dans les journaux du serveur : + +``` +auth cache: L2 get failed error=redis call timed out +``` + +Résolution : + +1. `redis-cli -h ping` pour confirmer que Redis est accessible sur le réseau du cluster. +2. Si Redis était brièvement indisponible et est maintenant de retour, **redémarrez les pods du serveur**. Le `redis::aio::ConnectionManager` ne rétablit pas de manière fiable la connexion après une interruption ; un redémarrage du pod établit proprement une nouvelle connexion. Cela s'applique également au tableau de bord. +3. Si vous ne souhaitez pas exécuter Redis pour l'instant, désactivez `REDIS_URL` dans le déploiement et redémarrez. Les deux services fonctionnent sans le cache (l'exactitude est préservée ; la latence revient à la référence pré-Redis). + +### Le serveur signale `OTP request rate-limited` dans les journaux mais l'utilisateur dit n'avoir essayé qu'une seule fois + +Vérifiez si Redis était inaccessible. Le chemin de repli utilise `SELECT COUNT(*) FROM otp_codes WHERE created_at > now() - interval '15 minutes'`, qui voit les lignes OTP précédemment générées. Si l'utilisateur a cliqué plusieurs fois sur "Renvoyer" pendant une heure, la fenêtre de 15 minutes peut encore contenir ≥5 codes. Résolvez en attendant que la fenêtre expire, ou exécutez `DELETE FROM otp_codes WHERE user_id = $1 AND created_at > now() - interval '15 minutes'` (console opérateur). + +### J'ai modifié `ALLOWED_EMAILS` / `SESSION_TTL_SECS` / `OTP_TTL_SECS` et redémarré ; rien n'a changé + +Ces variables d'environnement sont des **valeurs initiales uniquement au premier démarrage**. Une fois que la table `settings` contient une ligne pour la clé correspondante, cette ligne est la source de vérité ; la variable d'environnement est lue une seule fois au premier démarrage et ignorée lors de chaque redémarrage ultérieur. + +Pour les modifier après le premier démarrage, connectez-vous au tableau de bord et modifiez-les sous `/settings`. Le changement s'applique en quelques secondes sur tous les réplicas ; aucun redémarrage n'est nécessaire. + +Si vous devez forcer un re-seeding depuis l'environnement (rare, généralement utile uniquement en développement), exécutez `DELETE FROM settings WHERE key = ''` et redémarrez le serveur. Le bootstrap récupérera la valeur actuelle de la variable d'environnement au prochain démarrage. La modification via `/settings` est la voie recommandée en production. + +--- + +## Problèmes de collecteur + +### Le collecteur démarre mais les événements n'apparaissent pas dans le tableau de bord + +1. Confirmez que le collecteur fonctionne : `systemctl status agenteye-collector` (Linux) ou vérifiez le processus. +2. Confirmez que `AGENTEYE_URL` pointe vers `http(s)://your-server-host:8080/events` (notez : chemin `/events`). +3. Exécutez un vidage ponctuel pour voir la sortie immédiate : + ```bash + agenteye-collector flush + ``` +4. Vérifiez que le SDK Python écrit bien des fichiers : `ls ${AGENTEYE_HOME:-~/.agenteye}/events/` +5. Si des fichiers existent dans `${AGENTEYE_HOME:-~/.agenteye}/failed/`, les envois échouent. Vérifiez les journaux du collecteur pour l'erreur, probablement une 4xx (mauvaise clé ou URL) ou un problème réseau. + +### Les fichiers s'accumulent dans `$AGENTEYE_HOME/events/` et ne sont pas envoyés + +- Le collecteur n'est peut-être pas en cours d'exécution. Démarrez-le : `agenteye-collector start` ; il vide automatiquement les événements préexistants au démarrage. +- Vérifiez l'état du collecteur : `agenteye-collector health` +- Le collecteur est peut-être en cours d'exécution mais ne peut pas atteindre le serveur. Vérifiez les règles de pare-feu entre les hôtes du collecteur et du serveur. + +### Fichiers dans `$AGENTEYE_HOME/failed/` + +Les fichiers sont déplacés vers `failed/` après épuisement de toutes les tentatives de réessai (par défaut : 5 tentatives avec backoff exponentiel). Cela signifie soit : +- Le serveur a retourné une erreur 4xx (mauvaise clé, URL incorrecte ou problème de charge utile) +- Le serveur était inaccessible pendant toute la fenêtre de réessai + +Corrigez le problème sous-jacent, puis remettez les fichiers en file d'attente manuellement : + +```bash +mv ${AGENTEYE_HOME:-~/.agenteye}/failed/*.jsonl ${AGENTEYE_HOME:-~/.agenteye}/events/ +agenteye-collector flush +``` + +### Le collecteur signale une `network error` à chaque envoi (échec de la poignée de main TLS) + +Si `curl -k` contre `AGENTEYE_URL` réussit mais que le binaire du collecteur échoue à chaque envoi avec `error sending request for url (...)`, le serveur AgentEye présente un certificat TLS non signé par une AC publiquement approuvée. + +Le **chemin de production** est le nom d'hôte ACME d'ingestion configuré dans `deploy/base/certificates/domain.env` (voir [`kubernetes-deployment.md`](/fr/agenteye/kubernetes-deployment) Phase 3.1 / 4.2). Une fois que `INGEST_DOMAIN` pointe vers le LB public Traefik et que cert-manager a émis le certificat Let's Encrypt, les collecteurs vérifient le certificat du serveur par rapport au magasin de confiance système **sans `AGENTEYE_TLS_CA` nécessaire** ; effacez-le de votre configuration de collecteur s'il avait été défini pour un ancien déploiement auto-signé. + +**Symptôme : le collecteur fonctionnait hier, échoue aujourd'hui après un intervalle de ~90 jours.** Cela signifie que le déploiement utilise encore l'émetteur `selfsigned` hérité pour `ingest-tls`. Le certificat de 90 jours a été renouvelé et le fichier CA épinglé est obsolète. Corrigez définitivement en basculant le cluster vers l'émetteur ACME (Phase 3.1 du guide de déploiement). Déblocage à court terme : réextrayez le certificat serveur actuel et mettez à jour `AGENTEYE_TLS_CA` : + +```bash +kubectl get secret ingest-tls-cert -n agenteye \ + -o jsonpath='{.data.tls\.crt}' | base64 -d > /etc/agenteye/server-ca.crt +``` + +```bash +export AGENTEYE_TLS_CA=/etc/agenteye/server-ca.crt +agenteye-collector flush +``` + +`AGENTEYE_TLS_CA` ajoute une ancre de confiance supplémentaire ; les racines publiques standard sont toujours approuvées. + +### Le certificat `ingest-tls` reste bloqué `Ready: False` après le déploiement + +```bash +kubectl describe certificate ingest-tls -n agenteye +``` + +Examinez les `Events` et l'`Order` / `Challenge` référencé. Causes courantes : + +- **Le DNS ne pointe pas vers le LB public.** Le validateur HTTP-01 ne peut pas atteindre `INGEST_DOMAIN`. Vérifiez avec `dig +short INGEST_DOMAIN` ; cela doit résoudre vers la même adresse que l'`EXTERNAL-IP` du LoadBalancer `traefik-public`. cert-manager réessaie automatiquement une fois le DNS propagé ; inutile de supprimer le Certificate. +- **Le port 80 est bloqué au niveau du load balancer / security group.** HTTP-01 nécessite que le port 80 soit accessible depuis les validateurs publics de Let's Encrypt. Si un WAF ou SG en amont restreint `:80`, ouvrez-le (la configuration Traefik redirige vers HTTPS, mais Boulder suit la redirection et accepte la réponse). +- **`dnsNames` non substitué.** Si `kubectl get certificate ingest-tls -n agenteye -o jsonpath='{.spec.dnsNames}'` affiche `INGEST_DOMAIN_PLACEHOLDER`, vous avez omis l'étape `domain.env` ; créez-le depuis `domain.env.example` et réappliquez. +- **Limite de débit de Let's Encrypt.** Des ordres échoués répétés pour le même nom d'hôte déclenchent les limites de certificat dupliqué ou de validation échouée. Attendez au moins une heure avant de réessayer ; vérifiez le statut de l'Order pour le message exact de limite de débit. + +### Le certificat `dashboard-tls` reste bloqué `Ready: False` / le navigateur affiche toujours un avertissement + +Même procédure de diagnostic que pour `ingest-tls` ci-dessus (`kubectl describe certificate dashboard-tls -n agenteye`) ; les causes liées au DNS, au port 80, aux espaces réservés et aux limites de débit s'appliquent toutes, plus deux spécifiques au tableau de bord : + +- **`DASHBOARD_DOMAIN` pointe vers le mauvais LoadBalancer.** Il doit pointer vers le LB Traefik du *tableau de bord*, pas celui d'ingestion public. Utilisez `dig +short` sur le nom d'hôte et comparez avec l'adresse du LB du tableau de bord. +- **L'instance Traefik du tableau de bord ne peut pas servir le défi.** Elle doit être installée avec le fichier de valeurs du tableau de bord fourni, qui active un fournisseur Ingress limité pour le solveur HTTP-01 de cert-manager. Sans celui-ci, le solveur est inaccessible et l'Order reste `pending` indéfiniment. Mettez à niveau l'instance avec les valeurs fournies ; le défi en attente se complète alors automatiquement. +- **Le LoadBalancer était restreint par IP.** Les plages sources s'appliquent également au port 80, ce qui bloque les validateurs de Let's Encrypt — aussi bien lors de la première émission que lors de chaque renouvellement tous les ~75 jours. Rouvrez le LB, ou coordonnez un solveur DNS-01 avec le support avant de le verrouiller. + +Pendant l'échec de l'émission, le tableau de bord continue de servir son certificat précédent (ou le certificat par défaut de l'ingress sur une nouvelle installation) — l'accès est dégradé par un avertissement du navigateur, mais jamais interrompu. + +### Le CLI saute toujours la vérification TLS après que le tableau de bord a obtenu un certificat approuvé + +`--insecure` est persisté dans `cli.json` à la connexion. Une fois que le tableau de bord sert un certificat publiquement approuvé, reconnectez-vous avec `agenteye --base-url https:// --secure login` ; la vérification est réactivée et l'avertissement au démarrage disparaît. + +--- + +## Problèmes de tableau de bord + +### Impossible de désactiver ou de modifier l'utilisateur `ADMIN_EMAIL` + +Par conception. L'utilisateur correspondant à `ADMIN_EMAIL` est marqué comme protégé à chaque démarrage du serveur : le tableau de bord masque le bouton Désactiver pour cette ligne, et l'API rejette `DELETE /users/:id` et `PUT /users/:id` contre lui avec `403 Forbidden`. Un déclencheur de base de données rejette également les instructions `UPDATE` directes qui désactiveraient la ligne protégée. + +Pour remplacer l'administrateur d'amorçage, modifiez `ADMIN_EMAIL` dans votre environnement et redémarrez le serveur. Le nouvel email est inséré/mis à jour comme protégé. L'administrateur précédent conserve l'indicateur de protection jusqu'à ce qu'il soit effacé dans la base de données (généralement sans conséquence, car l'email précédent reste un administrateur valide jusqu'à ce que vous le supprimiez explicitement). + +### Le tableau de bord n'affiche aucun événement + +1. Confirmez que l'URL du serveur et la clé API sont correctes dans les variables d'environnement du tableau de bord (`AGENTEYE_SERVER_URL`, `AGENTEYE_API_KEY`). +2. La clé API du tableau de bord nécessite la permission `events:read`. +3. Confirmez que des événements ont bien été ingérés : `curl http://your-server:8080/events -H "Authorization: Bearer $ADMIN_KEY"` + +### `/errors` est vide mais `/events` affiche des lignes rouges + +Les versions récentes du SDK émettent les échecs sous forme d'événements `agent_end` / `tool_result` / `hook_completed` avec `outcome: "error"` dans la charge utile, plutôt que comme une ligne `event_type: "error"` dédiée. La page `/errors` correspond désormais aux deux : toute ligne que le flux `/events` colore en rouge (type d'événement explicite `event_type='error'`, `outcome`/`status` de la charge utile dans l'ensemble des échecs, `is_error: true`, ou un champ `error` truthy) apparaît sur `/errors`. Si vous voyiez auparavant "aucune erreur dans cette fenêtre" alors que des lignes rouges étaient visibles sur `/events`, mettez à jour le tableau de bord et le serveur ensemble (le filtre élargi est `errored=true` sur `GET /events`) et les deux vues seront cohérentes. + +### `/models`, `/tools` ou `/hooks` est lent ou échoue à charger sur de larges plages temporelles + +**Symptôme :** sur une grande table d'événements (des millions de lignes), l'ouverture de `/models`, `/tools` ou `/hooks` — ou l'élargissement de la plage à `7d`, `30d` ou `all` — fait tourner les graphiques puis affiche une erreur de chargement. Le serveur enregistre une erreur ClickHouse `MEMORY_LIMIT_EXCEEDED` (Code 241) ou un dépassement de délai de requête pour la demande `latency_aggregate`. + +**Cause :** les anciennes versions calculaient les rollups de latence et de distribution de ces pages avec une requête qui lisait l'intégralité de la colonne `payload` JSON brute et appariait les événements requête/réponse avec un tri et une jointure en mémoire. La mémoire de requête maximale croissait donc avec la taille de la fenêtre, si bien que sur un tenant actif, une large plage pouvait dépasser le plafond de mémoire par requête de ClickHouse. + +**Correction :** mettez à niveau vers une version incluant ce correctif. Le rollup ne lit désormais que les colonnes promues compactes et apparie les événements avec une agrégation en flux, de sorte que la mémoire maximale ne croît plus avec la charge utile brute — les larges fenêtres restent bien en deçà du plafond mémoire et retournent en une fraction du temps. L'amélioration est entièrement côté requête : elle s'applique à toutes les données existantes au prochain chargement de page, sans re-ingestion ni remplissage. + +### Le tableau de bord ne se charge pas / page blanche + +Vérifiez les journaux du conteneur du tableau de bord : + +```bash +docker logs agenteye-dashboard +``` + +La cause la plus courante est `AGENTEYE_SERVER_URL` ou `AGENTEYE_API_KEY` manquant ou pointant vers un serveur inaccessible. + +### Analytics / télémétrie du tableau de bord + +Le tableau de bord envoie des analytics d'utilisation du produit anonymes à PostHog par défaut, acheminées via le propre chemin `/ingest` du tableau de bord (un proxy inverse vers `https://us.i.posthog.com`). Les envoyer en first-party signifie que les bloqueurs de publicité des navigateurs ne les filtrent pas. Cela est indépendant des fonctionnalités principales du tableau de bord : + +- C'est le **conteneur du tableau de bord** (pas le navigateur) qui contacte PostHog. Si son accès sortant vers `https://us.i.posthog.com` est bloqué, la télémétrie échoue silencieusement ; le tableau de bord fonctionne normalement et aucune erreur n'est visible pour les utilisateurs. +- Aucune donnée d'agent, de session ou d'événement n'est jamais incluse, uniquement l'utilisation de l'interface du tableau de bord. +- Pour désactiver entièrement la télémétrie, définissez `AE_ANALYTICS_DISABLED=1` sur le conteneur du tableau de bord et redémarrez. Voir [Télémétrie et confidentialité](/fr/agenteye/deployment#telemetry--privacy) dans le guide de déploiement. + +### Analytics / télémétrie du CLI + +Le CLI `agenteye` envoie des analytics d'utilisation anonymes à PostHog par défaut : quelles commandes sont exécutées, le statut de succès/sortie, et la durée. Cela est indépendant des fonctionnalités du CLI : + +- La **machine exécutant le CLI** contacte `https://us.i.posthog.com` directement. Si son accès sortant est bloqué, la télémétrie échoue silencieusement (l'envoi est limité dans le temps, donc ne retarde jamais une commande) et le CLI fonctionne normalement. +- Aucune donnée d'agent, de session ou d'événement n'est jamais incluse : les **arguments de commande et les valeurs des indicateurs** (URL du tableau de bord, jeton, email, identifiants de session, filtres de requête) ne sont jamais envoyés. +- Pour le désactiver, définissez `AGENTEYE_ANALYTICS_DISABLED=1` (ou le `DO_NOT_TRACK=1` universel) dans l'environnement du CLI. Voir [Télémétrie et confidentialité](/fr/agenteye/cli#telemetry--privacy) dans le guide CLI. + +--- + +## Problèmes d'assistant IA + +Consultez [enterprise-docs/assistant.md](/fr/agenteye/assistant) pour la configuration complète. + +### La bulle de l'assistant n'apparaît pas + +La bulle est masquée sauf si **toutes** ces conditions sont remplies : + +- L'utilisateur connecté a la permission `agent:use`. +- `AGENTEYE_AGENT_URL` est défini sur le tableau de bord et le service `agent` est accessible. +- Un point de terminaison LLM est configuré sur le service `agent` (`ANTHROPIC_API_KEY`, une passerelle via `ANTHROPIC_BASE_URL`, ou Bedrock/Vertex). Sans aucun de ces éléments, l'agent signale "not configured" et la bulle reste masquée. + +Vérifiez l'état de l'agent depuis l'hôte du tableau de bord : `curl http://agent:9100/health` doit retourner `{"status":"ok","llm_configured":true,...}`. + +### L'assistant dit qu'il ne peut pas lire quelque chose + +Les outils sont limités par utilisateur. Si un utilisateur n'a pas `evaluations:read` (ou `events:read`, `dashboards:read`), les outils correspondants ne sont pas proposés et l'assistant dira qu'il ne peut pas lire ces données. Accordez la permission de lecture pertinente. + +### "assistant not configured" (HTTP 503) lors de l'envoi + +Le conteneur `agent` n'a pas de point de terminaison LLM configuré, ou le `AGENTEYE_AGENT_TOKEN` du tableau de bord ne correspond pas à celui de l'agent. Définissez les deux et redémarrez. + +### Le conteneur `agent` redémarre / OOM sous charge + +Chaque conversation crée un processus enfant de courte durée. Assurez-vous que le conteneur s'exécute avec un processus init (l'image utilise `tini` ; dans Compose définissez `init: true`) et accordez-lui des limites de mémoire suffisantes. Réduisez `AGENTEYE_AGENT_MAX_STEPS` si nécessaire. + +--- + +## Problèmes de CLI + +### `agenteye` échoue au démarrage avec `ModuleNotFoundError: No module named 'click'` + +Une installation fraîche du CLI `agenteye` en version **0.1.6** peut planter au démarrage avec : + +``` +ModuleNotFoundError: No module named 'click' +``` + +La version 0.1.6 dépendait de `click` installé indirectement par `typer` ; les versions actuelles de `typer` ne l'incluent plus, donc un environnement propre se retrouve sans le paquet. **Mettez à niveau vers la version 0.1.7 ou ultérieure**, qui dépend de `click` directement : + +```bash +pipx upgrade agenteye # si installé avec pipx (ou : pipx install --force agenteye) +uv tool upgrade agenteye # si installé avec uv +pip install --upgrade agenteye +``` + +Consultez [enterprise-docs/cli.md](/fr/agenteye/cli) pour les instructions d'installation. + +--- + +## Problèmes du SDK Python + +### Aucun fichier n'apparaît dans `$AGENTEYE_HOME/events/` + +Le SDK met les événements en tampon et les vide toutes les 500 ms par défaut. Si votre processus se termine avant le vidage, des événements peuvent être perdus. Appelez `agenteye.configure(flush_interval=0.1)` pour un vidage plus rapide dans les scripts de courte durée, ou assurez-vous que votre processus s'exécute suffisamment longtemps pour un cycle de vidage. + +Si `AGENTEYE_HOME` est défini, vérifiez que le SDK écrit dans `$AGENTEYE_HOME/events/` et non dans `~/.agenteye/events/` (nécessite SDK ≥ 0.0.1b5). + +### `ValueError: Reserved field names cannot be used as custom fields` + +Les noms `timestamp`, `type` et `environment` sont réservés et ne peuvent pas être utilisés comme champs personnalisés. Les passer lève l'exception : + +``` +ValueError: Reserved field names cannot be used as custom fields: [...] +``` + +Renommez le champ personnalisé en cause. Notez que `session_id` et `agent_id` sont des paramètres explicites de l'appel d'événement, et non des champs personnalisés ; les passer à nouveau comme champ personnalisé lève une `TypeError`. + +--- + +## Problèmes de surveillance de l'état + +### Aucune alerte ne parvient à Slack (Robusta) + +Les alertes de surveillance de l'état Robusta sont **opt-in** ; elles n'envoient rien tant qu'elles ne sont pas installées et pointées vers un canal Slack. Vérifiez la release et son sink : + +```bash +kubectl get pods -n robusta # robusta-runner + robusta-forwarder doivent être Running +kubectl logs -n robusta -l app=robusta-runner --tail=50 +``` + +Causes courantes : l'`api_key` Slack / le `slack_channel` n'ont pas été définis (ou le jeton a été révoqué) ; l'`api_key` est un jeton de relais cloud Robusta (`robusta integrations slack`) mais le `disableCloudRouting: true` fourni nécessite un **jeton de bot Slack** auto-hébergé (`xoxb-…`), ou définissez `disableCloudRouting: false` ; le `scope` du sink exclut l'espace de noms dans lequel vos pods s'exécutent (les valeurs fournies limitent à `agenteye`) ; ou aucune défaillance ne s'est encore produite. Forcez une alerte de test en arrêtant un pod : + +```bash +kubectl -n agenteye delete pod -l app=clickhouse # il sera recréé +``` + +Consultez [enterprise-docs/health-monitoring.md](/fr/agenteye/health-monitoring#2-pod-failure-alerting-with-robusta-opt-in) pour l'installation et la configuration. + +### Le serveur oscille continuellement `NotReady` + +La sonde de disponibilité atteint `/ready`, qui échoue lorsque Postgres ou ClickHouse est inaccessible. Si le serveur oscille entre `NotReady` et `Ready`, une dépendance est intermittemment indisponible ; vérifiez les pods ClickHouse et Postgres ainsi que les variables `CLICKHOUSE_URL` / `DATABASE_URL` du serveur. Confirmez ce que `/ready` signale : + +```bash +kubectl -n agenteye exec deploy/server -- sh -c 'curl -s localhost:8080/ready' +``` + +Cette sonde est délibérément tolérante (un seuil d'échec généreux), donc une oscillation soutenue indique un vrai problème de dépendance plutôt qu'une sonde trop agressive. La sonde de vivacité reste sur `/health`, donc une oscillation de disponibilité **ne redémarrera pas** le pod. + +## Problèmes de surveillance des certificats + +### Le CronJob n'envoie pas de notifications Slack + +Le CronJob `cert-renewal-check` nécessite une URL de webhook Slack stockée dans un Secret. Vérifiez qu'il existe : + +```bash +kubectl get secret cert-renewal-notify-config -n agenteye +``` + +S'il est absent, créez-le : + +```bash +kubectl create secret generic cert-renewal-notify-config \ + --namespace agenteye \ + --from-literal=SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL" +``` + +Sans le secret, le CronJob s'exécute quand même et enregistre les résultats sur stdout. Vérifiez les journaux avec : + +```bash +kubectl logs -n agenteye -l job-name --tail=50 +``` + +### Le certificat client a expiré avant qu'une notification soit reçue + +Le CronJob s'exécute toutes les 12 heures. S'il n'a pas fonctionné, vérifiez son statut : + +```bash +kubectl get cronjob cert-renewal-check -n agenteye +``` + +Déclenchez une vérification manuelle : + +```bash +kubectl create job --from=cronjob/cert-renewal-check manual-cert-check -n agenteye +kubectl logs -n agenteye -l job-name=manual-cert-check +``` + +Pour réémettre immédiatement le certificat expiré : + +```bash +cd base/certificates/client-certs +./issue-client-cert.sh +``` + +Appliquez ensuite le `collector-mtls-secret.yaml` régénéré dans le(s) cluster(s) exécutant vos collecteurs et redémarrez-les : + +```bash +kubectl apply -f collector-mtls-secret.yaml -n +``` + +--- + +## Problèmes de sauvegarde + +### `agenteye-backup` échoue avec "No space left on device" + +Le CronJob `agenteye-backup` déverse Postgres + ClickHouse dans un volume scratch `emptyDir` `backup-tmp` (par défaut `30Gi`), puis **diffuse** l'archive `tar` directement vers S3 — l'archive compressée n'est jamais réécrite sur le scratch, donc le scratch n'a besoin de contenir que les *dumps bruts*, pas les dumps + une seconde copie d'archive sur disque. Un pod expulsé / `No space left on device` signifie donc que les **dumps bruts** dépassent la taille du scratch (le dump ClickHouse `events` domine et grossit avec le temps). Vérifiez les journaux du job échoué : + +```bash +kubectl logs -n agenteye -l job-name= +``` + +Correction : dans votre overlay, augmentez la `sizeLimit` de `emptyDir` `backup-tmp` du CronJob au-dessus du total de vos dumps bruts, et assurez-vous que le stockage éphémère du nœud peut effectivement le contenir (`sizeLimit` est un plafond, pas une réservation). Si les dumps dépassent le disque d'un seul nœud, remplacez l'`emptyDir` par un PVC (EBS/PD) pour `backup-tmp`, ou compressez les dumps à la source. + +> Les anciennes versions écrivaient le `.tar.gz` dans le *même* scratch de `20Gi` que les dumps, donc `dumps + archive` le dépassait et le pod était expulsé **avant** que l'envoi ne s'exécute — ce qui ressemble à un échec S3 mais est en réalité un problème de disque. La diffusion de l'envoi élimine ce doublement. + +### `agenteye-backup` échoue lors de l'installation de `curl` + +Le job s'exécute sur l'image `postgres:16` et installe `curl` au démarrage pour le dump HTTP ClickHouse. Sur un cluster sans accès sortant vers les miroirs de paquets Debian, l'étape `apt-get` échoue. Soit autorisez cet accès sortant depuis le pod de sauvegarde, soit intégrez `curl` dans une image de sauvegarde miroir/personnalisée et référencez-la dans votre overlay. + +### `agenteye-backup` s'exécute mais rien n'arrive dans le stockage objet + +La base inclut un vrai `BACKUP_BUCKET` (`ts-prod-agenteye/backups`) et le ServiceAccount `agenteye-backup`. Le job **diffuse** l'archive vers S3 (`tar cz … | aws s3 cp - s3://…`). Si le pod de sauvegarde n'a pas accès en écriture au bucket, l'envoi échoue — et comme le script s'exécute sous `set -euo pipefail`, un échec n'importe où dans ce pipe **fait échouer** l'ensemble du job à l'étape `upload` plutôt que d'échouer silencieusement (le piège EXIT du pod enregistre `backup FAILED during step: upload`). C'est aussi l'étape que vous atteignez *après* avoir corrigé une expulsion due à l'espace disque, donc si des sauvegardes étaient précédemment expulsées à l'étape d'archivage, vérifiez maintenant que l'envoi aboutit. Recherchez l'erreur d'accès S3 dans les journaux du job échoué : + +```bash +kubectl logs -n agenteye -l job-name= | grep -iE 's3|upload|denied' +``` + +Correction : dans votre overlay, définissez `BACKUP_BUCKET` vers un bucket que vous possédez et annotez le ServiceAccount `agenteye-backup` existant avec l'accès en écriture (IRSA / Workload Identity / Pod Identity). Consultez la section **Sauvegardes** de [enterprise-docs/kubernetes-deployment.md](/fr/agenteye/kubernetes-deployment). + +--- + +## Évaluations / sessions / requêtes basées sur ClickHouse + +### La barre latérale de la page `/queries` est vide après la mise à niveau + +Trois tables sont attendues (`events`, `evaluations`, `agent_sessions`). Si la barre latérale SchemaBrowser est vide après la mise à niveau, le serveur a échoué à appliquer le DDL ClickHouse au démarrage. Vérifiez les journaux du serveur pour `failed to apply CH DDL statement` : + +```bash +kubectl logs -n agenteye deploy/server | grep -E 'clickhouse|CH DDL' +``` + +La cause la plus courante est ClickHouse inaccessible pendant les migrations. Le serveur refuse de démarrer s'il ne peut pas atteindre CH, donc un pod bloqué a généralement un `CrashLoopBackOff` plutôt qu'une page de requêtes silencieusement cassée, mais un DDL partiellement appliqué (une instruction OK, les 5 suivantes en 5xx) laisse le schéma à moitié formé. Redémarrez le pod serveur après avoir vérifié que CH est accessible : + +```bash +kubectl rollout restart deploy/server -n agenteye +``` + +### Les nouvelles évaluations n'apparaissent pas dans `/sessions` ou `/queries` + +Après la mise à niveau, les nouvelles évaluations sont écrites dans ClickHouse, pas dans Postgres, et apparaissent sous `/sessions` (protégé par `evaluations:read`) et dans `/queries`. Si elles n'apparaissent pas : + +1. Confirmez que le pipeline d'évaluation est activé (`EVALUATOR_ENDPOINT` défini sur le serveur) et qu'il produit des résultats terminaux ; vérifiez les lignes de journal `evaluation_finalized`. +2. Confirmez que CH est accessible depuis le serveur : `kubectl exec -n agenteye deploy/server -- curl -fsS http://clickhouse:8123/ping`. +3. Vérifiez directement dans la table CH : `kubectl exec -n agenteye clickhouse-0 -- clickhouse-client -q 'SELECT count() FROM agenteye.evaluations'`. + +### Les requêtes échouent sous charge avec "Memory limit exceeded", ou ClickHouse est `OOMKilled` + +**Symptôme :** sous une charge importante de tableau de bord/requêtes, les pages analytiques (le flux d'événements, `/sessions`, la vue modèles/latence, l'éditeur SQL) commencent à échouer ou à expirer ; le serveur oscille brièvement `NotReady` ; et le pod ClickHouse affiche un nombre de redémarrages croissant. C'est presque toujours de la **mémoire**, pas du CPU ou du disque. + +**Confirmez que c'est de la mémoire** (et non un problème de débit que la réplication résoudrait) : + +1. Vérifiez si le pod a subi des arrêts par manque de mémoire : + ```bash + kubectl -n agenteye describe pod clickhouse-0 | grep -iE 'Restart Count|Last State|Reason|OOMKilled' + ``` + `Reason: OOMKilled` / `Exit Code: 137` avec un nombre de redémarrages croissant est le signe distinctif. + +2. Demandez à ClickHouse ce qu'il rejette : + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT name, value FROM system.errors WHERE value>0 ORDER BY value DESC" + ``` + Un grand nombre de `MEMORY_LIMIT_EXCEEDED` est la signature. Le message indique *"maximum: N GiB"* — ce **N est `0.9 × la limite mémoire du pod`** (le `max_server_memory_usage_to_ram_ratio` dans `deploy/base/clickhouse/configmap.yaml`). Si vos lectures intensives nécessitent plus de N, elles sont rejetées. + +3. Éliminez les fausses pistes — si CPU, nombre de partitions et disque sont tous faibles, ajouter des réplicas/sharding serait un coût inutile : + ```bash + kubectl -n agenteye top pod clickhouse-0 + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT table, count() parts FROM system.parts WHERE active AND database='agenteye' GROUP BY table" + ``` + +**Cause :** la limite mémoire du pod ClickHouse est trop faible pour l'ensemble de travail analytique. Les lectures les plus lourdes tirent la colonne `payload` JSON brute, exécutent `JSONExtract*` dessus, et utilisent `FINAL` — chacune peut nécessiter plusieurs Gio. Si les caches configurés (`mark_cache_size` + `uncompressed_cache_size`) sont plus grands que le pod, ils aggravent le problème : les caches sont imputés sur le même budget et réduisent la mémoire de requête disponible. + +**Correction — augmenter la mémoire de ClickHouse :** + +1. Augmentez la limite mémoire de ClickHouse dans votre overlay en corrigeant les `resources` du conteneur du StatefulSet `clickhouse` (le même mécanisme d'overlay utilisé pour les `resources` des autres composants). Le budget serveur utilisable est `0.9 × limite`, donc une limite de `6Gi` donne ~5.4 Gio, `16Gi` donne ~14 Gio. Définissez également `requests.memory` à un plancher réel, afin que le scheduler le réserve. Appliquer cela **recrée le pod CH** (réplica unique → ~30–60s d'interruption des analytics) ; faites-le pendant une fenêtre de faible trafic. +2. Gardez les caches dans `deploy/base/clickhouse/configmap.yaml` proportionnels à la limite — de petits caches (quelques centaines de Mio) sont sûrs sur un petit pod ; ne les augmentez qu'en parallèle d'une augmentation correspondante de la limite mémoire. Le `max_memory_usage` par requête est défini explicitement dans le profil `users.xml` (voir la section nœud fixe ci-dessous) et est maintenu en dessous du plafond au niveau serveur (`0.9 × limite`) afin qu'aucune requête individuelle ne puisse utiliser plus de RAM que le conteneur en dispose. +3. Si le nœud lui-même est le plafond, vérifiez la mémoire hôte que ClickHouse peut voir : + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT formatReadableSize(value) FROM system.asynchronous_metrics WHERE metric='OSMemoryTotal'" + ``` + Si c'est à peine au-dessus de la limite du pod, déplacez ClickHouse vers un nœud plus grand (optimisé mémoire) — via un sélecteur de nœud/affinité dans votre overlay — avant d'augmenter davantage la limite. + +**Quand vous ne pouvez pas ajouter de mémoire : exécutez les requêtes en RAM et échouez rapidement — ne déversez pas sur un disque lent.** Si le nœud est fixe et que le pod ne peut pas grossir, limitez ce qu'une requête individuelle peut utiliser (afin qu'une requête ne puisse pas prendre tout le nœud) et, sur un **disque de données lent (non-SSD)**, **ne permettez pas** aux grandes agrégations/tris de se déverser sur disque. Le déversement sur un disque lent est plus lent que le délai d'expiration de lecture client du serveur, donc une requête qui se déverse retourne une `500` du tableau de bord en cours d'exécution pendant que ClickHouse continue de traiter — garder les requêtes en RAM et rejeter rapidement la rare requête qui dépasse le budget (`MEMORY_LIMIT_EXCEEDED`, en moins d'une seconde) est ce qui rétablit le chargement. Notez un point subtil de ClickHouse pour appliquer ces paramètres : + +- **Ce sont des paramètres de *profil*, et ClickHouse lit `` uniquement depuis `users_config` (`users.xml` / `users.d/*.xml`) — jamais depuis `config.d`.** Un bloc `` placé dans `config.d/agenteye.xml` est **ignoré silencieusement** (`max_execution_time`, `max_memory_usage`, etc. ne s'appliquent tout simplement pas). La configuration fournie les livre donc comme clé `users.xml` sur le ConfigMap `clickhouse-config`, montée dans `/etc/clickhouse-server/users.d/agenteye.xml`. +- Les valeurs par défaut fournies : `max_memory_usage` (plafond par requête — une requête ne peut pas consommer tout le budget serveur), `max_bytes_before_external_group_by` / `max_bytes_before_external_sort` = **`0` (déversement désactivé)** pour que les requêtes restent en RAM plutôt que de ramper sur le disque lent, et `max_execution_time` (garde-fou contre les requêtes incontrôlées, aligné avec le délai d'expiration de lecture client du serveur). +- **Vérifiez qu'ils sont actifs** (c'est aussi ainsi que vous détectez le piège config.d) : + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT name, value FROM system.settings + WHERE name IN ('max_memory_usage','max_bytes_before_external_group_by','max_execution_time')" + ``` + Attendez un `max_memory_usage` non nul et `max_bytes_before_external_group_by = 0`. Si `max_memory_usage` affiche `0`/valeur par défaut, le profil n'est pas appliqué — vérifiez que les paramètres se trouvent dans un montage `users.d`, pas `config.d`. + +Compromis : avec le déversement désactivé, une requête dont l'ensemble de travail dépasse `max_memory_usage` est **rejetée** (`MEMORY_LIMIT_EXCEEDED`) plutôt que de se terminer lentement — sur un disque lent, ce rejet rapide est préférable, car une requête qui se déverse dépasserait de toute façon le délai client et échouerait. Si votre disque de données est **rapide (SSD)**, vous pouvez augmenter les seuils `max_bytes_before_external_*` pour permettre aux grandes requêtes de se déverser sur disque et de se terminer. + +--- + +## Multi-location (organisations) + +### Erreurs lors de la mise à niveau qui active les organisations (pods serveur anciens et nouveaux mélangés) + +**Symptôme :** lors d'un déploiement progressif de la version activant les organisations, certaines requêtes échouent : les journaux du serveur affichent `there is no unique or exclusion constraint matching the ON CONFLICT specification` sur le chemin `api_keys`, et/ou les canaux d'alerte/Slack/webhook cessent de fonctionner pendant le déploiement. + +**Cause :** la mise à niveau remplace l'ancien index unique à l'échelle de l'instance sur `api_keys(name)` par des index partiels par organisation, et déplace les paramètres des canaux d'alerte (et `default_user_permissions`) hors de la table globale `settings` vers des `org_settings` par organisation. Un **ancien** pod serveur émet toujours `ON CONFLICT (name)` (aucune contrainte correspondante désormais) et lit toujours la configuration des canaux depuis les anciennes lignes `settings` (maintenant vides). Les anciens et nouveaux pods ne peuvent pas coexister en toute sécurité pour ces deux chemins. + +**Correction :** ne déployez pas progressivement cette mise à niveau particulière sur des versions mixtes. Basculez proprement : réduisez l'ancien serveur à zéro (ou utilisez une courte fenêtre de maintenance) et démarrez la nouvelle version en même temps que ses migrations, plutôt qu'exécuter des réplicas anciens et nouveaux côte à côte. Le trafic normal et l'ingestion reprennent immédiatement après le basculement ; cela n'affecte que la fenêtre de transition de version. + +### L'approvisionnement d'une organisation échoue sur `CREATE USER` / `CREATE ROW POLICY`, ou une organisation peut lire les données d'une autre + +**Symptôme :** la création d'une organisation retourne une erreur mentionnant `CREATE USER`, `CREATE ROW POLICY`, ou "access management is disabled" ; ou, pire, les membres d'une organisation voient les événements/évaluations d'une autre organisation dans l'éditeur SQL ou l'assistant. + +**Cause :** l'isolation par organisation est appliquée par un utilisateur ClickHouse dédié + une politique de ligne par organisation. Cela nécessite que la **gestion des accès** SQL soit activée et que `users_without_row_policies_can_read_rows=false` sur ClickHouse. Sans la gestion des accès, l'approvisionnement ne peut pas créer l'utilisateur/la politique ; avec la valeur par défaut permissive des politiques de ligne, un utilisateur qui a SELECT mais aucune politique lit **toutes** les lignes (fail-open). + +**Correction :** utilisez la configuration `deploy/base/clickhouse/` fournie, qui définit les deux. Si vous exécutez votre propre configuration ClickHouse, activez la gestion des accès SQL sur l'utilisateur interne au serveur et définissez `users_without_row_policies_can_read_rows=false` (voir `deploy/base/clickhouse/configmap.yaml`), puis redémarrez ClickHouse et recréez l'organisation avec le CLI `agenteye-orgctl` (voir [enterprise-docs/tenant-management.md](/fr/agenteye/tenant-management)). + +### Les utilisateurs d'une organisation perdent l'accès à ClickHouse après avoir modifié `ORG_CH_SECRET` + +**Symptôme :** l'éditeur SQL et l'assistant IA retournent soudainement des erreurs d'authentification ClickHouse pour chaque organisation, immédiatement après que `ORG_CH_SECRET` a été modifié ou défini de manière incohérente entre les réplicas. + +**Cause :** le mot de passe ClickHouse de chaque organisation est dérivé comme un HMAC de `ORG_CH_SECRET`. Le faire pivoter (ou exécuter des réplicas avec des valeurs différentes) invalide les identifiants ClickHouse stockés de chaque organisation ; le mot de passe dérivé ne correspond plus à l'utilisateur approvisionné. + +**Correction :** définissez `ORG_CH_SECRET` à une valeur forte unique **avant** d'approvisionner une deuxième organisation et gardez-le stable et identique sur chaque réplica de serveur. La réconciliation au démarrage du serveur reprovisionne l'utilisateur ClickHouse de chaque organisation depuis le secret actuel au démarrage, donc un redémarrage du serveur sur tous les réplicas (avec le secret cohérent) répare les utilisateurs orphelins. Traitez la valeur comme un secret durable ; ne la faites pas pivoter légèrement. Par mesure de sécurité, si `ORG_CH_SECRET` reste à la valeur de développement intégrée (c'est-à-dire non définie), la réconciliation au démarrage **ignore** les organisations non par défaut et enregistre une erreur plutôt que de réécrire leurs identifiants ClickHouse avec la valeur de développement publiquement connue, de sorte qu'un réplica unique qui redémarre sans le secret ne peut pas casser les autres réplicas. Définissez le secret de manière cohérente et redémarrez pour approvisionner ces organisations. + +### L'assistant IA retourne 400 / refuse de dialoguer après l'activation des organisations + +**Symptôme :** le dock de l'assistant se charge mais chaque message revient avec une erreur (HTTP `400`), et l'agent enregistre une requête `/chat` sans organisation rejetée. + +**Cause :** l'agent est conscient des organisations et échoue fermé ; il rejette un `/chat` sans contexte d'organisation. Cela se produit lors d'un déploiement progressif où l'agent a été mis à niveau mais le tableau de bord envoyant la requête ne l'est pas encore. + +**Correction :** terminez le déploiement pour que le tableau de bord envoie le contexte d'organisation (l'état final normal, aucun indicateur nécessaire). Pour combler l'écart pendant qu'un tableau de bord non encore conscient des organisations communique avec un agent conscient des organisations, définissez `AGENTEYE_AGENT_ALLOW_NO_ORG=1` sur le service `agent` pour qu'il se rabatte sur l'organisation `default` au lieu de refuser, et effacez-le une fois la mise à niveau du tableau de bord effectuée. Consultez la référence des variables d'environnement dans [enterprise-docs/assistant.md](/fr/agenteye/assistant#environment-variable-reference). + +--- + +## Audits + +### Un audit ne s'exécute jamais (la prochaine exécution ne cesse de glisser, aucun historique d'exécution) + +**Symptôme :** la page d'audit affiche *dernière exécution : jamais*, ou `next run` ne cesse de se déplacer dans le futur sans qu'aucune ligne n'apparaisse dans l'historique d'exécution. + +**Cause :** l'audit est désactivé (les audits désactivés n'ont pas d'entrée dans la file d'attente), ou les travailleurs d'audit du serveur échouent à réclamer le travail. + +**Correction :** confirmez que l'audit est **activé** (le bouton d'exécution immédiate le nécessite). Vérifiez ensuite les journaux du serveur pour `audits pipeline started` au démarrage et pour les erreurs `audits:` — une ligne `claim_due failed` pointe vers la connectivité Postgres. `AUDIT_WORKERS` vaut par défaut `1` ; il doit être ≥ 1 pour qu'un audit s'exécute. + +### Les audits réussissent mais ne trouvent rien + +**Symptôme :** l'historique d'exécution affiche `succeeded` avec `findings: 0` même si `/errors` montre clairement des échecs. + +**Cause :** la fenêtre d'analyse ne couvre pas les échecs, ou les filtres de portée les excluent. + +**Correction :** vérifiez la fenêtre de la ligne d'exécution (`window_from → window_to`) par rapport au moment où les échecs se sont produits — en mode `since_last`, chaque exécution n'analyse que depuis la dernière exécution réussie, donc les anciens échecs ne sont vus que par la *première* exécution ou un audit à fenêtre `fixed`. Élargissez `scope` (environnements / identifiants d'agent). Les statistiques d'exécution affichent `policy_hits` (combien de politiques déterministes ont été déclenchées) et `improvements` (combien l'investigation IA a enregistrées) — si les deux valent 0, la fenêtre/portée n'a genuinement rien vu. + +### L'exécution affiche `analysis_unavailable` et ne produit que des résultats de politiques + +**Symptôme :** les statistiques d'exécution incluent `analysis_unavailable` et les seuls résultats sont de type `kind: policy` ; aucune amélioration IA n'apparaît. + +**Cause :** l'investigation agentique n'a pas pu s'exécuter : le serveur ne peut pas atteindre le service agent (`AGENTEYE_AGENT_URL` / `AGENTEYE_AGENT_TOKEN` non définis sur le **serveur** — l'audit réutilise la connexion de l'assistant), le service assistant n'a pas de LLM configuré, ou l'appel a échoué/expiré (la chaîne `analysis_unavailable` contient le détail). La passe de politiques déterministes est le plancher — elle s'exécute toujours — donc l'audit réussit quand même avec ses résultats de sécurité. + +**Correction :** définissez ` \ No newline at end of file diff --git a/docs/he/agenteye/alerts.mdx b/docs/he/agenteye/alerts.mdx new file mode 100644 index 00000000..7d91b74a --- /dev/null +++ b/docs/he/agenteye/alerts.mdx @@ -0,0 +1,308 @@ +--- +title: "התראות" +description: "תיעוד התראות AgentEye." +--- + +התראות מערכות כלל על לוח זמנים ומודיעות לך כאשר משהו חוצה סף. הן הופכות את AgentEye מלוח מחוונים פסיבי למשטח דירוג לדברים החשובים: עליות בשיעור שגיאות, רגרסיות בזמן תגובה, ירידות בציוני מעריך, או כל אירוע מותאם שאתה יכול להביע כשאילתה ClickHouse. + +מדריך זה מכסה מה זו התראה, חמישת סוגי ההדלקה, ארבע ערוצי ההודעות, מחזור החיים של התקרית, וחוגי הפעולה. + +![דף התראות: רשת של כרטיסי כללי התראות, כל אחד מציג את סוג ההדלקה שלו, חלון הערכה, ערוצים, ותג חומרת חומרה/אזהרה/קריטית](/agenteye/images/alerts.png) + +--- + +## מושגים + +- **התראה** — הכלל. הוא אומר *מה* לבדוק (ההדלקה), *כמה לעתים קרובות* (מרווח ההערכה), *מתי להתייחס אליו כשבור* (לוגיקה מרוכבת), *כמה דחוף* (חומרה), ו*מי/איפה להודיע* (ערוצים). +- **תקרית** — מה קורה כאשר התראה משתלחת. התראה אחת יכולה להיות בעלת תקרית פתוחה אחת בלבד בכל פעם. הפרות חוזרות מעדכנות את ראיות אותה תקרית. תקריות נפתרות על ידי מפעיל; רזולוציה אוטומטית כאשר הכלל מפסיק לשלוח אותות מתוכננת אך לא מופעלת כרגע. +- **ערוץ** — היכן הודעה מגיעה: דוא"ל, Slack, webhook כללי, או בתוך הלוח. כל התראה יכולה לצרף כל שילוב. + +התראות ותקריות שייכות לארגון ומשותפות בין מפעילי הארגון הזה (בפריסה חד-שוכנית זה פשוט הארגון המובנה `default`). ניתן להקצות תקריות למפעיל בודד לבדיקה. + +--- + +## סוגי הדלקה + +חמישה סוגים, כל אחד עם תו JSON משלו. בחר את זה שמתאים לדרך שבה אתה רוצה לתאר "שבור". טופס **התראה חדשה** של הלוח משנה את אותו תו עבורך, ומעביר את עורך התנאי כדי להתאים לסוג ההדלקה שבחרת: + +![טופס התראה חדשה, עם היסודות (שם, תיאור, מופעל) ובורר ההדלקה המציג סף מטרי, SQL מותאם, ניקוד הערכה, כשלים בהערכה, ואפשרויות לכל אירוע](/agenteye/images/alert-new.png) + +### 1. `metric_threshold` + +הפשוט ביותר. בחר מטרי מרשימה סגורה, מפעיל, סף, וחלון זמן. + +| מטרי | מה זה סופר | +|---|---| +| `event_count` | סך הכל אירועים בחלון | +| `error_count` | `event_type = 'error'` או כל אירוע עם `error_type IS NOT NULL` | +| `error_rate` | `error_count / event_count` (0..1) | +| `p95_latency_ms` | `quantile(0.95)(duration_ms)` על פני כל האירועים עם `duration_ms` | +| `p99_latency_ms` | `quantile(0.99)(duration_ms)` | +| `token_sum` | `SUM(input_tokens + output_tokens)` | + +מפעילים: `>`, `>=`, `<`, `<=`, `==` (גם מקובל כ-`gt`, `gte`, `lt`, `lte`, `eq`). + +מסננים אופציונליים: `environment`, `event_type`. + +דוגמה למפרט: + +```json +{ + "metric": "p95_latency_ms", + "filter": { "environment": "production" }, + "window_secs": 900, + "op": ">", + "value": 5000 +} +``` + +### 2. `custom_sql` + +לכל דבר שהמטריקות הקבועות מראש לא מכסות. ה-SQL שמסר המפעיל עובר דרך אותו שומר `/queries/run` (SELECT/WITH בלבד, הצהרה יחידה, תקרת שורות 10,000) לפני שהמשלח מריץ אותה. שני מצבים: + +- **מצב שורות** (ללא `op`/`value`): ההתראה משתלחת ברגע שהשאילתה מחזירה לפחות שורה אחת. +- **מצב ערך**: השאילתה חייבת לכנות עמודה אחת כ-`metric_value`; המשלח משווה את ה-`metric_value` של השורה הראשונה מול `value` באמצעות `op`. + +```json +{ + "sql": "SELECT count() AS metric_value FROM agenteye.events WHERE event_type = 'error' AND ts >= now() - INTERVAL 1 HOUR", + "op": ">", + "value": 100 +} +``` + +### 3. `evaluation_score` + +קורא מ-`agenteye.evaluations` ומשווה את הממוצע של ציון בשם על פני חלון. + +```json +{ + "score_key": "hallucination", + "op": ">", + "value": 0.6, + "window_secs": 3600, + "min_count": 5, + "environment": "production" +} +``` + +`min_count` מגן מפני חריגי מדגם יחיד; המשלח לא ישלח עד שלפחות N הערכות קיימות בחלון. + +### 4. `eval_compound` + +תופסת רגרסיה בחומר שמופיעה רק על פני *מספר* ציוני מעריך בו-זמנית. כאשר `evaluation_score` עוקבת אחר ציון בשם יחיד, `eval_compound` מרכיבה מספר תנאי ציוני הערכה לתראה אחת ומשלבת את התוצאות שלהן עם לוגיקה שנבחרה; אז כלל אחד יכול להביע "שלח אם עזרתיות ירידה **או** הזיות עולות", "שלח רק אם עזרתיות **ו** יעילות כלים שתיהן ירידות", או "שלח אם **לפחות 2 מ** שלוש הבדיקות הללו הפרו". + +כל תנאי קורא את הממוצע של ציון בשם אחד מ-`agenteye.evaluations` על פני החלון המשותף ובוחן אותו עם מפעיל וסף משלו. התוצאות הבוליאניות משולבות לאחר מכן על ידי `combinator`: + +| משלב | לוגיקה | משלח כאשר | +|---|---|---| +| `"any"` | OR | לפחות תנאי אחד הופר | +| `"all"` | AND | כל תנאי הופר | +| `{ "at_least": N }` | M-of-N | לפחות N תנאים הופרו | + +```json +{ + "combinator": { "at_least": 2 }, + "conditions": [ + { "score_key": "hallucination", "op": ">", "value": 0.8 }, + { "score_key": "helpfulness", "op": "<", "value": 0.6 }, + { "score_key": "tone", "op": "<", "value": 0.5 } + ], + "window_secs": 3600, + "min_count": 5, + "environment": "production" +} +``` + +- `combinator`: `"any"`, `"all"`, או `{ "at_least": N }`. +- `conditions[]`: כל `{ score_key, op, value }`, תוך שימוש באותם מפעילים כמו ההדלקות האחרות (`>`, `>=`, `<`, `<=`, `==`). +- `window_secs`: ההחזר אחורה המשותף החל על כל תנאי (ברירת מחדל `3600`). +- `min_count`: מספר הערכות מינימום לכל תנאי לפני שתנאי זה יכול להיות הפרה; תנאי בעל דגימות מעטות מדי בחלון נחשב "לא הופר" (ברירת מחדל `1`). +- `environment`: אופציונלי; מגביל כל תנאי לסביבה אחת. + +ראיות ההודעה רושמות את הממוצע שנצפה של כל תנאי, את הסף שהוא בוחן מולו, כמה הערכות נראו, ואם הוא הופר; כך שתוכל לראות בדיוק אילו בדיקות הצביעו. + +### 5. `per_event` + +לכל התראות "כל אירוע התואם X נחת". ללא צבירה; המשלח משלח ברגע שהוא רואה התאמה בחלון ההחזר אחורה. + +```json +{ + "event_type": "error", + "lookback_secs": 60, + "environment": "production", + "tool_name": "bash", + "agent_id": "caa", + "error_type": "TimeoutError", + "message_contains": "vertex-ai timed out" +} +``` + +כל המסננים משולבים עם AND; כל שדה שתשאיר אינו מוגבל. + +| שדה | מטרה | +|---|---| +| `agent_id` | הגבל לשגיאות מסוכן ספציפי (האחד המוצג בשורת `/errors`). | +| `error_type` | הגבל למחלקת שגיאה ספציפית (למשל `TimeoutError`) ולא לכל שגיאה. | +| `message_contains` | התאמת מחרוזת משנה לא תלויה בגודל אותיות מול `payload.message`. שימושי לתפיסת אופן כשל ספציפי אחד (למשל `prompt is too long`) ללא התראה על כל שגיאה מהסוכן זה. מוגבל ל-200 תווים; התאם כמחרוזת מילולית, לא כדפוס. | + +טיפ: קבע את `lookback_secs` ערך בערך להתאמת `eval_interval_secs` של ההתראה כך שלא תקבל הודעה כפולה על אותו אירוע. + +**קיצור מ-`/errors`:** לכל קבוצת שגיאה שורה כונית בתצוגת השגיאות (וחלונת פרטי אירוע הסעת לאירוע שגיאה) יש כפתור **+ התראה** שפותח את `/alerts/new` מלא מראש עם ההדלקה `per_event` מחובר לאותו שורה של `event_type` + סביבה, כולל שם שזוריע מ-`error_type` של הטעון כאשר קיים. אתה עדיין בוחר ערוצים ומאשר את ההחזר אחורה, אבל התאמה היא מלאה עבורך. מפעילים צריכים `alerts:write` כדי שהכפתור יופיע. + +--- + +## לוגיקה מרוכבת (M of N) + +לכל התראה יש שני כפתורים שלמים בנוסף להדלקה: + +- `eval_window`: כמה הערכות אחרונות להסתכל על (ברירת מחדל 1) +- `min_breaches`: כמה מהן חייבות להיות הפרה לפני שההתראה משתלחת (ברירת מחדל 1) + +`1 of 1` (ברירת המחדל) הוא "שלח בהפרה הראשונה". `3 of 5` אומר "שלח כאשר הכלל הופר 3 מ-5 ההערכות האחרונות", שימושי לאותות רועדים כאשר מדידה רעה אחת היא רעש. המשלח מתחזק חיץ טבעת לכל התראה; אתה לא צריך לנהל מדינה. + +--- + +## מרווח הערכה + +`eval_interval_secs` שולט כמה לעתים קרובות המשלח מריץ את הכלל שלך. מוגבל ל-`[30, 86400]`. קבועות בלוח: 1m / 5m / 15m / 1h. בחר מרווח תואם לאופן תנועת האות הבסיסי: התראת שיעור שגיאה של 5 דקות המוערכת כל 15 שניות בזבוזי CPU; התראה לכל אירוע צריכה החזר אחורה קצר או היא תשמיט בשקט אירועים בין קללות. + +--- + +## ערוצים + +כל התראה יכולה לצרף כל שילוב מאלה הארבע. פרטי עדכון לערוץ (Slack webhook URL, generic webhook URL + חתימת סודי, נמענים דוא"ל ברירת מחדל) מוגדרים פעם אחת בַ**`/settings`** והנקובים לפי מפתח מכל התראה. בדרך זו ערוץ Slack אחד יכול לשרת התראות רבות ללא כל אחד לאחסן את העתק משלו של ה-webhook URL. + +שלושת סוגי הערוץ החיצוני (דוא"ל, Slack, webhook) גם מהודקים על ידי כיבוי ארגוני רחב-חלל, `alerts.enabled_channels`. כאשר התראה משתלחת מצרפת סוג ערוץ שאינו בקבוצה זו, המשלח מדלג עליה ורושם שורת `alert_notifications` עם סטטוס `skipped_disabled` ויעד `` (שיכול לעזור לך לעצור בכללי, נגיד, את כל משלוח Slack ללא עריכת כל כלל). ערוץ בתוך הלוח תמיד מותר. ראה [תצורה](#configuration). + +### דוא"ל + +משתמש בשפל SMTP זהה שחומק אימיילי התחברות OTP. נמענים פותרים בסדר: + +1. החזקה ערוץ-ספציפית `recipients[]` (כאשר לא ריק). +2. הגדרת `alerts.email_default_recipients` (מערך של מחרוזות דוא"ל). + +אם SMTP אינו מוגדר הערוץ הוא no-op; המשלח עדיין רושם שורת `alert_notifications` עם יעד `` כך ששביל הביקורת הופך את ההשגחה גלויה. + +### Slack + +שולח הודעת Block Kit ל-[Incoming webhook URL](https://api.slack.com/messaging/webhooks). + +- URL ברירת מחדל: `alerts.slack_default_webhook` (קבע בַ`/settings`). +- עקיפה לכל התראה: קבע את `webhook_setting_key` של הערוץ לכל מפתח הגדרה מסוג URL אחר, למשל `alerts.slack_oncall`, `alerts.slack_costs`. + +ראש כלול אימוג'י חומרה (`:rotating_light:` / `:warning:` / `:bell:`), והודעה נושאת כפתור שחובר עמוק לדף התקרית. + +### Webhook כללי + +אינטגרציה JSON-POST לכן PagerDuty, Opsgenie, או נקודת קבלה משלך. צורת הגוף: + +```json +{ + "schema_version": 1, + "event": "alert.firing", + "incident": { "id": "uuid", "url": "https://…/incidents/uuid", "opened_at": "2026-…" }, + "alert": { "id": "uuid", "name": "errors > 50/hr", "severity": "critical" }, + "breach": { "value": 73.0, "summary": "ErrorCount > 50 (observed 73.000)", "evidence": { … } } +} +``` + +כאשר `alerts.webhook_signing_secret` מוקבע, הבקשה כוללת כותרת `X-AgentEye-Signature: sha256=`, ה-HMAC-SHA256 של הגוף באמצעות הסוד. אמת אותה בצד המקבל לפני הסמכת הטעון. + +ראש `X-AgentEye-Event` נושא `alert.firing` / `alert.test`. (`alert.resolved` שמור לתכונת ההסדר האוטומטי המתוכננת ואינו נפלט כרגע.) + +### בתוך הלוח + +ללא משלוח חיצוני: ההתראה פשוט כותבת שורת `alert_notifications` שדף התקריות של הלוח משטח. שימושי בזמן כיוונון כלל ולא רוצה לספאם מערכת חיצונית, או לתראות נמוכות-דחיפות שמפעילים בודקים במהלך בדיקה רגילה. + +--- + +## מחזור חיים של תקרית + +``` +firing ──ack──▶ acknowledged + │ │ + └────────────────────┴───── operator resolve ───▶ resolved +``` + +- **משדר** — המשלח פשוט פתח את התקרית או גילה הפרה נוספת. הודעת הדלקה היא מחוברת בדיוק פעם אחת (מהודקת על ידי חותמת הזמן `notified_firing_at` על התקרית). +- **מודה** — מפעיל לחץ על *ack* בַ`/incidents/:id`. התקרית עדיין נחשבת פתוחה; הפרות עתידיות יעדכנו את ראיות שלה ללא הודעה חוזרת. +- **פתור** — מפעיל לחץ על *resolve*. רזולוציה אוטומטית כאשר הכלל מפסיק לשלוח אותות מתוכננת אך לא מופעלת כרגע, כך שתקרית פתוחה נשארת פתוחה עד שמפעיל פותר אותה. + +תקרית חדשה יכולה להפתח מחדש על אותה התראה בכל נקודה לאחר רזולוציה של קודמתה. + +**ציר זמן פעילות.** כל פעולה על תקרית — נפתחה, הודתה, פתורה — מתועדה בעיתון פעילות המצטבר בלבד ומופיעה בציר הזמן *פעילות* של התקרית, כל כניסה המיוחסת למפעיל שביצע אותה (לפי דוא"ל) או **automated** לפעולות המשלח לקח בעצמו (auto-open בהפרה). הודעה משותפת: מספר מפעילים יכולים ack אותה תקרית וכל אחד מופיע כערך מובחן ומיוחס. + +תא **התקריות** מקבץ תקריות פתוחות לפי מצב ומאפשר לך לסנן לפי חומרה ומועסק: + +![תא התקריות המציג כרטיסי תקריות מקושרות התראה וכרטיסי תקריות אד-הוק עם תגי חומרה ומועסקות](/agenteye/images/incidents.png) + +פתיחת תקרית מציגה את ראיות ההפרה, מועסקות והמנויים, ציר הזמן של הפעילות המיוחסת, ועצומת הערות: + +![תצוגת פרטי תקרית: התראה האב, סיכום הפרה, מועסקות, מנויים, עיתון פעילות מיוחס, ושיחה](/agenteye/images/incident-detail.png) + +--- + +## הרשאות נדרשות + +תוכן כללי *התראות* ובדיקת *תקריות* הם חששות נפרדים עם מענקים נפרדים, כך שתוכל להעניק לסיבוב ברירת מחדל גישה תקרית ללא סיפור לתוכה גם היכולת לכתוב מחדש את הכללים. + +- `alerts:read`: הצג כללי התראות. +- `alerts:write`: צור, ערוך, מחק כללי התראות, והפעל הודעת בדיקה. +- `incidents:read`: הצג תקריות. +- `incidents:write`: פתח תקריות ידניות (ad-hoc) שאינן קשורות להתראה. +- `incidents:ack`: הודא, הקצה, הערות, ופתור תקריות. + +> **הורשת `alerts:ack` מורשת.** מפתחות ומפעילים שהוענקו לטוקן `alerts:ack` הישן שלהם ממשיכים לעבוד: זה מכובד כ-`incidents:ack` (והרמז `incidents:read`), כך שיום-קרוביות קיימות שומרות על גישתם ללא הדלקה מחדש של פרטים. בעיה מענקים חדשים עם המשפחה `incidents:*`. + +מענק על מפתחות API (`POST /keys`) ומפעילים (`PUT /users/:id`). `PermGate` של הלוח נועל את הכפתורים הרלוונטיים כאשר הרשאה חסרה; תראה `// 403` ליד הפעולה. + +> **בורר נמען דוא"ל.** בורר הנמענים של עורך ההתראות רושם את חברי הארגון שלך כך שתוכל לבחור אותם לפי שם. הוא טוען לכל מפעיל המחזיק `alerts:read` או `alerts:write`; צפיית ספרית הצוות שלך למטרה זו **לא** דורשת `users:read`, והבורר מחזיר רק כתובות דוא"ל של חברים, לעולם לא רשומות משתמש מלאות. + +--- + +## תצורה + +משתנים סביבה שנצרכו על ידי המשלח: + +| Var | ברירת מחדל | מטרה | +|---|---|---| +| `ALERT_WORKERS` | `1` | משימות עובדים לכל מופע שרת. רוב הפריסות צריכות רק אחד. | +| `ALERT_CLAIM_BATCH` | `16` | התראות מרביות עובד יחיד מעבד. | +| `ALERT_POLL_IDLE_SECS` | `5` | שינה עובדת כאשר התור ריק. | +| `ALERT_REQUEST_TIMEOUT_MS` | `15000` | פרקודה הערכה הדלקה. | +| `DASHBOARD_URL` | `https://app.befailproof.ai` | מקור המשמש לבניית קישור הקסם של תקרית בהודעות. קבע לבעלות לוח הבקרה שלך. | + +לאחר כשל הערכה חולף (ClickHouse בלתי נגיש, פרק זמן שאילתה), המשלח מנסה מחדש את הכלל עם מעוך אקספוננציאלי. ברגע שלכלל יש זכירה **5** כשלים חוליים רצופים הוא משוכסל בקדנציה רגילה שלו בכל מקום חוקי על רקע להמשיך, לכן כלל שמשכך בעקביות עדיין ממשיך להיות מוערך מחדש. תקרה זו קבועה ואינה מתויבלת על ידי מפעיל. + +הגדרות ערוץ (מנוהל מ-`/settings`, לא env): + +- `alerts.email_default_recipients` (`email_list`): מערך JSON של מחרוזות דוא"ל — הנמענים ברירת המחדל לערוצי דוא"ל. +- `alerts.slack_default_webhook` (`url`): URL webhook נכנס ברירת המחדל של Slack. +- `alerts.webhook_default_url` (`url`): generic-webhook URL ברירת המחדל. +- `alerts.webhook_signing_secret` (`secret`): מפתח HMAC-SHA256. תמיד החזר כ-`""` בתגובת GET; הקלד ערך חדש לסיבוב. +- `alerts.enabled_channels` (`channel_set`): קבוצת ערוצים חיצוני רחב-ארגוני שמשודרות כאשר התראה משתלחת; ברירות לכל שלוש (`email`, `slack`, `webhook`). הסרת סוג כאן משעות את הערוץ בכללי לכל התראה ללא עריכת כל כלל. ערוץ בתוך הלוח תמיד מועבר ואינו מושפע מהגדרה זו. + +--- + +## אמת התראה חדשה + +לפני הסמכה על התראה חדשה: + +1. שמור אותו כמופעל עם לפחות ערוץ הודעות אחד. +2. בחר **בדיקה** בעמוד פרטי ההתראה וקבל את הודעת הבדיקה הסינתטית בכל יעד מוגדר. +3. לאחר ההפרה הראשונה בעולם האמת, קבל את הופעת התקרית תחת **Incidents** וערכו הנמדד תואם את שאילתת הלוח המקביל. + +תקריות לא נפתרות באופן אוטומטי כאשר תנאי מתנקה. מפעיל חייב לפתור אותם מעמוד פרטי התקרית. + +--- + +## פתרון בעיות + +| סימפטום | סיבה סבירה | +|---|---| +| התראה לא משתלחת לעולם | `enabled = false`, או אין ערוצים מצורפים, או שאילתת CH בסיסית מחזירה 0 שורות. השתמש בתקן *לבדיקה* כדי לקבל ערוצים; השתמש ב-`/queries/run` כדי לקבל המטרי. | +| הודעת Slack חסרה | `alerts.slack_default_webhook` (או מפתח העקיפה לכל התראה) אינו קבוע: בדוק `alert_notifications.target` לשורות ``; או `slack` סוג מופעל בגלל ב`alerts.enabled_channels`: בדוק שורות `alert_notifications` עם סטטוס `skipped_disabled` ויעד ``. | +| Webhook כללי 401 | התמקד דורש חתימה אך `alerts.webhook_signing_secret` אינו קבוע. אמת בנמקד שה-HMAC תואם `hmac_sha256(secret, body)`. | +| דוא"ל "מכל השידורים נכשלו" | פרטי SMTP שגויים או כתובת `from` נדחתה על ידי השידור שלך. אותו משטח שחומק אימיילי OTP: אם אלה עובדים, תחבורת SMTP בסדר. | +| תקרית משחזרת שוב ושוב | כפתורי המרוכב תוקפים מדי: נסה להרים את `min_breaches` או `eval_window` אז טריגרים חולפים לא פתוחים מחדש תקריות פתרת. | \ No newline at end of file diff --git a/docs/he/agenteye/api-keys.mdx b/docs/he/agenteye/api-keys.mdx new file mode 100644 index 00000000..47b5e3b4 --- /dev/null +++ b/docs/he/agenteye/api-keys.mdx @@ -0,0 +1,255 @@ +--- +title: "מפתחות API" +description: "תיעוד מפתחות API של AgentEye." +--- + + +AgentEye משתמש במפתחות API דקים להשתלטה על גישה לשרת. כל מפתח נושא הרשאה אחת או יותר המגדירות את מה שהוא יכול לעשות. + +--- + +## הרשאות + +השרת אוכף קטלוג קבוע של הרשאות; כל אחת מהן שומרת על נתיבי HTTP ספציפיים. **מפתח admin** מחזיק בכולן; מפתח בתחום מחזיק בתת-קבוצה שתאשרו בעת יצירה. מחרוזות הרשאות לא ידועות נדחות בעת יצירת מפתח. + +> **לא ניתן להקצות למפתחות.** שתי הרשאות תקפות הן dashboard-only של אדם ולא יכולות להיות ממונות למפתח API: `orgs:admin` (ניהול אינסטנסיה, המיוחד למפעיל) ו-`keys:update`. בקשה ל-`POST /keys` או `PATCH /keys/:id` שמנסה להעניק אחת מהן נדחית עם HTTP 422. ראה את השורה `keys:update` למטה כדי להבין מדוע מפתח bearer עשוי ליצור מפתחות אך לעולם לא לערוך אותם. + +### קבלה וביצוע שאילתות של אירועים + +| הרשאה | נתיבי HTTP | מה זה מאפשר | +|---|---|---| +| `events:add` | `POST /events` | קבל אירועים בערך מאספן. זו ההרשאה היחידה שאספן צריך. | +| `events:read` | `GET /events`, `GET /events/latency_aggregate`, `GET /events/environments`, `GET /events/models`, `GET /sessions/:session_id/export` | בצע שאילתות על אירועים, רשום את הסביבות הידועות, רשום את מזהי המודל שנראו בנתונים (בו משתמשים בתצוגת Models ובמסננים מודל), חשב את ההצבירה של latency המנעה את מפת החום / פס האחוזון, וייצא הפעלה כ-JSONL. נקודות קצה של ההיבט של סרגל המסננים המשותף `GET /events/environments` ו-`GET /events/models` נגישות עם **כל אחד** מ-`events:read` **או** `evaluations:read`, כך שדף ההפעלות (סגור `evaluations:read`) משחזר את אותו ממד per-org. | + +### הפעלות והערכות + +| הרשאה | נתיבי HTTP | מה זה מאפשר | +|---|---|---| +| `evaluations:read` | `GET /sessions`, `GET /evaluations`, `GET /evaluations/aggregate`, `GET /evaluations/environments`, `GET /evaluation-jobs` | רשום הפעלות, קרא תוצאות הערכה, בריאות ההערכה שנאספו המשמשות לוח מחוונים, וזה המצב של שורת חריטה evaluation-job. | +| `evaluations:trigger` | `POST /sessions/:session_id/re-evaluate` | שורת הערכה מחודשת ידנית עבור הפעלה מוגמרת. | + +### לוחות מחוונים + +| הרשאה | נתיבי HTTP | מה זה מאפשר | +|---|---|---| +| `dashboards:read` | `GET /dashboards`, `GET /dashboards/:id`, `GET /dashboards/:id/tiles` | רשום לוחות מחוונים, טען אחד, וקרא את אריחיו. | +| `dashboards:write` | `POST /dashboards`, `PUT /dashboards/:id`, `POST /dashboards/:id/tiles`, `PUT /dashboards/:id/tiles/:tile_id`, `DELETE /dashboards/:id/tiles/:tile_id`, `PUT /dashboards/:id/tiles/layout` | צור וערוך לוחות מחוונים, הוסף / ערוך / הסר אריחים, וסדר מחדש את רשת האריח. | +| `dashboards:delete` | `DELETE /dashboards/:id` | מחק לוח מחוונים שלם (מחיקה ברמת אריח נמצאת תחת `dashboards:write`). | + +### שאילתות שמורות (SQL composer) + +| הרשאה | נתיבי HTTP | מה זה מאפשר | +|---|---|---| +| `queries:read` | `GET /queries`, `GET /queries/:id`, `GET /queries/schema` | רשום שאילתות שמורות, טען אחת, וסקור את סכמת ClickHouse read-only שאליה יוצב ה-composer. | +| `queries:write` | `POST /queries`, `PUT /queries/:id` | צור וערוך שאילתות שמורות. SQL בעדיין מנותב דרך אותו תפקיד read-only ובדיקות `sql_guard` כמו קריאה `queries:run`. | +| `queries:delete` | `DELETE /queries/:id` | מחק שאילתה שמורה. | +| `queries:run` | `POST /queries/run` | בצע SQL שמור או ad-hoc כנגד תפקיד read-only המשמש את ה-composer. | + +### עוזר AI + +| הרשאה | נתיבי HTTP | מה זה מאפשר | +|---|---|---| +| `agent:use` | `GET /agent/conversations`, `POST /agent/conversations`, `GET /agent/conversations/:id`, `PATCH /agent/conversations/:id`, `DELETE /agent/conversations/:id`, `PUT /agent/conversations/:id/messages` | שוחח עם עוזר AI של לוח המחוונים וטפל בשיחות שלך (פרטיות). נדרש ב-**משתמש** כדי לראות את עגינת העוזר; המפתח שלו של העוזר הוא `dashboard-assistant` וזרוע בנפרד (ראה למטה). | + +### מפתחות API + +| הרשאה | נתיבי HTTP | מה זה מאפשר | +|---|---|---| +| `keys:create` | `POST /keys` | צור מפתח API בתחום חדש. **לא** מעניק עריכה של הרשאות של מפתח קיים (זה `keys:update`). | +| `keys:read` | `GET /keys` | רשום מפתחות קיימים. Secrets אף פעם לא מוחזרים על ידי נקודת קצה זו. | +| `keys:update` | `PATCH /keys/:id` | ערוך הרשאות של מפתח קיים. הרשאה **dashboard-only** של אדם; היא לא יכולה להיות מהוקצית למפתח API (מפתח bearer עשוי ליצור מפתחות אך לעולם לא לערוך אותם). | +| `keys:disable` | `POST /keys/:id/disable` | שלול מפתח. מפתחות מוגנים (`admin`, `dashboard-assistant`) לא יכולים להיות מחוסלים; סובב אותם דרך env var + הפעל מחדש. | +| `keys:regenerate` | `POST /keys/:id/regenerate` | סובב את ה-secret של מפתח. מפתחות מוגנים לא יכולים להיווצר מחדש דרך נקודת קצה זו. | + +### משתמשי לוח מחוונים + +| הרשאה | נתיבי HTTP | מה זה מאפשר | +|---|---|---| +| `users:create` | `POST /users`, `GET /users/defaults` | הזמן משתמש לוח מחוונים חדש (הוציא דוא"ל + כניסת OTP) וקרא את ערכת ההרשאות שהתוצבה בלוח המחוונים המשמשת זרע את טופס ההזמנה. | +| `users:read` | `GET /users`, `GET /users/:id` | רשום משתמשים וטען רשומת משתמש יחידה. | +| `users:update` | `PUT /users/:id` | ערוך הרשאות של משתמש. עדכונים שלחו דוא"ל לשינוי הרשאות למשתמש המושפע ונכנסו לתוקף בבקשתו הבאה; לא נדרש כניסה מחדש. | +| `users:delete` | `DELETE /users/:id`, `POST /users/:id/enable` | הפוך משתמש (שלול את הפעלותיו מיד) והפוך משתמש מוסקה לפעיל. | + +הרשאות אלה תומכות בדף **Users** של לוח המחוונים, כאשר ההיקפים המוקצים של כל חברה מוצגים כחתיכות: + +![דף Users: כרטיס לכל משתמש לוח מחוונים עם הדוא"ל שלו, הרשאות מוקצות, ועריכה/הפוך פקדים](/agenteye/images/users.png) + +### הגדרות תפעוליות + +| הרשאה | נתיבי HTTP | מה זה מאפשר | +|---|---|---| +| `settings:read` | `GET /settings`, `GET /settings/schema`, `GET /settings/model-context-windows`, `GET /settings/model-context-windows/resolve` | הצג הגדרות תפעוליות מנוהלות בלוח המחוונים ושלהן metadata; רשום עקיפות מחלון הקשר לכל מודל; ופתור את החלון האפקטיבי עבור מודל. | +| `settings:write` | `PUT /settings/:key`, `PUT /settings/model-context-windows`, `DELETE /settings/model-context-windows` | ערוך הגדרות תפעוליות והוסף, שנה, או הסר עקיפות מחלון הקשר לכל מודל. שינויים משפיעים על אירועים חדשים ללא הפעלה מחדש של השרת. | + +![דף Settings: הגדרות תפעוליות מנוהלות בלוח המחוונים כגון כניסות מורשות ותוחלות חיים של הפעלה/OTP, הניתנות לעריכה ללא הפעלה מחדש](/agenteye/images/settings.png) + +### התראות והתקריות + +| הרשאה | נתיבי HTTP | מה זה מאפשר | +|---|---|---| +| `alerts:read` | `GET /alerts`, `GET /alerts/:id` | הצג הגדרות התראות שהוגדרו. | +| `alerts:write` | `POST /alerts`, `PUT /alerts/:id`, `DELETE /alerts/:id`, `POST /alerts/:id/test` | צור, ערוך, מחק, ובדוק שריפת הגדרות התראות. | +| `incidents:read` | `GET /alerts/incidents`, `GET /alerts/incidents/:iid`, `GET /alerts/incidents/:iid/comments`, `GET /alerts/incidents/:iid/subscribers` | הצג התקריות והנתיב של ההערמה שלהן. | +| `incidents:write` | `POST /alerts/:id/incidents` | פתח התקרייה ידנית כנגד התראה קיימת. | +| `incidents:ack` | `POST /alerts/incidents/:iid/ack`, `POST /alerts/incidents/:iid/assign`, `POST /alerts/incidents/:iid/resolve`, `POST /alerts/incidents/:iid/comments`, `POST /alerts/incidents/:iid/subscribe`, `POST /alerts/incidents/:iid/unsubscribe` | הודה בהתקריות, הקצה, פתור, ותיאור התקריות. | + +### ביקורות + +| הרשאה | נתיבי HTTP | מה זה מאפשר | +|---|---|---| +| `audits:read` | `GET /audits`, `GET /audits/:id`, `GET /audits/:id/runs`, `GET /audits/findings`, `GET /audits/findings/:fid` | הצג הגדרות ביקורת, היסטוריית הריצה, ותוצאות. | +| `audits:write` | `POST /audits`, `PUT /audits/:id`, `DELETE /audits/:id`, `POST /audits/:id/run`, `POST /audits/findings/:fid/status` | צור, ערוך, מחק, והרץ ביקורות; הערמת תוצאות (הודא / השתק / דחה / פתור / פתח מחדש / הקצה). | + +> כאשר Audits הושקו, בעלי זכויות קיימים הורחבו לאורך אותן צורות תפקיד כמו התראות: כל משתמש וערכת הרשאות המחזיקים `alerts:read` קיבלו `audits:read`, וכל בעל `alerts:write` קיבל `audits:write`. מפתחות API קיימים **לא** הורחבו — הקצה `audits:*` למפתח בעצמאות אם הוא צריך את משטח הביקורת. + +> Stored grants של ה-legacy `alerts:ack` token מנותחים כ-`incidents:ack` כך שעל-קוראים שומרים על גישה ללא rekeying. ה-token כבר לא ניתן להקצאה מעורך המשתמשים של לוח המחוונים; המטריצה מציעה `incidents:ack` במקום. + +> נקודת קצה של picker-הנמען `GET /alerts/recipients` (אשר רשומה את דוא"ל החברים שעורך ההתראה יכול להודיע) נגישה על ידי בעל **כל אחד** מ-`alerts:read` **או** `alerts:write`, כך שעורכי התראות יכולים למלא את ה-picker ללא הקצאה של `users:read`. + +> צופה לוחות מחוונים צריך **הן** `dashboards:read` (כדי לטעון את התצוגות השמורות) **והן** `evaluations:read` (מדדי הבריאות מחושבים מנתוני הערכה). הקצה `dashboards:write` כדי לאפשר למשתמש ליצור או לערוך לוחות מחוונים, ו-`dashboards:delete` כדי להסיר אותם. + +> `/health` ו-`/auth/*` (בקשת OTP, אימות OTP, בדיקת הפעלה, התנתקות) הם לא מאומתים בעיצוב; הם זרימת ההתחברות וחוקר חיות. `GET /access-granters` דורש מפתח תקף אך אין הרשאה ספציפית, כך שכל משתמש מחובר יכול לראות אילו admins יש ליצור קשר איתם בנוגע לשינויי גישה. + +--- + +## ערכות הרשאות + +ערכות הרשאות מאפשרות לך להחיל תפקיד שם תחת בחירה ידנית של אסימונים בודדים בכל פעם. במקום לבחור תריסר הרשאות אחת אחת עבור כל משתמש לוח מחוונים או מפתח API חדש, אתה בוחר ערכה, וכולם שהוקצו לו נושא הענקה עקבית וניתנת לבדיקה. עריכה של ערכת מותאם מחודשת את ההענקה החדשה לכל משתמש שכבר הוקצה לו, כך ששינוי תפקיד הוא עריכה אחת ולא טיפול בכל חברה. + +כל ארגון זרוע עם שלוש ערכות מובנות: + +| ערכה | הרשאות | מיועד ל | +|---|---|---| +| `read-only` | `events:read`, `keys:read`, `users:read`, `evaluations:read`, `dashboards:read`, `queries:read`, `settings:read`, `alerts:read`, `audits:read`, `incidents:read` | גישה לצפייה בלבד בכל משטח תפעולי. | +| `standard` | הכל ב-`read-only`, בתוספת `evaluations:trigger`, `queries:run`, `incidents:ack`, `agent:use` | קרא בלבד בתוספת פעולות על-קורא יומיומיות: הרץ שאילתות, הערך הפעלות מחדש, הודא התקריות, והשתמש בעוזר ה-AI. | +| `admin` | כל הרשאה הניתנת להקצאה | שליטה מלאה בארגון. | + +שלוש הערכות המובנות הן **בלתי ניתנות לשינוי**; שמותיהן תמיד אומרות אותו דבר, כך ש-`read-only`, `standard`, ו-`admin` בטוחים להפניה בתוך מדיניות והעלאה. מפעיל יכול ליצור **ערכות מותאמות** נוספות למודל תפקידים ספציפיים לארגון שלך (לדוגמה, תפקיד "dashboard author" או תפקיד "collector-only"). + +ערכות מוצעות בלוח המחוונים ומנוהלות דרך ה-API ב-`GET /permission-sets` (רשום, סגור על ידי `users:read`) ו-`POST /permission-sets` / `PUT /permission-sets/:name` / `DELETE /permission-sets/:name` (צור, ערוך, מחק ערכה מותאמת, סגור על ידי `settings:write`). מחיקה או עריכה של ערכה מובנית מוסרבת. + +חברות בערכה היא מה שתומך בשתי תכונות אחרות: + +- **`DEFAULT_USER_PERMISSIONS`** (ההענקה שנבחרה מראש בעת פתיחת admin + משתמש חדש) מתחברת לערכה `standard`. ראה [Deployment](/he/agenteye/deployment). +- **דגל `--set`** ב-`agenteye-orgctl` (ניהול חברים של מפעיל) מתחיל חברה מערכה בשם, שלאחר מכן אתה משופר עם `--add` / `--remove`. ראה [Tenant Management](/he/agenteye/tenant-management). + +> כאשר ערכה כוללת הרשאה שאינה key-assignable (לדוגמה, ערכה מותאמת הנושאת `keys:update`), זריעת מפתח מהערכה זו מטילה את האסימונים הלא-assignable; השרת אחרת רח מפתח עם HTTP 422. משתמשי לוח מחוונים אינם כפופים להגבלה זו. + +--- + +## מפתח Admin Bootstrap + +מפתח ה-admin הוא ה-credential שורש היחיד המאפשר למפעיל להעלות גישה מכלום: איתו אתה יכול ליצור כל מפתח scoped אחר, להזמין את משתמשי לוח המחוונים הראשונים, ולהגדיר את ההתקנה לפני שיש מפתח אחר כלשהו. זה המפתח היחיד שאתה לא יוצר דרך ה-keys API; הוא מסופק מהסביבה כך שהשרת ניתן להגעה בהפעלה הראשונה. + +קבע את משתנה הסביבה `ADMIN_KEY` בשרת. בכל הפעלה, השרת upserts ערך זה כמפתח admin עם כל ההרשאות. + +כדי לסובב: שנה `ADMIN_KEY` לסוד חדש והפעל מחדש את השרת. + +--- + +## ארגון scoping + +**ארגונים עצמם נוצרים ומנוהלים out-of-band על ידי מפעיל, לא דרך API מפתחות זה.** Org ו-member lifecycle (צור / שנה שם / מחק / טהר ארגון; הוסף / עדכן / הסר חברה) נעשה עם ה-**`agenteye-orgctl`** CLI שפועל בתוך pod השרת; אין HTTP API או כפתור לוח מחוונים עבורו. ראה [Tenant Management](/he/agenteye/tenant-management). מה *הוא* ללא שינוי: **מפתחות API per-org עדיין מטבעות בלוח המחוונים (או דרך API מפתחות זה)** על ידי חברי ארגון. + +בפריסה מרובת-ארגון, כל מפתח שחברי ארגון יוצרים (דרך API מפתחות זה או דף ה-**Keys** של לוח המחוונים) שייך ל-**ארגון אחד** ויכול רק אי פעם לקרוא או לכתוב נתוני ארגון זה; הארגון חתום על המפתח בעת יצירה ו-enforced בכל בקשה. שני ה-bootstrap keys הם החריג היחיד: מפתח ה-`admin` (זרוע מ-`ADMIN_KEY`) ומפתח ה-`dashboard-assistant` (זרוע מ-`AGENT_API_KEY`) הם **instance-scoped** (הם לא נושאים ארגון). קונטיינר לוח המחוונים מתחבר עם מפתח ה-`admin` כך שהוא יכול לתיווך בקשות per-org בשם חברים שנכנסו. פריסות חד-דיירנו לא צריכות לחשוב על זה; כל המפתחות שייכים לארגון `default` המובנה. + +--- + +## יצירת מפתחות + +השתמש במפתח admin (או כל מפתח עם הרשאה `keys:create`) כדי ליצור מפתחות scoped נוספים. + +### מפתח אספן (קבל בלבד) + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "prod-collector", + "key": "your-collector-secret", + "permissions": ["events:add"] + }' +``` + +### מפתח לוח מחוונים (קרא בלבד) + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "dashboard", + "key": "your-dashboard-secret", + "permissions": ["events:read", "keys:read"] + }' +``` + +כאשר אתה יוצר מפתח דרך HTTP API, אתה מספק את ערך ה-`key` בעצמך; בחר סוד חזק ואחזור אותו בבטחה. (לוח המחוונים עובד בדרך ההפוכה: זה יוצר סוד חזק בשבילך ומציג אותו פעם אחת בעת יצירה; ראה [Key Management in the Dashboard](#key-management-in-the-dashboard).) התגובה מאשרת שהמפתח נוצר: + +```json +{ + "id": "550e8400-e29b-41d4-a716-446655440000", + "name": "prod-collector", + "permissions": ["events:add"], + "created_at": "2026-04-01T12:00:00Z" +} +``` + +--- + +## רשימת מפתחות + +```bash +curl -s http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +סודות מפתחות אינם מוחזרים בתגובות רשימה, רק IDs, שמות והרשאות. + +--- + +## הפוך מפתח + +הפיכה משלול גישה מיד ללא מחיקת רשומת המפתח. + +```bash +curl -s -X POST http://your-server:8080/keys//disable \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +--- + +## סיבוב מפתח + +יצר סוד חדש למפתח קיים. הסוד הישן מבוטל מיד. + +```bash +curl -s -X POST http://your-server:8080/keys//regenerate \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +התגובה כוללת את ה-secret plaintext החדש, **הוצג רק פעם אחת**. + +--- + +## ניהול מפתח בלוח המחוונים + +דף ה-**Keys** בלוח המחוונים מספק UI עבור כל הפעולות לעיל. אתה צריך מפתח עם הרשאה `keys:read` כדי לראות את הרשימה, ו-`keys:create` / `keys:update` / `keys:disable` / `keys:regenerate` עבור פעולות create / edit / disable / regenerate בהתאמה. עריכה של הרשאות של מפתח (`keys:update`) היא נפרדת מיצירת אחד (`keys:create`), כך שתוכל להקצות למפעיל את היכולת ליצור מפתחות ללא יכולת לעשות rescope למפתחות קיימים, או להיפך. מפתח ה-admin מכסה את כל אלה. + +כאשר אתה יוצר מפתח מלוח המחוונים אתה לא מספק את ה-secret; לוח המחוונים יוצר סוד חזק בשבילך ומציג אותו **פעם אחת** בעת יצירה. העתק אותו מיד ואחזור אותו בבטחה; הוא לעולם לא מוצג שוב, בדיוק כמו עם regenerate. אתה עדיין יכול לבחור את הרשאות של המפתח ישירות, או לזרוע אותם מערכה הרשאות (ראה למטה). + +![דף API Keys: כרטיס לכל מפתח המציג את שמו, הרשאות מוקצות, וזמן יצירה, עם פעולות regenerate ו-disable; מפתחות מוגנים כמו `admin` מסומנים](/agenteye/images/api-keys.png) + +--- + +## פריסת מפתח מומלצת + +| מפתח | הרשאות | בשימוש על ידי | +|---|---|---| +| `admin` (bootstrap דרך `ADMIN_KEY` env var) | הכל | Ops/setup, וקונטיינר לוח המחוונים (מתחבר עם `ADMIN_KEY`, תיווך בקשות משתמש עם בדיקות הרשאות) | +| מפתח אספן לכל-host | `events:add` | אספן על כל מכונת agent | +| `dashboard-assistant` (bootstrap דרך `AGENT_API_KEY` env var) | `events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run` | קונטיינר עוזר AI, זרוע אוטומטית, **מוגן**; לא יכול להיות ערוך דרך ה-API | +| מפתח טלמטריה של עוזר (אופציונלי) | `events:add` | self-instrumentation של עוזר AI, אם מופעל | + +> **מפתח עוזר.** מפתח ה-עוזר **זרוע אוטומטית** על ידי השרת מ-`AGENT_API_KEY` env var (אותו סוד שהעוזר מציג כ-`AGENTEYE_API_KEY`); אין שלב key-minting ידני וללא מפתח admin. הרשאותיו קבועות בקוד מקור כך שלא ניתן להרחיב scope על ידי misconfiguration: קרא על פני events / evaluations / dashboards, בתוספת dashboards-write ו-queries-read / write / run עבור זרימת יצירת Ask AI to write a query. כל SQL עדיין הולך דרך אותו תפקיד read-only ובדיקות `sql_guard` כמו שאילתה שנכתבה על ידי משתמש, כך זה מרחיב את *משטח הקמתה*, לא את משטח הנתונים; פעולות כושלות (`queries:delete`, `dashboards:delete`) בשפט קבועות מפתח העוזר. כמו מפתח ה-`admin`, זה **מוגן**: לא יכול להיות מוסקה או regenerated דרך מפתחות API, רק סובב על ידי שינוי `AGENT_API_KEY` והפעלה מחדש. לוח המחוונים *משתמשים* בנוסף צריך הרשאה `agent:use` כדי לראות ולהשתמש בעוזר. אם אתה מפעיל self-instrumentation, תן לעוזר מפתח `events:add`-בלבד נפרד. \ No newline at end of file diff --git a/docs/he/agenteye/assistant.mdx b/docs/he/agenteye/assistant.mdx new file mode 100644 index 00000000..6e49fcf2 --- /dev/null +++ b/docs/he/agenteye/assistant.mdx @@ -0,0 +1,197 @@ +--- +--- +title: "עוזר AI" +description: "תיעוד עוזר AI של AgentEye." +--- + + +לוח המחוונים כולל עוזר **AI** אופציונלי, פנל צ'אט המעוגן לקצה הימני של לוח המחוונים המענה לשאלות בשפה טבעית לגבי הסוכנים שלך ("איך הטרנד של איכות ב-prod השבוע הזה?", "אילו סשנים כשלו היום?", "סכם את הסשן הזה") ו, כאשר המשתמש מתיר כל פעולה, משרטט וחוסך שאילתות SQL וממשקים על חשבונם. הוא מצטט קישורים הניתנים ללחיצה ישירות לסשנים, שאילתות וממשקים הרלוונטיים, והוא **מודע לעמוד**: שאל על "סשן זה" בזמן צפייה באחד והוא יודע על מה אתה מדבר. + +התא מציג **מסילה אנכית של 44px** בברירת מחדל: גליף הנמודה `›_` בתוספת נקודת בריאות בצבע. לחץ על המסילה (או לחץ על `⌘J` / `Ctrl+J`) כדי להרחיב אותה לפנל הצ'אט המלא. הפנל המורחב הוא **ניתן לשינוי גודל** בין 320 ל-640 פיקסלים על ידי גרירת הקצה השמאלי שלו; הרוחב המועדף שלך נזכר בתוך טעינות מחדש. + +הוא רץ כ**קונטיינר** פנימי קטן של `agent` (ב-Claude Agent SDK) שרק לוח המחוונים יכול להגיע אליו. הוא **משבית כברירת מחדל** ונשאר מוסתר עד שתשדר נקודת קצה של LLM. + +--- + +## מה הוא יכול ולא יכול לעשות + +- **קורא את הנתונים התפעוליים שהמשתמש השואל יכול לראות.** אירועים, הערכות, סשנים, תור עבודות הערכה, שאילתות שמורות וממשקים שמורים, מסובבים בכל בקשה להרשאות הקריאה של המשתמש. כלים קריאה מתבצעים באופן מיידי. +- **כתיבה מוערכת בהעדכון לכל פעולה.** הוא יכול לחבור שאילתות שמורות (`create_saved_query`, `update_saved_query`), להפעיל SQL טיוטה נגד התפקיד קרוא-בלבד כדי לאמת אותה (`run_query`), וליצור ממשקים מאותן שאילתות (`create_dashboard`, `update_dashboard`, `add_query_to_dashboard`). כל כתיבה עוצרת למייל **אשר / דחו / שאל שאלה** בצ'אט; ה-SDK לא קורא לכלי עד שהמפעיל לוחץ על אישור. **מחיקה לעולם אינה זמינה לעוזר**; פעולות הרסניות נשארות עם מפעילים. +- **SQL משוטט עובר דרך אותה `sql_guard` אימות ותפקידי קרוא-בלבד כמו SQL כתוב על ידי משתמש** (SELECT/WITH בלבד, אין רב-הצהרה). הביצוע מנוטב לפי איזה טבלאות שהשאילתה נוגעת בהן: שאילתות המציגות את טבלאות הניתוח (אירועים, הערכות, סשנים) רצות כמשתמש ClickHouse קרוא-בלבד של הארגון (מסובב לאורגון זה על ידי מדיניות שורה, עם כובע ביצוע של 10 שניות וכובע שורה של 100k) בעוד ששאילתות שנוגעות רק בטבלאות יחסיות רצות על תפקיד Postgres קרוא-בלבד (10 שניות, 10k שורות). העוזר לא יכול להרחיב את פני הנתונים; הוא יכול רק להיות מחבר על פני משטח השאילתות שלמפעיל כבר יש. +- הוא משתמש ב**מפתח עוזר ייעודי** (ראה למטה) זרוע עם סט הרשאות קבוע; גם אם המודל מתנהג בצורה לא תקינה, הוא לא יכול לחרוג מהתחומים האלה. +- כל משתמש לוח מחוונים צריך את הרשאת **`agent:use`** כדי לראות ולהשתמש בעוזר. כלים מסוננים לפי בקשה כדי להתאים את הרשאות הנתונים של המשתמש שלו, כך שמשתמש `events:read` מקבל כלי אירוע אך לא כלים `dashboards:write`. + +--- + +## תא AI מודע לעמוד: מקם על `/queries`, צ'אט בכל מקום אחר + +תא העוזר בצד ימין הוא **מודע לעמוד**. בחר המודל, היסטוריית השיחה, נקודת בריאות המודל וקלט הצ'אט נשארים ללא שינוי, אך **שבבי תבנית מצב ריק, טקסט ממלא מקום, ואיזו נקודת קצה של backend שאילת משתמש פוגעת** הכל משתנה באופן אוטומטי בהתאם לנתיב הנוכחי. התא הופך ל"עוזר AI עבור בכל עמוד שאתה עומד עליו". + +**שני backends, מובחנים לכל עמוד (עם עריכות לכל שבב).** + +| נתיב | backend ברירת מחדל של דף | למה | +| ------------------------------ | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | +| `/queries`, `/queries/new` | `POST /api/agent/compose-sql` (לא לולאת כלים) | המשתמש מתחיל מחדש; SQL של ≤1s token ראשון זורם ישר לעורך | +| `/queries/` (קיים) | `POST /api/agent/chat` (עוזר לולאת כלים מלא), ברירת מחדל של עמוד | הודעות מקלידות בחופשיות צריכות להתיר למשתמש לשאול הכל ("הסביר את זה", "מה זה עושה?"); שבבי רפקטור הן בחזרה להרכבה-sql דרך כל סוג של שבב | +| כל עמוד אחר | `POST /api/agent/chat` (עוזר לולאת כלים מלא) | קרא כלים + כלים כתיבה ברוכי אישור | + +שבבים על `/queries/` נושאים `kind` מפורש כך שעמוד יחיד יכול לערבב את שני הזרימות בצורה חלקה. קבוצת השבב ברירת המחדל היא שני שבבי **צ'אט** (`הסביר את השאילתה על המסך`, `מה עושה השאילתה הזו?`) בתוספת חמישה שבבי **compose-sql** (`parametrize לפי טווח תאריכים`, `הוסף סטטוס='שגיאה' פילטר`, וכו'). הודעות מקלידות בחופשיות נופלות דרך ברירת המחדל של העמוד (צ'אט), כך ששאלה כמו "למה זה כל כך איטי?" מקבלת תשובת פרוזה, בעוד שלחיצה על שבב `parametrize לפי טווח תאריכים` משוטט דרך נקודת הקצה של הרכבה וערכה את SQL. + +כאשר המקום פועל ב**מצב עריכה** (הוא רואה `currentSql` שאינו ריק מכיוון שהמשתמש נמצא ב-`/queries/` או `/queries/new` עם SQL המוצע שכבר טעון), הנושא שלו משתנה מ"הרכבה שאילתה חדשה" ל"שנה את SQL המסופק מינימלי: שמור בחירת טבלה, שמות עמודה, מבנה צירוף, כינויים, הזחה". המודל מוצג לקבוצה נפרדת של דוגמאות עובדות לפני/אחרי (parametrize, הוסף סינון, המר לדלי שעתי), כך שרפקטור שנלחץ על שבב מייצר דיפ מינימלי נגד SQL של העורך, לא כתיבה מחדש מאפס. + +לחץ על שבב הרכבה (או הקלד בחופשיות ב-`/queries/new`) → SQL זורם לתוך הודעת העוזר כ-` ```sql ` בלוק מובקע. **ברגע שהזרימה מסתיימת, אם Monaco מעוגן בנתיב הנוכחי, העורך באופן אוטומטי דולק בתצוגת דיפ** (המקור בצד שמאל, המוצע בצד ימין, ` ▾ AI הציע עריכה` רמז בחלק העליון, ופתילי **קבל / דחו** למטה). המשתמש לא צריך למצוא או ללחוץ על כפתור `Insert into editor` כדי לראות את ההפרש. לחצן ההוספה עדיין מעורך מתחת לבלוק SQL כ-re-trigger ידני (שימושי אחרי דחייה או כאשר המשתמש נסע משם וחזרה), והוא נשאר הנתיב היחיד כאשר המשתמש נמצא בעמוד שאינו עורך (לדוגמה, רשימת השאילתות השמורות); שם היא מטמינה את SQL ב-`sessionStorage` ופעילות ל-`/queries/new`, כאשר העורך החדש-מעוגן קורא את הטמון בתקנה וסוגר את אותה תצוגת דיפ. + +אם SQL המוצע זהה ביתות לגבי מה שכבר בעורך (עריכת no-op), ה-auto-open דולק; אנחנו לא פופ הפרש ריק. כפתור `Insert into editor` הוא גם no-op במקרה זה. + +כאשר המשתמש מקבל הצעה על `/queries/new`, הפעולה הראשונה של סרגל הכלים קורא **`save`** במקום `create`; SQL הופץ להם על ידי העוזר; המודל נפשי הוא "סיימו את זה", לא "כתוב מאפס". התווית מתהפכת ברגע שהתא מכניס SQL ונשארת כ-`save` עד ניווט העמוד. ב-`/queries/` כפתור הקרא תמיד `save`; שום דבר לא משתנה שם. + +מחוץ `/queries`, התא עובד בדיוק כמו קודם: צ'אט מלא עם כרטיסי אישור כלים, מודעות בהקשר עמוד, ציטוטים. + +**הרשאות / גביע.** נקודת הקצה של הרכבה גביע בהרשאת `queries:run` לכל משתמש (קריאה-שווה ערך; למשתמש עדיין צריך ללחוץ על אישור והפעל, והפעל עובר דרך `sql_guard` + `references_ch_tables` הנוכחי על שרת Rust). נקודת הקצה של צ'אט גביע ב-`agent:use`. שניהם עדיין דורשים חיבור LLM שהוגדר בקונטיינר `agent`; אם אף אחד לא הוגדר, התא משטח את "העוזר לא הוגדר בהצבה זו" בנר בכל נתיב. + +**סירובים.** המקום סיר כל בקשה שהוא לא יכול להשביע עם שאילתת ניתוח קרוא-בלבד וסופר `-- REFUSE: ` בתוך SQL. הוא סיר בקשות שיכתבו נתונים או להגיע לטבלאות מחוץ לתצפיות ניתוח (`api_keys`, `users`, `dashboards`, `saved_queries`, `evaluation_jobs`), והוא סיר בקשות פרוזה טהורות ("הסביר את זה", "מה זה עושה?") בנתיב הרכבה; אלה שייכות לנתיב הצ'אט והיצרו תשובת פרוזה שם. התא משטח את מחרוזת הסירוב כשבב שגיאה אדום מובקע בהודעת העוזר; שום דבר לא מוכנס. + +**בחירת מודל.** משותף עם נתיב הצ'אט. בוחר המודל בראש התא חל על שתי נקודות הקצה (קריאת הרכבה עוברת את המודל הנבחר דרך `resolveModel()` בשירות הסוכן). כאשר `AGENTEYE_AGENT_MODELS` רשימות מודלים מרובים, מפעילים יכולים לערבב אפשרות מחלקה Haiku עבור הרכבה עם אפשרות מחלקה Sonnet עבור צ'אט; המשתמש בוחר לכל שיחה. + +**תבניות לכל עמוד.** לכל עמוד יש את התבנית שלו (כותרת, גוף העתק, טקסט ממלא מקום, ושבבי הצעה) כך התא מסתגל לעמוד שאתה עומד עליו. השבבים שהוצעו בנתיב נתון ממפים לאותם כוונות שהרכבה מכוונת, כך שלחיצה על הצעה מייצרת את העריכה שאתה מצפה. + +**השבתתו.** זהה לנתיב הצ'אט: התא + הרכבה שניהם מוערכים על ידי קונטיינר `agent` והחיבור LLM שלו. אם אתה רוצה התנהגות צ'אט בלבד למשתמש מסוים, הסר את הרשאת `queries:run` (המשבית גם את כפתור ה-**Run** של העורך); אם אתה רוצה התנהגות מקום בלבד, הסר `agent:use` מתפקידי המשתמש, ואז הוסף מחדש `queries:run` בנפרד כך שהם עדיין יכולים להפעיל SQL כתוב מחבר. + +--- + +## הפעלתו + +שירות `agent` משונה בקובץ Docker Compose והמניפסטים של Kubernetes. כדי להפעיל את העוזר, ספק **(1)** נקודת קצה של LLM ו**(2)** מפתח הנתונים המיוחד של העוזר. + +### 1. בחר חיבור LLM + +בחר באחד מאלה והגדר את המשתנים התואמים בשירות `agent`: + +**א) Anthropic ישירות** + +``` +ANTHROPIC_API_KEY=sk-ant-... +``` + +**ב) דרך Portkey (מומלץ; קטלוג מודל slug, מפתח בלבד)** + +``` +PORTKEY_API_KEY= +AGENTEYE_AGENT_MODEL=@/claude-sonnet-4-6 +``` + +זה הנתיב הפשוט ביותר: ב-Portkey, הגדר **אינטגרציית Anthropic** (Catalog דגם); הוא מקבל **slug**. שם את המודל כ-`@/` והקליע מוביל את נתיב הספק + יומן, כך **לא צריך מפתח וירטואלי**, רק המפתח Portkey שלך. הסוכן שולח רק `x-portkey-api-key` ומצביע על שער Portkey; Portkey פותר את השאר. (שם מודל *פשוט* כשל עם "x-portkey-config או x-portkey-provider header is required"; הקדומה `@slug/` היא מה שעושה קרא בלבד עבודה.) עבור שער שמעוצב בעצמו הגדר `PORTKEY_BASE_URL`. + +מעדיפה ניתוב לכל בקשה במקום slug? הגדר `PORTKEY_VIRTUAL_KEY=` (או `PORTKEY_CONFIG=`) עם `AGENTEYE_AGENT_MODEL` פשוט. + +**ג) שער תואם Anthropic אחר (LiteLLM, ממשוכן בעצמו, …)** + +``` +ANTHROPIC_BASE_URL=https://your-gateway +# Newline-delimited "Name: Value" header lines (NOT JSON): +ANTHROPIC_CUSTOM_HEADERS=x-my-header: value +``` + +**ד) Amazon Bedrock / Google Vertex** + +``` +CLAUDE_CODE_USE_BEDROCK=1 # + standard AWS credentials in the environment +# or +CLAUDE_CODE_USE_VERTEX=1 # + standard GCP credentials in the environment +``` + +צפה להשמעה את המודל ברירת המחדל עם `AGENTEYE_AGENT_MODEL` (ברירת מחדל `claude-sonnet-4-6`). כדי להתיר למשתמשים **לבחור** בין מודלים מרובים, הגדר `AGENTEYE_AGENT_MODELS` לרשימת הרשאות מופרדת בפסיקים (לדוגמה, `@anthropic-prod/claude-opus-4-7,@anthropic-prod/claude-sonnet-4-6`); בחר מודל מופיע בראש צ'אט, ובחירה של כל משתמש נזכרת. הסוכן קורא לעולם מודל בעצם הרשאה זו. + +### 2. ספק את מפתח העוזר + +בחר בכל סוד אקראי והנח אותו לחברת **agent** כ-`AGENTEYE_API_KEY` ול-**server** כ-`AGENT_API_KEY` (אותו ערך). בהפעלה השרת זורע אותו כמפתח ייעודי בשם `dashboard-assistant` עם ערכת הרשאה קבועה זו: `events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run`. הרשאות הכתיבה מעולם מתורגלות רק דרך כלים ברוכי אישור (ראה "מה הוא יכול ולא יכול לעשות" למעלה). אין **שום שלב כישוף מפתח ידני ואין מפתח יועץ מעורב**. ערכת ההרשאה קבועה בשרת, והמפתח הזרוע הוא **מוגן**: אי אפשר להשבית או להחליף דור דרך מפתחות API; סובב אותו על ידי שינוי הערך והפעלת מחדש של השרת. אל **תעשה** שימוש חוזר במפתח מנהל / לוח מחוונים. + +```bash +SECRET="$(openssl rand -base64 32)" +# on the agent service: +AGENTEYE_API_KEY="$SECRET" +# on the server service: +AGENT_API_KEY="$SECRET" +``` + +על Kubernetes זה חווט בשבילך: שים `AGENTEYE_API_KEY` בסוד `agenteye-agent` והשרת Deployment כבר קורא את אותו ערך כ-`AGENT_API_KEY`. + +### 3. הגדר את הטוקן המשותף של dashboard↔agent + +הגדר את אותו `AGENTEYE_AGENT_TOKEN` על **שתי** שירותי `dashboard` ו-`agent`. לוח המחוונים משתנה אותו כאשר קורא לשירות הסוכן הפנימי; הסוכן דוחה קריאות ללא זה. + +### 4. הנח גישה למשתמשים + +תן למפעילי לוח המחוונים הרלוונטיים את הרשאת `agent:use` (ראה [enterprise-docs/api-keys.md](/he/agenteye/api-keys)). משתמשים ללא זה לעולם לא רואים את העוזר. + +ברגע שנקודת קצה של LLM ומפתח קרוא-בלבד מוגדרים, הפעלת מחדש את **server** (כדי לזרוע את מפתח קרוא-בלבד) ושירות **agent**. תא העוזר מופיע בקצה הימני לכל משתמש `agent:use`, מכובה כברירת מחדל; לחץ על המסילה או לחץ על `⌘J` / `Ctrl+J` כדי להרחיב. + +--- + +## הפניה למשתנה סביבה + +הגדר בשירות **`agent`**: + +| משתנה | מטרה | +|---|---| +| `PORTKEY_API_KEY` | ניתוב דרך Portkey (הסוכן בונה את חיבור השער מזה) | +| `PORTKEY_VIRTUAL_KEY` | מפתח וירטואלי Portkey עבור יומן Anthropic שלך (אופציונלי אם למפתח קונפ ברירת מחדל) | +| `PORTKEY_CONFIG` / `PORTKEY_BASE_URL` | תצורת Portkey שם / URL שער Portkey ממשוכן בעצמו (אופציונלי) | +| `PORTKEY_PROVIDER` | Portkey ספק קלף — אפשרות ניתוב שלישית לצד `PORTKEY_VIRTUAL_KEY` / `PORTKEY_CONFIG` (בשימוש רק כאשר אף אחד מאלה לא הוגדר) | +| `ANTHROPIC_API_KEY` | גישה ישירה Anthropic (חלופה לשער / Bedrock / Vertex) | +| `ANTHROPIC_AUTH_TOKEN` | Bearer token עבור שער שמעמיד את זה דרך `Authorization: Bearer` במקום `x-api-key` (אופציונלי) | +| `ANTHROPIC_BASE_URL` | נקודת קצה עבור שער שאינו Portkey | +| `ANTHROPIC_CUSTOM_HEADERS` | כותרות נוספות עבור שער שאינו Portkey: `Name: Value` שורות מופרדות בשורה חדשה (לא JSON) | +| `CLAUDE_CODE_USE_BEDROCK` / `CLAUDE_CODE_USE_VERTEX` | ניתוב דרך Bedrock / Vertex | +| `AGENTEYE_AGENT_MODEL` | מזהה דגם ברירת מחדל (ברירת מחדל `claude-sonnet-4-6`) | +| `AGENTEYE_AGENT_MODELS` | רשימת הרשאות מופרדת בפסיקים של מודלים שהמשתמש יכול לבחור בראש צ'אט. השאר לא מוגדר עבור דגם יחיד קבוע. ברירת המחדל למעלה חייבת להיות אחד מאלה (אחרת היא מתווספת). | +| `AGENTEYE_AGENT_MAX_CONCURRENCY` | שיחות מקבילות מרביות לכל תרכובת (ברירת מחדל 4); בקשות עודפות מקבלות 429 | +| `AGENTEYE_API_KEY` | מפתח נתונים של העוזר. הגדר את **אותו** ערך כ-`AGENT_API_KEY` של השרת, שזורע אותו עם ערכת הרשאה מסובבת קבועה בהפעלה (ראה שלב 2). | +| `AGENTEYE_AGENT_TOKEN` | סוד משותף עם לוח המחוונים | +| `AGENTEYE_SERVER_URL` | URL שרת AgentEye (ברירת מחדל `http://server:8080`) | +| `AGENTEYE_AGENT_ALLOW_NO_ORG` | **ריבוי דיירים.** כבוי כברירת מחדל (סגור כושל): העוזר דוחה בקשת `/chat` שאינה נושאת הקשר ארגון עם `400`, מכיוון שכל כלי שהוא מפעיל מוסדר לארגון אחד. לוח המחוונים תמיד שולח הקשר זה ברגע שהוא מודע לארגון, ולכן אתה בדרך כלל משאיר זה לא מוגדר. הגדר ל-`1` **רק** במהלך צבא מעבר שבו לוח מחוונים שלא-עדיין-מודע-לארגון מדבר לסוכן מודע לארגון, כך העוזר חוזר לארגון `default` במקום להסרב. נקה אותו ברגע שהשדרוג של לוח המחוונים נוחת. | +| `AGENTEYE_AGENT_MAX_STEPS` | שלבי כלים מרביים לכל תשובה (ברירת מחדל 8) | +| `AGENTEYE_AGENT_TIMEOUT_MS` | פג תוקף בקשת `/chat` הכללי (כל סיבובי דגם + שלבי כלים), במילישניות (ברירת מחדל 90000); לכלי SQL יש תאריך משלו של 10 שניות | +| `AGENTEYE_AGENT_SELF_TELEMETRY` | `1` כדי להקליט את ריצות העוזר שלו ל-AgentEye | +| `AGENTEYE_TELEMETRY_API_KEY` | מפתח `events:add` ייעודי בלבד עבור כלי עצמי | +| `AGENTEYE_AGENT_ENV` | תג סביבה הוחל על טלמטריה עצמית של העוזר (ברירת מחדל `prod`) | + +הגדר על שירות **`dashboard`**: + +| משתנה | מטרה | +|---|---| +| `AGENTEYE_AGENT_URL` | היכן לוח המחוונים מגיע לשירות הסוכן. המניפסטים המצוברים של Kubernetes וקובץ Compose הגדירו זאת ל-`http://agent:9100`. השאר לא מוגדר כדי להסתיר את העוזר לחלוטין. | +| `AGENTEYE_AGENT_TOKEN` | חייב להתאים לטוקן של הסוכן | + +--- + +## טלמטריה וראיית מה משתמשים שואלים + +תוכן הנושא **נשאר בתוך המערכות שלך בלבד** כברירת מחדל. שלוש שכבות: + +1. **חנות שיחה**: כל נושא ותשובה שמורה בבסיס הנתונים AgentEye שלך (לכל משתמש, פרטי), וניתנת לטעינה מחדש מממיר ההיסטוריה של העוזר. זה התיעוד העמיד של מה שמשתמשים שואלים. +2. **אנליטיקה של מוצר**: לוח המחוונים מתעד **נתונים בלבד** (כמה משתמשים במשתמש העוזר, ספר כלים, זמן השהייה) לאנליטיקה שלך. נושא **טקסט** לעולם אינו כלול בנתיב זה. +3. **כלי עצמי (אופציונלי)**: הגדר `AGENTEYE_AGENT_SELF_TELEMETRY=1` (בתוספת `events:add`-בלבד `AGENTEYE_TELEMETRY_API_KEY`) והעוזר מתעד ריצות משלו ל-AgentEye כסוכן `dashboard-assistant`. אתה אז צופה בנושאים של משתמשים והנמקת העוזר בדיוק באותה תצפיות/אירועים שאתה משתמש בהם לכל השאר. הערה: אירועים אלה נראים לכל מי שיש `events:read`; אם זה רחב מדי, השאר זה כבוי. + +--- + +## השבתתו + +כל אחד מאלה משבית את העוזר (התא מסילה נעלם): + +- בטל הגדרה `AGENTEYE_AGENT_URL` בלוח המחוונים, **או** +- השאר את נקודת הקצה של LLM לא מוגדרת על הסוכן (לא `ANTHROPIC_API_KEY` / gateway / Bedrock / Vertex), **או** +- אל תפרוס את שירות `agent` בכלל. + +--- + +## סיכום אבטחה + +- **ללא כתיבה שקטה**: כלי הכתיבה של העוזר (`create_saved_query`, `update_saved_query`, `create_dashboard`, `update_dashboard`, `add_query_to_dashboard`) לא יכולים להתבצע ללא לחיצת מפעיל מפורשת על כפתור אישור בצ'אט; שער הקדם-קריאה של ה-SDK חוסם את הכלי עד שהאישור מגיע לסוכן דרך תעלה משנית. אין הגדרה המשבית שער זה. +- **טווח נתונים קבוע וצר**: העוזר משנה את עצמו לשרת עם מפתח ייעודי שערכת ההרשאה שלו קבועה בשרת (`events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run`). הכתיבות היחידות שהוא יכול לחבור הן שאילתות שמורות וממשקים; השרת דוחה קום שהוא מחוץ להיקף זה ללא קשר לכל מה שהמודל מנסה. +- **פני מחיקה**: המפתח אינו נושא הרשאה מחיקה ולא כלי מחיקה חשוף. מפעילים מוחקים דרך הממשק של לוח המחוונים, לעולם לא העוזר. +- **פנימית בלבד**: לסוכן אין נתיב ציבורי; רק לוח המחוונים יכול להתקשר אליו, ורק עם הטוקן המשותף. (ב-Kubernetes, מדיניות רשת מגביל את הסוכן להשגת רק שרת AgentEye ונקודת קצה של LLM.) +- **סקופ לכל משתמש**: רק משתמשי `agent:use` מקבלים את העוזר, והם ניתנים רק הכלים התואמים לכל הרשאות הקריאה של המשתמש. +- **ללא HTML גולמי / ללא פליטת קישור**: תשובות משתנות כמו markdown מעוקם; קישורים חיצוניים מובוססו. + +ראה [enterprise-docs/troubleshooting.md](/he/agenteye/troubleshooting) לבעיות נפוצות. \ No newline at end of file diff --git a/docs/he/agenteye/audits.mdx b/docs/he/agenteye/audits.mdx new file mode 100644 index 00000000..1c2c39b2 --- /dev/null +++ b/docs/he/agenteye/audits.mdx @@ -0,0 +1,107 @@ +--- +title: "Audits — זיהוי שיפורים עבור סוכנים" +description: "תיעוד AgentEye Audits — זיהוי שיפורים עבור סוכנים." +--- + + +Audits הם משימות חוזרות שחופרות בתוך יומני הסוכן שלך **על פני מושבים** כדי למצוא דברים שכדאי לשפר. כאשר alert עוקב אחרי מטרית יחידה שאתה כבר מכיר בזמן קרוב למציאות, audit *חוקר*: לפי לוח זמנים שאתה קובע, הוא מריץ מעבר מדיניות דטרמיניסטי על החלון, ואז מפרק **סוכן AI לאמינות** על המושבים שלך — הסוכן שואל את הנתונים בעצמו, קורא תמלילים חשודים, וכאשר זה עוזר, מריץ סקריפטים ניתוח קטנים, ואז כותב **המלצות שיפור** עם הראיות מאחורי כל אחת. + +השתמש ב-audits כדי לענות על "מה אני צריך לתקן או לשפר בסוכנים שלי?" — ו-alerts כדי להיות מעורר ברגע שסף ספציפי חוצה. כל שיפור מקשור לסשנים וחקירות בדיוק, וקליק אחד יוצר alert מלא מראש כדי לתפוס חזרות. + +משטח הדאשבורד הוא **`//audits`** (סרגל צד → *analyze* → *audits*), מגונן על ידי ההרשאות `audits:read` / `audits:write`. + +--- + +## איך ריצה עובדת + +לכל ריצה יש שתי שכבות — בסיס דטרמיניסטי וחקירה מסוכנת. + +### 1. מעבר המדיניות (דטרמיניסטי) + +לפני שמודל כלשהו רץ, audit מריץ קטלוג קטן של **בדיקות מדיניות SQL** על החלון: שאילתות צבור מוגבלות המדגלות דפוסים רעים ידועים ודיווח *כמה* אירועים / *אילו* סשנים תאמו — לעולם לא הטקסט המתאים עצמו. הקטלוג כולל: + +- **דליפת סודות / אישורים** בעומסי אירועים — AWS access keys, `sk-…` API keys, PEM private keys, JWT / bearer tokens, וְ `KEY=…` הקצאות אישורים. +- **סימני הזרקת prompt** — "ignore previous instructions", "reveal your system prompt", וכדומה. +- **PII** — מספרים בצורת SSN (היוריסטי). +- **שלילות הרשאות כלי** ו**לולאות קריאות כלי חוזרות**. + +מכות מדיניות מתמשכות כממצאים (סוג `policy`) ש**תמיד משטחות** (הן לעולם לא קוצצות על ידי הקאפ לכל ריצה), והן מועברות לסוכן ה-AI כעלויות התחלה. מכיוון ששכבה זו לא צריכה מודל, audit עדיין מייצר את האותות הביטחוני החשובים ביותר שלו גם אם סוכן ה-AI אינו זמין. + +### 2. החקירה המסוכנת (AI) + +לאחר מכן audit מריץ **סוכן אמינות עצמאי** (אותו שירות Agents SDK שמעניק כוח לעוזר הדאשבורד, עם prompt ספציפי לביקורת). בהינתן **ההיקף** של audit (סוכנים שנבחרו × סביבות) ו**החלון הזמני**, הסוכן: + +- מריץ שאילתות SQL קריאה בלבד נגד טבלאות הנתונים שלך, +- קורא קומץ תמלילי סשנים מייצגים, +- כתיבה אופציונלית והרצה של סקריפטים **Python קצרים בחומת חול נעולה בתוך ה-pod** (אין רשת, אין גישה למערכת קבצים, סודות נקוביים) לניתוח ש-SQL לא יכול להביע — clustering שגיאות, חישוב התפלגויות, סריקת עומסים שהוא כבר הביא, +- והוא רושם כל **שיפור** שתוק בראיות שמצא. + +זה עובד דרך כמה קווי חקירה — clustering שגיאות, סחף לעומת בסיס, כישלון מטרה בתמלילים, שימוש לא נכון בכלים, פשרות איכות/עלות, וחסמי כיסוי — ב**רגישות** של audit (נמוך / בינוני / גבוה). כל שיפור **חייב להצטטות ראיות**: ה-session ids שהסוכן בעצם ביקר בהם ו/או ה-SQL שהוא הריץ. השרת מאמת שסשנים מצוטטים קיימים ו**מסיר כל שיפור ללא ראיות שורדות**, אז הסוכן חוקר אך לעולם לא משדך. + +כל שיפור נושא: + +- **המלצה** (השינוי הקונקרטי לביצוע — התאמת prompt, תיקון schema כלי, מדיניות ניסיון, guardrail, כיסוי eval נוסף), +- **השפעה צפויה** וְ**הערכת מאמץ** (נמוך / בינוני / גבוה), +- **גודל** — `big` (מפעיל צריך להיות מעורר), `medium` (שייך לדוח הריצה), או `small` (הקשר דאשבורד), +- **טביעת יד** יציבה (מקטגוריית הבעיה + היקף, *לא* סשנים של ריצה זו) כך שאותה בעיה מעוקבת מריצה לריצה גם כאשר הראיות משתנות, +- וכאשר משקיף דטרמיניסטי פשוט יכול לתפוס חזרה, **alert מוצע** שאתה יכול ליצור בקליק אחד. + +> **שכבת ה-AI היא אופציונלית אך מומלצת.** אם לא קונפיגורירו סוכן AI לצינור ביקורת, ריצות עדיין מתבצעות, תמשך את ממצאי המדיניות, וידווחו בכנות "analysis unavailable" לשכבה המסוכנת במקום להעביר בדיממוקה. + +### מצבי כישלון + +שיפורים מסווגים לתוך **קטלוג מצבי כישלון** עמיד של הארגון שלך (או מציעים מצב חדש). מצבים נותנים לדפוסים זהות יציבה על פני ריצות ועקיבות אופק ארוך. + +## מחזור חיי סיווג + +בעמוד ממצא (`/audits//findings/`): + +| פעולה | השפעה | +|---|---| +| **acknowledge** | שומר את הממצא גלוי אך חוצה את העדיפות שלו. | +| **resolve** | סימון כתוקן. אם הדפוס באמת חוזר מאוחר יותר, הוא חוזר לפתיחה כ-**new** — אז רגרסיה גם היא חזקה, לא מקופלת בשקט לתוך ההיסטוריה. | +| **mute** / **dismiss** | דיכוי עמיד: טביעת היד של הדפוס זוכרת ולא משטחת לעולם שוב, גם על פני ריצות. השתמש ב-mute ל"ידוע, מקובל"; dismiss ל"לא שימושי". | +| **reopen** | מחוקות דיכוי / רזולוציה ודרגות את הדפוס שוב. | +| **assign** | מנתב את הממצא למפעיל (חבר ארגון) לבעלות. מצב העדיפות והדיכוי לא משתנים. | + +הרעש של אות נמוך נשלט לכל ביקורת עם כובע ממצאים לכל ריצה (top_k`) על השיפורים המסוכנים. ממצאי מדיניות עוקפים את הכובע (הם רלוונטיים לביטחון ותמיד מוצגים). כל דבר שנחתך על ידי הכובע מתואר בסטטיסטיקות הריצה — שום דבר לא מוטל בשקט. + +## תזמון + +- **Cadence** (`schedule_interval_secs`): שעתי עד שבועי; **יומי הוא ברירת המחדל**. Audits הם בכוונה גסים יותר מ-alerts — חקירה מסוכנת סורקת חלונות שלמים וחוזרת לדקות. +- **Window**: או lookback מתגלגל קבוע (למשל "כל ריצה סורקת את 7 הימים האחרונים") או **since-last-run** (ברירת המחדל) — כל ריצה מתעדכנת מהמקום שהריצה הקודמת שהצליחה הסתיימה, עם חפיפה קטנה אז אירועי גבול לעולם לא מתחמקים. +- הריצה הבאה משוללת מרווח מלא לאחר הקודמת **משלימה**, אז ריצה איטית לעולם לא ערימות ריצה שנייה קונקוריתית של אותה ביקורת. +- **Run now** בעמוד ביקורת הופך אותה למעונייינת מיד. + +## בחירת מודל + +בעת יצירת ביקורת אתה יכול לבחור איזה מודל החקירה משתמשת, מ**רשימת המודלים שהמפעיל שלך קונפיגורירו** לשירות סוכנים. עם מודל יחיד מוגדר, הסלקטור מציג אותו ככיתוביות; עם מספרים, אתה בוחר. השאירו אותו לא מוגדר משתמש בברירת המחדל המוגדרת. + +## התראות + +כאשר ריצה משטחת **חדש** ממצאים, ביקורת מודיעה לערוצים שנקבעו של הארגון שלך — אותה `alerts.enabled_channels` שער והגדרות צינור alerts משתמש: + +- **Slack** — סיכום הפריטים החדשים המשמעותיים (`big`) עם קישור עמוק. +- **Email** — **דוח ביקורת** מעוצב המציגה את השיפורים החדשים (חומרה עליונה, המלצות לכל פריט, קישור עמוק), שנשלח כאשר ביקורת יש ערוץ **email** מצורף ויש לפחות ממצא חדש אחד. + +ממצאים חוזרים אך ידועים אינם מודיעים שוב. + +## הפניית תצורה + +הגדרות Audit מנוהלות בדאשבורד (`/audits/new`) או דרך ה-API. הגדרות לכל ביקורת כוללות את קדנס לוח הזמנים והחלון, ההיקף (`{"environments": [...], "agent_ids": [...]}`), הרגישות (`low` / `medium` / `high`), ערוצי ההתראות, כובע הממצאים לכל ריצה (`top_k`), והמודל (דרך `llm_budget.model`). הגדרות שרת ברמת מפעיל (timeouts, sandbox, כתובת ה-agent-service) תועדות ב-[deployment.md](/he/agenteye/deployment). + +## API + +כל נקודות הקצה הן ממלקוח וצעד בעקבות auth מפתח נושא סטנדרטי (ראה [api-keys.md](/he/agenteye/api-keys)). + +| נקודה קצה | הרשאה | תכלית | +|---|---|---| +| `GET /audits` · `POST /audits` | `audits:read` / `audits:write` | רשום / צור הגדרות ביקורת. | +| `GET` / `PUT` / `DELETE /audits/:id` | קרא / כתוב / כתוב | בדוק, ערוך, מחק ביקורת. | +| `POST /audits/:id/run` | `audits:write` | הפוך את ביקורת מעונייינת מיד. | +| `GET /audits/:id/runs` | `audits:read` | היסטוריית ריצה (חלון, סטטוס, סטטיסטיקה, ספירת ממצאים). | +| `GET /audits/findings` | `audits:read` | ממצאים בכל הארגון, סינון עם `audit_id`, `status`; ממוין לפי עדיפות. | +| `GET /audits/findings/:fid` | `audits:read` | פרט מלא ממצא (המלצה, ראיות, עדיפות). | +| `POST /audits/findings/:fid/status` | `audits:write` | סיווג: `{"action": "ack" \| "mute" \| "dismiss" \| "resolve" \| "reopen" \| "assign"}`. | + +ל"ביקורת הריצה אבל לא מצא כלום", "חומת החול של קוד מנוטרלת", ו"דוא"ל ביקורת לא סופק", ראה [troubleshooting.md](/he/agenteye/troubleshooting#audits). \ No newline at end of file diff --git a/docs/he/agenteye/cli-recipes.mdx b/docs/he/agenteye/cli-recipes.mdx new file mode 100644 index 00000000..7e376421 --- /dev/null +++ b/docs/he/agenteye/cli-recipes.mdx @@ -0,0 +1,169 @@ +--- +title: "מתכונים CLI לסוכנים" +description: "תיעוד מתכונים CLI של AgentEye לסוכנים." +--- + +משוך נתוני session, event והערכה (והפעל הערכות מחדש) ישירות מסקריפט או סוכן קידוד, עם JSON נקי ב-stdout שמצנח ישירות ל-`jq`. המתכונים הללו הופכים את נתוני ה-observability של AgentEye למשהו שמשתמש טרמינל או סוכן קידוד AI (Claude Code, Cursor) יכול לשאול עליו ולהשתמש בו באופן אוטומטי, ללא לחיצה דרך ה-dashboard. + +התבניות להלן מוכנות לשכפול עבור AgentEye CLI (`agenteye`). להתקנה, אימות וקائמת האפשרויות המלאה ראה [CLI](/he/agenteye/cli); הרץ `agenteye -h` או `agenteye -h` לקבלת העזרה המובנית. + +## הכללים הזהובים + +1. **אפשרויות גלובליות נמצאות *לפני* הפקודה.** `agenteye --json sessions` נכון; `agenteye sessions --json` לא. ה-globals הם `--json`, `--base-url`, `--org`, `--token`, `--insecure`/`--secure`, `--timeout`, `--quiet`, `--no-color`. +2. **עבור `--json` בכל פעם שאתה מנתח פלט.** הנתונים עוברים ל-**stdout** כ-JSON; סטטוס אנושי ושגיאות עוברים ל-**stderr**, כך stdout נשאר נקי להצנחה ל-`jq`. +3. **התניה בקוד היציאה**, לא בטקסט stderr: `0` בסדר · `2` ארגומנטים רעים · `3` לא ניתן להגיע ל-dashboard · `4` לא מחובר או פג תוקף · `5` הרשאה חסרה. +4. **גלה עם `-h`.** כל פקודה מתעדת את הפילטרים שלה, פורמטי ערך וצורת JSON. + +## הגדרה חד-פעמית + +```bash +export AGENTEYE_DASHBOARD_URL=https://agenteye.example.com # כדי שלא תחזור על --base-url +agenteye login --email you@example.com # הדבק את הקוד שהתקבל בדואר; תקף ~24h +``` + +## אשר אימות לפני ביצוע עבודה + +`whoami` לעולם לא שוגה בחסר או session שפג תוקף; זה דיווח `logged_in:false` במקום זאת, כך שסוכן יכול לבדוק את מצב האימות בבטחה. (זה עדיין יכול לצאת עם קוד שאינו אפס אם לא מוגדרת כתובת URL של base או ה-dashboard אינו זמין.) + +```bash +if [ "$(agenteye --json whoami | jq -r .logged_in)" != "true" ]; then + echo "Not authenticated. Run: agenteye login" >&2; exit 1 +fi +``` + +## מצא sessions שנכשלו או בעלי ניקוד נמוך + +```bash +# sessions ב-24 השעות האחרונות שההערכה שלהם שגתה +agenteye --json sessions --since 24h --status error | jq -r '.sessions[].session_id' + +# הערכות בעלות ניקוד <= 0.5 ב-helpfulness, לסוכן אחד +agenteye --json evals --agent-id checkout-bot --score helpfulness:..0.5 \ + | jq '.evaluations[] | {session_id, scores}' +``` + +סינון ניקוד חי ב-**`evals`**, לא `sessions`. `--score KEY:MIN..MAX` חוזר ו-AND-משולב; כל גבול הוא אופציונלי (`..0.5` אומר ≤ 0.5, `0.9..` אומר ≥ 0.9). אתה יכול להעביר עד 20 מסננים ניקוד לבקשה; יותר מחזיר HTTP 400. `sessions` משתף את `--env`, `--status`, `--agent-id`, `--session-id`, ומסננים טווח זמן עם `evals`, אבל אין לו `--score`. + +## קרא session מקצה לקצה + +אין פקודת `session show` יחידה — שלב את שביל האירועים עם ההערכה של ה-session: + +```bash +# ההערכה האחרונה של ה-session (סטטוס + ניקוד) +agenteye --json evals --session-id run-001 | jq '.evaluations[0] | {status, scores}' + +# כל אירוע בריצה (הרם --limit לסוויפ מלא) +agenteye --json events --session-id run-001 --all --limit 1000 | jq '.events[] | {ts, event_type}' + +# רק קריאות הכלים ב-session +agenteye --json events --session-id run-001 --event-type tool_use,tool_result --all \ + | jq '.events[].payload' +``` + +## אחזר הכל (pagination) + +התוצאות הן newest-first ו-cursor-paginated. + +```bash +# בשיגור אחד: אחזר עד 500 שורות בעמודים של 200 שורות +agenteye --json events --session-id run-001 --limit 500 --all > events.json + +# pagination ידני: הזן את next_cursor חזרה +page=$(agenteye --json events --limit 100) +cursor=$(echo "$page" | jq -r '.next_cursor // empty') +[ -n "$cursor" ] && agenteye --json events --limit 100 --cursor "$cursor" +``` + +## הרזן את הפלט עם --fields + +הגבל את המפתחות (גם בטבלה וגם ב-`--json`) כדי להפחית מה סוכן צריך לקרוא. + +```bash +agenteye --json sessions --since 7d --fields session_id,status,scores | jq -c '.sessions[]' +agenteye --json events --session-id run-001 --fields ts,event_type --all +``` + +שמות שדות לא ידועים נדחים (exit `2`) עם הרשימה התקפה, דרך זולה לגילוי שמות שדות. + +## גלה ערכי פילטר תקפים + +```bash +agenteye --json list envs | jq -r '.values[]' # ערכים עבור --env +agenteye --json list tools | jq -r '.values[]' # שמות כלים; גם agents, models, event_types, … +agenteye --json list score_filters | jq -r '.values[]' # KEY תקף עבור --score KEY:MIN..MAX +``` + +## בחר את ה-org שלך (multi-tenant) + +אם אתה שייך ליותר מ-org אחד, בחר את ה-tenant הפעיל בעת הכניסה (זה נשמר): + +```bash +agenteye login --org acme --email you@corp.com # הגדר את ה-tenant באותו השלב כמו הכניסה +agenteye --json orgs list | jq -r '.orgs[].org_slug' +agenteye --org globex --json sessions --since 24h # דרוס לפקודה אחת +``` + +כניסה multi-org ללא `--org` יוצאת עם קוד שאינו אפס והדפסת ה-orgs לבחירה. + +## סיפק מפתח API עבור SDK/collector + +```bash +# הסוד מודפס פעם אחת בלבד — עם --json זה שדה .key +key=$(agenteye --json keys create ci-bot --add events:read.add | jq -r '.key') +agenteye keys regenerate ci-bot --yes # סובב; agenteye keys disable ci-bot --yes לשלילת הרשאות +``` + +## הרץ שאילתה שמורה או ad-hoc + +```bash +agenteye --json query run --sql "select count(*) from analytics.events" | jq '.rows' +agenteye --json query run errs --arg prod | jq '.rows' # שאילתה שמורה + $1 positional +``` + +## טריאג' אירוע בעדכון ללא אינטראקטיבי + +```bash +id=$(agenteye --json incidents list --state firing | jq -r '.incidents[0].id') +agenteye incidents ack "$id" +agenteye incidents assign "$id" you@corp.com +agenteye incidents resolve "$id" --yes +``` + +> מוטציות דילוג אוטומטי בהנחתן תשובה תחת `--json` או כאשר stdin אינו TTY, כך שסוכנים לעולם לא תלויים; עבור `--yes`/`-y` לדלוג עליו בקפדנות במקום אחר. + +## טיפול בקוד יציאה בסקריפט + +```bash +out=$(agenteye --json sessions --since 1h) || code=$? +case "${code:-0}" in + 0) echo "$out" | jq '.sessions | length' ;; + 4) echo "Session expired - run 'agenteye login'." >&2 ;; + 5) echo "Missing permission (ask an admin for evaluations:read)." >&2 ;; + 3) echo "Dashboard unreachable - check the URL." >&2 ;; + *) echo "Unexpected error (exit ${code})." >&2 ;; +esac +``` + +## צורות פלט JSON + +| פקודה | stdout JSON (עם `--json`) | +|---|---| +| `whoami` | `{"logged_in": true, "id", "email", "is_instance_admin", "active_org", "permissions": [...], "memberships": [...]}` או `{"logged_in": false}` | +| `orgs list` | `{"active_org", "orgs": [{"org_slug","org_name","permission_set","permissions"}]}` | +| `events` | `{"events": [...], "next_cursor": }` | +| `evals` | `{"evaluations": [...], "next_cursor": }` | +| `sessions` | `{"sessions": [...], "next_cursor": }` | +| `errors` | `{"errors": [...], "next_cursor": }` | +| `list ` | `{"kind", "values": [...]}` | +| `keys list` / `keys create` | `{"keys": [...]}` / `{id, name, permissions, created_at, key}` (`key` הוצג פעם אחת) | +| `query run` | `{columns: [{name,type}], rows: [[...]], truncated, elapsed_ms}` | +| `users list` / `settings list` | `{"users": [...]}` / `{"settings": [...]}` | +| `alerts list` / `incidents list` | `{"alerts": [...]}` / `{"incidents": [...]}` | +| create/update/delete (כל) | אובייקט המשאב, או `{"deleted": true, "id"}` למחיקות | +| כישלון (כל, עם `--json`) | `{"error": "...", "exit_code": , "status"?: , "hint"?: "..."}` ב-stdout | + +- כל פריט **event** (`events`): `id, session_id, agent_id, event_type, ts, payload, environment`. +- כל פריט **evaluation** (`evals`): `id, session_id, agent_id, environment, status, scores, reasoning, summary, error, attempt_count, duration_ms, completed_at, created_at`. +- כל פריט **session** (`sessions`): `session_id, agent_id, environment, status, scores, event_count, started_at, last_event_at, first_event_id, last_event_id, latest_evaluation`. + +`--fields` של כל פקודה קובל בדיוק שמות שדות של הפריט שלה — הסט שונה בין `sessions` ו-`evals`, כך ששם חוקי לאחד עלול להיות דחוי על ידי השני. \ No newline at end of file diff --git a/docs/he/agenteye/cli-skill.mdx b/docs/he/agenteye/cli-skill.mdx new file mode 100644 index 00000000..18a6e03c --- /dev/null +++ b/docs/he/agenteye/cli-skill.mdx @@ -0,0 +1,95 @@ +--- +title: "AgentEye CLI Agent Skill" +description: "AgentEye AgentEye CLI Agent Skill documentation." +--- + + +**AgentEye CLI skill** (`agenteye-cli`) היא *Agent Skill* ניתנת להתקנה המלמדת סוכן קוד — Claude Code, Codex וכלים תואמים — להפעיל את הפריסה שלך של AgentEye דרך [`agenteye` CLI](/he/agenteye/cli) מבקשות ברגלית אנגלית: *"האם משהו שבור היום?"*, *"תן ל-CI מפתח שיכול רק לדחוף אירועים"*, *"אשר את האירוע הפורצ שורה וקצה לי"*. + +זה **לא** שירות או בינארי נפרד. זה חבילת הוראות קטנה שרוכבת על ה-CLI שכבר התקנת: הסוכן משדר אל `agenteye --json …`, מחליץ את ה-JSON הנקי, ועונה לך בטקסט. כל מה שהוא יכול לעשות, אתה יכול לעשות בעצמך על ידי הקלדת אותן פקודות. + +--- + +## כיצד זה קשור לממשקים האחרים של AgentEye + +AgentEye נותן לך ארבע דרכים להגיע לאותם נתונים וקטגוריות. הם משלימים אחד את השני: + +| ממשק | מה זה | היכן זה פועל | השתמש בו כאשר | +|---|---|---|---| +| **[CLI](/he/agenteye/cli)** | ההפניה לפקודה/דגל עבור `agenteye` | הטרמינל שלך | אתה רוצה להריץ או לכתוב סקריפט לפקודה ספציפית | +| **[CLI recipes](/he/agenteye/cli-recipes)** | דפוסי `jq`/pipeline להעתיק והדבק | הטרמינל שלך / סקריפטים | אתה מחבר את ה-CLI לאוטומציה | +| **CLI skill** (מסמך זה) | דלת קדמית בשפה טבעית ב-CLI | סוכן הקוד שלך, בתחנה שלך | אתה רוצה *פשוט לשאול* ולתן לסוכן לבחור את הפקודה | +| **[עוזר AI בלוח המחוונים](/he/agenteye/assistant)** | צ'אט מובנה בלוח המחוונים | מיכל `agent` פנימי בקלסטר שלך | אתה רוצה שאלות ותשובות בלוח המחוונים על הנתונים שלך | + +### לעומת עוזר ה-AI בלוח המחוונים — הבחנה חשובה + +אלה שני כלים שונים עם רדיוסי התפוצה שונים מאוד: + +- **עוזר ה-AI בלוח המחוונים** ([assistant.md](/he/agenteye/assistant)) הוא צ'אט מובנה בלוח המחוונים, תומך על ידי מיכל `agent` פנימי. זה **קריאה בלבד בתוספת כתיבה מאושרת**: זה יכול להשרטט שאילתות שמורות ולוחות מחוונים, אך כל כתיבה משהה לאישור נקודה מפורש שלך, והוא לעולם לא מוחק. זה מוגבל בהרשאה `agent:use` וזה רואה רק נתונים עבור הארגון שאתה צופה בו. +- **CLI skill** פועל על *תחנה שלך* בתוך *סוכן הקוד שלך* ומנהל את `agenteye` CLI כ-**אתה**. זה יכול לבצע את **המשטח המלא, כולל מוטציות** — ליצור/לסובב/להשבית מפתחות API, לשנות הגדרות ארגון, לפתור אירועים, למחוק שאילתות שמורות — מוגבל רק בהרשאות של כניסת ה-CLI שלך. התייחס אליו בדיוק כמו שהיית מתייחס להפעלת אותן פקודות ביד. + +--- + +## דרישות מוקדמות + +1. **ה-`agenteye` CLI מותקן** וב-`PATH` (ראה [cli.md](/he/agenteye/cli) — `pipx install agenteye`). +2. **כתובת URL של לוח המחוונים שלך** מוגדרת (`AGENTEYE_DASHBOARD_URL`, או הסוכן מעביר `--base-url`). +3. **סשן מחובר**: הרץ `agenteye login` בעצמך תחילה. ה-skill **לא יכול** להשלים עבורך את כניסת קוד חד-פעמי בדוא"ל — זה יגיד לך להריץ `agenteye login` אם הסשן חסר או פג (קוד יציאת CLI `4`). + +--- + +## התקנת ה-Skill + +Agent Skills הם תיקיות המכילות `SKILL.md` (בתוספת הפניות אופציונליות). אתה מתקין את ה-`agenteye-cli` skill על ידי הצבת התיקייה שלה היכן שהסוכן שלך מחפש skills: + +- **Claude Code** — העתק את תיקיית `agenteye-cli/` לתוך `~/.claude/skills/` (זמין בכל פרויקט) או לתוך `/.claude/skills/` (מוגבל לריפו זה). Claude Code מגלה אותו באופן אוטומטי; אמת עם רשימת `/skills`, או פשוט שאל שאלה התואמת את התיאור שלו. +- **Codex (OpenAI)** — Codex קורא את אותו `SKILL.md`. ה-`agents/openai.yaml` המצורף מגדיר `allow_implicit_invocation: true`, כך ש-Codex בוחר באופן אוטומטי את ה-skill כאשר המשימה תואמת; אחרת בקיע אותו במפורש כ-`$agenteye-cli`. + +ה-skill נתחזק לצד ה-`agenteye` CLI והוא מופץ כחלק מחבילת AgentEye שלך — אם אין לך את תיקיית `agenteye-cli`, בקש מנציג AgentEye שלך. שום דבר בקשר אליו לא מוגבל: זה לא צריך תמונת Docker ושום אישור, כי זה רק מנהל את ה-**ציבור** `agenteye` CLI כנגד לוח המחוונים שלך. + +--- + +## בטיחות — מוטציות לא מהבהבות כאשר סוכן מריץ את ה-CLI + +**קרא את זה לפני שאתה מאפשר לסוכן לבצע שינויים.** + +ה-`agenteye` CLI בדרך כלל שואל *"אתה בטוח?"* לפני פעולה הרסנית. זה **דלג אוטומטי על אישור זה בכל פעם שזה לא מחובר לטרמינל — שזה בדיוק איך סוכן קוד מריץ אותו — ו-`--json` דלג עליו גם.** אז הודעת הבטיחות **לא** תורה עבור הסוכן. + +ה-skill כתוב לפיצוי: זה מוסר להצהיר את הפקודה המדויקת שהיא תריץ ולקבל את ה-**OK** המפורש שלך לפני כל שינוי מצב. שמור על משמעת זו — כאשר אתה מנהל את AgentEye דרך סוכן, *אתה* הם שלב האישור. פקודות שינוי המצב שיש להשגיח עליהם: + +- `keys create` / `update` / `disable` / `regenerate` +- `users create` / `update` / `disable` / `enable` +- `settings set` +- `alerts create` / `update` / `delete` / `test` +- פקודות ה-`incidents` הכתובות: `ack` / `assign` / `resolve` / `open` / `comment-add` / `comment-delete` / `subscribe` / `unsubscribe` +- `query create` / `update` / `delete` +- `agent rename` / `delete` +- `orgs switch` + +הכל תחת **Observe** (`events`, `sessions`, `evals`, `errors`, `list`, `whoami`, `orgs list/current/perms`) הוא קריאה בלבד ולא משנה דבר. + +כי הסוכן פועל כ-**אתה**, זה יכול לעשות רק מה שההיכנסה שלך מורשית לעשות — הרשאות מתוקנות **לכל ארגון** (ראה [api-keys.md](/he/agenteye/api-keys)). פקודה שאתה חסר הרשאה עבורה מחזירה קוד יציאה `5` עם ההרשאה המדויקת בשם, כך שהסוכן יכול להגיד לך בדיוק למה לשאול מנהל במקום להיכשל בעמימות. + +--- + +## מה אתה יכול לשאול אותו + +ה-skill ממפה כוונה בשפה טבעית לפקודת `agenteye` הנכונה, גילוי ערכים תקפים תחילה (`list `, `whoami`) כך שזה לא מנחש: + +- *"האם משהו שבור / פורץ ביום האחרון 24?"* → `errors --since 24h --aggregate`, אז פירוט. +- *"למה הסשן `run-001` נכשל?"* → `events --session-id run-001 --all` + `evals --session-id run-001`. +- *"כיצד איכות מתגמרת השבוע?"* → `evals --aggregate --since 7d`, אז עמוק לתוך ריצות ניקוד נמוך. +- *"תן ל-CI מפתח שיכול רק לדחוף אירועים."* → `keys create ci --add events:add` (זה מציין את הפקודה, אז יוצר אותה וקצירות את הסוד החד-פעמי). +- *"מי יש גישה? תן ל-Dana קריאה בלבד."* → `users list` → `users update dana@… --permission-set read-only` (אחרי שאישרת עם אתה). +- *"אשר את אירוע הירי והקצה אותו לי."* → `incidents list --state firing` → `incidents ack ` / `incidents assign you@…`. + +עבור הפקודות המדויקות, דגלים וצורות JSON מאחוריהם, ראה [cli.md](/he/agenteye/cli) ו-[cli-recipes.md](/he/agenteye/cli-recipes). + +--- + +## ראה גם + +- **[CLI](/he/agenteye/cli)** — הפניה פקודה ודגל מלאה עבור `agenteye`. +- **[CLI recipes לסוכנים](/he/agenteye/cli-recipes)** — דפוסי `jq` להעתיק והדבק וטיפול בקוד יציאה. +- **[עוזר AI](/he/agenteye/assistant)** — העוזר בלוח המחוונים (לא להתבלבל עם ה-skill הטרמינל הזה). +- **[API Keys](/he/agenteye/api-keys)** — מודל ההרשאות לכל ארגון השומר מה ה-skill יכול לעשות. \ No newline at end of file diff --git a/docs/he/agenteye/cli.mdx b/docs/he/agenteye/cli.mdx new file mode 100644 index 00000000..44b0190b --- /dev/null +++ b/docs/he/agenteye/cli.mdx @@ -0,0 +1,291 @@ +--- +title: "CLI" +description: "תיעוד AgentEye CLI." +--- + +AgentEye CLI (`agenteye`) הוא קליינט טרמינל להגדרת AgentEye שלך. הוא שואל את הנתונים שלך (sessions, event logs, evaluations) וממנהל את הארגון (API keys, users, settings, alerts, incidents, saved queries) — הכל שהלוח המחווני עושה, מסקריפט או מ-coding agent. כל פקודה תומכת בדגל `--json`, כך שהיא עובדת באותה מידה היטב עבור אדם בשורה הפקודה או עבור coding agent (Claude Code, Cursor) המריץ קוד וניתח את התוצאה. + +> זהו ה-**`agenteye` CLI**, כלי שונה מה-**collector** daemon (`agenteye-collector`). ה-CLI דיברת עם ה-**dashboard** שלך; ה-collector משדר אירועים לשרת. ראה [Collector Installation](/he/agenteye/collector-installation) לאחר האספן. + +--- + +## התקנה + +ה-CLI פורסם ל-public PyPI בשם **`agenteye`**. מכיוון ש-AgentEye Python SDK משתמש גם בשם ההפצה `agenteye`, התקן את ה-CLI בסביבה **מבודדת** (`pipx` או `uv tool`) כך שהשניים לא יתנגשו בסביבה וירטואלית אחת: + +```bash +pipx install agenteye +# or +uv tool install agenteye +``` + +`pip install agenteye` רגיל גם עובד אם אתה לא מתקין את Python SDK לאותה סביבה. ה-CLI דורש Python 3.10+ ולא צריך GitHub token; זה חבילה ציבורית. + +הפקודה המותקנת היא **`agenteye`**: + +```bash +agenteye --version +agenteye --help +``` + +--- + +## הנחה + +ה-CLI משתנה עם ה-**dashboard** קוד חד-פעמי שהשתלח בדוא"ל: + +```bash +agenteye login --email you@example.com +# קוד בן 6 ספרות נשלח אליך בדוא"ל; הדבק אותו בהנחיה. +``` + +טוקן ה-session מאוחסן ב-`~/.agenteye/cli.json` (קריא רק לך, mode `0600`) ותקף למשך 24 שעות כברירת מחדל. כאשר הוא פקע, הרץ `agenteye login` שוב. + +```bash +agenteye whoami # הצג את המשתמש הנוכחי, את הארגון הפעיל, וההרשאות +agenteye logout # שלול את ה-session ומחק את הטוקן המאוחסן +``` + +`whoami` לא תמיד טועה בסשן חסר או שפג — הוא דיווח `logged_in: false` במקום זאת, כך שסקריפט או agent יכול לבדוק בבטחה את מצב הנחה (הוא עדיין יכול לצאת עם קוד שאינו אפס אם לא הוגדרה כתובת URL בסיס או לוח המחווני אינו נגיש). + +**דרישות:** הדוא"ל שלך חייב להיות מורשה להיכנס ללוח המחווני (בקש מהמנהל AgentEye), ולוח המחווני חייב להיות נגיש בכתובת ה-URL הבסיסית שלו (ראה [Configuration](#configuration)). אם תבקש קוד ואף אחד לא יגיע, הדוא"ל שלך עדיין לא הופעל לגישה ללוח המחווני. + +--- + +## בחירת הארגון שלך (multi-tenant) + +אם החשבון שלך שייך ליותר מארגון אחד, בחר את האחד הפעיל **בעת ההתחברות** — הוא נשמר ומשמש לכל פקודה מאוחרת יותר: + +```bash +agenteye login --org acme # התחבר וקבע את ה-tenant הפעיל בצעד אחד +agenteye orgs list # הארגונים שאתה יכול לגשת (הפעיל מסומן) +agenteye orgs switch globex # שנה את ברירת המחדל השמורה +agenteye --org globex sessions # עקוף לפקודה אחת +``` + +אם אתה משייך לדיוק ארגון אחד, הוא נבחר באופן אוטומטי ותוכל להתעלם מ-`--org` לחלוטין. אם אתה שייך לכמה ולא בחרת אחד, ה-CLI מפרט אותם ומבקש ממך להריץ שוב עם `--org `. הארגון הפעיל נשלח ללוח המחווני בכל בקשה, וההרשאות שלך מסולקות **לכל ארגון** — `agenteye whoami` מציג את הארגון הפעיל, ההרשאות שלך בו, וכל חברויות שלך. + +--- + +## הגדרה + +| הגדרה | דגל | משתנה סביבה | ברירת מחדל | +|---|---|---|---| +| כתובת URL בסיסית של לוח המחווני | `--base-url` | `AGENTEYE_DASHBOARD_URL` | **נדרש** (ללא ברירת מחדל) | +| ארגון/tenant פעיל | `--org` | `AGENTEYE_ORG` | נבחר בהתחברות; שמור ב-`~/.agenteye/cli.json` | +| טוקן של Session | `--token` | `AGENTEYE_CLI_TOKEN` | מ-`~/.agenteye/cli.json` | +| פלט JSON | `--json` | `AGENTEYE_CLI_JSON` | כבוי | +| דלג על אימות TLS | `--insecure` / `--secure` | `AGENTEYE_INSECURE` | כבוי (שמור בהתחברות) | +| פקת זמן בקשה (שניות) | `--timeout` | — | 30 | +| הפוך טלמטריה של שימוש | _(none)_ | `AGENTEYE_ANALYTICS_DISABLED` (או `DO_NOT_TRACK`) | כבוי (טלמטריה פעילה) | + +סדר ההחלטה הוא **דגל → משתנה סביבה → קובץ תצורה**. אין ברירת מחדל; עליך להצביע על ה-CLI בלוח המחווני שלך, או לכל פקודה (`--base-url https://agenteye.example.com`) או פעם אחת דרך הסביבה (היא גם נשמרת לאחר ה-`login` הראשון שלך): + +```bash +export AGENTEYE_DASHBOARD_URL=https://agenteye.example.com +``` + +ספריית התצורה כבדה `AGENTEYE_HOME` (אותה קונבנציה בה משתמשים ה-SDK וה-collector); אם מוגדר, `cli.json` חי ב-`$AGENTEYE_HOME/cli.json`. + +### TLS חתום עצמי או פנימי + +אם לוח המחווני שלך מוגש על HTTPS עם תעודה חתומה עצמית או פנימית (לדוגמה, שם מארח טעינה גולמי), אימות TLS דוחה אותה בשגיאה `CERTIFICATE_VERIFY_FAILED`. העבור `--insecure` לדלג על אימות תעודה: + +```bash +agenteye --base-url https://agenteye.internal --insecure login +``` + +`--insecure` הוא **שמור ל-`cli.json` כאשר אתה מתחבר**, כך שפקודות מאוחרות יותר דולגות על אימות באופן אוטומטי; אתה לא צריך לחזור על הדגל. העבור `--secure` לשיחה מאומתת חד-פעמית, או כדי לשמור על אימות בחזרה בהתחברות הבאה שלך. ה-CLI מדפיס אזהרה ל-stderr לפני כל פקודה שמתקשרת עם לוח המחווני בזמן השבתת האימות. דלג על אימות מסיר הגנה מפני התקפות אדם-בתוך-האמצע; ודא שאתה סומך על נתיב הרשת ללוח המחווני שלך (VPN, תת-רשת פרטית, וכו') לפני שאתה מסתמך עליו. + +--- + +## טלמטריה וחסיוניות + +ה-CLI שולח **ניתוחי שימוש אנונימיים** לשירות הניתוחים של Exosphere (PostHog): אילו פקודות מריץ (למשל `sessions`, `keys create`), האם הם הצליחו, וכמה זמן לקחו. אות שימוש זה מעביר עדיפות אילו תכונות. + +- **אף פעם לא יעזוב נתוני agent, session או event את התשתית שלך.** דווח רק שימוש CLI: שם הפקודה וה-subcommand (למשל `keys create`), **שמות** הדגלים שבהם השתמשת (לעולם לא הערכים שלהם), מצב הצלחה/יציאה, ותזמון — בתוספת אירוע לפעולה למוטציות (למשל `api_key_created`, `query_run`) הנושאות רק שמות סטטיים/enums וספירות גסות. כתובת ה-URL של לוח המחווני שלך, טוקן ה-session, דוא"ל, ארגון slug, ids משאבים, SQL, סודות מפתח, וסינוני שאילתה הם **לעולם** לא נשלחים. מפעילים מזוהים רק לפי מזהה פנימי אטום, לעולם לא בדוא"ל. +- טלמטריה **מופעלת כברירת מחדל**. כדי לכבות זאת, הגדר `AGENTEYE_ANALYTICS_DISABLED=1` בסביבת ה-CLI (ה-CLI גם כבד את הקונבנציה החוצה-כלים `DO_NOT_TRACK=1`). +- ה-CLI שולח ישירות ל-PostHog (`https://us.i.posthog.com`). **המכונה המריצה את ה-CLI** זקוקה לגישת יציאה לאותו מארח; אם היא חסומה, טלמטריה שותקת לא עושה כלום (שליחה מוגבלת בזמן כך שלעולם לא תעכב או תשבור פקודה) וה-CLI לא מושפע. + +--- + +## אפשרויות גלובליות וקונבנציות + +קרא את זה פעם אחת; זה חל על כל פקודה. + +- **אפשרויות גלובליות הולכות לפני הפקודה.** `agenteye --json sessions` נכון; `agenteye sessions --json` הוא שגיאת שימוש. הגלובליים הם `--json`, `--base-url`, `--org`, `--token`, `--insecure`/`--secure`, `--timeout`, `--quiet`, ו-`--no-color`. +- **`--json` הדפס JSON טהור ל-stdout, ותו לא.** שורות סטטוס אנושיות, אזהרות ושגיאות הולכות ל-**stderr**, כך ש-`--json` stdout capture נשאר נקי להצנעה ל-`jq` גם כאשר מוצגת שורת סטטוס. ללא `--json` אתה מקבל תצוגה מעוטרת וצבעוני לעיניים אנושיות. +- **גלה עם `--help`.** לכל פקודה ו-subcommand יש `--help` (וגם כינוי `-h`): `agenteye -h`, `agenteye sessions -h`, `agenteye keys create -h`. העזרה ברמה העליונה גם רשימות את קודי היציאה והאפשרויות הגלובליות. אין יומן משטחי קריא-מכונה גלובלי; השתמש ב-`--help` לכל פקודה, בתוספת `agenteye query schema` ו-`agenteye settings schema` המיוחדים לתחום לאלו שתי רישומים. +- **אישורים דלגים אוטומטית לסקריפטים וחוכמים.** פקודות יצירה/עדכון/מחיקה מהווה "האם אתה בטוח?" בטרמינל אינטראקטיבי, אך **דלוג אוטומטי על כל הנחיה תחת `--json` או בכל פעם שה-stdin אינו TTY** — כך שסקריפטים וחוכמים לעולם לא תלויים. העבור `--yes`/`-y` כדי לדלג עליו במפורש. מכיוון שהנחיה לא תשריא לחוכם, חוכם צריך לאשר פעולות הרסניות עם האדם תחילה. +- **עימוד:** התוצאות הן הנדירות ראשונות ו-cursor-paginated. `--limit N` (כינוי `-n`) מכסה שורות ו-**ברירת מחדל ל-50**; `--all` auto-paginates (ב-200 שורות chunks) **עד `--limit`** — כך שחוסר `--all` עדיין עוצר ב-50. לטיול מלא העבור הגבול המפורש הגבוה: `--all --limit 1000`. `--page-size N` שולטת ב-chunk לכל בקשה (max 200); `--cursor ` התחלה מה-`next_cursor` של דף קוד. +- **סינני זמן:** `--since` לוקח חלון יחסי — `15m`, `1h`, `6h`, `24h`, `7d`, `30d`, או `all` (ההגדרות המוקדמות של לוח המחווני). `--from`/`--to` לוקחו בדיוק ISO-8601 UTC timestamps **עם `T` ואזור זמן** (למשל `2026-06-01T00:00:00Z`) לטווח מותאם אישית ועקוף `--since`; ערך מופרד בחלל או חסר אזור זמן הוא שגיאת שימוש. +- **`--fields a,b,c`** (ב-`events`, `sessions`, `evals`, `errors`) מגביל את התפוקה לאותם מפתחות, לטבלה ול-`--json`. שמות לא ידועים נדחים עם רשימה תקפה — דרך זולה לגלות שמות שדה. +- **`--file payload.json`** (או `--file -` קרא stdin) מסופק גוף בקשה JSON מלא שבו משאב בעל צורה מורכבת — על `alerts create/update`, `settings set`, ו-`users create/update`. SQL שמור לשימוש `--sql @file.sql` במקום זאת. +- **סינני רב-ערך** הם מופרדים בפסיקים → התאמה כסדרה (איחוד בתוך מסנן אחד, AND בין סינוני): `--event-type tool_use,tool_result`. אפשרויות לחיצה אינן variadic, כך `--add a b` מנתק — השתמש ב-`--add a,b`, חזור על הדגל (`--add a --add b`), או ציטוט (`--add "a b"`). + +--- + +## ייחוס הפקודה + +ל-CLI יש **18 פקודות ברמה עליונה**. כל פקודות קריאה מקבלות `--json` והאפשרויות הגלובליות לעיל; הרץ `agenteye -h` (או ` -h`) לרשימת הדגל המקיפה וצורת JSON של כל אחד. + +### זהות — `login` · `logout` · `whoami` · `orgs` · `version` · `help` + +```bash +agenteye login --email you@example.com [--org acme] # emailed one-time code; saves the session +agenteye logout # clear the saved session on this machine +agenteye whoami # current user, active org, permissions +agenteye version # print the CLI version (same as --version) +agenteye help # top-level help (same as --help) +``` + +`orgs` בודקת ומחליפה את ה-tenant הפעיל: + +```bash +agenteye orgs list # הארגונים שלך + תפקידך בכל אחד (הפעיל מסומן) +agenteye orgs switch acme # שנה את הארגון הפעיל השמור (השמט את ה-slug כדי לבחור מרשימה ב-TTY) +agenteye orgs current # כרטיס זהות לארגון הפעיל +agenteye orgs perms # ההרשאות שלך בארגון הפעיל, מקובצות לפי משאב +``` + +### הצגה (קריאה בלבד) — `events` · `sessions` · `evals` · `errors` · `list` + +אף אחד מאלה לא זקוק לאישור. סינוני משותפים: `--session-id`, `--agent-id`, `--env` (**לא** `--environment`), וטווח הזמן (`--since` / `--from` / `--to`). + +```bash +# events (alias: the raw per-step trail) — newest first +agenteye --json events --session-id run-001 --event-type tool_use,tool_result --all --limit 1000 +agenteye --json events --since 1h --search timeout --all | jq '.events[].payload' + +# sessions — one row per agent run (time/env/agent/session/status; no score filtering) +agenteye --json sessions --since 24h --status error +agenteye --json sessions --agent-id checkout-bot --env prod --all --limit 1000 + +# evals — evaluation results + scores; --score filters by metric, --aggregate rolls up +agenteye --json evals --score helpfulness:0.5..0.8 --score tool_efficiency:..0.3 +agenteye --json evals --aggregate --since 7d --env prod # status mix + per-key score stats + +# errors — errored events; --aggregate for counts/sessions/agents/last-seen +agenteye --json errors --since 24h --aggregate +agenteye --json errors --since 24h --error-type timeout --all --limit 1000 + +# list — discover valid filter values before you filter +agenteye list envs # also: agents event_types score_filters models hooks triggers tools error_types +``` + +`--score KEY:MIN..MAX` (ב-**`evals`**, לא `sessions`) ניתן לחזור ו-AND-combined; כל קשור הוא אופציונלי (`..0.5` משמעו ≤ 0.5, `0.9..` משמעו ≥ 0.9). עד 20 סינני ניקוד לכל בקשה. `evals --scores-full` מחזירה את אובייקט הניקוד המלא ולא את הסיכום. כדי לקרוא **session אחד מסוף לסוף**, שלב את שביל האירוע עם הערכה שלו: + +```bash +agenteye --json events --session-id run-001 --all --limit 1000 | jq '.events[] | {ts, event_type}' +agenteye --json evals --session-id run-001 # its scores + status +``` + +### ניהול (gated permission) — `keys` · `users` · `settings` · `alerts` · `incidents` + +**`keys`** — מפתחות API. הסוד נוצר באופן מקומי, נשלח לשרת (השרת מאחסן רק hash), ו-**מוצג פעם אחת** ביצירה/הפק מחדש — תפוס אותו אז. עם `--json` זה מופיע רק בשדה `key`. מוזכר לפי **שם**. + +```bash +agenteye keys list # active keys first, then revoked +agenteye keys show ci-bot +agenteye keys create ci-bot --add events:read.add # scope to what you need; prints the secret ONCE +agenteye keys create ops --permission-set standard --remove queries:run # seed a preset, then trim +agenteye keys update ci-bot --add evaluations:read --yes +agenteye keys regenerate ci-bot --yes # rotate the secret (the old one stops working) +agenteye keys disable ci-bot --yes # revoke +``` + +הרשאות עובדות כ-`(permission-set ∪ --add) − --remove`. טוקנים הם `slug:action` (למשל `events:read`) או `slug:action.action` להרחבת כמה על משאב אחד (`events:read.add` → `events:read`, `events:add`). Presets: `read-only`, `standard`, `admin`. הרשאות בעלות-בעלות בלבד (`keys:update`) לא ניתן להעניק למפתח. + +**`users`** — חברי הארגון, מוזכרים לפי **דוא"ל** (id UUID מקובל גם כן). + +```bash +agenteye users list [--active-only] +agenteye users show dev@corp.com +agenteye users create dev@corp.com --permission-set standard +agenteye users update dev@corp.com --add alerts:write --remove queries:delete # predicts + confirms +agenteye users disable dev@corp.com --yes # has protected/self guards +agenteye users enable dev@corp.com +``` + +**`settings`** — רישום קבוע (אתה קורא ומשנה מפתחות קיימים; אתה לא יכול ליצור חדשים). + +```bash +agenteye settings list # key · value · type · updated (secrets masked) +agenteye settings schema # what each key accepts (type · range · description) +agenteye settings set session_ttl_secs --value 86400 --yes +``` + +**`alerts`** — הגדרות התראה, מוזכרות לפי **שם**. `create` לוקח NAME עמדתי בתוספת דגלים או גוף JSON מלא דרך `--file`. + +```bash +agenteye alerts list +agenteye alerts show high-errors +agenteye alerts create high-errors --file alert.json # NAME is required (positional) +agenteye alerts update high-errors --severity critical --yes +agenteye alerts test high-errors --yes # fire a test notification +agenteye alerts delete high-errors --yes +``` + +**`incidents`** — התראה אירועים, מוזכרים ב-id (ids קצרים מקובלים). `show` הדפיס את יומן הפעילות המלא — קרא אותו לפני השקעת אקטיביזם. + +```bash +agenteye incidents list --state firing # also: acknowledged, resolved +agenteye incidents count +agenteye incidents show +agenteye incidents ack +agenteye incidents assign you@corp.com # assignee must be an operator +agenteye incidents resolve --yes +agenteye incidents open --alert-id --severity critical # open one manually against an alert +agenteye incidents comment-add "root cause: upstream 5xx" +agenteye incidents comment-list ; agenteye incidents comment-delete +agenteye incidents subscribe ; agenteye incidents unsubscribe ; agenteye incidents subscribers +``` + +### ניתוח ומסייע — `query` · `agent` + +**`query`** — SQL ClickHouse שמור בתוספת רץ ad-hoc. שאילתות שמורות מוזכרות לפי **שם**; ה-SQL מאומת בצד השרת (רק SELECT/WITH, timeout הצהרה, row cap). + +```bash +agenteye query schema [TABLE] # column layout of the analytics views +agenteye query run --sql "select count(*) from analytics.events" +agenteye query run errs --arg prod --limit 100 # run a saved query + a positional $1 +agenteye query list ; agenteye query show errs +agenteye query create errs --sql @errs.sql --description "errored events (24h)" +agenteye query update errs --sql @errs.sql --yes ; agenteye query delete errs --yes +``` + +**`agent`** — מסייע לוח המחווני הבנוי-ב (אותו אנליסט קריא-בלבד שאתה יכול לשוחח איתו בלוח המחווני). הצ'טים מוזכרים ב-short chat-id (prefix-resolved). + +```bash +agenteye agent health # is the assistant configured/reachable +agenteye agent models # models you can pass to --model (default marked) +agenteye agent ask "which agents errored most in the last day?" # starts a chat; prints its short id +agenteye agent ask --chat "and which tools did they call?" # continue that chat +agenteye agent chats ; agenteye agent show +agenteye agent rename --title "error triage" ; agenteye agent delete +``` + +--- + +## קודי יציאה + +| קוד | משמעות | +|---|---| +| 0 | הצלחה | +| 1 | שגיאה בלתי צפויה (למשל לוח המחווני החזיר 5xx) | +| 2 | שגיאת שימוש (טיעונים לא חוקיים, פקודה/דגל לא ידוע, התנגשות שם) | +| 3 | לא יכול להגיע ללוח המחווני | +| 4 | לא מחובר או session שפג; הרץ `agenteye login` | +| 5 | מאומת, אך החשבון שלך חסר בהרשאה הנדרשת (ההודעה שם זה) | +| 6 | המשאב המבוקש לא נמצא (למשל unknown session או incident id) | + +אלה הופכים את ה-CLI בטוח לסקריפט: coding agent יכול לסניף על `4` לנקוב אותך להנחה מחדש, או `5` לפני ההרשאה החסרה. ראה [CLI recipes for agents](/he/agenteye/cli-recipes) עבור דוגמנים exit-code-handling וצורות JSON פלט. + +--- + +## ראה גם + +- **[CLI recipes for agents](/he/agenteye/cli-recipes)** — copy-paste query patterns, `jq` one-liners, `--fields` projections, exit-code handling, and JSON output shapes, written for coding agents driving the CLI. +- **[AgentEye CLI skill](/he/agenteye/cli-skill)** — package this CLI as an installable Claude Code / Codex *skill* so a coding agent drives AgentEye from plain-English requests. +- **[API Keys](/he/agenteye/api-keys)** — the permission model behind `keys create --add …`. +- **[AI Assistant](/he/agenteye/assistant)** — enabling the assistant that `agent ask` talks to. \ No newline at end of file diff --git a/docs/he/agenteye/collector-installation.mdx b/docs/he/agenteye/collector-installation.mdx new file mode 100644 index 00000000..4a76678c --- /dev/null +++ b/docs/he/agenteye/collector-installation.mdx @@ -0,0 +1,401 @@ +--- +title: "התקנת Collector" +description: "תיעוד התקנת AgentEye Collector." +--- + + +ה-daemon `agenteye-collector` מבטיח שהטלמטריה של הסוכנים שלך תגיע ל-AgentEye מבלי לחסום את האפליקציה שלך אי פעם. הקוד שלך כותב אירועים לספריה מקומית ומעביר הלאה; ה-collector משתלט משם, מעלה כל קובץ תוך מילישניות ומשרד הפעלות מחדש, הפסקות רשת וטעויות שרת חולפות. העלאות שנכשלו מנסו שוב עם exponential backoff, וסיור התאוששות תקופתי מכניס לתור מחדש כל דבר שנותר מ-crash או deploy. התוצאה היא משלוח עמיד ו-fire-and-forget: הסוכנים שלך ממשיכים לרוץ במהירות מלאה בזמן שה-collector מוודא שלא יאבדו אירועים בדרך. + +מבחינה מכנית, ה-collector הוא daemon קל משקל שמראיין `$AGENTEYE_HOME/events/` (ברירת מחדל: `~/.agenteye/events/`) לקבצי `.jsonl` שנכתבו על ידי Python SDK ומעלה אותם לשרת AgentEye. + +> **שונה שם:** הפקודה של ה-collector כעת היא **`agenteye-collector`** (בעבר היתה `agenteye`). השם הקצר `agenteye` שייך כעת ל-AgentEye CLI. אם אתה משדרג התקנה קיימת, ראה [enterprise-docs/collector-migration.md](/he/agenteye/collector-migration). + +--- + +## דרישות קדם + +- ה-`AGENTEYE_TOKEN` שלך: GitHub PAT שאתה מייצר בעצמך (ראה [enterprise-docs/github-token.md](/he/agenteye/github-token)) +- כתובת ה-URL של השרת ומפתח API של collector (ראה [enterprise-docs/api-keys.md](/he/agenteye/api-keys)) + +--- + +## אפשרות A: Binary (מומלץ) + +Binary סטטיים שנבנו מראש זמינים ל-Linux, macOS ו-Windows (x86_64 ו-arm64). הורד את ה-binary עבור הפלטפורמה שלך ישירות מריפו `agenteye-enterprise/releases` תחת תג ההשחרור האחרון `collector/v`. + +שמות artifacts זמינים: + +| פלטפורמה | Artifact | +|---|---| +| Linux x86_64 | `agenteye-collector-linux-x86_64` | +| Linux arm64 | `agenteye-collector-linux-arm64` | +| macOS x86_64 | `agenteye-collector-darwin-x86_64` | +| macOS arm64 | `agenteye-collector-darwin-arm64` | +| Windows x86_64 | `agenteye-collector-windows-x86_64.exe` | +| Windows arm64 | `agenteye-collector-windows-arm64.exe` | + +**הורד באמצעות CLI של `gh`** (החלף את הגרסה ובחר את ה-artifact של הפלטפורמה שלך): + +```bash +VERSION=0.0.1-beta.13 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "collector/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-collector-linux-x86_64' + +chmod +x agenteye-collector-linux-x86_64 +sudo mv agenteye-collector-linux-x86_64 /usr/local/bin/agenteye-collector +``` + +**או עם `curl`:** + +```bash +VERSION=0.0.1-beta.13 +ARTIFACT=agenteye-collector-linux-x86_64 +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + -L "https://github.com/agenteye-enterprise/releases/releases/download/collector%2Fv${VERSION}/${ARTIFACT}" \ + -o agenteye-collector +chmod +x agenteye-collector +sudo mv agenteye-collector /usr/local/bin/agenteye-collector +``` + +--- + +## אפשרות B: Docker + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +docker pull ghcr.io/agenteye-enterprise/collector:beta-latest +``` + +> בניות beta נוכחיות מפרסמות את התג הצף `:beta-latest`; `:latest` מוקצה רק לשחרורים יציבים. להטמעות חוזרות, עדיף תג גרסה קבועה כמו `:v0.0.1-beta.13`. + +**הפעל:** + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-collector \ + -e AGENTEYE_URL=https://ingest.example.com/events \ + -e AGENTEYE_KEY="$AGENTEYE_KEY" \ + -e AGENTEYE_HOME=/data \ + -v "$HOME/.agenteye:/data" \ + ghcr.io/agenteye-enterprise/collector:beta-latest \ + start +``` + +התמונה הרשמית פועלת כמשתמש שאינו root, אז הגדר `AGENTEYE_HOME` בהפרשה וחבר את ה-spool של המארח אליו. העלאת הנפח משתפת את אותה ספריית `~/.agenteye/` שה-Python SDK כותב אליה על המארח. אם כבר הגדרת `AGENTEYE_HOME` במקום אחר על המארח, חבר את הספריה הזאת במקום `$HOME/.agenteye`. + +--- + +## תצורה + +ניתן להגדיר את כל האפשרויות בשלוש דרכים (סדר עדיפויות מהגבוה לנמוך): + +1. דגל CLI: `agenteye-collector start --url https://...` +2. משתנה סביבה: `AGENTEYE_URL=https://...` +3. קובץ תצורה: `~/.agenteye/config.json` + +### אפשרויות נדרשות + +| אפשרות | דגל CLI | משתנה סביבה | מפתח config.json | +|---|---|---|---| +| כתובת URL של Backend | `--url ` | `AGENTEYE_URL` | `"url"` | +| מפתח API | `--key ` | `AGENTEYE_KEY` | `"key"` | + +### אפשרויות אופציונליות (עם ברירות מחדל) + +| אפשרות | דגל CLI | משתנה סביבה | מפתח config.json | ברירת מחדל | +|---|---|---|---|---| +| עלאות מקביליות מקסימום | `--max-concurrent-uploads ` | `AGENTEYE_MAX_CONCURRENT_UPLOADS` | `"max_concurrent_uploads"` | `64` | +| מרווח Sweeper (s) | `--sweep-interval ` | `AGENTEYE_SWEEP_INTERVAL` | `"sweep_interval_secs"` | `60` | +| גיל קובץ מינימום של Sweeper (s) | `--sweep-min-age ` | `AGENTEYE_SWEEP_MIN_AGE` | `"sweep_min_age_secs"` | `120` | +| קבצים מקסימום לכל sweep | `--sweep-max-files ` | `AGENTEYE_SWEEP_MAX_FILES` | `"sweep_max_files"` | `64` | +| ניסיונות העלאה מקסימום | `--max-retries ` | `AGENTEYE_MAX_RETRIES` | `"max_retries"` | `5` | +| קידום בסיסי של נסיון (ms) | `--retry-base-delay ` | `AGENTEYE_RETRY_BASE_DELAY` | `"retry_base_delay_ms"` | `1000` | + +### אפשרויות mTLS (אופציונליות) + +להטמעות הדורשות TLS הדדי (mTLS), ה-collector יכול להציג תעודת קליינט במהלך handshake של TLS. כאשר האפשרויות הללו אינן מוגדרות, ה-collector משתמש ב-HTTPS סטנדרטי. + +| אפשרות | דגל CLI | משתנה סביבה | מפתח config.json | +|---|---|---|---| +| תעודת קליינט (PEM) | `--tls-cert ` | `AGENTEYE_TLS_CERT` | `"tls_cert"` | +| מפתח פרטי של קליינט (PEM) | `--tls-key ` | `AGENTEYE_TLS_KEY` | `"tls_key"` | +| תעודת CA מותאמת (PEM) | `--tls-ca ` | `AGENTEYE_TLS_CA` | `"tls_ca"` | + +יש להגדיר `--tls-cert` ו-`--tls-key` ביחד. הקבצים חייבים להיות מקודדים PEM. + +`--tls-ca` אינו תלוי ודרוש רק כאשר שרת AgentEye מציג תעודת TLS שלא הוצאה על ידי CA שנחשב לאמין בציבור (למשל ממוקד עצמי על ידי issuer `cert-manager` בתוך cluster כאשר אין לך תחום DNS אמיתי). ה-collector מוסיף את ה-CA המסופק כנקודת אמון נוספת; השורשים הציבוריים הסטנדרטיים נשארים מהימנים, אז הטמעות קיימות לא מושפעות. הקובץ עשוי להכיל תעודת PEM יחידה או שרשרת מלאה (בלוקי PEM מרובים בשרשור). + +**הפעלת ה-collector כ-sidecar בחלונית האפליקציה שלך?** ראה [enterprise-docs/single-pod-deployment.md](/he/agenteye/single-pod-deployment) בשביל דפוס EKS מקצה לקצה: חבילת mTLS שמועברת דרך AWS Secrets Manager + Secrets Store CSI Driver + IRSA, עם סיבוב אוטומטי. + +כאשר פועלים ב-Kubernetes עם דפוס הסגה של Secret, חבר את ה-Secret של התעודה כנפח והצבע את הנתיבים הללו לקבצים המחוברים: + +```yaml +# דוגמה: קטע Deployment של collector +volumes: + - name: mtls-certs + secret: + secretName: agenteye-collector-mtls +containers: + - name: collector + env: + - name: AGENTEYE_TLS_CERT + value: /etc/agenteye/tls/tls.crt + - name: AGENTEYE_TLS_KEY + value: /etc/agenteye/tls/tls.key + # רק כאשר תעודת השרת אינה נחשבת לאמון בציבור (למשל + # CA ממוקד עצמי בתוך cluster). ה-Secret הזהה בדרך כלל נושא ca.crt + # לצד tls.crt/tls.key. + - name: AGENTEYE_TLS_CA + value: /etc/agenteye/tls/ca.crt + volumeMounts: + - name: mtls-certs + mountPath: /etc/agenteye/tls + readOnly: true +``` + +### דוגמה `~/.agenteye/config.json` + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "max_concurrent_uploads": 16, + "sweep_interval_secs": 30 +} +``` + +עם mTLS: + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "tls_cert": "/etc/agenteye/tls/tls.crt", + "tls_key": "/etc/agenteye/tls/tls.key" +} +``` + +עם mTLS בתוספת CA מותאם (שרת AgentEye ממוקד עצמי): + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "tls_cert": "/etc/agenteye/tls/tls.crt", + "tls_key": "/etc/agenteye/tls/tls.key", + "tls_ca": "/etc/agenteye/tls/ca.crt" +} +``` + +אם `AGENTEYE_HOME` מוגדר, הספריה הזאת משמשת במקום `~/.agenteye`. + +--- + +## הגדרה בפעם הראשונה + +לאחר ההתקנה, קבע את ה-collector עם כתובת ה-URL של השרת ומפתח ה-API שלך: + +```bash +mkdir -p ~/.agenteye +cat > ~/.agenteye/config.json <<'EOF' +{ + "url": "https://ingest.example.com/events", + "key": "YOUR_COLLECTOR_KEY" +} +EOF +``` + +> השתמש ב-`https` עבור כל הטמעה החוצה רשת לא מהימנה כדי שאירועים לא ישלחו בטקסט רגיל. טופס `http://your-server-host:8080/events` בטקסט רגיל מתאים רק לבדיקה טהורה מקומית נגד שרת באותו מארח. + +**בדוק את החיבור** (flush חד פעמי, יוצא לאחר ניקוז אירועים תלויים): + +```bash +agenteye-collector flush +``` + +`flush` דוחה את ההתקדמות שלו ל-stdout. כאשר ה-spool ריק זה מדפיס `No pending files.` ויוצא `0`. אחרת זה מדפיס שורה אחת לכל קובץ (`[UPLOADED] ` או `[FAILED] ()`), ואחריה סיכום `Done: / uploaded, failed.`. זה הופך את `flush` לבדיקה חד פעמית נוחה שהכתובת, המפתח וההגדרות של TLS שלך נכונות לפני שתתחיל את ה-daemon. + +--- + +## הפעלה כ-Daemon + +### ישיר + +```bash +agenteye-collector start +``` + +### Container / Docker + +כאשר ה-collector והאפליקציה שלך משתפים container, הפעל אותם תחת מפקח תהליך. האפשרות הפשוטה ביותר היא `supervisord`; זה משולח בכל distro עיקרי, הפעל מחדש תהליכים שהתרסקו, העביר אותות והמתן לשדרוג מסודר. + +**`Dockerfile`:** + +```Dockerfile +FROM python:3.11-slim + +RUN apt-get update && apt-get install -y --no-install-recommends supervisor \ + && rm -rf /var/lib/apt/lists/* + +# משוך את ה-binary של agenteye-collector מהתמונה הרשמית. +# קבע תג ספציפי (:beta-latest עבור beta נוכחיות, או תג :v); +# :latest פורסם רק עבור שחרורים יציבים. +COPY --from=ghcr.io/agenteye-enterprise/collector:beta-latest \ + /usr/local/bin/agenteye-collector /usr/local/bin/agenteye-collector + +COPY supervisord.conf /etc/supervisor/conf.d/agenteye.conf +COPY my_agent.py /app/my_agent.py + +CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"] +``` + +**`supervisord.conf`:** + +```ini +[supervisord] +nodaemon=true +user=root + +[program:agenteye-collector] +command=/usr/local/bin/agenteye-collector start +autorestart=true +stopwaitsecs=30 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:app] +command=python /app/my_agent.py +autorestart=unexpected +stopwaitsecs=30 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +``` + +למה הגדרות אלה: + +- `autorestart=true` על agenteye-collector: הפעל מחדש בכל יציאה (crash, panic, OOM). +- `autorestart=unexpected` על האפליקציה: הפעל מחדש רק בעלייה שאינה אפסית, אז סוכן חד פעמי שיוצא 0 לא לולאה. +- `stopwaitsecs=30`: נותן לה-collector מקום לניקוז עלאות תלויות על SIGTERM לפני שה-supervisord מעלה ל-SIGKILL. +- `stdout_logfile=/dev/stdout`, `*_maxbytes=0`: זרם את הפלט של שני התוכניות ל-container stdout; אין קבצי יומן בתוך ה-container. + +עבור `docker run -e` אמור `AGENTEYE_URL` / `AGENTEYE_KEY` (וכל משתני TLS env) כבעבר; supervisord יורש את הסביבה. + +> **מיכלים נפרדים?** אם אתה מפעיל את ה-collector כמיכל משלו (שירות Docker Compose, sidecar של Kubernetes וכו'), אל תשתמש ב-supervisord; מדיניות ההפעלה מחדש של זמן ריצה של ה-container כבר עושה עבודה זו. ראה [enterprise-docs/single-pod-deployment.md](/he/agenteye/single-pod-deployment) לדפוס ה-sidecar של EKS. + +**בדיקת בריאות ב-Kubernetes** (חל בין אם ה-collector פועל לבדו או תחת supervisord): + +```yaml +livenessProbe: + exec: + command: ["agenteye-collector", "health"] + initialDelaySeconds: 10 + periodSeconds: 30 +``` + +ה-daemon הפועל כותב heartbeat ל-`$AGENTEYE_HOME/health.json` כל 30 שניות. `agenteye-collector health` קורא את הקובץ הזה ויוצא `0` (בריא) רק כאשר ה-heartbeat טרי ותפקידי ההעלאה פועלים כרגיל; זה יוצא `1` (לא בריא) כאשר ה-heartbeat ישן יותר מ-90 שניות (למשל, ה-daemon התחיל) או בזמן שה-watcher וה-sweeper מתחילים מחדש לאחר יציאה בלתי צפויה. ה-heartbeat נכתב רק על ידי `start`, אז הפעל את הבדיקה נגד ה-daemon ארוך הטווח ולא את הפקודה `flush` של חד פעמי. + +### systemd (Linux, מומלץ לייצור) + +```ini +# /etc/systemd/system/agenteye-collector.service +[Unit] +Description=AgentEye Collector +After=network.target + +[Service] +ExecStart=/usr/local/bin/agenteye-collector start +Restart=on-failure +RestartSec=5 +EnvironmentFile=/etc/agenteye/env + +[Install] +WantedBy=multi-user.target +``` + +צור `/etc/agenteye/env`: + +``` +AGENTEYE_URL=https://ingest.example.com/events +AGENTEYE_KEY=YOUR_COLLECTOR_KEY +``` + +```bash +sudo systemctl daemon-reload +sudo systemctl enable --now agenteye-collector +sudo systemctl status agenteye-collector +``` + +### launchd (macOS) + +```xml + + + + + + Label + ai.befailproof.agenteye-collector + ProgramArguments + + /usr/local/bin/agenteye-collector + start + + EnvironmentVariables + + AGENTEYE_URL + https://ingest.example.com/events + AGENTEYE_KEY + YOUR_COLLECTOR_KEY + + RunAtLoad + + KeepAlive + + + +``` + +```bash +launchctl load ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +``` + +--- + +## שדרוג ה-Collector + +ה-collector לא מעדכן את עצמו. כדי לשדרג: + +- **Binary:** הורד את ה-artifact החדש `agenteye-collector--` מהשחרור `collector/v` האחרון (ראה [אפשרות A](#option-a-binary-recommended)), החלף `/usr/local/bin/agenteye-collector`, ואז הפעל מחדש את השירות (`sudo systemctl restart agenteye-collector`, re-`launchctl load`, או הפעל מחדש את ה-supervisor). +- **Docker:** `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (או תג `:v` קבוע; `:latest` קיים רק עבור שחרורים יציבים) ובנה מחדש את ה-container. + +`AGENTEYE_TOKEN` נדרש להורדת binary/image חדשים מריפו releases פרטי, אך **לא** נדרש על ידי ה-daemon הפועל. + +--- + +## Subcommands + +| פקודה | תיאור | +|---|---| +| `agenteye-collector start` | התחל את ה-daemon ארוך הטווח. בהפעלה זה משפשף אירועים שנותרו מהרצה קודמת, ואז מראיין קבצים חדשים ומעלה אותם. ה-watcher וה-sweeper מתחילים מחדש באופן אוטומטי בעלייה בלתי צפויה, וה-heartbeat נכתב ל-`health.json` כל 30 שניות. | +| `agenteye-collector flush` | חד פעמי: העלה את כל הקבצים התלויים ויצא. מדפיס `No pending files.` כאשר ה-spool ריק, אחרת רישום לכל קובץ `[UPLOADED]`/`[FAILED]` וסיכום `Done: / uploaded, failed.`. | +| `agenteye-collector health` | קרא את ה-heartbeat של `health.json` של ה-daemon. יצא `0` כאשר טרי ובריא; יצא `1` כאשר ה-heartbeat הוא מיושן (ישן יותר מ-90 שניות) או התפקידים מתחילים מחדש. | + +--- + +## פריסת ספרייה + +``` +~/.agenteye/ +├── config.json <- קובץ תצורה אופציונלי +├── events/ <- קבצי .jsonl שנכתבו על ידי SDK, בחרו על ידי ה-collector +└── failed/ <- קבצים שנכשלו כל ניסיונות העלאה +``` + +קבצים ב-`failed/` לא מנסו שוב באופן אוטומטי. כדי להכניס אותם לתור שוב באופן ידני, הזז אותם חזרה ל-`events/` והפעל `agenteye-collector flush`. \ No newline at end of file diff --git a/docs/he/agenteye/collector-migration.mdx b/docs/he/agenteye/collector-migration.mdx new file mode 100644 index 00000000..662f5f4a --- /dev/null +++ b/docs/he/agenteye/collector-migration.mdx @@ -0,0 +1,169 @@ +--- +title: "עברה ל-`agenteye-collector`" +description: "תיעוד AgentEye על עברה ל-`agenteye-collector`." +--- + + +העברה היא לא הרסנית: היא לא גורמת לשום זמן שבות ולא לאובדן נתונים, והיא משחררת את השם הקצר `agenteye` ל-[AgentEye CLI](/he/agenteye/cli) כך שדמון המאספן ו-CLI יכולים להתקיים באותה מכונה. + +קובץ המאספן קיבל **שינוי שם מ-`agenteye` ל-`agenteye-collector`**. השם הקצר `agenteye` שייך כעת ל-AgentEye CLI, כלי נפרד לשאילתות על הפעלות, אירועים והערכות מהטרמינל שלך. + +המדריך הזה מובילך דרך עברה של התקנה קיימת של מאספן. + +--- + +## מה השתנה + +| | לפני | אחרי | +|---|---|---| +| פקודה / קובץ בינארי | `agenteye` | `agenteye-collector` | +| נתיב התקנה ברירת מחדל | `/usr/local/bin/agenteye` | `/usr/local/bin/agenteye-collector` | +| תת-פקודות | `start`, `flush`, `health`, `update` | `start`, `flush`, `health` | +| עדכון עצמי (`agenteye update`) | מובנה | **הוסר**: הורד את הקובץ הבינארי החדש או שלוף את התמונה החדשה | +| סקריפט התקנה (`install.sh`) | מסופק | **הוסר**: הורד את הקובץ הבינארי ישירות (ראה [התקנה של מאספן](/he/agenteye/collector-installation)) | +| `AGENTEYE_TOKEN` | נדרש להורדה **וגם** לבדיקות עדכון בחזקה | נדרש רק להורדה של קבצים בינאריים/תמונות | + +התצורה לא השתנתה: אותו `~/.agenteye/config.json`, אותם משתני סביבה `AGENTEYE_URL` / `AGENTEYE_KEY` / `AGENTEYE_HOME` / TLS, ואותה ספול `~/.agenteye/events/`. **לא נדרש שום שינוי בתצורה.** + +> אם אתה מריץ את הקובץ הבינארי שחויה שמו תחת השם הישן `agenteye`, הוא עדיין עובד אך מדפיס הודעת התיחסות אל שורה אחת ל-stderr שמזכירה לך להחליף ל-`agenteye-collector`. + +--- + +## לפני שתתחיל + +- **ההתקנה הקיימת שלך של `agenteye` ממשיכה לרוץ**; שום דבר לא נשבר ברגע שאתה משדרג. בצע עברה בתחשבנות, ואחר כך הסר את הקובץ הבינארי הישן בסוף. +- עקוב אחר הסדר הזה כדי להימנע מזמן שבות: + 1. התקן את הקובץ הבינארי החדש `agenteye-collector` (או שלוף את התמונה החדשה). + 2. עדכן את הגדרת השירות / בדיקת הבריאות / סקריפטים שלך כדי לקרוא ל-`agenteye-collector`. + 3. טען מחדש והפעל מחדש את השירות; אשר שהוא בריא. + 4. **רק אז** הסר את קובץ הבינארי הישן `/usr/local/bin/agenteye`. + +--- + +## 1. התקן את הקובץ הבינארי החדש + +הורד את התוצר עבור הפלטפורמה שלך (`agenteye-collector-linux-x86_64`, `agenteye-collector-darwin-arm64`, וכו'; ראה [התקנה של מאספן → אפשרות A](/he/agenteye/collector-installation#option-a-binary-recommended) לרשימה המלאה) מהרלease `collector/v` האחרון והנח אותו ב-`/usr/local/bin/agenteye-collector`. משתמשי Docker: `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (או תג `:v` משוכלל, שהוא מועדף; `:latest` קיים רק לרלישים יציבים). + +אשר: + +```bash +agenteye-collector --version +``` + +--- + +## 2. עדכן את הפריסה שלך + +### systemd (Linux) + +ערוך `/etc/systemd/system/agenteye-collector.service` כך ש-`ExecStart` יצביע על הקובץ הבינארי החדש: + +```ini +[Service] +ExecStart=/usr/local/bin/agenteye-collector start +``` + +לאחר מכן טען מחדש והפעל מחדש: + +```bash +sudo systemctl daemon-reload +sudo systemctl restart agenteye-collector +sudo systemctl status agenteye-collector +``` + +### launchd (macOS) + +> **שינוי שם ברנד:** אם ה-plist הקיים שלך נמצא בנתיב הישן +> `~/Library/LaunchAgents/host.exosphere.agenteye-collector.plist`, שנה +> שם של קובץ ל-`ai.befailproof.agenteye-collector.plist` וגם שנה +> את ערך `Label` בתוך הקובץ למזהה החדש לפני +> טעינה מחדש. + +ב-`~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist`, שנה את ערך `ProgramArguments` הראשון מ-`/usr/local/bin/agenteye` ל-`/usr/local/bin/agenteye-collector`, ואז טען: + +```bash +launchctl unload ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +launchctl load ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +``` + +### supervisord + +בחסימת התוכנית `supervisord` שלך, הגדר את `command` לקובץ הבינארי החדש: + +```ini +[program:agenteye-collector] +command=/usr/local/bin/agenteye-collector start +``` + +לאחר מכן `supervisorctl reread && supervisorctl update`. + +### Docker / Kubernetes + +שלוף את התמונה החדשה (`ghcr.io/agenteye-enterprise/collector:beta-latest` או תג `:v` משוכלל, שהוא מועדף; `:latest` קיים רק לרלישים יציבים). נקודת הכניסה של התמונה כבר `agenteye-collector`, אז אותה פקודת `docker run` עם תת-הפקודה `start` ממשיכה לעבוד ללא שינוי. + +**חשוב: עדכן בדיקות בריאות.** אם אתה משתמש בבדיקת Kubernetes liveness/readiness (או כל `docker exec`) שמריצה את הקובץ הבינארי לפי שם, שנה את הפקודה ל-`agenteye-collector`: + +```yaml +livenessProbe: + exec: + command: ["agenteye-collector", "health"] +``` + +התמונה החדשה **לא** משלחת כינוי `agenteye`, אז בדיקה שעדיין קוראת ל-`agenteye` תכשל. עדכן את הבדיקה באותו rollout כמו התמונה החדשה. + +### Cron / סקריפטים ידניים + +החלף כל בקרו של `agenteye start|flush|health` בפקודה המתאימה של `agenteye-collector start|flush|health`. **מחק כל עבודות cron של `agenteye update`**; תת-פקודה זו כבר לא קיימת (ראה [שדרוגים מעכשיו והלאה](#upgrades-from-now-on)). + +--- + +## 3. הסר את הקובץ הבינארי הישן (בסוף) + +ברגע שהשירות רץ על `agenteye-collector` ודיווח בריא: + +```bash +sudo rm /usr/local/bin/agenteye +``` + +זה חשוב במיוחד אם אתה גם משתמש ב-AgentEye CLI, שמתקין את הפקודה `agenteye` שלו; השארת קובץ המאספן הישן ב-`/usr/local/bin/agenteye` תעשה את שם `agenteye` דו-משמעי ב-`PATH` שלך. + +--- + +## שדרוגים מעכשיו והלאה + +המאספן כבר לא מעדכן את עצמו. כדי לשדרג: + +- **קובץ בינארי:** הורד את התוצר החדש עבור הפלטפורמה שלך (לדוגמה `agenteye-collector-linux-x86_64`; ראה [התקנה של מאספן → אפשרות A](/he/agenteye/collector-installation#option-a-binary-recommended) לרשימה המלאה), החלף את `/usr/local/bin/agenteye-collector`, והפעל מחדש את השירות. +- **Docker:** `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (או תג `:v` משוכלל, שהוא מועדף; `:latest` קיים רק לרלישים יציבים) ובנה מחדש את הקונטיינר. + +`AGENTEYE_TOKEN` עדיין נדרש להורדה מאחסן ה-releases הפרטי, אך דמון ריצה כבר לא צריך אותו. + +--- + +## אשר + +```bash +agenteye-collector --version # קובץ בינארי חדש ב-PATH +agenteye-collector health # exit 0 = בריא +agenteye-collector flush # העברת כל אירועים בתור וצא בנקיות +``` + +לאחר מכן אשר שאירועים חדשים מופיעים בדוח הנתונים שלך. + +--- + +## חזרה לאחור + +העברה היא לא הרסנית. אם אתה צריך להחזור לאחור, הצביע את הגדרת השירות שלך חזרה לקובץ הבינארי הישן `/usr/local/bin/agenteye` (כל עוד לא הסרת אותו עדיין) והפעל מחדש. ספול האירועים והתצורה משותפים ולא מושפעים. + +--- + +## פתרון בעיות + +| סימפטום | סיבה | תיקייה | +|---|---|---| +| `warning: the collector binary is now agenteye-collector …` בכל הרצה | אתה משדר את הקובץ הבינארי תחת השם הישן `agenteye` | קרא ל-`agenteye-collector` במקום זאת; עדכן קבצי שירות וסקריפטים. | +| systemd נכשל: `.../agenteye: No such file or directory` | הסרת את הקובץ הבינארי הישן לפני עדכון `ExecStart` | הגדר `ExecStart=/usr/local/bin/agenteye-collector start`, ואז `sudo systemctl daemon-reload`. | +| Pod של Kubernetes נכנס ללולאות קריסה אחרי שדרוג התמונה | בדיקת liveness עדיין מריצה `agenteye` | שנה את פקודת הבדיקה ל-`["agenteye-collector", "health"]`. | +| `agenteye: command not found`, אבל `agenteye-collector` עובד | סקריפטים/כינויים עדיין מתייחסים לשם הישן | עדכן אותם ל-`agenteye-collector`. | +| הרצת `agenteye` מתחילה את ה-CLI, לא את המאספן | אתה בעל AgentEye CLI מותקן; הוא בעלי `agenteye` | השתמש ב-`agenteye-collector` עבור דמון והסר כל קובץ בינארי מאספן ישן שנותר ב-`/usr/local/bin/agenteye`. | \ No newline at end of file diff --git a/docs/he/agenteye/deployment.mdx b/docs/he/agenteye/deployment.mdx new file mode 100644 index 00000000..b9c62af7 --- /dev/null +++ b/docs/he/agenteye/deployment.mdx @@ -0,0 +1,400 @@ +--- +--- +title: "פריסה" +description: "תיעוד פריסה של AgentEye." +--- + + +מדריך זה מכסה את פריסת שרת AgentEye ולוח המחוונים בייצור. + +--- + +## סקירת ארכיטקטורה + +``` + [ AI agent machines ] [ Your infrastructure ] + + Python SDK + | writes JSONL +----------------------+ + v +--->| PostgreSQL 15+ | + agenteye-collector --HTTP--+ | | (relational store) | + | | +----------------------+ + v | + +--------+ | +----------------------+ + | Server |<------+--->| ClickHouse 24+ | + +--------+ | | (events / analytics) | + ^ | +----------------------+ + API | | + | | +----------------------+ + +-----------+ +- - >| Redis 7+ (optional) | + | Dashboard | +----------------------+ + +-----------+ +``` + +- **Server**: שירות HTTP ב-Rust; מקבל אצווות של אירועים, כותב אותם ל-ClickHouse ומשמר מצב יחסי ב-PostgreSQL. +- **Dashboard**: אפליקציית Next.js; קוראת וכותבת אך ורק דרך ה-API של השרת. +- **agenteye-collector**: מפורסת על מכונות ה-agent, לא על הוסט של השרת. +- **Postgres 15+**: נדרש. (הועלה מ-14 בהוצאה מולטי-דיירנית; סכמת החברות בארגון משתמשת בעמודה-רשימה `ON DELETE SET NULL` במפתח חוץ, המצריך Postgres 15+. שדרגו את Postgres לפני פריסה של גרסה זו.) מאחסן מצב OLTP: `api_keys`, `users`, `sessions`, `evaluation_jobs` (תור), `dashboards`, `saved_queries`, `otp_codes`, בתוספת הטבלאות מולטי-דיירניות `orgs`, `org_memberships`, `org_settings`. +- **ClickHouse 24+**: נדרש. חנות הניתוחים עבור כל אירוע שהוזן. Engine: `ReplacingMergeTree`, מחולק לפי חודש, מסודר לפי `(session_id, ts, dedup_key)`. השרת מתחבר דרך `CLICKHOUSE_URL`; התיקייה המרוכזת `deploy/base/clickhouse/` מספקת תצורה בעלת ביצועים מכוונת של צומת יחיד. **דרישת מולטי-דיירנית:** התיקייה המרוכזת מאפשרת ניהול גישה SQL + `users_without_row_policies_can_read_rows=false` כך שהשרת יכול ליצור משתמש ClickHouse בקריאה בלבד + מדיניות שורה אחת לכל ארגון (גבול בידוד כפוי-engine של עורך SQL וה-AI agent). אם אתה מספק תצורת ClickHouse משלך, העבר הגדרות אלה (ראה `deploy/base/clickhouse/configmap.yaml`). +- **Redis 7+**: *אופציונלי* חסומה משותפת + תשתית קצב-הגבלה. שרת ודשבורד מתחברים שניהם דרך `REDIS_URL`. אם חסר, שניהם מתדרדרים בחן בטוב ללבד דרכים ללא Postgres. ראה **Redis (אופציונלי חסומה)** להלן. + +--- + +## שרת + +### שלוף את התמונה + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +docker pull ghcr.io/agenteye-enterprise/server:beta-latest +``` + +> בנייה נוכחית מפרסמת תחת `beta-latest`; `latest` מוקצה רק לשחרורים יציבים. לייצור, צמד לתגית `:v` ספציפית; ראה [תגיות תמונה זמינות](#available-image-tags). + +### משתנים סביבה + +| משתנה | נדרש | ברירת מחדל | תיאור | +|---|---|---|---| +| `DATABASE_URL` | כן | בלא | Postgres DSN. מחרוזת חיבור libpq סטנדרטית עם סכמה `postgres://`. תומך ב-`?sslmode=require` ופרמטרים libpq אחרים. הסיסמה לא חייבת להכיל `/`, `+`, או `=`; השתמש ב-`openssl rand -hex` ליצירת סיסמאות בטוחות-URL. | +| `ADMIN_KEY` | לא | בלא | מפתח API admin bootstrap. Upserted עם כל ההרשאות בכל הפעלה. סיבוב על ידי שינוי הערך והפעלה מחדש. | +| `LISTEN_ADDR` | לא | `0.0.0.0:8080` | כתובת TCP להתחברות | +| `MAX_BODY_BYTES` | לא | `134217728` (128 MB) | גודל גוף בקשה מרבי | +| `ADMIN_EMAIL` | לא | בלא | כתובת דוא"ל של משתמש admin bootstrap. Upserted עם כל ההרשאות בכל הפעלה וסימן מוגן: אינו יכול להיות מוגבל או שיש הרשאות שונות דרך הדשבורד/API. לסיבוב ה-admin bootstrap, שנה את `ADMIN_EMAIL` והפעל מחדש; הדוא"ל החדש מוטמע כמוגן, וקודם שימור ההגנה שלו עד לניקוי ידני בבסיס הנתונים. | +| `ALLOWED_EMAILS` | לא | בלא (כל חסום) | רשימה מופרדת בפסיקים של דוא"לים מורשים ליצירה וכניסה של משתמש. תומך בכתובות מדויקות (`user@example.com`) ותמיכה בתחום בתחום (`*@example.com`). אם לא מוגדר, לא ניתן ליצור משתמשים או להיכנס. **זרע ברגל ראשונה בלבד**: זורעת את רשימת ההכחה של ארגון ברירת המחדל בהפעלה ראשונה; לאחר מכן, כל ארגון [`//settings`](#operational-settings) עמוד הוא מקור האמת וחוקים בעריכה של משתנה env זה אין השפעה. | +| `SMTP_HOST` | לא | בלא | שם הוסט של שרת SMTP לשליחת דוא"ל OTP. אם לא מוגדר, קודי OTP מוקלטים ל-stdout. | +| `SMTP_PORT` | לא | `587` | יציאת שרת SMTP | +| `SMTP_USERNAME` | לא | בלא | שם משתמש אימות SMTP | +| `SMTP_PASSWORD` | לא | בלא | סיסמת אימות SMTP | +| `SMTP_FROM` | לא | בלא | כתובת דוא"ל שולח לדוא"ל OTP | +| `SMTP_TLS` | לא | STARTTLS | STARTTLS משמש אלא אם כן תוציא זאת במפורש: `false` או `0` שולח טקסט רגול (ללא TLS); כל ערך אחר — לרבות לא מוגדר — מאפשר STARTTLS. | +| `DASHBOARD_URL` | לא | ברירת מחדל מובנית | מקור דשבורד המשמש לבנייה גם הקישור הקסום של דוא"ל OTP וגם קישורי השיוך בהודעות התראה. אם לא מוגדר, זה חוזר לברירת מחדל מובנית (ו, ל-OTP בלבד, למקור דשבורד-נגזר לבקשה). קבע זאת לרכיבי תחום מפוצלים כך שקישורים בדוא"ל וSlack/incident יוצבעו בדשבורד שלך. ראה **כתובת קישור קסום של דוא"ל** להלן; מפעילים רובים לא צריכים להגדיר זאת. | +| `SESSION_TTL_SECS` | לא | `86400` (24 שעות) | משך סשן דשבורד בשניות. **זרע ברגל ראשונה בלבד**: עדכן לכל ארגון דרך [`//settings`](#operational-settings) לאחר פריסה ראשונה. | +| `OTP_TTL_SECS` | לא | `600` (10 דק') | תקופת תוקף קוד OTP בשניות. **זרע ברגל ראשונה בלבד**: עדכן לכל ארגון דרך [`//settings`](#operational-settings) לאחר פריסה ראשונה. | +| `REDIS_URL` | לא | בלא | תשתית חסומה משותפת + קצב-הגבלה, למשל `redis://redis:6379/0`. כאשר מוגדר, השרת משימר בחסומה פקודות API-key מאומתות, סיכומי דשבורד `/models`, רשימת סשנים, ופן רשימה סביבה; הוא גם מעביר קצב OTP מ-Postgres COUNT ל-Redis INCR. אם לא מוגדר או לא זמין, השרת פועל ללא החסומה (קצב OTP חוזר ל-Postgres, כל קריאת חסומה אחרת חוזרת למקור האמת). ראה **Redis (אופציונלי חסומה)** להלן. | +| `CLICKHOUSE_URL` | **כן** | בלא | כתובת URL בסיסית של מופע ClickHouse, למשל `http://clickhouse:8123`. השרת יישם את סכמת האירועים שלו למסד נתונים זה בכל התחלה ויסרב להתחיל אם לא יוכל להגיע ל-ClickHouse. ראה **ClickHouse (חנות ניתוחים נדרשת)** להלן. | +| `CLICKHOUSE_DATABASE` | לא | `agenteye` | שם בסיס הנתונים ClickHouse (סכמה). השרת יוצר אותו בהתחלה אם הוא לא קיים. | +| `ORG_CH_SECRET` | לא (יחיד-דיירני) / **כן (מולטי-ארגון)** | ברירת מחדל פיתוח | מפתח HMAC שממנו נגזר סיסמת ClickHouse ייחודית לדיירן של כל ארגון. עורך ה-SQL וה-`run_query` של ה-AI agent מתבצעים כמשתמש ClickHouse בקריאה-בלבד של הארגון, שמדיניות השורה שלו כוחה בידוד דיירני בתוך Engine. פריסות יחיד-דיירניות התחילו כמו נעימה על ברירת המחדל של פיתוח המובנית; **לפני אספקת ארגון שני חייב להגדיר ערך חזק וקבוע**, כי הCLI `agenteye-orgctl org create` מסרב לרוץ על ברירת המחדל של פיתוח המובנית. סיבוב משאיר כל משתמש ClickHouse של ארגון יתום עד להתחלה הבאה לספק מחדש אותם (החוקק הזמן-התחלה מרפא זאת באופן אוטומטי). שמור זאת בסוד ולא שונה על פני משכפלות. פרוביזיה ארגון עצמו היא אופרטור-בלבד; ראה **ארגונים (מולטי-דיירנות)** להלן. | +| `DEFAULT_ORG_NAME` | לא | `Default` | שם תצוגה זרוע לארגון ברירת המחדל המובנה. **זרע ברגל ראשונה בלבד**, ורק בזמן שהארגון עדיין נושא את הזהות הגנרית שלו זה עתה הנדידה, יושם בהתחלה, ואז התעלם. לאחר שינוי שם הארגון (`agenteye-orgctl org rename`) השם הוא סמכות ולא עוד לעדכן משתנה env זה. | +| `DEFAULT_ORG_SLUG` | לא | `default` | תיבת URL לארגון ברירת המחדל המובנה, נתיב הדשבורד שהוא חי בו (`//…`). אותה דינמיקה ברגל ראשונה בלבד / טהור בלבד כמו `DEFAULT_ORG_NAME`. חייב להיות 1-40 אלפא-ספרות קטנות עם מקפים פנימיים יחידים ולא [מילה שמורה](#organizations-multi-tenancy); ערך לא חוקי מתעלם (הארגון שומר `default`). מאפשר התקנה יחיד-דיירנית לייצג כ-`/acme` במקום `/default` ללא שום שלב post-deploy CLI. | +| `RUST_LOG` | לא | `info` | קיבוץ יומן (`debug`, `warn`, `error`, `agenteye_server=trace`) | +| `EVALUATOR_ENDPOINT` | לא | בלא | כתובת URL בסיסית של שירות ה-evaluator שלך (למשל `http://evaluator:9000`). כאשר לא מוגדר כל צינור הערכה הוא no-op; שום שורות תור לא כתובות, אין עובדים מריצים. ראה [חדר הערכה](/he/agenteye/evaluation-suite). | +| `EVALUATOR_TOKEN` | לא | בלא | נשלח בתור `Authorization: Bearer ` ל-evaluator. **חייב להיות שווה לאותו ערך שהערכה משוערך מוגדרת עם.** אופציונלי רק אם הערכה מוגדרת ללא token. | +| `EVALUATOR_WORKERS` | לא | `2` | קונקור: מספר משימות עובד לכל מופע שרת המשדרות הערכות. בטוח לרוץ על שרתים בקנה-מידה אופקי מרובים. | +| `EVALUATOR_CLAIM_BATCH` | לא | `4` | מספר הערכות מרבי שעובד יחיד תובע לכל תופעה. אצווות משודרות **בו-זמנית**, כך שקונקור כללי על endpoint evaluator שלך הוא `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH`. | +| `EVALUATOR_POLL_IDLE_SECS` | לא | `2` | כמה זמן עובד ישן בין ניסיונות שיגור כאשר כלום אינו בא. | +| `EVALUATOR_POLLING_INTERVAL_SECS` | לא | `10` | קדנס choke-back סופי (שניות) לעדכונים `GET /evaluate/{id}` כאשר המעריך אינו חוזר `next_poll_secs` לכל התגובה ואינו מפרסם `default_poll_interval_secs` מ `GET /config`. | +| `EVALUATOR_REQUEST_TIMEOUT_MS` | לא | `30000` | עדכון לכל בקשת HTTP כנגד המעריך (אלפית השניה). | +| `EVALUATOR_MAX_ATTEMPTS` | לא | `5` | לאחר הרבה ניסיונות כושלים כל כך הערכה מוקלטת כטרמינל `error` (או `timeout` אם הכשלות היו בקשה timeout). | +| `EVALUATOR_CONFIG_REFRESH_SECS` | לא | `300` (5 דק') | כמה פעמים השרת re-fetches `GET /config` מ-evaluator. | +| `EVALUATOR_MAX_POLL_DURATION_SECS` | לא | `3600` (1 h) | זמן wallclock מרבי סשן עשוי להישאר בתור סקר לפני AgentEye מסיים אותו כ-`timeout`. משמרות נגד evaluator שחוזר `pending` לעד. | +| `ALERT_WORKERS` | לא | `1` | קונקור: מספר משימות עובד לכל מופע שרת המעריכות כללי התראה. ראה [התראות](/he/agenteye/alerts). | +| `ALERT_CLAIM_BATCH` | לא | `16` | מספר התראות מרבי עובד יחיד תובע לכל תופעה. | +| `ALERT_POLL_IDLE_SECS` | לא | `5` | כמה זמן עובד התראות ישן כאשר התור ריק. | +| `ALERT_REQUEST_TIMEOUT_MS` | לא | `15000` | עדכון הערכה להדלקת (ClickHouse queries + HTTP ערוץ יוצא). | +| `ALERT_MAX_ATTEMPTS` | לא | `5` | כשלים חולפים עוקבים לפני התראה משדרים בקדנס רגיל במקום backoff אקספוננציאלי. | +| `AUDIT_WORKERS` | לא | `1` | קונקור: מספר משימות עובד לכל מופע שרת המבצעות ביקורות. ראה [ביקורות](/he/agenteye/audits). | +| `AUDIT_CLAIM_BATCH` | לא | `1` | מספר מקסימום ביקורות בעבודה עובד יחיד תובע לכל תופעה. חקירה agentic היא לולאה ארוכה אחת, כך שברירת המחדל היא 1. | +| `AUDIT_POLL_IDLE_SECS` | לא | `30` | כמה זמן עובד ביקורות ישן כאשר אין ביקורת בעבודה. | +| `AUDIT_REQUEST_TIMEOUT_MS` | לא | `30000` | עדכון ממנו-query לכל-מדיניות נגד ClickHouse (אלפית השניה). | +| `AUDIT_LLM_TIMEOUT_MS` | לא | `1440000` | timeout לשיחה חקירה agentic עם שירות AI assistant. לולאת agent שלמה פועלת לדקות; שמור זאת למעלה מ-`AGENTEYE_AUDIT_TIMEOUT_MS` שלו agent כך ש-agent חוזר ממצאים חלקיים לפני השרת מתוך זמן. | +| `AUDIT_MAX_ATTEMPTS` | לא | `5` | כשלים חולפים עוקבים לפני ביקורת משדרות בקדנס רגיל במקום backoff אקספוננציאלי. | +| `AGENTEYE_AGENT_URL` / `AGENTEYE_AGENT_TOKEN` | לא | — | חקירה agentic של ביקורת קורא שירות AI-assistant `agent`, **למעשה הקשר זהה כ-assistant** — כך הגדר את שני אלה גם על ה-**server** (המשכפלות המרוכזות/רכיבי לבוש עושים). שתי קבוצות ⇒ ביקורות פעולות חקירה AI; אחד לא מוגדר ⇒ ביקורות פעולות **policy-only** (מעבר מדיניות דטרמיניסטי SQL עדיין פועל), ללא קשר לדגל לכל ביקורת `llm_enabled`. ה-agent חייב גם LLM מוגדר — ראה [assistant.md](/he/agenteye/assistant). | + +**שירות AI assistant — הגדרות ביקורת + sandbox.** החקירה agentic וה-Python sandbox שלה בתוך-pod עדכון על ה-**agent service** (לא השרת), הכל על `AGENTEYE_AUDIT_*` prefix וכל אופציונלי: + +| משתנה | ברירת מחדל | משמעות | +|---|---|---| +| `AGENTEYE_AUDIT_MAX_STEPS` | `200` | מקס סיבוב agent לכל חקירה. | +| `AGENTEYE_AUDIT_TIMEOUT_MS` | `1200000` | wallclock לחקירה אחת (20 דק'). חייב להישאר **למעלה** מ-`AUDIT_LLM_TIMEOUT_MS` שלו שרת. | +| `AGENTEYE_AUDIT_MAX_CONCURRENCY` | `1` | חקירות בו-זמניות לכל pod agent (בנפרד מהתקציב של chat assistant). | +| `AGENTEYE_AUDIT_SANDBOX_TIMEOUT_MS` / `_MEM_MB` / `_CPU_SECS` / `_OUTPUT_MAX_BYTES` / `_SCRIPT_MAX_BYTES` | `20000` / `768` / `10` / `64000` / `64000` | גבולות לכל-סקריפט לכל bubblewrap sandbox. | + +**דרישת פלטפורמת Sandbox.** קוד ביקורת sandbox פעולה בתוך Python של דוגמן בתוך כלא bubblewrap, אשר זקוק **משתמש לא חיזוק user namespaces**. pod ה-agent חייב לאפשר את `clone()` flags — הגדר `seccompProfile: Unconfined` (k8s) או `security_opt: [seccomp:unconfined]` (compose) על agent. כאשר kernel של צומת משבית user namespaces לא-חיזוק (למשל כמה GKE COS images), ה-sandbox **preflight נכשל ו-auditor משדרות SQL-בלבד באופן אוטומטי** — אין שגיאה, פשוט `sandbox_available: false` על `/health` של agent. | + +### הפעל + +הגדר `DATABASE_URL` ו-`CLICKHOUSE_URL` בסביבתך (השרת מסרב להתחיל ללא ClickHouse), ואז תמסור אותם דרך לכלי: + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-server \ + -e DATABASE_URL="$DATABASE_URL" \ + -e CLICKHOUSE_URL="$CLICKHOUSE_URL" \ + -e ADMIN_KEY="$ADMIN_KEY" \ + -p 8080:8080 \ + ghcr.io/agenteye-enterprise/server:beta-latest +``` + +השרת משמיע הגדרות בסיס נתונים באופן אוטומטי בהתחלה; שום שלב הגדרה נפרד נחוץ. + +### בדיקת בריאות + +``` +GET /health # liveness - תמיד {"status":"ok"} לאחר שהתהליך פועל +GET /ready # readiness - 200 כאשר Postgres + ClickHouse הם זמינים, אחרת 503 +``` + +אין דרישה לאימות. השתמש ב-`/health` לסיקור **liveness** ו-`/ready` לסיקורי **readiness** / load-balancer. `/ready` בדיקות התלויות הקשות שהשרת לא יכול לשרת ללא (Postgres + ClickHouse), כך שכלי שפועל אך אינו יכול להגיע לבסיס הנתונים שלו מוצא מתוך סיבוב ומציג כ-`NotReady`; Redis דיווח אך לעולם נכשל readiness. על המניפסטים המרוכזים של Kubernetes הסיקור readiness כבר מוצבע ב-`/ready` ו-liveness נשאר ב-`/health`. ראה [enterprise-docs/health-monitoring.md](/he/agenteye/health-monitoring) לתמונה המוקדמת, כולל opt-in Kubernetes-native pod-failure התראה ל-Slack. + +### כתובת קישור קסום של דוא"ל + +דוא"לי התחברות OTP מכילים כפתור **פתח דשבורד** חד-הקשה. לחיצה עליו מנחתת את המשתמש על `/login?token=&email=
`; הדשבורד מחליף צמד זה לסשן וחוזר אל האפליקציה, ללא הזנת קוד ידנית חוזרת. השרת פותר מקור הדשבורד המשמש לבנייה הקישור בשלוש רמות: + +1. **`X-AgentEye-Dashboard-Url` header**: הגדר באופן אוטומטי על ידי proxy `/api/auth/otp/request` של הדשבורד מהמקור הציבורי שלו. בפריסה same-origin (שרת ודשבורד שיתוף בעל אחד מאחורי ערסל אחד המעביר headers proxy), **אין תצורה נדרשת**. +2. **`DASHBOARD_URL` env var**: הגדר זאת אם הדשבורד שלך זמין על מקור שונה מה-origin שנקודת בקשת OTP של השרת רואה (split `api.example.com` / `app.example.com`), או אם ערסל שלך אינו הפוץ את host הציבורי לתוך pod הדשבורד (כך `request.nextUrl.origin` אחרת יפתור עדכון כגון `0.0.0.0:3000`). דוגמה: `DASHBOARD_URL=https://app.example.com`. +3. **ברירת מחדל**: `https://app.befailproof.ai`, בשימוש רק אם לא אחד משנייהם לעיל קיים. + +ערך header מאומת: רק `https://*` ו-loopback (`http://localhost*`, `http://127.0.0.1*`) מקורות מקובלים, וכתובות bind wildcard (`0.0.0.0`, `[::]`) נדחות אפילו עם ה-`https://` סכמה. כל דבר אחר חוזר אל רמה 2. + +הגדר זאת על אשכול פועל עם one-liner; לא קובץ, לא rebuild kustomize: + +```bash +kubectl set env deployment/server -n agenteye \ + DASHBOARD_URL=https://app.example.com +``` + +זה מעלה rollout; pod החדש בוחר את הערך בבקשה ראשונה. שימו לב כי override חי רק על Deployment; `kustomize build | kubectl apply` לאחר כך כנגד overlay ימחק אותו אלא אם כן הוספת משתנה env זהה לתיקייה patch `server-env.yaml` של overlay שלך. + +--- + +## דשבורד + +### שלוף את התמונה + +```bash +docker pull ghcr.io/agenteye-enterprise/dashboard:beta-latest +``` + +### משתנים סביבה + +| משתנה | נדרש | ברירת מחדל | תיאור | +|---|---|---|---| +| `AGENTEYE_SERVER_URL` | כן | בלא | כתובת URL בסיסית של השרת, למשל `http://localhost:8080` | +| `AGENTEYE_API_KEY` | כן | בלא | מפתח API דשבורד משתמש לאימות לשרת. צרכים כל הרשאות (מפתח admin מומלץ). | +| `AE_LOG_LEVEL` | לא | `info` | קיבוץ יומן צד-שרת: `debug`, `info`, `warn`, `error`. הגדר ל-`debug` לראות בקשה מעלה/תשובה שורות וסשן-validation עקבות כאשר אבחון ממצאים. | +| `AE_LOG_JSON` | לא | אוטומטי | `1` כופה JSON-per-line פלט; `0` כופה פלט קריא לאדם. כאשר לא מוגדר, JSON מופעל באופן אוטומטי אם `NODE_ENV=production`. JSON מומלץ בייצור כך יומנים parse בצורה נקייה עם `jq` או מערכת לוגים. | +| `AE_ANALYTICS_DISABLED` | לא | בלא | הגדר ל-`1`/`true` כדי להשבית את telemetry שימוש בשימוש דשבורד אנונימי. ראה [Telemetry & privacy](#telemetry--privacy) להלן. | +| `REDIS_URL` | לא | בלא | אופציונלי חסומה משותפת backend, למשל `redis://redis:6379/0`. כאשר מוגדר, דשבורד משימור `validateSession()` תוצאות על משכפלות ויתרות הבא.js fetch חסומה לנתבי proxy latency-aggregate / env-list. קצב OTP בקשה ו-verify גם השתמש Redis כאשר קיים (נפילה פתוח אם Redis לא זמין; קצב צד-שרת הוא backstop ביטחון). ראה **Redis (אופציונלי חסומה)** להלן. | +| `AGENTEYE_AGENT_URL` | לא | בלא | כתובת URL בסיסית של שירות `agent` AI-assistant אופציונלי, למשל `http://agent:9100`. **השאר אותו לא מוגדר להסתיר את ה-assistant לחלוטין**: בועת assistant אינה מופיעה בדשבורד. ראה [enterprise-docs/assistant.md](/he/agenteye/assistant). | +| `AGENTEYE_AGENT_TOKEN` | לא | בלא | סוד משותף דשבורד מופיע לשירות `agent`. חייב להתאים את `AGENTEYE_AGENT_TOKEN` מוגדר על ה-agent. ראה [enterprise-docs/assistant.md](/he/agenteye/assistant). | + +### הפעל + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-dashboard \ + -e AGENTEYE_SERVER_URL="http://your-server-host:8080" \ + -e AGENTEYE_API_KEY="$ADMIN_KEY" \ + -p 3000:3000 \ + ghcr.io/agenteye-enterprise/dashboard:beta-latest +``` + +### Telemetry & privacy + +הדשבורד שולח **analytics שימוש בשימוש אנונימי** לשירות analytics של Exosphere (PostHog): דפי דשבורד נצפו וקומץ פעולות UI כמו יצירת מפתח API או re-evaluating סשן. אות שימוש זה מודיע אילו תכונות עדיפות. + +- **אין agent, סשן, או נתוני אירוע עוזבת את התשתית שלך.** רק שימוש UI דשבורד דיווח. כתובות עמוד מעוטות מזהים לפני שליחה, ותפעילים מזוהים רק על ידי opaque פנימי id, לעולם לא כמו דוא"ל. +- Telemetry הוא **מופעל כברירת מחדל**. כדי לכבות אותו לחלוטין, הגדר `AE_ANALYTICS_DISABLED=1` על כלי דשבורד ו-restart. +- Analytics משלוח ל-`/ingest` דרך של דשבורד, אשר דשבורד reverse-proxies PostHog (`https://us.i.posthog.com`). שימור requests first-party פירושו browser ad-blockers לא משנה אותם. ה-**dashboard container** צרכים יוצא גישה ל-PostHog; אם זה חסום, telemetry בשקט לא עושה כלום והדשבורד לא מושפע. + +--- + +## AI Assistant (אופציונלי) + +in-dashboard AI assistant מאפשר לצוות שלך לשאול שאלות של agent נתוני בשפה רגילה (summarising סשנים, drafting SQL עבור עורך `/queries`, והפיכה של שאלות שמורות כדי דשבורד רעפים) ללא עזיבת דשבורד. זה פעולה כ-pod container `agent` פנימי נפרד (ב-Claude Agent SDK) שרק דשבורד יכול להגיע, ו-stays **השבת עד שתחפש LLM endpoint**. + +כדי לאפשר זאת אתה הגדרת, על שירות `agent`, חיבור LLM (**Portkey** דרך `PORTKEY_API_KEY` + דגם-catalog slug `AGENTEYE_AGENT_MODEL=@/`, Anthropic ישיר דרך `ANTHROPIC_API_KEY`, gateway אחר דרך `ANTHROPIC_BASE_URL`, או Bedrock/Vertex), **מפתח נתוני דתי**, ו-`AGENTEYE_AGENT_TOKEN` משותף תאם דשבורד. משתמשי דשבורד בנוסף צרכים `agent:use` הרשאות. + +עבור מפתח נתוני דתי של assistant אתה לא לעטוף כלום ביד: בחרו secret אקראי, הגדר אותו בתור `AGENTEYE_API_KEY` על `agent` **ו** כמו `AGENT_API_KEY` ב `server`, ו-server זורעת אותו בעת התחלה עם set הרשאות קבוע. גישת נתוני שלה היא read-only (`events:read`, `evaluations:read`, `dashboards:read`, `queries:read`), ובנוסף מחזקה authoring scopes אישור-gated (`dashboards:write`, `queries:write`, `queries:run`) כך שהוא יכול draft ו-validate שאלות שמורות בנים דשבורד רעפים על המשתמש של behalf; כל SQL עדיין פעולה דרך ארגון read-only ClickHouse תפקיד, כך ש-widening פירוש מה-assistant יכול author, לא אשר נתונים זה יכול להגיע. ה-scopes הם קבוע בקוד ו-cannot להרחיב על ידי תצורה. מפתח זה מוגן; זה לא יכול להיות השבת או תחדול דרך API, רק סיבוב על ידי עדכון הערך ו-restart. לעולם לא reuse admin/dashboard מפתח לזה. + +הגדרה מלאה, reference משתנה סביבה מלאה, אפשרויות telemetry, ו-security דגם נמצאים ב-**[enterprise-docs/assistant.md](/he/agenteye/assistant)**. + +--- + +## ClickHouse (חנות ניתוחים נדרשת) + +ClickHouse שומר דשבורד שלך מגיב בנתח גבוה אירוע ותן `/queries` עורך SQL לצטרף על פני אירועים, הערכות, וסשנים בחנות יחיד. זה חנות הקנוני הנדרשת עבור כל אירוע ingested, כל תוצאת הערכה סופית, ו-derived לכל-סשן aggregates. PostgreSQL מאחסן יחסי / mutable-state טבלאות (api_keys, users, otp_codes, evaluation_jobs, dashboards, saved_queries); ה-analytical משטח חיים ב-ClickHouse כדי דשבורד הרולאפים ו-SQL queries שלך יכול כוח וצטרף זה באופן native, ללא בין-בסיס-נתונים round-trips. השרת מסרב להתחיל ללא `CLICKHOUSE_URL`. + +### סכמה + +שלוש עצמים ClickHouse נוצרים בהתחלת שרת, הכל idempotent (`CREATE IF NOT EXISTS`): + +- **`agenteye.events`**: `ReplacingMergeTree(ingested_at)`, מחולק על ידי `toYYYYMM(ts)`, מסודר על ידי `(session_id, ts, dedup_key)`. כפול מכניס (collector retries) שיתוף שורה יחיד בעת merge זמן; השרת מחשבות deterministic SHA-256 `dedup_key` עבור כל אירוע כדי retries בטוחות. +- **`agenteye.evaluations`**: `ReplacingMergeTree(ingested_at)`, מחולק על ידי `toYYYYMM(finished_at)`, מסודר על ידי `(session_id, finished_at, dedup_key)`. כתוב פעם לתוצאת הערכה סופית על ידי צינור evaluator. אותה dedup-key דגם כמו `events`. +- **`agenteye.agent_sessions`**: a **VIEW** על `agenteye.events`, לא טבלה פיזית. כל עמודה היא נגזרת (`started_at = min(ts)`, `last_event_at = max(ts)`, `ended_at = max(if event_type='agent_end', ts, NULL)`, `event_count = count()`, וכו'). שום לכל-אירוע upsert ו-no separate backfill; view auto-reflects מה הוא בתוך `events`. + +עבור backwards-compat עם שאלות שמורות שהפניות `analytics.evaluations` / `analytics.sessions`, השרת גם יוצר `analytics` ClickHouse בסיס נתונים עם עיקולים על `agenteye.*` טבלאות; `analytics.events`, `analytics.evaluations`, `analytics.agent_sessions`, `analytics.sessions` כל החל שלוח. + +### תצורה + +docker-compose המרוכז ו `deploy/base/clickhouse/` חנות ClickHouse שירות tuned עבור workload של AgentEye: + +- 2 GiB בקשה / 4 GiB restrict זיכרון בתיקייה משלחת base overlay (sized להתאים קטן POC/staging צמתים); ייצור לקוחות צריך overlay למעלה — הרצפה מומלצת היא 2c / 4Gi בקשה, 6c / 8Gi restrict. `max_server_memory_usage_to_ram_ratio=0.9` +- 5 GiB סימן חסומה + 8 GiB uncompressed חסומה +- `background_pool_size=16`, `background_merges_mutations_concurrency_ratio=2` +- MergeTree: `parts_to_throw_insert=3000`, `parts_to_delay_insert=1500`, `non_replicated_deduplication_window=1000` +- `local_io_method=auto` (io_uring על supported kernels) +- `fsync_metadata=0`: קביל כי של לפחות-פעם-אחת ingest + ReplacingMergeTree dedup +- `query_log` מופעל עם 30-יום TTL; `query_thread_log` הוסר (יקר בגבוה QPS) +- `max_execution_time=30` עבור בצד-משתמש queries +- 100 GiB PVC בתבנית StatefulSet (משתמש overlays צריך override ל-fast SSD storage class עבור ייצור) + +### Backups + +ערכת הנתונים המוקדמת שלך מתקבלת nightly בחוקי יחיד restoreable, כל צומת או אחסן הפסד recoverable. ClickHouse מגובה באופן אוטומטי על ידי יומי `agenteye-backup` CronJob, אשר חנויות PostgreSQL וClickHouse ב-pass אחד. ClickHouse קרוא על פני HTTP API שלו: `agenteye.events` ו `agenteye.evaluations` dumped ב-ClickHouse-native עיצוב (ה-views וקו מדיניות recreated על ידי שרת בעת התחלה, כדי טבלה נתונים היא התמונה מלאה) וצרור עם Postgres dump כדי archive דחוס יחיד upload ל-object אחסן שלך. + +יעד bucket וודת credentials עננים configured לכל overlay. ראה את **Backups** סעיף של [enterprise-docs/kubernetes-deployment.md](/he/agenteye/kubernetes-deployment) עבור upload תצורה ו-restore שלבים. + +--- + +## Redis (אופציונלי חסומה) + +Redis היא **אופציונלי** משותפת חסומה + קצב-הגבלה backend בשימוש על ידי שרת ודשבורד. עם Redis deployed ו `REDIS_URL` הגדר על שניהם שירותים: + +- **Server** משימור מאומת API-key lookups, `/events/environments` + `/evaluations/environments` רשימות, `/events/latency_aggregate` rollup (הכבדה ביותר query דשבורד סקרים), `/sessions` רשימות, וmoves קצב OTP בקשה מ-Postgres `COUNT(*)` ל-Redis `INCR + EXPIRE`. +- **Dashboard** משימור `validateSession()` תוצאות כדי 10-20 authed API קוראות typicalpage load ממנו כל שיתוף בעלות סשן בודד. זה גם קצב-גבולות OTP בקשה וOTP-verify בדשבורד edge. + +**שניים שירותים degrade gracefully אם Redis להגיע.** כל חסומה קריאה מחזירה `Err` בתוך bounded timeout וקורא חוזר למקור האמת (Postgres על שרת, ה-Rust שרת upstream על דשבורד). קצב OTP חוזר ל-Postgres `COUNT(*)` דרך על שרת (ביטחון רכוש היא preserved); דשבורד edge OTP הגבול נכשל פתוח בזמן שרת-צד הגבול עדיין מחזיק. Redis להיות למטה degrades latency, לא correctness. + +### תצורה + +docker-compose חבילה כבר כולל Redis שירות וhardwares `REDIS_URL=redis://redis:6379/0` לתוך שרת ודשבורד. לשימוש בחיצוני Redis, הגדר `REDIS_URL` ל-endpoint ושלך הסר `redis` שירות מ-compose קובץ. + +### זיכרון + persistence + +bundled Redis תמונה פעולה עם `--appendonly yes --appendfsync everysec --maxmemory 256mb --maxmemory-policy allkeys-lru`. AOF persistence פירוש החסומה survives כלי restarts; `everysec` הוא האמצע נכון durability/perf כי losing את אחרוני secondes של החסומה כתיבות בטל. LRU eviction caps זיכרון גדילה. + +### כאשר לא ל-deploy Redis + +- יחיד-מופע פיתוח/QA. ה-in-process caches על שרת לבדו deliver רוב of per-replica הטבה; Redis מוסיף את הצלב-replica חלוקה שהיחיד-מופע setups לא צורך. +- אוויר-gapped מתקנים כאשר על פעולתי עלות של ריצה אחד יותר שירות outweighs את latency לצד חלוקה. + +--- + +## Docker Compose (מומלץ) + +A `docker-compose.yml` זמין ב `agenteye-enterprise/releases` repo. זה מעלה Postgres, ClickHouse, Redis, שרת, ודשבורד עם פקודה יחיד. + +```bash +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download \ + --repo agenteye-enterprise/releases \ + --pattern 'docker-compose.yml' \ + --dir ./agenteye +cd agenteye +``` + +**דרוג ברירות מחדל דרך `.env`:** + +``` +# שימוש URL-safe סיסמאות (לא /, +, או = תווים). +# ייצור עם: openssl rand -hex 24 +POSTGRES_PASSWORD=your-db-password +ADMIN_KEY=your-admin-secret + +# דשבורד אימות +ADMIN_EMAIL=admin@yourcompany.com +ALLOWED_EMAILS=*@yourcompany.com + +# SMTP עבור דוא"ל OTP (השמט ל-log קודי OTP ל-stdout) +# SMTP_HOST=smtp.yourprovider.com +# SMTP_PORT=587 +# SMTP_USERNAME=your-smtp-user +# SMTP_PASSWORD=your-smtp-password +# SMTP_FROM=noreply@yourcompany.com + +RUST_LOG=info +``` + +```bash +docker compose up -d +``` + +**עצור (שומר נתוני כרך):** + +```bash +docker compose down +``` + +**עצור וwipe כל נתונים:** + +```bash +docker compose down -v +``` + +--- + +## הגדרות תפעוליות + +קבוצה קטנה של תפעול קנבסים שבשימוש להיות נעוצה על ידי env vars הם כעת editable לכל ארגון מ-**`//settings`** דשבורד עמוד; כל ארגון מוגדר שלה שלה. שינויים לא עובר בתוך שניות, עם לא restart ואין redeploy. + +| הגדרה | Bootstrap env var | מה שזה שולטים | +|---|---|---| +| חתימה מורשית-ins | `ALLOWED_EMAILS` | דוא"לים (או `*@domain.com` wildcards) מורשים לקבל OTP ויהיו משתמשים | +| ברירת מחדל הרשאות משתמש | `DEFAULT_USER_PERMISSIONS` | פסיק-בתור רשימה רשאות tokens pre-selected כאשר admin פתוחים **+ משתמש חדש**. כל token חייב להיות אחד מה-strings רשום תחת [הרשאות מפתח API](/he/agenteye/api-keys). defaults ל-`standard` preset: read-only גישה בתוספת כל יום אודון-התיחות (תעסוקה re-evaluations, פעולה queries, ack incidents, שימוש assistant). | +| סשן lifetime | `SESSION_TTL_SECS` | אנגשת ארוך dash לוגין נשאר תוקף לפני re-auth. דשבורד re-checks upstream סשן כל 5 שניות, כדי הרשאה עדכון על `//users` לוקח השפעה על השפעו משתמש של בקשה הבאה, עם לא relogin. | +| חד-זמן-קוד lifetime | `OTP_TTL_SECS` | אנגשת ארוך OTP / קסום-link נשאר usable | +| התראה notification ערוצים | `ALERTS_ENABLED_CHANNELS` | פסיק-בתור רשימה ערוץ סוגים dispatcher התראה מורשה להשתמש: `email`, `slack`, `webhook`. לכל-alert תצורה עדיין authored על `//alerts/`, אך dispatcher מסננים כל יוצא-dispatch דרך set זה; ערוץ השבת כאן short-circuits עם `skipped_disabled` ביקורת שורה. `dashboard` ערוץ (local ביקורת הוסף) תמיד מורשה. Defaults להכל שלוש על. | + +### איך bootstrap פעולה + +הגדרות מאוחסן לכל ארגון בתוך `org_settings`. בעת boot ראשונה, שרת זורעות ברירת מחדל ארגון של שורות חסרות מ-matching env var (או default sensible אם env var הוא unset). אחרי כן, **הערך מאוחסן היא המקור של אמת ו-env var הוא התעלם**; עדכון env var בעת restart לאחר מכן לא ישפיע על לחיות ארגון של ערך, ו-additional ארגונים התחיל מברירות מחדל וconfigure שלהם שלהם. + +פירושו זה: + +- עבור fresh deploy, הגדר env vars כמו לעיל ו-default ארגון משמיע אותם בעת boot ראשונה. +- כדי לשנות ערך מאוחר, חתום לתוך דשבורד וedit זה תחת `//settings`. שינוי חל בתוך שניות על כל server משכפלות; לא restart נדרש. +- A startup יומן שורה רשומות מה קיבל seeded לעומת מה היה כבר מתנו, כדי אתה יכול לאשר bootstrap took השפעה: + + ```text + INFO settings bootstrap: seeded default-org row key=allowed_sign_ins env_var=ALLOWED_EMAILS seeded_from_env=true + ``` + +#### חתימה-in semantics על פני ארגונים + +סשן ו-OTP הם גלובלי ל-user, לא ל-single ארגון, כדי שני כללים מסכם לכל-ארגון הגדרות בעת sign-in: + +- **Seshon / OTP lifetime**: את strictest (קצר) lifetime בין ארגונים משתמש שייך ל-wins. +- **Allowed sign-ins**: ה-gate ORs כל ארגון allowlist ביחד עם ארגון חברות: משתמש אולי בקשה OTP אם כלום ארגון allowlist admits דוא"ל שלהם **או** הם כבר חברה של כלום ארגון. + +### הרשאות + +גישה ל-`//settings` עמוד היא gated על ידי שתי הרשאות: + +- `settings:read`: ראה עמוד וערכים הנוכחיים. +- `settings:write`: שמור שינויים. + +bootstrap admin משתמש (seeded מ `ADMIN_EMAIL`) קבל שניהם באופן אוטומטי יחד עם כל הרשאה אחרת. מתן אותם ל-users אחרים מ `//users` כמו נדרש. + +--- + +## ארגונים (מולטי-דיירנות) + +פריסה יחיד יכול לשרת מרובים מבודדים **ארגונים** (דיירנים); כל שורה נתוני שייך ל-org בדיוק אחד וגידול הוא כפוי-engine בבסיס הנתונים. יחיד-דיירני התקנה צרכים כלום כאן; כל נתוני חיים ב-built-in `default` ארגון. (אתה יכול תן את ארגון friendly שם ו-URL slug, כדי זה חיים ב-e.g. `/acme` במקום `/default`, על ידי הגדרת `DEFAULT_ORG_NAME` / `DEFAULT_ORG_SLUG` לפני ראשון boot, או על ידי הפיכת שם זה כלום זמן עם `agenteye-orgctl org rename`.) + +**דיירן provisioning הוא אופרטור-בלבד.** ארגונים וחברויות שלהם נוצרים וניהול עם **`agenteye-orgctl`** CLI, אשר חנויות **בתוך שרת תמונה** (יחד עם `agenteye-server`) וריצה **בתוך קיים שרת pod**; יש **אין pod/Job נפרד, אין HTTP API, ואין dשbורד כפתור**. זה reuses שרת של `DATABASE_URL`, `CLICKHOUSE_URL`, ו `ORG_CH_SECRET`. + +```bash +# Docker Compose - exec לתוך בפעולה שרת שירות: +docker compose exec server agenteye-orgctl org create --slug acme --name "Acme Corp" +docker compose exec server agenteye-orgctl member add --org acme --email alice@acme.example --set admin + +# Kubernetes - exec לתוך פעולה שרת Deployment: +kubectl -n agenteye exec deploy/server -- agenteye-orgctl org list +``` + +זמין verbs: `org create | list | rename | delete | purge` ו `member add | list | update | remove`, עם builtin הרשאה מוגדרות `admin`, `standard`, ו `read-only`. נוסף חברים קבל OTP בעת dash בעליל לראשונה. + +**לפני יצירה שנייה ארגון:** הגדר חזק, יציב `ORG_CH_SECRET` (ה `org create` פקודה מסרב לרוץ על ה-built-in פיתוח ברירת מחדל) ו-ensure Postgres הוא **15+**. **Unchanged:** לכל-ארגון API מפתחות עדיין minted בדשבורד/API על ידי ארגון חברים; רק ארגון + חברות lifecycle התמורה לCLI. מלא פקודה reference ועבד דוגמה: **[enterprise-docs/tenant-management.md](/he/agenteye/tenant-management)**. + +--- + +## Context-window fill + +כל `model_response` אירוע מציג **context-fill כדור** — input בתוספת output תוקן כמו אחוז של אותו דוגמן של context חלון. ה-bands הם `healthy` (0–24%), `watch` (25–49%), `compacting` (50–74%), ו `reset context` (75–100%). AgentEye פתר דוגמן ids נפוץ באופן אוטומטי, כדי לא ראשוני תצורה נדרש. + +כל דוגמן ארגון חנויות מופיע תחת **הגדרות → דוגמן context חלונות**. משתמשים עם `settings:write` יכול דרוג חלון שלו או הוסף פרטי/proxy דוגמן (0–1,000,000 תוקנים); `0` פירוש "לא ידוע" וsuppresses הכדור. שינויים חל ל-newly ingested אירועים. משתמשים עם `settings:read` יכול צפה הרשימה. + +חדש אירועים קבל fill מן הרגע הוא upgrade. כדי גם למלא **היסטורי** אירועים (ו-per-model רשימה) עבור קיים deployment, הפעיל את one-off backfill — זה חנויות בתוך שרת תמונה (כמו `agenteye-orgctl`) וריצה בקיים שרת pod: + +# preview (הדפסות per-org השינוי, שינויים כלום): +kubectl -n agenteye exec deploy/server -- \ No newline at end of file diff --git a/docs/he/agenteye/evaluation-suite.mdx b/docs/he/agenteye/evaluation-suite.mdx new file mode 100644 index 00000000..ff6ad07d --- /dev/null +++ b/docs/he/agenteye/evaluation-suite.mdx @@ -0,0 +1,389 @@ +--- +--- +title: "Evaluation Suite" +description: "תיעוד AgentEye Evaluation Suite." +--- + + +AgentEye מעריכה סשנים של agent שהושלמו על ידי POST של תמליל האירוע המלא לשירות **מעריך יחיד שבבעלות הלקוח**. המעריך מחזיר ניקוד או בתוך התגובה או על ידי החזרת `job_id` כדי שAgentEye יבצע poll עליו. התוצאות מאוחסנות והן מוצגות בדשבורד. + +מדריך זה מכסה: + +1. כיצד מתגלה השלמת סשן. +2. החוזה HTTP שעל המעריך ליישם. +3. הגדרת שרת AgentEye. +4. צפייה בתוצאות. +5. פתרון בעיות. + +עבור העוזר Python שמיישם את החוזה בשבילך, ראה את +[`agenteye-evaluator` package ב-PyPI](https://pypi.org/project/agenteye-evaluator/). + +--- + +## איך זה עובד + +```text +ingest /events ──▶ AgentEye ──── POST /evaluate ────▶ Evaluator service + (agent_end) server ◀──── done | pending ──── + │ + │ GET /evaluate/{job_id} ─────▶ + │ ◀──── done ────────────── + ▼ + evaluations (terminal results) +``` + +כאשר AgentEye SDK פולט אירוע `agent_end` לסשן, השרת מתזמן הערכה. לאחר מכן הוא עושה POST של תמליל האירוע המלא לשירות המעריך שלך, שיכול: + +- **להחזיר את התוצאה בתוך התגובה** עם `{"status":"done", "scores":{...}, "reasoning":{...}, "summary":"..."}`. התוצאה מצורפת לציר הזמן ההערכה של הסשן. `reasoning` ו-`summary` הם אופציונליים. +- **להשהות** עם `{"status":"pending", "job_id":"abc-123"}`. AgentEye אז קורא ל-`GET {EVALUATOR_ENDPOINT}/evaluate/abc-123` עד שהמעריך שלך מחזיר `{"status":"done", ...}` או `{"status":"error", "error":"..."}`. + + קצב ה-polling הוא לכל job: תגובה `pending` עשויה לכלול `next_poll_secs` כדי להציף; אחרת AgentEye משתמש בערך `default_poll_interval_secs` מ-`GET /config`; אחרת השרת חוזר ל-`EVALUATOR_POLLING_INTERVAL_SECS` (ברירת מחדל 10s). כל הערכים מוגבלים ל-[1s, 1h]. + +סשנים שלעולם לא פולטים `agent_end` (לדוגמה, process agent שקרס) יכולים גם להיאסף: `GET /config` של המעריך עשוי להחזיר `{"inactivity_timeout_secs": 1800}`, וAgentEye יעריך כל סשן שהיה inactive לאורך זמן זה. הגדר את השדה ל-`null` או השמט אותו כדי להשבית אפשרות חלופה זו. + +ה-pipeline הוא מלא no-op כאשר `EVALUATOR_ENDPOINT` לא מוגדר. + +סשן יכול להצבור **הערכות טרמינליות מרובות לאורך זמן**: כל אירוע `agent_end` (וכל re-eval ידני מהדשבורד) מוסיף שורת הערכה חדשה. זו הדרך הנתמכת להערכת שיחה שחודשה: משתמש מסיים agent, חוזר מאוחר יותר, שולח עוד אירועים, מסיים את ה-agent שוב, והערכה שנייה רצה כנגד תמליל מעודכן מלא. הדשבורד מעניק את ההערכה האחרונה כהכותרת הראשונה וההערכות הקודמות כציר זמן קובץ. כאשר הערכה אחת מתנהלת לסשן, אירועי `agent_end` נוספים לסשן זה מתעלמים; הבא אחרי השלמת ההערכה הרצה יתור הערכה חדשה כרגיל. + +הפלט inactivity מתחדש גם בסשנים שחודשו: אם אירועים חדשים מגיעים אחרי הערכה טרמינלית קודמת והסשן אז הופך ל-idle עברות `inactivity_timeout_secs`, הערכה חדשה מתורה. + +כשלים חולפים (5xx, 429, timeouts, network errors) נסיונות חוזרים עם exponential backoff עד `EVALUATOR_MAX_ATTEMPTS`; תגובות 4xx הן טרמינליות. AgentEye בטוח לריצה עם מספר instances שרת בקנה מידה אופקי; עבודה מחולקת כך שאותו סשן לעולם אינו מופץ פעמיים בו זמנית. + +--- + +## חוזה HTTP + +כל נתיב מאומת משתמש **bearer token auth**. אותו ערך חייב להיות מוגדר בשני הצדדים: + +- שרת AgentEye: משתנה env `EVALUATOR_TOKEN` +- שירות המעריך: מוגדר באותו אופן (SDK של `agenteye-evaluator` קוראת `EVALUATOR_TOKEN` לפי מוסכמה) + +אם `EVALUATOR_TOKEN` לא מוגדר, השרת לא שולח כל `Authorization` header; המעריך עשוי אז לקבל בקשות אנונימיות, וזה בסדר לרשת פנימית בלבד אך לא מעודדת באינטרנט הציבורי. + +### נתיבים שעל המעריך לשרת + +| נתיב | גוף / params | תגובה | +|---|---|---| +| `GET /health` | none | `{"status":"ok"}` (פתוח, ללא auth) | +| `GET /config` | none | `{"inactivity_timeout_secs": \| null, "default_poll_interval_secs": \| omitted}` | +| `POST /evaluate` | `EvalRequest` JSON | `{"status":"done", ...}` או `{"status":"pending", "job_id":"..."}` | +| `GET /evaluate/{id}` | none | אותה צורת תגובה כמו `/evaluate` | + +### `EvalRequest` גוף שנשלח על ידי השרת + +```json +{ + "schema_version": "1", + "session_id": "session-abc123", + "agent_id": "planner", + "environment": "production", + "started_at": "2026-05-10T12:00:00Z", + "ended_at": "2026-05-10T12:05:00Z", + "events": [ + { "id": 1234, "ts": "...", "event_type": "agent_start", "payload": { ... } }, + ... + ] +} +``` + +### צורות תגובה + +**Sync (done):** + +```json +{ + "status": "done", + "scores": { "helpfulness": 0.85, "tool_efficiency": 0.6 }, + "reasoning": { + "helpfulness": "answered the question directly with citations", + "tool_efficiency": "called list_files three times when one would have done" + }, + "summary": "strong answer quality, weak tool selection" +} +``` + +`reasoning` (מפת הצדקה לכל ניקוד) ו-`summary` (סיפור בפסקה אחת כללי) שניהם אופציונליים. המפתחות ב-`reasoning` צריכים להשתקף מפתחות ב-`scores`; הדשבורד מעניק כל ערך בתוך שורת הניקוד שלו. מעריכים ישנים יותר שמחזירים רק `scores` ממשיכים לעבוד ללא שינוי; `reasoning` ו-`summary` פשוט קוראים כ-null ו-affordances ה-UI המתאימות מושמטות. + +**Async (deferred):** + +```json +{ "status": "pending", "job_id": "abc-123", "next_poll_secs": 30 } +``` + +`next_poll_secs` הוא אופציונלי; אם מושמט השרת חוזר ל-`default_poll_interval_secs` של המעריך מ-`/config`, ואז ל-משתנה env `EVALUATOR_POLLING_INTERVAL_SECS` שלו. + +**שגיאה טרמינלית בצד המעריך:** + +```json +{ "status": "error", "error": "model service unavailable" } +``` + +השרת מתייחס לכל גוף 2xx אחר כשגיאת פרוטוקול ורושם terminal `error` לסשן. + +--- + +## כתיבת מעריך עם ה-SDK + +חבילת Python של `agenteye-evaluator` נותנת לך wrapper FastAPI שמוקלד המיישם את חוזה HTTP הנ״ל. התקן אותה מ-PyPI: + +```bash +pip install agenteye-evaluator +``` + +מעריך קטן וקיום ווידיוק: + +```python +import os +from agenteye_evaluator import Evaluator, EvalRequest, EvalResponse + +app = Evaluator(token=os.environ["EVALUATOR_TOKEN"]) + +@app.evaluator +def run(req: EvalRequest) -> EvalResponse: + # Inspect req.events (the full session transcript) and return scores. + tool_calls = sum(1 for e in req.events if e.event_type == "tool_use") + return EvalResponse( + scores={"tool_calls": float(tool_calls)}, + reasoning={"tool_calls": f"{tool_calls} tool invocations in the transcript"}, + summary="tight tool loop" if tool_calls < 5 else "agent looped on tools", + ) +``` + +מופע `app` הוא ASGI-callable, כך `uvicorn module:app` מריץ אותו. + +עבור מעריכים שצריכים לדחות עבודה יקרה, החזר `JobPending` במקום ורשום `@app.job_lookup` handler; שרת AgentEye עושה poll ל-`GET /evaluate/{job_id}` עד שתחזיר סטטוס טרמינלי או עד שמגיע כובר ה-`EVALUATOR_MAX_POLL_DURATION_SECS` (ברירת מחדל 1 h). + +התיעוד API המלא, דפוס async, וסכמת אירוע: ה-README של `agenteye-evaluator` משלח בתוך כל tarball release ב- +[agenteye-enterprise releases page](https://github.com/agenteye-enterprise/releases), +או שאתה יכול קרא אותו בעמוד PyPI של החבילה. + +--- + +## הפעלת מעריך ב-Kubernetes + +המעריך הוא **השירות שלך**: AgentEye לא משלח מעריך container ברירת מחדל. ה-release כולל דוגמאות Kubernetes manifests תחת `deploy/examples/evaluator/` שאתה יכול ליישם כפי שהם אחרי החלפת התמונה שלך וtoken bearer משותף. + +### 1. Containerize את המעריך שלך + +Dockerfile מינימלי למעריך שלך: + +```dockerfile +FROM python:3.12-slim +WORKDIR /app +RUN pip install --no-cache-dir agenteye-evaluator uvicorn +COPY my_evaluator.py . +RUN useradd --uid 10001 --create-home --shell /usr/sbin/nologin evaluator \ + && chown -R evaluator:evaluator /app +USER evaluator +EXPOSE 9000 +CMD ["uvicorn", "my_evaluator:app", "--host", "0.0.0.0", "--port", "9000"] +``` + +`runAsNonRoot` (UID 10001) שומר על ה-container תואם ל-Pod Security restricted profiles. + +### 2. צור את ה-bearer token המשותף + +```bash +kubectl -n agenteye create secret generic evaluator-token \ + --from-literal=token="$(openssl rand -hex 32)" +``` + +השתמש באותו ערך כמו `EVALUATOR_TOKEN` בשרת AgentEye. השרת שולח `Authorization: Bearer ` בכל בקשה; ה-SDK משתמש ב-`hmac.compare_digest` לבדיקה constant-time ודוחה חוסרי התאמה עם HTTP 401. + +### 3. יישום דוגמא manifests + +```bash +# Edit deploy/examples/evaluator/deployment.yaml first to point +# `image:` at your registry, then: +kubectl apply -k deploy/examples/evaluator/ +``` + +הדוגמה כוללת: + +- Deployment של 2-replica עם `runAsNonRoot`, read-only root filesystem, + כל capabilities מושמטות, liveness + readiness ב-`/health` +- ClusterIP Service על port 9000 +- `secret.example.yaml` template (מכוונים בכוונה מה-Kustomization; יצור את ה-secret האמיתי out-of-band כדי שלא token נחת ב-git) + +### 4. wire AgentEye אליו + +בשרת AgentEye, הגדר: + +```bash +EVALUATOR_ENDPOINT=http://evaluator:9000 +EVALUATOR_TOKEN= +``` + +השרת fan out `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH` +בקשות concurrent ברחבי כל evaluator pods (ברירות מחדל: `2 × 4 = 8`). +קנה מידה `replicas` וper-pod resource limits בשיתוף פעולה עם אלה +server-side knobs. + +### verification + +```bash +kubectl -n agenteye port-forward svc/evaluator 9000:9000 +curl -s http://localhost:9000/health # → {"status":"ok"} +``` + +אחרי שagent מתנהל end-to-end, `GET /evaluations` בשרת AgentEye +צריך להחזיר שורה עם `status: "done"` והניקוד שהמעריך שלך יצר. + +--- + +## הגדרת שרת AgentEye + +הגדר בתהליך השרת: + +| משתנה Env | משמעות | +|---|---| +| `EVALUATOR_ENDPOINT` | Base URL של המעריך שלך (`http://evaluator:9000`). Unset = pipeline disabled. | +| `EVALUATOR_TOKEN` | Bearer token. חייב להיות שווה לערך ששירות המעריך מוגדר איתו. | +| `EVALUATOR_WORKERS` | משימות worker לכל instance שרת (ברירת מחדל 2). | +| `EVALUATOR_CLAIM_BATCH` | שורות טענות לכל worker tick (ברירת מחדל 4). טבעות מעובדות **concurrently**; effective concurrency בנקודת הקצה של המעריך שלך היא `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH`. | +| `EVALUATOR_POLL_IDLE_SECS` | כמה זמן עובד ישינה בין ניסיונות dispatch כאשר אין הערכה בגינה (ברירת מחדל 2s). | +| `EVALUATOR_POLLING_INTERVAL_SECS` | fallback סופי עבור `GET /evaluate/{id}` cadence כאשר לא `next_poll_secs` לכל תגובה ולא `default_poll_interval_secs` של המעריך הוגדרו (ברירת מחדל 10s). | +| `EVALUATOR_REQUEST_TIMEOUT_MS` | timeout לכל בקשה (ברירת מחדל 30000). | +| `EVALUATOR_MAX_ATTEMPTS` | אחרי כל כשלים חולפים זה הרבה, התוצאה מתועדת כ-terminal `error` (ברירת מחדל 5). | +| `EVALUATOR_CONFIG_REFRESH_SECS` | `GET /config` cadence (ברירת מחדל 300). | +| `EVALUATOR_MAX_POLL_DURATION_SECS` | זמן wallclock מרבי שסשן עשוי להישאר בתור polling לפני שהוא מסתיים כ-`timeout` (ברירת מחדל 3600s). שומר כנגד מעריך שממשיך להחזיר `pending` לנצח. | + +כדי להפעיל ניקוד אוטומטי ברחבי המופע כולו, סדר את `agenteye-evaluator` Secret עם שני המפתחות מוגדרים. ב-bundled Kubernetes manifests, השרת קורא `EVALUATOR_ENDPOINT` ו-`EVALUATOR_TOKEN` מ-Secret זה אופציונלי. יצור אותו דרך תהליך ניהול Secret סטנדרטי של הארגון שלך, אז הפעל מחדש את Deployment של השרת כדי להרים את השינוי. + +ה-tuning knobs לעיל לא חוטים על ידי ברירת מחדל; חשוף משתנה env תואם בן container שרת ב-Deployment manifest שלך אם צריך להציף את ברירות המחדל. + +ראה [deployment.md](/he/agenteye/deployment) עבור טבלת משתנה env מלאה. + +--- + +## התיעוד API + +| שיטה | נתיב | הרשאה נדרשת | תכנית | +|---|---|---|---| +| `GET` | `/evaluations` | `evaluations:read` | תוצאות terminal של שאילתה. תומכת `session_id`, `agent_id`, `environment`, `status` (`done`/`error`/`timeout`), `ts_from`, `ts_to`, `cursor`, `limit`, `score_filters`, `latest_per_session`. `limit` ברירת מחדל 50 וcapped ב-200 (שים לב שזה שונה מ-`/events`, שcaps ב-1000). `environment` מקבל רשימה מופרדת בפסיקים (למשל `environment=prod,staging`); ערכים בודדים עדיין עובדים. עם `latest_per_session=true` התגובה מכילה לכל היותר שורה אחת לכל `session_id` (ה-recent ביותר על ידי `completed_at`) המשמשת עמוד sessions-list כדי לכווץ ציר זמן הערכה של סשן לכותרת הנוכחית שלו. ברירות מחדל ל-false (מחזיר את ההיסטוריה המלאה). | +| `GET` | `/evaluations/aggregate` | `evaluations:read` | health eval rolled-up לחתך מסונן: ספירה כוללת, done/error/timeout breakdown, per-score-key stats (count/avg/min/max/p50 מעל arbitrary `scores` מפתחות), וציר זמן bucketed. מקבל את **אותם filter params כמו `/evaluations`** בתוספת `featured_keys` (CSV של score keys לזרום) ו-`latest_per_session`. Powers הפיצ'ר Dashboards; מטריקות מדויקות מעל הסט כולו תואם, לא דגימה. | +| `GET` | `/evaluations/environments` | `evaluations:read` | ערכי environment מובחן מטבלת `evaluations`. משמש לאוכלוסיה dropdown filter scoped להערכה-קוראת נתונים. | +| `GET` | `/evaluation-jobs` | `evaluations:read` | נראות לתוך הערכות in-flight. סנן לפי `status` (`pending`/`polling`). | +| `GET` | `/events` | `events:read` | stream אירועי raw של סשן. תומכת `session_id`, `agent_id`, `event_type` (CSV), `environment` (CSV), `ts_from`, `ts_to`, `cursor`, `limit`, ו-`order`. `order` הוא `desc` (newest-first, ברירת המחדל) או `asc` (oldest-first); ערך לא מוכר חוזר ל-`desc`. Cursor-paginate דרך response ה-`next_cursor` (event id): פדיון אותו חזור ל-`cursor` כדי לקבל עמוד הבא; עם `asc` עמוד הבא הוא אירועים אחרי ה-id זה, עם `desc` האירועים לפניו. `limit` ברירות מחדל 50 וcapped ב-1000. | +| `GET` | `/sessions/:session_id/export` | `events:read` | מחזיר את גוף JSON המדויק שהמעריך יקבל לסשן זה, משרת כהטמון ניתן להורדה בשם `session-.json`. שימושי לreplay סשנים production דרך `agenteye-evaluator` לבדיקה offline. הבייטים הם byte-identical למה ש-evaluator pipeline שולח. | +| `POST` | `/sessions/:session_id/re-evaluate` | `evaluations:trigger` | תור הערכה חדשה לסשן; מתנהל בין אם קיימת הערכה קודמת ובין אם לא. התוצאה החדשה היא **מתווסת** לציר זמן ההערכה של הסשן במקום הודפסת ההערכה הקודמת, כך ניקוד קודם נשאר נראה כהיסטוריה. מחזיר `202` בתור, `404` לסשן לא ידוע, `409` אם הערכה כבר in-flight. השתמש בהוצאה אחרי development evaluator חדש, או לסשנים שלעולם לא פולטים `agent_end`. | + +### סינון לפי score range: `score_filters` + +`GET /evaluations` מקבל אופציונלי `score_filters` parameter שצמצם תוצאות לפי values מספריות בתוך ה-`scores` object. ה-parameter הוא CSV של `key:min..max` entries; כל bound עשוי להיות מושמט. ערכים מרובים משתלבים עם logical AND. שורות שבהן המפתח בשם היא היעדר או non-numeric אינן נכללות. בקשה עשויה להנשא לכל היותר 20 filter entries; חריגה זו מחזיר HTTP 400. + +דוגמאות: +```text +# helpfulness in [0.5, 0.8] +GET /evaluations?score_filters=helpfulness:0.5..0.8 + +# tool_efficiency at most 0.3 (no lower bound) +GET /evaluations?score_filters=tool_efficiency:..0.3 + +# helpfulness >= 0.5 AND factuality >= 0.9 +GET /evaluations?score_filters=helpfulness:0.5..,factuality:0.9.. +``` + +כל `/evaluations` response object כל שדות אלה: + +| שדה | סוג | הערות | +|---|---|---| +| `evaluation_id` | string (UUID) | המזהה הקנוני להערכה טרמינלית זו. כל הערכה טרמינלית מקבלת UUID חדש; סשן יחיד יכול להיות מחזיק מרובים. | +| `id` | string (UUID) | backwards-compatibility ממשיך לשאת את אותו ערך כמו `evaluation_id`. | +| `session_id` | string | הסשן שהערכה זו רצה כנגדו. סשן יכול להחזיק הערכות מרובות בציר הזמן. | +| `agent_id` | string | מזהה את ה-agent שיצר את הסשן. | +| `environment` | string | תווית environment המועתקת מהסשן. | +| `status` | enum | אחד מ-`"done"`, `"error"`, `"timeout"`. | +| `scores` | object \| null | ניקוד שהוחזר על ידי המעריך שלך. | +| `reasoning` | object \| null | אופציונלי per-score justification map שהוחזר על ידי המעריך שלך. מפתחות בדרך כלל משקפים אלה ב-`scores`. הדשבורד מעניק כל ערך תחת שרת ניקוד שלו. | +| `summary` | string \| null | אופציונלי one-paragraph סיפור כללי שהוחזר על ידי המעריך שלך. הדשבורד מעניק זאת מעל הפרוק per-score כהכותרת ההערכה. | +| `error` | string \| null | מלא על `"error"` / `"timeout"` בלבד. | +| `attempt_count` | integer | מספר dispatch attempts (≥ 1). | +| `duration_ms` | integer \| null | משך הניסיון הסופי. | +| `completed_at` | string (ISO 8601 UTC) | כאשר התוצאה הטרמינלית נתונה. התוצאות מסודרות לפי `completed_at` (newest first). | +| `created_at` | string (ISO 8601 UTC) | נושא אותו timestamp כ-`completed_at` (write-once semantics). | + +--- + +## הרשאות + +| הרשאה | מענקים | +|---|---| +| `evaluations:read` | הערכות רשימה, צפייה בניקוד בדשבורד, וטעינה מדדי health של דשבורד. | +| `evaluations:trigger` | manually תור הערכה לסשן via `POST /sessions/:session_id/re-evaluate` או דשבורד re-evaluate button. | +| `dashboards:read` | צפייה בדשבורדים שמורים (גם צריך `evaluations:read` כדי לטעון את המדדים שלהם). | +| `dashboards:write` | יצור ועריכה dashboards. | +| `dashboards:delete` | מחק dashboards. | + +bootstrap admin (`ADMIN_KEY`, `ADMIN_EMAIL`) קיבל באופן אוטומטי אלה. + +--- + +## צפייה בתוצאות + +- **`/sessions/`**: אירוע timeline + קריאה ימין המציגה את ניקוד הסשן וכל שגיאה מניסיון dispatch. אם המפתח שלך כולל `evaluations:trigger`, **re-evaluate** button מופיע ליד export button, שימושי לסשנים שלעולם לא פולטים `agent_end`, או פרש ניקוד אחרי הנפקת evaluator חדש. הדשבורד poll לתוצאה החדשה וmicroservices ה-right rail כאשר הוא נחת. +- **`/sessions`**: filterable session grid; score column מציג evaluation status וניקוד של כל סשן בהצצה. +- **`/dashboards`**: שמור eval-health views (ראה [Dashboards](#dashboards) למטה). + +![The Sessions grid with per-session evaluation status pills and colour-coded score badges (helpfulness, factuality, tool_efficiency, safety, coherence)](/agenteye/images/sessions-list.png) + +*grid sessions מציגה evaluation status וניקוד של כל ריצה בהצצה; red/amber/green badges יוצרים ניקוד נמוך להקפיץ.* + +![A session detail view with the evaluation scores and dispatch status in the right rail](/agenteye/images/session-detail.png) + +*פתיחה סשן מציגה ציר זמן מלא לצד evaluation scores וכל dispatcher error בקריאה ימין.* + +--- + +## Dashboards + +עמוד ה-**Dashboards** (`/dashboards`) מאפשר לך שמור שילוב של evaluation filters כמו נקוב, reusable view וצפייה כיצד החתך זה של evaluations עושה בהצצה. Dashboards הוא **משותף לעל כל הארגון שלך**; כולם עם `dashboards:read` רואים את אותה סט. + +כל dashboard מכיווץ: + +- **Filters**: אותם קרים כמו sessions page: environment, status, + agent, rolling time window, וscore-range filters (`key:min..max`). +- **A display configuration**: אילו score keys לfeature, ה-green/amber/red + health thresholds, אילו panels להציג, והאם לכווץ לאחרון + evaluation לכל סשן. + +כל card מציג את מספר הסשנים משחקה, done/error/timeout breakdown, +הממוצע של כל featured score, וsmall trend sparkline. פתיחה dashboard מציגה full-size panels; **open in sessions** זורק אותך ל-sessions page pre-filtered לחתך בדיוק זה. מטריקות מחושבות +server-side מעל הסט כולו משחקה (via `GET /evaluations/aggregate`), אז +המספרים מדויקים ולא דגימה. + +![An eval-health dashboard with average-score bars per evaluator dimension, a tool ok-vs-error breakdown, top tools, and an events-per-hour trend](/agenteye/images/dashboard-quality.png) + +**Permissions:** צפייה צריך גם `dashboards:read` וגם `evaluations:read`; +יצור וערוך צריך `dashboards:write`; מחק צריך `dashboards:delete`. +bootstrap admin מקבל כל אלה באופן אוטומטי. + +--- + +## פתרון בעיות + +**Sessions קיימים אבל אין evaluations יוצרו.** Confirm `EVALUATOR_ENDPOINT` +מוגדר בתהליך השרת, שהשרת ומעריך חולקים אותו `EVALUATOR_TOKEN` value, וש-`/health` endpoint של המעריך +שניתן להגיע מהשרת. עם `EVALUATOR_ENDPOINT` unset ה-pipeline הוא +no-op. + +**In-flight evaluations עומדים לערום.** שאילתה `GET /evaluation-jobs` כדי לראות את +ה-in-flight queue. Inspect `attempt_count`, `next_attempt_at`, ו-`last_error` +על כל שורה. סיבות נפוצות: evaluator service בלתי מעביר או חוזר 5xx +(נסיונות חוזרים עם backoff), wrong `EVALUATOR_TOKEN` (401 הוא terminal), או +async evaluator שחוזר `pending` indefinitely (ראה למטה). + +**Sessions שהושלמו אבל אין terminal evaluation.** שאילתה +`GET /evaluation-jobs?status=polling`; התוצאה עשויה עדיין להיות in-flight. +אם job הוא stuck ב-`pending`, השרת יש בעיה להגיע למעריך; בדוק את המעריך הוא עד וכי `EVALUATOR_TOKEN` matches. + +**`HTTP 401 from evaluator: invalid bearer token`.** ה-`EVALUATOR_TOKEN` +בשרת לא תואם את ערך המעריך service מוגדר +איתו. הם חייבים להיות זהים. + +**Async evaluator מחזיר `pending` לנצח.** השרת poll +`GET /evaluate/{job_id}` עד המעריך מחזיר `done` או `error`, או +עד `EVALUATOR_MAX_POLL_DURATION_SECS` (ברירת מחדל 1 h) elapses. אחרי ה-cap +ההערכה מתועדת כ-`timeout` ומוסרה מה-in-flight queue. +הגדל `EVALUATOR_MAX_POLL_DURATION_SECS` אם המעריך שלך legitimately צריך +יותר מברירת המחדל. \ No newline at end of file diff --git a/docs/he/agenteye/getting-started.mdx b/docs/he/agenteye/getting-started.mdx new file mode 100644 index 00000000..1479ff78 --- /dev/null +++ b/docs/he/agenteye/getting-started.mdx @@ -0,0 +1,236 @@ +--- +--- +title: "התחלה עם AgentEye" +description: "תיעוד התחלה עם AgentEye." +--- + + +מדריך זה מוביל אתכם דרך התקנה מלאה של AgentEye: פריסת השרת והלוח מחוונים, התקנת הקולטן על מכונת סוכן, והוספת instrumention לקוד הסוכן Python שלכם. + +--- + +## מה זה AgentEye? + +AgentEye הוא **פלטפורמת observability והערכה בעצמי לסוכנים בבינה מלאכותית**. הוא רושם מה הסוכנים שלכם עושים — כל שלב בריצה — והוא מעניק ניקוד אוטומטי לאיכות כל ריצה שהושלמה, כך שתוכלו לראות כיצד הסוכנים שלכם מתנהגים בייצור ולתפוס regression לפני שהמשתמשים שלכם יעשו זאת. + +הנתונים זורמים בכיוון אחד בלבד: קוד הסוכן שלכם פולט **events** דרך **ה-SDK של Python** → daemon קולטן קל משקל אוגדתים ושולח אותם לשרת → events וניתוח מאוחסנים ב-**ClickHouse** (מצב תפעולי כגון ארגונים, משתמשים, מפתחות API, לוחות מחוונים ושאילתות שמורות חיות ב-**Postgres**) → אתם חוקרים הכל בלוח **המחוונים**. + +מה אתם מקבלים: + +- **Events** — שביל גולמי לכל צעד בכל ריצת סוכן (קריאות כלי, קריאות מודל, hooks, שגיאות). +- **Sessions** — אירועים אלה מגורגרים לשורה אחת לכל ריצה, כל אחת **מוערכת ומדורגת באופן אוטומטי**. +- **Evaluations** — ניקודי איכות המיוצרים על ידי שירותי ה-evaluator שלכם, כך שירידות באיכות יופיעו ללא סקירה ידנית. +- **Queries & dashboards** — SQL ClickHouse שמור על הנתונים שלכם, מעוצב לתוך לוחות מחוונים משותפים בהיקף ארגוני. +- **Alerts & incidents** — כללי סף המעניקים לכם דף (דוא"ל, Slack, webhook, בתוך הלוח) בנוסף לזרימת עבודה של incident כדי לבחור אותם. +- **CLI & AI assistant** — לקוח טרמינל (`agenteye`) וסוכן בתוך הלוח לשאילת שאלות בשפה אנגלית רגילה. + +אתם מריצים הכל בתשתית שלכם, כ-stack יחיד של Docker Compose (מדריך זה), התקנת Kubernetes בייצור, או pod יחיד שנמצא במקום. שאר המדריך מגדיר את stack ה-Compose מלא וקצה. + +--- + +## שלב 1: הזדהות + +כל הנכסים של AgentEye מופצים מארגון `agenteye-enterprise` GitHub. כמפתח enterprise אתם יכולים ליצור את ה-GitHub PAT שלכם. עקבו אחר [enterprise-docs/github-token.md](/he/agenteye/github-token) לשלבים מדויקים והרשאות נדרשות. + +```bash +export AGENTEYE_TOKEN= + +# Authenticate Docker against GHCR +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +--- + +## שלב 2: פרוס את השרת והלוח + +השרת מקבל events מקולטנים ועושה אותם ניתנים לשאילתה; הלוח הוא המקום שבו אתם חוקרים אותם. Events וניתוח שנצרכו חיים ב-ClickHouse (חנות הניתוח הנדרשת), בעוד Postgres מחזיק מצב תפעולי כגון ארגונים, משתמשים, מפתחות API, לוחות מחוונים ושאילתות שמורות. + +**הורידו את קובץ ה-compose המפורסם:** + +```bash +mkdir -p ./agenteye +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + https://raw.githubusercontent.com/agenteye-enterprise/releases/main/docker-compose.yml \ + -o ./agenteye/docker-compose.yml +cd agenteye +``` + +**הגדרו את הסודות שלכם:** + +צרו קובץ `.env` כך שההפריסה לא תרוץ עם הרשאות ה-`admin` בברירת המחדל. לפחות הגדרו `ADMIN_KEY` ו-`POSTGRES_PASSWORD`: + +```bash +POSTGRES_PASSWORD=your-db-password +ADMIN_KEY=your-admin-secret +``` + +כמו כן ייצאו `ADMIN_KEY` בשל שלכם הנוכחי כך ששלבים מאוחרים (למשל ה-`curl` בשלב 3) יוכלו להתייחס אליו ישירות: + +```bash +export ADMIN_KEY=your-admin-secret +``` + +**הפעילו את ה-stack:** + +```bash +docker compose up -d +``` + +זה מביא את ה-stack המלא, כולל ClickHouse analytics store הנדרש ומטמון Redis אופציונלי, בצד השרת והלוח. ClickHouse צריך להיות בריא כדי שהשרת יתחיל. + +השרת מקשיב עכשיו ב-`http://localhost:8080` והלוח ב-`http://localhost:3000`. + +לפריסות בייצור (Postgres מותאם, TLS, reverse proxy), ראו [enterprise-docs/deployment.md](/he/agenteye/deployment). + +--- + +## שלב 3: צרו מפתח API עבור הקולטן + +כל קולטן מאומת עם מפתח API בהיקף. השתמשו ב-`ADMIN_KEY` שהגדרתם בשלב 2 ליצירה של אחד: + +```bash +curl -s -X POST http://localhost:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{"name":"prod-collector","key":"your-collector-secret","permissions":["events:add"]}' +``` + +אתם מספקים את ערך `key` בעצמכם; השתמשו בו בתצורת הקולטן בשלב 4. ראו [enterprise-docs/api-keys.md](/he/agenteye/api-keys) לניהול מפתחות מלא. + +--- + +## שלב 4: התקנת הקולטן + +על כל מכונה המריצה את הסוכנים בתחום הבינה המלאכותית שלכם, התקינו את daemon הקולטן. + +**הורידו את הקובץ הבינארי (Linux x86_64):** + +```bash +VERSION=0.0.1-beta.13 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "collector/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-collector-linux-x86_64' +chmod +x agenteye-collector-linux-x86_64 +sudo mv agenteye-collector-linux-x86_64 /usr/local/bin/agenteye-collector +``` + +> זה מוריד את הבנייה של **Linux x86_64**. עבור macOS (Apple Silicon או Intel), Linux arm64, או Docker / systemd / launchd setup, ראו [collector-installation.md](/he/agenteye/collector-installation), המוצגת ההורדה עבור כל פלטפורמה — הפקודה לעיל מתקינה קובץ בינארי של Linux שלא יפעל במקום אחר. + +**הגדירו:** + +```bash +mkdir -p ~/.agenteye +cat > ~/.agenteye/config.json </…`). + +- **Queries** (`//queries`): התחלו מספריית שאילתות שמורות וניתנות לשימוש חוזר על ה-events והערכות שלכם (presets מובנים בתוספת שלכם)… + +![ספריית השאילתות השמורות: רשת של שאילתות שניתן לשימוש חוזר, גם presets מובנים וגם שאילתות מותאמות אישית](/agenteye/images/queries.png) + + …לאחר מכן פתחו אחת ב-SQL composer כדי לכוונן אותה והריצו אותה עם תוצאות חיות: + +![מחברת שאילתות SQL המריצה שאילתה שמורה, עם סרגל צדדי של סכימה וגריד תוצאות חי](/agenteye/images/query-lab.png) + +- **Dashboards** (`//dashboards`): קבעו שאילתות כ-line, bar, area, או pie tiles לתוך לוחות מחוונים משותפים בהיקף כל הארגון. + +![לוח מחוונים שנבנה משאילתות שמורות: line של events-per-hour, bar של errors-by-type, area chart של latency ו-tokens-by-model](/agenteye/images/dashboard-fleet.png) + +- **Alerts** (`//alerts`): קדמו כל סף לתוך כלל עמוד המודיע לפי דוא"ל, Slack, webhook, או בתוך הלוח. ראו [enterprise-docs/alerts.md](/he/agenteye/alerts). + +--- + +## שלבים הבאים + +- [Deployment](/he/agenteye/deployment): חסנו עבור בייצור +- [API Keys](/he/agenteye/api-keys): נהלו גישה +- [Troubleshooting](/he/agenteye/troubleshooting): אבחנו בעיות \ No newline at end of file diff --git a/docs/he/agenteye/github-token.mdx b/docs/he/agenteye/github-token.mdx new file mode 100644 index 00000000..4eee65c4 --- /dev/null +++ b/docs/he/agenteye/github-token.mdx @@ -0,0 +1,132 @@ +--- +title: "הגדרת Token של GitHub" +description: "תיעוד הגדרת GitHub Token של AgentEye." +--- + + +GitHub Personal Access Token (PAT) היא האישור היחיד שפותח כל artifact של AgentEye. עם token אחד אתה יכול להוריד את תמונות Docker, להוריד binaries של release, והתקן Python wheels, ללא logins לכל קומפוננטה ולא צריך לחלוק סודות. כל ה-artifacts של AgentEye מופצים מ-organization של GitHub בשם `agenteye-enterprise`; כאשר הorganzation שלך מקבל גישה, כל developer או operator יוצר ומחליף את ה-token שלהם, כך שהגישה נשארת auditable וניתן לבטל אותה לפי אדם. + +הגדר את ה-token כמשתנה סביבה והimageidentifier credentials של Docker פעם אחת לכל מכונה: + +```bash +export AGENTEYE_TOKEN= +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +> **הערה על שם משתמש:** GHCR מתעלם משם המשתמש של `docker login` ומבחין רק דרך ה-token, כך שכל ערך לא ריק עובד. התיעוד הזה משתמש `-u x` לקיצור; deployment manifests שיוצרים Kubernetes image-pull secret עשויים להשתמש בשם משתמש תיאורי יותר כמו `agenteye-enterprise`. שניהם מקובלים. + +--- + +## אפשרות A: Classic Token (מומלץ) + +Classic token הוא הבחירה האמינה ביותר עבור AgentEye, מכיוון שה-GHCR `docker login` ו-image-pull flow יש את התמיכה הרחבה ביותר, העקבית ביותר עבור classic tokens. שניים scopes מכסים כל מה שאתה צריך (pulling images והורדת release assets), כך שאתה מבחין פעם אחת ומתקדם ללא בעיות עם registry. אחד מהם, `read:packages`, הוא באמת read-only; השני, `repo`, הוא ה-classic scope היחיד שנותן גישה לprivate release assets, והוא בכוונה רחב — GitHub מגדיר אותו כשליטה מלאה (read and write) של private repositories. + +### 1. יצירת ה-token + +עבור ל-**GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic) → Generate new token (classic)**. + +| שדה | ערך | +|---|---| +| **Note** | `agenteye-` (למשל `agenteye-prod-server`) | +| **Expiration** | הגדר expiry המתאים לפוליטיקת הביטחון שלך; 90 ימים הוא ברירת מחדל סבירה | + +> **הערה על תווית:** GitHub מתייג את השדה הזה **Note** עבור classic tokens ו-**Token name** עבור fine-grained tokens. הם משרתים את אותה מטרה: מזהה קריא לאדם ל审计וביטול מאוחר יותר. + +### 2. בחר scopes + +| Scope | למה זה נדרש | +|---|---| +| `read:packages` | הורדת תמונות Docker מ-`ghcr.io/agenteye-enterprise/` והורדת package assets | +| `repo` | קריאת תוכן private repository, raw files, וrelease assets מ-`agenteye-enterprise/releases`. זה ה-scope הרחב של GitHub "Full control of private repositories" (read and write), לא scope read-only — זה פשוט ה-classic scope היחיד שנותן גישה לprivate release assets | + +לא נדרשים scopes אחרים. + +### 3. צור והעתק את ה-token + +לחץ על **Generate token** והעתק את הערך מיד; הוא מוצג רק פעם אחת. אחסן אותו במנהל הסודות שלך או בסביבה. + +--- + +## אפשרות B: Fine-Grained Token + +Fine-grained tokens מגבילים את הגישה לrepositorys ספציפיים והrights, מה שהופך אותם לאפשרות המינימלית הקרובה ביותר ל-least-privilege. בחר בדרך הזו כאשר פוליטיקת הביטחון של הorganization שלך דורשת fine-grained tokens. + +> **הערה:** התמיכה של GHCR עבור fine-grained tokens פחות עקבית מאשר עבור classic tokens. אם `docker login` או `docker pull` נכשלים לאחר ביצוע שלבים אלה, חזור ל-classic token (אפשרות A). + +### 1. יצירת ה-token + +עבור ל-**GitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokens → Generate new token**. + +| שדה | ערך | +|---|---| +| **Token name** | `agenteye-` (למשל `agenteye-prod-server`) | +| **Expiration** | הגדר expiry המתאים לפוליטיקת הביטחון שלך; 90 ימים הוא ברירת מחדל סבירה | +| **Resource owner** | `agenteye-enterprise` | +| **Repository access** | **Only select repositories** → `agenteye-enterprise/releases` | + +### 2. הגדר repository permissions + +תחת **Permissions → Repository permissions**, הגדר: + +| Permission | Access | +|---|---| +| **Contents** | Read-only | +| **Packages** | Read-only | + +כל ההrights האחרים יכולים להישאר **No access**. + +> **הערה:** אם תמונות הcontainer (`ghcr.io/agenteye-enterprise/...`) פורסמו כorganization-level packages במקום repository-linked packages, Docker login עשוי להיכשל עם repository-scoped permissions לבדם. במקרה זה, הוסף organization-level permission: **Permissions → Organization permissions → Packages: Read-only**. + +### 3. מה כל permission נותן + +| Permission | משמש עבור | +|---|---| +| Contents: Read-only | הורדת `docker-compose.yml`, release binaries, וPython wheels מ-`agenteye-enterprise/releases` | +| Packages: Read-only | הורדת תמונות Docker מ-`ghcr.io/agenteye-enterprise/` | + +### 4. צור והעתק את ה-token + +לחץ על **Generate token** והעתק את הערך מיד; הוא מוצג רק פעם אחת. אחסן אותו במנהל הסודות שלך או בסביבה. + +--- + +## סיבוב Token + +סיבוב tokens לפי לוח זמנים שומר על הגישה auditable ומגביל את blast radius אם credential כלשהו דולף אי פעם. Tokens יכולים גם לפוג או להיות מבוטלים בכל עת, כך שסיבוב הוא הדרך הרגילה להישאר מובחן. לביצוע סיבוב: + +1. צור token חדש באמצעות השלבים לעיל. +2. עדכן `AGENTEYE_TOKEN` בסביבה שלך או במנהל הסודות. +3. בחן מחדש את Docker: `echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin` +4. בטל את ה-token הישן ב-GitHub → Settings → Developer settings → Personal access tokens, ואז פתח את תת-העמוד **Tokens (classic)** או **Fine-grained tokens** התואם לסוג ה-token ומחק אותו. + +--- + +## אימות ה-Token שלך + +אשר שה-token עובד לפני חיבורו לdeployment, כך ששגיאות ביחוד ייצוג יופיעו כאן ולא באמצע rollout. כל פקודה משתמשת באחד ה-scopes לעיל: + +```bash +# Packages scope - הבחן את Docker מול GHCR +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin + +# Contents scope - fetch raw release file +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + https://raw.githubusercontent.com/agenteye-enterprise/releases/main/docker-compose.yml \ + -o /tmp/agenteye-compose-check.yml +``` + +`docker login` מוצלח מאשר את package scope; קובץ שהורד מאשר את contents scope. + +--- + +## Troubleshooting + +| Symptom | סיבה סבירה | פתרון | +|---|---|---| +| `docker login` מחזיר 401 | Token חסר `Packages: Read-only` (fine-grained) או `read:packages` (classic) | הוסף את package scope וצור מחדש | +| `curl` מחזיר 404 ב-raw GitHub URLs | Token חסר `Contents: Read-only` או `repo` scope | הוסף את contents scope וצור מחדש | +| `gh release download` מחזיר 403 | Token לא מורשה ל-`agenteye-enterprise/releases` | אמת שה-repo כלול ב-repository access של fine-grained token, או השתמש ב-classic token עם `repo` scope | +| Token מקובל אך תמונות לא נמצאות | Org-level package permission חסר ב-fine-grained token | הוסף organization-level `Packages: Read-only` permission | + +עבור בעיות גישה, צור קשר עם `support@exosphere.host`. \ No newline at end of file diff --git a/docs/he/agenteye/health-monitoring.mdx b/docs/he/agenteye/health-monitoring.mdx new file mode 100644 index 00000000..82a9b8bd --- /dev/null +++ b/docs/he/agenteye/health-monitoring.mdx @@ -0,0 +1,93 @@ +--- +title: "Health Monitoring" +description: "תיעוד Health Monitoring של AgentEye." +--- + + +דע מתי AgentEye deployment **בעצמו** מושבת או מופחתת, לא רק כשהסוכנים שלך מתנהגים בצורה לא תקינה. הגילוי הוא **Kubernetes-native** ובאופן קריטי, **בלתי תלוי ב-AgentEye**: הוא קורא את מצב הפודים מ-Kubernetes control plane ובודק את התלויות הקשות של AgentEye, כך שהוא עדיין מופעל כאשר השרת, ClickHouse או Postgres הם זה שמושבתים. + +ישנן שתי שכבות. הראשונה מובנית; השנייה היא opt-in. + +## 1. Readiness מודע לתלויות (מובנה) + +השרת חושף שני endpoints probe עם משימות שונות בתכוונין: + +| Endpoint | Probe | בדיקות | Auth | +|---|---|---|---| +| `GET /health` | liveness | התהליך פעיל (תמיד `{"status":"ok"}`) | אף אחד | +| `GET /ready` | readiness | יכול להגיש בעצם: **Postgres + ClickHouse** בנגישות | אף אחד | + +`/ready` מחזיר `200` עם `"status":"ready"` וכל בדיקה `"ok"` כאשר שתי התלויות הקשות בנגישות, ו-`503` עם `"status":"not_ready"` כאשר אחת מהן לא בנגישות. שתי התשובות מכילות בגוף קטן: + +```json +{ "status": "not_ready", + "checks": { "postgres": "ok", "clickhouse": "down", "redis": "not_configured" } } +``` + +Redis הוא cache אופציונלי שהשרת מונמך אחריו, כך שהוא דווח למידע אך **לעולם** לא מכשל readiness. הוא מציג `"ok"` כאשר cache מוגדר ו-`"not_configured"` אחרת; זה לעולם לא `"down"`. + +בהצהרות Kubernetes המצורפות ה-**readiness** probe מצביע על `/ready` ו-**liveness** נשאר על `/health`. ההשפעה: שרת ש-*פועל אך לא יכול להגיע לבסיס הנתונים שלו* מוצא מה-Service ומופיע כ-`NotReady`, מצב שהמדידה של הקלאסטר שלך (למטה) יכולה להזהיר בגינו, בעוד liveness נשאר זול כך שקצר dependency blip לעולם לא מפעיל restart של פוד. ה-probe משתמש בסף כישלון נדיב כך ש-blip לרגע לא מניף רפליקות מחוץ לסיבוב. + +## 2. Pod-failure alerting עם Robusta (opt-in) + +[Robusta](https://github.com/robusta-dev/robusta) הוא Kubernetes-native monitor שצופה בשרת ה-API ופרסם כשלי פודים (`CrashLoopBackOff`, `OOMKilled`, `ImagePullBackOff`, `Pending`/`NotReady`, `Failed`, evictions) ל-Slack. מכיוון שהוא צופה ב-control plane במקום לבקש מ-AgentEye, הוא מזהיר אפילו כאשר AgentEye לא יכול להגיש כלל. + +Robusta משתלם כ-opt-in add-on בחבילת ההוצאה לאור. הפעל אותו עם תרשים Helm סטנדרטי של Robusta וקובץ ערכים קטן כמופיע להלן: + +1. הוסף את מאגר התרשים וקבל **bot token** של Slack (`xoxb-…`) עבור הערוץ: + + ```bash + helm repo add robusta https://robusta-charts.storage.googleapis.com + helm repo update + ``` + + מכיוון שהתצורה להלן שומרת הכל בתוך הקלאסטר + (`disableCloudRouting: true`), הטוקן מגיע מאפליקציית Slack בעצמה מתוקנת: צור אפליקציה ב-`https://api.slack.com/apps`, הוסף את ה-`chat:write` bot scope, התקן אותה לחלל העבודה שלך, העתק את **Bot User OAuth Token** (`xoxb-…`), והזמן את הבוט לערוץ (`/invite @your-app`). + +2. יצור `values.yaml` עם תווית לכל-deployment (`clusterName`) והערוץ Slack שלך, בהיקף ל-`agenteye` namespace: + + ```yaml + clusterName: "acme-prod" # תווית לכל-deployment; מופיעה בכל התראה + enablePrometheusStack: false # pod-crash alerts בלבד; לא metric stack + disableCloudRouting: true # הספק ל-Slack ישירות, בתוך הקלאסטר + sinksConfig: + - slack_sink: + name: vendor_slack + slack_channel: "agenteye-fleet-health" + api_key: "REPLACE_WITH_SLACK_BOT_TOKEN" # xoxb-… (העדף --set או סוד) + scope: + include: + - namespace: [agenteye] # התראות של namespace של AgentEye בלבד; הסר להרחבה + ``` + +3. התקן, תופס `--version` לשחרור תרשים Robusta ידוע-טוב + ([releases](https://github.com/robusta-dev/robusta/releases)) כך שלעולם לא + תתקין תרשים שלא בדוקת: + + ```bash + helm install robusta robusta/robusta \ + --namespace robusta --create-namespace \ + --version \ + -f values.yaml \ + --set sinksConfig[0].slack_sink.api_key=$ROBUSTA_SLACK_TOKEN + ``` + +### מה הוא מדווח + +- **מצב פוד** של Kubernetes (איזה פוד של AgentEye כושל ולמה) וכל **image tag** של פוד, כלומר **גרסת** הרכיב המפעיל. +- **אין נתוני AgentEye event וללא נתוני לקוח** עוזבים אי פעם את הקלאסטר. +- ערכי החבילה מגבילים התראות ל-**`agenteye` namespace**, כך שעומס עבודה לא קשור באותו קלאסטר לא דווח. + +### מקום אחד לכל deployment + +הצבע על כל ה-Robusta של deployment ב-**ערוץ Slack שותף אחד**, כל אחד עם ה-`clusterName` שלו. כל התראה מתויגת בתווית זו, כך שערוץ יחיד מראה את בריאות כל הצי שלך, ותוכל להגיד איזה deployment מושפע במבט אחד. + +### הפסקות קלאסטר כולל + +שומר בתוך-קלאסטר בלבד לא יכול להדווח על **הפסקה של קלאסטר או רשת כולה** +(הוא משבתת עם הקלאסטר). אם אתה צריך את זה, הפעל את ה-**Robusta UI sink** האופציונלי: הגדר `disableCloudRouting: false` והוסף `robusta_sink` (עם token מ-`robusta gen-config`) ל-`sinksConfig`. זה מוסיף לוח מחוונים מצטבר מולטי-קלאסטר וציין כל קלאסטר שמפסיק לבדוק. + +## פתרון בעיות + +ראה את סעיף **Health Monitoring** של +[enterprise-docs/troubleshooting.md](/he/agenteye/troubleshooting) עבור "אין התראות מגיעות" ו-"שרת ממשיך להפוך `NotReady`". \ No newline at end of file diff --git a/docs/he/agenteye/kubernetes-deployment.mdx b/docs/he/agenteye/kubernetes-deployment.mdx new file mode 100644 index 00000000..d7ec0b3a --- /dev/null +++ b/docs/he/agenteye/kubernetes-deployment.mdx @@ -0,0 +1,668 @@ +--- +title: "מדריך פריסה ל-Kubernetes" +description: "תיעוד מדריך פריסה ל-Kubernetes של AgentEye." +--- + +מדריך זה מפרוס את ערימת AgentEye המלאה על אשכול Kubernetes ייעודי: + +- **ClickHouse 24.8** -- אחסן הנתונים הקנוני לאנליטיקה של אירועים והערכות (StatefulSet עם נפח קבוע של 100Gi). נדרש: השרת מסרב להתחיל בלעדיו. +- **PostgreSQL 16** -- אחסן מטא-נתונים ויחסי למארגנויות, מפתחות API, משתמשים, לוחות בקרה, שאילתות שמורות והרשאות (StatefulSet עם נפח קבוע של 50Gi) +- **Redis 7.2** -- מטמון משותף אופציונלי ותשתית הגבלת קצב; השרת ולוח הבקרה מתכלים בחן אם הוא אינו זמין +- **שרת AgentEye** -- Rust API לספיגת אירועים, אנליטיקה וניהול מפתחות (2 העתקים) +- **לוח בקרה AgentEye** -- ממשק משתמש Next.js (2 העתקים) +- **עוזר AI (שירות סוכן)** -- עוזר אופציונלי קריאה-בלבד בתוך לוח הבקרה בפורט 9100; לא פעיל עד שנקודת קצה LLM תעבור תצורה +- **Traefik (ציבורי)** -- בקר ingress לתעבורת כללים, מוגן ב-mTLS +- **Traefik (לוח בקרה)** -- בקר ingress ללוח הבקרה, VPN/רשימת IP-בלבד +- **cert-manager** -- תעודות TLS ו-CA של mTLS +- **CronJob גיבוי** -- יומי של PostgreSQL + ClickHouse משולב ב-03:00 UTC +- **צג חידוש תעודות** -- התראות כאשר תעודות לקוח קרובות לתפוגה + +**זמן משוער:** 60-90 דקות לפריסה ראשונה. + +עבור מודל הפריסה המנוהל בו Exosphere מטפלת בכל זה בשמך, ראה [enterprise-docs/managed-deployment.md](/he/agenteye/managed-deployment). + +--- + +## דרישות מוקדמות + +הרץ כל פקודת אימות לפני התחלה. כל בדיקה חייבת להיות מוצלחת. + +| דרישה | מינימום | פקודת אימות | צפוי | +|---|---|---|---| +| אשכול Kubernetes | 1.27+ | `kubectl version` | Server Version >= v1.27 | +| Kustomize (מלאי עם kubectl) | Kustomize v1.14+ (משלוח בתוך kubectl 1.27+) | `kubectl kustomize --help` | הדפסת טקסט שימוש | +| Helm | v3 | `helm version` | `Version:"v3.x.x"` | +| cluster-admin RBAC | -- | `kubectl auth can-i create namespaces` | `yes` | +| StorageClass ברירת המחדל | -- | `kubectl get storageclass` | לפחות שורה אחת מסומנת `(default)` | +| תמיכת LoadBalancer | -- | תלוי בעננן (EKS, GKE, AKS כולם תומכים בברירת מחדל) | -- | +| GitHub PAT | -- | `echo $AGENTEYE_TOKEN` | לא ריק (ראה [enterprise-docs/github-token.md](/he/agenteye/github-token)) | +| openssl | -- | `openssl version` | OpenSSL 1.x או 3.x | +| דלי אחסון בעננן | -- | ל-PostgreSQL + ClickHouse גיבויים (S3, GCS, או Azure Blob) | -- | + +**גודל אשכול:** מינימום 3 צמתים, 4 vCPU / 8 GB RAM כל אחד. ראה [enterprise-docs/managed-deployment.md](/he/agenteye/managed-deployment) לדרישות מלאות. + +### הרץ את כל הבדיקות בבת אחת + +```bash +echo "--- Prerequisites Check ---" +kubectl version --client -o yaml 2>/dev/null | grep -q gitVersion && echo "PASS: kubectl" || echo "FAIL: kubectl not found" +helm version --short 2>/dev/null | grep -q v3 && echo "PASS: helm v3" || echo "FAIL: helm v3 not found" +kubectl auth can-i create namespaces 2>/dev/null | grep -q yes && echo "PASS: cluster-admin" || echo "FAIL: no cluster-admin" +kubectl get storageclass 2>/dev/null | grep -q default && echo "PASS: default StorageClass" || echo "FAIL: no default StorageClass" +[ -n "$AGENTEYE_TOKEN" ] && echo "PASS: AGENTEYE_TOKEN set" || echo "FAIL: AGENTEYE_TOKEN not set" +openssl version >/dev/null 2>&1 && echo "PASS: openssl" || echo "FAIL: openssl not found" +echo "---" +``` + +### צורת הפריסה + +**נקודת הסיום של ספיגה** מוגשת על כתובת שאתה שולט בה (למשל `ingest.your-company.example`). cert-manager מבקש תעודת TLS המהימנה בציבור מ-Let's Encrypt דרך HTTP-01, כך שמכללים מאומתים את תעודת השרת כנגד חנות ההאמנה של המערכת, ללא PIN CA לכל לקוח. + +**נקודת הסיום של לוח הבקרה** עובדת בדרך זהה: היא מוגשת על כתובת שנייה שאתה שולט בה (למשל `agenteye.your-company.example`) המצביעה על LoadBalancer של Traefik של לוח הבקרה, ו-cert-manager מנפיק את תעודת Let's Encrypt שלה דרך LoadBalancer זה. דפדפנים מקבלים תעודה מהימנה ללא אזהרה. + +> **הנפקת תעודות וחידוש אימות דרך HTTP-01**, כך שגם LoadBalancers חייבים להיות ניתנים להשגה מהאינטרנט הציבורי בפורט 80. אם אתה צריך הגבלת IP ללוח הבקרה LoadBalancer, תאם עם תמיכה תחילה על פותר DNS-01 -- אחרת חידושים נכשלים בשקט ותעודות מתפוגות. + +--- + +## קבל את המניפסטים + +```bash +git clone https://x:${AGENTEYE_TOKEN}@github.com/agenteye-enterprise/releases.git +cd releases/deploy +``` + +**בדוק את זה:** + +```bash +ls base/kustomization.yaml +``` + +צפוי: הקובץ קיים. אם לא, ההעתקה נכשלה -- בדוק את `AGENTEYE_TOKEN` שלך. + +**מבנה ספריה:** + +``` +deploy/ + base/ Kustomize בסיס משותף (כל משאבי K8s) + overlays/ עקיפות ספציפיות לאשכול (תגי תמונה, כתובות, משאבים) + third-party/ ערכי Helm עבור Traefik, cert-manager, ו-(opt-in) Robusta monitoring +``` + +**הבסיס** מכיל כל משאב הנדרש לפריסה מלאה, כולל תעודות Let's Encrypt לשני שמות המשתמשים הציבוריים שתעבור תצורה בשלב 3.1. **עקיפה** תיקע את הבסיס לסביבה ספציפית (למשל תגי תמונה מותאמים, מגבלות משאבים, חיווט env). ספריית **third-party** מכילה קובצי ערכי Helm עבור תשתיות חיצוניות. + +> **ניטור בריאות (אופציונלי):** הבדיקה הערות של השרת כבר משקפת בריאות Postgres + ClickHouse, ו-`third-party/robusta/` מוסיף התראות כשל pod מובנות-Kubernetes opt-in ל-Slack. ראה [enterprise-docs/health-monitoring.md](/he/agenteye/health-monitoring). + +--- + +## שלב 1 -- תשתיות צד שלישי (~30 דקות) + +### 1.1 התקן את cert-manager + +cert-manager מנהל תעודות TLS עבור HTTPS וה-CA הפרטי המשמש ללקוחות mTLS. + +```bash +helm repo add jetstack https://charts.jetstack.io +helm repo update + +helm install cert-manager jetstack/cert-manager \ + --namespace cert-manager --create-namespace \ + --set crds.install=true +``` + +**בדוק את זה:** + +```bash +kubectl get pods -n cert-manager +``` + +צפוי: 3 פודים הכל `Running` -- `cert-manager`, `cert-manager-cainjector`, `cert-manager-webhook`. + +```bash +kubectl get crds | grep cert-manager +``` + +צפוי: לפחות `certificates.cert-manager.io`, `clusterissuers.cert-manager.io`, `issuers.cert-manager.io`. + +**אם נכשל:** פודים ב-`CrashLoopBackOff` בדרך כלל פירושו ש-CRDs לא התקנו. הרץ מחדש עם `--set crds.install=true`. אם פודי webhook נכשלים readiness, חכה 30 שניות ובדוק שוב -- זה יכול לקחת רגע להתחיל. + +--- + +### 1.2 התקן את Traefik -- בקר Ingest ציבורי + +מופע Traefik זה טוען את תעבורת מכללים על LoadBalancer **חיצוני**. זה מסיים TLS וכופה mTLS (אימות תעודת לקוח) בנקודת הסיום של ספיגה. + +```bash +helm repo add traefik https://traefik.github.io/charts +helm repo update + +helm install traefik-public traefik/traefik \ + --namespace traefik-public --create-namespace \ + --version 39.0.8 \ + -f third-party/traefik/values-public.yaml +``` + +**בדוק את זה:** + +```bash +kubectl get pods -n traefik-public +``` + +צפוי: 1 פוד `Running`. + +```bash +kubectl get ingressclass traefik-public +``` + +צפוי: ה-IngressClass קיים (זה לא מחלקת ברירת המחדל). + +**אם נכשל:** בדוק `kubectl describe pod -n traefik-public ` לשגיאות pull תמונה או אילוצי משאבים. + +--- + +### 1.3 התקן את Traefik -- בקר לוח בקרה + +מופע Traefik זה מגדיש את לוח הבקרה ב-LoadBalancer ייעודי, מוגבל על ידי רשימת IP. + +> **שני מנגנוני רשימה הלבנה משלחים עבור מופע זה.** מדריך זה משתמש ב-`values-dashboard.yaml`, המגביל גישה עם שדה `service.loadBalancerSourceRanges` הניידים. מקביל `values-internal.yaml` גם מסופק לסביבות AWS המעדיפות את הביאור `service.beta.kubernetes.io/aws-load-balancer-source-ranges` במקום. בחר אחד והשתמש בו בעקביות; השלבים להלן מניחים `values-dashboard.yaml`. + +**לפני ההתקנה**, ערוך את `third-party/traefik/values-dashboard.yaml` כדי להגדיר את כתובות ה-IP המותרות. השדה `loadBalancerSourceRanges` שולט על אילו IP יכולים להגיע ללוח הבקרה. כברירת מחדל הוא מוגדר ל-`0.0.0.0/0` (כל ה-IP); הגבל אותו ל-VPN, משרד או ה-IPs של יציאה ידועות שלך. + +#### הוסף IP יחיד לרשימה הלבנה + +```yaml +service: + loadBalancerSourceRanges: + - "/32" +``` + +#### הוסף כמה IP לרשימה הלבנה + +הוסף ערך אחד ל-IP או בלוק CIDR. סיומת `/32` תואמת כתובת IPv4 יחידה; בלוק CIDR (למשל `/24`) תואמת טווח. אתה יכול לערבב IP בודדים וטווחים בחופשיות: + +```yaml +service: + loadBalancerSourceRanges: + - "203.0.113.10/32" # office gateway + - "203.0.113.11/32" # backup office gateway + - "198.51.100.0/24" # VPN pool + - "192.0.2.50/32" # on-call engineer home IP +``` + +טיפים כאשר מתחזקים את הרשימה: + +- שמור ערך אחד לכל שורה והוסף הערה קצרה `#` המזהה כל בעל IP או תכלית; זה מה שמפעילים עתידיים משתמשים בו כדי להחליט אם ערך עדיין דרוש. +- השתמש תמיד בסימן CIDR. IP חשוף כמו `203.0.113.10` נדחה על ידי ספק הענן; השתמש ב-`203.0.113.10/32`. +- עבור טווחי IPv6, השתמש בערך שקול `/128` (כתובת יחידה) או CIDR גדול יותר, למשל `2001:db8::1/128`. לא כל ספקי עננן תומכים בטווחי מקור IPv6; בדוק את תיעוד LoadBalancer של ספק שלך. +- הרשימה היא **OR**: התעבורה מותרת אם המקור תואם כל ערך. + +לאחר עריכת הקובץ, המשך ל-`helm install` להלן. אם הבקר כבר התקנו, הרץ `helm upgrade` עם אותות הדגלים, או patch את ה-Service בזמן ריצה (קטע הבא). + +#### עדכן את רשימת ההלבנה בזמן ריצה + +אתה יכול לשנות את ה-IPs המותרים ללא שדרוג Helm על ידי patching Service ישירות. **ה-patch מחליף את כל הרשימה**; הכלול תמיד כל IP שברצונך לשמור, לא רק את החדש. + +כדי להחליף את הרשימה בסט IP חדש: + +```bash +kubectl patch svc traefik-dashboard -n traefik-dashboard \ + -p '{"spec":{"loadBalancerSourceRanges":["203.0.113.10/32","198.51.100.0/24","192.0.2.50/32"]}}' +``` + +כדי **להוסיף** בבטחה IP מבלי לאבד ערכים קיימים, קרא תחילה את הרשימה הנוכחית, ואז תיקע עם הסט המשולב: + +```bash +# 1. הצג את רשימת ההלבנה הנוכחית +kubectl get svc traefik-dashboard -n traefik-dashboard \ + -o jsonpath='{.spec.loadBalancerSourceRanges}' + +# 2. Patch עם הרשימה המלאה כולל ה-IP החדש +kubectl patch svc traefik-dashboard -n traefik-dashboard \ + -p '{"spec":{"loadBalancerSourceRanges":["/32","/32","/32"]}}' +``` + +> Patches בזמן ריצה אינם מתמשכים חזרה ל-`values-dashboard.yaml`. כדי לשמור את השינוי על פני שדרוגי Helm עתידיים, עדכן גם את קובץ הערכים ותחייב אותו. + +ואז התקן: + +```bash +helm install traefik-dashboard traefik/traefik \ + --namespace traefik-dashboard --create-namespace \ + --version 39.0.8 \ + -f third-party/traefik/values-dashboard.yaml +``` + +**בדוק את זה:** + +```bash +kubectl get pods -n traefik-dashboard +``` + +צפוי: 1 פוד `Running`. + +```bash +kubectl get ingressclass traefik-dashboard +``` + +צפוי: ה-IngressClass קיים. + +--- + +### 1.4 חכה ל-LoadBalancers + +שני מופעי Traefik צריכים IP חיצוניים לפני המשך. + +```bash +kubectl get svc -n traefik-public +kubectl get svc -n traefik-dashboard +``` + +**בדוק את זה:** שתי השירותים מציגים `EXTERNAL-IP` (לא ``). + +אם עדיין ממתין, צפה להקצאה: + +```bash +kubectl get svc -n traefik-public -w +``` + +לחץ על `Ctrl+C` ברגע שה-IP מופיע. הקצאת IP בדרך כלל לוקחת 2-5 דקות. + +**אם נכשל:** `` אחרי 10 דקות בדרך כלל פירושו שספק הענן לא יכול להתקין LoadBalancer. בדוק: תגי תת-רשת (EKS דורש `kubernetes.io/role/elb`), תצורת VPC, מכסות שירות, וכי ההערה הנכונה של LB פנימי מוגדרת לדוגמה הפנימית. + +--- + +## שלב 2 -- יצירת סודות (~10 דקות) + +כל הסודות נוצרים באופן ידני לפני פריסת היישום. זה מבטיח שערכים רגישים אינם מופיעים בקבצי מניפסט. + +### 2.1 יצור את ה-namespace + +```bash +kubectl create namespace agenteye +``` + +**בדוק את זה:** + +```bash +kubectl get namespace agenteye +``` + +צפוי: סטטוס `Active`. + +--- + +### 2.2 סוד pull תמונה + +סוד זה מאומת עם `ghcr.io` כדי לשלוף את תמונות המיכל של AgentEye. ראה [enterprise-docs/github-token.md](/he/agenteye/github-token) כיצד לייצר את ה-PAT שלך. + +```bash +kubectl create secret docker-registry agenteye-image-pull \ + --namespace agenteye \ + --docker-server=ghcr.io \ + --docker-username=agenteye-enterprise \ + --docker-password="${AGENTEYE_TOKEN}" +``` + +**בדוק את זה:** + +```bash +kubectl get secret agenteye-image-pull -n agenteye -o jsonpath='{.type}' +``` + +צפוי: `kubernetes.io/dockerconfigjson`. + +**בדוק את זה (עמוק)** -- אימות שהטוקן יכול בעצם לשלוף תמונות: + +השתמש בתג תמונת `server` המעוגן בקובץ `kustomization.yaml` של overlay שלך (כרגע `v0.0.1-beta.48` גם בשכבה `acme` המלאה וגם בפריסה בסיס). החלף את התג למטה לזה שאתה פורס כך בדיקה זו לא תסחוף על פני הוצאות. + +```bash +kubectl run test-pull \ + --image=ghcr.io/agenteye-enterprise/server:v0.0.1-beta.48 \ + --overrides='{"spec":{"imagePullSecrets":[{"name":"agenteye-image-pull"}]}}' \ + --restart=Never -n agenteye --command -- echo ok + +# חכה כמה שניות לה-pull, ואז: +kubectl logs test-pull -n agenteye +kubectl delete pod test-pull -n agenteye +``` + +צפוי: `ok` מודפס ברישומים. + +**אם נכשל:** `ErrImagePull` או `401 Unauthorized` פירושו ש-PAT אינו תקף או חסר `read:packages` היקף. בדוק מחדש [enterprise-docs/github-token.md](/he/agenteye/github-token). + +--- + +### 2.3 אישורי PostgreSQL + +```bash +POSTGRES_PASSWORD=$(openssl rand -hex 24) + +kubectl create secret generic agenteye-postgres \ + --namespace agenteye \ + --from-literal=POSTGRES_USER=postgres \ + --from-literal=POSTGRES_PASSWORD="${POSTGRES_PASSWORD}" \ + --from-literal=POSTGRES_DB=agenteye +``` + +> **חשוב:** אנחנו משתמשים ב-`-hex` (לא `-base64`) כדי ליצור את הסיסמה. פלט Base64 יכול להכיל `+`, `/` ו-`=` אשר שוברים את מחרוזת חיבור `DATABASE_URL`. ראה [enterprise-docs/troubleshooting.md](/he/agenteye/troubleshooting) לפרטים. + +> **שמור `POSTGRES_PASSWORD` במנהל הסודות שלך מיד.** תצטרך אותו אם אי פעם תשחזר מגיבוי או תתחבר ישירות למסד הנתונים. + +**בדוק את זה:** + +```bash +kubectl get secret agenteye-postgres -n agenteye +``` + +צפוי: הסוד קיים. + +```bash +kubectl get secret agenteye-postgres -n agenteye \ + -o jsonpath='{.data.POSTGRES_PASSWORD}' | base64 -d | wc -c +``` + +צפוי: `48` (24 בתים hex = 48 תווים). + +--- + +### 2.4 מפתח API מנהל + +```bash +ADMIN_KEY=$(openssl rand -hex 32) + +kubectl create secret generic agenteye-admin-key \ + --namespace agenteye \ + --from-literal=ADMIN_KEY="${ADMIN_KEY}" +``` + +המפתח של המנהל הוא אישור ההתחלה. השרת upserts אותו עם הרשאות מלאות בכל הפעלה. השתמש בו כדי ליצור מפתחות מכללים בעלי היקף בשלב 7. ראה [enterprise-docs/api-keys.md](/he/agenteye/api-keys) עבור מודל ההרשאות המלא. + +> **שמור `ADMIN_KEY` במנהל הסודות שלך מיד.** + +**בדוק את זה:** + +```bash +kubectl get secret agenteye-admin-key -n agenteye +``` + +צפוי: הסוד קיים. + +--- + +### 2.5 תצורת אימות (כניסת לוח בקרה) + +לוח הבקרה משתמש ב-OTP של דוא"ל + ל-כניסת משתמש. ללא סוד זה השרת עדיין מתחיל ונתיב `ADMIN_KEY` API שמור עובד, אך **לא משתמש יכול להיכנס דרך ממשק ה-משתמש**. + +כל המפתחות מיוחס כ-`optional: true` במניפסט הבסיס, כך סודות חלקיים (או ללא סוד בכלל) בסדר; השרת חוזר לערכי ברירת המחדל המתועדים. פריסת הכל לסוד `agenteye-auth` אחד משמרת את פני המשטח של auth ניתנת להחלפה במקום אחד. + +```bash +kubectl create secret generic agenteye-auth \ + --namespace agenteye \ + --from-literal=ADMIN_EMAIL="admin@yourcompany.com" \ + --from-literal=ALLOWED_EMAILS="*@yourcompany.com" \ + --from-literal=SMTP_HOST="smtp.yourprovider.com" \ + --from-literal=SMTP_PORT="587" \ + --from-literal=SMTP_USERNAME="your-smtp-user" \ + --from-literal=SMTP_PASSWORD="your-smtp-password" \ + --from-literal=SMTP_FROM="noreply@yourcompany.com" \ + --from-literal=SMTP_TLS="starttls" \ + --from-literal=DEFAULT_ORG_NAME="Acme Corp" \ + --from-literal=DEFAULT_ORG_SLUG="acme" +``` + +| מפתח | תכלית | +|---|---| +| `ADMIN_EMAIL` | משתמש מנהל בתחום. Upserted בכל הפעלה עם הרשאות מלאות והוגן מחיקה/עריכת הרשאות דרך לוח הבקרה. ללא זה, לא מנהל זורע וכניסה ראשונה בלתי אפשרית. | +| `ALLOWED_EMAILS` | רשימת הלבנה מופרדת בפסיקים. תומך כתובות מדויקות (`user@example.com`) וכללי תחום (`*@example.com`). ללא זה, **לא משתמש יכול להיכנס או להיווצר**. | +| `SMTP_HOST`, `SMTP_PORT`, `SMTP_USERNAME`, `SMTP_PASSWORD`, `SMTP_FROM` | ממסר SMTP לשליחת קודי OTP. אם `SMTP_HOST` אינו מוגדר, קודי OTP מוגדלים ל-stdout של השרת במקום שליחה בדוא"ל (שימושי לבדיקות smoke ראשונות-בוט). ספק את כל המפתחות של SMTP ביחד להפקת דוא"ל אמיתית. | +| `SMTP_TLS` | אחד מ-`starttls` (ברירת מחדל), `tls`, או `none`. | +| `DEFAULT_ORG_NAME`, `DEFAULT_ORG_SLUG` | אופציונלי. תן למארגנות `default` המובנות שם תצוגה ידידותי וחלקאי URL כך זה חי בדוגמה `/acme` במקום `/default`. הוחל **בבוט ראשון בלבד**; ברגע שתשנה את שם המארגנות עם `agenteye-orgctl org rename` (ראה §7.6) אלה יתעלמו. ה-slug חייב להיות 1-40 alphanumerics קטנים עם מקצועות פנימיים יחידים. השאר שניהם לא מוגדרים כדי לשמור על `default` גנרי. | + +> **שמור את אישורי SMTP במנהל הסודות שלך.** + +**בדוק את זה:** + +```bash +kubectl get secret agenteye-auth -n agenteye \ + -o jsonpath='{.data}' | grep -o '"[A-Z_]*"' | sort -u +``` + +צפוי: המפתחות שהגדרת מופיעים בפלט. + +--- + +### 2.6 מפתח בידוד מארגנות מרובות דיירות (אופציונלי) + +דלג זה לפריסה בעלת דיירת אחת; השרת רץ על בסיס dev בנוי שכן ומגדיש את המארגנות `default` בסדר. **לפני שתיצור מארגנות שנייה**, קבע חזק, ערך `ORG_CH_SECRET` יציב: סיסמת ClickHouse של כל מארגנות נגזרת כ-`HMAC(ORG_CH_SECRET, org_id)`, אז ה-dev בנוי בציבור ידוע ייתן אישורים מובנעים הנגזרים לפי מארגנות. פקודת `agenteye-orgctl org create` (ראה [§7.6 מארגנויות Provision](#76-provision-organizations-multi-tenant)) מסרב לרוץ בזמן שהשרת עדיין ב-dev בנוי ברירת מחדל. + +```bash +kubectl create secret generic agenteye-org-ch-secret \ + --namespace agenteye \ + --from-literal=ORG_CH_SECRET="$(openssl rand -base64 48)" + +# הזז את השרת כך זה בוחר את הערך החדש. +kubectl -n agenteye rollout restart deployment/server +``` + +השרת קורא זה דרך `secretKeyRef` **אופציונלי**, אז אשכול בעל דיירת אחד שלעולם לא יוצר זה עדיין בוטס בדרך כלל. שמור את הערך **יציב וזהה על פני כל העתקים**; סיבוב זה מבטל סיסמת ClickHouse הנגזרת של כל מארגנות עד פעם הבוטה ההבאה תשלים מחדש (יציאה מחדש גלגלת עם הערך עקבי במקום כל מקום מרפא זה). ראה `deploy/base/server/secret.example.yaml`. + +> **שמור `ORG_CH_SECRET` במנהל הסודות שלך וא"ל לסובב אותו בזלזול.** + +--- + +### 2.7 אימות כל הסודות + +```bash +kubectl get secrets -n agenteye -o custom-columns='NAME:.metadata.name,TYPE:.type' +``` + +פלט צפוי (בין כל סודות ברירת המחדל): + +``` +NAME TYPE +agenteye-admin-key Opaque +agenteye-auth Opaque +agenteye-image-pull kubernetes.io/dockerconfigjson +agenteye-postgres Opaque +agenteye-org-ch-secret Opaque # רק אם השלמת §2.6 (מרובה דיירות) +``` + +ארבעת הסודות הליבה (`agenteye-admin-key`, `agenteye-auth`, `agenteye-image-pull`, `agenteye-postgres`) חייבים להיות נוכחים לפני המשך. `agenteye-org-ch-secret` נדרש רק לפריסות מרובות דיירות (ראה §2.6). + +--- + +## שלב 3 -- פרוס את היישום (~5 דקות) + +### 3.1 הגדר את שמות המשתמשים הציבוריים + +cert-manager צריך את שמות המשתמשים של ספיגה ולוח בקרה לפני שזה יכול לבקש תעודות Let's Encrypt שלהם. העתק את התבנית והגדר שניהם: + +```bash +cp base/certificates/domain.env.example base/certificates/domain.env +# ערוך base/certificates/domain.env והגדר: +# INGEST_DOMAIN=ingest.your-company.example (resolves to the public Traefik LB) +# DASHBOARD_DOMAIN=agenteye.your-company.example (resolves to the dashboard Traefik LB) +``` + +`domain.env` הוא gitignored; זה נשאר מקומי לכל פריסה. כישור kustomize נכשל בקול אם כל מפתח חסר. + +> **DNS חייב להיפתר תחילה.** אתה לא צריך להצביע DNS בעדיין בעת LBs (הם לא קיימים עד שלב 1.2 שלם), אך הנפקת ACME בשלב 3.2 יישנה עד כל כתובת המשתמש מיפוי ל-LoadBalancer שלה. אתה יכול להגדיר DNS עכשיו (באמצעות שם המשתמשים של הלוח המחזיקים בשלב 1.4) או להמשיך והוסף את הרשומות בשלב 4. + +--- + +### 3.2 החל מניפסטים + +החל את הבסיס ישירות לדוגמה רטובה, או overlay אם חיתכת אחד לסביבה זו (overlays פשוט תגי תמונה pin, משתנים env, ומגבלות משאבים; הם יורשים מינויי תעודות של הבסיס ותיתור): + +```bash +kubectl apply -k base/ +# או +kubectl apply -k overlays// +``` + +overlay כולל את הבסיס באופן אוטומטי; החל אחד, לא שניהם. + +--- + +### 3.3 חכה לפודים + +```bash +kubectl wait --for=condition=Ready pod -l 'app in (server,dashboard,postgres,clickhouse)' \ + -n agenteye --timeout=180s +``` + +ההמתנה מוגבלת לפודי מישור נתונים ליבה. הפודים אופציוניים `agent` (עוזר AI) ו-`redis` באים בצדם; העוזר נשאר לא פעיל עד שתספק את נקודת הקצה שלו של LLM (ראה [enterprise-docs/assistant.md](/he/agenteye/assistant)), Redis היא מטמון best-effort, אז לא צריך שניים להיות Ready עבור הפלטפורמה לגדיש תעבורה. + +**בדוק את זה:** + +```bash +kubectl get pods -n agenteye +``` + +צפוי (הפודים אופציוניים `agent` ו-`redis` גם מופיעים והשגות `Running`): + +``` +NAME READY STATUS RESTARTS AGE +agent-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +clickhouse-0 1/1 Running 0 ... +dashboard-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +dashboard-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +postgres-0 1/1 Running 0 ... +redis-0 1/1 Running 0 ... +server-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +server-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +``` + +**אם נכשל:** + +| סטטוס פוד | סיבה סבירה | פקודת Debug | +|---|---|---| +| `ImagePullBackOff` | סוד pull תמונה גרוע או PAT | `kubectl describe pod -n agenteye` | +| `CrashLoopBackOff` | משתנים env גרועים (למשל DATABASE_URL) | `kubectl logs -n agenteye` | +| `Pending` | CPU/זיכרון בלתי מספיק או אין צמתים | `kubectl describe pod -n agenteye` (בדוק אירועים) | + +--- + +### 3.4 אימות אחסון + +```bash +kubectl get pvc -n agenteye +``` + +צפוי, שניהם עם סטטוס `Bound`: + +| PVC | קיבולת | גב | +|---|---|---| +| `postgres-data-postgres-0` | `50Gi` | אחסן PostgreSQL יחסי/metadata | +| `clickhouse-data-clickhouse-0` | `100Gi` | אחסן ClickHouse אירועים + הערכות אנליטיקה | + +PVC `redis-data-redis-0` (1Gi) גם מופיע עבור המטמון אופציונלי. + +**אם נכשל:** `Pending` פירושו שום StorageClass יכול להתקין את הנפח. בדוק `kubectl get storageclass` וודא ברירת מחדל קיימת. לייצור, חפץ את נפח ClickHouse ל-StorageClass SSD מהיר (למשל gp3 ב-AWS, pd-ssd ב-GCP); תפוקת תופעה סובלת על דיסקים איטיים. + +--- + +### 3.5 תעודות אימות + +```bash +kubectl get certificates -n agenteye +``` + +צפוי: 3 תעודות, הכל `Ready: True`: + +| שם | מנפיק | תכלית | +|---|---|---| +| `mtls-ca` | `selfsigned` | CA פרטי לנפיקת תעודות לקוח mTLS (תוקף 10 שנים) | +| `ingest-tls` | `letsencrypt-prod` | תעודת TLS ציבורית עבור נקודת הסיום של ספיגה (90 יום, חידוש אוטומטי) | +| `dashboard-tls` | `letsencrypt-prod` | תעודת TLS ציבורית עבור לוח הבקרה (90 יום, חידוש אוטומטי) | + +**אם `ingest-tls` או `dashboard-tls` אינו Ready:** + +`kubectl describe certificate -n agenteye` וקרא את האירועים. הסיבות הנפוצות: + +- **DNS עדיין לא מצביע בעדיין בלוח הבקרה.** Let's Encrypt מיפוי כתובת המשתמש והכה בפורט 80 כדי לאמת -- `INGEST_DOMAIN` חייב מיפוי ל-LB ציבורי, `DASHBOARD_DOMAIN` ל-LB לוח הבקרה. עד CNAME/Alias מתפשט, ההזמנה נשאר `pending`. ברגע DNS נכון, cert-manager משנה באופן אוטומטי (אין צורך למחוק את Certificate). +- **כתובת משתמש לא החלפה.** אם `dnsNames` עדיין קורא `INGEST_DOMAIN_PLACEHOLDER` / `DASHBOARD_DOMAIN_PLACEHOLDER`, דילגת על שלב 3.1 -- יצור `base/certificates/domain.env` וההחל מחדש. +- **לוח הבקרה Traefik לא יכול לגדיש את אתגר** (`dashboard-tls` בלבד). מופע לוח בקרה Traefik חייב להתקנו עם קובץ ערכים משלוח (שלב 1.2), המאפשר ספק Ingress כעמית אשר גדיש אתגר HTTP-01 של cert-manager. דוגמה התקנו ללא זה משאיר אתגר ללא מסלול וההזמנה `pending` לעולם. + +**אם `mtls-ca` אינו Ready:** cert-manager עצמו לא בריא. בדוק מחדש פודי cert-manager משלב 1.1. + +--- + +### 3.6 אימות CronJobs + +```bash +kubectl get cronjobs -n agenteye +``` + +צפוי: + +| שם | לוח זמנים | תכלית | +|---|---|---| +| `agenteye-backup` | `0 3 * * *` | יומי Postgres + ClickHouse גיבוי ב-03:00 UTC | +| `cert-renewal-check` | `0 3,15 * * *` | התראות תפוגת תעודות ב-03:00 ו-15:00 UTC | + +--- + +### 3.7 אימות השרת הופעל בהצלחה + +```bash +kubectl logs -n agenteye -l app=server --tail=20 +``` + +**בדוק את זה:** חפש קו הפעלה המציע השרת מקשיב בפורט 8080. לא צריך להיות שגיאות חיבור בסיס נתונים (השרת דורש גם PostgreSQL וגם ClickHouse להיות ניתנים להשגה לפני זה דו"ח Ready). + +**אם נכשל:** הסיבה הנפוצה ביותר היא `POSTGRES_PASSWORD` מכיל תווים בעלי URL לא בטוחים שוברים את `DATABASE_URL`. ראה [enterprise-docs/troubleshooting.md](/he/agenteye/troubleshooting). + +--- + +### 3.8 אימות לוח בקרה מחובר לשרת + +```bash +kubectl logs -n agenteye -l app=dashboard --tail=20 +``` + +**בדוק את זה:** חפש `Ready` בפלט ללא `ECONNREFUSED` או שגיאות דומות. + +**אם נכשל:** בדוק ש-`server` Service קיים (`kubectl get svc server -n agenteye`) וכי `AGENTEYE_SERVER_URL` מוגדר ל-`http://server:8080` בפריסת לוח הבקרה. + +--- + +## שלב 4 -- גישה ברשת (~5 דקות) + +### 4.1 קחו כתובות LoadBalancer + +```bash +PUBLIC_IP=$(kubectl get svc -n traefik-public \ + -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') + +INTERNAL_IP=$(kubectl get svc -n traefik-dashboard \ + -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') +``` + +> ב-AWS EKS, LoadBalancers חוזרים שם משתמש במקום IP. החלף `.ip` עם `.hostname` בפקודות למעלה. + +**בדוק את זה:** + +```bash +echo "Public (ingest): $PUBLIC_IP" +echo "Internal (dashboard): $INTERNAL_IP" +``` + +שניהם חייבים להיות לא ריקים. + +--- + +### 4.2 הצב DNS בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיין בעדיים LoadBalancers בנקודות הסיום שלהם -- `INGEST_DOMAIN` לבקר Traefik **ציבורי** LB, `DASHBOARD_DOMAIN` לבקר Traefik **לוח בקרה** LB: + +- **AWS Route 53:** רשומת `A` עם `Alias = Yes`, קביעת mục tiêu = LB שם משתמש. אל תשתמש ב-A פשוט → IP; ELB IPs מסתובבות. +- **ספק אחר:** `CNAME` מכתובת המשתמש ל-LB שם משתמש. + +אימות: + +```bash +dig +short ingest.your-company.example +dig +short agenteye.your-company.example +``` + +צריך החזיר את אותן כתובות כמו `$PUBLIC_IP` ו-`$INTERNAL_IP` בהתאמה (או, ב-EKS, לפתור ל-`*.elb.amazonaws.com` אותו בעצם אם). + +ברגע DNS מיפוי, cert-manager מסיים ההזמנות ACME המנוהלות מ-3.5 בדקה אחת. הרץ מחדש `kubectl get \ No newline at end of file diff --git a/docs/he/agenteye/managed-deployment.mdx b/docs/he/agenteye/managed-deployment.mdx new file mode 100644 index 00000000..8601de37 --- /dev/null +++ b/docs/he/agenteye/managed-deployment.mdx @@ -0,0 +1,171 @@ +--- +title: "פריסה מנוהלת בקלסטר Kubernetes שלך" +description: "תיעוד פריסה מנוהלת של AgentEye בקלסטר Kubernetes שלך." +--- + + +AgentEye היא פלטפורמת תצפית והערכה בעלות עצמית עבור סוכנים AI ו-LLM. היא תופסת סשנים של סוכנים, קריאות כלים, בקשות מודלים וטעויות, הופכת אותם לניתוחים והערכות ניתנות לחיפוש, ומציגה את התוצאות בדוח מחוונים עם עוזר AI קריאה בלבד אופציונלי. + +בדגם הפריסה המנוהלת, אתה מספק קלסטר Kubernetes ייעודי ו-Exosphere מפעילה את הפלטפורמה המלאה בתוכו, מפרסת, מוגדרת, מפעילה, מגבה וחידוש כל רכיב מטעמך. הצוות שלך מקבל את ערך הפלטפורמה (נראות סוכנים, ניתוח, הערכה והעוזר האופציונלי) ללא הפעלת מסדי נתונים, תעודות או שדרוגים. כל הנתונים נשארים בתוך חשבון הענן שלך. + +--- + +## דרישות מקדימות + +- **GitHub PAT** למשיכת תמונות קונטיינר והורדת קובצי אחסון (ראה [הגדרת אסימון GitHub](/he/agenteye/github-token)) +- **קלסטר Kubernetes ייעודי** (ראה דרישות להלן) +- **דלי אחסון** לגיבויי מסדי נתונים +- **חיבור רשת**: יציאה 443 כנכנס לאיזן העומס של הקלסטר + +--- + +## שלב 1: הצבת קלסטר Kubernetes ייעודי + +צור קלסטר Kubernetes ייעודי עבור AgentEye. הוא לא צריך להיות משותף עם עומסי עבודה אחרים, כך שהפלטפורמה המלאה (שירותי יישום, מסדי נתונים, ניתוח ואחסון זמני) פועלת בבידוד ללא השפעה על התשתית הקיימת שלך. + +| דרישה | פרטים | +|---|---| +| **הפצה** | כל Kubernetes עומד בתנאים: EKS, GKE, AKS, או בניהול עצמי | +| **גרסה** | 1.27 ואילך | +| **מאגר צמתים** | מינימום: **3 צמתים, 4 vCPU / 8 GB RAM לכל אחד** (מופעים סטנדרטיים למטרה כללית) | +| **אחסון** | StorageClass ברירת מחדל המספק כרכים בלוקיים (לדוגמה `gp3` ב-AWS, `pd-ssd` ב-GCP) | +| **איזן עומס** | הקלסטר חייב להיות מסוגל להספיק שירותי LoadBalancer בענן (ברירת מחדל ב-EKS, GKE, AKS) | + +> Exosphere מותקנת וניהול הכל בתוך הקלסטר: בקרי כניסה, תעודות TLS, מסדי נתונים, אחסון זמני, ניטור וכל פריסות היישומים. + +--- + +## שלב 2: הענקת גישה לצוות AgentEye + +Exosphere זקוקה לגישת cluster-admin (או שקיל RBAC רחב שווה) כדי לנהל מרחבי שמות, הגדרות משאבים מותאמות, בקרי כניסה וממספקי אחסון. + +| דרישה | פרטים | +|---|---| +| **שיטת גישה** | תפקיד IAM (מומלץ עבור EKS/GKE), kubeconfig, או גישה מבוססת SSO | +| **VPN / bastion** | אם שרת ה-Kubernetes API פרטי, ספק עדויות VPN או גישה bastion לצוות הפעולות של Exosphere | + +--- + +## שלב 3: הגדרת חיבור רשת + +צוות הרשת שלך צריך לאפשר תעבורה כנכנסת על **יציאה 443** לאיזני העומס של הקלסטר. הפריסה מפעילה שני איזני עומס נפרדים: אחד להספקת אירוע (מוגן ב-mTLS) ואחד לדוח המחוונים: + +| תעבורה | מקור | יעד | ביטחון | +|---|---|---|---| +| **הספקת אירוע** | תרגולי אספן בקלסטרים שלך | Ingest LoadBalancer, יציאה 443 | mTLS (תעודת לקוח) + מפתח API | +| **דוח מחוונים** | דפדפני מפתחים | Dashboard LoadBalancer, יציאה 443 | HTTPS בדומיין שלך, כניסה חד-פעמית OTP ללא סיסמה דרך אימייל | + +נקודת הספקה מוגנת ב-TLS הדדי; אספנים חייבים להציג תעודת לקוח תקפה **וגם** מפתח API תקף בכל בקשה. דוח המחוונים פועל על איזן עומס והשם מחשב משלו, עם כניסה מוגבלת לכתובות/דומיינים של אימייל בנושא הרשימה הלבנה שלך. + +**רשומות DNS (חד-פעמי):** אתה יוצר שתי רשומות CNAME תחת דומיין שאתה שולט בו — אחת לנקודת הספקה ואחת לדוח המחוונים (לדוגמה `agenteye.your-company.example`) — מצביעות על שמות מחשב של איזן העומס ש-Exosphere מספקת. Exosphere לאחר מכן מספקת תעודות TLS נתונות לציבור עבור שני שמות המחשב באופן אוטומטי, כולל חידושים. + +> **הערת יציאה 80:** אישור תעודה ופיקוח אוטומטי ללא מילה מאמתים דרך HTTP ביציאה 80 של כל איזן עומס. אם עמדת הביטחון שלך דורשת הגבלת עומס דוח המחוונים לטווחי IP תאגידיים, אמור ל-Exosphere קודם — אנחנו עוברים לאימות תעודה לשיטה מבוססת DNS (רשומת DNS נוספת אחת בצד שלך) כך שחידושים ממשיכים לעבוד מאחורי ההגבלה. + +> **יציאה:** צמתי קלסטר זקוקים לגישה לאינטרנט כדי למשוך תמונות קונטיינר מ-`ghcr.io`. אם הרשת שלך מגבילה תעבורה יציאה, רשימה לבנה `ghcr.io` או תמונות מראה לרישום הפנימי שלך. + +--- + +## שלב 4: ספק דלי אחסון גיבוי + +גיבויי מסדי נתונים מאוחסנים בדלי אחסון בענן שאתה בעלך. + +| דרישה | פרטים | +|---|---| +| **שירות** | S3 (AWS), GCS (GCP), או Azure Blob Storage | +| **גישה** | הענק גישת כתיבה לצמתי הקלסטר דרך תפקיד IAM לחשבונות שירות (IRSA ב-EKS, Workload Identity ב-GKE) או ספק עדויות | +| **תעודה** | אתה שולט בנהלי מחזור חיים של הדלי (תקופת השמירה, כללי ארכיון). Exosphere כותבת גיבויים; אתה מחליט כמה זמן לשמור עליהם | + +גיבוי יומי אחד ממלא את PostgreSQL (מצב יחסי) ו-ClickHouse (אירוע והערכות) לתוך ארכיון דחוס אחד ומעלה אותו לדלי שלך. גיבויים גם רצים לפני כל שדרוג. + +--- + +## שלב 5: ייעד אנשי קשר + +ספק אדם אחד או ערוץ Slack/Teams בצד שלך לבעיות ברמת קלסטר: בריאות צמתים, מגבלות חשבון בענן, שינויים ברשת. פעולות יום-יום אינן כרוכות בקשר זה. + +--- + +## מה אנחנו פורסים + +ברגע ש-Exosphere יש גישה קלסטר, הרכיבים הבאים מוצבים וניהול עבורך: + +| רכיב | תפקיד | +|---|---| +| **AgentEye Server** | HTTP API המקבלת אירוע מאספנים, מפעילה ניתוח וניתנה נתונים לדוח מחוונים | +| **דוח מחוונים** | ממשק אינטרנט להצגת סשנים של סוכנים, קריאות כלים, בקשות מודלים וטעויות; מארח את העוזר AI קריאה בלבד האופציונלי | +| **ClickHouse** | אחסון קנוני נדרש לאירוע שהובא, ניתוח והערכות | +| **PostgreSQL** | חנות יחסית לארגונים, מפתחות API, משתמשים, דוחות מחוונים וסקלים שמורים | +| **Redis** | קיים אחסון זמני משותף אופציונלי וגבול-קצב קצה; הפלטפורמה מתדרדרת בחן אם היא אינה זמינה | +| **עוזר AI (אופציונלי)** | קונטיינר עוזר קריאה בלבד פנימי; נשאר מבוטל עד לתצורת נקודת קצה LLM | +| **בקרי כניסה** | שני איזני עומס (אחד ל-mTLS-protected ingest, אחד לדוח המחוונים) מסיימים TLS עם תעודות נתונות לציבור, חידוש אוטומטי, ובאכיפה mTLS בנקודת הספקה | +| **cert-manager** | מפעילה הספקת תעודה TLS ויצור אסימון לקוח-mTLS בצורה אוטומטית | +| **ניטור תעודה** | עבודה מתוזמנת בודקת פקיעת תעודה וישלח עריכות (לדוגמה ל-Slack) כאשר תעודות מתקרבות לחידוש | + +ההצעה המנוהלת גם מפעילה את צינור הערכה של הפלטפורמה, הדירוג פעילות סוכנים כנגד קריטריונים הערכה שלך. ראה [עוזר](/he/agenteye/assistant) ו-[חבילת הערכה](/he/agenteye/evaluation-suite) לאילו יכולות אלו מספקות. + +--- + +## מה אנחנו מספקים לך + +לאחר שהפריסה הושלמה, אתה מקבל: + +| פריט | פרטים | +|---|---| +| **כתובת דוח מחוונים** | שם מחשב תחת הדומיין שלך (לדוגמה `https://agenteye.your-company.example`), מוגש עם תעודה TLS נתונה לציבור, חידוש אוטומטי. אתה יוצר CNAME אחד לשם מחשב של איזן העומס ש-Exosphere מספקת; כניסה היא OTP ללא סיסמה דרך אימייל | +| **נקודת קצה אספן** | נתיב `/events` של שם מחשב הספקה (לדוגמה `https://ingest.your-company.example/events`), mTLS-protected | +| **חבילת תעודת לקוח** | לכל קלסטר: תעודת לקוח, מפתח פרטי ותעודת CA מסופקות כמניפסט סודי Kubernetes. החל אותה פעם אחת לכל קלסטר | +| **GitHub PAT** | להורדת בינריי אספן וחבילות Python SDK | +| **מפתחות API של אספן** | מפתחות בהיקף עם הרשאה `events:add`, אחד לכל פריסת אספן | +| **מדריכי התקנה** | מסמכים שלב-אחר-שלב עבור האספן ו-Python SDK | + +--- + +## מה אתה עושה לאחר הגדרה + +העבודה היחידה שלך בעבר היא בקלסטרים של סוכנים משלך, לא זה של AgentEye: + +1. **התקן את האספן** בכל קלסטר Kubernetes המפעיל סוכנים AI: העלה את תעודת הלקוח והגדר את כתובת נקודת הקצה ומפתח API. ראה [התקנת אספן](/he/agenteye/collector-installation). +2. **שלב את Python SDK** לקוד הסוכן שלך. ראה [Python SDK](/he/agenteye/python-sdk). +3. **פתח את דוח המחוונים** בדפדפן שלך כדי להציג פעילות סוכנים. + +לא פעולות קלסטר, ניהול מסדי נתונים, חידושי תעודות, שדרוגים. + +--- + +## ביטחון + +- **הנתונים נשארים בחשבון הענן שלך.** הקלסטר, האחסון, ומסדי הנתונים כולם פועלים בסביבה שלך. לא ממש נתונים עוזבים את הגבול שלך. +- **אתה שולט בגישה.** הקלסטר נמצא בחשבון שלך. אתה יכול לבקר, לעקוב, או לשלול את גישת Exosphere בכל זמן. כל הפעולות עוברות דרך רישום ביקורת של הענן שלך (CloudTrail, GCP Audit Logs, וכו'). +- **mTLS בהספקת אירוע.** כל בקשת אספן דורשת גם תעודת לקוח תקפה וגם מפתח API. מפתח דליפה חסר תועלת ללא התעודה; תעודה גנובה חסרת תועלת ללא מפתח תקף. +- **שליטה בגישה לדוח מחוונים.** דוח המחוונים פועל על איזן עומס משלו, נפרד מהספקת אירוע, וכניסה היא OTP ללא סיסמה דרך אימייל מוגבלת לכתובות/דומיינים שאתה רשימות לבנות. הגבלת טווח מקור IP על איזן העומס זמינה בבקשה; מכיוון שחידוש תעודה אוטומטי חייב להגיע לאיזן העומס, Exosphere משלבת את ההגבלה עם אימות תעודה מבוסס DNS כך שחידושים ממשיכים לעבוד. +- **תעודות לכל קלסטר.** כל אחד מהקלסטרים שלך מקבל תעודת לקוח משלו. אם קלסטר אחד נפגע, התעודה הזו מבוטלת באופן עצמאי ללא השפעה על אחרים. + +--- + +## לוח זמנים פריסה + +| שלב | משך | שלך מעורבות | +|---|---|---| +| **הצבת קלסטר** | 1-2 ימים | הצב את הקלסטר והענק לExosphere גישה | +| **הגדרת פלטפורמה** | יום 1 | כלום; Exosphere מותקנת כל רכיבי תשתית | +| **פריסת יישום** | יום 1 | כלום; Exosphere מוצבת השרת, דוח מחוונים, ויוצרת מפתחות API | +| **הרחקת אספן** | 1-3 ימים | התקן אספנים בקלסטרים שלך (עם הדרכה מ-Exosphere) | +| **שריפה בייצור** | שבוע 1 | כלום; Exosphere משגחת וכיוונון | + +סך הכל טיפוסי: **~2 שבועות** מהתחלה לערוך-לייצור. + +--- + +## תמיכה + +לשאלות או בעיות, צור קשר עם Exosphere ב-`support@exosphere.host`. + +--- + +## הצעדים הבאים + +- [תחילת עבודה](/he/agenteye/getting-started): הליכה שלמה מקצה לקצה +- [התקנת אספן](/he/agenteye/collector-installation): התקן והגדר את האספן +- [Python SDK](/he/agenteye/python-sdk): כלי את קוד הסוכן שלך +- [מפתחות API](/he/agenteye/api-keys): נהל גישה והרשאות +- [פתרון בעיות](/he/agenteye/troubleshooting): בעיות נפוצות ותיקונים \ No newline at end of file diff --git a/docs/he/agenteye/python-sdk.mdx b/docs/he/agenteye/python-sdk.mdx new file mode 100644 index 00000000..cd32c630 --- /dev/null +++ b/docs/he/agenteye/python-sdk.mdx @@ -0,0 +1,386 @@ +--- +title: "Python SDK" +description: "תיעוד AgentEye Python SDK." +--- + +AgentEye Python SDK נותן לך נראות מלאה להתנהגות הסוכנים שלך (כל הרצת סוכן, קריאת כלי, בקשת מודל, hook, והתערבות אדם) כדי שתוכל לבצע ניפוי שגיאות, ביקורת והערכה. הוא מחבר את קוד הסוכן שלך על ידי כתיבת אירועים מובנים לקבצי JSONL מקומיים; דימון האספן קוטף אלה ומשדר אותם לפלטפורמה באופן אוטומטי. + +--- + +## התקנה + +הורד את wheel מ-GitHub Releases באמצעות `AGENTEYE_TOKEN` שלך. אם עדיין אין לך token, ראה [GitHub Token Setup](/he/agenteye/github-token) לשלבי הגדרה ולהרשאות נדרשות. + +**שימוש ב-`gh` CLI + pip:** + +```bash +VERSION=0.0.1b9 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "python-sdk/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-*.whl' +pip install "agenteye-${VERSION}-py3-none-any.whl" +``` + +**שימוש ב-`gh` CLI + uv:** + +```bash +VERSION=0.0.1b9 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "python-sdk/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-*.whl' +uv add "./agenteye-${VERSION}-py3-none-any.whl" +``` + +**שימוש ב-curl (ללא `gh` CLI):** + +```bash +VERSION=0.0.1b9 +curl -fsSL \ + -H "Authorization: Bearer $AGENTEYE_TOKEN" \ + -L \ + "https://github.com/agenteye-enterprise/releases/releases/download/python-sdk%2Fv${VERSION}/agenteye-${VERSION}-py3-none-any.whl" \ + -o "agenteye-${VERSION}-py3-none-any.whl" +pip install "agenteye-${VERSION}-py3-none-any.whl" +``` + +--- + +## התחלה מהירה + +```python +import agenteye + +agenteye.configure(environment="production") + +agenteye.event.agent_start(session_id="run-001", agent_id="planner", goal="answer user query") + +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", + input={"query": "latest AI research"}, +) + +agenteye.event.tool_result( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", + output={"results": ["..."]}, +) + +agenteye.event.agent_end(session_id="run-001", agent_id="planner", outcome="success") +``` + +--- + +## configure() + +```python +agenteye.configure( + base_dir=None, # Path | str | None. Default: $AGENTEYE_HOME or ~/.agenteye + flush_interval=0.5, # float, seconds between flush cycles + environment=None, # str | None. Deployment environment label +) +``` + +קרא פעם אחת לפני כל קריאה `event.*`. בטוח להשמיט; ברירות המחדל עובדות מחוץ לתיבה. כל הארגומנטים הם keyword-only; העבר אותם לפי שם כפי שמוצג למעלה. + +כאשר `base_dir` הוא `None` (ברירת המחדל), ה-SDK קורא `$AGENTEYE_HOME` אם הוגדר, +אחרת חוזר ל-`~/.agenteye`. זה תואם את ההחלטה שלעצמו של האספן, +כך שמשתנה `AGENTEYE_HOME` אחד מסביבה מגדיר את ה-spool המשותף של האירועים עבור +ה-SDK והאספן, נדרש עבור פריסות sidecar / single-pod כאשר שתי התהליכים חייבים +להסכים על נתיב ה-spool. + +--- + +## Environment + +תייג כל אירוע עם environment פריסה (`production`, `staging`, `qa`, `canary`, וכו'). הגדר פעם אחת; ה-SDK מצרף אותה לכל אירוע באופן אוטומטי. + +**אפשרות 1: דרך `configure()`:** + +```python +agenteye.configure(environment="production") +``` + +**אפשרות 2: דרך משתנה סביבה:** + +```bash +export AGENTEYE_ENVIRONMENT=production +``` + +**עדיפות:** `configure(environment=...)` מנצח על משתנה הסביבה. אם שום דבר לא הוגדר, ברירת המחדל היא `"dev"`. + +ערך ה-environment מופיע כמסנן מדרגה ראשונה בלוח המחוונים ומאוחסן כעמודה מודדת על השרת לשאילתות מהירות. + +**הגבלה:** ערכי environment **לא חייבים להכיל פסיק `,` ממשי**. מסנני לוח המחוונים משתמשים בבחירה מרובה מופרדת בפסיקים על החוט (`?environment=prod,staging`), כך שenv בשם `prod,blue` היה מחולק לשני ערכים. אירועים עם environments המכילים פסיקים מדחים בזמן הספיגה. + +--- + +## הפניה לאירועים + +כל שיטות אירוע דורשות שני שדות אלה: + +| שדה | סוג | תיאור | +|---|---|---| +| `session_id` | `str` | מזהה את הרצת הסוכן ברמה העליונה | +| `agent_id` | `str` | מזהה איזה סוכן בתוך ה-session פרסם את האירוע | + +כל השיטות מקבלות גם `**kwargs` שרירותיות עבור מטא-נתונים מותאמים אישית (ראה [Custom Fields](#custom-fields)). + +--- + +### `event.agent_start()` + +פולט כאשר סוכן מתחיל לעבוד. + +```python +agenteye.event.agent_start( + session_id="run-001", + agent_id="planner", + goal="answer user query", # str | None + parent_id=None, # str | None - parent agent_id for nested agents +) +``` + +--- + +### `event.agent_end()` + +פולט כאשר סוכן סיים עבודה. + +```python +agenteye.event.agent_end( + session_id="run-001", + agent_id="planner", + outcome="success", # str | None + summary="Answered query", # str | None +) +``` + +--- + +### `event.tool_use()` + +פולט כאשר סוכן מעוררת כלי. זוגי עם `tool_result`; ה-SDK מחשב אוטומטית `duration_ms`. + +```python +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="web_search", # str, required + tool_call_id="toolu_01", # str, required - correlation key for the matching tool_result + input={"query": "..."}, # dict | None +) +``` + +--- + +### `event.tool_result()` + +פולט כאשר כלי חוזר. מתואם עם `tool_use` דרך `tool_call_id`. + +```python +agenteye.event.tool_result( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", # must match the prior tool_use + output={"results": ["..."]}, # Any | None + error=None, # str | None - set if the tool raised + # duration_ms is computed automatically - do not pass it +) +``` + +--- + +### `event.model_request()` + +פולט ממש לפני שליחת prompt ל-LLM. + +```python +agenteye.event.model_request( + session_id="run-001", + agent_id="planner", + model="claude-sonnet-4-6", # str | None + messages=[ # list[dict] | None - conversation turns + {"role": "user", "content": "..."}, + ], + system="You are helpful.", # Any | None - str or list of content blocks + tools=[ # list[dict] | None - tool schemas offered to the model + {"name": "search", "input_schema": {"type": "object"}}, + ], +) +``` + +ערכי `messages` מקבלים או `content` מחרוזת פשוטה או Anthropic-style list-of-blocks `content`. פרמטרי דגימה (`temperature`, `max_tokens`, וכו') יכולים להיות מועברים כ-kwargs נוסף. + +--- + +### `event.model_response()` + +פולט כאשר LLM חוזר עם תגובה. + +```python +agenteye.event.model_response( + session_id="run-001", + agent_id="planner", + model="claude-sonnet-4-6", # str | None + stop_reason="end_turn", # str | None + input_tokens=1024, # int | None + output_tokens=256, # int | None + content=[ # Any | None - str, or list of content blocks + {"type": "text", "text": "..."}, + ], + role="assistant", # str | None +) +``` + +`content` מקבל או מחרוזת פשוטה (ספקים גנריים) או רשימה של Anthropic-style content blocks. קריאות כלי חיות בתוך `content` כ-`{"type": "tool_use", ...}` blocks, ללא שדה `tool_calls` נפרד. + +--- + +### `event.hook_triggered()` + +פולט כאשר hook שורה. זוגי עם `hook_completed`; ה-SDK מחשב אוטומטית `duration_ms`. + +```python +agenteye.event.hook_triggered( + session_id="run-001", + agent_id="planner", + hook_name="pre_tool_use", # str, required + hook_id="hook-abc", # str, required - correlation key + trigger_event="tool_use", # str | None + input={"tool": "search"}, # Any | None +) +``` + +--- + +### `event.hook_completed()` + +פולט כאשר hook מסתיים. מתואם עם `hook_triggered` דרך `hook_id`. + +```python +agenteye.event.hook_completed( + session_id="run-001", + agent_id="planner", + hook_name="pre_tool_use", + hook_id="hook-abc", # must match the prior hook_triggered + outcome="allow", # str | None + output=None, # Any | None + error=None, # str | None + # duration_ms is computed automatically - do not pass it +) +``` + +--- + +### `event.error()` + +פולט כאשר שגיאה לא מטופלת מתרחשת. + +```python +agenteye.event.error( + session_id="run-001", + agent_id="planner", + error_type="TimeoutError", # str, required + message="timed out", # str, required + traceback="Traceback...", # str | None +) +``` + +--- + +## אירועי Human-in-the-Loop + +אירועי human-in-the-loop נותנים לך פיקוח על הרגעים שבהם אדם נכנס להוצאה לפועל של הסוכן (המתנה לאישור, הנמקת קלט, השהייה, או עצירת הסוכן). הם מאפשרים לך למדוד כמה זמן אדם לוקח כדי להגיב (ה-SDK מחשב אוטומטית `duration_ms` על אירועים מזווגים), ביקורת מי השהה או הפריע לסוכן, ובנייה של זרימות עבודה של אישור ופיקוח שמופיעות בלוח המחוונים. + +### `event.human_wait()` + +פולט כאשר הסוכן מעצור את ההוצאה לפועל כדי להמתין לאדם לספק קלט. זוגי עם `human_input`; ה-SDK מחשב אוטומטית `duration_ms` (כמה זמן לקח לאדם להגיב). + +```python +agenteye.event.human_wait( + session_id="run-001", + agent_id="planner", + input_id="inp-abc", # str, required - correlation key for the matching human_input + prompt="Do you approve this action?", # str | None - the question shown to the human + options=["approve", "reject", "defer"], # list[str] | None - choices presented to the human + reason="approval_required", # str | None - why the agent is waiting +) +``` + +### `event.human_input()` + +פולט כאשר אדם מספק קלט והסוכן חוזר. מתואם עם `human_wait` דרך `input_id`. `duration_ms` מחושב אוטומטית ולא חייב להיות מועבר על ידי הקורא. + +```python +agenteye.event.human_input( + session_id="run-001", + agent_id="planner", + input_id="inp-abc", # str, required - must match the prior human_wait + response="approve", # str | None - the human's answer (free text or selected option) + # duration_ms is computed automatically - do not pass it +) +``` + +### `event.human_pause()` + +פולט כאשר אדם בפעיל מעצור את הסוכן (למשל דרך בקרת לוח מחוונים). הסוכן מושעה אך לא מסתיים. + +```python +agenteye.event.human_pause( + session_id="run-001", + agent_id="planner", + reason="user_requested", # str | None + user_id="usr_42", # str | None - who paused the agent +) +``` + +### `event.human_interrupt()` + +פולט כאשר אדם בפעיל עוצר את הסוכן באמצע ביצוע. בניגוד ל-`human_pause`, עבודת הסוכן מסתיימת ולא משעה. + +```python +agenteye.event.human_interrupt( + session_id="run-001", + agent_id="planner", + reason="output_incorrect", # str | None + user_id="usr_42", # str | None - who interrupted the agent + at_step="tool_use:web_search", # str | None - what the agent was doing when stopped +) +``` + +--- + +## שדות מותאמים אישית + +כל kwargs נוסף מצורף לאירוע לאחר השדות הסטנדרטיים: + +```python +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="db_query", + tool_call_id="toolu_02", + tenant_id="acme", # custom field + region="us-east-1", # custom field +) +``` + +`timestamp`, `type`, ו-`environment` שמורים והעלו `ValueError` (`Reserved field names cannot be used as custom fields: [...]`) אם מועברים כשדות מותאמים אישית. `session_id` ו-`agent_id` הם פרמטרים נדרשים בכל שיטת אירוע ולא ניתן לספק אותם בפעם שנייה; Python מעלה `TypeError` אם אתה עושה זאת. הגדר את ה-environment עם `configure(environment=...)` (או משתנה `AGENTEYE_ENVIRONMENT`) במקום זאת. + +--- + +## כיצד אירועים נכתבים + +אירועים מאוגרים בתהליך ומשטפים לדיסק כל `flush_interval` שניות (ברירת מחדל 500 ms). כל flush כותב קובץ JSONL אחד: + +``` +~/.agenteye/events/event-2026-04-01T12-00-00-000Z.jsonl +``` + +האספן צפה בתיקייה זו ועלויים קבצים באופן אוטומטי. אתה לא צריך לנהל קבצים אלה ישירות. \ No newline at end of file diff --git a/docs/he/agenteye/single-pod-deployment.mdx b/docs/he/agenteye/single-pod-deployment.mdx new file mode 100644 index 00000000..9db3cbc9 --- /dev/null +++ b/docs/he/agenteye/single-pod-deployment.mdx @@ -0,0 +1,483 @@ +--- +title: "פריסה ב-Pod יחיד: Collector + Application Sidecar ב-EKS" +description: "תיעוד AgentEye Single-Pod Deployment: Collector + Application Sidecar ב-EKS." +--- + +הרץ את היישום וה-AgentEye collector **באותו Pod של Kubernetes** כך שהטלמטריה לעולם לא תחצה גבול רשת לצורך איסוף. ה-SDK של היישום וה-collector חולקים spool אירוע יחיד בתוך ה-pod, מה שאומר העברת טלמטריה בעלת latency נמוך, בתוך התהליך ללא חשיפת localhost port, ללא mesh שירותים לחצייה, וחיי ה-collector קשורים ישירות לעומס העבודה שהוא צופה בו. תעודת הלקוח של mTLS שה-collector מציג מועברת ישירות לתוך ה-pod שלך מ-AWS Secrets Manager, כך שהחלפת הרשאות אינה דורשת ערבול קבצים ידני מצדך. + +מודל ה-sidecar + shared-spool המתואר כאן הוא cloud-agnostic; שני containers החולקים `emptyDir` event spool עובד בכל התפוצה של Kubernetes. רק הנתיב של העברת תעודה במדריך זה (AWS Secrets Manager + Secrets Store CSI Driver + IRSA) ספציפי ל-AWS / EKS. אם אתה פועל במקום אחר, שמור על עיצוב ה-pod וה-spool והחלף את מנגנון ה-secret-mount של הפלטפורמה שלך עבור Phases 2 ו-3. + +> **מתי להשתמש בתבנית זו.** בחר single-pod כאשר היישום שלך לא צריך להתקשר על פני גבול רשת כדי להגיע ל-collector (IPC בתוך pod בעל latency נמוך, חיבור חיים הדוק, בידוד pod לכל דייר). עבור צי מולטי-אפליקציה החולק collector אחד לכל node או לכל cluster, ראה [enterprise-docs/kubernetes-deployment.md](/he/agenteye/kubernetes-deployment) במקום זאת. + +--- + +## בהצצה + +``` +┌──────────────────────────────── Pod ─────────────────────────────────┐ +│ │ +│ ┌──────────────────────┐ ┌──────────────────────┐ │ +│ │ your-app │ │ agenteye-collector │ │ +│ │ (SDK writes JSONL) │ │ (sweeps events/, │ │ +│ │ │ │ uploads over mTLS) │ │ +│ └──────────┬───────────┘ └──────────┬───────────┘ │ +│ │ writes reads │ │ +│ ▼ ▼ │ +│ ┌────────────────────────────────────────────────────┐ │ +│ │ emptyDir: /var/lib/agenteye/{events,failed}/ │ │ +│ │ (AGENTEYE_HOME - shared event spool) │ │ +│ └────────────────────────────────────────────────────┘ │ +│ ▲ │ +│ │ reads cert │ +│ ┌────────┴─────────┐ │ +│ │ CSI (read-only): │ │ +│ │ /etc/agenteye/ │ │ +│ │ tls/client.{crt, │ │ +│ │ key}, ca.crt │ │ +│ └────────┬─────────┘ │ +└───────────────────────────────────────────────────┼──────────────────┘ + │ mounted by + │ Secrets Store CSI + │ (AWS provider + + │ IRSA) + ┌────────┴──────────┐ + │ AWS Secrets │ + │ Manager │ + │ agenteye/mtls- │ + │ client/ │ + └────────┬──────────┘ + ▲ + │ push on issue / + │ renewal + ┌────────┴──────────┐ + │ Exosphere │ + │ delivers the cert │ + │ bundle into your │ + │ Secrets Manager │ + │ on renewal │ + └───────────────────┘ + +Outbound: collector → AGENTEYE_URL (mTLS, using the CSI-mounted cert). +``` + +שתי זרימות נתונים, שני נפחים: + +- **אירועים (בתוך pod):** ה-SDK של היישום שלך כותב קובצי `.jsonl` ל-`emptyDir` המשותף ב-`$AGENTEYE_HOME/events/`; ה-collector sweeper קוראה אותם ומעלה. אין localhost port, אין loopback, pure shared-filesystem handoff. +- **תעודת mTLS (pod ← cloud):** ה-Secrets Store CSI Driver מעלה את חבילת התעודה מ-Secrets Manager לתוך נפח read-only ב-`/etc/agenteye/tls/`, מתוחם ל-collector container. + +**שתי צדדים עצמאיים:** + +| צד | אחריות | +|---|---| +| Exosphere | מנפיק את תעודת הלקוח של mTLS ומעביר את החבילה לתוך **חשבון AWS שלך** ב-Secrets Manager תחת שם יציב. מפרסם מחדש את החבילה המחודשת לאותו secret לפני תוקף. | +| אתה | התקן את ה-Secrets Store CSI Driver, תן ל-ServiceAccount של ה-pod גישת read ל-secret דרך IRSA, והחל את manifest של ה-Pod. זהו. | + +--- + +## דרישות קדם + +### בחשבון AWS / EKS cluster שלך + +- EKS cluster עם **OIDC provider** משויך. אשר עם: + + ```bash + aws eks describe-cluster --name \ + --query "cluster.identity.oidc.issuer" --output text + ``` + + אם הפקודה מחזירה URL של `https://oidc.eks.…`, OIDC מופעל. אם לא, שייך אחד: + + ```bash + eksctl utils associate-iam-oidc-provider \ + --cluster --approve + ``` + +- [Secrets Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/) ו-[AWS provider](https://github.com/aws/secrets-store-csi-driver-provider-aws) מותקנים ב-cluster (ראה § Phase 2). + +- AWS CLI v2 ו-`kubectl` על תחנת העבודה שלך. + +### תיאום עם Exosphere + +לפני שאתה פורס, Exosphere מעביר את חבילת mTLS client לתוך Secrets Manager של חשבון AWS שלך ומספק: + +- **שם ה-secret** (כנס: `agenteye/mtls-client/`) +- **אזור AWS** שה-secret נמצא בו +- **URL בקצה AgentEye** לתצורת ה-collector +- **API key** של ה-collector שלך (ראה [enterprise-docs/api-keys.md](/he/agenteye/api-keys)) + +--- + +## Phase 1: מה Exosphere מעביר + +אתה לא יוצר את תעודת הלקוח של mTLS בעצמך. Exosphere מנפיקה אותה ומעביר את החבילה ישירות לתוך Secrets Manager של חשבון AWS שלך, כך שחומר הרשאות היחיד שכל פעם נוחת בסביבה שלך הוא ה-secret המוגמר, מוכן להעלאה. + +מה מגיע לחשבון שלך: + +| רכוש | ערך | +|---|---| +| שם Secret | `agenteye/mtls-client/` (יציב על פני חידושים) | +| אזור | אזור AWS שציינת עבור ה-EKS cluster שלך | +| Payload | secret JSON יחיד עם שלושה מפתחות (`client.crt`, `client.key`, ו-`ca.crt`), כל אחד מחזיק את חומר המקודד PEM | +| תג | `AgentEyeCluster=` | + +בעת חידוש, ה-secret הזהה מעודכן במקום עם גרסה חדשה, כך ש-ARN והשם לעולם לא משתנים; `SecretProviderClass` ו-IAM policy שלך ממשיכים לעבוד ללא שינוי. עבור מחזור חיי התעודה (תוקף, קצב חידוש, התרעות תוקף) ראה [enterprise-docs/kubernetes-deployment.md](/he/agenteye/kubernetes-deployment). + +--- + +## Phase 2: התקן את Secrets Store CSI Driver + AWS provider + +דלג על צעד זה אם אתה כבר מריץ עומס עבודה אחר המעלה AWS secrets דרך CSI. + +```bash +# CSI Driver +helm repo add secrets-store-csi-driver \ + https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts +helm install -n kube-system csi-secrets-store \ + secrets-store-csi-driver/secrets-store-csi-driver \ + --set syncSecret.enabled=true \ + --set enableSecretRotation=true \ + --set rotationPollInterval=1h + +# AWS provider +kubectl apply -f \ + https://raw.githubusercontent.com/aws/secrets-store-csi-driver-provider-aws/main/deployment/aws-provider-installer.yaml +``` + +**אשר:** + +```bash +kubectl get pods -n kube-system | grep -E 'csi-secrets-store|aws-provider' +``` + +צפוי: `Running` עבור כל pod. + +> **למה `rotationPollInterval=1h`?** כאשר Exosphere מפרסם תעודה מחודשת, Secrets Manager מעודכן במקום. ה-CSI Driver קורא את ה-secret במרווח זה ויכתב מחדש את הקבצים המעלים. ה-collector קורא את קבצי התעודה פעם אחת בעת ההתחלה, כך שהוא מתחיל להציג את התעודה המחודשת רק לאחר restart של התהליך; ראה § Certificate rotation לאופן הגרימה של אחד. + +--- + +## Phase 3: תן ל-pod גישת read ל-secret (IRSA) + +### 3.1 צור את IAM policy + +שמור כ-`agenteye-mtls-reader-policy.json`: + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "ReadAgentEyeMtlsBundle", + "Effect": "Allow", + "Action": [ + "secretsmanager:GetSecretValue", + "secretsmanager:DescribeSecret" + ], + "Resource": "arn:aws:secretsmanager:::secret:agenteye/mtls-client/-*" + } + ] +} +``` + +תחליף את ``, ``, ו-``. סיומת ה-`-*` משוררת משדוג תו אקראי שש-תווים AWS מוסיף לכל ARN secret. + +צור את ה-policy: + +```bash +aws iam create-policy \ + --policy-name AgentEyeMtlsReader- \ + --policy-document file://agenteye-mtls-reader-policy.json +``` + +### 3.2 צור את IAM role וקשור אותו ל-ServiceAccount של ה-pod + +```bash +eksctl create iamserviceaccount \ + --name agenteye-pod \ + --namespace \ + --cluster \ + --role-name AgentEyePodRole- \ + --attach-policy-arn arn:aws:iam:::policy/AgentEyeMtlsReader- \ + --approve +``` + +זה יוצר `ServiceAccount` בשם `agenteye-pod` עם האנוטציה `eks.amazonaws.com/role-arn` המצביעה לתפקיד החדש. + +### 3.3 הרשאות IAM נדרשות: סיכום + +| הרשאה | טווח | למה | +|---|---|---| +| `secretsmanager:GetSecretValue` | `arn:aws:secretsmanager:::secret:agenteye/mtls-client/-*` | CSI Driver קורא את חבילת ההסמכה בכל mount + rotation tick. | +| `secretsmanager:DescribeSecret` | זהה | CSI Driver קוראה `DescribeSecret` לגילוי שינויי גרסה בין polls. | + +**אל תן** `secretsmanager:PutSecretValue`, `secretsmanager:UpdateSecret`, או `secretsmanager:DeleteSecret` ל-pod. ה-pod רק קורא את ה-secret; כתיבת גרסיות חדשות אליו מטופלת על ידי Exosphere כאשר התעודה מונפקת או מחודשת. + +אם ה-secret מוצפן עם customer-managed KMS key (לא הדיפולט `aws/secretsmanager` key), גם תן: + +```json +{ + "Effect": "Allow", + "Action": ["kms:Decrypt"], + "Resource": "arn:aws:kms:::key/", + "Condition": { + "StringEquals": { + "kms:ViaService": "secretsmanager..amazonaws.com" + } + } +} +``` + +--- + +## Phase 4: פרוס את ה-Pod + +### 4.1 SecretProviderClass + +`agenteye-mtls-spc.yaml`: + +```yaml +apiVersion: secrets-store.csi.x-k8s.io/v1 +kind: SecretProviderClass +metadata: + name: agenteye-mtls + namespace: +spec: + provider: aws + parameters: + objects: | + - objectName: "agenteye/mtls-client/" + objectType: "secretsmanager" + jmesPath: + - path: '"client.crt"' + objectAlias: "client.crt" + - path: '"client.key"' + objectAlias: "client.key" + - path: '"ca.crt"' + objectAlias: "ca.crt" +``` + +בלוק `jmesPath` אומר ל-AWS provider לפצל את ה-JSON secret לשלושה קבצים נפרדים על דיסק. הציטוט ב-`'"client.crt"'` נדרש כי JMESPath מטפל בנקודה כ-sub-expression operator. + +```bash +kubectl apply -f agenteye-mtls-spc.yaml +``` + +### 4.2 Pod / Deployment manifest + +**איך שני containers מדברים זה לזה.** ה-AgentEye SDK וה-collector לא מתקשרים על פני network socket; אין local HTTP port. ה-SDK כותב batch אירועים כקבצי `.jsonl` לתוך `$AGENTEYE_HOME/events/`, וה-collector ממשיך לצפות בתיקייה זו ומעלה כל קובץ. עבור sidecar pod זה אומר: + +- שני containers מעלים את **אותו** `emptyDir` volume ב-**אותו** path. +- שני containers קובעים `AGENTEYE_HOME` לאותו path. +- תמונת היישום שלך חייבת להיות ב-AgentEye SDK מותקן ומוגדר (ראה [enterprise-docs/python-sdk.md](/he/agenteye/python-sdk)). + +> כאשר `AGENTEYE_HOME` לא מוגדר, גם SDK וגם collector מכריזים כברירת מחדל על `~/.agenteye`, ולשני containers יש בתי דירה שונים, כך שהם היו נוחתים על שתי spools נפרדות וה-handoff היה שקט נכשל. קבע `AGENTEYE_HOME` לאותו explicit path ב-**שני** containers. §4.3 verification והשורה Troubleshooting המתאימה תופסות זה אם זה מוחמץ. + +`agenteye-pod.yaml` (Deployment עם replicas אחד, scale כנדרש): + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-app-with-collector + namespace: +spec: + replicas: 1 + selector: + matchLabels: + app: my-app-with-collector + template: + metadata: + labels: + app: my-app-with-collector + spec: + serviceAccountName: agenteye-pod + containers: + - name: app + image: + env: + # SDK writes event JSONL files into $AGENTEYE_HOME/events/ + - name: AGENTEYE_HOME + value: /var/lib/agenteye + volumeMounts: + - name: agenteye-spool + mountPath: /var/lib/agenteye + + - name: agenteye-collector + # Pin to a versioned :v tag for production; :beta-latest + # tracks the current beta build (:latest exists only for stable releases). + image: ghcr.io/agenteye-enterprise/collector:beta-latest + args: ["start"] + env: + # Must match the app container's AGENTEYE_HOME so the collector + # sweeps the same directory the SDK writes to. + - name: AGENTEYE_HOME + value: /var/lib/agenteye + - name: AGENTEYE_URL + value: "https://ingest.example.agenteye.com/events" + - name: AGENTEYE_KEY + valueFrom: + secretKeyRef: + name: agenteye-collector-api-key + key: key + - name: AGENTEYE_TLS_CERT + value: /etc/agenteye/tls/client.crt + - name: AGENTEYE_TLS_KEY + value: /etc/agenteye/tls/client.key + # Only when the AgentEye server presents a cert not signed by a + # publicly-trusted CA (e.g. self-signed by an in-cluster issuer + # because you have no real DNS domain). The CSI mount already + # exposes ca.crt alongside the client cert/key. + - name: AGENTEYE_TLS_CA + value: /etc/agenteye/tls/ca.crt + volumeMounts: + - name: agenteye-spool + mountPath: /var/lib/agenteye + - name: agenteye-mtls + mountPath: /etc/agenteye/tls + readOnly: true + livenessProbe: + exec: + command: ["agenteye-collector", "health"] + initialDelaySeconds: 10 + periodSeconds: 30 + + volumes: + # Shared event spool between app and collector. emptyDir is fine: + # events are transient and the collector drains them before pod + # termination on graceful shutdown. + - name: agenteye-spool + emptyDir: {} + # mTLS cert bundle, mounted read-only into the collector only. + - name: agenteye-mtls + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: agenteye-mtls +``` + +ה-`agenteye-collector-api-key` Secret מחזיק את API key של ה-collector (ראה [enterprise-docs/api-keys.md](/he/agenteye/api-keys) לספקת). + +**החל:** + +```bash +kubectl apply -f agenteye-pod.yaml +``` + +### 4.3 אשר + +```bash +# Pod should be Running with 2/2 containers ready +kubectl get pods -n -l app=my-app-with-collector + +# Confirm the cert bundle was mounted +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- ls -l /etc/agenteye/tls/ +``` + +צפוי: `client.crt`, `client.key`, `ca.crt` כולם נוכחים וקריאה בלבד, בבעלות משתמש ה-container. + +**אשר ש-shared event spool גלוי לשני containers:** + +```bash +# In the collector, should show the events/ and failed/ subdirs that +# the collector auto-creates on startup: +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- ls /var/lib/agenteye/ + +# In the app, should show the same directory contents: +kubectl exec -n deploy/my-app-with-collector \ + -c app -- ls /var/lib/agenteye/ +``` + +אם שתי רשימות שונות, הנפח לא מעלה בשני containers (או `AGENTEYE_HOME` שונה); ראה § Troubleshooting. + +**בדיקת smoke end-to-end:** + +```bash +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- agenteye-collector flush +``` + +צפוי: ה-collector מעלה כל אירועים בתור ומדפיס סיכום `Done: N/N uploaded, 0 failed.`. אם ה-spool ריק הוא מדפיס `No pending files.` ויוצא ללא אימות כלום — אז הרץ זאת רק לאחר שהיישום שלך flush לפחות אירוע אחד. + +שימו לב ש-`flush` יוצא non-zero **רק** עבור setup faults מקומי: תצורה חסרה (לא URL/key resolved) או קובץ TLS cert לא קריא/unparseable (בדוק § Troubleshooting). **API key לא נכון אינו משנה את קוד ה-exit** — ההעלאה מקבלת `401`, הקובץ מועבר ל-`failed/`, והפקודה עדיין מדפיסה `[FAILED] …` לכל קובץ בתוספת `Done: 0/N uploaded, N failed.` ויוצאת `0`. כדי לגלות bad key או הורדת rejected, קרא את `Done:`/`[FAILED]` output או בדוק עבור קבצים נוחתים ב-`$AGENTEYE_HOME/failed/`, לא קוד ה-exit. + +--- + +## Certificate rotation + +תעודת הלקוח תקף 90 ימים ומחודשת אוטומטית בערך 15 ימים לפני תוקף; Exosphere מפרסמת את הצרור המחודש באותו Secrets Manager secret. משם, הזרימה בתוך pod היא: + +1. ה-secret של Secrets Manager מקבל גרסה `AWSCURRENT` חדשה. ARN ושם לא משתנים. +2. תוך `rotationPollInterval` (1 שעה כברירת מחדל; ראה § Phase 2), ה-CSI Driver קורא את הגרסה החדשה ויכתב קבצים תחת `/etc/agenteye/tls/`. +3. ה-collector עוגן קבצי תעודה **פעם אחת בעת ההתחלה**, כך שהוא ממשיך להציג את התעודה הקודמת עד שהתהליך מתחדש. כדי לעבור לחומר המחודש, הפעל מחדש את ה-collector; rolling restart מספיק: + + ```bash + kubectl rollout restart deploy/my-app-with-collector -n + ``` + + כדי להפוך זאת לאוטומטית, הוסף sidecar שצופה ב-`/etc/agenteye/tls/` (לדוגמה עם `inotifywait`) ובהפעלת ה-rollout כאשר הקבצים משתנים. + +מכיוון שהתעודה הקודמת נשארת תקפה בערך 15 ימים לאחר חידוש, יש לך חלון רחב לביצוע ה-restart ללא הפרעה לטלפטה. Exosphere מפרסמת את הצרור המחודש עבורך; הפעולה הדורשת דיון היחידה מצדך היא לוודא שה-collector מתחדש בתוך חלון זה. + +--- + +## Troubleshooting + +| תסריט | סיבה סבירה | תיקיה | +|---|---|---| +| Pod תקוע ב-`ContainerCreating`, אירועים מראים `MountVolume.SetUp failed for volume "agenteye-mtls"` | CSI provider לא יכול להגיע ל-Secrets Manager | בדוק IRSA קשור כראוי: `kubectl describe sa agenteye-pod -n ` מראה את האנוטציה `eks.amazonaws.com/role-arn`. בדוק CloudTrail עבור AssumeRole call. | +| Error: `AccessDeniedException: not authorized to perform secretsmanager:GetSecretValue` | IAM policy מתוחם ל-ARN לא נכון | סיומת ARN secret אקראית; השתמש ב-`agenteye/mtls-client/-*` עם wildcard, לא ב-ARN מדויק. | +| Error: `ParameterNotFound` מ-AWS provider | misMatch שם secret בין `SecretProviderClass.objects[].objectName` לבין ה-secret Exosphere מעביר | אשר את השם המדויק עם `aws secretsmanager list-secrets --filters Key=tag-key,Values=AgentEyeCluster`. | +| `jmesPath` error, רק קובץ אחד מעלה | JMESPath syntax | הנקודות במפתחות JSON דורשות double-quoting: `'"client.crt"'`, לא `client.crt`. | +| Collector logs `tls: bad certificate` אחרי renewal | ה-CSI Driver עדיין לא עברנו על הגרסה החדשה, או ה-collector עדיין פועל עם התעודה הקודמת שהוא העל בהתחלה | אשר את הקבצים המעלים עדכנו (`ls -l /etc/agenteye/tls/`), ואז הפעל מחדש את ה-collector לטעינה: `kubectl rollout restart deploy/my-app-with-collector -n `. ראה § Certificate rotation. | +| Collector container crashloops עם `no such file or directory: /etc/agenteye/tls/client.crt` | נפח עדיין לא מוסי בהתחלה ראשונה; startup probe חזק מדי | הוסף עיכוב ראשוני קטן או השתמש ב-init container שמחכה לקובץ להתקיים: `until [ -f /etc/agenteye/tls/client.crt ]; do sleep 1; done`. | +| CSI Driver pod `OOMKilled` | דיפולט memory limits נמוך מדי עבור clusters עם הרבה SecretProviderClasses | בום `--set linux.resources.limits.memory=200Mi` בהתקנה של Helm. | +| יישום פועל בנקיון, `agenteye-collector flush` דוחה `No pending files.`, אך לוח המחוונים AgentEye שלך מראה אירועים | האפליקציה וה-collector לא חולקים את ה-event spool | בדוק ש (א) שני containers מעלים את אותו `agenteye-spool` emptyDir באותו path, ו (ב) שניהם קובעים `AGENTEYE_HOME` לאותו path. הרץ את שתי בדיקות `ls /var/lib/agenteye/` מ-§ 4.3; הרשימות חייבות להתאים. | + +**Logs אופס ראשונות:** + +```bash +kubectl logs -n kube-system -l app=secrets-store-csi-driver --tail=100 +kubectl logs -n kube-system -l app=csi-secrets-store-provider-aws --tail=100 +kubectl describe pod -n -l app=my-app-with-collector +``` + +--- + +## התייחסות: קבצים על דיסק בתוך pod + +ל-pod יש שני נתיבי נתונים על דיסק: + +### חבילת תעודת mTLS: `/etc/agenteye/tls/` (CSI, read-only, collector רק) + +עלוי על ידי Secrets Store CSI Driver מ-AWS Secrets Manager. + +| קובץ | תוכן | בשימוש על ידי collector כמו | +|---|---|---| +| `client.crt` | PEM-encoded client certificate | `AGENTEYE_TLS_CERT` | +| `client.key` | PEM-encoded private key | `AGENTEYE_TLS_KEY` | +| `ca.crt` | PEM-encoded CA cert | `AGENTEYE_TLS_CA` (optional, רק כאשר ה-AgentEye server cert אינו publicly-trusted) | + +כולם שלוש מעולו read-only והשווים על ידי משתמש ה-container. הם כתובים מחדש על ידי ה-CSI Driver כאשר ה-secret משתנה. + +### Event spool: `$AGENTEYE_HOME/` (emptyDir, shared read-write בין שני containers) + +משותף דרך `emptyDir` volume בשם `agenteye-spool`. + +| Path | כתוב על ידי | קרוא על ידי | מטרה | +|---|---|---|---| +| `$AGENTEYE_HOME/events/*.jsonl` | יישום (AgentEye SDK) | Collector sweeper | Event batches ה-SDK flush, מחכה להעלאה. | +| `$AGENTEYE_HOME/failed/` | Collector (בהעלאה כישלון) | אתה (כאשר debugger) | JSONL קבצים ה-collector לא יכול להעלות לאחר retries. | +| `$AGENTEYE_HOME/config.json` | אתה (optional) | Collector | Optional collector קובץ תצורה (חלופה לאנציקלופדיה vars). | + +שתי תיקיות `events/` ו-`failed/` auto-created על ידי ה-collector בעת ההתחלה; לא `initContainer` צריך. + +--- + +## קשור docs + +- [enterprise-docs/collector-installation.md](/he/agenteye/collector-installation): אפשרויות collector binary, mTLS config reference, daemon modes. +- [enterprise-docs/kubernetes-deployment.md](/he/agenteye/kubernetes-deployment): multi-pod deployment, cert issuance internals, lifecycle and expiry alerts. +- [enterprise-docs/api-keys.md](/he/agenteye/api-keys): provisioning ה-collector API key consumed על ידי ה-pod. +- [enterprise-docs/troubleshooting.md](/he/agenteye/troubleshooting): cluster-wide troubleshooting index. \ No newline at end of file diff --git a/docs/he/agenteye/tenant-management.mdx b/docs/he/agenteye/tenant-management.mdx new file mode 100644 index 00000000..213e340b --- /dev/null +++ b/docs/he/agenteye/tenant-management.mdx @@ -0,0 +1,167 @@ +--- +title: "ניהול דיירים (ארגונים וחברים)" +description: "תיעוד ניהול דיירים של AgentEye (ארגונים וחברים)." +--- + + +פריסה יחידה של AgentEye משרתת מספר **ארגונים** מבודדים לחלוטין (דיירים), כך שאפשר להנחות שם צוותים נפרדים, יחידות עסקיות או לקוחות ללא חשיפת נתונים של דייר אחד לאחר. כל שורה של נתונים (אירועים, הערכות, סשנים, לוחות בקרה, שאילתות שמורות, התראות, מפתחות API וחברים) שייכת לבדיוק ארגון אחד. בידוד ראשוני מיושם בקוד היישום: כל בקשה מוגבלת לארגון שלה עם תחזוקי `org_id` מפורשים. ב-ClickHouse — שם האירועים וההערכות בנפח גבוה משתהים — זה מסובב על ידי אכיפה חזקה ברמת המנוע: כל ארגון מקבל משתמש ClickHouse ייעודי לקריאה בלבד עם מדיניות שורות לכל ארגון, כך שאפילו SQL אנליטיקה לא מהימנה לא יכולה לעולם לקרוא שורות של דייר אחר. בפוסטגרס, אבטחה ברמת השורה מוסיפה הגנה במעומק על נתיב השאילתה לקריאה בלבד (`/queries/run`), מצמצמת מה שנתיב זה יכול לראות גם אם מסנן ברמת היישום היה חסר אי פעם; חיבור הכתיבה שלעצמו של השרת פועל בתור בעל הטבלה ולכן פועל דרך אותה יישום-ברמת `org_id` scoping. + +מחזור החיים של הדייר נשלט על ידי המפעיל, בעוד שהכל שחברים עושים ביום-יום נשאר שירות עצמי בלוח הבקרה. ארגונים וחברותם שלהם נוצרים ומנוהלים באמצעות ה-CLI **`agenteye-orgctl`**, המגיע בתוך תמונת השרת ופועל **בתוך תרמיל השרת הקיים**. יצירת ומחיקת דיירים נשמרו בכוונה מחוץ ללוח הבקרה וממשק ה-HTTP: אין **ממשק HTTP ולא כפתור בלוח בקרה** למחזור חיים של דייר, כך שהוא מנעול מאחורי גישת shell של cluster/pod ולא על המשטח היישום. + +בתוך ארגון, חברים עובדים כולם בלוח הבקרה וב-API: הם נכנסים, עברים בין הארגונים שהם שייכים להם, מנהלים את המפתחות API שלהם, בונים לוחות בקרה ושאילתות שמורות, ומגדירים התראות לארגון שלהם. החלוקה נקייה: מפעילים מפקחים ומפחיתים דיירים וחברים שלהם דרך ה-CLI; חברים מפעילים הכל בתוך דייר דרך ממשק המשתמש. + +> **פריסות בדייר יחיד לא צריכות שום דבר מזה.** התקנה בדייר יחיד פועלת ללא כל פעולה של מפעיל. כל הנתונים, המשתמשים והמפתחות משתהים בארגון `default` מובנה שמסופק באופן אוטומטי. אתה זקוק להנחיה זו רק כשאתה מחליט להוסיף ארגון שני. + +--- + +## דרישות מוקדמות + +לפני שאתה יוצר את **הארגון השני** שלך (הארגון `default` המובנה לא צריך שום דבר): + +- **PostgreSQL 15+.** סכימת חברות הארגון משתמשת במפתח זר של `ON DELETE SET NULL` ברשימת עמודות הדורש PostgreSQL 15+. שדרג את PostgreSQL לפני הפקת ארגון שני. +- **`ORG_CH_SECRET` חזק ויציב.** סיסמת ClickHouse של כל ארגון נגזרת כ-`HMAC(ORG_CH_SECRET, org_id)`, כך שברירת ברירת הפיתוח המובנית הידועה לציבור תניב credentials לכל ארגון שניתן לגזור לציבור. `agenteye-orgctl org create` **מסרב לפעול בזמן `ORG_CH_SECRET` הוא ללא הגדרה או משמאל לברירת ברירת הפיתוח המובנית**. קבע את הערך שלך תחילה (ראה [Deployment → environment variables](/he/agenteye/deployment) ובקוברנטס, [§2.6 של מדריך Kubernetes](/he/agenteye/kubernetes-deployment#26-multi-tenant-org-isolation-key-optional)). שמור עליו זהה בכל רפליקות השרת ואל תסובב אותו בשפיות; סיבוב שלו יוצר יתמים כל משתמש ClickHouse של ארגון עד שהיום הבא של סטארט-אפ מחדש מחדש אותם. + +--- + +## הרצת ה-CLI + +`agenteye-orgctl` משונה בתוך **אותה תמונה כמו השרת** (לצד `agenteye-server`). אתה **לא** מפריס תרמיל, עבודה או פריסה נפרדת עבורה; אתה exec אותה בתוך תרמיל השרת שכבר פועל, כך שהוא קורא את אותו `DATABASE_URL`, `CLICKHOUSE_URL` ו-`ORG_CH_SECRET` שהשרת משתמש. + +**Kubernetes:** + +```bash +kubectl -n agenteye exec deploy/server -- agenteye-orgctl +``` + +**Docker Compose:** + +```bash +docker compose exec server agenteye-orgctl +``` + +הדוגמאות להלן מציגות את ה-`agenteye-orgctl ` חשוף בקצרות; הקדמה כל אחת עם אי מהשתיים למעלה שתאים להפריסה שלך. + +--- + +## הפניה לפקודה + +### ארגונים + +| פקודה | מה היא עושה | +|---|---| +| `org create --slug --name ` | יצירת ארגון חדש. מסרב לפעול בזמן `ORG_CH_SECRET` הוא ללא הגדרה או משמאל לברירת ברירת הפיתוח המובנית (קבע את שלך תחילה, ראה דרישות מוקדמות). מפקח משתמש ClickHouse לקריאה בלבד של הארגון + מדיניות שורות. | +| `org list` | רשימה של כל הארגונים (slug, שם, ומצב מחזור החיים). | +| `org rename --slug --name ` | שנה את שם התצוגה של ארגון. ה-slug (המשמש בכתובות URL ומפתחות) אינו משתנה. | +| `org delete --slug ` | **מחיקה רכה** של הארגון והורדת משתמש ClickHouse שלו. הנתונים **יישמרו**. זה מבטל גישה ומשחרר את ה-credential ClickHouse לכל ארגון, אבל לא מוחק אירועים. הפיך על ידי ops; צעד בטוח ראשון לפני טיהור. | +| `org purge --slug ` | **מחיקת נתונים בלתי הפיכה.** הארגון חייב להיות כבר `delete`d. לא מותר אי פעם בארגון `default` המובנה. השתמש רק כשאתה בטוח שנתוני הדייר צריכים להיהרס. | + +### חברים + +| פקודה | מה היא עושה | +|---|---| +| `member add --org --email [--set ] [--add perm1,perm2] [--remove perm3] [--protected]` | הוסף חבר לארגון. אופציונלי התחל מסט הרשאות מובנה, ואז הוסף/הסר הרשאות בודדות. `--protected` תופסים את החבר כך שלוח הבקרה לא יכול להסיר או להדחיק אותם (ראה להלן). החבר החדש מקבל OTP בהתחברות הלוח הראשונה שלהם. | +| `member list --org ` | רשימה של חברי הארגון. עמודות הפלט הן `EMAIL`, `SET` (סט ההרשאות המובנה שהחבר התחיל מהם, או `-`), `PROT` (האם החבר מוגן), ו-`PERMISSIONS` (ההרשאות האפקטיביות שלהם). דוא"ל המוצג עם `*` סיום היא מנהל מופע; יש להם גישה לכל ארגון. | +| `member update --org --email [--set ...] [--add ...] [--remove ...] [--protected \| --unprotect]` | שנה הרשאות של חבר ו/או דגל מוגן. `--set` מחליף מסט מובנה; `--add` / `--remove` התאמות הרשאות בודדות; `--protected` / `--unprotect` החלף הגנה. העברת רק `--protected`/`--unprotect` (ללא דגלי מענק) שינויים הגנה לבד והשארת הרשאות קיימות ללא נגע. | +| `member remove --org --email ` | הסר חבר מהארגון. מסרב אם החבר מוגן; `--unprotect` אותם קודם. (אדם יכול להיות חבר בכמה ארגונים; זה משפיע רק על הארגון בשם.) | + +אדם יכול להיות חבר ביותר מארגון אחד עם **הרשאות שונות** בכל אחד, למשל מנהל בארגון אחד וקריאה בלבד באחר. כל חברות מנוהלת באופן עצמאי לכל ארגון: מתן או שינוי הרשאות של אדם בארגון אחד אין השפעה על חברותו בשום ארגון אחר. + +### חברים מוגנים (מנהל ארגון בלתי ניתן להסרה) + +הגנה מבטחת שארגון לא יכול לעולם לנעול בטעות את עצמו מניהול עצמי. כברירת ברירת, מנהלי ארגון שלהם יכולים להוסיף ולהסיר אחד את השני דרך עמוד המשתמשים השרות עצמי של לוח הבקרה, כך שהם יכולים להסיר את מנהל האחרון ולהשאיר את הארגון ללא אחד שיכול לנהל אותו. + +![עמוד המשתמשים: כרטיס לכל משתמש של לוח בקרה עם הדוא"ל שלהם, הרשאות שהוקצו, ובקרות עריכה/השבתה.](/agenteye/images/users.png) + +כדי למנוע זאת, סימן חבר אחד **מוגן**: + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member add --org acme --email owner@acme.example --set admin --protected +``` + +חבר מוגן **לא יכול להיהסר או להדחיק דרך לוח הבקרה**; פעולות אלו מחזירות שגיאה. רק מפעיל יכול לשנות אותם, וזה רק דרך CLI זה: הרץ `member update --org acme --email owner@acme.example --unprotect` קודם, ואז להסיר או להדחיק. זה מבטח שכל ארגון שומר על פחות ממנהל אחד חברים משלהם לא יכולים לנעול, תוך שמירה על שליטה בדייר רק של מפעיל. הגנה היא **לכל ארגון**; הגנה על מישהו בארגון אחד אין השפעה על חברותו בארגון אחר. + +### סטים הרשאות מובנים + +`--set` מקבל אחד משלושת סטים מובנים, מיושם לכל ארגון: + +| סט | מיועד ל | +|---|---| +| `admin` | גישה מלאה בתוך הארגון, כולל ניהול מפתחות ומשתמשים API של הארגון. | +| `standard` | שימוש יום-יומי: קרא + הרץ שאילתות, בנה לוחות בקרה, הכר אירועים. | +| `read-only` | גישת תצוגה בלבד לנתונים ולוחות בקרה של הארגון. | + +התחל מסט עם `--set`, ואז בדוק בעדיניות באמצעות `--add` / `--remove` באמצעות אסימוני ההרשאה הבודדים המופיעים ב-[API Keys](/he/agenteye/api-keys). אסימוני ההרשאה עצמם זהים לאלה המשמשים למפתחות API. + +--- + +## דוגמה עבודה + +ספק דייר `acme` חדש, הוסף את המנהל הראשון שלו, אפשר להם למטבע מפתח, ואז להסיר את הארגון מההפעלה. + +**1. יצור את הארגון** (`ORG_CH_SECRET` חייב להיות כבר מוגדר לערך חזק ויציב, לא ללא הגדרה או ברירת ברירת הפיתוח המובנית): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org create --slug acme --name "Acme Corp" +``` + +**2. הוסף את החבר הראשון כמנהל ארגון:** + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member add --org acme --email alice@acme.example --set admin +``` + +אליס מקבלת OTP בפעם הראשונה שהיא נכנסת ללוח הבקרה. מאז הלאה היא עובדת כולה בממשק ברמת תחיית הארגון שלה (למשל `/acme/sessions`). + +**3. מטבע מפתח API לכל ארגון (בלוח הבקרה):** + +המפעיל **לא** מטבעות מפתחות נתונים לכל ארגון מה-CLI. אליס (או כל חבר ארגון עם `keys:create`) יוצרת אספן / מפתחות לוח בקרה לארגון `acme` מעמוד המפתחות של לוח הבקרה. כל מפתח שהיא יוצרת מוטבע באופן אוטומטי עם הארגון שלה ויכול לעולם לקרוא או לכתוב נתוני `acme` בלבד. ראה [API Keys](/he/agenteye/api-keys). + +**4. התאם חבר מאוחר יותר:** + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member update --org acme --email alice@acme.example --add alerts:write + +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member list --org acme +``` + +**5. מחיקה רכה של הארגון** (מבטל גישה + מורידה משתמש ClickHouse שלו; נתונים שמורים): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org delete --slug acme +``` + +**6. טיהור הארגון** (בלתי הפיך; רק אחרי מחיקה רכה; לא ממש הארגון `default`): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org purge --slug acme +``` + +ב-Docker Compose, החלף כל קידומת `kubectl -n agenteye exec deploy/server --` עם `docker compose exec server`. + +--- + +## חלוקת אחריות + +הכל חבר ארגון צריך ביום-יום הוא שרות עצמי בלוח הבקרה וב-API, מוגבל באופן אוטומטי לארגון הנוכחי שלהם: + +- **מפתחות API לכל ארגון** נוצרים ומנוהלים על ידי חברי ארגון בלוח הבקרה (או דרך API המפתחות עם מפתח שנושא `keys:create`). ה-CLI **לא** מטבעות נתונים מפתחות. ראה [API Keys](/he/agenteye/api-keys). +- **החלפת ארגון** מובנה בלוח הבקרה; חברים משתנים בין הארגונים שהם שייכים להם מה-org switcher, ודפי scoped של ארגון משתהים תחת `//…`. +- **לוחות בקרה, שאילתות שמורות, התראות, וכל נתוני השימוש** קורים כולם בממשק ה-UI וב-API, scoped לארגון הנוכחי של החבר. + +המפעיל, באמצעות `agenteye-orgctl`, בעלים רק את הארגון + חבר **מחזור חיים**: יצור / שם שנה / מחק / טיהור ארגון, והוסף / רשימה / עדכון / הסר חבר. + +--- + +## ראה גם + +- [Deployment](/he/agenteye/deployment): `ORG_CH_SECRET` והשאר סביבת השרת. +- [Kubernetes Deployment](/he/agenteye/kubernetes-deployment): §2.6 יוצר את `agenteye-org-ch-secret` Secret לפני הארגון הרב-דייר הראשון שלך. +- [API Keys](/he/agenteye/api-keys): דגם מפתחות לכל ארגון ואסימוני ההרשאה המשמשים על ידי `--add` / `--remove`. +- [Troubleshooting](/he/agenteye/troubleshooting): בעיות הפקת ruleulti-tenant והבדל ClickHouse. \ No newline at end of file diff --git a/docs/he/agenteye/troubleshooting.mdx b/docs/he/agenteye/troubleshooting.mdx new file mode 100644 index 00000000..b16d2e54 --- /dev/null +++ b/docs/he/agenteye/troubleshooting.mdx @@ -0,0 +1,587 @@ +--- + +--- +title: "פתרון בעיות" +description: "תיעוד פתרון בעיות AgentEye." +--- + + +מדריך זה ממפה את הסימפטומים שסביר שתיתקלו בהם בפרודקשן לאבחון קונקרטי ותיקייה, כך שתוכלו לפתור תקלות מהכלים שכבר יש לכם, ללא צורך בהצבת תשתית תצפיתיות נוספת. הוא מכסה את השרת, אוסף נתונים, לוח בקרה, עוזר AI, Python SDK, ניטור בריאות ותעודות, גיבויים, ניתוח בתמיכת ClickHouse ותרובות עסקיות. + +עמודי לוח הבקרה הם בהיקף ארגוני תחת `//…`, וזרם האירועים הוא בעמוד הבית של הארגון (`//`). שמות העמודים במדריך זה (לדוגמה `/sessions`, `/queries`) מתייחסים לנתיבים בהיקף ארגון אלה. + +--- + +## הצגת רישומים + +AgentEye אינו מכלול ערימת רישום או ניטור. גם השרת וגם לוח הבקרה כותבים רישומים מובנים ל-**stdout**, כך שתוכלו לקרוא אותם ישירות עם `kubectl` או `docker`; אין צורך בצבירן. + +### Kubernetes + +עקוב אחרי רישומים חיים של השרת והלוח הבקרה: + +```bash +kubectl logs -n agenteye -l app=server -f --timestamps +kubectl logs -n agenteye -l app=dashboard -f --timestamps +``` + +וריאנטים שימושיים: + +| מטרה | פקודה | +|---|---| +| 200 שורות אחרונות (ללא עקוב) | `kubectl logs -n agenteye -l app=server --tail=200 --timestamps` | +| רישומים מהקריסה הקודמת | `kubectl logs -n agenteye --previous` | +| עקוב אחרי כל העתקים בו-זמנית | `kubectl logs -n agenteye -l app=server --max-log-requests=10 -f` | +| Postgres (StatefulSet) | `kubectl logs -n agenteye postgres-0 -f` | + +### Docker Compose + +```bash +docker logs -f agenteye-server +docker logs -f agenteye-dashboard +``` + +### קורלציה של בקשה יחידה על פני לוח בקרה והשרת + +כל בקשת לוח בקרה מתויגת עם `request_id` ומופצת לשרת דרך כותרת `x-request-id`. השרת חוזר אליה בכותרי התגובה שלו וב-כל שורת רישום שהוא פולט עבור בקשה זו. כדי לעקוב אחרי בקשה אחת מקצה לקצה: + +1. תפוס את המזהה מכותרת התגובה, לדוגמה: + ```bash + curl -i https://dashboard.example.com/api/events | grep -i x-request-id + # x-request-id: 9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a + ``` +2. חפש את המזהה ברישומי שתי התא: + ```bash + REQ=9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a + kubectl logs -n agenteye -l app=dashboard --tail=5000 | grep "$REQ" + kubectl logs -n agenteye -l app=server --tail=5000 | grep "$REQ" + ``` + +תראה את שורות `proxy passthrough`, `withAuth: authorized` ו-`upstream response` של לוח הבקרה ליד צמד `http request received` / `http request completed` של השרת, כולם חולקים את אותו `request_id`. + +### רישומי JSON ו-`jq` + +הגדר `AE_LOG_JSON=1` בלוח הבקרה (הוא מופעל כברירת מחדל כאשר `NODE_ENV=production`) כדי לפלוט אובייקט JSON אחד לכל שורה. ואז סנן מבחינה מבנית: + +```bash +kubectl logs -n agenteye -l app=dashboard --tail=5000 \ + | jq 'select(.level == "warn" or .level == "error")' + +kubectl logs -n agenteye -l app=dashboard --tail=5000 \ + | jq 'select(.route == "POST /api/keys")' +``` + +שרת Rust פולט זוגות `key=value` של עקיבה שעובדים טוב עם grep ללא `jq`: + +```bash +kubectl logs -n agenteye -l app=server --tail=5000 | grep 'status=5' # 5xx +kubectl logs -n agenteye -l app=server --tail=5000 | grep 'actor_key_id=' +``` + +### הגדלת הפירוט + +| רכיב | משתנה סביבה | דוגמה | +|---|---|---| +| שרת | `RUST_LOG` | `RUST_LOG=debug` או `RUST_LOG=agenteye_server=debug,info` | +| לוח בקרה | `AE_LOG_LEVEL` | `AE_LOG_LEVEL=debug` | + +`debug` בשרת מוסיף שורה `api key authenticated` לכל הזדהות. `debug` בלוח הבקרה מוסיף שורות `upstream request`, `session validated` ו-`proxy passthrough`. + +### שמירת רישומים + +stdout של מיכל הוא זמני; kubelet מסיר קבצי רישום (ברירת מחדל ~10 MiB לכל מיכל) ושומר מספר קטן בדיסק. לאחר מחיקת תא הרישומים מתחדלים. אם אתה צריך שמירה ארוכה יותר או חיפוש חוצה-תא, הצב את הקלאסטר שלך באוסף רישומים (Loki, CloudWatch, Cloud Logging, Datadog וכו') ש-tails `/var/log/containers/`. AgentEye אינו דורש או מנציח בחירה ספציפית כלשהי. + +--- + +## בעיות הזדהות + +### `docker pull` נכשל עם "unauthorized" + +ודא שביצעת הזדהות Docker מול GHCR עם ה-`AGENTEYE_TOKEN` שלך: + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +הטוקן חייב להיות בעל הרשאת `read:packages` בארגון `agenteye-enterprise`. צור קשר עם `support@exosphere.host` אם הטוקן שלך אינו פועל. + +### `gh release download` מחזיר 404 או 401 + +- ודא שה-`AGENTEYE_TOKEN` מיוצא בפגז שלך: `echo $AGENTEYE_TOKEN` +- ודא שאתה משתמש ב-`GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download ...` (ה-CLI `gh` קורא את `GITHUB_TOKEN`) +- הטוקן צריך `contents:read` על `agenteye-enterprise/releases` + +--- + +## בעיות שרת + +### השרת נכשל עם "invalid port number" + +ה-`POSTGRES_PASSWORD` (או דברים אחרים) מכילה תווים מיוחדים של URL (`/`, `+`, `=`) שמקלקלים ניתוח `DATABASE_URL`. צור מחדש את הסיסמה באמצעות קידוד hex: + +```bash +NEW_PASS=$(openssl rand -hex 24) +``` + +לאחר מכן עדכן את סוד Kubernetes וחסימה בתוך Postgres (או צור מחדש את `.env` ל-Docker Compose), והפעל מחדש את השרת. ראה את השלבים המלאים ב-[enterprise-docs/kubernetes-deployment.md](/he/agenteye/kubernetes-deployment) § "PostgreSQL credentials". + +### השרת יוצא מייד בעת הפעלה + +בדוק את רישומי המיכל: + +```bash +docker logs agenteye-server +``` + +סיבות נפוצות: +- `DATABASE_URL` לא הוגדר או מעוות: השרת יפלוט את השגיאה ויצא. +- Postgres אינו ניתן לגישה: ודא שמיכל Postgres או DB מנוהל פועלים וה-host/port נכונים. +- הגדרות כשלו: בדוק רישומים עבור שגיאות SQL. + +### `GET /health` מחזיר לא-200 או timeout + +השרת עדיין עשוי להריץ הגדרות בהפעלה הראשונה. המתן כמה שניות ונסה שוב: + +```bash +curl http://localhost:8080/health +``` + +אם הבעיה נמשכת, בדוק `docker logs agenteye-server` עבור שגיאות. + +### `GET /ready` מחזיר 503 + +`/ready` הוא בדיקת הכשירות: הוא מחזיר `503` כאשר השרת אינו יכול להגיע ל-**Postgres או ClickHouse**. הגוף קורא לתלות נכשלת: + +```bash +curl -s http://localhost:8080/ready +# {"status":"not_ready","checks":{"postgres":"ok","clickhouse":"down","redis":"ok"}} +``` + +תקן כל תלות שהוא מדווח כ-`down`: האם תא ClickHouse/Postgres הוא `Running`? האם `CLICKHOUSE_URL` / `DATABASE_URL` נכון וניתן לגישה? ב-Kubernetes התא קורא `NotReady` עד ל-`/ready` מתחדש; זה צפוי וזה בדיוק הסיגנל שניטור בריאות מתריע עליו. Redis לעולם אינו גורם: הוא מדווח אך אינו מכשל כשירות. + +### Collector מחזיר 401 Unauthorized + +מפתח ה-API של ה-collector אין לו הרשאת `events:add`, או המפתח הועסק. צור מפתח חדש עם ההרשאה הנכונה: + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{"name":"new-collector","permissions":["events:add"]}' +``` + +### בקשות מאומתות פתאום התאטו (~200ms במקום ~5ms) + +זה סימפטום של Redis שנמצא במצב Down בזמן הגדרת `REDIS_URL`. כל קריאה בשמורה timeout לאחר 100ms ואז נופל דרך ל-Postgres; בנתיבי הזדהות ו-OTP הבקשה עושה שתי נפילות כאלה. + +ודא ברישומי השרת: + +``` +auth cache: L2 get failed error=redis call timed out +``` + +פתרון: + +1. `redis-cli -h ping` כדי לאשר ש-Redis ניתן לגישה ברשת הקלאסטר. +2. אם Redis היה למטה לזמן קצר וכעת הוא חזרה, **הפעל מחדש את תא השרת**. ה-`redis::aio::ConnectionManager` אינו מתקים מחדש באופן אמין לאחר שהחיבור הבסיסי מופסק; הפעלה מחדש של תא בוחר את החיבור החדש בצורה נקייה. הדבר ישים גם ללוח הבקרה. +3. אם אתה לא רוצה להריץ Redis כעת, הסר הגדר את `REDIS_URL` בפריסה והפעל מחדש. שתי השירותים פועלים ללא השמורה (הנכונות נשמרת; הזמן חוזר לקו הבסיס לפני Redis). + +### שרת מדווח `OTP request rate-limited` ברישומים אך המשתמש אומר שניסה רק פעם אחת + +בדוק האם Redis היה לא ניתן לגישה. נתיב ה-fallback משתמש ב-`SELECT COUNT(*) FROM otp_codes WHERE created_at > now() - interval '15 minutes'`, שרואה שורות OTP שנוצרו בעבר. אם המשתמש לחץ על "Resend" למשך שעה, חלון 15 דקות עשוי עדיין להכיל ≥5 קודים. פתור על ידי המתנה להחלון להסתובב או `DELETE FROM otp_codes WHERE user_id = $1 AND created_at > now() - interval '15 minutes'` (קונסול מפעיל). + +### שינויתי את `ALLOWED_EMAILS` / `SESSION_TTL_SECS` / `OTP_TTL_SECS` והפעלתי מחדש; שום דבר לא קרה + +משתנה env אלה הם **זרעי הפעלה ראשונה בלבד**. ברגע שלטבלת `settings` יש שורה למפתח תואם, אותה שורה היא מקור האמת; משתנה env נקרא פעם אחת בהפעלה ראשונה ואז מתעלם בכל הפעלה מחדש שלאחר מכן. + +כדי לשנות אותם לאחר הפעלה ראשונה, התחבר ללוח הבקרה וערוך אותם תחת `/settings`. השינוי חל תוך שניות על כל העתקים; לא נדרשת הפעלה מחדש. + +אם אתה צריך להכריח מחדש זריעה מסביבה (נדיר, בדרך כלל שימושי רק בפיתוח), `DELETE FROM settings WHERE key = ''` והפעל מחדש את השרת. ה-bootstrap יבחר את ערך משתנה env הנוכחי בהפעלה הבאה. עריכה דרך `/settings` היא הנתיב הנתמך בפרודקשן. + +--- + +## בעיות Collector + +### Collector מתחיל אך אירועים אינם מופיעים בלוח הבקרה + +1. ודא ש-collector פועל: `systemctl status agenteye-collector` (Linux) או בדוק את התהליך. +2. ודא שה-`AGENTEYE_URL` מצביע על `http(s)://your-server-host:8080/events` (הערה: נתיב `/events`). +3. הפעל ניקוזי חד-פעמי כדי לראות פלט מיידי: + ```bash + agenteye-collector flush + ``` +4. בדוק ש-Python SDK בעצם כותב קבצים: `ls ${AGENTEYE_HOME:-~/.agenteye}/events/` +5. אם קבצים קיימים ב-`${AGENTEYE_HOME:-~/.agenteye}/failed/`, ההעלאות נכשלות. בדוק רישומי ה-collector עבור השגיאה, כנראה 4xx (מפתח רע או URL) או בעיית רשת. + +### קבצים צבורים ב-`$AGENTEYE_HOME/events/` והם לא מועלים + +- ה-collector אולי אינו פועל. התחל אותו: `agenteye-collector start`; הוא מרוקן אירועים קיימים באופן אוטומטי בעת ההפעלה. +- בדוק בריאות collector: `agenteye-collector health` +- ה-collector עשוי להיות פועל אך אינו יכול להגיע לשרת. בדוק כללי חומת אש בין מחשבי collector והשרת. + +### קבצים ב-`$AGENTEYE_HOME/failed/` + +קבצים עוברים ל-`failed/` לאחר ש-כל ניסיונות ה-retry מסתיימים (ברירת מחדל: 5 ניסיונות עם backoff אקספוננציאלי). זה אומר: +- השרת החזיר שגיאה 4xx (מפתח רע, URL שגוי, או בעיית payload) +- השרת היה לא ניתן לגישה עבור כל חלון ה-retry + +תקן את הבעיה הבסיסית, ואז הצב מחדש ידנית: + +```bash +mv ${AGENTEYE_HOME:-~/.agenteye}/failed/*.jsonl ${AGENTEYE_HOME:-~/.agenteye}/events/ +agenteye-collector flush +``` + +### Collector מדווח `network error` על כל העלאה (TLS handshake נכשל) + +אם `curl -k` מול `AGENTEYE_URL` מתבצע בהצלחה אך הבינארי collector נכשל בכל העלאה עם `error sending request for url (...)`, שרת AgentEye מציג תעודת TLS שלא חתומה על ידי CA נאמן ברבים. + +**ה-path של פרודקשן** הוא שם המארח של ה-ingest של ACME שהוגדר בתוך `deploy/base/certificates/domain.env` (ראה [`kubernetes-deployment.md`](/he/agenteye/kubernetes-deployment) שלב 3.1 / 4.2). ברגע שה-`INGEST_DOMAIN` מתפזרת ל-public Traefik LB ו-cert-manager הוציא את התעודה של Let's Encrypt, collectors אומתים את תעודת השרת מול חנות האמון של המערכת עם **ללא `AGENTEYE_TLS_CA` נדרש**; נקה אותה מתצורת ה-collector שלך אם היא הוגדרה נגד פריסה ישנה של חתימה עצמית. + +**סימפטום: collector עבד אתמול, נכשל היום לאחר פער ~90 יום.** זה אומר שהפריסה עדיין ב-legacy `selfsigned` issuer ל-`ingest-tls`. התעודה של 90 יום סובבה וקובץ ה-CA המוצמד ישן. תקן לצמיתות על ידי החלפת הקלאסטר ל-issuer ACME (שלב 3.1 של מדריך הפריסה). unblock לטווח קצר: חלץ מחדש את תעודת השרת הנוכחית ועדכן את `AGENTEYE_TLS_CA`: + +```bash +kubectl get secret ingest-tls-cert -n agenteye \ + -o jsonpath='{.data.tls\.crt}' | base64 -d > /etc/agenteye/server-ca.crt +``` + +```bash +export AGENTEYE_TLS_CA=/etc/agenteye/server-ca.crt +agenteye-collector flush +``` + +`AGENTEYE_TLS_CA` מוסיף עוגן אמון נוסף; שורשי הציבור הסטנדרטיים עדיין נאמנים. + +### `ingest-tls` התעודה תקועה `Ready: False` לאחר פריסה + +```bash +kubectl describe certificate ingest-tls -n agenteye +``` + +חפש באירועים וב-`Order` / `Challenge` המרופה. סיבות נפוצות: + +- **DNS לא מתפזר ל-LB הציבורי.** ה-HTTP-01 validator אינו יכול להגיע ל-`INGEST_DOMAIN`. אמת עם `dig +short INGEST_DOMAIN`; זה צריך להתפזר לאותו כתובת כמו ה-`EXTERNAL-IP` של LoadBalancer `traefik-public`. cert-manager חוזר אוטומטית ברגע שתזרים DNS מתפזרות; אין צורך למחוק את ה-Certificate. +- **יציאה 80 חסומה ב-LB / קבוצת אבטחה.** HTTP-01 דורש שיציאה 80 תהיה ניתנת לגישה מאמחזי הזקוק של Let's Encrypt הציבורים. אם יש לך WAF או SG ממסדר שמגביל `:80`, פתח אותה (תצורת Traefik מחדש כיוונית ל-HTTPS, אך Boulder עוקב אחרי ההפניה ומקבל את התגובה). +- **`dnsNames` לא מוחלפו.** אם `kubectl get certificate ingest-tls -n agenteye -o jsonpath='{.spec.dnsNames}'` מציג `INGEST_DOMAIN_PLACEHOLDER`, דלגת על שלב `domain.env`; צור אותו מ-`domain.env.example` והחל מחדש. +- **מוגבל בקצב על ידי Let's Encrypt.** בקשות נכשלות חוזרות ונשנות עבור אותו שם מארח טיוטונים כפילות-תעודה או גבולות validation-failed. המתן לפחות שעה לפני שחידוש; בדוק את Order status לקבלת הודעת rate-limit המדויקת. + +### `dashboard-tls` התעודה תקועה `Ready: False` / דפדפן עדיין מציג אזהרה + +זה אותו זרימת אבחון כמו `ingest-tls` למעלה (`kubectl describe certificate dashboard-tls -n agenteye`); ה-DNS, port-80, placeholder, ותחומי rate-limit כולם חלים, בתוספת שניים ספציפיים ללוח בקרה: + +- **`DASHBOARD_DOMAIN` מתפזר ל-LoadBalancer שגוי.** הוא חייב להצביע על LB Traefik **ללוח בקרה**, לא על הציבור ingest אחד. `dig +short` את השם המארח והשווה מול כתובת dashboard LB. +- **ה-Dashboard Traefik instance אינו יכול להציע את הטיוטה.** הוא חייב להיות מותקן עם קובץ ערכים מיידי ללוח בקרה, המאפשר ספק Ingress בהיקף עבור ה-HTTP-01 solver של cert-manager. ללא זה ה-solver אינו ניתן לנתוב והסדר נשאר `pending` לנצח. שדרגו את ה-instance עם הערכים שסופקו; הטיוטה הממתינה משלימה מעצמה. +- **ה-LoadBalancer הוגבל IP.** טווחי מקור חלים גם על יציאה 80, שחוסמת מאימתי Let's Encrypt — הן הנפקה ראשונית והן כל ~75 יום renewal. פתח מחדש את LB, או תאם פתרון DNS-01 עם תמיכה לפני נעילה. בזמן שהנפקה כשלת, לוח הבקרה ממשיך להציע את התעודה הקודמת שלו (או ברירת המחדל של ingress בהתקנה טרייה) — הגישה מושפלת על ידי אזהרת דפדפן, לעולם לא מופעלת. + +### CLI עדיין דולג אימות TLS לאחר שלוח הבקרה קיבל תעודה אמינה + +`--insecure` נשמר ל-`cli.json` בעת התחברות. ברגע שלוח הבקרה משרת תעודה אמינה ברבים, התחבר שוב עם `agenteye --base-url https:// --secure login`; אימות נשמר חזרה וההתריע בהפעלה נעלם. + +--- + +## בעיות לוח בקרה + +### לא ניתן להשבית או לערוך את ה-`ADMIN_EMAIL` משתמש + +בעיצוב. המשתמש המתאים ל-`ADMIN_EMAIL` מסומן כמוגן בכל הפעלה מחדש של שרת: לוח הבקרה מסתיר את לחצן ההשבתה לאותה שורה, וה-API דוחה `DELETE /users/:id` ו-`PUT /users/:id` נגדה עם `403 Forbidden`. טריגר מסד נתונים גם דוחה הצהרות `UPDATE` ישירות שיהיו משבתות את השורה המוגנת. + +כדי להסיע את ה-bootstrap admin, שנה את `ADMIN_EMAIL` בסביבה שלך והפעל מחדש את השרת. הדוא"ל החדש יתוקן כמוגן. ה-admin הקודם שומר על הדגל המוגן עד לניקוי במסד הנתונים (בדרך כלל בסדר, מכיוון שהדוא"ל הקודם עדיין admin תקף עד להסרה מפורשת). + +### לוח הבקרה אינו מציג אירועים + +1. ודא ש-URL של השרת ומפתח API נכונים בעיבור לוח הבקרה של משתנה סביבה (`AGENTEYE_SERVER_URL`, `AGENTEYE_API_KEY`). +2. מפתח API של לוח הבקרה צריך הרשאת `events:read`. +3. ודא שאירועים בעצם קלטו: `curl http://your-server:8080/events -H "Authorization: Bearer $ADMIN_KEY"` + +### `/errors` ריק אך `/events` מציג שורות אדומות + +גרסאות SDK חדשות יותר פולטות כשלים כ-`agent_end` / `tool_result` / `hook_completed` אירועים עם `outcome: "error"` בחומר התאים, ולא כ-שורת `event_type: "error"` ייעודית. עמוד `/errors` כעת תאם את שניהם: כל שורה שזרם `/events` צובע אדום (explicit `event_type='error'`, payload `outcome`/`status` בקבוצת הכשל, `is_error: true`, או שדה `error` truthy) מופיע ב-`/errors`. אם ראית בעבר "לא יש שגיאות בחלון זה" בעודשורות אדומות היו גלויות ב-`/events`, שדרגו את לוח הבקרה + שרת יחד (הסינון המורחב הוא `errored=true` על `GET /events`) ושתי התצוגות יסכימו. + +### `/models`, `/tools`, או `/hooks` איטי או נכשל להעלות בטווחי זמן רחבים + +**סימפטום:** בטבלת אירועים גדולה (מיליונים שורות), פתיחת `/models`, `/tools`, או `/hooks` — או הרחבת טווח הזמן ל-`7d`, `30d`, או `all` — התרשימים מסתובבים ואז מציגים שגיאת עומס. רישומי השרת תיעוד ClickHouse `MEMORY_LIMIT_EXCEEDED` (קוד 241) או timeout שאילתה עבור בקשת `latency_aggregate`. + +**סיבה:** בניות ישנות יותר חישבו rollup של חלקי עמודים אלה עם שאילתה שקראה את `payload` של האירוע הגולמי המלא וזיווגו אירועי בקשה/תגובה עם מיון וצירוף בזיכרון. זיכרון שאילתה שיא גדל עם גודל החלון, כך שבשוכר עסוק טווח רחב יכול לחרוג מתקרת הזיכרון לכל-שאילתה של ClickHouse. + +**תיקייה:** שדרגו לבנייה המכילה תיקייה זו. ה-rollup כעת קורא רק את העמודות ה-compact המקודמות וזיווגו אירועים עם aggregation זרימה, אז זיכרון שיא כבר לא משתנה עם payload גולמי — חלונות רחבים נשארים טוב תוך תקרת הזיכרון וחוזרים בשבריר זמן. השיפור הוא לחלוטין צד שאילתה: הוא חל על כל הנתונים הקיימים בטעינת עמוד הבאה, ללא reingest או backfill. + +### לוח הבקרה אינו טוען / עמוד ריק + +בדוק רישומי מיכל לוח הבקרה: + +```bash +docker logs agenteye-dashboard +``` + +הסיבה הנפוצה ביותר היא `AGENTEYE_SERVER_URL` או `AGENTEYE_API_KEY` חסרים או מצביעים לשרת לא ניתן לגישה. + +### ניתוח / טלמטריה של לוח בקרה + +לוח הבקרה שולח ניתוח שימוש במוצר אנונימי ל-PostHog כברירת מחדל, נתב דרך נתיב `/ingest` שלו (פרוקסי הפוך ל-`https://us.i.posthog.com`). השליחה ראשונה אומר שחוסמי פרסומות של דפדפנים לא מפילים אותם. זה עצמאי מפעילות הליבה של לוח הבקרה: + +- **מיכל לוח הבקרה** (לא הדפדפן) הוא מה שמגיע ל-PostHog. אם ההגישה היוצאת שלה ל-`https://us.i.posthog.com` חסומה, טלמטריה שוקטת no-ops; לוח הבקרה פועל בדרך כלל וללא שגיאות עולות למשתמשים. +- לא נכללים כל agent, session, או אירוע, רק שימוש ב-UI בלוח בקרה. +- כדי להשבית טלמטריה לחלוטין, הגדר את `AE_ANALYTICS_DISABLED=1` על מיכל לוח הבקרה והפעל מחדש. ראה [Telemetry & privacy](/he/agenteye/deployment#telemetry--privacy) במדריך הפריסה. + +### CLI ניתוח / טלמטריה + +ה-`agenteye` CLI שולח ניתוח שימוש אנונימי ל-PostHog כברירת מחדל: אילו פקודות פועלות, הצלחה/מצב יציאה, ומשך. זה עצמאי מפעילות ה-CLI: + +- **המכונה שמריצה את ה-CLI** מגיעה ישירות ל-`https://us.i.posthog.com`. אם ההגישה היוצאת שלה חסומה, טלמטריה שוקטת no-ops (השליחה כוללת זמן, כך שלעולם לא מעכבת פקודה) וה-CLI פועל בדרך כלל. +- לא נכללים כל agent, session, או אירוע: פקודה **arguments וערכי דגל** (URL לוח בקרה, token, דוא"ל, session ids, מסננים שאילתה) לעולם לא שולחו. +- כדי להשבית אותה, הגדר את `AGENTEYE_ANALYTICS_DISABLED=1` (או את `DO_NOT_TRACK=1` החוצה-כלי) בסביבת CLI. ראה [Telemetry & privacy](/he/agenteye/cli#telemetry--privacy) במדריך CLI. + +--- + +## בעיות עוזר AI + +ראה [enterprise-docs/assistant.md](/he/agenteye/assistant) להגדרה מלאה. + +### בועת העוזר לא מופיעה + +הבועה מוסתרת אלא אם **כל** אלה מחזיקים: + +- למשתמש המחובר יש הרשאת `agent:use`. +- `AGENTEYE_AGENT_URL` הוגדר בלוח הבקרה ושירות ה-`agent` ניתן לגישה. +- נקודת קצה LLM מוגדרת בשירות ה-`agent` (`ANTHROPIC_API_KEY`, שער דרך `ANTHROPIC_BASE_URL`, או Bedrock/Vertex). ללא כל הגדרה, ה-agent מדווח "לא מוגדר" והבועה נשארת מוסתרת. + +בדוק בריאות ה-agent מה-dashboard host: `curl http://agent:9100/health` צריך להחזיר `{"status":"ok","llm_configured":true,...}`. + +### העוזר אומר שהוא אינו יכול לקרוא משהו + +כלים מחוסמים לכל משתמש. אם משתמש חסר `evaluations:read` (או `events:read`, `dashboards:read`), כלים תואמים לא מוצעים והעוזר יאמר שהוא אינו יכול לקרוא נתונים אלה. הענק את הרשאת הקריאה הרלוונטית. + +### "assistant not configured" (HTTP 503) בעת שליחה + +מיכל ה-`agent` אין לו נקודת קצה LLM מוגדרת, או `AGENTEYE_AGENT_TOKEN` של לוח הבקרה לא תואם את ה-agent's. הגדר את שניהם והפעל מחדש. + +### מיכל ה-`agent` מופעל מחדש / OOMs תחת עומס + +כל שיחה מטילה תהליך ילד לזמן קצר. וודא שהמיכל פועל עם תהליך init (התמונה משתמשת ב-`tini`; בעיבוד הגדר `init: true`) ותן לו גבולות זיכרון הולמים. הפחת את `AGENTEYE_AGENT_MAX_STEPS` אם נחוץ. + +--- + +## בעיות CLI + +### `agenteye` נכשל להתחיל עם `ModuleNotFoundError: No module named 'click'` + +התקנה טרייה של ה-`agenteye` CLI בגרסה **0.1.6** יכולה להיקרע בהפעלה עם: + +``` +ModuleNotFoundError: No module named 'click' +``` + +0.1.6 סמך על `click` מותקן בעקיפין על ידי `typer`; `typer` releases אחרון כבר לא +משכו זה, אז סביבה נקייה סיימה חסרת החבילה. **שדרגו ל-0.1.7 או חדש יותר**, +שתלוי ב-`click` ישירות: + +```bash +pipx upgrade agenteye # אם מותקן עם pipx (או: pipx install --force agenteye) +uv tool upgrade agenteye # אם מותקן עם uv +pip install --upgrade agenteye +``` + +ראה [enterprise-docs/cli.md](/he/agenteye/cli) להנחיות התקנה. + +--- + +## בעיות Python SDK + +### לא קבצים מופיעים ב-`$AGENTEYE_HOME/events/` + +ה-SDK מנקדים אירועים ו-flushes כל 500 ms כברירת מחדל. אם התהליך שלך יוצא לפני ה-flush, אירועים עשויים להיאבד. קרא ל-`agenteye.configure(flush_interval=0.1)` עבור flush מהיר יותר בסקריפטים קצי-חיים, או וודא שהתהליך שלך פועל מזמן מספיק עבור מחזור flush. + +אם `AGENTEYE_HOME` הוגדר, אמת שה-SDK כותב ל-`$AGENTEYE_HOME/events/` ולא `~/.agenteye/events/` (דורש SDK ≥ 0.0.1b5). + +### `ValueError: Reserved field names cannot be used as custom fields` + +השמות `timestamp`, `type`, ו-`environment` שמורים ואינם יכולים לשמש כשדות מותאמים אישית. העברת כל אחד מהם מעלה: + +``` +ValueError: Reserved field names cannot be used as custom fields: [...] +``` + +שנה את שם השדה המותאם אישית הפוגע. שים לב שה-`session_id` ו-`agent_id` הם פרמטרים מפורשים של קריאת אירוע, לא שדות מותאמים אישית; העברת כל אחד מהם שוב כשדה מותאם אישית מעלה `TypeError`. + +--- + +## בעיות ניטור בריאות + +### לא התרעות הגיעו ל-Slack (Robusta) + +Robusta health alerting הוא **opt-in**; הוא שולח כלום עד להתקנה וייצוג לערוץ Slack. אמת את ה-release וה-sink שלו: + +```bash +kubectl get pods -n robusta # robusta-runner + robusta-forwarder אמורים להיות Running +kubectl logs -n robusta -l app=robusta-runner --tail=50 +``` + +סיבות נפוצות: ה-Slack `api_key` / `slack_channel` לא הוגדרו (או ה-token בוטל); ה-`api_key` הוא Robusta token relay (`robusta integrations slack`) אך `disableCloudRouting: true` של ערימה צריך token bot Slack ממשי (`xoxb-…`), או הגדר `disableCloudRouting: false`; sink `scope` לא כולל את namespace שתא שלך פועלים בה (הערכים של ערימה scope ל-`agenteye`); או לא כשל קרה עדיין. כוח בדיקה התרעה על ידי נטילת תא למטה: + +```bash +kubectl -n agenteye delete pod -l app=clickhouse # זה יוקצה מחדש +``` + +ראה [enterprise-docs/health-monitoring.md](/he/agenteye/health-monitoring#2-pod-failure-alerting-with-robusta-opt-in) להתקנה ותצורה. + +### שרת כל הזמן flapping `NotReady` + +בדיקת הכשירות מכה `/ready`, שנכשלת כאשר Postgres או ClickHouse לא ניתן לגישה. אם השרת מחזור מחוץ ל-`NotReady`, תלות זמינה בהתנהגות תנודה; בדוק את תא ClickHouse ו-Postgres ואת השרת's `CLICKHOUSE_URL` / `DATABASE_URL`. ודא מה `/ready` מדווח: + +```bash +kubectl -n agenteye exec deploy/server -- sh -c 'curl -s localhost:8080/ready' +``` + +בדיקה זו בעיצוב מעורבת (סף כשל נדיב), כך שתנודה מתמשכת מציינת בעיית תלות אמיתית ולא בדיקה התקפית עם יתר. חיוניות נשארת ב-`/health`, אז flapping כשירות **לא** הפעל מחדש את התא. + +## בעיות ניטור תעודה + +### CronJob לא שולח התרעות Slack + +ה-`cert-renewal-check` CronJob דורש URL ווכן Slack המאוחסן בסוד. אמת שהוא קיים: + +```bash +kubectl get secret cert-renewal-notify-config -n agenteye +``` + +אם חסר, צור אותו: + +```bash +kubectl create secret generic cert-renewal-notify-config \ + --namespace agenteye \ + --from-literal=SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL" +``` + +ללא הסוד, CronJob עדיין מריץ ותיעוד התוצאות ל-stdout. בדוק רישומים עם: + +```bash +kubectl logs -n agenteye -l job-name --tail=50 +``` + +### תעודת לקוח פגה לפני שהתרעה הוקבלה + +ה-CronJob מריץ כל 12 שעות. אם זה לא היה פעיל, בדוק את הסטטוס שלו: + +```bash +kubectl get cronjob cert-renewal-check -n agenteye +``` + +תגבור ידני בדיקה: + +```bash +kubectl create job --from=cronjob/cert-renewal-check manual-cert-check -n agenteye +kubectl logs -n agenteye -l job-name=manual-cert-check +``` + +כדי להוציא מחדש את התעודה הפגה מיד: + +```bash +cd base/certificates/client-certs +./issue-client-cert.sh +``` + +ואז החל את `collector-mtls-secret.yaml` שנוצר מחדש בקלאסטר(ים) שמריצים את ה-collectors שלך והפעל אותם מחדש: + +```bash +kubectl apply -f collector-mtls-secret.yaml -n +``` + +--- + +## בעיות גיבוי + +### `agenteye-backup` נכשל עם "No space left on device" + +ה-`agenteye-backup` CronJob עלס Postgres + ClickHouse לתא `backup-tmp` `emptyDir` scratch (ברירת מחדל `30Gi`), ואז **streams** את ארכיון `tar` ישר ל-S3 — ארכיון compressed לעולם לא כתוב חזרה ל-scratch, אז scratch רק צריך להחזיק את ה-**raw dumps**, לא dumps + עותק ארכיון on-disk שני. תא evicted / `No space left on device` אם כן אומר ש-**raw dumps** חרוגים מגודל scratch (ה-ClickHouse `events` dump שולט וגדל לאורך זמן). בדוק רישומי התא הנכשל: + +```bash +kubectl logs -n agenteye -l job-name= +``` + +תיקייה: בחפוץ שלך, הרם את CronJob's `backup-tmp` `emptyDir` `sizeLimit` מעל סכום ה-raw dump שלך, וודא שה-node's ephemeral storage באמת יכול להחזיק אותו (`sizeLimit` הוא cap, לא reservation). אם ה-dumps הגביר יחיד node's disk, החלף את ה-`emptyDir` עם PVC (EBS/PD) עבור `backup-tmp`, או דחוס את ה-dumps במקור. + +> רישומים ישנים יותר כתבו את ה-`.tar.gz` לתא ה-*same* `20Gi` scratch כמו ה-dumps, אז `dumps + archive` הציפו אותו והתא הופחת **לפני** ה-upload רץ — שנראה כמו כשל S3 אבל באמת דיסק. streaming ה-upload מסיר את הכפילות. + +### `agenteye-backup` נכשל להתקנה `curl` + +העבודה מריצה על `postgres:16` image ומתקנה `curl` בהפעלה עבור ה-ClickHouse HTTP dump. בקלאסטר ללא egress ל-Debian package mirrors, שלב `apt-get` נכשל. בחלוקה egress מה-backup pod, או בנה `curl` לתמונת backup mirrored/custom ותייחס אותה בחפוץ שלך. + +### `agenteye-backup` מריץ אך כלום נוחת ב-object storage + +הערימה הבסיסית מספקת אמיתי `BACKUP_BUCKET` (`ts-prod-agenteye/backups`) ו-`agenteye-backup` ServiceAccount. העבודה **streams** את הארכיון ל-S3 (`tar cz … | aws s3 cp - s3://…`). אם backup pod אין לו גישה כתיבה לדלי, ה-upload שגיאות — ובגלל שהתסריט מריץ תחת `set -euo pipefail`, כשל בכל מקום בצינור זה **כושל** את כל העבודה ב-צעד `upload` ולא בשקט no-op'ing (ה-EXIT trap של התא רושם `backup FAILED during step: upload`). זה גם הצעד שאתה מגיע *אחרי* תיקון חלל scratch eviction, אז אם גיבויים היו בעבר evicted ב-archive צעד, אמת ה-upload כעת נוחת. Grep רישומי התא הנכשל עבור שגיאת גישה S3: + +```bash +kubectl logs -n agenteye -l job-name= | grep -iE 's3|upload|denied' +``` + +תיקייה: בחפוץ שלך הגדר את `BACKUP_BUCKET` לדלי שאתה בעלות וה-annotate את `agenteye-backup` ServiceAccount הקיים עם גישת כתיבה (IRSA / Workload Identity / Pod Identity). ראה קטע **Backups** של [enterprise-docs/kubernetes-deployment.md](/he/agenteye/kubernetes-deployment). + +--- + +## ClickHouse-backed evaluations / sessions / queries + +### הסרגל הצדדי של עמוד `/queries` ריק לאחר שדרוג + +שלוש טבלות (`events`, `evaluations`, `agent_sessions`) צפויות. אם ה-SchemaBrowser sidebar ריק לאחר שדרוג, השרת כשל להחיל את ה-ClickHouse DDL בהפעלה. בדוק רישומי השרת עבור `failed to apply CH DDL statement`: + +```bash +kubectl logs -n agenteye deploy/server | grep -E 'clickhouse|CH DDL' +``` + +הסיבה הנפוצה ביותר היא ClickHouse לא ניתן לגישה בזמן הגדרות כלים. השרת מסרב להתחיל אם אינו יכול להגיע ל-CH, אז תא תקוע בדרך כלל יש `CrashLoopBackOff` ולא עמוד queries שבור בשקט, אבל DDL apply חלקי (הצהרה אחת בסדר, 5 הבא 5xx) משמיט חצי של schema. הפעל מחדש את תא השרת לאחר CH מאומת ניתן לגישה: + +```bash +kubectl rollout restart deploy/server -n agenteye +``` + +### evaluations חדשות אינם מופיעים ב-`/sessions` או `/queries` + +לאחר השדרוג, evaluations חדשות כתובות ל-ClickHouse, לא Postgres, וגל תחת `/sessions` (מחוסם ב-`evaluations:read`) וב-`/queries`. אם הם לא מופיעים: + +1. אמת שה-evaluator pipeline מופעל (`EVALUATOR_ENDPOINT` הגדר בשרת) וייצור terminal outcomes; בדוק עבור `evaluation_finalized` שורות רישום. +2. אמת CH ניתן לגישה מהשרת: `kubectl exec -n agenteye deploy/server -- curl -fsS http://clickhouse:8123/ping`. +3. spot-check הטבלה CH: `kubectl exec -n agenteye clickhouse-0 -- clickhouse-client -q 'SELECT count() FROM agenteye.evaluations'`. + +### שאילתות כשל תחת עומס עם "Memory limit exceeded", או ClickHouse הוא `OOMKilled` + +**סימפטום:** תחת כבד dashboard/query עומס, עמודות ניתוח (זרם האירועים, `/sessions`, תצוגה models/latency, עורך SQL) התחיל כשל או timeout; שרת בקצרה flaps `NotReady`; ו-ClickHouse pod מציג ספירת הפעלה מחדש עולה. זה כמעט תמיד **זיכרון**, לא CPU או דיסק. + +**אמת זה זיכרון** (לא בעיית תפוקה שrepلication יתקן): + +1. בדוק את התא עבור יציאות מחוסר זיכרון: + ```bash + kubectl -n agenteye describe pod clickhouse-0 | grep -iE 'Restart Count|Last State|Reason|OOMKilled' + ``` + `Reason: OOMKilled` / `Exit Code: 137` עם ספירת הפעלה מחדש טיפוס היא התאים. + +2. שאל את ClickHouse מה זה דוחה: + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT name, value FROM system.errors WHERE value>0 ORDER BY value DESC" + ``` + `MEMORY_LIMIT_EXCEEDED` ספירה גדולה היא החתימה. ההודעה קוראת *"maximum: N GiB"* — ש-**N הוא `0.9 × זיכרון התא limit`** (ה-`max_server_memory_usage_to_ram_ratio` ב-`deploy/base/clickhouse/configmap.yaml`). אם קריאות כבדות צריכות יותר מ-N, הם דחויים. + +3. שלול הדברים שהם *לא* הבעיה — אם CPU, part count, וכן דיסק כולם נמוכים, הוספת replicas/sharding יהיה בזבוז עלות: + ```bash + kubectl -n agenteye top pod clickhouse-0 + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT table, count() parts FROM system.parts WHERE active AND database='agenteye' GROUP BY table" + ``` + +**סיבה:** זיכרון limit של ClickHouse pod קטן מדי עבור ה-working set ניתוחי. הקריאות הכבדות ביותר משכו את JSON `payload` column, הרץ `JSONExtract*` על זה, ו-use `FINAL` — כל אחד יכול להיות צורך מספר GiB. אם ה-configured caches (`mark_cache_size` + `uncompressed_cache_size`) גדול מה-pod, הם מחברים אותו: caches מחוייבים לאותו תקציב וshadow query זיכרון. + +**תיקייה — בקנה מידה ClickHouse's זיכרון:** + +1. הרם את ClickHouse memory limit בחפוץ שלך על ידי תיקיה ה-`clickhouse` StatefulSet's container `resources` (אותו מנגנון overlay בשימוש עבור `resources` של רכיבים אחרים). ה-usable server תקציב הוא `0.9 × limit`, אז `6Gi` limit נותן ~5.4 GiB, `16Gi` נותן ~14 GiB. הגדר את `requests.memory` לרצפה אמיתית גם, אז ה-scheduler שומר אותו. החלת זה **משחזר את CH pod** (עותק יחיד → ~30–60s analytics downtime); לעשות זאת בחלון תנועה נמוך. +2. שמור את ה-caches ב-`deploy/base/clickhouse/configmap.yaml` פרופורציונאלי ל-limit — caches קטנים (כמה מאות MiB) בטוחים בpod קטן; רק להרים אותם לצד limiting memory הגדלת. כל-שאילתה `max_memory_usage` מוגדר במפורש ב-`users.xml` פרופיל (ראה הקטע קבוע-node למטה) ונשמר תחת השרת-level cap (`0.9 × limit`) אז אין שאילתה יחידה *מותר* יותר RAM מה-container יש. +3. אם ה-node עצמו הוא תקרה, בדוק את host זיכרון ClickHouse יכול לראות: + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT formatReadableSize(value) FROM system.asynchronous_metrics WHERE metric='OSMemoryTotal'" + ``` + אם זה רק קצת מעל זיכרון limit, ענן את ClickHouse ל-node גדול יותר (זיכרון-מופטימי) — דרך node selector/affinity בחפוץ שלך — לפני הגדלת limit עוד יותר. + +**כשאתה לא יכול להוסיף זיכרון: הרץ שאילתות בRAM ו-fail fast — אל תפזור על דיסק איטי.** אם ה-node קבוע והpod לא יכול גדל, cap מה כל שאילתה יחידה עשוי להשתמש (כך שאילתה אחת לא יכולה לקחת כל node) ועל **איטי (לא-SSD) data disk**, לעשות **לא** תן לגדול aggregations/sorts לפיזור לדיסק. פיזור לדיסק איטי הוא איטי יותר מserver's client read timeout, כל שאילתה spilling מחזיר dashboard `500` mid-flight בעודClickHouse ממשיך צחוק — שמירה שאילתות בRAM ודחיה של נדיר מעל-תקציב אחד *fast* (`MEMORY_LIMIT_EXCEEDED`, תת-שנייה) הוא מה restores loading. הערה gotcha ClickHouse עבור החלת אלה: + +- **אלה הם *פרופיל* הגדרות, וClickHouse קורא `` רק מ-`users_config` (`users.xml` / `users.d/*.xml`) — לעולם לא מ-`config.d`.** A `` בלוק מקום ב-`config.d/agenteye.xml` הוא **שקט תעלום** (`max_execution_time`, `max_memory_usage`, וכו' פשוט לא להחיל). הערימה בנויה אם כן מספקת אותם כ-`users.xml` מפתח ב-`clickhouse-config` ConfigMap, הר בעלות `/etc/clickhouse-server/users.d/agenteye.xml`. +- הספקת defaults: `max_memory_usage` (לכל-שאילתה תקרה — שאילתה אחת לא יכולה לצרוך את כל תקציב השרת), `max_bytes_before_external_group_by` / `max_bytes_before \ No newline at end of file diff --git a/docs/hi/agenteye/alerts.mdx b/docs/hi/agenteye/alerts.mdx new file mode 100644 index 00000000..1023a27d --- /dev/null +++ b/docs/hi/agenteye/alerts.mdx @@ -0,0 +1,308 @@ +--- +title: "अलर्ट्स" +description: "AgentEye अलर्ट्स दस्तावेज़।" +--- + +अलर्ट्स शेड्यूल के अनुसार एक नियम का मूल्यांकन करते हैं और आपको सूचित करते हैं जब कुछ थ्रेसहोल्ड पार करता है। वे AgentEye को एक निष्क्रिय डैशबोर्ड से एक पेजिंग सर्फेस में बदल देते हैं जो महत्वपूर्ण चीजों के लिए है: त्रुटि दर स्पाइक्स, विलंबता प्रतिगमन, मूल्यांकनकर्ता स्कोर ड्रॉप, या कोई भी कस्टम इवेंट जो आप ClickHouse क्वेरी के रूप में व्यक्त कर सकते हैं। + +यह गाइड कवर करती है कि एक अलर्ट क्या है, पांच ट्रिगर प्रकार, चार सूचना चैनल, घटना जीवनचक्र, और परिचालन नियंत्रण। + +![अलर्ट्स पृष्ठ: अलर्ट-नियम कार्डों की एक ग्रिड, प्रत्येक अपने ट्रिगर प्रकार, मूल्यांकन विंडो, चैनल, और एक जानकारी/चेतावनी/महत्वपूर्ण गंभीरता बैज दिखाता है](/agenteye/images/alerts.png) + +--- + +## अवधारणाएं + +- **अलर्ट** — नियम। यह कहता है *क्या* जांचना है (ट्रिगर), *कितनी बार* (मूल्यांकन अंतराल), *कब इसे टूटा हुआ मानें* (मिश्रित तर्क), *कितना तत्काल* (गंभीरता), और *किसे/कहां सूचित करें* (चैनल)। +- **घटना** — जब एक अलर्ट निकलता है तो क्या होता है। एक अलर्ट के पास एक बार में अधिकतम एक खुली घटना होती है। दोहराए गए उल्लंघन एक ही घटना के प्रमाण को अपडेट करते हैं। घटनाओं को एक ऑपरेटर द्वारा हल किया जाता है; जब नियम निकलना बंद हो जाए तो स्वचालित समाधान की योजना है लेकिन वर्तमान में सक्षम नहीं है। +- **चैनल** — एक सूचना कहाँ जाती है: ईमेल, Slack, सामान्य वेबहुक, या इन-डैशबोर्ड। प्रत्येक अलर्ट किसी भी संयोजन को संलग्न कर सकता है। + +अलर्ट्स और घटनाएं एक संगठन के अंतर्गत आती हैं और उस संगठन के ऑपरेटरों में साझा की जाती हैं (एक एकल-किरायेदार तैनाती में यह सरलता से निर्मित `default` संगठन है)। घटनाओं को एक व्यक्तिगत ऑपरेटर के लिए छंटाई के लिए असाइन किया जा सकता है। + +--- + +## ट्रिगर प्रकार + +पाँच प्रकार, प्रत्येक का अपना JSON विनिर्देश। उसे चुनें जो यह बताता है कि "टूटा हुआ" कैसा दिखता है। डैशबोर्ड का **नया अलर्ट** फॉर्म आपके लिए एक ही विनिर्देश बनाता है, ट्रिगर प्रकार से मेल खाने के लिए स्थिति संपादक को स्विच करता है: + +![नए-अलर्ट फॉर्म, बेसिक्स (नाम, विवरण, सक्षम) और ट्रिगर पिकर के साथ मीट्रिक थ्रेसहोल्ड, कस्टम SQL, मूल्यांकन स्कोर, मूल्यांकन विफलताएं, और प्रति-इवेंट विकल्प दिखाता है](/agenteye/images/alert-new.png) + +### 1. `metric_threshold` + +सबसे सरल। एक बंद सूची से मीट्रिक, एक ऑपरेटर, थ्रेसहोल्ड, और एक समय विंडो चुनें। + +| मीट्रिक | यह क्या गिनता है | +|---|---| +| `event_count` | विंडो में कुल इवेंट्स | +| `error_count` | `event_type = 'error'` या `error_type IS NOT NULL` वाली कोई भी इवेंट | +| `error_rate` | `error_count / event_count` (0..1) | +| `p95_latency_ms` | `quantile(0.95)(duration_ms)` `duration_ms` वाली सभी इवेंट्स के पार | +| `p99_latency_ms` | `quantile(0.99)(duration_ms)` | +| `token_sum` | `SUM(input_tokens + output_tokens)` | + +ऑपरेटर: `>`, `>=`, `<`, `<=`, `==` (भी स्वीकार किए गए `gt`, `gte`, `lt`, `lte`, `eq` के रूप में)। + +वैकल्पिक फिल्टर: `environment`, `event_type`। + +उदाहरण विनिर्देश: + +```json +{ + "metric": "p95_latency_ms", + "filter": { "environment": "production" }, + "window_secs": 900, + "op": ">", + "value": 5000 +} +``` + +### 2. `custom_sql` + +जो कुछ भी पूर्वनिर्धारित मीट्रिक्स को कवर नहीं करते। ऑपरेटर-आपूर्ति SQL उसी `/queries/run` गार्ड के माध्यम से जाता है (केवल SELECT/WITH, एकल स्टेटमेंट, 10,000-पंक्ति कैप) डिस्पैचर इसे चलाता है। दो मोड: + +- **पंक्तियों मोड** (कोई `op`/`value` नहीं): अलर्ट तुरंत निकलता है जैसे ही क्वेरी कम से कम एक पंक्ति देता है। +- **मान मोड**: क्वेरी को एक कॉलम को `metric_value` के रूप में उपनाम देना चाहिए; डिस्पैचर पहली पंक्ति के `metric_value` की तुलना `value` के साथ `op` का उपयोग करके करता है। + +```json +{ + "sql": "SELECT count() AS metric_value FROM agenteye.events WHERE event_type = 'error' AND ts >= now() - INTERVAL 1 HOUR", + "op": ">", + "value": 100 +} +``` + +### 3. `evaluation_score` + +`agenteye.evaluations` पढ़ता है और एक विंडो के पार एक नामित स्कोर के औसत की तुलना करता है। + +```json +{ + "score_key": "hallucination", + "op": ">", + "value": 0.6, + "window_secs": 3600, + "min_count": 5, + "environment": "production" +} +``` + +`min_count` एकल-नमूना आउटलायर्स से रक्षा करता है; डिस्पैचर विंडो में कम से कम N मूल्यांकन तक मौजूद होने तक निकलेगा नहीं। + +### 4. `eval_compound` + +एक गुणवत्ता प्रतिगमन को पकड़ें जो केवल *कई* मूल्यांकनकर्ता स्कोर्स में एक साथ दिखाई देता है। जहाँ `evaluation_score` एक एकल नामित स्कोर को देखता है, `eval_compound` कई मूल्यांकन-स्कोर शर्तों को एक अलर्ट में रचता है और उन्हें एक चुने हुए तर्क के साथ जोड़ता है; तो एक नियम व्यक्त कर सकता है "निकल जाएं यदि सहायकता **या** मतिभ्रम चढ़ता है", "निकल जाएं यदि सहायकता **और** उपकरण-दक्षता दोनों ड्रॉप हों", या "निकल जाएं यदि **कम से कम 2 से** ये तीन जांच उल्लंघन करें"। + +प्रत्येक शर्त साझा विंडो में `agenteye.evaluations` से एक नामित स्कोर के औसत को पढ़ता है और इसे अपने स्वयं के ऑपरेटर और थ्रेसहोल्ड के साथ परीक्षण करता है। बूलियन परिणाम फिर `combinator` द्वारा जोड़े जाते हैं: + +| कॉम्बिनेटर | तर्क | कब निकलता है | +|---|---|---| +| `"any"` | OR | कम से कम एक शर्त उल्लंघन करती है | +| `"all"` | AND | हर शर्त उल्लंघन करती है | +| `{ "at_least": N }` | M-of-N | कम से कम N शर्तें उल्लंघन करती हैं | + +```json +{ + "combinator": { "at_least": 2 }, + "conditions": [ + { "score_key": "hallucination", "op": ">", "value": 0.8 }, + { "score_key": "helpfulness", "op": "<", "value": 0.6 }, + { "score_key": "tone", "op": "<", "value": 0.5 } + ], + "window_secs": 3600, + "min_count": 5, + "environment": "production" +} +``` + +- `combinator`: `"any"`, `"all"`, या `{ "at_least": N }`। +- `conditions[]`: प्रत्येक `{ score_key, op, value }`, अन्य ट्रिगर्स के समान ऑपरेटर्स का उपयोग करते हुए (`>`, `>=`, `<`, `<=`, `==`)। +- `window_secs`: हर शर्त पर लागू साझा लुकबैक (डिफ़ॉल्ट `3600`)। +- `min_count`: प्रति-शर्त न्यूनतम संख्या मूल्यांकन जिसके बाद वह शर्त उल्लंघन कर सकती है; बहुत कम नमूनों वाली एक शर्त विंडो में "उल्लंघन नहीं" के रूप में गिनती है (डिफ़ॉल्ट `1`)। +- `environment`: वैकल्पिक; हर शर्त को एक पर्यावरण तक सीमित करता है। + +सूचना का प्रमाण प्रत्येक शर्त के अवलोकित औसत, इसे परीक्षित किया गया थ्रेसहोल्ड, कितने मूल्यांकन देखे गए, और क्या यह उल्लंघन हुआ रिकॉर्ड करता है; तो आप देख सकते हैं कि कौन सी जांचें ट्रिप हुईं। + +### 5. `per_event` + +"X से मेल खाने वाली कोई भी इवेंट आ गई है" अलर्ट्स के लिए। कोई एकत्रीकरण नहीं; डिस्पैचर तुरंत निकलता है जैसे ही यह लुकबैक विंडो में मेल देखता है। + +```json +{ + "event_type": "error", + "lookback_secs": 60, + "environment": "production", + "tool_name": "bash", + "agent_id": "caa", + "error_type": "TimeoutError", + "message_contains": "vertex-ai timed out" +} +``` + +सभी फिल्टर्स AND-संयुक्त हैं; कोई भी फील्ड जिसे आप छोड़ते हैं वह अनबाध है। + +| फील्ड | उद्देश्य | +|---|---| +| `agent_id` | एक विशिष्ट एजेंट (जो `/errors` पंक्ति पर दिखाया गया है) से त्रुटियों तक सीमित करें। | +| `error_type` | एक विशिष्ट त्रुटि वर्ग तक सीमित करें (जैसे `TimeoutError`) सभी त्रुटियों के बजाय। | +| `message_contains` | `payload.message` के विरुद्ध केस-असंवेदनशील सबस्ट्रिंग मेल। एक विशिष्ट विफलता मोड को पकड़ने के लिए उपयोगी (जैसे `prompt is too long`) एक ही एजेंट से हर त्रुटि पर अलर्ट किए बिना। 200 वर्णों तक सीमित; एक शाब्दिक स्ट्रिंग के रूप में मेल किया गया, पैटर्न नहीं। | + +टिप: `lookback_secs` को अलर्ट के `eval_interval_secs` से मोटे तौर पर मेल खाने के लिए सेट करें ताकि आप एक ही इवेंट पर दोबारा सूचित न हों। + +**`/errors` से शॉर्टकट:** प्रत्येक त्रुटि समूह की प्रतिनिधि पंक्ति त्रुटि दृश्य पर (और एक त्रुटि इवेंट के लिए सत्र इवेंट-विवरण पैनल) में एक **+ alert** बटन है जो `/alerts/new` को खोलता है जो `per_event` ट्रिगर के साथ भरा होता है उस पंक्ति के `event_type` + पर्यावरण के लिए, जब मौजूद हो तो पेलोड के `error_type` से बीजित नाम सहित। आप अभी भी चैनल चुनते हैं और लुकबैक की पुष्टि करते हैं, लेकिन मेल आपके लिए भरा होता है। ऑपरेटर्स को बटन दिखाई देने के लिए `alerts:write` की आवश्यकता होती है। + +--- + +## मिश्रित तर्क (M of N) + +हर अलर्ट में ट्रिगर के अलावा दो पूर्णांक नियंत्रण होते हैं: + +- `eval_window`: हाल के कितने मूल्यांकन देखने के लिए (डिफ़ॉल्ट 1) +- `min_breaches`: उनमें से कितने अलर्ट निकलने से पहले उल्लंघन करना चाहिए (डिफ़ॉल्ट 1) + +`1 of 1` (डिफ़ॉल्ट) "पहली उल्लंघन पर निकल जाएं" है। `3 of 5` का अर्थ है "निकल जाएं जब नियम पिछली 5 मूल्यांकन में से 3 को उल्लंघन कर चुका हो", झिलमिलाते हुए संकेतों के लिए उपयोगी जहां एक एकल खराब माप शोर है। डिस्पैचर प्रति अलर्ट एक रिंग बफर बनाए रखता है; आपको राज्य प्रबंधित करने की आवश्यकता नहीं है। + +--- + +## मूल्यांकन अंतराल + +`eval_interval_secs` नियंत्रित करता है कि डिस्पैचर आपके नियम को कितनी बार चलाता है। `[30, 86400]` तक क्लैंप किया गया। डैशबोर्ड में प्रीसेट्स: 1m / 5m / 15m / 1h। एक अंतराल चुनें जो अंतर्निहित संकेत कितनी तेजी से चलता है इससे मेल खाता है: एक 5-मिनट की त्रुटि-दर अलर्ट हर 15 सेकंड में मूल्यांकन किया गया CPU बर्बाद करता है; एक प्रति-इवेंट अलर्ट को एक छोटे लुकबैक की आवश्यकता है या यह टिक्स के बीच घटनाओं को चुप्पी से ड्रॉप करेगा। + +--- + +## चैनल्स + +प्रत्येक अलर्ट इन चारों में से किसी संयोजन को संलग्न कर सकता है। प्रति-चैनल क्रेडेंशियल्स (Slack वेबहुक URL, सामान्य वेबहुक URL + हस्ताक्षर गुप्त, डिफ़ॉल्ट ईमेल प्राप्तकर्ता) **`/settings`** में एक बार कॉन्फ़िगर किए जाते हैं और प्रत्येक अलर्ट से कुंजी द्वारा संदर्भित होते हैं। इस तरह एक Slack चैनल कई अलर्ट्स को सेवा दे सकता है बिना प्रत्येक का अपना वेबहुक URL की कॉपी संग्रहीत किए। + +तीन बाहरी चैनल प्रकार (ईमेल, Slack, वेबहुक) भी एक संगठन-व्यापी किल स्विच द्वारा गेटेड हैं, `alerts.enabled_channels`। जब एक निकली अलर्ट एक चैनल प्रकार को संलग्न करती है जो इस सेट में नहीं है, डिस्पैचर इसे छोड़ता है और स्थिति `skipped_disabled` और लक्ष्य `` के साथ एक `alert_notifications` पंक्ति रिकॉर्ड करता है (आपको वैश्विक रूप से रोकने देता है, उदाहरण के लिए, सभी Slack वितरण हर नियम को संपादित किए बिना)। इन-डैशबोर्ड चैनल हमेशा अनुमत है। [कॉन्फ़िगरेशन](#configuration) देखें। + +### ईमेल + +OTP लॉगिन ईमेल भेजने वाली ही SMTP ट्रांसपोर्ट को पुनः उपयोग करता है। प्राप्तकर्ता क्रम में समाधान करते हैं: + +1. प्रति-चैनल `recipients[]` ओवरराइड (जब गैर-खाली)। +2. `alerts.email_default_recipients` सेटिंग (ईमेल स्ट्रिंग्स की एक array)। + +यदि SMTP अनकॉन्फ़िगर किया गया है तो चैनल एक no-op है; डिस्पैचर अभी भी लक्ष्य `` के साथ एक `alert_notifications` पंक्ति रिकॉर्ड करता है ताकि ऑडिट ट्रेल गलतकॉन्फ़िगरेशन को दृश्यमान बनाता है। + +### Slack + +एक [incoming webhook URL](https://api.slack.com/messaging/webhooks) के लिए एक Block Kit संदेश भेजता है। + +- डिफ़ॉल्ट URL: `alerts.slack_default_webhook` (`/settings` में सेट)। +- प्रति-अलर्ट ओवरराइड: चैनल के `webhook_setting_key` को किसी अन्य URL-प्रकार की सेटिंग कुंजी पर सेट करें, जैसे `alerts.slack_oncall`, `alerts.slack_costs`। + +शीर्षलेख में एक गंभीरता इमोजी (`:rotating_light:` / `:warning:` / `:bell:`) शामिल है, और संदेश एक बटन ले जाता है जो घटना पृष्ठ को गहराई से लिंक करता है। + +### सामान्य वेबहुक + +PagerDuty, Opsgenie, या आपकी स्वयं की ingestion endpoint के लिए एक JSON-POST एकीकरण। बॉडी आकार: + +```json +{ + "schema_version": 1, + "event": "alert.firing", + "incident": { "id": "uuid", "url": "https://…/incidents/uuid", "opened_at": "2026-…" }, + "alert": { "id": "uuid", "name": "errors > 50/hr", "severity": "critical" }, + "breach": { "value": 73.0, "summary": "ErrorCount > 50 (observed 73.000)", "evidence": { … } } +} +``` + +जब `alerts.webhook_signing_secret` सेट किया गया है, तो अनुरोध में एक `X-AgentEye-Signature: sha256=` हेडर शामिल है, गुप्त का उपयोग करके बॉडी का HMAC-SHA256। पेलोड पर विश्वास करने से पहले प्राप्त करने वाले पक्ष पर इसे सत्यापित करें। + +हेडर `X-AgentEye-Event` `alert.firing` / `alert.test` ले जाता है। (`alert.resolved` योजना बद्ध auto-resolve फीचर के लिए आरक्षित है और वर्तमान में उत्सर्जित नहीं है।) + +### इन-डैशबोर्ड + +कोई बाहरी वितरण नहीं: अलर्ट केवल एक `alert_notifications` पंक्ति लिखता है जो डैशबोर्ड का घटनाएं पृष्ठ सतह करता है। जब आप एक नियम को ट्यून कर रहे हैं और बाहरी सिस्टम को स्पैम नहीं करना चाहते हैं तो उपयोगी, या कम-तत्काल अलर्ट्स के लिए जो ऑपरेटर सामान्य छंटाई के दौरान जांचते हैं। + +--- + +## घटना जीवनचक्र + +``` +firing ──ack──▶ acknowledged + │ │ + └────────────────────┴───── operator resolve ───▶ resolved +``` + +- **firing** — डिस्पैचर बस घटना को खोलता है या एक और उल्लंघन का पता लगाता है। निकली सूचना बिल्कुल एक बार प्रशंसकों की ओर है (घटना पर `notified_firing_at` टाइमस्टैम्प द्वारा गेटेड)। +- **acknowledged** — एक ऑपरेटर `/incidents/:id` पर *ack* दबाता है। घटना अभी भी खुली मानी जाती है; बाद की उल्लंघनें इसके प्रमाण को अपडेट करेंगी बिना पुनः-सूचित किए। +- **resolved** — एक ऑपरेटर *resolve* दबाता है। जब नियम निकलना बंद हो जाए तो स्वचालित समाधान की योजना है लेकिन वर्तमान में सक्षम नहीं है, इसलिए एक खुली घटना एक ऑपरेटर द्वारा इसे हल करने तक खुली रहती है। + +एक नई घटना किसी भी समय पिछली को हल करने के बाद एक ही अलर्ट पर फिर से खुल सकती है। + +**गतिविधि समयरेखा।** घटना पर हर कार्य — खोला, स्वीकार किया, हल किया — एक append-only गतिविधि लॉग में रिकॉर्ड किया जाता है और घटना की *गतिविधि* समयरेखा पर दिखाया जाता है, प्रत्येक प्रविष्टि इसे करने वाले ऑपरेटर को (ईमेल द्वारा) या **स्वचालित** के लिए जो कार्य डिस्पैचर ने अपने आप पर किए (उल्लंघन पर auto-open)। स्वीकृति साझा की जाती है: कई ऑपरेटर एक ही घटना को ack कर सकते हैं और प्रत्येक एक अलग, विशेषीकृत प्रविष्टि के रूप में दिखाई देता है। + +**घटनाएं** इनबॉक्स राज्य द्वारा खुली घटनाओं को समूहित करता है और आपको गंभीरता और असाइनी द्वारा फिल्टर करने देता है: + +![घटनाएं इनबॉक्स अलर्ट-लिंक्ड और ad-hoc घटना कार्ड्स गंभीरता बैजेस और असाइनी के साथ दिखा रहा है](/agenteye/images/incidents.png) + +एक घटना विवरण खोलना उल्लंघन प्रमाण, असाइनी और सदस्य, विशेषीकृत गतिविधि समयरेखा, और एक टिप्पणी थ्रेड दिखाता है: + +![एक घटना विवरण दृश्य: मातृ अलर्ट, उल्लंघन सारांश, असाइनी, सदस्य, विशेषीकृत गतिविधि लॉग, और बातचीत](/agenteye/images/incident-detail.png) + +--- + +## आवश्यक अनुमतियां + +अलर्ट *नियमों* को लिखना और *घटनाओं* को ट्रिएज करना अलग-अलग चिंताएं हैं जिनके अलग-अलग अनुदान हैं, इसलिए आप एक ऑन-कॉल रोटेशन को घटना पहुंच दे सकते हैं बिना नियमों को फिर से लिखने की क्षमता भी सौंप दिए। + +- `alerts:read`: अलर्ट नियमों को देखें। +- `alerts:write`: अलर्ट नियमों को बनाएं, संपादित करें, हटाएं, और एक परीक्षण सूचना ट्रिगर करें। +- `incidents:read`: घटनाओं को देखें। +- `incidents:write`: मैनुअल (ad-hoc) घटनाएं खोलें जो एक अलर्ट से जुड़ी नहीं हैं। +- `incidents:ack`: घटनाओं को स्वीकार करें, असाइन करें, टिप्पणी करें, और हल करें। + +> **विरासत `alerts:ack`।** कुंजियां और ऑपरेटर जिन्हें पुरानी `alerts:ack` टोकन दी गई थी काम करते रहें: इसे `incidents:ack` के रूप में सम्मानित किया जाता है (और `incidents:read` को दर्शाता है), इसलिए मौजूदा ऑन-कॉलर्स को क्रेडेंशियल फिर से जारी किए बिना अपनी पहुंच बनाए रखते हैं। `incidents:*` परिवार के साथ नए अनुदान जारी करें। + +API कुंजियों पर अनुदान (`POST /keys`) और ऑपरेटर (`PUT /users/:id`)। डैशबोर्ड का `PermGate` संबंधित बटनों को तब लॉक करता है जब कोई अनुमति गायब हो; आप कार्य के आगे `// 403` देखेंगे। + +> **ईमेल-प्राप्तकर्ता पिकर।** अलर्ट संपादक का प्राप्तकर्ता पिकर आपके संगठन के सदस्यों को सूचीबद्ध करता है ताकि आप उन्हें नाम से चुन सकें। यह किसी भी ऑपरेटर के लिए लोड होता है जिसके पास `alerts:read` या `alerts:write` है; इस उद्देश्य के लिए अपनी टीम की निर्देशिका देखना `users:read` की आवश्यकता नहीं है, और पिकर केवल सदस्य ईमेल पते लौटाता है, पूर्ण उपयोगकर्ता रिकॉर्ड कभी नहीं। + +--- + +## कॉन्फ़िगरेशन + +डिस्पैचर द्वारा उपभोग किए गए पर्यावरण चर: + +| चर | डिफ़ॉल्ट | उद्देश्य | +|---|---|---| +| `ALERT_WORKERS` | `1` | प्रति सर्वर उदाहरण कार्य कार्य। अधिकांश तैनाती को केवल एक की आवश्यकता है। | +| `ALERT_CLAIM_BATCH` | `16` | अधिकतम अलर्ट्स एक एकल कार्यकर्ता टिक प्रक्रिया करता है। | +| `ALERT_POLL_IDLE_SECS` | `5` | जब कतार खाली हो तो कार्यकर्ता नींद। | +| `ALERT_REQUEST_TIMEOUT_MS` | `15000` | प्रति-ट्रिगर मूल्यांकन समय सीमा। | +| `DASHBOARD_URL` | `https://app.befailproof.ai` | मूल जिसका उपयोग सूचनाओं में घटना जादू-लिंक बनाने के लिए किया जाता है। अपने डैशबोर्ड होस्ट पर सेट करें। | + +एक अनुपस्थित मूल्यांकन विफलता के बाद (ClickHouse पहुंचने योग्य नहीं, एक क्वेरी समय सीमा), डिस्पैचर घातीय backoff के साथ नियम को फिर से प्रयास करता है। एक बार जब एक नियम **5** लगातार अनुपस्थित विफलताओं को जमा कर दिया है तो यह backoff जारी रखने के बजाय अपने सामान्य cadence पर फिर से अनुसूचित किया जाता है, इसलिए एक लगातार विफल नियम अभी भी फिर से मूल्यांकन किए जाते रहते हैं। यह सीमा तय की गई है और ऑपरेटर-tunable नहीं है। + +चैनल सेटिंग्स (`/settings` से प्रबंधित, env नहीं): + +- `alerts.email_default_recipients` (`email_list`): ईमेल स्ट्रिंग्स की JSON array — ईमेल चैनल्स के लिए डिफ़ॉल्ट प्राप्तकर्ता। +- `alerts.slack_default_webhook` (`url`): डिफ़ॉल्ट Slack incoming-webhook URL। +- `alerts.webhook_default_url` (`url`): डिफ़ॉल्ट सामान्य-वेबहुक URL। +- `alerts.webhook_signing_secret` (`secret`): HMAC-SHA256 कुंजी। GET प्रतिक्रिया में हमेशा `""` के रूप में लौटाया जाता है; घुमाने के लिए एक नया मान टाइप करें। +- `alerts.enabled_channels` (`channel_set`): बाहरी चैनल प्रकार्स का संगठन-व्यापी सेट जो अलर्ट निकलता है; सभी तीन के लिए डिफ़ॉल्ट (`email`, `slack`, `webhook`)। एक प्रकार को यहां हटाने से हर अलर्ट के लिए संपादित किए बिना उस चैनल को वैश्विक रूप से दबा दिया जाता है। इन-डैशबोर्ड चैनल हमेशा वितरित किया जाता है और इस सेटिंग से प्रभावित नहीं है। + +--- + +## एक नए अलर्ट को सत्यापित करें + +एक नए अलर्ट पर निर्भर करने से पहले: + +1. इसे कम से कम एक सूचना चैनल के साथ सक्षम के रूप में सहेजें। +2. अलर्ट विवरण पृष्ठ पर **परीक्षण** का चयन करें और पुष्टि करें कि प्रत्येक कॉन्फ़िगर किया गया गंतव्य सिंथेटिक सूचना प्राप्त करता है। +3. पहली वास्तविक उल्लंघन के बाद, पुष्टि करें कि घटना **घटनाएं** के अंतर्गत दिखाई देती है और इसका मापा मूल्य संबंधित डैशबोर्ड क्वेरी से मेल खाता है। + +जब एक शर्त स्पष्ट हो जाती है तो घटनाएं स्वचालित रूप से हल नहीं होती हैं। एक ऑपरेटर को घटना विवरण पृष्ठ से उन्हें हल करना चाहिए। + +--- + +## समस्या निवारण + +| लक्षण | संभावित कारण | +|---|---| +| अलर्ट कभी निकलता नहीं | `enabled = false`, या कोई चैनल संलग्न नहीं, या अंतर्निहित CH क्वेरी 0 पंक्तियां देता है। चैनल की पुष्टि करने के लिए *परीक्षण* का उपयोग करें; मीट्रिक की पुष्टि करने के लिए `/queries/run` का उपयोग करें। | +| Slack सूचना गायब | `alerts.slack_default_webhook` (या प्रति-अलर्ट ओवरराइड कुंजी) अनसेट है: `alert_notifications.target` में `` पंक्तियों के लिए जांचें; या `slack` प्रकार `alerts.enabled_channels` में वैश्विक रूप से अक्षम है: `alert_notifications` पंक्तियों को स्थिति `skipped_disabled` और लक्ष्य `` के साथ जांचें। | +| सामान्य वेबहुक 401 | प्राप्तकर्ता एक हस्ताक्षर की आवश्यकता है लेकिन `alerts.webhook_signing_secret` अनसेट है। प्राप्तकर्ता पर सत्यापित करें कि HMAC `hmac_sha256(secret, body)` से मेल खाता है। | +| ईमेल "सभी भेजने विफल से" | SMTP क्रेडेंशियल गलत या `from` पता आपके रिले द्वारा अस्वीकृत है। एक ही सतह जो OTP ईमेल भेजती है: यदि वह काम करते हैं, SMTP ट्रांसपोर्ट ठीक है। | +| घटना बार-बार फिर से खुलती है | मिश्रित नियंत्रण बहुत आक्रामक हैं: `min_breaches` बढ़ाने या `eval_window` बढ़ाने का प्रयास करें ताकि अस्थायी स्पाइक्स आप हल की गई घटनाओं को फिर से न खोलें। | \ No newline at end of file diff --git a/docs/hi/agenteye/api-keys.mdx b/docs/hi/agenteye/api-keys.mdx new file mode 100644 index 00000000..7dd7fdc3 --- /dev/null +++ b/docs/hi/agenteye/api-keys.mdx @@ -0,0 +1,255 @@ +--- +title: "API कुंजियाँ" +description: "AgentEye API कुंजियाँ दस्तावेज़।" +--- + + +AgentEye सर्वर तक पहुँच को नियंत्रित करने के लिए बारीक-दानेदार API कुंजियों का उपयोग करता है। प्रत्येक कुंजी एक या अधिक अनुमतियों के साथ आती है जो यह निर्धारित करती है कि यह क्या कर सकती है। + +--- + +## अनुमतियाँ + +सर्वर अनुमतियों का एक निश्चित कैटलॉग लागू करता है; प्रत्येक विशेष HTTP मार्गों को गेट करता है। एक **व्यवस्थापक कुंजी** सभी को रखती है; एक स्कोप की गई कुंजी वह सबसेट रखती है जिसे आप निर्माण पर देते हैं। अज्ञात अनुमति स्ट्रिंग्स को तब अस्वीकार कर दिया जाता है जब कुंजी बनाई जाती है। + +> **कुंजियों को असाइन करने योग्य नहीं।** दो वैध अनुमतियाँ मानव/डैशबोर्ड-केवल हैं और API कुंजी को नहीं दी जा सकतीं: `orgs:admin` (उदाहरण प्रशासन, जो केवल ऑपरेटर है) और `keys:update`। `POST /keys` या `PATCH /keys/:id` के लिए एक अनुरोध जो इनमें से किसी एक को देने का प्रयास करता है, HTTP 422 के साथ अस्वीकार कर दिया जाता है। `keys:update` पंक्ति नीचे देखें कि एक वहन करने वाली कुंजी कुंजियाँ क्यों बना सकती है लेकिन कभी उन्हें संपादित नहीं कर सकतीं। + +### ईवेंट्स इंजेस्ट और क्वेरी + +| अनुमति | HTTP मार्ग | यह क्या अनुमति देता है | +|---|---|---| +| `events:add` | `POST /events` | एक कलेक्टर से ईवेंट्स के बैच को अंतर्ग्रहण करें। एकमात्र अनुमति जिसकी एक कलेक्टर को आवश्यकता है। | +| `events:read` | `GET /events`, `GET /events/latency_aggregate`, `GET /events/environments`, `GET /events/models`, `GET /sessions/:session_id/export` | ईवेंट्स को क्वेरी करें, ज्ञात वातावरणों को सूचीबद्ध करें, डेटा में देखी गई मॉडल पहचानकर्ताओं को सूचीबद्ध करें (मॉडल्स व्यू और मॉडल फ़िल्टर्स द्वारा उपयोग किए जाते हैं), हीट-मैप / प्रतिशतक बैंड को शक्ति देने वाली विलंबता समुच्चय की गणना करें, और सत्र को JSONL के रूप में निर्यात करें। साझा फ़िल्टर-बार पहलू समापन बिंदु `GET /events/environments` और `GET /events/models` **या तो** `events:read` **या** `evaluations:read` के साथ पहुंचने योग्य हैं, इसलिए सत्र पृष्ठ (गेटेड `evaluations:read`) समान प्रति-org पहलू का पुनः उपयोग करता है। | + +### सत्र और मूल्यांकन + +| अनुमति | HTTP मार्ग | यह क्या अनुमति देता है | +|---|---|---| +| `evaluations:read` | `GET /sessions`, `GET /evaluations`, `GET /evaluations/aggregate`, `GET /evaluations/environments`, `GET /evaluation-jobs` | सत्रों को सूचीबद्ध करें, मूल्यांकन परिणामों को पढ़ें, डैशबोर्ड द्वारा उपयोग की जाने वाली रोल-अप eval स्वास्थ्य, और मूल्यांकन-कार्य कार्यकर्ता कतार स्थिति। | +| `evaluations:trigger` | `POST /sessions/:session_id/re-evaluate` | एक समाप्त सत्र के लिए मैनुअली रूप से पुनः-मूल्यांकन में कतार डालें। | + +### डैशबोर्ड + +| अनुमति | HTTP मार्ग | यह क्या अनुमति देता है | +|---|---|---| +| `dashboards:read` | `GET /dashboards`, `GET /dashboards/:id`, `GET /dashboards/:id/tiles` | डैशबोर्ड को सूचीबद्ध करें, एक को लोड करें, और इसकी टाइलों को पढ़ें। | +| `dashboards:write` | `POST /dashboards`, `PUT /dashboards/:id`, `POST /dashboards/:id/tiles`, `PUT /dashboards/:id/tiles/:tile_id`, `DELETE /dashboards/:id/tiles/:tile_id`, `PUT /dashboards/:id/tiles/layout` | डैशबोर्ड बनाएं और संपादित करें, टाइलें जोड़ें / संपादित करें / निकालें, और टाइल ग्रिड को पुनः क्रमित करें। | +| `dashboards:delete` | `DELETE /dashboards/:id` | एक संपूर्ण डैशबोर्ड को हटाएं (टाइल-स्तर का विलोपन `dashboards:write` के अंतर्गत रहता है)। | + +### सहेजी गई क्वेरीज़ (SQL संगीतकार) + +| अनुमति | HTTP मार्ग | यह क्या अनुमति देता है | +|---|---|---| +| `queries:read` | `GET /queries`, `GET /queries/:id`, `GET /queries/schema` | सहेजी गई क्वेरीज़ को सूचीबद्ध करें, एक को लोड करें, और संगीतकार को लक्ष्य करने वाली केवल-पढ़ने के लिए ClickHouse स्कीमा का निरीक्षण करें। | +| `queries:write` | `POST /queries`, `PUT /queries/:id` | सहेजी गई क्वेरीज़ बनाएं और संपादित करें। SQL को अभी भी `queries:run` कॉल के रूप में एक ही केवल-पढ़ने के लिए भूमिका और `sql_guard` जाँचों के माध्यम से भेजा जाता है। | +| `queries:delete` | `DELETE /queries/:id` | एक सहेजी गई क्वेरी को हटाएं। | +| `queries:run` | `POST /queries/run` | संगीतकार द्वारा उपयोग की जाने वाली केवल-पढ़ने के लिए भूमिका के विरुद्ध सहेजी गई या तदर्थ SQL निष्पादित करें। | + +### AI सहायक + +| अनुमति | HTTP मार्ग | यह क्या अनुमति देता है | +|---|---|---| +| `agent:use` | `GET /agent/conversations`, `POST /agent/conversations`, `GET /agent/conversations/:id`, `PATCH /agent/conversations/:id`, `DELETE /agent/conversations/:id`, `PUT /agent/conversations/:id/messages` | डैशबोर्ड AI सहायक से बात करें और अपनी स्वयं की (निजी) बातचीत का प्रबंधन करें। सहायक डॉक को देखने के लिए **उपयोगकर्ता** पर आवश्यक; सहायक की स्वयं की कुंजी `dashboard-assistant` है और अलग से बीज की जाती है (नीचे देखें)। | + +### API कुंजियाँ + +| अनुमति | HTTP मार्ग | यह क्या अनुमति देता है | +|---|---|---| +| `keys:create` | `POST /keys` | एक नई स्कोप की गई API कुंजी बनाएं। एक मौजूदा कुंजी की अनुमतियों को संपादित करने के लिए **अनुदान नहीं देता** (वह `keys:update` है)। | +| `keys:read` | `GET /keys` | मौजूदा कुंजियों को सूचीबद्ध करें। इस समापन बिंदु द्वारा रहस्य कभी नहीं लौटाए जाते हैं। | +| `keys:update` | `PATCH /keys/:id` | एक मौजूदा कुंजी की अनुमतियों को संपादित करें। एक **मानव/डैशबोर्ड-केवल** अनुमति; इसे API कुंजी को असाइन नहीं किया जा सकता (एक वहन करने वाली कुंजी कुंजियाँ बना सकती है लेकिन कभी उन्हें संपादित नहीं कर सकतीं)। | +| `keys:disable` | `POST /keys/:id/disable` | कुंजी को निरस्त करें। संरक्षित कुंजियाँ (`admin`, `dashboard-assistant`) को निकाला नहीं जा सकता; env var + पुनः आरंभ के माध्यम से उन्हें घुमाएं। | +| `keys:regenerate` | `POST /keys/:id/regenerate` | कुंजी के रहस्य को घुमाएं। संरक्षित कुंजियों को इस मार्ग के माध्यम से पुनः उत्पन्न नहीं किया जा सकता। | + +### डैशबोर्ड उपयोगकर्ता + +| अनुमति | HTTP मार्ग | यह क्या अनुमति देता है | +|---|---|---| +| `users:create` | `POST /users`, `GET /users/defaults` | एक नए डैशबोर्ड उपयोगकर्ता को आमंत्रित करें (ईमेल + OTP लॉगिन जारी करता है) और डैशबोर्ड-कॉन्फ़िगर की गई डिफ़ॉल्ट अनुमति सेट को पढ़ें जिसका उपयोग आमंत्रण फॉर्म को सीड करने के लिए किया जाता है। | +| `users:read` | `GET /users`, `GET /users/:id` | उपयोगकर्ताओं को सूचीबद्ध करें और एक एकल उपयोगकर्ता रिकॉर्ड को लोड करें। | +| `users:update` | `PUT /users/:id` | एक उपयोगकर्ता की अनुमतियों को संपादित करें। अपडेट एक अनुमति-परिवर्तन ईमेल को प्रभावित उपयोगकर्ता को भेजता है और उनके अगले अनुरोध पर प्रभावी होता है; कोई पुनः लॉगिन आवश्यक नहीं है। | +| `users:delete` | `DELETE /users/:id`, `POST /users/:id/enable` | एक उपयोगकर्ता को अक्षम करें (तुरंत उनके सत्रों को निरस्त करता है) और एक पहले से अक्षम उपयोगकर्ता को पुनः सक्षम करें। | + +ये अनुमतियाँ डैशबोर्ड के **उपयोगकर्ता** पृष्ठ को समर्थन देती हैं, जहाँ प्रत्येक सदस्य की प्रदान की गई स्कोप चिप्स के रूप में दिखाई देती है: + +![उपयोगकर्ता पृष्ठ: डैशबोर्ड उपयोगकर्ता प्रति एक कार्ड जिसमें उनका ईमेल, प्रदान की गई अनुमतियाँ, और संपादन/अक्षम नियंत्रण हैं](/agenteye/images/users.png) + +### परिचालन सेटिंग्स + +| अनुमति | HTTP मार्ग | यह क्या अनुमति देता है | +|---|---|---| +| `settings:read` | `GET /settings`, `GET /settings/schema`, `GET /settings/model-context-windows`, `GET /settings/model-context-windows/resolve` | डैशबोर्ड-प्रबंधित परिचालन सेटिंग्स और उनके मेटाडेटा को देखें; प्रति-मॉडल संदर्भ-विंडो ओवरराइड को सूचीबद्ध करें; और एक मॉडल के लिए प्रभावी विंडो को हल करें। | +| `settings:write` | `PUT /settings/:key`, `PUT /settings/model-context-windows`, `DELETE /settings/model-context-windows` | परिचालन सेटिंग्स को संपादित करें और प्रति-मॉडल संदर्भ-विंडो ओवरराइड जोड़ें, बदलें, या निकालें। परिवर्तन सर्वर को पुनः आरंभ किए बिना नई ईवेंट्स को प्रभावित करते हैं। | + +![सेटिंग्स पृष्ठ: डैशबोर्ड-प्रबंधित परिचालन सेटिंग्स जैसे अनुमत साइन-इन और सत्र/OTP जीवनकाल, पुनः आरंभ के बिना संपादन योग्य](/agenteye/images/settings.png) + +### अलर्ट्स और घटनाएं + +| अनुमति | HTTP मार्ग | यह क्या अनुमति देता है | +|---|---|---| +| `alerts:read` | `GET /alerts`, `GET /alerts/:id` | कॉन्फ़िगर किए गए अलर्ट परिभाषाओं को देखें। | +| `alerts:write` | `POST /alerts`, `PUT /alerts/:id`, `DELETE /alerts/:id`, `POST /alerts/:id/test` | अलर्ट परिभाषाओं को बनाएं, संपादित करें, हटाएं, और परीक्षण-फायर करें। | +| `incidents:read` | `GET /alerts/incidents`, `GET /alerts/incidents/:iid`, `GET /alerts/incidents/:iid/comments`, `GET /alerts/incidents/:iid/subscribers` | घटनाओं और उनके ट्रिएज ट्रेल को देखें। | +| `incidents:write` | `POST /alerts/:id/incidents` | एक मौजूदा अलर्ट के विरुद्ध मैनुअली रूप से एक घटना खोलें। | +| `incidents:ack` | `POST /alerts/incidents/:iid/ack`, `POST /alerts/incidents/:iid/assign`, `POST /alerts/incidents/:iid/resolve`, `POST /alerts/incidents/:iid/comments`, `POST /alerts/incidents/:iid/subscribe`, `POST /alerts/incidents/:iid/unsubscribe` | घटनाओं को स्वीकार करें, असाइन करें, हल करें, और टिप्पणी करें। | + +### ऑडिट्स + +| अनुमति | HTTP मार्ग | यह क्या अनुमति देता है | +|---|---|---| +| `audits:read` | `GET /audits`, `GET /audits/:id`, `GET /audits/:id/runs`, `GET /audits/findings`, `GET /audits/findings/:fid` | ऑडिट परिभाषाएं, रन इतिहास, और निष्कर्ष देखें। | +| `audits:write` | `POST /audits`, `PUT /audits/:id`, `DELETE /audits/:id`, `POST /audits/:id/run`, `POST /audits/findings/:fid/status` | ऑडिट्स बनाएं, संपादित करें, हटाएं, और चलाएं; निष्कर्षों को ट्रिएज करें (स्वीकार करें / शांत करें / खारिज करें / हल करें / फिर से खोलें / असाइन करें)। | + +> जब ऑडिट्स शिप किए गए थे, तो मौजूदा अनुदानकर्ताओं को अलर्ट्स के समान भूमिका आकार के साथ चौड़ा किया गया था: `alerts:read` रखने वाले प्रत्येक उपयोगकर्ता और अनुमति सेट को `audits:read` मिला, और `alerts:write` के प्रत्येक धारक को `audits:write` मिला। मौजूदा API कुंजियों को **चौड़ा नहीं** किया गया — यदि कुंजी को ऑडिट सतह की आवश्यकता है तो स्पष्ट रूप से `audits:*` को देते हैं। + +> विरासत `alerts:ack` टोकन के संग्रहीत अनुदान को `incidents:ack` के रूप में पार्स किया जाता है ताकि ऑन-कॉलर्स को पुनः कीइंग के बिना पहुँच बनी रहे। टोकन को अब डैशबोर्ड के उपयोगकर्ता संपादक से असाइन नहीं किया जा सकता है; मैट्रिक्स `incidents:ack` की पेशकश करता है। + +> प्राप्तकर्ता-पिकर समापन बिंदु `GET /alerts/recipients` (जो सदस्य ईमेल को सूचीबद्ध करता है जिसे एक अलर्ट संपादक सूचित कर सकता है) `alerts:read` **या** `alerts:write` के धारक द्वारा पहुंचने योग्य है, इसलिए अलर्ट संपादक `users:read` दिए बिना पिकर को भर सकते हैं। + +> एक डैशबोर्ड दर्शक को **दोनों** `dashboards:read` (सहेजे गए दृश्यों को लोड करने के लिए) और `evaluations:read` (स्वास्थ्य मेट्रिक्स मूल्यांकन डेटा से गणना की जाती है) की आवश्यकता होती है। उपयोगकर्ता को डैशबोर्ड बनाने या संपादित करने देने के लिए `dashboards:write` देते हैं, और उन्हें हटाने के लिए `dashboards:delete`। + +> `/health` और `/auth/*` (OTP अनुरोध, OTP सत्यापित करें, सत्र जाँच, लॉगआउट) डिज़ाइन के अनुसार अप्रमाणित हैं; वे लॉगिन प्रवाह और जीवंतता जांच हैं। `GET /access-granters` को एक वैध कुंजी की आवश्यकता होती है लेकिन कोई विशिष्ट अनुमति नहीं, इसलिए कोई भी लॉगिन किया गया उपयोगकर्ता देख सकता है कि एक्सेस परिवर्तनों के बारे में किन व्यवस्थापकों से संपर्क करना है। + +--- + +## अनुमति सेट्स + +अनुमति सेट्स आपको हर बार व्यक्तिगत टोकन को हाथ से चुनने के बजाय एक नामित भूमिका लागू करने देते हैं। प्रत्येक नए डैशबोर्ड उपयोगकर्ता या API कुंजी के लिए एक दर्जन अनुमतियों को एक-एक करके चुनने के बजाय, आप एक सेट चुनते हैं, और प्रत्येक को असाइन किया गया हर कोई एक सुसंगत, समीक्ष्य अनुदान ले जाता है। एक कस्टम सेट को संपादित करना पहले से ही असाइन किए गए प्रत्येक उपयोगकर्ता को नया अनुदान पुनः लागू करता है, इसलिए एक भूमिका परिवर्तन एक संपादन है न कि प्रत्येक सदस्य के माध्यम से एक स्वीप। + +प्रत्येक संगठन तीन बिल्ट-इन सेट्स के साथ सीड किया जाता है: + +| सेट | अनुमतियाँ | इसके लिए आशय | +|---|---|---| +| `read-only` | `events:read`, `keys:read`, `users:read`, `evaluations:read`, `dashboards:read`, `queries:read`, `settings:read`, `alerts:read`, `audits:read`, `incidents:read` | प्रत्येक परिचालन सतह में केवल-दृश्य पहुँच। | +| `standard` | `read-only` में सब कुछ, साथ ही `evaluations:trigger`, `queries:run`, `incidents:ack`, `agent:use` | केवल-पढ़ने के लिए साथ ही रोजमर्रा की ऑन-कॉलर कार्रवाइयाँ: क्वेरीज़ चलाएं, सत्रों का पुनः मूल्यांकन करें, घटनाओं को स्वीकार करें, और AI सहायक का उपयोग करें। | +| `admin` | प्रत्येक असाइन करने योग्य अनुमति | संगठन का पूर्ण नियंत्रण। | + +तीन बिल्ट-इन सेट्स **अपरिवर्तनीय** हैं; उनके नाम हमेशा एक ही चीज़ का मतलब रखते हैं, इसलिए `read-only`, `standard`, और `admin` नीति और ऑनबोर्डिंग में संदर्भित करने के लिए सुरक्षित हैं। एक ऑपरेटर अतिरिक्त **कस्टम सेट्स** बना सकता है आपके संगठन के लिए विशिष्ट भूमिकाओं को मॉडल करने के लिए (उदाहरण के लिए, एक डैशबोर्ड लेखक भूमिका या एक कलेक्टर-केवल भूमिका)। + +सेट्स डैशबोर्ड में भूतल होते हैं और `GET /permission-sets` (सूची, `users:read` द्वारा गेटेड) और `POST /permission-sets` / `PUT /permission-sets/:name` / `DELETE /permission-sets/:name` (एक कस्टम सेट बनाएं, संपादित करें, हटाएं, `settings:write` द्वारा गेटेड) पर API के माध्यम से प्रबंधित होते हैं। एक बिल्ट-इन सेट को हटाना या संपादित करना अस्वीकार कर दिया जाता है। + +सेट सदस्यता दो अन्य विशेषताओं को समर्थन देती है: + +- **`DEFAULT_USER_PERMISSIONS`** (जब एक व्यवस्थापक **+ नया उपयोगकर्ता** खोलता है तो पहले से चुनी गई अनुदान) `standard` सेट को डिफ़ॉल्ट करता है। [तैनाती](/hi/agenteye/deployment) देखें। +- **`agenteye-orgctl` पर `--set` फ़्लैग** (ऑपरेटर सदस्य प्रबंधन) एक सदस्य को एक नामित सेट से शुरू करता है, जिसे आप फिर `--add` / `--remove` के साथ सूक्ष्म-ट्यून करते हैं। [टेनेंट प्रबंधन](/hi/agenteye/tenant-management) देखें। + +> जब एक सेट एक अनुमति को शामिल करता है जो कुंजी-असाइन करने योग्य नहीं है (उदाहरण के लिए एक कस्टम सेट `keys:update` ले जाता है), सेट से कुंजी को सीड करना गैर-असाइन करने योग्य टोकन को छोड़ देता है; सर्वर अन्यथा HTTP 422 के साथ कुंजी को अस्वीकार कर देगा। डैशबोर्ड उपयोगकर्ता उस प्रतिबंध के अधीन नहीं हैं। + +--- + +## बूटस्ट्रैप व्यवस्थापक कुंजी + +व्यवस्थापक कुंजी एकल मूल साख है जो एक ऑपरेटर को कुछ भी नहीं से पहुँच को लाने देती है: इसके साथ आप प्रत्येक अन्य स्कोप की गई कुंजी को टकसाल कर सकते हैं, पहले डैशबोर्ड उपयोगकर्ताओं को आमंत्रित कर सकते हैं, और किसी अन्य कुंजी के अस्तित्व से पहले उदाहरण को कॉन्फ़िगर कर सकते हैं। यह एक कुंजी है जिसे आप कुंजी API के माध्यम से नहीं बनाते हैं; इसे पर्यावरण से प्रावधानित किया जाता है ताकि सर्वर पहली बूट पर पहुंचने योग्य हो। + +सर्वर पर `ADMIN_KEY` पर्यावरण चर सेट करें। हर स्टार्टअप पर सर्वर इस मान को सभी अनुमतियों के साथ एक व्यवस्थापक कुंजी के रूप में अपसर्ट करता है। + +घुमाने के लिए: `ADMIN_KEY` को एक नए रहस्य में बदलें और सर्वर को पुनः आरंभ करें। + +--- + +## संगठन स्कोपिंग + +**संगठनों को स्वयं ऑपरेटर द्वारा आउट-ऑफ-बैंड बनाया और प्रबंधित किया जाता है, इस कुंजी API के माध्यम से नहीं।** Org और सदस्य जीवनचक्र (एक org बनाएं / नाम बदलें / हटाएं / शुद्ध करें; एक सदस्य जोड़ें / अपडेट करें / निकालें) **`agenteye-orgctl`** CLI के साथ किया जाता है जो सर्वर पॉड के अंदर चलता है; इसके लिए कोई HTTP API या डैशबोर्ड बटन नहीं है। [टेनेंट प्रबंधन](/hi/agenteye/tenant-management) देखें। जो *अपरिवर्तित* है: **प्रति-org API कुंजियाँ अभी भी डैशबोर्ड में (या इस कुंजी API के माध्यम से) org सदस्यों द्वारा टकसाल की जाती हैं** डैशबोर्ड **कुंजियाँ** पृष्ठ। + +एक बहु-org तैनाती में, एक org सदस्य द्वारा बनाई गई प्रत्येक कुंजी (इस कुंजी API या डैशबोर्ड **कुंजियाँ** पृष्ठ के माध्यम से) **एक संगठन** से संबंधित है और केवल उस org के डेटा को पढ़ या लिख सकती है; org को निर्माण पर कुंजी पर मुहर लगाई जाती है और प्रत्येक अनुरोध पर लागू किया जाता है। दो बूटस्ट्रैप कुंजियाँ एकमात्र अपवाद हैं: `admin` कुंजी (`ADMIN_KEY` से सीडित) और `dashboard-assistant` कुंजी (`AGENT_API_KEY` से सीडित) **उदाहरण-स्कोप्ड** हैं (वे कोई org नहीं ले जाते हैं)। डैशबोर्ड कंटेनर `admin` कुंजी के साथ प्रमाणित करता है ताकि यह साइन-इन किए गए सदस्यों की ओर से प्रति-org अनुरोधों के लिए प्रॉक्सी कर सके। एकल-किरायेदार तैनाई को इसके बारे में सोचने की आवश्यकता नहीं है; सभी कुंजियाँ बिल्ट-इन `default` org से संबंधित हैं। + +--- + +## कुंजियाँ बनाना + +अतिरिक्त स्कोप की गई कुंजियों को बनाने के लिए व्यवस्थापक कुंजी (या `keys:create` अनुमति के साथ कोई भी कुंजी) का उपयोग करें। + +### कलेक्टर कुंजी (केवल इंजेस्ट) + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "prod-collector", + "key": "your-collector-secret", + "permissions": ["events:add"] + }' +``` + +### डैशबोर्ड कुंजी (केवल पढ़ने के लिए) + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "dashboard", + "key": "your-dashboard-secret", + "permissions": ["events:read", "keys:read"] + }' +``` + +जब आप HTTP API के माध्यम से कुंजी बनाते हैं, तो आप `key` मान को स्वयं प्रदान करते हैं; एक मजबूत रहस्य चुनें और इसे सुरक्षित रूप से स्टोर करें। (डैशबोर्ड दूसरे तरीके से काम करता है: यह आपके लिए एक मजबूत रहस्य उत्पन्न करता है और इसे निर्माण पर एक बार दिखाता है; [डैशबोर्ड में कुंजी प्रबंधन](#key-management-in-the-dashboard) देखें।) प्रतिक्रिया पुष्टि करती है कि कुंजी बनाई गई थी: + +```json +{ + "id": "550e8400-e29b-41d4-a716-446655440000", + "name": "prod-collector", + "permissions": ["events:add"], + "created_at": "2026-04-01T12:00:00Z" +} +``` + +--- + +## कुंजियों को सूचीबद्ध करना + +```bash +curl -s http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +कुंजी रहस्य सूची प्रतिक्रियाओं में नहीं लौटाए जाते हैं, केवल ID, नाम, और अनुमतियाँ। + +--- + +## कुंजी को अक्षम करना + +अक्षम करने से कुंजी रिकॉर्ड को हटाए बिना तुरंत पहुँच निरस्त हो जाती है। + +```bash +curl -s -X POST http://your-server:8080/keys//disable \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +--- + +## कुंजी को पुनः उत्पन्न करना + +एक मौजूदा कुंजी के लिए एक नया रहस्य उत्पन्न करता है। पुरानी कुंजी तुरंत अमान्य हो जाती है। + +```bash +curl -s -X POST http://your-server:8080/keys//regenerate \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +प्रतिक्रिया में नई सादे पाठ रहस्य शामिल है, **केवल एक बार दिखाया गया**। + +--- + +## डैशबोर्ड में कुंजी प्रबंधन + +डैशबोर्ड में **कुंजियाँ** पृष्ठ उपरोक्त सभी कार्यों के लिए एक UI प्रदान करता है। आपको कुंजी सूची को देखने के लिए `keys:read` अनुमति के साथ एक कुंजी की आवश्यकता है, और क्रमशः बनाने / संपादित करने / अक्षम करने / पुनः उत्पन्न करने की कार्रवाइयों के लिए `keys:create` / `keys:update` / `keys:disable` / `keys:regenerate`। एक कुंजी की अनुमतियों को संपादित करना (`keys:update`) एक को बनाने से अलग है (`keys:create`), इसलिए आप किसी ऑपरेटर को मौजूदा कुंजियों को फिर से स्कोप किए बिना कुंजियों को टकसाल करने की क्षमता दे सकते हैं, या इसके विपरीत। व्यवस्थापक कुंजी इन सभी को कवर करती है। + +जब आप डैशबोर्ड से एक कुंजी बनाते हैं तो आप रहस्य की आपूर्ति नहीं करते हैं; डैशबोर्ड आपके लिए एक मजबूत रहस्य उत्पन्न करता है और इसे **एक बार** निर्माण पर प्रदर्शित करता है। इसे तुरंत कॉपी करें और इसे सुरक्षित रूप से स्टोर करें; इसे फिर कभी दिखाया नहीं जाता है, बिल्कुल जैसे पुनः उत्पन्न के साथ। आप कुंजी की अनुमतियों को सीधे चुन सकते हैं, या उन्हें अनुमति सेट से सीड कर सकते हैं (नीचे देखें)। + +![API कुंजियाँ पृष्ठ: प्रति कुंजी एक कार्ड जिसमें इसका नाम, प्रदान की गई अनुमतियाँ, और निर्माण समय, पुनः उत्पन्न करने और अक्षम करने की कार्रवाइयों के साथ हैं; `admin` जैसी संरक्षित कुंजियों को चिह्नित किया जाता है](/agenteye/images/api-keys.png) + +--- + +## अनुशंसित कुंजी लेआउट + +| कुंजी | अनुमतियाँ | इसका उपयोग किस द्वारा किया जाता है | +|---|---|---| +| `admin` (`ADMIN_KEY` env var के माध्यम से बूटस्ट्रैप) | सभी | Ops/सेटअप, और डैशबोर्ड कंटेनर (`ADMIN_KEY` के साथ प्रमाणित करता है, अनुमति जाँचों के साथ उपयोगकर्ता अनुरोधों के लिए प्रॉक्सी) | +| प्रति-होस्ट कलेक्टर कुंजी | `events:add` | प्रत्येक एजेंट मशीन पर कलेक्टर | +| `dashboard-assistant` (`AGENT_API_KEY` env var के माध्यम से बूटस्ट्रैप) | `events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run` | AI सहायक कंटेनर, स्वचालित रूप से सीडित, **संरक्षित**; API के माध्यम से संपादित नहीं किया जा सकता | +| सहायक दूरदर्शिता कुंजी (वैकल्पिक) | `events:add` | AI सहायक स्व-उपकरण, यदि सक्षम है | + +> **सहायक कुंजी।** सहायक की कुंजी सर्वर द्वारा `AGENT_API_KEY` env var से स्वचालित रूप से **सीडित** की जाती है (समान रहस्य जिसे एजेंट `AGENTEYE_API_KEY` के रूप में प्रस्तुत करता है); कोई मैनुअल कुंजी-टकसाली कदम नहीं है और कोई व्यवस्थापक कुंजी शामिल नहीं है। इसकी अनुमतियाँ स्रोत कोड में निर्धारित हैं ताकि स्कोप को गलत विन्यास द्वारा चौड़ा न किया जा सके: ईवेंट्स / मूल्यांकन / डैशबोर्ड में पढ़ें, साथ ही dashboards-write और queries-read / write / run क्वेरी लेखन प्रवाह के लिए। सभी SQL अभी भी एक उपयोगकर्ता-लिखित क्वेरी के समान केवल-पढ़ने के लिए भूमिका और `sql_guard` जाँचों के माध्यम से जाता है, इसलिए यह *लेखन सतह* को चौड़ा करता है, डेटा सतह को नहीं; विनाशकारी कार्यों (`queries:delete`, `dashboards:delete`) जानबूझकर सहायक कुंजी से दूर रहते हैं। `admin` कुंजी की तरह, यह **संरक्षित** है: इसे कुंजी API के माध्यम से अक्षम या पुनः उत्पन्न नहीं किया जा सकता है, केवल `AGENT_API_KEY` को बदलकर और पुनः आरंभ करके घुमाया जा सकता है। डैशबोर्ड *उपयोगकर्ताओं* को अतिरिक्त रूप से सहायक को देखने और उपयोग करने के लिए `agent:use` अनुमति की आवश्यकता है। यदि आप स्व-उपकरण सक्षम करते हैं, तो सहायक को एक अलग `events:add`-केवल कुंजी दें। \ No newline at end of file diff --git a/docs/hi/agenteye/assistant.mdx b/docs/hi/agenteye/assistant.mdx new file mode 100644 index 00000000..1c419c8d --- /dev/null +++ b/docs/hi/agenteye/assistant.mdx @@ -0,0 +1,195 @@ +--- +title: "एआई सहायक" +description: "AgentEye एआई सहायक दस्तावेज़।" +--- + +डैशबोर्ड में एक वैकल्पिक **एआई सहायक** शामिल है, जो डैशबोर्ड के दाएं किनारे पर डॉक किया गया एक चैट पैनल है जो आपके एजेंटों के बारे में प्राकृतिक भाषा के प्रश्नों का उत्तर देता है ("इस सप्ताह prod में quality कैसी ट्रेंड कर रही है?", "आज किन सेशन में त्रुटि आई?", "इस सेशन को सारांशित करें") और जब उपयोगकर्ता प्रत्येक क्रिया की अनुमति देता है, तो SQL क्वेरी और डैशबोर्ड तैयार और सहेजता है। यह सीधे प्रासंगिक सेशन, क्वेरी और डैशबोर्ड के लिए क्लिक करने योग्य लिंक प्रदान करता है, और यह **पृष्ठ-जागरूक** है: किसी एक को देखते समय "इस सेशन" के बारे में पूछें और यह समझता है कि आपका क्या मतलब है। + +डॉक डिफ़ॉल्ट रूप से एक पतली **44px ऊर्ध्वाधर रेल** के रूप में दिखाई देता है: एक `›_` प्रॉम्प्ट ग्लिफ़ साथ ही एक रंगीन स्वास्थ्य बिंदु। रेल पर क्लिक करें (या `⌘J` / `Ctrl+J` दबाएं) इसे पूर्ण चैट पैनल में विस्तारित करने के लिए। विस्तारित पैनल इसके बाएं किनारे को खींचकर 320 और 640 पिक्सल के बीच **आकार बदलने योग्य** है; आपकी पसंदीदा चौड़ाई रीलोड के दौरान याद रखी जाती है। + +यह एक छोटे आंतरिक **`agent`** कंटेनर (Claude Agent SDK पर) के रूप में चलता है जिस तक केवल डैशबोर्ड पहुंच सकता है। यह **डिफ़ॉल्ट रूप से अक्षम** है और जब तक आप कोई LLM एंडपॉइंट कॉन्फ़िगर नहीं करते, तब तक छिपा रहता है। + +--- + +## यह क्या कर सकता है और क्या नहीं कर सकता + +- **पूछने वाले उपयोगकर्ता द्वारा देखे जाने वाले परिचालन डेटा को पढ़ता है।** Events, evaluations, sessions, evaluation-job queue, saved queries, और saved dashboards, प्रत्येक अनुरोध के लिए उपयोगकर्ता के read permissions तक सीमित। Read tools तुरंत निष्पादित होते हैं। +- **लेखन प्रति-क्रिया अनुमोदन द्वारा गेटेड है।** यह saved queries को लेखक बना सकता है (`create_saved_query`, `update_saved_query`), draft SQL को read-only role के विरुद्ध चलाकर validate कर सकता है (`run_query`), और उन क्वेरी से dashboards assemble कर सकता है (`create_dashboard`, `update_dashboard`, `add_query_to_dashboard`)। प्रत्येक लेखन एक इन-चैट **Approve / Reject / एक प्रश्न पूछें** प्रॉम्प्ट के लिए रुकता है; SDK जब तक ऑपरेटर Approve पर क्लिक नहीं करता तब तक tool को कॉल नहीं करता। **Deletion सहायक के लिए कभी उपलब्ध नहीं है**; विनाशकारी संचालन ऑपरेटरों के साथ रहते हैं। +- **Draft SQL उपयोगकर्ता-लिखित SQL के समान ही `sql_guard` validation और read-only roles के माध्यम से जाता है** (केवल SELECT/WITH, कोई multi-statement नहीं)। Execution को उस आधार पर route किया जाता है जो तालिकाएं क्वेरी स्पर्श करती हैं: वे क्वेरी जो analytics tables (events, evaluations, sessions) को reference करती हैं, organization के read-only ClickHouse user के रूप में चलती हैं (एक row policy द्वारा उस org तक सीमित, 10s execution cap और 100k row cap के साथ) जबकि वे क्वेरी जो केवल relational tables को touch करती हैं, एक read-only Postgres role पर चलती हैं (10s, 10k rows)। सहायक डेटा सतह को चौड़ा नहीं कर सकता; यह केवल उस क्वेरी सतह पर लेखक कर सकता है जो ऑपरेटर के पास पहले से है। +- यह एक **dedicated assistant key** (नीचे देखें) का उपयोग करता है जो एक fixed permission set के साथ seeded है; भले ही model का व्यवहार गलत हो, वह उन scopes को exceed नहीं कर सकता। +- प्रत्येक डैशबोर्ड उपयोगकर्ता को सहायक को देखने और उपयोग करने के लिए **`agent:use`** permission की आवश्यकता है। Tools को प्रति-अनुरोध उपयोगकर्ता के अपने डेटा permissions से मेल खाने के लिए फ़िल्ट किया जाता है, इसलिए एक `events:read` उपयोगकर्ता को event tools मिलते हैं लेकिन कोई `dashboards:write` tools नहीं। + +--- + +## पृष्ठ-जागरूक एआई डॉक: `/queries` पर composer, अन्यत्र chat + +दाहिनी ओर का सहायक डॉक **पृष्ठ-जागरूक** है। model picker, conversation history, model health dot, और chat input अपरिवर्तित हैं, लेकिन **empty-state template chips, placeholder text, और कौन सी backend endpoint एक उपयोगकर्ता का संदेश hits करता है** सभी automatically वर्तमान route के आधार पर switch करते हैं। डॉक "आप जिस भी पृष्ठ पर खड़े हैं उसके लिए एआई helper" बन जाता है। + +**दो backends, पृष्ठ प्रति (per-chip overrides के साथ)।** + +| Route | पृष्ठ-डिफ़ॉल्ट backend | क्यों | +| ------------------------------ | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | +| `/queries`, `/queries/new` | `POST /api/agent/compose-sql` (कोई tool loop नहीं) | उपयोगकर्ता नए सिरे से शुरुआत कर रहा है; ≤1s first-token SQL सीधे editor में streamed है | +| `/queries/` (existing) | `POST /api/agent/chat` (full tool-loop assistant), page default | Free-typed messages को उपयोगकर्ता को कुछ भी पूछने देना चाहिए ("explain this", "what does this do?"); refactor chips per-chip kind के माध्यम से compose-sql में opt करते हैं | +| हर दूसरा पृष्ठ | `POST /api/agent/chat` (full tool-loop assistant) | Read tools + approval-gated write tools | + +`/queries/` पर Chips में एक explicit `kind` है ताकि एक पृष्ठ दोनों flows को seamlessly मिश्रित कर सके। डिफ़ॉल्ट chip set दो **chat** chips हैं (`explain the query on screen`, `what does this query do?`) साथ ही पांच **compose-sql** chips (`parameterize by date range`, `add a status='error' filter`, आदि)। Free-typed messages page default (chat) में fall through करते हैं, इसलिए "why is this so slow?" जैसा सवाल एक prose answer मिलता है, जबकि `parameterize by date range` chip पर क्लिक compose endpoint के माध्यम से route करता है और SQL को संपादित करता है। + +जब composer **edit mode** में चलता है (यह एक non-empty `currentSql` देखता है क्योंकि उपयोगकर्ता `/queries/` या `/queries/new` पर है proposed SQL पहले से लोड के साथ), इसका system prompt "compose a new query" से "modify the provided SQL minimally: preserve table choice, column names, join structure, aliases, indentation" में switch करता है। मॉडल को before/after worked examples (parameterize, add filter, convert to hourly buckets) का एक अलग set दिखाया जाता है, इसलिए एक chip-clicked refactor editor के SQL के विरुद्ध एक minimal diff पैदा करता है, scratch से एक rewrite नहीं। + +एक compose chip पर क्लिक करें (या `/queries/new` पर freely type करें) → SQL assistant message में एक fenced ` ```sql ` block के रूप में streams करता है। **जैसे ही stream finalizes, अगर Monaco वर्तमान route पर mounted है, editor automatically diff view में lights up** (बाएं पर original, दाएं पर proposed, शीर्ष पर एक `▾ AI proposed an edit` cue, और नीचे **Accept / Reject** pills)। उपयोगकर्ता को एक `Insert into editor` बटन ढूंढने या क्लिक करने की आवश्यकता नहीं है diff देखने के लिए। Insert button still rendered है SQL block के नीचे एक manual re-trigger के रूप में (Reject के बाद उपयोगी या जब उपयोगकर्ता navigate गया हो और वापस आए), और यह एकमात्र path है जब उपयोगकर्ता एक non-editor page पर है (जैसे saved-queries list); यह `sessionStorage` में SQL को stash करता है और `/queries/new` navigate करता है, जहां freshly-mounted editor mount पर stash को read करता है और same diff view को खोलता है। + +अगर proposed SQL byte-identical है जो पहले से editor में है (एक no-op edit), auto-open को skip किया जाता है; हम एक empty diff को pop नहीं करते। `Insert into editor` button भी उस case में एक no-op है। + +जब उपयोगकर्ता `/queries/new` पर suggestion स्वीकार करता है, toolbar का primary action **`save`** reads करता है `create` की जगह; SQL उन्हें assistant द्वारा हाथ दिया गया था; mental model "finalize this" है, "write from scratch" नहीं। Label एक बार dock SQL insert करता है तब तक flip होता है जब तक page navigation नहीं होता। `/queries/` पर button हमेशा `save` read करता है; कुछ नहीं बदलता है। + +`/queries` के बाहर, डॉक बिल्कुल पहले की तरह काम करता है: full chat with tool-approval cards, page-context awareness, citations। + +**Permissions / gating।** Compose endpoint per-user `queries:run` permission पर gates (read-equivalent; उपयोगकर्ता को अभी भी Accept और Run click करना है, और Run existing `sql_guard` + `references_ch_tables` routing के माध्यम से Rust server पर जाता है)। Chat endpoint `agent:use` पर gates करता है। दोनों को अभी भी `agent` container पर configured एक LLM connection की आवश्यकता है; अगर कोई configured नहीं है, डॉक किसी भी path पर एक "the assistant isn't configured on this deployment" banner surface करता है। + +**Refusals।** Composer किसी भी request को refuse करता है जो वह read-only analytics query के साथ satisfy नहीं कर सकता और `-- REFUSE: ` emit करता है SQL की जगह। यह requests को refuse करता है जो data write करेंगे या analytics views (`api_keys`, `users`, `dashboards`, `saved_queries`, `evaluation_jobs`) के बाहर की tables तक reach करेंगे, और यह pure prose requests ("explain this", "what does this do?") को compose path पर refuse करता है; वे chat path से संबंधित हैं और वहां एक prose answer produce करते हैं। डॉक refusal string को assistant message में एक inline red error chip के रूप में render करता है; कुछ नहीं insert किया जाता है। + +**Model selection।** Chat path के साथ shared। डॉक header में model picker दोनों endpoints पर apply होता है (compose call picked model को `resolveModel()` पर agent service के माध्यम से pass करता है)। जब `AGENTEYE_AGENT_MODELS` multiple models को list करता है, operators एक Haiku-class option को composer के साथ एक Sonnet-class option के साथ chat के साथ mix कर सकते हैं; उपयोगकर्ता per-conversation pick करता है। + +**Per-page templates।** प्रत्येक page का अपना template (headline, body copy, placeholder text, और suggestion chips) है ताकि डॉक आप जिस page पर खड़े हैं उसे adapt करे। दिए गए route पर offered chips उसी intents के map करते हैं जो composer को tune किया जाता है, इसलिए suggestion पर क्लिक करने से आप जिस edit की expect करते हैं वह produce होता है। + +**इसे अक्षम करना।** Chat path के समान: डॉक + composer दोनों को `agent` container और इसके LLM connection द्वारा गेटेड किया जाता है। अगर आप किसी विशेष उपयोगकर्ता के लिए chat-only behavior चाहते हैं, `queries:run` permission को remove करें (जो editor के **Run** button को भी disable करता है); अगर आप composer-only behavior चाहते हैं, उस उपयोगकर्ता की roles से `agent:use` को remove करें, फिर `queries:run` को separately फिर से add करें ताकि वे अभी भी author-written SQL को execute कर सकें। + +--- + +## इसे सक्षम करना + +`agent` service Docker Compose file और Kubernetes manifests में ships। सहायक को turn on करने के लिए, **(1)** एक LLM endpoint और **(2)** सहायक की dedicated data key प्रदान करें। + +### 1. एक LLM connection चुनें + +इनमें से एक को pick करें और `agent` service पर corresponding variables को set करें: + +**a) सीधे Anthropic** + +``` +ANTHROPIC_API_KEY=sk-ant-... +``` + +**b) Portkey के माध्यम से (अनुशंसित; model-catalog slug, key only)** + +``` +PORTKEY_API_KEY= +AGENTEYE_AGENT_MODEL=@/claude-sonnet-4-6 +``` + +यह सबसे सरल path है: Portkey में, एक **Anthropic integration** (Model Catalog) को set up करें; इसे एक **slug** मिलता है। Model को `@/` के रूप में name करें और slug provider + credential routing को carry करता है, तो **कोई virtual key की जरूरत नहीं है**, बस आपकी Portkey API key। Agent केवल `x-portkey-api-key` भेजता है और Portkey gateway पर points करता है; Portkey बाकी को resolve करता है। (एक *plain* model name "x-portkey-config or x-portkey-provider header is required" के साथ fail होता है; `@slug/` prefix वह है जो key-only को काम करता है।) एक self-hosted gateway के लिए `PORTKEY_BASE_URL` को set करें। + +Per-request routing को prefer करते हैं slug की जगह? `PORTKEY_VIRTUAL_KEY=` (या `PORTKEY_CONFIG=`) को एक plain `AGENTEYE_AGENT_MODEL` के साथ set करें। + +**c) कोई अन्य Anthropic-compatible gateway (LiteLLM, self-hosted, ...)** + +``` +ANTHROPIC_BASE_URL=https://your-gateway +# Newline-delimited "Name: Value" header lines (JSON नहीं): +ANTHROPIC_CUSTOM_HEADERS=x-my-header: value +``` + +**d) Amazon Bedrock / Google Vertex** + +``` +CLAUDE_CODE_USE_BEDROCK=1 # + environment में standard AWS credentials +# या +CLAUDE_CODE_USE_VERTEX=1 # + environment में standard GCP credentials +``` + +Optionally `AGENTEYE_AGENT_MODEL` के साथ default model को pin करें (default `claude-sonnet-4-6`)। उपयोगकर्ताओं को **choose** करने देने के लिए कई models के बीच, `AGENTEYE_AGENT_MODELS` को comma-separated allowlist के लिए set करें (जैसे `@anthropic-prod/claude-opus-4-7,@anthropic-prod/claude-sonnet-4-6`); एक model picker तब chat header में appear होता है, और प्रत्येक उपयोगकर्ता की choice को याद रखा जाता है। Agent केवल कभी भी इस allowlist पर एक model को call करता है। + +### 2. सहायक key प्रदान करें + +कोई भी random secret pick करें और इसे **agent** को `AGENTEYE_API_KEY` के रूप में और **server** को `AGENT_API_KEY` के रूप में दें (वही value)। Startup पर server इसे एक dedicated key के रूप में seed करता है जिसका नाम `dashboard-assistant` है जिसमें यह fixed permission set है: `events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run`। Write permissions को केवल कभी approval-gated tools के माध्यम से exercise किया जाता है (ऊपर "यह क्या कर सकता है और क्या नहीं कर सकता" देखें)। **कोई manual key-minting step और कोई admin key involved नहीं है**। Permission set server में fixed है, और seeded key **protected** है: इसे keys API के माध्यम से disable या regenerate नहीं किया जा सकता; value को change करके और server को restart करके इसे rotate करें। **Admin/dashboard key को reuse न करें।** + +```bash +SECRET="$(openssl rand -base64 32)" +# agent service पर: +AGENTEYE_API_KEY="$SECRET" +# server service पर: +AGENT_API_KEY="$SECRET" +``` + +Kubernetes पर यह आपके लिए wired है: `AGENTEYE_API_KEY` को `agenteye-agent` secret में put करें और server Deployment पहले से ही उसी value को `AGENT_API_KEY` के रूप में read करता है। + +### 3. साझा dashboard↔agent token को set करें + +**दोनों** `dashboard` और `agent` services पर same `AGENTEYE_AGENT_TOKEN` को set करें। Dashboard इसे internal agent service को call करते समय present करता है; agent इसे बिना calls को reject करता है। + +### 4. उपयोगकर्ताओं को access grant करें + +प्रासंगिक dashboard operators को `agent:use` permission दें (देखें [enterprise-docs/api-keys.md](/hi/agenteye/api-keys))। इसके बिना उपयोगकर्ता कभी भी assistant को नहीं देखते हैं। + +एक बार LLM endpoint और read-only key set हो जाने के बाद, **server** (read-only key को seed करने के लिए) और **agent** service को restart करें। सहायक डॉक किसी भी `agent:use` उपयोगकर्ता के लिए दाएं किनारे पर appear होता है, डिफ़ॉल्ट रूप से collapsed; rail पर क्लिक करें या `⌘J` / `Ctrl+J` दबाएं expand करने के लिए। + +--- + +## Environment variable reference + +**`agent`** service पर set करें: + +| Variable | Purpose | +|---|---| +| `PORTKEY_API_KEY` | Portkey के माध्यम से route करें (agent इससे gateway connection build करता है) | +| `PORTKEY_VIRTUAL_KEY` | आपके Anthropic credentials के लिए Portkey virtual key (optional अगर key के पास एक default config है) | +| `PORTKEY_CONFIG` / `PORTKEY_BASE_URL` | Named Portkey config / self-hosted Portkey gateway URL (optional) | +| `PORTKEY_PROVIDER` | Portkey provider slug — `PORTKEY_VIRTUAL_KEY` / `PORTKEY_CONFIG` के साथ एक तीसरा routing option (केवल जब न तो वह set हो) | +| `ANTHROPIC_API_KEY` | Direct Anthropic access (gateway / Bedrock / Vertex के लिए alternative) | +| `ANTHROPIC_AUTH_TOKEN` | Bearer token के लिए एक gateway जो `Authorization: Bearer` के माध्यम से authenticate करता है `x-api-key` की जगह (optional) | +| `ANTHROPIC_BASE_URL` | एक non-Portkey gateway के लिए endpoint | +| `ANTHROPIC_CUSTOM_HEADERS` | एक non-Portkey gateway के लिए extra headers: newline-delimited `Name: Value` lines (JSON नहीं) | +| `CLAUDE_CODE_USE_BEDROCK` / `CLAUDE_CODE_USE_VERTEX` | Bedrock / Vertex के माध्यम से route करें | +| `AGENTEYE_AGENT_MODEL` | Default model id (default `claude-sonnet-4-6`) | +| `AGENTEYE_AGENT_MODELS` | Comma-separated allowlist उन models की जो उपयोगकर्ता chat header में pick कर सकते हैं। एक एकल fixed model के लिए unset छोड़ें। ऊपर दिया गया default इनमें से एक होना चाहिए (अन्यथा यह added है)। | +| `AGENTEYE_AGENT_MAX_CONCURRENCY` | Max concurrent chats per pod (default 4); अतिरिक्त requests को 429 मिलते हैं | +| `AGENTEYE_API_KEY` | सहायक की data key। **Same** value को server के `AGENT_API_KEY` के रूप में set करें, जो इसे startup पर एक fixed scoped permission set के साथ seed करता है (step 2 देखें)। | +| `AGENTEYE_AGENT_TOKEN` | Dashboard के साथ shared secret | +| `AGENTEYE_SERVER_URL` | AgentEye server URL (default `http://server:8080`) | +| `AGENTEYE_AGENT_ALLOW_NO_ORG` | **Multi-tenancy।** Default off (fail-closed): assistant एक `/chat` request को reject करता है जिसमें कोई organization context नहीं है `400` के साथ, क्योंकि हर tool जो वह चलाता है वह एक org तक scoped है। Dashboard एक बार org-aware होने के बाद हमेशा वह context भेजता है, तो आप normally इसे unset रखते हैं। **केवल** `1` पर set करें एक transitional rollout के दौरान जहां एक not-yet-org-aware dashboard एक org-aware agent से बात कर रहा है, तो assistant `default` org में fallback करता है refusing की जगह। एक बार dashboard upgrade lands तो clear करें। | +| `AGENTEYE_AGENT_MAX_STEPS` | Max tool-use steps per answer (default 8) | +| `AGENTEYE_AGENT_TIMEOUT_MS` | Overall `/chat` request timeout (सभी model turns + tool steps), milliseconds में (default 90000); SQL tool का अपना 10s cap है | +| `AGENTEYE_AGENT_SELF_TELEMETRY` | `1` assistant के अपने runs को AgentEye में record करने के लिए | +| `AGENTEYE_TELEMETRY_API_KEY` | Self-instrumentation के लिए अलग `events:add`-only key | +| `AGENTEYE_AGENT_ENV` | Environment tag को assistant के अपने self-telemetry पर apply किया जाता है (default `prod`) | + +**`dashboard`** service पर set करें: + +| Variable | Purpose | +|---|---| +| `AGENTEYE_AGENT_URL` | जहां dashboard agent service तक reach करता है। Bundled Kubernetes manifests और Compose file इसे `http://agent:9100` पर set करते हैं। Assistant को पूरी तरह छिपाने के लिए इसे unset छोड़ें। | +| `AGENTEYE_AGENT_TOKEN` | Agent के token से match होना चाहिए | + +--- + +## Telemetry & उपयोगकर्ताओं को क्या पूछते हैं यह देखना + +Prompt **content डिफ़ॉल्ट रूप से आपके अपने systems के अंदर रहता है**। तीन layers: + +1. **Conversation store**: हर prompt और answer आपके AgentEye database में saved है (per user, private), और assistant के history switcher से reloadable है। यह उपयोगकर्ता क्या पूछते हैं का durable record है। +2. **Product analytics**: डैशबोर्ड **metadata only** record करता है (कितनी बार assistant का उपयोग किया जाता है, tool counts, latency) आपके analytics में। Prompt **text** को इस path पर कभी भी include नहीं किया जाता है। +3. **Self-instrumentation (optional)**: `AGENTEYE_AGENT_SELF_TELEMETRY=1` को set करें (साथ ही एक `events:add`-only `AGENTEYE_TELEMETRY_API_KEY`) और assistant अपने runs को `dashboard-assistant` agent के रूप में AgentEye में record करता है। आप तब उपयोगकर्ता prompts और assistant का reasoning उसी sessions/events views में देख सकते हैं जो आप सब कुछ के लिए उपयोग करते हैं। Note: वे events किसी के लिए भी visible हैं जिसके पास `events:read` है; अगर वह बहुत broad है, इसे off छोड़ दें। + +--- + +## इसे अक्षम करना + +ये कोई भी assistant को disable करते हैं (डॉक rail disappear करता है): + +- Dashboard पर `AGENTEYE_AGENT_URL` को unset करें, **या** +- Agent पर LLM endpoint को unconfigured रखें (कोई `ANTHROPIC_API_KEY` / gateway / Bedrock / Vertex नहीं), **या** +- `agent` service को बिल्कुल deploy न करें। + +--- + +## Security summary + +- **कोई silent writes नहीं**: assistant के write tools (`create_saved_query`, `update_saved_query`, `create_dashboard`, `update_dashboard`, `add_query_to_dashboard`) बिना एक explicit operator click के in-chat Approve button पर execute नहीं कर सकते हैं; SDK का pre-call gate जब तक एक approval agent तक back-channel के माध्यम से नहीं पहुंचता तब तक tool को block करता है। कोई setting नहीं है जो इस gate को disable करता है। +- **Fixed, narrow data scope**: assistant एक dedicated key के साथ server के लिए authenticate करता है जिसका permission set server में fixed है (`events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run`)। एकमात्र writes जो यह author कर सकता है वह saved queries और dashboards हैं; server कुछ भी उस scope के बाहर reject करता है चाहे model क्या try करे। +- **कोई deletion surface नहीं**: key में कोई delete permission नहीं है और कोई delete tool expose नहीं है। Operators dashboard UI के माध्यम से delete करते हैं, कभी नहीं assistant। +- **Internal-only**: agent के पास कोई public route नहीं है; केवल dashboard ही इसे call कर सकता है, और केवल shared token के साथ। (Kubernetes में, एक NetworkPolicy agent को केवल AgentEye server और LLM endpoint तक reach करने तक restrict करता है।) +- **Per-user scoping**: केवल `agent:use` उपयोगकर्ताओं को assistant मिलता है, और इसे केवल tools दिए जाते हैं जो प्रत्येक उपयोगकर्ता के read permissions से match करते हैं। +- **कोई raw HTML / कोई link exfiltration नहीं**: answers को sanitized markdown के रूप में render किया जाता है; external links को defanged किया जाता है। + +Common issues के लिए [enterprise-docs/troubleshooting.md](/hi/agenteye/troubleshooting) देखें। \ No newline at end of file diff --git a/docs/hi/agenteye/audits.mdx b/docs/hi/agenteye/audits.mdx new file mode 100644 index 00000000..2e8a1f08 --- /dev/null +++ b/docs/hi/agenteye/audits.mdx @@ -0,0 +1,107 @@ +--- +title: "ऑडिट्स — एजेंटिक सुधार का पता लगाना" +description: "AgentEye ऑडिट्स — एजेंटिक सुधार का पता लगाना दस्तावेज़।" +--- + + +ऑडिट्स आवर्ती कार्य हैं जो आपके एजेंट लॉग्स को **सेशन्स के अंतर्गत** खनन करते हैं सुधार के लिए योग्य चीजों को खोजने के लिए। जहाँ एक अलर्ट एक मीट्रिक को देखता है जिसे आप पहले से जानते हैं लगभग-वास्तविक समय में, एक ऑडिट *जांच करता है*: आपके द्वारा निर्धारित एक शेड्यूल पर, यह विंडो पर एक नियतात्मक नीति पास चलाता है, फिर एक **AI विश्वसनीयता एजेंट** को आपके सेशन्स पर ढीला करता है — एजेंट डेटा को स्वयं क्वेरी करता है, संदिग्ध ट्रांसक्रिप्ट्स को पढ़ता है, और (जब यह मदद करता है) छोटी विश्लेषण स्क्रिप्ट्स चलाता है, फिर **सुधार सिफारिशें** लिखता है प्रत्येक के पीछे सबूत के साथ। + +ऑडिट्स का उपयोग "मुझे अपने एजेंट्स में क्या ठीक करना या सुधारना चाहिए?" का उत्तर देने के लिए करें — और अलर्ट्स का उपयोग तुरंत पेज किए जाने के लिए जब एक विशिष्ट थ्रेसहोल्ड पार हो। प्रत्येक सुधार सटीक सेशन्स और क्वेरीज़ से जुड़ता है जो इसके पीछे हैं, और एक क्लिक एक पूर्ण-भरी हुई अलर्ट बनाता है पुनरावृत्ति को पकड़ने के लिए। + +डैशबोर्ड सतह है **`//audits`** (साइडबार → *analyze* → *audits*), `audits:read` / `audits:write` अनुमतियों द्वारा गेटेड। + +--- + +## एक रन कैसे काम करता है + +प्रत्येक रन के दो स्तर हैं — एक नियतात्मक आधार और एक एजेंटिक जांच। + +### 1. नीति पास (नियतात्मक) + +किसी भी मॉडल के चलने से पहले, ऑडिट विंडो पर **SQL नीति जांचों** का एक छोटा कैटलॉग निष्पादित करता है: सीमांकित समुच्चय क्वेरीज़ जो ज्ञात-बुरे पैटर्न को फ्लैग करती हैं और रिपोर्ट करती हैं *कितनी* घटनाएं / *कौन से* सेशन्स मेल खाते हैं — कभी मेल खाए गए पाठ को नहीं। कैटलॉग में शामिल हैं: + +- इवेंट पेलोड्स में **सीक्रेट / क्रेडेंशियल लीकेज** — AWS एक्सेस कीज़, `sk-…` API कीज़, PEM निजी कीज़, JWT / बेयरर टोकन्स, और `KEY=…` क्रेडेंशियल असाइनमेंट्स। +- **प्रॉम्प्ट-इंजेक्शन मार्कर्स** — "पिछली निर्देशों को अनदेखा करें", "अपना सिस्टम प्रॉम्प्ट प्रकट करें", और समान। +- **PII** — SSN-आकार की संख्याएं (हेयुरिस्टिक)। +- **टूल-अनुमति निषेधाएं** और **भागीदार टूल-कॉल लूप्स**। + +नीति हिट्स निष्कर्षों के रूप में स्थायी होते हैं (तरह `policy`) जो **हमेशा सतह पर आते हैं** (वे प्रति-रन कैप द्वारा कभी ट्रिम नहीं किए जाते), और वे AI एजेंट को शुरुआती संकेत के रूप में सौंपे जाते हैं। क्योंकि इस स्तर को कोई मॉडल की आवश्यकता नहीं है, एक ऑडिट अपने सबसे महत्वपूर्ण सुरक्षा सिग्नल्स का उत्पादन करता है भले ही AI एजेंट अनुपलब्ध हो। + +### 2. एजेंटिक जांच (AI) + +ऑडिट फिर एक **स्वायत्त विश्वसनीयता एजेंट** चलाता है (वही Claude Code सेवा जो डैशबोर्ड सहायक को शक्ति देती है, एक ऑडिट-विशिष्ट प्रॉम्प्ट के साथ)। ऑडिट के **स्कोप** (चयनित एजेंट्स × वातावरण) और **समय विंडो** को देखते हुए, एजेंट: + +- आपकी विश्लेषण तालिकाओं के विरुद्ध केवल-पढ़ने योग्य SQL क्वेरीज़ चलाता है, +- प्रतिनिधि सेशन ट्रांसक्रिप्ट्स की एक मुट्ठी को पढ़ता है, +- वैकल्पिक रूप से छोटी **Python स्क्रिप्ट्स को एक लॉक-डाउन इन-पॉड सैंडबॉक्स में** लिखता और चलाता है (कोई नेटवर्क नहीं, कोई फाइलसिस्टम एक्सेस नहीं, सीक्रेट्स स्क्रब किए गए) विश्लेषण के लिए जो SQL व्यक्त नहीं कर सकता — क्लस्टरिंग त्रुटियां, वितरण की गणना, पेलोड्स को स्वीप करना जो यह पहले से प्राप्त कर चुका है, +- और प्रत्येक अच्छी तरह से सबूत दिए गए **सुधार** को रिकॉर्ड करता है जो यह खोजता है। + +यह कई जांच लाइनों के माध्यम से काम करता है — त्रुटि क्लस्टरिंग, एक आधारभूत बनाम ड्रिफ्ट, ट्रांसक्रिप्ट्स में लक्ष्य विफलता, टूल दुरुपयोग, गुणवत्ता/लागत ट्रेड-ऑफ, और कवरेज अंतराल — ऑडिट की **संवेदनशीलता** पर (कम / माध्यम / उच्च)। हर सुधार **सबूत का हवाला देना चाहिए**: सेशन आईडीज़ जो एजेंट वास्तव में निरीक्षण करता है और/या SQL जो यह चलाता है। सर्वर यह सत्यापित करता है कि उद्धृत सेशन्स मौजूद हैं और **किसी भी सुधार को कोई शेष सबूत के साथ छोड़ देता है**, इसलिए एजेंट जांच करता है लेकिन कभी आविष्कार नहीं करता। + +प्रत्येक सुधार ले जाता है: + +- एक **सिफारिश** (ठोस परिवर्तन करने के लिए — एक प्रॉम्प्ट ट्वीक, एक टूल-स्कीमा फिक्स, एक रिट्राई नीति, एक गार्ड्रेल, अधिक eval कवरेज), +- एक **अपेक्षित प्रभाव** और एक **प्रयास** अनुमान (कम / माध्यम / उच्च), +- एक **परिमाण** — `big` (एक ऑपरेटर को पेज किया जाना चाहिए), `medium` (रन रिपोर्ट में संबंधित), या `small` (डैशबोर्ड संदर्भ), +- एक स्थिर **फिंगरप्रिंट** (समस्या की श्रेणी + स्कोप से, *इस रन के सेशन्स से नहीं*) ताकि वही समस्या रन-दर-रन ट्रैक की जाए यहां तक कि जब सबूत बदलता है, +- और, जहाँ एक सरल नियतात्मक वॉचर पुनरावृत्ति को पकड़ सकता है, एक **सुझाई गई अलर्ट** जो आप एक क्लिक में बना सकते हैं। + +> **AI स्तर वैकल्पिक है लेकिन अनुशंसित है।** यदि ऑडिट पाइपलाइन के लिए कोई AI एजेंट कॉन्फ़िगर नहीं है, तो रन अभी भी निष्पादित होते हैं, नीति निष्कर्षों को स्थायी करते हैं, और ईमानदारी से एजेंटिक स्तर के लिए "विश्लेषण अनुपलब्ध" रिपोर्ट करते हैं बजाय चुप्पी से पास किए जाने के। + +### विफलता मोड्स + +सुधार आपके संगठन के टिकाऊ **विफलता-मोड कैटलॉग** में वर्गीकृत होते हैं (या एक नया मोड प्रस्तावित करते हैं)। मोड्स पैटर्न्स को रन्स के अंतर्गत एक स्थिर पहचान देते हैं और दीर्घ-क्षितिज पुनरावृत्ति ट्रैकिंग। + +## ट्रिएज लाइफसाइकल + +एक निष्कर्ष पृष्ठ पर (`/audits//findings/`): + +| कार्रवाई | प्रभाव | +|---|---| +| **acknowledge** | निष्कर्ष को दृश्यमान रखता है लेकिन इसकी प्राथमिकता को आधा करता है। | +| **resolve** | इसे ठीक किए गए के रूप में चिह्नित करता है। यदि पैटर्न वास्तव में बाद में वापस आता है, तो यह **new** के रूप में पुनः खुलता है — इसलिए एक प्रतिगमन जोर से होता है, चुप्पी से नहीं। | +| **mute** / **dismiss** | टिकाऊ दमन: पैटर्न की फिंगरप्रिंट को याद रखा जाता है और कभी भी सतह पर नहीं आता है, यहां तक कि रन्स के अंतर्गत। मute का उपयोग "ज्ञात, स्वीकृत" के लिए करें; dismiss का उपयोग "उपयोगी नहीं" के लिए करें। | +| **reopen** | दमन / समाधान को साफ करता है और पैटर्न को फिर से रैंक करता है। | +| **assign** | निष्कर्ष को एक ऑपरेटर (एक संगठन सदस्य) के लिए स्वामित्व के लिए भेजता है। प्राथमिकता और दमन स्थिति अपरिवर्तित हैं। | + +कम-सिग्नल शोर प्रति-ऑडिट के साथ एजेंटिक सुधारों पर एक प्रति-रन निष्कर्ष कैप (`top_k`) के साथ नियंत्रित होता है। नीति निष्कर्ष कैप को बायपास करते हैं (वे सुरक्षा-प्रासंगिक हैं और हमेशा दिखाए जाते हैं)। कैप द्वारा कट कुछ भी रन के आंकड़ों में गिना जाता है — कुछ भी चुप्पी से ड्रॉप नहीं होता है। + +## शेड्यूलिंग + +- **Cadence** (`schedule_interval_secs`): प्रति घंटा से साप्ताहिक; **दैनिक डिफ़ॉल्ट है**। ऑडिट्स जानबूझकर अलर्ट्स से मोटे हैं — एक एजेंटिक जांच पूरी विंडोज़ को स्कैन करता है और मिनटों तक चलता है। +- **Window**: या तो एक निश्चित रोलिंग लुकबैक (जैसे "प्रत्येक रन पिछले 7 दिनों को स्कैन करता है") या **since-last-run** (डिफ़ॉल्ट) — प्रत्येक रन वहाँ से शुरू होता है जहाँ पिछला सफल एक समाप्त हुआ था, एक छोटे ओवरलैप के साथ ताकि सीमा घटनाएं कभी न चूकें। +- अगला रन पिछले एक के **समाप्त होने** के बाद एक पूर्ण अंतराल निर्धारित है, इसलिए एक धीमा रन कभी एक ही ऑडिट का एक दूसरा सामयिक रन स्टैक नहीं करता है। +- ऑडिट पृष्ठ पर **Run now** इसे तुरंत देय बनाता है। + +## मॉडल चयन + +एक ऑडिट बनाते समय आप यह चुन सकते हैं कि जांच कौन सा मॉडल उपयोग करता है, **मॉडल्स की सूची से जो आपका ऑपरेटर एजेंट सेवा के लिए कॉन्फ़िगर कर चुका है**। एक एकल मॉडल कॉन्फ़िगर होने के साथ, पिकर इसे एक कैप्शन के रूप में दिखाता है; कई के साथ, आप चुनते हैं। इसे अनसेट रखना कॉन्फ़िगर किए गए डिफ़ॉल्ट का उपयोग करता है। + +## अधिसूचनाएं + +जब एक रन **नए** निष्कर्ष सतह पर लाता है, तो ऑडिट आपके संगठन के कॉन्फ़िगर किए गए चैनलों को सूचित करता है — वही `alerts.enabled_channels` गेट और सेटिंग्स जो अलर्ट्स पाइपलाइन का उपयोग करता है: + +- **Slack** — महत्वपूर्ण (`big`) नई वस्तुओं का एक सारांश एक गहरी लिंक के साथ। +- **Email** — एक डिज़ाइन किया गया **ऑडिट रिपोर्ट** जो नए सुधार (शीर्ष गंभीरता, प्रति-आइटम सिफारिशें, गहरी लिंक) सूचीबद्ध करता है, जब ऑडिट के पास एक **email** चैनल संलग्न हो और कम से कम एक नया निष्कर्ष हो। + +आवर्ती-लेकिन-ज्ञात निष्कर्ष फिर से सूचित नहीं करते हैं। + +## कॉन्फ़िगरेशन संदर्भ + +ऑडिट परिभाषाएं डैशबोर्ड (`/audits/new`) या API के माध्यम से प्रबंधित की जाती हैं। प्रति-ऑडिट सेटिंग्स में शेड्यूल cadence और विंडो, स्कोप (`{"environments": [...], "agent_ids": [...]}`), संवेदनशीलता (`low` / `medium` / `high`), सूचना चैनल, प्रति-रन निष्कर्ष कैप (`top_k`), और मॉडल (via `llm_budget.model`) शामिल हैं। ऑपरेटर-स्तर सर्वर सेटिंग्स (टाइमआउट्स, सैंडबॉक्स, एजेंट-सेवा URL) [deployment.md](/hi/agenteye/deployment) में दस्तावेज़ित हैं। + +## API + +सभी एंडपॉइंट्स संगठन-स्कोप किए गए हैं और मानक वाहक-कुंजी प्रमाणीकरण का पालन करते हैं (देखें [api-keys.md](/hi/agenteye/api-keys))। + +| एंडपॉइंट | अनुमति | उद्देश्य | +|---|---|---| +| `GET /audits` · `POST /audits` | `audits:read` / `audits:write` | ऑडिट परिभाषाओं को सूचीबद्ध / बनाएं। | +| `GET` / `PUT` / `DELETE /audits/:id` | read / write / write | एक ऑडिट का निरीक्षण, संपादन, हटाएं। | +| `POST /audits/:id/run` | `audits:write` | ऑडिट को तुरंत देय बनाएं। | +| `GET /audits/:id/runs` | `audits:read` | रन इतिहास (विंडो, स्थिति, आंकड़े, निष्कर्ष गिनती)। | +| `GET /audits/findings` | `audits:read` | संगठन-व्यापी निष्कर्ष, `audit_id`, `status` से फ़िल्टर योग्य; प्राथमिकता द्वारा सॉर्ट किए गए। | +| `GET /audits/findings/:fid` | `audits:read` | पूर्ण निष्कर्ष विवरण (सिफारिश, सबूत, प्राथमिकता)। | +| `POST /audits/findings/:fid/status` | `audits:write` | ट्रिएज: `{"action": "ack" \| "mute" \| "dismiss" \| "resolve" \| "reopen" \| "assign"}`. | + +"ऑडिट चला लेकिन कुछ नहीं मिला", "कोड सैंडबॉक्स अक्षम है", और "ऑडिट ईमेल वितरित नहीं किया गया" के लिए, [troubleshooting.md](/hi/agenteye/troubleshooting#audits) देखें। \ No newline at end of file diff --git a/docs/hi/agenteye/cli-recipes.mdx b/docs/hi/agenteye/cli-recipes.mdx new file mode 100644 index 00000000..33aac98d --- /dev/null +++ b/docs/hi/agenteye/cli-recipes.mdx @@ -0,0 +1,169 @@ +--- +title: "एजेंटों के लिए CLI रेसिपीज़" +description: "एजेंटों के लिए AgentEye CLI रेसिपीज़ दस्तावेज़।" +--- + +एक स्क्रिप्ट या कोडिंग एजेंट से सीधे सेशन, इवेंट और मूल्यांकन डेटा (और पुनः-मूल्यांकन ट्रिगर करें), stdout पर क्लीन JSON के साथ जो सीधे `jq` में पाइप होता है। ये रेसिपीज़ AgentEye के ऑब्ज़र्वेबिलिटी डेटा को ऐसी चीज़ में बदलती हैं जिसे एक टर्मिनल उपयोगकर्ता या एक AI कोडिंग एजेंट (Claude Code, Cursor) बिना डैशबोर्ड के क्लिक किए क्वेरी और ऑटोमेट कर सकता है। + +नीचे दिए गए पैटर्न AgentEye CLI (`agenteye`) के लिए कॉपी-पेस्ट के लिए तैयार हैं। इंस्टॉलेशन, प्रमाणीकरण और पूरी विकल्प सूची के लिए [CLI](/hi/agenteye/cli) देखें; बिल्ट-इन मदद के लिए `agenteye -h` या `agenteye -h` चलाएँ। + +## गोल्डन नियम + +1. **ग्लोबल विकल्प कमांड से *पहले* जाते हैं।** `agenteye --json sessions` सही है; `agenteye sessions --json` नहीं है। ग्लोबल्स हैं `--json`, `--base-url`, `--org`, `--token`, `--insecure`/`--secure`, `--timeout`, `--quiet`, `--no-color`। +2. **जब भी आप आउटपुट पार्स करें `--json` पास करें।** डेटा **stdout** पर JSON जाता है; मानव स्थिति और त्रुटियां **stderr** पर जाती हैं, इसलिए stdout `jq` में पाइप करने के लिए स्वच्छ रहता है। +3. **stderr टेक्स्ट पर नहीं, exit code पर शाखा दें**: `0` ठीक है · `2` खराब आर्गुमेंट्स · `3` डैशबोर्ड तक नहीं पहुंचा जा सकता · `4` लॉगिन नहीं किया गया या एक्सपायर हो गया · `5` अनुमति की कमी। +4. **`-h` के साथ खोजें।** हर कमांड अपने फिल्टर, वैल्यू फॉर्मेट और JSON आकार को डॉक्यूमेंट करता है। + +## एकबारी सेटअप + +```bash +export AGENTEYE_DASHBOARD_URL=https://agenteye.example.com # ताकि आप --base-url दोहराएं न +agenteye login --email you@example.com # ईमेल किए गए कोड को पेस्ट करें; ~24h वैलिड +``` + +## काम करने से पहले प्रमाणीकरण की पुष्टि करें + +`whoami` कभी भी गायब या एक्सपायर सेशन पर त्रुटि नहीं देता; यह इसके बजाय `logged_in:false` रिपोर्ट करता है, इसलिए एक एजेंट सुरक्षित रूप से प्रमाणीकरण स्थिति की जांच कर सकता है। (यह फिर भी गैर-शून्य exit कर सकता है यदि कोई base URL सेट नहीं है या डैशबोर्ड तक नहीं पहुंचा जा सकता है।) + +```bash +if [ "$(agenteye --json whoami | jq -r .logged_in)" != "true" ]; then + echo "Not authenticated. Run: agenteye login" >&2; exit 1 +fi +``` + +## विफल या कम स्कोरिंग वाले सेशन खोजें + +```bash +# पिछले 24h में सेशन जिनका मूल्यांकन त्रुटि है +agenteye --json sessions --since 24h --status error | jq -r '.sessions[].session_id' + +# एक एजेंट के लिए helpfulness पर 0.5 तक स्कोर करने वाले मूल्यांकन +agenteye --json evals --agent-id checkout-bot --score helpfulness:..0.5 \ + | jq '.evaluations[] | {session_id, scores}' +``` + +स्कोर फिल्टरिंग **`evals`** पर होती है, `sessions` पर नहीं। `--score KEY:MIN..MAX` दोहराने योग्य है और AND-संयुक्त है; कोई भी सीमा वैकल्पिक है (`..0.5` का मतलब ≤ 0.5, `0.9..` का मतलब ≥ 0.9)। आप प्रति अनुरोध 20 तक स्कोर फिल्टर पास कर सकते हैं; अधिक HTTP 400 देता है। `sessions` `evals` के साथ `--env`, `--status`, `--agent-id`, `--session-id`, और समय-रेंज फिल्टर साझा करता है, लेकिन `--score` नहीं है। + +## एक सेशन को शुरू से अंत तक पढ़ें + +कोई एकल `session show` कमांड नहीं है — इवेंट ट्रेल को सेशन के मूल्यांकन के साथ जोड़ें: + +```bash +# सेशन का नवीनतम मूल्यांकन (स्थिति + स्कोर) +agenteye --json evals --session-id run-001 | jq '.evaluations[0] | {status, scores}' + +# रन में हर इवेंट (पूर्ण स्वीप के लिए --limit बढ़ाएं) +agenteye --json events --session-id run-001 --all --limit 1000 | jq '.events[] | {ts, event_type}' + +# एक सेशन में सिर्फ टूल कॉल +agenteye --json events --session-id run-001 --event-type tool_use,tool_result --all \ + | jq '.events[].payload' +``` + +## सब कुछ फेच करें (पेजिनेशन) + +परिणाम सबसे नए-पहले हैं और कर्सर-पेजिनेटेड हैं। + +```bash +# एक शॉट: 200-पंक्ति के पेजों में 500 पंक्तियों तक फेच करें +agenteye --json events --session-id run-001 --limit 500 --all > events.json + +# मैनुअल पेजिंग: अगला cursor वापस फीड करें +page=$(agenteye --json events --limit 100) +cursor=$(echo "$page" | jq -r '.next_cursor // empty') +[ -n "$cursor" ] && agenteye --json events --limit 100 --cursor "$cursor" +``` + +## `--fields` के साथ आउटपुट को कम करें + +कुंजियों को (टेबल और `--json` दोनों में) प्रतिबंधित करें, एजेंट को जो पढ़ना चाहिए उसे कम करने के लिए। + +```bash +agenteye --json sessions --since 7d --fields session_id,status,scores | jq -c '.sessions[]' +agenteye --json events --session-id run-001 --fields ts,event_type --all +``` + +अज्ञात फील्ड नाम अस्वीकार किए जाते हैं (exit `2`) वैलिड सूची के साथ, फील्ड नाम खोजने का एक सस्ता तरीका। + +## वैलिड फिल्टर वैल्यूज़ खोजें + +```bash +agenteye --json list envs | jq -r '.values[]' # --env के लिए वैल्यूज़ +agenteye --json list tools | jq -r '.values[]' # टूल नाम; agents, models, event_types भी ... +agenteye --json list score_filters | jq -r '.values[]' # --score KEY:MIN..MAX के लिए वैलिड KEY +``` + +## अपना org चुनें (मल्टी-टेनेंट) + +यदि आप एक से अधिक org में हैं, तो लॉगिन पर सक्रिय टेनेंट चुनें (यह सहेजा जाता है): + +```bash +agenteye login --org acme --email you@corp.com # लॉगिन के समान चरण में टेनेंट सेट करें +agenteye --json orgs list | jq -r '.orgs[].org_slug' +agenteye --org globex --json sessions --since 24h # एक कमांड के लिए ओवरराइड करें +``` + +मल्टी-org लॉगिन `--org` के बिना गैर-शून्य exit करता है और चुनने के लिए orgs प्रिंट करता है। + +## SDK/collector के लिए एक API key प्रोविजन करें + +```bash +# सीक्रेट एक बार प्रिंट होता है — --json के साथ यह .key फील्ड है +key=$(agenteye --json keys create ci-bot --add events:read.add | jq -r '.key') +agenteye keys regenerate ci-bot --yes # घुमाएं; रद्द करने के लिए agenteye keys disable ci-bot --yes +``` + +## एक सहेजी गई या तदर्थ क्वेरी चलाएं + +```bash +agenteye --json query run --sql "select count(*) from analytics.events" | jq '.rows' +agenteye --json query run errs --arg prod | jq '.rows' # एक सहेजी गई क्वेरी + एक positional $1 +``` + +## एक incident को गैर-इंटरैक्टिवली ट्रिएज करें + +```bash +id=$(agenteye --json incidents list --state firing | jq -r '.incidents[0].id') +agenteye incidents ack "$id" +agenteye incidents assign "$id" you@corp.com +agenteye incidents resolve "$id" --yes +``` + +> Mutations `--json` के तहत या जब stdin एक TTY नहीं है तो अपनी पुष्टि प्रॉम्प्ट को ऑटो-स्किप करते हैं, इसलिए एजेंट कभी हैंग नहीं करते; कहीं और स्पष्ट रूप से इसे स्किप करने के लिए `--yes`/`-y` पास करें। + +## एक स्क्रिप्ट में Exit-code हैंडलिंग + +```bash +out=$(agenteye --json sessions --since 1h) || code=$? +case "${code:-0}" in + 0) echo "$out" | jq '.sessions | length' ;; + 4) echo "Session expired - run 'agenteye login'." >&2 ;; + 5) echo "Missing permission (ask an admin for evaluations:read)." >&2 ;; + 3) echo "Dashboard unreachable - check the URL." >&2 ;; + *) echo "Unexpected error (exit ${code})." >&2 ;; +esac +``` + +## JSON आउटपुट आकार + +| कमांड | stdout JSON (`--json` के साथ) | +|---|---| +| `whoami` | `{"logged_in": true, "id", "email", "is_instance_admin", "active_org", "permissions": [...], "memberships": [...]}` या `{"logged_in": false}` | +| `orgs list` | `{"active_org", "orgs": [{"org_slug","org_name","permission_set","permissions"}]}` | +| `events` | `{"events": [...], "next_cursor": }` | +| `evals` | `{"evaluations": [...], "next_cursor": }` | +| `sessions` | `{"sessions": [...], "next_cursor": }` | +| `errors` | `{"errors": [...], "next_cursor": }` | +| `list ` | `{"kind", "values": [...]}` | +| `keys list` / `keys create` | `{"keys": [...]}` / `{id, name, permissions, created_at, key}` (`key` एक बार दिखाया जाता है) | +| `query run` | `{columns: [{name,type}], rows: [[...]], truncated, elapsed_ms}` | +| `users list` / `settings list` | `{"users": [...]}` / `{"settings": [...]}` | +| `alerts list` / `incidents list` | `{"alerts": [...]}` / `{"incidents": [...]}` | +| create/update/delete (कोई भी) | संसाधन ऑब्जेक्ट, या डिलीट के लिए `{"deleted": true, "id"}` | +| विफलता (कोई भी, `--json` के साथ) | `{"error": "...", "exit_code": , "status"?: , "hint"?: "..."}` stdout पर | + +- प्रत्येक **event** आइटम (`events`): `id, session_id, agent_id, event_type, ts, payload, environment`। +- प्रत्येक **evaluation** आइटम (`evals`): `id, session_id, agent_id, environment, status, scores, reasoning, summary, error, attempt_count, duration_ms, completed_at, created_at`। +- प्रत्येक **session** आइटम (`sessions`): `session_id, agent_id, environment, status, scores, event_count, started_at, last_event_at, first_event_id, last_event_id, latest_evaluation`। + +प्रत्येक कमांड का `--fields` ठीक अपने स्वयं के आइटम के फील्ड नाम स्वीकार करता है — `sessions` और `evals` के बीच सेट अलग है, इसलिए एक के लिए वैलिड नाम दूसरे द्वारा अस्वीकार किया जा सकता है। \ No newline at end of file diff --git a/docs/hi/agenteye/cli-skill.mdx b/docs/hi/agenteye/cli-skill.mdx new file mode 100644 index 00000000..80c65fa5 --- /dev/null +++ b/docs/hi/agenteye/cli-skill.mdx @@ -0,0 +1,96 @@ +--- +--- +title: "AgentEye CLI Agent Skill" +description: "AgentEye AgentEye CLI Agent Skill डॉक्यूमेंटेशन।" +--- + + +**AgentEye CLI skill** (`agenteye-cli`) एक इंस्टॉल करने योग्य *Agent Skill* है जो एक कोडिंग एजेंट — Claude Code, Codex, और संगत टूल्स — को सादे अंग्रेजी अनुरोधों से आपके AgentEye डिप्लॉयमेंट को [`agenteye` CLI](/hi/agenteye/cli) के माध्यम से संचालित करने के लिए सिखाता है: *"क्या आज कुछ टूटा हुआ है?"*, *"CI को एक key दें जो केवल events को push कर सके"*, *"फायरिंग इंसिडेंट को स्वीकार करें और इसे मेरे लिए असाइन करें"*। + +यह **कोई सेवा या अलग बाइनरी नहीं** है। यह एक छोटा निर्देश बंडल है जो उस CLI के शीर्ष पर चलता है जिसे आप पहले से ही इंस्टॉल कर चुके हैं: एजेंट `agenteye --json …` को शेल करता है, स्वच्छ JSON को पार्स करता है, और आपको गद्य में जवाब देता है। सब कुछ जो यह कर सकता है, आप स्वयं उसी कमांड को टाइप करके कर सकते हैं। + +--- + +## यह अन्य AgentEye इंटरफेस से कैसे संबंधित है + +AgentEye आपको समान डेटा और नियंत्रण तक पहुंचने के चार तरीके देता है। वे एक-दूसरे को पूरक करते हैं: + +| इंटरफेस | यह क्या है | कहां चलता है | इसे कब चुनें | +|---|---|---|---| +| **[CLI](/hi/agenteye/cli)** | `agenteye` के लिए कमांड/फ़्लैग संदर्भ | आपका टर्मिनल | जब आप कोई विशिष्ट कमांड चलाना या स्क्रिप्ट करना चाहते हैं | +| **[CLI recipes](/hi/agenteye/cli-recipes)** | कॉपी-पेस्ट `jq`/पाइपलाइन पैटर्न | आपका टर्मिनल / स्क्रिप्ट्स | जब आप CLI को ऑटोमेशन में वायर कर रहे हों | +| **CLI skill** (यह डॉक्यूमेंटेशन) | CLI पर एक प्राकृतिक-भाषा फ्रंट डोर | आपका कोडिंग एजेंट, आपकी वर्कस्टेशन पर | जब आप बस पूछना चाहते हैं और एजेंट को कमांड चुनने दें | +| **[In-dashboard AI Assistant](/hi/agenteye/assistant)** | डैशबोर्ड में एम्बेडेड एक चैट | आपके क्लस्टर में एक आंतरिक `agent` कंटेनर | जब आप अपने डेटा पर डैशबोर्ड-में Q&A चाहते हैं | + +### in-dashboard AI Assistant के विरुद्ध — एक महत्वपूर्ण अंतर + +ये दो अलग-अलग टूल्स हैं जिनके बहुत अलग प्रभाव क्षेत्र हैं: + +- **in-dashboard AI Assistant** ([assistant.md](/hi/agenteye/assistant)) डैशबोर्ड में एम्बेडेड एक चैट है, जो एक आंतरिक `agent` कंटेनर द्वारा संचालित है। यह **read-only प्लस approval-gated authoring** है: यह सहेजे गए प्रश्न और डैशबोर्ड ड्राफ्ट कर सकता है, लेकिन हर लेखन आपकी स्पष्ट क्लिक-अनुमोदन के लिए रुकता है, और यह कभी नहीं हटाता। यह `agent:use` अनुमति द्वारा गेटेड है और केवल उस संगठन के लिए डेटा देखता है जिसे आप देख रहे हैं। +- **CLI skill** आपकी वर्कस्टेशन पर आपके कोडिंग एजेंट के अंदर चलता है और `agenteye` CLI को **आप** के रूप में चलाता है। यह CLI की **पूर्ण सतह चला सकता है, जिसमें mutations भी शामिल हैं** — API keys बनाएं/घुमाएं/अक्षम करें, संगठन सेटिंग्स बदलें, incidents को resolve करें, सहेजे गए प्रश्न हटाएं — केवल आपकी CLI लॉगिन की अनुमतियों द्वारा सीमित। इसे बिल्कुल उसी तरह से सावधानीपूर्वक व्यवहार करें जैसे आप उन कमांड्स को हाथ से चलाते समय करेंगे। + +--- + +## पूर्वापेक्षाएं + +1. **`agenteye` CLI इंस्टॉल** और `PATH` पर (देखें [cli.md](/hi/agenteye/cli) — `pipx install agenteye`)। +2. आपका **डैशबोर्ड URL सेट** (`AGENTEYE_DASHBOARD_URL`, या एजेंट `--base-url` को पास करता है)। +3. एक **लॉगिन किया गया सेशन**: पहले स्वयं `agenteye login` चलाएं। skill **नहीं** ईमेल किए गए एक बार के कोड लॉगिन को आपके लिए पूरा कर सकता है — यह आपको `agenteye login` चलाने के लिए कहेगा यदि सेशन गायब है या समाप्त हो गया है (CLI exit code `4`)। + +--- + +## Skill को इंस्टॉल करना + +Agent Skills फोल्डर हैं जिनमें एक `SKILL.md` होता है (साथ ही वैकल्पिक संदर्भ)। आप `agenteye-cli` skill को इंस्टॉल करते हैं इसके फोल्डर को उस स्थान पर रखकर जहां आपका एजेंट skills को देखता है: + +- **Claude Code** — `agenteye-cli/` फोल्डर को `~/.claude/skills/` में कॉपी करें (हर प्रोजेक्ट में उपलब्ध) या `/.claude/skills/` में (उस repo के लिए scoped)। Claude Code इसे auto-discover करता है; `/skills` सूची से सत्यापित करें, या बस एक प्रश्न पूछें जो इसके विवरण से मेल खाता हो। +- **Codex (OpenAI)** — Codex समान `SKILL.md` को पढ़ता है। bundled `agents/openai.yaml` `allow_implicit_invocation: true` सेट करता है, इसलिए Codex auto-selects करता है skill जब कोई कार्य मेल खाता है; अन्यथा इसे `$agenteye-cli` के रूप में स्पष्ट रूप से invoke करें। + +Skill को `agenteye` CLI के साथ बनाए रखा जाता है और आपके AgentEye पैकेज के भाग के रूप में वितरित किया जाता है — यदि आपके पास `agenteye-cli` फोल्डर नहीं है, तो अपने AgentEye संपर्क से पूछें। इसके बारे में कुछ भी गेटेड नहीं है: इसे कोई Docker image की आवश्यकता नहीं है और कोई credential नहीं है, क्योंकि यह केवल **public** `agenteye` CLI को आपके अपने डैशबोर्ड के विरुद्ध चलाता है। + +--- + +## सुरक्षा — mutations **नहीं** prompted जब कोई एजेंट CLI चलाता है + +**कोई एजेंट को परिवर्तन करने देने से पहले इसे पढ़ें।** + +`agenteye` CLI आम तौर पर किसी विनाशकारी कार्य से पहले *"क्या आप सुनिश्चित हैं?"* पूछता है। यह **auto-skips that confirmation जब यह किसी टर्मिनल से जुड़ा नहीं है — जो बिल्कुल वह है कि कैसे एक कोडिंग एजेंट इसे चलाता है — और `--json` भी इसे स्किप करता है।** इसलिए सुरक्षा प्रॉम्प्ट एजेंट के लिए **नहीं** फायर होगा। + +Skill को इसके लिए लिखा गया है: इसे निर्देशित किया जाता है कि यह बिल्कुल कमांड को स्टेट करे जो यह चलाएगा और किसी भी state change से पहले आपकी स्पष्ट **ठीक है** प्राप्त करे। उस अनुशासन को रखें — जब आप AgentEye को एजेंट के माध्यम से चलाते हैं, *आप* confirmation step हैं। state-changing कमांड्स जिन पर ध्यान देना है: + +- `keys create` / `update` / `disable` / `regenerate` +- `users create` / `update` / `disable` / `enable` +- `settings set` +- `alerts create` / `update` / `delete` / `test` +- writing `incidents` subcommands: `ack` / `assign` / `resolve` / `open` / `comment-add` / `comment-delete` / `subscribe` / `unsubscribe` +- `query create` / `update` / `delete` +- `agent rename` / `delete` +- `orgs switch` + +**Observe** के अंतर्गत सब कुछ (`events`, `sessions`, `evals`, `errors`, `list`, `whoami`, `orgs list/current/perms`) read-only है और कुछ भी नहीं बदलता। + +क्योंकि एजेंट **आप** के रूप में कार्य करता है, यह केवल वही कर सकता है जो आपकी लॉगिन को अनुमति है — अनुमतियों को **per org** resolve किया जाता है (देखें [api-keys.md](/hi/agenteye/api-keys))। एक कमांड जिसके लिए आपके पास अनुमति नहीं है exit code `5` के साथ return करता है साथ ही सटीक अनुमति named, तो एजेंट आपको बिल्कुल बता सकता है कि किसी व्यवस्थापक से क्या पूछना है, अपारदर्शी तरीके से विफल होने के बजाय। + +--- + +## आप इससे क्या पूछ सकते हैं + +Skill plain-English intent को सही `agenteye` कमांड में मैप करता है, पहले valid values को discover करता है (`list `, `whoami`) ताकि यह अनुमान न लगाए: + +- *"क्या कुछ टूटा/फायरिंग है पिछले 24 घंटों में?"* → `errors --since 24h --aggregate`, फिर एक breakdown। +- *"सेशन `run-001` क्यों विफल हुआ?"* → `events --session-id run-001 --all` + `evals --session-id run-001`। +- *"यह सप्ताह गुणवत्ता कैसे trending है?"* → `evals --aggregate --since 7d`, फिर low-scoring runs में ड्रिल करें। +- *"CI को एक key दें जो केवल events को push कर सके।"* → `keys create ci --add events:add` (यह कमांड को स्टेट करता है, फिर इसे बनाता है और एक बार का secret capture करता है)। +- *"किसके पास एक्सेस है? Dana को read-only बनाएं।"* → `users list` → `users update dana@… --permission-set read-only` (आपके साथ confirm करने के बाद)। +- *"फायरिंग इंसिडेंट को acknowledge करें और इसे मेरे लिए असाइन करें।"* → `incidents list --state firing` → `incidents ack ` / `incidents assign you@…`। + +सटीक कमांड्स, flags, और इन के पीछे JSON shapes के लिए, देखें [cli.md](/hi/agenteye/cli) और [cli-recipes.md](/hi/agenteye/cli-recipes)। + +--- + +## यह भी देखें + +- **[CLI](/hi/agenteye/cli)** — `agenteye` के लिए पूर्ण कमांड और flag संदर्भ। +- **[CLI recipes for agents](/hi/agenteye/cli-recipes)** — कॉपी-पेस्ट `jq` पैटर्न और exit-code handling। +- **[AI Assistant](/hi/agenteye/assistant)** — in-dashboard assistant (इस terminal skill के साथ भ्रमित न करें)। +- **[API Keys](/hi/agenteye/api-keys)** — per-org अनुमति मॉडल जो यह define करता है कि skill क्या कर सकता है। \ No newline at end of file diff --git a/docs/hi/agenteye/cli.mdx b/docs/hi/agenteye/cli.mdx new file mode 100644 index 00000000..56ad8e2b --- /dev/null +++ b/docs/hi/agenteye/cli.mdx @@ -0,0 +1,292 @@ +--- +title: "CLI" +description: "AgentEye CLI दस्तावेज़।" +--- + + +AgentEye CLI (`agenteye`) आपके AgentEye परिनियोजन के लिए एक टर्मिनल क्लाइंट है। यह आपके डेटा (सेशन, ईवेंट लॉग, मूल्यांकन) को क्वेरी करता है और संगठन का प्रबंधन करता है (API कुंजियाँ, उपयोगकर्ता, सेटिंग्स, अलर्ट, घटनाएं, सहेजी गई क्वेरीज़) — सब कुछ जो डैशबोर्ड करता है, एक स्क्रिप्ट या कोडिंग एजेंट से। हर कमांड `--json` फ़्लैग को सपोर्ट करता है, इसलिए यह एक प्रॉम्प्ट पर मनुष्य के लिए या कोडिंग एजेंट (Claude Code, Cursor) के लिए समान रूप से अच्छी तरह काम करता है। + +> यह **`agenteye` CLI** है, **कलेक्टर** डेमॉन (`agenteye-collector`) से एक अलग टूल है। CLI आपके **डैशबोर्ड** से बात करता है; कलेक्टर सर्वर को ईवेंट भेजता है। कलेक्टर के लिए [कलेक्टर इंस्टॉलेशन](/hi/agenteye/collector-installation) देखें। + +--- + +## इंस्टॉलेशन + +CLI को सार्वजनिक PyPI पर **`agenteye`** के रूप में प्रकाशित किया जाता है। क्योंकि AgentEye Python SDK भी `agenteye` वितरण नाम का उपयोग करता है, CLI को एक **अलग** वातावरण (`pipx` या `uv tool`) में इंस्टॉल करें ताकि दोनों कभी एक virtualenv में टकराएं नहीं: + +```bash +pipx install agenteye +# or +uv tool install agenteye +``` + +एक सादा `pip install agenteye` भी काम करता है यदि आप Python SDK को एक ही वातावरण में इंस्टॉल नहीं कर रहे हैं। CLI को Python 3.10+ की आवश्यकता है और GitHub टोकन की आवश्यकता नहीं है; यह एक सार्वजनिक पैकेज है। + +इंस्टॉल की गई कमांड **`agenteye`** है: + +```bash +agenteye --version +agenteye --help +``` + +--- + +## प्रमाणीकरण + +CLI **डैशबोर्ड** के साथ एक ईमेल किए गए एकबारी कोड के साथ प्रमाणित होता है: + +```bash +agenteye login --email you@example.com +# एक 6-अंकीय कोड आपको ईमेल किया जाता है; प्रॉम्प्ट पर इसे पेस्ट करें। +``` + +सेशन टोकन `~/.agenteye/cli.json` में संग्रहीत किया जाता है (केवल आपके द्वारा पठनीय, मोड `0600`) और डिफ़ॉल्ट रूप से 24 घंटे के लिए वैध है। जब यह समाप्त हो जाता है, `agenteye login` फिर से चलाएं। + +```bash +agenteye whoami # वर्तमान उपयोगकर्ता, सक्रिय संगठन, और अनुमतियां दिखाएं +agenteye logout # सेशन को रद्द करें और संग्रहीत टोकन को साफ़ करें +``` + +`whoami` कभी भी एक लापता या समाप्त सेशन पर त्रुटि नहीं देता — इसके बजाय `logged_in: false` की रिपोर्ट करता है, इसलिए एक स्क्रिप्ट या एजेंट सुरक्षित रूप से प्रमाणीकरण स्थिति को जांच सकता है (यदि कोई आधार URL सेट नहीं है या डैशबोर्ड अप्राप्य है तो यह अभी भी गैर-शून्य बाहर निकल सकता है)। + +**आवश्यकताएं:** आपके ईमेल को डैशबोर्ड में साइन इन करने की अनुमति दी जानी चाहिए (अपने AgentEye प्रशासक से पूछें), और डैशबोर्ड को अपने आधार URL पर पहुंचा जा सकता होना चाहिए (देखें [कॉन्फ़िगरेशन](#configuration))। यदि आप एक कोड का अनुरोध करते हैं और कोई नहीं आता है, तो आपका ईमेल शायद अभी तक डैशबोर्ड एक्सेस के लिए सक्षम नहीं है। + +--- + +## अपने संगठन को चुनना (मल्टी-टेनेंट) + +यदि आपका खाता एक से अधिक संगठन से संबंधित है, तो **लॉगिन पर** सक्रिय एक चुनें — इसे सहेजा जाता है और हर बाद की कमांड के लिए उपयोग किया जाता है: + +```bash +agenteye login --org acme # प्रमाणित करें और एक कदम में सक्रिय टेनेंट सेट करें +agenteye orgs list # जो संगठन आप एक्सेस कर सकते हैं (सक्रिय को चिह्नित किया गया) +agenteye orgs switch globex # सहेजा हुआ डिफ़ॉल्ट बदलें +agenteye --org globex sessions # एक ही कमांड के लिए ओवरराइड करें +``` + +यदि आप बिल्कुल एक संगठन से संबंधित हैं तो यह स्वचालित रूप से चुना जाता है और आप `--org` को पूरी तरह से अनदेखा कर सकते हैं। यदि आप कई से संबंधित हैं और एक को नहीं चुनते हैं, तो CLI उन्हें सूचीबद्ध करता है और आपको `--org ` के साथ फिर से चलाने के लिए कहता है। सक्रिय संगठन हर अनुरोध पर डैशबोर्ड को भेजा जाता है, और आपकी अनुमतियां **प्रति संगठन** में हल की जाती हैं — `agenteye whoami` सक्रिय संगठन, इसमें आपकी अनुमतियां, और आपकी सभी सदस्यताएं दिखाता है। + +--- + +## कॉन्फ़िगरेशन + +| सेटिंग | फ़्लैग | पर्यावरण चर | डिफ़ॉल्ट | +|---|---|---|---| +| डैशबोर्ड आधार URL | `--base-url` | `AGENTEYE_DASHBOARD_URL` | **आवश्यक** (कोई डिफ़ॉल्ट नहीं) | +| सक्रिय संगठन/टेनेंट | `--org` | `AGENTEYE_ORG` | लॉगिन पर चुना गया; `~/.agenteye/cli.json` में सहेजा गया | +| सेशन टोकन | `--token` | `AGENTEYE_CLI_TOKEN` | `~/.agenteye/cli.json` से | +| JSON आउटपुट | `--json` | `AGENTEYE_CLI_JSON` | बंद | +| TLS सत्यापन छोड़ें | `--insecure` / `--secure` | `AGENTEYE_INSECURE` | बंद (लॉगिन पर सहेजा गया) | +| अनुरोध टाइमआउट (सेकंड) | `--timeout` | — | 30 | +| उपयोग टेलीमेट्री अक्षम करें | _(कोई नहीं)_ | `AGENTEYE_ANALYTICS_DISABLED` (या `DO_NOT_TRACK`) | बंद (टेलीमेट्री चालू) | + +संकल्प क्रम है **फ़्लैग → पर्यावरण चर → कॉन्फ़िगरेशन फ़ाइल**। कोई डिफ़ॉल्ट नहीं है; आपको CLI को अपने डैशबोर्ड पर इंगित करना चाहिए, या तो प्रति-कमांड (`--base-url https://agenteye.example.com`) या एक बार वातावरण के माध्यम से (यह आपके पहले `login` के बाद भी सहेजा जाता है): + +```bash +export AGENTEYE_DASHBOARD_URL=https://agenteye.example.com +``` + +कॉन्फ़िगरेशन निर्देशिका `AGENTEYE_HOME` का सम्मान करती है (SDK और कलेक्टर द्वारा उपयोग की जाने वाली एक ही परंपरा); यदि सेट किया गया है, तो `cli.json` `$AGENTEYE_HOME/cli.json` में रहता है। + +### स्व-हस्ताक्षरित या आंतरिक TLS + +यदि आपका डैशबोर्ड एक स्व-हस्ताक्षरित या आंतरिक प्रमाणपत्र के साथ HTTPS पर परोसा जाता है (उदाहरण के लिए, एक कच्चा लोड-बैलेंसर होस्टनाम), TLS सत्यापन इसे एक `CERTIFICATE_VERIFY_FAILED` त्रुटि के साथ अस्वीकार करता है। प्रमाणपत्र सत्यापन को छोड़ने के लिए `--insecure` पास करें: + +```bash +agenteye --base-url https://agenteye.internal --insecure login +``` + +`--insecure` **आपके लॉगिन के समय `cli.json` में सहेजा जाता है**, इसलिए बाद की कमांड स्वचालित रूप से सत्यापन छोड़ देती हैं; आपको फ़्लैग को दोहराना नहीं पड़ता। एक एकबारी सत्यापित कॉल के लिए `--secure` पास करें, या अपने अगले लॉगिन पर सत्यापन वापस चालू करने के लिए। CLI एक चेतावनी को stderr पर प्रिंट करता है किसी भी कमांड से पहले जो डैशबोर्ड से संपर्क करता है जबकि सत्यापन अक्षम है। सत्यापन को छोड़ना मैन-इन-द-मिडिल हमलों से सुरक्षा को हटाता है; अपने डैशबोर्ड के लिए नेटवर्क पाथ पर भरोसा करने से पहले सुनिश्चित करें कि आप इस पर भरोसा करते हैं (VPN, निजी सबनेट, आदि)। + +--- + +## टेलीमेट्री और गोपनीयता + +CLI **अनाम उपयोग विश्लेषण** को Exosphere की विश्लेषण सेवा (PostHog) में भेजता है: कौन सी कमांड चलाई जाती हैं (उदाहरण के लिए `sessions`, `keys create`), क्या वे सफल हुईं, और वे कितने समय तक चलीं। यह उपयोग संकेत सूचित करता है कि कौन से फीचर को प्राथमिकता दी जाए। + +- **कोई एजेंट, सेशन, या ईवेंट डेटा कभी भी आपके बुनियादी ढांचे को नहीं छोड़ता है।** केवल CLI उपयोग की रिपोर्ट की जाती है: कमांड और सबकमांड नाम (उदाहरण के लिए `keys create`), आपके द्वारा उपयोग किए गए **फ़्लैग के नाम** (कभी भी उनके मान नहीं), सफलता/निकास स्थिति, और अवधि — साथ ही म्यूटेशन के लिए एक प्रति-कार्रवाई ईवेंट (उदाहरण के लिए `api_key_created`, `query_run`) केवल स्थैतिक नाम/एनम और मोटे गिनती ले जाते हुए। आपका डैशबोर्ड URL, सेशन टोकन, ईमेल, संगठन स्लग, संसाधन ids, SQL, कुंजी रहस्य, और क्वेरी फ़िल्टर **कभी** नहीं भेजे जाते हैं। ऑपरेटरों को केवल एक अपारदर्शी आंतरिक id द्वारा पहचाना जाता है, कभी भी ईमेल द्वारा नहीं। +- टेलीमेट्री **डिफ़ॉल्ट रूप से सक्षम है**। इसे बंद करने के लिए, CLI के वातावरण में `AGENTEYE_ANALYTICS_DISABLED=1` सेट करें (CLI क्रॉस-टूल `DO_NOT_TRACK=1` परंपरा का भी सम्मान करता है)। +- CLI सीधे PostHog (`https://us.i.posthog.com`) को भेजता है। **CLI चलाने वाली मशीन** को उस होस्ट तक आउटबाउंड एक्सेस की आवश्यकता है; यदि यह अवरुद्ध है, तो टेलीमेट्री चुप रहता है (भेजना समय-सीमित है इसलिए यह कभी भी एक कमांड को विलंबित या तोड़ता नहीं है) और CLI अप्रभावित है। + +--- + +## वैश्विक विकल्प और सम्मेलन + +यह एक बार पढ़ें; यह हर कमांड पर लागू होता है। + +- **वैश्विक विकल्प कमांड से पहले जाते हैं।** `agenteye --json sessions` सही है; `agenteye sessions --json` एक उपयोग त्रुटि है। ग्लोबल `--json`, `--base-url`, `--org`, `--token`, `--insecure`/`--secure`, `--timeout`, `--quiet`, और `--no-color` हैं। +- **`--json` शुद्ध JSON को stdout में, और कुछ नहीं प्रिंट करता है।** मानव स्थिति लाइनें, चेतावनियां, और त्रुटियां **stderr** पर जाती हैं, इसलिए एक `--json` stdout कैप्चर `jq` में पाइप करने के लिए स्वच्छ रहता है भले ही एक स्थिति पंक्ति दिखाई जाए। `--json` के बिना आप मानव आंखों के लिए एक बॉक्सित, रंगीन दृश्य प्राप्त करते हैं। +- **`--help` के साथ खोजें।** हर कमांड और सबकमांड के पास `--help` है (और `-h` उपनाम): `agenteye -h`, `agenteye sessions -h`, `agenteye keys create -h`। शीर्ष-स्तरीय सहायता भी निकास कोड और वैश्विक विकल्प सूचीबद्ध करता है। कोई वैश्विक मशीन-पठनीय सतह डंप नहीं है; प्रति-कमांड `--help` का उपयोग करें, साथ ही डोमेन-विशिष्ट `agenteye query schema` और `agenteye settings schema` उन दोनों रजिस्ट्रीज के लिए। +- **पुष्टिकरण स्क्रिप्ट और एजेंटों के लिए स्वचालित रूप से छोड़ते हैं।** बनाएं/अपडेट/हटाएं कमांड एक इंटरैक्टिव टर्मिनल में "क्या आप सुनिश्चित हैं?" के लिए प्रॉम्प्ट करते हैं, लेकिन **`--json` के तहत या जब भी stdin एक TTY नहीं है तो स्वचालित रूप से छोड़ देते हैं** — इसलिए स्क्रिप्ट और एजेंट कभी लटकते नहीं हैं। इसे स्पष्ट रूप से छोड़ने के लिए `--yes`/`-y` पास करें। क्योंकि प्रॉम्प्ट एक एजेंट के लिए फायर नहीं करेगा, एक एजेंट को विनाशकारी क्रियाओं की पुष्टि पहले मानव के साथ करनी चाहिए। +- **पेजिनेशन:** परिणाम नवीनतम-पहले और कर्सर-पेजिनेटेड हैं। `--limit N` (उपनाम `-n`) पंक्तियों को कैप करता है और **डिफ़ॉल्ट 50 है**; `--all` स्वचालित रूप से पेजिनेट करता है (200-पंक्ति चंकों में) **`--limit` तक** — इसलिए एक नंगा `--all` अभी भी 50 पर रुकता है। एक पूर्ण स्वीप के लिए एक उच्च स्पष्ट टोपी पास करें: `--all --limit 1000`। `--page-size N` प्रति-अनुरोध चंक को नियंत्रित करता है (अधिकतम 200); `--cursor ` एक पूर्व पृष्ठ के `next_cursor` से फिर से शुरू होता है। +- **समय फ़िल्टर:** `--since` एक सापेक्ष खिड़की लेता है — `15m`, `1h`, `6h`, `24h`, `7d`, `30d`, या `all` (डैशबोर्ड की प्रीसेट)। `--from`/`--to` स्पष्ट ISO-8601 UTC टाइमस्टैम्प **`T` और एक टाइमज़ोन के साथ** (उदाहरण के लिए `2026-06-01T00:00:00Z`) एक कस्टम रेंज के लिए और `--since` को ओवरराइड करते हैं; एक स्पेस-सेपरेटेड या टाइमज़ोन-रहित मान एक उपयोग त्रुटि है। +- **`--fields a,b,c`** (पर `events`, `sessions`, `evals`, `errors`) आउटपुट को उन कुंजियों तक सीमित करता है, तालिका और `--json` दोनों के लिए। अज्ञात नाम वैध सूची के साथ अस्वीकार किए जाते हैं — फ़ील्ड नाम खोजने का एक सस्ता तरीका। +- **`--file payload.json`** (या `--file -` stdin को पढ़ने के लिए) एक पूर्ण JSON अनुरोध बॉडी प्रदान करता है जहां एक संसाधन के पास एक जटिल आकार है — `alerts create/update`, `settings set`, और `users create/update` पर। सहेजी गई क्वेरी SQL के बजाय `--sql @file.sql` का उपयोग करता है। +- **मल्टी-मान फ़िल्टर** कोमा-सेपरेटेड हैं → एक सेट के रूप में मिलान किया गया (एक फ़िल्टर के भीतर संघ, फ़िल्टर में AND): `--event-type tool_use,tool_result`। क्लिक विकल्प variadic नहीं हैं, इसलिए `--add a b` टूटता है — `--add a,b` का उपयोग करें, फ़्लैग को दोहराएं (`--add a --add b`), या उद्धरण करें (`--add "a b"`)। + +--- + +## कमांड संदर्भ + +CLI के पास **18 शीर्ष-स्तरीय कमांड** हैं। सभी पढ़ें कमांड `--json` और ऊपर वैश्विक विकल्प स्वीकार करते हैं; किसी भी एक के लिए विस्तृत फ़्लैग सूची और JSON आकार के लिए `agenteye -h` (या ` -h`) चलाएं। + +### पहचान — `login` · `logout` · `whoami` · `orgs` · `version` · `help` + +```bash +agenteye login --email you@example.com [--org acme] # ईमेल किया गया एकबारी कोड; सेशन सहेजता है +agenteye logout # इस मशीन पर सहेजे गए सेशन को साफ़ करें +agenteye whoami # वर्तमान उपयोगकर्ता, सक्रिय संगठन, अनुमतियां +agenteye version # CLI संस्करण प्रिंट करें (समान --version) +agenteye help # शीर्ष-स्तरीय सहायता (समान --help) +``` + +`orgs` सक्रिय टेनेंट का निरीक्षण और स्विच करता है: + +```bash +agenteye orgs list # आपके संगठन + प्रत्येक में आपकी भूमिका (सक्रिय को चिह्नित किया गया) +agenteye orgs switch acme # सहेजे गए सक्रिय संगठन को बदलें (एक TTY पर सूची से चुनने के लिए स्लग को छोड़ें) +agenteye orgs current # सक्रिय संगठन के लिए पहचान पत्र +agenteye orgs perms # सक्रिय संगठन में आपकी अनुमतियां, संसाधन द्वारा समूहीकृत +``` + +### अवलोकन (केवल पढ़ें) — `events` · `sessions` · `evals` · `errors` · `list` + +इनमें से कोई भी पुष्टिकरण की जरूरत नहीं है। साझा फ़िल्टर: `--session-id`, `--agent-id`, `--env` (**नहीं** `--environment`), और समय सीमा (`--since` / `--from` / `--to`)। + +```bash +# events (उपनाम: कच्चा प्रति-चरण ट्रेल) — नवीनतम पहले +agenteye --json events --session-id run-001 --event-type tool_use,tool_result --all --limit 1000 +agenteye --json events --since 1h --search timeout --all | jq '.events[].payload' + +# sessions — एक पंक्ति प्रति एजेंट रन (समय/वातावरण/एजेंट/सेशन/स्थिति; कोई स्कोर फ़िल्टरिंग नहीं) +agenteye --json sessions --since 24h --status error +agenteye --json sessions --agent-id checkout-bot --env prod --all --limit 1000 + +# evals — मूल्यांकन परिणाम + स्कोर; --score मीट्रिक द्वारा फ़िल्टर करता है, --aggregate रोल अप करता है +agenteye --json evals --score helpfulness:0.5..0.8 --score tool_efficiency:..0.3 +agenteye --json evals --aggregate --since 7d --env prod # स्थिति मिश्रण + प्रति-कुंजी स्कोर सांख्यिकी + +# errors — त्रुटिपूर्ण ईवेंट; --aggregate गिनती/सेशन/एजेंट/अंतिम-देखे गए के लिए +agenteye --json errors --since 24h --aggregate +agenteye --json errors --since 24h --error-type timeout --all --limit 1000 + +# list — फ़िल्टर करने से पहले वैध फ़िल्टर मान खोजें +agenteye list envs # भी: agents event_types score_filters models hooks triggers tools error_types +``` + +`--score KEY:MIN..MAX` (**`evals`** पर, `sessions` नहीं) दोहराने योग्य है और AND-संयुक्त है; या तो सीमा वैकल्पिक है (`..0.5` का अर्थ है ≤ 0.5, `0.9..` का अर्थ है ≥ 0.9)। प्रति अनुरोध 20 स्कोर फ़िल्टर तक। `evals --scores-full` सारांश के बजाय संपूर्ण स्कोर ऑब्जेक्ट देता है। **एक सेशन को अंत तक पढ़ने के लिए**, ईवेंट ट्रेल को इसके मूल्यांकन के साथ संयोजित करें: + +```bash +agenteye --json events --session-id run-001 --all --limit 1000 | jq '.events[] | {ts, event_type}' +agenteye --json evals --session-id run-001 # इसके स्कोर + स्थिति +``` + +### प्रबंधन (अनुमति-गेटेड) — `keys` · `users` · `settings` · `alerts` · `incidents` + +**`keys`** — API कुंजियां। रहस्य स्थानीय रूप से उत्पन्न होता है, सर्वर को भेजा जाता है (जो केवल एक हैश संग्रहीत करता है), और बनाएं/पुनर्जन्म पर **एक बार दिखाया जाता है** — इसे तब कैप्चर करें। `--json` के साथ यह केवल `key` फ़ील्ड में दिखाई देता है। **नाम** द्वारा संदर्भित। + +```bash +agenteye keys list # सक्रिय कुंजियां पहले, फिर रद्द +agenteye keys show ci-bot +agenteye keys create ci-bot --add events:read.add # जो आपको चाहिए उस पर स्कोप; रहस्य प्रिंट करता है एक बार +agenteye keys create ops --permission-set standard --remove queries:run # प्रीसेट बीज करें, फिर ट्रिम करें +agenteye keys update ci-bot --add evaluations:read --yes +agenteye keys regenerate ci-bot --yes # रहस्य को घुमाएं (पुराना बंद हो जाता है) +agenteye keys disable ci-bot --yes # रद्द करें +``` + +अनुमतियां `(permission-set ∪ --add) − --remove` के रूप में काम करती हैं। टोकन `slug:action` हैं (उदाहरण के लिए `events:read`) या `slug:action.action` एक संसाधन पर कई को विस्तारित करने के लिए (`events:read.add` → `events:read`, `events:add`)। प्रीसेट: `read-only`, `standard`, `admin`। केवल-मानव अनुमतियां (`keys:update`) एक कुंजी को अनुदान नहीं दी जा सकती हैं। + +**`users`** — संगठन सदस्य, **ईमेल** द्वारा संदर्भित (एक UUID id भी स्वीकार किया जाता है)। + +```bash +agenteye users list [--active-only] +agenteye users show dev@corp.com +agenteye users create dev@corp.com --permission-set standard +agenteye users update dev@corp.com --add alerts:write --remove queries:delete # भविष्यवाणी करता है + पुष्टि करता है +agenteye users disable dev@corp.com --yes # संरक्षित/स्व-गार्ड है +agenteye users enable dev@corp.com +``` + +**`settings`** — एक निश्चित रजिस्ट्री (आप मौजूदा कुंजियों को पढ़ते और बदलते हैं; आप नई कुंजियां नहीं बना सकते)। + +```bash +agenteye settings list # कुंजी · मान · प्रकार · अद्यतन (रहस्य छिपाए गए) +agenteye settings schema # प्रत्येक कुंजी क्या स्वीकार करती है (प्रकार · रेंज · विवरण) +agenteye settings set session_ttl_secs --value 86400 --yes +``` + +**`alerts`** — अलर्ट परिभाषाएं, **नाम** द्वारा संदर्भित। `create` एक स्थितीय NAME साथ-साथ फ़्लैग या `--file` के माध्यम से एक पूर्ण JSON बॉडी लेता है। + +```bash +agenteye alerts list +agenteye alerts show high-errors +agenteye alerts create high-errors --file alert.json # NAME आवश्यक है (स्थितीय) +agenteye alerts update high-errors --severity critical --yes +agenteye alerts test high-errors --yes # एक परीक्षण अधिसूचना फायर करें +agenteye alerts delete high-errors --yes +``` + +**`incidents`** — अलर्ट घटनाएं, id द्वारा संदर्भित (छोटी ids स्वीकार की जाती हैं)। `show` पूर्ण गतिविधि लॉग प्रिंट करता है — कार्य करने से पहले इसे पढ़ें। + +```bash +agenteye incidents list --state firing # भी: acknowledged, resolved +agenteye incidents count +agenteye incidents show +agenteye incidents ack +agenteye incidents assign you@corp.com # प्राप्तकर्ता एक ऑपरेटर होना चाहिए +agenteye incidents resolve --yes +agenteye incidents open --alert-id --severity critical # एक अलर्ट के विरुद्ध मैनुअल रूप से खोलें +agenteye incidents comment-add "root cause: upstream 5xx" +agenteye incidents comment-list ; agenteye incidents comment-delete +agenteye incidents subscribe ; agenteye incidents unsubscribe ; agenteye incidents subscribers +``` + +### विश्लेषण और सहायक — `query` · `agent` + +**`query`** — सहेजी गई ClickHouse SQL साथ-साथ एक तदर्थ रनर। सहेजी गई क्वेरीज़ **नाम** द्वारा संदर्भित हैं; SQL सर्वर-पक्ष में सत्यापित किया जाता है (केवल SELECT/WITH, कथन टाइमआउट, पंक्ति कैप)। + +```bash +agenteye query schema [TABLE] # विश्लेषण दृश्य का स्तंभ लेआउट +agenteye query run --sql "select count(*) from analytics.events" +agenteye query run errs --arg prod --limit 100 # एक सहेजी गई क्वेरी + एक स्थितीय $1 चलाएं +agenteye query list ; agenteye query show errs +agenteye query create errs --sql @errs.sql --description "errored events (24h)" +agenteye query update errs --sql @errs.sql --yes ; agenteye query delete errs --yes +``` + +**`agent`** — निर्मित डैशबोर्ड सहायक (वही केवल-पढ़ने विश्लेषक जो आप डैशबोर्ड में चैट कर सकते हैं)। चैट एक छोटे chat-id द्वारा संदर्भित हैं (उपसर्ग-हल)। + +```bash +agenteye agent health # क्या सहायक कॉन्फ़िगर/पहुंचा है +agenteye agent models # मॉडल जो आप --model को पास कर सकते हैं (डिफ़ॉल्ट चिह्नित) +agenteye agent ask "which agents errored most in the last day?" # एक चैट शुरू करता है; इसका छोटा id प्रिंट करता है +agenteye agent ask --chat "and which tools did they call?" # उस चैट को जारी रखें +agenteye agent chats ; agenteye agent show +agenteye agent rename --title "error triage" ; agenteye agent delete +``` + +--- + +## निकास कोड + +| कोड | अर्थ | +|---|---| +| 0 | सफलता | +| 1 | अप्रत्याशित त्रुटि (उदाहरण के लिए डैशबोर्ड ने एक 5xx लौटाया) | +| 2 | उपयोग त्रुटि (अमान्य तर्क, अज्ञात कमांड/फ़्लैग, नाम टकराव) | +| 3 | डैशबोर्ड तक नहीं पहुंचा जा सकता | +| 4 | लॉगिन नहीं है या सेशन समाप्त; `agenteye login` चलाएं | +| 5 | प्रमाणित, लेकिन आपके खाते में आवश्यक अनुमति नहीं है (संदेश इसका नाम बताता है) | +| 6 | अनुरोधित संसाधन नहीं मिला (उदाहरण के लिए अज्ञात सेशन या घटना id) | + +ये CLI को स्क्रिप्ट के लिए सुरक्षित बनाते हैं: एक कोडिंग एजेंट एक `4` पर फिर से प्रमाणित करने के लिए प्रॉम्प्ट करने के लिए, या एक `5` को सतह पर लापता अनुमति के लिए शाखा कर सकता है। एक्जिट-कोड-हैंडलिंग पैटर्न और JSON आउटपुट आकार के लिए [एजेंटों के लिए CLI व्यंजन](/hi/agenteye/cli-recipes) देखें। + +--- + +## यह भी देखें + +- **[एजेंटों के लिए CLI व्यंजन](/hi/agenteye/cli-recipes)** — कॉपी-पेस्ट क्वेरी पैटर्न, `jq` एक-लाइनर, `--fields` प्रक्षेपण, निकास-कोड हैंडलिंग, और JSON आउटपुट आकार, कोडिंग एजेंटों के लिए लिखा गया जो CLI को चलाते हैं। +- **[AgentEye CLI कौशल](/hi/agenteye/cli-skill)** — इस CLI को एक स्थापनशील Claude Code / Codex *कौशल* के रूप में पैकेज करें ताकि एक कोडिंग एजेंट सादे-अंग्रेजी अनुरोधों से AgentEye को चलाए। +- **[API कुंजियां](/hi/agenteye/api-keys)** — `keys create --add …` के पीछे अनुमति मॉडल। +- **[AI सहायक](/hi/agenteye/assistant)** — सहायक को सक्षम करना जो `agent ask` बात करता है। \ No newline at end of file diff --git a/docs/hi/agenteye/collector-installation.mdx b/docs/hi/agenteye/collector-installation.mdx new file mode 100644 index 00000000..2f0930b3 --- /dev/null +++ b/docs/hi/agenteye/collector-installation.mdx @@ -0,0 +1,400 @@ +--- +title: "कलेक्टर इंस्टॉलेशन" +description: "AgentEye कलेक्टर इंस्टॉलेशन डॉक्यूमेंटेशन।" +--- + + +`agenteye-collector` डेमॉन गारंटी देता है कि आपके एजेंट्स की टेलीमेट्री AgentEye तक पहुंचे बिना कभी आपके एप्लिकेशन को ब्लॉक किए। आपका कोड लोकल डायरेक्टरी में इवेंट्स लिखता है और आगे बढ़ता है; कलेक्टर वहां से जिम्मेदारी संभालता है, प्रत्येक फाइल को मिलीसेकंड में अपलोड करता है और रीस्टार्ट्स, नेटवर्क आउटेज और ट्रांजिएंट सर्वर एरर्स को सहता है। विफल अपलोड्स को एक्सपोनेंशियल बैकऑफ के साथ रिट्राई किया जाता है, और एक आवधिक रिकवरी स्वीप किसी भी चीज को फिर से कतार में डालता है जो क्रैश या डिप्लॉय के पीछे छूट गई हो। परिणाम टिकाऊ, फायर-एंड-फॉरगेट डिलीवरी है: आपके एजेंट्स पूर्ण गति से चलते रहते हैं जबकि कलेक्टर यह सुनिश्चित करता है कि कोई भी इवेंट ट्रांजिट में खो न जाए। + +तकनीकी रूप से, कलेक्टर एक हल्का डेमॉन है जो `$AGENTEYE_HOME/events/` (डिफॉल्ट: `~/.agenteye/events/`) को देखता है जिसे Python SDK द्वारा लिखी गई `.jsonl` फाइलें ढूंढता है और उन्हें AgentEye सर्वर पर अपलोड करता है। + +> **नाम परिवर्तित:** कलेक्टर कमांड अब **`agenteye-collector`** है (पहले `agenteye` हुआ करता था)। छोटा `agenteye` नाम अब AgentEye CLI को संबंधित है। यदि आप किसी मौजूदा इंस्टॉल को अपग्रेड कर रहे हैं, तो [enterprise-docs/collector-migration.md](/hi/agenteye/collector-migration) देखें। + +--- + +## पूर्वापेक्षाएं + +- आपका `AGENTEYE_TOKEN`: एक GitHub PAT जिसे आप स्वयं जनरेट करते हैं (देखें [enterprise-docs/github-token.md](/hi/agenteye/github-token)) +- सर्वर URL और एक कलेक्टर API कुंजी (देखें [enterprise-docs/api-keys.md](/hi/agenteye/api-keys)) + +--- + +## विकल्प A: बायनरी (अनुशंसित) + +पूर्व-निर्मित स्टेटिक बायनरीज Linux, macOS और Windows (x86_64 और arm64) के लिए उपलब्ध हैं। `agenteye-enterprise/releases` रेपो से अपने प्लेटफॉर्म के लिए बायनरी सीधे नवीनतम `collector/v` रिलीज़ टैग के अंतर्गत डाउनलोड करें। + +उपलब्ध आर्टिफैक्ट नाम: + +| प्लेटफॉर्म | आर्टिफैक्ट | +|---|---| +| Linux x86_64 | `agenteye-collector-linux-x86_64` | +| Linux arm64 | `agenteye-collector-linux-arm64` | +| macOS x86_64 | `agenteye-collector-darwin-x86_64` | +| macOS arm64 | `agenteye-collector-darwin-arm64` | +| Windows x86_64 | `agenteye-collector-windows-x86_64.exe` | +| Windows arm64 | `agenteye-collector-windows-arm64.exe` | + +**`gh` CLI के साथ डाउनलोड करें** (संस्करण बदलें और अपने प्लेटफॉर्म के आर्टिफैक्ट को चुनें): + +```bash +VERSION=0.0.1-beta.13 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "collector/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-collector-linux-x86_64' + +chmod +x agenteye-collector-linux-x86_64 +sudo mv agenteye-collector-linux-x86_64 /usr/local/bin/agenteye-collector +``` + +**या `curl` के साथ:** + +```bash +VERSION=0.0.1-beta.13 +ARTIFACT=agenteye-collector-linux-x86_64 +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + -L "https://github.com/agenteye-enterprise/releases/releases/download/collector%2Fv${VERSION}/${ARTIFACT}" \ + -o agenteye-collector +chmod +x agenteye-collector +sudo mv agenteye-collector /usr/local/bin/agenteye-collector +``` + +--- + +## विकल्प B: Docker + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +docker pull ghcr.io/agenteye-enterprise/collector:beta-latest +``` + +> वर्तमान बीटा बिल्ड्स फ्लोटिंग `:beta-latest` टैग प्रकाशित करते हैं; `:latest` केवल स्थिर रिलीज़ को असाइन किया जाता है। दोहराए जा सकने वाले डिप्लॉयमेंट्स के लिए, `:v0.0.1-beta.13` जैसा पिन किया गया संस्करण टैग पसंद करें। + +**चलाएं:** + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-collector \ + -e AGENTEYE_URL=https://ingest.example.com/events \ + -e AGENTEYE_KEY="$AGENTEYE_KEY" \ + -e AGENTEYE_HOME=/data \ + -v "$HOME/.agenteye:/data" \ + ghcr.io/agenteye-enterprise/collector:beta-latest \ + start +``` + +आधिकारिक इमेज नॉन-रूट यूजर के रूप में चलती है, इसलिए `AGENTEYE_HOME` स्पष्ट रूप से सेट करें और होस्ट स्पूल को इसमें माउंट करें। वॉल्यूम माउंट वही `~/.agenteye/` डायरेक्टरी शेयर करता है जिसमें Python SDK होस्ट पर लिखता है। यदि आपने `AGENTEYE_HOME` कहीं अन्य जगह होस्ट पर पहले से सेट किया है, तो `$HOME/.agenteye` की जगह वह डायरेक्टरी माउंट करें। + +--- + +## कॉन्फ़िगरेशन + +सभी विकल्पों को तीन तरीकों से सेट किया जा सकता है (उच्चतम प्राथमिकता पहली): + +1. CLI फ्लैग: `agenteye-collector start --url https://...` +2. पर्यावरण चर: `AGENTEYE_URL=https://...` +3. कॉन्फ़िग फाइल: `~/.agenteye/config.json` + +### आवश्यक विकल्प + +| विकल्प | CLI फ्लैग | Env var | config.json कुंजी | +|---|---|---|---| +| बैकएंड URL | `--url ` | `AGENTEYE_URL` | `"url"` | +| API कुंजी | `--key ` | `AGENTEYE_KEY` | `"key"` | + +### वैकल्पिक विकल्प (डिफॉल्ट के साथ) + +| विकल्प | CLI फ्लैग | Env var | config.json कुंजी | डिफॉल्ट | +|---|---|---|---|---| +| अधिकतम समवर्ती अपलोड्स | `--max-concurrent-uploads ` | `AGENTEYE_MAX_CONCURRENT_UPLOADS` | `"max_concurrent_uploads"` | `64` | +| स्वीपर इंटरवल (s) | `--sweep-interval ` | `AGENTEYE_SWEEP_INTERVAL` | `"sweep_interval_secs"` | `60` | +| स्वीपर न्यूनतम फाइल आयु (s) | `--sweep-min-age ` | `AGENTEYE_SWEEP_MIN_AGE` | `"sweep_min_age_secs"` | `120` | +| प्रति स्वीप अधिकतम फाइलें | `--sweep-max-files ` | `AGENTEYE_SWEEP_MAX_FILES` | `"sweep_max_files"` | `64` | +| अधिकतम अपलोड प्रयास | `--max-retries ` | `AGENTEYE_MAX_RETRIES` | `"max_retries"` | `5` | +| रिट्राई बेस डिले (ms) | `--retry-base-delay ` | `AGENTEYE_RETRY_BASE_DELAY` | `"retry_base_delay_ms"` | `1000` | + +### mTLS विकल्प (वैकल्पिक) + +उन डिप्लॉयमेंट्स के लिए जिन्हें म्यूचुअल TLS (mTLS) की आवश्यकता होती है, कलेक्टर TLS हैंडशेक के दौरान एक क्लाइंट सर्टिफिकेट प्रस्तुत कर सकता है। जब ये विकल्प सेट नहीं होते हैं, कलेक्टर मानक HTTPS का उपयोग करता है। + +| विकल्प | CLI फ्लैग | Env var | config.json कुंजी | +|---|---|---|---| +| क्लाइंट सर्टिफिकेट (PEM) | `--tls-cert ` | `AGENTEYE_TLS_CERT` | `"tls_cert"` | +| क्लाइंट निजी कुंजी (PEM) | `--tls-key ` | `AGENTEYE_TLS_KEY` | `"tls_key"` | +| कस्टम CA सर्टिफिकेट (PEM) | `--tls-ca ` | `AGENTEYE_TLS_CA` | `"tls_ca"` | + +`--tls-cert` और `--tls-key` को एक साथ सेट किया जाना चाहिए। फाइलें PEM-एनकोडेड होनी चाहिए। + +`--tls-ca` स्वतंत्र है और केवल तभी आवश्यक है जब AgentEye सर्वर एक TLS सर्टिफिकेट प्रस्तुत करता है जिसे सार्वजनिक रूप से विश्वसनीय CA द्वारा जारी नहीं किया गया है (उदाहरण के लिए, यदि आपके पास वास्तविक DNS डोमेन नहीं है तो क्लस्टर-इन-द `cert-manager` जारीकर्ता द्वारा स्व-हस्ताक्षरित)। कलेक्टर आपूर्ति किए गए CA को एक अतिरिक्त ट्रस्ट एंकर के रूप में जोड़ता है; मानक सार्वजनिक रूट्स विश्वसनीय रहते हैं, इसलिए मौजूदा डिप्लॉयमेंट्स प्रभावित नहीं होते हैं। फाइल में एक एकल PEM सर्ट या पूरी चेन हो सकती है (एकाधिक संयोजित PEM ब्लॉक)। + +**अपने एप्लिकेशन पॉड में साइडकार के रूप में कलेक्टर चला रहे हैं?** एंड-टू-एंड EKS पैटर्न के लिए [enterprise-docs/single-pod-deployment.md](/hi/agenteye/single-pod-deployment) देखें: AWS सीक्रेट्स मैनेजर + सीक्रेट्स स्टोर CSI ड्राइवर + IRSA के माध्यम से mTLS बंडल, स्वचालित रोटेशन के साथ। + +Kubernetes में सीक्रेट हैंड-ऑफ पैटर्न के साथ चलाते समय, सर्टिफिकेट सीक्रेट को वॉल्यूम के रूप में माउंट करें और इन पथों को माउंट की गई फाइलों की ओर इशारा करें: + +```yaml +# उदाहरण: कलेक्टर डिप्लॉयमेंट स्निपेट +volumes: + - name: mtls-certs + secret: + secretName: agenteye-collector-mtls +containers: + - name: collector + env: + - name: AGENTEYE_TLS_CERT + value: /etc/agenteye/tls/tls.crt + - name: AGENTEYE_TLS_KEY + value: /etc/agenteye/tls/tls.key + # केवल तब जब सर्वर सर्ट सार्वजनिक रूप से विश्वसनीय नहीं है (उदा. क्लस्टर-इन-द + # स्व-हस्ताक्षरित CA)। समान सीक्रेट आमतौर पर tls.crt/tls.key के साथ ca.crt भी रखता है। + - name: AGENTEYE_TLS_CA + value: /etc/agenteye/tls/ca.crt + volumeMounts: + - name: mtls-certs + mountPath: /etc/agenteye/tls + readOnly: true +``` + +### उदाहरण `~/.agenteye/config.json` + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "max_concurrent_uploads": 16, + "sweep_interval_secs": 30 +} +``` + +mTLS के साथ: + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "tls_cert": "/etc/agenteye/tls/tls.crt", + "tls_key": "/etc/agenteye/tls/tls.key" +} +``` + +mTLS प्लस कस्टम CA के साथ (स्व-हस्ताक्षरित AgentEye सर्वर): + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "tls_cert": "/etc/agenteye/tls/tls.crt", + "tls_key": "/etc/agenteye/tls/tls.key", + "tls_ca": "/etc/agenteye/tls/ca.crt" +} +``` + +यदि `AGENTEYE_HOME` सेट है, तो वह डायरेक्टरी `~/.agenteye` की जगह उपयोग की जाती है। + +--- + +## पहली बार सेटअप + +इंस्टॉल करने के बाद, अपने सर्वर URL और API कुंजी के साथ कलेक्टर को कॉन्फ़िगर करें: + +```bash +mkdir -p ~/.agenteye +cat > ~/.agenteye/config.json <<'EOF' +{ + "url": "https://ingest.example.com/events", + "key": "YOUR_COLLECTOR_KEY" +} +EOF +``` + +> किसी भी डिप्लॉयमेंट के लिए `https` का उपयोग करें जो अविश्वसनीय नेटवर्क पार करता है ताकि इवेंट्स सादे पाठ में न भेजे जाएं। सादा पाठ `http://your-server-host:8080/events` फॉर्म केवल समान होस्ट पर सर्वर के विरुद्ध विशुद्ध रूप से स्थानीय परीक्षण के लिए उपयुक्त है। + +**कनेक्शन परीक्षण करें** (वन-शॉट फ्लश, लंबित इवेंट्स को निकालने के बाद निकलता है): + +```bash +agenteye-collector flush +``` + +`flush` अपनी प्रगति को stdout में रिपोर्ट करता है। जब स्पूल खाली हो तो यह `No pending files.` प्रिंट करता है और `0` को निकलता है। अन्यथा यह प्रति फाइल एक लाइन प्रिंट करता है (`[UPLOADED] ` या `[FAILED] ()`), `Done: / uploaded, failed.` सारांश के बाद। यह `flush` को आपके URL, कुंजी और TLS सेटिंग्स को सही करने से पहले डेमॉन शुरू करने से पहले परीक्षण करने का एक सुविधाजनक वन-शॉट तरीका बनाता है। + +--- + +## डेमॉन के रूप में चलाना + +### सीधे + +```bash +agenteye-collector start +``` + +### कंटेनर / Docker + +जब कलेक्टर और आपका एप्लिकेशन एक कंटेनर साझा करते हैं, तो उन्हें एक प्रक्रिया पर्यवेक्षक के तहत चलाएं। सबसे सरल विकल्प `supervisord` है; यह हर मुख्य डिस्ट्रो में आता है, क्रैश की गई प्रक्रियाओं को रीस्टार्ट करता है, सिग्नल को फॉरवर्ड करता है और सुंदर शटडाउन के लिए प्रतीक्षा करता है। + +**`Dockerfile`:** + +```Dockerfile +FROM python:3.11-slim + +RUN apt-get update && apt-get install -y --no-install-recommends supervisor \ + && rm -rf /var/lib/apt/lists/* + +# आधिकारिक इमेज से agenteye-collector बायनरी खींचें। +# एक विशिष्ट टैग पिन करें (:beta-latest वर्तमान बीटा के लिए, या एक :v टैग); +# :latest केवल स्थिर रिलीज़ के लिए प्रकाशित है। +COPY --from=ghcr.io/agenteye-enterprise/collector:beta-latest \ + /usr/local/bin/agenteye-collector /usr/local/bin/agenteye-collector + +COPY supervisord.conf /etc/supervisor/conf.d/agenteye.conf +COPY my_agent.py /app/my_agent.py + +CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"] +``` + +**`supervisord.conf`:** + +```ini +[supervisord] +nodaemon=true +user=root + +[program:agenteye-collector] +command=/usr/local/bin/agenteye-collector start +autorestart=true +stopwaitsecs=30 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:app] +command=python /app/my_agent.py +autorestart=unexpected +stopwaitsecs=30 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +``` + +क्यों ये सेटिंग्स: + +- agenteye-collector पर `autorestart=true`: किसी भी निकास पर रीस्टार्ट करें (क्रैश, पैनिक, OOM)। +- ऐप पर `autorestart=unexpected`: केवल गैर-शून्य निकास पर रीस्टार्ट करें, इसलिए एक वन-शॉट एजेंट जो `0` को निकलता है लूप नहीं करता। +- `stopwaitsecs=30`: कलेक्टर को SIGTERM पर लंबित अपलोड्स को निकालने के लिए जगह देता है इससे पहले कि supervisord SIGKILL को एस्केलेट करे। +- `stdout_logfile=/dev/stdout`, `*_maxbytes=0`: दोनों प्रोग्रामों के आउटपुट को कंटेनर stdout में स्ट्रीम करें; कंटेनर के अंदर कोई लॉग फाइल नहीं। + +`docker run -e` पर पहले की तरह `AGENTEYE_URL` / `AGENTEYE_KEY` (और कोई भी TLS env vars) पास करें; supervisord पर्यावरण को विरासत में लेता है। + +> **अलग कंटेनर्स?** यदि आप कलेक्टर को इसके अपने कंटेनर के रूप में चलाते हैं (Docker Compose सर्विस, Kubernetes साइडकार, आदि), `supervisord` का उपयोग न करें; कंटेनर रनटाइम की रीस्टार्ट पॉलिसी पहले से ही यह काम करती है। EKS साइडकार पैटर्न के लिए [enterprise-docs/single-pod-deployment.md](/hi/agenteye/single-pod-deployment) देखें। + +**Kubernetes लाइवनेस प्रोब** (चाहे कलेक्टर अकेले चले या supervisord के तहत): + +```yaml +livenessProbe: + exec: + command: ["agenteye-collector", "health"] + initialDelaySeconds: 10 + periodSeconds: 30 +``` + +चलने वाला डेमॉन हर 30 सेकंड में `$AGENTEYE_HOME/health.json` को एक हार्टबीट लिखता है। `agenteye-collector health` वह फाइल पढ़ता है और केवल तब `0` (स्वस्थ) को निकलता है जब हार्टबीट ताजा हो और अपलोड कार्य सामान्य रूप से चल रहे हों; यह `1` (अस्वस्थ) को तब निकलता है जब हार्टबीट 90 सेकंड से पुराना हो (उदाहरण के लिए, डेमॉन बंद हो गया) या जब वॉचर और स्वीपर एक अप्रत्याशित निकास के बाद रीस्टार्ट कर रहे हों। हार्टबीट केवल `start` द्वारा लिखा जाता है, इसलिए वन-शॉट `flush` कमांड के बजाय लंबे-जीवित डेमॉन के विरुद्ध प्रोब चलाएं। + +### systemd (Linux, प्रोडक्शन के लिए अनुशंसित) + +```ini +# /etc/systemd/system/agenteye-collector.service +[Unit] +Description=AgentEye Collector +After=network.target + +[Service] +ExecStart=/usr/local/bin/agenteye-collector start +Restart=on-failure +RestartSec=5 +EnvironmentFile=/etc/agenteye/env + +[Install] +WantedBy=multi-user.target +``` + +`/etc/agenteye/env` बनाएं: + +``` +AGENTEYE_URL=https://ingest.example.com/events +AGENTEYE_KEY=YOUR_COLLECTOR_KEY +``` + +```bash +sudo systemctl daemon-reload +sudo systemctl enable --now agenteye-collector +sudo systemctl status agenteye-collector +``` + +### launchd (macOS) + +```xml + + + + + + Label + ai.befailproof.agenteye-collector + ProgramArguments + + /usr/local/bin/agenteye-collector + start + + EnvironmentVariables + + AGENTEYE_URL + https://ingest.example.com/events + AGENTEYE_KEY + YOUR_COLLECTOR_KEY + + RunAtLoad + + KeepAlive + + + +``` + +```bash +launchctl load ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +``` + +--- + +## कलेक्टर को अपग्रेड करना + +कलेक्टर स्वयं को अपडेट नहीं करता। अपग्रेड करने के लिए: + +- **बायनरी:** नवीनतम `collector/v` रिलीज़ से अपने प्लेटफॉर्म के लिए नई `agenteye-collector--` आर्टिफैक्ट डाउनलोड करें (देखें [विकल्प A](#option-a-binary-recommended)), `/usr/local/bin/agenteye-collector` को बदलें, फिर सर्विस रीस्टार्ट करें (`sudo systemctl restart agenteye-collector`, दोबारा `launchctl load`, या अपने सुपरवाइजर को रीस्टार्ट करें)। +- **Docker:** `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (या एक पिन किया गया `:v` टैग; `:latest` केवल स्थिर रिलीज़ के लिए मौजूद है) और कंटेनर को फिर से बनाएं। + +`AGENTEYE_TOKEN` निजी रिलीज़ रेपो से नई बायनरीज/इमेजेज डाउनलोड करने के लिए आवश्यक है, लेकिन चलने वाले डेमॉन द्वारा **आवश्यक नहीं** है। + +--- + +## सबकमांड्स + +| कमांड | विवरण | +|---|---| +| `agenteye-collector start` | लंबे-जीवित डेमॉन शुरू करें। स्टार्टअप पर यह पिछले रन से बचे हुए किसी भी इवेंट को फ्लश करता है, फिर नई फाइलों को देखता है और उन्हें अपलोड करता है। वॉचर और स्वीपर एक अप्रत्याशित निकास पर स्वचालित रूप से रीस्टार्ट होते हैं, और हर 30 सेकंड में `health.json` को एक हार्टबीट लिखा जाता है। | +| `agenteye-collector flush` | वन-शॉट: सभी लंबित फाइलें अपलोड करें और बाहर निकलें। जब स्पूल खाली हो तो `No pending files.` प्रिंट करें, अन्यथा एक प्रति-फाइल `[UPLOADED]`/`[FAILED]` लॉग और `Done: / uploaded, failed.` सारांश। | +| `agenteye-collector health` | डेमॉन के `health.json` हार्टबीट को पढ़ें। जब ताजा और स्वस्थ हो तो `0` को निकलें; जब हार्टबीट पुराना हो (90s से अधिक पुराना) या कार्य रीस्टार्ट हो रहे हों तो `1` को निकलें। | + +--- + +## डायरेक्टरी लेआउट + +``` +~/.agenteye/ +├── config.json <- वैकल्पिक कॉन्फ़िग फाइल +├── events/ <- SDK द्वारा लिखी गई .jsonl फाइलें, कलेक्टर द्वारा उठाई गई +└── failed/ <- फाइलें जो सभी अपलोड प्रयासों में विफल रहीं +``` + +`failed/` में फाइलें स्वचालित रूप से रिट्राई नहीं की जाती हैं। उन्हें मैनुअली रीकयू करने के लिए, उन्हें `events/` में वापस ले जाएं और `agenteye-collector flush` चलाएं। \ No newline at end of file diff --git a/docs/hi/agenteye/collector-migration.mdx b/docs/hi/agenteye/collector-migration.mdx new file mode 100644 index 00000000..e2a734be --- /dev/null +++ b/docs/hi/agenteye/collector-migration.mdx @@ -0,0 +1,168 @@ +--- +title: "`agenteye-collector` में माइग्रेशन" +description: "AgentEye `agenteye-collector` में माइग्रेशन दस्तावेज़।" +--- + + +माइग्रेशन non-destructive है: इससे कोई डाउनटाइम नहीं होता और कोई डेटा नुकसान नहीं होता, और यह छोटे `agenteye` नाम को [AgentEye CLI](/hi/agenteye/cli) के लिए मुक्त करता है ताकि collector daemon और CLI एक ही मशीन पर coexist कर सकें। + +Collector binary का **नाम `agenteye` से `agenteye-collector` में बदल दिया गया है**। छोटा `agenteye` नाम अब AgentEye CLI को समर्पित है, जो आपके टर्मिनल से sessions, events और evaluations के लिए query करने का एक अलग tool है। + +यह गाइड आपको एक मौजूदा collector install को माइग्रेट करने में मदद करती है। + +--- + +## क्या बदला + +| | पहले | अब | +|---|---|---| +| Command / binary | `agenteye` | `agenteye-collector` | +| Default install path | `/usr/local/bin/agenteye` | `/usr/local/bin/agenteye-collector` | +| Subcommands | `start`, `flush`, `health`, `update` | `start`, `flush`, `health` | +| Self-update (`agenteye update`) | built in | **हटाया गया**: नया binary download करें या नई image pull करें | +| Install script (`install.sh`) | प्रदान किया गया | **हटाया गया**: binary सीधे download करें (देखें [Collector Installation](/hi/agenteye/collector-installation)) | +| `AGENTEYE_TOKEN` | binaries download करने के लिए **और** background update checks के लिए आवश्यक | केवल binaries/images **download** करने के लिए आवश्यक | + +Configuration unchanged है: same `~/.agenteye/config.json`, same `AGENTEYE_URL` / `AGENTEYE_KEY` / `AGENTEYE_HOME` / TLS environment variables, और same `~/.agenteye/events/` spool। **कोई config edits की आवश्यकता नहीं है।** + +> यदि आप renamed binary को पुराने नाम `agenteye` के तहत चलाते हैं, तो यह काम करता है लेकिन stderr पर एक-लाइन deprecation warning प्रिंट करता है जो आपको `agenteye-collector` पर स्विच करने की याद दिलाता है। + +--- + +## शुरू करने से पहले + +- आपका **मौजूदा `agenteye` install चलता रहता है**; upgrade के क्षण कुछ नहीं टूटता। जानबूझकर माइग्रेट करें, फिर पुराने binary को अंत में हटाएं। +- Downtime से बचने के लिए इस क्रम का पालन करें: + 1. नया `agenteye-collector` binary install करें (या नई image pull करें)। + 2. अपनी service definition / health probe / scripts को `agenteye-collector` को कॉल करने के लिए update करें। + 3. Service को reload और restart करें; confirm करें कि यह healthy है। + 4. **केवल तब** पुरानी `/usr/local/bin/agenteye` binary को हटाएं। + +--- + +## 1. नया binary install करें + +अपने platform के लिए artifact download करें (`agenteye-collector-linux-x86_64`, `agenteye-collector-darwin-arm64`, आदि; पूरी सूची के लिए [Collector Installation → Option A](/hi/agenteye/collector-installation#option-a-binary-recommended) देखें) नवीनतम `collector/v` release से और इसे `/usr/local/bin/agenteye-collector` पर रखें। Docker users: `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (या pinned `:v` tag, जो preferred है; `:latest` केवल stable releases के लिए मौजूद है)। + +Verify करें: + +```bash +agenteye-collector --version +``` + +--- + +## 2. अपने deployment को update करें + +### systemd (Linux) + +`/etc/systemd/system/agenteye-collector.service` को edit करें ताकि `ExecStart` नए binary की ओर point करे: + +```ini +[Service] +ExecStart=/usr/local/bin/agenteye-collector start +``` + +फिर reload और restart करें: + +```bash +sudo systemctl daemon-reload +sudo systemctl restart agenteye-collector +sudo systemctl status agenteye-collector +``` + +### launchd (macOS) + +> **Brand rename:** यदि आपकी मौजूदा plist पुराने path पर है +> `~/Library/LaunchAgents/host.exosphere.agenteye-collector.plist`, तो file को +> `ai.befailproof.agenteye-collector.plist` में rename करें और file के अंदर +> `Label` value को भी नए identifier में बदलें reloading से पहले। + +`~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist` में, पहली `ProgramArguments` entry को `/usr/local/bin/agenteye` से `/usr/local/bin/agenteye-collector` में बदलें, फिर reload करें: + +```bash +launchctl unload ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +launchctl load ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +``` + +### supervisord + +अपने `supervisord` program block में, `command` को नए binary पर set करें: + +```ini +[program:agenteye-collector] +command=/usr/local/bin/agenteye-collector start +``` + +फिर `supervisorctl reread && supervisorctl update` करें। + +### Docker / Kubernetes + +नई image pull करें (`ghcr.io/agenteye-enterprise/collector:beta-latest` या pinned `:v`, जो preferred है; `:latest` केवल stable releases के लिए मौजूद है)। Image entrypoint पहले से ही `agenteye-collector` है, तो `start` subcommand के साथ same `docker run` command बिना किसी change के काम करता रहता है। + +**महत्वपूर्ण: health probes को update करें।** यदि आप Kubernetes liveness/readiness probe (या कोई `docker exec`) का उपयोग करते हैं जो binary को name से चलाता है, तो command को `agenteye-collector` में बदलें: + +```yaml +livenessProbe: + exec: + command: ["agenteye-collector", "health"] +``` + +नई image `agenteye` alias ship नहीं करती, इसलिए अभी भी `agenteye` को कॉल करने वाला probe fail होगा। Probe को नई image के साथ same rollout में update करें। + +### Cron / manual scripts + +किसी भी `agenteye start|flush|health` invocations को matching `agenteye-collector start|flush|health` command से replace करें। **किसी भी `agenteye update` cron jobs को delete करें**; वह subcommand अब मौजूद नहीं है (देखें [Upgrades from now on](#upgrades-from-now-on))। + +--- + +## 3. पुरानी binary को हटाएं (अंत में) + +एक बार service `agenteye-collector` पर चल रही है और healthy report कर रही है: + +```bash +sudo rm /usr/local/bin/agenteye +``` + +यह विशेष रूप से महत्वपूर्ण है यदि आप AgentEye CLI का भी उपयोग करते हैं, जो अपना स्वयं का `agenteye` command install करता है; पुरानी collector binary को `/usr/local/bin/agenteye` पर रखना आपके `PATH` पर `agenteye` नाम को ambiguous बना देगा। + +--- + +## अब से upgrades + +Collector अब खुद को update नहीं करता। Upgrade करने के लिए: + +- **Binary:** अपने platform के लिए नया artifact download करें (उदाहरण के लिए `agenteye-collector-linux-x86_64`; पूरी सूची के लिए [Collector Installation → Option A](/hi/agenteye/collector-installation#option-a-binary-recommended) देखें), `/usr/local/bin/agenteye-collector` को replace करें, और service को restart करें। +- **Docker:** `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (या pinned `:v` tag, जो preferred है; `:latest` केवल stable releases के लिए मौजूद है) और container को recreate करें। + +`AGENTEYE_TOKEN` अभी भी private releases repo से download करने के लिए आवश्यक है, लेकिन running daemon को इसकी आवश्यकता नहीं है। + +--- + +## Verify करें + +```bash +agenteye-collector --version # new binary is on PATH +agenteye-collector health # exit 0 = healthy +agenteye-collector flush # forwards any queued events and exits cleanly +``` + +फिर confirm करें कि नई events आपके dashboard में appear हो रही हैं। + +--- + +## Rollback + +माइग्रेशन non-destructive है। यदि आपको rollback करने की आवश्यकता है, तो अपनी service definition को पुरानी `/usr/local/bin/agenteye` binary की ओर वापस point करें (जब तक आपने इसे हटाया न हो) और restart करें। Event spool और config shared हैं और unaffected हैं। + +--- + +## Troubleshooting + +| Symptom | Cause | Fix | +|---|---|---| +| हर run पर `warning: the collector binary is now agenteye-collector …` | आप पुराने `agenteye` नाम के तहत binary को invoke कर रहे हैं | `agenteye-collector` को कॉल करें; service files और scripts को update करें। | +| systemd fails: `.../agenteye: No such file or directory` | आपने `ExecStart` को update करने से पहले पुरानी binary को हटा दिया | `ExecStart=/usr/local/bin/agenteye-collector start` set करें, फिर `sudo systemctl daemon-reload` करें। | +| Image upgrade के बाद Kubernetes pod crash-loops | Liveness probe अभी भी `agenteye` चलाता है | Probe command को `["agenteye-collector", "health"]` में बदलें। | +| `agenteye: command not found`, लेकिन `agenteye-collector` काम करता है | Scripts/aliases अभी भी पुराने नाम को reference करते हैं | उन्हें `agenteye-collector` में update करें। | +| `agenteye` चलाना CLI को शुरू करता है, collector को नहीं | आपके पास AgentEye CLI installed है; यह `agenteye` को own करता है | Daemon के लिए `agenteye-collector` का उपयोग करें और `/usr/local/bin/agenteye` पर कोई leftover पुरानी collector binary को हटाएं। | \ No newline at end of file diff --git a/docs/hi/agenteye/deployment.mdx b/docs/hi/agenteye/deployment.mdx new file mode 100644 index 00000000..b409374c --- /dev/null +++ b/docs/hi/agenteye/deployment.mdx @@ -0,0 +1,245 @@ +--- +title: "तैनाती" +description: "AgentEye तैनाती दस्तावेज़।" +--- + + +यह गाइड AgentEye सर्वर और डैशबोर्ड को उत्पादन में तैनात करने को कवर करती है। + +--- + +## आर्किटेक्चर अवलोकन + +``` + [ AI agent machines ] [ Your infrastructure ] + + Python SDK + | writes JSONL +----------------------+ + v +--->| PostgreSQL 15+ | + agenteye-collector --HTTP--+ | | (relational store) | + | | +----------------------+ + v | + +--------+ | +----------------------+ + | Server |<------+--->| ClickHouse 24+ | + +--------+ | | (events / analytics) | + ^ | +----------------------+ + API | | + | | +----------------------+ + +-----------+ +- - >| Redis 7+ (optional) | + | Dashboard | +----------------------+ + +-----------+ +``` + +- **Server**: Rust HTTP सेवा; ईवेंट बैच प्राप्त करता है, उन्हें ClickHouse में लिखता है, और PostgreSQL में संबंधपरक स्थिति बनाए रखता है। +- **Dashboard**: Next.js वेब ऐप; विशेषता के साथ सर्वर API के माध्यम से पढ़ता और लिखता है। +- **agenteye-collector**: सर्वर होस्ट पर नहीं, एजेंट मशीनों पर तैनात किया जाता है। +- **Postgres 15+**: आवश्यक। (मल्टी-टेनेंट रिलीज़ में 14 से बढ़ाया गया; org-membership स्कीमा एक कॉलम-लिस्ट `ON DELETE SET NULL` विदेशी कुंजी का उपयोग करता है, जो Postgres 15+ है। इस संस्करण को तैनात करने से पहले Postgres को अपग्रेड करें।) OLTP स्थिति संग्रहीत करता है: `api_keys`, `users`, `sessions`, `evaluation_jobs` (कतार), `dashboards`, `saved_queries`, `otp_codes`, प्लस मल्टी-टेनेंट तालिकाएं `orgs`, `org_memberships`, `org_settings`। +- **ClickHouse 24+**: आवश्यक। हर एक अंतर्ग्रहण किए गए ईवेंट के लिए विश्लेषण स्टोर। इंजन: `ReplacingMergeTree`, महीने के आधार पर विभाजित, `(session_id, ts, dedup_key)` द्वारा क्रमित। सर्वर `CLICKHOUSE_URL` के माध्यम से जुड़ता है; बंडल किया गया `deploy/base/clickhouse/` एक प्रदर्शन-ट्यून किए गए सिंगल-नोड कॉन्फ़िगरेशन शिप करता है। **मल्टी-टेनेंट आवश्यकता:** बंडल किया गया कॉन्फ़िग SQL एक्सेस प्रबंधन + `users_without_row_policies_can_read_rows=false` सक्षम करता है ताकि सर्वर एक प्रति संगठन पढ़ने-मात्र ClickHouse उपयोगकर्ता + पंक्ति नीति बना सके (SQL संपादक और AI एजेंट के लिए इंजन-प्रवर्तित अलगाव सीमा)। यदि आप अपनी खुद की ClickHouse कॉन्फ़िगरेशन आपूर्ति करते हैं, तो इन सेटिंग्स को आगे ले जाएं (`deploy/base/clickhouse/configmap.yaml` देखें)। +- **Redis 7+**: *वैकल्पिक* साझा कैश + दर-सीमा बैकएंड। सर्वर और डैशबोर्ड दोनों `REDIS_URL` के माध्यम से जुड़ते हैं। यदि अनुपस्थित है, तो दोनों केवल Postgres-पथों तक पहुंचते हैं। नीचे **Redis (वैकल्पिक कैश)** देखें। + +--- + +## सर्वर + +### इमेज खींचें + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +docker pull ghcr.io/agenteye-enterprise/server:beta-latest +``` + +> वर्तमान निर्माण `beta-latest` के तहत प्रकाशित होते हैं; `latest` केवल स्थिर रिलीज़ को असाइन किया जाता है। उत्पादन के लिए, एक विशिष्ट `:v` टैग पिन करें; [उपलब्ध इमेज टैग](#available-image-tags) देखें। + +### पर्यावरण चर + +| चर | आवश्यक | डिफ़ॉल्ट | विवरण | +|---|---|---|---| +| `DATABASE_URL` | हाँ | कोई नहीं | Postgres DSN। मानक libpq कनेक्शन स्ट्रिंग प्रारूप योजना `postgres://` के साथ। `?sslmode=require` और अन्य libpq पैरामीटर का समर्थन करता है। पासवर्ड में `/`, `+`, या `=` नहीं हो सकते; URL-सुरक्षित पासवर्ड उत्पन्न करने के लिए `openssl rand -hex` का उपयोग करें। | +| `ADMIN_KEY` | नहीं | कोई नहीं | बूटस्ट्रैप एडमिन API कुंजी। हर स्टार्टअप पर सभी अनुमतियों के साथ अपसर्ट किया जाता है। मान को बदलकर और पुनः शुरू करके रोटेट करें। | +| `LISTEN_ADDR` | नहीं | `0.0.0.0:8080` | बाइंड करने के लिए TCP पता | +| `MAX_BODY_BYTES` | नहीं | `134217728` (128 MB) | अधिकतम अनुरोध निकाय आकार | +| `ADMIN_EMAIL` | नहीं | कोई नहीं | बूटस्ट्रैप एडमिन उपयोगकर्ता ईमेल। हर स्टार्टअप पर सभी अनुमतियों के साथ अपसर्ट किया जाता है और संरक्षित चिह्नित किया जाता है: डैशबोर्ड/API के माध्यम से अक्षम नहीं किया जा सकता या अनुमतियां संशोधित नहीं की जा सकती। बूटस्ट्रैप एडमिन को रोटेट करने के लिए, `ADMIN_EMAIL` बदलें और पुनः शुरू करें; नया ईमेल संरक्षित के रूप में अपसर्ट किया जाता है, और पिछला अपनी सुरक्षा रखता है जब तक मैन्युअल रूप से डेटाबेस में साफ़ नहीं किया जाता। | +| `ALLOWED_EMAILS` | नहीं | कोई नहीं (सभी अवरुद्ध) | उपयोगकर्ता निर्माण और लॉगिन के लिए अनुमत ईमेल की अल्पविराम-सीमांकित सूची। सटीक पते (`user@example.com`) और डोमेन वाइल्डकार्ड (`*@example.com`) का समर्थन करता है। यदि अनिर्धारित है, तो कोई उपयोगकर्ता बनाए या लॉगिन नहीं कर सकता। **पहली बार बूट सीड केवल**: पहले बूट पर डिफ़ॉल्ट org की allowlist को बीज देता है; उसके बाद प्रत्येक org का [`//settings`](#operational-settings) पेज सच का स्रोत है और इस env var को बदलने का कोई प्रभाव नहीं है। | +| `SMTP_HOST` | नहीं | कोई नहीं | OTP ईमेल भेजने के लिए SMTP सर्वर होस्टनाम। यदि अनिर्धारित है, तो OTP कोड बजाय stdout में लॉग किए जाते हैं। | +| `SMTP_PORT` | नहीं | `587` | SMTP सर्वर पोर्ट | +| `SMTP_USERNAME` | नहीं | कोई नहीं | SMTP प्रमाणीकरण उपयोगकर्ता नाम | +| `SMTP_PASSWORD` | नहीं | कोई नहीं | SMTP प्रमाणीकरण पासवर्ड | +| `SMTP_FROM` | नहीं | कोई नहीं | OTP ईमेल के लिए प्रेषक ईमेल पता | +| `SMTP_TLS` | नहीं | STARTTLS | STARTTLS का उपयोग किया जाता है जब तक आप स्पष्ट रूप से इसे बंद नहीं करते: `false` या `0` plaintext भेजता है (कोई TLS नहीं); कोई भी अन्य मान — अनिर्धारित सहित — STARTTLS सक्षम करता है। | +| `DASHBOARD_URL` | नहीं | बिल्ट-इन डिफ़ॉल्ट | OTP-ईमेल जादू लिंक और सतर्कता अधिसूचनाओं में घटना जादू-लिंक दोनों बनाने के लिए उपयोग किया जाने वाला डैशबोर्ड मूल। यदि अनिर्धारित है तो यह एक बिल्ट-इन डिफ़ॉल्ट पर वापस आता है (और, केवल OTP के लिए, डैशबोर्ड-व्युत्पन्न अनुरोध मूल पर)। स्प्लिट-डोमेन सेटअप के लिए इसे सेट करें ताकि ईमेल और Slack/घटना दोनों लिंक आपके डैशबोर्ड पर इंगित हों। **ईमेल जादू-लिंक URL** नीचे देखें; अधिकांश ऑपरेटर को इसे सेट करने की आवश्यकता नहीं है। | +| `SESSION_TTL_SECS` | नहीं | `86400` (24 h) | सेकंड में डैशबोर्ड सत्र अवधि। **पहली बार बूट सीड केवल**: पहली तैनाती के बाद [`//settings`](#operational-settings) के माध्यम से प्रति org संपादित करें। | +| `OTP_TTL_SECS` | नहीं | `600` (10 min) | सेकंड में OTP कोड वैधता अवधि। **पहली बार बूट सीड केवल**: पहली तैनाती के बाद [`//settings`](#operational-settings) के माध्यम से प्रति org संपादित करें। | +| `REDIS_URL` | नहीं | कोई नहीं | वैकल्पिक साझा कैश + दर-सीमा बैकएंड, उदाहरण के लिए `redis://redis:6379/0`। जब सेट किया जाता है, तो सर्वर प्रमाणित API-कुंजी लुकअप, डैशबोर्ड के `/models` एकत्रित, सत्र सूची, और env-list पहलू को कैश करता है; यह भी OTP-अनुरोध दर सीमा को Postgres COUNT से Redis INCR तक स्थानांतरित करता है। यदि अनिर्धारित या अपहुंच योग्य है, तो सर्वर कैश के बिना चलता है (OTP सीमा Postgres तक गिरती है, हर दूसरी कैश कॉल सच के स्रोत में गिरती है)। नीचे **Redis (वैकल्पिक कैश)** देखें। | +| `CLICKHOUSE_URL` | **हाँ** | कोई नहीं | ClickHouse उदाहरण का आधार URL, उदाहरण के लिए `http://clickhouse:8123`। सर्वर हर स्टार्टअप पर इस डेटाबेस पर अपनी ईवेंट स्कीमा लागू करता है और यदि यह ClickHouse तक पहुंच नहीं सकता तो बूट करने से इनकार करता है। नीचे **ClickHouse (आवश्यक विश्लेषण स्टोर)** देखें। | +| `CLICKHOUSE_DATABASE` | नहीं | `agenteye` | ClickHouse डेटाबेस (स्कीमा) नाम। सर्वर स्टार्टअप पर इसे बनाता है यदि यह मौजूद नहीं है। | +| `ORG_CH_SECRET` | नहीं (सिंगल-टेनेंट) / **हाँ (मल्टी-org)** | dev डिफ़ॉल्ट | HMAC कुंजी जिससे प्रत्येक संगठन के प्रति-टेनेंट ClickHouse पासवर्ड प्राप्त किए जाते हैं। SQL संपादक और AI एजेंट के `run_query` org के अपने पढ़ने-मात्र ClickHouse उपयोगकर्ता के रूप में निष्पादित होते हैं, जिसकी पंक्ति नीति इंजन में टेनेंट अलगाव को लागू करती है। सिंगल-टेनेंट तैनाती बिल्ट-इन dev डिफ़ॉल्ट पर ठीक बूट करती है; **दूसरा org प्रदान करने से पहले आपको एक मजबूत, स्थिर मान सेट करना होगा**, क्योंकि `agenteye-orgctl org create` CLI बिल्ट-इन dev डिफ़ॉल्ट पर चलने से इनकार करता है। इसे रोटेट करने से हर org का ClickHouse उपयोगकर्ता अगले स्टार्टअप तक अनाथ हो जाता है पुनः-प्रावधान (बूट-समय सामंजस्य स्वचालित रूप से इसे ठीक करता है)। इसे रहस्य रखें और प्रतिकृतियों में अपरिवर्तित रखें। Org प्रावधान स्वयं केवल ऑपरेटर है; नीचे **Organizations (multi-tenancy)** देखें। | +| `DEFAULT_ORG_NAME` | नहीं | `Default` | बिल्ट-इन डिफ़ॉल्ट org के लिए बीज किया गया प्रदर्शन नाम। **पहली बार बूट सीड केवल**, और केवल जब org अभी भी अपनी ताज़ा-प्रवासित सामान्य पहचान रखता है, स्टार्टअप पर लागू, फिर अनदेखा किया जाता है। एक बार जब आप org का नाम बदलते हैं (`agenteye-orgctl org rename`) तो नाम परिवर्तन प्राधिकार है और इस env var का कोई और प्रभाव नहीं है। | +| `DEFAULT_ORG_SLUG` | नहीं | `default` | बिल्ट-इन डिफ़ॉल्ट org के लिए URL स्लग, डैशबोर्ड पथ यह रहता है (`//…`)। `DEFAULT_ORG_NAME` के समान पहली-बूट-केवल / pristine-केवल सिमेंटिक्स। 1-40 लोअरकेस अलфान्यूमेरिक्स होना चाहिए एकल आंतरिक हाइफन के साथ और [आरक्षित शब्द](#organizations-multi-tenancy) नहीं; एक अमान्य मान अनदेखा किया जाता है (org `default` रखता है)। सिंगल-टेनेंट इंस्टॉल को बिना किसी पोस्ट-तैनाती CLI कदम के `/acme` के रूप में प्रस्तुत करने देता है। | +| `RUST_LOG` | नहीं | `info` | लॉग विस्तार (`debug`, `warn`, `error`, `agenteye_server=trace`) | +| `EVALUATOR_ENDPOINT` | नहीं | कोई नहीं | आपकी मूल्यांकनकर्ता सेवा का आधार URL (उदाहरण के लिए `http://evaluator:9000`)। जब अनिर्धारित है तो संपूर्ण मूल्यांकन पाइपलाइन एक नो-ऑप है; कोई कतार पंक्ति नहीं लिखी जाती, कोई कार्यकर्ता नहीं चलते। [मूल्यांकन सूट](/hi/agenteye/evaluation-suite) देखें। | +| `EVALUATOR_TOKEN` | नहीं | कोई नहीं | मूल्यांकनकर्ता के रूप में भेजा गया `Authorization: Bearer `। **मूल्यांकनकर्ता सेवा के साथ कॉन्फ़िगर किए गए समान मान के बराबर होना चाहिए।** केवल वैकल्पिक यदि आपका मूल्यांकनकर्ता कोई टोकन के साथ कॉन्फ़िगर किया गया है। | +| `EVALUATOR_WORKERS` | नहीं | `2` | समवर्तिता: मूल्यांकन भेजने वाले प्रति सर्वर उदाहरण कार्यकर्ता कार्यों की संख्या। क्षैतिज रूप से स्केल किए गए कई सर्वरों में चलाने के लिए सुरक्षित। | +| `EVALUATOR_CLAIM_BATCH` | नहीं | `4` | अधिकतम संख्या में मूल्यांकन जो एक एकल कार्यकर्ता प्रति टिक दावा करता है। बैच **समवर्ती** रूप से भेजे जाते हैं, इसलिए आपके मूल्यांकनकर्ता एंडपॉइंट पर कुल समवर्तिता `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH` है। | +| `EVALUATOR_POLL_IDLE_SECS` | नहीं | `2` | कार्यकर्ता कितने समय तक सो जाता है जब कुछ भी होना नहीं है तो भेजने का प्रयास करने के बीच। | +| `EVALUATOR_POLLING_INTERVAL_SECS` | नहीं | `10` | `GET /evaluate/{id}` पोल के लिए अंतिम फॉलबैक गति (सेकंड) जब मूल्यांकनकर्ता प्रति-प्रतिक्रिया `next_poll_secs` नहीं लौटाता है और `GET /config` से `default_poll_interval_secs` की विज्ञापन नहीं करता है। | +| `EVALUATOR_REQUEST_TIMEOUT_MS` | नहीं | `30000` | मूल्यांकनकर्ता के विरुद्ध प्रति-HTTP-अनुरोध टाइमआउट (मिलीसेकंड)। | +| `EVALUATOR_MAX_ATTEMPTS` | नहीं | `5` | इस कई विफल प्रयासों के बाद एक मूल्यांकन टर्मिनल `error` (या विफलताएं अनुरोध टाइमआउट थीं तो `timeout`) के रूप में रिकॉर्ड किया जाता है। | +| `EVALUATOR_CONFIG_REFRESH_SECS` | नहीं | `300` (5 min) | सर्वर कितनी बार `GET /config` को मूल्यांकनकर्ता से पुनः-प्राप्त करता है। | +| `EVALUATOR_MAX_POLL_DURATION_SECS` | नहीं | `3600` (1 h) | अधिकतम wallclock समय एक सत्र पोलिंग कतार में रह सकता है इससे पहले AgentEye इसे `timeout` के रूप में समाप्त कर देता है। एक मूल्यांकनकर्ता से रक्षा करता है जो `pending` को हमेशा के लिए लौटाता है। | +| `ALERT_WORKERS` | नहीं | `1` | समवर्तिता: प्रति सर्वर उदाहरण सतर्कता नियमों का मूल्यांकन करने वाले कार्यकर्ता कार्यों की संख्या। [सतर्कताएं](/hi/agenteye/alerts) देखें। | +| `ALERT_CLAIM_BATCH` | नहीं | `16` | अधिकतम संख्या में सतर्कताएं जो एक एकल कार्यकर्ता प्रति टिक दावा करता है। | +| `ALERT_POLL_IDLE_SECS` | नहीं | `5` | कतार खाली होने पर सतर्कता कार्यकर्ता कितने समय तक सो जाता है। | +| `ALERT_REQUEST_TIMEOUT_MS` | नहीं | `15000` | प्रति-ट्रिगर मूल्यांकन टाइमआउट (ClickHouse क्वेरीज़ + आउटबाउंड चैनल HTTP)। | +| `ALERT_MAX_ATTEMPTS` | नहीं | `5` | लगातार क्षणिक विफलताएं इससे पहले एक सतर्कता अपने सामान्य गति के बजाय घातीय बैकऑफ पर पुनः-शेड्यूल करती है। | +| `AUDIT_WORKERS` | नहीं | `1` | समवर्तिता: प्रति सर्वर उदाहरण ऑडिट निष्पादित करने वाले कार्यकर्ता कार्यों की संख्या। [ऑडिट्स](/hi/agenteye/audits) देखें। | +| `AUDIT_CLAIM_BATCH` | नहीं | `1` | अधिकतम संख्या में होने वाले ऑडिट जो एक एकल कार्यकर्ता प्रति टिक दावा करता है। एक एजेंटिक जांच एक लंबा लूप है, इसलिए डिफ़ॉल्ट 1 है। | +| `AUDIT_POLL_IDLE_SECS` | नहीं | `30` | कोई ऑडिट होने पर ऑडिट कार्यकर्ता कितने समय तक सो जाता है। | +| `AUDIT_REQUEST_TIMEOUT_MS` | नहीं | `30000` | ClickHouse के विरुद्ध प्रति-नीति-क्वेरी टाइमआउट (मिलीसेकंड)। | +| `AUDIT_LLM_TIMEOUT_MS` | नहीं | `1440000` | AI सहायक सेवा के लिए एजेंटिक जांच कॉल के लिए टाइमआउट। एक पूर्ण एजेंट लूप मिनटों के लिए चलता है; इसे एजेंट के अपने `AGENTEYE_AUDIT_TIMEOUT_MS` से ऊपर रखें ताकि एजेंट सर्वर हार मानने से पहले अपने आंशिक निष्कर्ष लौटाए। | +| `AUDIT_MAX_ATTEMPTS` | नहीं | `5` | लगातार क्षणिक विफलताएं इससे पहले एक ऑडिट अपने सामान्य गति के बजाय घातीय बैकऑफ पर पुनः-शेड्यूल करता है। | +| `AGENTEYE_AGENT_URL` / `AGENTEYE_AGENT_TOKEN` | नहीं | — | ऑडिट की एजेंटिक जांच AI-सहायक `agent` सेवा को कॉल करती है, **सहायक के रूप में एक ही कनेक्शन का पुनः उपयोग** — तो **सर्वर** पर भी ये दोनों सेट करें (बंडल किए गए manifests/compose करते हैं)। दोनों सेट ⇒ ऑडिट AI जांच चलाते हैं; या तो अनिर्धारित ⇒ ऑडिट **केवल-नीति** चलाते हैं (नियतात्मक SQL नीति पास अभी भी चलता है), प्रति-ऑडिट `llm_enabled` झंडे की परवाह किए बिना। एजेंट के पास भी एक LLM कॉन्फ़िगर होना चाहिए — [assistant.md](/hi/agenteye/assistant) देखें। | + +**AI सहायक सेवा — ऑडिट + सैंडबॉक्स सेटिंग्स।** एजेंटिक जांच और इसका इन-पॉड Python सैंडबॉक्स **एजेंट सेवा** पर ट्यून किए जाते हैं (सर्वर पर नहीं), सभी `AGENTEYE_AUDIT_*` प्रीफिक्स पर और सभी वैकल्पिक: + +| चर | डिफ़ॉल्ट | मतलब | +|---|---|---| +| `AGENTEYE_AUDIT_MAX_STEPS` | `200` | प्रति जांच अधिकतम एजेंट मोड़। | +| `AGENTEYE_AUDIT_TIMEOUT_MS` | `1200000` | एक जांच के लिए दीवार-घड़ी (20 min)। सर्वर के `AUDIT_LLM_TIMEOUT_MS` **नीचे** रहना चाहिए। | +| `AGENTEYE_AUDIT_MAX_CONCURRENCY` | `1` | एजेंट पॉड प्रति समवर्ती जांचें (चैट सहायक के बजट से अलग)। | +| `AGENTEYE_AUDIT_SANDBOX_TIMEOUT_MS` / `_MEM_MB` / `_CPU_SECS` / `_OUTPUT_MAX_BYTES` / `_SCRIPT_MAX_BYTES` | `20000` / `768` / `10` / `64000` / `64000` | बुलबुलेरैप सैंडबॉक्स के लिए प्रति-स्क्रिप्ट सीमाएं। | + +**सैंडबॉक्स प्लेटफॉर्म आवश्यकता।** ऑडिट कोड सैंडबॉक्स मॉडल के Python को एक bubblewrap जेल में चलाता है, जिसे **अप्रविष्ट उपयोगकर्ता नेमस्पेस** की आवश्यकता है। एजेंट पॉड को `clone()` झंडों की अनुमति देनी चाहिए — k8s पर `seccompProfile: Unconfined` सेट करें या compose पर `security_opt: [seccomp:unconfined]`। जहां नोड कर्नल अप्रविष्ट उपयोगकर्ता नेमस्पेस को अक्षम करता है (उदाहरण के लिए कुछ GKE COS छवियां), सैंडबॉक्स **प्रीफ्लाइट विफल हो जाता है और ऑडिटर स्वचालित रूप से केवल-SQL में घट जाता है** — कोई त्रुटि नहीं, बस एजेंट के `/health` पर `sandbox_available: false`। + +### चलाएं + +अपने पर्यावरण में `DATABASE_URL` और `CLICKHOUSE_URL` सेट करें (सर्वर ClickHouse के बिना बूट करने से इनकार करता है), फिर उन्हें कंटेनर तक पास करें: + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-server \ + -e DATABASE_URL="$DATABASE_URL" \ + -e CLICKHOUSE_URL="$CLICKHOUSE_URL" \ + -e ADMIN_KEY="$ADMIN_KEY" \ + -p 8080:8080 \ + ghcr.io/agenteye-enterprise/server:beta-latest +``` + +सर्वर स्टार्टअप पर स्वचालित रूप से डेटाबेस प्रवास चलाता है; कोई अलग प्रवास कदम आवश्यक नहीं है। + +### स्वास्थ्य जांच + +``` +GET /health # liveness - हमेशा {"status":"ok"} एक बार प्रक्रिया ऊपर हो जाती है +GET /ready # readiness - 200 जब Postgres + ClickHouse पहुंचने योग्य हों, अन्यथा 503 +``` + +कोई प्रमाणीकरण आवश्यक नहीं है। **liveness** प्रोब के लिए `/health` का उपयोग करें और **readiness** / लोड-बैलेंसर प्रोब के लिए `/ready` का उपयोग करें। `/ready` कठोर निर्भरताओं की जांच करता है जो सर्वर बिना सेवा नहीं कर सकता (Postgres + ClickHouse), तो एक सर्वर जो चल रहा है लेकिन अपने डेटाबेस तक नहीं पहुंच सकता, रोटेशन से बाहर निकाल दिया जाता है और `NotReady` के रूप में दिखाया जाता है; Redis की रिपोर्ट की जाती है लेकिन कभी readiness विफल नहीं करता। बंडल किए गए Kubernetes manifests पर readiness प्रोब पहले से `/ready` पर इंगित करता है और liveness `/health` पर रहता है। पूरी तस्वीर के लिए [enterprise-docs/health-monitoring.md](/hi/agenteye/health-monitoring) देखें, जिसमें Slack के लिए opt-in Kubernetes-मूल पॉड-विफलता सतर्कता शामिल है। + +### ईमेल जादू-लिंक URL + +OTP लॉगिन ईमेल में एक एक-टैप **डैशबोर्ड खोलें** बटन होता है। इसे क्लिक करने से उपयोगकर्ता को `/login?token=&email=
` पर ले जाता है; डैशबोर्ड उस जोड़ी को एक सत्र के लिए विनिमय करता है और ऐप पर पुनः निर्देशित करता है, बिना किसी मैन्युअल कोड पुनः-प्रविष्टि के। सर्वर तीन स्तरों में डैशबोर्ड मूल का समाधान करता है: + +1. **`X-AgentEye-Dashboard-Url` हेडर**: डैशबोर्ड के `/api/auth/otp/request` प्रॉक्सी द्वारा अपने स्वयं के सार्वजनिक मूल से स्वचालित रूप से सेट। एक समान-मूल तैनाती में (सर्वर और डैशबोर्ड एक होस्ट साझा करते हैं एक इनग्रेस के पीछे जो प्रॉक्सी हेडर अग्रेषित करते हैं), **कोई कॉन्फ़िगरेशन आवश्यक नहीं है**। +2. **`DASHBOARD_URL` env var**: यदि आपका डैशबोर्ड सर्वर के OTP अनुरोध एंडपॉइंट से एक भिन्न मूल पर पहुंचने योग्य है (विभाजित `api.example.com` / `app.example.com`), या यदि आपका इनग्रेस डैशबोर्ड पॉड में सार्वजनिक होस्ट को प्रचार नहीं करता है (तो `request.nextUrl.origin` अन्यथा एक वाइल्डकार्ड बाइंड जैसे `0.0.0.0:3000` को हल करेगा)। उदाहरण: `DASHBOARD_URL=https://app.example.com`। +3. **डिफ़ॉल्ट**: `https://app.befailproof.ai`, केवल यदि उपरोक्त में से कोई भी मौजूद नहीं है तो उपयोग किया जाता है। + +हेडर मान सत्यापित किया जाता है: केवल `https://*` और loopback (`http://localhost*`, `http://127.0.0.1*`) मूल स्वीकृत हैं, और वाइल्डकार्ड बाइंड पते (`0.0.0.0`, `[::]`) `https://` स्कीम के साथ भी अस्वीकार किए जाते हैं। कुछ और स्तर 2 तक गिरता है। + +एक चलंत क्लस्टर पर एक-लाइनर के साथ सेट करें; कोई फाइल नहीं, कोई kustomize पुनर्निर्माण नहीं: + +```bash +kubectl set env deployment/server -n agenteye \ + DASHBOARD_URL=https://app.example.com +``` + +यह एक रोलआउट को ट्रिगर करता है; नए पॉड पहले अनुरोध पर मान को उठाते हैं। ध्यान दें कि ओवरराइड केवल Deployment पर रहता है; ओवरले के विरुद्ध `kustomize build | kubectl apply` का एक बाद का समन्वय इसे पोंछ देगा जब तक आप अपने ओवरले के `server-env.yaml` पैच में समान env var नहीं जोड़ते। + +--- + +## डैशबोर्ड + +### इमेज खींचें + +```bash +docker pull ghcr.io/agenteye-enterprise/dashboard:beta-latest +``` + +### पर्यावरण चर + +| चर | आवश्यक | डिफ़ॉल्ट | विवरण | +|---|---|---|---| +| `AGENTEYE_SERVER_URL` | हाँ | कोई नहीं | सर्वर का आधार URL, उदाहरण के लिए `http://localhost:8080` | +| `AGENTEYE_API_KEY` | हाँ | कोई नहीं | API कुंजी डैशबोर्ड सर्वर के लिए प्रमाणीकृत करने के लिए उपयोग करता है। सभी अनुमतियों की आवश्यकता है (एडमिन कुंजी अनुशंसित)। | +| `AE_LOG_LEVEL` | नहीं | `info` | सर्वर-पक्ष लॉग विस्तार: `debug`, `info`, `warn`, `error`। मुद्दों का निदान करते समय अपस्ट्रीम-अनुरोध/प्रतिक्रिया लाइनें और सत्र-सत्यापन ट्रेस देखने के लिए `debug` पर सेट करें। | +| `AE_LOG_JSON` | नहीं | auto | `1` JSON-प्रति-लाइन आउटपुट को मजबूर करता है; `0` मानव-पठनीय आउटपुट को मजबूर करता है। जब अनिर्धारित है, तो `NODE_ENV=production` होने पर JSON स्वचालित रूप से सक्षम होता है। उत्पादन में JSON अनुशंसित है ताकि लॉग `jq` या लॉग एकत्रीकरण के साथ स्पष्ट रूप से पार्स हों। | +| `AE_ANALYTICS_DISABLED` | नहीं | कोई नहीं | डैशबोर्ड के गुमनाम उत्पाद-उपयोग टेलीमेट्री को अक्षम करने के लिए `1`/`true` पर सेट करें। नीचे [Telemetry & privacy](#telemetry--privacy) देखें। | +| `REDIS_URL` | नहीं | कोई नहीं | वैकल्पिक साझा कैश बैकएंड, उदाहरण के लिए `redis://redis:6379/0`। जब सेट किया जाता है, तो डैशबोर्ड प्रतिकृतियों में `validateSession()` परिणाम कैश करता है और latency-एकत्रित / env-list प्रॉक्सी मार्गों के लिए Next.js fetch कैश साझा करता है। Edge-side OTP अनुरोध और सत्यापन दर सीमाएं भी Redis का उपयोग करती हैं जब मौजूद हों (Redis अपहुंच योग्य होने पर खुली विफल; सर्वर-पक्ष सीमा सुरक्षा backstop है)। नीचे **Redis (वैकल्पिक कैश)** देखें। | +| `AGENTEYE_AGENT_URL` | नहीं | कोई नहीं | वैकल्पिक AI-सहायक `agent` सेवा का आधार URL, उदाहरण के लिए `http://agent:9100`। **इसे अनिर्धारित छोड़ें एजेंट को पूरी तरह से छिपाने के लिए**: कोई सहायक बुलबुला डैशबोर्ड में दिखाई नहीं देता। [enterprise-docs/assistant.md](/hi/agenteye/assistant) देखें। | +| `AGENTEYE_AGENT_TOKEN` | नहीं | कोई नहीं | साझा गुप्त डैशबोर्ड `agent` सेवा को प्रस्तुत करता है। एजेंट पर कॉन्फ़िगर किए गए `AGENTEYE_AGENT_TOKEN` से मेल खाना चाहिए। [enterprise-docs/assistant.md](/hi/agenteye/assistant) देखें। | + +### चलाएं + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-dashboard \ + -e AGENTEYE_SERVER_URL="http://your-server-host:8080" \ + -e AGENTEYE_API_KEY="$ADMIN_KEY" \ + -p 3000:3000 \ + ghcr.io/agenteye-enterprise/dashboard:beta-latest +``` + +### टेलीमेट्री और गोपनीयता + +डैशबोर्ड **गुमनाम उत्पाद-उपयोग विश्लेषण** Exosphere की विश्लेषण सेवा (PostHog) को भेजता है: कौन सी डैशबोर्ड पृष्ठ देखी जाती हैं और UI क्रियाओं की एक मुट्ठी जैसे API कुंजी बनाना या सत्र का पुनः मूल्यांकन करना। यह उपयोग संकेत सूचित करता है कि कौन सी विशेषताएं प्राथमिकता दी जाती हैं। + +- **कोई एजेंट, सत्र, या ईवेंट डेटा कभी आपके बुनियादी ढांचे को नहीं छोड़ता है।** केवल डैशबोर्ड UI उपयोग की रिपोर्ट की जाती है। पृष्ठ URL भेजने से पहले पहचानकर्ताओं को छीन लिया जाता है, और ऑपरेटरों को केवल एक अपारदर्शी आंतरिक id द्वारा पहचाना जाता है, कभी ईमेल द्वारा नहीं। +- टेलीमेट्री **डिफ़ॉल्ट रूप से सक्षम है**। इसे पूरी तरह से बंद करने के लिए, डैशबोर्ड कंटेनर पर `AE_ANALYTICS_DISABLED=1` सेट करें और पुनः शुरू करें। +- विश्लेषण डैशबोर्ड के अपने `/ingest` पथ पर भेजे जाते हैं, जो डैशबोर्ड PostHog (`https://us.i.posthog.com`) को रिवर्स-प्रॉक्सी करता है। अनुरोधों को प्रथम-पक्ष रखने का मतलब है ब्राउज़र विज्ञापन-अवरोधक उन्हें नहीं गिराते हैं। **डैशबोर्ड कंटेनर** को PostHog के लिए आउटबाउंड एक्सेस की आवश्यकता है; यदि यह अवरुद्ध है, तो टेलीमेट्री चुप से कुछ नहीं करता है और डैशबोर्ड प्रभावित नहीं होता है। + +--- + +## AI सहायक (वैकल्पिक) + +एक इन-डैशबोर्ड AI सहायक आपकी टीम को उनके एजेंट डेटा के बारे में सादे भाषा में प्रश्न पूछने देता है (सत्रों को सारांशित करना, `/queries` संपादक के लिए SQL का मसौदा तैयार करना, और बचाए गए प्रश्नों को डैशबोर्ड टाइल में बदलना) डैशबोर्ड छोड़े बिना। यह Claude Agent SDK पर एक अलग आंतरिक `agent` कंटेनर के रूप में चलता है जो केवल डैशबोर्ड तक पहुंच सकता है, और **तब तक अक्षम रहता है जब तक आप एक LLM एंडपॉइंट कॉन्फ़िगर नहीं करते**। + +इसे सक्षम करने के लिए आप `agent` सेवा पर सेट करते हैं, एक LLM कनेक्शन (**Portkey** via `PORTKEY_API_KEY` + एक मॉडल-कैटलॉग स्लग `AGENTEYE_AGENT_MODEL=@/`, सीधे Anthropic via `ANTHROPIC_API_KEY`, दूसरा gateway via `ANTHROPIC_BASE_URL`, या Bedrock/Vertex), एक **समर्पित** डेटा कुंजी, और एक साझा `AGENTEYE_AGENT_TOKEN` डैशबोर्ड से मेल खाता है। डैशबोर्ड उपयोगकर्ताओं को अतिरिक्त रूप से `agent:use` अनुमति की आवश्यकता है। + +सहायक की डेटा कुंजी के लिए आप किसी चीज़ को हाथ से टकसाल नहीं करते: एक यादृच्छिक गुप्त चुनें, इसे `AGENTEYE_API_KEY` के रूप में `agent` पर और `AGENT_API_KEY` के रूप में `server` पर सेट करें, और सर्वर स्टार्टअप पर एक निश्चित अनुमति सेट के साथ इसे बीज देता है। इसका डेटा पहुंच केवल-पढ़ने के लिए है (`events:read`, `evaluations:read`, `dashboards:read`, `queries:read`), और यह अतिरिक्त रूप से अनुमोदन-गेटेड लेखन स्कोप धारण करता है (`dashboards:write`, `queries:write`, `queries:run`) इसलिए यह उपयोगकर्ता की ओर से बचाए गए प्रश्नों का मसौदा तैयार कर सकता है और डैशबोर्ड टाइल बना सकता है; सभी SQL अभी भी org के पढ़ने-मात्र ClickHouse भूमिका के माध्यम से चलता है, तो यह क्या सहायक लेख कर सकता है को चौड़ा करता है, डेटा तक पहुंच नहीं है। स्कोप कोड में निश्चित हैं और कॉन्फ़िगरेशन द्वारा चौड़ा नहीं किए जा सकते हैं। वह कुंजी संरक्षित है; इसे API के माध्यम से अक्षम या पुनः उत्पन्न नहीं किया जा सकता, केवल मान बदलकर और पुनः शुरू करके रोटेट किया जा सकता है। कभी इसके लिए admin/dashboard कुंजी का पुनः उपयोग न करें। + +पूर्ण सेटअप, पूर्ण पर्यावरण-चर संदर्भ, टेलीमेट्री विकल्प, और सुरक्षा मॉडल **[enterprise-docs/assistant.md](/hi/agenteye/assistant)** में हैं। + +--- + +## ClickHouse (आवश्यक विश्लेषण स्टोर) + +ClickHouse आपके डैशबोर्ड को उच्च ईवेंट मात्रा पर प्रतिक्रियाशील रखता है और `/queries` SQL संपादक को एक एकल स्टोर में ईवेंट, मूल्यांकन, और सत्रों में शामिल होने देता है। यह हर एक अंतर्ग्रहण किए गए ईवेंट, हर टर्मिनल मूल्यांकन परिणाम, और प्रति-सत्र एकत्रित के लिए आवश्यक प्रामाणिक स्टोर है। PostgreSQL संबंधपरक / परिवर्तनशील-स्थिति तालिकाएं धारण करता है (api_keys, users, otp_codes, evaluation_jobs, dashboards, saved_queries); विश्लेषणात्मक सतह ClickHouse में रहती है ताकि डैशबोर्ड के रोलअप्स और आपके स्वयं के SQL प्रश्न इसे मूल रूप से स्कैन और शामिल कर सकें, बिना क्रॉस-डेटाबेस राउंड-ट्रिप के। सर्वर `CLICKHOUSE_URL` के बिना बूट करने से इनकार करता है। + +### स्कीमा + +तीन ClickHouse ऑब्जेक्ट सर्वर स्टार्टअप पर बनाए जाते हैं, सभी idempotent (`CREATE IF NOT EXISTS`): + +- **`agenteye.events`**: `ReplacingMergeTree(ingested_at)`, `toYYYYMM(ts)` द्वारा विभाजित, `(session_id, ts, dedup_key)` द्वारा क्रमित। नकली इनपुट (कलेक्टर पुनः प्रयास) मर्ज समय पर एक एकल पंक्ति में ढह जाते हैं; सर्वर हर ईवेंट के लिए एक निर्धारक SHA-256 `dedup_key` की गणना करता है इसलिए पुनः प्रयास सुरक्षित हैं। +- **`agenteye.evaluations`**: `ReplacingMergeTree(ingested_at)`, `toYYYYMM(finished_at)` द्वारा विभाजित, `(session_id, finished_at, dedup_key)` द्वारा क्रमित। मूल्यांकनकर्ता पाइपलाइन द्वारा प्रति टर्मिनल मूल्यांकन परिणाम एक बार लिखा गया। `events` के समान dedup-key मॉडल। +- **`agenteye.agent_sessions`**: `agenteye.events` पर एक **VIEW**, भौतिक तालिका नहीं। हर कॉलम व्युत्पन्न है (`started_at = min(ts)`, `last_event_at = max(ts)`, `ended_at = max(if event_type='agent_end', ts, NULL)`, `event_count = count()`, आदि)। कोई प्रति-ईवेंट अपसर्ट और कोई अलग बैकफिल नहीं; दृश्य स्वचालित रूप से जो कुछ भी `events` में प्रतिबिंबित होता है उसे प्रतिबिंबित करता है। + +पुरानी संगतता के लिए बचाए गए प्रश्नों के साथ जो `analytics.evaluations` / `analytics.sessions` का संदर्भ देते हैं, सर्वर भी एक `analytics` ClickHouse डेटाबेस बनाता है `agenteye.*` तालिकाओं के दृश्य के साथ; `analytics.events`, `analytics.evaluations`, `analytics.agent_sessions`, `analytics.sessions` सभी सही तरीके से समाधान करते हैं। + +### कॉन्फ़िगरेशन + +बंडल किए गए docker-compose और `deploy/base/clickhouse/` एक ClickHouse सेवा के साथ AgentEye के कार्य के लिए ट्यून किए गए: + +- 2 GiB अनुरोधित / 4 GiB सीमा मेमोरी शिप किए गए बेस ओवरले में (छोटे POC/staging नोड्स में फिट करने के आकार की); उत्पादन ग्राहकों को ओवरले करना चाहिए — अनुशंसित फर्श 2c / 4Gi अनुरोध, 6c / 8Gi सीमा है। `max_server_memory_usage_to_ram_ratio=0.9` +- 5 GiB मार्क कैश + 8 GiB असंपीड़ित कैश +- `background_pool_size=16`, `background_merges_mutations_concurrency_ratio=2` +- MergeTree: `parts_to_throw_insert=3000`, `parts_to_delay_insert=1500`, `non_replicated_deduplication_window=1000` +- `local_io_method=auto` (समर्थित कर्नेल पर io_uring) +- `fsync_metadata=0`: कम से कम-एक बार अंतर्ग्रहण + ReplacingMergeTree dedup के कारण स्वीकार्य +- `query_log` 30-दिन TTL के साथ सक्षम; `query_thread_log` हटाया गया (उच्च QPS पर महंगा) +- `max_execution_time=30` उपयोगकर्ता-पक्ष प्रश्नों के लिए +- StatefulSet टेम्पलेट पर 100 GiB PVC (ग्राहक ओवरले उत्पादन के लिए एक तेज़ SSD स्टोरेज क्लास को ओवरराइड करना चाहिए) + +### बैकअप + +आपका संपूर्ण डेटासेट रात भर एक एकल पुनर्स्थापन योग्य संग्रह में कैप्चर किया जाता है, इसलिए एक क्लस्टर या स्टोरेज नुकसान पुनर्प्राप्त होता है। ClickHouse स्वचालित रूप से दैनिक `agenteye-backup` CronJob द्वारा बैक किया जाता है, जो एक पास में PostgreSQL और ClickHouse दोनों को डंप करता है। ClickHouse इसके HTTP API पर पढ़ा जाता है: `agenteye.events` और `agenteye.evaluations` ClickHouse-मूल प्रारूप में डंप किए जाते हैं (दृश्य और पंक्ति नीतियां सर्वर द्वारा स्टार्टअप पर पुनः बनाई जाती हैं, इसलिए तालिका डेटा पूरी तस्वीर है) और Postgres डंप के साथ एक एकल संपीड़ित संग्रह में बंडल किया जाता है आपके ऑब्जेक्ट स्टोरेज में अपलोड किया गया। + +गंतव्य बाल्टी और क्लाउड क्रेडेंशियल ओवरले के अनुसार कॉन्फ़िगर किए जा \ No newline at end of file diff --git a/docs/hi/agenteye/evaluation-suite.mdx b/docs/hi/agenteye/evaluation-suite.mdx new file mode 100644 index 00000000..a2b78af7 --- /dev/null +++ b/docs/hi/agenteye/evaluation-suite.mdx @@ -0,0 +1,356 @@ +# मूल्यांकन सूट + +AgentEye पूर्ण किए गए एजेंट सेशन को पूरी इवेंट ट्रांसक्रिप्ट को +**एकल ग्राहक-स्वामित्व वाली मूल्यांकनकर्ता सेवा** के लिए POST करके स्कोर करता है। मूल्यांकनकर्ता इनलाइन स्कोर लौटाता है या AgentEye के पोल करने के लिए एक `job_id` वापस कर देता है। परिणाम संग्रहीत किए जाते हैं और डैशबोर्ड में दिखाए जाते हैं। + +यह गाइड निम्नलिखित को कवर करती है: + +1. सेशन पूर्णता की पहचान कैसे की जाती है। +2. मूल्यांकनकर्ता को लागू करना चाहिए HTTP अनुबंध। +3. AgentEye सर्वर को कॉन्फ़िगर करना। +4. परिणाम देखना। +5. समस्या निवारण। + +Python हेल्पर के लिए जो आपके लिए अनुबंध को लागू करता है, देखें +[PyPI पर `agenteye-evaluator` पैकेज](https://pypi.org/project/agenteye-evaluator/)। + +--- + +## यह कैसे काम करता है + +```text +ingest /events ──▶ AgentEye ──── POST /evaluate ────▶ Evaluator service + (agent_end) server ◀──── done | pending ──── + │ + │ GET /evaluate/{job_id} ─────▶ + │ ◀──── done ────────────── + ▼ + evaluations (terminal results) +``` + +जब AgentEye SDK किसी सेशन के लिए एक `agent_end` इवेंट उत्सर्जित करता है, तो सर्वर एक मूल्यांकन शेड्यूल करता है। फिर यह पूरी इवेंट ट्रांसक्रिप्ट को आपकी मूल्यांकनकर्ता सेवा के लिए POST करता है, जो या तो: + +- **परिणाम को इनलाइन लौटा सकता है** `{"status":"done", "scores":{...}, "reasoning":{...}, "summary":"..."}` के साथ। परिणाम सेशन की मूल्यांकन टाइमलाइन में जोड़ा जाता है। `reasoning` और `summary` वैकल्पिक हैं। +- **स्थगित** `{"status":"pending", "job_id":"abc-123"}` के साथ। AgentEye तब `GET {EVALUATOR_ENDPOINT}/evaluate/abc-123` को कॉल करता है जब तक आपका मूल्यांकनकर्ता `{"status":"done", ...}` या `{"status":"error", "error":"..."}` न लौटाए। + + पोलिंग की गति प्रति-जॉब है: एक `pending` प्रतिक्रिया में `next_poll_secs` शामिल हो सकता है; अन्यथा AgentEye `GET /config` से `default_poll_interval_secs` मान का उपयोग करता है; अन्यथा सर्वर `EVALUATOR_POLLING_INTERVAL_SECS` (डिफ़ॉल्ट 10s) पर वापस गिरता है। सभी मान [1s, 1h] तक सीमित हैं। + +सेशन जो कभी `agent_end` उत्सर्जित नहीं करते (उदाहरण के लिए, एक क्रैश एजेंट प्रक्रिया) भी उठाए जा सकते हैं: मूल्यांकनकर्ता का `GET /config` `{"inactivity_timeout_secs": 1800}` लौटा सकता है, और AgentEye किसी भी सेशन का मूल्यांकन करेगा जो उतने समय के लिए निष्क्रिय रहा है। इस फॉलबैक को अक्षम करने के लिए फ़ील्ड को `null` पर सेट करें या इसे छोड़ दें। + +`EVALUATOR_ENDPOINT` अनसेट होने पर पाइपलाइन पूरी तरह से no-op है। + +एक सेशन समय के साथ **कई टर्मिनल मूल्यांकन जमा कर सकता है**: प्रत्येक `agent_end` इवेंट (और डैशबोर्ड से प्रत्येक मैनुअल पुनः-मूल्यांकन) एक नई मूल्यांकन पंक्ति जोड़ता है। यह एक पुनः शुरू किए गए कथोपकथन का मूल्यांकन करने का समर्थित तरीका है: एक उपयोगकर्ता एक एजेंट को समाप्त करता है, बाद में वापस आता है, अधिक इवेंट भेजता है, एजेंट को फिर से समाप्त करता है, और एक दूसरा मूल्यांकन पूरी अपडेट की गई ट्रांसक्रिप्ट के विरुद्ध चलता है। डैशबोर्ड सबसे हाल के मूल्यांकन को हेडलाइन के रूप में और पूर्व मूल्यांकन को एक संक्षिप्त टाइमलाइन के रूप में प्रदर्शित करता है। जब एक मूल्यांकन एक सेशन के लिए चल रहा है, तो उस सेशन के लिए अतिरिक्त `agent_end` इवेंट को अनदेखा किया जाता है; चलने वाला मूल्यांकन पूरा होने के बाद अगला एक सामान्य तरीके से एक नया मूल्यांकन कतार में डालेगा। + +निष्क्रियता फॉलबैक पुनः शुरू किए गए सेशन पर भी फिर से जुड़ता है: यदि एक पूर्व टर्मिनल मूल्यांकन के बाद नए इवेंट आते हैं और सेशन तब `inactivity_timeout_secs` को पार करके निष्क्रिय हो जाता है, तो एक नया मूल्यांकन कतार में डाला जाता है। + +क्षणिक विफलताएं (5xx, 429, टाइमआउट, नेटवर्क त्रुटियां) `EVALUATOR_MAX_ATTEMPTS` तक घातीय बैकऑफ के साथ पुनः प्रयास की जाती हैं; 4xx प्रतिक्रियाएं टर्मिनल होती हैं। AgentEye को कई क्षैतिज रूप से स्केल किए गए सर्वर इंस्टेंस के साथ चलाना सुरक्षित है; कार्य विभाजित किया जाता है ताकि एक ही सेशन को कभी दो बार एक साथ भेजा न जाए। + +--- + +## HTTP अनुबंध + +प्रत्येक प्रमाणित रूट **बियरर टोकन प्रमाणीकरण** का उपयोग करता है। दोनों पक्षों पर समान मान को कॉन्फ़िगर किया जाना चाहिए: + +- AgentEye सर्वर: env var `EVALUATOR_TOKEN` +- मूल्यांकनकर्ता सेवा: समान तरीके से कॉन्फ़िगर किया गया (SDK `agenteye-evaluator` सम्मेलन के अनुसार `EVALUATOR_TOKEN` पढ़ता है) + +यदि `EVALUATOR_TOKEN` अनसेट है, तो सर्वर कोई `Authorization` हेडर नहीं भेजता है; मूल्यांकनकर्ता तब अनाम अनुरोधों को स्वीकार कर सकता है, जो आंतरिक-केवल नेटवर्क के लिए ठीक है लेकिन सार्वजनिक इंटरनेट पर हतोत्साहित है। + +### मूल्यांकनकर्ता को सेवा देना चाहिए के रूट + +| रूट | बॉडी / पैरामीटर | प्रतिक्रिया | +|---|---|---| +| `GET /health` | कोई नहीं | `{"status":"ok"}` (खुला, कोई प्रमाणीकरण नहीं) | +| `GET /config` | कोई नहीं | `{"inactivity_timeout_secs": \| null, "default_poll_interval_secs": \| omitted}` | +| `POST /evaluate` | `EvalRequest` JSON | `{"status":"done", ...}` या `{"status":"pending", "job_id":"..."}` | +| `GET /evaluate/{id}` | कोई नहीं | `/evaluate` जैसी ही प्रतिक्रिया आकार | + +### सर्वर द्वारा भेजा गया `EvalRequest` बॉडी + +```json +{ + "schema_version": "1", + "session_id": "session-abc123", + "agent_id": "planner", + "environment": "production", + "started_at": "2026-05-10T12:00:00Z", + "ended_at": "2026-05-10T12:05:00Z", + "events": [ + { "id": 1234, "ts": "...", "event_type": "agent_start", "payload": { ... } }, + ... + ] +} +``` + +### प्रतिक्रिया आकार + +**सिंक (पूर्ण):** + +```json +{ + "status": "done", + "scores": { "helpfulness": 0.85, "tool_efficiency": 0.6 }, + "reasoning": { + "helpfulness": "answered the question directly with citations", + "tool_efficiency": "called list_files three times when one would have done" + }, + "summary": "strong answer quality, weak tool selection" +} +``` + +`reasoning` (एक प्रति-स्कोर न्यायसंगत नक्शा) और `summary` (एक समग्र एक-पैराग्राफ आख्यान) दोनों वैकल्पिक हैं। `reasoning` में कुंजियाँ `scores` में कुंजियों को प्रतिबिंबित करनी चाहिए; डैशबोर्ड प्रत्येक प्रविष्टि को इसके स्कोर बार के नीचे प्रस्तुत करता है। पुरानी मूल्यांकनकर्ता जो केवल `scores` लौटाते हैं वे अपरिवर्तित काम करना जारी रखते हैं; `reasoning` और `summary` बस null के रूप में पढ़े जाते हैं और संबंधित UI सामर्थ्य छोड़ दी जाती हैं। + +**अतुल्यकालिक (स्थगित):** + +```json +{ "status": "pending", "job_id": "abc-123", "next_poll_secs": 30 } +``` + +`next_poll_secs` वैकल्पिक है; यदि छोड़ा जाता है तो सर्वर `/config` से मूल्यांकनकर्ता के `default_poll_interval_secs` पर वापस गिरता है, फिर अपने `EVALUATOR_POLLING_INTERVAL_SECS` env var पर। + +**टर्मिनल मूल्यांकनकर्ता-पक्ष त्रुटि:** + +```json +{ "status": "error", "error": "model service unavailable" } +``` + +सर्वर किसी भी अन्य 2xx बॉडी को प्रोटोकॉल त्रुटि के रूप में मानता है और सेशन के लिए एक टर्मिनल `error` रिकॉर्ड करता है। + +--- + +## SDK के साथ मूल्यांकनकर्ता लिखना + +`agenteye-evaluator` Python पैकेज आपको एक टाइप किया हुआ FastAPI +रैपर देता है जो ऊपर HTTP अनुबंध को लागू करता है। PyPI से इसे इंस्टॉल करें: + +```bash +pip install agenteye-evaluator +``` + +न्यूनतम व्यवहार्य मूल्यांकनकर्ता: + +```python +import os +from agenteye_evaluator import Evaluator, EvalRequest, EvalResponse + +app = Evaluator(token=os.environ["EVALUATOR_TOKEN"]) + +@app.evaluator +def run(req: EvalRequest) -> EvalResponse: + # Inspect req.events (the full session transcript) and return scores. + tool_calls = sum(1 for e in req.events if e.event_type == "tool_use") + return EvalResponse( + scores={"tool_calls": float(tool_calls)}, + reasoning={"tool_calls": f"{tool_calls} tool invocations in the transcript"}, + summary="tight tool loop" if tool_calls < 5 else "agent looped on tools", + ) +``` + +`app` इंस्टेंस ASGI-कॉल योग्य है, इसलिए `uvicorn module:app` इसे चलाता है। + +मूल्यांकनकर्ता के लिए जो महंगे कार्य को स्थगित करने की आवश्यकता है, इसके बजाय `JobPending` लौटाएं और एक `@app.job_lookup` हैंडलर पंजीकृत करें; AgentEye सर्वर `GET /evaluate/{job_id}` को पोल करता है जब तक आप एक टर्मिनल स्थिति न लौटाएं या `EVALUATOR_MAX_POLL_DURATION_SECS` कैप (डिफ़ॉल्ट 1 h) समाप्त न हो जाए। + +पूर्ण API संदर्भ, अतुल्यकालिक पैटर्न, और इवेंट स्कीमा: `agenteye-evaluator` README प्रत्येक रिलीज़ टारबॉल के अंदर +[agenteye-enterprise रिलीज़ पृष्ठ](https://github.com/agenteye-enterprise/releases) पर भेज दिया जाता है, या आप इसे पैकेज के PyPI पृष्ठ पर पढ़ सकते हैं। + +--- + +## Kubernetes पर मूल्यांकनकर्ता चलाना + +मूल्यांकनकर्ता **आपकी सेवा** है: AgentEye कोई डिफ़ॉल्ट मूल्यांकनकर्ता कंटेनर शिप नहीं करता है। रिलीज़ में `deploy/examples/evaluator/` के तहत संदर्भ Kubernetes मैनिफ़ेस्ट शामिल हैं जिन्हें आप अपनी इमेज और एक साझा बियरर टोकन को स्वैप करने के बाद यथावत लागू कर सकते हैं। + +### 1. अपने मूल्यांकनकर्ता को कंटेनरीकृत करें + +आपके मूल्यांकनकर्ता के लिए एक न्यूनतम Dockerfile: + +```dockerfile +FROM python:3.12-slim +WORKDIR /app +RUN pip install --no-cache-dir agenteye-evaluator uvicorn +COPY my_evaluator.py . +RUN useradd --uid 10001 --create-home --shell /usr/sbin/nologin evaluator \ + && chown -R evaluator:evaluator /app +USER evaluator +EXPOSE 9000 +CMD ["uvicorn", "my_evaluator:app", "--host", "0.0.0.0", "--port", "9000"] +``` + +`runAsNonRoot` (UID 10001) कंटेनर को Pod Security प्रतिबंधित प्रोफ़ाइल के साथ संगत रखता है। + +### 2. साझा बियरर टोकन बनाएं + +```bash +kubectl -n agenteye create secret generic evaluator-token \ + --from-literal=token="$(openssl rand -hex 32)" +``` + +AgentEye सर्वर पर समान मान को `EVALUATOR_TOKEN` के रूप में उपयोग करें। सर्वर हर अनुरोध पर `Authorization: Bearer ` भेजता है; SDK `hmac.compare_digest` का उपयोग करता है और HTTP 401 के साथ मेल खाने से इनकार करता है। + +### 3. उदाहरण मैनिफ़ेस्ट लागू करें + +```bash +# Edit deploy/examples/evaluator/deployment.yaml first to point +# `image:` at your registry, then: +kubectl apply -k deploy/examples/evaluator/ +``` + +उदाहरण में शामिल हैं: + +- `runAsNonRoot`, पढ़ने के लिए केवल रूट फ़ाइलसिस्टम, सभी क्षमताएं छोड़े गए, `/health` पर जीवित + तैयारी के साथ 2-प्रतिकृति तैनाती +- पोर्ट 9000 पर ClusterIP सेवा +- एक `secret.example.yaml` टेम्पलेट (जानबूझकर Kustomization से बाहर रखा गया; वास्तविक गुप्त आउट-ऑफ-बैंड बनाएं ताकि कोई टोकन git में न पड़े) + +### 4. AgentEye को इसके साथ जोड़ें + +AgentEye सर्वर पर, सेट करें: + +```bash +EVALUATOR_ENDPOINT=http://evaluator:9000 +EVALUATOR_TOKEN= +``` + +सर्वर सभी मूल्यांकनकर्ता pods में `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH` समवर्ती अनुरोधों को प्रशंसक करता है (डिफ़ॉल्ट: `2 × 4 = 8`)। इन सर्वर-पक्ष नॉब्स के साथ संगति में `replicas` और प्रति-pod संसाधन सीमाएं स्केल करें। + +### सत्यापन + +```bash +kubectl -n agenteye port-forward svc/evaluator 9000:9000 +curl -s http://localhost:9000/health # → {"status":"ok"} +``` + +एजेंट समाप्त-से-अंत तक चलने के बाद, AgentEye सर्वर पर `GET /evaluations` को `status: "done"` और आपके मूल्यांकनकर्ता द्वारा उत्पादित स्कोर के साथ एक पंक्ति लौटानी चाहिए। + +--- + +## AgentEye सर्वर को कॉन्फ़िगर करना + +सर्वर प्रक्रिया पर सेट करें: + +| Env var | अर्थ | +|---|---| +| `EVALUATOR_ENDPOINT` | आपके मूल्यांकनकर्ता का आधार URL (`http://evaluator:9000`)। Unset = पाइपलाइन अक्षम। | +| `EVALUATOR_TOKEN` | बियरर टोकन। मूल्यांकनकर्ता सेवा को कॉन्फ़िगर किए गए मान के बराबर होना चाहिए। | +| `EVALUATOR_WORKERS` | सर्वर इंस्टेंस प्रति कार्यकर्ता कार्य (डिफ़ॉल्ट 2)। | +| `EVALUATOR_CLAIM_BATCH` | प्रति कार्यकर्ता टिक पंक्तियां दावी की गई (डिफ़ॉल्ट 4)। बैच को **समवर्ती** रूप से संसाधित किया जाता है; आपके मूल्यांकनकर्ता endpoint पर प्रभावी समवर्तिता `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH` है। | +| `EVALUATOR_POLL_IDLE_SECS` | जब कोई मूल्यांकन होने वाला नहीं है तो कार्यकर्ता को डिस्पैच प्रयास के बीच कितना सोना चाहिए (डिफ़ॉल्ट 2s)। | +| `EVALUATOR_POLLING_INTERVAL_SECS` | `GET /evaluate/{id}` गति के लिए अंतिम फॉलबैक जब न तो प्रति-प्रतिक्रिया `next_poll_secs` और न ही मूल्यांकनकर्ता का `default_poll_interval_secs` सेट हो (डिफ़ॉल्ट 10s)। | +| `EVALUATOR_REQUEST_TIMEOUT_MS` | प्रति-अनुरोध टाइमआउट (डिफ़ॉल्ट 30000)। | +| `EVALUATOR_MAX_ATTEMPTS` | इस कई क्षणिक विफलताओं के बाद परिणाम टर्मिनल `error` के रूप में दर्ज किया जाता है (डिफ़ॉल्ट 5)। | +| `EVALUATOR_CONFIG_REFRESH_SECS` | `GET /config` गति (डिफ़ॉल्ट 300)। | +| `EVALUATOR_MAX_POLL_DURATION_SECS` | अधिकतम wallclock समय एक सेशन पोलिंग कतार में रह सकता है इससे पहले कि यह `timeout` के रूप में समाप्त हो (डिफ़ॉल्ट 3600s)। एक मूल्यांकनकर्ता को हमेशा `pending` लौटाना जारी रखने से बचाता है। | + +पूरे उदाहरण में स्वचालित स्कोरिंग को चालू करने के लिए, दोनों कुंजी सेट के साथ `agenteye-evaluator` Secret प्रदान करें। बंडल किए गए Kubernetes मैनिफ़ेस्ट पर, सर्वर इस वैकल्पिक Secret से `EVALUATOR_ENDPOINT` और `EVALUATOR_TOKEN` पढ़ता है। इसे अपने संगठन की मानक गुप्त-प्रबंधन प्रक्रिया के माध्यम से बनाएं, फिर परिवर्तन को उठाने के लिए सर्वर Deployment को पुनः शुरू करें। + +ऊपर दिए गए ट्यूनिंग नॉब्स डिफ़ॉल्ट रूप से वायर्ड नहीं हैं; यदि आपको डिफ़ॉल्ट को ओवरराइड करने की आवश्यकता है तो अपने Deployment मैनिफ़ेस्ट में सर्वर कंटेनर पर संबंधित पर्यावरण चर को उजागर करें। + +पूर्ण env var तालिका के लिए [deployment.md](/hi/agenteye/deployment) देखें। + +--- + +## API संदर्भ + +| विधि | पथ | आवश्यक अनुमति | उद्देश्य | +|---|---|---|---| +| `GET` | `/evaluations` | `evaluations:read` | टर्मिनल परिणाम क्वेरी करें। `session_id`, `agent_id`, `environment`, `status` (`done`/`error`/`timeout`), `ts_from`, `ts_to`, `cursor`, `limit`, `score_filters`, `latest_per_session` का समर्थन करता है। `limit` डिफ़ॉल्ट रूप से 50 है और 200 पर सीमित है (ध्यान दें कि यह `/events` से भिन्न है, जो 1000 पर सीमित है)। `environment` अल्पविराम-अलग सूची (उदाहरण के लिए `environment=prod,staging`) स्वीकार करता है; एकल मान अभी भी काम करते हैं। `latest_per_session=true` के साथ प्रतिक्रिया में प्रति `session_id` सबसे अधिक एक पंक्ति होती है (`completed_at` के अनुसार सबसे हाल की) जिसका उपयोग सेशन-सूची पृष्ठ द्वारा सेशन की मूल्यांकन टाइमलाइन को इसकी वर्तमान हेडलाइन में संक्षिप्त करने के लिए किया जाता है। डिफ़ॉल्ट false है (पूरा इतिहास लौटाता है)। | +| `GET` | `/evaluations/aggregate` | `evaluations:read` | एक फ़िल्टर किए गए स्लाइस के लिए रोल-अप मूल्यांकन स्वास्थ्य: कुल गणना, done/error/timeout ब्रेकडाउन, प्रति-स्कोर-कुंजी सांख्यिकी (मनमाने ढंग से `scores` कुंजियों पर गणना/औसत/न्यूनतम/अधिकतम/p50), और एक समय-बकेटेड टाइमलाइन। `/evaluations` के रूप में समान फ़िल्टर पैरामीटर स्वीकार करता है प्लस `featured_keys` (ट्रेंड करने के लिए स्कोर कुंजियों की CSV) और `latest_per_session`। डैशबोर्ड सुविधा को शक्ति देता है; मेट्रिक्स पूरे मेल खाने वाले सेट पर सटीक हैं, नमूना नहीं। | +| `GET` | `/evaluations/environments` | `evaluations:read` | `evaluations` तालिका से विशिष्ट environment मान। मूल्यांकन-पठनीय डेटा के दायरे में फ़िल्टर ड्रॉपडाउन भरने के लिए उपयोग किया जाता है। | +| `GET` | `/evaluation-jobs` | `evaluations:read` | इन-फ्लाइट मूल्यांकन में दृश्यमानता। `status` (`pending`/`polling`) द्वारा फ़िल्टर करें। | +| `GET` | `/events` | `events:read` | सेशन के raw events स्ट्रीम करें। `session_id`, `agent_id`, `event_type` (CSV), `environment` (CSV), `ts_from`, `ts_to`, `cursor`, `limit`, और `order` का समर्थन करता है। `order` `desc` (newest-first, डिफ़ॉल्ट) या `asc` (oldest-first) है; एक अस्पष्ट मान `desc` पर वापस गिरता है। प्रतिक्रिया के `next_cursor` (एक event id) के माध्यम से कर्सर-पैगिनेट करें: अगला पृष्ठ प्राप्त करने के लिए इसे `cursor` के रूप में वापस पास करें; `asc` के साथ अगला पृष्ठ उस id के बाद की events है, `desc` के साथ इससे पहले की events है। `limit` डिफ़ॉल्ट रूप से 50 है और 1000 पर सीमित है। | +| `GET` | `/sessions/:session_id/export` | `events:read` | `session-.json` नामित डाउनलोड करने योग्य संलग्नक के रूप में सेवा की गई सटीक JSON बॉडी लौटाता है जो मूल्यांकनकर्ता को प्राप्त होगी। ऑफ़लाइन परीक्षण के लिए `agenteye-evaluator` के माध्यम से उत्पादन सेशन को पुनः चलाना उपयोगी है। बाइट वह हैं जो मूल्यांकनकर्ता पाइपलाइन भेजता है। | +| `POST` | `/sessions/:session_id/re-evaluate` | `evaluations:trigger` | सेशन के लिए एक नया मूल्यांकन कतार में डालें; चाहे कोई पूर्व मूल्यांकन मौजूद हो या नहीं। नया परिणाम सेशन की मूल्यांकन टाइमलाइन में **जोड़ा जाता है** पिछले एक को ओवरराइट करने के बजाय, इसलिए पिछले स्कोर इतिहास के रूप में दृश्यमान रहते हैं। कतार पर `202` लौटाता है, अज्ञात सेशन के लिए `404`, यदि मूल्यांकन पहले से ही चल रहा है तो `409`। एक नए मूल्यांकनकर्ता को तैनात करने के बाद, या सेशन के लिए जो कभी `agent_end` उत्सर्जित नहीं करते, इसका उपयोग करें। | + +### स्कोर रेंज द्वारा फ़िल्टर करना: `score_filters` + +`GET /evaluations` एक वैकल्पिक `score_filters` पैरामीटर स्वीकार करता है जो `scores` ऑब्जेक्ट के अंदर संख्यात्मक मान द्वारा परिणामों को सीमित करता है। पैरामीटर `key:min..max` प्रविष्टियों की अल्पविराम-अलग सूची है; या तो बाउंड छोड़ा जा सकता है। कई प्रविष्टियां तार्किक AND के साथ संयोजित होती हैं। जहां नामित कुंजी अनुपस्थित है या गैर-संख्यात्मक है वहां पंक्तियों को बाहर रखा जाता है। एक अनुरोध में सबसे अधिक 20 फ़िल्टर प्रविष्टियां हो सकती हैं; उससे अधिक HTTP 400 लौटाता है। + +उदाहरण: +```text +# helpfulness in [0.5, 0.8] +GET /evaluations?score_filters=helpfulness:0.5..0.8 + +# tool_efficiency at most 0.3 (no lower bound) +GET /evaluations?score_filters=tool_efficiency:..0.3 + +# helpfulness >= 0.5 AND factuality >= 0.9 +GET /evaluations?score_filters=helpfulness:0.5..,factuality:0.9.. +``` + +प्रत्येक `/evaluations` प्रतिक्रिया ऑब्जेक्ट में ये क्षेत्र हैं: + +| क्षेत्र | प्रकार | नोट्स | +|---|---|---| +| `evaluation_id` | string (UUID) | इस टर्मिनल मूल्यांकन के लिए विहित पहचानकर्ता। प्रत्येक टर्मिनल मूल्यांकन को एक नया UUID मिलता है; एक एकल सेशन कई रख सकता है। | +| `id` | string (UUID) | पिछड़े-संगतता उपनाम `evaluation_id` के समान मान ले जाता है। | +| `session_id` | string | सेशन जिस पर यह मूल्यांकन चला। एक सेशन टाइमलाइन में कई मूल्यांकन हो सकते हैं। | +| `agent_id` | string | एजेंट की पहचान करता है जो सेशन का निर्माण किया। | +| `environment` | string | सेशन से कॉपी किया गया Environment लेबल। | +| `status` | enum | `"done"`, `"error"`, `"timeout"` में से एक। | +| `scores` | object \| null | आपके मूल्यांकनकर्ता द्वारा लौटाए गए स्कोर। | +| `reasoning` | object \| null | आपके मूल्यांकनकर्ता द्वारा लौटाया गया वैकल्पिक प्रति-स्कोर न्यायसंगत नक्शा। कुंजियां आम तौर पर `scores` में उन लोगों को प्रतिबिंबित करती हैं। डैशबोर्ड अपने स्कोर बार के नीचे प्रत्येक प्रविष्टि प्रस्तुत करता है। | +| `summary` | string \| null | आपके मूल्यांकनकर्ता द्वारा लौटाया गया वैकल्पिक एक-पैराग्राफ समग्र आख्यान। डैशबोर्ड इसे प्रति-स्कोर ब्रेकडाउन के ऊपर मूल्यांकन की हेडलाइन के रूप में प्रस्तुत करता है। | +| `error` | string \| null | `"error"` / `"timeout"` पर ही आबादी। | +| `attempt_count` | integer | डिस्पैच प्रयासों की संख्या (≥ 1)। | +| `duration_ms` | integer \| null | अंतिम प्रयास की अवधि। | +| `completed_at` | string (ISO 8601 UTC) | जब टर्मिनल परिणाम दर्ज किया गया था। परिणाम `completed_at` द्वारा क्रमबद्ध हैं (newest first)। | +| `created_at` | string (ISO 8601 UTC) | `completed_at` के समान टाइमस्टैम्प रखता है (write-once semantics)। | + +--- + +## अनुमति + +| अनुमति | अनुदान | +|---|---| +| `evaluations:read` | मूल्यांकन परिणाम सूचीबद्ध करें, डैशबोर्ड में स्कोर देखें, और डैशबोर्ड स्वास्थ्य मेट्रिक्स लोड करें। | +| `evaluations:trigger` | `POST /sessions/:session_id/re-evaluate` के माध्यम से या डैशबोर्ड के पुनः-मूल्यांकन बटन के माध्यम से सेशन के लिए मैन्युअल रूप से एक मूल्यांकन कतार में डालें। | +| `dashboards:read` | सहेजे गए डैशबोर्ड देखें (उनके मेट्रिक्स लोड करने के लिए `evaluations:read` की भी आवश्यकता है)। | +| `dashboards:write` | डैशबोर्ड बनाएं और संपादित करें। | +| `dashboards:delete` | डैशबोर्ड हटाएं। | + +बूटस्ट्रैप एडमिन (`ADMIN_KEY`, `ADMIN_EMAIL`) स्वचालित रूप से इन्हें प्राप्त करता है। + +--- + +## परिणाम देखना + +- **`/sessions/`**: events टाइमलाइन + एक दाएं रेल जो सेशन के स्कोर और डिस्पैच प्रयास से कोई त्रुटि दिखाता है। यदि आपकी कुंजी के पास `evaluations:trigger` है, तो निर्यात बटन के बगल में एक **पुनः-मूल्यांकन** बटन दिखाई देता है, जो उन सेशन के लिए उपयोगी है जिन्होंने कभी `agent_end` उत्सर्जित नहीं किए, या नए मूल्यांकनकर्ता को तैनात करने के बाद स्कोर को ताज़ा करने के लिए। डैशबोर्ड नई परिणाम के लिए पोल करता है और दाएं रेल को अपडेट करता है जब यह पहुंचता है। +- **`/sessions`**: फ़िल्टर करने योग्य सेशन ग्रिड; स्कोर कॉलम प्रत्येक सेशन की मूल्यांकन स्थिति और स्कोर को एक नज़र में दिखाता है। +- **`/dashboards`**: सहेजे गए मूल्यांकन-स्वास्थ्य दृश्य (नीचे [डैशबोर्ड](#dashboards) देखें)। + +![सेशन ग्रिड प्रति-सेशन मूल्यांकन स्थिति गोलियों और रंग-कोडित स्कोर बैज (helpfulness, factuality, tool_efficiency, safety, coherence) के साथ](/agenteye/images/sessions-list.png) + +*सेशन ग्रिड प्रत्येक रन की मूल्यांकन स्थिति और स्कोर को एक नज़र में दिखाता है; लाल/एम्बर/हरी बैज कम स्कोर को बाहर निकालते हैं।* + +![दाएं रेल में मूल्यांकन स्कोर और डिस्पैच स्थिति के साथ सेशन विस्तार दृश्य](/agenteye/images/session-detail.png) + +*सेशन खोलने से पूरी टाइमलाइन दाएं रेल में मूल्यांकन स्कोर और कोई डिस्पैचर त्रुटि के साथ दिखाई देती है।* + +--- + +## डैशबोर्ड + +**डैशबोर्ड** पृष्ठ (`/dashboards`) आपको मूल्यांकन फ़िल्टर के एक संयोजन को एक नामित, पुन: उपयोग करने योग्य दृश्य के रूप में सहेजने देता है और देखता है कि मूल्यांकन का वह स्लाइस एक नज़र में कैसा कर रहा है। डैशबोर्ड **आपके पूरे संगठन में साझा हैं**; `dashboards:read` के साथ सभी को समान सेट दिखाई देता है। + +प्रत्येक डैशबोर्ड पिन करता है: + +- **फ़िल्टर**: सेशन पृष्ठ के समान नियंत्रण: environment, स्थिति, एजेंट, एक रोलिंग समय विंडो, और स्कोर-रेंज फ़िल्टर (`key:min..max`)। +- **एक प्रदर्शन कॉन्फ़िगरेशन**: कौन सी स्कोर कुंजियों को दिखाना है, हरी/एम्बर/लाल स्वास्थ्य थ्रेशोल्ड, कौन से पैनल दिखाएं, और क्या प्रति सेशन नवीनतम मूल्यांकन में संक्षिप्त करें। + +प्रत्येक कार्ड मेल खाने वाले सेशन की संख्या, एक done/error/timeout ब्रेकडाउन, प्रत्येक विशेष स्कोर का औसत, और एक छोटा trend sparkline दिखाता है। डैशबोर्ड खोलने से पूर्ण आकार के पैनल दिखाई देते हैं; **"सेशन में खोलें"** आपको सेशन पृष्ठ पर ठीक उसी स्लाइस के साथ पूर्व-फ़िल्टर किया जाता है। मेट्रिक्स पूरे मेल खाने वाले सेट के ऊपर सर्वर-पक्ष (`GET /evaluations/aggregate`) पर गणना की जाती हैं, इसलिए संख्याएं नमूना के बजाय सटीक होती हैं। + +![eval-health डैशबोर्ड प्रति evaluator आयाम औसत-स्कोर बार, एक tool ok-vs-error ब्रेकडाउन, top tools, और एक events-per-hour trend के साथ](/agenteye/images/dashboard-quality.png) + +**अनुमतियां:** देखने के लिए `dashboards:read` और `evaluations:read` दोनों की आवश्यकता होती है; बनाने और संपादित करने के लिए `dashboards:write` की आवश्यकता होती है; हटाने के लिए `dashboards:delete` की आवश्यकता होती है। बूटस्ट्रैप एडमिन स्वचालित रूप से ये सभी प्राप्त करता है। + +--- + +## समस्या निवारण + +**सेशन मौजूद हैं लेकिन कोई मूल्यांकन नहीं बनाए जाते हैं।** पुष्टि करें कि `EVALUATOR_ENDPOINT` सर्वर प्रक्रिया पर सेट है, कि सर्वर और मूल्यांकनकर्ता समान `EVALUATOR_TOKEN` मान साझा करते हैं, और कि मूल्यांकनकर्ता का `/health` endpoint सर्वर से पहुंच योग्य है। `EVALUATOR_ENDPOINT` अनसेट के साथ पाइपलाइन एक no-op है। + +**इन-फ्लाइट मूल्यांकन ढेर हो जाते हैं।** इन-फ्लाइट कतार देखने के लिए `GET /evaluation-jobs` क्वेरी करें। प्रत्येक पंक्ति पर `attempt_count`, `next_attempt_at`, और `last_error` की जांच करें। सामान्य कारण: मूल्यांकनकर्ता सेवा अप्राप्य या 5xx लौटा रहा है (बैकऑफ के साथ पुनः प्रयास किया गया), गलत `EVALUATOR_TOKEN` (401 टर्मिनल है), या एक async मूल्यांकनकर्ता जो `pending` को अनिश्चित काल तक लौटाता है (नीचे देखें)। + +**सेशन पूर्ण होते हैं लेकिन कोई टर्मिनल मूल्यांकन नहीं।** `GET /evaluation-jobs?status=polling` क्वेरी करें; परिणाम अभी भी चल सकता है। यदि कोई जॉब `pending` में फंस गया है, तो सर्वर को मूल्यांकनकर्ता तक पहुंचने में परेशानी हो रही है; जांचें कि मूल्यांकनकर्ता ऊपर है और `EVALUATOR_TOKEN` मेल खाता है। + +**मूल्यांकनकर्ता से `HTTP 401: invalid bearer token`।** सर्वर पर `EVALUATOR_TOKEN` मूल्यांकनकर्ता सेवा को कॉन्फ़िगर किए गए मान से मेल नहीं खाता है। वे समान होने चाहिए। + +**Async मूल्यांकनकर्ता `pending` को हमेशा लौटाता है।** सर्वर `GET /evaluate/{job_id}` को पोल करता है जब तक मूल्यांकनकर्ता `done` या `error` न लौटाए, या जब तक `EVALUATOR_MAX_POLL_DURATION_SECS` (डिफ़ॉल्ट 1 h) समाप्त न हो जाए। कैप के बाद मूल्यांकन `timeout` के रूप में दर्ज किया जाता है और इन-फ्लाइट कतार से हटा दिया जाता है। यदि आपका मूल्यांकनकर्ता वैध रूप से डिफ़ॉल्ट से अधिक की आवश्यकता है तो `EVALUATOR_MAX_POLL_DURATION_SECS` बढ़ाएं। \ No newline at end of file diff --git a/docs/hi/agenteye/getting-started.mdx b/docs/hi/agenteye/getting-started.mdx new file mode 100644 index 00000000..19a4cc28 --- /dev/null +++ b/docs/hi/agenteye/getting-started.mdx @@ -0,0 +1,235 @@ +--- +title: "AgentEye के साथ शुरुआत करें" +description: "AgentEye के साथ शुरुआत करने का दस्तावेज़।" +--- + + +यह गाइड आपको एक संपूर्ण AgentEye सेटअप के माध्यम से ले जाता है: सर्वर और डैशबोर्ड को तैनात करना, एजेंट मशीन पर कलेक्टर स्थापित करना, और अपने Python एजेंट कोड को उपकरण से सुसज्जित करना। + +--- + +## AgentEye क्या है? + +AgentEye एक **AI एजेंट्स के लिए स्व-होस्टेड अवलोकनशीलता और मूल्यांकन प्लेटफॉर्म** है। यह रिकॉर्ड करता है कि आपके एजेंट्स क्या करते हैं — एक रन का हर चरण — और स्वचालित रूप से प्रत्येक पूर्ण रन की गुणवत्ता को स्कोर करता है, ताकि आप देख सकें कि आपके एजेंट्स प्रोडक्शन में कैसे व्यवहार करते हैं और अपने उपयोगकर्ताओं से पहले रिग्रेशन पकड़ सकें। + +डेटा एक दिशा में बहता है: आपका एजेंट कोड **Python SDK** के माध्यम से **ईवेंट्स** उत्सर्जित करता है → एक हल्का **कलेक्टर** डेमन उन्हें बैच करता है और **सर्वर** को भेजता है → ईवेंट्स और विश्लेषण **ClickHouse** में संग्रहीत होते हैं (संगठन, उपयोगकर्ता, API कुंजी, डैशबोर्ड और सहेजी गई क्वेरीज़ जैसी परिचालन स्थिति **Postgres** में रहती है) → आप **डैशबोर्ड** में सब कुछ खोजते हैं। + +आप क्या पाते हैं: + +- **ईवेंट्स** — हर एजेंट रन का कच्चा, प्रति-चरण ट्रेल (टूल कॉल्स, मॉडल कॉल्स, हुक्स, त्रुटियां)। +- **सेशन्स** — वे ईवेंट्स एक पंक्ति में रोल किए गए, प्रत्येक **स्वचालित रूप से मूल्यांकित** और स्कोर किया गया। +- **मूल्यांकन** — आपकी अपनी मूल्यांकनकर्ता सेवाओं द्वारा उत्पादित गुणवत्ता स्कोर, ताकि गुणवत्ता में गिरावट मैनुअल समीक्षा के बिना सामने आए। +- **क्वेरीज़ और डैशबोर्ड्स** — आपके डेटा पर सहेजी गई ClickHouse SQL, साझा, संगठन-स्कोप्ड डैशबोर्ड्स में चार्ट किए गए। +- **अलर्ट्स और इंसिडेंट्स** — थ्रेसहोल्ड नियम जो आपको पेज करते हैं (ईमेल, Slack, वेबहुक, डैशबोर्ड-इन) साथ ही उन्हें ट्रायएज करने के लिए एक इंसिडेंट वर्कफ़्लो। +- **CLI और AI असिस्टेंट** — एक टर्मिनल क्लाइंट (`agenteye`) और एक डैशबोर्ड-इन असिस्टेंट सादे अंग्रेजी में प्रश्न पूछने के लिए। + +आप इसे अपने स्वयं के बुनियादी ढांचे में चलाते हैं, एक एकल Docker Compose स्टैक के रूप में (यह गाइड), एक प्रोडक्शन Kubernetes इंस्टॉल, या एक एकल सह-स्थित पॉड। इस गाइड का बाकी हिस्सा Compose स्टैक को अंत तक सेट अप करता है। + +--- + +## चरण 1: प्रमाणीकरण करें + +सभी AgentEye कलाकृतियां `agenteye-enterprise` GitHub संगठन से वितरित की जाती हैं। एक एंटरप्राइज़ डेवलपर के रूप में आप अपनी स्वयं की GitHub PAT उत्पन्न कर सकते हैं। सटीक चरणों और आवश्यक अनुमतियों के लिए [enterprise-docs/github-token.md](/hi/agenteye/github-token) फॉलो करें। + +```bash +export AGENTEYE_TOKEN= + +# Authenticate Docker against GHCR +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +--- + +## चरण 2: सर्वर और डैशबोर्ड को तैनात करें + +सर्वर कलेक्टर्स से ईवेंट्स प्राप्त करता है और उन्हें क्वेरीयोग्य बनाता है; डैशबोर्ड वह जगह है जहां आप उन्हें खोजते हैं। अंतर्ग्रहित ईवेंट्स और विश्लेषण ClickHouse में रहते हैं (आवश्यक विश्लेषण स्टोर), जबकि Postgres संगठन, उपयोगकर्ता, API कुंजी, डैशबोर्ड और सहेजी गई क्वेरीज़ जैसी परिचालन स्थिति रखता है। + +**प्रकाशित कंपोज़ फ़ाइल डाउनलोड करें:** + +```bash +mkdir -p ./agenteye +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + https://raw.githubusercontent.com/agenteye-enterprise/releases/main/docker-compose.yml \ + -o ./agenteye/docker-compose.yml +cd agenteye +``` + +**अपने रहस्य सेट करें:** + +एक `.env` फ़ाइल बनाएं ताकि डिप्लॉयमेंट डिफॉल्ट `admin` क्रेडेंशियल पर न चले। कम से कम `ADMIN_KEY` और `POSTGRES_PASSWORD` सेट करें: + +```bash +POSTGRES_PASSWORD=your-db-password +ADMIN_KEY=your-admin-secret +``` + +अपनी वर्तमान शेल में `ADMIN_KEY` को भी एक्सपोर्ट करें ताकि बाद के चरण (उदाहरण के लिए स्टेप 3 `curl`) इसे सीधे संदर्भित कर सकें: + +```bash +export ADMIN_KEY=your-admin-secret +``` + +**स्टैक शुरू करें:** + +```bash +docker compose up -d +``` + +यह पूरे स्टैक को ऊपर लाता है, जिसमें आवश्यक ClickHouse विश्लेषण स्टोर और एक वैकल्पिक Redis कैश शामिल है, सर्वर और डैशबोर्ड के साथ। ClickHouse को स्वस्थ होना चाहिए ताकि सर्वर शुरू हो सके। + +सर्वर अब `http://localhost:8080` पर सुन रहा है और डैशबोर्ड `http://localhost:3000` पर है। + +प्रोडक्शन डिप्लॉयमेंट के लिए (कस्टम Postgres, TLS, रिवर्स प्रॉक्सी), [enterprise-docs/deployment.md](/hi/agenteye/deployment) देखें। + +--- + +## चरण 3: कलेक्टर के लिए API कुंजी बनाएं + +प्रत्येक कलेक्टर एक स्कोप्ड API कुंजी के साथ प्रमाणित करता है। स्टेप 2 में सेट की गई `ADMIN_KEY` का उपयोग करके एक बनाएं: + +```bash +curl -s -X POST http://localhost:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{"name":"prod-collector","key":"your-collector-secret","permissions":["events:add"]}' +``` + +आप `key` मान को स्वयं प्रदान करते हैं; स्टेप 4 में कलेक्टर कॉन्फ़िग में इसका उपयोग करें। पूर्ण कुंजी प्रबंधन के लिए [enterprise-docs/api-keys.md](/hi/agenteye/api-keys) देखें। + +--- + +## चरण 4: कलेक्टर स्थापित करें + +हर मशीन पर जो आपके AI एजेंट्स को चलाती है, कलेक्टर डेमन स्थापित करें। + +**बाइनरी डाउनलोड करें (Linux x86_64):** + +```bash +VERSION=0.0.1-beta.13 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "collector/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-collector-linux-x86_64' +chmod +x agenteye-collector-linux-x86_64 +sudo mv agenteye-collector-linux-x86_64 /usr/local/bin/agenteye-collector +``` + +> यह **Linux x86_64** बिल्ड डाउनलोड करता है। macOS (Apple Silicon या Intel), Linux arm64, या Docker/systemd/launchd सेटअप के लिए, [collector-installation.md](/hi/agenteye/collector-installation) देखें, जो प्रत्येक प्लेटफॉर्म के लिए डाउनलोड की सूची देता है — ऊपर दिया गया कमांड एक Linux बाइनरी स्थापित करता है जो अन्य जगहों पर नहीं चलेगा। + +**कॉन्फ़िगर करें:** + +```bash +mkdir -p ~/.agenteye +cat > ~/.agenteye/config.json </…`)। + +- **क्वेरीज़** (`//queries`): अपनी ईवेंट्स और मूल्यांकन पर सहेजी गई, पुनः उपयोग योग्य क्वेरीज़ की एक लाइब्रेरी से शुरू करें (बिल्ट-इन प्रीसेट्स साथ ही आपकी अपनी)… + +![सहेजी गई-क्वेरीज़ लाइब्रेरी: पुनः उपयोग योग्य क्वेरीज़ का एक ग्रिड, बिल्ट-इन प्रीसेट्स और कस्टम दोनों](/agenteye/images/queries.png) + + …फिर एक को SQL कम्पोजर में खोलें इसे ट्वीक करने और लाइव परिणामों के साथ चलाने के लिए: + +![SQL क्वेरी कम्पोजर एक सहेजी गई क्वेरी चला रहा है, स्कीमा साइडबार और एक लाइव परिणाम ग्रिड के साथ](/agenteye/images/query-lab.png) + +- **डैशबोर्ड्स** (`//dashboards`): क्वेरीज़ को लाइन, बार, एरिया या पाई टाइल्स के रूप में साझा, संगठन-व्यापी डैशबोर्ड्स में पिन करें। + +![एक डैशबोर्ड सहेजी गई क्वेरीज़ से बनाया गया: एक प्रति-घंटा लाइन, एक त्रुटि-दर-प्रकार बार, एक लेटेंसी एरिया चार्ट और टोकन-प्रति-मॉडल](/agenteye/images/dashboard-fleet.png) + +- **अलर्ट्स** (`//alerts`): किसी भी थ्रेसहोल्ड को एक पेजिंग नियम में प्रोन्नत करें जो ईमेल, Slack, वेबहुक या डैशबोर्ड-इन द्वारा सूचित करता है। [enterprise-docs/alerts.md](/hi/agenteye/alerts) देखें। + +--- + +## अगले चरण + +- [डिप्लॉयमेंट](/hi/agenteye/deployment): प्रोडक्शन के लिए कठोर करें +- [API कुंजियां](/hi/agenteye/api-keys): एक्सेस प्रबंधित करें +- [समस्या निवारण](/hi/agenteye/troubleshooting): समस्याओं का निदान करें \ No newline at end of file diff --git a/docs/hi/agenteye/github-token.mdx b/docs/hi/agenteye/github-token.mdx new file mode 100644 index 00000000..d612af32 --- /dev/null +++ b/docs/hi/agenteye/github-token.mdx @@ -0,0 +1,132 @@ +--- +title: "GitHub Token सेटअप" +description: "AgentEye GitHub Token सेटअप दस्तावेज़।" +--- + + +एक GitHub Personal Access Token (PAT) वह एकमात्र credential है जो हर AgentEye artifact को अनलॉक करता है। एक token के साथ आप Docker images pull कर सकते हैं, release binaries डाउनलोड कर सकते हैं, और Python wheels install कर सकते हैं, बिना किसी per-component login और बिना कोई shared secrets circulate किए। सभी AgentEye artifacts `agenteye-enterprise` GitHub organization से distribute किए जाते हैं; एक बार जब आपके organization को access दे दिया जाता है, तो प्रत्येक developer या operator अपना खुद का token generate और rotate करता है, इसलिए access auditable और per-person revocable रहता है। + +Token को environment variable के रूप में और Docker credential के रूप में एक बार प्रति machine सेट करें: + +```bash +export AGENTEYE_TOKEN= +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +> **Username नोट:** GHCR `docker login` username को ignore करता है और पूरी तरह से token से authenticate करता है, इसलिए कोई भी non-empty value काम करती है। ये docs संक्षेप के लिए `-u x` का उपयोग करते हैं; deployment manifests जो Kubernetes image-pull secret बनाते हैं वे `agenteye-enterprise` जैसे अधिक descriptive username का उपयोग कर सकते हैं। दोनों स्वीकार हैं। + +--- + +## विकल्प A: Classic Token (अनुशंसित) + +एक classic token AgentEye के लिए सबसे विश्वसनीय विकल्प है, क्योंकि GHCR का `docker login` और image-pull flow classic tokens के लिए सबसे व्यापक, सबसे सुसंगत support है। दो scopes सब कुछ cover करते हैं जो आपको चाहिए (images pull करना और release assets डाउनलोड करना), इसलिए आप एक बार authenticate करते हैं और registry quirks की troubleshooting किए बिना आगे बढ़ते हैं। इनमें से एक, `read:packages`, genuinely read-only है; दूसरा, `repo`, एकमात्र classic scope है जो private release assets तक access देता है, और यह deliberately broad है — GitHub इसे private repositories का full control (read और write) के रूप में define करता है। + +### 1. Token बनाएँ + +**GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic) → Generate new token (classic)** पर जाएं। + +| Field | Value | +|---|---| +| **Note** | `agenteye-` (जैसे `agenteye-prod-server`) | +| **Expiration** | अपनी security policy के लिए उपयुक्त expiry सेट करें; 90 दिन एक reasonable default है | + +> **Label नोट:** GitHub इस field को classic tokens के लिए **Note** और fine-grained tokens के लिए **Token name** कहता है। वे एक ही purpose serve करते हैं: बाद में auditing और revocation के लिए एक human-readable identifier। + +### 2. Scopes चुनें + +| Scope | यह क्यों आवश्यक है | +|---|---| +| `read:packages` | `ghcr.io/agenteye-enterprise/` से Docker images pull करें और package assets डाउनलोड करें | +| `repo` | Private repository contents, raw files, और `agenteye-enterprise/releases` से release assets को read करें। यह GitHub का broad "Full control of private repositories" scope (read और write) है, न कि read-only scope — यह बस एकमात्र classic scope है जो private release assets तक access देता है | + +कोई अन्य scopes आवश्यक नहीं हैं। + +### 3. Token generate और copy करें + +**Generate token** पर क्लिक करें और तुरंत value को copy करें; यह केवल एक बार दिखाया जाता है। इसे अपने secret manager या environment में store करें। + +--- + +## विकल्प B: Fine-Grained Token + +Fine-grained tokens specific repositories और permissions तक access को scope करते हैं, जिससे वे tightest least-privilege विकल्प बन जाते हैं। इस path को चुनें जब आपके organization की security policy fine-grained tokens को mandate करे। + +> **नोट:** Fine-grained tokens के लिए GHCR support classic tokens जितना consistent नहीं है। यदि इन steps को follow करने के बाद `docker login` या `docker pull` fail हो, तो classic token पर fall back करें (विकल्प A)। + +### 1. Token बनाएँ + +**GitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokens → Generate new token** पर जाएं। + +| Field | Value | +|---|---| +| **Token name** | `agenteye-` (जैसे `agenteye-prod-server`) | +| **Expiration** | अपनी security policy के लिए उपयुक्त expiry सेट करें; 90 दिन एक reasonable default है | +| **Resource owner** | `agenteye-enterprise` | +| **Repository access** | **Only select repositories** → `agenteye-enterprise/releases` | + +### 2. Repository permissions सेट करें + +**Permissions → Repository permissions** के तहत, सेट करें: + +| Permission | Access | +|---|---| +| **Contents** | Read-only | +| **Packages** | Read-only | + +सभी अन्य permissions **No access** पर रहे सकते हैं। + +> **नोट:** यदि container images (`ghcr.io/agenteye-enterprise/...`) organization-level packages के रूप में publish किए गए हैं न कि repository-linked packages के रूप में, तो Docker login repository-scoped permissions alone के साथ fail हो सकता है। उस स्थिति में, organization-level permission जोड़ें: **Permissions → Organization permissions → Packages: Read-only**। + +### 3. प्रत्येक permission क्या देता है + +| Permission | किसके लिए उपयोग किया जाता है | +|---|---| +| Contents: Read-only | `agenteye-enterprise/releases` से `docker-compose.yml`, release binaries, और Python wheels डाउनलोड करना | +| Packages: Read-only | `ghcr.io/agenteye-enterprise/` से Docker images pull करना | + +### 4. Token generate और copy करें + +**Generate token** पर क्लिक करें और तुरंत value को copy करें; यह केवल एक बार दिखाया जाता है। इसे अपने secret manager या environment में store करें। + +--- + +## Token को Rotate करना + +नियमित schedule पर tokens को rotate करना access को auditable रखता है और यदि कोई credential कभी leak हो तो blast radius को सीमित करता है। Tokens expire भी सकते हैं या किसी भी समय revoke किए जा सकते हैं, इसलिए rotation authenticated रहने का routine तरीका है। Rotate करने के लिए: + +1. ऊपर दिए गए steps का उपयोग करके एक नया token generate करें। +2. अपने environment या secret manager में `AGENTEYE_TOKEN` को update करें। +3. Docker को फिर से authenticate करें: `echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin` +4. GitHub → Settings → Developer settings → Personal access tokens में पुराने token को revoke करें, फिर token के type से मेल खाने वाले **Tokens (classic)** या **Fine-grained tokens** sub-page को खोलें और इसे delete करें। + +--- + +## अपने Token को Verify करें + +इसे deployment में wire करने से पहले confirm करें कि token काम करता है, ताकि authentication failures यहाँ surface हो बजाय mid-rollout के। प्रत्येक command ऊपर दिए गए scopes में से एक का exercise करता है: + +```bash +# Packages scope - GHCR के विरुद्ध Docker को authenticate करें +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin + +# Contents scope - एक raw release file को fetch करें +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + https://raw.githubusercontent.com/agenteye-enterprise/releases/main/docker-compose.yml \ + -o /tmp/agenteye-compose-check.yml +``` + +एक successful `docker login` package scope को confirm करता है; एक downloaded file contents scope को confirm करता है। + +--- + +## Troubleshooting + +| Symptom | संभावित कारण | Fix | +|---|---|---| +| `docker login` 401 return करता है | Token में `Packages: Read-only` (fine-grained) या `read:packages` (classic) missing है | Package scope जोड़ें और regenerate करें | +| `curl` raw GitHub URLs पर 404 return करता है | Token में `Contents: Read-only` या `repo` scope missing है | Contents scope जोड़ें और regenerate करें | +| `gh release download` 403 return करता है | Token को `agenteye-enterprise/releases` के लिए authorize नहीं किया गया है | Verify करें कि repo fine-grained token की repository access में included है, या `repo` scope के साथ classic token का उपयोग करें | +| Token accepted है लेकिन images नहीं मिले | Fine-grained token पर organization-level package permission missing है | Organization-level `Packages: Read-only` permission जोड़ें | + +Access issues के लिए, `support@exosphere.host` से contact करें। \ No newline at end of file diff --git a/docs/hi/agenteye/health-monitoring.mdx b/docs/hi/agenteye/health-monitoring.mdx new file mode 100644 index 00000000..56818f65 --- /dev/null +++ b/docs/hi/agenteye/health-monitoring.mdx @@ -0,0 +1,124 @@ +--- +title: "स्वास्थ्य निगरानी" +description: "AgentEye स्वास्थ्य निगरानी दस्तावेज़।" +--- + + +जानें कि AgentEye deployment **स्वयं** कब डाउन या गिरावट में है, न कि सिर्फ जब +आपके agents गलत व्यवहार करें। पहचान **Kubernetes-native** है और, महत्वपूर्ण रूप से, +**AgentEye से स्वतंत्र** है: यह Kubernetes control plane से pod state पढ़ता है +और AgentEye की hard dependencies की जांच करता है, इसलिए यह तब भी काम करता है जब +server, ClickHouse, या Postgres डाउन हो। + +दो परतें हैं। पहली built-in है; दूसरी opt-in है। + +## 1. Dependency-aware readiness (built in) + +सर्वर दो probe endpoints expose करता है जिनके अलग-अलग कार्य हैं: + +| Endpoint | Probe | जांचें | Auth | +|---|---|---|---| +| `GET /health` | liveness | process alive है (हमेशा `{"status":"ok"}`) | none | +| `GET /ready` | readiness | वास्तव में सेवा प्रदान कर सकता है: **Postgres + ClickHouse** reachable | none | + +`/ready` `200` के साथ `"status":"ready"` और हर check `"ok"` के साथ return करता है जब +दोनों hard dependencies reachable हैं, और `503` के साथ `"status":"not_ready"` return करता है +जब कोई भी unreachable हो। दोनों responses एक छोटा body ले जाते हैं: + +```json +{ "status": "not_ready", + "checks": { "postgres": "ok", "clickhouse": "down", "redis": "not_configured" } } +``` + +Redis एक optional cache है जिससे सर्वर degrade हो सकता है, इसलिए यह +जानकारी के लिए report किया जाता है लेकिन readiness को **कभी** fail नहीं करता। यह `"ok"` दिखाता है +जब cache configured हो और `"not_configured"` अन्यथा; यह कभी `"down"` नहीं होता। + +bundled Kubernetes manifests पर **readiness** probe `/ready` को point करता है +और **liveness** `/health` पर रहता है। प्रभाव: एक सर्वर जो *running है लेकिन +अपने database तक नहीं पहुंच सकता* को Service से निकाल दिया जाता है और `NotReady` दिखाता है, +एक state जिस पर आपका cluster monitoring (नीचे) alert दे सकता है, जबकि liveness सस्ता +रहता है ताकि एक brief dependency blip कभी pod restart को trigger न करे। Probe एक +generous failure threshold का उपयोग करता है ताकि एक momentary blip replicas को +rotation से बाहर न करे। + +## 2. Pod-failure alerting with Robusta (opt-in) + +[Robusta](https://github.com/robusta-dev/robusta) एक Kubernetes-native monitor है +जो API server को देखता है और pod failures (`CrashLoopBackOff`, +`OOMKilled`, `ImagePullBackOff`, `Pending`/`NotReady`, `Failed`, evictions) को +Slack पर post करता है। क्योंकि यह control plane को देखता है न कि AgentEye से पूछता है, +यह alert करता है यहां तक कि जब AgentEye बिल्कुल serve नहीं कर सकता। + +Robusta release bundle में एक opt-in add-on के रूप में ship करता है। इसे +standard Robusta Helm chart और नीचे दिया गया छोटा values file के साथ enable करें: + +1. chart repo add करें और channel के लिए एक Slack **bot token** (`xoxb-…`) प्राप्त करें: + + ```bash + helm repo add robusta https://robusta-charts.storage.googleapis.com + helm repo update + ``` + + क्योंकि नीचे दिया गया configuration सब कुछ in-cluster रखता है + (`disableCloudRouting: true`), token एक self-hosted Slack app से आता है: + `https://api.slack.com/apps` पर एक app बनाएं, `chat:write` bot scope add करें, + इसे अपने workspace में install करें, **Bot User OAuth Token** (`xoxb-…`) copy करें, और + bot को channel में invite करें (`/invite @your-app`)। + +2. एक `values.yaml` बनाएं per-deployment label (`clusterName`) और अपना + Slack channel के साथ, `agenteye` namespace को scope करते हुए: + + ```yaml + clusterName: "acme-prod" # per-deployment label; हर alert पर दिखता है + enablePrometheusStack: false # pod-crash alerts only; कोई metric stack नहीं + disableCloudRouting: true # Slack को directly deliver करें, in-cluster + sinksConfig: + - slack_sink: + name: vendor_slack + slack_channel: "agenteye-fleet-health" + api_key: "REPLACE_WITH_SLACK_BOT_TOKEN" # xoxb-… (--set या secret को prefer करें) + scope: + include: + - namespace: [agenteye] # केवल AgentEye-namespace alerts; बढ़ाने के लिए हटाएं + ``` + +3. Install करें, एक known-good Robusta chart release को `--version` के साथ pin करते हुए + ([releases](https://github.com/robusta-dev/robusta/releases)) ताकि आप कभी + untested chart install न करें: + + ```bash + helm install robusta robusta/robusta \ + --namespace robusta --create-namespace \ + --version \ + -f values.yaml \ + --set sinksConfig[0].slack_sink.api_key=$ROBUSTA_SLACK_TOKEN + ``` + +### यह क्या report करता है + +- Kubernetes **pod state** (कौन सा AgentEye pod fail हो रहा है और क्यों) और हर pod का + **image tag**, अर्थात् running component **version**। +- **कोई AgentEye event data और कोई customer data** कभी cluster को नहीं छोड़ता। +- bundled values alerts को **`agenteye` namespace** तक सीमित करते हैं, इसलिए + same cluster में unrelated workloads report नहीं होते। + +### हर deployment के लिए एक जगह + +हर deployment के Robusta को **एक shared Slack channel** की ओर point करें, हर एक अपना +`clusterName` के साथ। हर alert उस label के साथ tagged है, इसलिए एक single channel +आपके पूरे fleet का स्वास्थ्य दिखाता है, और आप एक नज़र में बता सकते हैं कि कौन सा deployment +प्रभावित है। + +### Total-cluster outages + +एक purely in-cluster watcher एक **whole-cluster या network outage** report नहीं कर सकता +(यह cluster के साथ नीचे जाता है)। अगर आपको इसकी जरूरत है, तो optional **Robusta +UI sink** enable करें: `disableCloudRouting: false` सेट करें और `sinksConfig` में एक +`robusta_sink` add करें (`robusta gen-config` से एक token के साथ)। यह एक aggregated +multi-cluster dashboard जोड़ता है और किसी भी cluster को flag करता है जो check-in करना बंद कर दे। + +## समस्या निवारण + +[enterprise-docs/troubleshooting.md](/hi/agenteye/troubleshooting) के **Health Monitoring** section को +देखें "no alerts arriving" और "server keeps flapping `NotReady`" के लिए। \ No newline at end of file diff --git a/docs/hi/agenteye/kubernetes-deployment.mdx b/docs/hi/agenteye/kubernetes-deployment.mdx new file mode 100644 index 00000000..7fe04e32 --- /dev/null +++ b/docs/hi/agenteye/kubernetes-deployment.mdx @@ -0,0 +1,695 @@ +--- +title: "Kubernetes डिप्लॉयमेंट गाइड" +description: "AgentEye Kubernetes डिप्लॉयमेंट गाइड दस्तावेज।" +--- + + +यह गाइड पूरे AgentEye स्टैक को एक समर्पित Kubernetes क्लस्टर पर डिप्लॉय करता है: + +- **ClickHouse 24.8** -- कैनोनिकल इवेंट्स और इवैल्यूएशंस एनालिटिक्स स्टोर (100Gi परसिस्टेंट वॉल्यूम के साथ StatefulSet)। आवश्यक: सर्वर इसके बिना शुरू नहीं होता। +- **PostgreSQL 16** -- संगठनों, API कुंजियों, उपयोगकर्ताओं, डैशबोर्ड, सहेजी गई क्वेरीज़ और प्रमाणीकरण के लिए संबंधपरक/मेटाडेटा स्टोर (50Gi परसिस्टेंट वॉल्यूम के साथ StatefulSet) +- **Redis 7.2** -- वैकल्पिक साझा कैश और रेट-लिमिट बैकएंड; यदि यह उपलब्ध नहीं है तो सर्वर और डैशबोर्ड सुंदर ढंग से हीन हो जाते हैं +- **AgentEye Server** -- इवेंट इंजेशन, एनालिटिक्स और कुंजी प्रबंधन के लिए Rust API (2 प्रतिकृतियां) +- **AgentEye Dashboard** -- Next.js वेब यूआई (2 प्रतिकृतियां) +- **AI असिस्टेंट (एजेंट सेवा)** -- वैकल्पिक पोर्ट 9100 पर डैशबोर्ड-इन केवल-पढ़ने के लिए असिस्टेंट; एक LLM एंडपॉइंट कॉन्फ़िगर होने तक निष्क्रिय +- **Traefik (सार्वजनिक)** -- कलेक्टर ट्रैफिक के लिए इनग्रेस कंट्रोलर, mTLS-सुरक्षित +- **Traefik (डैशबोर्ड)** -- डैशबोर्ड के लिए इनग्रेस कंट्रोलर, केवल VPN/IP-allowlist +- **cert-manager** -- TLS प्रमाणपत्र और mTLS CA +- **Backup CronJob** -- PostgreSQL + ClickHouse का दैनिक संयुक्त डंप 03:00 UTC पर +- **Cert Renewal Monitor** -- जब क्लाइंट प्रमाणपत्र समाप्त होने के करीब हों तो सतर्क करता है + +**अनुमानित समय:** पहली डिप्लॉयमेंट के लिए 60--90 मिनट। + +प्रबंधित डिप्लॉयमेंट मॉडल के लिए जहां Exosphere आपकी ओर से यह सब संभालता है, [enterprise-docs/managed-deployment.md](/hi/agenteye/managed-deployment) देखें। + +--- + +## पूर्वापेक्षाएं + +शुरू करने से पहले प्रत्येक सत्यापन आदेश चलाएं। हर जांच पास होनी चाहिए। + +| आवश्यकता | न्यूनतम | सत्यापन कमांड | अपेक्षित | +|---|---|---|---| +| Kubernetes क्लस्टर | 1.27+ | `kubectl version` | Server Version >= v1.27 | +| Kustomize (kubectl के साथ बंडल) | Kustomize v1.14+ (kubectl 1.27+ के अंदर शिप) | `kubectl kustomize --help` | उपयोग पाठ प्रिंट करता है | +| Helm | v3 | `helm version` | `Version:"v3.x.x"` | +| cluster-admin RBAC | -- | `kubectl auth can-i create namespaces` | `yes` | +| Default StorageClass | -- | `kubectl get storageclass` | कम से कम एक पंक्ति `(default)` चिह्नित | +| LoadBalancer समर्थन | -- | क्लाउड-आश्रित (EKS, GKE, AKS सभी डिफ़ॉल्ट रूप से समर्थन करते हैं) | -- | +| GitHub PAT | -- | `echo $AGENTEYE_TOKEN` | गैर-खाली (देखें [enterprise-docs/github-token.md](/hi/agenteye/github-token)) | +| openssl | -- | `openssl version` | OpenSSL 1.x या 3.x | +| क्लाउड स्टोरेज बकेट | -- | PostgreSQL + ClickHouse बैकअप के लिए (S3, GCS, या Azure Blob) | -- | + +**क्लस्टर आकार:** न्यूनतम 3 नोड्स, प्रत्येक 4 vCPU / 8 GB RAM। पूरी आवश्यकताओं के लिए [enterprise-docs/managed-deployment.md](/hi/agenteye/managed-deployment) देखें। + +### एक साथ सभी जांचें चलाएं + +```bash +echo "--- Prerequisites Check ---" +kubectl version --client -o yaml 2>/dev/null | grep -q gitVersion && echo "PASS: kubectl" || echo "FAIL: kubectl not found" +helm version --short 2>/dev/null | grep -q v3 && echo "PASS: helm v3" || echo "FAIL: helm v3 not found" +kubectl auth can-i create namespaces 2>/dev/null | grep -q yes && echo "PASS: cluster-admin" || echo "FAIL: no cluster-admin" +kubectl get storageclass 2>/dev/null | grep -q default && echo "PASS: default StorageClass" || echo "FAIL: no default StorageClass" +[ -n "$AGENTEYE_TOKEN" ] && echo "PASS: AGENTEYE_TOKEN set" || echo "FAIL: AGENTEYE_TOKEN not set" +openssl version >/dev/null 2>&1 && echo "PASS: openssl" || echo "FAIL: openssl not found" +echo "---" +``` + +### डिप्लॉयमेंट आकार + +**इंजेस्ट एंडपॉइंट** आपके द्वारा नियंत्रित होस्टनाम पर परोसा जाता है (उदाहरण `ingest.your-company.example`)। cert-manager Let's Encrypt से HTTP-01 के माध्यम से एक सार्वजनिक रूप से विश्वसनीय TLS प्रमाणपत्र का अनुरोध करता है, इसलिए कलेक्टर सिस्टम ट्रस्ट स्टोर के विरुद्ध सर्वर प्रमाणपत्र को सत्यापित करते हैं, कोई प्रति-ग्राहक CA पिनिंग नहीं। + +**डैशबोर्ड एंडपॉइंट** एक ही तरीके से काम करता है: यह आपके द्वारा नियंत्रित दूसरे होस्टनाम पर परोसा जाता है (उदाहरण `agenteye.your-company.example`) डैशबोर्ड Traefik LoadBalancer की ओर इशारा करता है, और cert-manager उस LoadBalancer के माध्यम से Let's Encrypt प्रमाणपत्र जारी करता है। ब्राउज़र को कोई चेतावनी के साथ एक विश्वसनीय प्रमाणपत्र मिलता है। + +> **प्रमाणपत्र जारी करना और नवीनीकरण HTTP-01 पर सत्यापित करता है**, इसलिए दोनों LoadBalancers को सार्वजनिक इंटरनेट से पोर्ट 80 पर पहुंचने योग्य होना चाहिए। यदि आप डैशबोर्ड LoadBalancer को IP-प्रतिबंधित करने की आवश्यकता है, तो DNS-01 सॉल्वर को समर्थन के साथ समन्वय करें -- अन्यथा नवीकरण चुप रहते हैं और प्रमाणपत्र समाप्त हो जाता है। + +--- + +## मैनिफेस्ट प्राप्त करें + +```bash +git clone https://x:${AGENTEYE_TOKEN}@github.com/agenteye-enterprise/releases.git +cd releases/deploy +``` + +**इसे टेस्ट करें:** + +```bash +ls base/kustomization.yaml +``` + +अपेक्षित: फ़ाइल मौजूद है। यदि यह नहीं है, तो क्लोन विफल रहा -- अपनी `AGENTEYE_TOKEN` की जांच करें। + +**निर्देशिका संरचना:** + +``` +deploy/ + base/ साझा Kustomize आधार (सभी K8s संसाधन) + overlays/ क्लस्टर-विशिष्ट ओवरराइड (इमेज टैग, होस्टनाम, संसाधन) + third-party/ Traefik, cert-manager और (opt-in) Robusta स्वास्थ्य निगरानी के लिए Helm मान +``` + +**आधार** में पूर्ण डिप्लॉयमेंट के लिए आवश्यक हर संसाधन होता है, जिसमें Phase 3.1 में आप जो कॉन्फ़िगर करते हैं उन दोनों सार्वजनिक होस्टनाम के लिए Let's Encrypt प्रमाणपत्र भी शामिल हैं। एक **ओवरले** किसी विशेष पर्यावरण (उदाहरण कस्टम इमेज टैग, संसाधन सीमाएं, env वायरिंग) के लिए आधार को पैच करता है। **third-party** निर्देशिका में बाहरी अवसंरचना के लिए Helm मान फ़ाइलें होती हैं। + +> **स्वास्थ्य निगरानी (वैकल्पिक):** सर्वर की तत्परता जांच पहले से Postgres + ClickHouse स्वास्थ्य को प्रतिबिंबित करती है, और `third-party/robusta/` opt-in Kubernetes-नेटिव पॉड-विफलता Slack को सतर्क करना जोड़ता है। देखें [enterprise-docs/health-monitoring.md](/hi/agenteye/health-monitoring)। + +--- + +## Phase 1 -- Third-Party इंफ्रास्ट्रक्चर (~30 मिनट) + +### 1.1 cert-manager इंस्टॉल करें + +cert-manager HTTPS के लिए TLS प्रमाणपत्र और mTLS क्लाइंट प्रमाणपत्र के लिए उपयोग किए जाने वाले निजी CA को प्रबंधित करता है। + +```bash +helm repo add jetstack https://charts.jetstack.io +helm repo update + +helm install cert-manager jetstack/cert-manager \ + --namespace cert-manager --create-namespace \ + --set crds.install=true +``` + +**इसे टेस्ट करें:** + +```bash +kubectl get pods -n cert-manager +``` + +अपेक्षित: 3 पॉड्स सभी `Running` -- `cert-manager`, `cert-manager-cainjector`, `cert-manager-webhook`। + +```bash +kubectl get crds | grep cert-manager +``` + +अपेक्षित: कम से कम `certificates.cert-manager.io`, `clusterissuers.cert-manager.io`, `issuers.cert-manager.io`। + +**यदि यह विफल होता है:** `CrashLoopBackOff` में पॉड्स आमतौर पर मतलब है CRD्स इंस्टॉल नहीं थे। `--set crds.install=true` के साथ फिर से चलाएं। यदि webhook पॉड्स तत्परता विफल करते हैं, 30 सेकंड प्रतीक्षा करें और फिर से जांचें -- वे शुरू होने में एक पल ले सकते हैं। + +--- + +### 1.2 Traefik इंस्टॉल करें -- सार्वजनिक इंजेस्ट कंट्रोलर + +यह Traefik उदाहरण **बाहरी** LoadBalancer पर कलेक्टर ट्रैफिक को संभालता है। यह TLS को समाप्त करता है और इंजेस्ट एंडपॉइंट पर mTLS (क्लाइंट प्रमाणपत्र सत्यापन) को लागू करता है। + +```bash +helm repo add traefik https://traefik.github.io/charts +helm repo update + +helm install traefik-public traefik/traefik \ + --namespace traefik-public --create-namespace \ + --version 39.0.8 \ + -f third-party/traefik/values-public.yaml +``` + +**इसे टेस्ट करें:** + +```bash +kubectl get pods -n traefik-public +``` + +अपेक्षित: 1 पॉड `Running`। + +```bash +kubectl get ingressclass traefik-public +``` + +अपेक्षित: IngressClass मौजूद है (यह डिफ़ॉल्ट वर्ग नहीं है)। + +**यदि यह विफल होता है:** इमेज पुल त्रुटियों या संसाधन बाधाओं के लिए `kubectl describe pod -n traefik-public ` की जांच करें। + +--- + +### 1.3 Traefik इंस्टॉल करें -- डैशबोर्ड कंट्रोलर + +यह Traefik उदाहरण एक समर्पित LoadBalancer पर डैशबोर्ड परोसता है, IP allowlist द्वारा प्रतिबंधित। + +> **इस उदाहरण के लिए दो allowlist तंत्र शिप होते हैं।** यह गाइड `values-dashboard.yaml` का उपयोग करता है, जो पोर्टेबल `service.loadBalancerSourceRanges` फ़ील्ड के साथ एक्सेस को प्रतिबंधित करता है। AWS वातावरण के लिए एक समानांतर `values-internal.yaml` भी प्रदान किया जाता है जो `service.beta.kubernetes.io/aws-load-balancer-source-ranges` एनोटेशन को पसंद करते हैं। एक को चुनें और इसे लगातार उपयोग करें; नीचे दिए गए चरण `values-dashboard.yaml` मानते हैं। + +**इंस्टॉल करने से पहले**, `third-party/traefik/values-dashboard.yaml` को संपादित करें अनुमत स्रोत IP सेट करने के लिए। `loadBalancerSourceRanges` फ़ील्ड नियंत्रित करता है कि कौन से IP डैशबोर्ड तक पहुंच सकते हैं। डिफ़ॉल्ट रूप से यह `0.0.0.0/0` (सभी IP) पर सेट है; इसे अपने VPN, कार्यालय या ज्ञात एग्रेस IP तक प्रतिबंधित करें। + +#### एकल IP व्हाइटलिस्ट करें + +```yaml +service: + loadBalancerSourceRanges: + - "/32" +``` + +#### कई IP व्हाइटलिस्ट करें + +एक IP या CIDR ब्लॉक प्रति प्रविष्टि जोड़ें। एक `/32` प्रत्यय एकल IPv4 पते से मेल खाता है; एक CIDR ब्लॉक (उदाहरण `/24`) एक श्रृंखला से मेल खाता है। आप व्यक्तिगत IP और श्रृंखलाओं को स्वतंत्र रूप से मिश्रित कर सकते हैं: + +```yaml +service: + loadBalancerSourceRanges: + - "203.0.113.10/32" # office gateway + - "203.0.113.11/32" # backup office gateway + - "198.51.100.0/24" # VPN pool + - "192.0.2.50/32" # on-call engineer home IP +``` + +सूची को बनाए रखते समय सुझाव: + +- एक प्रविष्टि प्रति पंक्ति रखें और एक छोटी `#` टिप्पणी जोड़ें जो प्रत्येक IP के स्वामी या उद्देश्य की पहचान करती है; यह है जो भविष्य के संचालक यह तय करने के लिए उपयोग करते हैं कि कोई प्रविष्टि अभी भी आवश्यक है। +- हमेशा CIDR संकेतन का उपयोग करें। `203.0.113.10` जैसा नंगा IP क्लाउड प्रदाता द्वारा अस्वीकार किया जाता है; `203.0.113.10/32` का उपयोग करें। +- IPv6 श्रृंखलाओं के लिए, समकक्ष `/128` (एकल पता) या बड़ी CIDR का उपयोग करें, उदाहरण `2001:db8::1/128`। सभी क्लाउड प्रदाता IPv6 स्रोत श्रृंखलाओं का समर्थन नहीं करते; अपने प्रदाता के LoadBalancer दस्तावेज़ की जांच करें। +- सूची एक **OR** है: ट्रैफिक की अनुमति है यदि स्रोत किसी भी प्रविष्टि से मेल खाता है। + +फ़ाइल संपादित करने के बाद, नीचे `helm install` पर जाएं। यदि कंट्रोलर पहले से ही इंस्टॉल है, तो एक ही फ़्लैग के साथ `helm upgrade` चलाएं, या रनटाइम पर सेवा को पैच करें (अगला अनुभाग)। + +#### रनटाइम पर व्हाइटलिस्ट अपडेट करें + +आप Helm अपग्रेड किए बिना सेवा को सीधे पैच करके अनुमत IP बदल सकते हैं। **पैच संपूर्ण सूची को बदलता है**; हमेशा प्रत्येक IP को शामिल करें जिसे आप रखना चाहते हैं, केवल नया नहीं। + +नए IP के एक सेट के साथ सूची को बदलने के लिए: + +```bash +kubectl patch svc traefik-dashboard -n traefik-dashboard \ + -p '{"spec":{"loadBalancerSourceRanges":["203.0.113.10/32","198.51.100.0/24","192.0.2.50/32"]}}' +``` + +मौजूदा प्रविष्टियों को खोए बिना एक IP को सुरक्षित रूप से **जोड़ने के लिए**, पहले वर्तमान सूची पढ़ें, फिर संयुक्त सेट के साथ पैच करें: + +```bash +# 1. वर्तमान allowlist दिखाएं +kubectl get svc traefik-dashboard -n traefik-dashboard \ + -o jsonpath='{.spec.loadBalancerSourceRanges}' + +# 2. पूर्ण सूची के साथ पैच करें जिसमें नया IP शामिल है +kubectl patch svc traefik-dashboard -n traefik-dashboard \ + -p '{"spec":{"loadBalancerSourceRanges":["/32","/32","/32"]}}' +``` + +> रनटाइम पैच `values-dashboard.yaml` में वापस परसिस्ट नहीं होते हैं। भविष्य के Helm अपग्रेड में परिवर्तन को रखने के लिए, मान फ़ाइल को भी अपडेट करें और इसे प्रतिबद्ध करें। + +फिर इंस्टॉल करें: + +```bash +helm install traefik-dashboard traefik/traefik \ + --namespace traefik-dashboard --create-namespace \ + --version 39.0.8 \ + -f third-party/traefik/values-dashboard.yaml +``` + +**इसे टेस्ट करें:** + +```bash +kubectl get pods -n traefik-dashboard +``` + +अपेक्षित: 1 पॉड `Running`। + +```bash +kubectl get ingressclass traefik-dashboard +``` + +अपेक्षित: IngressClass मौजूद है। + +--- + +### 1.4 LoadBalancers के लिए प्रतीक्षा करें + +आगे बढ़ने से पहले दोनों Traefik उदाहरणों को बाहरी IP की आवश्यकता है। + +```bash +kubectl get svc -n traefik-public +kubectl get svc -n traefik-dashboard +``` + +**इसे टेस्ट करें:** दोनों सेवाएं एक `EXTERNAL-IP` (`` नहीं) दिखाते हैं। + +अभी भी लंबित हो तो असाइनमेंट के लिए देखें: + +```bash +kubectl get svc -n traefik-public -w +``` + +IP प्रकट होने के बाद `Ctrl+C` दबाएं। IP असाइनमेंट आमतौर पर 2--5 मिनट लगता है। + +**यदि यह विफल होता है:** 10 मिनट के बाद `` आमतौर पर मतलब है क्लाउड प्रदाता LoadBalancer प्रावधान नहीं कर सकता। जांचें: सबनेट टैग (EKS को `kubernetes.io/role/elb` की आवश्यकता है), VPC कॉन्फ़िगरेशन, सेवा कोटा, और सही आंतरिक LB एनोटेशन आंतरिक उदाहरण के लिए सेट है। + +--- + +## Phase 2 -- सीक्रेट्स बनाएं (~10 मिनट) + +सभी सीक्रेट्स आवेदन को डिप्लॉय करने से पहले मैन्युअल रूप से बनाई जाती हैं। यह सुनिश्चित करता है कि संवेदनशील मानों कभी मैनिफेस्ट फ़ाइलों में प्रकट नहीं होते हैं। + +### 2.1 नेमस्पेस बनाएं + +```bash +kubectl create namespace agenteye +``` + +**इसे टेस्ट करें:** + +```bash +kubectl get namespace agenteye +``` + +अपेक्षित: स्थिति `Active`। + +--- + +### 2.2 इमेज पुल सीक्रेट + +यह सीक्रेट `ghcr.io` के साथ AgentEye कंटेनर इमेज खींचने के लिए प्रमाणीकरण करता है। अपनी PAT कैसे उत्पन्न करें के लिए [enterprise-docs/github-token.md](/hi/agenteye/github-token) देखें। + +```bash +kubectl create secret docker-registry agenteye-image-pull \ + --namespace agenteye \ + --docker-server=ghcr.io \ + --docker-username=agenteye-enterprise \ + --docker-password="${AGENTEYE_TOKEN}" +``` + +**इसे टेस्ट करें:** + +```bash +kubectl get secret agenteye-image-pull -n agenteye -o jsonpath='{.type}' +``` + +अपेक्षित: `kubernetes.io/dockerconfigjson`। + +**गहरे से इसे टेस्ट करें** -- सत्यापित करें कि टोकन वास्तव में इमेज खींच सकता है: + +अपने ओवरले के `kustomization.yaml` में पिन किए गए `server` इमेज टैग का उपयोग करें (वर्तमान में बंडल `acme` ओवरले और बेस डिप्लॉयमेंट दोनों में `v0.0.1-beta.48`)। यह जांच अभी सही रहे ताकि नीचे दिए गए टैग को प्रतिस्थापित करें जो आप डिप्लॉय कर रहे हैं: + +```bash +kubectl run test-pull \ + --image=ghcr.io/agenteye-enterprise/server:v0.0.1-beta.48 \ + --overrides='{"spec":{"imagePullSecrets":[{"name":"agenteye-image-pull"}]}}' \ + --restart=Never -n agenteye --command -- echo ok + +# खींचने के लिए कुछ सेकंड प्रतीक्षा करें, फिर: +kubectl logs test-pull -n agenteye +kubectl delete pod test-pull -n agenteye +``` + +अपेक्षित: लॉग्स में `ok` प्रिंट होता है। + +**यदि यह विफल होता है:** `ErrImagePull` या `401 Unauthorized` मतलब है PAT अमान्य है या `read:packages` स्कोप की कमी है। [enterprise-docs/github-token.md](/hi/agenteye/github-token) को फिर से जांचें। + +--- + +### 2.3 PostgreSQL क्रेडेंशियल्स + +```bash +POSTGRES_PASSWORD=$(openssl rand -hex 24) + +kubectl create secret generic agenteye-postgres \ + --namespace agenteye \ + --from-literal=POSTGRES_USER=postgres \ + --from-literal=POSTGRES_PASSWORD="${POSTGRES_PASSWORD}" \ + --from-literal=POSTGRES_DB=agenteye +``` + +> **महत्वपूर्ण:** हम `-hex` (न कि `-base64`) का उपयोग पासवर्ड उत्पन्न करने के लिए करते हैं। Base64 आउटपुट `+`, `/`, और `=` रखते हैं जो `DATABASE_URL` कनेक्शन स्ट्रिंग को तोड़ते हैं। विवरण के लिए [enterprise-docs/troubleshooting.md](/hi/agenteye/troubleshooting) देखें। + +> **`POSTGRES_PASSWORD` को अपने सीक्रेट्स मैनेजर में तुरंत स्टोर करें।** यदि आप कभी बैकअप से पुनर्स्थापित करते हैं या सीधे डेटाबेस से कनेक्ट करते हैं तो आपको इसकी आवश्यकता होगी। + +**इसे टेस्ट करें:** + +```bash +kubectl get secret agenteye-postgres -n agenteye +``` + +अपेक्षित: सीक्रेट मौजूद है। + +```bash +kubectl get secret agenteye-postgres -n agenteye \ + -o jsonpath='{.data.POSTGRES_PASSWORD}' | base64 -d | wc -c +``` + +अपेक्षित: `48` (24 hex बाइट्स = 48 वर्ण)। + +--- + +### 2.4 Admin API कुंजी + +```bash +ADMIN_KEY=$(openssl rand -hex 32) + +kubectl create secret generic agenteye-admin-key \ + --namespace agenteye \ + --from-literal=ADMIN_KEY="${ADMIN_KEY}" +``` + +Admin कुंजी bootstrap क्रेडेंशियल है। सर्वर हर स्टार्टअप पर इसे सभी अनुमतियों के साथ upsert करता है। Phase 7 में स्कॉप्ड कलेक्टर कुंजियां बनाने के लिए इसका उपयोग करें। पूर्ण अनुमति मॉडल के लिए [enterprise-docs/api-keys.md](/hi/agenteye/api-keys) देखें। + +> **`ADMIN_KEY` को अपने सीक्रेट्स मैनेजर में तुरंत स्टोर करें।** + +**इसे टेस्ट करें:** + +```bash +kubectl get secret agenteye-admin-key -n agenteye +``` + +अपेक्षित: सीक्रेट मौजूद है। + +--- + +### 2.5 Auth कॉन्फ़िगरेशन (डैशबोर्ड लॉगिन) + +डैशबोर्ड यूज़र लॉगिन के लिए ईमेल + OTP का उपयोग करता है। इस सीक्रेट के बिना सर्वर अभी भी शुरू होता है और `ADMIN_KEY` API पाथ काम करता रहता है, लेकिन **कोई यूज़र UI के माध्यम से लॉगिन नहीं कर सकता**। + +सभी कुंजियां बेस मैनिफेस्ट में `optional: true` के रूप में संदर्भित होती हैं, इसलिए आंशिक सीक्रेट्स (या कोई सीक्रेट नहीं) ठीक है; सर्वर प्रलेखित डिफ़ॉल्ट्स पर वापस आते हैं। सब कुछ एक `agenteye-auth` सीक्रेट में बंडल करना auth सतह को एक जगह में घुमाने योग्य रखता है। + +```bash +kubectl create secret generic agenteye-auth \ + --namespace agenteye \ + --from-literal=ADMIN_EMAIL="admin@yourcompany.com" \ + --from-literal=ALLOWED_EMAILS="*@yourcompany.com" \ + --from-literal=SMTP_HOST="smtp.yourprovider.com" \ + --from-literal=SMTP_PORT="587" \ + --from-literal=SMTP_USERNAME="your-smtp-user" \ + --from-literal=SMTP_PASSWORD="your-smtp-password" \ + --from-literal=SMTP_FROM="noreply@yourcompany.com" \ + --from-literal=SMTP_TLS="starttls" \ + --from-literal=DEFAULT_ORG_NAME="Acme Corp" \ + --from-literal=DEFAULT_ORG_SLUG="acme" +``` + +| कुंजी | उद्देश्य | +|---|---| +| `ADMIN_EMAIL` | Bootstrap admin यूज़र। सभी अनुमतियों के साथ हर स्टार्टअप पर upsert किया जाता है और डैशबोर्ड से हटाए जाने/अनुमति संपादन के खिलाफ सुरक्षित। इसके बिना, कोई admin seed नहीं है और पहली लॉगिन असंभव है। | +| `ALLOWED_EMAILS` | कॉमा-अलग allowlist। सटीक पते (`user@example.com`) और डोमेन वाइल्डकार्ड (`*@example.com`) समर्थन करता है। इसके बिना, **कोई यूज़र लॉगिन या बनाया नहीं जा सकता**। | +| `SMTP_HOST`, `SMTP_PORT`, `SMTP_USERNAME`, `SMTP_PASSWORD`, `SMTP_FROM` | OTP कोड्स भेजने के लिए SMTP रिले। यदि `SMTP_HOST` सेट नहीं है, OTP कोड्स सर्वर के stdout में लॉग होते हैं (पहली-बूट स्मोक टेस्ट्स के लिए उपयोगी)। असली ईमेल डिलीवरी के लिए सभी SMTP कुंजियां प्रदान करें। | +| `SMTP_TLS` | `starttls` (डिफ़ॉल्ट), `tls`, या `none` में से एक। | +| `DEFAULT_ORG_NAME`, `DEFAULT_ORG_SLUG` | वैकल्पिक। बिल्ट-इन `default` संगठन को एक अनुकूल प्रदर्शन नाम और URL स्लग दें ताकि यह उदाहरण `/acme` पर रहे `/default` के बजाय। **पहले बूट पर ही** लागू किया जाता है; एक बार जब आप `agenteye-orgctl org rename` (देखें §7.6) से संगठन का नाम बदल देते हैं तो ये अनदेखे होते हैं। स्लग 1--40 लोअरकेस अल्फान्यूमेरिक्स होना चाहिए एकल आंतरिक हाइफन के साथ। दोनों को सेट न करें सामान्य `default` रखने के लिए। | + +> **SMTP क्रेडेंशियल्स को अपने सीक्रेट्स मैनेजर में स्टोर करें।** + +**इसे टेस्ट करें:** + +```bash +kubectl get secret agenteye-auth -n agenteye \ + -o jsonpath='{.data}' | grep -o '"[A-Z_]*"' | sort -u +``` + +अपेक्षित: आप भरी गई कुंजियां आउटपुट में दिखाई देती हैं। + +--- + +### 2.6 Multi-tenant org अलगाव कुंजी (वैकल्पिक) + +एकल-टेनेंट डिप्लॉयमेंट के लिए छोड़ें; सर्वर बिल्ट-इन dev default पर चलता है और एक `default` org ठीक से सेवा करता है। **इससे पहले कि आप दूसरा संगठन बनाएं**, एक मजबूत, स्थिर `ORG_CH_SECRET` सेट करें: प्रत्येक org का ClickHouse पासवर्ड `HMAC(ORG_CH_SECRET, org_id)` के रूप में व्युत्पन्न किया जाता है, इसलिए सार्वजनिक रूप से ज्ञात dev default सार्वजनिक रूप से-व्युत्पन्न प्रति-org क्रेडेंशियल्स देता। `agenteye-orgctl org create` कमांड (देखें [§7.6 संगठनों को प्रावधान करें](#76-provision-organizations-multi-tenant)) सर्वर अभी भी बिल्ट-इन dev default पर होने के दौरान चलने से इनकार करता है। + +```bash +kubectl create secret generic agenteye-org-ch-secret \ + --namespace agenteye \ + --from-literal=ORG_CH_SECRET="$(openssl rand -base64 48)" + +# सर्वर को रोल करें ताकि यह नई value लें। +kubectl -n agenteye rollout restart deployment/server +``` + +सर्वर एक **optional** `secretKeyRef` के माध्यम से यह पढ़ता है, इसलिए एकल-टेनेंट क्लस्टर जो कभी इसे नहीं बनाता अभी भी सामान्य रूप से बूट होता है। मान को **स्थिर और सभी प्रतिकृतियों में समान** रखें; इसे घुमाना हर org के व्युत्पन्न ClickHouse पासवर्ड को अमान्य करता है जब तक अगली बूट-टाइम reconcile फिर से प्रावधान नहीं करता (मान के साथ सभी जगह सुसंगत होने के साथ एक रोलिंग रीस्टार्ट इसे ठीक करता है)। `deploy/base/server/secret.example.yaml` देखें। + +> **`ORG_CH_SECRET` को अपने सीक्रेट्स मैनेजर में स्टोर करें और इसे आकस्मिक रूप से घुमाएं न करें।** + +--- + +### 2.7 सभी सीक्रेट्स सत्यापित करें + +```bash +kubectl get secrets -n agenteye -o custom-columns='NAME:.metadata.name,TYPE:.type' +``` + +अपेक्षित आउटपुट (किसी भी डिफ़ॉल्ट सीक्रेट्स में): + +``` +NAME TYPE +agenteye-admin-key Opaque +agenteye-auth Opaque +agenteye-image-pull kubernetes.io/dockerconfigjson +agenteye-postgres Opaque +agenteye-org-ch-secret Opaque # केवल यदि आपने §2.6 पूरा किया (multi-tenant) +``` + +चार कोर सीक्रेट्स (`agenteye-admin-key`, `agenteye-auth`, `agenteye-image-pull`, `agenteye-postgres`) आगे बढ़ने से पहले मौजूद होने चाहिए। `agenteye-org-ch-secret` केवल multi-tenant डिप्लॉयमेंट के लिए आवश्यक है (देखें §2.6)। + +--- + +## Phase 3 -- आवेदन डिप्लॉय करें (~5 मिनट) + +### 3.1 सार्वजनिक होस्टनाम कॉन्फ़िगर करें + +cert-manager को अपनी Let's Encrypt प्रमाणपत्र मांगने से पहले इंजेस्ट और डैशबोर्ड होस्टनाम की आवश्यकता है। टेम्पलेट को कॉपी करें और दोनों सेट करें: + +```bash +cp base/certificates/domain.env.example base/certificates/domain.env +# base/certificates/domain.env को संपादित करें और सेट करें: +# INGEST_DOMAIN=ingest.your-company.example (सार्वजनिक Traefik LB को resolves) +# DASHBOARD_DOMAIN=agenteye.your-company.example (डैशबोर्ड Traefik LB को resolves) +``` + +`domain.env` gitignored है; यह प्रत्येक डिप्लॉयमेंट के लिए स्थानीय रहता है। kustomize build विफल हो जाता है अगर कोई भी कुंजी लापता है। + +> **DNS को पहले resolve करना चाहिए।** आपको LB पर DNS इंगित करने की आवश्यकता नहीं है (वे Phase 1.2 तक मौजूद नहीं हैं), लेकिन Phase 3.2 में ACME issuance तब तक पुनः प्रयास करेगा जब तक प्रत्येक होस्टनाम अपने LoadBalancer को resolve न करे। आप अभी DNS सेट कर सकते हैं (Phase 1.4 में कैप्चर किए गए LB होस्टनाम का उपयोग करके) या आगे बढ़ें और Phase 4 में रिकॉर्ड जोड़ें। + +--- + +### 3.2 मैनिफेस्ट्स लागू करें + +ताज़ी स्थापना के लिए आधार को सीधे लागू करें, या एक ओवरले यदि आपने इस पर्यावरण के लिए कटा है (ओवरले्स केवल इमेज टैग, env vars और संसाधन सीमाएं पिन करते हैं; वे आधार के certs और रूटिंग को विरासत देते हैं): + +```bash +kubectl apply -k base/ +# या +kubectl apply -k overlays// +``` + +ओवरले में आधार स्वचालित रूप से शामिल होता है; दोनों को नहीं, एक को लागू करें। + +--- + +### 3.3 पॉड्स के लिए प्रतीक्षा करें + +```bash +kubectl wait --for=condition=Ready pod -l 'app in (server,dashboard,postgres,clickhouse)' \ + -n agenteye --timeout=180s +``` + +प्रतीक्षा कोर डेटा-प्लेन पॉड्स पर स्कॉप की जाती है। वैकल्पिक `agent` (AI असिस्टेंट) और `redis` पॉड्स उनके साथ आते हैं; असिस्टेंट तब तक निष्क्रिय रहता है जब तक आप इसे LLM एंडपॉइंट न दें ([enterprise-docs/assistant.md](/hi/agenteye/assistant) देखें), और Redis एक सर्वश्रेष्ठ-प्रयास कैश है, इसलिए प्लेटफॉर्म को ट्रैफिक परोसने के लिए न ही Ready होने की आवश्यकता है। + +**इसे टेस्ट करें:** + +```bash +kubectl get pods -n agenteye +``` + +अपेक्षित (वैकल्पिक `agent` और `redis` पॉड्स भी दिखाई देते हैं और `Running` तक पहुंचते हैं): + +``` +NAME READY STATUS RESTARTS AGE +agent-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +clickhouse-0 1/1 Running 0 ... +dashboard-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +dashboard-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +postgres-0 1/1 Running 0 ... +redis-0 1/1 Running 0 ... +server-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +server-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +``` + +**यदि यह विफल होता है:** + +| पॉड स्थिति | संभावित कारण | डीबग कमांड | +|---|---|---| +| `ImagePullBackOff` | खराब इमेज पुल सीक्रेट या PAT | `kubectl describe pod -n agenteye` | +| `CrashLoopBackOff` | खराब environment variables (उदाहरण DATABASE_URL) | `kubectl logs -n agenteye` | +| `Pending` | अपर्याप्त CPU/memory या कोई नोड्स नहीं | `kubectl describe pod -n agenteye` (Events जांचें) | + +--- + +### 3.4 स्टोरेज सत्यापित करें + +```bash +kubectl get pvc -n agenteye +``` + +अपेक्षित, दोनों `Bound` स्थिति के साथ: + +| PVC | क्षमता | समर्थन | +|---|---|---| +| `postgres-data-postgres-0` | `50Gi` | PostgreSQL relational/metadata store | +| `clickhouse-data-clickhouse-0` | `100Gi` | ClickHouse events + evaluations analytics store | + +वैकल्पिक कैश के लिए `redis-data-redis-0` PVC (1Gi) भी दिखाई देता है। + +**यदि यह विफल होता है:** `Pending` मतलब कोई StorageClass वॉल्यूम प्रावधान नहीं कर सकता। `kubectl get storageclass` जांचें और सुनिश्चित करें डिफ़ॉल्ट मौजूद है। उत्पादन के लिए, ClickHouse वॉल्यूम को एक तेज़ SSD StorageClass पर ओवरले करें (उदाहरण AWS पर gp3, GCP पर pd-ssd); संकुचन थ्रूपुट धीमी डिस्क पर पीड़ित होता है। + +--- + +### 3.5 प्रमाणपत्र सत्यापित करें + +```bash +kubectl get certificates -n agenteye +``` + +अपेक्षित: 3 प्रमाणपत्र, सभी `Ready: True`: + +| नाम | जारीकर्ता | उद्देश्य | +|---|---|---| +| `mtls-ca` | `selfsigned` | mTLS क्लाइंट certs जारी करने के लिए निजी CA (10-वर्ष वैधता) | +| `ingest-tls` | `letsencrypt-prod` | इंजेस्ट एंडपॉइंट के लिए सार्वजनिक TLS प्रमाणपत्र (90-दिन, ऑटो-नवीनीकरण) | +| `dashboard-tls` | `letsencrypt-prod` | डैशबोर्ड के लिए सार्वजनिक TLS प्रमाणपत्र (90-दिन, ऑटो-नवीनीकरण) | + +**यदि `ingest-tls` या `dashboard-tls` तैयार नहीं है:** + +`kubectl describe certificate -n agenteye` और Events पढ़ें। सामान्य कारण: + +- **DNS अभी LB की ओर इशारा नहीं करता।** Let's Encrypt होस्टनाम resolve करता है और HTTP-01 के लिए port 80 पर हिट करता है -- `INGEST_DOMAIN` को सार्वजनिक LB को resolve करना चाहिए, `DASHBOARD_DOMAIN` को डैशबोर्ड LB को। जब तक CNAME/Alias प्रचारित नहीं होता, order `pending` रहता है। एक बार DNS सही है, cert-manager स्वचालित रूप से पुनः प्रयास करता है (Certificate हटाने की आवश्यकता नहीं)। +- **होस्टनाम प्रतिस्थापित नहीं।** यदि `dnsNames` अभी भी `INGEST_DOMAIN_PLACEHOLDER` / `DASHBOARD_DOMAIN_PLACEHOLDER` पढ़ते हैं, आप step 3.1 छोड़ गए -- `base/certificates/domain.env` बनाएं और फिर से लागू करें। +- **डैशबोर्ड Traefik चुनौती परोस नहीं सकता** (`dashboard-tls` केवल)। डैशबोर्ड Traefik उदाहरण को बंडल मान फ़ाइल के साथ स्थापित किया जाना चाहिए (Phase 1.2), जो scoped Ingress प्रदाता को सक्षम करता है जो cert-manager के HTTP-01 सॉल्वर को परोसता है। इसके बिना स्थापित एक उदाहरण चुनौती को unroutable रखता है और order `pending` हमेशा के लिए। + +**यदि `mtls-ca` तैयार नहीं है:** cert-manager अस्वस्थ है। Phase 1.1 से cert-manager पॉड्स फिर से जांचें। + +--- + +### 3.6 CronJobs सत्यापित करें + +```bash +kubectl get cronjobs -n agenteye +``` + +अपेक्षित: + +| नाम | अनुसूची | उद्देश्य | +|---|---|---| +| `agenteye-backup` | `0 3 * * *` | 03:00 UTC पर दैनिक Postgres + ClickHouse backup | +| `cert-renewal-check` | `0 3,15 * * *` | 03:00 और 15:00 UTC पर प्रमाणपत्र समाप्ति सतर्कता | + +--- + +### 3.7 सर्वर सत्यापित करें ठीक से शुरू हुआ + +```bash +kubectl logs -n agenteye -l app=server --tail=20 +``` + +**इसे टेस्ट करें:** एक स्टार्टअप लाइन खोजें जो सर्वर को port 8080 पर सुनते हुए सूचित करे। कोई डेटाबेस कनेक्शन त्रुटि नहीं होनी चाहिए (सर्वर को तैयार रिपोर्ट करने से पहले PostgreSQL और ClickHouse दोनों तक पहुंचने योग्य होने की आवश्यकता है)। + +**यदि यह विफल होता है:** सबसे सामान्य कारण एक `POSTGRES_PASSWORD` URL-असुरक्षित वर्णों को समाहित करना है जो `DATABASE_URL` को तोड़ते हैं। [enterprise-docs/troubleshooting.md](/hi/agenteye/troubleshooting) देखें। + +--- + +### 3.8 डैशबोर्ड सर्वर से जुड़ा सत्यापित करें + +```bash +kubectl logs -n agenteye -l app=dashboard --tail=20 +``` + +**इसे टेस्ट करें:** आउटपुट में `Ready` खोजें `ECONNREFUSED` या समान त्रुटियों के साथ नहीं। + +**यदि यह विफल होता है:** जांचें कि `server` Service मौजूद है (`kubectl get svc server -n agenteye`) और `AGENTEYE_SERVER_URL` डैशबोर्ड डिप्लॉयमेंट में `http://server:8080` पर सेट है। + +--- + +## Phase 4 -- नेटवर्क एक्सेस (~5 मिनट) + +### 4.1 LoadBalancer पते प्राप्त करें + +```bash +PUBLIC_IP=$(kubectl get svc -n traefik-public \ + -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') + +INTERNAL_IP=$(kubectl get svc -n traefik-dashboard \ + -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') +``` + +> AWS EKS पर, LoadBalancers एक IP के बजाय होस्टनाम लौटाते हैं। ऊपर दिए गए कमांड्स में `.ip` को `.hostname` के साथ बदलें। + +**इसे टेस्ट करें:** + +```bash +echo "Public (ingest): $PUBLIC_IP" +echo "Internal (dashboard): $INTERNAL_IP" +``` + +दोनों गैर-खाली होने चाहिए। + +--- + +### 4.2 LoadBalancers पर DNS इंगित करें + +DNS रिकॉर्ड्स बनाएं ताकि `base/certificates/domain.env` से होस्टनाम अपने LoadBalancers को resolve करें -- `INGEST_DOMAIN` **सार्वजनिक** Traefik LB को, `DASHBOARD_DOMAIN` **डैशबोर्ड** Traefik LB को: + +- **AWS Route 53:** `A` रिकॉर्ड `Alias = Yes` के साथ, target = LB होस्टनाम। सादा A → IP न करें; ELB IPs घूमते हैं। +- **कोई अन्य प्रदाता:** `CNAME` होस्टनाम से LB होस्टनाम को। + +सत्यापित करें: + +```bash +dig +short ingest.your-company.example +dig +short agenteye.your-company.example +``` + +क्रमशः `$PUBLIC_IP` और `$INTERNAL_IP` जैसे ही पते लौटाना चाहिए (या, EKS पर, समान `*.elb.amazonaws.com` होस्टनाम को resolve करें)। + +एक बार DNS resolve करने के बाद, cert-manager Phase 3.5 से लंबित ACME ऑर्डर्स को एक मिनट के अंदर समाप्त करता है। दोनों `ingest-tls` और `dashboard-tls` `Ready: True` दिखाने तक `kubectl get certificates -n agenteye` फिर से चलाएं। + +--- + +### 4.3 इंजेस्ट एंडपॉइंट तक पहुंचें + +सार्वजनिक इंजेस्ट एंडपॉइंट पारस्परिक TLS को लागू करता है, इसलिए हर अनुरोध (including `/health`) एक क्लाइंट प्रमाणपत्र प्रस्तुत करना चाहिए। आप Phase 5 में अपना पहली क्लाइंट प्रमाणपत्र जारी करते हैं; यदि आपके पास पहले से एक है, अब पहुंच योग्यता सत्यापित करें: + +```bash +curl -s --cert issued//client.crt \ + --key issued//client.key \ + https://ingest.your-company.example/health +``` + +अपेक्षित: `{"status":"ok"}`। कोई `-k` की आवश्यकता नहीं -- सर्वर प्रमाणपत्र `INGEST_DOMAIN` के लिए सार्वजनिक CA में श्रृंखला, इसलिए यह सिस्टम ट्रस्ट स्टोर के विरुद्ध सत्यापित करता है। कच्चे LoadBalancer IP/होस्टनाम द्वारा नहीं, अपने `INGEST_DOMAIN` होस्टनाम द्वारा इंजेस्ट एंडपॉइंट तक पहुंचें (जो जारी प्रमाणपत्र से मेल खाता है)। + +डैशबोर्ड एंडपॉइंट `DASHBOARD_DOMAIN` पर एक सार्वजनिक रूप से विश्वसनीय प्रमाणपत्र के साथ परोसा जाता है और mTLS के पीछे नहीं है, इसलिए कोई `-k` और कोई क्लाइंट प्रमाणपत्र नहीं: + +```bash +curl -s https://agenteye.your-company.example/ -o /dev/null -w '%{http_code}\n' +``` + +कच्चे LB पते द्वारा नहीं, अपने होस्टनाम द्वारा डैशबोर्ड तक पहुंचें -- प्रमाणपत्र `DASHBOARD_DOMAIN` से बंधा है, इसलिए कच्चे पते पर प्रमाणपत्र-नाम mismatch दिखाई देता है। + +**यदि यह विफल होता है:** यदि `curl` लटकता है, जांचें क \ No newline at end of file diff --git a/docs/hi/agenteye/managed-deployment.mdx b/docs/hi/agenteye/managed-deployment.mdx new file mode 100644 index 00000000..a0ad07b5 --- /dev/null +++ b/docs/hi/agenteye/managed-deployment.mdx @@ -0,0 +1,172 @@ +--- +--- +title: "आपके Kubernetes क्लस्टर पर प्रबंधित परिनियोजन" +description: "आपके Kubernetes क्लस्टर पर AgentEye प्रबंधित परिनियोजन दस्तावेज़।" +--- + + +AgentEye एक स्व-होस्ट किया गया अवलोकनशीलता और मूल्यांकन मंच है AI और LLM एजेंट्स के लिए। यह एजेंट सेशन, टूल कॉल, मॉडल अनुरोध और त्रुटियों को कैप्चर करता है, उन्हें खोजने योग्य विश्लेषण और मूल्यांकन में बदल देता है, और परिणामों को एक डैशबोर्ड में प्रदर्शित करता है जिसमें एक वैकल्पिक केवल-पढ़ने के लिए AI सहायक होता है। + +प्रबंधित परिनियोजन मॉडल में, आप एक समर्पित Kubernetes क्लस्टर प्रदान करते हैं और Exosphere इसके अंदर पूरा मंच चलाता है, आपकी ओर से हर घटक को परिनियोजित, कॉन्फ़िगर, संचालित, बैकअप और अपग्रेड करता है। आपकी टीम को प्लेटफॉर्म का मूल्य मिलता है (एजेंट दृश्यता, विश्लेषण, मूल्यांकन, और वैकल्पिक सहायक) डेटाबेस, प्रमाणपत्र या अपग्रेड संचालित किए बिना। सभी डेटा आपके क्लाउड खाते के भीतर रहता है। + +--- + +## पूर्वापेक्षाएं + +- एक **GitHub PAT** कंटेनर इमेज खींचने और आर्टिफैक्ट डाउनलोड करने के लिए ([GitHub Token सेटअप](/hi/agenteye/github-token) देखें) +- एक **समर्पित Kubernetes क्लस्टर** (नीचे आवश्यकताएं देखें) +- डेटाबेस बैकअप के लिए एक **स्टोरेज बकेट** +- **नेटवर्क कनेक्टिविटी**: क्लस्टर के लोड बैलेंसर के लिए पोर्ट 443 इनबाउंड + +--- + +## चरण 1: एक समर्पित Kubernetes क्लस्टर प्रदान करें + +AgentEye के लिए एक समर्पित Kubernetes क्लस्टर बनाएं। इसे अन्य कार्यभार के साथ साझा नहीं किया जाना चाहिए, ताकि पूरा प्लेटफॉर्म (एप्लिकेशन सेवाएं, डेटाबेस, विश्लेषण और कैशिंग) अलगाव में चले और आपके मौजूदा बुनियादी ढांचे को प्रभावित न करे। + +| आवश्यकता | विवरण | +|---|---| +| **वितरण** | कोई भी अनुरूप Kubernetes: EKS, GKE, AKS, या स्व-प्रबंधित | +| **संस्करण** | 1.27 या बाद में | +| **नोड पूल** | न्यूनतम: **3 नोड्स, प्रत्येक 4 vCPU / 8 GB RAM** (मानक सामान्य प्रयोजन इंस्टेंस) | +| **स्टोरेज** | एक डिफ़ॉल्ट StorageClass जो ब्लॉक वॉल्यूम प्रदान करता है (AWS पर `gp3`, GCP पर `pd-ssd`) | +| **लोड बैलेंसर** | क्लस्टर को क्लाउड LoadBalancer सेवाएं प्रदान करने में सक्षम होना चाहिए (EKS, GKE, AKS पर डिफ़ॉल्ट) | + +> Exosphere क्लस्टर के अंदर सब कुछ इंस्टॉल और प्रबंधित करता है: इनग्रेस कंट्रोलर, TLS प्रमाणपत्र, डेटाबेस, कैशिंग, निगरानी, और सभी एप्लिकेशन परिनियोजन। + +--- + +## चरण 2: AgentEye टीम को पहुंच प्रदान करें + +Exosphere को cluster-admin पहुंच (या समतुल्य व्यापक RBAC) की आवश्यकता है नेमस्पेस, कस्टम रिसोर्स परिभाषा, इनग्रेस कंट्रोलर और स्टोरेज provisioners प्रबंधित करने के लिए। + +| आवश्यकता | विवरण | +|---|---| +| **पहुंच विधि** | IAM भूमिका (EKS/GKE के लिए पसंदीदा), kubeconfig, या SSO-आधारित पहुंच | +| **VPN / बेस्टियन** | यदि Kubernetes API सर्वर निजी है, तो Exosphere संचालन टीम के लिए VPN क्रेडेंशियल या बेस्टियन पहुंच प्रदान करें | + +--- + +## चरण 3: नेटवर्क कनेक्टिविटी कॉन्फ़िगर करें + +आपकी नेटवर्क टीम को क्लस्टर के लोड बैलेंसर में **पोर्ट 443** पर इनबाउंड ट्रैफिक की अनुमति देनी चाहिए। परिनियोजन दो अलग-अलग लोड बैलेंसर चलाता है: एक इवेंट इनजेस्शन के लिए (mTLS-सुरक्षित) और एक डैशबोर्ड के लिए: + +| ट्रैफिक | स्रोत | गंतव्य | सुरक्षा | +|---|---|---|---| +| **इवेंट इनजेस्शन** | आपके क्लस्टर में कलेक्टर पॉड्स | Ingest LoadBalancer, पोर्ट 443 | mTLS (क्लाइंट प्रमाणपत्र) + API कुंजी | +| **डैशबोर्ड** | डेवलपर ब्राउज़र | Dashboard LoadBalancer, पोर्ट 443 | आपके डोमेन पर HTTPS, पासवर्ड-रहित ईमेल OTP साइन-इन | + +ingest एंडपॉइंट पारस्परिक TLS द्वारा सुरक्षित है; कलेक्टर को हर अनुरोध पर एक वैध क्लाइंट प्रमाणपत्र **और** एक वैध API कुंजी प्रस्तुत करनी चाहिए। डैशबोर्ड अपने स्वयं के लोड बैलेंसर और होस्टनाम पर चलता है, साइन-इन आपके अनुमति सूची में डाले गए ईमेल पते/डोमेन तक सीमित है। + +**DNS रिकॉर्ड (एक बार):** आप अपने नियंत्रण वाले एक डोमेन के तहत दो CNAME रिकॉर्ड बनाते हैं — एक ingest एंडपॉइंट के लिए और एक डैशबोर्ड के लिए (जैसे `agenteye.your-company.example`) — Exosphere द्वारा प्रदान किए गए लोड बैलेंसर होस्टनाम की ओर इशारा करते हुए। Exosphere फिर दोनों होस्टनाम के लिए सार्वजनिक रूप से विश्वस्त TLS प्रमाणपत्र स्वचालित रूप से प्रदान करता है, नवीकरण सहित। + +> **पोर्ट 80 नोट:** स्वचालित प्रमाणपत्र जारी करना और नवीकरण प्रत्येक लोड बैलेंसर के पोर्ट 80 पर HTTP पर सत्यापित करते हैं। यदि आपकी सुरक्षा स्थिति के लिए डैशबोर्ड लोड बैलेंसर को कॉर्पोरेट IP श्रेणियों तक सीमित करने की आवश्यकता है, तो पहले Exosphere को बताएं — हम प्रमाणपत्र सत्यापन को एक DNS-आधारित विधि में स्विच करते हैं (आपकी ओर से एक अतिरिक्त DNS रिकॉर्ड) ताकि नवीकरण प्रतिबंध के पीछे काम करते रहें। + +> **आउटबाउंड:** क्लस्टर नोड्स को `ghcr.io` से कंटेनर इमेज खींचने के लिए इंटरनेट पहुंच की आवश्यकता है। यदि आपका नेटवर्क आउटबाउंड ट्रैफिक को प्रतिबंधित करता है, तो `ghcr.io` को अनुमति दें या इमेज को अपने आंतरिक रजिस्ट्री में मिरर करें। + +--- + +## चरण 4: एक बैकअप स्टोरेज बकेट प्रदान करें + +डेटाबेस बैकअप एक क्लाउड स्टोरेज बकेट में संग्रहीत होते हैं जिसके आप मालिक हैं। + +| आवश्यकता | विवरण | +|---|---| +| **सेवा** | S3 (AWS), GCS (GCP), या Azure Blob Storage | +| **पहुंच** | IAM भूमिका (EKS पर IRSA, GKE पर Workload Identity) या क्रेडेंशियल के माध्यम से क्लस्टर के नोड्स को लिखने के लिए पहुंच प्रदान करें | +| **प्रतिधारण** | आप बकेट की जीवनचक्र नीति को नियंत्रित करते हैं (प्रतिधारण अवधि, संग्रह नियम)। Exosphere बैकअप लिखता है; आप तय करते हैं कि उन्हें कितने समय तक रखना है | + +एक एकल दैनिक बैकअप PostgreSQL (संबंधपरक स्थिति) और ClickHouse (इवेंट और मूल्यांकन) दोनों को एक संपीड़ित संग्रह में डंप करता है और इसे आपके बकेट में अपलोड करता है। बैकअप हर अपग्रेड से पहले भी चलते हैं। + +--- + +## चरण 5: एक संपर्क व्यक्ति नामित करें + +क्लस्टर-स्तरीय समस्याओं के लिए आपकी ओर से एक व्यक्ति या Slack/Teams चैनल प्रदान करें: नोड स्वास्थ्य, क्लाउड खाता सीमा, नेटवर्क परिवर्तन। दिन-प्रतिदिन की संचालन में इस संपर्क को शामिल नहीं किया जाता है। + +--- + +## हम क्या परिनियोजित करते हैं + +एक बार Exosphere को क्लस्टर पहुंच मिलने के बाद, निम्नलिखित घटकों को परिनियोजित और आपके लिए प्रबंधित किया जाता है: + +| घटक | भूमिका | +|---|---| +| **AgentEye सर्वर** | HTTP API जो कलेक्टर से इवेंट प्राप्त करता है, विश्लेषण चलाता है, और डैशबोर्ड को डेटा परोसता है | +| **डैशबोर्ड** | एजेंट सेशन, टूल कॉल, मॉडल अनुरोध और त्रुटियों को देखने के लिए वेब इंटरफेस; वैकल्पिक केवल-पढ़ने के लिए सहायक को होस्ट करता है | +| **ClickHouse** | Ingested इवेंट, विश्लेषण और मूल्यांकन के लिए आवश्यक विहित स्टोर | +| **PostgreSQL** | संगठन, API कुंजी, उपयोगकर्ता, डैशबोर्ड और सहेजे गए क्वेरी के लिए संबंधपरक स्टोर | +| **Redis** | वैकल्पिक साझा कैश और दर-सीमा बैकएंड; प्लेटफॉर्म सुंदरता से गिरावट करता है यदि यह उपलब्ध नहीं है | +| **AI सहायक (वैकल्पिक)** | आंतरिक केवल-पढ़ने के लिए सहायक कंटेनर; एक LLM एंडपॉइंट कॉन्फ़िगर किए जाने तक अक्षम रहता है | +| **Ingress कंट्रोलर** | दो लोड बैलेंसर (एक mTLS-सुरक्षित ingest के लिए, एक डैशबोर्ड के लिए) सार्वजनिक रूप से विश्वस्त, स्वचालित रूप से नवीनीकृत प्रमाणपत्र के साथ TLS को समाप्त करते हैं और ingest एंडपॉइंट पर mTLS लागू करते हैं | +| **cert-manager** | TLS प्रमाणपत्र प्रदान और mTLS क्लाइंट-प्रमाणपत्र जारी को स्वचालित करता है | +| **प्रमाणपत्र निगरानी** | एक निर्धारित कार्य प्रमाणपत्र समाप्ति जांचता है और जैसे-जैसे प्रमाणपत्र नवीकरण के करीब आते हैं सतर्कताएं भेजता है (जैसे Slack के लिए) | + +प्रबंधित प्रस्ताव प्लेटफॉर्म के मूल्यांकन पाइपलाइन को भी संचालित करता है, जो एजेंट गतिविधि को आपके मूल्यांकन मानदंड के विरुद्ध स्कोर करता है। ये क्षमताएं क्या प्रदान करती हैं यह जानने के लिए [सहायक](/hi/agenteye/assistant) और [मूल्यांकन सूट](/hi/agenteye/evaluation-suite) देखें। + +--- + +## हम आपको क्या प्रदान करते हैं + +परिनियोजन पूरा होने के बाद, आप प्राप्त करते हैं: + +| आइटम | विवरण | +|---|---| +| **डैशबोर्ड URL** | आपके डोमेन के तहत एक होस्टनाम (जैसे `https://agenteye.your-company.example`), सार्वजनिक रूप से विश्वस्त, स्वचालित रूप से नवीनीकृत TLS प्रमाणपत्र के साथ परोसा जाता है। आप हमारे द्वारा प्रदान किए गए लोड बैलेंसर होस्टनाम के लिए एक CNAME बनाते हैं; साइन-इन पासवर्ड-रहित ईमेल OTP है | +| **कलेक्टर एंडपॉइंट** | ingest होस्टनाम का `/events` पाथ (जैसे `https://ingest.your-company.example/events`), mTLS-सुरक्षित | +| **क्लाइंट प्रमाणपत्र बंडल** | प्रति-क्लस्टर: क्लाइंट प्रमाणपत्र, निजी कुंजी, और CA प्रमाणपत्र एक Kubernetes Secret मैनिफेस्ट के रूप में वितरित। इसे प्रति क्लस्टर एक बार लागू करें | +| **GitHub PAT** | कलेक्टर बाइनरी और Python SDK पैकेज डाउनलोड करने के लिए | +| **कलेक्टर API कुंजी** | `events:add` अनुमति के साथ स्कोप की गई कुंजी, प्रत्येक कलेक्टर परिनियोजन के लिए एक | +| **स्थापना गाइड** | कलेक्टर और Python SDK के लिए चरण-दर-चरण दस्तावेज़ | + +--- + +## सेटअप के बाद आप क्या करते हैं + +आपका एकमात्र चल रहा काम आपनी अपनी एजेंट मशीनों पर है, AgentEye क्लस्टर पर नहीं: + +1. **कलेक्टर स्थापित करें** AI एजेंट चलाने वाले प्रत्येक Kubernetes क्लस्टर में: क्लाइंट प्रमाणपत्र माउंट करें और एंडपॉइंट URL और API कुंजी कॉन्फ़िगर करें। [कलेक्टर स्थापना](/hi/agenteye/collector-installation) देखें। +2. **Python SDK को एकीकृत करें** अपने एजेंट कोड में। [Python SDK](/hi/agenteye/python-sdk) देखें। +3. **डैशबोर्ड खोलें** अपने ब्राउज़र में एजेंट गतिविधि देखने के लिए। + +कोई क्लस्टर संचालन नहीं, कोई डेटाबेस प्रबंधन नहीं, कोई प्रमाणपत्र नवीकरण नहीं, कोई अपग्रेड नहीं। + +--- + +## सुरक्षा + +- **डेटा आपके क्लाउड खाते में रहता है।** क्लस्टर, स्टोरेज, और डेटाबेस सभी आपके वातावरण में चलते हैं। कोई डेटा आपकी सीमा से बाहर नहीं जाता है। +- **आप पहुंच को नियंत्रित करते हैं।** क्लस्टर आपके खाते में है। आप किसी भी समय Exosphere की पहुंच को ऑडिट, निगरानी, या रद्द कर सकते हैं। सभी संचालन आपके क्लाउड की ऑडिट लॉग (CloudTrail, GCP Audit Logs, आदि) के माध्यम से जाते हैं। +- **इवेंट ingest पर mTLS।** हर कलेक्टर अनुरोध को एक वैध क्लाइंट प्रमाणपत्र और एक API कुंजी दोनों की आवश्यकता है। एक रिसाव हुई कुंजी प्रमाणपत्र के बिना बेकार है; एक चोरी किया गया प्रमाणपत्र एक वैध कुंजी के बिना बेकार है। +- **डैशबोर्ड पहुंच नियंत्रण।** डैशबोर्ड अपने स्वयं के लोड बैलेंसर पर चलता है, इवेंट ingest से अलग, और साइन-इन पासवर्ड-रहित ईमेल OTP है जो आपके द्वारा अनुमति सूची में डाले गए ईमेल पते/डोमेन तक सीमित है। लोड बैलेंसर पर एक IP स्रोत-श्रेणी अनुमति सूची अनुरोध पर उपलब्ध है; चूंकि स्वचालित प्रमाणपत्र नवीकरण को लोड बैलेंसर तक पहुंचना चाहिए, Exosphere प्रतिबंध को DNS-आधारित प्रमाणपत्र सत्यापन के साथ जोड़ता है ताकि नवीकरण काम करते रहें। +- **प्रति-क्लस्टर प्रमाणपत्र।** आपके प्रत्येक क्लस्टर को अपना क्लाइंट प्रमाणपत्र प्राप्त होता है। यदि एक क्लस्टर से समझौता होता है, तो वह प्रमाणपत्र स्वतंत्र रूप से रद्द किया जाता है दूसरों को प्रभावित किए बिना। + +--- + +## परिनियोजन समयरेखा + +| चरण | अवधि | आपकी संलिप्तता | +|---|---|---| +| **क्लस्टर provisioning** | 1-2 दिन | क्लस्टर प्रदान करें और Exosphere को पहुंच प्रदान करें | +| **प्लेटफॉर्म सेटअप** | 1 दिन | कोई नहीं; Exosphere सभी बुनियादी ढांचा घटकों को स्थापित करता है | +| **एप्लिकेशन परिनियोजन** | 1 दिन | कोई नहीं; Exosphere सर्वर, डैशबोर्ड को परिनियोजित करता है और API कुंजी बनाता है | +| **कलेक्टर रोलआउट** | 1-3 दिन | अपने क्लस्टर में कलेक्टर स्थापित करें (Exosphere से मार्गदर्शन के साथ) | +| **उत्पादन burn-in** | 1 सप्ताह | कोई नहीं; Exosphere निगरानी करता है और समायोजन करता है | + +विशिष्ट कुल: **~2 सप्ताह** किकऑफ से उत्पादन-तैयार तक। + +--- + +## समर्थन + +प्रश्नों या समस्याओं के लिए, Exosphere से `support@exosphere.host` पर संपर्क करें। + +--- + +## अगले कदम + +- [शुरुआत करें](/hi/agenteye/getting-started): end-to-end walkthrough +- [कलेक्टर स्थापना](/hi/agenteye/collector-installation): कलेक्टर स्थापित और कॉन्फ़िगर करें +- [Python SDK](/hi/agenteye/python-sdk): अपने एजेंट कोड को उपकरण करें +- [API कुंजी](/hi/agenteye/api-keys): पहुंच और अनुमति प्रबंधित करें +- [समस्या निवारण](/hi/agenteye/troubleshooting): सामान्य समस्याएं और समाधान \ No newline at end of file diff --git a/docs/hi/agenteye/python-sdk.mdx b/docs/hi/agenteye/python-sdk.mdx new file mode 100644 index 00000000..83412376 --- /dev/null +++ b/docs/hi/agenteye/python-sdk.mdx @@ -0,0 +1,385 @@ +--- +title: "Python SDK" +description: "AgentEye Python SDK दस्तावेज़।" +--- + + +AgentEye Python SDK आपको अपने एजेंटों के व्यवहार (प्रत्येक एजेंट रन, टूल कॉल, मॉडल अनुरोध, हुक, और मानवीय हस्तक्षेप) में पूर्ण दृश्यमानता देता है ताकि आप उन्हें डीबग, ऑडिट और मूल्यांकन कर सकें। यह आपके एजेंट कोड को स्ट्रक्चर्ड इवेंट्स को स्थानीय JSONL फ़ाइलों में लिखकर इंस्ट्रूमेंट करता है; कलेक्टर डेमन इन्हें उठाता है और उन्हें प्लेटफॉर्म पर स्वचालित रूप से भेजता है। + +--- + +## इंस्टॉलेशन + +अपने `AGENTEYE_TOKEN` का उपयोग करके GitHub Releases से व्हील डाउनलोड करें। यदि आपके पास अभी तोकन नहीं है, तो सेटअप स्टेप्स और आवश्यक अनुमतियों के लिए [GitHub Token Setup](/hi/agenteye/github-token) देखें। + +**`gh` CLI + pip का उपयोग करके:** + +```bash +VERSION=0.0.1b9 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "python-sdk/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-*.whl' +pip install "agenteye-${VERSION}-py3-none-any.whl" +``` + +**`gh` CLI + uv का उपयोग करके:** + +```bash +VERSION=0.0.1b9 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "python-sdk/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-*.whl' +uv add "./agenteye-${VERSION}-py3-none-any.whl" +``` + +**curl का उपयोग करके (कोई `gh` CLI नहीं):** + +```bash +VERSION=0.0.1b9 +curl -fsSL \ + -H "Authorization: Bearer $AGENTEYE_TOKEN" \ + -L \ + "https://github.com/agenteye-enterprise/releases/releases/download/python-sdk%2Fv${VERSION}/agenteye-${VERSION}-py3-none-any.whl" \ + -o "agenteye-${VERSION}-py3-none-any.whl" +pip install "agenteye-${VERSION}-py3-none-any.whl" +``` + +--- + +## क्विक स्टार्ट + +```python +import agenteye + +agenteye.configure(environment="production") + +agenteye.event.agent_start(session_id="run-001", agent_id="planner", goal="answer user query") + +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", + input={"query": "latest AI research"}, +) + +agenteye.event.tool_result( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", + output={"results": ["..."]}, +) + +agenteye.event.agent_end(session_id="run-001", agent_id="planner", outcome="success") +``` + +--- + +## configure() + +```python +agenteye.configure( + base_dir=None, # Path | str | None. Default: $AGENTEYE_HOME or ~/.agenteye + flush_interval=0.5, # float, seconds between flush cycles + environment=None, # str | None. Deployment environment label +) +``` + +किसी भी `event.*` कॉल से पहले एक बार कॉल करें। छोड़ना सुरक्षित है; डिफ़ॉल्ट मान तुरंत काम करते हैं। सभी आर्गुमेंट्स केवल कीवर्ड हैं; उन्हें ऊपर दिखाए गए नाम से पास करें। + +जब `base_dir` `None` है (डिफ़ॉल्ट), SDK `$AGENTEYE_HOME` को पढ़ता है यदि सेट है, +अन्यथा `~/.agenteye` पर वापस आता है। यह कलेक्टर के अपने रेजोल्यूशन से मेल खाता है, +इसलिए एक एकल `AGENTEYE_HOME` env var SDK और कलेक्टर दोनों के लिए साझा इवेंट स्पूल को कॉन्फ़िगर करता है, जो साइडकार / सिंगल-पॉड डिप्लॉयमेंट्स के लिए आवश्यक है जहां दोनों प्रक्रियाओं को स्पूल पाथ पर सहमत होना चाहिए। + +--- + +## Environment + +प्रत्येक इवेंट को डिप्लॉयमेंट environment के साथ लेबल करें (`production`, `staging`, `qa`, `canary`, आदि)। इसे एक बार सेट करें; SDK इसे स्वचालित रूप से प्रत्येक इवेंट से जोड़ता है। + +**विकल्प 1: `configure()` के माध्यम से:** + +```python +agenteye.configure(environment="production") +``` + +**विकल्प 2: environment variable के माध्यम से:** + +```bash +export AGENTEYE_ENVIRONMENT=production +``` + +**प्राथमिकता:** `configure(environment=...)` environment variable पर जीत जाता है। यदि कोई भी सेट नहीं है, तो डिफ़ॉल्ट `"dev"` है। + +Environment मान डैशबोर्ड में पहली पंक्ति फ़िल्टर के रूप में दिखाई देता है और तेज़ क्वेरीज़ के लिए सर्वर पर अनुक्रमित कॉलम के रूप में संग्रहीत किया जाता है। + +**बाधा:** environment मान **लाक्षणिक `,` अल्पविराम नहीं होना चाहिए**। डैशबोर्ड फ़िल्टर्स वायर पर अल्पविराम-अलग मल्टी-सिलेक्ट का उपयोग करते हैं (`?environment=prod,staging`), इसलिए `prod,blue` नाम का environment दो मानों में विभाजित हो जाएगा। अल्पविराम वाले environment वाली इवेंट्स इनजेस्ट समय पर अस्वीकार कर दी जाती हैं। + +--- + +## Event Reference + +सभी इवेंट methods को इन दो फ़ील्डों की आवश्यकता है: + +| फ़ील्ड | प्रकार | विवरण | +|---|---|---| +| `session_id` | `str` | शीर्ष-स्तर एजेंट रन की पहचान करता है | +| `agent_id` | `str` | सत्र के भीतर किस एजेंट ने इवेंट उत्सर्जित किया यह पहचान करता है | + +सभी methods कस्टम मेटाडेटा के लिए मनमाने `**kwargs` भी स्वीकार करते हैं ([कस्टम फ़ील्ड्स](#custom-fields) देखें)। + +--- + +### `event.agent_start()` + +जब एजेंट काम शुरू करता है तो उत्सर्जित होता है। + +```python +agenteye.event.agent_start( + session_id="run-001", + agent_id="planner", + goal="answer user query", # str | None + parent_id=None, # str | None - नेस्टेड एजेंट्स के लिए पैरेंट agent_id +) +``` + +--- + +### `event.agent_end()` + +जब एजेंट काम पूरा करता है तो उत्सर्जित होता है। + +```python +agenteye.event.agent_end( + session_id="run-001", + agent_id="planner", + outcome="success", # str | None + summary="Answered query", # str | None +) +``` + +--- + +### `event.tool_use()` + +जब एजेंट एक टूल को invoke करता है तो उत्सर्जित होता है। `tool_result` के साथ जोड़ी; SDK स्वचालित रूप से `duration_ms` की गणना करता है। + +```python +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="web_search", # str, required + tool_call_id="toolu_01", # str, required - matching tool_result के लिए correlation key + input={"query": "..."}, # dict | None +) +``` + +--- + +### `event.tool_result()` + +जब टूल return करता है तो उत्सर्जित होता है। `tool_call_id` के माध्यम से `tool_use` के साथ correlate करता है। + +```python +agenteye.event.tool_result( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", # prior tool_use से मेल खाना चाहिए + output={"results": ["..."]}, # Any | None + error=None, # str | None - सेट करें यदि टूल ने raise किया + # duration_ms स्वचालित रूप से गणना की जाती है - इसे पास न करें +) +``` + +--- + +### `event.model_request()` + +LLM को prompt भेजने से ठीक पहले उत्सर्जित होता है। + +```python +agenteye.event.model_request( + session_id="run-001", + agent_id="planner", + model="claude-sonnet-4-6", # str | None + messages=[ # list[dict] | None - conversation turns + {"role": "user", "content": "..."}, + ], + system="You are helpful.", # Any | None - str या content blocks की list + tools=[ # list[dict] | None - मॉडल को प्रदान किए गए टूल स्कीमा + {"name": "search", "input_schema": {"type": "object"}}, + ], +) +``` + +`messages` entries सादे स्ट्रिंग `content` या Anthropic-शैली blocks की list-of-blocks `content` स्वीकार करते हैं। Sampling params (`temperature`, `max_tokens`, आदि) को अतिरिक्त kwargs के रूप में पास किया जा सकता है। + +--- + +### `event.model_response()` + +जब LLM response return करता है तो उत्सर्जित होता है। + +```python +agenteye.event.model_response( + session_id="run-001", + agent_id="planner", + model="claude-sonnet-4-6", # str | None + stop_reason="end_turn", # str | None + input_tokens=1024, # int | None + output_tokens=256, # int | None + content=[ # Any | None - str, या content blocks की list + {"type": "text", "text": "..."}, + ], + role="assistant", # str | None +) +``` + +`content` सादे स्ट्रिंग (generic providers) या Anthropic-शैली content blocks की list स्वीकार करता है। Tool calls `content` के अंदर `{"type": "tool_use", ...}` blocks के रूप में रहते हैं, कोई अलग `tool_calls` फ़ील्ड के बिना। + +--- + +### `event.hook_triggered()` + +जब हुक fire होता है तो उत्सर्जित होता है। `hook_completed` के साथ जोड़ी; SDK स्वचालित रूप से `duration_ms` की गणना करता है। + +```python +agenteye.event.hook_triggered( + session_id="run-001", + agent_id="planner", + hook_name="pre_tool_use", # str, required + hook_id="hook-abc", # str, required - correlation key + trigger_event="tool_use", # str | None + input={"tool": "search"}, # Any | None +) +``` + +--- + +### `event.hook_completed()` + +जब हुक पूरा होता है तो उत्सर्जित होता है। `hook_id` के माध्यम से `hook_triggered` के साथ correlate करता है। + +```python +agenteye.event.hook_completed( + session_id="run-001", + agent_id="planner", + hook_name="pre_tool_use", + hook_id="hook-abc", # prior hook_triggered से मेल खाना चाहिए + outcome="allow", # str | None + output=None, # Any | None + error=None, # str | None + # duration_ms स्वचालित रूप से गणना की जाती है - इसे पास न करें +) +``` + +--- + +### `event.error()` + +जब unhandled error होता है तो उत्सर्जित होता है। + +```python +agenteye.event.error( + session_id="run-001", + agent_id="planner", + error_type="TimeoutError", # str, required + message="timed out", # str, required + traceback="Traceback...", # str | None +) +``` + +--- + +## Human-in-the-Loop Events + +Human-in-the-loop events आपको उन क्षणों में निरीक्षण देते हैं जहां कोई व्यक्ति एजेंट के निष्पादन में कदम रखता है (अनुमोदन की प्रतीक्षा, input प्रदान करना, pause करना, या एजेंट को रोकना)। वे आपको मापने देते हैं कि मनुष्य को प्रतिक्रिया देने में कितना समय लगता है (SDK paired events पर स्वचालित रूप से `duration_ms` की गणना करता है), ऑडिट करते हैं कि किसने एजेंट को pause या interrupt किया, और approval और oversight workflows बनाते हैं जो डैशबोर्ड में सामने आते हैं। + +### `event.human_wait()` + +जब एजेंट निष्पादन को pause करता है मानव को input प्रदान करने की प्रतीक्षा के लिए तो उत्सर्जित होता है। `human_input` के साथ जोड़ी; SDK स्वचालित रूप से `duration_ms` की गणना करता है (मानव को प्रतिक्रिया देने में कितना समय लगा)। + +```python +agenteye.event.human_wait( + session_id="run-001", + agent_id="planner", + input_id="inp-abc", # str, required - matching human_input के लिए correlation key + prompt="Do you approve this action?", # str | None - मानव को दिखाया गया प्रश्न + options=["approve", "reject", "defer"], # list[str] | None - मानव को प्रस्तुत विकल्प + reason="approval_required", # str | None - एजेंट क्यों प्रतीक्षा कर रहा है +) +``` + +### `event.human_input()` + +जब मानव input प्रदान करता है और एजेंट resume होता है तो उत्सर्जित होता है। `input_id` के माध्यम से `human_wait` के साथ correlate करता है। `duration_ms` स्वचालित रूप से गणना की जाती है और कॉलर द्वारा पास नहीं किया जाना चाहिए। + +```python +agenteye.event.human_input( + session_id="run-001", + agent_id="planner", + input_id="inp-abc", # str, required - prior human_wait से मेल खाना चाहिए + response="approve", # str | None - मानव का उत्तर (फ्री टेक्स्ट या चयनित विकल्प) + # duration_ms स्वचालित रूप से गणना की जाती है - इसे पास न करें +) +``` + +### `event.human_pause()` + +जब मानव सक्रिय रूप से एजेंट को pause करता है (जैसे डैशबोर्ड नियंत्रण के माध्यम से) तो उत्सर्जित होता है। एजेंट suspended है लेकिन terminated नहीं है। + +```python +agenteye.event.human_pause( + session_id="run-001", + agent_id="planner", + reason="user_requested", # str | None + user_id="usr_42", # str | None - किसने एजेंट को pause किया +) +``` + +### `event.human_interrupt()` + +जब मानव सक्रिय रूप से एजेंट को mid-execution में रोकता है तो उत्सर्जित होता है। `human_pause` के विपरीत, एजेंट का काम suspend करने के बजाय terminate किया जाता है। + +```python +agenteye.event.human_interrupt( + session_id="run-001", + agent_id="planner", + reason="output_incorrect", # str | None + user_id="usr_42", # str | None - किसने एजेंट को interrupt किया + at_step="tool_use:web_search", # str | None - जब रोका गया तो एजेंट क्या कर रहा था +) +``` + +--- + +## Custom Fields + +कोई भी अतिरिक्त keyword arguments standard fields के बाद event में appended किए जाते हैं: + +```python +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="db_query", + tool_call_id="toolu_02", + tenant_id="acme", # custom field + region="us-east-1", # custom field +) +``` + +`timestamp`, `type`, और `environment` reserved हैं और custom fields के रूप में पास किए जाने पर `ValueError` raise करते हैं (`Reserved field names cannot be used as custom fields: [...]`)। `session_id` और `agent_id` प्रत्येक event method पर आवश्यक पैरामीटर हैं और दूसरी बार सप्लाई नहीं किए जा सकते; यदि आप ऐसा करते हैं तो Python `TypeError` raise करता है। इसके बजाय `configure(environment=...)` (या `AGENTEYE_ENVIRONMENT` variable) के साथ environment सेट करें। + +--- + +## How Events Are Written + +Events को in-process में buffer किया जाता है और हर `flush_interval` सेकंड में डिस्क पर flush किया जाता है (डिफ़ॉल्ट 500 ms)। प्रत्येक flush एक JSONL फ़ाइल लिखता है: + +``` +~/.agenteye/events/event-2026-04-01T12-00-00-000Z.jsonl +``` + +कलेक्टर इस निर्देशिका को देखता है और फ़ाइलों को स्वचालित रूप से upload करता है। आपको इन फ़ाइलों को सीधे प्रबंधित करने की आवश्यकता नहीं है। \ No newline at end of file diff --git a/docs/hi/agenteye/single-pod-deployment.mdx b/docs/hi/agenteye/single-pod-deployment.mdx new file mode 100644 index 00000000..bf79caff --- /dev/null +++ b/docs/hi/agenteye/single-pod-deployment.mdx @@ -0,0 +1,483 @@ +--- +title: "एकल-पॉड डिप्लॉयमेंट: EKS पर कलेक्टर + एप्लिकेशन साइडकार" +description: "AgentEye एकल-पॉड डिप्लॉयमेंट: EKS पर कलेक्टर + एप्लिकेशन साइडकार दस्तावेज़।" +--- + +अपने एप्लिकेशन और AgentEye कलेक्टर को **एक ही Kubernetes पॉड में** चलाएं ताकि टेलीमेट्री कभी नेटवर्क सीमा को पार न करे। आपके एप्लिकेशन का SDK और कलेक्टर एक एकल इन-पॉड इवेंट स्पूल साझा करते हैं, जिसका मतलब है कम-विलंबता, इन-प्रोसेस टेलीमेट्री हैंडऑफ कोई लोकलहोस्ट पोर्ट के बिना, कोई सर्विस मेश के बिना, और कलेक्टर का लाइफसाइकल सीधे उस वर्कलोड से जुड़ा होता है जिसे वह देखता है। कलेक्टर जो mTLS क्लाइंट सर्टिफिकेट प्रस्तुत करता है वह सीधे AWS Secrets Manager से आपके पॉड में दिया जाता है, इसलिए क्रेडेंशियल रोटेशन के लिए आपकी ओर से कोई मैनुअल फ़ाइल स्ट्रैफल की आवश्यकता नहीं है। + +यहां वर्णित साइडकार + साझा-स्पूल मॉडल क्लाउड-अज्ञेयवादी है; दो कंटेनर एक `emptyDir` इवेंट स्पूल साझा करना किसी भी Kubernetes वितरण पर काम करता है। केवल इस गाइड में प्रमाणपत्र-वितरण पथ (AWS Secrets Manager + Secrets Store CSI Driver + IRSA) AWS / EKS के लिए विशिष्ट है। यदि आप अन्य जगह चलाते हैं, तो पॉड और स्पूल लेआउट रखें और चरण 2 और 3 के लिए अपने प्लेटफ़ॉर्म की गुप्त-माउंट तंत्र को प्रतिस्थापित करें। + +> **इस पैटर्न का उपयोग कब करें।** एकल-पॉड चुनें जब आपके एप्लिकेशन को कलेक्टर तक पहुंचने के लिए नेटवर्क सीमा को पार नहीं करना चाहिए (कम-विलंबता इन-पॉड IPC, टाइट लाइफसाइकल युग्मन, प्रति-किरायेदार पॉड अलगाव)। मल्टी-एप्प फ्लीट के लिए जो प्रति नोड या प्रति क्लस्टर एक कलेक्टर साझा करते हैं, इसके बजाय [enterprise-docs/kubernetes-deployment.md](/hi/agenteye/kubernetes-deployment) देखें। + +--- + +## एक नज़र में + +``` +┌──────────────────────────────── Pod ─────────────────────────────────┐ +│ │ +│ ┌──────────────────────┐ ┌──────────────────────┐ │ +│ │ your-app │ │ agenteye-collector │ │ +│ │ (SDK writes JSONL) │ │ (sweeps events/, │ │ +│ │ │ │ uploads over mTLS) │ │ +│ └──────────┬───────────┘ └──────────┬───────────┘ │ +│ │ writes reads │ │ +│ ▼ ▼ │ +│ ┌────────────────────────────────────────────────────┐ │ +│ │ emptyDir: /var/lib/agenteye/{events,failed}/ │ │ +│ │ (AGENTEYE_HOME - shared event spool) │ │ +│ └────────────────────────────────────────────────────┘ │ +│ ▲ │ +│ │ reads cert │ +│ ┌────────┴─────────┐ │ +│ │ CSI (read-only): │ │ +│ │ /etc/agenteye/ │ │ +│ │ tls/client.{crt, │ │ +│ │ key}, ca.crt │ │ +│ └────────┬─────────┘ │ +└───────────────────────────────────────────────────┼──────────────────┘ + │ mounted by + │ Secrets Store CSI + │ (AWS provider + + │ IRSA) + ┌────────┴──────────┐ + │ AWS Secrets │ + │ Manager │ + │ agenteye/mtls- │ + │ client/ │ + └────────┬──────────┘ + ▲ + │ push on issue / + │ renewal + ┌────────┴──────────┐ + │ Exosphere │ + │ delivers the cert │ + │ bundle into your │ + │ Secrets Manager │ + │ on renewal │ + └───────────────────┘ + +आउटबाउंड: कलेक्टर → AGENTEYE_URL (mTLS, CSI-माउंटेड सर्ट का उपयोग करके)। +``` + +दो डेटा प्रवाह, दो वॉल्यूम: + +- **इवेंट्स (इन-पॉड):** आपके एप्लिकेशन का SDK `.jsonl` फ़ाइलों को साझा `emptyDir` में `$AGENTEYE_HOME/events/` पर लिखता है; कलेक्टर स्वीपर उन्हें पढ़ता है और अपलोड करता है। कोई लोकलहोस्ट पोर्ट नहीं, कोई लूपबैक नहीं, शुद्ध साझा-फ़ाइलसिस्टम हैंडऑफ। +- **mTLS सर्ट (पॉड ← क्लाउड):** Secrets Store CSI Driver Secrets Manager से सर्ट बंडल को `/etc/agenteye/tls/` पर एक रीड-ओनली वॉल्यूम में माउंट करता है, कलेक्टर कंटेनर तक सीमित। + +**दो स्वतंत्र पार्टियां:** + +| पार्टी | जिम्मेदारी | +|---|---| +| Exosphere | mTLS क्लाइंट प्रमाणपत्र जारी करता है और बंडल को **आपके** AWS खाते के Secrets Manager में एक स्थिर नाम के तहत वितरित करता है। समाप्ति से पहले अपडेट किए गए बंडल को उसी गुप्त में पुनः प्रकाशित करता है। | +| आप | Secrets Store CSI Driver इंस्टॉल करें, IRSA के माध्यम से पॉड के ServiceAccount को गुप्त तक रीड एक्सेस प्रदान करें, और पॉड मैनिफेस्ट लागू करें। बस। | + +--- + +## पूर्वापेक्षाएं + +### आपके AWS खाते / EKS क्लस्टर में + +- एक EKS क्लस्टर जिसके साथ एक **OIDC प्रदाता** जुड़ा हो। इसके साथ पुष्टि करें: + + ```bash + aws eks describe-cluster --name \ + --query "cluster.identity.oidc.issuer" --output text + ``` + + यदि कमांड एक `https://oidc.eks.…` URL लौटाता है, तो OIDC सक्षम है। यदि नहीं, तो एक को जोड़ें: + + ```bash + eksctl utils associate-iam-oidc-provider \ + --cluster --approve + ``` + +- [Secrets Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/) और [AWS प्रदाता](https://github.com/aws/secrets-store-csi-driver-provider-aws) क्लस्टर में स्थापित (देखें § चरण 2)। + +- AWS CLI v2 और `kubectl` आपके वर्कस्टेशन पर। + +### Exosphere के साथ समन्वय + +तैनाती से पहले, Exosphere mTLS क्लाइंट बंडल को आपके AWS खाते के Secrets Manager में वितरित करता है और प्रदान करता है: + +- **गुप्त नाम** (सम्मेलन: `agenteye/mtls-client/`) +- **AWS क्षेत्र** जहां गुप्त रहता है +- **AgentEye बैकएंड URL** कलेक्टर के साथ कॉन्फ़िगर करने के लिए +- आपके कलेक्टर **API कुंजी** (देखें [enterprise-docs/api-keys.md](/hi/agenteye/api-keys)) + +--- + +## चरण 1: Exosphere जो वितरित करता है + +आप mTLS क्लाइंट प्रमाणपत्र स्वयं उत्पन्न नहीं करते हैं। Exosphere इसे जारी करता है और बंडल को सीधे आपके AWS खाते के Secrets Manager में वितरित करता है, इसलिए आपके वातावरण में केवल एकमात्र क्रेडेंशियल सामग्री जो कभी आता है वह तैयार, माउंट-के-लिए तैयार गुप्त है। + +आपके खाते में क्या आता है: + +| संपत्ति | मान | +|---|---| +| गुप्त नाम | `agenteye/mtls-client/` (नवीकरण के दौरान स्थिर) | +| क्षेत्र | AWS क्षेत्र जिसे आपने अपने EKS क्लस्टर के लिए नामित किया है | +| पेलोड | एक एकल JSON गुप्त तीन कुंजियों के साथ (`client.crt`, `client.key`, और `ca.crt`), प्रत्येक PEM-एन्कोडेड सामग्री रखता है | +| टैग | `AgentEyeCluster=` | + +नवीकरण पर, एक ही गुप्त एक नए संस्करण के साथ जगह पर अपडेट होता है, इसलिए ARN और नाम कभी नहीं बदलते; आपका `SecretProviderClass` और IAM नीति अपरिवर्तित रहती है। प्रमाणपत्र लाइफसाइकल के लिए (वैधता, नवीकरण गति, समाप्ति चेतावनी) देखें [enterprise-docs/kubernetes-deployment.md](/hi/agenteye/kubernetes-deployment)। + +--- + +## चरण 2: Secrets Store CSI Driver + AWS प्रदाता स्थापित करें + +यदि आप पहले से ही दूसरा वर्कलोड चलाते हैं जो CSI के माध्यम से AWS गुप्त को माउंट करता है तो यह चरण छोड़ें। + +```bash +# CSI Driver +helm repo add secrets-store-csi-driver \ + https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts +helm install -n kube-system csi-secrets-store \ + secrets-store-csi-driver/secrets-store-csi-driver \ + --set syncSecret.enabled=true \ + --set enableSecretRotation=true \ + --set rotationPollInterval=1h + +# AWS provider +kubectl apply -f \ + https://raw.githubusercontent.com/aws/secrets-store-csi-driver-provider-aws/main/deployment/aws-provider-installer.yaml +``` + +**सत्यापित करें:** + +```bash +kubectl get pods -n kube-system | grep -E 'csi-secrets-store|aws-provider' +``` + +अपेक्षित: हर पॉड के लिए `Running`। + +> **क्यों `rotationPollInterval=1h`?** जब Exosphere एक नवीकृत प्रमाणपत्र प्रकाशित करता है, तो Secrets Manager जगह पर अपडेट होता है। CSI Driver इस अंतराल पर गुप्त को पुनः पढ़ता है और माउंटेड फ़ाइलों को फिर से लिखता है। कलेक्टर प्रमाणपत्र फ़ाइलों को स्टार्टअप पर एक बार पढ़ता है, इसलिए यह प्रक्रिया पुनरारंभ होने तक नवीकृत प्रमाणपत्र प्रस्तुत करना शुरू करता है; देखें § प्रमाणपत्र नवीकरण कैसे एक को ट्रिगर करें। + +--- + +## चरण 3: पॉड को गुप्त के लिए रीड एक्सेस प्रदान करें (IRSA) + +### 3.1 IAM नीति बनाएं + +`agenteye-mtls-reader-policy.json` के रूप में सहेजें: + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "ReadAgentEyeMtlsBundle", + "Effect": "Allow", + "Action": [ + "secretsmanager:GetSecretValue", + "secretsmanager:DescribeSecret" + ], + "Resource": "arn:aws:secretsmanager:::secret:agenteye/mtls-client/-*" + } + ] +} +``` + +``, ``, और `` को प्रतिस्थापित करें। अनुगामी `-*` AWS के द्वारा जोड़ी जाने वाली छह-वर्ण यादृच्छिक प्रत्यय से मेल खाता है। + +नीति बनाएं: + +```bash +aws iam create-policy \ + --policy-name AgentEyeMtlsReader- \ + --policy-document file://agenteye-mtls-reader-policy.json +``` + +### 3.2 IAM भूमिका बनाएं और इसे पॉड के ServiceAccount से बांधें + +```bash +eksctl create iamserviceaccount \ + --name agenteye-pod \ + --namespace \ + --cluster \ + --role-name AgentEyePodRole- \ + --attach-policy-arn arn:aws:iam:::policy/AgentEyeMtlsReader- \ + --approve +``` + +यह `agenteye-pod` नामक एक `ServiceAccount` बनाता है जिसमें नई भूमिका की ओर इशारा करते हुए `eks.amazonaws.com/role-arn` एनोटेशन होता है। + +### 3.3 आवश्यक IAM अनुमतियां: सारांश + +| अनुमति | दायरा | क्यों | +|---|---|---| +| `secretsmanager:GetSecretValue` | `arn:aws:secretsmanager:::secret:agenteye/mtls-client/-*` | CSI Driver हर माउंट + रोटेशन टिक पर सर्ट बंडल पढ़ता है। | +| `secretsmanager:DescribeSecret` | समान | CSI Driver `DescribeSecret` को कॉल करता है पोल के बीच संस्करण परिवर्तन का पता लगाने के लिए। | + +**न दें** `secretsmanager:PutSecretValue`, `secretsmanager:UpdateSecret`, या `secretsmanager:DeleteSecret` पॉड को। पॉड केवल गुप्त को पढ़ता है; नए संस्करण को इसमें लिखना Exosphere द्वारा संभाला जाता है जब प्रमाणपत्र जारी या नवीकृत होता है। + +यदि गुप्त ग्राहक-प्रबंधित KMS कुंजी के साथ एन्क्रिप्ट है (डिफ़ॉल्ट `aws/secretsmanager` कुंजी नहीं), तो भी अनुदान दें: + +```json +{ + "Effect": "Allow", + "Action": ["kms:Decrypt"], + "Resource": "arn:aws:kms:::key/", + "Condition": { + "StringEquals": { + "kms:ViaService": "secretsmanager..amazonaws.com" + } + } +} +``` + +--- + +## चरण 4: पॉड तैनात करें + +### 4.1 SecretProviderClass + +`agenteye-mtls-spc.yaml`: + +```yaml +apiVersion: secrets-store.csi.x-k8s.io/v1 +kind: SecretProviderClass +metadata: + name: agenteye-mtls + namespace: +spec: + provider: aws + parameters: + objects: | + - objectName: "agenteye/mtls-client/" + objectType: "secretsmanager" + jmesPath: + - path: '"client.crt"' + objectAlias: "client.crt" + - path: '"client.key"' + objectAlias: "client.key" + - path: '"ca.crt"' + objectAlias: "ca.crt" +``` + +`jmesPath` ब्लॉक AWS प्रदाता को JSON गुप्त को डिस्क पर तीन अलग फ़ाइलों में विभाजित करने के लिए कहता है। `'"client.crt"'` में उद्धरण आवश्यक हैं क्योंकि JMESPath `.` को एक उप-अभिव्यक्ति ऑपरेटर के रूप में मानता है। + +```bash +kubectl apply -f agenteye-mtls-spc.yaml +``` + +### 4.2 पॉड / डिप्लॉयमेंट मैनिफेस्ट + +**दो कंटेनर एक दूसरे से कैसे बात करते हैं।** AgentEye SDK और कलेक्टर नेटवर्क सॉकेट पर संचार नहीं करते हैं; कोई स्थानीय HTTP पोर्ट नहीं है। SDK `$AGENTEYE_HOME/events/` में `.jsonl` फ़ाइलों के इवेंट बैच लिखता है, और कलेक्टर लगातार उस निर्देशिका को देखता है और प्रत्येक फ़ाइल को अपलोड करता है। साइडकार पॉड के लिए इसका मतलब है: + +- दोनों कंटेनर **एक ही** `emptyDir` वॉल्यूम को **एक ही** पथ पर माउंट करते हैं। +- दोनों कंटेनर `AGENTEYE_HOME` को उस पथ पर सेट करते हैं। +- आपके एप्लिकेशन इमेज में AgentEye SDK स्थापित और कॉन्फ़िगर होना चाहिए (देखें [enterprise-docs/python-sdk.md](/hi/agenteye/python-sdk))। + +> जब `AGENTEYE_HOME` अनसेट होता है, तो SDK और कलेक्टर दोनों `~/.agenteye` पर डिफ़ॉट होते हैं, और दोनों कंटेनरों की होम निर्देशिकाएं अलग होती हैं, इसलिए वे दो अलग-अलग स्पूल पर उतरते और हैंडऑफ चुप-चाप विफल हो जाते। `AGENTEYE_HOME` को **दोनों** कंटेनरों पर एक ही स्पष्ट पथ पर सेट करें। §4.3 सत्यापन और मिलान समस्या निवारण पंक्ति इसे पकड़ते हैं यदि इसे मिस किया जाता है। + +`agenteye-pod.yaml` (एक प्रतिकृति के साथ डिप्लॉयमेंट, आवश्यकतानुसार स्केल करें): + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-app-with-collector + namespace: +spec: + replicas: 1 + selector: + matchLabels: + app: my-app-with-collector + template: + metadata: + labels: + app: my-app-with-collector + spec: + serviceAccountName: agenteye-pod + containers: + - name: app + image: + env: + # SDK writes event JSONL files into $AGENTEYE_HOME/events/ + - name: AGENTEYE_HOME + value: /var/lib/agenteye + volumeMounts: + - name: agenteye-spool + mountPath: /var/lib/agenteye + + - name: agenteye-collector + # Pin to a versioned :v tag for production; :beta-latest + # tracks the current beta build (:latest exists only for stable releases). + image: ghcr.io/agenteye-enterprise/collector:beta-latest + args: ["start"] + env: + # Must match the app container's AGENTEYE_HOME so the collector + # sweeps the same directory the SDK writes to. + - name: AGENTEYE_HOME + value: /var/lib/agenteye + - name: AGENTEYE_URL + value: "https://ingest.example.agenteye.com/events" + - name: AGENTEYE_KEY + valueFrom: + secretKeyRef: + name: agenteye-collector-api-key + key: key + - name: AGENTEYE_TLS_CERT + value: /etc/agenteye/tls/client.crt + - name: AGENTEYE_TLS_KEY + value: /etc/agenteye/tls/client.key + # Only when the AgentEye server presents a cert not signed by a + # publicly-trusted CA (e.g. self-signed by an in-cluster issuer + # because you have no real DNS domain). The CSI mount already + # exposes ca.crt alongside the client cert/key. + - name: AGENTEYE_TLS_CA + value: /etc/agenteye/tls/ca.crt + volumeMounts: + - name: agenteye-spool + mountPath: /var/lib/agenteye + - name: agenteye-mtls + mountPath: /etc/agenteye/tls + readOnly: true + livenessProbe: + exec: + command: ["agenteye-collector", "health"] + initialDelaySeconds: 10 + periodSeconds: 30 + + volumes: + # Shared event spool between app and collector. emptyDir is fine: + # events are transient and the collector drains them before pod + # termination on graceful shutdown. + - name: agenteye-spool + emptyDir: {} + # mTLS cert bundle, mounted read-only into the collector only. + - name: agenteye-mtls + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: agenteye-mtls +``` + +`agenteye-collector-api-key` गुप्त कलेक्टर की API कुंजी रखता है (देखें [enterprise-docs/api-keys.md](/hi/agenteye/api-keys) प्रावधान के लिए)। + +**लागू करें:** + +```bash +kubectl apply -f agenteye-pod.yaml +``` + +### 4.3 सत्यापित करें + +```bash +# Pod should be Running with 2/2 containers ready +kubectl get pods -n -l app=my-app-with-collector + +# Confirm the cert bundle was mounted +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- ls -l /etc/agenteye/tls/ +``` + +अपेक्षित: `client.crt`, `client.key`, `ca.crt` सभी मौजूद और रीड-ओनली, कंटेनर उपयोगकर्ता द्वारा स्वामित्व में। + +**साझा इवेंट स्पूल दोनों कंटेनरों के लिए दृश्यमान है इसकी पुष्टि करें:** + +```bash +# In the collector, should show the events/ and failed/ subdirs that +# the collector auto-creates on startup: +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- ls /var/lib/agenteye/ + +# In the app, should show the same directory contents: +kubectl exec -n deploy/my-app-with-collector \ + -c app -- ls /var/lib/agenteye/ +``` + +यदि दोनों सूचियां विचलित होती हैं, तो वॉल्यूम दोनों कंटेनरों में माउंट नहीं है (या `AGENTEYE_HOME` अलग है); देखें § समस्या निवारण। + +**एंड-टू-एंड स्मोक टेस्ट:** + +```bash +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- agenteye-collector flush +``` + +अपेक्षित: कलेक्टर किसी भी कतारबद्ध इवेंट को अपलोड करता है और `Done: N/N uploaded, 0 failed.` सारांश प्रिंट करता है। यदि स्पूल खाली है तो यह `No pending files.` प्रिंट करता है और बिना कुछ मान्य किए बाहर निकल जाता है — इसलिए यह केवल तभी चलाएं जब आपके एप्लिकेशन ने कम से कम एक इवेंट फ्लश किया हो। + +ध्यान दें कि `flush` गैर-शून्य **केवल** स्थानीय सेटअप त्रुटियों के लिए बाहर निकलता है: लापता कॉन्फ़िगरेशन (कोई URL/कुंजी समाधान नहीं) या अपाठ्य/अपार्स्ड TLS सर्ट (देखें § समस्या निवारण)। **गलत API कुंजी निकास कोड को नहीं बदलता** — अपलोड को `401` मिलता है, फ़ाइल को `failed/` में स्थानांतरित किया जाता है, और कमांड अभी भी `Done: 0/N uploaded, N failed.` और निकास `0` प्रिंट करता है। खराब कुंजी या अस्वीकृत अपलोड का पता लगाने के लिए, `Done:`/`[FAILED]` आउटपुट पढ़ें या `$AGENTEYE_HOME/failed/` में फ़ाइलों की जांच करें, निकास कोड नहीं। + +--- + +## प्रमाणपत्र नवीकरण + +क्लाइंट प्रमाणपत्र 90 दिनों के लिए वैध है और समाप्ति से लगभग 15 दिन पहले स्वचालित रूप से नवीकृत होता है; Exosphere फिर अपडेट किए गए बंडल को उसी Secrets Manager गुप्त में प्रकाशित करता है। वहां से, इन-पॉड प्रवाह है: + +1. Secrets Manager की गुप्त को एक नया `AWSCURRENT` संस्करण मिलता है। ARN और नाम अपरिवर्तित हैं। +2. `rotationPollInterval` (डिफ़ॉल्ट 1h; देखें § चरण 2) के भीतर, CSI Driver नए संस्करण को पढ़ता है और `/etc/agenteye/tls/` के तहत फ़ाइलों को पुनः लिखता है। +3. कलेक्टर प्रमाणपत्र फ़ाइलों को **स्टार्टअप पर एक बार** लोड करता है, इसलिए यह प्रक्रिया पुनरारंभ होने तक पिछले प्रमाणपत्र को प्रस्तुत करना जारी रखता है। नवीकृत सामग्री पर स्विच करने के लिए, कलेक्टर को पुनरारंभ करें; रोलिंग पुनरारंभ पर्याप्त है: + + ```bash + kubectl rollout restart deploy/my-app-with-collector -n + ``` + + इसे स्वचालित बनाने के लिए, एक साइडकार जोड़ें जो `/etc/agenteye/tls/` को देखता है (उदाहरण के लिए `inotifywait` के साथ) और जब फ़ाइलें बदलें तो रोलआउट को ट्रिगर करता है। + +क्योंकि पिछला प्रमाणपत्र नवीकरण के बाद लगभग 15 दिनों के लिए वैध रहता है, आपके पास बिना किसी व्यवधान के पुनरारंभ करने के लिए एक व्यापक खिड़की है। Exosphere नवीकृत बंडल को आपके लिए प्रकाशित करता है; आपकी ओर से एकमात्र नियमित कार्य यह सुनिश्चित करना है कि कलेक्टर उस खिड़की के भीतर पुनरारंभ हो। + +--- + +## समस्या निवारण + +| लक्षण | संभावित कारण | ठीक करना | +|---|---|---| +| पॉड `ContainerCreating` में फंसा, इवेंट दिखाते हैं `MountVolume.SetUp failed for volume "agenteye-mtls"` | CSI प्रदाता Secrets Manager तक नहीं पहुंच सकता | जांचें कि IRSA सही तरीके से बंधा है: `kubectl describe sa agenteye-pod -n ` `eks.amazonaws.com/role-arn` एनोटेशन दिखाता है। CloudTrail में AssumeRole कॉल की जांच करें। | +| त्रुटि: `AccessDeniedException: not authorized to perform secretsmanager:GetSecretValue` | IAM नीति गलत ARN के लिए निर्धारित है | गुप्त ARN प्रत्यय यादृच्छिक है; `agenteye/mtls-client/-*` वाइल्डकार्ड के साथ उपयोग करें, सटीक ARN नहीं। | +| त्रुटि: AWS प्रदाता से `ParameterNotFound` | गुप्त नाम असमानता `SecretProviderClass.objects[].objectName` और Exosphere द्वारा वितरित गुप्त के बीच | सटीक नाम की पुष्टि करें `aws secretsmanager list-secrets --filters Key=tag-key,Values=AgentEyeCluster`। | +| `jmesPath` त्रुटि, केवल एक फ़ाइल माउंट की गई | JMESPath सिंटैक्स | JSON कुंजियों में डॉट्स को डबल-कोटिंग की आवश्यकता है: `'"client.crt"'`, न कि `client.crt`। | +| कलेक्टर लॉग नवीकरण के बाद `tls: bad certificate` | CSI Driver अभी तक नए संस्करण को पोल नहीं किया है, या कलेक्टर अभी भी स्टार्टअप पर लोड किए गए पिछले प्रमाणपत्र के साथ चल रहा है | माउंटेड फ़ाइलों की पुष्टि करें कि अपडेट हुई हैं (`ls -l /etc/agenteye/tls/`), फिर कलेक्टर को उन्हें लोड करने के लिए पुनरारंभ करें: `kubectl rollout restart deploy/my-app-with-collector -n `। देखें § प्रमाणपत्र नवीकरण। | +| कलेक्टर कंटेनर `no such file or directory: /etc/agenteye/tls/client.crt` के साथ क्रैशलूप्स | वॉल्यूम पहली शुरुआत पर अभी तक आबादी नहीं है; स्टार्टअप जांच बहुत आक्रामक है | एक छोटी प्रारंभिक देरी जोड़ें या एक init कंटेनर उपयोग करें जो फ़ाइल के मौजूद होने का इंतज़ार करता है: `until [ -f /etc/agenteye/tls/client.crt ]; do sleep 1; done`। | +| CSI Driver पॉड `OOMKilled` | डिफ़ॉल्ट मेमोरी सीमा बहुत कम कई SecretProviderClasses के साथ क्लस्टर के लिए | Helm इंस्टॉल में `--set linux.resources.limits.memory=200Mi` को बढ़ाएं। | +| एप्लिकेशन स्वच्छ रूप से चलता है, `agenteye-collector flush` रिपोर्ट `No pending files.`, लेकिन आपका AgentEye डैशबोर्ड कोई इवेंट नहीं दिखाता | एप्लिकेशन और कलेक्टर इवेंट स्पूल साझा नहीं कर रहे हैं | जांचें कि (a) दोनों कंटेनर एक ही `agenteye-spool` emptyDir को एक ही पथ पर माउंट करते हैं, और (b) दोनों `AGENTEYE_HOME` को उस पथ पर सेट करते हैं। § 4.3 से दोनों `ls /var/lib/agenteye/` जांच चलाएं; सूचियां मिलनी चाहिए। | + +**पहले लॉग पकड़ने के लिए:** + +```bash +kubectl logs -n kube-system -l app=secrets-store-csi-driver --tail=100 +kubectl logs -n kube-system -l app=csi-secrets-store-provider-aws --tail=100 +kubectl describe pod -n -l app=my-app-with-collector +``` + +--- + +## संदर्भ: पॉड में डिस्क पर फ़ाइलें + +पॉड में डिस्क पर दो डेटा पथ हैं: + +### mTLS सर्ट बंडल: `/etc/agenteye/tls/` (CSI, रीड-ओनली, कलेक्टर केवल) + +Secrets Store CSI Driver द्वारा AWS Secrets Manager से माउंट किया गया। + +| फ़ाइल | सामग्री | कलेक्टर द्वारा उपयोग किया जाता है | +|---|---|---| +| `client.crt` | PEM-एन्कोडेड क्लाइंट प्रमाणपत्र | `AGENTEYE_TLS_CERT` | +| `client.key` | PEM-एन्कोडेड निजी कुंजी | `AGENTEYE_TLS_KEY` | +| `ca.crt` | PEM-एन्कोडेड CA सर्ट | `AGENTEYE_TLS_CA` (वैकल्पिक, केवल जब AgentEye सर्वर सर्ट सार्वजनिक रूप से-विश्वसनीय नहीं है) | + +सभी तीन रीड-ओनली में माउंट किए गए हैं और कंटेनर उपयोगकर्ता द्वारा स्वामित्व में। वे गुप्त घुमाते समय CSI Driver द्वारा पुनः लिखे जाते हैं। + +### इवेंट स्पूल: `$AGENTEYE_HOME/` (emptyDir, दोनों कंटेनरों के बीच साझा रीड-राइट) + +एक `agenteye-spool` नामक `emptyDir` वॉल्यूम के माध्यम से साझा। + +| पथ | लिखता है | पढ़ता है | प्रयोजन | +|---|---|---|---| +| `$AGENTEYE_HOME/events/*.jsonl` | एप्लिकेशन (AgentEye SDK) | कलेक्टर स्वीपर | इवेंट बैच जो SDK को फ्लश किया गया है, अपलोड की प्रतीक्षा में। | +| `$AGENTEYE_HOME/failed/` | कलेक्टर (अपलोड विफलता पर) | आप (डिबग करते समय) | JSONL फ़ाइलें कलेक्टर पुनः प्रयास के बाद अपलोड नहीं कर सके। | +| `$AGENTEYE_HOME/config.json` | आप (वैकल्पिक) | कलेक्टर | वैकल्पिक कलेक्टर कॉन्फ़िग फ़ाइल (env vars के लिए विकल्प)। | + +`events/` और `failed/` दोनों सबडायरेक्टरी स्टार्टअप पर कलेक्टर द्वारा स्वचालित रूप से बनाई जाती हैं; कोई `initContainer` की आवश्यकता नहीं। + +--- + +## संबंधित दस्तावेज़ + +- [enterprise-docs/collector-installation.md](/hi/agenteye/collector-installation): कलेक्टर बाइनरी विकल्प, mTLS कॉन्फ़िग संदर्भ, डेमन मोड। +- [enterprise-docs/kubernetes-deployment.md](/hi/agenteye/kubernetes-deployment): मल्टी-पॉड डिप्लॉयमेंट, सर्ट जारी करना आंतरिकता, लाइफसाइकल और समाप्ति सतर्कता। +- [enterprise-docs/api-keys.md](/hi/agenteye/api-keys): पॉड द्वारा उपभोग की जाने वाली कलेक्टर API कुंजी प्रावधान। +- [enterprise-docs/troubleshooting.md](/hi/agenteye/troubleshooting): क्लस्टर-व्यापी समस्या निवारण सूचकांक। \ No newline at end of file diff --git a/docs/hi/agenteye/tenant-management.mdx b/docs/hi/agenteye/tenant-management.mdx new file mode 100644 index 00000000..bfd8ec3a --- /dev/null +++ b/docs/hi/agenteye/tenant-management.mdx @@ -0,0 +1,166 @@ +--- +title: "टेनेंट प्रबंधन (संगठन और सदस्य)" +description: "AgentEye टेनेंट प्रबंधन (संगठन और सदस्य) दस्तावेज़।" +--- + +एक एकल AgentEye स्थापन कई पूर्ण रूप से अलग-थलग **संगठनों** (टेनेंट) को सेवा प्रदान करता है, इसलिए एक उदाहरण अलग-अलग टीमों, व्यावसायिक इकाइयों, या ग्राहकों को होस्ट कर सकता है बिना किसी एक टेनेंट के डेटा को दूसरे को उजागर किए। डेटा की प्रत्येक पंक्ति (इवेंट्स, मूल्यांकन, सेशन, डैशबोर्ड, सहेजी गई क्वेरीज़, सतर्कताएं, API कुंजियाँ, और सदस्य) बिल्कुल एक संगठन से संबंधित है। प्राथमिक अलगाव एप्लिकेशन कोड में लागू किया जाता है: हर अनुरोध अपने संगठन के दायरे में होता है स्पष्ट `org_id` प्रेडिकेट्स के साथ। ClickHouse पर — जहाँ उच्च-मात्रा इवेंट्स और मूल्यांकन रहते हैं — यह मजबूत इंजन-स्तरीय प्रवर्तन द्वारा समर्थित है: प्रत्येक संगठन को एक समर्पित केवल-पढ़ने के लिए ClickHouse उपयोगकर्ता मिलता है प्रति-संगठन पंक्ति नीति के साथ, इसलिए यहां तक कि अविश्वसनीय विश्लेषण SQL कभी भी किसी अन्य टेनेंट की पंक्तियों को नहीं पढ़ सकता। PostgreSQL पर, पंक्ति-स्तरीय सुरक्षा केवल-पढ़ने के लिए क्वेरी पथ (`/queries/run`) पर रक्षा-गहराई जोड़ता है, संकीर्ण करता है कि पथ क्या देख सकता है भले ही एक एप्लिकेशन-स्तरीय फ़िल्टर कभी गायब हो; सर्वर का अपना लेखन कनेक्शन तालिका मालिक के रूप में चलता है और इसलिए उसी ऐप-स्तरीय `org_id` स्कोपिंग के माध्यम से संचालित होता है। + +टेनेंट जीवनचक्र ऑपरेटर-नियंत्रित है, जबकि सदस्य जो कुछ भी दिन-प्रतिदिन करते हैं वह डैशबोर्ड में स्व-सेवा रहता है। संगठन और उनकी सदस्यता **`agenteye-orgctl`** CLI के साथ बनाई और प्रबंधित की जाती है, जो सर्वर छवि के अंदर शिप की जाती है और **मौजूदा सर्वर पॉड के अंदर** चलती है। टेनेंट निर्माण और विलोपन जानबूझकर डैशबोर्ड और HTTP API से दूर रखे जाते हैं: टेनेंट जीवनचक्र के लिए **कोई HTTP API नहीं और कोई डैशबोर्ड बटन नहीं** है, इसलिए यह एप्लिकेशन सतह के बजाय क्लस्टर/पॉड शेल एक्सेस के पीछे गेटेड है। + +एक संगठन के भीतर, सदस्य पूरी तरह से डैशबोर्ड और API में काम करते हैं: वे साइन इन करते हैं, उन संगठनों के बीच स्विच करते हैं जिनसे वे संबंधित हैं, अपनी स्वयं की API कुंजियों का प्रबंधन करते हैं, डैशबोर्ड और सहेजी गई क्वेरीज़ बनाते हैं, और अपने संगठन के लिए सतर्कताओं को कॉन्फ़िगर करते हैं। विभाजन स्पष्ट है: ऑपरेटर CLI के माध्यम से टेनेंट और उनके सदस्यों को प्रावधान और बंद करते हैं; सदस्य एक टेनेंट के अंदर UI के माध्यम से सब कुछ चलाते हैं। + +> **एकल-टेनेंट स्थापन को इसमें से कुछ की भी आवश्यकता नहीं है।** एकल-टेनेंट इंस्टॉल किसी ऑपरेटर कार्रवाई के बिना चलता है। सभी डेटा, उपयोगकर्ता, और कुंजियाँ एक निर्मित-में `default` संगठन में रहती हैं जो स्वचालित रूप से प्रावधान की जाती है। आप केवल इस गाइड की आवश्यकता है जब आप दूसरा संगठन जोड़ने का निर्णय लें। + +--- + +## पूर्वापेक्षाएँ + +इससे पहले कि आप अपना **दूसरा** संगठन बनाएं (निर्मित-में `default` संगठन को कुछ नहीं चाहिए): + +- **PostgreSQL 15+.** org-membership स्कीमा एक स्तंभ-सूची `ON DELETE SET NULL` विदेशी कुंजी का उपयोग करता है जिसके लिए PostgreSQL 15+ की आवश्यकता होती है। दूसरे संगठन को प्रावधान करने से पहले PostgreSQL को अपग्रेड करें। +- **एक मजबूत, स्थिर `ORG_CH_SECRET`.** प्रत्येक संगठन की ClickHouse पासवर्ड `HMAC(ORG_CH_SECRET, org_id)` के रूप में प्राप्त की जाती है, इसलिए सार्वजनिक रूप से-ज्ञात निर्मित-में dev डिफ़ॉल्ट सार्वजनिक रूप से-व्युत्पन्न प्रति-संगठन क्रेडेंशियल्स प्राप्त करेगा। `agenteye-orgctl org create` **जब तक `ORG_CH_SECRET` अनसेट है या निर्मित-में dev डिफ़ॉल्ट पर छोड़ा गया है तब तक चलाने से इनकार करता है**। पहले अपना स्वयं का मूल्य सेट करें (देखें [Deployment → environment variables](/hi/agenteye/deployment) और, Kubernetes पर, [§2.6 of the Kubernetes guide](/hi/agenteye/kubernetes-deployment#26-multi-tenant-org-isolation-key-optional))। सभी सर्वर प्रतिकृतियों में इसे समान रखें और इसे आकस्मिक रूप से घुमाएं नहीं; इसे घुमाने से हर संगठन की ClickHouse उपयोगकर्ता अनाथ हो जाती है जब तक अगली स्टार्टअप पुनः प्रावधान न करे। + +--- + +## CLI चलाना + +`agenteye-orgctl` **सर्वर के समान छवि में** शिप किया जाता है (`agenteye-server` के साथ-साथ)। आप इसके लिए एक अलग पॉड, Job, या Deployment को **नहीं** तैनात करते हैं; आप इसे सर्वर पॉड के अंदर exec करते हैं जो पहले से चल रहा है, इसलिए यह समान `DATABASE_URL`, `CLICKHOUSE_URL`, और `ORG_CH_SECRET` को पढ़ता है जो सर्वर उपयोग करता है। + +**Kubernetes:** + +```bash +kubectl -n agenteye exec deploy/server -- agenteye-orgctl +``` + +**Docker Compose:** + +```bash +docker compose exec server agenteye-orgctl +``` + +नीचे दिए गए उदाहरण संक्षिप्तता के लिए नंगे `agenteye-orgctl ` दिखाते हैं; प्रत्येक को आपकी तैनाती से मेल खाने वाली ऊपर की दोनों लाइनों में से किसी एक के साथ उपसर्ग करें। + +--- + +## कमांड संदर्भ + +### संगठन + +| कमांड | यह क्या करता है | +|---|---| +| `org create --slug --name ` | एक नया संगठन बनाएं। जब तक `ORG_CH_SECRET` अनसेट है या निर्मित-में dev डिफ़ॉल्ट पर छोड़ा गया है तब तक चलाने से इनकार करता है (पहले अपना स्वयं सेट करें, पूर्वापेक्षाएँ देखें)। संगठन की केवल-पढ़ने के लिए ClickHouse उपयोगकर्ता + पंक्ति नीति को प्रावधान करता है। | +| `org list` | सभी संगठनों को सूचीबद्ध करें (slug, name, और जीवनचक्र स्थिति)। | +| `org rename --slug --name ` | एक संगठन का प्रदर्शन नाम बदलें। slug (URLs और कुंजियों में उपयोग किया जाता है) अपरिवर्तित है। | +| `org delete --slug ` | संगठन को **soft-delete** करें और इसके ClickHouse उपयोगकर्ता को छोड़ दें। डेटा **बनाए रखा जाता है**। यह एक्सेस को रद्द करता है और प्रति-संगठन ClickHouse क्रेडेंशियल को मुक्त करता है, लेकिन इवेंट्स को मिटाता नहीं है। ऑपरेटर द्वारा प्रतिवर्तनीय; शुद्धि से पहले सुरक्षित पहली कदम। | +| `org purge --slug ` | **अप्रतिवर्तनीय डेटा पोंछ।** संगठन पहले से ही `delete`d होना चाहिए। कभी भी निर्मित-में `default` संगठन पर अनुमति नहीं। केवल तब उपयोग करें जब आप निश्चित हों कि टेनेंट का डेटा नष्ट हो जाना चाहिए। | + +### सदस्य + +| कमांड | यह क्या करता है | +|---|---| +| `member add --org --email [--set ] [--add perm1,perm2] [--remove perm3] [--protected]` | एक सदस्य को संगठन में जोड़ें। वैकल्पिक रूप से एक निर्मित अनुमति सेट से शुरू करें, फिर व्यक्तिगत अनुमतियों को जोड़ें/हटाएं। `--protected` सदस्य को पिन करता है इसलिए डैशबोर्ड उन्हें हटा या डीमोट नहीं कर सकता (नीचे देखें)। नया सदस्य अपने पहले डैशबोर्ड लॉगिन पर एक OTP प्राप्त करता है। | +| `member list --org ` | संगठन के सदस्यों को सूचीबद्ध करें। आउटपुट स्तंभ `EMAIL`, `SET` (निर्मित सेट जिससे सदस्य शुरू हुआ, या `-`), `PROT` (क्या सदस्य संरक्षित है), और `PERMISSIONS` (उनकी प्रभावी अनुमतियां) हैं। एक अनुगामी `*` के साथ दिखाया गया ईमेल एक उदाहरण व्यवस्थापक है; उनके पास हर संगठन तक पहुंच है। | +| `member update --org --email [--set ...] [--add ...] [--remove ...] [--protected \| --unprotect]` | सदस्य की अनुमतियों और/या संरक्षित ध्वज को बदलें। `--set` एक निर्मित सेट से बदलता है; `--add` / `--remove` व्यक्तिगत अनुमतियों को समायोजित करते हैं; `--protected` / `--unprotect` सुरक्षा को टॉगल करते हैं। केवल `--protected`/`--unprotect` (कोई अनुदान ध्वज नहीं) को पास करने से केवल सुरक्षा बदलती है और मौजूदा अनुमतियां अपरिवर्तित छोड़ी जाती हैं। | +| `member remove --org --email ` | संगठन से एक सदस्य को हटाएं। यदि सदस्य संरक्षित है तो इनकार करता है; पहले उन्हें `--unprotect` करें। (एक व्यक्ति कई संगठनों का सदस्य हो सकता है; यह केवल नामित संगठन को प्रभावित करता है।) | + +एक व्यक्ति **विभिन्न** अनुमतियों के साथ एक से अधिक संगठन का सदस्य हो सकता है, उदाहरण के लिए एक संगठन में व्यवस्थापक और दूसरे में केवल-पढ़ने के लिए। प्रत्येक सदस्यता प्रति संगठन स्वतंत्र रूप से प्रशासित होती है: एक संगठन में किसी व्यक्ति की अनुमतियों को देना या बदलना किसी अन्य में उनकी सदस्यता पर कोई प्रभाव नहीं डालता है। + +### संरक्षित सदस्य (एक अदुहि-हटाने योग्य संगठन प्रशासक) + +सुरक्षा गारंटी देती है कि एक संगठन कभी भी स्वयं को स्व-प्रबंधन से आकस्मिक रूप से बाहर नहीं कर सकता। डिफ़ॉल्ट रूप से एक संगठन के अपने व्यवस्थापक डैशबोर्ड के स्व-सेवा उपयोगकर्ताओं पृष्ठ के माध्यम से एक-दूसरे को जोड़ और हटा सकते हैं, इसलिए वे अंतिम प्रशासक को हटा सकते हैं और संगठन को इसे प्रबंधित करने में सक्षम किसी के बिना छोड़ सकते हैं। + +![उपयोगकर्ताओं पृष्ठ: प्रति डैशबोर्ड उपयोगकर्ता का एक कार्ड उनके ईमेल, दी गई अनुमतियों, और edit/disable नियंत्रणों के साथ](/agenteye/images/users.png) + +यह रोकने के लिए, एक सदस्य **संरक्षित** को चिह्नित करें: + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member add --org acme --email owner@acme.example --set admin --protected +``` + +एक संरक्षित सदस्य **डैशबोर्ड के माध्यम से नहीं हटाया जा सकता या डीमोट नहीं किया जा सकता**; ये कार्रवाइयां एक त्रुटि लौटाती हैं। केवल एक ऑपरेटर उन्हें बदल सकता है, और केवल इस CLI के माध्यम से: पहले `member update --org acme --email owner@acme.example --unprotect` चलाएं, फिर हटाएं या डीमोट करें। यह गारंटी देता है कि हर संगठन कम से कम एक प्रशासक रखता है जिसे इसके अपने सदस्य बाहर नहीं कर सकते, जबकि टेनेंट नियंत्रण को ऑपरेटर-केवल रखते हैं। सुरक्षा **प्रति-संगठन** है; किसी को एक संगठन में सुरक्षित करना दूसरे में उनकी सदस्यता पर कोई प्रभाव नहीं डालता है। + +### निर्मित अनुमति सेट + +`--set` तीन निर्मित सेटों में से एक को स्वीकार करता है, प्रति संगठन लागू: + +| सेट | इसका उद्देश्य है | +|---|---| +| `admin` | संगठन के भीतर पूर्ण पहुंच, संगठन की API कुंजियों और उपयोगकर्ताओं का प्रबंधन सहित। | +| `standard` | दिन-प्रतिदिन का उपयोग: पढ़ें + क्वेरीज़ चलाएं, डैशबोर्ड बनाएं, घटनाओं को स्वीकार करें। | +| `read-only` | संगठन के डेटा और डैशबोर्ड के लिए केवल-देखें पहुंच। | + +`--set` के साथ एक सेट से शुरू करें, फिर `--add` / `--remove` का उपयोग करके [API Keys](/hi/agenteye/api-keys) में सूचीबद्ध व्यक्तिगत अनुमति टोकन के साथ ठीक-ट्यून करें। अनुमति टोकन स्वयं API कुंजियों के लिए उपयोग किए जाने वाले समान हैं। + +--- + +## कार्य किया गया उदाहरण + +एक नया `acme` टेनेंट प्रावधान करें, इसके पहले व्यवस्थापक को जोड़ें, उन्हें एक कुंजी बनाने दें, फिर संगठन को बंद करें। + +**1. संगठन बनाएं** (`ORG_CH_SECRET` पहले से ही एक मजबूत, स्थिर मूल्य पर सेट होना चाहिए, अनसेट नहीं या निर्मित-में dev डिफ़ॉल्ट): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org create --slug acme --name "Acme Corp" +``` + +**2. पहले सदस्य को एक संगठन व्यवस्थापक के रूप में जोड़ें:** + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member add --org acme --email alice@acme.example --set admin +``` + +Alice को डैशबोर्ड में पहली बार साइन इन करने पर एक OTP प्राप्त होता है। उसके बाद वह पूरी तरह से अपने संगठन के URL उपसर्ग के तहत UI में काम करती है (उदाहरण के लिए `/acme/sessions`)। + +**3. प्रति-संगठन API कुंजी बनाएं (डैशबोर्ड में):** + +ऑपरेटर CLI से प्रति-संगठन डेटा कुंजी **नहीं** बनाता है। Alice (या `keys:create` के साथ कोई भी संगठन सदस्य) `acme` संगठन के लिए डैशबोर्ड के **Keys** पृष्ठ से कलेक्टर / डैशबोर्ड कुंजियां बनाता है। हर कुंजी जो वह बनाती है वह स्वचालित रूप से उसके संगठन के साथ मुहर की जाती है और केवल `acme`'s डेटा को पढ़ या लिख सकती है। [API Keys](/hi/agenteye/api-keys) देखें। + +**4. बाद में एक सदस्य को समायोजित करें:** + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member update --org acme --email alice@acme.example --add alerts:write + +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member list --org acme +``` + +**5. संगठन को soft-delete करें** (एक्सेस को रद्द करता है + इसके ClickHouse उपयोगकर्ता को छोड़ता है; डेटा बनाए रखा जाता है): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org delete --slug acme +``` + +**6. संगठन को purge करें** (अप्रतिवर्तनीय; केवल soft-delete के बाद; कभी भी `default` संगठन नहीं): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org purge --slug acme +``` + +Docker Compose पर, प्रत्येक `kubectl -n agenteye exec deploy/server --` उपसर्ग को `docker compose exec server` से बदलें। + +--- + +## जिम्मेदारियों का विभाजन + +एक संगठन के सदस्य को दिन-प्रतिदिन जरूरत की सब कुछ डैशबोर्ड और API में स्व-सेवा है, स्वचालित रूप से उनके वर्तमान संगठन के दायरे में: + +- **प्रति-संगठन API कुंजियां** संगठन के सदस्यों द्वारा डैशबोर्ड में (या कुंजियों API के माध्यम से `keys:create` को ले जाने वाली कुंजी के साथ) बनाई और प्रबंधित की जाती हैं। CLI डेटा कुंजी **नहीं** बनाता है। [API Keys](/hi/agenteye/api-keys) देखें। +- **संगठन स्विचिंग** डैशबोर्ड में निर्मित है; सदस्य संगठन स्विचर से उन संगठनों के बीच स्विच करते हैं जिनसे वे संबंधित हैं, और संगठन-स्कोप किए गए पृष्ठ `//…` के अंतर्गत रहते हैं। +- **डैशबोर्ड, सहेजी गई क्वेरीज़, सतर्कताएं, और सभी डेटा उपयोग** पूरी तरह से UI और API में होता है, सदस्य के वर्तमान संगठन के दायरे में। + +ऑपरेटर, `agenteye-orgctl` का उपयोग करते हुए, केवल संगठन + सदस्य **जीवनचक्र** के मालिक है: एक संगठन बनाएं / नाम बदलें / हटाएं / purge करें, और एक सदस्य जोड़ें / सूचीबद्ध करें / अपडेट करें / हटाएं। + +--- + +## यह भी देखें + +- [Deployment](/hi/agenteye/deployment): `ORG_CH_SECRET` और बाकी सर्वर पर्यावरण। +- [Kubernetes Deployment](/hi/agenteye/kubernetes-deployment): §2.6 आपके पहले multi-tenant संगठन से पहले `agenteye-org-ch-secret` Secret बनाता है। +- [API Keys](/hi/agenteye/api-keys): प्रति-संगठन कुंजी मॉडल और `--add` / `--remove` द्वारा उपयोग की जाने वाली अनुमति टोकन। +- [Troubleshooting](/hi/agenteye/troubleshooting): multi-tenant provisioning और ClickHouse-isolation समस्याएं। \ No newline at end of file diff --git a/docs/hi/agenteye/troubleshooting.mdx b/docs/hi/agenteye/troubleshooting.mdx new file mode 100644 index 00000000..dfbf4031 --- /dev/null +++ b/docs/hi/agenteye/troubleshooting.mdx @@ -0,0 +1,562 @@ +--- +title: "समस्या निवारण" +description: "AgentEye समस्या निवारण दस्तावेज़।" +--- + + +यह गाइड आपको उत्पादन में सबसे अधिक संभावित समस्याओं को ठोस निदान और समाधान से जोड़ता है, ताकि आप अतिरिक्त अवलोकन बुनियादी ढांचे को सेट किए बिना पहले से मौजूद उपकरणों से घटनाओं को हल कर सकें। यह सर्वर, कलेक्टर, डैशबोर्ड, एआई असिस्टेंट, Python SDK, स्वास्थ्य और प्रमाणपत्र निगरानी, बैकअप, ClickHouse-समर्थित विश्लेषण और बहु-किरायेदारी को कवर करता है। + +डैशबोर्ड पृष्ठ `//…` के तहत संगठन-स्कोप किए गए हैं, और इवेंट्स स्ट्रीम संगठन मुखपृष्ठ है (`//`)। इस गाइड में पृष्ठ के नाम (उदाहरण के लिए `/sessions`, `/queries`) उन संगठन-स्कोप किए गए मार्गों को संदर्भित करते हैं। + +--- + +## लॉग्स देखना + +AgentEye एक लॉगिंग या निगरानी स्टैक बंडल नहीं करता है। सर्वर और डैशबोर्ड दोनों **stdout** में संरचित लॉग्स लिखते हैं, इसलिए आप उन्हें `kubectl` या `docker` से सीधे पढ़ सकते हैं; कोई एकत्रकर्ता आवश्यक नहीं है। + +### Kubernetes + +सर्वर और डैशबोर्ड के लिए लाइव लॉग्स का पालन करें: + +```bash +kubectl logs -n agenteye -l app=server -f --timestamps +kubectl logs -n agenteye -l app=dashboard -f --timestamps +``` + +उपयोगी वेरिएंट: + +| लक्ष्य | कमांड | +|---|---| +| पिछली 200 लाइनें (कोई पालन नहीं) | `kubectl logs -n agenteye -l app=server --tail=200 --timestamps` | +| पिछले क्रैश से लॉग्स | `kubectl logs -n agenteye --previous` | +| सभी प्रतिकृतियों को एक बार टेल करें | `kubectl logs -n agenteye -l app=server --max-log-requests=10 -f` | +| Postgres (StatefulSet) | `kubectl logs -n agenteye postgres-0 -f` | + +### Docker Compose + +```bash +docker logs -f agenteye-server +docker logs -f agenteye-dashboard +``` + +### डैशबोर्ड और सर्वर भर में एक अनुरोध को जोड़ना + +हर डैशबोर्ड अनुरोध एक `request_id` से टैग किया जाता है और `x-request-id` हेडर के माध्यम से सर्वर को प्रचारित किया जाता है। सर्वर इसे अपने प्रतिक्रिया हेडर में और उस अनुरोध के लिए उत्सर्जित हर लॉग लाइन में दोहराता है। एक अनुरोध को अंत-से-अंत ट्रेस करने के लिए: + +1. प्रतिक्रिया हेडर से आईडी कैप्चर करें, उदाहरण के लिए: + ```bash + curl -i https://dashboard.example.com/api/events | grep -i x-request-id + # x-request-id: 9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a + ``` +2. उस आईडी के लिए दोनों पॉड्स के लॉग्स को grep करें: + ```bash + REQ=9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a + kubectl logs -n agenteye -l app=dashboard --tail=5000 | grep "$REQ" + kubectl logs -n agenteye -l app=server --tail=5000 | grep "$REQ" + ``` + +आप डैशबोर्ड की `proxy passthrough`, `withAuth: authorized`, और `upstream response` लाइनें देखेंगे, साथ ही सर्वर की `http request received` / `http request completed` जोड़ी, सभी एक ही `request_id` साझा करते हुए। + +### JSON लॉग्स और `jq` + +डैशबोर्ड पर `AE_LOG_JSON=1` सेट करें (यह डिफ़ॉल्ट रूप से चालू है जब `NODE_ENV=production`) एक JSON ऑब्जेक्ट प्रति लाइन उत्सर्जित करने के लिए। फिर संरचनात्मक रूप से फ़िल्टर करें: + +```bash +kubectl logs -n agenteye -l app=dashboard --tail=5000 \ + | jq 'select(.level == "warn" or .level == "error")' + +kubectl logs -n agenteye -l app=dashboard --tail=5000 \ + | jq 'select(.route == "POST /api/keys")' +``` + +Rust सर्वर tracing `key=value` जोड़ी उत्सर्जित करता है जो `jq` के बिना अच्छी तरह से grep करते हैं: + +```bash +kubectl logs -n agenteye -l app=server --tail=5000 | grep 'status=5' # 5xx +kubectl logs -n agenteye -l app=server --tail=5000 | grep 'actor_key_id=' +``` + +### वर्बोसिटी को बढ़ाना + +| घटक | पर्यावरण चर | उदाहरण | +|---|---|---| +| सर्वर | `RUST_LOG` | `RUST_LOG=debug` या `RUST_LOG=agenteye_server=debug,info` | +| डैशबोर्ड | `AE_LOG_LEVEL` | `AE_LOG_LEVEL=debug` | + +सर्वर पर `debug` प्रति-प्रमाणीकरण `api key authenticated` लाइन जोड़ता है। डैशबोर्ड पर `debug` `upstream request`, `session validated`, और `proxy passthrough` लाइनें जोड़ता है। + +### लॉग प्रतिधारण + +कंटेनर stdout अस्थायी है; kubelet लॉग फ़ाइलों को घुमाता है (डिफ़ॉल्ट ~10 MiB प्रति कंटेनर) और डिस्क पर कुछ रखता है। एक बार पॉड हटाए जाने के बाद लॉग्स चले जाते हैं। यदि आपको लंबी प्रतिधारण या क्रॉस-पॉड खोज की आवश्यकता है, तो अपने क्लस्टर को एक लॉग कलेक्टर (Loki, CloudWatch, Cloud Logging, Datadog, आदि) की ओर इंगित करें जो `/var/log/containers/` को टेल करता है। AgentEye किसी विशिष्ट विकल्प की आवश्यकता या निर्धारण नहीं करता है। + +--- + +## प्रमाणीकरण समस्याएं + +### `docker pull` "unauthorized" के साथ विफल होता है + +सुनिश्चित करें कि आपने अपने `AGENTEYE_TOKEN` के साथ GHCR के विरुद्ध Docker को प्रमाणित किया है: + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +टोकन में `agenteye-enterprise` संगठन पर `read:packages` अनुमति होनी चाहिए। यदि आपका टोकन काम नहीं करता है तो `support@exosphere.host` से संपर्क करें। + +### `gh release download` 404 या 401 देता है + +- पुष्टि करें कि `AGENTEYE_TOKEN` आपके शेल में निर्यात किया गया है: `echo $AGENTEYE_TOKEN` +- पुष्टि करें कि आप `GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download ...` का उपयोग कर रहे हैं (the `gh` CLI `GITHUB_TOKEN` को पढ़ता है) +- टोकन को `agenteye-enterprise/releases` पर `contents:read` की आवश्यकता है + +--- + +## सर्वर समस्याएं + +### सर्वर "invalid port number" के साथ विफल होता है + +`POSTGRES_PASSWORD` (या अन्य क्रेडेंशियल) में URL-विशेष वर्ण (`/`, `+`, `=`) हैं जो `DATABASE_URL` पार्सिंग को तोड़ते हैं। हेक्स एन्कोडिंग का उपयोग करके पासवर्ड पुनः उत्पन्न करें: + +```bash +NEW_PASS=$(openssl rand -hex 24) +``` + +फिर Kubernetes गोपनीयता और Postgres के अंदर पासवर्ड को अपडेट करें (या Docker Compose के लिए `.env` को पुनः बनाएं), और सर्वर को पुनरारंभ करें। [enterprise-docs/kubernetes-deployment.md](/hi/agenteye/kubernetes-deployment) § "PostgreSQL credentials" में पूर्ण चरण देखें। + +### सर्वर स्टार्टअप पर तुरंत बाहर निकलता है + +कंटेनर लॉग्स जांचें: + +```bash +docker logs agenteye-server +``` + +सामान्य कारण: +- `DATABASE_URL` सेट नहीं है या विकृत है: सर्वर त्रुटि लॉग करेगा और बाहर निकलेगा। +- Postgres पहुंच योग्य नहीं है: पुष्टि करें कि Postgres कंटेनर या प्रबंधित DB चल रहा है और होस्ट/पोर्ट सही हैं। +- माइग्रेशन विफल हुए: SQL त्रुटियों के लिए लॉग्स जांचें। + +### `GET /health` गैर-200 या टाइमआउट देता है + +सर्वर पहली शुरुआत पर अभी भी माइग्रेशन चलाया जा रहा है। कुछ सेकंड प्रतीक्षा करें और पुनः प्रयास करें: + +```bash +curl http://localhost:8080/health +``` + +यदि समस्या बनी रहती है, तो त्रुटियों के लिए `docker logs agenteye-server` जांचें। + +### `GET /ready` 503 देता है + +`/ready` readiness जांच है: यह 503 देता है जब सर्वर **Postgres या ClickHouse** तक पहुंच नहीं सकता है। शरीर विफल निर्भरता का नाम बताता है: + +```bash +curl -s http://localhost:8080/ready +# {"status":"not_ready","checks":{"postgres":"ok","clickhouse":"down","redis":"ok"}} +``` + +जो निर्भरता यह `down` के रूप में रिपोर्ट करता है उसे ठीक करें: क्या ClickHouse/Postgres पॉड `Running` है? क्या `CLICKHOUSE_URL` / `DATABASE_URL` सही और पहुंच योग्य है? Kubernetes पर पॉड `NotReady` पढ़ता है जब तक `/ready` ठीक नहीं होता; यह अपेक्षित है और बिल्कुल वह संकेत है जो स्वास्थ्य निगरानी सतर्क करता है। Redis कभी कारण नहीं है: यह रिपोर्ट किया जाता है लेकिन readiness को विफल नहीं करता। + +### कलेक्टर 401 Unauthorized देता है + +कलेक्टर की API कुंजी के पास `events:add` अनुमति नहीं है, या कुंजी को अक्षम किया गया है। सही अनुमति के साथ एक नई कुंजी बनाएं: + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{"name":"new-collector","permissions":["events:add"]}' +``` + +### प्रमाणित अनुरोध अचानक धीमे हो गए (~200ms के बजाय ~5ms) + +यह Redis के नीचे होने का लक्षण है जबकि `REDIS_URL` सेट है। हर कैश कॉल 100ms के बाद टाइमआउट करता है फिर Postgres में गिरता है; प्रमाणीकरण और OTP पथों पर अनुरोध दो ऐसे पतन बनाता है। + +सर्वर लॉग्स में पुष्टि करें: + +``` +auth cache: L2 get failed error=redis call timed out +``` + +समाधान: + +1. `redis-cli -h ping` क्लस्टर नेटवर्क पर Redis पहुंच योग्य है यह पुष्टि करने के लिए। +2. यदि Redis संक्षिप्त रूप से नीचे था और अब वापस है, तो **सर्वर पॉड्स को पुनरारंभ करें**। `redis::aio::ConnectionManager` अंतर्निहित कनेक्शन गिरने के बाद विश्वसनीय रूप से पुनः स्थापित नहीं करता; पॉड रीस्टार्ट नई कनेक्शन को साफ-सुथरे तरीके से उठाता है। डैशबोर्ड पर भी वही लागू होता है। +3. यदि आप अभी Redis नहीं चलाना चाहते हैं, तो तैनाती में `REDIS_URL` को अनसेट करें और पुनरारंभ करें। दोनों सेवाएं कैश के बिना चलती हैं (शुद्धता संरक्षित है; विलंबता Redis-पूर्व आधारभूत पर वापस आता है)। + +### सर्वर लॉग्स में `OTP request rate-limited` रिपोर्ट करता है लेकिन उपयोगकर्ता कहता है कि वे केवल एक बार प्रयास करते हैं + +जांचें कि क्या Redis अपहुंच्य था। फॉलबैक पथ `SELECT COUNT(*) FROM otp_codes WHERE created_at > now() - interval '15 minutes'` का उपयोग करता है, जो पहले से उत्पन्न OTP पंक्तियों को देखता है। यदि उपयोगकर्ता एक घंटे के लिए "Resend" पर क्लिक-स्पैम कर रहा है, तो 15-मिनट की विंडो में अभी भी ≥5 कोड हो सकते हैं। विंडो के रोल-ओवर के लिए प्रतीक्षा करके या `DELETE FROM otp_codes WHERE user_id = $1 AND created_at > now() - interval '15 minutes'` (ऑपरेटर कंसोल) को समाधान करें। + +### मैंने `ALLOWED_EMAILS` / `SESSION_TTL_SECS` / `OTP_TTL_SECS` बदला और पुनरारंभ किया; कुछ नहीं हुआ + +ये env वेरिएबल्स **पहली बूट सीड्स केवल** हैं। एक बार `settings` तालिका में मिलान कुंजी के लिए एक पंक्ति होने के बाद, वह पंक्ति सत्य का स्रोत है; env वेरिएबल पहली बूट पर एक बार पढ़ा जाता है और फिर हर बाद की रीस्टार्ट पर अनदेखा किया जाता है। + +पहली बूट के बाद उन्हें बदलने के लिए, डैशबोर्ड में लॉगिन करें और `/settings` के तहत उन्हें संपादित करें। परिवर्तन सभी प्रतिकृतियों भर में सेकंड के भीतर लागू होता है; कोई रीस्टार्ट आवश्यक नहीं है। + +यदि आप env से पुनः-सीड को बल देने की आवश्यकता है (दुर्लभ, आमतौर पर विकास में केवल उपयोगी), `DELETE FROM settings WHERE key = ''` और सर्वर को पुनरारंभ करें। बूटस्ट्रैप अगली बूट पर वर्तमान env-var मान लेगा। `/settings` के माध्यम से संपादित करना उत्पादन में समर्थित पथ है। + +--- + +## कलेक्टर समस्याएं + +### कलेक्टर शुरू होता है लेकिन इवेंट्स डैशबोर्ड में नहीं दिख रहे हैं + +1. पुष्टि करें कि कलेक्टर चल रहा है: `systemctl status agenteye-collector` (Linux) या प्रक्रिया जांचें। +2. पुष्टि करें कि `AGENTEYE_URL` `http(s)://your-server-host:8080/events` की ओर इंगित करता है (नोट: `/events` पथ)। +3. तत्काल आउटपुट देखने के लिए एक-बार फ्लश चलाएं: + ```bash + agenteye-collector flush + ``` +4. जांचें कि Python SDK वास्तव में फाइलें लिख रहा है: `ls ${AGENTEYE_HOME:-~/.agenteye}/events/` +5. यदि `${AGENTEYE_HOME:-~/.agenteye}/failed/` में फाइलें मौजूद हैं, तो अपलोड विफल हो रहे हैं। कलेक्टर लॉग्स में त्रुटि जांचें, संभवतः 4xx (खराब कुंजी या URL) या नेटवर्क समस्या। + +### फाइलें `$AGENTEYE_HOME/events/` में जमा हो रही हैं और अपलोड नहीं हो रही हैं + +- कलेक्टर नहीं चल रहा हो सकता है। इसे शुरू करें: `agenteye-collector start`; यह स्टार्टअप पर पहले से मौजूद इवेंट्स को स्वचालित रूप से फ्लश करता है। +- कलेक्टर स्वास्थ्य जांचें: `agenteye-collector health` +- कलेक्टर चल रहा हो सकता है लेकिन सर्वर तक पहुंचने में असमर्थ है। कलेक्टर और सर्वर होस्ट के बीच फायरवाल नियम जांचें। + +### `$AGENTEYE_HOME/failed/` में फाइलें + +सभी पुनः प्रयास प्रयासों (डिफ़ॉल्ट: 5 प्रयास exponential backoff के साथ) के समाप्त होने के बाद फाइलें `failed/` में जाती हैं। इसका मतलब है: +- सर्वर ने 4xx त्रुटि देी (खराब कुंजी, गलत URL, या पेलोड समस्या) +- संपूर्ण पुनः प्रयास विंडो के लिए सर्वर अपहुंच्य था + +अंतर्निहित समस्या को ठीक करें, फिर मैन्युअल रूप से पुनः-कतार करें: + +```bash +mv ${AGENTEYE_HOME:-~/.agenteye}/failed/*.jsonl ${AGENTEYE_HOME:-~/.agenteye}/events/ +agenteye-collector flush +``` + +### कलेक्टर हर अपलोड पर `network error` रिपोर्ट करता है (TLS हैंडशेक विफल) + +यदि `curl -k` के विरुद्ध `AGENTEYE_URL` सफल होता है लेकिन कलेक्टर बाइनरी `error sending request for url (...)` के साथ हर अपलोड विफल करता है, तो AgentEye सर्वर एक TLS प्रमाणपत्र प्रस्तुत कर रहा है जो सार्वजनिक रूप से विश्वसनीय CA द्वारा हस्ताक्षरित नहीं है। + +**उत्पादन पथ** `deploy/base/certificates/domain.env` में कॉन्फ़िगर किया गया ACME ingest होस्टनाम है ([`kubernetes-deployment.md`](/hi/agenteye/kubernetes-deployment) Phase 3.1 / 4.2 देखें)। एक बार `INGEST_DOMAIN` सार्वजनिक Traefik LB में हल होने के बाद और cert-manager Let's Encrypt cert जारी कर देता है, कलेक्टर **कोई `AGENTEYE_TLS_CA` की आवश्यकता नहीं**; सिस्टम ट्रस्ट स्टोर के विरुद्ध सर्वर cert को सत्यापित करता है; यदि यह पुरानी स्व-हस्ताक्षरित तैनाती के विरुद्ध सेट था तो इसे कलेक्टर कॉन्फ़िग से साफ करें। + +**लक्षण: कलेक्टर कल काम करता था, ~90-दिन के अंतराल के बाद आज विफल हो जाता है।** इसका मतलब है तैनाती अभी भी `ingest-tls` के लिए legacy `selfsigned` issuer पर है। 90-दिन का प्रमाणपत्र घुमाया गया और pinned CA फाइल पुरानी है। permanently को fix करके deployment guide के Phase 3.1 के लिए क्लस्टर को ACME issuer पर स्विच करें। short-term को अनब्लॉक करें: वर्तमान सर्वर प्रमाणपत्र को पुनः-निकालें और `AGENTEYE_TLS_CA` को अपडेट करें: + +```bash +kubectl get secret ingest-tls-cert -n agenteye \ + -o jsonpath='{.data.tls\.crt}' | base64 -d > /etc/agenteye/server-ca.crt +``` + +```bash +export AGENTEYE_TLS_CA=/etc/agenteye/server-ca.crt +agenteye-collector flush +``` + +`AGENTEYE_TLS_CA` एक अतिरिक्त विश्वास anchors जोड़ता है; मानक सार्वजनिक रूट्स अभी भी विश्वसनीय हैं। + +### तैनाती के बाद `ingest-tls` Certificate `Ready: False` में फंस गया है + +```bash +kubectl describe certificate ingest-tls -n agenteye +``` + +`Events` और संदर्भित `Order` / `Challenge` देखें। सामान्य कारण: + +- **DNS सार्वजनिक LB को हल नहीं कर रहा है।** HTTP-01 वेलिडेटर `INGEST_DOMAIN` तक नहीं पहुंच सकता। `dig +short INGEST_DOMAIN` के साथ सत्यापित करें; यह `traefik-public` LoadBalancer के `EXTERNAL-IP` के समान पते को हल करना चाहिए। cert-manager स्वचालित रूप से पुनः प्रयास करता है एक बार DNS प्रसारित होता है; प्रमाणपत्र को हटाने की कोई आवश्यकता नहीं है। +- **पोर्ट 80 लोड बैलेंसर / सुरक्षा समूह पर ब्लॉक किया गया है।** HTTP-01 को Let's Encrypt के सार्वजनिक वेलिडेटर्स से `:80` पहुंच योग्य होने की आवश्यकता है। यदि आपके पास अपस्ट्रीम WAF या SG `:80` को सीमित कर रहा है, तो इसे खोलें (Traefik कॉन्फ़िग HTTPS में पुनर्निर्देश करता है, लेकिन Boulder पुनर्निर्देश का पालन करता है और प्रतिक्रिया स्वीकार करता है)। +- **`dnsNames` प्रतिस्थापित नहीं।** यदि `kubectl get certificate ingest-tls -n agenteye -o jsonpath='{.spec.dnsNames}'` `INGEST_DOMAIN_PLACEHOLDER` दिखाता है, तो आपने `domain.env` स्टेप को छोड़ा; इसे `domain.env.example` से बनाएं और पुनः-लागू करें। +- **Let's Encrypt द्वारा Rate limited।** एक ही होस्टनाम के लिए बार-बार विफल आदेश डुप्लिकेट-प्रमाणपत्र या विफल-सत्यापन सीमाएं tripped करते हैं। पुनः प्रयास करने से पहले कम से कम एक घंटा प्रतीक्षा करें; सटीक rate-limit संदेश के लिए Order status जांचें। + +### `dashboard-tls` Certificate `Ready: False` में फंस गया है / ब्राउज़र अभी भी चेतावनी दिखाता है + +`ingest-tls` के समान निदान प्रवाह (`kubectl describe certificate dashboard-tls -n agenteye`); DNS, port-80, placeholder, और rate-limit कारण सभी लागू होते हैं, साथ ही दो डैशबोर्ड-विशिष्ट भी: + +- **`DASHBOARD_DOMAIN` गलत LoadBalancer को हल करता है।** यह सार्वजनिक ingest के बजाय *डैशबोर्ड* Traefik LB की ओर इंगित करना चाहिए। होस्टनाम को `dig +short` करें और डैशबोर्ड LB पते के विरुद्ध तुलना करें। +- **डैशबोर्ड Traefik इंस्टेंस चुनौती को परोस नहीं सकता है।** इसे bundled डैशबोर्ड values फाइल के साथ स्थापित किया जाना चाहिए, जो cert-manager के HTTP-01 solver के लिए scoped Ingress प्रदाता को सक्षम बनाता है। इसके बिना solver अप्राप्य है और Order हमेशा के लिए `pending` रहता है। प्रदान किए गए values के साथ इंस्टेंस को अपग्रेड करें; pending challenge फिर अपने आप पूरा हो जाता है। +- **LoadBalancer IP-प्रतिबंधित था।** स्रोत रेंज पोर्ट 80 पर भी लागू होती हैं, जो Let's Encrypt के वेलिडेटर्स को ब्लॉक करता है — पहली जारी और हर ~75-दिन की नवीकरण दोनों। LB को खोलें, या इसे लॉक करने से पहले support के साथ DNS-01 solver का समन्वय करें। + +जारी करना विफल होने के दौरान, डैशबोर्ड अपना पिछला प्रमाणपत्र (या ताजी install पर ingress डिफ़ॉल्ट) परोस रहा है — पहुंच ब्राउज़र चेतावनी द्वारा कम हो गया है, कभी नीचे नहीं। + +### CLI अभी भी TLS सत्यापन को छोड़ता है डैशबोर्ड को विश्वस्त प्रमाणपत्र मिलने के बाद + +`--insecure` को `cli.json` पर login पर persist किया जाता है। एक बार डैशबोर्ड सार्वजनिक रूप से विश्वसनीय प्रमाणपत्र परोस रहा हो, `agenteye --base-url https:// --secure login` के साथ फिर से लॉगिन करें; सत्यापन वापस बचाया जाता है और startup चेतावनी गायब हो जाती है। + +--- + +## डैशबोर्ड समस्याएं + +### `ADMIN_EMAIL` उपयोगकर्ता को अक्षम या संपादित नहीं कर सकते + +डिज़ाइन के अनुसार। `ADMIN_EMAIL` से मेल खाने वाला उपयोगकर्ता हर सर्वर स्टार्टअप पर protected के रूप में चिह्नित किया जाता है: डैशबोर्ड उस पंक्ति के लिए Disable बटन छुपाता है, और API इसके विरुद्ध `DELETE /users/:id` और `PUT /users/:id` को `403 Forbidden` के साथ अस्वीकार करता है। एक डेटाबेस ट्रिगर भी प्रत्यक्ष `UPDATE` स्टेटमेंट को अस्वीकार करता है जो protected पंक्ति को अक्षम करेंगे। + +बूटस्ट्रैप admin को rotate करने के लिए, अपने environment में `ADMIN_EMAIL` बदलें और सर्वर को पुनरारंभ करें। नया ईमेल protected के रूप में upserted है। पिछला admin protected ध्वज को retain करता है जब तक डेटाबेस में साफ नहीं किया जाता (आमतौर पर ठीक है, क्योंकि पिछला ईमेल तब तक एक valid admin है जब तक आप स्पष्ट रूप से उन्हें नहीं हटाते)। + +### डैशबोर्ड कोई इवेंट्स नहीं दिखाता है + +1. डैशबोर्ड के environment वेरिएबल्स (`AGENTEYE_SERVER_URL`, `AGENTEYE_API_KEY`) में सर्वर URL और API कुंजी सही हैं यह पुष्टि करें। +2. डैशबोर्ड API कुंजी को `events:read` अनुमति की आवश्यकता है। +3. इवेंट्स वास्तव में ingested हैं यह पुष्टि करें: `curl http://your-server:8080/events -H "Authorization: Bearer $ADMIN_KEY"` + +### `/errors` खाली है लेकिन `/events` लाल पंक्तियां दिखाता है + +नए SDK संस्करण `agent_end` / `tool_result` / `hook_completed` इवेंट्स के रूप में failures को dedicated `event_type: "error"` पंक्ति के बजाय पेलोड में `outcome: "error"` के साथ उत्सर्जित करते हैं। `/errors` पृष्ठ अब दोनों को जोड़ता है: कोई भी पंक्ति जो `/events` स्ट्रीम लाल रंग में पेंट करता है (explicit `event_type='error'`, पेलोड `outcome`/`status` विफलता सेट में, `is_error: true`, या truthy `error` फील्ड) `/errors` पर दिखाई देता है। यदि आप पहले "/events" पर red पंक्तियों के visible होने के दौरान "no errors in this window" देखते थे, तो डैशबोर्ड + सर्वर को एक साथ अपग्रेड करें (broadened filter `errored=true` on `GET /events` है) और दोनों views सहमत होंगे। + +### `/models`, `/tools`, या `/hooks` wide समय रेंज पर धीमा या लोड करने में विफल है + +**लक्षण:** एक बड़ी events तालिका पर (लाखों पंक्तियां), `/models`, `/tools`, या `/hooks` को खोलना — या समय रेंज को `7d`, `30d`, या `all` तक चौड़ा करना — चार्ट स्पिन करते हैं और फिर लोड त्रुटि दिखाते हैं। सर्वर `latency_aggregate` अनुरोध के लिए ClickHouse `MEMORY_LIMIT_EXCEEDED` (Code 241) या query timeout को लॉग करता है। + +**कारण:** पुरानी builds ने इन पृष्ठों की latency और distribution rollups को एक query के साथ गणना की जो पूरे raw event `payload` को पढ़ता है और request/response events को एक in-memory sort-and-join के साथ जोड़ता है। Peak query memory इसलिए विंडो के आकार के साथ बढ़ता है, इसलिए एक busy tenant पर एक wide रेंज ClickHouse के per-query memory ceiling को exceed कर सकता है। + +**Fix:** इस fix को शामिल करने वाली build में अपग्रेड करें। Rollup अब केवल compact promoted columns को पढ़ता है और events को streaming aggregation के साथ जोड़ता है, इसलिए peak memory अब raw payload के आकार के साथ स्केल नहीं करता है — wide windows memory ceiling के भीतर अच्छी तरह रहते हैं और fraction of time में return होते हैं। सुधार पूरी तरह से query-side है: यह अगले पृष्ठ लोड पर सभी मौजूदा data पर लागू होता है, कोई re-ingest या backfill के बिना। + +### डैशबोर्ड लोड करने में विफल / blank पृष्ठ + +डैशबोर्ड कंटेनर लॉग्स जांचें: + +```bash +docker logs agenteye-dashboard +``` + +सबसे सामान्य कारण `AGENTEYE_SERVER_URL` या `AGENTEYE_API_KEY` missing है या unreachable सर्वर की ओर इंगित करता है। + +### डैशबोर्ड विश्लेषण / टेलीमेट्री + +डैशबोर्ड डिफ़ॉल्ट रूप से anonymous product-usage analytics को PostHog को भेजता है, डैशबोर्ड के अपने `/ingest` पथ के माध्यम से routed (a reverse proxy to `https://us.i.posthog.com`)। उन्हें first-party के माध्यम से भेजने का मतलब ब्राउज़र ad-blockers उन्हें drop नहीं करते। यह डैशबोर्ड की मुख्य कार्यक्षमता से independent है: + +- **डैशबोर्ड कंटेनर** (ब्राउज़र नहीं) वही है जो PostHog तक पहुंचता है। यदि इसकी आउटबाउंड access `https://us.i.posthog.com` को ब्लॉक किया जाता है, तो टेलीमेट्री silently no-ops; डैशबोर्ड सामान्य रूप से काम करता है और कोई त्रुटियां users को surfaced नहीं होती हैं। +- कोई agent, session, या event data कभी included नहीं है, केवल dashboard UI usage। +- टेलीमेट्री को पूरी तरह से अक्षम करने के लिए, डैशबोर्ड कंटेनर पर `AE_ANALYTICS_DISABLED=1` सेट करें और पुनरारंभ करें। तैनाती guide में [Telemetry & privacy](/hi/agenteye/deployment#telemetry--privacy) देखें। + +### CLI विश्लेषण / टेलीमेट्री + +`agenteye` CLI डिफ़ॉल्ट रूप से anonymous usage analytics को PostHog को भेजता है: कौन सी commands चलती हैं, success/exit status, और duration। यह CLI की कार्यक्षमता से independent है: + +- **CLI चलाने वाली machine** `https://us.i.posthog.com` सीधे तक पहुंचता है। यदि इसकी आउटबाउंड access ब्लॉक किया जाता है, तो टेलीमेट्री silently no-ops (sending time-bounded है, इसलिए यह कभी command को delay नहीं करता) और CLI सामान्य रूप से काम करता है। +- कोई agent, session, या event data कभी included नहीं है: command **arguments और flag values** (dashboard URL, token, email, session ids, query filters) कभी नहीं भेजे जाते हैं। +- इसे अक्षम करने के लिए, CLI के environment में `AGENTEYE_ANALYTICS_DISABLED=1` (या cross-tool `DO_NOT_TRACK=1`) सेट करें। CLI guide में [Telemetry & privacy](/hi/agenteye/cli#telemetry--privacy) देखें। + +--- + +## एआई असिस्टेंट समस्याएं + +पूर्ण setup के लिए [enterprise-docs/assistant.md](/hi/agenteye/assistant) देखें। + +### असिस्टेंट बुलबुला नहीं दिखाई देता है + +बुलबुला hidden है जब तक **सभी** ये hold नहीं करते: + +- Signed-in user के पास `agent:use` अनुमति है। +- `AGENTEYE_AGENT_URL` डैशबोर्ड पर सेट है और `agent` सेवा पहुंच योग्य है। +- एक LLM endpoint `agent` सेवा पर कॉन्फ़िगर किया गया है (`ANTHROPIC_API_KEY`, `ANTHROPIC_BASE_URL` के माध्यम से एक gateway, या Bedrock/Vertex)। कोई भी सेट नहीं होने पर, agent "not configured" रिपोर्ट करता है और बुलबुला hidden रहता है। + +डैशबोर्ड होस्ट से agent के स्वास्थ्य की जांच करें: `curl http://agent:9100/health` को `{"status":"ok","llm_configured":true,...}` return करना चाहिए। + +### असिस्टेंट कहता है कि यह कुछ नहीं पढ़ सकता + +Tools प्रति-user gated हैं। यदि user के पास `evaluations:read` (या `events:read`, `dashboards:read`) नहीं है, तो मिलान tools offered नहीं हैं और असिस्टेंट कहेगा कि यह वह data नहीं पढ़ सकता। प्रासंगिक read अनुमति दें। + +### भेजते समय "assistant not configured" (HTTP 503) + +`agent` कंटेनर के पास कोई LLM endpoint कॉन्फ़िगर नहीं है, या डैशबोर्ड का `AGENTEYE_AGENT_TOKEN` agent के से मेल नहीं खाता। दोनों सेट करें और पुनरारंभ करें। + +### `agent` कंटेनर लोड के तहत restarts / OOMs + +प्रत्येक बातचीत एक short-lived child process spawn करता है। सुनिश्चित करें कि कंटेनर एक init process के साथ चलता है (image `tini` का उपयोग करता है; Compose में `init: true` सेट करें) और इसे adequate memory limits दें। यदि आवश्यक हो तो `AGENTEYE_AGENT_MAX_STEPS` को कम करें। + +--- + +## CLI समस्याएं + +### `agenteye` `ModuleNotFoundError: No module named 'click'` के साथ शुरू करने में विफल + +Version **0.1.6** पर `agenteye` CLI का ताजा install: + +``` +ModuleNotFoundError: No module named 'click' +``` + +के साथ crash हो सकता है। + +0.1.6 `click` को `typer` द्वारा indirectly स्थापित किए जाने पर निर्भर था; वर्तमान `typer` releases अब इसे pull नहीं करते हैं, इसलिए एक clean environment में पैकेज missing हो सकता है। **0.1.7 या नए में अपग्रेड करें**, जो `click` पर directly निर्भर है: + +```bash +pipx upgrade agenteye # यदि pipx के साथ स्थापित (या: pipx install --force agenteye) +uv tool upgrade agenteye # यदि uv के साथ स्थापित +pip install --upgrade agenteye +``` + +Install guidance के लिए [enterprise-docs/cli.md](/hi/agenteye/cli) देखें। + +--- + +## Python SDK समस्याएं + +### `$AGENTEYE_HOME/events/` में कोई फाइलें नहीं दिख रहीं + +SDK events को buffer करता है और डिफ़ॉल्ट रूप से हर 500 ms को flush करता है। यदि आपकी प्रक्रिया flush से पहले exits करती है, तो events खो सकते हैं। short-lived scripts में तेजी से flushing के लिए `agenteye.configure(flush_interval=0.1)` को कॉल करें, या सुनिश्चित करें कि आपकी प्रक्रिया एक flush cycle के लिए काफी time चलती है। + +यदि `AGENTEYE_HOME` सेट है, तो सत्यापित करें कि SDK `$AGENTEYE_HOME/events/` में लिख रहा है न कि `~/.agenteye/events/` (requires SDK ≥ 0.0.1b5)। + +### `ValueError: Reserved field names cannot be used as custom fields` + +नाम `timestamp`, `type`, और `environment` reserved हैं और custom fields के रूप में उपयोग नहीं किए जा सकते। इनमें से कोई भी पास करना raise करता है: + +``` +ValueError: Reserved field names cannot be used as custom fields: [...] +``` + +offensive custom field को rename करें। नोट करें कि `session_id` और `agent_id` event call के explicit parameters हैं, custom fields नहीं; किसी को फिर से custom field के रूप में passing करना `TypeError` raise करता है। + +--- + +## Health Monitoring समस्याएं + +### Slack में कोई alerts नहीं आ रहे (Robusta) + +Robusta health alerting **opt-in** है; जब तक स्थापित और Slack channel की ओर इंगित नहीं किया जाता है तब तक यह कुछ नहीं भेजता। release और इसके sink को सत्यापित करें: + +```bash +kubectl get pods -n robusta # robusta-runner + robusta-forwarder Running होना चाहिए +kubectl logs -n robusta -l app=robusta-runner --tail=50 +``` + +सामान्य कारण: Slack `api_key` / `slack_channel` सेट नहीं थे (या token को revoked किया गया); `api_key` Robusta cloud-relay token है (`robusta integrations slack`) लेकिन bundled `disableCloudRouting: true` को self-hosted Slack **bot token** (`xoxb-…`) की आवश्यकता है, या `disableCloudRouting: false` सेट करें; sink `scope` उस namespace को exclude करता है जहां आपके pods चलते हैं (bundled values scope to `agenteye`); या कोई failure अभी नहीं हुआ है। एक pod को नीचे ले जाकर एक test alert को force करें: + +```bash +kubectl -n agenteye delete pod -l app=clickhouse # यह recreate होगा +``` + +Install और configuration के लिए [enterprise-docs/health-monitoring.md](/hi/agenteye/health-monitoring#2-pod-failure-alerting-with-robusta-opt-in) देखें। + +### सर्वर लगातार `NotReady` फ्लैप कर रहा है + +Readiness probe `/ready` को hit करता है, जो Postgres या ClickHouse unreachable होने पर fail होता है। यदि सर्वर `NotReady` में और बाहर चक्र कर रहा है, तो dependency intermittently unavailable है; ClickHouse और Postgres pods को जांचें और सर्वर के `CLICKHOUSE_URL` / `DATABASE_URL` को जांचें। पुष्टि करें कि `/ready` क्या रिपोर्ट करता है: + +```bash +kubectl -n agenteye exec deploy/server -- sh -c 'curl -s localhost:8080/ready' +``` + +यह probe deliberately tolerant है (एक generous failure threshold), इसलिए sustained flapping एक real dependency समस्या को indicate करता है rather than an over-aggressive probe। Liveness `/health` पर रहता है, इसलिए flapping readiness pod को **नहीं** restart करेगा। + +## Certificate Monitoring समस्याएं + +### CronJob Slack notifications नहीं भेज रहा है + +`cert-renewal-check` CronJob को एक Secret में stored Slack webhook URL की आवश्यकता है। सत्यापित करें यह मौजूद है: + +```bash +kubectl get secret cert-renewal-notify-config -n agenteye +``` + +यदि missing है, इसे बनाएं: + +```bash +kubectl create secret generic cert-renewal-notify-config \ + --namespace agenteye \ + --from-literal=SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL" +``` + +Secret के बिना, CronJob अभी भी चलता है और results को stdout में लॉग करता है। Logs को check करें with: + +```bash +kubectl logs -n agenteye -l job-name --tail=50 +``` + +### Client certificate notification प्राप्त होने से पहले expire हुआ + +CronJob हर 12 घंटे चलता है। यदि यह चल नहीं रहा है, तो इसकी status को check करें: + +```bash +kubectl get cronjob cert-renewal-check -n agenteye +``` + +एक manual check trigger करें: + +```bash +kubectl create job --from=cronjob/cert-renewal-check manual-cert-check -n agenteye +kubectl logs -n agenteye -l job-name=manual-cert-check +``` + +Expired certificate को तुरंत re-issue करने के लिए: + +```bash +cd base/certificates/client-certs +./issue-client-cert.sh +``` + +फिर regenerated `collector-mtls-secret.yaml` को cluster(s) में apply करें जहां आपके collectors चलते हैं और उन्हें restart करें: + +```bash +kubectl apply -f collector-mtls-secret.yaml -n +``` + +--- + +## Backup समस्याएं + +### `agenteye-backup` "No space left on device" के साथ विफल + +`agenteye-backup` CronJob Postgres + ClickHouse को एक `backup-tmp` `emptyDir` scratch volume (default `30Gi`) में dumps करता है, फिर **streams** `tar` archive सीधे S3 को — compressed archive कभी scratch में वापस written नहीं है, इसलिए scratch को केवल *raw dumps* को hold करना है, न dumps + a second on-disk archive copy को। एक pod evicted / `No space left on device` इसलिए मतलब है कि **raw dumps** scratch size को exceed करते हैं (ClickHouse `events` dump dominates और time के साथ बढ़ता है)। Failed job के logs को check करें: + +```bash +kubectl logs -n agenteye -l job-name= +``` + +Fix: आपके overlay में, CronJob के `backup-tmp` `emptyDir` `sizeLimit` को अपने raw dump total से ऊपर raise करें, और सुनिश्चित करें कि node की ephemeral storage वास्तव में इसे hold कर सकता है (`sizeLimit` एक cap है, न कि एक reservation)। यदि dumps एक single node's disk को outgrow करते हैं, तो `emptyDir` को `backup-tmp` के लिए PVC (EBS/PD) से replace करें, या source पर dumps को compress करें। + +> पुरानी releases को `.tar.gz` को dumps के समान `20Gi` scratch में लिखता था, इसलिए `dumps + archive` इसे overflow करता था और pod को **before** the upload ran से evict किया जाता था — जो S3 failure की तरह लगता है लेकिन वास्तव में disk है। Streaming the upload that doubling को remove करता है। + +### `agenteye-backup` `curl` install करने में विफल + +Job `postgres:16` image पर चलता है और ClickHouse HTTP dump के लिए startup पर `curl` को install करता है। कोई cluster egress के साथ Debian package mirrors के लिए, `apt-get` step fail होता है। या तो backup pod से उस egress को allow करें, या एक mirrored/custom backup image में `curl` को bake करें और अपने overlay में इसे reference करें। + +### `agenteye-backup` चलता है लेकिन कुछ भी object storage में lands नहीं करता है + +Base एक real `BACKUP_BUCKET` (`ts-prod-agenteye/backups`) और `agenteye-backup` ServiceAccount ship करता है। Job **streams** archive को S3 (`tar cz … | aws s3 cp - s3://…`)। यदि backup pod के पास bucket के लिए write access नहीं है, तो upload errors — और क्योंकि script `set -euo pipefail` के तहत चलता है, उस pipe में कहीं भी failure **पूरे** job को `upload` step में fail करता है rather than silently no-op'ing (pod का EXIT trap `backup FAILED during step: upload` को logs करता है)। यह भी step है जो आप एक scratch-space eviction को fix करने के बाद reach करते हैं, इसलिए यदि backups पहले archive step पर evicted थे, तो सत्यापित करें कि upload अब lands करता है। Failed job के logs में S3 access error को grep करें: + +```bash +kubectl logs -n agenteye -l job-name= | grep -iE 's3|upload|denied' +``` + +Fix: अपने overlay में `BACKUP_BUCKET` को एक bucket पर सेट करें जो आप own करते हैं और write access के साथ existing `agenteye-backup` ServiceAccount को annotate करें (IRSA / Workload Identity / Pod Identity)। [enterprise-docs/kubernetes-deployment.md](/hi/agenteye/kubernetes-deployment) के **Backups** section को देखें। + +--- + +## ClickHouse-backed evaluations / sessions / queries + +### अपग्रेड के बाद `/queries` पृष्ठ sidebar खाली है + +तीन tables (`events`, `evaluations`, `agent_sessions`) expected हैं। यदि SchemaBrowser sidebar upgrade के बाद खाली है, तो सर्वर startup पर ClickHouse DDL apply करने में विफल हुआ। `failed to apply CH DDL statement` के लिए सर्वर logs को check करें: + +```bash +kubectl logs -n agenteye deploy/server | grep -E 'clickhouse|CH DDL' +``` + +सबसे सामान्य कारण ClickHouse unreachable है जबकि migrations चलते हैं। सर्वर CH तक reach नहीं कर सकता तो start करने से refuse करता है, इसलिए एक stuck pod में आमतौर पर `CrashLoopBackOff` होता है rather than silently broken queries page, लेकिन एक partial DDL apply (एक statement OK, अगले 5xx) schema को half-baked छोड़ देता है। CH को verify reachable करने के बाद server pod को restart करें: + +```bash +kubectl rollout restart deploy/server -n agenteye +``` + +### नए evaluations `/sessions` या `/queries` में नहीं दिख रहे हैं + +अपग्रेड के बाद, नए evaluations ClickHouse को लिखे जाते हैं, Postgres को नहीं, और `/sessions` (`evaluations:read` पर gated) और `/queries` में surface होते हैं। यदि वे नहीं दिखते हैं: + +1. पुष्टि करें कि evaluator pipeline enabled है (`AGENTEYE_AGENT_URL` सर्वर पर सेट) और terminal outcomes produce कर रहा है; `evaluation_finalized` log lines के लिए check करें। +2. पुष्टि करें कि CH सर्वर से reachable है: `kubectl exec -n agenteye deploy/server -- curl -fsS http://clickhouse:8123/ping`। +3. CH table को spot-check करें: `kubectl exec -n agenteye clickhouse-0 -- clickhouse-client -q 'SELECT count() FROM agenteye.evaluations'`। + +### Queries लोड के तहत "Memory limit exceeded" के साथ विफल, या ClickHouse `OOMKilled` है + +**लक्षण:** भारी dashboard/query लोड के तहत, analytical pages (the events stream, `/sessions`, models/latency view, SQL editor) fail होने लगते हैं या timeout करते हैं; सर्वर संक्षिप्त रूप से flaps `NotReady`; और ClickHouse pod restart count बढ़ता दिखाता है। यह लगभग हमेशा **memory** है, न कि CPU या disk। + +**पुष्टि करें यह memory है** (न कि throughput समस्या जो replication fix करेगा): + +1. Pod को out-of-memory kills के लिए check करें: + ```bash + kubectl -n agenteye describe pod clickhouse-0 | grep -iE 'Restart Count|Last State|Reason|OOMKilled' + ``` + `Reason: OOMKilled` / `Exit Code: 137` एक climbing restart count के साथ tell है। + +2. ClickHouse से पूछें यह क्या reject कर रहा है: + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT name, value FROM system.errors WHERE value>0 ORDER BY value DESC" + ``` + एक large `MEMORY \ No newline at end of file diff --git a/docs/it/agenteye/alerts.mdx b/docs/it/agenteye/alerts.mdx new file mode 100644 index 00000000..0e459d8b --- /dev/null +++ b/docs/it/agenteye/alerts.mdx @@ -0,0 +1,308 @@ +--- +title: "Avvisi" +description: "Documentazione degli Avvisi di AgentEye." +--- + +Gli avvisi valutano una regola secondo una pianificazione e ti notificano quando qualcosa oltrepassa una soglia. Trasformano AgentEye da una dashboard passiva in una superficie di paging per le cose che contano: picchi di tasso d'errore, regressioni di latenza, cali nei punteggi degli evaluator, o qualsiasi evento personalizzato che puoi esprimere come query ClickHouse. + +Questa guida copre cos'è un avviso, i cinque tipi di trigger, i quattro canali di notifica, il ciclo di vita degli incidenti, e i controlli operativi. + +![La pagina Avvisi: una griglia di schede con le regole di avviso, ciascuna che mostra il tipo di trigger, la finestra di valutazione, i canali e un badge di severità info/avvertimento/critico](/agenteye/images/alerts.png) + +--- + +## Concetti + +- **Avviso** — la regola. Dice *cosa* verificare (il trigger), *con quale frequenza* (l'intervallo di valutazione), *quando considerarla rotta* (logica composta), *quanto è urgente* (severità), e *chi/dove notificare* (canali). +- **Incidente** — quello che accade quando un avviso si attiva. Un avviso ha al massimo un incidente aperto per volta. Le violazioni ripetute aggiornano le evidenze dello stesso incidente. Gli incidenti vengono risolti da un operatore; la risoluzione automatica quando la regola smette di attivarsi è pianificata ma non attualmente abilitata. +- **Canale** — dove va una notifica: email, Slack, webhook generico, o in-dashboard. Ogni avviso può collegare qualsiasi combinazione. + +Gli avvisi e gli incidenti appartengono a un'organizzazione e sono condivisi tra gli operatori di quell'organizzazione (in un'implementazione single-tenant è semplicemente l'organizzazione predefinita `default`). Gli incidenti possono essere assegnati a un singolo operatore per il triage. + +--- + +## Tipi di trigger + +Cinque tipi, ciascuno con la propria specifica JSON. Scegli quello che corrisponde a come vuoi descrivere "rotto". La forma **nuovo avviso** della dashboard costruisce la stessa specifica per te, passando l'editor della condizione in modo che corrisponda al tipo di trigger che scegli: + +![Il modulo new-alert, con le basi (nome, descrizione, abilitato) e il selettore di trigger che mostra soglia metrica, SQL personalizzato, punteggio di valutazione, errori di valutazione e opzioni per evento](/agenteye/images/alert-new.png) + +### 1. `metric_threshold` + +Il più semplice. Scegli una metrica da un elenco chiuso, un operatore, una soglia e una finestra temporale. + +| Metrica | Cosa conta | +|---|---| +| `event_count` | Eventi totali nella finestra | +| `error_count` | `event_type = 'error'` O qualsiasi evento con `error_type IS NOT NULL` | +| `error_rate` | `error_count / event_count` (0..1) | +| `p95_latency_ms` | `quantile(0.95)(duration_ms)` su tutti gli eventi con `duration_ms` | +| `p99_latency_ms` | `quantile(0.99)(duration_ms)` | +| `token_sum` | `SUM(input_tokens + output_tokens)` | + +Operatori: `>`, `>=`, `<`, `<=`, `==` (accettati anche come `gt`, `gte`, `lt`, `lte`, `eq`). + +Filtri opzionali: `environment`, `event_type`. + +Esempio di specifica: + +```json +{ + "metric": "p95_latency_ms", + "filter": { "environment": "production" }, + "window_secs": 900, + "op": ">", + "value": 5000 +} +``` + +### 2. `custom_sql` + +Per qualsiasi cosa le metriche preimpostate non coprano. L'SQL fornito dall'operatore passa attraverso la stessa protezione `/queries/run` (solo SELECT/WITH, singola istruzione, limite di 10.000 righe) prima che il dispatcher lo esegua. Due modalità: + +- **modalità righe** (nessun `op`/`value`): l'avviso si attiva non appena la query restituisce almeno una riga. +- **modalità valore**: la query deve alias una colonna come `metric_value`; il dispatcher confronta il `metric_value` della prima riga rispetto a `value` usando `op`. + +```json +{ + "sql": "SELECT count() AS metric_value FROM agenteye.events WHERE event_type = 'error' AND ts >= now() - INTERVAL 1 HOUR", + "op": ">", + "value": 100 +} +``` + +### 3. `evaluation_score` + +Legge `agenteye.evaluations` e confronta la media di un punteggio denominato su una finestra. + +```json +{ + "score_key": "hallucination", + "op": ">", + "value": 0.6, + "window_secs": 3600, + "min_count": 5, + "environment": "production" +} +``` + +`min_count` protegge da outlier a singolo campione; il dispatcher non si attiva finché non esistono almeno N valutazioni nella finestra. + +### 4. `eval_compound` + +Cattura una regressione della qualità che si manifesta solo attraverso *diversi* punteggi degli evaluator contemporaneamente. Dove `evaluation_score` osserva un singolo punteggio denominato, `eval_compound` compone più condizioni di valutazione in un avviso e combina i loro risultati con una logica scelta; quindi una regola può esprimere "attivati se l'utilità scende **o** l'allucinazione sale", "attivati solo se l'utilità **e** l'efficienza dello strumento scendono entrambe", o "attivati se **almeno 2 di** questi tre controlli violano". + +Ogni condizione legge la media di un punteggio denominato da `agenteye.evaluations` nella finestra condivisa e lo verifica con il suo operatore e soglia. I risultati booleani vengono quindi combinati dal `combinator`: + +| Combinator | Logica | Si attiva quando | +|---|---|---| +| `"any"` | OR | almeno una condizione viola | +| `"all"` | AND | ogni condizione viola | +| `{ "at_least": N }` | M-of-N | almeno N condizioni violano | + +```json +{ + "combinator": { "at_least": 2 }, + "conditions": [ + { "score_key": "hallucination", "op": ">", "value": 0.8 }, + { "score_key": "helpfulness", "op": "<", "value": 0.6 }, + { "score_key": "tone", "op": "<", "value": 0.5 } + ], + "window_secs": 3600, + "min_count": 5, + "environment": "production" +} +``` + +- `combinator`: `"any"`, `"all"`, o `{ "at_least": N }`. +- `conditions[]`: ogni `{ score_key, op, value }`, usando gli stessi operatori degli altri trigger (`>`, `>=`, `<`, `<=`, `==`). +- `window_secs`: il lookback condiviso applicato a ogni condizione (predefinito `3600`). +- `min_count`: numero minimo per-condizione di valutazioni prima che quella condizione possa violare; una condizione con troppi pochi campioni nella finestra conta come "non violata" (predefinito `1`). +- `environment`: opzionale; limita ogni condizione a un ambiente. + +La notifica dell'incidente registra la media osservata di ogni condizione, la soglia su cui è stata testata, quante valutazioni sono state viste e se ha violato; quindi puoi vedere esattamente quali controlli si sono attivati. + +### 5. `per_event` + +Per avvisi "qualsiasi evento che corrisponde a X è arrivato". Nessuna aggregazione; il dispatcher si attiva non appena vede una corrispondenza nella finestra di lookback. + +```json +{ + "event_type": "error", + "lookback_secs": 60, + "environment": "production", + "tool_name": "bash", + "agent_id": "caa", + "error_type": "TimeoutError", + "message_contains": "vertex-ai timed out" +} +``` + +Tutti i filtri sono AND-combinati; qualsiasi campo che ometti è non vincolato. + +| Campo | Scopo | +|---|---| +| `agent_id` | Limita agli errori da un agente specifico (quello mostrato nella riga `/errors`). | +| `error_type` | Limita a una classe di errore specifica (ad es. `TimeoutError`) piuttosto che ogni errore. | +| `message_contains` | Corrispondenza di sottostringa case-insensitive rispetto a `payload.message`. Utile per catturare una modalità di errore specifica (ad es. `prompt is too long`) senza avvertire ogni errore dello stesso agente. Limitato a 200 caratteri; abbinato come stringa letterale, non come pattern. | + +Consiglio: imposta `lookback_secs` per corrispondere approssimativamente all'`eval_interval_secs` dell'avviso in modo da non notificare due volte lo stesso evento. + +**Scorciatoia da `/errors`:** la riga rappresentativa di ogni gruppo di errori nella vista errori (e il pannello di dettaglio dell'evento della sessione per un evento di errore) ha un pulsante **+ alert** che apre `/alerts/new` precompilato con un trigger `per_event` basato su `event_type` + ambiente di quella riga, incluso un nome generato da `error_type` del payload se presente. Scegli ancora i canali e conferma il lookback, ma il matcher è compilato per te. Gli operatori hanno bisogno di `alerts:write` affinché il pulsante compaia. + +--- + +## Logica composta (M of N) + +Ogni avviso ha due manopole intere in aggiunta al trigger: + +- `eval_window`: quante valutazioni recenti guardare (predefinito 1) +- `min_breaches`: quante di queste devono violare prima che l'avviso si attivi (predefinito 1) + +`1 of 1` (il valore predefinito) è "attivati sulla prima violazione". `3 of 5` significa "attivati quando la regola ha violato 3 delle ultime 5 valutazioni", utile per segnali tremolanti dove una singola misurazione negativa è rumore. Il dispatcher mantiene un ring buffer per avviso; non devi gestire lo stato. + +--- + +## Intervallo di valutazione + +`eval_interval_secs` controlla con quale frequenza il dispatcher esegue la tua regola. Vincolato a `[30, 86400]`. Preimpostazioni nel dashboard: 1m / 5m / 15m / 1h. Scegli un intervallo corrispondente a quanto velocemente il segnale sottostante si muove: un avviso di tasso d'errore a 5 minuti valutato ogni 15 secondi spreca CPU; un avviso per evento ha bisogno di un lookback breve o silenziamente perderà gli eventi tra i tick. + +--- + +## Canali + +Ogni avviso può collegare qualsiasi combinazione di questi quattro. Le credenziali per-canale (URL webhook Slack, URL webhook generico + segreto di firma, destinatari email predefiniti) sono configurate una sola volta in **`/settings`** e referenziate per chiave da ogni avviso. In questo modo un canale Slack può servire molti avvisi senza che ognuno memorizzi la propria copia dell'URL webhook. + +I tre tipi di canale esterni (email, Slack, webhook) sono anche controllati da un interruttore di disattivazione a livello di organizzazione, `alerts.enabled_channels`. Quando un avviso attivato collega un tipo di canale che non è in questo set, il dispatcher lo salta e registra una riga `alert_notifications` con status `skipped_disabled` e target `` (permettendoti di sospendere globalmente, ad esempio, tutte le consegne Slack senza modificare ogni regola). Il canale in-dashboard è sempre consentito. Vedi [Configuration](#configuration). + +### Email + +Riutilizza lo stesso trasporto SMTP che spedisce le email di login OTP. I destinatari si risolvono in ordine: + +1. Override `recipients[]` per-canale (quando non vuoto). +2. L'impostazione `alerts.email_default_recipients` (un array di stringhe email). + +Se SMTP non è configurato il canale è un no-op; il dispatcher registra comunque una riga `alert_notifications` con target `` in modo che l'audit trail renda la misconfiguration visibile. + +### Slack + +Invia un messaggio Block Kit a un [URL webhook in arrivo](https://api.slack.com/messaging/webhooks). + +- URL predefinito: `alerts.slack_default_webhook` (impostato in `/settings`). +- Override per-alert: imposta il `webhook_setting_key` del canale a qualsiasi altra chiave di impostazione di tipo URL, ad es. `alerts.slack_oncall`, `alerts.slack_costs`. + +L'intestazione include un emoji di severità (`:rotating_light:` / `:warning:` / `:bell:`), e il messaggio include un pulsante che deep-linka alla pagina dell'incidente. + +### Webhook generico + +Un'integrazione JSON-POST per PagerDuty, Opsgenie, o il tuo endpoint di ingestione. Forma del corpo: + +```json +{ + "schema_version": 1, + "event": "alert.firing", + "incident": { "id": "uuid", "url": "https://…/incidents/uuid", "opened_at": "2026-…" }, + "alert": { "id": "uuid", "name": "errors > 50/hr", "severity": "critical" }, + "breach": { "value": 73.0, "summary": "ErrorCount > 50 (observed 73.000)", "evidence": { … } } +} +``` + +Quando `alerts.webhook_signing_secret` è impostato, la richiesta include un'intestazione `X-AgentEye-Signature: sha256=`, l'HMAC-SHA256 del corpo usando il segreto. Verifica su chi riceve prima di fidarti del payload. + +L'intestazione `X-AgentEye-Event` trasporta `alert.firing` / `alert.test`. (`alert.resolved` è riservato per la funzione di auto-resolve pianificata e non è attualmente emessa.) + +### In-dashboard + +Nessuna consegna esterna: l'avviso scrive semplicemente una riga `alert_notifications` che la pagina incidenti della dashboard mostra. Utile mentre stai sintonizzando una regola e non vuoi spammare un sistema esterno, o per avvisi a bassa urgenza che gli operatori controllano durante il triage normale. + +--- + +## Ciclo di vita dell'incidente + +``` +firing ──ack──▶ acknowledged + │ │ + └────────────────────┴───── operator resolve ───▶ resolved +``` + +- **firing** — il dispatcher ha appena aperto l'incidente o ha rilevato un'altra violazione. La notifica di firing è diffusa esattamente una volta (controllata dal timestamp `notified_firing_at` sull'incidente). +- **acknowledged** — un operatore ha premuto *ack* su `/incidents/:id`. L'incidente è ancora considerato aperto; le violazioni successive aggiorneranno le sue evidenze senza ri-notificare. +- **resolved** — un operatore ha premuto *resolve*. La risoluzione automatica quando la regola smette di violare è pianificata ma non attualmente abilitata, quindi un incidente aperto rimane aperto finché un operatore non lo risolve. + +Un nuovo incidente può riaprirsi nello stesso avviso in qualsiasi momento dopo che il precedente è stato risolto. + +**Timeline dell'attività.** Ogni azione su un incidente — aperto, acknowledged, risolto — è registrata in un log dell'attività append-only e mostrata sulla timeline dell'*attività* dell'incidente, ogni voce attribuita all'operatore che l'ha eseguita (per email) o a **automated** per le azioni che il dispatcher ha intrapreso da solo (auto-open su violazione). L'acknowledgement è condiviso: diversi operatori possono ack lo stesso incidente e ognuno appare come una voce separata e attribuita. + +La **casella di posta Incidenti** raggruppa gli incidenti aperti per stato e ti permette di filtrare per severità e assegnatario: + +![La casella di posta Incidenti che mostra schede di incidenti collegati ad alert e ad-hoc con badge di severità e assegnatari](/agenteye/images/incidents.png) + +L'apertura di un incidente mostra l'evidenza della violazione, gli assegnatari e i sottoscritti, la timeline dell'attività attribuita, e un thread di commenti: + +![Una visualizzazione di dettaglio dell'incidente: l'alert genitore, riassunto della violazione, assegnatari, sottoscritti, log dell'attività attribuito e conversazione](/agenteye/images/incident-detail.png) + +--- + +## Permessi richiesti + +La creazione di *regole* di avviso e il triage degli *incidenti* sono preoccupazioni separate con concessioni separate, quindi puoi dare a una rotazione on-call l'accesso agli incidenti senza anche darle la possibilità di riscrivere le regole. + +- `alerts:read`: visualizza le regole di avviso. +- `alerts:write`: crea, modifica, elimina regole di avviso e attiva una notifica di test. +- `incidents:read`: visualizza gli incidenti. +- `incidents:write`: apri incidenti manuali (ad-hoc) non legati a un avviso. +- `incidents:ack`: acknowledges, assegna, commenta e risolvi incidenti. + +> **Legacy `alerts:ack`.** Le chiavi e gli operatori a cui è stato concesso il token `alerts:ack` più vecchio continuano a funzionare: viene onorato come `incidents:ack` (e implica `incidents:read`), quindi gli on-caller esistenti mantengono il loro accesso senza ri-emettere credenziali. Emetti nuove concessioni con la famiglia `incidents:*`. + +Concedi su chiavi API (`POST /keys`) e operatori (`PUT /users/:id`). Il `PermGate` della dashboard blocca i pulsanti rilevanti quando manca un permesso; vedrai `// 403` accanto all'azione. + +> **Email-recipient picker.** Il selettore di destinatari dell'editor di avviso elenca i membri della tua organizzazione in modo da poterli selezionare per nome. Si carica per qualsiasi operatore che detiene `alerts:read` o `alerts:write`; visualizzare la directory del tuo team a questo scopo **non** richiede `users:read`, e il selettore restituisce solo gli indirizzi email dei membri, mai record utente completi. + +--- + +## Configurazione + +Variabili d'ambiente consumate dal dispatcher: + +| Var | Predefinito | Scopo | +|---|---|---| +| `ALERT_WORKERS` | `1` | Attività worker per istanza server. La maggior parte delle implementazioni ne hanno bisogno di una sola. | +| `ALERT_CLAIM_BATCH` | `16` | Max avvisi che un singolo tick worker elabora. | +| `ALERT_POLL_IDLE_SECS` | `5` | Sleep worker quando la coda è vuota. | +| `ALERT_REQUEST_TIMEOUT_MS` | `15000` | Timeout di valutazione per-trigger. | +| `DASHBOARD_URL` | `https://app.befailproof.ai` | Origine utilizzata per costruire il magic-link dell'incidente nelle notifiche. Impostala all'host della tua dashboard. | + +Dopo un errore di valutazione transitorio (ClickHouse irraggiungibile, timeout della query), il dispatcher riprova la regola con backoff esponenziale. Una volta che una regola ha accumulato **5** errori transitori consecutivi viene ripianificata al suo ritmo normale invece di continuare con backoff, quindi una regola persistentemente fallace continua ad essere rivalutata. Questo limite è fisso e non è sintonizzabile dall'operatore. + +Impostazioni dei canali (gestite da `/settings`, non env): + +- `alerts.email_default_recipients` (`email_list`): array JSON di stringhe email — i destinatari predefiniti per i canali email. +- `alerts.slack_default_webhook` (`url`): URL webhook in arrivo Slack predefinito. +- `alerts.webhook_default_url` (`url`): URL webhook generico predefinito. +- `alerts.webhook_signing_secret` (`secret`): chiave HMAC-SHA256. Sempre restituita come `""` nella risposta GET; digita un nuovo valore per ruotare. +- `alerts.enabled_channels` (`channel_set`): il set a livello di organizzazione dei tipi di canale esterni che vengono inviati quando un avviso si attiva; di default tutti e tre (`email`, `slack`, `webhook`). Rimuovendo un tipo qui globalmente sopprimi quel canale per ogni avviso senza modificare ogni regola. Il canale in-dashboard è sempre consegnato e non è interessato da questa impostazione. + +--- + +## Verifica un nuovo avviso + +Prima di affidarti a un nuovo avviso: + +1. Salvalo come abilitato con almeno un canale di notifica. +2. Seleziona **test** sulla pagina di dettaglio dell'avviso e conferma che ogni destinazione configurato riceva la notifica sintetica. +3. Dopo la prima violazione reale, conferma che l'incidente appaia sotto **Incidenti** e che il suo valore misurato corrisponda alla corrispondente query della dashboard. + +Gli incidenti non si risolvono automaticamente quando una condizione si cancella. Un operatore deve risolverli dalla pagina di dettaglio dell'incidente. + +--- + +## Risoluzione dei problemi + +| Sintomo | Causa probabile | +|---|---| +| L'avviso non si attiva mai | `enabled = false`, o nessun canale collegato, o la query CH sottostante restituisce 0 righe. Usa *test* per confermare i canali; usa `/queries/run` per confermare la metrica. | +| Notifica Slack mancante | `alerts.slack_default_webhook` (o la chiave di override per-alert) non è impostata: controlla `alert_notifications.target` per righe ``; o il tipo `slack` è globalmente disabilitato in `alerts.enabled_channels`: controlla le righe `alert_notifications` con status `skipped_disabled` e target ``. | +| Webhook generico 401 | Il destinatario richiede una firma ma `alerts.webhook_signing_secret` non è impostato. Verifica nel destinatario che l'HMAC corrisponda a `hmac_sha256(secret, body)`. | +| Email "from all sends failed" | Credenziali SMTP sbagliate o l'indirizzo `from` è rifiutato dal tuo relay. Stessa superficie che spedisce le email OTP: se quelli funzionano, il trasporto SMTP va bene. | +| L'incidente si riapre ripetutamente | Le manopole composte sono troppo aggressive: prova ad alzare `min_breaches` o `eval_window` in modo che i picchi transienti non riaprono gli incidenti che hai risolto. | \ No newline at end of file diff --git a/docs/it/agenteye/api-keys.mdx b/docs/it/agenteye/api-keys.mdx new file mode 100644 index 00000000..f6409ed2 --- /dev/null +++ b/docs/it/agenteye/api-keys.mdx @@ -0,0 +1,256 @@ +--- +--- +title: "Chiavi API" +description: "Documentazione delle chiavi API di AgentEye." +--- + + +AgentEye utilizza chiavi API a granularità fine per controllare l'accesso al server. Ogni chiave porta una o più autorizzazioni che determinano cosa può fare. + +--- + +## Autorizzazioni + +Il server applica un catalogo fisso di autorizzazioni; ognuna controlla route HTTP specifiche. Una **chiave admin** le contiene tutte; una chiave con ambito contiene il sottoinsieme che concedi al momento della creazione. Le stringhe di autorizzazione sconosciute vengono rifiutate quando si crea una chiave. + +> **Non assegnabili alle chiavi.** Due autorizzazioni valide sono solo per utenti/dashboard e non possono essere concesse a una chiave API: `orgs:admin` (amministrazione dell'istanza, esclusiva degli operatori) e `keys:update`. Una richiesta a `POST /keys` o `PATCH /keys/:id` che tenta di concedere una di queste viene rifiutata con HTTP 422. Vedi la riga `keys:update` di seguito per capire perché una chiave bearer può creare chiavi ma non modificarle. + +### Acquisizione e query di eventi + +| Autorizzazione | Route HTTP | Cosa consente | +|---|---|---| +| `events:add` | `POST /events` | Acquisire batch di eventi da un collettore. L'unica autorizzazione di cui ha bisogno un collettore. | +| `events:read` | `GET /events`, `GET /events/latency_aggregate`, `GET /events/environments`, `GET /events/models`, `GET /sessions/:session_id/export` | Query di eventi, elenco degli ambienti noti, elenco degli identificatori di modelli visti nei dati (utilizzati dalla vista Modelli e dai filtri modello), calcolo dell'aggregato di latenza che alimenta la heat-map / banda percentile ed esportazione di una sessione come JSONL. Gli endpoint di facet della barra filtri condivisa `GET /events/environments` e `GET /events/models` sono raggiungibili con **`events:read`** **o** `evaluations:read`, quindi la pagina sessioni (controllata da `evaluations:read`) riutilizza lo stesso facet per organizzazione. | + +### Sessioni e valutazioni + +| Autorizzazione | Route HTTP | Cosa consente | +|---|---|---| +| `evaluations:read` | `GET /sessions`, `GET /evaluations`, `GET /evaluations/aggregate`, `GET /evaluations/environments`, `GET /evaluation-jobs` | Elencare sessioni, leggere risultati di valutazione, la salute della valutazione ripiegata utilizzata dai dashboard e lo stato della coda di lavoro del worker evaluation-job. | +| `evaluations:trigger` | `POST /sessions/:session_id/re-evaluate` | Accodare manualmente una rivalutazione per una sessione completata. | + +### Dashboard + +| Autorizzazione | Route HTTP | Cosa consente | +|---|---|---| +| `dashboards:read` | `GET /dashboards`, `GET /dashboards/:id`, `GET /dashboards/:id/tiles` | Elencare dashboard, caricarne uno e leggere i suoi tile. | +| `dashboards:write` | `POST /dashboards`, `PUT /dashboards/:id`, `POST /dashboards/:id/tiles`, `PUT /dashboards/:id/tiles/:tile_id`, `DELETE /dashboards/:id/tiles/:tile_id`, `PUT /dashboards/:id/tiles/layout` | Creare e modificare dashboard, aggiungere/modificare/rimuovere tile e riordinare la griglia tile. | +| `dashboards:delete` | `DELETE /dashboards/:id` | Eliminare un intero dashboard (l'eliminazione a livello di tile rientra in `dashboards:write`). | + +### Query salvate (SQL composer) + +| Autorizzazione | Route HTTP | Cosa consente | +|---|---|---| +| `queries:read` | `GET /queries`, `GET /queries/:id`, `GET /queries/schema` | Elencare query salvate, caricarne una e ispezionare lo schema ClickHouse di sola lettura verso cui il composer punta. | +| `queries:write` | `POST /queries`, `PUT /queries/:id` | Creare e modificare query salvate. L'SQL viene ancora instradato attraverso lo stesso ruolo di sola lettura e i controlli `sql_guard` di una chiamata `queries:run`. | +| `queries:delete` | `DELETE /queries/:id` | Eliminare una query salvata. | +| `queries:run` | `POST /queries/run` | Eseguire SQL salvato o ad hoc rispetto al ruolo di sola lettura utilizzato dal composer. | + +### Assistente AI + +| Autorizzazione | Route HTTP | Cosa consente | +|---|---|---| +| `agent:use` | `GET /agent/conversations`, `POST /agent/conversations`, `GET /agent/conversations/:id`, `PATCH /agent/conversations/:id`, `DELETE /agent/conversations/:id`, `PUT /agent/conversations/:id/messages` | Comunicare con l'assistente AI del dashboard e gestire le tue conversazioni private. Richiesta sull'**utente** per vedere il dock dell'assistente; la chiave dell'assistente stesso è `dashboard-assistant` e viene seminata separatamente (vedi sotto). | + +### Chiavi API + +| Autorizzazione | Route HTTP | Cosa consente | +|---|---|---| +| `keys:create` | `POST /keys` | Creare una nuova chiave API con ambito. **Non** consente di modificare le autorizzazioni di una chiave esistente (quello è `keys:update`). | +| `keys:read` | `GET /keys` | Elencare chiavi esistenti. I segreti non vengono mai restituiti da questo endpoint. | +| `keys:update` | `PATCH /keys/:id` | Modificare le autorizzazioni di una chiave esistente. Un'autorizzazione **solo per utenti/dashboard**; non può essere assegnata a una chiave API (una chiave bearer può creare chiavi ma non modificarle). | +| `keys:disable` | `POST /keys/:id/disable` | Revocare una chiave. Le chiavi protette (`admin`, `dashboard-assistant`) non possono essere disabilitate; ruotale tramite variabile di ambiente + riavvio. | +| `keys:regenerate` | `POST /keys/:id/regenerate` | Ruotare il segreto di una chiave. Le chiavi protette non possono essere rigenerate tramite questa route. | + +### Utenti del dashboard + +| Autorizzazione | Route HTTP | Cosa consente | +|---|---|---| +| `users:create` | `POST /users`, `GET /users/defaults` | Invitare un nuovo utente del dashboard (invia email + login OTP) e leggere il set di autorizzazioni predefinite configurato nel dashboard utilizzato per inizializzare il modulo di invito. | +| `users:read` | `GET /users`, `GET /users/:id` | Elencare utenti e caricare un singolo record utente. | +| `users:update` | `PUT /users/:id` | Modificare le autorizzazioni di un utente. Gli aggiornamenti inoltrano un'email di modifica permessi all'utente interessato e hanno effetto alla sua prossima richiesta; non è richiesto accesso di nuovo. | +| `users:delete` | `DELETE /users/:id`, `POST /users/:id/enable` | Disabilitare un utente (revoca immediatamente le sue sessioni) e riabilitare un utente precedentemente disabilitato. | + +Queste autorizzazioni supportano la pagina **Utenti** del dashboard, dove gli ambiti concessi a ogni membro vengono mostrati come chip: + +![La pagina Utenti: una card per utente del dashboard con email, autorizzazioni concesse e controlli modifica/disabilita](/agenteye/images/users.png) + +### Impostazioni operative + +| Autorizzazione | Route HTTP | Cosa consente | +|---|---|---| +| `settings:read` | `GET /settings`, `GET /settings/schema`, `GET /settings/model-context-windows`, `GET /settings/model-context-windows/resolve` | Visualizzare le impostazioni operative gestite dal dashboard e i loro metadati; elencare override della finestra di contesto per modello; e risolvere la finestra effettiva per un modello. | +| `settings:write` | `PUT /settings/:key`, `PUT /settings/model-context-windows`, `DELETE /settings/model-context-windows` | Modificare le impostazioni operative e aggiungere, modificare o rimuovere override della finestra di contesto per modello. Le modifiche interessano i nuovi eventi senza riavviare il server. | + +![La pagina Impostazioni: impostazioni operative gestite dal dashboard come accessi consentiti e durate di sessione/OTP, modificabili senza riavvio](/agenteye/images/settings.png) + +### Avvisi e incidenti + +| Autorizzazione | Route HTTP | Cosa consente | +|---|---|---| +| `alerts:read` | `GET /alerts`, `GET /alerts/:id` | Visualizzare le definizioni di avviso configurate. | +| `alerts:write` | `POST /alerts`, `PUT /alerts/:id`, `DELETE /alerts/:id`, `POST /alerts/:id/test` | Creare, modificare, eliminare e testare le definizioni di avviso. | +| `incidents:read` | `GET /alerts/incidents`, `GET /alerts/incidents/:iid`, `GET /alerts/incidents/:iid/comments`, `GET /alerts/incidents/:iid/subscribers` | Visualizzare incidenti e il loro percorso di triage. | +| `incidents:write` | `POST /alerts/:id/incidents` | Aprire manualmente un incidente su un avviso esistente. | +| `incidents:ack` | `POST /alerts/incidents/:iid/ack`, `POST /alerts/incidents/:iid/assign`, `POST /alerts/incidents/:iid/resolve`, `POST /alerts/incidents/:iid/comments`, `POST /alerts/incidents/:iid/subscribe`, `POST /alerts/incidents/:iid/unsubscribe` | Riconoscere, assegnare, risolvere e commentare incidenti. | + +### Audit + +| Autorizzazione | Route HTTP | Cosa consente | +|---|---|---| +| `audits:read` | `GET /audits`, `GET /audits/:id`, `GET /audits/:id/runs`, `GET /audits/findings`, `GET /audits/findings/:fid` | Visualizzare definizioni di audit, cronologia di esecuzione e risultati. | +| `audits:write` | `POST /audits`, `PUT /audits/:id`, `DELETE /audits/:id`, `POST /audits/:id/run`, `POST /audits/findings/:fid/status` | Creare, modificare, eliminare ed eseguire audit; esaminare i risultati (riconoscere/escludere/respingere/risolvere/riaprire/assegnare). | + +> Quando Audits è stato lanciato, i destinatari esistenti sono stati ampliati selon la stessa forma di ruoli degli avvisi: ogni utente e set di autorizzazioni che contiene `alerts:read` ha acquisito `audits:read`, e ogni detentore di `alerts:write` ha acquisito `audits:write`. Le chiavi API esistenti **non** sono state ampliate — concedi esplicitamente `audits:*` a una chiave se ha bisogno della superficie di audit. + +> I grant archiviati del token legacy `alerts:ack` vengono analizzati come `incidents:ack` quindi gli on-caller mantengono l'accesso senza ricreaere le chiavi. Il token non è più assegnabile dall'editor utenti del dashboard; la matrice offre `incidents:ack` invece. + +> L'endpoint del selettore destinatari `GET /alerts/recipients` (che elenca le email dei membri che un editor di avviso può notificare) è raggiungibile da un detentore di **`alerts:read`** **o** `alerts:write`, così gli editor di avviso possono popolare il selettore senza che gli venga concesso `users:read`. + +> Un visualizzatore di dashboard ha bisogno di **entrambi** `dashboards:read` (per caricare le visualizzazioni salvate) e `evaluations:read` (le metriche di salute vengono calcolate da dati di valutazione). Concedi `dashboards:write` per consentire a un utente di creare o modificare dashboard, e `dashboards:delete` per rimuoverli. + +> `/health` e `/auth/*` (richiesta OTP, verifica OTP, controllo sessione, logout) sono senza autenticazione per design; sono il flusso di login e la sonda di vivacità. `GET /access-granters` richiede una chiave valida ma nessuna autorizzazione specifica, quindi qualsiasi utente connesso può vedere quali admin contattare per le modifiche di accesso. + +--- + +## Set di autorizzazioni + +I set di autorizzazioni ti consentono di applicare un ruolo denominato anziché selezionare manualmente singoli token ogni volta. Anziché selezionare una dozzina di autorizzazioni una per una per ogni nuovo utente di dashboard o chiave API, scegli un set e tutti coloro assegnati ad esso portano un grant coerente e verificabile. Modificare un set personalizzato applica il nuovo grant a ogni utente già assegnato ad esso, quindi un cambio di ruolo è una semplice modifica anziché una passata attraverso ogni membro. + +Ogni organizzazione viene inizializzata con tre set incorporati: + +| Set | Autorizzazioni | Destinato a | +|---|---|---| +| `read-only` | `events:read`, `keys:read`, `users:read`, `evaluations:read`, `dashboards:read`, `queries:read`, `settings:read`, `alerts:read`, `audits:read`, `incidents:read` | Accesso di sola visualizzazione su ogni superficie operativa. | +| `standard` | tutto in `read-only`, più `evaluations:trigger`, `queries:run`, `incidents:ack`, `agent:use` | Solo lettura più le azioni on-caller di tutti i giorni: eseguire query, rivalutare sessioni, riconoscere incidenti e utilizzare l'assistente AI. | +| `admin` | ogni autorizzazione assegnabile | Controllo completo dell'organizzazione. | + +I tre set incorporati sono **immutabili**; i loro nomi significano sempre la stessa cosa, quindi `read-only`, `standard` e `admin` sono sicuri da riferire in policy e onboarding. Un operatore può creare **set personalizzati** aggiuntivi per modellare ruoli specifici della tua organizzazione (per esempio, un ruolo di autore di dashboard o un ruolo di solo collettore). + +I set vengono visualizzati nel dashboard e gestiti sull'API in `GET /permission-sets` (elenca, controllato da `users:read`) e `POST /permission-sets` / `PUT /permission-sets/:name` / `DELETE /permission-sets/:name` (crea, modifica, elimina un set personalizzato, controllato da `settings:write`). L'eliminazione o la modifica di un set incorporato viene rifiutata. + +L'appartenenza al set è ciò che supporta altre due funzionalità: + +- **`DEFAULT_USER_PERMISSIONS`** (il grant preselezionato quando un admin apre **+ nuovo utente**) di default al set `standard`. Vedi [Deployment](/it/agenteye/deployment). +- **Il flag `--set`** su `agenteye-orgctl` (gestione dei membri dell'operatore) inizia un membro da un set denominato, che poi ottimizzi con `--add` / `--remove`. Vedi [Tenant Management](/it/agenteye/tenant-management). + +> Quando un set include un'autorizzazione che non è assegnabile alle chiavi (per esempio un set personalizzato che contiene `keys:update`), l'inizializzazione di una chiave da quel set scarta i token non assegnabili; il server altrimenti rifiuterebbe la chiave con HTTP 422. Gli utenti del dashboard non sono soggetti a questa restrizione. + +--- + +## Chiave Admin di Bootstrap + +La chiave admin è l'unica credenziale root che consente a un operatore di avviare l'accesso dal nulla: con essa puoi creare ogni altra chiave con ambito, invitare i primi utenti del dashboard e configurare l'istanza prima che esista qualsiasi altra chiave. È l'unica chiave che non crei tramite l'API delle chiavi; viene fornita dall'ambiente in modo che il server sia raggiungibile al primo avvio. + +Imposta la variabile di ambiente `ADMIN_KEY` sul server. Ad ogni avvio il server esegue un upsert di questo valore come chiave admin con tutte le autorizzazioni. + +Per ruotare: cambia `ADMIN_KEY` a un nuovo segreto e riavvia il server. + +--- + +## Ambito dell'organizzazione + +**Le organizzazioni stesse vengono create e gestite fuori banda da un operatore, non tramite questa API delle chiavi.** Il ciclo di vita dell'org e dei membri (creare/rinominare/eliminare/purificare un'org; aggiungere/aggiornare/rimuovere un membro) viene effettuato con il CLI **`agenteye-orgctl`** che viene eseguito all'interno del pod del server; non esiste un API HTTP o pulsante nel dashboard per esso. Vedi [Tenant Management](/it/agenteye/tenant-management). Quello che *non cambia*: **le chiavi API per org vengono comunque create nel dashboard (o tramite questa API delle chiavi)** dai membri dell'organizzazione. + +In un deployment multi-org, ogni chiave creata da un membro dell'org (tramite questa API delle chiavi o la pagina **Chiavi** del dashboard) appartiene a **un'organizzazione** e può solo leggere o scrivere i dati di quell'org; l'org viene timbrato sulla chiave al momento della creazione e applicato su ogni richiesta. Le due chiavi di bootstrap sono l'unica eccezione: la chiave `admin` (seminata da `ADMIN_KEY`) e la chiave `dashboard-assistant` (seminata da `AGENT_API_KEY`) sono **con scope istanza** (non portano org). Il container del dashboard autentica con la chiave `admin` in modo che possa eseguire il proxy di richieste per org per conto dei membri connessi. I deployment single-tenant non hanno bisogno di pensare a questo; tutte le chiavi appartengono all'org `default` incorporata. + +--- + +## Creazione di chiavi + +Utilizza la chiave admin (o qualsiasi chiave con autorizzazione `keys:create`) per creare chiavi con ambito aggiuntive. + +### Chiave collettore (solo acquisizione) + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "prod-collector", + "key": "your-collector-secret", + "permissions": ["events:add"] + }' +``` + +### Chiave dashboard (sola lettura) + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "dashboard", + "key": "your-dashboard-secret", + "permissions": ["events:read", "keys:read"] + }' +``` + +Quando crei una chiave tramite l'API HTTP, fornisci tu stesso il valore `key`; scegli un segreto forte e conservalo in sicurezza. (Il dashboard funziona al contrario: genera un segreto forte per te e lo mostra una sola volta alla creazione; vedi [Key Management in the Dashboard](#key-management-in-the-dashboard).) La risposta conferma che la chiave è stata creata: + +```json +{ + "id": "550e8400-e29b-41d4-a716-446655440000", + "name": "prod-collector", + "permissions": ["events:add"], + "created_at": "2026-04-01T12:00:00Z" +} +``` + +--- + +## Elenco delle chiavi + +```bash +curl -s http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +I segreti delle chiavi non vengono restituiti nelle risposte di elenco, solo ID, nomi e autorizzazioni. + +--- + +## Disabilitazione di una chiave + +La disabilitazione revoca l'accesso immediatamente senza eliminare il record della chiave. + +```bash +curl -s -X POST http://your-server:8080/keys//disable \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +--- + +## Rigenerazione di una chiave + +Genera un nuovo segreto per una chiave esistente. Il vecchio segreto viene invalidato immediatamente. + +```bash +curl -s -X POST http://your-server:8080/keys//regenerate \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +La risposta include il nuovo segreto di testo normale, **mostrato una sola volta**. + +--- + +## Key Management nel Dashboard + +La pagina **Chiavi** nel dashboard fornisce un'interfaccia utente per tutte le operazioni di cui sopra. Hai bisogno di una chiave con autorizzazione `keys:read` per visualizzare l'elenco, e `keys:create` / `keys:update` / `keys:disable` / `keys:regenerate` per le azioni di creazione/modifica/disabilitazione/rigenerazione rispettivamente. La modifica delle autorizzazioni di una chiave (`keys:update`) è separata dalla creazione di una (`keys:create`), quindi puoi concedere a un operatore la capacità di creare chiavi senza la capacità di ricambiare il campo di applicazione di quelle esistenti, o vice versa. La chiave admin copre tutte queste. + +Quando crei una chiave dal dashboard non fornisci il segreto; il dashboard genera un segreto forte per te e lo visualizza **una sola volta** alla creazione. Copialo immediatamente e conservalo in sicurezza; non viene mai mostrato di nuovo, proprio come con una rigenerazione. Puoi comunque scegliere direttamente le autorizzazioni della chiave o inizializzarle da un set di autorizzazioni (vedi sotto). + +![La pagina Chiavi API: una card per chiave che mostra il suo nome, le autorizzazioni concesse e l'ora di creazione, con azioni rigenerare e disabilitare; le chiavi protette come `admin` sono marcate](/agenteye/images/api-keys.png) + +--- + +## Layout di chiave consigliato + +| Chiave | Autorizzazioni | Utilizzato da | +|---|---|---| +| `admin` (bootstrap tramite variabile di ambiente `ADMIN_KEY`) | tutte | Ops/setup e il container del dashboard (autentica con `ADMIN_KEY`, esegue proxy delle richieste utente con controlli di autorizzazione) | +| Chiave collettore per host | `events:add` | Collettore su ogni macchina agente | +| `dashboard-assistant` (bootstrap tramite variabile di ambiente `AGENT_API_KEY`) | `events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run` | Container assistente AI, seminato automaticamente, **protetto**; non può essere modificato tramite l'API | +| Chiave telemetria assistente (opzionale) | `events:add` | Strumentazione autonoma dell'assistente AI, se abilitata | + +> **Chiave assistente.** La chiave dell'assistente viene **seminata automaticamente** dal server dalla variabile di ambiente `AGENT_API_KEY` (lo stesso segreto che l'agente presenta come `AGENTEYE_API_KEY`); non c'è alcun passaggio manuale di creazione delle chiavi e nessuna chiave admin coinvolta. Le sue autorizzazioni sono fissate nel codice sorgente in modo che l'ambito non possa essere allargato da misconfiguration: lettura su eventi/valutazioni/dashboard, più scrittura del dashboard e lettura/scrittura/esecuzione delle query per il flusso di authoring "Chiedi all'AI di scrivere una query". Tutto l'SQL passa comunque attraverso lo stesso ruolo di sola lettura e i controlli `sql_guard` di una query scritta dall'utente, quindi ciò allarga la *superficie di authoring*, non la superficie dati; le operazioni distruttive (`queries:delete`, `dashboards:delete`) rimangono deliberatamente fuori dalla chiave dell'assistente. Come la chiave `admin`, è **protetta**: non può essere disabilitata o rigenerata tramite l'API delle chiavi, solo ruotata cambiando `AGENT_API_KEY` e riavviando. Gli *utenti* del dashboard inoltre hanno bisogno dell'autorizzazione `agent:use` per vedere e utilizzare l'assistente. Se abiliti l'autostrumentazione, dai all'assistente una chiave separata `events:add`-only. \ No newline at end of file diff --git a/docs/it/agenteye/assistant.mdx b/docs/it/agenteye/assistant.mdx new file mode 100644 index 00000000..e0c57846 --- /dev/null +++ b/docs/it/agenteye/assistant.mdx @@ -0,0 +1,196 @@ +--- +title: "Assistente AI" +description: "Documentazione dell'Assistente AI di AgentEye." +--- + + +La dashboard include un **assistente AI** opzionale, un pannello di chat ancorato al bordo destro della dashboard che risponde a domande in linguaggio naturale sui tuoi agenti ("come sta il trend di qualità in prod questa settimana?", "quali sessioni hanno avuto errori oggi?", "riassumi questa sessione") e, quando l'utente lo consente per ogni azione, redige e salva query SQL e dashboard per loro conto. Cita link cliccabili direttamente alle sessioni, query e dashboard rilevanti, ed è **consapevole della pagina**: chiedi informazioni su "questa sessione" mentre ne visualizzi una e capisce cosa intendi. + +Il dock appare come una sottile **barra verticale di 44px** per impostazione predefinita: un glifo di prompt `›_` più un pallino di salute colorato. Fai clic sulla barra (o premi `⌘J` / `Ctrl+J`) per espandere il pannello di chat completo. Il pannello espanso è **ridimensionabile** tra 320 e 640 pixel trascinando il suo bordo sinistro; la larghezza preferita viene ricordata tra i ricaricamenti. + +Viene eseguito come un piccolo contenitore **`agent`** interno (su Claude Agent SDK) che solo la dashboard può raggiungere. È **disabilitato per impostazione predefinita** e rimane nascosto finché non configuri un endpoint LLM. + +--- + +## Cosa può e non può fare + +- **Legge i dati operazionali che l'utente che chiede può vedere.** Eventi, valutazioni, sessioni, la coda dei job di valutazione, query salvate e dashboard salvate, scoped per-richiesta ai permessi di lettura dell'utente. Gli strumenti di lettura vengono eseguiti immediatamente. +- **Le scritture sono controllate dall'approvazione per-azione.** Può redarre query salvate (`create_saved_query`, `update_saved_query`), eseguire SQL bozza contro il ruolo di sola lettura per convalidarlo (`run_query`), e assemblare dashboard da quelle query (`create_dashboard`, `update_dashboard`, `add_query_to_dashboard`). Ogni scrittura si interrompe per un prompt in-chat **Approva / Rifiuta / fai una domanda**; l'SDK non chiama lo strumento finché l'operatore non fa clic su Approva. **L'eliminazione non è mai disponibile per l'assistente**; le operazioni distruttive rimangono con gli operatori. +- **L'SQL bozzato passa attraverso la stessa convalida `sql_guard` e ruoli di sola lettura come l'SQL scritto dall'utente** (solo SELECT/WITH, no multi-statement). L'esecuzione viene instradata in base alle tabelle che la query tocca: le query che fanno riferimento alle tabelle analytics (eventi, valutazioni, sessioni) vengono eseguite come utente ClickHouse di sola lettura dell'organizzazione (scoped a quella org da una row policy, con un limite di esecuzione di 10s e un limite di 100k righe) mentre le query che toccano solo tabelle relazionali vengono eseguite su un ruolo Postgres di sola lettura (10s, 10k righe). L'assistente non può ampliare la superficie dei dati; può solo redarre sulla superficie di query che l'operatore ha già. +- Utilizza una **chiave assistente dedicata** (vedi sotto) inizializzata con un set di permessi fisso; anche se il modello si comporta male non può superare quegli scope. +- Ogni utente della dashboard ha bisogno del permesso **`agent:use`** per vedere e usare l'assistente. Gli strumenti vengono filtrati per-richiesta in modo da corrispondere ai permessi di dati dell'utente stesso, quindi un utente `events:read` ottiene strumenti di event ma nessuno strumento `dashboards:write`. + +--- + +## Dock AI consapevole della pagina: composer su `/queries`, chat altrove + +Il dock assistente sulla destra è **consapevole della pagina**. Il selettore di modello, la cronologia della conversazione, il pallino di salute del modello e l'input di chat rimangono invariati, ma i **chip del template di stato vuoto, il testo del placeholder e quale endpoint backend colpisce il messaggio di un utente** cambiano tutti automaticamente in base al percorso corrente. Il dock diventa "l'aiutante AI per qualsiasi pagina su cui stai". + +**Due backend, selezionati per pagina (con override per-chip).** + +| Percorso | Backend predefinito della pagina | Motivo | +| ------------------------------ | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | +| `/queries`, `/queries/new` | `POST /api/agent/compose-sql` (nessun tool loop) | L'utente inizia da zero; SQL del primo token in ≤1s inviato direttamente all'editor | +| `/queries/` (esistente) | `POST /api/agent/chat` (assistente con tool-loop completo), default della pagina | I messaggi liberi dovrebbero lasciare che l'utente chieda qualsiasi cosa ("spiega questo", "cosa fa questo?"); i chip di refactor opt back in compose-sql tramite kind per-chip | +| ogni altra pagina | `POST /api/agent/chat` (assistente con tool-loop completo) | Strumenti di lettura + strumenti di scrittura controllati dall'approvazione | + +I chip su `/queries/` portano un `kind` esplicito in modo che una singola pagina possa mescolare i due flussi senza problemi. L'insieme di chip predefinito è due chip **chat** (`spiega la query sullo schermo`, `cosa fa questa query?`) più cinque chip **compose-sql** (`parametrizza per intervallo di date`, `aggiungi un filtro status='error'`, ecc.). I messaggi a testo libero ricadono nel default della pagina (chat), quindi una domanda come "perché è così lento?" ottiene una risposta in prosa, mentre fare clic sul chip `parametrizza per intervallo di date` instrada attraverso l'endpoint compose e modifica l'SQL. + +Quando il composer viene eseguito in **modalità modifica** (vede un `currentSql` non vuoto perché l'utente è su `/queries/` o `/queries/new` con SQL proposto già caricato), il suo system prompt passa da "componi una nuova query" a "modifica l'SQL fornito minimamente: conserva la scelta della tabella, i nomi delle colonne, la struttura del join, gli alias, l'indentazione". Al modello viene mostrato un insieme separato di esempi lavorati prima/dopo (parametrizzare, aggiungere filtro, convertire in bucket orari), quindi un refactor cliccato da chip produce un diff minimo rispetto all'SQL dell'editor, non una riscrittura da zero. + +Fai clic su un chip compose (o digita liberamente su `/queries/new`) → l'SQL viene trasmesso nel messaggio dell'assistente come un blocco ` ```sql ` recintato. **Nel momento in cui il flusso si finalizza, se Monaco è montato sul percorso corrente, l'editor si accende automaticamente in vista diff** (originale a sinistra, proposto a destra, un indizio `▾ AI ha proposto una modifica` in alto, e pillole **Accetta / Rifiuta** sotto). L'utente non ha bisogno di trovare o fare clic su un pulsante `Inserisci nell'editor` per vedere il diff. Il pulsante Inserisci viene comunque reso sotto il blocco SQL come ri-trigger manuale (utile dopo un Rifiuta o quando l'utente si è navigato via e tornato), e rimane l'unico percorso quando l'utente si trova su una pagina non-editor (es. l'elenco delle query salvate); lì memorizza l'SQL in `sessionStorage` e naviga a `/queries/new`, dove l'editor appena montato legge la memorizzazione al mount e apre la stessa vista diff. + +Se l'SQL proposto è byte-identico a quello già nell'editor (una modifica no-op), l'apertura automatica viene saltata; non mostriamo un diff vuoto. Il pulsante `Inserisci nell'editor` è anche una no-op in quel caso. + +Quando l'utente accetta un suggerimento su `/queries/new`, l'azione principale della barra degli strumenti legge **`save`** invece di `create`; l'SQL è stato consegnato dall'assistente; il modello mentale è "finalizza questo", non "scrivi da zero". L'etichetta si capovolge una volta che il dock inserisce l'SQL e rimane come `save` fino alla navigazione della pagina. Su `/queries/` il pulsante ha sempre letto `save`; nulla cambia lì. + +Fuori da `/queries`, il dock funziona esattamente come prima: chat completa con carte di approvazione dello strumento, consapevolezza del contesto della pagina, citazioni. + +**Permessi / controllo.** L'endpoint compose controlla il permesso `queries:run` per-utente (equivalente di lettura; l'utente deve comunque fare clic su Accetta ed Esegui, e Esegui passa attraverso il routing `sql_guard` + `references_ch_tables` esistente sul server Rust). L'endpoint chat controlla `agent:use`. Entrambi richiedono ancora una connessione LLM configurata sul contenitore `agent`; se nessuna è configurata, il dock mostra un banner "l'assistente non è configurato su questo deployment" su entrambi i percorsi. + +**Rifiuti.** Il composer rifiuta qualsiasi richiesta che non può soddisfare con una query analytics di sola lettura e emette `-- REFUSE: ` invece di SQL. Rifiuta le richieste che scriverebbero dati o raggiungerebbero tabelle al di fuori delle viste analytics (`api_keys`, `users`, `dashboards`, `saved_queries`, `evaluation_jobs`), e rifiuta pure richieste prose ("spiega questo", "cosa fa questo?") sul percorso compose; quelle appartengono al percorso chat e producono una risposta in prosa lì. Il dock rende la stringa di rifiuto come un chip di errore rosso inline nel messaggio dell'assistente; nulla viene inserito. + +**Selezione del modello.** Condivisa con il percorso chat. Il selettore di modello nell'intestazione del dock si applica a entrambi gli endpoint (la chiamata compose passa il modello selezionato attraverso a `resolveModel()` sul servizio agent). Quando `AGENTEYE_AGENT_MODELS` elenca più modelli, gli operatori possono mescolare un'opzione di classe Haiku per il composer con un'opzione di classe Sonnet per la chat; l'utente sceglie per-conversazione. + +**Template per-pagina.** Ogni pagina ha il suo template (titolo, corpo del testo, testo del placeholder e chip di suggerimento) quindi il dock si adatta alla pagina su cui stai. I chip offerti su un dato percorso mappaano gli stessi intenti su cui è messo a punto il composer, quindi fare clic su un suggerimento produce la modifica che ti aspetti. + +**Disabilitandolo.** Come nel percorso chat: il dock + composer sono entrambi controllati dal contenitore `agent` e dalla sua connessione LLM. Se desideri un comportamento chat-only per un particolare utente, rimuovi il permesso `queries:run` (che disabilita anche il pulsante **Run** dell'editor); se desideri un comportamento composer-only, rimuovi `agent:use` dai ruoli di quell'utente, quindi re-aggiungi `queries:run` separatamente in modo che possano ancora eseguire SQL scritto dall'autore. + +--- + +## Abilitandolo + +Il servizio `agent` viene fornito nel file Docker Compose e nei manifest Kubernetes. Per attivare l'assistente, fornisci **(1)** un endpoint LLM e **(2)** la chiave dati dedicata dell'assistente. + +### 1. Scegli una connessione LLM + +Scegline una di queste e imposta le variabili corrispondenti sul servizio `agent`: + +**a) Anthropic direttamente** + +``` +ANTHROPIC_API_KEY=sk-ant-... +``` + +**b) Attraverso Portkey (consigliato; slug del catalogo dei modelli, solo chiave)** + +``` +PORTKEY_API_KEY= +AGENTEYE_AGENT_MODEL=@/claude-sonnet-4-6 +``` + +Questo è il percorso più semplice: in Portkey, configura un'**integrazione Anthropic** (Catalogo dei modelli); ottiene uno **slug**. Nomina il modello come `@/` e lo slug porta il routing del provider + credenziale, quindi **nessuna chiave virtuale è necessaria**, solo la tua chiave API Portkey. L'agente invia solo `x-portkey-api-key` e punta al gateway Portkey; Portkey risolve il resto. (Un nome di modello *semplice* fallisce con "x-portkey-config o x-portkey-provider header is required"; il prefisso `@slug/` è quello che rende il key-only funzionare.) Per un gateway auto-ospitato imposta `PORTKEY_BASE_URL`. + +Preferisci il routing per-richiesta invece di uno slug? Imposta `PORTKEY_VIRTUAL_KEY=` (o `PORTKEY_CONFIG=`) con un `AGENTEYE_AGENT_MODEL` semplice. + +**c) Qualsiasi altro gateway compatibile con Anthropic (LiteLLM, auto-ospitato, …)** + +``` +ANTHROPIC_BASE_URL=https://your-gateway +# Righe di intestazione newline-delimited "Name: Value" (NOT JSON): +ANTHROPIC_CUSTOM_HEADERS=x-my-header: value +``` + +**d) Amazon Bedrock / Google Vertex** + +``` +CLAUDE_CODE_USE_BEDROCK=1 # + credenziali AWS standard nell'ambiente +# oppure +CLAUDE_CODE_USE_VERTEX=1 # + credenziali GCP standard nell'ambiente +``` + +Opzionalmente fissa il modello predefinito con `AGENTEYE_AGENT_MODEL` (default `claude-sonnet-4-6`). Per lasciare che gli utenti **scelgano** tra più modelli, imposta `AGENTEYE_AGENT_MODELS` a una lista di autorizzazione separata da virgole (es. `@anthropic-prod/claude-opus-4-7,@anthropic-prod/claude-sonnet-4-6`); allora appare un selettore di modello nell'intestazione della chat, e la scelta di ogni utente viene ricordata. L'agente chiama solo un modello su questa lista di autorizzazione. + +### 2. Fornisci la chiave dell'assistente + +Scegli un segreto casuale e forniscilo all'**agent** come `AGENTEYE_API_KEY` e al **server** come `AGENT_API_KEY` (lo stesso valore). All'avvio il server lo inizializza come una chiave dedicata denominata `dashboard-assistant` con questo set di permessi fisso: `events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run`. I permessi di scrittura vengono esercitati solo attraverso strumenti controllati dall'approvazione (vedi "Cosa può e non può fare" sopra). Non c'è **nessun passaggio di minting di chiave manuale e nessuna chiave admin coinvolta**. Il set di permessi è fisso nel server e la chiave inizializzata è **protetta**: non può essere disabilitata o rigenerata attraverso l'API delle chiavi; ruotala cambiando il valore e riavviando il server. **Non** riutilizzare la chiave admin/dashboard. + +```bash +SECRET="$(openssl rand -base64 32)" +# sul servizio agent: +AGENTEYE_API_KEY="$SECRET" +# sul servizio server: +AGENT_API_KEY="$SECRET" +``` + +Su Kubernetes questo è cablato per te: metti `AGENTEYE_API_KEY` nel segreto `agenteye-agent` e il server Deployment legge già quello stesso valore come `AGENT_API_KEY`. + +### 3. Imposta il token dashboard↔agent condiviso + +Imposta lo stesso `AGENTEYE_AGENT_TOKEN` **su entrambi** i servizi `dashboard` e `agent`. La dashboard lo presenta quando chiama il servizio agent interno; l'agent rifiuta le chiamate senza di esso. + +### 4. Concedi accesso agli utenti + +Dai agli operatori dashboard rilevanti il permesso `agent:use` (vedi [enterprise-docs/api-keys.md](/it/agenteye/api-keys)). Gli utenti senza di esso non vedono mai l'assistente. + +Una volta che un endpoint LLM e la chiave di sola lettura sono impostati, riavvia il **server** (per inizializzare la chiave di sola lettura) e il servizio **agent**. Il dock assistente appare sul bordo destro per qualsiasi utente `agent:use`, collassato per impostazione predefinita; fai clic sulla barra o premi `⌘J` / `Ctrl+J` per espandere. + +--- + +## Riferimento delle variabili di ambiente + +Imposta sul servizio **`agent`**: + +| Variabile | Scopo | +|---|---| +| `PORTKEY_API_KEY` | Instrada attraverso Portkey (l'agente costruisce la connessione al gateway da questo) | +| `PORTKEY_VIRTUAL_KEY` | Chiave virtuale Portkey per le tue credenziali Anthropic (opzionale se la chiave ha una config predefinita) | +| `PORTKEY_CONFIG` / `PORTKEY_BASE_URL` | Config Portkey denominato / URL del gateway Portkey auto-ospitato (opzionale) | +| `PORTKEY_PROVIDER` | Slug del provider Portkey — un'opzione di routing terza insieme a `PORTKEY_VIRTUAL_KEY` / `PORTKEY_CONFIG` (usato solo quando nessuno di questi è impostato) | +| `ANTHROPIC_API_KEY` | Accesso diretto ad Anthropic (alternativa a un gateway / Bedrock / Vertex) | +| `ANTHROPIC_AUTH_TOKEN` | Token bearer per un gateway che autentica via `Authorization: Bearer` invece di `x-api-key` (opzionale) | +| `ANTHROPIC_BASE_URL` | Endpoint per un gateway non-Portkey | +| `ANTHROPIC_CUSTOM_HEADERS` | Header extra per un gateway non-Portkey: righe newline-delimited `Name: Value` (non JSON) | +| `CLAUDE_CODE_USE_BEDROCK` / `CLAUDE_CODE_USE_VERTEX` | Instrada via Bedrock / Vertex | +| `AGENTEYE_AGENT_MODEL` | ID del modello predefinito (default `claude-sonnet-4-6`) | +| `AGENTEYE_AGENT_MODELS` | Lista di autorizzazione separata da virgole dei modelli che l'utente può selezionare nell'intestazione della chat. Lascia non impostato per un singolo modello fisso. Il default sopra deve essere uno di questi (altrimenti viene aggiunto). | +| `AGENTEYE_AGENT_MAX_CONCURRENCY` | Max chat simultanee per pod (default 4); le richieste in eccesso ottengono 429 | +| `AGENTEYE_API_KEY` | Chiave dati dell'assistente. Imposta lo **stesso** valore dell'`AGENT_API_KEY` del server, che lo inizializza con un set di permessi scoped fisso all'avvio (vedi step 2). | +| `AGENTEYE_AGENT_TOKEN` | Segreto condiviso con la dashboard | +| `AGENTEYE_SERVER_URL` | URL del server AgentEye (default `http://server:8080`) | +| `AGENTEYE_AGENT_ALLOW_NO_ORG` | **Multi-tenancy.** Disabilitato per impostazione predefinita (fail-closed): l'assistente rifiuta una richiesta `/chat` che non porta contesto dell'organizzazione con `400`, perché ogni strumento che esegue è scoped a un'org. La dashboard invia sempre quel contesto una volta che è org-aware, quindi normalmente lasci questo non impostato. Imposta a `1` **solo** durante un rollout transizionale dove una dashboard non-ancora-org-aware sta parlando a un agent org-aware, in modo che l'assistente ricada nell'org `default` invece di rifiutare. Cancellalo una volta che l'upgrade della dashboard arriva. | +| `AGENTEYE_AGENT_MAX_STEPS` | Max step tool-use per risposta (default 8) | +| `AGENTEYE_AGENT_TIMEOUT_MS` | Timeout complessivo della richiesta `/chat` (tutti i turni del modello + step dei tool), in millisecondi (default 90000); lo strumento SQL ha il suo proprio limite di 10s | +| `AGENTEYE_AGENT_SELF_TELEMETRY` | `1` per registrare le proprie esecuzioni dell'assistente in AgentEye | +| `AGENTEYE_TELEMETRY_API_KEY` | Chiave separata `events:add`-only per self-instrumentation | +| `AGENTEYE_AGENT_ENV` | Tag di ambiente applicato alla self-telemetry dell'assistente (default `prod`) | + +Imposta sul servizio **`dashboard`**: + +| Variabile | Scopo | +|---|---| +| `AGENTEYE_AGENT_URL` | Dove la dashboard raggiunge il servizio agent. I manifest Kubernetes e il file Compose in bundle impostano questo a `http://agent:9100`. Lascialo non impostato per nascondere completamente l'assistente. | +| `AGENTEYE_AGENT_TOKEN` | Deve corrispondere al token dell'agent | + +--- + +## Telemetria e vedere cosa chiedono gli utenti + +Il **contenuto dei prompt rimane nei tuoi sistemi** per impostazione predefinita. Tre livelli: + +1. **Conversation store**: ogni prompt e risposta viene salvato nel tuo database AgentEye (per utente, privato), e ricaricabile dal selettore di cronologia dell'assistente. Questo è il record duraturo di quello che gli utenti chiedono. +2. **Product analytics**: la dashboard registra **solo i metadati** (quanto spesso viene utilizzato l'assistente, conteggi degli strumenti, latenza) nella tua analytics. Il **testo** del prompt non è mai incluso su questo percorso. +3. **Self-instrumentation (opzionale)**: imposta `AGENTEYE_AGENT_SELF_TELEMETRY=1` (più una `AGENTEYE_TELEMETRY_API_KEY` solo `events:add`) e l'assistente registra le proprie esecuzioni in AgentEye come un agente `dashboard-assistant`. Poi osservi i prompt degli utenti e il ragionamento dell'assistente nella stessa vista sessioni/eventi che usi per tutto il resto. Nota: quegli eventi sono visibili a chiunque abbia `events:read`; se è troppo ampio, lascialo disattivato. + +--- + +## Disabilitandolo + +Uno qualsiasi di questi disabilita l'assistente (la barra del dock scompare): + +- Annulla l'impostazione di `AGENTEYE_AGENT_URL` sulla dashboard, **oppure** +- Lascia l'endpoint LLM non configurato sull'agent (no `ANTHROPIC_API_KEY` / gateway / Bedrock / Vertex), **oppure** +- Non distribuire affatto il servizio `agent`. + +--- + +## Riassunto della sicurezza + +- **Nessuna scrittura silenziosa**: gli strumenti di scrittura dell'assistente (`create_saved_query`, `update_saved_query`, `create_dashboard`, `update_dashboard`, `add_query_to_dashboard`) non possono essere eseguiti senza un click esplicito dell'operatore sul pulsante Approva in-chat; il gate pre-call dell'SDK blocca lo strumento finché un'approvazione non raggiunge l'agent su un back-channel. Non c'è nessuna impostazione che disabilita questo gate. +- **Scope di dati fisso e stretto**: l'assistente autentica al server con una chiave dedicata il cui set di permessi è fisso nel server (`events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run`). Le uniche scritture che può redarre sono query salvate e dashboard; il server rifiuta qualsiasi cosa al di fuori di quello scope indipendentemente da quello che il modello tenta. +- **Nessuna superficie di eliminazione**: la chiave non porta nessun permesso di eliminazione e nessuno strumento di eliminazione è esposto. Gli operatori eliminano attraverso l'UI della dashboard, mai attraverso l'assistente. +- **Solo interno**: l'agent non ha nessun percorso pubblico; solo la dashboard può chiamarlo, e solo con il token condiviso. (Su Kubernetes, una NetworkPolicy limita l'agent a raggiungere solo il server AgentEye e l'endpoint LLM.) +- **Scoping per-utente**: solo gli utenti `agent:use` ottengono l'assistente, e viene dato solo gli strumenti corrispondenti ai permessi di lettura di ogni utente. +- **Nessun HTML grezzo / nessuna esfiltrazione di link**: le risposte sono renderizzate come markdown sanitizzato; i link esterni sono defanged. + +Vedi [enterprise-docs/troubleshooting.md](/it/agenteye/troubleshooting) per i problemi comuni. \ No newline at end of file diff --git a/docs/it/agenteye/audits.mdx b/docs/it/agenteye/audits.mdx new file mode 100644 index 00000000..70be54bc --- /dev/null +++ b/docs/it/agenteye/audits.mdx @@ -0,0 +1,107 @@ +--- +title: "Audits — agentic improvement detection" +description: "AgentEye Audits — agentic improvement detection documentation." +--- + + +Gli audit sono job ricorrenti che analizzano i tuoi log degli agenti **tra le sessioni** per trovare aree di miglioramento. Mentre un alert monitora una metrica specifica che conosci già in tempo quasi reale, un audit *indaga*: secondo una pianificazione che tu imposti, esegue una verifica di policy deterministica sulla finestra, quindi libera un **agente AI per l'affidabilità** sulle tue sessioni — l'agente interroga i dati stesso, legge transcript sospetti, ed (quando utile) esegue piccoli script di analisi, quindi redige **raccomandazioni di miglioramento** con le prove dietro ognuna. + +Usa gli audit per rispondere a "cosa dovrei correggere o migliorare nei miei agenti?" — e gli alert per essere avvisato nel momento esatto in cui una soglia specifica viene superata. Ogni miglioramento si collega alle sessioni e alle query esatte dietro di esso, e un solo clic crea un alert precompilato per catturare ricorrenze. + +La superficie del dashboard è **`//audits`** (sidebar → *analyze* → *audits*), protetta dalle autorizzazioni `audits:read` / `audits:write`. + +--- + +## Come funziona una esecuzione + +Ogni esecuzione ha due livelli — una base deterministica e un'indagine agentica. + +### 1. La verifica di policy (deterministica) + +Prima che qualsiasi modello venga eseguito, l'audit esegue un piccolo catalogo di **verifiche di policy SQL** sulla finestra: query aggregate delimitate che evidenziano schemi noti come problematici e segnalano *quanti* eventi / *quali* sessioni li hanno generati — mai il testo dei risultati. Il catalogo include: + +- **Leakage di secret / credenziali** nei payload degli eventi — chiavi di accesso AWS, chiavi API `sk-…`, chiavi private PEM, token JWT / bearer, e assegnazioni di credenziali `KEY=…`. +- **Marcatori di prompt injection** — "ignora le istruzioni precedenti", "rivela il tuo system prompt", e simili. +- **PII** — numeri simili a SSN (euristico). +- **Negazioni di autorizzazione degli strumenti** e **loop di tool-call in fuga**. + +I risultati della policy vengono persistiti come finding (tipo `policy`) che **affiorano sempre** (non vengono mai eliminati dal limite per-esecuzione), e vengono passati all'agente AI come piste iniziali. Poiché questo livello non necessita del modello, un audit produce comunque i suoi segnali di sicurezza più importanti anche se l'agente AI è non disponibile. + +### 2. L'indagine agentica (AI) + +L'audit quindi esegue un **agente di affidabilità autonomo** (lo stesso servizio Agents SDK di Claude che alimenta l'assistente dashboard, con un prompt specifico per l'audit). Data la **portata** dell'audit (agenti selezionati × ambienti) e la **finestra temporale**, l'agente: + +- esegue query SQL di sola lettura sulle tue tabelle di analytics, +- legge un certo numero di transcript di sessioni rappresentative, +- facoltativamente scrive ed esegue brevi **script Python in una sandbox in-pod blindata** (nessuna rete, nessun accesso al filesystem, secret eliminati) per analisi che SQL non può esprimere — clustering di errori, calcolo di distribuzioni, scansione di payload già recuperati, +- e registra ogni **miglioramento** ben comprovato che trova. + +Lavora attraverso diverse linee investigative — clustering di errori, drift rispetto a una baseline, fallimento dell'obiettivo negli transcript, abuso di strumenti, compromessi qualità/costo, e gap di copertura — secondo la **sensibilità** dell'audit (bassa / media / alta). Ogni miglioramento **deve citare prove**: gli id di sessione che l'agente ha effettivamente ispezionato e/o l'SQL che ha eseguito. Il server valida che le sessioni citate esistano e **scarta qualsiasi miglioramento senza prove sopravvissute**, quindi l'agente indaga ma non inventa mai. + +Ogni miglioramento comporta: + +- una **raccomandazione** (il cambio concreto da apportare — una modifica di prompt, una correzione di schema tool, una politica di retry, una guardrail, più copertura eval), +- una stima di **impatto atteso** e **sforzo** (basso / medio / alto), +- una **magnitudine** — `big` (un operatore dovrebbe essere avvisato), `medium` (appartiene alla relazione di esecuzione), o `small` (contesto dashboard), +- un'**impronta** stabile (dalla categoria del problema + portata, *non* dalle sessioni di questa esecuzione) così lo stesso problema viene tracciato da esecuzione a esecuzione anche mentre le prove cambiano, +- e, dove un semplice watcher deterministico potrebbe catturare ricorrenza, un **alert suggerito** che puoi creare con un solo clic. + +> **Il livello AI è opzionale ma consigliato.** Se nessun agente AI è configurato per la pipeline audit, le esecuzioni comunque si eseguono, persistono i finding di policy, e onestamente riportano "analisi non disponibile" per il livello agentico piuttosto che passare silenziosamente. + +### Modalità di fallimento + +I miglioramenti si classificano nel tuo catalogo durabile di **modalità di fallimento** (o propongono una nuova modalità). Le modalità danno ai pattern un'identità stabile tra le esecuzioni e il tracciamento di ricorrenza a lungo termine. + +## Ciclo di vita della triaging + +In una pagina di finding (`/audits//findings/`): + +| Azione | Effetto | +|---|---| +| **acknowledge** | Mantiene il finding visibile ma dimezza la sua priorità. | +| **resolve** | Lo contrassegna come risolto. Se il pattern ritorna genuinamente in seguito, si riapre come **new** — quindi una regressione è evidente, non silenziosamente incorporata nella storia. | +| **mute** / **dismiss** | Soppressione duratura: l'impronta del pattern viene ricordata e non affiora mai più, anche tra le esecuzioni. Usa mute per "noto, accettato"; dismiss per "non utile". | +| **reopen** | Cancella la soppressione / risoluzione e riclassifica il pattern. | +| **assign** | Instrada il finding a un operatore (un membro dell'org) per la proprietà. Priorità e stato di soppressione rimangono invariati. | + +Il rumore di basso segnale è controllato per audit con un limite di finding per-esecuzione (`top_k`) sui miglioramenti agentici. I finding di policy bypassano il limite (sono rilevanti per la sicurezza e sempre mostrati). Qualsiasi cosa tagliata dal limite è contata nelle statistiche dell'esecuzione — nulla viene silenziosamente eliminato. + +## Pianificazione + +- **Cadenza** (`schedule_interval_secs`): ogni ora fino a settimanale; **giornaliero è il default**. Gli audit sono deliberatamente più grossolani degli alert — un'indagine agentica scansiona intere finestre ed esegue per minuti. +- **Finestra**: o una lookback rolling fissa (ad es. "ogni esecuzione scansiona gli ultimi 7 giorni") o **since-last-run** (il default) — ogni esecuzione riprende da dove è finita la precedente esecuzione riuscita, con una piccola sovrapposizione così gli eventi al confine non vengono mai persi. +- L'esecuzione successiva è pianificata un intervallo completo dopo il completamento della precedente **completes**, quindi un'esecuzione lenta non mette mai in coda una seconda esecuzione concorrente dello stesso audit. +- **Run now** nella pagina audit la rende dovuta immediatamente. + +## Selezione del modello + +Quando crei un audit puoi scegliere quale modello l'indagine usa, dalla **lista di modelli che il tuo operatore ha configurato** per il servizio agenti. Con un singolo modello configurato, il picker lo mostra come caption; con più, tu scegli. Lasciarlo non impostato usa il default configurato. + +## Notifiche + +Quando un'esecuzione affiora finding **nuovi**, l'audit notifica i canali configurati della tua organizzazione — la stessa porta `alerts.enabled_channels` e le impostazioni che la pipeline di alert usa: + +- **Slack** — un riepilogo degli elementi nuovi significativi (`big`) con un deep link. +- **Email** — una **relazione di audit** progettata che elenca i nuovi miglioramenti (top severity, raccomandazioni per-item, deep link), inviata quando l'audit ha un canale **email** allegato ed esiste almeno un finding nuovo. + +I finding ricorrenti ma noti non ri-notificano. + +## Riferimento di configurazione + +Le definizioni di audit sono gestite nel dashboard (`/audits/new`) o via API. Le impostazioni per-audit includono la cadenza di pianificazione e la finestra, la portata (`{"environments": [...], "agent_ids": [...]}`), la sensibilità (`low` / `medium` / `high`), i canali di notifica, il limite di finding per-esecuzione (`top_k`), e il modello (via `llm_budget.model`). Le impostazioni server a livello operatore (timeout, sandbox, l'URL del servizio agenti) sono documentate in [deployment.md](/it/agenteye/deployment). + +## API + +Tutti gli endpoint sono org-scoped e seguono l'auth standard bearer-key (vedi [api-keys.md](/it/agenteye/api-keys)). + +| Endpoint | Autorizzazione | Scopo | +|---|---|---| +| `GET /audits` · `POST /audits` | `audits:read` / `audits:write` | Elenca / crea definizioni di audit. | +| `GET` / `PUT` / `DELETE /audits/:id` | read / write / write | Ispeziona, modifica, elimina un audit. | +| `POST /audits/:id/run` | `audits:write` | Rendi l'audit dovuto immediatamente. | +| `GET /audits/:id/runs` | `audits:read` | Cronologia di esecuzione (finestra, status, statistiche, conteggi di finding). | +| `GET /audits/findings` | `audits:read` | Finding a livello org, filtrabili per `audit_id`, `status`; ordinati per priorità. | +| `GET /audits/findings/:fid` | `audits:read` | Dettaglio completo di finding (raccomandazione, prova, priorità). | +| `POST /audits/findings/:fid/status` | `audits:write` | Triaging: `{"action": "ack" \| "mute" \| "dismiss" \| "resolve" \| "reopen" \| "assign"}`. | + +Per "audit eseguito ma non ha trovato nulla", "la sandbox del codice è disabilitata", e "email dell'audit non consegnata", vedi [troubleshooting.md](/it/agenteye/troubleshooting#audits). \ No newline at end of file diff --git a/docs/it/agenteye/cli-recipes.mdx b/docs/it/agenteye/cli-recipes.mdx new file mode 100644 index 00000000..fdbad359 --- /dev/null +++ b/docs/it/agenteye/cli-recipes.mdx @@ -0,0 +1,169 @@ +--- +title: "Ricette CLI per agenti" +description: "Documentazione delle ricette CLI di AgentEye per agenti." +--- + +Estrai dati di sessione, evento e valutazione (e attiva rivalutazioni) direttamente da uno script o da un agente di codifica, con JSON pulito su stdout che si collega direttamente a `jq`. Queste ricette trasformano i dati di osservabilità di AgentEye in qualcosa che un utente di terminale o un agente di codifica AI (Claude Code, Cursor) può interrogare e automatizzare, senza fare clic sulla dashboard. + +I modelli sottostanti sono pronti per copia-incolla per AgentEye CLI (`agenteye`). Per l'installazione, l'autenticazione e l'elenco completo delle opzioni consulta [CLI](/it/agenteye/cli); esegui `agenteye -h` o `agenteye -h` per la guida integrata. + +## Regole d'oro + +1. **Le opzioni globali vanno *prima* del comando.** `agenteye --json sessions` è corretto; `agenteye sessions --json` non lo è. Le globali sono `--json`, `--base-url`, `--org`, `--token`, `--insecure`/`--secure`, `--timeout`, `--quiet`, `--no-color`. +2. **Passa `--json` ogni volta che analizzi l'output.** I dati vanno su **stdout** come JSON; lo stato umano e gli errori vanno su **stderr**, quindi stdout rimane pulito per collegarsi a `jq`. +3. **Crea un ramo in base al codice di uscita**, non al testo di stderr: `0` ok · `2` argomenti non validi · `3` impossibile raggiungere la dashboard · `4` non connesso o scaduto · `5` autorizzazione mancante. +4. **Scopri con `-h`.** Ogni comando documenta i suoi filtri, i formati di valore e la forma JSON. + +## Configurazione una tantum + +```bash +export AGENTEYE_DASHBOARD_URL=https://agenteye.example.com # così non ripeti --base-url +agenteye login --email you@example.com # incolla il codice inviato; valido ~24h +``` + +## Conferma l'autenticazione prima di fare il lavoro + +`whoami` non genera mai errori su una sessione mancante o scaduta; invece segnala `logged_in:false`, così un agente può controllare lo stato di autenticazione in sicurezza. (Può comunque uscire con un codice diverso da zero se nessun URL di base è impostato o la dashboard non è raggiungibile.) + +```bash +if [ "$(agenteye --json whoami | jq -r .logged_in)" != "true" ]; then + echo "Not authenticated. Run: agenteye login" >&2; exit 1 +fi +``` + +## Trova sessioni fallite o con punteggio basso + +```bash +# sessioni nelle ultime 24h la cui valutazione ha generato errore +agenteye --json sessions --since 24h --status error | jq -r '.sessions[].session_id' + +# valutazioni con punteggio <= 0.5 su helpfulness, per un agente +agenteye --json evals --agent-id checkout-bot --score helpfulness:..0.5 \ + | jq '.evaluations[] | {session_id, scores}' +``` + +Il filtro dei punteggi vive su **`evals`**, non su `sessions`. `--score KEY:MIN..MAX` è ripetibile e AND-combinato; entrambi i limiti sono opzionali (`..0.5` significa ≤ 0.5, `0.9..` significa ≥ 0.9). Puoi passare fino a 20 filtri di punteggio per richiesta; più di questo restituisce HTTP 400. `sessions` condivide i filtri `--env`, `--status`, `--agent-id`, `--session-id` e intervallo di tempo con `evals`, ma non ha `--score`. + +## Leggi una sessione da capo a fondo + +Non esiste un singolo comando `session show` — combina il trail di eventi con la valutazione della sessione: + +```bash +# la valutazione più recente della sessione (status + scores) +agenteye --json evals --session-id run-001 | jq '.evaluations[0] | {status, scores}' + +# ogni evento nell'esecuzione (aumenta --limit per una scansione completa) +agenteye --json events --session-id run-001 --all --limit 1000 | jq '.events[] | {ts, event_type}' + +# solo le tool call in una sessione +agenteye --json events --session-id run-001 --event-type tool_use,tool_result --all \ + | jq '.events[].payload' +``` + +## Estrai tutto (paginazione) + +I risultati sono più recenti per primi e paginati con cursore. + +```bash +# in una sola volta: estrai fino a 500 righe in pagine di 200 righe +agenteye --json events --session-id run-001 --limit 500 --all > events.json + +# paginazione manuale: reinserisci next_cursor +page=$(agenteye --json events --limit 100) +cursor=$(echo "$page" | jq -r '.next_cursor // empty') +[ -n "$cursor" ] && agenteye --json events --limit 100 --cursor "$cursor" +``` + +## Semplifica l'output con --fields + +Limita le chiavi (sia nella tabella che in `--json`) per ridurre quello che un agente deve leggere. + +```bash +agenteye --json sessions --since 7d --fields session_id,status,scores | jq -c '.sessions[]' +agenteye --json events --session-id run-001 --fields ts,event_type --all +``` + +I nomi di campo sconosciuti vengono rifiutati (uscita `2`) con l'elenco valido, un modo economico per scoprire i nomi dei campi. + +## Scopri i valori di filtro validi + +```bash +agenteye --json list envs | jq -r '.values[]' # valori per --env +agenteye --json list tools | jq -r '.values[]' # nomi degli strumenti; anche agents, models, event_types, … +agenteye --json list score_filters | jq -r '.values[]' # KEY valido per --score KEY:MIN..MAX +``` + +## Scegli la tua organizzazione (multi-tenant) + +Se appartieni a più di un'organizzazione, scegli il tenant attivo al login (viene salvato): + +```bash +agenteye login --org acme --email you@corp.com # imposta il tenant nello stesso passaggio del login +agenteye --json orgs list | jq -r '.orgs[].org_slug' +agenteye --org globex --json sessions --since 24h # sostituisci per un comando +``` + +Un login multi-org senza `--org` esce con un codice diverso da zero e stampa le organizzazioni tra cui scegliere. + +## Fornisci una chiave API per SDK/collector + +```bash +# il segreto viene stampato UNA SOLA VOLTA — con --json è il campo .key +key=$(agenteye --json keys create ci-bot --add events:read.add | jq -r '.key') +agenteye keys regenerate ci-bot --yes # ruota; agenteye keys disable ci-bot --yes per revocare +``` + +## Esegui una query salvata o ad-hoc + +```bash +agenteye --json query run --sql "select count(*) from analytics.events" | jq '.rows' +agenteye --json query run errs --arg prod | jq '.rows' # una query salvata + un $1 posizionale +``` + +## Esamina un incidente in modo non interattivo + +```bash +id=$(agenteye --json incidents list --state firing | jq -r '.incidents[0].id') +agenteye incidents ack "$id" +agenteye incidents assign "$id" you@corp.com +agenteye incidents resolve "$id" --yes +``` + +> Le mutazioni saltano automaticamente il prompt di conferma sotto `--json` o quando stdin non è un TTY, quindi gli agenti non si bloccano mai; passa `--yes`/`-y` per saltarlo esplicitamente altrove. + +## Gestione del codice di uscita in uno script + +```bash +out=$(agenteye --json sessions --since 1h) || code=$? +case "${code:-0}" in + 0) echo "$out" | jq '.sessions | length' ;; + 4) echo "Session expired - run 'agenteye login'." >&2 ;; + 5) echo "Missing permission (ask an admin for evaluations:read)." >&2 ;; + 3) echo "Dashboard unreachable - check the URL." >&2 ;; + *) echo "Unexpected error (exit ${code})." >&2 ;; +esac +``` + +## Forme di output JSON + +| Comando | stdout JSON (con `--json`) | +|---|---| +| `whoami` | `{"logged_in": true, "id", "email", "is_instance_admin", "active_org", "permissions": [...], "memberships": [...]}` o `{"logged_in": false}` | +| `orgs list` | `{"active_org", "orgs": [{"org_slug","org_name","permission_set","permissions"}]}` | +| `events` | `{"events": [...], "next_cursor": }` | +| `evals` | `{"evaluations": [...], "next_cursor": }` | +| `sessions` | `{"sessions": [...], "next_cursor": }` | +| `errors` | `{"errors": [...], "next_cursor": }` | +| `list ` | `{"kind", "values": [...]}` | +| `keys list` / `keys create` | `{"keys": [...]}` / `{id, name, permissions, created_at, key}` (`key` mostrato una sola volta) | +| `query run` | `{columns: [{name,type}], rows: [[...]], truncated, elapsed_ms}` | +| `users list` / `settings list` | `{"users": [...]}` / `{"settings": [...]}` | +| `alerts list` / `incidents list` | `{"alerts": [...]}` / `{"incidents": [...]}` | +| create/update/delete (qualsiasi) | l'oggetto risorsa, o `{"deleted": true, "id"}` per le eliminazioni | +| failure (qualsiasi, con `--json`) | `{"error": "...", "exit_code": , "status"?: , "hint"?: "..."}` su stdout | + +- Ogni elemento **event** (`events`): `id, session_id, agent_id, event_type, ts, payload, environment`. +- Ogni elemento **evaluation** (`evals`): `id, session_id, agent_id, environment, status, scores, reasoning, summary, error, attempt_count, duration_ms, completed_at, created_at`. +- Ogni elemento **session** (`sessions`): `session_id, agent_id, environment, status, scores, event_count, started_at, last_event_at, first_event_id, last_event_id, latest_evaluation`. + +`--fields` di ogni comando accetta esattamente i nomi dei campi del suo elemento — l'insieme differisce tra `sessions` e `evals`, quindi un nome valido per uno potrebbe essere rifiutato dall'altro. \ No newline at end of file diff --git a/docs/it/agenteye/cli-skill.mdx b/docs/it/agenteye/cli-skill.mdx new file mode 100644 index 00000000..db582abf --- /dev/null +++ b/docs/it/agenteye/cli-skill.mdx @@ -0,0 +1,95 @@ +--- +title: "AgentEye CLI Agent Skill" +description: "Documentazione di AgentEye CLI Agent Skill." +--- + + +La **skill CLI di AgentEye** (`agenteye-cli`) è un *Agent Skill* installabile che insegna a un agente di codifica — Claude Code, Codex e strumenti compatibili — a operare sul tuo deployment di AgentEye attraverso la [`agenteye` CLI](/it/agenteye/cli) a partire da richieste in inglese naturale: *"c'è qualcosa di rotto oggi?"*, *"dai a CI una chiave che può solo inviare eventi"*, *"riconosci l'incidente in corso e assegnalo a me"*. + +**Non** è un servizio o un binario separato. È un piccolo bundle di istruzioni che gira sopra la CLI che hai già installato: l'agente esegue `agenteye --json …`, analizza il JSON pulito e ti risponde in prosa. Tutto ciò che può fare, potresti farlo tu stesso digitando gli stessi comandi. + +--- + +## Come si relaziona alle altre interfacce di AgentEye + +AgentEye ti offre quattro modi per raggiungere gli stessi dati e controlli. Si completano a vicenda: + +| Interfaccia | Che cosa è | Dove gira | Usala quando | +|---|---|---|---| +| **[CLI](/it/agenteye/cli)** | Il riferimento comando/flag per `agenteye` | Il tuo terminale | Vuoi eseguire o scrivere uno script di un comando specifico | +| **[CLI recipes](/it/agenteye/cli-recipes)** | Pattern copia-incolla di `jq`/pipeline | Il tuo terminale / script | Stai integrando la CLI nell'automazione | +| **CLI skill** (questo doc) | Una porta in linguaggio naturale sulla CLI | Il tuo agente di codifica, sulla tua workstation | Vuoi semplicemente chiedere e lasciare che l'agente scelga il comando | +| **[AI Assistant in-dashboard](/it/agenteye/assistant)** | Una chat integrata nel dashboard | Un container interno `agent` nel tuo cluster | Vuoi Q&A in-dashboard sui tuoi dati | + +### vs. l'AI Assistant in-dashboard — una distinzione importante + +Questi sono due strumenti diversi con raggi di azione molto diversi: + +- L'**AI Assistant in-dashboard** ([assistant.md](/it/agenteye/assistant)) è una chat integrata nel dashboard, supportata da un container interno `agent`. È **sola lettura più authoring approvato**: può bozze di query salvate e dashboard, ma ogni modifica si ferma per il tuo click-approvazione esplicito, e non cancella mai. È gestito dal permesso `agent:use` e vede solo i dati dell'org che stai visualizzando. +- La **CLI skill** gira sulla *tua* workstation dentro il *tuo* agente di codifica e guida la CLI `agenteye` come **te**. Può eseguire la **superficie completa, incluse le mutazioni** — creare/ruotare/disabilitare chiavi API, cambiare le impostazioni dell'org, risolvere incidenti, eliminare query salvate — limitato solo dai permessi del tuo login della CLI. Trattalo esattamente come faresti con l'esecuzione di questi comandi manualmente. + +--- + +## Prerequisiti + +1. La **CLI `agenteye` installata** e su `PATH` (vedi [cli.md](/it/agenteye/cli) — `pipx install agenteye`). +2. L'**URL del tuo dashboard** impostato (`AGENTEYE_DASHBOARD_URL`, oppure l'agente passa `--base-url`). +3. Una **sessione autenticata**: esegui prima `agenteye login` tu stesso. La skill **non può** completare per te il login con codice monouso inviato per email — ti dirà di eseguire `agenteye login` se la sessione manca o è scaduta (exit code CLI `4`). + +--- + +## Installare la skill + +Agent Skills sono cartelle che contengono un `SKILL.md` (più riferimenti opzionali). Installi la skill `agenteye-cli` posizionando la sua cartella dove il tuo agente cerca le skill: + +- **Claude Code** — copia la cartella `agenteye-cli/` in `~/.claude/skills/` (disponibile in ogni progetto) o in `/.claude/skills/` (limitato a quel repo). Claude Code la scopre automaticamente; verifica con l'elenco `/skills`, o semplicemente fai una domanda che corrisponda alla sua descrizione. +- **Codex (OpenAI)** — Codex legge lo stesso `SKILL.md`. Il `agents/openai.yaml` fornito imposta `allow_implicit_invocation: true`, quindi Codex auto-seleziona la skill quando un'attività corrisponde; altrimenti invocala esplicitamente come `$agenteye-cli`. + +La skill è mantenuta insieme alla CLI `agenteye` ed è distribuita come parte del tuo pacchetto AgentEye — se non hai la cartella `agenteye-cli`, contatta il tuo referente AgentEye. Nulla al riguardo è limitato: non ha bisogno di nessuna immagine Docker e nessuna credenziale, perché guida solo la CLI `agenteye` **pubblica** contro il tuo dashboard. + +--- + +## Sicurezza — le mutazioni NON richiedono conferma quando un agente esegue la CLI + +**Leggi questo prima di lasciare che un agente faccia modifiche.** + +La CLI `agenteye` normalmente chiede *"sei sicuro?"* prima di un'azione distruttiva. **Salta automaticamente quella conferma ogni volta che non è collegata a un terminale — che è esattamente il modo in cui un agente di codifica la esegue — e `--json` la salta anche.** Quindi il prompt di sicurezza **non** si attiverà per l'agente. + +La skill è scritta per compensare: le è stato indicato di dichiarare il comando esatto che eseguirà e ottenere il tuo **OK esplicito prima di qualsiasi cambio di stato**. Mantieni quella disciplina — quando guidi AgentEye attraverso un agente, *tu* sei il passo di conferma. I comandi che modificano lo stato su cui stare attenti: + +- `keys create` / `update` / `disable` / `regenerate` +- `users create` / `update` / `disable` / `enable` +- `settings set` +- `alerts create` / `update` / `delete` / `test` +- i subcommand `incidents` di scrittura: `ack` / `assign` / `resolve` / `open` / `comment-add` / `comment-delete` / `subscribe` / `unsubscribe` +- `query create` / `update` / `delete` +- `agent rename` / `delete` +- `orgs switch` + +Tutto sotto **Observe** (`events`, `sessions`, `evals`, `errors`, `list`, `whoami`, `orgs list/current/perms`) è di sola lettura e non cambia nulla. + +Poiché l'agente agisce come **te**, può solo fare ciò che il tuo login è autorizzato a fare — i permessi sono risolti **per org** (vedi [api-keys.md](/it/agenteye/api-keys)). Un comando per il quale non hai permesso restituisce exit code `5` con il permesso esatto denominato, quindi l'agente può dirti precisamente cosa chiedere a un admin invece di fallire opacamente. + +--- + +## Ciò che puoi chiedere + +La skill mappa l'intento in linguaggio naturale al comando `agenteye` giusto, scoprendo prima i valori validi (`list `, `whoami`) in modo che non indovini: + +- *"C'è qualcosa di rotto / fallito nelle ultime 24 ore?"* → `errors --since 24h --aggregate`, poi una ripartizione. +- *"Perché la sessione `run-001` ha fallito?"* → `events --session-id run-001 --all` + `evals --session-id run-001`. +- *"Come sta andando la qualità questa settimana?"* → `evals --aggregate --since 7d`, poi approfondisci le esecuzioni con punteggi bassi. +- *"Dai a CI una chiave che può solo inviare eventi."* → `keys create ci --add events:add` (dichiara il comando, poi lo crea e cattura il segreto monouso). +- *"Chi ha accesso? Rendi Dana di sola lettura."* → `users list` → `users update dana@… --permission-set read-only` (dopo confermare con te). +- *"Riconosci l'incidente in corso e assegnalo a me."* → `incidents list --state firing` → `incidents ack ` / `incidents assign you@…`. + +Per i comandi esatti, i flag e le forme JSON dietro questi, vedi [cli.md](/it/agenteye/cli) e [cli-recipes.md](/it/agenteye/cli-recipes). + +--- + +## Vedi anche + +- **[CLI](/it/agenteye/cli)** — riferimento completo di comando e flag per `agenteye`. +- **[CLI recipes per agenti](/it/agenteye/cli-recipes)** — pattern copia-incolla di `jq` e gestione exit-code. +- **[AI Assistant](/it/agenteye/assistant)** — l'assistente in-dashboard (da non confondere con questa skill di terminale). +- **[API Keys](/it/agenteye/api-keys)** — il modello di permesso per-org che limita ciò che la skill può fare. \ No newline at end of file diff --git a/docs/it/agenteye/cli.mdx b/docs/it/agenteye/cli.mdx new file mode 100644 index 00000000..e4b821b7 --- /dev/null +++ b/docs/it/agenteye/cli.mdx @@ -0,0 +1,292 @@ +--- +title: "CLI" +description: "Documentazione CLI di AgentEye." +--- + + +AgentEye CLI (`agenteye`) è un client di terminale per la tua distribuzione AgentEye. Interroga i tuoi dati (sessioni, log degli eventi, valutazioni) e amministra l'organizzazione (chiavi API, utenti, impostazioni, avvisi, incidenti, query salvate) — tutto ciò che fa il dashboard, da uno script o da un agente di codifica. Ogni comando supporta un flag `--json`, per funzionare allo stesso modo sia per un umano al prompt che per un agente di codifica (Claude Code, Cursor) che lo richiama e ne analizza il risultato. + +> Questo è il **CLI `agenteye`**, uno strumento diverso dal daemon **collector** (`agenteye-collector`). Il CLI comunica con il tuo **dashboard**; il collector invia gli eventi al server. Vedi [Collector Installation](/it/agenteye/collector-installation) per il collector. + +--- + +## Installazione + +Il CLI è pubblicato su PyPI pubblico come **`agenteye`**. Poiché l'SDK Python di AgentEye utilizza anch'esso il nome di distribuzione `agenteye`, installa il CLI in un ambiente **isolato** (`pipx` o `uv tool`) affinché i due non si scontrino mai nello stesso virtualenv: + +```bash +pipx install agenteye +# oppure +uv tool install agenteye +``` + +Un semplice `pip install agenteye` funziona anche se non stai installando l'SDK Python nello stesso ambiente. Il CLI richiede Python 3.10+ e non ha bisogno di alcun token GitHub; è un pacchetto pubblico. + +Il comando installato è **`agenteye`**: + +```bash +agenteye --version +agenteye --help +``` + +--- + +## Autenticazione + +Il CLI si autentica al **dashboard** con un codice una tantum inviato per email: + +```bash +agenteye login --email you@example.com +# Un codice di 6 cifre ti viene inviato per email; incollalo al prompt. +``` + +Il token di sessione è memorizzato in `~/.agenteye/cli.json` (leggibile solo da te, modo `0600`) ed è valido per 24 ore per impostazione predefinita. Quando scade, esegui di nuovo `agenteye login`. + +```bash +agenteye whoami # mostra l'utente corrente, l'org attiva e i permessi +agenteye logout # revoca la sessione e cancella il token memorizzato +``` + +`whoami` non genera mai errori su una sessione mancante o scaduta — invece riporta `logged_in: false`, così uno script o un agente può controllare lo stato dell'autenticazione in sicurezza (può comunque uscire con codice non zero se l'URL di base non è impostato o il dashboard non è raggiungibile). + +**Requisiti:** la tua email deve essere autorizzata ad accedere al dashboard (chiedi al tuo amministratore di AgentEye), e il dashboard deve essere raggiungibile al suo URL di base (vedi [Configuration](#configuration)). Se richiedi un codice e non arriva, è probabile che la tua email non sia ancora abilitata per l'accesso al dashboard. + +--- + +## Scelta della tua org (multi-tenant) + +Se il tuo account appartiene a più di un'org, scegli quella attiva **al login** — viene salvata e utilizzata per ogni comando successivo: + +```bash +agenteye login --org acme # autentica e imposta il tenant attivo in un unico passaggio +agenteye orgs list # le org a cui puoi accedere (quella attiva è marcata) +agenteye orgs switch globex # cambia il valore predefinito salvato +agenteye --org globex sessions # sovrascrivi per un singolo comando +``` + +Se appartieni a esattamente un'org verrà selezionata automaticamente e puoi ignorare completamente `--org`. Se appartieni a diversi e non ne scegli uno, il CLI li elenca e ti chiede di rieseguire con `--org `. L'org attiva viene inviata al dashboard su ogni richiesta, e i tuoi permessi vengono risolti **per org** — `agenteye whoami` mostra l'org attiva, i tuoi permessi in essa, e tutti i tuoi abbonamenti. + +--- + +## Configurazione + +| Impostazione | Flag | Variabile d'ambiente | Predefinito | +|---|---|---|---| +| URL base del Dashboard | `--base-url` | `AGENTEYE_DASHBOARD_URL` | **obbligatorio** (nessun valore predefinito) | +| Org/tenant attiva | `--org` | `AGENTEYE_ORG` | scelta al login; salvata in `~/.agenteye/cli.json` | +| Token di sessione | `--token` | `AGENTEYE_CLI_TOKEN` | da `~/.agenteye/cli.json` | +| Output JSON | `--json` | `AGENTEYE_CLI_JSON` | spento | +| Salta verifica TLS | `--insecure` / `--secure` | `AGENTEYE_INSECURE` | spento (salvato al login) | +| Timeout richiesta (secondi) | `--timeout` | — | 30 | +| Disabilita telemetria di utilizzo | _(nessuno)_ | `AGENTEYE_ANALYTICS_DISABLED` (o `DO_NOT_TRACK`) | spento (telemetria attiva) | + +L'ordine di risoluzione è **flag → variabile d'ambiente → file di configurazione**. Non c'è un valore predefinito; devi puntare il CLI al tuo dashboard, sia per comando (`--base-url https://agenteye.example.com`) che una volta tramite l'ambiente (viene salvato anche dopo il tuo primo `login`): + +```bash +export AGENTEYE_DASHBOARD_URL=https://agenteye.example.com +``` + +La directory di configurazione rispetta `AGENTEYE_HOME` (la stessa convenzione utilizzata dall'SDK e dal collector); se impostata, `cli.json` si trova in `$AGENTEYE_HOME/cli.json`. + +### TLS auto-firmato o interno + +Se il tuo dashboard viene servito su HTTPS con un certificato auto-firmato o interno (ad esempio, un nome host del load-balancer grezzo), la verifica TLS lo rifiuta con un errore `CERTIFICATE_VERIFY_FAILED`. Passa `--insecure` per saltare la verifica del certificato: + +```bash +agenteye --base-url https://agenteye.internal --insecure login +``` + +`--insecure` è **salvato in `cli.json` quando esegui il login**, così i comandi successivi saltano la verifica automaticamente; non devi ripetere il flag. Passa `--secure` per una chiamata verificata una tantum, o per salvare di nuovo la verifica al tuo prossimo login. Il CLI stampa un avviso su stderr prima di qualsiasi comando che contatta il dashboard mentre la verifica è disabilitata. Saltare la verifica rimuove la protezione contro gli attacchi man-in-the-middle; assicurati di fidarti del percorso di rete verso il tuo dashboard (VPN, subnet privata, ecc.) prima di fare affidamento su di esso. + +--- + +## Telemetria e privacy + +Il CLI invia **analitiche di utilizzo anonime** al servizio di analitiche di Exosphere (PostHog): quali comandi vengono eseguiti (ad esempio `sessions`, `keys create`), se hanno avuto successo e quanto tempo hanno impiegato. Questo segnale di utilizzo informa la priorità di quali funzionalità. + +- **Nessun dato di agente, sessione o evento esce mai dalla tua infrastruttura.** Solo l'utilizzo del CLI viene segnalato: il nome del comando e del subcommando (ad esempio `keys create`), i **nomi** dei flag che hai usato (mai i loro valori), stato di successo/uscita e durata — più un evento per azione per le mutazioni (ad esempio `api_key_created`, `query_run`) che portano solo nomi/enum statici e conteggi approssimativi. L'URL del tuo dashboard, il token di sessione, l'email, lo slug dell'org, gli id delle risorse, il SQL, i segreti delle chiavi e i filtri delle query **non vengono mai** inviati. Gli operatori sono identificati solo da un id interno opaco, mai per email. +- La telemetria è **abilitata per impostazione predefinita**. Per disattivarla, imposta `AGENTEYE_ANALYTICS_DISABLED=1` nell'ambiente del CLI (il CLI rispetta anche la convenzione cross-tool `DO_NOT_TRACK=1`). +- Il CLI invia direttamente a PostHog (`https://us.i.posthog.com`). La **macchina che esegue il CLI** ha bisogno di accesso in uscita a quell'host; se è bloccato, la telemetria non fa silenziosamente nulla (l'invio è limitato nel tempo quindi non ritarda mai o rompe un comando) e il CLI non è influenzato. + +--- + +## Opzioni globali e convenzioni + +Leggi questo una volta; si applica a ogni comando. + +- **Le opzioni globali vanno PRIMA del comando.** `agenteye --json sessions` è corretto; `agenteye sessions --json` è un errore di utilizzo. I globali sono `--json`, `--base-url`, `--org`, `--token`, `--insecure`/`--secure`, `--timeout`, `--quiet` e `--no-color`. +- **`--json` stampa JSON puro su stdout, e nient'altro.** Le linee di stato umane, gli avvisi e gli errori vanno su **stderr**, così una cattura di stdout di `--json` rimane pulita per il piping in `jq` anche quando viene mostrata una linea di stato. Senza `--json` ottieni una vista boxed e colorizzata per gli occhi umani. +- **Scopri con `--help`.** Ogni comando e subcommando ha `--help` (e l'alias `-h`): `agenteye -h`, `agenteye sessions -h`, `agenteye keys create -h`. L'aiuto di primo livello elenca anche i codici di uscita e le opzioni globali. Non c'è un dump di superficie leggibile da macchina globale; usa `--help` per comando, più i domini specifici `agenteye query schema` e `agenteye settings schema` per questi due registri. +- **Le conferme si saltano automaticamente per script e agenti.** I comandi create/update/delete chiedono conferma "sei sicuro?" in un terminale interattivo, ma **saltano automaticamente il prompt sotto `--json` o ogni volta che stdin non è un TTY** — così script e agenti non si bloccano mai. Passa `--yes`/`-y` per saltarlo esplicitamente. Poiché il prompt non si attiverà per un agente, un agente dovrebbe confermare le azioni distruttive con l'umano per primo. +- **Impaginazione:** i risultati sono i più recenti per primi e cursore-impaginati. `--limit N` (alias `-n`) limita le righe ed **è predefinito a 50**; `--all` impagina automaticamente (in chunk di 200 righe) **fino a `--limit`** — quindi un `--all` nudo si ferma comunque a 50. Per una scansione completa passa un limite esplicito alto: `--all --limit 1000`. `--page-size N` controlla lo chunk per richiesta (massimo 200); `--cursor ` riprende dalla pagina precedente `next_cursor`. +- **Filtri temporali:** `--since` prende una finestra relativa — `15m`, `1h`, `6h`, `24h`, `7d`, `30d` o `all` (i preset del dashboard). `--from`/`--to` accettano timestamp UTC espliciti in formato ISO-8601 **con `T` e un fuso orario** (ad esempio `2026-06-01T00:00:00Z`) per un intervallo personalizzato e sovrascrivono `--since`; un valore separato da spazio o senza fuso orario è un errore di utilizzo. +- **`--fields a,b,c`** (su `events`, `sessions`, `evals`, `errors`) limita l'output a quelle chiavi, sia per la tabella che per `--json`. I nomi sconosciuti vengono rifiutati con l'elenco valido — un modo economico per scoprire i nomi dei campi. +- **`--file payload.json`** (o `--file -` per leggere stdin) fornisce un corpo di richiesta JSON completo dove una risorsa ha una forma complessa — su `alerts create/update`, `settings set` e `users create/update`. Il SQL della query salvata usa `--sql @file.sql` invece. +- **I filtri multi-valore** sono separati da virgola → abbinati come set (unione all'interno di un filtro, AND su filtri): `--event-type tool_use,tool_result`. Le opzioni click non sono variadiche, quindi `--add a b` si interrompe — usa `--add a,b`, ripeti il flag (`--add a --add b`) o racchiudi tra virgolette (`--add "a b"`). + +--- + +## Riferimento comandi + +Il CLI ha **18 comandi di primo livello**. Tutti i comandi di lettura accettano `--json` e le opzioni globali sopra; esegui `agenteye -h` (o ` -h`) per l'elenco completo di flag e la forma JSON di uno qualsiasi. + +### Identità — `login` · `logout` · `whoami` · `orgs` · `version` · `help` + +```bash +agenteye login --email you@example.com [--org acme] # codice una tantum inviato per email; salva la sessione +agenteye logout # cancella la sessione salvata su questa macchina +agenteye whoami # utente corrente, org attiva, permessi +agenteye version # stampa la versione del CLI (come --version) +agenteye help # aiuto di primo livello (come --help) +``` + +`orgs` ispeziona e commuta il tenant attivo: + +```bash +agenteye orgs list # le tue org + il tuo ruolo in ognuna (quella attiva marcata) +agenteye orgs switch acme # cambia l'org attiva salvata (ometti lo slug per scegliere da un elenco su un TTY) +agenteye orgs current # carta d'identità per l'org attiva +agenteye orgs perms # i tuoi permessi nell'org attiva, raggruppati per risorsa +``` + +### Osserva (sola lettura) — `events` · `sessions` · `evals` · `errors` · `list` + +Nessuno di questi richiede una conferma. Filtri condivisi: `--session-id`, `--agent-id`, `--env` (**non** `--environment`) e l'intervallo temporale (`--since` / `--from` / `--to`). + +```bash +# events (alias: la traccia per-step grezza) — i più recenti per primi +agenteye --json events --session-id run-001 --event-type tool_use,tool_result --all --limit 1000 +agenteye --json events --since 1h --search timeout --all | jq '.events[].payload' + +# sessions — una riga per esecuzione dell'agente (ora/env/agente/sessione/stato; nessun filtro di score) +agenteye --json sessions --since 24h --status error +agenteye --json sessions --agent-id checkout-bot --env prod --all --limit 1000 + +# evals — risultati di valutazione + score; --score filtra per metrica, --aggregate aggrega +agenteye --json evals --score helpfulness:0.5..0.8 --score tool_efficiency:..0.3 +agenteye --json evals --aggregate --since 7d --env prod # mix di stato + statistiche di score per chiave + +# errors — eventi con errore; --aggregate per conteggi/sessioni/agenti/ultimo-visto +agenteye --json errors --since 24h --aggregate +agenteye --json errors --since 24h --error-type timeout --all --limit 1000 + +# list — scopri i valori di filtro validi prima di filtrare +agenteye list envs # anche: agents event_types score_filters models hooks triggers tools error_types +``` + +`--score KEY:MIN..MAX` (su **`evals`**, non `sessions`) è ripetibile e AND-combinato; uno qualsiasi dei limiti è opzionale (`..0.5` significa ≤ 0.5, `0.9..` significa ≥ 0.9). Fino a 20 filtri di score per richiesta. `evals --scores-full` restituisce l'oggetto score completo anziché il riepilogo. Per leggere **una sessione da capo a fondo**, combina la traccia di evento con la sua valutazione: + +```bash +agenteye --json events --session-id run-001 --all --limit 1000 | jq '.events[] | {ts, event_type}' +agenteye --json evals --session-id run-001 # i suoi score + stato +``` + +### Gestisci (limitato da permessi) — `keys` · `users` · `settings` · `alerts` · `incidents` + +**`keys`** — Chiavi API. Il segreto viene generato localmente, inviato al server (che memorizza solo un hash) e **mostrato una sola volta** su create/regenerate — catturalo allora. Con `--json` appare solo nel campo `key`. Referenziato per **nome**. + +```bash +agenteye keys list # chiavi attive per prime, poi revocate +agenteye keys show ci-bot +agenteye keys create ci-bot --add events:read.add # limita a quello di cui hai bisogno; stampa il segreto UNA SOLA VOLTA +agenteye keys create ops --permission-set standard --remove queries:run # semina un preset, poi riduci +agenteye keys update ci-bot --add evaluations:read --yes +agenteye keys regenerate ci-bot --yes # ruota il segreto (quello vecchio smette di funzionare) +agenteye keys disable ci-bot --yes # revoca +``` + +I permessi funzionano come `(permission-set ∪ --add) − --remove`. I token sono `slug:action` (ad esempio `events:read`) o `slug:action.action` per espanderne diversi su una risorsa (`events:read.add` → `events:read`, `events:add`). Preset: `read-only`, `standard`, `admin`. I permessi solo per umani (`keys:update`) non possono essere concessi a una chiave. + +**`users`** — Membri dell'org, referenziati per **email** (è accettato anche un id UUID). + +```bash +agenteye users list [--active-only] +agenteye users show dev@corp.com +agenteye users create dev@corp.com --permission-set standard +agenteye users update dev@corp.com --add alerts:write --remove queries:delete # prevede + conferma +agenteye users disable dev@corp.com --yes # ha protezioni/guardie di auto +agenteye users enable dev@corp.com +``` + +**`settings`** — Un registro fisso (leggi e cambia le chiavi esistenti; non puoi crearne di nuove). + +```bash +agenteye settings list # chiave · valore · tipo · aggiornato (segreti mascherati) +agenteye settings schema # cosa accetta ogni chiave (tipo · intervallo · descrizione) +agenteye settings set session_ttl_secs --value 86400 --yes +``` + +**`alerts`** — Definizioni di avviso, referenziate per **nome**. `create` accetta un NAME posizionale più flag o un corpo JSON completo tramite `--file`. + +```bash +agenteye alerts list +agenteye alerts show high-errors +agenteye alerts create high-errors --file alert.json # NAME è obbligatorio (posizionale) +agenteye alerts update high-errors --severity critical --yes +agenteye alerts test high-errors --yes # attiva una notifica di test +agenteye alerts delete high-errors --yes +``` + +**`incidents`** — Incidenti di avviso, referenziati per id (gli id brevi sono accettati). `show` stampa il log di attività completo — leggilo prima di agire. + +```bash +agenteye incidents list --state firing # anche: acknowledged, resolved +agenteye incidents count +agenteye incidents show +agenteye incidents ack +agenteye incidents assign you@corp.com # l'assegnatario deve essere un operatore +agenteye incidents resolve --yes +agenteye incidents open --alert-id --severity critical # apri uno manualmente contro un avviso +agenteye incidents comment-add "root cause: upstream 5xx" +agenteye incidents comment-list ; agenteye incidents comment-delete +agenteye incidents subscribe ; agenteye incidents unsubscribe ; agenteye incidents subscribers +``` + +### Analitiche e assistente — `query` · `agent` + +**`query`** — SQL ClickHouse salvato più un runner ad hoc. Le query salvate sono referenziate per **nome**; il SQL viene validato lato server (SELECT/WITH solo, timeout dell'istruzione, limite di riga). + +```bash +agenteye query schema [TABLE] # layout di colonna delle viste di analitiche +agenteye query run --sql "select count(*) from analytics.events" +agenteye query run errs --arg prod --limit 100 # esegui una query salvata + un $1 posizionale +agenteye query list ; agenteye query show errs +agenteye query create errs --sql @errs.sql --description "errored events (24h)" +agenteye query update errs --sql @errs.sql --yes ; agenteye query delete errs --yes +``` + +**`agent`** — L'assistente dashboard integrato (lo stesso analista di sola lettura con cui puoi chattare nel dashboard). Le chat sono referenziate da un breve chat-id (prefix-risolto). + +```bash +agenteye agent health # l'assistente è configurato/raggiungibile +agenteye agent models # i modelli che puoi passare a --model (predefinito marcato) +agenteye agent ask "which agents errored most in the last day?" # avvia una chat; stampa il suo breve id +agenteye agent ask --chat "and which tools did they call?" # continua quella chat +agenteye agent chats ; agenteye agent show +agenteye agent rename --title "error triage" ; agenteye agent delete +``` + +--- + +## Codici di uscita + +| Codice | Significato | +|---|---| +| 0 | Successo | +| 1 | Errore inaspettato (ad esempio il dashboard ha restituito un 5xx) | +| 2 | Errore di utilizzo (argomenti non validi, comando/flag sconosciuto, collisione di nome) | +| 3 | Impossibile raggiungere il dashboard | +| 4 | Non loggato o sessione scaduta; esegui `agenteye login` | +| 5 | Autenticato, ma il tuo account manca del permesso richiesto (il messaggio lo nomina) | +| 6 | La risorsa richiesta non è stata trovata (ad esempio id di sessione o incidente sconosciuto) | + +Questi rendono il CLI sicuro per lo scripting: un agente di codifica può fare un branch su un `4` per chiederti di riauthenticarti, o su un `5` per esporre il permesso mancante. Vedi [CLI recipes for agents](/it/agenteye/cli-recipes) per i pattern di gestione dei codici di uscita e le forme di output JSON. + +--- + +## Vedi anche + +- **[CLI recipes for agents](/it/agenteye/cli-recipes)** — pattern di query copia-incolla, one-liner `jq`, proiezioni `--fields`, gestione dei codici di uscita e forme di output JSON, scritti per agenti di codifica che guidano il CLI. +- **[AgentEye CLI skill](/it/agenteye/cli-skill)** — pacchetto questo CLI come una *skill* installabile Claude Code / Codex così un agente di codifica guida AgentEye da richieste in linguaggio naturale. +- **[API Keys](/it/agenteye/api-keys)** — il modello di permesso dietro `keys create --add …`. +- **[AI Assistant](/it/agenteye/assistant)** — abilitare l'assistente con cui `agent ask` comunica. \ No newline at end of file diff --git a/docs/it/agenteye/collector-installation.mdx b/docs/it/agenteye/collector-installation.mdx new file mode 100644 index 00000000..965506da --- /dev/null +++ b/docs/it/agenteye/collector-installation.mdx @@ -0,0 +1,401 @@ +--- +title: "Installazione del Collector" +description: "Documentazione sull'installazione di AgentEye Collector." +--- + + +Il daemon `agenteye-collector` garantisce che la telemetria dei tuoi agenti raggiunga AgentEye senza mai bloccare la tua applicazione. Il tuo codice scrive gli eventi in una directory locale e continua; il collector prende in carico da lì, caricando ogni file in pochi millisecondi e sopravvivendo a riavvii, interruzioni di rete e errori transitori del server. I caricamenti falliti vengono ritentati con backoff esponenziale, e una scansione di recupero periodica rimette in coda tutto ciò che è stato lasciato da un crash o da un deploy. Il risultato è una consegna duratura, fire-and-forget: i tuoi agenti continuano a funzionare a piena velocità mentre il collector assicura che nessun evento vada perso durante il transito. + +Meccanicamente, il collector è un daemon leggero che osserva `$AGENTEYE_HOME/events/` (predefinito: `~/.agenteye/events/`) per i file `.jsonl` scritti dall'SDK Python e li carica sul server AgentEye. + +> **Rinominato:** il comando del collector è ora **`agenteye-collector`** (in precedenza era `agenteye`). Il nome breve `agenteye` appartiene ora alla CLI di AgentEye. Se stai aggiornando un'installazione esistente, vedi [enterprise-docs/collector-migration.md](/it/agenteye/collector-migration). + +--- + +## Prerequisiti + +- Il tuo `AGENTEYE_TOKEN`: un GitHub PAT che generi tu stesso (vedi [enterprise-docs/github-token.md](/it/agenteye/github-token)) +- L'URL del server e una chiave API del collector (vedi [enterprise-docs/api-keys.md](/it/agenteye/api-keys)) + +--- + +## Opzione A: Binary (consigliato) + +I binari statici precompilati sono disponibili per Linux, macOS e Windows (x86_64 e arm64). Scarica il binario per la tua piattaforma direttamente dal repository `agenteye-enterprise/releases` sotto il tag di rilascio `collector/v` più recente. + +Nomi artefatti disponibili: + +| Piattaforma | Artefatto | +|---|---| +| Linux x86_64 | `agenteye-collector-linux-x86_64` | +| Linux arm64 | `agenteye-collector-linux-arm64` | +| macOS x86_64 | `agenteye-collector-darwin-x86_64` | +| macOS arm64 | `agenteye-collector-darwin-arm64` | +| Windows x86_64 | `agenteye-collector-windows-x86_64.exe` | +| Windows arm64 | `agenteye-collector-windows-arm64.exe` | + +**Scarica con la CLI `gh`** (sostituisci la versione e scegli l'artefatto della tua piattaforma): + +```bash +VERSION=0.0.1-beta.13 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "collector/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-collector-linux-x86_64' + +chmod +x agenteye-collector-linux-x86_64 +sudo mv agenteye-collector-linux-x86_64 /usr/local/bin/agenteye-collector +``` + +**O con `curl`:** + +```bash +VERSION=0.0.1-beta.13 +ARTIFACT=agenteye-collector-linux-x86_64 +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + -L "https://github.com/agenteye-enterprise/releases/releases/download/collector%2Fv${VERSION}/${ARTIFACT}" \ + -o agenteye-collector +chmod +x agenteye-collector +sudo mv agenteye-collector /usr/local/bin/agenteye-collector +``` + +--- + +## Opzione B: Docker + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +docker pull ghcr.io/agenteye-enterprise/collector:beta-latest +``` + +> I build beta attuali pubblicano il tag mobile `:beta-latest`; `:latest` viene assegnato solo ai rilasci stabili. Per deploy ripetibili, preferisci un tag di versione fissato come `:v0.0.1-beta.13`. + +**Esegui:** + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-collector \ + -e AGENTEYE_URL=https://ingest.example.com/events \ + -e AGENTEYE_KEY="$AGENTEYE_KEY" \ + -e AGENTEYE_HOME=/data \ + -v "$HOME/.agenteye:/data" \ + ghcr.io/agenteye-enterprise/collector:beta-latest \ + start +``` + +L'immagine ufficiale viene eseguita come utente non root, quindi imposta `AGENTEYE_HOME` esplicitamente e monta lo spool dell'host su di esso. Il mount del volume condivide la stessa directory `~/.agenteye/` in cui l'SDK Python scrive sull'host. Se hai già impostato `AGENTEYE_HOME` altrove sull'host, monta quella directory invece di `$HOME/.agenteye`. + +--- + +## Configurazione + +Tutte le opzioni possono essere impostate in tre modi (priorità più alta per prima): + +1. Flag CLI: `agenteye-collector start --url https://...` +2. Variabile di ambiente: `AGENTEYE_URL=https://...` +3. File di configurazione: `~/.agenteye/config.json` + +### Opzioni obbligatorie + +| Opzione | Flag CLI | Variabile di ambiente | Chiave config.json | +|---|---|---|---| +| URL Backend | `--url ` | `AGENTEYE_URL` | `"url"` | +| Chiave API | `--key ` | `AGENTEYE_KEY` | `"key"` | + +### Opzioni facoltative (con valori predefiniti) + +| Opzione | Flag CLI | Variabile di ambiente | Chiave config.json | Predefinito | +|---|---|---|---|---| +| Caricamenti simultanei massimi | `--max-concurrent-uploads ` | `AGENTEYE_MAX_CONCURRENT_UPLOADS` | `"max_concurrent_uploads"` | `64` | +| Intervallo sweeper (s) | `--sweep-interval ` | `AGENTEYE_SWEEP_INTERVAL` | `"sweep_interval_secs"` | `60` | +| Età minima file sweeper (s) | `--sweep-min-age ` | `AGENTEYE_SWEEP_MIN_AGE` | `"sweep_min_age_secs"` | `120` | +| File massimi per sweep | `--sweep-max-files ` | `AGENTEYE_SWEEP_MAX_FILES` | `"sweep_max_files"` | `64` | +| Tentativi di caricamento massimi | `--max-retries ` | `AGENTEYE_MAX_RETRIES` | `"max_retries"` | `5` | +| Ritardo base dei retry (ms) | `--retry-base-delay ` | `AGENTEYE_RETRY_BASE_DELAY` | `"retry_base_delay_ms"` | `1000` | + +### Opzioni mTLS (facoltative) + +Per i deploy che richiedono TLS reciproco (mTLS), il collector può presentare un certificato client durante l'handshake TLS. Quando queste opzioni non sono impostate, il collector utilizza HTTPS standard. + +| Opzione | Flag CLI | Variabile di ambiente | Chiave config.json | +|---|---|---|---| +| Certificato client (PEM) | `--tls-cert ` | `AGENTEYE_TLS_CERT` | `"tls_cert"` | +| Chiave privata client (PEM) | `--tls-key ` | `AGENTEYE_TLS_KEY` | `"tls_key"` | +| Certificato CA personalizzato (PEM) | `--tls-ca ` | `AGENTEYE_TLS_CA` | `"tls_ca"` | + +`--tls-cert` e `--tls-key` devono essere impostati insieme. I file devono essere codificati in PEM. + +`--tls-ca` è indipendente e necessario solo quando il server AgentEye presenta un certificato TLS che non è stato emesso da un'autorità di certificazione pubblicamente affidabile (ad es. autofirmato da un issuer `cert-manager` in-cluster quando non hai un vero dominio DNS). Il collector aggiunge il CA fornito come ancoraggio di trust aggiuntivo; le radici pubbliche standard rimangono fidate, quindi i deploy esistenti non sono interessati. Il file può contenere un singolo certificato PEM o una catena completa (più blocchi PEM concatenati). + +**Esegui il collector come sidecar nel pod della tua applicazione?** Vedi [enterprise-docs/single-pod-deployment.md](/it/agenteye/single-pod-deployment) per il pattern EKS end-to-end: bundle mTLS consegnato tramite AWS Secrets Manager + Secrets Store CSI Driver + IRSA, con rotazione automatica. + +Quando esegui in Kubernetes con il pattern di handoff del Secret, monta il Secret del certificato come volume e punta questi percorsi ai file montati: + +```yaml +# Esempio: frammento deployment del collector +volumes: + - name: mtls-certs + secret: + secretName: agenteye-collector-mtls +containers: + - name: collector + env: + - name: AGENTEYE_TLS_CERT + value: /etc/agenteye/tls/tls.crt + - name: AGENTEYE_TLS_KEY + value: /etc/agenteye/tls/tls.key + # Solo quando il certificato del server non è pubblicamente affidabile (ad es. CA + # autofirmato in-cluster). Lo stesso Secret generalmente porta ca.crt accanto + # a tls.crt/tls.key. + - name: AGENTEYE_TLS_CA + value: /etc/agenteye/tls/ca.crt + volumeMounts: + - name: mtls-certs + mountPath: /etc/agenteye/tls + readOnly: true +``` + +### Esempio `~/.agenteye/config.json` + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "max_concurrent_uploads": 16, + "sweep_interval_secs": 30 +} +``` + +Con mTLS: + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "tls_cert": "/etc/agenteye/tls/tls.crt", + "tls_key": "/etc/agenteye/tls/tls.key" +} +``` + +Con mTLS più un CA personalizzato (server AgentEye autofirmato): + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "tls_cert": "/etc/agenteye/tls/tls.crt", + "tls_key": "/etc/agenteye/tls/tls.key", + "tls_ca": "/etc/agenteye/tls/ca.crt" +} +``` + +Se `AGENTEYE_HOME` è impostato, quella directory viene utilizzata al posto di `~/.agenteye`. + +--- + +## Configurazione iniziale + +Dopo l'installazione, configura il collector con l'URL del server e la chiave API: + +```bash +mkdir -p ~/.agenteye +cat > ~/.agenteye/config.json <<'EOF' +{ + "url": "https://ingest.example.com/events", + "key": "YOUR_COLLECTOR_KEY" +} +EOF +``` + +> Usa `https` per qualsiasi deploy che attraversi una rete non affidabile in modo che gli eventi non vengano inviati in testo semplice. La forma `http://your-server-host:8080/events` in testo semplice è appropriata solo per test puramente locali contro un server sullo stesso host. + +**Prova la connessione** (flush singolo, esce dopo lo scarico degli eventi in sospeso): + +```bash +agenteye-collector flush +``` + +`flush` segnala il suo avanzamento a stdout. Quando lo spool è vuoto stampa `No pending files.` ed esce con `0`. Altrimenti stampa una riga per file (`[UPLOADED] ` o `[FAILED] ()`), seguita da un riepilogo `Done: / uploaded, failed.`. Questo rende `flush` una comoda verifica singola per verificare che l'URL, la chiave e le impostazioni TLS siano corretti prima di avviare il daemon. + +--- + +## Esecuzione come Daemon + +### Diretto + +```bash +agenteye-collector start +``` + +### Container / Docker + +Quando il collector e la tua applicazione condividono un container, eseguili sotto un supervisore di processi. L'opzione più semplice è `supervisord`; viene fornito in ogni distro principale, riavvia i processi in crash, inoltri i segnali e attende l'arresto corretto. + +**`Dockerfile`:** + +```Dockerfile +FROM python:3.11-slim + +RUN apt-get update && apt-get install -y --no-install-recommends supervisor \ + && rm -rf /var/lib/apt/lists/* + +# Estrai il binario agenteye-collector dall'immagine ufficiale. +# Fissa un tag specifico (:beta-latest per i beta attuali, o un tag :v); +# :latest viene pubblicato solo per i rilasci stabili. +COPY --from=ghcr.io/agenteye-enterprise/collector:beta-latest \ + /usr/local/bin/agenteye-collector /usr/local/bin/agenteye-collector + +COPY supervisord.conf /etc/supervisor/conf.d/agenteye.conf +COPY my_agent.py /app/my_agent.py + +CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"] +``` + +**`supervisord.conf`:** + +```ini +[supervisord] +nodaemon=true +user=root + +[program:agenteye-collector] +command=/usr/local/bin/agenteye-collector start +autorestart=true +stopwaitsecs=30 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:app] +command=python /app/my_agent.py +autorestart=unexpected +stopwaitsecs=30 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +``` + +Perché queste impostazioni: + +- `autorestart=true` su agenteye-collector: riavvia su qualsiasi uscita (crash, panic, OOM). +- `autorestart=unexpected` sull'app: riavvia solo su uscita non zero, quindi un agente singolo che esce 0 non entra in loop. +- `stopwaitsecs=30`: dà al collector spazio per drenare i caricamenti in sospeso su SIGTERM prima che supervisord passi a SIGKILL. +- `stdout_logfile=/dev/stdout`, `*_maxbytes=0`: flussi dell'output di entrambi i programmi allo stdout del container; nessun file di log dentro il container. + +Passa `AGENTEYE_URL` / `AGENTEYE_KEY` (e qualsiasi variabile di ambiente TLS) su `docker run -e` come prima; supervisord eredita l'ambiente. + +> **Container separati?** Se esegui il collector come suo proprio container (servizio Docker Compose, sidecar Kubernetes, ecc.), non usare supervisord; la politica di riavvio del runtime del container già fa questo lavoro. Vedi [enterprise-docs/single-pod-deployment.md](/it/agenteye/single-pod-deployment) per il pattern sidecar EKS. + +**Sonda di liveness Kubernetes** (si applica sia che il collector venga eseguito da solo che sotto supervisord): + +```yaml +livenessProbe: + exec: + command: ["agenteye-collector", "health"] + initialDelaySeconds: 10 + periodSeconds: 30 +``` + +Il daemon in esecuzione scrive un heartbeat a `$AGENTEYE_HOME/health.json` ogni 30 secondi. `agenteye-collector health` legge quel file ed esce con `0` (sano) solo quando l'heartbeat è fresco e i compiti di caricamento sono in esecuzione normalmente; esce con `1` (non sano) quando l'heartbeat è più vecchio di 90 secondi (ad esempio, il daemon si è fermato) o mentre il watcher e lo sweeper si stanno riavviando dopo un'uscita inaspettata. L'heartbeat viene scritto solo da `start`, quindi esegui la sonda contro il daemon longevo piuttosto che il comando `flush` singolo. + +### systemd (Linux, consigliato per la produzione) + +```ini +# /etc/systemd/system/agenteye-collector.service +[Unit] +Description=AgentEye Collector +After=network.target + +[Service] +ExecStart=/usr/local/bin/agenteye-collector start +Restart=on-failure +RestartSec=5 +EnvironmentFile=/etc/agenteye/env + +[Install] +WantedBy=multi-user.target +``` + +Crea `/etc/agenteye/env`: + +``` +AGENTEYE_URL=https://ingest.example.com/events +AGENTEYE_KEY=YOUR_COLLECTOR_KEY +``` + +```bash +sudo systemctl daemon-reload +sudo systemctl enable --now agenteye-collector +sudo systemctl status agenteye-collector +``` + +### launchd (macOS) + +```xml + + + + + + Label + ai.befailproof.agenteye-collector + ProgramArguments + + /usr/local/bin/agenteye-collector + start + + EnvironmentVariables + + AGENTEYE_URL + https://ingest.example.com/events + AGENTEYE_KEY + YOUR_COLLECTOR_KEY + + RunAtLoad + + KeepAlive + + + +``` + +```bash +launchctl load ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +``` + +--- + +## Aggiornamento del Collector + +Il collector non si aggiorna automaticamente. Per aggiornare: + +- **Binary:** scarica il nuovo artefatto `agenteye-collector--` dal rilascio `collector/v` più recente (vedi [Opzione A](#option-a-binary-recommended)), sostituisci `/usr/local/bin/agenteye-collector`, quindi riavvia il servizio (`sudo systemctl restart agenteye-collector`, ri-`launchctl load`, o riavvia il tuo supervisore). +- **Docker:** `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (o un tag `:v` fissato; `:latest` esiste solo per i rilasci stabili) e ricrea il container. + +`AGENTEYE_TOKEN` è richiesto per scaricare nuovi binari/immagini dal repository privato dei rilasci, ma **non** è necessario per il daemon in esecuzione. + +--- + +## Sottocomandi + +| Comando | Descrizione | +|---|---| +| `agenteye-collector start` | Avvia il daemon longevo. All'avvio, scarica tutti gli eventi rimasti da un'esecuzione precedente, quindi osserva i nuovi file e li carica. Il watcher e lo sweeper si riavviano automaticamente su uscita inaspettata, e un heartbeat viene scritto a `health.json` ogni 30 secondi. | +| `agenteye-collector flush` | Singolo: carica tutti i file in sospeso ed esce. Stampa `No pending files.` quando lo spool è vuoto, altrimenti un log per file `[UPLOADED]`/`[FAILED]` e un riepilogo `Done: / uploaded, failed.`. | +| `agenteye-collector health` | Leggi l'heartbeat `health.json` del daemon. Esce con `0` quando è fresco e sano; esce con `1` quando l'heartbeat è stantio (più vecchio di 90 secondi) o i compiti si stanno riavviando. | + +--- + +## Struttura delle Directory + +``` +~/.agenteye/ +├── config.json <- file di configurazione facoltativo +├── events/ <- file .jsonl scritti dall'SDK, prelevati dal collector +└── failed/ <- file che hanno fallito tutti i tentativi di caricamento +``` + +I file in `failed/` non vengono ritentati automaticamente. Per metterli di nuovo in coda manualmente, spostali nuovamente in `events/` ed esegui `agenteye-collector flush`. \ No newline at end of file diff --git a/docs/it/agenteye/collector-migration.mdx b/docs/it/agenteye/collector-migration.mdx new file mode 100644 index 00000000..2f57059e --- /dev/null +++ b/docs/it/agenteye/collector-migration.mdx @@ -0,0 +1,169 @@ +--- +title: "Migrazione a `agenteye-collector`" +description: "Documentazione di AgentEye per la migrazione a `agenteye-collector`." +--- + + +La migrazione è non-distruttiva: non comporta downtime e non comporta perdita di dati, e libera il breve nome `agenteye` per la [CLI AgentEye](/it/agenteye/cli) in modo che il daemon collector e la CLI possono coesistere sulla stessa macchina. + +Il binario del collector è stato **rinominato da `agenteye` a `agenteye-collector`**. Il breve nome `agenteye` ora appartiene alla CLI AgentEye, uno strumento separato per interrogare sessioni, eventi e valutazioni dal tuo terminale. + +Questa guida ti accompagna attraverso la migrazione di un'installazione collector esistente. + +--- + +## Cosa è cambiato + +| | Prima | Dopo | +|---|---|---| +| Comando / binario | `agenteye` | `agenteye-collector` | +| Percorso di installazione predefinito | `/usr/local/bin/agenteye` | `/usr/local/bin/agenteye-collector` | +| Sottocomandi | `start`, `flush`, `health`, `update` | `start`, `flush`, `health` | +| Auto-aggiornamento (`agenteye update`) | integrato | **rimosso**: scarica il nuovo binario o tira la nuova immagine | +| Script di installazione (`install.sh`) | fornito | **rimosso**: scarica il binario direttamente (vedi [Collector Installation](/it/agenteye/collector-installation)) | +| `AGENTEYE_TOKEN` | necessario per scaricare **e** per controlli di aggiornamento in background | necessario solo per **scaricare** binari/immagini | + +La configurazione è invariata: lo stesso `~/.agenteye/config.json`, le stesse variabili d'ambiente `AGENTEYE_URL` / `AGENTEYE_KEY` / `AGENTEYE_HOME` / TLS, e lo stesso spool `~/.agenteye/events/`. **Non sono richieste modifiche di configurazione.** + +> Se esegui il binario rinominato con il vecchio nome `agenteye`, funziona comunque ma stampa un avviso di deprecazione su una riga su stderr ricordandoti di passare a `agenteye-collector`. + +--- + +## Prima di iniziare + +- La tua **installazione `agenteye` esistente continua a funzionare**; nulla si rompe nel momento in cui aggiorni. Esegui la migrazione deliberatamente, poi rimuovi il vecchio binario per ultimo. +- Segui questo ordine per evitare downtime: + 1. Installa il nuovo binario `agenteye-collector` (o tira la nuova immagine). + 2. Aggiorna la tua definizione di servizio / health probe / script per chiamare `agenteye-collector`. + 3. Ricarica e riavvia il servizio; conferma che sia in salute. + 4. **Solo allora** rimuovi il vecchio binario `/usr/local/bin/agenteye`. + +--- + +## 1. Installa il nuovo binario + +Scarica l'artefatto per la tua piattaforma (`agenteye-collector-linux-x86_64`, `agenteye-collector-darwin-arm64`, e così via; vedi [Collector Installation → Option A](/it/agenteye/collector-installation#option-a-binary-recommended) per l'elenco completo) dall'ultima release `collector/v` e posizionalo in `/usr/local/bin/agenteye-collector`. Utenti Docker: `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (o un tag `:v` fisso, che è preferibile; `:latest` esiste solo per release stabili). + +Verifica: + +```bash +agenteye-collector --version +``` + +--- + +## 2. Aggiorna il tuo deployment + +### systemd (Linux) + +Modifica `/etc/systemd/system/agenteye-collector.service` in modo che `ExecStart` punti al nuovo binario: + +```ini +[Service] +ExecStart=/usr/local/bin/agenteye-collector start +``` + +Quindi ricarica e riavvia: + +```bash +sudo systemctl daemon-reload +sudo systemctl restart agenteye-collector +sudo systemctl status agenteye-collector +``` + +### launchd (macOS) + +> **Cambio di marca:** Se il tuo plist esistente si trova nel percorso più vecchio +> `~/Library/LaunchAgents/host.exosphere.agenteye-collector.plist`, rinomina +> il file in `ai.befailproof.agenteye-collector.plist` e cambia anche il +> valore `Label` all'interno del file al nuovo identificatore prima +> di ricaricare. + +In `~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist`, cambia la prima voce `ProgramArguments` da `/usr/local/bin/agenteye` a `/usr/local/bin/agenteye-collector`, quindi ricarica: + +```bash +launchctl unload ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +launchctl load ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +``` + +### supervisord + +Nel tuo blocco programma `supervisord`, imposta `command` al nuovo binario: + +```ini +[program:agenteye-collector] +command=/usr/local/bin/agenteye-collector start +``` + +Quindi `supervisorctl reread && supervisorctl update`. + +### Docker / Kubernetes + +Tira la nuova immagine (`ghcr.io/agenteye-enterprise/collector:beta-latest` o un tag `:v` fisso, che è preferibile; `:latest` esiste solo per release stabili). L'entrypoint dell'immagine è già `agenteye-collector`, quindi lo stesso comando `docker run` con il sottocomando `start` continua a funzionare senza modifiche. + +**Importante: aggiorna gli health probe.** Se usi una probe liveness/readiness di Kubernetes (o qualsiasi `docker exec`) che esegue il binario per nome, cambia il comando in `agenteye-collector`: + +```yaml +livenessProbe: + exec: + command: ["agenteye-collector", "health"] +``` + +La nuova immagine **non** fornisce un alias `agenteye`, quindi una probe che chiama ancora `agenteye` fallirà. Aggiorna la probe nello stesso rollout della nuova immagine. + +### Cron / script manuali + +Sostituisci qualsiasi invocazione `agenteye start|flush|health` con il comando `agenteye-collector start|flush|health` corrispondente. **Elimina qualsiasi cron job `agenteye update`**; quel sottocomando non esiste più (vedi [Upgrades from now on](#upgrades-from-now-on)). + +--- + +## 3. Rimuovi il vecchio binario (per ultimo) + +Una volta che il servizio funziona su `agenteye-collector` e segnala buone condizioni: + +```bash +sudo rm /usr/local/bin/agenteye +``` + +Questo è importante soprattutto se usi anche la CLI AgentEye, che installa il suo proprio comando `agenteye`; lasciare il vecchio binario del collector in `/usr/local/bin/agenteye` renderebbe il nome `agenteye` ambiguo nel tuo `PATH`. + +--- + +## Aggiornamenti da ora in poi + +Il collector non si aggiorna più da solo. Per aggiornare: + +- **Binario:** scarica il nuovo artefatto per la tua piattaforma (ad esempio `agenteye-collector-linux-x86_64`; vedi [Collector Installation → Option A](/it/agenteye/collector-installation#option-a-binary-recommended) per l'elenco completo), sostituisci `/usr/local/bin/agenteye-collector` e riavvia il servizio. +- **Docker:** `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (o un tag `:v` fisso, che è preferibile; `:latest` esiste solo per release stabili) e ricrea il container. + +`AGENTEYE_TOKEN` è ancora necessario per scaricare dal repo delle release private, ma il daemon in esecuzione non ne ha più bisogno. + +--- + +## Verifica + +```bash +agenteye-collector --version # nuovo binario è nel PATH +agenteye-collector health # exit 0 = in salute +agenteye-collector flush # inoltri gli eventi in coda e termina in modo pulito +``` + +Quindi conferma che i nuovi eventi appaiono nel tuo dashboard. + +--- + +## Rollback + +La migrazione è non-distruttiva. Se hai bisogno di eseguire il rollback, fai puntare la tua definizione di servizio di nuovo al vecchio binario `/usr/local/bin/agenteye` (purché non l'abbia ancora rimosso) e riavvia. Lo spool degli eventi e la configurazione sono condivisi e non sono interessati. + +--- + +## Risoluzione dei problemi + +| Sintomo | Causa | Soluzione | +|---|---|---| +| `warning: the collector binary is now agenteye-collector …` ad ogni esecuzione | Stai invocando il binario con il vecchio nome `agenteye` | Chiama `agenteye-collector` invece; aggiorna file di servizio e script. | +| systemd fallisce: `.../agenteye: No such file or directory` | Hai rimosso il vecchio binario prima di aggiornare `ExecStart` | Imposta `ExecStart=/usr/local/bin/agenteye-collector start`, quindi `sudo systemctl daemon-reload`. | +| Il pod Kubernetes va in crash-loop dopo l'aggiornamento dell'immagine | Il probe liveness esegue ancora `agenteye` | Cambia il comando del probe in `["agenteye-collector", "health"]`. | +| `agenteye: command not found`, ma `agenteye-collector` funziona | Script/alias fanno ancora riferimento al vecchio nome | Aggiornali a `agenteye-collector`. | +| L'esecuzione di `agenteye` avvia la CLI, non il collector | Hai la CLI AgentEye installata; possiede `agenteye` | Usa `agenteye-collector` per il daemon e rimuovi qualsiasi vecchio binario collector rimasto in `/usr/local/bin/agenteye`. | \ No newline at end of file diff --git a/docs/it/agenteye/deployment.mdx b/docs/it/agenteye/deployment.mdx new file mode 100644 index 00000000..c123297e --- /dev/null +++ b/docs/it/agenteye/deployment.mdx @@ -0,0 +1,427 @@ +--- +title: "Deployment" +description: "Documentazione del Deployment di AgentEye." +--- + +Questa guida copre il deployment del server AgentEye e della dashboard in produzione. + +--- + +## Panoramica dell'architettura + +``` + [ Macchine agenti AI ] [ Infrastruttura personale ] + + Python SDK + | scrive JSONL +----------------------+ + v +--->| PostgreSQL 15+ | + agenteye-collector --HTTP--+ | | (archivio relazionale)| + | | +----------------------+ + v | + +--------+ | +----------------------+ + | Server |<------+--->| ClickHouse 24+ | + +--------+ | | (eventi / analitiche)| + ^ | +----------------------+ + API | | + | | +----------------------+ + +-----------+ +- - >| Redis 7+ (facoltativo)| + | Dashboard | +----------------------+ + +-----------+ +``` + +- **Server**: servizio HTTP Rust; riceve batch di eventi, li scrive su ClickHouse e mantiene lo stato relazionale in PostgreSQL. +- **Dashboard**: app Next.js; legge e scrive esclusivamente attraverso l'API del server. +- **agenteye-collector**: deployato su macchine agenti, non sull'host del server. +- **Postgres 15+**: OBBLIGATORIO. (Aggiornato dalla versione 14 nel rilascio multi-tenant; lo schema dell'appartenenza organizzativa utilizza una chiave esterna `ON DELETE SET NULL` con elenco di colonne, che è disponibile solo in Postgres 15+. Aggiornare Postgres prima di eseguire il deployment di questa versione.) Archivia lo stato OLTP: `api_keys`, `users`, `sessions`, `evaluation_jobs` (coda), `dashboards`, `saved_queries`, `otp_codes`, più le tabelle multi-tenant `orgs`, `org_memberships`, `org_settings`. +- **ClickHouse 24+**: OBBLIGATORIO. L'archivio di analitiche per ogni evento acquisito. Engine: `ReplacingMergeTree`, partizionato per mese, ordinato per `(session_id, ts, dedup_key)`. Il server si connette tramite `CLICKHOUSE_URL`; il bundle `deploy/base/clickhouse/` fornisce una configurazione single-node ottimizzata per le prestazioni. **Requisito multi-tenant:** la configurazione bundled abilita la gestione dell'accesso SQL + `users_without_row_policies_can_read_rows=false` in modo che il server possa creare un utente e una politica di riga ClickHouse di sola lettura per organizzazione (il confine di isolamento imposto dal motore per l'editor SQL e l'agente AI). Se fornisci la tua configurazione ClickHouse, trasferisci queste impostazioni (vedi `deploy/base/clickhouse/configmap.yaml`). +- **Redis 7+**: *facoltativo* cache condiviso + backend per rate-limit. Il server e la dashboard si connettono entrambi tramite `REDIS_URL`. Se assente, entrambi degradano elegantemente a percorsi solo Postgres. Vedi **Redis (cache facoltativo)** di seguito. + +--- + +## Server + +### Estrai l'immagine + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +docker pull ghcr.io/agenteye-enterprise/server:beta-latest +``` + +> Le build attuali vengono pubblicate con `beta-latest`; `latest` viene assegnato solo ai rilasci stabili. Per la produzione, fissa un tag specifico `:v`; vedi [Tag immagine disponibili](#available-image-tags). + +### Variabili di ambiente + +| Variabile | Obbligatoria | Default | Descrizione | +|---|---|---|---| +| `DATABASE_URL` | Sì | nessuna | DSN Postgres. Stringa di connessione libpq standard con schema `postgres://`. Supporta `?sslmode=require` e altri parametri libpq. La password non deve contenere `/`, `+`, o `=`; usa `openssl rand -hex` per generare password sicure per URL. | +| `ADMIN_KEY` | No | nessuna | Chiave API amministratore bootstrap. Eseguita con tutti i permessi ad ogni avvio. Ruota cambiando il valore e riavviando. | +| `LISTEN_ADDR` | No | `0.0.0.0:8080` | Indirizzo TCP su cui fare il bind | +| `MAX_BODY_BYTES` | No | `134217728` (128 MB) | Dimensione massima del corpo della richiesta | +| `ADMIN_EMAIL` | No | nessuna | Email dell'utente amministratore bootstrap. Eseguita con tutti i permessi ad ogni avvio e contrassegnata come protetta: non può essere disabilitata o avere i permessi modificati tramite la dashboard/API. Per ruotare l'amministratore bootstrap, cambia `ADMIN_EMAIL` e riavvia; la nuova email viene eseguita come protetta, e la precedente mantiene la sua protezione fino a quando non viene manualmente cancellata dal database. | +| `ALLOWED_EMAILS` | No | nessuna (tutti bloccati) | Elenco separato da virgole di email consentite per la creazione e l'accesso degli utenti. Supporta indirizzi esatti (`user@example.com`) e wildcard di dominio (`*@example.com`). Se non impostato, nessun utente può essere creato o accedere. **Solo seed al primo avvio**: popola la lista consentita dell'organizzazione predefinita al primo avvio; successivamente la pagina [`//settings`](#operational-settings) di ogni organizzazione è la fonte della verità e cambiare questa variabile di ambiente non ha effetto. | +| `SMTP_HOST` | No | nessuna | Nome host del server SMTP per l'invio di email OTP. Se non impostato, i codici OTP vengono registrati su stdout. | +| `SMTP_PORT` | No | `587` | Porta del server SMTP | +| `SMTP_USERNAME` | No | nessuna | Nome utente di autenticazione SMTP | +| `SMTP_PASSWORD` | No | nessuna | Password di autenticazione SMTP | +| `SMTP_FROM` | No | nessuna | Indirizzo email del mittente per le email OTP | +| `SMTP_TLS` | No | STARTTLS | STARTTLS viene utilizzato a meno che tu non lo disabiliti esplicitamente: `false` o `0` invia testo semplice (nessun TLS); qualsiasi altro valore — incluso non impostato — abilita STARTTLS. | +| `DASHBOARD_URL` | No | default incorporato | Origine della dashboard utilizzata per creare sia il collegamento magico dell'email OTP che i collegamenti magici dell'incidente nelle notifiche di avviso. Se non impostato, torna al default incorporato (e, solo per OTP, all'origine della dashboard derivata dalla richiesta). Impostalo per configurazioni con dominio diviso in modo che sia i collegamenti email che Slack/incidente puntino alla tua dashboard. Vedi **URL collegamento magico email** di seguito; la maggior parte degli operatori non ha bisogno di impostarlo. | +| `SESSION_TTL_SECS` | No | `86400` (24 h) | Durata della sessione della dashboard in secondi. **Solo seed al primo avvio**: modifica per organizzazione tramite [`//settings`](#operational-settings) dopo il primo deployment. | +| `OTP_TTL_SECS` | No | `600` (10 min) | Periodo di validità del codice OTP in secondi. **Solo seed al primo avvio**: modifica per organizzazione tramite [`//settings`](#operational-settings) dopo il primo deployment. | +| `REDIS_URL` | No | nessuna | Backend cache condiviso facoltativo + rate-limit, ad es. `redis://redis:6379/0`. Quando impostato, il server memorizza nella cache le ricerche di chiavi API autenticate, l'aggregato `/models` della dashboard, l'elenco delle sessioni e il facet dell'elenco env; sposta anche il rate limiting della richiesta OTP da Postgres COUNT a Redis INCR. Se non impostato o non raggiungibile, il server funziona senza cache (il limite OTP torna a Postgres, ogni altra chiamata di cache cade alla fonte della verità). Vedi **Redis (cache facoltativo)** di seguito. | +| `CLICKHOUSE_URL` | **Sì** | nessuna | URL di base dell'istanza ClickHouse, ad es. `http://clickhouse:8123`. Il server applica il suo schema di eventi a questo database ad ogni avvio e si rifiuta di avviarsi se non riesce a raggiungere ClickHouse. Vedi **ClickHouse (archivio di analitiche richiesto)** di seguito. | +| `CLICKHOUSE_DATABASE` | No | `agenteye` | Nome database (schema) di ClickHouse. Il server lo crea all'avvio se non esiste. | +| `ORG_CH_SECRET` | No (single-tenant) / **Sì (multi-org)** | default dev | Chiave HMAC da cui viene derivata la password ClickHouse per tenant di ogni organizzazione. L'editor SQL e `run_query` dell'agente AI vengono eseguiti come utente ClickHouse di sola lettura dell'organizzazione, la cui politica di riga impone l'isolamento dei tenant nel motore. I deployment single-tenant si avviano bene con il default dev incorporato; **prima di eseguire il provisioning di una seconda organizzazione DEVI impostare un valore forte e stabile**, perché la CLI `agenteye-orgctl org create` si rifiuta di eseguire il default dev incorporato. Ruotarlo rende orfano ogni utente ClickHouse dell'organizzazione fino al successivo avvio che li riprovvigiona (la riconciliazione al tempo di avvio ripara questo automaticamente). Mantienilo segreto e invariato tra le repliche. Il provisioning dell'organizzazione è solo operatore; vedi **Organizzazioni (multi-tenancy)** di seguito. | +| `DEFAULT_ORG_NAME` | No | `Default` | Nome visualizzato sottoposto a seed per l'organizzazione predefinita incorporata. **Solo seed al primo avvio**, e solo mentre l'organizzazione mantiene ancora la sua identità generica appena migrata, applicata all'avvio, quindi ignorata. Una volta che rinomini l'organizzazione (`agenteye-orgctl org rename`) il rinomina è autorevole e questa variabile di ambiente non ha ulteriore effetto. | +| `DEFAULT_ORG_SLUG` | No | `default` | Slug URL per l'organizzazione predefinita incorporata, il percorso della dashboard su cui si trova (`//…`). Stessa semantica di primo-avvio-solo / pristino-solo di `DEFAULT_ORG_NAME`. Deve essere 1-40 caratteri alfanumerici minuscoli con singoli trattini interni e non essere una [parola riservata](#organizations-multi-tenancy); un valore non valido viene ignorato (l'organizzazione mantiene `default`). Consente a un'installazione single-tenant di presentarsi come ad es. `/acme` invece di `/default` senza alcun passaggio CLI post-deploy. | +| `RUST_LOG` | No | `info` | Verbosità del registro (`debug`, `warn`, `error`, `agenteye_server=trace`) | +| `EVALUATOR_ENDPOINT` | No | nessuna | URL di base del tuo servizio valutatore (ad es. `http://evaluator:9000`). Quando non impostato l'intera pipeline di valutazione è un no-op; non vengono scritte righe di coda, nessun worker viene eseguito. Vedi [Evaluation Suite](/it/agenteye/evaluation-suite). | +| `EVALUATOR_TOKEN` | No | nessuna | Inviato come `Authorization: Bearer ` al valutatore. **Deve essere uguale allo stesso valore con cui è configurato il servizio valutatore.** Facoltativo solo se il tuo valutatore è configurato senza token. | +| `EVALUATOR_WORKERS` | No | `2` | Concorrenza: numero di attività di lavoro per istanza di server che inviano valutazioni. Sicuro per l'esecuzione su più server con scalabilità orizzontale. | +| `EVALUATOR_CLAIM_BATCH` | No | `4` | Numero massimo di valutazioni che un singolo worker rivendica per tick. I batch vengono inviati **concorrentemente**, quindi la concorrenza totale sul tuo endpoint valutatore è `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH`. | +| `EVALUATOR_POLL_IDLE_SECS` | No | `2` | Quanto tempo un worker dorme tra i tentativi di invio quando nulla è dovuto. | +| `EVALUATOR_POLLING_INTERVAL_SECS` | No | `10` | Cadenza di fallback finale (secondi) per i poll `GET /evaluate/{id}` quando il valutatore non restituisce un `next_poll_secs` per risposta e non annuncia un `default_poll_interval_secs` da `GET /config`. | +| `EVALUATOR_REQUEST_TIMEOUT_MS` | No | `30000` | Timeout per richiesta HTTP al valutatore (millisecondi). | +| `EVALUATOR_MAX_ATTEMPTS` | No | `5` | Dopo questo numero di tentativi falliti una valutazione viene registrata come terminale `error` (o `timeout` se i fallimenti erano timeout di richiesta). | +| `EVALUATOR_CONFIG_REFRESH_SECS` | No | `300` (5 min) | Con quale frequenza il server recupera nuovamente `GET /config` dal valutatore. | +| `EVALUATOR_MAX_POLL_DURATION_SECS` | No | `3600` (1 h) | Tempo di wallclock massimo che una sessione può rimanere nella coda di polling prima che AgentEye la termini come `timeout`. Protegge da un valutatore che restituisce `pending` per sempre. | +| `ALERT_WORKERS` | No | `1` | Concorrenza: numero di attività di lavoro per istanza di server che valutano le regole di avviso. Vedi [Alerts](/it/agenteye/alerts). | +| `ALERT_CLAIM_BATCH` | No | `16` | Numero massimo di avvisi che un singolo worker rivendica per tick. | +| `ALERT_POLL_IDLE_SECS` | No | `5` | Quanto tempo un worker di avvisi dorme quando la coda è vuota. | +| `ALERT_REQUEST_TIMEOUT_MS` | No | `15000` | Timeout di valutazione per trigger (query ClickHouse + HTTP del canale in uscita). | +| `ALERT_MAX_ATTEMPTS` | No | `5` | Fallimenti transienti consecutivi prima che un avviso si riprogrammi al suo ritmo normale invece del backoff esponenziale. | +| `AUDIT_WORKERS` | No | `1` | Concorrenza: numero di attività di lavoro per istanza di server che eseguono gli audit. Vedi [Audits](/it/agenteye/audits). | +| `AUDIT_CLAIM_BATCH` | No | `1` | Numero massimo di audit dovuti che un singolo worker rivendica per tick. Un'indagine agentica è un lungo loop, quindi il default è 1. | +| `AUDIT_POLL_IDLE_SECS` | No | `30` | Quanto tempo un worker di audit dorme quando nessun audit è dovuto. | +| `AUDIT_REQUEST_TIMEOUT_MS` | No | `30000` | Timeout per query di politica su ClickHouse (millisecondi). | +| `AUDIT_LLM_TIMEOUT_MS` | No | `1440000` | Timeout per la chiamata di investigazione agentica al servizio assistente AI. Un loop agente completo funziona per minuti; mantienilo SOPRA il `AGENTEYE_AUDIT_TIMEOUT_MS` dell'agente stesso in modo che l'agente restituisca i suoi risultati parziali prima che il server rinunci. | +| `AUDIT_MAX_ATTEMPTS` | No | `5` | Fallimenti transienti consecutivi prima che un audit si riprogrammi al suo ritmo normale invece del backoff esponenziale. | +| `AGENTEYE_AGENT_URL` / `AGENTEYE_AGENT_TOKEN` | No | — | L'indagine agentica dell'audit chiama il servizio `agent` dell'assistente AI, **riutilizzando la stessa connessione dell'assistente** — quindi impostali entrambi anche su **server** (i manifesti/compose bundled lo fanno). Entrambi impostati ⇒ gli audit eseguono l'investigazione AI; uno qualsiasi non impostato ⇒ gli audit eseguono **solo politica** (il passaggio di politica SQL deterministico viene comunque eseguito), indipendentemente dal flag `llm_enabled` per audit. L'agente deve avere anche un LLM configurato — vedi [assistant.md](/it/agenteye/assistant). | + +**Servizio assistente AI — impostazioni di audit e sandbox.** L'indagine agentica e il suo sandbox Python in-pod sono sintonizzati sul **servizio agente** (non sul server), tutti con prefisso `AGENTEYE_AUDIT_*` e tutti facoltativi: + +| Variabile | Default | Significato | +|---|---|---| +| `AGENTEYE_AUDIT_MAX_STEPS` | `200` | Turni agente max per indagine. | +| `AGENTEYE_AUDIT_TIMEOUT_MS` | `1200000` | Wallclock per un'indagine (20 min). Deve rimanere **sotto** il `AUDIT_LLM_TIMEOUT_MS` del server. | +| `AGENTEYE_AUDIT_MAX_CONCURRENCY` | `1` | Indagini concorrenti per pod agente (separato dal budget dell'assistente di chat). | +| `AGENTEYE_AUDIT_SANDBOX_TIMEOUT_MS` / `_MEM_MB` / `_CPU_SECS` / `_OUTPUT_MAX_BYTES` / `_SCRIPT_MAX_BYTES` | `20000` / `768` / `10` / `64000` / `64000` | Limiti per-script per la jail bubblewrap. | + +**Requisito della piattaforma sandbox.** La sandbox del codice di audit esegue il Python del modello dentro una jail bubblewrap, che ha bisogno di **spazi dei nomi utente non privilegiati**. Il pod agente deve consentire i flag `clone()` — imposta `seccompProfile: Unconfined` (k8s) o `security_opt: [seccomp:unconfined]` (compose) sull'agente. Dove il kernel del nodo disabilita gli spazi dei nomi utente non privilegiati (ad es. alcune immagini GKE COS), il sandbox **il precheck fallisce e l'auditor degrada automaticamente a solo SQL** — nessun errore, solo un `sandbox_available: false` su `/health` dell'agente. + +### Esecuzione + +Imposta `DATABASE_URL` e `CLICKHOUSE_URL` nel tuo ambiente (il server si rifiuta di avviarsi senza ClickHouse), quindi passali al container: + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-server \ + -e DATABASE_URL="$DATABASE_URL" \ + -e CLICKHOUSE_URL="$CLICKHOUSE_URL" \ + -e ADMIN_KEY="$ADMIN_KEY" \ + -p 8080:8080 \ + ghcr.io/agenteye-enterprise/server:beta-latest +``` + +Il server esegue automaticamente le migrazioni del database all'avvio; nessun passaggio di migrazione separato necessario. + +### Health check + +``` +GET /health # liveness - sempre {"status":"ok"} una volta che il processo è in su +GET /ready # readiness - 200 quando Postgres + ClickHouse sono raggiungibili, altrimenti 503 +``` + +Nessuna autenticazione richiesta. Usa `/health` per i probe **liveness** e `/ready` per i probe **readiness** / load-balancer. `/ready` controlla le dipendenze hard che il server non può servire senza (Postgres + ClickHouse), quindi un server che è in esecuzione ma non può raggiungere il suo database viene tolto dalla rotazione e mostrato come `NotReady`; Redis viene segnalato ma non fallisce mai la readiness. Sui manifesti Kubernetes bundled il probe di readiness già punta a `/ready` e la liveness rimane su `/health`. Vedi [enterprise-docs/health-monitoring.md](/it/agenteye/health-monitoring) per il quadro completo, incluso l'alerting opzionale nativo di Kubernetes per il fallimento del pod a Slack. + +### URL collegamento magico email + +Le email di accesso OTP contengono un pulsante **apri la dashboard** one-tap. Cliccandolo l'utente arriva su `/login?token=&email=
`; la dashboard scambia quella coppia per una sessione e reindirizza all'app, senza re-immissione manuale del codice. Il server risolve l'origine della dashboard utilizzata per costruire il collegamento in tre livelli: + +1. **Header `X-AgentEye-Dashboard-Url`**: impostato automaticamente dal proxy `/api/auth/otp/request` della dashboard dalla sua stessa origine pubblica. In un deployment same-origin (server e dashboard condividono un host dietro un ingress che inoltra gli header proxy), **nessuna configurazione è richiesta**. +2. **Variabile di ambiente `DASHBOARD_URL`**: impostalo se la tua dashboard è raggiungibile su un'origine diversa da quella che l'endpoint della richiesta OTP del server vede (split `api.example.com` / `app.example.com`), o se il tuo ingress non propaga l'host pubblico nel pod della dashboard (quindi `request.nextUrl.origin` altrimenti si risolverebbe in un bind wildcard come `0.0.0.0:3000`). Esempio: `DASHBOARD_URL=https://app.example.com`. +3. **Default**: `https://app.befailproof.ai`, usato solo se nessuno dei precedenti è presente. + +Il valore dell'header viene validato: solo le origini `https://*` e loopback (`http://localhost*`, `http://127.0.0.1*`) vengono accettate, e gli indirizzi di bind wildcard (`0.0.0.0`, `[::]`) vengono rifiutati anche con lo schema `https://`. Tutto il resto cade al livello 2. + +Impostalo su un cluster in esecuzione con un one-liner; nessun file, nessuna ricostruzione di kustomize: + +```bash +kubectl set env deployment/server -n agenteye \ + DASHBOARD_URL=https://app.example.com +``` + +Questo attiva un rollout; i nuovi pod raccolgono il valore alla prima richiesta. Nota che l'override vive solo sulla Deployment; un successivo `kustomize build | kubectl apply` rispetto all'overlay lo cancellerà a meno che tu non aggiunga la stessa variabile di ambiente al patch `server-env.yaml` del tuo overlay. + +--- + +## Dashboard + +### Estrai l'immagine + +```bash +docker pull ghcr.io/agenteye-enterprise/dashboard:beta-latest +``` + +### Variabili di ambiente + +| Variabile | Obbligatoria | Default | Descrizione | +|---|---|---|---| +| `AGENTEYE_SERVER_URL` | Sì | nessuna | URL di base del server, ad es. `http://localhost:8080` | +| `AGENTEYE_API_KEY` | Sì | nessuna | Chiave API che la dashboard utilizza per autenticarsi al server. Ha bisogno di tutti i permessi (chiave admin consigliata). | +| `AE_LOG_LEVEL` | No | `info` | Verbosità del registro lato server: `debug`, `info`, `warn`, `error`. Impostalo su `debug` per vedere le linee di richiesta/risposta upstream e le tracce di validazione della sessione quando diagnostichi i problemi. | +| `AE_LOG_JSON` | No | auto | `1` forza l'output JSON-per-riga; `0` forza l'output leggibile dall'uomo. Se non impostato, JSON è abilitato automaticamente se `NODE_ENV=production`. JSON è consigliato in produzione in modo che i registri si analizzino in modo ordinato con `jq` o un aggregatore di registri. | +| `AE_ANALYTICS_DISABLED` | No | nessuna | Impostalo su `1`/`true` per disabilitare la telemetria di utilizzo del prodotto anonima della dashboard. Vedi [Telemetry & privacy](#telemetry--privacy) di seguito. | +| `REDIS_URL` | No | nessuna | Backend cache condiviso facoltativo, ad es. `redis://redis:6379/0`. Quando impostato, la dashboard memorizza nella cache i risultati di `validateSession()` tra le repliche e condivide la cache di recupero di Next.js per le rotte proxy aggregate di latenza / elenco env. I limiti di rate OTP di richiesta e verifica edge-side utilizzano anche Redis quando presente (che si aprono se Redis non è raggiungibile; il limite lato server è la difesa di sicurezza). Vedi **Redis (cache facoltativo)** di seguito. | +| `AGENTEYE_AGENT_URL` | No | nessuna | URL di base del servizio `agent` assistente AI opzionale, ad es. `http://agent:9100`. **Lascialo non impostato per nascondere completamente l'assistente**: nessuna bolla dell'assistente appare nella dashboard. Vedi [enterprise-docs/assistant.md](/it/agenteye/assistant). | +| `AGENTEYE_AGENT_TOKEN` | No | nessuna | Segreto condiviso che la dashboard presenta al servizio `agent`. Deve corrispondere al `AGENTEYE_AGENT_TOKEN` configurato sull'agente. Vedi [enterprise-docs/assistant.md](/it/agenteye/assistant). | + +### Esecuzione + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-dashboard \ + -e AGENTEYE_SERVER_URL="http://your-server-host:8080" \ + -e AGENTEYE_API_KEY="$ADMIN_KEY" \ + -p 3000:3000 \ + ghcr.io/agenteye-enterprise/dashboard:beta-latest +``` + +### Telemetria e privacy + +La dashboard invia **analitiche di utilizzo del prodotto anonimo** al servizio di analitiche di Exosphere (PostHog): quali pagine della dashboard vengono visualizzate e una manciata di azioni dell'interfaccia utente come la creazione di una chiave API o la rivalutazione di una sessione. Questo segnale di utilizzo informa quali funzioni sono prioritarie. + +- **Nessun dato di agente, sessione o evento esce mai dalla tua infrastruttura.** Solo l'utilizzo dell'interfaccia utente della dashboard viene segnalato. Gli URL delle pagine vengono spogliati degli identificatori prima dell'invio, e gli operatori vengono identificati solo da un id interno opaco, mai per email. +- La telemetria è **abilitata per impostazione predefinita**. Per disattivarla completamente, imposta `AE_ANALYTICS_DISABLED=1` nel container della dashboard e riavvia. +- Le analitiche vengono inviate al percorso `/ingest` della dashboard stessa, che la dashboard inoltra tramite proxy a PostHog (`https://us.i.posthog.com`). Mantenere le richieste first-party significa che i blocchi degli annunci del browser non le riducono. Il **container della dashboard** ha bisogno dell'accesso in uscita a PostHog; se è bloccato, la telemetria non fa silenziosamente nulla e la dashboard è inalterata. + +--- + +## Assistente AI (facoltativo) + +Un assistente AI in-dashboard consente al tuo team di porre domande sui dati del loro agente in linguaggio naturale (riassumendo le sessioni, elaborando SQL per l'editor `/queries` e trasformando le query salvate in tile della dashboard) senza lasciare la dashboard. Funziona come un container `agent` interno separato (su Claude Agent SDK) che solo la dashboard può raggiungere, e rimane **disabilitato fino a quando non configuri un endpoint LLM**. + +Per abilitarlo, imposta, sul servizio `agent`, una connessione LLM (**Portkey** tramite `PORTKEY_API_KEY` + uno slug del catalogo modelli `AGENTEYE_AGENT_MODEL=@/`, Anthropic diretto tramite `ANTHROPIC_API_KEY`, un altro gateway tramite `ANTHROPIC_BASE_URL`, o Bedrock/Vertex), una chiave di dati **dedicata**, e un `AGENTEYE_AGENT_TOKEN` condiviso che corrisponde alla dashboard. Gli utenti della dashboard hanno inoltre bisogno del permesso `agent:use`. + +Per la chiave di dati dell'assistente non conia nulla a mano: scegli un segreto casuale, impostalo come `AGENTEYE_API_KEY` su `agent` **e** come `AGENT_API_KEY` su `server`, e il server lo propaga all'avvio con un set di permessi fisso. Il suo accesso ai dati è di sola lettura (`events:read`, `evaluations:read`, `dashboards:read`, `queries:read`), e inoltre contiene scope di authoring con controllo di approvazione (`dashboards:write`, `queries:write`, `queries:run`) in modo che possa elaborare e convalidare le query salvate e costruire tile della dashboard per conto dell'utente; tutto SQL viene comunque eseguito attraverso il ruolo ClickHouse di sola lettura dell'organizzazione, quindi questo amplia ciò che l'assistente può creare, non i dati che può raggiungere. Gli scope sono fissi nel codice e non possono essere ampliati per configurazione. Quella chiave è protetta; non può essere disabilitata o rigenerata tramite l'API, solo ruotata cambiando il valore e riavviando. Non riutilizzare mai la chiave admin/dashboard per questo. + +Setup completo, il riferimento completo alle variabili di ambiente, opzioni di telemetria e il modello di sicurezza sono in **[enterprise-docs/assistant.md](/it/agenteye/assistant)**. + +--- + +## ClickHouse (archivio di analitiche richiesto) + +ClickHouse mantiene le tue dashboard responsabili ad alti volumi di eventi e consente all'editor SQL `/queries` di unire tra loro eventi, valutazioni e sessioni in un singolo archivio. È l'archivio canonico richiesto per ogni evento acquisito, ogni risultato di valutazione terminale e gli aggregati derivati per-sessione. PostgreSQL contiene le tabelle di stato relazionale / mutabile (api_keys, users, otp_codes, evaluation_jobs, dashboards, saved_queries); la superficie analitica vive in ClickHouse in modo che i rollup della dashboard e le tue query SQL possono scansionare e unirle in modo nativo, senza round-trip tra database. Il server si rifiuta di avviarsi senza `CLICKHOUSE_URL`. + +### Schema + +Tre oggetti ClickHouse vengono creati all'avvio del server, tutti idempotenti (`CREATE IF NOT EXISTS`): + +- **`agenteye.events`**: `ReplacingMergeTree(ingested_at)`, partizionato per `toYYYYMM(ts)`, ordinato per `(session_id, ts, dedup_key)`. Gli inserti duplicati (i retry del collettore) collassano in una singola riga al momento della fusione; il server calcola una chiave di dedup SHA-256 deterministica `dedup_key` per ogni evento in modo che i retry siano sicuri. +- **`agenteye.evaluations`**: `ReplacingMergeTree(ingested_at)`, partizionato per `toYYYYMM(finished_at)`, ordinato per `(session_id, finished_at, dedup_key)`. Scritto una volta per ogni risultato di valutazione terminale dalla pipeline del valutatore. Lo stesso modello di chiave di dedup di `events`. +- **`agenteye.agent_sessions`**: una **VIEW** su `agenteye.events`, non una tabella fisica. Ogni colonna è derivata (`started_at = min(ts)`, `last_event_at = max(ts)`, `ended_at = max(if event_type='agent_end', ts, NULL)`, `event_count = count()`, ecc.). Nessun upsert per evento e nessun backfill separato; la view riflette automaticamente qualsiasi cosa sia in `events`. + +Per la compatibilità all'indietro con le query salvate che fanno riferimento a `analytics.evaluations` / `analytics.sessions`, il server crea anche un database `analytics` di ClickHouse con view sui table `agenteye.*`; `analytics.events`, `analytics.evaluations`, `analytics.agent_sessions`, `analytics.sessions` si risolvono tutti correttamente. + +### Configurazione + +Il docker-compose bundled e `deploy/base/clickhouse/` forniscono un servizio ClickHouse sintonizzato per il carico di lavoro di AgentEye: + +- Memoria richiesta 2 GiB / limite 4 GiB nell'overlay di base fornito (dimensionato per adattarsi ai piccoli nodi POC/staging); i clienti di produzione dovrebbero sovrapporre — il floor consigliato è 2c / 4Gi richiesta, 6c / 8Gi limite. `max_server_memory_usage_to_ram_ratio=0.9` +- 5 GiB mark cache + 8 GiB cache non compressa +- `background_pool_size=16`, `background_merges_mutations_concurrency_ratio=2` +- MergeTree: `parts_to_throw_insert=3000`, `parts_to_delay_insert=1500`, `non_replicated_deduplication_window=1000` +- `local_io_method=auto` (io_uring sui kernel supportati) +- `fsync_metadata=0`: accettabile per inserimento at-least-once + dedup ReplacingMergeTree +- `query_log` abilitato con TTL di 30 giorni; `query_thread_log` rimosso (costoso ad alto QPS) +- `max_execution_time=30` per le query lato utente +- 100 GiB PVC nel template StatefulSet (gli overlay dei clienti DOVREBBERO eseguire l'override con una classe di archiviazione SSD veloce per la produzione) + +### Backup + +L'intero set di dati viene acquisito nightly in un singolo archivio ripristinabile, quindi una perdita di cluster o archiviazione è recuperabile. ClickHouse viene sottoposto a backup automaticamente dal CronJob `agenteye-backup` giornaliero, che scarica sia PostgreSQL che ClickHouse in un unico passaggio. ClickHouse viene letto sulla sua API HTTP: `agenteye.events` e `agenteye.evaluations` vengono scaricati nel formato nativo di ClickHouse (le view e le politiche di riga vengono ricreate dal server all'avvio, quindi i dati della tabella sono il quadro completo) e raggruppati con il dump Postgres in un singolo archivio compresso caricato sul tuo archivio di oggetti. + +Il bucket di destinazione e le credenziali cloud vengono configurati per overlay. Vedi la sezione **Backups** di [enterprise-docs/kubernetes-deployment.md](/it/agenteye/kubernetes-deployment) per la configurazione del caricamento e i passaggi di ripristino. + +--- + +## Redis (cache facoltativo) + +Redis è un backend cache condiviso **facoltativo** + rate-limit utilizzato dal server e dalla dashboard. Con Redis deployato e `REDIS_URL` impostato su entrambi i servizi: + +- **Server** memorizza nella cache le ricerche di chiavi API autenticate, gli elenchi `/events/environments` + `/evaluations/environments`, il rollup `/events/latency_aggregate` (la query più pesante che la dashboard esegue il polling), l'elenco `/sessions`, e cambia il rate limiting della richiesta OTP da un `COUNT(*)` Postgres a un `INCR + EXPIRE` Redis. +- **Dashboard** memorizza nella cache i risultati di `validateSession()` in modo che le 10-20 chiamate API autenticate che un tipico caricamento di pagina emette condividano tutte un singolo controllo di sessione upstream. Inoltre limita la velocità di richiesta e verifica OTP al bordo della dashboard. + +**Entrambi i servizi degradano elegantemente se Redis non è raggiungibile.** Ogni chiamata di cache restituisce `Err` entro un timeout limitato e il chiamante torna alla fonte della verità (Postgres sul server, il server Rust a monte sulla dashboard). Il rate limiting OTP torna al percorso `COUNT(*)` Postgres sul server (la proprietà di sicurezza è preservata); il limite OTP edge della dashboard non ha successo mentre il limite lato server continua a valere. Redis essere inattivo degrada la latenza, non la correttezza. + +### Configurazione + +Il bundle docker-compose include già un servizio Redis e cablagna `REDIS_URL=redis://redis:6379/0` nel server e nella dashboard. Per utilizzare un Redis esterno, imposta `REDIS_URL` sul tuo endpoint e rimuovi il servizio `redis` dal file compose. + +### Memoria + persistenza + +L'immagine Redis bundled si esegue con `--appendonly yes --appendfsync everysec --maxmemory 256mb --maxmemory-policy allkeys-lru`. La persistenza AOF significa che la cache sopravvive ai riavvii del container; `everysec` è il giusto equilibrio di durabilità/perf perché perdere l'ultimo secondo di scritture di cache è innocuo. L'evizione LRU limita la crescita della memoria. + +### Quando NON deployare Redis + +- Dev/QA single-instance. Le cache in-process sul server da solo forniscono la maggior parte del beneficio per-replica; Redis aggiunge la condivisione tra-replica che i setup single-instance non hanno. +- Installazioni air-gapped dove il costo operazionale di eseguire un servizio in più supera il guadagno di latenza. + +--- + +## Docker Compose (consigliato) + +Un `docker-compose.yml` è disponibile nel repo `agenteye-enterprise/releases`. Avvia Postgres, ClickHouse, Redis, il server e la dashboard con un singolo comando. + +```bash +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download \ + --repo agenteye-enterprise/releases \ + --pattern 'docker-compose.yml' \ + --dir ./agenteye +cd agenteye +``` + +**Esegui l'override dei default tramite `.env`:** + +``` +# Usa password sicure per URL (nessun /, +, o = caratteri). +# Genera con: openssl rand -hex 24 +POSTGRES_PASSWORD=your-db-password +ADMIN_KEY=your-admin-secret + +# Autenticazione dashboard +ADMIN_EMAIL=admin@yourcompany.com +ALLOWED_EMAILS=*@yourcompany.com + +# SMTP per email OTP (ometti per registrare i codici OTP su stdout) +# SMTP_HOST=smtp.yourprovider.com +# SMTP_PORT=587 +# SMTP_USERNAME=your-smtp-user +# SMTP_PASSWORD=your-smtp-password +# SMTP_FROM=noreply@yourcompany.com + +RUST_LOG=info +``` + +```bash +docker compose up -d +``` + +**Arresta (mantiene il volume dati):** + +```bash +docker compose down +``` + +**Arresta e cancella tutti i dati:** + +```bash +docker compose down -v +``` + +--- + +## Impostazioni operative + +Un piccolo set di manopole operative che erano precedentemente fissate dalle variabili di ambiente sono ora modificabili per organizzazione dalla pagina **`//settings`** della dashboard; ogni organizzazione configura la propria. Le modifiche hanno effetto entro secondi, senza riavvio e senza redistribuzione. + +| Impostazione | Variabile env bootstrap | Cosa controlla | +|---|---|---| +| Accessi consentiti | `ALLOWED_EMAILS` | Email (o wildcard `*@domain.com`) autorizzate a ricevere un OTP ed essere aggiunte come utenti | +| Permessi utente predefiniti | `DEFAULT_USER_PERMISSIONS` | Token di autorizzazione separati da virgole preselezionati quando un admin apre **+ nuovo utente**. Ogni token deve essere una delle stringhe elencate sotto [API key permissions](/it/agenteye/api-keys). Predefinito al preset `standard`: accesso di sola lettura più le azioni quotidiane on-call (attiva rivalutazioni, esegui query, riconosci incidenti, usa l'assistente). | +| Durata della sessione | `SESSION_TTL_SECS` | Quanto tempo un accesso alla dashboard rimane valido prima della riautenticazione. La dashboard ricontrolla la sessione a monte ogni 5 secondi, quindi un aggiornamento delle autorizzazioni su `//users` ha effetto sulla richiesta successiva dell'utente interessato, senza riaccesso. | +| Durata del codice monouso | `OTP_TTL_SECS` | Quanto tempo un OTP / collegamento magico rimane utilizzabile | +| Canali di notifica di avviso | `ALERTS_ENABLED_CHANNELS` | Elenco separato da virgole di tipi di canale che il dispatcher di avviso è autorizzato a utilizzare: `email`, `slack`, `webhook`. La configurazione per-avviso viene comunque creata su `//alerts/`, ma il dispatcher filtra ogni consegna in uscita attraverso questo set; un canale disabilitato qui cortocircuita con una riga di audit `skipped_disabled`. Il canale `dashboard` (l'inserimento dell'audit locale) è sempre consentito. Predefinito a tutti e tre su. | + +### Come funziona il bootstrap + +Le impostazioni vengono archiviate per organizzazione in `org_settings`. Al primo avvio, il server propaga le righe mancanti dell'organizzazione predefinita dalla variabile di ambiente corrispondente (o un default ragionevole se la variabile di ambiente non è impostata). Dopo ciò, **il valore archiviato è la fonte della verità e la variabile di ambiente viene ignorata**; cambiare la variabile di ambiente su un riavvio successivo non influenzerà il valore di un'organizzazione live, e le organizzazioni aggiuntive iniziano dai default e configurano le proprie. + +Questo significa: + +- Per un deployment fresco, imposta le variabili di ambiente come mostrato sopra e l'organizzazione predefinita le legge al primo avvio. +- Per cambiare un valore in seguito, accedi alla dashboard e modificalo sotto `//settings`. La modifica si applica entro secondi tra tutte le repliche del server; nessun riavvio necessario. +- Una riga di registro all'avvio registra cosa è stato sottoposto a seed rispetto a cosa era già presente, quindi puoi confermare che il bootstrap ha avuto effetto: + + ```text + INFO settings bootstrap: seeded default-org row key=allowed_sign_ins env_var=ALLOWED_EMAILS seeded_from_env=true + ``` + +#### Semantica di accesso tra le organizzazioni + +Una sessione e un OTP sono globali all'utente, non a una singola organizzazione, quindi due regole riconciliano le impostazioni per-organizzazione al momento dell'accesso: + +- **Durata della sessione / OTP**: la durata più severa (più breve) tra le organizzazioni a cui l'utente appartiene vince. +- **Accessi consentiti**: il gate combina logicamente (OR) ogni elenco consentito dell'organizzazione con l'appartenenza all'organizzazione: un utente può richiedere un OTP se l'elenco consentito di qualsiasi organizzazione ammette la sua email **o** è già membro di qualsiasi organizzazione. + +### Autorizzazioni + +L'accesso a una pagina `//settings` è controllato da due autorizzazioni: + +- `settings:read`: vedi la pagina e i valori attuali. +- `settings:write`: salva le modifiche. + +L'utente admin bootstrap (propagato da `ADMIN_EMAIL`) ottiene entrambi automaticamente insieme a ogni altra autorizzazione. Concedili ad altri utenti da `//users` come necessario. + +--- + +## Organizzazioni (multi-tenancy) + +Un singolo deployment può servire più **organizzazioni** isolate (tenant); ogni riga di dati appartiene a esattamente un'organizzazione e l'isolamento è imposto nel motore del database. Un'installazione single-tenant non ha bisogno di nulla qui; tutti i dati vivono in un'organizzazione `default` incorporata. (Puoi dare a quell'organizzazione un nome più amichevole e un slug URL, in modo che viva a es. `/acme` invece di `/default`, impostando `DEFAULT_ORG_NAME` / `DEFAULT_ORG_SLUG` prima del primo avvio, o rinominandola in qualsiasi momento con `agenteye-orgctl org rename`.) + +**Il provisioning del tenant è solo operatore.** Le organizzazioni e le loro appartenenze vengono create e gestite con la CLI **`agenteye-orgctl`**, che viene fornita **all'interno dell'immagine del server** (insieme a `agenteye-server`) e viene eseguita **all'interno del pod del server esistente**; non c'è **pod/Job separato, nessuna API HTTP, e nessun pulsante dashboard**. Riusa `DATABASE_URL`, `CLICKHOUSE_URL` e `ORG_CH_SECRET` del server. + +```bash +# Docker Compose - exec nel servizio server in esecuzione: +docker compose exec server agenteye-orgctl org create --slug acme --name "Acme Corp" +docker compose exec server agenteye-orgctl member add --org acme --email alice@acme.example --set admin + +# Kubernetes - exec nella Deployment del server in esecuzione: +kubectl -n agenteye exec deploy/server -- agenteye-orgctl org list +``` + +Verbi disponibili: `org create | list | rename | delete | purge` e `member add | list | update | remove`, con set di autorizzazioni incorporati `admin`, `standard`, e `read-only`. I membri aggiunti ricevono un OTP al primo accesso alla dashboard. + +**Prima di creare una seconda organizzazione:** imposta un `ORG_CH_SECRET` forte e stabile (il comando `org create` si rifiuta di eseguire il default dev incorporato) e assicurati che Postgres sia **15+**. **Invariato:** le chiavi API per-organizzazione vengono comunque coniate nella dashboard/API dai membri dell'organizzazione; solo il ciclo di vita org + member si è spostato sulla CLI. Riferimento del comando completo e un esempio pratico: **[enterprise-docs/tenant-management.md](/it/agenteye/tenant-management)**. + +--- + +## Riempimento della finestra di contesto + +Ogni evento `model_response` mostra una **pillola di riempimento del contesto** — token di input più output come percentuale della finestra di contesto di quel modello. Le bande sono `healthy` (0–24%), `watch` (25–49%), `compacting` (50–74%), e `reset context` (75–100%). AgentEye risolve gli ID dei modelli comuni automaticamente, quindi nessuna configurazione iniziale è richiesta. + +Ogni modello che un'organizzazione invia appare sotto **Settings → model context windows**. Gli utenti con `settings:write` possono eseguire l'override della sua finestra o aggiungere un modello privato/proxy (0–1.000.000 token); `0` significa "sconosciuto" e sopprime la pillola. Le modifiche si applicano agli eventi appena acquisiti. Gli utenti con `settings:read` possono visualizzare l'elenco. + +I nuovi eventi ricevono il riempimento dal momento in cui esegui l'upgrade. Per anche popolare gli eventi **storici** (e l'elenco per-modello) per un deployment esistente, esegui il backfill una tantum — viene fornito all'interno dell'immagine del server (come `agenteye-orgctl`) e si esegue nel pod del server esistente: + +```bash +# anteprima (stampa la mutazione per-organizzazione, non cambia nulla): +kubectl -n agenteye exec deploy/server -- agenteye-backfill-context-window --dry-run +# applica: +kubectl -n agenteye exec deploy/server -- agenteye-backfill-context-window +# docker compose: +docker compose exec server agenteye-backfill-context-window +``` + +È idempotente (sicuro di eseguire di nuovo) e riusa `DATABASE_URL` / `CLICKHOUSE_URL` / `REDIS_URL` dal pod. Rieseguilo dopo aver modificato le finestre dei modelli se vuoi che gli eventi esistenti vengano ricalcolati. + +--- + +## Considerazioni sulla produzione + +- **Postgres**: utilizza un servizio Postgres gestito o un'istanza dedicata con backup regolari. `DATABASE_URL` supporta tutti i parametri libpq standard, incluso `sslmode=require` per le connessioni crittografate. +- **TLS**: metti il server e la dashboard dietro un proxy inverso (nginx, Caddy, Traefik) che termina TLS. +- **Firewall**: la porta del server (default 8080) dovrebbe essere raggiungibile solo dalle macchine collettore e dall'host della dashboard, non da internet pubblico. +- **Chiave admin**: imposta `ADMIN_KEY` su un segreto casuale forte. Dopo il bootstrap, crea chiavi dedicate con scope per collettori e dashboard piuttosto che usare la chiave admin ovunque. +- **Tag immagine**: fissa alla versione nei tuoi manifesti di release (ad es. `server:v0.0.1-beta.48`) in produzione piuttosto che un tag mobile per evitare upgrade indesiderati. Le build beta attuali vengono pubblicate su `beta-latest`; `latest` viene assegnato solo ai rilasci stabili. +- **Monitoraggio della salute**: su Kubernetes il probe di readiness usa `/ready` (raggiungibilità Postgres + ClickHouse) mentre la liveness rimane su `/health`. Per l'alerting a livello di flotta "AgentEye stesso è in su?" a Slack, abilita l'add-on Robusta opzionale; vedi [enterprise-docs/health-monitoring.md](/it/agenteye/health-monitoring). + +--- + +## Tag immagine disponibili + +| Tag | Descrizione | +|-----|-------------| +| `latest` | Ultimo rilascio stabile | +| `beta-latest` | Ultimo pre-rilascio (beta) | +| `v` | Versione fissata, ad es. `v0.0.1-beta.48` (consigliato per la produzione) | \ No newline at end of file diff --git a/docs/it/agenteye/evaluation-suite.mdx b/docs/it/agenteye/evaluation-suite.mdx new file mode 100644 index 00000000..d8987a2c --- /dev/null +++ b/docs/it/agenteye/evaluation-suite.mdx @@ -0,0 +1,459 @@ +--- +title: "Suite di Valutazione" +description: "Documentazione della Suite di Valutazione di AgentEye." +--- + + +AgentEye assegna punteggi alle sessioni degli agenti completate effettuando il POST della trascrizione completa degli eventi a un +**unico servizio di valutazione di proprietà del cliente**. Il valutatore restituisce i punteggi in linea o tramite un `job_id` +per il polling da parte di AgentEye. I risultati vengono archiviati e visualizzati nella dashboard. + +Questa guida tratta: + +1. Come viene rilevato il completamento della sessione. +2. Il contratto HTTP che il valutatore deve implementare. +3. Configurazione del server AgentEye. +4. Visualizzazione dei risultati. +5. Risoluzione dei problemi. + +Per l'helper Python che implementa il contratto, vedere il pacchetto +[`agenteye-evaluator` su PyPI](https://pypi.org/project/agenteye-evaluator/). + +--- + +## Come funziona + +```text +ingest /events ──▶ AgentEye ──── POST /evaluate ────▶ Servizio valutatore + (agent_end) server ◀──── done | pending ──── + │ + │ GET /evaluate/{job_id} ─────▶ + │ ◀──── done ────────────── + ▼ + evaluations (risultati terminali) +``` + +Quando l'SDK di AgentEye emette un evento `agent_end` per una sessione, il server +pianifica una valutazione. Invia quindi la trascrizione completa degli eventi al tuo +servizio di valutazione, che può: + +- **Restituire il risultato in linea** con `{"status":"done", "scores":{...}, "reasoning":{...}, "summary":"..."}`. Il + risultato viene aggiunto alla timeline di valutazione della sessione. `reasoning` e + `summary` sono facoltativi. +- **Rinviare** con `{"status":"pending", "job_id":"abc-123"}`. AgentEye quindi + chiama `GET {EVALUATOR_ENDPOINT}/evaluate/abc-123` finché il tuo valutatore + non restituisce `{"status":"done", ...}` o `{"status":"error", "error":"..."}`. + + La cadenza del polling è per-job: una risposta `pending` può includere + `next_poll_secs` per escludere; altrimenti AgentEye utilizza il valore + `default_poll_interval_secs` da `GET /config`; altrimenti il server + ricade su `EVALUATOR_POLLING_INTERVAL_SECS` (predefinito 10s). Tutti i valori + sono vincolati a [1s, 1h]. + +Le sessioni che non emettono mai `agent_end` (ad esempio, un processo agente +bloccato) possono comunque essere rilevate: il `GET /config` del valutatore può restituire +`{"inactivity_timeout_secs": 1800}`, e AgentEye valuterà qualsiasi sessione +rimasta inattiva per quel tempo. Imposta il campo a `null` o omettilo per +disabilitare questo fallback. + +La pipeline è completamente no-op quando `EVALUATOR_ENDPOINT` non è impostato. + +Una sessione può accumulare **più valutazioni terminali nel tempo**: ogni +evento `agent_end` (e ogni rivalutazione manuale dalla dashboard) aggiunge una +nuova riga di valutazione. Questo è il modo supportato per valutare una +conversazione ripresa: un utente termina un agente, torna più tardi, invia altri eventi, +termina di nuovo l'agente, e viene eseguita una seconda valutazione sulla trascrizione completa aggiornata. La dashboard +rende la valutazione più recente come titolo e le valutazioni precedenti come una timeline comprimibile. Mentre una +valutazione è in esecuzione per una sessione, ulteriori eventi `agent_end` per quella +sessione vengono ignorati; il prossimo dopo il completamento della valutazione in esecuzione +accoderà una nuova valutazione come al solito. + +Il fallback di inattività si riattiva anche sulle sessioni riprese: se nuovi eventi +arrivano dopo una valutazione terminale precedente e la sessione rimane inattiva +oltre `inactivity_timeout_secs`, viene accodata una nuova valutazione. + +I guasti transitori (5xx, 429, timeout, errori di rete) vengono ritentati con +backoff esponenziale fino a `EVALUATOR_MAX_ATTEMPTS`; le risposte 4xx sono +terminali. AgentEye è sicuro da eseguire con più istanze di server scalate +orizzontalmente; il lavoro viene partizionato in modo che la stessa sessione non venga +mai inviata due volte contemporaneamente. + +--- + +## Contratto HTTP + +Ogni route autenticata utilizza **autenticazione bearer token**. Lo stesso valore deve essere +configurato su entrambi i lati: + +- Server AgentEye: variabile di ambiente `EVALUATOR_TOKEN` +- Servizio valutatore: configurato allo stesso modo (l'SDK `agenteye-evaluator` + legge `EVALUATOR_TOKEN` per convenzione) + +Se `EVALUATOR_TOKEN` non è impostato, il server non invia l'header `Authorization`; il +valutatore può quindi accettare richieste anonime, il che va bene per una +rete solo interna ma è sconsigliato su internet pubblico. + +### Route che il valutatore deve servire + +| Route | Body / parametri | Risposta | +|---|---|---| +| `GET /health` | nessuno | `{"status":"ok"}` (aperto, senza auth) | +| `GET /config` | nessuno | `{"inactivity_timeout_secs": \| null, "default_poll_interval_secs": \| omesso}` | +| `POST /evaluate` | JSON `EvalRequest` | `{"status":"done", ...}` o `{"status":"pending", "job_id":"..."}` | +| `GET /evaluate/{id}` | nessuno | stessa forma di risposta di `/evaluate` | + +### Body `EvalRequest` inviato dal server + +```json +{ + "schema_version": "1", + "session_id": "session-abc123", + "agent_id": "planner", + "environment": "production", + "started_at": "2026-05-10T12:00:00Z", + "ended_at": "2026-05-10T12:05:00Z", + "events": [ + { "id": 1234, "ts": "...", "event_type": "agent_start", "payload": { ... } }, + ... + ] +} +``` + +### Forme di risposta + +**Sincrona (done):** + +```json +{ + "status": "done", + "scores": { "helpfulness": 0.85, "tool_efficiency": 0.6 }, + "reasoning": { + "helpfulness": "answered the question directly with citations", + "tool_efficiency": "called list_files three times when one would have done" + }, + "summary": "strong answer quality, weak tool selection" +} +``` + +`reasoning` (una mappa di giustificazione per punteggio) e `summary` (una +narrativa di paragrafo unico complessiva) sono entrambi facoltativi. Le chiavi in `reasoning` dovrebbero +rispecchiare quelle in `scores`; la dashboard rende ogni voce in linea sotto +la sua barra dei punteggi. I valutatori più vecchi che restituiscono solo `scores` continuano a +funzionare senza modifiche; `reasoning` e `summary` semplicemente leggono come null e +i corrispondenti elementi dell'interfaccia utente vengono omessi. + +**Asincrona (rinviata):** + +```json +{ "status": "pending", "job_id": "abc-123", "next_poll_secs": 30 } +``` + +`next_poll_secs` è facoltativo; se omesso il server ricade su +`default_poll_interval_secs` del valutatore da `/config`, poi sulla sua +variabile di ambiente `EVALUATOR_POLLING_INTERVAL_SECS`. + +**Errore terminale lato valutatore:** + +```json +{ "status": "error", "error": "model service unavailable" } +``` + +Il server tratta qualsiasi altro body 2xx come errore di protocollo e registra un +`error` terminale per la sessione. + +--- + +## Scrivere un valutatore con l'SDK + +Il pacchetto Python `agenteye-evaluator` ti offre un wrapper FastAPI +tipizzato che implementa il contratto HTTP sopra. Installalo da PyPI: + +```bash +pip install agenteye-evaluator +``` + +Valutatore minimo praticabile: + +```python +import os +from agenteye_evaluator import Evaluator, EvalRequest, EvalResponse + +app = Evaluator(token=os.environ["EVALUATOR_TOKEN"]) + +@app.evaluator +def run(req: EvalRequest) -> EvalResponse: + # Inspect req.events (the full session transcript) and return scores. + tool_calls = sum(1 for e in req.events if e.event_type == "tool_use") + return EvalResponse( + scores={"tool_calls": float(tool_calls)}, + reasoning={"tool_calls": f"{tool_calls} tool invocations in the transcript"}, + summary="tight tool loop" if tool_calls < 5 else "agent looped on tools", + ) +``` + +L'istanza `app` è ASGI-callable, quindi `uvicorn module:app` la esegue. + +Per i valutatori che devono rinviare lavori costosi, restituisci `JobPending` +invece e registra un gestore `@app.job_lookup`; il server AgentEye +esegue il polling di `GET /evaluate/{job_id}` finché non restituisci uno stato terminale o non elapses il +cap `EVALUATOR_MAX_POLL_DURATION_SECS` (predefinito 1 h). + +Riferimento API completo, pattern asincrono e schema eventi: il README di `agenteye-evaluator` +è incluso in ogni tarball di versione sulla +[pagina dei rilasci di agenteye-enterprise](https://github.com/agenteye-enterprise/releases), +o puoi leggerlo sulla pagina PyPI del pacchetto. + +--- + +## Eseguire un valutatore su Kubernetes + +Il valutatore è **il tuo servizio**: AgentEye non fornisce un contenitore +valutatore predefinito. La versione include manifesti Kubernetes di riferimento sotto `deploy/examples/evaluator/` che puoi applicare così come sono +dopo aver sostituito la tua immagine e un token bearer condiviso. + +### 1. Containerizzare il tuo valutatore + +Un Dockerfile minimo per il tuo valutatore: + +```dockerfile +FROM python:3.12-slim +WORKDIR /app +RUN pip install --no-cache-dir agenteye-evaluator uvicorn +COPY my_evaluator.py . +RUN useradd --uid 10001 --create-home --shell /usr/sbin/nologin evaluator \ + && chown -R evaluator:evaluator /app +USER evaluator +EXPOSE 9000 +CMD ["uvicorn", "my_evaluator:app", "--host", "0.0.0.0", "--port", "9000"] +``` + +`runAsNonRoot` (UID 10001) mantiene il contenitore compatibile con i profili +ristretti di Pod Security. + +### 2. Creare il token bearer condiviso + +```bash +kubectl -n agenteye create secret generic evaluator-token \ + --from-literal=token="$(openssl rand -hex 32)" +``` + +Utilizza lo stesso valore di `EVALUATOR_TOKEN` sul server AgentEye. Il +server invia `Authorization: Bearer ` su ogni richiesta; l'SDK +utilizza `hmac.compare_digest` per un controllo a tempo costante e rifiuta +le mancate corrispondenze con HTTP 401. + +### 3. Applicare i manifesti di esempio + +```bash +# Edit deploy/examples/evaluator/deployment.yaml first to point +# `image:` at your registry, then: +kubectl apply -k deploy/examples/evaluator/ +``` + +L'esempio include: + +- Un Deployment con 2 repliche con `runAsNonRoot`, filesystem radice di sola lettura, + tutte le capacità rimosse, liveness + readiness su `/health` +- Un servizio ClusterIP sulla porta 9000 +- Un template `secret.example.yaml` (intenzionalmente escluso da + Kustomization; crea il vero segreto out-of-band in modo che nessun token finisca + in git) + +### 4. Collegare AgentEye a esso + +Sul server AgentEye, imposta: + +```bash +EVALUATOR_ENDPOINT=http://evaluator:9000 +EVALUATOR_TOKEN= +``` + +Il server distribuisce `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH` +richieste simultanee su tutti i pod valutatore (valori predefiniti: `2 × 4 = 8`). +Scala `replicas` e limiti di risorse per pod in coordinamento con questi +parametri lato server. + +### Verifica + +```bash +kubectl -n agenteye port-forward svc/evaluator 9000:9000 +curl -s http://localhost:9000/health # → {"status":"ok"} +``` + +Dopo che un agente viene eseguito end-to-end, `GET /evaluations` sul server +AgentEye dovrebbe restituire una riga con `status: "done"` e i punteggi +prodotti dal tuo valutatore. + +--- + +## Configurazione del server AgentEye + +Imposta sul processo del server: + +| Variabile di ambiente | Significato | +|---|---| +| `EVALUATOR_ENDPOINT` | URL di base del tuo valutatore (`http://evaluator:9000`). Non impostato = pipeline disabilitata. | +| `EVALUATOR_TOKEN` | Token bearer. Deve essere uguale al valore con il quale il servizio valutatore è configurato. | +| `EVALUATOR_WORKERS` | Attività di lavoro per istanza di server (predefinito 2). | +| `EVALUATOR_CLAIM_BATCH` | Righe rivendicate per tick di worker (predefinito 4). I batch vengono elaborati **simultaneamente**; la concorrenza effettiva sull'endpoint del valutatore è `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH`. | +| `EVALUATOR_POLL_IDLE_SECS` | Per quanto tempo un worker dorme tra i tentativi di invio quando nessuna valutazione è dovuta (predefinito 2s). | +| `EVALUATOR_POLLING_INTERVAL_SECS` | Fallback finale per la cadenza di `GET /evaluate/{id}` quando né il `next_poll_secs` per risposta né il `default_poll_interval_secs` del valutatore è impostato (predefinito 10s). | +| `EVALUATOR_REQUEST_TIMEOUT_MS` | Timeout per richiesta (predefinito 30000). | +| `EVALUATOR_MAX_ATTEMPTS` | Dopo questo numero di guasti transitori il risultato viene registrato come `error` terminale (predefinito 5). | +| `EVALUATOR_CONFIG_REFRESH_SECS` | Cadenza di `GET /config` (predefinito 300). | +| `EVALUATOR_MAX_POLL_DURATION_SECS` | Massimo tempo wallclock che una sessione può rimanere nella coda di polling prima di essere terminata come `timeout` (predefinito 3600s). Protegge da un valutatore che continua a restituire `pending` per sempre. | + +Per attivare il punteggio automatico su tutta l'istanza, fornisci il Secret `agenteye-evaluator` con entrambe le chiavi impostate. Nei manifesti Kubernetes in bundle, il server legge `EVALUATOR_ENDPOINT` e `EVALUATOR_TOKEN` da questo Secret facoltativo. Crealo tramite il processo di gestione dei segreti standard della tua organizzazione, quindi riavvia il Deployment del server per acquisire la modifica. + +I parametri di tuning sopra non sono collegati per impostazione predefinita; esponi le variabili di ambiente corrispondenti sul contenitore del server nel tuo manifesto Deployment se hai bisogno di escludere i valori predefiniti. + +Vedere [deployment.md](/it/agenteye/deployment) per la tabella completa delle variabili di ambiente. + +--- + +## Riferimento API + +| Metodo | Percorso | Autorizzazione richiesta | Scopo | +|---|---|---|---| +| `GET` | `/evaluations` | `evaluations:read` | Risultati terminali delle query. Supporta `session_id`, `agent_id`, `environment`, `status` (`done`/`error`/`timeout`), `ts_from`, `ts_to`, `cursor`, `limit`, `score_filters`, `latest_per_session`. `limit` predefinito a 50 ed è limitato a 200 (nota che questo differisce da `/events`, che è limitato a 1000). `environment` accetta un elenco separato da virgole (ad es. `environment=prod,staging`); i singoli valori funzionano ancora. Con `latest_per_session=true` la risposta contiene al massimo una riga per `session_id` (la più recente per `completed_at`) utilizzata dalla pagina dell'elenco delle sessioni per comprimere la timeline di valutazione di una sessione al suo titolo attuale. Predefinito false (restituisce la cronologia completa). | +| `GET` | `/evaluations/aggregate` | `evaluations:read` | Salute della valutazione aggregata per una sezione filtrata: conteggio totale, suddivisione done/error/timeout, statistiche per chiave di punteggio (count/avg/min/max/p50 sulle chiavi `scores` arbitrarie), e una timeline con bucket temporale. Accetta gli **stessi parametri di filtro di `/evaluations`** più `featured_keys` (CSV delle chiavi di punteggio per il trend) e `latest_per_session`. Alimenta la funzione Dashboards; le metriche sono esatte su tutto l'insieme corrispondente, non campionate. | +| `GET` | `/evaluations/environments` | `evaluations:read` | Valori di ambiente distinti dalla tabella `evaluations`. Utilizzato per popolare i dropdown dei filtri scoped ai dati leggibili dalla valutazione. | +| `GET` | `/evaluation-jobs` | `evaluations:read` | Visibilità nelle valutazioni in corso. Filtra per `status` (`pending`/`polling`). | +| `GET` | `/events` | `events:read` | Trasmetti gli eventi grezzi di una sessione. Supporta `session_id`, `agent_id`, `event_type` (CSV), `environment` (CSV), `ts_from`, `ts_to`, `cursor`, `limit`, e `order`. `order` è `desc` (più nuovo prima, il predefinito) o `asc` (più vecchio prima); un valore non riconosciuto ricade su `desc`. Pagina con cursore tramite `next_cursor` della risposta (un id evento): passalo di nuovo come `cursor` per ottenere la pagina successiva; con `asc` la pagina successiva sono gli eventi dopo quell'id, con `desc` gli eventi prima di esso. `limit` predefinito a 50 ed è limitato a 1000. | +| `GET` | `/sessions/:session_id/export` | `events:read` | Restituisce il body JSON esatto che il valutatore riceverà per questa sessione, servito come allegato scaricabile denominato `session-.json`. Utile per riprodurre sessioni di produzione tramite `agenteye-evaluator` per test offline. I byte sono identici a livello di byte a quelli che la pipeline del valutatore invia. | +| `POST` | `/sessions/:session_id/re-evaluate` | `evaluations:trigger` | Accoda una nuova valutazione per una sessione; viene eseguita indipendentemente dal fatto che esista una valutazione precedente. Il nuovo risultato è **aggiunto** alla timeline di valutazione della sessione piuttosto che sovrascrivere quella precedente, quindi i punteggi precedenti rimangono visibili come cronologia. Restituisce `202` on enqueue, `404` per una sessione sconosciuta, `409` se una valutazione è già in corso. Utilizza questo dopo aver distribuito un nuovo valutatore, o per sessioni che non hanno mai emesso `agent_end`. | + +### Filtro per intervallo di punteggio: `score_filters` + +`GET /evaluations` accetta un parametro facoltativo `score_filters` che +restringi i risultati per valori numerici all'interno dell'oggetto `scores`. Il +parametro è un elenco separato da virgole di voci `key:min..max`; entrambi i limiti +possono essere omessi. Più voci si combinano con AND logico. Le righe +in cui la chiave denominata è assente o non numerica sono escluse. Una richiesta può +portare al massimo 20 voci di filtro; il superamento restituisce HTTP 400. + +Esempi: +```text +# helpfulness in [0.5, 0.8] +GET /evaluations?score_filters=helpfulness:0.5..0.8 + +# tool_efficiency at most 0.3 (no lower bound) +GET /evaluations?score_filters=tool_efficiency:..0.3 + +# helpfulness >= 0.5 AND factuality >= 0.9 +GET /evaluations?score_filters=helpfulness:0.5..,factuality:0.9.. +``` + +Ogni oggetto di risposta `/evaluations` ha questi campi: + +| Campo | Tipo | Note | +|---|---|---| +| `evaluation_id` | string (UUID) | L'identificatore canonico per questa valutazione terminale. Ogni valutazione terminale riceve un nuovo UUID; una singola sessione può contenerne più. | +| `id` | string (UUID) | Alias di compatibilità all'indietro che porta lo stesso valore di `evaluation_id`. | +| `session_id` | string | La sessione su cui è stata eseguita questa valutazione. Una sessione può avere più valutazioni nella timeline. | +| `agent_id` | string | Identifica l'agente che ha prodotto la sessione. | +| `environment` | string | Etichetta di ambiente copiata dalla sessione. | +| `status` | enum | Uno di `"done"`, `"error"`, `"timeout"`. | +| `scores` | object \| null | Punteggi restituiti dal tuo valutatore. | +| `reasoning` | object \| null | Mappa facoltativa di giustificazione per punteggio restituita dal tuo valutatore. Le chiavi generalmente rispecchiano quelle in `scores`. La dashboard rende ogni voce sotto la sua barra dei punteggi. | +| `summary` | string \| null | Narrativa facoltativa di paragrafo unico complessiva restituita dal tuo valutatore. La dashboard rende questo sopra la suddivisione per punteggio come titolo della valutazione. | +| `error` | string \| null | Popolato su `"error"` / `"timeout"` solamente. | +| `attempt_count` | integer | Numero di tentativi di invio (≥ 1). | +| `duration_ms` | integer \| null | Durata del tentativo finale. | +| `completed_at` | string (ISO 8601 UTC) | Quando è stato registrato il risultato terminale. I risultati sono ordinati per `completed_at` (più recente prima). | +| `created_at` | string (ISO 8601 UTC) | Porta lo stesso timestamp di `completed_at` (semantica write-once). | + +--- + +## Autorizzazioni + +| Autorizzazione | Concede | +|---|---| +| `evaluations:read` | Elenco risultati di valutazione, visualizza i punteggi nella dashboard e carica le metriche di salute della dashboard. | +| `evaluations:trigger` | Accoda manualmente una valutazione per una sessione tramite `POST /sessions/:session_id/re-evaluate` o il pulsante di rivalutazione della dashboard. | +| `dashboards:read` | Visualizza dashboard salvate (ha anche bisogno di `evaluations:read` per caricare le loro metriche). | +| `dashboards:write` | Crea e modifica dashboard. | +| `dashboards:delete` | Elimina dashboard. | + +L'admin bootstrap (`ADMIN_KEY`, `ADMIN_EMAIL`) riceve automaticamente questi. + +--- + +## Visualizzazione dei risultati + +- **`/sessions/`**: timeline degli eventi + una barra destra che mostra i + punteggi della sessione e qualsiasi errore dal tentativo di invio. Se la tua chiave ha + `evaluations:trigger`, appare un pulsante **re-evaluate** accanto al pulsante di esportazione, + utile per sessioni che non hanno mai emesso `agent_end`, o per + aggiornare i punteggi dopo aver distribuito un nuovo valutatore. La dashboard esegue il polling del + nuovo risultato e aggiorna la barra destra quando arriva. +- **`/sessions`**: griglia delle sessioni filtrabile; la colonna dei punteggi mostra lo stato della valutazione di ogni + sessione e i punteggi a colpo d'occhio. +- **`/dashboards`**: viste di salute eval salvate (vedi [Dashboards](#dashboards) sotto). + +![La griglia Sessions con pillole di stato di valutazione per sessione e badge di punteggio codificati a colori (helpfulness, factuality, tool_efficiency, safety, coherence)](/agenteye/images/sessions-list.png) + +*La griglia delle sessioni mostra lo stato di valutazione e i punteggi di ogni esecuzione a colpo d'occhio; i badge rossi/ambra/verdi fanno saltare all'occhio i punteggi bassi.* + +![Una vista dettagliata della sessione con i punteggi di valutazione e lo stato di invio nella barra destra](/agenteye/images/session-detail.png) + +*L'apertura di una sessione mostra la sua timeline completa insieme ai punteggi di valutazione e qualsiasi errore del dispatcher nella barra destra.* + +--- + +## Dashboard + +La pagina **Dashboards** (`/dashboards`) ti consente di salvare una combinazione di filtri di valutazione +come vista denominata e riutilizzabile e di osservare come sta andando quella sezione di valutazioni a colpo d'occhio. Le dashboard sono **condivise su tutta la tua organizzazione**; +tutti coloro che hanno `dashboards:read` vedono lo stesso set. + +Ogni dashboard fissa: + +- **Filtri**: gli stessi controlli della pagina delle sessioni: ambiente, stato, + agente, una finestra temporale mobile, e filtri di intervallo di punteggio (`key:min..max`). +- **Una configurazione di visualizzazione**: quali chiavi di punteggio presentare, le soglie di salute verde/ambra/rossa, + quali pannelli mostrare, e se comprimere alla valutazione più recente per sessione. + +Ogni scheda mostra il numero di sessioni corrispondenti, una suddivisione done/error/timeout, +la media di ogni punteggio presentato, e una piccola sparkline di trend. L'apertura di una +dashboard mostra i pannelli a dimensioni complete; **"open in sessions"** ti porta nella +pagina delle sessioni pre-filtrata esattamente a quella sezione. Le metriche vengono calcolate +server-side su tutto l'insieme corrispondente (tramite `GET /evaluations/aggregate`), quindi +i numeri sono esatti piuttosto che campionati. + +![Una dashboard di salute eval con barre di punteggio medio per dimensione valutatore, una suddivisione tool ok-vs-error, strumenti principali, e un trend di eventi per ora](/agenteye/images/dashboard-quality.png) + +**Autorizzazioni:** visualizzazione richiede sia `dashboards:read` che `evaluations:read`; +creazione e modifica richiede `dashboards:write`; eliminazione richiede `dashboards:delete`. +L'admin bootstrap riceve automaticamente tutti questi. + +--- + +## Risoluzione dei problemi + +**Le sessioni esistono ma non vengono create valutazioni.** Conferma che `EVALUATOR_ENDPOINT` +è impostato sul processo del server, che il server e il valutatore condividono lo stesso +valore `EVALUATOR_TOKEN`, e che l'endpoint `/health` del valutatore è +raggiungibile dal server. Con `EVALUATOR_ENDPOINT` non impostato la pipeline è no-op. + +**Le valutazioni in corso si accumulano.** Esegui la query `GET /evaluation-jobs` per vedere la +coda in corso. Ispeziona `attempt_count`, `next_attempt_at`, e `last_error` +su ogni riga. Cause comuni: servizio valutatore non raggiungibile o che restituisce 5xx +(ritentativi con backoff), `EVALUATOR_TOKEN` errato (401 è terminale), o un +valutatore asincrono che restituisce `pending` indefinitamente (vedi sotto). + +**Le sessioni sono completate ma nessuna valutazione terminale.** Esegui la query +`GET /evaluation-jobs?status=polling`; il risultato può ancora essere in corso. +Se un job è bloccato in `pending`, il server ha difficoltà a raggiungere il +valutatore; verifica che il valutatore sia in funzione e che `EVALUATOR_TOKEN` corrisponda. + +**`HTTP 401 dal valutatore: bearer token non valido`.** Il `EVALUATOR_TOKEN` +sul server non corrisponde al valore con il quale il servizio valutatore è +configurato. Devono essere identici. + +**Il valutatore asincrono restituisce `pending` per sempre.** Il server esegue il polling di +`GET /evaluate/{job_id}` finché il valutatore non restituisce `done` o `error`, o +finché `EVALUATOR_MAX_POLL_DURATION_SECS` (predefinito 1 h) non elapses. Dopo il cap +la valutazione viene registrata come `timeout` e rimossa dalla coda in corso. +Aumenta `EVALUATOR_MAX_POLL_DURATION_SECS` se il tuo valutatore ha legittimamente bisogno di +più tempo del predefinito. \ No newline at end of file diff --git a/docs/it/agenteye/getting-started.mdx b/docs/it/agenteye/getting-started.mdx new file mode 100644 index 00000000..ed4853bd --- /dev/null +++ b/docs/it/agenteye/getting-started.mdx @@ -0,0 +1,235 @@ +--- +title: "Guida introduttiva ad AgentEye" +description: "Documentazione di AgentEye - Guida introduttiva ad AgentEye." +--- + + +Questa guida ti accompagna attraverso una configurazione completa di AgentEye: distribuire il server e il dashboard, installare il collector su una macchina agente e strumentare il codice dell'agente Python. + +--- + +## Che cos'è AgentEye? + +AgentEye è una **piattaforma di osservabilità e valutazione auto-hosted per agenti AI**. Registra tutto ciò che fanno i tuoi agenti — ogni fase di un'esecuzione — e valuta automaticamente la qualità di ogni esecuzione completata, così puoi vedere come si comportano i tuoi agenti in produzione e rilevare le regressioni prima che lo facciano i tuoi utenti. + +Il flusso dei dati va in una sola direzione: il codice dell'agente emette **eventi** attraverso l'**SDK Python** → un daemon **collector** leggero raggruppa e li invia al **server** → gli eventi e l'analytics vengono archiviati in **ClickHouse** (lo stato operativo come organizzazioni, utenti, chiavi API, dashboard e query salvate risiede in **Postgres**) → esplori tutto nel **dashboard**. + +Quello che ottieni: + +- **Eventi** — la traccia grezza e per-fase di ogni esecuzione di agente (tool call, model call, hook, errori). +- **Sessioni** — quegli eventi aggregati in una riga per esecuzione, ciascuno **automaticamente valutato** e punteggiato. +- **Valutazioni** — punteggi di qualità prodotti dai tuoi servizi di valutazione, così i cali di qualità emergono senza revisione manuale. +- **Query e dashboard** — SQL ClickHouse salvato sui tuoi dati, rappresentato in grafici in dashboard condivisi a livello di organizzazione. +- **Avvisi e incident** — regole di soglia che ti notificano (email, Slack, webhook, in-dashboard) più un flusso di lavoro incident per triaging. +- **CLI e assistente AI** — un client terminal (`agenteye`) e un assistente in-dashboard per fare domande in linguaggio naturale. + +Esegui tutto nella tua infrastruttura, come un singolo stack Docker Compose (questa guida), un'installazione Kubernetes in produzione, o un singolo pod co-locato. Il resto di questa guida configura lo stack Compose da capo a fondo. + +--- + +## Passaggio 1: Autenticazione + +Tutti gli artefatti di AgentEye sono distribuiti dall'organizzazione GitHub `agenteye-enterprise`. Come sviluppatore enterprise puoi generare il tuo GitHub PAT. Segui [enterprise-docs/github-token.md](/it/agenteye/github-token) per i passaggi esatti e le autorizzazioni richieste. + +```bash +export AGENTEYE_TOKEN= + +# Authenticate Docker against GHCR +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +--- + +## Passaggio 2: Distribuire il Server e il Dashboard + +Il server riceve gli eventi dai collector e li rende interrogabili; il dashboard è il luogo in cui li esplori. Gli eventi ingeriti e l'analytics risiedono in ClickHouse (lo store di analytics richiesto), mentre Postgres contiene lo stato operativo come organizzazioni, utenti, chiavi API, dashboard e query salvate. + +**Scarica il file compose pubblicato:** + +```bash +mkdir -p ./agenteye +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + https://raw.githubusercontent.com/agenteye-enterprise/releases/main/docker-compose.yml \ + -o ./agenteye/docker-compose.yml +cd agenteye +``` + +**Imposta i tuoi segreti:** + +Crea un file `.env` in modo che la distribuzione non venga eseguita con le credenziali predefinite `admin`. Come minimo imposta `ADMIN_KEY` e `POSTGRES_PASSWORD`: + +```bash +POSTGRES_PASSWORD=your-db-password +ADMIN_KEY=your-admin-secret +``` + +Esporta anche `ADMIN_KEY` nella tua shell attuale in modo che i passaggi successivi (ad es. il `curl` del Passaggio 3) possano farvi riferimento direttamente: + +```bash +export ADMIN_KEY=your-admin-secret +``` + +**Avvia lo stack:** + +```bash +docker compose up -d +``` + +Questo avvia lo stack completo, incluso lo store di analytics ClickHouse richiesto e una cache Redis opzionale, insieme al server e al dashboard. ClickHouse deve essere healthy affinché il server si avvii. + +Il server è ora in ascolto su `http://localhost:8080` e il dashboard su `http://localhost:3000`. + +Per le distribuzioni in produzione (Postgres personalizzato, TLS, reverse proxy), vedi [enterprise-docs/deployment.md](/it/agenteye/deployment). + +--- + +## Passaggio 3: Creare una Chiave API per il Collector + +Ogni collector si autentica con una chiave API scoped. Usa l'`ADMIN_KEY` che hai impostato al Passaggio 2 per crearne una: + +```bash +curl -s -X POST http://localhost:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{"name":"prod-collector","key":"your-collector-secret","permissions":["events:add"]}' +``` + +Tu fornisci il valore `key` stesso; usalo nella configurazione del collector al Passaggio 4. Vedi [enterprise-docs/api-keys.md](/it/agenteye/api-keys) per la gestione completa delle chiavi. + +--- + +## Passaggio 4: Installare il Collector + +Su ogni macchina che esegue i tuoi agenti AI, installa il daemon collector. + +**Scarica il binario (Linux x86_64):** + +```bash +VERSION=0.0.1-beta.13 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "collector/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-collector-linux-x86_64' +chmod +x agenteye-collector-linux-x86_64 +sudo mv agenteye-collector-linux-x86_64 /usr/local/bin/agenteye-collector +``` + +> Questo scarica il build **Linux x86_64**. Per macOS (Apple Silicon o Intel), Linux arm64, o setup Docker / systemd / launchd, vedi [collector-installation.md](/it/agenteye/collector-installation), che elenca il download per ogni piattaforma — il comando sopra installa un binario Linux che non funzionerà altrove. + +**Configura:** + +```bash +mkdir -p ~/.agenteye +cat > ~/.agenteye/config.json </…`). + +- **Queries** (`//queries`): inizia da una libreria di query salvate e riutilizzabili sui tuoi eventi e valutazioni (preset built-in più i tuoi)… + +![The saved-queries library: a grid of reusable queries, both built-in presets and custom ones](/agenteye/images/queries.png) + + …quindi aprine una nel compositore SQL per modificarla ed eseguirla con risultati live: + +![The SQL query composer running a saved query, with a schema sidebar and a live result grid](/agenteye/images/query-lab.png) + +- **Dashboards** (`//dashboards`): fissa le query come tile di linea, barra, area o torta in dashboard condivisi a livello di organizzazione. + +![A dashboard built from saved queries: an events-per-hour line, an errors-by-type bar, a latency area chart, and tokens-by-model](/agenteye/images/dashboard-fleet.png) + +- **Alerts** (`//alerts`): promuovi qualsiasi soglia in una regola di paging che notifica per email, Slack, webhook o in-dashboard. Vedi [enterprise-docs/alerts.md](/it/agenteye/alerts). + +--- + +## Passaggi Successivi + +- [Deployment](/it/agenteye/deployment): irrigidisci per la produzione +- [API Keys](/it/agenteye/api-keys): gestisci l'accesso +- [Troubleshooting](/it/agenteye/troubleshooting): diagnostica i problemi \ No newline at end of file diff --git a/docs/it/agenteye/github-token.mdx b/docs/it/agenteye/github-token.mdx new file mode 100644 index 00000000..e3d64514 --- /dev/null +++ b/docs/it/agenteye/github-token.mdx @@ -0,0 +1,132 @@ +--- +title: "Configurazione Token GitHub" +description: "Documentazione sulla configurazione del token GitHub di AgentEye." +--- + + +Un Personal Access Token (PAT) di GitHub è la singola credenziale che sblocca ogni artefatto di AgentEye. Con un token puoi scaricare le immagini Docker, ottenere i binari delle release e installare i wheel Python, senza login per componente e senza segreti condivisi da distribuire. Tutti gli artefatti di AgentEye sono distribuiti dall'organizzazione GitHub `agenteye-enterprise`; una volta che la tua organizzazione ottiene l'accesso, ogni sviluppatore o operatore genera e ruota il proprio token, in modo che l'accesso rimanga verificabile e revocabile per persona. + +Imposta il token come variabile di ambiente e credenziale Docker una volta per macchina: + +```bash +export AGENTEYE_TOKEN= +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +> **Nota su username:** GHCR ignora lo username in `docker login` e autentica interamente dal token, quindi qualsiasi valore non vuoto funziona. Questa documentazione usa `-u x` per brevità; i manifest di deployment che creano un secret per il pull delle immagini Kubernetes possono usare uno username più descrittivo come `agenteye-enterprise`. Entrambi sono accettati. + +--- + +## Opzione A: Token Classico (Consigliato) + +Un token classico è la scelta più affidabile per AgentEye, perché il flusso di `docker login` e image-pull di GHCR ha il supporto più ampio e coerente per i token classici. Due scope coprono tutto ciò di cui hai bisogno (pull di immagini e download di asset delle release), quindi ti autentichi una volta e procedi senza risolvere i problemi delle stranezze del registry. Uno di loro, `read:packages`, è veramente di sola lettura; l'altro, `repo`, è l'unico scope classico che concede accesso agli asset privati delle release, ed è deliberatamente ampio — GitHub lo definisce come controllo totale (lettura e scrittura) dei repository privati. + +### 1. Crea il token + +Vai a **GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic) → Generate new token (classic)**. + +| Campo | Valore | +|---|---| +| **Note** | `agenteye-` (es. `agenteye-prod-server`) | +| **Expiration** | Imposta una scadenza appropriata per la tua policy di sicurezza; 90 giorni è un valore predefinito ragionevole | + +> **Nota etichetta:** GitHub etichetta questo campo **Note** per i token classici e **Token name** per i token a grana fine. Servono allo stesso scopo: un identificatore leggibile dall'uomo per il successivo audit e revoca. + +### 2. Seleziona gli scope + +| Scope | Perché è necessario | +|---|---| +| `read:packages` | Eseguire il pull di immagini Docker da `ghcr.io/agenteye-enterprise/` e scaricare asset dei package | +| `repo` | Leggere i contenuti dei repository privati, i file grezzi e gli asset delle release da `agenteye-enterprise/releases`. Questo è lo scope ampio di GitHub per il controllo totale dei repository privati (lettura e scrittura), non uno scope di sola lettura — è semplicemente l'unico scope classico che concede accesso agli asset privati delle release | + +Nessun altro scope è richiesto. + +### 3. Genera e copia il token + +Fai clic su **Generate token** e copia il valore immediatamente; viene mostrato solo una volta. Memorizzalo nel tuo gestore di segreti o nell'ambiente. + +--- + +## Opzione B: Token a Grana Fine + +I token a grana fine limitano l'accesso a repository e permessi specifici, rendendoli l'opzione con i minori privilegi più ristretti. Scegli questo percorso quando la policy di sicurezza della tua organizzazione richiede token a grana fine. + +> **Nota:** il supporto di GHCR per i token a grana fine è meno coerente rispetto ai token classici. Se `docker login` o `docker pull` fallisce dopo aver seguito questi passaggi, torna a un token classico (Opzione A). + +### 1. Crea il token + +Vai a **GitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokens → Generate new token**. + +| Campo | Valore | +|---|---| +| **Token name** | `agenteye-` (es. `agenteye-prod-server`) | +| **Expiration** | Imposta una scadenza appropriata per la tua policy di sicurezza; 90 giorni è un valore predefinito ragionevole | +| **Resource owner** | `agenteye-enterprise` | +| **Repository access** | **Only select repositories** → `agenteye-enterprise/releases` | + +### 2. Imposta i permessi del repository + +Sotto **Permissions → Repository permissions**, imposta: + +| Permesso | Accesso | +|---|---| +| **Contents** | Read-only | +| **Packages** | Read-only | + +Tutti gli altri permessi possono rimanere **No access**. + +> **Nota:** Se le immagini del container (`ghcr.io/agenteye-enterprise/...`) sono pubblicate come package a livello di organizzazione piuttosto che come package collegati al repository, il login Docker potrebbe fallire con permessi limitati al repository. In questo caso, aggiungi un permesso a livello di organizzazione: **Permissions → Organization permissions → Packages: Read-only**. + +### 3. Cosa concede ogni permesso + +| Permesso | Usato per | +|---|---| +| Contents: Read-only | Scaricare `docker-compose.yml`, binari delle release e wheel Python da `agenteye-enterprise/releases` | +| Packages: Read-only | Eseguire il pull di immagini Docker da `ghcr.io/agenteye-enterprise/` | + +### 4. Genera e copia il token + +Fai clic su **Generate token** e copia il valore immediatamente; viene mostrato solo una volta. Memorizzalo nel tuo gestore di segreti o nell'ambiente. + +--- + +## Rotazione di un Token + +Ruotare i token secondo una pianificazione mantiene l'accesso verificabile e limita il raggio di impatto se una credenziale venisse mai esposta. I token possono anche scadere o essere revocati in qualsiasi momento, quindi la rotazione è il modo ordinario per rimanere autenticati. Per ruotare: + +1. Genera un nuovo token usando i passaggi sopra. +2. Aggiorna `AGENTEYE_TOKEN` nel tuo ambiente o gestore di segreti. +3. Autentica di nuovo Docker: `echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin` +4. Revoca il vecchio token in GitHub → Settings → Developer settings → Personal access tokens, quindi apri la sottopagina **Tokens (classic)** o **Fine-grained tokens** che corrisponde al tipo del token e cancellalo. + +--- + +## Verifica il Tuo Token + +Conferma che il token funziona prima di collegarlo a un deployment, in modo che i fallimenti di autenticazione vengono rilevati qui piuttosto che durante il rollout. Ogni comando esercita uno degli scope sopra: + +```bash +# Packages scope - authenticate Docker against GHCR +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin + +# Contents scope - fetch a raw release file +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + https://raw.githubusercontent.com/agenteye-enterprise/releases/main/docker-compose.yml \ + -o /tmp/agenteye-compose-check.yml +``` + +Un `docker login` riuscito conferma lo scope del package; un file scaricato conferma lo scope dei contents. + +--- + +## Risoluzione dei Problemi + +| Sintomo | Causa probabile | Soluzione | +|---|---|---| +| `docker login` restituisce 401 | Token privo di `Packages: Read-only` (a grana fine) o `read:packages` (classico) | Aggiungi lo scope del package e rigenera | +| `curl` restituisce 404 su URL GitHub grezzi | Token privo dello scope `Contents: Read-only` o `repo` | Aggiungi lo scope dei contents e rigenera | +| `gh release download` restituisce 403 | Token non autorizzato per `agenteye-enterprise/releases` | Verifica che il repo sia incluso nell'accesso del repository del token a grana fine, o usa un token classico con scope `repo` | +| Token accettato ma immagini non trovate | Permesso del package a livello di organizzazione mancante sul token a grana fine | Aggiungi il permesso a livello di organizzazione `Packages: Read-only` | + +Per problemi di accesso, contatta `support@exosphere.host`. \ No newline at end of file diff --git a/docs/it/agenteye/health-monitoring.mdx b/docs/it/agenteye/health-monitoring.mdx new file mode 100644 index 00000000..f6f9868a --- /dev/null +++ b/docs/it/agenteye/health-monitoring.mdx @@ -0,0 +1,125 @@ +--- +title: "Health Monitoring" +description: "Documentazione del Health Monitoring di AgentEye." +--- + + +Sappi quando un deployment di AgentEye è **lui stesso** down o degradato, non solo quando +i tuoi agenti si comportano male. Il rilevamento è **nativo di Kubernetes** e, crucialmente, +**indipendente da AgentEye**: legge lo stato dei pod dal control plane di Kubernetes +e verifica le dipendenze hard di AgentEye, quindi funziona anche quando il server, +ClickHouse o Postgres sono quelli che non funzionano. + +Ci sono due livelli. Il primo è integrato; il secondo è opzionale. + +## 1. Readiness consapevole delle dipendenze (integrato) + +Il server espone due endpoint di probe con compiti deliberatamente diversi: + +| Endpoint | Probe | Controlli | Auth | +|---|---|---|---| +| `GET /health` | liveness | il processo è attivo (sempre `{"status":"ok"}`) | nessuno | +| `GET /ready` | readiness | può effettivamente servire: **Postgres + ClickHouse** raggiungibili | nessuno | + +`/ready` ritorna `200` con `"status":"ready"` e ogni controllo `"ok"` quando entrambe +le dipendenze hard sono raggiungibili, e `503` con `"status":"not_ready"` quando +una di esse non è raggiungibile. Entrambe le risposte contengono un piccolo corpo: + +```json +{ "status": "not_ready", + "checks": { "postgres": "ok", "clickhouse": "down", "redis": "not_configured" } } +``` + +Redis è una cache opzionale rispetto a cui il server si degrada, quindi viene segnalata +a scopo informativo ma **non** provoca mai il fallimento della readiness. Mostra `"ok"` +quando una cache è configurata e `"not_configured"` altrimenti; non è mai `"down"`. + +Nei manifest Kubernetes raggruppati la probe di **readiness** punta a `/ready` +e la **liveness** rimane su `/health`. L'effetto: un server che è *in esecuzione ma +non può raggiungere il suo database* viene tolto dal Service e mostra lo stato `NotReady`, +uno stato su cui il tuo cluster monitoring (sotto) può fare un alert, mentre la liveness +rimane economica così che una breve anomalia di dipendenza non attiva mai un pod restart. +La probe usa una soglia di fallimento generosa in modo che un'anomalia momentanea +non faccia fluttuare le repliche fuori dalla rotazione. + +## 2. Pod-failure alerting con Robusta (opzionale) + +[Robusta](https://github.com/robusta-dev/robusta) è un monitor nativo di Kubernetes +che osserva il server API e invia i fallimenti dei pod (`CrashLoopBackOff`, +`OOMKilled`, `ImagePullBackOff`, `Pending`/`NotReady`, `Failed`, eviction) su +Slack. Poiché osserva il control plane invece di chiedere ad AgentEye, invia alert +anche quando AgentEye non può servire affatto. + +Robusta viene fornito come add-on opzionale nel bundle di release. Abilitalo con +il chart Helm standard di Robusta e il piccolo file di valori mostrato di seguito: + +1. Aggiungi il repository del chart e ottieni un **bot token** di Slack (`xoxb-…`) per il canale: + + ```bash + helm repo add robusta https://robusta-charts.storage.googleapis.com + helm repo update + ``` + + Poiché la configurazione di seguito mantiene tutto in-cluster + (`disableCloudRouting: true`), il token proviene da un'app Slack self-hosted: + crea un'app su `https://api.slack.com/apps`, aggiungi lo scope bot `chat:write`, + installala nel tuo workspace, copia il **Bot User OAuth Token** (`xoxb-…`), e + invita il bot al canale (`/invite @your-app`). + +2. Crea un `values.yaml` con un'etichetta per-deployment (`clusterName`) e il tuo + canale Slack, con scope nel namespace `agenteye`: + + ```yaml + clusterName: "acme-prod" # etichetta per-deployment; appare in ogni alert + enablePrometheusStack: false # solo pod-crash alerts; nessuno stack metrico + disableCloudRouting: true # consegna a Slack direttamente, in-cluster + sinksConfig: + - slack_sink: + name: vendor_slack + slack_channel: "agenteye-fleet-health" + api_key: "REPLACE_WITH_SLACK_BOT_TOKEN" # xoxb-… (preferisci --set o un secret) + scope: + include: + - namespace: [agenteye] # solo alert del namespace AgentEye; rimuovi per ampliare + ``` + +3. Installa, fissando `--version` a una release del chart Robusta conosciuta e affidabile + ([releases](https://github.com/robusta-dev/robusta/releases)) così non installi mai + un chart non testato: + + ```bash + helm install robusta robusta/robusta \ + --namespace robusta --create-namespace \ + --version \ + -f values.yaml \ + --set sinksConfig[0].slack_sink.api_key=$ROBUSTA_SLACK_TOKEN + ``` + +### Cosa segnala + +- **Stato del pod** di Kubernetes (quale pod di AgentEye sta fallendo e perché) e il + **image tag** di ogni pod, cioè la **versione** del componente in esecuzione. +- **Nessun dato di evento di AgentEye e nessun dato cliente** esce mai dal cluster. +- I valori raggruppati limitano gli alert al **namespace `agenteye`**, quindi i workload + non correlati nello stesso cluster non vengono segnalati. + +### Un posto per ogni deployment + +Fai puntare il Robusta di ogni deployment a **un canale Slack condiviso**, ciascuno +con il suo `clusterName`. Ogni alert è contrassegnato con quella etichetta, così un +singolo canale mostra la salute dell'intera flotta, e puoi dire quale deployment è +interessato a colpo d'occhio. + +### Interruzioni dell'intero cluster + +Un watcher puramente in-cluster non può segnalare un'**interruzione dell'intero cluster +o della rete** (si interrompe con il cluster). Se lo hai bisogno, abilita il facoltativo +**Robusta UI sink**: imposta `disableCloudRouting: false` e aggiungi un `robusta_sink` +(con un token da `robusta gen-config`) a `sinksConfig`. Aggiunge una dashboard aggregata +multi-cluster e segnala qualsiasi cluster che smette di fare check-in. + +## Troubleshooting + +Vedi la sezione **Health Monitoring** di +[enterprise-docs/troubleshooting.md](/it/agenteye/troubleshooting) per "nessun +alert in arrivo" e "il server continua a fluttuare `NotReady`". \ No newline at end of file diff --git a/docs/it/agenteye/kubernetes-deployment.mdx b/docs/it/agenteye/kubernetes-deployment.mdx new file mode 100644 index 00000000..27f3b5ea --- /dev/null +++ b/docs/it/agenteye/kubernetes-deployment.mdx @@ -0,0 +1,1088 @@ +--- +title: "Guida al Deployment su Kubernetes" +description: "Documentazione della guida al deployment di AgentEye su Kubernetes." +--- + + +Questa guida distribuisce l'intero stack AgentEye su un cluster Kubernetes dedicato: + +- **ClickHouse 24.8** -- archivio canonico per l'analisi di eventi e valutazioni (StatefulSet con volume persistente da 100Gi). Obbligatorio: il server rifiuta di avviarsi senza di esso. +- **PostgreSQL 16** -- archivio relazionale/metadati per organizzazioni, chiavi API, utenti, dashboard, query salvate e autenticazione (StatefulSet con volume persistente da 50Gi) +- **Redis 7.2** -- cache condivisa opzionale e backend di rate-limit; il server e la dashboard si degradano elegantemente se non disponibile +- **AgentEye Server** -- API Rust per l'acquisizione di eventi, l'analisi e la gestione delle chiavi (2 repliche) +- **AgentEye Dashboard** -- interfaccia utente Next.js (2 repliche) +- **Assistente AI (servizio agent)** -- assistente opzionale in sola lettura all'interno della dashboard sulla porta 9100; inerte finché non viene configurato un endpoint LLM +- **Traefik (pubblico)** -- controller di ingresso per il traffico del collector, protetto con mTLS +- **Traefik (dashboard)** -- controller di ingresso per la dashboard, solo VPN/allowlist IP +- **cert-manager** -- certificati TLS e CA mTLS +- **Backup CronJob** -- dump combinato giornaliero di PostgreSQL + ClickHouse alle 03:00 UTC +- **Cert Renewal Monitor** -- avvisi quando i certificati client stanno per scadere + +**Tempo stimato:** 60-90 minuti per un primo deployment. + +Per il modello di deployment gestito in cui Exosphere gestisce tutto questo per conto vostro, consultate [enterprise-docs/managed-deployment.md](/it/agenteye/managed-deployment). + +--- + +## Prerequisiti + +Eseguite ogni comando di verifica prima di iniziare. Ogni controllo deve essere superato. + +| Requisito | Minimo | Comando di Verifica | Risultato atteso | +|---|---|---|---| +| Cluster Kubernetes | 1.27+ | `kubectl version` | Server Version >= v1.27 | +| Kustomize (incluso in kubectl) | Kustomize v1.14+ (incluso in kubectl 1.27+) | `kubectl kustomize --help` | Stampa il testo di utilizzo | +| Helm | v3 | `helm version` | `Version:"v3.x.x"` | +| RBAC cluster-admin | -- | `kubectl auth can-i create namespaces` | `yes` | +| StorageClass predefinita | -- | `kubectl get storageclass` | Almeno una riga contrassegnata come `(default)` | +| Supporto LoadBalancer | -- | Dipende dal cloud (EKS, GKE, AKS supportano questo per impostazione predefinita) | -- | +| GitHub PAT | -- | `echo $AGENTEYE_TOKEN` | Non vuoto (vedere [enterprise-docs/github-token.md](/it/agenteye/github-token)) | +| openssl | -- | `openssl version` | OpenSSL 1.x o 3.x | +| Bucket di archiviazione cloud | -- | Per i backup di PostgreSQL + ClickHouse (S3, GCS o Azure Blob) | -- | + +**Dimensionamento del cluster:** minimo 3 nodi, 4 vCPU / 8 GB RAM ciascuno. Consultate [enterprise-docs/managed-deployment.md](/it/agenteye/managed-deployment) per i requisiti completi. + +### Eseguire tutti i controlli contemporaneamente + +```bash +echo "--- Prerequisites Check ---" +kubectl version --client -o yaml 2>/dev/null | grep -q gitVersion && echo "PASS: kubectl" || echo "FAIL: kubectl not found" +helm version --short 2>/dev/null | grep -q v3 && echo "PASS: helm v3" || echo "FAIL: helm v3 not found" +kubectl auth can-i create namespaces 2>/dev/null | grep -q yes && echo "PASS: cluster-admin" || echo "FAIL: no cluster-admin" +kubectl get storageclass 2>/dev/null | grep -q default && echo "PASS: default StorageClass" || echo "FAIL: no default StorageClass" +[ -n "$AGENTEYE_TOKEN" ] && echo "PASS: AGENTEYE_TOKEN set" || echo "FAIL: AGENTEYE_TOKEN not set" +openssl version >/dev/null 2>&1 && echo "PASS: openssl" || echo "FAIL: openssl not found" +echo "---" +``` + +### Forma del deployment + +L'**endpoint di acquisizione** è servito su un hostname che controllate (ad es. `ingest.your-company.example`). cert-manager richiede un certificato TLS pubblicamente attendibile da Let's Encrypt tramite HTTP-01, pertanto i collector verificano il certificato del server rispetto all'archivio di trust del sistema, senza alcun pinning CA per cliente. + +L'**endpoint della dashboard** funziona allo stesso modo: è servito su un secondo hostname che controllate (ad es. `agenteye.your-company.example`) che punta al LoadBalancer Traefik della dashboard, e cert-manager emette il suo certificato Let's Encrypt attraverso quel LoadBalancer. I browser ottengono un certificato attendibile senza avvisi. + +> **L'emissione del certificato e il rinnovo si convalidano su HTTP-01**, quindi entrambi i LoadBalancer devono essere raggiungibili da Internet pubblico sulla porta 80. Se è necessario limitare l'IP del LoadBalancer della dashboard, coordinare un risolutore DNS-01 con il supporto in anticipo — altrimenti i rinnovi non riescono silenziosamente e il certificato scade. + +--- + +## Ottenere i Manifest + +```bash +git clone https://x:${AGENTEYE_TOKEN}@github.com/agenteye-enterprise/releases.git +cd releases/deploy +``` + +**Testate:** + +```bash +ls base/kustomization.yaml +``` + +Risultato atteso: il file esiste. Se non esiste, il clone non è riuscito -- controllate il vostro `AGENTEYE_TOKEN`. + +**Struttura directory:** + +``` +deploy/ + base/ Base Kustomize condivisa (tutte le risorse K8s) + overlays/ Override specifici del cluster (tag immagini, hostname, risorse) + third-party/ Valori Helm per Traefik, cert-manager e (opzionale) monitoraggio della salute Robusta +``` + +La **base** contiene ogni risorsa necessaria per un deployment completo, inclusi i certificati Let's Encrypt per i due hostname pubblici che configurate nella Fase 3.1. Un **overlay** applica patch alla base per un ambiente specifico (ad es. tag immagini personalizzati, limiti di risorse, collegamento env). La directory **third-party** contiene file di valori Helm per l'infrastruttura esterna. + +> **Monitoraggio della salute (opzionale):** il probe di readiness del server già riflette la salute di Postgres + ClickHouse, e `third-party/robusta/` aggiunge avvisi facoltativi nativi di Kubernetes per i guasti dei pod a Slack. Consultate [enterprise-docs/health-monitoring.md](/it/agenteye/health-monitoring). + +--- + +## Fase 1 -- Infrastruttura di terze parti (~30 min) + +### 1.1 Installare cert-manager + +cert-manager gestisce i certificati TLS per HTTPS e la CA privata utilizzata per i certificati client mTLS. + +```bash +helm repo add jetstack https://charts.jetstack.io +helm repo update + +helm install cert-manager jetstack/cert-manager \ + --namespace cert-manager --create-namespace \ + --set crds.install=true +``` + +**Testate:** + +```bash +kubectl get pods -n cert-manager +``` + +Risultato atteso: 3 pod tutti `Running` -- `cert-manager`, `cert-manager-cainjector`, `cert-manager-webhook`. + +```bash +kubectl get crds | grep cert-manager +``` + +Risultato atteso: almeno `certificates.cert-manager.io`, `clusterissuers.cert-manager.io`, `issuers.cert-manager.io`. + +**Se non riesce:** i pod in `CrashLoopBackOff` di solito significano che i CRD non sono stati installati. Eseguite di nuovo con `--set crds.install=true`. Se i pod webhook non superano il controllo di readiness, aspettate 30 secondi e controllate di nuovo -- possono impiegare un momento per avviarsi. + +--- + +### 1.2 Installare Traefik -- Controller di Acquisizione Pubblico + +Questa istanza Traefik gestisce il traffico del collector su un LoadBalancer **esterno**. Termina TLS e applica mTLS (verifica del certificato client) sull'endpoint di acquisizione. + +```bash +helm repo add traefik https://traefik.github.io/charts +helm repo update + +helm install traefik-public traefik/traefik \ + --namespace traefik-public --create-namespace \ + --version 39.0.8 \ + -f third-party/traefik/values-public.yaml +``` + +**Testate:** + +```bash +kubectl get pods -n traefik-public +``` + +Risultato atteso: 1 pod `Running`. + +```bash +kubectl get ingressclass traefik-public +``` + +Risultato atteso: la IngressClass esiste (non è la classe predefinita). + +**Se non riesce:** controllate `kubectl describe pod -n traefik-public ` per errori di pull dell'immagine o vincoli di risorse. + +--- + +### 1.3 Installare Traefik -- Controller della Dashboard + +Questa istanza Traefik serve la dashboard su un LoadBalancer dedicato, limitato da allowlist IP. + +> **Due meccanismi di allowlist vengono forniti per questa istanza.** Questa guida utilizza `values-dashboard.yaml`, che limita l'accesso con il campo portatile `service.loadBalancerSourceRanges`. Un `values-internal.yaml` parallelo è fornito anche per gli ambienti AWS che preferiscono l'annotazione `service.beta.kubernetes.io/aws-load-balancer-source-ranges`. Scegliete uno e usatelo coerentemente; i passaggi seguenti presuppongono `values-dashboard.yaml`. + +**Prima dell'installazione**, modificate `third-party/traefik/values-dashboard.yaml` per impostare gli IP sorgente consentiti. Il campo `loadBalancerSourceRanges` controlla quali IP possono raggiungere la dashboard. Per impostazione predefinita è impostato su `0.0.0.0/0` (tutti gli IP); limitatelo a VPN, ufficio o IP di uscita noti. + +#### Allowlist di un singolo IP + +```yaml +service: + loadBalancerSourceRanges: + - "/32" +``` + +#### Allowlist di più IP + +Aggiungete una voce per IP o blocco CIDR. Un suffisso `/32` corrisponde a un singolo indirizzo IPv4; un blocco CIDR (ad es. `/24`) corrisponde a un intervallo. Potete mescolare liberamente IP individuali e intervalli: + +```yaml +service: + loadBalancerSourceRanges: + - "203.0.113.10/32" # gateway ufficio + - "203.0.113.11/32" # gateway ufficio di backup + - "198.51.100.0/24" # pool VPN + - "192.0.2.50/32" # IP home dell'ingegnere on-call +``` + +Suggerimenti per mantenere la lista: + +- Mantenete una voce per riga e aggiungete un commento breve `#` identificando il proprietario o lo scopo di ogni IP; questo è ciò che gli operatori futuri utilizzano per decidere se una voce è ancora necessaria. +- Usate sempre la notazione CIDR. Un IP bare come `203.0.113.10` è rifiutato dal provider cloud; usate `203.0.113.10/32`. +- Per gli intervalli IPv6, usate il CIDR equivalente `/128` (singolo indirizzo) o più grande, ad es. `2001:db8::1/128`. Non tutti i provider cloud supportano gli intervalli di origine IPv6; controllate la documentazione del vostro provider su LoadBalancer. +- La lista è un **OR**: il traffico è consentito se la sorgente corrisponde a qualsiasi voce. + +Dopo aver modificato il file, procedete a `helm install` di seguito. Se il controller è già installato, eseguite `helm upgrade` con gli stessi flag, o applicate una patch al Service in fase di esecuzione (sezione successiva). + +#### Aggiornare l'allowlist in fase di esecuzione + +Potete modificare gli IP consentiti senza un upgrade Helm applicando una patch al Service direttamente. **La patch sostituisce l'intera lista**; includete sempre ogni IP che volete mantenere, non solo quello nuovo. + +Per sostituire la lista con una nuova serie di IP: + +```bash +kubectl patch svc traefik-dashboard -n traefik-dashboard \ + -p '{"spec":{"loadBalancerSourceRanges":["203.0.113.10/32","198.51.100.0/24","192.0.2.50/32"]}}' +``` + +Per **aggiungere in modo sicuro** un IP senza perdere le voci esistenti, leggete prima la lista attuale, quindi applicate una patch con il set combinato: + +```bash +# 1. Mostra l'allowlist corrente +kubectl get svc traefik-dashboard -n traefik-dashboard \ + -o jsonpath='{.spec.loadBalancerSourceRanges}' + +# 2. Applica una patch con la lista completa incluso il nuovo IP +kubectl patch svc traefik-dashboard -n traefik-dashboard \ + -p '{"spec":{"loadBalancerSourceRanges":["/32","/32","/32"]}}' +``` + +> Le patch in fase di esecuzione non vengono mantenute in `values-dashboard.yaml`. Per mantenere il cambiamento nei futuri upgrade Helm, aggiornate anche il file di valori e committatelo. + +Quindi installate: + +```bash +helm install traefik-dashboard traefik/traefik \ + --namespace traefik-dashboard --create-namespace \ + --version 39.0.8 \ + -f third-party/traefik/values-dashboard.yaml +``` + +**Testate:** + +```bash +kubectl get pods -n traefik-dashboard +``` + +Risultato atteso: 1 pod `Running`. + +```bash +kubectl get ingressclass traefik-dashboard +``` + +Risultato atteso: la IngressClass esiste. + +--- + +### 1.4 Attendere i LoadBalancer + +Entrambe le istanze Traefik hanno bisogno di IP esterni prima di procedere. + +```bash +kubectl get svc -n traefik-public +kubectl get svc -n traefik-dashboard +``` + +**Testate:** entrambi i servizi mostrano un `EXTERNAL-IP` (non ``). + +Se ancora in sospeso, aspettate l'assegnazione: + +```bash +kubectl get svc -n traefik-public -w +``` + +Premete `Ctrl+C` una volta che l'IP appare. L'assegnazione dell'IP di solito richiede 2-5 minuti. + +**Se non riesce:** `` dopo 10 minuti di solito significa che il provider cloud non può provisioning un LoadBalancer. Controllate: tag della subnet (EKS richiede `kubernetes.io/role/elb`), configurazione VPC, quote di servizio e che l'annotazione LB interna corretta sia impostata per l'istanza interna. + +--- + +## Fase 2 -- Creare Secret (~10 min) + +Tutti i secret vengono creati manualmente prima di distribuire l'applicazione. Ciò garantisce che i valori sensibili non compaiano mai nei file manifest. + +### 2.1 Creare lo namespace + +```bash +kubectl create namespace agenteye +``` + +**Testate:** + +```bash +kubectl get namespace agenteye +``` + +Risultato atteso: stato `Active`. + +--- + +### 2.2 Secret di pull dell'immagine + +Questo secret autentica con `ghcr.io` per fare il pull delle immagini del container AgentEye. Consultate [enterprise-docs/github-token.md](/it/agenteye/github-token) per come generare il vostro PAT. + +```bash +kubectl create secret docker-registry agenteye-image-pull \ + --namespace agenteye \ + --docker-server=ghcr.io \ + --docker-username=agenteye-enterprise \ + --docker-password="${AGENTEYE_TOKEN}" +``` + +**Testate:** + +```bash +kubectl get secret agenteye-image-pull -n agenteye -o jsonpath='{.type}' +``` + +Risultato atteso: `kubernetes.io/dockerconfigjson`. + +**Testate (approfondimento)** -- verificate che il token possa effettivamente fare il pull delle immagini: + +Usate il tag dell'immagine `server` fissato nel `kustomization.yaml` del vostro overlay (attualmente `v0.0.1-beta.48` sia nell'overlay `acme` incluso che nel deployment base). Sostituite il tag di seguito con quello che state distribuendo in modo che questo controllo non diverga tra le versioni: + +```bash +kubectl run test-pull \ + --image=ghcr.io/agenteye-enterprise/server:v0.0.1-beta.48 \ + --overrides='{"spec":{"imagePullSecrets":[{"name":"agenteye-image-pull"}]}}' \ + --restart=Never -n agenteye --command -- echo ok + +# Aspettate qualche secondo per il pull, quindi: +kubectl logs test-pull -n agenteye +kubectl delete pod test-pull -n agenteye +``` + +Risultato atteso: `ok` stampato nei log. + +**Se non riesce:** `ErrImagePull` o `401 Unauthorized` significa che il PAT è non valido o manca l'ambito `read:packages`. Ri-controllate [enterprise-docs/github-token.md](/it/agenteye/github-token). + +--- + +### 2.3 Credenziali PostgreSQL + +```bash +POSTGRES_PASSWORD=$(openssl rand -hex 24) + +kubectl create secret generic agenteye-postgres \ + --namespace agenteye \ + --from-literal=POSTGRES_USER=postgres \ + --from-literal=POSTGRES_PASSWORD="${POSTGRES_PASSWORD}" \ + --from-literal=POSTGRES_DB=agenteye +``` + +> **Importante:** utilizziamo `-hex` (non `-base64`) per generare la password. L'output in base64 può contenere `+`, `/` e `=` che interrompono la stringa di connessione `DATABASE_URL`. Consultate [enterprise-docs/troubleshooting.md](/it/agenteye/troubleshooting) per i dettagli. + +> **Memorizzate `POSTGRES_PASSWORD` nel vostro gestore di segreti immediatamente.** Ve ne avrete bisogno se dovete mai ripristinare da un backup o connettervi al database direttamente. + +**Testate:** + +```bash +kubectl get secret agenteye-postgres -n agenteye +``` + +Risultato atteso: il secret esiste. + +```bash +kubectl get secret agenteye-postgres -n agenteye \ + -o jsonpath='{.data.POSTGRES_PASSWORD}' | base64 -d | wc -c +``` + +Risultato atteso: `48` (24 byte hex = 48 caratteri). + +--- + +### 2.4 Chiave API Admin + +```bash +ADMIN_KEY=$(openssl rand -hex 32) + +kubectl create secret generic agenteye-admin-key \ + --namespace agenteye \ + --from-literal=ADMIN_KEY="${ADMIN_KEY}" +``` + +La chiave admin è la credenziale di bootstrap. Il server la upsert a ogni avvio con tutti i permessi. Usatela per creare chiavi collector limitate nella Fase 7. Consultate [enterprise-docs/api-keys.md](/it/agenteye/api-keys) per il modello di permessi completo. + +> **Memorizzate `ADMIN_KEY` nel vostro gestore di segreti immediatamente.** + +**Testate:** + +```bash +kubectl get secret agenteye-admin-key -n agenteye +``` + +Risultato atteso: il secret esiste. + +--- + +### 2.5 Configurazione dell'autenticazione (accesso alla dashboard) + +La dashboard utilizza email + OTP per l'accesso dell'utente. Senza questo secret il server si avvia comunque e il percorso della chiave API `ADMIN_KEY` continua a funzionare, ma **nessun utente può accedere tramite l'interfaccia utente**. + +Tutte le chiavi sono referenziate come `optional: true` nel manifest base, quindi i secret parziali (o nessun secret affatto) vanno bene; il server ritorna ai valori predefiniti documentati. Raggruppare tutto in un unico secret `agenteye-auth` mantiene la superficie di autenticazione ruotabile in un unico luogo. + +```bash +kubectl create secret generic agenteye-auth \ + --namespace agenteye \ + --from-literal=ADMIN_EMAIL="admin@yourcompany.com" \ + --from-literal=ALLOWED_EMAILS="*@yourcompany.com" \ + --from-literal=SMTP_HOST="smtp.yourprovider.com" \ + --from-literal=SMTP_PORT="587" \ + --from-literal=SMTP_USERNAME="your-smtp-user" \ + --from-literal=SMTP_PASSWORD="your-smtp-password" \ + --from-literal=SMTP_FROM="noreply@yourcompany.com" \ + --from-literal=SMTP_TLS="starttls" \ + --from-literal=DEFAULT_ORG_NAME="Acme Corp" \ + --from-literal=DEFAULT_ORG_SLUG="acme" +``` + +| Chiave | Scopo | +|---|---| +| `ADMIN_EMAIL` | Utente admin di bootstrap. Upserted a ogni avvio con tutti i permessi e protetto da eliminazione/modifiche di permessi tramite la dashboard. Senza di esso, nessun admin è seminato e il primo accesso è impossibile. | +| `ALLOWED_EMAILS` | Allowlist separata da virgola. Supporta indirizzi esatti (`user@example.com`) e wildcard di dominio (`*@example.com`). Senza di esso, **nessun utente può accedere o essere creato**. | +| `SMTP_HOST`, `SMTP_PORT`, `SMTP_USERNAME`, `SMTP_PASSWORD`, `SMTP_FROM` | Relè SMTP per inviare codici OTP. Se `SMTP_HOST` non è impostato, i codici OTP vengono registrati nello stdout del server anziché inviati tramite email (utile per i test di smoke del primo avvio). Fornite tutte le chiavi SMTP insieme per la consegna di email reale. | +| `SMTP_TLS` | Uno di `starttls` (predefinito), `tls` o `none`. | +| `DEFAULT_ORG_NAME`, `DEFAULT_ORG_SLUG` | Opzionale. Date all'organizzazione incorporata `default` un nome di visualizzazione amichevole e uno slug URL in modo che risieda ad es. in `/acme` anziché in `/default`. Applicato **solo al primo avvio**; una volta che rinominate l'organizzazione con `agenteye-orgctl org rename` (consultate §7.6) questi vengono ignorati. Lo slug deve essere 1-40 alfanumerici minuscoli con singoli trattini interni. Lasciate entrambi non impostati per mantenere il `default` generico. | + +> **Memorizzate le credenziali SMTP nel vostro gestore di segreti.** + +**Testate:** + +```bash +kubectl get secret agenteye-auth -n agenteye \ + -o jsonpath='{.data}' | grep -o '"[A-Z_]*"' | sort -u +``` + +Risultato atteso: le chiavi che avete compilato appaiono nell'output. + +--- + +### 2.6 Chiave di isolamento organizzazione multi-tenant (opzionale) + +Saltate questo per un deployment a tenant singolo; il server funziona su un default incorporato dev e serve bene l'unica organizzazione `default`. **Prima di creare una seconda organizzazione**, impostate un forte e stabile `ORG_CH_SECRET`: la password ClickHouse di ogni organizzazione è derivata come `HMAC(ORG_CH_SECRET, org_id)`, quindi il default dev pubblicamente noto produrrebbe credenziali per organizzazione pubblicamente derivabili. Il comando `agenteye-orgctl org create` (consultate [§7.6 Provisioning di organizzazioni](#76-provisioning-di-organizzazioni-multi-tenant)) rifiuta di eseguire mentre il server è ancora sul default dev incorporato. + +```bash +kubectl create secret generic agenteye-org-ch-secret \ + --namespace agenteye \ + --from-literal=ORG_CH_SECRET="$(openssl rand -base64 48)" + +# Riavviate il server in modo che raccolga il nuovo valore. +kubectl -n agenteye rollout restart deployment/server +``` + +Il server legge questo tramite un `secretKeyRef` **opzionale**, quindi un cluster a tenant singolo che non lo crea mai si avvia comunque normalmente. Mantenete il valore **stabile e identico su tutte le repliche**; ruotarlo invalida la password ClickHouse derivata di ogni organizzazione finché il riconcile di avvio non ri-provisioning gli utenti (un riavvio rotante con il valore coerente ovunque lo guarisce). Consultate `deploy/base/server/secret.example.yaml`. + +> **Memorizzate `ORG_CH_SECRET` nel vostro gestore di segreti e non rotelatelo casualmente.** + +--- + +### 2.7 Verificare tutti i secret + +```bash +kubectl get secrets -n agenteye -o custom-columns='NAME:.metadata.name,TYPE:.type' +``` + +Output atteso (tra qualsiasi secret predefinito): + +``` +NAME TYPE +agenteye-admin-key Opaque +agenteye-auth Opaque +agenteye-image-pull kubernetes.io/dockerconfigjson +agenteye-postgres Opaque +agenteye-org-ch-secret Opaque # solo se avete completato §2.6 (multi-tenant) +``` + +I quattro secret principali (`agenteye-admin-key`, `agenteye-auth`, `agenteye-image-pull`, `agenteye-postgres`) devono essere presenti prima di continuare. `agenteye-org-ch-secret` è richiesto solo per deployment multi-tenant (consultate §2.6). + +--- + +## Fase 3 -- Distribuire l'Applicazione (~5 min) + +### 3.1 Configurare gli hostname pubblici + +cert-manager ha bisogno degli hostname di acquisizione e della dashboard prima di poter richiedere i loro certificati Let's Encrypt. Copiate il modello e impostate entrambi: + +```bash +cp base/certificates/domain.env.example base/certificates/domain.env +# Modificate base/certificates/domain.env e impostate: +# INGEST_DOMAIN=ingest.your-company.example (risolve al LB Traefik pubblico) +# DASHBOARD_DOMAIN=agenteye.your-company.example (risolve al LB Traefik della dashboard) +``` + +`domain.env` è gitignored; rimane locale a ogni deployment. Il build kustomize non riesce in modo evidente se una delle due chiavi è mancante. + +> **Il DNS deve risolvere prima.** Non dovete puntare il DNS ai LB ancora (non esistono fino al completamento della Fase 1.2), ma l'emissione ACME nel passaggio 3.2 ripeterà il tentativo finché ogni hostname non si risolva al suo LoadBalancer. Potete impostare il DNS ora (usando i nomi host LB catturati nella Fase 1.4) o procedere e aggiungere i record nella Fase 4. + +--- + +### 3.2 Applicare i manifest + +Applicate la base direttamente per un'installazione pulita, o un overlay se ne avete ritagliato uno per questo ambiente (gli overlay fissano solo tag immagini, variabili env e limiti di risorse; ereditano i certificati e il routing della base): + +```bash +kubectl apply -k base/ +# o +kubectl apply -k overlays// +``` + +L'overlay include la base automaticamente; applicate uno, non entrambi. + +--- + +### 3.3 Aspettare i pod + +```bash +kubectl wait --for=condition=Ready pod -l 'app in (server,dashboard,postgres,clickhouse)' \ + -n agenteye --timeout=180s +``` + +L'attesa è limitata ai pod del piano dati principale. I pod opzionali `agent` (assistente AI) e `redis` vengono avviati insieme a loro; l'assistente rimane inerte fino a quando non fornite il suo endpoint LLM (consultate [enterprise-docs/assistant.md](/it/agenteye/assistant)), e Redis è una cache best-effort, quindi nessuno dei due ha bisogno di essere Ready affinché la piattaforma serva il traffico. + +**Testate:** + +```bash +kubectl get pods -n agenteye +``` + +Risultato atteso (i pod opzionali `agent` e `redis` compaiono anche e raggiungono `Running`): + +``` +NAME READY STATUS RESTARTS AGE +agent-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +clickhouse-0 1/1 Running 0 ... +dashboard-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +dashboard-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +postgres-0 1/1 Running 0 ... +redis-0 1/1 Running 0 ... +server-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +server-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +``` + +**Se non riesce:** + +| Stato Pod | Causa probabile | Comando di Debug | +|---|---|---| +| `ImagePullBackOff` | Secret di pull dell'immagine scadente o PAT | `kubectl describe pod -n agenteye` | +| `CrashLoopBackOff` | Variabili d'ambiente scadenti (ad es. DATABASE_URL) | `kubectl logs -n agenteye` | +| `Pending` | CPU/memoria insufficiente o nessun nodo | `kubectl describe pod -n agenteye` (controllate Events) | + +--- + +### 3.4 Verificare l'archiviazione + +```bash +kubectl get pvc -n agenteye +``` + +Risultato atteso, entrambi con stato `Bound`: + +| PVC | Capacità | Supporta | +|---|---|---| +| `postgres-data-postgres-0` | `50Gi` | Archivio relazionale/metadati PostgreSQL | +| `clickhouse-data-clickhouse-0` | `100Gi` | Archivio di analisi degli eventi ClickHouse + valutazioni | + +Un PVC `redis-data-redis-0` (1Gi) appare anche per la cache opzionale. + +**Se non riesce:** `Pending` significa che nessuna StorageClass può provisioning il volume. Controllate `kubectl get storageclass` e assicuratevi che esista un'impostazione predefinita. Per la produzione, applicate il volume ClickHouse a una StorageClass SSD veloce (ad es. gp3 su AWS, pd-ssd su GCP); la velocità di compattazione soffre su dischi lenti. + +--- + +### 3.5 Verificare i certificati + +```bash +kubectl get certificates -n agenteye +``` + +Risultato atteso: 3 certificati, tutti `Ready: True`: + +| Nome | Emittente | Scopo | +|---|---|---| +| `mtls-ca` | `selfsigned` | CA privata per l'emissione di certificati client mTLS (validità 10 anni) | +| `ingest-tls` | `letsencrypt-prod` | Certificato TLS pubblico per l'endpoint di acquisizione (90 giorni, rinnovato automaticamente) | +| `dashboard-tls` | `letsencrypt-prod` | Certificato TLS pubblico per la dashboard (90 giorni, rinnovato automaticamente) | + +**Se `ingest-tls` o `dashboard-tls` non è Ready:** + +`kubectl describe certificate -n agenteye` e leggete gli Events. Le cause comuni: + +- **DNS non ancora puntato al LB.** Let's Encrypt risolve l'hostname e colpisce la porta 80 per convalidare — `INGEST_DOMAIN` deve risolvere al LB pubblico, `DASHBOARD_DOMAIN` al LB della dashboard. Fino a quando il CNAME/Alias non si propaga, l'ordine rimane `pending`. Una volta che il DNS è corretto, cert-manager ritenta automaticamente (non è necessario eliminare il Certificate). +- **Hostname non sostituito.** Se `dnsNames` continua a leggere `INGEST_DOMAIN_PLACEHOLDER` / `DASHBOARD_DOMAIN_PLACEHOLDER`, avete saltato il passaggio 3.1 -- create `base/certificates/domain.env` e ri-applicate. +- **Il Traefik della dashboard non può servire la sfida** (`dashboard-tls` solo). L'istanza Traefik della dashboard deve essere installata con il file di valori incluso (Fase 1.2), che abilita il provider Ingress scoped che serve il risolutore HTTP-01 di cert-manager. Un'istanza installata senza di esso lascia la sfida non instradabile e l'ordine `pending` per sempre. + +**Se `mtls-ca` non è Ready:** cert-manager stesso non è salubre. Ri-controllate i pod cert-manager dal passaggio 1.1. + +--- + +### 3.6 Verificare i CronJob + +```bash +kubectl get cronjobs -n agenteye +``` + +Risultato atteso: + +| Nome | Pianificazione | Scopo | +|---|---|---| +| `agenteye-backup` | `0 3 * * *` | Backup giornaliero di Postgres + ClickHouse alle 03:00 UTC | +| `cert-renewal-check` | `0 3,15 * * *` | Avvisi di scadenza certificato alle 03:00 e 15:00 UTC | + +--- + +### 3.7 Verificare che il server sia stato avviato correttamente + +```bash +kubectl logs -n agenteye -l app=server --tail=20 +``` + +**Testate:** cercate una linea di avvio che indichi che il server è in ascolto sulla porta 8080. Non dovrebbero esserci errori di connessione al database (il server richiede che sia PostgreSQL che ClickHouse siano raggiungibili prima che riporti Ready). + +**Se non riesce:** la causa più comune è un `POSTGRES_PASSWORD` contenente caratteri non sicuri per URL che interrompono `DATABASE_URL`. Consultate [enterprise-docs/troubleshooting.md](/it/agenteye/troubleshooting). + +--- + +### 3.8 Verificare che la dashboard sia connessa al server + +```bash +kubectl logs -n agenteye -l app=dashboard --tail=20 +``` + +**Testate:** cercate `Ready` nell'output senza errori `ECONNREFUSED` o simili. + +**Se non riesce:** verificate che il Service `server` esista (`kubectl get svc server -n agenteye`) e che `AGENTEYE_SERVER_URL` sia impostato su `http://server:8080` nel deployment della dashboard. + +--- + +## Fase 4 -- Accesso di rete (~5 min) + +### 4.1 Recuperare gli indirizzi LoadBalancer + +```bash +PUBLIC_IP=$(kubectl get svc -n traefik-public \ + -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') + +INTERNAL_IP=$(kubectl get svc -n traefik-dashboard \ + -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') +``` + +> Su AWS EKS, i LoadBalancer restituiscono un hostname invece di un IP. Sostituite `.ip` con `.hostname` nei comandi di cui sopra. + +**Testate:** + +```bash +echo "Public (ingest): $PUBLIC_IP" +echo "Internal (dashboard): $INTERNAL_IP" +``` + +Entrambi devono essere non vuoti. + +--- + +### 4.2 Puntare DNS ai LoadBalancer + +Create record DNS in modo che gli hostname da `base/certificates/domain.env` si risolvano ai loro LoadBalancer — `INGEST_DOMAIN` al LB Traefik **pubblico**, `DASHBOARD_DOMAIN` al LB Traefik della **dashboard**: + +- **AWS Route 53:** record `A` con `Alias = Yes`, target = hostname LB. Non usate A semplice → IP; gli IP ELB ruotano. +- **Qualsiasi altro provider:** `CNAME` dall'hostname all'hostname LB. + +Verificate: + +```bash +dig +short ingest.your-company.example +dig +short agenteye.your-company.example +``` + +Dovrebbe restituire gli stessi indirizzi di `$PUBLIC_IP` e `$INTERNAL_IP` rispettivamente (o, su EKS, risolvere agli stessi hostname `*.elb.amazonaws.com`). + +Una volta che il DNS si risolve, cert-manager termina gli ordini ACME in sospeso dalla Fase 3.5 entro un minuto. Ri-eseguite `kubectl get certificates -n agenteye` finché sia `ingest-tls` che `dashboard-tls` non mostrano `Ready: True`. + +--- + +### 4.3 Raggiungere l'endpoint di acquisizione + +L'endpoint di acquisizione pubblico applica TLS reciproco, quindi ogni richiesta (incluso `/health`) deve presentare un certificato client. Emettete il vostro primo certificato client nella Fase 5; se ne avete uno già, verificate la raggiungibilità ora: + +```bash +curl -s --cert issued//client.crt \ + --key issued//client.key \ + https://ingest.your-company.example/health +``` + +Risultato atteso: `{"status":"ok"}`. Non è necessario `-k` -- il certificato del server è vincolato a una CA pubblica per `INGEST_DOMAIN`, quindi si convalida rispetto all'archivio di trust del sistema. Raggiungete l'endpoint di acquisizione dal suo hostname `INGEST_DOMAIN` (che corrisponde al certificato emesso), non dall'IP/hostname del LoadBalancer raw. + +L'endpoint della dashboard è servito su `DASHBOARD_DOMAIN` con un certificato pubblicamente attendibile e non è dietro mTLS, quindi non `-k` e nessun certificato client è necessario: + +```bash +curl -s https://agenteye.your-company.example/ -o /dev/null -w '%{http_code}\n' +``` + +Raggiungete la dashboard dal suo hostname, non dall'indirizzo LB raw — il certificato è vincolato a `DASHBOARD_DOMAIN`, quindi l'indirizzo raw mostra una mancata corrispondenza del nome del certificato. + +**Se non riesce:** se `curl` blocca, controllate che il LB sia raggiungibile dalla vostra macchina (VPN, security group, regole firewall). Un errore di handshake `certificate required` sull'hostname di acquisizione significa che nessun certificato client è stato presentato; completate prima la Fase 5. Un errore di convalida TLS sull'hostname di acquisizione significa che il certificato del server non ha finito di essere emesso; tornate a Fase 3.5 e risolvete il problema lì. + +--- + +## Fase 5 -- Emettere Certificati Client mTLS (~10 min per cluster) + +I collector si autenticano con **due fattori**: un certificato client (livello di trasporto, prove che la richiesta proviene da un cluster autorizzato) e una chiave API (livello applicazione, prova che la richiesta proviene da un collector con permesso `events:add`). Una chiave persa è inutile senza il certificato; un certificato rubato è inutile senza una chiave valida. + +### 5.1 Emettere un certificato + +Ogni cluster che esegue collector ha bisogno del suo certificato client. Dalla directory dei manifest: + +```bash +cd base/certificates/client-certs +./issue-client-cert.sh +``` + +Sostituite `` con un identificatore significativo (ad es. `us-east-1-prod`, `staging`). + +**Testate:** lo script stampa `==> Done!` ed elenca i file di output. + +```bash +kubectl get certificate mtls-client- -n agenteye +``` + +Risultato atteso: `Ready: True`. + +File di output in `issued//`: + +| File | Scopo | +|---|---| +| `client.crt` | Certificato client (validità 90 giorni) | +| `client.key` | Chiave privata client | +| `ca.crt` | Certificato CA per la verifica del server | +| `collector-mtls-secret.yaml` | Secret Kubernetes pronto da applicare per il cluster del collector | + +--- + +### 5.1b Consegna alternativa: AWS Secrets Manager + +Se il consumer del certificato è un Pod Kubernetes che ha bisogno di `client.crt` e `client.key` su disco -- il caso tipico quando eseguite il agenteye-collector come sidecar nel vostro pod applicazione -- spingete il bundle del certificato in AWS Secrets Manager. Il pod dell'applicazione lo monta quindi tramite il [Secrets Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/) con IRSA, e la rotazione del certificato è completamente senza mani. + +```bash +cd base/certificates/client-certs +export AWS_REGION=us-east-1 # regione dove il vostro carico di lavoro viene eseguito +./issue-client-cert.sh --save-to aws-secrets-manager +``` + +Sulla ri-esecuzione (rinnovo), lo script chiama `PutSecretValue` sullo stesso secret, quindi l'ARN e il nome rimangono stabili. Il CSI Driver raccoglie la nuova versione al suo prossimo poll di rotazione e riscrive i file all'interno del pod. + +**Prerequisiti:** + +- `aws` CLI v2 autenticato al vostro account AWS. +- `jq` installato. +- Variabile d'ambiente `AWS_REGION` impostata. +- Permessi IAM sulla vostra identità di caller (ambito `Resource` a `arn:aws:secretsmanager:::secret:agenteye/mtls-client/*`): + - `secretsmanager:CreateSecret` + - `secretsmanager:DescribeSecret` + - `secretsmanager:PutSecretValue` + - `secretsmanager:TagResource` + +**Cosa fa lo script in questa modalità:** + +| Passaggio | Azione | +|---|---| +| 1 | Emette / ri-estrae il certificato tramite cert-manager (uguale alla modalità predefinita). | +| 2 | Chiama `DescribeSecret` su `agenteye/mtls-client/` per decidere creare-vs-aggiornare. | +| 3 | Al primo avvio: `CreateSecret` con un payload JSON a tre chiavi (`client.crt`, `client.key`, `ca.crt`), taggato `AgentEyeCluster=`. Sui successivi avvii: `PutSecretValue` per pubblicare una nuova versione; tag aggiornato tramite `TagResource`. | +| 4 | Cancella `issued//` solo dopo un caricamento riuscito. In caso di errore, la directory viene conservata in modo che possiate ritentare. | + +**Se il secret è pianificato per l'eliminazione**, lo script non riesce con un messaggio di errore chiaro che vi dice di eseguire `aws secretsmanager restore-secret --secret-id agenteye/mtls-client/` prima di ritentare. + +Per il cablaggio completo del pod (SecretProviderClass, setup IRSA, comportamento di rotazione, troubleshooting) consultate [enterprise-docs/single-pod-deployment.md](/it/agenteye/single-pod-deployment). + +--- + +### 5.2 Verificare che il certificato funzioni + +Testate il certificato emesso rispetto all'ingresso mTLS: + +```bash +curl -sk --cert issued//client.crt \ + --key issued//client.key \ + https://${PUBLIC_IP}/health +``` + +Risultato atteso: `{"status":"ok"}` + +**Se non riesce:** + +| Errore | Causa | Correzione | +|---|---|---| +| `certificate required` | Certificato non presentato | Controllate i percorsi file nel comando `curl` | +| `bad certificate` | Mancata corrispondenza CA | Verificate che `mtls-ca-issuer` abbia emesso il certificato: `kubectl describe certificate mtls-client- -n agenteye` | +| `connection refused` | Hostname sbagliato o LB non raggiungibile | Controllate `/etc/hosts` o DNS | + +--- + +### 5.3 Consegnare al cluster del collector + +Inviate `collector-mtls-secret.yaml` al team che gestisce il cluster del collector. Loro lo applicano: + +```bash +kubectl apply -f collector-mtls-secret.yaml -n +``` + +Quindi configurate il collector per montare il secret e utilizzare i percorsi certificato: + +```json +{ + "tls_cert": "/etc/agenteye/tls/client.crt", + "tls_key": "/etc/agenteye/tls/client.key" +} +``` + +Consultate [enterprise-docs/collector-installation.md](/it/agenteye/collector-installation) per la configurazione completa del collector inclusi i montaggi del volume Kubernetes. + +**Testate (nel cluster del collector):** + +```bash +kubectl get secret agenteye-collector-mtls -n +``` + +Risultato atteso: il secret esiste con 3 chiavi di dati (`client.crt`, `client.key`, `ca.crt`). + +--- + +### 5.4 Ciclo di vita del certificato + +| Proprietà | Valore | +|---|---| +| Validità certificato client | 90 giorni | +| Auto-rinnovo | cert-manager rinnova 15 giorni prima della scadenza | +| Validità CA | 10 anni | +| Avvisi di scadenza | CronJob avvisa 30 giorni prima della scadenza (Fase 6) | + +cert-manager rinnova automaticamente il certificato sul **cluster AgentEye**, ma il certificato rinnovato deve essere ri-consegnato al cluster del collector. Ri-eseguite `issue-client-cert.sh` e ri-applicate `collector-mtls-secret.yaml` prima che il vecchio certificato scada. + +Se state usando `--save-to aws-secrets-manager` (consultate § 5.1b), ri-eseguite lo stesso comando. Lo script chiama `PutSecretValue` sullo stesso secret; i pod che montano il secret tramite il Secrets Store CSI Driver raccolgono la nuova versione al loro prossimo poll di rotazione (predefinito: ogni ora), senza riavvio del pod richiesto. + +--- + +### 5.5 Revocare un certificato + +Per bloccare immediatamente l'accesso del collector di un cluster: + +```bash +kubectl delete certificate mtls-client- -n agenteye +``` + +**Testate:** il comando `curl` dal passaggio 5.2 ora non riesce con un errore di handshake TLS. + +--- + +## Fase 6 -- Monitoraggio del Rinnovo dei Certificati (~2 min) + +Un CronJob incorporato viene eseguito ogni 12 ore (03:00 e 15:00 UTC) e controlla tutti i certificati client etichettati come `agenteye.io/cert-type=mtls-client`. Avvisa quando un certificato è entro 30 giorni dalla scadenza. + +### 6.1 Abilita notifiche Slack (opzionale) + +```bash +kubectl create secret generic cert-renewal-notify-config \ + --namespace agenteye \ + --from-literal=SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL" +``` + +Senza questo secret, il CronJob continua a funzionare e registra lo stato del certificato nello stdout. + +**Testate:** + +```bash +kubectl get secret cert-renewal-notify-config -n agenteye +``` + +Risultato atteso: il secret esiste. + +--- + +### 6.2 Testare il CronJob + +```bash +kubectl create job --from=cronjob/cert-renewal-check test-cert-check -n agenteye + +kubectl wait --for=condition=Complete job/test-cert-check -n agenteye --timeout=60s + +kubectl logs -n agenteye -l job-name=test-cert-check +``` + +Risultato atteso: un elenco di certificati con il loro stato di scadenza. Se il webhook Slack è configurato, controllate il canale Slack per il messaggio di avviso. + +**Se non riesce:** controllate RBAC -- il ServiceAccount del CronJob ha bisogno di permessi `get, list` su risorse Certificate di cert-manager. Verificate con: `kubectl describe role cert-renewal-check -n agenteye`. + +Pulite il job di test: + +```bash +kubectl delete job test-cert-check -n agenteye +``` + +--- + +## Fase 7 -- Verificare End-to-End + +Questa fase conferma che l'intero pipeline funziona: controllo di salute, creazione della chiave, acquisizione di eventi e visualizzazione della dashboard. + +> **Nota:** gli esempi di seguito raggiungono l'endpoint di acquisizione dal suo indirizzo LoadBalancer raw (`${PUBLIC_IP}`) per comodità, motivo per cui passano `-k`; il certificato del server è vincolato a `INGEST_DOMAIN`, non all'IP LB, quindi il controllo del nome host è saltato. L'endpoint di acquisizione applica TLS reciproco su **ogni** percorso, quindi ogni chiamata deve presentare un certificato client (`--cert`/`--key`). Per convalidare il certificato pubblico pure, puntate a `https://ingest.your-company.example/...` anziché `${PUBLIC_IP}` e lasciate cadere `-k`. + +### 7.1 Controllo di salute + +```bash +curl -sk --cert issued//client.crt \ + --key issued//client.key \ + https://${PUBLIC_IP}/health +``` + +Risultato atteso: `{"status":"ok"}` con HTTP 200. + +--- + +### 7.2 Creare chiavi collector limitate + +La chiave admin è per il bootstrap e la gestione. Create chiavi dedicate `events:add` per i collector: + +```bash +COLLECTOR_KEY=$(openssl rand -hex 32) + +curl -sk -X POST https://${PUBLIC_IP}/keys \ + --cert issued//client.crt \ + --key issued//client.key \ + -H "Authorization: Bearer ${ADMIN_KEY}" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "prod-collector", + "key": "'"${COLLECTOR_KEY}"'", + "permissions": ["events:add"] + }' +``` + +**Testate:** la risposta include `"id"`, `"name": "prod-collector"`, `"permissions": ["events:add"]`, `"created_at"`. + +**Testate:** verificate che la chiave appaia nell'elenco di chiavi: + +```bash +curl -sk https://${PUBLIC_IP}/keys \ + --cert issued//client.crt \ + --key issued//client.key \ + -H "Authorization: Bearer ${ADMIN_KEY}" +``` + +Risultato atteso: `prod-collector` appare nella risposta. + +Consultate [enterprise-docs/api-keys.md](/it/agenteye/api-keys) per il riferimento di gestione completo delle chiavi. + +--- + +### 7.3 Acquisire un evento di test + +```bash +echo '{"session_id":"test","agent_id":"smoke-test","type":"test","timestamp":"2026-04-20T00:00:00Z"}' \ + | curl -sk --cert issued//client.crt \ + --key issued//client.key \ + -H "Authorization: Bearer ${COLLECTOR_KEY}" \ + -H "Content-Type: application/x-ndjson" \ + --data-binary @- \ + https://${PUBLIC_IP}/events +``` + +Risultato atteso: `{"accepted":1,"skipped":0}` con HTTP 200. + +**Se non riesce:** + +| Codice di stato HTTP | Causa | +|---|---| +| 401 | Chiave API non valida o mancante | +| 403 | La chiave manca del permesso `events:add` | +| Errore di handshake TLS | Problema del certificato client -- consultate il troubleshooting della Fase 5 | + +--- + +### 7.4 Verificare che l'evento appaia nella dashboard + +Aprite `https://agenteye.your-company.example` (il vostro `DASHBOARD_DOMAIN`) in un browser. Il certificato è pubblicamente attendibile, quindi non c'è avviso. + +> Se il LoadBalancer della dashboard è limitato dall'allowlist IP e non potete connettervi, verificate che il vostro IP sia consentito: +> ```bash +> kubectl get svc traefik-dashboard -n traefik-dashboard -o jsonpath='{.spec.loadBalancerSourceRanges}' +> ``` +> Ricordate che Let's Encrypt rinnova il certificato della dashboard su HTTP-01 sulla porta 80, e gli intervalli di origine si applicano all'intero LoadBalancer — prima di limitarlo agli intervalli aziendali, coordinare un risolutore DNS-01 con il supporto o i rinnovi non riescono silenziosamente. + +**Testate:** l'evento smoke-test dovrebbe apparire nell'elenco di eventi con sessione `test` e agent `smoke-test`. + +**Se non riesce:** controllate i log della dashboard (`kubectl logs -n agenteye -l app=dashboard --tail=50`). Verificate che `AGENTEYE_SERVER_URL` e `AGENTEYE_API_KEY` siano impostati correttamente. + +--- + +### 7.5 Testare il CronJob di backup + +```bash +kubectl create job --from=cronjob/agenteye-backup test-backup -n agenteye + +kubectl wait --for=condition=Complete job/test-backup -n agenteye --timeout=300s + +kubectl logs -n agenteye -l job-name=test-backup +``` + +Risultato atteso: `Backup created: agenteye-YYYYMMDD-HHMMSS.tar.gz (NNN)` nei log; l'archivio raggruppa il dump di Postgres e le tabelle ClickHouse. + +> Il passaggio di caricamento S3 è cablato nella CronJob e viene eseguito ogni volta che `BACKUP_BUCKET` è impostato (la base spedisce un valore di bucket predefinito). Viene saltato solo quando `BACKUP_BUCKET` è vuoto o letteralmente `PLACEHOLDER`. Puntatealo al vostro bucket proprio e concedete al ServiceAccount `agenteye-backup` l'accesso in scrittura prima di fare affidamento su di esso (consultate la sezione Backup di seguito). + +Pulite: + +```bash +kubectl delete job test-backup -n agenteye +``` + +--- + +### 7.6 Provisioning di organizzazioni (multi-tenant) + +Saltate questo per un deployment a tenant singolo; tutti i dati risiedono nell'organizzazione `default` incorporata e nulla qui è richiesto. + +Se state eseguendo più tenant isolati, le organizzazioni e le loro appartenenze vengono create con la **CLI `agenteye-orgctl`**. Viene fornita **all'interno dell'immagine del server** (insieme a `agenteye-server`) e lo eseguite **all'interno del Deployment `server` esistente con `kubectl exec`**; non c'è un pod, Job o Deployment separato, e nessuna API HTTP o pulsante della dashboard per il ciclo di vita del tenant.** L'esecuzione nel pod del server significa che riusa `DATABASE_URL`, `CLICKHOUSE_URL` e il `ORG_CH_SECRET` dal pod §2.6. + +> **Prerequisito:** completate prima §2.6. `org create` rifiuta di eseguire mentre il server è ancora sul `ORG_CH_SECRET` dev incorporato, e l'utente ClickHouse per organizzazione che provisioning dipende da quel secret essendo forte e stabile. + +**Creare un'organizzazione e aggiungere il suo primo admin:** + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org create --slug acme --name "Acme Corp" + +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member add --org acme --email alice@acme.example --set admin +``` + +Il nuovo membro riceve un OTP al primo accesso della dashboard e quindi funziona interamente nell'interfaccia utente sotto il prefisso URL dell'organizzazione (ad es. `/acme/...`). + +**Altri comandi** (eseguiti nello stesso modo `kubectl -n agenteye exec deploy/server -- agenteye-orgctl …`): + +| Comando | Cosa fa | +|---|---| +| `org list` | Elenca le organizzazioni e il loro stato. | +| `org rename --slug --name ` | Rinomina un'organizzazione (slug invariato). | +| `org delete --slug ` | Soft-delete + rilascia l'utente ClickHouse dell'organizzazione; **dati conservati**. | +| `org purge --slug ` | Wipe dei dati irreversibile; l'organizzazione deve essere prima `delete`d; mai l'organizzazione `default`. | +| `member list --org ` | Elenca i membri e i loro permessi. | +| `member update --org --email [--set ...] [--add ...] [--remove ...]` | Modificare i permessi di un membro. | +| `member remove --org --email ` | Rimuovere un membro dall'organizzazione. | + +I set di permessi incorporati sono `admin`, `standard` e `read-only`. **Le chiavi API per organizzazione sono comunque coniate nella dashboard/API dai membri dell'organizzazione (il §7.2 mostra l'API delle chiavi); solo il ciclo di vita dell'organizzazione + membro è solo per l'operatore.** Riferimento completo e un esempio funzionante: [enterprise-docs/tenant-management.md](/it/agenteye/tenant-management). + +--- + +## Checklist Post-Deployment + +Usate questa checklist per confermare che tutto funziona. Ogni elemento dovrebbe essere controllato prima di consegnare ai collector. + +- [ ] Tutti i pod `Running` nello spazio dei nomi `agenteye` +- [ ] PVC PostgreSQL bound (50Gi) e PVC ClickHouse bound (100Gi) +- [ ] Tutti e 3 i certificati `Ready: True` +- [ ] Entrambi gli IP LoadBalancer assegnati +- [ ] DNS o `/etc/hosts` configurato e che si risolve +- [ ] `/health` restituisce HTTP 200 +- [ ] Test del certificato mTLS superato (`curl` con certificato client a `/health`) +- [ ] Chiave collector scoped creata e testata +- [ ] Evento di test acquisito (`accepted: 1`) +- [ ] Evento visibile nella dashboard +- [ ] Certificati client emessi per ogni cluster del collector +- [ ] CronJob di backup testato manualmente +- [ ] CronJob di rinnovo certificato testato manualmente +- [ ] Webhook Slack per avvisi di certificato configurato (opzionale) +- [ ] Bucket di backup configurato nell'overlay (consultate di seguito) +- [ ] Chiave admin e password Postgres memorizzate nel gestore di segreti + +--- + +## Backup + +Un singolo `agenteye-backup` CronJob viene eseguito ogni giorno alle 03:00 UTC. Esegue il dump di **entrambi** gli archivi: PostgreSQL (stato relazionale) e ClickHouse (le tabelle di analisi `events` + `evaluations`), in un archivio compresso nel pod, quindi lo carica nello spazio di archiviazione che controllate nell'overlay. + +Ogni esecuzione produce un oggetto, `agenteye-.tar.gz`, che si decomprime in: + +``` +postgres.sql # pg_dump del database relazionale +events.sql # DDL della tabella degli eventi ClickHouse +events.native # Dati degli eventi ClickHouse (formato Native) +evaluations.sql # DDL della tabella delle valutazioni ClickHouse +evaluations.native # Dati delle valutazioni ClickHouse +``` + +ClickHouse viene letto sulla sua API HTTP (lo stesso endpoint che il server utilizza), quindi il job non ha bisogno di nessun client ClickHouse. Solo le due tabelle fisiche vengono scritte; il server ricrea tutte le viste (`agent_sessions`, gli alias `analytics.*`) e le politiche di riga all'avvio, quindi quelle tabelle sono l'immagine completa. + +### Configurare il caricamento cloud + +Il CronJob di backup viene fornito con il passaggio di caricamento S3 (`aws s3 cp`) \ No newline at end of file diff --git a/docs/it/agenteye/managed-deployment.mdx b/docs/it/agenteye/managed-deployment.mdx new file mode 100644 index 00000000..f48d19dd --- /dev/null +++ b/docs/it/agenteye/managed-deployment.mdx @@ -0,0 +1,172 @@ +--- +--- +title: "Distribuzione Gestita nel Vostro Cluster Kubernetes" +description: "Documentazione della distribuzione gestita di AgentEye nel vostro cluster Kubernetes." +--- + + +AgentEye è una piattaforma di osservabilità e valutazione auto-ospitata per agenti AI e LLM. Cattura sessioni di agenti, chiamate di strumenti, richieste di modelli ed errori, li trasforma in analytics e valutazioni ricercabili, e presenta i risultati in un dashboard con un assistente AI facoltativo in sola lettura. + +Nel modello di distribuzione gestita, voi fornite un cluster Kubernetes dedicato ed Exosphere esegue l'intera piattaforma al suo interno, distribuendo, configurando, operando, eseguendo il backup e aggiornando ogni componente per vostro conto. Il vostro team ottiene il valore della piattaforma (visibilità degli agenti, analytics, valutazione e l'assistente facoltativo) senza gestire database, certificati o aggiornamenti. Tutti i dati rimangono all'interno del vostro account cloud. + +--- + +## Prerequisiti + +- Un **GitHub PAT** per scaricare immagini di container e artefatti (vedere [Configurazione del Token GitHub](/it/agenteye/github-token)) +- Un **cluster Kubernetes dedicato** (vedere i requisiti di seguito) +- Un **bucket di storage** per i backup del database +- **Connettività di rete**: porta 443 in ingresso al load balancer del cluster + +--- + +## Fase 1: Provisioning di un Cluster Kubernetes Dedicato + +Creare un cluster Kubernetes dedicato ad AgentEye. Non deve essere condiviso con altri carichi di lavoro, in modo che l'intera piattaforma (servizi applicativi, database, analytics e caching) funzioni in isolamento senza impattare l'infrastruttura esistente. + +| Requisito | Dettagli | +|---|---| +| **Distribuzione** | Qualsiasi Kubernetes conforme: EKS, GKE, AKS, o auto-gestito | +| **Versione** | 1.27 o successiva | +| **Pool di nodi** | Minimo: **3 nodi, 4 vCPU / 8 GB RAM ciascuno** (istanze general-purpose standard) | +| **Storage** | Una StorageClass predefinita che provisioning di volumi a blocchi (es. `gp3` su AWS, `pd-ssd` su GCP) | +| **Load Balancer** | Il cluster deve essere in grado di effettuare il provisioning di servizi LoadBalancer nel cloud (predefinito su EKS, GKE, AKS) | + +> Exosphere installa e gestisce tutto il resto all'interno del cluster: controller di ingress, certificati TLS, database, caching, monitoraggio e tutte le distribuzioni di applicazioni. + +--- + +## Fase 2: Concedere Accesso al Team di AgentEye + +Exosphere ha bisogno di accesso cluster-admin (o RBAC ampio equivalente) per gestire namespace, definizioni di risorse personalizzate, controller di ingress e provisioner di storage. + +| Requisito | Dettagli | +|---|---| +| **Metodo di accesso** | Ruolo IAM (preferito per EKS/GKE), kubeconfig, o accesso basato su SSO | +| **VPN / bastion** | Se il server API Kubernetes è privato, fornire credenziali VPN o accesso bastion per il team delle operazioni Exosphere | + +--- + +## Fase 3: Configurare la Connettività di Rete + +Il vostro team di rete deve permettere il traffico in ingresso sulla **porta 443** ai load balancer del cluster. La distribuzione esegue due load balancer separati: uno per l'acquisizione di eventi (protetto da mTLS) e uno per il dashboard: + +| Traffico | Sorgente | Destinazione | Sicurezza | +|---|---|---|---| +| **Acquisizione di eventi** | Pod di raccolta nei vostri cluster | LoadBalancer di acquisizione, porta 443 | mTLS (certificato client) + chiave API | +| **Dashboard** | Browser degli sviluppatori | Dashboard LoadBalancer, porta 443 | HTTPS nel vostro dominio, accesso OTP email senza password | + +L'endpoint di acquisizione è protetto da TLS reciproco; i raccoglitori devono presentare un certificato client valido **e** una chiave API valida ad ogni richiesta. Il dashboard funziona nel suo load balancer e hostname separati, con l'accesso limitato agli indirizzi email/domini che avete consentito. + +**Record DNS (una tantum):** voi create due record CNAME in un dominio che controllate — uno per l'endpoint di acquisizione e uno per il dashboard (es. `agenteye.your-company.example`) — puntando ai nomi host del load balancer che Exosphere fornisce. Exosphere provisioning automaticamente certificati TLS pubblicamente affidabili per entrambi i nomi host, inclusi i rinnovi. + +> **Nota porta 80:** il rilascio automatico dei certificati e il rinnovo si validano sulla porta 80 di ogni load balancer tramite HTTP. Se la vostra postura di sicurezza richiede di limitare il dashboard load balancer a intervalli IP aziendali, comunicatelo a Exosphere — passiamo alla convalida dei certificati basata su DNS (un record DNS extra dal vostro lato) in modo che i rinnovi continuino a funzionare dietro la restrizione. + +> **In uscita:** I nodi del cluster hanno bisogno di accesso a Internet per scaricare immagini di container da `ghcr.io`. Se la vostra rete limita il traffico in uscita, consentite `ghcr.io` o specchiate le immagini nel vostro registro interno. + +--- + +## Fase 4: Fornire un Bucket di Storage per il Backup + +I backup del database sono archiviati in un bucket di cloud storage che voi possedete. + +| Requisito | Dettagli | +|---|---| +| **Servizio** | S3 (AWS), GCS (GCP), o Azure Blob Storage | +| **Accesso** | Concedere accesso in scrittura ai nodi del cluster tramite ruolo IAM per account di servizio (IRSA su EKS, Workload Identity su GKE) o fornire credenziali | +| **Conservazione** | Voi controllate la politica del ciclo di vita del bucket (periodo di conservazione, regole di archiviazione). Exosphere scrive i backup; voi decidete quanto tempo conservarli | + +Un singolo backup giornaliero esegue il dump sia di PostgreSQL (stato relazionale) che di ClickHouse (eventi e valutazioni) in un singolo archivio compresso e lo carica nel vostro bucket. I backup vengono eseguiti anche prima di ogni aggiornamento. + +--- + +## Fase 5: Designare un Punto di Contatto + +Fornite una persona o un canale Slack/Teams dal vostro lato per i problemi a livello di cluster: salute dei nodi, limiti dell'account cloud, modifiche di rete. Le operazioni quotidiane non coinvolgono questo contatto. + +--- + +## Cosa Distribuiamo + +Una volta che Exosphere ha accesso al cluster, i seguenti componenti vengono distribuiti e gestiti per voi: + +| Componente | Ruolo | +|---|---| +| **Server AgentEye** | API HTTP che riceve eventi dai raccoglitori, esegue analytics e fornisce dati al dashboard | +| **Dashboard** | Interfaccia web per visualizzare sessioni di agenti, chiamate di strumenti, richieste di modelli ed errori; ospita l'assistente AI facoltativo in sola lettura | +| **ClickHouse** | Archivio canonico obbligatorio per eventi acquisiti, analytics e valutazioni | +| **PostgreSQL** | Archivio relazionale per organizzazioni, chiavi API, utenti, dashboard e query salvate | +| **Redis** | Cache condivisa facoltativa e backend per limitare la frequenza; la piattaforma si degrada elegantemente se non disponibile | +| **Assistente AI (facoltativo)** | Container assistente interno in sola lettura; rimane disabilitato fino a quando non viene configurato un endpoint LLM | +| **Controller di ingress** | Due load balancer (uno per acquisizione protetta da mTLS, uno per il dashboard) che terminano TLS con certificati pubblicamente affidabili e auto-rinnovati e applicano mTLS nell'endpoint di acquisizione | +| **cert-manager** | Automatizza il provisioning di certificati TLS e il rilascio di certificati client mTLS | +| **Monitoraggio certificati** | Un lavoro pianificato verifica la scadenza dei certificati e invia avvisi (es. a Slack) quando i certificati si avvicinano al rinnovo | + +L'offerta gestita opera anche la pipeline di valutazione della piattaforma, che valuta l'attività dell'agente rispetto ai vostri criteri di valutazione. Vedere [Assistant](/it/agenteye/assistant) e [Evaluation Suite](/it/agenteye/evaluation-suite) per cosa queste funzionalità forniscono. + +--- + +## Cosa Vi Forniamo + +Dopo il completamento della distribuzione, ricevete: + +| Elemento | Dettagli | +|---|---| +| **URL del Dashboard** | Un nome host sotto il vostro dominio (es. `https://agenteye.your-company.example`), fornito con un certificato TLS pubblicamente affidabile e auto-rinnovato. Voi create un CNAME al nome host del load balancer che forniamo; l'accesso è passwordless OTP email | +| **Endpoint di raccolta** | Il percorso `/events` del nome host di acquisizione (es. `https://ingest.your-company.example/events`), protetto da mTLS | +| **Bundle certificato client** | Per cluster: certificato client, chiave privata e certificato CA consegnati come manifesto Kubernetes Secret. Applicateli una volta per cluster | +| **GitHub PAT** | Per scaricare i binari del raccoglitore e i pacchetti Python SDK | +| **Chiavi API del raccoglitore** | Chiavi ambite con permesso `events:add`, una per distribuzione di raccoglitore | +| **Guide di installazione** | Documentazione passo passo per il raccoglitore e Python SDK | + +--- + +## Cosa Fate Dopo la Configurazione + +Il vostro unico lavoro in corso è sulle vostre proprie macchine di agenti, non sul cluster AgentEye: + +1. **Installare il raccoglitore** in ogni cluster Kubernetes che esegue agenti AI: montare il certificato client e configurare l'URL dell'endpoint e la chiave API. Vedere [Installazione del Raccoglitore](/it/agenteye/collector-installation). +2. **Integrare Python SDK** nel vostro codice di agente. Vedere [Python SDK](/it/agenteye/python-sdk). +3. **Aprire il dashboard** nel vostro browser per visualizzare l'attività dell'agente. + +Nessuna operazione di cluster, nessuna gestione di database, nessun rinnovo di certificati, nessun aggiornamento. + +--- + +## Sicurezza + +- **I dati rimangono nel vostro account cloud.** Il cluster, lo storage e i database vengono tutti eseguiti nel vostro ambiente. Nessun dato esce dal vostro confine. +- **Voi controllate l'accesso.** Il cluster è nel vostro account. Potete controllare, monitorare o revocare l'accesso di Exosphere in qualsiasi momento. Tutte le operazioni passano attraverso il registro di audit del vostro cloud (CloudTrail, GCP Audit Logs, ecc.). +- **mTLS su acquisizione di eventi.** Ogni richiesta del raccoglitore richiede sia un certificato client valido che una chiave API. Una chiave trapelata è inutile senza il certificato; un certificato rubato è inutile senza una chiave valida. +- **Controllo dell'accesso al dashboard.** Il dashboard funziona nel suo load balancer separato, distinto dall'acquisizione di eventi, e l'accesso è passwordless OTP email limitato agli indirizzi email/domini che consentite. Un elenco di intervalli IP sorgente nel load balancer è disponibile su richiesta; poiché il rinnovo automatico del certificato deve raggiungere il load balancer, Exosphere accoppia la restrizione alla convalida del certificato basata su DNS in modo che i rinnovi continuino a funzionare. +- **Certificati per cluster.** Ognuno dei vostri cluster riceve il suo certificato client. Se un cluster viene compromesso, quel certificato viene revocato indipendentemente senza influire sugli altri. + +--- + +## Timeline di Distribuzione + +| Fase | Durata | Vostro coinvolgimento | +|---|---|---| +| **Provisioning del cluster** | 1-2 giorni | Effettuare il provisioning del cluster e concedere accesso a Exosphere | +| **Configurazione della piattaforma** | 1 giorno | Nessuno; Exosphere installa tutti i componenti infrastrutturali | +| **Distribuzione dell'applicazione** | 1 giorno | Nessuno; Exosphere distribuisce il server, il dashboard e crea chiavi API | +| **Rollout del raccoglitore** | 1-3 giorni | Installare i raccoglitori nei vostri cluster (con guida da Exosphere) | +| **Rodaggio in produzione** | 1 settimana | Nessuno; Exosphere monitora e ottimizza | + +Totale tipico: **~2 settimane** dal via ai ready per la produzione. + +--- + +## Supporto + +Per domande o problemi, contattate Exosphere a `support@exosphere.host`. + +--- + +## Passaggi Successivi + +- [Guida Introduttiva](/it/agenteye/getting-started): procedura dettagliata end-to-end +- [Installazione del Raccoglitore](/it/agenteye/collector-installation): installa e configura il raccoglitore +- [Python SDK](/it/agenteye/python-sdk): strumenta il tuo codice di agente +- [Chiavi API](/it/agenteye/api-keys): gestisci accesso e permessi +- [Risoluzione dei Problemi](/it/agenteye/troubleshooting): problemi comuni e soluzioni \ No newline at end of file diff --git a/docs/it/agenteye/python-sdk.mdx b/docs/it/agenteye/python-sdk.mdx new file mode 100644 index 00000000..e4376f72 --- /dev/null +++ b/docs/it/agenteye/python-sdk.mdx @@ -0,0 +1,388 @@ +--- +--- +title: "Python SDK" +description: "Documentazione AgentEye Python SDK." +--- + + +AgentEye Python SDK ti offre visibilità completa sul comportamento dei tuoi agenti (ogni esecuzione dell'agente, chiamata di strumento, richiesta al modello, hook e intervento umano) per poter effettuare debug, audit e valutazione. Instrumenta il codice del tuo agente scrivendo eventi strutturati in file JSONL locali; il daemon collector li raccoglie e li invia automaticamente alla piattaforma. + +--- + +## Installazione + +Scarica il wheel da GitHub Releases usando il tuo `AGENTEYE_TOKEN`. Se non hai ancora un token, consulta [GitHub Token Setup](/it/agenteye/github-token) per i passaggi di configurazione e le autorizzazioni richieste. + +**Usando `gh` CLI + pip:** + +```bash +VERSION=0.0.1b9 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "python-sdk/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-*.whl' +pip install "agenteye-${VERSION}-py3-none-any.whl" +``` + +**Usando `gh` CLI + uv:** + +```bash +VERSION=0.0.1b9 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "python-sdk/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-*.whl' +uv add "./agenteye-${VERSION}-py3-none-any.whl" +``` + +**Usando curl (senza `gh` CLI):** + +```bash +VERSION=0.0.1b9 +curl -fsSL \ + -H "Authorization: Bearer $AGENTEYE_TOKEN" \ + -L \ + "https://github.com/agenteye-enterprise/releases/releases/download/python-sdk%2Fv${VERSION}/agenteye-${VERSION}-py3-none-any.whl" \ + -o "agenteye-${VERSION}-py3-none-any.whl" +pip install "agenteye-${VERSION}-py3-none-any.whl" +``` + +--- + +## Avvio Rapido + +```python +import agenteye + +agenteye.configure(environment="production") + +agenteye.event.agent_start(session_id="run-001", agent_id="planner", goal="answer user query") + +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", + input={"query": "latest AI research"}, +) + +agenteye.event.tool_result( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", + output={"results": ["..."]}, +) + +agenteye.event.agent_end(session_id="run-001", agent_id="planner", outcome="success") +``` + +--- + +## configure() + +```python +agenteye.configure( + base_dir=None, # Path | str | None. Default: $AGENTEYE_HOME or ~/.agenteye + flush_interval=0.5, # float, seconds between flush cycles + environment=None, # str | None. Deployment environment label +) +``` + +Chiamalo una volta prima di qualsiasi chiamata `event.*`. È sicuro ometterlo; i valori predefiniti funzionano direttamente. Tutti gli argomenti sono keyword-only; passali per nome come mostrato sopra. + +Quando `base_dir` è `None` (il valore predefinito), l'SDK legge `$AGENTEYE_HOME` se impostato, +altrimenti ricade su `~/.agenteye`. Questo corrisponde alla risoluzione del collector stesso, +quindi una singola variabile di ambiente `AGENTEYE_HOME` configura lo spool di eventi condiviso per sia +l'SDK che il collector, necessario per i deployment sidecar / single-pod dove +entrambi i processi devono concordare sul percorso dello spool. + +--- + +## Ambiente + +Etichetta ogni evento con un ambiente di deployment (`production`, `staging`, `qa`, `canary`, ecc.). Impostalo una volta; l'SDK lo allega automaticamente a ogni evento. + +**Opzione 1: tramite `configure()`:** + +```python +agenteye.configure(environment="production") +``` + +**Opzione 2: tramite variabile di ambiente:** + +```bash +export AGENTEYE_ENVIRONMENT=production +``` + +**Priorità:** `configure(environment=...)` prevale sulla variabile di ambiente. Se nessuno dei due è impostato, il valore predefinito è `"dev"`. + +Il valore dell'ambiente appare come filtro di prima classe nel dashboard ed è archiviato come colonna indicizzata sul server per query rapide. + +**Vincolo:** i valori dell'ambiente **non devono contenere una virgola `,` letterale**. I filtri del dashboard utilizzano selezioni multiple separate da virgole sul collegamento (`?environment=prod,staging`), quindi un ambiente denominato `prod,blue` verrebbe diviso in due valori. Gli eventi con ambienti contenenti virgole vengono rifiutati al momento dell'ingestion. + +--- + +## Riferimento Eventi + +Tutti i metodi degli eventi richiedono questi due campi: + +| Campo | Tipo | Descrizione | +|---|---|---| +| `session_id` | `str` | Identifica l'esecuzione dell'agente di livello superiore | +| `agent_id` | `str` | Identifica quale agente nella sessione ha emesso l'evento | + +Tutti i metodi accettano anche `**kwargs` arbitrari per metadati personalizzati (vedi [Campi Personalizzati](#campi-personalizzati)). + +--- + +### `event.agent_start()` + +Emesso quando un agente inizia il lavoro. + +```python +agenteye.event.agent_start( + session_id="run-001", + agent_id="planner", + goal="answer user query", # str | None + parent_id=None, # str | None - parent agent_id for nested agents +) +``` + +--- + +### `event.agent_end()` + +Emesso quando un agente finisce il lavoro. + +```python +agenteye.event.agent_end( + session_id="run-001", + agent_id="planner", + outcome="success", # str | None + summary="Answered query", # str | None +) +``` + +--- + +### `event.tool_use()` + +Emesso quando un agente invoca uno strumento. Accoppialo con `tool_result`; l'SDK calcola automaticamente `duration_ms`. + +```python +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="web_search", # str, required + tool_call_id="toolu_01", # str, required - correlation key for the matching tool_result + input={"query": "..."}, # dict | None +) +``` + +--- + +### `event.tool_result()` + +Emesso quando uno strumento ritorna. Correla con `tool_use` tramite `tool_call_id`. + +```python +agenteye.event.tool_result( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", # must match the prior tool_use + output={"results": ["..."]}, # Any | None + error=None, # str | None - set if the tool raised + # duration_ms is computed automatically - do not pass it +) +``` + +--- + +### `event.model_request()` + +Emesso subito prima di inviare un prompt a un LLM. + +```python +agenteye.event.model_request( + session_id="run-001", + agent_id="planner", + model="claude-sonnet-4-6", # str | None + messages=[ # list[dict] | None - conversation turns + {"role": "user", "content": "..."}, + ], + system="You are helpful.", # Any | None - str or list of content blocks + tools=[ # list[dict] | None - tool schemas offered to the model + {"name": "search", "input_schema": {"type": "object"}}, + ], +) +``` + +Le voci `messages` accettano sia un `content` semplice string che Anthropic-style list-of-blocks `content`. I parametri di sampling (`temperature`, `max_tokens`, ecc.) possono essere passati come kwargs aggiuntivi. + +--- + +### `event.model_response()` + +Emesso quando l'LLM ritorna una risposta. + +```python +agenteye.event.model_response( + session_id="run-001", + agent_id="planner", + model="claude-sonnet-4-6", # str | None + stop_reason="end_turn", # str | None + input_tokens=1024, # int | None + output_tokens=256, # int | None + content=[ # Any | None - str, or list of content blocks + {"type": "text", "text": "..."}, + ], + role="assistant", # str | None +) +``` + +`content` accetta sia una semplice string (provider generici) che una lista di content block Anthropic-style. Le chiamate di strumenti vivono all'interno di `content` come blocchi `{"type": "tool_use", ...}`, senza un campo `tool_calls` separato. + +--- + +### `event.hook_triggered()` + +Emesso quando un hook si attiva. Accoppialo con `hook_completed`; l'SDK calcola automaticamente `duration_ms`. + +```python +agenteye.event.hook_triggered( + session_id="run-001", + agent_id="planner", + hook_name="pre_tool_use", # str, required + hook_id="hook-abc", # str, required - correlation key + trigger_event="tool_use", # str | None + input={"tool": "search"}, # Any | None +) +``` + +--- + +### `event.hook_completed()` + +Emesso quando un hook finisce. Correla con `hook_triggered` tramite `hook_id`. + +```python +agenteye.event.hook_completed( + session_id="run-001", + agent_id="planner", + hook_name="pre_tool_use", + hook_id="hook-abc", # must match the prior hook_triggered + outcome="allow", # str | None + output=None, # Any | None + error=None, # str | None + # duration_ms is computed automatically - do not pass it +) +``` + +--- + +### `event.error()` + +Emesso quando si verifica un errore non gestito. + +```python +agenteye.event.error( + session_id="run-001", + agent_id="planner", + error_type="TimeoutError", # str, required + message="timed out", # str, required + traceback="Traceback...", # str | None +) +``` + +--- + +## Eventi Human-in-the-Loop + +Gli eventi human-in-the-loop ti danno supervisione nei momenti in cui una persona interviene nell'esecuzione dell'agente (in attesa di approvazione, fornendo input, mettendo in pausa o fermando l'agente). Ti permettono di misurare quanto tempo gli umani impiegano per rispondere (l'SDK calcola automaticamente `duration_ms` sugli eventi accoppiati), controllare chi ha messo in pausa o interrotto un agente, e costruire flussi di lavoro di approvazione e supervisione che si presentano nel dashboard. + +### `event.human_wait()` + +Emesso quando l'agente mette in pausa l'esecuzione per attendere che un umano fornisca input. Accoppialo con `human_input`; l'SDK calcola automaticamente `duration_ms` (quanto tempo l'umano ha impiegato per rispondere). + +```python +agenteye.event.human_wait( + session_id="run-001", + agent_id="planner", + input_id="inp-abc", # str, required - correlation key for the matching human_input + prompt="Do you approve this action?", # str | None - the question shown to the human + options=["approve", "reject", "defer"], # list[str] | None - choices presented to the human + reason="approval_required", # str | None - why the agent is waiting +) +``` + +### `event.human_input()` + +Emesso quando un umano fornisce input e l'agente riprende. Correla con `human_wait` tramite `input_id`. `duration_ms` è calcolato automaticamente e non deve essere passato dal chiamante. + +```python +agenteye.event.human_input( + session_id="run-001", + agent_id="planner", + input_id="inp-abc", # str, required - must match the prior human_wait + response="approve", # str | None - the human's answer (free text or selected option) + # duration_ms is computed automatically - do not pass it +) +``` + +### `event.human_pause()` + +Emesso quando un umano mette attivamente in pausa l'agente (ad es. tramite un controllo dashboard). L'agente è sospeso ma non terminato. + +```python +agenteye.event.human_pause( + session_id="run-001", + agent_id="planner", + reason="user_requested", # str | None + user_id="usr_42", # str | None - who paused the agent +) +``` + +### `event.human_interrupt()` + +Emesso quando un umano ferma attivamente l'agente durante l'esecuzione. A differenza di `human_pause`, il lavoro dell'agente viene terminato piuttosto che sospeso. + +```python +agenteye.event.human_interrupt( + session_id="run-001", + agent_id="planner", + reason="output_incorrect", # str | None + user_id="usr_42", # str | None - who interrupted the agent + at_step="tool_use:web_search", # str | None - what the agent was doing when stopped +) +``` + +--- + +## Campi Personalizzati + +Tutti gli argomenti di parola chiave aggiuntivi vengono aggiunti all'evento dopo i campi standard: + +```python +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="db_query", + tool_call_id="toolu_02", + tenant_id="acme", # custom field + region="us-east-1", # custom field +) +``` + +`timestamp`, `type` e `environment` sono riservati e generano `ValueError` (`I nomi dei campi riservati non possono essere utilizzati come campi personalizzati: [...]`) se passati come campi personalizzati. `session_id` e `agent_id` sono parametri obbligatori su ogni metodo di evento e non possono essere forniti una seconda volta; Python genera `TypeError` se lo fai. Imposta l'ambiente con `configure(environment=...)` (o la variabile `AGENTEYE_ENVIRONMENT`) invece. + +--- + +## Come Vengono Scritti gli Eventi + +Gli eventi vengono bufferizzati in-process e svuotati su disco ogni `flush_interval` secondi (default 500 ms). Ogni flush scrive un file JSONL: + +``` +~/.agenteye/events/event-2026-04-01T12-00-00-000Z.jsonl +``` + +Il collector osserva questa directory e carica i file automaticamente. Non hai bisogno di gestire questi file direttamente. \ No newline at end of file diff --git a/docs/it/agenteye/single-pod-deployment.mdx b/docs/it/agenteye/single-pod-deployment.mdx new file mode 100644 index 00000000..85dd734c --- /dev/null +++ b/docs/it/agenteye/single-pod-deployment.mdx @@ -0,0 +1,484 @@ +--- +title: "Distribuzione Single-Pod: Collector + Application Sidecar su EKS" +description: "Documentazione di AgentEye Single-Pod Deployment: Collector + Application Sidecar su EKS." +--- + + +Esegui la tua applicazione e il collector AgentEye **nello stesso Pod Kubernetes** in modo che la telemetria non attraversi mai un confine di rete per essere raccolta. L'SDK della tua applicazione e il collector condividono un singolo spool di eventi in-pod, il che significa trasferimento di telemetria a bassa latenza in-process senza alcuna porta localhost esposta, nessun service mesh da attraversare, e il ciclo di vita del collector legato direttamente al carico di lavoro che osserva. Il certificato client mTLS che il collector presenta viene consegnato direttamente nel tuo pod da AWS Secrets Manager, quindi la rotazione delle credenziali non richiede nessuno shuffling manuale di file da parte tua. + +Il modello sidecar + shared-spool descritto qui è agnostico rispetto al cloud; due container che condividono uno spool di eventi `emptyDir` funziona su qualsiasi distribuzione Kubernetes. Solo il percorso di consegna dei certificati in questa guida (AWS Secrets Manager + Secrets Store CSI Driver + IRSA) è specifico di AWS / EKS. Se esegui in altri ambienti, mantieni il layout pod e spool e sostituisci il meccanismo di montaggio dei segreti della tua piattaforma per le Fasi 2 e 3. + +> **Quando utilizzare questo pattern.** Scegli single-pod quando la tua applicazione non dovrebbe chiamare attraverso un confine di rete per raggiungere il collector (IPC in-pod a bassa latenza, forte accoppiamento del ciclo di vita, isolamento pod per tenant). Per flotte multi-app che condividono un collector per nodo o per cluster, vedi [enterprise-docs/kubernetes-deployment.md](/it/agenteye/kubernetes-deployment) invece. + +--- + +## A colpo d'occhio + +``` +┌──────────────────────────────── Pod ─────────────────────────────────┐ +│ │ +│ ┌──────────────────────┐ ┌──────────────────────┐ │ +│ │ your-app │ │ agenteye-collector │ │ +│ │ (SDK writes JSONL) │ │ (sweeps events/, │ │ +│ │ │ │ uploads over mTLS) │ │ +│ └──────────┬───────────┘ └──────────┬───────────┘ │ +│ │ writes reads │ │ +│ ▼ ▼ │ +│ ┌────────────────────────────────────────────────────┐ │ +│ │ emptyDir: /var/lib/agenteye/{events,failed}/ │ │ +│ │ (AGENTEYE_HOME - shared event spool) │ │ +│ └────────────────────────────────────────────────────┘ │ +│ ▲ │ +│ │ reads cert │ +│ ┌────────┴─────────┐ │ +│ │ CSI (read-only): │ │ +│ │ /etc/agenteye/ │ │ +│ │ tls/client.{crt, │ │ +│ │ key}, ca.crt │ │ +│ └────────┬─────────┘ │ +└───────────────────────────────────────────────────┼──────────────────┘ + │ mounted by + │ Secrets Store CSI + │ (AWS provider + + │ IRSA) + ┌────────┴──────────┐ + │ AWS Secrets │ + │ Manager │ + │ agenteye/mtls- │ + │ client/ │ + └────────┬──────────┘ + ▲ + │ push on issue / + │ renewal + ┌────────┴──────────┐ + │ Exosphere │ + │ delivers the cert │ + │ bundle into your │ + │ Secrets Manager │ + │ on renewal │ + └───────────────────┘ + +Outbound: collector → AGENTEYE_URL (mTLS, using the CSI-mounted cert). +``` + +Due flussi di dati, due volumi: + +- **Eventi (in-pod):** l'SDK della tua app scrive file `.jsonl` nell'`emptyDir` condiviso a `$AGENTEYE_HOME/events/`; il sweeper del collector li legge e li carica. Nessuna porta localhost, nessun loopback, puro handoff da filesystem condiviso. +- **Certificato mTLS (pod ← cloud):** Secrets Store CSI Driver monta il bundle dei certificati da Secrets Manager in un volume read-only a `/etc/agenteye/tls/`, limitato al container del collector. + +**Due parti indipendenti:** + +| Parte | Responsabilità | +|---|---| +| Exosphere | Emette il certificato client mTLS e consegna il bundle nell'**account** AWS del tuo Secrets Manager con un nome stabile. Ri-pubblica il bundle rinnovato nello stesso segreto prima della scadenza. | +| Tu | Installa Secrets Store CSI Driver, concedi al ServiceAccount del pod l'accesso in lettura al segreto via IRSA, e applica il manifesto Pod. Basta così. | + +--- + +## Prerequisiti + +### Nel tuo account AWS / cluster EKS + +- Un cluster EKS con un **provider OIDC** associato. Conferma con: + + ```bash + aws eks describe-cluster --name \ + --query "cluster.identity.oidc.issuer" --output text + ``` + + Se il comando restituisce un URL `https://oidc.eks.…`, OIDC è abilitato. Se no, associane uno: + + ```bash + eksctl utils associate-iam-oidc-provider \ + --cluster --approve + ``` + +- [Secrets Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/) e [provider AWS](https://github.com/aws/secrets-store-csi-driver-provider-aws) installati nel cluster (vedi § Fase 2). + +- AWS CLI v2 e `kubectl` sulla tua workstation. + +### Coordinamento con Exosphere + +Prima di effettuare il deployment, Exosphere consegna il bundle client mTLS nell'account AWS Secrets Manager e fornisce: + +- Il **nome del segreto** (convenzione: `agenteye/mtls-client/`) +- La **regione AWS** dove risiede il segreto +- L'**URL del backend AgentEye** da configurare nel collector +- La **chiave API** del collector (vedi [enterprise-docs/api-keys.md](/it/agenteye/api-keys)) + +--- + +## Fase 1: Cosa Exosphere consegna + +Non generi il certificato client mTLS da solo. Exosphere lo emette e consegna il bundle direttamente nell'account AWS Secrets Manager, quindi il solo materiale di credenziale che sbarca nel tuo ambiente è il segreto finito e pronto per il montaggio. + +Ciò che arriva nel tuo account: + +| Proprietà | Valore | +|---|---| +| Nome del segreto | `agenteye/mtls-client/` (stabile tra i rinnovi) | +| Regione | La regione AWS che hai nominato per il tuo cluster EKS | +| Payload | Un singolo segreto JSON con tre chiavi (`client.crt`, `client.key` e `ca.crt`), ognuno contenente il materiale codificato PEM | +| Tag | `AgentEyeCluster=` | + +Al rinnovo, lo stesso segreto viene aggiornato sul posto con una nuova versione, quindi l'ARN e il nome non cambiano mai; la tua `SecretProviderClass` e la politica IAM continuano a funzionare senza modifiche. Per il ciclo di vita del certificato (validità, cadenza di rinnovo, avvisi di scadenza) vedi [enterprise-docs/kubernetes-deployment.md](/it/agenteye/kubernetes-deployment). + +--- + +## Fase 2: Installa Secrets Store CSI Driver + provider AWS + +Salta questo passaggio se esegui già un altro carico di lavoro che monta segreti AWS via CSI. + +```bash +# CSI Driver +helm repo add secrets-store-csi-driver \ + https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts +helm install -n kube-system csi-secrets-store \ + secrets-store-csi-driver/secrets-store-csi-driver \ + --set syncSecret.enabled=true \ + --set enableSecretRotation=true \ + --set rotationPollInterval=1h + +# AWS provider +kubectl apply -f \ + https://raw.githubusercontent.com/aws/secrets-store-csi-driver-provider-aws/main/deployment/aws-provider-installer.yaml +``` + +**Verifica:** + +```bash +kubectl get pods -n kube-system | grep -E 'csi-secrets-store|aws-provider' +``` + +Atteso: `Running` per ogni pod. + +> **Perché `rotationPollInterval=1h`?** Quando Exosphere pubblica un certificato rinnovato, Secrets Manager viene aggiornato sul posto. CSI Driver ri-legge il segreto a questo intervallo e ri-scrive i file montati. Il collector legge i file dei certificati una sola volta all'avvio, quindi inizia a presentare il certificato rinnovato solo dopo un restart del processo; vedi § Certificate rotation per sapere come attivarne uno. + +--- + +## Fase 3: Concedi al pod l'accesso in lettura al segreto (IRSA) + +### 3.1 Crea la politica IAM + +Salva come `agenteye-mtls-reader-policy.json`: + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "ReadAgentEyeMtlsBundle", + "Effect": "Allow", + "Action": [ + "secretsmanager:GetSecretValue", + "secretsmanager:DescribeSecret" + ], + "Resource": "arn:aws:secretsmanager:::secret:agenteye/mtls-client/-*" + } + ] +} +``` + +Sostituisci ``, `` e ``. Il suffisso `-*` finale corrisponde ai sei caratteri casuali che AWS aggiunge ad ogni ARN segreto. + +Crea la politica: + +```bash +aws iam create-policy \ + --policy-name AgentEyeMtlsReader- \ + --policy-document file://agenteye-mtls-reader-policy.json +``` + +### 3.2 Crea il ruolo IAM e collegalo al ServiceAccount del pod + +```bash +eksctl create iamserviceaccount \ + --name agenteye-pod \ + --namespace \ + --cluster \ + --role-name AgentEyePodRole- \ + --attach-policy-arn arn:aws:iam:::policy/AgentEyeMtlsReader- \ + --approve +``` + +Questo crea un `ServiceAccount` denominato `agenteye-pod` con l'annotazione `eks.amazonaws.com/role-arn` che punta al nuovo ruolo. + +### 3.3 Permessi IAM richiesti: riepilogo + +| Permesso | Ambito | Motivo | +|---|---|---| +| `secretsmanager:GetSecretValue` | `arn:aws:secretsmanager:::secret:agenteye/mtls-client/-*` | CSI Driver legge il bundle dei certificati ad ogni montaggio + tick di rotazione. | +| `secretsmanager:DescribeSecret` | stesso | CSI Driver chiama `DescribeSecret` per rilevare i cambiamenti di versione tra i polling. | + +**NON concedere** `secretsmanager:PutSecretValue`, `secretsmanager:UpdateSecret` o `secretsmanager:DeleteSecret` al pod. Il pod legge solo il segreto; la scrittura di nuove versioni in esso viene gestita da Exosphere quando il certificato viene emesso o rinnovato. + +Se il segreto è crittografato con una chiave KMS gestita dal cliente (non la chiave predefinita `aws/secretsmanager`), concedi anche: + +```json +{ + "Effect": "Allow", + "Action": ["kms:Decrypt"], + "Resource": "arn:aws:kms:::key/", + "Condition": { + "StringEquals": { + "kms:ViaService": "secretsmanager..amazonaws.com" + } + } +} +``` + +--- + +## Fase 4: Distribuisci il Pod + +### 4.1 SecretProviderClass + +`agenteye-mtls-spc.yaml`: + +```yaml +apiVersion: secrets-store.csi.x-k8s.io/v1 +kind: SecretProviderClass +metadata: + name: agenteye-mtls + namespace: +spec: + provider: aws + parameters: + objects: | + - objectName: "agenteye/mtls-client/" + objectType: "secretsmanager" + jmesPath: + - path: '"client.crt"' + objectAlias: "client.crt" + - path: '"client.key"' + objectAlias: "client.key" + - path: '"ca.crt"' + objectAlias: "ca.crt" +``` + +Il blocco `jmesPath` dice al provider AWS di dividere il segreto JSON in tre file separati su disco. Le virgolette in `'"client.crt"'` sono obbligatorie perché JMESPath tratta `.` come un operatore di sotto-espressione. + +```bash +kubectl apply -f agenteye-mtls-spc.yaml +``` + +### 4.2 Manifesto Pod / Deployment + +**Come i due container comunicano tra loro.** L'SDK AgentEye e il collector non comunicano su un socket di rete; non c'è alcuna porta HTTP locale. L'SDK scrive batch di eventi come file `.jsonl` in `$AGENTEYE_HOME/events/`, e il collector guarda continuamente quella directory e carica ogni file. Per un pod sidecar questo significa: + +- Entrambi i container montano il **medesimo** volume `emptyDir` nel **medesimo** percorso. +- Entrambi i container impostano `AGENTEYE_HOME` a quel percorso. +- La tua immagine dell'applicazione deve avere l'SDK AgentEye installato e configurato (vedi [enterprise-docs/python-sdk.md](/it/agenteye/python-sdk)). + +> Quando `AGENTEYE_HOME` non è impostato, sia l'SDK che il collector usano per impostazione predefinita `~/.agenteye`, e i due container hanno directory home diverse, quindi finirebbero su due spool separati e l'handoff fallirebbe silenziosamente. Imposta `AGENTEYE_HOME` allo stesso percorso esplicito su **entrambi** i container. La verifica di §4.3 e la riga di Troubleshooting corrispondente lo catturano se viene saltato. + +`agenteye-pod.yaml` (Deployment con una replica, scala secondo necessità): + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-app-with-collector + namespace: +spec: + replicas: 1 + selector: + matchLabels: + app: my-app-with-collector + template: + metadata: + labels: + app: my-app-with-collector + spec: + serviceAccountName: agenteye-pod + containers: + - name: app + image: + env: + # SDK writes event JSONL files into $AGENTEYE_HOME/events/ + - name: AGENTEYE_HOME + value: /var/lib/agenteye + volumeMounts: + - name: agenteye-spool + mountPath: /var/lib/agenteye + + - name: agenteye-collector + # Pin to a versioned :v tag for production; :beta-latest + # tracks the current beta build (:latest exists only for stable releases). + image: ghcr.io/agenteye-enterprise/collector:beta-latest + args: ["start"] + env: + # Must match the app container's AGENTEYE_HOME so the collector + # sweeps the same directory the SDK writes to. + - name: AGENTEYE_HOME + value: /var/lib/agenteye + - name: AGENTEYE_URL + value: "https://ingest.example.agenteye.com/events" + - name: AGENTEYE_KEY + valueFrom: + secretKeyRef: + name: agenteye-collector-api-key + key: key + - name: AGENTEYE_TLS_CERT + value: /etc/agenteye/tls/client.crt + - name: AGENTEYE_TLS_KEY + value: /etc/agenteye/tls/client.key + # Only when the AgentEye server presents a cert not signed by a + # publicly-trusted CA (e.g. self-signed by an in-cluster issuer + # because you have no real DNS domain). The CSI mount already + # exposes ca.crt alongside the client cert/key. + - name: AGENTEYE_TLS_CA + value: /etc/agenteye/tls/ca.crt + volumeMounts: + - name: agenteye-spool + mountPath: /var/lib/agenteye + - name: agenteye-mtls + mountPath: /etc/agenteye/tls + readOnly: true + livenessProbe: + exec: + command: ["agenteye-collector", "health"] + initialDelaySeconds: 10 + periodSeconds: 30 + + volumes: + # Shared event spool between app and collector. emptyDir is fine: + # events are transient and the collector drains them before pod + # termination on graceful shutdown. + - name: agenteye-spool + emptyDir: {} + # mTLS cert bundle, mounted read-only into the collector only. + - name: agenteye-mtls + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: agenteye-mtls +``` + +Il segreto `agenteye-collector-api-key` contiene la chiave API del collector (vedi [enterprise-docs/api-keys.md](/it/agenteye/api-keys) per il provisioning). + +**Applica:** + +```bash +kubectl apply -f agenteye-pod.yaml +``` + +### 4.3 Verifica + +```bash +# Pod should be Running with 2/2 containers ready +kubectl get pods -n -l app=my-app-with-collector + +# Confirm the cert bundle was mounted +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- ls -l /etc/agenteye/tls/ +``` + +Atteso: `client.crt`, `client.key`, `ca.crt` tutti presenti e read-only, di proprietà dell'utente del container. + +**Conferma che lo spool di eventi condiviso sia visibile a entrambi i container:** + +```bash +# In the collector, should show the events/ and failed/ subdirs that +# the collector auto-creates on startup: +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- ls /var/lib/agenteye/ + +# In the app, should show the same directory contents: +kubectl exec -n deploy/my-app-with-collector \ + -c app -- ls /var/lib/agenteye/ +``` + +Se i due elenchi divergono, il volume non è montato in entrambi i container (o `AGENTEYE_HOME` differisce); vedi § Troubleshooting. + +**Test smoke end-to-end:** + +```bash +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- agenteye-collector flush +``` + +Atteso: il collector carica tutti gli eventi in coda e stampa un riepilogo `Done: N/N uploaded, 0 failed.`. Se lo spool è vuoto stampa `No pending files.` e esce senza convalidare nulla — quindi esegui questo solo dopo che la tua app ha scaricato almeno un evento. + +Nota che `flush` esce con codice non-zero **solo** per i difetti di configurazione locale: configurazione mancante (nessun URL/chiave risolta) o un certificato TLS illeggibile/non parsabile (controlla § Troubleshooting). Una **chiave API sbagliata non cambia il codice di uscita** — l'upload riceve un `401`, il file viene spostato a `failed/`, e il comando stampa comunque `[FAILED] …` per file più `Done: 0/N uploaded, N failed.` ed esce con `0`. Per rilevare una chiave errata o un upload rifiutato, leggi l'output `Done:`/`[FAILED]` o controlla i file che sbarcano in `$AGENTEYE_HOME/failed/`, non il codice di uscita. + +--- + +## Rotazione dei certificati + +Il certificato client è valido per 90 giorni e viene rinnovato automaticamente circa 15 giorni prima della scadenza; Exosphere quindi pubblica il bundle rinnovato nello stesso segreto di Secrets Manager. Da lì, il flusso in-pod è: + +1. Il segreto di Secrets Manager ottiene una nuova versione `AWSCURRENT`. ARN e nome rimangono invariati. +2. Entro `rotationPollInterval` (1h per impostazione predefinita; vedi § Fase 2), CSI Driver legge la nuova versione e ri-scrive i file sotto `/etc/agenteye/tls/`. +3. Il collector carica i file dei certificati **una sola volta all'avvio**, quindi continua a presentare il certificato precedente fino al restart del processo. Per passare al materiale rinnovato, riavvia il collector; un rolling restart è sufficiente: + + ```bash + kubectl rollout restart deploy/my-app-with-collector -n + ``` + + Per renderlo automatico, aggiungi un sidecar che guarda `/etc/agenteye/tls/` (ad esempio con `inotifywait`) e attiva il rollout quando i file cambiano. + +Poiché il certificato precedente rimane valido per circa 15 giorni dopo il rinnovo, hai una finestra ampia per eseguire il restart senza interruzione dell'ingestion. Exosphere pubblica il bundle rinnovato per te; l'unica azione routinaria da parte tua è assicurarsi che il collector si riavvii entro quella finestra. + +--- + +## Troubleshooting + +| Sintomo | Probabile causa | Correzione | +|---|---|---| +| Pod bloccato in `ContainerCreating`, gli eventi mostrano `MountVolume.SetUp failed for volume "agenteye-mtls"` | Il provider CSI non riesce a raggiungere Secrets Manager | Controlla che IRSA sia correttamente collegato: `kubectl describe sa agenteye-pod -n ` mostra l'annotazione `eks.amazonaws.com/role-arn`. Controlla CloudTrail per la chiamata AssumeRole. | +| Errore: `AccessDeniedException: not authorized to perform secretsmanager:GetSecretValue` | La politica IAM è limitata a un ARN sbagliato | Il suffisso dell'ARN segreto è casuale; usa `agenteye/mtls-client/-*` con il wildcard, non l'ARN esatto. | +| Errore: `ParameterNotFound` dal provider AWS | Mancata corrispondenza del nome segreto tra `SecretProviderClass.objects[].objectName` e il segreto che Exosphere ha consegnato | Conferma il nome esatto con `aws secretsmanager list-secrets --filters Key=tag-key,Values=AgentEyeCluster`. | +| Errore `jmesPath`, solo un file montato | Sintassi JMESPath | I punti nelle chiavi JSON richiedono virgolette doppie: `'"client.crt"'`, non `client.crt`. | +| Il collector registra `tls: bad certificate` dopo un rinnovo | CSI Driver non ha ancora eseguito il polling della nuova versione, oppure il collector è ancora in esecuzione con il certificato precedente che ha caricato all'avvio | Conferma che i file montati siano stati aggiornati (`ls -l /etc/agenteye/tls/`), quindi riavvia il collector per caricarli: `kubectl rollout restart deploy/my-app-with-collector -n `. Vedi § Certificate rotation. | +| Container del collector crashloop con `no such file or directory: /etc/agenteye/tls/client.crt` | Volume non ancora popolato al primo avvio; probe di startup troppo aggressiva | Aggiungi un piccolo ritardo iniziale o usa un init container che attende che il file esista: `until [ -f /etc/agenteye/tls/client.crt ]; do sleep 1; done`. | +| Pod CSI Driver `OOMKilled` | I limiti di memoria predefiniti troppo bassi per i cluster con molte SecretProviderClasses | Aumenta `--set linux.resources.limits.memory=200Mi` nell'installazione di Helm. | +| L'app funziona correttamente, `agenteye-collector flush` riporta `No pending files.`, ma la tua dashboard AgentEye non mostra eventi | L'app e il collector non condividono lo spool di eventi | Controlla che (a) entrambi i container montino lo stesso `agenteye-spool` emptyDir nello stesso percorso, e (b) entrambi impostino `AGENTEYE_HOME` a quel percorso. Esegui i due controlli `ls /var/lib/agenteye/` da § 4.3; gli elenchi devono corrispondere. | + +**Log da acquisire per primo:** + +```bash +kubectl logs -n kube-system -l app=secrets-store-csi-driver --tail=100 +kubectl logs -n kube-system -l app=csi-secrets-store-provider-aws --tail=100 +kubectl describe pod -n -l app=my-app-with-collector +``` + +--- + +## Riferimento: file su disco nel pod + +Il pod ha due percorsi dati su disco: + +### Bundle dei certificati mTLS: `/etc/agenteye/tls/` (CSI, read-only, solo collector) + +Montato da Secrets Store CSI Driver da AWS Secrets Manager. + +| File | Contenuti | Utilizzato dal collector come | +|---|---|---| +| `client.crt` | Certificato client codificato PEM | `AGENTEYE_TLS_CERT` | +| `client.key` | Chiave privata codificata PEM | `AGENTEYE_TLS_KEY` | +| `ca.crt` | Certificato CA codificato PEM | `AGENTEYE_TLS_CA` (opzionale, solo quando il certificato del server AgentEye non è pubblicamente attendibile) | + +Tutti e tre sono montati read-only e di proprietà dell'utente del container. Sono ri-scritti da CSI Driver quando il segreto ruota. + +### Spool di eventi: `$AGENTEYE_HOME/` (emptyDir, condiviso read-write tra entrambi i container) + +Condiviso via un volume `emptyDir` denominato `agenteye-spool`. + +| Percorso | Scritto da | Letto da | Scopo | +|---|---|---|---| +| `$AGENTEYE_HOME/events/*.jsonl` | App (AgentEye SDK) | Sweeper del collector | Batch di eventi che l'SDK ha scaricato, in attesa di caricamento. | +| `$AGENTEYE_HOME/failed/` | Collector (su errore di caricamento) | Tu (durante il debug) | File JSONL che il collector non ha potuto caricare dopo i tentativi. | +| `$AGENTEYE_HOME/config.json` | Tu (opzionale) | Collector | File di configurazione opzionale del collector (alternativa alle variabili d'ambiente). | + +Entrambe le subdirectory `events/` e `failed/` sono auto-create dal collector all'avvio; nessun `initContainer` necessario. + +--- + +## Documentazione correlata + +- [enterprise-docs/collector-installation.md](/it/agenteye/collector-installation): opzioni binarie del collector, riferimento di configurazione mTLS, modalità daemon. +- [enterprise-docs/kubernetes-deployment.md](/it/agenteye/kubernetes-deployment): distribuzione multi-pod, internals di emissione dei certificati, ciclo di vita e avvisi di scadenza. +- [enterprise-docs/api-keys.md](/it/agenteye/api-keys): provisioning della chiave API del collector consumata dal pod. +- [enterprise-docs/troubleshooting.md](/it/agenteye/troubleshooting): indice di troubleshooting a livello di cluster. \ No newline at end of file diff --git a/docs/it/agenteye/tenant-management.mdx b/docs/it/agenteye/tenant-management.mdx new file mode 100644 index 00000000..54d47f73 --- /dev/null +++ b/docs/it/agenteye/tenant-management.mdx @@ -0,0 +1,167 @@ +--- +title: "Gestione dei tenant (organizzazioni e membri)" +description: "Documentazione sulla gestione dei tenant AgentEye (organizzazioni e membri)." +--- + + +Una singola distribuzione AgentEye serve più **organizzazioni** completamente isolate (tenant), così un'istanza può ospitare team distinti, unità aziendali o clienti senza esporre i dati di un tenant a un altro. Ogni riga di dati (eventi, valutazioni, sessioni, dashboard, query salvate, avvisi, chiavi API e membri) appartiene esattamente a un'organizzazione. L'isolamento principale è applicato nel codice dell'applicazione: ogni richiesta è limitata alla sua organizzazione con predicati espliciti `org_id`. Su ClickHouse — dove risiedono gli eventi e le valutazioni ad alto volume — questo è supportato da un'applicazione forte a livello di motore: ogni organizzazione riceve un utente ClickHouse dedicato in sola lettura con una policy per riga per organizzazione, così anche SQL analitici non attendibili non possono mai leggere le righe di un altro tenant. Su PostgreSQL, la sicurezza a livello di riga aggiunge difesa in profondità sul percorso di query in sola lettura (`/queries/run`), restringendo ciò che quel percorso può visualizzare anche se un filtro a livello di applicazione mancasse; la propria connessione di scrittura del server funziona come proprietario della tabella e quindi opera attraverso lo stesso scoping `org_id` a livello di app. + +Il ciclo di vita dei tenant è controllato dall'operatore, mentre tutto ciò che i membri fanno quotidianamente rimane self-service nel dashboard. Le organizzazioni e le loro appartenenze sono create e gestite con la CLI **`agenteye-orgctl`**, che è spedita all'interno dell'immagine del server ed eseguita **all'interno del pod server esistente**. La creazione e l'eliminazione dei tenant sono deliberatamente mantenute fuori dal dashboard e dall'API HTTP: non esiste **nessuna API HTTP e nessun pulsante nel dashboard** per il ciclo di vita dei tenant, quindi è protetto da un accesso shell al cluster/pod piuttosto che dalla superficie dell'applicazione. + +All'interno di un'organizzazione, i membri lavorano interamente nel dashboard e nell'API: accedono, passano tra le organizzazioni a cui appartengono, gestiscono le proprie chiavi API, costruiscono dashboard e query salvate, e configurano avvisi per la loro organizzazione. La divisione è netta: gli operatori forniscono e disattivano i tenant e i loro membri tramite la CLI; i membri eseguono tutto all'interno di un tenant tramite l'interfaccia utente. + +> **Le distribuzioni single-tenant non hanno bisogno di nulla di tutto questo.** Un'installazione single-tenant funziona senza alcuna azione dell'operatore. Tutti i dati, gli utenti e le chiavi risiedono in un'organizzazione `default` incorporata che viene fornita automaticamente. Hai bisogno di questa guida solo quando decidi di aggiungere una seconda organizzazione. + +--- + +## Prerequisiti + +Prima di creare la **seconda** organizzazione (l'organizzazione `default` incorporata non ha bisogno di nulla): + +- **PostgreSQL 15+.** Lo schema di appartenenza dell'organizzazione utilizza una chiave esterna `ON DELETE SET NULL` con elenco di colonne che richiede PostgreSQL 15+. Aggiorna PostgreSQL prima di fornire una seconda organizzazione. +- **Un `ORG_CH_SECRET` forte e stabile.** La password ClickHouse di ogni organizzazione è derivata come `HMAC(ORG_CH_SECRET, org_id)`, quindi il default di sviluppo pubblicamente noto incorporato comporterebbe credenziali per organizzazione pubblicamente derivabili. `agenteye-orgctl org create` **rifiuta di eseguire mentre `ORG_CH_SECRET` non è impostato o è lasciato al default di sviluppo incorporato**. Imposta prima il tuo valore (consulta [Deployment → environment variables](/it/agenteye/deployment) e, su Kubernetes, [§2.6 della guida Kubernetes](/it/agenteye/kubernetes-deployment#26-multi-tenant-org-isolation-key-optional)). Mantienilo identico su tutte le repliche del server e non ruotarlo casualmente; ruotarlo lascia orfano ogni utente ClickHouse dell'organizzazione fino al prossimo avvio che li fornisce di nuovo. + +--- + +## Esecuzione della CLI + +`agenteye-orgctl` è spedito nella **stessa immagine del server** (insieme a `agenteye-server`). **Non** distribuisci un pod, Job o Deployment separato per questo; lo esegui all'interno del pod server già in esecuzione, così legge lo stesso `DATABASE_URL`, `CLICKHOUSE_URL` e `ORG_CH_SECRET` che usa il server. + +**Kubernetes:** + +```bash +kubectl -n agenteye exec deploy/server -- agenteye-orgctl +``` + +**Docker Compose:** + +```bash +docker compose exec server agenteye-orgctl +``` + +Gli esempi seguenti mostrano il semplice `agenteye-orgctl ` per brevità; anteponi a ciascuno la riga corrispondente tra le due sopra che corrisponde alla tua distribuzione. + +--- + +## Riferimento dei comandi + +### Organizzazioni + +| Comando | Cosa fa | +|---|---| +| `org create --slug --name ` | Crea una nuova organizzazione. Rifiuta di eseguire mentre `ORG_CH_SECRET` non è impostato o è lasciato al default di sviluppo incorporato (imposta prima il tuo valore, consulta Prerequisiti). Fornisce l'utente ClickHouse in sola lettura dell'organizzazione + policy per riga. | +| `org list` | Elenca tutte le organizzazioni (slug, nome e stato del ciclo di vita). | +| `org rename --slug --name ` | Cambia il nome visualizzato di un'organizzazione. Lo slug (usato negli URL e nelle chiavi) rimane invariato. | +| `org delete --slug ` | **Soft-delete** dell'organizzazione e rimozione del suo utente ClickHouse. I dati sono **conservati**. Questo revoca l'accesso e libera le credenziali ClickHouse per organizzazione, ma non cancella gli eventi. Reversibile da parte dei responsabili; primo passo sicuro prima di una cancellazione. | +| `org purge --slug ` | **Cancellazione dei dati irreversibile.** L'organizzazione deve già essere `delete`d. Mai consentito nell'organizzazione `default` incorporata. Usa solo quando sei sicuro che i dati del tenant dovrebbero essere distrutti. | + +### Membri + +| Comando | Cosa fa | +|---|---| +| `member add --org --email [--set ] [--add perm1,perm2] [--remove perm3] [--protected]` | Aggiungi un membro a un'organizzazione. Facoltativamente inizia da un set di permessi incorporato, quindi aggiungi/rimuovi autorizzazioni individuali. `--protected` fissa il membro in modo che il dashboard non possa rimuoverlo o degradarlo (vedi sotto). Il nuovo membro riceve un OTP al primo accesso al dashboard. | +| `member list --org ` | Elenca i membri dell'organizzazione. Le colonne di output sono `EMAIL`, `SET` (il set incorporato da cui il membro ha iniziato, o `-`), `PROT` (se il membro è protetto), e `PERMISSIONS` (le loro autorizzazioni effettive). Un'email mostrata con un `*` finale è un amministratore dell'istanza; hanno accesso a ogni organizzazione. | +| `member update --org --email [--set ...] [--add ...] [--remove ...] [--protected \| --unprotect]` | Cambia le autorizzazioni di un membro e/o il flag protetto. `--set` sostituisce da un set incorporato; `--add` / `--remove` regolano autorizzazioni individuali; `--protected` / `--unprotect` attivano la protezione. Passare solo `--protected`/`--unprotect` (nessun flag di concessione) cambia solo la protezione e lascia intatte le autorizzazioni esistenti. | +| `member remove --org --email ` | Rimuovi un membro dall'organizzazione. Rifiuta se il membro è protetto; `--unprotect` prima. (Una persona può essere membro di più organizzazioni; questo colpisce solo l'organizzazione denominata.) | + +Una persona può essere membro di più di un'organizzazione con **autorizzazioni diverse** in ciascuna, ad es. un amministratore in un'organizzazione e sola lettura in un'altra. Ogni appartenenza è amministrata indipendentemente per organizzazione: concedere o modificare le autorizzazioni di una persona in un'organizzazione non ha alcun effetto sulla loro appartenenza in qualsiasi altra. + +### Membri protetti (un amministratore dell'organizzazione rimovibile) + +La protezione garantisce che un'organizzazione non possa mai accidentalmente bloccarsi dalla gestione autonoma. Per impostazione predefinita, gli amministratori di un'organizzazione possono aggiungere e rimuovere l'uno l'altro attraverso la pagina self-service degli utenti del dashboard, quindi potrebbero rimuovere l'ultimo amministratore e lasciare l'organizzazione senza nessuno in grado di gestirla. + +![La pagina Utenti: una scheda per utente del dashboard con la loro email, autorizzazioni concesse e controlli di modifica/disabilitazione](/agenteye/images/users.png) + +Per evitare ciò, contrassegna un membro come **protetto**: + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member add --org acme --email owner@acme.example --set admin --protected +``` + +Un membro protetto **non può essere rimosso o degradato tramite il dashboard**; queste azioni restituiscono un errore. Solo un operatore può modificarli, e solo tramite questa CLI: esegui prima `member update --org acme --email owner@acme.example --unprotect`, quindi rimuovi o degrada. Questo garantisce che ogni organizzazione mantenga almeno un amministratore che i suoi stessi membri non possono bloccare, mantenendo il controllo del tenant solo per l'operatore. La protezione è **per organizzazione**; proteggere qualcuno in un'organizzazione non ha alcun effetto sulla sua appartenenza in un'altra. + +### Set di autorizzazioni incorporati + +`--set` accetta uno di tre set incorporati, applicato per organizzazione: + +| Set | Previsto per | +|---|---| +| `admin` | Accesso completo all'interno dell'organizzazione, inclusa la gestione delle chiavi API e degli utenti dell'organizzazione. | +| `standard` | Uso quotidiano: lettura + esecuzione di query, creazione di dashboard, riconoscimento degli incidenti. | +| `read-only` | Accesso in sola lettura ai dati e ai dashboard dell'organizzazione. | + +Inizia da un set con `--set`, quindi affina con `--add` / `--remove` usando i token di autorizzazione individuali elencati in [API Keys](/it/agenteye/api-keys). I token di autorizzazione stessi sono identici a quelli utilizzati per le chiavi API. + +--- + +## Esempio pratico + +Fornisci un nuovo tenant `acme`, aggiungi il suo primo amministratore, consentigli di creare una chiave, quindi disattiva l'organizzazione. + +**1. Crea l'organizzazione** (`ORG_CH_SECRET` deve già essere impostato su un valore forte e stabile, non non impostato o il default di sviluppo incorporato): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org create --slug acme --name "Acme Corp" +``` + +**2. Aggiungi il primo membro come amministratore dell'organizzazione:** + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member add --org acme --email alice@acme.example --set admin +``` + +Alice riceve un OTP la prima volta che accede al dashboard. Da allora in poi lavora interamente nell'interfaccia utente sotto il prefisso URL della sua organizzazione (ad es. `/acme/sessions`). + +**3. Crea una chiave API per organizzazione (nel dashboard):** + +L'operatore **non** crea chiavi di dati per organizzazione dalla CLI. Alice (o qualsiasi membro dell'organizzazione con `keys:create`) crea chiavi di raccoglitore / dashboard per l'organizzazione `acme` dalla pagina **Keys** del dashboard. Ogni chiave che crea è automaticamente contrassegnata con la sua organizzazione e può leggere o scrivere solo i dati dell'`acme`. Consulta [API Keys](/it/agenteye/api-keys). + +**4. Regola un membro in seguito:** + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member update --org acme --email alice@acme.example --add alerts:write + +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member list --org acme +``` + +**5. Soft-delete dell'organizzazione** (revoca l'accesso + rimuove il suo utente ClickHouse; dati conservati): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org delete --slug acme +``` + +**6. Cancella l'organizzazione** (irreversibile; solo dopo un soft-delete; mai l'organizzazione `default`): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org purge --slug acme +``` + +Su Docker Compose, sostituisci ogni prefisso `kubectl -n agenteye exec deploy/server --` con `docker compose exec server`. + +--- + +## Divisione delle responsabilità + +Tutto ciò che un membro dell'organizzazione ha bisogno quotidianamente è self-service nel dashboard e nell'API, limitato automaticamente alla loro organizzazione attuale: + +- **Le chiavi API per organizzazione** sono create e gestite dai membri dell'organizzazione nel dashboard (o tramite l'API delle chiavi con una chiave che porta `keys:create`). La CLI **non** crea chiavi di dati. Consulta [API Keys](/it/agenteye/api-keys). +- **Il cambio di organizzazione** è incorporato nel dashboard; i membri passano tra le organizzazioni a cui appartengono dal selettore di organizzazione, e le pagine limitate all'organizzazione vivono sotto `//…`. +- **Dashboard, query salvate, avvisi e tutti gli usi dei dati** avvengono interamente nell'interfaccia utente e nell'API, limitati all'organizzazione corrente del membro. + +L'operatore, utilizzando `agenteye-orgctl`, possiede solo il **ciclo di vita** dell'organizzazione + membro: crea / rinomina / elimina / cancella un'organizzazione, e aggiungi / elenca / aggiorna / rimuovi un membro. + +--- + +## Vedi anche + +- [Deployment](/it/agenteye/deployment): `ORG_CH_SECRET` e il resto dell'ambiente del server. +- [Kubernetes Deployment](/it/agenteye/kubernetes-deployment): §2.6 crea il Secret `agenteye-org-ch-secret` prima della tua prima organizzazione multi-tenant. +- [API Keys](/it/agenteye/api-keys): il modello di chiave per organizzazione e i token di autorizzazione utilizzati da `--add` / `--remove`. +- [Troubleshooting](/it/agenteye/troubleshooting): problemi di provisioning multi-tenant e isolamento ClickHouse. \ No newline at end of file diff --git a/docs/it/agenteye/troubleshooting.mdx b/docs/it/agenteye/troubleshooting.mdx new file mode 100644 index 00000000..87861fe6 --- /dev/null +++ b/docs/it/agenteye/troubleshooting.mdx @@ -0,0 +1,691 @@ +--- +title: "Risoluzione dei problemi" +description: "Documentazione per la risoluzione dei problemi di AgentEye." +--- + + +Questa guida associa i sintomi che è più probabile riscontrare in produzione a una diagnosi concreta e a una soluzione, in modo che tu possa risolvere gli incidenti usando gli strumenti che già possiedi, senza dover implementare infrastrutture di osservabilità aggiuntive. Copre il server, il collector, il dashboard, l'assistente AI, Python SDK, il monitoraggio della salute e dei certificati, i backup, le analitiche supportate da ClickHouse e il multi-tenancy. + +Le pagine del dashboard hanno ambito dell'organizzazione sotto `//…`, e lo stream degli eventi è la home dell'organizzazione (`//`). I nomi delle pagine in questa guida (ad esempio `/sessions`, `/queries`) si riferiscono a questi percorsi con ambito organizzativo. + +--- + +## Visualizzazione dei log + +AgentEye non include uno stack di logging o monitoring. Sia il server che il dashboard scrivono log strutturati su **stdout**, quindi puoi leggerli direttamente con `kubectl` o `docker`; non è richiesto alcun aggregatore. + +### Kubernetes + +Segui i log live per il server e il dashboard: + +```bash +kubectl logs -n agenteye -l app=server -f --timestamps +kubectl logs -n agenteye -l app=dashboard -f --timestamps +``` + +Varianti utili: + +| Obiettivo | Comando | +|---|---| +| Ultime 200 righe (senza follow) | `kubectl logs -n agenteye -l app=server --tail=200 --timestamps` | +| Log dal crash precedente | `kubectl logs -n agenteye --previous` | +| Traccia tutte le repliche contemporaneamente | `kubectl logs -n agenteye -l app=server --max-log-requests=10 -f` | +| Postgres (StatefulSet) | `kubectl logs -n agenteye postgres-0 -f` | + +### Docker Compose + +```bash +docker logs -f agenteye-server +docker logs -f agenteye-dashboard +``` + +### Correlazione di una singola richiesta tra dashboard e server + +Ogni richiesta del dashboard è etichettata con un `request_id` e propagata al server tramite l'intestazione `x-request-id`. Il server lo ripete nelle sue intestazioni di risposta e in ogni riga di log che emette per quella richiesta. Per tracciare una richiesta end-to-end: + +1. Cattura l'id dall'intestazione di risposta, ad esempio: + ```bash + curl -i https://dashboard.example.com/api/events | grep -i x-request-id + # x-request-id: 9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a + ``` +2. Esegui grep nei log di entrambi i pod per quell'id: + ```bash + REQ=9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a + kubectl logs -n agenteye -l app=dashboard --tail=5000 | grep "$REQ" + kubectl logs -n agenteye -l app=server --tail=5000 | grep "$REQ" + ``` + +Vedrai le righe `proxy passthrough`, `withAuth: authorized` e `upstream response` del dashboard insieme alla coppia `http request received` / `http request completed` del server, condividendo tutte lo stesso `request_id`. + +### Log JSON e `jq` + +Imposta `AE_LOG_JSON=1` sul dashboard (è attivato per impostazione predefinita quando `NODE_ENV=production`) per emettere un oggetto JSON per riga. Quindi filtra strutturalmente: + +```bash +kubectl logs -n agenteye -l app=dashboard --tail=5000 \ + | jq 'select(.level == "warn" or .level == "error")' + +kubectl logs -n agenteye -l app=dashboard --tail=5000 \ + | jq 'select(.route == "POST /api/keys")' +``` + +Il server Rust emette coppie di traccia `key=value` che grep funziona bene senza `jq`: + +```bash +kubectl logs -n agenteye -l app=server --tail=5000 | grep 'status=5' # 5xx +kubectl logs -n agenteye -l app=server --tail=5000 | grep 'actor_key_id=' +``` + +### Aumento della verbosità + +| Componente | Variabile d'ambiente | Esempio | +|---|---|---| +| Server | `RUST_LOG` | `RUST_LOG=debug` o `RUST_LOG=agenteye_server=debug,info` | +| Dashboard | `AE_LOG_LEVEL` | `AE_LOG_LEVEL=debug` | + +`debug` sul server aggiunge una riga `api key authenticated` per auth. `debug` sul dashboard aggiunge righe `upstream request`, `session validated` e `proxy passthrough`. + +### Conservazione dei log + +Lo stdout del contenitore è effimero; kubelet ruota i file di log (default ~10 MiB per contenitore) e ne mantiene un numero ridotto su disco. Una volta eliminato un pod i log sono spariti. Se hai bisogno di una conservazione più lunga o di una ricerca cross-pod, punta il tuo cluster a un collector di log (Loki, CloudWatch, Cloud Logging, Datadog, ecc.) che traccia `/var/log/containers/`. AgentEye non richiede o prescrive alcuna scelta specifica. + +--- + +## Problemi di autenticazione + +### `docker pull` fallisce con "unauthorized" + +Assicurati di aver autenticato Docker su GHCR con il tuo `AGENTEYE_TOKEN`: + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +Il token deve avere permesso `read:packages` sull'org `agenteye-enterprise`. Contatta `support@exosphere.host` se il tuo token non funziona. + +### `gh release download` restituisce 404 o 401 + +- Conferma che `AGENTEYE_TOKEN` è esportato nella tua shell: `echo $AGENTEYE_TOKEN` +- Conferma che stai usando `GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download ...` (la CLI `gh` legge `GITHUB_TOKEN`) +- Il token ha bisogno di `contents:read` su `agenteye-enterprise/releases` + +--- + +## Problemi del server + +### Il server fallisce con "invalid port number" + +La `POSTGRES_PASSWORD` (o un'altra credenziale) contiene caratteri speciali URL (`/`, `+`, `=`) che interrompono l'analisi di `DATABASE_URL`. Rigenera la password utilizzando la codifica hex: + +```bash +NEW_PASS=$(openssl rand -hex 24) +``` + +Quindi aggiorna il secret Kubernetes e la password all'interno di Postgres (o ricrea il `.env` per Docker Compose), e riavvia il server. Vedi i passaggi completi in [enterprise-docs/kubernetes-deployment.md](/it/agenteye/kubernetes-deployment) § "PostgreSQL credentials". + +### Il server esce immediatamente all'avvio + +Controlla i log del contenitore: + +```bash +docker logs agenteye-server +``` + +Cause comuni: +- `DATABASE_URL` non impostato o malformato: il server registrerà l'errore e uscirà. +- Postgres non è raggiungibile: conferma che il contenitore Postgres o il DB gestito è in esecuzione e che host/porta sono corretti. +- Le migrazioni sono fallite: controlla i log per errori SQL. + +### `GET /health` restituisce non-200 o timeout + +Il server potrebbe ancora eseguire le migrazioni al primo avvio. Attendi alcuni secondi e riprova: + +```bash +curl http://localhost:8080/health +``` + +Se il problema persiste, controlla `docker logs agenteye-server` per gli errori. + +### `GET /ready` restituisce 503 + +`/ready` è il probe di readiness: restituisce `503` quando il server non riesce a raggiungere **Postgres o ClickHouse**. Il corpo nomina la dipendenza non funzionante: + +```bash +curl -s http://localhost:8080/ready +# {"status":"not_ready","checks":{"postgres":"ok","clickhouse":"down","redis":"ok"}} +``` + +Correggi qualunque dipendenza riporta come `down`: il pod ClickHouse/Postgres è `Running`? `CLICKHOUSE_URL` / `DATABASE_URL` è corretto e raggiungibile? Su Kubernetes il pod legge `NotReady` finché `/ready` non si recupera; è previsto ed è esattamente il segnale su cui gli alert di monitoraggio della salute si basano. Redis non è mai una causa: è riportato ma non fa fallire la readiness. + +### Il collector restituisce 401 Unauthorized + +La chiave API del collector non ha l'autorizzazione `events:add`, oppure la chiave è stata disabilitata. Crea una nuova chiave con il permesso corretto: + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{"name":"new-collector","permissions":["events:add"]}' +``` + +### Le richieste autenticate sono improvvisamente diventate lente (~200ms invece di ~5ms) + +Questo è il sintomo di Redis che è inattivo mentre `REDIS_URL` è impostato. Ogni chiamata cache timeout dopo 100ms e poi fallisce in Postgres; sui percorsi auth e OTP la richiesta effettua due tali fallimenti. + +Conferma nei log del server: + +``` +auth cache: L2 get failed error=redis call timed out +``` + +Risoluzione: + +1. `redis-cli -h ping` per confermare che Redis è raggiungibile sulla rete del cluster. +2. Se Redis era brevemente inattivo ed è ora di nuovo disponibile, **riavvia i pod del server**. `redis::aio::ConnectionManager` non ristabilisce in modo affidabile dopo che la connessione sottostante si interrompe; un riavvio del pod raccoglie la nuova connessione in modo pulito. Lo stesso vale per il dashboard. +3. Se non vuoi eseguire Redis in questo momento, cancella `REDIS_URL` nell'implementazione e riavvia. Entrambi i servizi funzionano senza la cache (la correttezza è conservata; la latenza ritorna alla baseline pre-Redis). + +### Il server riporta `OTP request rate-limited` nei log ma l'utente dice che ha provato solo una volta + +Controlla se Redis era irraggiungibile. Il percorso di fallback utilizza `SELECT COUNT(*) FROM otp_codes WHERE created_at > now() - interval '15 minutes'`, che vede le righe OTP precedentemente generate. Se l'utente è stato a fare clic ripetuto su "Resend" per un'ora, la finestra di 15 minuti potrebbe ancora contenere ≥5 codici. Risolvi aspettando che la finestra scorra o eseguendo `DELETE FROM otp_codes WHERE user_id = $1 AND created_at > now() - interval '15 minutes'` (console dell'operatore). + +### Ho cambiato `ALLOWED_EMAILS` / `SESSION_TTL_SECS` / `OTP_TTL_SECS` e riavviato; nulla è cambiato + +Queste variabili d'ambiente sono **seed del primo avvio solo**. Una volta che la tabella `settings` ha una riga per la chiave corrispondente, quella riga è la fonte di verità; la variabile d'ambiente viene letta una volta al primo avvio e quindi ignorata in ogni riavvio successivo. + +Per cambiarli dopo il primo avvio, accedi al dashboard e modificali in `/settings`. Il cambiamento si applica entro pochi secondi su tutte le repliche; nessun riavvio richiesto. + +Se hai bisogno di forzare un re-seed da env (raro, tipicamente utile solo in sviluppo), esegui `DELETE FROM settings WHERE key = ''` e riavvia il server. Il bootstrap raccoglierà il valore della variabile d'ambiente corrente al prossimo avvio. La modifica tramite `/settings` è il percorso supportato in produzione. + +--- + +## Problemi del collector + +### Il collector si avvia ma gli eventi non appaiono nel dashboard + +1. Conferma che il collector è in esecuzione: `systemctl status agenteye-collector` (Linux) o controlla il processo. +2. Conferma che `AGENTEYE_URL` punta a `http(s)://your-server-host:8080/events` (nota: percorso `/events`). +3. Esegui un flusso una tantum per vedere l'output immediato: + ```bash + agenteye-collector flush + ``` +4. Controlla che Python SDK stia effettivamente scrivendo file: `ls ${AGENTEYE_HOME:-~/.agenteye}/events/` +5. Se esistono file in `${AGENTEYE_HOME:-~/.agenteye}/failed/`, i caricamenti stanno fallendo. Controlla i log del collector per l'errore, probabilmente un 4xx (chiave o URL errato) o un problema di rete. + +### I file si stanno accumulando in `$AGENTEYE_HOME/events/` e non vengono caricati + +- Il collector potrebbe non essere in esecuzione. Avvialo: `agenteye-collector start`; scarica automaticamente gli eventi preesistenti all'avvio. +- Controlla la salute del collector: `agenteye-collector health` +- Il collector potrebbe essere in esecuzione ma non riuscire a raggiungere il server. Controlla le regole firewall tra gli host collector e server. + +### File in `$AGENTEYE_HOME/failed/` + +I file si spostano in `failed/` dopo che tutti i tentativi di ripetizione sono esauriti (predefinito: 5 tentativi con backoff esponenziale). Ciò significa che: +- Il server ha restituito un errore 4xx (chiave errata, URL sbagliato o problema di payload) +- Il server era irraggiungibile per l'intera finestra di ripetizione + +Correggi il problema sottostante, quindi ricoda manualmente: + +```bash +mv ${AGENTEYE_HOME:-~/.agenteye}/failed/*.jsonl ${AGENTEYE_HOME:-~/.agenteye}/events/ +agenteye-collector flush +``` + +### Il collector riporta `network error` su ogni caricamento (handshake TLS fallisce) + +Se `curl -k` contro `AGENTEYE_URL` ha successo ma il file binario del collector fallisce ogni caricamento con `error sending request for url (...)`, il server AgentEye sta presentando un certificato TLS che non è firmato da una CA pubblicamente attendibile. + +Il **percorso di produzione** è il nome host di ingestion ACME configurato in `deploy/base/certificates/domain.env` (vedi [`kubernetes-deployment.md`](/it/agenteye/kubernetes-deployment) Fase 3.1 / 4.2). Una volta che `INGEST_DOMAIN` si risolve verso il public Traefik LB e cert-manager ha emesso il certificato Let's Encrypt, i collector verificano il certificato del server rispetto all'archivio di fiducia del sistema **senza `AGENTEYE_TLS_CA` necessario**; cancellalo dalla configurazione del collector se era impostato rispetto a un'implementazione autofirmata più vecchia. + +**Sintomo: il collector ha funzionato ieri, fallisce oggi dopo un intervallo di ~90 giorni.** Ciò significa che l'implementazione è ancora sull'issuer `selfsigned` legacy per `ingest-tls`. Il certificato di 90 giorni ha ruotato e il file CA ancorato è obsoleto. Correggi permanentemente passando il cluster all'issuer ACME (Fase 3.1 della guida di implementazione). Sblocco a breve termine: estrai nuovamente il certificato del server corrente e aggiorna `AGENTEYE_TLS_CA`: + +```bash +kubectl get secret ingest-tls-cert -n agenteye \ + -o jsonpath='{.data.tls\.crt}' | base64 -d > /etc/agenteye/server-ca.crt +``` + +```bash +export AGENTEYE_TLS_CA=/etc/agenteye/server-ca.crt +agenteye-collector flush +``` + +`AGENTEYE_TLS_CA` aggiunge un ancoraggio di fiducia aggiuntivo; le radici pubbliche standard sono ancora attendibili. + +### Il certificato `ingest-tls` è bloccato con `Ready: False` dopo la distribuzione + +```bash +kubectl describe certificate ingest-tls -n agenteye +``` + +Guarda gli `Events` e l'`Order` / `Challenge` a cui si fa riferimento. Cause comuni: + +- **DNS non risolve verso il public LB.** Il validatore HTTP-01 non riesce a raggiungere `INGEST_DOMAIN`. Verifica con `dig +short INGEST_DOMAIN`; dovrebbe risolvere allo stesso indirizzo del `EXTERNAL-IP` del LoadBalancer `traefik-public`. cert-manager ritenta automaticamente una volta propagato il DNS; non è necessario eliminare il certificato. +- **Porta 80 bloccata al load balancer / security group.** HTTP-01 richiede che la porta 80 sia raggiungibile dai validatori pubblici di Let's Encrypt. Se hai un WAF a monte o SG che limita `:80`, aprilo (la configurazione di Traefik reindirizza a HTTPS, ma Boulder segue il reindirizzamento e accetta la risposta). +- **`dnsNames` non sostituito.** Se `kubectl get certificate ingest-tls -n agenteye -o jsonpath='{.spec.dnsNames}'` mostra `INGEST_DOMAIN_PLACEHOLDER`, hai saltato il passaggio `domain.env`; crealo da `domain.env.example` e riapplica. +- **Rate limited da Let's Encrypt.** Gli ordini ripetuti non riusciti per lo stesso nome host attivano i limiti di certificato duplicato o convalida non riuscita. Attendi almeno un'ora prima di riprovare; controlla lo stato dell'ordine per il messaggio di rate-limit esatto. + +### Il certificato `dashboard-tls` è bloccato con `Ready: False` / il browser mostra ancora un avviso + +Lo stesso flusso di diagnosi di `ingest-tls` sopra (`kubectl describe certificate dashboard-tls -n agenteye`); le cause DNS, porta-80, placeholder e rate-limit si applicano tutte, più due specifiche del dashboard: + +- **`DASHBOARD_DOMAIN` risolve al LoadBalancer sbagliato.** Deve puntare al LB Traefik del *dashboard*, non a quello di ingestion pubblico. Esegui `dig +short` sul nome host e confronta con l'indirizzo del LB del dashboard. +- **L'istanza Traefik del dashboard non può servire la sfida.** Deve essere installata con il file di valori del dashboard bundle, che abilita un provider Ingress con ambito per il risolutore HTTP-01 di cert-manager. Senza di esso il risolutore non è instradabile e l'ordine rimane `pending` per sempre. Aggiorna l'istanza con i valori forniti; la sfida pendente si completa quindi da sola. +- **Il LoadBalancer era limitato IP.** I range di origine si applicano anche alla porta 80, il che blocca i validatori di Let's Encrypt — sia il primo rilascio che ogni rinnovo di ~75 giorni. Riapri il LB, o coordina un risolutore DNS-01 con il supporto prima di bloccarlo. + +Durante il fallimento dell'emissione, il dashboard continua a servire il suo certificato precedente (o il valore predefinito dell'ingress su un'installazione nuova) — l'accesso è degradato da un avviso del browser, mai inattivo. + +### La CLI continua a saltare la verifica TLS dopo che il dashboard ha ottenuto un certificato attendibile + +`--insecure` è persistito su `cli.json` al login. Una volta che il dashboard serve un certificato pubblicamente attendibile, accedi di nuovo con `agenteye --base-url https:// --secure login`; la verifica viene salvata di nuovo e l'avviso di avvio scompare. + +--- + +## Problemi del dashboard + +### Impossibile disabilitare o modificare l'utente `ADMIN_EMAIL` + +Per progettazione. L'utente che corrisponde a `ADMIN_EMAIL` è contrassegnato come protetto ad ogni avvio del server: il dashboard nasconde il pulsante Disabilita per quella riga e l'API rifiuta `DELETE /users/:id` e `PUT /users/:id` contro di essa con `403 Forbidden`. Un trigger del database rifiuta anche istruzioni `UPDATE` dirette che disabiliterebbero la riga protetta. + +Per ruotare l'admin di bootstrap, cambia `ADMIN_EMAIL` nel tuo ambiente e riavvia il server. Il nuovo email è upsertato come protetto. L'admin precedente mantiene il flag protetto fino a quando non viene cancellato nel database (tipicamente va bene, poiché l'email precedente è comunque un admin valido fino a quando non lo rimuovi esplicitamente). + +### Il dashboard non mostra eventi + +1. Conferma che l'URL del server e la chiave API sono corretti nelle variabili d'ambiente del dashboard (`AGENTEYE_SERVER_URL`, `AGENTEYE_API_KEY`). +2. La chiave API del dashboard ha bisogno dell'autorizzazione `events:read`. +3. Conferma che gli eventi sono stati effettivamente acquisiti: `curl http://your-server:8080/events -H "Authorization: Bearer $ADMIN_KEY"` + +### `/errors` è vuoto ma `/events` mostra righe rosse + +Le versioni più recenti di SDK emettono guasti come eventi `agent_end` / `tool_result` / `hook_completed` con `outcome: "error"` nel payload, anziché come una riga `event_type: "error"` dedicata. La pagina `/errors` ora corrisponde a entrambi: qualsiasi riga che il flusso `/events` pinta di rosso (esplicito `event_type='error'`, payload `outcome`/`status` nell'insieme di guasto, `is_error: true`, o un campo `error` veritiero) appare su `/errors`. Se in precedenza hai visto "nessun errore in questa finestra" mentre le righe rosse erano visibili su `/events`, aggiorna il dashboard + server insieme (il filtro ampliato è `errored=true` su `GET /events`) e le due viste saranno d'accordo. + +### `/models`, `/tools` o `/hooks` è lento o non riesce a caricare su ampi intervalli di tempo + +**Sintomo:** su una grande tabella di eventi (milioni di righe), l'apertura di `/models`, `/tools` o `/hooks` — o l'ampliamento dell'intervallo di tempo a `7d`, `30d` o `all` — i grafici girano e poi mostrano un errore di caricamento. Il server registra un ClickHouse `MEMORY_LIMIT_EXCEEDED` (Codice 241) o un timeout della query per la richiesta `latency_aggregate`. + +**Causa:** le build più vecchie calcolavano i rollup di latenza e distribuzione di queste pagine con una query che leggeva il `payload` dell'evento grezzo completo e associava gli eventi di richiesta/risposta con un'ordinazione e un join in memoria. Il picco di memoria della query quindi cresceva con la dimensione della finestra, quindi su un tenant occupato un'ampia gamma potrebbe superare il ceiling di memoria per query di ClickHouse. + +**Correzione:** aggiorna a una build che include questa correzione. Il rollup ora legge solo le colonne promosse compatte e associa gli eventi con un'aggregazione di streaming, quindi il picco di memoria non scala più con il payload grezzo — le finestre larghe rimangono ben all'interno del ceiling di memoria e vengono restituite in una frazione del tempo. Il miglioramento è interamente lato query: si applica a tutti i dati esistenti al successivo caricamento della pagina, senza ricoingestione o backfill. + +### Il dashboard non riesce a caricare / pagina vuota + +Controlla i log del contenitore del dashboard: + +```bash +docker logs agenteye-dashboard +``` + +La causa più comune è che `AGENTEYE_SERVER_URL` o `AGENTEYE_API_KEY` manchi o punti a un server irraggiungibile. + +### Analitiche/telemetria del dashboard + +Il dashboard invia analitiche sull'utilizzo dei prodotti anonime a PostHog per impostazione predefinita, instradate tramite il percorso `/ingest` del dashboard stesso (un proxy inverso a `https://us.i.posthog.com`). L'invio in primo piano significa che i blocker di annunci del browser non li eliminano. Questo è indipendente dalla funzionalità principale del dashboard: + +- Il **contenitore dashboard** (non il browser) è ciò che raggiunge PostHog. Se il suo accesso in uscita a `https://us.i.posthog.com` è bloccato, la telemetria silenziamente non-op; il dashboard funziona normalmente e nessun errore viene visualizzato agli utenti. +- Non vengono mai inclusi dati di agenti, sessioni o eventi, solo l'utilizzo dell'UI del dashboard. +- Per disabilitare la telemetria interamente, imposta `AE_ANALYTICS_DISABLED=1` sul contenitore del dashboard e riavvia. Vedi [Telemetria & privacy](/it/agenteye/deployment#telemetria--privacy) nella guida di distribuzione. + +### Telemetria della CLI / telemetria + +La CLI `agenteye` invia analitiche sull'utilizzo anonime a PostHog per impostazione predefinita: quali comandi vengono eseguiti, stato di successo/uscita e durata. Questo è indipendente dalla funzionalità della CLI: + +- La **macchina che esegue la CLI** raggiunge direttamente `https://us.i.posthog.com`. Se il suo accesso in uscita è bloccato, la telemetria silenziamente non-op (l'invio è limitato nel tempo, quindi non ritarda mai un comando) e la CLI funziona normalmente. +- Non vengono mai inclusi dati di agenti, sessioni o eventi: gli **argomenti e i valori del flag** del comando (URL del dashboard, token, email, ID della sessione, filtri di query) non vengono mai inviati. +- Per disabilitarlo, imposta `AGENTEYE_ANALYTICS_DISABLED=1` (o il cross-tool `DO_NOT_TRACK=1`) nell'ambiente della CLI. Vedi [Telemetria & privacy](/it/agenteye/cli#telemetria--privacy) nella guida della CLI. + +--- + +## Problemi dell'assistente AI + +Vedi [enterprise-docs/assistant.md](/it/agenteye/assistant) per la configurazione completa. + +### La bolla dell'assistente non appare + +La bolla è nascosta a meno che **tutti** questi non siano veri: + +- L'utente connesso ha l'autorizzazione `agent:use`. +- `AGENTEYE_AGENT_URL` è impostato sul dashboard e il servizio `agent` è raggiungibile. +- Un endpoint LLM è configurato sul servizio `agent` (`ANTHROPIC_API_KEY`, un gateway tramite `ANTHROPIC_BASE_URL`, o Bedrock/Vertex). Senza alcuno impostato, l'agente riporta "non configurato" e la bolla rimane nascosta. + +Controlla la salute dell'agente dall'host del dashboard: `curl http://agent:9100/health` dovrebbe restituire `{"status":"ok","llm_configured":true,...}`. + +### L'assistente dice che non può leggere qualcosa + +Gli strumenti sono controllati per utente. Se un utente non dispone di `evaluations:read` (o `events:read`, `dashboards:read`), gli strumenti corrispondenti non vengono offerti e l'assistente dirà che non può leggere quei dati. Concedi il permesso di lettura pertinente. + +### "assistente non configurato" (HTTP 503) durante l'invio + +Il contenitore `agent` non ha un endpoint LLM configurato, oppure il `AGENTEYE_AGENT_TOKEN` del dashboard non corrisponde a quello dell'agente. Imposta entrambi e riavvia. + +### Il contenitore `agent` si riavvia / OOM sotto carico + +Ogni conversazione genera un processo figlio di breve durata. Assicurati che il contenitore venga eseguito con un processo init (l'immagine usa `tini`; in Compose imposta `init: true`) e dagli limiti di memoria adeguati. Riduci `AGENTEYE_AGENT_MAX_STEPS` se necessario. + +--- + +## Problemi della CLI + +### `agenteye` non riesce ad avviarsi con `ModuleNotFoundError: No module named 'click'` + +Un'installazione nuova della CLI `agenteye` alla versione **0.1.6** può bloccarsi all'avvio con: + +``` +ModuleNotFoundError: No module named 'click' +``` + +0.1.6 si affidava a `click` per essere installato indirettamente da `typer`; i rilasci `typer` attuali non lo estraggono più, quindi un ambiente pulito finisce per mancare il pacchetto. **Aggiorna a 0.1.7 o versioni successive**, che dipendono da `click` direttamente: + +```bash +pipx upgrade agenteye # se installato con pipx (o: pipx install --force agenteye) +uv tool upgrade agenteye # se installato con uv +pip install --upgrade agenteye +``` + +Vedi [enterprise-docs/cli.md](/it/agenteye/cli) per la guida di installazione. + +--- + +## Problemi di Python SDK + +### Nessun file che appare in `$AGENTEYE_HOME/events/` + +L'SDK memorizza nel buffer gli eventi e scarica ogni 500 ms per impostazione predefinita. Se il tuo processo esce prima dello scaricamento, gli eventi potrebbero andare persi. Chiama `agenteye.configure(flush_interval=0.1)` per uno scaricamento più veloce negli script di breve durata, o assicurati che il tuo processo sia in esecuzione abbastanza a lungo per un ciclo di scaricamento. + +Se `AGENTEYE_HOME` è impostato, verifica che l'SDK stia scrivendo in `$AGENTEYE_HOME/events/` e non in `~/.agenteye/events/` (richiede SDK ≥ 0.0.1b5). + +### `ValueError: Reserved field names cannot be used as custom fields` + +I nomi `timestamp`, `type` e `environment` sono riservati e non possono essere usati come campi personalizzati. Passare uno qualsiasi di loro solleva: + +``` +ValueError: Reserved field names cannot be used as custom fields: [...] +``` + +Rinomina il campo personalizzato offensivo. Nota che `session_id` e `agent_id` sono parametri espliciti della chiamata dell'evento, non campi personalizzati; passare uno di essi nuovamente come campo personalizzato solleva `TypeError`. + +--- + +## Problemi di monitoraggio della salute + +### Nessun avviso in arrivo su Slack (Robusta) + +L'avviso della salute di Robusta è **opt-in**; non invia nulla finché non è installato e puntato a un canale Slack. Verifica il rilascio e il suo sink: + +```bash +kubectl get pods -n robusta # robusta-runner + robusta-forwarder dovrebbero essere Running +kubectl logs -n robusta -l app=robusta-runner --tail=50 +``` + +Cause comuni: `api_key` / `slack_channel` di Slack non erano impostati (o il token è stato revocato); `api_key` è un token di relay cloud di Robusta (`robusta integrations slack`) ma il `disableCloudRouting: true` in bundle ha bisogno di un **bot token** Slack self-hosted (`xoxb-…`), o imposta `disableCloudRouting: false`; l'ambito del sink esclude lo spazio dei nomi in cui i tuoi pod vengono eseguiti (i valori in bundle hanno ambito `agenteye`); o ancora non c'è stata alcuna interruzione. Forza un avviso di test eliminando un pod: + +```bash +kubectl -n agenteye delete pod -l app=clickhouse # verrà ricreato +``` + +Vedi [enterprise-docs/health-monitoring.md](/it/agenteye/health-monitoring#2-pod-failure-alerting-with-robusta-opt-in) per l'installazione e la configurazione. + +### Il server continua a fluttuare `NotReady` + +Il probe di readiness colpisce `/ready`, che fallisce quando Postgres o ClickHouse è irraggiungibile. Se il server cicla dentro e fuori da `NotReady`, una dipendenza è intermittentemente non disponibile; controlla i pod di ClickHouse e Postgres e il `CLICKHOUSE_URL` / `DATABASE_URL` del server. Conferma cosa riporta `/ready`: + +```bash +kubectl -n agenteye exec deploy/server -- sh -c 'curl -s localhost:8080/ready' +``` + +Questo probe è deliberatamente tollerante (un generoso threshold di fallimento), quindi la fluttuazione sostenuta indica un vero problema di dipendenza piuttosto che un probe troppo aggressivo. La liveness rimane su `/health`, quindi la fluttuazione della readiness **non** riavvierà il pod. + +## Problemi di monitoraggio dei certificati + +### CronJob non sta inviando notifiche Slack + +`cert-renewal-check` CronJob richiede un URL webhook Slack archiviato in un Secret. Verifica che esista: + +```bash +kubectl get secret cert-renewal-notify-config -n agenteye +``` + +Se manca, crealo: + +```bash +kubectl create secret generic cert-renewal-notify-config \ + --namespace agenteye \ + --from-literal=SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL" +``` + +Senza il secret, CronJob continua a essere eseguito e registra i risultati su stdout. Controlla i log con: + +```bash +kubectl logs -n agenteye -l job-name --tail=50 +``` + +### Il certificato client è scaduto prima che venisse ricevuta una notifica + +CronJob viene eseguito ogni 12 ore. Se non è stato eseguito, controlla il suo stato: + +```bash +kubectl get cronjob cert-renewal-check -n agenteye +``` + +Attiva un controllo manuale: + +```bash +kubectl create job --from=cronjob/cert-renewal-check manual-cert-check -n agenteye +kubectl logs -n agenteye -l job-name=manual-cert-check +``` + +Per ri-emettere immediatamente il certificato scaduto: + +```bash +cd base/certificates/client-certs +./issue-client-cert.sh +``` + +Quindi applica il `collector-mtls-secret.yaml` rigenerato nel cluster(i) che esegue i collector e riavviali: + +```bash +kubectl apply -f collector-mtls-secret.yaml -n +``` + +--- + +## Problemi di backup + +### `agenteye-backup` fallisce con "No space left on device" + +CronJob `agenteye-backup` scarica Postgres + ClickHouse in un `backup-tmp` volume scratch `emptyDir` (predefinito `30Gi`), quindi **effettua lo streaming** dell'archivio `tar` direttamente verso S3 — l'archivio compresso non viene mai riscritto sul scratch, quindi lo scratch deve solo contenere i *dump grezzi*, non dump + una seconda copia di archivio su disco. Un pod evitato / `No space left on device` significa quindi che i **dump grezzi** superano la dimensione del scratch (il dump `events` di ClickHouse domina e cresce nel tempo). Controlla i log del job non riuscito: + +```bash +kubectl logs -n agenteye -l job-name= +``` + +Correzione: nel tuo overlay, aumenta il `sizeLimit` dell'`emptyDir` del `backup-tmp` di CronJob sopra il totale del dump grezzo, e assicurati che il dispositivo di archiviazione effimera del nodo possa effettivamente contenerlo (`sizeLimit` è un cap, non una prenotazione). Se i dump superano il disco di un singolo nodo, sostituisci l'`emptyDir` con un PVC (EBS/PD) per `backup-tmp`, o comprimi i dump all'origine. + +> Le versioni più vecchie scrivevano il `.tar.gz` nello *stesso* scratch `20Gi` dei dump, quindi `dump + archivio` lo ha superato e il pod è stato evitato **prima** che l'upload fosse eseguito — il che sembra un guasto S3 ma è veramente disco. Lo streaming dell'upload rimuove quel raddoppio. + +### `agenteye-backup` fallisce installando `curl` + +Il job viene eseguito sull'immagine `postgres:16` e installa `curl` all'avvio per il dump HTTP di ClickHouse. Su un cluster senza uscita verso i mirror del pacchetto Debian, il passaggio `apt-get` fallisce. Consenti quel egress dal pod di backup, o costruisci `curl` in un'immagine di backup personalizzata/con mirror e referenziala nel tuo overlay. + +### `agenteye-backup` viene eseguito ma nulla arriva nell'object storage + +La base spedisce un vero `BACKUP_BUCKET` (`ts-prod-agenteye/backups`) e il ServiceAccount `agenteye-backup`. Il job **effettua lo streaming** dell'archivio verso S3 (`tar cz … | aws s3 cp - s3://…`). Se il pod di backup non ha accesso in scrittura al bucket, l'upload fallisce — e poiché lo script viene eseguito in `set -euo pipefail`, un fallimento in qualsiasi punto del pipe **fallisce** l'intero job al passaggio `upload` piuttosto che silenziare non-op (il trap EXIT del pod registra `backup FAILED during step: upload`). Questo è anche il passaggio che raggiungi *dopo* aver corretto un'evizione di spazio scratch, quindi se i backup erano precedentemente evitati al passaggio di archivio, verifica che l'upload ora arriva. Grep il log del job non riuscito per l'errore di accesso S3: + +```bash +kubectl logs -n agenteye -l job-name= | grep -iE 's3|upload|denied' +``` + +Correzione: nel tuo overlay imposta `BACKUP_BUCKET` su un bucket che possiedi e annota il ServiceAccount `agenteye-backup` esistente con accesso in scrittura (IRSA / Workload Identity / Pod Identity). Vedi la sezione **Backups** di [enterprise-docs/kubernetes-deployment.md](/it/agenteye/kubernetes-deployment). + +--- + +## Valutazioni supportate da ClickHouse / sessioni / query + +### La barra laterale della pagina `/queries` è vuota dopo l'aggiornamento + +Sono previste tre tabelle (`events`, `evaluations`, `agent_sessions`). Se la barra laterale SchemaBrowser è vuota dopo l'aggiornamento, il server non ha applicato il DDL di ClickHouse all'avvio. Controlla i log del server per `failed to apply CH DDL statement`: + +```bash +kubectl logs -n agenteye deploy/server | grep -E 'clickhouse|CH DDL' +``` + +La causa più comune è che ClickHouse non sia raggiungibile durante l'esecuzione delle migrazioni. Il server rifiuta di avviarsi se non riesce a raggiungere CH, quindi un pod bloccato di solito ha un `CrashLoopBackOff` piuttosto che una pagina di query silenziosamente interrotta, ma un'applicazione DDL parziale (un'istruzione OK, i prossimi 5xx) lascia lo schema mezzo-cotto. Riavvia il pod del server dopo che è stato verificato che CH è raggiungibile: + +```bash +kubectl rollout restart deploy/server -n agenteye +``` + +### Le nuove valutazioni non appaiono in `/sessions` o `/queries` + +Dopo l'aggiornamento, le nuove valutazioni vengono scritte su ClickHouse, non su Postgres, e appaiono in `/sessions` (con gatekeeping su `evaluations:read`) e in `/queries`. Se non appaiono: + +1. Conferma che la pipeline dell'evaluator sia abilitata (`EVALUATOR_ENDPOINT` impostato sul server) e stia producendo risultati terminali; controlla le righe `evaluation_finalized`. +2. Conferma che CH sia raggiungibile dal server: `kubectl exec -n agenteye deploy/server -- curl -fsS http://clickhouse:8123/ping`. +3. Spot-check la tabella CH: `kubectl exec -n agenteye clickhouse-0 -- clickhouse-client -q 'SELECT count() FROM agenteye.evaluations'`. + +### Le query falliscono sotto carico con "Memory limit exceeded", oppure ClickHouse è `OOMKilled` + +**Sintomo:** sotto carico pesante di dashboard/query, le pagine analitiche (lo stream di eventi, `/sessions`, la visualizzazione latenza/modelli, l'editor SQL) iniziano a fallire o timeout; il server brevemente fluttua `NotReady`; e il pod di ClickHouse mostra un conteggio di riavvio in aumento. Questo è quasi sempre **memoria**, non CPU o disco. + +**Conferma che sia memoria** (non un problema di throughput che la replica risolverebbe): + +1. Controlla il pod per kill da mancanza di memoria: + ```bash + kubectl -n agenteye describe pod clickhouse-0 | grep -iE 'Restart Count|Last State|Reason|OOMKilled' + ``` + `Reason: OOMKilled` / `Exit Code: 137` con un conteggio di riavvio crescente è il contrassegno. + +2. Chiedi a ClickHouse cosa sta rifiutando: + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT name, value FROM system.errors WHERE value>0 ORDER BY value DESC" + ``` + Un grande conteggio di `MEMORY_LIMIT_EXCEEDED` è la firma. Il messaggio legge *"maximum: N GiB"* — quel **N è `0.9 × il limite di memoria del pod`** (il `max_server_memory_usage_to_ram_ratio` in `deploy/base/clickhouse/configmap.yaml`). Se le tue letture pesanti hanno bisogno di più di N, vengono rifiutate. + +3. Escludi le cose che *non* sono il problema — se CPU, conteggio parti e disco sono tutto basso, aggiungere repliche/sharding sarebbe costo sprecato: + ```bash + kubectl -n agenteye top pod clickhouse-0 + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT table, count() parts FROM system.parts WHERE active AND database='agenteye' GROUP BY table" + ``` + +**Causa:** il limite di memoria del pod di ClickHouse è troppo piccolo per il set di lavoro analitico. Le letture più pesanti estraggono la colonna JSON `payload` grezza, eseguono `JSONExtract*` su di essa, e usano `FINAL` — ognuna può avere bisogno di diversi GiB. Se le cache configurate (`mark_cache_size` + `uncompressed_cache_size`) sono più grandi del pod, le compongono: le cache sono caricate contro lo stesso budget e affollano la memoria di query. + +**Correzione — scala la memoria di ClickHouse:** + +1. Aumenta il limite di memoria di ClickHouse nel tuo overlay patchando le `resources` del contenitore StatefulSet `clickhouse` (lo stesso meccanismo di overlay usato per le `resources` degli altri componenti). Il budget del server utilizzabile è `0.9 × limit`, quindi un limite `6Gi` dà ~5.4 GiB, `16Gi` dà ~14 GiB. Imposta anche `requests.memory` a un floor vero, quindi lo scheduler lo prenota. L'applicazione di questo **ricrea il pod CH** (singola replica → ~30–60s di downtime analitico); fallo in una finestra di traffico basso. +2. Mantieni le cache in `deploy/base/clickhouse/configmap.yaml` proporzionate al limite — cache piccole (pochi centinaio MiB) sono sicure su un pod piccolo; aumentale solo insieme a un corrispondente aumento del limite di memoria. `max_memory_usage` per query è impostato esplicitamente nel profilo `users.xml` (vedi la sezione di nodo fisso di seguito) e viene mantenuto sotto il cap a livello di server (`0.9 × limit`) quindi nessuna singola query è *consentita* più RAM del contenitore. +3. Se il nodo stesso è il ceiling, controlla la memoria dell'host che ClickHouse può vedere: + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT formatReadableSize(value) FROM system.asynchronous_metrics WHERE metric='OSMemoryTotal'" + ``` + Se è solo un po' più in alto del limite del pod, sposta ClickHouse su un nodo più grande (ottimizzato per memoria) — tramite un selettore di nodo/affinità nel tuo overlay — prima di aumentare ulteriormente il limite. + +**Quando non puoi aggiungere memoria: esegui le query in RAM e fallisci velocemente — non versare su un disco lento.** Se il nodo è fisso e il pod non può crescere, cappare quello che qualsiasi singola query può usare (quindi una query non può prendere l'intero nodo) e, su un **disco dati lento (non-SSD)**, **non** lasciare che le aggregazioni/ordinamenti grandi si versino su disco. Versare su un disco lento è più lento del timeout di lettura del client del server, quindi una query che versa restituisce un dashboard `500` a metà volo mentre ClickHouse continua a macinare — mantenere le query in RAM e rifiutare la rara sovraspesa velocemente (`MEMORY_LIMIT_EXCEEDED`, sub-secondo) è ciò che ripristina il caricamento. Nota una gotcha di ClickHouse per l'applicazione di questi: + +- **Questi sono impostazioni di *profilo*, e ClickHouse legge `` solo da `users_config` (`users.xml` / `users.d/*.xml`) — mai da `config.d`.** Un blocco `` posto in `config.d/agenteye.xml` è **silenziosamente ignorato** (`max_execution_time`, `max_memory_usage`, ecc. semplicemente non si applicano). La configurazione in bundle quindi li spedisce come una chiave `users.xml` su ConfigMap `clickhouse-config`, montata in `/etc/clickhouse-server/users.d/agenteye.xml`. +- I default spediti: `max_memory_usage` (per-query ceiling — una query non può consumare l'intero budget del server), `max_bytes_before_external_group_by` / `max_bytes_before_external_sort` = **`0` (versamento disabilitato)** quindi le query rimangono in RAM invece di strisciare sul disco lento, e `max_execution_time` (guardia runaway, allineato al timeout di lettura del client del server). +- **Verifica che siano live** (questo è anche come tu rilevi la gotcha di config.d): + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT name, value FROM system.settings + WHERE name IN ('max_memory_usage','max_bytes_before_external_group_by','max_execution_time')" + ``` + Aspettati un `max_memory_usage` diverso da zero e `max_bytes_before_external_group_by = 0`. Se `max_memory_usage` legge `0`/default, il profilo non viene applicato — controlla che le impostazioni vivano in un mount `users.d`, non `config.d`. + +Trade-off: con versamento disabilitato, una query il cui set di lavoro eccede `max_memory_usage` è **rifiutato** (`MEMORY_LIMIT_EXCEEDED`) piuttosto che completarsi lentamente — su un disco lento quel rifiuto veloce è preferibile, perché una query che versa supererebbe il timeout del client e fallirebbe comunque. Se il tuo disco dati è **veloce (SSD)**, puoi invece aumentare le soglie di `max_bytes_before_external_*` per lasciare che le query grandi si versino su disco e si completino. + +--- + +## Multi-tenancy (organizzazioni) + +### Errori durante l'aggiornamento che abilita le organizzazioni (pod del server vecchio/nuovo misti) + +**Sintomo:** durante un'implementazione rolling della release che abilita l'org, alcuni richieste falliscono: i log del server mostrano `there is no unique or exclusion constraint matching the ON CONFLICT specification` nel percorso `api_keys`, e/o gli avvisi/Slack/canali webhook smettono di funzionare mentre il rollout è in volo. + +**Causa:** l'aggiornamento sostituisce il vecchio indice univoco a livello di istanza su `api_keys(name)` con indici parziali per-org, e sposta le impostazioni del canale di allerta (e `default_user_permissions`) dalla tabella `settings` globale all'org per-org `org_settings`. Un pod del server **vecchio** ancora emette `ON CONFLICT (name)` (ora nessun constraint corrispondente) e legge ancora la configurazione del canale dalle vecchie righe `settings` (ora vuote). I pod vecchi e nuovi non possono coesistere in sicurezza per questi due percorsi. + +**Correzione:** non eseguire lentamente roll questo particolare aggiornamento su versioni miste. Passare in modo pulito: scalare il server vecchio a zero (o utilizzare una breve finestra di manutenzione) e portare la nuova versione con le sue migrazioni, piuttosto che eseguire repliche vecchie e nuove fianco a fianco. Il traffico normale e l'ingest riprendono immediatamente dopo il cutover; questo influisce solo sulla finestra di transizione della versione. + +### Il provisioning di un'organizzazione fallisce su `CREATE USER` / `CREATE ROW POLICY`, oppure un'org può leggere i dati di un'altra org + +**Sintomo:** la creazione di un'org restituisce un errore che menziona `CREATE USER`, `CREATE ROW POLICY`, o "access management is disabled"; o, peggio, i membri di un'org vedono gli eventi/valutazioni di un'altra org nell'editor SQL o nell'assistente. + +**Causa:** l'isolamento per-org è applicato da un utente ClickHouse dedicato + politica di riga per org. Questo richiede **access management** di SQL per essere abilitato e `users_without_row_policies_can_read_rows=false` su ClickHouse. Con access management spento, il provisioning non può creare l'utente/politica; con il default della politica di riga lasciato al suo valore permissivo, un utente che ha SELECT ma nessuna politica legge **tutte** le righe (fail-open). + +**Correzione:** usa la configurazione `deploy/base/clickhouse/` in bundle, che imposta entrambe. Se esegui la tua configurazione ClickHouse, abilita SQL access management sull'utente server-interno e imposta `users_without_row_policies_can_read_rows=false` (vedi `deploy/base/clickhouse/configmap.yaml`), quindi riavvia ClickHouse e ricrea l'org con la CLI `agenteye-orgctl` (vedi [enterprise-docs/tenant-management.md](/it/agenteye/tenant-management)). + +### Gli utenti dell'org perdono l'accesso a ClickHouse dopo il cambiamento di `ORG_CH_SECRET` + +**Sintomo:** l'editor SQL e l'assistente AI improvvisamente restituiscono errori di autenticazione ClickHouse per ogni organizzazione, immediatamente dopo che `ORG_CH_SECRET` è stato modificato o impostato in modo incoerente su repliche. + +**Causa:** la password ClickHouse di ogni org è derivata come HMAC di `ORG_CH_SECRET`. Ruotarlo (o eseguire repliche con valori diversi) invalida le credenziali ClickHouse memorizzate di ogni org; la password derivata non corrisponde più all'utente provisioning. + +**Correzione:** imposta `ORG_CH_SECRET` su un unico valore forte **prima** di provisioning una seconda org e mantienilo stabile e identico su ogni replica del server. Il riconciliarsi del tempo di avvio del server riprovvede l'utente ClickHouse di ogni org dal secret corrente all'avvio, quindi un riavvio del server su tutte le repliche (con il secret coerente) guarisce gli utenti orfani. Tratta il valore come un secret di lunga durata; non ruotarlo casualmente. Come rete di sicurezza, se `ORG_CH_SECRET` è lasciato al default di sviluppo built-in (cioè non impostato), il riconciliarsi del tempo di avvio **salta** le organizzazioni non predefinite e registra un errore anziché riscrivere le loro credenziali ClickHouse al valore dev pubblicamente noto, quindi una singola replica che si riavvia senza il secret non può rompere le altre repliche. Imposta il secret in modo coerente e riavvia per provisioning quelle org. + +### L'assistente AI restituisce 400 / rifiuta di chattare dopo l'abilitazione delle organizzazioni + +**Sintomo:** la dock dell'assistente si carica ma ogni messaggio torna con un errore (HTTP `400`), e l'agente registra una richiesta `/chat` senza org rifiutata. + +**Causa:** l'agente è consapevole dell'org e fallisce chiuso; rifiuta un `/chat` che non porta contesto organizzativo. Questo accade durante un rollout transizionale dove l'agente è stato aggiornato ma il dashboard che invia la richiesta non è ancora org-aware. + +**Correzione:** termina il rollout in modo che il dashboard invii il contesto dell'org (lo stato finale normale, nessun flag necessario). Per colmare il divario mentre un dashboard non ancora org-aware parla a un agente org-aware, imposta `AGENTEYE_AGENT_ALLOW_NO_ORG=1` sul servizio `agent` in modo che effettui il fallback all'org `default` anziché rifiutare, e cancellalo una volta che l'aggiornamento del dashboard arriva. Vedi il riferimento env in [enterprise-docs/assistant.md](/it/agenteye/assistant#environment-variable-reference). + +--- + +## Audit + +### Un audit non viene mai eseguito (il prossimo run continua a scivolare, nessuna cronologia di esecuzione) + +**Sintomo:** la pagina di audit mostra *last run: never*, o `next run` continua a muoversi nel futuro senza una riga che appare nella cronologia di esecuzione. + +**Causa:** l'audit è disabilitato (gli audit disabilitati non hanno voce nella coda), oppure i worker di audit del server non riescono a rivendicare il lavoro. + +**Correzione:** conferma che l'audit sia **abilitato** (il pulsante esegui-ora lo richiede). Quindi controlla i log del server per `audits pipeline started` all'avvio e per errori `audits:` — una riga `claim_due failed` punta alla connettività di Postgres. `AUDIT_WORKERS` predefinito `1`; deve essere ≥ 1 affinché qualsiasi audit venga eseguito. + +### Le esecuzioni di audit hanno successo ma non trovano nulla + +**Sintomo:** la cronologia di esecuzione mostra `succeeded` con `findings: 0` anche se `/errors` chiaramente mostra guasti. + +**Causa:** la finestra di scansione non copre i guasti, o i filtri di ambito li escludono. + +**Correzione:** controlla la finestra della riga di esecuzione (`window_from → window_to`) rispetto a quando i guasti si sono verificati — in modalità `since_last` ogni esecuzione esegue la scansione solo dall'esecuzione precedente riuscita, quindi i guasti più vecchi vengono visualizzati solo dalla *prima* esecuzione o da un audit a `fixed`-window. Amplia `scope` (ambienti / id agenti). Le statistiche di esecuzione mostrano `policy_hits` (quanti criteri deterministici si sono attivati) e `improvements` (quanti l'indagine AI ha registrato) — se entrambi sono 0, la finestra/ambito genuinamente non ha visto nulla. + +### L'esecuzione dice `analysis_unavailable` e produce solo risultati di politica + +**Sintomo:** le statistiche di esecuzione includono `analysis_unavailable` e i soli risultati sono `kind: policy`; nessun miglioramento AI appare. + +**Causa:** l'indagine agenziale non poteva essere eseguita: il server non riesce a raggiungere il servizio agent (`AGENTEYE_AGENT_URL` / `AGENTEYE_AGENT_TOKEN` non impostato sul **server** — l'audit riutilizza la connessione dell'assistente), il servizio assistente non ha LLM configurato, oppure la chiamata ha generato errore/timeout (la stringa `analysis_unavailable` ha il dettaglio). Il pass di politica deterministica è il floor — sempre viene eseguito — quindi l'audit comunque ha successo con i suoi risultati di sicurezza. + +**Correzione:** imposta `AGENTEYE_AGENT_URL` (ad es. `http://agent:9100`) e `AGENTEYE_AGENT_TOKEN` sul **server** — gli stessi valori che l'assistente dashboard usa già (i manifesti/compose in bundle ora li innestano) — e configura un LLM sul servizio assistente (vedi [assistant.md](/it/agenteye/assistant)), quindi esegui di nuovo. Una grande indagine potrebbe avere bisogno di un `AUDIT_LLM_TIMEOUT_MS` più grande (server) — mantenerlo superiore al `AGENTEYE_AUDIT_TIMEOUT_MS` dell'agente. + +### La sandbox del codice di audit è disabilitata (`sandbox_available: false`) + +**Sintomo:** `/health` dell'agente mostra `sandbox_available: false`, e le esecuzioni di audit notano che la sandbox non è disponibile; l'AI indaga solo con SQL. + +**Causa:** la sandbox bubblewrap in-pod ha bisogno di **user namespace non privilegiati**, che il profilo seccomp del pod o il kernel del nodo stanno bloccando. + +**Correzione:** imposta `seccompProfile: Unconfined` (k8s) o `security_opt: [seccomp:unconfined]` (compose) sull'agente, e conferma che il kernel del nodo consenta namespace utente non privilegiati (alcune immagini gestite, ad es. GKE COS, le disabilitano). Dove non puoi abilitarlo, questo è previsto e sicuro — l'auditor degrada a SQL-only automaticamente. Vedi [deployment.md](/it/agenteye/deployment). + +### Il rapporto di audit email non viene consegnato + +**Sintomo:** un audit ha esposto nuovi risultati ma nessun email è arrivato. + +**Causa:** l'audit non ha un canale **email** allegato, l'email è disabilitato org-wide in `alerts.enabled_channels`, non ci sono destinatari, o SMTP non è configurato. + +**Correzione:** allega un canale email all'audit, assicurati che `email` sia in `alerts.enabled_channels`, imposta i destinatari (sul canale o tramite `alerts.email_default_recipients`), e configura SMTP (lo stesso trasporto utilizzato dagli alert + email OTP). L'email viene inviata solo quando un'esecuzione produce **almeno un** risultato nuovo. + +### Un motivo mutato o dismesso mantiene la sua vecchia pagina di risultati ma mai si riclassa + +**Sintomo:** dopo aver messo a tacere un risultato, le esecuzioni successive non fanno mai riapparire quel motivo — anche se ancora si verifica. + +**Causa:** questo è il comportamento progettato: mute/dismiss sono soppressioni durevoli keyed sull'impronta del motivo. + +**Correzione:** apri il risultato e usa **reopen** per cancellare la soppressione; l'esecuzione successiva classificherà di nuovo il motivo. Usa **resolve** (non mute) per i motivi "fixed" di cui vorresti sentire parlare se regressano. + +--- + +## Ottenere aiuto + +Contatta `support@exosphere.host` con: +- La tua versione di AgentEye (dal tag di rilascio) +- Log di contenitore pertinenti (`docker logs `) +- Una descrizione del problema e di ciò che hai già provato \ No newline at end of file diff --git a/docs/ja/agenteye/alerts.mdx b/docs/ja/agenteye/alerts.mdx new file mode 100644 index 00000000..763bf1b5 --- /dev/null +++ b/docs/ja/agenteye/alerts.mdx @@ -0,0 +1,309 @@ +--- +title: "アラート" +description: "AgentEye アラートのドキュメント。" +--- + + +アラートは、スケジュールに従ってルールを評価し、何かがしきい値を超えたときに通知します。アラートによって AgentEye は、エラー率のスパイク、レイテンシの低下、評価スコアの落ち込み、または ClickHouse クエリで表現できる任意のカスタムイベントなど、重要な事象を通知するページングサーフェスへと変わります。 + +このガイドでは、アラートの概要、5 種類のトリガータイプ、4 種類の通知チャンネル、インシデントのライフサイクル、および運用上の調整項目について説明します。 + +![アラートページ:アラートルールカードのグリッド。各カードにはトリガータイプ、評価ウィンドウ、チャンネル、情報/警告/重大の重要度バッジが表示されています](/agenteye/images/alerts.png) + +--- + +## 概念 + +- **アラート** — ルールそのものです。*何を*チェックするか(トリガー)、*どのくらいの頻度で*(評価間隔)、*いつ問題とみなすか*(複合ロジック)、*緊急度*(重要度)、*誰に/どこへ*通知するか(チャンネル)を定義します。 +- **インシデント** — アラートが発火したときに発生するものです。1 つのアラートに対して、同時に開いているインシデントは最大 1 つです。繰り返し違反が発生した場合は、同じインシデントのエビデンスが更新されます。インシデントはオペレーターが解決します。ルールが違反しなくなったときの自動解決は計画中ですが、現時点では有効になっていません。 +- **チャンネル** — 通知の送信先です:メール、Slack、汎用 Webhook、またはダッシュボード内。各アラートには任意の組み合わせを設定できます。 + +アラートとインシデントは組織に属し、その組織のオペレーター間で共有されます(シングルテナントデプロイメントでは、組み込みの `default` 組織がそれに当たります)。インシデントはトリアージのために個々のオペレーターに割り当てることができます。 + +--- + +## トリガータイプ + +それぞれ独自の JSON 仕様を持つ 5 種類があります。「問題あり」をどのように表現したいかに合ったものを選んでください。ダッシュボードの**新規アラート**フォームは、選択したトリガータイプに合わせて条件エディターを切り替えながら、同じ仕様を構築します。 + +![新規アラートフォーム:基本情報(名前、説明、有効/無効)と、メトリクスしきい値、カスタム SQL、評価スコア、評価失敗、イベント単位のオプションを表示するトリガーピッカー](/agenteye/images/alert-new.png) + +### 1. `metric_threshold` + +最もシンプルなタイプです。定義済みのリストからメトリクス、演算子、しきい値、時間ウィンドウを選択します。 + +| メトリクス | カウント対象 | +|---|---| +| `event_count` | ウィンドウ内のイベント総数 | +| `error_count` | `event_type = 'error'` または `error_type IS NOT NULL` のイベント | +| `error_rate` | `error_count / event_count`(0〜1) | +| `p95_latency_ms` | `duration_ms` を持つすべてのイベントに対する `quantile(0.95)(duration_ms)` | +| `p99_latency_ms` | `quantile(0.99)(duration_ms)` | +| `token_sum` | `SUM(input_tokens + output_tokens)` | + +演算子:`>`、`>=`、`<`、`<=`、`==`(`gt`、`gte`、`lt`、`lte`、`eq` も使用可)。 + +オプションフィルター:`environment`、`event_type`。 + +仕様の例: + +```json +{ + "metric": "p95_latency_ms", + "filter": { "environment": "production" }, + "window_secs": 900, + "op": ">", + "value": 5000 +} +``` + +### 2. `custom_sql` + +プリセットのメトリクスでカバーできないあらゆる用途に使用します。オペレーターが記述した SQL は、ディスパッチャーが実行する前に、`/queries/run` と同じガード(SELECT/WITH のみ、単一ステートメント、10,000 行上限)を通過します。2 つのモードがあります。 + +- **rows モード**(`op`/`value` なし):クエリが少なくとも 1 行を返した時点でアラートが発火します。 +- **value モード**:クエリは 1 つのカラムを `metric_value` としてエイリアスする必要があり、ディスパッチャーは最初の行の `metric_value` を `op` を使って `value` と比較します。 + +```json +{ + "sql": "SELECT count() AS metric_value FROM agenteye.events WHERE event_type = 'error' AND ts >= now() - INTERVAL 1 HOUR", + "op": ">", + "value": 100 +} +``` + +### 3. `evaluation_score` + +`agenteye.evaluations` を読み取り、ウィンドウ内の指定されたスコアの平均値を比較します。 + +```json +{ + "score_key": "hallucination", + "op": ">", + "value": 0.6, + "window_secs": 3600, + "min_count": 5, + "environment": "production" +} +``` + +`min_count` は単一サンプルの外れ値からの保護です。ウィンドウ内に少なくとも N 件の評価が存在するまで、ディスパッチャーは発火しません。 + +### 4. `eval_compound` + +*複数の*評価スコアにまたがって初めて現れる品質低下を検出します。`evaluation_score` が単一の名前付きスコアを監視するのに対し、`eval_compound` は複数の評価スコア条件を 1 つのアラートに組み合わせ、選択したロジックで結果を結合します。これにより、「ヘルプフルネスが低下**または**ハルシネーションが増加した場合に発火」「ヘルプフルネス**かつ**ツール効率の両方が低下した場合のみ発火」「3 つのチェックのうち**少なくとも 2 つ**が違反した場合に発火」といったルールを 1 つで表現できます。 + +各条件は、共有ウィンドウにわたって `agenteye.evaluations` から 1 つの名前付きスコアの平均値を読み取り、独自の演算子としきい値でテストします。ブール値の結果は `combinator` によって結合されます。 + +| コンビネーター | ロジック | 発火条件 | +|---|---|---| +| `"any"` | OR | 少なくとも 1 つの条件が違反 | +| `"all"` | AND | すべての条件が違反 | +| `{ "at_least": N }` | M of N | 少なくとも N 個の条件が違反 | + +```json +{ + "combinator": { "at_least": 2 }, + "conditions": [ + { "score_key": "hallucination", "op": ">", "value": 0.8 }, + { "score_key": "helpfulness", "op": "<", "value": 0.6 }, + { "score_key": "tone", "op": "<", "value": 0.5 } + ], + "window_secs": 3600, + "min_count": 5, + "environment": "production" +} +``` + +- `combinator`:`"any"`、`"all"`、または `{ "at_least": N }`。 +- `conditions[]`:各要素は `{ score_key, op, value }` で、他のトリガーと同じ演算子(`>`、`>=`、`<`、`<=`、`==`)を使用します。 +- `window_secs`:すべての条件に適用される共通のルックバック期間(デフォルト `3600`)。 +- `min_count`:条件が違反と判定される前に必要な評価の最小件数(条件ごと)。ウィンドウ内のサンプルが少なすぎる条件は「違反なし」としてカウントされます(デフォルト `1`)。 +- `environment`:省略可能。すべての条件を 1 つの環境に限定します。 + +通知のエビデンスには、各条件の観測された平均値、テストしたしきい値、評価の件数、違反したかどうかが記録されます。これにより、どのチェックがトリガーされたかを正確に確認できます。 + +### 5. `per_event` + +「X に一致するイベントが発生した」というアラートに使用します。集計は行わず、ディスパッチャーはルックバックウィンドウ内に一致するものを見つけた時点で発火します。 + +```json +{ + "event_type": "error", + "lookback_secs": 60, + "environment": "production", + "tool_name": "bash", + "agent_id": "caa", + "error_type": "TimeoutError", + "message_contains": "vertex-ai timed out" +} +``` + +すべてのフィルターは AND で結合されます。省略したフィールドは制約なしになります。 + +| フィールド | 用途 | +|---|---| +| `agent_id` | 特定のエージェント(`/errors` 行に表示されるもの)からのエラーに限定します。 | +| `error_type` | すべてのエラーではなく、特定のエラークラス(例:`TimeoutError`)に限定します。 | +| `message_contains` | `payload.message` に対する大文字・小文字を区別しない部分文字列マッチ。同じエージェントのすべてのエラーをアラートの対象にせず、特定の障害モード(例:`prompt is too long`)だけを捕捉するのに便利です。200 文字上限で、パターンではなくリテラル文字列としてマッチします。 | + +ヒント:同じイベントへの二重通知を防ぐために、`lookback_secs` をアラートの `eval_interval_secs` とおおよそ一致させるように設定してください。 + +**`/errors` からのショートカット:** エラービューの各エラーグループの代表行(およびエラーイベントのセッションイベント詳細パネル)には **+ アラート** ボタンがあります。このボタンをクリックすると、その行の `event_type` と環境に紐づいた `per_event` トリガーが事前に入力された状態で `/alerts/new` が開きます。ペイロードに `error_type` が存在する場合は、それから生成された名前も入力されます。チャンネルの選択とルックバックの確認は引き続き必要ですが、マッチャーは自動的に入力されます。このボタンを表示するにはオペレーターに `alerts:write` 権限が必要です。 + +--- + +## 複合ロジック(M of N) + +すべてのアラートには、トリガーに加えて 2 つの整数設定があります。 + +- `eval_window`:参照する直近の評価数(デフォルト 1) +- `min_breaches`:アラートを発火させるために必要な違反数(デフォルト 1) + +`1 of 1`(デフォルト)は「最初の違反で発火」を意味します。`3 of 5` は「直近 5 回の評価のうち 3 回違反した場合に発火」を意味し、単一の悪い測定値がノイズになりやすい不安定なシグナルに便利です。ディスパッチャーはアラートごとにリングバッファを管理するため、状態を自分で管理する必要はありません。 + +--- + +## 評価間隔 + +`eval_interval_secs` は、ディスパッチャーがルールを実行する頻度を制御します。`[30, 86400]` の範囲に制限されます。ダッシュボードのプリセット:1 分 / 5 分 / 15 分 / 1 時間。基となるシグナルの変化速度に合わせた間隔を選んでください。5 分間のエラー率アラートを 15 秒ごとに評価するのは CPU の無駄遣いです。また、イベント単位のアラートはルックバックを短くしないと、評価のタイミング間でイベントが検出されずに失われる可能性があります。 + +--- + +## チャンネル + +各アラートには以下の 4 種類の任意の組み合わせを設定できます。チャンネルごとの認証情報(Slack の Webhook URL、汎用 Webhook の URL と署名シークレット、デフォルトのメール受信者)は **`/settings`** で一度設定し、各アラートからキーで参照します。これにより、1 つの Slack チャンネルを多くのアラートで共有でき、各アラートが Webhook URL のコピーを保持する必要がありません。 + +3 つの外部チャンネル種別(メール、Slack、Webhook)は、組織全体のキルスイッチ `alerts.enabled_channels` によっても制御されます。発火したアラートに設定されているチャンネル種別がこのセットに含まれていない場合、ディスパッチャーはそのチャンネルをスキップし、ステータスを `skipped_disabled`、ターゲットを `` とした `alert_notifications` 行を記録します(これにより、すべてのルールを編集することなく、例えば Slack への配信をグローバルに一時停止できます)。ダッシュボード内チャンネルは常に許可されています。詳細は[設定](#configuration)を参照してください。 + +### メール + +OTP ログインメールを送信するのと同じ SMTP トランスポートを再利用します。受信者は以下の順序で解決されます。 + +1. チャンネルごとの `recipients[]` オーバーライド(空でない場合)。 +2. `alerts.email_default_recipients` 設定(メールアドレスの配列)。 + +SMTP が設定されていない場合、このチャンネルは何もしません。ただし、ディスパッチャーは引き続き `alert_notifications` 行をターゲット `` で記録するため、監査証跡で設定ミスを確認できます。 + +### Slack + +[受信 Webhook URL](https://api.slack.com/messaging/webhooks) に Block Kit メッセージを送信します。 + +- デフォルト URL:`alerts.slack_default_webhook`(`/settings` で設定)。 +- アラートごとのオーバーライド:チャンネルの `webhook_setting_key` を他の URL 型設定キー(例:`alerts.slack_oncall`、`alerts.slack_costs`)に設定します。 + +ヘッダーには重要度の絵文字(`:rotating_light:` / `:warning:` / `:bell:`)が含まれ、メッセージにはインシデントページへのディープリンクボタンが付いています。 + +### 汎用 Webhook + +PagerDuty、Opsgenie、または独自の取り込みエンドポイントへの JSON POST インテグレーションです。ボディの形式: + +```json +{ + "schema_version": 1, + "event": "alert.firing", + "incident": { "id": "uuid", "url": "https://…/incidents/uuid", "opened_at": "2026-…" }, + "alert": { "id": "uuid", "name": "errors > 50/hr", "severity": "critical" }, + "breach": { "value": 73.0, "summary": "ErrorCount > 50 (observed 73.000)", "evidence": { … } } +} +``` + +`alerts.webhook_signing_secret` が設定されている場合、リクエストにはシークレットを使ったボディの HMAC-SHA256 である `X-AgentEye-Signature: sha256=` ヘッダーが含まれます。ペイロードを信頼する前に、受信側で検証してください。 + +`X-AgentEye-Event` ヘッダーには `alert.firing` / `alert.test` が入ります(`alert.resolved` は計画中の自動解決機能用に予約されており、現時点では送信されません)。 + +### ダッシュボード内 + +外部への配信はなく、アラートはダッシュボードのインシデントページに表示される `alert_notifications` 行を書き込むだけです。ルールを調整中で外部システムへの通知を送りたくない場合や、通常のトリアージ中にオペレーターが確認する緊急度の低いアラートに便利です。 + +--- + +## インシデントのライフサイクル + +``` +firing ──ack──▶ acknowledged + │ │ + └────────────────────┴───── operator resolve ───▶ resolved +``` + +- **firing** — ディスパッチャーがインシデントを新規作成したか、別の違反を検出しました。発火通知は(インシデントの `notified_firing_at` タイムスタンプによるゲート制御で)正確に 1 回だけファンアウトされます。 +- **acknowledged** — オペレーターが `/incidents/:id` で *ack* を押しました。インシデントはまだオープンとみなされます。その後の違反はエビデンスを更新しますが、再通知はされません。 +- **resolved** — オペレーターが *resolve* を押しました。ルールの違反が止まったときの自動解決は計画中ですが、現時点では有効になっていないため、オープンなインシデントはオペレーターが解決するまでオープンのままです。 + +以前のインシデントが解決された後、同じアラートで新しいインシデントがいつでも再オープンできます。 + +**アクティビティタイムライン。** インシデントのすべてのアクション(オープン、承認、解決)は追記専用のアクティビティログに記録され、インシデントの*アクティビティ*タイムラインに表示されます。各エントリは、アクションを実行したオペレーター(メールアドレス)または、ディスパッチャーが自律的に実行したアクション(違反時の自動オープン)については**automated** に帰属します。承認は共有されます。複数のオペレーターが同じインシデントを承認でき、それぞれが個別の帰属エントリとして表示されます。 + +**インシデント**受信箱では、オープンなインシデントを状態ごとにグループ化し、重要度や担当者でフィルタリングできます。 + +![重要度バッジと担当者が表示された、アラートに紐づくインシデントとアドホックインシデントカードを示すインシデント受信箱](/agenteye/images/incidents.png) + +インシデントを開くと、違反のエビデンス、担当者とサブスクライバー、帰属アクティビティタイムライン、コメントスレッドが表示されます。 + +![インシデント詳細ビュー:親アラート、違反サマリー、担当者、サブスクライバー、帰属アクティビティログ、会話](/agenteye/images/incident-detail.png) + +--- + +## 必要な権限 + +アラート*ルール*の作成と*インシデント*のトリアージは別々の関心事であり、それぞれ個別の権限が必要です。これにより、オンコールローテーションにルールの書き換え権限を与えることなく、インシデントへのアクセス権を付与できます。 + +- `alerts:read`:アラートルールの表示。 +- `alerts:write`:アラートルールの作成、編集、削除、テスト通知のトリガー。 +- `incidents:read`:インシデントの表示。 +- `incidents:write`:アラートに紐づかない手動(アドホック)インシデントのオープン。 +- `incidents:ack`:インシデントの承認、割り当て、コメント、解決。 + +> **レガシー `alerts:ack`。** 旧 `alerts:ack` トークンが付与されたキーとオペレーターは引き続き機能します。`incidents:ack` として受け入れられ(`incidents:read` も含む)、既存のオンコール担当者は資格情報を再発行することなくアクセスを維持できます。新しい権限付与には `incidents:*` ファミリーを使用してください。 + +API キー(`POST /keys`)とオペレーター(`PUT /users/:id`)に付与します。ダッシュボードの `PermGate` は権限がない場合に関連ボタンをロックし、アクションの横に `// 403` が表示されます。 + +> **メール受信者ピッカー。** アラートエディターの受信者ピッカーは、組織のメンバーを一覧表示し、名前で選択できます。`alerts:read` または `alerts:write` を持つオペレーターであれば読み込まれます。この用途でチームのディレクトリを表示するために `users:read` は**不要**で、ピッカーはメンバーのメールアドレスのみを返し、完全なユーザーレコードは返しません。 + +--- + +## 設定 + +ディスパッチャーが使用する環境変数: + +| 変数 | デフォルト | 用途 | +|---|---|---| +| `ALERT_WORKERS` | `1` | サーバーインスタンスごとのワーカータスク数。ほとんどのデプロイメントでは 1 で十分です。 | +| `ALERT_CLAIM_BATCH` | `16` | 1 回のワーカーティックで処理するアラートの最大数。 | +| `ALERT_POLL_IDLE_SECS` | `5` | キューが空のときのワーカーのスリープ時間。 | +| `ALERT_REQUEST_TIMEOUT_MS` | `15000` | トリガーごとの評価タイムアウト。 | +| `DASHBOARD_URL` | `https://app.befailproof.ai` | 通知内のインシデントマジックリンクの生成に使用されるオリジン。ダッシュボードのホストに設定してください。 | + +一時的な評価の失敗(ClickHouse が到達不可能、クエリのタイムアウト)が発生した後、ディスパッチャーは指数バックオフでルールを再試行します。ルールが一時的な失敗を **5** 回連続で蓄積すると、バックオフを継続する代わりに通常のサイクルで再スケジュールされるため、永続的に失敗しているルールでも引き続き再評価されます。この上限は固定であり、オペレーターが調整することはできません。 + +チャンネル設定(環境変数ではなく `/settings` から管理): + +- `alerts.email_default_recipients`(`email_list`):メールアドレスの JSON 配列。メールチャンネルのデフォルト受信者。 +- `alerts.slack_default_webhook`(`url`):デフォルトの Slack 受信 Webhook URL。 +- `alerts.webhook_default_url`(`url`):デフォルトの汎用 Webhook URL。 +- `alerts.webhook_signing_secret`(`secret`):HMAC-SHA256 キー。GET レスポンスでは常に `""` として返されます。ローテーションするには新しい値を入力してください。 +- `alerts.enabled_channels`(`channel_set`):アラート発火時にディスパッチされる外部チャンネル種別の組織全体のセット。デフォルトはすべての 3 種別(`email`、`slack`、`webhook`)。ここから種別を削除すると、各ルールを編集することなく、そのチャンネルをすべてのアラートでグローバルに抑制します。ダッシュボード内チャンネルは常に配信され、この設定の影響を受けません。 + +--- + +## 新しいアラートの検証 + +新しいアラートを本番利用する前に: + +1. 少なくとも 1 つの通知チャンネルを設定して有効な状態で保存します。 +2. アラート詳細ページで**テスト**を選択し、設定した各送信先がテスト通知を受信することを確認します。 +3. 最初の実際の違反が発生したら、**インシデント**ページにインシデントが表示されること、および測定値が対応するダッシュボードクエリと一致することを確認します。 + +条件がクリアされてもインシデントは自動解決されません。オペレーターがインシデント詳細ページから解決する必要があります。 + +--- + +## トラブルシューティング + +| 症状 | 考えられる原因 | +|---|---| +| アラートが発火しない | `enabled = false`、チャンネルが設定されていない、または基となる CH クエリが 0 行を返している。*テスト*でチャンネルを確認し、`/queries/run` でメトリクスを確認してください。 | +| Slack 通知が届かない | `alerts.slack_default_webhook`(またはアラートごとのオーバーライドキー)が未設定:`alert_notifications.target` で `` 行を確認してください。または `slack` 種別が `alerts.enabled_channels` でグローバルに無効化されている:ステータスが `skipped_disabled`、ターゲットが `` の `alert_notifications` 行を確認してください。 | +| 汎用 Webhook で 401 が返る | 受信側が署名を要求しているが `alerts.webhook_signing_secret` が未設定です。受信側で HMAC が `hmac_sha256(secret, body)` と一致することを確認してください。 | +| メールで「from all sends failed」 | SMTP 認証情報が誤っているか、`from` アドレスがリレーで拒否されています。OTP メールを送信するのと同じ基盤であるため、それが機能していれば SMTP トランスポートは正常です。 | +| インシデントが繰り返し再オープンされる | 複合設定が積極的すぎます。一時的なスパイクによって解決済みのインシデントが再オープンされないよう、`min_breaches` または `eval_window` を大きくしてみてください。 | \ No newline at end of file diff --git a/docs/ja/agenteye/api-keys.mdx b/docs/ja/agenteye/api-keys.mdx new file mode 100644 index 00000000..789a5d89 --- /dev/null +++ b/docs/ja/agenteye/api-keys.mdx @@ -0,0 +1,255 @@ +--- +title: "APIキー" +description: "AgentEye APIキーのドキュメント。" +--- + + +AgentEyeはサーバーへのアクセスを制御するために細粒度のAPIキーを使用します。各キーは実行可能な操作を決定する1つ以上のパーミッションを保有します。 + +--- + +## パーミッション + +サーバーは固定のパーミッションカタログを適用し、それぞれが特定のHTTPルートを制御します。**adminキー**はすべてのパーミッションを保有し、スコープ付きキーは作成時に付与したサブセットのみを保有します。未知のパーミッション文字列はキー作成時に拒否されます。 + +> **キーへの割り当て不可。** 有効なパーミッションのうち2つは人間/ダッシュボード専用であり、APIキーには付与できません: `orgs:admin`(オペレーター専用のインスタンス管理)と `keys:update` です。これらのいずれかを付与しようとする `POST /keys` または `PATCH /keys/:id` へのリクエストはHTTP 422で拒否されます。ベアラーキーがキーを作成できても編集はできない理由については、以下の `keys:update` の行をご覧ください。 + +### イベントの取り込みとクエリ + +| パーミッション | HTTPルート | 許可される操作 | +|---|---|---| +| `events:add` | `POST /events` | コレクターからのイベントバッチを取り込む。コレクターに必要な唯一のパーミッション。 | +| `events:read` | `GET /events`, `GET /events/latency_aggregate`, `GET /events/environments`, `GET /events/models`, `GET /sessions/:session_id/export` | イベントのクエリ、既知の環境の一覧表示、データ内で確認されたモデル識別子の一覧表示(モデルビューとモデルフィルターで使用)、ヒートマップ/パーセンタイルバンドを支えるレイテンシ集計の計算、セッションのJSONLとしてのエクスポート。共有フィルターバーファセットエンドポイント `GET /events/environments` と `GET /events/models` は **`events:read`** または **`evaluations:read`** のいずれかで到達可能なため、セッションページ(`evaluations:read` で制限)は同じ組織単位のファセットを再利用できます。 | + +### セッションと評価 + +| パーミッション | HTTPルート | 許可される操作 | +|---|---|---| +| `evaluations:read` | `GET /sessions`, `GET /evaluations`, `GET /evaluations/aggregate`, `GET /evaluations/environments`, `GET /evaluation-jobs` | セッションの一覧表示、評価結果の読み取り、ダッシュボードで使用される集計済み評価ヘルス、評価ジョブワーカーキューの状態。 | +| `evaluations:trigger` | `POST /sessions/:session_id/re-evaluate` | 完了したセッションの再評価を手動でキューに追加する。 | + +### ダッシュボード + +| パーミッション | HTTPルート | 許可される操作 | +|---|---|---| +| `dashboards:read` | `GET /dashboards`, `GET /dashboards/:id`, `GET /dashboards/:id/tiles` | ダッシュボードの一覧表示、単一のダッシュボードの読み込み、タイルの読み取り。 | +| `dashboards:write` | `POST /dashboards`, `PUT /dashboards/:id`, `POST /dashboards/:id/tiles`, `PUT /dashboards/:id/tiles/:tile_id`, `DELETE /dashboards/:id/tiles/:tile_id`, `PUT /dashboards/:id/tiles/layout` | ダッシュボードの作成と編集、タイルの追加/編集/削除、タイルグリッドの並び替え。 | +| `dashboards:delete` | `DELETE /dashboards/:id` | ダッシュボード全体の削除(タイルレベルの削除は `dashboards:write` に属する)。 | + +### 保存済みクエリ(SQLコンポーザー) + +| パーミッション | HTTPルート | 許可される操作 | +|---|---|---| +| `queries:read` | `GET /queries`, `GET /queries/:id`, `GET /queries/schema` | 保存済みクエリの一覧表示、単一クエリの読み込み、コンポーザーが対象とする読み取り専用ClickHouseスキーマの参照。 | +| `queries:write` | `POST /queries`, `PUT /queries/:id` | 保存済みクエリの作成と編集。SQLは `queries:run` の呼び出しと同様に読み取り専用ロールと `sql_guard` チェックを経由します。 | +| `queries:delete` | `DELETE /queries/:id` | 保存済みクエリの削除。 | +| `queries:run` | `POST /queries/run` | コンポーザーが使用する読み取り専用ロールに対して保存済みまたはアドホックSQLを実行する。 | + +### AIアシスタント + +| パーミッション | HTTPルート | 許可される操作 | +|---|---|---| +| `agent:use` | `GET /agent/conversations`, `POST /agent/conversations`, `GET /agent/conversations/:id`, `PATCH /agent/conversations/:id`, `DELETE /agent/conversations/:id`, `PUT /agent/conversations/:id/messages` | ダッシュボードAIアシスタントとの対話および自身の(プライベートな)会話の管理。アシスタントドックを表示するには **ユーザー** に必要。アシスタント自体のキーは `dashboard-assistant` であり、別途シードされます(下記参照)。 | + +### APIキー + +| パーミッション | HTTPルート | 許可される操作 | +|---|---|---| +| `keys:create` | `POST /keys` | 新しいスコープ付きAPIキーを作成する。既存キーのパーミッションの編集は**許可されない**(それは `keys:update`)。 | +| `keys:read` | `GET /keys` | 既存のキーを一覧表示する。シークレットはこのエンドポイントでは返されない。 | +| `keys:update` | `PATCH /keys/:id` | 既存キーのパーミッションを編集する。**人間/ダッシュボード専用**のパーミッションであり、APIキーには割り当て不可(ベアラーキーはキーを作成できるが編集はできない)。 | +| `keys:disable` | `POST /keys/:id/disable` | キーを失効させる。保護されたキー(`admin`, `dashboard-assistant`)は無効化できない。それらはenv var + 再起動でローテーションする。 | +| `keys:regenerate` | `POST /keys/:id/regenerate` | キーのシークレットをローテーションする。保護されたキーはこのルートから再生成できない。 | + +### ダッシュボードユーザー + +| パーミッション | HTTPルート | 許可される操作 | +|---|---|---| +| `users:create` | `POST /users`, `GET /users/defaults` | 新しいダッシュボードユーザーを招待する(メール + OTPログインを発行)、および招待フォームのシードに使用されるダッシュボード設定済みデフォルトパーミッションセットを読み取る。 | +| `users:read` | `GET /users`, `GET /users/:id` | ユーザーの一覧表示および単一ユーザーレコードの読み込み。 | +| `users:update` | `PUT /users/:id` | ユーザーのパーミッションを編集する。更新は影響を受けるユーザーにパーミッション変更メールを送信し、次のリクエスト時に有効になる(再ログイン不要)。 | +| `users:delete` | `DELETE /users/:id`, `POST /users/:id/enable` | ユーザーを無効化する(セッションを即時失効)および以前に無効化されたユーザーを再有効化する。 | + +これらのパーミッションはダッシュボードの **Users** ページを支えており、各メンバーに付与されたスコープがチップとして表示されます: + +![Users ページ: ダッシュボードユーザーごとのカードにメール、付与されたパーミッション、編集/無効化コントロールが表示される](/agenteye/images/users.png) + +### 運用設定 + +| パーミッション | HTTPルート | 許可される操作 | +|---|---|---| +| `settings:read` | `GET /settings`, `GET /settings/schema`, `GET /settings/model-context-windows`, `GET /settings/model-context-windows/resolve` | ダッシュボード管理の運用設定とそのメタデータを表示、モデル単位のコンテキストウィンドウオーバーライドを一覧表示、モデルの有効なウィンドウを解決する。 | +| `settings:write` | `PUT /settings/:key`, `PUT /settings/model-context-windows`, `DELETE /settings/model-context-windows` | 運用設定を編集し、モデル単位のコンテキストウィンドウオーバーライドを追加、変更、削除する。変更はサーバーを再起動せずに新しいイベントに反映される。 | + +![Settings ページ: 許可されたサインインやセッション/OTP有効期限などのダッシュボード管理の運用設定を再起動なしで編集可能](/agenteye/images/settings.png) + +### アラートとインシデント + +| パーミッション | HTTPルート | 許可される操作 | +|---|---|---| +| `alerts:read` | `GET /alerts`, `GET /alerts/:id` | 設定されたアラート定義を表示する。 | +| `alerts:write` | `POST /alerts`, `PUT /alerts/:id`, `DELETE /alerts/:id`, `POST /alerts/:id/test` | アラート定義の作成、編集、削除、テスト発火。 | +| `incidents:read` | `GET /alerts/incidents`, `GET /alerts/incidents/:iid`, `GET /alerts/incidents/:iid/comments`, `GET /alerts/incidents/:iid/subscribers` | インシデントとトリアージ履歴を表示する。 | +| `incidents:write` | `POST /alerts/:id/incidents` | 既存のアラートに対してインシデントを手動でオープンする。 | +| `incidents:ack` | `POST /alerts/incidents/:iid/ack`, `POST /alerts/incidents/:iid/assign`, `POST /alerts/incidents/:iid/resolve`, `POST /alerts/incidents/:iid/comments`, `POST /alerts/incidents/:iid/subscribe`, `POST /alerts/incidents/:iid/unsubscribe` | インシデントの承認、割り当て、解決、コメント追加。 | + +### 監査 + +| パーミッション | HTTPルート | 許可される操作 | +|---|---|---| +| `audits:read` | `GET /audits`, `GET /audits/:id`, `GET /audits/:id/runs`, `GET /audits/findings`, `GET /audits/findings/:fid` | 監査定義、実行履歴、発見事項を表示する。 | +| `audits:write` | `POST /audits`, `PUT /audits/:id`, `DELETE /audits/:id`, `POST /audits/:id/run`, `POST /audits/findings/:fid/status` | 監査の作成、編集、削除、実行; 発見事項のトリアージ(承認/ミュート/却下/解決/再オープン/割り当て)。 | + +> Auditsがリリースされた際、既存の付与者はアラートと同じロール形状に沿って拡張されました: `alerts:read` を保有するすべてのユーザーとパーミッションセットが `audits:read` を取得し、`alerts:write` を保有するすべてのユーザーが `audits:write` を取得しました。既存のAPIキーは**拡張されませんでした** — 監査サーフェスが必要な場合は、キーに `audits:*` を明示的に付与してください。 + +> レガシーの `alerts:ack` トークンの保存済み付与は `incidents:ack` として解析されるため、オンコール担当者は再キーなしでアクセスを維持できます。このトークンはダッシュボードのユーザーエディターから割り当てることができなくなりました。マトリックスでは代わりに `incidents:ack` を提供しています。 + +> 受信者ピッカーエンドポイント `GET /alerts/recipients`(アラートエディターが通知できるメンバーメールを一覧表示)は **`alerts:read`** または **`alerts:write`** のいずれかを保有するユーザーが到達可能なため、アラートエディターは `users:read` を付与されなくてもピッカーを利用できます。 + +> ダッシュボードの閲覧者には **`dashboards:read`**(保存済みビューの読み込み)と **`evaluations:read`**(ヘルスメトリクスは評価データから計算される)の両方が必要です。ダッシュボードの作成や編集には `dashboards:write` を、削除には `dashboards:delete` を付与してください。 + +> `/health` と `/auth/*`(OTPリクエスト、OTP検証、セッションチェック、ログアウト)は設計上認証不要です。これらはログインフローとライブネスプローブです。`GET /access-granters` は有効なキーは必要ですが特定のパーミッションは不要なため、ログイン済みユーザーはアクセス変更について連絡すべき管理者を確認できます。 + +--- + +## パーミッションセット + +パーミッションセットを使用すると、毎回個別のトークンを手動で選択する代わりに、名前付きロールを適用できます。新しいダッシュボードユーザーやAPIキーごとに十数個のパーミッションを一つずつ選択するのではなく、セットを選択するだけで、割り当てられた全員が一貫したレビュー可能な付与を受け取れます。カスタムセットを編集すると、すでに割り当てられているすべてのユーザーに新しい付与が再適用されるため、ロールの変更は全メンバーを見直すのではなく一度の編集で済みます。 + +すべての組織には3つの組み込みセットがシードされています: + +| セット | パーミッション | 対象 | +|---|---|---| +| `read-only` | `events:read`, `keys:read`, `users:read`, `evaluations:read`, `dashboards:read`, `queries:read`, `settings:read`, `alerts:read`, `audits:read`, `incidents:read` | すべての運用サーフェスへの閲覧専用アクセス。 | +| `standard` | `read-only` のすべて + `evaluations:trigger`, `queries:run`, `incidents:ack`, `agent:use` | 読み取り専用に加え、日常的なオンコール操作: クエリ実行、セッション再評価、インシデント承認、AIアシスタント使用。 | +| `admin` | すべての割り当て可能なパーミッション | 組織の完全な制御。 | + +3つの組み込みセットは**変更不可**です。その名前は常に同じ意味を持つため、`read-only`、`standard`、`admin` はポリシーやオンボーディングでの参照に安全です。オペレーターは組織固有のロールをモデル化するために追加の**カスタムセット**を作成できます(例: 「ダッシュボード作成者」ロールや「コレクター専用」ロール)。 + +セットはダッシュボードに表示され、APIでは `GET /permission-sets`(一覧表示、`users:read` で制限)および `POST /permission-sets` / `PUT /permission-sets/:name` / `DELETE /permission-sets/:name`(カスタムセットの作成、編集、削除、`settings:write` で制限)で管理されます。組み込みセットの削除や編集は拒否されます。 + +セットメンバーシップは他の2つの機能を支えています: + +- **`DEFAULT_USER_PERMISSIONS`**(管理者が **+ new user** を開いたときに事前選択される付与)はデフォルトで `standard` セットになります。[デプロイメント](/ja/agenteye/deployment) を参照してください。 +- **`agenteye-orgctl` の `--set` フラグ**(オペレーターのメンバー管理)は名前付きセットからメンバーを開始し、`--add` / `--remove` で調整します。[テナント管理](/ja/agenteye/tenant-management) を参照してください。 + +> セットにキーに割り当て不可なパーミッションが含まれている場合(例: `keys:update` を持つカスタムセット)、そのセットからキーをシードすると割り当て不可のトークンは除外されます。そうでなければサーバーはHTTP 422でキーを拒否します。ダッシュボードユーザーにはこの制限は適用されません。 + +--- + +## ブートストラップAdminキー + +adminキーはオペレーターがゼロからアクセスを構築できる単一のルート資格情報です。これを使用して他のすべてのスコープ付きキーを作成し、最初のダッシュボードユーザーを招待し、他のキーが存在しない状態でインスタンスを設定できます。これはキーAPIを通じて作成しない唯一のキーであり、サーバーが最初の起動時に到達可能になるよう環境からプロビジョニングされます。 + +サーバーに `ADMIN_KEY` 環境変数を設定してください。起動するたびにサーバーはこの値をすべてのパーミッションを持つadminキーとしてアップサートします。 + +ローテーションするには: `ADMIN_KEY` を新しいシークレットに変更してサーバーを再起動してください。 + +--- + +## 組織スコープ + +**組織自体はオペレーターがアウトオブバンドで作成・管理するものであり、このキーAPIを通じては行いません。** 組織とメンバーのライフサイクル(組織の作成/名前変更/削除/パージ、メンバーの追加/更新/削除)は、サーバーポッド内で実行される **`agenteye-orgctl`** CLIを使用して行います。このためのHTTP APIやダッシュボードボタンはありません。[テナント管理](/ja/agenteye/tenant-management) を参照してください。**変わらないこと**: **組織ごとのAPIキーは引き続きダッシュボード(またはこのキーAPI経由)で組織メンバーによって作成されます。** + +マルチ組織デプロイメントでは、組織メンバーが(このキーAPIまたはダッシュボードの **Keys** ページを通じて)作成したすべてのキーは**1つの組織**に属し、その組織のデータのみを読み書きできます。組織はキー作成時に刻印され、すべてのリクエストで適用されます。2つのブートストラップキーだけは例外です: `admin` キー(`ADMIN_KEY` からシード)と `dashboard-assistant` キー(`AGENT_API_KEY` からシード)は**インスタンススコープ**です(組織を持たない)。ダッシュボードコンテナは `admin` キーで認証し、サインイン済みメンバーに代わって組織ごとのリクエストをプロキシします。シングルテナントデプロイメントではこれを気にする必要はなく、すべてのキーは組み込みの `default` 組織に属します。 + +--- + +## キーの作成 + +adminキー(または `keys:create` パーミッションを持つキー)を使用して、追加のスコープ付きキーを作成します。 + +### コレクターキー(取り込みのみ) + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "prod-collector", + "key": "your-collector-secret", + "permissions": ["events:add"] + }' +``` + +### ダッシュボードキー(読み取り専用) + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "dashboard", + "key": "your-dashboard-secret", + "permissions": ["events:read", "keys:read"] + }' +``` + +HTTP APIでキーを作成する場合、`key` の値は自分で指定します。強力なシークレットを選択し、安全に保存してください。(ダッシュボードはその逆で、強力なシークレットを生成して作成時に一度だけ表示します。[ダッシュボードでのキー管理](#key-management-in-the-dashboard) を参照してください。)レスポンスでキーが作成されたことが確認されます: + +```json +{ + "id": "550e8400-e29b-41d4-a716-446655440000", + "name": "prod-collector", + "permissions": ["events:add"], + "created_at": "2026-04-01T12:00:00Z" +} +``` + +--- + +## キーの一覧表示 + +```bash +curl -s http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +キーのシークレットは一覧レスポンスでは返されません。ID、名前、パーミッションのみが返されます。 + +--- + +## キーの無効化 + +無効化するとキーレコードを削除せずにアクセスを即時失効させます。 + +```bash +curl -s -X POST http://your-server:8080/keys//disable \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +--- + +## キーの再生成 + +既存のキーに新しいシークレットを生成します。古いシークレットは即座に無効化されます。 + +```bash +curl -s -X POST http://your-server:8080/keys//regenerate \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +レスポンスには新しい平文のシークレットが含まれます(**一度だけ表示されます**)。 + +--- + +## ダッシュボードでのキー管理 + +ダッシュボードの **Keys** ページは上記のすべての操作を行うUIを提供します。一覧を表示するには `keys:read` パーミッションを持つキーが必要で、作成/編集/無効化/再生成の操作にはそれぞれ `keys:create` / `keys:update` / `keys:disable` / `keys:regenerate` が必要です。キーのパーミッション編集(`keys:update`)とキーの作成(`keys:create`)は別個のものなので、既存キーの再スコープ能力なしにキーを作成する権限をオペレーターに付与したり、その逆も可能です。adminキーはこれらすべてをカバーします。 + +ダッシュボードからキーを作成する場合、シークレットを指定する必要はありません。ダッシュボードが強力なシークレットを生成し、作成時に**一度だけ**表示します。すぐにコピーして安全に保存してください。再生成と同様に、二度と表示されません。キーのパーミッションは直接選択することも、パーミッションセットからシードすることもできます(下記参照)。 + +![API Keys ページ: キーごとのカードに名前、付与されたパーミッション、作成日時が表示され、再生成と無効化のアクションがある。`admin` などの保護されたキーはマーク付き](/agenteye/images/api-keys.png) + +--- + +## 推奨キーレイアウト + +| キー | パーミッション | 使用者 | +|---|---|---| +| `admin`(`ADMIN_KEY` env var経由でブートストラップ) | すべて | 運用/セットアップ、およびダッシュボードコンテナ(`ADMIN_KEY` で認証し、パーミッションチェックとともにユーザーリクエストをプロキシ) | +| ホストごとのコレクターキー | `events:add` | 各エージェントマシン上のコレクター | +| `dashboard-assistant`(`AGENT_API_KEY` env var経由でブートストラップ) | `events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run` | AIアシスタントコンテナ、自動的にシード、**保護済み**; APIを通じて編集不可 | +| アシスタントテレメトリーキー(任意) | `events:add` | AIアシスタントの自己インスツルメンテーション(有効化した場合) | + +> **アシスタントキー。** アシスタントのキーは、`AGENT_API_KEY` env var(エージェントが `AGENTEYE_API_KEY` として提示するのと同じシークレット)からサーバーによって**自動的にシード**されます。手動のキー作成手順はなく、adminキーも関与しません。そのパーミッションはソースコードに固定されているため、設定ミスによってスコープが拡大されることはありません: イベント/評価/ダッシュボードへの読み取り、「AIにクエリを書かせる」オーサリングフロー用のダッシュボード書き込みおよびクエリ読み取り/書き込み/実行。すべてのSQLはユーザーが書いたクエリと同じ読み取り専用ロールと `sql_guard` チェックを通過するため、これは*データサーフェス*ではなく*オーサリングサーフェス*を拡大するものです。破壊的な操作(`queries:delete`, `dashboards:delete`)は意図的にアシスタントキーから除外されています。`admin` キーと同様に**保護済み**です: キーAPIを通じて無効化や再生成はできず、`AGENT_API_KEY` を変更して再起動することでのみローテーション可能です。ダッシュボードの*ユーザー*がアシスタントを表示・使用するには、追加で `agent:use` パーミッションが必要です。自己インスツルメンテーションを有効化する場合は、アシスタントに `events:add` 専用の別キーを付与してください。 \ No newline at end of file diff --git a/docs/ja/agenteye/assistant.mdx b/docs/ja/agenteye/assistant.mdx new file mode 100644 index 00000000..c767ea69 --- /dev/null +++ b/docs/ja/agenteye/assistant.mdx @@ -0,0 +1,195 @@ +--- +title: "AIアシスタント" +description: "AgentEye AIアシスタントのドキュメント。" +--- + +ダッシュボードにはオプションの**AIアシスタント**が含まれています。これはダッシュボードの右端にドッキングされたチャットパネルで、エージェントに関する自然言語の質問(「今週のプロダクション環境での品質トレンドはどうですか?」「今日エラーになったセッションはどれですか?」「このセッションを要約して」など)に回答し、ユーザーがアクションを許可した場合にはSQLクエリやダッシュボードを下書きして保存します。関連するセッション、クエリ、ダッシュボードへのクリッカブルリンクを引用として提示し、**ページ認識機能**を持っています。特定のセッションを表示中に「このセッションについて」と聞けば、何を指しているか正確に把握します。 + +ドックはデフォルトで幅**44pxの縦型レール**として表示されます:`›_` プロンプトグリフとカラーの健全性ドットが表示されます。レールをクリック(または `⌘J` / `Ctrl+J` を押す)するとフルチャットパネルに展開します。展開されたパネルは左端をドラッグすることで320〜640ピクセルの間で**リサイズ可能**で、お好みの幅はリロードをまたいで記憶されます。 + +これはダッシュボードからのみアクセス可能な小さな内部**`agent`**コンテナ(Claude Agents SDK上)として動作します。**デフォルトでは無効**になっており、LLMエンドポイントを設定するまで非表示のままです。 + +--- + +## できること・できないこと + +- **質問しているユーザーが閲覧できる運用データを読み取ります。** イベント、評価、セッション、評価ジョブキュー、保存済みクエリ、保存済みダッシュボードをユーザーの読み取り権限に基づいてリクエストごとにスコープします。読み取りツールは即座に実行されます。 +- **書き込みはアクション単位の承認によって制御されます。** 保存済みクエリの作成(`create_saved_query`、`update_saved_query`)、読み取り専用ロールに対する下書きSQLの検証実行(`run_query`)、それらのクエリからのダッシュボード組み立て(`create_dashboard`、`update_dashboard`、`add_query_to_dashboard`)が可能です。各書き込み操作ではチャット内に**承認 / 拒否 / 質問**のプロンプトが表示されて一時停止します。オペレーターが「承認」をクリックするまでSDKはツールを呼び出しません。**削除操作はアシスタントには一切提供されません**。破壊的な操作はオペレーターのみが実行できます。 +- **下書きされたSQLは、ユーザーが記述したSQLと同じ `sql_guard` 検証および読み取り専用ロールを通過します**(SELECT/WITHのみ、複数ステートメント不可)。実行はクエリが参照するテーブルによってルーティングされます。分析テーブル(イベント、評価、セッション)を参照するクエリは組織の読み取り専用ClickHouseユーザーとして実行され(行ポリシーによってその組織にスコープされ、実行上限10秒、行数上限10万行)、リレーショナルテーブルのみを参照するクエリは読み取り専用Postgresロールで実行されます(10秒、1万行)。アシスタントはデータのアクセス範囲を拡大できません。オペレーターがすでに持っているクエリ範囲に対してのみ操作できます。 +- **専用のアシスタントキー**(下記参照)を使用し、固定された権限セットで初期化されます。モデルが誤動作しても、そのスコープを超えることはできません。 +- 各ダッシュボードユーザーがアシスタントを表示・使用するには **`agent:use`** 権限が必要です。ツールはリクエストごとにユーザー自身のデータ権限に合わせてフィルタリングされるため、`events:read` ユーザーはイベントツールを取得できますが、`dashboards:write` ツールは取得できません。 + +--- + +## ページ認識AIドック:`/queries` ではコンポーザー、それ以外ではチャット + +右側のアシスタントドックは**ページ認識**機能を持っています。モデルピッカー、会話履歴、モデル健全性ドット、チャット入力は変わりませんが、**空の状態のテンプレートチップ、プレースホルダーテキスト、ユーザーのメッセージが送信されるバックエンドエンドポイント**はすべて現在のルートに基づいて自動的に切り替わります。ドックは「現在いるページのAIヘルパー」になります。 + +**2つのバックエンド、ページごとに選択(チップ単位のオーバーライドあり)。** + +| ルート | ページデフォルトバックエンド | 理由 | +| ------------------------------ | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | +| `/queries`、`/queries/new` | `POST /api/agent/compose-sql`(ツールループなし) | ユーザーがゼロから始める場合、1秒以内の初回トークンSQLがエディタに直接ストリーミングされる | +| `/queries/`(既存) | `POST /api/agent/chat`(フルツールループアシスタント)、ページデフォルト | 自由入力メッセージでは何でも質問できる(「これを説明して」「これは何をしている?」など)。リファクタリングチップはチップ単位のkindによってcompose-sqlに切り替わる | +| それ以外のすべてのページ | `POST /api/agent/chat`(フルツールループアシスタント) | 読み取りツール + 承認制の書き込みツール | + +`/queries/` のチップには明示的な `kind` が設定されており、1つのページで2つのフローをシームレスに混在させることができます。デフォルトのチップセットは2つの**chat**チップ(`explain the query on screen`、`what does this query do?`)と5つの**compose-sql**チップ(`parameterize by date range`、`add a status='error' filter`など)です。自由入力メッセージはページデフォルト(chat)にフォールスルーするため、「なぜこんなに遅いのか?」という質問は散文形式の回答を得られ、`parameterize by date range` チップをクリックするとcomposeエンドポイント経由でSQLが編集されます。 + +コンポーザーが**編集モード**で動作する場合(ユーザーが `/queries/` または既にSQLが読み込まれた `/queries/new` にいるため、空でない `currentSql` を参照している場合)、システムプロンプトは「新しいクエリを作成する」から「提供されたSQLを最小限に変更する:テーブル選択、カラム名、join構造、エイリアス、インデントを保持する」に切り替わります。モデルには変更前後の作業例(パラメータ化、フィルター追加、時間単位バケットへの変換)が別途提示されるため、チップクリックによるリファクタリングはゼロからの書き直しではなく、エディタのSQLに対する最小限の差分を生成します。 + +composeチップをクリック(または `/queries/new` で自由入力)すると → SQLがアシスタントメッセージにフェンスされた ` ```sql ` ブロックとしてストリーミングされます。**ストリームが完了した瞬間、Monacoが現在のルートにマウントされていれば、エディタは自動的に差分ビューで表示されます**(左側に元のSQL、右側に提案されたSQL、上部に `▾ AI proposed an edit` のキュー、下部に**承認 / 拒否**のピル)。ユーザーは差分を確認するために `エディタに挿入` ボタンを探してクリックする必要はありません。`エディタに挿入` ボタンはSQLブロックの下に手動再トリガーとして引き続き表示され(拒否後やユーザーが別のページに移動して戻った後に有用)、ユーザーが非エディタページ(例:保存済みクエリ一覧)にいる場合は唯一の手段となります。その場合、SQLを `sessionStorage` に保存して `/queries/new` にナビゲートし、新たにマウントされたエディタがマウント時にそのデータを読み取って同じ差分ビューを開きます。 + +提案されたSQLがすでにエディタにあるものとバイト単位で同一の場合(無操作の編集)、自動表示はスキップされます。空の差分は表示しません。その場合、`エディタに挿入` ボタンも無操作になります。 + +ユーザーが `/queries/new` で提案を承認した場合、ツールバーのプライマリアクションは `create` ではなく **`save`** と表示されます。SQLはアシスタントから渡されたものであり、メンタルモデルとしては「ゼロから書く」ではなく「これを確定させる」となります。ラベルはドックがSQLを挿入した時点で切り替わり、ページナビゲーションまで `save` のままです。`/queries/` ではボタンは常に `save` と表示されており、変更はありません。 + +`/queries` 以外では、ドックはこれまでどおりに動作します:ツール承認カード付きのフルチャット、ページコンテキスト認識、引用。 + +**権限 / ゲート。** composeエンドポイントはユーザーごとの `queries:run` 権限でゲートされます(読み取り相当。ユーザーは引き続き「承認」と「実行」をクリックする必要があり、「実行」はRustサーバー上の既存の `sql_guard` + `references_ch_tables` ルーティングを通過します)。chatエンドポイントは `agent:use` でゲートされます。どちらも `agent` コンテナに設定されたLLM接続が必要です。設定されていない場合、いずれのパスでもドックに「アシスタントはこのデプロイメントで設定されていません」というバナーが表示されます。 + +**拒否。** コンポーザーは読み取り専用分析クエリで満たせないリクエストを拒否し、SQLの代わりに `-- REFUSE: <1文の理由>` を出力します。データを書き込むリクエストや分析ビュー外のテーブル(`api_keys`、`users`、`dashboards`、`saved_queries`、`evaluation_jobs`)にアクセスするリクエストを拒否し、composeパスでの純粋な散文リクエスト(「これを説明して」「これは何をしている?」)も拒否します。それらはchatパスに属し、そこで散文形式の回答を提供します。ドックは拒否文字列をアシスタントメッセージ内のインライン赤色エラーチップとしてレンダリングします。何も挿入されません。 + +**モデル選択。** chatパスと共有されます。ドックヘッダーのモデルピッカーは両方のエンドポイントに適用されます(composeコールはエージェントサービスの `resolveModel()` に選択されたモデルを渡します)。`AGENTEYE_AGENT_MODELS` に複数のモデルがリストされている場合、オペレーターはコンポーザー用にHaikuクラスのオプション、チャット用にSonnetクラスのオプションを組み合わせることができ、ユーザーは会話ごとに選択できます。 + +**ページごとのテンプレート。** 各ページには独自のテンプレート(ヘッドライン、本文コピー、プレースホルダーテキスト、サジェスチョンチップ)があり、現在いるページに合わせてドックが適応します。特定のルートで提供されるチップはコンポーザーが調整されたインテントと同じものにマッピングされるため、サジェスチョンをクリックすると期待した編集が生成されます。 + +**無効化。** chatパスと同じです。ドックとコンポーザーはどちらも `agent` コンテナとそのLLM接続によってゲートされています。特定のユーザーにchatのみの動作をさせたい場合は `queries:run` 権限を削除します(これによりエディタの**実行**ボタンも無効になります)。コンポーザーのみの動作をさせたい場合は、そのユーザーのロールから `agent:use` を削除し、`queries:run` を別途再追加して作成済みSQLを実行できるようにします。 + +--- + +## 有効化 + +`agent` サービスはDocker ComposeファイルおよびKubernetesマニフェストに含まれています。アシスタントを有効にするには、**(1)** LLMエンドポイントと **(2)** アシスタント専用のデータキーを提供します。 + +### 1. LLM接続を選択する + +以下のいずれかを選択し、`agent` サービスに対応する変数を設定します。 + +**a) Anthropic直接接続** + +``` +ANTHROPIC_API_KEY=sk-ant-... +``` + +**b) Portkey経由(推奨;モデルカタログスラッグ、キーのみ)** + +``` +PORTKEY_API_KEY= +AGENTEYE_AGENT_MODEL=@/claude-sonnet-4-6 +``` + +これが最もシンプルな方法です。Portkeyで**Anthropicインテグレーション**(モデルカタログ)を設定すると**スラッグ**が付与されます。モデルを `@/` と指定すると、スラッグがプロバイダー + 認証情報のルーティングを担うため、**バーチャルキーは不要**で、Portkey APIキーのみで動作します。エージェントは `x-portkey-api-key` のみを送信してPortkeyゲートウェイを指定し、Portkeyが残りを解決します。(*プレーン*モデル名では「x-portkey-config or x-portkey-provider header is required」というエラーが発生します。`@slug/` プレフィックスがキーのみでの動作を可能にします。)セルフホストゲートウェイの場合は `PORTKEY_BASE_URL` を設定します。 + +スラッグではなくリクエストごとのルーティングを優先する場合は、プレーンな `AGENTEYE_AGENT_MODEL` と共に `PORTKEY_VIRTUAL_KEY=`(または `PORTKEY_CONFIG=`)を設定します。 + +**c) その他のAnthropicと互換性のあるゲートウェイ(LiteLLM、セルフホスト等)** + +``` +ANTHROPIC_BASE_URL=https://your-gateway +# 改行区切りの「Name: Value」ヘッダー行(JSONではない): +ANTHROPIC_CUSTOM_HEADERS=x-my-header: value +``` + +**d) Amazon Bedrock / Google Vertex** + +``` +CLAUDE_CODE_USE_BEDROCK=1 # + 環境内の標準AWSクレデンシャル +# または +CLAUDE_CODE_USE_VERTEX=1 # + 環境内の標準GCPクレデンシャル +``` + +オプションで `AGENTEYE_AGENT_MODEL` でデフォルトモデルを固定できます(デフォルト: `claude-sonnet-4-6`)。ユーザーが複数のモデルから**選択**できるようにするには、`AGENTEYE_AGENT_MODELS` にカンマ区切りの許可リストを設定します(例: `@anthropic-prod/claude-opus-4-7,@anthropic-prod/claude-sonnet-4-6`)。モデルピッカーがチャットヘッダーに表示され、各ユーザーの選択が記憶されます。エージェントはこの許可リスト上のモデルのみを呼び出します。 + +### 2. アシスタントキーを提供する + +任意のランダムなシークレットを選択し、**agent** には `AGENTEYE_API_KEY` として、**server** には `AGENT_API_KEY` として同じ値を設定します。起動時にサーバーはこれを `dashboard-assistant` という名前の専用キーとして、以下の固定権限セットでシードします:`events:read`、`evaluations:read`、`dashboards:read`、`dashboards:write`、`queries:read`、`queries:write`、`queries:run`。書き込み権限は承認制のツールを通じてのみ行使されます(上記の「できること・できないこと」を参照)。**手動のキー発行ステップも管理キーの関与もありません**。権限セットはサーバーに固定されており、シードされたキーは**保護されています**:キーAPIを通じて無効化や再生成はできません。値を変更してサーバーを再起動することでローテーションできます。管理者/ダッシュボードキーを再利用しないでください。 + +```bash +SECRET="$(openssl rand -base64 32)" +# agentサービスで: +AGENTEYE_API_KEY="$SECRET" +# serverサービスで: +AGENT_API_KEY="$SECRET" +``` + +Kubernetesでは自動的に設定されます:`AGENTEYE_API_KEY` を `agenteye-agent` シークレットに入れると、サーバーのDeploymentが同じ値を `AGENT_API_KEY` として読み取ります。 + +### 3. ダッシュボード↔エージェント共有トークンを設定する + +**dashboard** と **agent** の両方のサービスに同じ `AGENTEYE_AGENT_TOKEN` を設定します。ダッシュボードは内部エージェントサービスを呼び出す際にこれを提示し、エージェントはこれのない呼び出しを拒否します。 + +### 4. ユーザーにアクセスを付与する + +関連するダッシュボードオペレーターに `agent:use` 権限を付与します([enterprise-docs/api-keys.md](/ja/agenteye/api-keys) を参照)。この権限のないユーザーにはアシスタントが表示されません。 + +LLMエンドポイントと読み取り専用キーが設定されたら、**server**(読み取り専用キーをシードするため)と **agent** サービスを再起動します。アシスタントドックは `agent:use` ユーザーの右端に表示されます。デフォルトでは折りたたまれており、レールをクリックするか `⌘J` / `Ctrl+J` を押すと展開します。 + +--- + +## 環境変数リファレンス + +**`agent`** サービスに設定: + +| 変数 | 用途 | +|---|---| +| `PORTKEY_API_KEY` | Portkeyを経由したルーティング(エージェントはこれからゲートウェイ接続を構築する) | +| `PORTKEY_VIRTUAL_KEY` | Anthropicクレデンシャル用のPortkeyバーチャルキー(キーにデフォルト設定がある場合はオプション) | +| `PORTKEY_CONFIG` / `PORTKEY_BASE_URL` | 名前付きPortkeyコンフィグ / セルフホストPortkeyゲートウェイURL(オプション) | +| `PORTKEY_PROVIDER` | Portkeyプロバイダースラッグ — `PORTKEY_VIRTUAL_KEY` / `PORTKEY_CONFIG` のいずれも設定されていない場合のみ使用される、それらと並ぶ3番目のルーティングオプション | +| `ANTHROPIC_API_KEY` | Anthropicへの直接アクセス(ゲートウェイ / Bedrock / Vertexの代替) | +| `ANTHROPIC_AUTH_TOKEN` | `x-api-key` の代わりに `Authorization: Bearer` で認証するゲートウェイのBearerトークン(オプション) | +| `ANTHROPIC_BASE_URL` | Portkey以外のゲートウェイのエンドポイント | +| `ANTHROPIC_CUSTOM_HEADERS` | Portkey以外のゲートウェイ用の追加ヘッダー:改行区切りの `Name: Value` 行(JSONではない) | +| `CLAUDE_CODE_USE_BEDROCK` / `CLAUDE_CODE_USE_VERTEX` | Bedrock / Vertex経由でルーティング | +| `AGENTEYE_AGENT_MODEL` | デフォルトモデルID(デフォルト: `claude-sonnet-4-6`) | +| `AGENTEYE_AGENT_MODELS` | ユーザーがチャットヘッダーで選択できるモデルのカンマ区切り許可リスト。単一の固定モデルにする場合は未設定のままにする。上記のデフォルトはこの中の1つである必要があります(そうでない場合は追加されます)。 | +| `AGENTEYE_AGENT_MAX_CONCURRENCY` | ポッドあたりの最大同時チャット数(デフォルト4)。超過したリクエストには429が返される | +| `AGENTEYE_API_KEY` | アシスタントのデータキー。サーバーの `AGENT_API_KEY` と**同じ**値を設定します。起動時に固定のスコープ付き権限セットでシードされます(ステップ2を参照)。 | +| `AGENTEYE_AGENT_TOKEN` | ダッシュボードとの共有シークレット | +| `AGENTEYE_SERVER_URL` | AgentEyeサーバーURL(デフォルト: `http://server:8080`) | +| `AGENTEYE_AGENT_ALLOW_NO_ORG` | **マルチテナンシー。** デフォルトはオフ(フェイルクローズド):アシスタントは組織コンテキストを持たない `/chat` リクエストを `400` で拒否します。これはアシスタントが実行するすべてのツールが1つの組織にスコープされているためです。ダッシュボードは組織認識後に常にそのコンテキストを送信するため、通常はこれを未設定のままにします。組織未認識のダッシュボードが組織認識エージェントと通信している移行期のロールアウト中にのみ `1` に設定し、拒否する代わりに `default` 組織にフォールバックするようにします。ダッシュボードのアップグレードが完了したらクリアします。 | +| `AGENTEYE_AGENT_MAX_STEPS` | 回答あたりの最大ツール使用ステップ数(デフォルト8) | +| `AGENTEYE_AGENT_TIMEOUT_MS` | `/chat` リクエスト全体のタイムアウト(全モデルターン + ツールステップ)、ミリ秒単位(デフォルト90000)。SQLツールには独自の10秒上限がある | +| `AGENTEYE_AGENT_SELF_TELEMETRY` | アシスタント自身の実行をAgentEyeに記録するには `1` に設定 | +| `AGENTEYE_TELEMETRY_API_KEY` | 自己計装用の `events:add` のみの別キー | +| `AGENTEYE_AGENT_ENV` | アシスタント自身の自己テレメトリに適用される環境タグ(デフォルト: `prod`) | + +**`dashboard`** サービスに設定: + +| 変数 | 用途 | +|---|---| +| `AGENTEYE_AGENT_URL` | ダッシュボードがエージェントサービスにアクセスする場所。バンドルされたKubernetesマニフェストとComposeファイルでは `http://agent:9100` に設定されています。未設定の場合、アシスタントは完全に非表示になります。 | +| `AGENTEYE_AGENT_TOKEN` | エージェントのトークンと一致する必要があります | + +--- + +## テレメトリとユーザーの質問内容の確認 + +プロンプトの**内容はデフォルトで自分のシステム内に留まります**。3つのレイヤー: + +1. **会話ストア**:すべてのプロンプトと回答がAgentEyeデータベースに保存されます(ユーザーごと、プライベート)。アシスタントの履歴スイッチャーから再読み込み可能です。これがユーザーの質問内容の永続的な記録です。 +2. **プロダクト分析**:ダッシュボードはアナリティクスに**メタデータのみ**を記録します(アシスタントの使用頻度、ツール数、レイテンシ)。このパスにプロンプトの**テキスト**は含まれません。 +3. **自己計装(オプション)**:`AGENTEYE_AGENT_SELF_TELEMETRY=1` を設定(および `events:add` のみの `AGENTEYE_TELEMETRY_API_KEY`)すると、アシスタントは自身の実行を `dashboard-assistant` エージェントとしてAgentEyeに記録します。他のすべてに使用しているのと同じセッション/イベントビューでユーザープロンプトとアシスタントの推論を確認できます。注意:これらのイベントは `events:read` を持つ誰にでも表示されます。それが広すぎる場合は、この機能を無効のままにしてください。 + +--- + +## 無効化 + +以下のいずれかでアシスタントが無効になります(ドックレールが消えます): + +- ダッシュボードで `AGENTEYE_AGENT_URL` を未設定にする、**または** +- エージェントでLLMエンドポイントを未設定のままにする(`ANTHROPIC_API_KEY` / ゲートウェイ / Bedrock / Vertex なし)、**または** +- `agent` サービスをデプロイしない。 + +--- + +## セキュリティサマリ + +- **サイレントな書き込みなし**:アシスタントの書き込みツール(`create_saved_query`、`update_saved_query`、`create_dashboard`、`update_dashboard`、`add_query_to_dashboard`)は、チャット内の承認ボタンをオペレーターが明示的にクリックしない限り実行できません。SDKのプリコールゲートは、バックチャンネル経由でエージェントに承認が届くまでツールをブロックします。このゲートを無効にする設定はありません。 +- **固定された狭いデータスコープ**:アシスタントはサーバー内で固定された権限セット(`events:read`、`evaluations:read`、`dashboards:read`、`dashboards:write`、`queries:read`、`queries:write`、`queries:run`)を持つ専用キーでサーバーに認証します。作成できる書き込みは保存済みクエリとダッシュボードのみであり、モデルが試みた内容に関係なく、サーバーはそのスコープ外のものをすべて拒否します。 +- **削除機能なし**:キーには削除権限がなく、削除ツールも公開されていません。オペレーターはダッシュボードUIを通じて削除し、アシスタントを通じては削除しません。 +- **内部専用**:エージェントには公開ルートがなく、ダッシュボードのみが共有トークンを使って呼び出せます。(Kubernetesでは、NetworkPolicyがエージェントをAgentEyeサーバーとLLMエンドポイントのみに到達するよう制限します。) +- **ユーザーごとのスコーピング**:`agent:use` ユーザーのみがアシスタントを利用でき、各ユーザーの読み取り権限に一致するツールのみが提供されます。 +- **生のHTMLなし / リンク流出なし**:回答はサニタイズされたマークダウンとしてレンダリングされ、外部リンクは無効化されます。 + +一般的な問題については [enterprise-docs/troubleshooting.md](/ja/agenteye/troubleshooting) を参照してください。 \ No newline at end of file diff --git a/docs/ja/agenteye/audits.mdx b/docs/ja/agenteye/audits.mdx new file mode 100644 index 00000000..f00fce28 --- /dev/null +++ b/docs/ja/agenteye/audits.mdx @@ -0,0 +1,107 @@ +--- +title: "監査 — エージェント的な改善検出" +description: "AgentEye 監査 — エージェント的な改善検出のドキュメント。" +--- + + +監査は、**セッションをまたいで**エージェントのログを分析し、改善すべき点を発見する定期ジョブです。アラートが既知の指標をほぼリアルタイムで監視するのに対し、監査は*調査*を行います。設定したスケジュールで、ウィンドウ全体に対して決定論的なポリシーパスを実行し、続いて**AI信頼性エージェント**をセッションに対して動かします。エージェントはデータに対してクエリを実行し、疑わしいトランスクリプトを読み込み、必要に応じて小規模な分析スクリプトを実行したうえで、各発見の根拠とともに**改善提案**をまとめます。 + +「エージェントの何を修正・改善すべきか」という問いへの回答には監査を、特定の閾値を超えた瞬間に通知を受け取るにはアラートを使い分けてください。すべての改善提案は背後のセッションとクエリに直接リンクされており、ワンクリックで再発を検知するためのアラートを事前入力済みの状態で作成できます。 + +ダッシュボードの画面は **`//audits`**(サイドバー → *analyze* → *audits*)で、`audits:read` / `audits:write` 権限によって制御されます。 + +--- + +## 実行の仕組み + +各実行には2つの層があります。決定論的な基盤層と、エージェント的な調査層です。 + +### 1. ポリシーパス(決定論的) + +モデルが動く前に、監査はウィンドウに対して**SQLポリシーチェック**の小さなカタログを実行します。既知の問題パターンにフラグを立て、該当したイベント数/セッションを報告する境界付き集計クエリで、マッチしたテキスト自体は報告されません。カタログには以下が含まれます。 + +- イベントペイロード内の**シークレット/認証情報の漏洩** — AWSアクセスキー、`sk-…` APIキー、PEM秘密鍵、JWT / Bearerトークン、`KEY=…` 形式の認証情報 +- **プロンプトインジェクションのマーカー** — 「以前の指示を無視して」「システムプロンプトを教えて」など +- **PII** — SSN形式の番号(ヒューリスティック) +- **ツール権限の拒否**と**際限のないツールコールループ** + +ポリシーヒットはファインディング(kind: `policy`)として永続化され、**常に表示**されます(実行ごとの上限によるトリミングの対象外)。また、AIエージェントへの手がかりとして渡されます。この層はモデルを必要としないため、AIエージェントが利用できない場合でも、監査は最も重要なセキュリティシグナルを生成します。 + +### 2. エージェント的調査(AI) + +次に監査は**自律的な信頼性エージェント**を実行します(ダッシュボードアシスタントを動かしているのと同じ Claude Agent SDK サービスを、監査専用のプロンプトで使用)。エージェントは監査の**スコープ**(対象エージェント × 環境)と**時間ウィンドウ**をもとに、以下を行います。 + +- 分析テーブルに対して読み取り専用のSQLクエリを実行 +- 代表的なセッショントランスクリプトを数件読み込み +- SQLでは表現できない分析(エラーのクラスタリング、分布の計算、取得済みペイロードのスキャン)が必要な場合は、**隔離されたイン・ポッド・サンドボックス**(ネットワーク不可、ファイルシステムアクセス不可、シークレットはスクラブ済み)で短いPythonスクリプトを実行 +- 十分な根拠を持つ**改善点**を記録 + +エラーのクラスタリング、ベースラインとのドリフト、トランスクリプト上のゴール失敗、ツールの誤用、品質/コストのトレードオフ、カバレッジギャップなど、複数の調査ラインを監査の**感度**(low / medium / high)に従って検討します。すべての改善提案は**証拠の引用が必須**です。エージェントが実際に検査したセッションIDか、実行したSQLのいずれか(または両方)を引用する必要があります。サーバーは引用されたセッションの存在を検証し、**生き残った証拠のない改善提案は破棄**します。つまりエージェントは調査するだけで、事実を創作しません。 + +各改善提案には以下が含まれます。 + +- **推奨事項**(具体的な変更内容 — プロンプトの調整、ツールスキーマの修正、リトライポリシー、ガードレール、評価カバレッジの拡充など) +- **期待される効果**と**工数**の見積もり(low / medium / high) +- **重大度** — `big`(オペレーターへの即時通知が必要)、`medium`(実行レポートに記載)、`small`(ダッシュボードのコンテキスト情報) +- 安定した**フィンガープリント**(問題のカテゴリ + スコープに基づき、今回の実行セッションには依存しない)により、証拠が変わっても同じ問題を実行をまたいで追跡可能 +- 決定論的な監視で再発を検知できる場合は、ワンクリックで作成できる**アラートの提案** + +> **AIレイヤーは任意ですが推奨されます。** 監査パイプラインにAIエージェントが設定されていない場合も、実行は行われ、ポリシーファインディングは永続化されます。エージェント層については「分析利用不可」と正直にレポートし、静かにパスすることはありません。 + +### 障害モード + +改善提案は組織の永続的な**障害モードカタログ**に分類されます(または新しいモードを提案します)。モードにより、実行をまたいだパターンの安定したID管理と長期的な再発追跡が可能になります。 + +## トリアージのライフサイクル + +ファインディングページ(`/audits//findings/`)での操作: + +| アクション | 効果 | +|---|---| +| **acknowledge** | ファインディングを表示したまま優先度を半減させます。 | +| **resolve** | 修正済みとしてマークします。パターンが後日再発した場合、**new** として再オープン — 退行は静かに歴史に埋もれることなく、明示的に通知されます。 | +| **mute** / **dismiss** | 永続的な抑制:パターンのフィンガープリントが記憶され、実行をまたいで二度と表示されません。muteは「既知・許容済み」、dismissは「有用でない」場合に使用します。 | +| **reopen** | 抑制・解決をクリアし、パターンを再度ランク付けします。 | +| **assign** | ファインディングをオーナーとして組織メンバーのオペレーターに割り当てます。優先度と抑制状態は変わりません。 | + +低シグナルのノイズは、エージェント的な改善に対する実行ごとのファインディング上限(`top_k`)で監査ごとに制御されます。ポリシーファインディングはセキュリティ上重要なため上限をバイパスし、常に表示されます。上限によって除外されたものは実行の統計に計上されます — 何も静かに破棄されません。 + +## スケジューリング + +- **ケイデンス**(`schedule_interval_secs`):1時間ごと〜週1回。**デフォルトは1日1回**。監査はアラートよりも粗い粒度で設計されています。エージェント的な調査はウィンドウ全体をスキャンし、実行に数分かかります。 +- **ウィンドウ**:固定のローリングルックバック(例:「各実行は直近7日間をスキャン」)または**前回実行以降**(デフォルト)— 各実行は前回成功した実行が終了した時点から開始し、境界イベントを見逃さないように小さなオーバーラップを設けます。 +- 次の実行は、前の実行が**完了**してから1インターバル後にスケジュールされます。これにより、実行が遅延しても同じ監査の2回目の実行が同時に重なることはありません。 +- 監査ページの**今すぐ実行**をクリックすると、即座に実行対象となります。 + +## モデル選択 + +監査作成時に、エージェントサービス用に**オペレーターが設定したモデルリスト**から調査に使用するモデルを選択できます。モデルが1つだけ設定されている場合はキャプションとして表示され、複数ある場合は選択できます。未設定の場合は設定済みのデフォルトが使用されます。 + +## 通知 + +実行で**新規**ファインディングが検出された場合、監査は組織の設定済みチャネルに通知します。アラートパイプラインが使用するものと同じ `alerts.enabled_channels` ゲートと設定を使用します。 + +- **Slack** — 重要(`big`)な新規項目のサマリーとディープリンク +- **Email** — 新規改善提案(最高重大度、項目ごとの推奨事項、ディープリンク)をリストアップした**監査レポート**。監査に**email**チャネルが設定されており、新規ファインディングが1件以上ある場合に送信されます。 + +繰り返し検出されているが既知のファインディングは再通知されません。 + +## 設定リファレンス + +監査の定義はダッシュボード(`/audits/new`)またはAPIで管理します。監査ごとの設定には、スケジュールのケイデンスとウィンドウ、スコープ(`{"environments": [...], "agent_ids": [...]}`)、感度(`low` / `medium` / `high`)、通知チャネル、実行ごとのファインディング上限(`top_k`)、モデル(`llm_budget.model`)が含まれます。オペレーターレベルのサーバー設定(タイムアウト、サンドボックス、エージェントサービスのURL)は [deployment.md](/ja/agenteye/deployment) に記載されています。 + +## API + +すべてのエンドポイントは組織スコープで、標準のBearerキー認証を使用します([api-keys.md](/ja/agenteye/api-keys) を参照)。 + +| エンドポイント | 権限 | 目的 | +|---|---|---| +| `GET /audits` · `POST /audits` | `audits:read` / `audits:write` | 監査定義の一覧取得 / 作成 | +| `GET` / `PUT` / `DELETE /audits/:id` | read / write / write | 監査の参照、編集、削除 | +| `POST /audits/:id/run` | `audits:write` | 監査を即座に実行対象にする | +| `GET /audits/:id/runs` | `audits:read` | 実行履歴(ウィンドウ、ステータス、統計、ファインディング数) | +| `GET /audits/findings` | `audits:read` | 組織全体のファインディング。`audit_id`、`status` でフィルタリング可能。優先度順に並べ替え済み | +| `GET /audits/findings/:fid` | `audits:read` | ファインディングの全詳細(推奨事項、証拠、優先度) | +| `POST /audits/findings/:fid/status` | `audits:write` | トリアージ: `{"action": "ack" \| "mute" \| "dismiss" \| "resolve" \| "reopen" \| "assign"}` | + +「監査を実行したが何も検出されなかった」「コードサンドボックスが無効」「監査メールが届かない」については、[troubleshooting.md](/ja/agenteye/troubleshooting#audits) を参照してください。 \ No newline at end of file diff --git a/docs/ja/agenteye/cli-recipes.mdx b/docs/ja/agenteye/cli-recipes.mdx new file mode 100644 index 00000000..127e14bc --- /dev/null +++ b/docs/ja/agenteye/cli-recipes.mdx @@ -0,0 +1,170 @@ +--- +title: "エージェント向けCLIレシピ" +description: "エージェント向けAgentEye CLIレシピのドキュメント。" +--- + + +スクリプトやコーディングエージェントから直接、セッション・イベント・評価データを取得し(再評価のトリガーも可能)、`jq` にパイプできるクリーンなJSON を stdout に出力します。これらのレシピは、AgentEye のオブザーバビリティデータを、ターミナルユーザーやAIコーディングエージェント(Claude Code、Cursor)がダッシュボードをクリックせずにクエリ・自動化できる形に変えます。 + +以下のパターンは AgentEye CLI(`agenteye`)へそのままコピーペーストできます。インストール・認証・全オプション一覧については [CLI](/ja/agenteye/cli) を参照してください。組み込みヘルプは `agenteye -h` または `agenteye -h` で確認できます。 + +## 基本ルール + +1. **グローバルオプションはコマンドの*前*に指定する。** `agenteye --json sessions` が正しく、`agenteye sessions --json` は誤りです。グローバルオプションは `--json`、`--base-url`、`--org`、`--token`、`--insecure`/`--secure`、`--timeout`、`--quiet`、`--no-color` です。 +2. **出力をパースする場合は必ず `--json` を渡す。** データは JSON として **stdout** に出力され、人間向けのステータスやエラーは **stderr** に出力されるため、stdout が `jq` へのパイプに適した状態に保たれます。 +3. **分岐は stderr のテキストではなく終了コードで行う。** `0` 正常 · `2` 引数エラー · `3` ダッシュボード到達不能 · `4` 未ログインまたはセッション期限切れ · `5` 権限不足。 +4. **`-h` で仕様を確認する。** すべてのコマンドにフィルター・値のフォーマット・JSONの形式が記載されています。 + +## 初回セットアップ + +```bash +export AGENTEYE_DASHBOARD_URL=https://agenteye.example.com # --base-url の繰り返しを省略 +agenteye login --email you@example.com # メールで届いたコードを貼り付け; 有効期間 ~24h +``` + +## 作業前の認証確認 + +`whoami` はセッションが存在しない・期限切れの場合もエラーにならず、代わりに `logged_in:false` を返します。そのため、エージェントが安全に認証状態を確認できます(ベースURLが未設定またはダッシュボードに到達できない場合は、非ゼロで終了することがあります)。 + +```bash +if [ "$(agenteye --json whoami | jq -r .logged_in)" != "true" ]; then + echo "Not authenticated. Run: agenteye login" >&2; exit 1 +fi +``` + +## 失敗または低スコアのセッションを探す + +```bash +# 過去24時間で評価がエラーになったセッション +agenteye --json sessions --since 24h --status error | jq -r '.sessions[].session_id' + +# helpfulness スコアが 0.5 以下の評価(特定エージェント対象) +agenteye --json evals --agent-id checkout-bot --score helpfulness:..0.5 \ + | jq '.evaluations[] | {session_id, scores}' +``` + +スコアフィルタリングは `sessions` ではなく **`evals`** に対して行います。`--score KEY:MIN..MAX` は繰り返し指定可能でAND結合されます。いずれかの境界は省略可能です(`..0.5` は ≤ 0.5、`0.9..` は ≥ 0.9 を意味します)。1リクエストあたり最大20個のスコアフィルターを指定できます。それ以上はHTTP 400が返ります。`sessions` は `evals` と `--env`、`--status`、`--agent-id`、`--session-id`、時間範囲フィルターを共有しますが、`--score` はありません。 + +## セッションをエンドツーエンドで読む + +単一の `session show` コマンドはありません。イベント履歴とセッションの評価を組み合わせてください。 + +```bash +# セッションの最新評価(ステータス + スコア) +agenteye --json evals --session-id run-001 | jq '.evaluations[0] | {status, scores}' + +# 実行中の全イベント(全件取得は --limit を増やす) +agenteye --json events --session-id run-001 --all --limit 1000 | jq '.events[] | {ts, event_type}' + +# セッション内のツール呼び出しのみ +agenteye --json events --session-id run-001 --event-type tool_use,tool_result --all \ + | jq '.events[].payload' +``` + +## 全件取得(ページネーション) + +結果は新しい順で返され、カーソルページネーションを使用します。 + +```bash +# 一括取得: 200行ページで最大500行を取得 +agenteye --json events --session-id run-001 --limit 500 --all > events.json + +# 手動ページング: next_cursor を再利用 +page=$(agenteye --json events --limit 100) +cursor=$(echo "$page" | jq -r '.next_cursor // empty') +[ -n "$cursor" ] && agenteye --json events --limit 100 --cursor "$cursor" +``` + +## --fields で出力を絞り込む + +エージェントが読み取るキーを(テーブルと `--json` の両方で)制限します。 + +```bash +agenteye --json sessions --since 7d --fields session_id,status,scores | jq -c '.sessions[]' +agenteye --json events --session-id run-001 --fields ts,event_type --all +``` + +不明なフィールド名は(終了コード `2` で)拒否され、有効なフィールド一覧が表示されます。フィールド名を確認する手軽な方法です。 + +## 有効なフィルター値を調べる + +```bash +agenteye --json list envs | jq -r '.values[]' # --env に使える値 +agenteye --json list tools | jq -r '.values[]' # ツール名; agents, models, event_types なども同様 +agenteye --json list score_filters | jq -r '.values[]' # --score KEY:MIN..MAX の有効な KEY +``` + +## 組織の選択(マルチテナント) + +複数の組織に所属している場合、ログイン時にアクティブなテナントを選択します(保存されます)。 + +```bash +agenteye login --org acme --email you@corp.com # ログインと同時にテナントを設定 +agenteye --json orgs list | jq -r '.orgs[].org_slug' +agenteye --org globex --json sessions --since 24h # 1コマンドのみ上書き +``` + +`--org` を指定しないマルチ組織ログインは非ゼロで終了し、選択可能な組織一覧を表示します。 + +## SDK/コレクター用APIキーのプロビジョニング + +```bash +# シークレットは一度だけ表示されます — --json の場合は .key フィールドに含まれます +key=$(agenteye --json keys create ci-bot --add events:read.add | jq -r '.key') +agenteye keys regenerate ci-bot --yes # ローテーション; 無効化は agenteye keys disable ci-bot --yes +``` + +## 保存済みまたはアドホッククエリの実行 + +```bash +agenteye --json query run --sql "select count(*) from analytics.events" | jq '.rows' +agenteye --json query run errs --arg prod | jq '.rows' # 保存済みクエリ + 位置引数 $1 +``` + +## インシデントの非対話的なトリアージ + +```bash +id=$(agenteye --json incidents list --state firing | jq -r '.incidents[0].id') +agenteye incidents ack "$id" +agenteye incidents assign "$id" you@corp.com +agenteye incidents resolve "$id" --yes +``` + +> ミューテーション操作は `--json` 使用時またはstdinがTTYでない場合、確認プロンプトを自動的にスキップします。エージェントがハングしないようになっています。他の場所で明示的にスキップするには `--yes`/`-y` を渡してください。 + +## スクリプトでの終了コード処理 + +```bash +out=$(agenteye --json sessions --since 1h) || code=$? +case "${code:-0}" in + 0) echo "$out" | jq '.sessions | length' ;; + 4) echo "Session expired - run 'agenteye login'." >&2 ;; + 5) echo "Missing permission (ask an admin for evaluations:read)." >&2 ;; + 3) echo "Dashboard unreachable - check the URL." >&2 ;; + *) echo "Unexpected error (exit ${code})." >&2 ;; +esac +``` + +## JSON出力の形式 + +| コマンド | stdout JSON(`--json` 使用時) | +|---|---| +| `whoami` | `{"logged_in": true, "id", "email", "is_instance_admin", "active_org", "permissions": [...], "memberships": [...]}` または `{"logged_in": false}` | +| `orgs list` | `{"active_org", "orgs": [{"org_slug","org_name","permission_set","permissions"}]}` | +| `events` | `{"events": [...], "next_cursor": }` | +| `evals` | `{"evaluations": [...], "next_cursor": }` | +| `sessions` | `{"sessions": [...], "next_cursor": }` | +| `errors` | `{"errors": [...], "next_cursor": }` | +| `list ` | `{"kind", "values": [...]}` | +| `keys list` / `keys create` | `{"keys": [...]}` / `{id, name, permissions, created_at, key}` (`key` は一度のみ表示) | +| `query run` | `{columns: [{name,type}], rows: [[...]], truncated, elapsed_ms}` | +| `users list` / `settings list` | `{"users": [...]}` / `{"settings": [...]}` | +| `alerts list` / `incidents list` | `{"alerts": [...]}` / `{"incidents": [...]}` | +| 作成/更新/削除(全般) | リソースオブジェクト、または削除の場合は `{"deleted": true, "id"}` | +| 失敗時(全般、`--json` 使用) | stdout に `{"error": "...", "exit_code": , "status"?: , "hint"?: "..."}` | + +- **event** の各アイテム(`events`): `id, session_id, agent_id, event_type, ts, payload, environment` +- **evaluation** の各アイテム(`evals`): `id, session_id, agent_id, environment, status, scores, reasoning, summary, error, attempt_count, duration_ms, completed_at, created_at` +- **session** の各アイテム(`sessions`): `session_id, agent_id, environment, status, scores, event_count, started_at, last_event_at, first_event_id, last_event_id, latest_evaluation` + +各コマンドの `--fields` は、そのコマンド固有のアイテムのフィールド名のみを受け付けます。`sessions` と `evals` ではフィールドセットが異なるため、一方で有効な名前が他方では拒否される場合があります。 \ No newline at end of file diff --git a/docs/ja/agenteye/cli-skill.mdx b/docs/ja/agenteye/cli-skill.mdx new file mode 100644 index 00000000..2b52cd96 --- /dev/null +++ b/docs/ja/agenteye/cli-skill.mdx @@ -0,0 +1,95 @@ +--- +title: "AgentEye CLI エージェントスキル" +description: "AgentEye CLI エージェントスキルのドキュメント。" +--- + + +**AgentEye CLI スキル**(`agenteye-cli`)は、インストール可能な *エージェントスキル* です。Claude Code、Codex、および互換ツールなどのコーディングエージェントに、[`agenteye` CLI](/ja/agenteye/cli) を通じて自然言語のリクエスト(*「今日、何か壊れているものはある?」*、*「イベントのプッシュのみ可能なキーを CI に発行して」*、*「発火中のインシデントを確認して自分にアサインして」*)から AgentEye を操作する方法を教えます。 + +これはサービスでも独立したバイナリでもありません。すでにインストール済みの CLI の上で動作する、小さな命令バンドルです。エージェントは `agenteye --json …` をシェルアウトして実行し、返ってきたクリーンな JSON を解析して、結果を自然な文章で回答します。エージェントができることは、あなたが同じコマンドを手入力することで全て実現できます。 + +--- + +## 他の AgentEye インターフェースとの関係 + +AgentEye では、同じデータと操作にアクセスする方法が 4 つあります。それぞれ補完的な役割を持っています: + +| インターフェース | 概要 | 動作場所 | 使い所 | +|---|---|---|---| +| **[CLI](/ja/agenteye/cli)** | `agenteye` のコマンド・フラグリファレンス | ターミナル | 特定のコマンドを実行またはスクリプト化したいとき | +| **[CLI レシピ](/ja/agenteye/cli-recipes)** | コピー&ペーストで使える `jq`・パイプラインパターン | ターミナル/スクリプト | CLI を自動化に組み込むとき | +| **CLI スキル**(このドキュメント) | CLI への自然言語フロントエンド | ワークステーション上のコーディングエージェント | 質問するだけでエージェントに適切なコマンドを選ばせたいとき | +| **[ダッシュボード内 AI アシスタント](/ja/agenteye/assistant)** | ダッシュボードに組み込まれたチャット | クラスター内の内部 `agent` コンテナ | ダッシュボード上でデータに関する Q&A をしたいとき | + +### ダッシュボード内 AI アシスタントとの違い — 重要な区別 + +これらは影響範囲が大きく異なる、2 つの別々のツールです: + +- **ダッシュボード内 AI アシスタント**([assistant.md](/ja/agenteye/assistant))は、内部 `agent` コンテナをバックエンドとして持つ、ダッシュボードに組み込まれたチャットです。**読み取り専用+承認ゲート付きの編集**が可能で、保存済みクエリやダッシュボードの下書きを作成できますが、すべての書き込み操作はあなたの明示的なクリック承認が必要であり、削除操作は行いません。`agent:use` 権限によってアクセスが制限され、閲覧中の組織のデータのみにアクセスできます。 +- **CLI スキル**は *あなたの* ワークステーション上で *あなたの* コーディングエージェント内で動作し、**あなた自身として** `agenteye` CLI を操作します。API キーの作成・ローテーション・無効化、組織設定の変更、インシデントの解決、保存済みクエリの削除など、**ミューテーションを含む CLI のフルサーフェス**を実行できます。実行可能な操作はあなたの CLI ログインの権限にのみ制限されます。手動でコマンドを実行する場合と全く同じ慎重さで扱ってください。 + +--- + +## 前提条件 + +1. **`agenteye` CLI がインストール済み**で `PATH` が通っていること([cli.md](/ja/agenteye/cli) を参照 — `pipx install agenteye`)。 +2. **ダッシュボード URL** が設定済みであること(`AGENTEYE_DASHBOARD_URL`、またはエージェントが `--base-url` を渡す)。 +3. **ログイン済みのセッション**があること:事前に自分で `agenteye login` を実行してください。スキルはメールで送られるワンタイムコードによるログインを代行**できません** — セッションが存在しないか期限切れの場合(CLI 終了コード `4`)、`agenteye login` を実行するよう案内します。 + +--- + +## スキルのインストール + +エージェントスキルは `SKILL.md`(とオプションの参照ファイル)を含むフォルダーです。`agenteye-cli` スキルは、エージェントがスキルを探す場所にフォルダーを配置することでインストールします: + +- **Claude Code** — `agenteye-cli/` フォルダーを `~/.claude/skills/`(全プロジェクトで利用可能)または `<リポジトリ>/.claude/skills/`(そのリポジトリに限定)にコピーします。Claude Code は自動的に検出します。`/skills` リストで確認するか、説明に合致する質問を直接してみてください。 +- **Codex (OpenAI)** — Codex は同じ `SKILL.md` を読み込みます。同梱の `agents/openai.yaml` は `allow_implicit_invocation: true` を設定しているため、タスクが合致した場合は Codex が自動的にスキルを選択します。それ以外の場合は `$agenteye-cli` として明示的に呼び出せます。 + +このスキルは `agenteye` CLI と一緒にメンテナンスされ、AgentEye パッケージの一部として配布されています。`agenteye-cli` フォルダーが見当たらない場合は、AgentEye の担当者にお問い合わせください。Docker イメージも追加の認証情報も不要です。あなた自身のダッシュボードに対して **公開** の `agenteye` CLI を操作するだけです。 + +--- + +## 安全性 — エージェントが CLI を実行する際、ミューテーションは確認プロンプトを表示しません + +**エージェントに変更を加えさせる前に必ずお読みください。** + +`agenteye` CLI は通常、破壊的な操作の前に *「本当によろしいですか?」* と確認を求めます。しかし、**ターミナルに接続されていない場合は確認を自動スキップします — これはコーディングエージェントの実行方式そのものであり、`--json` も同様にスキップします。** そのため、エージェントに対して安全確認プロンプトは**表示されません**。 + +スキルはこれを補うように設計されています:実行するコマンドを明示的に提示し、状態変更の前にあなたの明示的な **OK** を求めるよう指示されています。この規律を守ってください — エージェントを通じて AgentEye を操作する際、*あなた自身* が確認ステップです。注意すべき状態変更コマンドは以下の通りです: + +- `keys create` / `update` / `disable` / `regenerate` +- `users create` / `update` / `disable` / `enable` +- `settings set` +- `alerts create` / `update` / `delete` / `test` +- 書き込み系 `incidents` サブコマンド:`ack` / `assign` / `resolve` / `open` / `comment-add` / `comment-delete` / `subscribe` / `unsubscribe` +- `query create` / `update` / `delete` +- `agent rename` / `delete` +- `orgs switch` + +**Observe** 配下(`events`、`sessions`、`evals`、`errors`、`list`、`whoami`、`orgs list/current/perms`)はすべて読み取り専用で、何も変更しません。 + +エージェントは **あなた自身** として動作するため、あなたのログインが許可している操作のみ実行できます。権限は**組織ごと**に解決されます([api-keys.md](/ja/agenteye/api-keys) を参照)。権限がないコマンドは終了コード `5` と共に該当する権限名を返すため、エージェントは失敗の理由を不明瞭にせず、管理者に何を依頼すべきかを正確に伝えることができます。 + +--- + +## 質問できること + +スキルは自然言語の意図を適切な `agenteye` コマンドにマッピングします。推測を避けるために、まず有効な値を確認します(`list `、`whoami`): + +- *「過去 24 時間に壊れている/失敗しているものはある?」* → `errors --since 24h --aggregate` を実行し、内訳を表示。 +- *「セッション `run-001` はなぜ失敗した?」* → `events --session-id run-001 --all` + `evals --session-id run-001`。 +- *「今週の品質トレンドはどう?」* → `evals --aggregate --since 7d` を実行し、スコアの低いランについて詳細を確認。 +- *「イベントのプッシュのみ可能なキーを CI に発行して。」* → `keys create ci --add events:add`(コマンドを提示してから作成し、ワンタイムシークレットを取得)。 +- *「誰がアクセスできる?Dana を読み取り専用にして。」* → `users list` → `users update dana@… --permission-set read-only`(あなたに確認した後)。 +- *「発火中のインシデントを確認して自分にアサインして。」* → `incidents list --state firing` → `incidents ack ` / `incidents assign you@…`。 + +これらの背後にある正確なコマンド、フラグ、JSON の形式については、[cli.md](/ja/agenteye/cli) および [cli-recipes.md](/ja/agenteye/cli-recipes) を参照してください。 + +--- + +## 関連ドキュメント + +- **[CLI](/ja/agenteye/cli)** — `agenteye` のコマンドとフラグの完全なリファレンス。 +- **[エージェント向け CLI レシピ](/ja/agenteye/cli-recipes)** — コピー&ペーストで使える `jq` パターンと終了コードの処理。 +- **[AI アシスタント](/ja/agenteye/assistant)** — ダッシュボード内アシスタント(このターミナルスキルとは異なります)。 +- **[API キー](/ja/agenteye/api-keys)** — スキルの実行可能範囲を決める組織ごとの権限モデル。 \ No newline at end of file diff --git a/docs/ja/agenteye/cli.mdx b/docs/ja/agenteye/cli.mdx new file mode 100644 index 00000000..ce7e4bdb --- /dev/null +++ b/docs/ja/agenteye/cli.mdx @@ -0,0 +1,291 @@ +--- +title: "CLI" +description: "AgentEye CLIのドキュメント。" +--- + +AgentEye CLI(`agenteye`)は、AgentEyeデプロイメント向けのターミナルクライアントです。データ(セッション、イベントログ、評価)の照会と、組織の管理(APIキー、ユーザー、設定、アラート、インシデント、保存済みクエリ)を行います。ダッシュボードで実行できることはすべて、スクリプトやコーディングエージェントからも実行できます。すべてのコマンドは `--json` フラグに対応しており、ターミナルで作業する人間にも、結果をパースするコーディングエージェント(Claude Code、Cursor)にも同様に使用できます。 + +> これは **`agenteye` CLI** であり、**コレクター**デーモン(`agenteye-collector`)とは異なるツールです。CLIはお使いの**ダッシュボード**と通信し、コレクターはサーバーにイベントを送信します。コレクターについては [コレクターのインストール](/ja/agenteye/collector-installation) を参照してください。 + +--- + +## インストール + +CLIはパブリックのPyPIに **`agenteye`** として公開されています。AgentEyeのPython SDKも `agenteye` というディストリビューション名を使用しているため、CLIは**独立した**環境(`pipx` または `uv tool`)にインストールして、同一の仮想環境で両者が競合しないようにしてください。 + +```bash +pipx install agenteye +# または +uv tool install agenteye +``` + +Python SDKを同じ環境にインストールしない場合は、通常の `pip install agenteye` でも動作します。CLIにはPython 3.10以上が必要で、GitHubトークンは不要です。パブリックパッケージです。 + +インストールされるコマンドは **`agenteye`** です。 + +```bash +agenteye --version +agenteye --help +``` + +--- + +## 認証 + +CLIは、メールで送信されるワンタイムコードを使用して**ダッシュボード**に認証します。 + +```bash +agenteye login --email you@example.com +# 6桁のコードがメールで届きます。プロンプトに貼り付けてください。 +``` + +セッショントークンは `~/.agenteye/cli.json`(本人のみ読み取り可能、モード `0600`)に保存され、デフォルトで24時間有効です。期限が切れたら、`agenteye login` を再度実行してください。 + +```bash +agenteye whoami # 現在のユーザー、アクティブな組織、権限を表示 +agenteye logout # セッションを無効化し、保存されたトークンを削除 +``` + +`whoami` はセッションが存在しない場合や期限切れの場合にエラーを返しません。代わりに `logged_in: false` を報告するため、スクリプトやエージェントが認証状態を安全に確認できます(ベースURLが設定されていない場合やダッシュボードに到達できない場合は、ゼロ以外の終了コードを返すことがあります)。 + +**前提条件:** あなたのメールアドレスがダッシュボードへのサインインを許可されている必要があります(AgentEye管理者に確認してください)。また、ダッシュボードはそのベースURLで到達可能である必要があります([設定](#configuration)を参照)。コードをリクエストしても届かない場合、そのメールアドレスはまだダッシュボードアクセスが有効化されていない可能性があります。 + +--- + +## 組織の選択(マルチテナント) + +アカウントが複数の組織に所属している場合、**ログイン時に**アクティブな組織を選択してください。選択内容が保存され、以降のすべてのコマンドに使用されます。 + +```bash +agenteye login --org acme # 認証とアクティブテナントの設定を一度に行う +agenteye orgs list # アクセス可能な組織の一覧(アクティブな組織にマーク付き) +agenteye orgs switch globex # 保存されたデフォルトを変更 +agenteye --org globex sessions # 単一コマンドのみ上書き +``` + +1つの組織にのみ所属している場合は自動的に選択されるため、`--org` は不要です。複数の組織に所属していて選択しない場合、CLIが一覧を表示して `--org ` で再実行するよう求めます。アクティブな組織はすべてのリクエストでダッシュボードに送信され、権限は**組織ごと**に解決されます。`agenteye whoami` はアクティブな組織、その中での権限、およびすべてのメンバーシップを表示します。 + +--- + +## 設定 + +| 設定 | フラグ | 環境変数 | デフォルト | +|---|---|---|---| +| ダッシュボードのベースURL | `--base-url` | `AGENTEYE_DASHBOARD_URL` | **必須**(デフォルトなし) | +| アクティブな組織/テナント | `--org` | `AGENTEYE_ORG` | ログイン時に選択、`~/.agenteye/cli.json` に保存 | +| セッショントークン | `--token` | `AGENTEYE_CLI_TOKEN` | `~/.agenteye/cli.json` から読み込み | +| JSON出力 | `--json` | `AGENTEYE_CLI_JSON` | オフ | +| TLS検証のスキップ | `--insecure` / `--secure` | `AGENTEYE_INSECURE` | オフ(ログイン時に保存) | +| リクエストタイムアウト(秒) | `--timeout` | — | 30 | +| 利用状況テレメトリーの無効化 | _(なし)_ | `AGENTEYE_ANALYTICS_DISABLED`(または `DO_NOT_TRACK`) | オフ(テレメトリー有効) | + +解決順序は **フラグ → 環境変数 → 設定ファイル** です。デフォルト値はありません。CLIをダッシュボードに向ける必要があります。コマンドごとに指定する(`--base-url https://agenteye.example.com`)か、環境変数で一度設定してください(最初の `login` 後にも保存されます)。 + +```bash +export AGENTEYE_DASHBOARD_URL=https://agenteye.example.com +``` + +設定ディレクトリは `AGENTEYE_HOME` を優先します(SDKおよびコレクターと同じ規約)。設定されている場合、`cli.json` は `$AGENTEYE_HOME/cli.json` に配置されます。 + +### 自己署名または内部TLS + +ダッシュボードが自己署名または内部証明書(例:ロードバランサーの生のホスト名)を使用したHTTPSで提供されている場合、TLS検証は `CERTIFICATE_VERIFY_FAILED` エラーで拒否されます。証明書検証をスキップするには `--insecure` を使用してください。 + +```bash +agenteye --base-url https://agenteye.internal --insecure login +``` + +**`--insecure` はログイン時に `cli.json` に保存される**ため、以降のコマンドは自動的に検証をスキップします。フラグを繰り返す必要はありません。検証付きで一度だけ呼び出すには `--secure` を使用するか、次回ログイン時に検証を有効に戻すために使用してください。検証が無効になっている状態でダッシュボードに接続するコマンドを実行する前に、CLIはstderrに警告を表示します。検証をスキップすると中間者攻撃からの保護が失われます。ダッシュボードへのネットワークパス(VPN、プライベートサブネットなど)を信頼できる場合のみ使用してください。 + +--- + +## テレメトリーとプライバシー + +CLIはExosphereの分析サービス(PostHog)に**匿名の利用状況分析**を送信します。実行されたコマンド(例:`sessions`、`keys create`)、成否、所要時間が含まれます。この利用状況シグナルは、どの機能を優先するかを決定するために使用されます。 + +- **エージェント、セッション、イベントデータはお客様のインフラストラクチャの外に出ることはありません。** 送信されるのはCLIの利用状況のみです。コマンドとサブコマンド名(例:`keys create`)、使用したフラグの**名前**(値は含まれません)、成功/終了ステータス、所要時間、およびミューテーション操作のイベント(例:`api_key_created`、`query_run`)。このイベントには静的な名前/列挙値と大まかなカウントのみが含まれます。ダッシュボードのURL、セッショントークン、メールアドレス、組織スラッグ、リソースID、SQL、キーシークレット、クエリフィルターは**一切送信されません**。オペレーターは不透明な内部IDによってのみ識別され、メールアドレスは使用されません。 +- テレメトリーは**デフォルトで有効**です。無効にするには、CLIの環境変数に `AGENTEYE_ANALYTICS_DISABLED=1` を設定してください(ツール共通の `DO_NOT_TRACK=1` 規約も有効です)。 +- CLIはPostHog(`https://us.i.posthog.com`)に直接送信します。**CLIを実行するマシン**はそのホストへのアウトバウンドアクセスが必要です。ブロックされている場合、テレメトリーは無音で何もしません(送信には時間制限があるため、コマンドの遅延や障害は発生しません)。CLIの動作には影響しません。 + +--- + +## グローバルオプションと規約 + +一度お読みください。すべてのコマンドに適用されます。 + +- **グローバルオプションはコマンドの前に指定します。** `agenteye --json sessions` が正しい形式です。`agenteye sessions --json` は使用エラーです。グローバルオプションは `--json`、`--base-url`、`--org`、`--token`、`--insecure`/`--secure`、`--timeout`、`--quiet`、`--no-color` です。 +- **`--json` は純粋なJSONのみをstdoutに出力します。** 人間向けのステータス行、警告、エラーはすべて**stderr**に出力されるため、ステータス行が表示されていても `--json` のstdoutキャプチャは `jq` にパイプできる状態を保ちます。`--json` なしの場合は、人間が読みやすいボックス形式でカラー表示されます。 +- **`--help` で詳細を確認できます。** すべてのコマンドとサブコマンドには `--help`(および `-h` エイリアス)があります:`agenteye -h`、`agenteye sessions -h`、`agenteye keys create -h`。トップレベルのヘルプには終了コードとグローバルオプションも記載されています。グローバルなマシン可読サーフェスダンプはありません。コマンドごとの `--help` と、2つのレジストリ専用の `agenteye query schema`、`agenteye settings schema` を使用してください。 +- **スクリプトとエージェントでは確認プロンプトが自動スキップされます。** 作成/更新/削除コマンドはインタラクティブなターミナルで確認を求めますが、**`--json` フラグが指定されている場合やstdinがTTYでない場合は自動スキップ**されるため、スクリプトやエージェントがハングすることはありません。明示的にスキップするには `--yes`/`-y` を使用してください。エージェントでプロンプトは表示されないため、エージェントは破壊的な操作を行う前に人間に確認を取るべきです。 +- **ページネーション:** 結果は新しい順にカーソルページネーションされます。`--limit N`(エイリアス `-n`)は行数を制限し、**デフォルトは50**です。`--all` は自動ページネーション(200行ずつ)を行いますが、**`--limit` まで**で停止します。つまり、`--all` 単独でも50件で止まります。完全な取得には高い上限を明示的に指定してください:`--all --limit 1000`。`--page-size N` はリクエストごとのチャンクを制御します(最大200)。`--cursor ` は前のページの `next_cursor` から再開します。 +- **時間フィルター:** `--since` は相対的なウィンドウを受け取ります — `15m`、`1h`、`6h`、`24h`、`7d`、`30d`、または `all`(ダッシュボードのプリセット)。`--from`/`--to` はカスタム範囲用に明示的なISO-8601 UTCタイムスタンプ(`T` とタイムゾーン付き、例:`2026-06-01T00:00:00Z`)を受け取り、`--since` を上書きします。スペース区切りやタイムゾーンなしの値は使用エラーになります。 +- **`--fields a,b,c`**(`events`、`sessions`、`evals`、`errors` で使用可能)は出力をそれらのキーに制限します。テーブルと `--json` の両方に適用されます。不明なフィールド名は有効なリストとともにエラーとして拒否されます。フィールド名を調べる簡単な方法として活用できます。 +- **`--file payload.json`**(または `--file -` でstdinから読み込み)は、リソースが複雑な形状を持つ場合にJSON形式のリクエストボディ全体を提供します。`alerts create/update`、`settings set`、`users create/update` で使用できます。保存済みクエリのSQLには `--sql @file.sql` を使用します。 +- **複数値フィルター**はカンマ区切りで、集合として照合されます(同一フィルター内ではOR、フィルター間ではAND):`--event-type tool_use,tool_result`。Clickオプションは可変長ではないため、`--add a b` は機能しません。`--add a,b`、フラグの繰り返し(`--add a --add b`)、またはクォート(`--add "a b"`)を使用してください。 + +--- + +## コマンドリファレンス + +CLIには**18のトップレベルコマンド**があります。すべての読み取りコマンドは `--json` とグローバルオプションに対応しています。詳細なフラグリストや任意のコマンドのJSON形式については `agenteye -h`(または ` -h`)を実行してください。 + +### Identity — `login` · `logout` · `whoami` · `orgs` · `version` · `help` + +```bash +agenteye login --email you@example.com [--org acme] # メールのワンタイムコード;セッションを保存 +agenteye logout # このマシンの保存されたセッションをクリア +agenteye whoami # 現在のユーザー、アクティブな組織、権限 +agenteye version # CLIバージョンを表示(--version と同じ) +agenteye help # トップレベルのヘルプ(--help と同じ) +``` + +`orgs` はアクティブなテナントの確認と切り替えを行います。 + +```bash +agenteye orgs list # 所属する組織 + 各組織のロール(アクティブな組織にマーク付き) +agenteye orgs switch acme # 保存されたアクティブ組織を変更(スラッグ省略でTTY上のリストから選択) +agenteye orgs current # アクティブな組織の情報カード +agenteye orgs perms # アクティブな組織でのあなたの権限(リソース別にグループ化) +``` + +### 観察(読み取り専用) — `events` · `sessions` · `evals` · `errors` · `list` + +これらはいずれも確認を必要としません。共有フィルター:`--session-id`、`--agent-id`、`--env`(**`--environment` ではありません**)、および時間範囲(`--since` / `--from` / `--to`)。 + +```bash +# events(エイリアス:ステップごとの生のトレイル)— 新しい順 +agenteye --json events --session-id run-001 --event-type tool_use,tool_result --all --limit 1000 +agenteye --json events --since 1h --search timeout --all | jq '.events[].payload' + +# sessions — エージェント実行ごとの1行(時刻/env/エージェント/セッション/ステータス;スコアフィルターなし) +agenteye --json sessions --since 24h --status error +agenteye --json sessions --agent-id checkout-bot --env prod --all --limit 1000 + +# evals — 評価結果 + スコア;--score はメトリクスでフィルター、--aggregate は集計 +agenteye --json evals --score helpfulness:0.5..0.8 --score tool_efficiency:..0.3 +agenteye --json evals --aggregate --since 7d --env prod # ステータス内訳 + キーごとのスコア統計 + +# errors — エラーが発生したイベント;--aggregate はカウント/セッション/エージェント/最終確認時刻を表示 +agenteye --json errors --since 24h --aggregate +agenteye --json errors --since 24h --error-type timeout --all --limit 1000 + +# list — フィルタリングの前に有効なフィルター値を確認 +agenteye list envs # 他にも:agents event_types score_filters models hooks triggers tools error_types +``` + +`--score KEY:MIN..MAX`(**`evals`** のみ、`sessions` では使用不可)は繰り返し指定可能でAND結合されます。どちらの境界も省略可能(`..0.5` は ≤ 0.5、`0.9..` は ≥ 0.9)。リクエストあたり最大20のスコアフィルター。`evals --scores-full` はサマリーではなく完全なスコアオブジェクトを返します。**1つのセッション全体を読む**には、イベントトレイルと評価を組み合わせます。 + +```bash +agenteye --json events --session-id run-001 --all --limit 1000 | jq '.events[] | {ts, event_type}' +agenteye --json evals --session-id run-001 # スコア + ステータス +``` + +### 管理(権限が必要) — `keys` · `users` · `settings` · `alerts` · `incidents` + +**`keys`** — APIキー。シークレットはローカルで生成されてサーバーに送信され(サーバーはハッシュのみを保存)、作成/再生成時に**一度だけ**表示されます。その場でキャプチャしてください。`--json` の場合は `key` フィールドにのみ表示されます。**名前**で参照します。 + +```bash +agenteye keys list # アクティブなキーを先頭に、無効化済みキーを後に表示 +agenteye keys show ci-bot +agenteye keys create ci-bot --add events:read.add # 必要なスコープに限定;シークレットは1度だけ表示 +agenteye keys create ops --permission-set standard --remove queries:run # プリセットをベースに調整 +agenteye keys update ci-bot --add evaluations:read --yes +agenteye keys regenerate ci-bot --yes # シークレットをローテーション(古いものは無効化) +agenteye keys disable ci-bot --yes # 無効化 +``` + +権限は `(permission-set ∪ --add) − --remove` として機能します。トークンは `slug:action`(例:`events:read`)または `slug:action.action`(1つのリソースで複数のアクションを展開、例:`events:read.add` → `events:read`、`events:add`)の形式です。プリセット:`read-only`、`standard`、`admin`。人間のみの権限(`keys:update`)はキーに付与できません。 + +**`users`** — 組織メンバー。**メールアドレス**(UUIDのidも使用可能)で参照します。 + +```bash +agenteye users list [--active-only] +agenteye users show dev@corp.com +agenteye users create dev@corp.com --permission-set standard +agenteye users update dev@corp.com --add alerts:write --remove queries:delete # 変更内容を確認して実行 +agenteye users disable dev@corp.com --yes # 保護/自己制約ガードあり +agenteye users enable dev@corp.com +``` + +**`settings`** — 固定レジストリです(既存のキーの読み取りと変更のみ可能、新規作成は不可)。 + +```bash +agenteye settings list # キー・値・型・更新日時(シークレットはマスク) +agenteye settings schema # 各キーが受け付ける値(型・範囲・説明) +agenteye settings set session_ttl_secs --value 86400 --yes +``` + +**`alerts`** — アラート定義。**名前**で参照します。`create` は位置引数のNAMEとフラグ、または `--file` でJSON形式のボディを受け取ります。 + +```bash +agenteye alerts list +agenteye alerts show high-errors +agenteye alerts create high-errors --file alert.json # NAME は必須(位置引数) +agenteye alerts update high-errors --severity critical --yes +agenteye alerts test high-errors --yes # テスト通知を送信 +agenteye alerts delete high-errors --yes +``` + +**`incidents`** — アラートインシデント。idで参照します(短いidも使用可能)。`show` は完全なアクティビティログを表示します。操作前に必ず確認してください。 + +```bash +agenteye incidents list --state firing # 他にも:acknowledged、resolved +agenteye incidents count +agenteye incidents show +agenteye incidents ack +agenteye incidents assign you@corp.com # 担当者はオペレーターである必要があります +agenteye incidents resolve --yes +agenteye incidents open --alert-id --severity critical # アラートに対して手動で作成 +agenteye incidents comment-add "root cause: upstream 5xx" +agenteye incidents comment-list ; agenteye incidents comment-delete +agenteye incidents subscribe ; agenteye incidents unsubscribe ; agenteye incidents subscribers +``` + +### 分析とアシスタント — `query` · `agent` + +**`query`** — 保存済みClickHouse SQLとアドホック実行ツール。保存済みクエリは**名前**で参照します。SQLはサーバー側で検証されます(SELECT/WITHのみ、ステートメントタイムアウト、行数上限あり)。 + +```bash +agenteye query schema [TABLE] # アナリティクスビューのカラム構造 +agenteye query run --sql "select count(*) from analytics.events" +agenteye query run errs --arg prod --limit 100 # 保存済みクエリを実行 + 位置引数 $1 +agenteye query list ; agenteye query show errs +agenteye query create errs --sql @errs.sql --description "errored events (24h)" +agenteye query update errs --sql @errs.sql --yes ; agenteye query delete errs --yes +``` + +**`agent`** — ダッシュボード組み込みのアシスタント(ダッシュボードでチャットできる読み取り専用のアナリストと同じ)。チャットは短いchat-id(プレフィックス解決あり)で参照します。 + +```bash +agenteye agent health # アシスタントの設定/到達可否を確認 +agenteye agent models # --model に渡せるモデル一覧(デフォルトにマーク付き) +agenteye agent ask "which agents errored most in the last day?" # チャットを開始;短いidを表示 +agenteye agent ask --chat "and which tools did they call?" # チャットを継続 +agenteye agent chats ; agenteye agent show +agenteye agent rename --title "error triage" ; agenteye agent delete +``` + +--- + +## 終了コード + +| コード | 意味 | +|---|---| +| 0 | 成功 | +| 1 | 予期しないエラー(例:ダッシュボードが5xxを返した) | +| 2 | 使用エラー(無効な引数、不明なコマンド/フラグ、名前の競合) | +| 3 | ダッシュボードに到達できない | +| 4 | ログインしていないかセッションが期限切れ;`agenteye login` を実行してください | +| 5 | 認証済みだが、アカウントに必要な権限がない(メッセージに権限名が表示されます) | +| 6 | 指定されたリソースが見つからない(例:不明なセッションIDまたはインシデントID) | + +これらの終了コードによりCLIはスクリプト内で安全に使用できます。コーディングエージェントは `4` を受け取って再認証を促したり、`5` で不足している権限を通知したりできます。終了コードの処理パターンとJSON出力の形式については、[エージェント向けCLIレシピ](/ja/agenteye/cli-recipes) を参照してください。 + +--- + +## 参考情報 + +- **[エージェント向けCLIレシピ](/ja/agenteye/cli-recipes)** — コピーして使えるクエリパターン、`jq` ワンライナー、`--fields` プロジェクション、終了コード処理、JSON出力形式。CLIを操作するコーディングエージェント向けに書かれています。 +- **[AgentEye CLI skill](/ja/agenteye/cli-skill)** — このCLIをインストール可能な Claude Code / Codex *スキル*としてパッケージ化し、コーディングエージェントが平易な英語のリクエストでAgentEyeを操作できるようにします。 +- **[APIキー](/ja/agenteye/api-keys)** — `keys create --add …` の背後にある権限モデル。 +- **[AIアシスタント](/ja/agenteye/assistant)** — `agent ask` が使用するアシスタントの有効化方法。 \ No newline at end of file diff --git a/docs/ja/agenteye/collector-installation.mdx b/docs/ja/agenteye/collector-installation.mdx new file mode 100644 index 00000000..01b46d3a --- /dev/null +++ b/docs/ja/agenteye/collector-installation.mdx @@ -0,0 +1,401 @@ +--- +title: "コレクターのインストール" +description: "AgentEye コレクターのインストールに関するドキュメントです。" +--- + + +`agenteye-collector` デーモンは、エージェントのテレメトリーをアプリケーションをブロックすることなく AgentEye へ確実に届けます。コードはローカルディレクトリにイベントを書き込んで次の処理へ進むだけで、あとはコレクターが引き受けます。各ファイルはミリ秒単位でアップロードされ、再起動・ネットワーク障害・一時的なサーバーエラーにも対応できます。アップロードに失敗した場合はエクスポネンシャルバックオフで再試行され、定期的なリカバリースイープによってクラッシュやデプロイで取り残されたファイルも再キューに追加されます。その結果、耐久性の高い「送りっぱなし」配信が実現します。エージェントはフルスピードで動き続け、コレクターがイベントの取りこぼしをなくします。 + +仕組みとしては、コレクターは `$AGENTEYE_HOME/events/`(デフォルト: `~/.agenteye/events/`)を監視する軽量デーモンで、Python SDK が書き込んだ `.jsonl` ファイルを AgentEye サーバーへアップロードします。 + +> **名称変更:** コレクターコマンドは **`agenteye-collector`** に変更されました(旧名称は `agenteye`)。短縮形の `agenteye` は AgentEye CLI に割り当てられました。既存のインストールからアップグレードする場合は [enterprise-docs/collector-migration.md](/ja/agenteye/collector-migration) を参照してください。 + +--- + +## 前提条件 + +- `AGENTEYE_TOKEN`: 自分で生成する GitHub PAT([enterprise-docs/github-token.md](/ja/agenteye/github-token) 参照) +- サーバー URL およびコレクター API キー([enterprise-docs/api-keys.md](/ja/agenteye/api-keys) 参照) + +--- + +## オプション A: バイナリ(推奨) + +Linux・macOS・Windows(x86_64 および arm64)向けのビルド済み静的バイナリが利用できます。最新の `collector/v` リリースタグ配下の `agenteye-enterprise/releases` リポジトリから、お使いのプラットフォームに対応するバイナリを直接ダウンロードしてください。 + +利用可能なアーティファクト名: + +| プラットフォーム | アーティファクト | +|---|---| +| Linux x86_64 | `agenteye-collector-linux-x86_64` | +| Linux arm64 | `agenteye-collector-linux-arm64` | +| macOS x86_64 | `agenteye-collector-darwin-x86_64` | +| macOS arm64 | `agenteye-collector-darwin-arm64` | +| Windows x86_64 | `agenteye-collector-windows-x86_64.exe` | +| Windows arm64 | `agenteye-collector-windows-arm64.exe` | + +**`gh` CLI でダウンロード**(バージョンを置き換え、プラットフォームに合わせてアーティファクトを選択): + +```bash +VERSION=0.0.1-beta.13 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "collector/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-collector-linux-x86_64' + +chmod +x agenteye-collector-linux-x86_64 +sudo mv agenteye-collector-linux-x86_64 /usr/local/bin/agenteye-collector +``` + +**`curl` を使う場合:** + +```bash +VERSION=0.0.1-beta.13 +ARTIFACT=agenteye-collector-linux-x86_64 +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + -L "https://github.com/agenteye-enterprise/releases/releases/download/collector%2Fv${VERSION}/${ARTIFACT}" \ + -o agenteye-collector +chmod +x agenteye-collector +sudo mv agenteye-collector /usr/local/bin/agenteye-collector +``` + +--- + +## オプション B: Docker + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +docker pull ghcr.io/agenteye-enterprise/collector:beta-latest +``` + +> 現在のベータビルドはフローティングタグ `:beta-latest` で公開されています。`:latest` は安定版リリースにのみ付与されます。再現性のあるデプロイには `:v0.0.1-beta.13` のようなピン留めされたバージョンタグを推奨します。 + +**実行:** + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-collector \ + -e AGENTEYE_URL=https://ingest.example.com/events \ + -e AGENTEYE_KEY="$AGENTEYE_KEY" \ + -e AGENTEYE_HOME=/data \ + -v "$HOME/.agenteye:/data" \ + ghcr.io/agenteye-enterprise/collector:beta-latest \ + start +``` + +公式イメージは非 root ユーザーで動作するため、`AGENTEYE_HOME` を明示的に設定し、ホストのスプールをマウントしてください。ボリュームマウントにより、ホスト上の Python SDK が書き込む `~/.agenteye/` ディレクトリを共有します。ホスト上で `AGENTEYE_HOME` を別の場所に設定済みの場合は、`$HOME/.agenteye` の代わりにそのディレクトリをマウントしてください。 + +--- + +## 設定 + +すべてのオプションは次の 3 通りの方法で設定できます(優先度の高い順): + +1. CLI フラグ: `agenteye-collector start --url https://...` +2. 環境変数: `AGENTEYE_URL=https://...` +3. 設定ファイル: `~/.agenteye/config.json` + +### 必須オプション + +| オプション | CLI フラグ | 環境変数 | config.json キー | +|---|---|---|---| +| バックエンド URL | `--url ` | `AGENTEYE_URL` | `"url"` | +| API キー | `--key ` | `AGENTEYE_KEY` | `"key"` | + +### 任意オプション(デフォルト値あり) + +| オプション | CLI フラグ | 環境変数 | config.json キー | デフォルト | +|---|---|---|---|---| +| 最大同時アップロード数 | `--max-concurrent-uploads ` | `AGENTEYE_MAX_CONCURRENT_UPLOADS` | `"max_concurrent_uploads"` | `64` | +| スイーパー間隔(秒) | `--sweep-interval ` | `AGENTEYE_SWEEP_INTERVAL` | `"sweep_interval_secs"` | `60` | +| スイーパー最小ファイル経過時間(秒) | `--sweep-min-age ` | `AGENTEYE_SWEEP_MIN_AGE` | `"sweep_min_age_secs"` | `120` | +| スイープあたりの最大ファイル数 | `--sweep-max-files ` | `AGENTEYE_SWEEP_MAX_FILES` | `"sweep_max_files"` | `64` | +| 最大アップロード試行回数 | `--max-retries ` | `AGENTEYE_MAX_RETRIES` | `"max_retries"` | `5` | +| リトライ基本遅延(ミリ秒) | `--retry-base-delay ` | `AGENTEYE_RETRY_BASE_DELAY` | `"retry_base_delay_ms"` | `1000` | + +### mTLS オプション(任意) + +相互 TLS(mTLS)が必要なデプロイ環境では、TLS ハンドシェイク時にクライアント証明書を提示するようコレクターを設定できます。これらのオプションが設定されていない場合、コレクターは標準的な HTTPS を使用します。 + +| オプション | CLI フラグ | 環境変数 | config.json キー | +|---|---|---|---| +| クライアント証明書(PEM) | `--tls-cert ` | `AGENTEYE_TLS_CERT` | `"tls_cert"` | +| クライアント秘密鍵(PEM) | `--tls-key ` | `AGENTEYE_TLS_KEY` | `"tls_key"` | +| カスタム CA 証明書(PEM) | `--tls-ca ` | `AGENTEYE_TLS_CA` | `"tls_ca"` | + +`--tls-cert` と `--tls-key` はセットで設定する必要があります。ファイルは PEM エンコード形式である必要があります。 + +`--tls-ca` は独立したオプションで、AgentEye サーバーが公的に信頼された CA から発行されていない TLS 証明書(例: 正規の DNS ドメインを持たない場合にクラスター内の `cert-manager` 発行者が自己署名した証明書)を提示する場合にのみ必要です。コレクターは指定された CA を追加の信頼アンカーとして加えます。標準の公的ルートは引き続き信頼されるため、既存のデプロイには影響しません。ファイルは単一の PEM 証明書でも、フルチェーン(複数の PEM ブロックを連結したもの)でも構いません。 + +**アプリケーション Pod 内でコレクターをサイドカーとして動かす場合は**、エンドツーエンドの EKS パターン(AWS Secrets Manager + Secrets Store CSI Driver + IRSA で配信される mTLS バンドルと自動ローテーション)について [enterprise-docs/single-pod-deployment.md](/ja/agenteye/single-pod-deployment) を参照してください。 + +Secret ハンドオフパターンで Kubernetes 上で動かす場合は、証明書の Secret をボリュームとしてマウントし、これらのパスをマウントされたファイルへ向けてください: + +```yaml +# 例: コレクター Deployment のスニペット +volumes: + - name: mtls-certs + secret: + secretName: agenteye-collector-mtls +containers: + - name: collector + env: + - name: AGENTEYE_TLS_CERT + value: /etc/agenteye/tls/tls.crt + - name: AGENTEYE_TLS_KEY + value: /etc/agenteye/tls/tls.key + # サーバー証明書が公的に信頼されていない場合のみ(例: クラスター内の + # 自己署名 CA)。同じ Secret に tls.crt/tls.key と並んで + # ca.crt が含まれている場合が多い。 + - name: AGENTEYE_TLS_CA + value: /etc/agenteye/tls/ca.crt + volumeMounts: + - name: mtls-certs + mountPath: /etc/agenteye/tls + readOnly: true +``` + +### `~/.agenteye/config.json` の設定例 + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "max_concurrent_uploads": 16, + "sweep_interval_secs": 30 +} +``` + +mTLS を使用する場合: + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "tls_cert": "/etc/agenteye/tls/tls.crt", + "tls_key": "/etc/agenteye/tls/tls.key" +} +``` + +mTLS にカスタム CA(自己署名の AgentEye サーバー)を加える場合: + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "tls_cert": "/etc/agenteye/tls/tls.crt", + "tls_key": "/etc/agenteye/tls/tls.key", + "tls_ca": "/etc/agenteye/tls/ca.crt" +} +``` + +`AGENTEYE_HOME` が設定されている場合は、`~/.agenteye` の代わりにそのディレクトリが使用されます。 + +--- + +## 初回セットアップ + +インストール後、サーバー URL と API キーでコレクターを設定します: + +```bash +mkdir -p ~/.agenteye +cat > ~/.agenteye/config.json <<'EOF' +{ + "url": "https://ingest.example.com/events", + "key": "YOUR_COLLECTOR_KEY" +} +EOF +``` + +> 信頼できないネットワークをまたぐデプロイでは必ず `https` を使用し、イベントが平文で送信されないようにしてください。`http://your-server-host:8080/events` のような平文形式は、同一ホスト上のサーバーに対するローカルテストのみに適しています。 + +**接続テスト**(ワンショットフラッシュ: 保留中のイベントを排出して終了): + +```bash +agenteye-collector flush +``` + +`flush` は進捗を stdout に出力します。スプールが空の場合は `No pending files.` と表示して終了コード `0` で終了します。それ以外の場合はファイルごとに 1 行(`[UPLOADED] ` または `[FAILED] ()`)出力し、最後に `Done: / uploaded, failed.` というサマリーを表示します。これにより `flush` は、デーモンを起動する前に URL・キー・TLS 設定が正しいかを確認するための便利なワンショットチェックとして使用できます。 + +--- + +## デーモンとして実行する + +### 直接実行 + +```bash +agenteye-collector start +``` + +### コンテナ / Docker + +コレクターとアプリケーションが同じコンテナを共有する場合は、プロセススーパーバイザー配下で実行してください。最もシンプルな選択肢は `supervisord` です。主要なディストリビューションにはすべて同梱されており、クラッシュしたプロセスの再起動・シグナルの転送・グレースフルシャットダウン待機に対応しています。 + +**`Dockerfile`:** + +```Dockerfile +FROM python:3.11-slim + +RUN apt-get update && apt-get install -y --no-install-recommends supervisor \ + && rm -rf /var/lib/apt/lists/* + +# 公式イメージから agenteye-collector バイナリを取得する。 +# 特定のタグをピン留めすること(現在のベータは :beta-latest、または :v タグ)。 +# :latest は安定版リリース時のみ公開される。 +COPY --from=ghcr.io/agenteye-enterprise/collector:beta-latest \ + /usr/local/bin/agenteye-collector /usr/local/bin/agenteye-collector + +COPY supervisord.conf /etc/supervisor/conf.d/agenteye.conf +COPY my_agent.py /app/my_agent.py + +CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"] +``` + +**`supervisord.conf`:** + +```ini +[supervisord] +nodaemon=true +user=root + +[program:agenteye-collector] +command=/usr/local/bin/agenteye-collector start +autorestart=true +stopwaitsecs=30 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:app] +command=python /app/my_agent.py +autorestart=unexpected +stopwaitsecs=30 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +``` + +各設定の意図: + +- agenteye-collector の `autorestart=true`: クラッシュ・パニック・OOM など、いかなる終了でも再起動する。 +- アプリの `autorestart=unexpected`: ゼロ以外の終了コードのときのみ再起動する。これにより、終了コード 0 で終了するワンショットエージェントがループしない。 +- `stopwaitsecs=30`: supervisord が SIGKILL にエスカレートする前に、コレクターが保留中のアップロードを排出する時間を確保する。 +- `stdout_logfile=/dev/stdout`、`*_maxbytes=0`: 両プログラムの出力をコンテナの stdout にストリーミングし、コンテナ内にログファイルを作成しない。 + +`AGENTEYE_URL` / `AGENTEYE_KEY`(および TLS 関連の環境変数)は従来どおり `docker run -e` で渡してください。supervisord は環境変数を継承します。 + +> **コンテナを分けて実行する場合**、コレクターを独自のコンテナ(Docker Compose サービス・Kubernetes サイドカーなど)として動かす場合は supervisord は不要です。コンテナランタイムの再起動ポリシーがその役割を担います。EKS サイドカーパターンについては [enterprise-docs/single-pod-deployment.md](/ja/agenteye/single-pod-deployment) を参照してください。 + +**Kubernetes liveness probe**(コレクターが単独で動いているか supervisord 配下かを問わず適用): + +```yaml +livenessProbe: + exec: + command: ["agenteye-collector", "health"] + initialDelaySeconds: 10 + periodSeconds: 30 +``` + +実行中のデーモンは 30 秒ごとに `$AGENTEYE_HOME/health.json` にハートビートを書き込みます。`agenteye-collector health` はそのファイルを読み取り、ハートビートが新鮮でアップロードタスクが正常に動作している場合のみ終了コード `0`(正常)で終了します。ハートビートが 90 秒より古い場合(デーモンが停止している場合など)や、予期しない終了後にウォッチャーとスイーパーが再起動中の場合は終了コード `1`(異常)で終了します。ハートビートは `start` によってのみ書き込まれるため、ワンショットの `flush` コマンドではなく、長期稼働デーモンに対してプローブを実行してください。 + +### systemd(Linux、本番環境推奨) + +```ini +# /etc/systemd/system/agenteye-collector.service +[Unit] +Description=AgentEye Collector +After=network.target + +[Service] +ExecStart=/usr/local/bin/agenteye-collector start +Restart=on-failure +RestartSec=5 +EnvironmentFile=/etc/agenteye/env + +[Install] +WantedBy=multi-user.target +``` + +`/etc/agenteye/env` を作成: + +``` +AGENTEYE_URL=https://ingest.example.com/events +AGENTEYE_KEY=YOUR_COLLECTOR_KEY +``` + +```bash +sudo systemctl daemon-reload +sudo systemctl enable --now agenteye-collector +sudo systemctl status agenteye-collector +``` + +### launchd(macOS) + +```xml + + + + + + Label + ai.befailproof.agenteye-collector + ProgramArguments + + /usr/local/bin/agenteye-collector + start + + EnvironmentVariables + + AGENTEYE_URL + https://ingest.example.com/events + AGENTEYE_KEY + YOUR_COLLECTOR_KEY + + RunAtLoad + + KeepAlive + + + +``` + +```bash +launchctl load ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +``` + +--- + +## コレクターのアップグレード + +コレクターは自動更新されません。アップグレードするには: + +- **バイナリ:** 最新の `collector/v` リリースから新しい `agenteye-collector--` アーティファクトをダウンロードし([オプション A](#option-a-binary-recommended) 参照)、`/usr/local/bin/agenteye-collector` を置き換えてからサービスを再起動してください(`sudo systemctl restart agenteye-collector`、`launchctl load` の再実行、またはスーパーバイザーの再起動)。 +- **Docker:** `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest`(またはピン留めされた `:v` タグ。`:latest` は安定版リリースにのみ存在します)を実行し、コンテナを再作成してください。 + +`AGENTEYE_TOKEN` はプライベートリリースリポジトリから新しいバイナリやイメージをダウンロードするために必要ですが、実行中のデーモンには**不要**です。 + +--- + +## サブコマンド + +| コマンド | 説明 | +|---|---| +| `agenteye-collector start` | 長期稼働デーモンを起動する。起動時に前回の実行で残ったイベントをフラッシュし、その後新しいファイルを監視してアップロードする。ウォッチャーとスイーパーは予期しない終了後に自動再起動し、30 秒ごとに `health.json` にハートビートが書き込まれる。 | +| `agenteye-collector flush` | ワンショット: 保留中のすべてのファイルをアップロードして終了する。スプールが空の場合は `No pending files.` を表示し、それ以外はファイルごとに `[UPLOADED]`/`[FAILED]` ログと `Done: / uploaded, failed.` サマリーを表示する。 | +| `agenteye-collector health` | デーモンの `health.json` ハートビートを読み取る。新鮮で正常な場合は終了コード `0`、ハートビートが古い(90 秒超)またはタスクが再起動中の場合は終了コード `1` で終了する。 | + +--- + +## ディレクトリ構成 + +``` +~/.agenteye/ +├── config.json <- 任意の設定ファイル +├── events/ <- SDK が書き込む .jsonl ファイル。コレクターが取得する +└── failed/ <- すべてのアップロード試行が失敗したファイル +``` + +`failed/` 内のファイルは自動的に再試行されません。手動で再キューに追加するには、`events/` に移動して `agenteye-collector flush` を実行してください。 \ No newline at end of file diff --git a/docs/ja/agenteye/collector-migration.mdx b/docs/ja/agenteye/collector-migration.mdx new file mode 100644 index 00000000..bc97b310 --- /dev/null +++ b/docs/ja/agenteye/collector-migration.mdx @@ -0,0 +1,167 @@ +--- +title: "`agenteye-collector` への移行" +description: "AgentEye の `agenteye-collector` への移行に関するドキュメント。" +--- + +移行は非破壊的です。ダウンタイムもデータ損失も発生せず、短い `agenteye` という名前を [AgentEye CLI](/ja/agenteye/cli) のために解放することで、コレクターデーモンと CLI を同一マシン上で共存させることができます。 + +コレクターのバイナリは **`agenteye` から `agenteye-collector` に改名されました**。短い `agenteye` という名前は、ターミナルからセッション、イベント、評価を照会するための別ツールである AgentEye CLI のものになりました。 + +このガイドでは、既存のコレクターインストールを移行する手順を説明します。 + +--- + +## 変更点 + +| | 変更前 | 変更後 | +|---|---|---| +| コマンド/バイナリ | `agenteye` | `agenteye-collector` | +| デフォルトのインストールパス | `/usr/local/bin/agenteye` | `/usr/local/bin/agenteye-collector` | +| サブコマンド | `start`, `flush`, `health`, `update` | `start`, `flush`, `health` | +| 自己更新(`agenteye update`) | 組み込み | **削除**:新しいバイナリをダウンロードするか、新しいイメージを pull してください | +| インストールスクリプト(`install.sh`) | 提供あり | **削除**:バイナリを直接ダウンロードしてください([コレクターのインストール](/ja/agenteye/collector-installation)を参照) | +| `AGENTEYE_TOKEN` | バイナリの**ダウンロード**およびバックグラウンドの更新チェックに必要 | バイナリ/イメージの**ダウンロード**のみに必要 | + +設定は変更なしです。同じ `~/.agenteye/config.json`、同じ `AGENTEYE_URL` / `AGENTEYE_KEY` / `AGENTEYE_HOME` / TLS 環境変数、そして同じ `~/.agenteye/events/` スプールが使われます。**設定ファイルの編集は不要です。** + +> 改名されたバイナリを古い名前 `agenteye` で実行した場合も動作しますが、`agenteye-collector` への切り替えを促す 1 行の非推奨警告が stderr に表示されます。 + +--- + +## 開始前に + +- **既存の `agenteye` のインストールはそのまま動き続けます**。アップグレードした瞬間に何かが壊れることはありません。計画的に移行を行い、古いバイナリの削除は最後に行ってください。 +- ダウンタイムを避けるために、以下の順序で作業してください: + 1. 新しい `agenteye-collector` バイナリをインストール(または新しいイメージを pull)する。 + 2. サービス定義/ヘルスプローブ/スクリプトを `agenteye-collector` を呼び出すように更新する。 + 3. サービスをリロードして再起動し、正常に動作していることを確認する。 + 4. **その後で初めて**、古い `/usr/local/bin/agenteye` バイナリを削除する。 + +--- + +## 1. 新しいバイナリのインストール + +お使いのプラットフォーム向けのアーティファクト(`agenteye-collector-linux-x86_64`、`agenteye-collector-darwin-arm64` など;完全なリストは [コレクターのインストール → オプション A](/ja/agenteye/collector-installation#option-a-binary-recommended) を参照)を最新の `collector/v` リリースからダウンロードし、`/usr/local/bin/agenteye-collector` に配置してください。Docker をご利用の方は `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest`(または固定された `:v` タグを推奨;`:latest` は安定版リリースにのみ存在します)を実行してください。 + +動作確認: + +```bash +agenteye-collector --version +``` + +--- + +## 2. デプロイメントの更新 + +### systemd(Linux) + +`/etc/systemd/system/agenteye-collector.service` を編集し、`ExecStart` が新しいバイナリを指すようにします: + +```ini +[Service] +ExecStart=/usr/local/bin/agenteye-collector start +``` + +その後、リロードして再起動します: + +```bash +sudo systemctl daemon-reload +sudo systemctl restart agenteye-collector +sudo systemctl status agenteye-collector +``` + +### launchd(macOS) + +> **ブランド名の変更:** 既存の plist が古いパス +> `~/Library/LaunchAgents/host.exosphere.agenteye-collector.plist` にある場合は、 +> ファイルを `ai.befailproof.agenteye-collector.plist` に改名し、 +> ファイル内の `Label` の値も新しい識別子に変更してからリロードしてください。 + +`~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist` 内の最初の `ProgramArguments` エントリを `/usr/local/bin/agenteye` から `/usr/local/bin/agenteye-collector` に変更し、リロードします: + +```bash +launchctl unload ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +launchctl load ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +``` + +### supervisord + +`supervisord` のプログラムブロックで、`command` を新しいバイナリに設定します: + +```ini +[program:agenteye-collector] +command=/usr/local/bin/agenteye-collector start +``` + +その後、`supervisorctl reread && supervisorctl update` を実行します。 + +### Docker / Kubernetes + +新しいイメージを pull します(`ghcr.io/agenteye-enterprise/collector:beta-latest` または固定された `:v` タグを推奨;`:latest` は安定版リリースにのみ存在します)。イメージのエントリポイントはすでに `agenteye-collector` になっているため、`start` サブコマンドを使った同じ `docker run` コマンドが変更なしで動作します。 + +**重要:ヘルスプローブを更新してください。** バイナリ名でコマンドを実行する Kubernetes の liveness/readiness プローブ(または `docker exec`)を使用している場合は、コマンドを `agenteye-collector` に変更してください: + +```yaml +livenessProbe: + exec: + command: ["agenteye-collector", "health"] +``` + +新しいイメージには `agenteye` というエイリアスが含まれていないため、`agenteye` を呼び出し続けるプローブは失敗します。新しいイメージへのロールアウトと同時にプローブを更新してください。 + +### Cron /手動スクリプト + +`agenteye start|flush|health` の呼び出しをすべて対応する `agenteye-collector start|flush|health` コマンドに置き換えてください。**`agenteye update` の cron ジョブはすべて削除してください**。そのサブコマンドはもう存在しません([今後のアップグレード](#upgrades-from-now-on)を参照)。 + +--- + +## 3. 古いバイナリの削除(最後に行う) + +サービスが `agenteye-collector` で動作し、正常であることを確認したら: + +```bash +sudo rm /usr/local/bin/agenteye +``` + +この手順は、AgentEye CLI を併用する場合に特に重要です。AgentEye CLI は独自の `agenteye` コマンドをインストールするため、古いコレクターバイナリが `/usr/local/bin/agenteye` に残っていると、`PATH` 上で `agenteye` という名前が曖昧になります。 + +--- + +## 今後のアップグレード + +コレクターはもはや自己更新を行いません。アップグレードするには: + +- **バイナリ:** お使いのプラットフォーム向けの新しいアーティファクト(例:`agenteye-collector-linux-x86_64`;完全なリストは [コレクターのインストール → オプション A](/ja/agenteye/collector-installation#option-a-binary-recommended) を参照)をダウンロードし、`/usr/local/bin/agenteye-collector` を置き換えて、サービスを再起動してください。 +- **Docker:** `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest`(または固定された `:v` タグを推奨;`:latest` は安定版リリースにのみ存在します)を実行し、コンテナを再作成してください。 + +`AGENTEYE_TOKEN` はプライベートリリースリポジトリからのダウンロードに引き続き必要ですが、実行中のデーモンにはもう必要ありません。 + +--- + +## 動作確認 + +```bash +agenteye-collector --version # 新しいバイナリが PATH 上にある +agenteye-collector health # 終了コード 0 = 正常 +agenteye-collector flush # キューに入ったイベントを転送してクリーンに終了 +``` + +その後、新しいイベントがダッシュボードに表示されることを確認してください。 + +--- + +## ロールバック + +移行は非破壊的です。ロールバックが必要な場合は、サービス定義を古い `/usr/local/bin/agenteye` バイナリに戻し(まだ削除していない場合)、再起動してください。イベントスプールと設定は共有されており、影響を受けません。 + +--- + +## トラブルシューティング + +| 症状 | 原因 | 対処法 | +|---|---|---| +| 実行のたびに `warning: the collector binary is now agenteye-collector …` が表示される | 古い `agenteye` という名前でバイナリを呼び出している | 代わりに `agenteye-collector` を呼び出してください;サービスファイルとスクリプトを更新してください。 | +| systemd が失敗する:`.../agenteye: No such file or directory` | `ExecStart` を更新する前に古いバイナリを削除した | `ExecStart=/usr/local/bin/agenteye-collector start` を設定し、`sudo systemctl daemon-reload` を実行してください。 | +| イメージのアップグレード後に Kubernetes Pod がクラッシュループに陥る | liveness プローブがまだ `agenteye` を実行している | プローブのコマンドを `["agenteye-collector", "health"]` に変更してください。 | +| `agenteye: command not found` が表示されるが `agenteye-collector` は動作する | スクリプト/エイリアスがまだ古い名前を参照している | `agenteye-collector` に更新してください。 | +| `agenteye` を実行するとコレクターではなく CLI が起動する | AgentEye CLI がインストールされており、`agenteye` はその管轄になっている | デーモンには `agenteye-collector` を使用し、`/usr/local/bin/agenteye` に残っている古いコレクターバイナリを削除してください。 | \ No newline at end of file diff --git a/docs/ja/agenteye/deployment.mdx b/docs/ja/agenteye/deployment.mdx new file mode 100644 index 00000000..40e90665 --- /dev/null +++ b/docs/ja/agenteye/deployment.mdx @@ -0,0 +1,415 @@ +--- +title: "デプロイメント" +description: "AgentEye デプロイメントドキュメント。" +--- + + +このガイドでは、AgentEye サーバーとダッシュボードを本番環境にデプロイする方法を説明します。 + +--- + +## アーキテクチャ概要 + +``` + [ AIエージェントマシン ] [ あなたのインフラ ] + + Python SDK + | JSONLを書き込む +----------------------+ + v +--->| PostgreSQL 15+ | + agenteye-collector --HTTP--+ | | (リレーショナルストア) | + | | +----------------------+ + v | + +--------+ | +----------------------+ + | Server |<------+--->| ClickHouse 24+ | + +--------+ | | (イベント / 分析) | + ^ | +----------------------+ + API | | + | | +----------------------+ + +-----------+ +- - >| Redis 7+ (オプション) | + | Dashboard | +----------------------+ + +-----------+ +``` + +- **Server**: Rust 製 HTTP サービス。イベントバッチを受信し、ClickHouse に書き込み、PostgreSQL でリレーショナル状態を管理します。 +- **Dashboard**: Next.js ウェブアプリ。サーバー API 経由でのみ読み書きします。 +- **agenteye-collector**: サーバーホストではなく、エージェントマシンにデプロイします。 +- **Postgres 15+**: **必須**。(マルチテナントリリースで 14 から引き上げ。org-membership スキーマが列リスト `ON DELETE SET NULL` 外部キーを使用しており、これは Postgres 15+ の機能です。このバージョンをデプロイする前に Postgres をアップグレードしてください。)OLTP 状態を保管します: `api_keys`、`users`、`sessions`、`evaluation_jobs`(キュー)、`dashboards`、`saved_queries`、`otp_codes`、およびマルチテナントテーブル `orgs`、`org_memberships`、`org_settings`。 +- **ClickHouse 24+**: **必須**。すべての取り込みイベントの分析ストア。エンジン: `ReplacingMergeTree`、月単位でパーティション分割、`(session_id, ts, dedup_key)` 順。サーバーは `CLICKHOUSE_URL` 経由で接続します。同梱の `deploy/base/clickhouse/` にはパフォーマンスチューニング済みシングルノード設定が含まれています。**マルチテナント要件:** 同梱設定では SQL アクセス管理と `users_without_row_policies_can_read_rows=false` が有効化されており、サーバーが組織ごとに読み取り専用 ClickHouse ユーザーと行ポリシーを作成できます(SQL エディターと AI エージェントのエンジンレベルの分離境界)。独自の ClickHouse 設定を使用する場合は、これらの設定を引き継いでください(`deploy/base/clickhouse/configmap.yaml` 参照)。 +- **Redis 7+**: *オプション*の共有キャッシュ + レート制限バックエンド。サーバーとダッシュボードの両方が `REDIS_URL` 経由で接続します。存在しない場合、どちらも Postgres のみのパスに安全にフォールバックします。後述の **Redis(オプションキャッシュ)** を参照してください。 + +--- + +## サーバー + +### イメージのプル + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +docker pull ghcr.io/agenteye-enterprise/server:beta-latest +``` + +> 現在のビルドは `beta-latest` で公開されています。`latest` は安定版リリースにのみ割り当てられます。本番環境では特定の `:v<バージョン>` タグを固定してください。[利用可能なイメージタグ](#available-image-tags)を参照してください。 + +### 環境変数 + +| 変数 | 必須 | デフォルト | 説明 | +|---|---|---|---| +| `DATABASE_URL` | はい | なし | Postgres DSN。`postgres://` スキームの標準 libpq 接続文字列形式。`?sslmode=require` などの libpq パラメーターをサポートします。パスワードに `/`、`+`、`=` を含めないでください。URL セーフなパスワードの生成には `openssl rand -hex` を使用してください。 | +| `ADMIN_KEY` | いいえ | なし | ブートストラップ管理者 API キー。起動のたびに全権限でアップサートされます。値を変更して再起動することでローテーションできます。 | +| `LISTEN_ADDR` | いいえ | `0.0.0.0:8080` | バインドする TCP アドレス | +| `MAX_BODY_BYTES` | いいえ | `134217728`(128 MB) | リクエストボディの最大サイズ | +| `ADMIN_EMAIL` | いいえ | なし | ブートストラップ管理者ユーザーのメールアドレス。起動のたびに全権限でアップサートされ、保護済みとしてマークされます(ダッシュボード/API から無効化や権限変更が不可)。ブートストラップ管理者をローテーションするには、`ADMIN_EMAIL` を変更して再起動してください。新しいメールアドレスが保護済みとしてアップサートされ、以前のアドレスは手動でデータベースから削除するまで保護が維持されます。 | +| `ALLOWED_EMAILS` | いいえ | なし(すべてブロック) | ユーザー作成およびログインを許可するメールアドレスのカンマ区切りリスト。完全なアドレス(`user@example.com`)とドメインワイルドカード(`*@example.com`)をサポートします。未設定の場合、ユーザーの作成もログインもできません。**初回起動時のシードのみ**: 初回起動時にデフォルト org のアローリストをシードします。それ以降は各 org の [`//settings`](#operational-settings) ページが正式な設定元となり、この環境変数の変更は無効です。 | +| `SMTP_HOST` | いいえ | なし | OTP メール送信用 SMTP サーバーのホスト名。未設定の場合、OTP コードは stdout に記録されます。 | +| `SMTP_PORT` | いいえ | `587` | SMTP サーバーのポート | +| `SMTP_USERNAME` | いいえ | なし | SMTP 認証ユーザー名 | +| `SMTP_PASSWORD` | いいえ | なし | SMTP 認証パスワード | +| `SMTP_FROM` | いいえ | なし | OTP メールの送信者メールアドレス | +| `SMTP_TLS` | いいえ | STARTTLS | 明示的に無効にしない限り STARTTLS が使用されます。`false` または `0` でプレーンテキスト(TLS なし)送信になります。それ以外の値(未設定を含む)では STARTTLS が有効になります。 | +| `DASHBOARD_URL` | いいえ | 組み込みデフォルト | OTP メールのマジックリンクとアラート通知のインシデントマジックリンクの構築に使用するダッシュボードのオリジン。未設定の場合、組み込みデフォルト(OTP のみの場合はダッシュボード由来のリクエストオリジンを優先)にフォールバックします。メールと Slack/インシデントリンクの両方をあなたのダッシュボードに向けるために、ドメインが分かれている場合はこれを設定してください。後述の **Email マジックリンク URL** を参照してください。ほとんどのオペレーターはこの設定は不要です。 | +| `SESSION_TTL_SECS` | いいえ | `86400`(24 時間) | ダッシュボードセッションの有効期間(秒)。**初回起動時のシードのみ**: 初回デプロイ後は [`//settings`](#operational-settings) から org ごとに編集してください。 | +| `OTP_TTL_SECS` | いいえ | `600`(10 分) | OTP コードの有効期間(秒)。**初回起動時のシードのみ**: 初回デプロイ後は [`//settings`](#operational-settings) から org ごとに編集してください。 | +| `REDIS_URL` | いいえ | なし | オプションの共有キャッシュ + レート制限バックエンド(例: `redis://redis:6379/0`)。設定すると、サーバーは認証済み API キーのルックアップ、ダッシュボードの `/models` 集計、セッションリスト、env リストファセットをキャッシュし、OTP リクエストのレート制限を Postgres COUNT から Redis INCR に切り替えます。未設定または接続不可の場合、サーバーはキャッシュなしで動作します(OTP 制限は Postgres にフォールバック、その他のキャッシュ呼び出しはソースオブトゥルースにフォールスルー)。後述の **Redis(オプションキャッシュ)** を参照してください。 | +| `CLICKHOUSE_URL` | **はい** | なし | ClickHouse インスタンスのベース URL(例: `http://clickhouse:8123`)。サーバーは起動のたびにこのデータベースにイベントスキーマを適用し、ClickHouse に到達できない場合は起動を拒否します。後述の **ClickHouse(必須分析ストア)** を参照してください。 | +| `CLICKHOUSE_DATABASE` | いいえ | `agenteye` | ClickHouse データベース(スキーマ)名。存在しない場合、サーバーが起動時に作成します。 | +| `ORG_CH_SECRET` | いいえ(シングルテナント) / **はい(マルチ org)** | 開発用デフォルト | 各組織のテナントごとの ClickHouse パスワードの導出元となる HMAC キー。SQL エディターと AI エージェントの `run_query` は org 専用の読み取り専用 ClickHouse ユーザーとして実行され、行ポリシーがエンジンレベルでテナント分離を強制します。シングルテナントデプロイメントは組み込み開発用デフォルトで正常に起動できますが、**2 番目の org をプロビジョニングする前に強力で安定した値を設定する必要があります**(`agenteye-orgctl org create` CLI は組み込み開発用デフォルトでの実行を拒否します)。ローテーションすると次回起動時の再プロビジョニングまで各 org の ClickHouse ユーザーが孤立します(起動時の調整で自動的に修復されます)。秘密を保持し、レプリカ間で変更しないでください。org プロビジョニング自体はオペレーター専用です。後述の **組織(マルチテナント)** を参照してください。 | +| `DEFAULT_ORG_NAME` | いいえ | `Default` | 組み込みデフォルト org にシードされる表示名。**初回起動時のシードのみ**(org がまだ新規移行後の汎用 ID を持っている間のみ)。org の名前を変更(`agenteye-orgctl org rename`)すると、その名前が正式となり、この環境変数は以降無効です。 | +| `DEFAULT_ORG_SLUG` | いいえ | `default` | 組み込みデフォルト org の URL スラグ(ダッシュボードのパス `//…`)。`DEFAULT_ORG_NAME` と同じ初回起動時のみ / 未変更時のみのセマンティクスです。1〜40 文字の小文字英数字で、単独の内部ハイフンを使用でき、[予約語](#organizations-multi-tenancy)でない必要があります。無効な値は無視されます(org は `default` を維持)。シングルテナントのインストールを、デプロイ後の CLI 手順なしに `/default` の代わりに `/acme` などで表示できます。 | +| `RUST_LOG` | いいえ | `info` | ログの冗長性(`debug`、`warn`、`error`、`agenteye_server=trace`) | +| `EVALUATOR_ENDPOINT` | いいえ | なし | 評価サービスのベース URL(例: `http://evaluator:9000`)。未設定の場合、評価パイプライン全体が no-op になります(キュー行の書き込みなし、ワーカーなし)。[Evaluation Suite](/ja/agenteye/evaluation-suite) を参照してください。 | +| `EVALUATOR_TOKEN` | いいえ | なし | 評価サービスへの `Authorization: Bearer ` として送信されます。**評価サービスに設定されている値と同一である必要があります。** 評価サービスがトークンなしで設定されている場合のみオプションです。 | +| `EVALUATOR_WORKERS` | いいえ | `2` | 並行数: 評価をディスパッチするサーバーインスタンスごとのワーカータスク数。水平スケールされた複数のサーバーで安全に実行できます。 | +| `EVALUATOR_CLAIM_BATCH` | いいえ | `4` | 1 回のティックでシングルワーカーがクレームする評価の最大数。バッチは**並行して**ディスパッチされるため、評価エンドポイントへの総並行数は `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH` になります。 | +| `EVALUATOR_POLL_IDLE_SECS` | いいえ | `2` | 処理待ちがない場合にワーカーがディスパッチ試行間にスリープする時間。 | +| `EVALUATOR_POLLING_INTERVAL_SECS` | いいえ | `10` | 評価サービスがレスポンスごとの `next_poll_secs` を返さず、`GET /config` から `default_poll_interval_secs` もアドバタイズしない場合の `GET /evaluate/{id}` ポーリングの最終フォールバック間隔(秒)。 | +| `EVALUATOR_REQUEST_TIMEOUT_MS` | いいえ | `30000` | 評価サービスへの HTTP リクエストごとのタイムアウト(ミリ秒)。 | +| `EVALUATOR_MAX_ATTEMPTS` | いいえ | `5` | この回数の失敗後、評価は終端的な `error`(失敗がリクエストタイムアウトの場合は `timeout`)として記録されます。 | +| `EVALUATOR_CONFIG_REFRESH_SECS` | いいえ | `300`(5 分) | サーバーが評価サービスから `GET /config` を再フェッチする頻度。 | +| `EVALUATOR_MAX_POLL_DURATION_SECS` | いいえ | `3600`(1 時間) | AgentEye がセッションを `timeout` として終了するまでのポーリングキュー内の最大経過時間。永遠に `pending` を返す評価サービスに対するガード。 | +| `ALERT_WORKERS` | いいえ | `1` | 並行数: アラートルールを評価するサーバーインスタンスごとのワーカータスク数。[Alerts](/ja/agenteye/alerts) を参照してください。 | +| `ALERT_CLAIM_BATCH` | いいえ | `16` | 1 回のティックでシングルワーカーがクレームするアラートの最大数。 | +| `ALERT_POLL_IDLE_SECS` | いいえ | `5` | キューが空のときにアラートワーカーがスリープする時間。 | +| `ALERT_REQUEST_TIMEOUT_MS` | いいえ | `15000` | トリガー評価ごとのタイムアウト(ClickHouse クエリ + アウトバウンドチャンネル HTTP)。 | +| `ALERT_MAX_ATTEMPTS` | いいえ | `5` | 通常のケイデンスへの再スケジュール(指数バックオフの代わり)が行われるまでの連続した一時的失敗回数。 | +| `AUDIT_WORKERS` | いいえ | `1` | 並行数: 監査を実行するサーバーインスタンスごとのワーカータスク数。[Audits](/ja/agenteye/audits) を参照してください。 | +| `AUDIT_CLAIM_BATCH` | いいえ | `1` | 1 回のティックでシングルワーカーがクレームする監査の最大数。エージェント型の調査は 1 つの長いループであるため、デフォルトは 1 です。 | +| `AUDIT_POLL_IDLE_SECS` | いいえ | `30` | 監査が予定されていないときに監査ワーカーがスリープする時間。 | +| `AUDIT_REQUEST_TIMEOUT_MS` | いいえ | `30000` | ClickHouse へのポリシークエリごとのタイムアウト(ミリ秒)。 | +| `AUDIT_LLM_TIMEOUT_MS` | いいえ | `1440000` | AI アシスタントサービスへのエージェント型調査呼び出しのタイムアウト。完全なエージェントループは数分かかるため、サーバーがあきらめる前にエージェントが部分的な調査結果を返せるよう、エージェント自身の `AGENTEYE_AUDIT_TIMEOUT_MS` より**大きく**設定してください。 | +| `AUDIT_MAX_ATTEMPTS` | いいえ | `5` | 通常のケイデンスへの再スケジュール(指数バックオフの代わり)が行われるまでの連続した一時的失敗回数。 | +| `AGENTEYE_AGENT_URL` / `AGENTEYE_AGENT_TOKEN` | いいえ | — | 監査のエージェント型調査は AI アシスタント `agent` サービスを呼び出します。**アシスタントと同じ接続を再利用する**ため、これら 2 つを**サーバー**にも設定してください(同梱のマニフェスト/compose はそうなっています)。両方設定 ⇒ 監査が AI 調査を実行。どちらか未設定 ⇒ 監査は**ポリシーのみ**で実行(決定論的 SQL ポリシーパスは引き続き実行)、監査ごとの `llm_enabled` フラグに関わらず。エージェントにも LLM が設定されている必要があります。[assistant.md](/ja/agenteye/assistant) を参照してください。 | + +**AI アシスタントサービス — 監査 + サンドボックス設定。** エージェント型調査とそのインポッド Python サンドボックスは、**エージェントサービス**(サーバーではない)で調整します。すべて `AGENTEYE_AUDIT_*` プレフィックス、すべてオプション: + +| 変数 | デフォルト | 意味 | +|---|---|---| +| `AGENTEYE_AUDIT_MAX_STEPS` | `200` | 調査ごとの最大エージェントターン数。 | +| `AGENTEYE_AUDIT_TIMEOUT_MS` | `1200000` | 1 回の調査の経過時間(20 分)。サーバーの `AUDIT_LLM_TIMEOUT_MS` より**小さく**設定する必要があります。 | +| `AGENTEYE_AUDIT_MAX_CONCURRENCY` | `1` | エージェントポッドごとの同時調査数(チャットアシスタントの予算とは別)。 | +| `AGENTEYE_AUDIT_SANDBOX_TIMEOUT_MS` / `_MEM_MB` / `_CPU_SECS` / `_OUTPUT_MAX_BYTES` / `_SCRIPT_MAX_BYTES` | `20000` / `768` / `10` / `64000` / `64000` | bubblewrap サンドボックスのスクリプトごとの制限。 | + +**サンドボックスのプラットフォーム要件。** 監査コードサンドボックスはモデルの Python を bubblewrap ジェイル内で実行しますが、これには**非特権ユーザー名前空間**が必要です。エージェントポッドは `clone()` フラグを許可する必要があります。k8s の場合は `seccompProfile: Unconfined`、compose の場合は `security_opt: [seccomp:unconfined]` をエージェントに設定してください。ノードカーネルが非特権ユーザー名前空間を無効にしている場合(一部の GKE COS イメージなど)、**サンドボックスのプリフライトが失敗し、監査は自動的に SQL のみに切り替わります**。エラーにはならず、エージェントの `/health` に `sandbox_available: false` が表示されるだけです。 + +### 実行 + +`DATABASE_URL` と `CLICKHOUSE_URL` を環境に設定し(サーバーは ClickHouse なしでの起動を拒否します)、コンテナに渡します: + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-server \ + -e DATABASE_URL="$DATABASE_URL" \ + -e CLICKHOUSE_URL="$CLICKHOUSE_URL" \ + -e ADMIN_KEY="$ADMIN_KEY" \ + -p 8080:8080 \ + ghcr.io/agenteye-enterprise/server:beta-latest +``` + +サーバーは起動時にデータベースマイグレーションを自動実行します。別途マイグレーション手順は不要です。 + +### ヘルスチェック + +``` +GET /health # 生存確認 - プロセス起動後は常に {"status":"ok"} +GET /ready # 準備確認 - Postgres + ClickHouse が到達可能なら 200、そうでなければ 503 +``` + +認証不要です。**生存確認**プローブには `/health` を、**準備確認** / ロードバランサープローブには `/ready` を使用してください。`/ready` はサーバーがサービスを提供するために必要なハード依存関係(Postgres + ClickHouse)をチェックするため、動作中でもデータベースに到達できないサーバーはローテーションから外され `NotReady` と表示されます。Redis は報告されますが準備確認を失敗させることはありません。同梱の Kubernetes マニフェストでは、準備確認プローブはすでに `/ready` を指しており、生存確認は `/health` のままです。Kubernetes ネイティブのポッド障害アラートを Slack に送信するオプトイン機能を含む全体像については、[enterprise-docs/health-monitoring.md](/ja/agenteye/health-monitoring) を参照してください。 + +### Email マジックリンク URL + +OTP ログインメールにはワンタップで**ダッシュボードを開く**ボタンが含まれています。クリックすると `/login?token=&email=
` に移動し、ダッシュボードはそのペアをセッションと交換してアプリにリダイレクトします(手動でのコード再入力は不要)。サーバーはリンクの構築に使用するダッシュボードのオリジンを 3 段階で解決します: + +1. **`X-AgentEye-Dashboard-Url` ヘッダー**: ダッシュボードの `/api/auth/otp/request` プロキシが、自身のパブリックオリジンから自動的に設定します。同一オリジンのデプロイメント(サーバーとダッシュボードがプロキシヘッダーを転送する 1 つのイングレスの背後でホストを共有している場合)では、**設定は不要です**。 +2. **`DASHBOARD_URL` 環境変数**: ダッシュボードがサーバーの OTP リクエストエンドポイントから見えるオリジンとは異なるオリジンで到達可能な場合(`api.example.com` / `app.example.com` の分割)、またはイングレスがパブリックホストをダッシュボードポッドに伝播しない場合(`request.nextUrl.origin` が `0.0.0.0:3000` のようなワイルドカードバインドに解決される場合)に設定してください。例: `DASHBOARD_URL=https://app.example.com`。 +3. **デフォルト**: `https://app.befailproof.ai`。上記のいずれも存在しない場合のみ使用されます。 + +ヘッダー値は検証されます。`https://*` およびループバック(`http://localhost*`、`http://127.0.0.1*`)オリジンのみ受け付け、ワイルドカードバインドアドレス(`0.0.0.0`、`[::]`)は `https://` スキームでも拒否されます。それ以外はティア 2 にフォールスルーします。 + +ワンライナーで実行中のクラスターに設定できます(ファイルなし、kustomize の再ビルドなし): + +```bash +kubectl set env deployment/server -n agenteye \ + DASHBOARD_URL=https://app.example.com +``` + +これによりロールアウトがトリガーされ、新しいポッドは最初のリクエストで値を受け取ります。このオーバーライドは Deployment にのみ存在するため、オーバーレイに対して後で `kustomize build | kubectl apply` を実行すると、オーバーレイの `server-env.yaml` パッチに同じ環境変数を追加しない限り上書きされます。 + +--- + +## ダッシュボード + +### イメージのプル + +```bash +docker pull ghcr.io/agenteye-enterprise/dashboard:beta-latest +``` + +### 環境変数 + +| 変数 | 必須 | デフォルト | 説明 | +|---|---|---|---| +| `AGENTEYE_SERVER_URL` | はい | なし | サーバーのベース URL(例: `http://localhost:8080`) | +| `AGENTEYE_API_KEY` | はい | なし | ダッシュボードがサーバーへの認証に使用する API キー。全権限が必要です(管理者キー推奨)。 | +| `AE_LOG_LEVEL` | いいえ | `info` | サーバーサイドのログ冗長性: `debug`、`info`、`warn`、`error`。問題診断時にアップストリームリクエスト/レスポンス行とセッション検証トレースを確認するには `debug` に設定してください。 | +| `AE_LOG_JSON` | いいえ | 自動 | `1` で JSON 形式の行ごと出力を強制、`0` で人間が読みやすい出力を強制。未設定の場合、`NODE_ENV=production` であれば JSON が自動的に有効になります。本番環境では `jq` やログアグリゲーターでパースしやすいよう JSON が推奨されます。 | +| `AE_ANALYTICS_DISABLED` | いいえ | なし | `1`/`true` に設定すると、ダッシュボードの匿名プロダクト利用テレメトリが無効になります。後述の[テレメトリとプライバシー](#telemetry--privacy)を参照してください。 | +| `REDIS_URL` | いいえ | なし | オプションの共有キャッシュバックエンド(例: `redis://redis:6379/0`)。設定すると、ダッシュボードはレプリカ間で `validateSession()` の結果をキャッシュし、レイテンシ集計 / env リストプロキシルートの Next.js フェッチキャッシュを共有します。エッジサイドの OTP リクエストと検証のレート制限も、Redis が存在する場合はそれを使用します(Redis に到達できない場合はオープンフォールバック、サーバーサイドの制限がセキュリティの最終防衛線)。後述の **Redis(オプションキャッシュ)** を参照してください。 | +| `AGENTEYE_AGENT_URL` | いいえ | なし | オプションの AI アシスタント `agent` サービスのベース URL(例: `http://agent:9100`)。**未設定でアシスタントを完全に非表示にします**: ダッシュボードにアシスタントバブルが表示されなくなります。[enterprise-docs/assistant.md](/ja/agenteye/assistant) を参照してください。 | +| `AGENTEYE_AGENT_TOKEN` | いいえ | なし | ダッシュボードが `agent` サービスに提示する共有シークレット。エージェントに設定された `AGENTEYE_AGENT_TOKEN` と一致する必要があります。[enterprise-docs/assistant.md](/ja/agenteye/assistant) を参照してください。 | + +### 実行 + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-dashboard \ + -e AGENTEYE_SERVER_URL="http://your-server-host:8080" \ + -e AGENTEYE_API_KEY="$ADMIN_KEY" \ + -p 3000:3000 \ + ghcr.io/agenteye-enterprise/dashboard:beta-latest +``` + +### テレメトリとプライバシー + +ダッシュボードは**匿名のプロダクト利用分析**を Exosphere の分析サービス(PostHog)に送信します。対象はどのダッシュボードページが閲覧されたか、API キーの作成やセッションの再評価などの一部の UI アクションです。この利用シグナルは機能の優先順位付けに活用されます。 + +- **エージェント、セッション、イベントデータはあなたのインフラの外に出ません。** レポートされるのはダッシュボード UI の利用のみです。ページ URL は送信前に識別子が取り除かれ、オペレーターは不透明な内部 ID でのみ識別されます(メールアドレスは使用されません)。 +- テレメトリは**デフォルトで有効**です。完全に無効にするには、ダッシュボードコンテナに `AE_ANALYTICS_DISABLED=1` を設定して再起動してください。 +- 分析はダッシュボード自身の `/ingest` パスに送信され、ダッシュボードがそれを PostHog(`https://us.i.posthog.com`)にリバースプロキシします。リクエストをファーストパーティに保つことで、ブラウザの広告ブロッカーにブロックされません。**ダッシュボードコンテナ**は PostHog へのアウトバウンドアクセスが必要です。ブロックされている場合、テレメトリは静かに何もせず、ダッシュボードへの影響はありません。 + +--- + +## AI アシスタント(オプション) + +ダッシュボード内 AI アシスタントを使用すると、チームがダッシュボードを離れることなく、平易な言葉でエージェントデータに対して質問できます(セッションの要約、`/queries` エディター用の SQL のドラフト作成、保存済みクエリのダッシュボードタイルへの変換など)。Claude Agents SDK 上で動作する別の内部 `agent` コンテナとして実行され、ダッシュボードのみがアクセスできます。**LLM エンドポイントを設定するまで無効のままです。** + +有効化するには、`agent` サービスに LLM 接続(**Portkey** の場合は `PORTKEY_API_KEY` + モデルカタログスラグ `AGENTEYE_AGENT_MODEL=@/`、Anthropic 直接の場合は `ANTHROPIC_API_KEY`、別のゲートウェイの場合は `ANTHROPIC_BASE_URL`、または Bedrock/Vertex)、**専用の**データキー、そしてダッシュボードと一致する共有 `AGENTEYE_AGENT_TOKEN` を設定します。ダッシュボードユーザーにはさらに `agent:use` 権限が必要です。 + +アシスタントのデータキーは手動で発行する必要はありません。ランダムなシークレットを選択し、`agent` に `AGENTEYE_API_KEY` として設定し、`server` に `AGENT_API_KEY` として設定すると、サーバーが起動時に固定された権限セットでシードします。そのデータアクセスは読み取り専用(`events:read`、`evaluations:read`、`dashboards:read`、`queries:read`)であり、承認ゲート付きの作成スコープ(`dashboards:write`、`queries:write`、`queries:run`)も持っており、ユーザーに代わって保存済みクエリのドラフトと検証、ダッシュボードタイルの構築ができます。すべての SQL は org の読み取り専用 ClickHouse ロールを通じて実行されるため、これはアシスタントが作成できるものを広げるものであり、アクセスできるデータを広げるものではありません。スコープはコード内で固定されており、設定で変更できません。このキーは保護されており、API 経由での無効化や再生成はできず、値を変更して再起動することでのみローテーションできます。管理者/ダッシュボードキーをこの用途に再利用しないでください。 + +完全なセットアップ、環境変数リファレンス、テレメトリオプション、セキュリティモデルは **[enterprise-docs/assistant.md](/ja/agenteye/assistant)** に記載されています。 + +--- + +## ClickHouse(必須分析ストア) + +ClickHouse は高イベント量でもダッシュボードを高速に保ち、`/queries` SQL エディターが単一ストアでイベント、評価、セッションをジョインできるようにします。すべての取り込みイベント、すべての終端評価結果、および派生したセッションごとの集計の必須正規ストアです。PostgreSQL はリレーショナル / 可変状態テーブル(api_keys、users、otp_codes、evaluation_jobs、dashboards、saved_queries)を保持し、分析サーフェスは ClickHouse に置かれているため、ダッシュボードのロールアップと独自の SQL クエリはデータベースをまたいだラウンドトリップなしにネイティブにスキャン・ジョインできます。サーバーは `CLICKHOUSE_URL` なしでは起動を拒否します。 + +### スキーマ + +サーバー起動時に 3 つの ClickHouse オブジェクトが作成されます。すべてべき等(`CREATE IF NOT EXISTS`)です: + +- **`agenteye.events`**: `ReplacingMergeTree(ingested_at)`、`toYYYYMM(ts)` でパーティション分割、`(session_id, ts, dedup_key)` 順。重複挿入(コレクターのリトライ)はマージ時に 1 行に集約されます。サーバーはすべてのイベントに対して決定論的な SHA-256 `dedup_key` を計算するため、リトライは安全です。 +- **`agenteye.evaluations`**: `ReplacingMergeTree(ingested_at)`、`toYYYYMM(finished_at)` でパーティション分割、`(session_id, finished_at, dedup_key)` 順。評価パイプラインによって終端評価結果ごとに 1 度書き込まれます。`events` と同じ dedup キーモデル。 +- **`agenteye.agent_sessions`**: `agenteye.events` 上の**ビュー**(物理テーブルではありません)。すべての列は派生値(`started_at = min(ts)`、`last_event_at = max(ts)`、`ended_at = max(if event_type='agent_end', ts, NULL)`、`event_count = count()` など)です。イベントごとのアップサートや個別のバックフィルは不要で、ビューは `events` の内容を自動的に反映します。 + +`analytics.evaluations` / `analytics.sessions` を参照する保存済みクエリとの後方互換性のため、サーバーは `agenteye.*` テーブル上のビューを持つ `analytics` ClickHouse データベースも作成します。`analytics.events`、`analytics.evaluations`、`analytics.agent_sessions`、`analytics.sessions` はすべて正しく解決されます。 + +### 設定 + +同梱の docker-compose と `deploy/base/clickhouse/` には AgentEye のワークロード向けにチューニングされた ClickHouse サービスが含まれています: + +- 同梱ベースオーバーレイでのメモリ: リクエスト 2 GiB / 制限 4 GiB(小規模 POC/ステージングノードに合わせたサイズ)。本番環境のお客様はオーバーレイでスケールアップしてください。推奨最低値はリクエスト 2c/4Gi、制限 6c/8Gi。`max_server_memory_usage_to_ram_ratio=0.9` +- マークキャッシュ 5 GiB + 非圧縮キャッシュ 8 GiB +- `background_pool_size=16`、`background_merges_mutations_concurrency_ratio=2` +- MergeTree: `parts_to_throw_insert=3000`、`parts_to_delay_insert=1500`、`non_replicated_deduplication_window=1000` +- `local_io_method=auto`(対応カーネルでは io_uring) +- `fsync_metadata=0`: at-least-once 取り込み + ReplacingMergeTree dedup のため許容 +- `query_log` は 30 日 TTL で有効。`query_thread_log` は削除済み(高 QPS でコストが高い) +- ユーザーサイドクエリに `max_execution_time=30` +- StatefulSet テンプレートで 100 GiB PVC(お客様のオーバーレイでは本番環境向けに高速 SSD ストレージクラスにオーバーライドすることを推奨) + +### バックアップ + +データセット全体は毎夜 1 つのリストア可能なアーカイブにキャプチャされるため、クラスターやストレージの損失から回復できます。ClickHouse は毎日の `agenteye-backup` CronJob によって自動的にバックアップされ、PostgreSQL と ClickHouse を 1 回のパスで一緒にダンプします。ClickHouse は HTTP API 経由で読み取られます。`agenteye.events` と `agenteye.evaluations` は ClickHouse ネイティブ形式でダンプされ(ビューと行ポリシーはサーバー起動時に再作成されるため、テーブルデータが完全な内容です)、Postgres ダンプとともに 1 つの圧縮アーカイブにまとめられてオブジェクトストレージにアップロードされます。 + +宛先バケットとクラウド認証情報はオーバーレイごとに設定します。アップロード設定とリストア手順については、[enterprise-docs/kubernetes-deployment.md](/ja/agenteye/kubernetes-deployment) の**バックアップ**セクションを参照してください。 + +--- + +## Redis(オプションキャッシュ) + +Redis はサーバーとダッシュボードが使用する**オプション**の共有キャッシュ + レート制限バックエンドです。Redis をデプロイし、両サービスに `REDIS_URL` を設定すると: + +- **Server** は認証済み API キーのルックアップ、`/events/environments` + `/evaluations/environments` リスト、`/events/latency_aggregate` ロールアップ(ダッシュボードがポーリングする最も重いクエリ)、`/sessions` リストをキャッシュし、OTP リクエストのレート制限を Postgres `COUNT(*)` から Redis `INCR + EXPIRE` に切り替えます。 +- **Dashboard** は `validateSession()` の結果をキャッシュし、典型的なページロードが発行する 10〜20 の認証済み API 呼び出しがすべて 1 つのアップストリームセッションチェックを共有できるようにします。OTP リクエストと OTP 検証のレート制限もダッシュボードエッジで行います。 + +**Redis に到達できない場合、両サービスは安全にデグレードします。** すべてのキャッシュ呼び出しは有界タイムアウト内に `Err` を返し、呼び出し元はソースオブトゥルース(サーバーでは Postgres、ダッシュボードではアップストリームの Rust サーバー)にフォールバックします。OTP レート制限はサーバー上の Postgres `COUNT(*)` パスにフォールバックします(セキュリティプロパティは維持されます)。ダッシュボードのエッジ OTP 制限はオープンフォールバックしますが、サーバーサイドの制限は引き続き機能します。Redis のダウンはレイテンシを低下させますが、正確性には影響しません。 + +### 設定 + +docker-compose バンドルにはすでに Redis サービスが含まれており、`REDIS_URL=redis://redis:6379/0` がサーバーとダッシュボードに設定されています。外部 Redis を使用するには、`REDIS_URL` をエンドポイントに設定し、compose ファイルから `redis` サービスを削除してください。 + +### メモリと永続化 + +同梱の Redis イメージは `--appendonly yes --appendfsync everysec --maxmemory 256mb --maxmemory-policy allkeys-lru` で実行されます。AOF 永続化によりキャッシュはコンテナ再起動後も存続します。`everysec` はキャッシュ書き込みの最後の 1 秒を失っても無害なため、適切な耐久性/パフォーマンスのバランスです。LRU エビクションによりメモリの増大を抑制します。 + +### Redis をデプロイしないケース + +- 単一インスタンスの開発/QA 環境。サーバー上のインプロセスキャッシュだけでもレプリカごとのメリットの大部分が得られます。Redis はシングルインスタンス設定では不要なクロスレプリカ共有を追加するものです。 +- エアギャップ環境で、もう 1 つサービスを運用するコストがレイテンシの改善を上回る場合。 + +--- + +## Docker Compose(推奨) + +`docker-compose.yml` は `agenteye-enterprise/releases` リポジトリで入手できます。1 つのコマンドで Postgres、ClickHouse、Redis、サーバー、ダッシュボードを起動できます。 + +```bash +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download \ + --repo agenteye-enterprise/releases \ + --pattern 'docker-compose.yml' \ + --dir ./agenteye +cd agenteye +``` + +**`.env` でデフォルトをオーバーライド:** + +``` +# URL セーフなパスワードを使用してください(/、+、= 文字を含まない)。 +# 生成方法: openssl rand -hex 24 +POSTGRES_PASSWORD=your-db-password +ADMIN_KEY=your-admin-secret + +# ダッシュボード認証 +ADMIN_EMAIL=admin@yourcompany.com +ALLOWED_EMAILS=*@yourcompany.com + +# OTP メール用 SMTP(省略すると OTP コードが stdout に記録されます) +# SMTP_HOST=smtp.yourprovider.com +# SMTP_PORT=587 +# SMTP_USERNAME=your-smtp-user +# SMTP_PASSWORD=your-smtp-password +# SMTP_FROM=noreply@yourcompany.com + +RUST_LOG=info +``` + +```bash +docker compose up -d +``` + +**停止(データボリュームを保持):** + +```bash +docker compose down +``` + +**停止してすべてのデータを削除:** + +```bash +docker compose down -v +``` + +--- + +## 運用設定 + +以前は環境変数で固定されていた少数の運用上の調整項目が、ダッシュボードの **`//settings`** ページから組織ごとに編集できるようになりました。各 org が独自に設定します。変更は数秒以内に有効になります(再起動や再デプロイは不要)。 + +| 設定 | ブートストラップ環境変数 | 制御内容 | +|---|---|---| +| 許可されたサインイン | `ALLOWED_EMAILS` | OTP の受信とユーザー追加が許可されるメールアドレス(または `*@domain.com` ワイルドカード) | +| デフォルトユーザー権限 | `DEFAULT_USER_PERMISSIONS` | 管理者が **+ new user** を開いたときにあらかじめ選択される権限トークンのカンマ区切りリスト。各トークンは [API key permissions](/ja/agenteye/api-keys) に記載された文字列のいずれかである必要があります。デフォルトは `standard` プリセット: 読み取り専用アクセスに加え、日常的なオンコールアクション(再評価のトリガー、クエリの実行、インシデントの確認、アシスタントの使用)。 | +| セッション有効期間 | `SESSION_TTL_SECS` | ダッシュボードのログインが再認証なしに有効な期間。ダッシュボードは 5 秒ごとにアップストリームセッションを再確認するため、`//users` での権限更新は対象ユーザーの次のリクエストで有効になります(再ログイン不要)。 | +| ワンタイムコードの有効期間 | `OTP_TTL_SECS` | OTP / マジックリンクが使用可能な期間 | +| アラート通知チャンネル | `ALERTS_ENABLED_CHANNELS` | アラートディスパッチャーが使用を許可されるチャンネル種別のカンマ区切りリスト: `email`、`slack`、`webhook`。アラートごとの設定は引き続き `//alerts/` で行いますが、ディスパッチャーはすべてのアウトバウンド配信をこのセットでフィルタリングします。ここで無効にされたチャンネルは `skipped_disabled` 監査行で短絡されます。`dashboard` チャンネル(ローカル監査挿入)は常に許可されます。デフォルトは 3 つすべて有効。 | + +### ブートストラップの仕組み + +設定は `org_settings` に組織ごとに保存されます。初回起動時、サーバーはデフォルト org の欠落している行に対応する環境変数(または環境変数が未設定の場合は適切なデフォルト値)からシードします。それ以降は**保存された値がソースオブトゥルースとなり、環境変数は無視されます**。後から環境変数を変更して再起動しても、ライブ org の値には影響せず、追加の org はデフォルトから始まって独自に設定します。 + +つまり: + +- 新規デプロイでは、上記の環境変数を設定すると、デフォルト org が初回起動時にそれらを読み込みます。 +- 後から値を変更するには、ダッシュボードにログインして `//settings` で編集してください。変更はすべてのサーバーレプリカに数秒以内に適用されます(再起動不要)。 +- ブートストラップが有効だったことを確認するため、起動ログ行にシードされた内容と既に存在していた内容が記録されます: + + ```text + INFO settings bootstrap: seeded default-org row key=allowed_sign_ins env_var=ALLOWED_EMAILS seeded_from_env=true + ``` + +#### 組織をまたいだサインインのセマンティクス + +セッションと OTP はユーザーに対してグローバルであり、単一の org に紐付けられません。そのため、2 つのルールがサインイン時に org ごとの設定を調整します: + +- **セッション / OTP の有効期間**: ユーザーが所属する org の中で最も厳しい(最短の)有効期間が優先されます。 +- **許可されたサインイン**: ゲートはすべての org のアローリストと org メンバーシップを OR 結合します。任意の org のアローリストがそのメールアドレスを許可している場合、**またはその**ユーザーがすでにいずれかの org のメンバーである場合に、OTP をリクエストできます。 + +### 権限 + +`//settings` ページへのアクセスは 2 つの権限でゲートされています: + +- `settings:read`: ページと現在の値の閲覧。 +- `settings:write`: 変更の保存。 + +ブートストラップ管理者ユーザー(`ADMIN_EMAIL` からシード)は、他のすべての権限とともに両方を自動的に取得します。必要に応じて `//users` から他のユーザーに付与してください。 + +--- + +## 組織(マルチテナント) + +1 つのデプロイメントで複数の独立した**組織**(テナント)を提供できます。データのすべての行はちょうど 1 つの org に属し、分離はデータベースエンジンで強制されます。シングルテナントインストールではここで何もする必要はありません。すべてのデータは組み込みの `default` org に存在します。(その org に分かりやすい名前と URL スラグを付けて、例えば `/default` の代わりに `/acme` に配置することもできます。初回起動前に `DEFAULT_ORG_NAME` / `DEFAULT_ORG_SLUG` を設定するか、`agenteye-orgctl org rename` でいつでも名前を変更できます。) + +**テナントプロビジョニングはオペレーター専用です。** 組織とそのメンバーシップは、**`agenteye-orgctl`** CLI で作成・管理します。この CLI はサーバーイメージ内に同梱されており(`agenteye-server` と並んで)、**既存のサーバーポッド内で実行されます**。**別個のポッド/ジョブ、HTTP API、ダッシュボードボタンはありません。** サーバーの `DATABASE_URL`、`CLICKHOUSE_URL`、`ORG_CH_SECRET` を再利用します。 + +```bash +# Docker Compose - 実行中のサーバーサービスに exec: +docker compose exec server agenteye-orgctl org create --slug acme --name "Acme Corp" +docker compose exec server agenteye-orgctl member add --org acme --email alice@acme.example --set admin + +# Kubernetes - 実行中のサーバー Deployment に exec: +kubectl -n agenteye exec deploy/server -- agenteye-orgctl org list +``` + +利用可能なサブコマンド: `org create | list | rename | delete | purge` と `member add | list | update | remove`。組み込み権限セット `admin`、`standard`、`read-only` があります。追加されたメンバーは最初のダッシュボードログイン時に OTP を受け取ります。 + +**2 番目の org を作成する前に:** 強力で安定した `ORG_CH_SECRET` を設定してください(`org create` コマンドは組み込み開発用デフォルトでの実行を拒否します)。また Postgres が **15+** であることを確認してください。**変更なし:** org ごとの API キーは引き続き org メンバーがダッシュボード/API でミントします。org とメンバーのライフサイクルのみ CLI に移動しました。完全なコマンドリファレンスと実例: **[enterprise-docs/tenant-management.md](/ja/agenteye/tenant-management)**。 + +--- + +## コンテキストウィンドウ充填率 + +各 `model_response` イベントには**コンテキスト充填率ピル**が表示されます。入力トークンと出力トークンの合計をそのモデルのコンテキストウィンドウに対するパーセンテージで表します。バンドは `healthy`(0〜24%)、`watch`(25〜49%)、`compacting`(50〜74%)、`reset context`(75〜100%)です。AgentEye は一般的なモデル ID を自動的に解決するため、初期設定は不要です。 + +組織が送信した各モデルは **Settings → model context windows** に表示されます。`settings:write` 権限を持つユーザーはそのウィンドウをオーバーライドしたり、プライベート/プロキシモデルを追加したりできます(0〜1,000,000 トークン)。`0` は「不明」を意味し、ピルを非表示にします。変更は新たに取り込まれたイベントに適用されます。`settings:read` 権限を持つユーザーはリストを閲覧できます。 + +アップグレード後の新しいイベントには、その時点から充填率が入ります。既存のデプロイメントで**過去の**イベント(およびモデルごとのリスト)にも入力するには、ワンオフのバックフィルを実行します。これはサーバーイメージ内に同梱されており(`agenteye-orgctl` と同様)、既存のサーバーポッド内で実行されます: + +```bash +# プレビュー(org ごとのミューテーションを表示、変更なし): +kubectl -n agenteye exec deploy/server -- agenteye-backfill-context-window --dry-run +# 適用: +kubectl -n agenteye exec deploy/server -- agenteye-backfill-context-window +# docker compose: +docker compose exec server agenteye-backfill-context-window +``` + +べき等(再実行しても安全)であり、ポッドの `DATABASE_URL` / `CLICKHOUSE_URL` / `REDIS_URL` を再利用します。モデルウィンドウを編集した後、既存のイベントを再計算したい場合は再実行してください。 + +--- + +## 本番環境での考慮事項 + +- **Postgres**: マネージド Postgres サービスまたは定期バックアップ付きの専用インスタンスを使用してください。`DATABASE_URL` は `sslmode=require` などの標準 libpq パラメーターをすべてサポートしています。 +- **TLS**: TLS を終端するリバースプロキシ(nginx、Caddy、Traefik)の背後にサーバーとダッシュボードを配置してください。 +- **ファイアウォール**: サーバーポート(デフォルト 8080)はコレクターマシンとダッシュボードホストからのみアクセス可能にし、パブリックインターネットからは到達できないようにして \ No newline at end of file diff --git a/docs/ja/agenteye/evaluation-suite.mdx b/docs/ja/agenteye/evaluation-suite.mdx new file mode 100644 index 00000000..5b3d7359 --- /dev/null +++ b/docs/ja/agenteye/evaluation-suite.mdx @@ -0,0 +1,355 @@ +--- +title: "評価スイート" +description: "AgentEye 評価スイートのドキュメント。" +--- + +AgentEye は、完了したエージェントセッションを評価するために、イベントトランスクリプト全体を **顧客が管理する単一の評価サービス** に POST して採点します。評価サービスはスコアをインラインで返すか、AgentEye がポーリングするための `job_id` を返します。結果は保存され、ダッシュボードに表示されます。 + +このガイドでは以下を説明します: + +1. セッション完了の検出方法 +2. 評価サービスが実装すべき HTTP コントラクト +3. AgentEye サーバーの設定 +4. 結果の確認方法 +5. トラブルシューティング + +コントラクトを代わりに実装してくれる Python ヘルパーについては、[PyPI の `agenteye-evaluator` パッケージ](https://pypi.org/project/agenteye-evaluator/)を参照してください。 + +--- + +## 仕組み + +```text +ingest /events ──▶ AgentEye ──── POST /evaluate ────▶ Evaluator service + (agent_end) server ◀──── done | pending ──── + │ + │ GET /evaluate/{job_id} ─────▶ + │ ◀──── done ────────────── + ▼ + evaluations (terminal results) +``` + +AgentEye SDK がセッションの `agent_end` イベントを発行すると、サーバーは評価をスケジュールします。その後、イベントトランスクリプト全体を評価サービスに POST します。評価サービスは次のいずれかを返します: + +- **インラインで結果を返す**:`{"status":"done", "scores":{...}, "reasoning":{...}, "summary":"..."}` を返します。結果はセッションの評価タイムラインに追記されます。`reasoning` と `summary` は省略可能です。 +- **処理を遅延させる**:`{"status":"pending", "job_id":"abc-123"}` を返します。AgentEye はその後、評価サービスが `{"status":"done", ...}` または `{"status":"error", "error":"..."}` を返すまで `GET {EVALUATOR_ENDPOINT}/evaluate/abc-123` を呼び出し続けます。 + + ポーリング間隔はジョブごとに設定可能です。`pending` レスポンスに `next_poll_secs` を含めることでデフォルト値を上書きできます。指定がない場合、AgentEye は `GET /config` の `default_poll_interval_secs` を使用し、それも指定がない場合はサーバーの `EVALUATOR_POLLING_INTERVAL_SECS`(デフォルト 10 秒)にフォールバックします。すべての値は [1 秒, 1 時間] の範囲にクランプされます。 + +`agent_end` を発行しないセッション(例:エージェントプロセスがクラッシュした場合)にも対応できます。評価サービスの `GET /config` が `{"inactivity_timeout_secs": 1800}` を返せば、AgentEye はその時間アイドル状態のセッションも評価します。このフォールバックを無効にするには、フィールドを `null` にするか省略してください。 + +`EVALUATOR_ENDPOINT` が未設定の場合、パイプラインは完全に無効化されます。 + +セッションには**複数の終端評価が時系列で蓄積される**ことがあります。`agent_end` イベントが発生するたびに(およびダッシュボードから手動で再評価するたびに)、新しい評価行が追記されます。これは再開された会話を評価するための公式のやり方です。ユーザーがエージェントを終了し、後で戻ってきてイベントを追加送信し、再びエージェントを終了すると、更新されたトランスクリプト全体に対して 2 回目の評価が実行されます。ダッシュボードでは最新の評価がメインとして表示され、過去の評価は折りたたみ可能なタイムラインとして表示されます。あるセッションで評価が実行中の場合、そのセッションの追加 `agent_end` イベントは無視されます。実行中の評価が完了した後の次の `agent_end` イベントで、新しい評価が通常どおりキューに追加されます。 + +アイドルタイムアウトによるフォールバックは、再開されたセッションにも再適用されます。過去の終端評価の後に新しいイベントが到着し、その後セッションが `inactivity_timeout_secs` を超えてアイドル状態になった場合、新しい評価がキューに追加されます。 + +一時的な障害(5xx、429、タイムアウト、ネットワークエラー)は `EVALUATOR_MAX_ATTEMPTS` まで指数バックオフでリトライされます。4xx レスポンスは終端扱いです。AgentEye は複数のサーバーインスタンスを水平スケールして実行しても安全です。作業はパーティション分割されているため、同じセッションが同時に 2 度ディスパッチされることはありません。 + +--- + +## HTTP コントラクト + +認証が必要なすべてのルートは **ベアラートークン認証** を使用します。同じ値を両側で設定する必要があります: + +- AgentEye サーバー:環境変数 `EVALUATOR_TOKEN` +- 評価サービス:同様の方法で設定(`agenteye-evaluator` SDK は慣例として `EVALUATOR_TOKEN` を読み取ります) + +`EVALUATOR_TOKEN` が未設定の場合、サーバーは `Authorization` ヘッダーを送信しません。その場合、評価サービスは匿名リクエストを受け入れることができますが、これは内部ネットワーク専用の場合は問題ありませんが、公開インターネット上での使用は推奨されません。 + +### 評価サービスが提供すべきルート + +| ルート | ボディ / パラメーター | レスポンス | +|---|---|---| +| `GET /health` | なし | `{"status":"ok"}` (オープン、認証不要) | +| `GET /config` | なし | `{"inactivity_timeout_secs": \| null, "default_poll_interval_secs": \| omitted}` | +| `POST /evaluate` | `EvalRequest` JSON | `{"status":"done", ...}` または `{"status":"pending", "job_id":"..."}` | +| `GET /evaluate/{id}` | なし | `/evaluate` と同じレスポンス形式 | + +### サーバーが送信する `EvalRequest` ボディ + +```json +{ + "schema_version": "1", + "session_id": "session-abc123", + "agent_id": "planner", + "environment": "production", + "started_at": "2026-05-10T12:00:00Z", + "ended_at": "2026-05-10T12:05:00Z", + "events": [ + { "id": 1234, "ts": "...", "event_type": "agent_start", "payload": { ... } }, + ... + ] +} +``` + +### レスポンスの形式 + +**同期(完了):** + +```json +{ + "status": "done", + "scores": { "helpfulness": 0.85, "tool_efficiency": 0.6 }, + "reasoning": { + "helpfulness": "answered the question directly with citations", + "tool_efficiency": "called list_files three times when one would have done" + }, + "summary": "strong answer quality, weak tool selection" +} +``` + +`reasoning`(スコアごとの根拠マップ)と `summary`(全体的な概要の段落)はどちらも省略可能です。`reasoning` のキーは `scores` のキーに対応させてください。ダッシュボードでは各エントリがスコアバーの下にインラインで表示されます。`scores` のみを返す古い評価サービスも変更なしで動作し続けます。`reasoning` と `summary` は null として扱われ、対応する UI 要素は省略されます。 + +**非同期(遅延):** + +```json +{ "status": "pending", "job_id": "abc-123", "next_poll_secs": 30 } +``` + +`next_poll_secs` は省略可能です。省略した場合、サーバーは `/config` の `default_poll_interval_secs`、次に `EVALUATOR_POLLING_INTERVAL_SECS` 環境変数にフォールバックします。 + +**評価サービス側の終端エラー:** + +```json +{ "status": "error", "error": "model service unavailable" } +``` + +サーバーはその他の 2xx ボディをプロトコルエラーとして扱い、セッションの終端 `error` として記録します。 + +--- + +## SDK を使った評価サービスの実装 + +`agenteye-evaluator` Python パッケージは、上記の HTTP コントラクトを実装した型付き FastAPI ラッパーを提供します。PyPI からインストールしてください: + +```bash +pip install agenteye-evaluator +``` + +最小構成の評価サービス: + +```python +import os +from agenteye_evaluator import Evaluator, EvalRequest, EvalResponse + +app = Evaluator(token=os.environ["EVALUATOR_TOKEN"]) + +@app.evaluator +def run(req: EvalRequest) -> EvalResponse: + # req.events(セッションのフルトランスクリプト)を検査してスコアを返します + tool_calls = sum(1 for e in req.events if e.event_type == "tool_use") + return EvalResponse( + scores={"tool_calls": float(tool_calls)}, + reasoning={"tool_calls": f"{tool_calls} tool invocations in the transcript"}, + summary="tight tool loop" if tool_calls < 5 else "agent looped on tools", + ) +``` + +`app` インスタンスは ASGI 呼び出し可能なので、`uvicorn module:app` で起動できます。 + +コストのかかる処理を遅延させる必要がある評価サービスの場合は、代わりに `JobPending` を返し、`@app.job_lookup` ハンドラーを登録してください。AgentEye サーバーは、終端ステータスが返されるか `EVALUATOR_MAX_POLL_DURATION_SECS` 上限(デフォルト 1 時間)に達するまで `GET /evaluate/{job_id}` をポーリングします。 + +完全な API リファレンス、非同期パターン、およびイベントスキーマは、`agenteye-evaluator` の README が各リリース tarball に含まれています。[agenteye-enterprise リリースページ](https://github.com/agenteye-enterprise/releases)から取得するか、パッケージの PyPI ページで確認できます。 + +--- + +## Kubernetes での評価サービスの実行 + +評価サービスは**お客様自身のサービス**です。AgentEye はデフォルトの評価サービスコンテナを提供しません。リリースには `deploy/examples/evaluator/` 配下に参考用の Kubernetes マニフェストが含まれており、イメージと共有ベアラートークンを差し替えるだけで適用できます。 + +### 1. 評価サービスをコンテナ化する + +評価サービスの最小構成 Dockerfile: + +```dockerfile +FROM python:3.12-slim +WORKDIR /app +RUN pip install --no-cache-dir agenteye-evaluator uvicorn +COPY my_evaluator.py . +RUN useradd --uid 10001 --create-home --shell /usr/sbin/nologin evaluator \ + && chown -R evaluator:evaluator /app +USER evaluator +EXPOSE 9000 +CMD ["uvicorn", "my_evaluator:app", "--host", "0.0.0.0", "--port", "9000"] +``` + +`runAsNonRoot`(UID 10001)により、Pod Security の restricted プロファイルとの互換性が保たれます。 + +### 2. 共有ベアラートークンを作成する + +```bash +kubectl -n agenteye create secret generic evaluator-token \ + --from-literal=token="$(openssl rand -hex 32)" +``` + +AgentEye サーバーの `EVALUATOR_TOKEN` と同じ値を使用してください。サーバーはすべてのリクエストに `Authorization: Bearer ` を送信します。SDK は `hmac.compare_digest` を使って定数時間で検証し、不一致の場合は HTTP 401 を返します。 + +### 3. サンプルマニフェストを適用する + +```bash +# まず deploy/examples/evaluator/deployment.yaml を編集して +# `image:` をご自身のレジストリに変更してから: +kubectl apply -k deploy/examples/evaluator/ +``` + +サンプルには以下が含まれます: + +- `runAsNonRoot`、読み取り専用ルートファイルシステム、全 capabilities ドロップ、`/health` へのライブネス+レディネスプローブを設定した 2 レプリカの Deployment +- ポート 9000 の ClusterIP Service +- `secret.example.yaml` テンプレート(トークンが git に含まれないよう、Kustomization から意図的に除外されています。実際の Secret は帯域外で作成してください) + +### 4. AgentEye と接続する + +AgentEye サーバーに以下を設定してください: + +```bash +EVALUATOR_ENDPOINT=http://evaluator:9000 +EVALUATOR_TOKEN=<上記で生成した値> +``` + +サーバーは `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH` の同時リクエストを全評価サービス Pod に分散します(デフォルト:`2 × 4 = 8`)。サーバー側の設定値に合わせて `replicas` と Pod ごとのリソース制限を調整してください。 + +### 動作確認 + +```bash +kubectl -n agenteye port-forward svc/evaluator 9000:9000 +curl -s http://localhost:9000/health # → {"status":"ok"} +``` + +エージェントがエンドツーエンドで実行された後、AgentEye サーバーの `GET /evaluations` から `status: "done"` と評価サービスが生成したスコアを含む行が返されるはずです。 + +--- + +## AgentEye サーバーの設定 + +サーバープロセスに以下を設定してください: + +| 環境変数 | 説明 | +|---|---| +| `EVALUATOR_ENDPOINT` | 評価サービスのベース URL(`http://evaluator:9000`)。未設定の場合、パイプラインは無効になります。 | +| `EVALUATOR_TOKEN` | ベアラートークン。評価サービスに設定された値と一致する必要があります。 | +| `EVALUATOR_WORKERS` | サーバーインスタンスごとのワーカータスク数(デフォルト 2)。 | +| `EVALUATOR_CLAIM_BATCH` | ワーカーのティックごとにクレームする行数(デフォルト 4)。バッチは**並行**処理されます。評価サービスエンドポイントへの実効並行数は `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH` です。 | +| `EVALUATOR_POLL_IDLE_SECS` | 評価が不要な場合にワーカーがディスパッチを試みる間隔(デフォルト 2 秒)。 | +| `EVALUATOR_POLLING_INTERVAL_SECS` | `GET /evaluate/{id}` のポーリング間隔の最終フォールバック。レスポンスごとの `next_poll_secs` も評価サービスの `default_poll_interval_secs` も設定されていない場合に使用されます(デフォルト 10 秒)。 | +| `EVALUATOR_REQUEST_TIMEOUT_MS` | リクエストごとのタイムアウト(デフォルト 30000)。 | +| `EVALUATOR_MAX_ATTEMPTS` | この回数だけ一時的な障害が発生すると、結果が終端 `error` として記録されます(デフォルト 5)。 | +| `EVALUATOR_CONFIG_REFRESH_SECS` | `GET /config` の呼び出し間隔(デフォルト 300)。 | +| `EVALUATOR_MAX_POLL_DURATION_SECS` | セッションがポーリングキューに残れる最大のウォールクロック時間。これを超えると `timeout` として終端処理されます(デフォルト 3600 秒)。評価サービスが永続的に `pending` を返し続けることを防ぎます。 | + +インスタンス全体で自動採点を有効にするには、両方のキーが設定された `agenteye-evaluator` Secret をプロビジョニングしてください。バンドルされた Kubernetes マニフェストでは、サーバーはこのオプションの Secret から `EVALUATOR_ENDPOINT` と `EVALUATOR_TOKEN` を読み取ります。組織の標準的なシークレット管理プロセスで作成し、変更を反映させるためにサーバーの Deployment を再起動してください。 + +上記のチューニング設定はデフォルトでは接続されていません。デフォルト値を上書きする必要がある場合は、Deployment マニフェストのサーバーコンテナに対応する環境変数を設定してください。 + +完全な環境変数一覧については [deployment.md](/ja/agenteye/deployment) を参照してください。 + +--- + +## API リファレンス + +| メソッド | パス | 必要なパーミッション | 目的 | +|---|---|---|---| +| `GET` | `/evaluations` | `evaluations:read` | 終端結果を照会します。`session_id`、`agent_id`、`environment`、`status`(`done`/`error`/`timeout`)、`ts_from`、`ts_to`、`cursor`、`limit`、`score_filters`、`latest_per_session` をサポートします。`limit` のデフォルトは 50、上限は 200 です(`/events` の上限 1000 とは異なります)。`environment` はカンマ区切りのリストを受け付けます(例:`environment=prod,staging`)。単一値でも動作します。`latest_per_session=true` を指定すると、レスポンスは `session_id` ごとに最新の行(`completed_at` が最も新しいもの)のみを返します。セッション一覧ページでセッションの評価タイムラインを現在のヘッドラインに折りたたむために使用されます。デフォルトは false(全履歴を返します)。 | +| `GET` | `/evaluations/aggregate` | `evaluations:read` | フィルタリングされたスライスの評価ヘルスを集計します。総数、done/error/timeout の内訳、スコアキーごとの統計情報(任意の `scores` キーに対する count/avg/min/max/p50)、時間バケットのタイムラインを返します。**`/evaluations` と同じフィルターパラメーター**に加え、`featured_keys`(トレンド表示するスコアキーの CSV)と `latest_per_session` を受け付けます。ダッシュボード機能を動かします。メトリクスはサンプリングではなく、一致するセット全体に対して正確に計算されます。 | +| `GET` | `/evaluations/environments` | `evaluations:read` | `evaluations` テーブルのユニークな environment 値を返します。評価データにスコープされたフィルタードロップダウンの選択肢を生成するために使用されます。 | +| `GET` | `/evaluation-jobs` | `evaluations:read` | 実行中の評価の可視性を提供します。`status`(`pending`/`polling`)でフィルタリングできます。 | +| `GET` | `/events` | `events:read` | セッションの生イベントをストリームします。`session_id`、`agent_id`、`event_type`(CSV)、`environment`(CSV)、`ts_from`、`ts_to`、`cursor`、`limit`、`order` をサポートします。`order` は `desc`(新しい順、デフォルト)または `asc`(古い順)です。不明な値は `desc` にフォールバックします。レスポンスの `next_cursor`(イベント ID)を使ってカーソルページネーションができます。`cursor` として渡すと次のページが取得できます。`asc` の場合は該当 ID より後のイベント、`desc` の場合は該当 ID より前のイベントが返されます。`limit` のデフォルトは 50、上限は 1000 です。 | +| `GET` | `/sessions/:session_id/export` | `events:read` | このセッションに対して評価サービスが受け取るであろう正確な JSON ボディを `session-.json` という名前のダウンロード可能な添付ファイルとして返します。本番セッションを `agenteye-evaluator` を使ってオフラインでテストするために便利です。バイト列は評価パイプラインが送信するものと完全に一致します。 | +| `POST` | `/sessions/:session_id/re-evaluate` | `evaluations:trigger` | セッションの新しい評価をキューに追加します。過去の評価の有無に関わらず実行されます。新しい結果は以前の評価を上書きするのではなく、セッションの評価タイムラインに**追記**されます。そのため過去のスコアは履歴として引き続き参照できます。キュー追加時に `202` を返します。セッションが不明な場合は `404`、評価がすでに実行中の場合は `409` を返します。新しい評価サービスをデプロイした後や、`agent_end` を発行しなかったセッションに対して使用してください。 | + +### スコア範囲によるフィルタリング:`score_filters` + +`GET /evaluations` はオプションの `score_filters` パラメーターを受け付けます。このパラメーターは `scores` オブジェクト内の数値によって結果を絞り込みます。パラメーターはカンマ区切りの `key:min..max` エントリーのリストです。どちらの境界も省略可能です。複数のエントリーは論理 AND で結合されます。指定されたキーが存在しないか非数値の行は除外されます。1 リクエストあたり最大 20 フィルターエントリーを指定できます。超過した場合は HTTP 400 が返されます。 + +例: +```text +# helpfulness が [0.5, 0.8] の範囲 +GET /evaluations?score_filters=helpfulness:0.5..0.8 + +# tool_efficiency が 0.3 以下(下限なし) +GET /evaluations?score_filters=tool_efficiency:..0.3 + +# helpfulness >= 0.5 かつ factuality >= 0.9 +GET /evaluations?score_filters=helpfulness:0.5..,factuality:0.9.. +``` + +`/evaluations` の各レスポンスオブジェクトには以下のフィールドがあります: + +| フィールド | 型 | 備考 | +|---|---|---| +| `evaluation_id` | string(UUID) | この終端評価の正規識別子。終端評価ごとに新しい UUID が割り当てられます。1 つのセッションに複数の UUID を持てます。 | +| `id` | string(UUID) | `evaluation_id` と同じ値を持つ後方互換エイリアス。 | +| `session_id` | string | この評価が実行されたセッション。1 つのセッションがタイムライン上に複数の評価を持てます。 | +| `agent_id` | string | セッションを生成したエージェントを識別します。 | +| `environment` | string | セッションからコピーされた環境ラベル。 | +| `status` | enum | `"done"`、`"error"`、`"timeout"` のいずれか。 | +| `scores` | object \| null | 評価サービスが返したスコア。 | +| `reasoning` | object \| null | 評価サービスが返したオプションのスコアごとの根拠マップ。キーは通常 `scores` のキーに対応します。ダッシュボードでは各エントリーがスコアバーの下に表示されます。 | +| `summary` | string \| null | 評価サービスが返したオプションの全体的な概要の段落。ダッシュボードでは、スコアの内訳の上にこの評価のヘッドラインとして表示されます。 | +| `error` | string \| null | `"error"` / `"timeout"` の場合のみ設定されます。 | +| `attempt_count` | integer | ディスパッチの試行回数(1 以上)。 | +| `duration_ms` | integer \| null | 最終試行の所要時間。 | +| `completed_at` | string(ISO 8601 UTC) | 終端結果が記録された日時。結果は `completed_at` の降順(新しい順)でソートされます。 | +| `created_at` | string(ISO 8601 UTC) | `completed_at` と同じタイムスタンプを持ちます(書き込み一回限りのセマンティクス)。 | + +--- + +## パーミッション + +| パーミッション | 付与する権限 | +|---|---| +| `evaluations:read` | 評価結果の一覧表示、ダッシュボードでのスコア表示、ダッシュボードのヘルスメトリクスの読み込み。 | +| `evaluations:trigger` | `POST /sessions/:session_id/re-evaluate` またはダッシュボードの再評価ボタンからセッションの評価を手動でキューに追加する。 | +| `dashboards:read` | 保存済みダッシュボードの表示(メトリクスの読み込みには `evaluations:read` も必要)。 | +| `dashboards:write` | ダッシュボードの作成と編集。 | +| `dashboards:delete` | ダッシュボードの削除。 | + +ブートストラップ管理者(`ADMIN_KEY`、`ADMIN_EMAIL`)はこれらのパーミッションをすべて自動的に受け取ります。 + +--- + +## 結果の確認 + +- **`/sessions/`**:イベントタイムライン+セッションのスコアとディスパッチ試行からのエラーを表示する右サイドレール。キーに `evaluations:trigger` がある場合、エクスポートボタンの横に**再評価**ボタンが表示されます。`agent_end` を発行しなかったセッションや、新しい評価サービスをデプロイした後にスコアをリフレッシュする際に便利です。ダッシュボードは新しい結果をポーリングし、確認でき次第右サイドレールを更新します。 +- **`/sessions`**:フィルタリング可能なセッショングリッド。スコア列には各セッションの評価ステータスとスコアが一目でわかるように表示されます。 +- **`/dashboards`**:保存済みの評価ヘルスビュー(後述の[ダッシュボード](#dashboards)を参照)。 + +![セッションごとの評価ステータスピルとカラーコードのスコアバッジ(helpfulness、factuality、tool_efficiency、safety、coherence)が表示されたセッショングリッド](/agenteye/images/sessions-list.png) + +*セッショングリッドでは各実行の評価ステータスとスコアが一目でわかります。赤/黄/緑のバッジにより低スコアが目立ちます。* + +![評価スコアとディスパッチステータスが右サイドレールに表示されたセッション詳細ビュー](/agenteye/images/session-detail.png) + +*セッションを開くと、フルタイムラインと右サイドレールの評価スコアおよびディスパッチャーエラーが並べて表示されます。* + +--- + +## ダッシュボード + +**ダッシュボード**ページ(`/dashboards`)では、評価フィルターの組み合わせを名前付きの再利用可能なビューとして保存し、その評価スライスの状態を一目で確認できます。ダッシュボードは**組織全体で共有**されます。`dashboards:read` を持つ全員が同じセットを参照できます。 + +各ダッシュボードは以下を固定します: + +- **フィルター**:セッションページと同じコントロール(環境、ステータス、エージェント、ローリング時間ウィンドウ、スコア範囲フィルター(`key:min..max`))。 +- **表示設定**:どのスコアキーをフィーチャーするか、緑/黄/赤のヘルス閾値、表示するパネル、セッションごとの最新評価に折りたたむかどうか。 + +各カードには一致するセッション数、done/error/timeout の内訳、各フィーチャードスコアの平均値、小さなトレンドスパークラインが表示されます。ダッシュボードを開くとフルサイズのパネルが表示されます。**「セッションで開く」**をクリックすると、そのスライスに正確に事前フィルタリングされたセッションページに移動します。メトリクスはサーバーサイドで一致するセット全体に対して計算されます(`GET /evaluations/aggregate` 経由)。そのため数値はサンプリングではなく正確な値です。 + +![評価ディメンションごとの平均スコアバー、ツールの ok/error 内訳、トップツール、時間あたりのイベントトレンドが表示された評価ヘルスダッシュボード](/agenteye/images/dashboard-quality.png) + +**パーミッション:**表示には `dashboards:read` と `evaluations:read` の両方が必要です。作成・編集には `dashboards:write`、削除には `dashboards:delete` が必要です。ブートストラップ管理者はこれらをすべて自動的に受け取ります。 + +--- + +## トラブルシューティング + +**セッションは存在するが評価が作成されない。** サーバープロセスに `EVALUATOR_ENDPOINT` が設定されているか、サーバーと評価サービスが同じ `EVALUATOR_TOKEN` 値を共有しているか、評価サービスの `/health` エンドポイントがサーバーから到達可能かを確認してください。`EVALUATOR_ENDPOINT` が未設定の場合、パイプラインは無効です。 + +**実行中の評価が積み上がる。** `GET /evaluation-jobs` で実行中のキューを確認してください。各行の `attempt_count`、`next_attempt_at`、`last_error` を調べてください。よくある原因:評価サービスに到達できない、または 5xx を返している(バックオフでリトライ)、`EVALUATOR_TOKEN` が間違っている(401 は終端)、または `pending` を無限に返す非同期評価サービス(後述)。 + +**セッションは完了しているが終端評価が存在しない。** `GET /evaluation-jobs?status=polling` を照会してください。結果がまだ実行中の可能性があります。ジョブが `pending` で止まっている場合、サーバーが評価サービスに到達できていません。評価サービスが起動しており `EVALUATOR_TOKEN` が一致しているか確認してください。 + +**`HTTP 401 from evaluator: invalid bearer token`。** サーバーの `EVALUATOR_TOKEN` が評価サービスに設定された値と一致していません。両者は完全に同一である必要があります。 + +**非同期評価サービスが永続的に `pending` を返す。** サーバーは評価サービスが `done` または `error` を返すか、`EVALUATOR_MAX_POLL_DURATION_SECS`(デフォルト 1 時間)の上限に達するまで `GET /evaluate/{job_id}` をポーリングします。上限を超えると評価は `timeout` として記録され、実行中キューから削除されます。評価サービスが正当にデフォルトより長い時間を必要とする場合は、`EVALUATOR_MAX_POLL_DURATION_SECS` を引き上げてください。 \ No newline at end of file diff --git a/docs/ja/agenteye/getting-started.mdx b/docs/ja/agenteye/getting-started.mdx new file mode 100644 index 00000000..8297788b --- /dev/null +++ b/docs/ja/agenteye/getting-started.mdx @@ -0,0 +1,235 @@ +--- +title: "AgentEye のスタートガイド" +description: "AgentEye のスタートガイドドキュメント" +--- + + +このガイドでは、AgentEye のセットアップを一通り説明します。サーバーとダッシュボードのデプロイ、エージェントマシンへのコレクターのインストール、Python エージェントコードへのインストルメンテーションの追加まで順を追って解説します。 + +--- + +## AgentEye とは? + +AgentEye は **AI エージェント向けのセルフホスト型オブザーバビリティ・評価プラットフォーム**です。エージェントの動作、つまり実行の各ステップを記録し、完了した各実行の品質を自動的にスコアリングします。これにより、本番環境でのエージェントの挙動を把握し、ユーザーより先に品質低下を検知できます。 + +データは一方向に流れます。エージェントコードが **Python SDK** を通じて**イベント**を送出 → 軽量な**コレクター**デーモンがそれをまとめて**サーバー**に送信 → イベントと分析データが **ClickHouse** に保存(組織、ユーザー、API キー、ダッシュボード、保存クエリなどの運用状態は **Postgres** に保存)→ **ダッシュボード**ですべてを確認。 + +主な機能: + +- **Events(イベント)** — エージェント実行のステップごとの生の記録(ツール呼び出し、モデル呼び出し、フック、エラー)。 +- **Sessions(セッション)** — イベントを実行単位で集約した行。各実行は**自動評価**されスコアが付きます。 +- **Evaluations(評価)** — 独自のエバリュエーターサービスが生成する品質スコア。手動レビューなしで品質低下を検知できます。 +- **Queries & Dashboards(クエリ&ダッシュボード)** — データに対する保存済み ClickHouse SQL と、組織共有のダッシュボードへのグラフ表示。 +- **Alerts & Incidents(アラート&インシデント)** — 閾値ルールによるページング通知(メール、Slack、Webhook、ダッシュボード内)と、トリアージのためのインシデントワークフロー。 +- **CLI & AI アシスタント** — ターミナルクライアント(`agenteye`)と、自然言語で質問できるダッシュボード内アシスタント。 + +すべて自社インフラで運用できます。単一の Docker Compose スタック(本ガイド)、本番向け Kubernetes インストール、または単一のコロケーションポッドとして構成可能です。以降のガイドでは Compose スタックをエンドツーエンドでセットアップします。 + +--- + +## Step 1: 認証 + +AgentEye のすべてのアーティファクトは `agenteye-enterprise` GitHub 組織から配布されています。エンタープライズ開発者は独自の GitHub PAT を生成できます。具体的な手順と必要な権限については [enterprise-docs/github-token.md](/ja/agenteye/github-token) をご確認ください。 + +```bash +export AGENTEYE_TOKEN= + +# Docker を GHCR に対して認証する +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +--- + +## Step 2: サーバーとダッシュボードのデプロイ + +サーバーはコレクターからイベントを受け取りクエリ可能にします。ダッシュボードはそれらを確認する場所です。取り込まれたイベントと分析データは ClickHouse(必須の分析ストア)に保存され、Postgres には組織、ユーザー、API キー、ダッシュボード、保存クエリなどの運用状態が保存されます。 + +**公開された Compose ファイルをダウンロードします:** + +```bash +mkdir -p ./agenteye +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + https://raw.githubusercontent.com/agenteye-enterprise/releases/main/docker-compose.yml \ + -o ./agenteye/docker-compose.yml +cd agenteye +``` + +**シークレットを設定します:** + +デフォルトの `admin` 認証情報でデプロイが実行されないよう、`.env` ファイルを作成します。最低限 `ADMIN_KEY` と `POSTGRES_PASSWORD` を設定してください: + +```bash +POSTGRES_PASSWORD=your-db-password +ADMIN_KEY=your-admin-secret +``` + +後続のステップ(例:Step 3 の `curl`)から直接参照できるよう、現在のシェルにも `ADMIN_KEY` をエクスポートします: + +```bash +export ADMIN_KEY=your-admin-secret +``` + +**スタックを起動します:** + +```bash +docker compose up -d +``` + +これにより、必須の ClickHouse 分析ストアとオプションの Redis キャッシュを含む完全なスタックが、サーバーおよびダッシュボードとともに起動します。サーバーの起動には ClickHouse が正常に動作している必要があります。 + +サーバーは `http://localhost:8080` で、ダッシュボードは `http://localhost:3000` でリクエストを待ち受けます。 + +本番デプロイ(カスタム Postgres、TLS、リバースプロキシ)については [enterprise-docs/deployment.md](/ja/agenteye/deployment) をご参照ください。 + +--- + +## Step 3: コレクター用 API キーの作成 + +各コレクターはスコープ付き API キーで認証します。Step 2 で設定した `ADMIN_KEY` を使用して作成します: + +```bash +curl -s -X POST http://localhost:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{"name":"prod-collector","key":"your-collector-secret","permissions":["events:add"]}' +``` + +`key` の値は自分で指定します。Step 4 のコレクター設定で使用します。キー管理の詳細については [enterprise-docs/api-keys.md](/ja/agenteye/api-keys) をご参照ください。 + +--- + +## Step 4: コレクターのインストール + +AI エージェントを実行するすべてのマシンにコレクターデーモンをインストールします。 + +**バイナリをダウンロードします(Linux x86_64):** + +```bash +VERSION=0.0.1-beta.13 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "collector/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-collector-linux-x86_64' +chmod +x agenteye-collector-linux-x86_64 +sudo mv agenteye-collector-linux-x86_64 /usr/local/bin/agenteye-collector +``` + +> これは **Linux x86_64** ビルドをダウンロードします。macOS(Apple Silicon または Intel)、Linux arm64、Docker / systemd / launchd のセットアップについては [collector-installation.md](/ja/agenteye/collector-installation) を参照してください。各プラットフォーム向けのダウンロードが記載されています。上記コマンドでインストールされる Linux バイナリは他の環境では動作しません。 + +**設定します:** + +```bash +mkdir -p ~/.agenteye +cat > ~/.agenteye/config.json </…`)がプレフィックスとして付きます。 + +- **Queries**(`//queries`):イベントと評価に対する保存済み再利用可能クエリのライブラリから開始します(組み込みプリセットと独自クエリ)… + +![保存済みクエリライブラリ:組み込みプリセットとカスタムクエリを並べたグリッド表示](/agenteye/images/queries.png) + + …そして SQL コンポーザーで開いて調整し、ライブ結果を確認できます: + +![保存済みクエリを実行する SQL クエリコンポーザー。スキーマサイドバーとライブ結果グリッド付き](/agenteye/images/query-lab.png) + +- **Dashboards**(`//dashboards`):クエリを折れ線・棒・面・円グラフのタイルとして組織共有ダッシュボードにピン留めできます。 + +![保存済みクエリで構築したダッシュボード:時間別イベント数の折れ線グラフ、タイプ別エラーの棒グラフ、レイテンシの面グラフ、モデル別トークン数](/agenteye/images/dashboard-fleet.png) + +- **Alerts**(`//alerts`):任意の閾値をページングルールに昇格し、メール・Slack・Webhook・ダッシュボード内で通知を受け取れます。[enterprise-docs/alerts.md](/ja/agenteye/alerts) をご参照ください。 + +--- + +## 次のステップ + +- [Deployment(デプロイ)](/ja/agenteye/deployment):本番環境向けの堅牢化 +- [API Keys(API キー)](/ja/agenteye/api-keys):アクセス管理 +- [Troubleshooting(トラブルシューティング)](/ja/agenteye/troubleshooting):問題の診断 \ No newline at end of file diff --git a/docs/ja/agenteye/github-token.mdx b/docs/ja/agenteye/github-token.mdx new file mode 100644 index 00000000..1703c639 --- /dev/null +++ b/docs/ja/agenteye/github-token.mdx @@ -0,0 +1,132 @@ +--- +title: "GitHub トークンの設定" +description: "AgentEye GitHub トークン設定のドキュメント。" +--- + + +GitHub 個人アクセストークン(PAT)は、すべての AgentEye アーティファクトを利用可能にする唯一の認証情報です。1つのトークンで Docker イメージのプル、リリースバイナリのダウンロード、Python ホイールのインストールが可能になり、コンポーネントごとのログインや共有シークレットの配布は不要です。すべての AgentEye アーティファクトは `agenteye-enterprise` GitHub 組織から配布されます。組織にアクセス権が付与されたら、各開発者またはオペレーターが自分のトークンを生成・ローテーションするため、アクセスはユーザーごとに監査・失効が可能です。 + +マシンごとに1回、トークンを環境変数と Docker 認証情報として設定します: + +```bash +export AGENTEYE_TOKEN= +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +> **ユーザー名について:** GHCR は `docker login` のユーザー名を無視し、トークンのみで認証するため、空でない値であれば何でも機能します。このドキュメントでは簡潔さのために `-u x` を使用しています。Kubernetes のイメージプルシークレットを作成するデプロイメントマニフェストでは、`agenteye-enterprise` のようなより分かりやすいユーザー名を使用することもあります。どちらも受け付けられます。 + +--- + +## オプション A: クラシックトークン(推奨) + +GHCR の `docker login` およびイメージプローのフローはクラシックトークンに対して最も広く、一貫したサポートを提供しているため、クラシックトークンは AgentEye に最も信頼性の高い選択肢です。必要なものはすべて2つのスコープでカバーされ(イメージのプルとリリースアセットのダウンロード)、一度認証すれば、レジストリの問題をトラブルシューティングすることなく作業を進められます。そのうちの1つ `read:packages` は真に読み取り専用ですが、もう1つの `repo` はプライベートなリリースアセットへのアクセスを許可する唯一のクラシックスコープであり、意図的に広範な権限を持っています。GitHub はこれをプライベートリポジトリへの完全な制御(読み取りと書き込み)として定義しています。 + +### 1. トークンの作成 + +**GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic) → Generate new token (classic)** に移動します。 + +| フィールド | 値 | +|---|---| +| **Note** | `agenteye-<マシン名またはチーム名>`(例: `agenteye-prod-server`) | +| **Expiration** | セキュリティポリシーに適した有効期限を設定してください。90日が合理的なデフォルトです | + +> **ラベルについて:** GitHub はクラシックトークンではこのフィールドを **Note**、細粒度トークンでは **Token name** と表示しますが、どちらも同じ目的を果たします: 後の監査と失効のための人間が読みやすい識別子です。 + +### 2. スコープの選択 + +| スコープ | 必要な理由 | +|---|---| +| `read:packages` | `ghcr.io/agenteye-enterprise/` から Docker イメージをプルし、パッケージアセットをダウンロードする | +| `repo` | `agenteye-enterprise/releases` からプライベートリポジトリのコンテンツ、生ファイル、リリースアセットを読み取る。これは GitHub の広範な「プライベートリポジトリへの完全な制御」スコープ(読み取りと書き込み)であり、読み取り専用スコープではありませんが、プライベートなリリースアセットへのアクセスを許可する唯一のクラシックスコープです | + +他のスコープは不要です。 + +### 3. トークンの生成とコピー + +**Generate token** をクリックし、表示された値をすぐにコピーしてください。表示されるのは一度だけです。シークレットマネージャーまたは環境に保存してください。 + +--- + +## オプション B: 細粒度トークン + +細粒度トークンは特定のリポジトリと権限にアクセスを限定するため、最小権限の原則に最も適した選択肢です。組織のセキュリティポリシーで細粒度トークンが義務付けられている場合はこちらを選択してください。 + +> **注意:** GHCR の細粒度トークンのサポートはクラシックトークンほど一貫していません。これらの手順に従った後で `docker login` や `docker pull` が失敗する場合は、クラシックトークン(オプション A)にフォールバックしてください。 + +### 1. トークンの作成 + +**GitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokens → Generate new token** に移動します。 + +| フィールド | 値 | +|---|---| +| **Token name** | `agenteye-<マシン名またはチーム名>`(例: `agenteye-prod-server`) | +| **Expiration** | セキュリティポリシーに適した有効期限を設定してください。90日が合理的なデフォルトです | +| **Resource owner** | `agenteye-enterprise` | +| **Repository access** | **Only select repositories** → `agenteye-enterprise/releases` | + +### 2. リポジトリ権限の設定 + +**Permissions → Repository permissions** で以下を設定します: + +| 権限 | アクセス | +|---|---| +| **Contents** | Read-only | +| **Packages** | Read-only | + +その他の権限はすべて **No access** のままにできます。 + +> **注意:** コンテナイメージ(`ghcr.io/agenteye-enterprise/...`)がリポジトリにリンクされたパッケージではなく、組織レベルのパッケージとして公開されている場合、リポジトリスコープの権限だけでは Docker ログインが失敗する可能性があります。その場合は、組織レベルの権限を追加してください: **Permissions → Organization permissions → Packages: Read-only**。 + +### 3. 各権限で許可される操作 + +| 権限 | 用途 | +|---|---| +| Contents: Read-only | `agenteye-enterprise/releases` から `docker-compose.yml`、リリースバイナリ、Python ホイールをダウンロードする | +| Packages: Read-only | `ghcr.io/agenteye-enterprise/` から Docker イメージをプルする | + +### 4. トークンの生成とコピー + +**Generate token** をクリックし、表示された値をすぐにコピーしてください。表示されるのは一度だけです。シークレットマネージャーまたは環境に保存してください。 + +--- + +## トークンのローテーション + +定期的にトークンをローテーションすることで、アクセスの監査性が保たれ、認証情報が漏洩した場合の影響範囲を限定できます。トークンはいつでも期限切れや失効が発生する可能性があるため、ローテーションは認証を維持するための通常の手順です。ローテーションの手順: + +1. 上記の手順で新しいトークンを生成します。 +2. 環境またはシークレットマネージャーの `AGENTEYE_TOKEN` を更新します。 +3. Docker を再認証します: `echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin` +4. GitHub → Settings → Developer settings → Personal access tokens で古いトークンを失効させます。トークンの種類に合わせて **Tokens (classic)** または **Fine-grained tokens** のサブページを開き、削除してください。 + +--- + +## トークンの確認 + +デプロイメントに組み込む前にトークンが正常に動作することを確認してください。これにより、認証エラーをデプロイ中ではなくこの段階で検出できます。各コマンドで上記のスコープの1つを確認します: + +```bash +# Packages scope - authenticate Docker against GHCR +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin + +# Contents scope - fetch a raw release file +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + https://raw.githubusercontent.com/agenteye-enterprise/releases/main/docker-compose.yml \ + -o /tmp/agenteye-compose-check.yml +``` + +`docker login` が成功すればパッケージスコープが確認でき、ファイルがダウンロードされればコンテンツスコープが確認できます。 + +--- + +## トラブルシューティング + +| 症状 | 考えられる原因 | 対処法 | +|---|---|---| +| `docker login` が 401 を返す | トークンに `Packages: Read-only`(細粒度)または `read:packages`(クラシック)が不足している | パッケージスコープを追加して再生成する | +| GitHub の生 URL で `curl` が 404 を返す | トークンに `Contents: Read-only` または `repo` スコープが不足している | コンテンツスコープを追加して再生成する | +| `gh release download` が 403 を返す | トークンが `agenteye-enterprise/releases` に対して承認されていない | 細粒度トークンのリポジトリアクセスにそのリポジトリが含まれているか確認するか、`repo` スコープを持つクラシックトークンを使用する | +| トークンは受け付けられるがイメージが見つからない | 細粒度トークンに組織レベルのパッケージ権限がない | 組織レベルの `Packages: Read-only` 権限を追加する | + +アクセスに関する問題は `support@exosphere.host` までお問い合わせください。 \ No newline at end of file diff --git a/docs/ja/agenteye/health-monitoring.mdx b/docs/ja/agenteye/health-monitoring.mdx new file mode 100644 index 00000000..506a3058 --- /dev/null +++ b/docs/ja/agenteye/health-monitoring.mdx @@ -0,0 +1,87 @@ +--- +title: "ヘルスモニタリング" +description: "AgentEye ヘルスモニタリングのドキュメントです。" +--- + +AgentEye のデプロイメント**自体**がダウンまたは劣化状態にあるときを、エージェントの誤動作とは独立して把握できます。検出は **Kubernetes ネイティブ**であり、重要な点として **AgentEye から独立しています**。Kubernetes コントロールプレーンからポッドの状態を読み取り、AgentEye のハード依存関係を確認するため、サーバー、ClickHouse、または Postgres がダウンしている場合でも検知が機能します。 + +2 つのレイヤーがあります。1 つ目は組み込み済み、2 つ目はオプトイン式です。 + +## 1. 依存関係を考慮したレディネス(組み込み済み) + +サーバーは意図的に異なる役割を持つ 2 つのプローブエンドポイントを公開しています: + +| エンドポイント | プローブ | 確認内容 | 認証 | +|---|---|---|---| +| `GET /health` | liveness | プロセスが生存している(常に `{"status":"ok"}` を返す) | なし | +| `GET /ready` | readiness | 実際にリクエストを処理できるか:**Postgres + ClickHouse** に疎通できるか | なし | + +`/ready` は両方のハード依存関係に疎通できる場合、`"status":"ready"` と各チェック `"ok"` を含む `200` を返します。どちらかに疎通できない場合は `"status":"not_ready"` を含む `503` を返します。いずれのレスポンスにも小さなボディが含まれます: + +```json +{ "status": "not_ready", + "checks": { "postgres": "ok", "clickhouse": "down", "redis": "not_configured" } } +``` + +Redis はサーバーが機能を低下させながらも動作し続けられるオプションのキャッシュであるため、情報として報告されますが、**レディネス判定に影響しません**。キャッシュが設定されている場合は `"ok"`、設定されていない場合は `"not_configured"` と表示され、`"down"` になることはありません。 + +バンドルされた Kubernetes マニフェストでは、**readiness** プローブが `/ready` を指し、**liveness** は `/health` のままです。この構成により、*実行中だがデータベースに接続できない*サーバーは Service から切り離されて `NotReady` 状態として表示され(以下のクラスター監視でアラートを発火できます)、liveness は軽量なままに保たれるため、一時的な依存関係の瞬断でポッドが再起動されることはありません。プローブには十分な失敗閾値が設定されているため、一時的な瞬断でレプリカがローテーションから外れてフラッピングすることもありません。 + +## 2. Robusta によるポッド障害アラート(オプトイン) + +[Robusta](https://github.com/robusta-dev/robusta) は Kubernetes ネイティブのモニターで、API サーバーを監視し、ポッドの障害(`CrashLoopBackOff`、`OOMKilled`、`ImagePullBackOff`、`Pending`/`NotReady`、`Failed`、エビクション)を Slack に通知します。AgentEye に問い合わせるのではなくコントロールプレーンを監視するため、AgentEye が全くリクエストを処理できない状態でもアラートを発火します。 + +Robusta はリリースバンドルのオプトインアドオンとして提供されています。以下に示す標準の Robusta Helm チャートと小さな values ファイルを使用して有効化します: + +1. チャートリポジトリを追加し、対象チャンネル用の Slack **ボットトークン**(`xoxb-…`)を取得します: + + ```bash + helm repo add robusta https://robusta-charts.storage.googleapis.com + helm repo update + ``` + + 以下の設定ではすべてをクラスター内に閉じているため(`disableCloudRouting: true`)、トークンはセルフホスト型の Slack アプリから取得します。`https://api.slack.com/apps` でアプリを作成し、`chat:write` ボットスコープを追加してワークスペースにインストール後、**Bot User OAuth Token**(`xoxb-…`)をコピーし、ボットをチャンネルに招待してください(`/invite @your-app`)。 + +2. デプロイメントごとのラベル(`clusterName`)と Slack チャンネルを指定した `values.yaml` を作成します。スコープは `agenteye` 名前空間に限定します: + + ```yaml + clusterName: "acme-prod" # デプロイメントごとのラベル。すべてのアラートに付与される + enablePrometheusStack: false # ポッドクラッシュアラートのみ。メトリクススタックは不要 + disableCloudRouting: true # クラスター内から直接 Slack に配信 + sinksConfig: + - slack_sink: + name: vendor_slack + slack_channel: "agenteye-fleet-health" + api_key: "REPLACE_WITH_SLACK_BOT_TOKEN" # xoxb-… (--set またはシークレットの使用を推奨) + scope: + include: + - namespace: [agenteye] # AgentEye 名前空間のアラートのみ。広げる場合は削除 + ``` + +3. `--version` を既知の安定した Robusta チャートリリースに固定してインストールします([リリース一覧](https://github.com/robusta-dev/robusta/releases))。未テストのチャートがインストールされることを防ぐためです: + + ```bash + helm install robusta robusta/robusta \ + --namespace robusta --create-namespace \ + --version \ + -f values.yaml \ + --set sinksConfig[0].slack_sink.api_key=$ROBUSTA_SLACK_TOKEN + ``` + +### 報告される内容 + +- Kubernetes の**ポッド状態**(どの AgentEye ポッドがなぜ障害を起こしているか)と各ポッドの**イメージタグ**(実行中のコンポーネントの**バージョン**)。 +- **AgentEye のイベントデータも顧客データも**クラスター外に出ることはありません。 +- バンドルされた values は **`agenteye` 名前空間**にアラートを限定しているため、同じクラスター上の無関係なワークロードは報告されません。 + +### すべてのデプロイメントを一箇所で管理 + +各デプロイメントの Robusta を**一つの共有 Slack チャンネル**に向け、それぞれに固有の `clusterName` を設定します。すべてのアラートにそのラベルが付与されるため、一つのチャンネルでフリート全体の健全性を確認でき、どのデプロイメントに問題があるかを一目で把握できます。 + +### クラスター全体の障害 + +純粋にクラスター内で動作するウォッチャーは、**クラスター全体またはネットワーク全体の障害**を報告することができません(クラスターと一緒にダウンしてしまうため)。その場合はオプションの **Robusta UI シンク**を有効化してください。`disableCloudRouting: false` に設定し、`sinksConfig` に `robusta_sink`(`robusta gen-config` で取得したトークンを使用)を追加します。これにより、集約されたマルチクラスターダッシュボードが追加され、チェックインが停止したクラスターにフラグが立てられます。 + +## トラブルシューティング + +「アラートが届かない」および「サーバーが `NotReady` をフラッピングし続ける」については、[enterprise-docs/troubleshooting.md](/ja/agenteye/troubleshooting) の **ヘルスモニタリング** セクションを参照してください。 \ No newline at end of file diff --git a/docs/ja/agenteye/kubernetes-deployment.mdx b/docs/ja/agenteye/kubernetes-deployment.mdx new file mode 100644 index 00000000..475d0f07 --- /dev/null +++ b/docs/ja/agenteye/kubernetes-deployment.mdx @@ -0,0 +1,934 @@ +--- +title: "Kubernetes デプロイメントガイド" +description: "AgentEye Kubernetes デプロイメントガイドのドキュメントです。" +--- + + +このガイドでは、AgentEye の全スタックを専用の Kubernetes クラスターにデプロイします。 + +- **ClickHouse 24.8** -- イベントおよびエバリュエーション分析の正規ストア(StatefulSet、100Gi 永続ボリューム)。必須:これがないとサーバーは起動しません。 +- **PostgreSQL 16** -- 組織、API キー、ユーザー、ダッシュボード、保存済みクエリ、認証のリレーショナル/メタデータストア(StatefulSet、50Gi 永続ボリューム) +- **Redis 7.2** -- オプションの共有キャッシュおよびレート制限バックエンド。利用不可の場合もサーバーとダッシュボードはグレースフルに機能低下します +- **AgentEye Server** -- イベント取り込み、分析、キー管理用の Rust API(2 レプリカ) +- **AgentEye Dashboard** -- Next.js 製 Web UI(2 レプリカ) +- **AI アシスタント(エージェントサービス)** -- ポート 9100 で動作するダッシュボード内オプションの読み取り専用アシスタント。LLM エンドポイントが設定されるまで無効状態 +- **Traefik(パブリック)** -- コレクタートラフィック用の Ingress コントローラー(mTLS 保護) +- **Traefik(ダッシュボード)** -- ダッシュボード用の Ingress コントローラー(VPN/IP 許可リストのみ) +- **cert-manager** -- TLS 証明書および mTLS CA +- **バックアップ CronJob** -- 毎日 UTC 03:00 に PostgreSQL と ClickHouse を同時にダンプ +- **証明書更新モニター** -- クライアント証明書の有効期限が近づくとアラートを送信 + +**推定所要時間:** 初回デプロイで 60〜90 分。 + +Exosphere がこれらすべてをお客様に代わって管理するマネージドデプロイメントモデルについては、[enterprise-docs/managed-deployment.md](/ja/agenteye/managed-deployment) をご覧ください。 + +--- + +## 前提条件 + +開始前に各確認コマンドを実行してください。すべてのチェックがパスする必要があります。 + +| 要件 | 最低バージョン | 確認コマンド | 期待される結果 | +|---|---|---|---| +| Kubernetes クラスター | 1.27+ | `kubectl version` | Server Version >= v1.27 | +| Kustomize(kubectl 同梱) | Kustomize v1.14+(kubectl 1.27+ に内包) | `kubectl kustomize --help` | 使用方法テキストが表示される | +| Helm | v3 | `helm version` | `Version:"v3.x.x"` | +| cluster-admin RBAC | -- | `kubectl auth can-i create namespaces` | `yes` | +| デフォルト StorageClass | -- | `kubectl get storageclass` | `(default)` と表示された行が少なくとも 1 つある | +| LoadBalancer サポート | -- | クラウド依存(EKS、GKE、AKS はデフォルトで対応) | -- | +| GitHub PAT | -- | `echo $AGENTEYE_TOKEN` | 空でないこと([enterprise-docs/github-token.md](/ja/agenteye/github-token) 参照) | +| openssl | -- | `openssl version` | OpenSSL 1.x または 3.x | +| クラウドストレージバケット | -- | PostgreSQL と ClickHouse のバックアップ用(S3、GCS、または Azure Blob) | -- | + +**クラスターサイジング:** 最低 3 ノード、各ノード 4 vCPU / 8 GB RAM。全要件については [enterprise-docs/managed-deployment.md](/ja/agenteye/managed-deployment) を参照してください。 + +### 一括チェックの実行 + +```bash +echo "--- Prerequisites Check ---" +kubectl version --client -o yaml 2>/dev/null | grep -q gitVersion && echo "PASS: kubectl" || echo "FAIL: kubectl not found" +helm version --short 2>/dev/null | grep -q v3 && echo "PASS: helm v3" || echo "FAIL: helm v3 not found" +kubectl auth can-i create namespaces 2>/dev/null | grep -q yes && echo "PASS: cluster-admin" || echo "FAIL: no cluster-admin" +kubectl get storageclass 2>/dev/null | grep -q default && echo "PASS: default StorageClass" || echo "FAIL: no default StorageClass" +[ -n "$AGENTEYE_TOKEN" ] && echo "PASS: AGENTEYE_TOKEN set" || echo "FAIL: AGENTEYE_TOKEN not set" +openssl version >/dev/null 2>&1 && echo "PASS: openssl" || echo "FAIL: openssl not found" +echo "---" +``` + +### デプロイメント構成 + +**取り込みエンドポイント**はお客様が管理するホスト名(例:`ingest.your-company.example`)で提供されます。cert-manager は HTTP-01 チャレンジにより Let's Encrypt からパブリック信頼済み TLS 証明書を要求するため、コレクターはシステムトラストストアでサーバー証明書を検証します。カスタマーごとの CA ピン留めは不要です。 + +**ダッシュボードエンドポイント**も同様の仕組みです。お客様が管理する別のホスト名(例:`agenteye.your-company.example`)でダッシュボード Traefik LoadBalancer に向けて提供され、cert-manager がその LoadBalancer 経由で Let's Encrypt 証明書を発行します。ブラウザには警告なしで信頼済み証明書が表示されます。 + +> **証明書の発行と更新は HTTP-01 チャレンジで検証されます。** そのため、両方の LoadBalancer がポート 80 でインターネットから到達可能である必要があります。ダッシュボード LoadBalancer を IP 制限する必要がある場合は、事前にサポートと連携して DNS-01 ソルバーを設定してください。そうしないと更新が無音で失敗し、証明書が期限切れになります。 + +--- + +## マニフェストの取得 + +```bash +git clone https://x:${AGENTEYE_TOKEN}@github.com/agenteye-enterprise/releases.git +cd releases/deploy +``` + +**確認:** + +```bash +ls base/kustomization.yaml +``` + +期待される結果:ファイルが存在すること。存在しない場合はクローンが失敗しています。`AGENTEYE_TOKEN` を確認してください。 + +**ディレクトリ構造:** + +``` +deploy/ + base/ 共有 Kustomize ベース(すべての K8s リソース) + overlays/ クラスター固有のオーバーライド(イメージタグ、ホスト名、リソース) + third-party/ Traefik、cert-manager、(オプション)Robusta ヘルスモニタリング用の Helm バリューファイル +``` + +**base** にはフルデプロイメントに必要なすべてのリソースが含まれており、フェーズ 3.1 で設定する 2 つのパブリックホスト名の Let's Encrypt 証明書も含まれています。**overlay** は特定の環境(カスタムイメージタグ、リソース制限、環境変数設定など)に合わせてベースにパッチを適用します。**third-party** ディレクトリには外部インフラ用の Helm バリューファイルが含まれています。 + +> **ヘルスモニタリング(オプション):** サーバーの readiness プローブはすでに Postgres と ClickHouse のヘルス状態を反映しており、`third-party/robusta/` を使用すると Kubernetes ネイティブのポッド障害アラートを Slack にオプトインで追加できます。[enterprise-docs/health-monitoring.md](/ja/agenteye/health-monitoring) を参照してください。 + +--- + +## フェーズ 1 -- サードパーティインフラストラクチャ(約 30 分) + +### 1.1 cert-manager のインストール + +cert-manager は HTTPS 用の TLS 証明書と、mTLS クライアント証明書に使用するプライベート CA を管理します。 + +```bash +helm repo add jetstack https://charts.jetstack.io +helm repo update + +helm install cert-manager jetstack/cert-manager \ + --namespace cert-manager --create-namespace \ + --set crds.install=true +``` + +**確認:** + +```bash +kubectl get pods -n cert-manager +``` + +期待される結果:3 つのポッドがすべて `Running` 状態 -- `cert-manager`、`cert-manager-cainjector`、`cert-manager-webhook`。 + +```bash +kubectl get crds | grep cert-manager +``` + +期待される結果:`certificates.cert-manager.io`、`clusterissuers.cert-manager.io`、`issuers.cert-manager.io` が少なくとも表示される。 + +**失敗した場合:** ポッドが `CrashLoopBackOff` 状態の場合は通常、CRD がインストールされていません。`--set crds.install=true` を付けて再実行してください。Webhook ポッドの readiness に失敗する場合は、30 秒待ってから再確認してください。起動に少し時間がかかる場合があります。 + +--- + +### 1.2 Traefik(パブリック取り込みコントローラー)のインストール + +この Traefik インスタンスは**外部** LoadBalancer でコレクタートラフィックを処理します。TLS を終端し、取り込みエンドポイントで mTLS(クライアント証明書の検証)を強制します。 + +```bash +helm repo add traefik https://traefik.github.io/charts +helm repo update + +helm install traefik-public traefik/traefik \ + --namespace traefik-public --create-namespace \ + --version 39.0.8 \ + -f third-party/traefik/values-public.yaml +``` + +**確認:** + +```bash +kubectl get pods -n traefik-public +``` + +期待される結果:1 つのポッドが `Running` 状態。 + +```bash +kubectl get ingressclass traefik-public +``` + +期待される結果:IngressClass が存在すること(デフォルトクラスではありません)。 + +**失敗した場合:** `kubectl describe pod -n traefik-public ` でイメージプルエラーやリソース制約を確認してください。 + +--- + +### 1.3 Traefik(ダッシュボードコントローラー)のインストール + +この Traefik インスタンスは専用の LoadBalancer でダッシュボードを提供し、IP 許可リストにより制限されます。 + +> **このインスタンスには 2 種類の許可リストメカニズムが含まれています。** このガイドでは `values-dashboard.yaml` を使用します。これはポータブルな `service.loadBalancerSourceRanges` フィールドでアクセスを制限します。`service.beta.kubernetes.io/aws-load-balancer-source-ranges` アノテーションを好む AWS 環境向けに、`values-internal.yaml` も並行して提供されています。どちらか一方を選択して一貫して使用してください。以下の手順では `values-dashboard.yaml` を前提としています。 + +**インストール前に**、`third-party/traefik/values-dashboard.yaml` を編集して許可する送信元 IP を設定してください。`loadBalancerSourceRanges` フィールドがダッシュボードへのアクセス可能な IP を制御します。デフォルトは `0.0.0.0/0`(全 IP)です。VPN、オフィス、または既知の出口 IP に制限してください。 + +#### 単一 IP の許可 + +```yaml +service: + loadBalancerSourceRanges: + - "/32" +``` + +#### 複数 IP の許可 + +IP または CIDR ブロックごとに 1 エントリを追加します。`/32` サフィックスは単一の IPv4 アドレスに一致し、CIDR ブロック(例:`/24`)は範囲に一致します。個別 IP と範囲を自由に組み合わせることができます。 + +```yaml +service: + loadBalancerSourceRanges: + - "203.0.113.10/32" # office gateway + - "203.0.113.11/32" # backup office gateway + - "198.51.100.0/24" # VPN pool + - "192.0.2.50/32" # on-call engineer home IP +``` + +リストを管理する際のヒント: + +- 1 行に 1 エントリを記載し、各 IP の所有者や用途を示す短い `#` コメントを追加してください。将来のオペレーターがそのエントリが引き続き必要かどうかを判断する際に役立ちます。 +- 常に CIDR 表記を使用してください。`203.0.113.10` のような裸の IP はクラウドプロバイダーに拒否されます。`203.0.113.10/32` のように記述してください。 +- IPv6 の場合は、同等の `/128`(単一アドレス)またはそれ以上の CIDR を使用してください(例:`2001:db8::1/128`)。IPv6 送信元範囲をサポートしていないクラウドプロバイダーもあります。プロバイダーの LoadBalancer ドキュメントを確認してください。 +- このリストは **OR** 条件です。送信元がいずれかのエントリに一致すればトラフィックが許可されます。 + +ファイルを編集したら、以下の `helm install` に進んでください。コントローラーがすでにインストールされている場合は、同じフラグで `helm upgrade` を実行するか、実行時に Service を直接パッチしてください(次のセクション)。 + +#### 実行時の許可リスト更新 + +Helm アップグレードなしに、Service を直接パッチして許可 IP を変更できます。**パッチはリスト全体を置き換えます。** 新しい IP だけでなく、保持したい既存の IP もすべて含めてください。 + +リストを新しい IP セットで置き換えるには: + +```bash +kubectl patch svc traefik-dashboard -n traefik-dashboard \ + -p '{"spec":{"loadBalancerSourceRanges":["203.0.113.10/32","198.51.100.0/24","192.0.2.50/32"]}}' +``` + +既存のエントリを失わずに IP を**追記**するには、まず現在のリストを確認してから、統合したセットでパッチします: + +```bash +# 1. 現在の許可リストを確認 +kubectl get svc traefik-dashboard -n traefik-dashboard \ + -o jsonpath='{.spec.loadBalancerSourceRanges}' + +# 2. 新しい IP を含む完全なリストでパッチ +kubectl patch svc traefik-dashboard -n traefik-dashboard \ + -p '{"spec":{"loadBalancerSourceRanges":["/32","/32","/32"]}}' +``` + +> 実行時のパッチは `values-dashboard.yaml` には反映されません。将来の Helm アップグレードでも変更を維持するには、バリューファイルも更新してコミットしてください。 + +インストール: + +```bash +helm install traefik-dashboard traefik/traefik \ + --namespace traefik-dashboard --create-namespace \ + --version 39.0.8 \ + -f third-party/traefik/values-dashboard.yaml +``` + +**確認:** + +```bash +kubectl get pods -n traefik-dashboard +``` + +期待される結果:1 つのポッドが `Running` 状態。 + +```bash +kubectl get ingressclass traefik-dashboard +``` + +期待される結果:IngressClass が存在すること。 + +--- + +### 1.4 LoadBalancer の待機 + +次のステップに進む前に、両方の Traefik インスタンスに外部 IP が割り当てられている必要があります。 + +```bash +kubectl get svc -n traefik-public +kubectl get svc -n traefik-dashboard +``` + +**確認:** 両方のサービスに `EXTERNAL-IP` が表示されていること(`` でないこと)。 + +まだ pending の場合は、割り当てを待機します: + +```bash +kubectl get svc -n traefik-public -w +``` + +IP が表示されたら `Ctrl+C` を押してください。IP の割り当ては通常 2〜5 分かかります。 + +**失敗した場合:** 10 分経過しても `` の場合、クラウドプロバイダーが LoadBalancer をプロビジョニングできていない可能性があります。サブネットタグ(EKS では `kubernetes.io/role/elb` が必要)、VPC 設定、サービスクォータ、および内部インスタンスに正しい内部 LB アノテーションが設定されているかを確認してください。 + +--- + +## フェーズ 2 -- シークレットの作成(約 10 分) + +すべてのシークレットはアプリケーションのデプロイ前に手動で作成します。これにより、機密情報がマニフェストファイルに含まれることがありません。 + +### 2.1 ネームスペースの作成 + +```bash +kubectl create namespace agenteye +``` + +**確認:** + +```bash +kubectl get namespace agenteye +``` + +期待される結果:ステータスが `Active`。 + +--- + +### 2.2 イメージプルシークレット + +このシークレットは `ghcr.io` への認証に使用し、AgentEye コンテナイメージをプルします。PAT の生成方法については [enterprise-docs/github-token.md](/ja/agenteye/github-token) を参照してください。 + +```bash +kubectl create secret docker-registry agenteye-image-pull \ + --namespace agenteye \ + --docker-server=ghcr.io \ + --docker-username=agenteye-enterprise \ + --docker-password="${AGENTEYE_TOKEN}" +``` + +**確認:** + +```bash +kubectl get secret agenteye-image-pull -n agenteye -o jsonpath='{.type}' +``` + +期待される結果:`kubernetes.io/dockerconfigjson`。 + +**詳細確認** -- トークンが実際にイメージをプルできるかを検証します: + +オーバーレイの `kustomization.yaml` に固定されているサーバーイメージタグを使用してください(現在、バンドルされている `acme` オーバーレイとベースデプロイメントの両方で `v0.0.1-beta.48`)。リリース間でこのチェックがずれないよう、実際にデプロイするタグに置き換えてください: + +```bash +kubectl run test-pull \ + --image=ghcr.io/agenteye-enterprise/server:v0.0.1-beta.48 \ + --overrides='{"spec":{"imagePullSecrets":[{"name":"agenteye-image-pull"}]}}' \ + --restart=Never -n agenteye --command -- echo ok + +# 数秒待ってプルを待機してから: +kubectl logs test-pull -n agenteye +kubectl delete pod test-pull -n agenteye +``` + +期待される結果:ログに `ok` が出力される。 + +**失敗した場合:** `ErrImagePull` または `401 Unauthorized` は PAT が無効か `read:packages` スコープがないことを意味します。[enterprise-docs/github-token.md](/ja/agenteye/github-token) を再確認してください。 + +--- + +### 2.3 PostgreSQL 認証情報 + +```bash +POSTGRES_PASSWORD=$(openssl rand -hex 24) + +kubectl create secret generic agenteye-postgres \ + --namespace agenteye \ + --from-literal=POSTGRES_USER=postgres \ + --from-literal=POSTGRES_PASSWORD="${POSTGRES_PASSWORD}" \ + --from-literal=POSTGRES_DB=agenteye +``` + +> **重要:** パスワードの生成には `-hex`(`-base64` ではなく)を使用します。Base64 出力には `+`、`/`、`=` が含まれる可能性があり、`DATABASE_URL` 接続文字列が壊れます。詳細は [enterprise-docs/troubleshooting.md](/ja/agenteye/troubleshooting) を参照してください。 + +> **`POSTGRES_PASSWORD` はすぐにシークレットマネージャーに保存してください。** バックアップからの復元やデータベースへの直接接続時に必要になります。 + +**確認:** + +```bash +kubectl get secret agenteye-postgres -n agenteye +``` + +期待される結果:シークレットが存在すること。 + +```bash +kubectl get secret agenteye-postgres -n agenteye \ + -o jsonpath='{.data.POSTGRES_PASSWORD}' | base64 -d | wc -c +``` + +期待される結果:`48`(24 hex バイト = 48 文字)。 + +--- + +### 2.4 管理者 API キー + +```bash +ADMIN_KEY=$(openssl rand -hex 32) + +kubectl create secret generic agenteye-admin-key \ + --namespace agenteye \ + --from-literal=ADMIN_KEY="${ADMIN_KEY}" +``` + +管理者キーはブートストラップ用の認証情報です。サーバーは起動のたびに全権限付きでこのキーをアップサートします。フェーズ 7 でコレクター用のスコープ付きキーを作成する際に使用します。完全な権限モデルについては [enterprise-docs/api-keys.md](/ja/agenteye/api-keys) を参照してください。 + +> **`ADMIN_KEY` はすぐにシークレットマネージャーに保存してください。** + +**確認:** + +```bash +kubectl get secret agenteye-admin-key -n agenteye +``` + +期待される結果:シークレットが存在すること。 + +--- + +### 2.5 認証設定(ダッシュボードログイン) + +ダッシュボードはユーザーログインにメール + OTP を使用します。このシークレットがなくてもサーバーは起動し、`ADMIN_KEY` の API パスは動作し続けますが、**UI からユーザーがログインできなくなります**。 + +すべてのキーはベースマニフェストで `optional: true` として参照されているため、一部のシークレット(またはシークレットがまったくない状態)でも問題ありません。サーバーはドキュメントに記載されたデフォルト値にフォールバックします。すべてを 1 つの `agenteye-auth` シークレットにまとめることで、認証情報を一箇所でローテーションできます。 + +```bash +kubectl create secret generic agenteye-auth \ + --namespace agenteye \ + --from-literal=ADMIN_EMAIL="admin@yourcompany.com" \ + --from-literal=ALLOWED_EMAILS="*@yourcompany.com" \ + --from-literal=SMTP_HOST="smtp.yourprovider.com" \ + --from-literal=SMTP_PORT="587" \ + --from-literal=SMTP_USERNAME="your-smtp-user" \ + --from-literal=SMTP_PASSWORD="your-smtp-password" \ + --from-literal=SMTP_FROM="noreply@yourcompany.com" \ + --from-literal=SMTP_TLS="starttls" \ + --from-literal=DEFAULT_ORG_NAME="Acme Corp" \ + --from-literal=DEFAULT_ORG_SLUG="acme" +``` + +| キー | 用途 | +|---|---| +| `ADMIN_EMAIL` | ブートストラップ管理者ユーザー。起動のたびに全権限付きでアップサートされ、ダッシュボードからの削除/権限編集が保護されます。設定しない場合、管理者がシードされず最初のログインが不可能になります。 | +| `ALLOWED_EMAILS` | カンマ区切りの許可リスト。厳密なアドレス(`user@example.com`)とドメインワイルドカード(`*@example.com`)をサポートします。設定しない場合、**どのユーザーもログインまたは作成できません**。 | +| `SMTP_HOST`、`SMTP_PORT`、`SMTP_USERNAME`、`SMTP_PASSWORD`、`SMTP_FROM` | OTP コード送信用の SMTP リレー。`SMTP_HOST` が未設定の場合、OTP コードはメール送信の代わりにサーバーの stdout に記録されます(初回起動のスモークテストに便利)。実際のメール配信にはすべての SMTP キーを一緒に設定してください。 | +| `SMTP_TLS` | `starttls`(デフォルト)、`tls`、または `none` のいずれか。 | +| `DEFAULT_ORG_NAME`、`DEFAULT_ORG_SLUG` | オプション。組み込みの `default` 組織にわかりやすい表示名と URL スラグを付けることで、`/default` の代わりに例えば `/acme` のような URL にできます。**初回起動時のみ**適用されます。`agenteye-orgctl org rename` で組織名を変更した後(§7.6 参照)はこれらの設定は無視されます。スラグは 1〜40 文字の小文字英数字で、内部ハイフンは 1 つまで使用できます。デフォルトの `default` のままにする場合は両方未設定のままにしてください。 | + +> **SMTP 認証情報はシークレットマネージャーに保存してください。** + +**確認:** + +```bash +kubectl get secret agenteye-auth -n agenteye \ + -o jsonpath='{.data}' | grep -o '"[A-Z_]*"' | sort -u +``` + +期待される結果:設定したキーが出力に表示されること。 + +--- + +### 2.6 マルチテナント組織分離キー(オプション) + +シングルテナントデプロイメントではスキップしてください。サーバーは組み込みの dev デフォルトで動作し、1 つの `default` 組織を問題なく提供します。**2 番目の組織を作成する前に**、強固で安定した `ORG_CH_SECRET` を設定してください。各組織の ClickHouse パスワードは `HMAC(ORG_CH_SECRET, org_id)` として導出されるため、公知の dev デフォルトを使用すると組織ごとの認証情報が公開的に導出可能になってしまいます。`agenteye-orgctl org create` コマンド([§7.6 組織のプロビジョニング](#76-provision-organizations-multi-tenant)参照)は、サーバーが組み込み dev デフォルトを使用している間は実行を拒否します。 + +```bash +kubectl create secret generic agenteye-org-ch-secret \ + --namespace agenteye \ + --from-literal=ORG_CH_SECRET="$(openssl rand -base64 48)" + +# 新しい値を反映するためにサーバーをロールアウト再起動します。 +kubectl -n agenteye rollout restart deployment/server +``` + +サーバーはこれを**オプションの** `secretKeyRef` で読み取るため、このシークレットを作成しないシングルテナントクラスターでも正常に起動します。この値は**すべてのレプリカで安定かつ一致**させてください。ローテーションすると、起動時の調整で再プロビジョニングされるまで(値を一致させた状態でのローリング再起動で修復されます)、すべての組織の導出済み ClickHouse パスワードが無効になります。`deploy/base/server/secret.example.yaml` を参照してください。 + +> **`ORG_CH_SECRET` はシークレットマネージャーに保存し、安易にローテーションしないでください。** + +--- + +### 2.7 全シークレットの確認 + +```bash +kubectl get secrets -n agenteye -o custom-columns='NAME:.metadata.name,TYPE:.type' +``` + +期待される出力(デフォルトシークレットを含む): + +``` +NAME TYPE +agenteye-admin-key Opaque +agenteye-auth Opaque +agenteye-image-pull kubernetes.io/dockerconfigjson +agenteye-postgres Opaque +agenteye-org-ch-secret Opaque # §2.6(マルチテナント)を完了した場合のみ +``` + +続行前に 4 つのコアシークレット(`agenteye-admin-key`、`agenteye-auth`、`agenteye-image-pull`、`agenteye-postgres`)が存在している必要があります。`agenteye-org-ch-secret` はマルチテナントデプロイメントでのみ必要です(§2.6 参照)。 + +--- + +## フェーズ 3 -- アプリケーションのデプロイ(約 5 分) + +### 3.1 パブリックホスト名の設定 + +cert-manager が Let's Encrypt 証明書を要求する前に、取り込みとダッシュボードのホスト名が必要です。テンプレートをコピーして両方を設定してください: + +```bash +cp base/certificates/domain.env.example base/certificates/domain.env +# base/certificates/domain.env を編集して以下を設定: +# INGEST_DOMAIN=ingest.your-company.example (パブリック Traefik LB に解決) +# DASHBOARD_DOMAIN=agenteye.your-company.example (ダッシュボード Traefik LB に解決) +``` + +`domain.env` は gitignore されており、各デプロイメントにローカルに保存されます。いずれかのキーが欠けていると kustomize ビルドは明確にエラーとなります。 + +> **DNS は事前に解決できる状態にしてください。** まだ LB に DNS を向ける必要はありません(フェーズ 1.2 が完了するまで存在しないため)が、ステップ 3.2 の ACME 発行では各ホスト名がその LoadBalancer に解決されるまでリトライが続きます。フェーズ 1.4 で取得した LB ホスト名を使用して今すぐ DNS を設定するか、フェーズ 4 でレコードを追加することもできます。 + +--- + +### 3.2 マニフェストの適用 + +新規インストールの場合はベースを直接適用するか、この環境向けにオーバーレイを作成した場合はオーバーレイを適用してください(オーバーレイはイメージタグ、環境変数、リソース制限のみを設定し、ベースの証明書とルーティングを継承します): + +```bash +kubectl apply -k base/ +# または +kubectl apply -k overlays// +``` + +オーバーレイはベースを自動的に含みます。両方を適用しないでください。 + +--- + +### 3.3 ポッドの起動待機 + +```bash +kubectl wait --for=condition=Ready pod -l 'app in (server,dashboard,postgres,clickhouse)' \ + -n agenteye --timeout=180s +``` + +この待機はコアデータプレーンのポッドに限定されています。オプションの `agent`(AI アシスタント)と `redis` ポッドも同時に起動します。アシスタントは LLM エンドポイントを設定するまで無効状態([enterprise-docs/assistant.md](/ja/agenteye/assistant) 参照)で、Redis はベストエフォートのキャッシュです。そのため、どちらもプラットフォームがトラフィックを提供するために Ready 状態である必要はありません。 + +**確認:** + +```bash +kubectl get pods -n agenteye +``` + +期待される結果(オプションの `agent` と `redis` ポッドも表示され `Running` になります): + +``` +NAME READY STATUS RESTARTS AGE +agent-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +clickhouse-0 1/1 Running 0 ... +dashboard-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +dashboard-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +postgres-0 1/1 Running 0 ... +redis-0 1/1 Running 0 ... +server-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +server-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +``` + +**失敗した場合:** + +| ポッドのステータス | 考えられる原因 | デバッグコマンド | +|---|---|---| +| `ImagePullBackOff` | イメージプルシークレットまたは PAT が無効 | `kubectl describe pod -n agenteye` | +| `CrashLoopBackOff` | 環境変数が不正(例:DATABASE_URL) | `kubectl logs -n agenteye` | +| `Pending` | CPU/メモリ不足またはノードなし | `kubectl describe pod -n agenteye`(Events を確認) | + +--- + +### 3.4 ストレージの確認 + +```bash +kubectl get pvc -n agenteye +``` + +期待される結果:両方が `Bound` ステータス: + +| PVC | 容量 | 用途 | +|---|---|---| +| `postgres-data-postgres-0` | `50Gi` | PostgreSQL リレーショナル/メタデータストア | +| `clickhouse-data-clickhouse-0` | `100Gi` | ClickHouse イベント + エバリュエーション分析ストア | + +オプションのキャッシュ用に `redis-data-redis-0` PVC(1Gi)も表示されます。 + +**失敗した場合:** `Pending` はどの StorageClass もボリュームをプロビジョニングできないことを意味します。`kubectl get storageclass` でデフォルトが存在することを確認してください。本番環境では、高速 SSD StorageClass(AWS では gp3、GCP では pd-ssd)に ClickHouse ボリュームのオーバーレイを適用してください。低速ディスクではコンパクションのスループットが低下します。 + +--- + +### 3.5 証明書の確認 + +```bash +kubectl get certificates -n agenteye +``` + +期待される結果:3 つの証明書がすべて `Ready: True`: + +| 名前 | 発行者 | 用途 | +|---|---|---| +| `mtls-ca` | `selfsigned` | mTLS クライアント証明書発行用のプライベート CA(有効期限 10 年) | +| `ingest-tls` | `letsencrypt-prod` | 取り込みエンドポイント用パブリック TLS 証明書(90 日、自動更新) | +| `dashboard-tls` | `letsencrypt-prod` | ダッシュボード用パブリック TLS 証明書(90 日、自動更新) | + +**`ingest-tls` または `dashboard-tls` が Ready でない場合:** + +`kubectl describe certificate -n agenteye` を実行して Events を確認してください。一般的な原因: + +- **DNS がまだ LB を向いていない。** Let's Encrypt はホスト名を解決してポート 80 にアクセスして検証します。`INGEST_DOMAIN` はパブリック LB に、`DASHBOARD_DOMAIN` はダッシュボード LB に解決される必要があります。CNAME/Alias が伝播するまでオーダーは `pending` のままです。DNS が正しく設定されれば、cert-manager は自動的にリトライします(Certificate を削除する必要はありません)。 +- **ホスト名が置換されていない。** `dnsNames` が `INGEST_DOMAIN_PLACEHOLDER` / `DASHBOARD_DOMAIN_PLACEHOLDER` のままの場合、ステップ 3.1 をスキップしています。`base/certificates/domain.env` を作成して再適用してください。 +- **ダッシュボード Traefik がチャレンジを提供できない**(`dashboard-tls` のみ)。ダッシュボード Traefik インスタンスはバンドルされたバリューファイルでインストールされている必要があります(フェーズ 1.2)。このファイルは cert-manager の HTTP-01 ソルバーを提供するスコープ付き Ingress プロバイダーを有効にします。これなしでインストールされたインスタンスはチャレンジをルーティングできず、オーダーが永遠に `pending` のままになります。 + +**`mtls-ca` が Ready でない場合:** cert-manager 自体が不健全です。ステップ 1.1 の cert-manager ポッドを再確認してください。 + +--- + +### 3.6 CronJob の確認 + +```bash +kubectl get cronjobs -n agenteye +``` + +期待される結果: + +| 名前 | スケジュール | 用途 | +|---|---|---| +| `agenteye-backup` | `0 3 * * *` | UTC 03:00 に Postgres と ClickHouse の日次バックアップ | +| `cert-renewal-check` | `0 3,15 * * *` | UTC 03:00 と 15:00 に証明書有効期限アラート | + +--- + +### 3.7 サーバーの起動確認 + +```bash +kubectl logs -n agenteye -l app=server --tail=20 +``` + +**確認:** サーバーがポート 8080 でリッスンしていることを示す起動ログを探してください。データベース接続エラーがないことを確認してください(サーバーは Ready と報告する前に PostgreSQL と ClickHouse の両方に到達できる必要があります)。 + +**失敗した場合:** 最も一般的な原因は、`POSTGRES_PASSWORD` に URL 安全でない文字が含まれており、`DATABASE_URL` が壊れていることです。[enterprise-docs/troubleshooting.md](/ja/agenteye/troubleshooting) を参照してください。 + +--- + +### 3.8 ダッシュボードのサーバー接続確認 + +```bash +kubectl logs -n agenteye -l app=dashboard --tail=20 +``` + +**確認:** 出力に `Ready` が表示され、`ECONNREFUSED` などのエラーがないことを確認してください。 + +**失敗した場合:** `server` Service が存在すること(`kubectl get svc server -n agenteye`)と、ダッシュボードデプロイメントで `AGENTEYE_SERVER_URL` が `http://server:8080` に設定されていることを確認してください。 + +--- + +## フェーズ 4 -- ネットワークアクセス(約 5 分) + +### 4.1 LoadBalancer アドレスの取得 + +```bash +PUBLIC_IP=$(kubectl get svc -n traefik-public \ + -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') + +INTERNAL_IP=$(kubectl get svc -n traefik-dashboard \ + -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') +``` + +> AWS EKS では、LoadBalancer は IP の代わりにホスト名を返します。上記コマンドの `.ip` を `.hostname` に置き換えてください。 + +**確認:** + +```bash +echo "Public (ingest): $PUBLIC_IP" +echo "Internal (dashboard): $INTERNAL_IP" +``` + +両方が空でないこと。 + +--- + +### 4.2 LoadBalancer への DNS の向け先設定 + +`base/certificates/domain.env` のホスト名がそれぞれの LoadBalancer に解決されるように DNS レコードを作成してください。`INGEST_DOMAIN` は**パブリック** Traefik LB に、`DASHBOARD_DOMAIN` は**ダッシュボード** Traefik LB に向けます: + +- **AWS Route 53:** `Alias = Yes` の `A` レコードで、ターゲットを LB ホスト名に設定。単純な A → IP は使用しないでください。ELB の IP はローテーションされます。 +- **その他のプロバイダー:** ホスト名から LB ホスト名への `CNAME`。 + +確認: + +```bash +dig +short ingest.your-company.example +dig +short agenteye.your-company.example +``` + +それぞれ `$PUBLIC_IP` と `$INTERNAL_IP` と同じアドレスが返されるはずです(EKS の場合は同じ `*.elb.amazonaws.com` ホスト名に解決)。 + +DNS が解決されると、cert-manager はフェーズ 3.5 の pending ACME オーダーを 1 分以内に完了します。`ingest-tls` と `dashboard-tls` の両方が `Ready: True` になるまで `kubectl get certificates -n agenteye` を再実行してください。 + +--- + +### 4.3 取り込みエンドポイントへの到達確認 + +パブリック取り込みエンドポイントは相互 TLS を強制するため、`/health` を含むすべてのリクエストにクライアント証明書が必要です。フェーズ 5 で最初のクライアント証明書を発行します。すでに持っている場合は今すぐ到達性を確認してください: + +```bash +curl -s --cert issued//client.crt \ + --key issued//client.key \ + https://ingest.your-company.example/health +``` + +期待される結果:`{"status":"ok"}`。`-k` は不要です。`INGEST_DOMAIN` のサーバー証明書はパブリック CA からチェーンされているため、システムトラストストアで検証されます。取り込みエンドポイントには、未加工の LoadBalancer の IP/ホスト名ではなく `INGEST_DOMAIN` ホスト名でアクセスしてください。 + +ダッシュボードエンドポイントは `DASHBOARD_DOMAIN` でパブリック信頼済み証明書により提供され、mTLS の背後にはありません。そのため `-k` もクライアント証明書も不要です: + +```bash +curl -s https://agenteye.your-company.example/ -o /dev/null -w '%{http_code}\n' +``` + +証明書は `DASHBOARD_DOMAIN` にバインドされているため、未加工の LB アドレスで接続すると証明書名の不一致が発生します。ダッシュボードへはホスト名でアクセスしてください。 + +**失敗した場合:** `curl` がハングする場合は、ご利用のマシンから LB に到達できるかを確認してください(VPN、セキュリティグループ、ファイアウォールルール)。取り込みホスト名での `certificate required` ハンドシェイクエラーはクライアント証明書が提示されていないことを意味します。まずフェーズ 5 を完了してください。取り込みホスト名での TLS 検証エラーは、サーバー証明書の発行が完了していないことを意味します。フェーズ 3.5 に戻って問題を解決してください。 + +--- + +## フェーズ 5 -- mTLS クライアント証明書の発行(クラスターあたり約 10 分) + +コレクターは**2 要素**で認証します。クライアント証明書(トランスポート層、認可されたクラスターからのリクエストであることを証明)と API キー(アプリケーション層、`events:add` 権限を持つコレクターからのリクエストであることを証明)です。流出したキーは証明書なしでは無効であり、盗まれた証明書は有効なキーなしでは無効です。 + +### 5.1 証明書の発行 + +コレクターを実行する各クラスターには固有のクライアント証明書が必要です。マニフェストのディレクトリから: + +```bash +cd base/certificates/client-certs +./issue-client-cert.sh +``` + +`` を意味のある識別子(例:`us-east-1-prod`、`staging`)に置き換えてください。 + +**確認:** スクリプトが `==> Done!` を出力し、出力ファイルの一覧が表示される。 + +```bash +kubectl get certificate mtls-client- -n agenteye +``` + +期待される結果:`Ready: True`。 + +`issued//` の出力ファイル: + +| ファイル | 用途 | +|---|---| +| `client.crt` | クライアント証明書(有効期限 90 日) | +| `client.key` | クライアント秘密鍵 | +| `ca.crt` | サーバー検証用 CA 証明書 | +| `collector-mtls-secret.yaml` | コレクタークラスター用の即適用可能な Kubernetes Secret | + +--- + +### 5.1b 代替配信方法:AWS Secrets Manager + +証明書の使用者が `client.crt` と `client.key` をディスク上に必要とする Kubernetes Pod(アプリケーションポッドのサイドカーとして agenteye-collector を実行する典型的なケース)の場合は、証明書バンドルを AWS Secrets Manager にプッシュします。アプリケーションポッドは [Secrets Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/) と IRSA を通じてマウントし、証明書のローテーションは完全に自動化されます。 + +```bash +cd base/certificates/client-certs +export AWS_REGION=us-east-1 # ワークロードが実行されているリージョン +./issue-client-cert.sh --save-to aws-secrets-manager +``` + +再実行(更新)時、スクリプトは同じシークレットに対して `PutSecretValue` を呼び出すため、ARN と名前は安定したままです。CSI Driver は次のローテーションポーリング時に新しいバージョンを取得し、ポッド内のファイルを書き換えます。 + +**前提条件:** + +- AWS アカウントに認証済みの `aws` CLI v2。 +- `jq` がインストールされていること。 +- `AWS_REGION` 環境変数が設定されていること。 +- 呼び出し元の IAM 権限(`Resource` を `arn:aws:secretsmanager:::secret:agenteye/mtls-client/*` にスコープ): + - `secretsmanager:CreateSecret` + - `secretsmanager:DescribeSecret` + - `secretsmanager:PutSecretValue` + - `secretsmanager:TagResource` + +**このモードでスクリプトが行うこと:** + +| ステップ | アクション | +|---|---| +| 1 | cert-manager を通じて証明書を発行/再抽出します(デフォルトモードと同じ)。 | +| 2 | `agenteye/mtls-client/` に対して `DescribeSecret` を呼び出し、作成か更新かを判断します。 | +| 3 | 初回実行時:3 キーの JSON ペイロード(`client.crt`、`client.key`、`ca.crt`)で `CreateSecret` を実行し、`AgentEyeCluster=` タグを付与。以降の実行時:`PutSecretValue` で新しいバージョンを発行し、`TagResource` でタグを更新。 | +| 4 | アップロード成功後のみ `issued//` を削除します。失敗した場合はディレクトリが保持されるのでリトライできます。 | + +**シークレットが削除スケジュールされている場合**、スクリプトはリトライ前に `aws secretsmanager restore-secret --secret-id agenteye/mtls-client/` を実行するよう促す明確なエラーを表示して失敗します。 + +完全なポッドの配線(SecretProviderClass、IRSA セットアップ、ローテーション動作、トラブルシューティング)については [enterprise-docs/single-pod-deployment.md](/ja/agenteye/single-pod-deployment) を参照してください。 + +--- + +### 5.2 証明書の動作確認 + +発行した証明書を mTLS イングレスに対してテストします: + +```bash +curl -sk --cert issued//client.crt \ + --key issued//client.key \ + https://${PUBLIC_IP}/health +``` + +期待される結果:`{"status":"ok"}` + +**失敗した場合:** + +| エラー | 原因 | 対処法 | +|---|---|---| +| `certificate required` | 証明書が提示されていない | `curl` コマンドのファイルパスを確認 | +| `bad certificate` | CA の不一致 | `mtls-ca-issuer` が証明書を発行したか確認:`kubectl describe certificate mtls-client- -n agenteye` | +| `connection refused` | ホスト名が誤っているか LB に到達できない | `/etc/hosts` または DNS を確認 | + +--- + +### 5.3 コレクタークラスターへの配信 + +`collector-mtls-secret.yaml` をコレクタークラスターを運用するチームに送付します。適用方法: + +```bash +kubectl apply -f collector-mtls-secret.yaml -n +``` + +次に、シークレットをマウントして証明書パスを使用するようコレクターを設定します: + +```json +{ + "tls_cert": "/etc/agenteye/tls/client.crt", + "tls_key": "/etc/agenteye/tls/client.key" +} +``` + +Kubernetes ボリュームマウントを含む完全なコレクターセットアップについては [enterprise-docs/collector-installation.md](/ja/agenteye/collector-installation) を参照してください。 + +**確認(コレクタークラスター内):** + +```bash +kubectl get secret agenteye-collector-mtls -n +``` + +期待される結果:3 つのデータキー(`client.crt`、`client.key`、`ca.crt`)を持つシークレットが存在すること。 + +--- + +### 5.4 証明書のライフサイクル + +| プロパティ | 値 | +|---|---| +| クライアント証明書の有効期限 | 90 日 | +| 自動更新 | cert-manager が有効期限の 15 日前に更新 | +| CA の有効期限 | 10 年 | +| 有効期限アラート | CronJob が有効期限の 30 日前にアラート(フェーズ 6) | + +cert-manager は **AgentEye クラスター**上の証明書を自動更新しますが、更新された証明書はコレクタークラスターに再配信する必要があります。古い証明書が期限切れになる前に `issue-client-cert.sh` を再実行して `collector-mtls-secret.yaml` を再適用してください。 + +`--save-to aws-secrets-manager` を使用している場合(§ 5.1b 参照)は、同じコマンドを再実行してください。スクリプトは同じシークレットに対して `PutSecretValue` を呼び出し、Secrets Store CSI Driver を通じてシークレットをマウントしているポッドは次のローテーションポーリング時(デフォルト:1 時間ごと)に新しいバージョンを取得します。ポッドの再起動は不要です。 + +--- + +### 5.5 証明書の失効 + +クラスターのコレクターアクセスを即座にブロックするには: + +```bash +kubectl delete certificate mtls-client- -n agenteye +``` + +**確認:** ステップ 5.2 の `curl` コマンドが TLS ハンドシェイクエラーで失敗するようになる。 + +--- + +## フェーズ 6 -- 証明書更新モニタリング(約 2 分) + +組み込みの CronJob が 12 時間ごと(UTC 03:00 と 15:00)に実行され、`agenteye.io/cert-type=mtls-client` ラベルの付いたすべてのクライアント証明書をチェックします。有効期限まで 30 日以内の証明書があるとアラートを送信します。 + +### 6.1 Slack 通知の有効化(オプション) + +```bash +kubectl create secret generic cert-renewal-notify-config \ + --namespace agenteye \ + --from-literal=SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL" +``` + +このシークレットがなくても、CronJob は実行され証明書のステータスを stdout にログ出力します。 + +**確認:** + +```bash +kubectl get secret cert-renewal-notify-config -n agenteye +``` + +期待される結果:シークレットが存在すること。 + +--- + +### 6.2 CronJob のテスト + +```bash +kubectl create job --from=cronjob/cert-renewal-check test-cert-check -n agenteye + +kubectl wait --for=condition=Complete job/test-cert-check -n agenteye --timeout=60s + +kubectl logs -n agenteye -l job-name=test-cert-check +``` + +期待される結果:有効期限ステータスを含む証明書の一覧が表示される。Slack Webhook が設定されている場合は、Slack チャンネルにアラートメッセージが届くことを確認してください。 + +**失敗した場合:** RBAC を確認してください。CronJob の ServiceAccount は cert-manager Certificate リソースへの `get, list` 権限が必要です。`kubectl describe role cert-renewal-check -n agenteye` で確認してください。 + +テスト用 Job のクリーンアップ: + +```bash +kubectl delete job test-cert-check -n agenteye +``` + +--- + +## フェーズ 7 -- エンドツーエンドの検証 + +このフェーズでは、パイプライン全体が正常に動作することを確認します:ヘルスチェック、キー作成、イベント取り込み、ダッシュボード表示。 + +> **注:** 以下の例では利便性のために未加工の LoadBalancer アドレス(`${PUBLIC_IP}`)で取り込みエンドポイントにアクセスしているため、`-k` を使用します。サーバー証明書は LB IP ではなく `INGEST_DOMAIN` にバインドされているため、ホスト名チェックをスキップしています。取り込みエンドポイントは**すべての**パスで相互 TLS を強制するため、すべての呼び出しにクライアント証明書(`--cert`/`--key`)も必要です。パブリック証明書も検証する場合は、`${PUBLIC_IP}` の代わりに `https://ingest.your-company.example/...` を対象にして `-k` を省略してください。 + +### 7.1 ヘルスチェック + +```bash +curl -sk --cert issued//client.crt \ + --key issued//client.key \ + https://${PUBLIC_IP}/health +``` + +期待される結果:HTTP 200 で `{"status":"ok"}`。 + +--- + +### 7.2 スコープ付きコレクターキーの作成 + +管理者キーはブートストラップと管理用です。コレクター用の専用 `events:add` キーを作成してください: + +```bash +COLLECTOR_KEY=$(openssl rand -hex 32) + +curl -sk -X POST https://${PUBLIC_IP}/keys \ + --cert issued//client.crt \ + --key issued//client.key \ + -H "Authorization: Bearer ${ADMIN_KEY}" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "prod-collector", + "key": "'"${COLLECTOR_KEY}"'", + "permissions": ["events:add"] + }' +``` + +**確認:** レスポンスに `"id"`、`"name": "prod-collector"`、`"permissions": ["events:add"]`、`"created_at"` が含まれること。 + +**確認:** キーがキー一覧に表示されることを確認: diff --git a/docs/ja/agenteye/managed-deployment.mdx b/docs/ja/agenteye/managed-deployment.mdx new file mode 100644 index 00000000..69750752 --- /dev/null +++ b/docs/ja/agenteye/managed-deployment.mdx @@ -0,0 +1,171 @@ +--- +title: "Kubernetesクラスターへのマネージドデプロイ" +description: "KubernetesクラスターへのAgentEyeマネージドデプロイのドキュメント" +--- + + +AgentEyeは、AIおよびLLMエージェント向けのセルフホスト型オブザーバビリティ・評価プラットフォームです。エージェントセッション、ツール呼び出し、モデルリクエスト、エラーをキャプチャし、検索可能なアナリティクスと評価に変換して、オプションの読み取り専用AIアシスタントを備えたダッシュボードに結果を表示します。 + +マネージドデプロイメントモデルでは、お客様が専用のKubernetesクラスターを用意し、Exosphereがそのクラスター内でプラットフォーム全体を運用します。すべてのコンポーネントのデプロイ、設定、運用、バックアップ、アップグレードをExosphereが代行します。お客様のチームは、データベース、証明書、アップグレードの管理を行うことなく、エージェントの可視化・アナリティクス・評価・オプションのアシスタントといったプラットフォームの価値を享受できます。すべてのデータはお客様のクラウドアカウント内に保持されます。 + +--- + +## 前提条件 + +- コンテナイメージのプルおよびアーティファクトのダウンロードに使用する **GitHub PAT**([GitHub トークンのセットアップ](/ja/agenteye/github-token) を参照) +- **専用のKubernetesクラスター**(以下の要件を参照) +- データベースバックアップ用の **ストレージバケット** +- **ネットワーク接続**: クラスターのロードバランサーへのポート 443 インバウンド + +--- + +## ステップ 1: 専用Kubernetesクラスターのプロビジョニング + +AgentEye専用のKubernetesクラスターを作成してください。他のワークロードと共有しないことで、プラットフォーム全体(アプリケーションサービス、データベース、アナリティクス、キャッシュ)が既存のインフラに影響を与えることなく独立した環境で動作します。 + +| 要件 | 詳細 | +|---|---| +| **ディストリビューション** | 準拠したKubernetes: EKS、GKE、AKS、またはセルフマネージド | +| **バージョン** | 1.27 以降 | +| **ノードプール** | 最小構成: **3ノード、各4 vCPU / 8 GB RAM**(標準的な汎用インスタンス) | +| **ストレージ** | ブロックボリュームをプロビジョニングするデフォルトの StorageClass(例: AWSの `gp3`、GCPの `pd-ssd`) | +| **ロードバランサー** | クラウドのLoadBalancerサービスをプロビジョニングできること(EKS、GKE、AKSでは標準対応) | + +> Exosphereはクラスター内のその他すべてをインストール・管理します: イングレスコントローラー、TLS証明書、データベース、キャッシュ、モニタリング、およびすべてのアプリケーションデプロイメント。 + +--- + +## ステップ 2: AgentEyeチームへのアクセス付与 + +Exosphereは、名前空間、カスタムリソース定義、イングレスコントローラー、ストレージプロビジョナーを管理するために、cluster-adminアクセス(または同等の広範なRBAC)が必要です。 + +| 要件 | 詳細 | +|---|---| +| **アクセス方法** | IAMロール(EKS/GKEでは推奨)、kubeconfig、またはSSOベースのアクセス | +| **VPN / 踏み台サーバー** | Kubernetes APIサーバーがプライベートな場合は、Exosphere運用チーム向けにVPN認証情報または踏み台サーバーへのアクセスを提供してください | + +--- + +## ステップ 3: ネットワーク接続の設定 + +ネットワークチームは、クラスターのロードバランサーへの**ポート 443** インバウンドトラフィックを許可する必要があります。デプロイメントでは2つの独立したロードバランサーが稼働します。1つはイベントの取り込み用(mTLS保護)、もう1つはダッシュボード用です。 + +| トラフィック | 送信元 | 宛先 | セキュリティ | +|---|---|---|---| +| **イベント取り込み** | お客様のクラスター内のコレクターポッド | イングレストLoadBalancer、ポート 443 | mTLS(クライアント証明書)+ APIキー | +| **ダッシュボード** | 開発者のブラウザ | ダッシュボードLoadBalancer、ポート 443 | お客様のドメインでのHTTPS、パスワードレスメールOTPサインイン | + +取り込みエンドポイントは相互TLSで保護されており、コレクターはすべてのリクエストで有効なクライアント証明書**と**有効なAPIキーの両方を提示する必要があります。ダッシュボードは独自のロードバランサーとホスト名で動作し、サインインはお客様が許可リストに登録したメールアドレス/ドメインに制限されます。 + +**DNSレコード(一度のみ):** お客様が管理するドメインの下に2つのCNAMEレコードを作成します。1つは取り込みエンドポイント用、もう1つはダッシュボード用(例: `agenteye.your-company.example`)で、Exosphereが提供するロードバランサーのホスト名を指します。Exosphereは両方のホスト名に対してパブリック信頼のTLS証明書を自動的にプロビジョニングし、更新も含めて管理します。 + +> **ポート 80 について:** 証明書の自動発行と更新は、各ロードバランサーのポート 80 へのHTTPで検証されます。ダッシュボードのロードバランサーを社内IPレンジに制限するセキュリティポリシーがある場合は、事前にExosphereにお知らせください。証明書の検証方式をDNSベースの方法(お客様側で追加のDNSレコードが1件必要)に切り替えることで、制限が適用されていても証明書の更新が継続して機能します。 + +> **アウトバウンド:** クラスターノードは `ghcr.io` からコンテナイメージをプルするためにインターネットアクセスが必要です。アウトバウンドトラフィックが制限されている場合は、`ghcr.io` を許可リストに追加するか、内部レジストリにイメージをミラーリングしてください。 + +--- + +## ステップ 4: バックアップ用ストレージバケットの提供 + +データベースのバックアップは、お客様が所有するクラウドストレージバケットに保存されます。 + +| 要件 | 詳細 | +|---|---| +| **サービス** | S3(AWS)、GCS(GCP)、またはAzure Blob Storage | +| **アクセス** | IAMロール for サービスアカウント(EKSのIRSA、GKEのWorkload Identity)経由でクラスターノードへの書き込みアクセスを付与するか、認証情報を提供してください | +| **保持期間** | バケットのライフサイクルポリシー(保持期間、アーカイブルール)はお客様が管理します。Exosphereがバックアップを書き込み、保持期間はお客様が決定します | + +1日1回のバックアップで、PostgreSQL(リレーショナルデータ)とClickHouse(イベントと評価)の両方を1つの圧縮アーカイブにダンプし、お客様のバケットにアップロードします。バックアップはアップグレード前にも実行されます。 + +--- + +## ステップ 5: 担当者の指定 + +クラスターレベルの問題(ノードの健全性、クラウドアカウントの制限、ネットワークの変更)に対応する、お客様側の担当者またはSlack/Teamsチャンネルを1つ指定してください。日常的な運用ではこの担当者への連絡は発生しません。 + +--- + +## デプロイされるコンポーネント + +Exosphereがクラスターへのアクセスを取得すると、以下のコンポーネントがデプロイされ、管理されます。 + +| コンポーネント | 役割 | +|---|---| +| **AgentEyeサーバー** | コレクターからイベントを受信し、アナリティクスを実行し、ダッシュボードにデータを提供するHTTP API | +| **ダッシュボード** | エージェントセッション、ツール呼び出し、モデルリクエスト、エラーを表示するWebインターフェース。オプションの読み取り専用AIアシスタントをホスト | +| **ClickHouse** | 取り込まれたイベント、アナリティクス、評価のための必須の正規ストア | +| **PostgreSQL** | 組織、APIキー、ユーザー、ダッシュボード、保存済みクエリのリレーショナルストア | +| **Redis** | オプションの共有キャッシュおよびレート制限バックエンド。利用不可能な場合もプラットフォームはグレースフルに機能低下 | +| **AIアシスタント(オプション)** | 内部の読み取り専用アシスタントコンテナ。LLMエンドポイントが設定されるまで無効 | +| **イングレスコントローラー** | 2つのロードバランサー(mTLS保護の取り込み用と、ダッシュボード用)。パブリック信頼の自動更新TLS証明書でTLSを終端し、取り込みエンドポイントでmTLSを強制 | +| **cert-manager** | TLS証明書のプロビジョニングとmTLSクライアント証明書の発行を自動化 | +| **証明書モニタリング** | 証明書の有効期限を確認し、更新期限が近づいたときにアラート(例: Slack)を送信するスケジュールジョブ | + +マネージドオファリングには、エージェントのアクティビティをお客様の評価基準に基づいてスコアリングする評価パイプラインの運用も含まれます。これらの機能の詳細については、[アシスタント](/ja/agenteye/assistant)および[評価スイート](/ja/agenteye/evaluation-suite)を参照してください。 + +--- + +## お客様へ提供されるもの + +デプロイ完了後、以下が提供されます。 + +| 項目 | 詳細 | +|---|---| +| **ダッシュボードURL** | お客様のドメイン配下のホスト名(例: `https://agenteye.your-company.example`)。パブリック信頼の自動更新TLS証明書で提供。提供されるロードバランサーのホスト名に対してCNAMEを1件作成するだけで、サインインはパスワードレスのメールOTP | +| **コレクターエンドポイント** | 取り込みホスト名の `/events` パス(例: `https://ingest.your-company.example/events`)、mTLS保護 | +| **クライアント証明書バンドル** | クラスターごと: クライアント証明書、秘密鍵、CA証明書をKubernetes Secretマニフェストとして提供。クラスターごとに1度適用 | +| **GitHub PAT** | コレクターバイナリおよびPython SDKパッケージのダウンロード用 | +| **コレクターAPIキー** | `events:add` 権限を持つスコープ付きキー。コレクターデプロイメントごとに1つ | +| **インストールガイド** | コレクターとPython SDKのステップバイステップドキュメント | + +--- + +## セットアップ後の作業 + +継続的な作業はAgentEyeクラスターではなく、お客様自身のエージェントマシン上でのみ発生します。 + +1. AIエージェントが稼働する各Kubernetesクラスターに**コレクターをインストール**: クライアント証明書をマウントし、エンドポイントURLとAPIキーを設定します。[コレクターのインストール](/ja/agenteye/collector-installation)を参照してください。 +2. エージェントコードに**Python SDKを統合**します。[Python SDK](/ja/agenteye/python-sdk)を参照してください。 +3. ブラウザで**ダッシュボードを開き**、エージェントのアクティビティを確認します。 + +クラスター運用、データベース管理、証明書の更新、アップグレードは一切不要です。 + +--- + +## セキュリティ + +- **データはお客様のクラウドアカウント内に保持されます。** クラスター、ストレージ、データベースはすべてお客様の環境で稼働します。データがお客様の境界外に出ることはありません。 +- **アクセスはお客様が管理します。** クラスターはお客様のアカウント内にあります。Exosphereのアクセスをいつでも監査、監視、または取り消すことができます。すべての操作はお客様のクラウドの監査ログ(CloudTrail、GCP監査ログなど)に記録されます。 +- **イベント取り込みにはmTLSを使用。** すべてのコレクターリクエストに有効なクライアント証明書とAPIキーの両方が必要です。漏洩したキーは証明書がなければ無意味であり、盗まれた証明書は有効なキーがなければ無意味です。 +- **ダッシュボードのアクセス制御。** ダッシュボードはイベント取り込みとは分離した独自のロードバランサーで稼働し、サインインはお客様が許可リストに登録したメールアドレス/ドメインに制限されたパスワードレスのメールOTPです。ロードバランサーへのIPソースレンジ許可リストはリクエストに応じて対応可能です。証明書の自動更新がロードバランサーに到達できる必要があるため、制限を適用する場合はExosphereがDNSベースの証明書検証と組み合わせることで、制限下でも証明書の更新が継続して機能します。 +- **クラスターごとの証明書。** お客様の各クラスターにはそれぞれ固有のクライアント証明書が発行されます。あるクラスターが侵害された場合、その証明書のみを独立して失効させることができ、他のクラスターには影響しません。 + +--- + +## デプロイメントタイムライン + +| フェーズ | 所要期間 | お客様の関与 | +|---|---|---| +| **クラスタープロビジョニング** | 1〜2日 | クラスターをプロビジョニングし、Exosphereにアクセスを付与 | +| **プラットフォームセットアップ** | 1日 | 不要。Exosphereがすべてのインフラコンポーネントをインストール | +| **アプリケーションデプロイメント** | 1日 | 不要。Exosphereがサーバー、ダッシュボードをデプロイし、APIキーを作成 | +| **コレクターロールアウト** | 1〜3日 | お客様のクラスターにコレクターをインストール(Exosphereによるガイダンスあり) | +| **本番バーンイン** | 1週間 | 不要。Exosphereが監視・チューニングを実施 | + +キックオフから本番稼働まで、典型的なトータル期間: **約2週間** + +--- + +## サポート + +ご質問やお問い合わせは、Exosphereの `support@exosphere.host` までご連絡ください。 + +--- + +## 次のステップ + +- [はじめに](/ja/agenteye/getting-started): エンドツーエンドのウォークスルー +- [コレクターのインストール](/ja/agenteye/collector-installation): コレクターのインストールと設定 +- [Python SDK](/ja/agenteye/python-sdk): エージェントコードのインストルメンテーション +- [APIキー](/ja/agenteye/api-keys): アクセスと権限の管理 +- [トラブルシューティング](/ja/agenteye/troubleshooting): 一般的な問題と解決策 \ No newline at end of file diff --git a/docs/ja/agenteye/python-sdk.mdx b/docs/ja/agenteye/python-sdk.mdx new file mode 100644 index 00000000..14f3c5a2 --- /dev/null +++ b/docs/ja/agenteye/python-sdk.mdx @@ -0,0 +1,383 @@ +--- +title: "Python SDK" +description: "AgentEye Python SDK のドキュメント。" +--- + + +AgentEye Python SDK は、エージェントの動作(すべてのエージェント実行、ツール呼び出し、モデルリクエスト、フック、人間による介入)に対する完全な可視性を提供します。これにより、デバッグ・監査・評価を行うことができます。構造化されたイベントをローカルの JSONL ファイルに書き込むことでエージェントコードを計測し、コレクターデーモンがそれらを自動的にプラットフォームへ送信します。 + +--- + +## インストール + +`AGENTEYE_TOKEN` を使用して GitHub Releases からホイールをダウンロードしてください。トークンをまだお持ちでない場合は、[GitHub トークンのセットアップ](/ja/agenteye/github-token)でセットアップ手順と必要な権限をご確認ください。 + +**`gh` CLI + pip を使用する場合:** + +```bash +VERSION=0.0.1b9 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "python-sdk/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-*.whl' +pip install "agenteye-${VERSION}-py3-none-any.whl" +``` + +**`gh` CLI + uv を使用する場合:** + +```bash +VERSION=0.0.1b9 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "python-sdk/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-*.whl' +uv add "./agenteye-${VERSION}-py3-none-any.whl" +``` + +**curl を使用する場合(`gh` CLI 不要):** + +```bash +VERSION=0.0.1b9 +curl -fsSL \ + -H "Authorization: Bearer $AGENTEYE_TOKEN" \ + -L \ + "https://github.com/agenteye-enterprise/releases/releases/download/python-sdk%2Fv${VERSION}/agenteye-${VERSION}-py3-none-any.whl" \ + -o "agenteye-${VERSION}-py3-none-any.whl" +pip install "agenteye-${VERSION}-py3-none-any.whl" +``` + +--- + +## クイックスタート + +```python +import agenteye + +agenteye.configure(environment="production") + +agenteye.event.agent_start(session_id="run-001", agent_id="planner", goal="answer user query") + +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", + input={"query": "latest AI research"}, +) + +agenteye.event.tool_result( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", + output={"results": ["..."]}, +) + +agenteye.event.agent_end(session_id="run-001", agent_id="planner", outcome="success") +``` + +--- + +## configure() + +```python +agenteye.configure( + base_dir=None, # Path | str | None. デフォルト: $AGENTEYE_HOME または ~/.agenteye + flush_interval=0.5, # float, フラッシュ間隔(秒) + environment=None, # str | None. デプロイ環境のラベル +) +``` + +`event.*` を呼び出す前に一度だけ実行してください。省略しても問題ありません。デフォルト設定でそのまま動作します。すべての引数はキーワード専用です。上記のように名前を指定して渡してください。 + +`base_dir` が `None`(デフォルト)の場合、SDK は `$AGENTEYE_HOME` が設定されていればその値を使用し、設定されていなければ `~/.agenteye` にフォールバックします。これはコレクター自身の解決方法と一致するため、`AGENTEYE_HOME` 環境変数を一つ設定するだけで、SDK とコレクターの両方に対して共有イベントスプールを構成できます。サイドカー構成やシングルポッドのデプロイなど、両プロセスがスプールパスを共有する必要がある場合に必要です。 + +--- + +## 環境 + +すべてのイベントにデプロイ環境のラベル(`production`、`staging`、`qa`、`canary` など)を付与します。一度設定するだけで、SDK が自動的にすべてのイベントに付加します。 + +**オプション 1: `configure()` で設定する場合:** + +```python +agenteye.configure(environment="production") +``` + +**オプション 2: 環境変数で設定する場合:** + +```bash +export AGENTEYE_ENVIRONMENT=production +``` + +**優先順位:** `configure(environment=...)` は環境変数よりも優先されます。どちらも設定されていない場合は `"dev"` がデフォルト値となります。 + +環境の値はダッシュボードのファーストクラスフィルターとして表示され、高速クエリのためにサーバー上のインデックス付きカラムとして保存されます。 + +**制約:** 環境の値にリテラルのカンマ `,` を含めることは**できません**。ダッシュボードのフィルターはカンマ区切りのマルチセレクトをワイヤ上で使用するため(`?environment=prod,staging`)、`prod,blue` という名前の環境は2つの値に分割されてしまいます。カンマを含む環境を持つイベントは、インジェスト時に拒否されます。 + +--- + +## イベントリファレンス + +すべてのイベントメソッドには以下の2つのフィールドが必要です: + +| フィールド | 型 | 説明 | +|---|---|---| +| `session_id` | `str` | トップレベルのエージェント実行を識別する | +| `agent_id` | `str` | セッション内でイベントを発行したエージェントを識別する | + +すべてのメソッドはカスタムメタデータ用の任意の `**kwargs` も受け付けます([カスタムフィールド](#custom-fields)を参照)。 + +--- + +### `event.agent_start()` + +エージェントが処理を開始したときに発行されます。 + +```python +agenteye.event.agent_start( + session_id="run-001", + agent_id="planner", + goal="answer user query", # str | None + parent_id=None, # str | None - ネストされたエージェントの親 agent_id +) +``` + +--- + +### `event.agent_end()` + +エージェントが処理を終了したときに発行されます。 + +```python +agenteye.event.agent_end( + session_id="run-001", + agent_id="planner", + outcome="success", # str | None + summary="Answered query", # str | None +) +``` + +--- + +### `event.tool_use()` + +エージェントがツールを呼び出したときに発行されます。`tool_result` と対で使用し、SDK が `duration_ms` を自動計算します。 + +```python +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="web_search", # str, 必須 + tool_call_id="toolu_01", # str, 必須 - 対応する tool_result との相関キー + input={"query": "..."}, # dict | None +) +``` + +--- + +### `event.tool_result()` + +ツールが結果を返したときに発行されます。`tool_call_id` を通じて `tool_use` と対応付けられます。 + +```python +agenteye.event.tool_result( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", # 対応する tool_use と一致する必要がある + output={"results": ["..."]}, # Any | None + error=None, # str | None - ツールが例外を発生させた場合に設定 + # duration_ms は自動計算されるため渡さないこと +) +``` + +--- + +### `event.model_request()` + +LLM にプロンプトを送信する直前に発行されます。 + +```python +agenteye.event.model_request( + session_id="run-001", + agent_id="planner", + model="claude-sonnet-4-6", # str | None + messages=[ # list[dict] | None - 会話のターン + {"role": "user", "content": "..."}, + ], + system="You are helpful.", # Any | None - 文字列またはコンテンツブロックのリスト + tools=[ # list[dict] | None - モデルに提供するツールスキーマ + {"name": "search", "input_schema": {"type": "object"}}, + ], +) +``` + +`messages` のエントリは、プレーンな文字列の `content` または Anthropic スタイルのブロックリスト形式の `content` を受け付けます。サンプリングパラメータ(`temperature`、`max_tokens` など)は追加の kwargs として渡すことができます。 + +--- + +### `event.model_response()` + +LLM がレスポンスを返したときに発行されます。 + +```python +agenteye.event.model_response( + session_id="run-001", + agent_id="planner", + model="claude-sonnet-4-6", # str | None + stop_reason="end_turn", # str | None + input_tokens=1024, # int | None + output_tokens=256, # int | None + content=[ # Any | None - 文字列、またはコンテンツブロックのリスト + {"type": "text", "text": "..."}, + ], + role="assistant", # str | None +) +``` + +`content` はプレーンな文字列(汎用プロバイダー向け)または Anthropic スタイルのコンテンツブロックのリストを受け付けます。ツール呼び出しは `content` 内に `{"type": "tool_use", ...}` ブロックとして格納されており、別途 `tool_calls` フィールドはありません。 + +--- + +### `event.hook_triggered()` + +フックが発火したときに発行されます。`hook_completed` と対で使用し、SDK が `duration_ms` を自動計算します。 + +```python +agenteye.event.hook_triggered( + session_id="run-001", + agent_id="planner", + hook_name="pre_tool_use", # str, 必須 + hook_id="hook-abc", # str, 必須 - 相関キー + trigger_event="tool_use", # str | None + input={"tool": "search"}, # Any | None +) +``` + +--- + +### `event.hook_completed()` + +フックが完了したときに発行されます。`hook_id` を通じて `hook_triggered` と対応付けられます。 + +```python +agenteye.event.hook_completed( + session_id="run-001", + agent_id="planner", + hook_name="pre_tool_use", + hook_id="hook-abc", # 対応する hook_triggered と一致する必要がある + outcome="allow", # str | None + output=None, # Any | None + error=None, # str | None + # duration_ms は自動計算されるため渡さないこと +) +``` + +--- + +### `event.error()` + +未処理のエラーが発生したときに発行されます。 + +```python +agenteye.event.error( + session_id="run-001", + agent_id="planner", + error_type="TimeoutError", # str, 必須 + message="timed out", # str, 必須 + traceback="Traceback...", # str | None +) +``` + +--- + +## ヒューマン・イン・ザ・ループイベント + +ヒューマン・イン・ザ・ループイベントは、人間がエージェントの実行に介入する瞬間(承認待ち、入力提供、一時停止、またはエージェントの停止)を監視する機能を提供します。人間が応答するまでの時間の計測(SDK は対となるイベントで `duration_ms` を自動計算)、エージェントを一時停止または中断した人物の監査、そしてダッシュボードに表示される承認・監視ワークフローの構築が可能になります。 + +### `event.human_wait()` + +エージェントが人間の入力を待って実行を一時停止したときに発行されます。`human_input` と対で使用し、SDK が `duration_ms`(人間が応答するまでの時間)を自動計算します。 + +```python +agenteye.event.human_wait( + session_id="run-001", + agent_id="planner", + input_id="inp-abc", # str, 必須 - 対応する human_input との相関キー + prompt="Do you approve this action?", # str | None - 人間に表示される質問 + options=["approve", "reject", "defer"], # list[str] | None - 人間に提示される選択肢 + reason="approval_required", # str | None - エージェントが待機している理由 +) +``` + +### `event.human_input()` + +人間が入力を提供し、エージェントが実行を再開したときに発行されます。`input_id` を通じて `human_wait` と対応付けられます。`duration_ms` は自動計算されるため、呼び出し元が渡す必要はありません。 + +```python +agenteye.event.human_input( + session_id="run-001", + agent_id="planner", + input_id="inp-abc", # str, 必須 - 対応する human_wait と一致する必要がある + response="approve", # str | None - 人間の回答(自由入力または選択肢から選んだもの) + # duration_ms は自動計算されるため渡さないこと +) +``` + +### `event.human_pause()` + +人間がエージェントを能動的に一時停止したとき(例: ダッシュボードのコントロールを使用)に発行されます。エージェントは中断されますが、終了はしません。 + +```python +agenteye.event.human_pause( + session_id="run-001", + agent_id="planner", + reason="user_requested", # str | None + user_id="usr_42", # str | None - エージェントを一時停止した人物 +) +``` + +### `event.human_interrupt()` + +人間がエージェントの実行中に能動的に停止させたときに発行されます。`human_pause` とは異なり、エージェントの処理は中断ではなく終了します。 + +```python +agenteye.event.human_interrupt( + session_id="run-001", + agent_id="planner", + reason="output_incorrect", # str | None + user_id="usr_42", # str | None - エージェントを中断した人物 + at_step="tool_use:web_search", # str | None - 停止時にエージェントが実行していた処理 +) +``` + +--- + +## カスタムフィールド + +追加のキーワード引数はすべて、標準フィールドの後にイベントへ付加されます: + +```python +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="db_query", + tool_call_id="toolu_02", + tenant_id="acme", # カスタムフィールド + region="us-east-1", # カスタムフィールド +) +``` + +`timestamp`、`type`、`environment` は予約済みであり、カスタムフィールドとして渡した場合は `ValueError`(`Reserved field names cannot be used as custom fields: [...]`)が発生します。`session_id` と `agent_id` はすべてのイベントメソッドで必須パラメータのため、2度目に渡すことはできません。その場合、Python が `TypeError` を発生させます。環境の設定には `configure(environment=...)` または `AGENTEYE_ENVIRONMENT` 変数を使用してください。 + +--- + +## イベントの書き込み方法 + +イベントはプロセス内でバッファリングされ、`flush_interval` 秒ごと(デフォルト 500 ms)にディスクへフラッシュされます。フラッシュのたびに1つの JSONL ファイルが書き込まれます: + +``` +~/.agenteye/events/event-2026-04-01T12-00-00-000Z.jsonl +``` + +コレクターはこのディレクトリを監視し、ファイルを自動的にアップロードします。これらのファイルを直接管理する必要はありません。 \ No newline at end of file diff --git a/docs/ja/agenteye/single-pod-deployment.mdx b/docs/ja/agenteye/single-pod-deployment.mdx new file mode 100644 index 00000000..04e9d494 --- /dev/null +++ b/docs/ja/agenteye/single-pod-deployment.mdx @@ -0,0 +1,484 @@ +--- +title: "シングルポッドデプロイ: EKS 上のコレクター + アプリケーションサイドカー" +description: "AgentEye シングルポッドデプロイ: EKS 上のコレクター + アプリケーションサイドカーのドキュメント。" +--- + + +アプリケーションと AgentEye コレクターを**同一の Kubernetes Pod 内**で実行することで、テレメトリーがネットワーク境界を越えることなく収集できます。アプリケーションの SDK とコレクターはポッド内の単一イベントスプールを共有するため、低レイテンシーのインプロセステレメトリーハンドオフが実現し、公開すべき localhost ポートも、通過するサービスメッシュも不要で、コレクターのライフサイクルは監視するワークロードに直接結びついています。コレクターが提示する mTLS クライアント証明書は AWS Secrets Manager から Pod に直接配信されるため、資格情報のローテーションで手動のファイル操作は一切必要ありません。 + +ここで説明するサイドカー + 共有スプールモデルはクラウドに依存しません。`emptyDir` イベントスプールを共有する 2 つのコンテナは、どの Kubernetes ディストリビューションでも動作します。このガイドで AWS / EKS に固有なのは、証明書の配信パス(AWS Secrets Manager + Secrets Store CSI Driver + IRSA)のみです。別のプラットフォームで運用する場合は、ポッドとスプールのレイアウトをそのまま利用し、フェーズ 2 および 3 のシークレットマウント手順をお使いのプラットフォームの仕組みに置き換えてください。 + +> **このパターンを選ぶ場面。** コレクターに到達するためにアプリケーションがネットワーク境界を越えるべきでない場合(低レイテンシーのポッド内 IPC、厳密なライフサイクル結合、テナントごとのポッド分離)には、シングルポッドを選択してください。ノードまたはクラスターごとに 1 つのコレクターを共有するマルチアプリフリートについては、代わりに [enterprise-docs/kubernetes-deployment.md](/ja/agenteye/kubernetes-deployment) を参照してください。 + +--- + +## 概要 + +``` +┌──────────────────────────────── Pod ─────────────────────────────────┐ +│ │ +│ ┌──────────────────────┐ ┌──────────────────────┐ │ +│ │ your-app │ │ agenteye-collector │ │ +│ │ (SDK writes JSONL) │ │ (sweeps events/, │ │ +│ │ │ │ uploads over mTLS) │ │ +│ └──────────┬───────────┘ └──────────┬───────────┘ │ +│ │ writes reads │ │ +│ ▼ ▼ │ +│ ┌────────────────────────────────────────────────────┐ │ +│ │ emptyDir: /var/lib/agenteye/{events,failed}/ │ │ +│ │ (AGENTEYE_HOME - shared event spool) │ │ +│ └────────────────────────────────────────────────────┘ │ +│ ▲ │ +│ │ reads cert │ +│ ┌────────┴─────────┐ │ +│ │ CSI (read-only): │ │ +│ │ /etc/agenteye/ │ │ +│ │ tls/client.{crt, │ │ +│ │ key}, ca.crt │ │ +│ └────────┬─────────┘ │ +└───────────────────────────────────────────────────┼──────────────────┘ + │ mounted by + │ Secrets Store CSI + │ (AWS provider + + │ IRSA) + ┌────────┴──────────┐ + │ AWS Secrets │ + │ Manager │ + │ agenteye/mtls- │ + │ client/ │ + └────────┬──────────┘ + ▲ + │ push on issue / + │ renewal + ┌────────┴──────────┐ + │ Exosphere │ + │ delivers the cert │ + │ bundle into your │ + │ Secrets Manager │ + │ on renewal │ + └───────────────────┘ + +Outbound: collector → AGENTEYE_URL (mTLS, using the CSI-mounted cert). +``` + +2 つのデータフロー、2 つのボリューム: + +- **イベント(ポッド内):** アプリの SDK が `$AGENTEYE_HOME/events/` の共有 `emptyDir` に `.jsonl` ファイルを書き込み、コレクターのスイーパーがそれを読み取ってアップロードします。localhost ポートもループバックも不要で、純粋な共有ファイルシステムによるハンドオフです。 +- **mTLS 証明書(ポッド ← クラウド):** Secrets Store CSI Driver が Secrets Manager から証明書バンドルをマウントし、コレクターコンテナのみにスコープされた `/etc/agenteye/tls/` の読み取り専用ボリュームに配置します。 + +**2 つの独立した当事者:** + +| 当事者 | 責任 | +|---|---| +| Exosphere | mTLS クライアント証明書を発行し、安定した名前で**お客様の** AWS アカウントの Secrets Manager にバンドルを配信します。有効期限前に同じシークレットに更新済みバンドルを再発行します。 | +| お客様 | Secrets Store CSI Driver をインストールし、IRSA 経由でポッドの ServiceAccount にシークレットへの読み取りアクセスを付与し、Pod マニフェストを適用します。以上です。 | + +--- + +## 前提条件 + +### AWS アカウント / EKS クラスター内 + +- **OIDC プロバイダー**が関連付けられた EKS クラスター。次のコマンドで確認できます: + + ```bash + aws eks describe-cluster --name \ + --query "cluster.identity.oidc.issuer" --output text + ``` + + コマンドが `https://oidc.eks.…` の URL を返せば OIDC が有効です。返さない場合は関連付けてください: + + ```bash + eksctl utils associate-iam-oidc-provider \ + --cluster --approve + ``` + +- クラスターにインストールされた [Secrets Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/) および [AWS プロバイダー](https://github.com/aws/secrets-store-csi-driver-provider-aws)(フェーズ 2 を参照)。 + +- ワークステーションに AWS CLI v2 と `kubectl`。 + +### Exosphere との調整 + +デプロイ前に、Exosphere は mTLS クライアントバンドルをお客様の AWS アカウントの Secrets Manager に配信し、以下を提供します: + +- **シークレット名**(命名規則: `agenteye/mtls-client/`) +- シークレットが存在する **AWS リージョン** +- コレクターに設定する **AgentEye バックエンド URL** +- コレクターの **API キー**([enterprise-docs/api-keys.md](/ja/agenteye/api-keys) を参照) + +--- + +## フェーズ 1: Exosphere が配信するもの + +mTLS クライアント証明書をお客様自身で生成する必要はありません。Exosphere が発行し、バンドルをお客様の AWS アカウントの Secrets Manager に直接配信するため、お客様の環境に届く資格情報は、完成済みのすぐにマウントできるシークレットのみです。 + +お客様のアカウントに届くもの: + +| プロパティ | 値 | +|---|---| +| シークレット名 | `agenteye/mtls-client/`(更新をまたいで安定) | +| リージョン | EKS クラスター用に指定した AWS リージョン | +| ペイロード | 3 つのキー(`client.crt`、`client.key`、`ca.crt`)を持つ単一の JSON シークレット。各キーに PEM エンコードされた内容を保持 | +| タグ | `AgentEyeCluster=` | + +更新時には同じシークレットが新しいバージョンでインプレース更新されるため、ARN と名前は変わりません。`SecretProviderClass` と IAM ポリシーはそのまま機能し続けます。証明書のライフサイクル(有効期間、更新サイクル、有効期限アラート)については [enterprise-docs/kubernetes-deployment.md](/ja/agenteye/kubernetes-deployment) を参照してください。 + +--- + +## フェーズ 2: Secrets Store CSI Driver + AWS プロバイダーのインストール + +CSI 経由で AWS シークレットをマウントする別のワークロードがすでに動作している場合は、このステップをスキップしてください。 + +```bash +# CSI Driver +helm repo add secrets-store-csi-driver \ + https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts +helm install -n kube-system csi-secrets-store \ + secrets-store-csi-driver/secrets-store-csi-driver \ + --set syncSecret.enabled=true \ + --set enableSecretRotation=true \ + --set rotationPollInterval=1h + +# AWS provider +kubectl apply -f \ + https://raw.githubusercontent.com/aws/secrets-store-csi-driver-provider-aws/main/deployment/aws-provider-installer.yaml +``` + +**確認:** + +```bash +kubectl get pods -n kube-system | grep -E 'csi-secrets-store|aws-provider' +``` + +期待値: すべてのポッドが `Running` 状態。 + +> **`rotationPollInterval=1h` の理由:** Exosphere が更新済み証明書を発行すると、Secrets Manager がインプレースで更新されます。CSI Driver はこのインターバルでシークレットを再読み込みし、マウントされたファイルを書き換えます。コレクターは証明書ファイルを起動時に 1 度だけ読み込むため、プロセスの再起動後にのみ更新済み証明書を提示するようになります。再起動をトリガーする方法については「証明書のローテーション」セクションを参照してください。 + +--- + +## フェーズ 3: ポッドへのシークレット読み取りアクセスの付与(IRSA) + +### 3.1 IAM ポリシーの作成 + +`agenteye-mtls-reader-policy.json` として保存します: + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "ReadAgentEyeMtlsBundle", + "Effect": "Allow", + "Action": [ + "secretsmanager:GetSecretValue", + "secretsmanager:DescribeSecret" + ], + "Resource": "arn:aws:secretsmanager:::secret:agenteye/mtls-client/-*" + } + ] +} +``` + +``、``、`` を置き換えてください。末尾の `-*` は、AWS がすべてのシークレット ARN に付加する 6 文字のランダムサフィックスに対応します。 + +ポリシーを作成します: + +```bash +aws iam create-policy \ + --policy-name AgentEyeMtlsReader- \ + --policy-document file://agenteye-mtls-reader-policy.json +``` + +### 3.2 IAM ロールの作成とポッドの ServiceAccount へのバインド + +```bash +eksctl create iamserviceaccount \ + --name agenteye-pod \ + --namespace \ + --cluster \ + --role-name AgentEyePodRole- \ + --attach-policy-arn arn:aws:iam:::policy/AgentEyeMtlsReader- \ + --approve +``` + +これにより、新しいロールを指す `eks.amazonaws.com/role-arn` アノテーション付きの `agenteye-pod` という名前の `ServiceAccount` が作成されます。 + +### 3.3 必要な IAM 権限: まとめ + +| 権限 | スコープ | 理由 | +|---|---|---| +| `secretsmanager:GetSecretValue` | `arn:aws:secretsmanager:::secret:agenteye/mtls-client/-*` | CSI Driver がマウントおよびローテーションのたびに証明書バンドルを読み取ります。 | +| `secretsmanager:DescribeSecret` | 同上 | CSI Driver がポーリング間のバージョン変更を検出するために `DescribeSecret` を呼び出します。 | + +`secretsmanager:PutSecretValue`、`secretsmanager:UpdateSecret`、`secretsmanager:DeleteSecret` をポッドに**付与しないでください**。ポッドはシークレットを読み取るのみです。新しいバージョンの書き込みは、証明書の発行または更新時に Exosphere が行います。 + +シークレットがカスタマー管理の KMS キー(デフォルトの `aws/secretsmanager` キーではない)で暗号化されている場合は、以下も付与します: + +```json +{ + "Effect": "Allow", + "Action": ["kms:Decrypt"], + "Resource": "arn:aws:kms:::key/", + "Condition": { + "StringEquals": { + "kms:ViaService": "secretsmanager..amazonaws.com" + } + } +} +``` + +--- + +## フェーズ 4: Pod のデプロイ + +### 4.1 SecretProviderClass + +`agenteye-mtls-spc.yaml`: + +```yaml +apiVersion: secrets-store.csi.x-k8s.io/v1 +kind: SecretProviderClass +metadata: + name: agenteye-mtls + namespace: +spec: + provider: aws + parameters: + objects: | + - objectName: "agenteye/mtls-client/" + objectType: "secretsmanager" + jmesPath: + - path: '"client.crt"' + objectAlias: "client.crt" + - path: '"client.key"' + objectAlias: "client.key" + - path: '"ca.crt"' + objectAlias: "ca.crt" +``` + +`jmesPath` ブロックは、AWS プロバイダーに JSON シークレットをディスク上の 3 つの個別ファイルに分割するよう指示します。`'"client.crt"'` のクォーティングは、JMESPath が `.` をサブ式演算子として扱うために必要です。 + +```bash +kubectl apply -f agenteye-mtls-spc.yaml +``` + +### 4.2 Pod / Deployment マニフェスト + +**2 つのコンテナの通信方法。** AgentEye SDK とコレクターはネットワークソケット経由では通信しません。ローカル HTTP ポートは存在しません。SDK はイベントバッチを `.jsonl` ファイルとして `$AGENTEYE_HOME/events/` に書き込み、コレクターはそのディレクトリを継続的に監視して各ファイルをアップロードします。サイドカーポッドの場合、以下の点が重要です: + +- 両方のコンテナが**同じ** `emptyDir` ボリュームを**同じ**パスにマウントする。 +- 両方のコンテナが `AGENTEYE_HOME` をそのパスに設定する。 +- アプリケーションイメージに AgentEye SDK がインストールされ設定されている必要があります([enterprise-docs/python-sdk.md](/ja/agenteye/python-sdk) を参照)。 + +> `AGENTEYE_HOME` が未設定の場合、SDK とコレクターはいずれもデフォルトで `~/.agenteye` を使用しますが、2 つのコンテナはホームディレクトリが異なるため、別々のスプールに書き込まれ、ハンドオフは無音で失敗します。**両方の**コンテナで `AGENTEYE_HOME` を同じ明示的なパスに設定してください。§4.3 の検証と対応するトラブルシューティング行で、見落とした場合に検出できます。 + +`agenteye-pod.yaml`(レプリカ 1 の Deployment、必要に応じてスケール): + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-app-with-collector + namespace: +spec: + replicas: 1 + selector: + matchLabels: + app: my-app-with-collector + template: + metadata: + labels: + app: my-app-with-collector + spec: + serviceAccountName: agenteye-pod + containers: + - name: app + image: + env: + # SDK writes event JSONL files into $AGENTEYE_HOME/events/ + - name: AGENTEYE_HOME + value: /var/lib/agenteye + volumeMounts: + - name: agenteye-spool + mountPath: /var/lib/agenteye + + - name: agenteye-collector + # Pin to a versioned :v tag for production; :beta-latest + # tracks the current beta build (:latest exists only for stable releases). + image: ghcr.io/agenteye-enterprise/collector:beta-latest + args: ["start"] + env: + # Must match the app container's AGENTEYE_HOME so the collector + # sweeps the same directory the SDK writes to. + - name: AGENTEYE_HOME + value: /var/lib/agenteye + - name: AGENTEYE_URL + value: "https://ingest.example.agenteye.com/events" + - name: AGENTEYE_KEY + valueFrom: + secretKeyRef: + name: agenteye-collector-api-key + key: key + - name: AGENTEYE_TLS_CERT + value: /etc/agenteye/tls/client.crt + - name: AGENTEYE_TLS_KEY + value: /etc/agenteye/tls/client.key + # Only when the AgentEye server presents a cert not signed by a + # publicly-trusted CA (e.g. self-signed by an in-cluster issuer + # because you have no real DNS domain). The CSI mount already + # exposes ca.crt alongside the client cert/key. + - name: AGENTEYE_TLS_CA + value: /etc/agenteye/tls/ca.crt + volumeMounts: + - name: agenteye-spool + mountPath: /var/lib/agenteye + - name: agenteye-mtls + mountPath: /etc/agenteye/tls + readOnly: true + livenessProbe: + exec: + command: ["agenteye-collector", "health"] + initialDelaySeconds: 10 + periodSeconds: 30 + + volumes: + # Shared event spool between app and collector. emptyDir is fine: + # events are transient and the collector drains them before pod + # termination on graceful shutdown. + - name: agenteye-spool + emptyDir: {} + # mTLS cert bundle, mounted read-only into the collector only. + - name: agenteye-mtls + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: agenteye-mtls +``` + +`agenteye-collector-api-key` シークレットにはコレクターの API キーが格納されています(プロビジョニングについては [enterprise-docs/api-keys.md](/ja/agenteye/api-keys) を参照)。 + +**適用:** + +```bash +kubectl apply -f agenteye-pod.yaml +``` + +### 4.3 確認 + +```bash +# Pod が 2/2 コンテナ準備完了で Running 状態であること +kubectl get pods -n -l app=my-app-with-collector + +# 証明書バンドルがマウントされていることを確認 +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- ls -l /etc/agenteye/tls/ +``` + +期待値: `client.crt`、`client.key`、`ca.crt` がすべて存在し、読み取り専用でコンテナユーザーが所有者であること。 + +**共有イベントスプールが両方のコンテナから見えることを確認:** + +```bash +# コレクター内で、起動時にコレクターが自動作成する +# events/ および failed/ サブディレクトリが表示されるはずです: +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- ls /var/lib/agenteye/ + +# アプリ内で、同じディレクトリの内容が表示されるはずです: +kubectl exec -n deploy/my-app-with-collector \ + -c app -- ls /var/lib/agenteye/ +``` + +2 つのリスト結果が異なる場合、ボリュームが両方のコンテナにマウントされていないか、`AGENTEYE_HOME` が異なります。「トラブルシューティング」セクションを参照してください。 + +**エンドツーエンドのスモークテスト:** + +```bash +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- agenteye-collector flush +``` + +期待値: コレクターがキューに入っているイベントをアップロードし、`Done: N/N uploaded, 0 failed.` のサマリーを出力します。スプールが空の場合は `No pending files.` と表示して終了し、何も検証しません。そのため、アプリが少なくとも 1 つのイベントをフラッシュした後にのみ実行してください。 + +`flush` がゼロ以外で終了するのは、**ローカルのセットアップ障害の場合のみ**です: 設定の欠落(URL/キーが解決できない)または読み取り不能/解析不能な TLS 証明書(「トラブルシューティング」セクションを参照)。**API キーが間違っていても終了コードは変わりません**。アップロードが `401` を受け取り、ファイルは `failed/` に移動され、コマンドはファイルごとに `[FAILED] …` と出力した後 `Done: 0/N uploaded, N failed.` と表示して `0` で終了します。不正なキーや拒否されたアップロードを検出するには、終了コードではなく `Done:`/`[FAILED]` の出力を確認するか、`$AGENTEYE_HOME/failed/` にファイルが存在するかどうかを確認してください。 + +--- + +## 証明書のローテーション + +クライアント証明書は 90 日間有効で、有効期限の約 15 日前に自動的に更新されます。Exosphere は更新済みバンドルを同じ Secrets Manager シークレットに発行します。その後のポッド内フローは以下の通りです: + +1. Secrets Manager のシークレットに新しい `AWSCURRENT` バージョンが設定されます。ARN と名前は変わりません。 +2. `rotationPollInterval`(デフォルト 1 時間; フェーズ 2 を参照)以内に、CSI Driver が新しいバージョンを読み取り、`/etc/agenteye/tls/` 以下のファイルを書き換えます。 +3. コレクターは証明書ファイルを**起動時に 1 度だけ**読み込むため、プロセスが再起動されるまで以前の証明書を提示し続けます。更新された証明書に切り替えるには、コレクターを再起動してください。ローリング再起動で十分です: + + ```bash + kubectl rollout restart deploy/my-app-with-collector -n + ``` + + これを自動化するには、`/etc/agenteye/tls/` を監視するサイドカー(例: `inotifywait` を使用)を追加し、ファイルが変更されたときにロールアウトをトリガーします。 + +以前の証明書は更新後も約 15 日間有効なため、取り込みを中断せずに再起動を行う余裕があります。更新済みバンドルの発行は Exosphere が行います。お客様側での通常の作業は、その期間内にコレクターを再起動することだけです。 + +--- + +## トラブルシューティング + +| 症状 | 考えられる原因 | 対処法 | +|---|---|---| +| Pod が `ContainerCreating` で詰まり、`MountVolume.SetUp failed for volume "agenteye-mtls"` イベントが表示される | CSI プロバイダーが Secrets Manager に到達できない | IRSA が正しくバインドされているか確認: `kubectl describe sa agenteye-pod -n ` で `eks.amazonaws.com/role-arn` アノテーションが表示されるはずです。AssumeRole 呼び出しについて CloudTrail を確認してください。 | +| エラー: `AccessDeniedException: not authorized to perform secretsmanager:GetSecretValue` | IAM ポリシーが間違った ARN にスコープされている | シークレット ARN サフィックスはランダムです。正確な ARN ではなくワイルドカード付きの `agenteye/mtls-client/-*` を使用してください。 | +| AWS プロバイダーから `ParameterNotFound` エラー | `SecretProviderClass.objects[].objectName` と Exosphere が配信したシークレットの名前が一致しない | `aws secretsmanager list-secrets --filters Key=tag-key,Values=AgentEyeCluster` で正確な名前を確認してください。 | +| `jmesPath` エラー、ファイルが 1 つしかマウントされない | JMESPath の構文 | JSON キーのドットは二重クォートが必要です: `client.crt` ではなく `'"client.crt"'` を使用してください。 | +| 更新後にコレクターのログに `tls: bad certificate` が出る | CSI Driver がまだ新しいバージョンをポーリングしていないか、コレクターが起動時に読み込んだ以前の証明書で動作し続けている | マウントされたファイルが更新されているか確認(`ls -l /etc/agenteye/tls/`)し、コレクターを再起動してファイルを読み込ませてください: `kubectl rollout restart deploy/my-app-with-collector -n `。「証明書のローテーション」セクションを参照してください。 | +| コレクターコンテナが `no such file or directory: /etc/agenteye/tls/client.crt` でクラッシュループする | 初回起動時にボリュームがまだ作成されていない。スタートアッププローブが積極的すぎる | 少し初期遅延を加えるか、ファイルの存在を待つ init コンテナを使用してください: `until [ -f /etc/agenteye/tls/client.crt ]; do sleep 1; done` | +| CSI Driver ポッドが `OOMKilled` になる | SecretProviderClass が多いクラスターではデフォルトのメモリ制限が不足 | Helm インストールで `--set linux.resources.limits.memory=200Mi` を増やしてください。 | +| アプリは正常に動作し、`agenteye-collector flush` は `No pending files.` と報告するが、AgentEye ダッシュボードにイベントが表示されない | アプリとコレクターがイベントスプールを共有していない | (a) 両方のコンテナが同じ `agenteye-spool` emptyDir を同じパスにマウントしていること、(b) 両方が `AGENTEYE_HOME` をそのパスに設定していることを確認してください。§4.3 の 2 つの `ls /var/lib/agenteye/` チェックを実行し、リスト結果が一致することを確認してください。 | + +**最初に収集するログ:** + +```bash +kubectl logs -n kube-system -l app=secrets-store-csi-driver --tail=100 +kubectl logs -n kube-system -l app=csi-secrets-store-provider-aws --tail=100 +kubectl describe pod -n -l app=my-app-with-collector +``` + +--- + +## リファレンス: ポッド内のディスク上のファイル + +ポッドにはディスク上に 2 つのデータパスがあります: + +### mTLS 証明書バンドル: `/etc/agenteye/tls/`(CSI、読み取り専用、コレクターのみ) + +AWS Secrets Manager から Secrets Store CSI Driver によってマウントされます。 + +| ファイル | 内容 | コレクターでの使用 | +|---|---|---| +| `client.crt` | PEM エンコードされたクライアント証明書 | `AGENTEYE_TLS_CERT` | +| `client.key` | PEM エンコードされた秘密鍵 | `AGENTEYE_TLS_KEY` | +| `ca.crt` | PEM エンコードされた CA 証明書 | `AGENTEYE_TLS_CA`(オプション、AgentEye サーバー証明書がパブリックに信頼されていない場合のみ) | + +3 つすべてが読み取り専用でマウントされ、コンテナユーザーが所有します。シークレットがローテーションされると CSI Driver によって書き換えられます。 + +### イベントスプール: `$AGENTEYE_HOME/`(emptyDir、両コンテナ間で読み書き共有) + +`agenteye-spool` という名前の `emptyDir` ボリューム経由で共有されます。 + +| パス | 書き込み元 | 読み取り元 | 目的 | +|---|---|---|---| +| `$AGENTEYE_HOME/events/*.jsonl` | アプリ(AgentEye SDK) | コレクタースイーパー | SDK がフラッシュしたイベントバッチ。アップロード待ち。 | +| `$AGENTEYE_HOME/failed/` | コレクター(アップロード失敗時) | お客様(デバッグ時) | コレクターがリトライ後もアップロードできなかった JSONL ファイル。 | +| `$AGENTEYE_HOME/config.json` | お客様(オプション) | コレクター | オプションのコレクター設定ファイル(環境変数の代替)。 | + +`events/` と `failed/` の両サブディレクトリはコレクターの起動時に自動作成されます。`initContainer` は不要です。 + +--- + +## 関連ドキュメント + +- [enterprise-docs/collector-installation.md](/ja/agenteye/collector-installation): コレクターバイナリのオプション、mTLS 設定リファレンス、デーモンモード。 +- [enterprise-docs/kubernetes-deployment.md](/ja/agenteye/kubernetes-deployment): マルチポッドデプロイ、証明書発行の内部動作、ライフサイクルと有効期限アラート。 +- [enterprise-docs/api-keys.md](/ja/agenteye/api-keys): ポッドで使用するコレクター API キーのプロビジョニング。 +- [enterprise-docs/troubleshooting.md](/ja/agenteye/troubleshooting): クラスター全体のトラブルシューティングインデックス。 \ No newline at end of file diff --git a/docs/ja/agenteye/tenant-management.mdx b/docs/ja/agenteye/tenant-management.mdx new file mode 100644 index 00000000..f8406857 --- /dev/null +++ b/docs/ja/agenteye/tenant-management.mdx @@ -0,0 +1,167 @@ +--- +title: "テナント管理(組織とメンバー)" +description: "AgentEye テナント管理(組織とメンバー)のドキュメント。" +--- + + +単一の AgentEye デプロイメントで、複数の完全に分離された**組織**(テナント)を提供します。これにより、1つのインスタンスで異なるチーム、事業部門、または顧客をホストしながら、あるテナントのデータが別のテナントに公開されることを防ぎます。すべてのデータ行(イベント、評価、セッション、ダッシュボード、保存済みクエリ、アラート、APIキー、メンバー)は、必ず1つの組織に属します。主要な分離はアプリケーションコードで強制されます。すべてのリクエストは、明示的な `org_id` 述語によって対象の組織にスコープされます。大量のイベントと評価が格納される ClickHouse では、これはエンジンレベルの強力な強制によって裏付けられています。各組織は専用の読み取り専用 ClickHouse ユーザーと組織ごとの行ポリシーを持つため、信頼されていない分析 SQL でも別テナントの行を読み取ることはできません。PostgreSQL では、行レベルセキュリティが読み取り専用クエリパス(`/queries/run`)に多層防御を追加し、アプリケーションレベルのフィルターが欠落していた場合でも、そのパスが参照できるデータを制限します。サーバー自身の書き込みコネクションはテーブルオーナーとして実行されるため、アプリケーションレベルの `org_id` スコープを通じて動作します。 + +テナントのライフサイクルはオペレーターが管理し、メンバーが日常的に行うすべての操作はダッシュボードでセルフサービスとして利用できます。組織とそのメンバーシップは **`agenteye-orgctl`** CLIを使用して作成・管理します。このCLIはサーバーイメージに同梱されており、**既存のサーバーポッド内で実行します**。テナントの作成と削除は意図的にダッシュボードとHTTP APIから除外されています。テナントのライフサイクルには**HTTPエンドポイントもダッシュボードのボタンも存在しません**。そのため、アプリケーションの表面からではなく、クラスター/ポッドのシェルアクセスによってのみ操作できます。 + +組織内では、メンバーはダッシュボードとAPIだけで作業します。サインイン、所属する組織の切り替え、自分のAPIキーの管理、ダッシュボードや保存済みクエリの構築、および組織のアラート設定などが行えます。役割分担は明確です。オペレーターはCLIを通じてテナントとメンバーのプロビジョニング・廃止を行い、メンバーはUIを通じてテナント内のすべてを操作します。 + +> **シングルテナント構成ではこの手順は不要です。** シングルテナントのインストールは、オペレーターの操作なしに動作します。すべてのデータ、ユーザー、キーは、自動的にプロビジョニングされる組み込みの `default` 組織に格納されます。このガイドが必要になるのは、2つ目の組織を追加する場合のみです。 + +--- + +## 前提条件 + +**2つ目**の組織を作成する前に(組み込みの `default` 組織には何も必要ありません): + +- **PostgreSQL 15以降。** 組織メンバーシップのスキーマは、PostgreSQL 15以降が必要な列リスト形式の `ON DELETE SET NULL` 外部キーを使用します。2つ目の組織をプロビジョニングする前に PostgreSQL をアップグレードしてください。 +- **強力で安定した `ORG_CH_SECRET`。** 各組織の ClickHouse パスワードは `HMAC(ORG_CH_SECRET, org_id)` として導出されます。そのため、公知の組み込み開発用デフォルト値を使用すると、組織ごとの認証情報が外部から推測可能になります。`agenteye-orgctl org create` は **`ORG_CH_SECRET` が未設定または組み込みの開発用デフォルト値のままの場合、実行を拒否します**。事前に独自の値を設定してください([デプロイメント → 環境変数](/ja/agenteye/deployment) および Kubernetes の場合は [Kubernetes ガイドのセクション 2.6](/ja/agenteye/kubernetes-deployment#26-multi-tenant-org-isolation-key-optional) を参照してください)。すべてのサーバーレプリカで同一の値を使用し、気軽にローテーションしないでください。ローテーションすると、次回の起動で再プロビジョニングされるまで、すべての組織の ClickHouse ユーザーが孤立状態になります。 + +--- + +## CLIの実行方法 + +`agenteye-orgctl` は **サーバーと同じイメージ**(`agenteye-server` の隣)に同梱されています。専用のポッド、Job、Deployment はデプロイ**しません**。既に実行中のサーバーポッド内で exec して使用するため、サーバーが使用している `DATABASE_URL`、`CLICKHOUSE_URL`、`ORG_CH_SECRET` と同じ値が読み込まれます。 + +**Kubernetes:** + +```bash +kubectl -n agenteye exec deploy/server -- agenteye-orgctl +``` + +**Docker Compose:** + +```bash +docker compose exec server agenteye-orgctl +``` + +以下の例では簡潔さのために `agenteye-orgctl ` のみ記載しています。実際には、デプロイメント環境に応じて上記いずれかの行を先頭に付けてください。 + +--- + +## コマンドリファレンス + +### 組織 + +| コマンド | 内容 | +|---|---| +| `org create --slug --name ` | 新しい組織を作成します。`ORG_CH_SECRET` が未設定または組み込みの開発用デフォルト値のままの場合は実行を拒否します(前提条件を参照して事前に独自の値を設定してください)。組織の読み取り専用 ClickHouse ユーザーと行ポリシーをプロビジョニングします。 | +| `org list` | すべての組織(スラッグ、名前、ライフサイクル状態)を一覧表示します。 | +| `org rename --slug --name ` | 組織の表示名を変更します。スラッグ(URLとキーで使用)は変更されません。 | +| `org delete --slug ` | 組織を**ソフトデリート**し、その ClickHouse ユーザーを削除します。データは**保持されます**。アクセスを無効化し、組織ごとの ClickHouse 認証情報を解放しますが、イベントは削除しません。オペレーターによって元に戻すことができ、パージ前の安全な最初のステップです。 | +| `org purge --slug ` | **不可逆的なデータ削除。** 組織は事前に `delete` されている必要があります。組み込みの `default` 組織には絶対に実行できません。テナントのデータを確実に破棄する場合にのみ使用してください。 | + +### メンバー + +| コマンド | 内容 | +|---|---| +| `member add --org --email [--set ] [--add perm1,perm2] [--remove perm3] [--protected]` | 組織にメンバーを追加します。オプションで組み込みの権限セットをベースにして、個別の権限を追加/削除できます。`--protected` を指定すると、ダッシュボードからメンバーを削除またはデモートできなくなります(後述)。新しいメンバーは、最初のダッシュボードログイン時にOTPを受け取ります。 | +| `member list --org ` | 組織のメンバーを一覧表示します。出力列は `EMAIL`、`SET`(メンバーが使用した組み込みセット、または `-`)、`PROT`(メンバーが保護されているかどうか)、`PERMISSIONS`(有効な権限)です。末尾に `*` が付いたメールアドレスはインスタンス管理者を示し、すべての組織にアクセスできます。 | +| `member update --org --email [--set ...] [--add ...] [--remove ...] [--protected \| --unprotect]` | メンバーの権限や保護フラグを変更します。`--set` は組み込みセットで置き換え、`--add` / `--remove` は個別の権限を調整し、`--protected` / `--unprotect` は保護を切り替えます。付与フラグなしで `--protected`/`--unprotect` のみを指定した場合、保護のみが変更され、既存の権限はそのまま維持されます。 | +| `member remove --org --email ` | 組織からメンバーを削除します。メンバーが保護されている場合は拒否されます。先に `--unprotect` してください。(1人が複数の組織のメンバーになれますが、これは指定した組織のみに影響します。) | + +1人が複数の組織のメンバーになることができ、それぞれで**異なる**権限を持てます。例えば、ある組織では管理者、別の組織では読み取り専用といった設定が可能です。各メンバーシップは組織ごとに独立して管理されます。ある組織でのメンバーの権限変更は、他の組織でのメンバーシップには影響しません。 + +### 保護メンバー(削除不可能な組織管理者) + +保護機能により、組織が誤ってセルフ管理から締め出されることを防ぎます。デフォルトでは、組織内の管理者はダッシュボードのセルフサービスのユーザーページから互いを追加・削除できるため、最後の管理者を削除して組織を管理できない状態にしてしまう可能性があります。 + +![ユーザーページ:ダッシュボードユーザーごとにカードが表示され、メールアドレス、付与された権限、編集/無効化コントロールが含まれます](/agenteye/images/users.png) + +これを防ぐために、1人のメンバーを**保護**としてマークします: + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member add --org acme --email owner@acme.example --set admin --protected +``` + +保護されたメンバーは**ダッシュボードから削除またはデモートできません**。そのような操作はエラーになります。変更できるのはオペレーターのみで、このCLIからのみ操作可能です。まず `member update --org acme --email owner@acme.example --unprotect` を実行してから、削除またはデモートしてください。これにより、すべての組織が少なくとも1人の管理者を維持し、組織のメンバー自身がその管理者を締め出せないようになります。また、テナントの管理権限はオペレーターのみに維持されます。保護は**組織ごと**に設定されます。ある組織で誰かを保護しても、別の組織でのメンバーシップには影響しません。 + +### 組み込み権限セット + +`--set` は、組織ごとに適用される3つの組み込みセットのいずれかを受け付けます: + +| セット | 対象 | +|---|---| +| `admin` | 組織内でのフルアクセス。組織のAPIキーとユーザーの管理を含みます。 | +| `standard` | 日常的な使用:クエリの読み取りと実行、ダッシュボードの構築、インシデントの承認。 | +| `read-only` | 組織のデータとダッシュボードへの閲覧のみのアクセス。 | + +`--set` でセットを指定した後、[APIキー](/ja/agenteye/api-keys) に記載されている個別の権限トークンを使用して `--add` / `--remove` で細かく調整できます。権限トークン自体はAPIキーに使用されるものと同一です。 + +--- + +## 実践例 + +新しい `acme` テナントをプロビジョニングし、最初の管理者を追加して、キーを作成させた後、組織を廃止します。 + +**1. 組織を作成する**(`ORG_CH_SECRET` は事前に強力で安定した値に設定されている必要があります。未設定または組み込みの開発用デフォルト値のままにしないでください): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org create --slug acme --name "Acme Corp" +``` + +**2. 最初のメンバーを組織管理者として追加する:** + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member add --org acme --email alice@acme.example --set admin +``` + +Alice はダッシュボードに初めてサインインするときにOTPを受け取ります。それ以降は、組織のURLプレフィックス(例: `/acme/sessions`)のもとで、UIでのみ作業します。 + +**3. 組織ごとのAPIキーを作成する(ダッシュボードにて):** + +オペレーターはCLIから組織ごとのデータキーを**作成しません**。Alice(または `keys:create` 権限を持つ組織メンバー)が、ダッシュボードの**キー**ページから `acme` 組織のコレクター/ダッシュボードキーを作成します。作成されたすべてのキーは自動的に組織と紐付けられ、`acme` のデータの読み書きのみが可能です。[APIキー](/ja/agenteye/api-keys) を参照してください。 + +**4. 後でメンバーを変更する:** + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member update --org acme --email alice@acme.example --add alerts:write + +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member list --org acme +``` + +**5. 組織をソフトデリートする**(アクセスを無効化し ClickHouse ユーザーを削除;データは保持): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org delete --slug acme +``` + +**6. 組織をパージする**(不可逆;ソフトデリート後のみ;`default` 組織は不可): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org purge --slug acme +``` + +Docker Compose の場合は、各コマンドの `kubectl -n agenteye exec deploy/server --` プレフィックスを `docker compose exec server` に置き換えてください。 + +--- + +## 責任の分担 + +組織メンバーが日常的に必要とするすべての操作は、ダッシュボードとAPIでセルフサービスとして利用でき、現在の組織に自動的にスコープされます: + +- **組織ごとのAPIキー**は、ダッシュボード(または `keys:create` を持つキーを使用したキーAPIを通じて)で組織メンバーが作成・管理します。CLIはデータキーを**作成しません**。[APIキー](/ja/agenteye/api-keys) を参照してください。 +- **組織の切り替え**はダッシュボードに組み込まれており、メンバーは組織スイッチャーから所属する組織を切り替えることができます。組織スコープのページは `//…` 以下に存在します。 +- **ダッシュボード、保存済みクエリ、アラート、およびすべてのデータ利用**は、UIとAPIで完結し、メンバーの現在の組織にスコープされます。 + +オペレーターは `agenteye-orgctl` を使用して、組織とメンバーの**ライフサイクル**のみを管理します。つまり、組織の作成/名前変更/削除/パージ、およびメンバーの追加/一覧表示/更新/削除です。 + +--- + +## 関連情報 + +- [デプロイメント](/ja/agenteye/deployment): `ORG_CH_SECRET` とその他のサーバー環境変数。 +- [Kubernetes デプロイメント](/ja/agenteye/kubernetes-deployment): セクション 2.6 では、最初のマルチテナント組織の前に `agenteye-org-ch-secret` シークレットを作成します。 +- [APIキー](/ja/agenteye/api-keys): 組織ごとのキーモデルと、`--add` / `--remove` で使用される権限トークン。 +- [トラブルシューティング](/ja/agenteye/troubleshooting): マルチテナントのプロビジョニングと ClickHouse 分離に関する問題。 \ No newline at end of file diff --git a/docs/ja/agenteye/troubleshooting.mdx b/docs/ja/agenteye/troubleshooting.mdx new file mode 100644 index 00000000..44917897 --- /dev/null +++ b/docs/ja/agenteye/troubleshooting.mdx @@ -0,0 +1,610 @@ +--- +title: "トラブルシューティング" +description: "AgentEye トラブルシューティングドキュメント。" +--- + + +このガイドでは、本番環境で発生しやすい症状を具体的な診断方法と修正手順にマッピングしています。追加の監視インフラを構築しなくても、既存のツールでインシデントを解決できます。対象範囲は、サーバー、コレクター、ダッシュボード、AIアシスタント、Python SDK、ヘルスおよび証明書モニタリング、バックアップ、ClickHouse連携アナリティクス、マルチテナントです。 + +ダッシュボードのページは `//…` 配下に組織スコープされており、イベントストリームは組織ホーム (`//`) です。このガイドのページ名(例:`/sessions`、`/queries`)は、これらの組織スコープのルートを指します。 + +--- + +## ログの確認 + +AgentEye はロギングや監視スタックをバンドルしていません。サーバーとダッシュボードはどちらも構造化ログを **stdout** に書き出すため、`kubectl` や `docker` で直接読み取れます。アグリゲーターは不要です。 + +### Kubernetes + +サーバーとダッシュボードのライブログを表示する: + +```bash +kubectl logs -n agenteye -l app=server -f --timestamps +kubectl logs -n agenteye -l app=dashboard -f --timestamps +``` + +便利なバリエーション: + +| 目的 | コマンド | +|---|---| +| 直近200行(フォローなし) | `kubectl logs -n agenteye -l app=server --tail=200 --timestamps` | +| 前回クラッシュ時のログ | `kubectl logs -n agenteye --previous` | +| 全レプリカを一括テール | `kubectl logs -n agenteye -l app=server --max-log-requests=10 -f` | +| Postgres(StatefulSet) | `kubectl logs -n agenteye postgres-0 -f` | + +### Docker Compose + +```bash +docker logs -f agenteye-server +docker logs -f agenteye-dashboard +``` + +### ダッシュボードとサーバー間の単一リクエストの追跡 + +ダッシュボードの各リクエストには `request_id` が付与され、`x-request-id` ヘッダーを通じてサーバーへ伝搬されます。サーバーはレスポンスヘッダーと、そのリクエストに関するすべてのログ行にこのIDを含めます。リクエストをエンドツーエンドで追跡するには: + +1. レスポンスヘッダーからIDを取得する: + ```bash + curl -i https://dashboard.example.com/api/events | grep -i x-request-id + # x-request-id: 9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a + ``` +2. 両方のPodのログから該当IDを検索する: + ```bash + REQ=9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a + kubectl logs -n agenteye -l app=dashboard --tail=5000 | grep "$REQ" + kubectl logs -n agenteye -l app=server --tail=5000 | grep "$REQ" + ``` + +ダッシュボードの `proxy passthrough`、`withAuth: authorized`、`upstream response` の各行と、サーバーの `http request received` / `http request completed` のペアが、同じ `request_id` を共有しているのを確認できます。 + +### JSON ログと `jq` + +ダッシュボードに `AE_LOG_JSON=1` を設定(`NODE_ENV=production` の場合はデフォルトで有効)すると、1行1JSONオブジェクト形式で出力されます。構造的にフィルタリングできます: + +```bash +kubectl logs -n agenteye -l app=dashboard --tail=5000 \ + | jq 'select(.level == "warn" or .level == "error")' + +kubectl logs -n agenteye -l app=dashboard --tail=5000 \ + | jq 'select(.route == "POST /api/keys")' +``` + +Rust サーバーは `key=value` 形式のトレースログを出力するため、`jq` なしで grep できます: + +```bash +kubectl logs -n agenteye -l app=server --tail=5000 | grep 'status=5' # 5xx +kubectl logs -n agenteye -l app=server --tail=5000 | grep 'actor_key_id=' +``` + +### ログの詳細度を上げる + +| コンポーネント | 環境変数 | 例 | +|---|---|---| +| サーバー | `RUST_LOG` | `RUST_LOG=debug` または `RUST_LOG=agenteye_server=debug,info` | +| ダッシュボード | `AE_LOG_LEVEL` | `AE_LOG_LEVEL=debug` | + +サーバーで `debug` を設定すると、認証ごとに `api key authenticated` ログが追加されます。ダッシュボードで `debug` を設定すると、`upstream request`、`session validated`、`proxy passthrough` の各ログが追加されます。 + +### ログの保持期間 + +コンテナの stdout は揮発性です。kubelet はログファイルをローテーション(デフォルトでコンテナあたり約10MiB)し、ディスク上に少数のファイルのみ保持します。Podが削除されるとログも失われます。より長期間の保持やPodをまたいだ検索が必要な場合は、`/var/log/containers/` をテールするログコレクター(Loki、CloudWatch、Cloud Logging、Datadogなど)をクラスターに設定してください。AgentEye は特定の選択を要求・規定しません。 + +--- + +## 認証の問題 + +### `docker pull` が "unauthorized" で失敗する + +`AGENTEYE_TOKEN` を使って Docker を GHCR に対して認証済みであることを確認してください: + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +トークンには `agenteye-enterprise` 組織に対する `read:packages` 権限が必要です。トークンが機能しない場合は `support@exosphere.host` にお問い合わせください。 + +### `gh release download` が 404 または 401 を返す + +- `AGENTEYE_TOKEN` がシェルにエクスポートされていることを確認する:`echo $AGENTEYE_TOKEN` +- `GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download ...` の形式で使用していることを確認する(`gh` CLI は `GITHUB_TOKEN` を読み取ります) +- トークンには `agenteye-enterprise/releases` に対する `contents:read` が必要です + +--- + +## サーバーの問題 + +### サーバーが "invalid port number" で失敗する + +`POSTGRES_PASSWORD`(または他の認証情報)にURLで特殊扱いされる文字(`/`、`+`、`=`)が含まれており、`DATABASE_URL` のパースが失敗しています。16進エンコードを使ってパスワードを再生成してください: + +```bash +NEW_PASS=$(openssl rand -hex 24) +``` + +その後、Kubernetes シークレットと Postgres 内のパスワードを更新(または Docker Compose 用の `.env` を再作成)し、サーバーを再起動してください。詳細な手順は [enterprise-docs/kubernetes-deployment.md](/ja/agenteye/kubernetes-deployment) の「PostgreSQL credentials」セクションを参照してください。 + +### サーバーが起動直後に終了する + +コンテナのログを確認してください: + +```bash +docker logs agenteye-server +``` + +よくある原因: +- `DATABASE_URL` が未設定または形式が不正:サーバーはエラーをログに記録して終了します。 +- Postgres に到達できない:Postgres コンテナまたはマネージドDBが稼働しており、ホスト/ポートが正しいことを確認してください。 +- マイグレーションが失敗した:SQLエラーのログを確認してください。 + +### `GET /health` が 200 以外を返すかタイムアウトする + +初回起動時にサーバーがマイグレーションを実行中の可能性があります。数秒待ってから再試行してください: + +```bash +curl http://localhost:8080/health +``` + +問題が続く場合は、`docker logs agenteye-server` でエラーを確認してください。 + +### `GET /ready` が 503 を返す + +`/ready` はレディネスプローブです。サーバーが **Postgres または ClickHouse** に到達できない場合に `503` を返します。レスポンスボディに問題のある依存関係が記載されています: + +```bash +curl -s http://localhost:8080/ready +# {"status":"not_ready","checks":{"postgres":"ok","clickhouse":"down","redis":"ok"}} +``` + +`down` と報告された依存関係を修正してください:ClickHouse/Postgres の Pod は `Running` ですか?`CLICKHOUSE_URL` / `DATABASE_URL` は正しく、到達可能ですか?Kubernetes では、`/ready` が回復するまで Pod は `NotReady` 状態になります。これは想定動作であり、まさにヘルスモニタリングがアラートを発するシグナルです。Redis は readiness の失敗原因にはなりません。報告はされますが、readiness を失敗させません。 + +### コレクターが 401 Unauthorized を返す + +コレクターの API キーに `events:add` 権限がないか、キーが無効化されています。正しい権限で新しいキーを作成してください: + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{"name":"new-collector","permissions":["events:add"]}' +``` + +### 認証済みリクエストが突然遅くなった(〜5ms から〜200ms に) + +これは `REDIS_URL` が設定されているのに Redis がダウンしているときの症状です。すべてのキャッシュ呼び出しが100ms後にタイムアウトし、Postgres にフォールスルーします。認証と OTP のパスでは、リクエストごとにこのフォールスルーが2回発生します。 + +サーバーログで確認する: + +``` +auth cache: L2 get failed error=redis call timed out +``` + +対処法: + +1. `redis-cli -h ping` で Redis がクラスターネットワーク上で到達可能か確認する。 +2. Redis が一時的にダウンして復旧した場合は、**サーバー Pod を再起動**してください。`redis::aio::ConnectionManager` は基盤となる接続が切断された後に確実に再接続しないため、Pod の再起動によってクリーンに新しい接続を確立します。ダッシュボードも同様です。 +3. 現時点で Redis を使いたくない場合は、デプロイメントから `REDIS_URL` を削除して再起動してください。両サービスはキャッシュなしで動作します(正確性は保たれ、レイテンシは Redis 導入前のベースラインに戻ります)。 + +### サーバーのログに `OTP request rate-limited` が記録されるが、ユーザーは一度しか試みていないと言っている + +Redis が到達不能だったかどうかを確認してください。フォールバックパスは `SELECT COUNT(*) FROM otp_codes WHERE created_at > now() - interval '15 minutes'` を使用しており、既に生成された OTP の行が見えます。ユーザーが1時間ほど「再送信」をクリックし続けていた場合、15分のウィンドウ内にまだ5件以上のコードが含まれている可能性があります。ウィンドウが切れるまで待つか、`DELETE FROM otp_codes WHERE user_id = $1 AND created_at > now() - interval '15 minutes'`(オペレーターコンソール)で解消できます。 + +### `ALLOWED_EMAILS` / `SESSION_TTL_SECS` / `OTP_TTL_SECS` を変更して再起動したが、何も変わらない + +これらの環境変数は**初回起動時のシードのみ**です。`settings` テーブルに対応するキーの行が存在する場合、その行が正規の設定です。環境変数は初回起動時に一度だけ読み込まれ、以降の再起動では無視されます。 + +初回起動後に変更するには、ダッシュボードにログインして `/settings` で編集してください。変更はすべてのレプリカに数秒以内に適用されます。再起動は不要です。 + +環境変数から強制的に再シードする必要がある場合(まれで、通常は開発時のみ有用)は、`DELETE FROM settings WHERE key = ''` を実行してサーバーを再起動してください。次回起動時に現在の環境変数の値が読み込まれます。本番環境では `/settings` での編集が推奨されます。 + +--- + +## コレクターの問題 + +### コレクターは起動しているが、ダッシュボードにイベントが表示されない + +1. コレクターが稼働していることを確認する:`systemctl status agenteye-collector`(Linux)またはプロセスを確認する。 +2. `AGENTEYE_URL` が `http(s)://your-server-host:8080/events`(`/events` パスに注意)を指していることを確認する。 +3. ワンショットフラッシュを実行して即座に出力を確認する: + ```bash + agenteye-collector flush + ``` +4. Python SDK が実際にファイルを書き込んでいるか確認する:`ls ${AGENTEYE_HOME:-~/.agenteye}/events/` +5. `${AGENTEYE_HOME:-~/.agenteye}/failed/` にファイルが存在する場合、アップロードが失敗しています。コレクターのログでエラーを確認してください。4xx(不正なキーまたはURL)またはネットワークの問題の可能性があります。 + +### `$AGENTEYE_HOME/events/` にファイルが蓄積され、アップロードされない + +- コレクターが起動していない可能性があります。`agenteye-collector start` で起動してください。起動時に既存のイベントを自動的にフラッシュします。 +- コレクターのヘルスを確認する:`agenteye-collector health` +- コレクターは稼働しているがサーバーに到達できない可能性があります。コレクターとサーバーホスト間のファイアウォールルールを確認してください。 + +### `$AGENTEYE_HOME/failed/` 内のファイル + +ファイルはすべての再試行(デフォルト:指数バックオフで5回)が尽きた後に `failed/` に移動されます。これは以下のいずれかを意味します: +- サーバーが 4xx エラーを返した(不正なキー、誤ったURL、またはペイロードの問題) +- 全リトライウィンドウの間、サーバーに到達できなかった + +根本的な問題を修正してから、手動で再キューに入れてください: + +```bash +mv ${AGENTEYE_HOME:-~/.agenteye}/failed/*.jsonl ${AGENTEYE_HOME:-~/.agenteye}/events/ +agenteye-collector flush +``` + +### コレクターがすべてのアップロードで `network error` を報告する(TLSハンドシェイクが失敗) + +`curl -k` で `AGENTEYE_URL` に対して成功するが、コレクターバイナリがすべてのアップロードで `error sending request for url (...)` エラーで失敗する場合、AgentEye サーバーが公的に信頼された CA によって署名されていない TLS 証明書を提示しています。 + +**本番環境での対処法**は `deploy/base/certificates/domain.env` で設定された ACME インジェストホスト名を使用することです([`kubernetes-deployment.md`](/ja/agenteye/kubernetes-deployment) のフェーズ 3.1 / 4.2 を参照)。`INGEST_DOMAIN` がパブリックの Traefik LB に解決され、cert-manager が Let's Encrypt 証明書を発行したら、コレクターはシステムトラストストアでサーバー証明書を検証します。**`AGENTEYE_TLS_CA` は不要**です。以前の自己署名デプロイに対して設定していた場合は削除してください。 + +**症状:コレクターは昨日まで動作していたが、約90日後に失敗するようになった。** これは、デプロイメントが `ingest-tls` に従来の `selfsigned` 発行者を使い続けていることを意味します。90日間隔で証明書がローテーションされ、ピン留めされた CA ファイルが古くなっています。恒久的な修正として、クラスターを ACME 発行者に切り替えてください(デプロイガイドのフェーズ 3.1)。短期的な回避策として、現在のサーバー証明書を再抽出して `AGENTEYE_TLS_CA` を更新します: + +```bash +kubectl get secret ingest-tls-cert -n agenteye \ + -o jsonpath='{.data.tls\.crt}' | base64 -d > /etc/agenteye/server-ca.crt +``` + +```bash +export AGENTEYE_TLS_CA=/etc/agenteye/server-ca.crt +agenteye-collector flush +``` + +`AGENTEYE_TLS_CA` は追加のトラストアンカーを追加します。標準のパブリックルートは引き続き信頼されます。 + +### デプロイ後に `ingest-tls` 証明書が `Ready: False` のままになる + +```bash +kubectl describe certificate ingest-tls -n agenteye +``` + +`Events` と参照されている `Order` / `Challenge` を確認してください。よくある原因: + +- **DNS がパブリック LB に解決されていない。** HTTP-01 バリデーターが `INGEST_DOMAIN` に到達できません。`dig +short INGEST_DOMAIN` で確認してください。`traefik-public` ロードバランサーの `EXTERNAL-IP` と同じアドレスに解決されるはずです。DNS が伝搬されると cert-manager は自動的に再試行します。証明書を削除する必要はありません。 +- **ロードバランサー/セキュリティグループでポート80がブロックされている。** HTTP-01 では、Let's Encrypt のパブリックバリデーターからポート80に到達可能である必要があります。上流の WAF や SG が `:80` を制限している場合は開放してください(Traefik の設定は HTTPS にリダイレクトしますが、Boulder はリダイレクトに従いレスポンスを受け入れます)。 +- **`dnsNames` が置換されていない。** `kubectl get certificate ingest-tls -n agenteye -o jsonpath='{.spec.dnsNames}'` が `INGEST_DOMAIN_PLACEHOLDER` を表示する場合は、`domain.env` のステップをスキップしています。`domain.env.example` から作成して再適用してください。 +- **Let's Encrypt によるレート制限。** 同一ホスト名への繰り返しの失敗したオーダーは、重複証明書または検証失敗の制限に達します。少なくとも1時間待ってから再試行してください。正確なレート制限メッセージは Order のステータスで確認できます。 + +### `dashboard-tls` 証明書が `Ready: False` のままになる / ブラウザに警告が表示される + +`ingest-tls` と同じ診断フロー(`kubectl describe certificate dashboard-tls -n agenteye`)です。DNS、ポート80、プレースホルダー、レート制限の原因がすべて該当するほか、ダッシュボード固有の原因が2つあります: + +- **`DASHBOARD_DOMAIN` が誤ったロードバランサーに解決される。** *ダッシュボード* の Traefik LB を指している必要があります。パブリックインジェスト用ではありません。ホスト名を `dig +short` で確認し、ダッシュボードの LB アドレスと比較してください。 +- **ダッシュボードの Traefik インスタンスがチャレンジを処理できない。** cert-manager の HTTP-01 ソルバー用にスコープされた Ingress プロバイダーを有効にするバンドルされたダッシュボード値ファイルでインストールする必要があります。これがないとソルバーがルーティングできず、Order は永遠に `pending` 状態のままになります。提供された values でインスタンスをアップグレードしてください。保留中のチャレンジは自動的に完了します。 +- **ロードバランサーが IP 制限されていた。** ソースレンジはポート80にも適用され、Let's Encrypt のバリデーターをブロックします。初回発行時と約75日ごとの更新時の両方に影響します。LB を再開放するか、ロックダウン前にサポートと DNS-01 ソルバーについて調整してください。 + +発行が失敗している間、ダッシュボードは以前の証明書(または新規インストールの場合は ingress のデフォルト)を引き続き提供します。アクセスはブラウザ警告で劣化しますが、ダウンにはなりません。 + +### ダッシュボードが信頼された証明書を取得した後も、CLI が TLS 検証をスキップし続ける + +`--insecure` はログイン時に `cli.json` に保存されます。ダッシュボードが公的に信頼された証明書を提供するようになったら、`agenteye --base-url https:// --secure login` で再ログインしてください。検証が有効に保存され、起動時の警告が消えます。 + +--- + +## ダッシュボードの問題 + +### `ADMIN_EMAIL` ユーザーを無効化または編集できない + +これは仕様です。`ADMIN_EMAIL` に一致するユーザーはサーバーの起動のたびに保護済みとしてマークされます。ダッシュボードはその行の無効化ボタンを非表示にし、API は `DELETE /users/:id` および `PUT /users/:id` に対して `403 Forbidden` を返します。データベーストリガーも保護された行を無効化しようとする直接の `UPDATE` 文を拒否します。 + +ブートストラップ管理者をローテーションするには、環境の `ADMIN_EMAIL` を変更してサーバーを再起動してください。新しいメールアドレスが保護済みとしてアップサートされます。以前の管理者はデータベースでフラグが解除されるまで保護済み状態のままですが(以前のメールアドレスを明示的に削除するまでは有効な管理者のままなので通常は問題ありません)。 + +### ダッシュボードにイベントが表示されない + +1. ダッシュボードの環境変数(`AGENTEYE_SERVER_URL`、`AGENTEYE_API_KEY`)のサーバー URL と API キーが正しいことを確認する。 +2. ダッシュボードの API キーに `events:read` 権限が必要です。 +3. イベントが実際に取り込まれているか確認する:`curl http://your-server:8080/events -H "Authorization: Bearer $ADMIN_KEY"` + +### `/errors` は空だが `/events` に赤い行が表示される + +新しいバージョンの SDK は、専用の `event_type: "error"` 行としてではなく、ペイロードに `outcome: "error"` を持つ `agent_end` / `tool_result` / `hook_completed` イベントとして失敗を送信します。`/errors` ページは現在、両方にマッチします。`/events` ストリームが赤く表示する行(明示的な `event_type='error'`、ペイロードの `outcome`/`status` が失敗セット内、`is_error: true`、または truthy な `error` フィールド)はすべて `/errors` に表示されます。以前、`/events` で赤い行が見えているのに「このウィンドウにエラーなし」と表示されていた場合は、ダッシュボードとサーバーを一緒にアップグレードしてください(拡張フィルターは `GET /events` に対する `errored=true` です)。2つのビューが一致するようになります。 + +### 広い時間範囲で `/models`、`/tools`、`/hooks` の読み込みが遅いまたは失敗する + +**症状:** 大規模なイベントテーブル(数百万行)で、`/models`、`/tools`、`/hooks` を開いたり、時間範囲を `7d`、`30d`、`all` に広げたりすると、チャートがスピンしてからロードエラーが表示されます。サーバーは `latency_aggregate` リクエストに対して ClickHouse の `MEMORY_LIMIT_EXCEEDED`(コード 241)またはクエリタイムアウトをログに記録します。 + +**原因:** 古いビルドでは、これらのページのレイテンシおよびディストリビューション集計を、完全な生イベント `payload` を読み込んでリクエスト/レスポンスイベントをインメモリのソートと結合でペアリングするクエリで計算していました。そのため、ピーク時のクエリメモリはウィンドウのサイズに比例して増加し、ビジーなテナントで広い範囲を指定すると ClickHouse のクエリごとのメモリ上限を超える可能性がありました。 + +**修正:** この修正を含むビルドにアップグレードしてください。集計はコンパクトなプロモートカラムのみを読み込み、ストリーミング集計でイベントをペアリングするようになりました。ピーク時のメモリが生ペイロードに比例して増加しなくなるため、広い範囲でもメモリ上限内に収まり、短時間で返るようになります。この改善は完全にクエリ側のものであり、次回のページロード時に既存のすべてのデータに適用されます。再取り込みやバックフィルは不要です。 + +### ダッシュボードが読み込まれない / 空白ページ + +ダッシュボードコンテナのログを確認してください: + +```bash +docker logs agenteye-dashboard +``` + +最もよくある原因は、`AGENTEYE_SERVER_URL` または `AGENTEYE_API_KEY` が未設定か、到達不能なサーバーを指していることです。 + +### ダッシュボードアナリティクス / テレメトリ + +ダッシュボードはデフォルトで匿名のプロダクト使用状況アナリティクスを PostHog に送信します。ダッシュボード自身の `/ingest` パス(`https://us.i.posthog.com` へのリバースプロキシ)を経由して送信されます。ファーストパーティとして送信することで、ブラウザの広告ブロッカーに遮断されません。これはダッシュボードのコア機能とは独立しています: + +- PostHog に到達するのは **ダッシュボードコンテナ**(ブラウザではなく)です。`https://us.i.posthog.com` へのアウトバウンドアクセスがブロックされている場合、テレメトリは静かにno-opになります。ダッシュボードは正常に動作し、ユーザーへのエラーは表示されません。 +- エージェント、セッション、イベントデータは一切含まれません。ダッシュボードのUI使用状況のみです。 +- テレメトリを完全に無効にするには、ダッシュボードコンテナに `AE_ANALYTICS_DISABLED=1` を設定して再起動してください。デプロイガイドの [テレメトリとプライバシー](/ja/agenteye/deployment#telemetry--privacy) を参照してください。 + +### CLI アナリティクス / テレメトリ + +`agenteye` CLI はデフォルトで匿名の使用状況アナリティクスを PostHog に送信します。実行されたコマンド、成功/終了ステータス、所要時間が対象です。これは CLI の機能とは独立しています: + +- PostHog の `https://us.i.posthog.com` に直接到達するのは **CLI を実行しているマシン**です。アウトバウンドアクセスがブロックされている場合、テレメトリは静かにno-opになります(送信は時間制限があるため、コマンドを遅延させることはありません)。CLI は正常に動作します。 +- エージェント、セッション、イベントデータは一切含まれません。コマンドの**引数やフラグの値**(ダッシュボードURL、トークン、メール、セッションID、クエリフィルター)は送信されません。 +- 無効にするには、CLI の環境に `AGENTEYE_ANALYTICS_DISABLED=1`(またはクロスツール共通の `DO_NOT_TRACK=1`)を設定してください。CLI ガイドの [テレメトリとプライバシー](/ja/agenteye/cli#telemetry--privacy) を参照してください。 + +--- + +## AIアシスタントの問題 + +完全なセットアップは [enterprise-docs/assistant.md](/ja/agenteye/assistant) を参照してください。 + +### アシスタントバブルが表示されない + +バブルは以下の**すべて**が満たされている場合にのみ表示されます: + +- サインインしているユーザーに `agent:use` 権限がある。 +- `AGENTEYE_AGENT_URL` がダッシュボードに設定されており、`agent` サービスに到達できる。 +- `agent` サービスに LLM エンドポイントが設定されている(`ANTHROPIC_API_KEY`、`ANTHROPIC_BASE_URL` 経由のゲートウェイ、または Bedrock/Vertex)。何も設定されていない場合、agent は「not configured」と報告し、バブルは非表示のままになります。 + +ダッシュボードホストから agent のヘルスを確認してください:`curl http://agent:9100/health` は `{"status":"ok","llm_configured":true,...}` を返すはずです。 + +### アシスタントが何かを読めないと言う + +ツールはユーザーごとに制限されています。ユーザーに `evaluations:read`(または `events:read`、`dashboards:read`)がない場合、対応するツールは提供されず、アシスタントはそのデータを読めないと言います。関連する読み取り権限を付与してください。 + +### メッセージ送信時に "assistant not configured"(HTTP 503)が発生する + +`agent` コンテナに LLM エンドポイントが設定されていないか、ダッシュボードの `AGENTEYE_AGENT_TOKEN` が agent のものと一致していません。両方を設定して再起動してください。 + +### `agent` コンテナが負荷の下で再起動する / OOM になる + +各会話はショートリブドの子プロセスを起動します。コンテナが init プロセスで実行されていることを確認してください(イメージは `tini` を使用しています。Compose では `init: true` を設定)。また、十分なメモリ制限を設定してください。必要に応じて `AGENTEYE_AGENT_MAX_STEPS` を下げてください。 + +--- + +## CLI の問題 + +### `agenteye` が `ModuleNotFoundError: No module named 'click'` で起動に失敗する + +バージョン **0.1.6** の `agenteye` CLI の新規インストールが起動時にクラッシュすることがあります: + +``` +ModuleNotFoundError: No module named 'click' +``` + +0.1.6 は `typer` によって `click` が間接的にインストールされることを前提としていましたが、現在の `typer` のリリースではそれが行われなくなり、クリーンな環境でパッケージが不足します。**0.1.7 以降にアップグレード**してください。`click` への直接依存が追加されています: + +```bash +pipx upgrade agenteye # pipx でインストールした場合(または:pipx install --force agenteye) +uv tool upgrade agenteye # uv でインストールした場合 +pip install --upgrade agenteye +``` + +インストールガイダンスは [enterprise-docs/cli.md](/ja/agenteye/cli) を参照してください。 + +--- + +## Python SDK の問題 + +### `$AGENTEYE_HOME/events/` にファイルが表示されない + +SDK はイベントをバッファリングし、デフォルトで500msごとにフラッシュします。フラッシュ前にプロセスが終了すると、イベントが失われる可能性があります。短命なスクリプトでは `agenteye.configure(flush_interval=0.1)` でフラッシュを早くするか、少なくとも1フラッシュサイクル分プロセスを実行し続けてください。 + +`AGENTEYE_HOME` が設定されている場合は、SDK が `~/.agenteye/events/` ではなく `$AGENTEYE_HOME/events/` に書き込んでいることを確認してください(SDK ≥ 0.0.1b5 が必要)。 + +### `ValueError: Reserved field names cannot be used as custom fields` + +`timestamp`、`type`、`environment` という名前は予約済みであり、カスタムフィールドとして使用できません。これらのいずれかを渡すと以下のエラーが発生します: + +``` +ValueError: Reserved field names cannot be used as custom fields: [...] +``` + +問題のあるカスタムフィールド名を変更してください。`session_id` と `agent_id` はカスタムフィールドではなくイベント呼び出しの明示的なパラメーターであることに注意してください。これらをカスタムフィールドとして渡すと `TypeError` が発生します。 + +--- + +## ヘルスモニタリングの問題 + +### Slack(Robusta)にアラートが届かない + +Robusta のヘルスアラートは**オプトイン**です。インストールして Slack チャンネルを指定するまで何も送信されません。リリースとそのシンクを確認してください: + +```bash +kubectl get pods -n robusta # robusta-runner と robusta-forwarder が Running であるべき +kubectl logs -n robusta -l app=robusta-runner --tail=50 +``` + +よくある原因:Slack の `api_key` / `slack_channel` が設定されていない(またはトークンが失効している);`api_key` が Robusta クラウドリレートークン(`robusta integrations slack`)だが、バンドルされた `disableCloudRouting: true` はセルフホストの Slack **bot トークン**(`xoxb-…`)が必要(または `disableCloudRouting: false` を設定する);シンクの `scope` が Pod が稼働しているネームスペースを除外している(バンドルされた values は `agenteye` にスコープされています);まだ障害が発生していない。Pod をダウンさせてテストアラートを強制発行する: + +```bash +kubectl -n agenteye delete pod -l app=clickhouse # 再作成されます +``` + +インストールと設定については [enterprise-docs/health-monitoring.md](/ja/agenteye/health-monitoring#2-pod-failure-alerting-with-robusta-opt-in) を参照してください。 + +### サーバーが `NotReady` を繰り返す + +レディネスプローブが `/ready` にアクセスし、Postgres または ClickHouse が到達不能な場合に失敗します。サーバーが `NotReady` と `Ready` を行き来している場合は、依存関係が断続的に利用不可能になっています。ClickHouse と Postgres の Pod とサーバーの `CLICKHOUSE_URL` / `DATABASE_URL` を確認してください。`/ready` が何を報告しているか確認する: + +```bash +kubectl -n agenteye exec deploy/server -- sh -c 'curl -s localhost:8080/ready' +``` + +このプローブは意図的に寛容(失敗閾値を大きく)に設定されているため、持続的なフラッピングは過剰なプローブではなく実際の依存関係の問題を示しています。Liveness は `/health` のままなので、readiness のフラッピングはPodの**再起動を引き起こしません**。 + +## 証明書モニタリングの問題 + +### CronJob が Slack 通知を送信しない + +`cert-renewal-check` CronJob は、シークレットに保存された Slack webhook URL が必要です。存在を確認してください: + +```bash +kubectl get secret cert-renewal-notify-config -n agenteye +``` + +ない場合は作成してください: + +```bash +kubectl create secret generic cert-renewal-notify-config \ + --namespace agenteye \ + --from-literal=SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL" +``` + +シークレットがない場合でも CronJob は実行され、結果を stdout にログします。以下でログを確認できます: + +```bash +kubectl logs -n agenteye -l job-name --tail=50 +``` + +### 通知を受け取る前にクライアント証明書が期限切れになった + +CronJob は12時間ごとに実行されます。実行されていない場合は、ステータスを確認してください: + +```bash +kubectl get cronjob cert-renewal-check -n agenteye +``` + +手動チェックを実行する: + +```bash +kubectl create job --from=cronjob/cert-renewal-check manual-cert-check -n agenteye +kubectl logs -n agenteye -l job-name=manual-cert-check +``` + +期限切れの証明書を直ちに再発行するには: + +```bash +cd base/certificates/client-certs +./issue-client-cert.sh +``` + +その後、コレクターを実行しているクラスターに再生成された `collector-mtls-secret.yaml` を適用し、再起動してください: + +```bash +kubectl apply -f collector-mtls-secret.yaml -n +``` + +--- + +## バックアップの問題 + +### `agenteye-backup` が "No space left on device" で失敗する + +`agenteye-backup` CronJob は Postgres + ClickHouse を `backup-tmp` という `emptyDir` スクラッチボリューム(デフォルト `30Gi`)にダンプし、`tar` アーカイブを S3 に**ストリーミング**します。圧縮アーカイブはスクラッチに書き戻されないため、スクラッチには*生ダンプ*だけを格納できれば十分です。Pod がエビクトされたり `No space left on device` が発生した場合、**生ダンプ**がスクラッチサイズを超えていることを意味します(ClickHouse の `events` ダンプが支配的で、時間とともに増大します)。失敗したジョブのログを確認してください: + +```bash +kubectl logs -n agenteye -l job-name= +``` + +修正:オーバーレイで CronJob の `backup-tmp` `emptyDir` の `sizeLimit` を生ダンプの合計サイズより大きく設定し、ノードのエフェメラルストレージが実際に保持できることを確認してください(`sizeLimit` はキャップであり、予約ではありません)。ダンプが単一ノードのディスクを超える場合は、`backup-tmp` の `emptyDir` を PVC(EBS/PD)に置き換えるか、ソースでダンプを圧縮してください。 + +> 古いリリースではダンプと同じ `20Gi` スクラッチに `.tar.gz` を書き込んでいたため、`ダンプ + アーカイブ` がそれを超えて Pod がアップロード前にエビクトされていました。これは S3 の問題のように見えますが実際はディスクの問題です。アップロードをストリーミングにすることでこの二重使用がなくなりました。 + +### `agenteye-backup` が `curl` のインストールで失敗する + +このジョブは `postgres:16` イメージで実行され、ClickHouse HTTP ダンプのために起動時に `curl` をインストールします。Debian パッケージミラーへのエグレスがないクラスターでは `apt-get` ステップが失敗します。バックアップ Pod からそのエグレスを許可するか、`curl` を組み込んだミラー/カスタムバックアップイメージを作成してオーバーレイで参照してください。 + +### `agenteye-backup` は実行されるがオブジェクトストレージに何も保存されない + +ベースには実際の `BACKUP_BUCKET`(`ts-prod-agenteye/backups`)と `agenteye-backup` ServiceAccount が含まれています。このジョブはアーカイブを S3 に**ストリーミング**します(`tar cz … | aws s3 cp - s3://…`)。バックアップ Pod がバケットへの書き込みアクセスを持っていない場合、アップロードはエラーになります。スクリプトは `set -euo pipefail` で実行されるため、パイプ内のどこかで失敗すると `upload` ステップでジョブ全体が失敗します(サイレントにno-opにはなりません。Pod の EXIT トラップは `backup FAILED during step: upload` とログします)。これはスクラッチスペースのエビクションを修正した後に到達するステップでもあるため、以前にバックアップがアーカイブステップでエビクトされていた場合は、アップロードが成功するようになったか確認してください。失敗したジョブのログで S3 アクセスエラーを検索してください: + +```bash +kubectl logs -n agenteye -l job-name= | grep -iE 's3|upload|denied' +``` + +修正:オーバーレイで `BACKUP_BUCKET` を所有するバケットに設定し、既存の `agenteye-backup` ServiceAccount に書き込みアクセス(IRSA / Workload Identity / Pod Identity)をアノテートしてください。[enterprise-docs/kubernetes-deployment.md](/ja/agenteye/kubernetes-deployment) の**バックアップ**セクションを参照してください。 + +--- + +## ClickHouse バックエンドの evaluations / sessions / queries + +### アップグレード後に `/queries` ページのサイドバーが空になる + +3つのテーブル(`events`、`evaluations`、`agent_sessions`)が期待されています。アップグレード後に SchemaBrowser サイドバーが空の場合、サーバーが起動時に ClickHouse DDL を適用できなかったことを示します。`failed to apply CH DDL statement` のサーバーログを確認してください: + +```bash +kubectl logs -n agenteye deploy/server | grep -E 'clickhouse|CH DDL' +``` + +最もよくある原因は、マイグレーション実行中に ClickHouse が到達不能だったことです。サーバーは CH に到達できない場合に起動を拒否するため、スタックした Pod は通常、サイレントに壊れたクエリページではなく `CrashLoopBackOff` になりますが、部分的な DDL 適用(1ステートメントは OK、次の5ステートメントは 5xx)によってスキーマが半途端な状態になることがあります。CH が到達可能であることを確認してからサーバー Pod を再起動してください: + +```bash +kubectl rollout restart deploy/server -n agenteye +``` + +### 新しい evaluations が `/sessions` または `/queries` に表示されない + +アップグレード後、新しい evaluations は Postgres ではなく ClickHouse に書き込まれ、`/sessions`(`evaluations:read` が必要)および `/queries` に表示されます。表示されない場合: + +1. エバリュエーターパイプラインが有効(サーバーに `EVALUATOR_ENDPOINT` が設定されている)で、終端の結果を生成しているか確認する。`evaluation_finalized` のログ行を確認してください。 +2. サーバーから CH に到達できるか確認する:`kubectl exec -n agenteye deploy/server -- curl -fsS http://clickhouse:8123/ping` +3. CH テーブルをスポットチェックする:`kubectl exec -n agenteye clickhouse-0 -- clickhouse-client -q 'SELECT count() FROM agenteye.evaluations'` + +### 負荷下でクエリが "Memory limit exceeded" で失敗する、または ClickHouse が `OOMKilled` になる + +**症状:** 重いダッシュボード/クエリ負荷の下で、分析ページ(イベントストリーム、`/sessions`、モデル/レイテンシビュー、SQL エディタ)が失敗またはタイムアウトし始める。サーバーが一時的に `NotReady` になり、ClickHouse Pod の再起動回数が増加する。これはほぼ常に CPU やディスクではなく**メモリ**の問題です。 + +**メモリの問題であることを確認する**(スループットの問題ではないことを確認し、レプリケーションが解決策ではないことを確認する): + +1. OOM キルが発生していないかPodを確認する: + ```bash + kubectl -n agenteye describe pod clickhouse-0 | grep -iE 'Restart Count|Last State|Reason|OOMKilled' + ``` + 再起動回数が増加し、`Reason: OOMKilled` / `Exit Code: 137` が見えれば確定です。 + +2. ClickHouse が何を拒否しているか確認する: + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT name, value FROM system.errors WHERE value>0 ORDER BY value DESC" + ``` + `MEMORY_LIMIT_EXCEEDED` のカウントが多い場合がシグネチャです。メッセージには *"maximum: N GiB"* と記載されています。**この N は Pod のメモリ制限の `0.9 倍`**(`deploy/base/clickhouse/configmap.yaml` の `max_server_memory_usage_to_ram_ratio`)です。重い読み取りが N を超えると拒否されます。 + +3. 問題でないことを確認する。CPU、パート数、ディスクがすべて低ければ、レプリカの追加やシャーディングはコストの無駄です: + ```bash + kubectl -n agenteye top pod clickhouse-0 + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT table, count() parts FROM system.parts WHERE active AND database='agenteye' GROUP BY table" + ``` + +**原因:** ClickHouse Pod のメモリ制限が分析的なワーキングセットに対して小さすぎます。最も重い読み取りは生 JSON `payload` カラムを引き込み、そこで `JSONExtract*` を実行し、`FINAL` を使用します。各操作に数GiBが必要になる場合があります。設定されたキャッシュ(`mark_cache_size` + `uncompressed_cache_size`)が Pod より大きい場合、同じバジェットに課金されてクエリメモリを圧迫します。 + +**修正 — ClickHouse のメモリをスケールアップ:** + +1. オーバーレイで `clickhouse` StatefulSet のコンテナ `resources` をパッチして ClickHouse のメモリ制限を上げます(他のコンポーネントの `resources` に使用するオーバーレイメカニズムと同じ)。使用可能なサーバーバジェットは `0.9 × 制限` なので、`6Gi` 制限で約 5.4 GiB、`16Gi` で約 14 GiB になります。スケジューラーが予約するように `requests.memory` も実際のフロアに設定してください。これを適用すると **CH Pod が再作成されます**(単一レプリカ → 約 30〜60 秒の分析ダウンタイム)。トラフィックが少ない時間帯に実施してください。 +2. `deploy/base/clickhouse/configmap.yaml` のキャッシュを制限に比例して設定してください。小さいPodでは数百MiBの小さいキャッシュが安全です。メモリ制限の増加に合わせてのみ上げてください。クエリごとの `max_memory_usage` は `users.xml` プロファイル(後述の固定ノードセクション参照)で明示的に設定され、サーバーレベルの上限(`0.9 × 制限`)を下回るよう保たれているため、1つのクエリがコンテナが持つ以上の RAM を*使用することはできません*。 +3. ノード自体が上限の場合、ClickHouse が見えるホストメモリを確認してください: + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT formatReadableSize(value) FROM system.asynchronous_metrics WHERE metric='OSMemoryTotal'" + ``` + これが Pod の制限をわずかに上回るだけであれば、ClickHouse を(オーバーレイのノードセレクター/アフィニティ経由で)より大きい(メモリ最適化)ノードに移動してから制限を上げてください。 + +**メモリを追加できない場合:クエリを RAM に収めて高速に失敗させてください。低速ディスクへのスピルは避けてください。** ノードが固定で Pod を拡張できない場合は、1つのクエリが使用できる量を制限し(ノード全体を占有できないように)、**低速(非SSD)データディスク**では大きな集計/ソートのディスクへのスピルを**許可しないでください**。低速ディスクへのスピルはサーバーのクライアント読み取りタイムアウトより遅いため、スピル中のクエリはダッシュボードに `500` を返しながら ClickHouse が処理し続けます。クエリを RAM に収め、バジェット超過の場合は高速に拒否する(`MEMORY_LIMIT_EXCEEDED`、サブ秒)ことでロードが回復します。これらを適用する際の ClickHouse の注意点: + +- **これらは*プロファイル*設定であり、ClickHouse は `` を `users_config`(`users.xml` / `users.d/*.xml`)からのみ読み取ります。`config.d` からは読み取りません。** `config.d/agenteye.xml` に `` ブロックを配置しても**サイレントに無視されます**(`max_execution_time`、`max_memory_usage` などが単純に適用されません)。そのため、バンドルされた設定はこれらを `clickhouse-config` ConfigMap の `users.xml` キーとして出荷し、`/etc/clickhouse-server/users.d/agenteye.xml` にマウントされます。 +- デフォルト値:`max_memory_usage`(クエリごとの上限 — 1つのクエリがサーバーバジェット全体を消費できない)、`max_bytes_before_external_group_by` / `max_bytes_before_external_sort` = **`0`(スピル無効)** でクエリが低速ディスクをクロールする代わりに RAM に収まるようにし、`max_execution_time`(暴走ガード、サーバーのクライアント読み取りタイムアウトに合わせる)。 +- **有効であることを確認する**(これは `config.d` の問題を検出する方法でもあります): + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT name, value FROM system.settings + WHERE name IN ('max_memory_usage','max_bytes_before_external_group_by','max_execution_time')" + ``` + ゼロでない `max_memory_usage` と `max_bytes_before_external_group_by = 0` が期待される結果です。`max_memory_usage` が `0`/デフォルトの場合、プロファイルが適用されていません。設定が `config.d` ではなく `users.d` マウントに存在することを確認してください。 + +トレードオフ:スピルが無効の場合、ワーキングセットが `max_memory_usage` を超えるクエリは、ゆっくり完了する代わりに**拒否されます**(`MEMORY_LIMIT_EXCEEDED`)。低速ディスクでは、スピル中のクエリはクライアントタイムアウトを超えて結局失敗するため、この高速な拒否が望ましいです。データディスクが**高速(SSD)**の場合は、`max_bytes_before_external_*` の閾値を上げて大きなクエリがディスクにスピルして完了できるようにすることも検討できます。 + +--- + +## マルチテナント(組織) + +### 組織を有効にするアップグレード中のエラー(古い/新しいサーバー Pod が混在) + +**症状:** 組織対応リリースのローリングデプロイ中、一部のリクエストが失敗する。サーバーログに `api_keys` パスでの `there is no unique or exclusion constraint matching the ON CONFLICT specification` が表示され、ロールアウト中にアラート/Slack/Webhook チャンネルの発火が停止する。 + +**原因:** このアップグレードは `api_keys(name)` の古いインスタンス全体のユニークインデックスをPer-org部分インデックスに置き換え、アラートチャンネル設定(および `default_user_permissions`)をグローバルな `settings` テーブルからPer-orgの `org_settings` に移動します。**古い**サーバー Pod はまだ `ON CONFLICT (name)` を発行し(一致する制約がなくなった)、古い `settings` 行(現在は空)からチャンネル設定を読み取ります。古いPodと新しいPodはこの2つのパスで安全に共存できません。 + +**修正:** この特定のアップグレードをバージョン混在でゆっくりロールアウトしないでください。クリーンに切り替えてください。古いサーバーをゼロにスケールダウン(または短いメンテナンスウィンドウを設ける)し、新バージョンをマイグレーションと一緒に起動してください。古いレプリカと新しいレプリカを並行して実行しないでください。通常のトラフィックとインジェストはカットオーバー直後に再開します。これはバージョン移行ウィンドウのみに影響します。 + +### 組織のプロビジョニングが `CREATE USER` / `CREATE ROW POLICY` で失敗する、または1つの組織が別の組織のデータを読める + +**症状:** 組織の作成時に `CREATE USER`、`CREATE ROW POLICY`、または「access management is disabled」というエラーが返される。または、あるいはより深刻なことに、ある組織のメンバーが SQL エディタやアシスタントで別の \ No newline at end of file diff --git a/docs/ko/agenteye/alerts.mdx b/docs/ko/agenteye/alerts.mdx new file mode 100644 index 00000000..064b68c9 --- /dev/null +++ b/docs/ko/agenteye/alerts.mdx @@ -0,0 +1,308 @@ +--- +title: "Alerts" +description: "AgentEye Alerts 문서." +--- + +Alerts는 스케줄에 따라 규칙을 평가하고, 특정 값이 임계값을 초과하면 알림을 보냅니다. AgentEye를 단순한 수동형 대시보드에서 벗어나, 오류율 급등, 지연 시간 저하, 평가자 점수 하락, 또는 ClickHouse 쿼리로 표현할 수 있는 모든 커스텀 이벤트를 즉시 감지하는 알림 서비스로 전환합니다. + +이 가이드에서는 Alert의 개념, 다섯 가지 트리거 유형, 네 가지 알림 채널, 인시던트 생명주기, 그리고 운영 설정 옵션을 다룹니다. + +![Alerts 페이지: 트리거 유형, 평가 윈도우, 채널, info/warning/critical 심각도 배지를 각각 표시하는 alert 규칙 카드 그리드](/agenteye/images/alerts.png) + +--- + +## 개념 + +- **Alert** — 규칙입니다. *무엇을* 확인할지(트리거), *얼마나 자주*(평가 주기), *언제 문제로 볼지*(복합 로직), *얼마나 긴급한지*(심각도), *누구에게/어디로 알릴지*(채널)를 정의합니다. +- **Incident** — Alert가 발동될 때 생성됩니다. 하나의 Alert에는 동시에 열린 인시던트가 최대 하나만 존재합니다. 반복적인 위반은 동일 인시던트의 근거 데이터를 업데이트합니다. 인시던트는 운영자가 직접 해결해야 하며, 규칙이 발동을 멈출 때 자동 해결하는 기능은 계획 중이나 현재는 미지원입니다. +- **Channel** — 알림이 전달되는 대상: 이메일, Slack, 일반 웹훅, 또는 대시보드 내. 각 Alert에 원하는 조합을 붙일 수 있습니다. + +Alert와 인시던트는 조직 단위에 속하며, 해당 조직의 모든 운영자가 공유합니다(단일 테넌트 배포에서는 기본 제공 `default` 조직이 이에 해당합니다). 인시던트는 트리아지를 위해 특정 운영자에게 배정할 수 있습니다. + +--- + +## 트리거 유형 + +각각 고유한 JSON 스펙을 가진 다섯 가지 종류가 있습니다. "문제 있음"을 어떻게 표현하고 싶은지에 맞는 유형을 선택하세요. 대시보드의 **새 Alert** 폼은 동일한 스펙을 자동으로 구성하며, 선택한 트리거 유형에 맞게 조건 편집기를 전환합니다. + +![새 Alert 폼: 기본 정보(이름, 설명, 활성화) 및 metric threshold, custom SQL, evaluation score, eval failures, per-event 옵션을 보여주는 트리거 선택기](/agenteye/images/alert-new.png) + +### 1. `metric_threshold` + +가장 단순한 유형입니다. 제공된 목록에서 메트릭, 연산자, 임계값, 시간 윈도우를 선택합니다. + +| 메트릭 | 측정 대상 | +|---|---| +| `event_count` | 윈도우 내 전체 이벤트 수 | +| `error_count` | `event_type = 'error'` 이거나 `error_type IS NOT NULL`인 이벤트 | +| `error_rate` | `error_count / event_count` (0..1) | +| `p95_latency_ms` | `duration_ms`가 있는 모든 이벤트의 `quantile(0.95)(duration_ms)` | +| `p99_latency_ms` | `quantile(0.99)(duration_ms)` | +| `token_sum` | `SUM(input_tokens + output_tokens)` | + +연산자: `>`, `>=`, `<`, `<=`, `==` (`gt`, `gte`, `lt`, `lte`, `eq`도 사용 가능). + +선택적 필터: `environment`, `event_type`. + +스펙 예시: + +```json +{ + "metric": "p95_latency_ms", + "filter": { "environment": "production" }, + "window_secs": 900, + "op": ">", + "value": 5000 +} +``` + +### 2. `custom_sql` + +프리셋 메트릭으로 표현할 수 없는 모든 경우에 사용합니다. 운영자가 작성한 SQL은 디스패처가 실행하기 전에 동일한 `/queries/run` 가드(SELECT/WITH만 허용, 단일 문, 10,000행 제한)를 통과합니다. 두 가지 모드가 있습니다: + +- **rows 모드** (`op`/`value` 없음): 쿼리가 하나 이상의 행을 반환하는 즉시 Alert가 발동됩니다. +- **value 모드**: 쿼리에서 컬럼 하나를 `metric_value`로 별칭 지정해야 하며, 디스패처는 첫 번째 행의 `metric_value`를 `op`를 사용해 `value`와 비교합니다. + +```json +{ + "sql": "SELECT count() AS metric_value FROM agenteye.events WHERE event_type = 'error' AND ts >= now() - INTERVAL 1 HOUR", + "op": ">", + "value": 100 +} +``` + +### 3. `evaluation_score` + +`agenteye.evaluations`를 읽어 특정 점수의 윈도우 내 평균값을 비교합니다. + +```json +{ + "score_key": "hallucination", + "op": ">", + "value": 0.6, + "window_secs": 3600, + "min_count": 5, + "environment": "production" +} +``` + +`min_count`는 단일 샘플 이상치를 방지합니다. 윈도우 내 평가 횟수가 N개 이상이 될 때까지 디스패처는 발동하지 않습니다. + +### 4. `eval_compound` + +*여러* 평가자 점수에 걸쳐서만 나타나는 품질 저하를 감지합니다. `evaluation_score`가 단일 점수를 감시하는 반면, `eval_compound`는 여러 evaluation-score 조건을 하나의 Alert로 묶고 선택한 로직으로 결과를 결합합니다. 따라서 "helpfulness가 떨어지거나 **또는** hallucination이 올라가면 발동", "helpfulness와 tool-efficiency 모두 떨어질 때만 발동", "이 세 가지 검사 중 **최소 2개** 이상 위반 시 발동" 같은 규칙을 하나로 표현할 수 있습니다. + +각 조건은 공유 윈도우에서 `agenteye.evaluations`의 특정 점수 평균을 읽어 고유한 연산자와 임계값으로 테스트합니다. 불리언 결과는 `combinator`에 의해 결합됩니다: + +| Combinator | 논리 | 발동 조건 | +|---|---|---| +| `"any"` | OR | 최소 하나의 조건이 위반될 때 | +| `"all"` | AND | 모든 조건이 위반될 때 | +| `{ "at_least": N }` | M of N | 최소 N개의 조건이 위반될 때 | + +```json +{ + "combinator": { "at_least": 2 }, + "conditions": [ + { "score_key": "hallucination", "op": ">", "value": 0.8 }, + { "score_key": "helpfulness", "op": "<", "value": 0.6 }, + { "score_key": "tone", "op": "<", "value": 0.5 } + ], + "window_secs": 3600, + "min_count": 5, + "environment": "production" +} +``` + +- `combinator`: `"any"`, `"all"`, 또는 `{ "at_least": N }`. +- `conditions[]`: 각각 `{ score_key, op, value }` 형태이며, 다른 트리거와 동일한 연산자(`>`, `>=`, `<`, `<=`, `==`)를 사용합니다. +- `window_secs`: 모든 조건에 공통으로 적용되는 기간(기본값 `3600`). +- `min_count`: 조건이 위반으로 판정되기 전 필요한 최소 평가 횟수. 윈도우 내 샘플이 부족한 조건은 "위반 없음"으로 처리됩니다(기본값 `1`). +- `environment`: 선택 사항. 모든 조건을 특정 환경으로 제한합니다. + +알림의 근거 데이터에는 각 조건의 관측 평균, 비교 임계값, 평가 횟수, 위반 여부가 기록되므로 어떤 검사가 발동했는지 정확히 확인할 수 있습니다. + +### 5. `per_event` + +"X와 일치하는 이벤트가 발생했을 때" 알림에 사용합니다. 집계 없이, 디스패처는 조회 윈도우에서 일치하는 항목을 발견하는 즉시 발동합니다. + +```json +{ + "event_type": "error", + "lookback_secs": 60, + "environment": "production", + "tool_name": "bash", + "agent_id": "caa", + "error_type": "TimeoutError", + "message_contains": "vertex-ai timed out" +} +``` + +모든 필터는 AND로 결합되며, 생략한 필드는 제한 없이 허용됩니다. + +| 필드 | 용도 | +|---|---| +| `agent_id` | 특정 에이전트(`/errors` 행에 표시된 에이전트)의 오류만 감지합니다. | +| `error_type` | 모든 오류가 아닌 특정 오류 클래스(예: `TimeoutError`)만 감지합니다. | +| `message_contains` | `payload.message`에 대한 대소문자 구분 없는 부분 문자열 검색입니다. 동일 에이전트의 모든 오류에 Alert를 보내지 않고 특정 실패 유형(예: `prompt is too long`)만 감지할 때 유용합니다. 최대 200자이며, 패턴이 아닌 리터럴 문자열로 매칭됩니다. | + +팁: `lookback_secs`를 Alert의 `eval_interval_secs`와 대략 일치하도록 설정하면 동일 이벤트에 대한 중복 알림을 방지할 수 있습니다. + +**`/errors`에서 바로 생성:** 오류 보기의 각 오류 그룹 대표 행(및 오류 이벤트의 세션 이벤트 상세 패널)에는 **+ alert** 버튼이 있으며, 해당 행의 `event_type` + 환경 정보로 미리 채워진 `per_event` 트리거와 함께 `/alerts/new`를 엽니다. 페이로드의 `error_type`이 있을 경우 이름도 자동으로 채워집니다. 채널 선택과 조회 기간 확인은 여전히 필요하지만, 매처는 자동으로 입력됩니다. 버튼이 표시되려면 운영자에게 `alerts:write` 권한이 필요합니다. + +--- + +## 복합 로직 (M of N) + +모든 Alert에는 트리거 외에 두 개의 정수 설정이 있습니다: + +- `eval_window`: 살펴볼 최근 평가 횟수 (기본값 1) +- `min_breaches`: 그 중 Alert가 발동되기 위해 위반되어야 하는 횟수 (기본값 1) + +`1 of 1`(기본값)은 "첫 번째 위반 시 발동"입니다. `3 of 5`는 "최근 5번의 평가 중 3번 위반 시 발동"으로, 단일 불량 측정값이 노이즈인 불안정한 신호에 유용합니다. 디스패처가 Alert별로 링 버퍼를 관리하므로 상태를 직접 관리할 필요가 없습니다. + +--- + +## 평가 주기 + +`eval_interval_secs`는 디스패처가 규칙을 실행하는 빈도를 제어합니다. `[30, 86400]` 범위로 제한됩니다. 대시보드 프리셋: 1분 / 5분 / 15분 / 1시간. 기반 신호가 변화하는 속도에 맞는 주기를 선택하세요. 5분 오류율 Alert를 15초마다 평가하면 CPU 낭비이고, per-event Alert는 틱 사이 이벤트를 조용히 놓치지 않으려면 짧은 조회 기간이 필요합니다. + +--- + +## 채널 + +각 Alert에 아래 네 가지의 조합을 붙일 수 있습니다. 채널별 자격 증명(Slack 웹훅 URL, 일반 웹훅 URL + 서명 시크릿, 기본 이메일 수신자)은 **`/settings`** 에서 한 번만 설정하고 각 Alert에서 키로 참조합니다. 이렇게 하면 하나의 Slack 채널이 각자 웹훅 URL 사본을 저장하지 않아도 여러 Alert에 사용될 수 있습니다. + +세 가지 외부 채널(이메일, Slack, 웹훅)은 조직 전체 킬 스위치인 `alerts.enabled_channels`의 적용을 받습니다. 발동된 Alert에 이 설정에 없는 채널 종류가 연결된 경우, 디스패처는 해당 채널을 건너뛰고 `alert_notifications` 행에 `skipped_disabled` 상태와 `` 대상을 기록합니다(예: 모든 규칙을 편집하지 않고도 Slack 전송을 전역으로 일시 중지 가능). 대시보드 내 채널은 항상 허용됩니다. [구성](#configuration)을 참조하세요. + +### 이메일 + +OTP 로그인 이메일을 전송하는 동일한 SMTP 트랜스포트를 재사용합니다. 수신자 결정 순서: + +1. 채널별 `recipients[]` 재정의(비어 있지 않은 경우). +2. `alerts.email_default_recipients` 설정(이메일 문자열 배열). + +SMTP가 설정되지 않은 경우 채널은 아무 동작도 하지 않으며, 디스패처는 `` 대상과 함께 `alert_notifications` 행을 기록하여 감사 추적에서 설정 오류를 확인할 수 있게 합니다. + +### Slack + +[수신 웹훅 URL](https://api.slack.com/messaging/webhooks)로 Block Kit 메시지를 전송합니다. + +- 기본 URL: `alerts.slack_default_webhook` (`/settings`에서 설정). +- Alert별 재정의: 채널의 `webhook_setting_key`를 다른 URL 유형 설정 키(예: `alerts.slack_oncall`, `alerts.slack_costs`)로 지정합니다. + +헤더에는 심각도 이모지(`:rotating_light:` / `:warning:` / `:bell:`)가 포함되며, 메시지에는 인시던트 페이지로 바로 연결되는 버튼이 있습니다. + +### 일반 웹훅 + +PagerDuty, Opsgenie, 또는 자체 수집 엔드포인트를 위한 JSON POST 연동입니다. 본문 형식: + +```json +{ + "schema_version": 1, + "event": "alert.firing", + "incident": { "id": "uuid", "url": "https://…/incidents/uuid", "opened_at": "2026-…" }, + "alert": { "id": "uuid", "name": "errors > 50/hr", "severity": "critical" }, + "breach": { "value": 73.0, "summary": "ErrorCount > 50 (observed 73.000)", "evidence": { … } } +} +``` + +`alerts.webhook_signing_secret`이 설정된 경우, 요청에 `X-AgentEye-Signature: sha256=` 헤더가 포함됩니다. 이는 시크릿을 사용한 본문의 HMAC-SHA256 값입니다. 수신 측에서 페이로드를 신뢰하기 전에 검증하세요. + +`X-AgentEye-Event` 헤더에는 `alert.firing` / `alert.test`가 전달됩니다. (`alert.resolved`는 예정된 자동 해결 기능을 위해 예약되어 있으며 현재는 전송되지 않습니다.) + +### 대시보드 내 + +외부 전달 없음: Alert가 `alert_notifications` 행만 기록하며, 대시보드의 인시던트 페이지에서 확인할 수 있습니다. 규칙을 조정하는 동안 외부 시스템에 스팸을 보내고 싶지 않거나, 운영자가 일반 트리아지 중에 확인하는 낮은 긴급도 Alert에 유용합니다. + +--- + +## 인시던트 생명주기 + +``` +firing ──ack──▶ acknowledged + │ │ + └────────────────────┴───── 운영자 해결 ───▶ resolved +``` + +- **firing** — 디스패처가 방금 인시던트를 열었거나 또 다른 위반을 감지했습니다. 발동 알림은 정확히 한 번만 전송됩니다(인시던트의 `notified_firing_at` 타임스탬프로 게이팅). +- **acknowledged** — 운영자가 `/incidents/:id`에서 *ack*를 눌렀습니다. 인시던트는 여전히 열린 상태로 간주되며, 이후 위반은 재알림 없이 근거 데이터를 업데이트합니다. +- **resolved** — 운영자가 *resolve*를 눌렀습니다. 규칙 위반이 멈출 때 자동 해결하는 기능은 계획 중이나 현재는 미지원이므로, 열린 인시던트는 운영자가 해결할 때까지 유지됩니다. + +이전 인시던트가 해결된 이후 언제든지 동일 Alert에서 새 인시던트가 다시 열릴 수 있습니다. + +**활동 타임라인.** 인시던트에 대한 모든 작업(열림, 확인, 해결)은 추가 전용 활동 로그에 기록되며, 인시던트의 *활동* 타임라인에 표시됩니다. 각 항목은 작업을 수행한 운영자(이메일로 표시) 또는 디스패처가 자체적으로 수행한 작업(위반 시 자동 열림)의 경우 **automated**로 귀속됩니다. 확인은 공유됩니다. 여러 운영자가 동일 인시던트를 ack할 수 있으며 각각 별도의 귀속 항목으로 나타납니다. + +**Incidents** 인박스는 열린 인시던트를 상태별로 그룹화하고 심각도 및 담당자별로 필터링할 수 있습니다: + +![심각도 배지와 담당자가 있는 Alert 연결 및 임시 인시던트 카드를 보여주는 Incidents 인박스](/agenteye/images/incidents.png) + +인시던트를 열면 위반 근거, 담당자 및 구독자, 귀속 활동 타임라인, 댓글 스레드가 표시됩니다: + +![상위 Alert, 위반 요약, 담당자, 구독자, 귀속 활동 로그, 대화를 보여주는 인시던트 상세 보기](/agenteye/images/incident-detail.png) + +--- + +## 필요 권한 + +Alert *규칙* 작성과 *인시던트* 트리아지는 별개의 관심사로 각각 별도의 권한을 가지므로, 규칙 재작성 권한 없이도 온콜 로테이션에 인시던트 접근 권한을 부여할 수 있습니다. + +- `alerts:read`: Alert 규칙 보기. +- `alerts:write`: Alert 규칙 생성, 편집, 삭제 및 테스트 알림 트리거. +- `incidents:read`: 인시던트 보기. +- `incidents:write`: Alert와 연결되지 않은 수동(임시) 인시던트 열기. +- `incidents:ack`: 인시던트 확인, 배정, 댓글 작성, 해결. + +> **레거시 `alerts:ack`.** 이전 `alerts:ack` 토큰을 부여받은 키와 운영자는 계속 사용 가능합니다. `incidents:ack`로 인정되며(`incidents:read` 포함), 기존 온콜 담당자는 자격 증명을 재발급하지 않아도 접근 권한을 유지합니다. 새 권한은 `incidents:*` 계열로 발급하세요. + +API 키(`POST /keys`) 및 운영자(`PUT /users/:id`)에 권한을 부여합니다. 대시보드의 `PermGate`는 권한이 없을 때 관련 버튼을 잠그며, 작업 옆에 `// 403`이 표시됩니다. + +> **이메일 수신자 선택기.** Alert 편집기의 수신자 선택기는 이름으로 선택할 수 있도록 조직 구성원 목록을 표시합니다. `alerts:read` 또는 `alerts:write` 권한을 가진 운영자라면 로드되며, 이 목적으로 팀 디렉터리를 보는 데는 `users:read`가 **필요하지 않습니다**. 선택기는 구성원 이메일 주소만 반환하며, 전체 사용자 레코드는 반환하지 않습니다. + +--- + +## 구성 + +디스패처가 사용하는 환경 변수: + +| 변수 | 기본값 | 용도 | +|---|---|---| +| `ALERT_WORKERS` | `1` | 서버 인스턴스당 워커 태스크 수. 대부분의 배포에서 하나면 충분합니다. | +| `ALERT_CLAIM_BATCH` | `16` | 단일 워커 틱이 처리하는 최대 Alert 수. | +| `ALERT_POLL_IDLE_SECS` | `5` | 큐가 비어 있을 때 워커 대기 시간(초). | +| `ALERT_REQUEST_TIMEOUT_MS` | `15000` | 트리거별 평가 제한 시간(ms). | +| `DASHBOARD_URL` | `https://app.befailproof.ai` | 알림의 인시던트 매직 링크 생성에 사용되는 출처. 대시보드 호스트로 설정하세요. | + +일시적인 평가 실패(ClickHouse 연결 불가, 쿼리 타임아웃) 후 디스패처는 지수 백오프로 규칙을 재시도합니다. 규칙에서 일시적 실패가 **5번** 연속 누적되면 계속 백오프하는 대신 정상 주기로 재스케줄링되므로, 지속적으로 실패하는 규칙도 계속 재평가됩니다. 이 상한값은 고정이며 운영자가 변경할 수 없습니다. + +채널 설정(`/settings`에서 관리, 환경 변수 아님): + +- `alerts.email_default_recipients` (`email_list`): 이메일 채널의 기본 수신자를 담은 이메일 문자열 JSON 배열. +- `alerts.slack_default_webhook` (`url`): 기본 Slack 수신 웹훅 URL. +- `alerts.webhook_default_url` (`url`): 기본 일반 웹훅 URL. +- `alerts.webhook_signing_secret` (`secret`): HMAC-SHA256 키. GET 응답에서는 항상 `""`로 반환되며, 새 값을 입력하면 교체됩니다. +- `alerts.enabled_channels` (`channel_set`): Alert 발동 시 디스패치되는 외부 채널 종류의 조직 전체 설정. 기본값은 세 가지 모두(`email`, `slack`, `webhook`). 여기서 채널 종류를 제거하면 각 규칙을 편집하지 않아도 모든 Alert에서 해당 채널이 전역으로 억제됩니다. 대시보드 내 채널은 항상 전달되며 이 설정의 영향을 받지 않습니다. + +--- + +## 새 Alert 검증 + +새 Alert를 신뢰하기 전에: + +1. 최소 하나의 알림 채널을 붙여 활성화된 상태로 저장합니다. +2. Alert 상세 페이지에서 **test**를 선택하고 설정된 각 대상이 테스트 알림을 수신하는지 확인합니다. +3. 실제 첫 번째 위반 후, **Incidents** 아래에 인시던트가 나타나고 측정값이 해당 대시보드 쿼리와 일치하는지 확인합니다. + +조건이 해소되어도 인시던트는 자동으로 해결되지 않습니다. 운영자가 인시던트 상세 페이지에서 직접 해결해야 합니다. + +--- + +## 문제 해결 + +| 증상 | 가능한 원인 | +|---|---| +| Alert가 전혀 발동하지 않음 | `enabled = false`이거나, 채널이 연결되지 않았거나, 기반 CH 쿼리가 0개의 행을 반환합니다. *test*로 채널을 확인하고, `/queries/run`으로 메트릭을 확인하세요. | +| Slack 알림 없음 | `alerts.slack_default_webhook`(또는 Alert별 재정의 키)이 설정되지 않았습니다: `alert_notifications.target`에서 `` 행을 확인하세요. 또는 `slack` 종류가 `alerts.enabled_channels`에서 전역으로 비활성화되었습니다: `alert_notifications` 행에서 `skipped_disabled` 상태와 `` 대상을 확인하세요. | +| 일반 웹훅 401 | 수신자가 서명을 요구하는데 `alerts.webhook_signing_secret`이 설정되지 않았습니다. 수신 측에서 HMAC이 `hmac_sha256(secret, body)`와 일치하는지 확인하세요. | +| 이메일 전송 실패 | SMTP 자격 증명이 잘못되었거나 `from` 주소가 릴레이에서 거부되었습니다. OTP 이메일을 전송하는 동일한 서비스입니다: OTP 이메일이 정상이라면 SMTP 트랜스포트는 문제없는 것입니다. | +| 인시던트가 반복적으로 재열림 | 복합 설정이 너무 공격적입니다: 일시적인 급등으로 해결한 인시던트가 다시 열리지 않도록 `min_breaches` 또는 `eval_window`를 높여보세요. | \ No newline at end of file diff --git a/docs/ko/agenteye/api-keys.mdx b/docs/ko/agenteye/api-keys.mdx new file mode 100644 index 00000000..53e51230 --- /dev/null +++ b/docs/ko/agenteye/api-keys.mdx @@ -0,0 +1,255 @@ +--- +title: "API 키" +description: "AgentEye API 키 문서." +--- + + +AgentEye는 서버 접근을 제어하기 위해 세분화된 API 키를 사용합니다. 각 키는 하나 이상의 권한을 보유하며, 이 권한이 해당 키가 수행할 수 있는 작업을 결정합니다. + +--- + +## 권한 + +서버는 고정된 권한 목록을 강제하며, 각 권한은 특정 HTTP 라우트에 대한 접근을 제어합니다. **admin 키**는 모든 권한을 보유하고, 범위가 지정된(scoped) 키는 생성 시 부여한 권한의 하위 집합을 보유합니다. 키를 생성할 때 알 수 없는 권한 문자열이 포함되면 거부됩니다. + +> **키에 할당할 수 없음.** 두 가지 유효한 권한은 사람/대시보드 전용이며 API 키에 부여할 수 없습니다: `orgs:admin`(인스턴스 관리, 운영자 전용)과 `keys:update`. `POST /keys` 또는 `PATCH /keys/:id` 요청에서 이 둘 중 하나를 부여하려 하면 HTTP 422로 거부됩니다. Bearer 키가 키를 생성할 수는 있지만 편집할 수 없는 이유는 아래 `keys:update` 항목을 참고하세요. + +### 이벤트 수집 및 조회 + +| 권한 | HTTP 라우트 | 허용 작업 | +|---|---|---| +| `events:add` | `POST /events` | 수집기에서 이벤트 배치를 수집합니다. 수집기에 필요한 유일한 권한입니다. | +| `events:read` | `GET /events`, `GET /events/latency_aggregate`, `GET /events/environments`, `GET /events/models`, `GET /sessions/:session_id/export` | 이벤트 조회, 알려진 환경 목록, 데이터에서 확인된 모델 식별자 목록(Models 뷰 및 모델 필터에서 사용), 히트맵/백분위 밴드를 구동하는 지연 집계 계산, 그리고 세션을 JSONL로 내보내기를 허용합니다. 공유 필터바 패싯 엔드포인트인 `GET /events/environments`와 `GET /events/models`는 `events:read` **또는** `evaluations:read` 중 하나로 접근할 수 있으므로, (`evaluations:read`로 제한된) 세션 페이지가 동일한 org별 패싯을 재사용할 수 있습니다. | + +### 세션 및 평가 + +| 권한 | HTTP 라우트 | 허용 작업 | +|---|---|---| +| `evaluations:read` | `GET /sessions`, `GET /evaluations`, `GET /evaluations/aggregate`, `GET /evaluations/environments`, `GET /evaluation-jobs` | 세션 목록, 평가 결과, 대시보드에서 사용하는 롤업된 평가 상태, 평가 작업 워커 큐 상태를 읽습니다. | +| `evaluations:trigger` | `POST /sessions/:session_id/re-evaluate` | 완료된 세션에 대해 재평가를 수동으로 큐에 넣습니다. | + +### 대시보드 + +| 권한 | HTTP 라우트 | 허용 작업 | +|---|---|---| +| `dashboards:read` | `GET /dashboards`, `GET /dashboards/:id`, `GET /dashboards/:id/tiles` | 대시보드 목록, 개별 대시보드 로드, 타일 읽기를 허용합니다. | +| `dashboards:write` | `POST /dashboards`, `PUT /dashboards/:id`, `POST /dashboards/:id/tiles`, `PUT /dashboards/:id/tiles/:tile_id`, `DELETE /dashboards/:id/tiles/:tile_id`, `PUT /dashboards/:id/tiles/layout` | 대시보드 생성 및 편집, 타일 추가/편집/삭제, 타일 그리드 순서 변경을 허용합니다. | +| `dashboards:delete` | `DELETE /dashboards/:id` | 전체 대시보드를 삭제합니다(타일 수준 삭제는 `dashboards:write`에 속합니다). | + +### 저장된 쿼리 (SQL 작성기) + +| 권한 | HTTP 라우트 | 허용 작업 | +|---|---|---| +| `queries:read` | `GET /queries`, `GET /queries/:id`, `GET /queries/schema` | 저장된 쿼리 목록, 개별 쿼리 로드, 작성기가 대상으로 하는 읽기 전용 ClickHouse 스키마 검사를 허용합니다. | +| `queries:write` | `POST /queries`, `PUT /queries/:id` | 저장된 쿼리를 생성하고 편집합니다. SQL은 `queries:run` 호출과 동일한 읽기 전용 역할 및 `sql_guard` 검사를 통해 라우팅됩니다. | +| `queries:delete` | `DELETE /queries/:id` | 저장된 쿼리를 삭제합니다. | +| `queries:run` | `POST /queries/run` | 작성기에서 사용하는 읽기 전용 역할로 저장된 쿼리 또는 임시 SQL을 실행합니다. | + +### AI 어시스턴트 + +| 권한 | HTTP 라우트 | 허용 작업 | +|---|---|---| +| `agent:use` | `GET /agent/conversations`, `POST /agent/conversations`, `GET /agent/conversations/:id`, `PATCH /agent/conversations/:id`, `DELETE /agent/conversations/:id`, `PUT /agent/conversations/:id/messages` | 대시보드 AI 어시스턴트와 대화하고 자신의 (비공개) 대화를 관리합니다. 어시스턴트 독을 보려면 **사용자**에게 필요하며, 어시스턴트 자체 키는 `dashboard-assistant`로 별도로 시딩됩니다(아래 참조). | + +### API 키 + +| 권한 | HTTP 라우트 | 허용 작업 | +|---|---|---| +| `keys:create` | `POST /keys` | 새로운 범위 지정 API 키를 생성합니다. 기존 키의 권한 편집은 **허용하지 않습니다**(그것은 `keys:update`입니다). | +| `keys:read` | `GET /keys` | 기존 키 목록을 조회합니다. 시크릿은 이 엔드포인트에서 반환되지 않습니다. | +| `keys:update` | `PATCH /keys/:id` | 기존 키의 권한을 편집합니다. **사람/대시보드 전용** 권한으로, API 키에 할당할 수 없습니다(Bearer 키는 키를 생성할 수 있지만 편집할 수 없습니다). | +| `keys:disable` | `POST /keys/:id/disable` | 키를 폐지합니다. 보호된 키(`admin`, `dashboard-assistant`)는 비활성화할 수 없으며, 환경 변수 변경 후 재시작을 통해 교체하세요. | +| `keys:regenerate` | `POST /keys/:id/regenerate` | 키의 시크릿을 교체합니다. 보호된 키는 이 라우트를 통해 재생성할 수 없습니다. | + +### 대시보드 사용자 + +| 권한 | HTTP 라우트 | 허용 작업 | +|---|---|---| +| `users:create` | `POST /users`, `GET /users/defaults` | 새 대시보드 사용자를 초대(이메일 + OTP 로그인 발송)하고, 초대 양식 초기값으로 사용하는 대시보드 설정 기본 권한 집합을 읽습니다. | +| `users:read` | `GET /users`, `GET /users/:id` | 사용자 목록과 개별 사용자 레코드를 조회합니다. | +| `users:update` | `PUT /users/:id` | 사용자의 권한을 편집합니다. 업데이트 시 영향받는 사용자에게 권한 변경 이메일이 발송되며, 다음 요청부터 즉시 적용됩니다. 재로그인이 필요하지 않습니다. | +| `users:delete` | `DELETE /users/:id`, `POST /users/:id/enable` | 사용자를 비활성화(즉시 세션 폐지)하거나 이전에 비활성화된 사용자를 다시 활성화합니다. | + +이 권한들은 대시보드의 **Users** 페이지를 지원하며, 각 멤버에게 부여된 범위가 칩 형태로 표시됩니다: + +![Users 페이지: 각 대시보드 사용자의 이메일, 부여된 권한, 편집/비활성화 컨트롤이 포함된 카드](/agenteye/images/users.png) + +### 운영 설정 + +| 권한 | HTTP 라우트 | 허용 작업 | +|---|---|---| +| `settings:read` | `GET /settings`, `GET /settings/schema`, `GET /settings/model-context-windows`, `GET /settings/model-context-windows/resolve` | 대시보드 관리형 운영 설정 및 메타데이터 조회, 모델별 컨텍스트 윈도우 오버라이드 목록, 특정 모델의 유효 윈도우 해석을 허용합니다. | +| `settings:write` | `PUT /settings/:key`, `PUT /settings/model-context-windows`, `DELETE /settings/model-context-windows` | 운영 설정을 편집하고 모델별 컨텍스트 윈도우 오버라이드를 추가, 변경, 삭제합니다. 변경 사항은 서버 재시작 없이 새 이벤트에 즉시 적용됩니다. | + +![Settings 페이지: 허용된 로그인 방식 및 세션/OTP 유효 기간 등 대시보드 관리형 운영 설정, 재시작 없이 편집 가능](/agenteye/images/settings.png) + +### 알림 및 인시던트 + +| 권한 | HTTP 라우트 | 허용 작업 | +|---|---|---| +| `alerts:read` | `GET /alerts`, `GET /alerts/:id` | 설정된 알림 정의를 조회합니다. | +| `alerts:write` | `POST /alerts`, `PUT /alerts/:id`, `DELETE /alerts/:id`, `POST /alerts/:id/test` | 알림 정의를 생성, 편집, 삭제, 테스트 발송합니다. | +| `incidents:read` | `GET /alerts/incidents`, `GET /alerts/incidents/:iid`, `GET /alerts/incidents/:iid/comments`, `GET /alerts/incidents/:iid/subscribers` | 인시던트와 트리아지 이력을 조회합니다. | +| `incidents:write` | `POST /alerts/:id/incidents` | 기존 알림에 대해 인시던트를 수동으로 생성합니다. | +| `incidents:ack` | `POST /alerts/incidents/:iid/ack`, `POST /alerts/incidents/:iid/assign`, `POST /alerts/incidents/:iid/resolve`, `POST /alerts/incidents/:iid/comments`, `POST /alerts/incidents/:iid/subscribe`, `POST /alerts/incidents/:iid/unsubscribe` | 인시던트를 확인(acknowledge), 담당자 지정, 해결, 댓글 작성, 구독/구독 취소합니다. | + +### 감사 + +| 권한 | HTTP 라우트 | 허용 작업 | +|---|---|---| +| `audits:read` | `GET /audits`, `GET /audits/:id`, `GET /audits/:id/runs`, `GET /audits/findings`, `GET /audits/findings/:fid` | 감사 정의, 실행 이력, 발견 항목을 조회합니다. | +| `audits:write` | `POST /audits`, `PUT /audits/:id`, `DELETE /audits/:id`, `POST /audits/:id/run`, `POST /audits/findings/:fid/status` | 감사를 생성, 편집, 삭제, 실행하고 발견 항목을 트리아지(확인/음소거/기각/해결/재개/담당자 지정)합니다. | + +> Audits 기능이 출시될 때, 기존 권한 부여자는 알림과 동일한 역할 형태로 확장되었습니다: `alerts:read`를 보유한 모든 사용자와 권한 집합에는 `audits:read`가 추가되었고, `alerts:write`를 보유한 모든 권한 부여자에게는 `audits:write`가 추가되었습니다. 기존 API 키는 **확장되지 않았습니다** — 감사 기능이 필요한 키에는 `audits:*`를 명시적으로 부여하세요. + +> 레거시 `alerts:ack` 토큰의 저장된 권한 부여는 `incidents:ack`로 파싱되므로, 온콜 담당자는 키를 재발급하지 않고도 접근을 유지할 수 있습니다. 이 토큰은 더 이상 대시보드 사용자 편집기에서 할당할 수 없으며, 매트릭스에서는 `incidents:ack`를 제공합니다. + +> 수신자 선택 엔드포인트 `GET /alerts/recipients`(알림 편집자가 알림을 보낼 수 있는 멤버 이메일 목록)는 `alerts:read` **또는** `alerts:write` 중 하나를 보유한 사람이 접근할 수 있으므로, 알림 편집자는 `users:read`를 부여받지 않아도 선택기에서 목록을 채울 수 있습니다. + +> 대시보드 뷰어는 `dashboards:read`(저장된 뷰 로드)와 `evaluations:read`(평가 데이터에서 계산되는 상태 지표) **두 가지 모두** 필요합니다. 사용자가 대시보드를 생성하거나 편집하려면 `dashboards:write`를, 삭제하려면 `dashboards:delete`를 부여하세요. + +> `/health`와 `/auth/*`(OTP 요청, OTP 검증, 세션 확인, 로그아웃)는 설계상 인증이 필요 없습니다. 이는 로그인 플로우와 활성 상태 프로브입니다. `GET /access-granters`는 유효한 키가 필요하지만 특정 권한은 필요하지 않으므로, 로그인한 모든 사용자가 접근 변경 사항에 대해 어떤 관리자에게 연락해야 하는지 확인할 수 있습니다. + +--- + +## 권한 집합 + +권한 집합을 사용하면 매번 개별 토큰을 일일이 선택하는 대신 명명된 역할을 적용할 수 있습니다. 새로운 대시보드 사용자나 API 키마다 수십 개의 권한을 하나씩 선택하는 대신 집합을 선택하면, 해당 집합에 배정된 모든 사람이 일관되고 검토 가능한 권한을 보유하게 됩니다. 커스텀 집합을 편집하면 이미 배정된 모든 사용자에게 새 권한이 재적용되므로, 역할 변경 시 모든 멤버를 일일이 수정할 필요 없이 한 번의 편집으로 완료됩니다. + +모든 조직은 세 가지 기본 제공 집합으로 시딩됩니다: + +| 집합 | 권한 | 대상 | +|---|---|---| +| `read-only` | `events:read`, `keys:read`, `users:read`, `evaluations:read`, `dashboards:read`, `queries:read`, `settings:read`, `alerts:read`, `audits:read`, `incidents:read` | 모든 운영 영역에 대한 읽기 전용 접근. | +| `standard` | `read-only`의 모든 권한 + `evaluations:trigger`, `queries:run`, `incidents:ack`, `agent:use` | 읽기 전용에 더해 일상적인 온콜 작업(쿼리 실행, 세션 재평가, 인시던트 확인, AI 어시스턴트 사용)이 가능합니다. | +| `admin` | 할당 가능한 모든 권한 | 조직의 완전한 제어권. | + +세 가지 기본 제공 집합은 **불변**입니다. 이름이 항상 동일한 의미를 가지므로 `read-only`, `standard`, `admin`은 정책 및 온보딩에서 안전하게 참조할 수 있습니다. 운영자는 조직에 특화된 역할(예: "대시보드 작성자" 역할 또는 "수집기 전용" 역할)을 모델링하기 위해 추가 **커스텀 집합**을 생성할 수 있습니다. + +집합은 대시보드에 표시되며 API를 통해 `GET /permission-sets`(목록, `users:read`로 제한)와 `POST /permission-sets` / `PUT /permission-sets/:name` / `DELETE /permission-sets/:name`(커스텀 집합 생성, 편집, 삭제, `settings:write`로 제한)으로 관리됩니다. 기본 제공 집합의 삭제 또는 편집은 거부됩니다. + +집합 멤버십은 다음 두 가지 기능의 기반이 됩니다: + +- **`DEFAULT_USER_PERMISSIONS`**(관리자가 **+ new user**를 열 때 사전 선택되는 권한 부여)는 기본적으로 `standard` 집합으로 설정됩니다. [배포](/ko/agenteye/deployment)를 참조하세요. +- **`agenteye-orgctl`의 `--set` 플래그**(운영자 멤버 관리)는 명명된 집합으로 멤버를 시작한 후 `--add` / `--remove`로 세부 조정합니다. [테넌트 관리](/ko/agenteye/tenant-management)를 참조하세요. + +> 집합에 키 할당 불가 권한(예: `keys:update`를 포함한 커스텀 집합)이 포함된 경우, 해당 집합에서 키를 시딩하면 할당 불가 토큰이 제외됩니다. 그렇지 않으면 서버가 HTTP 422로 키를 거부합니다. 대시보드 사용자에게는 이 제한이 적용되지 않습니다. + +--- + +## 부트스트랩 Admin 키 + +admin 키는 운영자가 아무것도 없는 상태에서 접근을 구성할 수 있게 해주는 단일 루트 자격 증명입니다. 이 키로 다른 모든 범위 지정 키를 생성하고, 첫 번째 대시보드 사용자를 초대하며, 다른 키가 존재하기 전에 인스턴스를 구성할 수 있습니다. 이 키는 keys API를 통해 생성하지 않는 유일한 키로, 서버가 처음 부팅될 때 접근 가능하도록 환경에서 프로비저닝됩니다. + +서버에 `ADMIN_KEY` 환경 변수를 설정하세요. 매 시작 시 서버는 이 값을 모든 권한을 가진 admin 키로 upsert합니다. + +교체하려면: `ADMIN_KEY`를 새 시크릿으로 변경하고 서버를 재시작하세요. + +--- + +## 조직 범위 + +**조직 자체는 운영자가 대역 외(out-of-band)로 생성하고 관리하며, 이 keys API를 통해 관리하지 않습니다.** 조직 및 멤버 수명 주기(조직 생성/이름 변경/삭제/제거, 멤버 추가/업데이트/삭제)는 서버 파드 내부에서 실행되는 **`agenteye-orgctl`** CLI로 수행하며, HTTP API나 대시보드 버튼이 없습니다. [테넌트 관리](/ko/agenteye/tenant-management)를 참조하세요. **변경되지 않는 것**: **org별 API 키는 여전히 대시보드(또는 이 keys API를 통해)에서 org 멤버가 발급합니다.** + +다중 org 배포에서 org 멤버가 생성하는 모든 키(이 keys API 또는 대시보드 **Keys** 페이지를 통해)는 **하나의 조직**에 속하며 해당 org의 데이터만 읽거나 쓸 수 있습니다. org는 키 생성 시 스탬핑되어 모든 요청에서 강제 적용됩니다. 두 가지 부트스트랩 키만 예외입니다: `admin` 키(`ADMIN_KEY`에서 시딩)와 `dashboard-assistant` 키(`AGENT_API_KEY`에서 시딩)는 **인스턴스 범위**(org 없음)를 가집니다. 대시보드 컨테이너는 `admin` 키로 인증하여 로그인된 멤버를 대신해 org별 요청을 프록시합니다. 단일 테넌트 배포에서는 이를 고려할 필요가 없습니다. 모든 키는 기본 제공 `default` org에 속합니다. + +--- + +## 키 생성 + +추가 범위 지정 키를 생성하려면 admin 키(또는 `keys:create` 권한을 가진 키)를 사용하세요. + +### 수집기 키 (수집 전용) + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "prod-collector", + "key": "your-collector-secret", + "permissions": ["events:add"] + }' +``` + +### 대시보드 키 (읽기 전용) + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "dashboard", + "key": "your-dashboard-secret", + "permissions": ["events:read", "keys:read"] + }' +``` + +HTTP API를 통해 키를 생성할 때는 `key` 값을 직접 제공해야 합니다. 강력한 시크릿을 선택하고 안전하게 보관하세요. (대시보드는 반대 방식으로 작동합니다: 강력한 시크릿을 자동으로 생성하여 생성 시 한 번만 표시합니다. [대시보드에서의 키 관리](#key-management-in-the-dashboard)를 참조하세요.) 응답은 키가 생성되었음을 확인합니다: + +```json +{ + "id": "550e8400-e29b-41d4-a716-446655440000", + "name": "prod-collector", + "permissions": ["events:add"], + "created_at": "2026-04-01T12:00:00Z" +} +``` + +--- + +## 키 목록 조회 + +```bash +curl -s http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +키 시크릿은 목록 응답에 반환되지 않으며, ID, 이름, 권한만 반환됩니다. + +--- + +## 키 비활성화 + +비활성화하면 키 레코드를 삭제하지 않고도 즉시 접근이 폐지됩니다. + +```bash +curl -s -X POST http://your-server:8080/keys//disable \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +--- + +## 키 재생성 + +기존 키에 대해 새 시크릿을 생성합니다. 기존 시크릿은 즉시 무효화됩니다. + +```bash +curl -s -X POST http://your-server:8080/keys//regenerate \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +응답에는 새로운 평문 시크릿이 포함되며, **한 번만 표시됩니다**. + +--- + +## 대시보드에서의 키 관리 + +대시보드의 **Keys** 페이지는 위의 모든 작업을 위한 UI를 제공합니다. 목록을 보려면 `keys:read` 권한이 있는 키가 필요하고, 생성/편집/비활성화/재생성 작업에는 각각 `keys:create` / `keys:update` / `keys:disable` / `keys:regenerate`가 필요합니다. 키의 권한 편집(`keys:update`)은 키 생성(`keys:create`)과 별개이므로, 운영자에게 기존 키의 범위를 재설정하는 권한 없이 키 발급 권한만 부여하거나 그 반대로 설정할 수 있습니다. admin 키는 이 모든 권한을 포함합니다. + +대시보드에서 키를 생성할 때 시크릿을 직접 입력하지 않아도 됩니다. 대시보드가 강력한 시크릿을 자동으로 생성하여 생성 시 **한 번만** 표시합니다. 재생성과 마찬가지로 이후에는 다시 표시되지 않으므로 즉시 복사하여 안전하게 보관하세요. 키의 권한을 직접 선택하거나 권한 집합에서 시딩할 수도 있습니다(아래 참조). + +![API Keys 페이지: 각 키의 이름, 부여된 권한, 생성 시간을 보여주는 카드, 재생성 및 비활성화 작업 포함; `admin` 같은 보호된 키는 별도로 표시됨](/agenteye/images/api-keys.png) + +--- + +## 권장 키 구성 + +| 키 | 권한 | 사용처 | +|---|---|---| +| `admin` (`ADMIN_KEY` 환경 변수를 통해 부트스트랩) | 전체 | 운영/설정, 그리고 대시보드 컨테이너(`ADMIN_KEY`로 인증, 권한 검사를 통해 사용자 요청 프록시) | +| 호스트별 수집기 키 | `events:add` | 각 에이전트 머신의 수집기 | +| `dashboard-assistant` (`AGENT_API_KEY` 환경 변수를 통해 부트스트랩) | `events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run` | AI 어시스턴트 컨테이너, 자동으로 시딩됨, **보호됨**; API를 통해 편집 불가 | +| 어시스턴트 텔레메트리 키 (선택 사항) | `events:add` | AI 어시스턴트 자체 계측(활성화된 경우) | + +> **어시스턴트 키.** 어시스턴트 키는 서버가 `AGENT_API_KEY` 환경 변수에서 **자동으로 시딩**합니다(에이전트가 `AGENTEYE_API_KEY`로 제공하는 것과 동일한 시크릿). 수동 키 발급 단계나 admin 키가 필요하지 않습니다. 권한은 소스 코드에서 고정되어 있으므로 잘못된 구성으로 범위가 확장될 수 없습니다: 이벤트/평가/대시보드에 대한 읽기 접근, "AI에게 쿼리 작성 요청" 작성 플로우를 위한 dashboards-write 및 queries-read/write/run. 모든 SQL은 사용자가 작성한 쿼리와 동일한 읽기 전용 역할 및 `sql_guard` 검사를 거치므로, 이는 *데이터 영역*이 아닌 *작성 영역*을 확장합니다. 파괴적인 작업(`queries:delete`, `dashboards:delete`)은 의도적으로 어시스턴트 키에서 제외됩니다. `admin` 키와 마찬가지로 **보호됩니다**: keys API를 통해 비활성화하거나 재생성할 수 없으며, `AGENT_API_KEY`를 변경하고 재시작하는 방식으로만 교체할 수 있습니다. 대시보드 *사용자*는 어시스턴트를 보고 사용하기 위해 추가로 `agent:use` 권한이 필요합니다. 자체 계측을 활성화하는 경우 어시스턴트에게 별도의 `events:add` 전용 키를 부여하세요. \ No newline at end of file diff --git a/docs/ko/agenteye/assistant.mdx b/docs/ko/agenteye/assistant.mdx new file mode 100644 index 00000000..b6262520 --- /dev/null +++ b/docs/ko/agenteye/assistant.mdx @@ -0,0 +1,195 @@ +--- +title: "AI 어시스턴트" +description: "AgentEye AI 어시스턴트 문서입니다." +--- + +대시보드에는 선택적으로 사용할 수 있는 **AI 어시스턴트**가 포함되어 있습니다. 이 채팅 패널은 대시보드 오른쪽 가장자리에 고정되어, 에이전트에 대한 자연어 질문("이번 주 프로덕션 품질 추세는?", "오늘 오류가 발생한 세션은?", "이 세션 요약해줘")에 답하고, 사용자가 각 작업을 허가한 경우 SQL 쿼리와 대시보드를 초안 작성 및 저장합니다. 관련 세션, 쿼리, 대시보드로 바로 이동하는 클릭 가능한 링크를 인용하며, **현재 페이지를 인식**합니다. 특정 세션을 보는 중에 "이 세션"에 대해 물어보면 문맥을 파악합니다. + +도크는 기본적으로 얇은 **44px 세로 레일**로 표시됩니다(`›_` 프롬프트 글리프와 색상이 있는 상태 점). 레일을 클릭하거나 `⌘J` / `Ctrl+J`를 눌러 전체 채팅 패널로 확장할 수 있습니다. 확장된 패널은 왼쪽 가장자리를 드래그하여 320~640픽셀 사이에서 **크기 조정**이 가능하며, 선호하는 너비는 새로고침 후에도 유지됩니다. + +이 기능은 소규모 내부 **`agent`** 컨테이너(Claude Agent SDK 기반)로 실행되며, 대시보드만 접근할 수 있습니다. **기본적으로 비활성화**되어 있으며, LLM 엔드포인트를 구성하기 전까지는 표시되지 않습니다. + +--- + +## 가능한 것과 불가능한 것 + +- **요청한 사용자가 볼 수 있는 운영 데이터를 읽습니다.** 이벤트, 평가, 세션, 평가 작업 큐, 저장된 쿼리, 저장된 대시보드를 사용자의 읽기 권한에 따라 요청별로 범위를 제한합니다. 읽기 도구는 즉시 실행됩니다. +- **쓰기는 작업별 승인이 필요합니다.** 저장된 쿼리(`create_saved_query`, `update_saved_query`)를 작성하고, 읽기 전용 역할로 초안 SQL을 실행하여 유효성을 검사하며(`run_query`), 해당 쿼리로 대시보드를 조립할 수 있습니다(`create_dashboard`, `update_dashboard`, `add_query_to_dashboard`). 각 쓰기 작업은 채팅 내 **승인 / 거부 / 질문하기** 프롬프트에서 일시 정지됩니다. SDK는 운영자가 승인을 클릭하기 전까지 도구를 호출하지 않습니다. **삭제는 어시스턴트에서 절대 사용할 수 없으며**, 파괴적인 작업은 운영자만 수행할 수 있습니다. +- **초안 SQL은 사용자 작성 SQL과 동일한 `sql_guard` 검증 및 읽기 전용 역할을 거칩니다**(SELECT/WITH만 허용, 다중 명령문 불가). 실행은 쿼리가 참조하는 테이블에 따라 라우팅됩니다. 분석 테이블(이벤트, 평가, 세션)을 참조하는 쿼리는 조직의 읽기 전용 ClickHouse 사용자로 실행되고(행 정책으로 해당 조직에 범위 제한, 10초 실행 제한, 10만 행 제한), 관계형 테이블만 참조하는 쿼리는 읽기 전용 Postgres 역할로 실행됩니다(10초, 1만 행). 어시스턴트는 데이터 접근 범위를 확장할 수 없으며, 운영자가 이미 가진 쿼리 범위 내에서만 작성할 수 있습니다. +- **전용 어시스턴트 키**(아래 참조)를 사용하여 고정된 권한 세트로 초기화됩니다. 모델이 오작동하더라도 해당 범위를 초과할 수 없습니다. +- 각 대시보드 사용자는 어시스턴트를 보고 사용하려면 **`agent:use`** 권한이 필요합니다. 도구는 요청별로 사용자 자신의 데이터 권한에 맞게 필터링되므로, `events:read` 사용자는 이벤트 도구를 사용할 수 있지만 `dashboards:write` 도구는 사용할 수 없습니다. + +--- + +## 페이지 인식 AI 도크: `/queries`에서는 작성기, 그 외에서는 채팅 + +오른쪽 어시스턴트 도크는 **페이지를 인식**합니다. 모델 선택기, 대화 기록, 모델 상태 점, 채팅 입력창은 변경되지 않지만, **빈 상태 템플릿 칩, 플레이스홀더 텍스트, 사용자 메시지가 전달되는 백엔드 엔드포인트**는 현재 라우트에 따라 자동으로 전환됩니다. 도크는 "현재 보고 있는 페이지의 AI 도우미"가 됩니다. + +**페이지별로 선택되는 두 가지 백엔드(칩별 오버라이드 가능).** + +| 라우트 | 페이지 기본 백엔드 | 이유 | +| --- | --- | --- | +| `/queries`, `/queries/new` | `POST /api/agent/compose-sql` (도구 루프 없음) | 사용자가 처음 시작하는 경우이며, 1초 이하의 첫 토큰 SQL이 에디터로 직접 스트리밍됩니다 | +| `/queries/` (기존) | `POST /api/agent/chat` (전체 도구 루프 어시스턴트), 페이지 기본값 | 자유롭게 입력된 메시지에서 사용자가 뭐든 물어볼 수 있어야 하며("설명해줘", "이게 뭐 하는 건지?"), 리팩터 칩은 칩별 kind로 compose-sql을 다시 선택합니다 | +| 그 외 모든 페이지 | `POST /api/agent/chat` (전체 도구 루프 어시스턴트) | 읽기 도구 + 승인 게이트 쓰기 도구 | + +`/queries/`의 칩은 명시적인 `kind`를 가지므로 단일 페이지에서 두 흐름을 원활하게 혼합할 수 있습니다. 기본 칩 세트는 두 개의 **chat** 칩(`explain the query on screen`, `what does this query do?`)과 다섯 개의 **compose-sql** 칩(`parameterize by date range`, `add a status='error' filter` 등)으로 구성됩니다. 자유롭게 입력된 메시지는 페이지 기본값(채팅)으로 처리되므로, "이게 왜 이렇게 느리지?"와 같은 질문은 산문 답변을 받고, `parameterize by date range` 칩을 클릭하면 작성 엔드포인트를 통해 SQL을 수정합니다. + +작성기가 **편집 모드**로 실행될 때(사용자가 `/queries/`에 있거나 이미 제안된 SQL이 로드된 `/queries/new`에 있어 비어 있지 않은 `currentSql`을 감지), 시스템 프롬프트가 "새 쿼리 작성"에서 "제공된 SQL을 최소한으로 수정: 테이블 선택, 컬럼 이름, 조인 구조, 별칭, 들여쓰기 유지"로 전환됩니다. 모델에는 별도의 before/after 예제(파라미터화, 필터 추가, 시간별 버킷으로 변환)가 제공되므로, 칩 클릭 리팩터는 에디터의 SQL을 처음부터 다시 작성하는 것이 아니라 최소한의 diff를 생성합니다. + +작성 칩 클릭(또는 `/queries/new`에서 자유롭게 입력) → SQL이 ` ```sql ` 펜스 블록으로 어시스턴트 메시지에 스트리밍됩니다. **스트림이 완료되는 순간, Monaco가 현재 라우트에 마운트되어 있으면 에디터가 자동으로 diff 뷰로 전환됩니다**(왼쪽에 원본, 오른쪽에 제안, 상단에 `▾ AI가 편집을 제안했습니다` 표시, 하단에 **수락 / 거부** 버튼). 사용자는 diff를 보기 위해 `에디터에 삽입` 버튼을 찾거나 클릭할 필요가 없습니다. 삽입 버튼은 SQL 블록 아래에 수동 재실행 트리거로 여전히 렌더링되며(거부 후 또는 사용자가 다른 곳으로 이동했다가 돌아왔을 때 유용), 에디터 외 페이지(예: 저장된 쿼리 목록)에서는 유일한 경로입니다. 이 경우 SQL을 `sessionStorage`에 저장하고 `/queries/new`로 이동하며, 새로 마운트된 에디터가 마운트 시 저장소를 읽어 동일한 diff 뷰를 엽니다. + +제안된 SQL이 에디터에 이미 있는 것과 바이트 단위로 동일한 경우(변경 없는 편집), 자동 열기는 건너뜁니다. 빈 diff는 표시하지 않습니다. `에디터에 삽입` 버튼도 이 경우 아무런 동작을 하지 않습니다. + +사용자가 `/queries/new`에서 제안을 수락하면 툴바의 기본 작업이 `create` 대신 **`save`**로 표시됩니다. SQL은 어시스턴트로부터 전달받은 것이므로, 사용자의 심리 모델은 "처음부터 작성"이 아닌 "마무리"입니다. 레이블은 도크가 SQL을 삽입하면 한 번 변경되어 페이지 이동 전까지 `save`로 유지됩니다. `/queries/`에서는 버튼이 항상 `save`였으므로 변화가 없습니다. + +`/queries` 외에서는 도크가 이전과 동일하게 작동합니다: 도구 승인 카드와 함께 전체 채팅, 페이지 컨텍스트 인식, 인용. + +**권한 / 게이팅.** 작성 엔드포인트는 사용자별 `queries:run` 권한으로 게이팅됩니다(읽기에 해당; 사용자는 여전히 수락 및 실행을 클릭해야 하며, 실행은 Rust 서버의 기존 `sql_guard` + `references_ch_tables` 라우팅을 거칩니다). 채팅 엔드포인트는 `agent:use`로 게이팅됩니다. 두 경로 모두 `agent` 컨테이너에 LLM 연결이 구성되어 있어야 합니다. 구성되지 않은 경우 도크는 두 경로 모두에서 "이 배포에서 어시스턴트가 구성되지 않았습니다" 배너를 표시합니다. + +**거부.** 작성기는 읽기 전용 분석 쿼리로 충족할 수 없는 요청을 거부하고, SQL 대신 `-- REFUSE: <한 문장 이유>`를 반환합니다. 데이터를 쓰거나 분석 뷰 외부 테이블(`api_keys`, `users`, `dashboards`, `saved_queries`, `evaluation_jobs`)에 접근하는 요청을 거부하며, 작성 경로에서 순수 산문 요청("설명해줘", "이게 뭐 하는 건지?")도 거부합니다. 이러한 요청은 채팅 경로에 속하며, 채팅에서 산문 답변을 제공합니다. 도크는 어시스턴트 메시지에 인라인 빨간색 오류 칩으로 거부 문자열을 렌더링하며, 아무것도 삽입되지 않습니다. + +**모델 선택.** 채팅 경로와 공유됩니다. 도크 헤더의 모델 선택기는 두 엔드포인트 모두에 적용됩니다(작성 호출은 선택된 모델을 에이전트 서비스의 `resolveModel()`로 전달합니다). `AGENTEYE_AGENT_MODELS`에 여러 모델이 나열된 경우, 운영자는 작성기에는 Haiku급 옵션을, 채팅에는 Sonnet급 옵션을 혼합할 수 있으며, 사용자는 대화별로 선택할 수 있습니다. + +**페이지별 템플릿.** 각 페이지마다 고유한 템플릿(헤드라인, 본문, 플레이스홀더 텍스트, 제안 칩)이 있어 도크가 현재 페이지에 맞게 적응합니다. 특정 라우트에서 제공되는 칩은 작성기가 최적화된 의도에 매핑되므로, 제안을 클릭하면 예상한 편집이 수행됩니다. + +**비활성화.** 채팅 경로와 동일합니다. 도크와 작성기 모두 `agent` 컨테이너와 LLM 연결로 게이팅됩니다. 특정 사용자에게 채팅 전용 동작을 원하면 `queries:run` 권한을 제거하세요(에디터의 **실행** 버튼도 비활성화됩니다). 작성기 전용 동작을 원하면 해당 사용자의 역할에서 `agent:use`를 제거하고, 사용자가 직접 작성한 SQL을 실행할 수 있도록 `queries:run`을 별도로 다시 추가하세요. + +--- + +## 활성화 방법 + +`agent` 서비스는 Docker Compose 파일 및 Kubernetes 매니페스트에 포함되어 있습니다. 어시스턴트를 활성화하려면 **(1)** LLM 엔드포인트와 **(2)** 어시스턴트의 전용 데이터 키를 제공하세요. + +### 1. LLM 연결 선택 + +다음 중 하나를 선택하고 `agent` 서비스에 해당 변수를 설정하세요: + +**a) Anthropic 직접 연결** + +``` +ANTHROPIC_API_KEY=sk-ant-... +``` + +**b) Portkey를 통한 연결 (권장; 모델 카탈로그 슬러그, 키만 필요)** + +``` +PORTKEY_API_KEY= +AGENTEYE_AGENT_MODEL=@/claude-sonnet-4-6 +``` + +가장 간단한 방법입니다. Portkey에서 **Anthropic 통합**(모델 카탈로그)을 설정하면 **슬러그**가 생성됩니다. 모델 이름을 `@/`로 지정하면 슬러그가 프로바이더와 자격증명 라우팅을 처리하므로 **가상 키가 필요하지 않으며**, Portkey API 키만 있으면 됩니다. 에이전트는 `x-portkey-api-key`만 전송하고 Portkey 게이트웨이를 가리키면 Portkey가 나머지를 처리합니다. (*일반* 모델 이름은 "x-portkey-config or x-portkey-provider header is required" 오류가 발생합니다. `@slug/` 접두사가 키 전용 방식을 가능하게 합니다.) 셀프 호스팅 게이트웨이의 경우 `PORTKEY_BASE_URL`을 설정하세요. + +슬러그 대신 요청별 라우팅을 선호한다면, 일반 `AGENTEYE_AGENT_MODEL`과 함께 `PORTKEY_VIRTUAL_KEY=` (또는 `PORTKEY_CONFIG=`)를 설정하세요. + +**c) 기타 Anthropic 호환 게이트웨이 (LiteLLM, 셀프 호스팅 등)** + +``` +ANTHROPIC_BASE_URL=https://your-gateway +# 줄바꿈으로 구분된 "Name: Value" 헤더 줄 (JSON 아님): +ANTHROPIC_CUSTOM_HEADERS=x-my-header: value +``` + +**d) Amazon Bedrock / Google Vertex** + +``` +CLAUDE_CODE_USE_BEDROCK=1 # + 환경 변수에 표준 AWS 자격증명 +# 또는 +CLAUDE_CODE_USE_VERTEX=1 # + 환경 변수에 표준 GCP 자격증명 +``` + +`AGENTEYE_AGENT_MODEL`로 기본 모델을 선택적으로 고정할 수 있습니다(기본값 `claude-sonnet-4-6`). 사용자가 여러 모델 중 **선택**하게 하려면 `AGENTEYE_AGENT_MODELS`에 쉼표로 구분된 허용 목록을 설정하세요(예: `@anthropic-prod/claude-opus-4-7,@anthropic-prod/claude-sonnet-4-6`). 그러면 채팅 헤더에 모델 선택기가 나타나고 각 사용자의 선택이 기억됩니다. 에이전트는 이 허용 목록에 있는 모델만 호출합니다. + +### 2. 어시스턴트 키 제공 + +임의의 시크릿을 생성하여 **agent**에는 `AGENTEYE_API_KEY`로, **server**에는 `AGENT_API_KEY`로 동일한 값을 제공하세요. 서버가 시작될 때 이를 `dashboard-assistant`라는 이름의 전용 키로 다음 고정 권한 세트와 함께 초기화합니다: `events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run`. 쓰기 권한은 승인 게이트 도구를 통해서만 사용됩니다(위의 "가능한 것과 불가능한 것" 참조). **수동 키 생성 단계나 관리자 키는 필요하지 않습니다.** 권한 세트는 서버에 고정되며, 초기화된 키는 **보호됩니다**: 키 API를 통해 비활성화하거나 재생성할 수 없습니다. 값을 변경하고 서버를 재시작하여 교체하세요. 관리자/대시보드 키를 재사용하지 **마세요**. + +```bash +SECRET="$(openssl rand -base64 32)" +# agent 서비스: +AGENTEYE_API_KEY="$SECRET" +# server 서비스: +AGENT_API_KEY="$SECRET" +``` + +Kubernetes에서는 이미 연결되어 있습니다: `AGENTEYE_API_KEY`를 `agenteye-agent` 시크릿에 넣으면 서버 Deployment가 동일한 값을 `AGENT_API_KEY`로 읽습니다. + +### 3. 대시보드↔에이전트 공유 토큰 설정 + +**대시보드**와 **agent** 서비스 모두에 동일한 `AGENTEYE_AGENT_TOKEN`을 설정하세요. 대시보드는 내부 에이전트 서비스를 호출할 때 이를 제시하며, 에이전트는 이 토큰 없이는 호출을 거부합니다. + +### 4. 사용자 접근 권한 부여 + +관련 대시보드 운영자에게 `agent:use` 권한을 부여하세요([enterprise-docs/api-keys.md](/ko/agenteye/api-keys) 참조). 이 권한이 없는 사용자는 어시스턴트를 볼 수 없습니다. + +LLM 엔드포인트와 읽기 전용 키를 설정한 후 **server**(읽기 전용 키 초기화)와 **agent** 서비스를 재시작하세요. `agent:use` 사용자라면 오른쪽 가장자리에 어시스턴트 도크가 기본적으로 접힌 채로 나타납니다. 레일을 클릭하거나 `⌘J` / `Ctrl+J`를 눌러 확장하세요. + +--- + +## 환경 변수 참조 + +**`agent`** 서비스에 설정: + +| 변수 | 용도 | +|---|---| +| `PORTKEY_API_KEY` | Portkey를 통한 라우팅 (에이전트가 이 값으로 게이트웨이 연결을 구성) | +| `PORTKEY_VIRTUAL_KEY` | Anthropic 자격증명에 대한 Portkey 가상 키 (키에 기본 설정이 있는 경우 선택사항) | +| `PORTKEY_CONFIG` / `PORTKEY_BASE_URL` | Portkey 명명된 구성 / 셀프 호스팅 Portkey 게이트웨이 URL (선택사항) | +| `PORTKEY_PROVIDER` | Portkey 프로바이더 슬러그 — `PORTKEY_VIRTUAL_KEY` / `PORTKEY_CONFIG`와 함께 사용하는 세 번째 라우팅 옵션 (둘 다 설정되지 않은 경우에만 사용) | +| `ANTHROPIC_API_KEY` | Anthropic 직접 접근 (게이트웨이 / Bedrock / Vertex 대안) | +| `ANTHROPIC_AUTH_TOKEN` | `x-api-key` 대신 `Authorization: Bearer`로 인증하는 게이트웨이의 Bearer 토큰 (선택사항) | +| `ANTHROPIC_BASE_URL` | Portkey 외 게이트웨이 엔드포인트 | +| `ANTHROPIC_CUSTOM_HEADERS` | Portkey 외 게이트웨이의 추가 헤더: 줄바꿈으로 구분된 `Name: Value` 줄 (JSON 아님) | +| `CLAUDE_CODE_USE_BEDROCK` / `CLAUDE_CODE_USE_VERTEX` | Bedrock / Vertex를 통한 라우팅 | +| `AGENTEYE_AGENT_MODEL` | 기본 모델 ID (기본값 `claude-sonnet-4-6`) | +| `AGENTEYE_AGENT_MODELS` | 채팅 헤더에서 사용자가 선택할 수 있는 모델의 쉼표로 구분된 허용 목록. 단일 고정 모델의 경우 설정하지 마세요. 위의 기본값이 포함되어 있지 않으면 자동으로 추가됩니다. | +| `AGENTEYE_AGENT_MAX_CONCURRENCY` | 파드당 최대 동시 채팅 수 (기본값 4). 초과 요청은 429를 받습니다 | +| `AGENTEYE_API_KEY` | 어시스턴트의 데이터 키. 서버의 `AGENT_API_KEY`와 **동일한** 값으로 설정하세요. 서버는 시작 시 고정된 범위 권한 세트로 초기화합니다(2단계 참조). | +| `AGENTEYE_AGENT_TOKEN` | 대시보드와의 공유 시크릿 | +| `AGENTEYE_SERVER_URL` | AgentEye 서버 URL (기본값 `http://server:8080`) | +| `AGENTEYE_AGENT_ALLOW_NO_ORG` | **멀티테넌시.** 기본적으로 비활성화(페일 클로즈): 어시스턴트는 조직 컨텍스트가 없는 `/chat` 요청을 `400`으로 거부합니다. 실행하는 모든 도구가 하나의 조직에 범위가 지정되기 때문입니다. 대시보드는 조직 인식 상태가 되면 항상 해당 컨텍스트를 전송하므로, 일반적으로 설정하지 않아도 됩니다. 아직 조직 인식이 되지 않은 대시보드가 조직 인식 에이전트와 통신하는 과도기적 롤아웃 중에만 `1`로 설정하세요. 이 경우 어시스턴트가 거부 대신 `default` 조직으로 폴백합니다. 대시보드 업그레이드가 완료되면 제거하세요. | +| `AGENTEYE_AGENT_MAX_STEPS` | 답변당 최대 도구 사용 단계 수 (기본값 8) | +| `AGENTEYE_AGENT_TIMEOUT_MS` | 전체 `/chat` 요청 타임아웃(모든 모델 턴 + 도구 단계), 밀리초 단위 (기본값 90000). SQL 도구는 자체 10초 제한이 있습니다 | +| `AGENTEYE_AGENT_SELF_TELEMETRY` | `1`로 설정하면 어시스턴트 자체 실행을 AgentEye에 기록합니다 | +| `AGENTEYE_TELEMETRY_API_KEY` | 자체 계측을 위한 별도의 `events:add` 전용 키 | +| `AGENTEYE_AGENT_ENV` | 어시스턴트 자체 텔레메트리에 적용되는 환경 태그 (기본값 `prod`) | + +**`dashboard`** 서비스에 설정: + +| 변수 | 용도 | +|---|---| +| `AGENTEYE_AGENT_URL` | 대시보드가 에이전트 서비스에 접근하는 주소. 번들된 Kubernetes 매니페스트와 Compose 파일은 이를 `http://agent:9100`으로 설정합니다. 설정하지 않으면 어시스턴트가 완전히 숨겨집니다. | +| `AGENTEYE_AGENT_TOKEN` | 에이전트의 토큰과 일치해야 합니다 | + +--- + +## 텔레메트리 및 사용자 질문 확인 + +프롬프트 **내용은 기본적으로 자체 시스템 내에 유지됩니다.** 세 가지 레이어: + +1. **대화 저장소**: 모든 프롬프트와 답변이 AgentEye 데이터베이스에 저장됩니다(사용자별, 비공개). 어시스턴트의 기록 전환기에서 다시 불러올 수 있습니다. 사용자가 무엇을 질문하는지에 대한 영구적인 기록입니다. +2. **제품 분석**: 대시보드는 **메타데이터만** 기록합니다(어시스턴트 사용 빈도, 도구 수, 지연 시간). 프롬프트 **텍스트**는 이 경로에 절대 포함되지 않습니다. +3. **자체 계측(선택사항)**: `AGENTEYE_AGENT_SELF_TELEMETRY=1`을 설정하고(그리고 `events:add` 전용 `AGENTEYE_TELEMETRY_API_KEY` 추가) 어시스턴트가 자체 실행을 `dashboard-assistant` 에이전트로 AgentEye에 기록하도록 하세요. 그러면 다른 모든 것에 사용하는 세션/이벤트 뷰에서 사용자 프롬프트와 어시스턴트의 추론 과정을 확인할 수 있습니다. 참고: 해당 이벤트는 `events:read` 권한이 있는 모든 사람에게 표시됩니다. 범위가 너무 넓다면 이 기능을 비활성화하세요. + +--- + +## 비활성화 방법 + +다음 중 하나를 수행하면 어시스턴트가 비활성화됩니다(도크 레일이 사라집니다): + +- 대시보드에서 `AGENTEYE_AGENT_URL` 설정 해제, **또는** +- 에이전트에 LLM 엔드포인트를 구성하지 않음(`ANTHROPIC_API_KEY` / 게이트웨이 / Bedrock / Vertex 없음), **또는** +- `agent` 서비스를 아예 배포하지 않음. + +--- + +## 보안 요약 + +- **자동 쓰기 없음**: 어시스턴트의 쓰기 도구(`create_saved_query`, `update_saved_query`, `create_dashboard`, `update_dashboard`, `add_query_to_dashboard`)는 운영자가 채팅 내 승인 버튼을 명시적으로 클릭하지 않으면 실행할 수 없습니다. SDK의 사전 호출 게이트는 승인이 백채널을 통해 에이전트에 도달하기 전까지 도구를 차단합니다. 이 게이트를 비활성화하는 설정은 없습니다. +- **고정된 좁은 데이터 범위**: 어시스턴트는 서버에서 권한 세트가 고정된 전용 키로 서버에 인증합니다(`events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run`). 작성할 수 있는 쓰기 작업은 저장된 쿼리와 대시보드뿐이며, 서버는 모델이 시도하는 것과 관계없이 해당 범위 외의 모든 것을 거부합니다. +- **삭제 기능 없음**: 키는 삭제 권한을 가지지 않으며 삭제 도구가 노출되지 않습니다. 운영자는 어시스턴트가 아닌 대시보드 UI를 통해 삭제합니다. +- **내부 전용**: 에이전트는 공개 라우트가 없으며, 공유 토큰이 있는 대시보드만 호출할 수 있습니다. (Kubernetes에서는 NetworkPolicy가 에이전트가 AgentEye 서버와 LLM 엔드포인트에만 접근하도록 제한합니다.) +- **사용자별 범위 지정**: `agent:use` 사용자만 어시스턴트를 사용할 수 있으며, 각 사용자의 읽기 권한에 맞는 도구만 제공됩니다. +- **원시 HTML 없음 / 링크 유출 없음**: 답변은 정제된 마크다운으로 렌더링되며 외부 링크는 무력화됩니다. + +일반적인 문제는 [enterprise-docs/troubleshooting.md](/ko/agenteye/troubleshooting)를 참조하세요. \ No newline at end of file diff --git a/docs/ko/agenteye/audits.mdx b/docs/ko/agenteye/audits.mdx new file mode 100644 index 00000000..19f0dc9e --- /dev/null +++ b/docs/ko/agenteye/audits.mdx @@ -0,0 +1,107 @@ +--- +title: "감사 — 에이전틱 개선 탐지" +description: "AgentEye 감사 — 에이전틱 개선 탐지 문서." +--- + + +감사(Audit)는 **세션 전반**에 걸쳐 에이전트 로그를 분석해 개선할 사항을 찾아내는 반복 실행 작업입니다. 알림(alert)이 이미 알고 있는 특정 지표를 거의 실시간으로 감시한다면, 감사는 *조사*를 수행합니다. 설정한 일정에 따라 해당 기간에 대한 결정적(deterministic) 정책 검사를 실행한 뒤, **AI 신뢰성 에이전트**를 세션에 풀어 데이터를 직접 쿼리하고, 의심스러운 대화록을 읽으며, 필요한 경우 간단한 분석 스크립트를 실행합니다. 그 결과로 각 근거가 뒷받침된 **개선 권고사항**을 작성합니다. + +감사는 "내 에이전트에서 무엇을 수정하거나 개선해야 하는가?"라는 질문에 답하고, 알림은 특정 임계값이 넘는 순간 즉시 알려줍니다. 모든 개선 사항은 배경이 된 정확한 세션과 쿼리로 연결되며, 클릭 한 번으로 재발을 감지하는 알림을 미리 채워진 상태로 생성할 수 있습니다. + +대시보드 화면은 **`//audits`** (사이드바 → *분석* → *감사*)이며, `audits:read` / `audits:write` 권한이 필요합니다. + +--- + +## 실행 방식 + +각 실행은 결정적(deterministic) 기반 레이어와 에이전틱 조사 레이어, 두 단계로 구성됩니다. + +### 1. 정책 검사 (결정적) + +어떤 모델도 실행되기 전에, 감사는 해당 기간에 대해 소규모 **SQL 정책 검사** 카탈로그를 실행합니다. 이 카탈로그는 경계가 있는 집계 쿼리로 알려진 문제 패턴을 플래그하고, 일치하는 텍스트 자체가 아닌 *몇 건의* 이벤트 / *어느* 세션이 해당되는지를 보고합니다. 카탈로그 항목은 다음과 같습니다: + +- 이벤트 페이로드의 **비밀 / 자격증명 유출** — AWS 액세스 키, `sk-…` API 키, PEM 개인 키, JWT / 베어러 토큰, `KEY=…` 자격증명 할당 +- **프롬프트 주입 마커** — "이전 지침을 무시하라", "시스템 프롬프트를 공개하라" 등 +- **개인식별정보(PII)** — 주민등록번호 형식 숫자(휴리스틱) +- **도구 권한 거부** 및 **도구 호출 루프 폭주** + +정책 위반은 (종류: `policy`) 발견 사항으로 저장되며, **항상 표시**됩니다(실행별 상한선에 의해 제거되지 않음). 또한 AI 에이전트에 초기 단서로 전달됩니다. 이 레이어는 모델이 필요 없으므로, AI 에이전트를 사용할 수 없는 경우에도 감사는 가장 중요한 보안 신호를 생성합니다. + +### 2. 에이전틱 조사 (AI) + +감사는 이어서 **자율 신뢰성 에이전트**(대시보드 어시스턴트를 구동하는 것과 동일한 Claude Agent SDK 서비스이며, 감사 전용 프롬프트 적용)를 실행합니다. 에이전트는 감사의 **범위**(선택된 에이전트 × 환경)와 **시간 창**을 바탕으로: + +- 분석 테이블에 대해 읽기 전용 SQL 쿼리를 실행하고, +- 대표적인 세션 대화록 일부를 읽으며, +- SQL로 표현할 수 없는 분석(오류 클러스터링, 분포 계산, 이미 가져온 페이로드 스윕 등)을 위해 **네트워크와 파일시스템 접근이 차단된 인-팟 샌드박스** (비밀 정보 제거)에서 짧은 **Python 스크립트**를 작성·실행하고, +- 근거가 충분히 확인된 **개선 사항**을 기록합니다. + +에이전트는 감사의 **민감도**(낮음 / 보통 / 높음)에 따라 오류 클러스터링, 기준선 대비 드리프트, 대화록의 목표 실패, 도구 오용, 품질/비용 균형, 커버리지 공백 등 여러 조사 방향을 탐색합니다. 모든 개선 사항에는 **반드시 근거가 있어야 합니다**: 에이전트가 실제로 검사한 세션 ID 및/또는 실행한 SQL. 서버는 인용된 세션의 존재를 검증하고 **근거가 없는 개선 사항은 폐기**하므로, 에이전트는 조사하지만 결코 꾸며내지 않습니다. + +각 개선 사항에는 다음이 포함됩니다: + +- **권고사항** (구체적인 변경 내용 — 프롬프트 수정, 도구 스키마 수정, 재시도 정책, 가드레일, 평가 커버리지 확대), +- **예상 영향** 및 **노력** 추정치 (낮음 / 보통 / 높음), +- **중요도** — `big` (운영자에게 즉시 알림 필요), `medium` (실행 보고서에 포함), `small` (대시보드 컨텍스트 수준), +- 안정적인 **핑거프린트** (이번 실행의 세션이 아닌 이슈의 카테고리 + 범위 기반) — 근거가 바뀌어도 실행에 걸쳐 동일 이슈를 추적 가능, +- 재발을 감지할 수 있는 간단한 결정적 감시자를 만들 수 있을 때, 클릭 한 번으로 생성 가능한 **알림 제안**. + +> **AI 레이어는 선택 사항이지만 권장됩니다.** 감사 파이프라인에 AI 에이전트가 구성되어 있지 않아도 실행은 계속되며, 정책 발견 사항은 저장됩니다. 에이전틱 레이어에 대해서는 조용히 통과시키는 대신 "분석 불가"로 정직하게 보고합니다. + +### 실패 모드 + +개선 사항은 조직의 영속적인 **실패 모드 카탈로그**로 분류되거나 새로운 모드를 제안합니다. 모드는 실행 전반과 장기적인 재발 추적에 걸쳐 패턴에 안정적인 정체성을 부여합니다. + +## 심사(Triage) 라이프사이클 + +발견 사항 페이지 (`/audits//findings/`)에서: + +| 액션 | 효과 | +|---|---| +| **인지(acknowledge)** | 발견 사항을 계속 표시하되 우선순위를 절반으로 낮춥니다. | +| **해결(resolve)** | 수정 완료로 표시합니다. 이후 패턴이 실제로 다시 나타나면 **신규**로 재오픈됩니다 — 회귀가 조용히 기록에 묻히지 않고 눈에 띄게 표시됩니다. | +| **음소거(mute)** / **기각(dismiss)** | 영구 억제: 패턴의 핑거프린트가 기억되어 실행 전반에 걸쳐 다시 표시되지 않습니다. mute는 "알고 있으며 수용함", dismiss는 "유용하지 않음"에 사용합니다. | +| **재오픈(reopen)** | 억제 / 해결을 취소하고 패턴의 우선순위를 다시 부여합니다. | +| **할당(assign)** | 소유권을 위해 발견 사항을 운영자(조직 멤버)에게 라우팅합니다. 우선순위와 억제 상태는 변경되지 않습니다. | + +저신호 노이즈는 에이전틱 개선에 대한 실행별 발견 사항 상한선(`top_k`)으로 감사별 제어됩니다. 정책 발견 사항은 보안 관련 항목으로 항상 표시되며 상한선을 우회합니다. 상한선에 의해 잘린 항목은 실행 통계에 포함되며, 조용히 삭제되지 않습니다. + +## 스케줄링 + +- **주기** (`schedule_interval_secs`): 매시간부터 매주까지; **기본값은 매일**. 감사는 의도적으로 알림보다 주기가 깁니다 — 에이전틱 조사는 전체 창을 스캔하며 수 분이 소요됩니다. +- **창(Window)**: 고정된 롤링 룩백(예: "각 실행은 지난 7일을 스캔") 또는 **마지막 실행 이후**(기본값) — 각 실행은 이전 성공적인 실행이 끝난 지점부터 시작하며, 경계 이벤트를 놓치지 않기 위해 작은 겹침(overlap)이 있습니다. +- 다음 실행은 이전 실행이 **완료된** 후 전체 주기만큼 지나 예약되므로, 느린 실행이 동일 감사의 두 번째 동시 실행을 쌓지 않습니다. +- 감사 페이지의 **지금 실행**을 누르면 즉시 실행 예약됩니다. + +## 모델 선택 + +감사를 생성할 때 **운영자가 에이전트 서비스에 구성한 모델 목록**에서 조사에 사용할 모델을 선택할 수 있습니다. 단일 모델이 구성된 경우 선택기는 해당 모델을 캡션으로 표시하며, 여러 모델이 있으면 선택할 수 있습니다. 설정하지 않으면 구성된 기본값이 사용됩니다. + +## 알림 + +실행에서 **신규** 발견 사항이 나타나면, 감사는 조직의 구성된 채널에 알림을 보냅니다 — 알림 파이프라인이 사용하는 것과 동일한 `alerts.enabled_channels` 게이트 및 설정: + +- **Slack** — 중요한(`big`) 신규 항목 요약과 딥 링크 +- **이메일** — 감사에 **이메일** 채널이 연결되어 있고 신규 발견 사항이 하나 이상 있을 때, 새로운 개선 사항(최고 심각도, 항목별 권고사항, 딥 링크)을 나열한 **감사 보고서**를 전송 + +반복되지만 알려진 발견 사항은 재알림을 보내지 않습니다. + +## 구성 참조 + +감사 정의는 대시보드(`/audits/new`) 또는 API를 통해 관리합니다. 감사별 설정에는 스케줄 주기와 창, 범위(`{"environments": [...], "agent_ids": [...]}`), 민감도(`low` / `medium` / `high`), 알림 채널, 실행별 발견 사항 상한선(`top_k`), 모델(`llm_budget.model`을 통해)이 포함됩니다. 운영자 수준 서버 설정(타임아웃, 샌드박스, 에이전트 서비스 URL)은 [deployment.md](/ko/agenteye/deployment)에 문서화되어 있습니다. + +## API + +모든 엔드포인트는 조직 범위이며 표준 베어러 키 인증을 따릅니다([api-keys.md](/ko/agenteye/api-keys) 참조). + +| 엔드포인트 | 권한 | 목적 | +|---|---|---| +| `GET /audits` · `POST /audits` | `audits:read` / `audits:write` | 감사 정의 목록 조회 / 생성 | +| `GET` / `PUT` / `DELETE /audits/:id` | read / write / write | 감사 조회, 수정, 삭제 | +| `POST /audits/:id/run` | `audits:write` | 감사를 즉시 실행 예약 | +| `GET /audits/:id/runs` | `audits:read` | 실행 기록 (창, 상태, 통계, 발견 사항 수) | +| `GET /audits/findings` | `audits:read` | 조직 전체 발견 사항, `audit_id`, `status`로 필터링 가능; 우선순위 순 정렬 | +| `GET /audits/findings/:fid` | `audits:read` | 발견 사항 전체 상세 정보 (권고사항, 근거, 우선순위) | +| `POST /audits/findings/:fid/status` | `audits:write` | 심사: `{"action": "ack" \| "mute" \| "dismiss" \| "resolve" \| "reopen" \| "assign"}` | + +"감사를 실행했지만 아무것도 찾지 못함", "코드 샌드박스가 비활성화됨", "감사 이메일이 전달되지 않음"에 대해서는 [troubleshooting.md](/ko/agenteye/troubleshooting#audits)를 참조하세요. \ No newline at end of file diff --git a/docs/ko/agenteye/cli-recipes.mdx b/docs/ko/agenteye/cli-recipes.mdx new file mode 100644 index 00000000..a066eb9b --- /dev/null +++ b/docs/ko/agenteye/cli-recipes.mdx @@ -0,0 +1,170 @@ +--- +title: "에이전트용 CLI 레시피" +description: "에이전트를 위한 AgentEye CLI 레시피 문서." +--- + + +스크립트나 코딩 에이전트에서 직접 세션, 이벤트, 평가 데이터를 가져오고(재평가 트리거 포함), `jq`로 바로 파이프할 수 있는 깔끔한 JSON을 stdout에 출력합니다. 이 레시피들은 AgentEye의 관측 가능성 데이터를 터미널 사용자나 AI 코딩 에이전트(Claude Code, Cursor)가 대시보드를 클릭하지 않고도 조회하고 자동화할 수 있는 형태로 변환합니다. + +아래 패턴들은 AgentEye CLI(`agenteye`)에서 바로 복사해서 사용할 수 있습니다. 설치, 인증, 전체 옵션 목록은 [CLI](/ko/agenteye/cli)를 참고하세요. 내장 도움말은 `agenteye -h` 또는 `agenteye -h`로 확인할 수 있습니다. + +## 기본 원칙 + +1. **전역 옵션은 커맨드 *앞에* 붙입니다.** `agenteye --json sessions`가 올바른 형태이며, `agenteye sessions --json`은 올바르지 않습니다. 전역 옵션은 `--json`, `--base-url`, `--org`, `--token`, `--insecure`/`--secure`, `--timeout`, `--quiet`, `--no-color`입니다. +2. **출력을 파싱할 때는 반드시 `--json`을 전달합니다.** 데이터는 JSON 형태로 **stdout**에 출력되고, 상태 메시지와 오류는 **stderr**로 출력되어 stdout을 `jq`로 파이프하기 깔끔하게 유지됩니다. +3. **stderr 텍스트가 아닌 종료 코드를 기준으로 분기합니다.** `0` 성공 · `2` 잘못된 인수 · `3` 대시보드 연결 불가 · `4` 미로그인 또는 세션 만료 · `5` 권한 없음. +4. **`-h`로 탐색합니다.** 모든 커맨드에서 필터, 값 형식, JSON 형태를 문서로 확인할 수 있습니다. + +## 초기 설정 + +```bash +export AGENTEYE_DASHBOARD_URL=https://agenteye.example.com # --base-url을 반복하지 않아도 됨 +agenteye login --email you@example.com # 이메일로 받은 코드를 붙여넣기; 약 24시간 유효 +``` + +## 작업 전 인증 확인 + +`whoami`는 세션이 없거나 만료된 경우에도 오류를 발생시키지 않고 `logged_in:false`를 반환하므로, 에이전트가 인증 상태를 안전하게 확인할 수 있습니다. (단, 베이스 URL이 설정되지 않았거나 대시보드에 연결할 수 없는 경우에는 여전히 비정상 종료될 수 있습니다.) + +```bash +if [ "$(agenteye --json whoami | jq -r .logged_in)" != "true" ]; then + echo "Not authenticated. Run: agenteye login" >&2; exit 1 +fi +``` + +## 실패하거나 낮은 점수의 세션 찾기 + +```bash +# 평가가 오류 상태인 최근 24시간 세션 +agenteye --json sessions --since 24h --status error | jq -r '.sessions[].session_id' + +# 특정 에이전트에서 helpfulness 점수가 0.5 이하인 평가 +agenteye --json evals --agent-id checkout-bot --score helpfulness:..0.5 \ + | jq '.evaluations[] | {session_id, scores}' +``` + +점수 필터링은 `sessions`가 아닌 **`evals`**에서 적용됩니다. `--score KEY:MIN..MAX`는 반복 사용 가능하며 AND 조건으로 결합됩니다. 양쪽 경계값은 선택 사항입니다(`..0.5`는 ≤ 0.5, `0.9..`는 ≥ 0.9를 의미합니다). 요청당 최대 20개의 점수 필터를 전달할 수 있으며, 초과하면 HTTP 400이 반환됩니다. `sessions`는 `evals`와 `--env`, `--status`, `--agent-id`, `--session-id`, 시간 범위 필터를 공유하지만 `--score`는 없습니다. + +## 하나의 세션 전체 읽기 + +단일 `session show` 커맨드는 없으며, 이벤트 이력과 세션 평가를 조합합니다. + +```bash +# 세션의 최신 평가 (상태 + 점수) +agenteye --json evals --session-id run-001 | jq '.evaluations[0] | {status, scores}' + +# 실행의 모든 이벤트 (전체 조회를 위해 --limit 늘리기) +agenteye --json events --session-id run-001 --all --limit 1000 | jq '.events[] | {ts, event_type}' + +# 세션에서 도구 호출만 +agenteye --json events --session-id run-001 --event-type tool_use,tool_result --all \ + | jq '.events[].payload' +``` + +## 전체 데이터 가져오기 (페이지네이션) + +결과는 최신순으로 정렬되며 커서 기반 페이지네이션을 사용합니다. + +```bash +# 한 번에: 200행 페이지 단위로 최대 500행 가져오기 +agenteye --json events --session-id run-001 --limit 500 --all > events.json + +# 수동 페이지 이동: next_cursor를 다시 전달 +page=$(agenteye --json events --limit 100) +cursor=$(echo "$page" | jq -r '.next_cursor // empty') +[ -n "$cursor" ] && agenteye --json events --limit 100 --cursor "$cursor" +``` + +## --fields로 출력 줄이기 + +에이전트가 읽어야 할 내용을 줄이기 위해 키를 제한합니다(테이블과 `--json` 모두 적용). + +```bash +agenteye --json sessions --since 7d --fields session_id,status,scores | jq -c '.sessions[]' +agenteye --json events --session-id run-001 --fields ts,event_type --all +``` + +알 수 없는 필드 이름은 유효한 목록과 함께 거부됩니다(종료 코드 `2`). 이를 통해 필드 이름을 간편하게 탐색할 수 있습니다. + +## 유효한 필터 값 탐색 + +```bash +agenteye --json list envs | jq -r '.values[]' # --env에 사용할 값 +agenteye --json list tools | jq -r '.values[]' # 도구 이름; agents, models, event_types 등도 가능 +agenteye --json list score_filters | jq -r '.values[]' # --score KEY:MIN..MAX의 유효한 KEY +``` + +## 조직 선택 (멀티 테넌트) + +둘 이상의 조직에 속해 있는 경우, 로그인 시 활성 테넌트를 선택합니다(저장됨): + +```bash +agenteye login --org acme --email you@corp.com # 로그인과 동시에 테넌트 설정 +agenteye --json orgs list | jq -r '.orgs[].org_slug' +agenteye --org globex --json sessions --since 24h # 단일 커맨드에 대해 재정의 +``` + +`--org` 없이 여러 조직에 로그인하면 비정상 종료되며 선택 가능한 조직 목록이 출력됩니다. + +## SDK/콜렉터용 API 키 발급 + +```bash +# 시크릿은 한 번만 출력됨 — --json 사용 시 .key 필드에서 확인 +key=$(agenteye --json keys create ci-bot --add events:read.add | jq -r '.key') +agenteye keys regenerate ci-bot --yes # 키 교체; 폐기는 agenteye keys disable ci-bot --yes +``` + +## 저장된 쿼리 또는 임시 쿼리 실행 + +```bash +agenteye --json query run --sql "select count(*) from analytics.events" | jq '.rows' +agenteye --json query run errs --arg prod | jq '.rows' # 저장된 쿼리 + 위치 인수 $1 +``` + +## 인시던트 비대화형 트리아지 + +```bash +id=$(agenteye --json incidents list --state firing | jq -r '.incidents[0].id') +agenteye incidents ack "$id" +agenteye incidents assign "$id" you@corp.com +agenteye incidents resolve "$id" --yes +``` + +> 뮤테이션은 `--json` 사용 시 또는 stdin이 TTY가 아닌 경우 확인 프롬프트를 자동으로 건너뜁니다. 따라서 에이전트가 멈추는 일이 없으며, 다른 곳에서 명시적으로 건너뛰려면 `--yes`/`-y`를 전달하세요. + +## 스크립트에서 종료 코드 처리 + +```bash +out=$(agenteye --json sessions --since 1h) || code=$? +case "${code:-0}" in + 0) echo "$out" | jq '.sessions | length' ;; + 4) echo "Session expired - run 'agenteye login'." >&2 ;; + 5) echo "Missing permission (ask an admin for evaluations:read)." >&2 ;; + 3) echo "Dashboard unreachable - check the URL." >&2 ;; + *) echo "Unexpected error (exit ${code})." >&2 ;; +esac +``` + +## JSON 출력 형태 + +| 커맨드 | stdout JSON (`--json` 사용 시) | +|---|---| +| `whoami` | `{"logged_in": true, "id", "email", "is_instance_admin", "active_org", "permissions": [...], "memberships": [...]}` 또는 `{"logged_in": false}` | +| `orgs list` | `{"active_org", "orgs": [{"org_slug","org_name","permission_set","permissions"}]}` | +| `events` | `{"events": [...], "next_cursor": }` | +| `evals` | `{"evaluations": [...], "next_cursor": }` | +| `sessions` | `{"sessions": [...], "next_cursor": }` | +| `errors` | `{"errors": [...], "next_cursor": }` | +| `list ` | `{"kind", "values": [...]}` | +| `keys list` / `keys create` | `{"keys": [...]}` / `{id, name, permissions, created_at, key}` (`key`는 한 번만 표시) | +| `query run` | `{columns: [{name,type}], rows: [[...]], truncated, elapsed_ms}` | +| `users list` / `settings list` | `{"users": [...]}` / `{"settings": [...]}` | +| `alerts list` / `incidents list` | `{"alerts": [...]}` / `{"incidents": [...]}` | +| create/update/delete (모두) | 리소스 객체, 또는 삭제 시 `{"deleted": true, "id"}` | +| 실패 (모두, `--json` 사용 시) | stdout에 `{"error": "...", "exit_code": , "status"?: , "hint"?: "..."}` | + +- **이벤트** 항목(`events`) 각각: `id, session_id, agent_id, event_type, ts, payload, environment`. +- **평가** 항목(`evals`) 각각: `id, session_id, agent_id, environment, status, scores, reasoning, summary, error, attempt_count, duration_ms, completed_at, created_at`. +- **세션** 항목(`sessions`) 각각: `session_id, agent_id, environment, status, scores, event_count, started_at, last_event_at, first_event_id, last_event_id, latest_evaluation`. + +각 커맨드의 `--fields`는 해당 항목의 필드 이름만 허용합니다. `sessions`와 `evals`는 필드 집합이 다르므로, 한쪽에서 유효한 이름이 다른 쪽에서는 거부될 수 있습니다. \ No newline at end of file diff --git a/docs/ko/agenteye/cli-skill.mdx b/docs/ko/agenteye/cli-skill.mdx new file mode 100644 index 00000000..04d2fbb6 --- /dev/null +++ b/docs/ko/agenteye/cli-skill.mdx @@ -0,0 +1,95 @@ +--- +title: "AgentEye CLI Agent Skill" +description: "AgentEye AgentEye CLI Agent Skill 문서." +--- + + +**AgentEye CLI 스킬** (`agenteye-cli`)은 설치 가능한 *Agent Skill*로, Claude Code, Codex 등 호환 가능한 코딩 에이전트 도구가 자연어 요청을 통해 AgentEye 배포 환경을 [`agenteye` CLI](/ko/agenteye/cli)로 운용할 수 있도록 가르쳐 줍니다. 예를 들어 *"오늘 문제 있는 게 있어?"*, *"CI에 이벤트 푸시만 가능한 키 줘"*, *"발생 중인 인시던트 확인하고 나한테 할당해줘"* 같은 요청이 가능합니다. + +이 스킬은 별도 서비스나 바이너리가 **아닙니다**. 이미 설치된 CLI 위에서 동작하는 소형 명령어 번들입니다. 에이전트가 `agenteye --json …` 명령을 실행하고 깔끔한 JSON을 파싱한 뒤 자연어로 결과를 알려줍니다. 스킬이 할 수 있는 모든 것은 동일한 명령어를 직접 입력해도 수행할 수 있습니다. + +--- + +## 다른 AgentEye 인터페이스와의 관계 + +AgentEye는 동일한 데이터와 컨트롤에 접근하는 네 가지 방법을 제공하며, 서로 보완적으로 사용할 수 있습니다: + +| 인터페이스 | 설명 | 실행 환경 | 사용 시점 | +|---|---|---|---| +| **[CLI](/ko/agenteye/cli)** | `agenteye` 명령어/플래그 레퍼런스 | 터미널 | 특정 명령을 직접 실행하거나 스크립트로 작성할 때 | +| **[CLI 레시피](/ko/agenteye/cli-recipes)** | 복사하여 바로 사용 가능한 `jq`/파이프라인 패턴 | 터미널 / 스크립트 | CLI를 자동화에 연결할 때 | +| **CLI 스킬** (이 문서) | CLI에 자연어 인터페이스를 제공하는 프론트엔드 | 워크스테이션의 코딩 에이전트 | 직접 물어보고 에이전트가 명령어를 선택하게 하고 싶을 때 | +| **[대시보드 내 AI 어시스턴트](/ko/agenteye/assistant)** | 대시보드에 내장된 채팅 | 클러스터 내부의 `agent` 컨테이너 | 대시보드에서 데이터를 Q&A 방식으로 조회하고 싶을 때 | + +### 대시보드 내 AI 어시스턴트와의 차이 — 중요한 구분 + +두 도구는 영향 범위가 크게 다릅니다: + +- **대시보드 내 AI 어시스턴트** ([assistant.md](/ko/agenteye/assistant))는 내부 `agent` 컨테이너를 기반으로 대시보드에 내장된 채팅입니다. **읽기 전용 + 승인 기반 작성**만 가능합니다. 저장된 쿼리와 대시보드를 초안으로 작성할 수 있지만, 모든 쓰기 작업은 사용자의 명시적인 클릭 승인을 요구하며 삭제는 불가능합니다. `agent:use` 권한으로 제한되며 현재 조회 중인 조직의 데이터만 볼 수 있습니다. +- **CLI 스킬**은 *사용자*의 워크스테이션에서 *사용자*의 코딩 에이전트 내에 실행되며, **사용자** 권한으로 `agenteye` CLI를 구동합니다. API 키 생성/교체/비활성화, 조직 설정 변경, 인시던트 해결, 저장된 쿼리 삭제 등 **변경(mutation)을 포함한 CLI의 전체 기능**을 수행할 수 있으며, CLI 로그인 권한 범위 내에서만 작동합니다. 해당 명령어를 직접 입력하는 것과 동일하게 신중하게 다루어야 합니다. + +--- + +## 사전 요구 사항 + +1. **`agenteye` CLI가 설치**되어 있고 `PATH`에 등록되어 있어야 합니다 ([cli.md](/ko/agenteye/cli) 참고 — `pipx install agenteye`). +2. **대시보드 URL**이 설정되어 있어야 합니다 (`AGENTEYE_DASHBOARD_URL` 환경 변수 또는 에이전트가 `--base-url` 옵션으로 전달). +3. **로그인된 세션**: 먼저 직접 `agenteye login`을 실행해야 합니다. 스킬은 이메일로 전송된 일회용 코드 로그인을 완료할 수 **없습니다**. 세션이 없거나 만료된 경우 (CLI 종료 코드 `4`) `agenteye login`을 실행하라고 안내합니다. + +--- + +## 스킬 설치 + +Agent Skill은 `SKILL.md`(및 선택적 참조 파일)를 포함하는 폴더입니다. `agenteye-cli` 스킬을 설치하려면 에이전트가 스킬을 찾는 위치에 해당 폴더를 배치하면 됩니다: + +- **Claude Code** — `agenteye-cli/` 폴더를 `~/.claude/skills/` (모든 프로젝트에서 사용 가능)에 복사하거나 `/.claude/skills/` (해당 저장소로 범위 제한)에 복사합니다. Claude Code가 자동으로 감지합니다. `/skills` 목록으로 확인하거나 스킬 설명과 관련된 질문을 해보세요. +- **Codex (OpenAI)** — Codex는 동일한 `SKILL.md`를 읽습니다. 번들에 포함된 `agents/openai.yaml`에 `allow_implicit_invocation: true`가 설정되어 있어, 태스크가 일치하면 Codex가 자동으로 스킬을 선택합니다. 그렇지 않은 경우 `$agenteye-cli`로 명시적으로 호출할 수 있습니다. + +이 스킬은 `agenteye` CLI와 함께 유지 관리되며 AgentEye 패키지의 일부로 배포됩니다. `agenteye-cli` 폴더가 없다면 AgentEye 담당자에게 문의하세요. 별도로 게이트되어 있지 않습니다. Docker 이미지나 별도 자격 증명이 필요 없으며, 단지 사용자 자신의 대시보드를 대상으로 **공개** `agenteye` CLI를 구동할 뿐입니다. + +--- + +## 안전 — 에이전트가 CLI를 실행할 때 변경 작업은 확인 프롬프트가 표시되지 않습니다 + +**에이전트가 변경 작업을 수행하도록 허용하기 전에 반드시 읽어주세요.** + +`agenteye` CLI는 일반적으로 파괴적인 작업 전에 *"정말로 실행하시겠습니까?"*라고 묻습니다. 하지만 **터미널에 연결되어 있지 않을 경우 이 확인 과정을 자동으로 건너뛰는데, 코딩 에이전트가 CLI를 실행하는 방식이 바로 그렇습니다. `--json` 옵션도 확인 과정을 건너뜁니다.** 따라서 에이전트에서는 안전 확인 프롬프트가 **표시되지 않습니다**. + +이를 보완하기 위해 스킬은 다음과 같이 동작하도록 설계되었습니다. 실행할 정확한 명령어를 먼저 명시하고, 상태 변경 전에 사용자의 명시적인 **승인**을 받도록 지시되어 있습니다. 이 원칙을 유지하세요. 에이전트를 통해 AgentEye를 구동할 때 *사용자*가 바로 확인 단계입니다. 주의해야 할 상태 변경 명령어는 다음과 같습니다: + +- `keys create` / `update` / `disable` / `regenerate` +- `users create` / `update` / `disable` / `enable` +- `settings set` +- `alerts create` / `update` / `delete` / `test` +- 쓰기 관련 `incidents` 하위 명령어: `ack` / `assign` / `resolve` / `open` / `comment-add` / `comment-delete` / `subscribe` / `unsubscribe` +- `query create` / `update` / `delete` +- `agent rename` / `delete` +- `orgs switch` + +**Observe** 하위 명령어(`events`, `sessions`, `evals`, `errors`, `list`, `whoami`, `orgs list/current/perms`)는 모두 읽기 전용이며 아무것도 변경하지 않습니다. + +에이전트는 **사용자**로서 동작하므로 로그인 권한 범위 내에서만 작업을 수행할 수 있습니다. 권한은 **조직별**로 확인됩니다 ([api-keys.md](/ko/agenteye/api-keys) 참고). 권한이 없는 명령어를 실행하면 종료 코드 `5`와 함께 필요한 권한 이름이 정확히 반환되므로, 에이전트가 불분명한 오류 대신 관리자에게 정확히 무엇을 요청해야 하는지 알려줄 수 있습니다. + +--- + +## 물어볼 수 있는 내용 + +이 스킬은 자연어 의도를 적절한 `agenteye` 명령어로 매핑하며, 추측 없이 먼저 유효한 값을 확인합니다 (`list `, `whoami`): + +- *"지난 24시간 동안 문제가 있거나 실패한 게 있어?"* → `errors --since 24h --aggregate` 후 상세 분석 결과 제공. +- *"세션 `run-001`이 왜 실패했어?"* → `events --session-id run-001 --all` + `evals --session-id run-001`. +- *"이번 주 품질 추세는 어때?"* → `evals --aggregate --since 7d` 후 낮은 점수 실행에 대한 심층 분석. +- *"CI에 이벤트 푸시만 가능한 키 줘."* → `keys create ci --add events:add` (명령어를 먼저 명시한 후 생성하고 일회용 시크릿 캡처). +- *"누가 접근 권한이 있어? Dana를 읽기 전용으로 바꿔줘."* → `users list` → (사용자 확인 후) `users update dana@… --permission-set read-only`. +- *"발생 중인 인시던트 확인하고 나한테 할당해줘."* → `incidents list --state firing` → `incidents ack ` / `incidents assign you@…`. + +이 내용의 배경이 되는 정확한 명령어, 플래그, JSON 구조는 [cli.md](/ko/agenteye/cli)와 [cli-recipes.md](/ko/agenteye/cli-recipes)를 참고하세요. + +--- + +## 참고 자료 + +- **[CLI](/ko/agenteye/cli)** — `agenteye`의 전체 명령어 및 플래그 레퍼런스. +- **[에이전트용 CLI 레시피](/ko/agenteye/cli-recipes)** — 복사하여 바로 사용 가능한 `jq` 패턴과 종료 코드 처리. +- **[AI 어시스턴트](/ko/agenteye/assistant)** — 대시보드 내 어시스턴트 (이 터미널 스킬과 혼동하지 마세요). +- **[API Keys](/ko/agenteye/api-keys)** — 스킬이 수행할 수 있는 작업 범위를 결정하는 조직별 권한 모델. \ No newline at end of file diff --git a/docs/ko/agenteye/cli.mdx b/docs/ko/agenteye/cli.mdx new file mode 100644 index 00000000..bac06b3a --- /dev/null +++ b/docs/ko/agenteye/cli.mdx @@ -0,0 +1,292 @@ +--- +title: "CLI" +description: "AgentEye CLI 문서." +--- + + +AgentEye CLI(`agenteye`)는 AgentEye 배포 환경을 위한 터미널 클라이언트입니다. 데이터(세션, 이벤트 로그, 평가)를 조회하고 조직을 관리(API 키, 사용자, 설정, 알림, 인시던트, 저장된 쿼리)합니다. 대시보드에서 할 수 있는 모든 작업을 스크립트나 코딩 에이전트에서도 수행할 수 있습니다. 모든 명령은 `--json` 플래그를 지원하므로, 터미널 앞의 사람에게도, 결과를 파싱하는 코딩 에이전트(Claude Code, Cursor)에게도 동일하게 활용할 수 있습니다. + +> 이 문서는 **`agenteye` CLI**에 관한 것으로, **컬렉터** 데몬(`agenteye-collector`)과는 별개의 도구입니다. CLI는 **대시보드**와 통신하고, 컬렉터는 서버로 이벤트를 전송합니다. 컬렉터에 대한 내용은 [컬렉터 설치](/ko/agenteye/collector-installation)를 참고하세요. + +--- + +## 설치 + +CLI는 **`agenteye`**라는 이름으로 공개 PyPI에 게시되어 있습니다. AgentEye Python SDK도 동일한 `agenteye` 배포 이름을 사용하므로, 두 패키지가 하나의 가상 환경에서 충돌하지 않도록 **격리된** 환경(`pipx` 또는 `uv tool`)에 CLI를 설치하세요. + +```bash +pipx install agenteye +# 또는 +uv tool install agenteye +``` + +Python SDK를 같은 환경에 설치하지 않는다면 `pip install agenteye`도 사용할 수 있습니다. CLI는 Python 3.10 이상이 필요하며 GitHub 토큰은 필요하지 않습니다. 공개 패키지입니다. + +설치된 명령은 **`agenteye`**입니다: + +```bash +agenteye --version +agenteye --help +``` + +--- + +## 인증 + +CLI는 이메일로 전송되는 일회용 코드를 사용해 **대시보드**에 인증합니다: + +```bash +agenteye login --email you@example.com +# 6자리 코드가 이메일로 발송됩니다. 프롬프트에 붙여넣으세요. +``` + +세션 토큰은 `~/.agenteye/cli.json`에 저장됩니다(본인만 읽을 수 있도록 모드 `0600`으로 설정). 기본적으로 24시간 동안 유효하며, 만료되면 `agenteye login`을 다시 실행하세요. + +```bash +agenteye whoami # 현재 사용자, 활성 조직, 권한 표시 +agenteye logout # 세션을 취소하고 저장된 토큰 삭제 +``` + +`whoami`는 세션이 없거나 만료된 경우에도 오류를 발생시키지 않습니다. 대신 `logged_in: false`를 반환하므로, 스크립트나 에이전트가 안전하게 인증 상태를 확인할 수 있습니다(기본 URL이 설정되지 않았거나 대시보드에 연결할 수 없는 경우에는 여전히 0이 아닌 종료 코드를 반환할 수 있습니다). + +**요구 사항:** 이메일이 대시보드 로그인 권한이 있어야 하며(AgentEye 관리자에게 문의), 대시보드가 기본 URL에서 접근 가능해야 합니다([구성](#구성) 참고). 코드를 요청했는데 수신되지 않는다면, 해당 이메일이 아직 대시보드 접근 권한을 부여받지 않은 것일 수 있습니다. + +--- + +## 조직 선택 (멀티 테넌트) + +계정이 둘 이상의 조직에 속해 있다면, **로그인 시** 활성 조직을 선택하세요. 선택된 조직은 저장되어 이후 모든 명령에 사용됩니다: + +```bash +agenteye login --org acme # 인증하면서 활성 테넌트를 한 번에 설정 +agenteye orgs list # 접근 가능한 조직 목록 (활성 조직이 표시됨) +agenteye orgs switch globex # 저장된 기본값 변경 +agenteye --org globex sessions # 단일 명령에 대해 재정의 +``` + +정확히 하나의 조직에 속해 있다면 자동으로 선택되므로 `--org`를 신경 쓸 필요가 없습니다. 여러 조직에 속해 있으면서 선택하지 않으면, CLI가 조직 목록을 표시하고 `--org `를 사용하여 다시 실행하도록 안내합니다. 활성 조직은 모든 요청에 포함되며, 권한은 **조직별로** 결정됩니다. `agenteye whoami`는 활성 조직, 해당 조직에서의 권한, 모든 멤버십을 표시합니다. + +--- + +## 구성 + +| 설정 | 플래그 | 환경 변수 | 기본값 | +|---|---|---|---| +| 대시보드 기본 URL | `--base-url` | `AGENTEYE_DASHBOARD_URL` | **필수** (기본값 없음) | +| 활성 조직/테넌트 | `--org` | `AGENTEYE_ORG` | 로그인 시 선택, `~/.agenteye/cli.json`에 저장 | +| 세션 토큰 | `--token` | `AGENTEYE_CLI_TOKEN` | `~/.agenteye/cli.json`에서 읽음 | +| JSON 출력 | `--json` | `AGENTEYE_CLI_JSON` | 비활성 | +| TLS 검증 건너뛰기 | `--insecure` / `--secure` | `AGENTEYE_INSECURE` | 비활성 (로그인 시 저장) | +| 요청 타임아웃 (초) | `--timeout` | — | 30 | +| 사용 텔레메트리 비활성화 | _(없음)_ | `AGENTEYE_ANALYTICS_DISABLED` (또는 `DO_NOT_TRACK`) | 비활성 (텔레메트리 활성) | + +우선순위 순서는 **플래그 → 환경 변수 → 설정 파일**입니다. 기본값이 없으므로 CLI가 대시보드를 가리키도록 명령별(`--base-url https://agenteye.example.com`) 또는 환경 변수로 한 번 설정해야 합니다(첫 `login` 이후에도 저장됩니다): + +```bash +export AGENTEYE_DASHBOARD_URL=https://agenteye.example.com +``` + +설정 디렉토리는 `AGENTEYE_HOME` 환경 변수를 따릅니다(SDK 및 컬렉터와 동일한 규칙). 설정된 경우 `cli.json`은 `$AGENTEYE_HOME/cli.json`에 위치합니다. + +### 자체 서명 또는 내부 TLS + +대시보드가 자체 서명 또는 내부 인증서(예: 로드 밸런서 호스트명)로 HTTPS를 제공하는 경우, TLS 검증이 `CERTIFICATE_VERIFY_FAILED` 오류로 실패합니다. `--insecure`를 전달하여 인증서 검증을 건너뛰세요: + +```bash +agenteye --base-url https://agenteye.internal --insecure login +``` + +`--insecure`는 **로그인 시 `cli.json`에 저장**되므로, 이후 명령에서 자동으로 검증을 건너뜁니다. 플래그를 반복할 필요가 없습니다. 일회성 검증 호출에는 `--secure`를 사용하거나, 다음 로그인 시 검증을 다시 활성화하려면 `--secure`를 저장하세요. CLI는 검증이 비활성화된 상태에서 대시보드에 접속하는 모든 명령 전에 stderr에 경고를 출력합니다. 검증을 건너뛰면 중간자 공격 방어가 제거됩니다. 이를 사용하기 전에 대시보드로의 네트워크 경로(VPN, 사설 서브넷 등)를 신뢰할 수 있는지 확인하세요. + +--- + +## 텔레메트리 및 개인 정보 + +CLI는 Exosphere의 분석 서비스(PostHog)에 **익명 사용 분석**을 전송합니다: 실행된 명령(예: `sessions`, `keys create`), 성공 여부, 소요 시간. 이 사용 신호는 기능 우선순위 결정에 활용됩니다. + +- **에이전트, 세션, 이벤트 데이터는 절대 인프라 외부로 전송되지 않습니다.** CLI 사용 정보만 보고됩니다: 명령 및 서브명령 이름(예: `keys create`), 사용한 플래그의 **이름**(값은 절대 포함하지 않음), 성공/종료 상태, 소요 시간. 변경 작업에 대한 이벤트(예: `api_key_created`, `query_run`)는 정적 이름/열거형과 대략적인 수치만 포함합니다. 대시보드 URL, 세션 토큰, 이메일, 조직 슬러그, 리소스 ID, SQL, 키 시크릿, 쿼리 필터는 **절대 전송되지 않습니다.** 운영자는 불투명한 내부 ID로만 식별되며, 이메일은 사용되지 않습니다. +- 텔레메트리는 **기본적으로 활성화**되어 있습니다. 비활성화하려면 CLI 환경에서 `AGENTEYE_ANALYTICS_DISABLED=1`을 설정하세요(크로스 툴 규칙인 `DO_NOT_TRACK=1`도 지원합니다). +- CLI는 PostHog(`https://us.i.posthog.com`)로 직접 전송합니다. **CLI를 실행하는 머신**은 해당 호스트에 대한 아웃바운드 접근이 필요합니다. 차단된 경우 텔레메트리는 조용히 아무것도 하지 않습니다(전송은 시간 제한이 있으므로 명령을 지연시키거나 중단시키지 않습니다). CLI 동작에는 영향이 없습니다. + +--- + +## 전역 옵션 및 규칙 + +한 번만 읽어두면 모든 명령에 적용됩니다. + +- **전역 옵션은 명령 앞에 위치합니다.** `agenteye --json sessions`는 올바른 형식이고, `agenteye sessions --json`은 사용 오류입니다. 전역 옵션은 `--json`, `--base-url`, `--org`, `--token`, `--insecure`/`--secure`, `--timeout`, `--quiet`, `--no-color`입니다. +- **`--json`은 순수 JSON을 stdout으로 출력하며, 그 외에는 아무것도 출력하지 않습니다.** 사람용 상태 메시지, 경고, 오류는 **stderr**로 전달되므로, `--json` stdout 캡처는 상태 메시지가 표시되더라도 `jq`로 파이프하기에 깨끗한 상태를 유지합니다. `--json` 없이는 사람이 읽기 좋은 박스형 컬러 뷰가 표시됩니다. +- **`--help`로 탐색하세요.** 모든 명령과 서브명령에는 `--help`(및 `-h` 별칭)가 있습니다: `agenteye -h`, `agenteye sessions -h`, `agenteye keys create -h`. 최상위 도움말에는 종료 코드와 전역 옵션도 나열됩니다. 전역 머신 가독형 전체 목록은 없습니다. 명령별 `--help`와, 두 레지스트리에 대한 도메인별 `agenteye query schema` 및 `agenteye settings schema`를 활용하세요. +- **스크립트 및 에이전트에서는 확인 프롬프트가 자동으로 건너뜁니다.** 생성/수정/삭제 명령은 대화형 터미널에서 "확인하시겠습니까?" 메시지를 표시하지만, **`--json`이나 stdin이 TTY가 아닌 경우에는 자동으로 건너뜁니다.** 따라서 스크립트와 에이전트는 멈추지 않습니다. 명시적으로 건너뛰려면 `--yes`/`-y`를 사용하세요. 에이전트에서는 프롬프트가 실행되지 않으므로, 에이전트는 파괴적인 작업을 수행하기 전에 먼저 사람에게 확인을 받아야 합니다. +- **페이지네이션:** 결과는 최신순으로 커서 페이지네이션됩니다. `--limit N`(별칭: `-n`)은 행 수를 제한하며 **기본값은 50**입니다. `--all`은 자동 페이지네이션(200행 단위)을 수행하지만 **`--limit`까지만** 가져옵니다. 따라서 `--all`만 사용하면 여전히 50개에서 멈춥니다. 전체 조회를 원하면 명시적으로 높은 값을 지정하세요: `--all --limit 1000`. `--page-size N`은 요청당 청크 크기를 제어하며(최대 200), `--cursor `는 이전 페이지의 `next_cursor`에서 재개합니다. +- **시간 필터:** `--since`는 상대 시간 범위(`15m`, `1h`, `6h`, `24h`, `7d`, `30d`, `all` - 대시보드 프리셋)를 받습니다. `--from`/`--to`는 명시적 ISO-8601 UTC 타임스탬프(**`T`와 타임존 포함**, 예: `2026-06-01T00:00:00Z`)를 받아 사용자 지정 범위를 지정하며 `--since`를 재정의합니다. 공백으로 구분되거나 타임존이 없는 값은 사용 오류입니다. +- **`--fields a,b,c`**(`events`, `sessions`, `evals`, `errors`에서 사용 가능)는 출력을 해당 키로 제한합니다(테이블과 `--json` 모두 해당). 알 수 없는 이름은 유효한 목록과 함께 거부됩니다. 필드 이름을 간편하게 확인하는 방법입니다. +- **`--file payload.json`**(또는 stdin을 읽으려면 `--file -`)은 리소스가 복잡한 형태를 가질 때 전체 JSON 요청 본문을 제공합니다. `alerts create/update`, `settings set`, `users create/update`에서 사용합니다. 저장된 쿼리 SQL은 `--sql @file.sql`을 사용합니다. +- **다중 값 필터**는 쉼표로 구분되며 집합으로 매칭됩니다(하나의 필터 내에서는 합집합, 필터 간에는 AND): `--event-type tool_use,tool_result`. Click 옵션은 가변 인수가 아니므로 `--add a b`는 오류입니다. `--add a,b`를 사용하거나 플래그를 반복(`--add a --add b`)하거나 따옴표로 묶으세요(`--add "a b"`). + +--- + +## 명령 참조 + +CLI에는 **18개의 최상위 명령**이 있습니다. 모든 읽기 명령은 `--json`과 위의 전역 옵션을 지원합니다. 각 명령의 전체 플래그 목록과 JSON 형태는 `agenteye -h`(또는 ` -h`)를 실행하세요. + +### 신원 — `login` · `logout` · `whoami` · `orgs` · `version` · `help` + +```bash +agenteye login --email you@example.com [--org acme] # 이메일 일회용 코드; 세션 저장 +agenteye logout # 이 머신에서 저장된 세션 삭제 +agenteye whoami # 현재 사용자, 활성 조직, 권한 +agenteye version # CLI 버전 출력 (--version과 동일) +agenteye help # 최상위 도움말 (--help와 동일) +``` + +`orgs`는 활성 테넌트를 확인하고 전환합니다: + +```bash +agenteye orgs list # 내 조직 + 각 조직에서의 역할 (활성 조직 표시) +agenteye orgs switch acme # 저장된 활성 조직 변경 (슬러그 생략 시 TTY에서 목록 선택) +agenteye orgs current # 활성 조직의 신원 카드 +agenteye orgs perms # 활성 조직에서 내 권한 (리소스별 그룹화) +``` + +### 관찰 (읽기 전용) — `events` · `sessions` · `evals` · `errors` · `list` + +이 명령들은 확인이 필요하지 않습니다. 공통 필터: `--session-id`, `--agent-id`, `--env`(**`--environment`가 아님**), 시간 범위(`--since` / `--from` / `--to`). + +```bash +# events (별칭: 단계별 원시 추적) — 최신순 +agenteye --json events --session-id run-001 --event-type tool_use,tool_result --all --limit 1000 +agenteye --json events --since 1h --search timeout --all | jq '.events[].payload' + +# sessions — 에이전트 실행별 한 행 (시간/환경/에이전트/세션/상태; 점수 필터 없음) +agenteye --json sessions --since 24h --status error +agenteye --json sessions --agent-id checkout-bot --env prod --all --limit 1000 + +# evals — 평가 결과 + 점수; --score는 지표로 필터, --aggregate는 집계 +agenteye --json evals --score helpfulness:0.5..0.8 --score tool_efficiency:..0.3 +agenteye --json evals --aggregate --since 7d --env prod # 상태 분포 + 키별 점수 통계 + +# errors — 오류 이벤트; --aggregate는 수량/세션/에이전트/마지막 발생 시간 집계 +agenteye --json errors --since 24h --aggregate +agenteye --json errors --since 24h --error-type timeout --all --limit 1000 + +# list — 필터링 전 유효한 필터 값 탐색 +agenteye list envs # 또한: agents event_types score_filters models hooks triggers tools error_types +``` + +`--score KEY:MIN..MAX`(**`evals`**에서 사용 가능, `sessions`에서는 불가)는 반복 가능하며 AND로 결합됩니다. 어느 쪽 경계도 선택 사항입니다(`..0.5`는 ≤ 0.5, `0.9..`는 ≥ 0.9 의미). 요청당 최대 20개의 점수 필터. `evals --scores-full`은 요약 대신 전체 점수 객체를 반환합니다. **하나의 세션을 처음부터 끝까지 읽으려면** 이벤트 추적과 평가를 함께 사용하세요: + +```bash +agenteye --json events --session-id run-001 --all --limit 1000 | jq '.events[] | {ts, event_type}' +agenteye --json evals --session-id run-001 # 점수 + 상태 +``` + +### 관리 (권한 필요) — `keys` · `users` · `settings` · `alerts` · `incidents` + +**`keys`** — API 키. 시크릿은 로컬에서 생성되어 서버로 전송되고(서버는 해시만 저장), 생성/재생성 시 **한 번만 표시됩니다**. 그때 반드시 캡처하세요. `--json`을 사용하면 `key` 필드에만 나타납니다. **이름**으로 참조됩니다. + +```bash +agenteye keys list # 활성 키 먼저, 그 다음 취소된 키 +agenteye keys show ci-bot +agenteye keys create ci-bot --add events:read.add # 필요한 범위만 지정; 시크릿은 한 번만 출력 +agenteye keys create ops --permission-set standard --remove queries:run # 프리셋에서 시작 후 제거 +agenteye keys update ci-bot --add evaluations:read --yes +agenteye keys regenerate ci-bot --yes # 시크릿 교체 (이전 시크릿은 즉시 비활성화) +agenteye keys disable ci-bot --yes # 취소 +``` + +권한은 `(permission-set ∪ --add) − --remove` 방식으로 작동합니다. 토큰은 `slug:action`(예: `events:read`) 또는 `slug:action.action` 형태로 하나의 리소스에 여러 액션을 확장할 수 있습니다(`events:read.add` → `events:read`, `events:add`). 프리셋: `read-only`, `standard`, `admin`. 사람 전용 권한(`keys:update`)은 키에 부여할 수 없습니다. + +**`users`** — 조직 멤버. **이메일**로 참조됩니다(UUID id도 허용). + +```bash +agenteye users list [--active-only] +agenteye users show dev@corp.com +agenteye users create dev@corp.com --permission-set standard +agenteye users update dev@corp.com --add alerts:write --remove queries:delete # 예측 + 확인 +agenteye users disable dev@corp.com --yes # 보호/자기 자신 가드 포함 +agenteye users enable dev@corp.com +``` + +**`settings`** — 고정 레지스트리 (기존 키를 읽고 변경하는 것만 가능; 새 키 생성 불가). + +```bash +agenteye settings list # 키 · 값 · 타입 · 수정 시간 (시크릿은 마스킹) +agenteye settings schema # 각 키가 허용하는 값 (타입 · 범위 · 설명) +agenteye settings set session_ttl_secs --value 86400 --yes +``` + +**`alerts`** — 알림 정의. **이름**으로 참조됩니다. `create`는 위치 인수로 NAME을 받으며, 플래그 또는 `--file`로 전체 JSON 본문을 제공할 수 있습니다. + +```bash +agenteye alerts list +agenteye alerts show high-errors +agenteye alerts create high-errors --file alert.json # NAME 필수 (위치 인수) +agenteye alerts update high-errors --severity critical --yes +agenteye alerts test high-errors --yes # 테스트 알림 전송 +agenteye alerts delete high-errors --yes +``` + +**`incidents`** — 알림 인시던트. ID로 참조됩니다(짧은 ID 허용). `show`는 전체 활동 로그를 출력합니다. 조치 전에 반드시 확인하세요. + +```bash +agenteye incidents list --state firing # 또한: acknowledged, resolved +agenteye incidents count +agenteye incidents show +agenteye incidents ack +agenteye incidents assign you@corp.com # 담당자는 운영자여야 함 +agenteye incidents resolve --yes +agenteye incidents open --alert-id --severity critical # 알림에 대해 수동으로 생성 +agenteye incidents comment-add "root cause: upstream 5xx" +agenteye incidents comment-list ; agenteye incidents comment-delete +agenteye incidents subscribe ; agenteye incidents unsubscribe ; agenteye incidents subscribers +``` + +### 분석 및 어시스턴트 — `query` · `agent` + +**`query`** — 저장된 ClickHouse SQL과 임시 실행기. 저장된 쿼리는 **이름**으로 참조됩니다. SQL은 서버 측에서 검증됩니다(SELECT/WITH만 허용, 쿼리 타임아웃, 행 제한). + +```bash +agenteye query schema [TABLE] # 분석 뷰의 컬럼 레이아웃 +agenteye query run --sql "select count(*) from analytics.events" +agenteye query run errs --arg prod --limit 100 # 저장된 쿼리 실행 + 위치 인수 $1 +agenteye query list ; agenteye query show errs +agenteye query create errs --sql @errs.sql --description "errored events (24h)" +agenteye query update errs --sql @errs.sql --yes ; agenteye query delete errs --yes +``` + +**`agent`** — 내장 대시보드 어시스턴트(대시보드에서 채팅할 수 있는 것과 동일한 읽기 전용 분석가). 채팅은 짧은 chat-id로 참조됩니다(접두사 자동 해결). + +```bash +agenteye agent health # 어시스턴트 설정/접근 가능 여부 확인 +agenteye agent models # --model에 전달 가능한 모델 (기본값 표시) +agenteye agent ask "which agents errored most in the last day?" # 채팅 시작; 짧은 id 출력 +agenteye agent ask --chat "and which tools did they call?" # 채팅 계속 +agenteye agent chats ; agenteye agent show +agenteye agent rename --title "error triage" ; agenteye agent delete +``` + +--- + +## 종료 코드 + +| 코드 | 의미 | +|---|---| +| 0 | 성공 | +| 1 | 예상치 못한 오류 (예: 대시보드가 5xx를 반환) | +| 2 | 사용 오류 (잘못된 인수, 알 수 없는 명령/플래그, 이름 충돌) | +| 3 | 대시보드에 연결할 수 없음 | +| 4 | 로그인하지 않았거나 세션이 만료됨; `agenteye login` 실행 필요 | +| 5 | 인증되었지만 필요한 권한이 없음 (메시지에 권한 이름 표시) | +| 6 | 요청한 리소스를 찾을 수 없음 (예: 알 수 없는 세션 또는 인시던트 ID) | + +이 코드들을 통해 CLI를 안전하게 스크립트화할 수 있습니다. 코딩 에이전트는 `4`를 받으면 재인증을 요청하거나, `5`를 받으면 누락된 권한을 표시할 수 있습니다. 종료 코드 처리 패턴과 JSON 출력 형태는 [에이전트를 위한 CLI 레시피](/ko/agenteye/cli-recipes)를 참고하세요. + +--- + +## 관련 문서 + +- **[에이전트를 위한 CLI 레시피](/ko/agenteye/cli-recipes)** — 코딩 에이전트를 위한 복사-붙여넣기 쿼리 패턴, `jq` 원라이너, `--fields` 프로젝션, 종료 코드 처리, JSON 출력 형태. +- **[AgentEye CLI 스킬](/ko/agenteye/cli-skill)** — 이 CLI를 설치 가능한 Claude Code / Codex *스킬*로 패키징하여 코딩 에이전트가 일반 영어 요청으로 AgentEye를 구동할 수 있게 합니다. +- **[API 키](/ko/agenteye/api-keys)** — `keys create --add …` 뒤의 권한 모델. +- **[AI 어시스턴트](/ko/agenteye/assistant)** — `agent ask`가 대화하는 어시스턴트 활성화 방법. \ No newline at end of file diff --git a/docs/ko/agenteye/collector-installation.mdx b/docs/ko/agenteye/collector-installation.mdx new file mode 100644 index 00000000..95317717 --- /dev/null +++ b/docs/ko/agenteye/collector-installation.mdx @@ -0,0 +1,401 @@ +--- +title: "Collector 설치" +description: "AgentEye Collector 설치 문서입니다." +--- + + +`agenteye-collector` 데몬은 애플리케이션을 차단하지 않고 에이전트의 텔레메트리를 AgentEye로 안정적으로 전송합니다. 코드는 이벤트를 로컬 디렉터리에 기록하고 즉시 다음 작업으로 넘어가며, 이후의 처리는 collector가 담당합니다. collector는 각 파일을 수 밀리초 내에 업로드하며, 재시작·네트워크 장애·일시적인 서버 오류에도 중단 없이 동작합니다. 업로드에 실패한 파일은 지수 백오프(exponential backoff)로 재시도되며, 주기적인 복구 스윕을 통해 크래시나 배포 도중 남겨진 파일도 다시 대기열에 올립니다. 결과적으로 내구성 있는 fire-and-forget 전송이 보장됩니다. 에이전트는 전속력으로 실행되고, collector가 이벤트 유실을 방지합니다. + +내부적으로 collector는 경량 데몬으로, Python SDK가 작성하는 `.jsonl` 파일을 `$AGENTEYE_HOME/events/`(기본값: `~/.agenteye/events/`)에서 감시하여 AgentEye 서버에 업로드합니다. + +> **이름 변경 안내:** collector 명령어가 **`agenteye-collector`**로 변경되었습니다(이전 이름: `agenteye`). 짧은 이름인 `agenteye`는 이제 AgentEye CLI에서 사용합니다. 기존 설치를 업그레이드하는 경우 [enterprise-docs/collector-migration.md](/ko/agenteye/collector-migration)를 참조하세요. + +--- + +## 사전 요구사항 + +- `AGENTEYE_TOKEN`: 직접 생성하는 GitHub PAT([enterprise-docs/github-token.md](/ko/agenteye/github-token) 참조) +- 서버 URL 및 collector API 키([enterprise-docs/api-keys.md](/ko/agenteye/api-keys) 참조) + +--- + +## 옵션 A: 바이너리 (권장) + +Linux, macOS, Windows(x86_64 및 arm64)용 사전 빌드된 정적 바이너리를 제공합니다. 최신 `collector/v` 릴리스 태그 아래의 `agenteye-enterprise/releases` 저장소에서 플랫폼에 맞는 바이너리를 직접 다운로드하세요. + +사용 가능한 아티팩트 이름: + +| 플랫폼 | 아티팩트 | +|---|---| +| Linux x86_64 | `agenteye-collector-linux-x86_64` | +| Linux arm64 | `agenteye-collector-linux-arm64` | +| macOS x86_64 | `agenteye-collector-darwin-x86_64` | +| macOS arm64 | `agenteye-collector-darwin-arm64` | +| Windows x86_64 | `agenteye-collector-windows-x86_64.exe` | +| Windows arm64 | `agenteye-collector-windows-arm64.exe` | + +**`gh` CLI로 다운로드** (버전을 교체하고 플랫폼에 맞는 아티팩트를 선택하세요): + +```bash +VERSION=0.0.1-beta.13 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "collector/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-collector-linux-x86_64' + +chmod +x agenteye-collector-linux-x86_64 +sudo mv agenteye-collector-linux-x86_64 /usr/local/bin/agenteye-collector +``` + +**또는 `curl`로 다운로드:** + +```bash +VERSION=0.0.1-beta.13 +ARTIFACT=agenteye-collector-linux-x86_64 +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + -L "https://github.com/agenteye-enterprise/releases/releases/download/collector%2Fv${VERSION}/${ARTIFACT}" \ + -o agenteye-collector +chmod +x agenteye-collector +sudo mv agenteye-collector /usr/local/bin/agenteye-collector +``` + +--- + +## 옵션 B: Docker + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +docker pull ghcr.io/agenteye-enterprise/collector:beta-latest +``` + +> 현재 베타 빌드는 부동 태그(floating tag)인 `:beta-latest`로 게시됩니다. `:latest`는 안정 릴리스에만 부여됩니다. 재현 가능한 배포를 위해 `:v0.0.1-beta.13`과 같이 특정 버전 태그를 고정해서 사용하는 것을 권장합니다. + +**실행:** + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-collector \ + -e AGENTEYE_URL=https://ingest.example.com/events \ + -e AGENTEYE_KEY="$AGENTEYE_KEY" \ + -e AGENTEYE_HOME=/data \ + -v "$HOME/.agenteye:/data" \ + ghcr.io/agenteye-enterprise/collector:beta-latest \ + start +``` + +공식 이미지는 비루트(non-root) 사용자로 실행되므로 `AGENTEYE_HOME`을 명시적으로 설정하고 호스트 스풀 디렉터리를 마운트해야 합니다. 볼륨 마운트는 호스트에서 Python SDK가 쓰는 `~/.agenteye/` 디렉터리를 공유합니다. 호스트에서 이미 `AGENTEYE_HOME`을 다른 경로로 설정한 경우, `$HOME/.agenteye` 대신 해당 디렉터리를 마운트하세요. + +--- + +## 설정 + +모든 옵션은 아래 세 가지 방법으로 설정할 수 있으며, 우선순위는 높은 것부터 낮은 순서입니다: + +1. CLI 플래그: `agenteye-collector start --url https://...` +2. 환경 변수: `AGENTEYE_URL=https://...` +3. 설정 파일: `~/.agenteye/config.json` + +### 필수 옵션 + +| 옵션 | CLI 플래그 | 환경 변수 | config.json 키 | +|---|---|---|---| +| 백엔드 URL | `--url ` | `AGENTEYE_URL` | `"url"` | +| API 키 | `--key ` | `AGENTEYE_KEY` | `"key"` | + +### 선택 옵션 (기본값 포함) + +| 옵션 | CLI 플래그 | 환경 변수 | config.json 키 | 기본값 | +|---|---|---|---|---| +| 최대 동시 업로드 수 | `--max-concurrent-uploads ` | `AGENTEYE_MAX_CONCURRENT_UPLOADS` | `"max_concurrent_uploads"` | `64` | +| 스윕 간격(초) | `--sweep-interval ` | `AGENTEYE_SWEEP_INTERVAL` | `"sweep_interval_secs"` | `60` | +| 스윕 최소 파일 나이(초) | `--sweep-min-age ` | `AGENTEYE_SWEEP_MIN_AGE` | `"sweep_min_age_secs"` | `120` | +| 스윕당 최대 파일 수 | `--sweep-max-files ` | `AGENTEYE_SWEEP_MAX_FILES` | `"sweep_max_files"` | `64` | +| 최대 업로드 시도 횟수 | `--max-retries ` | `AGENTEYE_MAX_RETRIES` | `"max_retries"` | `5` | +| 재시도 기본 지연(ms) | `--retry-base-delay ` | `AGENTEYE_RETRY_BASE_DELAY` | `"retry_base_delay_ms"` | `1000` | + +### mTLS 옵션 (선택) + +상호 TLS(mTLS)가 필요한 배포 환경에서 collector는 TLS 핸드셰이크 시 클라이언트 인증서를 제시할 수 있습니다. 이 옵션을 설정하지 않으면 collector는 표준 HTTPS를 사용합니다. + +| 옵션 | CLI 플래그 | 환경 변수 | config.json 키 | +|---|---|---|---| +| 클라이언트 인증서(PEM) | `--tls-cert ` | `AGENTEYE_TLS_CERT` | `"tls_cert"` | +| 클라이언트 개인 키(PEM) | `--tls-key ` | `AGENTEYE_TLS_KEY` | `"tls_key"` | +| 커스텀 CA 인증서(PEM) | `--tls-ca ` | `AGENTEYE_TLS_CA` | `"tls_ca"` | + +`--tls-cert`와 `--tls-key`는 반드시 함께 설정해야 합니다. 파일은 PEM 형식으로 인코딩되어야 합니다. + +`--tls-ca`는 독립적으로 사용할 수 있으며, AgentEye 서버가 공개적으로 신뢰받는 CA가 발급하지 않은 TLS 인증서(예: 실제 DNS 도메인 없이 클러스터 내 `cert-manager` 이슈어가 자체 서명한 인증서)를 사용할 때만 필요합니다. collector는 지정한 CA를 추가 신뢰 앵커로 추가하며, 기존 공개 루트 CA는 계속 신뢰되므로 기존 배포에는 영향이 없습니다. 파일에는 단일 PEM 인증서 또는 전체 체인(여러 PEM 블록을 연결한 형태) 모두 사용할 수 있습니다. + +**애플리케이션 파드의 사이드카로 collector를 실행하시나요?** AWS Secrets Manager + Secrets Store CSI Driver + IRSA를 통한 mTLS 번들 전달 및 자동 교체를 포함한 엔드투엔드 EKS 패턴은 [enterprise-docs/single-pod-deployment.md](/ko/agenteye/single-pod-deployment)를 참조하세요. + +Secret 핸드오프 패턴으로 Kubernetes에서 실행할 때, 인증서 Secret을 볼륨으로 마운트하고 해당 경로를 지정하세요: + +```yaml +# 예시: collector Deployment 스니펫 +volumes: + - name: mtls-certs + secret: + secretName: agenteye-collector-mtls +containers: + - name: collector + env: + - name: AGENTEYE_TLS_CERT + value: /etc/agenteye/tls/tls.crt + - name: AGENTEYE_TLS_KEY + value: /etc/agenteye/tls/tls.key + # 서버 인증서가 공개적으로 신뢰받지 않는 경우에만 설정 + # (예: 클러스터 내 자체 서명 CA). 동일한 Secret에 + # tls.crt/tls.key와 함께 ca.crt가 포함되는 경우가 많습니다. + - name: AGENTEYE_TLS_CA + value: /etc/agenteye/tls/ca.crt + volumeMounts: + - name: mtls-certs + mountPath: /etc/agenteye/tls + readOnly: true +``` + +### `~/.agenteye/config.json` 예시 + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "max_concurrent_uploads": 16, + "sweep_interval_secs": 30 +} +``` + +mTLS 적용 시: + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "tls_cert": "/etc/agenteye/tls/tls.crt", + "tls_key": "/etc/agenteye/tls/tls.key" +} +``` + +mTLS + 커스텀 CA(자체 서명 AgentEye 서버) 적용 시: + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "tls_cert": "/etc/agenteye/tls/tls.crt", + "tls_key": "/etc/agenteye/tls/tls.key", + "tls_ca": "/etc/agenteye/tls/ca.crt" +} +``` + +`AGENTEYE_HOME`이 설정된 경우 `~/.agenteye` 대신 해당 디렉터리가 사용됩니다. + +--- + +## 초기 설정 + +설치 후 서버 URL과 API 키로 collector를 설정합니다: + +```bash +mkdir -p ~/.agenteye +cat > ~/.agenteye/config.json <<'EOF' +{ + "url": "https://ingest.example.com/events", + "key": "YOUR_COLLECTOR_KEY" +} +EOF +``` + +> 신뢰할 수 없는 네트워크를 경유하는 모든 배포 환경에서는 `https`를 사용하여 이벤트가 평문으로 전송되지 않도록 하세요. 평문 형식인 `http://your-server-host:8080/events`는 동일 호스트에서 서버를 대상으로 순수 로컬 테스트를 할 때만 적합합니다. + +**연결 테스트** (일회성 플러시, 대기 중인 이벤트를 모두 전송한 후 종료): + +```bash +agenteye-collector flush +``` + +`flush`는 진행 상황을 stdout에 출력합니다. 스풀이 비어 있으면 `No pending files.`를 출력하고 `0`으로 종료합니다. 그렇지 않으면 파일별로 한 줄씩(`[UPLOADED] ` 또는 `[FAILED] ()`) 출력한 후, `Done: / uploaded, failed.` 요약을 출력합니다. 이를 통해 데몬을 시작하기 전에 URL, 키, TLS 설정이 올바른지 편리하게 확인할 수 있습니다. + +--- + +## 데몬으로 실행 + +### 직접 실행 + +```bash +agenteye-collector start +``` + +### 컨테이너 / Docker + +collector와 애플리케이션이 같은 컨테이너를 공유하는 경우, 프로세스 슈퍼바이저 아래에서 실행하세요. 가장 간단한 옵션은 `supervisord`입니다. 주요 배포판에 모두 포함되어 있으며, 크래시된 프로세스를 재시작하고, 시그널을 전달하며, 우아한 종료를 기다립니다. + +**`Dockerfile`:** + +```Dockerfile +FROM python:3.11-slim + +RUN apt-get update && apt-get install -y --no-install-recommends supervisor \ + && rm -rf /var/lib/apt/lists/* + +# 공식 이미지에서 agenteye-collector 바이너리를 가져옵니다. +# 특정 태그를 고정하세요 (현재 베타는 :beta-latest, 또는 :v 태그). +# :latest는 안정 릴리스에만 게시됩니다. +COPY --from=ghcr.io/agenteye-enterprise/collector:beta-latest \ + /usr/local/bin/agenteye-collector /usr/local/bin/agenteye-collector + +COPY supervisord.conf /etc/supervisor/conf.d/agenteye.conf +COPY my_agent.py /app/my_agent.py + +CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"] +``` + +**`supervisord.conf`:** + +```ini +[supervisord] +nodaemon=true +user=root + +[program:agenteye-collector] +command=/usr/local/bin/agenteye-collector start +autorestart=true +stopwaitsecs=30 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:app] +command=python /app/my_agent.py +autorestart=unexpected +stopwaitsecs=30 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +``` + +각 설정의 이유: + +- agenteye-collector의 `autorestart=true`: 어떤 이유로든 종료 시 재시작(크래시, 패닉, OOM 포함). +- 앱의 `autorestart=unexpected`: 비정상 종료 시에만 재시작하므로, 0으로 종료하는 일회성 에이전트가 반복 실행되지 않습니다. +- `stopwaitsecs=30`: SIGTERM 수신 후 supervisord가 SIGKILL로 에스컬레이션하기 전에 collector가 대기 중인 업로드를 처리할 시간을 줍니다. +- `stdout_logfile=/dev/stdout`, `*_maxbytes=0`: 두 프로그램의 출력을 컨테이너 stdout으로 스트리밍하며, 컨테이너 내부에 로그 파일을 생성하지 않습니다. + +`AGENTEYE_URL` / `AGENTEYE_KEY`(및 TLS 환경 변수)는 기존과 동일하게 `docker run -e`로 전달하세요. supervisord는 환경 변수를 상속합니다. + +> **컨테이너를 분리해서 실행하시나요?** collector를 별도 컨테이너(Docker Compose 서비스, Kubernetes 사이드카 등)로 실행하는 경우 supervisord를 사용하지 마세요. 컨테이너 런타임의 재시작 정책이 이미 그 역할을 담당합니다. EKS 사이드카 패턴은 [enterprise-docs/single-pod-deployment.md](/ko/agenteye/single-pod-deployment)를 참조하세요. + +**Kubernetes 활성 프로브(liveness probe)** (collector가 단독 또는 supervisord 아래에서 실행되는 경우 모두 적용): + +```yaml +livenessProbe: + exec: + command: ["agenteye-collector", "health"] + initialDelaySeconds: 10 + periodSeconds: 30 +``` + +실행 중인 데몬은 30초마다 `$AGENTEYE_HOME/health.json`에 하트비트를 기록합니다. `agenteye-collector health`는 해당 파일을 읽어, 하트비트가 최신 상태이고 업로드 태스크가 정상적으로 실행 중일 때만 `0`(정상)으로 종료합니다. 하트비트가 90초보다 오래된 경우(예: 데몬이 중지됨) 또는 예기치 않은 종료 후 watcher와 sweeper가 재시작 중인 경우에는 `1`(비정상)로 종료합니다. 하트비트는 `start`에서만 기록되므로, 일회성 `flush` 명령이 아닌 장시간 실행되는 데몬에 대해 프로브를 실행하세요. + +### systemd (Linux, 프로덕션 권장) + +```ini +# /etc/systemd/system/agenteye-collector.service +[Unit] +Description=AgentEye Collector +After=network.target + +[Service] +ExecStart=/usr/local/bin/agenteye-collector start +Restart=on-failure +RestartSec=5 +EnvironmentFile=/etc/agenteye/env + +[Install] +WantedBy=multi-user.target +``` + +`/etc/agenteye/env` 생성: + +``` +AGENTEYE_URL=https://ingest.example.com/events +AGENTEYE_KEY=YOUR_COLLECTOR_KEY +``` + +```bash +sudo systemctl daemon-reload +sudo systemctl enable --now agenteye-collector +sudo systemctl status agenteye-collector +``` + +### launchd (macOS) + +```xml + + + + + + Label + ai.befailproof.agenteye-collector + ProgramArguments + + /usr/local/bin/agenteye-collector + start + + EnvironmentVariables + + AGENTEYE_URL + https://ingest.example.com/events + AGENTEYE_KEY + YOUR_COLLECTOR_KEY + + RunAtLoad + + KeepAlive + + + +``` + +```bash +launchctl load ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +``` + +--- + +## Collector 업그레이드 + +collector는 자동으로 업데이트되지 않습니다. 업그레이드 방법: + +- **바이너리:** 최신 `collector/v` 릴리스에서 새 `agenteye-collector--` 아티팩트를 다운로드하고([옵션 A](#option-a-binary-recommended) 참조), `/usr/local/bin/agenteye-collector`를 교체한 후 서비스를 재시작합니다(`sudo systemctl restart agenteye-collector`, `launchctl load` 재실행, 또는 슈퍼바이저 재시작). +- **Docker:** `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest`(또는 고정된 `:v` 태그; `:latest`는 안정 릴리스에만 존재)를 실행하고 컨테이너를 재생성합니다. + +`AGENTEYE_TOKEN`은 비공개 릴리스 저장소에서 새 바이너리/이미지를 다운로드할 때 필요하지만, 실행 중인 데몬에는 **필요하지 않습니다**. + +--- + +## 서브커맨드 + +| 명령어 | 설명 | +|---|---| +| `agenteye-collector start` | 장시간 실행 데몬을 시작합니다. 시작 시 이전 실행에서 남은 이벤트를 플러시한 후, 새 파일을 감시하며 업로드합니다. watcher와 sweeper는 예기치 않은 종료 시 자동 재시작되며, 30초마다 `health.json`에 하트비트를 기록합니다. | +| `agenteye-collector flush` | 일회성 실행: 대기 중인 모든 파일을 업로드하고 종료합니다. 스풀이 비어 있으면 `No pending files.`를 출력하고, 그렇지 않으면 파일별 `[UPLOADED]`/`[FAILED]` 로그와 `Done: / uploaded, failed.` 요약을 출력합니다. | +| `agenteye-collector health` | 데몬의 `health.json` 하트비트를 읽습니다. 최신 상태이고 정상이면 `0`으로 종료하고, 하트비트가 오래되었거나(90초 초과) 태스크가 재시작 중이면 `1`로 종료합니다. | + +--- + +## 디렉터리 구조 + +``` +~/.agenteye/ +├── config.json <- 선택적 설정 파일 +├── events/ <- SDK가 작성하는 .jsonl 파일, collector가 처리 +└── failed/ <- 모든 업로드 시도에 실패한 파일 +``` + +`failed/`의 파일은 자동으로 재시도되지 않습니다. 수동으로 재대기열에 넣으려면 해당 파일을 `events/`로 이동한 후 `agenteye-collector flush`를 실행하세요. \ No newline at end of file diff --git a/docs/ko/agenteye/collector-migration.mdx b/docs/ko/agenteye/collector-migration.mdx new file mode 100644 index 00000000..40e76b1d --- /dev/null +++ b/docs/ko/agenteye/collector-migration.mdx @@ -0,0 +1,167 @@ +--- +title: "`agenteye-collector`로 마이그레이션" +description: "AgentEye `agenteye-collector`로의 마이그레이션 문서." +--- + +마이그레이션은 비파괴적입니다. 다운타임과 데이터 손실이 없으며, 짧은 `agenteye` 이름을 [AgentEye CLI](/ko/agenteye/cli)에 양도하여 컬렉터 데몬과 CLI가 동일한 머신에서 공존할 수 있게 됩니다. + +컬렉터 바이너리가 **`agenteye`에서 `agenteye-collector`로 이름이 변경되었습니다**. 짧은 `agenteye` 이름은 이제 AgentEye CLI에 속하며, 이는 터미널에서 세션, 이벤트, 평가를 조회하기 위한 별도의 도구입니다. + +이 가이드는 기존 컬렉터 설치를 마이그레이션하는 과정을 안내합니다. + +--- + +## 변경 사항 + +| | 변경 전 | 변경 후 | +|---|---|---| +| 커맨드 / 바이너리 | `agenteye` | `agenteye-collector` | +| 기본 설치 경로 | `/usr/local/bin/agenteye` | `/usr/local/bin/agenteye-collector` | +| 서브커맨드 | `start`, `flush`, `health`, `update` | `start`, `flush`, `health` | +| 자체 업데이트 (`agenteye update`) | 내장 기능 | **제거됨**: 새 바이너리를 다운로드하거나 새 이미지를 pull | +| 설치 스크립트 (`install.sh`) | 제공됨 | **제거됨**: 바이너리를 직접 다운로드 ([Collector Installation](/ko/agenteye/collector-installation) 참고) | +| `AGENTEYE_TOKEN` | 다운로드 **및** 백그라운드 업데이트 확인에 필요 | 바이너리/이미지 **다운로드**에만 필요 | + +설정은 변경되지 않습니다. 동일한 `~/.agenteye/config.json`, 동일한 `AGENTEYE_URL` / `AGENTEYE_KEY` / `AGENTEYE_HOME` / TLS 환경 변수, 그리고 동일한 `~/.agenteye/events/` 스풀을 그대로 사용합니다. **설정 파일을 수정할 필요가 없습니다.** + +> 이름이 변경된 바이너리를 이전 이름인 `agenteye`로 실행하면 여전히 동작하지만, stderr에 `agenteye-collector`로 전환하도록 안내하는 한 줄짜리 지원 중단 경고를 출력합니다. + +--- + +## 시작하기 전에 + +- **기존 `agenteye` 설치는 계속 실행됩니다.** 업그레이드 직후에도 아무것도 중단되지 않습니다. 신중하게 마이그레이션을 진행한 후 마지막에 이전 바이너리를 제거하세요. +- 다운타임을 피하려면 다음 순서를 따르세요: + 1. 새 `agenteye-collector` 바이너리를 설치합니다(또는 새 이미지를 pull). + 2. 서비스 정의 / 헬스 프로브 / 스크립트를 `agenteye-collector`를 호출하도록 업데이트합니다. + 3. 서비스를 리로드하고 재시작한 후 정상 상태를 확인합니다. + 4. **그런 다음에만** 이전 `/usr/local/bin/agenteye` 바이너리를 제거합니다. + +--- + +## 1. 새 바이너리 설치 + +플랫폼에 맞는 아티팩트(`agenteye-collector-linux-x86_64`, `agenteye-collector-darwin-arm64` 등; 전체 목록은 [Collector Installation → Option A](/ko/agenteye/collector-installation#option-a-binary-recommended) 참고)를 최신 `collector/v` 릴리스에서 다운로드하여 `/usr/local/bin/agenteye-collector`에 배치합니다. Docker 사용자: `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (또는 고정된 `:v` 태그 사용을 권장하며, `:latest`는 안정 릴리스에만 존재합니다). + +설치 확인: + +```bash +agenteye-collector --version +``` + +--- + +## 2. 배포 환경 업데이트 + +### systemd (Linux) + +`/etc/systemd/system/agenteye-collector.service`를 편집하여 `ExecStart`가 새 바이너리를 가리키도록 합니다: + +```ini +[Service] +ExecStart=/usr/local/bin/agenteye-collector start +``` + +그런 다음 리로드하고 재시작합니다: + +```bash +sudo systemctl daemon-reload +sudo systemctl restart agenteye-collector +sudo systemctl status agenteye-collector +``` + +### launchd (macOS) + +> **브랜드 이름 변경:** 기존 plist가 이전 경로인 +> `~/Library/LaunchAgents/host.exosphere.agenteye-collector.plist`에 있다면, +> 파일 이름을 `ai.befailproof.agenteye-collector.plist`로 변경하고 +> 파일 내부의 `Label` 값도 새 식별자로 변경한 후 리로드하세요. + +`~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist`에서 첫 번째 `ProgramArguments` 항목을 `/usr/local/bin/agenteye`에서 `/usr/local/bin/agenteye-collector`로 변경한 후 리로드합니다: + +```bash +launchctl unload ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +launchctl load ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +``` + +### supervisord + +`supervisord` 프로그램 블록에서 `command`를 새 바이너리로 설정합니다: + +```ini +[program:agenteye-collector] +command=/usr/local/bin/agenteye-collector start +``` + +그런 다음 `supervisorctl reread && supervisorctl update`를 실행합니다. + +### Docker / Kubernetes + +새 이미지를 pull합니다(`ghcr.io/agenteye-enterprise/collector:beta-latest` 또는 고정된 `:v` 태그 사용을 권장하며, `:latest`는 안정 릴리스에만 존재합니다). 이미지 엔트리포인트가 이미 `agenteye-collector`이므로, `start` 서브커맨드와 함께 기존 `docker run` 명령을 변경 없이 그대로 사용할 수 있습니다. + +**중요: 헬스 프로브를 업데이트하세요.** 바이너리 이름으로 실행하는 Kubernetes liveness/readiness 프로브(또는 `docker exec`)를 사용하는 경우, 커맨드를 `agenteye-collector`로 변경해야 합니다: + +```yaml +livenessProbe: + exec: + command: ["agenteye-collector", "health"] +``` + +새 이미지에는 `agenteye` 별칭이 포함되지 않으므로, 여전히 `agenteye`를 호출하는 프로브는 실패합니다. 새 이미지와 동일한 롤아웃에서 프로브를 업데이트하세요. + +### Cron / 수동 스크립트 + +`agenteye start|flush|health` 호출을 해당하는 `agenteye-collector start|flush|health` 커맨드로 교체합니다. **`agenteye update` cron 작업은 모두 삭제하세요.** 해당 서브커맨드는 더 이상 존재하지 않습니다([이후 업그레이드 방법](#upgrades-from-now-on) 참고). + +--- + +## 3. 이전 바이너리 제거 (마지막 단계) + +서비스가 `agenteye-collector`로 실행되고 정상 상태를 보고하면: + +```bash +sudo rm /usr/local/bin/agenteye +``` + +AgentEye CLI도 함께 사용하는 경우 이 단계가 특히 중요합니다. CLI는 자체적으로 `agenteye` 커맨드를 설치하며, 이전 컬렉터 바이너리가 `/usr/local/bin/agenteye`에 남아 있으면 `PATH`에서 `agenteye` 이름이 모호해집니다. + +--- + +## 이후 업그레이드 방법 + +컬렉터는 더 이상 자체 업데이트를 지원하지 않습니다. 업그레이드 방법: + +- **바이너리:** 플랫폼에 맞는 새 아티팩트(예: `agenteye-collector-linux-x86_64`; 전체 목록은 [Collector Installation → Option A](/ko/agenteye/collector-installation#option-a-binary-recommended) 참고)를 다운로드하여 `/usr/local/bin/agenteye-collector`를 교체한 후 서비스를 재시작합니다. +- **Docker:** `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (또는 고정된 `:v` 태그 사용을 권장하며, `:latest`는 안정 릴리스에만 존재합니다)를 실행한 후 컨테이너를 재생성합니다. + +`AGENTEYE_TOKEN`은 프라이빗 릴리스 저장소에서 다운로드하는 데 여전히 필요하지만, 실행 중인 데몬에서는 더 이상 필요하지 않습니다. + +--- + +## 확인 + +```bash +agenteye-collector --version # 새 바이너리가 PATH에 있는지 확인 +agenteye-collector health # 종료 코드 0 = 정상 +agenteye-collector flush # 대기 중인 이벤트를 전달하고 정상 종료 +``` + +이후 대시보드에 새 이벤트가 나타나는지 확인하세요. + +--- + +## 롤백 + +마이그레이션은 비파괴적입니다. 롤백이 필요한 경우, (아직 제거하지 않은 경우) 서비스 정의를 이전 `/usr/local/bin/agenteye` 바이너리로 다시 지정하고 재시작하세요. 이벤트 스풀과 설정은 공유되며 영향을 받지 않습니다. + +--- + +## 문제 해결 + +| 증상 | 원인 | 해결 방법 | +|---|---|---| +| 실행할 때마다 `warning: the collector binary is now agenteye-collector …` 출력 | 이전 `agenteye` 이름으로 바이너리를 호출하고 있음 | `agenteye-collector`를 사용하도록 변경하고, 서비스 파일과 스크립트를 업데이트하세요. | +| systemd 실패: `.../agenteye: No such file or directory` | `ExecStart`를 업데이트하기 전에 이전 바이너리를 제거했음 | `ExecStart=/usr/local/bin/agenteye-collector start`로 설정한 후 `sudo systemctl daemon-reload`를 실행하세요. | +| 이미지 업그레이드 후 Kubernetes 파드가 크래시 루프 | liveness 프로브가 여전히 `agenteye`를 실행하고 있음 | 프로브 커맨드를 `["agenteye-collector", "health"]`로 변경하세요. | +| `agenteye: command not found`, 하지만 `agenteye-collector`는 동작함 | 스크립트/별칭이 이전 이름을 참조하고 있음 | `agenteye-collector`로 업데이트하세요. | +| `agenteye`를 실행하면 컬렉터가 아닌 CLI가 시작됨 | AgentEye CLI가 설치되어 있으며 `agenteye`를 소유하고 있음 | 데몬에는 `agenteye-collector`를 사용하고, `/usr/local/bin/agenteye`에 남아 있는 이전 컬렉터 바이너리를 제거하세요. | \ No newline at end of file diff --git a/docs/ko/agenteye/deployment.mdx b/docs/ko/agenteye/deployment.mdx new file mode 100644 index 00000000..58cb9e4d --- /dev/null +++ b/docs/ko/agenteye/deployment.mdx @@ -0,0 +1,364 @@ +--- +title: "배포" +description: "AgentEye 배포 문서" +--- + +이 가이드는 프로덕션 환경에서 AgentEye 서버와 대시보드를 배포하는 방법을 다룹니다. + +--- + +## 아키텍처 개요 + +``` + [ AI agent machines ] [ Your infrastructure ] + + Python SDK + | writes JSONL +----------------------+ + v +--->| PostgreSQL 15+ | + agenteye-collector --HTTP--+ | | (relational store) | + | | +----------------------+ + v | + +--------+ | +----------------------+ + | Server |<------+--->| ClickHouse 24+ | + +--------+ | | (events / analytics) | + ^ | +----------------------+ + API | | + | | +----------------------+ + +-----------+ +- - >| Redis 7+ (optional) | + | Dashboard | +----------------------+ + +-----------+ +``` + +- **Server**: Rust HTTP 서비스. 이벤트 배치를 수신하여 ClickHouse에 기록하고, PostgreSQL에 관계형 상태를 유지합니다. +- **Dashboard**: Next.js 웹 앱. 서버 API를 통해서만 읽기/쓰기를 수행합니다. +- **agenteye-collector**: 서버 호스트가 아닌 에이전트 머신에 배포됩니다. +- **Postgres 15+**: **필수.** (멀티테넌트 릴리스에서 14에서 15로 상향됨. org-membership 스키마에서 컬럼 목록 `ON DELETE SET NULL` 외래 키를 사용하는데, 이는 Postgres 15+에서만 지원됩니다. 이 버전을 배포하기 전에 Postgres를 업그레이드하세요.) OLTP 상태를 저장합니다: `api_keys`, `users`, `sessions`, `evaluation_jobs` (큐), `dashboards`, `saved_queries`, `otp_codes`, 그리고 멀티테넌트 테이블 `orgs`, `org_memberships`, `org_settings`. +- **ClickHouse 24+**: **필수.** 수집된 모든 이벤트에 대한 분석 저장소입니다. 엔진: `ReplacingMergeTree`, 월별 파티션, `(session_id, ts, dedup_key)` 순서로 정렬됩니다. 서버는 `CLICKHOUSE_URL`을 통해 연결됩니다. 번들로 제공되는 `deploy/base/clickhouse/`는 성능이 최적화된 단일 노드 구성을 포함합니다. **멀티테넌트 요구사항:** 번들 구성은 SQL 접근 관리와 `users_without_row_policies_can_read_rows=false`를 활성화하여, 서버가 조직별로 읽기 전용 ClickHouse 사용자와 행 정책을 생성할 수 있도록 합니다(SQL 편집기와 AI 에이전트에 대한 엔진 수준의 격리 경계). 직접 ClickHouse 구성을 제공하는 경우 이 설정을 유지하세요(`deploy/base/clickhouse/configmap.yaml` 참조). +- **Redis 7+**: *선택 사항*인 공유 캐시 + 속도 제한 백엔드입니다. 서버와 대시보드 모두 `REDIS_URL`을 통해 연결합니다. 없는 경우 두 서비스 모두 Postgres 전용 경로로 자연스럽게 폴백합니다. 아래의 **Redis(선택 사항 캐시)** 섹션을 참조하세요. + +--- + +## 서버 + +### 이미지 가져오기 + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +docker pull ghcr.io/agenteye-enterprise/server:beta-latest +``` + +> 현재 빌드는 `beta-latest`로 게시됩니다. `latest`는 안정적인 릴리스에만 할당됩니다. 프로덕션 환경에서는 특정 `:v` 태그를 고정하세요. [사용 가능한 이미지 태그](#available-image-tags)를 참조하세요. + +### 환경 변수 + +| 변수 | 필수 여부 | 기본값 | 설명 | +|---|---|---|---| +| `DATABASE_URL` | 예 | 없음 | Postgres DSN. `postgres://` 스키마를 사용하는 표준 libpq 연결 문자열 형식. `?sslmode=require` 및 기타 libpq 파라미터를 지원합니다. 비밀번호에 `/`, `+`, `=` 문자가 포함되면 안 됩니다. URL 안전 비밀번호 생성에는 `openssl rand -hex`를 사용하세요. | +| `ADMIN_KEY` | 아니오 | 없음 | 부트스트랩 관리자 API 키. 매 시작 시 모든 권한으로 업서트됩니다. 값을 변경하고 재시작하여 순환할 수 있습니다. | +| `LISTEN_ADDR` | 아니오 | `0.0.0.0:8080` | 바인딩할 TCP 주소 | +| `MAX_BODY_BYTES` | 아니오 | `134217728` (128 MB) | 최대 요청 본문 크기 | +| `ADMIN_EMAIL` | 아니오 | 없음 | 부트스트랩 관리자 사용자 이메일. 매 시작 시 모든 권한으로 업서트되며 보호됨으로 표시됩니다. 대시보드/API를 통해 비활성화하거나 권한을 수정할 수 없습니다. 부트스트랩 관리자를 순환하려면 `ADMIN_EMAIL`을 변경하고 재시작하세요. 새 이메일이 보호됨으로 업서트되고, 이전 이메일은 데이터베이스에서 수동으로 초기화할 때까지 보호 상태를 유지합니다. | +| `ALLOWED_EMAILS` | 아니오 | 없음 (모두 차단됨) | 사용자 생성 및 로그인에 허용된 이메일의 쉼표로 구분된 목록. 정확한 주소(`user@example.com`)와 도메인 와일드카드(`*@example.com`)를 지원합니다. 설정하지 않으면 사용자를 생성하거나 로그인할 수 없습니다. **첫 번째 부트 시드 전용**: 첫 번째 부팅 시 기본 조직의 허용 목록을 시드합니다. 이후에는 각 조직의 [`//settings`](#operational-settings) 페이지가 진실의 원천이 되며, 이 환경 변수를 변경해도 효력이 없습니다. | +| `SMTP_HOST` | 아니오 | 없음 | OTP 이메일 발송을 위한 SMTP 서버 호스트명. 설정하지 않으면 OTP 코드가 stdout에 기록됩니다. | +| `SMTP_PORT` | 아니오 | `587` | SMTP 서버 포트 | +| `SMTP_USERNAME` | 아니오 | 없음 | SMTP 인증 사용자명 | +| `SMTP_PASSWORD` | 아니오 | 없음 | SMTP 인증 비밀번호 | +| `SMTP_FROM` | 아니오 | 없음 | OTP 이메일의 발신자 이메일 주소 | +| `SMTP_TLS` | 아니오 | STARTTLS | 명시적으로 비활성화하지 않는 한 STARTTLS가 사용됩니다. `false` 또는 `0`은 일반 텍스트(TLS 없음)로 전송하고, 설정하지 않은 경우를 포함한 다른 모든 값은 STARTTLS를 활성화합니다. | +| `DASHBOARD_URL` | 아니오 | 내장 기본값 | OTP 이메일 매직 링크 및 알림의 인시던트 매직 링크 생성에 사용되는 대시보드 원본 주소. 설정하지 않으면 내장 기본값으로 폴백하고(OTP의 경우에만 대시보드에서 파생된 요청 원본 주소로 먼저 폴백). 이메일과 Slack/인시던트 링크가 모두 대시보드를 가리키도록 도메인이 분리된 설정에서는 이 값을 설정하세요. 아래의 **이메일 매직 링크 URL** 참조. 대부분의 운영자는 설정할 필요가 없습니다. | +| `SESSION_TTL_SECS` | 아니오 | `86400` (24시간) | 대시보드 세션 지속 시간(초). **첫 번째 부트 시드 전용**: 첫 번째 배포 후 [`//settings`](#operational-settings)에서 조직별로 수정하세요. | +| `OTP_TTL_SECS` | 아니오 | `600` (10분) | OTP 코드 유효 기간(초). **첫 번째 부트 시드 전용**: 첫 번째 배포 후 [`//settings`](#operational-settings)에서 조직별로 수정하세요. | +| `REDIS_URL` | 아니오 | 없음 | 선택 사항인 공유 캐시 + 속도 제한 백엔드. 예: `redis://redis:6379/0`. 설정하면 서버는 인증된 API 키 조회, 대시보드의 `/models` 집계, 세션 목록, env 목록 패싯을 캐시합니다. 또한 OTP 요청 속도 제한을 Postgres COUNT에서 Redis INCR로 전환합니다. 설정하지 않거나 연결할 수 없으면 캐시 없이 실행됩니다(OTP 제한은 Postgres로 폴백, 나머지 캐시 호출은 진실의 원천으로 폴스루). 아래의 **Redis(선택 사항 캐시)** 참조. | +| `CLICKHOUSE_URL` | **예** | 없음 | ClickHouse 인스턴스의 기본 URL. 예: `http://clickhouse:8123`. 서버는 매 시작 시 이 데이터베이스에 이벤트 스키마를 적용하며, ClickHouse에 연결할 수 없으면 부팅을 거부합니다. 아래의 **ClickHouse(필수 분석 저장소)** 참조. | +| `CLICKHOUSE_DATABASE` | 아니오 | `agenteye` | ClickHouse 데이터베이스(스키마) 이름. 존재하지 않으면 서버가 시작 시 생성합니다. | +| `ORG_CH_SECRET` | 아니오(단일 테넌트) / **예(멀티 조직)** | 개발 기본값 | 각 조직의 테넌트별 ClickHouse 비밀번호를 파생하는 데 사용되는 HMAC 키. SQL 편집기와 AI 에이전트의 `run_query`는 조직 자체의 읽기 전용 ClickHouse 사용자로 실행되며, 해당 사용자의 행 정책이 엔진에서 테넌트 격리를 강제합니다. 단일 테넌트 배포는 내장된 개발 기본값으로 정상 부팅됩니다. **두 번째 조직을 프로비저닝하기 전에 강력하고 안정적인 값을 반드시 설정하세요.** `agenteye-orgctl org create` CLI는 내장된 개발 기본값에서 실행을 거부합니다. 값을 변경하면 다음 시작 시 부트 타임 조정이 자동으로 복구할 때까지 모든 조직의 ClickHouse 사용자가 고아 상태가 됩니다. 복제본 전체에서 비밀로 유지하고 변경하지 마세요. 조직 프로비저닝 자체는 운영자 전용입니다. 아래의 **조직(멀티테넌시)** 참조. | +| `DEFAULT_ORG_NAME` | 아니오 | `Default` | 내장된 기본 조직에 시드되는 표시 이름. **첫 번째 부트 시드 전용**이며, 조직이 아직 새로 마이그레이션된 일반 ID를 유지하는 동안에만 시작 시 적용된 후 무시됩니다. 조직 이름을 변경(`agenteye-orgctl org rename`)하면 해당 이름이 신뢰할 수 있는 값이 되고 이 환경 변수는 더 이상 효력이 없습니다. | +| `DEFAULT_ORG_SLUG` | 아니오 | `default` | 내장된 기본 조직의 URL 슬러그. 대시보드에서 조직이 위치하는 경로(`//…`). `DEFAULT_ORG_NAME`과 동일한 첫 번째 부트 전용/초기 상태 전용 시맨틱을 갖습니다. 1-40자의 소문자 영숫자로 구성되며 단일 내부 하이픈이 허용되고 [예약어](#organizations-multi-tenancy)는 사용할 수 없습니다. 잘못된 값은 무시됩니다(조직은 `default`를 유지). 단일 테넌트 설치를 배포 후 CLI 단계 없이 `/default` 대신 `/acme`와 같은 경로로 표시할 수 있습니다. | +| `RUST_LOG` | 아니오 | `info` | 로그 상세도 (`debug`, `warn`, `error`, `agenteye_server=trace`) | +| `EVALUATOR_ENDPOINT` | 아니오 | 없음 | 평가자 서비스의 기본 URL (예: `http://evaluator:9000`). 설정하지 않으면 전체 평가 파이프라인이 no-op이 됩니다. 큐 행이 기록되지 않고 워커도 실행되지 않습니다. [평가 스위트](/ko/agenteye/evaluation-suite) 참조. | +| `EVALUATOR_TOKEN` | 아니오 | 없음 | 평가자에게 `Authorization: Bearer `으로 전송됩니다. **평가자 서비스에 구성된 값과 동일해야 합니다.** 평가자가 토큰 없이 구성된 경우에만 선택 사항입니다. | +| `EVALUATOR_WORKERS` | 아니오 | `2` | 동시성: 평가를 디스패치하는 서버 인스턴스당 워커 태스크 수. 수평 확장된 여러 서버에서 안전하게 실행할 수 있습니다. | +| `EVALUATOR_CLAIM_BATCH` | 아니오 | `4` | 단일 워커가 틱당 클레임하는 최대 평가 수. 배치는 **동시에** 디스패치되므로 평가자 엔드포인트의 총 동시성은 `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH`입니다. | +| `EVALUATOR_POLL_IDLE_SECS` | 아니오 | `2` | 디스패치할 항목이 없을 때 워커가 디스패치 시도 사이에 대기하는 시간. | +| `EVALUATOR_POLLING_INTERVAL_SECS` | 아니오 | `10` | 평가자가 응답별 `next_poll_secs`를 반환하지 않고 `GET /config`에서 `default_poll_interval_secs`를 광고하지 않는 경우 `GET /evaluate/{id}` 폴링의 최종 폴백 주기(초). | +| `EVALUATOR_REQUEST_TIMEOUT_MS` | 아니오 | `30000` | 평가자에 대한 HTTP 요청당 타임아웃(밀리초). | +| `EVALUATOR_MAX_ATTEMPTS` | 아니오 | `5` | 이 횟수만큼 실패하면 평가가 최종 `error`(실패가 요청 타임아웃이었던 경우 `timeout`)로 기록됩니다. | +| `EVALUATOR_CONFIG_REFRESH_SECS` | 아니오 | `300` (5분) | 서버가 평가자로부터 `GET /config`를 다시 가져오는 주기. | +| `EVALUATOR_MAX_POLL_DURATION_SECS` | 아니오 | `3600` (1시간) | AgentEye가 세션을 `timeout`으로 종료하기 전까지 폴링 큐에 남아 있을 수 있는 최대 실시간 시간. 영원히 `pending`을 반환하는 평가자로부터 보호합니다. | +| `ALERT_WORKERS` | 아니오 | `1` | 동시성: 알림 규칙을 평가하는 서버 인스턴스당 워커 태스크 수. [알림](/ko/agenteye/alerts) 참조. | +| `ALERT_CLAIM_BATCH` | 아니오 | `16` | 단일 워커가 틱당 클레임하는 최대 알림 수. | +| `ALERT_POLL_IDLE_SECS` | 아니오 | `5` | 큐가 비었을 때 알림 워커가 대기하는 시간. | +| `ALERT_REQUEST_TIMEOUT_MS` | 아니오 | `15000` | 트리거 평가당 타임아웃(ClickHouse 쿼리 + 아웃바운드 채널 HTTP). | +| `ALERT_MAX_ATTEMPTS` | 아니오 | `5` | 지수 백오프 대신 정상 주기로 알림을 재예약하기 전 연속 일시적 실패 횟수. | +| `AUDIT_WORKERS` | 아니오 | `1` | 동시성: 감사를 실행하는 서버 인스턴스당 워커 태스크 수. [감사](/ko/agenteye/audits) 참조. | +| `AUDIT_CLAIM_BATCH` | 아니오 | `1` | 단일 워커가 틱당 클레임하는 최대 예정된 감사 수. 에이전트 조사는 긴 루프이므로 기본값은 1입니다. | +| `AUDIT_POLL_IDLE_SECS` | 아니오 | `30` | 예정된 감사가 없을 때 감사 워커가 대기하는 시간. | +| `AUDIT_REQUEST_TIMEOUT_MS` | 아니오 | `30000` | ClickHouse에 대한 정책 쿼리당 타임아웃(밀리초). | +| `AUDIT_LLM_TIMEOUT_MS` | 아니오 | `1440000` | AI 어시스턴트 서비스에 대한 에이전트 조사 호출의 타임아웃. 전체 에이전트 루프는 몇 분간 실행됩니다. 에이전트가 서버가 포기하기 전에 부분 결과를 반환할 수 있도록 에이전트 자체의 `AGENTEYE_AUDIT_TIMEOUT_MS`보다 높게 유지하세요. | +| `AUDIT_MAX_ATTEMPTS` | 아니오 | `5` | 지수 백오프 대신 정상 주기로 감사를 재예약하기 전 연속 일시적 실패 횟수. | +| `AGENTEYE_AGENT_URL` / `AGENTEYE_AGENT_TOKEN` | 아니오 | — | 감사의 에이전트 조사는 어시스턴트와 동일한 연결을 재사용하여 AI 어시스턴트 `agent` 서비스를 호출합니다. 따라서 이 두 값을 **서버**에도 설정하세요(번들 매니페스트/컴포즈에서 이미 설정됨). 둘 다 설정되면 감사에서 AI 조사가 실행됩니다. 하나라도 설정되지 않으면 감사는 **정책 전용**으로 실행됩니다(결정론적 SQL 정책 패스는 여전히 실행됨). 감사별 `llm_enabled` 플래그와 무관합니다. 에이전트에도 LLM이 구성되어 있어야 합니다. [assistant.md](/ko/agenteye/assistant) 참조. | + +**AI 어시스턴트 서비스 — 감사 + 샌드박스 설정.** 에이전트 조사와 인팟 Python 샌드박스는 **에이전트 서비스**(서버가 아님)에서 `AGENTEYE_AUDIT_*` 접두사로 모두 선택 사항으로 조정됩니다: + +| 변수 | 기본값 | 의미 | +|---|---|---| +| `AGENTEYE_AUDIT_MAX_STEPS` | `200` | 조사당 최대 에이전트 턴 수. | +| `AGENTEYE_AUDIT_TIMEOUT_MS` | `1200000` | 하나의 조사에 대한 실시간 타임아웃(20분). 서버의 `AUDIT_LLM_TIMEOUT_MS`보다 **낮게** 유지해야 합니다. | +| `AGENTEYE_AUDIT_MAX_CONCURRENCY` | `1` | 에이전트 파드당 동시 조사 수(채팅 어시스턴트 예산과 별개). | +| `AGENTEYE_AUDIT_SANDBOX_TIMEOUT_MS` / `_MEM_MB` / `_CPU_SECS` / `_OUTPUT_MAX_BYTES` / `_SCRIPT_MAX_BYTES` | `20000` / `768` / `10` / `64000` / `64000` | bubblewrap 샌드박스에 대한 스크립트당 제한. | + +**샌드박스 플랫폼 요구사항.** 감사 코드 샌드박스는 bubblewrap 감옥 내에서 모델의 Python을 실행하며, **비권한 사용자 네임스페이스**가 필요합니다. 에이전트 파드는 `clone()` 플래그를 허용해야 합니다. k8s에서는 `seccompProfile: Unconfined`를, 컴포즈에서는 `security_opt: [seccomp:unconfined]`를 에이전트에 설정하세요. 노드 커널이 비권한 사용자 네임스페이스를 비활성화한 경우(예: 일부 GKE COS 이미지), 샌드박스 **프리플라이트가 실패하고 감사자는 자동으로 SQL 전용으로 저하됩니다.** 오류 없이 에이전트의 `/health`에 `sandbox_available: false`만 표시됩니다. + +### 실행 + +환경에서 `DATABASE_URL`과 `CLICKHOUSE_URL`을 설정하고(서버는 ClickHouse 없이 부팅을 거부합니다), 컨테이너로 전달하세요: + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-server \ + -e DATABASE_URL="$DATABASE_URL" \ + -e CLICKHOUSE_URL="$CLICKHOUSE_URL" \ + -e ADMIN_KEY="$ADMIN_KEY" \ + -p 8080:8080 \ + ghcr.io/agenteye-enterprise/server:beta-latest +``` + +서버는 시작 시 데이터베이스 마이그레이션을 자동으로 실행합니다. 별도의 마이그레이션 단계가 필요하지 않습니다. + +### 헬스 체크 + +``` +GET /health # liveness - always {"status":"ok"} once the process is up +GET /ready # readiness - 200 when Postgres + ClickHouse are reachable, else 503 +``` + +인증이 필요하지 않습니다. **활성(liveness)** 프로브에는 `/health`를, **준비(readiness)**/로드 밸런서 프로브에는 `/ready`를 사용하세요. `/ready`는 서버가 서비스를 제공할 수 없는 하드 의존성(Postgres + ClickHouse)을 확인합니다. 따라서 실행 중이지만 데이터베이스에 연결할 수 없는 서버는 로테이션에서 제외되고 `NotReady`로 표시됩니다. Redis는 보고되지만 준비 상태 실패를 유발하지 않습니다. 번들로 제공되는 Kubernetes 매니페스트에서 준비 프로브는 이미 `/ready`를 가리키고 활성 프로브는 `/health`를 유지합니다. Slack으로의 선택적 Kubernetes 네이티브 파드 실패 알림을 포함한 전체 내용은 [enterprise-docs/health-monitoring.md](/ko/agenteye/health-monitoring)를 참조하세요. + +### 이메일 매직 링크 URL + +OTP 로그인 이메일에는 **대시보드 열기** 원탭 버튼이 포함됩니다. 클릭하면 사용자가 `/login?token=&email=
`로 이동하고, 대시보드는 해당 쌍을 세션으로 교환하여 앱으로 리디렉션합니다. 코드를 수동으로 다시 입력할 필요가 없습니다. 서버는 링크 생성에 사용되는 대시보드 원본 주소를 세 단계로 결정합니다: + +1. **`X-AgentEye-Dashboard-Url` 헤더**: 대시보드의 `/api/auth/otp/request` 프록시가 자체 공개 원본 주소에서 자동으로 설정합니다. 동일 원본 배포(서버와 대시보드가 프록시 헤더를 전달하는 하나의 인그레스 뒤에 있는 경우)에서는 **구성이 필요하지 않습니다.** +2. **`DASHBOARD_URL` 환경 변수**: 대시보드가 서버의 OTP 요청 엔드포인트가 보는 원본 주소와 다른 원본 주소(`api.example.com` / `app.example.com` 분리)로 접근 가능한 경우, 또는 인그레스가 공개 호스트를 대시보드 파드로 전파하지 않는 경우(`request.nextUrl.origin`이 `0.0.0.0:3000`과 같은 와일드카드 바인드로 해석될 수 있음) 이 값을 설정하세요. 예: `DASHBOARD_URL=https://app.example.com`. +3. **기본값**: `https://app.befailproof.ai`. 위의 두 가지가 모두 없는 경우에만 사용됩니다. + +헤더 값이 검증됩니다. `https://*` 및 루프백(`http://localhost*`, `http://127.0.0.1*`) 원본만 허용되며, `https://` 스키마가 있더라도 와일드카드 바인드 주소(`0.0.0.0`, `[::]`)는 거부됩니다. 그 외의 경우는 2단계로 폴스루됩니다. + +파일이나 kustomize 재빌드 없이 원라이너로 실행 중인 클러스터에 설정하세요: + +```bash +kubectl set env deployment/server -n agenteye \ + DASHBOARD_URL=https://app.example.com +``` + +이렇게 하면 롤아웃이 트리거되고 새 파드가 첫 번째 요청 시 값을 가져옵니다. 재정의는 Deployment에만 존재합니다. 이후에 오버레이에 대해 `kustomize build | kubectl apply`를 실행하면 동일한 환경 변수를 오버레이의 `server-env.yaml` 패치에 추가하지 않는 한 이 값이 지워집니다. + +--- + +## 대시보드 + +### 이미지 가져오기 + +```bash +docker pull ghcr.io/agenteye-enterprise/dashboard:beta-latest +``` + +### 환경 변수 + +| 변수 | 필수 여부 | 기본값 | 설명 | +|---|---|---|---| +| `AGENTEYE_SERVER_URL` | 예 | 없음 | 서버의 기본 URL. 예: `http://localhost:8080` | +| `AGENTEYE_API_KEY` | 예 | 없음 | 대시보드가 서버 인증에 사용하는 API 키. 모든 권한이 필요합니다(관리자 키 권장). | +| `AE_LOG_LEVEL` | 아니오 | `info` | 서버 측 로그 상세도: `debug`, `info`, `warn`, `error`. 문제 진단 시 업스트림 요청/응답 줄과 세션 검증 추적을 보려면 `debug`로 설정하세요. | +| `AE_LOG_JSON` | 아니오 | 자동 | `1`은 JSON 한 줄 출력 강제, `0`은 사람이 읽을 수 있는 출력 강제. 설정하지 않으면 `NODE_ENV=production`인 경우 JSON이 자동으로 활성화됩니다. 프로덕션에서는 `jq`나 로그 집계기로 깔끔하게 파싱할 수 있도록 JSON을 권장합니다. | +| `AE_ANALYTICS_DISABLED` | 아니오 | 없음 | `1`/`true`로 설정하면 대시보드의 익명 제품 사용 텔레메트리가 비활성화됩니다. 아래의 [텔레메트리 및 개인정보 보호](#telemetry--privacy) 참조. | +| `REDIS_URL` | 아니오 | 없음 | 선택 사항인 공유 캐시 백엔드. 예: `redis://redis:6379/0`. 설정하면 대시보드는 복제본 전체에서 `validateSession()` 결과를 캐시하고 지연 집계/env 목록 프록시 라우트에 대한 Next.js 페치 캐시를 공유합니다. 엣지 OTP 요청 및 검증 속도 제한도 Redis가 있으면 Redis를 사용합니다(Redis에 연결할 수 없으면 열린 상태로 실패하며, 서버 측 제한이 보안 백스톱). 아래의 **Redis(선택 사항 캐시)** 참조. | +| `AGENTEYE_AGENT_URL` | 아니오 | 없음 | 선택 사항인 AI 어시스턴트 `agent` 서비스의 기본 URL. 예: `http://agent:9100`. **어시스턴트를 완전히 숨기려면 설정하지 마세요.** 대시보드에 어시스턴트 버블이 나타나지 않습니다. [enterprise-docs/assistant.md](/ko/agenteye/assistant) 참조. | +| `AGENTEYE_AGENT_TOKEN` | 아니오 | 없음 | 대시보드가 `agent` 서비스에 제공하는 공유 비밀. 에이전트에 구성된 `AGENTEYE_AGENT_TOKEN`과 일치해야 합니다. [enterprise-docs/assistant.md](/ko/agenteye/assistant) 참조. | + +### 실행 + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-dashboard \ + -e AGENTEYE_SERVER_URL="http://your-server-host:8080" \ + -e AGENTEYE_API_KEY="$ADMIN_KEY" \ + -p 3000:3000 \ + ghcr.io/agenteye-enterprise/dashboard:beta-latest +``` + +### 텔레메트리 및 개인정보 보호 + +대시보드는 **익명 제품 사용 분석**을 Exosphere의 분석 서비스(PostHog)로 전송합니다. 대시보드 페이지 조회 및 API 키 생성이나 세션 재평가 같은 일부 UI 액션이 포함됩니다. 이 사용 신호는 기능 우선순위 결정에 활용됩니다. + +- **에이전트, 세션 또는 이벤트 데이터는 인프라 외부로 전혀 전송되지 않습니다.** 오직 대시보드 UI 사용만 보고됩니다. 페이지 URL은 전송 전에 식별자가 제거되며, 운영자는 이메일이 아닌 불투명한 내부 ID로만 식별됩니다. +- 텔레메트리는 **기본적으로 활성화**되어 있습니다. 완전히 끄려면 대시보드 컨테이너에 `AE_ANALYTICS_DISABLED=1`을 설정하고 재시작하세요. +- 분석은 대시보드의 `/ingest` 경로로 전송되며, 대시보드는 이를 PostHog(`https://us.i.posthog.com`)로 역방향 프록시합니다. 요청을 퍼스트 파티로 유지하면 브라우저 광고 차단기가 차단하지 않습니다. **대시보드 컨테이너**는 PostHog에 대한 아웃바운드 액세스가 필요합니다. 차단된 경우 텔레메트리는 조용히 아무것도 하지 않고 대시보드는 영향을 받지 않습니다. + +--- + +## AI 어시스턴트 (선택 사항) + +인대시보드 AI 어시스턴트를 통해 팀원들이 자연어로 에이전트 데이터에 대한 질문을 할 수 있습니다(세션 요약, `/queries` 편집기를 위한 SQL 초안 작성, 저장된 쿼리를 대시보드 타일로 변환). 대시보드를 떠날 필요가 없으며, 대시보드만 접근할 수 있는 별도의 내부 `agent` 컨테이너(Claude Agents SDK 기반)로 실행됩니다. **LLM 엔드포인트를 구성할 때까지 비활성화 상태입니다.** + +활성화하려면 `agent` 서비스에 LLM 연결(**Portkey**: `PORTKEY_API_KEY` + 모델 카탈로그 슬러그 `AGENTEYE_AGENT_MODEL=@/`, 직접 Anthropic: `ANTHROPIC_API_KEY`, 다른 게이트웨이: `ANTHROPIC_BASE_URL`, 또는 Bedrock/Vertex), **전용** 데이터 키, 그리고 대시보드와 일치하는 공유 `AGENTEYE_AGENT_TOKEN`을 설정합니다. 대시보드 사용자는 추가로 `agent:use` 권한이 필요합니다. + +어시스턴트의 데이터 키는 직접 생성하지 않아도 됩니다. 랜덤 비밀을 선택하여 `agent`에 `AGENTEYE_API_KEY`로 설정하고 `server`에 `AGENT_API_KEY`로 설정하면, 서버가 시작 시 고정된 권한 세트로 시드합니다. 데이터 접근은 읽기 전용(`events:read`, `evaluations:read`, `dashboards:read`, `queries:read`)이며, 승인 게이트 작성 범위(`dashboards:write`, `queries:write`, `queries:run`)도 보유하여 사용자를 대신해 저장된 쿼리를 초안 작성/검증하고 대시보드 타일을 빌드할 수 있습니다. 모든 SQL은 여전히 조직의 읽기 전용 ClickHouse 역할을 통해 실행되므로, 어시스턴트가 작성할 수 있는 범위가 넓어지는 것이지 접근할 수 있는 데이터 범위가 넓어지는 것은 아닙니다. 범위는 코드에서 고정되며 구성으로 확장할 수 없습니다. 해당 키는 보호됩니다. API를 통해 비활성화하거나 재생성할 수 없으며, 값을 변경하고 재시작하여 순환할 수 있습니다. 이 용도로 관리자/대시보드 키를 재사용하지 마세요. + +전체 설정, 완전한 환경 변수 레퍼런스, 텔레메트리 옵션, 보안 모델은 **[enterprise-docs/assistant.md](/ko/agenteye/assistant)**에 있습니다. + +--- + +## ClickHouse (필수 분석 저장소) + +ClickHouse는 높은 이벤트 볼륨에서도 대시보드의 응답성을 유지하고, `/queries` SQL 편집기가 이벤트, 평가, 세션을 단일 저장소에서 조인할 수 있게 합니다. 수집된 모든 이벤트, 모든 최종 평가 결과, 파생된 세션별 집계에 대한 필수 정규 저장소입니다. PostgreSQL은 관계형/가변 상태 테이블(api_keys, users, otp_codes, evaluation_jobs, dashboards, saved_queries)을 보유하고, 분석 표면은 ClickHouse에 있어 대시보드 롤업과 사용자 정의 SQL 쿼리가 크로스 데이터베이스 라운드트립 없이 기본적으로 스캔하고 조인할 수 있습니다. 서버는 `CLICKHOUSE_URL` 없이 부팅을 거부합니다. + +### 스키마 + +서버 시작 시 세 개의 ClickHouse 객체가 생성됩니다. 모두 멱등적입니다(`CREATE IF NOT EXISTS`): + +- **`agenteye.events`**: `ReplacingMergeTree(ingested_at)`, `toYYYYMM(ts)`로 파티션됨, `(session_id, ts, dedup_key)` 순서로 정렬됨. 중복 삽입(콜렉터 재시도)은 병합 시 단일 행으로 합쳐집니다. 서버는 모든 이벤트에 대해 결정론적 SHA-256 `dedup_key`를 계산하므로 재시도가 안전합니다. +- **`agenteye.evaluations`**: `ReplacingMergeTree(ingested_at)`, `toYYYYMM(finished_at)`로 파티션됨, `(session_id, finished_at, dedup_key)` 순서로 정렬됨. 평가자 파이프라인이 최종 평가 결과마다 한 번 기록합니다. `events`와 동일한 dedup 키 모델. +- **`agenteye.agent_sessions`**: 물리적 테이블이 아닌 `agenteye.events`에 대한 **뷰**. 모든 컬럼이 파생됩니다(`started_at = min(ts)`, `last_event_at = max(ts)`, `ended_at = max(if event_type='agent_end', ts, NULL)`, `event_count = count()` 등). 이벤트별 업서트나 별도 백필 없이 뷰가 `events`의 내용을 자동으로 반영합니다. + +`analytics.evaluations` / `analytics.sessions`를 참조하는 저장된 쿼리와의 하위 호환성을 위해 서버는 `agenteye.*` 테이블 위에 뷰가 있는 `analytics` ClickHouse 데이터베이스도 생성합니다. `analytics.events`, `analytics.evaluations`, `analytics.agent_sessions`, `analytics.sessions`가 모두 올바르게 해석됩니다. + +### 구성 + +번들로 제공되는 docker-compose와 `deploy/base/clickhouse/`는 AgentEye의 워크로드에 최적화된 ClickHouse 서비스를 포함합니다: + +- 번들 기본 오버레이에서 2 GiB 요청 / 4 GiB 제한 메모리(작은 POC/스테이징 노드에 맞게 조정됨). 프로덕션 고객은 오버레이를 조정해야 합니다. 권장 최솟값은 2c / 4Gi 요청, 6c / 8Gi 제한입니다. `max_server_memory_usage_to_ram_ratio=0.9` +- 5 GiB 마크 캐시 + 8 GiB 비압축 캐시 +- `background_pool_size=16`, `background_merges_mutations_concurrency_ratio=2` +- MergeTree: `parts_to_throw_insert=3000`, `parts_to_delay_insert=1500`, `non_replicated_deduplication_window=1000` +- `local_io_method=auto` (지원되는 커널에서 io_uring) +- `fsync_metadata=0`: 최소 1회 이상 수집 + ReplacingMergeTree dedup으로 인해 허용됨 +- `query_log`은 30일 TTL로 활성화됨. `query_thread_log`는 제거됨(높은 QPS에서 비용이 많이 듦) +- 사용자 측 쿼리에 대한 `max_execution_time=30` +- StatefulSet 템플릿에 100 GiB PVC(고객 오버레이는 프로덕션에서 빠른 SSD 스토리지 클래스로 재정의해야 함) + +### 백업 + +전체 데이터셋은 매일 밤 단일 복원 가능한 아카이브로 캡처되므로, 클러스터 또는 스토리지 손실 시 복구할 수 있습니다. ClickHouse는 일일 `agenteye-backup` CronJob에 의해 자동으로 백업됩니다. 이 CronJob은 PostgreSQL과 ClickHouse를 한 번에 덤프합니다. ClickHouse는 HTTP API를 통해 읽힙니다. `agenteye.events`와 `agenteye.evaluations`는 ClickHouse 네이티브 형식으로 덤프되며(뷰와 행 정책은 서버 시작 시 재생성되므로 테이블 데이터가 완전한 그림), Postgres 덤프와 함께 단일 압축 아카이브로 번들되어 객체 스토리지에 업로드됩니다. + +대상 버킷과 클라우드 자격 증명은 오버레이별로 구성됩니다. 업로드 구성 및 복원 단계는 [enterprise-docs/kubernetes-deployment.md](/ko/agenteye/kubernetes-deployment)의 **백업** 섹션을 참조하세요. + +--- + +## Redis (선택 사항 캐시) + +Redis는 서버와 대시보드가 사용하는 **선택 사항**인 공유 캐시 + 속도 제한 백엔드입니다. Redis를 배포하고 두 서비스 모두에 `REDIS_URL`을 설정하면: + +- **서버**는 인증된 API 키 조회, `/events/environments` + `/evaluations/environments` 목록, `/events/latency_aggregate` 롤업(대시보드가 폴링하는 가장 무거운 쿼리), `/sessions` 목록을 캐시하고, OTP 요청 속도 제한을 Postgres `COUNT(*)`에서 Redis `INCR + EXPIRE`로 전환합니다. +- **대시보드**는 `validateSession()` 결과를 캐시하여 일반적인 페이지 로드에서 발생하는 10-20개의 인증된 API 호출이 하나의 업스트림 세션 확인을 공유합니다. 또한 대시보드 엣지에서 OTP 요청 및 검증 속도를 제한합니다. + +**Redis에 연결할 수 없으면 두 서비스 모두 자연스럽게 저하됩니다.** 모든 캐시 호출은 제한된 타임아웃 내에 `Err`를 반환하고, 호출자는 진실의 원천으로 폴백합니다(서버는 Postgres, 대시보드는 업스트림 Rust 서버). OTP 속도 제한은 서버의 Postgres `COUNT(*)` 경로로 폴백합니다(보안 속성 유지). 대시보드의 엣지 OTP 제한은 열린 상태로 실패하지만 서버 측 제한은 여전히 유효합니다. Redis 다운 시 정확성이 아닌 지연 시간이 저하됩니다. + +### 구성 + +docker-compose 번들에는 이미 Redis 서비스가 포함되어 있으며, 서버와 대시보드에 `REDIS_URL=redis://redis:6379/0`이 연결됩니다. 외부 Redis를 사용하려면 `REDIS_URL`을 엔드포인트로 설정하고 컴포즈 파일에서 `redis` 서비스를 제거하세요. + +### 메모리 + 지속성 + +번들 Redis 이미지는 `--appendonly yes --appendfsync everysec --maxmemory 256mb --maxmemory-policy allkeys-lru`로 실행됩니다. AOF 지속성은 컨테이너 재시작 후에도 캐시가 유지됨을 의미합니다. `everysec`는 마지막 1초의 캐시 쓰기 손실이 무해하기 때문에 올바른 내구성/성능 균형입니다. LRU 제거는 메모리 증가를 제한합니다. + +### Redis를 배포하지 않아야 할 때 + +- 단일 인스턴스 개발/QA 환경. 서버의 인프로세스 캐시만으로도 복제본당 이점의 대부분을 제공합니다. Redis는 단일 인스턴스 설정에서는 필요하지 않은 크로스 복제본 공유를 추가합니다. +- 서비스 하나를 더 운영하는 비용이 지연 시간 이점보다 큰 에어갭 설치 환경. + +--- + +## Docker Compose (권장) + +`docker-compose.yml`은 `agenteye-enterprise/releases` 저장소에서 사용할 수 있습니다. 단일 명령으로 Postgres, ClickHouse, Redis, 서버, 대시보드를 시작합니다. + +```bash +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download \ + --repo agenteye-enterprise/releases \ + --pattern 'docker-compose.yml' \ + --dir ./agenteye +cd agenteye +``` + +**`.env`를 통해 기본값 재정의:** + +``` +# Use URL-safe passwords (no /, +, or = characters). +# Generate with: openssl rand -hex 24 +POSTGRES_PASSWORD=your-db-password +ADMIN_KEY=your-admin-secret + +# Dashboard authentication +ADMIN_EMAIL=admin@yourcompany.com +ALLOWED_EMAILS=*@yourcompany.com + +# SMTP for OTP emails (omit to log OTP codes to stdout) +# SMTP_HOST=smtp.yourprovider.com +# SMTP_PORT=587 +# SMTP_USERNAME=your-smtp-user +# SMTP_PASSWORD=your-smtp-password +# SMTP_FROM=noreply@yourcompany.com + +RUST_LOG=info +``` + +```bash +docker compose up -d +``` + +**중지(데이터 볼륨 유지):** + +```bash +docker compose down +``` + +**중지 및 모든 데이터 삭제:** + +```bash +docker compose down -v +``` + +--- + +## 운영 설정 + +환경 변수로 고정되던 일부 운영 설정은 이제 대시보드의 **`//settings`** 페이지에서 조직별로 편집할 수 있습니다. 각 조직이 독립적으로 구성합니다. 변경 사항은 재시작이나 재배포 없이 수 초 내에 적용됩니다. + +| 설정 | 부트스트랩 환경 변수 | 제어 대상 | +|---|---|---| +| 허용된 로그인 | `ALLOWED_EMAILS` | OTP를 받고 사용자로 추가될 수 있는 이메일(또는 `*@domain.com` 와일드카드) | +| 기본 사용자 권한 | `DEFAULT_USER_PERMISSIONS` | 관리자가 **+ new user**를 열 때 미리 선택되는 쉼표로 구분된 권한 토큰. 각 토큰은 [API 키 권한](/ko/agenteye/api-keys)에 나열된 문자열 중 하나여야 합니다. 기본값은 `standard` 프리셋: 읽기 전용 접근 및 일상적인 온콜 액션(재평가 트리거, 쿼리 실행, 인시던트 확인, 어시스턴트 사용). | +| 세션 수명 | `SESSION_TTL_SECS` | 재인증 전까지 대시보드 로그인 유효 기간. 대시보드는 매 5초마다 업스트림 세션을 재확인하므로, `//users`에서의 권한 업데이트는 재로그인 없이 다음 요청에서 해당 사용자에게 적용됩니다. | +| 일회용 코드 수명 | `OTP_TTL_SECS` | OTP/매직 링크 사용 가능 기간 | +| 알림 채널 | `ALERTS_ENABLED_CHANNELS` | 알림 디스패처가 사용할 수 있는 채널 종류의 쉼표 구분 목록: `email`, `slack`, `webhook`. 알림별 구성은 여전히 `//alerts/`에서 작성되지만, 디스패처는 이 세트를 통해 모든 아웃바운드 전달을 필터링합니다. 여기서 비활성화된 채널은 `skipped_disabled` 감사 행으로 단락됩니다. `dashboard` 채널(로컬 감사 삽입)은 항상 허용됩니다. 기본값은 세 채널 모두 활성화. | + +### 부트스트랩 동작 방식 + +설정은 `org_settings`에 조직별로 저장됩니다. 첫 번째 부팅 시 서버는 일치하는 환경 변수(또는 환경 변수가 설정되지 않은 경우 적절한 기본값)에서 기본 조직의 누락된 행을 시드합니다. 이후에는 **저장된 값이 진실의 원천이 되며 환경 변수는 무시됩니다.** 이후 재시작 시 환경 변수를 변경해도 라이브 조직의 값에 영향을 주지 않으며, 추가 조직은 기본값에서 시작하여 독립적으로 구성합니다. + +이는 다음을 의미합니다: + +- 새로운 배포에서는 위에 표시된 대로 환경 변수를 설정하면 기본 조직이 첫 번째 부팅 시 읽습니다. +- 나중에 값을 변경하려면 대시보드에 로그인하여 `//settings`에서 편집하세요. 변경 사항은 모든 서버 복제본에 수 초 내에 적용됩니다. 재시작이 필요하지 않습니다. +- 시작 로그 줄에 시드된 항목과 이미 존재하는 항목이 기록되어 부트스트랩이 적용되었는지 확인할 수 있습니다: + + ```text + INFO settings bootstrap: seeded default-org row key=allowed_sign_ins env_var=ALLOWED_EMAILS seeded_from_env=true + ``` + +#### 조직 간 로그인 시맨틱 + +세션과 OTP는 단일 조직이 아닌 사용자 전체에 적용되므로, 로그인 시 조직별 설정을 조정하는 두 가지 규칙이 있습니다: + +- **세션/OTP 수명**: 사용자가 속한 조직 중 가장 엄격한(가장 짧은) 수명이 적용됩니다. +- **허용된 로그인**: 게이트는 모든 조직의 허용 목록과 조직 멤버십을 OR로 결합합니다. 어떤 조직의 허용 목록이 이메일을 허용하거나 사용자가 이미 어떤 조직의 멤버인 경우 OTP를 요청할 수 있습니다. + +### 권한 + +`//settings` 페이지 접근은 두 가지 권한으로 제어됩니다: + +- `settings:read`: 페이지 및 현재 값 보기. +- `settings:write`: 변경 사항 저장. + +부트스트랩 관리자(`ADMIN_EMAIL`에서 시드됨)는 다른 모든 권한과 함께 두 권한을 자동으로 받습니다. 필요에 따라 `//users`에서 다른 사 \ No newline at end of file diff --git a/docs/ko/agenteye/evaluation-suite.mdx b/docs/ko/agenteye/evaluation-suite.mdx new file mode 100644 index 00000000..4fa6d38b --- /dev/null +++ b/docs/ko/agenteye/evaluation-suite.mdx @@ -0,0 +1,447 @@ +--- +title: "Evaluation Suite" +description: "AgentEye Evaluation Suite 문서." +--- + +AgentEye는 완료된 에이전트 세션을 평가하기 위해 전체 이벤트 트랜스크립트를 +**고객이 소유한 단일 평가자 서비스**에 POST 요청으로 전송합니다. 평가자는 결과를 +인라인으로 반환하거나, AgentEye가 폴링할 수 있는 `job_id`를 돌려주는 방식으로 응답합니다. +결과는 저장되어 대시보드에 표시됩니다. + +이 가이드에서 다루는 내용: + +1. 세션 완료 감지 방법 +2. 평가자가 구현해야 하는 HTTP 계약 +3. AgentEye 서버 구성 +4. 결과 확인 +5. 문제 해결 + +계약을 대신 구현해 주는 Python 헬퍼에 대해서는 +[PyPI의 `agenteye-evaluator` 패키지](https://pypi.org/project/agenteye-evaluator/)를 참고하세요. + +--- + +## 동작 방식 + +```text +ingest /events ──▶ AgentEye ──── POST /evaluate ────▶ Evaluator service + (agent_end) server ◀──── done | pending ──── + │ + │ GET /evaluate/{job_id} ─────▶ + │ ◀──── done ────────────── + ▼ + evaluations (terminal results) +``` + +AgentEye SDK가 세션에 대한 `agent_end` 이벤트를 발생시키면, 서버가 평가를 예약합니다. +그런 다음 전체 이벤트 트랜스크립트를 평가자 서비스에 POST합니다. 평가자는 다음 두 가지 방식으로 응답할 수 있습니다: + +- **결과를 인라인으로 반환**: `{"status":"done", "scores":{...}, "reasoning":{...}, "summary":"..."}` 형태로 반환하면 + 해당 결과가 세션의 평가 타임라인에 추가됩니다. `reasoning`과 `summary`는 선택 사항입니다. +- **지연 처리**: `{"status":"pending", "job_id":"abc-123"}` 형태로 응답하면, AgentEye는 + 평가자가 `{"status":"done", ...}` 또는 `{"status":"error", "error":"..."}`를 반환할 때까지 + `GET {EVALUATOR_ENDPOINT}/evaluate/abc-123`을 호출합니다. + + 폴링 주기는 작업별로 설정됩니다. `pending` 응답에 `next_poll_secs`를 포함하면 기본값을 + 재정의할 수 있습니다. 그렇지 않으면 AgentEye는 `GET /config`에서 받은 + `default_poll_interval_secs`를 사용하고, 그것도 없으면 서버의 `EVALUATOR_POLLING_INTERVAL_SECS` + 환경 변수(기본값: 10초)로 폴백합니다. 모든 값은 [1초, 1시간] 범위로 제한됩니다. + +`agent_end`를 전혀 발생시키지 않는 세션(예: 에이전트 프로세스가 비정상 종료된 경우)도 +처리할 수 있습니다. 평가자의 `GET /config`가 `{"inactivity_timeout_secs": 1800}`을 반환하면, +AgentEye는 해당 시간 동안 유휴 상태였던 세션을 평가합니다. 이 폴백을 비활성화하려면 +해당 필드를 `null`로 설정하거나 생략하세요. + +`EVALUATOR_ENDPOINT`가 설정되지 않으면 파이프라인은 완전히 아무 작업도 수행하지 않습니다. + +세션은 **시간이 지남에 따라 여러 개의 터미널 평가를 누적할 수 있습니다**. 각 `agent_end` +이벤트(및 대시보드에서의 수동 재평가)마다 새로운 평가 행이 추가됩니다. 이것이 재개된 +대화를 평가하는 공식 방법입니다. 사용자가 에이전트를 종료했다가 나중에 다시 접속하여 +더 많은 이벤트를 보내고 에이전트를 다시 종료하면, 두 번째 평가가 전체 업데이트된 +트랜스크립트를 대상으로 실행됩니다. 대시보드는 가장 최근 평가를 헤드라인으로 표시하고, +이전 평가들은 접을 수 있는 타임라인으로 보여줍니다. 세션에 대한 평가가 진행 중일 때 +추가로 발생하는 `agent_end` 이벤트는 무시됩니다. 진행 중인 평가가 완료된 후 다음 +이벤트가 발생하면 새로운 평가가 평소대로 대기열에 추가됩니다. + +비활성 폴백은 재개된 세션에도 다시 적용됩니다. 이전 터미널 평가 이후 새로운 이벤트가 +도착하고 세션이 다시 `inactivity_timeout_secs`를 초과하여 유휴 상태가 되면, 새로운 +평가가 대기열에 추가됩니다. + +일시적인 오류(5xx, 429, 타임아웃, 네트워크 오류)는 `EVALUATOR_MAX_ATTEMPTS`에 도달할 +때까지 지수 백오프로 재시도됩니다. 4xx 응답은 터미널 오류로 처리됩니다. AgentEye는 +수평으로 확장된 여러 서버 인스턴스와 함께 안전하게 실행될 수 있습니다. 작업이 +파티션으로 나뉘어 동일한 세션이 동시에 두 번 디스패치되지 않습니다. + +--- + +## HTTP 계약 + +인증이 필요한 모든 라우트는 **베어러 토큰 인증**을 사용합니다. 양쪽에 동일한 값이 +설정되어야 합니다: + +- AgentEye 서버: 환경 변수 `EVALUATOR_TOKEN` +- 평가자 서비스: 동일한 방식으로 구성 (`agenteye-evaluator` SDK는 관례적으로 + `EVALUATOR_TOKEN`을 읽습니다) + +`EVALUATOR_TOKEN`이 설정되지 않으면 서버는 `Authorization` 헤더를 전송하지 않습니다. +평가자는 익명 요청을 허용할 수 있지만, 이는 내부 전용 네트워크에서는 괜찮으나 +공개 인터넷에서는 권장하지 않습니다. + +### 평가자가 제공해야 하는 라우트 + +| 라우트 | 요청 본문 / 파라미터 | 응답 | +|---|---|---| +| `GET /health` | 없음 | `{"status":"ok"}` (공개, 인증 불필요) | +| `GET /config` | 없음 | `{"inactivity_timeout_secs": \| null, "default_poll_interval_secs": \| omitted}` | +| `POST /evaluate` | `EvalRequest` JSON | `{"status":"done", ...}` 또는 `{"status":"pending", "job_id":"..."}` | +| `GET /evaluate/{id}` | 없음 | `/evaluate`와 동일한 응답 형태 | + +### 서버가 전송하는 `EvalRequest` 본문 + +```json +{ + "schema_version": "1", + "session_id": "session-abc123", + "agent_id": "planner", + "environment": "production", + "started_at": "2026-05-10T12:00:00Z", + "ended_at": "2026-05-10T12:05:00Z", + "events": [ + { "id": 1234, "ts": "...", "event_type": "agent_start", "payload": { ... } }, + ... + ] +} +``` + +### 응답 형태 + +**동기(완료):** + +```json +{ + "status": "done", + "scores": { "helpfulness": 0.85, "tool_efficiency": 0.6 }, + "reasoning": { + "helpfulness": "answered the question directly with citations", + "tool_efficiency": "called list_files three times when one would have done" + }, + "summary": "strong answer quality, weak tool selection" +} +``` + +`reasoning`(점수별 근거 맵)과 `summary`(전체 요약 단락)는 모두 선택 사항입니다. +`reasoning`의 키는 `scores`의 키와 동일해야 하며, 대시보드는 각 항목을 해당 점수 +막대 아래에 인라인으로 렌더링합니다. `scores`만 반환하는 기존 평가자는 수정 없이 +계속 작동합니다. `reasoning`과 `summary`는 null로 읽히며 해당 UI 요소는 생략됩니다. + +**비동기(지연):** + +```json +{ "status": "pending", "job_id": "abc-123", "next_poll_secs": 30 } +``` + +`next_poll_secs`는 선택 사항입니다. 생략된 경우 서버는 `/config`에서 받은 평가자의 +`default_poll_interval_secs`를 사용하고, 그것도 없으면 자체 `EVALUATOR_POLLING_INTERVAL_SECS` +환경 변수를 사용합니다. + +**평가자 측 터미널 오류:** + +```json +{ "status": "error", "error": "model service unavailable" } +``` + +서버는 그 외의 2xx 응답 본문을 프로토콜 오류로 처리하고 세션에 터미널 `error`를 +기록합니다. + +--- + +## SDK로 평가자 작성하기 + +`agenteye-evaluator` Python 패키지는 위의 HTTP 계약을 구현하는 타입이 지정된 FastAPI +래퍼를 제공합니다. PyPI에서 설치하세요: + +```bash +pip install agenteye-evaluator +``` + +최소 구성 평가자: + +```python +import os +from agenteye_evaluator import Evaluator, EvalRequest, EvalResponse + +app = Evaluator(token=os.environ["EVALUATOR_TOKEN"]) + +@app.evaluator +def run(req: EvalRequest) -> EvalResponse: + # Inspect req.events (the full session transcript) and return scores. + tool_calls = sum(1 for e in req.events if e.event_type == "tool_use") + return EvalResponse( + scores={"tool_calls": float(tool_calls)}, + reasoning={"tool_calls": f"{tool_calls} tool invocations in the transcript"}, + summary="tight tool loop" if tool_calls < 5 else "agent looped on tools", + ) +``` + +`app` 인스턴스는 ASGI 호환이므로 `uvicorn module:app`으로 실행할 수 있습니다. + +비용이 많이 드는 작업을 지연해야 하는 평가자의 경우, `JobPending`을 반환하고 +`@app.job_lookup` 핸들러를 등록하세요. AgentEye 서버는 평가자가 터미널 상태를 +반환하거나 `EVALUATOR_MAX_POLL_DURATION_SECS` 제한(기본값: 1시간)에 도달할 때까지 +`GET /evaluate/{job_id}`를 폴링합니다. + +전체 API 레퍼런스, 비동기 패턴, 이벤트 스키마는 `agenteye-evaluator` README에서 +확인할 수 있으며, 이는 [agenteye-enterprise 릴리스 페이지](https://github.com/agenteye-enterprise/releases)의 +각 릴리스 타볼에 포함되어 있거나 패키지의 PyPI 페이지에서 읽을 수 있습니다. + +--- + +## Kubernetes에서 평가자 실행하기 + +평가자는 **사용자가 직접 제공하는 서비스**입니다. AgentEye는 기본 평가자 컨테이너를 +제공하지 않습니다. 릴리스에는 `deploy/examples/evaluator/` 아래에 참조용 Kubernetes +매니페스트가 포함되어 있으며, 이미지와 공유 베어러 토큰만 교체하면 바로 적용할 수 있습니다. + +### 1. 평가자 컨테이너화 + +평가자를 위한 최소 Dockerfile: + +```dockerfile +FROM python:3.12-slim +WORKDIR /app +RUN pip install --no-cache-dir agenteye-evaluator uvicorn +COPY my_evaluator.py . +RUN useradd --uid 10001 --create-home --shell /usr/sbin/nologin evaluator \ + && chown -R evaluator:evaluator /app +USER evaluator +EXPOSE 9000 +CMD ["uvicorn", "my_evaluator:app", "--host", "0.0.0.0", "--port", "9000"] +``` + +`runAsNonRoot`(UID 10001)를 사용하면 컨테이너가 Pod Security 제한 프로파일과 +호환됩니다. + +### 2. 공유 베어러 토큰 생성 + +```bash +kubectl -n agenteye create secret generic evaluator-token \ + --from-literal=token="$(openssl rand -hex 32)" +``` + +AgentEye 서버의 `EVALUATOR_TOKEN`과 동일한 값을 사용하세요. 서버는 모든 요청에 +`Authorization: Bearer ` 헤더를 전송하며, SDK는 `hmac.compare_digest`를 +사용하여 상수 시간 검사를 수행하고 불일치 시 HTTP 401을 반환합니다. + +### 3. 예제 매니페스트 적용 + +```bash +# 먼저 deploy/examples/evaluator/deployment.yaml를 편집하여 +# `image:`를 자신의 레지스트리로 변경한 다음: +kubectl apply -k deploy/examples/evaluator/ +``` + +예제에 포함된 내용: + +- `runAsNonRoot`, 읽기 전용 루트 파일시스템, 모든 권한 제거, `/health` 기반 + liveness + readiness 프로브가 설정된 2-레플리카 Deployment +- 포트 9000의 ClusterIP Service +- `secret.example.yaml` 템플릿(토큰이 git에 저장되지 않도록 의도적으로 Kustomization에서 + 제외됨; 실제 시크릿은 별도로 생성하세요) + +### 4. AgentEye와 연결하기 + +AgentEye 서버에 다음을 설정하세요: + +```bash +EVALUATOR_ENDPOINT=http://evaluator:9000 +EVALUATOR_TOKEN=<위에서 생성한 값> +``` + +서버는 `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH`만큼의 동시 요청을 모든 평가자 +파드에 분산합니다(기본값: `2 × 4 = 8`). 이 서버 측 설정과 함께 `replicas` 및 +파드당 리소스 제한을 적절히 조정하세요. + +### 검증 + +```bash +kubectl -n agenteye port-forward svc/evaluator 9000:9000 +curl -s http://localhost:9000/health # → {"status":"ok"} +``` + +에이전트가 처음부터 끝까지 실행된 후, AgentEye 서버의 `GET /evaluations`는 +`status: "done"`과 평가자가 생성한 점수가 포함된 행을 반환해야 합니다. + +--- + +## AgentEye 서버 구성 + +서버 프로세스에 다음 환경 변수를 설정하세요: + +| 환경 변수 | 설명 | +|---|---| +| `EVALUATOR_ENDPOINT` | 평가자의 기본 URL(`http://evaluator:9000`). 미설정 시 파이프라인이 비활성화됩니다. | +| `EVALUATOR_TOKEN` | 베어러 토큰. 평가자 서비스에 설정된 값과 동일해야 합니다. | +| `EVALUATOR_WORKERS` | 서버 인스턴스당 워커 태스크 수 (기본값: 2). | +| `EVALUATOR_CLAIM_BATCH` | 워커 틱당 클레임하는 행 수 (기본값: 4). 배치는 **동시에** 처리됩니다. 평가자 엔드포인트의 실효 동시성은 `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH`입니다. | +| `EVALUATOR_POLL_IDLE_SECS` | 평가가 예정되지 않은 경우 워커가 디스패치 시도 사이에 대기하는 시간 (기본값: 2초). | +| `EVALUATOR_POLLING_INTERVAL_SECS` | 응답별 `next_poll_secs`나 평가자의 `default_poll_interval_secs`가 없을 때 `GET /evaluate/{id}` 주기의 최종 폴백 (기본값: 10초). | +| `EVALUATOR_REQUEST_TIMEOUT_MS` | 요청당 타임아웃 (기본값: 30000). | +| `EVALUATOR_MAX_ATTEMPTS` | 이 횟수만큼 일시적 오류가 발생하면 결과가 터미널 `error`로 기록됩니다 (기본값: 5). | +| `EVALUATOR_CONFIG_REFRESH_SECS` | `GET /config` 주기 (기본값: 300). | +| `EVALUATOR_MAX_POLL_DURATION_SECS` | 세션이 폴링 대기열에 남아있을 수 있는 최대 실제 경과 시간. 초과 시 `timeout`으로 종료됩니다 (기본값: 3600초). 평가자가 계속 `pending`을 반환하는 경우를 방지합니다. | + +인스턴스 전체에 자동 채점을 활성화하려면, 두 키가 모두 설정된 `agenteye-evaluator` +시크릿을 프로비저닝하세요. 번들로 제공되는 Kubernetes 매니페스트에서 서버는 이 선택적 +시크릿으로부터 `EVALUATOR_ENDPOINT`와 `EVALUATOR_TOKEN`을 읽습니다. 조직의 표준 +시크릿 관리 프로세스를 통해 시크릿을 생성한 후, 변경 사항을 적용하기 위해 서버 +Deployment를 재시작하세요. + +위의 튜닝 설정은 기본적으로 연결되어 있지 않습니다. 기본값을 재정의해야 하는 경우 +Deployment 매니페스트의 서버 컨테이너에 해당 환경 변수를 노출하세요. + +전체 환경 변수 표는 [deployment.md](/ko/agenteye/deployment)를 참고하세요. + +--- + +## API 레퍼런스 + +| 메서드 | 경로 | 필요 권한 | 목적 | +|---|---|---|---| +| `GET` | `/evaluations` | `evaluations:read` | 터미널 결과 조회. `session_id`, `agent_id`, `environment`, `status` (`done`/`error`/`timeout`), `ts_from`, `ts_to`, `cursor`, `limit`, `score_filters`, `latest_per_session` 지원. `limit` 기본값은 50이며 최대 200입니다(최대 1000인 `/events`와 다릅니다). `environment`는 쉼표로 구분된 목록을 허용합니다(예: `environment=prod,staging`). 단일 값도 작동합니다. `latest_per_session=true` 설정 시 `session_id`당 최대 하나의 행만 반환합니다(`completed_at` 기준 최신). 세션 목록 페이지에서 세션의 평가 타임라인을 현재 헤드라인으로 접는 데 사용됩니다. 기본값은 false(전체 이력 반환). | +| `GET` | `/evaluations/aggregate` | `evaluations:read` | 필터링된 슬라이스에 대한 집계된 평가 상태: 총 개수, done/error/timeout 분류, 점수 키별 통계(임의 `scores` 키에 대한 count/avg/min/max/p50), 시간 버킷 타임라인. `/evaluations`와 동일한 필터 파라미터에 `featured_keys`(트렌드를 표시할 점수 키의 CSV)와 `latest_per_session`을 추가로 허용합니다. Dashboards 기능을 지원하며, 메트릭은 샘플링 없이 전체 매칭 세트에 대해 정확하게 계산됩니다. | +| `GET` | `/evaluations/environments` | `evaluations:read` | `evaluations` 테이블의 고유 environment 값. 평가 읽기 가능 데이터 범위의 필터 드롭다운을 채우는 데 사용됩니다. | +| `GET` | `/evaluation-jobs` | `evaluations:read` | 진행 중인 평가 상태 조회. `status` (`pending`/`polling`)로 필터링 가능. | +| `GET` | `/events` | `events:read` | 세션의 원시 이벤트 스트리밍. `session_id`, `agent_id`, `event_type`(CSV), `environment`(CSV), `ts_from`, `ts_to`, `cursor`, `limit`, `order` 지원. `order`는 `desc`(최신 순, 기본값) 또는 `asc`(오래된 순)이며, 인식할 수 없는 값은 `desc`로 폴백됩니다. 응답의 `next_cursor`(이벤트 id)를 통해 커서 페이지네이션을 사용하세요. `cursor`로 전달하면 다음 페이지를 가져옵니다. `asc`의 경우 해당 id 이후 이벤트를, `desc`의 경우 그 이전 이벤트를 반환합니다. `limit` 기본값은 50이며 최대 1000입니다. | +| `GET` | `/sessions/:session_id/export` | `events:read` | 이 세션에 대해 평가자가 받을 정확한 JSON 본문을 `session-.json`이라는 이름의 다운로드 가능한 첨부 파일로 반환합니다. 오프라인 테스트를 위해 프로덕션 세션을 `agenteye-evaluator`를 통해 재현하는 데 유용합니다. 평가자 파이프라인이 전송하는 내용과 바이트 단위로 동일합니다. | +| `POST` | `/sessions/:session_id/re-evaluate` | `evaluations:trigger` | 세션에 대한 새로운 평가를 대기열에 추가합니다. 이전 평가 존재 여부와 관계없이 실행됩니다. 새 결과는 이전 결과를 덮어쓰지 않고 세션의 평가 타임라인에 **추가**되어 이전 점수가 이력으로 남습니다. 대기열 추가 시 `202`, 알 수 없는 세션의 경우 `404`, 평가가 이미 진행 중인 경우 `409`를 반환합니다. 새 평가자 배포 후 또는 `agent_end`를 발생시키지 않은 세션에 사용하세요. | + +### 점수 범위로 필터링: `score_filters` + +`GET /evaluations`는 `scores` 객체 내의 숫자 값으로 결과를 좁히는 선택적 +`score_filters` 파라미터를 허용합니다. 이 파라미터는 쉼표로 구분된 `key:min..max` +항목의 목록이며, 각 경계는 생략할 수 있습니다. 여러 항목은 논리 AND로 결합됩니다. +지정된 키가 없거나 숫자가 아닌 행은 제외됩니다. 요청당 최대 20개의 필터 항목을 +허용하며, 초과 시 HTTP 400을 반환합니다. + +예시: +```text +# helpfulness가 [0.5, 0.8] 범위인 경우 +GET /evaluations?score_filters=helpfulness:0.5..0.8 + +# tool_efficiency가 최대 0.3인 경우 (하한 없음) +GET /evaluations?score_filters=tool_efficiency:..0.3 + +# helpfulness >= 0.5 AND factuality >= 0.9 +GET /evaluations?score_filters=helpfulness:0.5..,factuality:0.9.. +``` + +각 `/evaluations` 응답 객체의 필드: + +| 필드 | 타입 | 설명 | +|---|---|---| +| `evaluation_id` | string (UUID) | 이 터미널 평가의 표준 식별자. 각 터미널 평가는 새로운 UUID를 받으며, 하나의 세션이 여러 개를 가질 수 있습니다. | +| `id` | string (UUID) | `evaluation_id`와 동일한 값을 가지는 하위 호환 별칭. | +| `session_id` | string | 이 평가가 실행된 세션. 하나의 세션이 타임라인에 여러 평가를 가질 수 있습니다. | +| `agent_id` | string | 세션을 생성한 에이전트 식별자. | +| `environment` | string | 세션에서 복사된 환경 레이블. | +| `status` | enum | `"done"`, `"error"`, `"timeout"` 중 하나. | +| `scores` | object \| null | 평가자가 반환한 점수. | +| `reasoning` | object \| null | 평가자가 반환한 선택적 점수별 근거 맵. 키는 일반적으로 `scores`의 키와 동일합니다. 대시보드는 각 항목을 점수 막대 아래에 렌더링합니다. | +| `summary` | string \| null | 평가자가 반환한 선택적 전체 요약 단락. 대시보드는 점수별 분류 위에 평가의 헤드라인으로 표시합니다. | +| `error` | string \| null | `"error"` / `"timeout"` 상태에서만 채워집니다. | +| `attempt_count` | integer | 디스패치 시도 횟수 (≥ 1). | +| `duration_ms` | integer \| null | 마지막 시도의 소요 시간. | +| `completed_at` | string (ISO 8601 UTC) | 터미널 결과가 기록된 시간. 결과는 `completed_at` 기준으로 정렬됩니다(최신 순). | +| `created_at` | string (ISO 8601 UTC) | `completed_at`과 동일한 타임스탬프 (쓰기 한 번 시맨틱스). | + +--- + +## 권한 + +| 권한 | 부여 내용 | +|---|---| +| `evaluations:read` | 평가 결과 목록 조회, 대시보드에서 점수 확인, 대시보드 상태 메트릭 로드. | +| `evaluations:trigger` | `POST /sessions/:session_id/re-evaluate` 또는 대시보드의 재평가 버튼을 통해 세션 평가를 수동으로 대기열에 추가. | +| `dashboards:read` | 저장된 대시보드 조회 (메트릭 로드에는 `evaluations:read`도 필요). | +| `dashboards:write` | 대시보드 생성 및 편집. | +| `dashboards:delete` | 대시보드 삭제. | + +부트스트랩 관리자(`ADMIN_KEY`, `ADMIN_EMAIL`)는 이 모든 권한을 자동으로 받습니다. + +--- + +## 결과 확인 + +- **`/sessions/`**: 이벤트 타임라인 + 세션 점수와 디스패치 시도 오류를 표시하는 + 오른쪽 패널. 키에 `evaluations:trigger` 권한이 있으면 내보내기 버튼 옆에 + **재평가** 버튼이 나타납니다. `agent_end`를 발생시키지 않은 세션이나 새 평가자 + 배포 후 점수를 갱신하는 데 유용합니다. 대시보드는 새 결과를 폴링하고 결과가 + 도착하면 오른쪽 패널을 업데이트합니다. +- **`/sessions`**: 필터링 가능한 세션 그리드. 점수 열에 각 세션의 평가 상태와 + 점수가 한눈에 표시됩니다. +- **`/dashboards`**: 저장된 평가 상태 뷰 (아래 [Dashboards](#dashboards) 참고). + +![세션별 평가 상태 pill과 색상 코딩된 점수 배지(helpfulness, factuality, tool_efficiency, safety, coherence)가 있는 Sessions 그리드](/agenteye/images/sessions-list.png) + +*세션 그리드는 각 실행의 평가 상태와 점수를 한눈에 보여줍니다. 빨간색/노란색/녹색 배지로 낮은 점수가 눈에 띕니다.* + +![오른쪽 패널에 평가 점수와 디스패치 상태가 표시된 세션 상세 뷰](/agenteye/images/session-detail.png) + +*세션을 열면 평가 점수와 오른쪽 패널의 디스패처 오류가 전체 타임라인과 함께 표시됩니다.* + +--- + +## Dashboards + +**Dashboards** 페이지(`/dashboards`)에서는 평가 필터 조합을 이름이 있는 재사용 가능한 +뷰로 저장하고, 해당 평가 슬라이스의 상태를 한눈에 모니터링할 수 있습니다. 대시보드는 +**조직 전체에서 공유됩니다**. `dashboards:read` 권한이 있는 모든 사용자가 동일한 세트를 +볼 수 있습니다. + +각 대시보드에 고정되는 내용: + +- **필터**: 세션 페이지와 동일한 컨트롤: 환경, 상태, 에이전트, 롤링 시간 창, + 점수 범위 필터(`key:min..max`). +- **표시 구성**: 강조할 점수 키, 녹색/노란색/빨간색 상태 임계값, 표시할 패널, + 세션당 최신 평가로 접을지 여부. + +각 카드에는 매칭된 세션 수, done/error/timeout 분류, 각 주요 점수의 평균, +작은 트렌드 스파크라인이 표시됩니다. 대시보드를 열면 전체 크기 패널이 표시되며, +**"세션에서 열기"**를 클릭하면 해당 슬라이스로 미리 필터링된 세션 페이지로 이동합니다. +메트릭은 서버 측에서 전체 매칭 세트에 대해 계산됩니다(`GET /evaluations/aggregate` 사용). +따라서 숫자는 샘플링 없이 정확합니다. + +![평가자 차원별 평균 점수 막대, 도구 ok-vs-error 분류, 상위 도구, 시간당 이벤트 트렌드가 있는 평가 상태 대시보드](/agenteye/images/dashboard-quality.png) + +**권한:** 조회에는 `dashboards:read`와 `evaluations:read` 모두 필요합니다. +생성 및 편집에는 `dashboards:write`, 삭제에는 `dashboards:delete`가 필요합니다. +부트스트랩 관리자는 이 모든 권한을 자동으로 받습니다. + +--- + +## 문제 해결 + +**세션이 존재하지만 평가가 생성되지 않습니다.** 서버 프로세스에 `EVALUATOR_ENDPOINT`가 +설정되어 있는지, 서버와 평가자가 동일한 `EVALUATOR_TOKEN` 값을 공유하는지, 서버에서 +평가자의 `/health` 엔드포인트에 접근할 수 있는지 확인하세요. `EVALUATOR_ENDPOINT`가 +설정되지 않으면 파이프라인은 아무 작업도 수행하지 않습니다. + +**진행 중인 평가가 쌓입니다.** `GET /evaluation-jobs`를 조회하여 진행 중인 대기열을 +확인하세요. 각 행의 `attempt_count`, `next_attempt_at`, `last_error`를 검사하세요. +일반적인 원인: 평가자 서비스에 접근할 수 없거나 5xx를 반환하는 경우(백오프로 재시도), +잘못된 `EVALUATOR_TOKEN`(401은 터미널 오류), 또는 계속 `pending`을 반환하는 비동기 +평가자(아래 참고). + +**세션이 완료되었지만 터미널 평가가 없습니다.** `GET /evaluation-jobs?status=polling`을 +조회하세요. 결과가 아직 진행 중일 수 있습니다. 작업이 `pending` 상태에 멈춰 있다면, +서버가 평가자에 접근하는 데 문제가 있는 것입니다. 평가자가 실행 중인지, `EVALUATOR_TOKEN`이 +일치하는지 확인하세요. + +**`HTTP 401 from evaluator: invalid bearer token`.** 서버의 `EVALUATOR_TOKEN`이 평가자 +서비스에 설정된 값과 일치하지 않습니다. 두 값이 정확히 동일해야 합니다. + +**비동기 평가자가 계속 `pending`을 반환합니다.** 서버는 평가자가 `done` 또는 `error`를 +반환하거나 `EVALUATOR_MAX_POLL_DURATION_SECS` 제한(기본값: 1시간)에 도달할 때까지 +`GET /evaluate/{job_id}`를 폴링합니다. 제한에 도달하면 평가가 `timeout`으로 기록되고 +진행 중인 대기열에서 제거됩니다. 평가자가 기본값보다 더 오랜 시간이 합법적으로 +필요한 경우 `EVALUATOR_MAX_POLL_DURATION_SECS`를 늘리세요. \ No newline at end of file diff --git a/docs/ko/agenteye/getting-started.mdx b/docs/ko/agenteye/getting-started.mdx new file mode 100644 index 00000000..94f4c602 --- /dev/null +++ b/docs/ko/agenteye/getting-started.mdx @@ -0,0 +1,235 @@ +--- +title: "AgentEye 시작하기" +description: "AgentEye 시작하기 문서입니다." +--- + + +이 가이드는 AgentEye의 전체 설정 과정을 안내합니다. 서버와 대시보드 배포, 에이전트 머신에 수집기 설치, 그리고 Python 에이전트 코드 계측까지 다룹니다. + +--- + +## AgentEye란 무엇인가요? + +AgentEye는 **AI 에이전트를 위한 자체 호스팅 관찰 가능성 및 평가 플랫폼**입니다. 에이전트가 수행하는 모든 작업 — 실행의 각 단계 — 을 기록하고, 완료된 각 실행의 품질을 자동으로 평가합니다. 덕분에 프로덕션 환경에서 에이전트의 동작을 파악하고, 사용자보다 먼저 회귀를 발견할 수 있습니다. + +데이터는 단방향으로 흐릅니다. 에이전트 코드가 **Python SDK**를 통해 **이벤트**를 내보내면 → 경량 **수집기** 데몬이 이를 일괄 처리해 **서버**로 전송하고 → 이벤트와 분석 데이터는 **ClickHouse**에 저장됩니다(조직, 사용자, API 키, 대시보드, 저장된 쿼리와 같은 운영 상태는 **Postgres**에 보관됩니다) → 모든 데이터를 **대시보드**에서 탐색할 수 있습니다. + +제공되는 기능: + +- **이벤트** — 모든 에이전트 실행의 단계별 원시 기록 (도구 호출, 모델 호출, 훅, 오류). +- **세션** — 실행 단위로 집계된 이벤트로, 각 실행마다 **자동 평가** 및 점수가 부여됩니다. +- **평가** — 자체 평가자 서비스가 생성하는 품질 점수로, 수동 검토 없이 품질 저하를 감지합니다. +- **쿼리 및 대시보드** — 데이터에 대한 저장된 ClickHouse SQL을 조직 범위의 공유 대시보드로 시각화합니다. +- **알림 및 인시던트** — 임계값 규칙에 따라 알림(이메일, Slack, 웹훅, 대시보드 내)을 발송하고, 인시던트 분류를 위한 워크플로를 제공합니다. +- **CLI 및 AI 어시스턴트** — 터미널 클라이언트(`agenteye`)와 대시보드 내 어시스턴트로 자연어 질의를 지원합니다. + +모든 구성 요소를 자체 인프라에서 실행할 수 있습니다. 단일 Docker Compose 스택(이 가이드), 프로덕션 Kubernetes 설치, 또는 단일 코로케이션 파드로 구성할 수 있습니다. 이 가이드의 나머지 부분은 Compose 스택을 처음부터 끝까지 설정합니다. + +--- + +## 1단계: 인증 + +모든 AgentEye 아티팩트는 `agenteye-enterprise` GitHub 조직에서 배포됩니다. 엔터프라이즈 개발자는 자체 GitHub PAT를 생성할 수 있습니다. 정확한 단계와 필요한 권한은 [enterprise-docs/github-token.md](/ko/agenteye/github-token)를 참고하세요. + +```bash +export AGENTEYE_TOKEN= + +# Authenticate Docker against GHCR +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +--- + +## 2단계: 서버 및 대시보드 배포 + +서버는 수집기로부터 이벤트를 수신하여 조회할 수 있게 만들고, 대시보드는 데이터를 탐색하는 공간입니다. 수집된 이벤트와 분석 데이터는 ClickHouse(필수 분석 저장소)에 저장되며, Postgres는 조직, 사용자, API 키, 대시보드, 저장된 쿼리와 같은 운영 상태를 보관합니다. + +**게시된 compose 파일 다운로드:** + +```bash +mkdir -p ./agenteye +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + https://raw.githubusercontent.com/agenteye-enterprise/releases/main/docker-compose.yml \ + -o ./agenteye/docker-compose.yml +cd agenteye +``` + +**시크릿 설정:** + +기본 `admin` 자격 증명으로 배포되지 않도록 `.env` 파일을 생성하세요. 최소한 `ADMIN_KEY`와 `POSTGRES_PASSWORD`를 설정해야 합니다: + +```bash +POSTGRES_PASSWORD=your-db-password +ADMIN_KEY=your-admin-secret +``` + +이후 단계(예: 3단계의 `curl`)에서 직접 참조할 수 있도록 현재 셸에도 `ADMIN_KEY`를 내보내세요: + +```bash +export ADMIN_KEY=your-admin-secret +``` + +**스택 시작:** + +```bash +docker compose up -d +``` + +이 명령은 필수 ClickHouse 분석 저장소, 선택적 Redis 캐시, 서버, 대시보드를 포함한 전체 스택을 시작합니다. 서버가 시작되려면 ClickHouse가 정상 상태여야 합니다. + +서버는 `http://localhost:8080`에서, 대시보드는 `http://localhost:3000`에서 수신 대기 중입니다. + +프로덕션 배포(커스텀 Postgres, TLS, 리버스 프록시)는 [enterprise-docs/deployment.md](/ko/agenteye/deployment)를 참고하세요. + +--- + +## 3단계: 수집기용 API 키 생성 + +각 수집기는 범위가 지정된 API 키로 인증합니다. 2단계에서 설정한 `ADMIN_KEY`를 사용하여 키를 생성하세요: + +```bash +curl -s -X POST http://localhost:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{"name":"prod-collector","key":"your-collector-secret","permissions":["events:add"]}' +``` + +`key` 값은 직접 지정하며, 4단계의 수집기 설정에서 사용됩니다. 전체 키 관리 방법은 [enterprise-docs/api-keys.md](/ko/agenteye/api-keys)를 참고하세요. + +--- + +## 4단계: 수집기 설치 + +AI 에이전트가 실행되는 모든 머신에 수집기 데몬을 설치하세요. + +**바이너리 다운로드 (Linux x86_64):** + +```bash +VERSION=0.0.1-beta.13 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "collector/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-collector-linux-x86_64' +chmod +x agenteye-collector-linux-x86_64 +sudo mv agenteye-collector-linux-x86_64 /usr/local/bin/agenteye-collector +``` + +> 이 명령은 **Linux x86_64** 빌드를 다운로드합니다. macOS(Apple Silicon 또는 Intel), Linux arm64, Docker / systemd / launchd 설정의 경우 [collector-installation.md](/ko/agenteye/collector-installation)를 참고하세요. 각 플랫폼별 다운로드 링크가 나열되어 있습니다 — 위 명령은 다른 환경에서는 실행되지 않는 Linux 바이너리를 설치합니다. + +**설정:** + +```bash +mkdir -p ~/.agenteye +cat > ~/.agenteye/config.json </…`)가 접두사로 붙습니다. + +- **쿼리** (`//queries`): 이벤트와 평가에 대한 저장된 재사용 가능한 쿼리 라이브러리(기본 제공 프리셋 및 사용자 정의)에서 시작하세요… + +![저장된 쿼리 라이브러리: 기본 제공 프리셋과 사용자 정의 쿼리가 그리드 형식으로 표시됩니다](/agenteye/images/queries.png) + + …그런 다음 SQL 작성기에서 열어 수정하고 실시간 결과와 함께 실행하세요: + +![저장된 쿼리를 실행하는 SQL 쿼리 작성기 - 스키마 사이드바와 실시간 결과 그리드](/agenteye/images/query-lab.png) + +- **대시보드** (`//dashboards`): 쿼리를 선 그래프, 막대 그래프, 영역 그래프, 파이 차트 타일로 고정하여 조직 전체가 공유하는 대시보드를 만드세요. + +![저장된 쿼리로 구성된 대시보드: 시간당 이벤트 선 그래프, 오류 유형별 막대 그래프, 지연 시간 영역 차트, 모델별 토큰 수](/agenteye/images/dashboard-fleet.png) + +- **알림** (`//alerts`): 임계값 조건을 이메일, Slack, 웹훅, 또는 대시보드 내 알림 규칙으로 전환하세요. [enterprise-docs/alerts.md](/ko/agenteye/alerts)를 참고하세요. + +--- + +## 다음 단계 + +- [배포](/ko/agenteye/deployment): 프로덕션 환경 강화 +- [API 키](/ko/agenteye/api-keys): 접근 권한 관리 +- [문제 해결](/ko/agenteye/troubleshooting): 문제 진단 \ No newline at end of file diff --git a/docs/ko/agenteye/github-token.mdx b/docs/ko/agenteye/github-token.mdx new file mode 100644 index 00000000..5067c161 --- /dev/null +++ b/docs/ko/agenteye/github-token.mdx @@ -0,0 +1,131 @@ +--- +title: "GitHub 토큰 설정" +description: "AgentEye GitHub 토큰 설정 문서입니다." +--- + +GitHub Personal Access Token(PAT)은 모든 AgentEye 아티팩트에 접근할 수 있는 단일 자격증명입니다. 토큰 하나로 Docker 이미지 가져오기, 릴리스 바이너리 다운로드, Python 휠 설치가 모두 가능하며, 컴포넌트별 로그인이나 공유 시크릿을 배포할 필요가 없습니다. 모든 AgentEye 아티팩트는 `agenteye-enterprise` GitHub 조직에서 배포됩니다. 조직에 접근 권한이 부여되면, 각 개발자 또는 운영자가 자신의 토큰을 개별적으로 생성하고 교체하므로, 접근 기록을 감사하고 개인별로 권한을 취소할 수 있습니다. + +머신마다 한 번씩 토큰을 환경 변수로 설정하고 Docker 자격증명을 등록하세요: + +```bash +export AGENTEYE_TOKEN= +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +> **사용자명 참고:** GHCR은 `docker login`의 사용자명을 무시하고 토큰만으로 인증하므로, 비어 있지 않은 값이면 무엇이든 사용할 수 있습니다. 이 문서에서는 간결함을 위해 `-u x`를 사용합니다. Kubernetes 이미지 풀 시크릿을 생성하는 배포 매니페스트에서는 `agenteye-enterprise`와 같이 좀 더 설명적인 사용자명을 사용할 수도 있습니다. 두 방식 모두 허용됩니다. + +--- + +## 옵션 A: 클래식 토큰 (권장) + +클래식 토큰은 AgentEye에서 가장 안정적인 선택입니다. GHCR의 `docker login` 및 이미지 풀 과정에서 클래식 토큰에 대한 지원이 가장 광범위하고 일관적이기 때문입니다. 두 가지 스코프만으로 필요한 모든 작업(이미지 가져오기 및 릴리스 에셋 다운로드)이 가능하므로, 한 번 인증하면 레지스트리 관련 문제를 따로 해결할 필요가 없습니다. 그 중 `read:packages`는 진정한 의미의 읽기 전용이지만, `repo`는 비공개 릴리스 에셋에 대한 접근 권한을 부여하는 유일한 클래식 스코프로, 의도적으로 넓은 범위를 가집니다 — GitHub는 이를 비공개 리포지토리에 대한 완전한 제어권(읽기 및 쓰기)으로 정의하고 있습니다. + +### 1. 토큰 생성 + +**GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic) → Generate new token (classic)**으로 이동합니다. + +| 필드 | 값 | +|---|---| +| **Note** | `agenteye-<머신 또는 팀 이름>` (예: `agenteye-prod-server`) | +| **Expiration** | 보안 정책에 맞는 만료 기간 설정; 기본값으로 90일이 적절합니다 | + +> **레이블 참고:** GitHub는 클래식 토큰의 경우 이 필드를 **Note**, 세분화된 토큰의 경우 **Token name**으로 표시합니다. 두 필드 모두 동일한 목적, 즉 이후 감사 및 취소를 위한 사람이 읽을 수 있는 식별자로 사용됩니다. + +### 2. 스코프 선택 + +| 스코프 | 필요한 이유 | +|---|---| +| `read:packages` | `ghcr.io/agenteye-enterprise/`에서 Docker 이미지를 가져오고 패키지 에셋을 다운로드하기 위해 필요 | +| `repo` | `agenteye-enterprise/releases`의 비공개 리포지토리 콘텐츠, 원시 파일, 릴리스 에셋을 읽기 위해 필요. 이는 GitHub의 "비공개 리포지토리 완전 제어"(읽기 및 쓰기) 스코프로, 읽기 전용이 아니지만 비공개 릴리스 에셋에 접근할 수 있는 유일한 클래식 스코프입니다 | + +그 외의 스코프는 필요하지 않습니다. + +### 3. 토큰 생성 및 복사 + +**Generate token**을 클릭하고 즉시 값을 복사합니다. 토큰은 한 번만 표시됩니다. 시크릿 매니저 또는 환경 변수에 저장하세요. + +--- + +## 옵션 B: 세분화된 토큰 (Fine-Grained Token) + +세분화된 토큰은 특정 리포지토리와 권한으로 접근 범위를 제한하므로 최소 권한 원칙을 가장 엄격하게 적용할 수 있는 옵션입니다. 조직의 보안 정책에서 세분화된 토큰을 의무적으로 요구하는 경우 이 방법을 선택하세요. + +> **참고:** GHCR의 세분화된 토큰 지원은 클래식 토큰에 비해 일관성이 낮습니다. 위 단계를 따른 후 `docker login` 또는 `docker pull`이 실패하면, 클래식 토큰(옵션 A)으로 전환하세요. + +### 1. 토큰 생성 + +**GitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokens → Generate new token**으로 이동합니다. + +| 필드 | 값 | +|---|---| +| **Token name** | `agenteye-<머신 또는 팀 이름>` (예: `agenteye-prod-server`) | +| **Expiration** | 보안 정책에 맞는 만료 기간 설정; 기본값으로 90일이 적절합니다 | +| **Resource owner** | `agenteye-enterprise` | +| **Repository access** | **Only select repositories** → `agenteye-enterprise/releases` | + +### 2. 리포지토리 권한 설정 + +**Permissions → Repository permissions**에서 다음과 같이 설정합니다: + +| 권한 | 접근 수준 | +|---|---| +| **Contents** | Read-only | +| **Packages** | Read-only | + +그 외 모든 권한은 **No access**로 유지할 수 있습니다. + +> **참고:** 컨테이너 이미지(`ghcr.io/agenteye-enterprise/...`)가 리포지토리 연결 패키지가 아닌 조직 수준 패키지로 게시된 경우, 리포지토리 스코프 권한만으로는 Docker 로그인이 실패할 수 있습니다. 이 경우 조직 수준 권한을 추가하세요: **Permissions → Organization permissions → Packages: Read-only**. + +### 3. 각 권한이 부여하는 접근 범위 + +| 권한 | 사용 목적 | +|---|---| +| Contents: Read-only | `agenteye-enterprise/releases`에서 `docker-compose.yml`, 릴리스 바이너리, Python 휠 다운로드 | +| Packages: Read-only | `ghcr.io/agenteye-enterprise/`에서 Docker 이미지 가져오기 | + +### 4. 토큰 생성 및 복사 + +**Generate token**을 클릭하고 즉시 값을 복사합니다. 토큰은 한 번만 표시됩니다. 시크릿 매니저 또는 환경 변수에 저장하세요. + +--- + +## 토큰 교체 + +정기적으로 토큰을 교체하면 접근 기록을 감사 가능한 상태로 유지하고, 자격증명이 유출되더라도 피해 범위를 최소화할 수 있습니다. 토큰은 만료되거나 언제든지 취소될 수 있으므로, 인증 상태를 유지하기 위한 일반적인 방법이 토큰 교체입니다. 교체 방법: + +1. 위의 단계에 따라 새 토큰을 생성합니다. +2. 환경 변수 또는 시크릿 매니저에서 `AGENTEYE_TOKEN`을 업데이트합니다. +3. Docker 재인증: `echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin` +4. GitHub → Settings → Developer settings → Personal access tokens에서 이전 토큰을 취소합니다. 토큰 유형에 맞는 **Tokens (classic)** 또는 **Fine-grained tokens** 하위 페이지를 열고 삭제합니다. + +--- + +## 토큰 검증 + +배포에 연결하기 전에 토큰이 정상적으로 작동하는지 확인하세요. 인증 오류가 배포 중간에 발생하지 않고 여기서 표면화될 수 있습니다. 아래 각 명령은 위에서 설명한 스코프 중 하나를 검증합니다: + +```bash +# Packages scope - authenticate Docker against GHCR +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin + +# Contents scope - fetch a raw release file +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + https://raw.githubusercontent.com/agenteye-enterprise/releases/main/docker-compose.yml \ + -o /tmp/agenteye-compose-check.yml +``` + +`docker login`이 성공하면 패키지 스코프가 확인된 것이고, 파일이 다운로드되면 콘텐츠 스코프가 확인된 것입니다. + +--- + +## 문제 해결 + +| 증상 | 예상 원인 | 해결 방법 | +|---|---|---| +| `docker login`에서 401 반환 | 세분화된 토큰에서 `Packages: Read-only` 누락, 또는 클래식 토큰에서 `read:packages` 누락 | 패키지 스코프를 추가하고 토큰을 재생성하세요 | +| `curl`이 GitHub raw URL에서 404 반환 | `Contents: Read-only` 또는 `repo` 스코프 누락 | 콘텐츠 스코프를 추가하고 토큰을 재생성하세요 | +| `gh release download`에서 403 반환 | 토큰이 `agenteye-enterprise/releases`에 대한 권한 없음 | 세분화된 토큰의 리포지토리 접근에 해당 리포지토리가 포함되어 있는지 확인하거나, `repo` 스코프가 있는 클래식 토큰을 사용하세요 | +| 토큰은 수락되지만 이미지를 찾을 수 없음 | 세분화된 토큰에 조직 수준 패키지 권한 누락 | 조직 수준 `Packages: Read-only` 권한을 추가하세요 | + +접근 문제가 있으면 `support@exosphere.host`로 문의하세요. \ No newline at end of file diff --git a/docs/ko/agenteye/health-monitoring.mdx b/docs/ko/agenteye/health-monitoring.mdx new file mode 100644 index 00000000..20f6dc97 --- /dev/null +++ b/docs/ko/agenteye/health-monitoring.mdx @@ -0,0 +1,88 @@ +--- +title: "상태 모니터링" +description: "AgentEye 상태 모니터링 문서입니다." +--- + +에이전트가 오작동할 때만이 아니라, AgentEye 배포 자체가 **다운되거나 성능이 저하된 경우**를 즉시 파악할 수 있습니다. 탐지는 **Kubernetes 네이티브** 방식이며, 결정적으로 **AgentEye와 독립적으로 작동**합니다. Kubernetes 컨트롤 플레인에서 파드 상태를 직접 읽고 AgentEye의 핵심 의존성을 확인하기 때문에, 서버, ClickHouse, 또는 Postgres가 다운된 경우에도 알림이 발생합니다. + +두 가지 레이어로 구성됩니다. 첫 번째는 기본 내장이며, 두 번째는 선택적으로 활성화합니다. + +## 1. 의존성 인식 준비성 검사 (기본 내장) + +서버는 명확히 다른 역할을 가진 두 가지 프로브 엔드포인트를 제공합니다: + +| 엔드포인트 | 프로브 | 확인 항목 | 인증 | +|---|---|---|---| +| `GET /health` | 활성(liveness) | 프로세스 정상 동작 여부 (항상 `{"status":"ok"}` 반환) | 없음 | +| `GET /ready` | 준비(readiness) | 실제 서비스 가능 여부: **Postgres + ClickHouse** 연결 가능 여부 | 없음 | + +`/ready`는 두 핵심 의존성이 모두 연결 가능한 경우 `"status":"ready"`와 모든 항목 `"ok"`와 함께 `200`을 반환하고, 하나라도 연결 불가능한 경우 `"status":"not_ready"`와 함께 `503`을 반환합니다. 두 응답 모두 간략한 본문을 포함합니다: + +```json +{ "status": "not_ready", + "checks": { "postgres": "ok", "clickhouse": "down", "redis": "not_configured" } } +``` + +Redis는 서버가 없어도 성능 저하 상태로 동작할 수 있는 선택적 캐시이므로, 정보 제공 목적으로만 보고되며 **준비성 검사에 실패를 유발하지 않습니다**. 캐시가 설정된 경우 `"ok"`, 설정되지 않은 경우 `"not_configured"`를 표시하며, `"down"` 상태는 절대 표시되지 않습니다. + +번들로 제공되는 Kubernetes 매니페스트에서 **준비(readiness)** 프로브는 `/ready`를, **활성(liveness)** 프로브는 `/health`를 가리킵니다. 그 결과: *실행 중이지만 데이터베이스에 연결할 수 없는* 서버는 Service에서 제외되어 `NotReady` 상태로 표시되며, 아래에서 설명하는 클러스터 모니터링을 통해 알림을 받을 수 있습니다. 활성 프로브는 비용이 낮게 유지되므로, 일시적인 의존성 장애가 파드 재시작을 유발하지 않습니다. 프로브는 넉넉한 실패 임계값을 사용하므로, 순간적인 장애로 인해 레플리카가 로테이션에서 빠지는 현상이 발생하지 않습니다. + +## 2. Robusta를 이용한 파드 장애 알림 (선택 사항) + +[Robusta](https://github.com/robusta-dev/robusta)는 Kubernetes 네이티브 모니터로, API 서버를 감시하고 파드 장애(`CrashLoopBackOff`, `OOMKilled`, `ImagePullBackOff`, `Pending`/`NotReady`, `Failed`, 퇴거)를 Slack으로 전달합니다. AgentEye에 직접 묻는 방식이 아닌 컨트롤 플레인을 관찰하기 때문에, AgentEye가 전혀 응답하지 못하는 상황에서도 알림이 발생합니다. + +Robusta는 릴리스 번들에 선택적 애드온으로 포함되어 있습니다. 아래에 안내된 표준 Robusta Helm 차트와 소규모 values 파일을 사용하여 활성화하세요: + +1. 차트 저장소를 추가하고 해당 채널에 사용할 Slack **봇 토큰** (`xoxb-…`)을 준비합니다: + + ```bash + helm repo add robusta https://robusta-charts.storage.googleapis.com + helm repo update + ``` + + 아래 설정은 모든 것을 클러스터 내부로 유지하므로 (`disableCloudRouting: true`), 토큰은 자체 호스팅 Slack 앱에서 가져옵니다. `https://api.slack.com/apps`에서 앱을 생성하고, `chat:write` 봇 스코프를 추가한 후, 워크스페이스에 설치하고 **Bot User OAuth Token** (`xoxb-…`)을 복사한 다음, 채널에 봇을 초대합니다 (`/invite @your-app`). + +2. 배포별 레이블 (`clusterName`)과 Slack 채널을 포함한 `values.yaml`을 생성하고, `agenteye` 네임스페이스로 범위를 지정합니다: + + ```yaml + clusterName: "acme-prod" # 배포별 레이블; 모든 알림에 표시됨 + enablePrometheusStack: false # 파드 크래시 알림만 사용; 메트릭 스택 제외 + disableCloudRouting: true # 클러스터 내부에서 Slack으로 직접 전달 + sinksConfig: + - slack_sink: + name: vendor_slack + slack_channel: "agenteye-fleet-health" + api_key: "REPLACE_WITH_SLACK_BOT_TOKEN" # xoxb-… (--set 또는 시크릿 사용 권장) + scope: + include: + - namespace: [agenteye] # AgentEye 네임스페이스 알림만; 제거하면 범위 확장 + ``` + +3. 검증된 Robusta 차트 릴리스에 `--version`을 고정하여 설치합니다 ([릴리스 목록](https://github.com/robusta-dev/robusta/releases)). 테스트되지 않은 차트가 설치되는 것을 방지할 수 있습니다: + + ```bash + helm install robusta robusta/robusta \ + --namespace robusta --create-namespace \ + --version \ + -f values.yaml \ + --set sinksConfig[0].slack_sink.api_key=$ROBUSTA_SLACK_TOKEN + ``` + +### 보고 항목 + +- Kubernetes **파드 상태** (어떤 AgentEye 파드가 실패하고 있으며 원인이 무엇인지)와 각 파드의 **이미지 태그**, 즉 실행 중인 컴포넌트의 **버전**. +- **AgentEye 이벤트 데이터 및 고객 데이터는 클러스터 외부로 절대 유출되지 않습니다**. +- 번들로 제공되는 values는 알림 범위를 **`agenteye` 네임스페이스**로 제한하므로, 동일 클러스터의 관련 없는 워크로드는 보고되지 않습니다. + +### 모든 배포를 한 곳에서 + +모든 배포의 Robusta가 **하나의 공유 Slack 채널**을 가리키도록 설정하되, 각 배포마다 고유한 `clusterName`을 지정합니다. 모든 알림에 해당 레이블이 태그되므로, 단일 채널에서 전체 플릿의 상태를 확인할 수 있으며, 어떤 배포에 문제가 발생했는지 한눈에 파악할 수 있습니다. + +### 클러스터 전체 장애 + +클러스터 내부에서만 동작하는 감시자는 **클러스터 전체 또는 네트워크 장애**를 보고할 수 없습니다 (클러스터와 함께 다운됩니다). 이 경우가 필요하다면, 선택적 **Robusta UI 싱크**를 활성화하세요: `disableCloudRouting: false`로 설정하고 `robusta gen-config`에서 발급받은 토큰과 함께 `robusta_sink`를 `sinksConfig`에 추가합니다. 이를 통해 다중 클러스터 통합 대시보드가 제공되며, 체크인이 중단된 클러스터를 플래그로 표시합니다. + +## 문제 해결 + +"알림이 수신되지 않음" 및 "서버가 계속 `NotReady`로 flapping됨" 문제는 +[enterprise-docs/troubleshooting.md](/ko/agenteye/troubleshooting)의 **상태 모니터링** 섹션을 참조하세요. \ No newline at end of file diff --git a/docs/ko/agenteye/kubernetes-deployment.mdx b/docs/ko/agenteye/kubernetes-deployment.mdx new file mode 100644 index 00000000..4993450f --- /dev/null +++ b/docs/ko/agenteye/kubernetes-deployment.mdx @@ -0,0 +1,831 @@ +--- +title: "Kubernetes 배포 가이드" +description: "AgentEye Kubernetes 배포 가이드 문서." +--- + + +이 가이드는 전용 Kubernetes 클러스터에 AgentEye 전체 스택을 배포하는 방법을 안내합니다: + +- **ClickHouse 24.8** -- 이벤트 및 평가 분석의 기준 저장소 (100Gi 퍼시스턴트 볼륨을 가진 StatefulSet). 필수 항목: 없으면 서버가 시작되지 않습니다. +- **PostgreSQL 16** -- 조직, API 키, 사용자, 대시보드, 저장된 쿼리, 인증을 위한 관계형/메타데이터 저장소 (50Gi 퍼시스턴트 볼륨을 가진 StatefulSet) +- **Redis 7.2** -- 선택적 공유 캐시 및 속도 제한 백엔드; 사용 불가 시 서버와 대시보드는 기능이 저하된 상태로 계속 동작합니다 +- **AgentEye Server** -- 이벤트 수집, 분석, 키 관리를 위한 Rust API (2개 레플리카) +- **AgentEye Dashboard** -- Next.js 웹 UI (2개 레플리카) +- **AI 어시스턴트 (에이전트 서비스)** -- 포트 9100에서 제공되는 선택적 읽기 전용 대시보드 내 어시스턴트; LLM 엔드포인트가 구성되기 전까지 비활성 상태 +- **Traefik (공용)** -- 수집기 트래픽용 인그레스 컨트롤러, mTLS 보호 +- **Traefik (대시보드)** -- 대시보드용 인그레스 컨트롤러, VPN/IP 허용 목록 전용 +- **cert-manager** -- TLS 인증서 및 mTLS CA +- **백업 CronJob** -- 매일 UTC 03:00에 PostgreSQL + ClickHouse 통합 덤프 실행 +- **인증서 갱신 모니터** -- 클라이언트 인증서 만료 임박 시 알림 발송 + +**예상 소요 시간:** 최초 배포 기준 60~90분. + +Exosphere가 모든 과정을 대신 처리하는 관리형 배포 모델에 대해서는 [enterprise-docs/managed-deployment.md](/ko/agenteye/managed-deployment)를 참조하세요. + +--- + +## 사전 요구 사항 + +시작하기 전에 각 확인 명령을 실행하세요. 모든 항목을 통과해야 합니다. + +| 요구 사항 | 최솟값 | 확인 명령 | 예상 결과 | +|---|---|---|---| +| Kubernetes 클러스터 | 1.27+ | `kubectl version` | Server Version >= v1.27 | +| Kustomize (kubectl에 포함) | Kustomize v1.14+ (kubectl 1.27+에 포함) | `kubectl kustomize --help` | 사용법 텍스트 출력 | +| Helm | v3 | `helm version` | `Version:"v3.x.x"` | +| cluster-admin RBAC | -- | `kubectl auth can-i create namespaces` | `yes` | +| 기본 StorageClass | -- | `kubectl get storageclass` | `(default)` 표시가 있는 항목 최소 1개 | +| LoadBalancer 지원 | -- | 클라우드 환경에 따라 다름 (EKS, GKE, AKS 모두 기본 지원) | -- | +| GitHub PAT | -- | `echo $AGENTEYE_TOKEN` | 값이 존재해야 함 ([enterprise-docs/github-token.md](/ko/agenteye/github-token) 참조) | +| openssl | -- | `openssl version` | OpenSSL 1.x 또는 3.x | +| 클라우드 스토리지 버킷 | -- | PostgreSQL + ClickHouse 백업용 (S3, GCS, 또는 Azure Blob) | -- | + +**클러스터 사양:** 최소 3개 노드, 각 노드당 4 vCPU / 8 GB RAM. 전체 요구 사항은 [enterprise-docs/managed-deployment.md](/ko/agenteye/managed-deployment)를 참조하세요. + +### 모든 항목 한 번에 확인 + +```bash +echo "--- Prerequisites Check ---" +kubectl version --client -o yaml 2>/dev/null | grep -q gitVersion && echo "PASS: kubectl" || echo "FAIL: kubectl not found" +helm version --short 2>/dev/null | grep -q v3 && echo "PASS: helm v3" || echo "FAIL: helm v3 not found" +kubectl auth can-i create namespaces 2>/dev/null | grep -q yes && echo "PASS: cluster-admin" || echo "FAIL: no cluster-admin" +kubectl get storageclass 2>/dev/null | grep -q default && echo "PASS: default StorageClass" || echo "FAIL: no default StorageClass" +[ -n "$AGENTEYE_TOKEN" ] && echo "PASS: AGENTEYE_TOKEN set" || echo "FAIL: AGENTEYE_TOKEN not set" +openssl version >/dev/null 2>&1 && echo "PASS: openssl" || echo "FAIL: openssl not found" +echo "---" +``` + +### 배포 구조 + +**수집 엔드포인트**는 사용자가 제어하는 호스트명(예: `ingest.your-company.example`)으로 제공됩니다. cert-manager는 HTTP-01 방식으로 Let's Encrypt에 공개 신뢰 TLS 인증서를 요청하므로, 수집기는 고객별 CA 고정 없이 시스템 신뢰 저장소에서 서버 인증서를 검증합니다. + +**대시보드 엔드포인트**도 동일한 방식으로 동작합니다. 사용자가 제어하는 두 번째 호스트명(예: `agenteye.your-company.example`)으로 제공되며, 대시보드 Traefik LoadBalancer를 가리킵니다. cert-manager는 해당 LoadBalancer를 통해 Let's Encrypt 인증서를 발급합니다. 브라우저는 경고 없이 신뢰된 인증서를 받습니다. + +> **인증서 발급 및 갱신은 HTTP-01로 검증됩니다.** 따라서 두 LoadBalancer 모두 인터넷에서 포트 80으로 접근 가능해야 합니다. 대시보드 LoadBalancer에 IP 제한이 필요한 경우, 먼저 지원팀과 DNS-01 솔버를 조율하세요 — 그렇지 않으면 갱신이 자동으로 실패하여 인증서가 만료됩니다. + +--- + +## 매니페스트 가져오기 + +```bash +git clone https://x:${AGENTEYE_TOKEN}@github.com/agenteye-enterprise/releases.git +cd releases/deploy +``` + +**확인:** + +```bash +ls base/kustomization.yaml +``` + +예상 결과: 파일이 존재해야 합니다. 존재하지 않으면 클론에 실패한 것입니다 — `AGENTEYE_TOKEN`을 확인하세요. + +**디렉터리 구조:** + +``` +deploy/ + base/ 공유 Kustomize 기반 (모든 K8s 리소스) + overlays/ 클러스터별 오버라이드 (이미지 태그, 호스트명, 리소스) + third-party/ Traefik, cert-manager, 및 (선택적) Robusta 상태 모니터링용 Helm 값 +``` + +**base**에는 Phase 3.1에서 구성하는 두 공용 호스트명의 Let's Encrypt 인증서를 포함한 전체 배포에 필요한 모든 리소스가 포함되어 있습니다. **overlay**는 특정 환경(예: 사용자 정의 이미지 태그, 리소스 제한, 환경 변수 연결)에 맞게 base를 패치합니다. **third-party** 디렉터리에는 외부 인프라용 Helm 값 파일이 있습니다. + +> **상태 모니터링 (선택 사항):** 서버의 readiness probe는 이미 Postgres + ClickHouse 상태를 반영하며, `third-party/robusta/`는 선택적으로 Kubernetes 네이티브 파드 오류 알림을 Slack에 전송하는 기능을 추가합니다. [enterprise-docs/health-monitoring.md](/ko/agenteye/health-monitoring)를 참조하세요. + +--- + +## Phase 1 -- 서드파티 인프라 (~30분) + +### 1.1 cert-manager 설치 + +cert-manager는 HTTPS용 TLS 인증서와 mTLS 클라이언트 인증서에 사용되는 프라이빗 CA를 관리합니다. + +```bash +helm repo add jetstack https://charts.jetstack.io +helm repo update + +helm install cert-manager jetstack/cert-manager \ + --namespace cert-manager --create-namespace \ + --set crds.install=true +``` + +**확인:** + +```bash +kubectl get pods -n cert-manager +``` + +예상 결과: 3개 파드가 모두 `Running` 상태 — `cert-manager`, `cert-manager-cainjector`, `cert-manager-webhook`. + +```bash +kubectl get crds | grep cert-manager +``` + +예상 결과: 최소 `certificates.cert-manager.io`, `clusterissuers.cert-manager.io`, `issuers.cert-manager.io`가 표시되어야 합니다. + +**실패 시:** 파드가 `CrashLoopBackOff` 상태이면 일반적으로 CRD가 설치되지 않은 것입니다. `--set crds.install=true`를 추가하여 다시 실행하세요. webhook 파드가 readiness에 실패하면 30초 기다렸다가 다시 확인하세요 — 시작하는 데 잠시 시간이 걸릴 수 있습니다. + +--- + +### 1.2 Traefik 설치 -- 공용 수집 컨트롤러 + +이 Traefik 인스턴스는 **외부** LoadBalancer에서 수집기 트래픽을 처리합니다. TLS를 종료하고 수집 엔드포인트에서 mTLS(클라이언트 인증서 검증)를 강제합니다. + +```bash +helm repo add traefik https://traefik.github.io/charts +helm repo update + +helm install traefik-public traefik/traefik \ + --namespace traefik-public --create-namespace \ + --version 39.0.8 \ + -f third-party/traefik/values-public.yaml +``` + +**확인:** + +```bash +kubectl get pods -n traefik-public +``` + +예상 결과: 1개 파드가 `Running` 상태. + +```bash +kubectl get ingressclass traefik-public +``` + +예상 결과: IngressClass가 존재해야 합니다 (기본 클래스가 아님). + +**실패 시:** `kubectl describe pod -n traefik-public `으로 이미지 풀 오류나 리소스 제약을 확인하세요. + +--- + +### 1.3 Traefik 설치 -- 대시보드 컨트롤러 + +이 Traefik 인스턴스는 전용 LoadBalancer에서 대시보드를 제공하며, IP 허용 목록으로 접근을 제한합니다. + +> **이 인스턴스에는 두 가지 허용 목록 메커니즘이 제공됩니다.** 이 가이드는 이식성 있는 `service.loadBalancerSourceRanges` 필드로 접근을 제한하는 `values-dashboard.yaml`을 사용합니다. `service.beta.kubernetes.io/aws-load-balancer-source-ranges` 어노테이션을 선호하는 AWS 환경을 위해 `values-internal.yaml`도 함께 제공됩니다. 하나를 선택하여 일관되게 사용하세요. 아래 단계는 `values-dashboard.yaml`을 기준으로 설명합니다. + +**설치 전에** `third-party/traefik/values-dashboard.yaml`을 편집하여 허용된 소스 IP를 설정하세요. `loadBalancerSourceRanges` 필드는 대시보드에 접근할 수 있는 IP를 제어합니다. 기본값은 `0.0.0.0/0`(모든 IP)으로 설정되어 있으므로, VPN, 사무실 또는 알려진 이그레스 IP로 제한하세요. + +#### 단일 IP 허용 + +```yaml +service: + loadBalancerSourceRanges: + - "/32" +``` + +#### 여러 IP 허용 + +IP 또는 CIDR 블록마다 하나씩 항목을 추가하세요. `/32` 접미사는 단일 IPv4 주소를 의미하며, CIDR 블록(예: `/24`)은 범위를 의미합니다. 개별 IP와 범위를 자유롭게 혼합할 수 있습니다: + +```yaml +service: + loadBalancerSourceRanges: + - "203.0.113.10/32" # 사무실 게이트웨이 + - "203.0.113.11/32" # 예비 사무실 게이트웨이 + - "198.51.100.0/24" # VPN 풀 + - "192.0.2.50/32" # 온콜 엔지니어 자택 IP +``` + +목록 관리 시 유의 사항: + +- 줄당 하나의 항목을 유지하고 각 IP의 소유자나 목적을 `#` 주석으로 추가하세요. 이 정보는 나중에 운영자가 해당 항목이 아직 필요한지 판단하는 데 사용됩니다. +- 항상 CIDR 표기법을 사용하세요. `203.0.113.10`처럼 슬래시 없는 IP는 클라우드 제공업체에서 거부합니다. `203.0.113.10/32`를 사용하세요. +- IPv6 범위의 경우 `/128`(단일 주소) 또는 더 큰 CIDR(예: `2001:db8::1/128`)을 사용하세요. 모든 클라우드 제공업체가 IPv6 소스 범위를 지원하지는 않으므로 해당 제공업체의 LoadBalancer 문서를 확인하세요. +- 목록은 **OR** 조건입니다. 소스가 어느 항목과도 일치하면 트래픽이 허용됩니다. + +파일 편집 후 아래의 `helm install`을 진행하세요. 컨트롤러가 이미 설치되어 있다면 같은 플래그로 `helm upgrade`를 실행하거나 런타임에 Service를 직접 패치하세요 (다음 섹션 참조). + +#### 런타임에 허용 목록 업데이트 + +Helm 업그레이드 없이 Service를 직접 패치하여 허용 IP를 변경할 수 있습니다. **패치는 전체 목록을 교체합니다.** 새 IP만 포함하지 말고 유지하고 싶은 모든 IP를 반드시 포함하세요. + +새 IP 집합으로 목록을 교체하려면: + +```bash +kubectl patch svc traefik-dashboard -n traefik-dashboard \ + -p '{"spec":{"loadBalancerSourceRanges":["203.0.113.10/32","198.51.100.0/24","192.0.2.50/32"]}}' +``` + +기존 항목을 잃지 않고 IP를 안전하게 **추가**하려면 먼저 현재 목록을 읽은 후 합쳐진 집합으로 패치하세요: + +```bash +# 1. 현재 허용 목록 확인 +kubectl get svc traefik-dashboard -n traefik-dashboard \ + -o jsonpath='{.spec.loadBalancerSourceRanges}' + +# 2. 새 IP를 포함한 전체 목록으로 패치 +kubectl patch svc traefik-dashboard -n traefik-dashboard \ + -p '{"spec":{"loadBalancerSourceRanges":["/32","/32","/32"]}}' +``` + +> 런타임 패치는 `values-dashboard.yaml`에 저장되지 않습니다. 향후 Helm 업그레이드 이후에도 변경 사항을 유지하려면 값 파일도 업데이트하고 커밋하세요. + +그런 다음 설치: + +```bash +helm install traefik-dashboard traefik/traefik \ + --namespace traefik-dashboard --create-namespace \ + --version 39.0.8 \ + -f third-party/traefik/values-dashboard.yaml +``` + +**확인:** + +```bash +kubectl get pods -n traefik-dashboard +``` + +예상 결과: 1개 파드가 `Running` 상태. + +```bash +kubectl get ingressclass traefik-dashboard +``` + +예상 결과: IngressClass가 존재해야 합니다. + +--- + +### 1.4 LoadBalancer 대기 + +두 Traefik 인스턴스 모두 진행하기 전에 외부 IP가 필요합니다. + +```bash +kubectl get svc -n traefik-public +kubectl get svc -n traefik-dashboard +``` + +**확인:** 두 서비스 모두 `EXTERNAL-IP`가 표시되어야 합니다 (`` 상태가 아닌 것). + +여전히 pending 상태라면 할당을 대기하세요: + +```bash +kubectl get svc -n traefik-public -w +``` + +IP가 표시되면 `Ctrl+C`를 누르세요. IP 할당은 일반적으로 2~5분이 소요됩니다. + +**실패 시:** 10분 후에도 `` 상태이면 일반적으로 클라우드 제공업체가 LoadBalancer를 프로비저닝할 수 없는 것입니다. 서브넷 태그(EKS는 `kubernetes.io/role/elb` 필요), VPC 구성, 서비스 할당량, 내부 LB 어노테이션이 올바르게 설정되어 있는지 확인하세요. + +--- + +## Phase 2 -- 시크릿 생성 (~10분) + +모든 시크릿은 애플리케이션을 배포하기 전에 수동으로 생성합니다. 이렇게 하면 민감한 값이 매니페스트 파일에 노출되지 않습니다. + +### 2.1 네임스페이스 생성 + +```bash +kubectl create namespace agenteye +``` + +**확인:** + +```bash +kubectl get namespace agenteye +``` + +예상 결과: 상태가 `Active`. + +--- + +### 2.2 이미지 풀 시크릿 + +이 시크릿은 AgentEye 컨테이너 이미지를 가져오기 위해 `ghcr.io`에 인증합니다. PAT 생성 방법은 [enterprise-docs/github-token.md](/ko/agenteye/github-token)를 참조하세요. + +```bash +kubectl create secret docker-registry agenteye-image-pull \ + --namespace agenteye \ + --docker-server=ghcr.io \ + --docker-username=agenteye-enterprise \ + --docker-password="${AGENTEYE_TOKEN}" +``` + +**확인:** + +```bash +kubectl get secret agenteye-image-pull -n agenteye -o jsonpath='{.type}' +``` + +예상 결과: `kubernetes.io/dockerconfigjson`. + +**심층 확인** -- 토큰이 실제로 이미지를 풀할 수 있는지 확인: + +overlay의 `kustomization.yaml`에 고정된 `server` 이미지 태그를 사용하세요 (현재 번들된 `acme` overlay와 base 배포 모두 `v0.0.1-beta.48`). 릴리스 간 이 확인이 어긋나지 않도록 아래 태그를 배포할 태그로 교체하세요: + +```bash +kubectl run test-pull \ + --image=ghcr.io/agenteye-enterprise/server:v0.0.1-beta.48 \ + --overrides='{"spec":{"imagePullSecrets":[{"name":"agenteye-image-pull"}]}}' \ + --restart=Never -n agenteye --command -- echo ok + +# 풀이 완료될 때까지 몇 초 기다린 후: +kubectl logs test-pull -n agenteye +kubectl delete pod test-pull -n agenteye +``` + +예상 결과: 로그에 `ok`가 출력되어야 합니다. + +**실패 시:** `ErrImagePull` 또는 `401 Unauthorized`는 PAT가 유효하지 않거나 `read:packages` 스코프가 없는 것입니다. [enterprise-docs/github-token.md](/ko/agenteye/github-token)를 다시 확인하세요. + +--- + +### 2.3 PostgreSQL 자격 증명 + +```bash +POSTGRES_PASSWORD=$(openssl rand -hex 24) + +kubectl create secret generic agenteye-postgres \ + --namespace agenteye \ + --from-literal=POSTGRES_USER=postgres \ + --from-literal=POSTGRES_PASSWORD="${POSTGRES_PASSWORD}" \ + --from-literal=POSTGRES_DB=agenteye +``` + +> **중요:** 비밀번호 생성 시 `-base64`가 아닌 `-hex`를 사용합니다. Base64 출력에는 `+`, `/`, `=`가 포함될 수 있으며, 이는 `DATABASE_URL` 연결 문자열을 깨뜨립니다. 자세한 내용은 [enterprise-docs/troubleshooting.md](/ko/agenteye/troubleshooting)를 참조하세요. + +> **`POSTGRES_PASSWORD`를 즉시 시크릿 매니저에 저장하세요.** 백업에서 복원하거나 데이터베이스에 직접 연결할 때 필요합니다. + +**확인:** + +```bash +kubectl get secret agenteye-postgres -n agenteye +``` + +예상 결과: 시크릿이 존재해야 합니다. + +```bash +kubectl get secret agenteye-postgres -n agenteye \ + -o jsonpath='{.data.POSTGRES_PASSWORD}' | base64 -d | wc -c +``` + +예상 결과: `48` (24 hex 바이트 = 48자). + +--- + +### 2.4 관리자 API 키 + +```bash +ADMIN_KEY=$(openssl rand -hex 32) + +kubectl create secret generic agenteye-admin-key \ + --namespace agenteye \ + --from-literal=ADMIN_KEY="${ADMIN_KEY}" +``` + +관리자 키는 부트스트랩 자격 증명입니다. 서버는 시작 시마다 모든 권한으로 이 키를 upsert합니다. Phase 7에서 이 키를 사용하여 스코프가 지정된 수집기 키를 생성하세요. 전체 권한 모델은 [enterprise-docs/api-keys.md](/ko/agenteye/api-keys)를 참조하세요. + +> **`ADMIN_KEY`를 즉시 시크릿 매니저에 저장하세요.** + +**확인:** + +```bash +kubectl get secret agenteye-admin-key -n agenteye +``` + +예상 결과: 시크릿이 존재해야 합니다. + +--- + +### 2.5 인증 구성 (대시보드 로그인) + +대시보드는 사용자 로그인에 이메일 + OTP를 사용합니다. 이 시크릿이 없어도 서버는 시작되고 `ADMIN_KEY` API 경로는 계속 동작하지만, **사용자가 UI를 통해 로그인할 수 없습니다.** + +모든 키는 base 매니페스트에서 `optional: true`로 참조되므로, 일부 시크릿만 있거나 시크릿이 전혀 없어도 됩니다. 서버는 문서화된 기본값으로 폴백합니다. 모든 것을 하나의 `agenteye-auth` 시크릿으로 묶으면 인증 관련 값을 한 곳에서 교체할 수 있습니다. + +```bash +kubectl create secret generic agenteye-auth \ + --namespace agenteye \ + --from-literal=ADMIN_EMAIL="admin@yourcompany.com" \ + --from-literal=ALLOWED_EMAILS="*@yourcompany.com" \ + --from-literal=SMTP_HOST="smtp.yourprovider.com" \ + --from-literal=SMTP_PORT="587" \ + --from-literal=SMTP_USERNAME="your-smtp-user" \ + --from-literal=SMTP_PASSWORD="your-smtp-password" \ + --from-literal=SMTP_FROM="noreply@yourcompany.com" \ + --from-literal=SMTP_TLS="starttls" \ + --from-literal=DEFAULT_ORG_NAME="Acme Corp" \ + --from-literal=DEFAULT_ORG_SLUG="acme" +``` + +| 키 | 목적 | +|---|---| +| `ADMIN_EMAIL` | 부트스트랩 관리자 사용자. 시작 시마다 모든 권한으로 upsert되며, 대시보드를 통한 삭제/권한 수정이 차단됩니다. 설정하지 않으면 관리자가 시드되지 않아 첫 번째 로그인이 불가능합니다. | +| `ALLOWED_EMAILS` | 쉼표로 구분된 허용 목록. 정확한 주소(`user@example.com`)와 도메인 와일드카드(`*@example.com`)를 지원합니다. 설정하지 않으면 **사용자 로그인 또는 생성이 불가능합니다.** | +| `SMTP_HOST`, `SMTP_PORT`, `SMTP_USERNAME`, `SMTP_PASSWORD`, `SMTP_FROM` | OTP 코드 발송을 위한 SMTP 릴레이. `SMTP_HOST`가 설정되지 않으면 OTP 코드는 이메일 대신 서버 stdout에 기록됩니다 (최초 부팅 스모크 테스트에 유용). 실제 이메일 발송을 위해서는 모든 SMTP 키를 함께 제공하세요. | +| `SMTP_TLS` | `starttls`(기본값), `tls`, 또는 `none` 중 하나. | +| `DEFAULT_ORG_NAME`, `DEFAULT_ORG_SLUG` | 선택 사항. 내장된 `default` 조직에 친숙한 표시 이름과 URL 슬러그를 지정하여 `/default` 대신 `/acme`와 같은 경로에서 사용할 수 있게 합니다. **최초 부팅 시에만 적용되며**, `agenteye-orgctl org rename`으로 조직 이름을 변경하면 이후에는 무시됩니다 (§7.6 참조). 슬러그는 1~40자의 소문자 영숫자로, 중간에 단일 하이픈을 사용할 수 있습니다. 기본 `default`를 유지하려면 두 값 모두 설정하지 마세요. | + +> **SMTP 자격 증명을 시크릿 매니저에 저장하세요.** + +**확인:** + +```bash +kubectl get secret agenteye-auth -n agenteye \ + -o jsonpath='{.data}' | grep -o '"[A-Z_]*"' | sort -u +``` + +예상 결과: 입력한 키들이 출력에 나타나야 합니다. + +--- + +### 2.6 멀티 테넌트 조직 격리 키 (선택 사항) + +단일 테넌트 배포에서는 건너뛰세요. 서버는 내장된 개발용 기본값으로 실행되며, 단일 `default` 조직을 정상적으로 제공합니다. **두 번째 조직을 생성하기 전에** 강력하고 안정적인 `ORG_CH_SECRET`을 설정하세요. 각 조직의 ClickHouse 비밀번호는 `HMAC(ORG_CH_SECRET, org_id)`로 파생되므로, 공개적으로 알려진 개발용 기본값을 사용하면 조직별 자격 증명이 공개적으로 유추 가능해집니다. `agenteye-orgctl org create` 명령(§7.6 참조)은 서버가 내장된 개발용 기본값을 사용하는 동안에는 실행을 거부합니다. + +```bash +kubectl create secret generic agenteye-org-ch-secret \ + --namespace agenteye \ + --from-literal=ORG_CH_SECRET="$(openssl rand -base64 48)" + +# 서버를 롤아웃 재시작하여 새 값을 적용합니다. +kubectl -n agenteye rollout restart deployment/server +``` + +서버는 이 값을 **선택적** `secretKeyRef`로 읽으므로, 이 시크릿을 생성하지 않은 단일 테넌트 클러스터도 정상적으로 부팅됩니다. 값을 **안정적으로 유지하고 모든 레플리카에서 동일하게** 유지하세요. 교체 시 부팅 시 재조정이 사용자를 다시 프로비저닝할 때까지 모든 조직의 파생된 ClickHouse 비밀번호가 무효화됩니다 (값이 모든 곳에서 일치하는 롤링 재시작으로 복구됩니다). `deploy/base/server/secret.example.yaml`을 참조하세요. + +> **`ORG_CH_SECRET`을 시크릿 매니저에 저장하고 불필요하게 교체하지 마세요.** + +--- + +### 2.7 모든 시크릿 확인 + +```bash +kubectl get secrets -n agenteye -o custom-columns='NAME:.metadata.name,TYPE:.type' +``` + +예상 출력 (기본 시크릿 외에): + +``` +NAME TYPE +agenteye-admin-key Opaque +agenteye-auth Opaque +agenteye-image-pull kubernetes.io/dockerconfigjson +agenteye-postgres Opaque +agenteye-org-ch-secret Opaque # §2.6(멀티 테넌트)을 완료한 경우에만 +``` + +4개의 핵심 시크릿(`agenteye-admin-key`, `agenteye-auth`, `agenteye-image-pull`, `agenteye-postgres`)은 계속하기 전에 반드시 존재해야 합니다. `agenteye-org-ch-secret`은 멀티 테넌트 배포에서만 필요합니다 (§2.6 참조). + +--- + +## Phase 3 -- 애플리케이션 배포 (~5분) + +### 3.1 공용 호스트명 구성 + +cert-manager가 Let's Encrypt 인증서를 요청하려면 수집 및 대시보드 호스트명이 필요합니다. 템플릿을 복사하고 두 값을 설정하세요: + +```bash +cp base/certificates/domain.env.example base/certificates/domain.env +# base/certificates/domain.env를 편집하고 다음을 설정하세요: +# INGEST_DOMAIN=ingest.your-company.example (공용 Traefik LB로 해석됨) +# DASHBOARD_DOMAIN=agenteye.your-company.example (대시보드 Traefik LB로 해석됨) +``` + +`domain.env`는 gitignore에 포함되어 있으므로 각 배포에 로컬로 유지됩니다. 둘 중 하나라도 누락되면 kustomize 빌드가 오류를 발생시킵니다. + +> **DNS가 먼저 해석되어야 합니다.** 아직 DNS를 LB에 연결하지 않아도 됩니다 (Phase 1.2가 완료될 때까지 LB가 존재하지 않음). 하지만 단계 3.2의 ACME 발급은 각 호스트명이 해당 LoadBalancer로 해석될 때까지 재시도합니다. Phase 1.4에서 캡처한 LB 호스트명을 사용하여 지금 DNS를 설정하거나, Phase 4에서 레코드를 추가할 수 있습니다. + +--- + +### 3.2 매니페스트 적용 + +신규 설치 시 base를 직접 적용하거나, 해당 환경용 overlay가 있다면 overlay를 적용하세요 (overlay는 이미지 태그, 환경 변수, 리소스 제한만 고정하며 base의 인증서와 라우팅을 상속합니다): + +```bash +kubectl apply -k base/ +# 또는 +kubectl apply -k overlays// +``` + +overlay는 base를 자동으로 포함하므로 둘 다 적용하지 마세요. + +--- + +### 3.3 파드 대기 + +```bash +kubectl wait --for=condition=Ready pod -l 'app in (server,dashboard,postgres,clickhouse)' \ + -n agenteye --timeout=180s +``` + +대기는 핵심 데이터 플레인 파드로 범위가 지정됩니다. 선택적 `agent`(AI 어시스턴트)와 `redis` 파드는 함께 시작됩니다. 어시스턴트는 LLM 엔드포인트를 제공할 때까지 비활성 상태이고 ([enterprise-docs/assistant.md](/ko/agenteye/assistant) 참조), Redis는 최선 노력 캐시이므로, 플랫폼이 트래픽을 처리하기 위해 둘 다 Ready 상태일 필요는 없습니다. + +**확인:** + +```bash +kubectl get pods -n agenteye +``` + +예상 결과 (선택적 `agent` 및 `redis` 파드도 함께 표시되어 `Running` 상태가 됨): + +``` +NAME READY STATUS RESTARTS AGE +agent-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +clickhouse-0 1/1 Running 0 ... +dashboard-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +dashboard-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +postgres-0 1/1 Running 0 ... +redis-0 1/1 Running 0 ... +server-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +server-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +``` + +**실패 시:** + +| 파드 상태 | 가능한 원인 | 디버그 명령 | +|---|---|---| +| `ImagePullBackOff` | 이미지 풀 시크릿 또는 PAT 오류 | `kubectl describe pod -n agenteye` | +| `CrashLoopBackOff` | 잘못된 환경 변수 (예: DATABASE_URL) | `kubectl logs -n agenteye` | +| `Pending` | CPU/메모리 부족 또는 노드 없음 | `kubectl describe pod -n agenteye` (Events 확인) | + +--- + +### 3.4 스토리지 확인 + +```bash +kubectl get pvc -n agenteye +``` + +예상 결과, 두 항목 모두 `Bound` 상태: + +| PVC | 용량 | 대상 | +|---|---|---| +| `postgres-data-postgres-0` | `50Gi` | PostgreSQL 관계형/메타데이터 저장소 | +| `clickhouse-data-clickhouse-0` | `100Gi` | ClickHouse 이벤트 + 평가 분석 저장소 | + +선택적 캐시용 `redis-data-redis-0` PVC(1Gi)도 함께 표시됩니다. + +**실패 시:** `Pending`은 StorageClass가 볼륨을 프로비저닝할 수 없다는 의미입니다. `kubectl get storageclass`를 확인하고 기본값이 있는지 확인하세요. 프로덕션에서는 overlay로 ClickHouse 볼륨을 빠른 SSD StorageClass(예: AWS의 gp3, GCP의 pd-ssd)에 마운트하세요. 느린 디스크에서는 컴팩션 처리량이 저하됩니다. + +--- + +### 3.5 인증서 확인 + +```bash +kubectl get certificates -n agenteye +``` + +예상 결과: 3개 인증서, 모두 `Ready: True`: + +| 이름 | 발급자 | 목적 | +|---|---|---| +| `mtls-ca` | `selfsigned` | mTLS 클라이언트 인증서 발급을 위한 프라이빗 CA (10년 유효) | +| `ingest-tls` | `letsencrypt-prod` | 수집 엔드포인트용 공용 TLS 인증서 (90일, 자동 갱신) | +| `dashboard-tls` | `letsencrypt-prod` | 대시보드용 공용 TLS 인증서 (90일, 자동 갱신) | + +**`ingest-tls` 또는 `dashboard-tls`가 Ready 상태가 아닌 경우:** + +`kubectl describe certificate -n agenteye`를 실행하고 Events를 확인하세요. 일반적인 원인: + +- **DNS가 아직 LB를 가리키지 않음.** Let's Encrypt는 호스트명을 해석하고 포트 80에 연결하여 검증합니다 — `INGEST_DOMAIN`은 공용 LB로, `DASHBOARD_DOMAIN`은 대시보드 LB로 해석되어야 합니다. CNAME/Alias가 전파될 때까지 주문은 `pending` 상태로 유지됩니다. DNS가 올바르게 설정되면 cert-manager가 자동으로 재시도합니다 (Certificate를 삭제할 필요 없음). +- **호스트명이 치환되지 않음.** `dnsNames`가 여전히 `INGEST_DOMAIN_PLACEHOLDER` / `DASHBOARD_DOMAIN_PLACEHOLDER`로 표시되면 3.1 단계를 건너뛴 것입니다 — `base/certificates/domain.env`를 생성하고 다시 적용하세요. +- **대시보드 Traefik이 챌린지를 처리할 수 없음** (`dashboard-tls`만 해당). 대시보드 Traefik 인스턴스는 번들된 값 파일(Phase 1.2)과 함께 설치되어야 합니다. 이 파일은 cert-manager의 HTTP-01 솔버를 처리하는 스코프가 지정된 Ingress 제공자를 활성화합니다. 이 파일 없이 설치된 인스턴스는 챌린지를 라우팅할 수 없어 주문이 영원히 `pending` 상태로 남습니다. + +**`mtls-ca`가 Ready 상태가 아닌 경우:** cert-manager 자체가 비정상 상태입니다. 1.1 단계의 cert-manager 파드를 다시 확인하세요. + +--- + +### 3.6 CronJob 확인 + +```bash +kubectl get cronjobs -n agenteye +``` + +예상 결과: + +| 이름 | 스케줄 | 목적 | +|---|---|---| +| `agenteye-backup` | `0 3 * * *` | UTC 03:00에 매일 Postgres + ClickHouse 백업 | +| `cert-renewal-check` | `0 3,15 * * *` | UTC 03:00 및 15:00에 인증서 만료 알림 | + +--- + +### 3.7 서버 정상 시작 확인 + +```bash +kubectl logs -n agenteye -l app=server --tail=20 +``` + +**확인:** 서버가 포트 8080에서 수신 대기 중임을 나타내는 시작 로그를 찾으세요. 데이터베이스 연결 오류가 없어야 합니다 (서버는 Ready를 보고하기 전에 PostgreSQL과 ClickHouse 모두 도달 가능한지 확인합니다). + +**실패 시:** 가장 일반적인 원인은 URL에 안전하지 않은 문자가 포함된 `POSTGRES_PASSWORD`가 `DATABASE_URL`을 깨뜨리는 경우입니다. [enterprise-docs/troubleshooting.md](/ko/agenteye/troubleshooting)를 참조하세요. + +--- + +### 3.8 대시보드가 서버에 연결되었는지 확인 + +```bash +kubectl logs -n agenteye -l app=dashboard --tail=20 +``` + +**확인:** 출력에서 `Ready`를 찾고 `ECONNREFUSED` 또는 유사한 오류가 없는지 확인하세요. + +**실패 시:** `server` Service가 존재하는지 확인하고 (`kubectl get svc server -n agenteye`), 대시보드 배포에서 `AGENTEYE_SERVER_URL`이 `http://server:8080`으로 설정되어 있는지 확인하세요. + +--- + +## Phase 4 -- 네트워크 접근 (~5분) + +### 4.1 LoadBalancer 주소 확인 + +```bash +PUBLIC_IP=$(kubectl get svc -n traefik-public \ + -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') + +INTERNAL_IP=$(kubectl get svc -n traefik-dashboard \ + -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') +``` + +> AWS EKS에서는 LoadBalancer가 IP 대신 호스트명을 반환합니다. 위 명령에서 `.ip`를 `.hostname`으로 교체하세요. + +**확인:** + +```bash +echo "Public (ingest): $PUBLIC_IP" +echo "Internal (dashboard): $INTERNAL_IP" +``` + +두 값 모두 비어 있지 않아야 합니다. + +--- + +### 4.2 LoadBalancer에 DNS 연결 + +`base/certificates/domain.env`의 호스트명이 각 LoadBalancer로 해석되도록 DNS 레코드를 생성하세요 — `INGEST_DOMAIN`은 **공용** Traefik LB로, `DASHBOARD_DOMAIN`은 **대시보드** Traefik LB로: + +- **AWS Route 53:** `Alias = Yes`로 `A` 레코드 생성, 대상 = LB 호스트명. 일반 A → IP는 사용하지 마세요. ELB IP는 교체됩니다. +- **다른 제공업체:** 호스트명에서 LB 호스트명으로 `CNAME` 생성. + +확인: + +```bash +dig +short ingest.your-company.example +dig +short agenteye.your-company.example +``` + +각각 `$PUBLIC_IP` 및 `$INTERNAL_IP`와 동일한 주소가 반환되어야 합니다 (EKS에서는 동일한 `*.elb.amazonaws.com` 호스트명으로 해석). + +DNS가 해석되면 cert-manager는 Phase 3.5의 보류 중인 ACME 주문을 1분 이내에 완료합니다. `ingest-tls`와 `dashboard-tls` 모두 `Ready: True`가 될 때까지 `kubectl get certificates -n agenteye`를 다시 실행하세요. + +--- + +### 4.3 수집 엔드포인트 접근 + +공용 수집 엔드포인트는 상호 TLS를 강제하므로 `/health`를 포함한 모든 요청에 클라이언트 인증서가 필요합니다. 첫 번째 클라이언트 인증서는 Phase 5에서 발급합니다. 이미 인증서가 있다면 지금 접근 가능 여부를 확인하세요: + +```bash +curl -s --cert issued//client.crt \ + --key issued//client.key \ + https://ingest.your-company.example/health +``` + +예상 결과: `{"status":"ok"}`. `-k`는 필요하지 않습니다 — 서버 인증서는 `INGEST_DOMAIN`에 대해 공용 CA에 체인되어 있으므로 시스템 신뢰 저장소에서 검증됩니다. 원시 LoadBalancer IP/호스트명이 아닌 `INGEST_DOMAIN` 호스트명으로 수집 엔드포인트에 접근하세요 (발급된 인증서와 호스트명이 일치해야 함). + +대시보드 엔드포인트는 `DASHBOARD_DOMAIN`에서 공개 신뢰 인증서로 제공되며 mTLS 뒤에 있지 않으므로, `-k`와 클라이언트 인증서가 필요하지 않습니다: + +```bash +curl -s https://agenteye.your-company.example/ -o /dev/null -w '%{http_code}\n' +``` + +원시 LB 주소가 아닌 호스트명으로 대시보드에 접근하세요 — 인증서는 `DASHBOARD_DOMAIN`에 바인딩되어 있으므로 원시 주소는 인증서 이름 불일치를 표시합니다. + +**실패 시:** `curl`이 멈추면 해당 머신에서 LB에 접근 가능한지 확인하세요 (VPN, 보안 그룹, 방화벽 규칙). 수집 호스트명에서 `certificate required` 핸드셰이크 오류는 클라이언트 인증서가 제공되지 않은 것입니다. Phase 5를 먼저 완료하세요. 수집 호스트명에서 TLS 유효성 검사 오류는 서버 인증서 발급이 완료되지 않은 것입니다. Phase 3.5로 돌아가서 해결하세요. + +--- + +## Phase 5 -- mTLS 클라이언트 인증서 발급 (~클러스터당 10분) + +수집기는 **두 가지 요소**로 인증합니다: 클라이언트 인증서(전송 계층, 요청이 승인된 클러스터에서 온 것을 증명)와 API 키(애플리케이션 계층, 요청이 `events:add` 권한을 가진 수집기에서 온 것을 증명). 유출된 키는 인증서 없이 쓸모없고, 도난당한 인증서는 유효한 키 없이 쓸모없습니다. + +### 5.1 인증서 발급 + +수집기를 실행하는 각 클러스터에는 고유한 클라이언트 인증서가 필요합니다. 매니페스트 디렉터리에서: + +```bash +cd base/certificates/client-certs +./issue-client-cert.sh +``` + +``을 의미 있는 식별자(예: `us-east-1-prod`, `staging`)로 교체하세요. + +**확인:** 스크립트가 `==> Done!`을 출력하고 출력 파일 목록을 나열합니다. + +```bash +kubectl get certificate mtls-client- -n agenteye +``` + +예상 결과: `Ready: True`. + +`issued//`의 출력 파일: + +| 파일 | 목적 | +|---|---| +| `client.crt` | 클라이언트 인증서 (90일 유효) | +| `client.key` | 클라이언트 개인 키 | +| `ca.crt` | 서버 검증을 위한 CA 인증서 | +| `collector-mtls-secret.yaml` | 수집기 클러스터에 바로 적용 가능한 Kubernetes Secret | + +--- + +### 5.1b 대체 전달 방법: AWS Secrets Manager + +인증서 소비자가 `client.crt`와 `client.key`를 디스크에 필요로 하는 Kubernetes Pod인 경우 — agenteye-collector를 애플리케이션 파드의 사이드카로 실행할 때의 일반적인 경우 — 인증서 번들을 AWS Secrets Manager에 저장하세요. 그러면 애플리케이션 파드는 IRSA와 함께 [Secrets Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/)를 통해 마운트하고, 인증서 교체가 자동으로 처리됩니다. + +```bash +cd base/certificates/client-certs +export AWS_REGION=us-east-1 # 워크로드가 실행되는 리전 +./issue-client-cert.sh --save-to aws-secrets-manager +``` + +재실행(갱신) 시 스크립트는 동일한 시크릿에 `PutSecretValue`를 호출하므로 ARN과 이름이 안정적으로 유지됩니다. CSI Driver는 다음 교체 폴링 시 새 버전을 가져와 파드 내부 파일을 덮어씁니다. + +**사전 요구 사항:** + +- AWS 계정에 인증된 `aws` CLI v2. +- `jq` 설치됨. +- `AWS_REGION` 환경 변수 설정됨. +- 호출자 ID의 IAM 권한 (`Resource`를 `arn:aws:secretsmanager:::secret:agenteye/mtls-client/*`로 제한): + - `secretsmanager:CreateSecret` + - `secretsmanager:DescribeSecret` + - `secretsmanager:PutSecretValue` + - `secretsmanager:TagResource` + +**이 모드에서 스크립트가 하는 작업:** + +| 단계 | 작업 | +|---|---| +| 1 | cert-manager를 통해 인증서를 발급/재추출합니다 (기본 모드와 동일). | +| 2 | `agenteye/mtls-client/`에서 `DescribeSecret`을 호출하여 생성 또는 업데이트를 결정합니다. | +| 3 | 최초 실행: 세 개의 키 JSON 페이로드(`client.crt`, `client.key`, `ca.crt`)와 `AgentEyeCluster=` 태그로 `CreateSecret`. 이후 실행: 새 버전을 게시하는 `PutSecretValue`; `TagResource`로 태그 갱신. | +| 4 | 성공적인 업로드 후에만 `issued//`를 삭제합니다. 실패 시 디렉터리를 보존하여 재시도할 수 있습니다. | + +**시크릿이 삭제 예정인 경우**, 스크립트는 재시도 전에 `aws secretsmanager restore-secret --secret-id agenteye/mtls-client/`을 실행하라는 명확한 오류 메시지와 함께 실패합니다. + +전체 파드 연결 설정(SecretProviderClass, IRSA 설정, 교체 동작, 문제 해결)은 [enterprise-docs/single-pod-deployment.md](/ko/agenteye/single-pod-deployment)를 참조하세요. + +--- + +### 5.2 인증서 동작 확인 + +mTLS 인그레스에 발급된 인증서를 테스트하세요: + +```bash +curl -sk --cert issued//client.crt \ + --key issued//client.key \ + https://${PUBLIC_IP}/health +``` + +예상 결과: `{"status":"ok"}` + +**실패 시:** + +| 오류 | 원인 | 해결 방법 | +|---|---|---| +| `certificate required` | 인증서가 제공되지 않음 | `curl` 명령의 파일 경로 확인 | +| `bad certificate` | CA 불일치 | `mtls-ca-issuer`가 인증서를 발급했는지 확인: `kubectl describe certificate mtls-client- -n agenteye` | +| `connection refused` | 잘못된 호스트명 또는 LB에 접근 불가 | `/etc/hosts` 또는 DNS 확인 | + +--- + +### 5.3 수집기 클러스터에 전달 + +`collector-mtls-secret.yaml`을 수집기 클러스터를 운영하는 팀에 전달하세요. 팀은 이를 적용합니다: + +```bash +kubectl apply -f collector-mtls-secret.yaml -n +``` + +그런 다음 수집기가 시크릿을 마운트하고 인증서 경로를 사용하도록 구성하세요: + +```json +{ + "tls_cert": "/etc/agenteye/tls/client.crt", + "tls_key": "/etc/agenteye/tls/client.key" +} +``` + +Kubernetes 볼륨 마운트를 포함한 완전한 수집기 설정은 [enterprise-docs/collector-installation.md](/ko/agenteye/collector-installation)를 참조하세요. + +**확인 (수집기 클러스터에서):** + +```bash +kubectl get secret agenteye-collector-mtls -n +``` + +예상 결과: 3개의 데이터 키(`client.crt`, `client.key`, `ca.crt`)를 가진 시크릿이 존재해야 합니다. + +--- + +### 5.4 인증서 수명 주기 + +| 속성 | 값 | +|---|---| +| 클라이언트 인증서 유효 기간 | 90일 | +| 자동 갱신 | cert-manager가 만료 15일 전에 갱신 | +| CA 유효 기간 | 10년 | +| 만료 알림 | CronJob이 만료 30일 전에 알림 (Phase 6) | + +cert-manager는 **AgentEye 클러스터**에서 인증서를 자동으로 갱신하지만, 갱신된 인증서는 수집기 클러스터에 다시 전달해야 합니다. 이전 인증 \ No newline at end of file diff --git a/docs/ko/agenteye/managed-deployment.mdx b/docs/ko/agenteye/managed-deployment.mdx new file mode 100644 index 00000000..a08edbbe --- /dev/null +++ b/docs/ko/agenteye/managed-deployment.mdx @@ -0,0 +1,170 @@ +--- +title: "Kubernetes 클러스터에서의 Managed Deployment" +description: "Kubernetes 클러스터에서의 AgentEye Managed Deployment 문서입니다." +--- + +AgentEye는 AI 및 LLM 에이전트를 위한 셀프 호스팅 관찰 가능성(observability) 및 평가 플랫폼입니다. 에이전트 세션, 도구 호출, 모델 요청, 오류를 캡처하여 검색 가능한 분석 및 평가로 변환하고, 선택적 읽기 전용 AI 어시스턴트가 포함된 대시보드에 결과를 표시합니다. + +Managed Deployment 모델에서는 전용 Kubernetes 클러스터를 제공하면 Exosphere가 그 안에서 전체 플랫폼을 운영합니다. 모든 컴포넌트의 배포, 구성, 운영, 백업, 업그레이드를 Exosphere가 대신 처리합니다. 팀은 데이터베이스, 인증서, 업그레이드를 직접 관리하지 않고도 플랫폼의 가치(에이전트 가시성, 분석, 평가, 선택적 어시스턴트)를 누릴 수 있습니다. 모든 데이터는 여러분의 클라우드 계정 내에 유지됩니다. + +--- + +## 사전 요구 사항 + +- 컨테이너 이미지 가져오기 및 아티팩트 다운로드를 위한 **GitHub PAT** ([GitHub Token 설정](/ko/agenteye/github-token) 참조) +- **전용 Kubernetes 클러스터** (아래 요구 사항 참조) +- 데이터베이스 백업을 위한 **스토리지 버킷** +- **네트워크 연결**: 클러스터 로드 밸런서로의 인바운드 포트 443 + +--- + +## 1단계: 전용 Kubernetes 클러스터 프로비저닝 + +AgentEye 전용 Kubernetes 클러스터를 생성합니다. 다른 워크로드와 공유하지 않아야 하며, 전체 플랫폼(애플리케이션 서비스, 데이터베이스, 분석, 캐싱)이 기존 인프라에 영향을 주지 않고 격리된 환경에서 실행됩니다. + +| 요구 사항 | 세부 사항 | +|---|---| +| **배포판** | EKS, GKE, AKS 또는 자체 관리형 등 표준 규격을 준수하는 Kubernetes | +| **버전** | 1.27 이상 | +| **노드 풀** | 최소 사양: **노드 3개, 각 4 vCPU / 8 GB RAM** (표준 범용 인스턴스) | +| **스토리지** | 블록 볼륨을 프로비저닝하는 기본 StorageClass (예: AWS의 `gp3`, GCP의 `pd-ssd`) | +| **로드 밸런서** | 클러스터가 클라우드 LoadBalancer 서비스를 프로비저닝할 수 있어야 함 (EKS, GKE, AKS 기본 지원) | + +> Exosphere는 클러스터 내부의 나머지 모든 것을 설치하고 관리합니다: 인그레스 컨트롤러, TLS 인증서, 데이터베이스, 캐싱, 모니터링, 모든 애플리케이션 배포. + +--- + +## 2단계: AgentEye 팀에 접근 권한 부여 + +Exosphere는 네임스페이스, 커스텀 리소스 정의, 인그레스 컨트롤러, 스토리지 프로비저너를 관리하기 위해 cluster-admin 권한(또는 동등한 광범위한 RBAC)이 필요합니다. + +| 요구 사항 | 세부 사항 | +|---|---| +| **접근 방법** | IAM 역할 (EKS/GKE에 권장), kubeconfig, 또는 SSO 기반 접근 | +| **VPN / 배스천** | Kubernetes API 서버가 비공개인 경우 Exosphere 운영 팀을 위한 VPN 자격 증명 또는 배스천 접근 제공 | + +--- + +## 3단계: 네트워크 연결 구성 + +네트워크 팀에서 클러스터 로드 밸런서의 **포트 443**으로의 인바운드 트래픽을 허용해야 합니다. 배포는 두 개의 별도 로드 밸런서를 운영합니다: 하나는 이벤트 수집(mTLS 보호)용, 다른 하나는 대시보드용입니다. + +| 트래픽 | 출발지 | 목적지 | 보안 | +|---|---|---|---| +| **이벤트 수집** | 클러스터의 Collector 파드 | Ingest LoadBalancer, 포트 443 | mTLS (클라이언트 인증서) + API 키 | +| **대시보드** | 개발자 브라우저 | Dashboard LoadBalancer, 포트 443 | 도메인의 HTTPS, 패스워드리스 이메일 OTP 로그인 | + +수집 엔드포인트는 상호 TLS로 보호됩니다. Collector는 모든 요청 시 유효한 클라이언트 인증서 **및** 유효한 API 키를 함께 제시해야 합니다. 대시보드는 자체 로드 밸런서와 호스트네임에서 실행되며, 허용 목록에 등록된 이메일 주소/도메인만 로그인이 가능합니다. + +**DNS 레코드 (최초 1회):** 관리하는 도메인 하위에 두 개의 CNAME 레코드를 생성합니다 — 하나는 수집 엔드포인트용, 하나는 대시보드용 (예: `agenteye.your-company.example`) — Exosphere가 제공하는 로드 밸런서 호스트네임을 가리킵니다. 이후 Exosphere가 두 호스트네임에 대해 공개적으로 신뢰받는 TLS 인증서를 자동으로 프로비저닝하며 갱신도 포함됩니다. + +> **포트 80 참고:** 자동 인증서 발급 및 갱신은 각 로드 밸런서의 포트 80을 통한 HTTP로 유효성을 검사합니다. 보안 정책상 대시보드 로드 밸런서를 회사 IP 범위로 제한해야 하는 경우 Exosphere에 먼저 알려주세요 — DNS 기반 인증서 검증 방식으로 전환하여 (고객 측에서 DNS 레코드 하나 추가) 제한된 환경에서도 갱신이 계속 작동하도록 합니다. + +> **아웃바운드:** 클러스터 노드는 `ghcr.io`에서 컨테이너 이미지를 가져오기 위해 인터넷 접근이 필요합니다. 아웃바운드 트래픽을 제한하는 네트워크 환경이라면 `ghcr.io`를 허용 목록에 추가하거나 내부 레지스트리로 이미지를 미러링하세요. + +--- + +## 4단계: 백업 스토리지 버킷 제공 + +데이터베이스 백업은 고객이 소유한 클라우드 스토리지 버킷에 저장됩니다. + +| 요구 사항 | 세부 사항 | +|---|---| +| **서비스** | S3 (AWS), GCS (GCP), 또는 Azure Blob Storage | +| **접근 권한** | IAM 역할(IRSA on EKS, Workload Identity on GKE)을 통해 클러스터 노드에 쓰기 권한 부여 또는 자격 증명 제공 | +| **보존 기간** | 버킷의 수명 주기 정책(보존 기간, 아카이브 규칙)은 고객이 직접 제어합니다. Exosphere는 백업을 기록하고, 보존 기간은 고객이 결정합니다 | + +하루에 한 번 PostgreSQL(관계형 상태)과 ClickHouse(이벤트 및 평가) 모두를 하나의 압축 아카이브로 덤프하여 버킷에 업로드합니다. 업그레이드 전에도 백업이 실행됩니다. + +--- + +## 5단계: 담당자 지정 + +클러스터 수준 문제(노드 상태, 클라우드 계정 한도, 네트워크 변경)에 대응할 담당자 1인 또는 Slack/Teams 채널을 지정해 주세요. 일상적인 운영에서는 이 담당자의 개입이 필요하지 않습니다. + +--- + +## 배포 컴포넌트 + +Exosphere가 클러스터 접근 권한을 확보하면 다음 컴포넌트들이 배포되고 관리됩니다. + +| 컴포넌트 | 역할 | +|---|---| +| **AgentEye Server** | Collector로부터 이벤트를 수신하고, 분석을 실행하며, 대시보드에 데이터를 제공하는 HTTP API | +| **대시보드** | 에이전트 세션, 도구 호출, 모델 요청, 오류를 조회하는 웹 인터페이스; 선택적 읽기 전용 AI 어시스턴트 호스팅 | +| **ClickHouse** | 수집된 이벤트, 분석, 평가를 위한 필수 정규 스토어 | +| **PostgreSQL** | 조직, API 키, 사용자, 대시보드, 저장된 쿼리를 위한 관계형 스토어 | +| **Redis** | 선택적 공유 캐시 및 속도 제한 백엔드; 사용 불가 시 플랫폼이 우아하게 성능 저하됨 | +| **AI 어시스턴트 (선택)** | 내부 읽기 전용 어시스턴트 컨테이너; LLM 엔드포인트가 구성될 때까지 비활성 상태 유지 | +| **인그레스 컨트롤러** | 두 개의 로드 밸런서 (mTLS 보호 수집용 및 대시보드용): 공개적으로 신뢰받는 자동 갱신 인증서로 TLS를 종료하고 수집 엔드포인트에 mTLS 적용 | +| **cert-manager** | TLS 인증서 프로비저닝 및 mTLS 클라이언트 인증서 발급 자동화 | +| **인증서 모니터링** | 예약 작업이 인증서 만료를 확인하고 갱신 시점이 다가오면 알림 전송 (예: Slack) | + +Managed 제공에는 에이전트 활동을 평가 기준에 따라 점수화하는 플랫폼의 평가 파이프라인 운영도 포함됩니다. 이 기능들이 제공하는 내용은 [어시스턴트](/ko/agenteye/assistant) 및 [평가 스위트](/ko/agenteye/evaluation-suite)를 참조하세요. + +--- + +## 제공 항목 + +배포 완료 후 다음 항목을 받게 됩니다. + +| 항목 | 세부 사항 | +|---|---| +| **대시보드 URL** | 고객 도메인 하위의 호스트네임 (예: `https://agenteye.your-company.example`), 공개적으로 신뢰받는 자동 갱신 TLS 인증서로 제공. 제공된 로드 밸런서 호스트네임으로 CNAME 하나를 생성하면 되며, 로그인은 패스워드리스 이메일 OTP 방식 | +| **Collector 엔드포인트** | 수집 호스트네임의 `/events` 경로 (예: `https://ingest.your-company.example/events`), mTLS 보호 | +| **클라이언트 인증서 번들** | 클러스터별: 클라이언트 인증서, 개인 키, CA 인증서가 Kubernetes Secret 매니페스트로 전달됨. 클러스터당 한 번만 적용 | +| **GitHub PAT** | Collector 바이너리 및 Python SDK 패키지 다운로드용 | +| **Collector API 키** | `events:add` 권한을 가진 범위 한정 키, Collector 배포당 하나 | +| **설치 가이드** | Collector 및 Python SDK에 대한 단계별 문서 | + +--- + +## 설정 이후 할 일 + +이후 지속적인 작업은 AgentEye 클러스터가 아닌 고객의 에이전트 머신에서만 이루어집니다. + +1. AI 에이전트를 실행하는 각 Kubernetes 클러스터에 **Collector를 설치**합니다: 클라이언트 인증서를 마운트하고 엔드포인트 URL 및 API 키를 설정합니다. [Collector 설치](/ko/agenteye/collector-installation)를 참조하세요. +2. 에이전트 코드에 **Python SDK를 통합**합니다. [Python SDK](/ko/agenteye/python-sdk)를 참조하세요. +3. 브라우저에서 **대시보드를 열어** 에이전트 활동을 확인합니다. + +클러스터 운영, 데이터베이스 관리, 인증서 갱신, 업그레이드 — 모두 필요 없습니다. + +--- + +## 보안 + +- **데이터는 클라우드 계정 내에 유지됩니다.** 클러스터, 스토리지, 데이터베이스 모두 고객 환경에서 실행됩니다. 데이터가 경계 밖으로 나가지 않습니다. +- **접근 권한은 고객이 제어합니다.** 클러스터는 고객 계정에 있습니다. Exosphere의 접근을 언제든지 감사, 모니터링, 철회할 수 있습니다. 모든 작업은 클라우드 감사 로그(CloudTrail, GCP Audit Logs 등)를 통해 기록됩니다. +- **이벤트 수집에 mTLS 적용.** 모든 Collector 요청은 유효한 클라이언트 인증서와 API 키를 모두 필요로 합니다. 키가 유출되어도 인증서 없이는 무용지물이며, 인증서를 탈취해도 유효한 키 없이는 사용할 수 없습니다. +- **대시보드 접근 제어.** 대시보드는 이벤트 수집과 분리된 자체 로드 밸런서에서 실행되며, 로그인은 허용 목록에 등록된 이메일 주소/도메인으로 제한된 패스워드리스 이메일 OTP 방식입니다. 로드 밸런서의 IP 소스 범위 허용 목록은 요청 시 제공됩니다. 자동 인증서 갱신이 로드 밸런서에 도달해야 하므로 Exosphere는 제한과 함께 DNS 기반 인증서 검증으로 전환하여 제한 환경에서도 갱신이 계속 작동하도록 합니다. +- **클러스터별 인증서.** 각 클러스터는 고유한 클라이언트 인증서를 받습니다. 한 클러스터가 침해되더라도 해당 인증서만 독립적으로 폐기되며 다른 클러스터에는 영향이 없습니다. + +--- + +## 배포 일정 + +| 단계 | 소요 시간 | 고객 참여 | +|---|---|---| +| **클러스터 프로비저닝** | 1~2일 | 클러스터 프로비저닝 및 Exosphere 접근 권한 부여 | +| **플랫폼 설정** | 1일 | 없음; Exosphere가 모든 인프라 컴포넌트 설치 | +| **애플리케이션 배포** | 1일 | 없음; Exosphere가 서버, 대시보드 배포 및 API 키 생성 | +| **Collector 롤아웃** | 1~3일 | 클러스터에 Collector 설치 (Exosphere 가이드 지원) | +| **프로덕션 번인** | 1주일 | 없음; Exosphere가 모니터링 및 튜닝 | + +킥오프부터 프로덕션 준비 완료까지 일반적으로 **약 2주** 소요됩니다. + +--- + +## 지원 + +문의 사항이나 이슈가 있으면 `support@exosphere.host`로 Exosphere에 연락하세요. + +--- + +## 다음 단계 + +- [시작하기](/ko/agenteye/getting-started): 엔드투엔드 안내 +- [Collector 설치](/ko/agenteye/collector-installation): Collector 설치 및 구성 +- [Python SDK](/ko/agenteye/python-sdk): 에이전트 코드 계측 +- [API 키](/ko/agenteye/api-keys): 접근 및 권한 관리 +- [트러블슈팅](/ko/agenteye/troubleshooting): 일반적인 문제 및 해결 방법 \ No newline at end of file diff --git a/docs/ko/agenteye/python-sdk.mdx b/docs/ko/agenteye/python-sdk.mdx new file mode 100644 index 00000000..679bfcc1 --- /dev/null +++ b/docs/ko/agenteye/python-sdk.mdx @@ -0,0 +1,383 @@ +--- +title: "Python SDK" +description: "AgentEye Python SDK 문서." +--- + + +AgentEye Python SDK는 에이전트의 동작(모든 에이전트 실행, 도구 호출, 모델 요청, 훅, 사람의 개입)에 대한 완전한 가시성을 제공하여 디버깅, 감사, 평가를 수행할 수 있게 해줍니다. 에이전트 코드를 계측하여 구조화된 이벤트를 로컬 JSONL 파일에 기록하며, 수집기 데몬이 이를 자동으로 플랫폼에 전송합니다. + +--- + +## 설치 + +`AGENTEYE_TOKEN`을 사용하여 GitHub Releases에서 wheel 파일을 다운로드합니다. 아직 토큰이 없다면 [GitHub Token Setup](/ko/agenteye/github-token)에서 설정 단계와 필요한 권한을 확인하세요. + +**`gh` CLI + pip 사용:** + +```bash +VERSION=0.0.1b9 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "python-sdk/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-*.whl' +pip install "agenteye-${VERSION}-py3-none-any.whl" +``` + +**`gh` CLI + uv 사용:** + +```bash +VERSION=0.0.1b9 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "python-sdk/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-*.whl' +uv add "./agenteye-${VERSION}-py3-none-any.whl" +``` + +**curl 사용 (`gh` CLI 없이):** + +```bash +VERSION=0.0.1b9 +curl -fsSL \ + -H "Authorization: Bearer $AGENTEYE_TOKEN" \ + -L \ + "https://github.com/agenteye-enterprise/releases/releases/download/python-sdk%2Fv${VERSION}/agenteye-${VERSION}-py3-none-any.whl" \ + -o "agenteye-${VERSION}-py3-none-any.whl" +pip install "agenteye-${VERSION}-py3-none-any.whl" +``` + +--- + +## 빠른 시작 + +```python +import agenteye + +agenteye.configure(environment="production") + +agenteye.event.agent_start(session_id="run-001", agent_id="planner", goal="answer user query") + +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", + input={"query": "latest AI research"}, +) + +agenteye.event.tool_result( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", + output={"results": ["..."]}, +) + +agenteye.event.agent_end(session_id="run-001", agent_id="planner", outcome="success") +``` + +--- + +## configure() + +```python +agenteye.configure( + base_dir=None, # Path | str | None. 기본값: $AGENTEYE_HOME 또는 ~/.agenteye + flush_interval=0.5, # float, 플러시 주기(초) + environment=None, # str | None. 배포 환경 레이블 +) +``` + +`event.*` 호출 전에 한 번만 실행하세요. 생략해도 안전하며, 기본값으로 즉시 동작합니다. 모든 인수는 키워드 전용이므로 위와 같이 이름으로 전달해야 합니다. + +`base_dir`가 `None`(기본값)인 경우, SDK는 `$AGENTEYE_HOME`이 설정되어 있으면 해당 값을 사용하고, 그렇지 않으면 `~/.agenteye`로 폴백합니다. 이는 수집기 자체의 경로 결정 방식과 동일하므로, `AGENTEYE_HOME` 환경 변수 하나로 SDK와 수집기 양쪽의 공유 이벤트 스풀을 설정할 수 있습니다. 두 프로세스가 스풀 경로에 동의해야 하는 사이드카/단일 파드 배포에서 필수적입니다. + +--- + +## 환경(Environment) + +모든 이벤트에 배포 환경(`production`, `staging`, `qa`, `canary` 등)을 레이블로 지정합니다. 한 번만 설정하면 SDK가 모든 이벤트에 자동으로 첨부합니다. + +**방법 1: `configure()`를 통해:** + +```python +agenteye.configure(environment="production") +``` + +**방법 2: 환경 변수를 통해:** + +```bash +export AGENTEYE_ENVIRONMENT=production +``` + +**우선순위:** `configure(environment=...)`가 환경 변수보다 우선합니다. 둘 다 설정되지 않은 경우 `"dev"`가 기본값입니다. + +환경 값은 대시보드에서 1급 필터로 표시되며, 빠른 쿼리를 위해 서버의 인덱스된 컬럼에 저장됩니다. + +**제약:** 환경 값에는 **리터럴 `,` 쉼표가 포함되어서는 안 됩니다**. 대시보드 필터는 쉼표로 구분된 다중 선택을 와이어에서 사용하므로(`?environment=prod,staging`), `prod,blue`처럼 쉼표가 포함된 환경 이름은 두 개의 값으로 분리됩니다. 쉼표가 포함된 환경의 이벤트는 수집 시 거부됩니다. + +--- + +## 이벤트 레퍼런스 + +모든 이벤트 메서드에는 다음 두 필드가 필요합니다: + +| 필드 | 타입 | 설명 | +|---|---|---| +| `session_id` | `str` | 최상위 에이전트 실행을 식별합니다 | +| `agent_id` | `str` | 세션 내에서 이벤트를 발생시킨 에이전트를 식별합니다 | + +모든 메서드는 커스텀 메타데이터를 위한 임의의 `**kwargs`도 허용합니다([커스텀 필드](#custom-fields) 참조). + +--- + +### `event.agent_start()` + +에이전트가 작업을 시작할 때 발생합니다. + +```python +agenteye.event.agent_start( + session_id="run-001", + agent_id="planner", + goal="answer user query", # str | None + parent_id=None, # str | None - 중첩 에이전트의 경우 부모 agent_id +) +``` + +--- + +### `event.agent_end()` + +에이전트가 작업을 완료할 때 발생합니다. + +```python +agenteye.event.agent_end( + session_id="run-001", + agent_id="planner", + outcome="success", # str | None + summary="Answered query", # str | None +) +``` + +--- + +### `event.tool_use()` + +에이전트가 도구를 호출할 때 발생합니다. `tool_result`와 쌍으로 사용하며, SDK가 `duration_ms`를 자동으로 계산합니다. + +```python +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="web_search", # str, 필수 + tool_call_id="toolu_01", # str, 필수 - 대응하는 tool_result와의 상관 키 + input={"query": "..."}, # dict | None +) +``` + +--- + +### `event.tool_result()` + +도구가 반환될 때 발생합니다. `tool_call_id`를 통해 `tool_use`와 연관됩니다. + +```python +agenteye.event.tool_result( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", # 이전 tool_use와 일치해야 함 + output={"results": ["..."]}, # Any | None + error=None, # str | None - 도구에서 예외가 발생한 경우 설정 + # duration_ms는 자동으로 계산됩니다 - 전달하지 마세요 +) +``` + +--- + +### `event.model_request()` + +LLM에 프롬프트를 전송하기 직전에 발생합니다. + +```python +agenteye.event.model_request( + session_id="run-001", + agent_id="planner", + model="claude-sonnet-4-6", # str | None + messages=[ # list[dict] | None - 대화 턴 + {"role": "user", "content": "..."}, + ], + system="You are helpful.", # Any | None - 문자열 또는 콘텐츠 블록 리스트 + tools=[ # list[dict] | None - 모델에 제공되는 도구 스키마 + {"name": "search", "input_schema": {"type": "object"}}, + ], +) +``` + +`messages` 항목은 일반 문자열 `content` 또는 Anthropic 스타일의 블록 리스트 `content`를 모두 허용합니다. 샘플링 파라미터(`temperature`, `max_tokens` 등)는 추가 kwargs로 전달할 수 있습니다. + +--- + +### `event.model_response()` + +LLM이 응답을 반환할 때 발생합니다. + +```python +agenteye.event.model_response( + session_id="run-001", + agent_id="planner", + model="claude-sonnet-4-6", # str | None + stop_reason="end_turn", # str | None + input_tokens=1024, # int | None + output_tokens=256, # int | None + content=[ # Any | None - 문자열 또는 콘텐츠 블록 리스트 + {"type": "text", "text": "..."}, + ], + role="assistant", # str | None +) +``` + +`content`는 일반 문자열(일반 공급자) 또는 Anthropic 스타일의 콘텐츠 블록 리스트를 모두 허용합니다. 도구 호출은 `{"type": "tool_use", ...}` 블록으로 `content` 안에 포함되며, 별도의 `tool_calls` 필드는 없습니다. + +--- + +### `event.hook_triggered()` + +훅이 실행될 때 발생합니다. `hook_completed`와 쌍으로 사용하며, SDK가 `duration_ms`를 자동으로 계산합니다. + +```python +agenteye.event.hook_triggered( + session_id="run-001", + agent_id="planner", + hook_name="pre_tool_use", # str, 필수 + hook_id="hook-abc", # str, 필수 - 상관 키 + trigger_event="tool_use", # str | None + input={"tool": "search"}, # Any | None +) +``` + +--- + +### `event.hook_completed()` + +훅이 완료될 때 발생합니다. `hook_id`를 통해 `hook_triggered`와 연관됩니다. + +```python +agenteye.event.hook_completed( + session_id="run-001", + agent_id="planner", + hook_name="pre_tool_use", + hook_id="hook-abc", # 이전 hook_triggered와 일치해야 함 + outcome="allow", # str | None + output=None, # Any | None + error=None, # str | None + # duration_ms는 자동으로 계산됩니다 - 전달하지 마세요 +) +``` + +--- + +### `event.error()` + +처리되지 않은 오류가 발생할 때 발생합니다. + +```python +agenteye.event.error( + session_id="run-001", + agent_id="planner", + error_type="TimeoutError", # str, 필수 + message="timed out", # str, 필수 + traceback="Traceback...", # str | None +) +``` + +--- + +## Human-in-the-Loop 이벤트 + +Human-in-the-loop 이벤트는 사람이 에이전트 실행에 개입하는 순간(승인 대기, 입력 제공, 일시 정지, 에이전트 중단)에 대한 감시를 제공합니다. 인간이 응답하는 데 걸리는 시간을 측정하고(SDK가 쌍을 이룬 이벤트에서 `duration_ms`를 자동 계산), 에이전트를 일시 정지하거나 중단한 사람을 감사하며, 대시보드에 표시되는 승인 및 감시 워크플로를 구축할 수 있습니다. + +### `event.human_wait()` + +에이전트가 사람의 입력을 기다리며 실행을 일시 정지할 때 발생합니다. `human_input`과 쌍으로 사용하며, SDK가 `duration_ms`(사람이 응답하는 데 걸린 시간)를 자동으로 계산합니다. + +```python +agenteye.event.human_wait( + session_id="run-001", + agent_id="planner", + input_id="inp-abc", # str, 필수 - 대응하는 human_input과의 상관 키 + prompt="Do you approve this action?", # str | None - 사람에게 표시되는 질문 + options=["approve", "reject", "defer"], # list[str] | None - 사람에게 제시되는 선택지 + reason="approval_required", # str | None - 에이전트가 대기하는 이유 +) +``` + +### `event.human_input()` + +사람이 입력을 제공하고 에이전트가 재개될 때 발생합니다. `input_id`를 통해 `human_wait`와 연관됩니다. `duration_ms`는 자동으로 계산되므로 호출자가 전달해서는 안 됩니다. + +```python +agenteye.event.human_input( + session_id="run-001", + agent_id="planner", + input_id="inp-abc", # str, 필수 - 이전 human_wait와 일치해야 함 + response="approve", # str | None - 사람의 답변 (자유 텍스트 또는 선택된 옵션) + # duration_ms는 자동으로 계산됩니다 - 전달하지 마세요 +) +``` + +### `event.human_pause()` + +사람이 에이전트를 능동적으로 일시 정지할 때 발생합니다(예: 대시보드 컨트롤을 통해). 에이전트는 중단되지 않고 일시 중단됩니다. + +```python +agenteye.event.human_pause( + session_id="run-001", + agent_id="planner", + reason="user_requested", # str | None + user_id="usr_42", # str | None - 에이전트를 일시 정지한 사람 +) +``` + +### `event.human_interrupt()` + +사람이 에이전트 실행 도중 능동적으로 중단시킬 때 발생합니다. `human_pause`와 달리, 에이전트의 작업이 일시 중단이 아닌 종료됩니다. + +```python +agenteye.event.human_interrupt( + session_id="run-001", + agent_id="planner", + reason="output_incorrect", # str | None + user_id="usr_42", # str | None - 에이전트를 중단시킨 사람 + at_step="tool_use:web_search", # str | None - 중단 시점에 에이전트가 수행 중이던 작업 +) +``` + +--- + +## 커스텀 필드 + +추가 키워드 인수는 표준 필드 뒤에 이벤트에 추가됩니다: + +```python +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="db_query", + tool_call_id="toolu_02", + tenant_id="acme", # 커스텀 필드 + region="us-east-1", # 커스텀 필드 +) +``` + +`timestamp`, `type`, `environment`는 예약된 이름으로, 커스텀 필드로 전달하면 `ValueError`(`Reserved field names cannot be used as custom fields: [...]`)가 발생합니다. `session_id`와 `agent_id`는 모든 이벤트 메서드의 필수 파라미터이므로 두 번 제공할 수 없으며, 그렇게 하면 Python이 `TypeError`를 발생시킵니다. 환경은 `configure(environment=...)`(또는 `AGENTEYE_ENVIRONMENT` 변수)를 통해 설정하세요. + +--- + +## 이벤트 기록 방식 + +이벤트는 프로세스 내에 버퍼링되었다가 `flush_interval`초마다(기본값 500ms) 디스크에 플러시됩니다. 각 플러시는 하나의 JSONL 파일을 작성합니다: + +``` +~/.agenteye/events/event-2026-04-01T12-00-00-000Z.jsonl +``` + +수집기는 이 디렉터리를 감시하고 파일을 자동으로 업로드합니다. 이 파일들을 직접 관리할 필요는 없습니다. \ No newline at end of file diff --git a/docs/ko/agenteye/single-pod-deployment.mdx b/docs/ko/agenteye/single-pod-deployment.mdx new file mode 100644 index 00000000..af4b6548 --- /dev/null +++ b/docs/ko/agenteye/single-pod-deployment.mdx @@ -0,0 +1,482 @@ +--- +title: "단일 Pod 배포: EKS에서 Collector + Application Sidecar" +description: "AgentEye 단일 Pod 배포: EKS에서 Collector + Application Sidecar 문서." +--- + +애플리케이션과 AgentEye 컬렉터를 **동일한 Kubernetes Pod 내**에서 실행하면 텔레메트리 수집 시 네트워크 경계를 절대 통과하지 않습니다. 애플리케이션의 SDK와 컬렉터는 단일 Pod 내 이벤트 스풀을 공유하므로, localhost 포트를 노출할 필요도 없고, 서비스 메시를 통과할 필요도 없으며, 컬렉터의 라이프사이클이 관찰 대상 워크로드에 직접 연결된 상태에서 저지연 인프로세스 텔레메트리 핸드오프가 가능합니다. 컬렉터가 제시하는 mTLS 클라이언트 인증서는 AWS Secrets Manager에서 직접 Pod로 전달되므로, 자격 증명 갱신 시 파일을 수동으로 조작할 필요가 없습니다. + +여기서 설명하는 sidecar + 공유 스풀 모델은 클라우드에 종속되지 않습니다. `emptyDir` 이벤트 스풀을 공유하는 두 컨테이너는 모든 Kubernetes 배포판에서 동작합니다. 이 가이드에서 인증서 전달 경로(AWS Secrets Manager + Secrets Store CSI Driver + IRSA)만 AWS / EKS에 특화되어 있습니다. 다른 플랫폼을 사용한다면 Pod 및 스풀 레이아웃은 그대로 유지하고, Phase 2와 3의 시크릿 마운트 방식만 해당 플랫폼의 메커니즘으로 대체하면 됩니다. + +> **이 패턴을 사용할 시기.** 애플리케이션이 컬렉터에 도달하기 위해 네트워크 경계를 통과해서는 안 되는 경우(저지연 인 Pod IPC, 긴밀한 라이프사이클 결합, 테넌트별 Pod 격리)에 단일 Pod를 선택하세요. 노드 또는 클러스터당 하나의 컬렉터를 공유하는 다중 앱 플리트의 경우, [enterprise-docs/kubernetes-deployment.md](/ko/agenteye/kubernetes-deployment)를 참조하세요. + +--- + +## 개요 + +``` +┌──────────────────────────────── Pod ─────────────────────────────────┐ +│ │ +│ ┌──────────────────────┐ ┌──────────────────────┐ │ +│ │ your-app │ │ agenteye-collector │ │ +│ │ (SDK writes JSONL) │ │ (sweeps events/, │ │ +│ │ │ │ uploads over mTLS) │ │ +│ └──────────┬───────────┘ └──────────┬───────────┘ │ +│ │ writes reads │ │ +│ ▼ ▼ │ +│ ┌────────────────────────────────────────────────────┐ │ +│ │ emptyDir: /var/lib/agenteye/{events,failed}/ │ │ +│ │ (AGENTEYE_HOME - shared event spool) │ │ +│ └────────────────────────────────────────────────────┘ │ +│ ▲ │ +│ │ reads cert │ +│ ┌────────┴─────────┐ │ +│ │ CSI (read-only): │ │ +│ │ /etc/agenteye/ │ │ +│ │ tls/client.{crt, │ │ +│ │ key}, ca.crt │ │ +│ └────────┬─────────┘ │ +└───────────────────────────────────────────────────┼──────────────────┘ + │ mounted by + │ Secrets Store CSI + │ (AWS provider + + │ IRSA) + ┌────────┴──────────┐ + │ AWS Secrets │ + │ Manager │ + │ agenteye/mtls- │ + │ client/ │ + └────────┬──────────┘ + ▲ + │ push on issue / + │ renewal + ┌────────┴──────────┐ + │ Exosphere │ + │ delivers the cert │ + │ bundle into your │ + │ Secrets Manager │ + │ on renewal │ + └───────────────────┘ + +Outbound: collector → AGENTEYE_URL (mTLS, using the CSI-mounted cert). +``` + +두 가지 데이터 흐름, 두 가지 볼륨: + +- **이벤트 (인 Pod):** 앱의 SDK가 `$AGENTEYE_HOME/events/`의 공유 `emptyDir`에 `.jsonl` 파일을 작성하면, 컬렉터 스위퍼가 이를 읽어 업로드합니다. localhost 포트도 없고, 루프백도 없으며, 순수한 공유 파일시스템 핸드오프입니다. +- **mTLS 인증서 (pod ← cloud):** Secrets Store CSI Driver가 Secrets Manager의 인증서 번들을 `/etc/agenteye/tls/`의 읽기 전용 볼륨에 마운트하며, 컬렉터 컨테이너에만 적용됩니다. + +**두 독립적인 주체:** + +| 주체 | 책임 | +|---|---| +| Exosphere | mTLS 클라이언트 인증서를 발급하고 번들을 **귀하의** AWS 계정 Secrets Manager에 안정적인 이름으로 전달합니다. 만료 전에 갱신된 번들을 동일한 시크릿에 재발행합니다. | +| 귀하 | Secrets Store CSI Driver를 설치하고, IRSA를 통해 Pod의 ServiceAccount에 시크릿 읽기 권한을 부여하고, Pod 매니페스트를 적용합니다. 이것이 전부입니다. | + +--- + +## 사전 요구사항 + +### AWS 계정 / EKS 클러스터 + +- **OIDC 공급자**가 연결된 EKS 클러스터. 다음으로 확인하세요: + + ```bash + aws eks describe-cluster --name \ + --query "cluster.identity.oidc.issuer" --output text + ``` + + 명령이 `https://oidc.eks.…` URL을 반환하면 OIDC가 활성화된 것입니다. 그렇지 않다면 다음과 같이 연결하세요: + + ```bash + eksctl utils associate-iam-oidc-provider \ + --cluster --approve + ``` + +- 클러스터에 [Secrets Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/)와 [AWS 공급자](https://github.com/aws/secrets-store-csi-driver-provider-aws)가 설치되어 있어야 합니다 (§ Phase 2 참조). + +- 워크스테이션에 AWS CLI v2와 `kubectl`이 설치되어 있어야 합니다. + +### Exosphere와의 협의 + +배포 전에 Exosphere가 mTLS 클라이언트 번들을 귀하의 AWS 계정 Secrets Manager에 전달하고 다음을 제공합니다: + +- **시크릿 이름** (규칙: `agenteye/mtls-client/`) +- 시크릿이 위치한 **AWS 리전** +- 컬렉터에 구성할 **AgentEye 백엔드 URL** +- 컬렉터 **API 키** ([enterprise-docs/api-keys.md](/ko/agenteye/api-keys) 참조) + +--- + +## Phase 1: Exosphere가 전달하는 것 + +mTLS 클라이언트 인증서를 직접 생성하지 않아도 됩니다. Exosphere가 이를 발급하고 번들을 귀하의 AWS 계정 Secrets Manager에 직접 전달하므로, 귀하의 환경에 전달되는 자격 증명 자료는 완성되어 마운트 준비가 된 시크릿뿐입니다. + +귀하의 계정에 도착하는 내용: + +| 속성 | 값 | +|---|---| +| 시크릿 이름 | `agenteye/mtls-client/` (갱신 시에도 안정적으로 유지) | +| 리전 | EKS 클러스터에 지정한 AWS 리전 | +| 페이로드 | PEM 인코딩 자료를 각각 담은 세 가지 키(`client.crt`, `client.key`, `ca.crt`)를 포함한 단일 JSON 시크릿 | +| 태그 | `AgentEyeCluster=` | + +갱신 시 동일한 시크릿이 새 버전으로 업데이트되므로 ARN과 이름은 절대 변경되지 않습니다. `SecretProviderClass`와 IAM 정책은 변경 없이 계속 작동합니다. 인증서 라이프사이클(유효 기간, 갱신 주기, 만료 알림)에 대해서는 [enterprise-docs/kubernetes-deployment.md](/ko/agenteye/kubernetes-deployment)를 참조하세요. + +--- + +## Phase 2: Secrets Store CSI Driver + AWS 공급자 설치 + +이미 CSI를 통해 AWS 시크릿을 마운트하는 다른 워크로드를 실행 중이라면 이 단계를 건너뛰세요. + +```bash +# CSI Driver +helm repo add secrets-store-csi-driver \ + https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts +helm install -n kube-system csi-secrets-store \ + secrets-store-csi-driver/secrets-store-csi-driver \ + --set syncSecret.enabled=true \ + --set enableSecretRotation=true \ + --set rotationPollInterval=1h + +# AWS provider +kubectl apply -f \ + https://raw.githubusercontent.com/aws/secrets-store-csi-driver-provider-aws/main/deployment/aws-provider-installer.yaml +``` + +**확인:** + +```bash +kubectl get pods -n kube-system | grep -E 'csi-secrets-store|aws-provider' +``` + +예상 결과: 모든 Pod에서 `Running` 상태. + +> **`rotationPollInterval=1h`를 사용하는 이유?** Exosphere가 갱신된 인증서를 게시하면 Secrets Manager가 현재 위치에서 업데이트됩니다. CSI Driver는 이 간격으로 시크릿을 다시 읽고 마운트된 파일을 다시 씁니다. 컬렉터는 시작 시 인증서 파일을 한 번만 읽으므로, 프로세스가 재시작된 후에야 갱신된 인증서를 제시하기 시작합니다. 재시작 방법은 § 인증서 갱신을 참조하세요. + +--- + +## Phase 3: Pod에 시크릿 읽기 권한 부여 (IRSA) + +### 3.1 IAM 정책 생성 + +`agenteye-mtls-reader-policy.json`으로 저장: + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "ReadAgentEyeMtlsBundle", + "Effect": "Allow", + "Action": [ + "secretsmanager:GetSecretValue", + "secretsmanager:DescribeSecret" + ], + "Resource": "arn:aws:secretsmanager:::secret:agenteye/mtls-client/-*" + } + ] +} +``` + +``, ``, ``을 실제 값으로 대체하세요. 끝의 `-*`는 AWS가 모든 시크릿 ARN에 추가하는 6자리 임의 접미사와 일치합니다. + +정책 생성: + +```bash +aws iam create-policy \ + --policy-name AgentEyeMtlsReader- \ + --policy-document file://agenteye-mtls-reader-policy.json +``` + +### 3.2 IAM 역할 생성 및 Pod의 ServiceAccount에 바인딩 + +```bash +eksctl create iamserviceaccount \ + --name agenteye-pod \ + --namespace \ + --cluster \ + --role-name AgentEyePodRole- \ + --attach-policy-arn arn:aws:iam:::policy/AgentEyeMtlsReader- \ + --approve +``` + +이 명령은 새 역할을 가리키는 `eks.amazonaws.com/role-arn` 어노테이션이 있는 `agenteye-pod`라는 이름의 `ServiceAccount`를 생성합니다. + +### 3.3 필수 IAM 권한: 요약 + +| 권한 | 범위 | 이유 | +|---|---|---| +| `secretsmanager:GetSecretValue` | `arn:aws:secretsmanager:::secret:agenteye/mtls-client/-*` | CSI Driver가 모든 마운트 및 갱신 틱 시 인증서 번들을 읽습니다. | +| `secretsmanager:DescribeSecret` | 동일 | CSI Driver가 폴링 간격 사이에 버전 변경을 감지하기 위해 `DescribeSecret`을 호출합니다. | + +Pod에 `secretsmanager:PutSecretValue`, `secretsmanager:UpdateSecret`, `secretsmanager:DeleteSecret`을 **절대 부여하지 마세요**. Pod는 시크릿을 읽기만 하며, 새 버전 작성은 인증서 발급 또는 갱신 시 Exosphere가 처리합니다. + +시크릿이 기본 `aws/secretsmanager` 키가 아닌 고객 관리형 KMS 키로 암호화된 경우, 다음도 추가로 부여하세요: + +```json +{ + "Effect": "Allow", + "Action": ["kms:Decrypt"], + "Resource": "arn:aws:kms:::key/", + "Condition": { + "StringEquals": { + "kms:ViaService": "secretsmanager..amazonaws.com" + } + } +} +``` + +--- + +## Phase 4: Pod 배포 + +### 4.1 SecretProviderClass + +`agenteye-mtls-spc.yaml`: + +```yaml +apiVersion: secrets-store.csi.x-k8s.io/v1 +kind: SecretProviderClass +metadata: + name: agenteye-mtls + namespace: +spec: + provider: aws + parameters: + objects: | + - objectName: "agenteye/mtls-client/" + objectType: "secretsmanager" + jmesPath: + - path: '"client.crt"' + objectAlias: "client.crt" + - path: '"client.key"' + objectAlias: "client.key" + - path: '"ca.crt"' + objectAlias: "ca.crt" +``` + +`jmesPath` 블록은 AWS 공급자에게 JSON 시크릿을 디스크의 세 개의 개별 파일로 분할하도록 지시합니다. `'"client.crt"'`의 따옴표 처리는 JMESPath가 `.`을 하위 표현식 연산자로 처리하기 때문에 필요합니다. + +```bash +kubectl apply -f agenteye-mtls-spc.yaml +``` + +### 4.2 Pod / Deployment 매니페스트 + +**두 컨테이너의 통신 방식.** AgentEye SDK와 컬렉터는 네트워크 소켓으로 통신하지 않으며, 로컬 HTTP 포트도 없습니다. SDK는 이벤트 배치를 `$AGENTEYE_HOME/events/`에 `.jsonl` 파일로 작성하고, 컬렉터는 해당 디렉토리를 지속적으로 감시하여 각 파일을 업로드합니다. sidecar Pod의 경우: + +- 두 컨테이너 모두 **동일한** `emptyDir` 볼륨을 **동일한** 경로에 마운트합니다. +- 두 컨테이너 모두 `AGENTEYE_HOME`을 해당 경로로 설정합니다. +- 애플리케이션 이미지에 AgentEye SDK가 설치 및 구성되어 있어야 합니다 ([enterprise-docs/python-sdk.md](/ko/agenteye/python-sdk) 참조). + +> `AGENTEYE_HOME`이 설정되지 않으면 SDK와 컬렉터 모두 기본값인 `~/.agenteye`를 사용하는데, 두 컨테이너의 홈 디렉토리가 다르기 때문에 서로 다른 스풀을 사용하게 되어 핸드오프가 자동으로 실패합니다. **두** 컨테이너 모두에 `AGENTEYE_HOME`을 동일한 명시적 경로로 설정하세요. §4.3 검증 단계와 해당 문제 해결 항목에서 이를 놓쳤을 경우 잡아낼 수 있습니다. + +`agenteye-pod.yaml` (복제본 1개의 Deployment, 필요에 따라 확장): + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-app-with-collector + namespace: +spec: + replicas: 1 + selector: + matchLabels: + app: my-app-with-collector + template: + metadata: + labels: + app: my-app-with-collector + spec: + serviceAccountName: agenteye-pod + containers: + - name: app + image: + env: + # SDK writes event JSONL files into $AGENTEYE_HOME/events/ + - name: AGENTEYE_HOME + value: /var/lib/agenteye + volumeMounts: + - name: agenteye-spool + mountPath: /var/lib/agenteye + + - name: agenteye-collector + # Pin to a versioned :v tag for production; :beta-latest + # tracks the current beta build (:latest exists only for stable releases). + image: ghcr.io/agenteye-enterprise/collector:beta-latest + args: ["start"] + env: + # Must match the app container's AGENTEYE_HOME so the collector + # sweeps the same directory the SDK writes to. + - name: AGENTEYE_HOME + value: /var/lib/agenteye + - name: AGENTEYE_URL + value: "https://ingest.example.agenteye.com/events" + - name: AGENTEYE_KEY + valueFrom: + secretKeyRef: + name: agenteye-collector-api-key + key: key + - name: AGENTEYE_TLS_CERT + value: /etc/agenteye/tls/client.crt + - name: AGENTEYE_TLS_KEY + value: /etc/agenteye/tls/client.key + # Only when the AgentEye server presents a cert not signed by a + # publicly-trusted CA (e.g. self-signed by an in-cluster issuer + # because you have no real DNS domain). The CSI mount already + # exposes ca.crt alongside the client cert/key. + - name: AGENTEYE_TLS_CA + value: /etc/agenteye/tls/ca.crt + volumeMounts: + - name: agenteye-spool + mountPath: /var/lib/agenteye + - name: agenteye-mtls + mountPath: /etc/agenteye/tls + readOnly: true + livenessProbe: + exec: + command: ["agenteye-collector", "health"] + initialDelaySeconds: 10 + periodSeconds: 30 + + volumes: + # Shared event spool between app and collector. emptyDir is fine: + # events are transient and the collector drains them before pod + # termination on graceful shutdown. + - name: agenteye-spool + emptyDir: {} + # mTLS cert bundle, mounted read-only into the collector only. + - name: agenteye-mtls + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: agenteye-mtls +``` + +`agenteye-collector-api-key` 시크릿에는 컬렉터의 API 키가 담겨 있습니다 (프로비저닝 방법은 [enterprise-docs/api-keys.md](/ko/agenteye/api-keys) 참조). + +**적용:** + +```bash +kubectl apply -f agenteye-pod.yaml +``` + +### 4.3 확인 + +```bash +# Pod가 2/2 컨테이너 준비 완료 상태로 Running이어야 함 +kubectl get pods -n -l app=my-app-with-collector + +# 인증서 번들이 마운트되었는지 확인 +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- ls -l /etc/agenteye/tls/ +``` + +예상 결과: `client.crt`, `client.key`, `ca.crt` 모두 존재하며, 읽기 전용으로 컨테이너 사용자 소유. + +**공유 이벤트 스풀이 두 컨테이너에서 보이는지 확인:** + +```bash +# 컬렉터에서, 시작 시 컬렉터가 자동 생성하는 events/ 및 failed/ 하위 디렉토리가 보여야 함: +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- ls /var/lib/agenteye/ + +# 앱에서, 동일한 디렉토리 내용이 보여야 함: +kubectl exec -n deploy/my-app-with-collector \ + -c app -- ls /var/lib/agenteye/ +``` + +두 목록이 다르다면, 볼륨이 두 컨테이너에 모두 마운트되지 않았거나 (`AGENTEYE_HOME`이 다른 경우) 문제가 있는 것입니다. § 문제 해결을 참조하세요. + +**엔드투엔드 스모크 테스트:** + +```bash +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- agenteye-collector flush +``` + +예상 결과: 컬렉터가 대기 중인 이벤트를 업로드하고 `Done: N/N uploaded, 0 failed.` 요약을 출력합니다. 스풀이 비어 있으면 `No pending files.`를 출력하고 아무것도 검증하지 않고 종료됩니다. 따라서 앱이 최소 하나의 이벤트를 플러시한 후에만 실행하세요. + +`flush`는 **로컬 설정 오류**에 대해서만 0이 아닌 값으로 종료됩니다: 구성 누락(URL/키 미설정) 또는 읽을 수 없거나 파싱 불가능한 TLS 인증서 (§ 문제 해결 참조). **잘못된 API 키는 종료 코드를 변경하지 않습니다** — 업로드가 `401`을 받으면 파일이 `failed/`로 이동되고, 명령은 여전히 파일별로 `[FAILED] …`를 출력하고 `Done: 0/N uploaded, N failed.`를 출력한 후 `0`으로 종료됩니다. 잘못된 키나 거부된 업로드를 감지하려면 종료 코드가 아닌 `Done:`/`[FAILED]` 출력을 읽거나 `$AGENTEYE_HOME/failed/`에 파일이 생기는지 확인하세요. + +--- + +## 인증서 갱신 + +클라이언트 인증서는 90일 동안 유효하며, 만료 약 15일 전에 자동으로 갱신됩니다. 그러면 Exosphere가 갱신된 번들을 동일한 Secrets Manager 시크릿에 게시합니다. Pod 내 흐름은 다음과 같습니다: + +1. Secrets Manager의 시크릿이 새 `AWSCURRENT` 버전을 얻습니다. ARN과 이름은 변경되지 않습니다. +2. `rotationPollInterval` (기본값 1h; § Phase 2 참조) 이내에 CSI Driver가 새 버전을 읽고 `/etc/agenteye/tls/` 아래의 파일을 다시 씁니다. +3. 컬렉터는 시작 시 **한 번** 인증서 파일을 로드하므로, 프로세스가 재시작될 때까지 이전 인증서를 계속 제시합니다. 갱신된 자료로 전환하려면 컬렉터를 재시작하세요. 롤링 재시작으로 충분합니다: + + ```bash + kubectl rollout restart deploy/my-app-with-collector -n + ``` + + 이를 자동화하려면 `/etc/agenteye/tls/`를 감시하는 사이드카를 추가하고 (예: `inotifywait` 사용), 파일이 변경될 때 롤아웃을 트리거하도록 하세요. + +이전 인증서는 갱신 후 약 15일 동안 유효하므로, 중단 없이 재시작을 수행할 수 있는 넉넉한 시간이 있습니다. Exosphere가 갱신된 번들을 게시하며, 귀하 측의 유일한 정기 작업은 해당 기간 내에 컬렉터가 재시작되도록 보장하는 것입니다. + +--- + +## 문제 해결 + +| 증상 | 가능한 원인 | 해결 방법 | +|---|---|---| +| Pod가 `ContainerCreating`에서 멈추고, 이벤트에 `MountVolume.SetUp failed for volume "agenteye-mtls"` 표시 | CSI 공급자가 Secrets Manager에 접근할 수 없음 | IRSA가 올바르게 바인딩되었는지 확인: `kubectl describe sa agenteye-pod -n `에서 `eks.amazonaws.com/role-arn` 어노테이션이 표시되어야 합니다. AssumeRole 호출에 대해 CloudTrail을 확인하세요. | +| 오류: `AccessDeniedException: not authorized to perform secretsmanager:GetSecretValue` | IAM 정책이 잘못된 ARN 범위로 지정됨 | 시크릿 ARN 접미사는 임의적이므로, 정확한 ARN이 아닌 와일드카드 `agenteye/mtls-client/-*`를 사용하세요. | +| AWS 공급자에서 `ParameterNotFound` 오류 | `SecretProviderClass.objects[].objectName`과 Exosphere가 전달한 시크릿 이름 불일치 | `aws secretsmanager list-secrets --filters Key=tag-key,Values=AgentEyeCluster`로 정확한 이름을 확인하세요. | +| `jmesPath` 오류, 파일이 하나만 마운트됨 | JMESPath 구문 오류 | JSON 키의 점은 이중 따옴표가 필요합니다: `client.crt`가 아닌 `'"client.crt"'`. | +| 갱신 후 컬렉터 로그에 `tls: bad certificate` | CSI Driver가 아직 새 버전을 폴링하지 않았거나, 컬렉터가 시작 시 로드한 이전 인증서로 여전히 실행 중 | 마운트된 파일이 업데이트되었는지 확인 (`ls -l /etc/agenteye/tls/`)한 후 컬렉터를 재시작하여 로드: `kubectl rollout restart deploy/my-app-with-collector -n `. § 인증서 갱신 참조. | +| 컬렉터 컨테이너가 `no such file or directory: /etc/agenteye/tls/client.crt`로 크래시루프 | 첫 시작 시 볼륨이 아직 채워지지 않음; 스타트업 프로브가 너무 공격적 | 작은 초기 지연을 추가하거나, 파일이 존재할 때까지 기다리는 init 컨테이너를 사용하세요: `until [ -f /etc/agenteye/tls/client.crt ]; do sleep 1; done`. | +| CSI Driver Pod가 `OOMKilled` | SecretProviderClass가 많은 클러스터에서 기본 메모리 한도가 너무 낮음 | Helm 설치에서 `--set linux.resources.limits.memory=200Mi`로 늘리세요. | +| 앱은 정상 실행되고, `agenteye-collector flush`는 `No pending files.`를 보고하지만, AgentEye 대시보드에 이벤트가 표시되지 않음 | 앱과 컬렉터가 이벤트 스풀을 공유하지 않음 | (a) 두 컨테이너 모두 동일한 경로에 동일한 `agenteye-spool` emptyDir을 마운트하고, (b) 두 컨테이너 모두 `AGENTEYE_HOME`을 해당 경로로 설정했는지 확인하세요. § 4.3의 두 `ls /var/lib/agenteye/` 확인을 실행하세요. 목록이 일치해야 합니다. | + +**먼저 수집할 로그:** + +```bash +kubectl logs -n kube-system -l app=secrets-store-csi-driver --tail=100 +kubectl logs -n kube-system -l app=csi-secrets-store-provider-aws --tail=100 +kubectl describe pod -n -l app=my-app-with-collector +``` + +--- + +## 참조: Pod 내 디스크 파일 + +Pod에는 두 가지 데이터 경로가 있습니다: + +### mTLS 인증서 번들: `/etc/agenteye/tls/` (CSI, 읽기 전용, 컬렉터 전용) + +AWS Secrets Manager에서 Secrets Store CSI Driver로 마운트됩니다. + +| 파일 | 내용 | 컬렉터 사용 환경 변수 | +|---|---|---| +| `client.crt` | PEM 인코딩 클라이언트 인증서 | `AGENTEYE_TLS_CERT` | +| `client.key` | PEM 인코딩 개인 키 | `AGENTEYE_TLS_KEY` | +| `ca.crt` | PEM 인코딩 CA 인증서 | `AGENTEYE_TLS_CA` (선택 사항, AgentEye 서버 인증서가 공개적으로 신뢰되지 않는 경우에만) | + +세 파일 모두 읽기 전용으로 마운트되며 컨테이너 사용자 소유입니다. 시크릿이 갱신될 때 CSI Driver에 의해 다시 씁니다. + +### 이벤트 스풀: `$AGENTEYE_HOME/` (emptyDir, 두 컨테이너 간 읽기-쓰기 공유) + +`agenteye-spool`이라는 이름의 `emptyDir` 볼륨을 통해 공유됩니다. + +| 경로 | 작성자 | 읽기 주체 | 목적 | +|---|---|---|---| +| `$AGENTEYE_HOME/events/*.jsonl` | 앱 (AgentEye SDK) | 컬렉터 스위퍼 | SDK가 플러시한 이벤트 배치, 업로드 대기 중. | +| `$AGENTEYE_HOME/failed/` | 컬렉터 (업로드 실패 시) | 귀하 (디버깅 시) | 재시도 후에도 컬렉터가 업로드하지 못한 JSONL 파일. | +| `$AGENTEYE_HOME/config.json` | 귀하 (선택 사항) | 컬렉터 | 선택적 컬렉터 구성 파일 (환경 변수 대안). | + +`events/`와 `failed/` 하위 디렉토리는 모두 컬렉터 시작 시 자동으로 생성됩니다. `initContainer`는 필요하지 않습니다. + +--- + +## 관련 문서 + +- [enterprise-docs/collector-installation.md](/ko/agenteye/collector-installation): 컬렉터 바이너리 옵션, mTLS 구성 참조, 데몬 모드. +- [enterprise-docs/kubernetes-deployment.md](/ko/agenteye/kubernetes-deployment): 멀티 Pod 배포, 인증서 발급 내부 구조, 라이프사이클 및 만료 알림. +- [enterprise-docs/api-keys.md](/ko/agenteye/api-keys): Pod에서 사용하는 컬렉터 API 키 프로비저닝. +- [enterprise-docs/troubleshooting.md](/ko/agenteye/troubleshooting): 클러스터 전체 문제 해결 인덱스. \ No newline at end of file diff --git a/docs/ko/agenteye/tenant-management.mdx b/docs/ko/agenteye/tenant-management.mdx new file mode 100644 index 00000000..3adead1d --- /dev/null +++ b/docs/ko/agenteye/tenant-management.mdx @@ -0,0 +1,167 @@ +--- +title: "테넌트 관리 (조직 및 멤버)" +description: "AgentEye 테넌트 관리 (조직 및 멤버) 문서." +--- + + +단일 AgentEye 배포는 완전히 격리된 여러 **조직**(테넌트)을 지원하므로, 하나의 인스턴스에서 서로 다른 팀, 사업부, 또는 고객을 호스팅하면서 각 테넌트의 데이터가 다른 테넌트에 노출되지 않도록 합니다. 모든 데이터 행(이벤트, 평가, 세션, 대시보드, 저장된 쿼리, 알림, API 키, 멤버)은 정확히 하나의 조직에 속합니다. 기본 격리는 애플리케이션 코드에서 강제됩니다. 모든 요청은 명시적인 `org_id` 조건으로 해당 조직에 범위가 지정됩니다. 대용량 이벤트와 평가가 저장되는 ClickHouse에서는 엔진 수준의 강력한 격리가 적용됩니다. 각 조직은 조직별 행 정책이 있는 전용 읽기 전용 ClickHouse 사용자를 가지므로, 신뢰할 수 없는 분석 SQL도 다른 테넌트의 행을 읽을 수 없습니다. PostgreSQL에서는 읽기 전용 쿼리 경로(`/queries/run`)에 행 수준 보안이 추가적인 방어 계층을 제공하여, 애플리케이션 수준 필터가 누락되더라도 해당 경로에서 볼 수 있는 데이터를 제한합니다. 서버의 쓰기 연결은 테이블 소유자로 실행되므로 동일한 앱 수준 `org_id` 범위 지정을 통해 작동합니다. + +테넌트 생명 주기는 운영자가 관리하며, 멤버가 일상적으로 수행하는 모든 작업은 대시보드에서 셀프 서비스로 처리됩니다. 조직과 그 멤버십은 서버 이미지 내에 포함되어 **기존 서버 파드 내부에서** 실행되는 **`agenteye-orgctl`** CLI로 생성 및 관리됩니다. 테넌트 생성 및 삭제는 의도적으로 대시보드와 HTTP API에서 제외됩니다. 테넌트 생명 주기를 위한 **HTTP API나 대시보드 버튼은 존재하지 않으며**, 애플리케이션 표면이 아닌 클러스터/파드 셸 접근을 통해서만 수행할 수 있습니다. + +조직 내에서 멤버는 대시보드와 API를 통해 모든 작업을 수행합니다. 로그인, 소속 조직 간 전환, 자신의 API 키 관리, 대시보드 및 저장된 쿼리 구성, 조직의 알림 설정 등이 가능합니다. 역할 구분이 명확합니다. 운영자는 CLI를 통해 테넌트와 멤버를 프로비저닝하고 해제하며, 멤버는 UI를 통해 테넌트 내의 모든 작업을 수행합니다. + +> **단일 테넌트 배포에서는 이 내용이 필요하지 않습니다.** 단일 테넌트 설치는 별도의 운영자 작업 없이 실행됩니다. 모든 데이터, 사용자, 키는 자동으로 프로비저닝되는 기본 `default` 조직에 저장됩니다. 두 번째 조직을 추가하려는 경우에만 이 가이드가 필요합니다. + +--- + +## 사전 요구 사항 + +**두 번째** 조직을 생성하기 전에(기본 내장 `default` 조직은 별도 작업 불필요): + +- **PostgreSQL 15+.** 조직-멤버십 스키마는 PostgreSQL 15+에서 필요한 컬럼 목록 `ON DELETE SET NULL` 외래 키를 사용합니다. 두 번째 조직을 프로비저닝하기 전에 PostgreSQL을 업그레이드하세요. +- **강력하고 안정적인 `ORG_CH_SECRET`.** 각 조직의 ClickHouse 비밀번호는 `HMAC(ORG_CH_SECRET, org_id)`로 파생되므로, 공개적으로 알려진 기본 개발 값을 사용하면 조직별 자격 증명이 외부에 노출될 수 있습니다. `agenteye-orgctl org create`는 **`ORG_CH_SECRET`가 설정되지 않았거나 기본 개발 값으로 남아 있는 경우 실행을 거부합니다**. 먼저 고유한 값을 설정하세요([배포 → 환경 변수](/ko/agenteye/deployment) 및 Kubernetes의 경우 [Kubernetes 가이드 §2.6](/ko/agenteye/kubernetes-deployment#26-multi-tenant-org-isolation-key-optional) 참고). 모든 서버 레플리카에서 동일한 값을 유지하고 임의로 변경하지 마세요. 변경하면 다음 시작 시 재프로비저닝될 때까지 모든 조직의 ClickHouse 사용자가 고아 상태가 됩니다. + +--- + +## CLI 실행 + +`agenteye-orgctl`은 **서버와 동일한 이미지**에 포함됩니다(`agenteye-server`와 함께). 별도의 파드, Job, 또는 Deployment를 배포할 **필요가 없으며**, 이미 실행 중인 서버 파드 내부에서 exec으로 실행합니다. 따라서 서버가 사용하는 것과 동일한 `DATABASE_URL`, `CLICKHOUSE_URL`, `ORG_CH_SECRET`을 읽습니다. + +**Kubernetes:** + +```bash +kubectl -n agenteye exec deploy/server -- agenteye-orgctl +``` + +**Docker Compose:** + +```bash +docker compose exec server agenteye-orgctl +``` + +아래 예시는 간결함을 위해 `agenteye-orgctl ` 형태로 표시합니다. 실제 사용 시 배포 환경에 맞게 위의 두 줄 중 하나를 앞에 붙이세요. + +--- + +## 명령어 참조 + +### 조직 + +| 명령어 | 설명 | +|---|---| +| `org create --slug --name ` | 새 조직을 생성합니다. `ORG_CH_SECRET`이 설정되지 않았거나 기본 개발 값으로 남아 있는 경우 실행을 거부합니다(먼저 고유한 값을 설정하세요, 사전 요구 사항 참고). 조직의 읽기 전용 ClickHouse 사용자와 행 정책을 프로비저닝합니다. | +| `org list` | 모든 조직(slug, 이름, 생명 주기 상태)을 나열합니다. | +| `org rename --slug --name ` | 조직의 표시 이름을 변경합니다. URL과 키에 사용되는 slug는 변경되지 않습니다. | +| `org delete --slug ` | 조직을 **소프트 삭제**하고 ClickHouse 사용자를 삭제합니다. 데이터는 **보존됩니다**. 접근 권한을 취소하고 조직별 ClickHouse 자격 증명을 해제하지만, 이벤트를 삭제하지는 않습니다. 운영자가 되돌릴 수 있으며, 삭제 전 안전한 첫 번째 단계입니다. | +| `org purge --slug ` | **되돌릴 수 없는 데이터 삭제.** 조직이 이미 `delete` 상태여야 합니다. 기본 내장 `default` 조직에는 절대 허용되지 않습니다. 테넌트의 데이터를 완전히 삭제해야 할 때만 사용하세요. | + +### 멤버 + +| 명령어 | 설명 | +|---|---| +| `member add --org --email [--set ] [--add perm1,perm2] [--remove perm3] [--protected]` | 조직에 멤버를 추가합니다. 선택적으로 기본 제공 권한 세트에서 시작하여 개별 권한을 추가/제거할 수 있습니다. `--protected`는 대시보드에서 멤버를 제거하거나 권한을 낮출 수 없도록 고정합니다(아래 참고). 새 멤버는 첫 번째 대시보드 로그인 시 OTP를 받습니다. | +| `member list --org ` | 조직의 멤버를 나열합니다. 출력 컬럼은 `EMAIL`, `SET`(멤버가 시작한 기본 제공 세트, 또는 `-`), `PROT`(멤버의 보호 여부), `PERMISSIONS`(유효 권한)입니다. 이메일 뒤에 `*`가 표시된 경우 인스턴스 관리자로 모든 조직에 접근할 수 있습니다. | +| `member update --org --email [--set ...] [--add ...] [--remove ...] [--protected \| --unprotect]` | 멤버의 권한 및/또는 보호 플래그를 변경합니다. `--set`은 기본 제공 세트로 대체하고, `--add` / `--remove`는 개별 권한을 조정하며, `--protected` / `--unprotect`는 보호를 전환합니다. `--protected`/`--unprotect`만 전달하면(권한 플래그 없이) 보호만 변경되고 기존 권한은 그대로 유지됩니다. | +| `member remove --org --email ` | 조직에서 멤버를 제거합니다. 멤버가 보호 상태인 경우 거부됩니다. 먼저 `--unprotect`를 적용하세요. (한 사람이 여러 조직의 멤버일 수 있으며, 이 명령은 지정된 조직에만 영향을 줍니다.) | + +한 사람이 **서로 다른** 권한으로 여러 조직의 멤버가 될 수 있습니다. 예를 들어 한 조직에서는 관리자이고 다른 조직에서는 읽기 전용일 수 있습니다. 각 멤버십은 조직별로 독립적으로 관리됩니다. 한 조직에서 권한을 부여하거나 변경해도 다른 조직의 멤버십에는 영향을 주지 않습니다. + +### 보호된 멤버 (제거 불가능한 조직 관리자) + +보호 기능은 조직이 실수로 자기 관리 권한을 잃지 않도록 보장합니다. 기본적으로 조직의 관리자는 대시보드의 셀프 서비스 사용자 페이지에서 서로를 추가하고 제거할 수 있으므로, 마지막 관리자를 제거하여 관리할 수 있는 사람이 없는 조직이 될 수 있습니다. + +![사용자 페이지: 각 대시보드 사용자의 이메일, 부여된 권한, 편집/비활성화 컨트롤이 있는 카드](/agenteye/images/users.png) + +이를 방지하려면 멤버 하나를 **보호** 상태로 표시하세요: + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member add --org acme --email owner@acme.example --set admin --protected +``` + +보호된 멤버는 **대시보드를 통해 제거하거나 권한을 낮출 수 없으며**, 해당 작업을 시도하면 오류가 반환됩니다. 운영자만 변경할 수 있고, 오직 이 CLI를 통해서만 가능합니다. 먼저 `member update --org acme --email owner@acme.example --unprotect`를 실행한 후 제거하거나 권한을 낮추세요. 이를 통해 모든 조직에 조직 멤버가 잠글 수 없는 최소 하나의 관리자가 유지되면서, 테넌트 제어는 운영자 전용으로 유지됩니다. 보호는 **조직별**로 적용되며, 한 조직에서 누군가를 보호해도 다른 조직의 멤버십에는 영향을 주지 않습니다. + +### 기본 제공 권한 세트 + +`--set`은 조직별로 적용되는 세 가지 기본 제공 세트 중 하나를 허용합니다: + +| 세트 | 대상 | +|---|---| +| `admin` | 조직 내 전체 접근 권한. 조직의 API 키와 사용자 관리를 포함합니다. | +| `standard` | 일상적인 사용: 쿼리 읽기 및 실행, 대시보드 구성, 인시던트 확인. | +| `read-only` | 조직의 데이터와 대시보드에 대한 보기 전용 접근. | + +`--set`으로 세트를 선택한 후, [API Keys](/ko/agenteye/api-keys)에 나열된 개별 권한 토큰을 사용하여 `--add` / `--remove`로 세부 조정하세요. 권한 토큰은 API 키에 사용되는 것과 동일합니다. + +--- + +## 실습 예시 + +새 `acme` 테넌트를 프로비저닝하고, 첫 번째 관리자를 추가하고, 키를 발급한 후 조직을 해제합니다. + +**1. 조직 생성** (`ORG_CH_SECRET`이 설정되지 않았거나 기본 개발 값이 아닌 강력하고 안정적인 값으로 미리 설정되어야 합니다): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org create --slug acme --name "Acme Corp" +``` + +**2. 첫 번째 멤버를 조직 관리자로 추가:** + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member add --org acme --email alice@acme.example --set admin +``` + +Alice는 처음 대시보드에 로그인할 때 OTP를 받습니다. 이후에는 조직의 URL 접두사(예: `/acme/sessions`) 아래에서 UI를 통해 모든 작업을 수행합니다. + +**3. 조직별 API 키 발급 (대시보드에서):** + +운영자는 CLI에서 조직별 데이터 키를 발급하지 **않습니다**. Alice(또는 `keys:create` 권한이 있는 조직 멤버)가 대시보드의 **Keys** 페이지에서 `acme` 조직의 수집기/대시보드 키를 생성합니다. 그녀가 생성하는 모든 키는 자동으로 해당 조직으로 스탬프가 찍히며, `acme`의 데이터만 읽거나 쓸 수 있습니다. [API Keys](/ko/agenteye/api-keys)를 참고하세요. + +**4. 나중에 멤버 조정:** + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member update --org acme --email alice@acme.example --add alerts:write + +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member list --org acme +``` + +**5. 조직 소프트 삭제** (접근 취소 + ClickHouse 사용자 삭제; 데이터 보존): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org delete --slug acme +``` + +**6. 조직 퍼지** (되돌릴 수 없음; 소프트 삭제 이후에만; `default` 조직 불가): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org purge --slug acme +``` + +Docker Compose를 사용하는 경우 각 `kubectl -n agenteye exec deploy/server --` 접두사를 `docker compose exec server`로 대체하세요. + +--- + +## 책임 분담 + +조직 멤버가 일상적으로 필요한 모든 것은 대시보드와 API에서 셀프 서비스로 제공되며, 현재 조직으로 자동 범위가 지정됩니다: + +- **조직별 API 키**는 대시보드에서 조직 멤버가 생성하고 관리합니다(또는 `keys:create`를 가진 키를 사용하여 키 API를 통해). CLI는 데이터 키를 발급하지 **않습니다**. [API Keys](/ko/agenteye/api-keys)를 참고하세요. +- **조직 전환**은 대시보드에 내장되어 있으며, 멤버는 조직 전환기에서 소속 조직 간에 전환할 수 있고, 조직 범위의 페이지는 `//…` 아래에 있습니다. +- **대시보드, 저장된 쿼리, 알림, 모든 데이터 사용**은 UI와 API에서 전적으로 이루어지며, 멤버의 현재 조직으로 범위가 지정됩니다. + +`agenteye-orgctl`을 사용하는 운영자는 조직 + 멤버 **생명 주기**만 소유합니다. 조직 생성/이름 변경/삭제/퍼지, 멤버 추가/나열/업데이트/제거가 해당됩니다. + +--- + +## 참고 항목 + +- [배포](/ko/agenteye/deployment): `ORG_CH_SECRET` 및 기타 서버 환경 설정. +- [Kubernetes 배포](/ko/agenteye/kubernetes-deployment): §2.6에서 첫 번째 멀티 테넌트 조직 전에 `agenteye-org-ch-secret` Secret을 생성합니다. +- [API Keys](/ko/agenteye/api-keys): 조직별 키 모델과 `--add` / `--remove`에 사용되는 권한 토큰. +- [문제 해결](/ko/agenteye/troubleshooting): 멀티 테넌트 프로비저닝 및 ClickHouse 격리 문제. \ No newline at end of file diff --git a/docs/ko/agenteye/troubleshooting.mdx b/docs/ko/agenteye/troubleshooting.mdx new file mode 100644 index 00000000..85acff1d --- /dev/null +++ b/docs/ko/agenteye/troubleshooting.mdx @@ -0,0 +1,574 @@ +--- +title: "문제 해결" +description: "AgentEye 문제 해결 문서입니다." +--- + + +이 가이드는 프로덕션 환경에서 자주 발생하는 증상을 구체적인 진단 방법 및 해결책과 연결하여, 별도의 모니터링 인프라 없이 기존 도구만으로 인시던트를 해결할 수 있도록 합니다. 서버, 수집기, 대시보드, AI 어시스턴트, Python SDK, 헬스/인증서 모니터링, 백업, ClickHouse 기반 분석, 멀티테넌시를 다룹니다. + +대시보드 페이지는 `//…` 형태의 조직 범위 경로를 사용하며, 이벤트 스트림은 조직 홈(`//`)입니다. 이 가이드에서 언급하는 페이지 이름(예: `/sessions`, `/queries`)은 해당 조직 범위 경로를 가리킵니다. + +--- + +## 로그 확인 + +AgentEye는 별도의 로깅 또는 모니터링 스택을 포함하지 않습니다. 서버와 대시보드 모두 구조화된 로그를 **stdout**에 출력하므로, 별도의 로그 수집기 없이 `kubectl` 또는 `docker`로 직접 확인할 수 있습니다. + +### Kubernetes + +서버 및 대시보드의 실시간 로그 확인: + +```bash +kubectl logs -n agenteye -l app=server -f --timestamps +kubectl logs -n agenteye -l app=dashboard -f --timestamps +``` + +유용한 변형 명령어: + +| 목적 | 명령어 | +|---|---| +| 마지막 200줄 (실시간 아님) | `kubectl logs -n agenteye -l app=server --tail=200 --timestamps` | +| 이전 크래시 로그 | `kubectl logs -n agenteye --previous` | +| 모든 레플리카 동시 tail | `kubectl logs -n agenteye -l app=server --max-log-requests=10 -f` | +| Postgres (StatefulSet) | `kubectl logs -n agenteye postgres-0 -f` | + +### Docker Compose + +```bash +docker logs -f agenteye-server +docker logs -f agenteye-dashboard +``` + +### 대시보드와 서버 간 단일 요청 추적 + +모든 대시보드 요청에는 `request_id`가 태그되며, `x-request-id` 헤더를 통해 서버로 전달됩니다. 서버는 해당 요청에 대한 응답 헤더와 모든 로그 줄에 이 ID를 포함합니다. 단일 요청을 처음부터 끝까지 추적하려면: + +1. 응답 헤더에서 ID를 캡처합니다: + ```bash + curl -i https://dashboard.example.com/api/events | grep -i x-request-id + # x-request-id: 9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a + ``` +2. 두 파드의 로그에서 해당 ID를 검색합니다: + ```bash + REQ=9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a + kubectl logs -n agenteye -l app=dashboard --tail=5000 | grep "$REQ" + kubectl logs -n agenteye -l app=server --tail=5000 | grep "$REQ" + ``` + +동일한 `request_id`를 공유하는 대시보드의 `proxy passthrough`, `withAuth: authorized`, `upstream response` 로그 줄과 서버의 `http request received` / `http request completed` 쌍을 함께 확인할 수 있습니다. + +### JSON 로그와 `jq` + +대시보드에서 `AE_LOG_JSON=1`을 설정하면(기본값: `NODE_ENV=production`일 때 활성화) 한 줄에 하나의 JSON 객체를 출력합니다. 구조적으로 필터링하려면: + +```bash +kubectl logs -n agenteye -l app=dashboard --tail=5000 \ + | jq 'select(.level == "warn" or .level == "error")' + +kubectl logs -n agenteye -l app=dashboard --tail=5000 \ + | jq 'select(.route == "POST /api/keys")' +``` + +Rust 서버는 `key=value` 형식의 tracing 로그를 출력하므로 `jq` 없이도 grep이 잘 됩니다: + +```bash +kubectl logs -n agenteye -l app=server --tail=5000 | grep 'status=5' # 5xx +kubectl logs -n agenteye -l app=server --tail=5000 | grep 'actor_key_id=' +``` + +### 로그 상세도 높이기 + +| 컴포넌트 | 환경 변수 | 예시 | +|---|---|---| +| 서버 | `RUST_LOG` | `RUST_LOG=debug` 또는 `RUST_LOG=agenteye_server=debug,info` | +| 대시보드 | `AE_LOG_LEVEL` | `AE_LOG_LEVEL=debug` | + +서버에서 `debug`를 설정하면 인증마다 `api key authenticated` 줄이 추가됩니다. 대시보드에서 `debug`를 설정하면 `upstream request`, `session validated`, `proxy passthrough` 줄이 추가됩니다. + +### 로그 보존 + +컨테이너 stdout은 휘발성이며, kubelet이 로그 파일을 순환(기본값: 컨테이너당 약 10MiB)하고 디스크에 소수의 파일만 유지합니다. 파드가 삭제되면 로그도 사라집니다. 더 긴 보존 기간이나 파드 간 검색이 필요한 경우, `/var/log/containers/`를 tail하는 로그 수집기(Loki, CloudWatch, Cloud Logging, Datadog 등)를 클러스터에 연결하세요. AgentEye는 특정 수집기를 요구하거나 권장하지 않습니다. + +--- + +## 인증 문제 + +### `docker pull`이 "unauthorized"로 실패하는 경우 + +`AGENTEYE_TOKEN`으로 GHCR에 Docker 인증이 되어 있는지 확인하세요: + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +토큰은 `agenteye-enterprise` org의 `read:packages` 권한이 있어야 합니다. 토큰이 작동하지 않으면 `support@exosphere.host`에 문의하세요. + +### `gh release download`가 404 또는 401을 반환하는 경우 + +- 셸에서 `AGENTEYE_TOKEN`이 export되어 있는지 확인합니다: `echo $AGENTEYE_TOKEN` +- `GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download ...` 형식을 사용하고 있는지 확인합니다(`gh` CLI는 `GITHUB_TOKEN`을 읽습니다) +- 토큰에 `agenteye-enterprise/releases`의 `contents:read` 권한이 필요합니다 + +--- + +## 서버 문제 + +### 서버가 "invalid port number"로 실패하는 경우 + +`POSTGRES_PASSWORD`(또는 다른 자격 증명)에 URL 특수 문자(`/`, `+`, `=`)가 포함되어 `DATABASE_URL` 파싱이 실패합니다. 16진수 인코딩을 사용하여 비밀번호를 재생성하세요: + +```bash +NEW_PASS=$(openssl rand -hex 24) +``` + +그런 다음 Kubernetes 시크릿과 Postgres 내부의 비밀번호를 업데이트(또는 Docker Compose용 `.env`를 재생성)하고 서버를 재시작하세요. 전체 절차는 [enterprise-docs/kubernetes-deployment.md](/ko/agenteye/kubernetes-deployment) § "PostgreSQL credentials"를 참조하세요. + +### 서버가 시작 즉시 종료되는 경우 + +컨테이너 로그를 확인합니다: + +```bash +docker logs agenteye-server +``` + +주요 원인: +- `DATABASE_URL`이 설정되지 않았거나 잘못된 형식: 서버가 오류를 로그에 기록하고 종료합니다. +- Postgres에 연결할 수 없음: Postgres 컨테이너 또는 관리형 DB가 실행 중이고 호스트/포트가 올바른지 확인합니다. +- 마이그레이션 실패: SQL 오류가 있는지 로그를 확인합니다. + +### `GET /health`가 non-200을 반환하거나 타임아웃되는 경우 + +첫 시작 시 서버가 마이그레이션을 실행 중일 수 있습니다. 잠시 기다렸다가 재시도하세요: + +```bash +curl http://localhost:8080/health +``` + +문제가 지속되면 `docker logs agenteye-server`에서 오류를 확인하세요. + +### `GET /ready`가 503을 반환하는 경우 + +`/ready`는 준비 상태 프로브로, 서버가 **Postgres 또는 ClickHouse**에 연결할 수 없을 때 `503`을 반환합니다. 응답 본문에 실패한 의존성이 명시됩니다: + +```bash +curl -s http://localhost:8080/ready +# {"status":"not_ready","checks":{"postgres":"ok","clickhouse":"down","redis":"ok"}} +``` + +`down`으로 보고된 의존성을 수정하세요: ClickHouse/Postgres 파드가 `Running` 상태인가요? `CLICKHOUSE_URL` / `DATABASE_URL`이 올바르고 접근 가능한가요? Kubernetes에서 파드는 `/ready`가 회복될 때까지 `NotReady`로 표시됩니다. 이는 예상된 동작이며 헬스 모니터링이 경고하는 신호입니다. Redis는 원인이 되지 않습니다: 보고되지만 준비 상태에 영향을 미치지 않습니다. + +### 수집기가 401 Unauthorized를 반환하는 경우 + +수집기의 API 키에 `events:add` 권한이 없거나 키가 비활성화되어 있습니다. 올바른 권한으로 새 키를 생성하세요: + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{"name":"new-collector","permissions":["events:add"]}' +``` + +### 인증된 요청이 갑자기 느려진 경우(~5ms 대신 ~200ms) + +Redis가 다운되었으나 `REDIS_URL`은 설정된 상태일 때 나타나는 증상입니다. 모든 캐시 호출이 100ms 후 타임아웃되고 Postgres로 폴스루됩니다. 인증 및 OTP 경로에서는 요청마다 두 번의 폴스루가 발생합니다. + +서버 로그에서 확인: + +``` +auth cache: L2 get failed error=redis call timed out +``` + +해결 방법: + +1. `redis-cli -h ping`으로 클러스터 네트워크에서 Redis에 접근 가능한지 확인합니다. +2. Redis가 잠깐 다운되었다가 복구된 경우, **서버 파드를 재시작**하세요. `redis::aio::ConnectionManager`는 기본 연결이 끊긴 후 안정적으로 재연결하지 못합니다. 파드 재시작 시 새 연결을 깔끔하게 가져옵니다. 대시보드도 마찬가지입니다. +3. 당장 Redis를 운영하지 않으려면 배포에서 `REDIS_URL`을 해제하고 재시작하세요. 두 서비스 모두 캐시 없이 실행됩니다(정확성은 유지되며, 지연 시간은 Redis 이전 기준으로 돌아갑니다). + +### 서버 로그에 `OTP request rate-limited`가 기록되지만 사용자는 한 번만 시도했다고 하는 경우 + +Redis가 연결 불가 상태였는지 확인하세요. 폴백 경로는 `SELECT COUNT(*) FROM otp_codes WHERE created_at > now() - interval '15 minutes'`를 사용하는데, 이전에 생성된 OTP 행이 포함됩니다. 사용자가 한 시간 동안 "재전송"을 반복 클릭했다면 15분 창 내에 여전히 5개 이상의 코드가 있을 수 있습니다. 창이 롤오버될 때까지 기다리거나, `DELETE FROM otp_codes WHERE user_id = $1 AND created_at > now() - interval '15 minutes'`(운영자 콘솔)를 실행하여 해결하세요. + +### `ALLOWED_EMAILS` / `SESSION_TTL_SECS` / `OTP_TTL_SECS`를 변경하고 재시작했지만 변경이 적용되지 않는 경우 + +이 환경 변수들은 **최초 부팅 시에만 적용되는 시드 값**입니다. `settings` 테이블에 해당 키의 행이 존재하면, 그 행이 진실의 원천이 됩니다. 환경 변수는 최초 부팅 시 한 번만 읽히고 이후 재시작 시에는 무시됩니다. + +최초 부팅 이후 변경하려면, 대시보드에 로그인하여 `/settings`에서 편집하세요. 변경 사항은 모든 레플리카에 수초 내에 적용되며 재시작이 필요 없습니다. + +환경 변수에서 강제로 재시드해야 하는 경우(드물며 주로 개발 환경에서만 유용), `DELETE FROM settings WHERE key = ''` 후 서버를 재시작하면 다음 부팅 시 현재 환경 변수 값을 가져옵니다. 프로덕션에서는 `/settings`를 통한 편집이 지원되는 방식입니다. + +--- + +## 수집기 문제 + +### 수집기는 시작되지만 이벤트가 대시보드에 나타나지 않는 경우 + +1. 수집기가 실행 중인지 확인합니다: `systemctl status agenteye-collector`(Linux) 또는 프로세스를 확인합니다. +2. `AGENTEYE_URL`이 `http(s)://your-server-host:8080/events`(`/events` 경로 포함)를 가리키는지 확인합니다. +3. 즉각적인 출력을 보려면 단발성 플러시를 실행합니다: + ```bash + agenteye-collector flush + ``` +4. Python SDK가 실제로 파일을 기록하고 있는지 확인합니다: `ls ${AGENTEYE_HOME:-~/.agenteye}/events/` +5. `${AGENTEYE_HOME:-~/.agenteye}/failed/`에 파일이 있다면 업로드가 실패하고 있는 것입니다. 수집기 로그에서 오류를 확인하세요. 4xx 오류(잘못된 키 또는 URL)나 네트워크 문제일 가능성이 높습니다. + +### `$AGENTEYE_HOME/events/`에 파일이 쌓이고 업로드되지 않는 경우 + +- 수집기가 실행 중이 아닐 수 있습니다. 시작하세요: `agenteye-collector start`. 시작 시 기존 이벤트를 자동으로 플러시합니다. +- 수집기 헬스 확인: `agenteye-collector health` +- 수집기는 실행 중이지만 서버에 연결할 수 없을 수 있습니다. 수집기와 서버 호스트 간 방화벽 규칙을 확인하세요. + +### `$AGENTEYE_HOME/failed/`에 파일이 있는 경우 + +파일은 모든 재시도가 소진된 후(기본값: 지수 백오프를 적용한 5회) `failed/`로 이동됩니다. 이는 다음 중 하나를 의미합니다: +- 서버가 4xx 오류를 반환(잘못된 키, 잘못된 URL, 또는 페이로드 문제) +- 전체 재시도 창 동안 서버에 연결할 수 없음 + +근본 원인을 수정한 후 수동으로 재대기열에 추가하세요: + +```bash +mv ${AGENTEYE_HOME:-~/.agenteye}/failed/*.jsonl ${AGENTEYE_HOME:-~/.agenteye}/events/ +agenteye-collector flush +``` + +### 수집기가 모든 업로드에서 `network error`를 보고하는 경우(TLS 핸드셰이크 실패) + +`curl -k`로 `AGENTEYE_URL`에 접근하면 성공하지만 수집기 바이너리가 매번 `error sending request for url (...)`로 실패한다면, AgentEye 서버가 공개 신뢰 CA에서 서명되지 않은 TLS 인증서를 제공하고 있는 것입니다. + +**프로덕션 경로**는 `deploy/base/certificates/domain.env`에 구성된 ACME 수집 호스트명입니다([`kubernetes-deployment.md`](/ko/agenteye/kubernetes-deployment) Phase 3.1 / 4.2 참조). `INGEST_DOMAIN`이 공개 Traefik LB로 해석되고 cert-manager가 Let's Encrypt 인증서를 발급하면, 수집기는 **`AGENTEYE_TLS_CA` 없이** 시스템 신뢰 저장소에 대해 서버 인증서를 검증합니다. 이전에 자체 서명 배포 시 설정했다면 이를 해제하세요. + +**증상: 수집기가 어제까지 작동했는데 약 90일 후 오늘 실패하는 경우.** 배포가 여전히 `ingest-tls`에 레거시 `selfsigned` 발급자를 사용하고 있다는 의미입니다. 90일짜리 인증서가 순환되어 고정된 CA 파일이 오래된 것이 됐습니다. 클러스터를 ACME 발급자로 전환하여 영구적으로 수정하세요(배포 가이드 Phase 3.1). 단기 해결책으로, 현재 서버 인증서를 재추출하고 `AGENTEYE_TLS_CA`를 업데이트하세요: + +```bash +kubectl get secret ingest-tls-cert -n agenteye \ + -o jsonpath='{.data.tls\.crt}' | base64 -d > /etc/agenteye/server-ca.crt +``` + +```bash +export AGENTEYE_TLS_CA=/etc/agenteye/server-ca.crt +agenteye-collector flush +``` + +`AGENTEYE_TLS_CA`는 추가 신뢰 앵커를 추가합니다. 표준 공개 루트는 계속 신뢰됩니다. + +### 배포 후 `ingest-tls` 인증서가 `Ready: False` 상태에서 멈춰 있는 경우 + +```bash +kubectl describe certificate ingest-tls -n agenteye +``` + +`Events`와 참조된 `Order` / `Challenge`를 확인하세요. 주요 원인: + +- **DNS가 공개 LB로 해석되지 않음.** HTTP-01 검증자가 `INGEST_DOMAIN`에 도달하지 못합니다. `dig +short INGEST_DOMAIN`으로 확인하세요. `traefik-public` LoadBalancer의 `EXTERNAL-IP`와 동일한 주소로 해석되어야 합니다. DNS가 전파되면 cert-manager가 자동으로 재시도하므로 Certificate를 삭제할 필요가 없습니다. +- **로드 밸런서 / 보안 그룹에서 포트 80이 차단됨.** HTTP-01은 Let's Encrypt의 공개 검증자가 포트 80에 접근 가능해야 합니다. 업스트림 WAF나 SG가 `:80`을 제한하고 있다면 열어주세요(Traefik 설정은 HTTPS로 리디렉션하지만, Boulder는 리디렉션을 따르고 응답을 수락합니다). +- **`dnsNames`가 치환되지 않음.** `kubectl get certificate ingest-tls -n agenteye -o jsonpath='{.spec.dnsNames}'`가 `INGEST_DOMAIN_PLACEHOLDER`를 표시한다면 `domain.env` 단계를 건너뛴 것입니다. `domain.env.example`에서 생성하고 재적용하세요. +- **Let's Encrypt 속도 제한.** 동일 호스트명에 대한 반복 실패한 주문은 중복 인증서 또는 유효성 검사 실패 한도를 초과합니다. 재시도 전 최소 한 시간 기다리세요. 정확한 속도 제한 메시지는 Order 상태를 확인하세요. + +### `dashboard-tls` 인증서가 `Ready: False` 상태이거나 브라우저에서 여전히 경고가 표시되는 경우 + +위의 `ingest-tls`와 동일한 진단 절차를 따르세요(`kubectl describe certificate dashboard-tls -n agenteye`). DNS, 포트 80, 플레이스홀더, 속도 제한 원인이 모두 적용되며, 대시보드에만 해당하는 두 가지 추가 원인이 있습니다: + +- **`DASHBOARD_DOMAIN`이 잘못된 LoadBalancer를 가리킴.** 공개 수집용 Traefik LB가 아닌 *대시보드* Traefik LB를 가리켜야 합니다. 호스트명을 `dig +short`로 확인하고 대시보드 LB 주소와 비교하세요. +- **대시보드 Traefik 인스턴스가 챌린지를 처리하지 못함.** cert-manager의 HTTP-01 솔버를 위한 범위 지정 Ingress 공급자를 활성화하는 번들 대시보드 값 파일과 함께 설치되어야 합니다. 없으면 솔버가 라우팅 불가능하여 Order가 영구적으로 `pending` 상태가 됩니다. 제공된 값으로 인스턴스를 업그레이드하면 대기 중인 챌린지가 자동으로 완료됩니다. +- **LoadBalancer에 IP 제한이 걸려 있음.** 소스 범위는 포트 80에도 적용되어 Let's Encrypt의 검증자를 차단합니다. 최초 발급과 약 75일마다의 갱신 시 모두 영향을 받습니다. LB를 다시 열거나, 잠그기 전에 지원팀과 DNS-01 솔버를 조율하세요. + +발급이 실패하는 동안 대시보드는 이전 인증서(또는 신규 설치의 경우 ingress 기본값)로 계속 서비스됩니다. 브라우저 경고로 접근이 불편해질 뿐, 서비스가 중단되지는 않습니다. + +### 대시보드에 신뢰할 수 있는 인증서가 적용된 후에도 CLI가 TLS 검증을 건너뛰는 경우 + +`--insecure`는 로그인 시 `cli.json`에 저장됩니다. 대시보드가 공개 신뢰 인증서를 제공하면, `agenteye --base-url https:// --secure login`으로 다시 로그인하세요. 검증이 다시 활성화되어 저장되고 시작 경고가 사라집니다. + +--- + +## 대시보드 문제 + +### `ADMIN_EMAIL` 사용자를 비활성화하거나 편집할 수 없는 경우 + +이는 의도된 동작입니다. `ADMIN_EMAIL`과 일치하는 사용자는 서버 시작 시마다 보호됨으로 표시됩니다. 대시보드는 해당 행의 비활성화 버튼을 숨기며, API는 해당 사용자에 대한 `DELETE /users/:id` 및 `PUT /users/:id` 요청을 `403 Forbidden`으로 거부합니다. 데이터베이스 트리거도 보호된 행을 비활성화하는 직접 `UPDATE` 문을 거부합니다. + +부트스트랩 관리자를 교체하려면, 환경에서 `ADMIN_EMAIL`을 변경하고 서버를 재시작하세요. 새 이메일이 보호됨으로 업서트됩니다. 이전 관리자는 데이터베이스에서 명시적으로 제거할 때까지 보호 플래그를 유지합니다(이전 이메일이 여전히 유효한 관리자이므로 일반적으로 무방합니다). + +### 대시보드에 이벤트가 표시되지 않는 경우 + +1. 대시보드 환경 변수(`AGENTEYE_SERVER_URL`, `AGENTEYE_API_KEY`)에서 서버 URL과 API 키가 올바른지 확인합니다. +2. 대시보드 API 키에 `events:read` 권한이 필요합니다. +3. 이벤트가 실제로 수집되었는지 확인합니다: `curl http://your-server:8080/events -H "Authorization: Bearer $ADMIN_KEY"` + +### `/errors`는 비어 있는데 `/events`에는 빨간색 행이 표시되는 경우 + +최신 SDK 버전은 실패를 전용 `event_type: "error"` 행 대신 페이로드에 `outcome: "error"`가 포함된 `agent_end` / `tool_result` / `hook_completed` 이벤트로 보냅니다. `/errors` 페이지는 이제 두 가지 모두를 매칭합니다: `/events` 스트림에서 빨간색으로 표시되는 모든 행(명시적 `event_type='error'`, 페이로드의 `outcome`/`status`가 실패 집합에 속하는 경우, `is_error: true`, 또는 truthy `error` 필드)이 `/errors`에 표시됩니다. 이전에 `/events`에 빨간색 행이 있었는데 "이 창에 오류 없음"이 표시됐다면, 대시보드와 서버를 함께 업그레이드하세요(`GET /events`의 확장된 필터 `errored=true`). 그러면 두 뷰가 일치하게 됩니다. + +### 넓은 시간 범위에서 `/models`, `/tools`, `/hooks`가 느리거나 로드 실패하는 경우 + +**증상:** 대규모 이벤트 테이블(수백만 행)에서 `/models`, `/tools`, `/hooks`를 열거나 시간 범위를 `7d`, `30d`, `all`로 넓히면 차트가 로딩되다가 오류가 표시됩니다. 서버 로그에 `latency_aggregate` 요청에 대한 ClickHouse `MEMORY_LIMIT_EXCEEDED`(Code 241) 또는 쿼리 타임아웃이 기록됩니다. + +**원인:** 이전 빌드에서는 이 페이지들의 지연 시간 및 분포 롤업을 전체 원시 이벤트 `payload`를 읽고 인메모리 정렬-조인으로 요청/응답 이벤트를 쌍으로 맞추는 쿼리로 계산했습니다. 이로 인해 쿼리 최대 메모리가 창의 크기에 비례하여 증가했고, 바쁜 테넌트에서는 ClickHouse의 쿼리당 메모리 한계를 초과할 수 있었습니다. + +**해결 방법:** 이 수정을 포함하는 빌드로 업그레이드하세요. 롤업은 이제 압축된 승격 컬럼만 읽고 스트리밍 집계로 이벤트를 쌍으로 맞추므로, 최대 메모리가 더 이상 원시 페이로드와 함께 확장되지 않습니다. 넓은 창도 메모리 한계 내에서 빠르게 반환됩니다. 개선은 전적으로 쿼리 측에서 이루어집니다. 기존 데이터에 즉시 적용되며, 재수집이나 백필이 필요 없습니다. + +### 대시보드가 로드되지 않거나 빈 페이지가 표시되는 경우 + +대시보드 컨테이너 로그를 확인합니다: + +```bash +docker logs agenteye-dashboard +``` + +가장 흔한 원인은 `AGENTEYE_SERVER_URL` 또는 `AGENTEYE_API_KEY`가 누락되거나 연결할 수 없는 서버를 가리키는 경우입니다. + +### 대시보드 분석 / 텔레메트리 + +대시보드는 기본적으로 익명의 제품 사용 분석을 PostHog에 전송하며, 대시보드 자체의 `/ingest` 경로(퍼스트 파티 `https://us.i.posthog.com` 리버스 프록시)를 통해 라우팅됩니다. 브라우저 광고 차단기가 차단하지 않도록 퍼스트 파티로 전송됩니다. 이는 대시보드의 핵심 기능과 독립적입니다: + +- **대시보드 컨테이너**(브라우저가 아님)가 PostHog에 연결합니다. `https://us.i.posthog.com`에 대한 아웃바운드 접근이 차단되면 텔레메트리는 무음으로 비활성화되며, 대시보드는 정상적으로 작동하고 사용자에게 오류가 표시되지 않습니다. +- 에이전트, 세션, 이벤트 데이터는 포함되지 않으며 대시보드 UI 사용 데이터만 전송됩니다. +- 텔레메트리를 완전히 비활성화하려면 대시보드 컨테이너에 `AE_ANALYTICS_DISABLED=1`을 설정하고 재시작하세요. 배포 가이드의 [Telemetry & privacy](/ko/agenteye/deployment#telemetry--privacy)를 참조하세요. + +### CLI 분석 / 텔레메트리 + +`agenteye` CLI는 기본적으로 익명의 사용 분석(실행된 명령어, 성공/종료 상태, 실행 시간)을 PostHog에 전송합니다. 이는 CLI 기능과 독립적입니다: + +- **CLI를 실행하는 머신**이 `https://us.i.posthog.com`에 직접 연결합니다. 아웃바운드 접근이 차단되면 텔레메트리는 무음으로 비활성화되며(전송에 시간 제한이 있어 명령어 실행이 지연되지 않습니다) CLI는 정상적으로 작동합니다. +- 에이전트, 세션, 이벤트 데이터는 포함되지 않습니다. 명령어 **인수 및 플래그 값**(대시보드 URL, 토큰, 이메일, 세션 ID, 쿼리 필터)은 전송되지 않습니다. +- 비활성화하려면 CLI 환경에서 `AGENTEYE_ANALYTICS_DISABLED=1`(또는 크로스 도구 `DO_NOT_TRACK=1`)을 설정하세요. CLI 가이드의 [Telemetry & privacy](/ko/agenteye/cli#telemetry--privacy)를 참조하세요. + +--- + +## AI 어시스턴트 문제 + +전체 설정은 [enterprise-docs/assistant.md](/ko/agenteye/assistant)를 참조하세요. + +### 어시스턴트 버블이 표시되지 않는 경우 + +다음 조건이 **모두** 충족될 때만 버블이 표시됩니다: + +- 로그인한 사용자에게 `agent:use` 권한이 있어야 합니다. +- 대시보드에 `AGENTEYE_AGENT_URL`이 설정되어 있고 `agent` 서비스에 접근 가능해야 합니다. +- `agent` 서비스에 LLM 엔드포인트가 구성되어 있어야 합니다(`ANTHROPIC_API_KEY`, `ANTHROPIC_BASE_URL`을 통한 게이트웨이, 또는 Bedrock/Vertex). 아무것도 설정되지 않으면 에이전트가 "구성되지 않음"을 보고하고 버블이 숨겨집니다. + +대시보드 호스트에서 에이전트 헬스를 확인하세요: `curl http://agent:9100/health`는 `{"status":"ok","llm_configured":true,...}`를 반환해야 합니다. + +### 어시스턴트가 특정 데이터를 읽을 수 없다고 하는 경우 + +도구는 사용자별로 제한됩니다. 사용자에게 `evaluations:read`(또는 `events:read`, `dashboards:read`) 권한이 없으면 해당 도구가 제공되지 않으며, 어시스턴트는 해당 데이터를 읽을 수 없다고 말합니다. 관련 읽기 권한을 부여하세요. + +### 메시지 전송 시 "assistant not configured" (HTTP 503)가 발생하는 경우 + +`agent` 컨테이너에 LLM 엔드포인트가 구성되지 않았거나, 대시보드의 `AGENTEYE_AGENT_TOKEN`이 에이전트의 토큰과 일치하지 않습니다. 두 값을 모두 설정하고 재시작하세요. + +### `agent` 컨테이너가 부하 시 재시작되거나 OOM이 발생하는 경우 + +각 대화는 단기적인 자식 프로세스를 생성합니다. 컨테이너가 init 프로세스로 실행되는지 확인하세요(이미지가 `tini`를 사용하며, Compose에서는 `init: true` 설정). 적절한 메모리 한도를 설정하고, 필요시 `AGENTEYE_AGENT_MAX_STEPS`를 줄이세요. + +--- + +## CLI 문제 + +### `agenteye`가 `ModuleNotFoundError: No module named 'click'`으로 시작 실패하는 경우 + +**0.1.6** 버전의 `agenteye` CLI를 새로 설치하면 시작 시 다음 오류가 발생할 수 있습니다: + +``` +ModuleNotFoundError: No module named 'click' +``` + +0.1.6은 `typer`가 `click`을 간접적으로 설치하는 것에 의존했습니다. 현재 `typer` 릴리스는 더 이상 이를 포함하지 않아, 깨끗한 환경에서 패키지가 누락됩니다. `click`에 직접 의존하는 **0.1.7 이상으로 업그레이드**하세요: + +```bash +pipx upgrade agenteye # pipx로 설치한 경우 (또는: pipx install --force agenteye) +uv tool upgrade agenteye # uv로 설치한 경우 +pip install --upgrade agenteye +``` + +설치 안내는 [enterprise-docs/cli.md](/ko/agenteye/cli)를 참조하세요. + +--- + +## Python SDK 문제 + +### `$AGENTEYE_HOME/events/`에 파일이 생성되지 않는 경우 + +SDK는 이벤트를 버퍼링하고 기본적으로 500ms마다 플러시합니다. 플러시 전에 프로세스가 종료되면 이벤트가 손실될 수 있습니다. 단기 실행 스크립트에서는 `agenteye.configure(flush_interval=0.1)`로 더 빠른 플러시를 설정하거나, 플러시 사이클이 완료될 때까지 프로세스가 실행되도록 하세요. + +`AGENTEYE_HOME`이 설정되어 있다면, SDK가 `~/.agenteye/events/`가 아닌 `$AGENTEYE_HOME/events/`에 기록하는지 확인하세요(SDK ≥ 0.0.1b5 필요). + +### `ValueError: Reserved field names cannot be used as custom fields` + +`timestamp`, `type`, `environment`는 예약된 이름으로 커스텀 필드로 사용할 수 없습니다. 이 중 하나를 전달하면 다음 오류가 발생합니다: + +``` +ValueError: Reserved field names cannot be used as custom fields: [...] +``` + +문제가 되는 커스텀 필드의 이름을 변경하세요. `session_id`와 `agent_id`는 이벤트 호출의 명시적 파라미터이며 커스텀 필드가 아닙니다. 이를 다시 커스텀 필드로 전달하면 `TypeError`가 발생합니다. + +--- + +## 헬스 모니터링 문제 + +### Slack으로 경고가 오지 않는 경우(Robusta) + +Robusta 헬스 경고는 **옵트인** 방식입니다. 설치하고 Slack 채널을 지정할 때까지 아무것도 전송하지 않습니다. 릴리스와 싱크를 확인하세요: + +```bash +kubectl get pods -n robusta # robusta-runner + robusta-forwarder가 Running 상태여야 합니다 +kubectl logs -n robusta -l app=robusta-runner --tail=50 +``` + +주요 원인: Slack `api_key` / `slack_channel`이 설정되지 않았거나(또는 토큰이 취소됨); `api_key`가 Robusta 클라우드 릴레이 토큰(`robusta integrations slack`)인데 번들된 `disableCloudRouting: true`는 셀프 호스팅 Slack **봇 토큰**(`xoxb-…`)이 필요하거나 `disableCloudRouting: false`로 설정해야 함; 싱크 `scope`가 파드가 실행 중인 네임스페이스를 제외함(번들 값은 `agenteye`로 범위 지정); 또는 아직 실패가 발생하지 않음. 파드를 종료하여 테스트 경고를 강제 발생시키세요: + +```bash +kubectl -n agenteye delete pod -l app=clickhouse # 다시 생성됩니다 +``` + +설치 및 구성은 [enterprise-docs/health-monitoring.md](/ko/agenteye/health-monitoring#2-pod-failure-alerting-with-robusta-opt-in)를 참조하세요. + +### 서버가 지속적으로 `NotReady` 상태를 반복하는 경우 + +준비 상태 프로브가 `/ready`를 호출하며, Postgres 또는 ClickHouse에 연결할 수 없을 때 실패합니다. 서버가 `NotReady`를 반복한다면 의존성이 간헐적으로 사용 불가능한 것입니다. ClickHouse와 Postgres 파드, 그리고 서버의 `CLICKHOUSE_URL` / `DATABASE_URL`을 확인하세요. `/ready`가 보고하는 내용을 확인합니다: + +```bash +kubectl -n agenteye exec deploy/server -- sh -c 'curl -s localhost:8080/ready' +``` + +이 프로브는 의도적으로 허용적입니다(관대한 실패 임계값). 따라서 지속적인 반복은 프로브가 너무 엄격한 것이 아니라 실제 의존성 문제를 나타냅니다. 활성 프로브는 `/health`에 남아 있으므로, 준비 상태 반복이 파드를 **재시작하지는 않습니다**. + +## 인증서 모니터링 문제 + +### CronJob이 Slack 알림을 보내지 않는 경우 + +`cert-renewal-check` CronJob은 시크릿에 저장된 Slack 웹훅 URL이 필요합니다. 존재 여부를 확인하세요: + +```bash +kubectl get secret cert-renewal-notify-config -n agenteye +``` + +없으면 생성하세요: + +```bash +kubectl create secret generic cert-renewal-notify-config \ + --namespace agenteye \ + --from-literal=SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL" +``` + +시크릿이 없어도 CronJob은 실행되어 stdout에 결과를 기록합니다. 로그 확인: + +```bash +kubectl logs -n agenteye -l job-name --tail=50 +``` + +### 알림을 받기 전에 클라이언트 인증서가 만료된 경우 + +CronJob은 12시간마다 실행됩니다. 실행되지 않고 있다면 상태를 확인하세요: + +```bash +kubectl get cronjob cert-renewal-check -n agenteye +``` + +수동 확인을 트리거합니다: + +```bash +kubectl create job --from=cronjob/cert-renewal-check manual-cert-check -n agenteye +kubectl logs -n agenteye -l job-name=manual-cert-check +``` + +만료된 인증서를 즉시 재발급하려면: + +```bash +cd base/certificates/client-certs +./issue-client-cert.sh +``` + +그런 다음 수집기를 실행하는 클러스터에 재생성된 `collector-mtls-secret.yaml`을 적용하고 재시작하세요: + +```bash +kubectl apply -f collector-mtls-secret.yaml -n +``` + +--- + +## 백업 문제 + +### `agenteye-backup`이 "No space left on device"로 실패하는 경우 + +`agenteye-backup` CronJob은 Postgres + ClickHouse를 `backup-tmp` `emptyDir` 임시 볼륨(기본값 `30Gi`)에 덤프한 다음, `tar` 아카이브를 S3에 **스트리밍**합니다. 압축된 아카이브는 임시 저장소에 기록되지 않으므로, 임시 저장소는 *원시 덤프*만 보관하면 됩니다. 파드 퇴거 / `No space left on device`는 **원시 덤프**가 임시 저장소 크기를 초과함을 의미합니다(ClickHouse `events` 덤프가 주된 원인이며 시간이 지날수록 증가합니다). 실패한 작업의 로그를 확인하세요: + +```bash +kubectl logs -n agenteye -l job-name= +``` + +해결 방법: 오버레이에서 CronJob의 `backup-tmp` `emptyDir` `sizeLimit`을 원시 덤프 총 크기보다 높이고, 노드의 임시 저장소가 실제로 이를 수용할 수 있는지 확인하세요(`sizeLimit`은 상한이지 예약이 아닙니다). 덤프가 단일 노드의 디스크를 초과하면 `backup-tmp`를 PVC(EBS/PD)로 교체하거나, 소스에서 덤프를 압축하세요. + +> 이전 릴리스에서는 `.tar.gz`를 덤프와 동일한 `20Gi` 임시 저장소에 기록하여 `덤프 + 아카이브`가 초과되어 업로드 전에 파드가 퇴거됐습니다. 이는 S3 오류처럼 보이지만 실제로는 디스크 문제입니다. 업로드 스트리밍으로 이 두 배 문제가 해결됩니다. + +### `agenteye-backup`이 `curl` 설치 실패로 실패하는 경우 + +작업이 `postgres:16` 이미지에서 실행되며 ClickHouse HTTP 덤프를 위해 시작 시 `curl`을 설치합니다. Debian 패키지 미러에 대한 이그레스가 없는 클러스터에서는 `apt-get` 단계가 실패합니다. 백업 파드의 이그레스를 허용하거나, `curl`이 포함된 미러링/커스텀 백업 이미지를 빌드하여 오버레이에서 참조하세요. + +### `agenteye-backup`은 실행되지만 오브젝트 스토리지에 아무것도 저장되지 않는 경우 + +기본 구성은 실제 `BACKUP_BUCKET`(`ts-prod-agenteye/backups`)과 `agenteye-backup` ServiceAccount를 포함합니다. 작업은 아카이브를 S3에 **스트리밍**합니다(`tar cz … | aws s3 cp - s3://…`). 백업 파드가 버킷에 대한 쓰기 권한이 없으면 업로드 오류가 발생합니다. 스크립트가 `set -euo pipefail` 하에 실행되므로, 파이프 어느 곳에서든 실패하면 전체 작업이 `upload` 단계에서 실패합니다(파드의 EXIT 트랩이 `backup FAILED during step: upload`를 기록합니다). 임시 저장소 퇴거를 수정한 후에도 이 단계에 도달하므로, 이제 업로드가 정상적으로 저장되는지 확인하세요. 실패한 작업의 로그에서 S3 접근 오류를 검색하세요: + +```bash +kubectl logs -n agenteye -l job-name= | grep -iE 's3|upload|denied' +``` + +해결 방법: 오버레이에서 `BACKUP_BUCKET`을 소유한 버킷으로 설정하고, 기존 `agenteye-backup` ServiceAccount에 쓰기 권한을 주석으로 추가하세요(IRSA / Workload Identity / Pod Identity). [enterprise-docs/kubernetes-deployment.md](/ko/agenteye/kubernetes-deployment)의 **Backups** 섹션을 참조하세요. + +--- + +## ClickHouse 기반 평가 / 세션 / 쿼리 + +### 업그레이드 후 `/queries` 페이지 사이드바가 비어 있는 경우 + +세 개의 테이블(`events`, `evaluations`, `agent_sessions`)이 있어야 합니다. 업그레이드 후 SchemaBrowser 사이드바가 비어 있다면, 서버가 시작 시 ClickHouse DDL 적용에 실패한 것입니다. `failed to apply CH DDL statement`가 있는지 서버 로그를 확인하세요: + +```bash +kubectl logs -n agenteye deploy/server | grep -E 'clickhouse|CH DDL' +``` + +가장 흔한 원인은 마이그레이션 실행 중 ClickHouse에 연결할 수 없는 경우입니다. 서버는 CH에 연결할 수 없으면 시작을 거부하므로, 멈춘 파드는 일반적으로 쿼리 페이지가 조용히 고장나는 것보다 `CrashLoopBackOff` 상태가 됩니다. 그러나 부분적인 DDL 적용(하나는 성공, 다음 5개는 5xx)은 스키마를 절반만 적용된 상태로 남깁니다. CH가 연결 가능함을 확인한 후 서버 파드를 재시작하세요: + +```bash +kubectl rollout restart deploy/server -n agenteye +``` + +### 새 평가가 `/sessions` 또는 `/queries`에 나타나지 않는 경우 + +업그레이드 후 새 평가는 Postgres가 아닌 ClickHouse에 기록되며, `/sessions`(`evaluations:read` 권한 필요)와 `/queries`에 표시됩니다. 표시되지 않는다면: + +1. 평가자 파이프라인이 활성화되어 있고(`EVALUATOR_ENDPOINT`가 서버에 설정됨) 최종 결과를 생성하고 있는지 확인합니다. `evaluation_finalized` 로그 줄을 확인하세요. +2. 서버에서 CH에 연결 가능한지 확인합니다: `kubectl exec -n agenteye deploy/server -- curl -fsS http://clickhouse:8123/ping`. +3. CH 테이블을 직접 확인합니다: `kubectl exec -n agenteye clickhouse-0 -- clickhouse-client -q 'SELECT count() FROM agenteye.evaluations'`. + +### 부하 시 쿼리가 "Memory limit exceeded"로 실패하거나 ClickHouse가 OOMKilled되는 경우 + +**증상:** 대시보드/쿼리 부하가 높을 때 분석 페이지(이벤트 스트림, `/sessions`, 모델/지연 시간 뷰, SQL 편집기)가 실패하거나 타임아웃됩니다. 서버가 잠깐 `NotReady` 상태가 되고 ClickHouse 파드의 재시작 횟수가 증가합니다. 거의 항상 **메모리** 문제이며 CPU나 디스크 문제가 아닙니다. + +**메모리 문제 확인** (복제로 해결할 처리량 문제가 아님을 확인): + +1. OOM 킬 여부를 파드에서 확인합니다: + ```bash + kubectl -n agenteye describe pod clickhouse-0 | grep -iE 'Restart Count|Last State|Reason|OOMKilled' + ``` + 재시작 횟수가 증가하면서 `Reason: OOMKilled` / `Exit Code: 137`이 나타나면 이것이 원인입니다. + +2. ClickHouse가 거부하고 있는 것을 확인합니다: + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT name, value FROM system.errors WHERE value>0 ORDER BY value DESC" + ``` + `MEMORY_LIMIT_EXCEEDED` 횟수가 많으면 해당 증상입니다. 메시지에 *"maximum: N GiB"*가 표시되는데, 이 **N은 파드 메모리 한도의 0.9배**입니다(`deploy/base/clickhouse/configmap.yaml`의 `max_server_memory_usage_to_ram_ratio`). 대용량 읽기가 N을 초과하면 거부됩니다. + +3. 문제가 **아닌** 것들을 배제합니다. CPU, 파트 수, 디스크가 모두 낮다면 레플리카/샤딩 추가는 낭비입니다: + ```bash + kubectl -n agenteye top pod clickhouse-0 + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT table, count() parts FROM system.parts WHERE active AND database='agenteye' GROUP BY table" + ``` + +**원인:** ClickHouse 파드의 메모리 한도가 분석 작업 집합에 비해 너무 작습니다. 가장 무거운 읽기는 원시 JSON `payload` 컬럼을 가져와 `JSONExtract*`를 실행하고 `FINAL`을 사용하며, 각각 수 GiB가 필요할 수 있습니다. 구성된 캐시(`mark_cache_size` + `uncompressed_cache_size`)가 파드보다 크면 동일한 예산을 소비하여 쿼리 메모리를 압박합니다. + +**해결 방법 — ClickHouse 메모리 확장:** + +1. 오버레이에서 `clickhouse` StatefulSet의 컨테이너 `resources`를 패치하여 ClickHouse 메모리 한도를 높이세요(다른 컴포넌트의 `resources`에 사용하는 오버레이 메커니즘과 동일). 사용 가능한 서버 예산은 `0.9 × 한도`입니다. `6Gi` 한도는 약 5.4GiB, `16Gi` 한도는 약 14GiB입니다. `requests.memory`도 실제 최솟값으로 설정하여 스케줄러가 이를 예약하도록 하세요. 이를 적용하면 **CH 파드가 재생성됩니다**(단일 레플리카 → 약 30~60초의 분석 다운타임). 트래픽이 적은 시간에 수행하세요. +2. `deploy/base/clickhouse/configmap \ No newline at end of file diff --git a/docs/pt-br/agenteye/alerts.mdx b/docs/pt-br/agenteye/alerts.mdx new file mode 100644 index 00000000..6169d460 --- /dev/null +++ b/docs/pt-br/agenteye/alerts.mdx @@ -0,0 +1,308 @@ +--- +title: "Alertas" +description: "Documentação de Alertas do AgentEye." +--- + +Alertas avaliam uma regra de forma programada e notificam você quando algo ultrapassa um limite. Eles transformam o AgentEye de um painel passivo em uma superfície de notificação para o que realmente importa: picos na taxa de erros, regressões de latência, quedas na pontuação de avaliadores ou qualquer evento personalizado que você consiga expressar como uma query ClickHouse. + +Este guia aborda o que é um alerta, os cinco tipos de gatilho, os quatro canais de notificação, o ciclo de vida de incidentes e os controles operacionais. + +![A página de Alertas: uma grade de cards de regras de alerta, cada um exibindo seu tipo de gatilho, janela de avaliação, canais e um emblema de severidade info/warning/critical](/agenteye/images/alerts.png) + +--- + +## Conceitos + +- **Alerta** — a regra. Ela define *o que* verificar (o gatilho), *com que frequência* (o intervalo de avaliação), *quando considerar algo quebrado* (lógica composta), *o nível de urgência* (severidade) e *quem/onde notificar* (canais). +- **Incidente** — o que acontece quando um alerta é disparado. Um alerta tem no máximo um incidente aberto por vez. Violações repetidas atualizam as evidências do mesmo incidente. Incidentes são resolvidos por um operador; a resolução automática quando a regra para de disparar está planejada, mas ainda não está ativa. +- **Canal** — para onde uma notificação vai: e-mail, Slack, webhook genérico ou painel. Cada alerta pode usar qualquer combinação. + +Alertas e incidentes pertencem a uma organização e são compartilhados entre os operadores dessa organização (em uma implantação single-tenant, isso é simplesmente a org padrão `default` integrada). Incidentes podem ser atribuídos a um operador individual para triagem. + +--- + +## Tipos de gatilho + +Cinco tipos, cada um com seu próprio spec JSON. Escolha o que melhor descreve o que significa "quebrado". O formulário **novo alerta** no painel constrói o mesmo spec para você, ajustando o editor de condição conforme o tipo de gatilho selecionado: + +![O formulário de novo alerta, com os campos básicos (nome, descrição, habilitado) e o seletor de gatilho exibindo as opções: limite de métrica, SQL personalizado, pontuação de avaliação, falhas de avaliação e por evento](/agenteye/images/alert-new.png) + +### 1. `metric_threshold` + +O mais simples. Escolha uma métrica de uma lista fechada, um operador, um limite e uma janela de tempo. + +| Métrica | O que conta | +|---|---| +| `event_count` | Total de eventos na janela | +| `error_count` | `event_type = 'error'` OU qualquer evento com `error_type IS NOT NULL` | +| `error_rate` | `error_count / event_count` (0..1) | +| `p95_latency_ms` | `quantile(0.95)(duration_ms)` em todos os eventos com `duration_ms` | +| `p99_latency_ms` | `quantile(0.99)(duration_ms)` | +| `token_sum` | `SUM(input_tokens + output_tokens)` | + +Operadores: `>`, `>=`, `<`, `<=`, `==` (também aceitos como `gt`, `gte`, `lt`, `lte`, `eq`). + +Filtros opcionais: `environment`, `event_type`. + +Exemplo de spec: + +```json +{ + "metric": "p95_latency_ms", + "filter": { "environment": "production" }, + "window_secs": 900, + "op": ">", + "value": 5000 +} +``` + +### 2. `custom_sql` + +Para situações que as métricas predefinidas não cobrem. O SQL fornecido pelo operador passa pela mesma validação do `/queries/run` (somente SELECT/WITH, instrução única, limite de 10.000 linhas) antes de o dispatcher executá-lo. Dois modos: + +- **Modo rows** (sem `op`/`value`): o alerta dispara assim que a query retorna pelo menos uma linha. +- **Modo value**: a query deve ter um alias de coluna chamado `metric_value`; o dispatcher compara o `metric_value` da primeira linha com `value` usando `op`. + +```json +{ + "sql": "SELECT count() AS metric_value FROM agenteye.events WHERE event_type = 'error' AND ts >= now() - INTERVAL 1 HOUR", + "op": ">", + "value": 100 +} +``` + +### 3. `evaluation_score` + +Lê `agenteye.evaluations` e compara a média de uma pontuação nomeada ao longo de uma janela. + +```json +{ + "score_key": "hallucination", + "op": ">", + "value": 0.6, + "window_secs": 3600, + "min_count": 5, + "environment": "production" +} +``` + +`min_count` protege contra outliers de amostra única; o dispatcher não dispara até que pelo menos N avaliações existam na janela. + +### 4. `eval_compound` + +Captura uma regressão de qualidade que só aparece em *vários* scores de avaliadores ao mesmo tempo. Enquanto `evaluation_score` monitora um único score nomeado, `eval_compound` compõe múltiplas condições de pontuação de avaliação em um único alerta e combina seus resultados com uma lógica escolhida; assim, uma regra pode expressar "disparar se a utilidade cair **ou** a alucinação subir", "disparar somente se a utilidade **e** a eficiência de ferramentas caírem", ou "disparar se **pelo menos 2 de** três verificações forem violadas". + +Cada condição lê a média de um score nomeado de `agenteye.evaluations` ao longo da janela compartilhada e o testa com seu próprio operador e limite. Os resultados booleanos são então combinados pelo `combinator`: + +| Combinador | Lógica | Dispara quando | +|---|---|---| +| `"any"` | OU | pelo menos uma condição é violada | +| `"all"` | E | todas as condições são violadas | +| `{ "at_least": N }` | M de N | pelo menos N condições são violadas | + +```json +{ + "combinator": { "at_least": 2 }, + "conditions": [ + { "score_key": "hallucination", "op": ">", "value": 0.8 }, + { "score_key": "helpfulness", "op": "<", "value": 0.6 }, + { "score_key": "tone", "op": "<", "value": 0.5 } + ], + "window_secs": 3600, + "min_count": 5, + "environment": "production" +} +``` + +- `combinator`: `"any"`, `"all"` ou `{ "at_least": N }`. +- `conditions[]`: cada `{ score_key, op, value }`, usando os mesmos operadores dos outros gatilhos (`>`, `>=`, `<`, `<=`, `==`). +- `window_secs`: o lookback compartilhado aplicado a cada condição (padrão `3600`). +- `min_count`: número mínimo de avaliações por condição antes que ela possa ser violada; uma condição com amostras insuficientes na janela é contada como "não violada" (padrão `1`). +- `environment`: opcional; restringe todas as condições a um único ambiente. + +As evidências da notificação registram a média observada de cada condição, o limite testado, quantas avaliações foram vistas e se houve violação; assim, você pode ver exatamente quais verificações foram acionadas. + +### 5. `per_event` + +Para alertas do tipo "qualquer evento que corresponda a X chegou". Sem agregação; o dispatcher dispara assim que encontra uma correspondência na janela de lookback. + +```json +{ + "event_type": "error", + "lookback_secs": 60, + "environment": "production", + "tool_name": "bash", + "agent_id": "caa", + "error_type": "TimeoutError", + "message_contains": "vertex-ai timed out" +} +``` + +Todos os filtros são combinados com AND; qualquer campo omitido fica sem restrição. + +| Campo | Finalidade | +|---|---| +| `agent_id` | Restringe a erros de um agente específico (o exibido na linha `/errors`). | +| `error_type` | Restringe a uma classe de erro específica (ex: `TimeoutError`) em vez de todos os erros. | +| `message_contains` | Correspondência de substring sem distinção de maiúsculas/minúsculas em `payload.message`. Útil para capturar um modo de falha específico (ex: `prompt is too long`) sem alertar sobre todos os erros do mesmo agente. Limitado a 200 caracteres; correspondido como string literal, não como padrão. | + +Dica: defina `lookback_secs` para corresponder aproximadamente ao `eval_interval_secs` do alerta, para evitar notificações duplicadas sobre o mesmo evento. + +**Atalho em `/errors`:** o botão **+ alert** na linha representativa de cada grupo de erros na visão de erros (e no painel de detalhes de evento de sessão para um evento de erro) abre `/alerts/new` preenchido com um gatilho `per_event` associado ao `event_type` + ambiente daquela linha, incluindo um nome derivado do `error_type` do payload quando presente. Você ainda escolhe os canais e confirma o lookback, mas o matcher já vem preenchido. Operadores precisam de `alerts:write` para que o botão apareça. + +--- + +## Lógica composta (M de N) + +Cada alerta tem dois controles inteiros além do gatilho: + +- `eval_window`: quantas avaliações recentes considerar (padrão 1) +- `min_breaches`: quantas delas precisam violar antes que o alerta dispare (padrão 1) + +`1 de 1` (o padrão) significa "disparar na primeira violação". `3 de 5` significa "disparar quando a regra tiver violado 3 das últimas 5 avaliações", útil para sinais instáveis onde uma única medição ruim é ruído. O dispatcher mantém um buffer circular por alerta; você não precisa gerenciar o estado. + +--- + +## Intervalo de avaliação + +`eval_interval_secs` controla com que frequência o dispatcher executa sua regra. Limitado ao intervalo `[30, 86400]`. Predefinições no painel: 1m / 5m / 15m / 1h. Escolha um intervalo compatível com a velocidade do sinal subjacente: um alerta de taxa de erros de 5 minutos avaliado a cada 15 segundos desperdiça CPU; um alerta por evento precisa de um lookback curto ou perderá eventos silenciosamente entre as execuções. + +--- + +## Canais + +Cada alerta pode usar qualquer combinação destes quatro. Credenciais por canal (URL do webhook do Slack, URL de webhook genérico + segredo de assinatura, destinatários de e-mail padrão) são configuradas uma vez em **`/settings`** e referenciadas por chave em cada alerta. Assim, um único canal Slack pode atender muitos alertas sem que cada um armazene sua própria cópia da URL do webhook. + +Os três tipos de canais externos (e-mail, Slack, webhook) também são controlados por um interruptor global da organização, `alerts.enabled_channels`. Quando um alerta disparado usa um tipo de canal que não está neste conjunto, o dispatcher o ignora e registra uma linha em `alert_notifications` com status `skipped_disabled` e destino `` (permitindo pausar globalmente, por exemplo, toda a entrega via Slack sem editar cada regra). O canal no painel sempre é permitido. Consulte [Configuração](#configuration). + +### E-mail + +Reutiliza o mesmo transporte SMTP que envia os e-mails de login OTP. Os destinatários são resolvidos nesta ordem: + +1. Substituição `recipients[]` por canal (quando não vazio). +2. A configuração `alerts.email_default_recipients` (um array de strings de e-mail). + +Se o SMTP não estiver configurado, o canal não faz nada; o dispatcher ainda registra uma linha em `alert_notifications` com destino `` para que a trilha de auditoria torne visível a configuração incorreta. + +### Slack + +Envia uma mensagem Block Kit para uma [URL de webhook de entrada](https://api.slack.com/messaging/webhooks). + +- URL padrão: `alerts.slack_default_webhook` (definida em `/settings`). +- Substituição por alerta: defina o `webhook_setting_key` do canal para qualquer outra chave de configuração do tipo URL, ex: `alerts.slack_oncall`, `alerts.slack_costs`. + +O cabeçalho inclui um emoji de severidade (`:rotating_light:` / `:warning:` / `:bell:`), e a mensagem traz um botão com link direto para a página do incidente. + +### Webhook genérico + +Uma integração JSON-POST para PagerDuty, Opsgenie ou seu próprio endpoint de ingestão. Formato do corpo: + +```json +{ + "schema_version": 1, + "event": "alert.firing", + "incident": { "id": "uuid", "url": "https://…/incidents/uuid", "opened_at": "2026-…" }, + "alert": { "id": "uuid", "name": "errors > 50/hr", "severity": "critical" }, + "breach": { "value": 73.0, "summary": "ErrorCount > 50 (observed 73.000)", "evidence": { … } } +} +``` + +Quando `alerts.webhook_signing_secret` está definido, a requisição inclui um cabeçalho `X-AgentEye-Signature: sha256=`, o HMAC-SHA256 do corpo usando o segredo. Verifique-o no lado receptor antes de confiar no payload. + +O cabeçalho `X-AgentEye-Event` carrega `alert.firing` / `alert.test`. (`alert.resolved` está reservado para o recurso de auto-resolução planejado e não é emitido atualmente.) + +### No painel + +Sem entrega externa: o alerta apenas escreve uma linha em `alert_notifications` que a página de incidentes do painel exibe. Útil enquanto você está ajustando uma regra e não quer sobrecarregar um sistema externo, ou para alertas de baixa urgência que os operadores verificam durante a triagem normal. + +--- + +## Ciclo de vida do incidente + +``` +firing ──ack──▶ acknowledged + │ │ + └────────────────────┴───── operator resolve ───▶ resolved +``` + +- **firing** — o dispatcher acabou de abrir o incidente ou detectou outra violação. A notificação de disparo é enviada exatamente uma vez (controlada pelo timestamp `notified_firing_at` no incidente). +- **acknowledged** — um operador pressionou *ack* em `/incidents/:id`. O incidente ainda é considerado aberto; violações subsequentes atualizarão suas evidências sem re-notificar. +- **resolved** — um operador pressionou *resolve*. A resolução automática quando a regra para de violar está planejada, mas ainda não está ativa, portanto um incidente aberto permanece aberto até que um operador o resolva. + +Um novo incidente pode ser reaberto no mesmo alerta a qualquer momento após o anterior ter sido resolvido. + +**Linha do tempo de atividade.** Cada ação em um incidente — aberto, reconhecido, resolvido — é registrada em um log de atividades somente-acréscimo e exibida na linha do tempo de *atividade* do incidente, com cada entrada atribuída ao operador que a realizou (por e-mail) ou a **automated** para ações que o dispatcher tomou por conta própria (abertura automática em violação). O reconhecimento é compartilhado: vários operadores podem reconhecer o mesmo incidente e cada um aparece como uma entrada separada e atribuída. + +A caixa de entrada de **Incidentes** agrupa incidentes abertos por estado e permite filtrar por severidade e responsável: + +![A caixa de entrada de Incidentes exibindo cards de incidentes vinculados a alertas e ad-hoc com emblemas de severidade e responsáveis](/agenteye/images/incidents.png) + +Abrir um incidente exibe as evidências da violação, responsáveis e assinantes, a linha do tempo de atividade atribuída e uma thread de comentários: + +![Uma visão de detalhe do incidente: o alerta pai, resumo da violação, responsáveis, assinantes, log de atividade atribuído e conversa](/agenteye/images/incident-detail.png) + +--- + +## Permissões necessárias + +A criação de *regras* de alerta e a triagem de *incidentes* são responsabilidades separadas com concessões distintas, para que você possa dar a uma rotação de plantão acesso a incidentes sem também conceder a capacidade de reescrever as regras. + +- `alerts:read`: visualizar regras de alerta. +- `alerts:write`: criar, editar, excluir regras de alerta e acionar uma notificação de teste. +- `incidents:read`: visualizar incidentes. +- `incidents:write`: abrir incidentes manuais (ad-hoc) que não estão vinculados a um alerta. +- `incidents:ack`: reconhecer, atribuir, comentar e resolver incidentes. + +> **`alerts:ack` legado.** Chaves e operadores que receberam o token `alerts:ack` antigo continuam funcionando: ele é aceito como `incidents:ack` (e implica `incidents:read`), para que os plantões existentes mantenham o acesso sem precisar reemitir credenciais. Emita novas concessões com a família `incidents:*`. + +Conceda em chaves de API (`POST /keys`) e operadores (`PUT /users/:id`). O `PermGate` do painel bloqueia os botões relevantes quando uma permissão está ausente; você verá `// 403` ao lado da ação. + +> **Seletor de destinatários de e-mail.** O seletor de destinatários do editor de alertas lista os membros da sua organização para que você possa selecioná-los pelo nome. Ele carrega para qualquer operador que possua `alerts:read` ou `alerts:write`; visualizar o diretório da sua equipe para esse fim **não** requer `users:read`, e o seletor retorna apenas endereços de e-mail dos membros, nunca registros completos de usuário. + +--- + +## Configuração + +Variáveis de ambiente consumidas pelo dispatcher: + +| Variável | Padrão | Finalidade | +|---|---|---| +| `ALERT_WORKERS` | `1` | Tarefas de worker por instância de servidor. A maioria das implantações precisa apenas de uma. | +| `ALERT_CLAIM_BATCH` | `16` | Máximo de alertas processados em um único tick do worker. | +| `ALERT_POLL_IDLE_SECS` | `5` | Tempo de espera do worker quando a fila está vazia. | +| `ALERT_REQUEST_TIMEOUT_MS` | `15000` | Tempo limite de avaliação por gatilho. | +| `DASHBOARD_URL` | `https://app.befailproof.ai` | Origem usada para construir o link mágico do incidente nas notificações. Defina para o host do seu painel. | + +Após uma falha de avaliação transitória (ClickHouse inacessível, timeout de query), o dispatcher tenta novamente a regra com backoff exponencial. Quando uma regra acumula **5** falhas transitórias consecutivas, ela é reagendada no seu cadência normal em vez de continuar com backoff, para que uma regra com falha persistente continue sendo reavaliada. Esse limite é fixo e não pode ser ajustado pelo operador. + +Configurações de canal (gerenciadas em `/settings`, não via env): + +- `alerts.email_default_recipients` (`email_list`): array JSON de strings de e-mail — os destinatários padrão para canais de e-mail. +- `alerts.slack_default_webhook` (`url`): URL padrão do webhook de entrada do Slack. +- `alerts.webhook_default_url` (`url`): URL padrão do webhook genérico. +- `alerts.webhook_signing_secret` (`secret`): chave HMAC-SHA256. Sempre retornada como `""` na resposta GET; digite um novo valor para rotacionar. +- `alerts.enabled_channels` (`channel_set`): o conjunto global de tipos de canais externos que são despachados quando um alerta dispara; o padrão inclui todos os três (`email`, `slack`, `webhook`). Remover um tipo aqui suprime globalmente esse canal para todos os alertas sem editar cada regra. O canal no painel sempre é entregue e não é afetado por essa configuração. + +--- + +## Verificar um novo alerta + +Antes de confiar em um novo alerta: + +1. Salve-o como habilitado com pelo menos um canal de notificação. +2. Selecione **test** na página de detalhes do alerta e confirme que cada destino configurado recebe a notificação sintética. +3. Após a primeira violação real, confirme que o incidente aparece em **Incidents** e que o valor medido corresponde à query do painel correspondente. + +Incidentes não se resolvem automaticamente quando uma condição é eliminada. Um operador deve resolvê-los na página de detalhes do incidente. + +--- + +## Solução de problemas + +| Sintoma | Causa provável | +|---|---| +| O alerta nunca dispara | `enabled = false`, nenhum canal anexado ou a query CH subjacente retorna 0 linhas. Use *test* para confirmar os canais; use `/queries/run` para confirmar a métrica. | +| Notificação do Slack ausente | `alerts.slack_default_webhook` (ou a chave de substituição por alerta) não está definida: verifique `alert_notifications.target` por linhas ``; ou o tipo `slack` está desabilitado globalmente em `alerts.enabled_channels`: verifique linhas em `alert_notifications` com status `skipped_disabled` e destino ``. | +| Webhook genérico retorna 401 | O destinatário está exigindo uma assinatura, mas `alerts.webhook_signing_secret` não está definido. Verifique no destinatário se o HMAC corresponde a `hmac_sha256(secret, body)`. | +| E-mail "from all sends failed" | Credenciais SMTP incorretas ou o endereço `from` é rejeitado pelo seu relay. A mesma superfície que envia e-mails OTP: se esses funcionam, o transporte SMTP está correto. | +| Incidente reabre repetidamente | Os controles compostos estão muito agressivos: tente aumentar `min_breaches` ou `eval_window` para que picos transitórios não reabram incidentes que você resolveu. | \ No newline at end of file diff --git a/docs/pt-br/agenteye/api-keys.mdx b/docs/pt-br/agenteye/api-keys.mdx new file mode 100644 index 00000000..b6607617 --- /dev/null +++ b/docs/pt-br/agenteye/api-keys.mdx @@ -0,0 +1,255 @@ +--- +title: "API Keys" +description: "Documentação de API Keys do AgentEye." +--- + + +O AgentEye utiliza API keys com permissões refinadas para controlar o acesso ao servidor. Cada chave carrega uma ou mais permissões que determinam o que ela pode fazer. + +--- + +## Permissões + +O servidor aplica um catálogo fixo de permissões; cada uma protege rotas HTTP específicas. Uma **chave admin** possui todas elas; uma chave com escopo restrito possui apenas o subconjunto que você define na criação. Strings de permissão desconhecidas são rejeitadas ao criar uma chave. + +> **Não atribuíveis a chaves.** Duas permissões válidas são exclusivas para humanos/dashboard e não podem ser concedidas a uma API key: `orgs:admin` (administração da instância, exclusiva do operador) e `keys:update`. Uma requisição para `POST /keys` ou `PATCH /keys/:id` que tente conceder qualquer uma delas será rejeitada com HTTP 422. Veja a linha `keys:update` abaixo para entender por que uma chave bearer pode criar chaves, mas nunca editá-las. + +### Ingestão e consulta de eventos + +| Permissão | Rotas HTTP | O que permite | +|---|---|---| +| `events:add` | `POST /events` | Ingerir lotes de eventos de um coletor. É a única permissão que um coletor precisa. | +| `events:read` | `GET /events`, `GET /events/latency_aggregate`, `GET /events/environments`, `GET /events/models`, `GET /sessions/:session_id/export` | Consultar eventos, listar os ambientes conhecidos, listar os identificadores de modelos vistos nos dados (usado pela view de Modelos e filtros de modelo), calcular o agregado de latência que alimenta o mapa de calor/banda de percentil, e exportar uma sessão como JSONL. Os endpoints de faceta do filtro compartilhado `GET /events/environments` e `GET /events/models` são acessíveis com **`events:read` ou `evaluations:read`**, de modo que a página de sessões (controlada por `evaluations:read`) reutiliza a mesma faceta por organização. | + +### Sessões e avaliações + +| Permissão | Rotas HTTP | O que permite | +|---|---|---| +| `evaluations:read` | `GET /sessions`, `GET /evaluations`, `GET /evaluations/aggregate`, `GET /evaluations/environments`, `GET /evaluation-jobs` | Listar sessões, ler resultados de avaliações, a saúde consolidada de avaliações usada pelos dashboards, e o estado da fila de trabalho de evaluation-jobs. | +| `evaluations:trigger` | `POST /sessions/:session_id/re-evaluate` | Enfileirar manualmente uma reavaliação para uma sessão finalizada. | + +### Dashboards + +| Permissão | Rotas HTTP | O que permite | +|---|---|---| +| `dashboards:read` | `GET /dashboards`, `GET /dashboards/:id`, `GET /dashboards/:id/tiles` | Listar dashboards, carregar um deles e ler seus tiles. | +| `dashboards:write` | `POST /dashboards`, `PUT /dashboards/:id`, `POST /dashboards/:id/tiles`, `PUT /dashboards/:id/tiles/:tile_id`, `DELETE /dashboards/:id/tiles/:tile_id`, `PUT /dashboards/:id/tiles/layout` | Criar e editar dashboards, adicionar/editar/remover tiles e reorganizar o grid. | +| `dashboards:delete` | `DELETE /dashboards/:id` | Excluir um dashboard inteiro (a exclusão a nível de tile está em `dashboards:write`). | + +### Consultas salvas (compositor SQL) + +| Permissão | Rotas HTTP | O que permite | +|---|---|---| +| `queries:read` | `GET /queries`, `GET /queries/:id`, `GET /queries/schema` | Listar consultas salvas, carregar uma delas e inspecionar o schema somente leitura do ClickHouse que o compositor utiliza. | +| `queries:write` | `POST /queries`, `PUT /queries/:id` | Criar e editar consultas salvas. O SQL ainda é roteado pelo mesmo papel somente leitura e pelas verificações do `sql_guard`, assim como em uma chamada `queries:run`. | +| `queries:delete` | `DELETE /queries/:id` | Excluir uma consulta salva. | +| `queries:run` | `POST /queries/run` | Executar SQL salvo ou ad-hoc contra o papel somente leitura usado pelo compositor. | + +### Assistente de IA + +| Permissão | Rotas HTTP | O que permite | +|---|---|---| +| `agent:use` | `GET /agent/conversations`, `POST /agent/conversations`, `GET /agent/conversations/:id`, `PATCH /agent/conversations/:id`, `DELETE /agent/conversations/:id`, `PUT /agent/conversations/:id/messages` | Conversar com o assistente de IA do dashboard e gerenciar suas próprias conversas (privadas). É necessária no **usuário** para exibir o painel do assistente; a própria chave do assistente é `dashboard-assistant` e é inicializada separadamente (veja abaixo). | + +### API Keys + +| Permissão | Rotas HTTP | O que permite | +|---|---|---| +| `keys:create` | `POST /keys` | Criar uma nova API key com escopo. **Não** concede a edição das permissões de uma chave existente (isso é `keys:update`). | +| `keys:read` | `GET /keys` | Listar as chaves existentes. Segredos nunca são retornados por esse endpoint. | +| `keys:update` | `PATCH /keys/:id` | Editar as permissões de uma chave existente. Permissão **exclusiva para humanos/dashboard**; não pode ser atribuída a uma API key (uma chave bearer pode criar chaves, mas nunca editá-las). | +| `keys:disable` | `POST /keys/:id/disable` | Revogar uma chave. Chaves protegidas (`admin`, `dashboard-assistant`) não podem ser desabilitadas; faça a rotação via variável de ambiente + reinicialização. | +| `keys:regenerate` | `POST /keys/:id/regenerate` | Rotacionar o segredo de uma chave. Chaves protegidas não podem ser regeneradas por essa rota. | + +### Usuários do dashboard + +| Permissão | Rotas HTTP | O que permite | +|---|---|---| +| `users:create` | `POST /users`, `GET /users/defaults` | Convidar um novo usuário do dashboard (envia um email + login OTP) e ler o conjunto de permissões padrão configurado no dashboard, usado para preencher o formulário de convite. | +| `users:read` | `GET /users`, `GET /users/:id` | Listar usuários e carregar um registro de usuário individual. | +| `users:update` | `PUT /users/:id` | Editar as permissões de um usuário. As atualizações enviam um email de mudança de permissão ao usuário afetado e entram em vigor na próxima requisição dele; não é necessário fazer login novamente. | +| `users:delete` | `DELETE /users/:id`, `POST /users/:id/enable` | Desabilitar um usuário (revoga suas sessões imediatamente) e reabilitar um usuário previamente desabilitado. | + +Essas permissões embasam a página **Users** do dashboard, onde os escopos concedidos a cada membro são exibidos como chips: + +![A página Users: um card por usuário do dashboard com seu email, permissões concedidas e controles de edição/desabilitação](/agenteye/images/users.png) + +### Configurações operacionais + +| Permissão | Rotas HTTP | O que permite | +|---|---|---| +| `settings:read` | `GET /settings`, `GET /settings/schema`, `GET /settings/model-context-windows`, `GET /settings/model-context-windows/resolve` | Visualizar as configurações operacionais gerenciadas pelo dashboard e seus metadados; listar overrides de janela de contexto por modelo; e resolver a janela efetiva para um modelo. | +| `settings:write` | `PUT /settings/:key`, `PUT /settings/model-context-windows`, `DELETE /settings/model-context-windows` | Editar configurações operacionais e adicionar, alterar ou remover overrides de janela de contexto por modelo. As alterações afetam novos eventos sem reiniciar o servidor. | + +![A página Settings: configurações operacionais gerenciadas pelo dashboard, como logins permitidos e durações de sessão/OTP, editáveis sem reinicialização](/agenteye/images/settings.png) + +### Alertas e incidentes + +| Permissão | Rotas HTTP | O que permite | +|---|---|---| +| `alerts:read` | `GET /alerts`, `GET /alerts/:id` | Visualizar definições de alertas configuradas. | +| `alerts:write` | `POST /alerts`, `PUT /alerts/:id`, `DELETE /alerts/:id`, `POST /alerts/:id/test` | Criar, editar, excluir e disparar alertas para teste. | +| `incidents:read` | `GET /alerts/incidents`, `GET /alerts/incidents/:iid`, `GET /alerts/incidents/:iid/comments`, `GET /alerts/incidents/:iid/subscribers` | Visualizar incidentes e sua trilha de triagem. | +| `incidents:write` | `POST /alerts/:id/incidents` | Abrir um incidente manualmente para um alerta existente. | +| `incidents:ack` | `POST /alerts/incidents/:iid/ack`, `POST /alerts/incidents/:iid/assign`, `POST /alerts/incidents/:iid/resolve`, `POST /alerts/incidents/:iid/comments`, `POST /alerts/incidents/:iid/subscribe`, `POST /alerts/incidents/:iid/unsubscribe` | Reconhecer, atribuir, resolver e comentar em incidentes. | + +### Auditorias + +| Permissão | Rotas HTTP | O que permite | +|---|---|---| +| `audits:read` | `GET /audits`, `GET /audits/:id`, `GET /audits/:id/runs`, `GET /audits/findings`, `GET /audits/findings/:fid` | Visualizar definições de auditoria, histórico de execuções e achados. | +| `audits:write` | `POST /audits`, `PUT /audits/:id`, `DELETE /audits/:id`, `POST /audits/:id/run`, `POST /audits/findings/:fid/status` | Criar, editar, excluir e executar auditorias; fazer triagem de achados (reconhecer/silenciar/descartar/resolver/reabrir/atribuir). | + +> Quando o recurso de Auditorias foi lançado, as concessões existentes foram ampliadas seguindo os mesmos padrões de função dos alertas: todo usuário e conjunto de permissões com `alerts:read` passou a ter `audits:read`, e todo portador de `alerts:write` passou a ter `audits:write`. As API keys existentes **não** foram ampliadas — conceda `audits:*` a uma chave explicitamente caso ela precise acessar a funcionalidade de auditoria. + +> Concessões armazenadas do token legado `alerts:ack` são interpretadas como `incidents:ack`, para que os responsáveis de plantão mantenham o acesso sem precisar gerar novas chaves. O token não é mais atribuível pelo editor de usuários do dashboard; a matriz oferece `incidents:ack` em seu lugar. + +> O endpoint de seleção de destinatários `GET /alerts/recipients` (que lista os emails dos membros que um editor de alerta pode notificar) é acessível por quem possui **`alerts:read` ou `alerts:write`**, de modo que os editores de alertas podem preencher o seletor sem precisar de `users:read`. + +> Um visualizador de dashboards precisa de **`dashboards:read`** (para carregar as views salvas) **e** `evaluations:read` (as métricas de saúde são calculadas a partir de dados de avaliação). Conceda `dashboards:write` para permitir que um usuário crie ou edite dashboards, e `dashboards:delete` para removê-los. + +> `/health` e `/auth/*` (solicitação de OTP, verificação de OTP, verificação de sessão, logout) não requerem autenticação por design; fazem parte do fluxo de login e do probe de liveness. `GET /access-granters` exige uma chave válida, mas nenhuma permissão específica, de modo que qualquer usuário autenticado pode ver quais administradores contatar sobre mudanças de acesso. + +--- + +## Conjuntos de Permissões + +Os conjuntos de permissões permitem aplicar uma função nomeada em vez de selecionar tokens individuais manualmente a cada vez. Em vez de escolher uma dúzia de permissões uma a uma para cada novo usuário do dashboard ou API key, você escolhe um conjunto, e todos os que forem atribuídos a ele terão uma concessão consistente e auditável. Editar um conjunto personalizado reaplicará a nova concessão a todos os usuários já atribuídos a ele, de modo que uma mudança de função é uma única edição, não uma varredura por todos os membros. + +Cada organização é inicializada com três conjuntos padrão: + +| Conjunto | Permissões | Destinado a | +|---|---|---| +| `read-only` | `events:read`, `keys:read`, `users:read`, `evaluations:read`, `dashboards:read`, `queries:read`, `settings:read`, `alerts:read`, `audits:read`, `incidents:read` | Acesso somente leitura em toda a superfície operacional. | +| `standard` | tudo em `read-only`, mais `evaluations:trigger`, `queries:run`, `incidents:ack`, `agent:use` | Somente leitura acrescido das ações cotidianas de plantão: executar consultas, reavaliar sessões, reconhecer incidentes e usar o assistente de IA. | +| `admin` | toda permissão atribuível | Controle total da organização. | + +Os três conjuntos padrão são **imutáveis**; seus nomes sempre significam a mesma coisa, portanto `read-only`, `standard` e `admin` são seguros para referenciar em políticas e processos de integração. Um operador pode criar **conjuntos personalizados** adicionais para modelar funções específicas de sua organização (por exemplo, uma função de "autor de dashboard" ou uma função de "somente coletor"). + +Os conjuntos são expostos no dashboard e gerenciados via API em `GET /permission-sets` (listagem, controlada por `users:read`) e `POST /permission-sets` / `PUT /permission-sets/:name` / `DELETE /permission-sets/:name` (criar, editar, excluir um conjunto personalizado, controlado por `settings:write`). Excluir ou editar um conjunto padrão é recusado. + +A associação a conjuntos embase dois outros recursos: + +- **`DEFAULT_USER_PERMISSIONS`** (a concessão pré-selecionada quando um admin abre **+ novo usuário**) tem como padrão o conjunto `standard`. Veja [Deployment](/pt-br/agenteye/deployment). +- **A flag `--set`** no `agenteye-orgctl` (gerenciamento de membros pelo operador) inicia um membro a partir de um conjunto nomeado, que você pode ajustar com `--add` / `--remove`. Veja [Tenant Management](/pt-br/agenteye/tenant-management). + +> Quando um conjunto inclui uma permissão não atribuível a chaves (por exemplo, um conjunto personalizado com `keys:update`), ao inicializar uma chave a partir desse conjunto, os tokens não atribuíveis são descartados; caso contrário, o servidor rejeitaria a chave com HTTP 422. Usuários do dashboard não estão sujeitos a essa restrição. + +--- + +## Chave Admin de Bootstrap + +A chave admin é a credencial raiz única que permite a um operador iniciar o acesso do zero: com ela você pode criar todas as outras chaves com escopo, convidar os primeiros usuários do dashboard e configurar a instância antes que qualquer outra chave exista. É a única chave que você não cria pela API de chaves; ela é provisionada a partir do ambiente para que o servidor seja acessível na primeira inicialização. + +Defina a variável de ambiente `ADMIN_KEY` no servidor. Em cada inicialização, o servidor faz upsert desse valor como uma chave admin com todas as permissões. + +Para rotacionar: altere `ADMIN_KEY` para um novo segredo e reinicie o servidor. + +--- + +## Escopo de organização + +**As organizações em si são criadas e gerenciadas fora de banda por um operador, não por esta API de chaves.** O ciclo de vida de organizações e membros (criar/renomear/excluir/purgar uma organização; adicionar/atualizar/remover um membro) é realizado com a CLI **`agenteye-orgctl`**, que roda dentro do pod do servidor; não há API HTTP ou botão no dashboard para isso. Veja [Tenant Management](/pt-br/agenteye/tenant-management). O que *não muda*: **as API keys por organização ainda são criadas no dashboard (ou via esta API de chaves)** pelos membros da organização. + +Em uma implantação multi-organização, toda chave criada por um membro (por esta API de chaves ou pela página **Keys** do dashboard) pertence a **uma organização** e só pode ler ou escrever os dados dessa organização; a organização é registrada na chave no momento da criação e verificada em cada requisição. As duas chaves de bootstrap são a única exceção: a chave `admin` (inicializada a partir de `ADMIN_KEY`) e a chave `dashboard-assistant` (inicializada a partir de `AGENT_API_KEY`) têm **escopo de instância** (não carregam organização). O container do dashboard autentica com a chave `admin` para que possa fazer proxy de requisições por organização em nome dos membros autenticados. Implantações single-tenant não precisam se preocupar com isso; todas as chaves pertencem à organização padrão `default`. + +--- + +## Criando Chaves + +Use a chave admin (ou qualquer chave com permissão `keys:create`) para criar chaves adicionais com escopo. + +### Chave de coletor (somente ingestão) + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "prod-collector", + "key": "your-collector-secret", + "permissions": ["events:add"] + }' +``` + +### Chave de dashboard (somente leitura) + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "dashboard", + "key": "your-dashboard-secret", + "permissions": ["events:read", "keys:read"] + }' +``` + +Ao criar uma chave pela API HTTP, você fornece o valor de `key` você mesmo; escolha um segredo forte e armazene-o com segurança. (O dashboard funciona de forma diferente: ele gera um segredo forte para você e o exibe uma única vez na criação; veja [Gerenciamento de Chaves no Dashboard](#key-management-in-the-dashboard).) A resposta confirma que a chave foi criada: + +```json +{ + "id": "550e8400-e29b-41d4-a716-446655440000", + "name": "prod-collector", + "permissions": ["events:add"], + "created_at": "2026-04-01T12:00:00Z" +} +``` + +--- + +## Listando Chaves + +```bash +curl -s http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +Os segredos das chaves não são retornados nas respostas de listagem; apenas IDs, nomes e permissões. + +--- + +## Desabilitando uma Chave + +Desabilitar revoga o acesso imediatamente sem excluir o registro da chave. + +```bash +curl -s -X POST http://your-server:8080/keys//disable \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +--- + +## Regenerando uma Chave + +Gera um novo segredo para uma chave existente. O segredo antigo é invalidado imediatamente. + +```bash +curl -s -X POST http://your-server:8080/keys//regenerate \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +A resposta inclui o novo segredo em texto simples, **exibido apenas uma vez**. + +--- + +## Gerenciamento de Chaves no Dashboard + +A página **Keys** no dashboard oferece uma interface para todas as operações acima. Você precisa de uma chave com permissão `keys:read` para visualizar a lista, e `keys:create` / `keys:update` / `keys:disable` / `keys:regenerate` para as ações de criar/editar/desabilitar/regenerar, respectivamente. Editar as permissões de uma chave (`keys:update`) é separado de criá-la (`keys:create`), de modo que você pode conceder a um operador a capacidade de criar chaves sem a capacidade de reatribuir o escopo das existentes, ou vice-versa. A chave admin cobre todas essas operações. + +Ao criar uma chave pelo dashboard, você não fornece o segredo; o dashboard gera um segredo forte para você e o exibe **uma única vez** na criação. Copie-o imediatamente e armazene-o com segurança; ele nunca será exibido novamente, exatamente como acontece com uma regeneração. Você ainda pode escolher as permissões da chave diretamente, ou inicializá-las a partir de um conjunto de permissões (veja abaixo). + +![A página API Keys: um card por chave mostrando nome, permissões concedidas e data de criação, com ações de regenerar e desabilitar; chaves protegidas como `admin` são marcadas](/agenteye/images/api-keys.png) + +--- + +## Layout de Chaves Recomendado + +| Chave | Permissões | Usada por | +|---|---|---| +| `admin` (bootstrap via variável de ambiente `ADMIN_KEY`) | todas | Operações/configuração, e o container do dashboard (autentica com `ADMIN_KEY`, faz proxy de requisições de usuários com verificações de permissão) | +| Chave de coletor por host | `events:add` | Coletor em cada máquina de agente | +| `dashboard-assistant` (bootstrap via variável de ambiente `AGENT_API_KEY`) | `events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run` | Container do assistente de IA, inicializado automaticamente, **protegido**; não pode ser editado pela API | +| Chave de telemetria do assistente (opcional) | `events:add` | Auto-instrumentação do assistente de IA, se habilitada | + +> **Chave do assistente.** A chave do assistente é **inicializada automaticamente** pelo servidor a partir da variável de ambiente `AGENT_API_KEY` (o mesmo segredo que o agente apresenta como `AGENTEYE_API_KEY`); não há etapa manual de criação de chave nem envolvimento da chave admin. Suas permissões são fixadas no código-fonte para que o escopo não possa ser ampliado por configuração incorreta: leitura de eventos/avaliações/dashboards, mais escrita em dashboards e leitura/escrita/execução de consultas para o fluxo de criação de consultas via IA. Todo SQL ainda passa pelo mesmo papel somente leitura e pelas verificações do `sql_guard` que uma consulta escrita por um usuário, portanto isso amplia a *superfície de criação*, não a superfície de dados; operações destrutivas (`queries:delete`, `dashboards:delete`) são deliberadamente mantidas fora da chave do assistente. Assim como a chave `admin`, ela é **protegida**: não pode ser desabilitada ou regenerada pela API de chaves, apenas rotacionada alterando `AGENT_API_KEY` e reiniciando. *Usuários* do dashboard também precisam da permissão `agent:use` para ver e usar o assistente. Se você habilitar a auto-instrumentação, forneça ao assistente uma chave separada somente com `events:add`. \ No newline at end of file diff --git a/docs/pt-br/agenteye/assistant.mdx b/docs/pt-br/agenteye/assistant.mdx new file mode 100644 index 00000000..00a02135 --- /dev/null +++ b/docs/pt-br/agenteye/assistant.mdx @@ -0,0 +1,195 @@ +--- +title: "Assistente IA" +description: "Documentação do Assistente IA AgentEye." +--- + +O dashboard inclui um **assistente IA** opcional, um painel de chat ancorado na borda direita do dashboard que responde perguntas em linguagem natural sobre seus agentes ("como está a qualidade evoluindo em produção esta semana?", "quais sessões apresentaram erros hoje?", "resuma esta sessão") e, quando o usuário autoriza cada ação, elabora e salva queries SQL e dashboards em seu nome. Ele cita links clicáveis diretamente para as sessões, queries e dashboards relevantes, e é **ciente do contexto da página**: pergunte sobre "esta sessão" enquanto estiver visualizando uma e ele entende o que você quer dizer. + +O dock aparece por padrão como um **trilho vertical de 44px**: um glifo de prompt `›_` mais um ponto colorido de saúde. Clique no trilho (ou pressione `⌘J` / `Ctrl+J`) para expandir ao painel de chat completo. O painel expandido é **redimensionável** entre 320 e 640 pixels arrastando sua borda esquerda; a largura preferida é lembrada entre recarregamentos. + +Ele roda como um pequeno container **`agent`** interno (no Claude Agent SDK) que apenas o dashboard pode acessar. Está **desabilitado por padrão** e permanece oculto até que você configure um endpoint de LLM. + +--- + +## O que ele pode e não pode fazer + +- **Lê os dados operacionais que o usuário solicitante pode ver.** Eventos, avaliações, sessões, a fila de jobs de avaliação, queries salvas e dashboards salvos, com escopo por requisição conforme as permissões de leitura do usuário. As ferramentas de leitura são executadas imediatamente. +- **Escritas requerem aprovação por ação.** Ele pode criar queries salvas (`create_saved_query`, `update_saved_query`), executar SQL de rascunho contra o papel somente-leitura para validação (`run_query`), e montar dashboards a partir dessas queries (`create_dashboard`, `update_dashboard`, `add_query_to_dashboard`). Cada escrita pausa para um prompt **Aprovar / Rejeitar / fazer uma pergunta** no chat; o SDK não chama a ferramenta até que o operador clique em Aprovar. **Exclusão nunca está disponível para o assistente**; operações destrutivas permanecem com os operadores. +- **O SQL elaborado passa pela mesma validação `sql_guard` e pelos mesmos papéis somente-leitura que o SQL escrito pelo usuário** (apenas SELECT/WITH, sem múltiplos statements). A execução é roteada conforme quais tabelas a query referencia: queries que referenciam as tabelas de analytics (eventos, avaliações, sessões) rodam como o usuário ClickHouse somente-leitura da organização (com escopo para aquela org por uma política de linha, com limite de execução de 10s e limite de 100k linhas), enquanto queries que tocam apenas tabelas relacionais rodam em um papel Postgres somente-leitura (10s, 10k linhas). O assistente não pode ampliar a superfície de dados; ele só pode criar queries sobre a superfície que o operador já possui. +- Ele usa uma **chave de assistente dedicada** (veja abaixo) inicializada com um conjunto fixo de permissões; mesmo que o modelo se comporte de forma inesperada, não pode ultrapassar esses escopos. +- Cada usuário do dashboard precisa da permissão **`agent:use`** para ver e usar o assistente. As ferramentas são filtradas por requisição para corresponder às permissões de dados do próprio usuário, então um usuário com `events:read` recebe ferramentas de eventos, mas não ferramentas de `dashboards:write`. + +--- + +## Dock de IA ciente do contexto: composer em `/queries`, chat em outros lugares + +O dock de assistente no lado direito é **ciente do contexto da página**. O seletor de modelo, o histórico de conversa, o ponto de saúde do modelo e o campo de chat permanecem inalterados, mas os **chips de template do estado vazio, o texto placeholder e qual endpoint de backend uma mensagem do usuário acessa** mudam automaticamente com base na rota atual. O dock se torna "o assistente IA para a página em que você está". + +**Dois backends, escolhidos por página (com substituições por chip).** + +| Rota | Backend padrão da página | Por quê | +| ------------------------------ | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | +| `/queries`, `/queries/new` | `POST /api/agent/compose-sql` (sem loop de ferramentas) | O usuário está começando do zero; SQL com primeiro token em ≤1s transmitido diretamente para o editor | +| `/queries/` (existente) | `POST /api/agent/chat` (assistente com loop de ferramentas completo), padrão da página | Mensagens digitadas livremente devem permitir que o usuário pergunte qualquer coisa ("explique isso", "o que isso faz?"); chips de refatoração optam pelo compose-sql via `kind` por chip | +| todas as outras páginas | `POST /api/agent/chat` (assistente com loop de ferramentas completo) | Ferramentas de leitura + ferramentas de escrita com aprovação | + +Os chips em `/queries/` carregam um `kind` explícito para que uma única página possa misturar os dois fluxos de forma transparente. O conjunto padrão de chips é dois chips de **chat** (`explicar a query na tela`, `o que esta query faz?`) mais cinco chips de **compose-sql** (`parametrizar por intervalo de datas`, `adicionar filtro status='error'`, etc.). Mensagens digitadas livremente recaem no padrão da página (chat), então uma pergunta como "por que isso está tão lento?" recebe uma resposta em prosa, enquanto clicar no chip `parametrizar por intervalo de datas` roteia pelo endpoint compose e edita o SQL. + +Quando o composer roda no **modo de edição** (ele vê um `currentSql` não vazio porque o usuário está em `/queries/` ou `/queries/new` com SQL proposto já carregado), seu prompt do sistema muda de "escreva uma nova query" para "modifique o SQL fornecido minimamente: preserve a escolha de tabela, nomes de colunas, estrutura de joins, aliases, indentação". O modelo recebe um conjunto separado de exemplos antes/depois trabalhados (parametrizar, adicionar filtro, converter para buckets por hora), então uma refatoração acionada por chip produz uma diferença mínima em relação ao SQL do editor, não uma reescrita do zero. + +Clique em um chip compose (ou digite livremente em `/queries/new`) → o SQL é transmitido para a mensagem do assistente como um bloco ` ```sql ` delimitado. **No momento em que a transmissão finaliza, se o Monaco estiver montado na rota atual, o editor acende automaticamente no modo diff** (original à esquerda, proposto à direita, um indicador `▾ IA propôs uma edição` no topo, e botões **Aceitar / Rejeitar** abaixo). O usuário não precisa encontrar ou clicar em um botão `Inserir no editor` para ver o diff. O botão Inserir ainda é renderizado abaixo do bloco SQL como um acionador manual (útil após um Rejeitar ou quando o usuário navegou para outro lugar e voltou), e permanece o único caminho quando o usuário está em uma página sem editor (ex.: a lista de queries salvas); lá ele armazena o SQL no `sessionStorage` e navega para `/queries/new`, onde o editor recém-montado lê o armazenamento no mount e abre o mesmo modo diff. + +Se o SQL proposto for byte a byte idêntico ao que já está no editor (uma edição sem efeito), a abertura automática é ignorada; não exibimos um diff vazio. O botão `Inserir no editor` também não tem efeito nesse caso. + +Quando o usuário aceita uma sugestão em `/queries/new`, a ação primária da barra de ferramentas exibe **`salvar`** em vez de `criar`; o SQL foi entregue a eles pelo assistente; o modelo mental é "finalizar isso", não "escrever do zero". O rótulo muda uma vez que o dock insere SQL e permanece como `salvar` até a navegação de página. Em `/queries/` o botão sempre exibiu `salvar`; nada muda ali. + +Fora de `/queries`, o dock funciona exatamente como antes: chat completo com cards de aprovação de ferramentas, consciência de contexto de página, citações. + +**Permissões / controle de acesso.** O endpoint compose verifica a permissão `queries:run` por usuário (equivalente a leitura; o usuário ainda precisa clicar em Aceitar e Executar, e Executar passa pelo `sql_guard` + roteamento `references_ch_tables` existente no servidor Rust). O endpoint chat verifica `agent:use`. Ambos ainda requerem uma conexão LLM configurada no container `agent`; se nenhuma estiver configurada, o dock exibe um banner "o assistente não está configurado neste deployment" em qualquer um dos caminhos. + +**Recusas.** O composer recusa qualquer requisição que não possa satisfazer com uma query de analytics somente-leitura e emite `-- REFUSE: ` em vez de SQL. Ele recusa requisições que escrevam dados ou acessem tabelas fora das views de analytics (`api_keys`, `users`, `dashboards`, `saved_queries`, `evaluation_jobs`), e recusa requisições de prosa pura ("explique isso", "o que isso faz?") no caminho compose; essas pertencem ao caminho chat e produzem uma resposta em prosa lá. O dock renderiza a string de recusa como um chip de erro vermelho inline na mensagem do assistente; nada é inserido. + +**Seleção de modelo.** Compartilhada com o caminho chat. O seletor de modelo no cabeçalho do dock se aplica a ambos os endpoints (a chamada compose passa o modelo selecionado para `resolveModel()` no serviço agent). Quando `AGENTEYE_AGENT_MODELS` lista múltiplos modelos, operadores podem combinar uma opção da classe Haiku para o composer com uma opção da classe Sonnet para o chat; o usuário escolhe por conversa. + +**Templates por página.** Cada página tem seu próprio template (título, corpo, texto placeholder e chips de sugestão) para que o dock se adapte à página em que você está. Os chips oferecidos em uma determinada rota mapeiam para as mesmas intenções para as quais o composer foi ajustado, então clicar em uma sugestão produz a edição esperada. + +**Desabilitando.** Igual ao caminho chat: o dock + composer são ambos controlados pelo container `agent` e sua conexão LLM. Se você quiser comportamento apenas-chat para um usuário específico, remova a permissão `queries:run` (que também desabilita o botão **Executar** do editor); se quiser comportamento apenas-composer, remova `agent:use` dos papéis desse usuário, depois adicione `queries:run` separadamente para que ainda possam executar SQL escrito por autores. + +--- + +## Habilitando + +O serviço `agent` vem no arquivo Docker Compose e nos manifestos Kubernetes. Para ativar o assistente, forneça **(1)** um endpoint de LLM e **(2)** a chave de dados dedicada do assistente. + +### 1. Escolha uma conexão LLM + +Escolha uma destas opções e defina as variáveis correspondentes no serviço `agent`: + +**a) Anthropic diretamente** + +``` +ANTHROPIC_API_KEY=sk-ant-... +``` + +**b) Através do Portkey (recomendado; slug do catálogo de modelos, apenas chave)** + +``` +PORTKEY_API_KEY= +AGENTEYE_AGENT_MODEL=@/claude-sonnet-4-6 +``` + +Este é o caminho mais simples: no Portkey, configure uma **integração Anthropic** (Model Catalog); ela recebe um **slug**. Nomeie o modelo como `@/` e o slug carrega o roteamento de provedor + credencial, então **nenhuma chave virtual é necessária**, apenas sua chave de API do Portkey. O agent envia apenas `x-portkey-api-key` e aponta para o gateway do Portkey; o Portkey resolve o restante. (Um nome de modelo *simples* falha com "x-portkey-config or x-portkey-provider header is required"; o prefixo `@slug/` é o que faz o modo apenas-chave funcionar.) Para um gateway auto-hospedado, defina `PORTKEY_BASE_URL`. + +Prefere roteamento por requisição em vez de slug? Defina `PORTKEY_VIRTUAL_KEY=` (ou `PORTKEY_CONFIG=`) com um `AGENTEYE_AGENT_MODEL` simples. + +**c) Qualquer outro gateway compatível com Anthropic (LiteLLM, auto-hospedado, …)** + +``` +ANTHROPIC_BASE_URL=https://seu-gateway +# Linhas "Nome: Valor" delimitadas por nova linha (NÃO JSON): +ANTHROPIC_CUSTOM_HEADERS=x-meu-header: valor +``` + +**d) Amazon Bedrock / Google Vertex** + +``` +CLAUDE_CODE_USE_BEDROCK=1 # + credenciais AWS padrão no ambiente +# ou +CLAUDE_CODE_USE_VERTEX=1 # + credenciais GCP padrão no ambiente +``` + +Opcionalmente fixe o modelo padrão com `AGENTEYE_AGENT_MODEL` (padrão `claude-sonnet-4-6`). Para permitir que usuários **escolham** entre vários modelos, defina `AGENTEYE_AGENT_MODELS` como uma lista de permissões separada por vírgulas (ex.: `@anthropic-prod/claude-opus-4-7,@anthropic-prod/claude-sonnet-4-6`); um seletor de modelo então aparece no cabeçalho do chat, e a escolha de cada usuário é lembrada. O agent sempre chama apenas um modelo nesta lista de permissões. + +### 2. Forneça a chave do assistente + +Escolha qualquer secret aleatório e forneça-o ao **agent** como `AGENTEYE_API_KEY` e ao **server** como `AGENT_API_KEY` (o mesmo valor). Na inicialização, o server o inicializa como uma chave dedicada chamada `dashboard-assistant` com este conjunto fixo de permissões: `events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run`. As permissões de escrita são exercidas apenas através de ferramentas com aprovação (consulte "O que ele pode e não pode fazer" acima). **Não há etapa manual de criação de chave e nenhuma chave admin envolvida**. O conjunto de permissões é fixado no server, e a chave inicializada é **protegida**: não pode ser desabilitada ou regenerada pela API de chaves; faça a rotação alterando o valor e reiniciando o server. **Não** reutilize a chave admin/dashboard. + +```bash +SECRET="$(openssl rand -base64 32)" +# no serviço agent: +AGENTEYE_API_KEY="$SECRET" +# no serviço server: +AGENT_API_KEY="$SECRET" +``` + +No Kubernetes, isso é configurado automaticamente: coloque `AGENTEYE_API_KEY` no secret `agenteye-agent` e o Deployment do server já lê esse mesmo valor como `AGENT_API_KEY`. + +### 3. Configure o token compartilhado dashboard↔agent + +Defina o mesmo `AGENTEYE_AGENT_TOKEN` nos serviços **dashboard** e **agent**. O dashboard o apresenta ao chamar o serviço agent interno; o agent rejeita chamadas sem ele. + +### 4. Conceda acesso aos usuários + +Dê aos operadores de dashboard relevantes a permissão `agent:use` (consulte [enterprise-docs/api-keys.md](/pt-br/agenteye/api-keys)). Usuários sem ela nunca veem o assistente. + +Uma vez que um endpoint LLM e a chave somente-leitura estejam configurados, reinicie o **server** (para inicializar a chave somente-leitura) e o serviço **agent**. O dock do assistente aparece na borda direita para qualquer usuário com `agent:use`, recolhido por padrão; clique no trilho ou pressione `⌘J` / `Ctrl+J` para expandir. + +--- + +## Referência de variáveis de ambiente + +Definir no serviço **`agent`**: + +| Variável | Propósito | +|---|---| +| `PORTKEY_API_KEY` | Rotear através do Portkey (o agent constrói a conexão de gateway a partir disso) | +| `PORTKEY_VIRTUAL_KEY` | Chave virtual do Portkey para suas credenciais Anthropic (opcional se a chave tiver uma configuração padrão) | +| `PORTKEY_CONFIG` / `PORTKEY_BASE_URL` | Configuração Portkey nomeada / URL do gateway Portkey auto-hospedado (opcional) | +| `PORTKEY_PROVIDER` | Slug de provedor do Portkey — uma terceira opção de roteamento ao lado de `PORTKEY_VIRTUAL_KEY` / `PORTKEY_CONFIG` (usado apenas quando nenhum dos dois está definido) | +| `ANTHROPIC_API_KEY` | Acesso direto à Anthropic (alternativa a gateway / Bedrock / Vertex) | +| `ANTHROPIC_AUTH_TOKEN` | Token Bearer para um gateway que autentica via `Authorization: Bearer` em vez de `x-api-key` (opcional) | +| `ANTHROPIC_BASE_URL` | Endpoint para um gateway não-Portkey | +| `ANTHROPIC_CUSTOM_HEADERS` | Headers extras para um gateway não-Portkey: linhas `Nome: Valor` delimitadas por nova linha (não JSON) | +| `CLAUDE_CODE_USE_BEDROCK` / `CLAUDE_CODE_USE_VERTEX` | Rotear via Bedrock / Vertex | +| `AGENTEYE_AGENT_MODEL` | ID do modelo padrão (padrão `claude-sonnet-4-6`) | +| `AGENTEYE_AGENT_MODELS` | Lista de permissões de modelos separada por vírgulas que o usuário pode escolher no cabeçalho do chat. Deixe sem definir para um único modelo fixo. O padrão acima deve ser um destes (caso contrário, é adicionado). | +| `AGENTEYE_AGENT_MAX_CONCURRENCY` | Máximo de chats simultâneos por pod (padrão 4); requisições excedentes recebem 429 | +| `AGENTEYE_API_KEY` | Chave de dados do assistente. Defina o **mesmo** valor que o `AGENT_API_KEY` do server, que o inicializa com um conjunto fixo de permissões com escopo na inicialização (veja etapa 2). | +| `AGENTEYE_AGENT_TOKEN` | Secret compartilhado com o dashboard | +| `AGENTEYE_SERVER_URL` | URL do server AgentEye (padrão `http://server:8080`) | +| `AGENTEYE_AGENT_ALLOW_NO_ORG` | **Multi-tenancy.** Desativado por padrão (fail-closed): o assistente rejeita uma requisição `/chat` que não carrega contexto de organização com `400`, porque cada ferramenta que executa tem escopo para uma org. O dashboard sempre envia esse contexto assim que é ciente de org, então normalmente deixe isso sem definir. Defina como `1` **apenas** durante um rollout de transição onde um dashboard ainda não ciente de org está se comunicando com um agent ciente de org, para que o assistente recaia na org `default` em vez de recusar. Remova assim que a atualização do dashboard for implantada. | +| `AGENTEYE_AGENT_MAX_STEPS` | Máximo de etapas de uso de ferramenta por resposta (padrão 8) | +| `AGENTEYE_AGENT_TIMEOUT_MS` | Timeout geral da requisição `/chat` (todas as rodadas do modelo + etapas de ferramentas), em milissegundos (padrão 90000); a ferramenta SQL tem seu próprio limite de 10s | +| `AGENTEYE_AGENT_SELF_TELEMETRY` | `1` para registrar as próprias execuções do assistente no AgentEye | +| `AGENTEYE_TELEMETRY_API_KEY` | Chave separada apenas `events:add` para auto-instrumentação | +| `AGENTEYE_AGENT_ENV` | Tag de ambiente aplicada à própria telemetria do assistente (padrão `prod`) | + +Definir no serviço **`dashboard`**: + +| Variável | Propósito | +|---|---| +| `AGENTEYE_AGENT_URL` | Onde o dashboard acessa o serviço agent. Os manifestos Kubernetes e o arquivo Compose incluídos definem isso como `http://agent:9100`. Deixe sem definir para ocultar o assistente completamente. | +| `AGENTEYE_AGENT_TOKEN` | Deve corresponder ao token do agent | + +--- + +## Telemetria e visualização do que os usuários perguntam + +O **conteúdo dos prompts permanece dentro dos seus próprios sistemas** por padrão. Três camadas: + +1. **Armazenamento de conversas**: cada prompt e resposta é salvo no seu banco de dados AgentEye (por usuário, privado), e pode ser recarregado pelo seletor de histórico do assistente. Este é o registro durável do que os usuários perguntam. +2. **Analytics de produto**: o dashboard registra **apenas metadados** (frequência de uso do assistente, contagens de ferramentas, latência) em seus analytics. O **texto** do prompt nunca é incluído neste caminho. +3. **Auto-instrumentação (opcional)**: defina `AGENTEYE_AGENT_SELF_TELEMETRY=1` (mais um `AGENTEYE_TELEMETRY_API_KEY` apenas `events:add`) e o assistente registra suas próprias execuções no AgentEye como um agente `dashboard-assistant`. Você então observa os prompts dos usuários e o raciocínio do assistente nas mesmas views de sessões/eventos que usa para tudo mais. Nota: esses eventos são visíveis para qualquer pessoa com `events:read`; se isso for muito amplo, deixe isso desativado. + +--- + +## Desabilitando + +Qualquer uma destas opções desabilita o assistente (o trilho do dock desaparece): + +- Remova a definição de `AGENTEYE_AGENT_URL` no dashboard, **ou** +- Deixe o endpoint LLM não configurado no agent (sem `ANTHROPIC_API_KEY` / gateway / Bedrock / Vertex), **ou** +- Não implante o serviço `agent` de forma alguma. + +--- + +## Resumo de segurança + +- **Sem escritas silenciosas**: as ferramentas de escrita do assistente (`create_saved_query`, `update_saved_query`, `create_dashboard`, `update_dashboard`, `add_query_to_dashboard`) não podem ser executadas sem um clique explícito do operador no botão Aprovar no chat; o gate pré-chamada do SDK bloqueia a ferramenta até que uma aprovação chegue ao agent por um canal de retorno. Não há configuração que desative este gate. +- **Escopo de dados fixo e restrito**: o assistente autentica no server com uma chave dedicada cujo conjunto de permissões é fixado no server (`events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run`). As únicas escritas que pode realizar são queries salvas e dashboards; o server rejeita qualquer coisa fora desse escopo independentemente do que o modelo tente. +- **Sem superfície de exclusão**: a chave não carrega permissão de exclusão e nenhuma ferramenta de exclusão é exposta. Operadores excluem pela interface do dashboard, nunca pelo assistente. +- **Apenas interno**: o agent não tem rota pública; apenas o dashboard pode chamá-lo, e apenas com o token compartilhado. (No Kubernetes, uma NetworkPolicy restringe o agent a acessar apenas o server AgentEye e o endpoint LLM.) +- **Escopo por usuário**: apenas usuários com `agent:use` têm acesso ao assistente, e ele recebe apenas as ferramentas correspondentes às permissões de leitura de cada usuário. +- **Sem HTML bruto / sem exfiltração de links**: as respostas são renderizadas como markdown sanitizado; links externos são neutralizados. + +Consulte [enterprise-docs/troubleshooting.md](/pt-br/agenteye/troubleshooting) para problemas comuns. \ No newline at end of file diff --git a/docs/pt-br/agenteye/audits.mdx b/docs/pt-br/agenteye/audits.mdx new file mode 100644 index 00000000..95997279 --- /dev/null +++ b/docs/pt-br/agenteye/audits.mdx @@ -0,0 +1,106 @@ +--- +title: "Auditorias — detecção de melhorias por agentes" +description: "Documentação do AgentEye Audits — detecção de melhorias por agentes." +--- + +Auditorias são tarefas recorrentes que analisam os logs do seu agente **entre sessões** para encontrar pontos de melhoria. Enquanto um alerta monitora uma métrica específica que você já conhece em tempo quase real, uma auditoria *investiga*: em um cronograma que você define, ela executa uma verificação de políticas determinística sobre a janela de tempo, depois envia um **agente de confiabilidade com IA** para analisar suas sessões — o agente consulta os dados diretamente, lê transcrições suspeitas e (quando necessário) executa pequenos scripts de análise, produzindo **recomendações de melhoria** com as evidências correspondentes. + +Use auditorias para responder "o que devo corrigir ou melhorar nos meus agentes?" — e alertas para ser notificado imediatamente quando um limite específico for ultrapassado. Cada melhoria está vinculada às sessões e consultas exatas que a embasam, e um único clique cria um alerta pré-preenchido para detectar recorrências. + +A interface do painel está disponível em **`//audits`** (barra lateral → *analyze* → *audits*), protegida pelas permissões `audits:read` / `audits:write`. + +--- + +## Como uma execução funciona + +Cada execução tem duas camadas — uma base determinística e uma investigação por agentes. + +### 1. A verificação de políticas (determinística) + +Antes de qualquer modelo ser executado, a auditoria realiza um conjunto de **verificações de políticas em SQL** sobre a janela de tempo: consultas agregadas delimitadas que sinalizam padrões problemáticos conhecidos e reportam *quantos* eventos / *quais* sessões corresponderam — nunca o texto correspondente em si. O catálogo inclui: + +- **Vazamento de segredos / credenciais** em cargas de eventos — chaves de acesso AWS, chaves de API `sk-…`, chaves privadas PEM, tokens JWT / bearer e atribuições de credencial `KEY=…`. +- **Marcadores de injeção de prompt** — "ignore previous instructions", "reveal your system prompt" e similares. +- **PII** — números com formato de CPF/SSN (heurístico). +- **Negações de permissão de ferramentas** e **loops descontrolados de chamadas de ferramentas**. + +Hits de política são persistidos como descobertas (tipo `policy`) que **sempre aparecem** (nunca são removidos pelo limite por execução) e são entregues ao agente de IA como pontos de partida. Como essa camada não precisa de modelo, uma auditoria ainda produz os sinais de segurança mais importantes mesmo que o agente de IA esteja indisponível. + +### 2. A investigação por agentes (IA) + +A auditoria então executa um **agente autônomo de confiabilidade** (o mesmo serviço Claude Agent SDK que alimenta o assistente do painel, com um prompt específico para auditorias). Com base no **escopo** da auditoria (agentes selecionados × ambientes) e na **janela de tempo**, o agente: + +- executa consultas SQL somente leitura nas suas tabelas de analytics, +- lê algumas transcrições de sessão representativas, +- opcionalmente escreve e executa **scripts Python curtos em um sandbox isolado dentro do pod** (sem rede, sem acesso ao sistema de arquivos, segredos removidos) para análises que o SQL não consegue expressar — agrupamento de erros, cálculo de distribuições, varredura de cargas já obtidas, +- e registra cada **melhoria** bem fundamentada que encontra. + +O agente percorre diversas linhas de investigação — agrupamento de erros, desvio em relação a uma linha de base, falhas de objetivo nas transcrições, uso indevido de ferramentas, trade-offs de qualidade/custo e lacunas de cobertura — conforme a **sensibilidade** da auditoria (baixa / média / alta). Cada melhoria **deve citar evidências**: os IDs das sessões que o agente inspecionou de fato e/ou o SQL executado. O servidor valida que as sessões citadas existem e **descarta qualquer melhoria sem evidência válida**, garantindo que o agente investigue sem inventar. + +Cada melhoria inclui: + +- uma **recomendação** (a mudança concreta a ser feita — ajuste de prompt, correção de schema de ferramenta, política de retry, guardrail, mais cobertura de avaliação), +- um **impacto esperado** e uma estimativa de **esforço** (baixo / médio / alto), +- uma **magnitude** — `big` (um operador deve ser notificado), `medium` (pertence ao relatório da execução) ou `small` (contexto do painel), +- uma **impressão digital** estável (baseada na categoria + escopo do problema, *não* nas sessões desta execução) para que o mesmo problema seja rastreado entre execuções mesmo quando as evidências mudam, +- e, quando um monitor determinístico simples poderia detectar recorrências, um **alerta sugerido** que você pode criar em um clique. + +> **A camada de IA é opcional, mas recomendada.** Se nenhum agente de IA estiver configurado para o pipeline de auditoria, as execuções ainda ocorrem, persistem as descobertas de política e reportam honestamente "análise indisponível" para a camada de agentes, em vez de passar silenciosamente. + +### Modos de falha + +As melhorias são classificadas no **catálogo de modos de falha** duráveis da sua organização (ou propõem um novo modo). Os modos fornecem identidade estável aos padrões entre execuções e rastreamento de recorrência em longo prazo. + +## Ciclo de vida de triagem + +Na página de uma descoberta (`/audits//findings/`): + +| Ação | Efeito | +|---|---| +| **acknowledge** | Mantém a descoberta visível, mas reduz sua prioridade pela metade. | +| **resolve** | Marca como corrigido. Se o padrão realmente retornar, reabre como **new** — tornando uma regressão evidente, sem ser silenciosamente arquivada no histórico. | +| **mute** / **dismiss** | Supressão permanente: a impressão digital do padrão é memorizada e nunca mais aparece, mesmo entre execuções. Use mute para "conhecido, aceito"; dismiss para "não é útil". | +| **reopen** | Remove a supressão / resolução e classifica o padrão novamente. | +| **assign** | Direciona a descoberta a um operador (membro da organização) para responsabilização. Prioridade e estado de supressão permanecem inalterados. | + +O ruído de baixo sinal é controlado por auditoria com um limite de descobertas por execução (`top_k`) para as melhorias geradas por agentes. Descobertas de política ignoram esse limite (são relevantes para segurança e sempre exibidas). Tudo que for cortado pelo limite é contabilizado nas estatísticas da execução — nada é descartado silenciosamente. + +## Agendamento + +- **Cadência** (`schedule_interval_secs`): de horária a semanal; **diária é o padrão**. Auditorias são deliberadamente menos frequentes que alertas — uma investigação por agentes examina janelas inteiras e leva minutos para executar. +- **Janela**: lookback contínuo fixo (por exemplo, "cada execução analisa os últimos 7 dias") ou **desde a última execução** (padrão) — cada execução continua de onde a anterior bem-sucedida terminou, com uma pequena sobreposição para que eventos no limite nunca sejam perdidos. +- A próxima execução é agendada um intervalo completo após a **conclusão** da anterior, portanto uma execução lenta nunca empilha uma segunda execução simultânea da mesma auditoria. +- **Run now** na página da auditoria a agenda para execução imediata. + +## Seleção de modelo + +Ao criar uma auditoria, você pode escolher qual modelo a investigação utiliza, a partir da **lista de modelos configurados pelo operador** para o serviço de agentes. Com um único modelo configurado, o seletor o exibe como legenda; com vários, você escolhe. Deixar sem definir usa o padrão configurado. + +## Notificações + +Quando uma execução encontra descobertas **novas**, a auditoria notifica os canais configurados da sua organização — os mesmos canais e configurações do gate `alerts.enabled_channels` usados pelo pipeline de alertas: + +- **Slack** — um resumo dos novos itens significativos (`big`) com um link direto. +- **Email** — um **relatório de auditoria** formatado listando as novas melhorias (maior severidade, recomendações por item, link direto), enviado quando a auditoria tem um canal de **email** vinculado e há pelo menos uma nova descoberta. + +Descobertas recorrentes já conhecidas não geram novas notificações. + +## Referência de configuração + +As definições de auditoria são gerenciadas no painel (`/audits/new`) ou via API. As configurações por auditoria incluem a cadência e janela do agendamento, o escopo (`{"environments": [...], "agent_ids": [...]}`), a sensibilidade (`low` / `medium` / `high`), os canais de notificação, o limite de descobertas por execução (`top_k`) e o modelo (via `llm_budget.model`). Configurações do servidor no nível do operador (timeouts, sandbox, a URL do serviço de agentes) estão documentadas em [deployment.md](/pt-br/agenteye/deployment). + +## API + +Todos os endpoints são com escopo de organização e seguem a autenticação padrão por bearer key (consulte [api-keys.md](/pt-br/agenteye/api-keys)). + +| Endpoint | Permissão | Finalidade | +|---|---|---| +| `GET /audits` · `POST /audits` | `audits:read` / `audits:write` | Listar / criar definições de auditoria. | +| `GET` / `PUT` / `DELETE /audits/:id` | read / write / write | Inspecionar, editar, excluir uma auditoria. | +| `POST /audits/:id/run` | `audits:write` | Agendar a auditoria para execução imediata. | +| `GET /audits/:id/runs` | `audits:read` | Histórico de execuções (janela, status, estatísticas, contagens de descobertas). | +| `GET /audits/findings` | `audits:read` | Descobertas de toda a organização, filtráveis por `audit_id`, `status`; ordenadas por prioridade. | +| `GET /audits/findings/:fid` | `audits:read` | Detalhes completos da descoberta (recomendação, evidências, prioridade). | +| `POST /audits/findings/:fid/status` | `audits:write` | Triagem: `{"action": "ack" \| "mute" \| "dismiss" \| "resolve" \| "reopen" \| "assign"}`. | + +Para os casos "a auditoria executou mas não encontrou nada", "o sandbox de código está desativado" e "email de auditoria não entregue", consulte [troubleshooting.md](/pt-br/agenteye/troubleshooting#audits). \ No newline at end of file diff --git a/docs/pt-br/agenteye/cli-recipes.mdx b/docs/pt-br/agenteye/cli-recipes.mdx new file mode 100644 index 00000000..bef42ada --- /dev/null +++ b/docs/pt-br/agenteye/cli-recipes.mdx @@ -0,0 +1,170 @@ +--- +title: "Receitas de CLI para agentes" +description: "Documentação de receitas de CLI do AgentEye para agentes." +--- + + +Acesse dados de sessão, evento e avaliação (e dispare reavaliações) diretamente de um script ou agente de código, com JSON limpo no stdout que se encaixa diretamente no `jq`. Essas receitas transformam os dados de observabilidade do AgentEye em algo que um usuário de terminal ou um agente de codificação com IA (Claude Code, Cursor) pode consultar e automatizar, sem precisar clicar no dashboard. + +Os padrões abaixo estão prontos para copiar e colar no CLI do AgentEye (`agenteye`). Para instalação, autenticação e a lista completa de opções, consulte [CLI](/pt-br/agenteye/cli); execute `agenteye -h` ou `agenteye -h` para ver a ajuda integrada. + +## Regras de ouro + +1. **As opções globais vêm *antes* do comando.** `agenteye --json sessions` está correto; `agenteye sessions --json` não está. As globais são `--json`, `--base-url`, `--org`, `--token`, `--insecure`/`--secure`, `--timeout`, `--quiet`, `--no-color`. +2. **Passe `--json` sempre que for fazer parsing da saída.** Os dados vão para o **stdout** como JSON; status e erros para humanos vão para o **stderr**, então o stdout permanece limpo para ser redirecionado ao `jq`. +3. **Tome decisões com base no código de saída**, não no texto do stderr: `0` ok · `2` argumentos inválidos · `3` não foi possível alcançar o dashboard · `4` não autenticado ou sessão expirada · `5` permissão ausente. +4. **Descubra com `-h`.** Cada comando documenta seus filtros, formatos de valores e estrutura JSON. + +## Configuração inicial + +```bash +export AGENTEYE_DASHBOARD_URL=https://agenteye.example.com # para não precisar repetir --base-url +agenteye login --email you@example.com # cole o código enviado por e-mail; válido por ~24h +``` + +## Confirme a autenticação antes de executar qualquer operação + +`whoami` nunca retorna erro por sessão ausente ou expirada; ele reporta `logged_in:false` em vez disso, então um agente pode verificar o estado de autenticação com segurança. (Ainda pode sair com código diferente de zero se nenhuma URL base estiver definida ou o dashboard estiver inacessível.) + +```bash +if [ "$(agenteye --json whoami | jq -r .logged_in)" != "true" ]; then + echo "Not authenticated. Run: agenteye login" >&2; exit 1 +fi +``` + +## Encontre sessões com falha ou pontuação baixa + +```bash +# sessões nas últimas 24h cuja avaliação retornou erro +agenteye --json sessions --since 24h --status error | jq -r '.sessions[].session_id' + +# avaliações com pontuação <= 0.5 em utilidade, para um agente específico +agenteye --json evals --agent-id checkout-bot --score helpfulness:..0.5 \ + | jq '.evaluations[] | {session_id, scores}' +``` + +A filtragem por pontuação está em **`evals`**, não em `sessions`. `--score KEY:MIN..MAX` é repetível e combinado com AND; qualquer limite é opcional (`..0.5` significa ≤ 0,5, `0.9..` significa ≥ 0,9). Você pode passar até 20 filtros de pontuação por requisição; mais do que isso retorna HTTP 400. `sessions` compartilha os filtros `--env`, `--status`, `--agent-id`, `--session-id` e de intervalo de tempo com `evals`, mas não possui `--score`. + +## Leia uma sessão do início ao fim + +Não existe um único comando `session show` — combine o histórico de eventos com a avaliação da sessão: + +```bash +# avaliação mais recente da sessão (status + pontuações) +agenteye --json evals --session-id run-001 | jq '.evaluations[0] | {status, scores}' + +# todos os eventos da execução (aumente --limit para uma varredura completa) +agenteye --json events --session-id run-001 --all --limit 1000 | jq '.events[] | {ts, event_type}' + +# apenas as chamadas de ferramenta em uma sessão +agenteye --json events --session-id run-001 --event-type tool_use,tool_result --all \ + | jq '.events[].payload' +``` + +## Busque tudo (paginação) + +Os resultados são ordenados do mais recente para o mais antigo e são paginados por cursor. + +```bash +# tudo de uma vez: busca até 500 registros em páginas de 200 +agenteye --json events --session-id run-001 --limit 500 --all > events.json + +# paginação manual: passe next_cursor de volta +page=$(agenteye --json events --limit 100) +cursor=$(echo "$page" | jq -r '.next_cursor // empty') +[ -n "$cursor" ] && agenteye --json events --limit 100 --cursor "$cursor" +``` + +## Reduza a saída com --fields + +Restrinja as chaves (tanto na tabela quanto no `--json`) para diminuir o que um agente precisa ler. + +```bash +agenteye --json sessions --since 7d --fields session_id,status,scores | jq -c '.sessions[]' +agenteye --json events --session-id run-001 --fields ts,event_type --all +``` + +Nomes de campos desconhecidos são rejeitados (saída `2`) com a lista de campos válidos — uma forma prática de descobrir os nomes disponíveis. + +## Descubra valores de filtro válidos + +```bash +agenteye --json list envs | jq -r '.values[]' # valores para --env +agenteye --json list tools | jq -r '.values[]' # nomes de ferramentas; também agents, models, event_types, … +agenteye --json list score_filters | jq -r '.values[]' # KEY válida para --score KEY:MIN..MAX +``` + +## Selecione sua organização (multi-tenant) + +Se você pertence a mais de uma organização, escolha o tenant ativo no login (ele é salvo): + +```bash +agenteye login --org acme --email you@corp.com # define o tenant no mesmo passo do login +agenteye --json orgs list | jq -r '.orgs[].org_slug' +agenteye --org globex --json sessions --since 24h # sobrescreve para um único comando +``` + +Um login multi-organização sem `--org` sai com código diferente de zero e exibe as organizações disponíveis para escolha. + +## Provisione uma chave de API para o SDK/coletor + +```bash +# o segredo é exibido UMA ÚNICA VEZ — com --json está no campo .key +key=$(agenteye --json keys create ci-bot --add events:read.add | jq -r '.key') +agenteye keys regenerate ci-bot --yes # rotaciona; use agenteye keys disable ci-bot --yes para revogar +``` + +## Execute uma consulta salva ou ad-hoc + +```bash +agenteye --json query run --sql "select count(*) from analytics.events" | jq '.rows' +agenteye --json query run errs --arg prod | jq '.rows' # uma consulta salva + um $1 posicional +``` + +## Faça triagem de um incidente de forma não interativa + +```bash +id=$(agenteye --json incidents list --state firing | jq -r '.incidents[0].id') +agenteye incidents ack "$id" +agenteye incidents assign "$id" you@corp.com +agenteye incidents resolve "$id" --yes +``` + +> Mutações ignoram automaticamente o prompt de confirmação quando `--json` está presente ou quando o stdin não é um TTY, para que agentes nunca fiquem travados; passe `--yes`/`-y` para ignorá-lo explicitamente em outros contextos. + +## Tratamento de código de saída em um script + +```bash +out=$(agenteye --json sessions --since 1h) || code=$? +case "${code:-0}" in + 0) echo "$out" | jq '.sessions | length' ;; + 4) echo "Session expired - run 'agenteye login'." >&2 ;; + 5) echo "Missing permission (ask an admin for evaluations:read)." >&2 ;; + 3) echo "Dashboard unreachable - check the URL." >&2 ;; + *) echo "Unexpected error (exit ${code})." >&2 ;; +esac +``` + +## Formatos de saída JSON + +| Comando | JSON no stdout (com `--json`) | +|---|---| +| `whoami` | `{"logged_in": true, "id", "email", "is_instance_admin", "active_org", "permissions": [...], "memberships": [...]}` ou `{"logged_in": false}` | +| `orgs list` | `{"active_org", "orgs": [{"org_slug","org_name","permission_set","permissions"}]}` | +| `events` | `{"events": [...], "next_cursor": }` | +| `evals` | `{"evaluations": [...], "next_cursor": }` | +| `sessions` | `{"sessions": [...], "next_cursor": }` | +| `errors` | `{"errors": [...], "next_cursor": }` | +| `list ` | `{"kind", "values": [...]}` | +| `keys list` / `keys create` | `{"keys": [...]}` / `{id, name, permissions, created_at, key}` (`key` exibida uma única vez) | +| `query run` | `{columns: [{name,type}], rows: [[...]], truncated, elapsed_ms}` | +| `users list` / `settings list` | `{"users": [...]}` / `{"settings": [...]}` | +| `alerts list` / `incidents list` | `{"alerts": [...]}` / `{"incidents": [...]}` | +| create/update/delete (qualquer) | o objeto do recurso, ou `{"deleted": true, "id"}` para exclusões | +| falha (qualquer, com `--json`) | `{"error": "...", "exit_code": , "status"?: , "hint"?: "..."}` no stdout | + +- Cada item de **evento** (`events`): `id, session_id, agent_id, event_type, ts, payload, environment`. +- Cada item de **avaliação** (`evals`): `id, session_id, agent_id, environment, status, scores, reasoning, summary, error, attempt_count, duration_ms, completed_at, created_at`. +- Cada item de **sessão** (`sessions`): `session_id, agent_id, environment, status, scores, event_count, started_at, last_event_at, first_event_id, last_event_id, latest_evaluation`. + +O `--fields` de cada comando aceita exatamente os nomes de campo do seu próprio item — o conjunto difere entre `sessions` e `evals`, então um nome válido para um pode ser rejeitado pelo outro. \ No newline at end of file diff --git a/docs/pt-br/agenteye/cli-skill.mdx b/docs/pt-br/agenteye/cli-skill.mdx new file mode 100644 index 00000000..fccaf195 --- /dev/null +++ b/docs/pt-br/agenteye/cli-skill.mdx @@ -0,0 +1,95 @@ +--- +title: "Habilidade de Agente CLI do AgentEye" +description: "Documentação da Habilidade de Agente CLI do AgentEye." +--- + + +A **habilidade CLI do AgentEye** (`agenteye-cli`) é uma *Habilidade de Agente* instalável que ensina um agente de codificação — Claude Code, Codex e ferramentas compatíveis — a operar sua implantação do AgentEye por meio da [`agenteye` CLI](/pt-br/agenteye/cli) a partir de solicitações em linguagem natural: *"tem algo quebrado hoje?"*, *"gera uma chave para o CI que só pode enviar eventos"*, *"reconhece o incidente ativo e me atribui"*. + +Ela **não** é um serviço nem um binário separado. É um pequeno pacote de instruções que funciona sobre a CLI que você já instalou: o agente chama `agenteye --json …`, analisa o JSON limpo e responde em texto corrido. Tudo o que ela pode fazer, você poderia fazer digitando os mesmos comandos. + +--- + +## Como ela se relaciona com as outras interfaces do AgentEye + +O AgentEye oferece quatro formas de acessar os mesmos dados e controles. Elas se complementam: + +| Interface | O que é | Onde roda | Use quando | +|---|---|---|---| +| **[CLI](/pt-br/agenteye/cli)** | Referência de comandos e flags do `agenteye` | Seu terminal | Você quer executar ou automatizar um comando específico | +| **[Receitas CLI](/pt-br/agenteye/cli-recipes)** | Padrões `jq`/pipeline prontos para copiar | Seu terminal / scripts | Você está integrando a CLI em automações | +| **Habilidade CLI** (este doc) | Uma porta de entrada em linguagem natural para a CLI | Seu agente de codificação, na sua estação de trabalho | Você quer *só perguntar* e deixar o agente escolher o comando | +| **[Assistente de IA no painel](/pt-br/agenteye/assistant)** | Um chat embutido no painel | Um container `agent` interno no seu cluster | Você quer Q&A no painel sobre seus dados | + +### vs. o Assistente de IA no painel — uma distinção importante + +Estas são duas ferramentas diferentes com impactos potenciais muito distintos: + +- O **Assistente de IA no painel** ([assistant.md](/pt-br/agenteye/assistant)) é um chat embutido no painel, sustentado por um container `agent` interno. É **somente leitura mais criação com aprovação**: ele pode rascunhar queries e dashboards salvos, mas toda escrita pausa aguardando seu clique de aprovação explícita, e nunca exclui nada. É protegido pela permissão `agent:use` e só vê dados da org que você está visualizando. +- A **habilidade CLI** roda *na sua* estação de trabalho dentro do *seu* agente de codificação e aciona a CLI `agenteye` como **você**. Ela pode executar a **superfície completa da CLI, incluindo mutações** — criar/rotacionar/desabilitar chaves de API, alterar configurações da org, resolver incidentes, excluir queries salvas — limitada apenas pelas permissões do seu login na CLI. Trate-a com exatamente o mesmo cuidado com que trataria a execução desses comandos manualmente. + +--- + +## Pré-requisitos + +1. A **CLI `agenteye` instalada** e no `PATH` (veja [cli.md](/pt-br/agenteye/cli) — `pipx install agenteye`). +2. Sua **URL do painel** configurada (`AGENTEYE_DASHBOARD_URL`, ou o agente passa `--base-url`). +3. Uma **sessão autenticada**: execute `agenteye login` você mesmo primeiro. A habilidade **não consegue** concluir o login por código único enviado por e-mail por você — ela pedirá para você executar `agenteye login` se a sessão estiver ausente ou expirada (código de saída da CLI `4`). + +--- + +## Instalando a habilidade + +Habilidades de Agente são pastas que contêm um `SKILL.md` (mais referências opcionais). Você instala a habilidade `agenteye-cli` colocando sua pasta onde seu agente procura por habilidades: + +- **Claude Code** — copie a pasta `agenteye-cli/` em `~/.claude/skills/` (disponível em todos os projetos) ou em `/.claude/skills/` (com escopo para aquele repositório). Claude Code a descobre automaticamente; verifique com a lista `/skills`, ou simplesmente faça uma pergunta que corresponda à sua descrição. +- **Codex (OpenAI)** — O Codex lê o mesmo `SKILL.md`. O arquivo `agents/openai.yaml` incluído define `allow_implicit_invocation: true`, então o Codex seleciona a habilidade automaticamente quando uma tarefa corresponde; caso contrário, invoque-a explicitamente como `$agenteye-cli`. + +A habilidade é mantida junto com a CLI `agenteye` e distribuída como parte do seu pacote AgentEye — se você não tiver a pasta `agenteye-cli`, entre em contato com seu contato AgentEye. Nada nela é restrito: não precisa de imagem Docker nem de credencial, pois aciona apenas a CLI **pública** `agenteye` contra seu próprio painel. + +--- + +## Segurança — mutações NÃO pedem confirmação quando um agente executa a CLI + +**Leia isto antes de deixar um agente fazer alterações.** + +A CLI `agenteye` normalmente pergunta *"tem certeza?"* antes de uma ação destrutiva. Ela **pula automaticamente essa confirmação sempre que não está conectada a um terminal — que é exatamente como um agente de codificação a executa — e `--json` também a pula.** Portanto, o prompt de segurança **não** disparará para o agente. + +A habilidade foi escrita para compensar isso: ela é instruída a declarar o comando exato que executará e obter seu **OK explícito antes de qualquer alteração de estado**. Mantenha essa disciplina — quando você aciona o AgentEye por meio de um agente, *você* é a etapa de confirmação. Os comandos que alteram estado a observar: + +- `keys create` / `update` / `disable` / `regenerate` +- `users create` / `update` / `disable` / `enable` +- `settings set` +- `alerts create` / `update` / `delete` / `test` +- os subcomandos de escrita de `incidents`: `ack` / `assign` / `resolve` / `open` / `comment-add` / `comment-delete` / `subscribe` / `unsubscribe` +- `query create` / `update` / `delete` +- `agent rename` / `delete` +- `orgs switch` + +Tudo em **Observe** (`events`, `sessions`, `evals`, `errors`, `list`, `whoami`, `orgs list/current/perms`) é somente leitura e não altera nada. + +Como o agente age como **você**, ele só pode fazer o que seu login tem permissão — as permissões são resolvidas **por org** (veja [api-keys.md](/pt-br/agenteye/api-keys)). Um comando para o qual você não tem permissão retorna código de saída `5` com o nome exato da permissão, para que o agente possa dizer exatamente o que pedir a um administrador em vez de falhar de forma obscura. + +--- + +## O que você pode perguntar + +A habilidade mapeia intenções em linguagem natural para o comando `agenteye` correto, descobrindo valores válidos primeiro (`list `, `whoami`) para não adivinhar: + +- *"Tem algo quebrado / falhando nas últimas 24 horas?"* → `errors --since 24h --aggregate`, seguido de um detalhamento. +- *"Por que a sessão `run-001` falhou?"* → `events --session-id run-001 --all` + `evals --session-id run-001`. +- *"Como a qualidade está evoluindo esta semana?"* → `evals --aggregate --since 7d`, então detalha as execuções com baixa pontuação. +- *"Gera uma chave para o CI que só pode enviar eventos."* → `keys create ci --add events:add` (ele declara o comando, cria e captura o segredo de uso único). +- *"Quem tem acesso? Deixa a Dana somente leitura."* → `users list` → `users update dana@… --permission-set read-only` (após confirmar com você). +- *"Reconhece o incidente ativo e me atribui."* → `incidents list --state firing` → `incidents ack ` / `incidents assign você@…`. + +Para os comandos exatos, flags e formatos JSON por trás dessas ações, veja [cli.md](/pt-br/agenteye/cli) e [cli-recipes.md](/pt-br/agenteye/cli-recipes). + +--- + +## Veja também + +- **[CLI](/pt-br/agenteye/cli)** — referência completa de comandos e flags do `agenteye`. +- **[Receitas CLI para agentes](/pt-br/agenteye/cli-recipes)** — padrões `jq` prontos para copiar e tratamento de códigos de saída. +- **[Assistente de IA](/pt-br/agenteye/assistant)** — o assistente no painel (não confundir com esta habilidade de terminal). +- **[Chaves de API](/pt-br/agenteye/api-keys)** — o modelo de permissões por org que limita o que a habilidade pode fazer. \ No newline at end of file diff --git a/docs/pt-br/agenteye/cli.mdx b/docs/pt-br/agenteye/cli.mdx new file mode 100644 index 00000000..d8780293 --- /dev/null +++ b/docs/pt-br/agenteye/cli.mdx @@ -0,0 +1,291 @@ +--- +title: "CLI" +description: "Documentação do CLI do AgentEye." +--- + +O CLI do AgentEye (`agenteye`) é um cliente de terminal para sua implantação do AgentEye. Ele consulta seus dados (sessões, logs de eventos, avaliações) e administra a organização (chaves de API, usuários, configurações, alertas, incidentes, consultas salvas) — tudo o que o dashboard faz, a partir de um script ou agente de programação. Todo comando suporta o flag `--json`, funcionando igualmente bem para um humano no terminal ou para um agente de programação (Claude Code, Cursor) que executa comandos e analisa o resultado. + +> Este é o **CLI `agenteye`**, uma ferramenta diferente do daemon **coletor** (`agenteye-collector`). O CLI se comunica com o seu **dashboard**; o coletor envia eventos ao servidor. Consulte [Instalação do Coletor](/pt-br/agenteye/collector-installation) para mais informações sobre o coletor. + +--- + +## Instalação + +O CLI está publicado no PyPI público como **`agenteye`**. Como o SDK Python do AgentEye também usa o nome de distribuição `agenteye`, instale o CLI em um ambiente **isolado** (`pipx` ou `uv tool`) para que os dois nunca colidam em um mesmo virtualenv: + +```bash +pipx install agenteye +# ou +uv tool install agenteye +``` + +Um simples `pip install agenteye` também funciona se você não estiver instalando o SDK Python no mesmo ambiente. O CLI requer Python 3.10+ e não precisa de token do GitHub; é um pacote público. + +O comando instalado é **`agenteye`**: + +```bash +agenteye --version +agenteye --help +``` + +--- + +## Autenticação + +O CLI se autentica no **dashboard** com um código único enviado por e-mail: + +```bash +agenteye login --email voce@exemplo.com +# Um código de 6 dígitos é enviado para você; cole-o quando solicitado. +``` + +O token de sessão é armazenado em `~/.agenteye/cli.json` (legível apenas por você, modo `0600`) e é válido por 24 horas por padrão. Quando expirar, execute `agenteye login` novamente. + +```bash +agenteye whoami # exibe o usuário atual, organização ativa e permissões +agenteye logout # revoga a sessão e limpa o token armazenado +``` + +`whoami` nunca gera erro em caso de sessão ausente ou expirada — em vez disso, reporta `logged_in: false`, para que um script ou agente possa verificar o estado de autenticação com segurança (ainda pode retornar código não-zero se nenhuma URL base estiver configurada ou se o dashboard estiver inacessível). + +**Requisitos:** seu e-mail deve ter permissão para entrar no dashboard (solicite ao administrador do AgentEye), e o dashboard deve estar acessível na sua URL base (consulte [Configuração](#configuration)). Se você solicitar um código e ele não chegar, provavelmente seu e-mail ainda não está habilitado para acesso ao dashboard. + +--- + +## Escolhendo sua organização (multi-tenant) + +Se sua conta pertence a mais de uma organização, escolha a ativa **no momento do login** — ela é salva e usada em todos os comandos posteriores: + +```bash +agenteye login --org acme # autentique e defina o tenant ativo em um só passo +agenteye orgs list # as organizações que você pode acessar (a ativa está marcada) +agenteye orgs switch globex # altere o padrão salvo +agenteye --org globex sessions # substitua para um único comando +``` + +Se você pertence a exatamente uma organização, ela é selecionada automaticamente e você pode ignorar `--org` completamente. Se pertencer a várias e não escolher nenhuma, o CLI as listará e pedirá que você execute novamente com `--org `. A organização ativa é enviada ao dashboard em cada requisição, e suas permissões são resolvidas **por organização** — `agenteye whoami` exibe a organização ativa, suas permissões nela e todas as suas associações. + +--- + +## Configuração + +| Configuração | Flag | Variável de ambiente | Padrão | +|---|---|---|---| +| URL base do dashboard | `--base-url` | `AGENTEYE_DASHBOARD_URL` | **obrigatório** (sem padrão) | +| Organização/tenant ativo | `--org` | `AGENTEYE_ORG` | definido no login; salvo em `~/.agenteye/cli.json` | +| Token de sessão | `--token` | `AGENTEYE_CLI_TOKEN` | de `~/.agenteye/cli.json` | +| Saída JSON | `--json` | `AGENTEYE_CLI_JSON` | desativado | +| Ignorar verificação TLS | `--insecure` / `--secure` | `AGENTEYE_INSECURE` | desativado (salvo no login) | +| Timeout da requisição (segundos) | `--timeout` | — | 30 | +| Desativar telemetria de uso | _(nenhum)_ | `AGENTEYE_ANALYTICS_DISABLED` (ou `DO_NOT_TRACK`) | desativado (telemetria ativa) | + +A ordem de resolução é **flag → variável de ambiente → arquivo de configuração**. Não há valor padrão; você deve apontar o CLI para o seu dashboard, seja por comando (`--base-url https://agenteye.exemplo.com`) ou uma vez via ambiente (também é salvo após o primeiro `login`): + +```bash +export AGENTEYE_DASHBOARD_URL=https://agenteye.exemplo.com +``` + +O diretório de configuração respeita `AGENTEYE_HOME` (a mesma convenção usada pelo SDK e pelo coletor); se definido, `cli.json` ficará em `$AGENTEYE_HOME/cli.json`. + +### TLS autoassinado ou interno + +Se o seu dashboard usa HTTPS com um certificado autoassinado ou interno (por exemplo, o hostname bruto de um load balancer), a verificação TLS rejeita a conexão com um erro `CERTIFICATE_VERIFY_FAILED`. Use `--insecure` para ignorar a verificação de certificado: + +```bash +agenteye --base-url https://agenteye.interno --insecure login +``` + +`--insecure` é **salvo em `cli.json` quando você faz login**, então comandos posteriores ignoram a verificação automaticamente; você não precisa repetir o flag. Use `--secure` para uma chamada verificada pontual, ou para reativar a verificação no próximo login. O CLI exibe um aviso no stderr antes de qualquer comando que contate o dashboard com a verificação desativada. Ignorar a verificação remove a proteção contra ataques man-in-the-middle; certifique-se de confiar no caminho de rede até o seu dashboard (VPN, sub-rede privada etc.) antes de depender disso. + +--- + +## Telemetria e privacidade + +O CLI envia **analytics de uso anônimos** para o serviço de analytics da Exosphere (PostHog): quais comandos são executados (ex.: `sessions`, `keys create`), se tiveram sucesso e quanto tempo levaram. Esse sinal de uso informa quais funcionalidades são priorizadas. + +- **Nenhum dado de agente, sessão ou evento sai da sua infraestrutura.** Apenas o uso do CLI é reportado: o nome do comando e subcomando (ex.: `keys create`), os **nomes** dos flags usados (nunca seus valores), status de sucesso/saída e duração — mais um evento por ação para mutações (ex.: `api_key_created`, `query_run`) contendo apenas nomes/enums estáticos e contagens aproximadas. Sua URL do dashboard, token de sessão, e-mail, slug da organização, IDs de recursos, SQL, segredos de chaves e filtros de consulta **nunca** são enviados. Os operadores são identificados apenas por um ID interno opaco, nunca por e-mail. +- A telemetria está **ativada por padrão**. Para desativá-la, defina `AGENTEYE_ANALYTICS_DISABLED=1` no ambiente do CLI (o CLI também respeita a convenção entre ferramentas `DO_NOT_TRACK=1`). +- O CLI envia diretamente para o PostHog (`https://us.i.posthog.com`). A **máquina que executa o CLI** precisa de acesso de saída para esse host; se estiver bloqueado, a telemetria não faz nada silenciosamente (o envio tem limite de tempo para nunca atrasar ou quebrar um comando) e o CLI não é afetado. + +--- + +## Opções globais e convenções + +Leia isto uma vez; aplica-se a todos os comandos. + +- **Opções globais vão ANTES do comando.** `agenteye --json sessions` está correto; `agenteye sessions --json` é um erro de uso. As opções globais são `--json`, `--base-url`, `--org`, `--token`, `--insecure`/`--secure`, `--timeout`, `--quiet` e `--no-color`. +- **`--json` imprime JSON puro no stdout, e nada mais.** Linhas de status, avisos e erros para o usuário vão para o **stderr**, então uma captura do stdout com `--json` permanece limpa para passar via pipe para `jq` mesmo quando uma linha de status é exibida. Sem `--json`, você recebe uma visualização formatada e colorida para leitura humana. +- **Descubra com `--help`.** Todo comando e subcomando tem `--help` (e o alias `-h`): `agenteye -h`, `agenteye sessions -h`, `agenteye keys create -h`. O help de nível superior também lista os códigos de saída e as opções globais. Não há uma listagem global legível por máquina; use `--help` por comando, mais `agenteye query schema` e `agenteye settings schema` para esses dois registros específicos. +- **Confirmações são ignoradas automaticamente para scripts e agentes.** Comandos de criação/atualização/exclusão solicitam confirmação em um terminal interativo, mas **ignoram esse prompt automaticamente com `--json` ou quando o stdin não é um TTY** — então scripts e agentes nunca ficam travados. Use `--yes`/`-y` para ignorar explicitamente. Como o prompt não é exibido para um agente, ele deve confirmar ações destrutivas com o usuário antes de executá-las. +- **Paginação:** os resultados são exibidos do mais recente para o mais antigo e paginados por cursor. `--limit N` (alias `-n`) limita as linhas e **tem padrão 50**; `--all` pagina automaticamente (em blocos de 200 linhas) **até `--limit`** — então um `--all` simples ainda para em 50. Para uma varredura completa, passe um limite alto explícito: `--all --limit 1000`. `--page-size N` controla o bloco por requisição (máx. 200); `--cursor ` retoma a partir do `next_cursor` de uma página anterior. +- **Filtros de tempo:** `--since` aceita uma janela relativa — `15m`, `1h`, `6h`, `24h`, `7d`, `30d` ou `all` (os presets do dashboard). `--from`/`--to` aceitam timestamps UTC ISO-8601 explícitos **com `T` e fuso horário** (ex.: `2026-06-01T00:00:00Z`) para um intervalo personalizado e substituem `--since`; um valor com espaço ou sem fuso horário é um erro de uso. +- **`--fields a,b,c`** (em `events`, `sessions`, `evals`, `errors`) restringe a saída a essas chaves, tanto na tabela quanto no `--json`. Nomes desconhecidos são rejeitados com a lista de valores válidos — uma forma prática de descobrir nomes de campos. +- **`--file payload.json`** (ou `--file -` para ler do stdin) fornece um corpo de requisição JSON completo quando um recurso tem uma estrutura complexa — em `alerts create/update`, `settings set` e `users create/update`. SQL de consultas salvas usa `--sql @arquivo.sql` em vez disso. +- **Filtros com múltiplos valores** são separados por vírgula → correspondidos como conjunto (união dentro de um filtro, AND entre filtros): `--event-type tool_use,tool_result`. Opções do Click não são variádicas, então `--add a b` não funciona — use `--add a,b`, repita o flag (`--add a --add b`) ou use aspas (`--add "a b"`). + +--- + +## Referência de comandos + +O CLI possui **18 comandos de nível superior**. Todos os comandos de leitura aceitam `--json` e as opções globais acima; execute `agenteye -h` (ou ` -h`) para a lista completa de flags e o formato JSON de qualquer um deles. + +### Identidade — `login` · `logout` · `whoami` · `orgs` · `version` · `help` + +```bash +agenteye login --email voce@exemplo.com [--org acme] # código único por e-mail; salva a sessão +agenteye logout # limpa a sessão salva nesta máquina +agenteye whoami # usuário atual, organização ativa, permissões +agenteye version # imprime a versão do CLI (igual a --version) +agenteye help # help de nível superior (igual a --help) +``` + +`orgs` inspeciona e alterna o tenant ativo: + +```bash +agenteye orgs list # suas organizações + seu papel em cada uma (a ativa está marcada) +agenteye orgs switch acme # altera a organização ativa salva (omita o slug para escolher de uma lista no TTY) +agenteye orgs current # cartão de identidade da organização ativa +agenteye orgs perms # suas permissões na organização ativa, agrupadas por recurso +``` + +### Observar (somente leitura) — `events` · `sessions` · `evals` · `errors` · `list` + +Nenhum desses requer confirmação. Filtros compartilhados: `--session-id`, `--agent-id`, `--env` (**não** `--environment`) e o intervalo de tempo (`--since` / `--from` / `--to`). + +```bash +# events (alias: trilha bruta por etapa) — do mais recente para o mais antigo +agenteye --json events --session-id run-001 --event-type tool_use,tool_result --all --limit 1000 +agenteye --json events --since 1h --search timeout --all | jq '.events[].payload' + +# sessions — uma linha por execução do agente (tempo/env/agente/sessão/status; sem filtragem por pontuação) +agenteye --json sessions --since 24h --status error +agenteye --json sessions --agent-id checkout-bot --env prod --all --limit 1000 + +# evals — resultados de avaliação + pontuações; --score filtra por métrica, --aggregate agrega +agenteye --json evals --score helpfulness:0.5..0.8 --score tool_efficiency:..0.3 +agenteye --json evals --aggregate --since 7d --env prod # mix de status + estatísticas de pontuação por chave + +# errors — eventos com erro; --aggregate para contagens/sessões/agentes/última ocorrência +agenteye --json errors --since 24h --aggregate +agenteye --json errors --since 24h --error-type timeout --all --limit 1000 + +# list — descubra valores válidos de filtro antes de filtrar +agenteye list envs # também: agents event_types score_filters models hooks triggers tools error_types +``` + +`--score KEY:MIN..MAX` (em **`evals`**, não em `sessions`) é repetível e combinado com AND; qualquer um dos limites é opcional (`..0.5` significa ≤ 0.5, `0.9..` significa ≥ 0.9). Até 20 filtros de pontuação por requisição. `evals --scores-full` retorna o objeto de pontuação completo em vez do resumo. Para ler **uma sessão de ponta a ponta**, combine a trilha de eventos com sua avaliação: + +```bash +agenteye --json events --session-id run-001 --all --limit 1000 | jq '.events[] | {ts, event_type}' +agenteye --json evals --session-id run-001 # suas pontuações + status +``` + +### Gerenciar (com controle de permissão) — `keys` · `users` · `settings` · `alerts` · `incidents` + +**`keys`** — chaves de API. O segredo é gerado localmente, enviado ao servidor (que armazena apenas um hash) e **exibido uma única vez** ao criar/regenerar — capture-o nesse momento. Com `--json`, ele aparece apenas no campo `key`. Referenciado por **nome**. + +```bash +agenteye keys list # chaves ativas primeiro, depois revogadas +agenteye keys show ci-bot +agenteye keys create ci-bot --add events:read.add # limite ao que você precisa; imprime o segredo UMA VEZ +agenteye keys create ops --permission-set standard --remove queries:run # inicia com um preset e ajusta +agenteye keys update ci-bot --add evaluations:read --yes +agenteye keys regenerate ci-bot --yes # rotaciona o segredo (o anterior para de funcionar) +agenteye keys disable ci-bot --yes # revogar +``` + +As permissões funcionam como `(permission-set ∪ --add) − --remove`. Os tokens são `slug:ação` (ex.: `events:read`) ou `slug:ação.ação` para expandir várias em um recurso (`events:read.add` → `events:read`, `events:add`). Presets: `read-only`, `standard`, `admin`. Permissões exclusivas para humanos (`keys:update`) não podem ser concedidas a uma chave. + +**`users`** — membros da organização, referenciados por **e-mail** (um ID UUID também é aceito). + +```bash +agenteye users list [--active-only] +agenteye users show dev@empresa.com +agenteye users create dev@empresa.com --permission-set standard +agenteye users update dev@empresa.com --add alerts:write --remove queries:delete # prevê + confirma +agenteye users disable dev@empresa.com --yes # possui proteções para admin/auto +agenteye users enable dev@empresa.com +``` + +**`settings`** — um registro fixo (você lê e altera chaves existentes; não é possível criar novas). + +```bash +agenteye settings list # chave · valor · tipo · atualizado (segredos mascarados) +agenteye settings schema # o que cada chave aceita (tipo · intervalo · descrição) +agenteye settings set session_ttl_secs --value 86400 --yes +``` + +**`alerts`** — definições de alertas, referenciadas por **nome**. `create` aceita um NOME posicional mais flags ou um corpo JSON completo via `--file`. + +```bash +agenteye alerts list +agenteye alerts show high-errors +agenteye alerts create high-errors --file alert.json # NOME é obrigatório (posicional) +agenteye alerts update high-errors --severity critical --yes +agenteye alerts test high-errors --yes # disparar uma notificação de teste +agenteye alerts delete high-errors --yes +``` + +**`incidents`** — incidentes de alerta, referenciados por ID (IDs curtos são aceitos). `show` imprime o log completo de atividades — leia-o antes de agir. + +```bash +agenteye incidents list --state firing # também: acknowledged, resolved +agenteye incidents count +agenteye incidents show +agenteye incidents ack +agenteye incidents assign voce@empresa.com # o responsável deve ser um operador +agenteye incidents resolve --yes +agenteye incidents open --alert-id --severity critical # abrir manualmente para um alerta +agenteye incidents comment-add "causa raiz: upstream 5xx" +agenteye incidents comment-list ; agenteye incidents comment-delete +agenteye incidents subscribe ; agenteye incidents unsubscribe ; agenteye incidents subscribers +``` + +### Analytics e assistente — `query` · `agent` + +**`query`** — SQL ClickHouse salvo mais um executor ad-hoc. Consultas salvas são referenciadas por **nome**; o SQL é validado no servidor (somente SELECT/WITH, timeout de instrução, limite de linhas). + +```bash +agenteye query schema [TABELA] # layout de colunas das views de analytics +agenteye query run --sql "select count(*) from analytics.events" +agenteye query run errs --arg prod --limit 100 # executar uma consulta salva + um $1 posicional +agenteye query list ; agenteye query show errs +agenteye query create errs --sql @errs.sql --description "eventos com erro (24h)" +agenteye query update errs --sql @errs.sql --yes ; agenteye query delete errs --yes +``` + +**`agent`** — o assistente integrado do dashboard (o mesmo analista somente leitura disponível no chat do dashboard). Chats são referenciados por um chat-id curto (resolvido por prefixo). + +```bash +agenteye agent health # o assistente está configurado/acessível +agenteye agent models # modelos que você pode passar para --model (padrão marcado) +agenteye agent ask "quais agentes mais erraram no último dia?" # inicia um chat; imprime seu ID curto +agenteye agent ask --chat "e quais ferramentas eles chamaram?" # continuar esse chat +agenteye agent chats ; agenteye agent show +agenteye agent rename --title "triagem de erros" ; agenteye agent delete +``` + +--- + +## Códigos de saída + +| Código | Significado | +|---|---| +| 0 | Sucesso | +| 1 | Erro inesperado (ex.: o dashboard retornou um 5xx) | +| 2 | Erro de uso (argumentos inválidos, comando/flag desconhecido, colisão de nomes) | +| 3 | Não foi possível alcançar o dashboard | +| 4 | Não autenticado ou sessão expirada; execute `agenteye login` | +| 5 | Autenticado, mas sua conta não tem a permissão necessária (a mensagem a nomeia) | +| 6 | O recurso solicitado não foi encontrado (ex.: ID de sessão ou incidente desconhecido) | + +Esses códigos tornam o CLI seguro para scripts: um agente de programação pode ramificar em `4` para solicitar que você se autentique novamente, ou em `5` para exibir a permissão ausente. Consulte [Receitas de CLI para agentes](/pt-br/agenteye/cli-recipes) para padrões de tratamento de código de saída e formatos de saída JSON. + +--- + +## Veja também + +- **[Receitas de CLI para agentes](/pt-br/agenteye/cli-recipes)** — padrões de consulta prontos para uso, one-liners com `jq`, projeções com `--fields`, tratamento de código de saída e formatos de saída JSON, escritos para agentes de programação que controlam o CLI. +- **[Skill do CLI do AgentEye](/pt-br/agenteye/cli-skill)** — empacote este CLI como um *skill* instalável do Claude Code / Codex para que um agente de programação controle o AgentEye por meio de requisições em linguagem natural. +- **[Chaves de API](/pt-br/agenteye/api-keys)** — o modelo de permissões por trás de `keys create --add …`. +- **[Assistente de IA](/pt-br/agenteye/assistant)** — habilitando o assistente com o qual `agent ask` se comunica. \ No newline at end of file diff --git a/docs/pt-br/agenteye/collector-installation.mdx b/docs/pt-br/agenteye/collector-installation.mdx new file mode 100644 index 00000000..3f579258 --- /dev/null +++ b/docs/pt-br/agenteye/collector-installation.mdx @@ -0,0 +1,401 @@ +--- +title: "Instalação do Collector" +description: "Documentação de instalação do AgentEye Collector." +--- + + +O daemon `agenteye-collector` garante que a telemetria dos seus agentes chegue ao AgentEye sem nunca bloquear sua aplicação. Seu código escreve eventos em um diretório local e segue em frente; o collector assume a responsabilidade a partir daí, fazendo o upload de cada arquivo em milissegundos e sobrevivendo a reinicializações, quedas de rede e erros transitórios do servidor. Uploads com falha são reprocessados com backoff exponencial, e uma varredura periódica de recuperação recoloca na fila tudo que ficou para trás por um crash ou deploy. O resultado é uma entrega durável no esquema dispare-e-esqueça: seus agentes continuam rodando em velocidade máxima enquanto o collector garante que nenhum evento seja perdido no caminho. + +Mecanicamente, o collector é um daemon leve que monitora `$AGENTEYE_HOME/events/` (padrão: `~/.agenteye/events/`) em busca de arquivos `.jsonl` escritos pelo SDK Python e os envia para o servidor AgentEye. + +> **Renomeado:** o comando do collector agora é **`agenteye-collector`** (antes era `agenteye`). O nome curto `agenteye` agora pertence à CLI do AgentEye. Se você está atualizando uma instalação existente, consulte [enterprise-docs/collector-migration.md](/pt-br/agenteye/collector-migration). + +--- + +## Pré-requisitos + +- Seu `AGENTEYE_TOKEN`: um PAT do GitHub que você mesmo gera (veja [enterprise-docs/github-token.md](/pt-br/agenteye/github-token)) +- A URL do servidor e uma chave de API do collector (veja [enterprise-docs/api-keys.md](/pt-br/agenteye/api-keys)) + +--- + +## Opção A: Binário (recomendado) + +Binários estáticos pré-compilados estão disponíveis para Linux, macOS e Windows (x86_64 e arm64). Baixe o binário para sua plataforma diretamente do repositório `agenteye-enterprise/releases` na tag de release mais recente `collector/v`. + +Nomes de artefatos disponíveis: + +| Plataforma | Artefato | +|---|---| +| Linux x86_64 | `agenteye-collector-linux-x86_64` | +| Linux arm64 | `agenteye-collector-linux-arm64` | +| macOS x86_64 | `agenteye-collector-darwin-x86_64` | +| macOS arm64 | `agenteye-collector-darwin-arm64` | +| Windows x86_64 | `agenteye-collector-windows-x86_64.exe` | +| Windows arm64 | `agenteye-collector-windows-arm64.exe` | + +**Baixe com a CLI `gh`** (substitua a versão e escolha o artefato da sua plataforma): + +```bash +VERSION=0.0.1-beta.13 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "collector/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-collector-linux-x86_64' + +chmod +x agenteye-collector-linux-x86_64 +sudo mv agenteye-collector-linux-x86_64 /usr/local/bin/agenteye-collector +``` + +**Ou com `curl`:** + +```bash +VERSION=0.0.1-beta.13 +ARTIFACT=agenteye-collector-linux-x86_64 +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + -L "https://github.com/agenteye-enterprise/releases/releases/download/collector%2Fv${VERSION}/${ARTIFACT}" \ + -o agenteye-collector +chmod +x agenteye-collector +sudo mv agenteye-collector /usr/local/bin/agenteye-collector +``` + +--- + +## Opção B: Docker + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +docker pull ghcr.io/agenteye-enterprise/collector:beta-latest +``` + +> As builds beta atuais publicam a tag flutuante `:beta-latest`; `:latest` é atribuída apenas a releases estáveis. Para deploys reproduzíveis, prefira uma tag de versão fixada como `:v0.0.1-beta.13`. + +**Executar:** + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-collector \ + -e AGENTEYE_URL=https://ingest.example.com/events \ + -e AGENTEYE_KEY="$AGENTEYE_KEY" \ + -e AGENTEYE_HOME=/data \ + -v "$HOME/.agenteye:/data" \ + ghcr.io/agenteye-enterprise/collector:beta-latest \ + start +``` + +A imagem oficial roda como um usuário não-root, então defina `AGENTEYE_HOME` explicitamente e monte o spool do host nele. O volume compartilha o mesmo diretório `~/.agenteye/` que o SDK Python escreve no host. Se você já definiu `AGENTEYE_HOME` em outro lugar no host, monte esse diretório em vez de `$HOME/.agenteye`. + +--- + +## Configuração + +Todas as opções podem ser definidas de três formas (maior prioridade primeiro): + +1. Flag CLI: `agenteye-collector start --url https://...` +2. Variável de ambiente: `AGENTEYE_URL=https://...` +3. Arquivo de configuração: `~/.agenteye/config.json` + +### Opções obrigatórias + +| Opção | Flag CLI | Var de ambiente | Chave no config.json | +|---|---|---|---| +| URL do backend | `--url ` | `AGENTEYE_URL` | `"url"` | +| Chave de API | `--key ` | `AGENTEYE_KEY` | `"key"` | + +### Opções opcionais (com valores padrão) + +| Opção | Flag CLI | Var de ambiente | Chave no config.json | Padrão | +|---|---|---|---|---| +| Uploads simultâneos máximos | `--max-concurrent-uploads ` | `AGENTEYE_MAX_CONCURRENT_UPLOADS` | `"max_concurrent_uploads"` | `64` | +| Intervalo do sweeper (s) | `--sweep-interval ` | `AGENTEYE_SWEEP_INTERVAL` | `"sweep_interval_secs"` | `60` | +| Idade mínima de arquivo do sweeper (s) | `--sweep-min-age ` | `AGENTEYE_SWEEP_MIN_AGE` | `"sweep_min_age_secs"` | `120` | +| Máximo de arquivos por varredura | `--sweep-max-files ` | `AGENTEYE_SWEEP_MAX_FILES` | `"sweep_max_files"` | `64` | +| Máximo de tentativas de upload | `--max-retries ` | `AGENTEYE_MAX_RETRIES` | `"max_retries"` | `5` | +| Delay base de retry (ms) | `--retry-base-delay ` | `AGENTEYE_RETRY_BASE_DELAY` | `"retry_base_delay_ms"` | `1000` | + +### Opções de mTLS (opcional) + +Para deploys que exigem TLS mútuo (mTLS), o collector pode apresentar um certificado de cliente durante o handshake TLS. Quando essas opções não estão definidas, o collector utiliza HTTPS padrão. + +| Opção | Flag CLI | Var de ambiente | Chave no config.json | +|---|---|---|---| +| Certificado do cliente (PEM) | `--tls-cert ` | `AGENTEYE_TLS_CERT` | `"tls_cert"` | +| Chave privada do cliente (PEM) | `--tls-key ` | `AGENTEYE_TLS_KEY` | `"tls_key"` | +| Certificado CA personalizado (PEM) | `--tls-ca ` | `AGENTEYE_TLS_CA` | `"tls_ca"` | + +`--tls-cert` e `--tls-key` devem ser definidos juntos. Os arquivos devem estar em formato PEM. + +`--tls-ca` é independente e só é necessário quando o servidor AgentEye apresenta um certificado TLS que não foi emitido por uma CA publicamente confiável (por exemplo, autoassinado por um emissor `cert-manager` dentro do cluster quando você não tem um domínio DNS real). O collector adiciona a CA fornecida como uma âncora de confiança adicional; as raízes públicas padrão continuam confiáveis, portanto implantações existentes não são afetadas. O arquivo pode conter um único certificado PEM ou uma cadeia completa (múltiplos blocos PEM concatenados). + +**Rodando o collector como sidecar no pod da sua aplicação?** Veja [enterprise-docs/single-pod-deployment.md](/pt-br/agenteye/single-pod-deployment) para o padrão completo no EKS: bundle mTLS entregue via AWS Secrets Manager + Secrets Store CSI Driver + IRSA, com rotação automática. + +Ao rodar no Kubernetes com o padrão de repasse de Secret, monte o Secret de certificado como um volume e aponte esses caminhos para os arquivos montados: + +```yaml +# Exemplo: trecho de Deployment do collector +volumes: + - name: mtls-certs + secret: + secretName: agenteye-collector-mtls +containers: + - name: collector + env: + - name: AGENTEYE_TLS_CERT + value: /etc/agenteye/tls/tls.crt + - name: AGENTEYE_TLS_KEY + value: /etc/agenteye/tls/tls.key + # Somente quando o certificado do servidor não é publicamente confiável + # (ex: CA autoassinada dentro do cluster). O mesmo Secret normalmente + # traz ca.crt junto com tls.crt/tls.key. + - name: AGENTEYE_TLS_CA + value: /etc/agenteye/tls/ca.crt + volumeMounts: + - name: mtls-certs + mountPath: /etc/agenteye/tls + readOnly: true +``` + +### Exemplo de `~/.agenteye/config.json` + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "max_concurrent_uploads": 16, + "sweep_interval_secs": 30 +} +``` + +Com mTLS: + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "tls_cert": "/etc/agenteye/tls/tls.crt", + "tls_key": "/etc/agenteye/tls/tls.key" +} +``` + +Com mTLS mais uma CA personalizada (servidor AgentEye autoassinado): + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "tls_cert": "/etc/agenteye/tls/tls.crt", + "tls_key": "/etc/agenteye/tls/tls.key", + "tls_ca": "/etc/agenteye/tls/ca.crt" +} +``` + +Se `AGENTEYE_HOME` estiver definido, esse diretório é usado em vez de `~/.agenteye`. + +--- + +## Configuração inicial + +Após instalar, configure o collector com a URL do seu servidor e a chave de API: + +```bash +mkdir -p ~/.agenteye +cat > ~/.agenteye/config.json <<'EOF' +{ + "url": "https://ingest.example.com/events", + "key": "YOUR_COLLECTOR_KEY" +} +EOF +``` + +> Use `https` para qualquer implantação que cruze uma rede não confiável para que os eventos não sejam enviados em texto simples. A forma com `http://seu-servidor:8080/events` é adequada apenas para testes puramente locais em um servidor no mesmo host. + +**Teste a conexão** (flush único, encerra após drenar os eventos pendentes): + +```bash +agenteye-collector flush +``` + +O `flush` reporta seu progresso no stdout. Quando o spool está vazio, imprime `No pending files.` e sai com código `0`. Caso contrário, imprime uma linha por arquivo (`[UPLOADED] ` ou `[FAILED] ()`), seguida de um resumo `Done: / uploaded, failed.`. Isso torna o `flush` uma verificação pontual conveniente para confirmar que sua URL, chave e configurações TLS estão corretas antes de iniciar o daemon. + +--- + +## Executando como Daemon + +### Diretamente + +```bash +agenteye-collector start +``` + +### Container / Docker + +Quando o collector e sua aplicação compartilham um container, execute-os sob um supervisor de processos. A opção mais simples é o `supervisord`; ele está disponível em todas as principais distribuições, reinicia processos com crash, encaminha sinais e aguarda o encerramento gracioso. + +**`Dockerfile`:** + +```Dockerfile +FROM python:3.11-slim + +RUN apt-get update && apt-get install -y --no-install-recommends supervisor \ + && rm -rf /var/lib/apt/lists/* + +# Obtém o binário agenteye-collector da imagem oficial. +# Fixe uma tag específica (:beta-latest para betas atuais, ou uma tag :v); +# :latest é publicada apenas para releases estáveis. +COPY --from=ghcr.io/agenteye-enterprise/collector:beta-latest \ + /usr/local/bin/agenteye-collector /usr/local/bin/agenteye-collector + +COPY supervisord.conf /etc/supervisor/conf.d/agenteye.conf +COPY my_agent.py /app/my_agent.py + +CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"] +``` + +**`supervisord.conf`:** + +```ini +[supervisord] +nodaemon=true +user=root + +[program:agenteye-collector] +command=/usr/local/bin/agenteye-collector start +autorestart=true +stopwaitsecs=30 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:app] +command=python /app/my_agent.py +autorestart=unexpected +stopwaitsecs=30 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +``` + +Por que essas configurações: + +- `autorestart=true` no agenteye-collector: reinicia em qualquer saída (crash, panic, OOM). +- `autorestart=unexpected` na aplicação: reinicia apenas em saída com código não-zero, para que um agente pontual que sai com 0 não entre em loop. +- `stopwaitsecs=30`: dá ao collector tempo para drenar uploads pendentes no SIGTERM antes que o supervisord escale para SIGKILL. +- `stdout_logfile=/dev/stdout`, `*_maxbytes=0`: transmite a saída de ambos os programas para o stdout do container; sem arquivos de log dentro do container. + +Passe `AGENTEYE_URL` / `AGENTEYE_KEY` (e quaisquer variáveis de ambiente TLS) via `docker run -e` como antes; o supervisord herda o ambiente. + +> **Containers separados?** Se você roda o collector como seu próprio container (serviço do Docker Compose, sidecar no Kubernetes, etc.), não use o supervisord; a política de restart do runtime de container já faz esse trabalho. Veja [enterprise-docs/single-pod-deployment.md](/pt-br/agenteye/single-pod-deployment) para o padrão de sidecar no EKS. + +**Liveness probe para Kubernetes** (aplica-se tanto quando o collector roda sozinho quanto sob o supervisord): + +```yaml +livenessProbe: + exec: + command: ["agenteye-collector", "health"] + initialDelaySeconds: 10 + periodSeconds: 30 +``` + +O daemon em execução grava um heartbeat em `$AGENTEYE_HOME/health.json` a cada 30 segundos. O `agenteye-collector health` lê esse arquivo e sai com `0` (saudável) apenas quando o heartbeat está fresco e as tarefas de upload estão funcionando normalmente; sai com `1` (não saudável) quando o heartbeat tem mais de 90 segundos (por exemplo, o daemon parou) ou enquanto o watcher e o sweeper estão reiniciando após uma saída inesperada. O heartbeat é escrito apenas pelo `start`, portanto execute a probe contra o daemon de longa duração e não contra o comando pontual `flush`. + +### systemd (Linux, recomendado para produção) + +```ini +# /etc/systemd/system/agenteye-collector.service +[Unit] +Description=AgentEye Collector +After=network.target + +[Service] +ExecStart=/usr/local/bin/agenteye-collector start +Restart=on-failure +RestartSec=5 +EnvironmentFile=/etc/agenteye/env + +[Install] +WantedBy=multi-user.target +``` + +Crie `/etc/agenteye/env`: + +``` +AGENTEYE_URL=https://ingest.example.com/events +AGENTEYE_KEY=YOUR_COLLECTOR_KEY +``` + +```bash +sudo systemctl daemon-reload +sudo systemctl enable --now agenteye-collector +sudo systemctl status agenteye-collector +``` + +### launchd (macOS) + +```xml + + + + + + Label + ai.befailproof.agenteye-collector + ProgramArguments + + /usr/local/bin/agenteye-collector + start + + EnvironmentVariables + + AGENTEYE_URL + https://ingest.example.com/events + AGENTEYE_KEY + YOUR_COLLECTOR_KEY + + RunAtLoad + + KeepAlive + + + +``` + +```bash +launchctl load ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +``` + +--- + +## Atualizando o Collector + +O collector não se atualiza automaticamente. Para atualizar: + +- **Binário:** baixe o novo artefato `agenteye-collector--` da release mais recente `collector/v` (veja [Opção A](#option-a-binary-recommended)), substitua `/usr/local/bin/agenteye-collector` e reinicie o serviço (`sudo systemctl restart agenteye-collector`, `launchctl load` novamente, ou reinicie seu supervisor). +- **Docker:** execute `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (ou uma tag fixada `:v`; `:latest` existe apenas para releases estáveis) e recrie o container. + +`AGENTEYE_TOKEN` é necessário para baixar novos binários/imagens do repositório privado de releases, mas **não** é necessário para o daemon em execução. + +--- + +## Subcomandos + +| Comando | Descrição | +|---|---| +| `agenteye-collector start` | Inicia o daemon de longa duração. Na inicialização, faz o flush de quaisquer eventos deixados por uma execução anterior, depois monitora novos arquivos e os envia. O watcher e o sweeper reiniciam automaticamente em caso de saída inesperada, e um heartbeat é gravado em `health.json` a cada 30 segundos. | +| `agenteye-collector flush` | Pontual: envia todos os arquivos pendentes e encerra. Imprime `No pending files.` quando o spool está vazio; caso contrário, um log por arquivo com `[UPLOADED]`/`[FAILED]` e um resumo `Done: / uploaded, failed.`. | +| `agenteye-collector health` | Lê o heartbeat `health.json` do daemon. Sai com `0` quando fresco e saudável; sai com `1` quando o heartbeat está desatualizado (mais de 90s) ou as tarefas estão reiniciando. | + +--- + +## Estrutura de Diretórios + +``` +~/.agenteye/ +├── config.json <- arquivo de configuração opcional +├── events/ <- arquivos .jsonl escritos pelo SDK, coletados pelo collector +└── failed/ <- arquivos que falharam em todas as tentativas de upload +``` + +Arquivos em `failed/` não são reprocessados automaticamente. Para recolocá-los na fila manualmente, mova-os de volta para `events/` e execute `agenteye-collector flush`. \ No newline at end of file diff --git a/docs/pt-br/agenteye/collector-migration.mdx b/docs/pt-br/agenteye/collector-migration.mdx new file mode 100644 index 00000000..68779674 --- /dev/null +++ b/docs/pt-br/agenteye/collector-migration.mdx @@ -0,0 +1,168 @@ +--- +title: "Migrando para `agenteye-collector`" +description: "Documentação de migração do AgentEye para `agenteye-collector`." +--- + +A migração é não-destrutiva: não gera downtime nem perda de dados, e libera o nome curto `agenteye` para o [AgentEye CLI](/pt-br/agenteye/cli), permitindo que o daemon coletor e o CLI coexistam na mesma máquina. + +O binário do coletor foi **renomeado de `agenteye` para `agenteye-collector`**. O nome curto `agenteye` agora pertence ao AgentEye CLI, uma ferramenta separada para consultar sessões, eventos e avaliações pelo terminal. + +Este guia mostra como migrar uma instalação existente do coletor. + +--- + +## O que mudou + +| | Antes | Depois | +|---|---|---| +| Comando / binário | `agenteye` | `agenteye-collector` | +| Caminho de instalação padrão | `/usr/local/bin/agenteye` | `/usr/local/bin/agenteye-collector` | +| Subcomandos | `start`, `flush`, `health`, `update` | `start`, `flush`, `health` | +| Auto-atualização (`agenteye update`) | integrada | **removida**: baixe o novo binário ou faça pull da nova imagem | +| Script de instalação (`install.sh`) | fornecido | **removido**: baixe o binário diretamente (veja [Instalação do Coletor](/pt-br/agenteye/collector-installation)) | +| `AGENTEYE_TOKEN` | necessário para download **e** para verificações de atualização em segundo plano | necessário apenas para **baixar** binários/imagens | + +A configuração permanece inalterada: o mesmo `~/.agenteye/config.json`, as mesmas variáveis de ambiente `AGENTEYE_URL` / `AGENTEYE_KEY` / `AGENTEYE_HOME` / TLS, e o mesmo spool `~/.agenteye/events/`. **Nenhuma edição de configuração é necessária.** + +> Se você executar o binário renomeado com o nome antigo `agenteye`, ele ainda funcionará, mas exibirá um aviso de deprecação de uma linha no stderr lembrando que você deve migrar para `agenteye-collector`. + +--- + +## Antes de começar + +- Sua **instalação existente do `agenteye` continua funcionando**; nada quebra no momento em que você fizer o upgrade. Migre com calma e remova o binário antigo por último. +- Siga esta ordem para evitar downtime: + 1. Instale o novo binário `agenteye-collector` (ou faça pull da nova imagem). + 2. Atualize sua definição de serviço / probe de saúde / scripts para chamar `agenteye-collector`. + 3. Recarregue e reinicie o serviço; confirme que está saudável. + 4. **Somente então** remova o binário antigo `/usr/local/bin/agenteye`. + +--- + +## 1. Instale o novo binário + +Baixe o artefato para sua plataforma (`agenteye-collector-linux-x86_64`, `agenteye-collector-darwin-arm64`, entre outros; veja [Instalação do Coletor → Opção A](/pt-br/agenteye/collector-installation#option-a-binary-recommended) para a lista completa) da release mais recente `collector/v` e coloque-o em `/usr/local/bin/agenteye-collector`. Usuários Docker: `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (ou uma tag fixada `:v`, o que é preferível; `:latest` existe apenas para releases estáveis). + +Verifique: + +```bash +agenteye-collector --version +``` + +--- + +## 2. Atualize seu deployment + +### systemd (Linux) + +Edite `/etc/systemd/system/agenteye-collector.service` para que o `ExecStart` aponte para o novo binário: + +```ini +[Service] +ExecStart=/usr/local/bin/agenteye-collector start +``` + +Em seguida, recarregue e reinicie: + +```bash +sudo systemctl daemon-reload +sudo systemctl restart agenteye-collector +sudo systemctl status agenteye-collector +``` + +### launchd (macOS) + +> **Renomeação de marca:** Se o seu plist existente estiver no caminho antigo +> `~/Library/LaunchAgents/host.exosphere.agenteye-collector.plist`, renomeie +> o arquivo para `ai.befailproof.agenteye-collector.plist` e também altere o +> valor de `Label` dentro do arquivo para o novo identificador antes +> de recarregar. + +Em `~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist`, altere a primeira entrada de `ProgramArguments` de `/usr/local/bin/agenteye` para `/usr/local/bin/agenteye-collector` e, em seguida, recarregue: + +```bash +launchctl unload ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +launchctl load ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +``` + +### supervisord + +No bloco de programa do seu `supervisord`, defina `command` para o novo binário: + +```ini +[program:agenteye-collector] +command=/usr/local/bin/agenteye-collector start +``` + +Em seguida, execute `supervisorctl reread && supervisorctl update`. + +### Docker / Kubernetes + +Faça pull da nova imagem (`ghcr.io/agenteye-enterprise/collector:beta-latest` ou uma tag fixada `:v`, o que é preferível; `:latest` existe apenas para releases estáveis). O entrypoint da imagem já é `agenteye-collector`, portanto o mesmo comando `docker run` com o subcomando `start` continua funcionando sem alterações. + +**Importante: atualize os probes de saúde.** Se você usar um probe de liveness/readiness do Kubernetes (ou qualquer `docker exec`) que execute o binário pelo nome, altere o comando para `agenteye-collector`: + +```yaml +livenessProbe: + exec: + command: ["agenteye-collector", "health"] +``` + +A nova imagem **não** inclui um alias `agenteye`, portanto um probe que ainda chame `agenteye` irá falhar. Atualize o probe no mesmo rollout da nova imagem. + +### Cron / scripts manuais + +Substitua todas as invocações `agenteye start|flush|health` pelo comando equivalente `agenteye-collector start|flush|health`. **Remova quaisquer cron jobs com `agenteye update`**; esse subcomando não existe mais (veja [Upgrades a partir de agora](#upgrades-from-now-on)). + +--- + +## 3. Remova o binário antigo (por último) + +Depois que o serviço estiver rodando com `agenteye-collector` e reportar saúde: + +```bash +sudo rm /usr/local/bin/agenteye +``` + +Isso é especialmente importante se você também usa o AgentEye CLI, que instala seu próprio comando `agenteye`; deixar o binário antigo do coletor em `/usr/local/bin/agenteye` tornaria o nome `agenteye` ambíguo no seu `PATH`. + +--- + +## Upgrades a partir de agora + +O coletor não se atualiza mais automaticamente. Para fazer upgrade: + +- **Binário:** baixe o novo artefato para sua plataforma (por exemplo, `agenteye-collector-linux-x86_64`; veja [Instalação do Coletor → Opção A](/pt-br/agenteye/collector-installation#option-a-binary-recommended) para a lista completa), substitua `/usr/local/bin/agenteye-collector` e reinicie o serviço. +- **Docker:** `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (ou uma tag fixada `:v`, o que é preferível; `:latest` existe apenas para releases estáveis) e recrie o container. + +`AGENTEYE_TOKEN` ainda é necessário para baixar do repositório de releases privado, mas o daemon em execução não precisa mais dele. + +--- + +## Verificar + +```bash +agenteye-collector --version # novo binário está no PATH +agenteye-collector health # exit 0 = saudável +agenteye-collector flush # encaminha quaisquer eventos na fila e encerra normalmente +``` + +Em seguida, confirme que novos eventos aparecem no seu dashboard. + +--- + +## Rollback + +A migração é não-destrutiva. Se precisar reverter, aponte sua definição de serviço de volta para o binário antigo `/usr/local/bin/agenteye` (contanto que você ainda não o tenha removido) e reinicie. O spool de eventos e a configuração são compartilhados e não são afetados. + +--- + +## Solução de problemas + +| Sintoma | Causa | Solução | +|---|---|---| +| `warning: the collector binary is now agenteye-collector …` a cada execução | Você está invocando o binário com o nome antigo `agenteye` | Chame `agenteye-collector` no lugar; atualize arquivos de serviço e scripts. | +| systemd falha: `.../agenteye: No such file or directory` | Você removeu o binário antigo antes de atualizar o `ExecStart` | Defina `ExecStart=/usr/local/bin/agenteye-collector start` e então execute `sudo systemctl daemon-reload`. | +| Pod do Kubernetes entra em crash-loop após o upgrade da imagem | O probe de liveness ainda executa `agenteye` | Altere o comando do probe para `["agenteye-collector", "health"]`. | +| `agenteye: command not found`, mas `agenteye-collector` funciona | Scripts/aliases ainda fazem referência ao nome antigo | Atualize-os para `agenteye-collector`. | +| Executar `agenteye` inicia o CLI, não o coletor | Você tem o AgentEye CLI instalado; ele é o dono do `agenteye` | Use `agenteye-collector` para o daemon e remova qualquer binário antigo do coletor em `/usr/local/bin/agenteye`. | \ No newline at end of file diff --git a/docs/pt-br/agenteye/deployment.mdx b/docs/pt-br/agenteye/deployment.mdx new file mode 100644 index 00000000..a5eaaa91 --- /dev/null +++ b/docs/pt-br/agenteye/deployment.mdx @@ -0,0 +1,427 @@ +--- +title: "Deployment" +description: "Documentação de deployment do AgentEye." +--- + +Este guia aborda como fazer o deploy do servidor e do dashboard do AgentEye em produção. + +--- + +## Visão Geral da Arquitetura + +``` + [ Máquinas dos agentes de IA ] [ Sua infraestrutura ] + + Python SDK + | escreve JSONL +----------------------+ + v +--->| PostgreSQL 15+ | + agenteye-collector --HTTP--+ | | (armazenamento | + | | | relacional) | + v | +----------------------+ + +--------+ | + | Server |<------+ +----------------------+ + +--------+ +--->| ClickHouse 24+ | + ^ | | (eventos / analytics)| + API | | +----------------------+ + | | + +-----------+ | +----------------------+ + | Dashboard | +- - >| Redis 7+ (opcional) | + +-----------+ +----------------------+ +``` + +- **Server**: Serviço HTTP em Rust; recebe lotes de eventos, grava-os no ClickHouse e mantém o estado relacional no PostgreSQL. +- **Dashboard**: Aplicação web em Next.js; lê e escreve exclusivamente via API do servidor. +- **agenteye-collector**: implantado nas máquinas dos agentes, não no host do servidor. +- **Postgres 15+**: OBRIGATÓRIO. (Elevado do 14 na versão multi-tenant; o schema de membros de org usa uma foreign key `ON DELETE SET NULL` com lista de colunas, disponível apenas no Postgres 15+. Atualize o Postgres antes de fazer o deploy desta versão.) Armazena o estado OLTP: `api_keys`, `users`, `sessions`, `evaluation_jobs` (fila), `dashboards`, `saved_queries`, `otp_codes`, além das tabelas multi-tenant `orgs`, `org_memberships`, `org_settings`. +- **ClickHouse 24+**: OBRIGATÓRIO. O armazenamento de analytics para cada evento ingerido. Engine: `ReplacingMergeTree`, particionado por mês, ordenado por `(session_id, ts, dedup_key)`. O servidor conecta via `CLICKHOUSE_URL`; o `deploy/base/clickhouse/` incluído no pacote traz uma configuração de nó único ajustada para performance. **Requisito multi-tenant:** a configuração inclusa habilita gerenciamento de acesso SQL + `users_without_row_policies_can_read_rows=false` para que o servidor possa criar um usuário ClickHouse somente leitura + row policy por organização (o limite de isolamento imposto pelo engine para o editor SQL e o agente de IA). Se você fornecer sua própria configuração do ClickHouse, inclua essas definições (veja `deploy/base/clickhouse/configmap.yaml`). +- **Redis 7+**: cache compartilhado *opcional* + backend de rate limiting. Servidor e dashboard conectam via `REDIS_URL`. Se ausente, ambos degradam de forma elegante para caminhos somente via Postgres. Veja **Redis (cache opcional)** abaixo. + +--- + +## Servidor + +### Baixar a imagem + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +docker pull ghcr.io/agenteye-enterprise/server:beta-latest +``` + +> As builds atuais são publicadas sob `beta-latest`; `latest` é atribuído apenas a releases estáveis. Em produção, fixe uma tag específica `:v`; veja [Tags de imagem disponíveis](#available-image-tags). + +### Variáveis de ambiente + +| Variável | Obrigatória | Padrão | Descrição | +|---|---|---|---| +| `DATABASE_URL` | Sim | none | DSN do Postgres. Formato de string de conexão libpq padrão com esquema `postgres://`. Suporta `?sslmode=require` e outros parâmetros libpq. A senha não deve conter `/`, `+` ou `=`; use `openssl rand -hex` para gerar senhas seguras para URL. | +| `ADMIN_KEY` | Não | none | Chave de API admin de bootstrap. Inserida/atualizada com todas as permissões em cada inicialização. Troque alterando o valor e reiniciando. | +| `LISTEN_ADDR` | Não | `0.0.0.0:8080` | Endereço TCP para bind | +| `MAX_BODY_BYTES` | Não | `134217728` (128 MB) | Tamanho máximo do corpo da requisição | +| `ADMIN_EMAIL` | Não | none | Email do usuário admin de bootstrap. Inserido/atualizado com todas as permissões em cada inicialização e marcado como protegido: não pode ser desativado nem ter permissões modificadas via dashboard/API. Para trocar o admin de bootstrap, altere `ADMIN_EMAIL` e reinicie; o novo email é inserido como protegido, e o anterior mantém sua proteção até ser removido manualmente no banco de dados. | +| `ALLOWED_EMAILS` | Não | none (todos bloqueados) | Lista separada por vírgulas de emails permitidos para criação de usuário e login. Suporta endereços exatos (`user@example.com`) e wildcards de domínio (`*@example.com`). Se não definido, nenhum usuário pode ser criado ou fazer login. **Seed apenas no primeiro boot**: alimenta a allowlist da org padrão no primeiro boot; a partir daí, a página [`//settings`](#operational-settings) de cada org é a fonte de verdade e alterar essa variável de ambiente não tem efeito. | +| `SMTP_HOST` | Não | none | Hostname do servidor SMTP para envio de emails com OTP. Se não definido, os códigos OTP são registrados no stdout. | +| `SMTP_PORT` | Não | `587` | Porta do servidor SMTP | +| `SMTP_USERNAME` | Não | none | Nome de usuário para autenticação SMTP | +| `SMTP_PASSWORD` | Não | none | Senha para autenticação SMTP | +| `SMTP_FROM` | Não | none | Endereço de email remetente para emails com OTP | +| `SMTP_TLS` | Não | STARTTLS | STARTTLS é usado por padrão, a menos que você o desative explicitamente: `false` ou `0` envia em texto puro (sem TLS); qualquer outro valor — incluindo não definido — habilita STARTTLS. | +| `DASHBOARD_URL` | Não | padrão interno | Origem do dashboard usada para construir tanto o magic link do email com OTP quanto os magic links de incidentes nas notificações de alertas. Se não definido, recorre a um padrão interno (e, apenas para OTP, à origem derivada da requisição do dashboard primeiro). Defina isso para setups com domínio separado para que links de email e Slack/incidente apontem para o seu dashboard. Veja **URL do magic link de email** abaixo; a maioria dos operadores não precisa definir isso. | +| `SESSION_TTL_SECS` | Não | `86400` (24 h) | Duração da sessão do dashboard em segundos. **Seed apenas no primeiro boot**: edite por org via [`//settings`](#operational-settings) após o primeiro deploy. | +| `OTP_TTL_SECS` | Não | `600` (10 min) | Período de validade do código OTP em segundos. **Seed apenas no primeiro boot**: edite por org via [`//settings`](#operational-settings) após o primeiro deploy. | +| `REDIS_URL` | Não | none | Cache compartilhado opcional + backend de rate limiting, ex.: `redis://redis:6379/0`. Quando definido, o servidor cacheia lookups de API key autenticados, o agregado `/models` do dashboard, a lista de sessões e a faceta de lista de ambientes; também move o rate limiting de requisição OTP do Postgres COUNT para o Redis INCR. Se não definido ou inacessível, o servidor funciona sem o cache (o limite OTP recai para o Postgres, todas as outras chamadas de cache passam diretamente para a fonte de verdade). Veja **Redis (cache opcional)** abaixo. | +| `CLICKHOUSE_URL` | **Sim** | none | URL base da instância ClickHouse, ex.: `http://clickhouse:8123`. O servidor aplica o schema de eventos a esse banco a cada inicialização e recusa o boot se não conseguir alcançar o ClickHouse. Veja **ClickHouse (armazenamento de analytics obrigatório)** abaixo. | +| `CLICKHOUSE_DATABASE` | Não | `agenteye` | Nome do banco de dados (schema) do ClickHouse. O servidor o cria na inicialização se não existir. | +| `ORG_CH_SECRET` | Não (single-tenant) / **Sim (multi-org)** | padrão de dev | Chave HMAC a partir da qual a senha ClickHouse por tenant de cada organização é derivada. O editor SQL e o `run_query` do agente de IA executam como o usuário ClickHouse somente leitura da org, cuja row policy impõe o isolamento do tenant no engine. Deployments single-tenant funcionam bem com o padrão de dev interno; **antes de provisionar uma segunda org você DEVE definir um valor forte e estável**, pois o CLI `agenteye-orgctl org create` recusa executar com o padrão de dev interno. Rotacioná-lo deixa o usuário ClickHouse de cada org órfão até a próxima inicialização reaprovisioná-los (a reconciliação no boot cura isso automaticamente). Mantenha-o secreto e inalterado entre réplicas. O provisionamento de orgs em si é exclusivo do operador; veja **Organizações (multi-tenancy)** abaixo. | +| `DEFAULT_ORG_NAME` | Não | `Default` | Nome de exibição semeado para a org padrão interna. **Seed apenas no primeiro boot**, e somente enquanto a org ainda mantém sua identidade genérica recém-migrada, aplicado na inicialização e depois ignorado. Uma vez que você renomeia a org (`agenteye-orgctl org rename`) a renomeação é autoritativa e essa variável de ambiente não tem mais efeito. | +| `DEFAULT_ORG_SLUG` | Não | `default` | Slug de URL para a org padrão interna, o caminho do dashboard em que ela vive (`//…`). Mesma semântica de apenas-primeiro-boot/apenas-pristine que `DEFAULT_ORG_NAME`. Deve ter 1-40 caracteres alfanuméricos minúsculos com hífens internos simples e não ser uma [palavra reservada](#organizations-multi-tenancy); um valor inválido é ignorado (a org mantém `default`). Permite que uma instalação single-tenant apareça como ex. `/acme` em vez de `/default` sem nenhuma etapa de CLI pós-deploy. | +| `RUST_LOG` | Não | `info` | Verbosidade de log (`debug`, `warn`, `error`, `agenteye_server=trace`) | +| `EVALUATOR_ENDPOINT` | Não | none | URL base do seu serviço de avaliação (ex.: `http://evaluator:9000`). Quando não definido, todo o pipeline de avaliação é uma no-op; nenhuma linha de fila é escrita, nenhum worker é executado. Veja [Suite de Avaliação](/pt-br/agenteye/evaluation-suite). | +| `EVALUATOR_TOKEN` | Não | none | Enviado como `Authorization: Bearer ` ao avaliador. **Deve ser igual ao valor com o qual o serviço de avaliação está configurado.** Opcional somente se o seu avaliador estiver configurado sem token. | +| `EVALUATOR_WORKERS` | Não | `2` | Concorrência: número de tarefas de worker por instância do servidor que despacham avaliações. Seguro para executar em múltiplos servidores com escalonamento horizontal. | +| `EVALUATOR_CLAIM_BATCH` | Não | `4` | Número máximo de avaliações que um único worker reivindica por tick. Os lotes são despachados **concorrentemente**, portanto a concorrência total no seu endpoint de avaliação é `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH`. | +| `EVALUATOR_POLL_IDLE_SECS` | Não | `2` | Quanto tempo um worker dorme entre tentativas de despacho quando não há nada pendente. | +| `EVALUATOR_POLLING_INTERVAL_SECS` | Não | `10` | Cadência de fallback final (segundos) para polls `GET /evaluate/{id}` quando o avaliador não retorna um `next_poll_secs` por resposta e não anuncia um `default_poll_interval_secs` via `GET /config`. | +| `EVALUATOR_REQUEST_TIMEOUT_MS` | Não | `30000` | Timeout por requisição HTTP contra o avaliador (milissegundos). | +| `EVALUATOR_MAX_ATTEMPTS` | Não | `5` | Após este número de tentativas falhas, uma avaliação é registrada como `error` terminal (ou `timeout` se as falhas foram timeouts de requisição). | +| `EVALUATOR_CONFIG_REFRESH_SECS` | Não | `300` (5 min) | Com que frequência o servidor rebusca `GET /config` do avaliador. | +| `EVALUATOR_MAX_POLL_DURATION_SECS` | Não | `3600` (1 h) | Tempo máximo de relógio que uma sessão pode permanecer na fila de polling antes do AgentEye encerrá-la com `timeout`. Protege contra um avaliador que retorna `pending` indefinidamente. | +| `ALERT_WORKERS` | Não | `1` | Concorrência: número de tarefas de worker por instância do servidor que avaliam regras de alerta. Veja [Alertas](/pt-br/agenteye/alerts). | +| `ALERT_CLAIM_BATCH` | Não | `16` | Número máximo de alertas que um único worker reivindica por tick. | +| `ALERT_POLL_IDLE_SECS` | Não | `5` | Quanto tempo um worker de alertas dorme quando a fila está vazia. | +| `ALERT_REQUEST_TIMEOUT_MS` | Não | `15000` | Timeout por avaliação de trigger (queries do ClickHouse + HTTP do canal de saída). | +| `ALERT_MAX_ATTEMPTS` | Não | `5` | Falhas transitórias consecutivas antes de um alerta ser reagendado em sua cadência normal em vez de backoff exponencial. | +| `AUDIT_WORKERS` | Não | `1` | Concorrência: número de tarefas de worker por instância do servidor que executam auditorias. Veja [Auditorias](/pt-br/agenteye/audits). | +| `AUDIT_CLAIM_BATCH` | Não | `1` | Número máximo de auditorias pendentes que um único worker reivindica por tick. Uma investigação agêntica é um loop longo, então o padrão é 1. | +| `AUDIT_POLL_IDLE_SECS` | Não | `30` | Quanto tempo um worker de auditorias dorme quando nenhuma auditoria está pendente. | +| `AUDIT_REQUEST_TIMEOUT_MS` | Não | `30000` | Timeout por query de política contra o ClickHouse (milissegundos). | +| `AUDIT_LLM_TIMEOUT_MS` | Não | `1440000` | Timeout para a chamada de investigação agêntica ao serviço de assistente de IA. Um loop de agente completo dura minutos; mantenha isso ACIMA do `AGENTEYE_AUDIT_TIMEOUT_MS` do próprio agente para que o agente retorne seus achados parciais antes de o servidor desistir. | +| `AUDIT_MAX_ATTEMPTS` | Não | `5` | Falhas transitórias consecutivas antes de uma auditoria ser reagendada em sua cadência normal em vez de backoff exponencial. | +| `AGENTEYE_AGENT_URL` / `AGENTEYE_AGENT_TOKEN` | Não | — | A investigação agêntica da auditoria chama o serviço `agent` de assistente de IA, **reutilizando a mesma conexão do assistente** — portanto defina esses dois também no **servidor** (os manifestos/compose incluídos no pacote já fazem isso). Ambos definidos ⇒ auditorias executam a investigação de IA; qualquer um não definido ⇒ auditorias executam **somente políticas** (o passo determinístico de política SQL ainda é executado), independentemente do flag `llm_enabled` por auditoria. O agente também deve ter um LLM configurado — veja [assistant.md](/pt-br/agenteye/assistant). | + +**Serviço de assistente de IA — configurações de auditoria + sandbox.** A investigação agêntica e seu sandbox Python no pod são ajustados no **serviço agent** (não no servidor), todos com o prefixo `AGENTEYE_AUDIT_*` e todos opcionais: + +| Variável | Padrão | Significado | +|---|---|---| +| `AGENTEYE_AUDIT_MAX_STEPS` | `200` | Máximo de turnos do agente por investigação. | +| `AGENTEYE_AUDIT_TIMEOUT_MS` | `1200000` | Tempo de relógio para uma investigação (20 min). Deve ficar **abaixo** do `AUDIT_LLM_TIMEOUT_MS` do servidor. | +| `AGENTEYE_AUDIT_MAX_CONCURRENCY` | `1` | Investigações simultâneas por pod de agente (separado do orçamento do assistente de chat). | +| `AGENTEYE_AUDIT_SANDBOX_TIMEOUT_MS` / `_MEM_MB` / `_CPU_SECS` / `_OUTPUT_MAX_BYTES` / `_SCRIPT_MAX_BYTES` | `20000` / `768` / `10` / `64000` / `64000` | Limites por script para o sandbox bubblewrap. | + +**Requisito de plataforma do Sandbox.** O sandbox de código da auditoria executa o Python do modelo dentro de um jail bubblewrap, que precisa de **namespaces de usuário sem privilégio**. O pod do agente deve permitir os flags `clone()` — defina `seccompProfile: Unconfined` (k8s) ou `security_opt: [seccomp:unconfined]` (compose) no agente. Onde o kernel do nó desabilita namespaces de usuário sem privilégio (ex.: algumas imagens GKE COS), o sandbox **falha no preflight e o auditor degrada automaticamente para somente SQL** — sem erro, apenas um `sandbox_available: false` no `/health` do agente. + +### Executar + +Defina `DATABASE_URL` e `CLICKHOUSE_URL` no seu ambiente (o servidor recusa o boot sem o ClickHouse), e então passe-os para o container: + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-server \ + -e DATABASE_URL="$DATABASE_URL" \ + -e CLICKHOUSE_URL="$CLICKHOUSE_URL" \ + -e ADMIN_KEY="$ADMIN_KEY" \ + -p 8080:8080 \ + ghcr.io/agenteye-enterprise/server:beta-latest +``` + +O servidor executa as migrations do banco de dados automaticamente na inicialização; nenhuma etapa de migration separada é necessária. + +### Health check + +``` +GET /health # liveness - sempre {"status":"ok"} uma vez que o processo está em execução +GET /ready # readiness - 200 quando Postgres + ClickHouse estão acessíveis, caso contrário 503 +``` + +Nenhuma autenticação necessária. Use `/health` para probes de **liveness** e `/ready` para probes de **readiness** / load balancer. `/ready` verifica as dependências obrigatórias sem as quais o servidor não consegue atender (Postgres + ClickHouse), então um servidor em execução que não consegue alcançar seu banco de dados é removido da rotação e aparece como `NotReady`; o Redis é reportado mas nunca falha o readiness. Nos manifestos Kubernetes incluídos no pacote, o probe de readiness já aponta para `/ready` e o liveness permanece em `/health`. Veja [enterprise-docs/health-monitoring.md](/pt-br/agenteye/health-monitoring) para o quadro completo, incluindo alertas opcionais para o Slack sobre falhas de pods Kubernetes-native. + +### URL do magic link de email + +Os emails de login OTP contêm um botão **abrir o dashboard** com um toque. Ao clicar, o usuário vai para `/login?token=&email=
`; o dashboard troca esse par por uma sessão e redireciona para o aplicativo, sem reinserção manual do código. O servidor resolve a origem do dashboard usada para construir o link em três níveis: + +1. **Header `X-AgentEye-Dashboard-Url`**: definido automaticamente pelo proxy `/api/auth/otp/request` do dashboard a partir de sua própria origem pública. Em um deploy de mesma origem (servidor e dashboard compartilham um host atrás de um ingress que encaminha headers de proxy), **nenhuma configuração é necessária**. +2. **Variável de ambiente `DASHBOARD_URL`**: defina isso se seu dashboard está acessível em uma origem diferente daquela que o endpoint de requisição OTP do servidor vê (domínios separados `api.example.com` / `app.example.com`), ou se o seu ingress não propaga o host público para o pod do dashboard (para que `request.nextUrl.origin` não resolva para um bind wildcard como `0.0.0.0:3000`). Exemplo: `DASHBOARD_URL=https://app.example.com`. +3. **Padrão**: `https://app.befailproof.ai`, usado apenas se nenhum dos anteriores estiver presente. + +O valor do header é validado: apenas origens `https://*` e loopback (`http://localhost*`, `http://127.0.0.1*`) são aceitas, e endereços de bind wildcard (`0.0.0.0`, `[::]`) são rejeitados mesmo com o esquema `https://`. Qualquer outra coisa passa para o nível 2. + +Defina em um cluster em execução com um one-liner; sem arquivo, sem rebuild do kustomize: + +```bash +kubectl set env deployment/server -n agenteye \ + DASHBOARD_URL=https://app.example.com +``` + +Isso aciona um rollout; os novos pods captam o valor na primeira requisição. Note que o override vive apenas no Deployment; um `kustomize build | kubectl apply` subsequente contra o overlay vai apagá-lo, a menos que você adicione a mesma variável de ambiente ao patch `server-env.yaml` do seu overlay. + +--- + +## Dashboard + +### Baixar a imagem + +```bash +docker pull ghcr.io/agenteye-enterprise/dashboard:beta-latest +``` + +### Variáveis de ambiente + +| Variável | Obrigatória | Padrão | Descrição | +|---|---|---|---| +| `AGENTEYE_SERVER_URL` | Sim | none | URL base do servidor, ex.: `http://localhost:8080` | +| `AGENTEYE_API_KEY` | Sim | none | Chave de API que o dashboard usa para autenticar no servidor. Precisa de todas as permissões (chave admin recomendada). | +| `AE_LOG_LEVEL` | Não | `info` | Verbosidade de log no lado do servidor: `debug`, `info`, `warn`, `error`. Defina como `debug` para ver linhas de requisição/resposta upstream e traces de validação de sessão ao diagnosticar problemas. | +| `AE_LOG_JSON` | Não | automático | `1` força saída JSON por linha; `0` força saída legível por humanos. Quando não definido, JSON é habilitado automaticamente se `NODE_ENV=production`. JSON é recomendado em produção para que os logs sejam parseados facilmente com `jq` ou um agregador de logs. | +| `AE_ANALYTICS_DISABLED` | Não | none | Defina como `1`/`true` para desabilitar a telemetria anônima de uso do produto do dashboard. Veja [Telemetria e privacidade](#telemetry--privacy) abaixo. | +| `REDIS_URL` | Não | none | Backend de cache compartilhado opcional, ex.: `redis://redis:6379/0`. Quando definido, o dashboard cacheia resultados de `validateSession()` entre réplicas e compartilha o cache de fetch do Next.js para as rotas de proxy de latência-agregada / env-list. Os rate limits de requisição e verificação OTP no lado do edge também usam Redis quando presente (falha aberta se o Redis estiver inacessível; o limite no lado do servidor é o backstop de segurança). Veja **Redis (cache opcional)** abaixo. | +| `AGENTEYE_AGENT_URL` | Não | none | URL base do serviço `agent` de assistente de IA opcional, ex.: `http://agent:9100`. **Deixe não definido para ocultar o assistente completamente**: nenhuma bolha do assistente aparece no dashboard. Veja [enterprise-docs/assistant.md](/pt-br/agenteye/assistant). | +| `AGENTEYE_AGENT_TOKEN` | Não | none | Segredo compartilhado que o dashboard apresenta ao serviço `agent`. Deve corresponder ao `AGENTEYE_AGENT_TOKEN` configurado no agente. Veja [enterprise-docs/assistant.md](/pt-br/agenteye/assistant). | + +### Executar + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-dashboard \ + -e AGENTEYE_SERVER_URL="http://your-server-host:8080" \ + -e AGENTEYE_API_KEY="$ADMIN_KEY" \ + -p 3000:3000 \ + ghcr.io/agenteye-enterprise/dashboard:beta-latest +``` + +### Telemetria e privacidade + +O dashboard envia **analytics anônimos de uso do produto** para o serviço de analytics da Exosphere (PostHog): quais páginas do dashboard são visitadas e algumas ações de UI, como criar uma chave de API ou reavaliar uma sessão. Esse sinal de uso informa quais funcionalidades são priorizadas. + +- **Nenhum dado de agente, sessão ou evento jamais sai da sua infraestrutura.** Apenas o uso da UI do dashboard é reportado. As URLs de páginas são despidas de identificadores antes do envio, e os operadores são identificados apenas por um id interno opaco, nunca por email. +- A telemetria está **habilitada por padrão**. Para desativá-la completamente, defina `AE_ANALYTICS_DISABLED=1` no container do dashboard e reinicie. +- Os analytics são enviados para o próprio caminho `/ingest` do dashboard, que o dashboard faz proxy reverso para o PostHog (`https://us.i.posthog.com`). Manter as requisições como first-party significa que bloqueadores de anúncio do navegador não as descartam. O **container do dashboard** precisa de acesso de saída para o PostHog; se estiver bloqueado, a telemetria silenciosamente não faz nada e o dashboard não é afetado. + +--- + +## Assistente de IA (opcional) + +Um assistente de IA integrado ao dashboard permite que sua equipe faça perguntas sobre os dados dos agentes em linguagem natural (resumindo sessões, redigindo SQL para o editor `/queries` e transformando queries salvas em tiles do dashboard) sem sair do dashboard. Ele roda como um container interno separado `agent` (no Claude Agents SDK) que apenas o dashboard consegue alcançar, e permanece **desabilitado até você configurar um endpoint de LLM**. + +Para habilitá-lo, você define no serviço `agent` uma conexão de LLM (**Portkey** via `PORTKEY_API_KEY` + um slug do catálogo de modelos `AGENTEYE_AGENT_MODEL=@/`, Anthropic direto via `ANTHROPIC_API_KEY`, outro gateway via `ANTHROPIC_BASE_URL`, ou Bedrock/Vertex), uma chave de dados **dedicada** e um `AGENTEYE_AGENT_TOKEN` compartilhado correspondente ao dashboard. Os usuários do dashboard também precisam da permissão `agent:use`. + +Para a chave de dados do assistente, você não precisa criar nada manualmente: escolha um segredo aleatório, defina-o como `AGENTEYE_API_KEY` no `agent` **e** como `AGENT_API_KEY` no `server`, e o servidor o alimenta na inicialização com um conjunto fixo de permissões. Seu acesso a dados é somente leitura (`events:read`, `evaluations:read`, `dashboards:read`, `queries:read`), e adicionalmente possui escopos de autoria com aprovação (`dashboards:write`, `queries:write`, `queries:run`) para que ele possa redigir e validar queries salvas e construir tiles do dashboard em nome do usuário; todo SQL ainda é executado pelo papel ClickHouse somente leitura da org, portanto isso amplia o que o assistente pode criar, não os dados que pode acessar. Os escopos são fixos no código e não podem ser ampliados por configuração. Essa chave é protegida; não pode ser desabilitada ou regenerada via API, apenas rotacionada alterando o valor e reiniciando. Nunca reutilize a chave admin/dashboard para isso. + +A configuração completa, a referência completa de variáveis de ambiente, opções de telemetria e o modelo de segurança estão em **[enterprise-docs/assistant.md](/pt-br/agenteye/assistant)**. + +--- + +## ClickHouse (armazenamento de analytics obrigatório) + +O ClickHouse mantém seus dashboards responsivos em altos volumes de eventos e permite que o editor SQL `/queries` faça joins entre eventos, avaliações e sessões em um único armazenamento. É o armazenamento canônico obrigatório para cada evento ingerido, cada resultado de avaliação terminal e os agregados derivados por sessão. O PostgreSQL mantém as tabelas relacionais/de estado mutável (api_keys, users, otp_codes, evaluation_jobs, dashboards, saved_queries); a superfície analítica vive no ClickHouse para que os rollups do dashboard e suas próprias queries SQL possam escanear e fazer joins nativamente, sem round-trips entre bancos de dados. O servidor recusa o boot sem `CLICKHOUSE_URL`. + +### Schema + +Três objetos ClickHouse são criados na inicialização do servidor, todos idempotentes (`CREATE IF NOT EXISTS`): + +- **`agenteye.events`**: `ReplacingMergeTree(ingested_at)`, particionado por `toYYYYMM(ts)`, ordenado por `(session_id, ts, dedup_key)`. Inserções duplicadas (retentativas do collector) colapsam para uma única linha no momento do merge; o servidor calcula um `dedup_key` SHA-256 determinístico para cada evento, tornando as retentativas seguras. +- **`agenteye.evaluations`**: `ReplacingMergeTree(ingested_at)`, particionado por `toYYYYMM(finished_at)`, ordenado por `(session_id, finished_at, dedup_key)`. Escrito uma vez por resultado de avaliação terminal pelo pipeline de avaliação. Mesmo modelo de dedup-key que `events`. +- **`agenteye.agent_sessions`**: uma **VIEW** sobre `agenteye.events`, não uma tabela física. Cada coluna é derivada (`started_at = min(ts)`, `last_event_at = max(ts)`, `ended_at = max(if event_type='agent_end', ts, NULL)`, `event_count = count()`, etc.). Sem upsert por evento e sem backfill separado; a view reflete automaticamente o que estiver em `events`. + +Para compatibilidade retroativa com queries salvas que referenciam `analytics.evaluations` / `analytics.sessions`, o servidor também cria um banco de dados ClickHouse `analytics` com views sobre as tabelas `agenteye.*`; `analytics.events`, `analytics.evaluations`, `analytics.agent_sessions`, `analytics.sessions` resolvem corretamente. + +### Configuração + +O docker-compose incluso e `deploy/base/clickhouse/` trazem um serviço ClickHouse ajustado para a carga de trabalho do AgentEye: + +- 2 GiB solicitados / 4 GiB limite de memória no overlay base incluso (dimensionado para nós pequenos de POC/staging); clientes de produção devem aumentar o overlay — o piso recomendado é 2c / 4Gi request, 6c / 8Gi limit. `max_server_memory_usage_to_ram_ratio=0.9` +- 5 GiB mark cache + 8 GiB uncompressed cache +- `background_pool_size=16`, `background_merges_mutations_concurrency_ratio=2` +- MergeTree: `parts_to_throw_insert=3000`, `parts_to_delay_insert=1500`, `non_replicated_deduplication_window=1000` +- `local_io_method=auto` (io_uring em kernels suportados) +- `fsync_metadata=0`: aceitável por causa da ingestão pelo menos uma vez + dedup do ReplacingMergeTree +- `query_log` habilitado com TTL de 30 dias; `query_thread_log` removido (caro em QPS alto) +- `max_execution_time=30` para queries do lado do usuário +- PVC de 100 GiB no template StatefulSet (os overlays do cliente DEVEM sobrescrever para uma classe de armazenamento SSD rápida em produção) + +### Backups + +Seu conjunto de dados completo é capturado nightly em um único arquivo restaurável, então uma perda de cluster ou armazenamento é recuperável. O ClickHouse é feito backup automaticamente pelo CronJob diário `agenteye-backup`, que despeja tanto o PostgreSQL quanto o ClickHouse em uma única passagem. O ClickHouse é lido via sua API HTTP: `agenteye.events` e `agenteye.evaluations` são despejados no formato nativo do ClickHouse (as views e row policies são recriadas pelo servidor na inicialização, então os dados da tabela são o quadro completo) e empacotados com o dump do Postgres em um único arquivo comprimido enviado para o seu armazenamento de objetos. + +O bucket de destino e as credenciais de nuvem são configurados por overlay. Veja a seção **Backups** de [enterprise-docs/kubernetes-deployment.md](/pt-br/agenteye/kubernetes-deployment) para configuração de upload e passos de restauração. + +--- + +## Redis (cache opcional) + +O Redis é um cache compartilhado **opcional** + backend de rate limiting usado pelo servidor e pelo dashboard. Com o Redis implantado e `REDIS_URL` definido em ambos os serviços: + +- **Servidor** cacheia lookups de API key autenticados, as listas `/events/environments` + `/evaluations/environments`, o rollup `/events/latency_aggregate` (a query mais pesada que o dashboard faz poll), a lista `/sessions`, e troca o rate limiting de requisição OTP de um `COUNT(*)` do Postgres por um `INCR + EXPIRE` do Redis. +- **Dashboard** cacheia resultados de `validateSession()` para que as 10-20 chamadas de API autenticadas que um carregamento de página típico faz compartilhem uma única verificação de sessão upstream. Também faz rate limiting de requisição e verificação OTP no edge do dashboard. + +**Ambos os serviços degradam de forma elegante se o Redis estiver inacessível.** Cada chamada de cache retorna `Err` dentro de um timeout limitado e o chamador recai para a fonte de verdade (Postgres no servidor, o servidor Rust upstream no dashboard). O rate limiting OTP recai para o caminho `COUNT(*)` do Postgres no servidor (a propriedade de segurança é preservada); o limite OTP de edge do dashboard falha aberto enquanto o limite do lado do servidor ainda é mantido. O Redis fora do ar degrada a latência, não a correção. + +### Configuração + +O pacote docker-compose já inclui um serviço Redis e conecta `REDIS_URL=redis://redis:6379/0` ao servidor e ao dashboard. Para usar um Redis externo, defina `REDIS_URL` para o seu endpoint e remova o serviço `redis` do arquivo compose. + +### Memória + persistência + +A imagem Redis inclusa no pacote executa com `--appendonly yes --appendfsync everysec --maxmemory 256mb --maxmemory-policy allkeys-lru`. A persistência AOF significa que o cache sobrevive a reinicializações do container; `everysec` é o equilíbrio certo de durabilidade/performance porque perder o último segundo de writes de cache é inofensivo. A evicção LRU limita o crescimento de memória. + +### Quando NÃO implantar o Redis + +- Dev/QA de instância única. Os caches em processo no servidor por si só entregam a maior parte do benefício por réplica; o Redis adiciona o compartilhamento entre réplicas que setups de instância única não precisam. +- Instalações air-gapped onde o custo operacional de executar mais um serviço supera o ganho de latência. + +--- + +## Docker Compose (recomendado) + +Um `docker-compose.yml` está disponível no repositório `agenteye-enterprise/releases`. Ele sobe o Postgres, ClickHouse, Redis, o servidor e o dashboard com um único comando. + +```bash +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download \ + --repo agenteye-enterprise/releases \ + --pattern 'docker-compose.yml' \ + --dir ./agenteye +cd agenteye +``` + +**Sobrescreva os padrões via `.env`:** + +``` +# Use senhas seguras para URL (sem os caracteres /, +, ou =). +# Gere com: openssl rand -hex 24 +POSTGRES_PASSWORD=your-db-password +ADMIN_KEY=your-admin-secret + +# Autenticação do dashboard +ADMIN_EMAIL=admin@yourcompany.com +ALLOWED_EMAILS=*@yourcompany.com + +# SMTP para emails OTP (omita para registrar códigos OTP no stdout) +# SMTP_HOST=smtp.yourprovider.com +# SMTP_PORT=587 +# SMTP_USERNAME=your-smtp-user +# SMTP_PASSWORD=your-smtp-password +# SMTP_FROM=noreply@yourcompany.com + +RUST_LOG=info +``` + +```bash +docker compose up -d +``` + +**Parar (mantém o volume de dados):** + +```bash +docker compose down +``` + +**Parar e apagar todos os dados:** + +```bash +docker compose down -v +``` + +--- + +## Configurações operacionais + +Um pequeno conjunto de parâmetros operacionais que antes eram fixados por variáveis de ambiente agora são editáveis por organização na página **`//settings`** do dashboard; cada org configura os seus próprios. As alterações entram em vigor em segundos, sem restart e sem redeploy. + +| Configuração | Variável de ambiente de bootstrap | O que controla | +|---|---|---| +| Logins permitidos | `ALLOWED_EMAILS` | Emails (ou wildcards `*@dominio.com`) autorizados a receber um OTP e serem adicionados como usuários | +| Permissões padrão do usuário | `DEFAULT_USER_PERMISSIONS` | Tokens de permissão separados por vírgula pré-selecionados quando um admin abre **+ novo usuário**. Cada token deve ser uma das strings listadas em [Permissões de chave de API](/pt-br/agenteye/api-keys). Padrão para o preset `standard`: acesso somente leitura mais as ações cotidianas de plantão (disparar reavaliações, executar queries, confirmar incidentes, usar o assistente). | +| Tempo de vida da sessão | `SESSION_TTL_SECS` | Por quanto tempo um login no dashboard permanece válido antes de reautenticação. O dashboard reverifica a sessão upstream a cada 5 segundos, então uma atualização de permissão em `//users` entra em vigor na próxima requisição do usuário afetado, sem necessidade de novo login. | +| Tempo de vida do código único | `OTP_TTL_SECS` | Por quanto tempo um OTP / magic-link permanece utilizável | +| Canais de notificação de alertas | `ALERTS_ENABLED_CHANNELS` | Lista separada por vírgulas de tipos de canal que o despachante de alertas pode usar: `email`, `slack`, `webhook`. A configuração por alerta ainda é feita em `//alerts/`, mas o despachante filtra cada entrega de saída por este conjunto; um canal desabilitado aqui é curto-circuitado com uma linha de auditoria `skipped_disabled`. O canal `dashboard` (o insert de auditoria local) é sempre permitido. Padrão para os três habilitados. | + +### Como o bootstrap funciona + +As configurações são armazenadas por organização em `org_settings`. No primeiro boot, o servidor alimenta as linhas ausentes da org padrão a partir da variável de ambiente correspondente (ou um padrão sensato se a variável não estiver definida). Depois disso, **o valor armazenado é a fonte de verdade e a variável de ambiente é ignorada**; alterar a variável de ambiente em um restart posterior não afetará o valor de uma org em produção, e orgs adicionais iniciam com padrões e configuram os seus próprios. + +Isso significa que: + +- Para um deploy novo, defina as variáveis de ambiente como mostrado acima e a org padrão as lerá no primeiro boot. +- Para alterar um valor posteriormente, faça login no dashboard e edite em `//settings`. A alteração é aplicada em segundos em todas as réplicas do servidor; nenhum restart é necessário. +- Uma linha de log na inicialização registra o que foi alimentado vs. o que já estava presente, para que você possa confirmar que o bootstrap teve efeito: + + ```text + INFO settings bootstrap: seeded default-org row key=allowed_sign_ins env_var=ALLOWED_EMAILS seeded_from_env=true + ``` + +#### Semântica de login entre organizações + +Uma sessão e um OTP são globais para o usuário, não para uma única org, então duas regras reconciliam as configurações por org no momento do login: + +- **Tempo de vida da sessão / OTP**: o tempo de vida mais restritivo (mais curto) entre as orgs às quais o usuário pertence prevalece. +- **Logins permitidos**: a porta faz OR de cada allowlist de org com a associação de org: um usuário pode solicitar um OTP se a allowlist de qualquer org admitir seu email **ou** ele já for membro de qualquer org. + +### Permissões + +O acesso a uma página `//settings` é controlado por duas permissões: + +- `settings:read`: ver a página e os valores atuais. +- `settings:write`: salvar alterações. + +O usuário admin de bootstrap (alimentado a partir de `ADMIN_EMAIL`) recebe ambas automaticamente junto com todas as outras permissões. Conceda-as a outros usuários a partir de `//users` conforme necessário. + +--- + +## Organizações (multi-tenancy) + +Um único deployment pode servir múltiplas **organizações** (tenants) isoladas; cada linha de dados pertence exatamente a uma org e o isolamento é imposto no engine do banco de dados. Uma instalação single-tenant não precisa de nada aqui; todos os dados vivem em uma org `default` integrada. (Você pode dar a essa org um nome mais amigável e slug de URL, para que ela viva em ex. `/acme` em vez de `/default`, definindo `DEFAULT_ORG_NAME` / `DEFAULT_ORG_SLUG` antes do primeiro boot, ou renomeando-a a qualquer momento com `agenteye-orgctl org rename`.) + +**O provisionamento de tenants é exclusivo do operador.** Organizações e suas associações são criadas e gerenciadas com o CLI **`agenteye-orgctl`**, que é distribuído **dentro da imagem do servidor** (ao lado de `agenteye-server`) e executa **dentro do pod do servidor existente**; não há **pod/Job separado, sem API HTTP e sem botão no dashboard**. Ele reutiliza `DATABASE_URL`, `CLICKHOUSE_URL` e `ORG_CH_SECRET` do servidor. + +```bash +# Docker Compose - exec no serviço servidor em execução: +docker compose exec server agenteye-orgctl org create --slug acme --name "Acme Corp" +docker compose exec server agenteye-orgctl member add --org acme --email alice@acme.example --set admin + +# Kubernetes - exec no Deployment servidor em execução: +kubectl -n agenteye exec deploy/server -- agenteye-orgctl org list +``` + +Verbos disponíveis: `org create | list | rename | delete | purge` e `member add | list | update | remove`, com conjuntos de permissões integrados `admin`, `standard` e `read-only`. Membros adicionados recebem um OTP no primeiro login no dashboard. + +**Antes de criar uma segunda org:** defina um `ORG_CH_SECRET` forte e estável (o comando `org create` recusa executar com o padrão de dev interno) e garanta que o Postgres seja **15+**. **Sem alteração:** chaves de API por org ainda são criadas no dashboard/API por membros da org; apenas o ciclo de vida de org + membro foi movido para o CLI. Referência completa de comandos e um exemplo prático: **[enterprise-docs/tenant-management.md](/pt-br/agenteye/tenant-management)**. + +--- + +## Preenchimento da janela de contexto + +Cada evento `model_response` mostra um **indicador de preenchimento de contexto** — tokens de entrada mais saída como percentagem da janela de contexto daquele modelo. As faixas são `healthy` (0–24%), `watch` (25–49%), `compacting` (50–74%) e `reset context` (75–100%). O AgentEye resolve IDs de modelos comuns automaticamente, portanto nenhuma configuração inicial é necessária. + +Cada modelo que uma organização envia aparece em **Configurações → janelas de contexto de modelos**. Usuários com `settings:write` podem sobrescrever sua janela ou adicionar um modelo privado/proxy (0–1.000.000 tokens); `0` significa "desconhecido" e suprime o indicador. As alterações se aplicam a eventos recém-ingeridos. Usuários com `settings:read` podem visualizar a lista. + +Novos eventos recebem o preenchimento a partir do momento em que você atualiza. Para também popular eventos **históricos** (e a lista por modelo) para um deployment existente, execute o backfill único — ele é distribuído dentro da imagem do servidor (como `agenteye-orgctl`) e executa no pod do servidor existente: + +```bash +# preview (imprime a mutação por org, não altera nada): +kubectl -n agenteye exec deploy/server -- agenteye-backfill-context-window --dry-run +# aplicar: +kubectl -n agenteye exec deploy/server -- agenteye-backfill-context-window +# docker compose: +docker compose exec server agenteye-backfill-context-window +``` + +É idempotente (seguro para re-executar) e reutiliza `DATABASE_URL` / `CLICKHOUSE_URL` / `REDIS_URL` do pod. Execute novamente após editar janelas de modelos se quiser que os eventos existentes sejam recomputados. + +--- + +## Considerações para produção + +- **Postgres**: Use um serviço Postgres gerenciado ou uma instância dedicada com backups regulares. O `DATABASE_URL` suporta todos os parâmetros libpq padrão, incluindo `sslmode=require` para conexões criptografadas. +- **TLS**: Coloque o servidor e o dashboard atrás de um proxy reverso (nginx, Caddy, Traefik) que encerra o TLS. +- **Firewall**: A porta do servidor (padrão 8080) deve ser acessível apenas pelas máquinas do collector e pelo host do dashboard, não pela internet pública. +- **Chave admin**: Defina `ADMIN_KEY` como um segredo aleatório forte. Após o bootstrap, crie chaves com escopos dedicados para collectors e o dashboard em vez de usar a chave admin em todo lugar. +- **Tags de imagem**: Fixe na versão nos seus manifestos de release (por exemplo, `server:v0.0.1-beta.48`) em produção em vez de uma tag flutuante para evitar atualizações não intencionais. As builds beta atuais são publicadas sob `beta-latest`; `latest` é atribuído apenas a releases estáveis. +- **Monitoramento de saúde**: No Kubernetes, o probe de readiness usa `/ready` (acessibilidade do Postgres + ClickHouse) enquanto o liveness permanece em `/health`. Para alertas de toda a frota sobre "o AgentEye está funcionando?" para o Slack, habilite o add-on Robusta opcional; veja [enterprise-docs/health-monitoring.md](/pt-br/agenteye/health-monitoring). + +--- + +## Tags de imagem disponíveis + +| Tag | Descrição | +|-----|-------------| +| `latest` | Último release estável | +| `beta-latest` | Último pré-release (beta) | +| `v` | Versão fixada, ex.: `v0.0.1-beta.48` (recomendado para produção) | \ No newline at end of file diff --git a/docs/pt-br/agenteye/evaluation-suite.mdx b/docs/pt-br/agenteye/evaluation-suite.mdx new file mode 100644 index 00000000..568d54e4 --- /dev/null +++ b/docs/pt-br/agenteye/evaluation-suite.mdx @@ -0,0 +1,459 @@ +--- +title: "Evaluation Suite" +description: "Documentação do AgentEye Evaluation Suite." +--- + +O AgentEye pontua sessões de agentes concluídas enviando via POST a transcrição completa de eventos para um **único serviço avaliador de propriedade do cliente**. O avaliador retorna as pontuações de forma inline ou devolvendo um `job_id` para que o AgentEye faça polling. Os resultados são armazenados e exibidos no dashboard. + +Este guia cobre: + +1. Como a conclusão de sessão é detectada. +2. O contrato HTTP que o avaliador deve implementar. +3. Como configurar o servidor AgentEye. +4. Como visualizar os resultados. +5. Solução de problemas. + +Para o helper Python que implementa o contrato por você, consulte o +[pacote `agenteye-evaluator` no PyPI](https://pypi.org/project/agenteye-evaluator/). + +--- + +## Como funciona + +```text +ingest /events ──▶ AgentEye ──── POST /evaluate ────▶ Serviço avaliador + (agent_end) server ◀──── done | pending ──── + │ + │ GET /evaluate/{job_id} ─────▶ + │ ◀──── done ────────────── + ▼ + evaluations (resultados terminais) +``` + +Quando o SDK do AgentEye emite um evento `agent_end` para uma sessão, o servidor +agenda uma avaliação. Em seguida, envia via POST a transcrição completa de eventos +para o seu serviço avaliador, que pode: + +- **Retornar o resultado de forma inline** com `{"status":"done", "scores":{...}, "reasoning":{...}, "summary":"..."}`. O + resultado é adicionado à linha do tempo de avaliações da sessão. `reasoning` e + `summary` são opcionais. +- **Adiar** com `{"status":"pending", "job_id":"abc-123"}`. O AgentEye então + chama `GET {EVALUATOR_ENDPOINT}/evaluate/abc-123` até que o avaliador + retorne `{"status":"done", ...}` ou `{"status":"error", "error":"..."}`. + + A cadência de polling é por job: uma resposta `pending` pode incluir + `next_poll_secs` para substituir o padrão; caso contrário, o AgentEye usa o + valor `default_poll_interval_secs` de `GET /config`; caso contrário, o servidor + usa `EVALUATOR_POLLING_INTERVAL_SECS` como fallback (padrão: 10s). Todos os valores + são limitados ao intervalo [1s, 1h]. + +Sessões que nunca emitem `agent_end` (por exemplo, um processo de agente que travou) +também podem ser processadas: o `GET /config` do avaliador pode retornar +`{"inactivity_timeout_secs": 1800}`, e o AgentEye avaliará qualquer sessão +que ficou ociosa por esse período. Defina o campo como `null` ou omita-o para +desabilitar esse fallback. + +O pipeline é completamente inativo quando `EVALUATOR_ENDPOINT` não está definido. + +Uma sessão pode acumular **múltiplas avaliações terminais ao longo do tempo**: cada +evento `agent_end` (e cada re-avaliação manual pelo dashboard) adiciona uma nova +linha de avaliação. Essa é a forma recomendada de avaliar uma conversa retomada: +um usuário encerra um agente, retorna mais tarde, envia mais eventos, +encerra o agente novamente, e uma segunda avaliação é executada contra a transcrição +completa e atualizada. O dashboard renderiza a avaliação mais recente como destaque +e as avaliações anteriores como uma linha do tempo recolhível. Enquanto uma +avaliação está em andamento para uma sessão, eventos `agent_end` adicionais para essa +sessão são ignorados; o próximo após a avaliação em andamento ser concluída +enfileirará uma nova avaliação normalmente. + +O fallback de inatividade também é reativado em sessões retomadas: se novos eventos +chegarem após uma avaliação terminal anterior e a sessão ficar ociosa por mais tempo +que `inactivity_timeout_secs`, uma nova avaliação é enfileirada. + +Falhas transientes (5xx, 429, timeouts, erros de rede) são repetidas com +backoff exponencial até `EVALUATOR_MAX_ATTEMPTS`; respostas 4xx são +terminais. O AgentEye pode ser executado com segurança em múltiplas instâncias +de servidor com escalonamento horizontal; o trabalho é particionado para que a mesma +sessão nunca seja despachada duas vezes simultaneamente. + +--- + +## Contrato HTTP + +Todas as rotas autenticadas usam **autenticação via bearer token**. O mesmo valor deve ser +configurado em ambos os lados: + +- Servidor AgentEye: variável de ambiente `EVALUATOR_TOKEN` +- Serviço avaliador: configurado da mesma forma (o SDK `agenteye-evaluator` + lê `EVALUATOR_TOKEN` por convenção) + +Se `EVALUATOR_TOKEN` não estiver definido, o servidor não envia o header `Authorization`; +o avaliador pode então aceitar requisições anônimas, o que é aceitável para uma +rede interna, mas não recomendado na internet pública. + +### Rotas que o avaliador deve disponibilizar + +| Rota | Body / parâmetros | Resposta | +|---|---|---| +| `GET /health` | nenhum | `{"status":"ok"}` (aberta, sem auth) | +| `GET /config` | nenhum | `{"inactivity_timeout_secs": \| null, "default_poll_interval_secs": \| omitted}` | +| `POST /evaluate` | JSON `EvalRequest` | `{"status":"done", ...}` ou `{"status":"pending", "job_id":"..."}` | +| `GET /evaluate/{id}` | nenhum | mesmo formato de resposta que `/evaluate` | + +### Body `EvalRequest` enviado pelo servidor + +```json +{ + "schema_version": "1", + "session_id": "session-abc123", + "agent_id": "planner", + "environment": "production", + "started_at": "2026-05-10T12:00:00Z", + "ended_at": "2026-05-10T12:05:00Z", + "events": [ + { "id": 1234, "ts": "...", "event_type": "agent_start", "payload": { ... } }, + ... + ] +} +``` + +### Formatos de resposta + +**Síncrono (done):** + +```json +{ + "status": "done", + "scores": { "helpfulness": 0.85, "tool_efficiency": 0.6 }, + "reasoning": { + "helpfulness": "answered the question directly with citations", + "tool_efficiency": "called list_files three times when one would have done" + }, + "summary": "strong answer quality, weak tool selection" +} +``` + +`reasoning` (um mapa de justificativa por pontuação) e `summary` (uma narrativa +geral de um parágrafo) são ambos opcionais. As chaves em `reasoning` devem +espelhar as chaves em `scores`; o dashboard renderiza cada entrada inline abaixo +de sua barra de pontuação. Avaliadores mais antigos que retornam apenas `scores` continuam +funcionando sem alterações; `reasoning` e `summary` simplesmente são lidos como null e +os elementos de interface correspondentes são omitidos. + +**Assíncrono (adiado):** + +```json +{ "status": "pending", "job_id": "abc-123", "next_poll_secs": 30 } +``` + +`next_poll_secs` é opcional; se omitido, o servidor usa como fallback o +`default_poll_interval_secs` do avaliador via `/config`, e depois a sua própria +variável de ambiente `EVALUATOR_POLLING_INTERVAL_SECS`. + +**Erro terminal no lado do avaliador:** + +```json +{ "status": "error", "error": "model service unavailable" } +``` + +O servidor trata qualquer outro body 2xx como erro de protocolo e registra um +`error` terminal para a sessão. + +--- + +## Escrevendo um avaliador com o SDK + +O pacote Python `agenteye-evaluator` fornece um wrapper FastAPI tipado +que implementa o contrato HTTP acima. Instale-o via PyPI: + +```bash +pip install agenteye-evaluator +``` + +Avaliador mínimo viável: + +```python +import os +from agenteye_evaluator import Evaluator, EvalRequest, EvalResponse + +app = Evaluator(token=os.environ["EVALUATOR_TOKEN"]) + +@app.evaluator +def run(req: EvalRequest) -> EvalResponse: + # Inspecione req.events (a transcrição completa da sessão) e retorne pontuações. + tool_calls = sum(1 for e in req.events if e.event_type == "tool_use") + return EvalResponse( + scores={"tool_calls": float(tool_calls)}, + reasoning={"tool_calls": f"{tool_calls} tool invocations in the transcript"}, + summary="tight tool loop" if tool_calls < 5 else "agent looped on tools", + ) +``` + +A instância `app` é ASGI-callable, então `uvicorn module:app` a executa. + +Para avaliadores que precisam adiar trabalho pesado, retorne `JobPending` +em vez disso e registre um handler `@app.job_lookup`; o servidor AgentEye +faz polling em `GET /evaluate/{job_id}` até que você retorne um status terminal ou o +limite `EVALUATOR_MAX_POLL_DURATION_SECS` (padrão: 1h) seja atingido. + +Referência completa da API, padrão assíncrono e schema de eventos: o README do +`agenteye-evaluator` está incluído em cada tarball de release na +[página de releases do agenteye-enterprise](https://github.com/agenteye-enterprise/releases), +ou você pode lê-lo na página do pacote no PyPI. + +--- + +## Executando um avaliador no Kubernetes + +O avaliador é **seu serviço**: o AgentEye não inclui um container avaliador padrão. +O release inclui manifests de referência do Kubernetes +em `deploy/examples/evaluator/` que você pode aplicar diretamente +após substituir sua imagem e um bearer token compartilhado. + +### 1. Containerize seu avaliador + +Um Dockerfile mínimo para seu avaliador: + +```dockerfile +FROM python:3.12-slim +WORKDIR /app +RUN pip install --no-cache-dir agenteye-evaluator uvicorn +COPY my_evaluator.py . +RUN useradd --uid 10001 --create-home --shell /usr/sbin/nologin evaluator \ + && chown -R evaluator:evaluator /app +USER evaluator +EXPOSE 9000 +CMD ["uvicorn", "my_evaluator:app", "--host", "0.0.0.0", "--port", "9000"] +``` + +`runAsNonRoot` (UID 10001) mantém o container compatível com perfis de segurança +restritos do Pod Security. + +### 2. Crie o bearer token compartilhado + +```bash +kubectl -n agenteye create secret generic evaluator-token \ + --from-literal=token="$(openssl rand -hex 32)" +``` + +Use o mesmo valor como `EVALUATOR_TOKEN` no servidor AgentEye. O +servidor envia `Authorization: Bearer ` em cada requisição; o SDK +usa `hmac.compare_digest` para uma verificação em tempo constante e rejeita +incompatibilidades com HTTP 401. + +### 3. Aplique os manifests de exemplo + +```bash +# Edite deploy/examples/evaluator/deployment.yaml primeiro para apontar +# `image:` para o seu registry, depois: +kubectl apply -k deploy/examples/evaluator/ +``` + +O exemplo inclui: + +- Um Deployment de 2 réplicas com `runAsNonRoot`, sistema de arquivos raiz somente leitura, + todas as capabilities removidas, liveness + readiness em `/health` +- Um Service ClusterIP na porta 9000 +- Um template `secret.example.yaml` (intencionalmente excluído da + Kustomization; crie o secret real fora do processo para que nenhum token vá parar + no git) + +### 4. Configure o AgentEye para usá-lo + +No servidor AgentEye, defina: + +```bash +EVALUATOR_ENDPOINT=http://evaluator:9000 +EVALUATOR_TOKEN= +``` + +O servidor distribui `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH` +requisições concorrentes entre todos os pods do avaliador (padrões: `2 × 4 = 8`). +Escale `replicas` e os limites de recursos por pod em conjunto com esses +parâmetros do lado do servidor. + +### Verificação + +```bash +kubectl -n agenteye port-forward svc/evaluator 9000:9000 +curl -s http://localhost:9000/health # → {"status":"ok"} +``` + +Após um agente executar de ponta a ponta, `GET /evaluations` no servidor AgentEye +deve retornar uma linha com `status: "done"` e as pontuações produzidas pelo seu avaliador. + +--- + +## Configurando o servidor AgentEye + +Defina no processo do servidor: + +| Variável de ambiente | Significado | +|---|---| +| `EVALUATOR_ENDPOINT` | URL base do seu avaliador (`http://evaluator:9000`). Não definida = pipeline desabilitado. | +| `EVALUATOR_TOKEN` | Bearer token. Deve ser igual ao valor com que o serviço avaliador está configurado. | +| `EVALUATOR_WORKERS` | Tarefas de worker por instância do servidor (padrão: 2). | +| `EVALUATOR_CLAIM_BATCH` | Linhas processadas por tick de worker (padrão: 4). Os lotes são processados **de forma concorrente**; a concorrência efetiva no endpoint do avaliador é `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH`. | +| `EVALUATOR_POLL_IDLE_SECS` | Quanto tempo um worker dorme entre tentativas de despacho quando nenhuma avaliação está pendente (padrão: 2s). | +| `EVALUATOR_POLLING_INTERVAL_SECS` | Fallback final para a cadência de `GET /evaluate/{id}` quando nem o `next_poll_secs` por resposta nem o `default_poll_interval_secs` do avaliador está definido (padrão: 10s). | +| `EVALUATOR_REQUEST_TIMEOUT_MS` | Timeout por requisição (padrão: 30000). | +| `EVALUATOR_MAX_ATTEMPTS` | Após este número de falhas transientes, o resultado é registrado como `error` terminal (padrão: 5). | +| `EVALUATOR_CONFIG_REFRESH_SECS` | Cadência de `GET /config` (padrão: 300). | +| `EVALUATOR_MAX_POLL_DURATION_SECS` | Tempo máximo em relógio de parede que uma sessão pode permanecer na fila de polling antes de ser encerrada como `timeout` (padrão: 3600s). Protege contra um avaliador que continua retornando `pending` indefinidamente. | + +Para ativar a pontuação automática em toda a instância, provisione o Secret `agenteye-evaluator` com ambas as chaves definidas. Nos manifests Kubernetes incluídos, o servidor lê `EVALUATOR_ENDPOINT` e `EVALUATOR_TOKEN` desse Secret opcional. Crie-o pelo processo padrão de gerenciamento de secrets da sua organização e reinicie o Deployment do servidor para aplicar a mudança. + +Os parâmetros de ajuste acima não são configurados por padrão; exponha as variáveis de ambiente correspondentes no container do servidor no seu manifest de Deployment caso precise substituir os valores padrão. + +Consulte [deployment.md](/pt-br/agenteye/deployment) para a tabela completa de variáveis de ambiente. + +--- + +## Referência da API + +| Método | Caminho | Permissão necessária | Finalidade | +|---|---|---|---| +| `GET` | `/evaluations` | `evaluations:read` | Consulta resultados terminais. Suporta `session_id`, `agent_id`, `environment`, `status` (`done`/`error`/`timeout`), `ts_from`, `ts_to`, `cursor`, `limit`, `score_filters`, `latest_per_session`. `limit` tem padrão 50 e máximo 200 (diferente de `/events`, que tem máximo 1000). `environment` aceita uma lista separada por vírgulas (ex.: `environment=prod,staging`); valores únicos ainda funcionam. Com `latest_per_session=true`, a resposta contém no máximo uma linha por `session_id` (a mais recente por `completed_at`), usada pela página de listagem de sessões para colapsar a linha do tempo de avaliações de uma sessão ao seu destaque atual. Padrão é false (retorna o histórico completo). | +| `GET` | `/evaluations/aggregate` | `evaluations:read` | Métricas agregadas de saúde de avaliação para uma fatia filtrada: contagem total, distribuição done/error/timeout, estatísticas por chave de pontuação (count/avg/min/max/p50 sobre as chaves arbitrárias de `scores`), e uma linha do tempo por intervalos de tempo. Aceita os **mesmos parâmetros de filtro que `/evaluations`** mais `featured_keys` (CSV de chaves de pontuação para tendência) e `latest_per_session`. Alimenta a funcionalidade de Dashboards; as métricas são exatas sobre todo o conjunto correspondente, sem amostragem. | +| `GET` | `/evaluations/environments` | `evaluations:read` | Valores distintos de environment da tabela `evaluations`. Usado para preencher dropdowns de filtro com escopo para dados legíveis por avaliações. | +| `GET` | `/evaluation-jobs` | `evaluations:read` | Visibilidade sobre avaliações em andamento. Filtre por `status` (`pending`/`polling`). | +| `GET` | `/events` | `events:read` | Transmite os eventos brutos de uma sessão. Suporta `session_id`, `agent_id`, `event_type` (CSV), `environment` (CSV), `ts_from`, `ts_to`, `cursor`, `limit` e `order`. `order` é `desc` (mais recente primeiro, padrão) ou `asc` (mais antigo primeiro); um valor não reconhecido usa `desc` como fallback. Pagine via cursor usando o `next_cursor` da resposta (um id de evento): passe-o de volta como `cursor` para obter a próxima página; com `asc` a próxima página são os eventos após esse id, com `desc` os eventos antes dele. `limit` tem padrão 50 e máximo 1000. | +| `GET` | `/sessions/:session_id/export` | `events:read` | Retorna exatamente o body JSON que o avaliador receberia para esta sessão, servido como um anexo para download chamado `session-.json`. Útil para reproduzir sessões de produção através do `agenteye-evaluator` para testes offline. Os bytes são idênticos ao que o pipeline do avaliador envia. | +| `POST` | `/sessions/:session_id/re-evaluate` | `evaluations:trigger` | Enfileira uma nova avaliação para uma sessão; executa independentemente de existir uma avaliação anterior. O novo resultado é **adicionado** à linha do tempo de avaliações da sessão em vez de sobrescrever o anterior, então as pontuações anteriores permanecem visíveis como histórico. Retorna `202` ao enfileirar, `404` para sessão desconhecida, `409` se já houver uma avaliação em andamento. Use isso após implantar um novo avaliador, ou para sessões que nunca emitiram `agent_end`. | + +### Filtrando por intervalo de pontuação: `score_filters` + +`GET /evaluations` aceita um parâmetro opcional `score_filters` que +restringe os resultados por valores numéricos dentro do objeto `scores`. O +parâmetro é uma lista separada por vírgulas de entradas `key:min..max`; qualquer +um dos limites pode ser omitido. Múltiplas entradas se combinam com AND lógico. Linhas +onde a chave nomeada está ausente ou não é numérica são excluídas. Uma requisição pode +conter no máximo 20 entradas de filtro; exceder isso retorna HTTP 400. + +Exemplos: +```text +# helpfulness em [0.5, 0.8] +GET /evaluations?score_filters=helpfulness:0.5..0.8 + +# tool_efficiency no máximo 0.3 (sem limite inferior) +GET /evaluations?score_filters=tool_efficiency:..0.3 + +# helpfulness >= 0.5 E factuality >= 0.9 +GET /evaluations?score_filters=helpfulness:0.5..,factuality:0.9.. +``` + +Cada objeto de resposta de `/evaluations` tem estes campos: + +| Campo | Tipo | Observações | +|---|---|---| +| `evaluation_id` | string (UUID) | O identificador canônico desta avaliação terminal. Cada avaliação terminal recebe um novo UUID; uma única sessão pode ter múltiplos. | +| `id` | string (UUID) | Alias de compatibilidade retroativa com o mesmo valor que `evaluation_id`. | +| `session_id` | string | A sessão contra a qual esta avaliação foi executada. Uma sessão pode ter múltiplas avaliações na linha do tempo. | +| `agent_id` | string | Identifica o agente que produziu a sessão. | +| `environment` | string | Rótulo de environment copiado da sessão. | +| `status` | enum | Um de `"done"`, `"error"`, `"timeout"`. | +| `scores` | object \| null | Pontuações retornadas pelo seu avaliador. | +| `reasoning` | object \| null | Mapa opcional de justificativa por pontuação retornado pelo seu avaliador. As chaves normalmente espelham as de `scores`. O dashboard renderiza cada entrada abaixo de sua barra de pontuação. | +| `summary` | string \| null | Narrativa geral opcional de um parágrafo retornada pelo seu avaliador. O dashboard a renderiza acima da distribuição por pontuação como o destaque da avaliação. | +| `error` | string \| null | Preenchido apenas em `"error"` / `"timeout"`. | +| `attempt_count` | integer | Número de tentativas de despacho (≥ 1). | +| `duration_ms` | integer \| null | Duração da tentativa final. | +| `completed_at` | string (ISO 8601 UTC) | Quando o resultado terminal foi registrado. Os resultados são ordenados por `completed_at` (mais recente primeiro). | +| `created_at` | string (ISO 8601 UTC) | Carrega o mesmo timestamp que `completed_at` (semântica de escrita única). | + +--- + +## Permissões + +| Permissão | Concede | +|---|---| +| `evaluations:read` | Listar resultados de avaliação, visualizar pontuações no dashboard e carregar métricas de saúde do dashboard. | +| `evaluations:trigger` | Enfileirar manualmente uma avaliação para uma sessão via `POST /sessions/:session_id/re-evaluate` ou o botão de re-avaliar no dashboard. | +| `dashboards:read` | Visualizar dashboards salvos (também precisa de `evaluations:read` para carregar suas métricas). | +| `dashboards:write` | Criar e editar dashboards. | +| `dashboards:delete` | Excluir dashboards. | + +O admin bootstrap (`ADMIN_KEY`, `ADMIN_EMAIL`) recebe essas permissões automaticamente. + +--- + +## Visualizando resultados + +- **`/sessions/`**: linha do tempo de eventos + um painel lateral direito mostrando as + pontuações da sessão e qualquer erro da tentativa de despacho. Se sua chave tem + `evaluations:trigger`, um botão de **re-avaliar** aparece ao lado do botão de exportar, + útil para sessões que nunca emitiram `agent_end`, ou para + atualizar pontuações após implantar um novo avaliador. O dashboard faz polling pelo + novo resultado e atualiza o painel lateral quando ele chegar. +- **`/sessions`**: grade de sessões filtrável; a coluna de pontuação mostra o + status de avaliação e as pontuações de cada sessão rapidamente. +- **`/dashboards`**: visualizações salvas de saúde de avaliação (veja [Dashboards](#dashboards) abaixo). + +![Grade de sessões com pílulas de status de avaliação por sessão e emblemas de pontuação com código de cores (helpfulness, factuality, tool_efficiency, safety, coherence)](/agenteye/images/sessions-list.png) + +*A grade de sessões mostra o status de avaliação e as pontuações de cada execução rapidamente; emblemas vermelhos/âmbar/verdes destacam pontuações baixas.* + +![Visualização de detalhes de uma sessão com as pontuações de avaliação e o status de despacho no painel lateral direito](/agenteye/images/session-detail.png) + +*Abrir uma sessão mostra sua linha do tempo completa ao lado das pontuações de avaliação e qualquer erro do dispatcher no painel lateral direito.* + +--- + +## Dashboards + +A página **Dashboards** (`/dashboards`) permite salvar uma combinação de filtros de avaliação +como uma visualização nomeada e reutilizável, e acompanhar como aquela fatia de avaliações está +se saindo rapidamente. Os Dashboards são **compartilhados por toda a sua organização**; +todos com `dashboards:read` veem o mesmo conjunto. + +Cada dashboard fixa: + +- **Filtros**: os mesmos controles da página de sessões: environment, status, + agente, uma janela de tempo contínua e filtros de intervalo de pontuação (`key:min..max`). +- **Uma configuração de exibição**: quais chaves de pontuação destacar, os limites de saúde + verde/âmbar/vermelho, quais painéis mostrar e se colapsar para a avaliação mais recente + por sessão. + +Cada card mostra o número de sessões correspondentes, uma distribuição done/error/timeout, +a média de cada pontuação destacada e um pequeno sparkline de tendência. Abrir um +dashboard mostra os painéis em tamanho completo; **"abrir em sessões"** leva você à +página de sessões pré-filtrada exatamente para aquela fatia. As métricas são calculadas +no lado do servidor sobre todo o conjunto correspondente (via `GET /evaluations/aggregate`), então +os números são exatos em vez de amostrados. + +![Dashboard de saúde de avaliação com barras de pontuação média por dimensão do avaliador, distribuição ok vs. erro de ferramentas, principais ferramentas e tendência de eventos por hora](/agenteye/images/dashboard-quality.png) + +**Permissões:** visualizar requer tanto `dashboards:read` quanto `evaluations:read`; +criar e editar requer `dashboards:write`; excluir requer `dashboards:delete`. +O admin bootstrap recebe todas essas permissões automaticamente. + +--- + +## Solução de problemas + +**Sessões existem mas nenhuma avaliação é criada.** Confirme que `EVALUATOR_ENDPOINT` +está definido no processo do servidor, que o servidor e o avaliador compartilham o mesmo +valor de `EVALUATOR_TOKEN`, e que o endpoint `/health` do avaliador é +acessível a partir do servidor. Com `EVALUATOR_ENDPOINT` não definido, o pipeline é inativo. + +**Avaliações em andamento se acumulam.** Consulte `GET /evaluation-jobs` para ver a +fila em andamento. Inspecione `attempt_count`, `next_attempt_at` e `last_error` +em cada linha. Causas comuns: serviço avaliador inacessível ou retornando 5xx +(repetido com backoff), `EVALUATOR_TOKEN` incorreto (401 é terminal), ou um +avaliador assíncrono que retorna `pending` indefinidamente (veja abaixo). + +**Sessões concluídas mas sem avaliação terminal.** Consulte +`GET /evaluation-jobs?status=polling`; o resultado pode ainda estar em andamento. +Se um job está preso em `pending`, o servidor está tendo dificuldade em acessar o +avaliador; verifique se o avaliador está em funcionamento e se `EVALUATOR_TOKEN` corresponde. + +**`HTTP 401 from evaluator: invalid bearer token`.** O `EVALUATOR_TOKEN` +no servidor não corresponde ao valor com que o serviço avaliador está configurado. +Eles devem ser idênticos. + +**Avaliador assíncrono retorna `pending` indefinidamente.** O servidor faz polling em +`GET /evaluate/{job_id}` até que o avaliador retorne `done` ou `error`, ou +até que `EVALUATOR_MAX_POLL_DURATION_SECS` (padrão: 1h) seja atingido. Após o limite, +a avaliação é registrada como `timeout` e removida da fila em andamento. +Aumente `EVALUATOR_MAX_POLL_DURATION_SECS` se o seu avaliador legitimamente precisar +de mais tempo que o padrão. \ No newline at end of file diff --git a/docs/pt-br/agenteye/getting-started.mdx b/docs/pt-br/agenteye/getting-started.mdx new file mode 100644 index 00000000..1e3799a1 --- /dev/null +++ b/docs/pt-br/agenteye/getting-started.mdx @@ -0,0 +1,234 @@ +--- +title: "Primeiros Passos com AgentEye" +description: "Documentação de Primeiros Passos com AgentEye." +--- + +Este guia apresenta uma configuração completa do AgentEye: implantação do servidor e do dashboard, instalação do coletor em uma máquina de agente e instrumentação do seu código Python de agente. + +--- + +## O que é o AgentEye? + +O AgentEye é uma **plataforma de observabilidade e avaliação self-hosted para agentes de IA**. Ele registra tudo o que seus agentes fazem — cada etapa de uma execução — e pontua automaticamente a qualidade de cada execução concluída, para que você possa acompanhar o comportamento dos seus agentes em produção e identificar regressões antes que seus usuários percebam. + +Os dados fluem em uma única direção: seu código de agente emite **eventos** via **Python SDK** → um daemon **coletor** leve os agrupa e envia para o **servidor** → eventos e análises são armazenados no **ClickHouse** (estado operacional como organizações, usuários, chaves de API, dashboards e queries salvas fica no **Postgres**) → você explora tudo no **dashboard**. + +O que você obtém: + +- **Eventos** — o rastro bruto, passo a passo, de cada execução de agente (chamadas de ferramentas, chamadas de modelo, hooks, erros). +- **Sessões** — esses eventos consolidados em uma linha por execução, cada uma **avaliada e pontuada automaticamente**. +- **Avaliações** — pontuações de qualidade produzidas pelos seus próprios serviços de avaliação, para que quedas de qualidade apareçam sem revisão manual. +- **Queries e dashboards** — SQL ClickHouse salvo sobre seus dados, visualizado em dashboards compartilhados com escopo por organização. +- **Alertas e incidentes** — regras de limite que notificam você (e-mail, Slack, webhook, in-dashboard) além de um fluxo de trabalho de incidentes para triagem. +- **CLI e assistente de IA** — um cliente de terminal (`agenteye`) e um assistente integrado ao dashboard para fazer perguntas em linguagem natural. + +Você executa tudo na sua própria infraestrutura, como uma stack Docker Compose (este guia), uma instalação Kubernetes para produção ou um único pod co-localizado. O restante deste guia configura a stack Compose do início ao fim. + +--- + +## Passo 1: Autenticar + +Todos os artefatos do AgentEye são distribuídos pela organização GitHub `agenteye-enterprise`. Como desenvolvedor enterprise, você pode gerar seu próprio GitHub PAT. Siga [enterprise-docs/github-token.md](/pt-br/agenteye/github-token) para os passos exatos e as permissões necessárias. + +```bash +export AGENTEYE_TOKEN= + +# Authenticate Docker against GHCR +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +--- + +## Passo 2: Implantar o Servidor e o Dashboard + +O servidor recebe eventos dos coletores e os torna consultáveis; o dashboard é onde você os explora. Eventos ingeridos e análises ficam no ClickHouse (o armazenamento de análises obrigatório), enquanto o Postgres mantém o estado operacional como organizações, usuários, chaves de API, dashboards e queries salvas. + +**Baixe o arquivo compose publicado:** + +```bash +mkdir -p ./agenteye +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + https://raw.githubusercontent.com/agenteye-enterprise/releases/main/docker-compose.yml \ + -o ./agenteye/docker-compose.yml +cd agenteye +``` + +**Configure seus segredos:** + +Crie um arquivo `.env` para que a implantação não use a credencial padrão `admin`. No mínimo, defina `ADMIN_KEY` e `POSTGRES_PASSWORD`: + +```bash +POSTGRES_PASSWORD=your-db-password +ADMIN_KEY=your-admin-secret +``` + +Também exporte `ADMIN_KEY` no seu shell atual para que os passos seguintes (por exemplo, o `curl` do Passo 3) possam referenciá-lo diretamente: + +```bash +export ADMIN_KEY=your-admin-secret +``` + +**Inicie a stack:** + +```bash +docker compose up -d +``` + +Isso sobe a stack completa, incluindo o armazenamento de análises ClickHouse obrigatório e um cache Redis opcional, juntamente com o servidor e o dashboard. O ClickHouse precisa estar saudável para o servidor iniciar. + +O servidor agora está ouvindo em `http://localhost:8080` e o dashboard em `http://localhost:3000`. + +Para implantações em produção (Postgres personalizado, TLS, proxy reverso), consulte [enterprise-docs/deployment.md](/pt-br/agenteye/deployment). + +--- + +## Passo 3: Criar uma Chave de API para o Coletor + +Cada coletor se autentica com uma chave de API com escopo definido. Use o `ADMIN_KEY` que você definiu no Passo 2 para criar uma: + +```bash +curl -s -X POST http://localhost:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{"name":"prod-collector","key":"your-collector-secret","permissions":["events:add"]}' +``` + +Você define o valor de `key` você mesmo; use-o na configuração do coletor no Passo 4. Consulte [enterprise-docs/api-keys.md](/pt-br/agenteye/api-keys) para o gerenciamento completo de chaves. + +--- + +## Passo 4: Instalar o Coletor + +Em cada máquina que executa seus agentes de IA, instale o daemon coletor. + +**Baixe o binário (Linux x86_64):** + +```bash +VERSION=0.0.1-beta.13 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "collector/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-collector-linux-x86_64' +chmod +x agenteye-collector-linux-x86_64 +sudo mv agenteye-collector-linux-x86_64 /usr/local/bin/agenteye-collector +``` + +> Isso baixa o build **Linux x86_64**. Para macOS (Apple Silicon ou Intel), Linux arm64, ou configuração via Docker / systemd / launchd, consulte [collector-installation.md](/pt-br/agenteye/collector-installation), que lista o download para cada plataforma — o comando acima instala um binário Linux que não funcionará em outros sistemas operacionais. + +**Configure:** + +```bash +mkdir -p ~/.agenteye +cat > ~/.agenteye/config.json </…`). + +- **Queries** (`//queries`): comece a partir de uma biblioteca de queries reutilizáveis salvas sobre seus eventos e avaliações (predefinições integradas mais as suas próprias)… + +![A biblioteca de queries salvas: uma grade de queries reutilizáveis, tanto predefinições integradas quanto personalizadas](/agenteye/images/queries.png) + + …depois abra uma no compositor SQL para ajustá-la e executá-la com resultados em tempo real: + +![O compositor de queries SQL executando uma query salva, com uma barra lateral de esquema e uma grade de resultados em tempo real](/agenteye/images/query-lab.png) + +- **Dashboards** (`//dashboards`): fixe queries como tiles de linha, barra, área ou pizza em dashboards compartilhados por toda a organização. + +![Um dashboard construído a partir de queries salvas: uma linha de eventos por hora, um gráfico de barras de erros por tipo, um gráfico de área de latência e tokens por modelo](/agenteye/images/dashboard-fleet.png) + +- **Alertas** (`//alerts`): transforme qualquer limite em uma regra de notificação que avisa por e-mail, Slack, webhook ou in-dashboard. Consulte [enterprise-docs/alerts.md](/pt-br/agenteye/alerts). + +--- + +## Próximos Passos + +- [Implantação](/pt-br/agenteye/deployment): fortaleça para produção +- [Chaves de API](/pt-br/agenteye/api-keys): gerencie o acesso +- [Solução de Problemas](/pt-br/agenteye/troubleshooting): diagnostique problemas \ No newline at end of file diff --git a/docs/pt-br/agenteye/github-token.mdx b/docs/pt-br/agenteye/github-token.mdx new file mode 100644 index 00000000..b64049f8 --- /dev/null +++ b/docs/pt-br/agenteye/github-token.mdx @@ -0,0 +1,131 @@ +--- +title: "Configuração do Token GitHub" +description: "Documentação de configuração do Token GitHub do AgentEye." +--- + +Um GitHub Personal Access Token (PAT) é a única credencial necessária para acessar todos os artefatos do AgentEye. Com um único token, você pode baixar imagens Docker, fazer download de binários de versão e instalar os pacotes Python — sem necessidade de logins separados por componente e sem segredos compartilhados circulando pela equipe. Todos os artefatos do AgentEye são distribuídos pela organização `agenteye-enterprise` no GitHub; assim que sua organização receber acesso, cada desenvolvedor ou operador gera e rotaciona seu próprio token, mantendo o acesso auditável e revogável por pessoa. + +Defina o token como variável de ambiente e credencial Docker uma vez por máquina: + +```bash +export AGENTEYE_TOKEN= +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +> **Observação sobre o nome de usuário:** O GHCR ignora o nome de usuário informado no `docker login` e autentica exclusivamente pelo token, portanto qualquer valor não vazio funciona. Esta documentação usa `-u x` por brevidade; manifestos de implantação que criam um secret de pull de imagem no Kubernetes podem usar um nome de usuário mais descritivo, como `agenteye-enterprise`. Ambas as opções são aceitas. + +--- + +## Opção A: Token Clássico (Recomendado) + +Um token clássico é a escolha mais confiável para o AgentEye, pois o fluxo de `docker login` e pull de imagens do GHCR apresenta suporte mais amplo e consistente para tokens clássicos. Dois escopos cobrem tudo o que você precisa (baixar imagens e fazer download de assets de versão), permitindo que você se autentique uma vez e siga em frente sem precisar depurar quirks do registry. Um deles, `read:packages`, é genuinamente somente leitura; o outro, `repo`, é o único escopo clássico que concede acesso a assets de versão privados — e é deliberadamente amplo: o GitHub o define como controle total (leitura e escrita) de repositórios privados. + +### 1. Crie o token + +Acesse **GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic) → Generate new token (classic)**. + +| Campo | Valor | +|---|---| +| **Note** | `agenteye-` (ex.: `agenteye-prod-server`) | +| **Expiration** | Defina uma expiração adequada à sua política de segurança; 90 dias é um padrão razoável | + +> **Observação sobre o campo de nome:** O GitHub rotula esse campo como **Note** para tokens clássicos e **Token name** para tokens refinados. Ambos servem ao mesmo propósito: um identificador legível por humanos para auditoria e revogação posteriores. + +### 2. Selecione os escopos + +| Escopo | Por que é necessário | +|---|---| +| `read:packages` | Baixar imagens Docker de `ghcr.io/agenteye-enterprise/` e fazer download de assets de pacote | +| `repo` | Ler conteúdos de repositório privado, arquivos brutos e assets de versão de `agenteye-enterprise/releases`. Este é o escopo amplo do GitHub de "Controle total de repositórios privados" (leitura e escrita), não um escopo somente leitura — é simplesmente o único escopo clássico que concede acesso a assets de versão privados | + +Nenhum outro escopo é necessário. + +### 3. Gere e copie o token + +Clique em **Generate token** e copie o valor imediatamente; ele é exibido apenas uma vez. Armazene-o no seu gerenciador de segredos ou variável de ambiente. + +--- + +## Opção B: Token Refinado (Fine-Grained) + +Tokens refinados limitam o acesso a repositórios e permissões específicos, tornando-os a opção mais restritiva e com menor privilégio. Escolha este caminho quando a política de segurança da sua organização exigir tokens refinados. + +> **Observação:** O suporte do GHCR a tokens refinados é menos consistente do que para tokens clássicos. Se `docker login` ou `docker pull` falhar após seguir estas etapas, recorra a um token clássico (Opção A). + +### 1. Crie o token + +Acesse **GitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokens → Generate new token**. + +| Campo | Valor | +|---|---| +| **Token name** | `agenteye-` (ex.: `agenteye-prod-server`) | +| **Expiration** | Defina uma expiração adequada à sua política de segurança; 90 dias é um padrão razoável | +| **Resource owner** | `agenteye-enterprise` | +| **Repository access** | **Only select repositories** → `agenteye-enterprise/releases` | + +### 2. Defina as permissões do repositório + +Em **Permissions → Repository permissions**, configure: + +| Permissão | Acesso | +|---|---| +| **Contents** | Read-only | +| **Packages** | Read-only | + +Todas as demais permissões podem permanecer como **No access**. + +> **Observação:** Se as imagens de contêiner (`ghcr.io/agenteye-enterprise/...`) forem publicadas como pacotes em nível de organização, e não como pacotes vinculados a repositório, o login Docker poderá falhar apenas com permissões de escopo de repositório. Nesse caso, adicione uma permissão em nível de organização: **Permissions → Organization permissions → Packages: Read-only**. + +### 3. O que cada permissão concede + +| Permissão | Utilizada para | +|---|---| +| Contents: Read-only | Download de `docker-compose.yml`, binários de versão e pacotes Python de `agenteye-enterprise/releases` | +| Packages: Read-only | Pull de imagens Docker de `ghcr.io/agenteye-enterprise/` | + +### 4. Gere e copie o token + +Clique em **Generate token** e copie o valor imediatamente; ele é exibido apenas uma vez. Armazene-o no seu gerenciador de segredos ou variável de ambiente. + +--- + +## Rotação de Token + +Rotacionar tokens periodicamente mantém o acesso auditável e limita o raio de impacto caso uma credencial vaze. Tokens também podem expirar ou ser revogados a qualquer momento, portanto a rotação é a forma habitual de se manter autenticado. Para rotacionar: + +1. Gere um novo token seguindo as etapas acima. +2. Atualize `AGENTEYE_TOKEN` no seu ambiente ou gerenciador de segredos. +3. Reautentique o Docker: `echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin` +4. Revogue o token antigo em GitHub → Settings → Developer settings → Personal access tokens, abrindo a subpágina **Tokens (classic)** ou **Fine-grained tokens** correspondente ao tipo do token, e o exclua. + +--- + +## Verifique Seu Token + +Confirme que o token funciona antes de integrá-lo a uma implantação, para que falhas de autenticação apareçam aqui em vez de no meio de um rollout. Cada comando exercita um dos escopos acima: + +```bash +# Escopo de Packages - autentica o Docker no GHCR +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin + +# Escopo de Contents - obtém um arquivo bruto de versão +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + https://raw.githubusercontent.com/agenteye-enterprise/releases/main/docker-compose.yml \ + -o /tmp/agenteye-compose-check.yml +``` + +Um `docker login` bem-sucedido confirma o escopo de pacotes; um arquivo baixado confirma o escopo de conteúdos. + +--- + +## Solução de Problemas + +| Sintoma | Causa provável | Solução | +|---|---|---| +| `docker login` retorna 401 | Token sem `Packages: Read-only` (refinado) ou `read:packages` (clássico) | Adicione o escopo de pacotes e regenere o token | +| `curl` retorna 404 em URLs brutas do GitHub | Token sem `Contents: Read-only` ou escopo `repo` | Adicione o escopo de conteúdos e regenere o token | +| `gh release download` retorna 403 | Token não autorizado para `agenteye-enterprise/releases` | Verifique se o repositório está incluído no acesso de repositórios do token refinado, ou use um token clássico com escopo `repo` | +| Token aceito, mas imagens não encontradas | Permissão de pacote em nível de organização ausente no token refinado | Adicione a permissão `Packages: Read-only` em nível de organização | + +Para problemas de acesso, entre em contato com `support@exosphere.host`. \ No newline at end of file diff --git a/docs/pt-br/agenteye/health-monitoring.mdx b/docs/pt-br/agenteye/health-monitoring.mdx new file mode 100644 index 00000000..7a732746 --- /dev/null +++ b/docs/pt-br/agenteye/health-monitoring.mdx @@ -0,0 +1,134 @@ +--- +title: "Monitoramento de Saúde" +description: "Documentação de Monitoramento de Saúde do AgentEye." +--- + +Saiba quando um deployment do AgentEye está **ele próprio** fora do ar ou +degradado — não apenas quando seus agentes se comportam mal. A detecção é +**nativa do Kubernetes** e, crucialmente, **independente do AgentEye**: ela lê o +estado dos pods a partir do plano de controle do Kubernetes e verifica as +dependências críticas do AgentEye, então continua disparando alertas mesmo +quando o servidor, o ClickHouse ou o Postgres é o que está fora do ar. + +Existem duas camadas. A primeira é integrada; a segunda é opcional. + +## 1. Readiness com consciência de dependências (integrado) + +O servidor expõe dois endpoints de probe com responsabilidades deliberadamente +distintas: + +| Endpoint | Probe | Verificações | Autenticação | +|---|---|---|---| +| `GET /health` | liveness | processo está vivo (sempre `{"status":"ok"}`) | nenhuma | +| `GET /ready` | readiness | consegue servir de verdade: **Postgres + ClickHouse** acessíveis | nenhuma | + +`/ready` retorna `200` com `"status":"ready"` e todas as verificações com `"ok"` +quando ambas as dependências críticas estão acessíveis, e `503` com +`"status":"not_ready"` quando uma delas está inacessível. Ambas as respostas +carregam um corpo pequeno: + +```json +{ "status": "not_ready", + "checks": { "postgres": "ok", "clickhouse": "down", "redis": "not_configured" } } +``` + +O Redis é um cache opcional pelo qual o servidor opera em modo degradado, por +isso é reportado apenas para informação, mas **nunca** falha o readiness. Ele +aparece como `"ok"` quando um cache está configurado e `"not_configured"` caso +contrário; jamais aparece como `"down"`. + +Nos manifestos Kubernetes incluídos no pacote, o probe de **readiness** aponta +para `/ready` e o de **liveness** permanece em `/health`. O efeito: um servidor +que está *rodando mas não consegue alcançar seu banco de dados* é removido do +Service e aparece como `NotReady` — um estado que o monitoramento do seu cluster +(abaixo) pode alertar — enquanto o liveness permanece leve para que uma +instabilidade momentânea de dependência nunca dispare o reinício do pod. O probe +usa um limiar de falha generoso para que uma instabilidade momentânea não faça +as réplicas entrarem e saírem da rotação. + +## 2. Alertas de falha de pod com Robusta (opcional) + +[Robusta](https://github.com/robusta-dev/robusta) é um monitor nativo do +Kubernetes que observa o servidor de API e envia falhas de pod +(`CrashLoopBackOff`, `OOMKilled`, `ImagePullBackOff`, `Pending`/`NotReady`, +`Failed`, despejos) para o Slack. Por observar o plano de controle em vez de +consultar o AgentEye, ele alerta mesmo quando o AgentEye não consegue servir +nenhuma requisição. + +O Robusta vem como um complemento opcional no pacote de lançamento. Habilite-o +com o Helm chart padrão do Robusta e o pequeno arquivo de values mostrado abaixo: + +1. Adicione o repositório do chart e obtenha um **bot token** do Slack + (`xoxb-…`) para o canal: + + ```bash + helm repo add robusta https://robusta-charts.storage.googleapis.com + helm repo update + ``` + + Como a configuração abaixo mantém tudo dentro do cluster + (`disableCloudRouting: true`), o token vem de um aplicativo Slack + auto-hospedado: crie um app em `https://api.slack.com/apps`, adicione o + escopo de bot `chat:write`, instale-o no seu workspace, copie o **Bot User + OAuth Token** (`xoxb-…`) e convide o bot para o canal (`/invite @seu-app`). + +2. Crie um `values.yaml` com um label por deployment (`clusterName`) e seu + canal do Slack, com escopo para o namespace `agenteye`: + + ```yaml + clusterName: "acme-prod" # label por deployment; aparece em cada alerta + enablePrometheusStack: false # apenas alertas de crash de pod; sem stack de métricas + disableCloudRouting: true # entrega diretamente ao Slack, dentro do cluster + sinksConfig: + - slack_sink: + name: vendor_slack + slack_channel: "agenteye-fleet-health" + api_key: "REPLACE_WITH_SLACK_BOT_TOKEN" # xoxb-… (prefira --set ou um secret) + scope: + include: + - namespace: [agenteye] # apenas alertas do namespace AgentEye; remova para ampliar + ``` + +3. Instale fixando `--version` em uma versão conhecida e estável do chart do + Robusta ([releases](https://github.com/robusta-dev/robusta/releases)) para + nunca instalar um chart não testado: + + ```bash + helm install robusta robusta/robusta \ + --namespace robusta --create-namespace \ + --version \ + -f values.yaml \ + --set sinksConfig[0].slack_sink.api_key=$ROBUSTA_SLACK_TOKEN + ``` + +### O que é reportado + +- **Estado dos pods** do Kubernetes (qual pod do AgentEye está falhando e por + quê) e a **tag de imagem** de cada pod, ou seja, a **versão** do componente + em execução. +- **Nenhum dado de eventos do AgentEye e nenhum dado de cliente** jamais sai + do cluster. +- Os values incluídos restringem os alertas ao **namespace `agenteye`**, de + forma que workloads não relacionadas no mesmo cluster não sejam reportadas. + +### Um único lugar para cada deployment + +Aponte o Robusta de cada deployment para **um canal Slack compartilhado**, cada +um com seu próprio `clusterName`. Cada alerta é marcado com esse label, de modo +que um único canal exibe a saúde de toda a sua frota e você consegue identificar +qual deployment foi afetado de relance. + +### Interrupções totais do cluster + +Um watcher puramente dentro do cluster não consegue reportar uma **interrupção +total do cluster ou da rede** (ele cai junto com o cluster). Se você precisar +disso, habilite o **sink da UI do Robusta** opcional: defina +`disableCloudRouting: false` e adicione um `robusta_sink` (com um token gerado +por `robusta gen-config`) ao `sinksConfig`. Ele adiciona um dashboard +multi-cluster agregado e sinaliza qualquer cluster que pare de fazer check-in. + +## Solução de Problemas + +Consulte a seção **Health Monitoring** em +[enterprise-docs/troubleshooting.md](/pt-br/agenteye/troubleshooting) para os casos +"nenhum alerta chegando" e "servidor continua alternando para `NotReady`". \ No newline at end of file diff --git a/docs/pt-br/agenteye/kubernetes-deployment.mdx b/docs/pt-br/agenteye/kubernetes-deployment.mdx new file mode 100644 index 00000000..17efc531 --- /dev/null +++ b/docs/pt-br/agenteye/kubernetes-deployment.mdx @@ -0,0 +1,1100 @@ +--- +title: "Guia de Deploy no Kubernetes" +description: "Documentação do Guia de Deploy no Kubernetes do AgentEye." +--- + + +Este guia realiza o deploy completo do stack do AgentEye em um cluster Kubernetes dedicado: + +- **ClickHouse 24.8** -- armazenamento canônico de eventos e análises de avaliações (StatefulSet com volume persistente de 100Gi). Obrigatório: o servidor se recusa a iniciar sem ele. +- **PostgreSQL 16** -- armazenamento relacional/de metadados para organizações, chaves de API, usuários, dashboards, consultas salvas e autenticação (StatefulSet com volume persistente de 50Gi) +- **Redis 7.2** -- cache compartilhado e backend de rate-limit opcionais; o servidor e o dashboard degradam de forma elegante se estiver indisponível +- **AgentEye Server** -- API em Rust para ingestão de eventos, analytics e gerenciamento de chaves (2 réplicas) +- **AgentEye Dashboard** -- UI web em Next.js (2 réplicas) +- **AI assistant (serviço agent)** -- assistente opcional somente leitura no dashboard, na porta 9100; inativo até que um endpoint LLM seja configurado +- **Traefik (público)** -- controlador de ingress para tráfego do coletor, protegido com mTLS +- **Traefik (dashboard)** -- controlador de ingress para o dashboard, restrito a VPN/lista de IPs permitidos +- **cert-manager** -- certificados TLS e CA para mTLS +- **Backup CronJob** -- dump combinado diário de PostgreSQL + ClickHouse às 03:00 UTC +- **Cert Renewal Monitor** -- alertas quando certificados de cliente estão próximos do vencimento + +**Tempo estimado:** 60--90 minutos para um primeiro deploy. + +Para o modelo de deploy gerenciado, onde a Exosphere cuida de tudo isso em seu nome, consulte [enterprise-docs/managed-deployment.md](/pt-br/agenteye/managed-deployment). + +--- + +## Pré-requisitos + +Execute cada comando de verificação antes de começar. Todas as verificações devem passar. + +| Requisito | Mínimo | Comando de Verificação | Esperado | +|---|---|---|---| +| Cluster Kubernetes | 1.27+ | `kubectl version` | Server Version >= v1.27 | +| Kustomize (incluído no kubectl) | Kustomize v1.14+ (incluso no kubectl 1.27+) | `kubectl kustomize --help` | Exibe texto de uso | +| Helm | v3 | `helm version` | `Version:"v3.x.x"` | +| RBAC cluster-admin | -- | `kubectl auth can-i create namespaces` | `yes` | +| StorageClass padrão | -- | `kubectl get storageclass` | Pelo menos uma linha marcada como `(default)` | +| Suporte a LoadBalancer | -- | Dependente do cloud (EKS, GKE, AKS oferecem suporte por padrão) | -- | +| GitHub PAT | -- | `echo $AGENTEYE_TOKEN` | Não vazio (consulte [enterprise-docs/github-token.md](/pt-br/agenteye/github-token)) | +| openssl | -- | `openssl version` | OpenSSL 1.x ou 3.x | +| Bucket de armazenamento em nuvem | -- | Para backups de PostgreSQL + ClickHouse (S3, GCS ou Azure Blob) | -- | + +**Dimensionamento do cluster:** Mínimo de 3 nós, 4 vCPU / 8 GB RAM cada. Consulte [enterprise-docs/managed-deployment.md](/pt-br/agenteye/managed-deployment) para os requisitos completos. + +### Executar todas as verificações de uma vez + +```bash +echo "--- Prerequisites Check ---" +kubectl version --client -o yaml 2>/dev/null | grep -q gitVersion && echo "PASS: kubectl" || echo "FAIL: kubectl not found" +helm version --short 2>/dev/null | grep -q v3 && echo "PASS: helm v3" || echo "FAIL: helm v3 not found" +kubectl auth can-i create namespaces 2>/dev/null | grep -q yes && echo "PASS: cluster-admin" || echo "FAIL: no cluster-admin" +kubectl get storageclass 2>/dev/null | grep -q default && echo "PASS: default StorageClass" || echo "FAIL: no default StorageClass" +[ -n "$AGENTEYE_TOKEN" ] && echo "PASS: AGENTEYE_TOKEN set" || echo "FAIL: AGENTEYE_TOKEN not set" +openssl version >/dev/null 2>&1 && echo "PASS: openssl" || echo "FAIL: openssl not found" +echo "---" +``` + +### Formato do deploy + +O **endpoint de ingestão** é servido em um hostname que você controla (ex.: `ingest.sua-empresa.example`). O cert-manager solicita um certificado TLS publicamente confiável da Let's Encrypt via HTTP-01, de modo que os coletores verificam o certificado do servidor em relação ao repositório de confiança do sistema, sem fixação de CA por cliente. + +O **endpoint do dashboard** funciona da mesma forma: é servido em um segundo hostname que você controla (ex.: `agenteye.sua-empresa.example`), apontando para o LoadBalancer do Traefik do dashboard, e o cert-manager emite o certificado Let's Encrypt por meio desse LoadBalancer. Os navegadores recebem um certificado confiável sem avisos. + +> **A emissão e renovação de certificados são validadas via HTTP-01**, portanto ambos os LoadBalancers devem estar acessíveis pela internet pública na porta 80. Se você precisar restringir o LoadBalancer do dashboard por IP, coordene previamente um solver DNS-01 com o suporte — caso contrário, as renovações falham silenciosamente e o certificado expira. + +--- + +## Obter os Manifestos + +```bash +git clone https://x:${AGENTEYE_TOKEN}@github.com/agenteye-enterprise/releases.git +cd releases/deploy +``` + +**Teste:** + +```bash +ls base/kustomization.yaml +``` + +Esperado: o arquivo existe. Se não existir, o clone falhou — verifique seu `AGENTEYE_TOKEN`. + +**Estrutura de diretórios:** + +``` +deploy/ + base/ Base compartilhada do Kustomize (todos os recursos K8s) + overlays/ Overrides específicos do cluster (tags de imagem, hostnames, recursos) + third-party/ Valores Helm para Traefik, cert-manager e (opcional) monitoramento de saúde com Robusta +``` + +A **base** contém todos os recursos necessários para um deploy completo, incluindo os certificados Let's Encrypt para os dois hostnames públicos que você configura na Fase 3.1. Um **overlay** modifica a base para um ambiente específico (ex.: tags de imagem personalizadas, limites de recursos, configuração de variáveis de ambiente). O diretório **third-party** contém arquivos de valores Helm para infraestrutura externa. + +> **Monitoramento de saúde (opcional):** a probe de readiness do servidor já reflete a saúde do Postgres + ClickHouse, e `third-party/robusta/` adiciona alertas de falha de pod nativos do Kubernetes para o Slack, de forma opcional. Consulte [enterprise-docs/health-monitoring.md](/pt-br/agenteye/health-monitoring). + +--- + +## Fase 1 -- Infraestrutura de Terceiros (~30 min) + +### 1.1 Instalar o cert-manager + +O cert-manager gerencia os certificados TLS para HTTPS e a CA privada usada para certificados de cliente mTLS. + +```bash +helm repo add jetstack https://charts.jetstack.io +helm repo update + +helm install cert-manager jetstack/cert-manager \ + --namespace cert-manager --create-namespace \ + --set crds.install=true +``` + +**Teste:** + +```bash +kubectl get pods -n cert-manager +``` + +Esperado: 3 pods todos em `Running` -- `cert-manager`, `cert-manager-cainjector`, `cert-manager-webhook`. + +```bash +kubectl get crds | grep cert-manager +``` + +Esperado: pelo menos `certificates.cert-manager.io`, `clusterissuers.cert-manager.io`, `issuers.cert-manager.io`. + +**Se falhar:** Pods em `CrashLoopBackOff` geralmente indicam que os CRDs não foram instalados. Execute novamente com `--set crds.install=true`. Se os pods do webhook falharem na readiness, aguarde 30 segundos e verifique novamente — eles podem levar um momento para iniciar. + +--- + +### 1.2 Instalar o Traefik -- Controlador de Ingestão Público + +Esta instância do Traefik lida com o tráfego dos coletores em um LoadBalancer **externo**. Ela encerra o TLS e aplica o mTLS (verificação de certificado de cliente) no endpoint de ingestão. + +```bash +helm repo add traefik https://traefik.github.io/charts +helm repo update + +helm install traefik-public traefik/traefik \ + --namespace traefik-public --create-namespace \ + --version 39.0.8 \ + -f third-party/traefik/values-public.yaml +``` + +**Teste:** + +```bash +kubectl get pods -n traefik-public +``` + +Esperado: 1 pod em `Running`. + +```bash +kubectl get ingressclass traefik-public +``` + +Esperado: a IngressClass existe (não é a classe padrão). + +**Se falhar:** Verifique `kubectl describe pod -n traefik-public ` para erros de pull de imagem ou restrições de recursos. + +--- + +### 1.3 Instalar o Traefik -- Controlador do Dashboard + +Esta instância do Traefik serve o dashboard em um LoadBalancer dedicado, restrito por lista de IPs permitidos. + +> **Dois mecanismos de lista de permissões estão disponíveis para esta instância.** Este guia usa `values-dashboard.yaml`, que restringe o acesso com o campo portável `service.loadBalancerSourceRanges`. Um `values-internal.yaml` paralelo também é fornecido para ambientes AWS que preferem a anotação `service.beta.kubernetes.io/aws-load-balancer-source-ranges`. Escolha um e use-o de forma consistente; os passos abaixo assumem `values-dashboard.yaml`. + +**Antes de instalar**, edite `third-party/traefik/values-dashboard.yaml` para definir os IPs de origem permitidos. O campo `loadBalancerSourceRanges` controla quais IPs podem acessar o dashboard. Por padrão, está definido como `0.0.0.0/0` (todos os IPs); restrinja-o à sua VPN, escritório ou IPs de egresso conhecidos. + +#### Permitir um único IP + +```yaml +service: + loadBalancerSourceRanges: + - "/32" +``` + +#### Permitir múltiplos IPs + +Adicione uma entrada por IP ou bloco CIDR. O sufixo `/32` corresponde a um único endereço IPv4; um bloco CIDR (ex.: `/24`) corresponde a um intervalo. Você pode misturar IPs individuais e intervalos livremente: + +```yaml +service: + loadBalancerSourceRanges: + - "203.0.113.10/32" # gateway do escritório + - "203.0.113.11/32" # gateway de backup do escritório + - "198.51.100.0/24" # pool de VPN + - "192.0.2.50/32" # IP residencial do engenheiro de plantão +``` + +Dicas ao manter a lista: + +- Mantenha uma entrada por linha e adicione um comentário curto `#` identificando o proprietário ou a finalidade de cada IP; é isso que os operadores futuros usam para decidir se uma entrada ainda é necessária. +- Sempre use notação CIDR. Um IP sem sufixo como `203.0.113.10` é rejeitado pelo provedor de nuvem; use `203.0.113.10/32`. +- Para intervalos IPv6, use o equivalente `/128` (endereço único) ou CIDR maior, ex.: `2001:db8::1/128`. Nem todos os provedores de nuvem suportam intervalos de origem IPv6; consulte a documentação do LoadBalancer do seu provedor. +- A lista funciona como um **OR**: o tráfego é permitido se a origem corresponder a qualquer entrada. + +Após editar o arquivo, prossiga para o `helm install` abaixo. Se o controlador já estiver instalado, execute `helm upgrade` com os mesmos parâmetros ou faça um patch no Service em tempo de execução (próxima seção). + +#### Atualizar a lista de permissões em tempo de execução + +Você pode alterar os IPs permitidos sem um upgrade do Helm fazendo um patch diretamente no Service. **O patch substitui a lista inteira**; sempre inclua todos os IPs que deseja manter, não apenas o novo. + +Para substituir a lista por um novo conjunto de IPs: + +```bash +kubectl patch svc traefik-dashboard -n traefik-dashboard \ + -p '{"spec":{"loadBalancerSourceRanges":["203.0.113.10/32","198.51.100.0/24","192.0.2.50/32"]}}' +``` + +Para **adicionar** um IP com segurança sem perder as entradas existentes, leia a lista atual primeiro e depois faça o patch com o conjunto combinado: + +```bash +# 1. Exibir a lista de permissões atual +kubectl get svc traefik-dashboard -n traefik-dashboard \ + -o jsonpath='{.spec.loadBalancerSourceRanges}' + +# 2. Fazer o patch com a lista completa incluindo o novo IP +kubectl patch svc traefik-dashboard -n traefik-dashboard \ + -p '{"spec":{"loadBalancerSourceRanges":["/32","/32","/32"]}}' +``` + +> Patches em tempo de execução não são persistidos de volta em `values-dashboard.yaml`. Para manter a alteração em futuros upgrades do Helm, atualize também o arquivo de valores e faça o commit. + +Em seguida, instale: + +```bash +helm install traefik-dashboard traefik/traefik \ + --namespace traefik-dashboard --create-namespace \ + --version 39.0.8 \ + -f third-party/traefik/values-dashboard.yaml +``` + +**Teste:** + +```bash +kubectl get pods -n traefik-dashboard +``` + +Esperado: 1 pod em `Running`. + +```bash +kubectl get ingressclass traefik-dashboard +``` + +Esperado: a IngressClass existe. + +--- + +### 1.4 Aguardar os LoadBalancers + +Ambas as instâncias do Traefik precisam de IPs externos antes de prosseguir. + +```bash +kubectl get svc -n traefik-public +kubectl get svc -n traefik-dashboard +``` + +**Teste:** Ambos os serviços exibem um `EXTERNAL-IP` (não ``). + +Se ainda estiver pendente, observe a atribuição: + +```bash +kubectl get svc -n traefik-public -w +``` + +Pressione `Ctrl+C` quando o IP aparecer. A atribuição de IP geralmente leva 2--5 minutos. + +**Se falhar:** `` após 10 minutos geralmente indica que o provedor de nuvem não consegue provisionar um LoadBalancer. Verifique: tags de sub-rede (o EKS requer `kubernetes.io/role/elb`), configuração da VPC, cotas de serviço e se a anotação correta de LB interno está definida para a instância interna. + +--- + +## Fase 2 -- Criar Secrets (~10 min) + +Todos os secrets são criados manualmente antes do deploy da aplicação. Isso garante que valores sensíveis nunca apareçam em arquivos de manifesto. + +### 2.1 Criar o namespace + +```bash +kubectl create namespace agenteye +``` + +**Teste:** + +```bash +kubectl get namespace agenteye +``` + +Esperado: status `Active`. + +--- + +### 2.2 Secret de pull de imagem + +Este secret autentica com `ghcr.io` para fazer pull das imagens de container do AgentEye. Consulte [enterprise-docs/github-token.md](/pt-br/agenteye/github-token) para saber como gerar seu PAT. + +```bash +kubectl create secret docker-registry agenteye-image-pull \ + --namespace agenteye \ + --docker-server=ghcr.io \ + --docker-username=agenteye-enterprise \ + --docker-password="${AGENTEYE_TOKEN}" +``` + +**Teste:** + +```bash +kubectl get secret agenteye-image-pull -n agenteye -o jsonpath='{.type}' +``` + +Esperado: `kubernetes.io/dockerconfigjson`. + +**Teste (detalhado)** -- verifique se o token consegue de fato fazer pull das imagens: + +Use a tag de imagem do `server` fixada no `kustomization.yaml` do seu overlay (atualmente `v0.0.1-beta.48` tanto no overlay `acme` incluído quanto no deploy base). Substitua a tag abaixo pela que você está implantando para que esta verificação não fique desatualizada entre releases: + +```bash +kubectl run test-pull \ + --image=ghcr.io/agenteye-enterprise/server:v0.0.1-beta.48 \ + --overrides='{"spec":{"imagePullSecrets":[{"name":"agenteye-image-pull"}]}}' \ + --restart=Never -n agenteye --command -- echo ok + +# Aguarde alguns segundos para o pull e então: +kubectl logs test-pull -n agenteye +kubectl delete pod test-pull -n agenteye +``` + +Esperado: `ok` impresso nos logs. + +**Se falhar:** `ErrImagePull` ou `401 Unauthorized` significa que o PAT é inválido ou não tem o escopo `read:packages`. Verifique novamente [enterprise-docs/github-token.md](/pt-br/agenteye/github-token). + +--- + +### 2.3 Credenciais do PostgreSQL + +```bash +POSTGRES_PASSWORD=$(openssl rand -hex 24) + +kubectl create secret generic agenteye-postgres \ + --namespace agenteye \ + --from-literal=POSTGRES_USER=postgres \ + --from-literal=POSTGRES_PASSWORD="${POSTGRES_PASSWORD}" \ + --from-literal=POSTGRES_DB=agenteye +``` + +> **Importante:** Usamos `-hex` (não `-base64`) para gerar a senha. A saída Base64 pode conter `+`, `/` e `=`, que quebram a string de conexão `DATABASE_URL`. Consulte [enterprise-docs/troubleshooting.md](/pt-br/agenteye/troubleshooting) para mais detalhes. + +> **Armazene `POSTGRES_PASSWORD` no seu gerenciador de secrets imediatamente.** Você precisará dele se precisar restaurar a partir de um backup ou conectar diretamente ao banco de dados. + +**Teste:** + +```bash +kubectl get secret agenteye-postgres -n agenteye +``` + +Esperado: o secret existe. + +```bash +kubectl get secret agenteye-postgres -n agenteye \ + -o jsonpath='{.data.POSTGRES_PASSWORD}' | base64 -d | wc -c +``` + +Esperado: `48` (24 bytes hex = 48 caracteres). + +--- + +### 2.4 Chave de API admin + +```bash +ADMIN_KEY=$(openssl rand -hex 32) + +kubectl create secret generic agenteye-admin-key \ + --namespace agenteye \ + --from-literal=ADMIN_KEY="${ADMIN_KEY}" +``` + +A chave admin é a credencial de bootstrap. O servidor a registra (upsert) a cada inicialização com todas as permissões. Use-a para criar chaves de coletor com escopo na Fase 7. Consulte [enterprise-docs/api-keys.md](/pt-br/agenteye/api-keys) para o modelo completo de permissões. + +> **Armazene `ADMIN_KEY` no seu gerenciador de secrets imediatamente.** + +**Teste:** + +```bash +kubectl get secret agenteye-admin-key -n agenteye +``` + +Esperado: o secret existe. + +--- + +### 2.5 Configuração de autenticação (login no dashboard) + +O dashboard usa email + OTP para login de usuários. Sem este secret, o servidor ainda inicia e o caminho de API com `ADMIN_KEY` continua funcionando, mas **nenhum usuário pode fazer login pela UI**. + +Todas as chaves são referenciadas como `optional: true` no manifesto base, portanto secrets parciais (ou nenhum secret) são aceitáveis; o servidor utiliza os padrões documentados como fallback. Agrupar tudo em um único secret `agenteye-auth` mantém a superfície de autenticação rotacionável em um único lugar. + +```bash +kubectl create secret generic agenteye-auth \ + --namespace agenteye \ + --from-literal=ADMIN_EMAIL="admin@suaempresa.com" \ + --from-literal=ALLOWED_EMAILS="*@suaempresa.com" \ + --from-literal=SMTP_HOST="smtp.seuprovedor.com" \ + --from-literal=SMTP_PORT="587" \ + --from-literal=SMTP_USERNAME="seu-usuario-smtp" \ + --from-literal=SMTP_PASSWORD="sua-senha-smtp" \ + --from-literal=SMTP_FROM="noreply@suaempresa.com" \ + --from-literal=SMTP_TLS="starttls" \ + --from-literal=DEFAULT_ORG_NAME="Acme Corp" \ + --from-literal=DEFAULT_ORG_SLUG="acme" +``` + +| Chave | Finalidade | +|---|---| +| `ADMIN_EMAIL` | Usuário admin de bootstrap. Registrado (upsert) a cada inicialização com todas as permissões e protegido contra exclusão/edição de permissões via dashboard. Sem ele, nenhum admin é criado e o primeiro login é impossível. | +| `ALLOWED_EMAILS` | Lista de permissões separada por vírgulas. Suporta endereços exatos (`user@example.com`) e curingas de domínio (`*@example.com`). Sem ela, **nenhum usuário pode fazer login ou ser criado**. | +| `SMTP_HOST`, `SMTP_PORT`, `SMTP_USERNAME`, `SMTP_PASSWORD`, `SMTP_FROM` | Relay SMTP para envio de códigos OTP. Se `SMTP_HOST` não estiver definido, os códigos OTP são registrados no stdout do servidor em vez de enviados por email (útil para testes iniciais). Forneça todas as chaves SMTP juntas para entrega real de emails. | +| `SMTP_TLS` | Um de `starttls` (padrão), `tls` ou `none`. | +| `DEFAULT_ORG_NAME`, `DEFAULT_ORG_SLUG` | Opcional. Dê à organização `default` integrada um nome de exibição amigável e slug de URL para que fique em ex.: `/acme` em vez de `/default`. Aplicado apenas na **primeira inicialização**; depois de renomear a organização com `agenteye-orgctl org rename` (ver §7.6), esses valores são ignorados. O slug deve ter 1--40 caracteres alfanuméricos minúsculos com hífens internos simples. Deixe ambos sem definir para manter o `default` genérico. | + +> **Armazene as credenciais SMTP no seu gerenciador de secrets.** + +**Teste:** + +```bash +kubectl get secret agenteye-auth -n agenteye \ + -o jsonpath='{.data}' | grep -o '"[A-Z_]*"' | sort -u +``` + +Esperado: as chaves que você preencheu aparecem na saída. + +--- + +### 2.6 Chave de isolamento de organização multi-tenant (opcional) + +Pule esta etapa para um deploy single-tenant; o servidor roda com um padrão de desenvolvimento integrado e serve bem a única organização `default`. **Antes de criar uma segunda organização**, defina um `ORG_CH_SECRET` forte e estável: a senha do ClickHouse de cada organização é derivada como `HMAC(ORG_CH_SECRET, org_id)`, portanto o padrão de desenvolvimento público resultaria em credenciais por organização deriváveis publicamente. O comando `agenteye-orgctl org create` (ver [§7.6 Provisionar organizações](#76-provision-organizations-multi-tenant)) se recusa a executar enquanto o servidor ainda estiver usando o padrão de desenvolvimento integrado. + +```bash +kubectl create secret generic agenteye-org-ch-secret \ + --namespace agenteye \ + --from-literal=ORG_CH_SECRET="$(openssl rand -base64 48)" + +# Reinicie o servidor para que ele utilize o novo valor. +kubectl -n agenteye rollout restart deployment/server +``` + +O servidor lê isso via uma `secretKeyRef` **opcional**, portanto um cluster single-tenant que nunca o criar ainda inicializa normalmente. Mantenha o valor **estável e idêntico em todas as réplicas**; rotacioná-lo invalida a senha ClickHouse derivada de cada organização até que a reconciliação na inicialização reprovisionne os usuários (um rolling restart com o valor consistente em todos os lugares resolve). Consulte `deploy/base/server/secret.example.yaml`. + +> **Armazene `ORG_CH_SECRET` no seu gerenciador de secrets e não o rotacione sem necessidade.** + +--- + +### 2.7 Verificar todos os secrets + +```bash +kubectl get secrets -n agenteye -o custom-columns='NAME:.metadata.name,TYPE:.type' +``` + +Saída esperada (entre quaisquer secrets padrão): + +``` +NAME TYPE +agenteye-admin-key Opaque +agenteye-auth Opaque +agenteye-image-pull kubernetes.io/dockerconfigjson +agenteye-postgres Opaque +agenteye-org-ch-secret Opaque # somente se você concluiu o §2.6 (multi-tenant) +``` + +Os quatro secrets principais (`agenteye-admin-key`, `agenteye-auth`, `agenteye-image-pull`, `agenteye-postgres`) devem estar presentes antes de continuar. `agenteye-org-ch-secret` é necessário apenas para deploys multi-tenant (ver §2.6). + +--- + +## Fase 3 -- Deploy da Aplicação (~5 min) + +### 3.1 Configurar os hostnames públicos + +O cert-manager precisa dos hostnames de ingestão e do dashboard antes de poder solicitar os certificados Let's Encrypt. Copie o template e defina ambos: + +```bash +cp base/certificates/domain.env.example base/certificates/domain.env +# Edite base/certificates/domain.env e defina: +# INGEST_DOMAIN=ingest.sua-empresa.example (resolve para o LB público do Traefik) +# DASHBOARD_DOMAIN=agenteye.sua-empresa.example (resolve para o LB do Traefik do dashboard) +``` + +`domain.env` está no .gitignore; fica local a cada deploy. O build do kustomize falha explicitamente se alguma das chaves estiver ausente. + +> **O DNS deve resolver primeiro.** Você não precisa apontar o DNS para os LBs agora (eles não existem até que a Fase 1.2 esteja concluída), mas a emissão ACME no passo 3.2 continuará tentando até que cada hostname resolva para seu LoadBalancer. Você pode definir o DNS agora (usando os hostnames dos LBs capturados na Fase 1.4) ou prosseguir e adicionar os registros na Fase 4. + +--- + +### 3.2 Aplicar os manifestos + +Aplique a base diretamente para uma instalação nova, ou um overlay se você já criou um para este ambiente (overlays apenas fixam tags de imagem, variáveis de ambiente e limites de recursos; eles herdam os certs e o roteamento da base): + +```bash +kubectl apply -k base/ +# ou +kubectl apply -k overlays// +``` + +O overlay inclui a base automaticamente; aplique um, não ambos. + +--- + +### 3.3 Aguardar os pods + +```bash +kubectl wait --for=condition=Ready pod -l 'app in (server,dashboard,postgres,clickhouse)' \ + -n agenteye --timeout=180s +``` + +A espera está limitada aos pods principais do data-plane. Os pods opcionais `agent` (assistente de IA) e `redis` sobem junto com eles; o assistente permanece inativo até que você forneça seu endpoint LLM (consulte [enterprise-docs/assistant.md](/pt-br/agenteye/assistant)), e o Redis é um cache de melhor esforço, portanto nenhum dos dois precisa estar Ready para a plataforma servir tráfego. + +**Teste:** + +```bash +kubectl get pods -n agenteye +``` + +Esperado (os pods opcionais `agent` e `redis` também aparecem e atingem `Running`): + +``` +NAME READY STATUS RESTARTS AGE +agent-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +clickhouse-0 1/1 Running 0 ... +dashboard-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +dashboard-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +postgres-0 1/1 Running 0 ... +redis-0 1/1 Running 0 ... +server-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +server-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +``` + +**Se falhar:** + +| Status do Pod | Causa Provável | Comando de Debug | +|---|---|---| +| `ImagePullBackOff` | Secret de pull de imagem inválido ou PAT incorreto | `kubectl describe pod -n agenteye` | +| `CrashLoopBackOff` | Variáveis de ambiente incorretas (ex.: DATABASE_URL) | `kubectl logs -n agenteye` | +| `Pending` | CPU/memória insuficiente ou sem nós disponíveis | `kubectl describe pod -n agenteye` (verifique Events) | + +--- + +### 3.4 Verificar armazenamento + +```bash +kubectl get pvc -n agenteye +``` + +Esperado, ambos com status `Bound`: + +| PVC | Capacidade | Utilizado por | +|---|---|---| +| `postgres-data-postgres-0` | `50Gi` | Armazenamento relacional/de metadados do PostgreSQL | +| `clickhouse-data-clickhouse-0` | `100Gi` | Armazenamento de analytics de eventos + avaliações do ClickHouse | + +Um PVC `redis-data-redis-0` (1Gi) também aparece para o cache opcional. + +**Se falhar:** `Pending` significa que nenhuma StorageClass consegue provisionar o volume. Verifique `kubectl get storageclass` e assegure que existe uma padrão. Para produção, utilize no overlay uma StorageClass de SSD rápido para o volume do ClickHouse (ex.: gp3 na AWS, pd-ssd no GCP); o throughput de compactação sofre com discos lentos. + +--- + +### 3.5 Verificar certificados + +```bash +kubectl get certificates -n agenteye +``` + +Esperado: 3 certificados, todos `Ready: True`: + +| Nome | Emissor | Finalidade | +|---|---|---| +| `mtls-ca` | `selfsigned` | CA privada para emissão de certificados de cliente mTLS (validade de 10 anos) | +| `ingest-tls` | `letsencrypt-prod` | Certificado TLS público para o endpoint de ingestão (90 dias, renovação automática) | +| `dashboard-tls` | `letsencrypt-prod` | Certificado TLS público para o dashboard (90 dias, renovação automática) | + +**Se `ingest-tls` ou `dashboard-tls` não estiver Ready:** + +Execute `kubectl describe certificate -n agenteye` e leia os Events. As causas comuns são: + +- **DNS ainda não aponta para o LB.** A Let's Encrypt resolve o hostname e acessa a porta 80 para validar — `INGEST_DOMAIN` deve resolver para o LB público e `DASHBOARD_DOMAIN` para o LB do dashboard. Enquanto o CNAME/Alias não propagar, o pedido fica `pending`. Quando o DNS estiver correto, o cert-manager tenta novamente automaticamente (não é necessário excluir o Certificate). +- **Hostname não substituído.** Se `dnsNames` ainda exibe `INGEST_DOMAIN_PLACEHOLDER` / `DASHBOARD_DOMAIN_PLACEHOLDER`, você pulou o passo 3.1 — crie `base/certificates/domain.env` e aplique novamente. +- **O Traefik do dashboard não consegue servir o desafio** (somente para `dashboard-tls`). A instância do Traefik do dashboard deve ser instalada com o arquivo de valores incluído (Fase 1.2), que habilita o provedor de Ingress com escopo que serve o solver HTTP-01 do cert-manager. Uma instância instalada sem ele deixa o desafio sem rota e o pedido `pending` indefinidamente. + +**Se `mtls-ca` não estiver Ready:** o próprio cert-manager está com problemas. Verifique novamente os pods do cert-manager do passo 1.1. + +--- + +### 3.6 Verificar CronJobs + +```bash +kubectl get cronjobs -n agenteye +``` + +Esperado: + +| Nome | Agendamento | Finalidade | +|---|---|---| +| `agenteye-backup` | `0 3 * * *` | Backup diário de Postgres + ClickHouse às 03:00 UTC | +| `cert-renewal-check` | `0 3,15 * * *` | Alertas de vencimento de certificado às 03:00 e 15:00 UTC | + +--- + +### 3.7 Verificar se o servidor iniciou corretamente + +```bash +kubectl logs -n agenteye -l app=server --tail=20 +``` + +**Teste:** Procure por uma linha de inicialização indicando que o servidor está escutando na porta 8080. Não deve haver erros de conexão com o banco de dados (o servidor requer que tanto o PostgreSQL quanto o ClickHouse estejam acessíveis antes de reportar Ready). + +**Se falhar:** A causa mais comum é um `POSTGRES_PASSWORD` contendo caracteres não seguros para URL que quebram o `DATABASE_URL`. Consulte [enterprise-docs/troubleshooting.md](/pt-br/agenteye/troubleshooting). + +--- + +### 3.8 Verificar se o dashboard conectou ao servidor + +```bash +kubectl logs -n agenteye -l app=dashboard --tail=20 +``` + +**Teste:** Procure por `Ready` na saída sem erros `ECONNREFUSED` ou similares. + +**Se falhar:** Verifique se o Service `server` existe (`kubectl get svc server -n agenteye`) e se `AGENTEYE_SERVER_URL` está definido como `http://server:8080` no deployment do dashboard. + +--- + +## Fase 4 -- Acesso à Rede (~5 min) + +### 4.1 Obter os endereços dos LoadBalancers + +```bash +PUBLIC_IP=$(kubectl get svc -n traefik-public \ + -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') + +INTERNAL_IP=$(kubectl get svc -n traefik-dashboard \ + -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') +``` + +> No AWS EKS, os LoadBalancers retornam um hostname em vez de um IP. Substitua `.ip` por `.hostname` nos comandos acima. + +**Teste:** + +```bash +echo "Público (ingestão): $PUBLIC_IP" +echo "Interno (dashboard): $INTERNAL_IP" +``` + +Ambos devem ser não vazios. + +--- + +### 4.2 Apontar o DNS para os LoadBalancers + +Crie registros DNS para que os hostnames de `base/certificates/domain.env` resolvam para seus LoadBalancers — `INGEST_DOMAIN` para o LB Traefik **público** e `DASHBOARD_DOMAIN` para o LB Traefik do **dashboard**: + +- **AWS Route 53:** Registro `A` com `Alias = Yes`, alvo = o hostname do LB. Não use A → IP simples; os IPs do ELB são rotacionados. +- **Qualquer outro provedor:** `CNAME` do hostname para o hostname do LB. + +Verifique: + +```bash +dig +short ingest.sua-empresa.example +dig +short agenteye.sua-empresa.example +``` + +Deve retornar os mesmos endereços que `$PUBLIC_IP` e `$INTERNAL_IP` respectivamente (ou, no EKS, resolver para os mesmos hostnames `*.elb.amazonaws.com`). + +Quando o DNS resolver, o cert-manager concluirá os pedidos ACME pendentes da Fase 3.5 em um minuto. Execute novamente `kubectl get certificates -n agenteye` até que tanto `ingest-tls` quanto `dashboard-tls` exibam `Ready: True`. + +--- + +### 4.3 Acessar o endpoint de ingestão + +O endpoint de ingestão público aplica mutual TLS, portanto toda requisição (incluindo `/health`) deve apresentar um certificado de cliente. Você emite seu primeiro certificado de cliente na Fase 5; se você já tiver um, verifique a acessibilidade agora: + +```bash +curl -s --cert issued//client.crt \ + --key issued//client.key \ + https://ingest.sua-empresa.example/health +``` + +Esperado: `{"status":"ok"}`. O `-k` não é necessário -- o certificado do servidor encadeia para uma CA pública para `INGEST_DOMAIN`, portanto valida em relação ao repositório de confiança do sistema. Acesse o endpoint de ingestão pelo hostname `INGEST_DOMAIN` (que corresponde ao certificado emitido), não pelo IP/hostname bruto do LoadBalancer. + +O endpoint do dashboard é servido em `DASHBOARD_DOMAIN` com um certificado publicamente confiável e não está atrás de mTLS, portanto nenhum `-k` e nenhum certificado de cliente são necessários: + +```bash +curl -s https://agenteye.sua-empresa.example/ -o /dev/null -w '%{http_code}\n' +``` + +Acesse o dashboard pelo seu hostname, não pelo endereço bruto do LB — o certificado está vinculado a `DASHBOARD_DOMAIN`, portanto o endereço bruto exibe um erro de incompatibilidade de nome de certificado. + +**Se falhar:** Se o `curl` travar, verifique se o LB está acessível a partir da sua máquina (VPN, grupos de segurança, regras de firewall). Um erro de handshake `certificate required` no hostname de ingestão significa que nenhum certificado de cliente foi apresentado; conclua a Fase 5 primeiro. Um erro de validação TLS no hostname de ingestão significa que o certificado do servidor ainda não terminou de ser emitido; volte à Fase 3.5 e resolva o problema lá. + +--- + +## Fase 5 -- Emitir Certificados de Cliente mTLS (~10 min por cluster) + +Os coletores se autenticam com **dois fatores**: um certificado de cliente (camada de transporte, prova que a requisição vem de um cluster autorizado) e uma chave de API (camada de aplicação, prova que a requisição é de um coletor com permissão `events:add`). Uma chave vazada é inútil sem o certificado; um certificado roubado é inútil sem uma chave válida. + +### 5.1 Emitir um certificado + +Cada cluster que executa coletores precisa do seu próprio certificado de cliente. No diretório dos manifestos: + +```bash +cd base/certificates/client-certs +./issue-client-cert.sh +``` + +Substitua `` por um identificador significativo (ex.: `us-east-1-prod`, `staging`). + +**Teste:** O script exibe `==> Done!` e lista os arquivos de saída. + +```bash +kubectl get certificate mtls-client- -n agenteye +``` + +Esperado: `Ready: True`. + +Arquivos de saída em `issued//`: + +| Arquivo | Finalidade | +|---|---| +| `client.crt` | Certificado de cliente (validade de 90 dias) | +| `client.key` | Chave privada do cliente | +| `ca.crt` | Certificado CA para verificação do servidor | +| `collector-mtls-secret.yaml` | Secret Kubernetes pronto para aplicar no cluster do coletor | + +--- + +### 5.1b Entrega alternativa: AWS Secrets Manager + +Se o consumidor do certificado é um Pod Kubernetes que precisa de `client.crt` e `client.key` em disco -- o caso típico ao executar o agenteye-collector como sidecar no pod da sua aplicação -- envie o pacote de certificados para o AWS Secrets Manager. O pod da aplicação então o monta via [Secrets Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/) com IRSA, e a rotação de certificados é totalmente automatizada. + +```bash +cd base/certificates/client-certs +export AWS_REGION=us-east-1 # região onde sua carga de trabalho executa +./issue-client-cert.sh --save-to aws-secrets-manager +``` + +Na reexecução (renovação), o script chama `PutSecretValue` no mesmo secret, de modo que o ARN e o nome permanecem estáveis. O CSI Driver obtém a nova versão na próxima poll de rotação e reescreve os arquivos dentro do pod. + +**Pré-requisitos:** + +- CLI `aws` v2 autenticado na sua conta AWS. +- `jq` instalado. +- Variável de ambiente `AWS_REGION` definida. +- Permissões IAM na sua identidade chamadora (restrinja `Resource` a `arn:aws:secretsmanager:::secret:agenteye/mtls-client/*`): + - `secretsmanager:CreateSecret` + - `secretsmanager:DescribeSecret` + - `secretsmanager:PutSecretValue` + - `secretsmanager:TagResource` + +**O que o script faz neste modo:** + +| Passo | Ação | +|---|---| +| 1 | Emite/reextrai o certificado via cert-manager (mesmo que o modo padrão). | +| 2 | Chama `DescribeSecret` em `agenteye/mtls-client/` para decidir entre criar ou atualizar. | +| 3 | Na primeira execução: `CreateSecret` com um payload JSON de três chaves (`client.crt`, `client.key`, `ca.crt`), com a tag `AgentEyeCluster=`. Nas execuções subsequentes: `PutSecretValue` para publicar uma nova versão; tag atualizada via `TagResource`. | +| 4 | Exclui `issued//` somente após um upload bem-sucedido. Em caso de falha, o diretório é preservado para que você possa tentar novamente. | + +**Se o secret estiver agendado para exclusão**, o script falha com um erro claro informando para executar `aws secretsmanager restore-secret --secret-id agenteye/mtls-client/` antes de tentar novamente. + +Para a configuração completa do pod (SecretProviderClass, setup IRSA, comportamento de rotação, troubleshooting), consulte [enterprise-docs/single-pod-deployment.md](/pt-br/agenteye/single-pod-deployment). + +--- + +### 5.2 Verificar se o certificado funciona + +Teste o certificado emitido contra o ingress mTLS: + +```bash +curl -sk --cert issued//client.crt \ + --key issued//client.key \ + https://${PUBLIC_IP}/health +``` + +Esperado: `{"status":"ok"}` + +**Se falhar:** + +| Erro | Causa | Solução | +|---|---|---| +| `certificate required` | Certificado não sendo apresentado | Verifique os caminhos dos arquivos no comando `curl` | +| `bad certificate` | Incompatibilidade de CA | Verifique se `mtls-ca-issuer` emitiu o certificado: `kubectl describe certificate mtls-client- -n agenteye` | +| `connection refused` | Hostname incorreto ou LB inacessível | Verifique `/etc/hosts` ou DNS | + +--- + +### 5.3 Entregar ao cluster do coletor + +Envie `collector-mtls-secret.yaml` para a equipe que opera o cluster do coletor. Eles aplicam: + +```bash +kubectl apply -f collector-mtls-secret.yaml -n +``` + +Em seguida, configure o coletor para montar o secret e usar os caminhos do certificado: + +```json +{ + "tls_cert": "/etc/agenteye/tls/client.crt", + "tls_key": "/etc/agenteye/tls/client.key" +} +``` + +Consulte [enterprise-docs/collector-installation.md](/pt-br/agenteye/collector-installation) para a configuração completa do coletor, incluindo montagens de volumes no Kubernetes. + +**Teste (no cluster do coletor):** + +```bash +kubectl get secret agenteye-collector-mtls -n +``` + +Esperado: o secret existe com 3 chaves de dados (`client.crt`, `client.key`, `ca.crt`). + +--- + +### 5.4 Ciclo de vida do certificado + +| Propriedade | Valor | +|---|---| +| Validade do certificado de cliente | 90 dias | +| Renovação automática | cert-manager renova 15 dias antes do vencimento | +| Validade da CA | 10 anos | +| Alertas de vencimento | CronJob alerta 30 dias antes do vencimento (Fase 6) | + +O cert-manager renova automaticamente o certificado no **cluster AgentEye**, mas o certificado renovado deve ser reenviado ao cluster do coletor. Execute novamente `issue-client-cert.sh` e reaplique `collector-mtls-secret.yaml` antes que o certificado antigo expire. + +Se você estiver usando `--save-to aws-secrets-manager` (ver §5.1b), execute o mesmo comando novamente. O script chama `PutSecretValue` no mesmo secret; os pods que montam o secret via Secrets Store CSI Driver obtêm a nova versão na próxima poll de rotação (padrão: a cada hora), sem necessidade de reiniciar o pod. + +--- + +### 5.5 Revogar um certificado + +Para bloquear imediatamente o acesso do coletor de um cluster: + +```bash +kubectl delete certificate mtls-client- -n agenteye +``` + +**Teste:** O comando `curl` do passo 5.2 agora falha com um erro de handshake TLS. + +--- + +## Fase 6 -- Monitoramento de Renovação de Certificados (~2 min) + +Um CronJob integrado é executado a cada 12 horas (03:00 e 15:00 UTC) e verifica todos os certificados de cliente com o rótulo `agenteye.io/cert-type=mtls-client`. Ele alerta quando algum certificado está a 30 dias do vencimento. + +### 6.1 Habilitar notificações no Slack (opcional) + +```bash +kubectl create secret generic cert-renewal-notify-config \ + --namespace agenteye \ + --from-literal=SLACK_WEBHOOK_URL="https://hooks.slack.com/services/SEU/WEBHOOK/URL" +``` + +Sem este secret, o CronJob ainda executa e registra o status dos certificados no stdout. + +**Teste:** + +```bash +kubectl get secret cert-renewal-notify-config -n agenteye +``` + +Esperado: o secret existe. + +--- + +### 6.2 Testar o CronJob + +```bash +kubectl create job --from=cronjob/cert-renewal-check test-cert-check -n agenteye + +kubectl wait --for=condition=Complete job/test-cert-check -n agenteye --timeout=60s + +kubectl logs -n agenteye -l job-name=test-cert-check +``` + +Esperado: uma lista de certificados com seus status de vencimento. Se o webhook do Slack estiver configurado, verifique o canal Slack para a mensagem de alerta. + +**Se falhar:** Verifique o RBAC -- a ServiceAccount do CronJob precisa de permissões `get, list` nos recursos Certificate do cert-manager. Verifique com: `kubectl describe role cert-renewal-check -n agenteye`. + +Limpe o job de teste: + +```bash +kubectl delete job test-cert-check -n agenteye +``` + +--- + +## Fase 7 -- Verificar End-to-End + +Esta fase confirma que todo o pipeline funciona: verificação de saúde, criação de chaves, ingestão de eventos e exibição no dashboard. + +> **Nota:** Os exemplos abaixo acessam o endpoint de ingestão pelo endereço bruto do LoadBalancer (`${PUBLIC_IP}`) por conveniência, razão pela qual passam `-k`; o certificado do servidor está vinculado a `INGEST_DOMAIN`, não ao IP do LB, portanto a verificação de hostname é ignorada. O endpoint de ingestão aplica mutual TLS em **todos** os caminhos, portanto toda chamada também deve apresentar um certificado de cliente (`--cert`/`--key`). Para validar também o certificado público, direcione para `https://ingest.sua-empresa.example/...` em vez de `${PUBLIC_IP}` e remova o `-k`. + +### 7.1 Verificação de saúde + +```bash +curl -sk --cert issued//client.crt \ + --key issued//client.key \ + https://${PUBLIC_IP}/health +``` + +Esperado: `{"status":"ok"}` com HTTP 200. + +--- + +### 7.2 Criar chaves de coletor com escopo + +A chave admin é para bootstrap e gerenciamento. Crie chaves dedicadas com permissão `events:add` para os coletores: + +```bash +COLLECTOR_KEY=$(openssl rand -hex 32) + +curl -sk -X POST https://${PUBLIC_IP}/keys \ + --cert issued//client.crt \ + --key issued//client.key \ + -H "Authorization: Bearer ${ADMIN_KEY}" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "prod-collector", + "key": "'"${COLLECTOR_KEY}"'", + "permissions": ["events:add"] + }' +``` + +**Teste:** A resposta inclui `"id"`, `"name": "prod-collector"`, `"permissions": ["events:add"]`, `"created_at"`. + +**Teste:** Verifique se a chave aparece na lista de chaves: + +```bash +curl -sk https://${PUBLIC_IP}/keys \ + --cert issued//client.crt \ + --key issued//client.key \ + -H "Authorization: Bearer ${ADMIN_KEY}" +``` + +Esperado: `prod-collector` aparece na resposta. + +Consulte [enterprise-docs/api-keys.md](/pt-br/agenteye/api-keys) para a referência completa de gerenciamento de chaves. + +--- + +### 7.3 Ingerir um evento de teste + +```bash +echo '{"session_id":"test","agent_id":"smoke-test","type":"test","timestamp":"2026-04-20T00:00:00Z"}' \ + | curl -sk --cert issued//client.crt \ + --key issued//client.key \ + -H "Authorization: Bearer ${COLLECTOR_KEY}" \ + -H "Content-Type: application/x-ndjson" \ + --data-binary @- \ + https://${PUBLIC_IP}/events +``` + +Esperado: `{"accepted":1,"skipped":0}` com HTTP 200. + +**Se falhar:** + +| Status HTTP | Causa | +|---|---| +| 401 | Chave de API inválida ou ausente | +| 403 | Chave sem permissão `events:add` | +| Erro de handshake TLS | Problema com certificado de cliente -- consulte o troubleshooting da Fase 5 | + +--- + +### 7.4 Verificar se o evento aparece no dashboard + +Abra `https://agenteye.sua-empresa.example` (seu `DASHBOARD_DOMAIN`) em um navegador. O certificado é publicamente confiável, portanto não há avisos. + +> Se o LoadBalancer do dashboard estiver restrito por lista de IPs e você não conseguir se conectar, verifique se seu IP está permitido: +> ```bash +> kubectl get svc traefik-dashboard -n traefik-dashboard -o jsonpath='{.spec.loadBalancerSourceRanges}' +> ``` +> Lembre-se de que a Let's Encrypt renova o certificado do dashboard via HTTP-01 na porta 80, e os intervalos de origem se aplicam a todo o LoadBalancer — antes de restringi-lo a intervalos corporativos, coordene um solver DNS-01 com o suporte, ou as renovações falharão silenciosamente. + +**Teste:** O evento de smoke-test deve aparecer na lista de eventos com session `test` e agent `smoke-test`. + +**Se falhar:** Verifique os logs do dashboard (`kubectl logs -n agenteye -l app=dashboard --tail=50`). Verifique se `AGENTEYE_SERVER_URL` e `AGENTEYE_API_KEY` estão definidos corretamente. + +--- + +### 7.5 Testar o CronJob de backup + +```bash +kubectl create job --from=cronjob/agenteye-backup test-backup -n agenteye + +kubectl wait --for=condition=Complete job/test-backup -n agenteye --timeout=300s + +kubectl logs -n agenteye -l job-name=test-backup +``` + +Esperado: `Backup created: agenteye-YYYYMMDD-HHMMSS.tar.gz (NNN)` nos logs; o arquivo agrega o dump do Postgres e as tabelas do ClickHouse. + +> A etapa de upload para S3 é incluída no CronJob e é executada sempre que `BACKUP_BUCKET` estiver definido (a base inclui um valor padrão de bucket). É ignorada somente quando `BACKUP_BUCKET` está vazio ou literalmente `PLACEHOLDER`. Aponte-o para seu próprio bucket e conceda acesso de escrita à ServiceAccount `agenteye-backup` antes de depender dele (consulte a seção Backups abaixo). + +Limpeza: + +```bash +kubectl delete job test-backup -n agenteye +``` + +--- + +### 7.6 Provisionar organizações (multi-tenant) + +Pule esta etapa para um deploy single-tenant; todos os dados residem na organização `default` integrada e nada aqui é necessário. + +Se você estiver executando múltiplos tenants isolados, organizações e seus membros são criados com a CLI **`agenteye-orgctl`**. Ela é incluída **dentro da imagem do servidor** (junto com `agenteye-server`) e você a executa **dentro do Deployment `server` existente com `kubectl exec`; não há pod, Job ou Deployment separado, e nenhuma API HTTP ou botão no dashboard para o ciclo de vida do tenant.** Executá-la no pod do servidor significa que ela reutiliza o `DATABASE_URL`, `CLICKHOUSE_URL` e o `ORG_CH_SECRET` do §2.6 do pod. + +> **Pré-requisito:** conclua o §2.6 primeiro. `org create` se recusa a executar enquanto o servidor ainda estiver usando o `ORG_CH_SECRET` de desenvolvimento integrado, e o usuário ClickHouse por organização que ele provisiona depende de esse secret ser forte e estável. + +**Criar uma organização e adicionar seu primeiro admin:** + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org create --slug acme --name "Acme Corp" + +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member add --org acme --email alice@acme.example --set admin +``` + +O novo membro recebe um OTP no primeiro login no dashboard e depois opera inteiramente pela UI sob o prefixo de URL da organização (ex.: `/acme/...`). + +**Outros comandos** (execute da mesma forma com `kubectl -n agenteye exec deploy/server -- agenteye-orgctl …`): + +| Comando | O que faz | +|---|---| +| `org list` | Lista organizações e seus estados. | +| `org rename --slug --name ` | Renomeia uma organização (slug inalterado). | +| `org delete --slug ` | Soft-delete + remove o usuário ClickHouse da organização; **dados retidos**. | +| `org purge --slug ` | Exclusão irreversível de dados; a organização deve ter sido `delete`d primeiro; nunca a organização `default`. | +| `member list --org ` | Lista membros e suas permissões. | +| `member update --org --email [--set ...] [--add ...] [--remove ...]` | Altera as permissões de um membro. | +| `member remove --org --email ` | Remove um membro da organização. | + +Os conjuntos de permissões integrados são `admin`, `standard` e `read-only`. **As chaves de API por organização ainda são criadas no dashboard/API pelos membros da organização (o §7.2 mostra a API de chaves); somente o ciclo de vida de organização + membro é exclusivo do operador.** Referência completa e exemplo prático: [enterprise-docs/tenant-management.md](/pt-br/agenteye/tenant-management). + +--- + +## Checklist Pós-Deploy + +Use este checklist para confirmar que tudo está funcionando. Cada item deve ser verificado antes de entregar aos coletores. + +- [ ] Todos os pods em `Running` no namespace `agenteye` +- [ ] PVC do PostgreSQL vinculado (50Gi) e PVC do ClickHouse vinculado (100Gi) +- [ ] Todos os 3 certificados `Ready: True` +- [ ] Ambos os IPs do LoadBalancer atribuídos +- [ ] DNS ou `/etc/hosts` configurado e resolvendo +- [ ] `/health` retorna HTTP 200 +- [ ] Teste de certificado mTLS aprovado (`curl` com certificado de cliente para `/health`) +- [ ] Chave de coletor com escopo criada e testada +- [ ] Evento de teste ingerido (`accepted: 1`) +- [ ] Evento visível no dashboard +- [ ] Certificados de cliente emitidos para cada cluster de coletor +- [ ] CronJob de backup testado manualmente +- [ ] CronJob de renovação de certificados testado manualmente +- [ ] Webhook do Slack para alertas de certificados configurado (opcional) +- [ ] Bucket de backup configurado no overlay (ver abaixo) +- [ ] Chave admin e senha do Postgres armazenadas no gerenciador de secrets + +--- + +## Backups + +Um único CronJob `agenteye-backup` é executado diariamente às 03:00 UTC. Ele faz dump de **ambos** os armazenamentos: PostgreSQL (estado relacional) e ClickHouse (as tabelas de analytics `events` + `evaluations`), em um único arquivo comprimido no pod, e então o envia para o armazenamento de objetos que você configura no seu overlay. + +Cada execução produz um objeto, `agenteye-.tar.gz`, que descompactado contém: + +``` +postgres.sql # pg_dump do banco de dados relacional +events.sql # DDL da tabela de eventos do ClickHouse +events.native # Dados da tabela de eventos do ClickHouse (formato Native) +evaluations.sql # DDL da tabela de avaliações do ClickHouse +evaluations.native # Dados da tabela de avaliações do ClickHouse +``` + +O ClickHouse é lido via sua API HTTP (o mesmo endpoint que o servidor usa), portanto o job não precisa de cliente ClickHouse. Apenas as duas tabelas físicas são despejadas; o servidor recria todas as views (`agent_sessions`, os aliases `analytics.*`) e políticas de linha na inicialização, portanto essas tabelas representam o quadro completo. + +### Configurar upload para nuvem + +O CronJob de backup inclui a etapa de upload para S3 (`aws s3 cp`) já configurada, e a base define um `BACKUP_BUCKET` padrão que você deve substituir pelo seu próprio bucket. + +**Na AWS:** você apenas define `BACKUP_BUCKET` para o seu bucket e concede acesso de escrita à ServiceAccount `agenteye-backup` via IRSA — sem necessidade de alterar o script. + +**No GCP / Azure:** você deve *substituir* a linha `aws s3 cp` incluída no script do CronJob pelo comando correspondente abaixo — não apenas adicionar o seu, porque o `aws s3 cp` restante é executado sob `set -eu` e falha o job. + +| Cloud | Comando de Upload | +|---|---| +| **AWS S3** | `aws s3 cp /tmp/${FILENAME} s3://${BACKUP_BUCKET}/${FILENAME}` (padrão incluído) | +| **GCP Cloud Storage** | `gsutil cp /tmp/${FILENAME} gs://${BACKUP_BUCKET}/${FILENAME}` | +| **Azure Blob** | `az storage blob upload -f /tmp/${FILENAME} -c backups -n ${FILENAME}` | + +Um objeto por execução significa que uma regra de ciclo de vida do bucket (ex.: "excluir após 30 dias") limpa backups completos de forma \ No newline at end of file diff --git a/docs/pt-br/agenteye/managed-deployment.mdx b/docs/pt-br/agenteye/managed-deployment.mdx new file mode 100644 index 00000000..a3348888 --- /dev/null +++ b/docs/pt-br/agenteye/managed-deployment.mdx @@ -0,0 +1,171 @@ +--- +title: "Implantação Gerenciada no Seu Cluster Kubernetes" +description: "Documentação da Implantação Gerenciada do AgentEye no Seu Cluster Kubernetes." +--- + + +O AgentEye é uma plataforma de observabilidade e avaliação self-hosted para agentes de IA e LLM. Ele captura sessões de agentes, chamadas de ferramentas, requisições de modelos e erros, transforma-os em análises e avaliações pesquisáveis, e exibe os resultados em um dashboard com um assistente de IA opcional somente leitura. + +No modelo de implantação gerenciada, você fornece um cluster Kubernetes dedicado e a Exosphere executa toda a plataforma dentro dele, implantando, configurando, operando, fazendo backup e atualizando cada componente em seu nome. Sua equipe obtém o valor da plataforma (visibilidade dos agentes, análises, avaliação e o assistente opcional) sem precisar operar bancos de dados, certificados ou atualizações. Todos os dados permanecem dentro da sua conta na nuvem. + +--- + +## Pré-requisitos + +- Um **GitHub PAT** para baixar imagens de contêiner e artefatos (consulte [Configuração do Token GitHub](/pt-br/agenteye/github-token)) +- Um **cluster Kubernetes dedicado** (consulte os requisitos abaixo) +- Um **bucket de armazenamento** para backups do banco de dados +- **Conectividade de rede**: porta 443 de entrada para o load balancer do cluster + +--- + +## Etapa 1: Provisionar um Cluster Kubernetes Dedicado + +Crie um cluster Kubernetes dedicado ao AgentEye. Ele não deve ser compartilhado com outras cargas de trabalho, para que toda a plataforma (serviços de aplicação, bancos de dados, análises e cache) seja executada em isolamento sem impactar sua infraestrutura existente. + +| Requisito | Detalhes | +|---|---| +| **Distribuição** | Qualquer Kubernetes compatível: EKS, GKE, AKS ou autogerenciado | +| **Versão** | 1.27 ou superior | +| **Pool de nós** | Mínimo: **3 nós, 4 vCPU / 8 GB de RAM cada** (instâncias de uso geral padrão) | +| **Armazenamento** | Uma StorageClass padrão que provisiona volumes em bloco (ex.: `gp3` na AWS, `pd-ssd` no GCP) | +| **Load Balancer** | O cluster deve ser capaz de provisionar serviços LoadBalancer na nuvem (padrão em EKS, GKE, AKS) | + +> A Exosphere instala e gerencia tudo o mais dentro do cluster: controladores de ingresso, certificados TLS, bancos de dados, cache, monitoramento e todos os deployments de aplicação. + +--- + +## Etapa 2: Conceder Acesso à Equipe AgentEye + +A Exosphere precisa de acesso cluster-admin (ou RBAC amplo equivalente) para gerenciar namespaces, definições de recursos personalizados, controladores de ingresso e provisionadores de armazenamento. + +| Requisito | Detalhes | +|---|---| +| **Método de acesso** | Função IAM (preferida para EKS/GKE), kubeconfig ou acesso baseado em SSO | +| **VPN / bastion** | Se o servidor de API do Kubernetes for privado, forneça credenciais de VPN ou acesso via bastion para a equipe de operações da Exosphere | + +--- + +## Etapa 3: Configurar a Conectividade de Rede + +Sua equipe de rede precisa permitir tráfego de entrada na **porta 443** para os load balancers do cluster. A implantação utiliza dois load balancers separados: um para ingestão de eventos (protegido por mTLS) e outro para o dashboard: + +| Tráfego | Origem | Destino | Segurança | +|---|---|---|---| +| **Ingestão de eventos** | Pods coletores nos seus clusters | Load Balancer de ingestão, porta 443 | mTLS (certificado de cliente) + chave de API | +| **Dashboard** | Navegadores dos desenvolvedores | Load Balancer do dashboard, porta 443 | HTTPS no seu domínio, login por OTP de e-mail sem senha | + +O endpoint de ingestão é protegido por TLS mútuo; os coletores devem apresentar um certificado de cliente válido **e** uma chave de API válida em cada requisição. O dashboard é executado em seu próprio load balancer e hostname, com acesso restrito aos endereços de e-mail/domínios autorizados por você. + +**Registros DNS (uma única vez):** você cria dois registros CNAME em um domínio que você controla — um para o endpoint de ingestão e outro para o dashboard (ex.: `agenteye.sua-empresa.exemplo`) — apontando para os hostnames do load balancer fornecidos pela Exosphere. A Exosphere então provisiona automaticamente certificados TLS de confiança pública para ambos os hostnames, incluindo as renovações. + +> **Observação sobre a porta 80:** a emissão e renovação automáticas de certificados são validadas via HTTP na porta 80 de cada load balancer. Se a sua política de segurança exigir restringir o load balancer do dashboard a faixas de IP corporativas, informe a Exosphere primeiro — nós mudamos a validação de certificados para o método baseado em DNS (um registro DNS extra do seu lado) para que as renovações continuem funcionando com a restrição ativa. + +> **Saída:** Os nós do cluster precisam de acesso à internet para baixar imagens de contêiner de `ghcr.io`. Se a sua rede restringe o tráfego de saída, adicione `ghcr.io` à lista de permissões ou espelhe as imagens para o seu registro interno. + +--- + +## Etapa 4: Fornecer um Bucket de Armazenamento para Backup + +Os backups do banco de dados são armazenados em um bucket de armazenamento na nuvem que pertence a você. + +| Requisito | Detalhes | +|---|---| +| **Serviço** | S3 (AWS), GCS (GCP) ou Azure Blob Storage | +| **Acesso** | Conceda acesso de escrita aos nós do cluster via função IAM para contas de serviço (IRSA no EKS, Workload Identity no GKE) ou forneça credenciais | +| **Retenção** | Você controla a política de ciclo de vida do bucket (período de retenção, regras de arquivamento). A Exosphere grava os backups; você decide por quanto tempo mantê-los | + +Um único backup diário exporta tanto o PostgreSQL (estado relacional) quanto o ClickHouse (eventos e avaliações) em um arquivo compactado e o envia ao seu bucket. Os backups também são executados antes de cada atualização. + +--- + +## Etapa 5: Designar um Ponto de Contato + +Indique uma pessoa ou canal do Slack/Teams no seu lado para questões no nível do cluster: saúde dos nós, limites da conta na nuvem, mudanças de rede. As operações do dia a dia não envolvem esse contato. + +--- + +## O Que Implantamos + +Assim que a Exosphere obtiver acesso ao cluster, os seguintes componentes serão implantados e gerenciados para você: + +| Componente | Função | +|---|---| +| **AgentEye Server** | API HTTP que recebe eventos dos coletores, executa análises e fornece dados ao dashboard | +| **Dashboard** | Interface web para visualização de sessões de agentes, chamadas de ferramentas, requisições de modelos e erros; hospeda o assistente de IA opcional somente leitura | +| **ClickHouse** | Armazenamento canônico obrigatório para eventos ingeridos, análises e avaliações | +| **PostgreSQL** | Armazenamento relacional para organizações, chaves de API, usuários, dashboards e consultas salvas | +| **Redis** | Cache compartilhado opcional e backend de limitação de taxa; a plataforma degrada graciosamente se não estiver disponível | +| **Assistente de IA (opcional)** | Contêiner assistente interno somente leitura; permanece desativado até que um endpoint de LLM seja configurado | +| **Controladores de ingresso** | Dois load balancers (um para ingestão protegida por mTLS, outro para o dashboard) encerrando TLS com certificados de confiança pública e renovação automática, e aplicando mTLS no endpoint de ingestão | +| **cert-manager** | Automatiza o provisionamento de certificados TLS e a emissão de certificados de cliente mTLS | +| **Monitoramento de certificados** | Um job agendado verifica a expiração dos certificados e envia alertas (ex.: para o Slack) conforme os certificados se aproximam da renovação | + +A oferta gerenciada também opera o pipeline de avaliação da plataforma, que pontua a atividade dos agentes com base nos seus critérios de avaliação. Consulte [Assistente](/pt-br/agenteye/assistant) e [Suite de Avaliação](/pt-br/agenteye/evaluation-suite) para saber o que essas capacidades oferecem. + +--- + +## O Que Fornecemos a Você + +Após a conclusão da implantação, você recebe: + +| Item | Detalhes | +|---|---| +| **URL do Dashboard** | Um hostname no seu domínio (ex.: `https://agenteye.sua-empresa.exemplo`), servido com um certificado TLS de confiança pública e renovação automática. Você cria um CNAME para o hostname do load balancer que fornecemos; o login é por OTP de e-mail sem senha | +| **Endpoint do coletor** | O caminho `/events` do hostname de ingestão (ex.: `https://ingest.sua-empresa.exemplo/events`), protegido por mTLS | +| **Bundle de certificado de cliente** | Por cluster: certificado de cliente, chave privada e certificado CA entregues como um manifesto de Secret do Kubernetes. Aplique uma vez por cluster | +| **GitHub PAT** | Para download de binários do coletor e pacotes do SDK Python | +| **Chaves de API do coletor** | Chaves com escopo de permissão `events:add`, uma por implantação de coletor | +| **Guias de instalação** | Documentação passo a passo para o coletor e o SDK Python | + +--- + +## O Que Você Faz Após a Configuração + +O único trabalho contínuo é nas suas próprias máquinas de agentes, não no cluster do AgentEye: + +1. **Instale o coletor** em cada cluster Kubernetes que executa agentes de IA: monte o certificado de cliente e configure a URL do endpoint e a chave de API. Consulte [Instalação do Coletor](/pt-br/agenteye/collector-installation). +2. **Integre o SDK Python** ao código do seu agente. Consulte [SDK Python](/pt-br/agenteye/python-sdk). +3. **Abra o dashboard** no seu navegador para visualizar a atividade dos agentes. + +Sem operações de cluster, sem gerenciamento de banco de dados, sem renovações de certificados, sem atualizações. + +--- + +## Segurança + +- **Os dados permanecem na sua conta na nuvem.** O cluster, o armazenamento e os bancos de dados são executados no seu ambiente. Nenhum dado sai do seu perímetro. +- **Você controla o acesso.** O cluster está na sua conta. Você pode auditar, monitorar ou revogar o acesso da Exosphere a qualquer momento. Todas as operações passam pelo log de auditoria da sua nuvem (CloudTrail, GCP Audit Logs, etc.). +- **mTLS na ingestão de eventos.** Cada requisição do coletor exige tanto um certificado de cliente válido quanto uma chave de API. Uma chave vazada é inútil sem o certificado; um certificado roubado é inútil sem uma chave válida. +- **Controle de acesso ao dashboard.** O dashboard é executado em seu próprio load balancer, separado da ingestão de eventos, e o login é por OTP de e-mail sem senha, restrito aos endereços de e-mail/domínios autorizados por você. Uma lista de permissões de faixas de IP de origem no load balancer está disponível mediante solicitação; como a renovação automática de certificados precisa acessar o load balancer, a Exosphere combina a restrição com a validação de certificados baseada em DNS para que as renovações continuem funcionando. +- **Certificados por cluster.** Cada um dos seus clusters recebe seu próprio certificado de cliente. Se um cluster for comprometido, esse certificado é revogado de forma independente, sem afetar os demais. + +--- + +## Cronograma de Implantação + +| Fase | Duração | Seu envolvimento | +|---|---|---| +| **Provisionamento do cluster** | 1-2 dias | Provisionar o cluster e conceder acesso à Exosphere | +| **Configuração da plataforma** | 1 dia | Nenhum; a Exosphere instala todos os componentes de infraestrutura | +| **Implantação da aplicação** | 1 dia | Nenhum; a Exosphere implanta o servidor, o dashboard e cria as chaves de API | +| **Rollout do coletor** | 1-3 dias | Instalar os coletores nos seus clusters (com orientação da Exosphere) | +| **Burn-in em produção** | 1 semana | Nenhum; a Exosphere monitora e ajusta | + +Total típico: **~2 semanas** do kickoff até a produção pronta. + +--- + +## Suporte + +Para dúvidas ou problemas, entre em contato com a Exosphere em `support@exosphere.host`. + +--- + +## Próximos Passos + +- [Primeiros Passos](/pt-br/agenteye/getting-started): guia completo de ponta a ponta +- [Instalação do Coletor](/pt-br/agenteye/collector-installation): instalar e configurar o coletor +- [SDK Python](/pt-br/agenteye/python-sdk): instrumentar o código do seu agente +- [Chaves de API](/pt-br/agenteye/api-keys): gerenciar acesso e permissões +- [Solução de Problemas](/pt-br/agenteye/troubleshooting): problemas comuns e soluções \ No newline at end of file diff --git a/docs/pt-br/agenteye/python-sdk.mdx b/docs/pt-br/agenteye/python-sdk.mdx new file mode 100644 index 00000000..5d02f3af --- /dev/null +++ b/docs/pt-br/agenteye/python-sdk.mdx @@ -0,0 +1,382 @@ +--- +title: "Python SDK" +description: "Documentação do AgentEye Python SDK." +--- + +O AgentEye Python SDK oferece visibilidade completa sobre o comportamento dos seus agentes (cada execução de agente, chamada de ferramenta, requisição de modelo, hook e intervenção humana) para que você possa depurá-los, auditá-los e avaliá-los. Ele instrumenta o código do agente gravando eventos estruturados em arquivos JSONL locais; o daemon coletor os captura e os envia automaticamente para a plataforma. + +--- + +## Instalação + +Baixe o wheel a partir das GitHub Releases usando seu `AGENTEYE_TOKEN`. Caso ainda não tenha um token, consulte [Configuração do Token GitHub](/pt-br/agenteye/github-token) para ver os passos de configuração e as permissões necessárias. + +**Usando `gh` CLI + pip:** + +```bash +VERSION=0.0.1b9 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "python-sdk/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-*.whl' +pip install "agenteye-${VERSION}-py3-none-any.whl" +``` + +**Usando `gh` CLI + uv:** + +```bash +VERSION=0.0.1b9 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "python-sdk/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-*.whl' +uv add "./agenteye-${VERSION}-py3-none-any.whl" +``` + +**Usando curl (sem `gh` CLI):** + +```bash +VERSION=0.0.1b9 +curl -fsSL \ + -H "Authorization: Bearer $AGENTEYE_TOKEN" \ + -L \ + "https://github.com/agenteye-enterprise/releases/releases/download/python-sdk%2Fv${VERSION}/agenteye-${VERSION}-py3-none-any.whl" \ + -o "agenteye-${VERSION}-py3-none-any.whl" +pip install "agenteye-${VERSION}-py3-none-any.whl" +``` + +--- + +## Início Rápido + +```python +import agenteye + +agenteye.configure(environment="production") + +agenteye.event.agent_start(session_id="run-001", agent_id="planner", goal="answer user query") + +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", + input={"query": "latest AI research"}, +) + +agenteye.event.tool_result( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", + output={"results": ["..."]}, +) + +agenteye.event.agent_end(session_id="run-001", agent_id="planner", outcome="success") +``` + +--- + +## configure() + +```python +agenteye.configure( + base_dir=None, # Path | str | None. Padrão: $AGENTEYE_HOME ou ~/.agenteye + flush_interval=0.5, # float, segundos entre ciclos de flush + environment=None, # str | None. Rótulo do ambiente de implantação +) +``` + +Chame uma vez antes de qualquer chamada `event.*`. É seguro omitir; os padrões funcionam imediatamente. Todos os argumentos são apenas por palavra-chave; passe-os pelo nome conforme mostrado acima. + +Quando `base_dir` é `None` (o padrão), o SDK lê `$AGENTEYE_HOME` se definido, caso contrário, usa `~/.agenteye`. Isso corresponde à própria resolução do coletor, de modo que uma única variável de ambiente `AGENTEYE_HOME` configura o spool de eventos compartilhado tanto para o SDK quanto para o coletor — necessário para implantações em sidecar/single-pod onde ambos os processos precisam concordar com o caminho do spool. + +--- + +## Ambiente + +Rotule cada evento com um ambiente de implantação (`production`, `staging`, `qa`, `canary`, etc.). Defina uma vez; o SDK o vincula a cada evento automaticamente. + +**Opção 1: via `configure()`:** + +```python +agenteye.configure(environment="production") +``` + +**Opção 2: via variável de ambiente:** + +```bash +export AGENTEYE_ENVIRONMENT=production +``` + +**Prioridade:** `configure(environment=...)` tem precedência sobre a variável de ambiente. Se nenhum dos dois for definido, o padrão é `"dev"`. + +O valor do ambiente aparece como um filtro de primeira classe no dashboard e é armazenado como uma coluna indexada no servidor para consultas rápidas. + +**Restrição:** os valores de ambiente **não devem conter uma vírgula `,` literal**. Os filtros do dashboard usam multi-seleção separada por vírgulas na requisição (`?environment=prod,staging`), portanto, um ambiente chamado `prod,blue` seria dividido em dois valores. Eventos com ambientes contendo vírgulas são rejeitados no momento da ingestão. + +--- + +## Referência de Eventos + +Todos os métodos de evento exigem estes dois campos: + +| Campo | Tipo | Descrição | +|---|---|---| +| `session_id` | `str` | Identifica a execução de agente de nível superior | +| `agent_id` | `str` | Identifica qual agente dentro da sessão emitiu o evento | + +Todos os métodos também aceitam `**kwargs` arbitrários para metadados personalizados (consulte [Campos Personalizados](#custom-fields)). + +--- + +### `event.agent_start()` + +Emitido quando um agente começa a trabalhar. + +```python +agenteye.event.agent_start( + session_id="run-001", + agent_id="planner", + goal="answer user query", # str | None + parent_id=None, # str | None - agent_id pai para agentes aninhados +) +``` + +--- + +### `event.agent_end()` + +Emitido quando um agente termina de trabalhar. + +```python +agenteye.event.agent_end( + session_id="run-001", + agent_id="planner", + outcome="success", # str | None + summary="Answered query", # str | None +) +``` + +--- + +### `event.tool_use()` + +Emitido quando um agente invoca uma ferramenta. Combine com `tool_result`; o SDK calcula `duration_ms` automaticamente. + +```python +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="web_search", # str, obrigatório + tool_call_id="toolu_01", # str, obrigatório - chave de correlação para o tool_result correspondente + input={"query": "..."}, # dict | None +) +``` + +--- + +### `event.tool_result()` + +Emitido quando uma ferramenta retorna. Correlaciona-se com `tool_use` via `tool_call_id`. + +```python +agenteye.event.tool_result( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", # deve corresponder ao tool_use anterior + output={"results": ["..."]}, # Any | None + error=None, # str | None - definido se a ferramenta lançou uma exceção + # duration_ms é calculado automaticamente - não passe este campo +) +``` + +--- + +### `event.model_request()` + +Emitido imediatamente antes de enviar um prompt para um LLM. + +```python +agenteye.event.model_request( + session_id="run-001", + agent_id="planner", + model="claude-sonnet-4-6", # str | None + messages=[ # list[dict] | None - turnos da conversa + {"role": "user", "content": "..."}, + ], + system="You are helpful.", # Any | None - str ou lista de blocos de conteúdo + tools=[ # list[dict] | None - esquemas de ferramentas oferecidos ao modelo + {"name": "search", "input_schema": {"type": "object"}}, + ], +) +``` + +As entradas de `messages` aceitam tanto um `content` em string simples quanto um `content` no estilo Anthropic de lista de blocos. Parâmetros de amostragem (`temperature`, `max_tokens`, etc.) podem ser passados como kwargs extras. + +--- + +### `event.model_response()` + +Emitido quando o LLM retorna uma resposta. + +```python +agenteye.event.model_response( + session_id="run-001", + agent_id="planner", + model="claude-sonnet-4-6", # str | None + stop_reason="end_turn", # str | None + input_tokens=1024, # int | None + output_tokens=256, # int | None + content=[ # Any | None - str, ou lista de blocos de conteúdo + {"type": "text", "text": "..."}, + ], + role="assistant", # str | None +) +``` + +`content` aceita tanto uma string simples (provedores genéricos) quanto uma lista de blocos de conteúdo no estilo Anthropic. Chamadas de ferramentas ficam dentro de `content` como blocos `{"type": "tool_use", ...}`, sem um campo `tool_calls` separado. + +--- + +### `event.hook_triggered()` + +Emitido quando um hook dispara. Combine com `hook_completed`; o SDK calcula `duration_ms` automaticamente. + +```python +agenteye.event.hook_triggered( + session_id="run-001", + agent_id="planner", + hook_name="pre_tool_use", # str, obrigatório + hook_id="hook-abc", # str, obrigatório - chave de correlação + trigger_event="tool_use", # str | None + input={"tool": "search"}, # Any | None +) +``` + +--- + +### `event.hook_completed()` + +Emitido quando um hook termina. Correlaciona-se com `hook_triggered` via `hook_id`. + +```python +agenteye.event.hook_completed( + session_id="run-001", + agent_id="planner", + hook_name="pre_tool_use", + hook_id="hook-abc", # deve corresponder ao hook_triggered anterior + outcome="allow", # str | None + output=None, # Any | None + error=None, # str | None + # duration_ms é calculado automaticamente - não passe este campo +) +``` + +--- + +### `event.error()` + +Emitido quando ocorre um erro não tratado. + +```python +agenteye.event.error( + session_id="run-001", + agent_id="planner", + error_type="TimeoutError", # str, obrigatório + message="timed out", # str, obrigatório + traceback="Traceback...", # str | None +) +``` + +--- + +## Eventos de Human-in-the-Loop + +Os eventos de human-in-the-loop oferecem supervisão sobre os momentos em que uma pessoa intervém na execução do agente (aguardando aprovação, fornecendo entrada, pausando ou interrompendo o agente). Eles permitem medir quanto tempo os humanos levam para responder (o SDK calcula `duration_ms` automaticamente nos eventos pareados), auditar quem pausou ou interrompeu um agente, e construir fluxos de trabalho de aprovação e supervisão que aparecem no dashboard. + +### `event.human_wait()` + +Emitido quando o agente pausa a execução para aguardar que um humano forneça entrada. Combine com `human_input`; o SDK calcula `duration_ms` automaticamente (quanto tempo o humano levou para responder). + +```python +agenteye.event.human_wait( + session_id="run-001", + agent_id="planner", + input_id="inp-abc", # str, obrigatório - chave de correlação para o human_input correspondente + prompt="Do you approve this action?", # str | None - a pergunta exibida ao humano + options=["approve", "reject", "defer"], # list[str] | None - opções apresentadas ao humano + reason="approval_required", # str | None - por que o agente está aguardando +) +``` + +### `event.human_input()` + +Emitido quando um humano fornece entrada e o agente retoma a execução. Correlaciona-se com `human_wait` via `input_id`. `duration_ms` é calculado automaticamente e não deve ser passado pelo chamador. + +```python +agenteye.event.human_input( + session_id="run-001", + agent_id="planner", + input_id="inp-abc", # str, obrigatório - deve corresponder ao human_wait anterior + response="approve", # str | None - a resposta do humano (texto livre ou opção selecionada) + # duration_ms é calculado automaticamente - não passe este campo +) +``` + +### `event.human_pause()` + +Emitido quando um humano pausa ativamente o agente (por exemplo, via controle no dashboard). O agente é suspenso, mas não encerrado. + +```python +agenteye.event.human_pause( + session_id="run-001", + agent_id="planner", + reason="user_requested", # str | None + user_id="usr_42", # str | None - quem pausou o agente +) +``` + +### `event.human_interrupt()` + +Emitido quando um humano para ativamente o agente no meio da execução. Diferente de `human_pause`, o trabalho do agente é encerrado em vez de suspenso. + +```python +agenteye.event.human_interrupt( + session_id="run-001", + agent_id="planner", + reason="output_incorrect", # str | None + user_id="usr_42", # str | None - quem interrompeu o agente + at_step="tool_use:web_search", # str | None - o que o agente estava fazendo quando foi parado +) +``` + +--- + +## Campos Personalizados + +Quaisquer argumentos de palavra-chave extras são acrescentados ao evento após os campos padrão: + +```python +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="db_query", + tool_call_id="toolu_02", + tenant_id="acme", # campo personalizado + region="us-east-1", # campo personalizado +) +``` + +`timestamp`, `type` e `environment` são reservados e lançam `ValueError` (`Reserved field names cannot be used as custom fields: [...]`) se passados como campos personalizados. `session_id` e `agent_id` são parâmetros obrigatórios em todos os métodos de evento e não podem ser fornecidos uma segunda vez; o Python lança `TypeError` se isso ocorrer. Defina o ambiente com `configure(environment=...)` (ou a variável `AGENTEYE_ENVIRONMENT`) em vez disso. + +--- + +## Como os Eventos São Gravados + +Os eventos são armazenados em buffer no processo e descarregados em disco a cada `flush_interval` segundos (padrão de 500 ms). Cada descarga grava um arquivo JSONL: + +``` +~/.agenteye/events/event-2026-04-01T12-00-00-000Z.jsonl +``` + +O coletor monitora este diretório e faz o upload dos arquivos automaticamente. Você não precisa gerenciar esses arquivos diretamente. \ No newline at end of file diff --git a/docs/pt-br/agenteye/single-pod-deployment.mdx b/docs/pt-br/agenteye/single-pod-deployment.mdx new file mode 100644 index 00000000..74dd76a5 --- /dev/null +++ b/docs/pt-br/agenteye/single-pod-deployment.mdx @@ -0,0 +1,484 @@ +--- +title: "Implantação em Pod Único: Coletor + Sidecar de Aplicação no EKS" +description: "Documentação do AgentEye para implantação em pod único: Coletor + Sidecar de Aplicação no EKS." +--- + + +Execute sua aplicação e o coletor AgentEye **no mesmo Pod do Kubernetes** para que a telemetria nunca precise cruzar um limite de rede para ser coletada. O SDK da sua aplicação e o coletor compartilham um único spool de eventos dentro do pod, o que garante handoff de telemetria com baixa latência, sem necessidade de expor uma porta localhost, sem service mesh para atravessar, e com o ciclo de vida do coletor diretamente vinculado à carga de trabalho que ele observa. O certificado de cliente mTLS que o coletor apresenta é entregue diretamente no seu pod a partir do AWS Secrets Manager, de modo que a rotação de credenciais não exige nenhuma manipulação manual de arquivos da sua parte. + +O modelo sidecar + spool compartilhado descrito aqui é agnóstico em relação à nuvem; dois contêineres compartilhando um spool de eventos `emptyDir` funciona em qualquer distribuição Kubernetes. Apenas o caminho de entrega do certificado neste guia (AWS Secrets Manager + Secrets Store CSI Driver + IRSA) é específico para AWS/EKS. Se você operar em outro ambiente, mantenha o layout do pod e do spool e substitua o mecanismo de montagem de segredos da sua plataforma pelas Fases 2 e 3. + +> **Quando usar este padrão.** Opte pelo pod único quando sua aplicação não deve fazer chamadas através de um limite de rede para alcançar o coletor (IPC intra-pod de baixa latência, acoplamento rigoroso de ciclo de vida, isolamento de pod por tenant). Para frotas multi-aplicação que compartilham um único coletor por nó ou por cluster, consulte [enterprise-docs/kubernetes-deployment.md](/pt-br/agenteye/kubernetes-deployment). + +--- + +## Visão geral + +``` +┌──────────────────────────────── Pod ─────────────────────────────────┐ +│ │ +│ ┌──────────────────────┐ ┌──────────────────────┐ │ +│ │ your-app │ │ agenteye-collector │ │ +│ │ (SDK writes JSONL) │ │ (sweeps events/, │ │ +│ │ │ │ uploads over mTLS) │ │ +│ └──────────┬───────────┘ └──────────┬───────────┘ │ +│ │ writes reads │ │ +│ ▼ ▼ │ +│ ┌────────────────────────────────────────────────────┐ │ +│ │ emptyDir: /var/lib/agenteye/{events,failed}/ │ │ +│ │ (AGENTEYE_HOME - shared event spool) │ │ +│ └────────────────────────────────────────────────────┘ │ +│ ▲ │ +│ │ reads cert │ +│ ┌────────┴─────────┐ │ +│ │ CSI (read-only): │ │ +│ │ /etc/agenteye/ │ │ +│ │ tls/client.{crt, │ │ +│ │ key}, ca.crt │ │ +│ └────────┬─────────┘ │ +└───────────────────────────────────────────────────┼──────────────────┘ + │ mounted by + │ Secrets Store CSI + │ (AWS provider + + │ IRSA) + ┌────────┴──────────┐ + │ AWS Secrets │ + │ Manager │ + │ agenteye/mtls- │ + │ client/ │ + └────────┬──────────┘ + ▲ + │ push on issue / + │ renewal + ┌────────┴──────────┐ + │ Exosphere │ + │ delivers the cert │ + │ bundle into your │ + │ Secrets Manager │ + │ on renewal │ + └───────────────────┘ + +Outbound: collector → AGENTEYE_URL (mTLS, using the CSI-mounted cert). +``` + +Dois fluxos de dados, dois volumes: + +- **Eventos (intra-pod):** o SDK da sua aplicação grava arquivos `.jsonl` no `emptyDir` compartilhado em `$AGENTEYE_HOME/events/`; o sweeper do coletor os lê e realiza o upload. Sem porta localhost, sem loopback, handoff puro via sistema de arquivos compartilhado. +- **Certificado mTLS (pod ← nuvem):** o Secrets Store CSI Driver monta o bundle de certificados do Secrets Manager em um volume somente leitura em `/etc/agenteye/tls/`, com escopo para o contêiner do coletor. + +**Duas partes independentes:** + +| Parte | Responsabilidade | +|---|---| +| Exosphere | Emite o certificado de cliente mTLS e entrega o bundle no Secrets Manager da **sua** conta AWS com um nome estável. Republica o bundle renovado no mesmo segredo antes do vencimento. | +| Você | Instala o Secrets Store CSI Driver, concede ao ServiceAccount do pod acesso de leitura ao segredo via IRSA e aplica o manifesto do Pod. Só isso. | + +--- + +## Pré-requisitos + +### Na sua conta AWS / cluster EKS + +- Um cluster EKS com um **provedor OIDC** associado. Confirme com: + + ```bash + aws eks describe-cluster --name \ + --query "cluster.identity.oidc.issuer" --output text + ``` + + Se o comando retornar uma URL `https://oidc.eks.…`, o OIDC está habilitado. Caso contrário, associe um: + + ```bash + eksctl utils associate-iam-oidc-provider \ + --cluster --approve + ``` + +- O [Secrets Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/) e o [AWS provider](https://github.com/aws/secrets-store-csi-driver-provider-aws) instalados no cluster (consulte a § Fase 2). + +- AWS CLI v2 e `kubectl` na sua estação de trabalho. + +### Coordenação com a Exosphere + +Antes de fazer a implantação, a Exosphere entrega o bundle de cliente mTLS no Secrets Manager da sua conta AWS e fornece: + +- O **nome do segredo** (convenção: `agenteye/mtls-client/`) +- A **região AWS** onde o segredo está armazenado +- A **URL do backend do AgentEye** para configurar o coletor +- Sua **chave de API** do coletor (consulte [enterprise-docs/api-keys.md](/pt-br/agenteye/api-keys)) + +--- + +## Fase 1: O que a Exosphere entrega + +Você não gera o certificado de cliente mTLS por conta própria. A Exosphere o emite e entrega o bundle diretamente no Secrets Manager da sua conta AWS, de modo que o único material de credencial que chega ao seu ambiente é o segredo pronto para montagem. + +O que chega na sua conta: + +| Propriedade | Valor | +|---|---| +| Nome do segredo | `agenteye/mtls-client/` (estável entre renovações) | +| Região | A região AWS que você indicou para o seu cluster EKS | +| Payload | Um único segredo JSON com três chaves (`client.crt`, `client.key` e `ca.crt`), cada uma contendo o material codificado em PEM | +| Tag | `AgentEyeCluster=` | + +Na renovação, o mesmo segredo é atualizado no local com uma nova versão, de modo que o ARN e o nome nunca mudam; sua `SecretProviderClass` e política IAM continuam funcionando sem alterações. Para o ciclo de vida do certificado (validade, cadência de renovação, alertas de vencimento), consulte [enterprise-docs/kubernetes-deployment.md](/pt-br/agenteye/kubernetes-deployment). + +--- + +## Fase 2: Instalar o Secrets Store CSI Driver + AWS provider + +Pule esta etapa se você já executa outra carga de trabalho que monta segredos AWS via CSI. + +```bash +# CSI Driver +helm repo add secrets-store-csi-driver \ + https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts +helm install -n kube-system csi-secrets-store \ + secrets-store-csi-driver/secrets-store-csi-driver \ + --set syncSecret.enabled=true \ + --set enableSecretRotation=true \ + --set rotationPollInterval=1h + +# AWS provider +kubectl apply -f \ + https://raw.githubusercontent.com/aws/secrets-store-csi-driver-provider-aws/main/deployment/aws-provider-installer.yaml +``` + +**Verificação:** + +```bash +kubectl get pods -n kube-system | grep -E 'csi-secrets-store|aws-provider' +``` + +Esperado: `Running` para todos os pods. + +> **Por que `rotationPollInterval=1h`?** Quando a Exosphere publica um certificado renovado, o Secrets Manager é atualizado no local. O CSI Driver relê o segredo nesse intervalo e regrava os arquivos montados. O coletor lê os arquivos de certificado uma única vez na inicialização, portanto começa a apresentar o certificado renovado apenas após uma reinicialização do processo; consulte a § Rotação de certificados para saber como acionar uma. + +--- + +## Fase 3: Conceder ao pod acesso de leitura ao segredo (IRSA) + +### 3.1 Criar a política IAM + +Salve como `agenteye-mtls-reader-policy.json`: + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "ReadAgentEyeMtlsBundle", + "Effect": "Allow", + "Action": [ + "secretsmanager:GetSecretValue", + "secretsmanager:DescribeSecret" + ], + "Resource": "arn:aws:secretsmanager:::secret:agenteye/mtls-client/-*" + } + ] +} +``` + +Substitua ``, `` e ``. O `-*` no final corresponde ao sufixo aleatório de seis caracteres que a AWS acrescenta a cada ARN de segredo. + +Crie a política: + +```bash +aws iam create-policy \ + --policy-name AgentEyeMtlsReader- \ + --policy-document file://agenteye-mtls-reader-policy.json +``` + +### 3.2 Criar a função IAM e vinculá-la ao ServiceAccount do pod + +```bash +eksctl create iamserviceaccount \ + --name agenteye-pod \ + --namespace \ + --cluster \ + --role-name AgentEyePodRole- \ + --attach-policy-arn arn:aws:iam:::policy/AgentEyeMtlsReader- \ + --approve +``` + +Isso cria um `ServiceAccount` chamado `agenteye-pod` com a anotação `eks.amazonaws.com/role-arn` apontando para a nova função. + +### 3.3 Permissões IAM necessárias: resumo + +| Permissão | Escopo | Motivo | +|---|---|---| +| `secretsmanager:GetSecretValue` | `arn:aws:secretsmanager:::secret:agenteye/mtls-client/-*` | O CSI Driver lê o bundle de certificados a cada montagem e a cada tick de rotação. | +| `secretsmanager:DescribeSecret` | mesmo | O CSI Driver chama `DescribeSecret` para detectar mudanças de versão entre as consultas. | + +**Não conceda** `secretsmanager:PutSecretValue`, `secretsmanager:UpdateSecret` ou `secretsmanager:DeleteSecret` ao pod. O pod apenas lê o segredo; a gravação de novas versões é responsabilidade da Exosphere quando o certificado é emitido ou renovado. + +Se o segredo estiver criptografado com uma chave KMS gerenciada pelo cliente (e não a chave padrão `aws/secretsmanager`), conceda também: + +```json +{ + "Effect": "Allow", + "Action": ["kms:Decrypt"], + "Resource": "arn:aws:kms:::key/", + "Condition": { + "StringEquals": { + "kms:ViaService": "secretsmanager..amazonaws.com" + } + } +} +``` + +--- + +## Fase 4: Implantar o Pod + +### 4.1 SecretProviderClass + +`agenteye-mtls-spc.yaml`: + +```yaml +apiVersion: secrets-store.csi.x-k8s.io/v1 +kind: SecretProviderClass +metadata: + name: agenteye-mtls + namespace: +spec: + provider: aws + parameters: + objects: | + - objectName: "agenteye/mtls-client/" + objectType: "secretsmanager" + jmesPath: + - path: '"client.crt"' + objectAlias: "client.crt" + - path: '"client.key"' + objectAlias: "client.key" + - path: '"ca.crt"' + objectAlias: "ca.crt" +``` + +O bloco `jmesPath` instrui o AWS provider a dividir o segredo JSON em três arquivos separados no disco. As aspas em `'"client.crt"'` são obrigatórias porque o JMESPath trata `.` como operador de sub-expressão. + +```bash +kubectl apply -f agenteye-mtls-spc.yaml +``` + +### 4.2 Manifesto do Pod / Deployment + +**Como os dois contêineres se comunicam.** O SDK do AgentEye e o coletor não se comunicam via socket de rede; não há porta HTTP local. O SDK grava lotes de eventos como arquivos `.jsonl` em `$AGENTEYE_HOME/events/`, e o coletor monitora continuamente esse diretório e realiza o upload de cada arquivo. Para um pod sidecar, isso significa: + +- Ambos os contêineres montam o **mesmo** volume `emptyDir` no **mesmo** caminho. +- Ambos os contêineres definem `AGENTEYE_HOME` para esse caminho. +- A imagem da sua aplicação deve ter o SDK do AgentEye instalado e configurado (consulte [enterprise-docs/python-sdk.md](/pt-br/agenteye/python-sdk)). + +> Quando `AGENTEYE_HOME` não está definido, tanto o SDK quanto o coletor usam `~/.agenteye` como padrão, e os dois contêineres têm diretórios home diferentes, de modo que cada um utilizaria um spool separado e o handoff falharia silenciosamente. Defina `AGENTEYE_HOME` para o mesmo caminho explícito em **ambos** os contêineres. A verificação da §4.3 e a linha correspondente na seção de Solução de Problemas identificam esse erro caso seja cometido. + +`agenteye-pod.yaml` (Deployment com uma réplica, escale conforme necessário): + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-app-with-collector + namespace: +spec: + replicas: 1 + selector: + matchLabels: + app: my-app-with-collector + template: + metadata: + labels: + app: my-app-with-collector + spec: + serviceAccountName: agenteye-pod + containers: + - name: app + image: + env: + # SDK writes event JSONL files into $AGENTEYE_HOME/events/ + - name: AGENTEYE_HOME + value: /var/lib/agenteye + volumeMounts: + - name: agenteye-spool + mountPath: /var/lib/agenteye + + - name: agenteye-collector + # Pin to a versioned :v tag for production; :beta-latest + # tracks the current beta build (:latest exists only for stable releases). + image: ghcr.io/agenteye-enterprise/collector:beta-latest + args: ["start"] + env: + # Must match the app container's AGENTEYE_HOME so the collector + # sweeps the same directory the SDK writes to. + - name: AGENTEYE_HOME + value: /var/lib/agenteye + - name: AGENTEYE_URL + value: "https://ingest.example.agenteye.com/events" + - name: AGENTEYE_KEY + valueFrom: + secretKeyRef: + name: agenteye-collector-api-key + key: key + - name: AGENTEYE_TLS_CERT + value: /etc/agenteye/tls/client.crt + - name: AGENTEYE_TLS_KEY + value: /etc/agenteye/tls/client.key + # Only when the AgentEye server presents a cert not signed by a + # publicly-trusted CA (e.g. self-signed by an in-cluster issuer + # because you have no real DNS domain). The CSI mount already + # exposes ca.crt alongside the client cert/key. + - name: AGENTEYE_TLS_CA + value: /etc/agenteye/tls/ca.crt + volumeMounts: + - name: agenteye-spool + mountPath: /var/lib/agenteye + - name: agenteye-mtls + mountPath: /etc/agenteye/tls + readOnly: true + livenessProbe: + exec: + command: ["agenteye-collector", "health"] + initialDelaySeconds: 10 + periodSeconds: 30 + + volumes: + # Shared event spool between app and collector. emptyDir is fine: + # events are transient and the collector drains them before pod + # termination on graceful shutdown. + - name: agenteye-spool + emptyDir: {} + # mTLS cert bundle, mounted read-only into the collector only. + - name: agenteye-mtls + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: agenteye-mtls +``` + +O Secret `agenteye-collector-api-key` contém a chave de API do coletor (consulte [enterprise-docs/api-keys.md](/pt-br/agenteye/api-keys) para provisionamento). + +**Aplicar:** + +```bash +kubectl apply -f agenteye-pod.yaml +``` + +### 4.3 Verificação + +```bash +# O pod deve estar Running com 2/2 contêineres prontos +kubectl get pods -n -l app=my-app-with-collector + +# Confirmar que o bundle de certificados foi montado +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- ls -l /etc/agenteye/tls/ +``` + +Esperado: `client.crt`, `client.key` e `ca.crt` todos presentes, somente leitura e de propriedade do usuário do contêiner. + +**Confirmar que o spool de eventos compartilhado é visível para ambos os contêineres:** + +```bash +# No coletor, deve mostrar os subdiretórios events/ e failed/ que +# o coletor cria automaticamente na inicialização: +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- ls /var/lib/agenteye/ + +# Na aplicação, deve mostrar o mesmo conteúdo do diretório: +kubectl exec -n deploy/my-app-with-collector \ + -c app -- ls /var/lib/agenteye/ +``` + +Se as duas listagens divergirem, o volume não está montado em ambos os contêineres (ou `AGENTEYE_HOME` é diferente); consulte a § Solução de Problemas. + +**Teste de fumaça ponta a ponta:** + +```bash +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- agenteye-collector flush +``` + +Esperado: o coletor realiza o upload de todos os eventos enfileirados e exibe um resumo `Done: N/N uploaded, 0 failed.`. Se o spool estiver vazio, exibe `No pending files.` e encerra sem validar nada — portanto, execute isso apenas depois que sua aplicação tiver descarregado pelo menos um evento. + +Note que `flush` encerra com código diferente de zero **apenas** para falhas de configuração local: ausência de configuração (URL/chave não resolvidos) ou certificado TLS ilegível/não parseável (consulte § Solução de Problemas). Uma **chave de API incorreta não altera o código de saída** — o upload recebe um `401`, o arquivo é movido para `failed/`, e o comando ainda exibe `[FAILED] …` por arquivo mais `Done: 0/N uploaded, N failed.` e encerra com `0`. Para detectar uma chave inválida ou um upload rejeitado, leia a saída `Done:`/`[FAILED]` ou verifique se há arquivos em `$AGENTEYE_HOME/failed/`, não o código de saída. + +--- + +## Rotação de certificados + +O certificado de cliente é válido por 90 dias e é renovado automaticamente cerca de 15 dias antes do vencimento; a Exosphere então publica o bundle renovado no mesmo segredo do Secrets Manager. A partir daí, o fluxo intra-pod é: + +1. O segredo no Secrets Manager recebe uma nova versão `AWSCURRENT`. O ARN e o nome permanecem inalterados. +2. Dentro do `rotationPollInterval` (1h por padrão; consulte a § Fase 2), o CSI Driver lê a nova versão e regrava os arquivos em `/etc/agenteye/tls/`. +3. O coletor carrega os arquivos de certificado **uma vez na inicialização**, portanto continua apresentando o certificado anterior até que o processo seja reiniciado. Para alternar para o material renovado, reinicie o coletor; uma reinicialização gradual é suficiente: + + ```bash + kubectl rollout restart deploy/my-app-with-collector -n + ``` + + Para automatizar isso, adicione um sidecar que monitore `/etc/agenteye/tls/` (por exemplo, com `inotifywait`) e acione o rollout quando os arquivos mudarem. + +Como o certificado anterior permanece válido por cerca de 15 dias após a renovação, você tem uma janela ampla para realizar a reinicialização sem interromper a ingestão. A Exosphere publica o bundle renovado por você; a única ação rotineira da sua parte é garantir que o coletor seja reiniciado dentro dessa janela. + +--- + +## Solução de Problemas + +| Sintoma | Causa provável | Correção | +|---|---|---| +| Pod travado em `ContainerCreating`, eventos mostram `MountVolume.SetUp failed for volume "agenteye-mtls"` | O provedor CSI não consegue alcançar o Secrets Manager | Verifique se o IRSA está corretamente vinculado: `kubectl describe sa agenteye-pod -n ` deve mostrar a anotação `eks.amazonaws.com/role-arn`. Verifique o CloudTrail para a chamada AssumeRole. | +| Erro: `AccessDeniedException: not authorized to perform secretsmanager:GetSecretValue` | A política IAM está com escopo para o ARN errado | O sufixo do ARN do segredo é aleatório; use `agenteye/mtls-client/-*` com o curinga, não o ARN exato. | +| Erro: `ParameterNotFound` do AWS provider | Incompatibilidade de nome de segredo entre `SecretProviderClass.objects[].objectName` e o segredo entregue pela Exosphere | Confirme o nome exato com `aws secretsmanager list-secrets --filters Key=tag-key,Values=AgentEyeCluster`. | +| Erro de `jmesPath`, apenas um arquivo montado | Sintaxe JMESPath | Os pontos nas chaves JSON exigem aspas duplas: `'"client.crt"'`, não `client.crt`. | +| Coletor registra `tls: bad certificate` após uma renovação | O CSI Driver ainda não consultou a nova versão, ou o coletor ainda está rodando com o certificado anterior carregado na inicialização | Confirme que os arquivos montados foram atualizados (`ls -l /etc/agenteye/tls/`) e reinicie o coletor para carregá-los: `kubectl rollout restart deploy/my-app-with-collector -n `. Consulte § Rotação de certificados. | +| O contêiner do coletor entra em crashloop com `no such file or directory: /etc/agenteye/tls/client.crt` | Volume ainda não populado na primeira inicialização; probe de startup muito agressiva | Adicione um pequeno atraso inicial ou use um init container que aguarde o arquivo existir: `until [ -f /etc/agenteye/tls/client.crt ]; do sleep 1; done`. | +| Pod do CSI Driver com `OOMKilled` | Limites de memória padrão muito baixos para clusters com muitas SecretProviderClasses | Aumente com `--set linux.resources.limits.memory=200Mi` na instalação via Helm. | +| A aplicação roda normalmente, `agenteye-collector flush` reporta `No pending files.`, mas o dashboard do AgentEye não mostra eventos | A aplicação e o coletor não estão compartilhando o spool de eventos | Verifique se (a) ambos os contêineres montam o mesmo `emptyDir` `agenteye-spool` no mesmo caminho, e (b) ambos definem `AGENTEYE_HOME` para esse caminho. Execute as duas verificações `ls /var/lib/agenteye/` da § 4.3; as listagens devem ser idênticas. | + +**Logs para coletar primeiro:** + +```bash +kubectl logs -n kube-system -l app=secrets-store-csi-driver --tail=100 +kubectl logs -n kube-system -l app=csi-secrets-store-provider-aws --tail=100 +kubectl describe pod -n -l app=my-app-with-collector +``` + +--- + +## Referência: arquivos no disco do pod + +O pod possui dois caminhos de dados no disco: + +### Bundle de certificados mTLS: `/etc/agenteye/tls/` (CSI, somente leitura, apenas para o coletor) + +Montado pelo Secrets Store CSI Driver a partir do AWS Secrets Manager. + +| Arquivo | Conteúdo | Usado pelo coletor como | +|---|---|---| +| `client.crt` | Certificado de cliente codificado em PEM | `AGENTEYE_TLS_CERT` | +| `client.key` | Chave privada codificada em PEM | `AGENTEYE_TLS_KEY` | +| `ca.crt` | Certificado de CA codificado em PEM | `AGENTEYE_TLS_CA` (opcional, apenas quando o certificado do servidor AgentEye não é publicamente confiável) | + +Os três são montados somente leitura e de propriedade do usuário do contêiner. Eles são regravados pelo CSI Driver quando o segredo é rotacionado. + +### Spool de eventos: `$AGENTEYE_HOME/` (emptyDir, compartilhado com leitura/escrita entre ambos os contêineres) + +Compartilhado via volume `emptyDir` chamado `agenteye-spool`. + +| Caminho | Gravado por | Lido por | Finalidade | +|---|---|---|---| +| `$AGENTEYE_HOME/events/*.jsonl` | Aplicação (SDK do AgentEye) | Sweeper do coletor | Lotes de eventos descarregados pelo SDK, aguardando upload. | +| `$AGENTEYE_HOME/failed/` | Coletor (em caso de falha no upload) | Você (ao depurar) | Arquivos JSONL que o coletor não conseguiu enviar após as tentativas de retry. | +| `$AGENTEYE_HOME/config.json` | Você (opcional) | Coletor | Arquivo de configuração opcional do coletor (alternativa às variáveis de ambiente). | + +Ambos os subdiretórios `events/` e `failed/` são criados automaticamente pelo coletor na inicialização; nenhum `initContainer` é necessário. + +--- + +## Documentação relacionada + +- [enterprise-docs/collector-installation.md](/pt-br/agenteye/collector-installation): opções do binário do coletor, referência de configuração mTLS, modos daemon. +- [enterprise-docs/kubernetes-deployment.md](/pt-br/agenteye/kubernetes-deployment): implantação multi-pod, detalhes internos de emissão de certificados, ciclo de vida e alertas de vencimento. +- [enterprise-docs/api-keys.md](/pt-br/agenteye/api-keys): provisionamento da chave de API do coletor usada pelo pod. +- [enterprise-docs/troubleshooting.md](/pt-br/agenteye/troubleshooting): índice de solução de problemas para todo o cluster. \ No newline at end of file diff --git a/docs/pt-br/agenteye/tenant-management.mdx b/docs/pt-br/agenteye/tenant-management.mdx new file mode 100644 index 00000000..92dd8eac --- /dev/null +++ b/docs/pt-br/agenteye/tenant-management.mdx @@ -0,0 +1,166 @@ +--- +title: "Gerenciamento de Tenants (organizações e membros)" +description: "Documentação de Gerenciamento de Tenants do AgentEye (organizações e membros)." +--- + +Um único deployment do AgentEye atende múltiplas **organizações** (tenants) completamente isoladas, de modo que uma única instância pode hospedar times, unidades de negócio ou clientes distintos sem expor os dados de um tenant para outro. Cada linha de dados (eventos, avaliações, sessões, dashboards, consultas salvas, alertas, chaves de API e membros) pertence a exatamente uma org. O isolamento primário é aplicado no código da aplicação: cada requisição é delimitada à sua org com predicados explícitos `org_id`. No ClickHouse — onde vivem os eventos e avaliações de alto volume — isso é respaldado por uma aplicação forte no nível do motor: cada org recebe um usuário ClickHouse dedicado e somente leitura com uma política de linha por org, de modo que mesmo SQL analítico não confiável nunca consegue ler as linhas de outro tenant. No PostgreSQL, a segurança em nível de linha adiciona uma camada de defesa em profundidade no caminho de consulta somente leitura (`/queries/run`), restringindo o que esse caminho pode ver mesmo que um filtro no nível da aplicação esteja ausente; a própria conexão de escrita do servidor é executada como o proprietário da tabela e, portanto, opera pelo mesmo escopo `org_id` no nível da aplicação. + +O ciclo de vida do tenant é controlado pelo operador, enquanto tudo o que os membros fazem no dia a dia permanece como autoatendimento no dashboard. Organizações e suas associações são criadas e gerenciadas com a CLI **`agenteye-orgctl`**, que é distribuída dentro da imagem do servidor e executa **dentro do pod do servidor existente**. A criação e exclusão de tenants são deliberadamente mantidas fora do dashboard e da API HTTP: não há **API HTTP nem botão no dashboard** para o ciclo de vida do tenant, portanto ele fica protegido por trás do acesso ao shell do cluster/pod em vez da superfície da aplicação. + +Dentro de uma org, os membros trabalham inteiramente no dashboard e na API: eles fazem login, alternam entre as orgs às quais pertencem, gerenciam suas próprias chaves de API, constroem dashboards e consultas salvas, e configuram alertas para sua org. A divisão é clara: operadores provisionam e desativam tenants e seus membros via CLI; membros executam tudo dentro de um tenant pela UI. + +> **Deployments single-tenant não precisam de nada disso.** Uma instalação single-tenant funciona sem nenhuma ação do operador. Todos os dados, usuários e chaves vivem em uma organização `default` integrada que é provisionada automaticamente. Você só precisa deste guia quando decidir adicionar uma segunda org. + +--- + +## Pré-requisitos + +Antes de criar sua **segunda** organização (a org `default` integrada não precisa de nada): + +- **PostgreSQL 15+.** O esquema de membros da org usa uma chave estrangeira `ON DELETE SET NULL` com lista de colunas que requer PostgreSQL 15+. Faça o upgrade do PostgreSQL antes de provisionar uma segunda org. +- **Um `ORG_CH_SECRET` forte e estável.** A senha do ClickHouse de cada org é derivada como `HMAC(ORG_CH_SECRET, org_id)`, portanto o padrão de desenvolvimento integrado publicamente conhecido resultaria em credenciais por org publicamente deriváveis. `agenteye-orgctl org create` **se recusa a executar enquanto `ORG_CH_SECRET` não estiver definido ou estiver no padrão de desenvolvimento integrado**. Defina seu próprio valor primeiro (consulte [Deployment → variáveis de ambiente](/pt-br/agenteye/deployment) e, no Kubernetes, [§2.6 do guia Kubernetes](/pt-br/agenteye/kubernetes-deployment#26-multi-tenant-org-isolation-key-optional)). Mantenha-o idêntico em todas as réplicas do servidor e não o rotacione casualmente; rotacioná-lo torna órfão o usuário ClickHouse de cada org até que o próximo startup os reprovisionne. + +--- + +## Executando a CLI + +`agenteye-orgctl` é distribuída na **mesma imagem que o servidor** (junto com `agenteye-server`). Você **não** faz deploy de um pod, Job ou Deployment separado para ela; você a executa dentro do pod do servidor que já está em execução, de modo que ela lê o mesmo `DATABASE_URL`, `CLICKHOUSE_URL` e `ORG_CH_SECRET` que o servidor usa. + +**Kubernetes:** + +```bash +kubectl -n agenteye exec deploy/server -- agenteye-orgctl +``` + +**Docker Compose:** + +```bash +docker compose exec server agenteye-orgctl +``` + +Os exemplos abaixo mostram o `agenteye-orgctl ` simples por brevidade; prefixe cada um com uma das duas linhas acima que corresponda ao seu deployment. + +--- + +## Referência de comandos + +### Organizações + +| Comando | O que faz | +|---|---| +| `org create --slug --name ` | Cria uma nova organização. Se recusa a executar enquanto `ORG_CH_SECRET` não estiver definido ou estiver no padrão de desenvolvimento integrado (defina o seu próprio primeiro, veja Pré-requisitos). Provisiona o usuário ClickHouse somente leitura da org + política de linha. | +| `org list` | Lista todas as organizações (slug, nome e estado do ciclo de vida). | +| `org rename --slug --name ` | Altera o nome de exibição de uma organização. O slug (usado em URLs e chaves) permanece inalterado. | +| `org delete --slug ` | **Exclusão suave** da org e remoção do seu usuário ClickHouse. Os dados são **retidos**. Isso revoga o acesso e libera a credencial ClickHouse por org, mas não apaga os eventos. Reversível por ops; primeiro passo seguro antes de uma purga. | +| `org purge --slug ` | **Limpeza irreversível de dados.** A org já deve ter sido `delete`d. Nunca permitido na org `default` integrada. Use somente quando tiver certeza de que os dados do tenant devem ser destruídos. | + +### Membros + +| Comando | O que faz | +|---|---| +| `member add --org --email [--set ] [--add perm1,perm2] [--remove perm3] [--protected]` | Adiciona um membro a uma org. Opcionalmente começa a partir de um conjunto de permissões integrado, depois adiciona/remove permissões individuais. `--protected` fixa o membro para que o dashboard não possa removê-lo ou rebaixá-lo (veja abaixo). O novo membro recebe um OTP no primeiro login no dashboard. | +| `member list --org ` | Lista os membros da org. As colunas de saída são `EMAIL`, `SET` (o conjunto integrado do qual o membro partiu, ou `-`), `PROT` (se o membro é protegido) e `PERMISSIONS` (suas permissões efetivas). Um e-mail exibido com um `*` no final é um admin da instância; eles têm acesso a todas as orgs. | +| `member update --org --email [--set ...] [--add ...] [--remove ...] [--protected \| --unprotect]` | Altera as permissões e/ou o estado de proteção de um membro. `--set` substitui a partir de um conjunto integrado; `--add` / `--remove` ajustam permissões individuais; `--protected` / `--unprotect` alternam a proteção. Passar apenas `--protected`/`--unprotect` (sem flags de concessão) altera somente a proteção e deixa as permissões existentes intactas. | +| `member remove --org --email ` | Remove um membro da org. Se recusa se o membro for protegido; use `--unprotect` primeiro. (Uma pessoa pode ser membro de várias orgs; isso afeta apenas a org especificada.) | + +Uma pessoa pode ser membro de mais de uma org com permissões **diferentes** em cada uma, por exemplo, admin em uma org e somente leitura em outra. Cada associação é administrada de forma independente por org: conceder ou alterar as permissões de uma pessoa em uma org não tem efeito sobre sua associação em nenhuma outra. + +### Membros protegidos (um admin da org irremovível) + +A proteção garante que uma org nunca possa acidentalmente se bloquear do autogerenciamento. Por padrão, os admins de uma org podem adicionar e remover uns aos outros pela página de usuários de autoatendimento do dashboard, de modo que poderiam remover o último admin e deixar a org sem ninguém capaz de gerenciá-la. + +![A página de Usuários: um cartão por usuário do dashboard com seu e-mail, permissões concedidas e controles de edição/desativação](/agenteye/images/users.png) + +Para evitar isso, marque um membro como **protegido**: + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member add --org acme --email owner@acme.example --set admin --protected +``` + +Um membro protegido **não pode ser removido ou rebaixado pelo dashboard**; essas ações retornam um erro. Apenas um operador pode alterá-lo, e somente via esta CLI: execute `member update --org acme --email owner@acme.example --unprotect` primeiro, depois remova ou rebaixe. Isso garante que cada org mantenha pelo menos um admin que seus próprios membros não possam bloquear, ao mesmo tempo que mantém o controle do tenant exclusivamente para operadores. A proteção é **por org**; proteger alguém em uma org não tem efeito sobre sua associação em outra. + +### Conjuntos de permissões integrados + +`--set` aceita um dos três conjuntos integrados, aplicados por org: + +| Conjunto | Destinado para | +|---|---| +| `admin` | Acesso completo dentro da org, incluindo gerenciamento de chaves de API e usuários da org. | +| `standard` | Uso no dia a dia: leitura + execução de consultas, construção de dashboards, reconhecimento de incidentes. | +| `read-only` | Acesso somente visualização aos dados e dashboards da org. | + +Comece com um conjunto usando `--set`, depois ajuste com `--add` / `--remove` usando os tokens de permissão individuais listados em [API Keys](/pt-br/agenteye/api-keys). Os próprios tokens de permissão são idênticos aos usados para chaves de API. + +--- + +## Exemplo prático + +Provisione um novo tenant `acme`, adicione seu primeiro admin, deixe-o criar uma chave e, em seguida, desative a org. + +**1. Crie a org** (`ORG_CH_SECRET` já deve estar definido com um valor forte e estável, não indefinido ou o padrão de desenvolvimento integrado): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org create --slug acme --name "Acme Corp" +``` + +**2. Adicione o primeiro membro como admin da org:** + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member add --org acme --email alice@acme.example --set admin +``` + +Alice recebe um OTP na primeira vez que faz login no dashboard. A partir daí, ela trabalha inteiramente na UI sob o prefixo de URL da sua org (ex.: `/acme/sessions`). + +**3. Crie uma chave de API por org (no dashboard):** + +O operador **não** cria chaves de dados por org pela CLI. Alice (ou qualquer membro da org com `keys:create`) cria chaves de coletor/dashboard para a org `acme` pela página de **Keys** do dashboard. Cada chave que ela cria é automaticamente marcada com sua org e só pode ler ou escrever dados da `acme`. Consulte [API Keys](/pt-br/agenteye/api-keys). + +**4. Ajuste um membro posteriormente:** + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member update --org acme --email alice@acme.example --add alerts:write + +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member list --org acme +``` + +**5. Exclusão suave da org** (revoga o acesso + remove seu usuário ClickHouse; dados retidos): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org delete --slug acme +``` + +**6. Purga da org** (irreversível; somente após uma exclusão suave; nunca a org `default`): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org purge --slug acme +``` + +No Docker Compose, substitua cada prefixo `kubectl -n agenteye exec deploy/server --` por `docker compose exec server`. + +--- + +## Divisão de responsabilidades + +Tudo o que um membro da org precisa no dia a dia é autoatendimento no dashboard e na API, com escopo automaticamente para sua org atual: + +- **Chaves de API por org** são criadas e gerenciadas por membros da org no dashboard (ou via API de chaves com uma chave que carrega `keys:create`). A CLI **não** cria chaves de dados. Consulte [API Keys](/pt-br/agenteye/api-keys). +- **Troca de org** está integrada ao dashboard; os membros alternam entre as orgs às quais pertencem pelo seletor de org, e as páginas com escopo de org ficam em `//…`. +- **Dashboards, consultas salvas, alertas e todo uso de dados** acontecem inteiramente na UI e na API, com escopo para a org atual do membro. + +O operador, usando `agenteye-orgctl`, é responsável apenas pelo **ciclo de vida** da org + membro: criar/renomear/excluir/purgar uma org, e adicionar/listar/atualizar/remover um membro. + +--- + +## Veja também + +- [Deployment](/pt-br/agenteye/deployment): `ORG_CH_SECRET` e o restante do ambiente do servidor. +- [Kubernetes Deployment](/pt-br/agenteye/kubernetes-deployment): §2.6 cria o Secret `agenteye-org-ch-secret` antes da sua primeira org multi-tenant. +- [API Keys](/pt-br/agenteye/api-keys): o modelo de chave por org e os tokens de permissão usados por `--add` / `--remove`. +- [Troubleshooting](/pt-br/agenteye/troubleshooting): provisionamento multi-tenant e problemas de isolamento do ClickHouse. \ No newline at end of file diff --git a/docs/pt-br/agenteye/troubleshooting.mdx b/docs/pt-br/agenteye/troubleshooting.mdx new file mode 100644 index 00000000..489ac538 --- /dev/null +++ b/docs/pt-br/agenteye/troubleshooting.mdx @@ -0,0 +1,691 @@ +--- +title: "Solução de Problemas" +description: "Documentação de Solução de Problemas do AgentEye." +--- + + +Este guia mapeia os sintomas mais comuns em produção para um diagnóstico e correção concretos, para que você possa resolver incidentes com as ferramentas que já possui, sem precisar configurar infraestrutura adicional de observabilidade. Ele cobre o servidor, coletor, painel, assistente de IA, Python SDK, monitoramento de saúde e certificados, backups, análises com ClickHouse e multi-tenancy. + +As páginas do painel têm escopo por organização em `//…`, e o stream de eventos é a página inicial da organização (`//`). Os nomes de páginas neste guia (por exemplo, `/sessions`, `/queries`) referem-se a essas rotas com escopo de organização. + +--- + +## Visualizando Logs + +O AgentEye não inclui uma pilha de logging ou monitoramento. Tanto o servidor quanto o painel escrevem logs estruturados no **stdout**, para que você possa lê-los diretamente com `kubectl` ou `docker`; nenhum agregador é necessário. + +### Kubernetes + +Acompanhe os logs ao vivo do servidor e do painel: + +```bash +kubectl logs -n agenteye -l app=server -f --timestamps +kubectl logs -n agenteye -l app=dashboard -f --timestamps +``` + +Variações úteis: + +| Objetivo | Comando | +|---|---| +| Últimas 200 linhas (sem acompanhamento) | `kubectl logs -n agenteye -l app=server --tail=200 --timestamps` | +| Logs da falha anterior | `kubectl logs -n agenteye --previous` | +| Acompanhar todas as réplicas ao mesmo tempo | `kubectl logs -n agenteye -l app=server --max-log-requests=10 -f` | +| Postgres (StatefulSet) | `kubectl logs -n agenteye postgres-0 -f` | + +### Docker Compose + +```bash +docker logs -f agenteye-server +docker logs -f agenteye-dashboard +``` + +### Correlacionando uma única requisição entre painel e servidor + +Cada requisição do painel é marcada com um `request_id` e propagada ao servidor via cabeçalho `x-request-id`. O servidor o ecoa nos cabeçalhos de resposta e em cada linha de log emitida para aquela requisição. Para rastrear uma requisição de ponta a ponta: + +1. Capture o id do cabeçalho de resposta, por exemplo: + ```bash + curl -i https://dashboard.example.com/api/events | grep -i x-request-id + # x-request-id: 9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a + ``` +2. Busque nos logs de ambos os pods esse id: + ```bash + REQ=9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a + kubectl logs -n agenteye -l app=dashboard --tail=5000 | grep "$REQ" + kubectl logs -n agenteye -l app=server --tail=5000 | grep "$REQ" + ``` + +Você verá as linhas `proxy passthrough`, `withAuth: authorized` e `upstream response` do painel junto com o par `http request received` / `http request completed` do servidor, todos compartilhando o mesmo `request_id`. + +### Logs JSON e `jq` + +Defina `AE_LOG_JSON=1` no painel (ativado por padrão quando `NODE_ENV=production`) para emitir um objeto JSON por linha. Então filtre estruturalmente: + +```bash +kubectl logs -n agenteye -l app=dashboard --tail=5000 \ + | jq 'select(.level == "warn" or .level == "error")' + +kubectl logs -n agenteye -l app=dashboard --tail=5000 \ + | jq 'select(.route == "POST /api/keys")' +``` + +O servidor Rust emite pares `key=value` de tracing que funcionam bem com grep sem `jq`: + +```bash +kubectl logs -n agenteye -l app=server --tail=5000 | grep 'status=5' # 5xx +kubectl logs -n agenteye -l app=server --tail=5000 | grep 'actor_key_id=' +``` + +### Aumentando a verbosidade + +| Componente | Variável de ambiente | Exemplo | +|---|---|---| +| Servidor | `RUST_LOG` | `RUST_LOG=debug` ou `RUST_LOG=agenteye_server=debug,info` | +| Painel | `AE_LOG_LEVEL` | `AE_LOG_LEVEL=debug` | + +`debug` no servidor adiciona uma linha `api key authenticated` por autenticação. `debug` no painel adiciona linhas `upstream request`, `session validated` e `proxy passthrough`. + +### Retenção de logs + +O stdout do container é efêmero; o kubelet rotaciona os arquivos de log (padrão ~10 MiB por container) e mantém uma quantidade pequena em disco. Uma vez que o pod é excluído, os logs são perdidos. Se você precisar de retenção mais longa ou busca entre pods, aponte seu cluster para um coletor de logs (Loki, CloudWatch, Cloud Logging, Datadog, etc.) que monitore `/var/log/containers/`. O AgentEye não exige nem prescreve nenhuma escolha específica. + +--- + +## Problemas de Autenticação + +### `docker pull` falha com "unauthorized" + +Certifique-se de ter autenticado o Docker no GHCR com seu `AGENTEYE_TOKEN`: + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +O token deve ter permissão `read:packages` na organização `agenteye-enterprise`. Entre em contato com `support@exosphere.host` se seu token não funcionar. + +### `gh release download` retorna 404 ou 401 + +- Confirme que `AGENTEYE_TOKEN` está exportado no seu shell: `echo $AGENTEYE_TOKEN` +- Confirme que você está usando `GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download ...` (a CLI `gh` lê `GITHUB_TOKEN`) +- O token precisa de `contents:read` em `agenteye-enterprise/releases` + +--- + +## Problemas no Servidor + +### Servidor falha com "invalid port number" + +O `POSTGRES_PASSWORD` (ou outra credencial) contém caracteres especiais para URL (`/`, `+`, `=`) que quebram a análise de `DATABASE_URL`. Regenere a senha usando codificação hexadecimal: + +```bash +NEW_PASS=$(openssl rand -hex 24) +``` + +Em seguida, atualize o secret do Kubernetes e a senha dentro do Postgres (ou recrie o `.env` para Docker Compose) e reinicie o servidor. Veja os passos completos em [enterprise-docs/kubernetes-deployment.md](/pt-br/agenteye/kubernetes-deployment) § "PostgreSQL credentials". + +### Servidor encerra imediatamente na inicialização + +Verifique os logs do container: + +```bash +docker logs agenteye-server +``` + +Causas comuns: +- `DATABASE_URL` não definido ou malformado: o servidor registrará o erro e encerrará. +- Postgres inacessível: confirme que o container do Postgres ou banco de dados gerenciado está em execução e que o host/porta estão corretos. +- Migrações falharam: verifique os logs por erros SQL. + +### `GET /health` retorna não-200 ou expira + +O servidor pode ainda estar executando migrações na primeira inicialização. Aguarde alguns segundos e tente novamente: + +```bash +curl http://localhost:8080/health +``` + +Se o problema persistir, verifique `docker logs agenteye-server` por erros. + +### `GET /ready` retorna 503 + +`/ready` é a sonda de prontidão: retorna `503` quando o servidor não consegue alcançar **Postgres ou ClickHouse**. O corpo identifica a dependência com falha: + +```bash +curl -s http://localhost:8080/ready +# {"status":"not_ready","checks":{"postgres":"ok","clickhouse":"down","redis":"ok"}} +``` + +Corrija a dependência reportada como `down`: o pod do ClickHouse/Postgres está `Running`? O `CLICKHOUSE_URL` / `DATABASE_URL` está correto e acessível? No Kubernetes, o pod fica como `NotReady` até que `/ready` se recupere; isso é esperado e é exatamente o sinal que o monitoramento de saúde alerta. Redis nunca é causa: é reportado, mas não falha a prontidão. + +### Coletor retorna 401 Unauthorized + +A chave de API do coletor não tem permissão `events:add`, ou a chave foi desativada. Crie uma nova chave com a permissão correta: + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{"name":"new-collector","permissions":["events:add"]}' +``` + +### Requisições autenticadas ficaram lentas de repente (~200ms em vez de ~5ms) + +Este é o sintoma de o Redis estar fora do ar enquanto `REDIS_URL` está definido. Cada chamada ao cache expira após 100ms e recai no Postgres; nos caminhos de autenticação e OTP, a requisição faz duas dessas recaídas. + +Confirme nos logs do servidor: + +``` +auth cache: L2 get failed error=redis call timed out +``` + +Resolução: + +1. `redis-cli -h ping` para confirmar que o Redis está acessível na rede do cluster. +2. Se o Redis ficou brevemente fora do ar e voltou, **reinicie os pods do servidor**. O `redis::aio::ConnectionManager` não reestabelece de forma confiável após a queda da conexão subjacente; uma reinicialização do pod retoma a nova conexão de forma limpa. O mesmo se aplica ao painel. +3. Se você não quer executar o Redis agora, remova `REDIS_URL` do deployment e reinicie. Ambos os serviços funcionam sem o cache (a correção é preservada; a latência volta à linha de base pré-Redis). + +### Servidor reporta `OTP request rate-limited` nos logs, mas o usuário diz que tentou apenas uma vez + +Verifique se o Redis estava inacessível. O caminho de fallback usa `SELECT COUNT(*) FROM otp_codes WHERE created_at > now() - interval '15 minutes'`, que vê linhas de OTP geradas anteriormente. Se o usuário ficou clicando em "Reenviar" por uma hora, a janela de 15 minutos ainda pode conter ≥5 códigos. Resolva aguardando a janela expirar ou execute `DELETE FROM otp_codes WHERE user_id = $1 AND created_at > now() - interval '15 minutes'` (console do operador). + +### Alterei `ALLOWED_EMAILS` / `SESSION_TTL_SECS` / `OTP_TTL_SECS` e reiniciei; nada mudou + +Essas variáveis de ambiente são **sementes apenas da primeira inicialização**. Uma vez que a tabela `settings` tem uma linha para a chave correspondente, essa linha é a fonte de verdade; a variável de ambiente é lida uma vez na primeira inicialização e ignorada em todas as reinicializações subsequentes. + +Para alterá-las após a primeira inicialização, faça login no painel e edite-as em `/settings`. A alteração se aplica em segundos em todas as réplicas; sem necessidade de reinicialização. + +Se você precisar forçar uma re-semeação a partir do env (raro, tipicamente útil apenas em desenvolvimento), `DELETE FROM settings WHERE key = ''` e reinicie o servidor. O bootstrap captará o valor atual da variável de ambiente na próxima inicialização. Editar via `/settings` é o caminho suportado em produção. + +--- + +## Problemas no Coletor + +### Coletor inicia, mas os eventos não aparecem no painel + +1. Confirme que o coletor está em execução: `systemctl status agenteye-collector` (Linux) ou verifique o processo. +2. Confirme que `AGENTEYE_URL` aponta para `http(s)://your-server-host:8080/events` (observe: o caminho `/events`). +3. Execute um flush único para ver a saída imediata: + ```bash + agenteye-collector flush + ``` +4. Verifique que o Python SDK está de fato escrevendo arquivos: `ls ${AGENTEYE_HOME:-~/.agenteye}/events/` +5. Se existirem arquivos em `${AGENTEYE_HOME:-~/.agenteye}/failed/`, os uploads estão falhando. Verifique os logs do coletor pelo erro, provavelmente um 4xx (chave incorreta ou URL) ou problema de rede. + +### Arquivos estão acumulando em `$AGENTEYE_HOME/events/` e não estão sendo enviados + +- O coletor pode não estar em execução. Inicie-o: `agenteye-collector start`; ele automaticamente faz o flush de eventos pré-existentes na inicialização. +- Verifique a saúde do coletor: `agenteye-collector health` +- O coletor pode estar em execução, mas incapaz de alcançar o servidor. Verifique as regras de firewall entre os hosts do coletor e do servidor. + +### Arquivos em `$AGENTEYE_HOME/failed/` + +Os arquivos são movidos para `failed/` após todas as tentativas de retry serem esgotadas (padrão: 5 tentativas com backoff exponencial). Isso significa: +- O servidor retornou um erro 4xx (chave incorreta, URL errada ou problema de payload) +- O servidor estava inacessível durante toda a janela de retry + +Corrija o problema subjacente e, em seguida, recoloque manualmente na fila: + +```bash +mv ${AGENTEYE_HOME:-~/.agenteye}/failed/*.jsonl ${AGENTEYE_HOME:-~/.agenteye}/events/ +agenteye-collector flush +``` + +### Coletor reporta `network error` em cada upload (falha no handshake TLS) + +Se `curl -k` contra `AGENTEYE_URL` funciona, mas o binário do coletor falha em cada upload com `error sending request for url (...)`, o servidor AgentEye está apresentando um certificado TLS que não foi assinado por uma CA de confiança pública. + +O **caminho de produção** é o hostname ACME de ingestão configurado em `deploy/base/certificates/domain.env` (veja [`kubernetes-deployment.md`](/pt-br/agenteye/kubernetes-deployment) Fases 3.1 / 4.2). Uma vez que `INGEST_DOMAIN` resolve para o LB público do Traefik e o cert-manager emitiu o certificado Let's Encrypt, os coletores verificam o certificado do servidor contra o store de confiança do sistema **sem necessidade de `AGENTEYE_TLS_CA`**; remova-o da sua configuração do coletor se foi definido para um deployment antigo com certificado autoassinado. + +**Sintoma: o coletor funcionava ontem, falha hoje após uma lacuna de ~90 dias.** Isso significa que o deployment ainda usa o emissor legado `selfsigned` para `ingest-tls`. O certificado de 90 dias foi rotacionado e o arquivo de CA fixado está desatualizado. Corrija permanentemente mudando o cluster para o emissor ACME (Fase 3.1 do guia de deployment). Desbloqueio de curto prazo: re-extraia o certificado atual do servidor e atualize `AGENTEYE_TLS_CA`: + +```bash +kubectl get secret ingest-tls-cert -n agenteye \ + -o jsonpath='{.data.tls\.crt}' | base64 -d > /etc/agenteye/server-ca.crt +``` + +```bash +export AGENTEYE_TLS_CA=/etc/agenteye/server-ca.crt +agenteye-collector flush +``` + +`AGENTEYE_TLS_CA` adiciona uma âncora de confiança adicional; as raízes públicas padrão ainda são confiáveis. + +### Certificado `ingest-tls` está preso em `Ready: False` após o deploy + +```bash +kubectl describe certificate ingest-tls -n agenteye +``` + +Observe os `Events` e o `Order` / `Challenge` referenciado. Causas comuns: + +- **DNS não resolvendo para o LB público.** O validador HTTP-01 não consegue alcançar `INGEST_DOMAIN`. Verifique com `dig +short INGEST_DOMAIN`; deve resolver para o mesmo endereço que o `EXTERNAL-IP` do LoadBalancer `traefik-public`. O cert-manager retenta automaticamente quando o DNS se propaga; não é necessário excluir o Certificate. +- **Porta 80 bloqueada no load balancer / security group.** HTTP-01 requer que a porta 80 seja acessível pelos validadores públicos do Let's Encrypt. Se você tem um WAF ou SG restringindo `:80`, abra-o (a configuração do Traefik redireciona para HTTPS, mas o Boulder segue o redirecionamento e aceita a resposta). +- **`dnsNames` não substituídos.** Se `kubectl get certificate ingest-tls -n agenteye -o jsonpath='{.spec.dnsNames}'` mostrar `INGEST_DOMAIN_PLACEHOLDER`, você pulou a etapa do `domain.env`; crie-o a partir de `domain.env.example` e reaplique. +- **Rate limiting pelo Let's Encrypt.** Ordens repetidas com falha para o mesmo hostname ativam os limites de certificado duplicado ou validação falhada. Aguarde pelo menos uma hora antes de tentar novamente; verifique o status do Order pela mensagem exata de rate limit. + +### Certificado `dashboard-tls` está preso em `Ready: False` / o navegador ainda mostra um aviso + +Mesmo fluxo de diagnóstico que `ingest-tls` acima (`kubectl describe certificate dashboard-tls -n agenteye`); as causas de DNS, porta 80, placeholder e rate limit se aplicam, mais duas específicas do painel: + +- **`DASHBOARD_DOMAIN` resolve para o LoadBalancer errado.** Deve apontar para o LB do Traefik do *painel*, não o de ingestão pública. Execute `dig +short` no hostname e compare com o endereço do LB do painel. +- **A instância Traefik do painel não consegue servir o desafio.** Deve ser instalada com o arquivo de valores do painel incluído, que habilita um provedor Ingress com escopo para o solver HTTP-01 do cert-manager. Sem ele, o solver é inacessível e o Order fica em `pending` para sempre. Atualize a instância com os valores fornecidos; o desafio pendente então se completa por conta própria. +- **O LoadBalancer tinha restrição de IP.** Os intervalos de origem se aplicam à porta 80 também, o que bloqueia os validadores do Let's Encrypt — tanto na emissão inicial quanto em cada renovação de ~75 dias. Reabra o LB, ou coordene um solver DNS-01 com o suporte antes de restringi-lo. + +Enquanto a emissão está falhando, o painel continua servindo o certificado anterior (ou o padrão do ingress em uma nova instalação) — o acesso é degradado por um aviso do navegador, nunca interrompido. + +### A CLI ainda ignora a verificação TLS após o painel obter um certificado confiável + +`--insecure` é persistido em `cli.json` no login. Uma vez que o painel serve um certificado de confiança pública, faça login novamente com `agenteye --base-url https:// --secure login`; a verificação é salva de volta como ativada e o aviso de inicialização desaparece. + +--- + +## Problemas no Painel + +### Não consigo desativar ou editar o usuário `ADMIN_EMAIL` + +Por design. O usuário correspondente ao `ADMIN_EMAIL` é marcado como protegido em cada inicialização do servidor: o painel oculta o botão Desativar para aquela linha, e a API rejeita `DELETE /users/:id` e `PUT /users/:id` com `403 Forbidden`. Um trigger do banco de dados também rejeita instruções `UPDATE` diretas que desativariam a linha protegida. + +Para rotacionar o admin de bootstrap, altere `ADMIN_EMAIL` no seu ambiente e reinicie o servidor. O novo e-mail é inserido/atualizado como protegido. O admin anterior retém o sinalizador de proteção até ser limpo no banco de dados (normalmente está bem, pois o e-mail anterior ainda é um admin válido até você removê-lo explicitamente). + +### O painel não mostra eventos + +1. Confirme que a URL do servidor e a chave de API estão corretas nas variáveis de ambiente do painel (`AGENTEYE_SERVER_URL`, `AGENTEYE_API_KEY`). +2. A chave de API do painel precisa da permissão `events:read`. +3. Confirme que eventos foram realmente ingeridos: `curl http://your-server:8080/events -H "Authorization: Bearer $ADMIN_KEY"` + +### `/errors` está vazio, mas `/events` mostra linhas vermelhas + +Versões mais recentes do SDK emitem falhas como eventos `agent_end` / `tool_result` / `hook_completed` com `outcome: "error"` no payload, em vez de uma linha dedicada com `event_type: "error"`. A página `/errors` agora corresponde a ambos: qualquer linha que o stream `/events` pinta de vermelho (tipo `event_type='error'` explícito, `outcome`/`status` no conjunto de falhas no payload, `is_error: true`, ou um campo `error` verdadeiro) aparece em `/errors`. Se você anteriormente via "no errors in this window" enquanto linhas vermelhas eram visíveis em `/events`, atualize o painel + servidor juntos (o filtro ampliado é `errored=true` em `GET /events`) e as duas visualizações concordarão. + +### `/models`, `/tools` ou `/hooks` está lento ou falha ao carregar em intervalos de tempo amplos + +**Sintoma:** em uma tabela de eventos grande (milhões de linhas), abrir `/models`, `/tools` ou `/hooks` — ou ampliar o intervalo de tempo para `7d`, `30d` ou `all` — os gráficos giram e então mostram um erro de carregamento. O servidor registra um `MEMORY_LIMIT_EXCEEDED` do ClickHouse (Código 241) ou um timeout de consulta para a requisição `latency_aggregate`. + +**Causa:** builds mais antigas calculavam os rollups de latência e distribuição dessas páginas com uma consulta que lia o `payload` completo de eventos brutos e emparelhava eventos de requisição/resposta com uma classificação e junção na memória. O pico de memória da consulta crescia portanto com o tamanho da janela, então em um tenant ocupado um intervalo amplo poderia exceder o teto de memória por consulta do ClickHouse. + +**Correção:** atualize para um build que inclua essa correção. O rollup agora lê apenas as colunas compactas promovidas e emparelha eventos com uma agregação em streaming, então o pico de memória não escala mais com o payload bruto — intervalos amplos ficam bem dentro do teto de memória e retornam em uma fração do tempo. A melhoria é inteiramente do lado da consulta: aplica-se a todos os dados existentes no próximo carregamento de página, sem re-ingestão ou backfill. + +### Painel falha ao carregar / página em branco + +Verifique os logs do container do painel: + +```bash +docker logs agenteye-dashboard +``` + +A causa mais comum é `AGENTEYE_SERVER_URL` ou `AGENTEYE_API_KEY` ausentes ou apontando para um servidor inacessível. + +### Analytics / telemetria do painel + +O painel envia analytics de uso de produto anônimos para o PostHog por padrão, roteados pelo próprio caminho `/ingest` do painel (um proxy reverso para `https://us.i.posthog.com`). Enviá-los como first-party significa que bloqueadores de anúncios do navegador não os descartam. Isso é independente da funcionalidade principal do painel: + +- O **container do painel** (não o navegador) é quem alcança o PostHog. Se seu acesso de saída para `https://us.i.posthog.com` estiver bloqueado, a telemetria silenciosamente não opera; o painel funciona normalmente e nenhum erro é exibido aos usuários. +- Nenhum dado de agente, sessão ou evento é incluído, apenas o uso da UI do painel. +- Para desativar a telemetria completamente, defina `AE_ANALYTICS_DISABLED=1` no container do painel e reinicie. Veja [Telemetry & privacy](/pt-br/agenteye/deployment#telemetry--privacy) no guia de deployment. + +### Analytics / telemetria da CLI + +A CLI `agenteye` envia analytics de uso anônimos para o PostHog por padrão: quais comandos são executados, status de sucesso/saída e duração. Isso é independente da funcionalidade da CLI: + +- A **máquina que executa a CLI** alcança `https://us.i.posthog.com` diretamente. Se seu acesso de saída estiver bloqueado, a telemetria silenciosamente não opera (o envio tem limite de tempo, então nunca atrasa um comando) e a CLI funciona normalmente. +- Nenhum dado de agente, sessão ou evento é incluído: **argumentos de comandos e valores de flags** (URL do painel, token, e-mail, ids de sessão, filtros de consulta) nunca são enviados. +- Para desativá-la, defina `AGENTEYE_ANALYTICS_DISABLED=1` (ou o cross-tool `DO_NOT_TRACK=1`) no ambiente da CLI. Veja [Telemetry & privacy](/pt-br/agenteye/cli#telemetry--privacy) no guia da CLI. + +--- + +## Problemas no Assistente de IA + +Veja [enterprise-docs/assistant.md](/pt-br/agenteye/assistant) para configuração completa. + +### O botão do assistente não aparece + +O botão fica oculto a menos que **todos** esses critérios sejam atendidos: + +- O usuário conectado tem a permissão `agent:use`. +- `AGENTEYE_AGENT_URL` está definido no painel e o serviço `agent` está acessível. +- Um endpoint LLM está configurado no serviço `agent` (`ANTHROPIC_API_KEY`, um gateway via `ANTHROPIC_BASE_URL`, ou Bedrock/Vertex). Com nenhum definido, o agente reporta "not configured" e o botão permanece oculto. + +Verifique a saúde do agente a partir do host do painel: `curl http://agent:9100/health` deve retornar `{"status":"ok","llm_configured":true,...}`. + +### O assistente diz que não consegue ler algo + +As ferramentas são controladas por usuário. Se um usuário não tem `evaluations:read` (ou `events:read`, `dashboards:read`), as ferramentas correspondentes não são oferecidas e o assistente dirá que não consegue ler aquele dado. Conceda a permissão de leitura relevante. + +### "assistant not configured" (HTTP 503) ao enviar + +O container `agent` não tem endpoint LLM configurado, ou o `AGENTEYE_AGENT_TOKEN` do painel não corresponde ao do agente. Defina ambos e reinicie. + +### O container `agent` reinicia / fica sem memória sob carga + +Cada conversa gera um processo filho de curta duração. Certifique-se de que o container executa com um processo init (a imagem usa `tini`; no Compose defina `init: true`) e forneça limites de memória adequados. Reduza `AGENTEYE_AGENT_MAX_STEPS` se necessário. + +--- + +## Problemas na CLI + +### `agenteye` falha ao iniciar com `ModuleNotFoundError: No module named 'click'` + +Uma instalação nova da CLI `agenteye` na versão **0.1.6** pode travar na inicialização com: + +``` +ModuleNotFoundError: No module named 'click' +``` + +A versão 0.1.6 dependia de `click` ser instalado indiretamente pelo `typer`; versões atuais do `typer` não o incluem mais, então um ambiente limpo acaba sem o pacote. **Atualize para a versão 0.1.7 ou mais recente**, que depende de `click` diretamente: + +```bash +pipx upgrade agenteye # se instalado com pipx (ou: pipx install --force agenteye) +uv tool upgrade agenteye # se instalado com uv +pip install --upgrade agenteye +``` + +Veja [enterprise-docs/cli.md](/pt-br/agenteye/cli) para orientações de instalação. + +--- + +## Problemas no Python SDK + +### Nenhum arquivo aparecendo em `$AGENTEYE_HOME/events/` + +O SDK armazena eventos em buffer e faz flush a cada 500 ms por padrão. Se o processo encerrar antes do flush, os eventos podem ser perdidos. Chame `agenteye.configure(flush_interval=0.1)` para flush mais rápido em scripts de curta duração, ou garanta que seu processo execute por tempo suficiente para um ciclo de flush. + +Se `AGENTEYE_HOME` estiver definido, verifique se o SDK está escrevendo em `$AGENTEYE_HOME/events/` e não em `~/.agenteye/events/` (requer SDK ≥ 0.0.1b5). + +### `ValueError: Reserved field names cannot be used as custom fields` + +Os nomes `timestamp`, `type` e `environment` são reservados e não podem ser usados como campos personalizados. Passá-los gera: + +``` +ValueError: Reserved field names cannot be used as custom fields: [...] +``` + +Renomeie o campo personalizado com problema. Observe que `session_id` e `agent_id` são parâmetros explícitos da chamada de evento, não campos personalizados; passar qualquer um deles novamente como campo personalizado gera `TypeError`. + +--- + +## Problemas no Monitoramento de Saúde + +### Nenhum alerta chegando no Slack (Robusta) + +O alerta de saúde do Robusta é **opt-in**; não envia nada até ser instalado e apontado para um canal do Slack. Verifique o release e seu sink: + +```bash +kubectl get pods -n robusta # robusta-runner + robusta-forwarder devem estar Running +kubectl logs -n robusta -l app=robusta-runner --tail=50 +``` + +Causas comuns: `api_key` / `slack_channel` do Slack não foram definidos (ou o token foi revogado); o `api_key` é um token de relay em nuvem do Robusta (`robusta integrations slack`), mas o `disableCloudRouting: true` incluído precisa de um **bot token** do Slack auto-hospedado (`xoxb-…`), ou defina `disableCloudRouting: false`; o `scope` do sink exclui o namespace onde seus pods estão (os valores incluídos limitam a `agenteye`); ou nenhuma falha ocorreu ainda. Force um alerta de teste derrubando um pod: + +```bash +kubectl -n agenteye delete pod -l app=clickhouse # será recriado +``` + +Veja [enterprise-docs/health-monitoring.md](/pt-br/agenteye/health-monitoring#2-pod-failure-alerting-with-robusta-opt-in) para instalação e configuração. + +### Servidor continua alternando entre `NotReady` + +A sonda de prontidão atinge `/ready`, que falha quando Postgres ou ClickHouse está inacessível. Se o servidor alterna entre `NotReady`, uma dependência está intermitentemente indisponível; verifique os pods do ClickHouse e Postgres e os valores `CLICKHOUSE_URL` / `DATABASE_URL` do servidor. Confirme o que `/ready` reporta: + +```bash +kubectl -n agenteye exec deploy/server -- sh -c 'curl -s localhost:8080/ready' +``` + +Essa sonda é deliberadamente tolerante (limite de falha generoso), então alternâncias sustentadas indicam um problema real de dependência em vez de uma sonda muito agressiva. A liveness permanece em `/health`, então a alternância de prontidão **não** reiniciará o pod. + +## Problemas no Monitoramento de Certificados + +### CronJob não está enviando notificações para o Slack + +O CronJob `cert-renewal-check` requer uma URL de webhook do Slack armazenada em um Secret. Verifique se existe: + +```bash +kubectl get secret cert-renewal-notify-config -n agenteye +``` + +Se estiver faltando, crie-o: + +```bash +kubectl create secret generic cert-renewal-notify-config \ + --namespace agenteye \ + --from-literal=SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL" +``` + +Sem o secret, o CronJob ainda executa e registra os resultados no stdout. Verifique os logs com: + +```bash +kubectl logs -n agenteye -l job-name --tail=50 +``` + +### Certificado do cliente expirou antes de uma notificação ser recebida + +O CronJob executa a cada 12 horas. Se não esteve em execução, verifique seu status: + +```bash +kubectl get cronjob cert-renewal-check -n agenteye +``` + +Dispare uma verificação manual: + +```bash +kubectl create job --from=cronjob/cert-renewal-check manual-cert-check -n agenteye +kubectl logs -n agenteye -l job-name=manual-cert-check +``` + +Para reemitir o certificado expirado imediatamente: + +```bash +cd base/certificates/client-certs +./issue-client-cert.sh +``` + +Em seguida, aplique o `collector-mtls-secret.yaml` regenerado nos clusters que executam seus coletores e reinicie-os: + +```bash +kubectl apply -f collector-mtls-secret.yaml -n +``` + +--- + +## Problemas de Backup + +### `agenteye-backup` falha com "No space left on device" + +O CronJob `agenteye-backup` despeja Postgres + ClickHouse em um volume de rascunho `emptyDir` chamado `backup-tmp` (padrão `30Gi`), depois **transmite em streaming** o arquivo `tar` diretamente para o S3 — o arquivo comprimido nunca é gravado de volta no rascunho, então o rascunho só precisa conter os *dumps brutos*, não dumps + uma segunda cópia de arquivo em disco. Um pod despejado / `No space left on device` portanto significa que os **dumps brutos** excedem o tamanho do rascunho (o dump de `events` do ClickHouse domina e cresce ao longo do tempo). Verifique os logs do job com falha: + +```bash +kubectl logs -n agenteye -l job-name= +``` + +Correção: no seu overlay, aumente o `sizeLimit` do `emptyDir` `backup-tmp` do CronJob acima do total de dumps brutos, e certifique-se de que o armazenamento efêmero do nó pode realmente armazená-lo (`sizeLimit` é um limite, não uma reserva). Se os dumps ultrapassarem o disco de um único nó, substitua o `emptyDir` por um PVC (EBS/PD) para `backup-tmp`, ou comprima os dumps na fonte. + +> Versões mais antigas gravavam o `.tar.gz` no mesmo rascunho de `20Gi` dos dumps, então `dumps + arquivo` o estouravam e o pod era despejado **antes** do upload ser executado — o que parece uma falha do S3, mas na verdade é disco. A transmissão em streaming do upload remove esse problema de duplicação. + +### `agenteye-backup` falha ao instalar `curl` + +O job executa na imagem `postgres:16` e instala `curl` na inicialização para o dump HTTP do ClickHouse. Em um cluster sem acesso de saída aos mirrors de pacotes Debian, a etapa `apt-get` falha. Permita esse acesso de saída do pod de backup, ou inclua `curl` em uma imagem de backup espelhada/personalizada e referencie-a no seu overlay. + +### `agenteye-backup` executa, mas nada chega ao armazenamento de objetos + +A base vem com um `BACKUP_BUCKET` real (`ts-prod-agenteye/backups`) e a ServiceAccount `agenteye-backup`. O job **transmite em streaming** o arquivo para o S3 (`tar cz … | aws s3 cp - s3://…`). Se o pod de backup não tem acesso de escrita ao bucket, o upload falha — e porque o script executa sob `set -euo pipefail`, uma falha em qualquer ponto desse pipe **falha** todo o job na etapa `upload` em vez de silenciosamente não fazer nada (o trap EXIT do pod registra `backup FAILED during step: upload`). Esta também é a etapa que você alcança *após* corrigir um despejo por espaço em disco, então se os backups eram anteriormente despejados na etapa de arquivo, verifique se o upload agora chega. Busque nos logs do job com falha o erro de acesso ao S3: + +```bash +kubectl logs -n agenteye -l job-name= | grep -iE 's3|upload|denied' +``` + +Correção: no seu overlay defina `BACKUP_BUCKET` para um bucket que você possui e anote a ServiceAccount `agenteye-backup` existente com acesso de escrita (IRSA / Workload Identity / Pod Identity). Veja a seção **Backups** de [enterprise-docs/kubernetes-deployment.md](/pt-br/agenteye/kubernetes-deployment). + +--- + +## Avaliações / sessões / queries com ClickHouse + +### A barra lateral da página `/queries` está vazia após a atualização + +Três tabelas (`events`, `evaluations`, `agent_sessions`) são esperadas. Se a barra lateral do SchemaBrowser estiver vazia após a atualização, o servidor falhou ao aplicar o DDL do ClickHouse na inicialização. Verifique os logs do servidor por `failed to apply CH DDL statement`: + +```bash +kubectl logs -n agenteye deploy/server | grep -E 'clickhouse|CH DDL' +``` + +A causa mais comum é o ClickHouse estar inacessível enquanto as migrações executam. O servidor recusa iniciar se não conseguir alcançar o CH, então um pod travado geralmente tem um `CrashLoopBackOff` em vez de uma página de queries silenciosamente quebrada, mas um DDL parcialmente aplicado (um statement OK, os próximos com 5xx) deixa o schema incompleto. Reinicie o pod do servidor após verificar que o CH está acessível: + +```bash +kubectl rollout restart deploy/server -n agenteye +``` + +### Novas avaliações não aparecem em `/sessions` ou `/queries` + +Após a atualização, novas avaliações são escritas no ClickHouse, não no Postgres, e aparecem em `/sessions` (controlado por `evaluations:read`) e em `/queries`. Se não aparecerem: + +1. Confirme que o pipeline do avaliador está habilitado (`EVALUATOR_ENDPOINT` definido no servidor) e produzindo resultados terminais; verifique linhas de log `evaluation_finalized`. +2. Confirme que o CH está acessível a partir do servidor: `kubectl exec -n agenteye deploy/server -- curl -fsS http://clickhouse:8123/ping`. +3. Faça uma verificação pontual na tabela CH: `kubectl exec -n agenteye clickhouse-0 -- clickhouse-client -q 'SELECT count() FROM agenteye.evaluations'`. + +### Queries falham sob carga com "Memory limit exceeded", ou ClickHouse tem `OOMKilled` + +**Sintoma:** sob carga pesada de painel/queries, páginas analíticas (stream de eventos, `/sessions`, visualização de modelos/latência, editor SQL) começam a falhar ou expirar; o servidor alterna brevemente para `NotReady`; e o pod do ClickHouse mostra contagem de reinicializações crescente. Isso é quase sempre **memória**, não CPU ou disco. + +**Confirme que é memória** (não um problema de throughput que replicação resolveria): + +1. Verifique se o pod teve kills por falta de memória: + ```bash + kubectl -n agenteye describe pod clickhouse-0 | grep -iE 'Restart Count|Last State|Reason|OOMKilled' + ``` + `Reason: OOMKilled` / `Exit Code: 137` com contagem de reinicializações crescente é o indicador. + +2. Pergunte ao ClickHouse o que ele está rejeitando: + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT name, value FROM system.errors WHERE value>0 ORDER BY value DESC" + ``` + Uma contagem grande de `MEMORY_LIMIT_EXCEEDED` é a assinatura. A mensagem diz *"maximum: N GiB"* — esse **N é `0,9 × o limite de memória do pod`** (o `max_server_memory_usage_to_ram_ratio` em `deploy/base/clickhouse/configmap.yaml`). Se suas leituras pesadas precisam de mais que N, são rejeitadas. + +3. Descarte as coisas que *não* são o problema — se CPU, contagem de partes e disco estão todos baixos, adicionar réplicas/sharding seria custo desperdiçado: + ```bash + kubectl -n agenteye top pod clickhouse-0 + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT table, count() parts FROM system.parts WHERE active AND database='agenteye' GROUP BY table" + ``` + +**Causa:** o limite de memória do pod do ClickHouse é muito pequeno para o conjunto de trabalho analítico. As leituras mais pesadas puxam a coluna `payload` JSON bruta, executam `JSONExtract*` sobre ela e usam `FINAL` — cada uma pode precisar de vários GiB. Se os caches configurados (`mark_cache_size` + `uncompressed_cache_size`) são maiores que o pod, eles agravam: caches são cobrados contra o mesmo orçamento e competem com a memória de queries. + +**Correção — escale a memória do ClickHouse:** + +1. Aumente o limite de memória do ClickHouse no seu overlay fazendo patch nos `resources` do container do StatefulSet `clickhouse` (o mesmo mecanismo de overlay usado para `resources` de outros componentes). O orçamento utilizável do servidor é `0,9 × limite`, então um limite de `6Gi` dá ~5,4 GiB, `16Gi` dá ~14 GiB. Defina `requests.memory` como um piso real também, para que o scheduler o reserve. Aplicar isso **recria o pod do CH** (réplica única → ~30–60s de tempo de inatividade de analytics); faça-o em uma janela de baixo tráfego. +2. Mantenha os caches em `deploy/base/clickhouse/configmap.yaml` proporcionais ao limite — caches pequenos (algumas centenas de MiB) são seguros em um pod pequeno; aumente-os apenas junto com um aumento correspondente no limite de memória. O `max_memory_usage` por query é definido explicitamente no perfil `users.xml` (veja a seção de nó fixo abaixo) e é mantido abaixo do limite em nível de servidor (`0,9 × limite`) para que nenhuma query única possa usar *mais* RAM que o container tem. +3. Se o próprio nó é o teto, verifique a memória do host que o ClickHouse consegue ver: + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT formatReadableSize(value) FROM system.asynchronous_metrics WHERE metric='OSMemoryTotal'" + ``` + Se isso for apenas um pouco acima do limite do pod, mova o ClickHouse para um nó maior (otimizado para memória) — via seletor de nó/affinity no seu overlay — antes de aumentar o limite ainda mais. + +**Quando você não pode adicionar memória: execute queries na RAM e falhe rapidamente — não derrame em um disco lento.** Se o nó é fixo e o pod não pode crescer, limite o que qualquer query pode usar (para que uma query não tome o nó inteiro) e, em um **disco de dados lento (não-SSD)**, **não** permita que grandes agregações/ordenações derramem em disco. Derramar em um disco lento é mais lento que o timeout de leitura do cliente do servidor, então uma query derramando retorna um `500` do painel no meio do caminho enquanto o ClickHouse continua processando — manter queries na RAM e rejeitar rapidamente a rara que excede o orçamento (`MEMORY_LIMIT_EXCEEDED`, sub-segundo) é o que restaura o carregamento. Observe uma peculiaridade do ClickHouse ao aplicar estas configurações: + +- **Estas são configurações de *perfil*, e o ClickHouse lê `` apenas de `users_config` (`users.xml` / `users.d/*.xml`) — nunca de `config.d`.** Um bloco `` colocado em `config.d/agenteye.xml` é **silenciosamente ignorado** (`max_execution_time`, `max_memory_usage`, etc. simplesmente não se aplicam). A configuração incluída portanto as fornece como uma chave `users.xml` no ConfigMap `clickhouse-config`, montada em `/etc/clickhouse-server/users.d/agenteye.xml`. +- Os padrões incluídos: `max_memory_usage` (teto por query — uma query não pode consumir todo o orçamento do servidor), `max_bytes_before_external_group_by` / `max_bytes_before_external_sort` = **`0` (derrame desativado)** para que queries fiquem na RAM em vez de arrastar no disco lento, e `max_execution_time` (proteção contra runaway, alinhado com o timeout de leitura do cliente do servidor). +- **Verifique se estão ativos** (assim você também detecta o problema do config.d): + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT name, value FROM system.settings + WHERE name IN ('max_memory_usage','max_bytes_before_external_group_by','max_execution_time')" + ``` + Espere um `max_memory_usage` diferente de zero e `max_bytes_before_external_group_by = 0`. Se `max_memory_usage` mostrar `0`/padrão, o perfil não está sendo aplicado — verifique se as configurações estão em um mount `users.d`, não em `config.d`. + +Trade-off: com derrame desativado, uma query cujo conjunto de trabalho excede `max_memory_usage` é **rejeitada** (`MEMORY_LIMIT_EXCEEDED`) em vez de completar lentamente — em um disco lento essa rejeição rápida é preferível, porque uma query derramando excederia o timeout do cliente e falharia de qualquer forma. Se seu disco de dados é **rápido (SSD)**, você pode em vez disso aumentar os limites `max_bytes_before_external_*` para permitir que queries grandes derramem para disco e completem. + +--- + +## Multi-tenancy (organizações) + +### Erros durante a atualização que habilita organizações (pods mistos antigos/novos) + +**Sintoma:** durante um deploy em rolagem da versão que habilita organizações, algumas requisições falham: os logs do servidor mostram `there is no unique or exclusion constraint matching the ON CONFLICT specification` no caminho de `api_keys`, e/ou canais de alerta/Slack/webhook param de disparar enquanto o rollout está em andamento. + +**Causa:** a atualização substitui o antigo índice único de escopo de instância em `api_keys(name)` por índices parciais por organização, e move as configurações de canal de alerta (e `default_user_permissions`) da tabela global `settings` para `org_settings` por organização. Um pod **antigo** do servidor ainda emite `ON CONFLICT (name)` (agora sem constraint correspondente) e ainda lê a configuração de canal das antigas linhas de `settings` (agora vazias). Pods antigos e novos não podem coexistir com segurança nesses dois caminhos. + +**Correção:** não faça um rollout lento desta atualização específica entre versões mistas. Faça a transição de forma limpa: escale o servidor antigo para zero (ou use uma breve janela de manutenção) e suba a nova versão junto com suas migrações, em vez de executar réplicas antigas e novas lado a lado. O tráfego normal e a ingestão retomam imediatamente após a transição; isso afeta apenas a janela de transição de versão. + +### O provisionamento de uma organização falha em `CREATE USER` / `CREATE ROW POLICY`, ou uma organização consegue ler os dados de outra + +**Sintoma:** criar uma organização retorna um erro mencionando `CREATE USER`, `CREATE ROW POLICY` ou "access management is disabled"; ou, pior, membros de uma organização veem eventos/avaliações de outra no editor SQL ou assistente. + +**Causa:** o isolamento por organização é aplicado por um usuário ClickHouse dedicado + política de linha por organização. Isso requer que o **gerenciamento de acesso** SQL esteja habilitado e que `users_without_row_policies_can_read_rows=false` esteja configurado no ClickHouse. Com o gerenciamento de acesso desativado, o provisionamento não consegue criar o usuário/política; com o padrão da política de linha deixado no seu valor permissivo, um usuário que tem SELECT mas nenhuma política lê **todas** as linhas (falha aberta). + +**Correção:** use a configuração incluída em `deploy/base/clickhouse/`, que define ambos. Se você usa sua própria configuração do ClickHouse, habilite o gerenciamento de acesso SQL no usuário interno do servidor e defina `users_without_row_policies_can_read_rows=false` (veja `deploy/base/clickhouse/configmap.yaml`), depois reinicie o ClickHouse e re-crie a organização com a CLI `agenteye-orgctl` (veja [enterprise-docs/tenant-management.md](/pt-br/agenteye/tenant-management)). + +### Usuários da organização perdem acesso ao ClickHouse após alterar `ORG_CH_SECRET` + +**Sintoma:** o editor SQL e o assistente de IA de repente retornam falhas de autenticação do ClickHouse para todas as organizações, imediatamente após `ORG_CH_SECRET` ser alterado ou definido de forma inconsistente entre réplicas. + +**Causa:** a senha do ClickHouse de cada organização é derivada como um HMAC de `ORG_CH_SECRET`. Rotacioná-lo (ou executar réplicas com valores diferentes) invalida a credencial ClickHouse armazenada de cada organização; a senha derivada não corresponde mais ao usuário provisionado. + +**Correção:** defina `ORG_CH_SECRET` como um único valor forte **antes** de provisionar uma segunda organização e mantenha-o estável e idêntico em cada réplica do servidor. A reconciliação de inicialização do servidor re-provisiona o usuário ClickHouse de cada organização a partir do secret atual na inicialização, então uma reinicialização do servidor em todas as réplicas (com o secret consistente) corrige os usuários órfãos. Trate o valor como um secret de longa duração; não o rotacione casualmente. Como rede de segurança, se `ORG_CH_SECRET` for deixado no valor padrão de desenvolvimento integrado (ou seja, não definido), a reconciliação de inicialização **ignora** organizações não-padrão e registra um erro em vez de reescrever suas credenciais ClickHouse para o valor de desenvolvimento conhecido publicamente, então uma única réplica que reinicia sem o secret não pode quebrar as outras réplicas. Defina o secret de forma consistente e reinicie para provisionar essas organizações. + +### O assistente de IA retorna 400 / recusa conversar após habilitar organizações + +**Sintoma:** o dock do assistente carrega, mas cada mensagem retorna um erro (HTTP `400`), e o agente registra uma requisição `/chat` sem organização rejeitada. + +**Causa:** o agente é ciente de organização e falha de forma fechada; ele rejeita um `/chat` que não carrega contexto de organização. Isso acontece durante um rollout de transição onde o agente foi atualizado, mas o painel que envia a requisição ainda não está ciente de organização. + +**Correção:** conclua o rollout para que o painel envie contexto de organização (o estado final normal, nenhum flag necessário). Para cobrir o período enquanto um painel não ciente de organização fala com um agente ciente de organização, defina `AGENTEYE_AGENT_ALLOW_NO_ORG=1` no serviço `agent` para que ele recue para a organização `default` em vez de recusar, e limpe-o assim que a atualização do painel chegar. Veja a referência de variáveis de ambiente em [enterprise-docs/assistant.md](/pt-br/agenteye/assistant#environment-variable-reference). + +--- + +## Auditorias + +### Uma auditoria nunca é executada (próxima execução continua adiando, sem histórico de execução) + +**Sintoma:** a página de auditoria mostra *last run: never*, ou `next run` continua avançando para o futuro sem que apareça uma linha no histórico de execução. + +**Causa:** a auditoria está desativada (auditorias desativadas não têm entrada na fila), ou os workers de auditoria do servidor estão falhando ao reivindicar trabalho. + +**Correção:** confirme que a auditoria está **habilitada** (o botão executar agora requer isso). Então verifique os logs do servidor por `audits pipeline started` na inicialização e por erros `audits:` — uma linha `claim_due failed` aponta para conectividade do Postgres. `AUDIT_WORKERS` padrão é `1`; deve ser ≥ 1 para qualquer auditoria executar. + +### Execuções de auditoria têm sucesso, mas não encontram nada + +**Sintoma:** o histórico de execução mostra `succeeded` com `findings: 0` mesmo que `/errors` claramente mostre falhas. + +**Causa:** a janela de varredura não cobre as falhas, ou os filtros de escopo as excluem. + +**Correção:** verifique a janela da linha de execução (`window_from → window_to`) contra quando as falhas ocorreram — no modo `since_last`, cada execução só varre desde a última execução bem-sucedida, então falhas mais antigas são vistas apenas pela *primeira* execução ou por uma auditoria de janela `fixed`. Amplie `scope` (ambientes / ids de agente). As estatísticas de execução mostram `policy_hits` (quantas políticas determinísticas dispararam) e `improvements` (quantos a investigação de IA registrou) — se ambos são 0, a janela/escopo genuinamente não viu nada. + +### A execução diz `analysis_unavailable` e produz apenas descobertas de política + +**Sintoma:** as estatísticas de execução incluem `analysis_unavailable` e as únicas descobertas são `kind: policy`; nenhuma melhoria de IA aparece. + +**Causa:** a investigação agêntica não pôde executar: o servidor não consegue alcançar o serviço agent (`AGENTEYE_AGENT_URL` / `AGENTEYE_AGENT_TOKEN` não definidos no **servidor** — a auditoria reutiliza a conexão do assistente), o serviço assistente não tem LLM configurado, ou a chamada errou/expirou (a string `analysis_unavailable` tem o detalhe). A passagem de política determinística é o piso — sempre executa — então a auditoria ainda tem sucesso com suas descobertas de segurança. + +**Correção:** defina `AGENTEYE_AGENT_URL` (por exemplo, `http://agent:9100`) e `AGENTEYE_AGENT_TOKEN` no **servidor** — os mesmos valores que o assistente do painel já usa (os manifestos/compose incluídos agora os conectam) — e configure um LLM no serviço assistente (veja [assistant.md](/pt-br/agenteye/assistant)), depois execute novamente. Uma investigação grande pode precisar de um `AUDIT_LLM_TIMEOUT_MS` maior (servidor) — mantenha-o acima do `AGENTEYE_AUDIT_TIMEOUT_MS` do agente. + +### O sandbox de código da auditoria está desativado (`sandbox_available: false`) + +**Sintoma:** o `/health` do agente mostra `sandbox_available: false`, e as execuções de auditoria observam que o sandbox está indisponível; a IA investiga apenas com SQL. + +**Causa:** o sandbox bubblewrap dentro do pod precisa de **namespaces de usuário não privilegiados**, que o perfil seccomp do pod ou o kernel do nó está bloqueando. + +**Correção:** defina `seccompProfile: Unconfined` (k8s) ou `security_opt: [seccomp:unconfined]` (compose) no agente, e confirme que o kernel do nó permite namespaces de usuário não privilegiados (algumas imagens gerenciadas, como GKE COS, os desativam). Onde você não pode habilitá-lo, isso é esperado e seguro — o auditor degrada para SQL apenas automaticamente. Veja [deployment.md](/pt-br/agenteye/deployment). + +### Relatório de e-mail de auditoria não entregue + +**Sintoma:** uma auditoria revelou novas descobertas, mas nenhum e-mail chegou. + +**Causa:** a auditoria não tem um canal de **e-mail** anexado, o e-mail está desativado em toda a organização em `alerts.enabled_channels`, não há destinatários, ou o SMTP não está configurado. + +**Correção:** anexe um canal de e-mail à auditoria, certifique-se de que `email` está em `alerts.enabled_channels`, defina destinatários (no canal ou via `alerts.email_default_recipients`) e configure o SMTP (o mesmo transporte que os e-mails de alertas + OTP usam). O e-mail é enviado apenas quando uma execução produz **pelo menos uma nova** descoberta. + +### Um padrão silenciado ou descartado mantém sua página de descoberta antiga, mas nunca é re-classificado + +**Sintoma:** após silenciar uma descoberta, execuções posteriores nunca surfaceiam aquele padrão novamente — mesmo que ele ainda ocorra. + +**Causa:** esse é o comportamento projetado: silenciar/descartar são supressões duráveis codificadas pela impressão digital do padrão. + +**Correção:** abra a descoberta e use **reopen** para limpar a supressão; a próxima execução classificará o padrão novamente. Use **resolve** (não silenciar) para padrões "corrigidos" sobre os quais você gostaria de ser notificado se regredirem. + +--- + +## Obtendo Ajuda + +Entre em contato com `support@exosphere.host` com: +- Sua versão do AgentEye (da tag de release) +- Logs relevantes do container (`docker logs `) +- Uma descrição do problema e o que você já tentou \ No newline at end of file diff --git a/docs/ru/agenteye/alerts.mdx b/docs/ru/agenteye/alerts.mdx new file mode 100644 index 00000000..08bb3256 --- /dev/null +++ b/docs/ru/agenteye/alerts.mdx @@ -0,0 +1,309 @@ +--- +title: "Alerts" +description: "Документация AgentEye Alerts." +--- + + +Alerts оценивают правило по расписанию и уведомляют вас, когда что-либо пересекает пороговое значение. Они превращают AgentEye из пассивной панели мониторинга в систему оповещений для важных событий: всплески процента ошибок, регрессия задержки, падение оценок от оценивателя или любое пользовательское событие, которое можно выразить как запрос ClickHouse. + +В этом руководстве рассмотрены: что такое alert, пять типов триггеров, четыре канала уведомлений, жизненный цикл инцидента и операционные параметры. + +![Страница Alerts: сетка карточек alert-правил, каждая показывает тип триггера, окно оценки, каналы и значок серьезности (info/warning/critical)](/agenteye/images/alerts.png) + +--- + +## Основные понятия + +- **Alert** — правило. Оно указывает *что* проверять (триггер), *как часто* (интервал оценки), *когда считать неисправным* (составная логика), *насколько срочно* (серьезность) и *кого/куда уведомлять* (каналы). +- **Incident** — что происходит, когда alert срабатывает. Один alert имеет максимум один открытый инцидент одновременно. Повторные нарушения обновляют доказательства того же инцидента. Инциденты разрешаются оператором; автоматическое разрешение при прекращении действия правила планируется, но не включено в настоящее время. +- **Channel** — место отправки уведомления: email, Slack, generic webhook или внутри панели. Каждый alert может использовать любую комбинацию. + +Alerts и инциденты принадлежат организации и совместно используются операторами этой организации (в развертывании с одним клиентом это просто встроенная организация `default`). Инциденты можно назначить отдельному оператору для сортировки. + +--- + +## Типы триггеров + +Пять видов, каждый с собственной JSON-спецификацией. Выберите тот, который соответствует тому, как вы хотите описать "неисправность". Форма **new alert** на панели мониторинга создает ту же спецификацию для вас, переключая редактор условий в соответствии с выбранным типом триггера: + +![Форма new-alert с основами (имя, описание, включено) и средство выбора триггера, показывающее metric threshold, custom SQL, evaluation score, eval failures и per-event опции](/agenteye/images/alert-new.png) + +### 1. `metric_threshold` + +Самый простой. Выберите метрику из закрытого списка, оператор, пороговое значение и временное окно. + +| Метрика | Что она считает | +|---|---| +| `event_count` | Всего событий в окне | +| `error_count` | `event_type = 'error'` ИЛИ любое событие с `error_type IS NOT NULL` | +| `error_rate` | `error_count / event_count` (0..1) | +| `p95_latency_ms` | `quantile(0.95)(duration_ms)` для всех событий с `duration_ms` | +| `p99_latency_ms` | `quantile(0.99)(duration_ms)` | +| `token_sum` | `SUM(input_tokens + output_tokens)` | + +Операторы: `>`, `>=`, `<`, `<=`, `==` (также принимаются как `gt`, `gte`, `lt`, `lte`, `eq`). + +Необязательные фильтры: `environment`, `event_type`. + +Пример спецификации: + +```json +{ + "metric": "p95_latency_ms", + "filter": { "environment": "production" }, + "window_secs": 900, + "op": ">", + "value": 5000 +} +``` + +### 2. `custom_sql` + +Для всего, что не охватывают предустановленные метрики. SQL, предоставленный оператором, проходит через ту же защиту `/queries/run` (SELECT/WITH только, одно выражение, лимит 10 000 строк) перед запуском диспетчером. Два режима: + +- **rows mode** (без `op`/`value`): alert срабатывает, как только запрос вернет как минимум одну строку. +- **value mode**: запрос должен давать одному столбцу псевдоним `metric_value`; диспетчер сравнивает `metric_value` первой строки с `value`, используя `op`. + +```json +{ + "sql": "SELECT count() AS metric_value FROM agenteye.events WHERE event_type = 'error' AND ts >= now() - INTERVAL 1 HOUR", + "op": ">", + "value": 100 +} +``` + +### 3. `evaluation_score` + +Читает `agenteye.evaluations` и сравнивает среднее значение именованной оценки в пределах окна. + +```json +{ + "score_key": "hallucination", + "op": ">", + "value": 0.6, + "window_secs": 3600, + "min_count": 5, + "environment": "production" +} +``` + +`min_count` защищает от выбросов с одной выборкой; диспетчер не срабатывает, пока в окне не будет как минимум N оценок. + +### 4. `eval_compound` + +Перехватите регрессию качества, которая проявляется только во *многих* оценках оценивателя одновременно. Где `evaluation_score` отслеживает одну именованную оценку, `eval_compound` составляет несколько условий evaluation-score в один alert и объединяет их результаты с выбранной логикой; так что одно правило может выражать "срабатывай, если helpful падает **или** hallucination растет", "срабатывай только если helpful **и** tool-efficiency оба падают", или "срабатывай, если **как минимум 2 из** этих трех проверок нарушаются". + +Каждое условие читает среднее значение одной именованной оценки из `agenteye.evaluations` в пределах общего окна и тестирует его с собственным оператором и пороговым значением. Логические результаты затем объединяются с помощью `combinator`: + +| Combinator | Логика | Срабатывает, когда | +|---|---|---| +| `"any"` | ИЛИ | как минимум одно условие нарушено | +| `"all"` | И | все условия нарушены | +| `{ "at_least": N }` | M из N | как минимум N условий нарушены | + +```json +{ + "combinator": { "at_least": 2 }, + "conditions": [ + { "score_key": "hallucination", "op": ">", "value": 0.8 }, + { "score_key": "helpfulness", "op": "<", "value": 0.6 }, + { "score_key": "tone", "op": "<", "value": 0.5 } + ], + "window_secs": 3600, + "min_count": 5, + "environment": "production" +} +``` + +- `combinator`: `"any"`, `"all"`, или `{ "at_least": N }`. +- `conditions[]`: каждый `{ score_key, op, value }`, используя те же операторы, что и другие триггеры (`>`, `>=`, `<`, `<=`, `==`). +- `window_secs`: общий lookback, применяемый к каждому условию (по умолчанию `3600`). +- `min_count`: минимальное количество оценок на условие перед тем, как это условие может быть нарушено; условие с слишком малым количеством выборок в окне считается нарушенным (по умолчанию `1`). +- `environment`: необязательно; ограничивает каждое условие одной средой. + +Доказательство уведомления записывает наблюдаемое среднее каждого условия, пороговое значение, для которого оно было протестировано, количество видимых оценок и был ли нарушен порог; так вы можете точно увидеть, какие проверки сработали. + +### 5. `per_event` + +Для alerts типа "любое событие, соответствующее X, попало". Без агрегации; диспетчер срабатывает, как только видит совпадение в окне lookback. + +```json +{ + "event_type": "error", + "lookback_secs": 60, + "environment": "production", + "tool_name": "bash", + "agent_id": "caa", + "error_type": "TimeoutError", + "message_contains": "vertex-ai timed out" +} +``` + +Все фильтры объединяются с И; любое поле, которое вы не указываете, не ограничено. + +| Поле | Назначение | +|---|---| +| `agent_id` | Ограничить ошибками от конкретного агента (тот, что показан на строке `/errors`). | +| `error_type` | Ограничить определенным классом ошибок (например, `TimeoutError`) вместо каждой ошибки. | +| `message_contains` | Совпадение подстроки без учета регистра против `payload.message`. Полезно для перехвата одного конкретного режима отказа (например, `prompt is too long`) без оповещения об каждой ошибке от одного агента. Ограничено 200 символами; сопоставляется как буквальная строка, не как шаблон. | + +Совет: установите `lookback_secs` примерно соответствующим `eval_interval_secs` alert, чтобы не получить двойное уведомление об одном и том же событии. + +**Ярлык из `/errors`:** каждая строка представителя группы ошибок на представлении ошибок (и панель деталей события сеанса для события ошибки) имеет кнопку **+ alert**, которая открывает `/alerts/new` с предварительно заполненным триггером `per_event`, ключевым для `event_type` и среды этой строки, включая имя, полученное из `error_type` payload, когда присутствует. Вы все еще выбираете каналы и подтверждаете lookback, но средство сопоставления заполнено за вас. Операторы нуждаются в `alerts:write` для появления кнопки. + +--- + +## Составная логика (M из N) + +Каждый alert имеет два целочисленных параметра в дополнение к триггеру: + +- `eval_window`: количество последних оценок, на которые смотреть (по умолчанию 1) +- `min_breaches`: сколько из них должны быть нарушены перед срабатыванием alert (по умолчанию 1) + +`1 of 1` (по умолчанию) — это срабатывание при первом нарушении. `3 of 5` означает срабатывание, когда правило нарушено в 3 из последних 5 оценок, полезно для нестабильных сигналов, где одно плохое измерение является шумом. Диспетчер поддерживает кольцевой буфер для каждого alert; вам не нужно управлять состоянием. + +--- + +## Интервал оценки + +`eval_interval_secs` контролирует, как часто диспетчер запускает ваше правило. Ограничено `[30, 86400]`. Предустановки на панели мониторинга: 1m / 5m / 15m / 1h. Выберите интервал, соответствующий скорости изменения основного сигнала: alert об ошибке за 5 минут, оцениваемый каждые 15 секунд, тратит ЦП впустую; alert per-event нуждается в коротком lookback или он будет молча пропускать события между тиками. + +--- + +## Каналы + +Каждый alert может использовать любую комбинацию из этих четырех. Учетные данные по каналам (URL Slack webhook, generic webhook URL + signing secret, получатели email по умолчанию) настраиваются один раз в **`/settings`** и ссылаются по ключу из каждого alert. Таким образом, один канал Slack может служить множеству alerts без сохранения собственной копии URL webhook. + +Три внешних типа каналов (email, Slack, webhook) также контролируются общим для организации переключателем отключения, `alerts.enabled_channels`. Когда срабатывающий alert присоединяет тип канала, который не входит в этот набор, диспетчер пропускает его и записывает строку `alert_notifications` со статусом `skipped_disabled` и целевым `` (позволяя вам глобально приостановить, например, всю доставку Slack без редактирования каждого правила). Канал внутри панели всегда разрешен. Смотрите [Конфигурация](#configuration). + +### Email + +Повторно использует тот же SMTP-транспорт, который доставляет email-ы входа OTP. Получатели разрешаются в порядке: + +1. Переопределение `recipients[]` для каждого канала (когда не пусто). +2. Параметр `alerts.email_default_recipients` (массив строк email). + +Если SMTP не настроен, канал — это no-op; диспетчер все еще записывает строку `alert_notifications` с целевым ``, так что журнал аудита делает неправильную конфигурацию видимой. + +### Slack + +Отправляет Block Kit-сообщение на [incoming webhook URL](https://api.slack.com/messaging/webhooks). + +- URL по умолчанию: `alerts.slack_default_webhook` (установлено в `/settings`). +- Переопределение для каждого alert: установите `webhook_setting_key` канала на любой другой ключ параметра типа URL, например, `alerts.slack_oncall`, `alerts.slack_costs`. + +Заголовок включает emoji серьезности (`:rotating_light:` / `:warning:` / `:bell:`), и сообщение содержит кнопку, которая глубоко ссылается на страницу инцидента. + +### Generic webhook + +Интеграция JSON-POST для PagerDuty, Opsgenie или вашей собственной конечной точки приема. Форма тела: + +```json +{ + "schema_version": 1, + "event": "alert.firing", + "incident": { "id": "uuid", "url": "https://…/incidents/uuid", "opened_at": "2026-…" }, + "alert": { "id": "uuid", "name": "errors > 50/hr", "severity": "critical" }, + "breach": { "value": 73.0, "summary": "ErrorCount > 50 (observed 73.000)", "evidence": { … } } +} +``` + +Когда установлен `alerts.webhook_signing_secret`, запрос включает заголовок `X-AgentEye-Signature: sha256=`, HMAC-SHA256 тела с использованием секрета. Проверьте его на стороне получателя перед доверием payload. + +Заголовок `X-AgentEye-Event` содержит `alert.firing` / `alert.test`. (`alert.resolved` зарезервирован для планируемой функции авторазрешения и в настоящее время не передается.) + +### Внутри панели + +Без внешней доставки: alert просто записывает строку `alert_notifications`, которую страница инцидентов панели отображает. Полезно при настройке правила и вы не хотите спамить внешнюю систему, или для неспешных alerts, которые операторы проверяют при обычной сортировке. + +--- + +## Жизненный цикл инцидента + +``` +firing ──ack──▶ acknowledged + │ │ + └────────────────────┴───── operator resolve ───▶ resolved +``` + +- **firing** — диспетчер только что открыл инцидент или обнаружил другое нарушение. Уведомление о срабатывании разветвляется ровно один раз (контролируется временной меткой `notified_firing_at` инцидента). +- **acknowledged** — оператор нажал *ack* на `/incidents/:id`. Инцидент по-прежнему считается открытым; последующие нарушения обновят его доказательства без повторного уведомления. +- **resolved** — оператор нажал *resolve*. Автоматическое разрешение при прекращении нарушения правила планируется, но в настоящее время не включено, поэтому открытый инцидент остается открытым, пока оператор его не разрешит. + +Новый инцидент может снова открыться на одном и том же alert в любой момент после разрешения предыдущего. + +**Временная шкала активности.** Каждое действие на инцидент — открыт, подтвержден, разрешен — записывается в журнал активности только для добавления и показывается на временной шкале *activity* инцидента, каждая запись приписывается оператору, который выполнил это действие (по email) или к **automated** для действий, которые диспетчер выполнил самостоятельно (автоматическое открытие при нарушении). Подтверждение является общим: несколько операторов могут подтвердить один инцидент, и каждое появляется как отдельная, приписываемая запись. + +Входящий список **Incidents** группирует открытые инциденты по состоянию и позволяет фильтровать по серьезности и назначенному лицу: + +![Входящий список Incidents, показывающий alert-связанные и ad-hoc карточки инцидентов со значками серьезности и назначенными лицами](/agenteye/images/incidents.png) + +Открытие инцидента показывает доказательство нарушения, назначенные лица и подписчики, приписываемую временную шкалу активности и ветку комментариев: + +![Представление детали инцидента: родительский alert, резюме нарушения, назначенные лица, подписчики, журнал приписываемой активности и разговор](/agenteye/images/incident-detail.png) + +--- + +## Требуемые разрешения + +Создание alert-*правил* и сортировка *инцидентов* — это отдельные проблемы с отдельными разрешениями, поэтому вы можете дать доступ к инцидентам дежурной ротации без передачи ей возможности переписывать правила. + +- `alerts:read`: просмотр alert-правил. +- `alerts:write`: создание, редактирование, удаление alert-правил и активирование тестового уведомления. +- `incidents:read`: просмотр инцидентов. +- `incidents:write`: открытие ручных (ad-hoc) инцидентов, не связанных с alert. +- `incidents:ack`: подтверждение, назначение, комментирование и разрешение инцидентов. + +> **Устаревший `alerts:ack`.** Ключи и операторы, которым было предоставлено более старое разрешение `alerts:ack`, продолжают работать: оно принимается как `incidents:ack` (и подразумевает `incidents:read`), поэтому существующие дежурные операторы сохраняют свой доступ без переизданий учетных данных. Выпускайте новые разрешения с семейством `incidents:*`. + +Предоставьте на API-ключи (`POST /keys`) и операторов (`PUT /users/:id`). `PermGate` панели блокирует соответствующие кнопки при отсутствии разрешения; вы увидите `// 403` рядом с действием. + +> **Средство выбора получателя Email.** Средство выбора получателей редактора alert отображает членов вашей организации, так что вы можете выбрать их по имени. Он загружается для любого оператора, имеющего `alerts:read` или `alerts:write`; просмотр каталога вашей команды для этой цели **не** требует `users:read`, и средство выбора возвращает только адреса email членов, никогда полные записи пользователей. + +--- + +## Конфигурация + +Переменные окружения, используемые диспетчером: + +| Переменная | По умолчанию | Назначение | +|---|---|---| +| `ALERT_WORKERS` | `1` | Рабочие задачи на экземпляр сервера. Большинство развертываний нуждаются только в одной. | +| `ALERT_CLAIM_BATCH` | `16` | Макс alert-ы, которые один рабочий тик обрабатывает. | +| `ALERT_POLL_IDLE_SECS` | `5` | Сон рабочего при пустой очереди. | +| `ALERT_REQUEST_TIMEOUT_MS` | `15000` | Тайм-аут оценки на триггер. | +| `DASHBOARD_URL` | `https://app.befailproof.ai` | Источник, используемый для построения magic-link инцидента в уведомлениях. Установите на вашего хоста панели. | + +После временного сбоя оценки (ClickHouse недоступен, тайм-аут запроса), диспетчер повторяет правило с экспоненциальной задержкой. Как только правило накопит **5** последовательных временных сбоев, оно переплан ируется на нормальный ритм вместо продолжения задержки, так что постоянно неправильное правило все еще продолжает переоцениваться. Этот потолок фиксирован и не настраивается оператором. + +Параметры канала (управляются из `/settings`, не env): + +- `alerts.email_default_recipients` (`email_list`): JSON-массив строк email — получатели по умолчанию для email-каналов. +- `alerts.slack_default_webhook` (`url`): URL Slack incoming-webhook по умолчанию. +- `alerts.webhook_default_url` (`url`): URL generic-webhook по умолчанию. +- `alerts.webhook_signing_secret` (`secret`): ключ HMAC-SHA256. Всегда возвращается как `""` в ответе GET; введите новое значение для ротации. +- `alerts.enabled_channels` (`channel_set`): набор внешних типов каналов для организации, которые отправляются при срабатывании alert; по умолчанию все три (`email`, `slack`, `webhook`). Удаление типа здесь глобально подавляет этот канал для каждого alert без редактирования каждого правила. Канал внутри панели всегда доставляется и не затрагивается этим параметром. + +--- + +## Проверка нового alert + +Перед использованием нового alert: + +1. Сохраните его как включенный с как минимум одним каналом уведомления. +2. Выберите **test** на странице деталей alert и подтвердите, что каждое настроенное место назначения получает синтетическое уведомление. +3. После первого реального нарушения подтвердите, что инцидент появляется под **Incidents** и его измеренное значение соответствует соответствующему запросу панели. + +Инциденты не разрешаются автоматически при очистке условия. Оператор должен разрешить их со страницы детали инцидента. + +--- + +## Устранение неполадок + +| Симптом | Вероятная причина | +|---|---| +| Alert никогда не срабатывает | `enabled = false`, или нет прикрепленных каналов, или основной запрос CH возвращает 0 строк. Используйте *test* для подтверждения каналов; используйте `/queries/run` для подтверждения метрики. | +| Уведомление Slack отсутствует | `alerts.slack_default_webhook` (или ключ переопределения для каждого alert) не установлен: проверьте `alert_notifications.target` на строках ``; или тип `slack` глобально отключен в `alerts.enabled_channels`: проверьте строки `alert_notifications` со статусом `skipped_disabled` и целевым ``. | +| Generic webhook 401 | Получатель требует подписи, но `alerts.webhook_signing_secret` не установлен. Проверьте на получателе, что HMAC соответствует `hmac_sha256(secret, body)`. | +| Email "from all sends failed" | SMTP-учетные данные неправильны или адрес `from` отклоняется вашим реле. Та же поверхность, которая доставляет email-ы OTP: если те работают, SMTP-транспорт в порядке. | +| Инцидент переоткрывается повторно | Составные параметры слишком агрессивны: попробуйте увеличить `min_breaches` или `eval_window`, чтобы временные всплески не переоткрывали разрешенные инциденты. | \ No newline at end of file diff --git a/docs/ru/agenteye/api-keys.mdx b/docs/ru/agenteye/api-keys.mdx new file mode 100644 index 00000000..6fc6d1ee --- /dev/null +++ b/docs/ru/agenteye/api-keys.mdx @@ -0,0 +1,255 @@ +--- +title: "API-ключи" +description: "Документация по API-ключам AgentEye." +--- + + +AgentEye использует детально настраиваемые API-ключи для управления доступом к серверу. Каждый ключ имеет одно или несколько разрешений, которые определяют его возможности. + +--- + +## Разрешения + +Сервер поддерживает фиксированный набор разрешений; каждое из них управляет доступом к определённым HTTP маршрутам. **Административный ключ** имеет все разрешения; ограниченный ключ имеет подмножество, которое вы предоставляете при создании. Неизвестные строки разрешений отклоняются при создании ключа. + +> **Не могут быть назначены ключам.** Два действительных разрешения предназначены только для человека/панели и не могут быть предоставлены API-ключу: `orgs:admin` (администрирование экземпляра, только для операторов) и `keys:update`. Запрос к `POST /keys` или `PATCH /keys/:id`, пытающийся предоставить одно из них, отклоняется с кодом HTTP 422. Смотрите строку `keys:update` ниже, чтобы понять, почему ключ-носитель может создавать ключи, но не может их редактировать. + +### Приём и запрос событий + +| Разрешение | HTTP-маршруты | Что оно позволяет | +|---|---|---| +| `events:add` | `POST /events` | Приём пакетов событий от сборщика. Единственное разрешение, необходимое сборщику. | +| `events:read` | `GET /events`, `GET /events/latency_aggregate`, `GET /events/environments`, `GET /events/models`, `GET /sessions/:session_id/export` | Запрос событий, получение списка известных окружений, получение идентификаторов моделей в данных (используется в представлении Models и фильтрах модели), расчёт совокупной задержки для тепловой карты / полос процентилей и экспорт сеанса в формате JSONL. Общие конечные точки фасетов фильтра `GET /events/environments` и `GET /events/models` доступны с **либо** `events:read` **либо** `evaluations:read`, поэтому страница сеансов (требует `evaluations:read`) переиспользует тот же фасет для каждой организации. | + +### Сеансы и оценки + +| Разрешение | HTTP-маршруты | Что оно позволяет | +|---|---|---| +| `evaluations:read` | `GET /sessions`, `GET /evaluations`, `GET /evaluations/aggregate`, `GET /evaluations/environments`, `GET /evaluation-jobs` | Список сеансов, чтение результатов оценки, свёрнутое состояние здоровья оценки для панелей и состояние очереди работников заданий оценки. | +| `evaluations:trigger` | `POST /sessions/:session_id/re-evaluate` | Ручная постановка в очередь переоценки завершённого сеанса. | + +### Панели + +| Разрешение | HTTP-маршруты | Что оно позволяет | +|---|---|---| +| `dashboards:read` | `GET /dashboards`, `GET /dashboards/:id`, `GET /dashboards/:id/tiles` | Получение списка панелей, загрузка одной и чтение её плиток. | +| `dashboards:write` | `POST /dashboards`, `PUT /dashboards/:id`, `POST /dashboards/:id/tiles`, `PUT /dashboards/:id/tiles/:tile_id`, `DELETE /dashboards/:id/tiles/:tile_id`, `PUT /dashboards/:id/tiles/layout` | Создание и редактирование панелей, добавление / редактирование / удаление плиток и переупорядочение сетки плиток. | +| `dashboards:delete` | `DELETE /dashboards/:id` | Удаление полной панели (удаление уровня плиток находится под `dashboards:write`). | + +### Сохранённые запросы (SQL-композитор) + +| Разрешение | HTTP-маршруты | Что оно позволяет | +|---|---|---| +| `queries:read` | `GET /queries`, `GET /queries/:id`, `GET /queries/schema` | Получение списка сохранённых запросов, загрузка одного и проверка схемы только для чтения ClickHouse, на которую ориентирован композитор. | +| `queries:write` | `POST /queries`, `PUT /queries/:id` | Создание и редактирование сохранённых запросов. SQL по-прежнему маршрутизируется через ту же роль только для чтения и проверки `sql_guard`, что и вызов `queries:run`. | +| `queries:delete` | `DELETE /queries/:id` | Удаление сохранённого запроса. | +| `queries:run` | `POST /queries/run` | Выполнение сохранённого или специального SQL-запроса к роли только для чтения, используемой композитором. | + +### Помощник AI + +| Разрешение | HTTP-маршруты | Что оно позволяет | +|---|---|---| +| `agent:use` | `GET /agent/conversations`, `POST /agent/conversations`, `GET /agent/conversations/:id`, `PATCH /agent/conversations/:id`, `DELETE /agent/conversations/:id`, `PUT /agent/conversations/:id/messages` | Общение с помощником AI панели и управление своими (приватными) беседами. Требуется для **пользователя**, чтобы увидеть док помощника; собственный ключ помощника - это `dashboard-assistant` и он инициализируется отдельно (смотрите ниже). | + +### API-ключи + +| Разрешение | HTTP-маршруты | Что оно позволяет | +|---|---|---| +| `keys:create` | `POST /keys` | Создание нового ограниченного API-ключа. **Не** предоставляет редактирование разрешений существующего ключа (это `keys:update`). | +| `keys:read` | `GET /keys` | Получение списка существующих ключей. Секреты никогда не возвращаются этой конечной точкой. | +| `keys:update` | `PATCH /keys/:id` | Редактирование разрешений существующего ключа. Разрешение **только для человека/панели**; оно не может быть назначено API-ключу (ключ-носитель может создавать ключи, но не может их редактировать). | +| `keys:disable` | `POST /keys/:id/disable` | Отзыв ключа. Защищённые ключи (`admin`, `dashboard-assistant`) нельзя отключить; поверните их через переменную окружения и перезагрузку. | +| `keys:regenerate` | `POST /keys/:id/regenerate` | Ротация секрета ключа. Защищённые ключи нельзя восстановить через эту маршрут. | + +### Пользователи панели + +| Разрешение | HTTP-маршруты | Что оно позволяет | +|---|---|---| +| `users:create` | `POST /users`, `GET /users/defaults` | Приглашение нового пользователя панели (выдача письма + вход через OTP) и чтение набора разрешений по умолчанию, настроенного панелью и используемого для предварительного заполнения формы приглашения. | +| `users:read` | `GET /users`, `GET /users/:id` | Получение списка пользователей и загрузка одной записи пользователя. | +| `users:update` | `PUT /users/:id` | Редактирование разрешений пользователя. Обновления отправляют письмо об изменении разрешений затронутому пользователю и вступают в силу при его следующем запросе; повторный вход не требуется. | +| `users:delete` | `DELETE /users/:id`, `POST /users/:id/enable` | Отключение пользователя (немедленно отзывает его сеансы) и повторное включение ранее отключённого пользователя. | + +Эти разрешения поддерживают страницу **Пользователи** панели, где предоставленные области каждого члена отображаются как чипы: + +![Страница Пользователи: карточка на пользователя панели с адресом электронной почты, предоставленными разрешениями и элементами управления редактированием/отключением](/agenteye/images/users.png) + +### Операционные настройки + +| Разрешение | HTTP-маршруты | Что оно позволяет | +|---|---|---| +| `settings:read` | `GET /settings`, `GET /settings/schema`, `GET /settings/model-context-windows`, `GET /settings/model-context-windows/resolve` | Просмотр операционных настроек, управляемых панелью, и их метаданных; получение списка переопределений размера контекста для каждой модели; и разрешение эффективного окна для модели. | +| `settings:write` | `PUT /settings/:key`, `PUT /settings/model-context-windows`, `DELETE /settings/model-context-windows` | Редактирование операционных настроек и добавление, изменение или удаление переопределений размера контекста для каждой модели. Изменения влияют на новые события без перезагрузки сервера. | + +![Страница Настройки: операционные настройки, управляемые панелью, такие как допустимые входы и время жизни сеанса/OTP, редактируемые без перезагрузки](/agenteye/images/settings.png) + +### Оповещения и инциденты + +| Разрешение | HTTP-маршруты | Что оно позволяет | +|---|---|---| +| `alerts:read` | `GET /alerts`, `GET /alerts/:id` | Просмотр настроенных определений оповещений. | +| `alerts:write` | `POST /alerts`, `PUT /alerts/:id`, `DELETE /alerts/:id`, `POST /alerts/:id/test` | Создание, редактирование, удаление и тестовое срабатывание определений оповещений. | +| `incidents:read` | `GET /alerts/incidents`, `GET /alerts/incidents/:iid`, `GET /alerts/incidents/:iid/comments`, `GET /alerts/incidents/:iid/subscribers` | Просмотр инцидентов и их тропы сортировки. | +| `incidents:write` | `POST /alerts/:id/incidents` | Открытие инцидента вручную против существующего оповещения. | +| `incidents:ack` | `POST /alerts/incidents/:iid/ack`, `POST /alerts/incidents/:iid/assign`, `POST /alerts/incidents/:iid/resolve`, `POST /alerts/incidents/:iid/comments`, `POST /alerts/incidents/:iid/subscribe`, `POST /alerts/incidents/:iid/unsubscribe` | Подтверждение, назначение, разрешение и комментирование инцидентов. | + +### Проверки + +| Разрешение | HTTP-маршруты | Что оно позволяет | +|---|---|---| +| `audits:read` | `GET /audits`, `GET /audits/:id`, `GET /audits/:id/runs`, `GET /audits/findings`, `GET /audits/findings/:fid` | Просмотр определений проверок, истории выполнения и результатов. | +| `audits:write` | `POST /audits`, `PUT /audits/:id`, `DELETE /audits/:id`, `POST /audits/:id/run`, `POST /audits/findings/:fid/status` | Создание, редактирование, удаление и выполнение проверок; сортировка результатов (подтверждение / отключение / отклонение / разрешение / переоткрытие / назначение). | + +> Когда была выпущена функция Проверки, существующие грантополучатели были расширены по той же структуре ролей, что и оповещения: каждый пользователь и набор разрешений, содержащий `alerts:read`, получили `audits:read`, и каждый владелец `alerts:write` получил `audits:write`. Существующие API-ключи **не были** расширены — явно предоставьте `audits:*` ключу, если ему нужна поверхность проверок. + +> Сохранённые предоставления устаревшего токена `alerts:ack` анализируются как `incidents:ack`, поэтому дежурные сохраняют доступ без переключения ключей. Токен больше не может быть назначен из редактора пользователей панели; матрица вместо этого предлагает `incidents:ack`. + +> Конечная точка средства выбора получателей `GET /alerts/recipients` (которая перечисляет адреса электронной почты членов, которых может уведомить редактор оповещений) доступна держателю **либо** `alerts:read` **либо** `alerts:write`, поэтому редакторы оповещений могут заполнить средство выбора без предоставления `users:read`. + +> Зритель панели нуждается в **обоих** `dashboards:read` (для загрузки сохранённых представлений) и `evaluations:read` (метрики здоровья вычисляются из данных оценки). Предоставьте `dashboards:write`, чтобы позволить пользователю создавать или редактировать панели, и `dashboards:delete`, чтобы удалять их. + +> `/health` и `/auth/*` (запрос OTP, проверка OTP, проверка сеанса, выход) не аутентифицированы намеренно; это поток входа и зонд живости. `GET /access-granters` требует действительный ключ, но не требует конкретного разрешения, поэтому любой вошедший пользователь может увидеть, какие администраторы могут помочь с изменением доступа. + +--- + +## Наборы разрешений + +Наборы разрешений позволяют применять именованную роль вместо выбора отдельных токенов каждый раз. Вместо выбора дюжины разрешений одного за другим для каждого нового пользователя панели или API-ключа, вы выбираете набор, и каждому, кто ему назначен, присваивается согласованное, проверяемое предоставление. Редактирование пользовательского набора повторно применяет новое предоставление каждому пользователю, уже ему назначенному, поэтому изменение роли - это одно редактирование, а не обход каждого члена. + +Каждая организация инициализируется с тремя встроенными наборами: + +| Набор | Разрешения | Предназначен для | +|---|---|---| +| `read-only` | `events:read`, `keys:read`, `users:read`, `evaluations:read`, `dashboards:read`, `queries:read`, `settings:read`, `alerts:read`, `audits:read`, `incidents:read` | Доступ только для просмотра по всей операционной поверхности. | +| `standard` | всё в `read-only`, плюс `evaluations:trigger`, `queries:run`, `incidents:ack`, `agent:use` | Только для чтения плюс повседневные действия дежурного: выполнение запросов, переоценка сеансов, подтверждение инцидентов и использование помощника AI. | +| `admin` | каждое назначаемое разрешение | Полный контроль над организацией. | + +Три встроенных набора **неизменяемы**; их имена всегда означают одно и то же, поэтому `read-only`, `standard` и `admin` безопасно ссылать в политике и адаптации. Оператор может создавать дополнительные **пользовательские наборы** для моделирования ролей, специфичных для вашей организации (например, роль "автор панели" или роль "только сборщик"). + +Наборы отображаются на панели и управляются через API в `GET /permission-sets` (список, требует `users:read`) и `POST /permission-sets` / `PUT /permission-sets/:name` / `DELETE /permission-sets/:name` (создание, редактирование, удаление пользовательского набора, требует `settings:write`). Удаление или редактирование встроенного набора отклоняется. + +Членство в наборе поддерживает две другие функции: + +- **`DEFAULT_USER_PERMISSIONS`** (предварительно выбранное предоставление при открытии администратором **+ новый пользователь**) по умолчанию использует набор `standard`. Смотрите [Развёртывание](/ru/agenteye/deployment). +- **Флаг `--set`** в `agenteye-orgctl` (управление членами оператора) запускает члена из именованного набора, который вы затем дополняете с помощью `--add` / `--remove`. Смотрите [Управление арендаторами](/ru/agenteye/tenant-management). + +> Когда набор включает разрешение, которое не может быть назначено ключу (например пользовательский набор, содержащий `keys:update`), инициализация ключа из этого набора отбрасывает неназначаемые токены; сервер иначе отклонил бы ключ с кодом HTTP 422. Пользователи панели не подлежат этому ограничению. + +--- + +## Начальный административный ключ + +Административный ключ - это единственное корневое учётное данные, которое позволяет оператору начать доступ с нуля: с его помощью вы можете создавать каждый другой ограниченный ключ, приглашать первых пользователей панели и конфигурировать экземпляр до того, как существует какой-либо другой ключ. Это единственный ключ, который вы не создаёте через API ключей; он инициализируется из окружения, чтобы сервер был доступен при первой загрузке. + +Установите переменную окружения `ADMIN_KEY` на сервере. При каждой загрузке сервер вставляет это значение как административный ключ со всеми разрешениями. + +Для ротации: измените `ADMIN_KEY` на новый секрет и перезагрузите сервер. + +--- + +## Область организации + +**Организации сами создаются и управляются оператором вне полосы, не через этот API ключей.** Жизненный цикл организации и членов (создание / переименование / удаление / очистка организации; добавление / обновление / удаление члена) осуществляется с помощью **CLI `agenteye-orgctl`**, который работает внутри модуля сервера; нет HTTP API или кнопки панели для этого. Смотрите [Управление арендаторами](/ru/agenteye/tenant-management). Что *остаётся* неизменным: **API-ключи для каждой организации всё ещё создаются на панели (или через этот API ключей)** членами организации. + +При развёртывании с несколькими организациями, каждый ключ, создаваемый членом организации (через этот API ключей или страницу **Ключи** панели), принадлежит **одной организации** и может только читать или писать данные этой организации; организация отмечается на ключе при создании и применяется при каждом запросе. Два начальных ключа - единственное исключение: ключ `admin` (инициализируется из `ADMIN_KEY`) и ключ `dashboard-assistant` (инициализируется из `AGENT_API_KEY`) **относятся к экземпляру** (они не имеют организации). Контейнер панели аутентифицируется с помощью ключа `admin`, чтобы он мог проксировать запросы для каждой организации от имени вошедших членов. Развёртывания с одним арендатором не нуждаются в этом; все ключи принадлежат встроенной организации `default`. + +--- + +## Создание ключей + +Используйте административный ключ (или любой ключ с разрешением `keys:create`) для создания дополнительных ограниченных ключей. + +### Ключ сборщика (только приём) + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "prod-collector", + "key": "your-collector-secret", + "permissions": ["events:add"] + }' +``` + +### Ключ панели (только чтение) + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "dashboard", + "key": "your-dashboard-secret", + "permissions": ["events:read", "keys:read"] + }' +``` + +Когда вы создаёте ключ через HTTP API, вы сами предоставляете значение `key`; выберите надёжный секрет и сохраните его безопасно. (Панель работает по-другому: она генерирует надёжный секрет для вас и показывает его один раз при создании; смотрите [Управление ключами на панели](#key-management-in-the-dashboard).) Ответ подтверждает, что ключ был создан: + +```json +{ + "id": "550e8400-e29b-41d4-a716-446655440000", + "name": "prod-collector", + "permissions": ["events:add"], + "created_at": "2026-04-01T12:00:00Z" +} +``` + +--- + +## Получение списка ключей + +```bash +curl -s http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +Секреты ключей не возвращаются в ответах списка, только ID, имена и разрешения. + +--- + +## Отключение ключа + +Отключение отзывает доступ немедленно без удаления записи ключа. + +```bash +curl -s -X POST http://your-server:8080/keys//disable \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +--- + +## Восстановление ключа + +Генерирует новый секрет для существующего ключа. Старый секрет немедленно становится недействительным. + +```bash +curl -s -X POST http://your-server:8080/keys//regenerate \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +Ответ включает новый секрет в открытом виде, **показываемый только один раз**. + +--- + +## Управление ключами на панели + +Страница **Ключи** на панели предоставляет интерфейс для всех вышеперечисленных операций. Вам нужен ключ с разрешением `keys:read`, чтобы просмотреть список, и `keys:create` / `keys:update` / `keys:disable` / `keys:regenerate` для действий создания / редактирования / отключения / восстановления соответственно. Редактирование разрешений ключа (`keys:update`) отделено от создания (`keys:create`), поэтому вы можете предоставить оператору возможность создавать ключи без возможности переопределения существующих или наоборот. Административный ключ охватывает все эти действия. + +Когда вы создаёте ключ из панели, вы не предоставляете секрет; панель генерирует надёжный секрет для вас и отображает его **один раз** при создании. Скопируйте его немедленно и сохраните безопасно; он никогда больше не будет показан, точно как при восстановлении. Вы по-прежнему можете выбрать разрешения ключа напрямую или инициализировать их из набора разрешений (смотрите ниже). + +![Страница API-ключи: карточка на ключ, показывающая его имя, предоставленные разрешения и время создания, с действиями восстановления и отключения; защищённые ключи, такие как `admin`, отмечены](/agenteye/images/api-keys.png) + +--- + +## Рекомендуемый макет ключей + +| Ключ | Разрешения | Используется | +|---|---|---| +| `admin` (начальный через переменную окружения `ADMIN_KEY`) | все | Операции/настройка и контейнер панели (аутентифицируется с помощью `ADMIN_KEY`, проксирует запросы пользователей с проверками разрешений) | +| Ключ сборщика на хост | `events:add` | Сборщик на каждой машине агента | +| `dashboard-assistant` (начальный через переменную окружения `AGENT_API_KEY`) | `events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run` | Контейнер помощника AI, инициализируется автоматически, **защищён**; не может быть отредактирован через API | +| Ключ телеметрии помощника (опционально) | `events:add` | Самоинструментирование помощника AI, если включено | + +> **Ключ помощника.** Ключ помощника **инициализируется автоматически** сервером из переменной окружения `AGENT_API_KEY` (тот же секрет, который агент представляет как `AGENTEYE_API_KEY`); нет ручного шага создания ключа и не требуется административный ключ. Его разрешения фиксированы в исходном коде, поэтому область не может быть расширена неправильной конфигурацией: чтение по событиям / оценкам / панелям, плюс dashboards-write и queries-read / write / run для потока написания запроса Спроси AI. Весь SQL по-прежнему проходит через ту же роль только для чтения и проверки `sql_guard`, что и пользовательский запрос, поэтому это расширяет *поверхность написания*, а не поверхность данных; деструктивные операции (`queries:delete`, `dashboards:delete`) намеренно остаются вне ключа помощника. Как и ключ `admin`, он **защищён**: не может быть отключен или восстановлен через API ключей, только повёрнут изменением `AGENT_API_KEY` и перезагрузкой. Пользователи панели **дополнительно** нуждаются в разрешении `agent:use`, чтобы увидеть и использовать помощника. Если вы включаете самоинструментирование, дайте помощнику отдельный ключ, содержащий только `events:add`. \ No newline at end of file diff --git a/docs/ru/agenteye/assistant.mdx b/docs/ru/agenteye/assistant.mdx new file mode 100644 index 00000000..4f81a1fb --- /dev/null +++ b/docs/ru/agenteye/assistant.mdx @@ -0,0 +1,196 @@ +--- +title: "AI Assistant" +description: "Документация AI Assistant AgentEye." +--- + + +Панель управления включает опциональный **AI Assistant** — чат-панель, прикрепленную к правому краю, которая отвечает на вопросы на естественном языке об ваших агентах ("как меняется качество в prod на этой неделе?", "какие сессии упали сегодня?", "суммаризируй эту сессию") и при наличии разрешения пользователя создает и сохраняет SQL-запросы и панели управления от их имени. Ассистент приводит кликабельные ссылки прямо на соответствующие сессии, запросы и панели, и он **осведомлен о странице**: спросите о "этой сессии" во время просмотра — и он поймет, что вы имеете в виду. + +Панель показывается как тонкая **вертикальная полоса размером 44px** по умолчанию: глиф приглашения `›_` плюс цветная точка статуса. Нажмите на полосу (или нажмите `⌘J` / `Ctrl+J`), чтобы развернуть её в полную панель чата. Развернутая панель **изменяемого размера** между 320 и 640 пиксели путем перетягивания левого края; ваша предпочтительная ширина запоминается после перезагрузки. + +Работает как маленький внутренний контейнер **`agent`** (на Claude Agent SDK), который может вызывать только панель управления. По умолчанию **отключен** и остается скрытым до конфигурации LLM endpoint. + +--- + +## Что он может и не может делать + +- **Читает операционные данные, видимые запрашивающему пользователю.** События, оценки, сессии, очередь задач оценки, сохраненные запросы и панели, ограниченные по запросу правами доступа пользователя. Инструменты чтения выполняются немедленно. +- **Записи управляются поэтапным одобрением.** Может создавать сохраненные запросы (`create_saved_query`, `update_saved_query`), запускать черновик SQL против роли только для чтения для проверки (`run_query`) и собирать панели из этих запросов (`create_dashboard`, `update_dashboard`, `add_query_to_dashboard`). Каждая запись переходит в режим ожидания для приглашения **Одобрить / Отклонить / задать вопрос** в чате; SDK не вызывает инструмент до нажатия оператором кнопки Одобрить. **Удаление никогда не доступно ассистенту**; деструктивные операции остаются на стороне операторов. +- **Черновик SQL проходит ту же валидацию `sql_guard` и роли только для чтения, что и SQL, написанный пользователем** (SELECT/WITH только, без многоинструкционности). Выполнение маршрутизируется в зависимости от таблиц, к которым обращается запрос: запросы, ссылающиеся на таблицы аналитики (события, оценки, сессии), выполняются как пользователь организации только для чтения ClickHouse (ограничиваемый организацией политикой строк, с ограничением выполнения 10s и ограничением строк 100k), тогда как запросы, затрагивающие только реляционные таблицы, запускаются на роли только для чтения Postgres (10s, 10k строк). Ассистент не может расширить поверхность данных; он может только создавать запросы над поверхностью, к которой оператор уже имеет доступ. +- Использует **выделенный ключ ассистента** (см. ниже) с фиксированным набором разрешений; даже если модель ведет себя неправильно, она не может выходить за пределы этих областей. +- Каждому пользователю панели управления нужно разрешение **`agent:use`** для просмотра и использования ассистента. Инструменты фильтруются по запросу в соответствии с правами доступа пользователя, поэтому пользователь с `events:read` получает инструменты событий, но не инструменты `dashboards:write`. + +--- + +## Осведомленная о странице AI панель: композитор на `/queries`, чат в других местах + +Ассистент с правой стороны **осведомлен о странице**. Выбор модели, история разговора, точка статуса модели и ввод чата остаются неизменными, но **чипсы пустого состояния, текст-заполнитель и на какой бэкенд-endpoint попадает сообщение пользователя** автоматически переключаются на основе текущего маршрута. Панель становится "AI помощником для любой страницы, на которой вы находитесь". + +**Два бэкенда, выбранные для каждой страницы (с переопределением по чипу).** + +| Маршрут | Бэкенд по умолчанию для страницы | Причина | +| ------------------------------ | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | +| `/queries`, `/queries/new` | `POST /api/agent/compose-sql` (без цикла инструментов) | Пользователь начинает с нуля; ≤1s первый токен SQL потоком прямо в редактор | +| `/queries/` (существующий) | `POST /api/agent/chat` (полный цикл ассистента), по умолчанию для страницы | Вольные сообщения должны позволить пользователю спросить что угодно ("объясни это", "что это делает?"); чипсы рефакторинга возвращаются к compose-sql через явный `kind` | +| каждая другая страница | `POST /api/agent/chat` (полный цикл ассистента) | Инструменты чтения + инструменты записи с одобрением | + +Чипсы на `/queries/` несут явный `kind`, поэтому одна страница может беспрепятственно смешивать оба потока. Набор чипсов по умолчанию включает два чипса **chat** (`объясни запрос на экране`, `что делает этот запрос?`) плюс пять чипсов **compose-sql** (`параметризируй по диапазону дат`, `добавить фильтр status='error'` и т.д.). Вольно введенные сообщения переходят к значению по умолчанию для страницы (chat), поэтому вопрос типа "почему это так медленно?" получает ответ в прозе, тогда как клик на чип `параметризируй по диапазону дат` маршрутизируется через конечную точку compose и редактирует SQL. + +Когда композитор работает в **режиме редактирования** (он видит непустой `currentSql`, потому что пользователь находится на `/queries/` или `/queries/new` с предложенным SQL уже загруженным), его системный prompt переходит от "составить новый запрос" к "минимально изменить предоставленный SQL: сохранить выбор таблицы, имена столбцов, структуру соединения, псевдонимы, отступ". Модели показан отдельный набор примеров до/после (параметризация, добавление фильтра, преобразование в почасовые сегменты), поэтому рефакторинг по клику на чип создает минимальный diff против SQL редактора, а не переписывание с нуля. + +Щелкните чип compose (или введите свободно на `/queries/new`) → SQL потоком в сообщение ассистента как экранированный блок ` ```sql `. **В момент завершения потока, если Monaco смонтирован на текущем маршруте, редактор автоматически включает вид diff** (исходный слева, предложенный справа, подсказка `▾ AI предложил правку` вверху и таблетки **Принять / Отклонить** внизу). Пользователю не нужно искать или нажимать кнопку `Вставить в редактор` для просмотра diff. Кнопка Insert по-прежнему отображается под блоком SQL как ручной триггер повтора (полезна после Отклонения или когда пользователь ушел и вернулся), и это остается единственным путем, когда пользователь находится на странице без редактора (например, список сохраненных запросов); там он сохраняет SQL в `sessionStorage` и переходит к `/queries/new`, где свежемонтированный редактор читает запас при монтировании и открывает тот же вид diff. + +Если предложенный SQL байт-идентичен тому, что уже есть в редакторе (правка no-op), автооткрытие пропускается; мы не открываем пустой diff. Кнопка `Вставить в редактор` в этом случае также является no-op. + +Когда пользователь принимает предложение на `/queries/new`, основное действие панели инструментов читает **`save`** вместо `create`; SQL был передан им ассистентом; модель мышления — "завершить это", а не "писать с нуля". Метка переключается один раз, когда док вставляет SQL, и остается `save` до навигации по странице. На `/queries/` кнопка всегда читала `save`; там ничего не меняется. + +Вне `/queries` док работает как прежде: полный чат с карточками одобрения инструментов, осведомленность о контексте страницы, ссылки. + +**Разрешения / управление.** Конечная точка compose управляется разрешением `queries:run` для каждого пользователя (читайте-эквивалент; пользователь все еще должен нажать Принять и Запустить, и Запустить проходит через существующую маршрутизацию `sql_guard` + `references_ch_tables` на сервере Rust). Конечная точка chat управляется `agent:use`. Обе по-прежнему требуют конфигурации LLM-соединения на контейнере `agent`; если оно не сконфигурировано, док отображает баннер "ассистент не сконфигурирован на этом развертывании" на любом пути. + +**Отказы.** Композитор отказывается от любого запроса, который он не может удовлетворить с помощью запроса только для чтения аналитики, и выдает `-- REFUSE: <одноразовая причина>` вместо SQL. Отказывает запросы, которые будут писать данные или достигать таблиц вне представлений аналитики (`api_keys`, `users`, `dashboards`, `saved_queries`, `evaluation_jobs`), и отказывает чистые запросы в прозе ("объясни это", "что это делает?") на пути compose; они принадлежат пути chat и создают там ответ в прозе. Док отображает строку отказа как встроенный красный чип ошибки в сообщение ассистента; ничего не вставляется. + +**Выбор модели.** Общий с путем chat. Выбор модели в заголовке дока применяется к обоим конечным точкам (вызов compose передает выбранную модель через `resolveModel()` на сервис агента). Когда `AGENTEYE_AGENT_MODELS` указывает несколько моделей, операторы могут смешивать опцию Haiku-класса для композитора с опцией Sonnet-класса для чата; пользователь выбирает на разговор. + +**Шаблоны для каждой страницы.** Каждая страница имеет свой шаблон (заголовок, основной текст, текст-заполнитель и чипсы предложений), поэтому док адаптируется к странице, на которой вы находитесь. Предложенные чипсы на данном маршруте отображаются на те же намерения, на которые настроен композитор, поэтому клик на предложение создает ожидаемую правку. + +**Отключение.** Так же, как путь chat: док + композитор оба управляются контейнером `agent` и его LLM-соединением. Если вы хотите поведение только chat для конкретного пользователя, удалите разрешение `queries:run` (которое также отключает кнопку **Run** редактора); если вы хотите поведение только composer, удалите `agent:use` из ролей этого пользователя, затем повторно добавьте `queries:run` отдельно, чтобы они все еще могли выполнять авторский SQL. + +--- + +## Включение + +Сервис `agent` поставляется в файле Docker Compose и манифестах Kubernetes. Чтобы включить ассистента, предоставьте **(1)** LLM endpoint и **(2)** выделенный ключ данных ассистента. + +### 1. Выберите LLM-соединение + +Выберите одно из этих и установите соответствующие переменные на сервис `agent`: + +**a) Anthropic напрямую** + +``` +ANTHROPIC_API_KEY=sk-ant-... +``` + +**b) Через Portkey (рекомендуется; слаг каталога моделей, только ключ)** + +``` +PORTKEY_API_KEY= +AGENTEYE_AGENT_MODEL=@/claude-sonnet-4-6 +``` + +Это самый простой путь: в Portkey установите **Anthropic integration** (Model Catalog); она получит **слаг**. Назовите модель как `@/`, и слаг содержит маршрутизацию провайдера + учетные данные, поэтому **виртуальный ключ не требуется**, только ваш API ключ Portkey. Агент отправляет только `x-portkey-api-key` и указывает на шлюз Portkey; Portkey разрешает остальное. (Простое имя модели не работает с "x-portkey-config или x-portkey-provider header is required"; префикс `@slug/` — это то, что делает работу с ключом только). Для самостоятельного хостинга шлюза установите `PORTKEY_BASE_URL`. + +Предпочитаете маршрутизацию для каждого запроса вместо слага? Установите `PORTKEY_VIRTUAL_KEY=` (или `PORTKEY_CONFIG=`) с простым `AGENTEYE_AGENT_MODEL`. + +**c) Любой другой Anthropic-совместимый шлюз (LiteLLM, самостоятельно размещённый, …)** + +``` +ANTHROPIC_BASE_URL=https://your-gateway +# Разделённые новой строкой "Name: Value" строки заголовков (НЕ JSON): +ANTHROPIC_CUSTOM_HEADERS=x-my-header: value +``` + +**d) Amazon Bedrock / Google Vertex** + +``` +CLAUDE_CODE_USE_BEDROCK=1 # + стандартные учетные данные AWS в окружении +# или +CLAUDE_CODE_USE_VERTEX=1 # + стандартные учетные данные GCP в окружении +``` + +Опционально привязывайте модель по умолчанию с помощью `AGENTEYE_AGENT_MODEL` (по умолчанию `claude-sonnet-4-6`). Чтобы позволить пользователям **выбирать** среди нескольких моделей, установите `AGENTEYE_AGENT_MODELS` на список разрешенных через запятую (например, `@anthropic-prod/claude-opus-4-7,@anthropic-prod/claude-sonnet-4-6`); тогда в заголовке чата появляется выбор модели, и выбор каждого пользователя запоминается. Агент только когда-либо вызывает модель из этого списка разрешенных. + +### 2. Предоставьте ключ ассистента + +Выберите любой случайный секрет и дайте его **agent** как `AGENTEYE_API_KEY` и **server** как `AGENT_API_KEY` (то же значение). При запуске сервер заполняет его как выделенный ключ с именем `dashboard-assistant` с этим фиксированным набором разрешений: `events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run`. Разрешения на запись выполняются только через инструменты с управлением одобрением (см. "Что он может и не может делать" выше). **Нет ручного шага создания ключа и нет затронутого административного ключа**. Набор разрешений фиксирован в сервере, и заполненный ключ **защищен**: он не может быть отключен или переоформлен через API ключей; ротируйте его, изменив значение и перезапустив сервер. **Не** переиспользуйте административный/ключ панели управления. + +```bash +SECRET="$(openssl rand -base64 32)" +# на сервисе agent: +AGENTEYE_API_KEY="$SECRET" +# на сервисе server: +AGENT_API_KEY="$SECRET" +``` + +На Kubernetes это подготовлено для вас: поместите `AGENTEYE_API_KEY` в секрет `agenteye-agent`, и Deployment сервера уже читает то же значение как `AGENT_API_KEY`. + +### 3. Установите общий токен панель↔agent + +Установите одинаковый `AGENTEYE_AGENT_TOKEN` на **обоих** сервисах `dashboard` и `agent`. Панель представляет его при вызове внутреннего сервиса агента; агент отклоняет вызовы без него. + +### 4. Предоставьте пользователям доступ + +Дайте соответствующим операторам панели управления разрешение `agent:use` (см. [enterprise-docs/api-keys.md](/ru/agenteye/api-keys)). Пользователи без него никогда не видят ассистента. + +После установки LLM endpoint и ключа только для чтения перезапустите **server** (для заполнения ключа только для чтения) и сервис **agent**. Док ассистента появляется с правой стороны для любого пользователя `agent:use`, свернутый по умолчанию; щелкните полосу или нажмите `⌘J` / `Ctrl+J` для развертывания. + +--- + +## Справочник переменных окружения + +Установить на сервис **`agent`**: + +| Переменная | Цель | +|---|---| +| `PORTKEY_API_KEY` | Маршрут через Portkey (агент строит соединение шлюза из этого) | +| `PORTKEY_VIRTUAL_KEY` | Виртуальный ключ Portkey для ваших учетных данных Anthropic (опционально, если ключ имеет конфигурацию по умолчанию) | +| `PORTKEY_CONFIG` / `PORTKEY_BASE_URL` | Именованная конфигурация Portkey / URL самостоятельного хостинга шлюза Portkey (опционально) | +| `PORTKEY_PROVIDER` | Слаг провайдера Portkey — третий вариант маршрутизации наряду с `PORTKEY_VIRTUAL_KEY` / `PORTKEY_CONFIG` (используется только когда ни один из них не установлен) | +| `ANTHROPIC_API_KEY` | Прямой доступ Anthropic (альтернатива шлюзу / Bedrock / Vertex) | +| `ANTHROPIC_AUTH_TOKEN` | Токен Bearer для шлюза, который аутентифицируется через `Authorization: Bearer` вместо `x-api-key` (опционально) | +| `ANTHROPIC_BASE_URL` | Endpoint для шлюза без Portkey | +| `ANTHROPIC_CUSTOM_HEADERS` | Дополнительные заголовки для шлюза без Portkey: разделённые новой строкой линии `Name: Value` (не JSON) | +| `CLAUDE_CODE_USE_BEDROCK` / `CLAUDE_CODE_USE_VERTEX` | Маршрут через Bedrock / Vertex | +| `AGENTEYE_AGENT_MODEL` | Id модели по умолчанию (по умолчанию `claude-sonnet-4-6`) | +| `AGENTEYE_AGENT_MODELS` | Список разрешенных через запятую моделей, которые пользователь может выбрать в заголовке чата. Оставьте неустановленным для одной фиксированной модели. Значение по умолчанию выше должно быть одним из этих (иначе оно добавляется). | +| `AGENTEYE_AGENT_MAX_CONCURRENCY` | Максимум одновременных чатов на pod (по умолчанию 4); избыточные запросы получают 429 | +| `AGENTEYE_API_KEY` | Ключ данных ассистента. Установите **то же самое** значение, что и `AGENT_API_KEY` сервера, который заполняет его фиксированным набором разрешений области при запуске (см. шаг 2). | +| `AGENTEYE_AGENT_TOKEN` | Общий секрет с панелью управления | +| `AGENTEYE_SERVER_URL` | URL сервера AgentEye (по умолчанию `http://server:8080`) | +| `AGENTEYE_AGENT_ALLOW_NO_ORG` | **Мультитенантность.** По умолчанию отключена (fail-closed): ассистент отклоняет запрос `/chat`, который не содержит контекста организации, с `400`, потому что каждый инструмент, который он запускает, ограничивается одной организацией. Панель управления всегда отправляет этот контекст один раз, когда она осведомлена об организации, поэтому вы обычно оставляете это неустановленным. Установите на `1` **только** во время переходного развертывания, когда еще не осведомленная об организации панель управления разговаривает с осведомленным об организации агентом, поэтому ассистент переходит на организацию `default` вместо отказа. Очистите это после приземления обновления панели управления. | +| `AGENTEYE_AGENT_MAX_STEPS` | Максимум шагов инструмента на ответ (по умолчанию 8) | +| `AGENTEYE_AGENT_TIMEOUT_MS` | Общее время ожидания запроса `/chat` (все обороты модели + шаги инструмента), в миллисекундах (по умолчанию 90000); инструмент SQL имеет собственную крышку 10s | +| `AGENTEYE_AGENT_SELF_TELEMETRY` | `1` для записи собственных прогонов ассистента в AgentEye | +| `AGENTEYE_TELEMETRY_API_KEY` | Отдельный ключ `events:add`-only для самоинструментации | +| `AGENTEYE_AGENT_ENV` | Тег окружения, применяемый к собственной телеметрии ассистента (по умолчанию `prod`) | + +Установить на сервис **`dashboard`**: + +| Переменная | Цель | +|---|---| +| `AGENTEYE_AGENT_URL` | Где панель управления достигает сервис агента. Поставляемые манифесты Kubernetes и файл Compose установили это на `http://agent:9100`. Оставьте неустановленным, чтобы полностью скрыть ассистента. | +| `AGENTEYE_AGENT_TOKEN` | Должен соответствовать токену агента | + +--- + +## Телеметрия и просмотр того, о чем спрашивают пользователи + +Содержимое prompt **остается в ваших собственных системах** по умолчанию. Три слоя: + +1. **Хранилище разговоров**: каждый prompt и ответ сохраняются в вашей базе данных AgentEye (для каждого пользователя, приватно) и перезагружаются из переключателя истории ассистента. Это долговечный записи того, о чем спрашивают пользователи. +2. **Аналитика продукта**: панель управления записывает **только метаданные** (как часто используется ассистент, количество инструментов, задержка) в вашу аналитику. Текст **prompt** никогда не включается на этот путь. +3. **Самоинструментация (опционально)**: установите `AGENTEYE_AGENT_SELF_TELEMETRY=1` (плюс `events:add`-only `AGENTEYE_TELEMETRY_API_KEY`) и ассистент записывает свои прогоны в AgentEye как агент `dashboard-assistant`. Затем вы можете просмотреть prompts пользователя и рассуждения ассистента в этих же представлениях сессий/событий, которые вы используете для всего остального. Примечание: эти события видны всем с `events:read`; если это слишком широко, оставьте это отключенным. + +--- + +## Отключение + +Любое из этих отключит ассистента (полоса дока исчезает): + +- Отмените установку `AGENTEYE_AGENT_URL` на панели управления, **или** +- Оставьте LLM endpoint несконфигурированным на агенте (без `ANTHROPIC_API_KEY` / шлюза / Bedrock / Vertex), **или** +- Не развертывайте сервис `agent` вообще. + +--- + +## Резюме безопасности + +- **Нет молчаливых записей**: инструменты записи ассистента (`create_saved_query`, `update_saved_query`, `create_dashboard`, `update_dashboard`, `add_query_to_dashboard`) не могут выполняться без явного нажатия оператором кнопки Одобрить в чате; шлюз предварительного вызова SDK блокирует инструмент до получения одобрения агентом через обратный канал. Нет настройки, которая отключит этот шлюз. +- **Фиксированная, узкая область данных**: ассистент аутентифицируется на сервере с выделенным ключом, набор разрешений которого фиксирован в сервере (`events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run`). Единственные записи, которые он может создавать, — это сохраненные запросы и панели; сервер отклоняет что угодно за пределами этой области независимо от того, что пытается сделать модель. +- **Нет поверхности удаления**: ключ не содержит разрешение на удаление и нет инструмента удаления. Операторы удаляют через пользовательский интерфейс панели управления, никогда через ассистента. +- **Только внутренний**: агент не имеет публичного маршрута; только панель управления может вызвать его, и только с общим токеном. (На Kubernetes NetworkPolicy ограничивает агента только достижением сервера AgentEye и endpoint LLM.) +- **Каждого пользователя область**: только пользователи `agent:use` получают ассистента, и ему даны только инструменты, соответствующие разрешениям чтения каждого пользователя. +- **Нет сырого HTML / нет утечки ссылок**: ответы отображаются как санитизированный markdown; внешние ссылки обезопасены. + +См. [enterprise-docs/troubleshooting.md](/ru/agenteye/troubleshooting) для общих проблем. \ No newline at end of file diff --git a/docs/ru/agenteye/audits.mdx b/docs/ru/agenteye/audits.mdx new file mode 100644 index 00000000..25de5223 --- /dev/null +++ b/docs/ru/agenteye/audits.mdx @@ -0,0 +1,107 @@ +--- +title: "Audits — обнаружение улучшений агентов" +description: "AgentEye Audits — документация обнаружения улучшений агентов." +--- + + +Audits — это повторяющиеся задания, которые анализируют логи вашего агента **между сеансами** в поиске областей для улучшения. Если alert отслеживает одну известную вам метрику в режиме реального времени, audit *исследует*: по расписанию, которое вы установили, он выполняет детерминированный проход политики по временному окну, а затем запускает **AI-агента надежности** на ваших сеансах — агент запрашивает данные самостоятельно, читает подозрительные транскрипты и (при необходимости) запускает небольшие аналитические скрипты, а затем составляет **рекомендации по улучшениям** с доказательствами, подтверждающими каждую из них. + +Используйте audits для ответа на вопрос «что нужно исправить или улучшить в моих агентах?» — и alerts для получения уведомления в момент пересечения определенного порога. Каждое улучшение содержит ссылки на точные сеансы и запросы, на основе которых оно выявлено, и один клик создает предзаполненный alert для перехвата повторений. + +Поверхность дашборда — **`//audits`** (боковая панель → *analyze* → *audits*), защищена разрешениями `audits:read` / `audits:write`. + +--- + +## Как работает запуск + +Каждый запуск имеет два уровня — детерминированный базовый уровень и исследование на основе агента. + +### 1. Проход политики (детерминированный) + +Перед запуском любой модели audit выполняет небольшой набор **проверок политики SQL** по временному окну: ограниченные агрегированные запросы, которые помечают известные плохие паттерны и сообщают, *сколько* событий / *какие* сеансы совпали — никогда не сам текст совпадений. Каталог включает: + +- **Утечка секретов / учетных данных** в полезных нагрузках событий — AWS ключи доступа, API ключи типа `sk-…`, приватные ключи PEM, JWT / bearer токены и назначения учетных данных типа `KEY=…`. +- **Маркеры prompt-injection** — "игнорировать предыдущие инструкции", "раскрыть системное приглашение" и подобные. +- **PII** — номера похожие на SSN (эвристический анализ). +- **Отказы в доступе к инструментам** и **зацикленные вызовы инструментов**. + +Обнаружения политики сохраняются как findings (вид `policy`), которые **всегда отображаются** (их никогда не удаляет лимит per-run), и передаются AI-агенту как стартовые подсказки. Поскольку этому уровню не нужна модель, audit все равно выдает свои наиболее важные сигналы безопасности, даже если AI-агент недоступен. + +### 2. Исследование на основе агента (AI) + +Затем audit запускает **автономный агент надежности** (тот же сервис Claude Agent SDK, который работает в помощнике дашборда, с подсказкой, специфичной для audit). Учитывая **область** audit (выбранные агенты × окружения) и **временное окно**, агент: + +- выполняет запросы SQL только для чтения к вашим аналитическим таблицам, +- читает несколько репрезентативных транскриптов сеансов, +- при необходимости пишет и запускает короткие **Python скрипты в защищенной изолированной sandbox** (без сети, без доступа к файловой системе, секреты очищены) для анализа, который SQL не может выразить — кластеризация ошибок, вычисление распределений, просмотр полезных нагрузок, которые он уже загрузил, +- и записывает каждое хорошо обоснованное **улучшение**, которое он находит. + +Он работает через несколько следственных линий — кластеризация ошибок, отклонение от базовой линии, неудача цели в транскриптах, неправильное использование инструментов, компромиссы качества/стоимости и пробелы в охвате — согласно **чувствительности** audit (низкая / средняя / высокая). Каждое улучшение **должно содержать доказательства**: идентификаторы сеансов, которые агент действительно проверил, и/или SQL, который он запустил. Сервер проверяет, что указанные сеансы существуют, и **отбрасывает любое улучшение без подтверждающих доказательств**, поэтому агент исследует, но никогда не придумывает. + +Каждое улучшение содержит: + +- **рекомендацию** (конкретное изменение для внесения — корректировку приглашения, исправление схемы инструмента, политику повтора, guardrail, большее покрытие eval), +- оценку **ожидаемого влияния** и **усилия** (низкое / среднее / высокое), +- **масштаб** — `big` (оператора нужно уведомить), `medium` (должно быть в отчете о запуске) или `small` (контекст дашборда), +- стабильный **fingerprint** (из категории проблемы + область, *не* из сеансов этого запуска), поэтому одна и та же проблема отслеживается от запуска к запуску даже при изменении доказательств, +- и, где простой детерминированный watcher может перехватить повторение, **предложенный alert**, который вы можете создать в один клик. + +> **AI-уровень опционален, но рекомендуется.** Если никакой AI-агент не настроен для конвейера audit, запуски по-прежнему выполняются, сохраняют findings политики и честно сообщают "анализ недоступен" для уровня агента вместо молчаливого прохождения. + +### Режимы отказа + +Улучшения классифицируются в долговечный **каталог режимов отказа** вашей организации (или предлагают новый режим). Режимы дают паттернам стабильную идентичность между запусками и отслеживание долгосрочного повторения. + +## Жизненный цикл триажа + +На странице findings (`/audits//findings/`): + +| Действие | Эффект | +|---|---| +| **acknowledge** | Оставляет finding видимым, но вдвое снижает его приоритет. | +| **resolve** | Отмечает как исправленное. Если паттерн действительно вернется позже, он откроется как **new** — поэтому регрессия будет заметна, а не молча сложена в историю. | +| **mute** / **dismiss** | Длительное подавление: отпечаток (fingerprint) паттерна запоминается и никогда больше не отображается, даже между запусками. Используйте mute для "известного, принятого"; dismiss для "не полезно". | +| **reopen** | Очищает подавление / разрешение и переранжирует паттерн. | +| **assign** | Маршрутизирует finding оператору (члену организации) для владения. Приоритет и состояние подавления не изменяются. | + +Шум с низким сигналом управляется для каждого audit с помощью лимита per-run на agentic improvements (`top_k`). Findings политики обходят лимит (они важны для безопасности и всегда показываются). Все обрезанное лимитом подсчитывается в статистике запуска — ничего не отбрасывается молча. + +## Расписание + +- **Cadence** (`schedule_interval_secs`): ежечасно или еженедельно; **ежедневно по умолчанию**. Audits намеренно грубше, чем alerts — исследование на основе агента сканирует целые окна и работает в течение минут. +- **Window**: либо фиксированный скользящий lookback (например, "каждый запуск сканирует последние 7 дней"), либо **since-last-run** (по умолчанию) — каждый запуск продолжает с того, где закончился предыдущий успешный, с небольшим перекрытием, чтобы события на границе никогда не пропускались. +- Следующий запуск планируется на полный интервал после завершения предыдущего, поэтому медленный запуск никогда не создает второй одновременный запуск того же audit. +- **Run now** на странице audit делает его срочным. + +## Выбор модели + +При создании audit вы можете выбрать, какую модель использует исследование, из **списка моделей, которые ваш оператор настроил** для сервиса агента. С одной настроенной моделью средство выбора показывает ее как подпись; с несколькими — вы выбираете. Если оставить его без установки, будет использована настроенная по умолчанию. + +## Уведомления + +Когда запуск выявляет **новые** findings, audit уведомляет настроенные каналы вашей организации — те же ворота `alerts.enabled_channels` и настройки, которые использует конвейер alerts: + +- **Slack** — краткое описание значительных (`big`) новых элементов с глубокой ссылкой. +- **Email** — оформленный **отчет audit**, перечисляющий новые улучшения (высший приоритет, рекомендации по элементам, глубокая ссылка), отправляется, когда audit имеет подключенный канал **email** и есть по крайней мере один новый finding. + +Повторяющиеся, но известные findings не отправляют повторные уведомления. + +## Справочник по конфигурации + +Определения Audit управляются в дашборде (`/audits/new`) или через API. Настройки per-audit включают cadence расписания и window, область (`{"environments": [...], "agent_ids": [...]}`), чувствительность (`low` / `medium` / `high`), каналы уведомлений, лимит per-run для findings (`top_k`) и модель (через `llm_budget.model`). Параметры сервера уровня оператора (timeouts, sandbox, URL сервиса агента) описаны в [deployment.md](/ru/agenteye/deployment). + +## API + +Все endpoints имеют область org и следуют стандартной аутентификации bearer-key (см. [api-keys.md](/ru/agenteye/api-keys)). + +| Endpoint | Разрешение | Назначение | +|---|---|---| +| `GET /audits` · `POST /audits` | `audits:read` / `audits:write` | Список / создание определений audit. | +| `GET` / `PUT` / `DELETE /audits/:id` | read / write / write | Проверка, редактирование, удаление audit. | +| `POST /audits/:id/run` | `audits:write` | Сделать audit срочным. | +| `GET /audits/:id/runs` | `audits:read` | История запусков (window, статус, статистика, количество findings). | +| `GET /audits/findings` | `audits:read` | Org-wide findings, фильтруемые по `audit_id`, `status`; отсортированы по приоритету. | +| `GET /audits/findings/:fid` | `audits:read` | Полные детали findings (рекомендация, доказательства, приоритет). | +| `POST /audits/findings/:fid/status` | `audits:write` | Триаж: `{"action": "ack" \| "mute" \| "dismiss" \| "resolve" \| "reopen" \| "assign"}`. | + +Для "audit запустился, но ничего не найдено", "code sandbox отключена" и "email от audit не доставлена", см. [troubleshooting.md](/ru/agenteye/troubleshooting#audits). \ No newline at end of file diff --git a/docs/ru/agenteye/cli-recipes.mdx b/docs/ru/agenteye/cli-recipes.mdx new file mode 100644 index 00000000..01cef519 --- /dev/null +++ b/docs/ru/agenteye/cli-recipes.mdx @@ -0,0 +1,170 @@ +--- +title: "CLI рецепты для агентов" +description: "Документация CLI рецептов AgentEye для агентов." +--- + + +Извлекайте данные о сессиях, событиях и оценках (и запускайте переоценки) прямо из скрипта или кодирующего агента с чистым JSON на stdout, который можно передавать в `jq`. Эти рецепты превращают данные наблюдаемости AgentEye в нечто, что может запрашивать и автоматизировать пользователь терминала или кодирующий AI-агент (Claude Code, Cursor), без необходимости кликать по панели управления. + +Приведённые ниже паттерны готовы к копированию для AgentEye CLI (`agenteye`). Инструкции по установке, аутентификации и полный список опций см. в [CLI](/ru/agenteye/cli); запустите `agenteye -h` или `agenteye -h` для встроенной справки. + +## Золотые правила + +1. **Глобальные опции идут *перед* командой.** `agenteye --json sessions` — правильно; `agenteye sessions --json` — нет. Глобальные опции: `--json`, `--base-url`, `--org`, `--token`, `--insecure`/`--secure`, `--timeout`, `--quiet`, `--no-color`. +2. **Передавайте `--json` всякий раз, когда разбираете вывод.** Данные выводятся на **stdout** в JSON; статусные сообщения и ошибки выводятся на **stderr**, так что stdout остаётся чистым для передачи в `jq`. +3. **Ветвитесь по коду выхода, не по тексту stderr**: `0` ок · `2` неверные аргументы · `3` не удалось достичь панель управления · `4` не аутентифицирован или истекла сессия · `5` недостаточно прав. +4. **Исследуйте с помощью `-h`.** Каждая команда документирует свои фильтры, форматы значений и форму JSON. + +## Одноразовая настройка + +```bash +export AGENTEYE_DASHBOARD_URL=https://agenteye.example.com # чтобы не повторять --base-url +agenteye login --email you@example.com # вставьте отправленный по почте код; действителен ~24ч +``` + +## Подтвердите аутентификацию перед работой + +`whoami` никогда не ошибается при отсутствующей или истекшей сессии; вместо этого он сообщает `logged_in:false`, поэтому агент может безопасно проверить состояние аутентификации. (Он всё ещё может выйти с ненулевым кодом, если не установлен базовый URL или панель управления недоступна.) + +```bash +if [ "$(agenteye --json whoami | jq -r .logged_in)" != "true" ]; then + echo "Not authenticated. Run: agenteye login" >&2; exit 1 +fi +``` + +## Найдите неудачные или низкоскоринговые сессии + +```bash +# сессии за последние 24ч, оценка которых ошибилась +agenteye --json sessions --since 24h --status error | jq -r '.sessions[].session_id' + +# оценки с баллом <= 0.5 по полезности для одного агента +agenteye --json evals --agent-id checkout-bot --score helpfulness:..0.5 \ + | jq '.evaluations[] | {session_id, scores}' +``` + +Фильтрация по баллам находится на **`evals`**, а не на `sessions`. `--score KEY:MIN..MAX` повторяется и объединяется с AND; любая граница опциональна (`..0.5` означает ≤ 0.5, `0.9..` означает ≥ 0.9). Вы можете передать до 20 фильтров по баллам в одном запросе; больше возвращает HTTP 400. `sessions` разделяет фильтры `--env`, `--status`, `--agent-id`, `--session-id` и временного диапазона с `evals`, но не имеет `--score`. + +## Прочитайте одну сессию от начала до конца + +Нет единой команды `session show` — объедините цепь событий с оценкой сессии: + +```bash +# последняя оценка сессии (статус + баллы) +agenteye --json evals --session-id run-001 | jq '.evaluations[0] | {status, scores}' + +# каждое событие в прогоне (повысьте --limit для полного обзора) +agenteye --json events --session-id run-001 --all --limit 1000 | jq '.events[] | {ts, event_type}' + +# только вызовы инструментов в сессии +agenteye --json events --session-id run-001 --event-type tool_use,tool_result --all \ + | jq '.events[].payload' +``` + +## Получите всё (постраничность) + +Результаты отсортированы по убыванию и использует курсорную постраничность. + +```bash +# одноразово: получите до 500 строк по 200 строк в страницу +agenteye --json events --session-id run-001 --limit 500 --all > events.json + +# ручная постраничность: передайте next_cursor обратно +page=$(agenteye --json events --limit 100) +cursor=$(echo "$page" | jq -r '.next_cursor // empty') +[ -n "$cursor" ] && agenteye --json events --limit 100 --cursor "$cursor" +``` + +## Сокращайте вывод с помощью --fields + +Ограничьте ключи (в таблице и в `--json`) для снижения объёма информации, которую должен прочитать агент. + +```bash +agenteye --json sessions --since 7d --fields session_id,status,scores | jq -c '.sessions[]' +agenteye --json events --session-id run-001 --fields ts,event_type --all +``` + +Неизвестные имена полей отклоняются (выход `2`) с указанием допустимого списка — дешёвый способ обнаружить имена полей. + +## Обнаружьте допустимые значения фильтров + +```bash +agenteye --json list envs | jq -r '.values[]' # значения для --env +agenteye --json list tools | jq -r '.values[]' # имена инструментов; также agents, models, event_types, … +agenteye --json list score_filters | jq -r '.values[]' # допустимый KEY для --score KEY:MIN..MAX +``` + +## Выберите вашу организацию (мультитенантность) + +Если вы принадлежите более чем одной организации, выберите активный тенант при входе (он сохраняется): + +```bash +agenteye login --org acme --email you@corp.com # установите тенанта на том же шаге входа +agenteye --json orgs list | jq -r '.orgs[].org_slug' +agenteye --org globex --json sessions --since 24h # переопределите для одной команды +``` + +Вход в мультиорганизационную систему без `--org` завершается с ненулевым кодом и выводит организации на выбор. + +## Провизионируйте ключ API для SDK/сборщика + +```bash +# секрет выводится ОДИН РАЗ — с --json это поле .key +key=$(agenteye --json keys create ci-bot --add events:read.add | jq -r '.key') +agenteye keys regenerate ci-bot --yes # ротация; agenteye keys disable ci-bot --yes для отзыва +``` + +## Запустите сохранённый или специальный запрос + +```bash +agenteye --json query run --sql "select count(*) from analytics.events" | jq '.rows' +agenteye --json query run errs --arg prod | jq '.rows' # сохранённый запрос + позиционный $1 +``` + +## Классифицируйте инцидент неинтерактивно + +```bash +id=$(agenteye --json incidents list --state firing | jq -r '.incidents[0].id') +agenteye incidents ack "$id" +agenteye incidents assign "$id" you@corp.com +agenteye incidents resolve "$id" --yes +``` + +> Мутации автоматически пропускают подтверждение при `--json` или когда stdin не является TTY, так что агенты никогда не зависают; передайте `--yes`/`-y` для явного пропуска в других местах. + +## Обработка кода выхода в скрипте + +```bash +out=$(agenteye --json sessions --since 1h) || code=$? +case "${code:-0}" in + 0) echo "$out" | jq '.sessions | length' ;; + 4) echo "Session expired - run 'agenteye login'." >&2 ;; + 5) echo "Missing permission (ask an admin for evaluations:read)." >&2 ;; + 3) echo "Dashboard unreachable - check the URL." >&2 ;; + *) echo "Unexpected error (exit ${code})." >&2 ;; +esac +``` + +## Формы JSON вывода + +| Команда | stdout JSON (с `--json`) | +|---|---| +| `whoami` | `{"logged_in": true, "id", "email", "is_instance_admin", "active_org", "permissions": [...], "memberships": [...]}` или `{"logged_in": false}` | +| `orgs list` | `{"active_org", "orgs": [{"org_slug","org_name","permission_set","permissions"}]}` | +| `events` | `{"events": [...], "next_cursor": }` | +| `evals` | `{"evaluations": [...], "next_cursor": }` | +| `sessions` | `{"sessions": [...], "next_cursor": }` | +| `errors` | `{"errors": [...], "next_cursor": }` | +| `list ` | `{"kind", "values": [...]}` | +| `keys list` / `keys create` | `{"keys": [...]}` / `{id, name, permissions, created_at, key}` (`key` показывается один раз) | +| `query run` | `{columns: [{name,type}], rows: [[...]], truncated, elapsed_ms}` | +| `users list` / `settings list` | `{"users": [...]}` / `{"settings": [...]}` | +| `alerts list` / `incidents list` | `{"alerts": [...]}` / `{"incidents": [...]}` | +| create/update/delete (любой) | объект ресурса или `{"deleted": true, "id"}` для удалений | +| сбой (любой, с `--json`) | `{"error": "...", "exit_code": , "status"?: , "hint"?: "..."}` на stdout | + +- Каждый элемент **события** (`events`): `id, session_id, agent_id, event_type, ts, payload, environment`. +- Каждый элемент **оценки** (`evals`): `id, session_id, agent_id, environment, status, scores, reasoning, summary, error, attempt_count, duration_ms, completed_at, created_at`. +- Каждый элемент **сессии** (`sessions`): `session_id, agent_id, environment, status, scores, event_count, started_at, last_event_at, first_event_id, last_event_id, latest_evaluation`. + +`--fields` каждой команды принимает ровно имена полей своего собственного элемента — набор отличается между `sessions` и `evals`, поэтому имя, допустимое для одной, может быть отклонено другой. \ No newline at end of file diff --git a/docs/ru/agenteye/cli-skill.mdx b/docs/ru/agenteye/cli-skill.mdx new file mode 100644 index 00000000..94ec19db --- /dev/null +++ b/docs/ru/agenteye/cli-skill.mdx @@ -0,0 +1,95 @@ +--- +title: "AgentEye CLI Agent Skill" +description: "Документация AgentEye CLI Agent Skill." +--- + + +**AgentEye CLI skill** (`agenteye-cli`) — это устанавливаемый *Agent Skill*, который обучает кодирующего агента — Claude Code, Codex и совместимые инструменты — управлять вашим развёртыванием AgentEye через CLI [`agenteye`](/ru/agenteye/cli) на основе запросов на естественном языке: *«что-нибудь сломалось сегодня?»*, *«дай CI ключ, который может только отправлять события»*, *«подтверди срабатывающий инцидент и назначь его мне»*. + +Это **не** сервис и **не** отдельный бинарный файл. Это небольшой пакет инструкций, который работает поверх уже установленного CLI: агент запускает `agenteye --json …`, парсит чистый JSON и отвечает вам прозой. Всё, что он может сделать, вы можете сделать сами, введя те же команды. + +--- + +## Как это связано с другими интерфейсами AgentEye + +AgentEye предоставляет четыре способа достичь одних и тех же данных и управления. Они дополняют друг друга: + +| Интерфейс | Что это | Где работает | Используйте, когда | +|---|---|---|---| +| **[CLI](/ru/agenteye/cli)** | Справочник команд и флагов для `agenteye` | Ваш терминал | Вы хотите запустить или создать скрипт для конкретной команды | +| **[CLI recipes](/ru/agenteye/cli-recipes)** | Готовые к копированию паттерны `jq`/pipeline | Ваш терминал / скрипты | Вы интегрируете CLI в автоматизацию | +| **CLI skill** (этот документ) | Интерфейс на естественном языке к CLI | Ваш кодирующий агент на вашей рабочей станции | Вы хотите просто спросить и позволить агенту выбрать команду | +| **[Встроенный AI ассистент](/ru/agenteye/assistant)** | Чат, встроенный в панель управления | Внутренний контейнер `agent` в вашем кластере | Вы хотите вопросы и ответы в панели управления над вашими данными | + +### против встроенного AI ассистента — важное различие + +Это два разных инструмента с очень разными областями воздействия: + +- **Встроенный AI ассистент** ([assistant.md](/ru/agenteye/assistant)) — это чат в панели управления, поддерживаемый внутренним контейнером `agent`. Это **только для чтения плюс авторизация с подтверждением**: он может создавать черновики сохранённых запросов и панелей, но любое изменение требует вашего явного подтверждения, и он никогда не удаляет. Защищён разрешением `agent:use` и видит только данные той организации, которую вы просматриваете. +- **CLI skill** работает на *вашей* рабочей станции внутри *вашего* кодирующего агента и управляет CLI `agenteye` **как вы**. Он может выполнять **полную поверхность CLI, включая изменения** — создавать/ротировать/отключать API ключи, менять настройки организации, разрешать инциденты, удалять сохранённые запросы — ограниченный только разрешениями вашего логина CLI. Относитесь к нему так же внимательно, как если бы вы вводили эти команды вручную. + +--- + +## Необходимые условия + +1. **`agenteye` CLI установлен** и находится в `PATH` (см. [cli.md](/ru/agenteye/cli) — `pipx install agenteye`). +2. Ваш **URL панели управления установлен** (`AGENTEYE_DASHBOARD_URL`, или агент передаёт `--base-url`). +3. **Активная сессия входа**: сначала запустите `agenteye login` самостоятельно. Skill **не может** завершить отправленный по почте одноразовый код входа за вас — он скажет вам запустить `agenteye login`, если сессия отсутствует или истекла (код выхода CLI `4`). + +--- + +## Установка skill + +Agent Skills — это папки, содержащие `SKILL.md` (плюс опциональные справочники). Вы устанавливаете skill `agenteye-cli`, поместив его папку туда, где ваш агент ищет skills: + +- **Claude Code** — скопируйте папку `agenteye-cli/` в `~/.claude/skills/` (доступно во всех проектах) или в `<ваш-репо>/.claude/skills/` (ограничено этим репо). Claude Code автоматически обнаруживает его; проверьте со списком `/skills` или просто задайте вопрос, который соответствует его описанию. +- **Codex (OpenAI)** — Codex читает тот же `SKILL.md`. Включённый `agents/openai.yaml` устанавливает `allow_implicit_invocation: true`, поэтому Codex автоматически выбирает skill при совпадении задачи; иначе вызовите его явно как `$agenteye-cli`. + +Skill поддерживается вместе с CLI `agenteye` и распространяется как часть вашего пакета AgentEye — если у вас нет папки `agenteye-cli`, обратитесь к вашему контакту AgentEye. Ничего в этом не ограничивается: ему не нужен образ Docker и не нужны учётные данные, потому что он только управляет **публичным** CLI `agenteye` против вашей собственной панели управления. + +--- + +## Безопасность — изменения НЕ требуют подтверждения, когда агент запускает CLI + +**Прочитайте это перед тем, как позволить агенту вносить изменения.** + +CLI `agenteye` обычно спрашивает *«вы уверены?»* перед деструктивным действием. Это **автоматически пропускает подтверждение, когда он не подключен к терминалу — это именно то, как работает кодирующий агент — и `--json` тоже пропускает это.** Поэтому запрос безопасности **не** срабатывает для агента. + +Skill написан для компенсации: ему поручено указать точную команду, которую он запустит, и получить ваше явное **OK перед любым изменением состояния**. Сохраняйте эту дисциплину — когда вы управляете AgentEye через агента, *вы* являетесь шагом подтверждения. Команды, изменяющие состояние, на которые следует обратить внимание: + +- `keys create` / `update` / `disable` / `regenerate` +- `users create` / `update` / `disable` / `enable` +- `settings set` +- `alerts create` / `update` / `delete` / `test` +- записывающие подкоманды `incidents`: `ack` / `assign` / `resolve` / `open` / `comment-add` / `comment-delete` / `subscribe` / `unsubscribe` +- `query create` / `update` / `delete` +- `agent rename` / `delete` +- `orgs switch` + +Всё под **Observe** (`events`, `sessions`, `evals`, `errors`, `list`, `whoami`, `orgs list/current/perms`) только для чтения и ничего не изменяет. + +Поскольку агент действует **как вы**, он может делать только то, что разрешено вашему логину — разрешения разрешаются **по организации** (см. [api-keys.md](/ru/agenteye/api-keys)). Команда, для которой у вас нет разрешения, возвращает код выхода `5` с указанным точным разрешением, поэтому агент может точно сказать вам, что попросить у администратора, вместо того чтобы дать неудачу без объяснений. + +--- + +## Что вы можете у него спросить + +Skill отображает намерения на естественном языке на правую команду `agenteye`, сначала обнаруживая допустимые значения (`list `, `whoami`), поэтому он не угадывает: + +- *«Что-нибудь сломалось / срабатывает в последние 24 часа?»* → `errors --since 24h --aggregate`, затем разбор. +- *«Почему сессия `run-001` не удалась?»* → `events --session-id run-001 --all` + `evals --session-id run-001`. +- *«Как качество развивается на этой неделе?»* → `evals --aggregate --since 7d`, затем углубитесь в низкооценённые запуски. +- *«Дай CI ключ, который может только отправлять события.»* → `keys create ci --add events:add` (он указывает команду, затем создаёт её и захватывает одноразовый секрет). +- *«Кто имеет доступ? Сделай Dana только для чтения.»* → `users list` → `users update dana@… --permission-set read-only` (после подтверждения с вами). +- *«Подтверди срабатывающий инцидент и назначь его мне.»* → `incidents list --state firing` → `incidents ack ` / `incidents assign you@…`. + +Для точных команд, флагов и JSON форм за этим см. [cli.md](/ru/agenteye/cli) и [cli-recipes.md](/ru/agenteye/cli-recipes). + +--- + +## Смотрите также + +- **[CLI](/ru/agenteye/cli)** — полный справочник команд и флагов для `agenteye`. +- **[CLI recipes для агентов](/ru/agenteye/cli-recipes)** — готовые к копированию паттерны `jq` и обработка кодов выхода. +- **[AI ассистент](/ru/agenteye/assistant)** — встроенный в панель ассистент (не путайте с этим terminal skill). +- **[API ключи](/ru/agenteye/api-keys)** — модель разрешений по организации, которая ограничивает то, что может делать skill. \ No newline at end of file diff --git a/docs/ru/agenteye/cli.mdx b/docs/ru/agenteye/cli.mdx new file mode 100644 index 00000000..e1ecf4fd --- /dev/null +++ b/docs/ru/agenteye/cli.mdx @@ -0,0 +1,292 @@ +--- +title: "CLI" +description: "Документация AgentEye CLI." +--- + + +AgentEye CLI (`agenteye`) — это терминальный клиент для вашего развёртывания AgentEye. Он запрашивает ваши данные (сеансы, журналы событий, оценки) и управляет организацией (ключи API, пользователи, параметры, оповещения, инциденты, сохранённые запросы) — всё, что делает панель управления, из скрипта или кодирующего агента. Каждая команда поддерживает флаг `--json`, поэтому она одинаково хорошо работает как для человека в терминале, так и для кодирующего агента (Claude Code, Cursor), который её вызывает и обрабатывает результат. + +> Это **CLI `agenteye`**, отличный от **коллектора** (`agenteye-collector`). CLI общается с вашей **панелью управления**; коллектор отправляет события на сервер. См. [Установка коллектора](/ru/agenteye/collector-installation) для коллектора. + +--- + +## Установка + +CLI опубликован в публичном PyPI как **`agenteye`**. Поскольку Python SDK AgentEye также использует имя дистрибутива `agenteye`, установите CLI в **изолированной** среде (`pipx` или `uv tool`), чтобы эти два инструмента никогда не конфликтовали в одном virtualenv: + +```bash +pipx install agenteye +# или +uv tool install agenteye +``` + +Обычная установка через `pip install agenteye` также работает, если вы не устанавливаете Python SDK в ту же среду. CLI требует Python 3.10+ и не нуждается в токене GitHub; это публичный пакет. + +Установленная команда — **`agenteye`**: + +```bash +agenteye --version +agenteye --help +``` + +--- + +## Аутентификация + +CLI аутентифицируется на **панели управления** с помощью отправленного по почте одноразового кода: + +```bash +agenteye login --email you@example.com +# На вашу почту отправится 6-значный код; вставьте его в приглашение. +``` + +Токен сеанса сохраняется в `~/.agenteye/cli.json` (доступен только вам, права `0600`) и по умолчанию действителен 24 часа. По истечении срока действия снова запустите `agenteye login`. + +```bash +agenteye whoami # показать текущего пользователя, активную организацию и права доступа +agenteye logout # отозвать сеанс и удалить сохранённый токен +``` + +`whoami` никогда не вызывает ошибку при отсутствующем или истёкшем сеансе — вместо этого сообщает `logged_in: false`, поэтому скрипт или агент может безопасно проверить состояние аутентификации (но может завершиться с ненулевым кодом, если базовый URL не установлен или панель управления недоступна). + +**Требования:** ваша электронная почта должна быть разрешена для входа на панель управления (обратитесь к администратору AgentEye), и панель управления должна быть доступна по своему базовому URL (см. [Конфигурация](#configuration)). Если вы запросили код и он не пришёл, ваша почта, вероятно, ещё не включена для доступа к панели управления. + +--- + +## Выбор организации (мультитенантность) + +Если ваша учётная запись принадлежит нескольким организациям, выберите активную **при входе** — она будет сохранена и использоваться для всех последующих команд: + +```bash +agenteye login --org acme # аутентифицировать и установить активного тенанта в один шаг +agenteye orgs list # организации, к которым вы можете получить доступ (активная отмечена) +agenteye orgs switch globex # изменить сохранённое значение по умолчанию +agenteye --org globex sessions # переопределить для одной команды +``` + +Если вы принадлежите ровно одной организации, она выбирается автоматически и вы можете полностью игнорировать `--org`. Если вы принадлежите нескольким и не выбираете одну, CLI их список и просит переиспользовать `--org `. Активная организация отправляется на панель управления при каждом запросе, и ваши права решаются **для каждой организации** — `agenteye whoami` показывает активную организацию, ваши права в ней и все ваши членства. + +--- + +## Конфигурация + +| Параметр | Флаг | Переменная окружения | По умолчанию | +|---|---|---|---| +| Базовый URL панели управления | `--base-url` | `AGENTEYE_DASHBOARD_URL` | **обязателен** (нет значения по умолчанию) | +| Активная организация/тенант | `--org` | `AGENTEYE_ORG` | выбирается при входе; сохраняется в `~/.agenteye/cli.json` | +| Токен сеанса | `--token` | `AGENTEYE_CLI_TOKEN` | из `~/.agenteye/cli.json` | +| Вывод JSON | `--json` | `AGENTEYE_CLI_JSON` | выключен | +| Пропустить проверку TLS | `--insecure` / `--secure` | `AGENTEYE_INSECURE` | выключен (сохраняется при входе) | +| Тайм-аут запроса (секунды) | `--timeout` | — | 30 | +| Отключить телеметрию использования | _(нет)_ | `AGENTEYE_ANALYTICS_DISABLED` (или `DO_NOT_TRACK`) | выключен (телеметрия включена) | + +Порядок разрешения: **флаг → переменная окружения → файл конфигурации**. По умолчанию нет; вы должны указать CLI на вашу панель управления, либо для каждой команды (`--base-url https://agenteye.example.com`), либо один раз через окружение (она также сохраняется после первого `login`): + +```bash +export AGENTEYE_DASHBOARD_URL=https://agenteye.example.com +``` + +Каталог конфигурации учитывает `AGENTEYE_HOME` (то же соглашение, используемое SDK и коллектором); если задано, `cli.json` находится в `$AGENTEYE_HOME/cli.json`. + +### Самоподписанные или внутренние сертификаты TLS + +Если ваша панель управления обслуживается по HTTPS с самоподписанным или внутренним сертификатом (например, имя хоста сырого load-balancer'а), проверка TLS его отклонит с ошибкой `CERTIFICATE_VERIFY_FAILED`. Передайте `--insecure` для пропуска проверки сертификата: + +```bash +agenteye --base-url https://agenteye.internal --insecure login +``` + +`--insecure` **сохраняется в `cli.json` при входе**, поэтому более поздние команды автоматически пропускают проверку; вам не нужно повторять флаг. Передайте `--secure` для единоразового проверяемого вызова или для повторного включения проверки при следующем входе. CLI выводит предупреждение в stderr перед любой командой, которая обращается к панели управления с отключённой проверкой. Пропуск проверки устраняет защиту от атак «человек посередине»; убедитесь, что вы доверяете сетевому пути к вашей панели управления (VPN, приватная подсеть и т.д.), прежде чем на неё полагаться. + +--- + +## Телеметрия и конфиденциальность + +CLI отправляет **анонимную аналитику использования** на сервис аналитики Exosphere (PostHog): какие команды запускаются (например, `sessions`, `keys create`), прошли ли они успешно и сколько времени заняло. Этот сигнал использования информирует о приоритизации функций. + +- **Данные агента, сеанса или события никогда не покидают вашу инфраструктуру.** Сообщается только использование CLI: имя команды и подкоманды (например, `keys create`), **имена** используемых флагов (никогда не их значения), статус успеха/выхода и длительность — плюс событие за действие для мутаций (например, `api_key_created`, `query_run`), содержащее только статические имена/перечисления и приблизительные счёты. Ваш URL панели управления, токен сеанса, почта, slug организации, идентификаторы ресурсов, SQL, секреты ключей и фильтры запросов **никогда** не отправляются. Операторы идентифицируются только по непрозрачному внутреннему id, никогда по почте. +- Телеметрия **включена по умолчанию**. Чтобы её отключить, установите `AGENTEYE_ANALYTICS_DISABLED=1` в окружении CLI (CLI также учитывает кроссутильное соглашение `DO_NOT_TRACK=1`). +- CLI отправляет напрямую на PostHog (`https://us.i.posthog.com`). **Машине, на которой работает CLI**, нужен исходящий доступ к этому хосту; если он заблокирован, телеметрия молча ничего не делает (отправка ограничена по времени, поэтому никогда не задерживает и не ломает команду) и CLI не затронут. + +--- + +## Глобальные опции и соглашения + +Прочитайте это один раз; это применяется к каждой команде. + +- **Глобальные опции идут ДО команды.** `agenteye --json sessions` верно; `agenteye sessions --json` — ошибка использования. Глобальные — это `--json`, `--base-url`, `--org`, `--token`, `--insecure`/`--secure`, `--timeout`, `--quiet` и `--no-color`. +- **`--json` выводит чистый JSON в stdout и больше ничего.** Строки статуса человека, предупреждения и ошибки идут в **stderr**, поэтому захват stdout `--json` остаётся чистым для передачи в `jq` даже когда показана строка статуса. Без `--json` вы получаете оформленный, раскрашенный вид для человеческих глаз. +- **Открывайте с помощью `--help`.** Каждая команда и подкоманда имеет `--help` (и псевдоним `-h`): `agenteye -h`, `agenteye sessions -h`, `agenteye keys create -h`. Справка верхнего уровня также перечисляет коды выхода и глобальные опции. Нет глобального машиночитаемого дампа поверхности; используйте для каждой команды `--help`, плюс специфичные для домена `agenteye query schema` и `agenteye settings schema`. +- **Подтверждения автоматически пропускаются для скриптов и агентов.** Команды create/update/delete подсказывают «вы уверены?» в интерактивном терминале, но **автоматически пропускают подсказку при `--json` или когда stdin — не TTY** — поэтому скрипты и агенты никогда не зависают. Передайте `--yes`/`-y` для явного пропуска. Поскольку подсказка не сработает для агента, агент должен сначала подтвердить деструктивные действия с человеком. +- **Постраничный вывод:** результаты новые первые и курсор-постраничные. `--limit N` (псевдоним `-n`) ограничивает строки и **по умолчанию 50**; `--all` автопостраничивает (порциями по 200 строк) **вплоть до `--limit`** — поэтому простой `--all` всё равно останавливается в 50. Для полного сканирования передайте высокий явный лимит: `--all --limit 1000`. `--page-size N` контролирует порцию на запрос (максимум 200); `--cursor ` возобновляет с `next_cursor` предыдущей страницы. +- **Фильтры времени:** `--since` принимает относительное окно — `15m`, `1h`, `6h`, `24h`, `7d`, `30d` или `all` (предустановки панели управления). `--from`/`--to` принимают явные временные метки ISO-8601 UTC **с `T` и временной зоной** (например, `2026-06-01T00:00:00Z`) для пользовательского диапазона и переопределяют `--since`; разделённое пробелом или без временной зоны значение — ошибка использования. +- **`--fields a,b,c`** (на `events`, `sessions`, `evals`, `errors`) ограничивает вывод этими ключами, для таблицы и `--json`. Неизвестные имена отклоняются с действительным списком — дешёвый способ открыть имена полей. +- **`--file payload.json`** (или `--file -` для чтения stdin) поставляет полное тело JSON запроса где ресурс имеет сложную форму — на `alerts create/update`, `settings set` и `users create/update`. SQL сохранённого запроса использует `--sql @file.sql`. +- **Фильтры с несколькими значениями** разделены запятыми → сопоставлены как набор (объединение в одном фильтре, AND через фильтры): `--event-type tool_use,tool_result`. Опции Click не вариадичны, поэтому `--add a b` ломает — используйте `--add a,b`, повторите флаг (`--add a --add b`) или кавычки (`--add "a b"`). + +--- + +## Справочник команд + +CLI имеет **18 команд верхнего уровня**. Все команды чтения принимают `--json` и глобальные опции выше; запустите `agenteye -h` (или ` -h`) для исчерпывающего списка флагов и формы JSON любой из них. + +### Идентификация — `login` · `logout` · `whoami` · `orgs` · `version` · `help` + +```bash +agenteye login --email you@example.com [--org acme] # одноразовый код по почте; сохраняет сеанс +agenteye logout # очистить сохранённый сеанс на этой машине +agenteye whoami # текущий пользователь, активная организация, права +agenteye version # вывести версию CLI (то же, что --version) +agenteye help # справка верхнего уровня (то же, что --help) +``` + +`orgs` проверяет и переключает активного тенанта: + +```bash +agenteye orgs list # ваши организации + ваша роль в каждой (активная отмечена) +agenteye orgs switch acme # изменить сохранённую активную организацию (пропустите slug для выбора списка на TTY) +agenteye orgs current # карточка идентификации активной организации +agenteye orgs perms # ваши права в активной организации, сгруппированные по ресурсам +``` + +### Наблюдение (только чтение) — `events` · `sessions` · `evals` · `errors` · `list` + +Ни один из них не нуждается в подтверждении. Общие фильтры: `--session-id`, `--agent-id`, `--env` (**не** `--environment`) и временной диапазон (`--since` / `--from` / `--to`). + +```bash +# события (псевдоним: след на этапе) — новые первые +agenteye --json events --session-id run-001 --event-type tool_use,tool_result --all --limit 1000 +agenteye --json events --since 1h --search timeout --all | jq '.events[].payload' + +# сеансы — одна строка на запуск агента (время/окружение/агент/сеанс/статус; без фильтра оценки) +agenteye --json sessions --since 24h --status error +agenteye --json sessions --agent-id checkout-bot --env prod --all --limit 1000 + +# оценки — результаты оценки + оценки; --score фильтрует по метрике, --aggregate сводит +agenteye --json evals --score helpfulness:0.5..0.8 --score tool_efficiency:..0.3 +agenteye --json evals --aggregate --since 7d --env prod # микс статусов + статистика оценок по ключам + +# ошибки — события с ошибками; --aggregate для счётов/сеансов/агентов/последнего-видел +agenteye --json errors --since 24h --aggregate +agenteye --json errors --since 24h --error-type timeout --all --limit 1000 + +# list — открыть действительные значения фильтров перед фильтрацией +agenteye list envs # также: agents event_types score_filters models hooks triggers tools error_types +``` + +`--score KEY:MIN..MAX` (на **`evals`**, не `sessions`) повторяется и AND-комбинируется; граница опциональна (`..0.5` означает ≤ 0.5, `0.9..` означает ≥ 0.9). До 20 фильтров оценок на запрос. `evals --scores-full` возвращает полный объект оценки вместо сводки. Для чтения **одного сеанса конец-в-конец**, объедините тропу события с его оценкой: + +```bash +agenteye --json events --session-id run-001 --all --limit 1000 | jq '.events[] | {ts, event_type}' +agenteye --json evals --session-id run-001 # его оценки + статус +``` + +### Управление (ограничено правами) — `keys` · `users` · `settings` · `alerts` · `incidents` + +**`keys`** — ключи API. Секрет генерируется локально, отправляется на сервер (который хранит только хэш) и **показывается один раз** на create/regenerate — захватите его тогда. При `--json` он появляется только в поле `key`. На что ссылаются по **имени**. + +```bash +agenteye keys list # активные ключи первые, затем отозванные +agenteye keys show ci-bot +agenteye keys create ci-bot --add events:read.add # область охвата, что вам нужно; выводит секрет ОДИН РАЗ +agenteye keys create ops --permission-set standard --remove queries:run # инициализируйте предустановкой, затем обрежьте +agenteye keys update ci-bot --add evaluations:read --yes +agenteye keys regenerate ci-bot --yes # ротация секрета (старый переходит в стоп) +agenteye keys disable ci-bot --yes # отозвать +``` + +Права работают как `(permission-set ∪ --add) − --remove`. Токены — это `slug:action` (например, `events:read`) или `slug:action.action` для расширения нескольких на одном ресурсе (`events:read.add` → `events:read`, `events:add`). Предустановки: `read-only`, `standard`, `admin`. Права только для человека (`keys:update`) не могут быть выданы ключу. + +**`users`** — члены организации, на которых ссылаются по **почте** (UUID id также принимается). + +```bash +agenteye users list [--active-only] +agenteye users show dev@corp.com +agenteye users create dev@corp.com --permission-set standard +agenteye users update dev@corp.com --add alerts:write --remove queries:delete # предсказывает + подтверждает +agenteye users disable dev@corp.com --yes # имеет защищённые/самозащитные охраны +agenteye users enable dev@corp.com +``` + +**`settings`** — фиксированный реестр (вы читаете и изменяете существующие ключи; вы не можете создавать новые). + +```bash +agenteye settings list # ключ · значение · тип · обновлено (секреты скрыты) +agenteye settings schema # что каждый ключ принимает (тип · диапазон · описание) +agenteye settings set session_ttl_secs --value 86400 --yes +``` + +**`alerts`** — определения оповещений, на которые ссылаются по **имени**. `create` принимает позиционное ИМЯ плюс флаги или полное тело JSON через `--file`. + +```bash +agenteye alerts list +agenteye alerts show high-errors +agenteye alerts create high-errors --file alert.json # ИМЯ обязательно (позиционный) +agenteye alerts update high-errors --severity critical --yes +agenteye alerts test high-errors --yes # отправить тестовое уведомление +agenteye alerts delete high-errors --yes +``` + +**`incidents`** — инциденты оповещений, на которые ссылаются по id (короткие id приняты). `show` выводит полный журнал активности — прочитайте его перед действием. + +```bash +agenteye incidents list --state firing # также: acknowledged, resolved +agenteye incidents count +agenteye incidents show +agenteye incidents ack +agenteye incidents assign you@corp.com # назначенный должен быть оператором +agenteye incidents resolve --yes +agenteye incidents open --alert-id --severity critical # открыть один вручную против оповещения +agenteye incidents comment-add "root cause: upstream 5xx" +agenteye incidents comment-list ; agenteye incidents comment-delete +agenteye incidents subscribe ; agenteye incidents unsubscribe ; agenteye incidents subscribers +``` + +### Аналитика и помощник — `query` · `agent` + +**`query`** — сохранённый SQL ClickHouse плюс ad-hoc runner. Сохранённые запросы на которые ссылаются по **имени**; SQL проверяется на стороне сервера (только SELECT/WITH, тайм-аут оператора, ограничение строк). + +```bash +agenteye query schema [TABLE] # раскладка столбцов аналитических представлений +agenteye query run --sql "select count(*) from analytics.events" +agenteye query run errs --arg prod --limit 100 # запустить сохранённый запрос + позиционный $1 +agenteye query list ; agenteye query show errs +agenteye query create errs --sql @errs.sql --description "errored events (24h)" +agenteye query update errs --sql @errs.sql --yes ; agenteye query delete errs --yes +``` + +**`agent`** — встроенный помощник панели управления (тот же аналитик только для чтения, с которым вы можете общаться в панели управления). Чаты на которые ссылаются по короткому chat-id (разрешение префиксом). + +```bash +agenteye agent health # помощник настроен/доступен +agenteye agent models # модели, которые вы можете передать в --model (по умолчанию отмечена) +agenteye agent ask "which agents errored most in the last day?" # запускает чат; выводит его короткий id +agenteye agent ask --chat "and which tools did they call?" # продолжить тот чат +agenteye agent chats ; agenteye agent show +agenteye agent rename --title "error triage" ; agenteye agent delete +``` + +--- + +## Коды выхода + +| Код | Значение | +|---|---| +| 0 | Успех | +| 1 | Неожиданная ошибка (например, панель управления вернула 5xx) | +| 2 | Ошибка использования (неправильные аргументы, неизвестная команда/флаг, коллизия имён) | +| 3 | Невозможно достичь панель управления | +| 4 | Не вошли или сеанс истёк; запустите `agenteye login` | +| 5 | Аутентифицированы, но вашей учётной записи не хватает требуемого права (сообщение его называет) | +| 6 | Запрошенный ресурс не найден (например, неизвестный id сеанса или инцидента) | + +Это делает CLI безопасным для скриптов: кодирующий агент может ветвиться на `4` для подсказки вам переаутентифицироваться, или на `5` для поверхности отсутствующего права. См. [CLI рецепты для агентов](/ru/agenteye/cli-recipes) для обработки кодов выхода и форм вывода JSON. + +--- + +## См. также + +- **[CLI рецепты для агентов](/ru/agenteye/cli-recipes)** — скопируйте-вставьте шаблоны запросов, одноразовые `jq`, проекции `--fields`, обработка кодов выхода и формы вывода JSON, написанные для кодирующих агентов, управляющих CLI. +- **[Навык CLI AgentEye](/ru/agenteye/cli-skill)** — упакуйте этот CLI как устанавливаемый *навык* Claude Code / Codex, чтобы кодирующий агент управлял AgentEye из запросов на простом английском. +- **[Ключи API](/ru/agenteye/api-keys)** — модель прав за `keys create --add …`. +- **[ИИ помощник](/ru/agenteye/assistant)** — включение помощника, с которым общается `agent ask`. \ No newline at end of file diff --git a/docs/ru/agenteye/collector-installation.mdx b/docs/ru/agenteye/collector-installation.mdx new file mode 100644 index 00000000..ae8190e6 --- /dev/null +++ b/docs/ru/agenteye/collector-installation.mdx @@ -0,0 +1,401 @@ +--- +title: "Установка Collector" +description: "Документация по установке AgentEye Collector." +--- + + +Демон `agenteye-collector` гарантирует, что телеметрия ваших агентов достигает AgentEye без блокирования приложения. Ваш код записывает события в локальный каталог и продолжает работу; collector берет на себя ответственность, загружая каждый файл в течение миллисекунд и сохраняя работоспособность при перезагрузках, сбоях сети и временных ошибках сервера. Неудачные загрузки повторяются с экспоненциальной задержкой, а периодическая восстановительная развёртка повторно ставит в очередь всё, что осталось после сбоя или развёртывания. Результат — надежная доставка с принципом «отправить и забыть»: ваши агенты работают на полной скорости, а collector гарантирует, что события не потеряются в пути. + +По сути, collector — это лёгкий демон, который отслеживает `$AGENTEYE_HOME/events/` (по умолчанию: `~/.agenteye/events/`) для файлов `.jsonl`, записанных Python SDK, и загружает их на сервер AgentEye. + +> **Переименовано:** команда collector теперь **`agenteye-collector`** (раньше это был `agenteye`). Краткое имя `agenteye` теперь принадлежит CLI AgentEye. Если вы обновляете существующую установку, см. [enterprise-docs/collector-migration.md](/ru/agenteye/collector-migration). + +--- + +## Предварительные требования + +- Ваш `AGENTEYE_TOKEN`: GitHub PAT, который вы создаёте сами (см. [enterprise-docs/github-token.md](/ru/agenteye/github-token)) +- URL сервера и ключ API collector (см. [enterprise-docs/api-keys.md](/ru/agenteye/api-keys)) + +--- + +## Вариант A: Бинарный файл (рекомендуется) + +Предварительно собранные статические бинарные файлы доступны для Linux, macOS и Windows (x86_64 и arm64). Загрузите бинарный файл для вашей платформы прямо из репозитория `agenteye-enterprise/releases` под последний тег релиза `collector/v`. + +Доступные имена артефактов: + +| Платформа | Артефакт | +|---|---| +| Linux x86_64 | `agenteye-collector-linux-x86_64` | +| Linux arm64 | `agenteye-collector-linux-arm64` | +| macOS x86_64 | `agenteye-collector-darwin-x86_64` | +| macOS arm64 | `agenteye-collector-darwin-arm64` | +| Windows x86_64 | `agenteye-collector-windows-x86_64.exe` | +| Windows arm64 | `agenteye-collector-windows-arm64.exe` | + +**Загрузка с помощью CLI `gh`** (замените версию и выберите артефакт для вашей платформы): + +```bash +VERSION=0.0.1-beta.13 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "collector/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-collector-linux-x86_64' + +chmod +x agenteye-collector-linux-x86_64 +sudo mv agenteye-collector-linux-x86_64 /usr/local/bin/agenteye-collector +``` + +**Или с помощью `curl`:** + +```bash +VERSION=0.0.1-beta.13 +ARTIFACT=agenteye-collector-linux-x86_64 +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + -L "https://github.com/agenteye-enterprise/releases/releases/download/collector%2Fv${VERSION}/${ARTIFACT}" \ + -o agenteye-collector +chmod +x agenteye-collector +sudo mv agenteye-collector /usr/local/bin/agenteye-collector +``` + +--- + +## Вариант B: Docker + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +docker pull ghcr.io/agenteye-enterprise/collector:beta-latest +``` + +> Текущие бета-сборки публикуют плавающий тег `:beta-latest`; `:latest` назначается только стабильным релизам. Для повторяемых развёртываний предпочитайте закреплённый тег версии, такой как `:v0.0.1-beta.13`. + +**Запуск:** + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-collector \ + -e AGENTEYE_URL=https://ingest.example.com/events \ + -e AGENTEYE_KEY="$AGENTEYE_KEY" \ + -e AGENTEYE_HOME=/data \ + -v "$HOME/.agenteye:/data" \ + ghcr.io/agenteye-enterprise/collector:beta-latest \ + start +``` + +Официальный образ запускается от непривилегированного пользователя, поэтому задайте `AGENTEYE_HOME` явно и смонтируйте хостовый буфер к нему. Монтирование тома использует тот же каталог `~/.agenteye/`, в который Python SDK записывает на хосте. Если вы уже установили `AGENTEYE_HOME` в другом месте на хосте, смонтируйте вместо этого этот каталог. + +--- + +## Конфигурация + +Все параметры можно установить тремя способами (в порядке приоритета): + +1. Флаг CLI: `agenteye-collector start --url https://...` +2. Переменная окружения: `AGENTEYE_URL=https://...` +3. Файл конфигурации: `~/.agenteye/config.json` + +### Обязательные параметры + +| Параметр | Флаг CLI | Переменная окружения | Ключ config.json | +|---|---|---|---| +| URL сервера | `--url ` | `AGENTEYE_URL` | `"url"` | +| Ключ API | `--key ` | `AGENTEYE_KEY` | `"key"` | + +### Опциональные параметры (со значениями по умолчанию) + +| Параметр | Флаг CLI | Переменная окружения | Ключ config.json | По умолчанию | +|---|---|---|---|---| +| Макс. одновременных загрузок | `--max-concurrent-uploads ` | `AGENTEYE_MAX_CONCURRENT_UPLOADS` | `"max_concurrent_uploads"` | `64` | +| Интервал развёртки (сек) | `--sweep-interval ` | `AGENTEYE_SWEEP_INTERVAL` | `"sweep_interval_secs"` | `60` | +| Мин. возраст файла развёртки (сек) | `--sweep-min-age ` | `AGENTEYE_SWEEP_MIN_AGE` | `"sweep_min_age_secs"` | `120` | +| Макс. файлов в развёртке | `--sweep-max-files ` | `AGENTEYE_SWEEP_MAX_FILES` | `"sweep_max_files"` | `64` | +| Макс. попыток загрузки | `--max-retries ` | `AGENTEYE_MAX_RETRIES` | `"max_retries"` | `5` | +| Базовая задержка повтора (мс) | `--retry-base-delay ` | `AGENTEYE_RETRY_BASE_DELAY` | `"retry_base_delay_ms"` | `1000` | + +### Параметры mTLS (опционально) + +Для развёртываний, требующих взаимной TLS (mTLS), collector может представить сертификат клиента во время установления TLS. Если эти параметры не установлены, collector использует стандартный HTTPS. + +| Параметр | Флаг CLI | Переменная окружения | Ключ config.json | +|---|---|---|---| +| Сертификат клиента (PEM) | `--tls-cert ` | `AGENTEYE_TLS_CERT` | `"tls_cert"` | +| Приватный ключ клиента (PEM) | `--tls-key ` | `AGENTEYE_TLS_KEY` | `"tls_key"` | +| Пользовательский сертификат CA (PEM) | `--tls-ca ` | `AGENTEYE_TLS_CA` | `"tls_ca"` | + +`--tls-cert` и `--tls-key` должны быть установлены вместе. Файлы должны быть в формате PEM. + +`--tls-ca` независим и требуется только тогда, когда сервер AgentEye представляет TLS-сертификат, который не выдан общедоступным CA (например, самоподписанный издателем `cert-manager` в кластере, когда у вас нет настоящего DNS-домена). Collector добавляет предоставленный CA как дополнительное доверенное якорё; стандартные корни общедоступности остаются доверенными, поэтому существующие развёртывания не затрагиваются. Файл может содержать один PEM-сертификат или полную цепь (несколько объединённых PEM-блоков). + +**Запуск collector как sidecar в поде приложения?** См. [enterprise-docs/single-pod-deployment.md](/ru/agenteye/single-pod-deployment) для полного паттерна EKS: пакет mTLS, доставляемый через AWS Secrets Manager + Secrets Store CSI Driver + IRSA с автоматической ротацией. + +При запуске в Kubernetes с паттерном передачи Secret смонтируйте Secret сертификата как том и укажите эти пути на смонтированные файлы: + +```yaml +# Пример: фрагмент Deployment collector +volumes: + - name: mtls-certs + secret: + secretName: agenteye-collector-mtls +containers: + - name: collector + env: + - name: AGENTEYE_TLS_CERT + value: /etc/agenteye/tls/tls.crt + - name: AGENTEYE_TLS_KEY + value: /etc/agenteye/tls/tls.key + # Только если сертификат сервера не выдан общедоступным CA (например, + # самоподписанный CA в кластере). Тот же Secret обычно содержит ca.crt + # рядом с tls.crt/tls.key. + - name: AGENTEYE_TLS_CA + value: /etc/agenteye/tls/ca.crt + volumeMounts: + - name: mtls-certs + mountPath: /etc/agenteye/tls + readOnly: true +``` + +### Пример `~/.agenteye/config.json` + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "max_concurrent_uploads": 16, + "sweep_interval_secs": 30 +} +``` + +С mTLS: + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "tls_cert": "/etc/agenteye/tls/tls.crt", + "tls_key": "/etc/agenteye/tls/tls.key" +} +``` + +С mTLS плюс пользовательский CA (самоподписанный сервер AgentEye): + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "tls_cert": "/etc/agenteye/tls/tls.crt", + "tls_key": "/etc/agenteye/tls/tls.key", + "tls_ca": "/etc/agenteye/tls/ca.crt" +} +``` + +Если установлен `AGENTEYE_HOME`, используется этот каталог вместо `~/.agenteye`. + +--- + +## Первоначальная настройка + +После установки настройте collector с URL сервера и ключом API: + +```bash +mkdir -p ~/.agenteye +cat > ~/.agenteye/config.json <<'EOF' +{ + "url": "https://ingest.example.com/events", + "key": "YOUR_COLLECTOR_KEY" +} +EOF +``` + +> Используйте `https` для любого развёртывания, пересекающего ненадёжную сеть, чтобы события не отправлялись в открытом виде. Открытая форма `http://your-server-host:8080/events` подходит только для чисто локального тестирования против сервера на том же хосте. + +**Протестируйте соединение** (одноразовое полоскание, выход после слива ожидающих событий): + +```bash +agenteye-collector flush +``` + +`flush` сообщает о прогрессе на stdout. Когда буфер пуст, выводит `No pending files.` и выходит с кодом `0`. В противном случае выводит одну строку на файл (`[UPLOADED] ` или `[FAILED] ()`), затем итоговую сводку `Done: / uploaded, failed.`. Это делает `flush` удобной одноразовой проверкой, что ваш URL, ключ и параметры TLS верны перед запуском демона. + +--- + +## Запуск как демон + +### Прямой запуск + +```bash +agenteye-collector start +``` + +### Контейнер / Docker + +Когда collector и приложение используют один контейнер, запустите их под супервизором процессов. Самый простой вариант — `supervisord`; он поставляется в каждом основном дистрибутиве, перезапускает упавшие процессы, перенаправляет сигналы и ждёт корректного завершения. + +**`Dockerfile`:** + +```Dockerfile +FROM python:3.11-slim + +RUN apt-get update && apt-get install -y --no-install-recommends supervisor \ + && rm -rf /var/lib/apt/lists/* + +# Получите бинарный файл agenteye-collector из официального образа. +# Закрепите конкретный тег (:beta-latest для текущих бета-версий или тег :v); +# :latest публикуется только для стабильных релизов. +COPY --from=ghcr.io/agenteye-enterprise/collector:beta-latest \ + /usr/local/bin/agenteye-collector /usr/local/bin/agenteye-collector + +COPY supervisord.conf /etc/supervisor/conf.d/agenteye.conf +COPY my_agent.py /app/my_agent.py + +CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"] +``` + +**`supervisord.conf`:** + +```ini +[supervisord] +nodaemon=true +user=root + +[program:agenteye-collector] +command=/usr/local/bin/agenteye-collector start +autorestart=true +stopwaitsecs=30 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:app] +command=python /app/my_agent.py +autorestart=unexpected +stopwaitsecs=30 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +``` + +Почему эти параметры: + +- `autorestart=true` на agenteye-collector: перезапуск при любом выходе (сбой, паника, OOM). +- `autorestart=unexpected` на приложении: перезапуск только при ненулевом выходе, поэтому одноразовый агент, выходящий с 0, не зацикливается. +- `stopwaitsecs=30`: дает collector возможность слить ожидающие загрузки при SIGTERM перед тем, как supervisord переключится на SIGKILL. +- `stdout_logfile=/dev/stdout`, `*_maxbytes=0`: потоковая передача вывода обоих программ на контейнер stdout; без логфайлов внутри контейнера. + +Передайте `AGENTEYE_URL` / `AGENTEYE_KEY` (и любые переменные TLS) на `docker run -e` как раньше; supervisord наследует окружение. + +> **Отдельные контейнеры?** Если вы запускаете collector как собственный контейнер (сервис Docker Compose, sidecar Kubernetes и т.д.), не используйте supervisord; политика перезагрузки runtime контейнера уже выполняет эту работу. См. [enterprise-docs/single-pod-deployment.md](/ru/agenteye/single-pod-deployment) для паттерна EKS sidecar. + +**Проверка живучести Kubernetes** (применяется независимо от того, работает ли collector отдельно или под supervisord): + +```yaml +livenessProbe: + exec: + command: ["agenteye-collector", "health"] + initialDelaySeconds: 10 + periodSeconds: 30 +``` + +Работающий демон записывает пульс в `$AGENTEYE_HOME/health.json` каждые 30 секунд. `agenteye-collector health` читает этот файл и выходит с кодом `0` (здоров) только если пульс свежий и задачи загрузки работают нормально; выходит с кодом `1` (болен) если пульс старше 90 секунд (например, демон остановился) или пока наблюдатель и развёртка перезагружаются после непредвиденного выхода. Пульс записывается только командой `start`, поэтому запустите проверку против долгоживущего демона, а не одноразовой команды `flush`. + +### systemd (Linux, рекомендуется для production) + +```ini +# /etc/systemd/system/agenteye-collector.service +[Unit] +Description=AgentEye Collector +After=network.target + +[Service] +ExecStart=/usr/local/bin/agenteye-collector start +Restart=on-failure +RestartSec=5 +EnvironmentFile=/etc/agenteye/env + +[Install] +WantedBy=multi-user.target +``` + +Создайте `/etc/agenteye/env`: + +``` +AGENTEYE_URL=https://ingest.example.com/events +AGENTEYE_KEY=YOUR_COLLECTOR_KEY +``` + +```bash +sudo systemctl daemon-reload +sudo systemctl enable --now agenteye-collector +sudo systemctl status agenteye-collector +``` + +### launchd (macOS) + +```xml + + + + + + Label + ai.befailproof.agenteye-collector + ProgramArguments + + /usr/local/bin/agenteye-collector + start + + EnvironmentVariables + + AGENTEYE_URL + https://ingest.example.com/events + AGENTEYE_KEY + YOUR_COLLECTOR_KEY + + RunAtLoad + + KeepAlive + + + +``` + +```bash +launchctl load ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +``` + +--- + +## Обновление Collector + +Collector не обновляется самостоятельно. Для обновления: + +- **Бинарный файл:** загрузите новый артефакт `agenteye-collector--` из последнего релиза `collector/v` (см. [Вариант A](#вариант-a-бинарный-файл-рекомендуется)), замените `/usr/local/bin/agenteye-collector`, затем перезагрузите сервис (`sudo systemctl restart agenteye-collector`, переза-`launchctl load` или перезагрузите ваш супервизор). +- **Docker:** `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (или закреплённый тег `:v`; `:latest` существует только для стабильных релизов) и пересоздайте контейнер. + +`AGENTEYE_TOKEN` требуется для загрузки новых бинарных файлов/образов из приватного репозитория релизов, но **не** требуется работающему демону. + +--- + +## Подкоманды + +| Команда | Описание | +|---|---| +| `agenteye-collector start` | Запустить долгоживущий демон. При запуске он полоскает все события, оставшиеся с предыдущего запуска, затем отслеживает новые файлы и загружает их. Наблюдатель и развёртка автоматически перезагружаются при непредвиденном выходе, и пульс записывается в `health.json` каждые 30 секунд. | +| `agenteye-collector flush` | Одноразово: загрузить все ожидающие файлы и выйти. Выводит `No pending files.` если буфер пуст, в противном случае логирует для каждого файла `[UPLOADED]`/`[FAILED]` и итоговую сводку `Done: / uploaded, failed.`. | +| `agenteye-collector health` | Прочитать пульс `health.json` демона. Выход `0` если свежий и здоров; выход `1` если пульс устарел (старше 90 сек) или задачи перезагружаются. | + +--- + +## Макет каталога + +``` +~/.agenteye/ +├── config.json <- опциональный файл конфигурации +├── events/ <- файлы .jsonl, записанные SDK, подхваченные collector +└── failed/ <- файлы, которые не загрузились при всех попытках +``` + +Файлы в `failed/` не повторяются автоматически. Чтобы вручную переставить их в очередь, переместите их обратно в `events/` и запустите `agenteye-collector flush`. \ No newline at end of file diff --git a/docs/ru/agenteye/collector-migration.mdx b/docs/ru/agenteye/collector-migration.mdx new file mode 100644 index 00000000..5efe37fb --- /dev/null +++ b/docs/ru/agenteye/collector-migration.mdx @@ -0,0 +1,168 @@ +--- +title: "Миграция на `agenteye-collector`" +description: "Документация AgentEye по миграции на `agenteye-collector`." +--- + + +Миграция не деструктивна: она не вызывает простоев и потери данных, а также освобождает короткое имя `agenteye` для [AgentEye CLI](/ru/agenteye/cli), так что демон-сборщик и CLI могут сосуществовать на одной машине. + +Бинарный файл сборщика был **переименован с `agenteye` на `agenteye-collector`**. Короткое имя `agenteye` теперь принадлежит AgentEye CLI — отдельному инструменту для запроса сессий, событий и оценок из терминала. + +Это руководство поможет вам провести миграцию существующей установки сборщика. + +--- + +## Что изменилось + +| | До | После | +|---|---|---| +| Команда / бинарный файл | `agenteye` | `agenteye-collector` | +| Путь установки по умолчанию | `/usr/local/bin/agenteye` | `/usr/local/bin/agenteye-collector` | +| Подкоманды | `start`, `flush`, `health`, `update` | `start`, `flush`, `health` | +| Самообновление (`agenteye update`) | встроено | **удалено**: загрузите новый бинарный файл или получите новый образ | +| Скрипт установки (`install.sh`) | предоставляется | **удалено**: загрузите бинарный файл напрямую (см. [Установка сборщика](/ru/agenteye/collector-installation)) | +| `AGENTEYE_TOKEN` | требуется для загрузки **и** для проверки фонового обновления | требуется только для **загрузки** бинарных файлов/образов | + +Конфигурация не изменилась: тот же `~/.agenteye/config.json`, те же переменные среды `AGENTEYE_URL` / `AGENTEYE_KEY` / `AGENTEYE_HOME` / TLS и тот же буфер `~/.agenteye/events/`. **Редактирование конфигурации не требуется.** + +> Если вы запустите переименованный бинарный файл под старым именем `agenteye`, он всё ещё работает, но выведет одну строку предупреждения об устаревании в stderr, напоминая вам о переходе на `agenteye-collector`. + +--- + +## Прежде чем начать + +- Ваша **существующая установка `agenteye` продолжает работать**; ничего не сломается в момент обновления. Проведите миграцию намеренно, затем удалите старый бинарный файл последним. +- Следуйте этому порядку, чтобы избежать простоев: + 1. Установите новый бинарный файл `agenteye-collector` (или получите новый образ). + 2. Обновите определение вашего сервиса / зонд здоровья / скрипты для вызова `agenteye-collector`. + 3. Перезагрузите и перезапустите сервис; подтвердите, что он в порядке. + 4. **Только потом** удалите старый бинарный файл `/usr/local/bin/agenteye`. + +--- + +## 1. Установите новый бинарный файл + +Загрузите артефакт для вашей платформы (`agenteye-collector-linux-x86_64`, `agenteye-collector-darwin-arm64` и так далее; см. [Установка сборщика → Вариант A](/ru/agenteye/collector-installation#option-a-binary-recommended) для полного списка) из последнего релиза `collector/v` и поместите его в `/usr/local/bin/agenteye-collector`. Для Docker пользователей: `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (или закреплённый тег `:v`, что предпочтительно; `:latest` существует только для стабильных релизов). + +Проверьте: + +```bash +agenteye-collector --version +``` + +--- + +## 2. Обновите ваше развёртывание + +### systemd (Linux) + +Отредактируйте `/etc/systemd/system/agenteye-collector.service` так, чтобы `ExecStart` указывал на новый бинарный файл: + +```ini +[Service] +ExecStart=/usr/local/bin/agenteye-collector start +``` + +Затем перезагрузите и перезапустите: + +```bash +sudo systemctl daemon-reload +sudo systemctl restart agenteye-collector +sudo systemctl status agenteye-collector +``` + +### launchd (macOS) + +> **Переименование бренда:** Если ваш существующий plist находится по старому пути +> `~/Library/LaunchAgents/host.exosphere.agenteye-collector.plist`, переименуйте +> файл на `ai.befailproof.agenteye-collector.plist` и также измените значение +> `Label` внутри файла на новый идентификатор перед перезагрузкой. + +В `~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist` измените первую запись `ProgramArguments` с `/usr/local/bin/agenteye` на `/usr/local/bin/agenteye-collector`, затем перезагрузите: + +```bash +launchctl unload ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +launchctl load ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +``` + +### supervisord + +В блоке программы `supervisord` установите `command` на новый бинарный файл: + +```ini +[program:agenteye-collector] +command=/usr/local/bin/agenteye-collector start +``` + +Затем выполните `supervisorctl reread && supervisorctl update`. + +### Docker / Kubernetes + +Получите новый образ (`ghcr.io/agenteye-enterprise/collector:beta-latest` или закреплённый `:v`, что предпочтительно; `:latest` существует только для стабильных релизов). Точка входа образа уже `agenteye-collector`, так что та же команда `docker run` с подкомандой `start` продолжает работать без изменений. + +**Важно: обновите зонды здоровья.** Если вы используете зонд живучести/готовности Kubernetes (или любой `docker exec`), который запускает бинарный файл по имени, измените команду на `agenteye-collector`: + +```yaml +livenessProbe: + exec: + command: ["agenteye-collector", "health"] +``` + +Новый образ **не** содержит псевдонима `agenteye`, поэтому зонд, всё ещё вызывающий `agenteye`, будет неудачным. Обновите зонд при той же развёртке нового образа. + +### Cron / ручные скрипты + +Замените любые вызовы `agenteye start|flush|health` на соответствующую команду `agenteye-collector start|flush|health`. **Удалите любые cron-задания `agenteye update`**; эта подкоманда больше не существует (см. [Обновления с этого момента](#обновления-с-этого-момента)). + +--- + +## 3. Удалите старый бинарный файл (последним) + +Когда сервис работает на `agenteye-collector` и сообщает о здоровье: + +```bash +sudo rm /usr/local/bin/agenteye +``` + +Это особенно важно, если вы также используете AgentEye CLI, который устанавливает собственную команду `agenteye`; оставление старого бинарного файла сборщика в `/usr/local/bin/agenteye` сделает имя `agenteye` неоднозначным в вашем `PATH`. + +--- + +## Обновления с этого момента + +Сборщик больше не обновляет себя. Для обновления: + +- **Бинарный файл:** загрузите новый артефакт для вашей платформы (например `agenteye-collector-linux-x86_64`; см. [Установка сборщика → Вариант A](/ru/agenteye/collector-installation#option-a-binary-recommended) для полного списка), замените `/usr/local/bin/agenteye-collector` и перезапустите сервис. +- **Docker:** `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (или закреплённый тег `:v`, что предпочтительно; `:latest` существует только для стабильных релизов) и пересоздайте контейнер. + +`AGENTEYE_TOKEN` всё ещё требуется для загрузки из приватного репозитория релизов, но работающий демон больше его не требует. + +--- + +## Проверка + +```bash +agenteye-collector --version # новый бинарный файл в PATH +agenteye-collector health # exit 0 = здоров +agenteye-collector flush # пересылает любые события в очереди и завершается чисто +``` + +Затем подтвердите, что новые события появляются в вашей панели управления. + +--- + +## Откат + +Миграция не деструктивна. Если вам нужно откатиться, верните определение вашего сервиса обратно на старый бинарный файл `/usr/local/bin/agenteye` (если вы его ещё не удалили) и перезапустите. Буфер событий и конфигурация являются общими и не затронуты. + +--- + +## Поиск и устранение неисправностей + +| Симптом | Причина | Решение | +|---|---|---| +| `warning: the collector binary is now agenteye-collector …` при каждом запуске | Вы вызываете бинарный файл под старым именем `agenteye` | Вместо этого вызывайте `agenteye-collector`; обновите файлы и скрипты сервисов. | +| systemd падает: `.../agenteye: No such file or directory` | Вы удалили старый бинарный файл перед обновлением `ExecStart` | Установите `ExecStart=/usr/local/bin/agenteye-collector start`, затем `sudo systemctl daemon-reload`. | +| Pod Kubernetes зависает в цикле сбоев после обновления образа | Зонд живучести всё ещё запускает `agenteye` | Измените команду зонда на `["agenteye-collector", "health"]`. | +| `agenteye: command not found`, но `agenteye-collector` работает | Скрипты/псевдонимы всё ещё ссылаются на старое имя | Обновите их на `agenteye-collector`. | +| Запуск `agenteye` запускает CLI, а не сборщик | У вас установлен AgentEye CLI; он владеет `agenteye` | Используйте `agenteye-collector` для демона и удалите оставшийся старый бинарный файл сборщика в `/usr/local/bin/agenteye`. | \ No newline at end of file diff --git a/docs/ru/agenteye/deployment.mdx b/docs/ru/agenteye/deployment.mdx new file mode 100644 index 00000000..3ad061f2 --- /dev/null +++ b/docs/ru/agenteye/deployment.mdx @@ -0,0 +1,427 @@ +--- +title: "Развертывание" +description: "Документация по развертыванию AgentEye." +--- + +Это руководство охватывает развертывание сервера AgentEye и панели управления в production. + +--- + +## Обзор архитектуры + +``` + [ Машины с ИИ-агентами ] [ Ваша инфраструктура ] + + Python SDK + | записывает JSONL +----------------------+ + v +--->| PostgreSQL 15+ | + agenteye-collector --HTTP--+ | | (реляционное | + | | | хранилище) | + v | +----------------------+ + +--------+ | + | Server |<------+--->| ClickHouse 24+ | + +--------+ | | (события / аналитика)| + ^ | +----------------------+ + API | | + | | +----------------------+ + +-----------+ +- - >| Redis 7+ (опционально)| + | Dashboard | +----------------------+ + +-----------+ +``` + +- **Server**: HTTP-сервис на Rust; получает пакеты событий, записывает их в ClickHouse и поддерживает relational-состояние в PostgreSQL. +- **Dashboard**: веб-приложение Next.js; читает и записывает исключительно через API сервера. +- **agenteye-collector**: развертывается на машинах агентов, а не на хосте сервера. +- **Postgres 15+**: ТРЕБУЕТСЯ. (Повышено с 14 в релизе multi-tenant; схема org-membership использует foreign key с `ON DELETE SET NULL` для списка колонок, что требует Postgres 15+. Обновите Postgres перед развертыванием этой версии.) Хранит OLTP-состояние: `api_keys`, `users`, `sessions`, `evaluation_jobs` (очередь), `dashboards`, `saved_queries`, `otp_codes`, плюс multi-tenant таблицы `orgs`, `org_memberships`, `org_settings`. +- **ClickHouse 24+**: ТРЕБУЕТСЯ. Аналитическое хранилище для каждого ingested события. Engine: `ReplacingMergeTree`, разделенное по месяцам, отсортированное по `(session_id, ts, dedup_key)`. Сервер подключается через `CLICKHOUSE_URL`; встроенная конфигурация `deploy/base/clickhouse/` содержит оптимизированную конфигурацию для single-node. **Требование для multi-tenant:** встроенная конфигурация включает управление доступом SQL + `users_without_row_policies_can_read_rows=false`, чтобы сервер мог создать одного read-only пользователя ClickHouse + row policy на организацию (boundary изоляции, обеспечиваемое engine, для SQL-редактора и ИИ-агента). Если вы используете собственную конфигурацию ClickHouse, перенесите эти параметры (см. `deploy/base/clickhouse/configmap.yaml`). +- **Redis 7+**: *опционально* shared cache + rate-limit backend. Сервер и панель управления подключаются через `REDIS_URL`. Если отсутствует, оба gracefully деградируют до Postgres-only путей. См. **Redis (опциональный кеш)** ниже. + +--- + +## Server + +### Получение образа + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +docker pull ghcr.io/agenteye-enterprise/server:beta-latest +``` + +> Текущие сборки публикуются под `beta-latest`; `latest` присваивается только stable релизам. Для production используйте конкретный тег `:v`; см. [Доступные теги образов](#доступные-теги-образов). + +### Переменные окружения + +| Переменная | Требуется | По умолчанию | Описание | +|---|---|---|---| +| `DATABASE_URL` | Да | нет | Postgres DSN. Стандартная строка подключения libpq с схемой `postgres://`. Поддерживает `?sslmode=require` и другие параметры libpq. Пароль не должен содержать `/`, `+` или `=`; используйте `openssl rand -hex` для генерации URL-безопасных паролей. | +| `ADMIN_KEY` | Нет | нет | Bootstrap admin API key. Upserted со всеми разрешениями при каждом запуске. Ротируйте, изменив значение и перезагрузив. | +| `LISTEN_ADDR` | Нет | `0.0.0.0:8080` | TCP-адрес для привязки | +| `MAX_BODY_BYTES` | Нет | `134217728` (128 MB) | Максимальный размер тела запроса | +| `ADMIN_EMAIL` | Нет | нет | Email bootstrap admin пользователя. Upserted со всеми разрешениями при каждом запуске и отмечен как protected: не может быть отключен или иметь измененные разрешения через dashboard/API. Чтобы ротировать bootstrap admin, измените `ADMIN_EMAIL` и перезагрузитесь; новый email upserted как protected, а предыдущий сохраняет protection до ручной очистки в БД. | +| `ALLOWED_EMAILS` | Нет | нет (все заблокированы) | Список разделенных запятыми разрешенных адресов электронной почты для создания пользователя и входа. Поддерживает точные адреса (`user@example.com`) и wildcards домена (`*@example.com`). Если не установлено, никакие пользователи не могут быть созданы или войти. **Только первая загрузка**: заполняет allowlist org по умолчанию при первой загрузке; после этого страница [`//settings`](#operational-settings) каждой org является источником истины и изменение этой переменной окружения не имеет эффекта. | +| `SMTP_HOST` | Нет | нет | Имя хоста SMTP-сервера для отправки OTP-писем. Если не установлено, OTP-коды логируются в stdout вместо этого. | +| `SMTP_PORT` | Нет | `587` | Порт SMTP-сервера | +| `SMTP_USERNAME` | Нет | нет | Имя пользователя SMTP-аутентификации | +| `SMTP_PASSWORD` | Нет | нет | Пароль SMTP-аутентификации | +| `SMTP_FROM` | Нет | нет | Адрес отправителя для OTP-писем | +| `SMTP_TLS` | Нет | STARTTLS | STARTTLS используется, если вы явно не отключите: `false` или `0` отправляет plaintext (без TLS); любое другое значение — включая не установленное — включает STARTTLS. | +| `DASHBOARD_URL` | Нет | встроенное значение по умолчанию | Источник Dashboard, используемый для построения как magic link в OTP-письме, так и incident magic-links в уведомлениях оповещений. Если не установлено, он возвращается к встроенному значению по умолчанию (и, только для OTP, к origin, полученному из dashboard первым). Установите это для split-domain конфигураций, чтобы как email, так и Slack/incident ссылки указывали на вашу dashboard. См. **Email magic-link URL** ниже; большинство операторов это устанавливать не должны. | +| `SESSION_TTL_SECS` | Нет | `86400` (24 ч) | Продолжительность dashboard сессии в секундах. **Только первая загрузка**: редактируйте по org через [`//settings`](#operational-settings) после первого развертывания. | +| `OTP_TTL_SECS` | Нет | `600` (10 мин) | Период действия OTP-кода в секундах. **Только первая загрузка**: редактируйте по org через [`//settings`](#operational-settings) после первого развертывания. | +| `REDIS_URL` | Нет | нет | Опциональный shared cache + rate-limit backend, например `redis://redis:6379/0`. При установке сервер кеширует аутентифицированные поиски API-ключей, aggregate `/models` dashboard, список сессий и env-list facet; он также перемещает OTP-request rate limiting с Postgres COUNT на Redis INCR. Если не установлено или недостижимо, сервер работает без кеша (OTP limit возвращается к Postgres, каждый другой вызов кеша возвращается к источнику истины). См. **Redis (опциональный кеш)** ниже. | +| `CLICKHOUSE_URL` | **Да** | нет | Базовый URL ClickHouse экземпляра, например `http://clickhouse:8123`. Сервер применяет свою схему событий к этой БД при каждом запуске и отказывается загружаться, если не может достичь ClickHouse. См. **ClickHouse (требуемое аналитическое хранилище)** ниже. | +| `CLICKHOUSE_DATABASE` | Нет | `agenteye` | Имя ClickHouse database (schema). Сервер создает его при запуске, если он не существует. | +| `ORG_CH_SECRET` | Нет (single-tenant) / **Да (multi-org)** | dev default | HMAC key, из которого получается пароль per-tenant ClickHouse каждой организации. SQL-редактор и `run_query` ИИ-агента выполняются как read-only ClickHouse пользователь org, чей row policy обеспечивает tenant isolation в engine. Single-tenant развертывания хорошо загружаются на встроенный dev default; **перед provisioning второй org вы ДОЛЖНЫ установить сильное, стабильное значение**, потому что CLI `agenteye-orgctl org create` отказывает на встроенном dev default. Ротация orphans каждого org's ClickHouse пользователя до следующей загрузки re-provisions их (boot-time reconcile лечит это автоматически). Держите это в секрете и неизменяемым на replicas. Org provisioning сам по себе только для operator; см. **Organizations (multi-tenancy)** ниже. | +| `DEFAULT_ORG_NAME` | Нет | `Default` | Отображаемое имя, заполненное для встроенной org по умолчанию. **Только первая загрузка**, и только пока org все еще имеет свежее migrated generic identity, применяется при запуске, затем игнорируется. После переименования org (`agenteye-orgctl org rename`) переименование является authoritative и эта переменная окружения не имеет дальнейшего эффекта. | +| `DEFAULT_ORG_SLUG` | Нет | `default` | URL slug для встроенной org по умолчанию, dashboard path, где она живет (`//…`). Той же first-boot-only / pristine-only семантики как `DEFAULT_ORG_NAME`. Должен быть 1-40 lowercase буквы и цифры с одними internal hyphens и не [зарезервированное слово](#organizations-multi-tenancy); неправильное значение игнорируется (org сохраняет `default`). Позволяет single-tenant install представляться как например `/acme` вместо `/default` без post-deploy CLI step. | +| `RUST_LOG` | Нет | `info` | Уровень логирования (`debug`, `warn`, `error`, `agenteye_server=trace`) | +| `EVALUATOR_ENDPOINT` | Нет | нет | Базовый URL вашего evaluator service (например `http://evaluator:9000`). Если не установлено, весь evaluation pipeline - это no-op; никакие queue rows не записываются, никакие workers не работают. См. [Evaluation Suite](/ru/agenteye/evaluation-suite). | +| `EVALUATOR_TOKEN` | Нет | нет | Отправляется как `Authorization: Bearer ` к evaluator. **Должен равняться тому же значению, с которым скonfigurирован evaluator service.** Опционально только если ваш evaluator скonfigurирован без токена. | +| `EVALUATOR_WORKERS` | Нет | `2` | Concurrency: количество worker задач на экземпляр сервера, которые dispatch evaluations. Безопасно работать на multiple horizontally-scaled servers. | +| `EVALUATOR_CLAIM_BATCH` | Нет | `4` | Максимальное количество evaluations, которое один worker claims за tick. Batch dispatched **concurrently**, таким образом total concurrency на вашем evaluator endpoint - это `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH`. | +| `EVALUATOR_POLL_IDLE_SECS` | Нет | `2` | Как долго worker спит между dispatch попытками, когда ничего не в очереди. | +| `EVALUATOR_POLLING_INTERVAL_SECS` | Нет | `10` | Final fallback cadence (секунды) для `GET /evaluate/{id}` polls, когда evaluator не возвращает per-response `next_poll_secs` и не advertises `default_poll_interval_secs` от `GET /config`. | +| `EVALUATOR_REQUEST_TIMEOUT_MS` | Нет | `30000` | Per-HTTP-request timeout против evaluator (миллисекунды). | +| `EVALUATOR_MAX_ATTEMPTS` | Нет | `5` | После этого количества failed попыток evaluation записывается как terminal `error` (или `timeout`, если failures были request timeouts). | +| `EVALUATOR_CONFIG_REFRESH_SECS` | Нет | `300` (5 мин) | Как часто сервер повторно fetches `GET /config` от evaluator. | +| `EVALUATOR_MAX_POLL_DURATION_SECS` | Нет | `3600` (1 ч) | Максимальное wallclock время, в течение которого сессия может оставаться в polling queue перед тем, как AgentEye прерывает ее как `timeout`. Guards против evaluator, который возвращает `pending` навсегда. | +| `ALERT_WORKERS` | Нет | `1` | Concurrency: количество worker задач на экземпляр сервера, которые evaluate alert rules. См. [Alerts](/ru/agenteye/alerts). | +| `ALERT_CLAIM_BATCH` | Нет | `16` | Максимальное количество alerts, которое один worker claims за tick. | +| `ALERT_POLL_IDLE_SECS` | Нет | `5` | Как долго alerts worker спит, когда очередь пуста. | +| `ALERT_REQUEST_TIMEOUT_MS` | Нет | `15000` | Per-trigger evaluation timeout (ClickHouse queries + outbound channel HTTP). | +| `ALERT_MAX_ATTEMPTS` | Нет | `5` | Consecutive transient failures перед тем, как alert reschedules на его normal cadence вместо exponential backoff. | +| `AUDIT_WORKERS` | Нет | `1` | Concurrency: количество worker задач на экземпляр сервера, которые execute audits. См. [Audits](/ru/agenteye/audits). | +| `AUDIT_CLAIM_BATCH` | Нет | `1` | Максимальное количество due audits, которое один worker claims за tick. Agentic investigation - это один долгий loop, таким образом default - 1. | +| `AUDIT_POLL_IDLE_SECS` | Нет | `30` | Как долго audits worker спит, когда no audit is due. | +| `AUDIT_REQUEST_TIMEOUT_MS` | Нет | `30000` | Per-policy-query timeout против ClickHouse (миллисекунды). | +| `AUDIT_LLM_TIMEOUT_MS` | Нет | `1440000` | Timeout для agentic investigation call к AI assistant service. Full agent loop работает в течение минут; держите это ABOVE agent's own `AGENTEYE_AUDIT_TIMEOUT_MS` таким образом agent возвращает свои partial findings перед тем, как сервер give up. | +| `AUDIT_MAX_ATTEMPTS` | Нет | `5` | Consecutive transient failures перед тем, как audit reschedules на его normal cadence вместо exponential backoff. | +| `AGENTEYE_AGENT_URL` / `AGENTEYE_AGENT_TOKEN` | Нет | — | Audit's agentic investigation вызывает AI-assistant `agent` service, **reusing the same connection как assistant** — таким образом установите эти два также на **сервер** (встроенные manifests/compose делают). Оба установлены ⇒ audits run the AI investigation; либо unset ⇒ audits run **policy-only** (deterministic SQL policy pass все еще runs), независимо от per-audit `llm_enabled` flag. Agent также должен иметь LLM, скonfigurирован — см. [assistant.md](/ru/agenteye/assistant). | + +**AI assistant service — audit + sandbox settings.** Agentic investigation и его in-pod Python sandbox tuned на **agent service** (не на сервер), все на префиксе `AGENTEYE_AUDIT_*` и все опционально: + +| Переменная | По умолчанию | Значение | +|---|---|---| +| `AGENTEYE_AUDIT_MAX_STEPS` | `200` | Max agent turns на investigation. | +| `AGENTEYE_AUDIT_TIMEOUT_MS` | `1200000` | Wall-clock для одного investigation (20 мин). Должно оставаться **below** server's `AUDIT_LLM_TIMEOUT_MS`. | +| `AGENTEYE_AUDIT_MAX_CONCURRENCY` | `1` | Concurrent investigations на agent pod (отдельно от chat assistant's budget). | +| `AGENTEYE_AUDIT_SANDBOX_TIMEOUT_MS` / `_MEM_MB` / `_CPU_SECS` / `_OUTPUT_MAX_BYTES` / `_SCRIPT_MAX_BYTES` | `20000` / `768` / `10` / `64000` / `64000` | Per-script limits для bubblewrap sandbox. | + +**Sandbox platform requirement.** Audit code sandbox запускает model's Python в bubblewrap jail, который needs **unprivileged user namespaces**. Agent pod должен allow `clone()` flags — установите `seccompProfile: Unconfined` (k8s) или `security_opt: [seccomp:unconfined]` (compose) на agent. Где node kernel отключает unprivileged user namespaces (например некоторые GKE COS images), sandbox **preflight fails и auditor degrades к SQL-only автоматически** — никакой ошибки, просто `sandbox_available: false` на agent's `/health`. + +### Запуск + +Установите `DATABASE_URL` и `CLICKHOUSE_URL` в вашу окружение (сервер отказывается загружаться без ClickHouse), затем передайте их в контейнер: + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-server \ + -e DATABASE_URL="$DATABASE_URL" \ + -e CLICKHOUSE_URL="$CLICKHOUSE_URL" \ + -e ADMIN_KEY="$ADMIN_KEY" \ + -p 8080:8080 \ + ghcr.io/agenteye-enterprise/server:beta-latest +``` + +Сервер запускает миграции базы данных автоматически при запуске; никакого отдельного шага миграции не требуется. + +### Проверка здоровья + +``` +GET /health # liveness - всегда {"status":"ok"} когда процесс запущен +GET /ready # readiness - 200 когда Postgres + ClickHouse достижимы, иначе 503 +``` + +Аутентификация не требуется. Используйте `/health` для **liveness** проб и `/ready` для **readiness** / load-balancer проб. `/ready` проверяет hard dependencies, без которых сервер не может служить (Postgres + ClickHouse), поэтому сервер, который работает, но не может достичь свою базу данных, исключается из ротации и показывается как `NotReady`; Redis передается но никогда не falls readiness. На встроенных Kubernetes manifests readiness probe уже указывает на `/ready` и liveness остается на `/health`. См. [enterprise-docs/health-monitoring.md](/ru/agenteye/health-monitoring) для полной картины, включая opt-in Kubernetes-native pod-failure alerting к Slack. + +### Email magic-link URL + +OTP login emails содержат one-tap **open the dashboard** кнопку. Клик на нее приводит пользователя на `/login?token=&email=
`; dashboard обменивает эту пару на сессию и перенаправляет в приложение, без ручного повторного ввода кода. Сервер разрешает origin dashboard, используемый для построения ссылки, в три уровня: + +1. **`X-AgentEye-Dashboard-Url` header**: автоматически установлено dashboard's `/api/auth/otp/request` proxy из его собственного public origin. В same-origin deployment (сервер и dashboard share host за одним ingress, который forwards proxy headers), **никакая конфигурация не требуется**. +2. **`DASHBOARD_URL` env var**: установите это, если ваша dashboard достижима на другом origin, чем тот, который видит server's OTP request endpoint (split `api.example.com` / `app.example.com`), или если ваш ingress не propagates public host в dashboard pod (таким образом `request.nextUrl.origin` иначе разрешится на wildcard bind как `0.0.0.0:3000`). Пример: `DASHBOARD_URL=https://app.example.com`. +3. **Default**: `https://app.befailproof.ai`, используется только если ни один из выше не присутствует. + +Значение header валидируется: только `https://*` и loopback (`http://localhost*`, `http://127.0.0.1*`) origins принимаются, и wildcard bind addresses (`0.0.0.0`, `[::]`) отклоняются даже с `https://` схемой. Что-либо еще падает через tier 2. + +Установите это на running cluster с one-liner; no file, no kustomize rebuild: + +```bash +kubectl set env deployment/server -n agenteye \ + DASHBOARD_URL=https://app.example.com +``` + +Это запускает rollout; новые pods берут значение при первом запросе. Отметим, что override живет только на Deployment; последующий `kustomize build | kubectl apply` против overlay сотрет его, если вы не добавите тот же env var в вашу overlay's `server-env.yaml` patch. + +--- + +## Dashboard + +### Получение образа + +```bash +docker pull ghcr.io/agenteye-enterprise/dashboard:beta-latest +``` + +### Переменные окружения + +| Переменная | Требуется | По умолчанию | Описание | +|---|---|---|---| +| `AGENTEYE_SERVER_URL` | Да | нет | Базовый URL сервера, например `http://localhost:8080` | +| `AGENTEYE_API_KEY` | Да | нет | API key, который dashboard использует для аутентификации на сервере. Нуждается во всех разрешениях (рекомендуется admin key). | +| `AE_LOG_LEVEL` | Нет | `info` | Server-side log verbosity: `debug`, `info`, `warn`, `error`. Установите на `debug` для просмотра upstream-request/response lines и session-validation traces при диагностике проблем. | +| `AE_LOG_JSON` | Нет | auto | `1` forces JSON-per-line output; `0` forces human-readable output. Если не установлено, JSON включен автоматически, если `NODE_ENV=production`. JSON рекомендуется в production, таким образом logs parse cleanly с `jq` или log aggregator. | +| `AE_ANALYTICS_DISABLED` | Нет | нет | Установите на `1`/`true` для отключения dashboard's anonymous product-usage telemetry. См. [Telemetry & privacy](#telemetry--privacy) ниже. | +| `REDIS_URL` | Нет | нет | Опциональный shared cache backend, например `redis://redis:6379/0`. При установке, dashboard кеширует `validateSession()` результаты на replicas и shares Next.js fetch cache для latency-aggregate / env-list proxy routes. Edge-side OTP request и verify rate limits также используют Redis, если present (falling open если Redis unreachable; server-side limit - это security backstop). См. **Redis (опциональный кеш)** ниже. | +| `AGENTEYE_AGENT_URL` | Нет | нет | Базовый URL опционального AI-assistant `agent` service, например `http://agent:9100`. **Оставьте это не установленным, чтобы скрыть assistant полностью**: no assistant bubble появляется в dashboard. См. [enterprise-docs/assistant.md](/ru/agenteye/assistant). | +| `AGENTEYE_AGENT_TOKEN` | Нет | нет | Shared secret, который dashboard представляет `agent` service. Должен соответствовать `AGENTEYE_AGENT_TOKEN`, скonfigurирован на agent. См. [enterprise-docs/assistant.md](/ru/agenteye/assistant). | + +### Запуск + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-dashboard \ + -e AGENTEYE_SERVER_URL="http://your-server-host:8080" \ + -e AGENTEYE_API_KEY="$ADMIN_KEY" \ + -p 3000:3000 \ + ghcr.io/agenteye-enterprise/dashboard:beta-latest +``` + +### Telemetry & privacy + +Dashboard отправляет **anonymous product-usage analytics** в analytics service Exosphere (PostHog): какие dashboard pages просмотрены и handful UI actions, такие как creating API key или re-evaluating session. Этот usage signal информирует о приоритизации features. + +- **Никакие agent, session, или event data никогда не покидают вашу инфраструктуру.** Только dashboard UI usage сообщается. Page URLs stripped идентификаторов перед отправкой, и operators идентифицированы только opaque internal id, никогда по email. +- Telemetry **включен по умолчанию**. Чтобы отключить его полностью, установите `AE_ANALYTICS_DISABLED=1` на dashboard контейнере и перезагрузитесь. +- Analytics отправляются на dashboard's собственный `/ingest` path, который dashboard reverse-proxies к PostHog (`https://us.i.posthog.com`). Keeping requests first-party означает, что browser ad-blockers не drops их. Dashboard контейнер needs outbound access к PostHog; если это заблокировано, telemetry silently делает ничего и dashboard unaffected. + +--- + +## AI Assistant (опционально) + +In-dashboard AI assistant позволяет вашей team задавать вопросы о их agent data на plain language (summarising sessions, drafting SQL для `/queries` редактора, и turning saved queries в dashboard tiles) не покидая dashboard. Он запускается как отдельный internal `agent` контейнер (на Claude Agent SDK), который может достигать только dashboard, и остается **отключенным, пока вы не сконфигурируете LLM endpoint**. + +Чтобы включить его, вы устанавливаете на `agent` service LLM connection (**Portkey** через `PORTKEY_API_KEY` + model-catalog slug `AGENTEYE_AGENT_MODEL=@/`, direct Anthropic через `ANTHROPIC_API_KEY`, другой gateway через `ANTHROPIC_BASE_URL`, или Bedrock/Vertex), **dedicate** data key, и shared `AGENTEYE_AGENT_TOKEN`, совпадающий с dashboard. Dashboard users дополнительно нуждаются в разрешении `agent:use`. + +Для assistant's data key вы не mint ничего вручную: выберите random secret, установите его как `AGENTEYE_API_KEY` на `agent` **и** как `AGENT_API_KEY` на `server`, и server seeds его при startup с fixed permission set. Его data access - это read-only (`events:read`, `evaluations:read`, `dashboards:read`, `queries:read`), и он дополнительно держит approval-gated authoring scopes (`dashboards:write`, `queries:write`, `queries:run`), таким образом он может draft и validate saved queries и build dashboard tiles от user's имени; весь SQL все еще runs через org's read-only ClickHouse role, таким образом это widens что assistant может author, не какие data он может reach. Scopes fixed в коде и не могут быть widened конфигурацией. Тот key protected; он не может быть disabled или regenerated через API, только ротирован путем изменения значения и перезагрузки. Никогда не переиспользуйте admin/dashboard key для этого. + +Полная setup, полная переменная окружения reference, telemetry options, и security model в **[enterprise-docs/assistant.md](/ru/agenteye/assistant)**. + +--- + +## ClickHouse (требуемое аналитическое хранилище) + +ClickHouse держит ваши dashboards responsive при high event volumes и позволяет `/queries` SQL редактору join across events, evaluations, и sessions в одном store. Это требуемый canonical store для каждого ingested события, каждого terminal evaluation outcome, и derived per-session aggregates. PostgreSQL holds relational / mutable-state tables (api_keys, users, otp_codes, evaluation_jobs, dashboards, saved_queries); analytical surface lives в ClickHouse, таким образом dashboard's rollups и ваши собственные SQL queries могут scan и join его natively, без cross-database round-trips. Сервер отказывается загружаться без `CLICKHOUSE_URL`. + +### Schema + +Три ClickHouse объекта создаются при startup сервера, все idempotent (`CREATE IF NOT EXISTS`): + +- **`agenteye.events`**: `ReplacingMergeTree(ingested_at)`, разделено по `toYYYYMM(ts)`, отсортировано по `(session_id, ts, dedup_key)`. Duplicate inserts (collector retries) collapse в одну row при merge time; сервер вычисляет deterministic SHA-256 `dedup_key` для каждого события, таким образом retries безопасны. +- **`agenteye.evaluations`**: `ReplacingMergeTree(ingested_at)`, разделено по `toYYYYMM(finished_at)`, отсортировано по `(session_id, finished_at, dedup_key)`. Написано один раз на terminal evaluation outcome от evaluator pipeline. Same dedup-key model как `events`. +- **`agenteye.agent_sessions`**: a **VIEW** над `agenteye.events`, не физическая table. Каждая колонка derived (`started_at = min(ts)`, `last_event_at = max(ts)`, `ended_at = max(if event_type='agent_end', ts, NULL)`, `event_count = count()`, и т.д.). No per-event upsert и никакой отдельный backfill; view auto-reflects что бы ни было в `events`. + +Для backwards-compat с saved queries, которые reference `analytics.evaluations` / `analytics.sessions`, сервер также создает ClickHouse database `analytics` с views над `agenteye.*` таблицами; `analytics.events`, `analytics.evaluations`, `analytics.agent_sessions`, `analytics.sessions` все resolve правильно. + +### Configuration + +Встроенный docker-compose и `deploy/base/clickhouse/` поставляют ClickHouse service, tuned для AgentEye's workload: + +- 2 GiB requested / 4 GiB limit memory в shipped base overlay (sized для fit small POC/staging nodes); production customers должны overlay up — recommended floor - 2c / 4Gi request, 6c / 8Gi limit. `max_server_memory_usage_to_ram_ratio=0.9` +- 5 GiB mark cache + 8 GiB uncompressed cache +- `background_pool_size=16`, `background_merges_mutations_concurrency_ratio=2` +- MergeTree: `parts_to_throw_insert=3000`, `parts_to_delay_insert=1500`, `non_replicated_deduplication_window=1000` +- `local_io_method=auto` (io_uring на supported kernels) +- `fsync_metadata=0`: приемлемо благодаря at-least-once ingest + ReplacingMergeTree dedup +- `query_log` включен с 30-day TTL; `query_thread_log` удален (expensive при high QPS) +- `max_execution_time=30` для user-side queries +- 100 GiB PVC в StatefulSet template (customer overlays SHOULD override к fast SSD storage class для production) + +### Backups + +Ваш full dataset captured nightly в одном restorable archive, таким образом cluster или storage loss recoverable. ClickHouse backed up автоматически daily `agenteye-backup` CronJob, который dumps обе PostgreSQL и ClickHouse в одном pass. ClickHouse - read over его HTTP API: `agenteye.events` и `agenteye.evaluations` dumped в ClickHouse-native format (views и row policies recreated сервером при startup, таким образом table data - это complete picture) и bundled с Postgres dump в одном compressed archive uploaded к вашему object storage. + +Destination bucket и cloud credentials скonfigured per overlay. См. **Backups** section of [enterprise-docs/kubernetes-deployment.md](/ru/agenteye/kubernetes-deployment) для upload configuration и restore steps. + +--- + +## Redis (опциональный кеш) + +Redis - это **опциональный** shared cache + rate-limit backend, используемый сервером и dashboard. С Redis deployed и `REDIS_URL` установленным на обе services: + +- **Server** кеширует authenticated API-key lookups, `/events/environments` + `/evaluations/environments` списки, `/events/latency_aggregate` rollup (heaviest query, который dashboard polls), `/sessions` list, и переключает OTP-request rate limiting с Postgres `COUNT(*)` на Redis `INCR + EXPIRE`. +- **Dashboard** кеширует `validateSession()` результаты, таким образом 10-20 authed API calls типичный page load issues все share одну upstream session check. Он также rate-limits OTP-request и OTP-verify в dashboard edge. + +**Обе services gracefully degrade, если Redis unreachable.** Каждый cache call возвращает `Err` в bounded timeout и caller falls back к source of truth (Postgres на сервере, upstream Rust server на dashboard). OTP rate limiting falls back к Postgres `COUNT(*)` path на сервере (security property сохраняется); dashboard's edge OTP limit fails open пока server-side limit все еще holds. Redis being down degrades latency, не correctness. + +### Configuration + +Docker-compose bundle уже includes Redis service и wires `REDIS_URL=redis://redis:6379/0` в сервер и dashboard. Чтобы использовать external Redis, установите `REDIS_URL` на вашу endpoint и удалите `redis` service из compose файла. + +### Memory + persistence + +Встроенный Redis image запускается с `--appendonly yes --appendfsync everysec --maxmemory 256mb --maxmemory-policy allkeys-lru`. AOF persistence означает, что cache survives container restarts; `everysec` - это правильный durability/perf баланс, потому что потеря последней секунды cache writes безвредна. LRU eviction caps memory growth. + +### When NOT to deploy Redis + +- Single-instance dev/QA. In-process caches на сервере alone deliver большую часть per-replica benefit; Redis adds cross-replica sharing, которую single-instance setups не нуждаются. +- Air-gapped installs, где operational cost запуска один более service outweighs latency win. + +--- + +## Docker Compose (рекомендуется) + +`docker-compose.yml` доступен в `agenteye-enterprise/releases` repo. Он brings up Postgres, ClickHouse, Redis, сервер, и dashboard с одной командой. + +```bash +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download \ + --repo agenteye-enterprise/releases \ + --pattern 'docker-compose.yml' \ + --dir ./agenteye +cd agenteye +``` + +**Override defaults via `.env`:** + +``` +# Use URL-safe passwords (no /, +, or = characters). +# Generate with: openssl rand -hex 24 +POSTGRES_PASSWORD=your-db-password +ADMIN_KEY=your-admin-secret + +# Dashboard authentication +ADMIN_EMAIL=admin@yourcompany.com +ALLOWED_EMAILS=*@yourcompany.com + +# SMTP for OTP emails (omit to log OTP codes to stdout) +# SMTP_HOST=smtp.yourprovider.com +# SMTP_PORT=587 +# SMTP_USERNAME=your-smtp-user +# SMTP_PASSWORD=your-smtp-password +# SMTP_FROM=noreply@yourcompany.com + +RUST_LOG=info +``` + +```bash +docker compose up -d +``` + +**Stop (keeps data volume):** + +```bash +docker compose down +``` + +**Stop and wipe all data:** + +```bash +docker compose down -v +``` + +--- + +## Operational settings + +Небольшой набор operational knobs, которые когда-то были pinned env vars, теперь editable per organization из dashboard's **`//settings`** страницы; каждая org скonfigурирует свой собственный. Changes take effect в течение секунд, без restart и без redeploy. + +| Setting | Bootstrap env var | Что он контролирует | +|---|---|---| +| Allowed sign-ins | `ALLOWED_EMAILS` | Emails (или `*@domain.com` wildcards) permitted для receive OTP и be added как users | +| Default user permissions | `DEFAULT_USER_PERMISSIONS` | Comma-separated permission tokens preselected когда admin opens **+ new user**. Каждый token должен быть один из strings listed under [API key permissions](/ru/agenteye/api-keys). Defaults к `standard` preset: read-only access плюс everyday on-call actions (trigger re-evaluations, run queries, ack incidents, use the assistant). | +| Session lifetime | `SESSION_TTL_SECS` | Как долго dashboard login остается valid перед re-auth. Dashboard re-checks upstream session каждые 5 секунд, таким образом permission update на `//users` takes effect на affected user's next request, без relogin. | +| One-time-code lifetime | `OTP_TTL_SECS` | Как долго OTP / magic-link остается usable | +| Alert notification channels | `ALERTS_ENABLED_CHANNELS` | Comma-separated list channel kinds, которые alert dispatcher allowed использовать: `email`, `slack`, `webhook`. Per-alert configuration все еще authored на `//alerts/`, но dispatcher filters каждый outbound delivery через этот set; channel disabled здесь short-circuits с `skipped_disabled` audit row. `dashboard` channel (local audit insert) всегда allowed. Defaults ко всем трем on. | + +### How the bootstrap works + +Settings хранятся per organization в `org_settings`. На первый boot, сервер seeds default org's missing rows из matching env var (или sensible default, если env var не установлен). После этого, **stored value - это source of truth и env var игнорируется**; изменение env var при позднем restart не будет affect live org's value, и additional orgs start из defaults и скonfigурируют их собственный. + +Это означает: + +- Для fresh deploy, установите env vars как shown выше и default org читает их на first boot. +- Чтобы изменить value позже, log в dashboard и edit его under `//settings`. Change применяется в течение секунд на all server replicas; restart не нужен. +- Startup log line записывает что got seeded vs. что было уже present, таким образом вы можете confirm bootstrap took effect: + + ```text + INFO settings bootstrap: seeded default-org row key=allowed_sign_ins env_var=ALLOWED_EMAILS seeded_from_env=true + ``` + +#### Sign-in semantics across organizations + +Session и OTP глобальны пользователю, не к одной org, таким образом два rules reconcile per-org settings в sign-in time: + +- **Session / OTP lifetime**: strictest (shortest) lifetime среди orgs пользователь belongs к wins. +- **Allowed sign-ins**: gate ORs каждую org's allowlist вместе с org membership: пользователь может request OTP если любая org's allowlist admits их email **или** они уже member любой org. + +### Permissions + +Access к `//settings` странице gated двумя permissions: + +- `settings:read`: see page и current values. +- `settings:write`: save changes. + +Bootstrap admin user (seeded из `ADMIN_EMAIL`) gets оба автоматически вместе с каждым другим permission. Grant их другим users из `//users` как needed. + +--- + +## Organizations (multi-tenancy) + +Single deployment может serve multiple isolated **organizations** (tenants); каждый row данных belongs к ровно одной org и isolation enforced в database engine. Single-tenant install нуждается ничего здесь; все данные lives в built-in `default` org. (Вы можете дать той org friendlier name и URL slug, таким образом это lives в например `/acme` вместо `/default`, путем установки `DEFAULT_ORG_NAME` / `DEFAULT_ORG_SLUG` перед first boot, или путем переименования его anytime с `agenteye-orgctl org rename`.) + +**Tenant provisioning - это operator-only.** Organizations и их memberships created и managed с **`agenteye-orgctl`** CLI, который ships **inside сервер image** (alongside `agenteye-server`) и runs **inside существующий server pod**; there is **no separate pod/Job, no HTTP API, и no dashboard button**. Это reuses server's `DATABASE_URL`, `CLICKHOUSE_URL`, и `ORG_CH_SECRET`. + +```bash +# Docker Compose - exec в running server service: +docker compose exec server agenteye-orgctl org create --slug acme --name "Acme Corp" +docker compose exec server agenteye-orgctl member add --org acme --email alice@acme.example --set admin + +# Kubernetes - exec в running server Deployment: +kubectl -n agenteye exec deploy/server -- agenteye-orgctl org list +``` + +Available verbs: `org create | list | rename | delete | purge` и `member add | list | update | remove`, с builtin permission sets `admin`, `standard`, и `read-only`. Added members get OTP на first dashboard login. + +**Перед созданием second org:** установите strong, stable `ORG_CH_SECRET` (`org create` command отказывает на built-in dev default) и ensure Postgres - **15+**. **Unchanged:** per-org API keys все еще minted в dashboard/API по org members; только org + member lifecycle moved к CLI. Full command reference и worked example: **[enterprise-docs/tenant-management.md](/ru/agenteye/tenant-management)**. + +--- + +## Context-window fill + +Каждый `model_response` event показывает **context-fill pill** — input плюс output tokens как процент той model's context window. Bands - `healthy` (0–24%), `watch` (25–49%), `compacting` (50–74%), и `reset context` (75–100%). AgentEye разрешает common model IDs автоматически, таким образом никакая initial configuration не требуется. + +Каждый model, который organization отправляет, появляется under **Settings → model context windows**. Users с `settings:write` могут override его window или add private/proxy model (0–1,000,000 tokens); `0` означает уnknown и suppresses pill. Changes apply к newly ingested events. Users с `settings:read` могут view list. + +New events get fill из момента вы upgrade. Чтобы также populate **historical** events (и per-model list) для existing deployment, run one-off backfill — он ships inside сервер image (как `agenteye-orgctl`) и runs в existing server pod: + +```bash +# preview (prints per-org mutation, changes nothing): +kubectl -n agenteye exec deploy/server -- agenteye-backfill-context-window --dry-run +# apply: +kubectl -n agenteye exec deploy/server -- agenteye-backfill-context-window +# docker compose: +docker compose exec server agenteye-backfill-context-window +``` + +Это idempotent (safe к re-run) и re-uses `DATABASE_URL` / `CLICKHOUSE_URL` / `REDIS_URL` из pod. Re-run это после editing model windows если вы want existing events recomputed. + +--- + +## Production Considerations + +- **Postgres**: Используйте managed Postgres service или dedicated instance с regular backups. `DATABASE_URL` поддерживает все standard libpq parameters, включая `sslmode=require` для encrypted connections. +- **TLS**: Put сервер и dashboard за reverse proxy (nginx, Caddy, Traefik), который terminates TLS. +- **Firewall**: Server port (default 8080) должен быть reachable только из collector machines и dashboard host, не public internet. +- **Admin key**: Установите `ADMIN_KEY` на strong random secret. После bootstrapping, create dedicated scoped keys для collectors и dashboard вместо использования admin key везде. +- **Image tags**: Pin к version в вашу release manifests (например `server:v0.0.1-beta.48`) в production вместо floating tag избежать unintended upgrades. Current beta builds publish под `beta-latest`; `latest` assigned только к stable releases. +- **Health monitoring**: На Kubernetes readiness probe использует `/ready` (Postgres + ClickHouse reachability), пока liveness остается на `/health`. Для fleet-wide "is AgentEye itself up?" alerting к Slack, enable opt-in Robusta add-on; см. [enterprise-docs/health-monitoring.md](/ru/agenteye/health-monitoring). + +--- + +## Доступные теги образов + +| Tag | Описание | +|-----|-------------| +| `latest` | Последний stable release | +| `beta-latest` | Последний pre-release (beta) | +| `v` | Pinned version, например `v0.0.1-beta.48` (рекомендуется для production) | \ No newline at end of file diff --git a/docs/ru/agenteye/evaluation-suite.mdx b/docs/ru/agenteye/evaluation-suite.mdx new file mode 100644 index 00000000..4bc1c6d1 --- /dev/null +++ b/docs/ru/agenteye/evaluation-suite.mdx @@ -0,0 +1,357 @@ +--- +title: "Evaluation Suite" +description: "Документация AgentEye Evaluation Suite." +--- + + +AgentEye оценивает завершённые сеансы агента, отправляя полную стенограмму событий с помощью POST-запроса на **единственный сервис оценки, принадлежащий клиенту**. Оценщик возвращает оценки либо сразу, либо передав `job_id` для опроса AgentEye. Результаты сохраняются и отображаются на панели управления. + +Это руководство охватывает: + +1. Как определяется завершение сеанса. +2. HTTP-контракт, который должен реализовать оценщик. +3. Конфигурирование сервера AgentEye. +4. Просмотр результатов. +5. Устранение неполадок. + +Для вспомогательного пакета Python, который реализует контракт за вас, см. +[пакет `agenteye-evaluator` на PyPI](https://pypi.org/project/agenteye-evaluator/). + +--- + +## Как это работает + +```text +ingest /events ──▶ AgentEye ──── POST /evaluate ────▶ Evaluator service + (agent_end) server ◀──── done | pending ──── + │ + │ GET /evaluate/{job_id} ─────▶ + │ ◀──── done ────────────── + ▼ + evaluations (terminal results) +``` + +Когда SDK AgentEye излучает событие `agent_end` для сеанса, сервер планирует оценку. Затем он отправляет POST-запрос с полной стенограммой событий на ваш сервис оценки, который может: + +- **Вернуть результат сразу** с `{"status":"done", "scores":{...}, "reasoning":{...}, "summary":"..."}`. Результат добавляется на временную шкалу оценки сеанса. Поля `reasoning` и `summary` являются необязательными. +- **Отложить** с `{"status":"pending", "job_id":"abc-123"}`. AgentEye затем вызывает `GET {EVALUATOR_ENDPOINT}/evaluate/abc-123` до тех пор, пока ваш оценщик не вернёт `{"status":"done", ...}` или `{"status":"error", "error":"..."}`. + + Частота опроса зависит от задачи: ответ `pending` может включать `next_poll_secs` для переопределения; в противном случае AgentEye использует значение `default_poll_interval_secs` из `GET /config`; в противном случае сервер возвращается к `EVALUATOR_POLLING_INTERVAL_SECS` (по умолчанию 10s). Все значения ограничены диапазоном [1s, 1h]. + +Сеансы, которые никогда не излучают `agent_end` (например, процесс агента, который упал), также могут быть обработаны: `GET /config` оценщика может вернуть `{"inactivity_timeout_secs": 1800}`, и AgentEye будет оценивать любой сеанс, простаивающий так долго. Установите это поле в `null` или опустите его, чтобы отключить этот резервный вариант. + +Конвейер полностью неоперативен, когда `EVALUATOR_ENDPOINT` не установлен. + +Сеанс может накапливать **несколько терминальных оценок со временем**: каждое событие `agent_end` (и каждый ручной переоценка с панели управления) добавляет новую строку оценки. Это рекомендуемый способ оценить возобновленный диалог: пользователь завершает агента, возвращается позже, отправляет больше событий, снова завершает агента, и выполняется вторая оценка для полной обновлённой стенограммы. На панели управления показывается последняя оценка как основной результат, а предыдущие оценки — как сворачиваемая временная шкала. Пока одна оценка выполняется для сеанса, дополнительные события `agent_end` для этого сеанса игнорируются; следующее после завершения текущей оценки поставит в очередь новую оценку как обычно. + +Резервный вариант неактивности повторно включается и на возобновлённых сеансах: если новые события поступают после предыдущей терминальной оценки и сеанс затем переходит в режим ожидания свыше `inactivity_timeout_secs`, новая оценка ставится в очередь. + +Временные сбои (5xx, 429, таймауты, ошибки сети) повторяются с экспоненциальной задержкой до `EVALUATOR_MAX_ATTEMPTS`; ответы 4xx являются терминальными. AgentEye можно безопасно запускать с несколькими горизонтально масштабируемыми экземплярами серверов; работа распределена так, чтобы один и тот же сеанс никогда не отправлялся дважды одновременно. + +--- + +## HTTP-контракт + +Все аутентифицированные маршруты используют **аутентификацию с маркером-носителем**. Одно и то же значение должно быть настроено на обеих сторонах: + +- Сервер AgentEye: переменная окружения `EVALUATOR_TOKEN` +- Сервис оценки: настроено так же (SDK `agenteye-evaluator` по соглашению читает `EVALUATOR_TOKEN`) + +Если `EVALUATOR_TOKEN` не установлен, сервер не отправляет заголовок `Authorization`; оценщик может затем принимать анонимные запросы, что приемлемо для внутренней сети, но не рекомендуется в открытом интернете. + +### Маршруты, которые должен обслуживать оценщик + +| Маршрут | Тело / параметры | Ответ | +|---|---|---| +| `GET /health` | нет | `{"status":"ok"}` (открыто, без аутентификации) | +| `GET /config` | нет | `{"inactivity_timeout_secs": \| null, "default_poll_interval_secs": \| опущено}` | +| `POST /evaluate` | JSON `EvalRequest` | `{"status":"done", ...}` или `{"status":"pending", "job_id":"..."}` | +| `GET /evaluate/{id}` | нет | такая же форма ответа как `/evaluate` | + +### Тело запроса `EvalRequest`, отправляемое сервером + +```json +{ + "schema_version": "1", + "session_id": "session-abc123", + "agent_id": "planner", + "environment": "production", + "started_at": "2026-05-10T12:00:00Z", + "ended_at": "2026-05-10T12:05:00Z", + "events": [ + { "id": 1234, "ts": "...", "event_type": "agent_start", "payload": { ... } }, + ... + ] +} +``` + +### Формы ответа + +**Синхронно (выполнено):** + +```json +{ + "status": "done", + "scores": { "helpfulness": 0.85, "tool_efficiency": 0.6 }, + "reasoning": { + "helpfulness": "answered the question directly with citations", + "tool_efficiency": "called list_files three times when one would have done" + }, + "summary": "strong answer quality, weak tool selection" +} +``` + +`reasoning` (карта обоснования для каждой оценки) и `summary` (общее однопараграфное описание) являются необязательными. Ключи в `reasoning` должны соответствовать ключам в `scores`; панель управления отображает каждую запись в строке под полосой оценки. Более старые оценщики, которые возвращают только `scores`, продолжают работать без изменений; `reasoning` и `summary` просто отображаются как null, и соответствующие элементы интерфейса опускаются. + +**Асинхронно (отложено):** + +```json +{ "status": "pending", "job_id": "abc-123", "next_poll_secs": 30 } +``` + +`next_poll_secs` является необязательным; если опущено, сервер возвращается к `default_poll_interval_secs` оценщика из `/config`, затем к своей переменной окружения `EVALUATOR_POLLING_INTERVAL_SECS`. + +**Терминальная ошибка на стороне оценщика:** + +```json +{ "status": "error", "error": "model service unavailable" } +``` + +Сервер обрабатывает любое другое тело 2xx как ошибку протокола и записывает терминальную `error` для сеанса. + +--- + +## Написание оценщика с помощью SDK + +Пакет `agenteye-evaluator` Python предоставляет типизированную обёртку FastAPI, которая реализует HTTP-контракт выше. Установите его из PyPI: + +```bash +pip install agenteye-evaluator +``` + +Минимальный жизнеспособный оценщик: + +```python +import os +from agenteye_evaluator import Evaluator, EvalRequest, EvalResponse + +app = Evaluator(token=os.environ["EVALUATOR_TOKEN"]) + +@app.evaluator +def run(req: EvalRequest) -> EvalResponse: + # Inspect req.events (the full session transcript) and return scores. + tool_calls = sum(1 for e in req.events if e.event_type == "tool_use") + return EvalResponse( + scores={"tool_calls": float(tool_calls)}, + reasoning={"tool_calls": f"{tool_calls} tool invocations in the transcript"}, + summary="tight tool loop" if tool_calls < 5 else "agent looped on tools", + ) +``` + +Экземпляр `app` вызывается ASGI, поэтому `uvicorn module:app` запускает его. + +Для оценщиков, которым нужно отложить дорогостоящую работу, возвращайте `JobPending` и зарегистрируйте обработчик `@app.job_lookup`; сервер AgentEye опрашивает `GET /evaluate/{job_id}` до тех пор, пока вы не вернёте терминальный статус или не истечёт лимит `EVALUATOR_MAX_POLL_DURATION_SECS` (по умолчанию 1 ч). + +Полная ссылка API, асинхронный шаблон и схема событий: README `agenteye-evaluator` поставляется внутри каждого архива выпуска на [странице выпусков agenteye-enterprise](https://github.com/agenteye-enterprise/releases), или вы можете прочитать его на странице пакета в PyPI. + +--- + +## Запуск оценщика на Kubernetes + +Оценщик — это **ваш сервис**: AgentEye не поставляет контейнер оценщика по умолчанию. Выпуск включает ссылочные манифесты Kubernetes в `deploy/examples/evaluator/`, которые вы можете применить как есть после замены вашего образа и общего маркера-носителя. + +### 1. Контейнеризируйте ваш оценщик + +Минимальный Dockerfile для вашего оценщика: + +```dockerfile +FROM python:3.12-slim +WORKDIR /app +RUN pip install --no-cache-dir agenteye-evaluator uvicorn +COPY my_evaluator.py . +RUN useradd --uid 10001 --create-home --shell /usr/sbin/nologin evaluator \ + && chown -R evaluator:evaluator /app +USER evaluator +EXPOSE 9000 +CMD ["uvicorn", "my_evaluator:app", "--host", "0.0.0.0", "--port", "9000"] +``` + +`runAsNonRoot` (UID 10001) сохраняет совместимость контейнера с профилями ограниченной безопасности Pod. + +### 2. Создайте общий маркер-носитель + +```bash +kubectl -n agenteye create secret generic evaluator-token \ + --from-literal=token="$(openssl rand -hex 32)" +``` + +Используйте то же значение как `EVALUATOR_TOKEN` на сервере AgentEye. Сервер отправляет `Authorization: Bearer ` при каждом запросе; SDK использует `hmac.compare_digest` для проверки в постоянное время и отклоняет несоответствия с HTTP 401. + +### 3. Примените примеры манифестов + +```bash +# Edit deploy/examples/evaluator/deployment.yaml first to point +# `image:` at your registry, then: +kubectl apply -k deploy/examples/evaluator/ +``` + +Пример включает: + +- Развёртывание с 2 репликами с `runAsNonRoot`, файловой системой только для чтения, всеми возможностями отключены, проверки живости и готовности на `/health` +- ClusterIP сервис на порту 9000 +- Шаблон `secret.example.yaml` (намеренно исключён из Kustomization; создайте реальный секрет вне пределов, чтобы ни один маркер не попал в git) + +### 4. Подключите AgentEye к нему + +На сервере AgentEye установите: + +```bash +EVALUATOR_ENDPOINT=http://evaluator:9000 +EVALUATOR_TOKEN= +``` + +Сервер распределяет `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH` одновременных запросов по всем подам оценщика (по умолчанию: `2 × 4 = 8`). Масштабируйте `replicas` и лимиты ресурсов на поде в соответствии с этими серверными переключателями. + +### Проверка + +```bash +kubectl -n agenteye port-forward svc/evaluator 9000:9000 +curl -s http://localhost:9000/health # → {"status":"ok"} +``` + +После полного запуска агента `GET /evaluations` на сервере AgentEye должен вернуть строку со статусом `"done"` и оценками, которые производит ваш оценщик. + +--- + +## Конфигурирование сервера AgentEye + +Установите в процессе сервера: + +| Переменная окружения | Значение | +|---|---| +| `EVALUATOR_ENDPOINT` | Базовый URL вашего оценщика (`http://evaluator:9000`). Не установлено = конвейер отключён. | +| `EVALUATOR_TOKEN` | Маркер-носитель. Должен соответствовать значению, которое настроено на сервисе оценщика. | +| `EVALUATOR_WORKERS` | Рабочие задачи на экземпляр сервера (по умолчанию 2). | +| `EVALUATOR_CLAIM_BATCH` | Строки, запрашиваемые за тик работника (по умолчанию 4). Пакеты обрабатываются **параллельно**; фактическое параллелизм на вашей конечной точке оценщика — это `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH`. | +| `EVALUATOR_POLL_IDLE_SECS` | Как долго работник спит между попытками отправки, когда оценка не назначена (по умолчанию 2s). | +| `EVALUATOR_POLLING_INTERVAL_SECS` | Окончательный резервный вариант для частоты `GET /evaluate/{id}` когда ни per-response `next_poll_secs`, ни `default_poll_interval_secs` оценщика не установлены (по умолчанию 10s). | +| `EVALUATOR_REQUEST_TIMEOUT_MS` | Таймаут для каждого запроса (по умолчанию 30000). | +| `EVALUATOR_MAX_ATTEMPTS` | После этого количества временных сбоев результат записывается как терминальная `error` (по умолчанию 5). | +| `EVALUATOR_CONFIG_REFRESH_SECS` | Частота `GET /config` (по умолчанию 300). | +| `EVALUATOR_MAX_POLL_DURATION_SECS` | Максимальное реальное время, в течение которого сеанс может оставаться в очереди опроса, прежде чем он будет завершён как `timeout` (по умолчанию 3600s). Защищает от оценщика, который продолжает возвращать `pending` навечно. | + +Чтобы включить автоматическое оценивание для всего экземпляра, подготовьте секрет `agenteye-evaluator` с обоими установленными ключами. В поставляемых манифестах Kubernetes сервер читает `EVALUATOR_ENDPOINT` и `EVALUATOR_TOKEN` из этого необязательного секрета. Создайте его через стандартный процесс управления секретами вашей организации, затем перезагрузите развёртывание сервера, чтобы подхватить изменение. + +Переключатели настройки выше по умолчанию не подключены; выставьте соответствующие переменные окружения на контейнере сервера в манифесте развёртывания, если вам нужно переопределить значения по умолчанию. + +См. [deployment.md](/ru/agenteye/deployment) для полной таблицы переменных окружения. + +--- + +## Ссылка API + +| Метод | Путь | Требуемое разрешение | Назначение | +|---|---|---|---| +| `GET` | `/evaluations` | `evaluations:read` | Запросить терминальные результаты. Поддерживает `session_id`, `agent_id`, `environment`, `status` (`done`/`error`/`timeout`), `ts_from`, `ts_to`, `cursor`, `limit`, `score_filters`, `latest_per_session`. `limit` по умолчанию 50 и ограничен 200 (обратите внимание, это отличается от `/events`, который ограничен 1000). `environment` принимает список, разделённый запятыми (например, `environment=prod,staging`); отдельные значения по-прежнему работают. С `latest_per_session=true` ответ содержит не более одной строки на `session_id` (самой свежей по `completed_at`), используемой на странице списка сеансов для свёртывания временной шкалы оценки сеанса в его текущий заголовок. По умолчанию false (возвращает полную историю). | +| `GET` | `/evaluations/aggregate` | `evaluations:read` | Свёрнутое здоровье оценок для отфильтрованного среза: общее количество, разбивка done/error/timeout, статистика по ключам оценки (count/avg/min/max/p50 по произвольным ключам `scores`), и временная шкала по периодам. Принимает **те же параметры фильтра как `/evaluations`** плюс `featured_keys` (CSV ключей оценки для тренда) и `latest_per_session`. Питает функцию Dashboards; метрики точны над целым совпадающим набором, не выбираются. | +| `GET` | `/evaluations/environments` | `evaluations:read` | Отличные значения окружения из таблицы `evaluations`. Используется для заполнения выпадающих меню фильтра, ограниченных данными, доступными для чтения оценок. | +| `GET` | `/evaluation-jobs` | `evaluations:read` | Видимость в полёте оценок. Фильтр по `status` (`pending`/`polling`). | +| `GET` | `/events` | `events:read` | Поток необработанных событий сеанса. Поддерживает `session_id`, `agent_id`, `event_type` (CSV), `environment` (CSV), `ts_from`, `ts_to`, `cursor`, `limit` и `order`. `order` — это `desc` (новое в первую очередь, по умолчанию) или `asc` (старое в первую очередь); неправильное значение возвращается к `desc`. Постраничное переключение курсора через `next_cursor` ответа (id события): передайте его как `cursor` для получения следующей страницы; с `asc` следующая страница — события после этого id, с `desc` события до него. `limit` по умолчанию 50 и ограничен 1000. | +| `GET` | `/sessions/:session_id/export` | `events:read` | Возвращает точное тело JSON, которое оценщик получит для этого сеанса, поданное как загружаемое вложение с именем `session-.json`. Полезно для повторного воспроизведения сеансов производства через `agenteye-evaluator` для автономного тестирования. Байты идентичны тому, что отправляет конвейер оценщика. | +| `POST` | `/sessions/:session_id/re-evaluate` | `evaluations:trigger` | Поставить в очередь свежую оценку для сеанса; работает независимо от того, существует ли предыдущая оценка. Новый результат **добавляется** на временную шкалу оценки сеанса вместо перезаписи предыдущей, поэтому предыдущие оценки остаются видимыми как история. Возвращает `202` при постановке в очередь, `404` для неизвестного сеанса, `409` если оценка уже выполняется. Используйте это после развёртывания нового оценщика или для сеансов, которые никогда не излучали `agent_end`. | + +### Фильтрация по диапазону оценок: `score_filters` + +`GET /evaluations` принимает необязательный параметр `score_filters`, который сужает результаты по числовым значениям внутри объекта `scores`. Параметр — это список, разделённый запятыми, записей `key:min..max`; либо граница может быть опущена. Несколько записей объединяются с логическим И. Строки, где названный ключ отсутствует или не является числовым, исключаются. Запрос может содержать не более 20 записей фильтра; превышение возвращает HTTP 400. + +Примеры: +```text +# helpfulness в [0.5, 0.8] +GET /evaluations?score_filters=helpfulness:0.5..0.8 + +# tool_efficiency не более 0.3 (без нижней границы) +GET /evaluations?score_filters=tool_efficiency:..0.3 + +# helpfulness >= 0.5 AND factuality >= 0.9 +GET /evaluations?score_filters=helpfulness:0.5..,factuality:0.9.. +``` + +Каждый объект ответа `/evaluations` имеет эти поля: + +| Поле | Тип | Примечания | +|---|---|---| +| `evaluation_id` | string (UUID) | Канонический идентификатор для этой терминальной оценки. Каждая терминальная оценка получает новый UUID; один сеанс может содержать несколько. | +| `id` | string (UUID) | Обратная совместимость псевдоним, несущий то же значение как `evaluation_id`. | +| `session_id` | string | Сеанс, против которого выполнялась оценка. Сеанс может иметь несколько оценок на временной шкале. | +| `agent_id` | string | Идентифицирует агента, который произвёл сеанс. | +| `environment` | string | Метка окружения, скопированная из сеанса. | +| `status` | enum | Один из `"done"`, `"error"`, `"timeout"`. | +| `scores` | object \| null | Оценки, возвращённые вашим оценщиком. | +| `reasoning` | object \| null | Необязательная карта обоснования для каждой оценки, возвращённая вашим оценщиком. Ключи обычно отражают те, что в `scores`. На панели управления каждая запись отображается под полосой оценки. | +| `summary` | string \| null | Необязательное однопараграфное общее описание, возвращённое вашим оценщиком. На панели управления это отображается выше разбивки per-score как заголовок оценки. | +| `error` | string \| null | Заполнено только на `"error"` / `"timeout"`. | +| `attempt_count` | integer | Количество попыток отправки (≥ 1). | +| `duration_ms` | integer \| null | Длительность последней попытки. | +| `completed_at` | string (ISO 8601 UTC) | Когда был записан терминальный результат. Результаты упорядочены по `completed_at` (новое в первую очередь). | +| `created_at` | string (ISO 8601 UTC) | Несёт тот же временной штамп как `completed_at` (семантика write-once). | + +--- + +## Разрешения + +| Разрешение | Предоставляет | +|---|---| +| `evaluations:read` | Список результатов оценок, просмотр оценок на панели управления и загрузка метрик здоровья панели управления. | +| `evaluations:trigger` | Ручная постановка оценки для сеанса в очередь через `POST /sessions/:session_id/re-evaluate` или кнопку re-evaluate на панели управления. | +| `dashboards:read` | Просмотр сохранённых панелей управления (также требует `evaluations:read` для загрузки их метрик). | +| `dashboards:write` | Создание и редактирование панелей управления. | +| `dashboards:delete` | Удаление панелей управления. | + +Администратор начальной загрузки (`ADMIN_KEY`, `ADMIN_EMAIL`) автоматически получает эти. + +--- + +## Просмотр результатов + +- **`/sessions/`**: временная шкала событий + правая колонка, показывающая оценки сеанса и любую ошибку из попытки отправки. Если ваш ключ имеет `evaluations:trigger`, рядом с кнопкой экспорта появляется кнопка **re-evaluate**, полезная для сеансов, которые никогда не излучали `agent_end`, или для обновления оценок после развёртывания нового оценщика. Панель управления опрашивает новый результат и обновляет правую колонку, когда он прибывает. +- **`/sessions`**: фильтруемая сетка сеансов; столбец оценки показывает статус оценки каждого сеанса и оценки с одного взгляда. +- **`/dashboards`**: сохранённые представления здоровья оценок (см. [Dashboards](#dashboards) ниже). + +![Сетка Sessions с таблетками статуса оценки per-session и раскрашенными в цвет значками оценки (helpfulness, factuality, tool_efficiency, safety, coherence)](/agenteye/images/sessions-list.png) + +*Сетка сеансов показывает статус оценки каждого запуска и оценки с одного взгляда; красные/жёлтые/зелёные значки выделяют низкие оценки.* + +![Представление деталей сеанса с оценками оценки и состоянием отправки в правой колонке](/agenteye/images/session-detail.png) + +*Открытие сеанса показывает его полную временную шкалу рядом с оценками оценки и любой ошибкой диспетчера в правой колонке.* + +--- + +## Панели управления + +Страница **Dashboards** (`/dashboards`) позволяет вам сохранить комбинацию фильтров оценок как названное, переиспользуемое представление и видеть, как этот срез оценок делает дела с одного взгляда. Панели управления **совместно используются всей вашей организацией**; все, у кого есть `dashboards:read`, видят один и тот же набор. + +Каждая панель управления закрепляет: + +- **Фильтры**: те же элементы управления как на странице сеансов: окружение, статус, агент, скользящее временное окно и фильтры диапазона оценок (`key:min..max`). +- **Конфигурацию отображения**: какие ключи оценок выделять, пороги здоровья зелёный/жёлтый/красный, какие панели показывать и свёртывать ли в последнюю оценку на сеанс. + +Каждая карточка показывает количество совпадающих сеансов, разбивку done/error/timeout, среднее для каждой выделенной оценки и маленький трендовый спарклайн. Открытие панели управления показывает полномасштабные панели; **open in sessions** переносит вас на страницу сеансов предварительно отфильтрованную на точно этот срез. Метрики вычисляются серверной стороной по целому совпадающему набору (через `GET /evaluations/aggregate`), поэтому числа точны, а не выбираются. + +![Панель управления оценкой-здоровьем с полосами средней оценки на измерение оценщика, разбивкой инструмента ok-vs-error, лучшими инструментами и трендом events-per-hour](/agenteye/images/dashboard-quality.png) + +**Разрешения:** просмотр требует обоих `dashboards:read` и `evaluations:read`; создание и редактирование требует `dashboards:write`; удаление требует `dashboards:delete`. Администратор начальной загрузки автоматически получает все эти. + +--- + +## Устранение неполадок + +**Сеансы существуют, но оценки не создаются.** Подтвердите, что `EVALUATOR_ENDPOINT` установлен в процессе сервера, что сервер и оценщик совместно используют то же значение `EVALUATOR_TOKEN`, и что конечная точка `/health` оценщика достижима с сервера. Когда `EVALUATOR_ENDPOINT` не установлен, конвейер неоперативен. + +**Оценки в полёте накапливаются.** Запросите `GET /evaluation-jobs`, чтобы увидеть очередь в полёте. Проверьте `attempt_count`, `next_attempt_at` и `last_error` для каждой строки. Частые причины: сервис оценщика недостижим или возвращает 5xx (повторяется с задержкой), неправильный `EVALUATOR_TOKEN` (401 является терминальным), или асинхронный оценщик, который возвращает `pending` бесконечно (см. ниже). + +**Сеансы завершены, но нет терминальной оценки.** Запросите `GET /evaluation-jobs?status=polling`; результат всё ещё может быть в полёте. Если задача зависает в `pending`, сервер имеет проблемы с достижением оценщика; проверьте, что оценщик работает и что `EVALUATOR_TOKEN` совпадает. + +**`HTTP 401 from evaluator: invalid bearer token`.** `EVALUATOR_TOKEN` на сервере не совпадает со значением, которое настроено на сервисе оценщика. Они должны быть идентичны. + +**Асинхронный оценщик возвращает `pending` навечно.** Сервер опрашивает `GET /evaluate/{job_id}` до тех пор, пока оценщик не вернёт `done` или `error`, или пока не истечёт `EVALUATOR_MAX_POLL_DURATION_SECS` (по умолчанию 1 ч). После лимита оценка записывается как `timeout` и удаляется из очереди в полёте. Поднимите `EVALUATOR_MAX_POLL_DURATION_SECS`, если ваш оценщик законно нуждается дольше, чем по умолчанию. \ No newline at end of file diff --git a/docs/ru/agenteye/getting-started.mdx b/docs/ru/agenteye/getting-started.mdx new file mode 100644 index 00000000..a3d78f37 --- /dev/null +++ b/docs/ru/agenteye/getting-started.mdx @@ -0,0 +1,235 @@ +--- +title: "Начало работы с AgentEye" +description: "Документация AgentEye. Начало работы с AgentEye." +--- + + +Это руководство проведёт вас через полную настройку AgentEye: развёртывание сервера и панели управления, установку сборщика на машину агента и подключение вашего кода Python-агента. + +--- + +## Что такое AgentEye? + +AgentEye — это **самостоятельно развёртываемая платформа наблюдаемости и оценки для AI-агентов**. Она записывает действия ваших агентов — каждый шаг выполнения — и автоматически оценивает качество каждого завершённого прогона, позволяя вам видеть поведение агентов в боевых условиях и перехватывать регрессии до того, как это заметят ваши пользователи. + +Данные движутся в одном направлении: ваш код агента генерирует **события** через **Python SDK** → лёгкий демон **сборщика** группирует их и отправляет на **сервер** → события и аналитика хранятся в **ClickHouse** (операционное состояние, такое как организации, пользователи, ключи API, панели управления и сохранённые запросы, находится в **Postgres**) → вы изучаете всё в **панели управления**. + +Что вы получаете: + +- **События** — неотработанный, пошаговый журнал каждого прогона агента (вызовы инструментов, вызовы модели, хуки, ошибки). +- **Сессии** — события, объединённые в одну строку на прогон, каждая **автоматически оценивается** и получает балл. +- **Оценки** — баллы качества, созданные вашими собственными сервисами оценки, так что падение качества всплывает без ручной проверки. +- **Запросы и панели управления** — сохранённые SQL-запросы ClickHouse к вашим данным, визуализированные в общих, организационных панелях управления. +- **Оповещения и инциденты** — правила по пороговым значениям, которые вас уведомляют (email, Slack, webhook, в панели управления) плюс рабочий процесс инцидентов для их сортировки. +- **CLI и AI-ассистент** — клиент терминала (`agenteye`) и встроенный ассистент для вопросов на простом английском языке. + +Вы запускаете всё это в своей инфраструктуре как один стек Docker Compose (это руководство), как производственную установку Kubernetes или как один совместно размещённый pod. Остаток руководства настраивает стек Compose от начала до конца. + +--- + +## Шаг 1: Аутентификация + +Все артефакты AgentEye распространяются из организации GitHub `agenteye-enterprise`. Как разработчик enterprise вы можете сгенерировать свой собственный GitHub PAT. Следуйте [enterprise-docs/github-token.md](/ru/agenteye/github-token) для точных шагов и необходимых разрешений. + +```bash +export AGENTEYE_TOKEN= + +# Authenticate Docker against GHCR +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +--- + +## Шаг 2: Развёртывание сервера и панели управления + +Сервер получает события от сборщиков и делает их доступными для запроса; панель управления — это место, где вы их изучаете. Поступившие события и аналитика хранятся в ClickHouse (требуемое хранилище аналитики), а Postgres хранит операционное состояние, такое как организации, пользователи, ключи API, панели управления и сохранённые запросы. + +**Загрузите опубликованный файл композа:** + +```bash +mkdir -p ./agenteye +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + https://raw.githubusercontent.com/agenteye-enterprise/releases/main/docker-compose.yml \ + -o ./agenteye/docker-compose.yml +cd agenteye +``` + +**Установите ваши секреты:** + +Создайте файл `.env`, чтобы развёртывание не запускалось с учётными данными по умолчанию `admin`. Минимально установите `ADMIN_KEY` и `POSTGRES_PASSWORD`: + +```bash +POSTGRES_PASSWORD=your-db-password +ADMIN_KEY=your-admin-secret +``` + +Также экспортируйте `ADMIN_KEY` в вашей текущей оболочке, чтобы более поздние шаги (например, `curl` на Шаге 3) могли ссылаться на него напрямую: + +```bash +export ADMIN_KEY=your-admin-secret +``` + +**Запустите стек:** + +```bash +docker compose up -d +``` + +Это включает полный стек, включая требуемое хранилище аналитики ClickHouse и дополнительный кеш Redis, наряду с сервером и панелью управления. ClickHouse должен быть здоров, чтобы сервер запустился. + +Сервер теперь прослушивает `http://localhost:8080`, а панель управления — `http://localhost:3000`. + +Для производственных развёртываний (пользовательский Postgres, TLS, reverse proxy), см. [enterprise-docs/deployment.md](/ru/agenteye/deployment). + +--- + +## Шаг 3: Создание ключа API для сборщика + +Каждый сборщик аутентифицируется с помощью ограниченного ключа API. Используйте `ADMIN_KEY`, который вы установили на Шаге 2, чтобы создать один: + +```bash +curl -s -X POST http://localhost:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{"name":"prod-collector","key":"your-collector-secret","permissions":["events:add"]}' +``` + +Вы предоставляете значение `key` самостоятельно; используйте его в конфигурации сборщика на Шаге 4. См. [enterprise-docs/api-keys.md](/ru/agenteye/api-keys) для полного управления ключами. + +--- + +## Шаг 4: Установка сборщика + +На каждой машине, где запускаются ваши AI-агенты, установите демон сборщика. + +**Загрузите бинарный файл (Linux x86_64):** + +```bash +VERSION=0.0.1-beta.13 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "collector/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-collector-linux-x86_64' +chmod +x agenteye-collector-linux-x86_64 +sudo mv agenteye-collector-linux-x86_64 /usr/local/bin/agenteye-collector +``` + +> Это загружает сборку **Linux x86_64**. Для macOS (Apple Silicon или Intel), Linux arm64 или Docker/systemd/launchd настройки, см. [collector-installation.md](/ru/agenteye/collector-installation), которая содержит ссылки загрузки для каждой платформы — вышеуказанная команда устанавливает бинарный файл Linux, который не будет запускаться в других местах. + +**Настройка:** + +```bash +mkdir -p ~/.agenteye +cat > ~/.agenteye/config.json </…`). + +- **Запросы** (`//queries`): начните с библиотеки сохранённых, повторно используемых запросов над вашими событиями и оценками (встроенные предустановки плюс ваши собственные)… + +![Библиотека сохранённых запросов: сетка повторно используемых запросов, как встроенные предустановки, так и пользовательские](/agenteye/images/queries.png) + + …затем откройте один в SQL-компоновщике, чтобы его настроить и запустить с живыми результатами: + +![Компоновщик SQL-запросов, запускающий сохранённый запрос, с боковой панелью схемы и живой сеткой результатов](/agenteye/images/query-lab.png) + +- **Панели управления** (`//dashboards`): закрепите запросы как линейные, столбцовые, области или круговые плитки в общих, организационных панелях управления. + +![Панель управления, построенная из сохранённых запросов: линия событий в час, столбцовая диаграмма ошибок по типу, диаграмма площади задержки и токены по модели](/agenteye/images/dashboard-fleet.png) + +- **Оповещения** (`//alerts`): повысьте любой порог до правила уведомления, которое уведомляет по email, Slack, webhook или в панель управления. См. [enterprise-docs/alerts.md](/ru/agenteye/alerts). + +--- + +## Следующие шаги + +- [Развёртывание](/ru/agenteye/deployment): укрепление для производства +- [Ключи API](/ru/agenteye/api-keys): управление доступом +- [Устранение неполадок](/ru/agenteye/troubleshooting): диагностика проблем \ No newline at end of file diff --git a/docs/ru/agenteye/github-token.mdx b/docs/ru/agenteye/github-token.mdx new file mode 100644 index 00000000..37e51ee4 --- /dev/null +++ b/docs/ru/agenteye/github-token.mdx @@ -0,0 +1,132 @@ +--- +title: "Настройка GitHub Token" +description: "Документация по настройке GitHub Token для AgentEye." +--- + + +GitHub Personal Access Token (PAT) — это единственное учетное данные, которое открывает доступ ко всем артефактам AgentEye. С одним токеном вы можете загружать Docker-образы, скачивать релизные бинарники и устанавливать Python-пакеты без отдельных логинов для каждого компонента и без обмена общими секретами. Все артефакты AgentEye распространяются из организации GitHub `agenteye-enterprise`; после предоставления доступа вашей организации каждый разработчик или оператор генерирует и обновляет свой собственный токен, что обеспечивает отслеживаемость и возможность отзыва доступа для каждого пользователя. + +Установите токен как переменную окружения и учетные данные Docker один раз на машину: + +```bash +export AGENTEYE_TOKEN= +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +> **Примечание о пользователе:** GHCR игнорирует имя пользователя при `docker login` и выполняет аутентификацию полностью на основе токена, поэтому подойдет любое непустое значение. В этой документации используется `-u x` для краткости; манифесты развертывания, создающие Kubernetes image-pull secret, могут использовать более описательное имя пользователя, такое как `agenteye-enterprise`. Оба варианта приняты. + +--- + +## Вариант A: Классический токен (Рекомендуется) + +Классический токен — это наиболее надежный выбор для AgentEye, так как поток `docker login` и загрузки образов GHCR имеет наиболее широкую и стабильную поддержку классических токенов. Двух областей действия достаточно для всего необходимого (загрузка образов и скачивание релизных ресурсов), поэтому вы аутентифицируетесь один раз и движетесь дальше без возни с реестром. Одна из них, `read:packages`, является истинно только для чтения; другая, `repo`, — единственная классическая область действия, предоставляющая доступ к приватным релизным ресурсам, и она намеренно широка — GitHub определяет ее как полный контроль (чтение и запись) приватных репозиториев. + +### 1. Создайте токен + +Перейдите в **GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic) → Generate new token (classic)**. + +| Поле | Значение | +|---|---| +| **Note** | `agenteye-` (например `agenteye-prod-server`) | +| **Expiration** | Установите срок действия в соответствии с вашей политикой безопасности; 90 дней — разумное значение по умолчанию | + +> **Примечание о метке:** GitHub называет это поле **Note** для классических токенов и **Token name** для детализированных токенов. Они служат одной и той же цели: удобочитаемый идентификатор для последующего аудита и отзыва. + +### 2. Выберите области действия + +| Область действия | Зачем она нужна | +|---|---| +| `read:packages` | Загружать Docker-образы из `ghcr.io/agenteye-enterprise/` и скачивать ресурсы пакетов | +| `repo` | Читать содержимое приватных репозиториев, исходные файлы и релизные ресурсы из `agenteye-enterprise/releases`. Это широкая область GitHub — полный контроль приватных репозиториев (чтение и запись), а не область только для чтения — это просто единственная классическая область, предоставляющая доступ к приватным релизным ресурсам | + +Никакие другие области действия не требуются. + +### 3. Сгенерируйте и скопируйте токен + +Нажмите **Generate token** и сразу скопируйте значение; оно отображается только один раз. Сохраните его в вашем менеджере секретов или окружении. + +--- + +## Вариант B: Детализированный токен + +Детализированные токены ограничивают доступ к конкретным репозиториям и разрешениям, что делает их наиболее жестким вариантом с принципом наименьших привилегий. Выберите этот путь, если политика безопасности вашей организации требует детализированных токенов. + +> **Примечание:** Поддержка детализированных токенов в GHCR менее консистентна, чем для классических токенов. Если `docker login` или `docker pull` не работает после выполнения этих шагов, вернитесь к классическому токену (Вариант A). + +### 1. Создайте токен + +Перейдите в **GitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokens → Generate new token**. + +| Поле | Значение | +|---|---| +| **Token name** | `agenteye-` (например `agenteye-prod-server`) | +| **Expiration** | Установите срок действия в соответствии с вашей политикой безопасности; 90 дней — разумное значение по умолчанию | +| **Resource owner** | `agenteye-enterprise` | +| **Repository access** | **Only select repositories** → `agenteye-enterprise/releases` | + +### 2. Установите разрешения репозитория + +В разделе **Permissions → Repository permissions** установите: + +| Разрешение | Доступ | +|---|---| +| **Contents** | Read-only | +| **Packages** | Read-only | + +Все остальные разрешения могут оставаться **No access**. + +> **Примечание:** Если образы контейнеров (`ghcr.io/agenteye-enterprise/...`) опубликованы как пакеты на уровне организации, а не как пакеты, связанные с репозиторием, `docker login` может завершиться ошибкой с разрешениями только на уровне репозитория. В этом случае добавьте разрешение на уровне организации: **Permissions → Organization permissions → Packages: Read-only**. + +### 3. Что дает каждое разрешение + +| Разрешение | Используется для | +|---|---| +| Contents: Read-only | Скачивания `docker-compose.yml`, релизных бинарников и Python-пакетов из `agenteye-enterprise/releases` | +| Packages: Read-only | Загрузки Docker-образов из `ghcr.io/agenteye-enterprise/` | + +### 4. Сгенерируйте и скопируйте токен + +Нажмите **Generate token** и сразу скопируйте значение; оно отображается только один раз. Сохраните его в вашем менеджере секретов или окружении. + +--- + +## Обновление токена + +Плановое обновление токенов поддерживает отслеживаемость доступа и ограничивает радиус действия если учетные данные когда-либо утекут. Токены также могут истечь или быть отозваны в любой момент, поэтому обновление — это стандартный способ оставаться аутентифицированным. Чтобы обновить токен: + +1. Сгенерируйте новый токен, используя описанные выше шаги. +2. Обновите `AGENTEYE_TOKEN` в вашем окружении или менеджере секретов. +3. Заново аутентифицируйте Docker: `echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin` +4. Отзовите старый токен в GitHub → Settings → Developer settings → Personal access tokens, затем откройте подраздел **Tokens (classic)** или **Fine-grained tokens**, соответствующий типу токена, и удалите его. + +--- + +## Проверьте ваш токен + +Убедитесь, что токен работает перед интеграцией в развертывание, чтобы ошибки аутентификации обнаружились здесь, а не во время развертывания. Каждая команда проверяет одну из областей действия выше: + +```bash +# Packages scope - аутентифицируйте Docker в GHCR +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin + +# Contents scope - загрузите исходный файл релиза +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + https://raw.githubusercontent.com/agenteye-enterprise/releases/main/docker-compose.yml \ + -o /tmp/agenteye-compose-check.yml +``` + +Успешный `docker login` подтверждает область действия пакетов; загруженный файл подтверждает область действия содержимого. + +--- + +## Устранение неполадок + +| Симптом | Вероятная причина | Решение | +|---|---|---| +| `docker login` возвращает 401 | Токену не хватает `Packages: Read-only` (детализированный) или `read:packages` (классический) | Добавьте область действия пакетов и заново сгенерируйте | +| `curl` возвращает 404 на исходные URL GitHub | Токену не хватает области действия `Contents: Read-only` или `repo` | Добавьте область действия содержимого и заново сгенерируйте | +| `gh release download` возвращает 403 | Токен не авторизован для `agenteye-enterprise/releases` | Проверьте, что репозиторий включен в доступ репозитория детализированного токена, или используйте классический токен с областью действия `repo` | +| Токен принят, но образы не найдены | На детализированном токене отсутствует разрешение пакета на уровне организации | Добавьте разрешение на уровне организации `Packages: Read-only` | + +По вопросам доступа обратитесь в `support@exosphere.host`. \ No newline at end of file diff --git a/docs/ru/agenteye/health-monitoring.mdx b/docs/ru/agenteye/health-monitoring.mdx new file mode 100644 index 00000000..73c3162b --- /dev/null +++ b/docs/ru/agenteye/health-monitoring.mdx @@ -0,0 +1,88 @@ +--- +title: "Health Monitoring" +description: "Документация AgentEye Health Monitoring." +--- + + +Узнайте, когда развертывание AgentEye **само по себе** неработоспособно или деградировано, а не только когда ваши агенты ведут себя неправильно. Обнаружение **нативно для Kubernetes** и, что самое важное, **независимо от AgentEye**: оно читает состояние подов из плоскости управления Kubernetes и проверяет жесткие зависимости AgentEye, поэтому срабатывает даже когда неработоспособен сервер, ClickHouse или Postgres. + +Существует два слоя. Первый встроен; второй — опциональный. + +## 1. Осведомленная о зависимостях готовность (встроено) + +Сервер предоставляет два конечных точки проверки с намеренно разными функциями: + +| Конечная точка | Проверка | Что проверяется | Аутентификация | +|---|---|---|---| +| `GET /health` | liveness | процесс запущен (всегда `{"status":"ok"}`) | нет | +| `GET /ready` | readiness | может фактически обслуживать: **Postgres + ClickHouse** доступны | нет | + +`/ready` возвращает `200` с `"status":"ready"` и всеми проверками `"ok"` когда обе жесткие зависимости доступны, и `503` с `"status":"not_ready"` когда хотя бы одна недоступна. Оба ответа содержат небольшое тело: + +```json +{ "status": "not_ready", + "checks": { "postgres": "ok", "clickhouse": "down", "redis": "not_configured" } } +``` + +Redis — опциональный кеш, за пределы которого сервер деградирует, поэтому он отражается в целях информирования, но **никогда** не влияет на готовность. Он показывает `"ok"` когда кеш сконфигурирован и `"not_configured"` иначе; он никогда не будет `"down"`. + +В комплектных манифестах Kubernetes проверка **readiness** указывает на `/ready`, а **liveness** остается на `/health`. Эффект: сервер, который *запущен, но не может достичь базы данных*, удаляется из Service и отображается как `NotReady` — состояние, на которое может среагировать мониторинг кластера (см. ниже), при этом liveness остается недорогой, так что кратковременный сбой зависимости никогда не вызовет перезагрузку пода. Проверка использует щедрый порог отказа, поэтому мгновенный сбой не вызовет колебания реплик из ротации. + +## 2. Оповещение об отказах подов с Robusta (опционально) + +[Robusta](https://github.com/robusta-dev/robusta) — монитор, нативный для Kubernetes, который отслеживает сервер API и отправляет сообщения об отказах подов (`CrashLoopBackOff`, `OOMKilled`, `ImagePullBackOff`, `Pending`/`NotReady`, `Failed`, вытеснения) в Slack. Поскольку он наблюдает за плоскостью управления, а не запрашивает AgentEye, он генерирует оповещения даже когда AgentEye вообще не может обслуживать. + +Robusta поставляется как опциональный компонент в комплект выпуска. Включите его с помощью стандартного Helm-чарта Robusta и небольшого файла значений, показанного ниже: + +1. Добавьте репозиторий чарта и получите **токен бота** Slack (`xoxb-…`) для канала: + + ```bash + helm repo add robusta https://robusta-charts.storage.googleapis.com + helm repo update + ``` + + Поскольку конфигурация ниже держит все внутри кластера (`disableCloudRouting: true`), токен поступает от самохостируемого приложения Slack: создайте приложение на `https://api.slack.com/apps`, добавьте область бота `chat:write`, установите его в свой workspace, скопируйте **Bot User OAuth Token** (`xoxb-…`) и пригласите бота на канал (`/invite @your-app`). + +2. Создайте `values.yaml` с меткой для каждого развертывания (`clusterName`) и вашим каналом Slack, ограниченным пространством имен `agenteye`: + + ```yaml + clusterName: "acme-prod" # метка для каждого развертывания; появляется в каждом оповещении + enablePrometheusStack: false # только оповещения об отказах подов; без стека метрик + disableCloudRouting: true # доставка в Slack напрямую, внутри кластера + sinksConfig: + - slack_sink: + name: vendor_slack + slack_channel: "agenteye-fleet-health" + api_key: "REPLACE_WITH_SLACK_BOT_TOKEN" # xoxb-… (предпочитайте --set или секрет) + scope: + include: + - namespace: [agenteye] # только оповещения из пространства имен AgentEye; удалите для расширения + ``` + +3. Установите, закрепив `--version` на известную хорошую версию Robusta-чарта ([releases](https://github.com/robusta-dev/robusta/releases)) так, чтобы вы никогда не устанавливали непроверенный чарт: + + ```bash + helm install robusta robusta/robusta \ + --namespace robusta --create-namespace \ + --version \ + -f values.yaml \ + --set sinksConfig[0].slack_sink.api_key=$ROBUSTA_SLACK_TOKEN + ``` + +### Что он отчитывает + +- **Состояние пода** Kubernetes (какой под AgentEye отказал и почему) и **тег образа** каждого пода, то есть **версия** запущенного компонента. +- **Никакие данные события AgentEye и никакие данные клиентов** никогда не покидают кластер. +- Комплектные значения ограничивают оповещения **пространством имен `agenteye`**, поэтому несвязанные рабочие нагрузки в том же кластере не отчитываются. + +### Одно место для каждого развертывания + +Направьте Robusta каждого развертывания на **один общий канал Slack**, каждый с собственным `clusterName`. Каждое оповещение помечено этой меткой, поэтому один канал показывает здоровье вашего целого флота, и вы можете определить, какое развертывание затронуто с первого взгляда. + +### Полные сбои кластера + +Чисто внутренний наблюдатель кластера не может отчитаться о **сбое всего кластера или сети** (он выходит из строя вместе с кластером). Если вам это нужно, включите опциональный **Robusta UI sink**: установите `disableCloudRouting: false` и добавьте `robusta_sink` (с токеном из `robusta gen-config`) в `sinksConfig`. Это добавляет агрегированную многокластерную панель управления и отмечает любой кластер, который перестал проверяться. + +## Устранение неполадок + +Смотрите раздел **Health Monitoring** в [enterprise-docs/troubleshooting.md](/ru/agenteye/troubleshooting) для «оповещения не поступают» и «сервер продолжает переключаться `NotReady`». \ No newline at end of file diff --git a/docs/ru/agenteye/kubernetes-deployment.mdx b/docs/ru/agenteye/kubernetes-deployment.mdx new file mode 100644 index 00000000..9731abed --- /dev/null +++ b/docs/ru/agenteye/kubernetes-deployment.mdx @@ -0,0 +1,981 @@ +--- +title: "Kubernetes Deployment Guide" +description: "AgentEye Kubernetes Deployment Guide documentation." +--- + + +Это руководство развертывает полный стек AgentEye на выделенный кластер Kubernetes: + +- **ClickHouse 24.8** -- каноническое хранилище аналитики событий и оценок (StatefulSet с постоянным томом 100Gi). Обязателен: сервер отказывается запускаться без него. +- **PostgreSQL 16** -- хранилище реляционных данных/метаданных для организаций, ключей API, пользователей, панелей, сохраненных запросов и аутентификации (StatefulSet с постоянным томом 50Gi) +- **Redis 7.2** -- опциональный общий кэш и бэкэнд ограничения скорости; сервер и панель корректно деградируют при его недоступности +- **AgentEye Server** -- Rust API для приема событий, аналитики и управления ключами (2 реплики) +- **AgentEye Dashboard** -- Next.js веб-интерфейс (2 реплики) +- **AI помощник (сервис агента)** -- опциональный помощник только для чтения в панели на порту 9100; неактивен до настройки конечной точки LLM +- **Traefik (public)** -- контроллер входящего трафика для трафика сборщика, защищенный mTLS +- **Traefik (dashboard)** -- контроллер входящего трафика для панели, только для VPN/IP-разрешенного списка +- **cert-manager** -- TLS сертификаты и CA для mTLS +- **Резервная копия CronJob** -- ежедневный комбинированный дамп PostgreSQL + ClickHouse в 03:00 UTC +- **Монитор обновления сертификатов** -- предупреждения при приближении истечения сертификатов клиента + +**Примерное время:** 60-90 минут для первого развертывания. + +Для модели управляемого развертывания, где Exosphere берет это на себя, см. [enterprise-docs/managed-deployment.md](/ru/agenteye/managed-deployment). + +--- + +## Предварительные условия + +Запустите каждую команду проверки перед началом. Каждая проверка должна пройти. + +| Требование | Минимум | Команда проверки | Ожидаемый результат | +|---|---|---|---| +| Кластер Kubernetes | 1.27+ | `kubectl version` | Server Version >= v1.27 | +| Kustomize (поставляется с kubectl) | Kustomize v1.14+ (поставляется в kubectl 1.27+) | `kubectl kustomize --help` | Выводит текст справки | +| Helm | v3 | `helm version` | `Version:"v3.x.x"` | +| cluster-admin RBAC | -- | `kubectl auth can-i create namespaces` | `yes` | +| Класс хранилища по умолчанию | -- | `kubectl get storageclass` | По крайней мере одна строка отмечена `(default)` | +| Поддержка LoadBalancer | -- | Зависит от облака (EKS, GKE, AKS поддерживают по умолчанию) | -- | +| GitHub PAT | -- | `echo $AGENTEYE_TOKEN` | Не пусто (см. [enterprise-docs/github-token.md](/ru/agenteye/github-token)) | +| openssl | -- | `openssl version` | OpenSSL 1.x или 3.x | +| Бакет облачного хранилища | -- | Для резервных копий PostgreSQL + ClickHouse (S3, GCS или Azure Blob) | -- | + +**Размер кластера:** минимум 3 узла, по 4 vCPU / 8 ГБ ОЗУ каждый. Полные требования см. в [enterprise-docs/managed-deployment.md](/ru/agenteye/managed-deployment). + +### Запустить все проверки сразу + +```bash +echo "--- Prerequisites Check ---" +kubectl version --client -o yaml 2>/dev/null | grep -q gitVersion && echo "PASS: kubectl" || echo "FAIL: kubectl not found" +helm version --short 2>/dev/null | grep -q v3 && echo "PASS: helm v3" || echo "FAIL: helm v3 not found" +kubectl auth can-i create namespaces 2>/dev/null | grep -q yes && echo "PASS: cluster-admin" || echo "FAIL: no cluster-admin" +kubectl get storageclass 2>/dev/null | grep -q default && echo "PASS: default StorageClass" || echo "FAIL: no default StorageClass" +[ -n "$AGENTEYE_TOKEN" ] && echo "PASS: AGENTEYE_TOKEN set" || echo "FAIL: AGENTEYE_TOKEN not set" +openssl version >/dev/null 2>&1 && echo "PASS: openssl" || echo "FAIL: openssl not found" +echo "---" +``` + +### Форма развертывания + +**Конечная точка приема** работает на имени хоста, которым вы управляете (например, `ingest.your-company.example`). cert-manager запрашивает общедоступный сертификат TLS от Let's Encrypt через HTTP-01, поэтому сборщики проверяют сертификат сервера в системном хранилище доверия без привязки CA для каждого клиента. + +**Конечная точка панели** работает так же: она работает на втором имени хоста, которым вы управляете (например, `agenteye.your-company.example`), указывающем на LoadBalancer Traefik панели, и cert-manager выпускает его сертификат Let's Encrypt через этот LoadBalancer. Браузеры получают доверенный сертификат без предупреждения. + +> **Выпуск сертификата и обновление проверяются через HTTP-01**, поэтому оба LoadBalancer должны быть доступны из общественного интернета на порту 80. Если вам нужно ограничить IP-адреса для LoadBalancer панели, сначала согласуйте решатель DNS-01 с поддержкой — в противном случае обновления молча не срабатывают и сертификат истекает. + +--- + +## Получение манифестов + +```bash +git clone https://x:${AGENTEYE_TOKEN}@github.com/agenteye-enterprise/releases.git +cd releases/deploy +``` + +**Проверьте это:** + +```bash +ls base/kustomization.yaml +``` + +Ожидается: файл существует. Если нет, клонирование не удалось -- проверьте ваш `AGENTEYE_TOKEN`. + +**Структура каталогов:** + +``` +deploy/ + base/ Общая база Kustomize (все ресурсы K8s) + overlays/ Переопределения для конкретного кластера (теги образов, имена хостов, ресурсы) + third-party/ Значения Helm для Traefik, cert-manager и (опционально) мониторинга здоровья Robusta +``` + +**Base** содержит каждый ресурс, необходимый для полного развертывания, включая сертификаты Let's Encrypt для двух общедоступных имен хостов, которые вы настраиваете на этапе 3.1. **Overlay** применяет патчи к базе для конкретной среды (например, пользовательские теги образов, лимиты ресурсов, подключение переменных). Каталог **third-party** содержит файлы значений Helm для внешней инфраструктуры. + +> **Мониторинг здоровья (опционально):** проверка готовности сервера уже отражает здоровье Postgres + ClickHouse, и `third-party/robusta/` добавляет опциональное оповещение об отказе pod в Slack на уровне Kubernetes. См. [enterprise-docs/health-monitoring.md](/ru/agenteye/health-monitoring). + +--- + +## Этап 1 -- Инфраструктура третьих лиц (~30 мин) + +### 1.1 Установка cert-manager + +cert-manager управляет TLS сертификатами для HTTPS и приватным CA, используемым для сертификатов клиента mTLS. + +```bash +helm repo add jetstack https://charts.jetstack.io +helm repo update + +helm install cert-manager jetstack/cert-manager \ + --namespace cert-manager --create-namespace \ + --set crds.install=true +``` + +**Проверьте это:** + +```bash +kubectl get pods -n cert-manager +``` + +Ожидается: 3 pod'а, все `Running` -- `cert-manager`, `cert-manager-cainjector`, `cert-manager-webhook`. + +```bash +kubectl get crds | grep cert-manager +``` + +Ожидается: по крайней мере `certificates.cert-manager.io`, `clusterissuers.cert-manager.io`, `issuers.cert-manager.io`. + +**Если не удалось:** Pod'ы в `CrashLoopBackOff` обычно означают, что CRD не были установлены. Повторно запустите с `--set crds.install=true`. Если pod'ы webhook не прошли проверку готовности, подождите 30 секунд и проверьте снова -- они могут требовать немного времени на запуск. + +--- + +### 1.2 Установка Traefik -- контроллер входящего трафика для общественного приема + +Этот экземпляр Traefik обрабатывает трафик сборщика на **внешнем** LoadBalancer. Он завершает TLS и обеспечивает mTLS (проверку сертификата клиента) на конечной точке приема. + +```bash +helm repo add traefik https://traefik.github.io/charts +helm repo update + +helm install traefik-public traefik/traefik \ + --namespace traefik-public --create-namespace \ + --version 39.0.8 \ + -f third-party/traefik/values-public.yaml +``` + +**Проверьте это:** + +```bash +kubectl get pods -n traefik-public +``` + +Ожидается: 1 pod `Running`. + +```bash +kubectl get ingressclass traefik-public +``` + +Ожидается: IngressClass существует (это не класс по умолчанию). + +**Если не удалось:** Проверьте `kubectl describe pod -n traefik-public ` на предмет ошибок извлечения образа или ограничений ресурсов. + +--- + +### 1.3 Установка Traefik -- контроллер панели + +Этот экземпляр Traefik обслуживает панель на выделенном LoadBalancer, ограниченном списком разрешенных IP-адресов. + +> **Два механизма разрешения списков поставляются для этого экземпляра.** Это руководство использует `values-dashboard.yaml`, который ограничивает доступ переносимым полем `service.loadBalancerSourceRanges`. Параллельный `values-internal.yaml` также предоставляется для окружений AWS, которые предпочитают аннотацию `service.beta.kubernetes.io/aws-load-balancer-source-ranges`. Выберите один и используйте его постоянно; шаги ниже предполагают `values-dashboard.yaml`. + +**Перед установкой** отредактируйте `third-party/traefik/values-dashboard.yaml` для установки разрешенных IP-адресов источника. Поле `loadBalancerSourceRanges` управляет тем, какие IP-адреса могут получить доступ к панели. По умолчанию установлено `0.0.0.0/0` (все IP-адреса); ограничьте его вашим VPN, офисом или известными IP-адресами исходящего трафика. + +#### Разрешить один IP-адрес + +```yaml +service: + loadBalancerSourceRanges: + - "/32" +``` + +#### Разрешить несколько IP-адресов + +Добавьте одну запись для каждого IP-адреса или блока CIDR. Суффикс `/32` соответствует одному адресу IPv4; блок CIDR (например, `/24`) соответствует диапазону. Вы можете смешивать отдельные IP-адреса и диапазоны свободно: + +```yaml +service: + loadBalancerSourceRanges: + - "203.0.113.10/32" # office gateway + - "203.0.113.11/32" # backup office gateway + - "198.51.100.0/24" # VPN pool + - "192.0.2.50/32" # on-call engineer home IP +``` + +Советы при ведении списка: + +- Держите одну запись на строку и добавляйте краткий комментарий `#` для идентификации владельца каждого IP-адреса или назначения; это то, что будущие операторы используют для определения необходимости записи. +- Всегда используйте нотацию CIDR. Простой IP-адрес как `203.0.113.10` отклоняется облачным поставщиком; используйте `203.0.113.10/32`. +- Для диапазонов IPv6 используйте эквивалент `/128` (один адрес) или больший CIDR, например `2001:db8::1/128`. Не все облачные поставщики поддерживают диапазоны источников IPv6; проверьте документацию LoadBalancer вашего поставщика. +- Список это **OR**: трафик разрешен, если источник соответствует любой записи. + +После редактирования файла перейдите к `helm install` ниже. Если контроллер уже установлен, запустите `helm upgrade` с теми же флагами или примените патч Service во время выполнения (следующий раздел). + +#### Обновить список разрешений во время выполнения + +Вы можете изменить разрешенные IP-адреса без обновления Helm, применив патч Service напрямую. **Патч заменяет весь список**; всегда включайте каждый IP-адрес, который вы хотите сохранить, а не только новый. + +Для замены списка новым набором IP-адресов: + +```bash +kubectl patch svc traefik-dashboard -n traefik-dashboard \ + -p '{"spec":{"loadBalancerSourceRanges":["203.0.113.10/32","198.51.100.0/24","192.0.2.50/32"]}}' +``` + +Для безопасного **добавления** IP-адреса без потери существующих записей сначала прочитайте текущий список, затем примените патч с объединенным набором: + +```bash +# 1. Показать текущий список разрешений +kubectl get svc traefik-dashboard -n traefik-dashboard \ + -o jsonpath='{.spec.loadBalancerSourceRanges}' + +# 2. Применить патч с полным списком, включая новый IP +kubectl patch svc traefik-dashboard -n traefik-dashboard \ + -p '{"spec":{"loadBalancerSourceRanges":["/32","/32","/32"]}}' +``` + +> Патчи во время выполнения не сохраняются обратно в `values-dashboard.yaml`. Для сохранения изменения при будущих обновлениях Helm также обновите файл значений и зафиксируйте его. + +Затем установите: + +```bash +helm install traefik-dashboard traefik/traefik \ + --namespace traefik-dashboard --create-namespace \ + --version 39.0.8 \ + -f third-party/traefik/values-dashboard.yaml +``` + +**Проверьте это:** + +```bash +kubectl get pods -n traefik-dashboard +``` + +Ожидается: 1 pod `Running`. + +```bash +kubectl get ingressclass traefik-dashboard +``` + +Ожидается: IngressClass существует. + +--- + +### 1.4 Ожидание LoadBalancer'ов + +Оба экземпляра Traefik нуждаются в внешних IP-адресах перед продолжением. + +```bash +kubectl get svc -n traefik-public +kubectl get svc -n traefik-dashboard +``` + +**Проверьте это:** Оба сервиса показывают `EXTERNAL-IP` (не ``). + +Если все еще ожидание, наблюдайте за назначением: + +```bash +kubectl get svc -n traefik-public -w +``` + +Нажмите `Ctrl+C` после появления IP-адреса. Назначение IP обычно занимает 2-5 минут. + +**Если не удалось:** `` через 10 минут обычно означает, что облачный поставщик не может выделить LoadBalancer. Проверьте: теги подсети (EKS требует `kubernetes.io/role/elb`), конфигурацию VPC, квоты услуги и что правильная аннотация внутреннего LB установлена для внутреннего экземпляра. + +--- + +## Этап 2 -- Создание секретов (~10 мин) + +Все секреты создаются вручную перед развертыванием приложения. Это гарантирует, что конфиденциальные значения никогда не появляются в файлах манифестов. + +### 2.1 Создание пространства имен + +```bash +kubectl create namespace agenteye +``` + +**Проверьте это:** + +```bash +kubectl get namespace agenteye +``` + +Ожидается: статус `Active`. + +--- + +### 2.2 Секрет для извлечения образа + +Этот секрет аутентифицируется с `ghcr.io` для извлечения контейнерных образов AgentEye. См. [enterprise-docs/github-token.md](/ru/agenteye/github-token) для генерации PAT. + +```bash +kubectl create secret docker-registry agenteye-image-pull \ + --namespace agenteye \ + --docker-server=ghcr.io \ + --docker-username=agenteye-enterprise \ + --docker-password="${AGENTEYE_TOKEN}" +``` + +**Проверьте это:** + +```bash +kubectl get secret agenteye-image-pull -n agenteye -o jsonpath='{.type}' +``` + +Ожидается: `kubernetes.io/dockerconfigjson`. + +**Проверьте это (глубоко)** -- убедитесь, что токен может действительно извлекать образы: + +Используйте тег образа `server`, указанный в `kustomization.yaml` вашего overlay (в настоящее время `v0.0.1-beta.48` в обоих поставляемом overlay `acme` и базовом развертывании). Замените тег ниже на тот, который вы развертываете, чтобы эта проверка не дрейфовала между выпусками: + +```bash +kubectl run test-pull \ + --image=ghcr.io/agenteye-enterprise/server:v0.0.1-beta.48 \ + --overrides='{"spec":{"imagePullSecrets":[{"name":"agenteye-image-pull"}]}}' \ + --restart=Never -n agenteye --command -- echo ok + +# Подождите несколько секунд для извлечения, затем: +kubectl logs test-pull -n agenteye +kubectl delete pod test-pull -n agenteye +``` + +Ожидается: `ok` выводится в логах. + +**Если не удалось:** `ErrImagePull` или `401 Unauthorized` означает, что PAT недействителен или не имеет области `read:packages`. Повторно проверьте [enterprise-docs/github-token.md](/ru/agenteye/github-token). + +--- + +### 2.3 Учетные данные PostgreSQL + +```bash +POSTGRES_PASSWORD=$(openssl rand -hex 24) + +kubectl create secret generic agenteye-postgres \ + --namespace agenteye \ + --from-literal=POSTGRES_USER=postgres \ + --from-literal=POSTGRES_PASSWORD="${POSTGRES_PASSWORD}" \ + --from-literal=POSTGRES_DB=agenteye +``` + +> **Важно:** Мы используем `-hex` (не `-base64`) для создания пароля. Выходные данные Base64 могут содержать `+`, `/` и `=`, которые нарушают строку подключения `DATABASE_URL`. Подробности см. в [enterprise-docs/troubleshooting.md](/ru/agenteye/troubleshooting). + +> **Сохраните `POSTGRES_PASSWORD` в менеджер секретов немедленно.** Вам это понадобится, если вы когда-либо восстанавливаете из резервной копии или подключаетесь к базе данных напрямую. + +**Проверьте это:** + +```bash +kubectl get secret agenteye-postgres -n agenteye +``` + +Ожидается: секрет существует. + +```bash +kubectl get secret agenteye-postgres -n agenteye \ + -o jsonpath='{.data.POSTGRES_PASSWORD}' | base64 -d | wc -c +``` + +Ожидается: `48` (24 hex байта = 48 символов). + +--- + +### 2.4 Ключ администратора API + +```bash +ADMIN_KEY=$(openssl rand -hex 32) + +kubectl create secret generic agenteye-admin-key \ + --namespace agenteye \ + --from-literal=ADMIN_KEY="${ADMIN_KEY}" +``` + +Ключ администратора - это начальный учетные данные. Сервер обновляет его при каждом запуске со всеми разрешениями. Используйте его для создания областных ключей сборщика на этапе 7. Полную модель разрешений см. в [enterprise-docs/api-keys.md](/ru/agenteye/api-keys). + +> **Сохраните `ADMIN_KEY` в менеджер секретов немедленно.** + +**Проверьте это:** + +```bash +kubectl get secret agenteye-admin-key -n agenteye +``` + +Ожидается: секрет существует. + +--- + +### 2.5 Конфигурация аутентификации (вход на панель) + +Панель использует электронную почту + OTP для входа пользователя. Без этого секрета сервер все еще запускается и путь `ADMIN_KEY` API продолжает работать, но **ни один пользователь не может войти через пользовательский интерфейс**. + +Все ключи упоминаются как `optional: true` в базовом манифесте, поэтому частичные секреты (или вообще отсутствие секрета) нормальны; сервер возвращается к задокументированным значениям по умолчанию. Упаковка всего в один секрет `agenteye-auth` держит поверхность аутентификации ротируемой в одном месте. + +```bash +kubectl create secret generic agenteye-auth \ + --namespace agenteye \ + --from-literal=ADMIN_EMAIL="admin@yourcompany.com" \ + --from-literal=ALLOWED_EMAILS="*@yourcompany.com" \ + --from-literal=SMTP_HOST="smtp.yourprovider.com" \ + --from-literal=SMTP_PORT="587" \ + --from-literal=SMTP_USERNAME="your-smtp-user" \ + --from-literal=SMTP_PASSWORD="your-smtp-password" \ + --from-literal=SMTP_FROM="noreply@yourcompany.com" \ + --from-literal=SMTP_TLS="starttls" \ + --from-literal=DEFAULT_ORG_NAME="Acme Corp" \ + --from-literal=DEFAULT_ORG_SLUG="acme" +``` + +| Ключ | Назначение | +|---|---| +| `ADMIN_EMAIL` | Пользователь администратора начальной загрузки. Обновляется при каждом запуске со всеми разрешениями и защищен от удаления/редактирования разрешений через панель. Без него администратор не может быть созданный начальный и первый вход невозможен. | +| `ALLOWED_EMAILS` | Список разрешений через запятую. Поддерживает точные адреса (`user@example.com`) и подстановочные знаки для доменов (`*@example.com`). Без него **ни один пользователь не может войти или быть создан**. | +| `SMTP_HOST`, `SMTP_PORT`, `SMTP_USERNAME`, `SMTP_PASSWORD`, `SMTP_FROM` | Ретрансляция SMTP для отправки кодов OTP. Если `SMTP_HOST` не установлен, коды OTP записываются в stdout сервера вместо отправки по электронной почте (полезно для первоначальной дымовой проверки). Предоставьте все ключи SMTP вместе для реальной доставки электронной почты. | +| `SMTP_TLS` | Один из `starttls` (по умолчанию), `tls` или `none`. | +| `DEFAULT_ORG_NAME`, `DEFAULT_ORG_SLUG` | Опционально. Дайте встроенной организации `default` дружественное отображаемое имя и слаг URL, так что она находится, например, в `/acme` вместо `/default`. Применяется только при **первой загрузке**; после переименования org с `agenteye-orgctl org rename` (см. §7.6) эти параметры игнорируются. Слаг должен быть 1-40 строчных буквоцифровых символов с одиночными внутренними дефисами. Оставьте оба неустановленными, чтобы сохранить общий `default`. | + +> **Сохраните учетные данные SMTP в менеджер секретов.** + +**Проверьте это:** + +```bash +kubectl get secret agenteye-auth -n agenteye \ + -o jsonpath='{.data}' | grep -o '"[A-Z_]*"' | sort -u +``` + +Ожидается: ключи, которые вы заполнили, появляются в выводе. + +--- + +### 2.6 Ключ изоляции организаций для нескольких клиентов (опционально) + +Пропустите это для развертывания с одним клиентом; сервер работает на встроенной разработке по умолчанию и отлично служит одной организации `default`. **Перед созданием второй организации** установите сильный, стабильный `ORG_CH_SECRET`: пароль ClickHouse каждой организации получается как `HMAC(ORG_CH_SECRET, org_id)`, поэтому общедоступное значение разработки по умолчанию дало бы общедоступные производные учетные данные для каждой организации. Команда `agenteye-orgctl org create` (см. [§7.6 Подготовка организаций](#76-подготовка-организаций-несколько-клиентов)) отказывается запускаться, пока сервер остается на встроенном значении разработки по умолчанию. + +```bash +kubectl create secret generic agenteye-org-ch-secret \ + --namespace agenteye \ + --from-literal=ORG_CH_SECRET="$(openssl rand -base64 48)" + +# Перезагрузите сервер, чтобы он подхватил новое значение. +kubectl -n agenteye rollout restart deployment/server +``` + +Сервер читает это через **опциональный** `secretKeyRef`, поэтому кластер с одним клиентом, который никогда его не создает, все еще нормально запускается. Держите значение **стабильным и идентичным во всех репликах**; его ротация делает недействительным пароль производного ClickHouse каждой организации до тех пор, пока переинициализация начальной загрузки не переприведет пользователей (перезагрузка с постоянным значением везде заживает его). См. `deploy/base/server/secret.example.yaml`. + +> **Сохраните `ORG_CH_SECRET` в менеджер секретов и не ротируйте его случайно.** + +--- + +### 2.7 Проверка всех секретов + +```bash +kubectl get secrets -n agenteye -o custom-columns='NAME:.metadata.name,TYPE:.type' +``` + +Ожидаемый выход (среди любых стандартных секретов): + +``` +NAME TYPE +agenteye-admin-key Opaque +agenteye-auth Opaque +agenteye-image-pull kubernetes.io/dockerconfigjson +agenteye-postgres Opaque +agenteye-org-ch-secret Opaque # только если вы завершили §2.6 (несколько клиентов) +``` + +Четыре основных секрета (`agenteye-admin-key`, `agenteye-auth`, `agenteye-image-pull`, `agenteye-postgres`) должны присутствовать перед продолжением. `agenteye-org-ch-secret` требуется только для развертываний с несколькими клиентами (см. §2.6). + +--- + +## Этап 3 -- Развертывание приложения (~5 мин) + +### 3.1 Конфигурирование общедоступных имен хостов + +cert-manager нужны имена хостов приема и панели перед запросом их сертификатов Let's Encrypt. Скопируйте шаблон и установите оба: + +```bash +cp base/certificates/domain.env.example base/certificates/domain.env +# Отредактируйте base/certificates/domain.env и установите: +# INGEST_DOMAIN=ingest.your-company.example (разрешает на общественный LB Traefik) +# DASHBOARD_DOMAIN=agenteye.your-company.example (разрешает на LB Traefik панели) +``` + +`domain.env` находится в gitignore; это остается локально для каждого развертывания. Сборка kustomize громко не срабатывает, если один из ключей отсутствует. + +> **DNS должен сначала разрешиться.** Вам не нужно указывать DNS на LB'ы сейчас (они не существуют до завершения этапа 1.2), но выпуск ACME на шаге 3.2 будет повторно пытаться до тех пор, пока каждое имя хоста разрешится на его LoadBalancer. Вы можете либо установить DNS сейчас (используя имена хостов LB, захваченные на этапе 1.4), либо продолжить и добавить записи на этапе 4. + +--- + +### 3.2 Применение манифестов + +Примените базу непосредственно для нового установления или overlay если вы его вырезали для этой среды (overlay'ы просто закрепляют теги образов, переменные среды и лимиты ресурсов; они наследуют сертификаты и маршрутизацию базы): + +```bash +kubectl apply -k base/ +# или +kubectl apply -k overlays// +``` + +Overlay включает базу автоматически; примените один, не оба. + +--- + +### 3.3 Ожидание pod'ов + +```bash +kubectl wait --for=condition=Ready pod -l 'app in (server,dashboard,postgres,clickhouse)' \ + -n agenteye --timeout=180s +``` + +Ожидание ограничено основными pod'ами уровня данных. Опциональные pod'ы `agent` (AI помощник) и `redis` появляются рядом с ними; помощник остается неактивным до предоставления его конечной точки LLM (см. [enterprise-docs/assistant.md](/ru/agenteye/assistant)), а Redis является кэшем, лучшего качества, поэтому ни то, ни другое не нужно готовиться для платформы для обслуживания трафика. + +**Проверьте это:** + +```bash +kubectl get pods -n agenteye +``` + +Ожидается (опциональные pod'ы `agent` и `redis` также появляются и достигают `Running`): + +``` +NAME READY STATUS RESTARTS AGE +agent-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +clickhouse-0 1/1 Running 0 ... +dashboard-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +dashboard-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +postgres-0 1/1 Running 0 ... +redis-0 1/1 Running 0 ... +server-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +server-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +``` + +**Если не удалось:** + +| Статус Pod'а | Вероятная причина | Команда отладки | +|---|---|---| +| `ImagePullBackOff` | Плохой секрет для извлечения образа или PAT | `kubectl describe pod -n agenteye` | +| `CrashLoopBackOff` | Плохие переменные среды (например, DATABASE_URL) | `kubectl logs -n agenteye` | +| `Pending` | Недостаточно CPU/памяти или нет узлов | `kubectl describe pod -n agenteye` (проверьте Events) | + +--- + +### 3.4 Проверка хранилища + +```bash +kubectl get pvc -n agenteye +``` + +Ожидается оба со статусом `Bound`: + +| PVC | Емкость | Основа | +|---|---|---| +| `postgres-data-postgres-0` | `50Gi` | Хранилище реляционных данных/метаданных PostgreSQL | +| `clickhouse-data-clickhouse-0` | `100Gi` | Хранилище аналитики событий + оценок ClickHouse | + +PVC `redis-data-redis-0` (1Gi) также появляется для опционального кэша. + +**Если не удалось:** `Pending` означает, что ни один StorageClass не может выделить том. Проверьте `kubectl get storageclass` и убедитесь, что существует по умолчанию. Для производства наложите том ClickHouse на быстрый SSD StorageClass (например, gp3 на AWS, pd-ssd на GCP); пропускная способность сжатия страдает на медленных дисках. + +--- + +### 3.5 Проверка сертификатов + +```bash +kubectl get certificates -n agenteye +``` + +Ожидается: 3 сертификата, все `Ready: True`: + +| Имя | Издатель | Назначение | +|---|---|---| +| `mtls-ca` | `selfsigned` | Приватный CA для выпуска сертификатов клиента mTLS (валидность 10 лет) | +| `ingest-tls` | `letsencrypt-prod` | Общедоступный TLS сертификат для конечной точки приема (90 дней, автоматическое обновление) | +| `dashboard-tls` | `letsencrypt-prod` | Общедоступный TLS сертификат для панели (90 дней, автоматическое обновление) | + +**Если `ingest-tls` или `dashboard-tls` не готов:** + +`kubectl describe certificate -n agenteye` и прочитайте Events. Общие причины: + +- **DNS еще не указывает на LB.** Let's Encrypt разрешает имя хоста и попадает на порт 80 для валидации — `INGEST_DOMAIN` должен разрешиться на общественный LB, `DASHBOARD_DOMAIN` на LB панели. До распространения CNAME/Alias заказ остается `pending`. После правильного DNS cert-manager автоматически повторит попытку (не нужно удалять Certificate). +- **Имя хоста не заменено.** Если `dnsNames` все еще читает `INGEST_DOMAIN_PLACEHOLDER` / `DASHBOARD_DOMAIN_PLACEHOLDER`, вы пропустили шаг 3.1 -- создайте `base/certificates/domain.env` и повторно примените. +- **Traefik панели не может обслужить вызов** (только `dashboard-tls`). Экземпляр Traefik панели должен быть установлен с поставляемым файлом значений (этап 1.2), который включает поставщика Ingress с областью видимости, который обслуживает решатель HTTP-01 cert-manager. Экземпляр установленный без этого оставляет вызов неуспешным и заказ `pending` навечно. + +**Если `mtls-ca` не готов:** cert-manager сам неисправен. Повторно проверьте pod'ы cert-manager из шага 1.1. + +--- + +### 3.6 Проверка CronJob'ов + +```bash +kubectl get cronjobs -n agenteye +``` + +Ожидается: + +| Имя | Расписание | Назначение | +|---|---|---| +| `agenteye-backup` | `0 3 * * *` | Ежедневная резервная копия Postgres + ClickHouse в 03:00 UTC | +| `cert-renewal-check` | `0 3,15 * * *` | Предупреждения об истечении сертификата в 03:00 и 15:00 UTC | + +--- + +### 3.7 Проверка правильного запуска сервера + +```bash +kubectl logs -n agenteye -l app=server --tail=20 +``` + +**Проверьте это:** Ищите строку запуска, указывающую на то, что сервер прослушивает порт 8080. Не должно быть ошибок подключения к базе данных (сервер требует досягаемости и PostgreSQL, и ClickHouse перед отчетом Ready). + +**Если не удалось:** Наиболее распространенная причина - `POSTGRES_PASSWORD` содержит символы, небезопасные для URL, которые нарушают `DATABASE_URL`. См. [enterprise-docs/troubleshooting.md](/ru/agenteye/troubleshooting). + +--- + +### 3.8 Проверка подключения панели к серверу + +```bash +kubectl logs -n agenteye -l app=dashboard --tail=20 +``` + +**Проверьте это:** Ищите `Ready` в выводе без `ECONNREFUSED` или аналогичных ошибок. + +**Если не удалось:** Проверьте, что Service `server` существует (`kubectl get svc server -n agenteye`) и что `AGENTEYE_SERVER_URL` установлена на `http://server:8080` в развертывании панели. + +--- + +## Этап 4 -- Сетевой доступ (~5 мин) + +### 4.1 Получение адресов LoadBalancer'ов + +```bash +PUBLIC_IP=$(kubectl get svc -n traefik-public \ + -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') + +INTERNAL_IP=$(kubectl get svc -n traefik-dashboard \ + -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') +``` + +> На AWS EKS LoadBalancer'ы возвращают имя хоста вместо IP-адреса. Замените `.ip` на `.hostname` в командах выше. + +**Проверьте это:** + +```bash +echo "Public (ingest): $PUBLIC_IP" +echo "Internal (dashboard): $INTERNAL_IP" +``` + +Оба должны быть не пусты. + +--- + +### 4.2 Точка DNS на LoadBalancer'ы + +Создайте записи DNS так, чтобы имена хостов из `base/certificates/domain.env` разрешались на их LoadBalancer'ы — `INGEST_DOMAIN` на **общественный** LB Traefik, `DASHBOARD_DOMAIN` на LB **панели** Traefik: + +- **AWS Route 53:** запись `A` с `Alias = Yes`, цель = имя хоста LB. Не используйте простой A → IP; IP ELB ротируются. +- **Любой другой поставщик:** `CNAME` от имени хоста к имени хоста LB. + +Проверьте: + +```bash +dig +short ingest.your-company.example +dig +short agenteye.your-company.example +``` + +Должны возвращать те же адреса, что и `$PUBLIC_IP` и `$INTERNAL_IP` соответственно (или на EKS разрешаться на то же имя хоста `*.elb.amazonaws.com`). + +После разрешения DNS cert-manager завершит ожидающие заказы ACME из этапа 3.5 в течение минуты. Повторно запустите `kubectl get certificates -n agenteye` пока оба `ingest-tls` и `dashboard-tls` не покажут `Ready: True`. + +--- + +### 4.3 Достижение конечной точки приема + +Общественная конечная точка приема обеспечивает взаимный TLS, поэтому каждый запрос (включая `/health`) должен представить сертификат клиента. Вы выпускаете первый сертификат клиента на этапе 5; если у вас уже есть, проверьте достижимость сейчас: + +```bash +curl -s --cert issued//client.crt \ + --key issued//client.key \ + https://ingest.your-company.example/health +``` + +Ожидается: `{"status":"ok"}`. Не требуется `-k` -- сертификат сервера цепляется к общедоступному CA для `INGEST_DOMAIN`, поэтому он проверяется в системном хранилище доверия. Достигайте конечной точки приема по ее имени хоста `INGEST_DOMAIN` (которое совпадает с выпущенным сертификатом), не по сырому IP/имени хоста LoadBalancer'а. + +Конечная точка панели обслуживается на `DASHBOARD_DOMAIN` с общедоступно доверенным сертификатом и не находится за mTLS, поэтому не требуются `-k` и сертификат клиента: + +```bash +curl -s https://agenteye.your-company.example/ -o /dev/null -w '%{http_code}\n' +``` + +Достигайте панели по ее имени хоста, не по сырому адресу LB — сертификат привязан к `DASHBOARD_DOMAIN`, поэтому сырой адрес показывает несоответствие имени сертификата. + +**Если не удалось:** Если `curl` зависает, проверьте, достижим ли LB с вашей машины (VPN, группы безопасности, правила брандмауэра). Ошибка `certificate required` в рукопожатии на имени хоста приема означает, что сертификат клиента не был представлен; сначала завершите этап 5. Ошибка проверки TLS на имени хоста приема означает, что сертификат сервера еще не закончил выпуск; вернитесь к этапу 3.5 и решите проблему там. + +--- + +## Этап 5 -- Выпуск сертификатов клиента mTLS (~10 мин на кластер) + +Сборщики аутентифицируются с **двумя факторами**: сертификатом клиента (транспортный слой, доказывает, что запрос приходит от авторизованного кластера) и ключом API (уровень приложения, доказывает, что запрос от сборщика с разрешением `events:add`). Утечка ключа бесполезна без сертификата; украденный сертификат бесполезен без действительного ключа. + +### 5.1 Выпуск сертификата + +Каждый кластер, запускающий сборщики, нуждается в своем собственном сертификате клиента. Из каталога манифестов: + +```bash +cd base/certificates/client-certs +./issue-client-cert.sh +``` + +Замените `` на значимый идентификатор (например, `us-east-1-prod`, `staging`). + +**Проверьте это:** Скрипт выводит `==> Done!` и перечисляет файлы вывода. + +```bash +kubectl get certificate mtls-client- -n agenteye +``` + +Ожидается: `Ready: True`. + +Файлы вывода в `issued//`: + +| Файл | Назначение | +|---|---| +| `client.crt` | Сертификат клиента (валидность 90 дней) | +| `client.key` | Приватный ключ клиента | +| `ca.crt` | Сертификат CA для проверки сервера | +| `collector-mtls-secret.yaml` | Готовый к применению Kubernetes Secret для кластера сборщика | + +--- + +### 5.1b Альтернативная доставка: AWS Secrets Manager + +Если потребитель сертификата - это Kubernetes Pod'а, которому нужны `client.crt` и `client.key` на диске -- типичный случай, когда вы запускаете agenteye-collector как sidecar в pod'е приложения -- отправьте пакет сертификата в AWS Secrets Manager. Pod приложения затем подключает его через [Secrets Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/) с IRSA, и ротация сертификата полностью безрук. + +```bash +cd base/certificates/client-certs +export AWS_REGION=us-east-1 # регион где запускается ваша рабочая нагрузка +./issue-client-cert.sh --save-to aws-secrets-manager +``` + +При повторном запуске (обновление) скрипт вызывает `PutSecretValue` на том же секрете, поэтому ARN и имя остаются стабильными. CSI Driver подхватывает новую версию на следующей ротации опроса и переписывает файлы внутри pod'а. + +**Предварительные условия:** + +- `aws` CLI v2 аутентифицированный для вашего аккаунта AWS. +- `jq` установлен. +- Переменная окружения `AWS_REGION` установлена. +- IAM разрешения на вашей идентификации вызывающей (область видимости `Resource` к `arn:aws:secretsmanager:::secret:agenteye/mtls-client/*`): + - `secretsmanager:CreateSecret` + - `secretsmanager:DescribeSecret` + - `secretsmanager:PutSecretValue` + - `secretsmanager:TagResource` + +**Что делает скрипт в этом режиме:** + +| Шаг | Действие | +|---|---| +| 1 | Выпускает / переизвлекает сертификат через cert-manager (то же, что режим по умолчанию). | +| 2 | Вызывает `DescribeSecret` на `agenteye/mtls-client/` для решения о создании против обновления. | +| 3 | При первом запуске: `CreateSecret` с трехключевым JSON payload (`client.crt`, `client.key`, `ca.crt`), помечено `AgentEyeCluster=`. При последующих запусках: `PutSecretValue` для публикации новой версии; тег обновлен через `TagResource`. | +| 4 | Удаляет `issued//` только после успешной загрузки. При любом отказе каталог сохраняется, так что вы можете повторить попытку. | + +**Если секрет запланирован на удаление**, скрипт не срабатывает с четким сообщением об ошибке, сообщающим вам запустить `aws secretsmanager restore-secret --secret-id agenteye/mtls-client/` перед повтором. + +Для полной кабельной разводки pod'а (SecretProviderClass, настройка IRSA, поведение ротации, устранение неполадок) см. [enterprise-docs/single-pod-deployment.md](/ru/agenteye/single-pod-deployment). + +--- + +### 5.2 Проверка работы сертификата + +Протестируйте выпущенный сертификат против входящего mTLS: + +```bash +curl -sk --cert issued//client.crt \ + --key issued//client.key \ + https://${PUBLIC_IP}/health +``` + +Ожидается: `{"status":"ok"}` + +**Если не удалось:** + +| Ошибка | Причина | Исправление | +|---|---|---| +| `certificate required` | Сертификат не представляется | Проверьте пути к файлам в команде `curl` | +| `bad certificate` | Несоответствие CA | Проверьте, что `mtls-ca-issuer` выпустил сертификат: `kubectl describe certificate mtls-client- -n agenteye` | +| `connection refused` | Неправильное имя хоста или LB недостижим | Проверьте `/etc/hosts` или DNS | + +--- + +### 5.3 Доставка в кластер сборщика + +Отправьте `collector-mtls-secret.yaml` команде, эксплуатирующей кластер сборщика. Они применяют его: + +```bash +kubectl apply -f collector-mtls-secret.yaml -n +``` + +Затем настройте сборщик на подключение секрета и использование путей сертификата: + +```json +{ + "tls_cert": "/etc/agenteye/tls/client.crt", + "tls_key": "/etc/agenteye/tls/client.key" +} +``` + +Полная установка сборщика включая подключение тома Kubernetes см. в [enterprise-docs/collector-installation.md](/ru/agenteye/collector-installation). + +**Проверьте это (в кластере сборщика):** + +```bash +kubectl get secret agenteye-collector-mtls -n +``` + +Ожидается: секрет существует с 3 ключами данных (`client.crt`, `client.key`, `ca.crt`). + +--- + +### 5.4 Жизненный цикл сертификата + +| Свойство | Значение | +|---|---| +| Валидность сертификата клиента | 90 дней | +| Автоматическое обновление | cert-manager обновляет за 15 дней до истечения | +| Валидность CA | 10 лет | +| Предупреждения об истечении | CronJob предупреждает за 30 дней до истечения (этап 6) | + +cert-manager автоматически обновляет сертификат на **кластере AgentEye**, но обновленный сертификат должен быть доставлен на кластер сборщика. Повторно запустите `issue-client-cert.sh` и повторно примените `collector-mtls-secret.yaml` перед истечением старого сертификата. + +Если вы используете `--save-to aws-secrets-manager` (см. § 5.1b), повторно запустите ту же команду. Скрипт вызывает `PutSecretValue` на том же секрете; pod'ы подключающие секрет через Secrets Store CSI Driver подхватывают новую версию на следующем опросе ротации (по умолчанию: каждый час), без перезагрузки pod'а. + +--- + +### 5.5 Отзыв сертификата + +Для немедленной блокировки доступа сборщика кластера: + +```bash +kubectl delete certificate mtls-client- -n agenteye +``` + +**Проверьте это:** Команда `curl` из шага 5.2 теперь не срабатывает с ошибкой рукопожатия TLS. + +--- + +## Этап 6 -- Мониторинг обновления сертификата (~2 мин) + +Встроенный CronJob запускается каждые 12 часов (03:00 и 15:00 UTC) и проверяет все сертификаты клиента с меткой `agenteye.io/cert-type=mtls-client`. Он предупреждает, когда какой-либо сертификат находится в пределах 30 дней до истечения. + +### 6.1 Включение уведомлений Slack (опционально) + +```bash +kubectl create secret generic cert-renewal-notify-config \ + --namespace agenteye \ + --from-literal=SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL" +``` + +Без этого секрета CronJob все еще запускается и заносит статус сертификата в stdout. + +**Проверьте это:** + +```bash +kubectl get secret cert-renewal-notify-config -n agenteye +``` + +Ожидается: секрет существует. + +--- + +### 6.2 Проверка CronJob'а + +```bash +kubectl create job --from=cronjob/cert-renewal-check test-cert-check -n agenteye + +kubectl wait --for=condition=Complete job/test-cert-check -n agenteye --timeout=60s + +kubectl logs -n agenteye -l job-name=test-cert-check +``` + +Ожидается: список сертификатов с их статусом истечения. Если webhook Slack настроен, проверьте канал Slack на предмет сообщения предупреждения. + +**Если не удалось:** Проверьте RBAC -- ServiceAccount CronJob'а нуждается в разрешениях `get, list` на ресурсах Certificate cert-manager. Проверьте с: `kubectl describe role cert-renewal-check -n agenteye`. + +Очистите тестовое задание: + +```bash +kubectl delete job test-cert-check -n agenteye +``` + +--- + +## Этап 7 -- Проверка end-to-end + +Этот этап подтверждает, что вся конвейер работает: проверка здоровья, создание ключей, прием событий и отображение панели. + +> **Примечание:** Примеры ниже достигают конечной точки приема по ее сырому адресу LoadBalancer'а (`${PUBLIC_IP}`) для удобства, поэтому они передают `-k`; сертификат сервера привязан к `INGEST_DOMAIN`, не к IP LB, поэтому проверка имени хоста пропускается. Конечная точка приема обеспечивает взаимный TLS на **каждом** пути, поэтому каждый вызов также должен представить сертификат клиента (`--cert`/`--key`). Для также проверки общедоступного сертификата целевой `https://ingest.your-company.example/...` вместо `${PUBLIC_IP}` и удалите `-k`. + +### 7.1 Проверка здоровья + +```bash +curl -sk --cert issued//client.crt \ + --key issued//client.key \ + https://${PUBLIC_IP}/health +``` + +Ожидается: `{"status":"ok"}` с HTTP 200. + +--- + +### 7.2 Создание областных ключей сборщика + +Ключ администратора предназначен для начальной загрузки и управления. Создайте выделенные ключи `events:add` для сборщиков: + +```bash +COLLECTOR_KEY=$(openssl rand -hex 32) + +curl -sk -X POST https://${PUBLIC_IP}/keys \ + --cert issued//client.crt \ + --key issued//client.key \ + -H "Authorization: Bearer ${ADMIN_KEY}" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "prod-collector", + "key": "'"${COLLECTOR_KEY}"'", + "permissions": ["events:add"] + }' +``` + +**Проверьте это:** Ответ включает `"id"`, `"name": "prod-collector"`, `"permissions": ["events:add"]`, `"created_at"`. + +**Проверьте это:** Убедитесь, что ключ появляется в списке ключей: + +```bash +curl -sk https://${PUBLIC_IP}/keys \ + --cert issued//client.crt \ + --key issued//client.key \ + -H "Authorization: Bearer ${ADMIN_KEY}" +``` + +Ожидается: `prod-collector` появляется в ответе. + +Полный справочник управления ключей см. в [enterprise-docs/api-keys.md](/ru/agenteye/api-keys). + +--- + +### 7.3 Прием тестового события + +```bash +echo '{"session_id":"test","agent_id":"smoke-test","type":"test","timestamp":"2026-04-20T00:00:00Z"}' \ + | curl -sk --cert issued//client.crt \ + --key issued//client.key \ + -H "Authorization: Bearer ${COLLECTOR_KEY}" \ + -H "Content-Type: application/x-ndjson" \ + --data-binary @- \ + https://${PUBLIC_IP}/events +``` + +Ожидается: `{"accepted":1,"skipped":0}` с HTTP 200. + +**Если не удалось:** + +| HTTP статус | Причина | +|---|---| +| 401 | Недействительный или отсутствующий ключ API | +| 403 | Ключу не хватает разрешения `events:add` | +| Ошибка рукопожатия TLS | Проблема с сертификатом клиента -- см. устранение неполадок этапа 5 | + +--- + +### 7.4 Проверка появления события на панели + +Откройте `https://agenteye.your-company.example` (ваш `DASHBOARD_DOMAIN`) в браузере. Сертификат общедоступно доверенный, поэтому нет предупреждения. + +> Если LB панели ограничен списком разрешенных IP-адресов и вы не можете подключиться, проверьте, что ваш IP разрешен: +> ```bash +> kubectl get svc traefik-dashboard -n traefik-dashboard -o jsonpath='{.spec.loadBalancerSourceRanges}' +> ``` +> Помните, что Let's Encrypt обновляет сертификат панели через HTTP-01 на порту 80, и диапазоны источников применяются ко всему LoadBalancer'у -- перед ограничением его корпоративными диапазонами согласуйте решатель DNS-01 с поддержкой или обнов \ No newline at end of file diff --git a/docs/ru/agenteye/managed-deployment.mdx b/docs/ru/agenteye/managed-deployment.mdx new file mode 100644 index 00000000..5084879b --- /dev/null +++ b/docs/ru/agenteye/managed-deployment.mdx @@ -0,0 +1,171 @@ +--- +title: "Управляемое развёртывание в вашем кластере Kubernetes" +description: "Документация по управляемому развёртыванию AgentEye в вашем кластере Kubernetes." +--- + + +AgentEye — это самостоятельно развёртываемая платформа наблюдения и оценки для AI и LLM агентов. Она фиксирует сеансы агентов, вызовы инструментов, запросы к моделям и ошибки, преобразует их в доступные для поиска аналитику и оценки, и отображает результаты в панели управления с опциональным помощником AI только для чтения. + +В модели управляемого развёртывания вы предоставляете выделенный кластер Kubernetes, а Exosphere запускает полную платформу внутри него, развёртывая, настраивая, управляя, выполняя резервное копирование и обновляя каждый компонент от вашего имени. Ваша команда получает преимущества платформы (видимость агентов, аналитику, оценку и опциональный помощник) без необходимости управлять базами данных, сертификатами и обновлениями. Все данные остаются в вашей облачной учётной записи. + +--- + +## Предварительные требования + +- **GitHub PAT** для загрузки образов контейнеров и скачивания артефактов (см. [Настройка GitHub Token](/ru/agenteye/github-token)) +- **Выделенный кластер Kubernetes** (см. требования ниже) +- **Хранилище для резервных копий** баз данных +- **Сетевая связность**: входящий трафик на порт 443 к балансировщику нагрузки кластера + +--- + +## Шаг 1: Подготовка выделенного кластера Kubernetes + +Создайте кластер Kubernetes, выделенный для AgentEye. Он не должен быть общим с другими рабочими нагрузками, чтобы полная платформа (сервисы приложения, базы данных, аналитика и кэширование) работала в изоляции без влияния на вашу существующую инфраструктуру. + +| Требование | Детали | +|---|---| +| **Дистрибутив** | Любой совместимый Kubernetes: EKS, GKE, AKS или самоуправляемый | +| **Версия** | 1.27 или выше | +| **Пул узлов** | Минимум: **3 узла, 4 vCPU / 8 ГБ ОЗУ каждый** (стандартные экземпляры общего назначения) | +| **Хранилище** | Класс StorageClass по умолчанию, который выделяет блочные тома (например `gp3` на AWS, `pd-ssd` на GCP) | +| **Балансировщик нагрузки** | Кластер должен иметь возможность выделять облачные сервисы LoadBalancer (по умолчанию на EKS, GKE, AKS) | + +> Exosphere устанавливает и управляет всем остальным внутри кластера: контроллеры ingress, сертификаты TLS, базы данных, кэширование, мониторинг и все развёртывания приложения. + +--- + +## Шаг 2: Предоставление доступа команде AgentEye + +Exosphere требуется доступ cluster-admin (или эквивалентный широкий RBAC) для управления пространствами имён, определениями пользовательских ресурсов, контроллерами ingress и провизионерами хранилища. + +| Требование | Детали | +|---|---| +| **Метод доступа** | Роль IAM (предпочтительно для EKS/GKE), kubeconfig или доступ на основе SSO | +| **VPN / bastion** | Если сервер API Kubernetes приватный, предоставьте учётные данные VPN или доступ к bastion для операционной группы Exosphere | + +--- + +## Шаг 3: Настройка сетевой связности + +Ваша сетевая группа должна разрешить входящий трафик на **порт 443** к балансировщикам нагрузки кластера. Развёртывание использует два отдельных балансировщика нагрузки: один для приёма событий (защищённый mTLS) и один для панели управления: + +| Трафик | Источник | Назначение | Безопасность | +|---|---|---|---| +| **Приём событий** | Подсистемы сборщика в ваших кластерах | Балансировщик Ingest LoadBalancer, порт 443 | mTLS (клиентский сертификат) + API ключ | +| **Панель управления** | Браузеры разработчиков | Балансировщик Dashboard LoadBalancer, порт 443 | HTTPS на вашем домене, вход без пароля с OTP по электронной почте | + +Конечная точка приёма защищена взаимным TLS; сборщики должны предоставлять действительный клиентский сертификат **и** действительный API ключ при каждом запросе. Панель управления работает на отдельном балансировщике нагрузки и хостнейме с ограничением входа на внесённые в список разрешённые адреса электронной почты и домены. + +**DNS записи (одноразово):** вы создаёте две CNAME записи под доменом, который вы контролируете — одну для конечной точки приёма и одну для панели управления (например `agenteye.your-company.example`) — указывающие на хостнеймы балансировщика нагрузки, которые предоставляет Exosphere. Exosphere затем автоматически выделяет общедоступные доверенные сертификаты TLS для обоих хостнеймов, включая обновления. + +> **Примечание о порте 80:** автоматическое выделение сертификатов и их обновление проверяются через HTTP на порту 80 каждого балансировщика нагрузки. Если ваша политика безопасности требует ограничения балансировщика нагрузки панели управления диапазонами корпоративных IP, сообщите об этом Exosphere сначала — мы переключимся на метод проверки на основе DNS (одна дополнительная DNS запись на вашей стороне), чтобы обновления продолжали работать за ограничением. + +> **Исходящий трафик:** узлы кластера требуют доступ в интернет для загрузки образов контейнеров из `ghcr.io`. Если ваша сеть ограничивает исходящий трафик, добавьте `ghcr.io` в список разрешённых или зеркалируйте образы в ваш внутренний реестр. + +--- + +## Шаг 4: Предоставление хранилища для резервных копий + +Резервные копии баз данных хранятся в облачном хранилище, которым вы владеете. + +| Требование | Детали | +|---|---| +| **Сервис** | S3 (AWS), GCS (GCP) или Azure Blob Storage | +| **Доступ** | Предоставьте доступ на запись узлам кластера через роль IAM для сервисных учётных записей (IRSA на EKS, Workload Identity на GKE) или предоставьте учётные данные | +| **Хранение** | Вы контролируете политику жизненного цикла хранилища (период хранения, правила архивации). Exosphere пишет резервные копии; вы решаете, как долго их хранить | + +Одна ежедневная резервная копия выгружает PostgreSQL (состояние отношений) и ClickHouse (события и оценки) в один сжатый архив и загружает его в ваше хранилище. Резервные копии также выполняются перед каждым обновлением. + +--- + +## Шаг 5: Назначение ответственного + +Предоставьте одного человека или канал Slack/Teams на вашей стороне для проблем уровня кластера: здоровье узлов, лимиты облачной учётной записи, изменения сети. Ежедневные операции не требуют участия этого контакта. + +--- + +## Что мы развёртываем + +Когда Exosphere получит доступ к кластеру, будут развёрнуты и управляться следующие компоненты: + +| Компонент | Роль | +|---|---| +| **AgentEye Server** | HTTP API, который получает события от сборщиков, запускает аналитику и обслуживает данные панели управления | +| **Панель управления** | Веб-интерфейс для просмотра сеансов агентов, вызовов инструментов, запросов к моделям и ошибок; размещает опциональный помощник AI только для чтения | +| **ClickHouse** | Требуемое основное хранилище для полученных событий, аналитики и оценок | +| **PostgreSQL** | Хранилище отношений для организаций, API ключей, пользователей, панелей управления и сохранённых запросов | +| **Redis** | Опциональный общий кэш и бэкенд для ограничения скорости; платформа деградирует корректно при его недоступности | +| **Помощник AI (опционально)** | Внутренний контейнер помощника только для чтения; остаётся отключённым до настройки конечной точки LLM | +| **Контроллеры ingress** | Два балансировщика нагрузки (один для защищённого mTLS приёма, один для панели управления) прерывающие TLS с общедоступными доверенными сертификатами с автоматическим обновлением и принуждающие mTLS на конечной точке приёма | +| **cert-manager** | Автоматизирует выделение сертификатов TLS и выделение клиентских mTLS сертификатов | +| **Мониторинг сертификатов** | Запланированное задание проверяет срок действия сертификатов и отправляет оповещения (например в Slack) по мере приближения обновлений сертификатов | + +Управляемое предложение также работает с конвейером оценки платформы, который оценивает активность агента по вашим критериям оценки. Смотрите [Assistant](/ru/agenteye/assistant) и [Evaluation Suite](/ru/agenteye/evaluation-suite) для информации о возможностях. + +--- + +## Что мы предоставляем вам + +После завершения развёртывания вы получаете: + +| Элемент | Детали | +|---|---| +| **URL панели управления** | Хостнейм под вашим доменом (например `https://agenteye.your-company.example`), обслуживаемый с общедоступным доверенным сертификатом TLS с автоматическим обновлением. Вы создаёте одну CNAME запись на хостнейм балансировщика нагрузки, который мы предоставляем; вход осуществляется через OTP по электронной почте без пароля | +| **Конечная точка сборщика** | Путь `/events` хостнейма приёма (например `https://ingest.your-company.example/events`), защищённый mTLS | +| **Пакет клиентского сертификата** | За кластер: клиентский сертификат, приватный ключ и сертификат CA поставляются как манифест Kubernetes Secret. Применяется один раз за кластер | +| **GitHub PAT** | Для загрузки бинарных файлов сборщика и пакетов Python SDK | +| **API ключи сборщика** | Ограниченные ключи с разрешением `events:add`, по одному на развёртывание сборщика | +| **Руководства по установке** | Пошаговая документация для сборщика и Python SDK | + +--- + +## Что вы делаете после установки + +Ваша единственная текущая работа — на ваших собственных машинах с агентами, а не на кластере AgentEye: + +1. **Установите сборщик** в каждый кластер Kubernetes, работающий с AI агентами: смонтируйте клиентский сертификат и настройте URL конечной точки и API ключ. Смотрите [Collector Installation](/ru/agenteye/collector-installation). +2. **Интегрируйте Python SDK** в код вашего агента. Смотрите [Python SDK](/ru/agenteye/python-sdk). +3. **Откройте панель управления** в браузере для просмотра активности агента. + +Никаких операций с кластером, никакого управления базами данных, никаких обновлений сертификатов, никаких обновлений. + +--- + +## Безопасность + +- **Данные остаются в вашей облачной учётной записи.** Кластер, хранилище и базы данных все работают в вашей среде. Никакие данные не выходят за вашу границу. +- **Вы контролируете доступ.** Кластер находится в вашей учётной записи. Вы можете проверять, мониторить или отозвать доступ Exosphere в любое время. Все операции проходят через журнал аудита вашего облака (CloudTrail, GCP Audit Logs и т.д.). +- **mTLS при приёме событий.** Каждый запрос сборщика требует как действительный клиентский сертификат, так и API ключ. Утёкший ключ бесполезен без сертификата; украденный сертификат бесполезен без действительного ключа. +- **Контроль доступа к панели управления.** Панель управления работает на отдельном балансировщике нагрузки, отдельно от приёма событий, и вход осуществляется через OTP по электронной почте без пароля, ограниченный адресами электронной почты и доменами, которые вы внесли в список разрешённых. Ограничение диапазона источника IP на балансировщике нагрузки доступно по запросу; так как автоматическое обновление сертификата должно достичь балансировщика нагрузки, Exosphere сочетает ограничение с проверкой сертификата на основе DNS, чтобы обновления продолжали работать. +- **Сертификаты за кластер.** Каждый из ваших кластеров получает собственный клиентский сертификат. Если один кластер скомпрометирован, этот сертификат отзывается независимо без влияния на остальные. + +--- + +## График развёртывания + +| Фаза | Длительность | Ваше участие | +|---|---|---| +| **Подготовка кластера** | 1-2 дня | Подготовьте кластер и предоставьте Exosphere доступ | +| **Настройка платформы** | 1 день | Нет; Exosphere устанавливает все компоненты инфраструктуры | +| **Развёртывание приложения** | 1 день | Нет; Exosphere развёртывает сервер, панель управления и создаёт API ключи | +| **Развёртывание сборщика** | 1-3 дня | Установите сборщики в ваши кластеры (с руководством от Exosphere) | +| **Работа в production** | 1 неделя | Нет; Exosphere мониторит и настраивает | + +Обычный итог: **~2 недели** от начала до готовности к production. + +--- + +## Поддержка + +По вопросам или проблемам обратитесь в Exosphere на `support@exosphere.host`. + +--- + +## Следующие шаги + +- [Getting Started](/ru/agenteye/getting-started): сквозное руководство +- [Collector Installation](/ru/agenteye/collector-installation): установка и настройка сборщика +- [Python SDK](/ru/agenteye/python-sdk): инструментирование кода вашего агента +- [API Keys](/ru/agenteye/api-keys): управление доступом и разрешениями +- [Troubleshooting](/ru/agenteye/troubleshooting): часто встречающиеся проблемы и решения \ No newline at end of file diff --git a/docs/ru/agenteye/python-sdk.mdx b/docs/ru/agenteye/python-sdk.mdx new file mode 100644 index 00000000..491b523b --- /dev/null +++ b/docs/ru/agenteye/python-sdk.mdx @@ -0,0 +1,387 @@ +--- +title: "Python SDK" +description: "Документация AgentEye Python SDK." +--- + + +AgentEye Python SDK обеспечивает полную видимость поведения ваших агентов (каждый запуск агента, вызов инструмента, запрос к модели, хук и ручное вмешательство), что позволяет вам отлаживать, аудировать и оценивать их. Он инструментирует код вашего агента, записывая структурированные события в локальные файлы JSONL; демон-сборщик собирает их и автоматически отправляет на платформу. + +--- + +## Установка + +Загрузите wheel с GitHub Releases, используя ваш `AGENTEYE_TOKEN`. Если у вас еще нет токена, см. [GitHub Token Setup](/ru/agenteye/github-token) для описания шагов настройки и необходимых разрешений. + +**Использование `gh` CLI + pip:** + +```bash +VERSION=0.0.1b9 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "python-sdk/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-*.whl' +pip install "agenteye-${VERSION}-py3-none-any.whl" +``` + +**Использование `gh` CLI + uv:** + +```bash +VERSION=0.0.1b9 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "python-sdk/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-*.whl' +uv add "./agenteye-${VERSION}-py3-none-any.whl" +``` + +**Использование curl (без `gh` CLI):** + +```bash +VERSION=0.0.1b9 +curl -fsSL \ + -H "Authorization: Bearer $AGENTEYE_TOKEN" \ + -L \ + "https://github.com/agenteye-enterprise/releases/releases/download/python-sdk%2Fv${VERSION}/agenteye-${VERSION}-py3-none-any.whl" \ + -o "agenteye-${VERSION}-py3-none-any.whl" +pip install "agenteye-${VERSION}-py3-none-any.whl" +``` + +--- + +## Быстрый старт + +```python +import agenteye + +agenteye.configure(environment="production") + +agenteye.event.agent_start(session_id="run-001", agent_id="planner", goal="answer user query") + +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", + input={"query": "latest AI research"}, +) + +agenteye.event.tool_result( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", + output={"results": ["..."]}, +) + +agenteye.event.agent_end(session_id="run-001", agent_id="planner", outcome="success") +``` + +--- + +## configure() + +```python +agenteye.configure( + base_dir=None, # Path | str | None. По умолчанию: $AGENTEYE_HOME или ~/.agenteye + flush_interval=0.5, # float, секунды между циклами флеша + environment=None, # str | None. Метка среды развертывания +) +``` + +Вызовите один раз перед любым вызовом `event.*`. Безопасно опустить; параметры по умолчанию работают сразу. Все аргументы только именованные; передавайте их по имени, как показано выше. + +Когда `base_dir` равен `None` (по умолчанию), SDK читает `$AGENTEYE_HOME`, если установлена, +в противном случае переходит к `~/.agenteye`. Это совпадает с разрешением коллектора, +поэтому одна переменная окружения `AGENTEYE_HOME` настраивает общий пул событий для обоих +SDK и коллектора, что необходимо для развертываний sidecar / single-pod, где +оба процесса должны согласиться с путем пула. + +--- + +## Среда + +Пометьте каждое событие средой развертывания (`production`, `staging`, `qa`, `canary` и т.д.). Установите один раз; SDK автоматически прикрепляет его к каждому событию. + +**Вариант 1: через `configure()`:** + +```python +agenteye.configure(environment="production") +``` + +**Вариант 2: через переменную окружения:** + +```bash +export AGENTEYE_ENVIRONMENT=production +``` + +**Приоритет:** `configure(environment=...)` имеет приоритет над переменной окружения. Если ничего не установлено, по умолчанию равен `"dev"`. + +Значение среды появляется в качестве фильтра первого уровня в панели управления и хранится в виде индексированного столбца на сервере для быстрых запросов. + +**Ограничение:** значения среды **не должны содержать литеральную запятую `,`**. Фильтры панели управления используют разделенную запятыми мультивыборку по каналу (`?environment=prod,staging`), поэтому среда с названием `prod,blue` будет разделена на два значения. События с содержащимися запятыми окружениями отклоняются при приеме. + +--- + +## Справка по событиям + +Все методы события требуют эти два поля: + +| Поле | Тип | Описание | +|---|---|---| +| `session_id` | `str` | Идентифицирует запуск агента верхнего уровня | +| `agent_id` | `str` | Идентифицирует, какой агент в сеансе создал событие | + +Все методы также принимают произвольные `**kwargs` для пользовательских метаданных (см. [Пользовательские поля](#пользовательские-поля)). + +--- + +### `event.agent_start()` + +Создается, когда агент начинает работу. + +```python +agenteye.event.agent_start( + session_id="run-001", + agent_id="planner", + goal="answer user query", # str | None + parent_id=None, # str | None - parent_id агента для вложенных агентов +) +``` + +--- + +### `event.agent_end()` + +Создается, когда агент заканчивает работу. + +```python +agenteye.event.agent_end( + session_id="run-001", + agent_id="planner", + outcome="success", # str | None + summary="Answered query", # str | None +) +``` + +--- + +### `event.tool_use()` + +Создается, когда агент вызывает инструмент. Сопряжен с `tool_result`; SDK автоматически вычисляет `duration_ms`. + +```python +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="web_search", # str, обязательно + tool_call_id="toolu_01", # str, обязательно - ключ корреляции для соответствующего tool_result + input={"query": "..."}, # dict | None +) +``` + +--- + +### `event.tool_result()` + +Создается, когда инструмент возвращает результат. Коррелирует с `tool_use` через `tool_call_id`. + +```python +agenteye.event.tool_result( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", # должен совпадать с предыдущим tool_use + output={"results": ["..."]}, # Any | None + error=None, # str | None - установите, если инструмент вызвал ошибку + # duration_ms вычисляется автоматически - не передавайте его +) +``` + +--- + +### `event.model_request()` + +Создается непосредственно перед отправкой подсказки в LLM. + +```python +agenteye.event.model_request( + session_id="run-001", + agent_id="planner", + model="claude-sonnet-4-6", # str | None + messages=[ # list[dict] | None - ходы беседы + {"role": "user", "content": "..."}, + ], + system="You are helpful.", # Any | None - str или список блоков контента + tools=[ # list[dict] | None - схемы инструментов, предложенные модели + {"name": "search", "input_schema": {"type": "object"}}, + ], +) +``` + +Записи `messages` принимают либо простую строку `content`, либо стиль Anthropic с списком блоков `content`. Параметры выборки (`temperature`, `max_tokens` и т.д.) могут быть переданы в виде дополнительных kwargs. + +--- + +### `event.model_response()` + +Создается, когда LLM возвращает ответ. + +```python +agenteye.event.model_response( + session_id="run-001", + agent_id="planner", + model="claude-sonnet-4-6", # str | None + stop_reason="end_turn", # str | None + input_tokens=1024, # int | None + output_tokens=256, # int | None + content=[ # Any | None - str, или список блоков контента + {"type": "text", "text": "..."}, + ], + role="assistant", # str | None +) +``` + +`content` принимает либо простую строку (универсальные провайдеры), либо список блоков контента в стиле Anthropic. Вызовы инструментов находятся внутри `content` в виде блоков `{"type": "tool_use", ...}` без отдельного поля `tool_calls`. + +--- + +### `event.hook_triggered()` + +Создается, когда срабатывает хук. Сопряжен с `hook_completed`; SDK автоматически вычисляет `duration_ms`. + +```python +agenteye.event.hook_triggered( + session_id="run-001", + agent_id="planner", + hook_name="pre_tool_use", # str, обязательно + hook_id="hook-abc", # str, обязательно - ключ корреляции + trigger_event="tool_use", # str | None + input={"tool": "search"}, # Any | None +) +``` + +--- + +### `event.hook_completed()` + +Создается, когда хук завершается. Коррелирует с `hook_triggered` через `hook_id`. + +```python +agenteye.event.hook_completed( + session_id="run-001", + agent_id="planner", + hook_name="pre_tool_use", + hook_id="hook-abc", # должен совпадать с предыдущим hook_triggered + outcome="allow", # str | None + output=None, # Any | None + error=None, # str | None + # duration_ms вычисляется автоматически - не передавайте его +) +``` + +--- + +### `event.error()` + +Создается, когда происходит необработанная ошибка. + +```python +agenteye.event.error( + session_id="run-001", + agent_id="planner", + error_type="TimeoutError", # str, обязательно + message="timed out", # str, обязательно + traceback="Traceback...", # str | None +) +``` + +--- + +## События "человек в цикле" + +События "человек в цикле" дают вам надзор над моментами, когда человек вмешивается в выполнение агента (ожидание утверждения, предоставление ввода, пауза или остановка агента). Они позволяют вам измерить, сколько времени требуется людям на ответ (SDK автоматически вычисляет `duration_ms` в парных событиях), аудировать, кто приостановил или прервал агента, и создавать рабочие процессы одобрения и надзора, которые отображаются на панели управления. + +### `event.human_wait()` + +Создается, когда агент приостанавливает выполнение в ожидании ввода человеком. Сопряжен с `human_input`; SDK автоматически вычисляет `duration_ms` (как долго человек отвечал). + +```python +agenteye.event.human_wait( + session_id="run-001", + agent_id="planner", + input_id="inp-abc", # str, обязательно - ключ корреляции для соответствующего human_input + prompt="Do you approve this action?", # str | None - вопрос, показанный человеку + options=["approve", "reject", "defer"], # list[str] | None - варианты выбора, представленные человеку + reason="approval_required", # str | None - почему агент ждет +) +``` + +### `event.human_input()` + +Создается, когда человек предоставляет ввод и агент возобновляет работу. Коррелирует с `human_wait` через `input_id`. `duration_ms` вычисляется автоматически и не должен передаваться вызывающей стороной. + +```python +agenteye.event.human_input( + session_id="run-001", + agent_id="planner", + input_id="inp-abc", # str, обязательно - должен совпадать с предыдущим human_wait + response="approve", # str | None - ответ человека (свободный текст или выбранный вариант) + # duration_ms вычисляется автоматически - не передавайте его +) +``` + +### `event.human_pause()` + +Создается, когда человек активно приостанавливает агента (например, через элемент управления панели управления). Агент приостановлен, но не завершен. + +```python +agenteye.event.human_pause( + session_id="run-001", + agent_id="planner", + reason="user_requested", # str | None + user_id="usr_42", # str | None - кто приостановил агента +) +``` + +### `event.human_interrupt()` + +Создается, когда человек активно останавливает агента во время выполнения. В отличие от `human_pause`, работа агента завершается, а не приостанавливается. + +```python +agenteye.event.human_interrupt( + session_id="run-001", + agent_id="planner", + reason="output_incorrect", # str | None + user_id="usr_42", # str | None - кто прервал агента + at_step="tool_use:web_search", # str | None - что делал агент, когда был остановлен +) +``` + +--- + +## Пользовательские поля + +Любые дополнительные аргументы ключевого слова добавляются к событию после стандартных полей: + +```python +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="db_query", + tool_call_id="toolu_02", + tenant_id="acme", # пользовательское поле + region="us-east-1", # пользовательское поле +) +``` + +`timestamp`, `type` и `environment` зарезервированы и вызывают `ValueError` (`Reserved field names cannot be used as custom fields: [...]`) если переданы как пользовательские поля. `session_id` и `agent_id` являются обязательными параметрами для каждого метода события и не могут быть поданы во второй раз; Python вызывает `TypeError`, если вы это сделаете. Установите среду с помощью `configure(environment=...)` (или переменной `AGENTEYE_ENVIRONMENT`) вместо этого. + +--- + +## Как события записываются + +События буферизуются в процессе и записываются на диск каждые `flush_interval` секунд (по умолчанию 500 мс). Каждый флеш записывает один файл JSONL: + +``` +~/.agenteye/events/event-2026-04-01T12-00-00-000Z.jsonl +``` + +Коллектор наблюдает за этим каталогом и автоматически загружает файлы. Вам не нужно управлять этими файлами напрямую. \ No newline at end of file diff --git a/docs/ru/agenteye/single-pod-deployment.mdx b/docs/ru/agenteye/single-pod-deployment.mdx new file mode 100644 index 00000000..f3ba9a54 --- /dev/null +++ b/docs/ru/agenteye/single-pod-deployment.mdx @@ -0,0 +1,484 @@ +--- +title: "Развертывание на одном поде: Collector + Application Sidecar на EKS" +description: "Документация AgentEye Single-Pod Deployment: Collector + Application Sidecar на EKS." +--- + + +Запускайте ваше приложение и collector AgentEye **в одном поде Kubernetes**, чтобы телеметрия никогда не пересекала границу сети при сборе. SDK вашего приложения и collector совместно используют единую очередь событий в поде, что означает низколатентную передачу телеметрии внутри процесса без открытого порта localhost, без сетевого взаимодействия и с жизненным циклом collector'а, привязанным непосредственно к рабочей нагрузке, которую он наблюдает. Сертификат клиента mTLS, который представляет collector, доставляется прямо в ваш под из AWS Secrets Manager, поэтому ротация учетных данных не требует ручного перемещения файлов с вашей стороны. + +Модель sidecar + shared-spool, описанная здесь, независима от облачной платформы; два контейнера, совместно использующих очередь событий `emptyDir`, работают на любом дистрибутиве Kubernetes. Только путь доставки сертификата в этом руководстве (AWS Secrets Manager + Secrets Store CSI Driver + IRSA) специфичен для AWS/EKS. Если вы работаете в другом месте, сохраняйте компоновку pod'а и очереди и замените механизм монтирования секретов вашей платформы на этапы 2 и 3. + +> **Когда использовать этот паттерн.** Выбирайте single-pod, когда ваше приложение не должно обращаться через границу сети к collector'у (низколатентный in-pod IPC, тесная связь жизненных циклов, изоляция pod'а по тенантам). Для многоприложных флотов, совместно использующих один collector на узел или на кластер, см. вместо этого [enterprise-docs/kubernetes-deployment.md](/ru/agenteye/kubernetes-deployment). + +--- + +## На первый взгляд + +``` +┌──────────────────────────────── Pod ─────────────────────────────────┐ +│ │ +│ ┌──────────────────────┐ ┌──────────────────────┐ │ +│ │ your-app │ │ agenteye-collector │ │ +│ │ (SDK writes JSONL) │ │ (sweeps events/, │ │ +│ │ │ │ uploads over mTLS) │ │ +│ └──────────┬───────────┘ └──────────┬───────────┘ │ +│ │ writes reads │ │ +│ ▼ ▼ │ +│ ┌────────────────────────────────────────────────────┐ │ +│ │ emptyDir: /var/lib/agenteye/{events,failed}/ │ │ +│ │ (AGENTEYE_HOME - shared event spool) │ │ +│ └────────────────────────────────────────────────────┘ │ +│ ▲ │ +│ │ reads cert │ +│ ┌────────┴─────────┐ │ +│ │ CSI (read-only): │ │ +│ │ /etc/agenteye/ │ │ +│ │ tls/client.{crt, │ │ +│ │ key}, ca.crt │ │ +│ └────────┬─────────┘ │ +└───────────────────────────────────────────────────┼──────────────────┘ + │ mounted by + │ Secrets Store CSI + │ (AWS provider + + │ IRSA) + ┌────────┴──────────┐ + │ AWS Secrets │ + │ Manager │ + │ agenteye/mtls- │ + │ client/ │ + └────────┬──────────┘ + ▲ + │ push on issue / + │ renewal + ┌────────┴──────────┐ + │ Exosphere │ + │ delivers the cert │ + │ bundle into your │ + │ Secrets Manager │ + │ on renewal │ + └───────────────────┘ + +Outbound: collector → AGENTEYE_URL (mTLS, using the CSI-mounted cert). +``` + +Два потока данных, два тома: + +- **События (in-pod):** SDK вашего приложения записывает файлы `.jsonl` в общий `emptyDir` в `$AGENTEYE_HOME/events/`; sweeper collector'а их читает и загружает. Без порта localhost, без loopback, чистая передача через общую файловую систему. +- **Сертификат mTLS (pod ← cloud):** Secrets Store CSI Driver монтирует пакет сертификата из Secrets Manager в том только для чтения в `/etc/agenteye/tls/`, ограниченный контейнером collector'а. + +**Две независимые стороны:** + +| Сторона | Ответственность | +|---|---| +| Exosphere | Выдает сертификат клиента mTLS и доставляет пакет в **ваш** AWS аккаунт в Secrets Manager под стабильным именем. Переиздает обновленный пакет в тот же секрет перед истечением срока действия. | +| Вы | Установите Secrets Store CSI Driver, предоставьте ServiceAccount pod'а доступ к чтению секрета через IRSA и примените манифест Pod. Вот и все. | + +--- + +## Предварительные условия + +### В вашем AWS аккаунте/кластере EKS + +- Кластер EKS с связанным **поставщиком OIDC**. Подтвердите с помощью: + + ```bash + aws eks describe-cluster --name \ + --query "cluster.identity.oidc.issuer" --output text + ``` + + Если команда возвращает URL `https://oidc.eks.…`, то OIDC включен. Если нет, свяжите его: + + ```bash + eksctl utils associate-iam-oidc-provider \ + --cluster --approve + ``` + +- [Secrets Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/) и [AWS provider](https://github.com/aws/secrets-store-csi-driver-provider-aws), установленные в кластере (см. § Этап 2). + +- AWS CLI v2 и `kubectl` на вашей рабочей станции. + +### Координация с Exosphere + +Перед развертыванием Exosphere доставляет пакет клиента mTLS в Secrets Manager вашего AWS аккаунта и предоставляет: + +- **Имя секрета** (соглашение: `agenteye/mtls-client/`) +- **Регион AWS**, где находится секрет +- **URL backend'а AgentEye** для конфигурации collector'а +- Ваш **API ключ** collector'а (см. [enterprise-docs/api-keys.md](/ru/agenteye/api-keys)) + +--- + +## Этап 1: Что доставляет Exosphere + +Вы не генерируете сертификат клиента mTLS самостоятельно. Exosphere выдает его и доставляет пакет непосредственно в Secrets Manager вашего AWS аккаунта, поэтому единственный материал учетных данных, который попадает в вашу среду, — это готовый к монтированию секрет. + +Что прибывает в ваш аккаунт: + +| Свойство | Значение | +|---|---| +| Имя секрета | `agenteye/mtls-client/` (стабильно при обновлениях) | +| Регион | Регион AWS, который вы номинировали для вашего кластера EKS | +| Payload | Единственный JSON-секрет с тремя ключами (`client.crt`, `client.key` и `ca.crt`), каждый содержит PEM-кодированный материал | +| Тег | `AgentEyeCluster=` | + +При обновлении один и тот же секрет обновляется на месте с новой версией, поэтому ARN и имя никогда не меняются; ваш `SecretProviderClass` и политика IAM продолжают работать без изменений. Для жизненного цикла сертификата (валидность, кадрия обновления, оповещения об истечении) см. [enterprise-docs/kubernetes-deployment.md](/ru/agenteye/kubernetes-deployment). + +--- + +## Этап 2: Установка Secrets Store CSI Driver + AWS provider + +Пропустите этот шаг, если вы уже запускаете другую рабочую нагрузку, которая монтирует AWS секреты через CSI. + +```bash +# CSI Driver +helm repo add secrets-store-csi-driver \ + https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts +helm install -n kube-system csi-secrets-store \ + secrets-store-csi-driver/secrets-store-csi-driver \ + --set syncSecret.enabled=true \ + --set enableSecretRotation=true \ + --set rotationPollInterval=1h + +# AWS provider +kubectl apply -f \ + https://raw.githubusercontent.com/aws/secrets-store-csi-driver-provider-aws/main/deployment/aws-provider-installer.yaml +``` + +**Проверка:** + +```bash +kubectl get pods -n kube-system | grep -E 'csi-secrets-store|aws-provider' +``` + +Ожидается: `Running` для каждого pod'а. + +> **Почему `rotationPollInterval=1h`?** Когда Exosphere публикует обновленный сертификат, Secrets Manager обновляется на месте. CSI Driver перечитывает секрет в этом интервале и переписывает смонтированные файлы. Collector читает файлы сертификата один раз при запуске, поэтому он начинает представлять обновленный сертификат только после перезагрузки процесса; см. § Ротация сертификата о том, как запустить перезагрузку. + +--- + +## Этап 3: Предоставьте pod'у доступ к чтению секрета (IRSA) + +### 3.1 Создание политики IAM + +Сохраните как `agenteye-mtls-reader-policy.json`: + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "ReadAgentEyeMtlsBundle", + "Effect": "Allow", + "Action": [ + "secretsmanager:GetSecretValue", + "secretsmanager:DescribeSecret" + ], + "Resource": "arn:aws:secretsmanager:::secret:agenteye/mtls-client/-*" + } + ] +} +``` + +Замените ``, `` и ``. Завершающий `-*` соответствует шестизначному случайному суффиксу, который AWS добавляет к каждому ARN секрета. + +Создайте политику: + +```bash +aws iam create-policy \ + --policy-name AgentEyeMtlsReader- \ + --policy-document file://agenteye-mtls-reader-policy.json +``` + +### 3.2 Создание роли IAM и привязка к ServiceAccount pod'а + +```bash +eksctl create iamserviceaccount \ + --name agenteye-pod \ + --namespace \ + --cluster \ + --role-name AgentEyePodRole- \ + --attach-policy-arn arn:aws:iam:::policy/AgentEyeMtlsReader- \ + --approve +``` + +Это создает `ServiceAccount` с именем `agenteye-pod` с аннотацией `eks.amazonaws.com/role-arn`, указывающей на новую роль. + +### 3.3 Требуемые разрешения IAM: итоговая таблица + +| Разрешение | Область | Почему | +|---|---|---| +| `secretsmanager:GetSecretValue` | `arn:aws:secretsmanager:::secret:agenteye/mtls-client/-*` | CSI Driver читает пакет сертификата при каждом монтировании и тике ротации. | +| `secretsmanager:DescribeSecret` | то же | CSI Driver вызывает `DescribeSecret` для обнаружения изменений версии между опросами. | + +**НЕ предоставляйте** `secretsmanager:PutSecretValue`, `secretsmanager:UpdateSecret` или `secretsmanager:DeleteSecret` pod'у. Pod только читает секрет; запись новых версий обрабатывается Exosphere при выдаче или обновлении сертификата. + +Если секрет зашифрован с использованием управляемого пользователем ключа KMS (не ключа `aws/secretsmanager` по умолчанию), также предоставьте: + +```json +{ + "Effect": "Allow", + "Action": ["kms:Decrypt"], + "Resource": "arn:aws:kms:::key/", + "Condition": { + "StringEquals": { + "kms:ViaService": "secretsmanager..amazonaws.com" + } + } +} +``` + +--- + +## Этап 4: Развертывание Pod'а + +### 4.1 SecretProviderClass + +`agenteye-mtls-spc.yaml`: + +```yaml +apiVersion: secrets-store.csi.x-k8s.io/v1 +kind: SecretProviderClass +metadata: + name: agenteye-mtls + namespace: +spec: + provider: aws + parameters: + objects: | + - objectName: "agenteye/mtls-client/" + objectType: "secretsmanager" + jmesPath: + - path: '"client.crt"' + objectAlias: "client.crt" + - path: '"client.key"' + objectAlias: "client.key" + - path: '"ca.crt"' + objectAlias: "ca.crt" +``` + +Блок `jmesPath` сообщает AWS provider'у разбить JSON-секрет на три отдельных файла на диске. Кавычки в `'"client.crt"'` необходимы, потому что JMESPath рассматривает `.` как оператор подвыражения. + +```bash +kubectl apply -f agenteye-mtls-spc.yaml +``` + +### 4.2 Манифест Pod / Deployment + +**Как два контейнера взаимодействуют друг с другом.** SDK AgentEye и collector не взаимодействуют через сокет сети; нет локального HTTP-порта. SDK записывает пакеты событий как файлы `.jsonl` в `$AGENTEYE_HOME/events/`, и collector непрерывно отслеживает этот каталог и загружает каждый файл. Для pod'а sidecar это означает: + +- Оба контейнера монтируют **один и тот же** том `emptyDir` в **один и тот же** путь. +- Оба контейнера устанавливают `AGENTEYE_HOME` на этот путь. +- Ваш образ приложения должен иметь установленный и настроенный SDK AgentEye (см. [enterprise-docs/python-sdk.md](/ru/agenteye/python-sdk)). + +> Когда `AGENTEYE_HOME` не установлен, как SDK, так и collector по умолчанию используют `~/.agenteye`, и два контейнера имеют разные домашние каталоги, поэтому они приземлились бы на две отдельные очереди и передача была бы молчаливо потеряна. Установите `AGENTEYE_HOME` на одинаковый явный путь на **обоих** контейнерах. Проверка в §4.3 и соответствующая строка Troubleshooting перехватывают это, если это пропущено. + +`agenteye-pod.yaml` (Deployment с одной копией, масштабируйте по мере необходимости): + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-app-with-collector + namespace: +spec: + replicas: 1 + selector: + matchLabels: + app: my-app-with-collector + template: + metadata: + labels: + app: my-app-with-collector + spec: + serviceAccountName: agenteye-pod + containers: + - name: app + image: + env: + # SDK writes event JSONL files into $AGENTEYE_HOME/events/ + - name: AGENTEYE_HOME + value: /var/lib/agenteye + volumeMounts: + - name: agenteye-spool + mountPath: /var/lib/agenteye + + - name: agenteye-collector + # Pin to a versioned :v tag for production; :beta-latest + # tracks the current beta build (:latest exists only for stable releases). + image: ghcr.io/agenteye-enterprise/collector:beta-latest + args: ["start"] + env: + # Must match the app container's AGENTEYE_HOME so the collector + # sweeps the same directory the SDK writes to. + - name: AGENTEYE_HOME + value: /var/lib/agenteye + - name: AGENTEYE_URL + value: "https://ingest.example.agenteye.com/events" + - name: AGENTEYE_KEY + valueFrom: + secretKeyRef: + name: agenteye-collector-api-key + key: key + - name: AGENTEYE_TLS_CERT + value: /etc/agenteye/tls/client.crt + - name: AGENTEYE_TLS_KEY + value: /etc/agenteye/tls/client.key + # Only when the AgentEye server presents a cert not signed by a + # publicly-trusted CA (e.g. self-signed by an in-cluster issuer + # because you have no real DNS domain). The CSI mount already + # exposes ca.crt alongside the client cert/key. + - name: AGENTEYE_TLS_CA + value: /etc/agenteye/tls/ca.crt + volumeMounts: + - name: agenteye-spool + mountPath: /var/lib/agenteye + - name: agenteye-mtls + mountPath: /etc/agenteye/tls + readOnly: true + livenessProbe: + exec: + command: ["agenteye-collector", "health"] + initialDelaySeconds: 10 + periodSeconds: 30 + + volumes: + # Shared event spool between app and collector. emptyDir is fine: + # events are transient and the collector drains them before pod + # termination on graceful shutdown. + - name: agenteye-spool + emptyDir: {} + # mTLS cert bundle, mounted read-only into the collector only. + - name: agenteye-mtls + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: agenteye-mtls +``` + +Секрет `agenteye-collector-api-key` содержит API ключ collector'а (см. [enterprise-docs/api-keys.md](/ru/agenteye/api-keys) для подготовки). + +**Применить:** + +```bash +kubectl apply -f agenteye-pod.yaml +``` + +### 4.3 Проверка + +```bash +# Pod should be Running with 2/2 containers ready +kubectl get pods -n -l app=my-app-with-collector + +# Confirm the cert bundle was mounted +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- ls -l /etc/agenteye/tls/ +``` + +Ожидается: `client.crt`, `client.key`, `ca.crt` все присутствуют и только для чтения, принадлежащие пользователю контейнера. + +**Подтвердите, что общая очередь событий видна обоим контейнерам:** + +```bash +# In the collector, should show the events/ and failed/ subdirs that +# the collector auto-creates on startup: +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- ls /var/lib/agenteye/ + +# In the app, should show the same directory contents: +kubectl exec -n deploy/my-app-with-collector \ + -c app -- ls /var/lib/agenteye/ +``` + +Если два списка различаются, том не смонтирован в оба контейнера (или `AGENTEYE_HOME` отличается); см. § Troubleshooting. + +**Тест дыма end-to-end:** + +```bash +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- agenteye-collector flush +``` + +Ожидается: collector загружает все находящиеся в очереди события и печатает сводку `Done: N/N uploaded, 0 failed.`. Если очередь пуста, она печатает `No pending files.` и выходит без проверки чего-либо — поэтому запустите это только после того, как ваше приложение выгрузит хотя бы одно событие. + +Обратите внимание, что `flush` выходит с ненулевым кодом **только** для локальных ошибок установки: отсутствует конфигурация (нет разрешенного URL/ключа) или нечитаемый/непарсируемый сертификат TLS (проверьте § Troubleshooting). **Неправильный API ключ не меняет код выхода** — загрузка получает `401`, файл перемещается в `failed/`, и команда все еще печатает `[FAILED] …` на файл плюс `Done: 0/N uploaded, N failed.` и выходит `0`. Для обнаружения плохого ключа или отклоненной загрузки читайте выход `Done:`/`[FAILED]` или проверяйте файлы, попадающие в `$AGENTEYE_HOME/failed/`, не код выхода. + +--- + +## Ротация сертификата + +Сертификат клиента действителен в течение 90 дней и автоматически обновляется примерно за 15 дней до истечения; затем Exosphere публикует обновленный пакет в тот же секрет Secrets Manager. Оттуда поток in-pod работает следующим образом: + +1. Версия `AWSCURRENT` секрета Secrets Manager обновляется. ARN и имя не изменяются. +2. В течение `rotationPollInterval` (по умолчанию 1 час; см. § Этап 2) CSI Driver читает новую версию и переписывает файлы в `/etc/agenteye/tls/`. +3. Collector загружает файлы сертификата **один раз при запуске**, поэтому он продолжает представлять предыдущий сертификат до перезагрузки процесса. Для переключения на обновленный материал перезагрузите collector'а; rolling restart достаточно: + + ```bash + kubectl rollout restart deploy/my-app-with-collector -n + ``` + + Чтобы это было автоматическим, добавьте sidecar, который отслеживает `/etc/agenteye/tls/` (например, с `inotifywait`) и запускает rollout при изменении файлов. + +Поскольку предыдущий сертификат остается действительным примерно 15 дней после обновления, у вас есть широкое окно для выполнения перезагрузки без перерыва в приеме. Exosphere публикует обновленный пакет для вас; единственное рутинное действие с вашей стороны — убедиться, что collector перезагружается в этом окне. + +--- + +## Troubleshooting + +| Симптом | Вероятная причина | Решение | +|---|---|---| +| Pod'а зависает в `ContainerCreating`, события показывают `MountVolume.SetUp failed for volume "agenteye-mtls"` | CSI provider не может достичь Secrets Manager | Проверьте, правильно ли привязана IRSA: `kubectl describe sa agenteye-pod -n ` показывает аннотацию `eks.amazonaws.com/role-arn`. Проверьте CloudTrail для вызова AssumeRole. | +| Ошибка: `AccessDeniedException: not authorized to perform secretsmanager:GetSecretValue` | Политика IAM ограничена неправильным ARN | Суффикс секрета ARN случайный; используйте `agenteye/mtls-client/-*` с подстановочным знаком, а не точный ARN. | +| Ошибка: `ParameterNotFound` от AWS provider | Несоответствие имени секрета между `SecretProviderClass.objects[].objectName` и секретом, доставленным Exosphere | Подтвердите точное имя с помощью `aws secretsmanager list-secrets --filters Key=tag-key,Values=AgentEyeCluster`. | +| Ошибка `jmesPath`, смонтирован только один файл | Синтаксис JMESPath | Точки в ключах JSON требуют двойного кавычирования: `'"client.crt"'`, а не `client.crt`. | +| Collector логирует `tls: bad certificate` после обновления | CSI Driver еще не опросил новую версию, или collector все еще работает с предыдущим сертификатом, который он загрузил при запуске | Подтвердите, что смонтированные файлы обновлены (`ls -l /etc/agenteye/tls/`), затем перезагрузите collector для их загрузки: `kubectl rollout restart deploy/my-app-with-collector -n `. См. § Ротация сертификата. | +| Контейнер Collector crashloops с `no such file or directory: /etc/agenteye/tls/client.crt` | Том еще не заполнен при первом запуске; probe запуска слишком агрессивен | Добавьте небольшую начальную задержку или используйте init контейнер, который ждет, пока файл существует: `until [ -f /etc/agenteye/tls/client.crt ]; do sleep 1; done`. | +| CSI Driver pod `OOMKilled` | Ограничения памяти по умолчанию слишком низки для кластеров со многими SecretProviderClasses | Увеличьте `--set linux.resources.limits.memory=200Mi` в установке Helm. | +| Приложение работает чисто, `agenteye-collector flush` сообщает `No pending files.`, но ваша панель управления AgentEye не показывает события | Приложение и collector не совместно используют очередь событий | Проверьте, что (a) оба контейнера монтируют один и тот же `agenteye-spool` emptyDir по одному пути, и (b) оба устанавливают `AGENTEYE_HOME` на этот путь. Запустите две проверки `ls /var/lib/agenteye/` из § 4.3; списки должны совпадать. | + +**Логи для получения в первую очередь:** + +```bash +kubectl logs -n kube-system -l app=secrets-store-csi-driver --tail=100 +kubectl logs -n kube-system -l app=csi-secrets-store-provider-aws --tail=100 +kubectl describe pod -n -l app=my-app-with-collector +``` + +--- + +## Справка: файлы на диске в pod'е + +Pod имеет два пути данных на диске: + +### Пакет сертификата mTLS: `/etc/agenteye/tls/` (CSI, только для чтения, только collector) + +Смонтирован Secrets Store CSI Driver из AWS Secrets Manager. + +| Файл | Содержание | Используется collector'ом как | +|---|---|---| +| `client.crt` | PEM-кодированный сертификат клиента | `AGENTEYE_TLS_CERT` | +| `client.key` | PEM-кодированный приватный ключ | `AGENTEYE_TLS_KEY` | +| `ca.crt` | PEM-кодированный сертификат CA | `AGENTEYE_TLS_CA` (опционально, только когда сертификат сервера AgentEye не подписан публично доверенным центром) | + +Все три смонтированы только для чтения и принадлежат пользователю контейнера. Они переписываются CSI Driver при ротации секрета. + +### Очередь событий: `$AGENTEYE_HOME/` (emptyDir, общая чтение-запись между обоими контейнерами) + +Совместно используется через том `emptyDir` с именем `agenteye-spool`. + +| Путь | Записано | Прочитано | Назначение | +|---|---|---|---| +| `$AGENTEYE_HOME/events/*.jsonl` | Приложение (SDK AgentEye) | Sweeper collector'а | Пакеты событий, которые SDK выгрузил, ожидающие загрузки. | +| `$AGENTEYE_HOME/failed/` | Collector (при ошибке загрузки) | Вы (при отладке) | Файлы JSONL, которые collector не смог загрузить после повторных попыток. | +| `$AGENTEYE_HOME/config.json` | Вы (опционально) | Collector | Опциональный файл конфигурации collector'а (альтернатива переменным окружения). | + +Оба подкаталога `events/` и `failed/` автоматически создаются collector'ом при запуске; init контейнер не требуется. + +--- + +## Связанные документы + +- [enterprise-docs/collector-installation.md](/ru/agenteye/collector-installation): опции бинарного файла collector, справочник конфигурации mTLS, режимы демона. +- [enterprise-docs/kubernetes-deployment.md](/ru/agenteye/kubernetes-deployment): развертывание на несколько pod'ов, внутренние процессы выдачи сертификата, оповещения о жизненном цикле и истечении. +- [enterprise-docs/api-keys.md](/ru/agenteye/api-keys): подготовка API ключа collector'а, потребляемого pod'ом. +- [enterprise-docs/troubleshooting.md](/ru/agenteye/troubleshooting): индекс troubleshooting'а на уровне кластера. \ No newline at end of file diff --git a/docs/ru/agenteye/tenant-management.mdx b/docs/ru/agenteye/tenant-management.mdx new file mode 100644 index 00000000..f0ee226b --- /dev/null +++ b/docs/ru/agenteye/tenant-management.mdx @@ -0,0 +1,167 @@ +--- +title: "Управление тенантами (организации и участники)" +description: "Документация по управлению тенантами AgentEye (организации и участники)." +--- + + +Единое развертывание AgentEye обслуживает несколько полностью изолированных **организаций** (тенантов), так что один экземпляр может размещать отдельные команды, подразделения или клиентов без утечки данных одного тенанта к другому. Каждая строка данных (события, оценки, сессии, дашборды, сохраненные запросы, оповещения, ключи API и участники) принадлежит ровно одной организации. Первичная изоляция обеспечивается в коде приложения: каждый запрос ограничен своей организацией явными предикатами `org_id`. На ClickHouse — где хранятся большие объемы событий и оценок — это поддерживается строгим принудительным применением на уровне движка: каждая организация получает выделенного пользователя ClickHouse только для чтения с политикой строк для каждой организации, поэтому даже ненадежный аналитический SQL не сможет прочитать строки другого тенанта. На PostgreSQL безопасность на уровне строк добавляет дополнительную защиту на пути только для чтения (`/queries/run`), ограничивая то, что этот путь может видеть, даже если фильтр на уровне приложения когда-то не сработает; собственное подключение для записи на сервере работает от имени владельца таблицы и, таким образом, использует то же ограничение `org_id` на уровне приложения. + +Жизненный цикл тенанта контролируется оператором, в то время как все, что делают участники в повседневной работе, остается самообслуживанием на дашборде. Организации и их членство создаются и управляются с помощью CLI **`agenteye-orgctl`**, который входит в образ сервера и запускается **внутри существующего пода сервера**. Создание и удаление тенантов намеренно исключены из дашборда и HTTP API: **нет HTTP API и нет кнопки на дашборде** для жизненного цикла тенанта, поэтому это контролируется доступом к оболочке кластера/пода, а не поверхностью приложения. + +В рамках организации участники работают полностью на дашборде и API: они входят в систему, переключаются между организациями, к которым они принадлежат, управляют своими ключами API, создают дашборды и сохраненные запросы, а также настраивают оповещения для своей организации. Разделение четкое: операторы подготавливают и выводят из строя тенанты и их участников через CLI; участники запускают все внутри тенанта через пользовательский интерфейс. + +> **Развертыванию с одним тенантом ничего из этого не требуется.** Установка с одним тенантом работает без каких-либо действий оператора. Все данные, пользователи и ключи живут во встроенной организации `default`, которая подготавливается автоматически. Вам нужно это руководство только если вы решите добавить вторую организацию. + +--- + +## Предварительные требования + +Перед созданием **второй** организации (встроенной организации `default` ничего не требуется): + +- **PostgreSQL 15+.** Схема членства организации использует внешний ключ с `ON DELETE SET NULL` для списка столбцов, который требует PostgreSQL 15+. Обновите PostgreSQL перед подготовкой второй организации. +- **Мощный, стабильный `ORG_CH_SECRET`.** Пароль ClickHouse каждой организации получается как `HMAC(ORG_CH_SECRET, org_id)`, поэтому общеизвестное встроенное значение по умолчанию разработки привело бы к общедоступным учетным данным для каждой организации. `agenteye-orgctl org create` **отказывается работать, пока `ORG_CH_SECRET` не установлен или остается встроенным значением по умолчанию разработки**. Установите свое значение первым (см. [Deployment → переменные окружения](/ru/agenteye/deployment) и на Kubernetes [§2.6 руководства по развертыванию на Kubernetes](/ru/agenteye/kubernetes-deployment#26-multi-tenant-org-isolation-key-optional)). Сохраняйте его одинаковым на всех репликах сервера и не вращайте его небрежно; ротация оставляет каждого пользователя ClickHouse организации без привязки до следующего запуска, который повторно подготовит их. + +--- + +## Запуск CLI + +`agenteye-orgctl` входит в **тот же образ, что и сервер** (наряду с `agenteye-server`). Вы **не** развертываете отдельный под, Job или Deployment для него; вы выполняете его внутри уже работающего пода сервера, поэтому он читает тот же `DATABASE_URL`, `CLICKHOUSE_URL` и `ORG_CH_SECRET`, которые использует сервер. + +**Kubernetes:** + +```bash +kubectl -n agenteye exec deploy/server -- agenteye-orgctl +``` + +**Docker Compose:** + +```bash +docker compose exec server agenteye-orgctl +``` + +Приведенные ниже примеры показывают простую `agenteye-orgctl ` для краткости; добавьте перед каждой одну из двух приведенных выше строк, которая соответствует вашему развертыванию. + +--- + +## Справочник команд + +### Организации + +| Команда | Что она делает | +|---|---| +| `org create --slug --name ` | Создать новую организацию. Отказывает работу, пока `ORG_CH_SECRET` не установлен или остается встроенным значением по умолчанию разработки (установите свое значение, см. Предварительные требования). Подготавливает пользователя ClickHouse организации только для чтения + политику строк. | +| `org list` | Список всех организаций (слаг, имя и статус жизненного цикла). | +| `org rename --slug --name ` | Изменить отображаемое имя организации. Слаг (используется в URL и ключах) остается без изменений. | +| `org delete --slug ` | **Мягкое удаление** организации и удаление её пользователя ClickHouse. Данные **сохраняются**. Это отзывает доступ и освобождает учетные данные ClickHouse для каждой организации, но не стирает события. Может быть отменено оператором; безопасный первый шаг перед очисткой. | +| `org purge --slug ` | **Необратимое стирание данных.** Организация должна быть уже `delete`d. Никогда не разрешено для встроенной организации `default`. Используйте только если вы уверены, что данные тенанта должны быть уничтожены. | + +### Участники + +| Команда | Что она делает | +|---|---| +| `member add --org --email [--set ] [--add perm1,perm2] [--remove perm3] [--protected]` | Добавить участника в организацию. Опционально начните с встроенного набора разрешений, затем добавьте/удалите отдельные разрешения. `--protected` закрепляет участника, чтобы дашборд не мог удалить или понизить его в должности (см. ниже). Новый участник получит OTP при первом входе на дашборд. | +| `member list --org ` | Список участников организации. Выходные столбцы: `EMAIL`, `SET` (встроенный набор, с которого начал участник, или `-`), `PROT` (защищен ли участник), и `PERMISSIONS` (их эффективные разрешения). Email, показанный с завершающей `*`, является администратором экземпляра; у них есть доступ к каждой организации. | +| `member update --org --email [--set ...] [--add ...] [--remove ...] [--protected \| --unprotect]` | Изменить разрешения участника и/или флаг защиты. `--set` заменяет встроенным набором; `--add` / `--remove` корректируют отдельные разрешения; `--protected` / `--unprotect` переключают защиту. Передача только `--protected`/`--unprotect` (без флагов грантов) изменяет только защиту и оставляет существующие разрешения без изменений. | +| `member remove --org --email ` | Удалить участника из организации. Отказывает, если участник защищен; сначала отмените для них `--unprotect`. (Человек может быть участником нескольких организаций; это влияет только на названную организацию.) | + +Человек может быть участником более чем одной организации с **разными** разрешениями в каждой, например администратор в одной организации и только для чтения в другой. Каждое членство администрируется независимо для каждой организации: предоставление или изменение разрешений человека в одной организации не влияет на его членство в какой-либо другой. + +### Защищенные участники (администратор организации, которого нельзя удалить) + +Защита гарантирует, что организация никогда случайно не заблокирует себя от самоуправления. По умолчанию администраторы организации могут добавлять и удалять друг друга через страницу пользователей самообслуживания дашборда, поэтому они могут удалить последнего администратора и оставить организацию без возможности управления. + +![Страница Users: карточка на пользователя дашборда с его адресом электронной почты, предоставленными разрешениями и элементами управления редактирования/отключения](/agenteye/images/users.png) + +Чтобы этого избежать, отметьте одного участника как **защищенного**: + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member add --org acme --email owner@acme.example --set admin --protected +``` + +Защищенного участника **нельзя удалить или понизить в должности через дашборд**; эти действия возвращают ошибку. Только оператор может изменить их, и только через этот CLI: сначала запустите `member update --org acme --email owner@acme.example --unprotect`, затем удалите или понизьте. Это гарантирует, что каждая организация сохраняет как минимум одного администратора, которого её собственные участники не могут заблокировать, сохраняя контроль над тенантом исключительно оператору. Защита **для каждой организации**; защита кого-то в одной организации не влияет на их членство в другой. + +### Встроенные наборы разрешений + +`--set` принимает один из трех встроенных наборов, применяемых для каждой организации: + +| Набор | Предназначен для | +|---|---| +| `admin` | Полный доступ в пределах организации, включая управление ключами API и пользователями организации. | +| `standard` | Повседневное использование: чтение + запуск запросов, построение дашбордов, подтверждение инцидентов. | +| `read-only` | Доступ только для просмотра к данным и дашбордам организации. | + +Начните с набора с помощью `--set`, затем уточните с помощью `--add` / `--remove` используя маркеры отдельных разрешений, указанные в [API Keys](/ru/agenteye/api-keys). Сами маркеры разрешений идентичны используемым для ключей API. + +--- + +## Практический пример + +Подготовьте нового тенанта `acme`, добавьте его первого администратора, позвольте ему создать ключ, затем выведите организацию из строя. + +**1. Создать организацию** (`ORG_CH_SECRET` должен быть уже установлен на мощное, стабильное значение, не оставлен незаданным или встроенным значением по умолчанию разработки): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org create --slug acme --name "Acme Corp" +``` + +**2. Добавить первого участника как администратора организации:** + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member add --org acme --email alice@acme.example --set admin +``` + +Alice получит OTP при первом входе на дашборд. С тех пор она работает полностью в пользовательском интерфейсе под префиксом URL её организации (например, `/acme/sessions`). + +**3. Создать ключ API для каждой организации (на дашборде):** + +Оператор **не** создает ключи данных для каждой организации из CLI. Alice (или любой участник организации с `keys:create`) создает ключи сборщика/дашборда для организации `acme` на странице **Keys** дашборда. Каждый ключ, который она создает, автоматически помечается её организацией и может только когда-либо читать или писать данные `acme`. См. [API Keys](/ru/agenteye/api-keys). + +**4. Отрегулировать участника позже:** + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member update --org acme --email alice@acme.example --add alerts:write + +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member list --org acme +``` + +**5. Мягко удалить организацию** (отозвать доступ + удалить её пользователя ClickHouse; данные сохранены): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org delete --slug acme +``` + +**6. Очистить организацию** (необратимо; только после мягкого удаления; никогда организацию `default`): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org purge --slug acme +``` + +На Docker Compose замените каждый префикс `kubectl -n agenteye exec deploy/server --` на `docker compose exec server`. + +--- + +## Распределение ответственности + +Все, что нужно участнику организации в повседневной работе, является самообслуживанием на дашборде и API, автоматически ограниченное их текущей организацией: + +- **Ключи API для каждой организации** создаются и управляются участниками организации на дашборде (или через API ключей с ключом, который содержит `keys:create`). CLI **не** создает ключи данных. См. [API Keys](/ru/agenteye/api-keys). +- **Переключение организации** встроено в дашборд; участники переключаются между организациями, к которым они принадлежат, из переключателя организации, и страницы с областью организации находятся под `//…`. +- **Дашборды, сохраненные запросы, оповещения и все использование данных** происходят полностью в пользовательском интерфейсе и API, ограниченное текущей организацией участника. + +Оператор, используя `agenteye-orgctl`, владеет только **жизненным циклом** организации + участника: создание / переименование / удаление / очистка организации, а также добавление / вывод списка / обновление / удаление участника. + +--- + +## См. также + +- [Deployment](/ru/agenteye/deployment): `ORG_CH_SECRET` и остальная часть окружения сервера. +- [Kubernetes Deployment](/ru/agenteye/kubernetes-deployment): §2.6 создает Secret `agenteye-org-ch-secret` перед вашей первой организацией multi-tenant. +- [API Keys](/ru/agenteye/api-keys): модель ключа для каждой организации и маркеры разрешений, используемые `--add` / `--remove`. +- [Troubleshooting](/ru/agenteye/troubleshooting): проблемы с подготовкой multi-tenant и изоляцией ClickHouse. \ No newline at end of file diff --git a/docs/ru/agenteye/troubleshooting.mdx b/docs/ru/agenteye/troubleshooting.mdx new file mode 100644 index 00000000..1427d7ce --- /dev/null +++ b/docs/ru/agenteye/troubleshooting.mdx @@ -0,0 +1,624 @@ +--- +title: "Устранение неполадок" +description: "Документация по устранению неполадок AgentEye." +--- + + +Это руководство соответствует симптомам, которые вы наиболее вероятно можете столкнуться в production, конкретному диагнозу и исправлению, чтобы вы могли разрешить инциденты из инструментов, которые у вас уже есть, без развертывания дополнительной инфраструктуры наблюдаемости. Оно охватывает сервер, коллектор, приборную панель, помощника ИИ, Python SDK, мониторинг здоровья и сертификатов, резервные копии, аналитику на основе ClickHouse и мультитенантность. + +Страницы приборной панели — это область видимости орга в `//…`, а поток событий — это домашняя страница орга (`//`). Названия страниц в этом руководстве (например `/sessions`, `/queries`) ссылаются на эти маршруты с областью видимости организации. + +--- + +## Просмотр журналов + +AgentEye не поставляется с инфраструктурой логирования или мониторинга. Как сервер, так и приборная панель записывают структурированные журналы в **stdout**, поэтому вы можете читать их напрямую с помощью `kubectl` или `docker`; агрегатор не требуется. + +### Kubernetes + +Следите за живыми журналами сервера и приборной панели: + +```bash +kubectl logs -n agenteye -l app=server -f --timestamps +kubectl logs -n agenteye -l app=dashboard -f --timestamps +``` + +Полезные варианты: + +| Цель | Команда | +|---|---| +| Последние 200 строк (без отслеживания) | `kubectl logs -n agenteye -l app=server --tail=200 --timestamps` | +| Журналы из предыдущего краха | `kubectl logs -n agenteye --previous` | +| Отслеживание всех реплик одновременно | `kubectl logs -n agenteye -l app=server --max-log-requests=10 -f` | +| Postgres (StatefulSet) | `kubectl logs -n agenteye postgres-0 -f` | + +### Docker Compose + +```bash +docker logs -f agenteye-server +docker logs -f agenteye-dashboard +``` + +### Корреляция одного запроса по приборной панели и серверу + +Каждый запрос приборной панели помечается `request_id` и распространяется на сервер через заголовок `x-request-id`. Сервер повторяет его в заголовках ответа и в каждой строке журнала, которую он выдает для этого запроса. Чтобы проследить один запрос от конца до конца: + +1. Захватите идентификатор из заголовка ответа, например: + ```bash + curl -i https://dashboard.example.com/api/events | grep -i x-request-id + # x-request-id: 9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a + ``` +2. Найдите этот идентификатор в журналах обоих pod: + ```bash + REQ=9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a + kubectl logs -n agenteye -l app=dashboard --tail=5000 | grep "$REQ" + kubectl logs -n agenteye -l app=server --tail=5000 | grep "$REQ" + ``` + +Вы увидите строки `proxy passthrough`, `withAuth: authorized` и `upstream response` приборной панели рядом с парой `http request received` / `http request completed` сервера, все они имеют один и тот же `request_id`. + +### JSON-журналы и `jq` + +Установите `AE_LOG_JSON=1` на приборной панели (он включен по умолчанию при `NODE_ENV=production`), чтобы выдать один JSON-объект на строку. Затем фильтруйте структурно: + +```bash +kubectl logs -n agenteye -l app=dashboard --tail=5000 \ + | jq 'select(.level == "warn" or .level == "error")' + +kubectl logs -n agenteye -l app=dashboard --tail=5000 \ + | jq 'select(.route == "POST /api/keys")' +``` + +Rust-сервер выдает пары `key=value` трассировки, которые хорошо работают с grep без `jq`: + +```bash +kubectl logs -n agenteye -l app=server --tail=5000 | grep 'status=5' # 5xx +kubectl logs -n agenteye -l app=server --tail=5000 | grep 'actor_key_id=' +``` + +### Увеличение детализации + +| Компонент | Переменная окружения | Пример | +|---|---|---| +| Сервер | `RUST_LOG` | `RUST_LOG=debug` или `RUST_LOG=agenteye_server=debug,info` | +| Приборная панель | `AE_LOG_LEVEL` | `AE_LOG_LEVEL=debug` | + +`debug` на сервере добавляет строку `api key authenticated` для каждой аутентификации. `debug` на приборной панели добавляет строки `upstream request`, `session validated` и `proxy passthrough`. + +### Хранение журналов + +Stdout контейнера эфемерный; kubelet ротирует файлы журналов (по умолчанию ~10 МиБ на контейнер) и хранит небольшое количество на диске. После удаления pod журналы теряются. Если вам нужно более длительное хранение или поиск по pod, направьте ваш кластер на сборщик логов (Loki, CloudWatch, Cloud Logging, Datadog и т. д.), который отслеживает `/var/log/containers/`. AgentEye не требует и не предписывает какой-либо конкретный выбор. + +--- + +## Проблемы с аутентификацией + +### `docker pull` не удается с ошибкой "unauthorized" + +Убедитесь, что вы аутентифицировали Docker для GHCR с помощью вашего `AGENTEYE_TOKEN`: + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +Токен должен иметь разрешение `read:packages` на организацию `agenteye-enterprise`. Обратитесь к `support@exosphere.host`, если ваш токен не работает. + +### `gh release download` возвращает 404 или 401 + +- Подтвердите, что `AGENTEYE_TOKEN` экспортирован в вашей оболочке: `echo $AGENTEYE_TOKEN` +- Подтвердите, что вы используете `GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download ...` (CLI `gh` читает `GITHUB_TOKEN`) +- Токен должен иметь `contents:read` на `agenteye-enterprise/releases` + +--- + +## Проблемы сервера + +### Сервер не запускается с ошибкой "invalid port number" + +Переменная `POSTGRES_PASSWORD` (или другой учетные данные) содержит специальные символы URL (`/`, `+`, `=`), которые нарушают анализ `DATABASE_URL`. Переформируйте пароль, используя шестнадцатеричное кодирование: + +```bash +NEW_PASS=$(openssl rand -hex 24) +``` + +Затем обновите секрет Kubernetes и пароль внутри Postgres (или пересоздайте `.env` для Docker Compose), и перезагрузите сервер. См. полные шаги в [enterprise-docs/kubernetes-deployment.md](/ru/agenteye/kubernetes-deployment) § "PostgreSQL credentials". + +### Сервер выходит немедленно при запуске + +Проверьте журналы контейнера: + +```bash +docker logs agenteye-server +``` + +Распространенные причины: +- `DATABASE_URL` не установлен или неверно сформирован: сервер записывает ошибку и выходит. +- Postgres недостижим: подтвердите, что контейнер Postgres или управляемая БД работают и хост/порт правильны. +- Миграции не удались: проверьте журналы на наличие ошибок SQL. + +### `GET /health` возвращает не-200 или истекает + +Сервер может все еще запускать миграции при первом запуске. Подождите несколько секунд и повторите попытку: + +```bash +curl http://localhost:8080/health +``` + +Если проблема сохраняется, проверьте `docker logs agenteye-server` на наличие ошибок. + +### `GET /ready` возвращает 503 + +`/ready` — это зонд готовности: он возвращает `503`, когда сервер не может достичь **Postgres или ClickHouse**. Тело указывает на неправильную зависимость: + +```bash +curl -s http://localhost:8080/ready +# {"status":"not_ready","checks":{"postgres":"ok","clickhouse":"down","redis":"ok"}} +``` + +Исправьте зависимость, которую оно указывает как `down`: является ли pod ClickHouse/Postgres `Running`? Верны ли `CLICKHOUSE_URL` / `DATABASE_URL` и достижимы? На Kubernetes pod читает `NotReady` до восстановления `/ready`; это ожидаемо и является именно сигналом, по которому оповещения мониторинга здоровья должны срабатывать. Redis никогда не является причиной: он сообщается, но не приводит к отказу готовности. + +### Коллектор возвращает 401 Unauthorized + +API ключ коллектора не имеет разрешения `events:add`, или ключ был отключен. Создайте новый ключ с правильным разрешением: + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{"name":"new-collector","permissions":["events:add"]}' +``` + +### Аутентифицированные запросы вдруг стали медленными (~200ms вместо ~5ms) + +Это симптом того, что Redis находится вниз, пока `REDIS_URL` установлен. Каждый вызов кэша истекает через 100 мс, затем переходит к Postgres; на путях аутентификации и OTP запрос выполняет два таких перехода. + +Подтвердите в журналах сервера: + +``` +auth cache: L2 get failed error=redis call timed out +``` + +Разрешение: + +1. `redis-cli -h ping` чтобы подтвердить, что Redis достижим в сетевом кластере. +2. Если Redis был кратко отключен и теперь вернулся, **перезагрузите pod сервера**. `redis::aio::ConnectionManager` не восстанавливается надежно после падения основного соединения; перезагрузка pod выбирает новое соединение чисто. То же самое относится к приборной панели. +3. Если вы не хотите запускать Redis прямо сейчас, отмените установку `REDIS_URL` в развертывании и перезагрузитесь. Обе службы работают без кэша (корректность сохраняется; задержка возвращается к базовому уровню до Redis). + +### Сервер сообщает `OTP request rate-limited` в журналах, но пользователь говорит, что попробовал только один раз + +Проверьте, был ли Redis недостижим. Путь резервной копии использует `SELECT COUNT(*) FROM otp_codes WHERE created_at > now() - interval '15 minutes'`, что видит ранее созданные строки OTP. Если пользователь нажимал спам "Отправить" час, окно в 15 минут может все еще содержать ≥5 кодов. Разрешите либо ожидание прохождения окна, либо `DELETE FROM otp_codes WHERE user_id = $1 AND created_at > now() - interval '15 minutes'` (консоль оператора). + +### Я изменил `ALLOWED_EMAILS` / `SESSION_TTL_SECS` / `OTP_TTL_SECS` и перезагрузился; ничего не произошло + +Эти переменные окружения — это **только семена первой загрузки**. После того как таблица `settings` имеет строку для соответствующего ключа, эта строка является источником истины; переменная окружения читается один раз при первой загрузке, а затем игнорируется при каждой последующей перезагрузке. + +Чтобы изменить их после первой загрузки, войдите на приборную панель и отредактируйте их в `/settings`. Изменение применяется за считанные секунды на всех репликах; перезагрузка не требуется. + +Если вам необходимо принудительно пересеять из переменной окружения (редко, обычно полезно только в разработке), используйте `DELETE FROM settings WHERE key = ''` и перезагрузите сервер. Bootstrap выберет текущее значение переменной окружения при следующей загрузке. Редактирование через `/settings` — поддерживаемый путь в production. + +--- + +## Проблемы коллектора + +### Коллектор запускается, но события не появляются на приборной панели + +1. Подтвердите, что коллектор работает: `systemctl status agenteye-collector` (Linux) или проверьте процесс. +2. Подтвердите, что `AGENTEYE_URL` указывает на `http(s)://your-server-host:8080/events` (примечание: путь `/events`). +3. Выполните одноразовый сброс, чтобы увидеть немедленный результат: + ```bash + agenteye-collector flush + ``` +4. Проверьте, что Python SDK действительно записывает файлы: `ls ${AGENTEYE_HOME:-~/.agenteye}/events/` +5. Если файлы существуют в `${AGENTEYE_HOME:-~/.agenteye}/failed/`, загрузки не удаются. Проверьте журналы коллектора на наличие ошибки, скорее всего 4xx (плохой ключ или URL) или проблема с сетью. + +### Файлы накапливаются в `$AGENTEYE_HOME/events/` и не загружаются + +- Коллектор может не работать. Запустите его: `agenteye-collector start`; он автоматически сбрасывает существующие события при запуске. +- Проверьте здоровье коллектора: `agenteye-collector health` +- Коллектор может работать, но не может достичь сервера. Проверьте правила брандмауэра между хостами коллектора и сервера. + +### Файлы в `$AGENTEYE_HOME/failed/` + +Файлы перемещаются в `failed/` после исчерпания всех попыток повторения (по умолчанию: 5 попыток с экспоненциальной отсрочкой). Это означает либо: +- Сервер вернул ошибку 4xx (плохой ключ, неправильный URL или проблема нагрузки) +- Сервер был недостижим для всего окна повторения + +Исправьте основную проблему, затем вручную переставьте в очередь: + +```bash +mv ${AGENTEYE_HOME:-~/.agenteye}/failed/*.jsonl ${AGENTEYE_HOME:-~/.agenteye}/events/ +agenteye-collector flush +``` + +### Коллектор сообщает `network error` при каждой загрузке (рукопожатие TLS не удается) + +Если `curl -k` для `AGENTEYE_URL` успешен, но двоичный файл коллектора при каждой загрузке не удается с `error sending request for url (...)`, сервер AgentEye представляет сертификат TLS, который не подписан доверенным центром сертификации. + +**Путь production** — это имя хоста входящего ACME, настроенное в `deploy/base/certificates/domain.env` (см. [`kubernetes-deployment.md`](/ru/agenteye/kubernetes-deployment) Фаза 3.1 / 4.2). Когда `INGEST_DOMAIN` разрешается на общественный LB Traefik и cert-manager выдал сертификат Let's Encrypt, коллекторы проверяют сертификат сервера по хранилищу системного доверия **без `AGENTEYE_TLS_CA` требуется**; очистите его из конфигурации коллектора, если он был установлен против старого развертывания с самоподписанным сертификатом. + +**Симптом: коллектор работал вчера, не удается сегодня после ~90-дневного перерыва.** Это означает, что развертывание по-прежнему использует устаревший издатель `selfsigned` для `ingest-tls`. 90-дневный сертификат ротировался и закрепленный файл центра сертификации устарел. Исправьте окончательно, переключив кластер на издателя ACME (Фаза 3.1 руководства развертывания). Краткосрочная разблокировка: переизвлеките текущий сертификат сервера и обновите `AGENTEYE_TLS_CA`: + +```bash +kubectl get secret ingest-tls-cert -n agenteye \ + -o jsonpath='{.data.tls\.crt}' | base64 -d > /etc/agenteye/server-ca.crt +``` + +```bash +export AGENTEYE_TLS_CA=/etc/agenteye/server-ca.crt +agenteye-collector flush +``` + +`AGENTEYE_TLS_CA` добавляет дополнительный якорь доверия; стандартные общественные корни по-прежнему доверены. + +### Сертификат `ingest-tls` застрял `Ready: False` после развертывания + +```bash +kubectl describe certificate ingest-tls -n agenteye +``` + +Посмотрите на `Events` и указанный `Order` / `Challenge`. Распространенные причины: + +- **DNS не разрешается на общественный LB.** Валидатор HTTP-01 не может достичь `INGEST_DOMAIN`. Проверьте с помощью `dig +short INGEST_DOMAIN`; он должен разрешаться на тот же адрес, что и `EXTERNAL-IP` LoadBalancer `traefik-public`. cert-manager автоматически повторяет попытки после распространения DNS; нет необходимости удалять сертификат. +- **Порт 80 заблокирован на load balancer / security group.** HTTP-01 требует, чтобы порт 80 был достижим от общественных валидаторов Let's Encrypt. Если у вас есть вышестоящий WAF или SG, ограничивающий `:80`, откройте его (конфигурация Traefik перенаправляет на HTTPS, но Boulder следует перенаправлению и принимает ответ). +- **`dnsNames` не подставлены.** Если `kubectl get certificate ingest-tls -n agenteye -o jsonpath='{.spec.dnsNames}'` показывает `INGEST_DOMAIN_PLACEHOLDER`, вы пропустили шаг `domain.env`; создайте его из `domain.env.example` и повторно примените. +- **Ограничено Let's Encrypt.** Повторяющиеся неудачные заказы для одного и того же имени хоста триггирует дублирование сертификатов или пределы сбоя валидации. Подождите не менее часа перед повторной попыткой; проверьте статус Order для точного сообщения об ограничении скорости. + +### Сертификат `dashboard-tls` застрял `Ready: False` / браузер все еще показывает предупреждение + +Тот же поток диагностики, что и для `ingest-tls` выше (`kubectl describe certificate dashboard-tls -n agenteye`); DNS, port-80, placeholder и причины ограничения скорости все применяются, плюс два специфических для приборной панели: + +- **`DASHBOARD_DOMAIN` разрешается на неправильный LoadBalancer.** Он должен указывать на LB Traefik *приборной панели*, а не на общественный входящий. `dig +short` имя хоста и сравните с адресом LB приборной панели. +- **Экземпляр приборной панели Traefik не может служить заданием.** Он должен быть установлен с объединенным файлом значений приборной панели, который включает поставщика Ingress с областью видимости для решателя HTTP-01 cert-manager. Без него решатель недостижим и заказ остается `pending` навсегда. Обновите экземпляр с предоставленными значениями; ожидающее задание затем завершается само по себе. +- **LoadBalancer был ограничен IP-адресами.** Исходные диапазоны применяются к порту 80 также, что блокирует валидаторы Let's Encrypt — как при первом выпуске, так и при каждом ~75-дневном обновлении. Переоткройте LB или согласуйте решатель DNS-01 с поддержкой перед его блокировкой. + +Пока выпуск не удается, приборная панель продолжает служить своему предыдущему сертификату (или значению по умолчанию входящего при свежей установке) — доступ деградирован предупреждением браузера, никогда полностью недоступен. + +### CLI все еще пропускает проверку TLS после того, как приборная панель получила доверенный сертификат + +`--insecure` сохраняется в `cli.json` при входе. После того как приборная панель служит общедоступно доверенным сертификатом, снова войдите с `agenteye --base-url https:// --secure login`; проверка сохраняется обратно включенной и предупреждение запуска исчезает. + +--- + +## Проблемы приборной панели + +### Невозможно отключить или отредактировать пользователя `ADMIN_EMAIL` + +По дизайну. Пользователь, совпадающий с `ADMIN_EMAIL`, помечается как защищенный при каждом запуске сервера: приборная панель скрывает кнопку Отключить для этой строки, и API отклоняет `DELETE /users/:id` и `PUT /users/:id` для него с `403 Forbidden`. Триггер базы данных также отклоняет прямые операторы `UPDATE`, которые отключили бы защищенную строку. + +Чтобы повернуть начальную загрузку администратора, измените `ADMIN_EMAIL` в своей среде и перезагрузите сервер. Новый адрес электронной почты помещается как защищенный. Предыдущий администратор сохраняет защищенный флаг до его очистки в базе данных (обычно в порядке, так как предыдущий адрес электронной почты по-прежнему является действительным администратором, пока вы явно не удалите его). + +### Приборная панель не показывает события + +1. Подтвердите, что URL сервера и API ключ правильны в переменных окружения приборной панели (`AGENTEYE_SERVER_URL`, `AGENTEYE_API_KEY`). +2. API ключ приборной панели должен иметь разрешение `events:read`. +3. Подтвердите, что события действительно были приняты: `curl http://your-server:8080/events -H "Authorization: Bearer $ADMIN_KEY"` + +### `/errors` пусто, но `/events` показывает красные строки + +Более новые версии SDK выдают сбои как события `agent_end` / `tool_result` / `hook_completed` с `outcome: "error"` в нагрузке, а не как специальная строка `event_type: "error"`. Страница `/errors` теперь соответствует обоим: любая строка, которую поток `/events` рисует красным (явный `event_type='error'`, нагрузка `outcome`/`status` в наборе сбоев, `is_error: true` или истинное поле `error`) появляется на `/errors`. Если вы ранее видели, что ошибок нет в этом окне, пока красные строки были видны на `/events`, обновите приборную панель + сервер вместе (расширенный фильтр — это `errored=true` на `GET /events`) и два представления будут согласованы. + +### `/models`, `/tools` или `/hooks` медленно или не загружаются на широких диапазонах времени + +**Симптом:** в большой таблице событий (миллионы строк) открытие `/models`, `/tools` или `/hooks` — или расширение диапазона времени до `7d`, `30d` или `all` — графики вращаются и затем показывают ошибку загрузки. Сервер логирует ошибку `MEMORY_LIMIT_EXCEEDED` ClickHouse (код 241) или превышение времени ожидания запроса для запроса `latency_aggregate`. + +**Причина:** старые сборки вычисляли откат и распределение часов этих страниц с помощью запроса, который читал полную нагрузку исходного события и сопарял события запроса/ответа с внутриполотной сортировкой и объединением. Поэтому пиковая память запроса росла с размером окна, поэтому на занятом тенанте широкий диапазон может превышать потолок памяти ClickHouse для каждого запроса. + +**Исправление:** обновитесь до сборки, которая включает это исправление. Откат теперь читает только компактные продвигаемые столбцы и сопаривает события с потоковой агрегацией, поэтому пиковая память больше не масштабируется с нагрузкой исходного события — широкие окна остаются хорошо в пределах потолка памяти и возвращаются за часть времени. Улучшение полностью на стороне запроса: оно применяется ко всем существующим данным при следующей загрузке страницы, без переприема или заполнения. + +### Приборная панель не загружается / пустая страница + +Проверьте журналы контейнера приборной панели: + +```bash +docker logs agenteye-dashboard +``` + +Наиболее распространенной причиной является отсутствие `AGENTEYE_SERVER_URL` или `AGENTEYE_API_KEY`, или указание на недостижимый сервер. + +### Аналитика / телеметрия приборной панели + +Приборная панель отправляет анонимную телеметрию использования продукта в PostHog по умолчанию, маршрутизируемую через собственный путь приборной панели `/ingest` (обратный прокси на `https://us.i.posthog.com`). Отправка их от первого лица означает, что блокировщики объявлений браузера их не отбрасывают. Это независимо от основной функциональности приборной панели: + +- **Контейнер приборной панели** (не браузер) — это то, что достигает PostHog. Если его исходящий доступ к `https://us.i.posthog.com` заблокирован, телеметрия молча не включается; приборная панель работает нормально и никакие ошибки не всплывают пользователям. +- Никогда не включаются данные агента, сеанса или события, только использование UI приборной панели. +- Чтобы полностью отключить телеметрию, установите `AE_ANALYTICS_DISABLED=1` на контейнер приборной панели и перезагрузитесь. См. [Telemetry & privacy](/ru/agenteye/deployment#telemetry--privacy) в руководстве развертывания. + +### Телеметрия CLI / телеметрия + +CLI `agenteye` отправляет анонимную телеметрию использования в PostHog по умолчанию: какие команды запускаются, успех/статус выхода и продолжительность. Это независимо от функциональности CLI: + +- **Машина, запускающая CLI**, напрямую достигает `https://us.i.posthog.com`. Если его исходящий доступ заблокирован, телеметрия молча не включается (отправка ограничена по времени, поэтому команда никогда не задерживается) и CLI работает нормально. +- Никогда не включаются данные агента, сеанса или события: **аргументы команды и значения флагов** (URL приборной панели, токен, адрес электронной почты, идентификаторы сеанса, фильтры запросов) никогда не отправляются. +- Чтобы отключить его, установите `AGENTEYE_ANALYTICS_DISABLED=1` (или кросс-инструментальный `DO_NOT_TRACK=1`) в окружении CLI. См. [Telemetry & privacy](/ru/agenteye/cli#telemetry--privacy) в руководстве CLI. + +--- + +## Проблемы помощника ИИ + +См. [enterprise-docs/assistant.md](/ru/agenteye/assistant) для полной установки. + +### Пузырь помощника не появляется + +Пузырь скрыт, если **не все** из следующих: + +- Вошедший пользователь имеет разрешение `agent:use`. +- `AGENTEYE_AGENT_URL` установлен на приборной панели и служба `agent` достижима. +- На служба `agent` настроена конечная точка LLM (`ANTHROPIC_API_KEY`, шлюз через `ANTHROPIC_BASE_URL` или Bedrock/Vertex). Если ничего не установлено, агент сообщает не сконфигурирован и пузырь остается скрытым. + +Проверьте здоровье агента с хоста приборной панели: `curl http://agent:9100/health` должно вернуть `{"status":"ok","llm_configured":true,...}`. + +### Помощник говорит, что не может прочитать что-то + +Инструменты ограничиваются для каждого пользователя. Если пользователь не имеет `evaluations:read` (или `events:read`, `dashboards:read`), соответствующие инструменты не предлагаются и помощник скажет, что не может прочитать эти данные. Предоставьте соответствующее разрешение на чтение. + +### assistant not configured (HTTP 503) при отправке + +Контейнер `agent` не имеет настроенной конечной точки LLM, или `AGENTEYE_AGENT_TOKEN` приборной панели не совпадает с токеном агента. Установите оба и перезагрузитесь. + +### Контейнер `agent` перезагружается / выходит за пределы памяти под нагрузкой + +Каждый разговор порождает короткоживущий дочерний процесс. Убедитесь, что контейнер работает с процессом инициализации (изображение использует `tini`; в Compose установите `init: true`) и дайте ему адекватные лимиты памяти. При необходимости уменьшите `AGENTEYE_AGENT_MAX_STEPS`. + +--- + +## Проблемы CLI + +### `agenteye` не запускается с `ModuleNotFoundError: No module named 'click'` + +Свежая установка CLI `agenteye` версии **0.1.6** может зависать при запуске с: + +``` +ModuleNotFoundError: No module named 'click' +``` + +0.1.6 полагалась на `click`, устанавливаемый косвенно посредством `typer`; текущие релизы `typer` больше не +его вытягивают, поэтому чистая среда заканчивается отсутствующим пакетом. **Обновитесь до 0.1.7 или новее**, +который зависит от `click` напрямую: + +```bash +pipx upgrade agenteye # если установлен с pipx (или: pipx install --force agenteye) +uv tool upgrade agenteye # если установлен с uv +pip install --upgrade agenteye +``` + +См. [enterprise-docs/cli.md](/ru/agenteye/cli) для руководства по установке. + +--- + +## Проблемы Python SDK + +### Файлы не появляются в `$AGENTEYE_HOME/events/` + +SDK буферизирует события и сбрасывает каждые 500 мс по умолчанию. Если ваш процесс выходит перед сбросом, события могут быть потеряны. Вызовите `agenteye.configure(flush_interval=0.1)` для более быстрого сброса в короткоживущих скриптах или убедитесь, что ваш процесс работает достаточно долго для цикла сброса. + +Если `AGENTEYE_HOME` установлен, убедитесь, что SDK пишет в `$AGENTEYE_HOME/events/`, а не в `~/.agenteye/events/` (требуется SDK ≥ 0.0.1b5). + +### `ValueError: Reserved field names cannot be used as custom fields` + +Названия `timestamp`, `type` и `environment` зарезервированы и не могут использоваться как пользовательские поля. Передача любого из них вызывает: + +``` +ValueError: Reserved field names cannot be used as custom fields: [...] +``` + +Переименуйте проблемное пользовательское поле. Обратите внимание, что `session_id` и `agent_id` — это явные параметры вызова события, а не пользовательские поля; передача одного из них снова как пользовательского поля вызывает `TypeError`. + +--- + +## Проблемы мониторинга здоровья + +### В Slack не приходят оповещения (Robusta) + +Оповещение здоровья Robusta является **opt-in**; оно не отправляет ничего, пока не установлено и не указано на канал Slack. Проверьте выпуск и его раковину: + +```bash +kubectl get pods -n robusta # robusta-runner + robusta-forwarder должны быть Running +kubectl logs -n robusta -l app=robusta-runner --tail=50 +``` + +Распространенные причины: Slack `api_key` / `slack_channel` не были установлены (или токен был отозван); `api_key` — это токен облачного релея Robusta (`robusta integrations slack`), но объединенный `disableCloudRouting: true` требует токена бота Slack с собственным размещением (`xoxb-…`), или установите `disableCloudRouting: false`; раковина `scope` исключает пространство имен, в котором работают ваши pod (объединенные значения ограничивают область видимости `agenteye`); или пока не произошел сбой. Принудительно тестовое оповещение путем отключения pod: + +```bash +kubectl -n agenteye delete pod -l app=clickhouse # он будет пересоздан +``` + +См. [enterprise-docs/health-monitoring.md](/ru/agenteye/health-monitoring#2-pod-failure-alerting-with-robusta-opt-in) для установки и конфигурации. + +### Сервер продолжает колебаться `NotReady` + +Зонд готовности попадает в `/ready`, который не удается, когда Postgres или ClickHouse недостижимы. Если сервер циклирует внутрь и наружу из `NotReady`, зависимость периодически недоступна; проверьте pod ClickHouse и Postgres и `CLICKHOUSE_URL` / `DATABASE_URL` сервера. Подтвердите, что сообщает `/ready`: + +```bash +kubectl -n agenteye exec deploy/server -- sh -c 'curl -s localhost:8080/ready' +``` + +Этот зонд намеренно терпим (щедрый порог отказа), поэтому устойчивое колебание указывает на реальную проблему зависимости, а не на чрезмерно агрессивный зонд. Живучесть остается на `/health`, поэтому колебание готовности **не** перезагрузит pod. + +## Проблемы мониторинга сертификатов + +### CronJob не отправляет уведомления Slack + +Для `cert-renewal-check` CronJob требуется URL вебхука Slack, сохраненный в Secret. Проверьте его наличие: + +```bash +kubectl get secret cert-renewal-notify-config -n agenteye +``` + +Если отсутствует, создайте его: + +```bash +kubectl create secret generic cert-renewal-notify-config \ + --namespace agenteye \ + --from-literal=SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL" +``` + +Без секрета CronJob все еще работает и регистрирует результаты в stdout. Проверьте журналы с помощью: + +```bash +kubectl logs -n agenteye -l job-name --tail=50 +``` + +### Сертификат клиента истек до получения уведомления + +CronJob работает каждые 12 часов. Если он не работал, проверьте его статус: + +```bash +kubectl get cronjob cert-renewal-check -n agenteye +``` + +Инициируйте ручную проверку: + +```bash +kubectl create job --from=cronjob/cert-renewal-check manual-cert-check -n agenteye +kubectl logs -n agenteye -l job-name=manual-cert-check +``` + +Чтобы немедленно переиздать истекший сертификат: + +```bash +cd base/certificates/client-certs +./issue-client-cert.sh +``` + +Затем примените переформированный `collector-mtls-secret.yaml` в кластер(ы), где работают коллекторы, и перезагрузитесь: + +```bash +kubectl apply -f collector-mtls-secret.yaml -n +``` + +--- + +## Проблемы резервного копирования + +### `agenteye-backup` не удается с ошибкой "No space left on device" + +CronJob `agenteye-backup` выводит Postgres + ClickHouse в `backup-tmp` `emptyDir` временный том (по умолчанию `30Gi`), затем **потоком** архив `tar` прямо в S3 — сжатый архив никогда не записывается обратно на временное хранилище, поэтому временное хранилище должно содержать только *необработанные выгрузки*, а не выгрузки + второй архив на диске. Pod, вытесненный / `No space left on device`, поэтому означает, что **необработанные выгрузки** превышают размер временного хранилища (выгрузка `events` ClickHouse доминирует и растет со временем). Проверьте журналы неудачного задания: + +```bash +kubectl logs -n agenteye -l job-name= +``` + +Исправление: в вашей оверлее поднимите `sizeLimit` `emptyDir` `backup-tmp` CronJob выше вашего итога необработанной выгрузки и убедитесь, что узел может действительно его держать (`sizeLimit` — это крышка, не резервирование). Если выгрузки превышают диск одного узла, замените `emptyDir` на PVC (EBS/PD) для `backup-tmp` или сожмите выгрузки у источника. + +> Более старые релизы писали `.tar.gz` в *то же* `20Gi` временное хранилище, что и выгрузки, поэтому `dumps + archive` переполнял его и pod был вытеснен **перед** запуском загрузки — что выглядит как сбой S3, но на самом деле это диск. Потоковая передача загрузки избегает этого удвоения. + +### `agenteye-backup` не удается установить `curl` + +Задание работает на образе `postgres:16` и устанавливает `curl` при запуске для выгрузки ClickHouse по HTTP. В кластере без исходящего доступа к зеркалам пакетов Debian шаг `apt-get` не удается. Либо разрешите исходящий доступ из pod резервного копирования, либо встройте `curl` в зеркальный/пользовательский образ резервного копирования и ссылайтесь на него в вашей оверлее. + +### `agenteye-backup` работает, но ничего не попадает в хранилище объектов + +База поставляется с реальным `BACKUP_BUCKET` (`ts-prod-agenteye/backups`) и `agenteye-backup` ServiceAccount. Задание **потоком** архив в S3 (`tar cz … | aws s3 cp - s3://…`). Если pod резервного копирования не имеет доступа на запись в ведро, загрузка ошибок — и потому что скрипт работает под `set -euo pipefail`, сбой в любом месте этого конвейера **не удается** во всем задании на шаге `upload` а не молча не включается (ловушка EXIT pod регистрирует `backup FAILED during step: upload`). Это также шаг, который вы достигаете *после* исправления временной эвакуации, поэтому если резервные копии ранее были вытеснены на шаге архивирования, убедитесь, что загрузка теперь приземляется. Найдите ошибку доступа S3 в журналах неудачного задания: + +```bash +kubectl logs -n agenteye -l job-name= | grep -iE 's3|upload|denied' +``` + +Исправление: в вашей оверлее установите `BACKUP_BUCKET` на ведро, которым вы владеете, и аннотируйте существующий ServiceAccount `agenteye-backup` с доступом на запись (IRSA / Workload Identity / Pod Identity). См. раздел **Backups** в [enterprise-docs/kubernetes-deployment.md](/ru/agenteye/kubernetes-deployment). + +--- + +## ClickHouse-поддерживаемые оценки / сеансы / запросы + +### Боковая панель страницы `/queries` пуста после обновления + +Три таблицы (`events`, `evaluations`, `agent_sessions`) ожидаются. Если боковая панель SchemaBrowser пуста после обновления, сервер не применил DDL ClickHouse при запуске. Проверьте журналы сервера на `failed to apply CH DDL statement`: + +```bash +kubectl logs -n agenteye deploy/server | grep -E 'clickhouse|CH DDL' +``` + +Наиболее распространенной причиной является то, что ClickHouse недостижим во время запуска миграций. Сервер отказывается запускаться, если не может достичь CH, поэтому застрявший pod обычно имеет `CrashLoopBackOff`, а не молчаливо сломанную страницу запросов, но частичное применение DDL (одна выписка OK, следующие 5xx) оставляет схему полусырой. Перезагрузите pod сервера после проверки достижимости CH: + +```bash +kubectl rollout restart deploy/server -n agenteye +``` + +### Новые оценки не появляются в `/sessions` или `/queries` + +После обновления новые оценки пишутся в ClickHouse, не Postgres, и появляются в `/sessions` (ограничены на `evaluations:read`) и в `/queries`. Если они не появляются: + +1. Подтвердите, что конвейер оценщика включен (`EVALUATOR_ENDPOINT` установлен на сервере) и выдает терминальные результаты; проверьте наличие строк `evaluation_finalized`. +2. Подтвердите, что CH достижим с сервера: `kubectl exec -n agenteye deploy/server -- curl -fsS http://clickhouse:8123/ping`. +3. Точечная проверка таблицы CH: `kubectl exec -n agenteye clickhouse-0 -- clickhouse-client -q 'SELECT count() FROM agenteye.evaluations'`. + +### Запросы не удаются под нагрузкой с ошибкой "Memory limit exceeded", или ClickHouse `OOMKilled` + +**Симптом:** под тяжелой нагрузкой приборной панели/запроса аналитические страницы (поток событий, `/sessions`, представление моделей/задержки, редактор SQL) начинают не удаваться или истекать; сервер кратко колебется `NotReady`; и pod ClickHouse показывает растущее количество перезагрузок. Это почти всегда **память**, а не CPU или диск. + +**Подтвердите, что это память** (не проблема пропускной способности, которую исправила бы репликация): + +1. Проверьте pod на выходе из памяти: + ```bash + kubectl -n agenteye describe pod clickhouse-0 | grep -iE 'Restart Count|Last State|Reason|OOMKilled' + ``` + `Reason: OOMKilled` / `Exit Code: 137` с растущим количеством перезагрузок является признаком. + +2. Спросите ClickHouse, что он отклоняет: + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT name, value FROM system.errors WHERE value>0 ORDER BY value DESC" + ``` + Большое количество `MEMORY_LIMIT_EXCEEDED` — это подпись. Сообщение гласит *maximum: N GiB* — это **N это `0.9 × лимит памяти pod`** (значение `max_server_memory_usage_to_ram_ratio` в `deploy/base/clickhouse/configmap.yaml`). Если тяжелые чтения нужны более чем N, они отклоняются. + +3. Исключите то, что *не является* проблемой — если CPU, часть количество и диск все низкие, добавление реплик/шардирования будет потраченной стоимостью: + ```bash + kubectl -n agenteye top pod clickhouse-0 + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT table, count() parts FROM system.parts WHERE active AND database='agenteye' GROUP BY table" + ``` + +**Причина:** лимит памяти pod ClickHouse слишком мал для аналитического рабочего набора. Самые тяжелые чтения вытягивают столбец `payload` с исходным JSON, запускают `JSONExtract*` над ним и используют `FINAL` — каждый может нуждаться в нескольких ГиБ. Если настроенные кэши (`mark_cache_size` + `uncompressed_cache_size`) больше pod, они усугубляют это: кэши заряжаются против того же бюджета и вытесняют память запроса. + +**Исправление — масштабируйте память ClickHouse:** + +1. Поднимите лимит памяти ClickHouse в вашей оверлее путем патчинга `resources` контейнера `clickhouse` StatefulSet (тот же механизм оверлея, используемый для `resources` других компонентов). Используемый бюджет сервера составляет `0.9 × limit`, поэтому лимит `6Gi` дает ~5.4 ГиБ, `16Gi` дает ~14 ГиБ. Установите `requests.memory` на реальный пол также, чтобы планировщик его зарезервировал. Применение этого **пересоздает CH pod** (одна реплика → ~30–60 сек простоя аналитики); сделайте это в окне низкого трафика. +2. Держите кэши в `deploy/base/clickhouse/configmap.yaml` пропорциональными лимиту — небольшие кэши (несколько сотен МиБ) безопасны на небольшом pod; только поднимите их вместе с соответствующим увеличением лимита памяти. Per-query `max_memory_usage` явно установлен в профиле `users.xml` (см. фиксированный раздел узла ниже) и держится ниже крышки уровня сервера (`0.9 × limit`), поэтому ни один запрос не *разрешено* более RAM, чем контейнер имеет. +3. Если сам узел является потолком, проверьте хост памяти, который ClickHouse может видеть: + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT formatReadableSize(value) FROM system.asynchronous_metrics WHERE metric='OSMemoryTotal'" + ``` + Если это только немного выше лимита pod, переместите ClickHouse на больший узел (оптимизированный для памяти) — через селектор узла/сродство в вашей оверлее — перед дальнейшим поднятием лимита. + +**Когда вы не можете добавить память: запустите запросы в RAM и быстро отклоните — не пролейте на медленный диск.** Если узел зафиксирован и pod не может вырасти, ограничьте то, что может использовать любой один запрос (поэтому один запрос не может занять весь узел) и на **медленном (не-SSD) диске данных** делайте **не** позволяйте большим агрегациям/сортировкам пролегчиться на диск. Пролегчивание на медленный диск медленнее, чем истечение времени чтения клиента сервера, поэтому пролегчивающий запрос возвращает `500` приборной панели в полете, пока ClickHouse продолжает молоть — держание запросов в RAM и быстрое отклонение редкого превышения бюджета (`MEMORY_LIMIT_EXCEEDED`, субсекунда) это то, что восстанавливает загрузку. Обратите внимание на подводный камень ClickHouse для применения этих: + +- **Это *профиль* настройки, и ClickHouse читает `` только из `users_config` (`users.xml` / `users.d/*.xml`) — никогда из `config.d`.** Блок ``, размещенный в `config.d/agenteye.xml`, является **молчаливо игнорируемым** (`max_execution_time`, `max_memory_usage` и т. д. просто не применяются). Объединенная конфигурация поэтому поставляется с ними как ключ `users.xml` в ConfigMap `clickhouse-config`, смонтированный по адресу `/etc/clickhouse-server/users.d/agenteye.xml`. +- Поставляемые по умолчанию: `max_memory_usage` (потолок по запросу — один запрос не может потреблять весь бюджет сервера), `max_bytes_before_external_group_by` / `max_bytes_before_external_sort` = **`0` (пролегчивание отключено)** поэтому запросы остаются в RAM вместо того, чтобы ползти на медленный диск, и `max_execution_time` (охрана убежище, согласованная с истечением времени чтения клиента сервера). +- **Проверьте, что они живы** (это также то, как вы обнаруживаете подводный камень config.d): + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT name, value FROM system.settings + WHERE name IN ('max_memory_usage','max_bytes_before_external_group_by','max_execution_time')" + ``` + Ожидайте ненулевого `max_memory_usage` и `max_bytes_before_external_group_by = 0`. Если `max_memory_usage` читается `0`/default, профиль не применяется — проверьте, что живут в монтировании `users.d`, а не `config.d`. + +Компромисс: с отключенным пролегчиванием запрос, чей рабочий набор превышает `max_memory_usage`, — это **отклоняется** (`MEMORY_LIMIT_EXCEEDED`) вместо завершения медленно — на медленном диске то быстрое отклонение предпочтительно, потому что пролегчивающий запрос превышал бы истечение времени клиента и все равно не удалось бы. Если ваш диск данных — это **быстро (SSD)**, вы можете вместо этого поднять пороги `max_bytes_before_external_*` чтобы позволить большим запросам пролегчиться на диск и завершиться. + +--- + +## Мультитенантность (организации) + +### Ошибки при обновлении, которое включает организации (смешанные pod старого/нового сервера) + +**Симптом:** во время катящегося развертывания рилиза, включающего орг, некоторые запросы не удаются: журналы сервера показывают `there is no unique or exclusion constraint matching the ON CONFLICT specification` на пути `api_keys`, и/или каналы оповещений/Slack/вебхука перестают срабатывать во время развертывания. + +**Причина:** обновление заменяет старый уникальный индекс экземпляра на `api_keys(name)` с частичными индексами для каждого орга и перемещает параметры канала оповещения (и `default_user_permissions`) из глобальной таблицы `settings` в `org_settings` для каждого орга. Pod **старого** сервера все еще выдает `ON CONFLICT (name)` (теперь нет соответствующего ограничения) и все еще читает конфигурацию канала из старых строк `settings` (теперь пусто). Старые и новые pod не могут безопасно сосуществовать для этих двух путей. + +**Исправление:** не делайте медленный откат для этого конкретного обновления на смешанные версии. Выполните чистое переключение: масштабируйте старый сервер до нуля (или используйте короткое окно обслуживания) и запустите новую версию вместе с ее миграциями, а не запускайте старые и новые реплики рядом. Обычный трафик и прием возобновляются сразу после переключения; это влияет только на окно переходной версии. + +### Провизионирование организации не удается на `CREATE USER` / `CREATE ROW POLICY`, или один орг может прочитать данные другого орга + +**Симптом:** создание орга возвращает ошибку, упоминающую `CREATE USER`, `CREATE ROW POLICY` или управление доступом отключено; или, что хуже, члены одного орга видят события/оценки другого орга в редакторе SQL или помощнике. + +**Причина:** изоляция для каждого орга обеспечивается выделенным пользователем ClickHouse + политикой строк для каждого орга. Это требует **управления доступом** SQL для включения и `users_without_row_policies_can_read_rows=false` на ClickHouse. С отключенным управлением доступом провизионирование не может создать пользователя/политику; со значением политики строк по умолчанию, оставленным в его разрешительном значении, пользователь, имеющий SELECT но отсутствующую политику, читает **все** строки (сбой-открыт). + +**Исправление:** используйте объединенную конфигурацию `deploy/base/clickhouse/`, которая устанавливает оба. Если вы запускаете собственную конфигурацию ClickHouse, включите управление доступом SQL для внутреннего пользователя сервера и установите `users_without_row_policies_can_read_rows=false` (см. `deploy/base/clickhouse/configmap.yaml`), затем перезагрузите ClickHouse и пересоздайте орг с CLI `agenteye-orgctl` (см. [enterprise-docs/tenant-management.md](/ru/agenteye/tenant-management)). + +### Пользователи организации теряют доступ ClickHouse после изменения `ORG_CH_SECRET` + +**Симптом:** редактор SQL и помощник ИИ внезапно возвращают ошибки аутентификации ClickHouse для каждой организации сразу после изменения или несогласованной установки `ORG_CH_SECRET` на репликах. + +**Причина:** пароль ClickHouse каждого орга выводится как HMAC `ORG_CH_SECRET`. Ротация его (или запуск реплик с разными значениями) аннулирует сохраненный учетные данные ClickHouse каждого орга; производный пароль больше не совпадает с провизионированным пользователем. + +**Исправление:** установите `ORG_CH_SECRET` на одно крепкое значение **перед** провизионированием второго орга и держите его стабильным и идентичным на каждой реплике сервера. Перестройка загрузочного времени сервера пересобирает учетные данные ClickHouse каждого орга с текущего секрета при запуске, поэтому перезагрузка сервера \ No newline at end of file diff --git a/docs/tr/agenteye/alerts.mdx b/docs/tr/agenteye/alerts.mdx new file mode 100644 index 00000000..8678999d --- /dev/null +++ b/docs/tr/agenteye/alerts.mdx @@ -0,0 +1,308 @@ +--- +title: "Uyarılar" +description: "AgentEye Uyarılar belgelendirmesi." +--- + +Uyarılar bir kuralı düzenli olarak değerlendirir ve bir değer eşiği aştığında sizi bilgilendirir. AgentEye'ı pasif bir panodan önemli olan şeyler için sayfalama yüzeyine dönüştürür: hata oranı artışları, gecikme gerilemeleri, değerlendirici puan düşüşleri veya ClickHouse sorgusu olarak ifade edebileceğiniz herhangi bir özel olay. + +Bu rehber, bir uyarının ne olduğunu, beş tetikleme türünü, dört bildirim kanalını, olayın yaşam döngüsünü ve operasyonel kontrolleri kapsar. + +![Uyarılar sayfası: her biri tetikleme türünü, değerlendirme penceresini, kanalları ve bir bilgi/uyarı/kritik önem rozeti gösteran uyarı kuralı kartlarının ızgarası](/agenteye/images/alerts.png) + +--- + +## Konseptler + +- **Uyarı** — kural. *Ne* kontrol edileceğini (tetikleyici), *ne sıklıkta* (değerlendirme aralığı), *ne zaman kırılmış sayılacağını* (bileşik mantık), *ne kadar acil olduğunu* (önem) ve *kime/nereye bildirileceğini* (kanallar) belirtir. +- **Olay** — bir uyarı tetiklendiğinde ne olur. Bir uyarının aynı anda en fazla bir açık olayı vardır. Tekrarlanan ihlaller aynı olayın kanıtını günceller. Olaylar bir operatör tarafından çözülür; kural tetiklemeyi durdurduğunda otomatik çözümleme planlanmıştır ancak şu anda etkinleştirilmemiştir. +- **Kanal** — bir bildirimin gittiği yer: e-posta, Slack, genel webhook veya panoda. Her uyarı herhangi bir kombinasyon ekleyebilir. + +Uyarılar ve olaylar bir kuruluşa aittir ve o kuruluşun operatörleri tarafından paylaşılır (tek kiracılı bir dağıtımda bu basitçe yerleşik `default` kuruluştur). Olaylar bireysel bir operatöre triaj için atanabilir. + +--- + +## Tetikleme türleri + +Beş tür, her birinin kendine ait JSON özellikleri vardır. "Kırılmış"ı nasıl tanımlamak istediğinize uyan birini seçin. Pano **yeni uyarı** formu aynı özellikleri sizin için oluşturur ve tetikleme türünü seçtikçe koşul düzenleyicisini değiştirir: + +![Temel bilgileri (ad, açıklama, etkinleştirildi) ve metrik eşiği, özel SQL, değerlendirme puanı, değerlendirme hatalarını ve olay başına seçenekleri gösteren tetikleyici seçiciyi içeren yeni uyarı formu](/agenteye/images/alert-new.png) + +### 1. `metric_threshold` + +En basiti. Kapalı bir listeden bir metrik, bir operatör, bir eşik ve bir zaman penceresi seçin. + +| Metrik | Ne saydığı | +|---|---| +| `event_count` | Penceredeki toplam olaylar | +| `error_count` | `event_type = 'error'` VEYA `error_type IS NOT NULL` olan herhangi bir olay | +| `error_rate` | `error_count / event_count` (0..1) | +| `p95_latency_ms` | `duration_ms` olan tüm olaylar arasında `quantile(0.95)(duration_ms)` | +| `p99_latency_ms` | `quantile(0.99)(duration_ms)` | +| `token_sum` | `SUM(input_tokens + output_tokens)` | + +Operatörler: `>`, `>=`, `<`, `<=`, `==` (ayrıca `gt`, `gte`, `lt`, `lte`, `eq` olarak kabul edilir). + +İsteğe bağlı filtreler: `environment`, `event_type`. + +Örnek spec: + +```json +{ + "metric": "p95_latency_ms", + "filter": { "environment": "production" }, + "window_secs": 900, + "op": ">", + "value": 5000 +} +``` + +### 2. `custom_sql` + +Önceden ayarlanmış metrikler kapsamayan her şey için. Operatör tarafından sağlanan SQL, işlemci bunu çalıştırmadan önce aynı `/queries/run` korumasından geçer (yalnızca SELECT/WITH, tek ifade, 10.000 satır sınırı). İki mod: + +- **satırlar modu** (no `op`/`value`): sorgu en az bir satır döndürür döndürmez uyarı tetiklenir. +- **değer modu**: sorgu bir sütunu `metric_value` olarak takma ad oluşturmalıdır; işlemci ilk satırın `metric_value`sini `op` kullanarak `value`a karşılaştırır. + +```json +{ + "sql": "SELECT count() AS metric_value FROM agenteye.events WHERE event_type = 'error' AND ts >= now() - INTERVAL 1 HOUR", + "op": ">", + "value": 100 +} +``` + +### 3. `evaluation_score` + +`agenteye.evaluations` okunur ve adlandırılmış bir puanın bir pencere boyunca ortalaması karşılaştırılır. + +```json +{ + "score_key": "hallucination", + "op": ">", + "value": 0.6, + "window_secs": 3600, + "min_count": 5, + "environment": "production" +} +``` + +`min_count` tek örnek aykırılıklarına karşı koruma sağlar; işlemci pencerede en az N değerlendirme mevcut olana kadar tetiklenmez. + +### 4. `eval_compound` + +*Birkaç* değerlendirici puanı arasında aynı anda ortaya çıkan kalite gerilemeleri yakala. `evaluation_score` tek bir adlandırılmış puanı izlerken, `eval_compound` birden çok değerlendirme puanı koşulunu tek bir uyarıya birleştirir ve sonuçlarını seçilen mantıkla birleştirir; böylece bir kural "helpfulness düşerse **VEYA** hallucination yükselirse tetikle", "yalnızca helpfulness **VE** tool-efficiency her ikisi de düşerse tetikle" veya "**bu üçten en az 2**si ihlal ederse tetikle" ifade edebilir. + +Her koşul `agenteye.evaluations`den adlandırılmış bir puanın ortalamasını paylaşılan pencere boyunca okur ve bunu kendi operatörü ve eşiği ile test eder. Boolean sonuçları daha sonra `combinator` tarafından birleştirilir: + +| Combinator | Mantık | Tetiklenir | +|---|---|---| +| `"any"` | VEYA | en az bir koşul ihlal edilirse | +| `"all"` | VE | her koşul ihlal edilirse | +| `{ "at_least": N }` | N-içinden-M | en az N koşul ihlal edilirse | + +```json +{ + "combinator": { "at_least": 2 }, + "conditions": [ + { "score_key": "hallucination", "op": ">", "value": 0.8 }, + { "score_key": "helpfulness", "op": "<", "value": 0.6 }, + { "score_key": "tone", "op": "<", "value": 0.5 } + ], + "window_secs": 3600, + "min_count": 5, + "environment": "production" +} +``` + +- `combinator`: `"any"`, `"all"` veya `{ "at_least": N }`. +- `conditions[]`: her `{ score_key, op, value }`, diğer tetikleyicilerle aynı operatörleri kullanarak (`>`, `>=`, `<`, `<=`, `==`). +- `window_secs`: her koşula uygulanan paylaşılan geri izleme (varsayılan `3600`). +- `min_count`: o koşul ihlal edilmeden önce koşul başına minimum değerlendirme sayısı; pencerede çok az örneği olan bir koşul "ihlal edilmedi" olarak sayılır (varsayılan `1`). +- `environment`: isteğe bağlı; her koşulu bir ortama kısıtlar. + +Bildirimin kanıtı her koşulun gözlenen ortalamasını, test edilen eşiği, kaç değerlendirme görüldüğünü ve ihlal edilip edilmediğini kaydeder; böylece hangi kontrollerin tetiklendiğini tam olarak görebilirsiniz. + +### 5. `per_event` + +"X ile eşleşen herhangi bir olay geldi" uyarıları için. Toplama yok; işlemci geri izleme penceresinde bir eşleşme görür görmez tetiklenir. + +```json +{ + "event_type": "error", + "lookback_secs": 60, + "environment": "production", + "tool_name": "bash", + "agent_id": "caa", + "error_type": "TimeoutError", + "message_contains": "vertex-ai timed out" +} +``` + +Tüm filtreler VE-birleştirilmiştir; bıraktığınız herhangi bir alan sınırlandırılmamıştır. + +| Alan | Amaç | +|---|---| +| `agent_id` | Hataları belirli bir aracıya (Error sayfasında gösterilen) kısıtla. | +| `error_type` | Tüm hatalardan ziyade belirli bir hata sınıfına (`TimeoutError` gibi) kısıtla. | +| `message_contains` | `payload.message`e karşı büyük/küçük harfe duyarsız alt dize eşleştirmesi. Aynı aracıdan her hataya karşı uyarı vermeden belirli bir arıza modunu yakalamak için kullanışlıdır (örneğin `prompt is too long`). 200 karakterle sınırlı; desen değil, değişmez bir dize olarak eşleştirilir. | + +İpucu: aynı olay üzerinde çift bildirimi yapmamak için `lookback_secs`i kabaca uyarının `eval_interval_secs`sine eşleşecek şekilde ayarlayın. + +**`/errors`ten kısayol:** hatalar görünümündeki her hata grubunun temsilci satırının ve bir hata olayı için oturum olayı ayrıntı panelinin, `/alerts/new`i bu satırın `event_type` + ortamına kili bir `per_event` tetikleyicisinin önceden doldurulmuş olarak açan bir **+ alert** düğmesi vardır; mevcut olduğunda `error_type`den kaynak alan bir ad dahil. Yine kanalları seçer ve geri izlemeyi onaylarsınız, ancak eşleyici sizin için doldurulmuştur. Operatörler düğmenin görünmesi için `alerts:write` gerekir. + +--- + +## Bileşik mantık (N içinden M) + +Her uyarının tetikleyiciye ek olarak iki tam sayı kontrol düğmesi vardır: + +- `eval_window`: kaç son değerlendirmeye bakılacağı (varsayılan 1) +- `min_breaches`: uyarı tetiklenmeden önce kaç tanesinin ihlal edilmesi gerektiği (varsayılan 1) + +`1 of 1` (varsayılan) "ilk ihlalde tetikle"dir. `3 of 5` "kuralın son 5 değerlendirmeden 3'ünü ihlal ettiğinde tetikle" anlamına gelir, tek bir kötü ölçüm gürültü olduğu titrek sinyaller için kullanışlıdır. İşlemci uyarı başına bir halka arabelleği tutar; durumu kendiniz yönetmek zorunda değilsiniz. + +--- + +## Değerlendirme aralığı + +`eval_interval_secs` işlemcinin kuralınızı ne sıklıkta çalıştıracağını kontrol eder. `[30, 86400]` ile sınırlandırılmıştır. Panodaki Presets: 1m / 5m / 15m / 1h. Temel alınan sinyalin ne kadar hızlı hareket ettiğine eşleşen bir aralık seçin: 15 saniyede değerlendirilen 5 dakikalık bir hata oranı uyarısı CPU'yu boşa harcar; bir olay başına uyarı kısa bir geri izleme gerektirir veya tick'ler arasındaki olayları sessizce bırakacaktır. + +--- + +## Kanallar + +Her uyarı bu dördünün herhangi bir kombinasyonunu ekleyebilir. Kanala özgü kimlik bilgileri (Slack webhook URL'si, genel webhook URL'si + imzalama sırrı, varsayılan e-posta alıcıları) **`/settings`** tarafından bir kez yapılandırılır ve her uyarıdan anahtar ile referans gösterilir. Bu şekilde bir Slack kanalı her birin kendi webhook URL kopyasını depolaması gerekmeden birçok uyarıya hizmet verebilir. + +Üç harici kanal türü (e-posta, Slack, webhook) ayrıca kuruluş çapında bir kill anahtarı `alerts.enabled_channels` tarafından geçit oluşturulmuştur. Tetiklenen bir uyarı bu sette olmayan bir kanal türü eklediğinde, işlemci bunu atlar ve durum `skipped_disabled` ve hedef `` olan bir `alert_notifications` satırı kaydeder (tüm Slack teslimatını global olarak duraklatmanıza izin vererek her kuralı düzenleme gerekmeden). Panodaki kanal her zaman izin verilir. Bkz. [Yapılandırma](#yapılandırma). + +### E-posta + +OTP giriş e-postalarını göndererek aynı SMTP taşımasını yeniden kullanır. Alıcılar şu sırada çözümlenir: + +1. Kanala özgü `recipients[]` geçersiz kılması (boş olmadığında). +2. `alerts.email_default_recipients` ayarı (e-posta dizelerinin bir dizisi). + +SMTP yapılandırılmamışsa kanal bir no-op'tır; işlemci yine de hedefi `` olan bir `alert_notifications` satırı kaydeder böylece denetim izi yanlış yapılandırmayı görünür kılar. + +### Slack + +Bir [gelen webhook URL'sine](https://api.slack.com/messaging/webhooks) Block Kit iletisi gönderir. + +- Varsayılan URL: `alerts.slack_default_webhook` (`/settings` içinde ayarlanır). +- Uyarı başına geçersiz kılma: kanalın `webhook_setting_key`sini başka herhangi bir URL türü ayar anahtarına ayarlayın, örneğin `alerts.slack_oncall`, `alerts.slack_costs`. + +Başlık bir önem emoji'si (`:rotating_light:` / `:warning:` / `:bell:`) içerir ve ileti olay sayfasına derin bağlantı veren bir düğme taşır. + +### Genel webhook + +PagerDuty, Opsgenie veya kendi alım uç noktanız için bir JSON-POST entegrasyonu. Gövde şekli: + +```json +{ + "schema_version": 1, + "event": "alert.firing", + "incident": { "id": "uuid", "url": "https://…/incidents/uuid", "opened_at": "2026-…" }, + "alert": { "id": "uuid", "name": "errors > 50/hr", "severity": "critical" }, + "breach": { "value": 73.0, "summary": "ErrorCount > 50 (observed 73.000)", "evidence": { … } } +} +``` + +`alerts.webhook_signing_secret` ayarlandığında, istek `X-AgentEye-Signature: sha256=` başlığı içerir, sırrı kullanarak gövdenin HMAC-SHA256'sı. Yükü güvenmeden önce alıcı tarafında doğrulayın. + +Başlık `X-AgentEye-Event` `alert.firing` / `alert.test` taşır. (`alert.resolved` planlanan otomatik çözümleme özelliği için ayrılmıştır ve şu anda yayınlanmamaktadır.) + +### Panodaki + +Harici teslimat yok: uyarı basitçe pano olayları sayfasının yüzeylendiği bir `alert_notifications` satırı yazar. Kuralı ayarlarken ve harici bir sistemi spam yapmak istemiyorsanız veya operatörlerin normal triaj sırasında kontrol ettiği düşük aciliyet uyarıları için kullanışlıdır. + +--- + +## Olay yaşam döngüsü + +``` +firing ──ack──▶ acknowledged + │ │ + └────────────────────┴───── operator resolve ───▶ resolved +``` + +- **firing** — işlemci az önce olayı açtı veya başka bir ihlal algıladı. Tetikleme bildirimi tam olarak bir kez yayılır (olayın `notified_firing_at` zaman damgasına göre geçit oluşturulmuş). +- **acknowledged** — bir operatör `/incidents/:id` üzerinde *ack* düğmesine bastı. Olay hala açık olarak kabul edilir; sonraki ihlaller kanıtını yeniden bildirmeden günceller. +- **resolved** — bir operatör *resolve* düğmesine bastı. Kural tetiklemeyi durdurduğunda otomatik çözümleme planlanmıştır ancak şu anda etkinleştirilmemiştir, bu nedenle açık bir olay bir operatör bunu çözene kadar açık kalır. + +Yeni bir olay, önceki olay çözüldükten sonra herhangi bir noktada aynı uyarı üzerinde yeniden açılabilir. + +**Aktivite zaman çizelgesi.** Bir olay üzerinde her eylem — açılmış, onaylanmış, çözülmüş — ek bir aktivite günlüğüne kaydedilir ve olayın *aktivite* zaman çizelgesinde gösterilir, her giriş bunu gerçekleştiren operatöre (e-posta ile) veya işlemcinin kendi başına aldığı eylemler için **automated** olarak atfedilir (ihlalde otomatik-açılış). Onay paylaşılmıştır: birden çok operatör aynı olayı onaylayabilir ve her biri ayrı, atfedilen bir giriş olarak görünür. + +**Incidents** gelen kutusu açık olayları duruma göre gruplandırır ve önem ve atanana göre filtrelemenizi sağlar: + +![Ciddi rozetleri ve atanmışları gösteren uyarı bağlantılı ve ad-hoc olay kartlarını gösteren Incidents gelen kutusu](/agenteye/images/incidents.png) + +Bir olayın açılması ihlal kanıtını, atanmışları ve abone olanları, atfedilen aktivite zaman çizelgesini ve bir yorum başlığını gösterir: + +![Bir olay ayrıntı görünümü: ana uyarı, ihlal özeti, atanmışlar, aboneler, atfedilen aktivite günlüğü ve sohbet](/agenteye/images/incident-detail.png) + +--- + +## Gerekli İzinler + +Yazarlık uyarı *kuralları* ve triaj *olayları* ayrı kaygılar ve ayrı hibeler olan şey; bu nedenle on-call'a bir olaya erişim verebilir kuralları yeniden yazma yeteneği vermeden. + +- `alerts:read`: uyarı kurallarını görüntüle. +- `alerts:write`: uyarı kuralları oluştur, düzenle, sil ve test bildirimi tetikle. +- `incidents:read`: olayları görüntüle. +- `incidents:write`: uyarıya bağlı olmayan manuel (ad-hoc) olaylar açılır. +- `incidents:ack`: olayları onayla, ata, yorum yap ve çözümle. + +> **Eski `alerts:ack`.** Eski `alerts:ack` token'ına sahip anahtarlar ve operatörler çalışmaya devam eder: `incidents:ack` olarak onurlandırılır (ve `incidents:read` ima eder), böylece mevcut on-callerlar kimlik bilgileri yeniden yayınlamadan erişimlerini korurlar. Yeni hibeler `incidents:*` ailesiyle verin. + +API anahtarlarında (`POST /keys`) ve operatörlerde (`PUT /users/:id`) hibe verin. Pano `PermGate`, bir izin eksik olduğunda ilgili düğmeleri kilitler; eylemin yanında `// 403` göreceksiniz. + +> **E-posta alıcı seçici.** Uyarı editörünün alıcı seçici kuruluşunuzun üyelerini listeler böylece onları ada göre seçebilirsiniz. `alerts:read` veya `alerts:write` tutan herhangi bir operatör için yükler; bu amaç için takımınızın dizinini görüntülemek **herhangi bir** `users:read` gerektirmez ve seçici yalnızca üye e-posta adreslerini döndürür, asla tam kullanıcı kayıtlarını döndürmez. + +--- + +## Yapılandırma + +İşlemci tarafından tüketilen ortam değişkenleri: + +| Var | Varsayılan | Amaç | +|---|---|---| +| `ALERT_WORKERS` | `1` | Sunucu örneği başına worker görevleri. Çoğu dağıtımın sadece bir tane gerekir. | +| `ALERT_CLAIM_BATCH` | `16` | Tek bir worker tick işlemlerinin maksimum uyarı sayısı. | +| `ALERT_POLL_IDLE_SECS` | `5` | Kuyruk boş olduğunda worker uyku. | +| `ALERT_REQUEST_TIMEOUT_MS` | `15000` | Tetikleyici başına değerlendirme zaman aşımı. | +| `DASHBOARD_URL` | `https://app.befailproof.ai` | Bildirimler içinde olay sihir linkini oluşturmak için kullanılan başlangıç. Pano ana bilgisayarınıza ayarlayın. | + +Geçici bir değerlendirme başarısızlığından (ClickHouse ulaşılamaz, sorgu zaman aşımı) sonra işlemci kuralı üstel geri çekilme ile yeniden dener. Bir kural 5 arka arkaya geçici başarısızlık biriktirdikten sonra, normal temposunda yeniden planlanır, geri çekilmeye devam etmek yerine, böylece kalıcı olarak başarısız bir kural yine de yeniden değerlendirilmeye devam eder. Bu tavan sabitlenmiş olup operatör tarafından ayarlanamaz. + +Kanal ayarları (`/settings`ten yönetilen, env değil): + +- `alerts.email_default_recipients` (`email_list`): e-posta dizeleri JSON dizisi — e-posta kanalları için varsayılan alıcılar. +- `alerts.slack_default_webhook` (`url`): varsayılan Slack gelen-webhook URL'si. +- `alerts.webhook_default_url` (`url`): varsayılan genel-webhook URL'si. +- `alerts.webhook_signing_secret` (`secret`): HMAC-SHA256 anahtarı. GET yanıtında her zaman `""` olarak döndürülür; döndürmek için yeni bir değer yazın. +- `alerts.enabled_channels` (`channel_set`): uyarı tetiklendiğinde gönderilenin kuruluş çapında harici kanal türleri kümesi; üçü de varsayılan (`email`, `slack`, `webhook`). Bir türü buradan çıkarmak, her kuralı düzenlemeden tüm uyarılar için bu kanalı global olarak bastırır. Panodaki kanal her zaman teslim edilir ve bu ayardan etkilenmez. + +--- + +## Yeni bir uyarıyı doğrula + +Yeni bir uyarıya güvenmeden önce: + +1. Bunu en az bir bildirim kanalı ile etkinleştirilmiş olarak kaydedin. +2. Uyarı ayrıntı sayfasından **test** seçin ve her yapılandırılmış hedefin sentetik bildirimi almasını doğrulayın. +3. İlk gerçek ihlaldan sonra, olayın **Incidents** altında görünmesini ve ölçülen değerinin karşılık gelen pano sorgusuyla eşleşmesini doğrulayın. + +Olaylar bir koşul temizlendiğinde otomatik olarak çözülmez. Bir operatör bunları olay ayrıntı sayfasından çözmelidir. + +--- + +## Sorun Giderme + +| Belirti | Olası Nedeni | +|---|---| +| Uyarı asla tetiklenmez | `enabled = false`, veya hiçbir kanal eklenmemiş veya temel CH sorgusu 0 satır döndürür. Kanalları doğrulamak için *test* kullanın; metriği doğrulamak için `/queries/run` kullanın. | +| Slack bildirimi eksik | `alerts.slack_default_webhook` (veya uyarı başına geçersiz kılma anahtarı) ayarlanmamıştır: `` satırları için `alert_notifications.target` kontrol edin; veya `slack` türü `alerts.enabled_channels` içinde global olarak devre dışı bırakılmıştır: durum `skipped_disabled` ve hedef `` olan `alert_notifications` satırlarını kontrol edin. | +| Genel webhook 401 | Alıcı bir imza gerektirir ancak `alerts.webhook_signing_secret` ayarlanmamıştır. Alıcıda HMAC'ın `hmac_sha256(secret, body)` eşleşip eşleşmediğini doğrulayın. | +| E-posta "tüm gönderiler başarısız oldu" | SMTP kimlik bilgileri yanlış veya `from` adresi yayın tarafından reddedilir. OTP e-postalarını gönderip göndermeyen aynı yüzey: bunlar işe yarıyorsa SMTP taşıması iyidir. | +| Olay tekrar tekrar açılır | Bileşik düğmeler çok agresiftir: `min_breaches` veya `eval_window`'ü yükseltmeyi deneyin böylece geçici artışlar çözdüğünüz olayları yeniden açmazsınız. | \ No newline at end of file diff --git a/docs/tr/agenteye/api-keys.mdx b/docs/tr/agenteye/api-keys.mdx new file mode 100644 index 00000000..5468d9bb --- /dev/null +++ b/docs/tr/agenteye/api-keys.mdx @@ -0,0 +1,254 @@ +--- +title: "API Anahtarları" +description: "AgentEye API Anahtarları belgelendirmesi." +--- + +AgentEye, sunucuya erişimi kontrol etmek için ayrıntılı API anahtarlarını kullanır. Her anahtar, yapabileceklerini belirleyen bir veya daha fazla izni taşır. + +--- + +## İzinler + +Sunucu sabit bir izin kataloğunu uygular; her biri belirli HTTP yollarını kontrol eder. Bir **yönetici anahtarı** hepsine sahiptir; kapsam belirtilmiş bir anahtar, oluşturma sırasında verdiğiniz alt kümeyi taşır. Bilinmeyen izin dizgileri, bir anahtar oluşturulduğunda reddedilir. + +> **Anahtarlara atanmaz.** İki geçerli izin yalnızca insan/pano için geçerli olup API anahtarına verilemez: `orgs:admin` (örnek yönetimi, yalnızca operatör için) ve `keys:update`. Bu izinlerden birini vermeye çalışan bir `POST /keys` veya `PATCH /keys/:id` isteği HTTP 422 ile reddedilir. Taşıyıcı anahtarın neden anahtar oluşturabileceği ancak bunları asla düzenleyemeyeceği hakkında `keys:update` satırına bakın. + +### Etkinlik alımı ve sorgulaması + +| İzin | HTTP yolları | Ne sağlar | +|---|---|---| +| `events:add` | `POST /events` | Bir toplayıcıdan etkinlik gruplarını alır. Toplayıcının ihtiyaç duyduğu tek izin. | +| `events:read` | `GET /events`, `GET /events/latency_aggregate`, `GET /events/environments`, `GET /events/models`, `GET /sessions/:session_id/export` | Etkinlikleri sorgula, bilinen ortamları listele, verilerde görülen model tanımlayıcılarını listele (Modeller görünümü ve model filtreleri tarafından kullanılır), ısı haritası / yüzdelik bantı güçlendiren gecikme toplamını hesapla ve bir oturumu JSONL olarak dışa aktar. Paylaşılan filtre çubuğu tarafı uç noktaları `GET /events/environments` ve `GET /events/models` **ya** `events:read` **ya da** `evaluations:read` ile erişilebilir, bu nedenle oturumlar sayfası (gated `evaluations:read`) aynı kuruluş başına tarafı yeniden kullanır. | + +### Oturumlar ve değerlendirmeler + +| İzin | HTTP yolları | Ne sağlar | +|---|---|---| +| `evaluations:read` | `GET /sessions`, `GET /evaluations`, `GET /evaluations/aggregate`, `GET /evaluations/environments`, `GET /evaluation-jobs` | Oturumları listele, değerlendirme sonuçlarını oku, panolar tarafından kullanılan düzenlenmiş eval sağlığı ve değerlendirme işi işçi kuyruğu durumunu oku. | +| `evaluations:trigger` | `POST /sessions/:session_id/re-evaluate` | Tamamlanan bir oturum için manual olarak yeniden değerlendirme kuyruğa al. | + +### Panolar + +| İzin | HTTP yolları | Ne sağlar | +|---|---|---| +| `dashboards:read` | `GET /dashboards`, `GET /dashboards/:id`, `GET /dashboards/:id/tiles` | Panoları listele, birini yükle ve fayanslarını oku. | +| `dashboards:write` | `POST /dashboards`, `PUT /dashboards/:id`, `POST /dashboards/:id/tiles`, `PUT /dashboards/:id/tiles/:tile_id`, `DELETE /dashboards/:id/tiles/:tile_id`, `PUT /dashboards/:id/tiles/layout` | Panoları oluştur ve düzenle, fayans ekle / düzenle / kaldır ve fayansgrid'i yeniden sırala. | +| `dashboards:delete` | `DELETE /dashboards/:id` | Tüm panoyu sil (fayans düzeyinde silme `dashboards:write` altında bulunur). | + +### Kaydedilmiş sorgular (SQL bestecisi) + +| İzin | HTTP yolları | Ne sağlar | +|---|---|---| +| `queries:read` | `GET /queries`, `GET /queries/:id`, `GET /queries/schema` | Kaydedilmiş sorguları listele, birini yükle ve bestecinin hedeflediği salt okunur ClickHouse şemasını incele. | +| `queries:write` | `POST /queries`, `PUT /queries/:id` | Kaydedilmiş sorguları oluştur ve düzenle. SQL, `queries:run` çağrısı ile aynı salt okunur rol ve `sql_guard` denetimlerinden geçer. | +| `queries:delete` | `DELETE /queries/:id` | Kaydedilmiş bir sorguyu sil. | +| `queries:run` | `POST /queries/run` | Besteci tarafından kullanılan salt okunur role karşı kaydedilmiş veya geçici SQL çalıştır. | + +### AI asistanı + +| İzin | HTTP yolları | Ne sağlar | +|---|---|---| +| `agent:use` | `GET /agent/conversations`, `POST /agent/conversations`, `GET /agent/conversations/:id`, `PATCH /agent/conversations/:id`, `DELETE /agent/conversations/:id`, `PUT /agent/conversations/:id/messages` | Pano AI asistanıyla konuş ve kendi (özel) konuşmalarını yönet. **Kullanıcı** üzerinde asistan rıhtımını görmek için gereklidir; asistanın kendi anahtarı `dashboard-assistant` ve ayrı olarak tohumlanır (aşağıya bakın). | + +### API anahtarları + +| İzin | HTTP yolları | Ne sağlar | +|---|---|---| +| `keys:create` | `POST /keys` | Yeni bir kapsamlı API anahtarı oluştur. Mevcut bir anahtarın izinlerini düzenlemeyi **vermez** (bu `keys:update`). | +| `keys:read` | `GET /keys` | Mevcut anahtarları listele. Sırlar bu uç nokta tarafından asla döndürülmez. | +| `keys:update` | `PATCH /keys/:id` | Mevcut bir anahtarın izinlerini düzenle. Bir **insan/pano için geçerli** izin; bir API anahtarına atanmaz (taşıyıcı anahtar anahtar oluşturabilir ancak asla düzenleyemez). | +| `keys:disable` | `POST /keys/:id/disable` | Bir anahtarı iptal et. Korunan anahtarlar (`admin`, `dashboard-assistant`) devre dışı bırakılamaz; ortam değişkeni + yeniden başlatma yoluyla döndür. | +| `keys:regenerate` | `POST /keys/:id/regenerate` | Bir anahtarın sırrını döndür. Korunan anahtarlar bu yol üzerinden yeniden oluşturulamaz. | + +### Pano kullanıcıları + +| İzin | HTTP yolları | Ne sağlar | +|---|---|---| +| `users:create` | `POST /users`, `GET /users/defaults` | Yeni bir pano kullanıcısını davet et (e-posta + OTP girişi verir) ve davet formunu tohumlamak için kullanılan pano yapılandırılmış varsayılan izin setini oku. | +| `users:read` | `GET /users`, `GET /users/:id` | Kullanıcıları listele ve tek bir kullanıcı kaydını yükle. | +| `users:update` | `PUT /users/:id` | Bir kullanıcının izinlerini düzenle. Güncellemeler, etkilenen kullanıcıya izin değişikliği e-postası gönderir ve sonraki isteklerinde yürürlüğe girer; yeniden giriş gerekli değildir. | +| `users:delete` | `DELETE /users/:id`, `POST /users/:id/enable` | Bir kullanıcıyı devre dışı bırak (oturumlarını hemen iptal eder) ve önceden devre dışı bırakılan bir kullanıcıyı yeniden etkinleştir. | + +Bu izinler panoyu destekler **Kullanıcılar** sayfasında, burada her üyenin verdiği kapsamlar çip olarak gösterilir: + +![Kullanıcılar sayfası: pano kullanıcısı başına bir kart, e-posta, verilen izinler ve düzenle/devre dışı bırak kontrolleri](/agenteye/images/users.png) + +### İşletim ayarları + +| İzin | HTTP yolları | Ne sağlar | +|---|---|---| +| `settings:read` | `GET /settings`, `GET /settings/schema`, `GET /settings/model-context-windows`, `GET /settings/model-context-windows/resolve` | Pano tarafından yönetilen işletim ayarlarını ve meta verilerini görüntüle; model başına bağlam penceresi geçersiz kılmalarını listele; ve model için geçerli pencereyi çöz. | +| `settings:write` | `PUT /settings/:key`, `PUT /settings/model-context-windows`, `DELETE /settings/model-context-windows` | İşletim ayarlarını düzenle ve model başına bağlam penceresi geçersiz kılmalarını ekle, değiştir veya kaldır. Değişiklikler sunucuyu yeniden başlatmadan yeni etkinlikleri etkiler. | + +![Ayarlar sayfası: pano tarafından yönetilen izin verilen oturum açmalar ve oturum/OTP yaşam süreleri gibi işletim ayarları, yeniden başlatma olmadan düzenlenebilir](/agenteye/images/settings.png) + +### Uyarılar ve olaylar + +| İzin | HTTP yolları | Ne sağlar | +|---|---|---| +| `alerts:read` | `GET /alerts`, `GET /alerts/:id` | Yapılandırılan uyarı tanımlarını görüntüle. | +| `alerts:write` | `POST /alerts`, `PUT /alerts/:id`, `DELETE /alerts/:id`, `POST /alerts/:id/test` | Uyarı tanımlarını oluştur, düzenle, sil ve test-fırla. | +| `incidents:read` | `GET /alerts/incidents`, `GET /alerts/incidents/:iid`, `GET /alerts/incidents/:iid/comments`, `GET /alerts/incidents/:iid/subscribers` | Olayları ve bunların triage izini görüntüle. | +| `incidents:write` | `POST /alerts/:id/incidents` | Mevcut bir uyarıya karşı manual olarak bir olay aç. | +| `incidents:ack` | `POST /alerts/incidents/:iid/ack`, `POST /alerts/incidents/:iid/assign`, `POST /alerts/incidents/:iid/resolve`, `POST /alerts/incidents/:iid/comments`, `POST /alerts/incidents/:iid/subscribe`, `POST /alerts/incidents/:iid/unsubscribe` | Olayları onayla, ata, çöz ve yorum yap. | + +### Denetimler + +| İzin | HTTP yolları | Ne sağlar | +|---|---|---| +| `audits:read` | `GET /audits`, `GET /audits/:id`, `GET /audits/:id/runs`, `GET /audits/findings`, `GET /audits/findings/:fid` | Denetim tanımlarını, çalıştırma geçmişini ve bulguları görüntüle. | +| `audits:write` | `POST /audits`, `PUT /audits/:id`, `DELETE /audits/:id`, `POST /audits/:id/run`, `POST /audits/findings/:fid/status` | Denetimleri oluştur, düzenle, sil ve çalıştır; bulguları triage et (onayla / kapat / reddet / çöz / yeniden aç / ata). | + +> Denetimler piyasaya sürüldüğünde, mevcut hak sahipleri uyarılarla aynı rol şekilleri boyunca genişletildi: `alerts:read` taşıyan her kullanıcı ve izin seti `audits:read` kazandı ve `alerts:write` tutucusu `audits:write` kazandı. Mevcut API anahtarları **genişletilmedi** — anahtar, denetim yüzeyine ihtiyaç duyuyorsa `audits:*` parametresini açıkça verin. + +> Eski `alerts:ack` belirteci için depolanan izinler `incidents:ack` olarak ayrıştırılır, böylece açık çağrıcılar anahtarı değiştirmeden erişimi korur. Belirteç artık panoyu kullanıcı editöründen atanmaz; matris bunun yerine `incidents:ack` sunar. + +> Alıcı seçici uç noktası `GET /alerts/recipients` (bir uyarı editörünün bildirimde bulunabileceği üye e-postalarını listeler) **ya** `alerts:read` **ya da** `alerts:write` tutucusu tarafından erişilebilir, böylece uyarı editörleri `users:read` verilmeden seçiciyi doldurabilir. + +> Pano görüntüleyici **hem** `dashboards:read` (kaydedilmiş görünümleri yüklemek için) **hem de** `evaluations:read` (sağlık metrikleri değerlendirme verilerinden hesaplanır) gerektirir. Bir kullanıcıya pano oluşturmasına veya düzenlemesine izin vermek için `dashboards:write` verin ve bunları kaldırmak için `dashboards:delete` verin. + +> `/health` ve `/auth/*` (OTP isteği, OTP doğrulama, oturum kontrolü, çıkış yapma) tasarım gereği kimliği doğrulanmamıştır; bunlar giriş akışı ve canlılık sondası. `GET /access-granters` geçerli bir anahtar gerektirir ancak özel bir izin yoktur, bu nedenle herhangi bir oturum açmış kullanıcı erişim değişiklikleri hakkında hangi yöneticilere başvuracağını görebilir. + +--- + +## İzin Setleri + +İzin setleri, her seferinde bireysel belirteçleri elle seçmek yerine adlandırılmış bir rol uygulamanıza olanak sağlar. Yeni pano kullanıcısı veya API anahtarı için bir düzine izni birer birer seçmek yerine, bir set seçersiniz ve herkese atanan tutarlı, gözden geçirilebilir bir hak taşır. Özel bir seti düzenleme, önceden kendisine atanan her kullanıcıya yeni izni yeniden uygular, böylece bir rol değişikliği her üyede bir değişiklik yapmak yerine tek bir düzenleme olur. + +Her kuruluş üç yerleşik set ile tohumlanır: + +| Set | İzinler | Amaçlanan | +|---|---|---| +| `read-only` | `events:read`, `keys:read`, `users:read`, `evaluations:read`, `dashboards:read`, `queries:read`, `settings:read`, `alerts:read`, `audits:read`, `incidents:read` | Her işletim yüzeyi genelinde görünüm yapabilir erişim. | +| `standard` | `read-only` içindeki her şey, artı `evaluations:trigger`, `queries:run`, `incidents:ack`, `agent:use` | Salt okunur artı günlük çağrıda çalışan eylemler: sorgu çalıştır, oturumları yeniden değerlendir, olayları onayla ve AI asistanını kullan. | +| `admin` | atanabilir her izin | Kuruluşun tam kontrolü. | + +Üç yerleşik set **değişmezdir**; adları her zaman aynı şeyi ifade eder, bu nedenle `read-only`, `standard` ve `admin` politika ve biniş açısından güvenli referanslardır. Bir operatör kuruluşunuza özgü roller modellemek için ek **özel setler** oluşturabilir (örneğin, bir "pano yazarı" rolü veya "yalnızca toplayıcı" rolü). + +Setler panoda sunulur ve `GET /permission-sets` (`users:read` ile gated liste) ve `POST /permission-sets` / `PUT /permission-sets/:name` / `DELETE /permission-sets/:name` (özel bir set oluştur, düzenle, sil, `settings:write` ile gated) adresinde API üzerinden yönetilir. Yerleşik bir seti silmek veya düzenlemek reddedilir. + +Set üyeliği iki diğer özelliği destekler: + +- **`DEFAULT_USER_PERMISSIONS`** (yönetici **+ yeni kullanıcı** açtığında önceden seçilmiş olan hak) varsayılan olarak `standard` sete sahiptir. Bkz. [Dağıtım](/tr/agenteye/deployment). +- **`agenteye-orgctl` üzerinde `--set` bayrağı** (operatör üye yönetimi) üyeyi adlandırılmış bir setten başlatır, daha sonra `--add` / `--remove` ile ince ayar yaparsınız. Bkz. [Kiracı Yönetimi](/tr/agenteye/tenant-management). + +> Bir set anahtar-atanabilir olmayan bir izin içerdiğinde (örneğin `keys:update` taşıyan özel set), bu setten bir anahtar tohumlamak atanmayan belirteçleri düşürür; sunucu aksi takdirde HTTP 422 ile anahtarı reddeder. Pano kullanıcıları bu kısıtlamaya tabi değildir. + +--- + +## Bootstrap Yönetici Anahtarı + +Yönetici anahtarı, operatörün hiçbir şeyden erişim başlatmasına izin veren tek kök kimlik bilgisidir: onunla diğer her kapsamlı anahtarı basabilir, ilk pano kullanıcılarını davet edebilir ve başka bir anahtar bulunmadan önce örneği yapılandırabilirsiniz. Bu, anahtarlar API aracılığıyla oluşturmadığınız tek anahtardır; ortamdan sağlanır, böylece sunucu ilk önyüklemede erişilebilir. + +Sunucuda `ADMIN_KEY` ortam değişkenini ayarlayın. Her başlangıçta sunucu bu değeri tüm izinlere sahip bir yönetici anahtarı olarak yükseltir. + +Döndürmek için: `ADMIN_KEY` yeni bir sırra değiştirin ve sunucuyu yeniden başlatın. + +--- + +## Kuruluş kapsamı + +**Kuruluşların kendileri bu anahtarlar API'si aracılığıyla değil, bir operatör tarafından bant dışında oluşturulur ve yönetilir.** Kuruluş ve üye yaşam döngüsü (kuruluş oluştur / yeniden adlandır / sil / temizle; üye ekle / güncelle / kaldır) **`agenteye-orgctl`** CLI ile yapılır; sunucu pod'u içinde çalışır; HTTP API veya pano düğmesi yoktur. Bkz. [Kiracı Yönetimi](/tr/agenteye/tenant-management). Değişmemiş olan: **kuruluş başına API anahtarları pano tarafından hala basılır (veya bu anahtarlar API'si aracılığıyla)** kuruluş üyeleri tarafından. + +Çok kuruluşlu dağıtımda, kuruluş üyesinin oluşturduğu her anahtar (bu anahtarlar API'si veya pano **Anahtarlar** sayfası aracılığıyla) **bir kuruluşa** aittir ve yalnızca o kuruluşun verilerini okuyabilir veya yazabilir; kuruluş oluşturmada damgalanır ve her istekte uygulanır. İki bootstrap anahtarı tek istisnadır: `admin` anahtarı (`ADMIN_KEY` tarafından tohumlanmış) ve `dashboard-assistant` anahtarı (`AGENT_API_KEY` tarafından tohumlanmış) **örnek kapsamlı**dır (kuruluş taşımazlar). Pano konteyneri, `admin` anahtarı ile kimlik doğrulaması yaparak, oturum açmış üyeleri adına kuruluş başına istekleri proxy edebilir. Tek kiracılı dağıtımlar bunu düşünmelerine gerek kalmaz; tüm anahtarlar yerleşik `default` kuruluşa aittir. + +--- + +## Anahtar Oluşturma + +Ek kapsamlı anahtarlar oluşturmak için yönetici anahtarını (veya `keys:create` izni olan herhangi bir anahtarı) kullanın. + +### Toplayıcı anahtarı (yalnızca alım) + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "prod-collector", + "key": "your-collector-secret", + "permissions": ["events:add"] + }' +``` + +### Pano anahtarı (salt okunur) + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "dashboard", + "key": "your-dashboard-secret", + "permissions": ["events:read", "keys:read"] + }' +``` + +HTTP API üzerinden bir anahtar oluşturduğunuzda, `key` değerini kendiniz sağlarsınız; güçlü bir sır seçin ve güvenli bir şekilde depolayın. (Pano ters yönde çalışır: sizin için güçlü bir sır oluşturur ve oluşturmada bir kez gösterir; bkz. [Panoda Anahtar Yönetimi](#key-management-in-the-dashboard).) Yanıt anahtarın oluşturulduğunu doğrular: + +```json +{ + "id": "550e8400-e29b-41d4-a716-446655440000", + "name": "prod-collector", + "permissions": ["events:add"], + "created_at": "2026-04-01T12:00:00Z" +} +``` + +--- + +## Anahtarları Listeleme + +```bash +curl -s http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +Anahtar sırları liste yanıtlarında döndürülmez, yalnızca kimlikler, adlar ve izinler döndürülür. + +--- + +## Anahtarı Devre Dışı Bırakma + +Devre dışı bırakmak, anahtar kaydını silmeden erişimi hemen iptal eder. + +```bash +curl -s -X POST http://your-server:8080/keys//disable \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +--- + +## Anahtarı Yeniden Oluşturma + +Mevcut bir anahtar için yeni bir sır oluşturur. Eski sır hemen geçersiz kılınır. + +```bash +curl -s -X POST http://your-server:8080/keys//regenerate \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +Yanıt yeni düz metin sırrı içerir, **yalnızca bir kez gösterilir**. + +--- + +## Panoda Anahtar Yönetimi + +Panodaki **Anahtarlar** sayfası yukarıdaki tüm işlemler için bir UI sağlar. Liste görüntülemek için `keys:read` izni olan bir anahtara ihtiyacınız vardır ve oluştur / düzenle / devre dışı bırak / yeniden oluştur eylemleri için sırasıyla `keys:create` / `keys:update` / `keys:disable` / `keys:regenerate` gerekir. Bir anahtarın izinlerini düzenlemek (`keys:update`) oluşturmaktan (`keys:create`) ayrıdır, böylece bir operatöre anahtarı basma yetkisi verebilirsiniz ancak mevcut olanları yeniden kapsamlı yetkiye sahip hale getirebilirsiniz veya tam tersi. Yönetici anahtarı tüm bunları kapsar. + +Panodan bir anahtar oluşturduğunuzda, sırrı sağlammazsınız; pano sizin için güçlü bir sır oluşturur ve bunu oluşturmada **bir kez** görüntüler. Hemen kopyalayın ve güvenli bir şekilde depolayın; yeniden üretmede olduğu gibi bir daha asla gösterilmez. Hala anahtarın izinlerini doğrudan seçebilir veya bunları bir izin setinden tohumlayabilirsiniz (aşağıya bakın). + +![API Anahtarları sayfası: anahtar başına bir kart, adı, verilen izinler ve oluşturma zamanı, yeniden oluştur ve devre dışı bırak eylemleri; `admin` gibi korunan anahtarlar işaretlenir](/agenteye/images/api-keys.png) + +--- + +## Önerilen Anahtar Düzeni + +| Anahtar | İzinler | Tarafından Kullanılan | +|---|---|---| +| `admin` (bootstrap via `ADMIN_KEY` env var) | hepsi | Operasyon/kurulum ve pano konteyneri (`ADMIN_KEY` ile kimlik doğrulaması yapar, izin denetimleri ile kullanıcı isteklerini proxy eder) | +| Kuruluş başına toplayıcı anahtarı | `events:add` | Her ajan makinesi üzerinde toplayıcı | +| `dashboard-assistant` (bootstrap via `AGENT_API_KEY` env var) | `events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run` | AI asistanı konteyneri, otomatik olarak tohumlanmış, **korunan**; API aracılığıyla düzenleme yapılamaz | +| Asistan telemetrisi anahtarı (isteğe bağlı) | `events:add` | AI asistanı kendi aletlendirmesi, etkinse | + +> **Asistan anahtarı.** Asistanın anahtarı `AGENT_API_KEY` ortam değişkeninden sunucu tarafından **otomatik olarak tohumlanır** (ajanın `AGENTEYE_API_KEY` olarak sunduğu aynı sır); manual anahtar basma adımı yoktur ve yönetici anahtarı söz konusu değildir. İzinleri kaynak kodda sabitlenmiştir, böylece kapsam yanlış yapılandırma tarafından genişletilemez: etkinlikler / değerlendirmeler / panolar genelinde okuyun, artı pano yazma ve sorgular okuyun / yazın / çalıştırın "AI'dan sorgu yazmak istediğinde" yazarlık akışı için. Tüm SQL, kullanıcı tarafından yazılan bir sorgu olarak aynı salt okunur rol ve `sql_guard` denetimlerinden geçer, bu nedenle bu *yazarlık yüzeyini* genişletir, veri yüzeyini değil; yıkıcı işlemler (`queries:delete`, `dashboards:delete`) kasıtlı olarak asistan anahtarında kalır. `admin` anahtarı gibi **korunan**dır: anahtarlar API üzerinden devre dışı bırakılamaz veya yeniden oluşturulamaz, yalnızca `AGENT_API_KEY` değiştirerek ve yeniden başlatarak döndürülür. Pano **kullanıcıları** ek olarak asistanı görmek ve kullanmak için `agent:use` izni gerektirir. Kendi aletlendirmesini etkinleştirirseniz, asistana ayrı bir `events:add`-yalnızca anahtar verin. \ No newline at end of file diff --git a/docs/tr/agenteye/assistant.mdx b/docs/tr/agenteye/assistant.mdx new file mode 100644 index 00000000..53140add --- /dev/null +++ b/docs/tr/agenteye/assistant.mdx @@ -0,0 +1,202 @@ +--- +title: "AI Asistanı" +description: "AgentEye AI Asistanı belgelendirmesi." +--- + + +Pano, isteğe bağlı bir **AI asistanı** içerir; panelinin sağ kenarına yerleştirilmiş bir sohbet paneli olup ajanlarınız hakkında doğal dile sorular yanıtlar ("bu hafta üretimde kalite nasıl değişiyor?", "bugün hangi oturumlar hata verdi?", "bu oturumu özetle") ve kullanıcı her işlemi izin verdiğinde, kendi adlarına SQL sorguları ve panoları oluşturur ve kaydeder. İlgili oturumlar, sorgular ve panolara doğrudan tıklanabilir bağlantılar belirtir ve **sayfa-farkında**dır: bir oturumu görüntülerken "bu oturum" hakkında sorun ve ne demek istediğinizi bilir. + +Yerleştirme varsayılan olarak ince bir **44px dikey raylı** olarak görünür: bir `›_` komut istemi karakteri ve renkli bir sistem durumu noktası. Rayla tıklayın (veya `⌘J` / `Ctrl+J` tuşlarına basın) tam sohbet paneline genişletmek için. Genişletilmiş panel sol kenarını sürükleyerek **320 ile 640 piksel arasında yeniden boyutlandırılabilir**; tercih ettiğiniz genişlik yeniden yüklemeler arasında hatırlanır. + +Claude Agent SDK üzerinde bir küçük dahili **`agent`** konteyner olarak çalışır ve buna sadece pano erişebilir. **Varsayılan olarak devre dışıdır** ve bir LLM uç noktası yapılandırana kadar gizli kalır. + +--- + +## Neler yapabilir ve yapamaz + +- **Soran kullanıcının görebileceği operasyonel verileri okur.** Olaylar, değerlendirmeler, oturumlar, değerlendirme işi sırası, kaydedilmiş sorgular ve kaydedilmiş panolar, her istek için kullanıcının okuma izinleriyle sınırlandırılır. Okuma araçları hemen çalışır. +- **Yazma işlemleri işlem başına onay ile kontrol edilir.** Kaydedilmiş sorgular oluşturabilir (`create_saved_query`, `update_saved_query`), taslak SQL'i salt okunur rolde doğrulamak için çalıştırabilir (`run_query`) ve bu sorgulardan pano derleyebilir (`create_dashboard`, `update_dashboard`, `add_query_to_dashboard`). Her yazma işlemi sohbet içinde bir **Onayla / Reddet / Bir soru sorun** istemi için duraklatılır; SDK operatör Onayla'ya tıklayana kadar aracı çağırmaz. **Silme asistana asla kullanılmaz**; yıkıcı işlemler operatörlerin elinde kalır. +- **Taslak SQL, kullanıcı tarafından yazılan SQL ile aynı `sql_guard` doğrulama ve salt okunur rollerinden geçer** (yalnızca SELECT/WITH, çok-deyim yok). Yürütme sorgunun dokunduğu tablalara göre yönlendirilir: analitik tabloları (olaylar, değerlendirmeler, oturumlar) referans alan sorgular kuruluşun salt okunur ClickHouse kullanıcısı olarak çalışır (satır ilkesiyle o kuruluşla sınırlandırılır, 10 sn yürütme sınırı ve 100k satır sınırı ile) yalnızca ilişkisel tablolara dokunan sorgular salt okunur Postgres rolünde çalışır (10 sn, 10k satır). Asistan veri yüzeyini genişletemez; sadece operatörün zaten erişimi olan sorgu yüzeyine yazma yapabilir. +- **Adanmış asistan anahtarı** kullanır (aşağıya bakın) sabit izin seti ile hazırlanır; model kötü davranırsa bile bu kapsamları aşamaz. +- Her pano kullanıcısı asistanı görmek ve kullanmak için **`agent:use`** iznine ihtiyaç duyar. Araçlar her istek için kullanıcının kendi veri izinleriyle eşleşecek şekilde filtrelenir, bu nedenle bir `events:read` kullanıcısı etkinlik araçları alır ama `dashboards:write` araçları almaz. + +--- + +## Sayfa-farkında AI yerleştirme: `/queries` üzerinde besteci, başka yerde sohbet + +Sağ taraf asistan yerleştirmesi **sayfa-farkında**dır. Model seçici, sohbet geçmişi, model sistem durumu noktası ve sohbet girdisi değişmez, ancak **boş durum şablonu çipleri, yer tutucu metni ve bir kullanıcının mesajının hangi arka uç uç noktasına vurduğu** geçerli rotaya göre otomatik olarak değişir. Yerleştirme "hangi sayfada duruyorsanız o sayfa için AI yardımcısı" olur. + +**İki arka uç, sayfa başına seçilir (çip başına geçersiz kılma ile).** + +| Rota | Sayfa-varsayılan arka uç | Neden | +| ------------------------------ | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | +| `/queries`, `/queries/new` | `POST /api/agent/compose-sql` (araç döngüsü yok) | Kullanıcı tazeden başlıyor; ≤1s ilk-token SQL doğrudan editöre akıtılır | +| `/queries/` (mevcut) | `POST /api/agent/chat` (tam araç-döngü asistanı), sayfa varsayılanı | Serbest yazılan mesajlar kullanıcının her şeyi sormasını sağlar ("bunu açıkla", "bu ne yapar?"); yeniden düzenleme çipleri çip başına türü ile compose-sql'ye geri seçilir | +| başka her sayfa | `POST /api/agent/chat` (tam araç-döngü asistanı) | Araçlar oku + onay-kapılı yazma araçları | + +`/queries/` üzerindeki çipleri iki akışı sorunsuzca karıştırabilecek şekilde açık bir `kind` taşır. Varsayılan çip seti iki **sohbet** çippi (`ekranda sorguyu açıkla`, `bu sorgu ne yapar?`) artı beş **compose-sql** çippi (`tarih aralığına göre parametrize et`, `status='error' filtresi ekle`, vb.). Serbest yazılan mesajlar sayfa varsayılanına (sohbet) geri düşer, bu nedenle "bu neden bu kadar yavaş?" gibi bir soru düz yazı yanıt alır, oysa `tarih aralığına göre parametrize et` çipine tıklamak compose uç noktasına yönlendirir ve SQL'yi düzenler. + +Besteci **düzenleme modunda** çalıştığında (kullanıcı `/queries/` veya `/queries/new` üzerinde önerilen SQL zaten yüklenmiş olarak olduğu için boş olmayan bir `currentSql` görür), sistem istemi "yeni sorgu oluştur"dan "sağlanan SQL'yi en az düzeyde değiştir: tablo seçimini, sütun adlarını, birleştirme yapısını, takma adları, girintiyi koru"ya geçer. Model ayrı bir grup before/after çalışılmış örnek gösterilir (parametrize, filtre ekle, saatlik gruplandırmaya dönüştür), bu nedenle çip-tıklanan yeniden düzenleme editörün SQL'sine göre en az fark üretir, tamamdan yeniden yazılmaz. + +Bir besteci çipine tıklayın (veya `/queries/new` üzerinde serbest yazın) → SQL asistan mesajı olarak bir çitli ` ```sql ` blok halinde akar. **Akış sonlandığında, geçerli rotada Monaco monte edilmişse, editör otomatik olarak diff görünümünde açılır** (sol tarafta orijinal, sağ tarafta önerilen, üstte bir `▾ AI önerdi bir düzenleme` ipucu ve aşağıda **Kabul Et / Reddet** düğmeleri). Kullanıcının bir `Editöre Ekle` düğmesini bulmak veya tıklamak gerekmez. Ekle düğmesi SQL blok altında manuel bir yeniden tetikleyici olarak işlenir (Reddetme'den sonra veya kullanıcı uzaklaştığında ve geri döndüğünde kullanışlı) ve bu, kullanıcı editör olmayan bir sayfada olduğunda tek yoldur (örneğin kayıtlı sorgular listesi); orada SQL `sessionStorage` içinde saklanır ve `/queries/new` sayfasına yönlendirilir, burada yeni monte edilen editör saklı alanı bağlama al ve aynı diff görünümü açar. + +Önerilen SQL, editörde zaten olan şeyin byte-özdeş olması halinde (no-op düzenleme), otomatik açılış atlanır; boş bir diff açmayız. Bu durumda `Editöre Ekle` düğmesi de no-op'tir. + +Kullanıcı `/queries/new` üzerinde bir öneriye onay verdiğinde, araç çubuğunun birincil eylem **`kaydet`** yazısı yerine `oluştur`; SQL asistan tarafından kendilerine verildi; zihinsel model "bunu sonlandır", "tamamdan yaz" değil. Etiket yerleştirme SQL eklediğinde çevrilir ve sayfa gezintisine kadar `kaydet` olarak kalır. `/queries/` üzerinde düğme her zaman `kaydet` yazıp durdu; orada hiçbir şey değişmez. + +`/queries` dışında, yerleştirme tamamen önceki gibi çalışır: araç onay kartları ile tam sohbet, sayfa-bağlam farkındalığı, alıntılar. + +**İzinler / Kapılar.** Besteci uç noktası kullanıcı başına `queries:run` izni ile kapı işlevi görür (okuma-eşdeğer; kullanıcı hala Kabul Et ve Çalıştır'a tıklamalı ve Çalıştır Rust sunucusunda mevcut `sql_guard` + `references_ch_tables` yönlendirmesinden geçer). Sohbet uç noktası `agent:use` ile kapı işlevi görür. Her ikisi de `agent` konteynerinde yapılandırılan bir LLM bağlantısı gerektirir; hiçbiri yapılandırılmamışsa, yerleştirme her iki yolda da "asistan bu dağıtıma yapılandırılmamış" banner sunuyor. + +**Reddişler.** Besteci salt okunur analitik sorguyla yerine getiremediği herhangi bir isteği reddeder ve SQL yerine `-- REFUSE: ` yayınlar. Veri yazacak veya analitik görünümler dışında tablolara (`api_keys`, `users`, `dashboards`, `saved_queries`, `evaluation_jobs`) ulaşacak istekleri reddeder ve besteci yolunda sade metin isteklerini ("bunu açıkla", "bu ne yapar?") reddeder; bunlar sohbet yoluna aittir ve orada sade metin yanıtı üretirler. Yerleştirme reddetme dizesini asistan mesajında satıriçi kırmızı hata çippi olarak işler; hiçbir şey eklenmez. + +**Model seçimi.** Sohbet yolu ile paylaşılır. Yerleştirme başlığındaki model seçici her iki uç noktaya uygulanır (besteci çağrısı seçilen modeli `resolveModel()` üzerinden aracı servise iletir). `AGENTEYE_AGENT_MODELS` birden fazla model listelediğinde, operatörler besteci için bir Haiku-sınıfı seçeneği sohbet için bir Sonnet-sınıfı seçeneği ile karıştırabilirler; kullanıcı konuşma başına seçer. + +**Sayfa başına şablonlar.** Her sayfanın kendi şablonı (başlık, gövde metni, yer tutucu metni ve öneri çipleri) vardır, böylece yerleştirme durduğunuz sayfaya uyum sağlar. Belirli bir rotada sunulan çipleri bestenin ayarlandığı aynı amaçlara eşlenir, bu nedenle bir öneriye tıklamak beklediğiniz düzenlemeyi üretir. + +**Devre dışı bırakmak.** Sohbet yolu ile aynı: yerleştirme + besteci her ikisi de `agent` konteyneri ve onun LLM bağlantısı tarafından kapılı. Belirli bir kullanıcı için sohbet-yalnız davranış istiyorsanız, `queries:run` iznini kaldırın (editörün **Çalıştır** düğmesini de devre dışı bırakır); besteci-yalnız davranış istiyorsanız, o kullanıcının rollerinden `agent:use` kaldırın, sonra `queries:run` ayrı olarak yeniden ekleyin, böylece yazarı tarafından yazılan SQL'i yine de çalıştırabilirler. + +--- + +## Bunu etkinleştirmek + +`agent` servisi Docker Compose dosyasında ve Kubernetes manifestlerinde gönderilir. Asistanı açmak için **(1)** bir LLM uç noktası ve **(2)** asistanın adanmış veri anahtarı sağlayın. + +### 1. Bir LLM bağlantısı seçin + +Bunlardan birini seçin ve `agent` serviste karşılık gelen değişkenleri ayarlayın: + +**a) Anthropic doğrudan** + +``` +ANTHROPIC_API_KEY=sk-ant-... +``` + +**b) Portkey üzerinden (önerilen; model-katalog slug, yalnızca anahtar)** + +``` +PORTKEY_API_KEY= +AGENTEYE_AGENT_MODEL=@/claude-sonnet-4-6 +``` + +Bu en basit yol: Portkey'de bir **Anthropic integrasyon** ayarlayın (Model +Katalog); bir **slug** alır. Modeli `@/` olarak adlandırın ve slug +sağlayıcı + kimlik bilgisi yönlendirmesi taşır, bu nedenle **sanal anahtar gerekli değildir**, +sadece Portkey API anahtarınız. Aracı yalnızca `x-portkey-api-key` gönderir ve Portkey ağ geçidine işaret eder; Portkey geri kalanını çözer. (Bir *sade* model adı "x-portkey-config veya x-portkey-provider başlığı gerekli" ile başarısız olur; `@slug/` öneki +anahtara göre işlemeyi mümkün kılan şeydir.) Kendi kendine barındırılan bir ağ geçidi için `PORTKEY_BASE_URL` ayarlayın. + +İstek başına yönlendirmeyi slug yerine tercih ediyor musunuz? `PORTKEY_VIRTUAL_KEY=` ayarlayın (veya +`PORTKEY_CONFIG=`) sade `AGENTEYE_AGENT_MODEL` ile. + +**c) Herhangi bir uyumlu Anthropic ağ geçidi (LiteLLM, kendi kendine barındırılan, …)** + +``` +ANTHROPIC_BASE_URL=https://your-gateway +# Newline-sınırlandırılmış "Ad: Değer" başlık satırları (JSON DEĞİL): +ANTHROPIC_CUSTOM_HEADERS=x-my-header: value +``` + +**d) Amazon Bedrock / Google Vertex** + +``` +CLAUDE_CODE_USE_BEDROCK=1 # + ortamda standart AWS kimlik bilgileri +# veya +CLAUDE_CODE_USE_VERTEX=1 # + ortamda standart GCP kimlik bilgileri +``` + +İsteğe bağlı olarak varsayılan modeli `AGENTEYE_AGENT_MODEL` ile sabitleyin (varsayılan `claude-sonnet-4-6`). Kullanıcıların birden fazla model arasında **seçmesine** izin vermek için `AGENTEYE_AGENT_MODELS` virgülle ayrılmış bir izin listesine ayarlayın (örn. +`@anthropic-prod/claude-opus-4-7,@anthropic-prod/claude-sonnet-4-6`); sohbet başlığında bir model seçici görünür ve her kullanıcının seçimi hatırlanır. Aracı yalnızca bu izin listesindeki bir modeli çağırır. + +### 2. Asistan anahtarını sağlayın + +Herhangi bir rastgele gizli dizi seçin ve bunu **agent**e `AGENTEYE_API_KEY` ve **server**e `AGENT_API_KEY` olarak verin (aynı değer). Başlangıçta sunucu bunu `dashboard-assistant` adlı adanmış bir anahtar olarak tohumlar; bu sabit izin seti ile: `events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run`. Yazma izinleri yalnızca onay-kapılı araçlarla çalıştırılır (yukarıda "Neler yapabilir ve yapamaz"a bakın). **Manuel anahtar hazırlama adımı ve yönetici anahtarı yok**. İzin seti sunucuda sabitlenmiş ve tohumlanmış anahtar **korumalı**dır: anahtarlar API'si üzerinden devre dışı bırakılamaz veya yeniden oluşturulamaz; değeri değiştirerek ve sunucuyu yeniden başlatarak döndürün. Yönetici/pano anahtarını **yeniden kullanmayın**. + +```bash +SECRET="$(openssl rand -base64 32)" +# agent serviste: +AGENTEYE_API_KEY="$SECRET" +# server serviste: +AGENT_API_KEY="$SECRET" +``` + +Kubernetes'te bu sizin için bağlanır: `AGENTEYE_API_KEY` `agenteye-agent` sırrına koyun ve sunucu Deployment zaten aynı değeri `AGENT_API_KEY` olarak okur. + +### 3. Paylaşılan pano↔agent belirtecini ayarlayın + +Aynı `AGENTEYE_AGENT_TOKEN` **hem** `dashboard` hem de `agent` servislerinde ayarlayın. Pano, dahili aracı servisi çağırırken bunu sunuyor; aracı onsuz çağrıları reddeder. + +### 4. Kullanıcılara erişim verin + +İlgili pano operatörlerine `agent:use` iznini verin (bkz. [enterprise-docs/api-keys.md](/tr/agenteye/api-keys)). Bunu yapmayanlar asistanı asla görmezler. + +Bir LLM uç noktası ve salt okunur anahtar ayarlandıktan sonra, **sunucuyu** (salt okunur anahtarı tohumlamak için) ve **aracı** servisi yeniden başlatın. Asistan yerleştirmesi sağ kenarında `agent:use` kullanıcısı için görünür, varsayılan olarak kapatılır; rayla tıklayın veya `⌘J` / `Ctrl+J` tuşlarına basın genişletmek için. + +--- + +## Ortam değişkeni başvurusu + +**`agent`** serviste ayarlayın: + +| Değişken | Amaç | +|---|---| +| `PORTKEY_API_KEY` | Portkey üzerinden yönlendir (aracı bu anahtar yardımıyla ağ geçidi bağlantısını kurar) | +| `PORTKEY_VIRTUAL_KEY` | Anthropic kimlik bilgileriniz için Portkey sanal anahtarı (anahtar varsayılan config'i varsa isteğe bağlı) | +| `PORTKEY_CONFIG` / `PORTKEY_BASE_URL` | Adlandırılmış Portkey yapılandırması / kendi kendine barındırılan Portkey ağ geçidi URL'si (isteğe bağlı) | +| `PORTKEY_PROVIDER` | Portkey sağlayıcı slug — `PORTKEY_VIRTUAL_KEY` / `PORTKEY_CONFIG` yanında üçüncü bir yönlendirme seçeneği (bunlardan hiçbiri ayarlanmadığında kullanılır) | +| `ANTHROPIC_API_KEY` | Doğrudan Anthropic erişimi (ağ geçidi / Bedrock / Vertex için alternatif) | +| `ANTHROPIC_AUTH_TOKEN` | `Authorization: Bearer` yerine `x-api-key` üzerinden kimlik doğrulayan bir ağ geçidi için taşıyıcı belirteci (isteğe bağlı) | +| `ANTHROPIC_BASE_URL` | Portkey olmayan ağ geçidi için uç nokta | +| `ANTHROPIC_CUSTOM_HEADERS` | Portkey olmayan ağ geçidi için ekstra başlıklar: newline-sınırlandırılmış `Ad: Değer` satırları (JSON değil) | +| `CLAUDE_CODE_USE_BEDROCK` / `CLAUDE_CODE_USE_VERTEX` | Bedrock / Vertex üzerinden yönlendir | +| `AGENTEYE_AGENT_MODEL` | Varsayılan model kimliği (varsayılan `claude-sonnet-4-6`) | +| `AGENTEYE_AGENT_MODELS` | Kullanıcının sohbet başlığında seçebileceği virgülle ayrılmış modeller izin listesi. Tek bir sabit model için ayarlanmamış bırakın. Yukarıdaki varsayılan bunlardan biri olmalıdır (yoksa eklenir). | +| `AGENTEYE_AGENT_MAX_CONCURRENCY` | Pod başına maksimum eş zamanlı sohbetler (varsayılan 4); fazla istekler 429 alır | +| `AGENTEYE_API_KEY` | Asistanın veri anahtarı. Sunucunun `AGENT_API_KEY` ile **aynı** değeri ayarlayın, başlangıçta sabit kapsamlı izin seti ile tohumlar (adım 2'ye bakın). | +| `AGENTEYE_AGENT_TOKEN` | Pano ile paylaşılan gizli dizi | +| `AGENTEYE_SERVER_URL` | AgentEye sunucu URL'si (varsayılan `http://server:8080`) | +| `AGENTEYE_AGENT_ALLOW_NO_ORG` | **Multi-tenancy.** Varsayılan olarak kapalı (başarısız-kapalı): asistan kuruluş bağlamı taşımayan `/chat` isteğini `400` ile reddeder, çünkü çalıştırdığı her araç bir kuruluşla sınırlandırılır. Pano kuruluş-farkında olması sonrasında her zaman bu bağlamı gönderir, bu nedenle normalde bunu ayarlanmamış bırakırsınız. `1` olarak ayarlayın **sadece** henüz kuruluş-farkında olmayan pano kuruluş-farkında aracı ile konuştuğunda geçiş yaşadığı sırada, bu nedenle asistan reddetme yerine `default` kuruluşuna geri döner. Pano yükseltmesi geliştiğinde temizleyin. | +| `AGENTEYE_AGENT_MAX_STEPS` | Yanıt başına maksimum araç-kullanım adımları (varsayılan 8) | +| `AGENTEYE_AGENT_TIMEOUT_MS` | Genel `/chat` istek zaman aşımı (tüm model dönüşleri + araç adımları), milisaniye cinsinden (varsayılan 90000); SQL aracının kendi 10s sınırı vardır | +| `AGENTEYE_AGENT_SELF_TELEMETRY` | Asistanın kendi çalışmalarını AgentEye'a kaydetmek için `1` | +| `AGENTEYE_TELEMETRY_API_KEY` | Kendi kendine araçlama için ayrı `events:add`-yalnızca anahtar | +| `AGENTEYE_AGENT_ENV` | Asistanın kendi kendine telemetriye uygulanan ortam etiketi (varsayılan `prod`) | + +**`dashboard`** serviste ayarlayın: + +| Değişken | Amaç | +|---|---| +| `AGENTEYE_AGENT_URL` | Panoda aracı servise nereden ulaştığı. Çerçeveli Kubernetes manifestleri ve Compose dosyası bunu `http://agent:9100` olarak ayarlar. Asistanı tamamen gizlemek için ayarlanmamış bırakın. | +| `AGENTEYE_AGENT_TOKEN` | Aracının belirteci ile eşleşmelidir | + +--- + +## Telemetri & Kullanıcıların Ne Sorduğunu Görmek + +İstem **içeriği varsayılan olarak kendi sistemleriniz içinde kalır**. Üç katman: + +1. **Sohbet deposu**: her istem ve yanıt AgentEye veritabanınızda kaydedilir (kullanıcı başına, özel) ve asistanın geçmiş seçicisinden yeniden yüklenebilir. Bu, kullanıcıların ne sorduğunun kalıcı kaydıdır. +2. **Ürün analitiği**: pano **yalnızca meta verileri** (asistanın ne sıklıkta kullanıldığı, araç sayıları, gecikme) analitiğinize kaydeder. İstem **metni** bu yolda asla dahil edilmez. +3. **Kendi kendine araçlama (isteğe bağlı)**: `AGENTEYE_AGENT_SELF_TELEMETRY=1` ayarlayın (artı bir `events:add`-yalnızca `AGENTEYE_TELEMETRY_API_KEY`) ve asistan kendi çalışmalarını AgentEye'a `dashboard-assistant` ajanı olarak kaydeder. Daha sonra kullanıcı istemi ve asistanın akıl yürütmesini başka tüm şeyler için kullandığınız aynı oturumlar/olaylar görünümlerinde izlersiniz. Not: bu olaylar `events:read` sahip herkese görünür; bu çok geniş ise, bunu kapalı bırakın. + +--- + +## Devre dışı bırakmak + +Bunlardan herhangi biri asistanı devre dışı bırakır (yerleştirme rayı kayboluyor): + +- Panoda `AGENTEYE_AGENT_URL` kaldırın, **veya** +- Aracıda LLM uç noktasını yapılandırılmamış bırakın (hiçbir `ANTHROPIC_API_KEY` / ağ geçidi / Bedrock / Vertex), **veya** +- `agent` servisi hiç dağıtmayın. + +--- + +## Güvenlik özeti + +- **Sessiz yazma yok**: asistanın yazma araçları (`create_saved_query`, `update_saved_query`, `create_dashboard`, `update_dashboard`, `add_query_to_dashboard`) sohbet içinde Onayla düğmesinde açık operatör tıklaması olmadan yürütülemez; SDK'nın ön çağrı kapısı arka kanala aracıya ulaşan bir onay kadar aracı engeller. Bunu devre dışı bırakan ayar yoktur. +- **Sabit, dar veri kapsamı**: asistan sunucuya adanmış bir anahtarla kimlik doğrular; izin seti sunucuda sabittir (`events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run`). Model ne denerse desin yazabilirse sunucu bu kapsamın dışındaki her şeyi reddeder. +- **Silme yüzeyi yok**: anahtar silme izni taşımaz ve silme aracı açığa çıkmaz. Operatörler pano UI'si üzerinden siler, asistan üzerinden asla. +- **Yalnızca dahili**: aracının herkese açık rotası yok; sadece pano bunu çağırabilir ve sadece paylaşılan belirteci ile. (Kubernetes'te, bir NetworkPolicy aracıyı sadece AgentEye sunucusuna ve LLM uç noktasına ulaşmak ile sınırlar.) +- **Kullanıcı başına kapsamlı**: sadece `agent:use` kullanıcıları asistanı alırlar ve sadece her kullanıcının okuma izinleriyle eşleşen araçlar verilir. +- **Ham HTML yok / bağlantı sızdırması yok**: cevaplar sanitizlenmiş markdown olarak işlenir; harici bağlantılar etkisizleştirilir. + +Yaygın sorunlar için [enterprise-docs/troubleshooting.md](/tr/agenteye/troubleshooting) bölümüne bakın. \ No newline at end of file diff --git a/docs/tr/agenteye/audits.mdx b/docs/tr/agenteye/audits.mdx new file mode 100644 index 00000000..b5f48779 --- /dev/null +++ b/docs/tr/agenteye/audits.mdx @@ -0,0 +1,107 @@ +--- +title: "Denetimler — agentic iyileştirme tespiti" +description: "AgentEye Denetimleri — agentic iyileştirme tespiti belgelendirmesi." +--- + + +Denetimler, agent günlüklerinizi **oturumlarda** tarayarak iyileştirmeye değer şeyleri bulan yinelenen işlerdir. Bir uyarı zaten bildiğiniz bir metriği gerçek zamana yakın şekilde izlerken, bir denetim *araştırır*: belirlediğiniz bir programa göre, pencere üzerinde deterministik bir politika geçişi çalıştırır, ardından bir **AI güvenilirlik agensi** oturumlarınıza bırakılır — agent verileri kendisi sorgular, şüpheli transkriptleri okur ve (yardımcı olduğunda) küçük analiz betikleri çalıştırır, ardından **iyileştirme önerileri** yazılır ve her birinin arkasındaki kanıtlar sunulur. + +Denetimler "agenlarımda neyi düzeltmeliyim veya iyileştirilmeliyim?" sorusuna yanıt vermek için kullanılır — uyarılar ise belirli bir eşik geçildiğinde anında sayfalanmak için kullanılır. Her iyileştirme, arkasındaki tam oturumlar ve sorgularla bağlantılıdır ve bir tıkla tekrarlanan olayları yakalaması için önceden doldurulmuş bir uyarı oluşturulabilir. + +Gösterge paneli yüzeyi **`//audits`** olup (`sidebar` → *analyze* → *audits*), `audits:read` / `audits:write` izinleriyle korunur. + +--- + +## Bir çalıştırma nasıl işler + +Her çalıştırmanın iki katmanı vardır — deterministik bir taban ve agentic araştırma. + +### 1. Politika geçişi (deterministik) + +Herhangi bir model çalışmadan önce, denetim pencere üzerinde küçük bir **SQL politika denetimleri** kataloğunu çalıştırır: bilinen kötü örüntüleri işaretleyen ve *kaç* olay / *hangi* oturumlar eşleştiğini raporlayan sınırlandırılmış toplam sorgular — hiçbir zaman eşleşen metin kendisi değil. Katalog şunları içerir: + +- Olay yüklerindeki **Gizli dizi / kimlik bilgisi sızıntısı** — AWS erişim anahtarları, `sk-…` API anahtarları, PEM özel anahtarları, JWT / taşıyıcı belirteçleri ve `KEY=…` kimlik bilgisi atamaları. +- **İstem enjeksiyonu işaretleri** — "önceki talimatları yoksay", "sistem isteminizi açığa çıkarın" ve benzer olanlar. +- **KKB** — SSN benzeri sayılar (buluşsal). +- **Araç izni reddetmeleri** ve **kaçak araç çağrısı döngüleri**. + +Politika isabet etmeleri, bulgular olarak kalıcı hale getirilir (tür `policy`) ve **her zaman yüzeyde görünür** (çalışma başına sınırlama tarafından hiçbir zaman kırpılmaz) ve AI agensi için başlangıç ipuçları olarak verilir. Bu katman modeliin gerektirmediğinden, bir denetim AI agensi kullanılamasa bile en önemli güvenlik sinyallerini üretir. + +### 2. Agentic araştırma (AI) + +Denetim daha sonra bir **otonom güvenilirlik agensi** çalıştırır (gösterge paneli asistanını güçlendiren aynı Claude Agent SDK hizmeti, denetim özel istemine sahip). Denetimin **kapsamı** (seçili agenler × ortamlar) ve **zaman penceresi** verildiğinde, agent: + +- analitik tablolarınıza karşı salt okunur SQL sorguları çalıştırır, +- bir avuç temsili oturum transkriptini okur, +- isteğe bağlı olarak SQL'in ifade edemeyeceği analiz için kilitlenmiş bir in-pod korumalı alanında kısa **Python betikleri** yazar ve çalıştırır (ağ yok, dosya sistemi erişimi yok, gizli diziler temizlendi) — hata kümeleme, dağılımları hesaplama, zaten getirdiği yükleri tarama, +- ve bulduğu her iyi kanıtlanmış **iyileştirme** kaydeder. + +Birkaç araştırma satırından geçer — hata kümeleme, tabana karşı sapma, transkriptlerde hedef başarısızlığı, araç suistimali, kalite/maliyet dengesi ve kapsama boşlukları — denetimin **duyarlılığında** (düşük / orta / yüksek). Her iyileştirme **kanıt belirtmelidir**: agentin aslında incelediği oturum kimlikleri ve/veya çalıştırdığı SQL. Sunucu alıntı yapılan oturumların var olduğunu doğrular ve **kanıtı kalmayan hiçbir iyileştirmeyi atar**, bu nedenle agent araştırır ancak asla uydurmazı. + +Her iyileştirme taşır: + +- yapılacak somut değişiklik **önerisi** — istemi ince ayarı, araç şeması düzeltmesi, yeniden deneme politikası, koruma, daha fazla eval kapsamı, +- **beklenen etki** ve **çaba** tahmini (düşük / orta / yüksek), +- bir **büyüklük** — `big` (operatör sayfalanmalı), `medium` (çalışma raporuna dahil), veya `small` (gösterge paneli bağlamı), +- stabilir **parmak izi** (sorunun kategorisi + kapsamından, *bu çalıştırmanın oturumlarından değil*) böyle aynı sorun kanıt değişse bile çalıştırmadan çalıştırmaya izlenir, +- ve basit bir deterministik gözlemci tekrarlanan olayları yakalarken, bir tıkla oluşturabileceğiniz **önerilen uyarı**. + +> **AI katmanı isteğe bağlı ancak tavsiye edilir.** Denetim ardışık düzeni için hiçbir AI agensi yapılandırılmamışsa, çalıştırmalar yine de çalıştırılır, politika bulguları kalıcı hale getirilir ve agentic katman için sessizce geçmek yerine "analiz kullanılamıyor" dürüstçe rapor edilir. + +### Başarısızlık yönetim modları + +İyileştirmeler, kuruluşunuzun dayanıklı **başarısızlık modu kataloğunda** sınıflandırılır (veya yeni bir mod önerilir). Modlar, örüntülere çalıştırmalar arasında kararlı bir kimlik ve uzun ufuk tekrarlanan olay izlemesi verir. + +## Değerlendirme yaşam döngüsü + +Bulgu sayfasında (`/audits//findings/`): + +| İşlem | Etki | +|---|---| +| **kabul et** | Bulguyu görünür tutar ancak önceliğini yarıya indirir. | +| **çöz** | Düzeltilmiş olarak işaretler. Örüntü daha sonra gerçekten geri dönerse, **yeni** olarak yeniden açılır — bu nedenle regresyon sessiz değil, gürültülü olur. | +| **sessiz kılma** / **reddet** | Dayanıklı suppression: örüntünün parmak izi hatırlanır ve çalıştırmalar arasında bile hiçbir zaman yüzeyde görünmez. "Bilinen, kabul edilen" için sessiz kılmayı; "yararlı değil" için reddet'i kullanın. | +| **yeniden aç** | Suppression / çözümü temizler ve örüntüyü yeniden sıralar. | +| **ata** | Bulguyu mülkiyeti için bir operatöre (kuruluş üyesi) yönlendirir. Öncelik ve suppression durumu değişmez. | + +Düşük sinyalli gürültü, agentic iyileştirmelerde çalışma başına bulgu sınırı (`top_k`) ile audit başına kontrol edilir. Politika bulguları sınırı atlar (güvenlikle ilgilidir ve her zaman gösterilir). Sınır tarafından kesilen her şey, çalıştırma istatistiklerinde sayılır — hiçbir şey sessizce bırakılmaz. + +## Planlama + +- **Kadans** (`schedule_interval_secs`): saatlik ile haftalık; **günlük varsayılandır**. Denetimler kasıtlı olarak uyarılardan daha kaba — agentic araştırma tam pencereleri tarar ve dakikalar boyunca çalışır. +- **Pencere**: sabit bir geri dönüş (ör. "her çalıştırma son 7 günü tarar") veya **son çalıştırmadan beri** (varsayılan) — her çalıştırma önceki başarılı olanın bıraktığı yerden devam eder, sınır olayları hiçbir zaman kaçırılmayacak şekilde küçük bir örtüşme ile. +- Sonraki çalıştırma, önceki tamamlandıktan sonra tam bir aralık sonra planlanır, bu nedenle yavaş bir çalıştırma aynı denetimin ikinci eşzamanlı çalıştırmasını hiçbir zaman istiflemez. +- Denetim sayfasında **şimdi çalıştır** onu hemen gerekli duruma getirir. + +## Model seçimi + +Denetim oluştururken, araştırmanın kullandığı modeli operatörünüzün agent hizmeti için yapılandırdığı **model listesinden** seçebilirsiniz. Tek bir model yapılandırılmışsa, seçici bunu başlık olarak gösterir; birkaçı varsa, seçim yaparsınız. Ayarlanmamış olarak bırakmak yapılandırılmış varsayılanı kullanır. + +## Bildirimler + +Çalıştırma **yeni** bulgular ortaya çıkardığında, denetim kuruluşunuzun yapılandırılmış kanallarını bilgilendirir — uyarı ardışık düzeninin kullandığı aynı `alerts.enabled_channels` geçidi ve ayarları: + +- **Slack** — önemli (`big`) yeni öğelerin ve derin bağlantının özeti. +- **E-posta** — tasarlanmış **denetim raporu** yeni iyileştirmeleri listeler (üst önem derecesi, her öğe önerileri, derin bağlantı), denetim **e-posta** kanalı ekli olduğunda ve en az bir yeni bulgu olduğunda gönderilir. + +Yinelenen ancak bilinen bulgular yeniden bildirim almaz. + +## Yapılandırma referansı + +Denetim tanımları gösterge panelinde (`/audits/new`) veya API aracılığıyla yönetilir. Audit başına ayarlar, program kadansı ve penceresi, kapsamı (`{"environments": [...], "agent_ids": [...]}`), duyarlılığı (`low` / `medium` / `high`), bildirim kanalları, çalıştırma başına bulgu sınırı (`top_k`) ve modeli (via `llm_budget.model`) içerir. Operatör seviyesi sunucu ayarları (zaman aşımları, korumalı alan, agent-hizmeti URL'si) [deployment.md](/tr/agenteye/deployment) adresinde belgelenmiştir. + +## API + +Tüm uç noktalar kuruluş kapsamlıdır ve standart taşıyıcı anahtar kimlik doğrulamasını izler (bkz. [api-keys.md](/tr/agenteye/api-keys)). + +| Uç nokta | İzin | Amaç | +|---|---|---| +| `GET /audits` · `POST /audits` | `audits:read` / `audits:write` | Denetim tanımlarını listele / oluştur. | +| `GET` / `PUT` / `DELETE /audits/:id` | read / write / write | Denetimi incele, düzenle, sil. | +| `POST /audits/:id/run` | `audits:write` | Denetimi hemen gerekli duruma getir. | +| `GET /audits/:id/runs` | `audits:read` | Çalıştırma geçmişi (pencere, durum, istatistikler, bulgu sayıları). | +| `GET /audits/findings` | `audits:read` | Kuruluş geneli bulgular, `audit_id`, `status` ile filtrelenebilir; önceye göre sıralanır. | +| `GET /audits/findings/:fid` | `audits:read` | Tam bulgu detayı (öneri, kanıt, öncelik). | +| `POST /audits/findings/:fid/status` | `audits:write` | Değerlendirme: `{"action": "ack" \| "mute" \| "dismiss" \| "resolve" \| "reopen" \| "assign"}`. | + +"Denetim çalıştı ancak hiçbir şey bulunamadı", "kod korumalı alanı devre dışı bırakıldı" ve "denetim e-postası teslim edilmedi" için bkz. [troubleshooting.md](/tr/agenteye/troubleshooting#audits). \ No newline at end of file diff --git a/docs/tr/agenteye/cli-recipes.mdx b/docs/tr/agenteye/cli-recipes.mdx new file mode 100644 index 00000000..9534c565 --- /dev/null +++ b/docs/tr/agenteye/cli-recipes.mdx @@ -0,0 +1,170 @@ +--- +title: "Ajanlar için CLI tarifleri" +description: "Ajanlar için AgentEye CLI tarifleri belgelendirmesi." +--- + + +Oturum, olay ve değerlendirme verilerini (ve yeniden değerlendirmeleri tetikleyin) doğrudan bir betikten veya kodlama ajanından çekin, `jq` içine doğrudan akan temiz JSON çıktısı ile. Bu tarifler, AgentEye'ın gözlenebilirlik verilerini, bir terminal kullanıcısının veya bir AI kodlama ajanının (Claude Code, Cursor) pano üzerinden tıklamadan sorgulayabileceği ve otomatikleştirebileceği bir şeye dönüştürür. + +Aşağıdaki desenler AgentEye CLI'si (`agenteye`) için kopyala-yapıştır hazırlığındadır. Kurulum, kimlik doğrulama ve tam seçenek listesi için [CLI](/tr/agenteye/cli) bölümüne bakın; yerleşik yardım için `agenteye -h` veya `agenteye -h` komutunu çalıştırın. + +## Altın kurallar + +1. **Global seçenekler komutun *öncesinde* gelir.** `agenteye --json sessions` doğrudur; `agenteye sessions --json` değildir. Global seçenekler şunlardır: `--json`, `--base-url`, `--org`, `--token`, `--insecure`/`--secure`, `--timeout`, `--quiet`, `--no-color`. +2. **Çıktıyı ayrıştırdığınız zaman `--json` geçirin.** Veriler **stdout** üzerinden JSON olarak çıkış yapar; insan durumu ve hatalar **stderr** üzerine gider, böylece stdout temiz kalır ve `jq` içine yönlendirilebilir. +3. **Çıkış koduna göre dallanma yapın**, stderr metnine göre değil: `0` tamam · `2` hatalı argümanlar · `3` panoya ulaşılamıyor · `4` giriş yapılmamış veya süresi dolmuş · `5` izin yok. +4. **`-h` ile keşfedin.** Her komut filtrelerini, değer biçimlerini ve JSON şeklini belgelendiren. + +## Tek seferlik kurulum + +```bash +export AGENTEYE_DASHBOARD_URL=https://agenteye.example.com # böylece --base-url tekrarlamaz +agenteye login --email you@example.com # e-posta ile gelen kodu yapıştırın; ~24s geçerli +``` + +## İş yapmadan önce kimlik doğrulamayı doğrulayın + +`whoami` eksik veya süresi dolmuş oturumlarda hata vermez; bunun yerine `logged_in:false` bildirir, böylece bir ajan kimlik doğrulama durumunu güvenli bir şekilde araştırabilir. (Temel URL ayarlanmamışsa veya pano ulaşılamazsa yine de sıfır olmayan çıkış verebilir.) + +```bash +if [ "$(agenteye --json whoami | jq -r .logged_in)" != "true" ]; then + echo "Not authenticated. Run: agenteye login" >&2; exit 1 +fi +``` + +## Başarısız veya düşük puanlı oturumları bulun + +```bash +# son 24 saatte değerlendirmesi hata veren oturumlar +agenteye --json sessions --since 24h --status error | jq -r '.sessions[].session_id' + +# bir ajan için yardımcılık açısından <= 0.5 puan alan değerlendirmeler +agenteye --json evals --agent-id checkout-bot --score helpfulness:..0.5 \ + | jq '.evaluations[] | {session_id, scores}' +``` + +Puan filtreleme **`evals`** üzerinde olur, `sessions` üzerinde değil. `--score KEY:MIN..MAX` tekrarlanabilir ve VE-birleştirilir; her iki sınır isteğe bağlıdır (`..0.5` ≤ 0.5 anlamına gelir, `0.9..` ≥ 0.9 anlamına gelir). İstek başına 20'ye kadar puan filtresi geçirebilirsiniz; daha fazla HTTP 400 döndürür. `sessions`, `--env`, `--status`, `--agent-id`, `--session-id` ve zaman aralığı filtrelerini `evals` ile paylaşır, ancak `--score` değerine sahip değildir. + +## Bir oturumu baştan sona okuyun + +Tek bir `session show` komutu yoktur — olay izini oturumun değerlendirmesi ile birleştirin: + +```bash +# oturumun en son değerlendirmesi (durum + puanlar) +agenteye --json evals --session-id run-001 | jq '.evaluations[0] | {status, scores}' + +# koşudaki her olay (tam tarama için --limit yükseltin) +agenteye --json events --session-id run-001 --all --limit 1000 | jq '.events[] | {ts, event_type}' + +# bir oturumdaki sadece araç çağrıları +agenteye --json events --session-id run-001 --event-type tool_use,tool_result --all \ + | jq '.events[].payload' +``` + +## Her şeyi getir (sayfalandırma) + +Sonuçlar en yeniden başa ve imleç-sayfalandırılmış şekildedir. + +```bash +# tek çekim: 200 satırlık sayfalarda 500'e kadar satır getir +agenteye --json events --session-id run-001 --limit 500 --all > events.json + +# manuel sayfalandırma: sonraki imleci geri besleyin +page=$(agenteye --json events --limit 100) +cursor=$(echo "$page" | jq -r '.next_cursor // empty') +[ -n "$cursor" ] && agenteye --json events --limit 100 --cursor "$cursor" +``` + +## Çıktıyı --fields ile daraltın + +Bir ajanın okuması gereken şeyi azaltmak için anahtarları (hem tabloda hem de `--json`'de) kısıtlayın. + +```bash +agenteye --json sessions --since 7d --fields session_id,status,scores | jq -c '.sessions[]' +agenteye --json events --session-id run-001 --fields ts,event_type --all +``` + +Bilinmeyen alan adları geçerli listeyle reddedilir (çıkış `2`) — alan adlarını keşfetmenin ucuz bir yolu. + +## Geçerli filtre değerlerini bulun + +```bash +agenteye --json list envs | jq -r '.values[]' # --env için değerler +agenteye --json list tools | jq -r '.values[]' # araç adları; ayrıca ajanlar, modeller, event_types, … +agenteye --json list score_filters | jq -r '.values[]' # --score KEY:MIN..MAX için geçerli KEY +``` + +## Kuruluşunuzu seçin (çok kiracılı) + +Birden fazla kuruluşa aitse, oturum açmada etkin kiracıyı seçin (kaydedilir): + +```bash +agenteye login --org acme --email you@corp.com # oturum açma ile aynı adımda kiracıyı ayarla +agenteye --json orgs list | jq -r '.orgs[].org_slug' +agenteye --org globex --json sessions --since 24h # bir komut için geçersiz kıl +``` + +`--org` olmayan çok kuruluşlu oturum açma sıfır olmayan çıkış verir ve aralarından seçim yapılacak kuruluşları yazdırır. + +## SDK/toplayıcı için bir API anahtarı sağlayın + +```bash +# gizli bir kez yazdırılır — --json ile bu .key alanıdır +key=$(agenteye --json keys create ci-bot --add events:read.add | jq -r '.key') +agenteye keys regenerate ci-bot --yes # döndür; iptal etmek için agenteye keys disable ci-bot --yes +``` + +## Kaydedilmiş veya geçici bir sorgu çalıştırın + +```bash +agenteye --json query run --sql "select count(*) from analytics.events" | jq '.rows' +agenteye --json query run errs --arg prod | jq '.rows' # kaydedilmiş bir sorgu + konumsal $1 +``` + +## Etkileşimsiz olarak bir olayı ayırıştırın + +```bash +id=$(agenteye --json incidents list --state firing | jq -r '.incidents[0].id') +agenteye incidents ack "$id" +agenteye incidents assign "$id" you@corp.com +agenteye incidents resolve "$id" --yes +``` + +> Mutasyonlar `--json` altında veya stdin bir TTY değilse onay istemini otomatik olarak atlar, böylece ajanlar asla takılmaz; başka yerlerde açıkça atlamak için `--yes`/`-y` geçirin. + +## Bir betik içinde çıkış kodu işleme + +```bash +out=$(agenteye --json sessions --since 1h) || code=$? +case "${code:-0}" in + 0) echo "$out" | jq '.sessions | length' ;; + 4) echo "Session expired - run 'agenteye login'." >&2 ;; + 5) echo "Missing permission (ask an admin for evaluations:read)." >&2 ;; + 3) echo "Dashboard unreachable - check the URL." >&2 ;; + *) echo "Unexpected error (exit ${code})." >&2 ;; +esac +``` + +## JSON çıktı şekilleri + +| Komut | stdout JSON (`--json` ile) | +|---|---| +| `whoami` | `{"logged_in": true, "id", "email", "is_instance_admin", "active_org", "permissions": [...], "memberships": [...]}` veya `{"logged_in": false}` | +| `orgs list` | `{"active_org", "orgs": [{"org_slug","org_name","permission_set","permissions"}]}` | +| `events` | `{"events": [...], "next_cursor": }` | +| `evals` | `{"evaluations": [...], "next_cursor": }` | +| `sessions` | `{"sessions": [...], "next_cursor": }` | +| `errors` | `{"errors": [...], "next_cursor": }` | +| `list ` | `{"kind", "values": [...]}` | +| `keys list` / `keys create` | `{"keys": [...]}` / `{id, name, permissions, created_at, key}` (`key` bir kez gösterilir) | +| `query run` | `{columns: [{name,type}], rows: [[...]], truncated, elapsed_ms}` | +| `users list` / `settings list` | `{"users": [...]}` / `{"settings": [...]}` | +| `alerts list` / `incidents list` | `{"alerts": [...]}` / `{"incidents": [...]}` | +| oluştur/güncelle/sil (herhangi bir) | kaynak nesnesi veya silmeler için `{"deleted": true, "id"}` | +| başarısızlık (herhangi bir, `--json` ile) | stdout üzerinde `{"error": "...", "exit_code": , "status"?: , "hint"?: "..."}` | + +- Her **olay** öğesi (`events`): `id, session_id, agent_id, event_type, ts, payload, environment`. +- Her **değerlendirme** öğesi (`evals`): `id, session_id, agent_id, environment, status, scores, reasoning, summary, error, attempt_count, duration_ms, completed_at, created_at`. +- Her **oturum** öğesi (`sessions`): `session_id, agent_id, environment, status, scores, event_count, started_at, last_event_at, first_event_id, last_event_id, latest_evaluation`. + +Her komutun `--fields`, tam olarak kendi öğesinin alan adlarını kabul eder — küme `sessions` ve `evals` arasında farklılık gösterir, bu nedenle biri için geçerli bir ad diğeri tarafından reddedilebilir. \ No newline at end of file diff --git a/docs/tr/agenteye/cli-skill.mdx b/docs/tr/agenteye/cli-skill.mdx new file mode 100644 index 00000000..859fd76e --- /dev/null +++ b/docs/tr/agenteye/cli-skill.mdx @@ -0,0 +1,95 @@ +--- +title: "AgentEye CLI Agent Skill" +description: "AgentEye AgentEye CLI Agent Skill belgelendirmesi." +--- + + +**AgentEye CLI becerisi** (`agenteye-cli`), kurulabilir bir *Agent Skill*'dir ve bir kodlama ajanı — Claude Code, Codex ve uyumlu araçlar — için AgentEye dağıtımını düz İngilizce isteklerle [`agenteye` CLI](/tr/agenteye/cli) aracılığıyla çalıştırmayı öğretir: *"bugün bir şey bozuk mu?"*, *"CI'ye sadece olayları itebilen bir anahtar ver"*, *"çalışan olayı kabul et ve bana ata"*. + +Bu, bir hizmet veya ayrı bir ikili **değildir**. Zaten yüklü olduğunuz CLI'nin üstünde çalışan küçük bir talimat paketidir: ajan `agenteye --json …` çalıştırır, temiz JSON'u ayrıştırır ve cevabı metinle veriri. Yapabileceği her şeyi, aynı komutları yazarak kendiniz yapabilirsiniz. + +--- + +## Diğer AgentEye arayüzleriyle ilişkisi + +AgentEye, aynı verilere ve denetimlere ulaşmanın dört yolunu sunar. Birbirini tamamlarlar: + +| Arayüz | Ne olduğu | Nerede çalışır | Şunu kullanın | +|---|---|---|---| +| **[CLI](/tr/agenteye/cli)** | `agenteye` için komut/bayrak referansı | Terminal'iniz | Belirli bir komutu çalıştırmak veya komut dosyası yazmak istediğinizde | +| **[CLI tarifleri](/tr/agenteye/cli-recipes)** | Kopyala-yapıştır `jq`/boru desenleri | Terminal'iniz / komut dosyaları | CLI'ı otomasyon içine entegre ettiğinizde | +| **CLI becerisi** (bu belge) | CLI için doğal dil giriş kapısı | Kodlama ajanınızda, iş istasyonunuzda | Sadece sorup ajanın komutu seçmesini istediğinizde | +| **[Kontrol paneli içi AI Asistanı](/tr/agenteye/assistant)** | Kontrol paneline gömülü sohbet | Kümenizde iç bir `agent` kapsayıcısı | Verileriniz hakkında kontrol paneli içi S&C istediğinizde | + +### Kontrol paneli içi AI Asistanı ile karşılaştırma — önemli bir ayrım + +Bunlar çok farklı etki yarıçaplarına sahip iki farklı araçtır: + +- **Kontrol paneli içi AI Asistanı** ([assistant.md](/tr/agenteye/assistant)), kontrol paneline gömülü bir sohbet olup, iç bir `agent` kapsayıcısı tarafından desteklenir. **Sadece okuma artı onay geçidi yazma**: kaydedilmiş sorguları ve kontrol panellerini taslaklandırabilir, ancak her yazma işlemi sizin açık tıklama onayınız için duraklatılır ve hiçbir zaman silmez. `agent:use` izni ile geçit kilitlidir ve yalnızca görüntülediğiniz org'un verilerini görür. +- **CLI becerisi**, iş istasyonunuzda *sizin* kodlama ajanınız içinde çalışır ve `agenteye` CLI'ı **siz** olarak çalıştırır. CLI'ın **tam yüzeyini, mutasyonlar dahil** gerçekleştirebilir — API anahtarları oluşturmak/döndürmek/devre dışı bırakmak, org ayarlarını değiştirmek, olayları çözmek, kaydedilmiş sorguları silmek — yalnızca CLI oturumunuzun izinleriyle sınırlıdır. Bunu, bu komutları elle çalıştırmak gibi dikkatli bir şekilde ele alın. + +--- + +## Ön Koşullar + +1. **`agenteye` CLI yüklü** ve `PATH`'de ([cli.md](/tr/agenteye/cli)'ye bakın — `pipx install agenteye`). +2. **Kontrol paneli URL'iniz ayarlanmış** (`AGENTEYE_DASHBOARD_URL` veya ajan `--base-url` geçer). +3. **Oturum açılmış bir oturum**: önce kendiniz `agenteye login` çalıştırın. Beceri, e-postayla gönderilen tek seferlik kod oturumunuzu **tamamlayamaz** — oturum eksikse veya süresi dolmuşsa `agenteye login` çalıştırmanızı söyler (CLI çıkış kodu `4`). + +--- + +## Beceriyi yükleme + +Agent Skills, `SKILL.md` içeren klasörlerdir (artı isteğe bağlı referanslar). `agenteye-cli` becerisini ajanınızın baktığı yere beceri klasörünü kopyalayarak yüklersiniz: + +- **Claude Code** — `agenteye-cli/` klasörünü `~/.claude/skills/`'e (her projede kullanılabilir) veya `/.claude/skills/`'e (o depoya kapsamlı) kopyalayın. Claude Code otomatik olarak keşfeder; `/skills` listesi ile doğrulayın veya açıklaması eşleşen bir soruya sorun. +- **Codex (OpenAI)** — Codex aynı `SKILL.md`'yi okur. Paketlenmiş `agents/openai.yaml`, `allow_implicit_invocation: true` ayarlar, bu nedenle Codex bir görev eşleştiğinde beceriyi otomatik seçer; aksi takdirde `$agenteye-cli` olarak açıkça çağırın. + +Beceri, `agenteye` CLI'ı ile birlikte korunur ve AgentEye paketinizin bir parçası olarak dağıtılır — `agenteye-cli` klasörünüz yoksa AgentEye kişinize danışın. Hiçbir şey kapı kilitli değildir: Docker görüntüsüne ve kimlik bilgisine ihtiyacı yoktur, çünkü yalnızca **genel** `agenteye` CLI'ı kendi kontrol panelinize karşı çalıştırır. + +--- + +## Güvenlik — mutasyonlar bir ajan CLI çalıştırırken istem vermez + +**Bir ajanın değişiklik yapmasına izin vermeden önce bunu okuyun.** + +`agenteye` CLI normalde bir yıkıcı işlemden önce *"emin misiniz?"* sorar. **Terminal'e bağlı olmadığı zaman bu — tam olarak bir kodlama ajanı tarafından çalıştırıldığı gibi — ve `--json` de atlar.** Bu nedenle güvenlik istemi ajan için **tetiklenmez**. + +Beceri bunu telafi etmek için yazılmıştır: tam olarak çalıştıracağı komutu belirtmesi ve herhangi bir durum değişikliğinden önce sizden açık **TAMAM** alması talimatı verilir. Bu disiplini koruyun — AgentEye'ı bir ajan aracılığıyla çalıştırdığınızda, *siz* onay adımısınız. İzlemek için durum değiştiren komutlar: + +- `keys create` / `update` / `disable` / `regenerate` +- `users create` / `update` / `disable` / `enable` +- `settings set` +- `alerts create` / `update` / `delete` / `test` +- yazma `incidents` alt komutları: `ack` / `assign` / `resolve` / `open` / `comment-add` / `comment-delete` / `subscribe` / `unsubscribe` +- `query create` / `update` / `delete` +- `agent rename` / `delete` +- `orgs switch` + +**Gözlemle**'nin altındaki her şey (`events`, `sessions`, `evals`, `errors`, `list`, `whoami`, `orgs list/current/perms`) salt okunur ve hiçbir şeyi değiştirmez. + +Ajan **siz** olarak hareket ettiği için, yalnızca oturumunuzun izin verdiği şeyleri yapabilir — izinler **org başına** çözümlenir ([api-keys.md](/tr/agenteye/api-keys)'ye bakın). İzin almadığınız bir komut, tam izin adıyla çıkış kodu `5` döndürür, bu nedenle ajan size tam olarak ne için admin'den istemesi gerektiğini söyleyebilir ve karamsar bir şekilde başarısız olmak yerine. + +--- + +## Ne sorabileceğiniz + +Beceri, düz İngilizce niyeti doğru `agenteye` komutuna eşler, önce geçerli değerleri keşfeder (`list `, `whoami`) böylece tahmin etmez: + +- *"Hiçbir şey bozuk mu / son 24 saatte başarısız mı?"* → `errors --since 24h --aggregate`, ardından bir döküm. +- *"Oturum `run-001` neden başarısız oldu?"* → `events --session-id run-001 --all` + `evals --session-id run-001`. +- *"Bu haftada kalite nasıl eğilim gösteriyor?"* → `evals --aggregate --since 7d`, ardından düşük puanlı çalışmalara dalın. +- *"CI'ye sadece olayları itebilen bir anahtar ver."* → `keys create ci --add events:add` (komutu belirtir, ardından oluşturur ve tek seferlik gizliyi yakalar). +- *"Kimin erişimi var? Dana'yı salt okunur yap."* → `users list` → `users update dana@… --permission-set read-only` (sizinle onayladıktan sonra). +- *"Çalışan olayı kabul et ve bana ata."* → `incidents list --state firing` → `incidents ack ` / `incidents assign you@…`. + +Bunların arkasındaki tam komutlar, bayraklar ve JSON şekilleri için, [cli.md](/tr/agenteye/cli) ve [cli-recipes.md](/tr/agenteye/cli-recipes)'ye bakın. + +--- + +## Ayrıca bkz. + +- **[CLI](/tr/agenteye/cli)** — `agenteye` için tam komut ve bayrak referansı. +- **[Ajanlar için CLI tarifleri](/tr/agenteye/cli-recipes)** — kopyala-yapıştır `jq` desenleri ve çıkış kodu işleme. +- **[AI Asistanı](/tr/agenteye/assistant)** — kontrol paneli içi asistan (bu terminal becerisinden farklı). +- **[API Anahtarları](/tr/agenteye/api-keys)** — becerinizin yapabileceğini sınırlayan org başına izin modeli. \ No newline at end of file diff --git a/docs/tr/agenteye/cli.mdx b/docs/tr/agenteye/cli.mdx new file mode 100644 index 00000000..eee91820 --- /dev/null +++ b/docs/tr/agenteye/cli.mdx @@ -0,0 +1,292 @@ +--- +title: "CLI" +description: "AgentEye CLI belgelendirmesi." +--- + + +AgentEye CLI (`agenteye`), AgentEye dağıtımınız için bir terminal istemcisidir. Verilerinizi (oturumlar, etkinlik günlükleri, değerlendirmeler) sorgular ve kuruluşu yönetir (API anahtarları, kullanıcılar, ayarlar, uyarılar, olaylar, kaydedilmiş sorgular) — panonun yaptığı her şeyi, bir betik veya kodlama aracısından yapabilirsiniz. Her komut `--json` bayrağını destekler, bu nedenle bir komut satırındaki bir insan veya sonucu ayrıştıran bir kodlama aracısı (Claude Code, Cursor) için eşit derecede iyi çalışır. + +> Bu **`agenteye` CLI**'dır, **toplayıcı** daemon (`agenteye-collector`) tarafından farklı bir araçtır. CLI, **panonuzla** konuşur; toplayıcı sunucuya etkinlikleri gönderir. Toplayıcı için [Toplayıcı Kurulumu](/tr/agenteye/collector-installation) bölümüne bakın. + +--- + +## Kurulum + +CLI, genel PyPI'ye **`agenteye`** olarak yayınlanır. AgentEye Python SDK de `agenteye` dağıtım adını kullandığından, CLI'yi **izole** bir ortamda (`pipx` veya `uv tool`) kurun, böylece ikisi hiçbir zaman tek bir virtualenv'de çakışmaz: + +```bash +pipx install agenteye +# veya +uv tool install agenteye +``` + +Python SDK'sını aynı ortama kurmuyorsanız, düz `pip install agenteye` de çalışır. CLI, Python 3.10+ gerektirir ve GitHub jetonuna ihtiyaç duymaz; bu genel bir pakettir. + +Yüklü komut **`agenteye`**'dir: + +```bash +agenteye --version +agenteye --help +``` + +--- + +## Kimlik Doğrulama + +CLI, **pano** ile e-postayla gönderilen tek kullanımlık bir kod kullanarak kimliğini doğrular: + +```bash +agenteye login --email you@example.com +# Size 6 haneli bir kod e-postayla gönderilir; istemde yapıştırın. +``` + +Oturum belirteci `~/.agenteye/cli.json` içinde depolanır (yalnızca siz tarafından okunabilir, mod `0600`) ve varsayılan olarak 24 saat geçerlidir. Süresi dolduğunda, `agenteye login` komutunu yeniden çalıştırın. + +```bash +agenteye whoami # geçerli kullanıcı, etkin kuruluş ve izinleri gösterir +agenteye logout # oturumu iptal et ve depolanmış belirteci temizle +``` + +`whoami` eksik veya süresi dolmuş bir oturumda asla hata vermez — bunun yerine `logged_in: false` bildirir, bu nedenle bir betik veya aracı, kimlik doğrulama durumunu güvenle araştırabilir (temel URL ayarlanmamış veya pano erişilemez ise yine sıfır olmayan bir değerle çıkabilir). + +**Gereksinimler:** e-posta adresiniz panoya oturum açmak için izinlenmiş olmalıdır (AgentEye yöneticinize sorun) ve pano, temel URL'sinde erişilebilir olmalıdır (bkz. [Yapılandırma](#configuration)). Bir kod talep ettiyseniz ve hiçbiri gelmemişse, e-posta adresiniz muhtemelen henüz pano erişimi için etkinleştirilmemiş. + +--- + +## Kuruluşunuzu seçin (çok kiracılı) + +Hesabınız birden fazla kuruluşa aitse, etkin olanı **oturum açma sırasında** seçin — kaydedilir ve sonraki her komut için kullanılır: + +```bash +agenteye login --org acme # kimlik doğrula ve etkin kiracıyı bir adımda ayarla +agenteye orgs list # erişebileceğiniz kuruluşlar (etkin olan işaretli) +agenteye orgs switch globex # kaydedilmiş varsayılanı değiştir +agenteye --org globex sessions # tek bir komut için geçersiz kıl +``` + +Tam olarak bir kuruluşa aitse, otomatik olarak seçilir ve `--org` tamamen yoksayabilirsiniz. Birkaçına aitse ve birini seçmezseniz, CLI bunları listeler ve `--org ` ile yeniden çalıştırmanız istenir. Etkin kuruluş her istekte panoya gönderilir ve izinleriniz **kuruluş başına** çözülür — `agenteye whoami` etkin kuruluşu, içindeki izinlerinizi ve tüm üyeliklerinizi gösterir. + +--- + +## Yapılandırma + +| Ayar | Bayrak | Ortam değişkeni | Varsayılan | +|---|---|---|---| +| Pano temel URL'si | `--base-url` | `AGENTEYE_DASHBOARD_URL` | **gerekli** (varsayılan yok) | +| Etkin kuruluş/kiracı | `--org` | `AGENTEYE_ORG` | oturum açma sırasında seçilir; `~/.agenteye/cli.json` içinde kaydedilir | +| Oturum belirteci | `--token` | `AGENTEYE_CLI_TOKEN` | `~/.agenteye/cli.json` içinden | +| JSON çıkışı | `--json` | `AGENTEYE_CLI_JSON` | kapalı | +| TLS doğrulamasını atla | `--insecure` / `--secure` | `AGENTEYE_INSECURE` | kapalı (oturum açma sırasında kaydedilir) | +| İstek zaman aşımı (saniye) | `--timeout` | — | 30 | +| Kullanım telemetrisini devre dışı bırak | _(yok)_ | `AGENTEYE_ANALYTICS_DISABLED` (veya `DO_NOT_TRACK`) | kapalı (telemetri açık) | + +Çözüm sırası **bayrak → ortam değişkeni → yapılandırma dosyası**'dır. Varsayılan yoktur; CLI'yi panonuza işaret etmelisiniz, komut başına (`--base-url https://agenteye.example.com`) veya ortam aracılığıyla bir kez (ayrıca ilk `login` sonrasında kaydedilir): + +```bash +export AGENTEYE_DASHBOARD_URL=https://agenteye.example.com +``` + +Yapılandırma dizini `AGENTEYE_HOME` (SDK ve toplayıcı tarafından kullanılan aynı kural) olur; ayarlanmışsa, `cli.json` `$AGENTEYE_HOME/cli.json` içinde yer alır. + +### Kendi imzalı veya dahili TLS + +Panonuz, kendi imzalı veya dahili bir sertifikaya sahip HTTPS üzerinden sunuluyorsa (örneğin, ham bir yük dengeleyici adı), TLS doğrulaması bunu `CERTIFICATE_VERIFY_FAILED` hatasıyla reddeder. Sertifika doğrulamasını atlamak için `--insecure` geçirin: + +```bash +agenteye --base-url https://agenteye.internal --insecure login +``` + +`--insecure` **oturum açarken `cli.json` içinde kaydedilir**, bu nedenle sonraki komutlar doğrulamayı otomatik olarak atlarlar; bayrağı tekrarlamanız gerekmez. Tek seferlik doğrulanmış bir çağrı için `--secure` geçirin veya doğrulamayı sonraki oturum açmada geri açmak için. CLI, doğrulama devre dışı bırakılırken panoya bağlanan herhangi bir komuttan önce stderr'e bir uyarı yazdırır. Doğrulamayı atlamak, ortadaki adam saldırılarına karşı korumayı kaldırır; panonuza giden ağ yolundan (VPN, özel alt ağ vb.) yararlanmadan önce ona güvendiğinizden emin olun. + +--- + +## Telemetri ve Gizlilik + +CLI, **anonim kullanım analitiğini** Exosphere'in analitik hizmetine (PostHog) gönderir: hangi komutlar çalıştırıldığı (ör. `sessions`, `keys create`), başarılı olup olmadığı ve ne kadar sürdüğü. Bu kullanım sinyali, hangi özelliklerin önceliklendirildiğini bilgilendirir. + +- **Aracı, oturum veya etkinlik verileri hiçbir zaman altyapınızdan ayrılmaz.** Yalnızca CLI kullanımı raporlanır: komut ve alt komut adı (ör. `keys create`), kullandığınız bayrakların **adları** (hiçbir zaman değerleri), başarı/çıkış durumu ve süre — artı mutasyonlar için komut başına bir etkinlik (ör. `api_key_created`, `query_run`) yalnızca statik adlar/numaralandırmalar ve kaba sayımlar taşıyan. Pano URL'niz, oturum belirteci, e-posta, kuruluş slug'ı, kaynak kimlikleri, SQL, anahtar sırları ve sorgu filtreleri **hiçbir zaman** gönderilmez. Operatörler yalnızca opak bir dahili kimlikle tanımlanır, hiçbir zaman e-postayla değil. +- Telemetri **varsayılan olarak etkindir**. Kapatmak için CLI'nin ortamında `AGENTEYE_ANALYTICS_DISABLED=1` ayarlayın (CLI ayrıca `DO_NOT_TRACK=1` çapraz aracı kuralını onurlandırır). +- CLI doğrudan PostHog'a gönderir (`https://us.i.posthog.com`). **CLI'yi çalıştıran makine** bu ana giden erişime ihtiyaç duyar; engellenmişse, telemetri sessizce hiçbir şey yapmaz (gönderme zaman sınırlıdır, bu nedenle hiçbir zaman bir komutu geciktirmez veya kırmaz) ve CLI etkilenmez. + +--- + +## Genel seçenekler ve kurallar + +Bunu bir kez okuyun; her komut için geçerlidir. + +- **Genel seçenekler komuttan ÖNCEsine gider.** `agenteye --json sessions` doğru; `agenteye sessions --json` kullanım hatasıdır. Genel seçenekler `--json`, `--base-url`, `--org`, `--token`, `--insecure`/`--secure`, `--timeout`, `--quiet` ve `--no-color`. +- **`--json` stdout'a saf JSON yazdırır ve başka bir şey yazmaz.** İnsan durum satırları, uyarılar ve hatalar **stderr**'e gider, bu nedenle `--json` stdout yakalaması bir durum satırı gösterilse bile `jq` tarafından işlenebilir durumdadır. `--json` olmadan bir kutu, renkli görünüm elde edersiniz. +- **`--help` ile keşfedin.** Her komutun ve alt komutun `--help` (ve `-h` takma adı) vardır: `agenteye -h`, `agenteye sessions -h`, `agenteye keys create -h`. Üst düzey yardım ayrıca çıkış kodlarını ve genel seçenekleri listeler. Genel makine tarafından okunabilir bir yüzey dökümü yoktur; komut başına `--help` ve bu iki kayıt defteri için etki alanına özgü `agenteye query schema` ve `agenteye settings schema` kullanın. +- **Onaylar betikler ve aracılar için otomatik olarak atlanır.** Oluştur/güncelle/sil komutları etkileşimli bir terminalde "emin misiniz?" istemi gösterir, ancak **`--json` altında veya stdin bir TTY değilse bu istemi otomatik olarak atlar** — böylece betikler ve aracılar asla kilitlenmez. Açıkça atlamak için `--yes`/`-y` geçirin. İstem bir aracı için ateşlenmeyeceğinden, bir aracı tahribatkar eylemler hakkında insan ile önce onaylamalıdır. +- **Sayfalandırma:** sonuçlar en yenisinden en eskiye ve imleç tarafından sayfalandırılır. `--limit N` (takma ad `-n`) satırları sınırlar ve **varsayılan olarak 50**'dir; `--all` otomatik sayfalandırır (200 satır parçalarında) **`--limit` kadar** — bu nedenle çıplak `--all` yine 50'de durur. Tam bir tarama için yüksek açık bir başlık geçin: `--all --limit 1000`. `--page-size N` komut başına parçayı kontrol eder (en fazla 200); `--cursor ` önceki sayfanın `next_cursor` adresinden devam eder. +- **Zaman filtreleri:** `--since` göreli bir pencere alır — `15m`, `1h`, `6h`, `24h`, `7d`, `30d` veya `all` (panonun ön ayarları). `--from`/`--to` açık ISO-8601 UTC zaman damgalarını alır **`T` ve bir saat dilimi** (ör. `2026-06-01T00:00:00Z`) ile özel bir aralık için ve `--since` geçersiz kılar; boşluk ayrılmış veya saat dilimi olmayan bir değer kullanım hatasıdır. +- **`--fields a,b,c`** (`events`, `sessions`, `evals`, `errors` üzerinde) çıkışı bu anahtarlarla sınırlar, hem tablo hem de `--json` için. Bilinmeyen adlar geçerli listenin sonuyla reddedilir — alan adlarını keşfetmenin ucuz bir yolu. +- **`--file payload.json`** (veya stdin okumak için `--file -`) bir kaynağın karmaşık bir şekil olması durumunda tam bir JSON istek gövdesi sağlar — `alerts create/update`, `settings set` ve `users create/update` üzerinde. Kaydedilmiş sorgu SQL, `--sql @file.sql` kullanır. +- **Çok değerli filtreler** virgülle ayrılmıştır → bir küme olarak eşleştirilir (bir filtre içinde birlik, filtreler arasında VE): `--event-type tool_use,tool_result`. Tıklama seçenekleri değişken değildir, bu nedenle `--add a b` bozulur — `--add a,b` kullanın, bayrağı yineleyin (`--add a --add b`) veya alıntılayın (`--add "a b"`). + +--- + +## Komut Başvurusu + +CLI'de **18 üst düzey komut** vardır. Tüm okuma komutları `--json` ve yukarıdaki genel seçenekleri kabul eder; herhangi biri için kapsamlı bayrak listesi ve JSON şekli için `agenteye -h` (veya ` -h`) çalıştırın. + +### Kimlik — `login` · `logout` · `whoami` · `orgs` · `version` · `help` + +```bash +agenteye login --email you@example.com [--org acme] # e-postayla gönderilen tek kullanımlık kod; oturumu kaydeder +agenteye logout # bu makinedeki kaydedilmiş oturumu temizle +agenteye whoami # geçerli kullanıcı, etkin kuruluş, izinler +agenteye version # CLI sürümünü yazdır (--version ile aynı) +agenteye help # üst düzey yardım (--help ile aynı) +``` + +`orgs` etkin kiracıyı inceler ve değiştirir: + +```bash +agenteye orgs list # kuruluşlarınız + her birindeki rolünüz (etkin olan işaretli) +agenteye orgs switch acme # kaydedilmiş etkin kuruluşu değiştir (TTY'de listeden seçmek için slug'ı atla) +agenteye orgs current # etkin kuruluşun kimlik kartı +agenteye orgs perms # etkin kuruluşunuzdaki izinleriniz, kaynağa göre gruplandırılmış +``` + +### Gözlemle (salt okunur) — `events` · `sessions` · `evals` · `errors` · `list` + +Bunların hiçbiri onay gerektirmez. Paylaşılan filtreler: `--session-id`, `--agent-id`, `--env` (**değil** `--environment`) ve zaman aralığı (`--since` / `--from` / `--to`). + +```bash +# events (takma ad: ham adım başı izi) — en yenisinden en eskiye +agenteye --json events --session-id run-001 --event-type tool_use,tool_result --all --limit 1000 +agenteye --json events --since 1h --search timeout --all | jq '.events[].payload' + +# sessions — aracı çalışması başına bir satır (saat/ortam/aracı/oturum/durum; puan filtrelemesi yok) +agenteye --json sessions --since 24h --status error +agenteye --json sessions --agent-id checkout-bot --env prod --all --limit 1000 + +# evals — değerlendirme sonuçları + puanlar; --score metriğe göre filtrelenirse, --aggregate yukarı döner +agenteye --json evals --score helpfulness:0.5..0.8 --score tool_efficiency:..0.3 +agenteye --json evals --aggregate --since 7d --env prod # durum karışımı + anahtar başına puan istatistikleri + +# errors — hata içeren etkinlikler; --aggregate sayımlar/oturumlar/aracılar/son görülen için +agenteye --json errors --since 24h --aggregate +agenteye --json errors --since 24h --error-type timeout --all --limit 1000 + +# list — filtre yapmadan önce geçerli filtre değerlerini keşfedin +agenteye list envs # ayrıca: agents event_types score_filters models hooks triggers tools error_types +``` + +`--score KEY:MIN..MAX` (**`evals`** üzerinde, `sessions` değil) tekrarlanabilir ve VE'ye bağlı; her iki sınırda isteğe bağlıdır (`..0.5` anlamı ≤ 0.5, `0.9..` anlamı ≥ 0.9). İstek başına 20 puan filtresine kadar. `evals --scores-full` özet yerine tam puan nesnesini döndürür. **Bir oturumu sondan sona okumak** için etkinlik izini değerlendirmesiyle birleştirin: + +```bash +agenteye --json events --session-id run-001 --all --limit 1000 | jq '.events[] | {ts, event_type}' +agenteye --json evals --session-id run-001 # puanlar + durum +``` + +### Yönet (izin kontrolüne tabi) — `keys` · `users` · `settings` · `alerts` · `incidents` + +**`keys`** — API anahtarları. Gizli dizi yerel olarak üretilir, sunucuya gönderilir (yalnızca karma depolayan) ve oluştur/yeniden üret sırasında **bir kez gösterilir** — şimdi yakala. `--json` ile yalnızca `key` alanında görünür. **Adla** referans alınır. + +```bash +agenteye keys list # etkin anahtarlar önce, sonra iptal edilen +agenteye keys show ci-bot +agenteye keys create ci-bot --add events:read.add # ihtiyaç duyduğunuz kapsamla kısıtla; sırrı yazdır BİR KEZ +agenteye keys create ops --permission-set standard --remove queries:run # ön ayar tohumlayın, sonra kırpın +agenteye keys update ci-bot --add evaluations:read --yes +agenteye keys regenerate ci-bot --yes # sırrı döndür (eski bir çalışmayı durdur) +agenteye keys disable ci-bot --yes # iptal et +``` + +İzinler `(permission-set ∪ --add) − --remove` olarak çalışır. Belirteçler `slug:action` (ör. `events:read`) veya birkaçını bir kaynakta genişletmek için `slug:action.action` (`events:read.add` → `events:read`, `events:add`). Ön ayarlar: `read-only`, `standard`, `admin`. İnsan yalnızca izinleri (`keys:update`) bir anahtara verilemez. + +**`users`** — kuruluş üyeleri, **e-postayla** referans alınır (bir UUID kimliği de kabul edilir). + +```bash +agenteye users list [--active-only] +agenteye users show dev@corp.com +agenteye users create dev@corp.com --permission-set standard +agenteye users update dev@corp.com --add alerts:write --remove queries:delete # tahminler + onaylar +agenteye users disable dev@corp.com --yes # korumalı/kendi kendine koruma vardır +agenteye users enable dev@corp.com +``` + +**`settings`** — sabit kayıt defteri (var olan anahtarları okuyup değiştirirsiniz; yenisini oluşturamazsınız). + +```bash +agenteye settings list # anahtar · değer · tür · güncellendi (gizlilikler maskelenmiş) +agenteye settings schema # her anahtar neyi kabul ediyor (tür · aralık · açıklama) +agenteye settings set session_ttl_secs --value 86400 --yes +``` + +**`alerts`** — uyarı tanımları, **adla** referans alınır. `create` konumsal bir AD artı bayraklar veya `--file` aracılığıyla tam bir JSON gövdesi alır. + +```bash +agenteye alerts list +agenteye alerts show high-errors +agenteye alerts create high-errors --file alert.json # AD gereklidir (konumsal) +agenteye alerts update high-errors --severity critical --yes +agenteye alerts test high-errors --yes # test bildirimi ateşle +agenteye alerts delete high-errors --yes +``` + +**`incidents`** — uyarı olayları, kimlikle referans alınır (kısa kimlikler kabul edilir). `show` tam etkinlik günlüğünü yazdırır — harekete geçmeden önce okuyun. + +```bash +agenteye incidents list --state firing # ayrıca: acknowledged, resolved +agenteye incidents count +agenteye incidents show +agenteye incidents ack +agenteye incidents assign you@corp.com # atanan bir operatör olmalıdır +agenteye incidents resolve --yes +agenteye incidents open --alert-id --severity critical # bir uyarıya karşı manuel olarak açın +agenteye incidents comment-add "root cause: upstream 5xx" +agenteye incidents comment-list ; agenteye incidents comment-delete +agenteye incidents subscribe ; agenteye incidents unsubscribe ; agenteye incidents subscribers +``` + +### Analitik ve asistan — `query` · `agent` + +**`query`** — kaydedilmiş ClickHouse SQL artı ad hoc çalıştırıcı. Kaydedilmiş sorgular **adla** referans alınır; SQL sunucu tarafı tarafından doğrulanır (SELECT/WITH yalnızca, ifade zaman aşımı, satır sınırı). + +```bash +agenteye query schema [TABLE] # analitik görünümlerin sütun düzeni +agenteye query run --sql "select count(*) from analytics.events" +agenteye query run errs --arg prod --limit 100 # kaydedilmiş sorgu + konumsal $1 çalıştır +agenteye query list ; agenteye query show errs +agenteye query create errs --sql @errs.sql --description "errored events (24h)" +agenteye query update errs --sql @errs.sql --yes ; agenteye query delete errs --yes +``` + +**`agent`** — yerleşik pano asistanı (panonun içinde sohbet edebileceğiniz aynı salt okunur analist). Sohbetler kısa bir sohbet kimliğiyle referans alınır (ön ek çözüldü). + +```bash +agenteye agent health # asistan yapılandırıldı mı/ulaşılabilir mi +agenteye agent models # --model'e geçirebileceğiniz modeller (varsayılan işaretli) +agenteye agent ask "which agents errored most in the last day?" # sohbeti başlat; kısa kimliğini yazdır +agenteye agent ask --chat "and which tools did they call?" # o sohbeti devam ettir +agenteye agent chats ; agenteye agent show +agenteye agent rename --title "error triage" ; agenteye agent delete +``` + +--- + +## Çıkış Kodları + +| Kod | Anlam | +|---|---| +| 0 | Başarı | +| 1 | Beklenmeyen hata (ör. pano bir 5xx döndürdü) | +| 2 | Kullanım hatası (geçersiz argümanlar, bilinmeyen komut/bayrak, ad çakışması) | +| 3 | Panoya ulaşılamıyor | +| 4 | Oturum açılı değil veya oturum süresi doldu; `agenteye login` çalıştırın | +| 5 | Kimliği doğrulanmış, ancak hesabınızda gerekli izin yok (ileti bunu adlandırır) | +| 6 | İstenen kaynak bulunamadı (ör. bilinmeyen oturum veya olay kimliği) | + +Bunlar CLI'yi komut dosyası yapmak için güvenli hale getirir: bir kodlama aracısı yeniden kimlik doğrulamanız istenmek için bir `4`'e veya eksik izni yüzey yapmak için bir `5`'e dallanabilir. CLI aracı komut dosyaları için çıkış kodu işleme desenleri ve JSON çıkış şekilleri için [Aracılar için CLI Tarifleri](/tr/agenteye/cli-recipes) bölümüne bakın. + +--- + +## Ayrıca Bkz. + +- **[Aracılar için CLI Tarifleri](/tr/agenteye/cli-recipes)** — kopya-yapıştır sorgu desenleri, `jq` tek satırlıkları, `--fields` projeksiyonları, çıkış kodu işlemesi ve JSON çıkış şekilleri, kodlama aracılarını CLI sürecine koyması için yazılmıştır. +- **[AgentEye CLI Becerisi](/tr/agenteye/cli-skill)** — bu CLI'yi kurulabilir bir Claude Code / Codex *becerisi* olarak paketleyin, böylece bir kodlama aracısı düz İngilizce isteklerden AgentEye'ı yönlendirir. +- **[API Anahtarları](/tr/agenteye/api-keys)** — `keys create --add …` arkasındaki izin modeli. +- **[AI Asistanı](/tr/agenteye/assistant)** — `agent ask` adresinin konuştuğu asistanı etkinleştirme. \ No newline at end of file diff --git a/docs/tr/agenteye/collector-installation.mdx b/docs/tr/agenteye/collector-installation.mdx new file mode 100644 index 00000000..79812de4 --- /dev/null +++ b/docs/tr/agenteye/collector-installation.mdx @@ -0,0 +1,400 @@ +--- +title: "Collector Installation" +description: "AgentEye Collector Installation documentation." +--- + + +`agenteye-collector` daemon'u, ajanlarınızın telemetrisinin AgentEye'a ulaşmasını sağlarken uygulamanızı asla engellemez. Kodunuz olayları yerel bir dizine yazar ve devam eder; collector oradan sahiplik üstlenir, her dosyayı milisaniyeler içinde yükler ve yeniden başlatmaları, ağ kesintilerini ve geçici sunucu hatalarını atlatır. Başarısız yüklemeler üstel geri çekilme ile yeniden denenir ve periyodik bir kurtarma taraması, bir çökme veya dağıtım tarafından geride bırakılan her şeyi yeniden sıraya alır. Sonuç dayanıklı, fire-and-forget teslimatıdır: ajanlarınız tam hızla çalışmaya devam ederken collector, transit sırasında hiçbir olayın kaybolmamasını sağlar. + +Mekanik olarak, collector `$AGENTEYE_HOME/events/` (varsayılan: `~/.agenteye/events/`) dizinini Python SDK tarafından yazılan `.jsonl` dosyaları için izleyen ve bunları AgentEye sunucusuna yükleyen hafif bir daemon'dur. + +> **Yeniden Adlandırıldı:** collector komutu artık **`agenteye-collector`** adıyla anılır (eski adı `agenteye` idi). Kısa `agenteye` adı şimdi AgentEye CLI'ye aittir. Mevcut bir yüklemeden yükseltme yapıyorsanız, [enterprise-docs/collector-migration.md](/tr/agenteye/collector-migration) adresine bakın. + +--- + +## Ön Koşullar + +- `AGENTEYE_TOKEN`: kendiniz oluşturduğunuz bir GitHub PAT (bkz. [enterprise-docs/github-token.md](/tr/agenteye/github-token)) +- Sunucu URL'si ve bir collector API anahtarı (bkz. [enterprise-docs/api-keys.md](/tr/agenteye/api-keys)) + +--- + +## Seçenek A: İkili Dosya (önerilir) + +Önceden derlenmiş statik ikili dosyalar Linux, macOS ve Windows (x86_64 ve arm64) için mevcuttur. İkili dosyayı platformunuz için doğrudan `agenteye-enterprise/releases` repo'sundan en son `collector/v` release etiketi altında indirin. + +Kullanılabilir yapı adları: + +| Platform | Yapı | +|---|---| +| Linux x86_64 | `agenteye-collector-linux-x86_64` | +| Linux arm64 | `agenteye-collector-linux-arm64` | +| macOS x86_64 | `agenteye-collector-darwin-x86_64` | +| macOS arm64 | `agenteye-collector-darwin-arm64` | +| Windows x86_64 | `agenteye-collector-windows-x86_64.exe` | +| Windows arm64 | `agenteye-collector-windows-arm64.exe` | + +**`gh` CLI ile indirin** (sürümü değiştirin ve platformunuzun yapı adını seçin): + +```bash +VERSION=0.0.1-beta.13 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "collector/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-collector-linux-x86_64' + +chmod +x agenteye-collector-linux-x86_64 +sudo mv agenteye-collector-linux-x86_64 /usr/local/bin/agenteye-collector +``` + +**Veya `curl` ile:** + +```bash +VERSION=0.0.1-beta.13 +ARTIFACT=agenteye-collector-linux-x86_64 +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + -L "https://github.com/agenteye-enterprise/releases/releases/download/collector%2Fv${VERSION}/${ARTIFACT}" \ + -o agenteye-collector +chmod +x agenteye-collector +sudo mv agenteye-collector /usr/local/bin/agenteye-collector +``` + +--- + +## Seçenek B: Docker + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +docker pull ghcr.io/agenteye-enterprise/collector:beta-latest +``` + +> Mevcut beta derlemeleri kayan `:beta-latest` etiketini yayınlar; `:latest` yalnızca kararlı sürümlere atanır. Tekrarlanabilir dağıtımlar için `:v0.0.1-beta.13` gibi sabitlenmiş bir sürüm etiketi tercih edin. + +**Çalıştırın:** + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-collector \ + -e AGENTEYE_URL=https://ingest.example.com/events \ + -e AGENTEYE_KEY="$AGENTEYE_KEY" \ + -e AGENTEYE_HOME=/data \ + -v "$HOME/.agenteye:/data" \ + ghcr.io/agenteye-enterprise/collector:beta-latest \ + start +``` + +Resmi görüntü root olmayan bir kullanıcı olarak çalışır, bu nedenle `AGENTEYE_HOME` açıkça ayarlayın ve host spool'unu ona bağlayın. Hacim bağlaması, Python SDK'sının host üzerinde yazma yaptığı `~/.agenteye/` dizinini paylaşır. Zaten host üzerinde başka bir yerde `AGENTEYE_HOME` ayarladıysanız, `$HOME/.agenteye` yerine o dizini bağlayın. + +--- + +## Yapılandırma + +Tüm seçenekler üç şekilde ayarlanabilir (en yüksek öncelik ilk sırada): + +1. CLI bayrağı: `agenteye-collector start --url https://...` +2. Çevre değişkeni: `AGENTEYE_URL=https://...` +3. Yapılandırma dosyası: `~/.agenteye/config.json` + +### Gerekli seçenekler + +| Seçenek | CLI bayrağı | Çevre değişkeni | config.json anahtarı | +|---|---|---|---| +| Backend URL | `--url ` | `AGENTEYE_URL` | `"url"` | +| API anahtarı | `--key ` | `AGENTEYE_KEY` | `"key"` | + +### İsteğe bağlı seçenekler (varsayılanlarla) + +| Seçenek | CLI bayrağı | Çevre değişkeni | config.json anahtarı | Varsayılan | +|---|---|---|---|---| +| Maksimum eşzamanlı yüklemeler | `--max-concurrent-uploads ` | `AGENTEYE_MAX_CONCURRENT_UPLOADS` | `"max_concurrent_uploads"` | `64` | +| Sweeper aralığı (s) | `--sweep-interval ` | `AGENTEYE_SWEEP_INTERVAL` | `"sweep_interval_secs"` | `60` | +| Sweeper min dosya yaşı (s) | `--sweep-min-age ` | `AGENTEYE_SWEEP_MIN_AGE` | `"sweep_min_age_secs"` | `120` | +| Sweep başına maksimum dosya | `--sweep-max-files ` | `AGENTEYE_SWEEP_MAX_FILES` | `"sweep_max_files"` | `64` | +| Maksimum yükleme denemeleri | `--max-retries ` | `AGENTEYE_MAX_RETRIES` | `"max_retries"` | `5` | +| Yeniden deneme temel gecikmesi (ms) | `--retry-base-delay ` | `AGENTEYE_RETRY_BASE_DELAY` | `"retry_base_delay_ms"` | `1000` | + +### mTLS seçenekleri (isteğe bağlı) + +Karşılıklı TLS (mTLS) gerektiren dağıtımlar için collector, TLS el sıkışması sırasında bir istemci sertifikası sunabilir. Bu seçenekler ayarlanmadığında, collector standart HTTPS kullanır. + +| Seçenek | CLI bayrağı | Çevre değişkeni | config.json anahtarı | +|---|---|---|---| +| İstemci sertifikası (PEM) | `--tls-cert ` | `AGENTEYE_TLS_CERT` | `"tls_cert"` | +| İstemci özel anahtarı (PEM) | `--tls-key ` | `AGENTEYE_TLS_KEY` | `"tls_key"` | +| Özel CA sertifikası (PEM) | `--tls-ca ` | `AGENTEYE_TLS_CA` | `"tls_ca"` | + +`--tls-cert` ve `--tls-key` birlikte ayarlanmalıdır. Dosyalar PEM kodlu olmalıdır. + +`--tls-ca` bağımsızdır ve yalnızca AgentEye sunucusu halka açık olarak güvenilen bir CA tarafından verilmemiş bir TLS sertifikası sunduğunda gereklidir (örneğin, gerçek bir DNS etki alanınız olmadığında bir kümede bulunan `cert-manager` veren tarafından kendi imzası). Collector, sağlanan CA'yı ek bir güven noktası olarak ekler; standart genel kökler güvenilir kalır, bu nedenle mevcut dağıtımlar etkilenmez. Dosya tek bir PEM sertifikası veya tam bir zincir (birden çok birleştirilmiş PEM bloğu) içerebilir. + +**Collector'u uygulamanız pod'unda bir sidecar olarak çalıştırıyor musunuz?** End-to-end EKS deseni için [enterprise-docs/single-pod-deployment.md](/tr/agenteye/single-pod-deployment) adresine bakın: mTLS paketi AWS Secrets Manager + Secrets Store CSI Driver + IRSA aracılığıyla teslim edildi, otomatik döndürmeyle. + +Kubernetes'te Secret el değişimi deseniyle çalışırken, sertifika Secret'ı bir birim olarak bağlayın ve bu yolları bağlanmış dosyalara işaret ettirin: + +```yaml +# Örnek: collector Deployment snippet'i +volumes: + - name: mtls-certs + secret: + secretName: agenteye-collector-mtls +containers: + - name: collector + env: + - name: AGENTEYE_TLS_CERT + value: /etc/agenteye/tls/tls.crt + - name: AGENTEYE_TLS_KEY + value: /etc/agenteye/tls/tls.key + # Yalnızca sunucu sertifikası halka açık olarak güvenilmediğinde (örneğin, kümede + # kendi imzası olan CA). Aynı Secret genellikle tls.crt/tls.key ile birlikte ca.crt'yi taşır. + - name: AGENTEYE_TLS_CA + value: /etc/agenteye/tls/ca.crt + volumeMounts: + - name: mtls-certs + mountPath: /etc/agenteye/tls + readOnly: true +``` + +### Örnek `~/.agenteye/config.json` + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "max_concurrent_uploads": 16, + "sweep_interval_secs": 30 +} +``` + +mTLS ile: + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "tls_cert": "/etc/agenteye/tls/tls.crt", + "tls_key": "/etc/agenteye/tls/tls.key" +} +``` + +mTLS artı özel CA (kendi imzası olan AgentEye sunucusu) ile: + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "tls_cert": "/etc/agenteye/tls/tls.crt", + "tls_key": "/etc/agenteye/tls/tls.key", + "tls_ca": "/etc/agenteye/tls/ca.crt" +} +``` + +`AGENTEYE_HOME` ayarlanırsa, `~/.agenteye` yerine o dizin kullanılır. + +--- + +## İlk Kurulum + +Yükledikten sonra collector'u sunucu URL'si ve API anahtarı ile yapılandırın: + +```bash +mkdir -p ~/.agenteye +cat > ~/.agenteye/config.json <<'EOF' +{ + "url": "https://ingest.example.com/events", + "key": "YOUR_COLLECTOR_KEY" +} +EOF +``` + +> Güvenilmeyen bir ağı geçen herhangi bir dağıtım için olaylar düz metin olarak gönderilmemesi için `https` kullanın. `http://your-server-host:8080/events` düz metin formu yalnızca aynı host üzerinde bir sunucu olmak üzere tamamen yerel testler için uygundur. + +**Bağlantıyı test edin** (tek atış flush, bekleyen olayları boşalttıktan sonra çıkar): + +```bash +agenteye-collector flush +``` + +`flush`, ilerlemeyi stdout'a raporlar. Spool boş olduğunda `No pending files.` yazdırır ve `0` ile çıkar. Aksi takdirde dosya başına bir satır yazdırır (`[UPLOADED] ` veya `[FAILED] ()`), ardından bir `Done: / uploaded, failed.` özeti. Bu, URL'niz, anahtarınız ve TLS ayarlarınızın daemon'u başlatmadan önce doğru olduğunu kontrol etmek için uygun bir tek atış kontrol sağlar. + +--- + +## Daemon Olarak Çalıştırma + +### Doğrudan + +```bash +agenteye-collector start +``` + +### Konteyner / Docker + +Collector ve uygulamanız bir konteyner paylaştığında, onları bir süreç denetçisi altında çalıştırın. En basit seçenek `supervisord`; her büyük distro'da yer alır, kilitlenmemiş süreçleri yeniden başlatır, sinyalleri iletir ve düzgün kapatmayı bekler. + +**`Dockerfile`:** + +```Dockerfile +FROM python:3.11-slim + +RUN apt-get update && apt-get install -y --no-install-recommends supervisor \ + && rm -rf /var/lib/apt/lists/* + +# agenteye-collector ikili dosyasını resmi görüntüden çekin. +# Belirli bir etiketi sabitleyin (:beta-latest mevcut betalar için veya bir :v etiketi); +# :latest yalnızca kararlı sürümler için yayınlanır. +COPY --from=ghcr.io/agenteye-enterprise/collector:beta-latest \ + /usr/local/bin/agenteye-collector /usr/local/bin/agenteye-collector + +COPY supervisord.conf /etc/supervisor/conf.d/agenteye.conf +COPY my_agent.py /app/my_agent.py + +CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"] +``` + +**`supervisord.conf`:** + +```ini +[supervisord] +nodaemon=true +user=root + +[program:agenteye-collector] +command=/usr/local/bin/agenteye-collector start +autorestart=true +stopwaitsecs=30 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:app] +command=python /app/my_agent.py +autorestart=unexpected +stopwaitsecs=30 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +``` + +Bu ayarların nedenleri: + +- agenteye-collector üzerinde `autorestart=true`: herhangi bir çıkış üzerinde yeniden başlat (çökme, panik, OOM). +- Uygulama üzerinde `autorestart=unexpected`: yalnızca sıfır olmayan çıkış üzerinde yeniden başlat, böylece 0 ile çıkan tek atış bir ajan döngüye girmez. +- `stopwaitsecs=30`: collector'a SIGTERM üzerinde bekleyen yüklemeleri boşaltmak için yer verir, supervisord SIGKILL'e geçmeden. +- `stdout_logfile=/dev/stdout`, `*_maxbytes=0`: her iki programın çıkışını konteyner stdout'una akış edin; konteyner içinde günlük dosyası yoktur. + +`docker run -e` üzerinde `AGENTEYE_URL` / `AGENTEYE_KEY` (ve herhangi bir TLS çevre değişkeni) geçirin; supervisord ortamı devralır. + +> **Ayrı konteynerler?** Collector'u ayrı kendi konteynerinde çalıştırırsanız (Docker Compose hizmeti, Kubernetes sidecar vb.), supervisord kullanmayın; konteyner çalışma zamanının yeniden başlatma politikası bu işi zaten yapar. EKS sidecar deseni için [enterprise-docs/single-pod-deployment.md](/tr/agenteye/single-pod-deployment) adresine bakın. + +**Kubernetes liveness probe** (collector tek başına veya supervisord altında çalışmasından bağımsız olarak geçerlidir): + +```yaml +livenessProbe: + exec: + command: ["agenteye-collector", "health"] + initialDelaySeconds: 10 + periodSeconds: 30 +``` + +Çalışan daemon `$AGENTEYE_HOME/health.json` dosyasına her 30 saniyede bir kalp atışı yazar. `agenteye-collector health` bu dosyayı okur ve kalp atışı taze ve yükleme görevleri normal çalışıyorken `0` (sağlıklı) ile çıkar; kalp atışı 90 saniyeden daha eski olduğunda (örneğin daemon durduruldu) veya watcher ve sweeper beklenmeyen çıkıştan sonra yeniden başlarken `1` (sağlıksız) ile çıkar. Kalp atışı yalnızca `start` tarafından yazılır, bu nedenle probu tek atış `flush` komutu yerine uzun süreli daemon'a karşı çalıştırın. + +### systemd (Linux, üretim için önerilir) + +```ini +# /etc/systemd/system/agenteye-collector.service +[Unit] +Description=AgentEye Collector +After=network.target + +[Service] +ExecStart=/usr/local/bin/agenteye-collector start +Restart=on-failure +RestartSec=5 +EnvironmentFile=/etc/agenteye/env + +[Install] +WantedBy=multi-user.target +``` + +`/etc/agenteye/env` oluşturun: + +``` +AGENTEYE_URL=https://ingest.example.com/events +AGENTEYE_KEY=YOUR_COLLECTOR_KEY +``` + +```bash +sudo systemctl daemon-reload +sudo systemctl enable --now agenteye-collector +sudo systemctl status agenteye-collector +``` + +### launchd (macOS) + +```xml + + + + + + Label + ai.befailproof.agenteye-collector + ProgramArguments + + /usr/local/bin/agenteye-collector + start + + EnvironmentVariables + + AGENTEYE_URL + https://ingest.example.com/events + AGENTEYE_KEY + YOUR_COLLECTOR_KEY + + RunAtLoad + + KeepAlive + + + +``` + +```bash +launchctl load ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +``` + +--- + +## Collector'u Yükseltme + +Collector kendini güncellemez. Yükseltmek için: + +- **İkili dosya:** en son `collector/v` release'den yeni `agenteye-collector--` yapısını indirin (bkz. [Seçenek A](#seçenek-a-ikili-dosya-önerilir)), `/usr/local/bin/agenteye-collector` değiştirin, ardından servisi yeniden başlatın (`sudo systemctl restart agenteye-collector`, yeniden `launchctl load` yapın veya denetçinizi yeniden başlatın). +- **Docker:** `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (veya sabitlenmiş bir `:v` etiketi; `:latest` yalnızca kararlı sürümler için mevcuttur) ve konteyner'i yeniden oluşturun. + +`AGENTEYE_TOKEN` özel releases repo'sundan yeni ikili dosyaları/görüntüleri indirmek için gereklidir, ancak çalışan daemon tarafından **gerekli değildir**. + +--- + +## Alt Komutlar + +| Komut | Açıklama | +|---|---| +| `agenteye-collector start` | Uzun süreli daemon'u başlat. Başlangıçta önceki çalıştırmadan geride kalan tüm olayları temizler, ardından yeni dosyaları izler ve yükler. Watcher ve sweeper beklenmeyen çıkışta otomatik olarak yeniden başlar ve kalp atışı her 30 saniyede `health.json` dosyasına yazılır. | +| `agenteye-collector flush` | Tek atış: tüm bekleyen dosyaları yükle ve çık. Spool boş olduğunda `No pending files.` yazdırır, aksi takdirde dosya başına `[UPLOADED]`/`[FAILED]` günlüğü ve `Done: / uploaded, failed.` özeti. | +| `agenteye-collector health` | Daemon'un `health.json` kalp atışını oku. Taze ve sağlıklı olduğunda `0` ile çık; kalp atışı eski olduğunda (90s'den eski) veya görevler yeniden başlarken `1` ile çık. | + +--- + +## Dizin Düzeni + +``` +~/.agenteye/ +├── config.json <- isteğe bağlı yapılandırma dosyası +├── events/ <- SDK tarafından yazılan .jsonl dosyaları, collector tarafından alınır +└── failed/ <- tüm yükleme denemelerinde başarısız olan dosyalar +``` + +`failed/` içindeki dosyalar otomatik olarak yeniden denenmez. Bunları el ile yeniden sıraya almak için bunları `events/` dizinine geri taşıyın ve `agenteye-collector flush` çalıştırın. \ No newline at end of file diff --git a/docs/tr/agenteye/collector-migration.mdx b/docs/tr/agenteye/collector-migration.mdx new file mode 100644 index 00000000..910d9008 --- /dev/null +++ b/docs/tr/agenteye/collector-migration.mdx @@ -0,0 +1,169 @@ +--- +title: "`agenteye-collector`'a Geçiş" +description: "AgentEye `agenteye-collector`'a Geçiş belgelendirmesi." +--- + + +Geçiş yıkıcı değildir: hiçbir kapalı kalma süresi ve veri kaybı olmaz ve kısa `agenteye` adını [AgentEye CLI](/tr/agenteye/cli) için serbest bırakır, böylece collector daemon ve CLI aynı makinede birlikte yaşayabilir. + +Collector ikili dosyası **`agenteye`'den `agenteye-collector`'a yeniden adlandırıldı**. Kısa `agenteye` adı artık AgentEye CLI'ye aittir; bu, terminalinizden oturumları, olayları ve değerlendirmeleri sorgulamak için ayrı bir araçtır. + +Bu kılavuz, mevcut bir collector kurulumunu geçirmede size yol gösterir. + +--- + +## Değişen Neler + +| | Öncesi | Sonrası | +|---|---|---| +| Komut / ikili dosya | `agenteye` | `agenteye-collector` | +| Varsayılan kurulum yolu | `/usr/local/bin/agenteye` | `/usr/local/bin/agenteye-collector` | +| Alt komutlar | `start`, `flush`, `health`, `update` | `start`, `flush`, `health` | +| Kendi kendini güncelleme (`agenteye update`) | yerleşik | **kaldırıldı**: yeni ikili dosyayı indirin veya yeni görüntüyü çekin | +| Kurulum komut dosyası (`install.sh`) | sağlandı | **kaldırıldı**: ikili dosyayı doğrudan indirin (bkz. [Collector Installation](/tr/agenteye/collector-installation)) | +| `AGENTEYE_TOKEN` | ikili dosyaları indirmek **ve** arka plan güncelleme denetimleri için gerekli | yalnızca ikili dosyaları/görüntüleri **indirmek** için gerekli | + +Yapılandırma değişmedi: aynı `~/.agenteye/config.json`, aynı `AGENTEYE_URL` / `AGENTEYE_KEY` / `AGENTEYE_HOME` / TLS ortam değişkenleri ve aynı `~/.agenteye/events/` spool. **Hiçbir yapılandırma düzenlemesi gerekmez.** + +> Yeniden adlandırılan ikili dosyayı eski `agenteye` adı altında çalıştırırsanız, yine de çalışır ancak stderr'ye bir satırlık bir kullanımdan kaldırma uyarısı yazdırır ve `agenteye-collector`'a geçmenizi hatırlatır. + +--- + +## Başlamadan Önce + +- **Mevcut `agenteye` kurulumunuz çalışmaya devam eder**; yükseltme anında hiçbir şey bozulmaz. Kasıtlı olarak geçiş yapın, sonra eski ikili dosyayı en son silin. +- Kapalı kalma süresini önlemek için şu sırayı izleyin: + 1. Yeni `agenteye-collector` ikili dosyasını kurun (veya yeni görüntüyü çekin). + 2. Hizmet tanımınızı / sağlık sondanızı / komut dosyalarınızı `agenteye-collector`'ı çağıracak şekilde güncelleyin. + 3. Hizmeti yeniden yükleyin ve yeniden başlatın; sağlıklı olduğunu doğrulayın. + 4. **Yalnızca o zaman** eski `/usr/local/bin/agenteye` ikili dosyasını silin. + +--- + +## 1. Yeni İkili Dosyayı Kurun + +Platformunuz için yapıyı (`agenteye-collector-linux-x86_64`, `agenteye-collector-darwin-arm64`, vb.; tam liste için [Collector Installation → Option A](/tr/agenteye/collector-installation#option-a-binary-recommended) bölümüne bakın) en son `collector/v` sürümünden indirin ve `/usr/local/bin/agenteye-collector` konumuna yerleştirin. Docker kullanıcıları: `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (veya sabitlenmiş bir `:v` etiketi tercih edilir; `:latest` yalnızca kararlı sürümler için mevcuttur). + +Doğrulayın: + +```bash +agenteye-collector --version +``` + +--- + +## 2. Dağıtımınızı Güncelleyin + +### systemd (Linux) + +`/etc/systemd/system/agenteye-collector.service` dosyasını düzenleyin, böylece `ExecStart` yeni ikili dosyaya işaret eder: + +```ini +[Service] +ExecStart=/usr/local/bin/agenteye-collector start +``` + +Ardından yeniden yükleyin ve yeniden başlatın: + +```bash +sudo systemctl daemon-reload +sudo systemctl restart agenteye-collector +sudo systemctl status agenteye-collector +``` + +### launchd (macOS) + +> **Marka yeniden adlandırması:** Mevcut plist dosyanız daha eski yolda +> `~/Library/LaunchAgents/host.exosphere.agenteye-collector.plist` ise, +> dosyayı `ai.befailproof.agenteye-collector.plist` olarak yeniden adlandırın +> ve ayrıca dosyanın içindeki `Label` değerini yeni tanımlayıcıya +> değiştirin, sonra yeniden yükleyin. + +`~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist` dosyasında, ilk `ProgramArguments` girdisini `/usr/local/bin/agenteye` yerine `/usr/local/bin/agenteye-collector` olarak değiştirin, sonra yeniden yükleyin: + +```bash +launchctl unload ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +launchctl load ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +``` + +### supervisord + +`supervisord` program bloğunuzda, `command`'i yeni ikili dosyaya ayarlayın: + +```ini +[program:agenteye-collector] +command=/usr/local/bin/agenteye-collector start +``` + +Ardından `supervisorctl reread && supervisorctl update` komutunu çalıştırın. + +### Docker / Kubernetes + +Yeni görüntüyü çekin (`ghcr.io/agenteye-enterprise/collector:beta-latest` veya sabitlenmiş bir `:v` etiketi tercih edilir; `:latest` yalnızca kararlı sürümler için mevcuttur). Görüntü entrypoint zaten `agenteye-collector` olduğundan, `start` alt komutuyla aynı `docker run` komutu değişiklik olmadan çalışmaya devam eder. + +**Önemli: sağlık sondalarını güncelleyin.** Kubernetes canlılık/hazırlık sondası veya ikili dosyayı ada göre çalıştıran herhangi bir `docker exec` kullanıyorsanız, komutu `agenteye-collector` olarak değiştirin: + +```yaml +livenessProbe: + exec: + command: ["agenteye-collector", "health"] +``` + +Yeni görüntü `agenteye` alias'ını göndermiyor, bu nedenle hala `agenteye` çağıran bir sonda başarısız olur. Sondayı yeni görüntüyle aynı dağıtımda güncelleyin. + +### Cron / manuel komut dosyaları + +Herhangi bir `agenteye start|flush|health` çağırmasını eşleşen `agenteye-collector start|flush|health` komutuyla değiştirin. **Herhangi bir `agenteye update` cron işini silin**; bu alt komut artık mevcut değildir (bkz. [Bundan sonraki yükseltmeler](#upgrades-from-now-on)). + +--- + +## 3. Eski İkili Dosyayı Silin (En Son) + +Hizmet `agenteye-collector` üzerinde çalıştığında ve sağlıklı olduğunu bildirdiğinde: + +```bash +sudo rm /usr/local/bin/agenteye +``` + +Bu, özellikle AgentEye CLI da kullanıyorsanız önemlidir; bu da kendi `agenteye` komutunu kurar; eski collector ikili dosyasını `/usr/local/bin/agenteye` konumunda bırakmak, `agenteye` adını `PATH` üzerinde belirsiz hale getirir. + +--- + +## Bundan Sonraki Yükseltmeler + +Collector artık kendi kendini güncellemiyor. Yükseltmek için: + +- **İkili dosya:** platformunuz için yeni yapıyı indirin (örneğin `agenteye-collector-linux-x86_64`; tam liste için [Collector Installation → Option A](/tr/agenteye/collector-installation#option-a-binary-recommended) bölümüne bakın), `/usr/local/bin/agenteye-collector` dosyasını değiştirin ve hizmeti yeniden başlatın. +- **Docker:** `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (veya sabitlenmiş bir `:v` etiketi tercih edilir; `:latest` yalnızca kararlı sürümler için mevcuttur) ve konteyneri yeniden oluşturun. + +`AGENTEYE_TOKEN` hala özel sürümler deposundan indirmek için gereklidir, ancak çalışan daemon artık buna ihtiyaç duymamaktadır. + +--- + +## Doğrulayın + +```bash +agenteye-collector --version # yeni ikili dosya PATH'te +agenteye-collector health # çıkış 0 = sağlıklı +agenteye-collector flush # sıraya alınan olayları iletir ve temiz çıkar +``` + +Ardından yeni olayların panonuzda göründüğünü doğrulayın. + +--- + +## Geri Al + +Geçiş yıkıcı değildir. Geri almanız gerekiyorsa, hizmet tanımınızı eski `/usr/local/bin/agenteye` ikili dosyasına geri işaret edin (henüz kaldırmadığınız sürece) ve yeniden başlatın. Olay spool ve yapılandırma paylaşılır ve etkilenmez. + +--- + +## Sorun Giderme + +| Belirti | Neden | Çözüm | +|---|---|---| +| `warning: the collector binary is now agenteye-collector …` her çalıştırmada | İkili dosyayı eski `agenteye` adı altında çağırıyorsunuz | Bunun yerine `agenteye-collector` komutunu çağırın; hizmet dosyalarını ve komut dosyalarını güncelleyin. | +| systemd başarısız olur: `.../agenteye: No such file or directory` | Eski ikili dosyayı `ExecStart` güncellemeden önce kaldırdınız | `ExecStart=/usr/local/bin/agenteye-collector start` komutunu ayarlayın, ardından `sudo systemctl daemon-reload` komutunu çalıştırın. | +| Kubernetes pod'u görüntü yükseltmesinden sonra crash-loops yapıyor | Canlılık sondası hala `agenteye` çalıştırıyor | Sonda komutunu `["agenteye-collector", "health"]` olarak değiştirin. | +| `agenteye: command not found`, ancak `agenteye-collector` çalışıyor | Komut dosyaları/takma adlar hala eski adı referans alıyor | Bunları `agenteye-collector` olarak güncelleyin. | +| `agenteye` komutunu çalıştırmak CLI'yi başlatıyor, collector'ı değil | AgentEye CLI yüklü; `agenteye` adına sahip | Daemon için `agenteye-collector` kullanın ve `/usr/local/bin/agenteye` konumunda kalan eski collector ikili dosyasını silin. | \ No newline at end of file diff --git a/docs/tr/agenteye/deployment.mdx b/docs/tr/agenteye/deployment.mdx new file mode 100644 index 00000000..da2f5f68 --- /dev/null +++ b/docs/tr/agenteye/deployment.mdx @@ -0,0 +1,415 @@ +--- +title: "Dağıtım" +description: "AgentEye Dağıtım belgelendirmesi." +--- + + +Bu rehber, AgentEye sunucusunun ve panosu'nun üretim ortamında dağıtılmasını kapsar. + +--- + +## Mimari Genel Bakış + +``` + [ AI agent makineleri ] [ Sizin altyapınız ] + + Python SDK + | JSONL yazıyor +----------------------+ + v +--->| PostgreSQL 15+ | + agenteye-collector --HTTP--+ | | (ilişkisel depo) | + | | +----------------------+ + v | + +--------+ | +----------------------+ + | Server |<------+--->| ClickHouse 24+ | + +--------+ | | (etkinlikler / analiz)| + ^ | +----------------------+ + API | | + | | +----------------------+ + +-----------+ +- - >| Redis 7+ (isteğe bağlı) | + | Pano | +----------------------+ + +-----------+ +``` + +- **Server**: Rust HTTP servisi; etkinlik gruplarını alır, bunları ClickHouse'a yazar ve ilişkisel durumu PostgreSQL'de tutar. +- **Pano**: Next.js web uygulaması; yalnızca sunucu API'si aracılığıyla okur ve yazar. +- **agenteye-collector**: sunucu ana bilgisayarında değil, agent makinelerine dağıtılır. +- **Postgres 15+**: GEREKLI. (Multi-tenant sürümünde 14'ten yükseltildi; org-membership şeması bir sütun listesi `ON DELETE SET NULL` yabancı anahtarı kullanır; bu Postgres 15+ tarafından gereklidir. Bu sürümü dağıtmadan önce Postgres'i yükseltin.) OLTP durumunu depolar: `api_keys`, `users`, `sessions`, `evaluation_jobs` (kuyruk), `dashboards`, `saved_queries`, `otp_codes` ve multi-tenant tabloları `orgs`, `org_memberships`, `org_settings`. +- **ClickHouse 24+**: GEREKLI. Alınan her etkinlik için analitik deposu. Motor: `ReplacingMergeTree`, ay cinsinden bölümlenmiş, `(session_id, ts, dedup_key)` tarafından sıralanmış. Sunucu `CLICKHOUSE_URL` aracılığıyla bağlanır; paket içi `deploy/base/clickhouse/` performans-ayarlı tek-node yapılandırması ile gelir. **Multi-tenant gereksinimi:** paket içi yapılandırma SQL erişim yönetimini ve `users_without_row_policies_can_read_rows=false` etkinleştirir, böylece sunucu kuruluş başına bir salt okunur ClickHouse kullanıcısı + satır politikası oluşturabilir (SQL editörü ve AI ajanı için motor-zorlanan yalıtım sınırı). Kendi ClickHouse yapılandırmanızı sağlarsanız, bu ayarları taşıyın (bkz. `deploy/base/clickhouse/configmap.yaml`). +- **Redis 7+**: *isteğe bağlı* paylaşılan önbellek + oran-sınırlama arka ucu. Sunucu ve pano her ikisi de `REDIS_URL` aracılığıyla bağlanır. Yoksa, her ikisi de Postgres-only yollarına incelikle düşer. Aşağıda **Redis (isteğe bağlı önbellek)** bölümüne bakın. + +--- + +## Sunucu + +### Görüntüyü çek + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +docker pull ghcr.io/agenteye-enterprise/server:beta-latest +``` + +> Mevcut yapılar `beta-latest` altında yayımlanır; `latest` yalnızca kararlı sürümlere atanır. Üretim için spesifik bir `:v` etiketine sabitleyin; bkz. [Mevcut Görüntü Etiketleri](#mevcut-görüntü-etiketleri). + +### Ortam değişkenleri + +| Değişken | Gerekli | Varsayılan | Açıklama | +|---|---|---|---| +| `DATABASE_URL` | Evet | yok | Postgres DSN. `postgres://` şemasına sahip standart libpq bağlantı dizesi biçimi. `?sslmode=require` ve diğer libpq parametrelerini destekler. Şifre `/`, `+` veya `=` içermemelidir; URL-safe şifreler oluşturmak için `openssl rand -hex` kullanın. | +| `ADMIN_KEY` | Hayır | yok | Bootstrap admin API anahtarı. Her başlamada tüm izinlerle yükseltilir. Değeri değiştirerek ve yeniden başlatarak döndürün. | +| `LISTEN_ADDR` | Hayır | `0.0.0.0:8080` | Bağlanacak TCP adresi | +| `MAX_BODY_BYTES` | Hayır | `134217728` (128 MB) | Maksimum istek gövdesi boyutu | +| `ADMIN_EMAIL` | Hayır | yok | Bootstrap admin kullanıcı e-postası. Her başlamada tüm izinlerle yükseltilir ve korunan olarak işaretlenir: pano/API aracılığıyla devre dışı bırakılamaz veya izinleri değiştirilemez. Bootstrap admin'i döndürmek için `ADMIN_EMAIL` değiştirin ve yeniden başlatın; yeni e-posta korunan olarak yükseltilir ve öncekisi veritabanında el ile temizlenene kadar korumasını tutar. | +| `ALLOWED_EMAILS` | Hayır | yok (hepsi engellenir) | Kullanıcı oluşturma ve oturum açma için izin verilen e-postaların virgülle ayrılmış listesi. Tam adresler (`user@example.com`) ve alan adı joker karakterleri (`*@example.com`) destekler. Ayarlanmazsa, hiçbir kullanıcı oluşturulamaz veya oturum açamaz. **İlk başlangıç seed'i yalnızca**: ilk önyüklemede varsayılan org'un izin listesini seed'ler; bundan sonra her org'un [`//settings`](#operational-settings) sayfası gerçek kaynaktır ve bu env var'ı değiştirmek hiçbir etkiye sahip değildir. | +| `SMTP_HOST` | Hayır | yok | OTP e-postaları göndermek için SMTP sunucusu ana bilgisayar adı. Ayarlanmazsa, OTP kodları stdout'a günlüğe kaydedilir. | +| `SMTP_PORT` | Hayır | `587` | SMTP sunucusu portu | +| `SMTP_USERNAME` | Hayır | yok | SMTP kimlik doğrulama kullanıcı adı | +| `SMTP_PASSWORD` | Hayır | yok | SMTP kimlik doğrulama şifresi | +| `SMTP_FROM` | Hayır | yok | OTP e-postaları için gönderici e-posta adresi | +| `SMTP_TLS` | Hayır | STARTTLS | Açıkça kapatmadığınız sürece STARTTLS kullanılır: `false` veya `0` düz metin gönderir (TLS yok); başka herhangi bir değer — ayarlanmamış dahil — STARTTLS'ı etkinleştirir. | +| `DASHBOARD_URL` | Hayır | yerleşik varsayılan | OTP-e-posta magic linkini ve uyarı bildirimlerindeki olay magic-linklerini oluşturmak için kullanılan pano kaynağı. Ayarlanmazsa yerleşik bir varsayılana geri döner (ve yalnızca OTP için, pano tarafından türetilen istek kaynağına). Bölünmüş etki alanı kurulumları için bunu ayarlayın, böylece hem e-posta hem de Slack/olay linkler pano'nuza işaret eder. Aşağıda **E-posta magic-link URL'i** bölümüne bakın; çoğu operatör bunu ayarlamak zorunda değildir. | +| `SESSION_TTL_SECS` | Hayır | `86400` (24 h) | Pano oturumu süresi (saniye cinsinden). **İlk başlangıç seed'i yalnızca**: ilk dağıtımdan sonra [`//settings`](#operational-settings) aracılığıyla org başına düzenleyin. | +| `OTP_TTL_SECS` | Hayır | `600` (10 min) | OTP kodu geçerlilik süresi (saniye cinsinden). **İlk başlangıç seed'i yalnızca**: ilk dağıtımdan sonra [`//settings`](#operational-settings) aracılığıyla org başına düzenleyin. | +| `REDIS_URL` | Hayır | yok | İsteğe bağlı paylaşılan önbellek + oran-sınırlama arka ucu, örn. `redis://redis:6379/0`. Ayarlandığında, sunucu kimlik doğrulaması yapılmış API-key araştırmasını, pano'nun `/models` toplamını, oturumlar listesini ve env-list fasetini önbelleğe alır; ayrıca OTP-istek oran sınırlamasını Postgres COUNT'tan Redis INCR'ye taşır. Ayarlanmazsa veya erişilemezse, sunucu önbellek olmadan çalışır (OTP sınırı Postgres'e geri döner, diğer her önbellek araması gerçek kaynağa düşer). **Redis (isteğe bağlı önbellek)** bölümüne bakın. | +| `CLICKHOUSE_URL` | **Evet** | yok | ClickHouse örneğinin temel URL'i, örn. `http://clickhouse:8123`. Sunucu her başlamada kendi etkinlik şemasını bu veritabanına uygular ve ClickHouse'a erişemezse önyüklemeyi reddeder. **ClickHouse (gerekli analitik depo)** bölümüne bakın. | +| `CLICKHOUSE_DATABASE` | Hayır | `agenteye` | ClickHouse veritabanı (şema) adı. Sunucu başlangıçta mevcut değilse oluşturur. | +| `ORG_CH_SECRET` | Hayır (tek-tenant) / **Evet (multi-org)** | dev varsayılanı | Her kuruluşun kiracı-başına ClickHouse şifresi türetildiği HMAC anahtarı. SQL editörü ve AI ajanının `run_query` org'un kendi salt-okunur ClickHouse kullanıcısı olarak yürütülür; satır politikası motorda kiracı yalıtımını uygular. Tek-tenant dağıtımları yerleşik dev varsayılanında iyiyse önyüklenir; **ikinci bir org sağlamadan önce güçlü, sabit bir değer AYARLAMALISINIZ**, çünkü `agenteye-orgctl org create` CLI yerleşik dev varsayılanında çalışmayı reddeder. Bunu döndürmek, her org'un ClickHouse kullanıcısını yetim bırakır; sonraki başlangıçta yeniden sağlayacaklar (önyükleme-zaman uzlaştırması bunu otomatik olarak iyileştirir). Gizli tutun ve çoğaltmalar arasında değişmeden kalın. Org sağlaması operatör tarafındandır; **Kuruluşlar (multi-tenancy)** bölümüne bakın. | +| `DEFAULT_ORG_NAME` | Hayır | `Default` | Yerleşik varsayılan org için seed'lenmiş görüntülü ad. **İlk başlangıç seed'i yalnızca** ve org hâlâ yeni-geçişlenmiş jenerik kimliğini taşırken, başlangıçta uygulanır, sonra yoksayılır. Org'u yeniden adlandırdığınızda (`agenteye-orgctl org rename`) yeniden ad, yetkili olur ve bu env var'ın başka etkisi yoktur. | +| `DEFAULT_ORG_SLUG` | Hayır | `default` | Yerleşik varsayılan org için URL slug'ı, pano yolu (`//…`). `DEFAULT_ORG_NAME` ile aynı ilk-başlangıç-yalnızca / temiz-yalnızca semantiği. 1-40 küçük alfanumerik, tekil iç tire ve [ayrılmış kelime](#organizations-multi-tenancy) olmayan olmalıdır; geçersiz bir değer yoksayılır (org `default`'u tutar). Tek-tenant kurulumun `/default` yerine örn. `/acme` olarak sunmasına izin verir, herhangi bir sonrası-dağıtım CLI adımı olmadan. | +| `RUST_LOG` | Hayır | `info` | Günlük ayrıntıları (`debug`, `warn`, `error`, `agenteye_server=trace`) | +| `EVALUATOR_ENDPOINT` | Hayır | yok | Evaluator hizmetinizin temel URL'i (örn. `http://evaluator:9000`). Ayarlanmazsa tüm değerlendirme boru hattı no-op olur; hiçbir kuyruk satırı yazılmaz, hiçbir işçi çalışmaz. Bkz. [Evaluation Suite](/tr/agenteye/evaluation-suite). | +| `EVALUATOR_TOKEN` | Hayır | yok | Evaluator olarak `Authorization: Bearer ` gönderilir. **Evaluator hizmetinin yapılandırıldığı aynı değere eşit OLMALIDIR.** İsteğe bağlı, yalnızca evaluator'unuz token olmayan şekilde yapılandırılmışsa. | +| `EVALUATOR_WORKERS` | Hayır | `2` | Eşzamanlılık: her sunucu örneği başına değerlendirmeleri görevlendirenişçi görevlerinin sayısı. Yatay olarak ölçeklenmiş birden fazla sunucu arasında çalışmak için güvenlidir. | +| `EVALUATOR_CLAIM_BATCH` | Hayır | `4` | Tek bir işçinin her tıkta talep ettiği maksimum değerlendirme sayısı. Gruplar **eşzamanlı** olarak gönderilir, bu nedenle evaluator uç noktanız üzerindeki toplam eşzamanlılık `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH` dir. | +| `EVALUATOR_POLL_IDLE_SECS` | Hayır | `2` | Hiçbir şey vadesi gelmediğinde bir işçinin gönderim denemeleri arasında uyuduğu süre. | +| `EVALUATOR_POLLING_INTERVAL_SECS` | Hayır | `10` | Evaluator bir `next_poll_secs` başına yanıt döndürmediğinde ve `GET /config` işleminden bir `default_poll_interval_secs` bildirmediğinde `GET /evaluate/{id}` yoklamalar için son yedek kadansı (saniye). | +| `EVALUATOR_REQUEST_TIMEOUT_MS` | Hayır | `30000` | Evaluator'a karşı HTTP isteği başına zaman aşımı (milisaniye). | +| `EVALUATOR_MAX_ATTEMPTS` | Hayır | `5` | Bu kadar başarısız deneyimden sonra bir değerlendirme terminal `error` (veya başarısızlıklar istek zaman aşımı ise `timeout`) olarak kaydedilir. | +| `EVALUATOR_CONFIG_REFRESH_SECS` | Hayır | `300` (5 min) | Sunucunun evaluator'dan `GET /config` işlemini ne sıklıkta yeniden getirdiği. | +| `EVALUATOR_MAX_POLL_DURATION_SECS` | Hayır | `3600` (1 h) | Bir oturumun yoklama kuyruğunda kalmadan önce maksimum duvar saati zamanı; bundan sonra AgentEye bunu `timeout` olarak sonlandırır. Evaluator'ın `pending`'i sonsuza kadar döndürmesine karşı korunma. | +| `ALERT_WORKERS` | Hayır | `1` | Eşzamanlılık: her sunucu örneği başına uyarı kurallarını değerlendirenişçi görevlerinin sayısı. Bkz. [Alerts](/tr/agenteye/alerts). | +| `ALERT_CLAIM_BATCH` | Hayır | `16` | Tek bir işçinin her tıkta talep ettiği maksimum uyarı sayısı. | +| `ALERT_POLL_IDLE_SECS` | Hayır | `5` | Kuyruk boş olduğunda bir uyarılar işçisinin uyuduğu süre. | +| `ALERT_REQUEST_TIMEOUT_MS` | Hayır | `15000` | Tetikleme değerlendirmesi başına zaman aşımı (ClickHouse sorguları + giden kanal HTTP). | +| `ALERT_MAX_ATTEMPTS` | Hayır | `5` | Ardışık geçici başarısızlıklar; bundan sonra uyarı üstel geri tepme yerine normal kadansında yeniden zamanlanır. | +| `AUDIT_WORKERS` | Hayır | `1` | Eşzamanlılık: her sunucu örneği başına denetimi gerçekleştirenişçi görevlerinin sayısı. Bkz. [Audits](/tr/agenteye/audits). | +| `AUDIT_CLAIM_BATCH` | Hayır | `1` | Tek bir işçinin her tıkta talep ettiği vadesi gelen maksimum denetim sayısı. Bir ajantik araştırma tek bir uzun döngüdür, bu nedenle varsayılan 1'dir. | +| `AUDIT_POLL_IDLE_SECS` | Hayır | `30` | Denetim vadesi gelmediğinde bir denetimler işçisinin uyuduğu süre. | +| `AUDIT_REQUEST_TIMEOUT_MS` | Hayır | `30000` | ClickHouse'a karşı ilke-sorgusu başına zaman aşımı (milisaniye). | +| `AUDIT_LLM_TIMEOUT_MS` | Hayır | `1440000` | AI yardımcı hizmetine ajantik araştırma çağrısı için zaman aşımı. Tam bir ajan döngüsü dakika boyunca çalışır; bu SUNUCU zaman aşımdan sonra YUKARIDA tut; böylece ajan sunucu vazgeçmeden kısmi bulgularını döndürür. | +| `AUDIT_MAX_ATTEMPTS` | Hayır | `5` | Ardışık geçici başarısızlıklar; bundan sonra denetim üstel geri tepme yerine normal kadansında yeniden zamanlanır. | +| `AGENTEYE_AGENT_URL` / `AGENTEYE_AGENT_TOKEN` | Hayır | — | Denetimin ajantik araştırması AI-yardımcısı `agent` hizmetine çağrı yapar, **yardımcı ile aynı bağlantıyı yeniden kullanarak** — bu nedenle bunları **sunucuda** da ayarlayın (paket içi manifests/compose yapar). Her ikisi de ayarlanmışsa ⇒ denetimler AI araştırmasını çalıştırır; ya ayarlanmamışsa ⇒ denetimler **politika-yalnızca** çalıştırır (belirleyici SQL politikası geçişi hâlâ çalışır), denetim başına `llm_enabled` bayrağından bağımsız olarak. Ajan ayrıca bir LLM yapılandırılmış olmalıdır — bkz. [assistant.md](/tr/agenteye/assistant). | + +**AI yardımcı hizmeti — denetim + sandbox ayarları.** Ajantik araştırma ve pod'daki Python sandbox'u **ajan hizmetinde** ayarlanır (sunucu değil), tümü `AGENTEYE_AUDIT_*` ön eki altında ve tümü isteğe bağlı: + +| Değişken | Varsayılan | Anlam | +|---|---|---| +| `AGENTEYE_AUDIT_MAX_STEPS` | `200` | Araştırma başına maksimum ajan adımları. | +| `AGENTEYE_AUDIT_TIMEOUT_MS` | `1200000` | Bir araştırma için duvar saati (20 min). Sunucunun `AUDIT_LLM_TIMEOUT_MS`'nin **altında** kalması gerekir. | +| `AGENTEYE_AUDIT_MAX_CONCURRENCY` | `1` | Ajan pod'u başına eşzamanlı araştırmalar (sohbet yardımcısının bütçesinden ayrı). | +| `AGENTEYE_AUDIT_SANDBOX_TIMEOUT_MS` / `_MEM_MB` / `_CPU_SECS` / `_OUTPUT_MAX_BYTES` / `_SCRIPT_MAX_BYTES` | `20000` / `768` / `10` / `64000` / `64000` | Bubblewrap sandbox'u için betik başına sınırlar. | + +**Sandbox platform gereksinimi.** Denetim kodu sandbox'u ajanın Python'unu bir bubblewrap hapishanesinde çalıştırır; bu **ayrıcalıklı olmayan kullanıcı ad alanlarına** ihtiyaç duyar. Ajan pod'u `clone()` bayraklarına izin vermelidir — `seccompProfile: Unconfined` (k8s) veya `security_opt: [seccomp:unconfined]` (compose) ayarlayın ajan'da. Düğüm kerneli ayrıcalıklı olmayan kullanıcı ad alanlarını devre dışı bırakan yerde (örn. bazı GKE COS görüntüleri), sandbox **preflight başarısız olur ve denetçi otomatik olarak SQL-only'ye düşer** — hata yok, ajan'ın `/health` üzerinde `sandbox_available: false`. + +### Çalıştır + +`DATABASE_URL` ve `CLICKHOUSE_URL`'i ortamınızda ayarlayın (sunucu ClickHouse olmadan önyüklemeyi reddeder), sonra bunları kapsayıcıya geçirin: + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-server \ + -e DATABASE_URL="$DATABASE_URL" \ + -e CLICKHOUSE_URL="$CLICKHOUSE_URL" \ + -e ADMIN_KEY="$ADMIN_KEY" \ + -p 8080:8080 \ + ghcr.io/agenteye-enterprise/server:beta-latest +``` + +Sunucu, başlamada otomatik olarak veritabanı geçişlerini çalıştırır; ayrı geçiş adımı gerekli değildir. + +### Sistem durumu kontrolü + +``` +GET /health # canlılık - işlem açıktan sonra her zaman {"status":"ok"} +GET /ready # hazırlık - Postgres + ClickHouse erişilebilir olduğunda 200, aksi durumda 503 +``` + +Kimlik doğrulama gerekli değildir. **Canlılık** yoklamaları için `/health` ve **hazırlık** / yük dengeleyici yoklamaları için `/ready` kullanın. `/ready`, sunucu olmadan sunucu'nun hizmet veremediği sabit bağımlılıkları kontrol eder (Postgres + ClickHouse), bu nedenle çalışan ama veritabanına ulaşamayan sunucu döndürülürü alır ve `NotReady` olarak gösterilir; Redis raporlanır ama hiçbir zaman hazırlığı başarısız kılmaz. Paket içi Kubernetes manifests'inde hazırlık yoklaması `/ready` konumunda ve canlılık `/health` konumunda kalır. Tam resim için [enterprise-docs/health-monitoring.md](/tr/agenteye/health-monitoring) dosyasına bakın; Slack'a Kubernetes-native pod-başarısızlığı uyarısı dahil. + +### E-posta magic-link URL'i + +OTP oturum açma e-postaları tek-dokunuş **pano'yu aç** düğmesi içerir. Tıklamak kullanıcıyı `/login?token=&email=
` konumuna indirir; pano bu çifti bir oturum için değiştirir ve uygulamaya yeniden yönlendirir, el ile kod yeniden girişi olmadan. Sunucu, linki oluşturmak için kullanılan pano kaynağını üç katmanda çözer: + +1. **`X-AgentEye-Dashboard-Url` başlığı**: pano'nun `/api/auth/otp/request` proxy'si tarafından otomatik olarak kendi genel kaynağından ayarlanır. Aynı-kaynaklı dağıtımda (sunucu ve pano host'u paylaş tek bir girişin arkasında proxy başlıklarını iletebilir), **yapılandırma gerekli değildir**. +2. **`DASHBOARD_URL` env var'ı**: pano'nuz, sunucu'nun OTP istek uç noktasının gördüğü kaynaktan farklı bir kaynakta erişilebiliyorsa (bölünmüş `api.example.com` / `app.example.com`) veya girişiniz genel host'u pano pod'una yayılamıyorsa (bu nedenle `request.nextUrl.origin` `0.0.0.0:3000` gibi bir joker karakteri bind'e çözümlenir), bunu ayarlayın. Örnek: `DASHBOARD_URL=https://app.example.com`. +3. **Varsayılan**: `https://app.befailproof.ai`, yalnızca yukarıdakilerden hiçbiri mevcut değilse kullanılır. + +Başlık değeri doğrulanır: yalnızca `https://*` ve loopback (`http://localhost*`, `http://127.0.0.1*`) kaynakları kabul edilir ve joker karakteri bind adresleri (`0.0.0.0`, `[::]`) `https://` şemasıyla bile reddedilir. Başka herhangi bir şey katman 2'ye düşer. + +Çalışan küme üzerinde tek satırlı olarak ayarlayın; dosya yok, kustomize yeniden derleme yok: + +```bash +kubectl set env deployment/server -n agenteye \ + DASHBOARD_URL=https://app.example.com +``` + +Bu bir dağıtımı tetikler; yeni pod'lar değeri ilk istekte alır. Override'ın yalnızca Dağıtımda yaşadığını unutmayın; sonraki `kustomize build | kubectl apply` overlay'a karşı, aynı env var'ı overlay'ın `server-env.yaml` yamalamasına eklemediğiniz sürece bunu silecektir. + +--- + +## Pano + +### Görüntüyü çek + +```bash +docker pull ghcr.io/agenteye-enterprise/dashboard:beta-latest +``` + +### Ortam değişkenleri + +| Değişken | Gerekli | Varsayılan | Açıklama | +|---|---|---|---| +| `AGENTEYE_SERVER_URL` | Evet | yok | Sunucunun temel URL'i, örn. `http://localhost:8080` | +| `AGENTEYE_API_KEY` | Evet | yok | Pano'nun sunucu'ya kimlik doğrulamak için kullandığı API anahtarı. Tüm izinleri gerektirir (admin anahtarı önerilir). | +| `AE_LOG_LEVEL` | Hayır | `info` | Sunucu tarafı günlük ayrıntıları: `debug`, `info`, `warn`, `error`. Sorunları tanılarken yukarı yönlü istek/yanıt satırlarını ve oturum-doğrulama izlerini görmek için `debug` olarak ayarlayın. | +| `AE_LOG_JSON` | Hayır | otomatik | `1` JSON-satır başına çıktıyı zorlar; `0` okunabilir çıktıyı zorlar. Ayarlanmazsa, `NODE_ENV=production` ise JSON otomatik olarak etkinleştirilir. JSON üretimde önerilir, böylece günlükler `jq` veya günlük toplayıcı ile düzgün ayrıştırılır. | +| `AE_ANALYTICS_DISABLED` | Hayır | yok | Pano'nun anonim ürün-kullanımı telemetrisini devre dışı bırakmak için `1`/`true` olarak ayarlayın. Aşağıda [Telemetri & gizlilik](#telemetri--gizlilik) bölümüne bakın. | +| `REDIS_URL` | Hayır | yok | İsteğe bağlı paylaşılan önbellek arka ucu, örn. `redis://redis:6379/0`. Ayarlandığında, pano `validateSession()` sonuçlarını çoğaltmalar arasında önbelleğe alır ve gecikme-toplama / env-list proxy rotaları için Next.js getirme önbelleğini paylaşır. Kenar tarafı OTP istek ve doğrulama oran sınırları mevcut olduğunda Redis kullanır (Redis erişilemezse açık kalır; sunucu tarafı sınırı güvenlik yedek saklayıcısıdır). **Redis (isteğe bağlı önbellek)** bölümüne bakın. | +| `AGENTEYE_AGENT_URL` | Hayır | yok | İsteğe bağlı AI-yardımcısı `agent` hizmetinin temel URL'i, örn. `http://agent:9100`. **Ayarlanmamış bırakın ve yardımcıyı tamamen gizleyin**: pano'da yardımcı balonu görünmez. Bkz. [enterprise-docs/assistant.md](/tr/agenteye/assistant). | +| `AGENTEYE_AGENT_TOKEN` | Hayır | yok | Pano'nun `agent` hizmetine sunduğu paylaşılan gizli. Ajan'da yapılandırılan `AGENTEYE_AGENT_TOKEN` ile eşleşmesi gerekir. Bkz. [enterprise-docs/assistant.md](/tr/agenteye/assistant). | + +### Çalıştır + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-dashboard \ + -e AGENTEYE_SERVER_URL="http://your-server-host:8080" \ + -e AGENTEYE_API_KEY="$ADMIN_KEY" \ + -p 3000:3000 \ + ghcr.io/agenteye-enterprise/dashboard:beta-latest +``` + +### Telemetri & gizlilik + +Pano, **anonim ürün-kullanımı analitiğini** Exosphere'ın analitik hizmetine (PostHog) gönderir: hangi pano sayfalarının görüntülendiği ve API anahtarı oluşturma veya oturumun yeniden değerlendirilmesi gibi bir avuç UI eylemi. Bu kullanım sinyali hangi özelliklerin önceliklendirildiğini bilgilendirir. + +- **Hiçbir ajan, oturum veya etkinlik verisi altyapınızı asla terk etmez.** Yalnızca pano UI kullanımı raporlanır. Sayfa URL'leri gönderilmeden önce tanımlayıcılardan temizlenir ve operatörler yalnızca opak iç kimliğe göre, asla e-postaya göre tanımlanır. +- Telemetri **varsayılan olarak etkindir**. Tamamen kapatmak için pano konteynerine `AE_ANALYTICS_DISABLED=1` ayarlayın ve yeniden başlatın. +- Analitikler pano'nun kendi `/ingest` yoluna gönderilir, pano bunu PostHog'a (`https://us.i.posthog.com`) ters proxy'ler. İstekleri birinci tarafa almak, tarayıcı ad-bloklayıcılarının bunları bırakmaması anlamına gelir. **Pano konteyner'ı** PostHog'a giden erişime ihtiyaç duyar; engellenmişse, telemetri sessizce hiçbir şey yapmaz ve pano etkilenmez. + +--- + +## AI Yardımcısı (isteğe bağlı) + +Pano içi AI yardımcısı, ekibinizin agent verilerini düz dilinde sormalarını sağlar (oturumları özetlemek, `/queries` editörü için SQL taslağı hazırlamak ve kaydedilen sorguları pano kutucuklarına dönüştürmek) pano'yu terk etmeden. Ayrı bir dahili `agent` konteyner'inde (Claude Agent SDK'da) çalışır, yalnızca pano'ya erişebilir ve **bir LLM uç noktası yapılandırıncaya kadar devre dışı kalır**. + +Etkinleştirmek için, `agent` hizmetine bir LLM bağlantısı (**Portkey** via `PORTKEY_API_KEY` + model-katalog slug `AGENTEYE_AGENT_MODEL=@/`, doğrudan Anthropic via `ANTHROPIC_API_KEY`, başka bir ağ geçidi via `ANTHROPIC_BASE_URL` veya Bedrock/Vertex), **adanmış** veri anahtarı ve pano ile eşleşen paylaşılan `AGENTEYE_AGENT_TOKEN` ayarlarsınız. Pano kullanıcıları ek olarak `agent:use` iznine ihtiyaç duyar. + +Yardımcının veri anahtarı için el ile hiçbir şey basmazsınız: rastgele gizli seçin, `agent` üzerinde `AGENTEYE_API_KEY` ve `server` üzerinde `AGENT_API_KEY` olarak ayarlayın ve sunucu başlangıçta sabit bir izin setiyle seed'ler. Veri erişimi salt-okunur (`events:read`, `evaluations:read`, `dashboards:read`, `queries:read`) ve ek olarak onay geçitli yazma kapsamlarını tutar (`dashboards:write`, `queries:write`, `queries:run`) böylece kaydedilen sorguları ve pano kutucuklarını kullanıcı adına tasarını doğrulayabilir; tüm SQL yine de org'un salt-okunur ClickHouse rolü aracılığıyla çalışır, bu yüzden bu yardımcının yazabileceğini genişletir, ulaşabileceği veri değil. Kapsamlar koddaki fixed'dir ve yapılandırma tarafından genişletilemez. Bu anahtar korunur; API aracılığıyla devre dışı bırakılamaz veya yeniden oluşturulamaz, yalnızca değeri değiştirerek ve yeniden başlatarak döndürülür. Asla admin/pano anahtarını bunu için yeniden kullanmayın. + +Tam kurulum, tam ortam-değişkeni referansı, telemetri seçenekleri ve güvenlik modeli **[enterprise-docs/assistant.md](/tr/agenteye/assistant)** sayfasındadır. + +--- + +## ClickHouse (gerekli analitik depo) + +ClickHouse, panolarınızı yüksek etkinlik hacimlerinde duyarlı tutar ve `/queries` SQL editörünün etkinlikler, değerlendirmeler ve oturumlar arasında tek bir depoda birleştirilmesine izin verir. Alınan her etkinlik, her terminal değerlendirme sonucu ve türetilmiş oturum başına toplamlar için gerekli kurallı depo olur. PostgreSQL ilişkisel / değiştirilebilir-durum tablolarını tutar (api_keys, users, otp_codes, evaluation_jobs, dashboards, saved_queries); analitik yüzey ClickHouse'da yaşar, bu yüzden pano'nuzun toplamları ve kendi SQL sorgularınız veri tabanları arasında tur yapılmadan onu veya katılması yapılmayan tüm deponuzda taraması yapılabilir. Sunucu `CLICKHOUSE_URL` olmadan önyüklemeyi reddeder. + +### Şema + +Üç ClickHouse nesnesi sunucu başlangıcında oluşturulur, tümü idempotent (`CREATE IF NOT EXISTS`): + +- **`agenteye.events`**: `ReplacingMergeTree(ingested_at)`, `toYYYYMM(ts)` tarafından bölümlenmiş, `(session_id, ts, dedup_key)` tarafından sıralanmış. Yinelenen eklemeler (collector yeniden denemeleri) birleştirme saatinde tek satıra çöker; sunucu her etkinlik için belirleyici SHA-256 `dedup_key` hesaplar, böylece yeniden denemeler güvenlidir. +- **`agenteye.evaluations`**: `ReplacingMergeTree(ingested_at)`, `toYYYYMM(finished_at)` tarafından bölümlenmiş, `(session_id, finished_at, dedup_key)` tarafından sıralanmış. Terminal değerlendirme sonucu başına evaluator boru hattı tarafından bir kez yazılır. `events` ile aynı dedup-key modeli. +- **`agenteye.agent_sessions`**: fiziksel bir tablo değil, `agenteye.events` üzerinde bir **VIEW**. Her sütun türetilir (`started_at = min(ts)`, `last_event_at = max(ts)`, `ended_at = max(if event_type='agent_end', ts, NULL)`, `event_count = count()` vb.). Olay başına yükseltme ve ayrı geri doldurma yok; görünüm `events` içinde ne varsa otomatik olarak yansıtır. + +Kaydedilmiş sorguların `analytics.evaluations` / `analytics.sessions` başvurusunda ileriye yönelik uyumluluğu için, sunucu ayrıca `agenteye.*` tabloları üzerinde görünümlerle `analytics` ClickHouse veritabanı oluşturur; `analytics.events`, `analytics.evaluations`, `analytics.agent_sessions`, `analytics.sessions` doğru şekilde çözümlenebilir. + +### Yapılandırma + +Paket içi docker-compose ve `deploy/base/clickhouse/` AgentEye'ın iş yüküne göre ayarlanan ClickHouse hizmeti ile gelir: + +- 2 GiB isteme / 4 GiB sınırı hafıza paket içi temel overlay'da (küçük POC/staging düğümlere sığmak için boyutlandırılır); üretim müşterileri yükseltme overlay yapmalıdır — önerilen taban katı 2c / 4Gi istek, 6c / 8Gi sınırıdır. `max_server_memory_usage_to_ram_ratio=0.9` +- 5 GiB işaret önbelleği + 8 GiB sıkıştırılmamış önbellek +- `background_pool_size=16`, `background_merges_mutations_concurrency_ratio=2` +- MergeTree: `parts_to_throw_insert=3000`, `parts_to_delay_insert=1500`, `non_replicated_deduplication_window=1000` +- `local_io_method=auto` (desteklenen çekirdeklerde io_uring) +- `fsync_metadata=0`: en az bir kez alım + ReplacingMergeTree dedup nedeniyle kabul edilebilir +- `query_log` etkin, 30 günlük TTL ile; `query_thread_log` kaldırıldı (yüksek QPS'de pahalı) +- `max_execution_time=30` kullanıcı tarafı sorguları için +- 100 GiB PVC StatefulSet şablonunda (müşteri overlay'ları üretim için hızlı SSD depolama sınıfına geçersiz kılmalıdır) + +### Yedeklemeler + +Tam veri setiniz her gece tek bir geri yüklenebilir arşivde yakalanır, böylece bir küme veya depolama kaybı kurtarılabilir. ClickHouse otomatik olarak `agenteye-backup` CronJob'u tarafından yedeklenir; günlük PostgreSQL ve ClickHouse'u tek bir geçişte dökümü yapar. ClickHouse HTTP API'si aracılığıyla okunur: `agenteye.events` ve `agenteye.evaluations` ClickHouse-native biçiminde boşaltılır (görünümler ve satır politikaları başlangıçta sunucu tarafından yeniden oluşturulur, böylece tablo verisi tam resim olur) ve Postgres dökümü ile tek bir sıkıştırılmış arşive birleştirilir ve nesne depolamasına yüklenir. + +Hedef tuş kutusu ve bulut kimlik bilgileri overlay'a göre yapılandırılır. Yükleme yapılandırması ve geri yükleme adımları için [enterprise-docs/kubernetes-deployment.md](/tr/agenteye/kubernetes-deployment) **Yedeklemeler** bölümüne bakın. + +--- + +## Redis (isteğe bağlı önbellek) + +Redis, sunucu ve pano tarafından kullanılan **isteğe bağlı** paylaşılan önbellek + oran-sınırlama arka ucudur. Redis dağıtılmış ve `REDIS_URL` her iki hizmette ayarlandığında: + +- **Sunucu** kimlik doğrulaması yapılmış API-key araştırmalarını, `/events/environments` + `/evaluations/environments` listelerini, `/events/latency_aggregate` toplamını (pano'nun yokladığı en ağır sorgu), `/sessions` listesini önbelleğe alır ve OTP-istek oran sınırlamasını Postgres `COUNT(*)` konumundan Redis `INCR + EXPIRE` konumuna geçirir. +- **Pano** `validateSession()` sonuçlarını çoğaltmalar arasında önbelleğe alır, böylece tipik sayfa yüklemesi 10-20 kimlik doğrulaması yapılmış API çağrısının tümü bir yukarı yönlü oturum kontrolünü paylaşır. Ek olarak pano kenarında OTP-istek ve OTP-verify'ı oran sınırlaması yapar. + +**Her iki hizmet de Redis erişilemezse incelikle düşer.** Her önbellek çağrısı sınırlandırılmış bir zaman aşımı içinde `Err` döndürür ve arayan gerçek kaynağa geri döner (sunucu üzerinde Postgres, pano'da yukarı yönlü Rust sunucu). OTP oran sınırlaması sunucu üzerinde Postgres `COUNT(*)` yoluna geri döner (güvenlik özelliği korunur); pano'nun kenar OTP sınırı açık kalırken sunucu tarafı sınırı hâlâ tutulur. Redis'in aşağı olması gecikmeyi, doğruluğu değil. Sunucu ve pano her iki tarafında gradual cache misses yönlendirmek için `REDIS_URL` set'ini kullanan her mekanizmanın yedeği açık tutmalı, ne Redis ne de kaynak erişilemezse her zaman orijinal veri tarafına dönmelidir. + +### Yapılandırma + +docker-compose paketi zaten bir Redis hizmeti içerir ve `REDIS_URL=redis://redis:6379/0` öğesini sunucu ve pano'ya bağlar. Harici Redis kullanmak için `REDIS_URL`'yi uç noktanıza ayarlayın ve compose dosyasından `redis` hizmetini kaldırın. + +### Hafıza + kalıcılık + +Paket içi Redis görüntüsü `--appendonly yes --appendfsync everysec --maxmemory 256mb --maxmemory-policy allkeys-lru` öğesiyle çalışır. AOF kalıcılığı, önbelleğin konteyner yeniden başlamalarından sağ kalması anlamına gelir; `everysec` dayanıklılık/perf dengesi doğrusudr, çünkü son saniye önbellek yazış kaybetme zararsızdır. LRU çıkarma hafıza büyümesini tutar. + +### Redis dağıtılmaması gereken durumlar + +- Tek örnek dev/QA. Sunucu'daki in-process önbellekler tek başına çoğu çoğaltma başına yararı sağlar; Redis tek örnek kurulumların ihtiyaç duymadığı çoğaltmalar arası paylaşım ekler. +- Hava boşluğu konfigürasyonları; bir hizmetin operasyonel maliyeti gecikme kazancından daha ağır görülmektedir. + +--- + +## Docker Compose (önerilir) + +`agenteye-enterprise/releases` deposunda bir `docker-compose.yml` mevcuttur. Postgres, ClickHouse, Redis, sunucu ve pano'yu tek bir komutla açar. + +```bash +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download \ + --repo agenteye-enterprise/releases \ + --pattern 'docker-compose.yml' \ + --dir ./agenteye +cd agenteye +``` + +**Varsayılan değerleri `.env` aracılığıyla geçersiz kılın:** + +``` +# URL-safe şifreler kullanın (/, +, veya = karakteri yok). +# Şu komutu kullanarak oluşturun: openssl rand -hex 24 +POSTGRES_PASSWORD=your-db-password +ADMIN_KEY=your-admin-secret + +# Pano kimlik doğrulaması +ADMIN_EMAIL=admin@yourcompany.com +ALLOWED_EMAILS=*@yourcompany.com + +# OTP e-postaları için SMTP (OTP kodlarını stdout'a günlüğe kaydetmek için atla) +# SMTP_HOST=smtp.yourprovider.com +# SMTP_PORT=587 +# SMTP_USERNAME=your-smtp-user +# SMTP_PASSWORD=your-smtp-password +# SMTP_FROM=noreply@yourcompany.com + +RUST_LOG=info +``` + +```bash +docker compose up -d +``` + +**Durdur (veri hacmini tutar):** + +```bash +docker compose down +``` + +**Durdur ve tüm veriyi sil:** + +```bash +docker compose down -v +``` + +--- + +## İşletme ayarları + +Daha önce env var'ları tarafından sabitlenen bir dizi işletme kolu şimdi pano'nun **`//settings`** sayfasından kuruluş başına düzenlenebilir; her org kendi öğesini yapılandırır. Değişiklikler saniyeler içinde etkinleşir, yeniden başlatma veya yeniden dağıtım olmadan. + +| Ayar | Bootstrap env var | Ne kontrolü yapıyor | +|---|---|---| +| İzin verilen sign-inler | `ALLOWED_EMAILS` | OTP almaya ve kullanıcı olarak eklenmesine izin verilen e-postalar (veya `*@domain.com` joker karakterleri) | +| Varsayılan kullanıcı izinleri | `DEFAULT_USER_PERMISSIONS` | Yönetici **+ yeni kullanıcı** açtığında önceden seçilen virgülle ayrılmış izin belirteçleri. Her belirteç [API anahtarı izinleri](/tr/agenteye/api-keys) altında listelenen dizelerden biri olmalıdır. Varsayılan olarak `standard` ön ayarına gider: salt-okunur erişim ve günlük on-call eylemleri (yeniden değerlendirmeleri tetikle, sorguları çalıştır, olayları kabul et, yardımcıyı kullan). | +| Oturum ömrü | `SESSION_TTL_SECS` | Pano oturum açması yeniden auth'a kadar ne kadar geçerli kalır? Pano yukarı yönlü oturumu her 5 saniyede yeniden kontrol eder, bu yüzden `//users` işlemindeki izin güncellemesi sonraki istek'te etkilenen kullanıcıya etkinleşir; relogin yok. | +| Tek seferlik kod ömrü | `OTP_TTL_SECS` | OTP / magic-link ne kadar kullanılabilir kalır? | +| Uyarı bildirim kanalları | `ALERTS_ENABLED_CHANNELS` | Uyarı sevkiyatçısının kullanmasına izin verilen kanal türlerinin virgülle ayrılmış listesi: `email`, `slack`, `webhook`. Kanal başına yapılandırma yine de `//alerts/` işleminde yazılır ama sevkiyatçı her giden teslimatı bu set aracılığıyla filtreler; burada devre dışı bırakılan kanal `skipped_disabled` denetim satırıyla kısa devre yapar. `dashboard` kanalı (yerel denetim ekleme) her zaman izinlidir. Varsayılan olarak üçü de açık. | + +### Bootstrap'ın işleyişi + +Ayarlar kuruluş başına `org_settings`'te saklanır. İlk önyüklemede, sunucu varsayılan org'un eksik satırlarını eşleşen env var'dan (veya env var'ı ayarlanmazsa makul bir varsayılandan) seed'ler. Bundan sonra, **saklanan değer gerçek kaynaktır ve env var'ı yoksayılır**; daha sonraki yeniden başlatmada env var'ı değiştirmek canlı org'un değerini etkilemez ve ek org'lar varsayılan yerlerde başlar ve kendi değerlerini yapılandırır. + +Bu şu anlama gelir: + +- Yeni bir dağıtım için, yukarıdaki env var'ları ayarlayın; varsayılan org ilk başlamada bunları okur. +- Daha sonra bir değer değiştirmek için pano'ya giriş yapın ve `//settings` altında düzenleyin. Değişiklik saniyeler içinde tüm sunucu çoğaltmalarında uygulanır; yeniden başlatma gerekmez. +- Başlangıç günlüğü satırı, seed'lenmiş vs. zaten mevcut olan şeyler kaydedilir, böylece bootstrap'ın etkinleştiğini doğrulayabilirsiniz: + + ```text + INFO settings bootstrap: seeded default-org row key=allowed_sign_ins env_var=ALLOWED_EMAILS seeded_from_env=true + ``` + +#### Kuruluşlar arasında sign-in semantiği + +Oturum ve OTP, tek org'a değil, kullanıcıya genel olarak geçerlidir, bu yüzden sign-in zamanında iki kural org başına ayarlarla uzlaştırır: + +- **Oturum / OTP ömrü**: kuruluşlar arasında en kesin (en kısa) ömür kazanır. +- **İzin verilen sign-inler**: kapı her org'un izin listesini org üyeliğiyle birleştirir: bir kullanıcı, herhangi bir org'un izin listesi e-postalarını kabul EDER veya zaten herhangi bir org'un üyesi EDER ise OTP talep edebilir. + +### İzinler + +Bir `//settings` sayfasına erişim iki izin tarafından geçitlenedbilir: + +- `settings:read`: sayfayı ve geçerli değerleri görün. +- `settings:write`: değişiklikleri kaydedin. + +Bootstrap admin kullanıcısı (`ADMIN_EMAIL`'den seed'lenen) diğer her izin ile birlikte her ikisini otomatik olarak alır. Gerektiğinde `//users`'ten başka kullanıcılara verin. + +--- + +## Kuruluşlar (multi-tenancy) + +Tek bir dağıtım, birden çok yalıtılmış **kuruluşları** (kiracıları) hizmet verebilir; veri satırının her biri tam olarak bir org'a aittir ve yalıtım veritabanı motorunda uygulanır. Tek-tenant kurulumun burada hiçbir şeye ihtiyacı yoktur; tüm veri yerleşik `default` org'unda yaşar. (Org'a daha uygun bir ad ve URL slug verebilirsiniz, böylece `/default` yerine örn. `/acme` konumunda yaşar; ilk önyüklemeden önce `DEFAULT_ORG_NAME` / `DEFAULT_ORG_SLUG` ayarlayarak veya `agenteye-orgctl org rename` öğesiyle istediğiniz zaman yeniden adlandırarak yapabilirsiniz.) + +**Kiracı sağlaması operatör tarafındandır.** Kuruluşlar ve üyelikleri **`agenteye-orgctl`** CLI'ı ile oluşturulur ve yönetilir; sunucu görüntüsünün içinde (`agenteye-server` ile birlikte) gemi gelir ve **mevcut sunucu pod'u içinde** çalışır; **ayrı pod/Job, HTTP API yok ve pano düğmesi yok**. Sunucu'nun `DATABASE_URL`, `CLICKHOUSE_URL` ve `ORG_CH_SECRET` öğelerini yeniden kullanır. + +```bash +# Docker Compose - çalışan sunucu hizmetine exec girin: +docker compose exec server agenteye-orgctl org create --slug acme --name "Acme Corp" +docker compose exec server agenteye-orgctl member add --org acme --email alice@acme.example --set admin + +# Kubernetes - çalışan sunucu Dağıtımına exec girin: +kubectl -n agenteye exec deploy/server -- agenteye-orgctl org list +``` + +Mevcut fiiller: `org create | list | rename | delete | purge` ve `member add | list | update | remove`, yerleşik izin setiyle `admin`, `standard` ve `read-only`. Eklenen üyeler, ilk pano oturum açmada OTP alırlar. + +**İkinci org oluşturmadan önce:** güçlü, sabit bir `ORG_CH_SECRET` ayarlayın (org oluşturma komutu yerleşik dev varsayılanında çalışmayı reddeder) ve Postgres'in **15+** olduğundan emin olun. **Değişmez:** org başına API anahtarları yine de pano/API tarafından org üyeleri tarafından basılır; yalnızca org + üye yaşam döngüsü CLI'ye taşındı. Tam komut referansı ve işlenmiş örnek: **[enterprise-docs/tenant-management.md](/tr/agenteye/tenant-management)**. + +--- + +## Bağlam penceresini doldur + +Her `model_response` etkinliği bir **bağlam dolum hapı** gösterir — bu modelin bağlam penceresinin yüzdesi olarak giriş artı çıktı belirteçleri. Bantlar `healthy` (0–24%), `watch` (25–49%), `compacting` (50–74%) ve `reset context` (75–100%) öğeleridir. AgentEye yaygın model kimliklerini otomatik olarak çözer, böylece ilk yapılandırma gerekmez. + +Kuruluş'un gönderdiği her model **Settings → model context windows** altında görünür. `settings:write` sahip kullanıcıları penceresi geçersiz kılabilir veya özel/proxy model ekleyebilir (0–1,000,000 belirteç); `0` "bilinmiyor" anlamına gelir ve hapı bastırır. Değişiklikler yeni alınan etkinliklere uygulanır. `settings:read` kullanan kullanıcılar listeyi görüntüleyebilir. + +Yeni etkinlikler yükseltme anından itibaren dolum alır. Mevcut dağıtım için **geçmiş** etkinlikleri (ve model başına listeyi) doldururmak için, tek seferlik geri doldurmayı çalıştırın — sunucu görüntüsünün içinde gemi gelir (`agenteye-orgctl` gibi) ve mevcut sunucu pod'u içinde çalışır: + +```bash +# ön izleme (org başına mutasyonu yazdırır, hiçbir şey değiştirmez): +kubectl -n agenteye exec deploy/server -- agenteye-backfill-context-window --dry-run +# uygulamak: +kubectl -n agenteye exec deploy/server -- agenteye-backfill-context-window +# docker compose: +docker compose exec server agenteye-backfill-context-window +``` + +Idempotent'tir (yeniden çalıştırılması güvenlidir) ve pod'dan `DATABASE_URL` / `CLICKHOUSE_URL` / `REDIS_URL` öğelerini yeniden kullanır. Model pencereleri düzenledikten sonra mevcut etkinliklerin yeniden hesaplanmasını isterse yeniden çalıştırın. + +--- + +## Üretim Hususları + +- **Postgres**: Yönetilen Postgres hizmeti veya düzenli yedeklemeler ile adanmış örnek kullanın. `DATABASE_URL`, `sslmode=require` dahil tüm standart libpq parametrelerini destekler, şifrelenmiş bağlantılar için. +- **TLS**: Sunucu ve pano'yu TLS'yi sonlandıran ters proxy'nin (nginx, Caddy, Traefik) arkasına yerleştirin. +- **Güvenlik duvarı**: Sunucu portu (varsayılan 8080) yalnızca collector makinelerine ve pano ana bilgisayarından erişilebilir olmalıdır; genel internet'ten değ \ No newline at end of file diff --git a/docs/tr/agenteye/evaluation-suite.mdx b/docs/tr/agenteye/evaluation-suite.mdx new file mode 100644 index 00000000..13849dcd --- /dev/null +++ b/docs/tr/agenteye/evaluation-suite.mdx @@ -0,0 +1,371 @@ +--- +title: "Değerlendirme Paketi" +description: "AgentEye Değerlendirme Paketi belgelendirmesi." +--- + + +AgentEye, tamamlanan ajan oturumlarını tam etkinlik transkriptini +**tek bir müşteriye ait değerlendirici hizmete** POST göndererek puanlandırır. Değerlendirici puanları satır içinde döndürebilir veya AgentEye'ın yoklama yapması için bir `job_id` geri verebilir. Sonuçlar depolanır ve panoda gösterilir. + +Bu kılavuz aşağıdakileri kapsar: + +1. Oturum tamamlanmasının nasıl algılandığı. +2. Değerlendircinin uygulaması gereken HTTP sözleşmesi. +3. AgentEye sunucusunun yapılandırılması. +4. Sonuçların görüntülenmesi. +5. Sorun giderme. + +Sözleşmeyi sizin için uygulayan Python yardımcısı için +[PyPI üzerinde `agenteye-evaluator` paketi](https://pypi.org/project/agenteye-evaluator/) başlığına bakınız. + +--- + +## Nasıl çalışır + +```text +ingest /events ──▶ AgentEye ──── POST /evaluate ────▶ Değerlendirici hizmeti + (agent_end) sunucu ◀──── done | pending ──── + │ + │ GET /evaluate/{job_id} ─────▶ + │ ◀──── done ────────────── + ▼ + evaluations (terminal sonuçları) +``` + +AgentEye SDK bir oturum için `agent_end` etkinliği yayınladığında, sunucu bir değerlendirmeyi zamanlar. Daha sonra tam etkinlik transkriptini değerlendirici hizmetinize POSTler; bu, şunlardan birini yapabilir: + +- **Sonucu satır içinde döndür** `{"status":"done", "scores":{...}, "reasoning":{...}, "summary":"..."}` ile. Sonuç oturumun değerlendirme zaman çizelgesine eklenir. `reasoning` ve `summary` isteğe bağlıdır. +- **Erteleme** `{"status":"pending", "job_id":"abc-123"}` ile. AgentEye daha sonra değerlendirici `{"status":"done", ...}` veya `{"status":"error", "error":"..."}` dönene kadar `GET {EVALUATOR_ENDPOINT}/evaluate/abc-123` çağrısını yapar. + + Yoklama temposu iş başına yapılır: bir `pending` yanıtı `next_poll_secs` içerebilir; aksi takdirde AgentEye `GET /config` yanıtından `default_poll_interval_secs` değerini kullanır; aksi takdirde sunucu `EVALUATOR_POLLING_INTERVAL_SECS` (varsayılan 10s) değerine geri döner. Tüm değerler [1s, 1h] aralığına sınırlandırılır. + +Hiçbir zaman `agent_end` yayan olmayan oturumlar (örneğin, çökmüş bir ajan süreci) +da alınabilir: değerlendircinin `GET /config` yanıtı +`{"inactivity_timeout_secs": 1800}` döndürebilir ve AgentEye bu kadar uzun süre boşta kalmış herhangi bir oturumu değerlendirir. Bu geri dönüşü devre dışı bırakmak için alanı `null` olarak ayarlayın veya atla. + +`EVALUATOR_ENDPOINT` ayarlanmadığında işlem hattı tamamen inaktiftir. + +Bir oturum zaman içinde **birden fazla terminal değerlendirmesi biriktirilebilir**: her `agent_end` etkinliği (ve panodaki her manuel yeniden değerlendirme) yeni bir değerlendirme satırı ekler. Bu, devam ettirilen bir konuşmayı değerlendirmenin desteklenen yoludur: bir kullanıcı ajanı sonlandırır, daha sonra geri gelir, daha fazla etkinlik gönderir, ajanı yeniden sonlandırır ve ikinci bir değerlendirme tam güncellenmiş transkript üzerinde çalışır. Panel en son değerlendirmeyi başlık olarak ve önceki değerlendirmeleri daraltılabilir zaman çizelgesi olarak gösterir. Bir oturum için bir değerlendirme çalışırken, o oturum için ek `agent_end` etkinlikleri yoksayılır; çalışan değerlendirme tamamlandıktan sonraki sonraki etkinlik yeni bir değerlendirmeyi normal olarak kuyruğa alacaktır. + +Etkinliksizlik geri dönüşü devam ettirilen oturumlarla da yeniden başlar: önceki bir terminal değerlendirmeden sonra yeni etkinlikler gelirse ve oturum daha sonra `inactivity_timeout_secs` öncesinde boşta kalırsa, yeni bir değerlendirme kuyruğa alınır. + +Geçici arızalar (5xx, 429, zaman aşımları, ağ hataları) `EVALUATOR_MAX_ATTEMPTS` kadar katlanarak artan geri alma ile yeniden denenilir; 4xx yanıtları terminaldir. AgentEye birden çok yatay olarak ölçeklendirilmiş sunucu örnekleriyle çalıştırmak için güvenlidir; iş bölümlendirilir, böylece aynı oturum asla eşzamanlı olarak iki kez gönderilmez. + +--- + +## HTTP sözleşmesi + +Kimliği doğrulanmış her rota **bearer token kimlik doğrulaması** kullanır. Her iki tarafta da aynı değer yapılandırılmalıdır: + +- AgentEye sunucusu: ortam değişkeni `EVALUATOR_TOKEN` +- Değerlendirici hizmeti: aynı şekilde yapılandırılmış (`agenteye-evaluator` SDK'sı kural gereği `EVALUATOR_TOKEN` okur) + +`EVALUATOR_TOKEN` ayarlanmamışsa, sunucu hiçbir `Authorization` başlığı göndermez; değerlendirici daha sonra anonim istekleri kabul edebilir, bu da yalnızca dahili ağ için iyidir ancak genel internet üzerinde önerilmez. + +### Değerlendircinin sunması gereken rotalar + +| Rota | Gövde / parametreler | Yanıt | +|---|---|---| +| `GET /health` | hiçbiri | `{"status":"ok"}` (açık, kimlik doğrulaması yok) | +| `GET /config` | hiçbiri | `{"inactivity_timeout_secs": \| null, "default_poll_interval_secs": \| atlanmış}` | +| `POST /evaluate` | `EvalRequest` JSON | `{"status":"done", ...}` veya `{"status":"pending", "job_id":"..."}` | +| `GET /evaluate/{id}` | hiçbiri | `/evaluate` ile aynı yanıt şekli | + +### Sunucu tarafından gönderilen `EvalRequest` gövdesi + +```json +{ + "schema_version": "1", + "session_id": "session-abc123", + "agent_id": "planner", + "environment": "production", + "started_at": "2026-05-10T12:00:00Z", + "ended_at": "2026-05-10T12:05:00Z", + "events": [ + { "id": 1234, "ts": "...", "event_type": "agent_start", "payload": { ... } }, + ... + ] +} +``` + +### Yanıt şekilleri + +**Senkron (done):** + +```json +{ + "status": "done", + "scores": { "helpfulness": 0.85, "tool_efficiency": 0.6 }, + "reasoning": { + "helpfulness": "answered the question directly with citations", + "tool_efficiency": "called list_files three times when one would have done" + }, + "summary": "strong answer quality, weak tool selection" +} +``` + +`reasoning` (puan başına gerekçelendirme haritası) ve `summary` (genel bir paragraf anlatısı) her ikisi de isteğe bağlıdır. `reasoning` içindeki anahtarlar `scores` içindeki anahtarları yansıtmalıdır; panel her girdiyi skor çubuğunun altında satır içinde gösterir. Yalnızca `scores` döndüren eski değerlendirciler değiştirilmeden çalışmaya devam eder; `reasoning` ve `summary` basitçe null olarak okunur ve karşılık gelen UI olanakları atlanır. + +**Zaman uyumsuz (erteleme):** + +```json +{ "status": "pending", "job_id": "abc-123", "next_poll_secs": 30 } +``` + +`next_poll_secs` isteğe bağlıdır; atlanırsa sunucu değerlendircinin `/config` yanıtından `default_poll_interval_secs` seçeneğini daha sonra kendi `EVALUATOR_POLLING_INTERVAL_SECS` ortam değişkenini kullanır. + +**Terminal değerlendirici tarafı hatası:** + +```json +{ "status": "error", "error": "model service unavailable" } +``` + +Sunucu diğer 2xx gövdesini protokol hatası olarak behandle eder ve oturum için terminal bir `error` kaydeder. + +--- + +## SDK ile değerlendirici yazma + +`agenteye-evaluator` Python paketi, yukarıdaki HTTP sözleşmesini uygulayan yazılı bir FastAPI sarmalayıcı sağlar. PyPI'den kurun: + +```bash +pip install agenteye-evaluator +``` + +Minimum uygulanabilir değerlendirici: + +```python +import os +from agenteye_evaluator import Evaluator, EvalRequest, EvalResponse + +app = Evaluator(token=os.environ["EVALUATOR_TOKEN"]) + +@app.evaluator +def run(req: EvalRequest) -> EvalResponse: + # Inspect req.events (the full session transcript) and return scores. + tool_calls = sum(1 for e in req.events if e.event_type == "tool_use") + return EvalResponse( + scores={"tool_calls": float(tool_calls)}, + reasoning={"tool_calls": f"{tool_calls} tool invocations in the transcript"}, + summary="tight tool loop" if tool_calls < 5 else "agent looped on tools", + ) +``` + +`app` örneği ASGI çağrılabilirdir, bu nedenle `uvicorn module:app` onu çalıştırır. + +Pahalı işi erteleme gerektiren değerlendirciler için, bunun yerine `JobPending` döndürün ve bir `@app.job_lookup` işleyiciyi kaydedin; AgentEye sunucusu terminal bir durum döndürülene veya `EVALUATOR_MAX_POLL_DURATION_SECS` sınırına (varsayılan 1 h) kadar ulaşılana kadar `GET /evaluate/{job_id}` yoklaması yapar. + +Tam API referansı, zaman uyumsuz desen ve etkinlik şeması: `agenteye-evaluator` +README, [agenteye-enterprise sürümleri sayfasındaki](https://github.com/agenteye-enterprise/releases) her sürüm tarball içinde gemidir veya paketin PyPI sayfasında okuyabilirsiniz. + +--- + +## Kubernetes'te değerlendirici çalıştırma + +Değerlendirici **sizin hizmetinizdir**: AgentEye varsayılan bir değerlendirici kapsayıcısı göndermez. Sürüm, `deploy/examples/evaluator/` altında, görüntüyü ve paylaşılan bir bearer token'ı değiştirdikten sonra olduğu gibi uygulayabileceğiniz referans Kubernetes manifestlerini içerir. + +### 1. Değerlendirici uygulamasını konteynırlaştır + +Değerlendirici için minimal bir Dockerfile: + +```dockerfile +FROM python:3.12-slim +WORKDIR /app +RUN pip install --no-cache-dir agenteye-evaluator uvicorn +COPY my_evaluator.py . +RUN useradd --uid 10001 --create-home --shell /usr/sbin/nologin evaluator \ + && chown -R evaluator:evaluator /app +USER evaluator +EXPOSE 9000 +CMD ["uvicorn", "my_evaluator:app", "--host", "0.0.0.0", "--port", "9000"] +``` + +`runAsNonRoot` (UID 10001) kapsayıcıyı Pod Güvenliği kısıtlanmış profilleriyle uyumlu tutar. + +### 2. Paylaşılan bearer token oluştur + +```bash +kubectl -n agenteye create secret generic evaluator-token \ + --from-literal=token="$(openssl rand -hex 32)" +``` + +AgentEye sunucusunda `EVALUATOR_TOKEN` olarak aynı değeri kullanın. Sunucu her istekte `Authorization: Bearer ` gönderir; SDK sabit zamanlı bir kontrol için `hmac.compare_digest` kullanır ve uyuşmazlıkları HTTP 401 ile reddeder. + +### 3. Örnek manifestleri uygula + +```bash +# Önce deploy/examples/evaluator/deployment.yaml dosyasını düzenleyin +# `image:` değerini kayıt defterinize gösterecek şekilde ayarlayın, sonra: +kubectl apply -k deploy/examples/evaluator/ +``` + +Örnek şunları içerir: + +- `runAsNonRoot` ile 2 çoğaltmalı Deployment, salt okunur kök dosya sistemi, + tüm yetkileri bırakılmış, `/health` üzerinde canlılık + hazırlık +- 9000 numaralı bağlantı noktasında ClusterIP Hizmeti +- `secret.example.yaml` şablonu (kasıtlı olarak Kustomization'tan hariç; gerçek sırrı + bant dışı oluşturun, böylece hiçbir token git'e girmez) + +### 4. AgentEye'ı buna bağla + +AgentEye sunucusunda şunları ayarlayın: + +```bash +EVALUATOR_ENDPOINT=http://evaluator:9000 +EVALUATOR_TOKEN= +``` + +Sunucu `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH` +eşzamanlı istekleri tüm değerlendirici pod'ları arasında dağıtır (varsayılanlar: `2 × 4 = 8`). +Bu sunucu tarafı kontrolleriyle birlikte `replicas` ve pod başına kaynak sınırlarını ölçeklendirin. + +### Doğrulama + +```bash +kubectl -n agenteye port-forward svc/evaluator 9000:9000 +curl -s http://localhost:9000/health # → {"status":"ok"} +``` + +Bir ajan uçtan uca çalıştırıldıktan sonra, AgentEye sunucusundaki `GET /evaluations` değerlendirici tarafından üretilen puanlarla birlikte `status: "done"` içeren bir satır döndürmelidir. + +--- + +## AgentEye sunucusunu yapılandırma + +Sunucu işleminde ayarlayın: + +| Ortam değişkeni | Anlamı | +|---|---| +| `EVALUATOR_ENDPOINT` | Değerlendirici temel URL'si (`http://evaluator:9000`). Ayarlanmamış = işlem hattı devre dışı. | +| `EVALUATOR_TOKEN` | Bearer token. Değerlendirici hizmetinin yapılandırıldığı değerle eşleşmelidir. | +| `EVALUATOR_WORKERS` | Sunucu örneği başına çalışan görevleri (varsayılan 2). | +| `EVALUATOR_CLAIM_BATCH` | Çalışan işaretlemesi başına talep edilen satırlar (varsayılan 4). Toplu işler **eşzamanlı** olarak işlenir; değerlendirici uç noktasındaki etkin eşzamanlılık `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH`. | +| `EVALUATOR_POLL_IDLE_SECS` | Hiçbir değerlendirme yapılması gerekmediğinde çalışanın gönderim denemeleri arasında uyuması gereken süre (varsayılan 2s). | +| `EVALUATOR_POLLING_INTERVAL_SECS` | `GET /evaluate/{id}` temposu için nihai geri dönüş, ne yanıt başına `next_poll_secs` ne de değerlendircinin `default_poll_interval_secs` ayarlandığında (varsayılan 10s). | +| `EVALUATOR_REQUEST_TIMEOUT_MS` | İstek başına zaman aşımı (varsayılan 30000). | +| `EVALUATOR_MAX_ATTEMPTS` | Bu kadar geçici başarısızlıktan sonra sonuç terminal `error` olarak kaydedilir (varsayılan 5). | +| `EVALUATOR_CONFIG_REFRESH_SECS` | `GET /config` temposu (varsayılan 300). | +| `EVALUATOR_MAX_POLL_DURATION_SECS` | Bir oturumun yoklama kuyruğunda kalabileceği maksimum duvar saati süresi, bundan sonra `timeout` olarak sonlandırılır (varsayılan 3600s). Değerlendircinin sonsuza kadar `pending` döndürdüğünü korur. | + +Tüm örnek arasında otomatik puanlamayı etkinleştirmek için `agenteye-evaluator` Secret'ini her iki anahtar kümesiyle sağlayın. Paketlenmiş Kubernetes manifestlerinde, sunucu bu isteğe bağlı Secret'ten `EVALUATOR_ENDPOINT` ve `EVALUATOR_TOKEN` okur. Kuruluşunuzun standart gizli yönetim süreci aracılığıyla oluşturun, ardından değişikliği alması için sunucu Deployment'ını yeniden başlatın. + +Yukarıdaki ayar düğmeleri varsayılan olarak bağlanmaz; varsayılanları geçersiz kılmanız gerekirse Deployment manifestinde sunucu kapsayıcısında karşılık gelen ortam değişkenlerini gösterin. + +Tam ortam değişkeni tablosu için [deployment.md](/tr/agenteye/deployment) sayfasını görün. + +--- + +## API referansı + +| Yöntem | Yol | Gerekli izin | Amaç | +|---|---|---|---| +| `GET` | `/evaluations` | `evaluations:read` | Terminal sonuçları sorgula. `session_id`, `agent_id`, `environment`, `status` (`done`/`error`/`timeout`), `ts_from`, `ts_to`, `cursor`, `limit`, `score_filters`, `latest_per_session` seçeneğini destekler. `limit` varsayılan olarak 50 ve 200 ile sınırlandırılmıştır (`/events` ile farklı olarak 1000 ile sınırlandırılır). `environment` virgülle ayrılmış bir liste kabul eder (örneğin `environment=prod,staging`); tek değerler yine de çalışır. `latest_per_session=true` ile yanıt `session_id` başına en fazla bir satır içerir (`completed_at` ile en son), oturumun değerlendirme zaman çizelgesini mevcut başlığına daraltmak için oturumlar listesi sayfası tarafından kullanılır. Varsayılan false (tam geçmişi döndürür). | +| `GET` | `/evaluations/aggregate` | `evaluations:read` | Filtrelenmiş bir dilim için yuvarlanmış eval sağlığı: toplam sayı, done/error/timeout dökümü, puan anahtarı başına istatistikler (keyfi `scores` anahtarları üzerinde sayı/ortalama/min/maks/p50) ve zaman dilimi zaman çizelgesi. **/evaluations** ile aynı filtre parametrelerini artı `featured_keys` (trend için skor anahtarı CSV'si) ve `latest_per_session` kabul eder. Panolar özelliğini güçlendirir; metrikler tam eşleşen küme üzerinde tam olmalı, örneklenmiş değil. | +| `GET` | `/evaluations/environments` | `evaluations:read` | `evaluations` tablosundan farklı ortam değerleri. Değerlendirme tarafından okunabilir verilere kapsamlı filtre açılır menülerini doldurmak için kullanılır. | +| `GET` | `/evaluation-jobs` | `evaluations:read` | Uçuştaki değerlendirmelere görünürlük. `status` (`pending`/`polling`) ile filtreleyin. | +| `GET` | `/events` | `events:read` | Bir oturumun ham etkinliklerini akış. `session_id`, `agent_id`, `event_type` (CSV), `environment` (CSV), `ts_from`, `ts_to`, `cursor`, `limit` ve `order` seçeneğini destekler. `order` `desc` (yeniden sıralı, varsayılan) veya `asc` (en eski birinci); tanınmayan bir değer `desc` seçeneğine geri döner. Yanıtın `next_cursor` (bir etkinlik kimliği) aracılığıyla imleci sayfalandırın: sonraki sayfa almak için onu `cursor` olarak geri geçirin; `asc` ile sonraki sayfa bu kimliğin sonraki etkinlikleridir, `desc` ile bu kimlikten önceki etkinliklerdir. `limit` varsayılan olarak 50 ve 1000 ile sınırlandırılmıştır. | +| `GET` | `/sessions/:session_id/export` | `events:read` | Değerlendirici bu oturum için alacağı tam JSON gövdesini döndürür, `session-.json` adlı indirilebilir bir ek olarak sunulur. Üretim oturumlarını çevrimdışı test için `agenteye-evaluator` aracılığıyla yeniden oynatmak için kullanışlı. Baytlar, değerlendirici işlem hattının gönderdiği bayt-özdeştir. | +| `POST` | `/sessions/:session_id/re-evaluate` | `evaluations:trigger` | Bir oturum için yeni bir değerlendirmeyi kuyruğa al; daha önce bir değerlendirme var mı yoksa yok mu yapılır. Yeni sonuç, önceki puanların tarih olarak görünür kalması için önceki sonucu geçersiz kılmak yerine oturumun değerlendirme zaman çizelgesine **eklenir**. Kuyruğa alma'da `202`, bilinmeyen oturum için `404`, bir değerlendirme zaten uçuşta ise `409` döndürür. Yeni bir değerlendirici dağıtıldıktan sonra veya hiçbir zaman `agent_end` yayan olmayan oturumlar için kullanın. | + +### Skor aralığında filtreleme: `score_filters` + +`GET /evaluations`, `scores` nesnesi içindeki sayısal değerlere göre sonuçları daraltacak isteğe bağlı bir `score_filters` parametresini kabul eder. Parametresi, virgülle ayrılmış `key:min..max` girdilerinin bir listesidir; her sınır atlanabilir. Birden çok giriş mantıksal AND ile birleşir. Adlandırılmış anahtarın bulunmadığı veya sayısal olmayan satırlar hariç tutulur. İstek en fazla 20 filtre girişi taşıyabilir; bunun aşılması HTTP 400 döndürür. + +Örnekler: +```text +# helpfulness in [0.5, 0.8] +GET /evaluations?score_filters=helpfulness:0.5..0.8 + +# tool_efficiency at most 0.3 (no lower bound) +GET /evaluations?score_filters=tool_efficiency:..0.3 + +# helpfulness >= 0.5 AND factuality >= 0.9 +GET /evaluations?score_filters=helpfulness:0.5..,factuality:0.9.. +``` + +Her `/evaluations` yanıt nesnesi şu alanlara sahiptir: + +| Alan | Tür | Notlar | +|---|---|---| +| `evaluation_id` | string (UUID) | Bu terminal değerlendirme için kanonik tanımlayıcı. Her terminal değerlendirme yeni bir UUID alır; tek bir oturum birden fazla tutabilir. | +| `id` | string (UUID) | `evaluation_id` ile aynı değeri taşıyan geriye dönük uyumluluk takma adı. | +| `session_id` | string | Bu değerlendirmenin çalıştığı oturum. Bir oturum zaman çizelgesinde birden fazla değerlendirmeye sahip olabilir. | +| `agent_id` | string | Oturumu üretmiş ajanı tanımlar. | +| `environment` | string | Ortam etiketi oturumdan kopyalanır. | +| `status` | enum | `"done"`, `"error"`, `"timeout"` içinden biri. | +| `scores` | object \| null | Değerlendirici tarafından döndürülen puanlar. | +| `reasoning` | object \| null | Değerlendirici tarafından döndürülen isteğe bağlı puan başına gerekçelendirme haritası. Anahtarlar genellikle `scores` içindeki anahtarları yansıtır. Panel her girdiyi skor çubuğunun altında gösterir. | +| `summary` | string \| null | Değerlendirici tarafından döndürülen isteğe bağlı bir paragraf genel anlatısı. Panel bunu puan başına dökümün üstünde değerlendirmenin başlığı olarak gösterir. | +| `error` | string \| null | Yalnızca `"error"` / `"timeout"` üzerinde doldurulur. | +| `attempt_count` | integer | Gönderim denemesi sayısı (≥ 1). | +| `duration_ms` | integer \| null | Son deneşin süresi. | +| `completed_at` | string (ISO 8601 UTC) | Terminal sonuç kaydedildiğinde. Sonuçlar `completed_at` (yeniye birinci) ile sıralanır. | +| `created_at` | string (ISO 8601 UTC) | `completed_at` ile aynı zaman damgasını taşır (yazma sonra semantik). | + +--- + +## İzinler + +| İzin | Vermeler | +|---|---| +| `evaluations:read` | Değerlendirme sonuçlarını listele, panoda puanları görüntüle ve panel sağlık metriklerini yükle. | +| `evaluations:trigger` | `POST /sessions/:session_id/re-evaluate` aracılığıyla bir oturum için değerlendirmeyi manuel olarak kuyruğa al veya panelin yeniden değerlendirme düğmesi. | +| `dashboards:read` | Kayıtlı panoları görüntüle (metriklerini yüklemek için `evaluations:read` da gerekir). | +| `dashboards:write` | Panolar oluştur ve düzenle. | +| `dashboards:delete` | Panoları sil. | + +Önyükleme yöneticisi (`ADMIN_KEY`, `ADMIN_EMAIL`) otomatik olarak bunların tümünü alır. + +--- + +## Sonuçları görüntüleme + +- **`/sessions/`**: etkinlikler zaman çizelgesi + oturumun puanlarını ve gönderim denemesinden herhangi bir hatayı gösteren sağ ray. Anahtarınız `evaluations:trigger` varsa, hiçbir zaman `agent_end` yayan oturumlar için yararlı olan dışa aktarma düğmesinin yanında bir **yeniden değerlendirme** düğmesi görünür veya yeni bir değerlendirici dağıtıldıktan sonra puanları yenileme. Panel yeni sonucu yoklar ve iniş yaptığında sağ rayı günceller. +- **`/sessions`**: filtrelenebilir oturum ızgarası; skor sütunu her oturumun değerlendirme durumunu ve puanlarını bir bakışta gösterir. +- **`/dashboards`**: kayıtlı eval-sağlık görünümleri (aşağıdaki [Panolar](#dashboards) bölümüne bakınız). + +![Oturum başına değerlendirme durumu hapları ve renkle kodlanmış skor rozeti (yararlılık, gerçeklik, araç verimliliği, güvenlik, tutarlılık) ile sessler ızgarası](/agenteye/images/sessions-list.png) + +*Oturumlar ızgarası her çalışmanın değerlendirme durumunu ve puanlarını bir bakışta gösterir; kırmızı/kehribar/yeşil rozetler düşük puanları öne çıkarır.* + +![Sağ rayda değerlendirme puanları ve gönderim durumunu gösteren oturum detayı görünümü](/agenteye/images/session-detail.png) + +*Bir oturum açılarak tam zaman çizelgesi sağ rayda değerlendirme puanları ve herhangi bir gönderici hatası ile birlikte gösterilir.* + +--- + +## Panolar + +**Panolar** sayfası (`/dashboards`) bir değerlendirme filtresi kombinasyonunu adlandırılmış, yeniden kullanılabilir bir görünüm olarak kaydetmenize ve bu dilimin değerlendirmelerinin bir bakışta nasıl yapıldığını izlemenize olanak tanır. Panolar **tüm kuruluşunuz arasında paylaşılır**; `dashboards:read` sahip olan herkes aynı kümeyi görür. + +Her panel şunları sabitler: + +- **Filtreler**: oturumlar sayfası ile aynı denetimler: ortam, durum, + ajan, kayan zaman penceresi ve skor aralığı filtreleri (`key:min..max`). +- **Ekran yapılandırması**: hangi skor anahtarlarının öne çıkarılacağı, yeşil/kehribar/kırmızı + sağlık eşikleri, gösterilecek paneller ve oturum başına en son değerlendirmeyi daraltıp daraltan şey. + +Her kart eşleşen oturumların sayısını, bir done/error/timeout dökümünü, +her öne çıkarılmış puanın ortalamasını ve küçük bir trend sparkline'ını gösterir. Bir panoyu açılarak tam boyut panelleri gösterir; **"oturumları aç"** tam olarak o dilime önceden filtrelenmiş oturumlar sayfasına sizi düşürür. Metrikler sunucu tarafı hesaplanır tam eşleşen küme üzerinde (via `GET /evaluations/aggregate`), bu nedenle sayılar örneklenmiş yerine kesindir. + +![Değerlendirici boyutu başına ortalama skor çubukları, araç tamam-karşı-hata dökümü, en yüksek araçlar ve saatlik olaylar trendi içeren eval-sağlık panosu](/agenteye/images/dashboard-quality.png) + +**İzinler:** görüntüleme `dashboards:read` ve `evaluations:read` ikisini de gerektirir; +oluşturma ve düzenleme `dashboards:write` gerektirir; silme `dashboards:delete` gerektirir. +Önyükleme yöneticisi bunların tümünü otomatik olarak alır. + +--- + +## Sorun giderme + +**Oturumlar var ama hiçbir değerlendirme oluşturulmaz.** Sunucu işleminde `EVALUATOR_ENDPOINT` ayarlandığını, sunucu ve değerlendircinin aynı `EVALUATOR_TOKEN` değerini paylaştığını ve değerlendircinin `/health` uç noktasının sunucudan erişilebilir olduğunu doğrulayın. `EVALUATOR_ENDPOINT` ayarlanmadığında işlem hattı inaktiftir. + +**Uçuştaki değerlendirmeler yığılır.** Uçuştaki kuyruğu görmek için `GET /evaluation-jobs` sorgusunu yapın. Her satırda `attempt_count`, `next_attempt_at` ve `last_error` şekline bakın. Yaygın nedenler: değerlendirici hizmeti erişilemez veya 5xx döndürüyor (geri alma ile yeniden denenilir), yanlış `EVALUATOR_TOKEN` (401 terminaldir) veya süresiz `pending` döndüren zaman uyumsuz bir değerlendirici (aşağıya bakınız). + +**Oturumlar tamamlandı ama terminal değerlendirmesi yok.** `GET /evaluation-jobs?status=polling` sorgusunu yapın; sonuç hala uçuştaki olabilir. +Bir iş `pending` içinde sıkışırsa, sunucu değerlendirciye ulaşmada sorun yaşıyor; değerlendircinin açık olduğunu ve `EVALUATOR_TOKEN` eşleşmesi doğrulayın. + +**Değerlendirciden `HTTP 401: geçersiz bearer token`**. Sunucudaki `EVALUATOR_TOKEN` değerlendirici hizmetinin yapılandırıldığı değerle eşleşmez. Özdeş olmalıdırlar. + +**Zaman uyumsuz değerlendirici sonsuza kadar `pending` döndürür.** Sunucu `GET /evaluate/{job_id}` yoklaması yapıyor terminal bir durum döndürülene veya `EVALUATOR_MAX_POLL_DURATION_SECS` (varsayılan 1 h) kadar ulaşılana kadar. Sınırdan sonra değerlendirme `timeout` olarak kaydedilir ve uçuştaki kuyruktan kaldırılır. Değerlendircinin varsayılandan daha uzun süre meşru olarak ihtiyacı varsa `EVALUATOR_MAX_POLL_DURATION_SECS` yükseltin. \ No newline at end of file diff --git a/docs/tr/agenteye/getting-started.mdx b/docs/tr/agenteye/getting-started.mdx new file mode 100644 index 00000000..f4a9ee29 --- /dev/null +++ b/docs/tr/agenteye/getting-started.mdx @@ -0,0 +1,235 @@ +--- +title: "AgentEye'a Başlarken" +description: "AgentEye'a Başlarken belgelendirmesi." +--- + +Bu kılavuz, tam bir AgentEye kurulumunu adım adım anlatır: sunucuyu ve panoyu dağıtmak, aracı makinesine toplayıcıyı yüklemek ve Python aracı kodunuzu işaretlemek. + +--- + +## AgentEye Nedir? + +AgentEye, **yapay zeka ajanları için kendi altyapınızda çalıştırılan gözlemlenebilirlik ve değerlendirme platformudur**. Ajanlarınızın ne yaptığını — bir çalışmanın her adımını — kaydeder ve tamamlanan her çalışmanın kalitesini otomatik olarak puanlar; böylece ajanlarınızın üretim ortamında nasıl davrandığını görebilir ve kullanıcılarınız sorunları fark etmeden gerilemeyi yakalayabilirsiniz. + +Veriler tek yönde akar: aracı kodunuz **olay**ları **Python SDK** aracılığıyla yayınlar → hafif **toplayıcı** daemon bunları toplu olarak paketler ve **sunucuya** gönderir → olaylar ve analizler **ClickHouse**'da saklanır (kuruluşlar, kullanıcılar, API anahtarları, panolar ve kaydedilmiş sorgular gibi işletimsel durum **Postgres**'de yaşar) → her şeyi **panoda** keşfedersiniz. + +Ne elde edersiniz: + +- **Olaylar** — her aracı çalışmasının ham, adım adım izi (araç çağrıları, model çağrıları, kancalar, hatalar). +- **Oturumlar** — bu olaylar bir satıra toplu halde, her biri **otomatik olarak değerlendirilmiş** ve puanlanmış. +- **Değerlendirmeler** — kendi değerlendirici hizmetleriniz tarafından üretilen kalite puanları; kalite düşüşü manuel inceleme olmadan yüzeye çıkar. +- **Sorgular & panolar** — verileriniz üzerinde kaydedilmiş ClickHouse SQL, paylaşılan, kuruluş kapsamlı panolara grafik halinde yerleştirilmiş. +- **Uyarılar & olaylar** — sizi sayfalayan eşik kuralları (e-posta, Slack, webhook, panoda) artı bunları sınıflandırmak için bir olay iş akışı. +- **CLI & yapay zeka asistanı** — bir terminal istemcisi (`agenteye`) ve panoda düz İngilizce'de soru sormak için bir asistan. + +Tüm bunları kendi altyapınızda çalıştırırsınız — tek bir Docker Compose yığını olarak (bu kılavuz), bir üretim Kubernetes kurulumu olarak veya tek bir ortak konumlandırılmış pod olarak. Bu kılavuzun geri kalanı Compose yığınını baştan sona kurar. + +--- + +## Adım 1: Kimlik Doğrulama + +Tüm AgentEye yapıtları `agenteye-enterprise` GitHub kuruluşundan dağıtılır. Bir kurumsal geliştirici olarak kendi GitHub PAT'ınızı oluşturabilirsiniz. Tam adımlar ve gerekli izinler için [enterprise-docs/github-token.md](/tr/agenteye/github-token) bölümünü izleyin. + +```bash +export AGENTEYE_TOKEN= + +# Docker'ı GHCR'a karşı kimlik doğrulaması yapın +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +--- + +## Adım 2: Sunucuyu ve Panoyu Dağıtın + +Sunucu, toplayıcılardan olayları alır ve bunları sorgulanabilir hale getirir; pano onları keşfettiğiniz yerdir. Alınan olaylar ve analizler ClickHouse'da yaşar (gerekli analitik deposu), Postgres ise kuruluşlar, kullanıcılar, API anahtarları, panolar ve kaydedilmiş sorgular gibi işletimsel durumu tutar. + +**Yayınlanan compose dosyasını indirin:** + +```bash +mkdir -p ./agenteye +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + https://raw.githubusercontent.com/agenteye-enterprise/releases/main/docker-compose.yml \ + -o ./agenteye/docker-compose.yml +cd agenteye +``` + +**Sırlarınızı ayarlayın:** + +Dağıtımın varsayılan `admin` kimlik bilgileriyle çalışmaması için bir `.env` dosyası oluşturun. En az `ADMIN_KEY` ve `POSTGRES_PASSWORD` ayarlayın: + +```bash +POSTGRES_PASSWORD=your-db-password +ADMIN_KEY=your-admin-secret +``` + +Ayrıca `ADMIN_KEY` dosyasını mevcut kabuğunuzda dışa aktarın; böylece sonraki adımlar (ör. Adım 3 `curl`) buna doğrudan başvurabilir: + +```bash +export ADMIN_KEY=your-admin-secret +``` + +**Yığını başlatın:** + +```bash +docker compose up -d +``` + +Bu, gerekli ClickHouse analitik deposu ve isteğe bağlı Redis önbelleği ile sunucu ve panoyu içeren tam yığını başlatır. Sunucunun başlaması için ClickHouse sağlıklı olmalıdır. + +Sunucu şimdi `http://localhost:8080` adresinde ve pano `http://localhost:3000` adresinde dinliyor. + +Üretim dağıtımları için (özel Postgres, TLS, ters proxy), bkz. [enterprise-docs/deployment.md](/tr/agenteye/deployment). + +--- + +## Adım 3: Toplayıcı için bir API Anahtarı Oluşturun + +Her toplayıcı kapsamlı bir API anahtarı ile kimlik doğrulaması yapar. Adım 2'de ayarladığınız `ADMIN_KEY` kullanarak bir tane oluşturun: + +```bash +curl -s -X POST http://localhost:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{"name":"prod-collector","key":"your-collector-secret","permissions":["events:add"]}' +``` + +`key` değerini kendiniz sağlarsınız; Adım 4'teki toplayıcı yapılandırmasında kullanırsınız. Tam anahtar yönetimi için [enterprise-docs/api-keys.md](/tr/agenteye/api-keys) bölümüne bakın. + +--- + +## Adım 4: Toplayıcıyı Yükleyin + +AI ajanlarınızı çalıştıran her makinede toplayıcı daemon'u yükleyin. + +**İkili dosyasını indirin (Linux x86_64):** + +```bash +VERSION=0.0.1-beta.13 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "collector/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-collector-linux-x86_64' +chmod +x agenteye-collector-linux-x86_64 +sudo mv agenteye-collector-linux-x86_64 /usr/local/bin/agenteye-collector +``` + +> Bu, **Linux x86_64** derlemesini indirir. macOS (Apple Silicon veya Intel), Linux arm64 veya Docker / systemd / launchd kurulumu için [collector-installation.md](/tr/agenteye/collector-installation) bölümüne bakın; bu, her platform için indirmeyi listeler — yukarıdaki komut başka bir yerde çalışmayacak olan bir Linux ikilisini yükler. + +**Yapılandırın:** + +```bash +mkdir -p ~/.agenteye +cat > ~/.agenteye/config.json </…`). + +- **Sorgular** (`//queries`): olaylarınız ve değerlendirmelerinizin üzerinde kaydedilmiş, yeniden kullanılabilir sorguların bir kütüphanesinden başlayın (yerleşik ön ayarlar artı kendi sorgualarınız)… + +![Kaydedilmiş sorguların kütüphanesi: yerleşik ön ayarlar ve özel olanlardan oluşan yeniden kullanılabilir sorguların ızgarası](/agenteye/images/queries.png) + + …ardından bir satırda SQL bestecisinde açın ve canlı sonuçlarla ince ayar yapın ve çalıştırın: + +```python +``` + +- **Panolar** (`//dashboards`): sorguları satır, çubuk, alan veya pasta kutucukları olarak paylaşılan, kuruluş genelindeki panolara sabitleyin. + +![Kaydedilmiş sorgulardan oluşturulmuş bir pano: saat başına olaylar satırı, tür başına hatalar çubuğu, gecikme alan grafiği ve model başına token'lar](/agenteye/images/dashboard-fleet.png) + +- **Uyarılar** (`//alerts`): herhangi bir eşiği e-posta, Slack, webhook veya panoda bildiren bir sayfalama kuralına dönüştürün. Bkz. [enterprise-docs/alerts.md](/tr/agenteye/alerts). + +--- + +## Sonraki Adımlar + +- [Dağıtım](/tr/agenteye/deployment): üretim için kilitlenme +- [API Anahtarları](/tr/agenteye/api-keys): erişimi yönetin +- [Sorun Giderme](/tr/agenteye/troubleshooting): sorunları tanılayın \ No newline at end of file diff --git a/docs/tr/agenteye/github-token.mdx b/docs/tr/agenteye/github-token.mdx new file mode 100644 index 00000000..c42ff31e --- /dev/null +++ b/docs/tr/agenteye/github-token.mdx @@ -0,0 +1,133 @@ +--- +--- +title: "GitHub Token Kurulumu" +description: "AgentEye GitHub Token Kurulumu belgelendirmesi." +--- + + +GitHub Personal Access Token (PAT), her AgentEye yapıtının kilidini açan tek kimlik bilgisidir. Bir token ile Docker imajlarını çekebilir, yayın ikili dosyalarını indirebilir ve Python wheel'lerini kurabilirsiniz; bileşen başına giriş ve dolaşan paylaşılan sırlar olmadan. Tüm AgentEye yapıtları `agenteye-enterprise` GitHub kuruluşundan dağıtılır; kuruluşunuza erişim verildiğinde, her geliştirici veya operatör kendi token'ını oluşturur ve döndürür, böylece erişim kişi başına denetlenebilir ve iptal edilebilir kalır. + +Token'ı makine başına bir kez ortam değişkeni ve Docker kimlik bilgisi olarak ayarlayın: + +```bash +export AGENTEYE_TOKEN= +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +> **Kullanıcı adı notu:** GHCR, `docker login` kullanıcı adını yok sayar ve kimlik doğrulamayı tamamen token'dan yapar, bu nedenle boş olmayan herhangi bir değer çalışır. Bu belgeler kısalık için `-u x` kullanır; Kubernetes imaj-çekme sırrı oluşturan dağıtım manifestleri `agenteye-enterprise` gibi daha açıklayıcı bir kullanıcı adı kullanabilir. Her ikisi de kabul edilir. + +--- + +## Seçenek A: Klasik Token (Önerilir) + +Klasik token, AgentEye için en güvenilir seçenektir, çünkü GHCR'nin `docker login` ve imaj çekme akışı klasik token'lar için en geniş, en tutarlı desteğe sahiptir. İhtiyacınız olan her şeyi (imajları çekme ve yayın varlıklarını indirme) kapsayan iki kapsam vardır, bu nedenle bir kez kimlik doğrulama yaparsınız ve kayıt defteri sorunlarını gidermeden devam edersiniz. Bunlardan biri olan `read:packages`, gerçekten salt okunurdur; diğeri olan `repo`, özel yayın varlıklarına erişim sağlayan tek klasik kapsamdır ve kasıtlı olarak geniştir — GitHub bunu özel depolar üzerinde tam kontrol (okuma ve yazma) olarak tanımlar. + +### 1. Token'ı oluşturun + +**GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic) → Generate new token (classic)** bölümüne gidin. + +| Alan | Değer | +|---|---| +| **Note** | `agenteye-` (örn. `agenteye-prod-server`) | +| **Expiration** | Güvenlik politikanız için uygun bir son kullanma tarihi belirleyin; 90 gün makul bir varsayılandır | + +> **Etiket notu:** GitHub bu alanı klasik token'lar için **Note** olarak etiketler ve ince taneli token'lar için **Token name** olarak etiketler. Aynı amaca hizmet ederler: daha sonraki denetim ve iptal için okunabilir bir tanımlayıcı. + +### 2. Kapsamları seçin + +| Kapsam | Neden gerekli | +|---|---| +| `read:packages` | `ghcr.io/agenteye-enterprise/` adresinden Docker imajlarını çekin ve paket varlıklarını indirin | +| `repo` | `agenteye-enterprise/releases` adresinden özel depo içeriğini, ham dosyaları ve yayın varlıklarını okuyun. Bu, GitHub'ın geniş kapsamlı "Özel depolar üzerinde tam kontrol" kapsamıdır (okuma ve yazma), salt okunur bir kapsam değildir — bu, özel yayın varlıklarına erişim sağlayan tek klasik kapsamdır | + +Başka hiçbir kapsam gerekli değildir. + +### 3. Token'ı oluşturun ve kopyalayın + +**Generate token** öğesine tıklayın ve değeri hemen kopyalayın; yalnızca bir kez gösterilir. Bunu gizli yöneticinizde veya ortamınızda saklayın. + +--- + +## Seçenek B: İnce Taneli Token + +İnce taneli token'lar erişimi belirli depolara ve izinlere kapsama alarak, en az ayrıcalık seçeneğini sunar. Kuruluşunuzun güvenlik politikası ince taneli token'ları zorunlu kıldığında bu yolu seçin. + +> **Not:** İnce taneli token'lar için GHCR desteği klasik token'lardan daha az tutarlıdır. Bu adımları izledikten sonra `docker login` veya `docker pull` başarısız olursa, klasik bir token'a (Seçenek A) geri dönün. + +### 1. Token'ı oluşturun + +**GitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokens → Generate new token** bölümüne gidin. + +| Alan | Değer | +|---|---| +| **Token name** | `agenteye-` (örn. `agenteye-prod-server`) | +| **Expiration** | Güvenlik politikanız için uygun bir son kullanma tarihi belirleyin; 90 gün makul bir varsayılandır | +| **Resource owner** | `agenteye-enterprise` | +| **Repository access** | **Only select repositories** → `agenteye-enterprise/releases` | + +### 2. Depo izinlerini ayarlayın + +**Permissions → Repository permissions** altında şunları ayarlayın: + +| İzin | Erişim | +|---|---| +| **Contents** | Salt okunur | +| **Packages** | Salt okunur | + +Diğer tüm izinler **No access** olarak kalabilir. + +> **Not:** Konteyner imajları (`ghcr.io/agenteye-enterprise/...`) kuruluş düzeyinde paket olarak yayınlanıyorsa, depo bağlantılı paketler değil, depo kapsamlı izinlerle Docker girişi başarısız olabilir. Bu durumda, kuruluş düzeyinde izin ekleyin: **Permissions → Organization permissions → Packages: Read-only**. + +### 3. Her izin ne sağlar + +| İzin | Kullanıldığı yer | +|---|---| +| Contents: Salt okunur | `agenteye-enterprise/releases` adresinden `docker-compose.yml`, yayın ikili dosyaları ve Python wheel'lerini indirme | +| Packages: Salt okunur | `ghcr.io/agenteye-enterprise/` adresinden Docker imajlarını çekme | + +### 4. Token'ı oluşturun ve kopyalayın + +**Generate token** öğesine tıklayın ve değeri hemen kopyalayın; yalnızca bir kez gösterilir. Bunu gizli yöneticinizde veya ortamınızda saklayın. + +--- + +## Token'ı Döndürme + +Token'ları belirli aralıklarla döndürmek, erişimi denetlenebilir tutar ve kimlik bilgisi sızarsa oluşacak hasarı sınırlar. Token'lar ayrıca herhangi bir zamanda sona erebilir veya iptal edilebilir, bu nedenle döndürme, kimlik doğrulama durumunun iyi kalması için rutin bir yoldur. Döndürmek için: + +1. Yukarıdaki adımları kullanarak yeni bir token oluşturun. +2. Ortamınız veya gizli yöneticinizde `AGENTEYE_TOKEN` öğesini güncelleyin. +3. Docker'ı yeniden kimlik doğrulayın: `echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin` +4. **GitHub → Settings → Developer settings → Personal access tokens** adresinde eski token'ı iptal edin, ardından token'ın türüyle eşleşen **Tokens (classic)** veya **Fine-grained tokens** alt sayfasını açın ve silin. + +--- + +## Token'ınızı Doğrulayın + +Dağıtıma entegre etmeden önce token'ın çalıştığını onaylayın, böylece kimlik doğrulama hataları burada ortaya çıkar, dağıtım ortasında değil. Her komut yukarıdaki kapsamlardan birini kullanır: + +```bash +# Packages scope - authenticate Docker against GHCR +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin + +# Contents scope - fetch a raw release file +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + https://raw.githubusercontent.com/agenteye-enterprise/releases/main/docker-compose.yml \ + -o /tmp/agenteye-compose-check.yml +``` + +Başarılı bir `docker login`, paket kapsamını onaylar; indirilen bir dosya, içerik kapsamını onaylar. + +--- + +## Sorun Giderme + +| Belirti | Olası neden | Çözüm | +|---|---|---| +| `docker login` 401 döndürür | Token eksik `Packages: Read-only` (ince taneli) veya `read:packages` (klasik) | Paket kapsamını ekleyin ve yeniden oluşturun | +| `curl` ham GitHub URL'lerinde 404 döndürür | Token eksik `Contents: Read-only` veya `repo` kapsamı | İçerik kapsamını ekleyin ve yeniden oluşturun | +| `gh release download` 403 döndürür | Token `agenteye-enterprise/releases` için yetkilendirilmemiş | Deponun ince taneli token'ın depo erişimine dahil olduğunu doğrulayın veya `repo` kapsamıyla klasik bir token kullanın | +| Token kabul edildi ancak imajlar bulunamadı | İnce taneli token'da kuruluş düzeyinde paket izni eksik | Kuruluş düzeyinde `Packages: Read-only` izni ekleyin | + +Erişim sorunları için `support@exosphere.host` ile iletişime geçin. \ No newline at end of file diff --git a/docs/tr/agenteye/health-monitoring.mdx b/docs/tr/agenteye/health-monitoring.mdx new file mode 100644 index 00000000..526d8978 --- /dev/null +++ b/docs/tr/agenteye/health-monitoring.mdx @@ -0,0 +1,122 @@ +--- +title: "Sistem Durumu İzleme" +description: "AgentEye Sistem Durumu İzleme belgeleri." +--- + + +AgentEye dağıtımının **kendisinin** aşağı olduğunu veya bozulmuş olduğunu bilin; yalnızca +aracılarınızın kötü davranışını değil. Algılama **Kubernetes'e özgüdür** ve önemlisi, +**AgentEye'den bağımsızdır**: Kubernetes kontrol düzleminden pod durumunu okur ve +AgentEye'ın sabit bağımlılıklarını kontrol eder; bu sayede sunucu, ClickHouse veya Postgres +aşağı olduğunda bile uyarı tetiklenir. + +İki katman vardır. Birincisi yerleşiktir; ikincisi seçmeli kullanım olanağı sunar. + +## 1. Bağımlılık farkında hazırlık durumu (yerleşik) + +Sunucu, kasıtlı olarak farklı görevlere sahip iki araştırma uç noktasını ortaya koymaktadır: + +| Uç Nokta | Araştırma | Kontroller | Yetkilendirme | +|---|---|---|---| +| `GET /health` | liveness | süreç canlı (her zaman `{"status":"ok"}`) | yok | +| `GET /ready` | readiness | gerçekten sunabilir: **Postgres + ClickHouse** erişilebilir | yok | + +`/ready`, her iki sabit bağımlılık da erişilebilir olduğunda `200` ve `"status":"ready"` ile +her kontrol `"ok"` olarak döner; biri erişilemez olduğunda `503` ve `"status":"not_ready"` ile +döner. Her iki yanıt da küçük bir gövde içerir: + +```json +{ "status": "not_ready", + "checks": { "postgres": "ok", "clickhouse": "down", "redis": "not_configured" } } +``` + +Redis, sunucunun geçtiği isteğe bağlı bir önbellektir; bu nedenle bilgi için raporlanır ancak +hazırlık durumunu **asla** başarısız kılamaz. Bir önbellek yapılandırıldığında `"ok"` olarak +gösterilir; aksi takdirde `"not_configured"` olarak gösterilir; hiçbir zaman `"down"` değildir. + +Paketlenmiş Kubernetes bildirimlerinde **readiness** araştırması `/ready` konumuna işaret eder +ve **liveness** `/health` konumunda kalır. Etki: veritabanına ulaşamayan ancak çalışan bir sunucu, +Service'ten çıkartılır ve `NotReady` olarak gösterilir; bu durum küme izlemenizin (aşağıya bakınız) +uyarı verebileceği bir durumdur; liveness ucuz kalır, böylece kısa bir bağımlılık sorunu asla pod +yeniden başlatmasını tetiklemez. Araştırma, anında bir soruna yanıt vermesi için cömert bir +başarısızlık eşiği kullanır. + +## 2. Robusta ile pod hatası uyarısı (seçmeli) + +[Robusta](https://github.com/robusta-dev/robusta), API sunucusunu izleyen ve pod hatalarını +(`CrashLoopBackOff`, `OOMKilled`, `ImagePullBackOff`, `Pending`/`NotReady`, `Failed`, tahliyeler) +Slack'e gönderen Kubernetes'e özgü bir izleme aracıdır. Kontrol düzlemini izlediği için +AgentEye'a sorgulamadığından, AgentEye hiç sunulamadığında bile uyarı verir. + +Robusta, sürüm paketinde seçmeli bir eklenti olarak gönderilir. Standart Robusta Helm grafiği +ve aşağıda gösterilen küçük değerler dosyasıyla etkinleştirin: + +1. Grafik deposunu ekleyin ve kanal için bir Slack **bot token**ı (`xoxb-…`) alın: + + ```bash + helm repo add robusta https://robusta-charts.storage.googleapis.com + helm repo update + ``` + + Aşağıdaki yapılandırma her şeyi küme içinde tutar (`disableCloudRouting: true`), + token kendi kendine barındırılan bir Slack uygulamasından gelir: `https://api.slack.com/apps` + adresinde bir uygulama oluşturun, `chat:write` bot kapsamını ekleyin, çalışma alanına yükleyin, + **Bot User OAuth Token**ı (`xoxb-…`) kopyalayın ve botu kanala davet edin (`/invite @your-app`). + +2. Dağıtım başına etiket (`clusterName`) ve Slack kanalınız ile `agenteye` ad alanına + kapsamlı `values.yaml` oluşturun: + + ```yaml + clusterName: "acme-prod" # dağıtım başına etiket; her uyarıda görünür + enablePrometheusStack: false # yalnızca pod kilitlenme uyarıları; metrik yığını yok + disableCloudRouting: true # Slack'e doğrudan teslim et, küme içinde + sinksConfig: + - slack_sink: + name: vendor_slack + slack_channel: "agenteye-fleet-health" + api_key: "REPLACE_WITH_SLACK_BOT_TOKEN" # xoxb-… (--set veya gizli anahtar tercih et) + scope: + include: + - namespace: [agenteye] # yalnızca AgentEye ad alanı uyarıları; genişletmek için kaldır + ``` + +3. Yükleme, `--version` öğesini bilinen iyi Robusta grafik sürümüne sabitle + ([sürümler](https://github.com/robusta-dev/robusta/releases)) böylece test edilmemiş bir + grafik hiçbir zaman yüklenmez: + + ```bash + helm install robusta robusta/robusta \ + --namespace robusta --create-namespace \ + --version \ + -f values.yaml \ + --set sinksConfig[0].slack_sink.api_key=$ROBUSTA_SLACK_TOKEN + ``` + +### Raporlanılan İçerik + +- Kubernetes **pod durumu** (hangi AgentEye podunun başarısız olduğu ve neden) ve her podun + **görüntü etiketi**, yani çalışan bileşen **sürümü**. +- **AgentEye olay verisi ve müşteri verisi yok** kümeyi asla terk etmez. +- Paketlenmiş değerler uyarıları **`agenteye` ad alanı** ile sınırlandırır; bu nedenle + aynı kümedeki ilişkisiz iş yükleri raporlanmaz. + +### Her dağıtım için bir yer + +Her dağıtımın Robusta'sını **bir paylaşılan Slack kanalına** işaret edin; her biri +kendi `clusterName` değerine sahiptir. Her uyarı bu etiketle etiketlenir; bu nedenle +tek bir kanal tüm filonuzun durumunu gösterir ve etkilenen dağıtımı bakışta belirleyebilirsiniz. + +### Tüm küme kesintileri + +Tamamen küme içi bir izleme aracı, **tüm küme veya ağ kesintisini** bildiremez +(kümeyle birlikte aşağı iner). Buna ihtiyacınız varsa isteğe bağlı **Robusta +UI sink** öğesini etkinleştirin: `disableCloudRouting: false` ayarlayın ve +`robusta gen-config` adresinden token içeren bir `robusta_sink` öğesini +`sinksConfig` öğesine ekleyin. Toplu çok kümeli pano ve kontrol etmeyi bırakan +kümeyi işaretleyen seçenekler ekler. + +## Sorun Giderme + +[enterprise-docs/troubleshooting.md](/tr/agenteye/troubleshooting) belgesinin +**Sistem Durumu İzleme** bölümüne bakın; "uyarı gelmiyorsa" ve "sunucu `NotReady` +durumunda sürekli tetikleniyor" için çözümleri bulun. \ No newline at end of file diff --git a/docs/tr/agenteye/kubernetes-deployment.mdx b/docs/tr/agenteye/kubernetes-deployment.mdx new file mode 100644 index 00000000..4ec48516 --- /dev/null +++ b/docs/tr/agenteye/kubernetes-deployment.mdx @@ -0,0 +1,913 @@ +--- +title: "Kubernetes Dağıtım Kılavuzu" +description: "AgentEye Kubernetes Dağıtım Kılavuzu belgeleri." +--- + + +Bu kılavuz, tam AgentEye yığınını adanmış bir Kubernetes kümesine dağıtır: + +- **ClickHouse 24.8** -- kanonik olaylar ve değerlendirmeler analitikleri depolama (100 GiB kalıcı birimli StatefulSet). Gerekli: sunucu bunu olmadan başlamayı reddeder. +- **PostgreSQL 16** -- kuruluşlar, API anahtarları, kullanıcılar, panolar, kaydedilmiş sorgular ve kimlik doğrulama için ilişkisel/meta veri depolaması (50 GiB kalıcı birimli StatefulSet) +- **Redis 7.2** -- isteğe bağlı paylaşılan önbellek ve hız sınırlama arka ucu; sunucu ve panel kullanılamadığında zarif bir şekilde bozulur +- **AgentEye Sunucusu** -- olay alımı, analitikleri ve anahtar yönetimi için Rust API (2 kopya) +- **AgentEye Paneli** -- Next.js web kullanıcı arayüzü (2 kopya) +- **AI asistanı (ajan hizmeti)** -- isteğe bağlı panel içi salt okunur asistan, 9100 portunda; bir LLM uç noktası yapılandırılana kadar pasif +- **Traefik (genel)** -- toplayıcı trafiği için giriş denetleyicisi, mTLS ile korumalı +- **Traefik (panel)** -- panel için giriş denetleyicisi, yalnızca VPN/IP-izin listesi +- **cert-manager** -- TLS sertifikaları ve mTLS CA +- **Yedekleme CronJob** -- 03:00 UTC'de PostgreSQL + ClickHouse'un günlük birleştirilmiş dökümü +- **Sertifika Yenileme İzleyicisi** -- istemci sertifikaları sona ermek üzereyken uyarı gönderir + +**Tahmini süre:** ilk dağıtım için 60-90 dakika. + +Exosphere'nin tüm bunları sizin adınıza yönettiği yönetilen dağıtım modeli için [enterprise-docs/managed-deployment.md](/tr/agenteye/managed-deployment) bölümüne bakın. + +--- + +## Ön Koşullar + +Başlamadan önce her doğrulama komutunu çalıştırın. Her kontrol başarılı olmalıdır. + +| Gereksinim | Minimum | Doğrulama Komutu | Beklenen Sonuç | +|---|---|---|---| +| Kubernetes kümesi | 1.27+ | `kubectl version` | Server Version >= v1.27 | +| Kustomize (kubectl ile paketlenmiş) | Kustomize v1.14+ (kubectl 1.27+ içinde bulunur) | `kubectl kustomize --help` | Kullanım metni yazdırır | +| Helm | v3 | `helm version` | `Version:"v3.x.x"` | +| cluster-admin RBAC | -- | `kubectl auth can-i create namespaces` | `yes` | +| Varsayılan StorageClass | -- | `kubectl get storageclass` | En az bir satır `(default)` olarak işaretlenmiş | +| LoadBalancer desteği | -- | Buluta bağlı (EKS, GKE, AKS varsayılan olarak bunu destekler) | -- | +| GitHub PAT | -- | `echo $AGENTEYE_TOKEN` | Boş olmayan ([enterprise-docs/github-token.md](/tr/agenteye/github-token) bölümüne bakın) | +| openssl | -- | `openssl version` | OpenSSL 1.x veya 3.x | +| Bulut depolama paketi | -- | PostgreSQL + ClickHouse yedekleri için (S3, GCS veya Azure Blob) | -- | + +**Küme boyutlandırması:** Minimum 3 düğüm, her biri 4 vCPU / 8 GB RAM. Tam gereksinimler için [enterprise-docs/managed-deployment.md](/tr/agenteye/managed-deployment) bölümüne bakın. + +### Tüm kontrolleri aynı anda çalıştırın + +```bash +echo "--- Prerequisites Check ---" +kubectl version --client -o yaml 2>/dev/null | grep -q gitVersion && echo "PASS: kubectl" || echo "FAIL: kubectl not found" +helm version --short 2>/dev/null | grep -q v3 && echo "PASS: helm v3" || echo "FAIL: helm v3 not found" +kubectl auth can-i create namespaces 2>/dev/null | grep -q yes && echo "PASS: cluster-admin" || echo "FAIL: no cluster-admin" +kubectl get storageclass 2>/dev/null | grep -q default && echo "PASS: default StorageClass" || echo "FAIL: no default StorageClass" +[ -n "$AGENTEYE_TOKEN" ] && echo "PASS: AGENTEYE_TOKEN set" || echo "FAIL: AGENTEYE_TOKEN not set" +openssl version >/dev/null 2>&1 && echo "PASS: openssl" || echo "FAIL: openssl not found" +echo "---" +``` + +### Dağıtım şekli + +**Alım uç noktası** kontrol ettiğiniz bir ana bilgisayar adında sunulur (örn. `ingest.your-company.example`). cert-manager, Let's Encrypt'den HTTP-01 üzerinden genel olarak güvenilir bir TLS sertifikası talep eder, bu nedenle toplayıcılar sunucu sertifikasını sistem güven deposuna karşı doğrular ve müşteri başına CA sabitleme yoktur. + +**Panel uç noktası** aynı şekilde çalışır: kontrol ettiğiniz ikinci bir ana bilgisayar adında sunulur (örn. `agenteye.your-company.example`) ve panel Traefik LoadBalancer'ına işaret eder; cert-manager, o LoadBalancer üzerinden Let's Encrypt sertifikasını yayınlar. Tarayıcılar uyarısız güvenilir bir sertifika alır. + +> **Sertifika yayınlama ve yenileme HTTP-01 üzerinden doğrular**, bu nedenle her iki LoadBalancer de genel internetten 80 portu üzerinde erişilebilir olmalıdır. Panel LoadBalancer'ını IP ile kısıtlama yapmanız gerekiyorsa, yenileme sessizce başarısız olmayacağı için öncelikle destek ekibiyle DNS-01 çözücüsü koordine edin ve sertifika sona ermez. + +--- + +## Manifestleri Alın + +```bash +git clone https://x:${AGENTEYE_TOKEN}@github.com/agenteye-enterprise/releases.git +cd releases/deploy +``` + +**Test edin:** + +```bash +ls base/kustomization.yaml +``` + +Beklenen sonuç: dosya var. Yoksa, klonlama başarısız oldu -- `AGENTEYE_TOKEN` öğesini kontrol edin. + +**Dizin yapısı:** + +``` +deploy/ + base/ Paylaşılan Kustomize temeli (tüm K8s kaynakları) + overlays/ Kümeye özgü geçersiz kılmalar (görüntü etiketleri, ana bilgisayar adları, kaynaklar) + third-party/ Traefik, cert-manager ve (opt-in) Robusta sağlık izleme için Helm değerleri +``` + +**Temel**, yapılandırdığınız iki genel ana bilgisayar adı için Let's Encrypt sertifikaları da dahil olmak üzere tam bir dağıtım için gereken her kaynağı içerir. Bir **kaplama**, belirli bir ortam için temeli yamaları (örn. özel görüntü etiketleri, kaynak sınırları, env kablolama). **Üçüncü taraf** dizini harici altyapı için Helm değerleri dosyalarını içerir. + +> **Sağlık izleme (isteğe bağlı):** sunucunun hazırlık sondası zaten Postgres + ClickHouse sağlığını yansıtır ve `third-party/robusta/`, Slack'e opt-in Kubernetes native pod-hata uyarısı ekler. [enterprise-docs/health-monitoring.md](/tr/agenteye/health-monitoring) bölümüne bakın. + +--- + +## Aşama 1 -- Üçüncü Taraf Altyapısı (~30 dk) + +### 1.1 cert-manager'ı kurun + +cert-manager, HTTPS için TLS sertifikalarını ve mTLS istemci sertifikaları için kullanılan özel CA'yı yönetir. + +```bash +helm repo add jetstack https://charts.jetstack.io +helm repo update + +helm install cert-manager jetstack/cert-manager \ + --namespace cert-manager --create-namespace \ + --set crds.install=true +``` + +**Test edin:** + +```bash +kubectl get pods -n cert-manager +``` + +Beklenen sonuç: 3 pod tümü `Running` -- `cert-manager`, `cert-manager-cainjector`, `cert-manager-webhook`. + +```bash +kubectl get crds | grep cert-manager +``` + +Beklenen sonuç: en az `certificates.cert-manager.io`, `clusterissuers.cert-manager.io`, `issuers.cert-manager.io`. + +**Başarısız olursa:** `CrashLoopBackOff` içindeki pod'lar genellikle CRD'lerin yüklenmediği anlamına gelir. `--set crds.install=true` ile yeniden çalıştırın. Webhook pod'ları hazırlık kontrolünde başarısız olursa, 30 saniye bekleyin ve tekrar kontrol edin -- başlamak biraz zaman alabilir. + +--- + +### 1.2 Traefik'i kurun -- Genel Alım Denetleyicisi + +Bu Traefik örneği, **harici** bir LoadBalancer'da toplayıcı trafiğini işler. TLS'yi sonlandırır ve alım uç noktasında mTLS (istemci sertifikası doğrulama) uygular. + +```bash +helm repo add traefik https://traefik.github.io/charts +helm repo update + +helm install traefik-public traefik/traefik \ + --namespace traefik-public --create-namespace \ + --version 39.0.8 \ + -f third-party/traefik/values-public.yaml +``` + +**Test edin:** + +```bash +kubectl get pods -n traefik-public +``` + +Beklenen sonuç: 1 pod `Running`. + +```bash +kubectl get ingressclass traefik-public +``` + +Beklenen sonuç: IngressClass var (varsayılan sınıf değildir). + +**Başarısız olursa:** `kubectl describe pod -n traefik-public ` ile görüntü çekme hataları veya kaynak kısıtlamaları kontrol edin. + +--- + +### 1.3 Traefik'i kurun -- Panel Denetleyicisi + +Bu Traefik örneği, panel'i IP izin listesi ile sınırlandırılmış adanmış bir LoadBalancer'da sunar. + +> **Bu örnek için iki izin listesi mekanizması verilir.** Bu kılavuz `values-dashboard.yaml` kullanır ve erişimi taşınabilir `service.loadBalancerSourceRanges` alanı ile kısıtlar. Parallel `values-internal.yaml` da AWS ortamları için sağlanır ve bunun yerine `service.beta.kubernetes.io/aws-load-balancer-source-ranges` ek açıklamasını tercih eder. Birini seçin ve tutarlı kullanın; aşağıdaki adımlar `values-dashboard.yaml` olduğunu varsayar. + +**Kurmadan önce**, izin verilen kaynak IP'lerini ayarlamak için `third-party/traefik/values-dashboard.yaml` öğesini düzenleyin. `loadBalancerSourceRanges` alanı, hangi IP'lerin panele erişebileceğini kontrol eder. Varsayılan olarak `0.0.0.0/0` (tüm IP'ler) olarak ayarlanır; bunu VPN, ofis veya bilinen çıkış IP'lerinize kısıtlayın. + +#### Tek bir IP'yi izin listesine ekleyin + +```yaml +service: + loadBalancerSourceRanges: + - "/32" +``` + +#### Birden fazla IP'yi izin listesine ekleyin + +Her IP veya CIDR bloğu için bir giriş ekleyin. `/32` soneki tek bir IPv4 adresini eşleştirir; CIDR bloğu (örn. `/24`) bir aralığı eşleştirir. Tek tek IP'leri ve aralıkları serbestçe karıştırabilirsiniz: + +```yaml +service: + loadBalancerSourceRanges: + - "203.0.113.10/32" # office gateway + - "203.0.113.11/32" # backup office gateway + - "198.51.100.0/24" # VPN pool + - "192.0.2.50/32" # on-call engineer home IP +``` + +Listeyi korurken ipuçları: + +- Her satırda bir giriş tutun ve her IP'nin sahibini veya amacını tanımlayan kısa `#` yorumu ekleyin; gelecekteki operatörlerin bir giriş hala gerekli olup olmadığını belirlemek için kullandığı şey budur. +- Her zaman CIDR gösterimini kullanın. `203.0.113.10` gibi çıplak IP, bulut sağlayıcı tarafından reddedilir; `203.0.113.10/32` kullanın. +- IPv6 aralıkları için eşdeğer `/128` (tek adres) veya daha büyük CIDR'ı kullanın, örn. `2001:db8::1/128`. Tüm bulut sağlayıcılar IPv6 kaynak aralıklarını desteklemez; sağlayıcınızın LoadBalancer belgelerine bakın. +- Liste bir **VEYA**'dır: trafik, kaynak herhangi bir giriş ile eşleşirse izin verilir. + +Dosyayı düzenledikten sonra aşağıdaki `helm install` adımına gidin. Denetleyici zaten kuruluysa, aynı bayraklarla `helm upgrade` çalıştırın veya çalışma zamanında Service'i yamalayın (sonraki bölüm). + +#### İzin listesini çalışma zamanında güncelleyin + +Helm yükseltmesi yapıştırmadan, Service'i doğrudan yamalayarak izin verilen IP'leri değiştirebilirsiniz. **Yama tüm listeyi değiştirir**; yalnızca yenisini değil, tutmak istediğiniz her IP'yi dahil edin. + +Listeyi yeni bir IP seti ile değiştirmek için: + +```bash +kubectl patch svc traefik-dashboard -n traefik-dashboard \ + -p '{"spec":{"loadBalancerSourceRanges":["203.0.113.10/32","198.51.100.0/24","192.0.2.50/32"]}}' +``` + +Mevcut girişleri kaybetmeden bir IP'yi güvenli bir şekilde **eklemek** için, önce geçerli listeyi okuyun, sonra birleştirilmiş küme ile yamalayın: + +```bash +# 1. Geçerli izin listesini gösterin +kubectl get svc traefik-dashboard -n traefik-dashboard \ + -o jsonpath='{.spec.loadBalancerSourceRanges}' + +# 2. Yeni IP dahil tam liste ile yamalayın +kubectl patch svc traefik-dashboard -n traefik-dashboard \ + -p '{"spec":{"loadBalancerSourceRanges":["/32","/32","/32"]}}' +``` + +> Çalışma zamanı yamaları `values-dashboard.yaml` öğesine geri kaydedilmez. Değişikliği gelecekteki Helm yükseltmeleri arasında tutmak için değerleri dosyasını da güncelleyin ve işleyin. + +Sonra kurun: + +```bash +helm install traefik-dashboard traefik/traefik \ + --namespace traefik-dashboard --create-namespace \ + --version 39.0.8 \ + -f third-party/traefik/values-dashboard.yaml +``` + +**Test edin:** + +```bash +kubectl get pods -n traefik-dashboard +``` + +Beklenen sonuç: 1 pod `Running`. + +```bash +kubectl get ingressclass traefik-dashboard +``` + +Beklenen sonuç: IngressClass var. + +--- + +### 1.4 LoadBalancer'ları bekleyin + +Devam etmeden önce her iki Traefik örneğinin harici IP'leri olması gerekir. + +```bash +kubectl get svc -n traefik-public +kubectl get svc -n traefik-dashboard +``` + +**Test edin:** Her iki service de `EXTERNAL-IP` gösterir (`` değil). + +Hala beklemede ise, atamayı izleyin: + +```bash +kubectl get svc -n traefik-public -w +``` + +IP göründükten sonra `Ctrl+C` tuşuna basın. IP ataması tipik olarak 2-5 dakika alır. + +**Başarısız olursa:** 10 dakika sonra `` genellikle bulut sağlayıcının LoadBalancer sağlayamadığı anlamına gelir. Kontrol edin: alt ağ etiketleri (EKS `kubernetes.io/role/elb` gerektirir), VPC yapılandırması, hizmet kotaları ve iç LB ek açıklamasının iç örnek için ayarlandığını kontrol edin. + +--- + +## Aşama 2 -- Gizlilikler Oluşturun (~10 dk) + +Tüm gizlilikler, uygulama dağıtılmadan önce el ile oluşturulur. Bu, hassas değerlerin hiçbir zaman manifest dosyalarında görünmemesini sağlar. + +### 2.1 Ad alanını oluşturun + +```bash +kubectl create namespace agenteye +``` + +**Test edin:** + +```bash +kubectl get namespace agenteye +``` + +Beklenen sonuç: durum `Active`. + +--- + +### 2.2 Görüntü çekme gizliliği + +Bu gizlilik, `ghcr.io` ile doğrulama yapar ve AgentEye kapsayıcı görüntülerini çeker. PAT'ınızı nasıl oluşturacağınız hakkında [enterprise-docs/github-token.md](/tr/agenteye/github-token) bölümüne bakın. + +```bash +kubectl create secret docker-registry agenteye-image-pull \ + --namespace agenteye \ + --docker-server=ghcr.io \ + --docker-username=agenteye-enterprise \ + --docker-password="${AGENTEYE_TOKEN}" +``` + +**Test edin:** + +```bash +kubectl get secret agenteye-image-pull -n agenteye -o jsonpath='{.type}' +``` + +Beklenen sonuç: `kubernetes.io/dockerconfigjson`. + +**Test edin (derin)** -- jetonu yapabilir doğrula gerçekten görüntüleri çeker: + +Kaplamanızda `kustomization.yaml` dosyasında sabitlenen `server` görüntü etiketini kullanın (şu anda hem paketlenmiş `acme` kaplamasında hem de temel dağıtımda `v0.0.1-beta.48`). Bu kontrol sürümler arasında kaymaması için aşağıdaki etiketi dağıttığınız etiket ile değiştirin: + +```bash +kubectl run test-pull \ + --image=ghcr.io/agenteye-enterprise/server:v0.0.1-beta.48 \ + --overrides='{"spec":{"imagePullSecrets":[{"name":"agenteye-image-pull"}]}}' \ + --restart=Never -n agenteye --command -- echo ok + +# Çekme için birkaç saniye bekleyin, sonra: +kubectl logs test-pull -n agenteye +kubectl delete pod test-pull -n agenteye +``` + +Beklenen sonuç: günlüklerde `ok` yazdırıldı. + +**Başarısız olursa:** `ErrImagePull` veya `401 Unauthorized` PAT'ın geçersiz olduğu veya `read:packages` kapsamından yoksun olduğu anlamına gelir. [enterprise-docs/github-token.md](/tr/agenteye/github-token) öğesini yeniden kontrol edin. + +--- + +### 2.3 PostgreSQL kimlik bilgileri + +```bash +POSTGRES_PASSWORD=$(openssl rand -hex 24) + +kubectl create secret generic agenteye-postgres \ + --namespace agenteye \ + --from-literal=POSTGRES_USER=postgres \ + --from-literal=POSTGRES_PASSWORD="${POSTGRES_PASSWORD}" \ + --from-literal=POSTGRES_DB=agenteye +``` + +> **Önemli:** `-hex` (değil `-base64`) kullanarak parolayı oluştururuz. Base64 çıkışı `+`, `/` ve `=` içerebilir ve bu da `DATABASE_URL` bağlantı dizesini bozar. Ayrıntılar için [enterprise-docs/troubleshooting.md](/tr/agenteye/troubleshooting) bölümüne bakın. + +> **`POSTGRES_PASSWORD` öğesini hemen gizli yöneticiye depolayin.** Yedekten geri yüklerseniz veya doğrudan veritabanına bağlanırseniz buna ihtiyacınız olur. + +**Test edin:** + +```bash +kubectl get secret agenteye-postgres -n agenteye +``` + +Beklenen sonuç: gizlilik var. + +```bash +kubectl get secret agenteye-postgres -n agenteye \ + -o jsonpath='{.data.POSTGRES_PASSWORD}' | base64 -d | wc -c +``` + +Beklenen sonuç: `48` (24 hex bayt = 48 karakter). + +--- + +### 2.4 Yönetici API anahtarı + +```bash +ADMIN_KEY=$(openssl rand -hex 32) + +kubectl create secret generic agenteye-admin-key \ + --namespace agenteye \ + --from-literal=ADMIN_KEY="${ADMIN_KEY}" +``` + +Yönetici anahtarı bootstrap kimlik bilgisidir. Sunucu, her başlangıçta tüm izinleriyle bunu upsert eder. 3. Aşama'da kapsam alınmış toplayıcı anahtarları oluşturmak için kullanın. Tam izinler modeli için [enterprise-docs/api-keys.md](/tr/agenteye/api-keys) bölümüne bakın. + +> **`ADMIN_KEY` öğesini hemen gizli yöneticiye depolayin.** + +**Test edin:** + +```bash +kubectl get secret agenteye-admin-key -n agenteye +``` + +Beklenen sonuç: gizlilik var. + +--- + +### 2.5 Kimlik doğrulama yapılandırması (panel girişi) + +Panel, kullanıcı girişi için e-posta + OTP kullanır. Bu gizlilik olmadan sunucu hala başlar ve `ADMIN_KEY` API yolu çalışır, ancak **hiçbir kullanıcı UI üzerinden giriş yapamaz**. + +Tüm anahtarlar temel manifestte `optional: true` olarak başvurulur, bu nedenle kısmi gizlilikler (veya hiç gizlilik) iyidir; sunucu belgelenen varsayılanlara geri döner. Her şeyi bir `agenteye-auth` gizliliğine bundleme, yetkilendirme yüzeyinin tek bir yerde döndürülebilir olmasını sağlar. + +```bash +kubectl create secret generic agenteye-auth \ + --namespace agenteye \ + --from-literal=ADMIN_EMAIL="admin@yourcompany.com" \ + --from-literal=ALLOWED_EMAILS="*@yourcompany.com" \ + --from-literal=SMTP_HOST="smtp.yourprovider.com" \ + --from-literal=SMTP_PORT="587" \ + --from-literal=SMTP_USERNAME="your-smtp-user" \ + --from-literal=SMTP_PASSWORD="your-smtp-password" \ + --from-literal=SMTP_FROM="noreply@yourcompany.com" \ + --from-literal=SMTP_TLS="starttls" \ + --from-literal=DEFAULT_ORG_NAME="Acme Corp" \ + --from-literal=DEFAULT_ORG_SLUG="acme" +``` + +| Anahtar | Amaç | +|---|---| +| `ADMIN_EMAIL` | Bootstrap yönetici kullanıcısı. Her başlangıçta tüm izinlerle oluşturulur ve dashboard aracılığıyla silme/izin düzenlemelerinden korunur. Olmadan hiçbir yönetici tohumlanmaz ve ilk giriş imkansızdır. | +| `ALLOWED_EMAILS` | Virgülle ayrılmış izin listesi. Tam adresleri (`user@example.com`) ve alan adı joker karakterlerini (`*@example.com`) destekler. Olmadan **hiçbir kullanıcı giriş yapamaz veya oluşturulamaz**. | +| `SMTP_HOST`, `SMTP_PORT`, `SMTP_USERNAME`, `SMTP_PASSWORD`, `SMTP_FROM` | OTP kodları göndermek için SMTP röle. `SMTP_HOST` ayarlanmazsa, OTP kodları gerçek e-posta teslimatı yerine sunucunun stdout'una kaydedilir (ilk başlangıç sigara testleri için yararlı). Gerçek e-posta teslimi için tüm SMTP anahtarlarını birlikte sağlayın. | +| `SMTP_TLS` | `starttls` (varsayılan), `tls` veya `none` birisi. | +| `DEFAULT_ORG_NAME`, `DEFAULT_ORG_SLUG` | İsteğe bağlı. Yerleşik `default` kuruluşa dostça bir görüntü adı ve URL slug'u verin, böylece örn. `/default` yerine `/acme` adresinde yaşasın. Slug 1-40 küçük harfli alfasayısal ile tek iç tire olmalıdır. Her iki tarafı da ayarlı bırakın jenerik `default` öğesini tutmak için. | + +> **SMTP kimlik bilgilerini gizli yöneticiye depolayin.** + +**Test edin:** + +```bash +kubectl get secret agenteye-auth -n agenteye \ + -o jsonpath='{.data}' | grep -o '"[A_-Z]*"' | sort -u +``` + +Beklenen sonuç: doldurduğunuz anahtarlar çıkışta görünür. + +--- + +### 2.6 Çok kiracılı org izolasyon anahtarı (isteğe bağlı) + +Tek kiracılı bir dağıtım için bunu atlayın; sunucu yerleşik bir geliştirme varsayılanında çalışır ve bir `default` org'u iyiyse sunmaktadır. **İkinci bir kuruluş oluşturmadan önce**, güçlü, kararlı bir `ORG_CH_SECRET` ayarlayın: her org'un ClickHouse parolası `HMAC(ORG_CH_SECRET, org_id)` olarak türetilir, bu nedenle genel olarak bilinen geliştirme varsayılanı genel olarak türetilebilir per-org kimlik bilgileri sağlayacaktır. `agenteye-orgctl org create` komutu ([§7.6 Sağlama kuruluşları](#76-provision-organizations-multi-tenant) bölümüne bakın) sunucu hala yerleşik geliştirme varsayılanında iken çalışmayı reddeder. + +```bash +kubectl create secret generic agenteye-org-ch-secret \ + --namespace agenteye \ + --from-literal=ORG_CH_SECRET="$(openssl rand -base64 48)" + +# Sunucuyu yeniden başlatın, böylece yeni değeri alır. +kubectl -n agenteye rollout restart deployment/server +``` + +Sunucu bunu **isteğe bağlı** bir `secretKeyRef` üzerinden okur, bu nedenle asla oluşturmayan tek kiracılı bir küme hala normal şekilde başlar. **Değeri kararlı ve tüm çoğaltmalar arasında özdeş tutun**; döndürme her org'un türetilmiş ClickHouse parolasını geçersiz kılar ve bu yapı zamanı yeniden sağlanması tüm çoğaltmalar arasında değer tutarlı olduğunda iyileştirir (kararlı bir değerle kayan bir yeniden başlatma işlemi bunu iyileştirir). `deploy/base/server/secret.example.yaml` bölümüne bakın. + +> **`ORG_CH_SECRET` öğesini gizli yöneticiye depolayin ve sırası olmadan döndürmeyin.** + +--- + +### 2.7 Tüm gizlilikleri doğrulayın + +```bash +kubectl get secrets -n agenteye -o custom-columns='NAME:.metadata.name,TYPE:.type' +``` + +Beklenen çıkış (herhangi bir varsayılan gizlilik arasında): + +``` +NAME TYPE +agenteye-admin-key Opaque +agenteye-auth Opaque +agenteye-image-pull kubernetes.io/dockerconfigjson +agenteye-postgres Opaque +agenteye-org-ch-secret Opaque # yalnızca §2.6 (çok kiracılı) tamamladıysanız +``` + +Dört temel gizlilik (`agenteye-admin-key`, `agenteye-auth`, `agenteye-image-pull`, `agenteye-postgres`) devam etmeden önce mevcut olmalıdır. `agenteye-org-ch-secret` yalnızca çok kiracılı dağıtımlar için gereklidir (bkz. §2.6). + +--- + +## Aşama 3 -- Uygulamayı Dağıtın (~5 dk) + +### 3.1 Genel ana bilgisayar adlarını yapılandırın + +cert-manager, Let's Encrypt sertifikalarını istemeden önce alım ve panel ana bilgisayar adlarına ihtiyaç duyar. Şablonu kopyalayın ve her ikisini ayarlayın: + +```bash +cp base/certificates/domain.env.example base/certificates/domain.env +# base/certificates/domain.env adresini düzenleyin ve ayarlayın: +# INGEST_DOMAIN=ingest.your-company.example (genel Traefik LB'de çözümlenir) +# DASHBOARD_DOMAIN=agenteye.your-company.example (panel Traefik LB'de çözümlenir) +``` + +`domain.env` gitignore edilir; her dağıtıma yerel kalır. Kustomize yapı, eğer herhangi bir anahtar eksikse sessizce başarısız olur. + +> **DNS önce çözümlenmelidir.** LB'leri henüz işaret etmek zorunda değilsiniz (Aşama 1.2 tamamlanana kadar yoklar), ancak 3.2 adımında ACME yayını her ana bilgisayar adı LoadBalancer'ına çözümlenene kadar yeniden dener. Şimdi DNS ayarlayabilir (Aşama 1.4'te yakalanan LB ana bilgisayar adlarını kullanarak) veya devam edin ve kayıtları Aşama 4'te ekleyin. + +--- + +### 3.2 Manifestleri uygulayın + +Taze bir yükleme için tabanı doğrudan uygulayın veya bu ortam için bir kaplamayı kestiyseniz (kaplamalar görüntü etiketlerini, env değişkenlerini ve kaynak sınırlarını sabitler; temel sertifikalarını ve yönlendirmesini devralırlar): + +```bash +kubectl apply -k base/ +# veya +kubectl apply -k overlays// +``` + +Kaplamalar tabanı otomatik olarak içerir; birini uygulayın, her ikisini değil. + +--- + +### 3.3 Pod'ları bekleyin + +```bash +kubectl wait --for=condition=Ready pod -l 'app in (server,dashboard,postgres,clickhouse)' \ + -n agenteye --timeout=180s +``` + +Bekleme, veri düzlemi pod'larına kapsama alınır. İsteğe bağlı `agent` (AI asistanı) ve `redis` pod'ları onlarla birlikte başlar; asistan LLM uç noktasını sağlayana kadar pasif kalır ([enterprise-docs/assistant.md](/tr/agenteye/assistant) bölümüne bakın) ve Redis, en iyi çalışma şansı yapan bir önbellektir, bu nedenle ne platform'un trafik sunmasına hazır olması gerekir. + +**Test edin:** + +```bash +kubectl get pods -n agenteye +``` + +Beklenen sonuç (isteğe bağlı `agent` ve `redis` pod'ları da görünür ve `Running` öğesine ulaşır): + +``` +NAME READY STATUS RESTARTS AGE +agent-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +clickhouse-0 1/1 Running 0 ... +dashboard-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +dashboard-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +postgres-0 1/1 Running 0 ... +redis-0 1/1 Running 0 ... +server-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +server-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +``` + +**Başarısız olursa:** + +| Pod Durumu | Muhtemel Neden | Hata Ayıklama Komutu | +|---|---|---| +| `ImagePullBackOff` | Kötü görüntü çekme gizliliği veya PAT | `kubectl describe pod -n agenteye` | +| `CrashLoopBackOff` | Kötü ortam değişkenleri (örn. DATABASE_URL) | `kubectl logs -n agenteye` | +| `Pending` | Yetersiz CPU/bellek veya düğüm yok | `kubectl describe pod -n agenteye` (Olayları kontrol edin) | + +--- + +### 3.4 Depolamayı doğrulayın + +```bash +kubectl get pvc -n agenteye +``` + +Beklenen sonuç, her ikisi de `Bound` durumuyla: + +| PVC | Kapasite | Yedekler | +|---|---|---| +| `postgres-data-postgres-0` | `50Gi` | PostgreSQL ilişkisel/meta veri depolaması | +| `clickhouse-data-clickhouse-0` | `100Gi` | ClickHouse olayları + değerlendirmeler analitikleri depolaması | + +İsteğe bağlı önbellek için bir `redis-data-redis-0` PVC (1Gi) de görünür. + +**Başarısız olursa:** `Pending` anlamına gelir StorageClass ses seslerini sağlayamaz. `kubectl get storageclass` öğesini kontrol edin ve varsayılan bir tane olduğundan emin olun. Üretim için, ClickHouse birimini hızlı bir SSD StorageClass'a yerleştirin (örn. AWS'de gp3, GCP'de pd-ssd); kompaksiyon verimlilik yavaş diskler üzerinde zarar görür. + +--- + +### 3.5 Sertifikaları doğrulayın + +```bash +kubectl get certificates -n agenteye +``` + +Beklenen sonuç: 3 sertifika, tümü `Ready: True`: + +| Ad | İhraçcı | Amaç | +|---|---|---| +| `mtls-ca` | `selfsigned` | mTLS istemci sertifikaları yayınlayan özel CA (10 yıl geçerlilik) | +| `ingest-tls` | `letsencrypt-prod` | Alım uç noktası için genel TLS sertifikası (90 gün, otomatik yenilenmiş) | +| `dashboard-tls` | `letsencrypt-prod` | Panel için genel TLS sertifikası (90 gün, otomatik yenilenmiş) | + +**Eğer `ingest-tls` veya `dashboard-tls` Ready değilse:** + +`kubectl describe certificate -n agenteye` çalıştırın ve Olayları okuyun. Yaygın nedenler: + +- **DNS henüz LB'ye işaret etmiyor.** Let's Encrypt, ana bilgisayar adını çözümler ve doğrulamak için 80 numaralı porta çarpar -- `INGEST_DOMAIN` genel LB'ye, `DASHBOARD_DOMAIN` panel LB'ye çözümlenmelidir. CNAME/Diğer ad yayılana kadar, sipariş `pending` kalır. DNS doğru olduktan sonra, cert-manager otomatik olarak yeniden dener (Sertifika'yı silmeye gerek yok). +- **Ana bilgisayar adı yerine konmamış.** `dnsNames` hala `INGEST_DOMAIN_PLACEHOLDER` / `DASHBOARD_DOMAIN_PLACEHOLDER` okuyorsa, 3.1. adımı atlattınız -- `base/certificates/domain.env` öğesini oluşturun ve yeniden uygulayın. +- **Dashboard Traefik, zorluk sunmıyor** (`dashboard-tls` sadece). Panel Traefik örneği, paketlenmiş değerler dosyasıyla kurulmalıdır (Aşama 1.2), cert-manager'ın HTTP-01 çözücüsünü sunan kapsama alınmış Ingress sağlayıcısını etkinleştirir. Olmadan kurulu bir örnek, zorluk yönlendirilemez ve sipariş `pending` sonsuza kadar kalır. + +**Eğer `mtls-ca` Ready değilse:** cert-manager kendisi sağlıksızdır. Aşama 1.1'den cert-manager pod'larını yeniden kontrol edin. + +--- + +### 3.6 CronJob'ları doğrulayın + +```bash +kubectl get cronjobs -n agenteye +``` + +Beklenen sonuç: + +| Ad | Zamanlama | Amaç | +|---|---|---| +| `agenteye-backup` | `0 3 * * *` | 03:00 UTC'de günlük Postgres + ClickHouse yedeklemesi | +| `cert-renewal-check` | `0 3,15 * * *` | 03:00 ve 15:00 UTC'de sertifika sona erme uyarıları | + +--- + +### 3.7 Sunucunun doğru şekilde başlatıldığını doğrulayın + +```bash +kubectl logs -n agenteye -l app=server --tail=20 +``` + +**Test edin:** Sunucunun 8080 portunda dinlediğini gösteren bir başlangıç satırı arayın. Veritabanı bağlantısı hataları olmamalıdır (sunucu Ready raporlamadan önce PostgreSQL ve ClickHouse'a erişilebildiğini gerektirir). + +**Başarısız olursa:** En yaygın neden, `DATABASE_URL` öğesini kıran `POSTGRES_PASSWORD` içinde URL-güvenli olmayan karakterlerdir. [enterprise-docs/troubleshooting.md](/tr/agenteye/troubleshooting) bölümüne bakın. + +--- + +### 3.8 Panel'in sunucuya bağlandığını doğrulayın + +```bash +kubectl logs -n agenteye -l app=dashboard --tail=20 +``` + +**Test edin:** Çıkışta `ECONNREFUSED` veya benzer hatalar olmadan `Ready` arayın. + +**Başarısız olursa:** `server` Service'in var olup olmadığını kontrol edin (`kubectl get svc server -n agenteye`) ve `AGENTEYE_SERVER_URL` panel dağıtımında `http://server:8080` olarak ayarlandığını kontrol edin. + +--- + +## Aşama 4 -- Ağ Erişimi (~5 dk) + +### 4.1 LoadBalancer adreslerini alın + +```bash +PUBLIC_IP=$(kubectl get svc -n traefik-public \ + -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') + +INTERNAL_IP=$(kubectl get svc -n traefik-dashboard \ + -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') +``` + +> AWS EKS'te LoadBalancer'lar IP yerine ana bilgisayar adı döndürür. Yukarıdaki komutlarda `.ip` öğesini `.hostname` ile değiştirin. + +**Test edin:** + +```bash +echo "Public (ingest): $PUBLIC_IP" +echo "Internal (dashboard): $INTERNAL_IP" +``` + +Her ikisi de boş olmayan olmalıdır. + +--- + +### 4.2 DNS'i LoadBalancer'lara işaret edin + +`base/certificates/domain.env` öğesinden ana bilgisayar adlarının LoadBalancer'larına çözümlenecek şekilde DNS kayıtları oluşturun -- `INGEST_DOMAIN` **genel** Traefik LB'ye, `DASHBOARD_DOMAIN` **panel** Traefik LB'ye: + +- **AWS Route 53:** `Alias = Yes` ile `A` kaydı, hedef = LB ana bilgisayar adı. Düz A → IP kullanmayın; ELB IP'leri döner. +- **Başka herhangi bir sağlayıcı:** Ana bilgisayar adından LB ana bilgisayar adına `CNAME`. + +Doğrulayın: + +```bash +dig +short ingest.your-company.example +dig +short agenteye.your-company.example +``` + +Sırasıyla `$PUBLIC_IP` ve `$INTERNAL_IP` ile aynı adres döndürmelidir (veya EKS'te aynı `*.elb.amazonaws.com` ana bilgisayar adlarına çözümlenmelidir). + +DNS çözümlendikten sonra, cert-manager 3.5. Aşamadaki beklemede olan ACME siparişlerini bir dakika içinde tamamlar. Hem `ingest-tls` hem de `dashboard-tls` `Ready: True` gösterin kadar `kubectl get certificates -n agenteye` öğesini yeniden çalıştırın. + +--- + +### 4.3 Alım uç noktasına ulaşın + +Genel alım uç noktası karşılıklı TLS'yi uygular, bu nedenle her istek (`/health` dahil) istemci sertifikası sunmalıdır. İlk istemci sertifikasını 5. Aşama'da yayınlarsınız; zaten birini varsa, şimdi erişilebilirliği doğrulayın: + +```bash +curl -s --cert issued//client.crt \ + --key issued//client.key \ + https://ingest.your-company.example/health +``` + +Beklenen sonuç: `{"status":"ok"}`. `-k` gerekmez -- sunucu sertifikası `INGEST_DOMAIN` için genel bir CA'ya zincirler, bu nedenle sistem güven deposuna karşı doğrulanır. Raw LoadBalancer IP/ana bilgisayar adı tarafından değil, `INGEST_DOMAIN` ana bilgisayar adı (sertifika ile eşleşen) tarafından alım uç noktasına ulaşın. + +Panel uç noktası, genel olarak güvenilir bir sertifika ile `DASHBOARD_DOMAIN` öğesinde sunulur ve mTLS arkasında değildir, bu nedenle `-k` ve istemci sertifikası yoktur: + +```bash +curl -s https://agenteye.your-company.example/ -o /dev/null -w '%{http_code}\n' +``` + +Raw LB adresinden değil, ana bilgisayar adı tarafından panele ulaşın -- sertifika `DASHBOARD_DOMAIN` öğesine bağlanır, bu nedenle ham adres sertifika adı uyuşmazlığı gösterir. + +**Başarısız olursa:** `curl` asılı kalırsa, LB'nin makinenizden erişilebildiğini kontrol edin (VPN, güvenlik grupları, güvenlik duvarı kuralları). Alım ana bilgisayar adında `certificate required` el sıkışma hatası, hiçbir istemci sertifikasının sunulmadığı anlamına gelir; önce 5. Aşama'yı tamamlayın. Alım ana bilgisayar adında TLS doğrulama hatası, sunucu sertifikasının henüz bitmemiş olduğu anlamına gelir; 3.5. Aşamaya geri dönün ve orada sorunu çözün. + +--- + +## Aşama 5 -- mTLS İstemci Sertifikaları Yayınlayın (~10 dk her küme) + +Toplayıcılar **iki faktör** ile kimlik doğrulama yapar: istemci sertifikası (taşıma katmanı, isteğin yetkili bir kümeden geldiğini kanıtlar) ve API anahtarı (uygulama katmanı, isteğin `events:add` izni olan bir toplayıcıdan geldiğini kanıtlar). Sızan anahtar sertifika olmadan işe yaramaz; çalınan sertifika geçerli anahtar olmadan işe yaramaz. + +### 5.1 Sertifika yayınlayın + +Toplayıcıları çalıştıran her kümenin kendi istemci sertifikasına ihtiyacı vardır. Manifest dizininden: + +```bash +cd base/certificates/client-certs +./issue-client-cert.sh +``` + +`` öğesini anlamlı bir tanımlayıcıyla değiştirin (örn. `us-east-1-prod`, `staging`). + +**Test edin:** Komut `==> Done!` yazdırır ve çıkış dosyalarını listeler. + +```bash +kubectl get certificate mtls-client- -n agenteye +``` + +Beklenen sonuç: `Ready: True`. + +`issued//` içindeki çıkış dosyaları: + +| Dosya | Amaç | +|---|---| +| `client.crt` | İstemci sertifikası (90 gün geçerlilik) | +| `client.key` | İstemci özel anahtarı | +| `ca.crt` | Sunucu doğrulaması için CA sertifikası | +| `collector-mtls-secret.yaml` | Toplayıcı kümesi için uygulamaya hazır Kubernetes Gizliliği | + +--- + +### 5.1b Alternatif teslimat: AWS Gizlilikler Yöneticisi + +Sertifikanın tüketeni diskten `client.crt` ve `client.key` gereken bir Kubernetes Pod'u ise -- uygulamayı uygulama pod'ında kenar aracı olarak çalıştırdığınızda tipik durum -- sertifika paketini AWS Gizlilikler Yöneticisi'ne itin. Uygulama pod'u ardından [Gizlilikler Depolama CSI Sürücüsü](https://secrets-store-csi-driver.sigs.k8s.io/) üzerinden IRSA ile bunu takar ve sertifika döndürme tamamen uygunsuz. + +```bash +cd base/certificates/client-certs +export AWS_REGION=us-east-1 # iş yükünüzün çalıştığı bölge +./issue-client-cert.sh --save-to aws-secrets-manager +``` + +Yeniden çalıştırıldıktan sonra (yenileme), komut dosyası aynı gizlilik üzerinde `PutSecretValue` öğesini çağırır, bu nedenle ARN ve ad kararlı kalır. CSI Sürücüsü, döndürme yoklama aralığını seçer ve dosyaları pod'un içinde yeniden yazar. + +**Önkoşullar:** + +- `aws` CLI v2 AWS hesabınıza kimlik doğrulama. +- `jq` yüklü. +- `AWS_REGION` ortam değişkeni ayarlandı. +- Arayanızın kimliğinde IAM izinleri (`Resource` `arn:aws:secretsmanager:::secret:agenteye/mtls-client/*` kapsamı): + - `secretsmanager:CreateSecret` + - `secretsmanager:DescribeSecret` + - `secretsmanager:PutSecretValue` + - `secretsmanager:TagResource` + +**Komut dosyası bu modda ne yapar:** + +| Adım | İşlem | +|---|---| +| 1 | Cert-manager aracılığıyla sertifikayı yayınlar / yeniden çıkarır (varsayılan mod gibi). | +| 2 | `agenteye/mtls-client/` üzerinde `DescribeSecret` öğesini çağırır ve oluştur-vs-güncelle'ye karar verir. | +| 3 | İlk çalıştırmada: `CreateSecret` öğesini üç tuşlu JSON yükü (`client.crt`, `client.key`, `ca.crt`) ile, etiketli `AgentEyeCluster=`. Sonraki çalıştırmalarda: yeni sürüm yayınlamak için `PutSecretValue`; etiket `TagResource` aracılığıyla yenilenir. | +| 4 | Başarılı yükleme sonrasında `issued//` adresini siler. Herhangi bir başarısızlıkta, dizin korunur, böylece yeniden deneyin. | + +**Gizlilik silme işaretlenmişse**, komut dosyası size yeniden denemeden önce `aws secretsmanager restore-secret --secret-id agenteye/mtls-client/` çalıştırmanız gerektiğini söyleyen açık bir hatayla başarısız olur. + +Tam pod kablolama (SecretProviderClass, IRSA kurulumu, döndürme davranışı, sorun giderme) için [enterprise-docs/single-pod-deployment.md](/tr/agenteye/single-pod-deployment) bölümüne bakın. + +--- + +### 5.2 Sertifikanın çalıştığını doğrulayın + +Verilen sertifikayı mTLS giriş tablosuna karşı test edin: + +```bash +curl -sk --cert issued//client.crt \ + --key issued//client.key \ + https://${PUBLIC_IP}/health +``` + +Beklenen sonuç: `{"status":"ok"}` + +**Başarısız olursa:** + +| Hata | Neden | Çözüm | +|---|---|---| +| `certificate required` | Sertifika sunulmuyor | `curl` komutundaki dosya yollarını kontrol edin | +| `bad certificate` | CA uyuşmazlığı | Sertifikanın `mtls-ca-issuer` tarafından yayınlandığını doğrulayın: `kubectl describe certificate mtls-client- -n agenteye` | +| `connection refused` | Yanlış ana bilgisayar adı veya LB erişilemez | `/etc/hosts` veya DNS'i kontrol edin | + +--- + +### 5.3 Toplayıcı kümesine teslim edin + +`collector-mtls-secret.yaml` öğesini toplayıcı kümesini işleten ekibe gönderin. Bunu uygularlar: + +```bash +kubectl apply -f collector-mtls-secret.yaml -n +``` + +Sonra toplayıcıyı gizliliği takmak ve sertifika yollarını kullanmak için yapılandırın: + +```json +{ + "tls_cert": "/etc/agenteye/tls/client.crt", + "tls_key": "/etc/agenteye/tls/client.key" +} +``` + +Kubernetes birim bağlamalarını içeren tam toplayıcı kurulumu için [enterprise-docs/collector-installation.md](/tr/agenteye/collector-installation) bölümüne bakın. + +**Test edin (toplayıcı kümesinde):** + +```bash +kubectl get secret agenteye-collector-mtls -n +``` + +Beklenen sonuç: 3 veri anahtarı (`client.crt`, `client.key`, `ca.crt`) ile gizlilik var. + +--- + +### 5.4 Sertifika yaşam döngüsü + +| Özellik | Değer | +|---|---| +| İstemci sertifika geçerliliği | 90 gün | +| Otomatik yenileme | cert-manager sona ermeden 15 gün önce yeniler | +| CA geçerliliği | 10 yıl | +| Sona erme uyarıları | CronJob sona ermeden 30 gün önce uyarı gönderir (Aşama 6) | + +cert-manager, **AgentEye kümesinde** sertifikayı otomatik olarak yeniler, ancak yenilenen sertifika toplayıcı kümesine yeniden teslim edilmelidir. `issue-client-cert.sh` öğesini yeniden çalıştırın ve eski sertifika sona ermeden önce `collector-mtls-secret.yaml` öğesini yeniden uygulayın. + +`--save-to aws-secrets-manager` kullanıyorsanız (bkz. § 5.1b), aynı komutu yeniden çalıştırın. Komut dosyası aynı gizlilik üzerinde `PutSecretValue` öğesini çağırır; pod'lar Gizlilikler Depolama CSI Sürücüsü aracılığıyla gizliliği taksa, sonraki döndürme yoklaması (varsayılan: her saat) yeni sürümü seçer, pod yeniden başlatması gerekmez. + +--- + +### 5.5 Sertifikayı iptal edin + +Bir kümenin toplayıcı erişimini hemen engellemek için: + +```bash +kubectl delete certificate mtls-client- -n agenteye +``` + +**Test edin:** 5.2. adımdan `curl` komutu artık TLS el sıkışma hatası ile başarısız olur. + +--- + +## Aşama 6 -- Sertifika Yenileme İzlemesi (~2 dk) + +Yerleşik bir CronJob, her 12 saatte bir (03:00 ve 15:00 UTC) çalışır ve `agenteye.io/cert-type=mtls-client` ile etiketlenmiş tüm istemci sertifikalarını kontrol eder. Herhangi bir sertifika sona ermesine 30 gün kaldığında uyarı gönderir. + +### 6.1 Slack bildirimlerini etkinleştirin (isteğe bağlı) + +```bash +kubectl create secret generic cert-renewal-notify-config \ + --namespace agenteye \ + --from-literal=SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL" +``` + +Bu gizlilik olmadan, CronJob hala çalışır ve sertifika durumunu stdout'a kaydeder. + +**Test edin:** + +```bash +kubectl get secret cert-renewal-notify-config -n agenteye +``` + +Beklenen sonuç: gizlilik var. + +--- + +### 6.2 CronJob'u test edin + +```bash +kubectl create job --from=cronjob/cert-renewal-check test-cert-check -n agenteye + +kubectl wait --for=condition=Complete job/test-cert-check -n agenteye --timeout=60s + +kubectl logs -n agenteye -l job-name=test-cert-check +``` + +Beklenen sonuç: sertifikaların ve sona erme durumlarının bir listesi. Slack web kancası yapılandırılmışsa, Slack kanalında uyarı mesajını kontrol edin. + +**Başarısız olursa:** RBAC'ı kontrol edin -- CronJob'un ServiceAccount'u cert-manager Certificate kaynaklarında `get, list` izinlerine ihtiyaç duyar. Şu komutla doğrulayın: `kubectl describe role cert-renewal-check -n agenteye`. + +Test işini temizleyin: + +```bash +kubectl delete job test-cert-check -n agenteye +``` + +--- + +## Aşama 7 -- Uçtan Uca Doğrulama + +Bu aşama, tüm işlem hattının çalıştığını doğrular: sağlık kontrolü, anahtar oluşturma, olay alımı ve panel görüntüsü. + +> **Not:** Aşağıdaki örnekler, alım uç noktasına ham LoadBalancer adresi (`${PUBLIC_IP}`) tarafından ulaşır; bu nedenle `-k` geçerler; sunucu sertifikası `INGEST_DOMAIN` öğesine bağlanır, host adı değil, `INGEST_DOMAIN` LB IP'ye bağlanır, bu nedenle ana bilgisayar adı kontrol atlanır. Alım uç noktası **her** yola mTLS uygular, bu nedenle her çağrı istemci sertifikası (`--cert`/`--key`) da sunmalıdır. Genel sertifikayı da doğrulamak için `https://ingest.your-company.example/...` yerine `${PUBLIC_IP}` öğesini hedefleyin ve `-k` kaybı düşürün. + +### 7.1 Sağlık kontrolü + +```bash +curl -sk --cert issued//client.crt \ + --key issued//client.key \ + https://${PUBLIC_IP}/health +``` + +Beklenen sonuç: HTTP 200 ile `{"status":"ok"}`. + +--- + +### 7.2 Kapsamlı toplayıcı anahtarları oluşturun \ No newline at end of file diff --git a/docs/tr/agenteye/managed-deployment.mdx b/docs/tr/agenteye/managed-deployment.mdx new file mode 100644 index 00000000..41b69bf6 --- /dev/null +++ b/docs/tr/agenteye/managed-deployment.mdx @@ -0,0 +1,171 @@ +--- +title: "Kubernetes Kümenizi Üzerinde Yönetilen Dağıtım" +description: "AgentEye Kubernetes Kümenizi Üzerinde Yönetilen Dağıtım belgeleri." +--- + + +AgentEye, yapay zeka ve LLM ajanları için kendi kendine barındırılan gözlemlenebilirlik ve değerlendirme platformudur. Ajan oturumlarını, araç çağrılarını, model isteklerini ve hataları yakalar, bunları aranabilir analitik ve değerlendirmelere dönüştürür ve sonuçları opsiyonel salt okunur yapay zeka asistanı ile bir panoda sunar. + +Yönetilen dağıtım modelinde, adanmış bir Kubernetes kümesi sağlarsınız ve Exosphere platform'un tamamını bu küme içinde çalıştırır, her bileşeni sizin adınıza dağıtır, yapılandırır, işletir, yedekler ve yükseltir. Ekibiniz platform'un değerini (ajan görünürlüğü, analitik, değerlendirme ve opsiyonel asistan) veritabanlarını, sertifikaları veya yükseltmeleri işletmek zorunda kalmadan elde eder. Tüm veriler bulut hesabınız içinde kalır. + +--- + +## Önkoşullar + +- Konteyner görüntülerini çekmek ve yapıtları indirmek için **GitHub PAT** (bkz. [GitHub Token Kurulumu](/tr/agenteye/github-token)) +- **Adanmış bir Kubernetes kümesi** (aşağıdaki gereksinimlere bakın) +- Veritabanı yedekleri için **depolama bucket'ı** +- **Ağ bağlantısı**: kümenin yük dengeleyicisine gelen port 443 + +--- + +## Adım 1: Adanmış Kubernetes Kümesi Hazırlayın + +AgentEye'a adanmış bir Kubernetes kümesi oluşturun. Bu küme diğer iş yükleriyle paylaşılmamalıdır, böylece tam platform (uygulama hizmetleri, veritabanları, analitik ve caching) mevcut altyapınızı etkilemeden izolasyon içinde çalışır. + +| Gereksinim | Ayrıntılar | +|---|---| +| **Dağıtım** | Herhangi bir uyumlu Kubernetes: EKS, GKE, AKS veya kendi kendine yönetilen | +| **Sürüm** | 1.27 veya sonrası | +| **Node havuzu** | Minimum: **3 düğüm, her biri 4 vCPU / 8 GB RAM** (standart genel amaçlı örnekler) | +| **Depolama** | Blok hacimler sağlayan varsayılan StorageClass (AWS'de `gp3`, GCP'de `pd-ssd` gibi) | +| **Yük Dengeleyici** | Küme, bulut LoadBalancer hizmetleri sağlayabilmelidir (EKS, GKE, AKS'de varsayılan) | + +> Exosphere küme içinde diğer her şeyi yükler ve yönetir: ingress denetleyicileri, TLS sertifikaları, veritabanları, caching, izleme ve tüm uygulama dağıtımları. + +--- + +## Adım 2: AgentEye Ekibine Erişim Verin + +Exosphere'in ad alanlarını, özel kaynak tanımlarını, ingress denetleyicilerini ve depolama sağlayıcılarını yönetmek için cluster-admin erişimine (veya eşdeğer geniş RBAC'ye) ihtiyacı vardır. + +| Gereksinim | Ayrıntılar | +|---|---| +| **Erişim yöntemi** | IAM rolü (EKS/GKE için tercih edilen), kubeconfig veya SSO tabanlı erişim | +| **VPN / bastion** | Kubernetes API sunucusu özel ise, Exosphere işletim ekibine VPN kimlik bilgilerini veya bastion erişimini sağlayın | + +--- + +## Adım 3: Ağ Bağlantısını Yapılandırın + +Ağ ekibinizin kümenin yük dengeleyicilerine **port 443**'te gelen trafiğe izin vermesi gerekir. Dağıtım iki ayrı yük dengeleyici çalıştırır: biri etkinlik alımı (mTLS korumalı) için, diğeri pano için: + +| Trafik | Kaynak | Hedef | Güvenlik | +|---|---|---|---| +| **Etkinlik alımı** | Kümelerinizde Toplayıcı podları | Alım LoadBalancer'ı, port 443 | mTLS (istemci sertifikası) + API anahtarı | +| **Pano** | Geliştirici tarayıcıları | Pano LoadBalancer'ı, port 443 | HTTPS sizin alan adınızda, parolasız email OTP oturum açma | + +Alım uç noktası karşılıklı TLS ile korunur; toplayıcılar her istekte geçerli bir istemci sertifikası **ve** geçerli bir API anahtarı sunmalıdır. Pano kendi yük dengeleyicisinde ve hostname'de çalışır ve oturum açma, beyaz listeye alınmış e-posta adresleri/etki alanlarıyla sınırlıdır. + +**DNS kayıtları (bir kez):** kontrol ettiğiniz bir etki alanı altında iki CNAME kaydı oluşturursunuz — biri alım uç noktası için biri pano için (örn. `agenteye.your-company.example`) — Exosphere'in sağladığı yük dengeleyici hostname'lerine işaret ederek. Exosphere, otomatik olarak yenilemeler dahil olmak üzere her iki hostname için de halka açık güvenilen TLS sertifikaları sağlar. + +> **Port 80 notu:** otomatik sertifika verme ve yenileme, her yük dengeleyicinin port 80'inde HTTP üzerinden doğrulama yapar. Güvenlik duruşunuz pano yük dengeleyicisini şirket IP aralıklarıyla kısıtlamayı gerektiriyorsa, önce Exosphere'e söyleyin — sertifika doğrulamayı DNS tabanlı bir yönteme değiştiririz (sizin tarafınızda bir ek DNS kaydı) böylece yenilemeler sınırlama arkasında çalışmaya devam eder. + +> **Giden:** Küme düğümlerinin `ghcr.io`'dan konteyner görüntülerini çekmek için internet erişimine ihtiyacı vardır. Ağınız giden trafiği kısıtlarsa, `ghcr.io`'yu beyaz listeye alın veya görüntüleri dahili kayıt defterinize yansıtın. + +--- + +## Adım 4: Yedekleme Depolama Bucket'ı Sağlayın + +Veritabanı yedekleri, sizin sahip olduğunuz bir bulut depolama bucket'ında depolanır. + +| Gereksinim | Ayrıntılar | +|---|---| +| **Hizmet** | S3 (AWS), GCS (GCP) veya Azure Blob Storage | +| **Erişim** | IAM rolü aracılığıyla küme düğümlerine yazma erişimi verin (EKS'de IRSA, GKE'de Workload Identity) veya kimlik bilgileri sağlayın | +| **Saklama** | Bucket'ın yaşam döngüsü ilkesini (saklama süresi, arşivleme kuralları) siz kontrol edersiniz. Exosphere yedekleri yazar; ne kadar süre tutacağınıza siz karar verirsiniz | + +Tek bir günlük yedekleme PostgreSQL'i (ilişkisel durum) ve ClickHouse'u (etkinlikler ve değerlendirmeler) tek sıkıştırılmış bir arşive döker ve bucket'ınıza yükler. Yedeklemeler ayrıca her yükseltmeden önce çalışır. + +--- + +## Adım 5: İletişim Kişisi Belirleyin + +Küme düzeyinde sorunlar için (düğüm durumu, bulut hesap sınırları, ağ değişiklikleri) sizin tarafınızdan bir kişi veya Slack/Teams kanalı sağlayın. Günlük işlemlerde bu kişi ile iletişim gerekmez. + +--- + +## Ne Dağıtıyoruz + +Exosphere küme erişimi aldığında, aşağıdaki bileşenler sizin için dağıtılır ve yönetilir: + +| Bileşen | Rol | +|---|---| +| **AgentEye Server** | Toplayıcılardan etkinlikleri alan, analitik çalıştıran ve pano'ya veri sunan HTTP API | +| **Pano** | Ajan oturumlarını, araç çağrılarını, model isteklerini ve hataları görüntülemek için web arayüzü; opsiyonel salt okunur yapay zeka asistanını barındırır | +| **ClickHouse** | Alınan etkinlikler, analitik ve değerlendirmeler için gerekli kanonik depo | +| **PostgreSQL** | Kuruluşlar, API anahtarları, kullanıcılar, panolar ve kaydedilen sorgular için ilişkisel depo | +| **Redis** | Opsiyonel paylaşılan önbellek ve hız sınırı arka ucu; kullanılamıyorsa platform incelikle bozulur | +| **Yapay zeka asistanı (opsiyonel)** | Dahili salt okunur asistan konteyneri; LLM uç noktası yapılandırılana kadar devre dışı kalır | +| **Ingress denetleyicileri** | İki yük dengeleyici (biri mTLS korumalı alım için, biri pano için) TLS'yi halka açık güvenilen, otomatik yenilenen sertifikalarla sonlandıran ve alım uç noktasında mTLS uygulayan | +| **cert-manager** | TLS sertifikası sağlamasını ve mTLS istemci sertifikası verişini otomatikleştirir | +| **Sertifika izleme** | Zamanlanmış bir iş sertifika süresini kontrol eder ve sertifikalar yenileme yaklaştığında uyarılar gönderir (ör. Slack'e) | + +Yönetilen teklif ayrıca platform'un değerlendirme hattını işletir ve bu hatt, ajan aktivitesini değerlendirme kriterlerinize göre puanlar. Ne sunan bu yetenekler için [Asistan](/tr/agenteye/assistant) ve [Değerlendirme Paketi](/tr/agenteye/evaluation-suite)'ne bakın. + +--- + +## Size Sağlananlar + +Dağıtım tamamlandıktan sonra aşağıdakileri alırsınız: + +| Öğe | Ayrıntılar | +|---|---| +| **Pano URL'si** | Alan adınız altında bir hostname (ör. `https://agenteye.your-company.example`), halka açık güvenilen, otomatik yenilenen TLS sertifikası ile sunulan. Sağladığımız yük dengeleyici hostname'ine bir CNAME oluşturursunuz; oturum açma parolasız email OTP'dir | +| **Toplayıcı uç noktası** | Alım hostname'inin `/events` yolu (ör. `https://ingest.your-company.example/events`), mTLS korumalı | +| **İstemci sertifikası paketi** | Küme başına: istemci sert., özel anahtar ve CA sertifikası Kubernetes Secret manifest'i olarak teslim edilir. Küme başına bir kez uygulayın | +| **GitHub PAT** | Toplayıcı ikili dosyalarını ve Python SDK paketlerini indirmek için | +| **Toplayıcı API anahtarları** | `events:add` izniyle kapsamlı anahtarlar, toplayıcı dağıtımı başına bir adet | +| **Kurulum kılavuzları** | Toplayıcı ve Python SDK için adım adım belgeler | + +--- + +## Kurulumdan Sonra Yapacağınız İşler + +Tek devam eden çalışmanız AgentEye kümesinde değil kendi ajan makinelerinizde: + +1. **Toplayıcıyı yükleyin** yapay zeka ajanları çalıştıran her Kubernetes kümesinde: istemci sertifikasını monte edin ve uç nokta URL'sini ve API anahtarını yapılandırın. Bkz. [Toplayıcı Kurulumu](/tr/agenteye/collector-installation). +2. **Python SDK'yı entegre edin** ajan kodunuza. Bkz. [Python SDK](/tr/agenteye/python-sdk). +3. **Pano'yu açın** tarayıcınızda ajan aktivitesini görüntülemek için. + +Küme işletimi yok, veritabanı yönetimi yok, sertifika yenileme yok, yükseltme yok. + +--- + +## Güvenlik + +- **Veriler bulut hesabınızda kalır.** Küme, depolama ve veritabanları tümü ortamınızda çalışır. Hiçbir veri sınırınızı terk etmez. +- **Erişimi siz kontrol edersiniz.** Küme hesabınızdadır. Herhangi bir zamanda Exosphere'in erişimini denetleyebilir, izleyebilir veya iptal edebilirsiniz. Tüm işlemler bulutunuzun denetim günlüğünden geçer (CloudTrail, GCP Audit Logs vb.). +- **Etkinlik alımında mTLS.** Her toplayıcı isteği hem geçerli bir istemci sertifikası hem de API anahtarı gerektirir. Sızan anahtar sert. olmadan işe yaramaz; çalınan sert. geçerli anahtar olmadan işe yaramaz. +- **Pano erişim kontrolü.** Pano kendi yük dengeleyicisinde, etkinlik alımından ayrı olarak çalışır ve oturum açma, beyaz listeye alınmış e-posta adresleri/etki alanlarıyla sınırlı parolasız email OTP'dir. Yük dengeleyicide IP kaynak aralığı beyaz listesi istekle kullanılabilir; otomatik sertifika yenileme yük dengeleyiciye ulaşması gerektiğinden, Exosphere kısıtlamayı DNS tabanlı sertifika doğrulaması ile eşleştirir böylece yenilemeler çalışmaya devam eder. +- **Küme başına sertifikalar.** Kümelerinizin her biri kendi istemci sertifikasını alır. Bir küme tehlikeye girerse, bu sertifika bağımsız olarak iptal edilir ve diğerlerini etkilemez. + +--- + +## Dağıtım Zaman Çizelgesi + +| Aşama | Süre | Sizin katılımınız | +|---|---|---| +| **Küme hazırlama** | 1-2 gün | Kümeyi hazırlayın ve Exosphere'e erişim verin | +| **Platform kurulumu** | 1 gün | Hiçbiri; Exosphere tüm altyapı bileşenlerini yükler | +| **Uygulama dağıtımı** | 1 gün | Hiçbiri; Exosphere sunucuyu, pano'yu dağıtır ve API anahtarları oluşturur | +| **Toplayıcı dağıtımı** | 1-3 gün | Kümelerinizde toplayıcıları yükleyin (Exosphere'in rehberliğiyle) | +| **Üretim deneme** | 1 hafta | Hiçbiri; Exosphere izler ve ayarlar | + +Tipik toplam: Kickoff'tan üretime hazır'a kadar **~2 hafta**. + +--- + +## Destek + +Sorular veya sorunlar için Exosphere'e `support@exosphere.host` adresinde ulaşın. + +--- + +## Sonraki Adımlar + +- [Başlangıç](/tr/agenteye/getting-started): uçtan uca kılavuz +- [Toplayıcı Kurulumu](/tr/agenteye/collector-installation): toplayıcıyı yükleyin ve yapılandırın +- [Python SDK](/tr/agenteye/python-sdk): ajan kodunuzu çalıştırın +- [API Anahtarları](/tr/agenteye/api-keys): erişimi ve izinleri yönetin +- [Sorun Giderme](/tr/agenteye/troubleshooting): yaygın sorunlar ve çözümleri \ No newline at end of file diff --git a/docs/tr/agenteye/python-sdk.mdx b/docs/tr/agenteye/python-sdk.mdx new file mode 100644 index 00000000..aa395b65 --- /dev/null +++ b/docs/tr/agenteye/python-sdk.mdx @@ -0,0 +1,386 @@ +--- +title: "Python SDK" +description: "AgentEye Python SDK dokümantasyonu." +--- + + +AgentEye Python SDK, aracılarınızın davranışına (her aracı çalıştırması, araç çağrısı, model isteği, kanca ve insan müdahalesi) tam görünürlük sağlayarak hata ayıklama, denetim ve değerlendirme yapmanıza olanak tanır. Yapılandırılmış olayları yerel JSONL dosyalarına yazarak aracı kodunuzu instrumantalleştirir; toplayıcı daemon bu dosyaları alır ve otomatik olarak platforma gönderir. + +--- + +## Kurulum + +`AGENTEYE_TOKEN` kullanarak GitHub Releases'ten wheel'i indirin. Henüz bir token'ınız yoksa, kurulum adımları ve gerekli izinler için [GitHub Token Kurulumu](/tr/agenteye/github-token) bölümüne bakın. + +**`gh` CLI + pip kullanarak:** + +```bash +VERSION=0.0.1b9 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "python-sdk/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-*.whl' +pip install "agenteye-${VERSION}-py3-none-any.whl" +``` + +**`gh` CLI + uv kullanarak:** + +```bash +VERSION=0.0.1b9 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "python-sdk/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-*.whl' +uv add "./agenteye-${VERSION}-py3-none-any.whl" +``` + +**curl kullanarak (`gh` CLI olmadan):** + +```bash +VERSION=0.0.1b9 +curl -fsSL \ + -H "Authorization: Bearer $AGENTEYE_TOKEN" \ + -L \ + "https://github.com/agenteye-enterprise/releases/releases/download/python-sdk%2Fv${VERSION}/agenteye-${VERSION}-py3-none-any.whl" \ + -o "agenteye-${VERSION}-py3-none-any.whl" +pip install "agenteye-${VERSION}-py3-none-any.whl" +``` + +--- + +## Hızlı Başlangıç + +```python +import agenteye + +agenteye.configure(environment="production") + +agenteye.event.agent_start(session_id="run-001", agent_id="planner", goal="answer user query") + +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", + input={"query": "latest AI research"}, +) + +agenteye.event.tool_result( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", + output={"results": ["..."]}, +) + +agenteye.event.agent_end(session_id="run-001", agent_id="planner", outcome="success") +``` + +--- + +## configure() + +```python +agenteye.configure( + base_dir=None, # Path | str | None. Default: $AGENTEYE_HOME or ~/.agenteye + flush_interval=0.5, # float, seconds between flush cycles + environment=None, # str | None. Deployment environment label +) +``` + +Herhangi bir `event.*` çağrısından önce bir kez çağırın. Atlanması güvenlidir; varsayılanlar kutudan çıktığı gibi çalışır. Tüm argümanlar yalnızca anahtar kelime argümanlarıdır; yukarıda gösterildiği gibi adlarına göre geçin. + +`base_dir` `None` (varsayılan) olduğunda, SDK `$AGENTEYE_HOME` okur (ayarlanmış ise), +aksi takdirde `~/.agenteye` olarak geri döner. Bu toplayıcının kendi çözünürlüğü ile eşleşir, +bu nedenle tek bir `AGENTEYE_HOME` ortam değişkeni SDK ve toplayıcı için paylaşılan olay kuyruğunu yapılandırır, +her iki işlemin de spool yolunda anlaşması gereken yan araç / tek-pod dağıtımları için gereklidir. + +--- + +## Ortam + +Her olayı bir dağıtım ortamı (`production`, `staging`, `qa`, `canary`, vb.) ile etiketleyin. Bir kez ayarlayın; SDK bunu otomatik olarak her olaya ekler. + +**Seçenek 1: `configure()` aracılığıyla:** + +```python +agenteye.configure(environment="production") +``` + +**Seçenek 2: ortam değişkeni aracılığıyla:** + +```bash +export AGENTEYE_ENVIRONMENT=production +``` + +**Öncelik:** `configure(environment=...)` ortam değişkenini geçersiz kılar. İkisi de ayarlanmamışsa, varsayılan değer `"dev"` olur. + +Ortam değeri panodaki birinci sınıf bir filtre olarak görünür ve hızlı sorgular için sunucuda dizinlenmiş bir sütun olarak depolanır. + +**Kısıtlama:** ortam değerleri **gerçek bir `,` virgül içermemeli**. Pano filtreleri kablodaki virgülden ayrılmış çoklu seçimi kullanır (`?environment=prod,staging`), bu nedenle `prod,blue` adlı bir ortam iki değere bölünür. Virgül içeren ortamlarla olaylar alındığında reddedilir. + +--- + +## Olay Başvurusu + +Tüm olay yöntemleri şu iki alanı gerektirir: + +| Alan | Tür | Açıklama | +|---|---|---| +| `session_id` | `str` | Üst düzey aracı çalıştırmasını tanımlar | +| `agent_id` | `str` | Oturum içindeki hangi aracının olayı yayınladığını tanımlar | + +Tüm yöntemler ayrıca özel meta veriler için rasgele `**kwargs` kabul eder (bkz. [Özel Alanlar](#custom-fields)). + +--- + +### `event.agent_start()` + +Bir aracı çalışmaya başladığında yayınlanır. + +```python +agenteye.event.agent_start( + session_id="run-001", + agent_id="planner", + goal="answer user query", # str | None + parent_id=None, # str | None - nested agents için üst agent_id +) +``` + +--- + +### `event.agent_end()` + +Bir aracı işi bitirdiğinde yayınlanır. + +```python +agenteye.event.agent_end( + session_id="run-001", + agent_id="planner", + outcome="success", # str | None + summary="Answered query", # str | None +) +``` + +--- + +### `event.tool_use()` + +Bir aracı bir araç çağırdığında yayınlanır. `tool_result` ile eşleştirin; SDK otomatik olarak `duration_ms` hesaplar. + +```python +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="web_search", # str, required + tool_call_id="toolu_01", # str, required - matching tool_result için korelasyon anahtarı + input={"query": "..."}, # dict | None +) +``` + +--- + +### `event.tool_result()` + +Bir araç döndüğünde yayınlanır. `tool_call_id` aracılığıyla `tool_use` ile ilişkilidir. + +```python +agenteye.event.tool_result( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", # prior tool_use ile eşleşmeli + output={"results": ["..."]}, # Any | None + error=None, # str | None - araç hata fırlatırsa ayarlayın + # duration_ms otomatik olarak hesaplanır - geçmeyin +) +``` + +--- + +### `event.model_request()` + +Bir istem bir LLM'ye gönderilmeden hemen önce yayınlanır. + +```python +agenteye.event.model_request( + session_id="run-001", + agent_id="planner", + model="claude-sonnet-4-6", # str | None + messages=[ # list[dict] | None - konuşma dönüşleri + {"role": "user", "content": "..."}, + ], + system="You are helpful.", # Any | None - str veya içerik blokları listesi + tools=[ # list[dict] | None - modele sunulan araç şemaları + {"name": "search", "input_schema": {"type": "object"}}, + ], +) +``` + +`messages` girişleri düz bir dize `content` veya Anthropic tarzı blok listesi `content` kabul eder. Örnekleme parametreleri (`temperature`, `max_tokens`, vb.) ek kwargs olarak geçilebilir. + +--- + +### `event.model_response()` + +LLM bir yanıt döndüğünde yayınlanır. + +```python +agenteye.event.model_response( + session_id="run-001", + agent_id="planner", + model="claude-sonnet-4-6", # str | None + stop_reason="end_turn", # str | None + input_tokens=1024, # int | None + output_tokens=256, # int | None + content=[ # Any | None - str, veya içerik blokları listesi + {"type": "text", "text": "..."}, + ], + role="assistant", # str | None +) +``` + +`content` düz bir dize (genel sağlayıcılar) veya Anthropic tarzı içerik blokları listesi kabul eder. Araç çağrıları `content` içinde `{"type": "tool_use", ...}` blokları olarak bulunur, ayrı bir `tool_calls` alanı olmadan. + +--- + +### `event.hook_triggered()` + +Bir kanca ateşlendiğinde yayınlanır. `hook_completed` ile eşleştirin; SDK otomatik olarak `duration_ms` hesaplar. + +```python +agenteye.event.hook_triggered( + session_id="run-001", + agent_id="planner", + hook_name="pre_tool_use", # str, required + hook_id="hook-abc", # str, required - korelasyon anahtarı + trigger_event="tool_use", # str | None + input={"tool": "search"}, # Any | None +) +``` + +--- + +### `event.hook_completed()` + +Bir kanca bittiğinde yayınlanır. `hook_id` aracılığıyla `hook_triggered` ile ilişkilidir. + +```python +agenteye.event.hook_completed( + session_id="run-001", + agent_id="planner", + hook_name="pre_tool_use", + hook_id="hook-abc", # prior hook_triggered ile eşleşmeli + outcome="allow", # str | None + output=None, # Any | None + error=None, # str | None + # duration_ms otomatik olarak hesaplanır - geçmeyin +) +``` + +--- + +### `event.error()` + +İşlenmeyen bir hata oluştuğunda yayınlanır. + +```python +agenteye.event.error( + session_id="run-001", + agent_id="planner", + error_type="TimeoutError", # str, required + message="timed out", # str, required + traceback="Traceback...", # str | None +) +``` + +--- + +## İnsan-Döngüde-Olay Olayları + +İnsan-döngüde-olay olayları, bir kişinin aracının yürütülmesine girdiği anlar (onay beklemek, girdi sağlamak, duraklatmak veya aracıyı durdurmak) hakkında gözetim sağlar. İnsanların yanıt vermesinin ne kadar sürdüğünü (SDK eşleştirilmiş olaylarda `duration_ms` otomatik olarak hesaplar), kimin aracıyı duraklatıp durdurduğunu denetleyin ve panoda görünen onay ve gözetim iş akışları oluşturun. + +### `event.human_wait()` + +Aracı bir insanın girdi sağlaması için beklemek üzere yürütmeyi duraklattığında yayınlanır. `human_input` ile eşleştirin; SDK otomatik olarak `duration_ms` hesaplar (insanın yanıt vermesi ne kadar sürdü). + +```python +agenteye.event.human_wait( + session_id="run-001", + agent_id="planner", + input_id="inp-abc", # str, required - matching human_input için korelasyon anahtarı + prompt="Do you approve this action?", # str | None - insana gösterilen soru + options=["approve", "reject", "defer"], # list[str] | None - insana sunulan seçenekler + reason="approval_required", # str | None - aracının neden beklediğinin nedeni +) +``` + +### `event.human_input()` + +Bir insan girdi sağladığında ve aracı devam ettiğinde yayınlanır. `input_id` aracılığıyla `human_wait` ile ilişkilidir. `duration_ms` otomatik olarak hesaplanır ve arayanlar tarafından geçmemesi gerekir. + +```python +agenteye.event.human_input( + session_id="run-001", + agent_id="planner", + input_id="inp-abc", # str, required - prior human_wait ile eşleşmeli + response="approve", # str | None - insanın cevabı (serbest metin veya seçili seçenek) + # duration_ms otomatik olarak hesaplanır - geçmeyin +) +``` + +### `event.human_pause()` + +Bir insan aracıyı etkin olarak duraklattığında yayınlanır (örneğin pano kontrol aracılığıyla). Aracı askıya alınır ancak sonlandırılmaz. + +```python +agenteye.event.human_pause( + session_id="run-001", + agent_id="planner", + reason="user_requested", # str | None + user_id="usr_42", # str | None - aracıyı kim duraklatmış +) +``` + +### `event.human_interrupt()` + +Bir insan aracıyı yürütmenin ortasında etkin olarak durduğunca yayınlanır. `human_pause` aksine, aracının işi askıya alınmak yerine sonlandırılır. + +```python +agenteye.event.human_interrupt( + session_id="run-001", + agent_id="planner", + reason="output_incorrect", # str | None + user_id="usr_42", # str | None - aracıyı kim durdurdu + at_step="tool_use:web_search", # str | None - aracı durdurulduğunda ne yapıyordu +) +``` + +--- + +## Özel Alanlar + +Tüm ek anahtar kelime argümanları standart alanlardan sonra olaya eklenir: + +```python +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="db_query", + tool_call_id="toolu_02", + tenant_id="acme", # custom field + region="us-east-1", # custom field +) +``` + +`timestamp`, `type` ve `environment` ayrılmıştır ve özel alanlar olarak geçilirse `ValueError` fırlatır (`Reserved field names cannot be used as custom fields: [...]`). `session_id` ve `agent_id` her olay yönteminde gerekli parametrelerdir ve ikinci kez sağlanamazlar; bunu yaparsanız Python `TypeError` fırlatır. Bunun yerine `configure(environment=...)` (veya `AGENTEYE_ENVIRONMENT` değişkeni) ile ortamı ayarlayın. + +--- + +## Olaylar Nasıl Yazılır + +Olaylar işlem içinde tamponlanır ve her `flush_interval` saniyede (varsayılan 500 ms) diske yazılır. Her flush bir JSONL dosyası yazar: + +``` +~/.agenteye/events/event-2026-04-01T12-00-00-000Z.jsonl +``` + +Toplayıcı bu dizini izler ve dosyaları otomatik olarak yükler. Bu dosyaları doğrudan yönetmeniz gerekmez. \ No newline at end of file diff --git a/docs/tr/agenteye/single-pod-deployment.mdx b/docs/tr/agenteye/single-pod-deployment.mdx new file mode 100644 index 00000000..f4874619 --- /dev/null +++ b/docs/tr/agenteye/single-pod-deployment.mdx @@ -0,0 +1,484 @@ +--- +title: "Tek-Pod Dağıtımı: Collector + Application Sidecar on EKS" +description: "AgentEye Tek-Pod Dağıtımı: Collector + Application Sidecar on EKS belgelendirmesi." +--- + + +Uygulamanızı ve AgentEye collector'ını **aynı Kubernetes Pod içinde** çalıştırın, böylece telemetri toplanmak üzere hiçbir zaman bir ağ sınırını geçmez. Uygulamanızın SDK'sı ve collector, tek bir pod içi olay spoolunu paylaşır, bu da düşük gecikmeli, işlem içi telemetri aktarımı anlamına gelir - localhost portu açıklanmaz, hizmet ağını geçilmez ve collector'ın yaşam döngüsü doğrudan gözlemlediği iş yüküne bağlıdır. Collector'ın sunduğu mTLS istemci sertifikası doğrudan AWS Secrets Manager'dan pod'unuza teslim edilir, böylece kimlik bilgisi döndürme sizin tarafınızda manuel dosya taşımayı gerektirmez. + +Burada açıklanan sidecar + shared-spool modeli buluta bağımsızdır; `emptyDir` olay spoolunu paylaşan iki konteyner herhangi bir Kubernetes dağıtımında çalışır. Bu kılavuzdaki sertifika teslim yolu (AWS Secrets Manager + Secrets Store CSI Driver + IRSA) yalnızca AWS / EKS'ye özgüdür. Başka bir yerde çalıştırırsanız, pod ve spool düzenini koruyun ve Aşamalar 2 ve 3 için platformunuzun gizli dağıtım mekanizmasını değiştirin. + +> **Bu deseni ne zaman kullanmalısınız.** Uygulamanız collector'a ulaşmak için bir ağ sınırını geçmemelidir (düşük gecikmeli pod içi IPC, sıkı yaşam döngüsü bağlaması, kiracı başına pod yalıtımı) when seçin. Bir collector'ı düğüm başına veya küme başına paylaşan çok uygulamalı filo için [enterprise-docs/kubernetes-deployment.md](/tr/agenteye/kubernetes-deployment) dosyasına bakın. + +--- + +## Bir bakışta + +``` +┌──────────────────────────────── Pod ─────────────────────────────────┐ +│ │ +│ ┌──────────────────────┐ ┌──────────────────────┐ │ +│ │ your-app │ │ agenteye-collector │ │ +│ │ (SDK writes JSONL) │ │ (sweeps events/, │ │ +│ │ │ │ uploads over mTLS) │ │ +│ └──────────┬───────────┘ └──────────┬───────────┘ │ +│ │ writes reads │ │ +│ ▼ ▼ │ +│ ┌────────────────────────────────────────────────────┐ │ +│ │ emptyDir: /var/lib/agenteye/{events,failed}/ │ │ +│ │ (AGENTEYE_HOME - shared event spool) │ │ +│ └────────────────────────────────────────────────────┘ │ +│ ▲ │ +│ │ reads cert │ +│ ┌────────┴─────────┐ │ +│ │ CSI (read-only): │ │ +│ │ /etc/agenteye/ │ │ +│ │ tls/client.{crt, │ │ +│ │ key}, ca.crt │ │ +│ └────────┬─────────┘ │ +└───────────────────────────────────────────────────┼──────────────────┘ + │ mounted by + │ Secrets Store CSI + │ (AWS provider + + │ IRSA) + ┌────────┴──────────┐ + │ AWS Secrets │ + │ Manager │ + │ agenteye/mtls- │ + │ client/ │ + └────────┬──────────┘ + ▲ + │ push on issue / + │ renewal + ┌────────┴──────────┐ + │ Exosphere │ + │ delivers the cert │ + │ bundle into your │ + │ Secrets Manager │ + │ on renewal │ + └───────────────────┘ + +Outbound: collector → AGENTEYE_URL (mTLS, using the CSI-mounted cert). +``` + +İki veri akışı, iki birim: + +- **Events (pod içi):** uygulamanızın SDK'sı `.jsonl` dosyalarını `$AGENTEYE_HOME/events/` adresindeki shared `emptyDir`'e yazarsa; collector sweeper onları okur ve yükler. Localhost portu yok, loopback yok, saf shared-filesystem aktarımı. +- **mTLS cert (pod ← bulut):** Secrets Store CSI Driver sertifika bundle'ını Secrets Manager'dan `/etc/agenteye/tls/` adresinde salt okunur bir volume'e takar, collector konteynerine kapsamlı olarak. + +**İki bağımsız taraf:** + +| Taraf | Sorumluluk | +|---|---| +| Exosphere | mTLS istemci sertifikasını yayınlar ve bundle'ı **sizin** AWS hesabınızın Secrets Manager'ına stable bir adla teslim eder. Yenilenen bundle'ı sona ermeden önce aynı gizliye yeniden yayınlar. | +| Siz | Secrets Store CSI Driver'ı kurun, pod'un ServiceAccount'ına IRSA aracılığıyla gizliye okuma erişimi verin ve Pod manifest'ini uygulayın. Hepsi bu. | + +--- + +## Ön koşullar + +### AWS hesabınızda / EKS kümesinde + +- İlişkili bir **OIDC sağlayıcısı** olan bir EKS kümesi. Şu komutla doğrulayın: + + ```bash + aws eks describe-cluster --name \ + --query "cluster.identity.oidc.issuer" --output text + ``` + + Komut bir `https://oidc.eks.…` URL döndürürse OIDC etkinleştirilmiştir. Değilse, birini ilişkilendirin: + + ```bash + eksctl utils associate-iam-oidc-provider \ + --cluster --approve + ``` + +- [Secrets Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/) ve [AWS sağlayıcısı](https://github.com/aws/secrets-store-csi-driver-provider-aws) kümede yüklü (bkz. § Aşama 2). + +- AWS CLI v2 ve `kubectl` iş istasyonunuzda. + +### Exosphere ile koordinasyon + +Dağıtmadan önce, Exosphere mTLS istemci bundle'ını AWS hesabınızın Secrets Manager'ına teslim eder ve sağlar: + +- **Gizli adı** (kural: `agenteye/mtls-client/`) +- Gizlinin yaşadığı **AWS bölgesi** +- Collector'ı yapılandırmak için **AgentEye arka uç URL'si** +- Collector **API anahtarı** (bkz. [enterprise-docs/api-keys.md](/tr/agenteye/api-keys)) + +--- + +## Aşama 1: Exosphere'nin teslim ettikleri + +mTLS istemci sertifikasını kendiniz oluşturmazsınız. Exosphere onu yayınlar ve bundle'ı doğrudan AWS hesabınızın Secrets Manager'ına teslim eder, bu nedenle ortamınıza inen tek kimlik bilgisi malzemesi bitmiş, monte etmeye hazır gizlidir. + +Hesabınıza gelen şeyler: + +| Özellik | Değer | +|---|---| +| Gizli adı | `agenteye/mtls-client/` (yenileme sırasında stabil) | +| Bölge | EKS kümeniz için belirlediğiniz AWS bölgesi | +| Yük | Üç anahtarlı tek bir JSON gizlisi (`client.crt`, `client.key` ve `ca.crt`), her biri PEM kodlu malzemeyi tutar | +| Etiket | `AgentEyeCluster=` | + +Yenileme sırasında, aynı gizli yerinde yeni bir sürümle güncellenir, böylece ARN ve ad hiç değişmez; `SecretProviderClass` ve IAM politikanız değişmeden çalışır. Sertifika yaşam döngüsü (geçerlilik, yenileme hızı, sona erme uyarıları) için bkz. [enterprise-docs/kubernetes-deployment.md](/tr/agenteye/kubernetes-deployment). + +--- + +## Aşama 2: Secrets Store CSI Driver + AWS sağlayıcısını kurun + +AWS gizlilerini CSI aracılığıyla takmış başka bir iş yükü çalıştırıyorsanız bu adımı atlayın. + +```bash +# CSI Driver +helm repo add secrets-store-csi-driver \ + https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts +helm install -n kube-system csi-secrets-store \ + secrets-store-csi-driver/secrets-store-csi-driver \ + --set syncSecret.enabled=true \ + --set enableSecretRotation=true \ + --set rotationPollInterval=1h + +# AWS provider +kubectl apply -f \ + https://raw.githubusercontent.com/aws/secrets-store-csi-driver-provider-aws/main/deployment/aws-provider-installer.yaml +``` + +**Doğrulayın:** + +```bash +kubectl get pods -n kube-system | grep -E 'csi-secrets-store|aws-provider' +``` + +Beklenen: her pod için `Running`. + +> **Neden `rotationPollInterval=1h`?** Exosphere yenilenen bir sertifika yayınladığında, Secrets Manager yerinde güncellenir. CSI Driver bu aralıkta gizliyi yeniden okur ve monte edilen dosyaları yeniden yazar. Collector sertifika dosyalarını başlangıçta bir kez okur, bu nedenle yenilenen sertifikayı sunmaya yalnızca bir işlem yeniden başlaması sonrasında başlar; bkz. § Sertifika yenileme nasıl bir yeniden başlatma tetiklenir. + +--- + +## Aşama 3: Pod'a gizliye okuma erişimi verin (IRSA) + +### 3.1 IAM politikasını oluşturun + +`agenteye-mtls-reader-policy.json` olarak kaydedin: + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "ReadAgentEyeMtlsBundle", + "Effect": "Allow", + "Action": [ + "secretsmanager:GetSecretValue", + "secretsmanager:DescribeSecret" + ], + "Resource": "arn:aws:secretsmanager:::secret:agenteye/mtls-client/-*" + } + ] +} +``` + +``, `` ve `` yerine koyun. Sondaki `-*` AWS'nin her gizli ARN'ye eklediği altı karakterlik rastgele soneki eşleştirir. + +Politikayı oluşturun: + +```bash +aws iam create-policy \ + --policy-name AgentEyeMtlsReader- \ + --policy-document file://agenteye-mtls-reader-policy.json +``` + +### 3.2 IAM rolünü oluşturun ve pod'un ServiceAccount'ına bağlayın + +```bash +eksctl create iamserviceaccount \ + --name agenteye-pod \ + --namespace \ + --cluster \ + --role-name AgentEyePodRole- \ + --attach-policy-arn arn:aws:iam:::policy/AgentEyeMtlsReader- \ + --approve +``` + +Bu, `agenteye-pod` adlı bir `ServiceAccount` oluşturur ve `eks.amazonaws.com/role-arn` ek açıklaması yeni role'ü gösterir. + +### 3.3 Gerekli IAM izinleri: özet + +| İzin | Kapsam | Neden | +|---|---|---| +| `secretsmanager:GetSecretValue` | `arn:aws:secretsmanager:::secret:agenteye/mtls-client/-*` | CSI Driver her monte etme + döndürme onayında gizliyi okur. | +| `secretsmanager:DescribeSecret` | aynı | CSI Driver `DescribeSecret` çağırır yoklamalar arasındaki sürüm değişikliklerini algılamak için. | + +**YAPMAYINIZ** `secretsmanager:PutSecretValue`, `secretsmanager:UpdateSecret` veya `secretsmanager:DeleteSecret` pod'a verin. Pod gizliyi yalnızca okur; sertifika yayınlandığında veya yenilendiğinde gizliye yeni sürümler yazmak Exosphere tarafından işlenir. + +Gizli müşteri tarafından yönetilen bir KMS anahtarıyla şifreli ise (varsayılan `aws/secretsmanager` anahtarı değil), aynı zamanda verin: + +```json +{ + "Effect": "Allow", + "Action": ["kms:Decrypt"], + "Resource": "arn:aws:kms:::key/", + "Condition": { + "StringEquals": { + "kms:ViaService": "secretsmanager..amazonaws.com" + } + } +} +``` + +--- + +## Aşama 4: Pod'u dağıtın + +### 4.1 SecretProviderClass + +`agenteye-mtls-spc.yaml`: + +```yaml +apiVersion: secrets-store.csi.x-k8s.io/v1 +kind: SecretProviderClass +metadata: + name: agenteye-mtls + namespace: +spec: + provider: aws + parameters: + objects: | + - objectName: "agenteye/mtls-client/" + objectType: "secretsmanager" + jmesPath: + - path: '"client.crt"' + objectAlias: "client.crt" + - path: '"client.key"' + objectAlias: "client.key" + - path: '"ca.crt"' + objectAlias: "ca.crt" +``` + +`jmesPath` bloğu AWS sağlayıcısına JSON gizlisini diske üç ayrı dosyaya bölmesini söyler. `'"client.crt"'` içindeki alıntı gereklidir çünkü JMESPath `.` işaretçisini bir alt ifade operatörü olarak kabul eder. + +```bash +kubectl apply -f agenteye-mtls-spc.yaml +``` + +### 4.2 Pod / Dağıtım manifest'i + +**İki konteyner birbirinden nasıl konuşur.** AgentEye SDK ve collector bir ağ socket üzerinden iletişim kurmaz; yerel HTTP portu yoktur. SDK `.jsonl` dosyaları olarak olay toplamlarını `$AGENTEYE_HOME/events/` içine yazar ve collector sürekli o dizini izler ve her dosyayı yükler. Sidecar pod için bu şu anlama gelir: + +- Her iki konteyner **aynı** `emptyDir` volume'ü **aynı** yolda monte eder. +- Her iki konteyner de `AGENTEYE_HOME` o yola ayarla. +- Uygulamanız image'ı AgentEye SDK yüklü ve yapılandırılmış olmalıdır (bkz. [enterprise-docs/python-sdk.md](/tr/agenteye/python-sdk)). + +> `AGENTEYE_HOME` ayarlanmadığında, SDK ve collector ikisi de `~/.agenteye`'ye varsayılan olarak ayarlanır ve iki konteyner farklı ev dizinlerine sahiptir, bu nedenle iki ayrı spool'un üzerine inerler ve handoff sessizce başarısız olurdu. `AGENTEYE_HOME` aynı açık yola **her iki** konteyner'e ayarlayın. §4.3 doğrulama ve eşleşen Sorun Giderme satırı bunun kaçırıldığını yakalarsa. + +`agenteye-pod.yaml` (Bir çoğaltmayla Dağıtım, gerektiğinde ölçeklendir): + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-app-with-collector + namespace: +spec: + replicas: 1 + selector: + matchLabels: + app: my-app-with-collector + template: + metadata: + labels: + app: my-app-with-collector + spec: + serviceAccountName: agenteye-pod + containers: + - name: app + image: + env: + # SDK writes event JSONL files into $AGENTEYE_HOME/events/ + - name: AGENTEYE_HOME + value: /var/lib/agenteye + volumeMounts: + - name: agenteye-spool + mountPath: /var/lib/agenteye + + - name: agenteye-collector + # Pin to a versioned :v tag for production; :beta-latest + # tracks the current beta build (:latest exists only for stable releases). + image: ghcr.io/agenteye-enterprise/collector:beta-latest + args: ["start"] + env: + # Must match the app container's AGENTEYE_HOME so the collector + # sweeps the same directory the SDK writes to. + - name: AGENTEYE_HOME + value: /var/lib/agenteye + - name: AGENTEYE_URL + value: "https://ingest.example.agenteye.com/events" + - name: AGENTEYE_KEY + valueFrom: + secretKeyRef: + name: agenteye-collector-api-key + key: key + - name: AGENTEYE_TLS_CERT + value: /etc/agenteye/tls/client.crt + - name: AGENTEYE_TLS_KEY + value: /etc/agenteye/tls/client.key + # Only when the AgentEye server presents a cert not signed by a + # publicly-trusted CA (e.g. self-signed by an in-cluster issuer + # because you have no real DNS domain). The CSI mount already + # exposes ca.crt alongside the client cert/key. + - name: AGENTEYE_TLS_CA + value: /etc/agenteye/tls/ca.crt + volumeMounts: + - name: agenteye-spool + mountPath: /var/lib/agenteye + - name: agenteye-mtls + mountPath: /etc/agenteye/tls + readOnly: true + livenessProbe: + exec: + command: ["agenteye-collector", "health"] + initialDelaySeconds: 10 + periodSeconds: 30 + + volumes: + # Shared event spool between app and collector. emptyDir is fine: + # events are transient and the collector drains them before pod + # termination on graceful shutdown. + - name: agenteye-spool + emptyDir: {} + # mTLS cert bundle, mounted read-only into the collector only. + - name: agenteye-mtls + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: agenteye-mtls +``` + +`agenteye-collector-api-key` Gizlisi collector'ın API anahtarını tutar (sağlama için bkz. [enterprise-docs/api-keys.md](/tr/agenteye/api-keys)). + +**Uygulayın:** + +```bash +kubectl apply -f agenteye-pod.yaml +``` + +### 4.3 Doğrulayın + +```bash +# Pod should be Running with 2/2 containers ready +kubectl get pods -n -l app=my-app-with-collector + +# Confirm the cert bundle was mounted +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- ls -l /etc/agenteye/tls/ +``` + +Beklenen: `client.crt`, `client.key`, `ca.crt` hepsi mevcut ve salt okunur, konteyner kullanıcısı tarafından sahip olunan. + +**Paylaşılan olay spoolunun her iki konteynerine görünür olduğunu doğrulayın:** + +```bash +# In the collector, should show the events/ and failed/ subdirs that +# the collector auto-creates on startup: +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- ls /var/lib/agenteye/ + +# In the app, should show the same directory contents: +kubectl exec -n deploy/my-app-with-collector \ + -c app -- ls /var/lib/agenteye/ +``` + +İki listeleme farklılaştırılırsa, volume her iki konteynerine monte edilmemiştir (veya `AGENTEYE_HOME` farklıdır); bkz. § Sorun Giderme. + +**Uçtan uca duman testi:** + +```bash +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- agenteye-collector flush +``` + +Beklenen: collector sıraya alınan tüm olayları yükler ve `Done: N/N uploaded, 0 failed.` özetini yazdırır. Spool boş ise `No pending files.` yazdırır ve hiçbir şeyi doğrulamadan çıkar — bu nedenle bunu yalnızca uygulamanız en az bir olay gönderdikten sonra çalıştırın. + +`flush` exit non-zero **yalnızca** yerel kurulum hataları için: eksik yapılandırma (hiçbir URL/anahtar çözümlenmemiş) veya okunulabilir/ayrıştırılabilir olmayan TLS sertifikası (§ Sorun Giderme kontrol edin). **Yanlış API anahtarı çıkış kodunu değiştirmez** — yükleme `401` alır, dosya `failed/` dizinine taşınır ve komut hala dosya başına `[FAILED] …` ve `Done: 0/N uploaded, N failed.` yazdırır ve `0` ile çıkar. Kötü bir anahtarı veya reddedilen yüklemeyi algılamak için, `Done:`/`[FAILED]` çıktısını okuyun veya dosyaları `$AGENTEYE_HOME/failed/` dosyasına inmek için denetleyin, çıkış kodu değil. + +--- + +## Sertifika yenileme + +İstemci sertifikası 90 gün için geçerlidir ve sona ermeden yaklaşık 15 gün önce otomatik olarak yenilenir; Exosphere daha sonra yenilenen bundle'ı aynı Secrets Manager gizlisine yayınlar. Oradan, pod içi akış şudur: + +1. Secrets Manager'ın gizli yeni bir `AWSCURRENT` sürümü alır. ARN ve ad değişmeden kalır. +2. `rotationPollInterval` içinde (varsayılan olarak 1 saat; bkz. § Aşama 2), CSI Driver yeni sürümü okur ve `/etc/agenteye/tls/` altındaki dosyaları yeniden yazar. +3. Collector sertifika dosyalarını **başlangıçta bir kez** yükler, bu nedenle işlem yeniden başlayana kadar önceki sertifikayı sunmaya devam eder. Yenilenen materyale geçmek için, collector'ı yeniden başlatın; yuvarlanan bir yeniden başlatma yeterlidir: + + ```bash + kubectl rollout restart deploy/my-app-with-collector -n + ``` + + Bunu otomatik hale getirmek için, `/etc/agenteye/tls/` izleyen bir sidecar ekleyin (örneğin `inotifywait` ile) ve dosyalar değiştiğinde yeniden başlatmayı tetikleyin. + +Önceki sertifika yenilemenin ardından yaklaşık 15 gün boyunca geçerli kaldığından, yeniden başlatmayı alımda kesintisiz olarak gerçekleştirebileceğiniz geniş bir pencereniz vardır. Exosphere yenilenen bundle'ı sizin için yayınlar; sizin tarafınızda tek rutin eylem, collector'ın bu pencere içinde yeniden başlatılmasını sağlamaktır. + +--- + +## Sorun Giderme + +| Belirti | Muhtemel Nedeni | Düzeltme | +|---|---|---| +| Pod `ContainerCreating` içinde takılı, olaylar `MountVolume.SetUp failed for volume "agenteye-mtls"` göster | CSI sağlayıcısı Secrets Manager'a ulaşamaz | IRSA'nın doğru bağlandığını kontrol edin: `kubectl describe sa agenteye-pod -n ` `eks.amazonaws.com/role-arn` ek açıklamasını göster. CloudTrail'de AssumeRole çağrısını kontrol edin. | +| Hata: `AccessDeniedException: not authorized to perform secretsmanager:GetSecretValue` | IAM politikası yanlış ARN'ye kapsamlıdır | Gizli ARN soneki rastgeledir; `agenteye/mtls-client/-*` joker karakterle kullanın, tam ARN değil. | +| AWS sağlayıcısından `ParameterNotFound` hatası | Gizli adı uyuşmazlığı `SecretProviderClass.objects[].objectName` ve Exosphere'nin teslim ettiği gizli arasında | `aws secretsmanager list-secrets --filters Key=tag-key,Values=AgentEyeCluster` ile tam adı doğrulayın. | +| `jmesPath` hatası, yalnızca bir dosya monte | JMESPath söz dizimi | JSON anahtarlarındaki noktalar çift alıntı gerektirir: `'"client.crt"'`, `client.crt` değil. | +| Collector günlükleri yenileme sonrası `tls: bad certificate` | CSI Driver yeni sürümü henüz yoklamadı veya collector başlangıçta yüklediği önceki sertifika ile çalışmaya devam ediyor | Monte edilen dosyaların güncellendiğini doğrulayın (`ls -l /etc/agenteye/tls/`), ardından collector'ı yüklemek için yeniden başlatın: `kubectl rollout restart deploy/my-app-with-collector -n `. Bkz. § Sertifika yenileme. | +| Collector konteyneri `no such file or directory: /etc/agenteye/tls/client.crt` ile crashloops | Volume ilk başlangıçta henüz doldurulmamış; başlangıç sondası çok agresif | Küçük bir ilk gecikme ekleyin veya dosyanın var olmasını bekleyen bir init konteyneri kullanın: `until [ -f /etc/agenteye/tls/client.crt ]; do sleep 1; done`. | +| CSI Driver pod `OOMKilled` | Birçok SecretProviderClass ile kümeler için varsayılan bellek sınırları çok düşük | Helm kurulumuna `--set linux.resources.limits.memory=200Mi` bump yapın. | +| Uygulama temiz çalışır, `agenteye-collector flush` rapor `No pending files.`, ancak AgentEye panosu hiçbir olay göstermez | Uygulama ve collector olay spoolunu paylaşmıyor | (a) her iki konteyner aynı `agenteye-spool` emptyDir'i aynı yolda monte eder ve (b) her ikisi de `AGENTEYE_HOME` o yola ayarla. § 4.3'ten iki `ls /var/lib/agenteye/` denetimini çalıştırın; listeleme eşleşmelidir. | + +**Önce grafiklenecek günlükler:** + +```bash +kubectl logs -n kube-system -l app=secrets-store-csi-driver --tail=100 +kubectl logs -n kube-system -l app=csi-secrets-store-provider-aws --tail=100 +kubectl describe pod -n -l app=my-app-with-collector +``` + +--- + +## Referans: pod içi diskte dosyalar + +Pod'un diskte iki veri yolu vardır: + +### mTLS sertifika bundle'ı: `/etc/agenteye/tls/` (CSI, salt okunur, collector yalnızca) + +Secrets Store CSI Driver tarafından AWS Secrets Manager'dan monte edilmiş. + +| Dosya | İçerik | Collector tarafından kullanıldığı gibi | +|---|---|---| +| `client.crt` | PEM kodlu istemci sertifikası | `AGENTEYE_TLS_CERT` | +| `client.key` | PEM kodlu özel anahtar | `AGENTEYE_TLS_KEY` | +| `ca.crt` | PEM kodlu CA sertifikası | `AGENTEYE_TLS_CA` (isteğe bağlı, yalnızca AgentEye sunucu sertifikası genel olarak güvenilir olmadığında) | + +Üçü de salt okunur olarak monte edilir ve konteyner kullanıcısı tarafından sahip olunan. Gizli döndüğünde CSI Driver tarafından yeniden yazılır. + +### Olay spoolü: `$AGENTEYE_HOME/` (emptyDir, her iki konteyner arasında paylaşılan okuma yazma) + +Adlandırılmış bir `emptyDir` volume `agenteye-spool` aracılığıyla paylaşılır. + +| Yol | Yazıldığı | Okunan | Amaç | +|---|---|---|---| +| `$AGENTEYE_HOME/events/*.jsonl` | Uygulama (AgentEye SDK) | Collector sweeper | SDK'nın yüklediği olay toplamları, yükleme beklemesi. | +| `$AGENTEYE_HOME/failed/` | Collector (yükleme başarısızlığında) | Siz (hata ayıklama sırasında) | Collector yeniden deneme sonrasında yüklemeyi başaramadığı JSONL dosyaları. | +| `$AGENTEYE_HOME/config.json` | Siz (isteğe bağlı) | Collector | İsteğe bağlı collector yapılandırma dosyası (env var'lar için alternatif). | + +`events/` ve `failed/` alt dizinlerinin ikisi de collector tarafından başlangıçta otomatik olarak oluşturulur; `initContainer` gerekli değildir. + +--- + +## İlgili belgeler + +- [enterprise-docs/collector-installation.md](/tr/agenteye/collector-installation): collector ikili seçenekleri, mTLS yapılandırma referansı, daemon modları. +- [enterprise-docs/kubernetes-deployment.md](/tr/agenteye/kubernetes-deployment): çok pod dağıtımı, sertifika yayınlama içerikler, yaşam döngüsü ve sona erme uyarıları. +- [enterprise-docs/api-keys.md](/tr/agenteye/api-keys): pod tarafından tüketilen collector API anahtarını sağlama. +- [enterprise-docs/troubleshooting.md](/tr/agenteye/troubleshooting): küme genelinde sorun giderme dizini. \ No newline at end of file diff --git a/docs/tr/agenteye/tenant-management.mdx b/docs/tr/agenteye/tenant-management.mdx new file mode 100644 index 00000000..1f640230 --- /dev/null +++ b/docs/tr/agenteye/tenant-management.mdx @@ -0,0 +1,167 @@ +--- +title: "Kiracı Yönetimi (organizasyonlar ve üyeler)" +description: "AgentEye Kiracı Yönetimi (organizasyonlar ve üyeler) belgelendirmesi." +--- + + +Tek bir AgentEye dağıtımı, birden fazla tamamen izole **organizasyonu** (kiracı) sunarak, bir örneğin farklı takımlar, iş birimleri veya müşterileri barındırabilir ve herhangi bir kiracının verilerini diğerine maruz bırakmaz. Tüm veri satırları (olaylar, değerlendirmeler, oturumlar, panolar, kaydedilen sorgular, uyarılar, API anahtarları ve üyeler) tam olarak bir kuruluşa aittir. Birincil izolasyon, uygulama kodunda zorlanır: her istek, açık `org_id` yüklemleriyle kendi kuruluşuyla kapsamlandırılır. ClickHouse'da — yüksek hacimli olaylar ve değerlendirmelerin bulunduğu yer — bu, güçlü motor düzeyinde zorlama ile desteklenir: her kuruluş, kuruluş başına satır politikası ile özel salt okunur bir ClickHouse kullanıcısı alır, böylece güvenilmeyen analitik SQL asla başka bir kiracının satırlarını okuyamaz. PostgreSQL'de, satır düzeyinde güvenlik, salt okunur sorgu yolunda (`/queries/run`) derinlemesine savunma ekler, uygulama düzeyinde bir filtre hiçbir zaman eksik olsa bile bu yolun görebileceği şeyi daraltır; sunucunun kendi yazma bağlantısı tablo sahibi olarak çalışır ve dolayısıyla aynı uygulama düzeyinde `org_id` kapsamlandırması aracılığıyla işler. + +Kiracı yaşam döngüsü operatör tarafından kontrol edilirken, üyelerin günlük yaptığı her şey panoda self-servis olarak kalır. Organizasyonlar ve üyeliklikleri **`agenteye-orgctl`** CLI ile oluşturulur ve yönetilir; bu, sunucu görüntüsünün içinde gemi alır ve **mevcut sunucu pod'unda çalışır**. Kiracı oluşturma ve silme, panonun ve HTTP API'sinin dışında tutulur: kiracı yaşam döngüsü için **HTTP API ve pano düğmesi yoktur**, bu nedenle uygulama yüzeyinden ziyade küme/pod kabuğu erişiminin arkasında kalır. + +Bir kuruluş içinde, üyeler tamamen panode ve API'de çalışırlar: oturum açarlar, ait oldukları kuruluşlar arasında geçiş yaparlar, kendi API anahtarlarını yönetirler, panolar ve kaydedilen sorgular oluştururlar ve kuruluşları için uyarılar yapılandırırlar. Bölüm temizdir: operatörler CLI aracılığıyla kiracıları ve üyelerini sağlarlar ve hizmet dışı bırakırlar; üyeler bir kiracı içindeki her şeyi UI aracılığıyla çalıştırırlar. + +> **Tek kiracılı dağıtımlar buna ihtiyaç duymaz.** Tek kiracılı bir kurulum, operatör işlemi olmadan çalışır. Tüm veriler, kullanıcılar ve anahtarlar, otomatik olarak sağlanan yerleşik `default` kuruluşunda bulunur. İkinci bir kuruluş eklemeye karar verdiğinizde bu kılavuza ihtiyacınız olur. + +--- + +## Ön Koşullar + +**İkinci** kuruluşunuzu oluşturmadan önce (yerleşik `default` kuruluşu hiçbir şeye ihtiyaç duymaz): + +- **PostgreSQL 15+.** Kuruluş-üyelik şeması, PostgreSQL 15+ gerektiren sütun listesi `ON DELETE SET NULL` yabancı anahtarı kullanır. İkinci bir kuruluş sağlamadan önce PostgreSQL'i yükseltin. +- **Güçlü, istikrarlı `ORG_CH_SECRET`.** Her kuruluşun ClickHouse şifresi `HMAC(ORG_CH_SECRET, org_id)` olarak türetilir, bu nedenle herkese açık yerleşik geliştirme varsayılanı herkese açık olarak türetilebilir kuruluş başına kimlik bilgileri verir. `agenteye-orgctl org create` **`ORG_CH_SECRET` ayarlanmamış veya yerleşik geliştirme varsayılanında bırakıldığı sürece çalışmaktan CABEDİR**. Önce kendi değerinizi ayarlayın ([Dağıtım → ortam değişkenleri](/tr/agenteye/deployment) ve Kubernetes'te, [Kubernetes kılavuzunun §2.6'sı](/tr/agenteye/kubernetes-deployment#26-multi-tenant-org-isolation-key-optional) bölümüne bakın). Tüm sunucu kopyaları arasında aynı tutun ve geçici olarak döndürmeyin; döndürmek, bir sonraki başlatmada yeniden sağlanana kadar her kuruluşun ClickHouse kullanıcısını sahipsiz bırakır. + +--- + +## CLI'yi Çalıştırma + +`agenteye-orgctl` **sunucuyla aynı görüntüde** gönderilir (`agenteye-server` ile birlikte). Bunun için ayrı bir pod, Job veya Deployment dağıtmayın; zaten çalışan sunucu pod'unun içinde exec yapın, böylece sunucunun kullandığı aynı `DATABASE_URL`, `CLICKHOUSE_URL` ve `ORG_CH_SECRET`'i okur. + +**Kubernetes:** + +```bash +kubectl -n agenteye exec deploy/server -- agenteye-orgctl +``` + +**Docker Compose:** + +```bash +docker compose exec server agenteye-orgctl +``` + +Aşağıdaki örnekler kısalık için boş `agenteye-orgctl `'i gösterir; her birinin başına dağıtımınızla eşleşen yukarıdaki iki satırdan hangisi ekleme yapın. + +--- + +## Komut referansı + +### Organizasyonlar + +| Komut | Ne yaptığı | +|---|---| +| `org create --slug --name ` | Yeni bir organizasyon oluştur. `ORG_CH_SECRET` ayarlanmamış veya yerleşik geliştirme varsayılanında bırakıldı ise çalışmaktan kaçın (önce kendi değerini ayarlayın, Ön Koşullara bakın). Kuruluşun salt okunur ClickHouse kullanıcısı + satır politikasını sağlar. | +| `org list` | Tüm organizasyonları listele (slug, ad ve yaşam döngüsü durumu). | +| `org rename --slug --name ` | Organizasyonun görüntü adını değiştir. Slug (URL'ler ve anahtarlarda kullanılan) değiştirilmez. | +| `org delete --slug ` | Kuruluşu **yazılı olarak sil** ve ClickHouse kullanıcısını kaldır. Veriler **korunur**. Bu, erişimi iptal eder ve kuruluş başına ClickHouse kimlik bilgisini serbest bırakır, ancak olayları silmez. Operatörler tarafından geri alınabilir; temizleme öncesi güvenli ilk adım. | +| `org purge --slug ` | **Geri alınamaz veri silme.** Kuruluş zaten `delete` edilmiş olmalı. Yerleşik `default` kuruluşta hiçbir zaman izin verilmez. Kiracının verilerinin yok edilmesi gerektiğinden emin olduğunuz zaman kullanın. | + +### Üyeler + +| Komut | Ne yaptığı | +|---|---| +| `member add --org --email [--set ] [--add perm1,perm2] [--remove perm3] [--protected]` | Bir kuruluşa üye ekle. İsteğe bağlı olarak yerleşik izin setinden başla, ardından bireysel izinleri ekle/kaldır. `--protected`, üyeyi sabitler, böylece pano onları kaldıramaz veya indirgemez (aşağıya bakın). Yeni üye, panosunda ilk oturum açışlarında OTP alır. | +| `member list --org ` | Kuruluşun üyelerini listele. Çıktı sütunları `EMAIL`, `SET` (üyenin başladığı yerleşik set, veya `-`), `PROT` (üyenin korunup korunmadığı) ve `PERMISSIONS` (etkili izinleri) dir. Sondaki `*` ile gösterilen bir e-posta, örnek yöneticisidir; tüm kuruluşlara erişimi vardır. | +| `member update --org --email [--set ...] [--add ...] [--remove ...] [--protected \| --unprotect]` | Üyenin izinlerini ve/veya korunan bayrağını değiştir. `--set`, yerleşik setinden değiştirir; `--add` / `--remove` bireysel izinleri ayarlar; `--protected` / `--unprotect` korumayı değiştirir. Yalnızca `--protected`/`--unprotect` geçirmek (izin bayraklarısız) korumayı tek başına değiştirir ve mevcut izinleri dokunulmadan bırakır. | +| `member remove --org --email ` | Üyeyi kuruluştan kaldır. Üye korunmuşsa reddedilir; önce `--unprotect` yapın. (Bir kişi birden fazla kuruluşun üyesi olabilir; bu yalnızca adlandırılan kuruluşu etkiler.) | + +Bir kişi, **farklı** izinlerle birden fazla kuruluşun üyesi olabilir, örneğin bir kuruluşta yönetici ve diğerinde salt okunur. Her üyelik, kuruluş başına bağımsız olarak yönetilir: bir kuruluştaki bir kişinin izinleri verme veya değiştirme, başka kuruluştaki üyeliğini etkilemez. + +### Korunan üyeler (kaldırılamayan kuruluş yöneticisi) + +Koruma, bir kuruluşun kendisini yönetimden asla yanlışlıkla kilitlemeyeceğini garanti eder. Varsayılan olarak, bir kuruluşun kendi yöneticileri, panonun self-servis kullanıcılar sayfası aracılığıyla birbirini ekleyebilir ve kaldırabilirler, bu nedenle son yöneticiyi kaldırabilir ve kuruluşu onu yönetebilecek hiç kimsenin olmadığı halde bırakabilirler. + +![Kullanıcılar sayfası: her pano kullanıcısı için e-posta, verilen izinler ve düzenle/devre dışı bırak denetimleri içeren bir kart](/agenteye/images/users.png) + +Bunu önlemek için, bir üyeyi **korunan** olarak işaretleyin: + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member add --org acme --email owner@acme.example --set admin --protected +``` + +Korunan bir üye **panonun aracılığıyla kaldırılamaz veya indirgenemez**; bu işlemler bir hata döndürür. Yalnızca bir operatör onları değiştirebilir ve yalnızca bu CLI aracılığıyla: ilk olarak `member update --org acme --email owner@acme.example --unprotect`'i çalıştırın, ardından kaldırın veya indirgeyin. Bu, her kuruluşun kendi üyelerinin kilitleyemeyeceği en az bir yöneticiyi tutmayı garanti ederken, kiracı kontrolünü operatör tarafından tutarak. Koruma **kuruluş başına**'dır; birini bir kuruluşta korumak, başka kuruluştaki üyeliğini etkilemez. + +### Yerleşik izin setleri + +`--set`, kuruluş başına uygulanan üç yerleşik setten birini kabul eder: + +| Set | Amaçlanan hedef | +|---|---| +| `admin` | Kuruluş içinde tam erişim, kuruluşun API anahtarlarını ve kullanıcılarını yönetme dahil. | +| `standard` | Günlük kullanım: sorguları oku ve çalıştır, panolar oluştur, olayları kabul et. | +| `read-only` | Kuruluşun verileri ve panolarına salt görüntüleme erişimi. | + +`--set` ile setinden başlayın, ardından [API Anahtarları](/tr/agenteye/api-keys) bölümünde listelenen bireysel izin belirteçlerini kullanarak `--add` / `--remove` ile ince ayar yapın. İzin belirteçlerinin kendileri API anahtarları için kullanılanlara özdeştir. + +--- + +## Çalışılmış örnek + +Yeni `acme` kiracısını sağlayın, ilk yöneticisini ekleyin, bir anahtar oluşturmalarını sağlayın, sonra kuruluşu hizmet dışı bırakın. + +**1. Kuruluşu oluştur** (`ORG_CH_SECRET` zaten güçlü, istikrarlı bir değer olarak ayarlanmış olmalı, ayarlanmamış veya yerleşik geliştirme varsayılanında değil): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org create --slug acme --name "Acme Corp" +``` + +**2. İlk üyeyi kuruluş yöneticisi olarak ekle:** + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member add --org acme --email alice@acme.example --set admin +``` + +Alice, panoda ilk oturum açışında bir OTP alır. Bundan sonra tamamen kuruluşunun URL öneki altında UI'de çalışır (örn. `/acme/sessions`). + +**3. Kuruluş başına API anahtarı oluştur (panoda):** + +Operatör CLI'den kuruluş başına veri anahtarları oluşturmaz. Alice (veya `keys:create` izni olan herhangi bir kuruluş üyesi) panonun **Anahtarlar** sayfasından `acme` kuruluşu için toplayıcı / pano anahtarları oluşturur. Oluşturduğu her anahtar otomatik olarak kuruluşuyla damgalanır ve yalnızca `acme` verilerini okuyabilir veya yazabilir. [API Anahtarları](/tr/agenteye/api-keys) bölümüne bakın. + +**4. Üyeyi sonra ayarla:** + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member update --org acme --email alice@acme.example --add alerts:write + +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member list --org acme +``` + +**5. Kuruluşu yazılı olarak sil** (erişimi iptal eder + ClickHouse kullanıcısını kaldırır; veriler korunur): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org delete --slug acme +``` + +**6. Kuruluşu temizle** (geri alınamaz; yalnızca yazılı silme sonrası; asla `default` kuruluşu değil): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org purge --slug acme +``` + +Docker Compose'ta, her `kubectl -n agenteye exec deploy/server --` önekini `docker compose exec server` ile değiştirin. + +--- + +## Sorumluluk Bölümü + +Kuruluş üyesinin günlük ihtiyaç duyduğu her şey panoda ve API'de self-servis olarak, geçerli kuruluşlarıyla otomatik olarak kapsamlandırılır: + +- **Kuruluş başına API anahtarları** panonun anahtarlarının yanı sıra kuruluş üyeleri tarafından oluşturulur ve yönetilir (veya `keys:create` taşıyan bir anahtar ile anahtarlar API'si aracılığıyla). CLI veri anahtarlarını oluşturmaz. [API Anahtarları](/tr/agenteye/api-keys) bölümüne bakın. +- **Kuruluş değişimi** panoya yerleştirilir; üyeler, kuruluş değiştiricisinden ait oldukları kuruluşlar arasında geçiş yaparlar ve kuruluş kapsamlı sayfalar `//…` altında bulunur. +- **Panolar, kaydedilen sorgular, uyarılar ve tüm veri kullanımı** tamamen UI ve API'de meydana gelir, üyenin geçerli kuruluşuyla kapsamlandırılır. + +`agenteye-orgctl` kullanan operatör, yalnızca kuruluş + üye **yaşam döngüsünü** sahiplenler: kuruluş oluştur / yeniden adlandır / sil / temizle ve üye ekle / listele / güncelle / kaldır. + +--- + +## Ayrıca Bakınız + +- [Dağıtım](/tr/agenteye/deployment): `ORG_CH_SECRET` ve sunucu ortamının geri kalanı. +- [Kubernetes Dağıtımı](/tr/agenteye/kubernetes-deployment): §2.6, ilk çok kiracılı kuruluşunuzdan önce `agenteye-org-ch-secret` Gizli'sini oluşturur. +- [API Anahtarları](/tr/agenteye/api-keys): kuruluş başına anahtar modeli ve `--add` / `--remove` tarafından kullanılan izin belirteçleri. +- [Sorun Giderme](/tr/agenteye/troubleshooting): çok kiracılı sağlama ve ClickHouse izolasyonu sorunları. \ No newline at end of file diff --git a/docs/tr/agenteye/troubleshooting.mdx b/docs/tr/agenteye/troubleshooting.mdx new file mode 100644 index 00000000..1fb4b4dc --- /dev/null +++ b/docs/tr/agenteye/troubleshooting.mdx @@ -0,0 +1,613 @@ +--- +--- +title: "Sorun Giderme" +description: "AgentEye Sorun Giderme belgeleri." +--- + + +Bu rehber, üretimde karşılaşabileceğiniz semptomları somut bir tanı ve çözüme eşleştirerek, zaten sahip olduğunuz araçlardan sorunları çözmekte yardımcı olur. Ek gözlemlenebilirlik altyapısı kurmanız gerekmez. Sunucu, toplayıcı, pano, yapay zeka asistanı, Python SDK, sağlık ve sertifika izleme, yedeklemeler, ClickHouse tabanlı analitikler ve çok kiracılılığı kapsar. + +Pano sayfaları `//…` altında kuruluş kapsamlıdır ve etkinlik akışı kuruluş ana sayfasıdır (`//`). Bu rehberdeki sayfa adları (örneğin `/sessions`, `/queries`) bu kuruluş kapsamlı rotaları ifade eder. + +--- + +## Günlükleri Görüntüleme + +AgentEye günlüğe kaydetme veya izleme yığını içermez. Hem sunucu hem de pano yapılandırılmış günlükleri **stdout** dosyasına yazar, böylece `kubectl` veya `docker` ile doğrudan okuyabilirsiniz; toplayıcıya gerek yoktur. + +### Kubernetes + +Sunucu ve pano için canlı günlükleri takip edin: + +```bash +kubectl logs -n agenteye -l app=server -f --timestamps +kubectl logs -n agenteye -l app=dashboard -f --timestamps +``` + +Yararlı varyantlar: + +| Amaç | Komut | +|---|---| +| Son 200 satır (izleme yok) | `kubectl logs -n agenteye -l app=server --tail=200 --timestamps` | +| Önceki kilitlenmeden günlükler | `kubectl logs -n agenteye --previous` | +| Tüm çoğaltmaları aynı anda takip et | `kubectl logs -n agenteye -l app=server --max-log-requests=10 -f` | +| Postgres (StatefulSet) | `kubectl logs -n agenteye postgres-0 -f` | + +### Docker Compose + +```bash +docker logs -f agenteye-server +docker logs -f agenteye-dashboard +``` + +### Pano ve sunucuyu arasında tek bir isteği ilişkilendirme + +Her pano isteği bir `request_id` ile etiketlenir ve `x-request-id` başlığı aracılığıyla sunucuya iletilir. Sunucu, yanıt başlıklarında ve bu istek için yayınladığı her günlük satırında okunur. Bir isteği uçtan uca izlemek için: + +1. Yanıt başlığından kimliği yakalayın, örneğin: + ```bash + curl -i https://dashboard.example.com/api/events | grep -i x-request-id + # x-request-id: 9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a + ``` +2. Her iki pod'un günlüklerinde o kimliği arayın: + ```bash + REQ=9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a + kubectl logs -n agenteye -l app=dashboard --tail=5000 | grep "$REQ" + kubectl logs -n agenteye -l app=server --tail=5000 | grep "$REQ" + ``` + +Panonun `proxy passthrough`, `withAuth: authorized` ve `upstream response` satırlarını sunucunun `http request received` / `http request completed` çifti ile birlikte göreceksiniz; hepsi aynı `request_id` paylaşır. + +### JSON günlükleri ve `jq` + +Panonun `NODE_ENV=production` olduğunda varsayılan olarak açık olan `AE_LOG_JSON=1` ayarlayın. Satır başına bir JSON nesnesi yayınlar. Sonra yapısal olarak filtreleyin: + +```bash +kubectl logs -n agenteye -l app=dashboard --tail=5000 \ + | jq 'select(.level == "warn" or .level == "error")' + +kubectl logs -n agenteye -l app=dashboard --tail=5000 \ + | jq 'select(.route == "POST /api/keys")' +``` + +Rust sunucusu izleme `key=value` çiftleri yayınlar; `jq` olmadan iyi çalışır: + +```bash +kubectl logs -n agenteye -l app=server --tail=5000 | grep 'status=5' # 5xx +kubectl logs -n agenteye -l app=server --tail=5000 | grep 'actor_key_id=' +``` + +### Ayrıntı düzeyini artırma + +| Bileşen | Ortam değişkeni | Örnek | +|---|---|---| +| Sunucu | `RUST_LOG` | `RUST_LOG=debug` veya `RUST_LOG=agenteye_server=debug,info` | +| Pano | `AE_LOG_LEVEL` | `AE_LOG_LEVEL=debug` | + +Sunucuda `debug`, kimlik doğrulama başına `api key authenticated` satırı ekler. Panoda `debug`, `upstream request`, `session validated` ve `proxy passthrough` satırları ekler. + +### Günlük tutma + +Konteyner stdout geçicidir; kubelet günlük dosyalarını (konteyner başına varsayılan ~10 MiB) döndürür ve diskte küçük bir sayı tutar. Pod silindiğinde günlükler ortadan kalkar. Daha uzun tutma veya çapraz pod araması gerekiyorsa, kümenizi `/var/log/containers/` dosyasını takip eden bir günlük toplayıcısına (Loki, CloudWatch, Cloud Logging, Datadog, vb.) yönlendirin. AgentEye belirli bir seçimi gerektirmez veya öne sürmez. + +--- + +## Kimlik Doğrulama Sorunları + +### `docker pull` "unauthorized" hatasıyla başarısız + +Docker'ı `AGENTEYE_TOKEN` ile GHCR'a karşı kimlik doğruladığınızdan emin olun: + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +Token `agenteye-enterprise` kuruluşunda `read:packages` izinine sahip olmalıdır. Tokeniniz işe yaramazsa `support@exosphere.host` ile iletişim kurun. + +### `gh release download` 404 veya 401 döndürüyor + +- `AGENTEYE_TOKEN` kabuğunuzda dışa aktarıldığını doğrulayın: `echo $AGENTEYE_TOKEN` +- `GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download ...` kullanmakta olduğunuzu doğrulayın (`gh` CLI, `GITHUB_TOKEN` okuyor) +- Token `agenteye-enterprise/releases` üzerinde `contents:read` gerekir + +--- + +## Sunucu Sorunları + +### Sunucu "invalid port number" ile başarısız + +`POSTGRES_PASSWORD` (veya başka bir kimlik bilgisi) URL'ye özel karakterler içeriyor (`/`, `+`, `=`) ve `DATABASE_URL` ayrıştırmasını kırarıyor. Hex kodlamasını kullanarak parolayı yeniden oluşturun: + +```bash +NEW_PASS=$(openssl rand -hex 24) +``` + +Sonra Kubernetes gizlisini güncelleyin ve Postgres içindeki parolayı değiştirin (veya Docker Compose için `.env` dosyasını yeniden oluşturun) ve sunucuyu yeniden başlatın. [enterprise-docs/kubernetes-deployment.md](/tr/agenteye/kubernetes-deployment) § "PostgreSQL credentials" içindeki tam adımları görebilirsiniz. + +### Sunucu başlangıçta hemen çıkıyor + +Konteyner günlüklerini kontrol edin: + +```bash +docker logs agenteye-server +``` + +Yaygın nedenler: +- `DATABASE_URL` ayarlanmadı veya hatalı biçimlendirildi: sunucu hatayı günlüğe kaydeder ve çıkar. +- Postgres ulaşılamıyor: Postgres konteynerinin veya yönetilen DB'nin çalıştığını ve ana bilgisayar/bağlantı noktasının doğru olduğunu doğrulayın. +- Göçler başarısız: SQL hataları için günlükleri kontrol edin. + +### `GET /health` 200 olmayan değer döndürüyor veya zaman aşımına uğruyor + +Sunucu ilk başlangıçta göçler çalıştırıyor olabilir. Birkaç saniye bekleyin ve yeniden deneyin: + +```bash +curl http://localhost:8080/health +``` + +Sorun devam ederse, hataların `docker logs agenteye-server` kontrol edin. + +### `GET /ready` 503 döndürüyor + +`/ready`, hazırlık sondası; sunucu **Postgres veya ClickHouse'a** ulaşamadığında `503` döndürür. Gövde, hangi bağımlılığın başarısız olduğunu adlandırır: + +```bash +curl -s http://localhost:8080/ready +# {"status":"not_ready","checks":{"postgres":"ok","clickhouse":"down","redis":"ok"}} +``` + +`down` olarak rapor ettiği bağımlılığı düzeltin: ClickHouse/Postgres pod'u `Running` durumunda mı? `CLICKHOUSE_URL` / `DATABASE_URL` doğru ve ulaşılabilir mi? Kubernetes'te pod `/ready` iyileşene kadar `NotReady` okunur; bu beklenen ve sağlık izlemesinin uyarı verdiği tam sinyaldir. Redis hiçbir zaman bir neden değildir: rapor edilir ancak hazırlığı başarısız kılmaz. + +### Toplayıcı 401 Unauthorized döndürüyor + +Toplayıcının API anahtarı `events:add` iznine sahip değildir veya anahtar devre dışı bırakılmıştır. Doğru izinle yeni bir anahtar oluşturun: + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{"name":"new-collector","permissions":["events:add"]}' +``` + +### Doğrulanmış istekler aniden yavaş (~200ms yerine ~5ms) + +Bu, `REDIS_URL` ayarlanırken Redis'in aşağıda olduğunun belirtisidir. Her önbellek çağrısı 100ms sonra zaman aşımına uğrar ve Postgres'e döner; kimlik doğrulama ve OTP yollarında istek iki tane bu tür geri dönüş yapar. + +Sunucu günlüklerinde doğrulayın: + +``` +auth cache: L2 get failed error=redis call timed out +``` + +Çözüm: + +1. `redis-cli -h ping` ile Redis'in küme ağında ulaşılabilir olduğunu doğrulayın. +2. Redis kısa bir süre aşağıdaydı ve şimdi geri döndüyse, **sunucu pod'larını yeniden başlatın**. `redis::aio::ConnectionManager` temel bağlantı bıraktıktan sonra güvenilir bir şekilde yeniden kurulmaz; pod yeniden başlatması yeni bağlantıyı temiz bir şekilde seçer. Aynı şey pano için de geçerlidir. +3. Şu an Redis çalıştırmak istemiyorsanız, dağıtımda `REDIS_URL` ayarını kaldırın ve yeniden başlatın. Her iki hizmet de önbellek olmadan çalışır (doğruluk korunur; gecikme önceki Redis tabanına döner). + +### Sunucu günlüklerde `OTP request rate-limited` raporları veriyor ancak kullanıcı sadece bir kez denedi diyor + +Redis'in ulaşılamaz olup olmadığını kontrol edin. Geri dönüş yolu `SELECT COUNT(*) FROM otp_codes WHERE created_at > now() - interval '15 minutes'` kullanır, bu daha önce oluşturulmuş OTP satırlarını görür. Kullanıcı bir saatlik "Yeniden Gönder" tıklaması yaptıysa, 15 dakikalık pencere yine de ≥5 kod içerebilir. Pencere döndükten sonra bekleme veya `DELETE FROM otp_codes WHERE user_id = $1 AND created_at > now() - interval '15 minutes'` (operatör konsolu) çalıştırarak çözün. + +### `ALLOWED_EMAILS` / `SESSION_TTL_SECS` / `OTP_TTL_SECS` değiştirdim ve yeniden başlattım; hiçbir şey olmadı + +Bu ortam değişkenleri **yalnızca ilk önyükleme tohumları**. `settings` tablosu eşleşen anahtar için bir satıra sahip olduğunda, bu satır gerçek kaynaktır; ortam değişkeni ilk önyüklemede bir kez okunur ve sonraki her yeniden başlattırmada göz ardı edilir. + +İlk önyüklemeden sonra bunları değiştirmek için panoya giriş yapın ve `/settings` altında düzenleyin. Değişiklik saniyeler içinde tüm çoğaltmalar arasında uygulanır; yeniden başlatma gerekmez. + +Ortamdan yeniden tohumlamayı zorlamanız gerekiyorsa (nadiren, genellikle yalnızca geliştirmede yararlı), `DELETE FROM settings WHERE key = ''` çalıştırın ve sunucuyu yeniden başlatın. Önyükleme, sonraki önyüklemede mevcut ortam değişkeni değerini seçer. `/settings` aracılığıyla düzenleme, üretimdeki desteklenen yoldur. + +--- + +## Toplayıcı Sorunları + +### Toplayıcı başlıyor ancak etkinlikler panoda görünmüyor + +1. Toplayıcının çalıştığını doğrulayın: `systemctl status agenteye-collector` (Linux) veya işlemi kontrol edin. +2. `AGENTEYE_URL` `http(s)://your-server-host:8080/events` (not: `/events` yolu) işaret ettiğini doğrulayın. +3. Hemen çıktı görmek için bir kerelik flush çalıştırın: + ```bash + agenteye-collector flush + ``` +4. Python SDK'nın aslında dosya yazıp yazmadığını kontrol edin: `ls ${AGENTEYE_HOME:-~/.agenteye}/events/` +5. `${AGENTEYE_HOME:-~/.agenteye}/failed/` içinde dosyalar varsa, yüklemeler başarısız oluyor. Toplayıcı günlüklerinde hatayı kontrol edin; büyük olasılıkla 4xx (kötü anahtar veya URL) veya ağ sorunu. + +### Dosyalar `$AGENTEYE_HOME/events/` içinde birikmiş ve yüklenmemiş + +- Toplayıcı çalışmıyor olabilir. Başlatın: `agenteye-collector start`; başlangıçta önceden varolan etkinlikleri otomatik olarak temizler. +- Toplayıcı durumunu kontrol edin: `agenteye-collector health` +- Toplayıcı çalışıyor ancak sunucuya ulaşamıyor olabilir. Toplayıcı ve sunucu ana bilgisayarları arasında güvenlik duvarı kurallarını kontrol edin. + +### `$AGENTEYE_HOME/failed/` içinde dosyalar + +Dosyalar tüm yeniden deneme denemelerinin tükendiğinden sonra `failed/` dizinine taşınır (varsayılan: 5 deneme, üstel geri kapatma). Bu, ya: +- Sunucu 4xx hatası döndürdü (kötü anahtar, yanlış URL veya yük sorunu) +- Sunucu, tüm yeniden deneme penceresi boyunca ulaşılamadı + +Temel sorunu düzeltin, ardından el ile yeniden kuyruğa alın: + +```bash +mv ${AGENTEYE_HOME:-~/.agenteye}/failed/*.jsonl ${AGENTEYE_HOME:-~/.agenteye}/events/ +agenteye-collector flush +``` + +### Toplayıcı her yüklemede `network error` raporları veriyor (TLS anlaşması başarısız) + +`AGENTEYE_URL` aleyhine `curl -k` başarılı olursa ancak toplayıcı ikili `error sending request for url (...)` ile her yüklemeyi başarısız olursa, AgentEye sunucusu, halka açık güvenilir bir CA tarafından imzalanmayan bir TLS sertifikası sunuyor. + +**Üretim yolu**, `deploy/base/certificates/domain.env` içinde yapılandırılmış ACME alımı ana bilgisayarıdır (bkz. [`kubernetes-deployment.md`](/tr/agenteye/kubernetes-deployment) Aşama 3.1 / 4.2). `INGEST_DOMAIN` halka açık Traefik LB'sine çözüldükten ve cert-manager Let's Encrypt sertifikasını verdikten sonra, toplayıcılar sunucu sertifikasını sistem güven deposuna karşı **`AGENTEYE_TLS_CA` olmadan** doğrularlar; eski kendi imzalı dağıtıma karşı ayarlandıysa onu toplayıcı yapılandırmasından temizleyin. + +**Belirti: toplayıcı dün çalıştı, ~90 günlük boşluğundan sonra bugün başarısız.** Bu, dağıtımın yine de `ingest-tls` için eski `selfsigned` vericisinde olduğu anlamına gelir. 90 günlük sertifika döndürüldü ve sabitlenmiş CA dosyası eski. Şu anki sunucu sertifikasını çıkararak ve `AGENTEYE_TLS_CA` güncelleyerek kısa vadede çözün: + +```bash +kubectl get secret ingest-tls-cert -n agenteye \ + -o jsonpath='{.data.tls\.crt}' | base64 -d > /etc/agenteye/server-ca.crt +``` + +```bash +export AGENTEYE_TLS_CA=/etc/agenteye/server-ca.crt +agenteye-collector flush +``` + +`AGENTEYE_TLS_CA` ek bir güven yerleri ekler; standart genel kökler yine de güvenilir. + +### `ingest-tls` Sertifikası dağıtımdan sonra `Ready: False` takılı + +```bash +kubectl describe certificate ingest-tls -n agenteye +``` + +`Events` ve başvurulan `Order` / `Challenge` bakın. Yaygın nedenler: + +- **DNS halka açık LB'ye çözülmüyor.** HTTP-01 doğrulayıcı `INGEST_DOMAIN` konumuna ulaşamıyor. `dig +short INGEST_DOMAIN` ile doğrulayın; `traefik-public` LoadBalancer'ın `EXTERNAL-IP` ile aynı adrese çözülmelidir. cert-manager DNS yayıldıktan sonra otomatik olarak yeniden dener; Sertifikayı silmek gerekmez. +- **Yük dengeleyici / güvenlik grubunda port 80 engellendi.** HTTP-01, Let's Encrypt'in genel doğrulayıcılarından port 80'e erişilebilirlik gerektirir. Yukarı akış WAF veya SG kısıtlıysa, açın (Traefik yapılandırması HTTPS'e yeniden yönlendirir ancak Boulder yeniden yönlendirmeyi izler ve yanıtı kabul eder). +- **`dnsNames` değiştirilmedi.** `kubectl get certificate ingest-tls -n agenteye -o jsonpath='{.spec.dnsNames}'` `INGEST_DOMAIN_PLACEHOLDER` gösteriyorsa, `domain.env` adımını atlattınız; `domain.env.example` dosyasından oluşturun ve yeniden uygulayın. +- **Let's Encrypt tarafından hız sınırlandırıldı.** Aynı ana bilgisayar için tekrarlanan başarısız siparişler, yinelenen sertifika veya başarısız doğrulama limitini tetikler. Yeniden denemeden önce en az bir saat bekleyin; tam hız sınırlaması iletisi için Sipariş durumunu kontrol edin. + +### `dashboard-tls` Sertifikası `Ready: False` takılı / tarayıcı hala uyarı gösteriyor + +Yukarıdaki `ingest-tls` ile aynı tanı akışı (`kubectl describe certificate dashboard-tls -n agenteye`); DNS, port-80, yer tutucu ve hız sınırlaması nedenleri tümü geçerlidir, artı iki panoya özel: + +- **`DASHBOARD_DOMAIN` yanlış LoadBalancer'a çözülüyor.** Halka açık alma LB'si değil, *pano* Traefik LB'sine işaret etmelidir. Ana bilgisayar adını `dig +short` yapın ve pano LB adresine karşı karşılaştırın. +- **Pano Traefik örneği sorunu sunulayamıyor.** Paket Traefik LB adresine erişebilir olabilir. Bundled pano değerleri dosyası ile kurulmalıdır; cert-manager'ın HTTP-01 çözücüsü için kapsamlı Ingress sağlayıcısını etkinleştirir. Olmadan çözücü yönlendirilmez ve Sipariş sonsuza kadar `pending` kalır. Sağlanan değerleri kullanarak örneği yükseltin; bekleyen meydan sonra otomatik olarak tamamlanır. +- **LoadBalancer IP'yi kısıtladı.** Kaynak aralıkları port 80'e de uygulanır; bu, Let's Encrypt'in doğrulayıcılarını engeller — hem ilk verme hem de her ~75 günlük yenileme. LB'yi yeniden açın veya kilitlemeden önce destek ile DNS-01 çözücüyü koordine edin. + +Verme başarısız olurken, pano önceki sertifikasını (veya yeni bir kurulumda ingress varsayılanı) sunmaya devam eder — erişim tarayıcı uyarısı tarafından düşürülür, hiçbir zaman düşmez. + +### CLI, pano güvenilir bir sertifika aldıktan sonra TLS doğrulamasını atlıyor + +`--insecure` `cli.json` adresinde oturum açma sırasında kalıcıdır. Pano halka açık güvenilir bir sertifika sunduğunda, `agenteye --base-url https:// --secure login` ile oturum açın; doğrulama geri açılır ve başlangıç uyarısı kaybolur. + +--- + +## Pano Sorunları + +### `ADMIN_EMAIL` kullanıcısını devre dışı bırakamaz veya düzenleyemez + +Tasarım gereğidir. `ADMIN_EMAIL` ile eşleşen kullanıcı, her sunucu başlangıcında korumalı olarak işaretlenir: pano bu satırın Devre Dışı Bırak düğmesini gizler ve API bu satıra karşı `DELETE /users/:id` ve `PUT /users/:id` `403 Forbidden` ile reddeder. Bir veritabanı tetikleyicisi ayrıca korumalı satırı devre dışı bırakacak doğrudan `UPDATE` deyimlerini reddeder. + +Önyükleme yöneticisini döndürmek için, ortamınızda `ADMIN_EMAIL` değiştirin ve sunucuyu yeniden başlatın. Yeni e-posta korumalı olarak üretilir. Önceki yönetici, veritabanında açıkça kaldırıncaya kadar korumalı bayrağı saklar (genellikle uygun, önceki e-posta açıkça kaldırıncaya kadar geçerli bir yönetici olduğundan). + +### Pano hiçbir etkinlik göstermediği + +1. Pano ortam değişkenlerindeki sunucu URL'sinin ve API anahtarının doğru olduğunu doğrulayın (`AGENTEYE_SERVER_URL`, `AGENTEYE_API_KEY`). +2. Pano API anahtarının `events:read` izinine ihtiyacı vardır. +3. Etkinliklerin gerçekten alındığını doğrulayın: `curl http://your-server:8080/events -H "Authorization: Bearer $ADMIN_KEY"` + +### `/errors` boş ancak `/events` kırmızı satırlar gösteriyor + +Daha yeni SDK sürümleri hataları `agent_end` / `tool_result` / `hook_completed` olayları olarak ve `event_type: "error"` satırı olarak, taşıda `outcome: "error"` ile yayınlarlar. `/errors` sayfası şimdi her ikisini de eşleştirir: `/events` akışının kırmızı olarak gösterdiği herhangi bir satır (açık `event_type='error'`, yük `outcome`/`status` başarısız kümede, `is_error: true` veya gerçek `error` alanı) `/errors` altında görünür. Daha önce `/events` kırmızı satırlar görüyorken "bu pencerede hata yok" görüştüyseniz, pano + sunucuyu birlikte yükseltin (genişletilmiş filtre `GET /events` üzerinde `errored=true` olur) ve iki görünüm anlaşacaktır. + +### `/models`, `/tools` veya `/hooks` geniş zaman aralıklarında yavaş veya yükleme başarısız + +**Belirti:** büyük bir etkinlikler tablosu (milyonlarca satır) üzerinde, `/models`, `/tools` veya `/hooks` açma — veya zaman aralığını `7d`, `30d` veya `all` olarak genişletme — grafikler döner ve sonra bir yükleme hatası gösterir. Sunucu `latency_aggregate` isteği için ClickHouse `MEMORY_LIMIT_EXCEEDED` (Kod 241) veya sorgu zaman aşımını günlüğe kaydeder. + +**Neden:** daha eski derlemeler bu sayfaların gecikme ve dağıtım toplamalarını tam ham olay `payload` okuyan ve istek/yanıt olaylarını bellek içi sırala ve birleştirme ile eşleştiren bir sorgu ile hesapladı. Tepe sorgusu belleği bu nedenle pencere boyutuyla büyüdü, böylece meşgul bir kiracıda geniş bir aralık ClickHouse'un sorgu başına bellek tavanını aşabilir. + +**Düzeltme:** bu düzeltmeyi içeren bir derlemeyü yükseltin. Toplamay artık yalnızca kompakt tanıtılan sütunları okur ve olayları akış birleştirmesiyle eşleştirir, böylece tepe belleği artık ham yükle ölçeklenmez — geniş pencereler bellek tavanında yer alır ve kesirleri tamamlar. İyileştirme tamamen sorgu tarafıdır: tüm mevcut verilere sonraki sayfa yüklemesinde uygulanır; yeniden alım veya geri doldurma yok. + +### Pano yükleme başarısız / boş sayfa + +Pano konteyner günlüklerini kontrol edin: + +```bash +docker logs agenteye-dashboard +``` + +En yaygın neden `AGENTEYE_SERVER_URL` veya `AGENTEYE_API_KEY` eksik veya ulaşılamayan bir sunucuyu işaret etmektir. + +### Pano analitikleri / telemetrisi + +Pano, varsayılan olarak anonim ürün kullanımı analitiklerini PostHog'a gönderir; pano kendi `/ingest` yolu (için `https://us.i.posthog.com` ters proxy) aracılığıyla yönlendirilir. İlk taraf olarak göndermek, tarayıcı adblocker'larının bunları bırakmaması anlamına gelir. Bu, panonun temel işlevselliğinden bağımsızdır: + +- **Pano konteynerı** (tarayıcı değil) PostHog'a ulaşıyor. Giden erişimi `https://us.i.posthog.com` engelliyse, telemetrisi sessiz olarak no-op; pano normal çalışır ve kullanıcılara hata yüzeylenmez. +- Agent, oturum veya etkinlik verisi hiçbir zaman dahil değildir, yalnızca pano kullanıcı arayüzü kullanımı. +- Telemetriyi tamamen devre dışı bırakmak için pano konteynerında `AE_ANALYTICS_DISABLED=1` ayarlayın ve yeniden başlatın. Dağıtım rehberindeki [Telemetri & gizlilik](/tr/agenteye/deployment#telemetry--privacy) bakın. + +### CLI analitikleri / telemetrisi + +`agenteye` CLI, varsayılan olarak anonim kullanımı analitiklerini PostHog'a gönderir: hangi komutlar çalışır, başarı/çıkış durumu ve süresi. Bu CLI'nin işlevselliğinden bağımsızdır: + +- **CLI çalıştıran makine** `https://us.i.posthog.com` doğrudan ulaşıyor. Giden erişimi engelliyse, telemetrisi sessiz olarak no-op (gönderme zaman sınırlı, bu nedenle bir komutu hiçbir zaman geciktirmez) ve CLI normal çalışır. +- Agent, oturum veya etkinlik verisi hiçbir zaman dahil değildir: komut **argümanları ve bayrak değerleri** (pano URL, token, e-posta, oturum kimlikleri, sorgu filtreleri) hiçbir zaman gönderilmez. +- Devre dışı bırakmak için CLI ortamında `AGENTEYE_ANALYTICS_DISABLED=1` (veya çapraz araçlar `DO_NOT_TRACK=1`) ayarlayın. CLI rehberindeki [Telemetri & gizlilik](/tr/agenteye/cli#telemetry--privacy) bakın. + +--- + +## Yapay Zeka Asistanı Sorunları + +Tam kurulum için bkz. [enterprise-docs/assistant.md](/tr/agenteye/assistant). + +### Asistan kabarcığı görünmüyor + +Kabarcık **tümü** tutarsa gizlenmiş olur: + +- Oturum açan kullanıcı `agent:use` izinlerine sahiptir. +- `AGENTEYE_AGENT_URL` panonun üzerinde ayarlanmış ve `agent` hizmeti ulaşılabilir. +- `agent` hizmette LLM uç noktası yapılandırılmıştır (`ANTHROPIC_API_KEY`, ağ geçidi ile `ANTHROPIC_BASE_URL` veya Bedrock/Vertex). Hiçbiri ayarlanmazsa, aracı "yapılandırılmamış" bildirir ve kabarcık gizli kalır. + +Pano ana bilgisayarından aracının durumunu kontrol edin: `curl http://agent:9100/health` `{"status":"ok","llm_configured":true,...}` döndürmelidir. + +### Asistan bir şeyi okuması gerektiğini söylüyor + +Araçlar kullanıcı başına kapı kapalı. Kullanıcı `evaluations:read` (veya `events:read`, `dashboards:read`) yoksa, eşleşen araçlar sunulmaz ve asistan okunması gerektiğini söyler. İlgili okuma iznini verin. + +### Gönderirken "assistant not configured" (HTTP 503) + +`agent` konteynerinin LLM uç noktası yapılandırılmamış veya panonun `AGENTEYE_AGENT_TOKEN` aracı ile eşleşmiyor. Her ikisini de ayarlayın ve yeniden başlatın. + +### `agent` konteynerı yük altında yeniden başlatılıyor / bellek yetersiz + +Her sohbet, kısa ömürlü bir alt işlem çıkartır. Konteynerü bir init işlemiyle çalıştırdığınızdan (görüntü `tini` kullanıyor; Compose'da `init: true` ayarlayın) ve yeterli bellek sınırları verdiğinizden emin olun. Gerekirse `AGENTEYE_AGENT_MAX_STEPS` azaltın. + +--- + +## CLI Sorunları + +### `agenteye` `ModuleNotFoundError: No module named 'click'` ile başlama başarısız + +Version **0.1.6** में `agenteye` CLI'nin taze kurulumu, başlangıçta çöküm yaşayabilir: + +``` +ModuleNotFoundError: No module named 'click' +``` + +0.1.6, `click` `typer` tarafından dolaylı olarak yüklenmesine güvendi; mevcut `typer` versiyonları artık çekmez, bu nedenle temiz bir ortam paketi eksik bir şekilde çıkıyor. **0.1.7 veya daha yenisine yükseltin**, `click` doğrudan bağımlı: + +```bash +pipx upgrade agenteye # pipx ile yüklendiyse (veya: pipx install --force agenteye) +uv tool upgrade agenteye # uv ile yüklendiyse +pip install --upgrade agenteye +``` + +Kurulum rehberi için bkz. [enterprise-docs/cli.md](/tr/agenteye/cli). + +--- + +## Python SDK Sorunları + +### `$AGENTEYE_HOME/events/` içinde görünen dosya yok + +SDK olayları arabelleğe alır ve varsayılan olarak her 500 ms temizler. İşleminiz temizlemeden önce çıkarsa, olaylar kaybolabilir. Kısa ömürlü komut dosyalarında daha hızlı temizleme için `agenteye.configure(flush_interval=0.1)` çağırın veya işleminiz bir temizleme döngüsü için yeterli uzun çalıştığından emin olun. + +`AGENTEYE_HOME` ayarlandıysa, SDK'nın `$AGENTEYE_HOME/events/` yazıp `~/.agenteye/events/` (SDK ≥ 0.0.1b5 gerekir) yazıp yazmadığını doğrulayın. + +### `ValueError: Reserved field names cannot be used as custom fields` + +`timestamp`, `type` ve `environment` adları ayrılmış olup özel alanlar olarak kullanılamaz. İçlerinden birini iletmek oluşturur: + +``` +ValueError: Reserved field names cannot be used as custom fields: [...] +``` + +Sorunlu özel alanı yeniden adlandırın. `session_id` ve `agent_id` olay çağrısının açık parametreleri, özel alanlar değildir; bir başka özel alan olarak tekrar iletmek `TypeError` oluşturur. + +--- + +## Sağlık İzleme Sorunları + +### Slack'a (Robusta) uyarı gelmiyorum + +Robusta sağlık uyarısı **opt-in**; kurulu ve bir Slack kanalına yönlendirilene kadar hiçbir şey göndermez. Sürüm ve havuzunu doğrulayın: + +```bash +kubectl get pods -n robusta # robusta-runner + robusta-forwarder Running olmalı +kubectl logs -n robusta -l app=robusta-runner --tail=50 +``` + +Yaygın nedenler: Slack `api_key` / `slack_channel` ayarlanmadı (veya token iptal edildi); `api_key` Robusta bulut geçişi tokenidir (`robusta integrations slack`) ancak paketlenmiş `disableCloudRouting: true` kendi barındırmalı Slack **bot token** gerekir (`xoxb-…`) veya `disableCloudRouting: false` ayarlayın; havuz `scope` pod'ların çalıştığı ad alanı hariç tutar (paketlenmiş değerler `agenteye` kapsamı); veya henüz hiçbir hata meydana gelmemiştir. Test uyarısını bir pod'u kaldırarak zorlayın: + +```bash +kubectl -n agenteye delete pod -l app=clickhouse # yeniden oluşturulur +``` + +Kurulum ve yapılandırma için bkz. [enterprise-docs/health-monitoring.md](/tr/agenteye/health-monitoring#2-pod-failure-alerting-with-robusta-opt-in). + +### Sunucu `NotReady` çevresinde dolaşıyor + +Hazırlık sondası `/ready` vurur, bu Postgres veya ClickHouse ulaşılamadığında başarısız olur. Sunucu `NotReady` girişi ve çıkışı döngüsü içindeyse, bir bağımlılık aralıklı olarak kullanılamaz; ClickHouse ve Postgres pod'larını kontrol edin ve sunucunun `CLICKHOUSE_URL` / `DATABASE_URL`. `/ready` raporlarını doğrulayın: + +```bash +kubectl -n agenteye exec deploy/server -- sh -c 'curl -s localhost:8080/ready' +``` + +Bu sonda kasıtlı olarak toleranttır (cömert başarısızlık eşiği), bu nedenle sürdürülen çevreleme gerçek bağımlılık sorununu gösterir; aşırı agresif sonda değil. Canlılık `/health` üzerinde kalır, bu nedenle hazırlığı çevreleme pod'u yeniden **başlatmaz**. + +## Sertifika İzleme Sorunları + +### CronJob Slack bildirimleri göndermiyorum + +`cert-renewal-check` CronJob, Sır'da depolanan bir Slack webhook URL'si gerektirir. Mevcut olduğunu doğrulayın: + +```bash +kubectl get secret cert-renewal-notify-config -n agenteye +``` + +Eksikse, oluşturun: + +```bash +kubectl create secret generic cert-renewal-notify-config \ + --namespace agenteye \ + --from-literal=SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL" +``` + +Sır olmadan, CronJob yine de çalışır ve sonuçları stdout dosyasında günlüğe kaydeder. Günlükleri şu şekilde kontrol edin: + +```bash +kubectl logs -n agenteye -l job-name --tail=50 +``` + +### İstemci sertifikası, bir bildirim alınmadan önce süresi doldu + +CronJob her 12 saatte bir çalışır. Çalışmıyor olmuşsa, durumunu kontrol edin: + +```bash +kubectl get cronjob cert-renewal-check -n agenteye +``` + +Manuel bir denetim tetikleyin: + +```bash +kubectl create job --from=cronjob/cert-renewal-check manual-cert-check -n agenteye +kubectl logs -n agenteye -l job-name=manual-cert-check +``` + +Süresi dolmuş sertifikayı hemen yeniden yayınlamak için: + +```bash +cd base/certificates/client-certs +./issue-client-cert.sh +``` + +Ardından yeniden oluşturulan `collector-mtls-secret.yaml` toplayıcıları çalıştıran kümeye uygulayın ve yeniden başlatın: + +```bash +kubectl apply -f collector-mtls-secret.yaml -n +``` + +--- + +## Yedekleme Sorunları + +### `agenteye-backup` "No space left on device" ile başarısız + +`agenteye-backup` CronJob, Postgres + ClickHouse'u bir `backup-tmp` `emptyDir` karalama hacmine (varsayılan `30Gi`) boşaltır, ardından `tar` arşivini doğrudan S3'e **akışla** — sıkıştırılmış arşiv hiçbir zaman karalama dosyasına yazılmaz, bu nedenle karalama sadece *ham dökümleri* tutmalıdır, dökümleri + ikinci bir diskte arşiv kopyası değil. Bir pod çıkarılan / `No space left on device` bu nedenle **ham dökümlerin** karalama boyutunu aştığı anlamına gelir (ClickHouse `events` dökümü baskın ve zaman içinde büyür). Başarısız iş günlüklerini kontrol edin: + +```bash +kubectl logs -n agenteye -l job-name= +``` + +Düzelt: kaplamada, CronJob'ın `backup-tmp` `emptyDir` `sizeLimit` ham dökümü toplamının üzerine çıkarın ve düğümün efemerler depolama alanı gerçekten tutabildiklerini emin olun (`sizeLimit` tavan, rezervasyon değil). Dökümleri tek bir düğümün diskini aşarsa, dökümleri kaynakta sıkıştırın veya `backup-tmp` için `emptyDir` bir PVC (EBS/PD) ile değiştirin. + +> Daha eski sürümler `.tar.gz` aynı karalama olarak *yazıp* dökümleri *ve* arşiv aşırı akış olarak yazıp pod çıkarıldı **yükleme çalışmadan** — S3 başarısızlığı gibi görünüyor ama gerçekten disk. Akış yüklemesi bölüşümü kaldırır. + +### `agenteye-backup` başarısız olmuş `curl` yüklemesi + +İş `postgres:16` görüntüsünde çalışır ve ClickHouse HTTP dökümü için başlangıçta `curl` yüklenir. Debian paket aynalarına çıkış olmayan bir kümedeki, `apt-get` adımı başarısız olur. Bu çıkıştan yedek pod'a izin verin veya `curl` aynalanan/özel yedekleme görüntüsüne pişirin ve kaplayıcıya başvurun. + +### `agenteye-backup` çalışır ancak hiçbir şey nesne depolama alanına inmiyor + +Taban gerçek `BACKUP_BUCKET` (`ts-prod-agenteye/backups`) ve `agenteye-backup` ServiceAccount gönderir. İş arşivi S3'e **akışla** (`tar cz … | aws s3 cp - s3://…`). Yedekleme pod'unun tutucuya yazma erişimi yoksa yükleme hatası — ve komut `set -euo pipefail` altında çalıştığı için, o borudan herhangi bir yerde hata **tüm işi** yükleme adımında başarısız olur sessiz no-op'a göre (pod'ın EXIT tuzağı `backup FAILED during step: upload` günlüğe kaydeder). Bu, bir karalama boşluğu tahliyesi düzelttikten sonra ulaştığınız adımdır, bu nedenle yedeklemeler daha önce arşiv adımında çıkarıldıysa, yüklemenin şimdi iniş olduğunu doğrulayın. Başarısız iş günlüklerindeki S3 erişim hatası için grep'in yapılması: + +```bash +kubectl logs -n agenteye -l job-name= | grep -iE 's3|upload|denied' +``` + +Düzelt: kaplayıcıda `BACKUP_BUCKET` sahip olduğunuz tutucuya ayarlayın ve varolan `agenteye-backup` ServiceAccount'u yazma erişimi ile açıklayın (IRSA / İş Kimliği / Pod Kimliği). [enterprise-docs/kubernetes-deployment.md](/tr/agenteye/kubernetes-deployment) **Yedeklemeler** bölümüne bakın. + +--- + +## ClickHouse tabanlı değerlendirmeler / oturumlar / sorgular + +### Yükseltmeden sonra `/queries` sayfası kenar çubuğu boş + +Üç tablo (`events`, `evaluations`, `agent_sessions`) beklenir. SchemaBrowser kenar çubuğu yükseltmeden sonra boş olmuşsa, sunucu başlangıçta ClickHouse DDL uygulamada başarısız oldu. `failed to apply CH DDL statement` sunucu günlüklerini kontrol edin: + +```bash +kubectl logs -n agenteye deploy/server | grep -E 'clickhouse|CH DDL' +``` + +En yaygın neden göçler çalışırken ClickHouse'a ulaşılamayacağıdır. Sunucu CH'a ulaşamıyorsa başlama reddettiğinden, takılı bir pod genellikle sessiz kopya sorgular sayfası yerine `CrashLoopBackOff` vardır, ancak kısmi DDL uygulaması (bir deyim tamam, sonraki 5xx) şemayı yarı pişmiş bırakır. CH'a ulaşılabilir doğrulandıktan sonra sunucu pod'unu yeniden başlatın: + +```bash +kubectl rollout restart deploy/server -n agenteye +``` + +### Yeni değerlendirmeler `/sessions` veya `/queries` içinde görünmüyor + +Yükseltmeden sonra, yeni değerlendirmeler Postgres değil ClickHouse'a yazılır ve `/sessions` (gated on `evaluations:read`) ve `/queries` altında yüzey. Görünmezlerse: + +1. Değerlendirici boru hattının etkin olduğunu (`EVALUATOR_ENDPOINT` sunucuda ayarlanmış) ve terminal sonuçları prodüksüyonun doğrulayın; `evaluation_finalized` günlük satırlarını kontrol edin. +2. CH sunucudan ulaşılabilir olduğunu doğrulayın: `kubectl exec -n agenteye deploy/server -- curl -fsS http://clickhouse:8123/ping`. +3. CH tablosunu spot kontrol edin: `kubectl exec -n agenteye clickhouse-0 -- clickhouse-client -q 'SELECT count() FROM agenteye.evaluations'`. + +### Sorgular yük altında "Memory limit exceeded" ile başarısız veya ClickHouse `OOMKilled` + +**Belirti:** ağır pano/sorgu yükü altında, analitik sayfalar (etkinlik akışı, `/sessions`, modeller/gecikme görünüşü, SQL düzenleyicisi) başarısız veya zaman aşımı; sunucu kısaca flaps `NotReady`; ve ClickHouse pod artan yeniden başlatma sayısı gösterir. Bu hemen hemen her zaman **bellek**, CPU veya disk değil. + +**Belleğin olduğunu doğrulayın** (throughput sorunu değil, çoğaltma düzelttir): + +1. Pod bellek dışı katllarını kontrol edin: + ```bash + kubectl -n agenteye describe pod clickhouse-0 | grep -iE 'Restart Count|Last State|Reason|OOMKilled' + ``` + `Reason: OOMKilled` / `Exit Code: 137` tırlama yeniden başlatma sayısı hikaye. + +2. ClickHouse'u reddettiklerini sorun: + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT name, value FROM system.errors WHERE value>0 ORDER BY value DESC" + ``` + Büyük `MEMORY_LIMIT_EXCEEDED` sayısı imza. İleti *"maximum: N GiB"* okuyor — o **N `0.9 × pod'ın bellek sınırıdır`** (`deploy/base/clickhouse/configmap.yaml` `max_server_memory_usage_to_ram_ratio`). Ağır okumalarınız N'den fazlasına ihtiyacsa reddedilir. + +3. *Sorun olmayan* şeyler kural — CPU, kısım sayısı ve disk tümü düşükse, çoğaltma/parçalama eklemek atılmış maliyet olur: + ```bash + kubectl -n agenteye top pod clickhouse-0 + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT table, count() parts FROM system.parts WHERE active AND database='agenteye' GROUP BY table" + ``` + +**Neden:** ClickHouse pod'ının bellek sınırı analitik çalışan kümesi için çok küçük. En ağır okumalar ham JSON `payload` sütununu çeker, `JSONExtract*` üzerinde çalışır ve `FINAL` kullanır — her biri çeşitli GiB gerekebilir. Yapılandırılmış önbellekler (`mark_cache_size` + `uncompressed_cache_size`) pod'dan daha büyükse, bunları dışar: önbellekler aynı bütçeye karşı ücretlendirilir ve sorgu belleğini kalabalık hale getirir. + +**Düzelt — ClickHouse'ın belleğini ölçekleyin:** + +1. Kaplayıcıda ClickHouse bellek sınırını `clickhouse` StatefulSet konteyner `resources` (diğer bileşenlerin `resources` için kullanılan aynı kaplamı mekanizması) düzeltmeyi yaparak çıkarın. Kullanılabilir sunucu bütçe `0.9 × limit`, böylece `6Gi` sınırı ~5.4 GiB verir, `16Gi` ~14 GiB verir. `requests.memory` gerçek bir taban olarak da ayarlayın, bu nedenle zamanlayıcı rezervasyon yapar. Bu uygulaması **CH pod'unu yeniden oluşturur** (tek kopya → ~30–60 saniye analitikleri kapalı kalma süresi); düşük trafik penceresi yapın. +2. `deploy/base/clickhouse/configmap.yaml` içinde önbellekleri sınırla orantılı tutun — küçük önbellekler (birkaç yüz MiB) küçük pod'da güvenli; eşleşen bellek sınırı artışı ile birlikte yükselt. Sorgu başına `max_memory_usage` `users.xml` profilinde açıkça ayarlanmıştır (sabitlenmiş düğüm bölümüne bakın) ve sunucu seviyesi başlığın altında tutulur (`0.9 × limit`) hiçbir sorgu izin verilemez kont sahip daha fazla RAM. +3. Düğümün kendisi tavan ise, ClickHouse görebileceği ana bilgisayar belleğini kontrol edin: + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT formatReadableSize(value) FROM system.asynchronous_metrics WHERE metric='OSMemoryTotal'" + ``` + Pod sınırının sadece biraz üzeride olduğunu düşünürse, ClickHouse'u daha büyük (bellek optimize) düğüme taşıyın — kaplayıcıda düğüm seçicisi/yakınlığı — limit daha da artırmadan önce. + +**Bellek ekleyemediğinizde: sorgular RAM'de çalıştırın ve hızlı başarısız — yavaş diskte dökmeyin.** Düğüm sabitlediyse ve pod büyüyemezse, herhangi bir sorgu kullanımı üst sınırı (böylece bir sorgu tüm düğümü alamaz) ve **yavaş (SSD olmayan) veri diski** üzerinde **denebilir ama büyük toplamalar/tür diskte dökme yapmayın. Yavaş diske dökme sunucunun istemci okuma zaman aşımından daha yavaş, bu nedenle bir dökme sorgusu uçuş ortasında pano `500` döndürürken ClickHouse öğütmeye devam ediyor — sorguları RAM'de tutup nadir bütçe aşımı hızlı **başarısız** (`MEMORY_LIMIT_EXCEEDED`, alt saniye) yüklemeyi geri yükler. ClickHouse gotcha, bunları uygulamak: + +- **Bunlar *profil* ayarları ve ClickHouse `` yalnızca `users_config` (`users.xml` / `users.d/*.xml`) dosyasından okur — hiçbir zaman `config.d` olmaz.** `config.d/agenteye.xml` yerleştirilen bir `` blok **sessizce göz ardı edilir** (`max_execution_time`, `max_memory_usage`, vb. basitçe uygulanmaz). Paketlenmiş yapılandırma, bu nedenle `clickhouse-config` ConfigMap `users.xml` anahtarı olarak gönderir, `/etc/clickhouse-server/users.d/agenteye.xml` takılan. +- Gönderilen varsayılanlar: `max_memory_usage` (sorgu başına tavan — bir sorgu tüm sunucu bütçesini tüketemez), `max_bytes_before_external_group_by` / `max_bytes_before_external_sort` = **`0` (döküm devre dışı)** yani sorgular yavaş diskten RAMda kalır yerine sürüyor ve `max_execution_time` (kaçak koruma, sunucunun istemci okuma zaman aşımı ile uyumludur). +- **Canlı olduklarını doğrulayın** (bu da config.d gotcha tespit etmekte): + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT name, value FROM system.settings + WHERE name IN ('max_memory_usage','max_bytes_before_external_group_by','max_execution_time')" + ``` + Sıfırdan farklı `max_memory_usage` ve `max_bytes_before_external_group_by = 0` bekledi. `max_memory_usage` `0`/varsayılan okursa, profil uygulanmıyor — ayarların `users.d` takısında canlı, `config.d` değil olduğunu kontrol edin. + +Ödünleşme: dökme devre dışı bırakılarak, çalışan seti `max_memory_usage` aşan bir sorgu **reddedilir** (`MEMORY_LIMIT_EXCEEDED`) yavaş tamamlamak yerine — yavaş diskte hızlı reddetme tercih edilir, çünkü dökme sorgusu öyle yine de başarısız olur. Veri diskiniz **hızlı (SSD)** olduğundan, `max_bytes_before_external_*` eşikleri yükseltebilir ve büyük sorguları diskte yığında tamamlaması gerek. + +--- + +## Çok kiracılılık (kuruluşlar) + +### Kuruluşları etkinleştiren yükseltme sırasında hatalar (karışık eski/yeni sunucu pod'ları) + +**Belirti:** eski örneği yeni sunucu pod'larını yayınlayan bir yayın dağıtımı sırasında, bazı istekler başarısız: sunucu günlükleri `there is no unique or exclusion constraint matching the ON CONFLICT specification` `api_keys` yolunda gösterir ve/veya uyarı/Slack/webhook kanalları rulo uçuşu sırasında ateş kesiyor. + +**Neden:** yükseltme eski örnek genişliği benzersiz dizini `api_keys(name)` kısmi per-org dizinler ile değiştirir ve uyarı kanı ayarlarını (ve `default_user_permissions`) genel `settings` tablosundan per-org `org_settings` tablosuna taşır. **Eski** bir sunucu pod'u yine `ON CONFLICT (name)` sorunları (şimdi eşleşen kısıtlama yok) ve yine eski `settings` satırlarından kanal yapılandırmasını okur (şimdi boş). Eski ve yeni pod'lar bu iki yol için güvenli bir şekilde varolan olamaz. + +**Düzelt:** bu belirli yükseltmeyi karışık versiyonlar arasında yavaş haddeleme yapmayın. Temiz bir şekilde kes: eski sunucuyu sıfıra ölçekle (veya kısa bakım penceresi kullanın) ve yeni sürümü göçleriyle birlikte getirir, eski ve yeni çoğaltmaları yan yana çalıştırmak yerine. Normal trafik ve alım derhal sonra devam eder; bu yalnızca sürüm geçişi penceresini etkiler. + +### Kuruluş `CREATE USER` / `CREATE ROW POLICY` üzerinde hazırlama başarısız veya bir kuruluş başka kuruluş verilerini okuyor + +**Belirti:** kuruluş oluşturmak `CREATE USER`, `CREATE ROW POLICY` veya "erişim yönetimi devre dışı" bildiren bir hata döndürür; veya daha kötü, bir kuruluşun üyeleri SQL düzenleyicisi veya asistan içinde başka bir kuruluşun etkinlikleri/değerlendirmelerini görüyor. + +**Neden:** per-org yalıtma, kuruluş başına ayrılmış ClickHouse kullanıcısı + satır ilkesi tarafından uygulanır. Bu SQL **erişim yönetimi** etkin ve `users_without_row_policies_can_read_rows=false` ClickHouse üzerinde gerektirir. Erişim yönetimi kapalıysa hazırlama kullanıcı/ilke oluşturamaz; satır ilkesi varsayılanı izin vericisi değerinde bırakıldıysa \ No newline at end of file diff --git a/docs/vi/agenteye/alerts.mdx b/docs/vi/agenteye/alerts.mdx new file mode 100644 index 00000000..0bd4e1af --- /dev/null +++ b/docs/vi/agenteye/alerts.mdx @@ -0,0 +1,309 @@ +--- +--- +title: "Cảnh báo" +description: "Tài liệu về Cảnh báo AgentEye." +--- + +Cảnh báo đánh giá một quy tắc theo lịch trình và thông báo cho bạn khi có điều gì vượt quá ngưỡng. Chúng biến AgentEye từ một bảng điều khiển thụ động thành một bề mặt báo cáo cho những điều quan trọng: tăng đột ngột tỷ lệ lỗi, hồi quy độ trễ, giảm điểm đánh giá, hoặc bất kỳ sự kiện tùy chỉnh nào mà bạn có thể biểu diễn dưới dạng truy vấn ClickHouse. + +Hướng dẫn này bao gồm cảnh báo là gì, năm loại kích hoạt, bốn kênh thông báo, vòng đời sự cố, và các điều khiển vận hành. + +![Trang Cảnh báo: một lưới các thẻ quy tắc cảnh báo, mỗi thẻ hiển thị loại kích hoạt, cửa sổ đánh giá, kênh, và huy hiệu mức độ nghiêm trọng thông tin/cảnh báo/tới hạn của nó](/agenteye/images/alerts.png) + +--- + +## Khái niệm + +- **Cảnh báo** — quy tắc. Nó nói *cái gì* để kiểm tra (kích hoạt), *tần suất* (khoảng đánh giá), *khi nào coi là bị hỏng* (logic phức hợp), *mức độ khẩn cấp* (mức độ nghiêm trọng), và *ai/nơi* để thông báo (kênh). +- **Sự cố** — những gì xảy ra khi cảnh báo phát động. Một cảnh báo có tối đa một sự cố mở tại một thời điểm. Những lần vi phạm lặp lại cập nhật bằng chứng của cùng một sự cố. Sự cố được giải quyết bởi một điều hành viên; giải quyết tự động khi quy tắc dừng phát động được lên kế hoạch nhưng hiện không được bật. +- **Kênh** — nơi thông báo đi: email, Slack, webhook chung, hoặc trong bảng điều khiển. Mỗi cảnh báo có thể đính kèm bất kỳ sự kết hợp nào. + +Cảnh báo và sự cố thuộc về một tổ chức và được chia sẻ giữa các điều hành viên của tổ chức đó (trong triển khai một người thuê đó chỉ là `default` org được xây dựng sẵn). Sự cố có thể được gán cho một điều hành viên cá nhân để phân loại. + +--- + +## Các loại kích hoạt + +Năm loại, mỗi loại có thông số kỹ thuật JSON riêng. Chọn loại phù hợp với cách bạn muốn mô tả "bị hỏng". Biểu mẫu **cảnh báo mới** trên bảng điều khiển xây dựng cùng một thông số kỹ thuật cho bạn, chuyển đổi trình chỉnh sửa điều kiện để phù hợp với loại kích hoạt bạn chọn: + +![Biểu mẫu cảnh báo mới, với các thông tin cơ bản (tên, mô tả, được bật) và bộ chọn kích hoạt hiển thị ngưỡng metric, SQL tùy chỉnh, điểm đánh giá, các lỗi đánh giá, và tùy chọn cho mỗi sự kiện](/agenteye/images/alert-new.png) + +### 1. `metric_threshold` + +Đơn giản nhất. Chọn một metric từ danh sách đóng, một toán tử, một ngưỡng, và một cửa sổ thời gian. + +| Metric | Nó đếm gì | +|---|---| +| `event_count` | Tổng số sự kiện trong cửa sổ | +| `error_count` | `event_type = 'error'` HOẶC bất kỳ sự kiện nào với `error_type IS NOT NULL` | +| `error_rate` | `error_count / event_count` (0..1) | +| `p95_latency_ms` | `quantile(0.95)(duration_ms)` trên tất cả các sự kiện với `duration_ms` | +| `p99_latency_ms` | `quantile(0.99)(duration_ms)` | +| `token_sum` | `SUM(input_tokens + output_tokens)` | + +Toán tử: `>`, `>=`, `<`, `<=`, `==` (cũng được chấp nhận dưới dạng `gt`, `gte`, `lt`, `lte`, `eq`). + +Bộ lọc tùy chọn: `environment`, `event_type`. + +Ví dụ thông số kỹ thuật: + +```json +{ + "metric": "p95_latency_ms", + "filter": { "environment": "production" }, + "window_secs": 900, + "op": ">", + "value": 5000 +} +``` + +### 2. `custom_sql` + +Cho bất kỳ điều gì mà các metric được đặt sẵn không bao gồm. SQL được cung cấp bởi toán tử đi qua cùng một bảo vệ `/queries/run` (chỉ SELECT/WITH, một câu lệnh, giới hạn 10.000 hàng) trước khi dispatcher chạy nó. Hai chế độ: + +- **chế độ hàng** (không có `op`/`value`): cảnh báo phát động ngay khi truy vấn trả về ít nhất một hàng. +- **chế độ giá trị**: truy vấn phải có bí danh một cột là `metric_value`; dispatcher so sánh `metric_value` của hàng đầu tiên với `value` sử dụng `op`. + +```json +{ + "sql": "SELECT count() AS metric_value FROM agenteye.events WHERE event_type = 'error' AND ts >= now() - INTERVAL 1 HOUR", + "op": ">", + "value": 100 +} +``` + +### 3. `evaluation_score` + +Đọc từ `agenteye.evaluations` và so sánh trung bình của một điểm được đặt tên trên một cửa sổ. + +```json +{ + "score_key": "hallucination", + "op": ">", + "value": 0.6, + "window_secs": 3600, + "min_count": 5, + "environment": "production" +} +``` + +`min_count` bảo vệ chống lại các ngoại lệ đơn mẫu; dispatcher sẽ không phát động cho đến khi có ít nhất N đánh giá tồn tại trong cửa sổ. + +### 4. `eval_compound` + +Bắt một hồi quy chất lượng chỉ hiện ra trên *nhiều* điểm đánh giá cùng một lúc. Khi `evaluation_score` theo dõi một điểm được đặt tên, `eval_compound` soạn thảo nhiều điều kiện điểm đánh giá thành một cảnh báo và kết hợp kết quả của chúng với một logic được chọn; vì vậy một quy tắc có thể biểu diễn "phát động nếu tính hữu ích giảm **hoặc** ảo tưởng tăng", "chỉ phát động nếu tính hữu ích **và** hiệu quả công cụ cùng giảm", hoặc "phát động nếu **ít nhất 2 trên** ba kiểm tra này vi phạm". + +Mỗi điều kiện đọc trung bình của một điểm được đặt tên từ `agenteye.evaluations` trong cửa sổ chia sẻ và kiểm tra nó với toán tử và ngưỡng riêng của nó. Kết quả boolean sau đó được kết hợp bởi `combinator`: + +| Combinator | Logic | Phát động khi | +|---|---|---| +| `"any"` | OR | ít nhất một điều kiện vi phạm | +| `"all"` | AND | mọi điều kiện vi phạm | +| `{ "at_least": N }` | M-of-N | ít nhất N điều kiện vi phạm | + +```json +{ + "combinator": { "at_least": 2 }, + "conditions": [ + { "score_key": "hallucination", "op": ">", "value": 0.8 }, + { "score_key": "helpfulness", "op": "<", "value": 0.6 }, + { "score_key": "tone", "op": "<", "value": 0.5 } + ], + "window_secs": 3600, + "min_count": 5, + "environment": "production" +} +``` + +- `combinator`: `"any"`, `"all"`, hoặc `{ "at_least": N }`. +- `conditions[]`: mỗi `{ score_key, op, value }`, sử dụng cùng các toán tử như các kích hoạt khác (`>`, `>=`, `<`, `<=`, `==`). +- `window_secs`: lookback được chia sẻ áp dụng cho mọi điều kiện (mặc định `3600`). +- `min_count`: số lượng đánh giá tối thiểu trên mỗi điều kiện trước khi điều kiện đó có thể vi phạm; một điều kiện có quá ít mẫu trong cửa sổ được tính là "không vi phạm" (mặc định `1`). +- `environment`: tùy chọn; hạn chế mọi điều kiện chỉ trong một môi trường. + +Bằng chứng thông báo ghi lại trung bình được quan sát của mỗi điều kiện, ngưỡng nó được kiểm tra, có bao nhiêu đánh giá được nhìn thấy, và liệu nó có vi phạm hay không; vì vậy bạn có thể thấy chính xác những kiểm tra nào được kích hoạt. + +### 5. `per_event` + +Cho các cảnh báo "bất kỳ sự kiện nào khớp X đã đến". Không có tổng hợp; dispatcher phát động ngay khi nó thấy kết quả khớp trong cửa sổ lookback. + +```json +{ + "event_type": "error", + "lookback_secs": 60, + "environment": "production", + "tool_name": "bash", + "agent_id": "caa", + "error_type": "TimeoutError", + "message_contains": "vertex-ai timed out" +} +``` + +Tất cả các bộ lọc được kết hợp bằng AND; bất kỳ trường nào bạn để trống là không bị ràng buộc. + +| Trường | Mục đích | +|---|---| +| `agent_id` | Hạn chế lỗi từ một tác nhân cụ thể (cái được hiển thị trên hàng `/errors`). | +| `error_type` | Hạn chế cho một lớp lỗi cụ thể (ví dụ: `TimeoutError`) thay vì mọi lỗi. | +| `message_contains` | Khớp chuỗi con không phân biệt chữ hoa chữ thường với `payload.message`. Hữu ích cho việc bắt một chế độ lỗi cụ thể (ví dụ: `prompt is too long`) mà không cảnh báo trên mọi lỗi từ cùng một tác nhân. Giới hạn 200 ký tự; khớp dưới dạng chuỗi cơ bản, không phải mẫu. | + +Mẹo: đặt `lookback_secs` để phù hợp với `eval_interval_secs` của cảnh báo để bạn không thông báo lại trên cùng một sự kiện. + +**Phím tắt từ `/errors`:** mỗi hàng đại diện nhóm lỗi trên chế độ xem lỗi (và bảng chi tiết sự kiện phiên cho một sự kiện lỗi) có nút **+ alert** mở `/alerts/new` được điền trước với kích hoạt `per_event` khóa trên `event_type` + môi trường của hàng đó, bao gồm tên được gieo từ `error_type` của payload khi có. Bạn vẫn chọn kênh và xác nhận lookback, nhưng bộ so khớp được điền cho bạn. Các điều hành viên cần `alerts:write` để nút xuất hiện. + +--- + +## Logic phức hợp (M of N) + +Mỗi cảnh báo có hai nút số nguyên bên cạnh kích hoạt: + +- `eval_window`: có bao nhiêu đánh giá gần đây để xem (mặc định 1) +- `min_breaches`: có bao nhiêu trong số đó phải vi phạm trước khi cảnh báo phát động (mặc định 1) + +`1 of 1` (mặc định) là "phát động khi lần vi phạm đầu tiên". `3 of 5` nghĩa là "phát động khi quy tắc đã vi phạm 3 trên 5 đánh giá gần đây", hữu ích cho các tín hiệu không ổn định nơi một phép đo xấu là nhiễu. Dispatcher duy trì một bộ đệm vòng cho mỗi cảnh báo; bạn không phải quản lý trạng thái. + +--- + +## Khoảng đánh giá + +`eval_interval_secs` kiểm soát tần suất dispatcher chạy quy tắc của bạn. Được giới hạn trong `[30, 86400]`. Các cài đặt trước trên bảng điều khiển: 1m / 5m / 15m / 1h. Chọn một khoảng phù hợp với tốc độ di chuyển của tín hiệu cơ bản: một cảnh báo tỷ lệ lỗi 5 phút được đánh giá mỗi 15 giây lãng phí CPU; một cảnh báo cho mỗi sự kiện cần một lookback ngắn hoặc nó sẽ im lặng bỏ qua các sự kiện giữa các tick. + +--- + +## Kênh + +Mỗi cảnh báo có thể đính kèm bất kỳ sự kết hợp nào của bốn kênh này. Thông tin đăng nhập theo kênh (URL webhook Slack, URL webhook chung + bí mật ký, các người nhận email mặc định) được cấu hình một lần trong **`/settings`** và được tham chiếu bằng khóa từ mỗi cảnh báo. Bằng cách này, một kênh Slack có thể phục vụ nhiều cảnh báo mà không cần mỗi cảnh báo lưu trữ bản sao riêng của URL webhook. + +Ba loại kênh bên ngoài (email, Slack, webhook) cũng được gated bởi một công tắc tắt toàn org, `alerts.enabled_channels`. Khi một cảnh báo phát động đính kèm một loại kênh không nằm trong bộ này, dispatcher bỏ qua nó và ghi một hàng `alert_notifications` với trạng thái `skipped_disabled` và mục tiêu `` (cho phép bạn tạm dừng toàn cầu, ví dụ, tất cả gửi Slack mà không chỉnh sửa từng quy tắc). Kênh trong bảng điều khiển luôn được cho phép. Xem [Cấu hình](#configuration). + +### Email + +Sử dụng lại cùng vận chuyển SMTP gửi email đăng nhập OTP. Người nhận giải quyết theo thứ tự: + +1. Ghi đè `recipients[]` theo kênh (khi không trống). +2. Cài đặt `alerts.email_default_recipients` (một mảng các chuỗi email). + +Nếu SMTP không được cấu hình, kênh là không hoạt động; dispatcher vẫn ghi một hàng `alert_notifications` với mục tiêu `` nên audit trail làm cho cấu hình sai được hiển thị. + +### Slack + +Gửi một thông báo Block Kit tới một [URL webhook đến](https://api.slack.com/messaging/webhooks). + +- URL mặc định: `alerts.slack_default_webhook` (được đặt trong `/settings`). +- Ghi đè cho mỗi cảnh báo: đặt `webhook_setting_key` của kênh thành bất kỳ khóa cài đặt kiểu URL nào khác, ví dụ: `alerts.slack_oncall`, `alerts.slack_costs`. + +Tiêu đề bao gồm biểu tượng mức độ nghiêm trọng (`:rotating_light:` / `:warning:` / `:bell:`), và thông báo mang một nút liên kết sâu tới trang sự cố. + +### Webhook chung + +Tích hợp JSON-POST cho PagerDuty, Opsgenie, hoặc điểm cuối tiếp nhận của bạn. Hình dạng cơ thể: + +```json +{ + "schema_version": 1, + "event": "alert.firing", + "incident": { "id": "uuid", "url": "https://…/incidents/uuid", "opened_at": "2026-…" }, + "alert": { "id": "uuid", "name": "errors > 50/hr", "severity": "critical" }, + "breach": { "value": 73.0, "summary": "ErrorCount > 50 (observed 73.000)", "evidence": { … } } +} +``` + +Khi `alerts.webhook_signing_secret` được đặt, yêu cầu bao gồm tiêu đề `X-AgentEye-Signature: sha256=`, HMAC-SHA256 của cơ thể sử dụng bí mật. Xác minh nó trên phía nhận trước khi tin tưởng tải trọng. + +Tiêu đề `X-AgentEye-Event` mang `alert.firing` / `alert.test`. (`alert.resolved` được dành riêng cho tính năng tự động giải quyết được lên kế hoạch và hiện không được phát hành.) + +### Trong bảng điều khiển + +Không có gửi bên ngoài: cảnh báo chỉ ghi một hàng `alert_notifications` mà trang sự cố của bảng điều khiển bề mặt. Hữu ích khi bạn đang điều chỉnh một quy tắc và không muốn spam một hệ thống bên ngoài, hoặc cho các cảnh báo ưu tiên thấp mà các điều hành viên kiểm tra trong quá trình phân loại thông thường. + +--- + +## Vòng đời sự cố + +``` +firing ──ack──▶ acknowledged + │ │ + └────────────────────┴───── operator resolve ───▶ resolved +``` + +- **firing** — dispatcher vừa mở sự cố hoặc phát hiện một vi phạm khác. Thông báo phát động được quạt ra chính xác một lần (được gated bởi dấu thời gian `notified_firing_at` trên sự cố). +- **acknowledged** — một điều hành viên nhấn *ack* trên `/incidents/:id`. Sự cố vẫn được coi là mở; các vi phạm tiếp theo sẽ cập nhật bằng chứng của nó mà không thông báo lại. +- **resolved** — một điều hành viên nhấn *resolve*. Giải quyết tự động khi quy tắc dừng phạm được lên kế hoạch nhưng hiện không được bật, vì vậy một sự cố mở vẫn mở cho đến khi một điều hành viên giải quyết nó. + +Một sự cố mới có thể mở lại cùng một cảnh báo tại bất kỳ điểm nào sau khi cảnh báo trước đó được giải quyết. + +**Dòng thời gian hoạt động.** Mỗi hành động trên một sự cố — mở, ack, giải quyết — được ghi trong nhật ký hoạt động chỉ nối thêm và được hiển thị trên dòng thời gian *activity* của sự cố, mỗi mục được ghi lại cho điều hành viên đã thực hiện nó (theo email) hoặc cho **automated** cho các hành động dispatcher thực hiện độc lập (tự động mở khi vi phạm). Xác nhận được chia sẻ: nhiều điều hành viên có thể ack cùng một sự cố và mỗi cái xuất hiện như một mục riêng, được ghi lại. + +Hộp thư **Sự cố** nhóm các sự cố mở theo trạng thái và cho phép bạn lọc theo mức độ nghiêm trọng và người được gán: + +![Hộp thư Sự cố hiển thị các thẻ sự cố liên kết cảnh báo và ad-hoc với huy hiệu mức độ nghiêm trọng và người được gán](/agenteye/images/incidents.png) + +Mở một sự cố cho thấy bằng chứng vi phạm, những người được gán và người theo dõi, dòng thời gian hoạt động được ghi lại, và một chuỗi bình luận: + +![Chế độ xem chi tiết sự cố: cảnh báo cha, tóm tắt vi phạm, những người được gán, người theo dõi, nhật ký hoạt động được ghi lại, và cuộc trò chuyện](/agenteye/images/incident-detail.png) + +--- + +## Quyền bắt buộc + +Soạn thảo *quy tắc* cảnh báo và phân loại *sự cố* là những mối quan tâm riêng biệt với các quyền riêng biệt, vì vậy bạn có thể cấp cho một vòng xoay on-call quyền truy cập sự cố mà không cũng trao cho nó khả năng viết lại các quy tắc. + +- `alerts:read`: xem các quy tắc cảnh báo. +- `alerts:write`: tạo, chỉnh sửa, xóa các quy tắc cảnh báo, và kích hoạt thông báo kiểm tra. +- `incidents:read`: xem sự cố. +- `incidents:write`: mở các sự cố thủ công (ad-hoc) không gắn liền với cảnh báo. +- `incidents:ack`: ack, gán, bình luận, và giải quyết sự cố. + +> **Legacy `alerts:ack`.** Các khóa và điều hành viên được cấp mã thông báo `alerts:ack` cũ hơn tiếp tục hoạt động: nó được chấp nhận là `incidents:ack` (và ngụ ý `incidents:read`), vì vậy các on-caller hiện tại giữ quyền truy cập của họ mà không cấp lại thông tin xác thực. Phát hành các khoản cấp mới với gia đình `incidents:*`. + +Cấp trên các khóa API (`POST /keys`) và các điều hành viên (`PUT /users/:id`). `PermGate` của bảng điều khiển khóa các nút liên quan khi thiếu quyền; bạn sẽ thấy `// 403` bên cạnh hành động. + +> **Bộ chọn người nhận email.** Bộ chọn người nhận của trình chỉnh sửa cảnh báo liệt kê các thành viên của tổ chức của bạn để bạn có thể chọn họ theo tên. Nó tải cho bất kỳ điều hành viên nào giữ `alerts:read` hoặc `alerts:write`; xem danh mục của nhóm của bạn cho mục đích này **không** yêu cầu `users:read`, và bộ chọn chỉ trả về địa chỉ email thành viên, không bao giờ toàn bộ hồ sơ người dùng. + +--- + +## Cấu hình + +Các biến môi trường được tiêu thụ bởi dispatcher: + +| Var | Mặc định | Mục đích | +|---|---|---| +| `ALERT_WORKERS` | `1` | Nhiệm vụ worker trên mỗi phiên bản máy chủ. Hầu hết các triển khai chỉ cần một. | +| `ALERT_CLAIM_BATCH` | `16` | Cảnh báo tối đa một tick worker xử lý. | +| `ALERT_POLL_IDLE_SECS` | `5` | Worker ngủ khi hàng đợi trống. | +| `ALERT_REQUEST_TIMEOUT_MS` | `15000` | Hết thời gian đánh giá kích hoạt trên mỗi lần. | +| `DASHBOARD_URL` | `https://app.befailproof.ai` | Nguồn gốc được sử dụng để xây dựng magic-link sự cố trong thông báo. Đặt thành máy chủ bảng điều khiển của bạn. | + +Sau khi thất bại tạm thời trong đánh giá (ClickHouse không thể tiếp cận, hết thời gian truy vấn), dispatcher thử lại quy tắc với backoff lũy thừa. Khi một quy tắc đã tích lũy **5** lỗi tạm thời liên tiếp, nó được lên lịch lại ở tốc độ bình thường thay vì tiếp tục backoff, vì vậy một quy tắc không ngừng thất bại vẫn được đánh giá lại. Trần này là cố định và không thể điều chỉnh bởi điều hành viên. + +Cài đặt kênh (được quản lý từ `/settings`, không phải env): + +- `alerts.email_default_recipients` (`email_list`): mảng JSON của các chuỗi email — người nhận mặc định cho kênh email. +- `alerts.slack_default_webhook` (`url`): URL webhook đến Slack mặc định. +- `alerts.webhook_default_url` (`url`): URL webhook chung mặc định. +- `alerts.webhook_signing_secret` (`secret`): khóa HMAC-SHA256. Luôn được trả về dưới dạng `""` trong phản hồi GET; gõ giá trị mới để xoay. +- `alerts.enabled_channels` (`channel_set`): bộ toàn org của các loại kênh bên ngoài được gửi khi cảnh báo phát động; mặc định tất cả ba (`email`, `slack`, `webhook`). Loại bỏ một loại ở đây sẽ loại bỏ kênh đó toàn cầu cho mọi cảnh báo mà không chỉnh sửa từng quy tắc. Kênh trong bảng điều khiển luôn được gửi và không bị ảnh hưởng bởi cài đặt này. + +--- + +## Xác minh cảnh báo mới + +Trước khi dựa vào cảnh báo mới: + +1. Lưu nó dưới dạng bật với ít nhất một kênh thông báo. +2. Chọn **test** trên trang chi tiết cảnh báo và xác nhận mỗi điểm đến được cấu hình nhận thông báo tổng hợp. +3. Sau lần vi phạm thực tế đầu tiên, xác nhận sự cố xuất hiện dưới **Sự cố** và giá trị đo được của nó phù hợp với truy vấn bảng điều khiển tương ứng. + +Sự cố không tự động giải quyết khi một điều kiện rõ ràng. Một điều hành viên phải giải quyết chúng từ trang chi tiết sự cố. + +--- + +## Khắc phục sự cố + +| Triệu chứng | Nguyên nhân có thể | +|---|---| +| Cảnh báo không bao giờ phát động | `enabled = false`, hoặc không có kênh đính kèm, hoặc truy vấn CH cơ bản trả về 0 hàng. Sử dụng *test* để xác nhận kênh; sử dụng `/queries/run` để xác nhận metric. | +| Thông báo Slack bị mất | `alerts.slack_default_webhook` (hoặc khóa ghi đè cho mỗi cảnh báo) không được đặt: kiểm tra `alert_notifications.target` cho các hàng ``; hoặc loại `slack` được tắt toàn cầu trong `alerts.enabled_channels`: kiểm tra các hàng `alert_notifications` với trạng thái `skipped_disabled` và mục tiêu ``. | +| Webhook chung 401 | Người nhận yêu cầu chữ ký nhưng `alerts.webhook_signing_secret` không được đặt. Xác minh ở bên nhận rằng HMAC phù hợp với `hmac_sha256(secret, body)`. | +| Email "từ tất cả gửi không thành công" | Thông tin xác thực SMTP sai hoặc địa chỉ `from` bị từ chối bởi chuyên chở của bạn. Cùng bề mặt gửi email OTP: nếu những cái đó hoạt động, vận chuyển SMTP ổn. | +| Sự cố mở lại lặp đi lặp lại | Các nút phức hợp quá tích cực: thử tăng `min_breaches` hoặc `eval_window` để các tăng đột ngột tạm thời không mở lại các sự cố bạn đã giải quyết. | \ No newline at end of file diff --git a/docs/vi/agenteye/api-keys.mdx b/docs/vi/agenteye/api-keys.mdx new file mode 100644 index 00000000..a5fb6099 --- /dev/null +++ b/docs/vi/agenteye/api-keys.mdx @@ -0,0 +1,254 @@ +--- +title: "API Keys" +description: "Tài liệu về API Keys của AgentEye." +--- + +AgentEye sử dụng các API key được kiểm soát chi tiết để điều khiển quyền truy cập vào máy chủ. Mỗi key mang một hoặc nhiều quyền xác định những gì nó có thể làm. + +--- + +## Quyền hạn + +Máy chủ thực thi một danh mục cố định các quyền hạn; mỗi quyền kiểm soát các tuyến HTTP cụ thể. Một **admin key** sở hữu tất cả chúng; một key được phạm vi giới hạn sở hữu tập hợp con mà bạn cấp khi tạo. Các chuỗi quyền không được biết đến sẽ bị từ chối khi tạo key. + +> **Không thể gán cho key.** Hai quyền hợp lệ chỉ dành cho con người/dashboard và không thể cấp cho API key: `orgs:admin` (quản trị phiên bản, chỉ dành cho nhà điều hành) và `keys:update`. Yêu cầu `POST /keys` hoặc `PATCH /keys/:id` cố gắng cấp một trong hai quyền sẽ bị từ chối với HTTP 422. Xem hàng `keys:update` bên dưới để biết tại sao một bearer key có thể tạo key nhưng không bao giờ chỉnh sửa chúng. + +### Nhập và truy vấn sự kiện + +| Quyền | Tuyến HTTP | Cho phép gì | +|---|---|---| +| `events:add` | `POST /events` | Nhập các lô sự kiện từ bộ thu thập. Quyền duy nhất mà bộ thu thập cần. | +| `events:read` | `GET /events`, `GET /events/latency_aggregate`, `GET /events/environments`, `GET /events/models`, `GET /sessions/:session_id/export` | Truy vấn sự kiện, liệt kê các môi trường đã biết, liệt kê các định danh mô hình được nhìn thấy trong dữ liệu (được sử dụng bởi chế độ xem Models và bộ lọc mô hình), tính toán tổng độ trễ để cấp năng lượng cho biểu đồ nhiệt / dải phần trăm, và xuất một phiên dưới dạng JSONL. Các điểm cuối facet bộ lọc được chia sẻ `GET /events/environments` và `GET /events/models` có thể truy cập được với **hoặc** `events:read` **hoặc** `evaluations:read`, do đó trang phiên (được kiểm soát `evaluations:read`) tái sử dụng facet mỗi tổ chức giống nhau. | + +### Phiên & đánh giá + +| Quyền | Tuyến HTTP | Cho phép gì | +|---|---|---| +| `evaluations:read` | `GET /sessions`, `GET /evaluations`, `GET /evaluations/aggregate`, `GET /evaluations/environments`, `GET /evaluation-jobs` | Liệt kê các phiên, đọc kết quả đánh giá, health được tổng hợp được sử dụng bởi bảng điều khiển, và trạng thái hàng đợi worker công việc đánh giá. | +| `evaluations:trigger` | `POST /sessions/:session_id/re-evaluate` | Tự động đưa một phiên đã hoàn thành vào hàng đợi để đánh giá lại. | + +### Bảng điều khiển + +| Quyền | Tuyến HTTP | Cho phép gì | +|---|---|---| +| `dashboards:read` | `GET /dashboards`, `GET /dashboards/:id`, `GET /dashboards/:id/tiles` | Liệt kê các bảng điều khiển, tải một, và đọc các tile của nó. | +| `dashboards:write` | `POST /dashboards`, `PUT /dashboards/:id`, `POST /dashboards/:id/tiles`, `PUT /dashboards/:id/tiles/:tile_id`, `DELETE /dashboards/:id/tiles/:tile_id`, `PUT /dashboards/:id/tiles/layout` | Tạo và chỉnh sửa bảng điều khiển, thêm / chỉnh sửa / loại bỏ tile, và sắp xếp lại lưới tile. | +| `dashboards:delete` | `DELETE /dashboards/:id` | Xóa toàn bộ bảng điều khiển (xóa cấp tile nằm dưới `dashboards:write`). | + +### Truy vấn đã lưu (SQL composer) + +| Quyền | Tuyến HTTP | Cho phép gì | +|---|---|---| +| `queries:read` | `GET /queries`, `GET /queries/:id`, `GET /queries/schema` | Liệt kê các truy vấn đã lưu, tải một, và kiểm tra schema ClickHouse chỉ đọc mà composer nhắm tới. | +| `queries:write` | `POST /queries`, `PUT /queries/:id` | Tạo và chỉnh sửa các truy vấn đã lưu. SQL vẫn được định tuyến qua cùng vai trò chỉ đọc và kiểm tra `sql_guard` như một lệnh gọi `queries:run`. | +| `queries:delete` | `DELETE /queries/:id` | Xóa một truy vấn đã lưu. | +| `queries:run` | `POST /queries/run` | Thực thi SQL đã lưu hoặc tạm thời so với vai trò chỉ đọc được sử dụng bởi composer. | + +### Trợ lý AI + +| Quyền | Tuyến HTTP | Cho phép gì | +|---|---|---| +| `agent:use` | `GET /agent/conversations`, `POST /agent/conversations`, `GET /agent/conversations/:id`, `PATCH /agent/conversations/:id`, `DELETE /agent/conversations/:id`, `PUT /agent/conversations/:id/messages` | Trò chuyện với trợ lý AI của bảng điều khiển và quản lý các cuộc trò chuyện riêng của bạn. Bắt buộc trên **người dùng** để xem dock trợ lý; key của chính trợ lý là `dashboard-assistant` và được hạt giống riêng biệt (xem bên dưới). | + +### API keys + +| Quyền | Tuyến HTTP | Cho phép gì | +|---|---|---| +| `keys:create` | `POST /keys` | Tạo một API key mới được phạm vi giới hạn. **Không** cấp chỉnh sửa quyền của key hiện có (đó là `keys:update`). | +| `keys:read` | `GET /keys` | Liệt kê các key hiện có. Các bí mật không bao giờ được trả về bởi điểm cuối này. | +| `keys:update` | `PATCH /keys/:id` | Chỉnh sửa quyền của key hiện có. Quyền **con người/chỉ dành cho dashboard**; nó không thể được gán cho API key (một bearer key có thể tạo key nhưng không bao giờ chỉnh sửa chúng). | +| `keys:disable` | `POST /keys/:id/disable` | Thu hồi key. Các key được bảo vệ (`admin`, `dashboard-assistant`) không thể bị vô hiệu hóa; xoay chúng qua biến env + khởi động lại. | +| `keys:regenerate` | `POST /keys/:id/regenerate` | Xoay bí mật của key. Các key được bảo vệ không thể được tạo lại thông qua tuyến này. | + +### Người dùng bảng điều khiển + +| Quyền | Tuyến HTTP | Cho phép gì | +|---|---|---| +| `users:create` | `POST /users`, `GET /users/defaults` | Mời một người dùng bảng điều khiển mới (cấp email + đăng nhập OTP) và đọc bộ quyền mặc định được cấu hình trên bảng điều khiển được sử dụng để hạt giống biểu mẫu mời. | +| `users:read` | `GET /users`, `GET /users/:id` | Liệt kê người dùng và tải một hồ sơ người dùng duy nhất. | +| `users:update` | `PUT /users/:id` | Chỉnh sửa quyền của người dùng. Các bản cập nhật gửi email thay đổi quyền cho người dùng bị ảnh hưởng và có hiệu lực khi yêu cầu tiếp theo của họ; không cần đăng nhập lại. | +| `users:delete` | `DELETE /users/:id`, `POST /users/:id/enable` | Vô hiệu hóa người dùng (thu hồi các phiên của họ ngay lập tức) và kích hoạt lại người dùng đã bị vô hiệu hóa trước đó. | + +Các quyền này hỗ trợ trang **Users** của bảng điều khiển, nơi các phạm vi được cấp của mỗi thành viên được hiển thị dưới dạng chip: + +![Trang Users: một thẻ trên mỗi người dùng bảng điều khiển với email, quyền được cấp và các điều khiển chỉnh sửa/vô hiệu hóa của họ](/agenteye/images/users.png) + +### Cài đặt hoạt động + +| Quyền | Tuyến HTTP | Cho phép gì | +|---|---|---| +| `settings:read` | `GET /settings`, `GET /settings/schema`, `GET /settings/model-context-windows`, `GET /settings/model-context-windows/resolve` | Xem cài đặt hoạt động được quản lý bằng bảng điều khiển và siêu dữ liệu của chúng; liệt kê các ghi đè cửa sổ ngữ cảnh trên mỗi mô hình; và giải quyết cửa sổ hiệu quả cho một mô hình. | +| `settings:write` | `PUT /settings/:key`, `PUT /settings/model-context-windows`, `DELETE /settings/model-context-windows` | Chỉnh sửa cài đặt hoạt động và thêm, thay đổi hoặc loại bỏ ghi đè cửa sổ ngữ cảnh trên mỗi mô hình. Các thay đổi ảnh hưởng đến các sự kiện mới mà không khởi động lại máy chủ. | + +![Trang Settings: cài đặt hoạt động được quản lý bằng bảng điều khiển như đăng nhập được phép và thời gian tồn tại phiên/OTP, có thể chỉnh sửa mà không cần khởi động lại](/agenteye/images/settings.png) + +### Cảnh báo & sự cố + +| Quyền | Tuyến HTTP | Cho phép gì | +|---|---|---| +| `alerts:read` | `GET /alerts`, `GET /alerts/:id` | Xem các định nghĩa cảnh báo đã cấu hình. | +| `alerts:write` | `POST /alerts`, `PUT /alerts/:id`, `DELETE /alerts/:id`, `POST /alerts/:id/test` | Tạo, chỉnh sửa, xóa và test-fire các định nghĩa cảnh báo. | +| `incidents:read` | `GET /alerts/incidents`, `GET /alerts/incidents/:iid`, `GET /alerts/incidents/:iid/comments`, `GET /alerts/incidents/:iid/subscribers` | Xem các sự cố và đường dẫn phân loại của chúng. | +| `incidents:write` | `POST /alerts/:id/incidents` | Mở một sự cố theo cách thủ công với một cảnh báo hiện có. | +| `incidents:ack` | `POST /alerts/incidents/:iid/ack`, `POST /alerts/incidents/:iid/assign`, `POST /alerts/incidents/:iid/resolve`, `POST /alerts/incidents/:iid/comments`, `POST /alerts/incidents/:iid/subscribe`, `POST /alerts/incidents/:iid/unsubscribe` | Xác nhận, gán, giải quyết và bình luận về các sự cố. | + +### Kiểm toán + +| Quyền | Tuyến HTTP | Cho phép gì | +|---|---|---| +| `audits:read` | `GET /audits`, `GET /audits/:id`, `GET /audits/:id/runs`, `GET /audits/findings`, `GET /audits/findings/:fid` | Xem các định nghĩa kiểm toán, lịch sử chạy và phát hiện. | +| `audits:write` | `POST /audits`, `PUT /audits/:id`, `DELETE /audits/:id`, `POST /audits/:id/run`, `POST /audits/findings/:fid/status` | Tạo, chỉnh sửa, xóa và chạy kiểm toán; phân loại phát hiện (xác nhận / tắt tiếng / bỏ / giải quyết / mở lại / gán). | + +> Khi Audits được phát hành, những người được cấp quyền hiện có đã được mở rộng theo cùng hình dạng vai trò với cảnh báo: mọi người dùng và bộ quyền giữ `alerts:read` đã có `audits:read`, và mỗi người giữ `alerts:write` đã có `audits:write`. Các API key hiện có **không** được mở rộng — cấp `audits:*` cho một key một cách rõ ràng nếu nó cần bề mặt kiểm toán. + +> Các cấp quyền được lưu trữ của token `alerts:ack` kế thừa được phân tích cú pháp như `incidents:ack` nên những người trực sàn giữ quyền truy cập mà không cần khóa lại. Token không thể gán từ trình chỉnh sửa người dùng của bảng điều khiển; ma trận cung cấp `incidents:ack` thay thế. + +> Điểm cuối bộ chọn người nhận `GET /alerts/recipients` (liệt kê các email thành viên mà trình chỉnh sửa cảnh báo có thể thông báo) có thể truy cập được bởi người giữ **hoặc** `alerts:read` **hoặc** `alerts:write`, vì vậy trình chỉnh sửa cảnh báo có thể điền bộ chọn mà không được cấp `users:read`. + +> Người xem bảng điều khiển cần **cả hai** `dashboards:read` (để tải các chế độ xem đã lưu) và `evaluations:read` (các chỉ số health được tính toán từ dữ liệu đánh giá). Cấp `dashboards:write` để cho phép người dùng tạo hoặc chỉnh sửa bảng điều khiển, và `dashboards:delete` để loại bỏ chúng. + +> `/health` và `/auth/*` (yêu cầu OTP, xác minh OTP, kiểm tra phiên, đăng xuất) không xác thực theo thiết kế; chúng là luồng đăng nhập và điểm kiểm tra tính khả dụng. `GET /access-granters` yêu cầu một key hợp lệ nhưng không có quyền cụ thể, do đó bất kỳ người dùng đã đăng nhập nào cũng có thể thấy những quản trị viên nào liên hệ để yêu cầu thay đổi quyền truy cập. + +--- + +## Bộ quyền + +Bộ quyền cho phép bạn áp dụng một vai trò được đặt tên thay vì chọn các token riêng lẻ mỗi lần. Thay vì chọn một tá quyền từng cái một cho mỗi người dùng bảng điều khiển hoặc API key mới, bạn chọn một bộ, và mọi người được gán cho nó đều có một cấp quyền nhất quán, có thể xem xét. Chỉnh sửa một bộ tùy chỉnh sẽ áp dụng lại cấp quyền mới cho mọi người dùng đã được gán cho nó, vì vậy một thay đổi vai trò là một chỉnh sửa thay vì một quét qua mỗi thành viên. + +Mỗi tổ chức được hạt giống với ba bộ dựng sẵn: + +| Bộ | Quyền | Dự định cho | +|---|---|---| +| `read-only` | `events:read`, `keys:read`, `users:read`, `evaluations:read`, `dashboards:read`, `queries:read`, `settings:read`, `alerts:read`, `audits:read`, `incidents:read` | Quyền truy cập chỉ xem trên mọi bề mặt hoạt động. | +| `standard` | mọi thứ trong `read-only`, cộng với `evaluations:trigger`, `queries:run`, `incidents:ack`, `agent:use` | Chỉ đọc cộng với các hành động sàn hàng ngày: chạy truy vấn, đánh giá lại phiên, xác nhận sự cố và sử dụng trợ lý AI. | +| `admin` | mọi quyền có thể gán được | Kiểm soát toàn bộ tổ chức. | + +Ba bộ dựng sẵn là **bất biến**; tên của chúng luôn có cùng một ý nghĩa, vì vậy `read-only`, `standard` và `admin` có thể được tham chiếu một cách an toàn trong chính sách và onboarding. Một nhà điều hành có thể tạo các **bộ tùy chỉnh** bổ sung để mô hình các vai trò cụ thể cho tổ chức của bạn (ví dụ, vai trò "tác giả bảng điều khiển" hoặc vai trò "chỉ bộ thu thập"). + +Bộ được bề mặt trong bảng điều khiển và được quản lý qua API tại `GET /permission-sets` (liệt kê, được kiểm soát bởi `users:read`) và `POST /permission-sets` / `PUT /permission-sets/:name` / `DELETE /permission-sets/:name` (tạo, chỉnh sửa, xóa một bộ tùy chỉnh, được kiểm soát bởi `settings:write`). Xóa hoặc chỉnh sửa một bộ dựng sẵn bị từ chối. + +Thành viên bộ là những gì hỗ trợ hai tính năng khác: + +- **`DEFAULT_USER_PERMISSIONS`** (cấp quyền được chọn trước khi quản trị viên mở **+ người dùng mới**) mặc định là bộ `standard`. Xem [Deployment](/vi/agenteye/deployment). +- **Cờ `--set`** trên `agenteye-orgctl` (quản lý thành viên nhà điều hành) bắt đầu một thành viên từ một bộ được đặt tên, mà sau đó bạn tinh chỉnh bằng `--add` / `--remove`. Xem [Tenant Management](/vi/agenteye/tenant-management). + +> Khi một bộ bao gồm một quyền không thể gán được cho key (ví dụ, một bộ tùy chỉnh mang `keys:update`), hạt giống của một key từ bộ đó sẽ bỏ các token không thể gán được; máy chủ sẽ từ chối key nếu không với HTTP 422. Người dùng bảng điều khiển không phải chịu hạn chế đó. + +--- + +## Key Admin Bootstrap + +Admin key là thông tin đăng nhập gốc duy nhất cho phép nhà điều hành khởi động quyền truy cập từ không có gì: với nó bạn có thể tạo mỗi key được phạm vi giới hạn khác, mời những người dùng bảng điều khiển đầu tiên và cấu hình phiên bản trước khi bất kỳ key nào khác tồn tại. Đó là key duy nhất bạn không tạo thông qua API key; nó được cung cấp từ môi trường nên máy chủ có thể tiếp cận được khi khởi động lần đầu. + +Đặt biến môi trường `ADMIN_KEY` trên máy chủ. Trên mỗi lần khởi động, máy chủ sẽ upsert giá trị này dưới dạng admin key có tất cả quyền. + +Để xoay: thay đổi `ADMIN_KEY` thành bí mật mới và khởi động lại máy chủ. + +--- + +## Phạm vi tổ chức + +**Các tổ chức chính nó được tạo và quản lý ngoài dòng bởi nhà điều hành, không phải thông qua API key này.** Vòng đời tổ chức và thành viên (tạo / đổi tên / xóa / thanh lọc một tổ chức; thêm / cập nhật / loại bỏ một thành viên) được thực hiện bằng CLI **`agenteye-orgctl`** chạy bên trong pod máy chủ; không có API HTTP hoặc nút bảng điều khiển cho nó. Xem [Tenant Management](/vi/agenteye/tenant-management). Những gì *không* thay đổi: **các API key cho mỗi tổ chức vẫn được tạo ra trong bảng điều khiển (hoặc qua API key này)** bởi các thành viên tổ chức. + +Trong triển khai nhiều tổ chức, mọi key mà thành viên tổ chức tạo (thông qua API key này hoặc trang **Keys** của bảng điều khiển) thuộc về **một tổ chức** và chỉ có thể đọc hoặc ghi dữ liệu của tổ chức đó; tổ chức được đóng dấu trên key khi tạo và được thực thi trên mỗi yêu cầu. Hai key bootstrap là ngoại lệ duy nhất: key `admin` (được hạt giống từ `ADMIN_KEY`) và key `dashboard-assistant` (được hạt giống từ `AGENT_API_KEY`) là **phạm vi phiên bản** (chúng không mang tổ chức). Vùng chứa bảng điều khiển xác thực bằng key `admin` để nó có thể ủy quyền các yêu cầu cho mỗi tổ chức thay mặt cho các thành viên đã đăng nhập. Các triển khai một người thuê không cần suy nghĩ về điều này; tất cả các key thuộc về tổ chức `default` dựng sẵn. + +--- + +## Tạo Key + +Sử dụng admin key (hoặc bất kỳ key nào có quyền `keys:create`) để tạo các key được phạm vi giới hạn bổ sung. + +### Key bộ thu thập (chỉ nhập) + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "prod-collector", + "key": "your-collector-secret", + "permissions": ["events:add"] + }' +``` + +### Key bảng điều khiển (chỉ đọc) + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "dashboard", + "key": "your-dashboard-secret", + "permissions": ["events:read", "keys:read"] + }' +``` + +Khi bạn tạo một key trên HTTP API, bạn cung cấp giá trị `key` tự mình; chọn một bí mật mạnh và lưu trữ nó một cách an toàn. (Bảng điều khiển hoạt động theo cách khác: nó tạo một bí mật mạnh cho bạn và hiển thị nó một lần khi tạo; xem [Key Management in the Dashboard](#key-management-in-the-dashboard).) Phản hồi xác nhận key đã được tạo: + +```json +{ + "id": "550e8400-e29b-41d4-a716-446655440000", + "name": "prod-collector", + "permissions": ["events:add"], + "created_at": "2026-04-01T12:00:00Z" +} +``` + +--- + +## Liệt kê Key + +```bash +curl -s http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +Bí mật của key không được trả về trong các phản hồi danh sách, chỉ ID, tên và quyền. + +--- + +## Vô hiệu hóa Key + +Vô hiệu hóa thu hồi quyền truy cập ngay lập tức mà không xóa hồ sơ key. + +```bash +curl -s -X POST http://your-server:8080/keys//disable \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +--- + +## Tạo lại Key + +Tạo một bí mật mới cho một key hiện có. Bí mật cũ bị vô hiệu hóa ngay lập tức. + +```bash +curl -s -X POST http://your-server:8080/keys//regenerate \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +Phản hồi bao gồm bí mật văn bản thường mới, **chỉ hiển thị một lần**. + +--- + +## Quản lý Key trong Bảng điều khiển + +Trang **Keys** trong bảng điều khiển cung cấp giao diện người dùng cho tất cả các hoạt động trên. Bạn cần một key có quyền `keys:read` để xem danh sách, và `keys:create` / `keys:update` / `keys:disable` / `keys:regenerate` cho các hành động tạo / chỉnh sửa / vô hiệu hóa / tạo lại tương ứng. Chỉnh sửa quyền của key (`keys:update`) tách biệt với việc tạo key (`keys:create`), vì vậy bạn có thể cấp cho nhà điều hành khả năng tạo key mà không có khả năng điều chỉnh phạm vi của các key hiện có, hoặc ngược lại. Admin key bao gồm tất cả những cái này. + +Khi bạn tạo một key từ bảng điều khiển, bạn không cung cấp bí mật; bảng điều khiển tạo một bí mật mạnh cho bạn và hiển thị nó **một lần** khi tạo. Sao chép ngay lập tức và lưu trữ nó một cách an toàn; nó không bao giờ được hiển thị lại, chính xác như với một lần tạo lại. Bạn vẫn có thể chọn quyền của key một cách trực tiếp, hoặc hạt giống chúng từ một bộ quyền (xem bên dưới). + +![Trang API Keys: một thẻ trên mỗi key hiển thị tên, quyền được cấp và thời gian tạo của nó, với các hành động tạo lại và vô hiệu hóa; các key được bảo vệ như `admin` được đánh dấu](/agenteye/images/api-keys.png) + +--- + +## Bố cục Key được Khuyến nghị + +| Key | Quyền | Được sử dụng bởi | +|---|---|---| +| `admin` (bootstrap qua biến env `ADMIN_KEY`) | tất cả | Ops/setup, và vùng chứa bảng điều khiển (xác thực bằng `ADMIN_KEY`, ủy quyền các yêu cầu người dùng với kiểm tra quyền) | +| Key bộ thu thập cho mỗi máy chủ | `events:add` | Bộ thu thập trên mỗi máy agent | +| `dashboard-assistant` (bootstrap qua biến env `AGENT_API_KEY`) | `events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run` | Vùng chứa trợ lý AI, được hạt giống tự động, **được bảo vệ**; không thể chỉnh sửa qua API | +| Key telemetry trợ lý (tùy chọn) | `events:add` | Tự lợi sử dụng của trợ lý AI, nếu được bật | + +> **Key trợ lý.** Key của trợ lý được **hạt giống tự động** bởi máy chủ từ biến env `AGENT_API_KEY` (bí mật tương tự mà agent trình bày như `AGENTEYE_API_KEY`); không có bước tạo key thủ công và không liên quan đến admin key. Quyền của nó được cố định trong mã nguồn nên phạm vi không thể được mở rộng bằng cấu hình sai: đọc trên các sự kiện / đánh giá / bảng điều khiển, cộng với dashboards-write và queries-read / write / run cho luồng tác giả "Ask AI to write a query". Tất cả SQL vẫn đi qua cùng vai trò chỉ đọc và kiểm tra `sql_guard` như một truy vấn được viết bởi người dùng, vì vậy điều này mở rộng *bề mặt tác giả*, không phải bề mặt dữ liệu; các hoạt động tá hại (`queries:delete`, `dashboards:delete`) cố ý ở ngoài key trợ lý. Giống như key `admin`, nó được **bảo vệ**: nó không thể bị vô hiệu hóa hoặc tạo lại thông qua API key, chỉ xoay bằng cách thay đổi `AGENT_API_KEY` và khởi động lại. Người dùng *bảng điều khiển* ngoài ra cần quyền `agent:use` để xem và sử dụng trợ lý. Nếu bạn bật tự lợi sử dụng, cấp cho trợ lý một key `events:add` riêng biệt. \ No newline at end of file diff --git a/docs/vi/agenteye/assistant.mdx b/docs/vi/agenteye/assistant.mdx new file mode 100644 index 00000000..0b5db74c --- /dev/null +++ b/docs/vi/agenteye/assistant.mdx @@ -0,0 +1,196 @@ +--- +title: "Trợ lý AI" +description: "Tài liệu về Trợ lý AI của AgentEye." +--- + + +Bảng điều khiển bao gồm một **trợ lý AI** tùy chọn, một bảng trò chuyện được ghim ở cạnh phải của bảng điều khiển giúp trả lời các câu hỏi bằng ngôn ngữ tự nhiên về các agents của bạn ("chất lượng đang xu hướng như thế nào trong prod tuần này?", "những sessions nào gặp lỗi hôm nay?", "tóm tắt session này") và khi người dùng cho phép từng hành động, nó sẽ soạn thảo và lưu các truy vấn SQL và bảng điều khiển thay mặt họ. Nó cung cấp các liên kết có thể nhấp trực tiếp đến các sessions, truy vấn và bảng điều khiển liên quan, và nó **biết về trang hiện tại**: hỏi về "session này" khi xem một session và nó sẽ hiểu ý của bạn. + +Bảng dock hiển thị dưới dạng một **thanh dọc 44px mỏng** theo mặc định: một ký tự dấu nhắc `›_` cộng với một chấm chỉ báo sức khỏe có màu. Nhấp vào thanh (hoặc nhấn `⌘J` / `Ctrl+J`) để mở rộng nó thành bảng trò chuyện đầy đủ. Bảng mở rộng **có thể thay đổi kích thước** từ 320 đến 640 pixel bằng cách kéo cạnh trái của nó; độ rộng ưa thích của bạn được ghi nhớ khi tải lại. + +Nó chạy dưới dạng một container **`agent`** nội bộ nhỏ (trên Claude Agent SDK) mà chỉ bảng điều khiển có thể truy cập. Nó **bị tắt theo mặc định** và ở trạng thái ẩn cho đến khi bạn cấu hình một điểm cuối LLM. + +--- + +## Nó có thể và không thể làm gì + +- **Đọc dữ liệu hoạt động mà người dùng yêu cầu có thể nhìn thấy.** Sự kiện, đánh giá, sessions, hàng đợi công việc đánh giá, truy vấn đã lưu và bảng điều khiển đã lưu, được phân loại theo yêu cầu dựa trên quyền đọc của người dùng. Các công cụ đọc được thực hiện ngay lập tức. +- **Ghi được kiểm soát bằng cách phê duyệt từng hành động.** Nó có thể tạo truy vấn đã lưu (`create_saved_query`, `update_saved_query`), chạy SQL dự thảo lại với vai trò chỉ đọc để xác thực nó (`run_query`) và lắp ráp bảng điều khiển từ các truy vấn đó (`create_dashboard`, `update_dashboard`, `add_query_to_dashboard`). Mỗi lần ghi sẽ tạm dừng để nhắc **Phê duyệt / Từ chối / Hỏi một câu hỏi**; SDK không gọi công cụ cho đến khi người vận hành nhấp Phê duyệt. **Xoá không bao giờ có sẵn cho trợ lý**; các hoạt động phá hủy dữ liệu vẫn được giữ với các nhà vận hành. +- **SQL soạn thảo được xem qua cùng xác thực `sql_guard` và vai trò chỉ đọc như SQL được viết bởi người dùng** (chỉ SELECT/WITH, không có câu lệnh nhiều dòng). Thực thi được định tuyến bằng các bảng mà truy vấn chạm vào: các truy vấn tham chiếu đến các bảng phân tích (events, evaluations, sessions) chạy với tư cách người dùng chỉ đọc ClickHouse của tổ chức (được phạm vi hóa theo tổ chức bằng chính sách hàng, với giới hạn thực thi 10 giây và giới hạn hàng 100k) trong khi các truy vấn chỉ chạm các bảng quan hệ chạy trên vai trò Postgres chỉ đọc (10 giây, 10k hàng). Trợ lý không thể mở rộng bề mặt dữ liệu; nó chỉ có thể tạo trên bề mặt truy vấn mà nhà vận hành đã có. +- Nó sử dụng một **khóa trợ lý chuyên dụng** (xem bên dưới) được gieo với một bộ quyền cố định; ngay cả khi mô hình hoạt động sai, nó cũng không thể vượt quá những phạm vi đó. +- Mỗi người dùng bảng điều khiển cần quyền **`agent:use`** để xem và sử dụng trợ lý. Các công cụ được lọc theo yêu cầu để phù hợp với quyền dữ liệu của người dùng riêng, vì vậy người dùng `events:read` sẽ nhận các công cụ sự kiện nhưng không có công cụ `dashboards:write`. + +--- + +## Bảng dock AI nhận biết trang: soạn thảo trên `/queries`, trò chuyện ở những nơi khác + +Bảng dock trợ lý ở bên phải **nhận biết trang**. Bộ chọn mô hình, lịch sử trò chuyện, chấm chỉ báo sức khỏe mô hình và đầu vào trò chuyện không thay đổi, nhưng **các chip mẫu trạng thái trống, văn bản giữ chỗ và điểm cuối backend mà thông báo của người dùng chạm tới** tất cả đều chuyển đổi tự động dựa trên tuyến đường hiện tại. Bảng dock trở thành "trợ lý AI cho bất kỳ trang nào bạn đang đứng trên đó". + +**Hai backends, được chọn theo trang (với các ghi đè mỗi chip).** + +| Tuyến đường | Backend mặc định trang | Lý do | +| ------------------------------ | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | +| `/queries`, `/queries/new` | `POST /api/agent/compose-sql` (không có vòng lặp công cụ) | Người dùng đang bắt đầu mới; SQL ≤1s token đầu tiên được phát trực tiếp vào trình chỉnh sửa | +| `/queries/` (hiện có) | `POST /api/agent/chat` (trợ lý vòng lặp công cụ đầy đủ), mặc định trang | Các tin nhắn được nhập tự do nên cho phép người dùng hỏi bất cứ điều gì ("giải thích cái này", "cái này làm gì?"); các chip tái cấu trúc chọn ngược lại thành compose-sql thông qua `kind` mỗi chip | +| mọi trang khác | `POST /api/agent/chat` (trợ lý vòng lặp công cụ đầy đủ) | Công cụ đọc + công cụ ghi được phê duyệt | + +Các chip trên `/queries/` mang một `kind` rõ ràng để một trang có thể trộn hai luồng một cách liền mạch. Bộ chip mặc định là hai chip **chat** (`giải thích truy vấn trên màn hình`, `truy vấn này làm gì?`) cộng với năm chip **compose-sql** (`tham số hóa theo phạm vi ngày`, `thêm bộ lọc status='error'`, v.v.). Các tin nhắn được nhập tự do rơi vào mặc định trang (chat), vì vậy một câu hỏi như "tại sao cái này lại chậm?" sẽ nhận được câu trả lời dạng văn bản, trong khi nhấp vào chip `tham số hóa theo phạm vi ngày` sẽ định tuyến thông qua điểm cuối soạn thảo và chỉnh sửa SQL. + +Khi trình soạn thảo chạy ở **chế độ chỉnh sửa** (nó thấy một `currentSql` không trống vì người dùng đang ở `/queries/` hoặc `/queries/new` với SQL được đề xuất đã được tải), lời nhắc hệ thống của nó chuyển từ "soạn một truy vấn mới" thành "sửa đổi SQL được cung cấp tối thiểu: bảo tồn lựa chọn bảng, tên cột, cấu trúc nối, bí danh, thụt lề". Mô hình được hiển thị một bộ ví dụ làm việc riêng biệt trước/sau (tham số hóa, thêm bộ lọc, chuyển đổi thành bucket hàng giờ), vì vậy một tái cấu trúc được nhấp chip tạo ra một diff tối thiểu so với SQL của trình chỉnh sửa, không phải viết lại từ đầu. + +Nhấp vào một chip soạn thảo (hoặc nhập tự do trên `/queries/new`) → SQL phát trực tiếp vào thông báo trợ lý dưới dạng một khối ` ```sql ` được bao quanh. **Ngay khi luồng kết thúc, nếu Monaco được gắn trên tuyến đường hiện tại, trình chỉnh sửa sẽ tự động sáng lên trong chế độ diff** (bản gốc ở bên trái, bản được đề xuất ở bên phải, một dấu `▾ AI đề xuất chỉnh sửa` ở trên cùng, và các viên **Chấp nhận / Từ chối** phía dưới). Người dùng không cần tìm hoặc nhấp vào nút `Chèn vào trình chỉnh sửa` để xem diff. Nút Chèn vẫn được hiển thị dưới khối SQL dưới dạng kích hoạt lại thủ công (hữu ích sau khi Từ chối hoặc khi người dùng đã điều hướng đi và quay lại), và nó vẫn là con đường duy nhất khi người dùng ở trên một trang không phải trình chỉnh sửa (ví dụ: danh sách các truy vấn đã lưu); ở đó nó sẽ lưu trữ SQL trong `sessionStorage` và điều hướng đến `/queries/new`, nơi trình chỉnh sửa vừa được gắn sẽ đọc kho lưu trữ khi gắn và mở chế độ diff tương tự. + +Nếu SQL được đề xuất giống byte với những gì đã có trong trình chỉnh sửa (một chỉnh sửa vô-op), tự động mở sẽ bị bỏ qua; chúng tôi không hiển thị một diff trống. Nút `Chèn vào trình chỉnh sửa` cũng là vô-op trong trường hợp đó. + +Khi người dùng chấp nhận một gợi ý trên `/queries/new`, hành động chính của thanh công cụ đọc **`save`** thay vì `create`; SQL đã được trao cho họ bởi trợ lý; mô hình tinh thần là "hoàn thành cái này", không phải "viết từ đầu". Nhãn lật một lần bảng dock chèn SQL và vẫn là `save` cho đến khi điều hướng trang. Trên `/queries/` nút luôn đọc `save`; không có gì thay đổi ở đó. + +Bên ngoài `/queries`, bảng dock hoạt động chính xác như trước: trò chuyện đầy đủ với các thẻ phê duyệt công cụ, nhận biết bối cảnh trang, trích dẫn. + +**Quyền / kiểm soát.** Điểm cuối soạn thảo kiểm soát quyền `queries:run` theo người dùng (đọc tương đương; người dùng vẫn phải nhấp Chấp nhận và Chạy, và Chạy đi qua `sql_guard` + `references_ch_tables` định tuyến hiện có trên máy chủ Rust). Điểm cuối trò chuyện kiểm soát `agent:use`. Cả hai đều vẫn yêu cầu một kết nối LLM được cấu hình trên container `agent`; nếu không có bất kỳ điều nào được cấu hình, bảng dock sẽ hiển thị một biểu ngữ "trợ lý không được cấu hình trên triển khai này" trên một trong hai tuyến đường. + +**Từ chối.** Trình soạn thảo từ chối bất kỳ yêu cầu nào mà nó không thể thỏa mãn bằng một truy vấn phân tích chỉ đọc và phát ra `-- REFUSE: ` thay vì SQL. Nó từ chối các yêu cầu sẽ ghi dữ liệu hoặc truy cập các bảng bên ngoài các chế độ xem phân tích (`api_keys`, `users`, `dashboards`, `saved_queries`, `evaluation_jobs`), và nó từ chối các yêu cầu văn bản thuần túy ("giải thích cái này", "cái này làm gì?") trên tuyến đường soạn thảo; những cái đó thuộc về tuyến đường trò chuyện và tạo ra câu trả lời văn bản ở đó. Bảng dock hiển thị chuỗi từ chối dưới dạng một chip lỗi đỏ nội tuyến trong thông báo trợ lý; không có gì được chèn vào. + +**Lựa chọn mô hình.** Được chia sẻ với tuyến đường trò chuyện. Bộ chọn mô hình trong tiêu đề bảng dock áp dụng cho cả hai điểm cuối (cuộc gọi soạn thảo chuyển mô hình được chọn thông qua `resolveModel()` trên dịch vụ agent). Khi `AGENTEYE_AGENT_MODELS` liệt kê nhiều mô hình, các nhà vận hành có thể trộn một tùy chọn lớp Haiku cho trình soạn thảo với tùy chọn lớp Sonnet cho trò chuyện; người dùng chọn mỗi cuộc hội thoại. + +**Mẫu theo trang.** Mỗi trang có mẫu riêng của nó (tiêu đề, nội dung phần thân, văn bản giữ chỗ và các chip gợi ý) để bảng dock thích ứng với trang bạn đang đứng. Các chip được cung cấp trên một tuyến đường nhất định ánh xạ đến các ý định giống nhau mà trình soạn thảo được tinh chỉnh, vì vậy nhấp vào một gợi ý tạo ra chỉnh sửa bạn mong đợi. + +**Tắt nó.** Giống như tuyến đường trò chuyện: bảng dock + trình soạn thảo đều được kiểm soát bởi container `agent` và kết nối LLM của nó. Nếu bạn muốn hành vi chỉ trò chuyện cho một người dùng cụ thể, hãy xóa quyền `queries:run` (nó cũng vô hiệu hóa nút **Chạy** của trình chỉnh sửa); nếu bạn muốn hành vi chỉ soạn thảo, hãy xóa `agent:use` khỏi các vai trò của người dùng đó, sau đó thêm lại `queries:run` riêng để họ có thể vẫn thực thi SQL được tác giả viết. + +--- + +## Bật nó + +Dịch vụ `agent` được gửi trong tệp Docker Compose và các bản kê khai Kubernetes. Để bật trợ lý, cung cấp **(1)** một điểm cuối LLM và **(2)** khóa dữ liệu chuyên dụng của trợ lý. + +### 1. Chọn một kết nối LLM + +Chọn một trong những cái này và đặt các biến tương ứng trên dịch vụ `agent`: + +**a) Trực tiếp từ Anthropic** + +``` +ANTHROPIC_API_KEY=sk-ant-... +``` + +**b) Thông qua Portkey (được khuyên dùng; slug danh mục mô hình, chỉ khóa)** + +``` +PORTKEY_API_KEY= +AGENTEYE_AGENT_MODEL=@/claude-sonnet-4-6 +``` + +Đây là con đường đơn giản nhất: trong Portkey, hãy thiết lập một **tích hợp Anthropic** (Danh mục mô hình); nó sẽ nhận một **slug**. Đặt tên mô hình dưới dạng `@/` và slug sẽ thực hiện định tuyến nhà cung cấp + thông tin xác thực, vì vậy **không cần khóa ảo**, chỉ cần khóa Portkey API của bạn. Agent chỉ gửi `x-portkey-api-key` và trỏ đến cổng Portkey; Portkey giải quyết phần còn lại. (Một tên mô hình *plain* sẽ thất bại với "x-portkey-config or x-portkey-provider header is required"; tiền tố `@slug/` là cái làm cho chỉ khóa có thể hoạt động.) Đối với một cổng tự lưu trữ, hãy đặt `PORTKEY_BASE_URL`. + +Thích định tuyến theo yêu cầu thay vì slug? Đặt `PORTKEY_VIRTUAL_KEY=` (hoặc `PORTKEY_CONFIG=`) với một `AGENTEYE_AGENT_MODEL` thuần túy. + +**c) Bất kỳ cổng tương thích Anthropic nào khác (LiteLLM, tự lưu trữ, …)** + +``` +ANTHROPIC_BASE_URL=https://your-gateway +# Newline-delimited "Name: Value" header lines (NOT JSON): +ANTHROPIC_CUSTOM_HEADERS=x-my-header: value +``` + +**d) Amazon Bedrock / Google Vertex** + +``` +CLAUDE_CODE_USE_BEDROCK=1 # + standard AWS credentials in the environment +# or +CLAUDE_CODE_USE_VERTEX=1 # + standard GCP credentials in the environment +``` + +Tùy chọn ghim mô hình mặc định với `AGENTEYE_AGENT_MODEL` (mặc định `claude-sonnet-4-6`). Để cho phép người dùng **chọn** từ một số mô hình, hãy đặt `AGENTEYE_AGENT_MODELS` thành danh sách cho phép được phân tách bằng dấu phẩy (ví dụ: `@anthropic-prod/claude-opus-4-7,@anthropic-prod/claude-sonnet-4-6`); một bộ chọn mô hình sẽ xuất hiện trong tiêu đề trò chuyện, và lựa chọn của mỗi người dùng được ghi nhớ. Agent chỉ bao giờ gọi một mô hình trên danh sách cho phép này. + +### 2. Cung cấp khóa trợ lý + +Chọn bất kỳ bí mật ngẫu nhiên nào và cung cấp cho **agent** dưới dạng `AGENTEYE_API_KEY` và cho **server** dưới dạng `AGENT_API_KEY` (cùng một giá trị). Khi khởi động, máy chủ sẽ gieo nó dưới dạng một khóa chuyên dụng có tên `dashboard-assistant` với bộ quyền cố định này: `events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run`. Các quyền ghi chỉ bao giờ được thực hiện thông qua các công cụ được kiểm soát bằng cách phê duyệt (xem "Nó có thể và không thể làm gì" ở trên). **Không có bước tạo khóa thủ công và không có khóa admin liên quan**. Bộ quyền được cố định trong máy chủ, và khóa được gieo **được bảo vệ**: nó không thể bị vô hiệu hóa hoặc tái tạo thông qua API khóa; xoay nó bằng cách thay đổi giá trị và khởi động lại máy chủ. **Không** tái sử dụng khóa admin/bảng điều khiển. + +```bash +SECRET="$(openssl rand -base64 32)" +# on the agent service: +AGENTEYE_API_KEY="$SECRET" +# on the server service: +AGENT_API_KEY="$SECRET" +``` + +Trên Kubernetes điều này được kết nối cho bạn: đặt `AGENTEYE_API_KEY` trong bí mật `agenteye-agent` và Deployment máy chủ đã đọc giá trị đó dưới dạng `AGENT_API_KEY`. + +### 3. Đặt token chia sẻ bảng điều khiển ↔ agent + +Đặt cùng `AGENTEYE_AGENT_TOKEN` trên **cả hai** dịch vụ `dashboard` và `agent`. Bảng điều khiển trình bày nó khi gọi dịch vụ agent nội bộ; agent từ chối các cuộc gọi không có nó. + +### 4. Cấp cho người dùng quyền truy cập + +Cung cấp cho các nhà vận hành bảng điều khiển liên quan quyền `agent:use` (xem [enterprise-docs/api-keys.md](/vi/agenteye/api-keys)). Người dùng không có nó sẽ không bao giờ thấy trợ lý. + +Khi một điểm cuối LLM và khóa chỉ đọc được đặt, hãy khởi động lại **máy chủ** (để gieo khóa chỉ đọc) và dịch vụ **agent**. Bảng dock trợ lý xuất hiện ở cạnh phải cho bất kỳ người dùng `agent:use` nào, thu gọn theo mặc định; nhấp vào thanh hoặc nhấn `⌘J` / `Ctrl+J` để mở rộng. + +--- + +## Tham chiếu biến môi trường + +Đặt trên dịch vụ **`agent`**: + +| Biến | Mục đích | +|---|---| +| `PORTKEY_API_KEY` | Định tuyến thông qua Portkey (agent xây dựng kết nối cổng từ cái này) | +| `PORTKEY_VIRTUAL_KEY` | Khóa ảo Portkey cho thông tin xác thực Anthropic của bạn (tùy chọn nếu khóa có cấu hình mặc định) | +| `PORTKEY_CONFIG` / `PORTKEY_BASE_URL` | Cấu hình Portkey được đặt tên / URL cổng Portkey tự lưu trữ (tùy chọn) | +| `PORTKEY_PROVIDER` | Slug nhà cung cấp Portkey — một tùy chọn định tuyến thứ ba cùng với `PORTKEY_VIRTUAL_KEY` / `PORTKEY_CONFIG` (chỉ được sử dụng khi cả hai không được đặt) | +| `ANTHROPIC_API_KEY` | Truy cập Anthropic trực tiếp (thay thế cho cổng / Bedrock / Vertex) | +| `ANTHROPIC_AUTH_TOKEN` | Mã thông báo Bearer cho một cổng xác thực qua `Authorization: Bearer` thay vì `x-api-key` (tùy chọn) | +| `ANTHROPIC_BASE_URL` | Điểm cuối cho một cổng không phải Portkey | +| `ANTHROPIC_CUSTOM_HEADERS` | Tiêu đề bổ sung cho một cổng không phải Portkey: các dòng `Name: Value` được phân tách bằng dòng mới (không phải JSON) | +| `CLAUDE_CODE_USE_BEDROCK` / `CLAUDE_CODE_USE_VERTEX` | Định tuyến qua Bedrock / Vertex | +| `AGENTEYE_AGENT_MODEL` | Id mô hình mặc định (mặc định `claude-sonnet-4-6`) | +| `AGENTEYE_AGENT_MODELS` | Danh sách cho phép được phân tách bằng dấu phẩy của các mô hình mà người dùng có thể chọn từ trong tiêu đề trò chuyện. Để trống để có một mô hình duy nhất cố định. Mô hình mặc định ở trên phải là một trong những cái này (nếu không nó được thêm vào). | +| `AGENTEYE_AGENT_MAX_CONCURRENCY` | Trò chuyện đồng thời tối đa cho mỗi pod (mặc định 4); các yêu cầu dư thừa nhận 429 | +| `AGENTEYE_API_KEY` | Khóa dữ liệu của trợ lý. Đặt **cùng** giá trị với `AGENT_API_KEY` của máy chủ, được gieo với một bộ quyền phạm vi cố định khi khởi động (xem bước 2). | +| `AGENTEYE_AGENT_TOKEN` | Bí mật chia sẻ với bảng điều khiển | +| `AGENTEYE_SERVER_URL` | URL máy chủ AgentEye (mặc định `http://server:8080`) | +| `AGENTEYE_AGENT_ALLOW_NO_ORG` | **Đa người thuê.** Tắt theo mặc định (thất bại kín): trợ lý từ chối một yêu cầu `/chat` không mang bối cảnh tổ chức với `400`, vì mọi công cụ nó chạy đều được phạm vi hóa thành một tổ chức. Bảng điều khiển luôn gửi bối cảnh đó sau khi nó nhận biết tổ chức, vì vậy bạn thường để cái này không được đặt. Đặt thành `1` **chỉ** trong quá trình triển khai chuyển tiếp khi một bảng điều khiển chưa nhận biết tổ chức đang nói chuyện với một agent nhận biết tổ chức, để trợ lý quay lại tổ chức `default` thay vì từ chối. Xóa nó khi nâng cấp bảng điều khiển đáp ứng. | +| `AGENTEYE_AGENT_MAX_STEPS` | Các bước sử dụng công cụ tối đa mỗi câu trả lời (mặc định 8) | +| `AGENTEYE_AGENT_TIMEOUT_MS` | Thời chờ yêu cầu `/chat` tổng thể (tất cả các lần quay của mô hình + các bước công cụ), tính bằng mili giây (mặc định 90000); công cụ SQL có giới hạn 10s riêng | +| `AGENTEYE_AGENT_SELF_TELEMETRY` | `1` để ghi lại các lần chạy của riêng trợ lý vào AgentEye | +| `AGENTEYE_TELEMETRY_API_KEY` | Khóa riêng `events:add` để tự động hóa | +| `AGENTEYE_AGENT_ENV` | Thẻ môi trường được áp dụng cho tự động đo từ xa của trợ lý (mặc định `prod`) | + +Đặt trên dịch vụ **`dashboard`**: + +| Biến | Mục đích | +|---|---| +| `AGENTEYE_AGENT_URL` | Nơi bảng điều khiển tiếp cận dịch vụ agent. Các bản kê khai Kubernetes và tệp Compose được gói đóng đặt cái này thành `http://agent:9100`. Để trống để ẩn trợ lý hoàn toàn. | +| `AGENTEYE_AGENT_TOKEN` | Phải phù hợp với token của agent | + +--- + +## Đo từ xa & xem những gì người dùng hỏi + +Nội dung nhắc **ở lại bên trong các hệ thống riêng của bạn** theo mặc định. Ba lớp: + +1. **Kho lưu trữ cuộc hội thoại**: mỗi nhắc nhở và câu trả lời được lưu trong cơ sở dữ liệu AgentEye của bạn (theo người dùng, riêng tư) và có thể được tải lại từ bộ chuyển đổi lịch sử của trợ lý. Đây là bản ghi bền về những gì người dùng hỏi. +2. **Phân tích sản phẩm**: bảng điều khiển ghi lại **chỉ siêu dữ liệu** (tần suất sử dụng trợ lý, số lượng công cụ, độ trễ) vào phân tích của bạn. **Văn bản** nhắc nhở không bao giờ được bao gồm trên con đường này. +3. **Tự động hóa (tùy chọn)**: đặt `AGENTEYE_AGENT_SELF_TELEMETRY=1` (cộng với một `events:add` chỉ `AGENTEYE_TELEMETRY_API_KEY`) và trợ lý sẽ ghi các lần chạy của riêng nó vào AgentEye dưới dạng một agent `dashboard-assistant`. Bạn sau đó xem các nhắc nhở của người dùng và lý luận của trợ lý trong các chế độ xem sessions/events giống nhau mà bạn sử dụng cho mọi thứ khác. Lưu ý: các sự kiện đó hiển thị cho bất kỳ ai có `events:read`; nếu điều đó quá rộng, hãy tắt cái này. + +--- + +## Tắt nó + +Bất kỳ điều nào trong số này sẽ tắt trợ lý (thanh railing dock biến mất): + +- Hủy đặt `AGENTEYE_AGENT_URL` trên bảng điều khiển, **hoặc** +- Để điểm cuối LLM không được cấu hình trên agent (không `ANTHROPIC_API_KEY` / gateway / Bedrock / Vertex), **hoặc** +- Không triển khai dịch vụ `agent` nào cả. + +--- + +## Tóm tắt bảo mật + +- **Không ghi lặng lẽ**: các công cụ ghi của trợ lý (`create_saved_query`, `update_saved_query`, `create_dashboard`, `update_dashboard`, `add_query_to_dashboard`) không thể thực hiện mà không cần một cú nhấp chuột rõ ràng của nhà vận hành vào nút Phê duyệt trong trò chuyện; cổng trước cuộc gọi của SDK chặn công cụ cho đến khi phê duyệt tiếp cận agent qua một kênh phụ. Không có cài đặt nào tắt cổng này. +- **Phạm vi dữ liệu cố định, hẹp**: trợ lý xác thực với máy chủ bằng một khóa chuyên dụng có bộ quyền cố định trong máy chủ (`events:read`, `evaluations:read`, `dashboards:read`, `dashboards:write`, `queries:read`, `queries:write`, `queries:run`). Các lần ghi duy nhất nó có thể tạo là các truy vấn đã lưu và bảng điều khiển; máy chủ từ chối bất kỳ điều gì ngoài phạm vi đó bất kể mô hình cố gắng. +- **Không bề mặt xoá**: khóa không mang quyền xoá và không có công cụ xoá nào được công khai. Các nhà vận hành xoá thông qua giao diện người dùng bảng điều khiển, không bao giờ trợ lý. +- **Chỉ nội bộ**: agent không có tuyến đường công khai; chỉ bảng điều khiển có thể gọi nó, và chỉ có token chia sẻ. (Trong Kubernetes, một NetworkPolicy hạn chế agent chỉ tiếp cận máy chủ AgentEye và điểm cuối LLM.) +- **Phạm vi theo người dùng**: chỉ người dùng `agent:use` mới nhận được trợ lý, và nó chỉ được cung cấp các công cụ phù hợp với quyền đọc của mỗi người dùng. +- **Không HTML thô / không thoát link**: câu trả lời hiển thị dưới dạng markdown được làm sạch; các liên kết bên ngoài bị khử độc. + +Xem [enterprise-docs/troubleshooting.md](/vi/agenteye/troubleshooting) để biết các vấn đề phổ biến. \ No newline at end of file diff --git a/docs/vi/agenteye/audits.mdx b/docs/vi/agenteye/audits.mdx new file mode 100644 index 00000000..d9a87968 --- /dev/null +++ b/docs/vi/agenteye/audits.mdx @@ -0,0 +1,107 @@ +--- +title: "Audits — phát hiện cải tiến agentic" +description: "AgentEye Audits — tài liệu phát hiện cải tiến agentic." +--- + + +Audits là những công việc lặp lại khai thác các nhật ký agent của bạn **trên các phiên** để tìm những điều đáng cải tiến. Trong khi alert theo dõi một số liệu mà bạn đã biết gần như thời gian thực, audit *điều tra*: theo lịch bạn đặt, nó chạy một đợt chính sách xác định trên cửa sổ thời gian, sau đó thả một **agent tin cậy AI** lỏng lẻo trên các phiên của bạn — agent truy vấn dữ liệu, đọc các bản ghi đáng nghi, và (khi cần thiết) chạy các script phân tích nhỏ, sau đó viết ra **khuyến nghị cải tiến** với bằng chứng đằng sau mỗi cái. + +Sử dụng audits để trả lời "tôi nên sửa hoặc cải tiến cái gì trong agents của mình?" — và alerts để được báo sớm nhất khi một ngưỡng cụ thể bị vượt qua. Mỗi cải tiến liên kết đến những phiên chính xác và truy vấn đằng sau nó, và chỉ cần một cú nhấp chuột tạo alert được điền sẵn để bắt các lần tái diễn. + +Bề mặt bảng điều khiển là **`//audits`** (thanh bên → *analyze* → *audits*), được kiểm soát bởi các quyền `audits:read` / `audits:write`. + +--- + +## Cách một lần chạy hoạt động + +Mỗi lần chạy có hai tầng — một mặt nền xác định và một cuộc điều tra agentic. + +### 1. Đợt chính sách (xác định) + +Trước khi bất kỳ mô hình nào chạy, audit thực hiện một danh mục nhỏ **kiểm tra chính sách SQL** trên cửa sổ: các truy vấn tổng hợp có giới hạn báo cờ các mẫu xấu đã biết và báo cáo *bao nhiêu* sự kiện / *sự kiện nào* phiên phù hợp — không bao giờ là văn bản phù hợp. Danh mục bao gồm: + +- **Rò rỉ bí mật / thông tin xác thực** trong tải trọng sự kiện — khóa truy cập AWS, `sk-…` khóa API, khóa riêng PEM, mã thông báo JWT / bearer, và các gán thông tin xác thực `KEY=…`. +- **Chỉ báo tiêm dấu nhắc** — "ignore previous instructions", "reveal your system prompt", và những cái tương tự. +- **PII** — số có hình dạng SSN (heuristic). +- **Các quyền công cụ từ chối** và **các vòng lặp gọi công cụ chạy trốn**. + +Các đợt chính sách được duy trì dưới dạng các phát hiện (kind `policy`) **luôn luôn bề mặt** (chúng không bao giờ bị cắt bởi tận cùng mỗi lần chạy), và chúng được trao cho agent AI như những dẫn đầu bắt đầu. Vì tầng này không cần mô hình, một audit vẫn tạo ra những tín hiệu bảo mật quan trọng nhất của nó ngay cả khi agent AI không khả dụng. + +### 2. Cuộc điều tra agentic (AI) + +Audit sau đó chạy một **agent tin cậy tự chủ** (dịch vụ Agents SDK Claude tương tự cung cấp trợ lý bảng điều khiển, với một lời nhắc dành riêng cho audit). Với **phạm vi** audit (các agent đã chọn × môi trường) và **cửa sổ thời gian**, agent: + +- chạy các truy vấn SQL chỉ đọc trên các bảng phân tích của bạn, +- đọc một vài bản ghi phiên đại diện, +- tùy chọn viết và chạy các **script Python trong hộp cát trong pod bị khóa** (không mạng, không truy cập tệp hệ thống, bí mật được làm sạch) để phân tích SQL không thể biểu thị — phân cụm lỗi, tính toán phân phối, quét tải trọng nó đã tìm nạp, +- và ghi lại mỗi **cải tiến** được chứng thực tốt nó tìm thấy. + +Nó hoạt động thông qua nhiều dòng điều tra — phân cụm lỗi, dịch chuyển so với đường cơ sở, thất bại mục tiêu trong bản ghi, sử dụng công cụ sai, đánh đổi chất lượng/chi phí, và khoảng trống trong phạm vi — tại **độ nhạy** audit (thấp / trung bình / cao). Mỗi cải tiến **phải trích dẫn bằng chứng**: các id phiên mà agent thực tế kiểm tra và/hoặc SQL nó chạy. Máy chủ xác nhận rằng các phiên được trích dẫn tồn tại và **loại bỏ bất kỳ cải tiến nào không có bằng chứng tồn tại**, vì vậy agent điều tra nhưng không bao giờ phát minh ra. + +Mỗi cải tiến mang: + +- một **khuyến nghị** (thay đổi cụ thể cần thực hiện — điều chỉnh lời nhắc, sửa lược đồ công cụ, chính sách thử lại, guardrail, phạm vi đánh giá nhiều hơn), +- một **tác động dự kiến** và ước tính **nỗ lực** (thấp / trung bình / cao), +- một **độ lớn** — `big` (một nhà khai thác nên được báo sớm), `medium` (thuộc báo cáo chạy), hoặc `small` (ngữ cảnh bảng điều khiển), +- một **dấu vân tay** ổn định (từ danh mục + phạm vi của vấn đề, *không phải* các phiên của lần chạy này) để vấn đề tương tự được theo dõi từng lần chạy ngay cả khi bằng chứng thay đổi, +- và, nơi một trình quan sát xác định đơn giản có thể bắt tái diễn, một **alert được đề xuất** bạn có thể tạo trong một cú nhấp chuột. + +> **Tầng AI là tùy chọn nhưng được khuyến nghị.** Nếu không có agent AI được cấu hình cho đường ống audit, các lần chạy vẫn thực hiện, duy trì các phát hiện chính sách, và thành thật báo cáo "phân tích không khả dụng" cho tầng agentic thay vì im lặng qua. + +### Chế độ lỗi + +Cải tiến phân loại vào **danh mục chế độ lỗi** bền của tổ chức bạn (hoặc đề xuất một chế độ mới). Các chế độ cung cấp các mẫu một danh tính ổn định trên các lần chạy và theo dõi tái diễn chân trời dài. + +## Chu kỳ triage + +Trên trang phát hiện (`/audits//findings/`): + +| Hành động | Hiệu ứng | +|---|---| +| **acknowledge** | Giữ phát hiện hiển thị nhưng giảm ưu tiên của nó một nửa. | +| **resolve** | Đánh dấu nó đã sửa chữa. Nếu mẫu thực sự quay trở lại sau này, nó mở lại là **new** — vì vậy một regression là lớn tiếng, không im lặng được gập vào lịch sử. | +| **mute** / **dismiss** | Duy trì loại bỏ: dấu vân tay của mẫu được nhớ và không bao giờ bề mặt lại, ngay cả trên các lần chạy. Sử dụng mute cho "known, accepted"; dismiss cho "not useful". | +| **reopen** | Xóa loại bỏ / giải quyết và xếp hạng mẫu lại. | +| **assign** | Định tuyến phát hiện cho một nhà khai thác (thành viên tổ chức) để sở hữu. Ưu tiên và trạng thái loại bỏ không thay đổi. | + +Tiếng ồn tín hiệu thấp được kiểm soát trên audit với một tận cùng phát hiện trên mỗi lần chạy (`top_k`) trên các cải tiến agentic. Phát hiện chính sách bỏ qua tận cùng (chúng liên quan đến bảo mật và luôn hiển thị). Bất cứ điều gì bị cắt bởi tận cùng được tính trong thống kê lần chạy — không có gì bị thả im lặng. + +## Lên lịch + +- **Cadence** (`schedule_interval_secs`): hàng giờ đến hàng tuần; **daily là mặc định**. Audits cố ý thô hơn alerts — một cuộc điều tra agentic quét các cửa sổ toàn bộ và chạy trong nhiều phút. +- **Window**: một lookback lăn cố định (ví dụ: "mỗi lần chạy quét 7 ngày cuối cùng") hoặc **since-last-run** (mặc định) — mỗi lần chạy chọn từ nơi lần chạy thành công trước đó kết thúc, với một sự chồng chéo nhỏ để các sự kiện ranh giới không bao giờ bị bỏ lỡ. +- Lần chạy tiếp theo được lên lịch một khoảng thời gian đầy đủ sau khi lần chạy trước **hoàn thành**, vì vậy một lần chạy chậm không bao giờ xếp chồng một lần chạy thứ hai đồng thời của cùng một audit. +- **Run now** trên trang audit làm cho nó do ngay lập tức. + +## Lựa chọn mô hình + +Khi tạo audit, bạn có thể chọn mô hình nào cuộc điều tra sử dụng, từ **danh sách các mô hình mà nhà khai thác đã cấu hình** cho dịch vụ agent. Với một mô hình được cấu hình, bộ chọn hiển thị nó như một chú thích; với nhiều hơn, bạn chọn. Để nó không được đặt sử dụng mặc định được cấu hình. + +## Thông báo + +Khi một lần chạy bề mặt **new** phát hiện, audit thông báo cho các kênh được cấu hình của tổ chức bạn — cùng một cổng `alerts.enabled_channels` và cài đặt đường ống alerts sử dụng: + +- **Slack** — tóm tắt các mục đáng kể (`big`) mới với một liên kết sâu. +- **Email** — một **báo cáo audit** được thiết kế liệt kê các cải tiến mới (mức độ nghiêm trọng cao nhất, khuyến nghị mỗi mục, liên kết sâu), được gửi khi audit có một kênh **email** được đính kèm và có ít nhất một phát hiện mới. + +Các phát hiện lặp lại nhưng đã biết không gửi thông báo lại. + +## Tài liệu tham khảo cấu hình + +Các định nghĩa audit được quản lý trong bảng điều khiển (`/audits/new`) hoặc thông qua API. Các cài đặt trên audit bao gồm cadence lịch biểu và window, phạm vi (`{"environments": [...], "agent_ids": [...]}`), độ nhạy (`low` / `medium` / `high`), các kênh thông báo, tận cùng phát hiện trên mỗi lần chạy (`top_k`), và mô hình (thông qua `llm_budget.model`). Các cài đặt máy chủ cấp độ nhà khai thác (hết giờ, hộp cát, URL dịch vụ agent) được tài liệu trong [deployment.md](/vi/agenteye/deployment). + +## API + +Tất cả các điểm cuối được phạm vi tổ chức và tuân theo auth khóa bearer tiêu chuẩn (xem [api-keys.md](/vi/agenteye/api-keys)). + +| Điểm cuối | Quyền | Mục đích | +|---|---|---| +| `GET /audits` · `POST /audits` | `audits:read` / `audits:write` | Liệt kê / tạo định nghĩa audit. | +| `GET` / `PUT` / `DELETE /audits/:id` | read / write / write | Kiểm tra, chỉnh sửa, xóa một audit. | +| `POST /audits/:id/run` | `audits:write` | Làm cho audit do ngay lập tức. | +| `GET /audits/:id/runs` | `audits:read` | Lịch sử chạy (window, trạng thái, thống kê, số lượng phát hiện). | +| `GET /audits/findings` | `audits:read` | Các phát hiện toàn tổ chức, có thể lọc theo `audit_id`, `status`; sắp xếp theo ưu tiên. | +| `GET /audits/findings/:fid` | `audits:read` | Chi tiết phát hiện đầy đủ (khuyến nghị, bằng chứng, ưu tiên). | +| `POST /audits/findings/:fid/status` | `audits:write` | Triage: `{"action": "ack" \| "mute" \| "dismiss" \| "resolve" \| "reopen" \| "assign"}`. | + +Đối với "audit chạy nhưng không tìm thấy gì", "hộp cát mã bị vô hiệu hóa", và "email audit không được gửi", xem [troubleshooting.md](/vi/agenteye/troubleshooting#audits). \ No newline at end of file diff --git a/docs/vi/agenteye/cli-recipes.mdx b/docs/vi/agenteye/cli-recipes.mdx new file mode 100644 index 00000000..684b45ee --- /dev/null +++ b/docs/vi/agenteye/cli-recipes.mdx @@ -0,0 +1,169 @@ +--- +title: "Công thức CLI cho agents" +description: "Tài liệu công thức CLI AgentEye cho agents." +--- + +Kéo dữ liệu phiên, sự kiện và đánh giá (cũng như kích hoạt lại đánh giá) trực tiếp từ một script hoặc coding agent, với JSON sạch trên stdout có thể ống trực tiếp vào `jq`. Những công thức này biến dữ liệu quan sát của AgentEye thành thứ mà người dùng terminal hoặc coding agent AI (Claude Code, Cursor) có thể truy vấn và tự động hóa, mà không cần nhấp qua bảng điều khiển. + +Các mẫu dưới đây đã sẵn sàng để sao chép-dán cho CLI AgentEye (`agenteye`). Để cài đặt, xác thực và danh sách tùy chọn đầy đủ, xem [CLI](/vi/agenteye/cli); chạy `agenteye -h` hoặc `agenteye -h` để xem trợ giúp tích hợp. + +## Các quy tắc vàng + +1. **Các tùy chọn toàn cầu đi *trước* lệnh.** `agenteye --json sessions` là đúng; `agenteye sessions --json` là không đúng. Các tùy chọn toàn cầu là `--json`, `--base-url`, `--org`, `--token`, `--insecure`/`--secure`, `--timeout`, `--quiet`, `--no-color`. +2. **Truyền `--json` bất cứ khi nào bạn phân tích đầu ra.** Dữ liệu đi đến **stdout** dưới dạng JSON; trạng thái của con người và lỗi đi đến **stderr**, vì vậy stdout vẫn sạch để ống vào `jq`. +3. **Phân nhánh dựa trên mã thoát**, không phải văn bản stderr: `0` ok · `2` đối số không tốt · `3` không thể tiếp cận bảng điều khiển · `4` không đăng nhập hoặc hết hạn · `5` thiếu quyền. +4. **Khám phá bằng `-h`.** Mỗi lệnh ghi lại các bộ lọc, định dạng giá trị và hình dạng JSON của nó. + +## Thiết lập một lần + +```bash +export AGENTEYE_DASHBOARD_URL=https://agenteye.example.com # để bạn không lặp lại --base-url +agenteye login --email you@example.com # dán mã được gửi qua email; hợp lệ ~24h +``` + +## Xác nhận xác thực trước khi thực hiện công việc + +`whoami` không bao giờ gặp lỗi khi phiên bị thiếu hoặc hết hạn; nó báo cáo `logged_in:false` thay thế, vì vậy agent có thể dễ dàng kiểm tra trạng thái xác thực. (Nó vẫn có thể thoát với mã khác không phải là 0 nếu không có URL cơ sở được đặt hoặc bảng điều khiển không thể tiếp cận.) + +```bash +if [ "$(agenteye --json whoami | jq -r .logged_in)" != "true" ]; then + echo "Not authenticated. Run: agenteye login" >&2; exit 1 +fi +``` + +## Tìm phiên thất bại hoặc điểm số thấp + +```bash +# phiên trong 24h qua có đánh giá gặp lỗi +agenteye --json sessions --since 24h --status error | jq -r '.sessions[].session_id' + +# đánh giá có điểm số <= 0.5 về tính hữu ích, cho một agent +agenteye --json evals --agent-id checkout-bot --score helpfulness:..0.5 \ + | jq '.evaluations[] | {session_id, scores}' +``` + +Lọc điểm số nằm trên **`evals`**, không phải `sessions`. `--score KEY:MIN..MAX` có thể lặp lại và kết hợp bằng AND; mỗi ràng buộc là tùy chọn (`..0.5` có nghĩa là ≤ 0.5, `0.9..` có nghĩa là ≥ 0.9). Bạn có thể truyền tối đa 20 bộ lọc điểm số cho mỗi yêu cầu; nhiều hơn trả về HTTP 400. `sessions` chia sẻ các bộ lọc `--env`, `--status`, `--agent-id`, `--session-id` và phạm vi thời gian với `evals`, nhưng không có `--score`. + +## Đọc một phiên từ đầu đến cuối + +Không có lệnh `session show` duy nhất — kết hợp dấu vết sự kiện với đánh giá của phiên: + +```bash +# đánh giá mới nhất của phiên (trạng thái + điểm số) +agenteye --json evals --session-id run-001 | jq '.evaluations[0] | {status, scores}' + +# mỗi sự kiện trong lần chạy (tăng --limit để quét toàn bộ) +agenteye --json events --session-id run-001 --all --limit 1000 | jq '.events[] | {ts, event_type}' + +# chỉ các lệnh gọi công cụ trong một phiên +agenteye --json events --session-id run-001 --event-type tool_use,tool_result --all \ + | jq '.events[].payload' +``` + +## Tìm nạp mọi thứ (phân trang) + +Kết quả là mới nhất trước tiên và được phân trang bằng con trỏ. + +```bash +# một lần: tìm nạp tối đa 500 hàng trong các trang 200 hàng +agenteye --json events --session-id run-001 --limit 500 --all > events.json + +# phân trang thủ công: đưa next_cursor vào lại +page=$(agenteye --json events --limit 100) +cursor=$(echo "$page" | jq -r '.next_cursor // empty') +[ -n "$cursor" ] && agenteye --json events --limit 100 --cursor "$cursor" +``` + +## Giảm bớt đầu ra bằng --fields + +Hạn chế các khóa (trong cả bảng và `--json`) để giảm những gì agent phải đọc. + +```bash +agenteye --json sessions --since 7d --fields session_id,status,scores | jq -c '.sessions[]' +agenteye --json events --session-id run-001 --fields ts,event_type --all +``` + +Tên trường không xác định bị từ chối (thoát `2`) với danh sách hợp lệ, một cách rẻ tiền để khám phá tên trường. + +## Khám phá các giá trị bộ lọc hợp lệ + +```bash +agenteye --json list envs | jq -r '.values[]' # giá trị cho --env +agenteye --json list tools | jq -r '.values[]' # tên công cụ; cũng agents, models, event_types, … +agenteye --json list score_filters | jq -r '.values[]' # KEY hợp lệ cho --score KEY:MIN..MAX +``` + +## Chọn org của bạn (đa người thuê) + +Nếu bạn thuộc về nhiều hơn một org, hãy chọn tenant hoạt động tại lúc đăng nhập (nó được lưu): + +```bash +agenteye login --org acme --email you@corp.com # đặt tenant trong cùng bước với đăng nhập +agenteye --json orgs list | jq -r '.orgs[].org_slug' +agenteye --org globex --json sessions --since 24h # ghi đè cho một lệnh +``` + +Đăng nhập đa org mà không có `--org` thoát với mã khác không phải là 0 và in các org để chọn từ. + +## Cấp khóa API cho SDK/bộ sưu tập + +```bash +# bí mật được in MỘT LẦN — với --json nó là trường .key +key=$(agenteye --json keys create ci-bot --add events:read.add | jq -r '.key') +agenteye keys regenerate ci-bot --yes # xoay; agenteye keys disable ci-bot --yes để thu hồi +``` + +## Chạy một truy vấn đã lưu hoặc ad-hoc + +```bash +agenteye --json query run --sql "select count(*) from analytics.events" | jq '.rows' +agenteye --json query run errs --arg prod | jq '.rows' # truy vấn đã lưu + một $1 vị trí +``` + +## Phân loại một sự cố không tương tác + +```bash +id=$(agenteye --json incidents list --state firing | jq -r '.incidents[0].id') +agenteye incidents ack "$id" +agenteye incidents assign "$id" you@corp.com +agenteye incidents resolve "$id" --yes +``` + +> Các đột biến tự động bỏ qua lời nhắc xác nhận của chúng dưới `--json` hoặc khi stdin không phải TTY, vì vậy agents không bao giờ bị treo; truyền `--yes`/`-y` để bỏ qua nó một cách rõ ràng nơi khác. + +## Xử lý mã thoát trong một script + +```bash +out=$(agenteye --json sessions --since 1h) || code=$? +case "${code:-0}" in + 0) echo "$out" | jq '.sessions | length' ;; + 4) echo "Session expired - run 'agenteye login'." >&2 ;; + 5) echo "Missing permission (ask an admin for evaluations:read)." >&2 ;; + 3) echo "Dashboard unreachable - check the URL." >&2 ;; + *) echo "Unexpected error (exit ${code})." >&2 ;; +esac +``` + +## Hình dạng đầu ra JSON + +| Lệnh | JSON stdout (với `--json`) | +|---|---| +| `whoami` | `{"logged_in": true, "id", "email", "is_instance_admin", "active_org", "permissions": [...], "memberships": [...]}` hoặc `{"logged_in": false}` | +| `orgs list` | `{"active_org", "orgs": [{"org_slug","org_name","permission_set","permissions"}]}` | +| `events` | `{"events": [...], "next_cursor": }` | +| `evals` | `{"evaluations": [...], "next_cursor": }` | +| `sessions` | `{"sessions": [...], "next_cursor": }` | +| `errors` | `{"errors": [...], "next_cursor": }` | +| `list ` | `{"kind", "values": [...]}` | +| `keys list` / `keys create` | `{"keys": [...]}` / `{id, name, permissions, created_at, key}` (`key` hiển thị một lần) | +| `query run` | `{columns: [{name,type}], rows: [[...]], truncated, elapsed_ms}` | +| `users list` / `settings list` | `{"users": [...]}` / `{"settings": [...]}` | +| `alerts list` / `incidents list` | `{"alerts": [...]}` / `{"incidents": [...]}` | +| tạo/cập nhật/xóa (bất kỳ) | đối tượng tài nguyên, hoặc `{"deleted": true, "id"}` cho xóa | +| lỗi (bất kỳ, với `--json`) | `{"error": "...", "exit_code": , "status"?: , "hint"?: "..."}` trên stdout | + +- Mỗi mục **sự kiện** (`events`): `id, session_id, agent_id, event_type, ts, payload, environment`. +- Mỗi mục **đánh giá** (`evals`): `id, session_id, agent_id, environment, status, scores, reasoning, summary, error, attempt_count, duration_ms, completed_at, created_at`. +- Mỗi mục **phiên** (`sessions`): `session_id, agent_id, environment, status, scores, event_count, started_at, last_event_at, first_event_id, last_event_id, latest_evaluation`. + +`--fields` của mỗi lệnh chấp nhận chính xác tên trường của mục riêng của nó — tập hợp khác nhau giữa `sessions` và `evals`, vì vậy tên hợp lệ cho tên này có thể bị từ chối bởi cái kia. \ No newline at end of file diff --git a/docs/vi/agenteye/cli-skill.mdx b/docs/vi/agenteye/cli-skill.mdx new file mode 100644 index 00000000..ada159d4 --- /dev/null +++ b/docs/vi/agenteye/cli-skill.mdx @@ -0,0 +1,95 @@ +--- +title: "AgentEye CLI Agent Skill" +description: "Tài liệu AgentEye CLI Agent Skill." +--- + + +**AgentEye CLI skill** (`agenteye-cli`) là một *Agent Skill* có thể cài đặt được, dạy cho một agent lập trình — Claude Code, Codex và các công cụ tương thích — cách vận hành triển khai AgentEye của bạn thông qua [`agenteye` CLI](/vi/agenteye/cli) từ những yêu cầu bằng tiếng Anh thường: *"có gì bị hỏng hôm nay không?"*, *"cấp cho CI một key chỉ có thể push events"*, *"xác nhận sự cố đang phát triển và giao nó cho tôi"*. + +Nó **không phải** là một dịch vụ hoặc một binary riêng biệt. Nó là một gói hướng dẫn nhỏ hoạt động trên CLI mà bạn đã cài đặt: agent gọi `agenteye --json …`, phân tích JSON sạch sẽ và trả lời bạn bằng văn bản. Mọi thứ nó có thể làm, bạn cũng có thể tự làm bằng cách gõ các lệnh tương tự. + +--- + +## Nó liên quan đến các giao diện AgentEye khác như thế nào + +AgentEye cung cấp cho bạn bốn cách để tiếp cận cùng một dữ liệu và điều khiển. Chúng bổ sung cho nhau: + +| Giao diện | Nó là gì | Chạy ở đâu | Sử dụng nó khi | +|---|---|---|---| +| **[CLI](/vi/agenteye/cli)** | Tham chiếu lệnh/flag cho `agenteye` | Terminal của bạn | Bạn muốn chạy hoặc viết script một lệnh cụ thể | +| **[CLI recipes](/vi/agenteye/cli-recipes)** | Các mẫu `jq`/pipeline sẵn sàng sao chép | Terminal / scripts của bạn | Bạn đang tích hợp CLI vào tự động hóa | +| **CLI skill** (tài liệu này) | Một cửa ra bằng ngôn ngữ tự nhiên cho CLI | Coding agent của bạn, trên workstation của bạn | Bạn muốn *chỉ cần hỏi* và để agent chọn lệnh | +| **[In-dashboard AI Assistant](/vi/agenteye/assistant)** | Một chat nhúng trong dashboard | Một container `agent` nội bộ trong cluster của bạn | Bạn muốn Q&A trong dashboard trên dữ liệu của bạn | + +### vs. In-dashboard AI Assistant — một sự phân biệt quan trọng + +Đây là hai công cụ khác nhau với phạm vi ảnh hưởng rất khác nhau: + +- **In-dashboard AI Assistant** ([assistant.md](/vi/agenteye/assistant)) là một chat nhúng trong dashboard, được hỗ trợ bởi một container `agent` nội bộ. Nó **chỉ đọc cộng với việc tạo có sự phê duyệt**: nó có thể soạn thảo các truy vấn đã lưu và dashboard, nhưng mọi lần ghi đều tạm dừng để chờ nhấp phê duyệt rõ ràng của bạn, và nó không bao giờ xóa. Nó được bảo vệ bởi quyền `agent:use` và chỉ nhìn thấy dữ liệu cho tổ chức bạn đang xem. +- **CLI skill** chạy trên *workstation của bạn* bên trong *coding agent của bạn* và điều khiển CLI `agenteye` như **bạn**. Nó có thể thực hiện **toàn bộ bề mặt của CLI, bao gồm các thay đổi** — tạo/xoay vòng/vô hiệu hóa API key, thay đổi cài đặt tổ chức, giải quyết sự cố, xóa truy vấn đã lưu — chỉ bị giới hạn bởi quyền của đăng nhập CLI của bạn. Hãy coi nó chính xác như cách bạn sẽ xử lý khi chạy những lệnh đó bằng tay. + +--- + +## Điều kiện tiên quyết + +1. **`agenteye` CLI được cài đặt** và trên `PATH` (xem [cli.md](/vi/agenteye/cli) — `pipx install agenteye`). +2. **URL dashboard của bạn được đặt** (`AGENTEYE_DASHBOARD_URL`, hoặc agent truyền `--base-url`). +3. **Một phiên đã đăng nhập**: trước tiên hãy tự chạy `agenteye login`. Skill **không thể** hoàn thành đăng nhập bằng mã một lần qua email cho bạn — nó sẽ yêu cầu bạn chạy `agenteye login` nếu phiên bị thiếu hoặc hết hạn (mã thoát CLI `4`). + +--- + +## Cài đặt skill + +Agent Skills là các thư mục chứa `SKILL.md` (cộng với các tham chiếu tùy chọn). Bạn cài đặt skill `agenteye-cli` bằng cách đặt thư mục của nó nơi agent của bạn tìm kiếm skill: + +- **Claude Code** — sao chép thư mục `agenteye-cli/` vào `~/.claude/skills/` (có sẵn trong mọi dự án) hoặc vào `/.claude/skills/` (phạm vi cho kho đó). Claude Code tự động khám phá nó; xác minh bằng danh sách `/skills` hoặc chỉ cần đặt một câu hỏi phù hợp với mô tả của nó. +- **Codex (OpenAI)** — Codex đọc cùng `SKILL.md`. `agents/openai.yaml` đi kèm đặt `allow_implicit_invocation: true`, do đó Codex tự động chọn skill khi một tác vụ phù hợp; nếu không, gọi nó rõ ràng như `$agenteye-cli`. + +Skill được duy trì cùng với CLI `agenteye` và được phân phối như một phần của gói AgentEye của bạn — nếu bạn không có thư mục `agenteye-cli`, hãy liên hệ với liên lạc AgentEye của bạn. Không có gì về nó bị hạn chế: nó không cần Docker image và không cần thông tin xác thực, vì nó chỉ điều khiển CLI `agenteye` **công khai** chống lại dashboard của riêng bạn. + +--- + +## An toàn — các thay đổi KHÔNG nhắc khi agent chạy CLI + +**Đọc điều này trước khi để agent thực hiện thay đổi.** + +CLI `agenteye` thường hỏi *"bạn có chắc không?"* trước một hành động phá hủy. Nó **tự động bỏ qua xác nhận đó bất cứ khi nào nó không được gắn vào terminal — đó chính xác là cách một coding agent chạy nó — và `--json` cũng bỏ qua nó.** Do đó lời nhắc an toàn sẽ **không** phát hành cho agent. + +Skill được viết để bù đắp: nó được hướng dẫn để nêu rõ lệnh chính xác mà nó sẽ chạy và nhận được **OK rõ ràng của bạn trước bất kỳ thay đổi trạng thái nào**. Giữ kỷ luật đó — khi bạn điều khiển AgentEye thông qua agent, *bạn* là bước xác nhận. Các lệnh thay đổi trạng thái cần xem: + +- `keys create` / `update` / `disable` / `regenerate` +- `users create` / `update` / `disable` / `enable` +- `settings set` +- `alerts create` / `update` / `delete` / `test` +- các subcommand `incidents` ghi: `ack` / `assign` / `resolve` / `open` / `comment-add` / `comment-delete` / `subscribe` / `unsubscribe` +- `query create` / `update` / `delete` +- `agent rename` / `delete` +- `orgs switch` + +Mọi thứ dưới **Observe** (`events`, `sessions`, `evals`, `errors`, `list`, `whoami`, `orgs list/current/perms`) chỉ được đọc và không thay đổi gì. + +Vì agent hoạt động như **bạn**, nó chỉ có thể làm những gì đăng nhập của bạn được phép làm — quyền được giải quyết **trên mỗi tổ chức** (xem [api-keys.md](/vi/agenteye/api-keys)). Một lệnh bạn không có quyền trả về mã thoát `5` với quyền chính xác được đặt tên, do đó agent có thể cho bạn biết chính xác cần yêu cầu gì từ quản trị viên thay vì thất bại mơ hồ. + +--- + +## Bạn có thể hỏi nó cái gì + +Skill ánh xạ ý định bằng tiếng Anh thường đến lệnh `agenteye` đúng, khám phá các giá trị hợp lệ trước (`list `, `whoami`) nên nó không đoán: + +- *"Có gì bị hỏng / đang phát triển trong 24 giờ qua không?"* → `errors --since 24h --aggregate`, rồi một bảng phân tích. +- *"Tại sao session `run-001` lại thất bại?"* → `events --session-id run-001 --all` + `evals --session-id run-001`. +- *"Chất lượng đang xu hướng như thế nào trong tuần này?"* → `evals --aggregate --since 7d`, sau đó đi sâu vào các chạy điểm thấp. +- *"Cấp cho CI một key chỉ có thể push events."* → `keys create ci --add events:add` (nó nêu rõ lệnh, sau đó tạo nó và ghi lại bí mật một lần). +- *"Ai có quyền truy cập? Làm cho Dana chỉ đọc."* → `users list` → `users update dana@… --permission-set read-only` (sau khi xác nhận với bạn). +- *"Xác nhận sự cố đang phát triển và giao nó cho tôi."* → `incidents list --state firing` → `incidents ack ` / `incidents assign you@…`. + +Để biết các lệnh chính xác, cờ và hình dạng JSON đằng sau những cái này, xem [cli.md](/vi/agenteye/cli) và [cli-recipes.md](/vi/agenteye/cli-recipes). + +--- + +## Xem thêm + +- **[CLI](/vi/agenteye/cli)** — tham chiếu lệnh và cờ đầy đủ cho `agenteye`. +- **[CLI recipes cho agents](/vi/agenteye/cli-recipes)** — các mẫu `jq` sẵn sàng sao chép và xử lý mã thoát. +- **[AI Assistant](/vi/agenteye/assistant)** — trợ lý trong dashboard (không nên nhầm với skill terminal này). +- **[API Keys](/vi/agenteye/api-keys)** — mô hình quyền trên mỗi tổ chức giới hạn những gì skill có thể làm. \ No newline at end of file diff --git a/docs/vi/agenteye/cli.mdx b/docs/vi/agenteye/cli.mdx new file mode 100644 index 00000000..f591a0e0 --- /dev/null +++ b/docs/vi/agenteye/cli.mdx @@ -0,0 +1,288 @@ +# AgentEye CLI + +AgentEye CLI (`agenteye`) là một ứng dụng terminal để quản lý triển khai AgentEye của bạn. Nó truy vấn dữ liệu của bạn (phiên, nhật ký sự kiện, đánh giá) và quản trị tổ chức (khóa API, người dùng, cài đặt, cảnh báo, sự cố, truy vấn đã lưu) — mọi thứ mà bảng điều khiển làm được, từ một script hoặc một coding agent. Mỗi lệnh hỗ trợ cờ `--json`, vì vậy nó hoạt động tốt cho cả con người ở dòng lệnh hoặc cho một coding agent (Claude Code, Cursor) chạy và phân tích kết quả. + +> Đây là **CLI `agenteye`**, một công cụ khác biệt so với daemon collector (`agenteye-collector`). CLI giao tiếp với **bảng điều khiển** của bạn; collector gửi sự kiện đến máy chủ. Xem [Cài đặt Collector](/vi/agenteye/collector-installation) để biết thêm về collector. + +--- + +## Cài đặt + +CLI được xuất bản lên PyPI công khai dưới dạng **`agenteye`**. Vì Python SDK của AgentEye cũng sử dụng tên phân phối `agenteye`, hãy cài đặt CLI trong một **môi trường cách ly** (`pipx` hoặc `uv tool`) để hai công cụ không bao giờ xung đột trong cùng một virtualenv: + +```bash +pipx install agenteye +# hoặc +uv tool install agenteye +``` + +`pip install agenteye` thông thường cũng hoạt động nếu bạn không cài đặt Python SDK vào cùng môi trường. CLI yêu cầu Python 3.10+ và không cần token GitHub; đó là một gói công khai. + +Lệnh được cài đặt là **`agenteye`**: + +```bash +agenteye --version +agenteye --help +``` + +--- + +## Xác thực + +CLI xác thực với **bảng điều khiển** bằng mã một lần được gửi qua email: + +```bash +agenteye login --email you@example.com +# Một mã 6 chữ số được gửi qua email cho bạn; dán nó ở lời nhắc. +``` + +Token phiên được lưu trữ trong `~/.agenteye/cli.json` (chỉ có thể đọc được bởi bạn, chế độ `0600`) và hợp lệ trong 24 giờ theo mặc định. Khi nó hết hạn, chạy lại `agenteye login`. + +```bash +agenteye whoami # hiển thị người dùng hiện tại, tổ chức hoạt động và quyền hạn +agenteye logout # thu hồi phiên và xóa token đã lưu +``` + +`whoami` không bao giờ báo lỗi nếu phiên bị thiếu hoặc hết hạn — nó báo cáo `logged_in: false` thay thế, vì vậy một script hoặc agent có thể kiểm tra trạng thái xác thực một cách an toàn (nó vẫn có thể thoát với mã khác không nếu không có URL cơ sở được đặt hoặc bảng điều khiển không thể tiếp cận). + +**Yêu cầu:** email của bạn phải được phép đăng nhập vào bảng điều khiển (hỏi quản trị viên AgentEye của bạn), và bảng điều khiển phải có thể tiếp cận được ở URL cơ sở của nó (xem [Cấu hình](#cấu-hình)). Nếu bạn yêu cầu một mã và không có mã nào đến, email của bạn có thể chưa được bật để truy cập bảng điều khiển. + +--- + +## Chọn tổ chức của bạn (đa tenant) + +Nếu tài khoản của bạn thuộc về nhiều hơn một tổ chức, hãy chọn tổ chức hoạt động **khi đăng nhập** — nó được lưu và sử dụng cho mọi lệnh sau: + +```bash +agenteye login --org acme # xác thực và đặt tenant hoạt động trong một bước +agenteye orgs list # các tổ chức bạn có thể truy cập (tổ chức hoạt động được đánh dấu) +agenteye orgs switch globex # thay đổi mặc định đã lưu +agenteye --org globex sessions # ghi đè cho một lệnh duy nhất +``` + +Nếu bạn chỉ thuộc về một tổ chức, nó sẽ được chọn tự động và bạn có thể hoàn toàn bỏ qua `--org`. Nếu bạn thuộc về một số tổ chức và không chọn cái nào, CLI sẽ liệt kê chúng và yêu cầu bạn chạy lại với `--org `. Tổ chức hoạt động được gửi đến bảng điều khiển trên mọi yêu cầu, và quyền của bạn được giải quyết **cho mỗi tổ chức** — `agenteye whoami` hiển thị tổ chức hoạt động, quyền của bạn trong đó, và tất cả các thành viên của bạn. + +--- + +## Cấu hình + +| Cài đặt | Cờ | Biến môi trường | Mặc định | +|---|---|---|---| +| URL cơ sở của bảng điều khiển | `--base-url` | `AGENTEYE_DASHBOARD_URL` | **bắt buộc** (không có mặc định) | +| Tổ chức/tenant hoạt động | `--org` | `AGENTEYE_ORG` | được chọn khi đăng nhập; lưu trong `~/.agenteye/cli.json` | +| Token phiên | `--token` | `AGENTEYE_CLI_TOKEN` | từ `~/.agenteye/cli.json` | +| Đầu ra JSON | `--json` | `AGENTEYE_CLI_JSON` | tắt | +| Bỏ qua xác minh TLS | `--insecure` / `--secure` | `AGENTEYE_INSECURE` | tắt (lưu khi đăng nhập) | +| Timeout yêu cầu (giây) | `--timeout` | — | 30 | +| Vô hiệu hóa telemetry sử dụng | _(không)_ | `AGENTEYE_ANALYTICS_DISABLED` (hoặc `DO_NOT_TRACK`) | tắt (telemetry bật) | + +Thứ tự giải quyết là **cờ → biến môi trường → tệp cấu hình**. Không có mặc định; bạn phải chỉ cho CLI các bảng điều khiển của bạn, hoặc cho mỗi lệnh (`--base-url https://agenteye.example.com`) hoặc một lần qua môi trường (nó cũng được lưu sau `login` đầu tiên của bạn): + +```bash +export AGENTEYE_DASHBOARD_URL=https://agenteye.example.com +``` + +Thư mục cấu hình tôn trọng `AGENTEYE_HOME` (quy ước tương tự được sử dụng bởi SDK và collector); nếu được đặt, `cli.json` nằm trong `$AGENTEYE_HOME/cli.json`. + +### TLS tự ký hoặc nội bộ + +Nếu bảng điều khiển của bạn được phục vụ qua HTTPS với chứng chỉ tự ký hoặc nội bộ (ví dụ: tên máy chủ load-balancer nguyên),xác minh TLS từ chối nó với lỗi `CERTIFICATE_VERIFY_FAILED`. Truyền `--insecure` để bỏ qua xác minh chứng chỉ: + +```bash +agenteye --base-url https://agenteye.internal --insecure login +``` + +`--insecure` **được lưu vào `cli.json` khi bạn đăng nhập**, vì vậy các lệnh sau sẽ bỏ qua xác minh tự động; bạn không phải lặp lại cờ. Truyền `--secure` cho một lệnh gọi xác minh một lần, hoặc để lưu xác minh lại khi đăng nhập lần tiếp theo. CLI in một cảnh báo đến stderr trước bất kỳ lệnh nào liên hệ với bảng điều khiển khi xác minh bị vô hiệu hóa. Bỏ qua xác minh sẽ loại bỏ bảo vệ chống lại các cuộc tấn công man-in-the-middle; đảm bảo bạn tin tưởng con đường mạng đến bảng điều khiển của bạn (VPN, subnet riêng, v.v.) trước khi dựa vào nó. + +--- + +## Telemetry & quyền riêng tư + +CLI gửi **phân tích sử dụng ẩn danh** đến dịch vụ phân tích của Exosphere (PostHog): lệnh nào được chạy (ví dụ: `sessions`, `keys create`), liệu chúng có thành công hay không, và chúng mất bao lâu. Tín hiệu sử dụng này thông báo cho biết những tính năng nào được ưu tiên. + +- **Không bao giờ có dữ liệu agent, phiên hoặc sự kiện rời khỏi cơ sở hạ tầng của bạn.** Chỉ có CLI usage được báo cáo: tên lệnh và sublệnh (ví dụ: `keys create`), **tên** của các cờ bạn sử dụng (không bao giờ là giá trị của chúng), trạng thái thành công/thoát, và thời lượng — cộng với mỗi sự kiện hành động cho các đột biến (ví dụ: `api_key_created`, `query_run`) chỉ mang tên/enums tĩnh và đếm thô. URL bảng điều khiển, token phiên, email, slug tổ chức, id tài nguyên, SQL, bí mật khóa, và bộ lọc truy vấn của bạn **không bao giờ** được gửi. Các toán tử chỉ được xác định bởi một id nội bộ không rõ ràng, không bao giờ bằng email. +- Telemetry **được bật theo mặc định**. Để tắt nó, đặt `AGENTEYE_ANALYTICS_DISABLED=1` trong môi trường của CLI (CLI cũng tôn trọng quy ước `DO_NOT_TRACK=1` giữa các công cụ). +- CLI gửi trực tiếp đến PostHog (`https://us.i.posthog.com`). **Máy chạy CLI** cần truy cập gửi đi đến máy chủ đó; nếu bị chặn, telemetry sẽ im lặng không làm gì (gửi bị giới hạn thời gian nên nó không bao giờ trì hoãn hoặc phá vỡ lệnh) và CLI không bị ảnh hưởng. + +--- + +## Tùy chọn toàn cục & quy ước + +Đọc một lần; nó áp dụng cho mọi lệnh. + +- **Tùy chọn toàn cục đi TRƯỚC lệnh.** `agenteye --json sessions` là chính xác; `agenteye sessions --json` là lỗi sử dụng. Các tùy chọn toàn cục là `--json`, `--base-url`, `--org`, `--token`, `--insecure`/`--secure`, `--timeout`, `--quiet`, và `--no-color`. +- **`--json` in JSON thuần vào stdout, và không gì khác.** Các dòng trạng thái con người, cảnh báo, và lỗi đi đến **stderr**, vì vậy một lần quay `--json` stdout vẫn sạch để đưa vào `jq` ngay cả khi dòng trạng thái được hiển thị. Mà không có `--json` bạn nhận được một chế độ xem hộp, được tô màu cho mắt con người. +- **Khám phá với `--help`.** Mỗi lệnh và sublệnh có `--help` (và bí danh `-h`): `agenteye -h`, `agenteye sessions -h`, `agenteye keys create -h`. Trợ giúp cấp cao nhất cũng liệt kê các mã thoát và tùy chọn toàn cục. Không có bề mặt máy có thể đọc được toàn cầu; sử dụng `--help` cho mỗi lệnh, cộng với `agenteye query schema` và `agenteye settings schema` dành riêng cho miền cho hai sổ đăng ký đó. +- **Xác nhận tự động bỏ qua cho script và agent.** Các lệnh tạo/cập nhật/xóa nhắc "bạn có chắc không?" trong một terminal tương tác, nhưng **tự động bỏ qua lời nhắc đó dưới `--json` hoặc bất cứ khi nào stdin không phải TTY** — vì vậy script và agent không bao giờ treo. Truyền `--yes`/`-y` để bỏ qua một cách rõ ràng. Vì lời nhắc sẽ không kích hoạt cho một agent, một agent nên xác nhận hành động phá hủy với con người trước. +- **Phân trang:** kết quả là mới nhất trước và được phân trang bằng con trỏ. `--limit N` (bí danh `-n`) giới hạn hàng và **mặc định là 50**; `--all` tự động phân trang (trong các khối 200 hàng) **lên đến `--limit`** — vì vậy `--all` trần cũng dừng ở 50. Để quét đầy đủ, hãy vượt qua một giới hạn rõ ràng cao: `--all --limit 1000`. `--page-size N` kiểm soát khối trên mỗi yêu cầu (tối đa 200); `--cursor ` tiếp tục từ `next_cursor` của trang trước. +- **Bộ lọc thời gian:** `--since` lấy một cửa sổ tương đối — `15m`, `1h`, `6h`, `24h`, `7d`, `30d`, hoặc `all` (các cài đặt trước của bảng điều khiển). `--from`/`--to` lấy các dấu thời gian UTC ISO-8601 rõ ràng **với `T` và múi giờ** (ví dụ: `2026-06-01T00:00:00Z`) cho một phạm vi tùy chỉnh và ghi đè `--since`; một giá trị được phân tách bằng khoảng trắng hoặc không có múi giờ là lỗi sử dụng. +- **`--fields a,b,c`** (trên `events`, `sessions`, `evals`, `errors`) giới hạn đầu ra đến các khóa đó, cho cả bảng và `--json`. Tên không rõ ràng bị từ chối bằng danh sách hợp lệ — một cách rẻ để khám phá tên trường. +- **`--file payload.json`** (hoặc `--file -` để đọc stdin) cung cấp một phần thân yêu cầu JSON đầy đủ nơi tài nguyên có hình dạng phức tạp — trên `alerts create/update`, `settings set`, và `users create/update`. SQL truy vấn đã lưu sử dụng `--sql @file.sql` thay thế. +- **Bộ lọc đa giá trị** được phân tách bằng dấu phẩy → khớp như một tập hợp (union trong một bộ lọc, AND trên các bộ lọc): `--event-type tool_use,tool_result`. Các tùy chọn click không phải variadic, vì vậy `--add a b` bị hỏng — sử dụng `--add a,b`, lặp lại cờ (`--add a --add b`), hoặc trích dẫn (`--add "a b"`). + +--- + +## Tham khảo lệnh + +CLI có **18 lệnh cấp cao nhất**. Tất cả các lệnh đọc chấp nhận `--json` và các tùy chọn toàn cục ở trên; chạy `agenteye -h` (hoặc ` -h`) cho danh sách cờ kỳ diệu và hình dạng JSON của bất kỳ cái nào. + +### Danh tính — `login` · `logout` · `whoami` · `orgs` · `version` · `help` + +```bash +agenteye login --email you@example.com [--org acme] # mã một lần được gửi qua email; lưu phiên +agenteye logout # xóa phiên đã lưu trên máy này +agenteye whoami # người dùng hiện tại, tổ chức hoạt động, quyền hạn +agenteye version # in phiên bản CLI (giống như --version) +agenteye help # trợ giúp cấp cao nhất (giống như --help) +``` + +`orgs` kiểm tra và chuyển đổi tenant hoạt động: + +```bash +agenteye orgs list # các tổ chức của bạn + vai trò của bạn trong mỗi tổ chức (tổ chức hoạt động được đánh dấu) +agenteye orgs switch acme # thay đổi tổ chức hoạt động đã lưu (bỏ qua slug để chọn từ danh sách trên TTY) +agenteye orgs current # thẻ danh tính cho tổ chức hoạt động +agenteye orgs perms # quyền hạn của bạn trong tổ chức hoạt động, được nhóm theo tài nguyên +``` + +### Quan sát (chỉ đọc) — `events` · `sessions` · `evals` · `errors` · `list` + +Không cái nào trong số này cần xác nhận. Bộ lọc được chia sẻ: `--session-id`, `--agent-id`, `--env` (**không** `--environment`), và phạm vi thời gian (`--since` / `--from` / `--to`). + +```bash +# events (bí danh: dấu vết mỗi bước thô) — mới nhất trước +agenteye --json events --session-id run-001 --event-type tool_use,tool_result --all --limit 1000 +agenteye --json events --since 1h --search timeout --all | jq '.events[].payload' + +# sessions — một hàng cho mỗi chạy agent (thời gian/env/agent/session/trạng thái; không lọc điểm) +agenteye --json sessions --since 24h --status error +agenteye --json sessions --agent-id checkout-bot --env prod --all --limit 1000 + +# evals — kết quả đánh giá + điểm; --score lọc theo metric, --aggregate cuộn lên +agenteye --json evals --score helpfulness:0.5..0.8 --score tool_efficiency:..0.3 +agenteye --json evals --aggregate --since 7d --env prod # trộn trạng thái + thống kê điểm cho mỗi khóa + +# errors — sự kiện có lỗi; --aggregate cho số lượng/phiên/agent/lần cuối cùng nhìn thấy +agenteye --json errors --since 24h --aggregate +agenteye --json errors --since 24h --error-type timeout --all --limit 1000 + +# list — khám phá các giá trị bộ lọc hợp lệ trước khi bạn lọc +agenteye list envs # cũng: agents event_types score_filters models hooks triggers tools error_types +``` + +`--score KEY:MIN..MAX` (trên **`evals`**, không `sessions`) có thể lặp lại và được kết hợp AND; mỗi ràng buộc là tùy chọn (`..0.5` có nghĩa là ≤ 0.5, `0.9..` có nghĩa là ≥ 0.9). Tối đa 20 bộ lọc điểm trên mỗi yêu cầu. `evals --scores-full` trả về đối tượng điểm hoàn chỉnh chứ không phải bản tóm tắt. Để đọc **một phiên từ đầu đến cuối**, kết hợp dấu vết sự kiện với đánh giá của nó: + +```bash +agenteye --json events --session-id run-001 --all --limit 1000 | jq '.events[] | {ts, event_type}' +agenteye --json evals --session-id run-001 # điểm + trạng thái của nó +``` + +### Quản lý (được bảo vệ bằng quyền hạn) — `keys` · `users` · `settings` · `alerts` · `incidents` + +**`keys`** — khóa API. Bí mật được tạo cục bộ, gửi đến máy chủ (chỉ lưu trữ một băm), và **hiển thị một lần** khi tạo/tạo lại — nắm bắt nó sau. Với `--json` nó chỉ xuất hiện trong trường `key`. Được tham chiếu bằng **tên**. + +```bash +agenteye keys list # khóa hoạt động trước, sau đó bị thu hồi +agenteye keys show ci-bot +agenteye keys create ci-bot --add events:read.add # phạm vi cho những gì bạn cần; in bí mật MỘT LẦN +agenteye keys create ops --permission-set standard --remove queries:run # hạt giống cài đặt trước, sau đó cắt +agenteye keys update ci-bot --add evaluations:read --yes +agenteye keys regenerate ci-bot --yes # xoay bí mật (cái cũ dừng hoạt động) +agenteye keys disable ci-bot --yes # thu hồi +``` + +Quyền hạn hoạt động như `(permission-set ∪ --add) − --remove`. Token là `slug:action` (ví dụ: `events:read`) hoặc `slug:action.action` để mở rộng một số trên một tài nguyên (`events:read.add` → `events:read`, `events:add`). Cài đặt trước: `read-only`, `standard`, `admin`. Quyền dành riêng cho con người (`keys:update`) không thể được cấp cho khóa. + +**`users`** — thành viên tổ chức, được tham chiếu bằng **email** (một id UUID cũng được chấp nhận). + +```bash +agenteye users list [--active-only] +agenteye users show dev@corp.com +agenteye users create dev@corp.com --permission-set standard +agenteye users update dev@corp.com --add alerts:write --remove queries:delete # dự đoán + xác nhận +agenteye users disable dev@corp.com --yes # có bảo vệ/tự bảo vệ +agenteye users enable dev@corp.com +``` + +**`settings`** — một sổ đăng ký cố định (bạn đọc và thay đổi các khóa hiện có; bạn không thể tạo khóa mới). + +```bash +agenteye settings list # khóa · giá trị · loại · cập nhật (bí mật bị che khuất) +agenteye settings schema # những gì mỗi khóa chấp nhận (loại · phạm vi · mô tả) +agenteye settings set session_ttl_secs --value 86400 --yes +``` + +**`alerts`** — định nghĩa cảnh báo, được tham chiếu bằng **tên**. `create` lấy một NAME vị trí cộng với cờ hoặc một phần thân yêu cầu JSON đầy đủ thông qua `--file`. + +```bash +agenteye alerts list +agenteye alerts show high-errors +agenteye alerts create high-errors --file alert.json # NAME là bắt buộc (vị trí) +agenteye alerts update high-errors --severity critical --yes +agenteye alerts test high-errors --yes # kích hoạt một thông báo thử nghiệm +agenteye alerts delete high-errors --yes +``` + +**`incidents`** — các sự cố cảnh báo, được tham chiếu bằng id (các id ngắn được chấp nhận). `show` in toàn bộ nhật ký hoạt động — đọc nó trước khi hành động. + +```bash +agenteye incidents list --state firing # cũng: acknowledged, resolved +agenteye incidents count +agenteye incidents show +agenteye incidents ack +agenteye incidents assign you@corp.com # người được giao phải là một toán tử +agenteye incidents resolve --yes +agenteye incidents open --alert-id --severity critical # mở một cái thủ công chống lại cảnh báo +agenteye incidents comment-add "root cause: upstream 5xx" +agenteye incidents comment-list ; agenteye incidents comment-delete +agenteye incidents subscribe ; agenteye incidents unsubscribe ; agenteye incidents subscribers +``` + +### Phân tích & trợ lý — `query` · `agent` + +**`query`** — SQL ClickHouse đã lưu cộng với trình chạy ad-hoc. Các truy vấn đã lưu được tham chiếu bằng **tên**; SQL được xác thực phía máy chủ (SELECT/WITH chỉ, timeout câu lệnh, giới hạn hàng). + +```bash +agenteye query schema [TABLE] # bố cục cột của các chế độ xem phân tích +agenteye query run --sql "select count(*) from analytics.events" +agenteye query run errs --arg prod --limit 100 # chạy truy vấn đã lưu + một $1 vị trí +agenteye query list ; agenteye query show errs +agenteye query create errs --sql @errs.sql --description "errored events (24h)" +agenteye query update errs --sql @errs.sql --yes ; agenteye query delete errs --yes +``` + +**`agent`** — trợ lý bảng điều khiển tích hợp (cùng một nhà phân tích chỉ đọc mà bạn có thể trò chuyện với trong bảng điều khiển). Các cuộc trò chuyện được tham chiếu bằng một short chat-id (prefix-resolved). + +```bash +agenteye agent health # trợ lý có được cấu hình/có thể tiếp cận +agenteye agent models # các mô hình bạn có thể chuyển đến --model (mặc định được đánh dấu) +agenteye agent ask "which agents errored most in the last day?" # bắt đầu cuộc trò chuyện; in short id của nó +agenteye agent ask --chat "and which tools did they call?" # tiếp tục cuộc trò chuyện đó +agenteye agent chats ; agenteye agent show +agenteye agent rename --title "error triage" ; agenteye agent delete +``` + +--- + +## Mã thoát + +| Mã | Ý nghĩa | +|---|---| +| 0 | Thành công | +| 1 | Lỗi không mong muốn (ví dụ: bảng điều khiển trả về 5xx) | +| 2 | Lỗi sử dụng (đối số không hợp lệ, lệnh/cờ không rõ ràng, va chạm tên) | +| 3 | Không thể tiếp cận bảng điều khiển | +| 4 | Chưa đăng nhập hoặc phiên hết hạn; chạy `agenteye login` | +| 5 | Được xác thực, nhưng tài khoản của bạn thiếu quyền hạn cần thiết (thông báo đặt tên cho nó) | +| 6 | Tài nguyên được yêu cầu không được tìm thấy (ví dụ: session id hoặc incident id không rõ ràng) | + +Những điều này làm cho CLI an toàn để script: một coding agent có thể phân nhánh trên `4` để nhắc bạn xác thực lại, hoặc `5` để làm nổi bật quyền hạn bị thiếu. Xem [CLI recipes cho agent](/vi/agenteye/cli-recipes) cho các mẫu xử lý mã thoát và hình dạng đầu ra JSON. + +--- + +## Xem thêm + +- **[CLI recipes cho agent](/vi/agenteye/cli-recipes)** — sao chép các mẫu truy vấn, `jq` one-liner, `--fields` projections, xử lý mã thoát, và hình dạng đầu ra JSON, được viết cho các coding agent điều khiển CLI. +- **[AgentEye CLI skill](/vi/agenteye/cli-skill)** — đóng gói CLI này dưới dạng Claude Code / Codex *skill* có thể cài đặt để một coding agent điều khiển AgentEye từ các yêu cầu bằng tiếng Anh thuần túy. +- **[API Keys](/vi/agenteye/api-keys)** — mô hình quyền hạn đằng sau `keys create --add …`. +- **[AI Assistant](/vi/agenteye/assistant)** — bật trợ lý mà `agent ask` giao tiếp với. \ No newline at end of file diff --git a/docs/vi/agenteye/collector-installation.mdx b/docs/vi/agenteye/collector-installation.mdx new file mode 100644 index 00000000..816c1e68 --- /dev/null +++ b/docs/vi/agenteye/collector-installation.mdx @@ -0,0 +1,400 @@ +--- +title: "Cài đặt Collector" +description: "Tài liệu cài đặt AgentEye Collector." +--- + + +Daemon `agenteye-collector` đảm bảo rằng telemetry của các agent của bạn đến AgentEye mà không bao giờ làm chậm ứng dụng của bạn. Mã của bạn ghi các sự kiện vào một thư mục cục bộ và tiếp tục; collector nhận trách nhiệm từ đó, tải lên từng file trong vài mili giây và tồn tại qua các lần khởi động lại, sự cố mạng và lỗi máy chủ tạm thời. Các lần tải lên thất bại được thử lại với exponential backoff, và một lần quét phục hồi định kỳ tái xếp hàng bất kỳ thứ gì bị bỏ lại do sự cố hoặc triển khai. Kết quả là truyền tải bền vững, fire-and-forget: các agent của bạn tiếp tục chạy ở tốc độ tối đa trong khi collector đảm bảo không có sự kiện nào bị mất trong quá trình truyền. + +Về mặt cơ học, collector là một daemon nhẹ theo dõi `$AGENTEYE_HOME/events/` (mặc định: `~/.agenteye/events/`) để tìm các file `.jsonl` được viết bởi Python SDK và tải chúng lên máy chủ AgentEye. + +> **Đã được đổi tên:** lệnh collector bây giờ là **`agenteye-collector`** (trước đó là `agenteye`). Tên ngắn `agenteye` bây giờ thuộc về CLI AgentEye. Nếu bạn đang nâng cấp cài đặt hiện có, xem [enterprise-docs/collector-migration.md](/vi/agenteye/collector-migration). + +--- + +## Điều kiện tiên quyết + +- `AGENTEYE_TOKEN` của bạn: một GitHub PAT mà bạn tự tạo (xem [enterprise-docs/github-token.md](/vi/agenteye/github-token)) +- URL máy chủ và một khóa API collector (xem [enterprise-docs/api-keys.md](/vi/agenteye/api-keys)) + +--- + +## Tùy chọn A: Binary (được khuyến nghị) + +Các binary tĩnh được xây dựng sẵn có sẵn cho Linux, macOS và Windows (x86_64 và arm64). Tải xuống binary cho nền tảng của bạn trực tiếp từ repo `agenteye-enterprise/releases` dưới tag phát hành mới nhất `collector/v`. + +Tên artifact có sẵn: + +| Nền tảng | Artifact | +|---|---| +| Linux x86_64 | `agenteye-collector-linux-x86_64` | +| Linux arm64 | `agenteye-collector-linux-arm64` | +| macOS x86_64 | `agenteye-collector-darwin-x86_64` | +| macOS arm64 | `agenteye-collector-darwin-arm64` | +| Windows x86_64 | `agenteye-collector-windows-x86_64.exe` | +| Windows arm64 | `agenteye-collector-windows-arm64.exe` | + +**Tải xuống với CLI `gh`** (thay đổi phiên bản và chọn artifact của nền tảng của bạn): + +```bash +VERSION=0.0.1-beta.13 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "collector/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-collector-linux-x86_64' + +chmod +x agenteye-collector-linux-x86_64 +sudo mv agenteye-collector-linux-x86_64 /usr/local/bin/agenteye-collector +``` + +**Hoặc với `curl`:** + +```bash +VERSION=0.0.1-beta.13 +ARTIFACT=agenteye-collector-linux-x86_64 +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + -L "https://github.com/agenteye-enterprise/releases/releases/download/collector%2Fv${VERSION}/${ARTIFACT}" \ + -o agenteye-collector +chmod +x agenteye-collector +sudo mv agenteye-collector /usr/local/bin/agenteye-collector +``` + +--- + +## Tùy chọn B: Docker + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +docker pull ghcr.io/agenteye-enterprise/collector:beta-latest +``` + +> Các bản dựng beta hiện tại xuất bản tag nổi `:beta-latest`; `:latest` được gán chỉ cho các phát hành ổn định. Để triển khai có thể lặp lại, hãy ưu tiên một tag phiên bản được ghim như `:v0.0.1-beta.13`. + +**Chạy:** + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-collector \ + -e AGENTEYE_URL=https://ingest.example.com/events \ + -e AGENTEYE_KEY="$AGENTEYE_KEY" \ + -e AGENTEYE_HOME=/data \ + -v "$HOME/.agenteye:/data" \ + ghcr.io/agenteye-enterprise/collector:beta-latest \ + start +``` + +Image chính thức chạy dưới dạng người dùng không phải root, vì vậy hãy đặt `AGENTEYE_HOME` rõ ràng và gắn kết spool máy chủ lưu trữ vào nó. Mount volume chia sẻ cùng một thư mục `~/.agenteye/` mà Python SDK ghi vào trên máy chủ. Nếu bạn đã đặt `AGENTEYE_HOME` ở nơi khác trên máy chủ, hãy gắn kết thư mục đó thay vì `$HOME/.agenteye`. + +--- + +## Cấu hình + +Tất cả các tùy chọn có thể được đặt ba cách (ưu tiên cao nhất trước): + +1. Cờ CLI: `agenteye-collector start --url https://...` +2. Biến môi trường: `AGENTEYE_URL=https://...` +3. File cấu hình: `~/.agenteye/config.json` + +### Tùy chọn bắt buộc + +| Tùy chọn | Cờ CLI | Biến env | khóa config.json | +|---|---|---|---| +| URL backend | `--url ` | `AGENTEYE_URL` | `"url"` | +| Khóa API | `--key ` | `AGENTEYE_KEY` | `"key"` | + +### Tùy chọn tùy chọn (với mặc định) + +| Tùy chọn | Cờ CLI | Biến env | khóa config.json | Mặc định | +|---|---|---|---|---| +| Tối đa các lần tải lên đồng thời | `--max-concurrent-uploads ` | `AGENTEYE_MAX_CONCURRENT_UPLOADS` | `"max_concurrent_uploads"` | `64` | +| Khoảng thời gian quét (s) | `--sweep-interval ` | `AGENTEYE_SWEEP_INTERVAL` | `"sweep_interval_secs"` | `60` | +| Tuổi file tối thiểu của quét (s) | `--sweep-min-age ` | `AGENTEYE_SWEEP_MIN_AGE` | `"sweep_min_age_secs"` | `120` | +| Tối đa file trên mỗi lần quét | `--sweep-max-files ` | `AGENTEYE_SWEEP_MAX_FILES` | `"sweep_max_files"` | `64` | +| Tối đa lần thử tải lên | `--max-retries ` | `AGENTEYE_MAX_RETRIES` | `"max_retries"` | `5` | +| Độ trễ cơ sở thử lại (ms) | `--retry-base-delay ` | `AGENTEYE_RETRY_BASE_DELAY` | `"retry_base_delay_ms"` | `1000` | + +### Tùy chọn mTLS (tùy chọn) + +Đối với các triển khai yêu cầu TLS lẫn nhau (mTLS), collector có thể trình bày chứng chỉ máy khách trong bắt tay TLS. Khi các tùy chọn này không được đặt, collector sử dụng HTTPS tiêu chuẩn. + +| Tùy chọn | Cờ CLI | Biến env | khóa config.json | +|---|---|---|---| +| Chứng chỉ máy khách (PEM) | `--tls-cert ` | `AGENTEYE_TLS_CERT` | `"tls_cert"` | +| Khóa riêng máy khách (PEM) | `--tls-key ` | `AGENTEYE_TLS_KEY` | `"tls_key"` | +| Chứng chỉ CA tùy chỉnh (PEM) | `--tls-ca ` | `AGENTEYE_TLS_CA` | `"tls_ca"` | + +`--tls-cert` và `--tls-key` phải được đặt cùng nhau. Các file phải được mã hóa PEM. + +`--tls-ca` là độc lập và chỉ cần khi máy chủ AgentEye trình bày chứng chỉ TLS không được cấp bởi CA được tin cậy công khai (ví dụ: tự ký bởi một trình phát hành `cert-manager` trong cụm khi bạn không có tên miền DNS thực). Collector thêm CA được cung cấp làm một liên kết tin tưởng bổ sung; các gốc công khai tiêu chuẩn vẫn được tin tưởng, vì vậy các triển khai hiện có không bị ảnh hưởng. File có thể chứa một chứng chỉ PEM đơn lẻ hoặc một chuỗi đầy đủ (nhiều khối PEM được nối). + +**Chạy collector như một sidecar trong pod ứng dụng của bạn?** Xem [enterprise-docs/single-pod-deployment.md](/vi/agenteye/single-pod-deployment) để biết mẫu EKS end-to-end: gói mTLS được cung cấp thông qua AWS Secrets Manager + Secrets Store CSI Driver + IRSA, với xoay vòng tự động. + +Khi chạy trong Kubernetes với mẫu bàn giao Secret, gắn kết Secret chứng chỉ dưới dạng một volume và trỏ các đường dẫn này đến các file được gắn kết: + +```yaml +# Ví dụ: collector Deployment snippet +volumes: + - name: mtls-certs + secret: + secretName: agenteye-collector-mtls +containers: + - name: collector + env: + - name: AGENTEYE_TLS_CERT + value: /etc/agenteye/tls/tls.crt + - name: AGENTEYE_TLS_KEY + value: /etc/agenteye/tls/tls.key + # Chỉ khi chứng chỉ máy chủ không được tin cậy công khai (ví dụ: CA tự ký trong cụm). + # Secret tương tự thường mang ca.crt cùng với tls.crt/tls.key. + - name: AGENTEYE_TLS_CA + value: /etc/agenteye/tls/ca.crt + volumeMounts: + - name: mtls-certs + mountPath: /etc/agenteye/tls + readOnly: true +``` + +### Ví dụ `~/.agenteye/config.json` + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "max_concurrent_uploads": 16, + "sweep_interval_secs": 30 +} +``` + +Với mTLS: + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "tls_cert": "/etc/agenteye/tls/tls.crt", + "tls_key": "/etc/agenteye/tls/tls.key" +} +``` + +Với mTLS cộng với CA tùy chỉnh (máy chủ AgentEye tự ký): + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "tls_cert": "/etc/agenteye/tls/tls.crt", + "tls_key": "/etc/agenteye/tls/tls.key", + "tls_ca": "/etc/agenteye/tls/ca.crt" +} +``` + +Nếu `AGENTEYE_HOME` được đặt, thư mục đó được sử dụng thay vì `~/.agenteye`. + +--- + +## Thiết lập lần đầu tiên + +Sau khi cài đặt, hãy cấu hình collector với URL máy chủ và khóa API của bạn: + +```bash +mkdir -p ~/.agenteye +cat > ~/.agenteye/config.json <<'EOF' +{ + "url": "https://ingest.example.com/events", + "key": "YOUR_COLLECTOR_KEY" +} +EOF +``` + +> Sử dụng `https` cho bất kỳ triển khai nào vượt qua một mạng không đáng tin cậy để các sự kiện không được gửi dưới dạng văn bản thuần. Dạng `http://your-server-host:8080/events` thuần túy chỉ thích hợp để kiểm tra cục bộ hoàn toàn chống lại máy chủ trên cùng một máy chủ. + +**Kiểm tra kết nối** (xả lần đầu tiên, thoát sau khi hết các sự kiện chờ): + +```bash +agenteye-collector flush +``` + +`flush` báo cáo tiến độ của nó cho stdout. Khi spool trống, nó in `No pending files.` và thoát `0`. Ngược lại, nó in một dòng cho mỗi file (`[UPLOADED] ` hoặc `[FAILED] ()`), theo sau bởi tóm tắt `Done: / uploaded, failed.`. Điều này làm cho `flush` là một kiểm tra tiện lợi một lần để URL, khóa và cài đặt TLS của bạn đúng trước khi bạn bắt đầu daemon. + +--- + +## Chạy như một Daemon + +### Trực tiếp + +```bash +agenteye-collector start +``` + +### Container / Docker + +Khi collector và ứng dụng của bạn chia sẻ một container, hãy chạy chúng dưới một giám sát quy trình. Tùy chọn đơn giản nhất là `supervisord`; nó được cung cấp trong mỗi bản phân phối chính, khởi động lại các quy trình bị sự cố, chuyển tiếp các tín hiệu và chờ tắt một cách duyên dáng. + +**`Dockerfile`:** + +```Dockerfile +FROM python:3.11-slim + +RUN apt-get update && apt-get install -y --no-install-recommends supervisor \ + && rm -rf /var/lib/apt/lists/* + +# Kéo binary agenteye-collector từ image chính thức. +# Ghim một tag cụ thể (:beta-latest cho beta hiện tại, hoặc tag :v); +# :latest chỉ được xuất bản cho các phát hành ổn định. +COPY --from=ghcr.io/agenteye-enterprise/collector:beta-latest \ + /usr/local/bin/agenteye-collector /usr/local/bin/agenteye-collector + +COPY supervisord.conf /etc/supervisor/conf.d/agenteye.conf +COPY my_agent.py /app/my_agent.py + +CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"] +``` + +**`supervisord.conf`:** + +```ini +[supervisord] +nodaemon=true +user=root + +[program:agenteye-collector] +command=/usr/local/bin/agenteye-collector start +autorestart=true +stopwaitsecs=30 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:app] +command=python /app/my_agent.py +autorestart=unexpected +stopwaitsecs=30 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +``` + +Tại sao các cài đặt này: + +- `autorestart=true` trên agenteye-collector: khởi động lại khi thoát bất kỳ (sự cố, panic, OOM). +- `autorestart=unexpected` trên ứng dụng: khởi động lại chỉ khi thoát không bằng 0, vì vậy một agent một lần thoát 0 không lặp lại. +- `stopwaitsecs=30`: cung cấp phòng cho collector để hết các lần tải lên chờ đợi trên SIGTERM trước khi supervisord leo thang lên SIGKILL. +- `stdout_logfile=/dev/stdout`, `*_maxbytes=0`: luồng đầu ra của cả hai chương trình đến container stdout; không có file nhật ký bên trong container. + +Chuyển `AGENTEYE_URL` / `AGENTEYE_KEY` (và bất kỳ biến env TLS nào) trên `docker run -e` như trước; supervisord kế thừa môi trường. + +> **Các container riêng biệt?** Nếu bạn chạy collector như một container của riêng nó (dịch vụ Docker Compose, sidecar Kubernetes, v.v.), đừng sử dụng supervisord; chính sách khởi động lại của vận hành container đã làm công việc này. Xem [enterprise-docs/single-pod-deployment.md](/vi/agenteye/single-pod-deployment) cho mẫu sidecar EKS. + +**Kubernetes liveness probe** (áp dụng cho dù collector chạy một mình hoặc dưới supervisord): + +```yaml +livenessProbe: + exec: + command: ["agenteye-collector", "health"] + initialDelaySeconds: 10 + periodSeconds: 30 +``` + +Daemon đang chạy ghi một nhịp tim vào `$AGENTEYE_HOME/health.json` mỗi 30 giây. `agenteye-collector health` đọc file đó và thoát `0` (khỏe mạnh) chỉ khi nhịp tim tươi mới và các nhiệm vụ tải lên chạy bình thường; nó thoát `1` (không khỏe) khi nhịp tim cũ hơn 90 giây (ví dụ: daemon đã dừng) hoặc trong khi watcher và sweeper đang khởi động lại sau một lần thoát không mong muốn. Nhịp tim chỉ được viết bởi `start`, vì vậy hãy chạy probe chống lại daemon lâu dài thay vì lệnh `flush` một lần. + +### systemd (Linux, được khuyến nghị cho sản xuất) + +```ini +# /etc/systemd/system/agenteye-collector.service +[Unit] +Description=AgentEye Collector +After=network.target + +[Service] +ExecStart=/usr/local/bin/agenteye-collector start +Restart=on-failure +RestartSec=5 +EnvironmentFile=/etc/agenteye/env + +[Install] +WantedBy=multi-user.target +``` + +Tạo `/etc/agenteye/env`: + +``` +AGENTEYE_URL=https://ingest.example.com/events +AGENTEYE_KEY=YOUR_COLLECTOR_KEY +``` + +```bash +sudo systemctl daemon-reload +sudo systemctl enable --now agenteye-collector +sudo systemctl status agenteye-collector +``` + +### launchd (macOS) + +```xml + + + + + + Label + ai.befailproof.agenteye-collector + ProgramArguments + + /usr/local/bin/agenteye-collector + start + + EnvironmentVariables + + AGENTEYE_URL + https://ingest.example.com/events + AGENTEYE_KEY + YOUR_COLLECTOR_KEY + + RunAtLoad + + KeepAlive + + + +``` + +```bash +launchctl load ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +``` + +--- + +## Nâng cấp Collector + +Collector không tự cập nhật. Để nâng cấp: + +- **Binary:** tải xuống artifact `agenteye-collector--` mới từ phát hành `collector/v` mới nhất (xem [Tùy chọn A](#option-a-binary-recommended)), thay thế `/usr/local/bin/agenteye-collector`, rồi khởi động lại dịch vụ (`sudo systemctl restart agenteye-collector`, `launchctl load` lại, hoặc khởi động lại supervisor của bạn). +- **Docker:** `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (hoặc một tag `:v` được ghim; `:latest` chỉ tồn tại cho các phát hành ổn định) và tạo lại container. + +`AGENTEYE_TOKEN` được yêu cầu để tải xuống các binary/image mới từ repo phát hành riêng, nhưng **không** được cần bởi daemon đang chạy. + +--- + +## Các lệnh phụ + +| Lệnh | Mô tả | +|---|---| +| `agenteye-collector start` | Bắt đầu daemon lâu dài. Khi khởi động, nó xả bất kỳ sự kiện nào còn lại từ lần chạy trước, sau đó theo dõi các file mới và tải chúng lên. Watcher và sweeper tự động khởi động lại khi thoát không mong muốn, và một nhịp tim được viết vào `health.json` mỗi 30 giây. | +| `agenteye-collector flush` | Một lần: tải lên tất cả các file chờ đợi và thoát. In `No pending files.` khi spool trống, ngược lại một nhật ký `[UPLOADED]`/`[FAILED]` cho mỗi file và một tóm tắt `Done: / uploaded, failed.`. | +| `agenteye-collector health` | Đọc nhịp tim `health.json` của daemon. Thoát `0` khi tươi mới và khỏe mạnh; thoát `1` khi nhịp tim cũ (cũ hơn 90 giây) hoặc các nhiệm vụ đang khởi động lại. | + +--- + +## Bố cục thư mục + +``` +~/.agenteye/ +├── config.json <- file cấu hình tùy chọn +├── events/ <- file .jsonl được viết bởi SDK, được nhặt lên bởi collector +└── failed/ <- file đã thất bại tất cả các lần thử tải lên +``` + +Các file trong `failed/` không được tự động thử lại. Để tái xếp hàng chúng theo cách thủ công, hãy di chuyển chúng trở lại `events/` và chạy `agenteye-collector flush`. \ No newline at end of file diff --git a/docs/vi/agenteye/collector-migration.mdx b/docs/vi/agenteye/collector-migration.mdx new file mode 100644 index 00000000..7e6c78d2 --- /dev/null +++ b/docs/vi/agenteye/collector-migration.mdx @@ -0,0 +1,169 @@ +--- +title: "Chuyển sang `agenteye-collector`" +description: "Tài liệu chuyển sang `agenteye-collector` của AgentEye." +--- + + +Quá trình chuyển đổi không phá hủy dữ liệu: không có thời gian chết và không mất dữ liệu, đồng thời giải phóng tên ngắn `agenteye` cho [AgentEye CLI](/vi/agenteye/cli) để daemon collector và CLI có thể cùng tồn tại trên cùng một máy. + +Tệp nhị phân collector đã được **đổi tên từ `agenteye` thành `agenteye-collector`**. Tên ngắn `agenteye` hiện thuộc về AgentEye CLI, một công cụ riêng biệt để truy vấn phiên, sự kiện và đánh giá từ terminal của bạn. + +Hướng dẫn này sẽ hướng dẫn bạn qua quá trình chuyển đổi một bản cài đặt collector hiện có. + +--- + +## Những gì đã thay đổi + +| | Trước | Sau | +|---|---|---| +| Lệnh / tệp nhị phân | `agenteye` | `agenteye-collector` | +| Đường dẫn cài đặt mặc định | `/usr/local/bin/agenteye` | `/usr/local/bin/agenteye-collector` | +| Lệnh con | `start`, `flush`, `health`, `update` | `start`, `flush`, `health` | +| Tự cập nhật (`agenteye update`) | tích hợp sẵn | **đã xóa**: tải xuống tệp nhị phân mới hoặc kéo image mới | +| Script cài đặt (`install.sh`) | được cung cấp | **đã xóa**: tải xuống tệp nhị phân trực tiếp (xem [Collector Installation](/vi/agenteye/collector-installation)) | +| `AGENTEYE_TOKEN` | cần thiết để tải xuống **và** cho các kiểm tra cập nhật nền | chỉ cần thiết để **tải xuống** tệp nhị phân/image | + +Cấu hình không thay đổi: `~/.agenteye/config.json` tương tự, các biến môi trường `AGENTEYE_URL` / `AGENTEYE_KEY` / `AGENTEYE_HOME` / TLS tương tự, và `~/.agenteye/events/` spool tương tự. **Không cần chỉnh sửa cấu hình.** + +> Nếu bạn chạy tệp nhị phân được đổi tên dưới tên cũ `agenteye`, nó vẫn hoạt động nhưng in cảnh báo không dùng nữa một dòng ra stderr để nhắc bạn chuyển sang `agenteye-collector`. + +--- + +## Trước khi bắt đầu + +- **Bản cài đặt `agenteye` hiện có của bạn tiếp tục chạy**; không có gì bị hỏng khi bạn nâng cấp. Chuyển đổi một cách cố ý, sau đó xóa tệp nhị phân cũ cuối cùng. +- Làm theo thứ tự này để tránh thời gian chết: + 1. Cài đặt tệp nhị phân `agenteye-collector` mới (hoặc kéo image mới). + 2. Cập nhật định nghĩa dịch vụ / kiểm tra sức khỏe / script của bạn để gọi `agenteye-collector`. + 3. Tải lại và khởi động lại dịch vụ; xác nhận nó hoạt động bình thường. + 4. **Chỉ sau đó** xóa tệp nhị phân `/usr/local/bin/agenteye` cũ. + +--- + +## 1. Cài đặt tệp nhị phân mới + +Tải xuống tệu phẩm cho nền tảng của bạn (`agenteye-collector-linux-x86_64`, `agenteye-collector-darwin-arm64`, v.v.; xem [Collector Installation → Option A](/vi/agenteye/collector-installation#option-a-binary-recommended) để xem danh sách đầy đủ) từ bản phát hành `collector/v` mới nhất và đặt nó tại `/usr/local/bin/agenteye-collector`. Người dùng Docker: `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (hoặc thẻ `:v` được ghim, được ưa thích; `:latest` chỉ tồn tại cho các bản phát hành ổn định). + +Xác minh: + +```bash +agenteye-collector --version +``` + +--- + +## 2. Cập nhật bản triển khai của bạn + +### systemd (Linux) + +Chỉnh sửa `/etc/systemd/system/agenteye-collector.service` sao cho `ExecStart` trỏ đến tệp nhị phân mới: + +```ini +[Service] +ExecStart=/usr/local/bin/agenteye-collector start +``` + +Sau đó tải lại và khởi động lại: + +```bash +sudo systemctl daemon-reload +sudo systemctl restart agenteye-collector +sudo systemctl status agenteye-collector +``` + +### launchd (macOS) + +> **Thay đổi tên thương hiệu:** Nếu plist hiện có của bạn nằm ở đường dẫn cũ +> `~/Library/LaunchAgents/host.exosphere.agenteye-collector.plist`, hãy đổi tên +> tệp thành `ai.befailproof.agenteye-collector.plist` và cũng thay đổi +> giá trị `Label` bên trong tệp thành định danh mới trước khi +> tải lại. + +Trong `~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist`, thay đổi mục đầu tiên `ProgramArguments` từ `/usr/local/bin/agenteye` thành `/usr/local/bin/agenteye-collector`, sau đó tải lại: + +```bash +launchctl unload ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +launchctl load ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +``` + +### supervisord + +Trong khối chương trình `supervisord` của bạn, đặt `command` thành tệp nhị phân mới: + +```ini +[program:agenteye-collector] +command=/usr/local/bin/agenteye-collector start +``` + +Sau đó `supervisorctl reread && supervisorctl update`. + +### Docker / Kubernetes + +Kéo image mới (`ghcr.io/agenteye-enterprise/collector:beta-latest` hoặc một thẻ `:v` được ghim, được ưa thích; `:latest` chỉ tồn tại cho các bản phát hành ổn định). Điểm vào image đã là `agenteye-collector`, vì vậy lệnh `docker run` tương tự với lệnh con `start` tiếp tục hoạt động mà không thay đổi. + +**Quan trọng: cập nhật các kiểm tra sức khỏe.** Nếu bạn sử dụng kiểm tra sức khỏe liveness/readiness của Kubernetes (hoặc bất kỳ `docker exec` nào) chạy tệp nhị phân theo tên, hãy thay đổi lệnh thành `agenteye-collector`: + +```yaml +livenessProbe: + exec: + command: ["agenteye-collector", "health"] +``` + +Image mới **không** cung cấp bí danh `agenteye`, vì vậy một kiểm tra vẫn gọi `agenteye` sẽ thất bại. Cập nhật kiểm tra trong cùng một bản triển khai như image mới. + +### Cron / script thủ công + +Thay thế bất kỳ lệnh gọi `agenteye start|flush|health` nào bằng lệnh `agenteye-collector start|flush|health` tương ứng. **Xóa bất kỳ công việc cron `agenteye update` nào**; lệnh con đó không còn tồn tại (xem [Upgrades from now on](#upgrades-from-now-on)). + +--- + +## 3. Xóa tệp nhị phân cũ (cuối cùng) + +Khi dịch vụ chạy trên `agenteye-collector` và báo cáo hoạt động bình thường: + +```bash +sudo rm /usr/local/bin/agenteye +``` + +Điều này đặc biệt quan trọng nếu bạn cũng sử dụng AgentEye CLI, nó cài đặt lệnh `agenteye` của riêng nó; để lại tệp nhị phân collector cũ tại `/usr/local/bin/agenteye` sẽ làm cho tên `agenteye` không rõ ràng trên `PATH` của bạn. + +--- + +## Nâng cấp từ bây giờ + +Collector không còn tự cập nhật. Để nâng cấp: + +- **Tệp nhị phân:** tải xuống tệu phẩm mới cho nền tảng của bạn (ví dụ `agenteye-collector-linux-x86_64`; xem [Collector Installation → Option A](/vi/agenteye/collector-installation#option-a-binary-recommended) để xem danh sách đầy đủ), thay thế `/usr/local/bin/agenteye-collector` và khởi động lại dịch vụ. +- **Docker:** `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest` (hoặc một thẻ `:v` được ghim, được ưa thích; `:latest` chỉ tồn tại cho các bản phát hành ổn định) và tạo lại container. + +`AGENTEYE_TOKEN` vẫn được yêu cầu để tải xuống từ kho lưu trữ bản phát hành riêng, nhưng daemon đang chạy không còn cần nó. + +--- + +## Xác minh + +```bash +agenteye-collector --version # tệp nhị phân mới nằm trên PATH +agenteye-collector health # exit 0 = hoạt động bình thường +agenteye-collector flush # chuyển tiếp bất kỳ sự kiện nào trong hàng đợi và thoát sạch sẽ +``` + +Sau đó xác nhận các sự kiện mới xuất hiện trong bảng điều khiển của bạn. + +--- + +## Quay lại + +Quá trình chuyển đổi không phá hủy dữ liệu. Nếu bạn cần quay lại, hãy trỏ định nghĩa dịch vụ của bạn trở lại tệp nhị phân `/usr/local/bin/agenteye` cũ (miễn là bạn chưa xóa nó) và khởi động lại. Spool sự kiện và cấu hình được chia sẻ và không bị ảnh hưởng. + +--- + +## Khắc phục sự cố + +| Triệu chứng | Nguyên nhân | Sửa | +|---|---|---| +| `warning: the collector binary is now agenteye-collector …` trên mỗi lần chạy | Bạn đang gọi tệp nhị phân dưới tên cũ `agenteye` | Gọi `agenteye-collector` thay vào đó; cập nhật tệp dịch vụ và script. | +| systemd thất bại: `.../agenteye: No such file or directory` | Bạn đã xóa tệp nhị phân cũ trước khi cập nhật `ExecStart` | Đặt `ExecStart=/usr/local/bin/agenteye-collector start`, sau đó `sudo systemctl daemon-reload`. | +| Pod Kubernetes crash-loop sau khi nâng cấp image | Kiểm tra sức khỏe liveness vẫn chạy `agenteye` | Thay đổi lệnh kiểm tra thành `["agenteye-collector", "health"]`. | +| `agenteye: command not found`, nhưng `agenteye-collector` hoạt động | Script/bí danh vẫn tham chiếu tên cũ | Cập nhật chúng thành `agenteye-collector`. | +| Chạy `agenteye` khởi động CLI, không phải collector | Bạn đã cài đặt AgentEye CLI; nó sở hữu `agenteye` | Sử dụng `agenteye-collector` cho daemon và xóa bất kỳ tệu phẩm collector cũ nào còn lại tại `/usr/local/bin/agenteye`. | \ No newline at end of file diff --git a/docs/vi/agenteye/deployment.mdx b/docs/vi/agenteye/deployment.mdx new file mode 100644 index 00000000..aee19a3f --- /dev/null +++ b/docs/vi/agenteye/deployment.mdx @@ -0,0 +1,396 @@ +--- +title: "Triển khai" +description: "Tài liệu triển khai AgentEye." +--- + + +Hướng dẫn này bao gồm triển khai server AgentEye và dashboard trong môi trường production. + +--- + +## Tổng quan kiến trúc + +``` + [ AI agent machines ] [ Your infrastructure ] + + Python SDK + | writes JSONL +----------------------+ + v +--->| PostgreSQL 15+ | + agenteye-collector --HTTP--+ | | (relational store) | + | | +----------------------+ + v | + +--------+ | +----------------------+ + | Server |<------+--->| ClickHouse 24+ | + +--------+ | | (events / analytics) | + ^ | +----------------------+ + API | | + | | +----------------------+ + +-----------+ +- - >| Redis 7+ (optional) | + | Dashboard | +----------------------+ + +-----------+ +``` + +- **Server**: Dịch vụ HTTP viết bằng Rust; nhận các batch sự kiện, ghi chúng vào ClickHouse, và duy trì trạng thái quan hệ trong PostgreSQL. +- **Dashboard**: Ứng dụng web Next.js; đọc và ghi độc quyền thông qua API của server. +- **agenteye-collector**: được triển khai trên các máy agent, không phải trên host server. +- **Postgres 15+**: YÊU CẦU. (Được nâng lên từ 14 trong bản phát hành multi-tenant; schema thành viên tổ chức sử dụng `ON DELETE SET NULL` foreign key danh sách cột, yêu cầu Postgres 15+. Nâng cấp Postgres trước khi triển khai phiên bản này.) Lưu trữ trạng thái OLTP: `api_keys`, `users`, `sessions`, `evaluation_jobs` (hàng đợi), `dashboards`, `saved_queries`, `otp_codes`, cộng với các bảng multi-tenant `orgs`, `org_memberships`, `org_settings`. +- **ClickHouse 24+**: YÊU CẦU. Kho lưu trữ phân tích cho mọi sự kiện được nhập. Engine: `ReplacingMergeTree`, được phân vùng theo tháng, sắp xếp theo `(session_id, ts, dedup_key)`. Server kết nối qua `CLICKHOUSE_URL`; bản triển khai đi kèm `deploy/base/clickhouse/` cung cấp cấu hình nút đơn được điều chỉnh hiệu suất. **Yêu cầu multi-tenant:** cấu hình đi kèm cho phép quản lý quyền truy cập SQL + `users_without_row_policies_can_read_rows=false` để server có thể tạo một người dùng ClickHouse chỉ đọc + chính sách hàng cho mỗi tổ chức (ranh giới cách ly được engine thực thi cho trình soạn thảo SQL và agent AI). Nếu bạn cung cấp cấu hình ClickHouse của riêng mình, hãy chuyển những cài đặt này (xem `deploy/base/clickhouse/configmap.yaml`). +- **Redis 7+**: *tùy chọn* bộ nhớ cache được chia sẻ + backend giới hạn tốc độ. Server và dashboard đều kết nối qua `REDIS_URL`. Nếu không có, cả hai đều suy giảm một cách duyên dáng thành các đường dẫn chỉ Postgres. Xem **Redis (cache tùy chọn)** dưới đây. + +--- + +## Server + +### Tải image + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +docker pull ghcr.io/agenteye-enterprise/server:beta-latest +``` + +> Bản dựng hiện tại được phát hành dưới `beta-latest`; `latest` chỉ được gán cho các bản phát hành ổn định. Để production, hãy chọn một tag phiên bản cụ thể `:v`; xem [Available Image Tags](#available-image-tags). + +### Biến môi trường + +| Variable | Required | Default | Description | +|---|---|---|---| +| `DATABASE_URL` | Yes | none | Postgres DSN. Chuỗi kết nối tiêu chuẩn libpq với scheme `postgres://`. Hỗ trợ `?sslmode=require` và các tham số libpq khác. Mật khẩu không được chứa `/`, `+`, hoặc `=`; sử dụng `openssl rand -hex` để tạo mật khẩu an toàn URL. | +| `ADMIN_KEY` | No | none | Khóa API admin bootstrap. Được upsert với tất cả các quyền trên mỗi lần khởi động. Xoay bằng cách thay đổi giá trị và khởi động lại. | +| `LISTEN_ADDR` | No | `0.0.0.0:8080` | Địa chỉ TCP để bind | +| `MAX_BODY_BYTES` | No | `134217728` (128 MB) | Kích thước phần thân yêu cầu tối đa | +| `ADMIN_EMAIL` | No | none | Email người dùng admin bootstrap. Được upsert với tất cả các quyền trên mỗi lần khởi động và đánh dấu bảo vệ: không thể bị vô hiệu hóa hoặc có quyền sửa đổi qua dashboard/API. Để xoay admin bootstrap, hãy thay đổi `ADMIN_EMAIL` và khởi động lại; email mới được upsert dưới dạng bảo vệ, và email trước đó giữ sự bảo vệ của nó cho đến khi được xóa thủ công trong cơ sở dữ liệu. | +| `ALLOWED_EMAILS` | No | none (all blocked) | Danh sách email được phép tách bằng dấu phẩy để tạo người dùng và đăng nhập. Hỗ trợ các địa chỉ chính xác (`user@example.com`) và ký tự đại diện miền (`*@example.com`). Nếu không được đặt, không có người dùng nào có thể được tạo hoặc đăng nhập. **Chỉ seed khởi động đầu tiên**: seed danh sách cho phép tổ chức mặc định trên khởi động đầu tiên; sau đó trang [`//settings`](#operational-settings) của từng tổ chức là nguồn quy chuẩn và thay đổi biến env này không có tác dụng. | +| `SMTP_HOST` | No | none | Tên máy chủ SMTP để gửi email OTP. Nếu không được đặt, mã OTP được ghi nhật ký vào stdout thay thế. | +| `SMTP_PORT` | No | `587` | Cổng máy chủ SMTP | +| `SMTP_USERNAME` | No | none | Tên người dùng xác thực SMTP | +| `SMTP_PASSWORD` | No | none | Mật khẩu xác thực SMTP | +| `SMTP_FROM` | No | none | Địa chỉ email người gửi cho email OTP | +| `SMTP_TLS` | No | STARTTLS | STARTTLS được sử dụng trừ khi bạn tắt nó một cách rõ ràng: `false` hoặc `0` gửi plaintext (không TLS); bất kỳ giá trị nào khác — bao gồm không được đặt — cho phép STARTTLS. | +| `DASHBOARD_URL` | No | built-in default | Nguồn gốc dashboard được sử dụng để xây dựng cả liên kết phép thuật OTP-email và các liên kết phép thuật sự cố trong thông báo cảnh báo. Nếu không được đặt, nó sẽ quay về mặc định tích hợp (và, chỉ dành cho OTP, quay về nguyên gốc request phát sinh từ dashboard trước tiên). Đặt điều này cho các thiết lập miền phân chia để cả email và liên kết Slack/sự cố chỉ tới dashboard của bạn. Xem **Email magic-link URL** dưới đây; hầu hết các operator không cần đặt điều này. | +| `SESSION_TTL_SECS` | No | `86400` (24 h) | Thời lượng phiên dashboard tính bằng giây. **Chỉ seed khởi động đầu tiên**: chỉnh sửa cho mỗi tổ chức qua [`//settings`](#operational-settings) sau khi triển khai đầu tiên. | +| `OTP_TTL_SECS` | No | `600` (10 min) | Thời gian hiệu lực mã OTP tính bằng giây. **Chỉ seed khởi động đầu tiên**: chỉnh sửa cho mỗi tổ chức qua [`//settings`](#operational-settings) sau khi triển khai đầu tiên. | +| `REDIS_URL` | No | none | Backend bộ nhớ cache + giới hạn tốc độ được chia sẻ tùy chọn, ví dụ `redis://redis:6379/0`. Khi được đặt, server cache các tìm kiếm khóa API được xác thực, `/models` aggregate của dashboard, danh sách phiên, và facet danh sách env; nó cũng chuyển giới hạn tốc độ OTP-request từ Postgres COUNT sang Redis INCR. Nếu không được đặt hoặc không thể truy cập, server chạy mà không cache (giới hạn OTP quay về Postgres, mọi lệnh gọi cache khác đi xuống nguồn quy chuẩn). Xem **Redis (cache tùy chọn)** dưới đây. | +| `CLICKHOUSE_URL` | **Yes** | none | URL cơ sở của phiên bản ClickHouse, ví dụ `http://clickhouse:8123`. Server áp dụng schema sự kiện của nó cho cơ sở dữ liệu này trên mỗi lần khởi động và từ chối khởi động nếu không thể tiếp cận ClickHouse. Xem **ClickHouse (kho lưu trữ phân tích bắt buộc)** dưới đây. | +| `CLICKHOUSE_DATABASE` | No | `agenteye` | Tên cơ sở dữ liệu (schema) ClickHouse. Server tạo nó trên khởi động nếu nó không tồn tại. | +| `ORG_CH_SECRET` | No (single-tenant) / **Yes (multi-org)** | dev default | Khóa HMAC từ đó mật khẩu ClickHouse của mỗi tổ chức được lấy. Trình soạn thảo SQL và `run_query` của agent AI thực thi như người dùng ClickHouse chỉ đọc của tổ chức, người dùng có chính sách hàng thực thi cách ly tenant trong engine. Các triển khai single-tenant khởi động tốt trên mặc định dev tích hợp; **trước khi cung cấp tổ chức thứ hai, bạn PHẢI đặt giá trị mạnh, ổn định**, vì CLI `agenteye-orgctl org create` từ chối chạy trên mặc định dev tích hợp. Xoay nó gây mồ côi mọi người dùng ClickHouse của tổ chức cho đến khi khởi động tiếp theo cung cấp lại chúng (hòa giải thời gian khởi động tự động chữa bệnh này). Giữ nó bí mật và không thay đổi trên các bản sao. Cung cấp tổ chức chính nó là chỉ operator; xem **Organizations (multi-tenancy)** dưới đây. | +| `DEFAULT_ORG_NAME` | No | `Default` | Tên hiển thị được seed cho tổ chức mặc định tích hợp. **Chỉ seed khởi động đầu tiên**, và chỉ khi tổ chức vẫn mang danh tính chung vừa di chuyển của nó, được áp dụng trên khởi động, sau đó bị bỏ qua. Khi bạn đổi tên tổ chức (`agenteye-orgctl org rename`), tên đổi là quyền lực và biến env này không còn có tác dụng. | +| `DEFAULT_ORG_SLUG` | No | `default` | Slug URL cho tổ chức mặc định tích hợp, đường dẫn dashboard nó sống (`//…`). Cùng ngữ nghĩa khởi động đầu tiên / nguyên bản như `DEFAULT_ORG_NAME`. Phải là 1-40 chữ số nhỏ với dấu gạch ngang bên trong đơn và không phải [từ dành riêng](#organizations-multi-tenancy); một giá trị không hợp lệ bị bỏ qua (tổ chức giữ `default`). Cho phép cài đặt single-tenant trình bày dưới dạng ví dụ `/acme` thay vì `/default` mà không có bất kỳ bước CLI sau khi triển khai nào. | +| `RUST_LOG` | No | `info` | Mức độ chi tiết nhật ký (`debug`, `warn`, `error`, `agenteye_server=trace`) | +| `EVALUATOR_ENDPOINT` | No | none | URL cơ sở của dịch vụ evaluator của bạn (ví dụ `http://evaluator:9000`). Khi không được đặt, toàn bộ pipeline đánh giá là no-op; không có hàng hàng đợi được ghi, không có worker chạy. Xem [Evaluation Suite](/vi/agenteye/evaluation-suite). | +| `EVALUATOR_TOKEN` | No | none | Được gửi dưới dạng `Authorization: Bearer ` tới evaluator. **Phải bằng cùng giá trị mà dịch vụ evaluator được cấu hình.** Tùy chọn chỉ khi evaluator của bạn được cấu hình mà không có token. | +| `EVALUATOR_WORKERS` | No | `2` | Đồng thời: số tác vụ worker trên mỗi phiên bản server gửi đi các đánh giá. An toàn để chạy trên nhiều server được mở rộng theo chiều ngang. | +| `EVALUATOR_CLAIM_BATCH` | No | `4` | Số đánh giá tối đa một worker yêu cầu trên mỗi tick. Batch được gửi **đồng thời**, vì vậy đồng thời tổng cộng trên endpoint evaluator của bạn là `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH`. | +| `EVALUATOR_POLL_IDLE_SECS` | No | `2` | Một worker ngủ bao lâu giữa các nỗ lực gửi đi khi không có gì đúng hạn. | +| `EVALUATOR_POLLING_INTERVAL_SECS` | No | `10` | Fallback cuối cùng (giây) cho `GET /evaluate/{id}` polls khi evaluator không trả về `next_poll_secs` trên mỗi phản hồi và không quảng cáo `default_poll_interval_secs` từ `GET /config`. | +| `EVALUATOR_REQUEST_TIMEOUT_MS` | No | `30000` | Timeout per-HTTP-request chống lại evaluator (milliseconds). | +| `EVALUATOR_MAX_ATTEMPTS` | No | `5` | Sau nhiều nỗ lực thất bại này, một đánh giá được ghi nhận là terminal `error` (hoặc `timeout` nếu các lỗi là timeout yêu cầu). | +| `EVALUATOR_CONFIG_REFRESH_SECS` | No | `300` (5 min) | Thường xuyên server tái tìm nạp `GET /config` từ evaluator. | +| `EVALUATOR_MAX_POLL_DURATION_SECS` | No | `3600` (1 h) | Thời gian tường tối đa một phiên có thể ở lại trong hàng đợi polling trước khi AgentEye chấm dứt nó dưới dạng `timeout`. Đảm bảo chống lại một evaluator trả về `pending` mãi mãi. | +| `ALERT_WORKERS` | No | `1` | Đồng thời: số tác vụ worker trên mỗi phiên bản server đánh giá các quy tắc cảnh báo. Xem [Alerts](/vi/agenteye/alerts). | +| `ALERT_CLAIM_BATCH` | No | `16` | Số cảnh báo tối đa một worker yêu cầu trên mỗi tick. | +| `ALERT_POLL_IDLE_SECS` | No | `5` | Một worker cảnh báo ngủ bao lâu khi hàng đợi trống. | +| `ALERT_REQUEST_TIMEOUT_MS` | No | `15000` | Timeout đánh giá kích hoạt per-trigger (ClickHouse queries + outbound channel HTTP). | +| `ALERT_MAX_ATTEMPTS` | No | `5` | Lỗi tạm thời liên tiếp trước khi cảnh báo lên lịch ở tần suất bình thường thay vì backoff theo cấp số nhân. | +| `AUDIT_WORKERS` | No | `1` | Đồng thời: số tác vụ worker trên mỗi phiên bản server thực thi kiểm toán. Xem [Audits](/vi/agenteye/audits). | +| `AUDIT_CLAIM_BATCH` | No | `1` | Số kiểm toán đúng hạn tối đa một worker yêu cầu trên mỗi tick. Một cuộc điều tra agentic là một vòng lặp dài, vì vậy mặc định là 1. | +| `AUDIT_POLL_IDLE_SECS` | No | `30` | Một worker kiểm toán ngủ bao lâu khi không có kiểm toán nào đúng hạn. | +| `AUDIT_REQUEST_TIMEOUT_MS` | No | `30000` | Timeout per-policy-query chống lại ClickHouse (milliseconds). | +| `AUDIT_LLM_TIMEOUT_MS` | No | `1440000` | Timeout cho cuộc gọi cuộc điều tra agentic tới dịch vụ trợ lý AI. Một vòng agent đầy đủ chạy trong nhiều phút; giữ điều này TRÊN `AGENTEYE_AUDIT_TIMEOUT_MS` của agent để agent trả về các phát hiện một phần của nó trước khi server từ bỏ. | +| `AUDIT_MAX_ATTEMPTS` | No | `5` | Lỗi tạm thời liên tiếp trước khi kiểm toán lên lịch ở tần suất bình thường thay vì backoff theo cấp số nhân. | +| `AGENTEYE_AGENT_URL` / `AGENTEYE_AGENT_TOKEN` | No | — | Cuộc điều tra agentic của kiểm toán gọi dịch vụ trợ lý AI `agent`, **sử dụng lại kết nối tương tự như trợ lý** — vì vậy hãy đặt hai cái này trên **server** cũng (các bản rõ ràng/compose do làm việc). Cả hai đặt ⇒ kiểm toán chạy cuộc điều tra AI; hoặc có thể không được đặt ⇒ kiểm toán chạy **policy-only** (lôi SQL xác định chính sách vẫn chạy), bất kể cờ `llm_enabled` của mỗi kiểm toán. Agent cũng phải có LLM được cấu hình — xem [assistant.md](/vi/agenteye/assistant). | + +**Dịch vụ trợ lý AI — cài đặt kiểm toán + sandbox.** Cuộc điều tra agentic và hộp cát Python trong pod của nó được điều chỉnh trên **dịch vụ agent** (không phải server), tất cả trên `AGENTEYE_AUDIT_*` tiền tố và tất cả tùy chọn: + +| Variable | Default | Meaning | +|---|---|---| +| `AGENTEYE_AUDIT_MAX_STEPS` | `200` | Số bước agent tối đa cho mỗi cuộc điều tra. | +| `AGENTEYE_AUDIT_TIMEOUT_MS` | `1200000` | Tường tối đa cho một cuộc điều tra (20 phút). Phải ở **dưới** `AUDIT_LLM_TIMEOUT_MS` của server. | +| `AGENTEYE_AUDIT_MAX_CONCURRENCY` | `1` | Các cuộc điều tra đồng thời trên mỗi pod agent (tách biệt khỏi ngân sách của trợ lý trò chuyện). | +| `AGENTEYE_AUDIT_SANDBOX_TIMEOUT_MS` / `_MEM_MB` / `_CPU_SECS` / `_OUTPUT_MAX_BYTES` / `_SCRIPT_MAX_BYTES` | `20000` / `768` / `10` / `64000` / `64000` | Giới hạn per-script cho hộp cát bubblewrap. | + +**Yêu cầu nền tảng Sandbox.** Hộp cát mã kiểm toán chạy Python của mô hình bên trong nhà tù bubblewrap, yêu cầu **không gian người dùng không được phép**. Pod agent phải cho phép các cờ `clone()` — đặt `seccompProfile: Unconfined` (k8s) hoặc `security_opt: [seccomp:unconfined]` (compose) trên agent. Khi hạt nhân nút vô hiệu hóa không gian người dùng không được phép (ví dụ như một số hình ảnh GKE COS), hộp cát **bỏ qua trước và độc lập tự động giảm xuống chỉ SQL** — không lỗi, chỉ là `sandbox_available: false` trên `/health` của agent. + +### Chạy + +Đặt `DATABASE_URL` và `CLICKHOUSE_URL` trong môi trường của bạn (server từ chối khởi động mà không có ClickHouse), sau đó chuyển chúng vào container: + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-server \ + -e DATABASE_URL="$DATABASE_URL" \ + -e CLICKHOUSE_URL="$CLICKHOUSE_URL" \ + -e ADMIN_KEY="$ADMIN_KEY" \ + -p 8080:8080 \ + ghcr.io/agenteye-enterprise/server:beta-latest +``` + +Server chạy các di chuyển cơ sở dữ liệu tự động trên khởi động; không cần bước di chuyển riêng biệt. + +### Kiểm tra sức khỏe + +``` +GET /health # liveness - luôn {"status":"ok"} khi quy trình khởi động xong +GET /ready # readiness - 200 khi Postgres + ClickHouse có thể truy cập được, nếu không 503 +``` + +Không cần xác thực. Sử dụng `/health` cho **liveness** probes và `/ready` cho **readiness** / load-balancer probes. `/ready` kiểm tra các phụ thuộc cứng mà server không thể phục vụ mà không có (Postgres + ClickHouse), vì vậy một server đang chạy nhưng không thể tiếp cận cơ sở dữ liệu của nó bị loại khỏi vòng quay và hiển thị là `NotReady`; Redis được báo cáo nhưng không bao giờ thất bại readiness. Trên các bản kê khai Kubernetes đi kèm, probe readiness đã chỉ tới `/ready` và liveness ở `/health`. Xem [enterprise-docs/health-monitoring.md](/vi/agenteye/health-monitoring) để có hình ảnh đầy đủ, bao gồm cảnh báo sự cố pod hỗ trợ Kubernetes-native để Slack. + +### Email magic-link URL + +Email đăng nhập OTP chứa nút **mở dashboard** một lần nhấn. Nhấp vào nó đưa người dùng tới `/login?token=&email=
`; dashboard trao đổi cặp đó cho một phiên và chuyển hướng tới ứng dụng, không cần nhập lại mã thủ công. Server giải quyết dashboard origin được sử dụng để xây dựng liên kết trong ba tầng: + +1. **`X-AgentEye-Dashboard-Url` header**: được đặt tự động bởi dashboard `/api/auth/otp/request` proxy từ gốc công khai của nó. Trong triển khai cùng gốc (server và dashboard chia sẻ một host đằng sau một ingress chuyển tiếp proxy headers), **không cần cấu hình**. +2. **`DASHBOARD_URL` env var**: đặt điều này nếu dashboard của bạn có thể truy cập trên một gốc khác so với gốc mà endpoint yêu cầu OTP của server nhìn thấy (chia `api.example.com` / `app.example.com`), hoặc nếu ingress của bạn không truyền host công khai vào pod dashboard (vì vậy `request.nextUrl.origin` sẽ giải quyết thành một bind ký tự đại diện như `0.0.0.0:3000`). Ví dụ: `DASHBOARD_URL=https://app.example.com`. +3. **Default**: `https://app.befailproof.ai`, chỉ được sử dụng nếu không có cái nào ở trên. + +Giá trị header được xác thực: chỉ `https://*` và loopback (`http://localhost*`, `http://127.0.0.1*`) origins được chấp nhận, và địa chỉ bind ký tự đại diện (`0.0.0.0`, `[::]`) bị từ chối ngay cả với scheme `https://`. Bất cứ điều gì khác sẽ rơi vào tầng 2. + +Đặt nó trên một cụm đang chạy bằng một lệnh một dòng; không có tệp, không xây dựng lại kustomize: + +```bash +kubectl set env deployment/server -n agenteye \ + DASHBOARD_URL=https://app.example.com +``` + +Điều này kích hoạt một rollout; các pod mới nhận giá trị này trên yêu cầu đầu tiên. Lưu ý rằng ghi đè chỉ sống trên Deployment; một `kustomize build | kubectl apply` tiếp theo chống lại overlay sẽ xóa nó trừ khi bạn thêm cùng env var vào `server-env.yaml` patch của overlay. + +--- + +## Dashboard + +### Tải image + +```bash +docker pull ghcr.io/agenteye-enterprise/dashboard:beta-latest +``` + +### Biến môi trường + +| Variable | Required | Default | Description | +|---|---|---|---| +| `AGENTEYE_SERVER_URL` | Yes | none | URL cơ sở của server, ví dụ `http://localhost:8080` | +| `AGENTEYE_API_KEY` | Yes | none | Khóa API mà dashboard sử dụng để xác thực với server. Cần tất cả các quyền (khóa admin được khuyến cáo). | +| `AE_LOG_LEVEL` | No | `info` | Mức độ chi tiết nhật ký phía máy chủ: `debug`, `info`, `warn`, `error`. Đặt thành `debug` để xem dòng yêu cầu/phản hồi thượng nguồn và theo dõi xác thực phiên khi chẩn đoán vấn đề. | +| `AE_LOG_JSON` | No | auto | `1` bắt buộc JSON-per-line output; `0` bắt buộc human-readable output. Khi không được đặt, JSON được bật tự động nếu `NODE_ENV=production`. JSON được khuyến cáo trong production để logs phân tích sạch với `jq` hoặc một aggregator nhật ký. | +| `AE_ANALYTICS_DISABLED` | No | none | Đặt thành `1`/`true` để vô hiệu hóa telemetry sử dụng sản phẩm ẩn danh của dashboard. Xem [Telemetry & privacy](#telemetry--privacy) dưới đây. | +| `REDIS_URL` | No | none | Backend bộ nhớ cache được chia sẻ tùy chọn, ví dụ `redis://redis:6379/0`. Khi được đặt, dashboard cache `validateSession()` kết quả trên các bản sao và chia sẻ bộ nhớ cache Next.js tìm nạp cho các bản lộ trình proxy aggregate tiên phong / env-list. Giới hạn tốc độ OTP yêu cầu edge-side và xác minh cũng sử dụng Redis khi có (thất bại mở nếu Redis không thể truy cập được; giới hạn phía máy chủ là bảo mật backstop). Xem **Redis (cache tùy chọn)** dưới đây. | +| `AGENTEYE_AGENT_URL` | No | none | URL cơ sở của dịch vụ trợ lý AI `agent` tùy chọn, ví dụ `http://agent:9100`. **Để lại không được đặt để ẩn trợ lý hoàn toàn**: không có bong bóng trợ lý xuất hiện trong dashboard. Xem [enterprise-docs/assistant.md](/vi/agenteye/assistant). | +| `AGENTEYE_AGENT_TOKEN` | No | none | Bí mật được chia sẻ mà dashboard trình bày cho dịch vụ `agent`. Phải khớp với `AGENTEYE_AGENT_TOKEN` được cấu hình trên agent. Xem [enterprise-docs/assistant.md](/vi/agenteye/assistant). | + +### Chạy + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-dashboard \ + -e AGENTEYE_SERVER_URL="http://your-server-host:8080" \ + -e AGENTEYE_API_KEY="$ADMIN_KEY" \ + -p 3000:3000 \ + ghcr.io/agenteye-enterprise/dashboard:beta-latest +``` + +### Telemetry & privacy + +Dashboard gửi **phân tích sử dụng sản phẩm ẩn danh** tới dịch vụ phân tích Exosphere (PostHog): những trang dashboard nào được xem và một số hành động UI như tạo khóa API hoặc tái đánh giá phiên. Tín hiệu sử dụng này thông báo cho những tính năng nào được ưu tiên. + +- **Không có dữ liệu agent, phiên hoặc sự kiện nào bao giờ rời khỏi cơ sở hạ tầng của bạn.** Chỉ sử dụng UI dashboard được báo cáo. URL trang được loại bỏ các định danh trước khi gửi, và các operator được xác định chỉ bằng id nội bộ opaque, không bao giờ bằng email. +- Telemetry **được bật theo mặc định**. Để tắt nó hoàn toàn, hãy đặt `AE_ANALYTICS_DISABLED=1` trên container dashboard và khởi động lại. +- Analytics được gửi tới đường dẫn `/ingest` của dashboard riêng, mà dashboard reverse-proxy tới PostHog (`https://us.i.posthog.com`). Giữ các yêu cầu first-party có nghĩa là trình chặn quảng cáo trình duyệt không thả chúng. **Container dashboard** cần truy cập outbound tới PostHog; nếu bị chặn, telemetry im lặng không làm gì và dashboard không bị ảnh hưởng. + +--- + +## AI Assistant (tùy chọn) + +Một trợ lý AI trong dashboard cho phép nhóm của bạn đặt câu hỏi về dữ liệu agent của họ bằng ngôn ngữ thường (tóm tắt phiên, soạn thảo SQL cho trình soạn thảo `/queries`, và biến các truy vấn lưu thành các tile dashboard) mà không cần rời dashboard. Nó chạy dưới dạng container `agent` nội bộ riêng (trên Claude Agent SDK) mà chỉ dashboard có thể tiếp cận, và ở **bị vô hiệu cho đến khi bạn cấu hình endpoint LLM**. + +Để bật nó, bạn đặt trên dịch vụ `agent`, kết nối LLM (**Portkey** via `PORTKEY_API_KEY` + slug danh mục mô hình `AGENTEYE_AGENT_MODEL=@/`, Anthropic trực tiếp qua `ANTHROPIC_API_KEY`, gateway khác qua `ANTHROPIC_BASE_URL`, hoặc Bedrock/Vertex), khóa dữ liệu **chuyên dụng**, và `AGENTEYE_AGENT_TOKEN` được chia sẻ khớp dashboard. Người dùng dashboard cũng cần quyền `agent:use`. + +Đối với khóa dữ liệu của trợ lý, bạn không tạo bất cứ thứ gì bằng tay: chọn một bí mật ngẫu nhiên, đặt nó là `AGENTEYE_API_KEY` trên `agent` **và** là `AGENT_API_KEY` trên `server`, và server seed nó trên khởi động với một tập quyền cố định. Truy cập dữ liệu của nó là chỉ đọc (`events:read`, `evaluations:read`, `dashboards:read`, `queries:read`), và nó còn giữ phạm vi tác giả được phê duyệt cổng (`dashboards:write`, `queries:write`, `queries:run`) để nó có thể soạn thảo và xác thực các truy vấn lưu và xây dựng các tile dashboard thay mặt người dùng; tất cả SQL vẫn chạy qua vai trò chỉ đọc ClickHouse của tổ chức, vì vậy điều này mở rộng những gì trợ lý có thể tác giả, không phải dữ liệu nào nó có thể truy cập. Các phạm vi được sửa chữa trong mã và không thể mở rộng bằng cấu hình. Khóa đó được bảo vệ; không thể bị vô hiệu hóa hoặc tái tạo qua API, chỉ xoay bằng cách thay đổi giá trị và khởi động lại. Không bao giờ sử dụng lại khóa admin/dashboard cho điều này. + +Thiết lập đầy đủ, tham khảo biến môi trường hoàn chỉnh, tùy chọn telemetry, và mô hình bảo mật nằm trong **[enterprise-docs/assistant.md](/vi/agenteye/assistant)**. + +--- + +## ClickHouse (kho lưu trữ phân tích bắt buộc) + +ClickHouse giữ dashboard của bạn đáp ứng ở khối lượng sự kiện cao và cho phép trình soạn thảo SQL `/queries` tham gia trên các sự kiện, đánh giá, và phiên trong một kho lưu trữ duy nhất. Nó là kho lưu trữ quy chuẩn bắt buộc cho mọi sự kiện được nhập, mọi kết quả đánh giá terminal, và các tổng hợp per-session dẫn xuất. PostgreSQL giữ các bảng trạng thái quan hệ / có thể thay đổi (api_keys, users, otp_codes, evaluation_jobs, dashboards, saved_queries); bề mặt phân tích sống trong ClickHouse để rollups của dashboard và các truy vấn SQL của riêng bạn có thể quét và tham gia nó một cách bản địa, mà không có các vòng lặp cross-database. Server từ chối khởi động mà không có `CLICKHOUSE_URL`. + +### Schema + +Ba đối tượng ClickHouse được tạo trên khởi động server, tất cả idempotent (`CREATE IF NOT EXISTS`): + +- **`agenteye.events`**: `ReplacingMergeTree(ingested_at)`, được phân vùng theo `toYYYYMM(ts)`, được sắp xếp theo `(session_id, ts, dedup_key)`. Các chèn trùng lặp (collector thử lại) sụp đổ thành một hàng duy nhất tại thời gian hợp nhất; server tính toán `dedup_key` SHA-256 xác định cho mỗi sự kiện để thử lại an toàn. +- **`agenteye.evaluations`**: `ReplacingMergeTree(ingested_at)`, được phân vùng theo `toYYYYMM(finished_at)`, được sắp xếp theo `(session_id, finished_at, dedup_key)`. Được viết một lần mỗi kết quả đánh giá terminal bởi pipeline evaluator. Mô hình dedup-key giống như `events`. +- **`agenteye.agent_sessions`**: một **VIEW** trên `agenteye.events`, không phải một bảng vật lý. Mỗi cột được dẫn xuất (`started_at = min(ts)`, `last_event_at = max(ts)`, `ended_at = max(if event_type='agent_end', ts, NULL)`, `event_count = count()`, v.v.). Không có per-event upsert và không có backfill riêng biệt; chế độ xem tự động phản ánh bất cứ cái gì nằm trong `events`. + +Để tương thích ngược với các truy vấn lưu tham khảo `analytics.evaluations` / `analytics.sessions`, server cũng tạo cơ sở dữ liệu ClickHouse `analytics` với các chế độ xem trên các bảng `agenteye.*`; `analytics.events`, `analytics.evaluations`, `analytics.agent_sessions`, `analytics.sessions` tất cả giải quyết chính xác. + +### Configuration + +Bộ docker-compose đi kèm và `deploy/base/clickhouse/` cung cấp dịch vụ ClickHouse được điều chỉnh cho khối lượng công việc của AgentEye: + +- 2 GiB yêu cầu / 4 GiB giới hạn bộ nhớ trong overlay cơ sở được vận chuyển (được định kích để phù hợp với các nút nhỏ POC/staging); khách hàng production nên overlay lên — sàn được khuyến cáo là 2c / 4Gi yêu cầu, 6c / 8Gi giới hạn. `max_server_memory_usage_to_ram_ratio=0.9` +- 5 GiB đánh dấu bộ nhớ cache + 8 GiB bộ nhớ cache không nén +- `background_pool_size=16`, `background_merges_mutations_concurrency_ratio=2` +- MergeTree: `parts_to_throw_insert=3000`, `parts_to_delay_insert=1500`, `non_replicated_deduplication_window=1000` +- `local_io_method=auto` (io_uring trên hạt nhân được hỗ trợ) +- `fsync_metadata=0`: chấp nhận được vì nhập ít nhất một lần + dedup ReplacingMergeTree +- `query_log` được bật với TTL 30 ngày; `query_thread_log` bị loại bỏ (đắt ở QPS cao) +- `max_execution_time=30` cho các truy vấn phía người dùng +- 100 GiB PVC tại mẫu StatefulSet (overlay khách hàng NÊN ghi đè thành lớp lưu trữ SSD nhanh cho production) + +### Backups + +Tập dữ liệu đầy đủ của bạn được chụp nightly trong một kho lưu trữ có thể khôi phục duy nhất, vì vậy mất cụm hoặc lưu trữ có thể khôi phục. ClickHouse được sao lưu tự động bởi `agenteye-backup` CronJob hàng ngày, đó sao lưu cả PostgreSQL và ClickHouse trong một lần vượt. ClickHouse được đọc trên API HTTP của nó: `agenteye.events` và `agenteye.evaluations` được dump ở định dạng ClickHouse-native (các chế độ xem và chính sách hàng được server tái tạo trên khởi động, vì vậy dữ liệu bảng là bức tranh hoàn chỉnh) và đóng gói với dump Postgres vào một kho lưu trữ được nén duy nhất được tải lên kho lưu trữ đối tượng của bạn. + +Bộ nhớ đích và thông tin xác thực cloud được cấu hình cho mỗi overlay. Xem phần **Backups** của [enterprise-docs/kubernetes-deployment.md](/vi/agenteye/kubernetes-deployment) để cấu hình tải lên và các bước khôi phục. + +--- + +## Redis (cache tùy chọn) + +Redis là một **optional** bộ nhớ cache được chia sẻ + backend giới hạn tốc độ được sử dụng bởi server và dashboard. Với Redis được triển khai và `REDIS_URL` được đặt trên cả hai dịch vụ: + +- **Server** cache các tìm kiếm khóa API được xác thực, danh sách `/events/environments` + `/evaluations/environments`, rollup `/events/latency_aggregate` (truy vấn nặng nhất mà dashboard polls), danh sách `/sessions`, và chuyển đổi giới hạn tốc độ yêu cầu OTP từ Postgres `COUNT(*)` sang Redis `INCR + EXPIRE`. +- **Dashboard** cache `validateSession()` kết quả để 10-20 API gọi được xác thực một tải trang điển hình chia sẻ một kiểm tra phiên thượng nguồn duy nhất. Nó cũng giới hạn tốc độ yêu cầu OTP và xác minh OTP tại dashboard edge. + +**Cả hai dịch vụ đều suy giảm duyên dáng nếu Redis không thể truy cập được.** Mỗi lệnh gọi bộ nhớ cache trả về `Err` trong khoảng thời gian bị giới hạn và người gọi quay về nguồn quy chuẩn (Postgres trên server, Rust server thượng nguồn trên dashboard). Giới hạn tốc độ OTP quay về đường dẫn `COUNT(*)` Postgres trên server (thuộc tính bảo mật được bảo tồn); giới hạn OTP edge của dashboard thất bại mở trong khi giới hạn phía máy chủ vẫn giữ. Redis bị hỏng hóc giảm độ trễ, không phải tính đúng. + +### Configuration + +Gói docker-compose đi kèm đã bao gồm dịch vụ Redis và dây `REDIS_URL=redis://redis:6379/0` vào server và dashboard. Để sử dụng Redis bên ngoài, hãy đặt `REDIS_URL` thành điểm cuối của bạn và loại bỏ dịch vụ `redis` khỏi tệp compose. + +### Memory + persistence + +Hình ảnh Redis đi kèm chạy với `--appendonly yes --appendfsync everysec --maxmemory 256mb --maxmemory-policy allkeys-lru`. Tính bền vững AOF có nghĩa là bộ nhớ cache sống sót sau khi khởi động lại container; `everysec` là cân bằng độ bền/hiệu suất phù hợp vì mất giây cuối cùng của ghi bộ nhớ cache là vô hại. Loại bỏ LRU giới hạn mức tăng bộ nhớ. + +### When NOT to deploy Redis + +- Single-instance dev/QA. Các bộ nhớ cache trong quy trình trên server một mình cung cấp hầu hết lợi ích per-replica; Redis thêm chia sẻ cross-replica mà các thiết lập single-instance không cần. +- Cài đặt được cách ly không khí nơi chi phí hoạt động của việc chạy một dịch vụ hơn nữa vượt quá chiến thắng độ trễ. + +--- + +## Docker Compose (được khuyến cáo) + +Một `docker-compose.yml` có sẵn trong kho lưu trữ `agenteye-enterprise/releases`. Nó đưa lên Postgres, ClickHouse, Redis, server, và dashboard bằng một lệnh duy nhất. + +```bash +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download \ + --repo agenteye-enterprise/releases \ + --pattern 'docker-compose.yml' \ + --dir ./agenteye +cd agenteye +``` + +**Ghi đè mặc định qua `.env`:** + +``` +# Sử dụng mật khẩu an toàn URL (không /, +, hoặc = ký tự). +# Tạo với: openssl rand -hex 24 +POSTGRES_PASSWORD=your-db-password +ADMIN_KEY=your-admin-secret + +# Xác thực dashboard +ADMIN_EMAIL=admin@yourcompany.com +ALLOWED_EMAILS=*@yourcompany.com + +# SMTP cho email OTP (bỏ qua để ghi nhật ký mã OTP vào stdout) +# SMTP_HOST=smtp.yourprovider.com +# SMTP_PORT=587 +# SMTP_USERNAME=your-smtp-user +# SMTP_PASSWORD=your-smtp-password +# SMTP_FROM=noreply@yourcompany.com + +RUST_LOG=info +``` + +```bash +docker compose up -d +``` + +**Dừng (giữ khối lượng dữ liệu):** + +```bash +docker compose down +``` + +**Dừng và xóa tất cả dữ liệu:** + +```bash +docker compose down -v +``` + +--- + +## Operational settings + +Một tập nhỏ các khóp hoạt động từng được ghim bằng biến env hiện có thể chỉnh sửa cho mỗi tổ chức từ trang **`//settings`** của dashboard; mỗi tổ chức cấu hình của chính nó. Các thay đổi có hiệu lực trong vài giây, không cần khởi động lại và không cần triển khai lại. + +| Setting | Bootstrap env var | What it controls | +|---|---|---| +| Allowed sign-ins | `ALLOWED_EMAILS` | Email (hoặc ký tự đại diện `*@domain.com`) được phép nhận OTP và được thêm dưới dạng người dùng | +| Default user permissions | `DEFAULT_USER_PERMISSIONS` | Mã quyền tách bằng dấu phẩy được chọn trước khi admin mở **+ người dùng mới**. Mỗi mã thông báo phải là một trong các chuỗi được liệt kê dưới [API key permissions](/vi/agenteye/api-keys). Mặc định cho preset `standard`: truy cập chỉ đọc cộng với các hành động on-call hàng ngày (kích hoạt lại đánh giá, chạy truy vấn, thừa nhận sự cố, sử dụng trợ lý). | +| Session lifetime | `SESSION_TTL_SECS` | Đăng nhập dashboard kéo dài bao lâu trước khi re-auth. Dashboard kiểm tra lại phiên thượng nguồn mỗi 5 giây, vì vậy cập nhật quyền trên `//users` có hiệu lực trên yêu cầu tiếp theo của người dùng bị ảnh hưởng, không có relogin. | +| One-time-code lifetime | `OTP_TTL_SECS` | OTP / magic-link kéo dài bao lâu trước khi có thể sử dụng | +| Alert notification channels | `ALERTS_ENABLED_CHANNELS` | Danh sách tách bằng dấu phẩy của các loại kênh mà bộ phân phối cảnh báo được phép sử dụng: `email`, `slack`, `webhook`. Cấu hình per-alert vẫn được tác giả trên `//alerts/`, nhưng bộ phân phối lọc mọi gửi outbound qua tập hợp này; kênh được vô hiệu hóa ở đây ngắn mạch với hàng tính toán `skipped_disabled`. Kênh `dashboard` (chèn kiểm toán cục bộ) luôn được phép. Mặc định cho cả ba. | + +### How the bootstrap works + +Các cài đặt được lưu trữ cho mỗi tổ chức trong `org_settings`. Trên khởi động đầu tiên, server seed các hàng còn thiếu của tổ chức mặc định từ biến env phù hợp (hoặc mặc định hợp lý nếu biến env không được đặt). Sau đó, **giá trị được lưu trữ là nguồn quy chuẩn và biến env bị bỏ qua**; thay đổi biến env trên lần khởi động sau này sẽ không ảnh hưởng đến giá trị tổ chức trực tiếp, và các tổ chức bổ sung bắt đầu từ mặc định và cấu hình của riêng chúng. + +Điều này có nghĩa: + +- Đối với triển khai mới, hãy đặt biến env như được hiển thị ở trên và tổ chức mặc định đọc chúng trên khởi động đầu tiên. +- Để thay đổi một giá trị sau này, hãy đăng nhập vào dashboard và chỉnh sửa nó dưới `//settings`. Thay đổi áp dụng trong vài giây trên tất cả các bản sao server; không cần khởi động lại. +- Dòng nhật ký khởi động ghi những gì được seed so với những gì đã có, vì vậy bạn có thể xác nhận bootstrap đã có tác dụng: + + ```text + INFO settings bootstrap: seeded default-org row key=allowed_sign_ins env_var=ALLOWED_EMAILS seeded_from_env=true + ``` + +#### Sign-in semantics across organizations + +Phiên và OTP là toàn cục cho người dùng, không phải cho một tổ chức duy nhất, vì vậy hai quy tắc hòa giải các cài đặt per-org tại thời điểm đăng nhập: + +- **Session / OTP lifetime**: thời gian tồn tại nghiêm ngặt nhất (ngắn nhất) giữa các tổ chức người dùng thuộc về chiến thắng. +- **Allowed sign-ins**: cổng HOẶC danh sách cho phép của mỗi tổ chức với thành viên tổ chức: người dùng có thể yêu cầu OTP nếu danh sách cho phép của bất kỳ tổ chức nào thừa nhận email của họ **hoặc** họ đã là thành viên của bất kỳ tổ chức nào. + +### Permissions + +Truy cập trang `//settings` được kiểm soát bởi hai quyền: + +- `settings:read`: xem trang và giá trị hiện tại. +- `settings:write`: lưu các thay đổi. + +Người dùng admin bootstrap (được seed từ `ADMIN_EMAIL`) nhận cả hai tự động cùng với mọi quyền khác. Cấp chúng cho người dùng khác từ `//users` khi cần. + +--- + +## Organizations (multi-tenancy) + +Một triển khai duy nhất có thể phục vụ nhiều **tổ chức** bị cô lập (tenant); mỗi hàng dữ liệu thuộc về chính xác một tổ chức và cách ly được thực thi trong engine cơ sở dữ liệu. Cài đặt single-tenant không cần gì ở đây; tất cả dữ liệu sống trong tổ chức `default` tích hợp. (Bạn có thể cho tổ chức đó một tên thân thiện hơn và slug URL, vì vậy nó sống ở ví dụ `/acme` thay vì `/default`, bằng cách đặt `DEFAULT_ORG_NAME` / `DEFAULT_ORG_SLUG` trước khởi động đầu tiên, hoặc bằng cách đổi tên nó bất kỳ lúc nào với `agenteye-orgctl org rename`.) + +**Cung cấp tenant chỉ operator.** Các tổ chức và thành viên của chúng được tạo và quản lý bằng CLI **`agenteye-orgctl`**, được cung cấp **bên trong hình ảnh server** (cùng với `agenteye-server`) và chạy **bên trong pod server hiện có**; không có pod/Job riêng biệt, không có API HTTP, và không có nút dashboard. Nó sử dụng lại `DATABASE_URL`, `CLICKHOUSE_URL`, và `ORG_CH_SECRET` của server. + +```bash +# Docker Compose - exec vào dịch vụ server chạy: +docker compose exec server agenteye-orgctl org create --slug acme --name "Acme Corp" +docker compose exec server agenteye-orgctl member add --org acme --email alice@acme.example --set admin + +# Kubernetes - exec vào Deployment server chạy: +kubectl -n agenteye exec deploy/server -- agenteye-orgctl org list +``` + +Động từ có sẵn: `org create | list | rename | delete | purge` và `member add | list | update | remove`, với tập quyền tích hợp `admin`, `standard`, và `read-only`. Các thành viên được thêm nhận OTP trên lần đăng nhập dashboard đầu tiên. + +**Trước khi tạo một tổ chức thứ hai:** đặt một `ORG_CH_SECRET` mạnh, ổn định (lệnh `org create` từ chối chạy trên mặc định dev tích hợp) và đảm bảo Postgres là **15+**. **Không thay đổi:** các khóa API per-org vẫn được tạo trong dashboard/API bởi các thành viên tổ chức; chỉ vòng đời tổ chức + thành viên chuyển đến CLI. Tham khảo lệnh đầy đủ và ví dụ đã làm: **[enterprise-docs/tenant-management.md](/vi/agenteye/tenant-management)**. + +--- + +## Context-window fill + +Mỗi sự kiện `model_response` hiển thị một **context-fill pill** — mã thông báo đầu vào cộng với đầu ra dưới dạng phần trăm của cửa sổ bối cảnh của mô hình đó. Các ban nhạc là `healthy` (0–24%), `watch` (25–49%), `compacting` (50–74%), và `reset context` (75–100%). AgentEye giải quyết các ID mô hình phổ biến tự động, vì vậy không cần cấu hình ban đầu. + +Mỗi mô hình một tổ chức gửi xuất hiện dưới **Settings → model context windows**. Người dùng có `settings:write` có thể ghi đè cửa sổ của nó hoặc thêm mô hình riêng/proxy (0–1.000.000 token); `0` có nghĩa là "unknown" và làm im lặng viên ngọc. Các thay đổi áp dụng cho các sự kiện được nhập mới. Người dùng có `settings:read` có thể xem danh sách. + +Các sự kiện mới nhận được lượng đầy từ lúc bạn nâng cấp. Để cũng điền **lịch sử** sự kiện (và danh sách per-model) cho triển khai hiện có, hãy chạy backfill một lần — nó được cung cấp bên trong hình ảnh server (giống như `agen \ No newline at end of file diff --git a/docs/vi/agenteye/evaluation-suite.mdx b/docs/vi/agenteye/evaluation-suite.mdx new file mode 100644 index 00000000..a10276de --- /dev/null +++ b/docs/vi/agenteye/evaluation-suite.mdx @@ -0,0 +1,356 @@ +--- +title: "Bộ công cụ Đánh giá" +description: "Tài liệu về Bộ công cụ Đánh giá AgentEye." +--- + +AgentEye đánh giá các phiên làm việc của agent đã hoàn thành bằng cách gửi toàn bộ bản ghi sự kiện đến **một dịch vụ đánh giá do khách hàng sở hữu**. Dịch vụ đánh giá trả về điểm số theo cách trực tiếp hoặc bằng cách trả về một `job_id` để AgentEye thăm dò. Kết quả được lưu trữ và hiển thị trên bảng điều khiển. + +Hướng dẫn này bao gồm: + +1. Cách phát hiện hoàn thành phiên làm việc. +2. Hợp đồng HTTP mà dịch vụ đánh giá phải triển khai. +3. Cấu hình máy chủ AgentEye. +4. Xem kết quả. +5. Xử lý sự cố. + +Để tìm helper Python triển khai hợp đồng này, hãy xem +[gói `agenteye-evaluator` trên PyPI](https://pypi.org/project/agenteye-evaluator/). + +--- + +## Cách hoạt động + +```text +ingest /events ──▶ AgentEye ──── POST /evaluate ────▶ Dịch vụ đánh giá + (agent_end) server ◀──── done | pending ──── + │ + │ GET /evaluate/{job_id} ─────▶ + │ ◀──── done ────────────── + ▼ + evaluations (kết quả cuối cùng) +``` + +Khi AgentEye SDK phát hành sự kiện `agent_end` cho một phiên làm việc, máy chủ lên lịch một đánh giá. Sau đó, nó gửi toàn bộ bản ghi sự kiện đến dịch vụ đánh giá của bạn, dịch vụ này có thể: + +- **Trả về kết quả trực tiếp** với `{"status":"done", "scores":{...}, "reasoning":{...}, "summary":"..."}`. Kết quả được thêm vào dòng thời gian đánh giá của phiên. `reasoning` và `summary` là tùy chọn. +- **Trì hoãn** với `{"status":"pending", "job_id":"abc-123"}`. AgentEye sau đó sẽ gọi `GET {EVALUATOR_ENDPOINT}/evaluate/abc-123` cho đến khi dịch vụ đánh giá của bạn trả về `{"status":"done", ...}` hoặc `{"status":"error", "error":"..."}`. + + Tốc độ thăm dò là theo từng công việc: một phản hồi `pending` có thể bao gồm `next_poll_secs` để ghi đè; nếu không thì AgentEye sử dụng giá trị `default_poll_interval_secs` từ `GET /config`; nếu không thì máy chủ quay lại `EVALUATOR_POLLING_INTERVAL_SECS` (mặc định 10s). Tất cả các giá trị được giới hạn ở [1s, 1h]. + +Các phiên làm việc không bao giờ phát hành `agent_end` (ví dụ: quá trình agent bị sập) cũng có thể được nhận diện: `GET /config` của dịch vụ đánh giá có thể trả về `{"inactivity_timeout_secs": 1800}`, và AgentEye sẽ đánh giá bất kỳ phiên nào không hoạt động trong khoảng thời gian đó. Đặt trường thành `null` hoặc bỏ qua để vô hiệu hóa fallback này. + +Pipeline hoàn toàn không hoạt động khi `EVALUATOR_ENDPOINT` không được đặt. + +Một phiên có thể tích lũy **nhiều đánh giá cuối cùng theo thời gian**: mỗi sự kiện `agent_end` (và mỗi lần đánh giá lại thủ công từ bảng điều khiển) sẽ thêm một hàng đánh giá mới. Đây là cách được hỗ trợ để đánh giá một cuộc trò chuyện được tiếp tục: người dùng kết thúc agent, quay lại sau đó, gửi thêm sự kiện, kết thúc agent lần nữa, và một đánh giá thứ hai chạy với toàn bộ bản ghi được cập nhật. Bảng điều khiển hiển thị đánh giá gần nhất là tiêu đề chính và các đánh giá trước đó dưới dạng dòng thời gian có thể thu gọn. Trong khi một đánh giá đang chạy cho một phiên, các sự kiện `agent_end` bổ sung cho phiên đó sẽ bị bỏ qua; sự kiện tiếp theo sau khi đánh giá đang chạy hoàn thành sẽ xếp hàng một đánh giá mới như bình thường. + +Fallback không hoạt động sẽ tái kích hoạt trên các phiên được tiếp tục: nếu các sự kiện mới đến sau một đánh giá cuối cùng trước đó và phiên sau đó trở nên không hoạt động quá `inactivity_timeout_secs`, một đánh giá mới sẽ được xếp hàng. + +Các lỗi tạm thời (5xx, 429, timeout, lỗi mạng) sẽ được thử lại với backoff hàm mũ cho đến `EVALUATOR_MAX_ATTEMPTS`; phản hồi 4xx là cuối cùng. AgentEye có thể chạy an toàn với nhiều phiên bản máy chủ có tỷ lệ ngang; công việc được phân vùng sao cho cùng một phiên không bao giờ được gửi đi hai lần cùng lúc. + +--- + +## Hợp đồng HTTP + +Mọi tuyến đường được xác thực sử dụng **xác thực mã thông báo người mang**. Giá trị tương tự phải được cấu hình ở cả hai bên: + +- Máy chủ AgentEye: biến env `EVALUATOR_TOKEN` +- Dịch vụ đánh giá: được cấu hình theo cách tương tự (SDK `agenteye-evaluator` theo quy ước đọc `EVALUATOR_TOKEN`) + +Nếu `EVALUATOR_TOKEN` không được đặt, máy chủ không gửi tiêu đề `Authorization`; dịch vụ đánh giá sau đó có thể chấp nhận các yêu cầu ẩn danh, điều này tốt cho một mạng nội bộ nhưng không được khuyến khích trên internet công cộng. + +### Các tuyến đường mà dịch vụ đánh giá phải phục vụ + +| Tuyến đường | Phần thân / thông số | Phản hồi | +|---|---|---| +| `GET /health` | không có | `{"status":"ok"}` (công khai, không xác thực) | +| `GET /config` | không có | `{"inactivity_timeout_secs": \| null, "default_poll_interval_secs": \| bỏ qua}` | +| `POST /evaluate` | JSON `EvalRequest` | `{"status":"done", ...}` hoặc `{"status":"pending", "job_id":"..."}` | +| `GET /evaluate/{id}` | không có | hình dạng phản hồi giống như `/evaluate` | + +### Phần thân `EvalRequest` được gửi bởi máy chủ + +```json +{ + "schema_version": "1", + "session_id": "session-abc123", + "agent_id": "planner", + "environment": "production", + "started_at": "2026-05-10T12:00:00Z", + "ended_at": "2026-05-10T12:05:00Z", + "events": [ + { "id": 1234, "ts": "...", "event_type": "agent_start", "payload": { ... } }, + ... + ] +} +``` + +### Các hình dạng phản hồi + +**Đồng bộ (done):** + +```json +{ + "status": "done", + "scores": { "helpfulness": 0.85, "tool_efficiency": 0.6 }, + "reasoning": { + "helpfulness": "answered the question directly with citations", + "tool_efficiency": "called list_files three times when one would have done" + }, + "summary": "strong answer quality, weak tool selection" +} +``` + +`reasoning` (bản đồ giải thích theo từng điểm) và `summary` (lý thuyết tổng thể) đều là tùy chọn. Các khóa trong `reasoning` phải phản ánh các khóa trong `scores`; bảng điều khiển hiển thị mỗi mục nội tuyến dưới thanh điểm của nó. Các đánh giá cũ hơn chỉ trả về `scores` tiếp tục hoạt động không thay đổi; `reasoning` và `summary` đơn giản đọc là null và các affordance UI tương ứng sẽ bị bỏ qua. + +**Không đồng bộ (trì hoãn):** + +```json +{ "status": "pending", "job_id": "abc-123", "next_poll_secs": 30 } +``` + +`next_poll_secs` là tùy chọn; nếu bỏ qua thì máy chủ quay lại `default_poll_interval_secs` của dịch vụ đánh giá từ `/config`, sau đó đến biến env `EVALUATOR_POLLING_INTERVAL_SECS` của nó. + +**Lỗi cuối cùng phía đánh giá:** + +```json +{ "status": "error", "error": "model service unavailable" } +``` + +Máy chủ coi bất kỳ phần thân 2xx nào khác là lỗi giao thức và ghi lại một `error` cuối cùng cho phiên. + +--- + +## Viết một dịch vụ đánh giá với SDK + +Gói Python `agenteye-evaluator` cung cấp cho bạn một trình bao FastAPI được gõ triển khai hợp đồng HTTP ở trên. Cài đặt nó từ PyPI: + +```bash +pip install agenteye-evaluator +``` + +Dịch vụ đánh giá tối thiểu: + +```python +import os +from agenteye_evaluator import Evaluator, EvalRequest, EvalResponse + +app = Evaluator(token=os.environ["EVALUATOR_TOKEN"]) + +@app.evaluator +def run(req: EvalRequest) -> EvalResponse: + # Kiểm tra req.events (bản ghi phiên đầy đủ) và trả về điểm số. + tool_calls = sum(1 for e in req.events if e.event_type == "tool_use") + return EvalResponse( + scores={"tool_calls": float(tool_calls)}, + reasoning={"tool_calls": f"{tool_calls} tool invocations in the transcript"}, + summary="tight tool loop" if tool_calls < 5 else "agent looped on tools", + ) +``` + +Phiên bản `app` là ASGI-callable, vì vậy `uvicorn module:app` chạy nó. + +Đối với các dịch vụ đánh giá cần trì hoãn công việc tốn kém, hãy trả về `JobPending` thay thế và đăng ký trình xử lý `@app.job_lookup`; máy chủ AgentEye thăm dò `GET /evaluate/{job_id}` cho đến khi bạn trả về trạng thái cuối cùng hoặc giới hạn `EVALUATOR_MAX_POLL_DURATION_SECS` (mặc định 1 giờ) hết hiệu lực. + +Tham khảo API đầy đủ, mẫu không đồng bộ và lược đồ sự kiện: README của `agenteye-evaluator` được gửi kèm trong mỗi tarball bản phát hành trên [trang bản phát hành agenteye-enterprise](https://github.com/agenteye-enterprise/releases), hoặc bạn có thể đọc nó trên trang PyPI của gói. + +--- + +## Chạy một dịch vụ đánh giá trên Kubernetes + +Dịch vụ đánh giá là **dịch vụ của bạn**: AgentEye không gửi một container dịch vụ đánh giá mặc định. Bản phát hành bao gồm các bản kê khai Kubernetes tham khảo dưới `deploy/examples/evaluator/` mà bạn có thể áp dụng nguyên trạng sau khi thay thế hình ảnh và mã thông báo người mang dùng chung. + +### 1. Đóng gói dịch vụ đánh giá của bạn + +Một Dockerfile tối thiểu cho dịch vụ đánh giá của bạn: + +```dockerfile +FROM python:3.12-slim +WORKDIR /app +RUN pip install --no-cache-dir agenteye-evaluator uvicorn +COPY my_evaluator.py . +RUN useradd --uid 10001 --create-home --shell /usr/sbin/nologin evaluator \ + && chown -R evaluator:evaluator /app +USER evaluator +EXPOSE 9000 +CMD ["uvicorn", "my_evaluator:app", "--host", "0.0.0.0", "--port", "9000"] +``` + +`runAsNonRoot` (UID 10001) giữ container tương thích với các hồ sơ Pod Security bị hạn chế. + +### 2. Tạo mã thông báo người mang dùng chung + +```bash +kubectl -n agenteye create secret generic evaluator-token \ + --from-literal=token="$(openssl rand -hex 32)" +``` + +Sử dụng cùng giá trị với `EVALUATOR_TOKEN` trên máy chủ AgentEye. Máy chủ gửi `Authorization: Bearer ` trên mọi yêu cầu; SDK sử dụng `hmac.compare_digest` để kiểm tra thời gian không đổi và từ chối sự không khớp với HTTP 401. + +### 3. Áp dụng các bản kê khai ví dụ + +```bash +# Trước tiên hãy chỉnh sửa deploy/examples/evaluator/deployment.yaml để trỏ +# `image:` tại registry của bạn, sau đó: +kubectl apply -k deploy/examples/evaluator/ +``` + +Ví dụ bao gồm: + +- Một Deployment 2 bản sao với `runAsNonRoot`, hệ thống tệp gốc chỉ đọc, tất cả khả năng được bỏ, liveness + readiness trên `/health` +- Một Dịch vụ ClusterIP trên cổng 9000 +- Một bản mẫu `secret.example.yaml` (cố tình không được bao gồm trong Kustomization; tạo secret thực tế ngoài dòng để không có mã thông báo nào được đặt trong git) + +### 4. Kết nối AgentEye với nó + +Trên máy chủ AgentEye, đặt: + +```bash +EVALUATOR_ENDPOINT=http://evaluator:9000 +EVALUATOR_TOKEN= +``` + +Máy chủ trải rộng các yêu cầu `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH` song song trên tất cả các pod dịch vụ đánh giá (mặc định: `2 × 4 = 8`). Mở rộng `replicas` và giới hạn tài nguyên trên mỗi pod phối hợp với các công tắc này phía máy chủ. + +### Xác minh + +```bash +kubectl -n agenteye port-forward svc/evaluator 9000:9000 +curl -s http://localhost:9000/health # → {"status":"ok"} +``` + +Sau khi agent chạy từ đầu đến cuối, `GET /evaluations` trên máy chủ AgentEye phải trả về một hàng có `status: "done"` và các điểm số mà dịch vụ đánh giá của bạn tạo ra. + +--- + +## Cấu hình máy chủ AgentEye + +Đặt trên quá trình máy chủ: + +| Biến Env | Ý nghĩa | +|---|---| +| `EVALUATOR_ENDPOINT` | URL cơ sở của dịch vụ đánh giá của bạn (`http://evaluator:9000`). Không được đặt = pipeline bị vô hiệu hóa. | +| `EVALUATOR_TOKEN` | Mã thông báo người mang. Phải bằng giá trị mà dịch vụ đánh giá được cấu hình. | +| `EVALUATOR_WORKERS` | Nhiệm vụ công nhân trên mỗi phiên bản máy chủ (mặc định 2). | +| `EVALUATOR_CLAIM_BATCH` | Các hàng được yêu cầu trên mỗi tick công nhân (mặc định 4). Các lô được xử lý **song song**; đồng quy hiệu quả trên endpoint dịch vụ đánh giá của bạn là `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH`. | +| `EVALUATOR_POLL_IDLE_SECS` | Công nhân ngủ bao lâu giữa các nỗ lực gửi khi không có đánh giá nào đến hạn (mặc định 2s). | +| `EVALUATOR_POLLING_INTERVAL_SECS` | Fallback cuối cùng cho tốc độ `GET /evaluate/{id}` khi cả `next_poll_secs` trên mỗi phản hồi và `default_poll_interval_secs` của dịch vụ đánh giá không được đặt (mặc định 10s). | +| `EVALUATOR_REQUEST_TIMEOUT_MS` | Timeout theo yêu cầu (mặc định 30000). | +| `EVALUATOR_MAX_ATTEMPTS` | Sau nhiều lần thất bại tạm thời này, kết quả được ghi lại là `error` cuối cùng (mặc định 5). | +| `EVALUATOR_CONFIG_REFRESH_SECS` | Tốc độ `GET /config` (mặc định 300). | +| `EVALUATOR_MAX_POLL_DURATION_SECS` | Thời gian tối đa một phiên có thể ở trong hàng thăm dò trước khi bị kết thúc là `timeout` (mặc định 3600s). Bảo vệ chống lại một dịch vụ đánh giá luôn trả về `pending`. | + +Để bật chấm điểm tự động trên toàn bộ phiên bản, cung cấp Secret `agenteye-evaluator` với cả hai khóa được đặt. Trên các bản kê khai Kubernetes đi kèm, máy chủ đọc `EVALUATOR_ENDPOINT` và `EVALUATOR_TOKEN` từ Secret tùy chọn này. Tạo nó thông qua quy trình quản lý bí mật tiêu chuẩn của tổ chức của bạn, sau đó khởi động lại Deployment máy chủ để nhận up sự thay đổi. + +Các công tắc điều chỉnh ở trên không được kết nối theo mặc định; hiển thị các biến môi trường tương ứng trên container máy chủ trong bản kê khai Deployment của bạn nếu bạn cần ghi đè các mặc định. + +Xem [deployment.md](/vi/agenteye/deployment) để xem bảng biến env đầy đủ. + +--- + +## Tham khảo API + +| Phương pháp | Đường dẫn | Quyền bắt buộc | Mục đích | +|---|---|---|---| +| `GET` | `/evaluations` | `evaluations:read` | Kết quả đầu cuối truy vấn. Hỗ trợ `session_id`, `agent_id`, `environment`, `status` (`done`/`error`/`timeout`), `ts_from`, `ts_to`, `cursor`, `limit`, `score_filters`, `latest_per_session`. `limit` mặc định là 50 và được giới hạn ở 200 (lưu ý điều này khác với `/events`, giới hạn ở 1000). `environment` chấp nhận danh sách tách bằng dấu phẩy (ví dụ: `environment=prod,staging`); các giá trị đơn vẫn hoạt động. Với `latest_per_session=true` phản hồi chứa nhiều nhất một hàng trên mỗi `session_id` (gần đây nhất theo `completed_at`) được sử dụng bởi trang danh sách phiên để thu gọn dòng thời gian đánh giá của phiên thành tiêu đề hiện tại của nó. Mặc định là false (trả về lịch sử đầy đủ). | +| `GET` | `/evaluations/aggregate` | `evaluations:read` | Sức khỏe eval được cuộn lại cho một lát được lọc: tổng số lần, phân tích xong/lỗi/timeout, thống kê theo khóa điểm (số lần/trung bình/tối thiểu/tối đa/p50 trên các khóa `scores` tùy ý), và dòng thời gian được phân nhóm theo thời gian. Chấp nhận **các thông số bộ lọc giống như `/evaluations`** cộng với `featured_keys` (CSV của các khóa điểm để theo dõi) và `latest_per_session`. Powers tính năng Bảng điều khiển; các số liệu chính xác trên toàn bộ tập hợp phù hợp, không được lấy mẫu. | +| `GET` | `/evaluations/environments` | `evaluations:read` | Các giá trị môi trường riêng biệt từ bảng `evaluations`. Được sử dụng để điền các menu thả xuống bộ lọc phạm vi dữ liệu đánh giá có thể đọc. | +| `GET` | `/evaluation-jobs` | `evaluations:read` | Khả năng hiển thị vào các đánh giá đang thực hiện. Lọc theo `status` (`pending`/`polling`). | +| `GET` | `/events` | `events:read` | Truyền phát sự kiện thô của phiên. Hỗ trợ `session_id`, `agent_id`, `event_type` (CSV), `environment` (CSV), `ts_from`, `ts_to`, `cursor`, `limit` và `order`. `order` là `desc` (mới nhất trước, mặc định) hoặc `asc` (cũ nhất trước); giá trị không được nhận dạng quay lại `desc`. Phân trang con trỏ thông qua `next_cursor` của phản hồi (một id sự kiện): chuyển nó trở lại thành `cursor` để lấy trang tiếp theo; với `asc` trang tiếp theo là các sự kiện sau id đó, với `desc` là các sự kiện trước nó. `limit` mặc định là 50 và được giới hạn ở 1000. | +| `GET` | `/sessions/:session_id/export` | `events:read` | Trả về phần thân JSON chính xác mà dịch vụ đánh giá sẽ nhận cho phiên này, được phục vụ dưới dạng tệp đính kèm có thể tải xuống có tên `session-.json`. Hữu ích để phát lại các phiên sản xuất qua `agenteye-evaluator` để thử nghiệm ngoài tuyến. Các byte giống hệt với những gì pipeline dịch vụ đánh giá gửi. | +| `POST` | `/sessions/:session_id/re-evaluate` | `evaluations:trigger` | Xếp hàng một đánh giá mới cho một phiên; chạy cho dù đánh giá trước đó có tồn tại hay không. Kết quả mới được **nối thêm** vào dòng thời gian đánh giá của phiên thay vì ghi đè kết quả trước đó, vì vậy điểm số trước đó vẫn hiển thị dưới dạng lịch sử. Trả về `202` trên xếp hàng, `404` cho một phiên không xác định, `409` nếu một đánh giá đã đang thực hiện. Sử dụng sau khi triển khai một dịch vụ đánh giá mới hoặc cho các phiên không bao giờ phát hành `agent_end`. | + +### Lọc theo phạm vi điểm: `score_filters` + +`GET /evaluations` chấp nhận một thông số `score_filters` tùy chọn thu hẹp kết quả theo các giá trị số bên trong đối tượng `scores`. Thông số này là danh sách tách bằng dấu phẩy của các mục `key:min..max`; có thể bỏ qua một trong hai giới hạn. Nhiều mục kết hợp với AND logic. Các hàng trong đó khóa được đặt tên vắng mặt hoặc không phải số được loại trừ. Một yêu cầu có thể chứa nhiều nhất 20 mục bộ lọc; vượt quá điều đó trả về HTTP 400. + +Ví dụ: +```text +# helpfulness in [0.5, 0.8] +GET /evaluations?score_filters=helpfulness:0.5..0.8 + +# tool_efficiency at most 0.3 (no lower bound) +GET /evaluations?score_filters=tool_efficiency:..0.3 + +# helpfulness >= 0.5 AND factuality >= 0.9 +GET /evaluations?score_filters=helpfulness:0.5..,factuality:0.9.. +``` + +Mỗi đối tượng phản hồi `/evaluations` có những trường này: + +| Trường | Loại | Ghi chú | +|---|---|---| +| `evaluation_id` | string (UUID) | Mã định danh chính tắc cho đánh giá cuối cùng này. Mỗi đánh giá cuối cùng nhận được một UUID mới; một phiên duy nhất có thể giữ nhiều. | +| `id` | string (UUID) | Bí danh tương thích ngược mang giá trị giống như `evaluation_id`. | +| `session_id` | string | Phiên mà đánh giá chạy trên đó. Một phiên có thể có nhiều đánh giá trong dòng thời gian. | +| `agent_id` | string | Xác định agent đã tạo phiên. | +| `environment` | string | Nhãn môi trường được sao chép từ phiên. | +| `status` | enum | Một trong `"done"`, `"error"`, `"timeout"`. | +| `scores` | object \| null | Điểm số được trả về bởi dịch vụ đánh giá của bạn. | +| `reasoning` | object \| null | Bản đồ giải thích tùy chọn theo từng điểm được trả về bởi dịch vụ đánh giá của bạn. Các khóa thường phản ánh những khóa trong `scores`. Bảng điều khiển hiển thị mỗi mục dưới thanh điểm của nó. | +| `summary` | string \| null | Tương tự tùy chọn một đoạn tổng thể được trả về bởi dịch vụ đánh giá của bạn. Bảng điều khiển hiển thị nó ở trên bước phân tích theo điểm làm tiêu đề của đánh giá. | +| `error` | string \| null | Được điền trên `"error"` / `"timeout"` chỉ. | +| `attempt_count` | integer | Số lần nỗ lực gửi (≥ 1). | +| `duration_ms` | integer \| null | Khoảng thời gian của nỗ lực cuối cùng. | +| `completed_at` | string (ISO 8601 UTC) | Khi kết quả cuối cùng được ghi lại. Kết quả được sắp xếp theo `completed_at` (mới nhất trước). | +| `created_at` | string (ISO 8601 UTC) | Mang cùng một dấu thời gian như `completed_at` (ngữ nghĩa ghi một lần). | + +--- + +## Quyền + +| Quyền | Cấp | +|---|---| +| `evaluations:read` | Danh sách kết quả đánh giá, xem điểm trong bảng điều khiển và tải số liệu sức khỏe bảng điều khiển. | +| `evaluations:trigger` | Tự động xếp hàng một đánh giá cho một phiên qua `POST /sessions/:session_id/re-evaluate` hoặc nút đánh giá lại của bảng điều khiển. | +| `dashboards:read` | Xem các bảng điều khiển đã lưu (cũng cần `evaluations:read` để tải các số liệu của chúng). | +| `dashboards:write` | Tạo và chỉnh sửa bảng điều khiển. | +| `dashboards:delete` | Xóa bảng điều khiển. | + +Admin bootstrap (`ADMIN_KEY`, `ADMIN_EMAIL`) tự động nhận các quyền này. + +--- + +## Xem kết quả + +- **`/sessions/`**: dòng thời gian sự kiện + thanh bên phải hiển thị điểm số của phiên và bất kỳ lỗi nào từ nỗ lực gửi. Nếu khóa của bạn có `evaluations:trigger`, một nút **đánh giá lại** sẽ xuất hiện bên cạnh nút xuất, hữu ích cho các phiên không bao giờ phát hành `agent_end`, hoặc để làm mới điểm sau khi triển khai một dịch vụ đánh giá mới. Bảng điều khiển thăm dò tìm kết quả mới và cập nhật thanh bên phải khi nó đến. +- **`/sessions`**: lưới phiên có thể lọc; cột điểm hiển thị trạng thái đánh giá và điểm của mỗi phiên trong nháy mắt. +- **`/dashboards`**: các chế độ xem sức khỏe eval đã lưu (xem [Bảng điều khiển](#dashboards) dưới đây). + +![Lưới Sessions với các viên chứng chỉ trạng thái đánh giá mỗi phiên và lá cờ điểm được mã hóa màu (helpfulness, factuality, tool_efficiency, safety, coherence)](/agenteye/images/sessions-list.png) + +*Lưới phiên hiển thị trạng thái đánh giá và điểm của mỗi lần chạy trong nháy mắt; lá cờ đỏ/hổ phách/xanh làm cho các điểm thấp nổi bật.* + +![Chế độ xem chi tiết phiên với điểm đánh giá và trạng thái gửi trong thanh bên phải](/agenteye/images/session-detail.png) + +*Mở một phiên hiển thị dòng thời gian đầy đủ của nó cùng với điểm đánh giá và bất kỳ lỗi gửi nào trong thanh bên phải.* + +--- + +## Bảng điều khiển + +Trang **Bảng điều khiển** (`/dashboards`) cho phép bạn lưu một kết hợp các bộ lọc đánh giá dưới dạng chế độ xem được đặt tên, có thể tái sử dụng và xem cách lát cắt đánh giá đó hoạt động trong nháy mắt. Bảng điều khiển được **chia sẻ trên toàn bộ tổ chức của bạn**; mọi người có `dashboards:read` đều nhìn thấy cùng một tập hợp. + +Mỗi bảng điều khiển ghim: + +- **Bộ lọc**: cùng các điều khiển với trang phiên: môi trường, trạng thái, agent, cửa sổ thời gian lăn và bộ lọc phạm vi điểm (`key:min..max`). +- **Cấu hình hiển thị**: khóa điểm nào để đặc biệt, ngưỡng sức khỏe xanh/hổ phách/đỏ, bảng điều khiển nào để hiển thị và có nên thu gọn thành đánh giá gần đây nhất cho mỗi phiên hay không. + +Mỗi thẻ hiển thị số lượng phiên phù hợp, phân tích xong/lỗi/timeout, trung bình của mỗi điểm đặc biệt và một sparkline xu hướng nhỏ. Mở bảng điều khiển hiển thị bảng điều khiển kích thước đầy đủ; **đơn vị mở trong phiên** bỏ bạn vào trang phiên được lọc trước sẵn với chính xác lát cắt đó. Các số liệu được tính toán phía máy chủ trên toàn bộ tập hợp phù hợp (thông qua `GET /evaluations/aggregate`), vì vậy các số chính xác hơn là lấy mẫu. + +![Bảng điều khiển sức khỏe eval với thanh điểm trung bình cho mỗi chiều đánh giá, phân tích công cụ ok-vs-error, công cụ hàng đầu và xu hướng sự kiện mỗi giờ](/agenteye/images/dashboard-quality.png) + +**Quyền:** xem cần cả `dashboards:read` và `evaluations:read`; tạo và chỉnh sửa cần `dashboards:write`; xóa cần `dashboards:delete`. Admin bootstrap nhận tất cả những cái này tự động. + +--- + +## Xử lý sự cố + +**Các phiên tồn tại nhưng không có đánh giá nào được tạo.** Xác nhận rằng `EVALUATOR_ENDPOINT` được đặt trên quá trình máy chủ, máy chủ và dịch vụ đánh giá chia sẻ cùng một giá trị `EVALUATOR_TOKEN` và endpoint `/health` của dịch vụ đánh giá có thể truy cập được từ máy chủ. Khi `EVALUATOR_ENDPOINT` không được đặt, pipeline là không hoạt động. + +**Các đánh giá đang thực hiện tích tụ.** Truy vấn `GET /evaluation-jobs` để xem hàng đợi đang thực hiện. Kiểm tra `attempt_count`, `next_attempt_at` và `last_error` trên mỗi hàng. Nguyên nhân phổ biến: dịch vụ đánh giá không thể truy cập hoặc trả về 5xx (được thử lại với backoff), `EVALUATOR_TOKEN` sai (401 là cuối cùng), hoặc một dịch vụ đánh giá không đồng bộ trả về `pending` vô thời hạn (xem dưới đây). + +**Các phiên đã hoàn thành nhưng không có đánh giá cuối cùng.** Truy vấn `GET /evaluation-jobs?status=polling`; kết quả vẫn có thể đang thực hiện. Nếu một công việc bị kẹt ở `pending`, máy chủ gặp sự cố khi kết nối với dịch vụ đánh giá; hãy kiểm tra xem dịch vụ đánh giá có được bật và `EVALUATOR_TOKEN` khớp không. + +**`HTTP 401 từ dịch vụ đánh giá: mã thông báo người mang không hợp lệ`.** `EVALUATOR_TOKEN` trên máy chủ không khớp với giá trị mà dịch vụ đánh giá được cấu hình. Chúng phải giống hệt nhau. + +**Dịch vụ đánh giá không đồng bộ trả về `pending` vĩnh viễn.** Máy chủ thăm dò `GET /evaluate/{job_id}` cho đến khi dịch vụ đánh giá trả về `done` hoặc `error`, hoặc cho đến khi `EVALUATOR_MAX_POLL_DURATION_SECS` (mặc định 1 giờ) hết hiệu lực. Sau khi vượt quá giới hạn, đánh giá được ghi lại là `timeout` và được xóa khỏi hàng đợi đang thực hiện. Tăng `EVALUATOR_MAX_POLL_DURATION_SECS` nếu dịch vụ đánh giá của bạn hợp pháp cần lâu hơn mặc định. \ No newline at end of file diff --git a/docs/vi/agenteye/getting-started.mdx b/docs/vi/agenteye/getting-started.mdx new file mode 100644 index 00000000..36171ac0 --- /dev/null +++ b/docs/vi/agenteye/getting-started.mdx @@ -0,0 +1,235 @@ +--- +title: "Bắt đầu với AgentEye" +description: "Tài liệu Bắt đầu với AgentEye." +--- + + +Hướng dẫn này sẽ đưa bạn qua toàn bộ quá trình thiết lập AgentEye: triển khai máy chủ và bảng điều khiển, cài đặt bộ thu thập trên máy chạy agent, và tích hợp mã Python agent của bạn. + +--- + +## AgentEye là gì? + +AgentEye là một **nền tảng quan sát và đánh giá tự lưu trữ cho các AI agent**. Nó ghi lại những gì các agent của bạn làm — từng bước của một lần chạy — và tự động chấm điểm chất lượng của mỗi lần chạy hoàn thành, để bạn có thể thấy cách các agent của bạn hoạt động trong môi trường sản xuất và phát hiện các suy thoái trước khi người dùng của bạn làm. + +Dữ liệu chảy theo một hướng: mã agent của bạn phát ra **events** thông qua **Python SDK** → một daemon **bộ thu thập** nhẹ nhàng phân loại và gửi chúng đến **máy chủ** → events và phân tích được lưu trữ trong **ClickHouse** (trạng thái hoạt động như các tổ chức, người dùng, API keys, bảng điều khiển và các truy vấn đã lưu sống trong **Postgres**) → bạn khám phá mọi thứ trong **bảng điều khiển**. + +Những gì bạn nhận được: + +- **Events** — dấu vết thô, từng bước của mỗi lần chạy agent (lệnh gọi công cụ, lệnh gọi mô hình, hooks, lỗi). +- **Sessions** — những events đó được tổng hợp thành một hàng cho mỗi lần chạy, mỗi cái được **tự động đánh giá** và chấm điểm. +- **Evaluations** — điểm chất lượng do các dịch vụ đánh giá của riêng bạn tạo ra, để các sụt giảm chất lượng hiển thị mà không cần xem xét thủ công. +- **Queries & dashboards** — SQL ClickHouse đã lưu trên dữ liệu của bạn, được vẽ biểu đồ thành các bảng điều khiển được chia sẻ, phạm vi tổ chức. +- **Alerts & incidents** — quy tắc ngưỡng trang bạn (email, Slack, webhook, trong bảng điều khiển) cộng với quy trình xử lý sự cố để phân loại chúng. +- **CLI & AI assistant** — máy khách terminal (`agenteye`) và trợ lý trong bảng điều khiển để đặt câu hỏi bằng tiếng Anh đơn giản. + +Bạn chạy tất cả nó trong cơ sở hạ tầng của riêng mình, dưới dạng một ngăn xếp Docker Compose duy nhất (hướng dẫn này), cài đặt Kubernetes sản xuất, hoặc một pod đặt cùng nhau duy nhất. Phần còn lại của hướng dẫn này thiết lập ngăn xếp Compose từ đầu đến cuối. + +--- + +## Bước 1: Xác thực + +Tất cả các tạo tác AgentEye được phân phối từ tổ chức GitHub `agenteye-enterprise`. Là nhà phát triển doanh nghiệp, bạn có thể tạo PAT GitHub của riêng mình. Làm theo [enterprise-docs/github-token.md](/vi/agenteye/github-token) để biết các bước chính xác và quyền cần thiết. + +```bash +export AGENTEYE_TOKEN= + +# Authenticate Docker against GHCR +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +--- + +## Bước 2: Triển khai Máy chủ và Bảng điều khiển + +Máy chủ nhận các events từ các bộ thu thập và làm cho chúng có thể truy vấn được; bảng điều khiển là nơi bạn khám phá chúng. Các events được nhập vào và phân tích sống trong ClickHouse (kho phân tích bắt buộc), trong khi Postgres giữ trạng thái hoạt động như các tổ chức, người dùng, API keys, bảng điều khiển và các truy vấn đã lưu. + +**Tải xuống tệp compose được xuất bản:** + +```bash +mkdir -p ./agenteye +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + https://raw.githubusercontent.com/agenteye-enterprise/releases/main/docker-compose.yml \ + -o ./agenteye/docker-compose.yml +cd agenteye +``` + +**Đặt bí mật của bạn:** + +Tạo tệp `.env` để triển khai không chạy trên thông tin đăng nhập mặc định `admin`. Ít nhất hãy đặt `ADMIN_KEY` và `POSTGRES_PASSWORD`: + +```bash +POSTGRES_PASSWORD=your-db-password +ADMIN_KEY=your-admin-secret +``` + +Cũng xuất `ADMIN_KEY` trong shell hiện tại của bạn để các bước sau này (ví dụ: `curl` Bước 3) có thể tham chiếu nó trực tiếp: + +```bash +export ADMIN_KEY=your-admin-secret +``` + +**Khởi động ngăn xếp:** + +```bash +docker compose up -d +``` + +Điều này đưa ngăn xếp đầy đủ lên, bao gồm kho phân tích ClickHouse bắt buộc và bộ nhớ cache Redis tùy chọn, cùng với máy chủ và bảng điều khiển. ClickHouse phải lành mạnh để máy chủ khởi động. + +Máy chủ hiện đang lắng nghe tại `http://localhost:8080` và bảng điều khiển tại `http://localhost:3000`. + +Để triển khai sản xuất (Postgres tùy chỉnh, TLS, reverse proxy), hãy xem [enterprise-docs/deployment.md](/vi/agenteye/deployment). + +--- + +## Bước 3: Tạo API Key cho Bộ thu thập + +Mỗi bộ thu thập xác thực bằng API key có phạm vi. Sử dụng `ADMIN_KEY` bạn đặt ở Bước 2 để tạo một cái: + +```bash +curl -s -X POST http://localhost:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{"name":"prod-collector","key":"your-collector-secret","permissions":["events:add"]}' +``` + +Bạn cung cấp giá trị `key` tự mình; sử dụng nó trong cấu hình bộ thu thập ở Bước 4. Xem [enterprise-docs/api-keys.md](/vi/agenteye/api-keys) để quản lý key đầy đủ. + +--- + +## Bước 4: Cài đặt Bộ thu thập + +Trên mỗi máy chạy các AI agent của bạn, hãy cài đặt daemon bộ thu thập. + +**Tải xuống tệp nhị phân (Linux x86_64):** + +```bash +VERSION=0.0.1-beta.13 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "collector/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-collector-linux-x86_64' +chmod +x agenteye-collector-linux-x86_64 +sudo mv agenteye-collector-linux-x86_64 /usr/local/bin/agenteye-collector +``` + +> Điều này tải xuống bản dựng **Linux x86_64**. Đối với macOS (Apple Silicon hoặc Intel), Linux arm64, hoặc Docker / systemd / launchd setup, xem [collector-installation.md](/vi/agenteye/collector-installation), liệt kê tải xuống cho mỗi nền tảng — lệnh trên cài đặt một tệp nhị phân Linux sẽ không chạy ở nơi khác. + +**Cấu hình:** + +```bash +mkdir -p ~/.agenteye +cat > ~/.agenteye/config.json </…`). + +- **Queries** (`//queries`): bắt đầu từ một thư viện các truy vấn đã lưu, có thể tái sử dụng trên các events và evaluations của bạn (các cài đặt sẵn tích hợp cộng với các truy vấn của riêng bạn)… + +![Thư viện truy vấn đã lưu: một lưới các truy vấn có thể tái sử dụng, cả cài đặt sẵn tích hợp và truy vấn tùy chỉnh](/agenteye/images/queries.png) + + …sau đó mở một cái trong nhà soạn SQL để điều chỉnh nó và chạy nó với kết quả trực tiếp: + +![Nhà soạn truy vấn SQL chạy một truy vấn đã lưu, với một thanh bên lược đồ và một lưới kết quả trực tiếp](/agenteye/images/query-lab.png) + +- **Dashboards** (`//dashboards`): ghim các truy vấn dưới dạng các tile đường, thanh, diện tích hoặc bánh vào các bảng điều khiển được chia sẻ, toàn org. + +![Bảng điều khiển được xây dựng từ các truy vấn đã lưu: một dòng events mỗi giờ, một thanh lỗi theo loại, biểu đồ diện tích độ trễ và tokens theo mô hình](/agenteye/images/dashboard-fleet.png) + +- **Alerts** (`//alerts`): thăng cấp bất kỳ ngưỡng nào thành quy tắc trang thông báo bằng email, Slack, webhook hoặc trong bảng điều khiển. Xem [enterprise-docs/alerts.md](/vi/agenteye/alerts). + +--- + +## Các bước tiếp theo + +- [Deployment](/vi/agenteye/deployment): củng cố cho sản xuất +- [API Keys](/vi/agenteye/api-keys): quản lý quyền truy cập +- [Troubleshooting](/vi/agenteye/troubleshooting): chẩn đoán các vấn đề \ No newline at end of file diff --git a/docs/vi/agenteye/github-token.mdx b/docs/vi/agenteye/github-token.mdx new file mode 100644 index 00000000..e58dcf73 --- /dev/null +++ b/docs/vi/agenteye/github-token.mdx @@ -0,0 +1,131 @@ +--- +title: "Thiết Lập Token GitHub" +description: "Tài liệu thiết lập Token GitHub cho AgentEye." +--- + +Token Truy Cập Cá Nhân (PAT) của GitHub là thông tin xác thực duy nhất mở khóa mọi artifact của AgentEye. Với một token, bạn có thể kéo các Docker image, tải xuống các nhị phân bản phát hành và cài đặt các wheel Python mà không cần đăng nhập từng thành phần và không cần chia sẻ bí mật. Tất cả các artifact của AgentEye được phân phối từ tổ chức `agenteye-enterprise` trên GitHub; sau khi tổ chức của bạn được cấp quyền truy cập, mỗi nhà phát triển hoặc người vận hành tạo và xoay token của riêng họ, do đó quyền truy cập vẫn có thể kiểm toán và thu hồi được cho từng người. + +Đặt token dưới dạng biến môi trường và thông tin xác thực Docker một lần trên mỗi máy: + +```bash +export AGENTEYE_TOKEN= +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +> **Lưu ý về tên người dùng:** GHCR bỏ qua tên người dùng trong `docker login` và xác thực hoàn toàn từ token, do đó bất kỳ giá trị nào khác rỗng đều hoạt động. Tài liệu này sử dụng `-u x` để gọn gàng; các manifest triển khai tạo secret kéo image Kubernetes có thể sử dụng tên người dùng mô tả hơn như `agenteye-enterprise`. Cả hai đều được chấp nhận. + +--- + +## Tùy Chọn A: Token Cổ Điển (Được Khuyến Nghị) + +Token cổ điển là lựa chọn đáng tin cậy nhất cho AgentEye, vì luồng `docker login` và kéo image của GHCR có sự hỗ trợ rộng nhất và nhất quán nhất cho token cổ điển. Hai phạm vi bao gồm mọi thứ bạn cần (kéo image và tải xuống asset bản phát hành), do đó bạn xác thực một lần và tiếp tục mà không cần khắc phục sự cố registry. Một trong số đó, `read:packages`, là thực sự chỉ đọc; phạm vi kia, `repo`, là phạm vi cổ điển duy nhất cấp quyền truy cập vào asset bản phát hành riêng tư, và nó được thiết kế để rộng - GitHub định nghĩa nó là kiểm soát đầy đủ (đọc và ghi) của các kho riêng tư. + +### 1. Tạo token + +Đi tới **GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic) → Generate new token (classic)**. + +| Trường | Giá Trị | +|---|---| +| **Note** | `agenteye-` (ví dụ: `agenteye-prod-server`) | +| **Expiration** | Đặt thời gian hết hạn phù hợp với chính sách bảo mật của bạn; 90 ngày là mặc định hợp lý | + +> **Lưu ý về nhãn:** GitHub gọi trường này là **Note** cho token cổ điển và **Token name** cho token chi tiết. Chúng phục vụ cùng mục đích: một định danh có thể đọc được của con người để kiểm toán và thu hồi sau này. + +### 2. Chọn phạm vi + +| Phạm Vi | Lý Do Cần Thiết | +|---|---| +| `read:packages` | Kéo Docker image từ `ghcr.io/agenteye-enterprise/` và tải xuống asset gói | +| `repo` | Đọc nội dung kho riêng tư, tệp thô và asset bản phát hành từ `agenteye-enterprise/releases`. Đây là phạm vi rộng Kiểm soát đầy đủ của kho riêng tư của GitHub (đọc và ghi), không phải phạm vi chỉ đọc — nó chỉ là phạm vi cổ điển duy nhất cấp quyền truy cập vào asset bản phát hành riêng tư | + +Không cần phạm vi nào khác. + +### 3. Tạo và sao chép token + +Nhấp vào **Generate token** và sao chép giá trị ngay lập tức; nó chỉ được hiển thị một lần. Lưu trữ nó trong trình quản lý bí mật hoặc môi trường của bạn. + +--- + +## Tùy Chọn B: Token Chi Tiết + +Token chi tiết giới hạn quyền truy cập vào các kho cụ thể và quyền, khiến chúng trở thành tùy chọn ít quyền hạn nhất chặt chẽ nhất. Chọn con đường này khi chính sách bảo mật của tổ chức bạn yêu cầu token chi tiết. + +> **Lưu ý:** Hỗ trợ GHCR cho token chi tiết ít nhất quán hơn cho token cổ điển. Nếu `docker login` hoặc `docker pull` không thành công sau khi làm theo các bước này, quay lại token cổ điển (Tùy Chọn A). + +### 1. Tạo token + +Đi tới **GitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokens → Generate new token**. + +| Trường | Giá Trị | +|---|---| +| **Token name** | `agenteye-` (ví dụ: `agenteye-prod-server`) | +| **Expiration** | Đặt thời gian hết hạn phù hợp với chính sách bảo mật của bạn; 90 ngày là mặc định hợp lý | +| **Resource owner** | `agenteye-enterprise` | +| **Repository access** | **Only select repositories** → `agenteye-enterprise/releases` | + +### 2. Đặt quyền kho + +Dưới **Permissions → Repository permissions**, đặt: + +| Quyền | Truy Cập | +|---|---| +| **Contents** | Read-only | +| **Packages** | Read-only | + +Tất cả các quyền khác có thể vẫn ở **No access**. + +> **Lưu ý:** Nếu các container image (`ghcr.io/agenteye-enterprise/...`) được xuất bản dưới dạng gói cấp tổ chức thay vì gói được liên kết kho, đăng nhập Docker có thể không thành công chỉ với quyền được giới hạn kho. Trong trường hợp đó, hãy thêm quyền cấp tổ chức: **Permissions → Organization permissions → Packages: Read-only**. + +### 3. Mỗi quyền cấp những gì + +| Quyền | Dùng Cho | +|---|---| +| Contents: Read-only | Tải xuống `docker-compose.yml`, nhị phân bản phát hành và wheel Python từ `agenteye-enterprise/releases` | +| Packages: Read-only | Kéo Docker image từ `ghcr.io/agenteye-enterprise/` | + +### 4. Tạo và sao chép token + +Nhấp vào **Generate token** và sao chép giá trị ngay lập tức; nó chỉ được hiển thị một lần. Lưu trữ nó trong trình quản lý bí mật hoặc môi trường của bạn. + +--- + +## Xoay Token + +Xoay token theo lịch giữ cho quyền truy cập có thể kiểm toán và giới hạn bán kính tác động nếu thông tin xác thực bao giờ bị rò rỉ. Token cũng có thể hết hạn hoặc bị thu hồi bất kỳ lúc nào, do đó xoay là cách thông thường để vẫn được xác thực. Để xoay: + +1. Tạo token mới bằng các bước ở trên. +2. Cập nhật `AGENTEYE_TOKEN` trong môi trường hoặc trình quản lý bí mật của bạn. +3. Xác thực lại Docker: `echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin` +4. Thu hồi token cũ trong GitHub → Settings → Developer settings → Personal access tokens, sau đó mở trang con **Tokens (classic)** hoặc **Fine-grained tokens** khớp với loại token của bạn và xóa nó. + +--- + +## Xác Minh Token Của Bạn + +Xác nhận token hoạt động trước khi kết nối nó vào triển khai, do đó những lỗi xác thực xuất hiện ở đây thay vì giữa cuộc triển khai. Mỗi lệnh sử dụng một trong các phạm vi ở trên: + +```bash +# Packages scope - authenticate Docker against GHCR +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin + +# Contents scope - fetch a raw release file +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + https://raw.githubusercontent.com/agenteye-enterprise/releases/main/docker-compose.yml \ + -o /tmp/agenteye-compose-check.yml +``` + +`docker login` thành công xác nhận phạm vi gói; tệp đã tải xuống xác nhận phạm vi nội dung. + +--- + +## Khắc Phục Sự Cố + +| Triệu Chứng | Nguyên Nhân Có Thể | Sửa Chữa | +|---|---|---| +| `docker login` trả về 401 | Token thiếu `Packages: Read-only` (chi tiết) hoặc `read:packages` (cổ điển) | Thêm phạm vi gói và tạo lại | +| `curl` trả về 404 trên URL GitHub thô | Token thiếu phạm vi `Contents: Read-only` hoặc `repo` | Thêm phạm vi nội dung và tạo lại | +| `gh release download` trả về 403 | Token không được phép cho `agenteye-enterprise/releases` | Xác minh kho được bao gồm trong quyền truy cập kho của token chi tiết, hoặc sử dụng token cổ điển với phạm vi `repo` | +| Token được chấp nhận nhưng không tìm thấy image | Quyền gói cấp tổ chức thiếu trên token chi tiết | Thêm quyền `Packages: Read-only` cấp tổ chức | + +Để khắc phục các vấn đề về quyền truy cập, hãy liên hệ với `support@exosphere.host`. \ No newline at end of file diff --git a/docs/vi/agenteye/health-monitoring.mdx b/docs/vi/agenteye/health-monitoring.mdx new file mode 100644 index 00000000..3bd8a9fd --- /dev/null +++ b/docs/vi/agenteye/health-monitoring.mdx @@ -0,0 +1,91 @@ +--- +title: "Giám sát Sức khỏe" +description: "Tài liệu Giám sát Sức khỏe AgentEye." +--- + +Biết khi nào một triển khai AgentEye **chính nó** bị sự cố hoặc hoạt động kém, không chỉ khi agents của bạn hoạt động không đúng. Phát hiện **tương thích Kubernetes** và quan trọng nhất là **độc lập với AgentEye**: nó đọc trạng thái pod từ mặt phẳng điều khiển Kubernetes và kiểm tra các phụ thuộc cứng của AgentEye, vì vậy nó vẫn hoạt động ngay cả khi máy chủ, ClickHouse hoặc Postgres bị sự cố. + +Có hai lớp. Lớp thứ nhất được tích hợp sẵn; lớp thứ hai là tùy chọn. + +## 1. Sự sẵn sàng nhận thức phụ thuộc (tích hợp sẵn) + +Máy chủ hiển thị hai điểm cuối probe có công việc khác nhau một cách cố ý: + +| Điểm cuối | Probe | Kiểm tra | Xác thực | +|---|---|---|---| +| `GET /health` | liveness | quá trình đang hoạt động (luôn là `{"status":"ok"}`) | không | +| `GET /ready` | readiness | có thể thực sự phục vụ: **Postgres + ClickHouse** có thể tiếp cận | không | + +`/ready` trả về `200` với `"status":"ready"` và mọi check `"ok"` khi cả hai phụ thuộc cứng có thể tiếp cận, và `503` với `"status":"not_ready"` khi một trong hai không thể tiếp cận. Cả hai phản hồi đều có phần nội dung nhỏ: + +```json +{ "status": "not_ready", + "checks": { "postgres": "ok", "clickhouse": "down", "redis": "not_configured" } } +``` + +Redis là một bộ đệm tùy chọn mà máy chủ có thể hoạt động vượt qua, vì vậy nó được báo cáo thông tin nhưng **không bao giờ** làm hỏng sự sẵn sàng. Nó hiển thị `"ok"` khi một bộ đệm được cấu hình và `"not_configured"` nếu ngược lại; nó không bao giờ là `"down"`. + +Trên các manifest Kubernetes được đóng gói, probe **readiness** trỏ tới `/ready` và **liveness** ở lại `/health`. Hiệu quả: một máy chủ *đang chạy nhưng không thể tiếp cận cơ sở dữ liệu* của nó bị loại khỏi Service và hiển thị dưới dạng `NotReady`, một trạng thái mà giám sát cụm của bạn (bên dưới) có thể cảnh báo, trong khi liveness vẫn rẻ nên một sự cố phụ thuộc thoáng qua không bao giờ kích hoạt khởi động lại pod. Probe sử dụng ngưỡng lỗi rộng rãi nên một sự cố thoáng qua không bao giờ làm dao động các bản sao ra khỏi rotation. + +## 2. Cảnh báo lỗi Pod với Robusta (tùy chọn) + +[Robusta](https://github.com/robusta-dev/robusta) là một monitor tương thích Kubernetes theo dõi máy chủ API và gửi các lỗi pod (`CrashLoopBackOff`, `OOMKilled`, `ImagePullBackOff`, `Pending`/`NotReady`, `Failed`, evictions) tới Slack. Vì nó quan sát mặt phẳng điều khiển thay vì hỏi AgentEye, nó cảnh báo ngay cả khi AgentEye không thể phục vụ hoàn toàn. + +Robusta được vận chuyển dưới dạng một add-on tùy chọn trong gói phát hành. Bật nó bằng biểu đồ Helm Robusta tiêu chuẩn và tệp giá trị nhỏ được hiển thị bên dưới: + +1. Thêm kho biểu đồ và nhận **bot token** của Slack (`xoxb-…`) cho kênh: + + ```bash + helm repo add robusta https://robusta-charts.storage.googleapis.com + helm repo update + ``` + + Vì cấu hình bên dưới giữ mọi thứ trong cụm (`disableCloudRouting: true`), token đến từ một ứng dụng Slack được lưu trữ tự: + tạo một ứng dụng tại `https://api.slack.com/apps`, thêm phạm vi bot `chat:write`, cài đặt nó vào không gian làm việc của bạn, sao chép **Bot User OAuth Token** (`xoxb-…`), và mời bot tới kênh (`/invite @your-app`). + +2. Tạo `values.yaml` với nhãn cho mỗi triển khai (`clusterName`) và kênh Slack của bạn, được phạm vi vào không gian tên `agenteye`: + + ```yaml + clusterName: "acme-prod" # nhãn cho mỗi triển khai; xuất hiện trên mỗi cảnh báo + enablePrometheusStack: false # cảnh báo crash pod chỉ; không có ngăn xếp số liệu + disableCloudRouting: true # gửi đến Slack trực tiếp, trong cụm + sinksConfig: + - slack_sink: + name: vendor_slack + slack_channel: "agenteye-fleet-health" + api_key: "REPLACE_WITH_SLACK_BOT_TOKEN" # xoxb-… (ưu tiên --set hoặc secret) + scope: + include: + - namespace: [agenteye] # chỉ cảnh báo không gian tên AgentEye; loại bỏ để mở rộng + ``` + +3. Cài đặt, ghim `--version` vào một bản phát hành biểu đồ Robusta đã được kiểm tra + ([releases](https://github.com/robusta-dev/robusta/releases)) để bạn không bao giờ + cài đặt một biểu đồ chưa được kiểm tra: + + ```bash + helm install robusta robusta/robusta \ + --namespace robusta --create-namespace \ + --version \ + -f values.yaml \ + --set sinksConfig[0].slack_sink.api_key=$ROBUSTA_SLACK_TOKEN + ``` + +### Những gì nó báo cáo + +- **Trạng thái pod** Kubernetes (pod AgentEye nào bị lỗi và tại sao) và **tag hình ảnh** của mỗi pod, tức là **phiên bản** thành phần đang chạy. +- **Không có dữ liệu sự kiện AgentEye và không có dữ liệu khách hàng** bao giờ rời khỏi cụm. +- Các giá trị được đóng gói hạn chế cảnh báo vào **không gian tên `agenteye`**, vì vậy khối lượng công việc không liên quan trong cụm tương tự không được báo cáo. + +### Một nơi cho mỗi triển khai + +Trỏ Robusta của mỗi triển khai tới **một kênh Slack được chia sẻ duy nhất**, mỗi kênh có `clusterName` riêng của nó. Mỗi cảnh báo được gắn thẻ với nhãn đó, vì vậy một kênh duy nhất hiển thị sức khỏe của toàn bộ đội hình của bạn, và bạn có thể biết triển khai nào bị ảnh hưởng trong nháy mắt. + +### Các sự cố cụm toàn bộ + +Một người theo dõi trong cụm không thể báo cáo một **sự cố cụm toàn bộ hoặc mạng** (nó bị sự cố cùng với cụm). Nếu bạn cần điều đó, bật **Robusta UI sink** tùy chọn: đặt `disableCloudRouting: false` và thêm một `robusta_sink` (với mã token từ `robusta gen-config`) vào `sinksConfig`. Nó thêm một bảng điều khiển đa cụm tổng hợp và đánh dấu bất kỳ cụm nào ngừng kiểm tra. + +## Khắc phục sự cố + +Xem phần **Giám sát Sức khỏe** của +[enterprise-docs/troubleshooting.md](/vi/agenteye/troubleshooting) để xem "không có cảnh báo nào đến" và "máy chủ tiếp tục flap `NotReady`". \ No newline at end of file diff --git a/docs/vi/agenteye/kubernetes-deployment.mdx b/docs/vi/agenteye/kubernetes-deployment.mdx new file mode 100644 index 00000000..d4e12d2c --- /dev/null +++ b/docs/vi/agenteye/kubernetes-deployment.mdx @@ -0,0 +1,801 @@ +--- + +--- +title: "Hướng dẫn triển khai Kubernetes" +description: "Tài liệu hướng dẫn triển khai AgentEye trên Kubernetes." +--- + + +Hướng dẫn này triển khai toàn bộ ngăn xếp AgentEye lên một cụm Kubernetes chuyên dụng: + +- **ClickHouse 24.8** -- kho lưu trữ phân tích chính cho sự kiện và đánh giá (StatefulSet với khối lưu trữ bền vững 100Gi). Bắt buộc: máy chủ từ chối khởi động mà không có nó. +- **PostgreSQL 16** -- kho lưu trữ quan hệ/siêu dữ liệu cho tổ chức, khóa API, người dùng, bảng điều khiển, truy vấn đã lưu và xác thực (StatefulSet với khối lưu trữ bền vững 50Gi) +- **Redis 7.2** -- bộ nhớ đệm chia sẻ tùy chọn và phần phụ trợ giới hạn tốc độ; máy chủ và bảng điều khiển sẽ hoạt động bình thường nếu nó không khả dụng +- **AgentEye Server** -- API Rust để thu nhận sự kiện, phân tích và quản lý khóa (2 bản sao) +- **AgentEye Dashboard** -- UI web Next.js (2 bản sao) +- **AI assistant (dịch vụ agent)** -- trợ lý chỉ đọc tùy chọn trong bảng điều khiển trên cổng 9100; vô hoạt cho đến khi điểm cuối LLM được cấu hình +- **Traefik (công khai)** -- bộ điều khiển ingress cho lưu lượng trạm thu thập, được bảo vệ bằng mTLS +- **Traefik (bảng điều khiển)** -- bộ điều khiển ingress cho bảng điều khiển, chỉ VPN/danh sách cho phép IP +- **cert-manager** -- chứng chỉ TLS và CA mTLS +- **Backup CronJob** -- xả khoá hợp nhất hàng ngày của PostgreSQL + ClickHouse lúc 03:00 UTC +- **Cert Renewal Monitor** -- cảnh báo khi chứng chỉ khách hàng sắp hết hạn + +**Thời gian ước tính:** 60–90 phút cho lần triển khai đầu tiên. + +Đối với mô hình triển khai được quản lý mà Exosphere xử lý tất cả các điều này thay bạn, hãy xem [enterprise-docs/managed-deployment.md](/vi/agenteye/managed-deployment). + +--- + +## Điều kiện tiên quyết + +Chạy từng lệnh xác minh trước khi bắt đầu. Mọi kiểm tra phải vượt qua. + +| Yêu cầu | Tối thiểu | Lệnh xác minh | Kết quả dự kiến | +|---|---|---|---| +| Cụm Kubernetes | 1.27+ | `kubectl version` | Server Version >= v1.27 | +| Kustomize (được đóng gói với kubectl) | Kustomize v1.14+ (được đóng gói trong kubectl 1.27+) | `kubectl kustomize --help` | In ra văn bản sử dụng | +| Helm | v3 | `helm version` | `Version:"v3.x.x"` | +| RBAC cluster-admin | -- | `kubectl auth can-i create namespaces` | `yes` | +| StorageClass mặc định | -- | `kubectl get storageclass` | Ít nhất một hàng được đánh dấu `(default)` | +| Hỗ trợ LoadBalancer | -- | Phụ thuộc vào đám mây (EKS, GKE, AKS đều hỗ trợ theo mặc định) | -- | +| GitHub PAT | -- | `echo $AGENTEYE_TOKEN` | Không trống (xem [enterprise-docs/github-token.md](/vi/agenteye/github-token)) | +| openssl | -- | `openssl version` | OpenSSL 1.x hoặc 3.x | +| Bộ lưu trữ cloud | -- | Dành cho sao lưu PostgreSQL + ClickHouse (S3, GCS hoặc Azure Blob) | -- | + +**Kích thước cụm:** Tối thiểu 3 nút, mỗi nút 4 vCPU / 8 GB RAM. Xem [enterprise-docs/managed-deployment.md](/vi/agenteye/managed-deployment) để xem yêu cầu đầy đủ. + +### Chạy tất cả các kiểm tra cùng một lúc + +```bash +echo "--- Prerequisites Check ---" +kubectl version --client -o yaml 2>/dev/null | grep -q gitVersion && echo "PASS: kubectl" || echo "FAIL: kubectl not found" +helm version --short 2>/dev/null | grep -q v3 && echo "PASS: helm v3" || echo "FAIL: helm v3 not found" +kubectl auth can-i create namespaces 2>/dev/null | grep -q yes && echo "PASS: cluster-admin" || echo "FAIL: no cluster-admin" +kubectl get storageclass 2>/dev/null | grep -q default && echo "PASS: default StorageClass" || echo "FAIL: no default StorageClass" +[ -n "$AGENTEYE_TOKEN" ] && echo "PASS: AGENTEYE_TOKEN set" || echo "FAIL: AGENTEYE_TOKEN not set" +openssl version >/dev/null 2>&1 && echo "PASS: openssl" || echo "FAIL: openssl not found" +echo "---" +``` + +### Hình dạng triển khai + +**Điểm cuối tiêu thụ** được phục vụ trên tên máy chủ mà bạn kiểm soát (ví dụ: `ingest.your-company.example`). cert-manager yêu cầu chứng chỉ TLS được tin cậy công khai từ Let's Encrypt qua HTTP-01, vì vậy trạm thu thập sẽ xác minh chứng chỉ máy chủ so với kho tin cậy hệ thống, không cần ghim CA theo khách hàng. + +**Điểm cuối bảng điều khiển** hoạt động theo cách tương tự: nó được phục vụ trên tên máy chủ thứ hai mà bạn kiểm soát (ví dụ: `agenteye.your-company.example`) chỉ đến bộ cân bằng tải Traefik bảng điều khiển, và cert-manager phát hành chứng chỉ Let's Encrypt của nó qua bộ cân bằng tải đó. Các trình duyệt nhận được chứng chỉ được tin cậy mà không có cảnh báo. + +> **Cấp phát và gia hạn chứng chỉ xác thực qua HTTP-01**, vì vậy cả hai LoadBalancer phải có thể truy cập được từ Internet công khai trên cổng 80. Nếu bạn cần hạn chế IP cho bộ cân bằng tải bảng điều khiển, hãy phối hợp trình giải quyết DNS-01 với hỗ trợ trước — nếu không, việc gia hạn sẽ thất bại im lặng và chứng chỉ hết hạn. + +--- + +## Lấy các tệp kê khai + +```bash +git clone https://x:${AGENTEYE_TOKEN}@github.com/agenteye-enterprise/releases.git +cd releases/deploy +``` + +**Kiểm tra nó:** + +```bash +ls base/kustomization.yaml +``` + +Kết quả dự kiến: tệp tồn tại. Nếu không, bản sao đã thất bại -- kiểm tra `AGENTEYE_TOKEN` của bạn. + +**Cấu trúc thư mục:** + +``` +deploy/ + base/ Cơ sở Kustomize chia sẻ (tất cả tài nguyên K8s) + overlays/ Ghi đè cụ thể cụm (thẻ hình ảnh, tên máy chủ, tài nguyên) + third-party/ Giá trị Helm cho Traefik, cert-manager và (tùy chọn) giám sát sức khỏe Robusta +``` + +**base** chứa mọi tài nguyên cần thiết cho triển khai đầy đủ, bao gồm chứng chỉ Let's Encrypt cho hai tên máy chủ công khai mà bạn cấu hình trong Giai đoạn 3.1. **overlay** sửa chữa cơ sở cho một môi trường cụ thể (ví dụ: thẻ hình ảnh tùy chỉnh, giới hạn tài nguyên, dây nối env). Thư mục **third-party** chứa các tệp giá trị Helm cho cơ sở hạ tầng bên ngoài. + +> **Giám sát sức khỏe (tùy chọn):** bộ thăm dò sẵn sàng của máy chủ đã phản ánh sức khỏe Postgres + ClickHouse, và `third-party/robusta/` thêm cảnh báo lỗi pod gốc Kubernetes tùy chọn cho Slack. Xem [enterprise-docs/health-monitoring.md](/vi/agenteye/health-monitoring). + +--- + +## Giai đoạn 1 -- Cơ sở hạ tầng bên thứ ba (~30 phút) + +### 1.1 Cài đặt cert-manager + +cert-manager quản lý chứng chỉ TLS cho HTTPS và CA riêng được sử dụng cho chứng chỉ khách hàng mTLS. + +```bash +helm repo add jetstack https://charts.jetstack.io +helm repo update + +helm install cert-manager jetstack/cert-manager \ + --namespace cert-manager --create-namespace \ + --set crds.install=true +``` + +**Kiểm tra nó:** + +```bash +kubectl get pods -n cert-manager +``` + +Kết quả dự kiến: 3 pod đều `Running` -- `cert-manager`, `cert-manager-cainjector`, `cert-manager-webhook`. + +```bash +kubectl get crds | grep cert-manager +``` + +Kết quả dự kiến: ít nhất `certificates.cert-manager.io`, `clusterissuers.cert-manager.io`, `issuers.cert-manager.io`. + +**Nếu nó không thành công:** Pod ở `CrashLoopBackOff` thường có nghĩa là CRD không được cài đặt. Chạy lại với `--set crds.install=true`. Nếu pod webhook không thành công trong kiểm tra sẵn sàng, chờ 30 giây và kiểm tra lại -- chúng có thể mất một chút thời gian để khởi động. + +--- + +### 1.2 Cài đặt Traefik -- Bộ điều khiển tiêu thụ công khai + +Thực thể Traefik này xử lý lưu lượng trạm thu thập trên LoadBalancer **bên ngoài**. Nó chấm dứt TLS và thực thi mTLS (xác minh chứng chỉ khách hàng) trên điểm cuối tiêu thụ. + +```bash +helm repo add traefik https://traefik.github.io/charts +helm repo update + +helm install traefik-public traefik/traefik \ + --namespace traefik-public --create-namespace \ + --version 39.0.8 \ + -f third-party/traefik/values-public.yaml +``` + +**Kiểm tra nó:** + +```bash +kubectl get pods -n traefik-public +``` + +Kết quả dự kiến: 1 pod `Running`. + +```bash +kubectl get ingressclass traefik-public +``` + +Kết quả dự kiến: IngressClass tồn tại (nó không phải là lớp mặc định). + +**Nếu nó không thành công:** Kiểm tra `kubectl describe pod -n traefik-public ` để xem lỗi kéo hình ảnh hoặc ràng buộc tài nguyên. + +--- + +### 1.3 Cài đặt Traefik -- Bộ điều khiển bảng điều khiển + +Thực thể Traefik này phục vụ bảng điều khiển trên LoadBalancer chuyên dụng, bị hạn chế bởi danh sách cho phép IP. + +> **Hai cơ chế danh sách cho phép được cung cấp cho thực thể này.** Hướng dẫn này sử dụng `values-dashboard.yaml`, giới hạn quyền truy cập bằng trường `service.loadBalancerSourceRanges` di động. Một `values-internal.yaml` song song cũng được cung cấp cho các môi trường AWS thích chú thích `service.beta.kubernetes.io/aws-load-balancer-source-ranges` thay thế. Chọn một và sử dụng nó một cách nhất quán; các bước dưới đây giả định `values-dashboard.yaml`. + +**Trước khi cài đặt**, hãy chỉnh sửa `third-party/traefik/values-dashboard.yaml` để đặt các IP nguồn được phép. Trường `loadBalancerSourceRanges` kiểm soát IP nào có thể truy cập bảng điều khiển. Theo mặc định, nó được đặt thành `0.0.0.0/0` (tất cả IP); hạn chế nó thành VPN, văn phòng hoặc IP xuất hiện đã biết của bạn. + +#### Danh sách cho phép một IP duy nhất + +```yaml +service: + loadBalancerSourceRanges: + - "/32" +``` + +#### Danh sách cho phép nhiều IP + +Thêm một mục trên mỗi IP hoặc khối CIDR. Hậu tố `/32` khớp với một địa chỉ IPv4 duy nhất; một khối CIDR (ví dụ: `/24`) khớp với một phạm vi. Bạn có thể trộn các IP riêng lẻ và phạm vi tự do: + +```yaml +service: + loadBalancerSourceRanges: + - "203.0.113.10/32" # cổng văn phòng + - "203.0.113.11/32" # cổng văn phòng dự phòng + - "198.51.100.0/24" # bộ VPN + - "192.0.2.50/32" # IP nhà kỹ sư trực +``` + +Mẹo khi duy trì danh sách: + +- Giữ một mục trên mỗi dòng và thêm một bình luận `#` ngắn để xác định chủ sở hữu hoặc mục đích của mỗi IP; đây là những gì các nhà khai thác trong tương lai sử dụng để quyết định xem mục nhập còn cần thiết hay không. +- Luôn sử dụng ký hiệu CIDR. Một IP trần như `203.0.113.10` bị nhà cung cấp đám mây từ chối; hãy sử dụng `203.0.113.10/32`. +- Đối với các phạm vi IPv6, hãy sử dụng CIDR tương đương `/128` (địa chỉ duy nhất) hoặc lớn hơn, ví dụ: `2001:db8::1/128`. Không phải tất cả các nhà cung cấp đám mây đều hỗ trợ phạm vi nguồn IPv6; kiểm tra tài liệu LoadBalancer của nhà cung cấp của bạn. +- Danh sách là **HOẶC**: lưu lượng được phép nếu nguồn khớp với bất kỳ mục nhập nào. + +Sau khi chỉnh sửa tệp, tiếp tục với `helm install` dưới đây. Nếu bộ điều khiển đã được cài đặt, hãy chạy `helm upgrade` với các cờ tương tự hoặc vá Service lúc chạy (phần tiếp theo). + +#### Cập nhật danh sách cho phép lúc chạy + +Bạn có thể thay đổi các IP được phép mà không cần nâng cấp Helm bằng cách vá Service trực tiếp. **Bản vá thay thế toàn bộ danh sách**; luôn bao gồm mọi IP bạn muốn giữ, không chỉ cái mới. + +Để thay thế danh sách bằng một bộ IP mới: + +```bash +kubectl patch svc traefik-dashboard -n traefik-dashboard \ + -p '{"spec":{"loadBalancerSourceRanges":["203.0.113.10/32","198.51.100.0/24","192.0.2.50/32"]}}' +``` + +Để an toàn **thêm** một IP mà không mất các mục nhập hiện có, trước tiên hãy đọc danh sách hiện tại, sau đó vá bằng bộ kết hợp: + +```bash +# 1. Hiển thị danh sách cho phép hiện tại +kubectl get svc traefik-dashboard -n traefik-dashboard \ + -o jsonpath='{.spec.loadBalancerSourceRanges}' + +# 2. Vá bằng danh sách đầy đủ bao gồm IP mới +kubectl patch svc traefik-dashboard -n traefik-dashboard \ + -p '{"spec":{"loadBalancerSourceRanges":["/32","/32","/32"]}}' +``` + +> Các bản vá lúc chạy không được giữ lại trong `values-dashboard.yaml`. Để giữ thay đổi trong các nâng cấp Helm trong tương lai, cũng cập nhật tệp giá trị và cam kết nó. + +Sau đó, cài đặt: + +```bash +helm install traefik-dashboard traefik/traefik \ + --namespace traefik-dashboard --create-namespace \ + --version 39.0.8 \ + -f third-party/traefik/values-dashboard.yaml +``` + +**Kiểm tra nó:** + +```bash +kubectl get pods -n traefik-dashboard +``` + +Kết quả dự kiến: 1 pod `Running`. + +```bash +kubectl get ingressclass traefik-dashboard +``` + +Kết quả dự kiến: IngressClass tồn tại. + +--- + +### 1.4 Chờ LoadBalancer + +Cả hai thực thể Traefik đều cần các IP bên ngoài trước khi tiếp tục. + +```bash +kubectl get svc -n traefik-public +kubectl get svc -n traefik-dashboard +``` + +**Kiểm tra nó:** Cả hai dịch vụ đều hiển thị một `EXTERNAL-IP` (không phải ``). + +Nếu vẫn chưa giải quyết, hãy theo dõi phân công: + +```bash +kubectl get svc -n traefik-public -w +``` + +Nhấn `Ctrl+C` sau khi IP xuất hiện. Phân công IP thường mất 2–5 phút. + +**Nếu nó không thành công:** `` sau 10 phút thường có nghĩa là nhà cung cấp đám mây không thể cấp phát LoadBalancer. Kiểm tra: thẻ con nít (EKS yêu cầu `kubernetes.io/role/elb`), cấu hình VPC, hạn ngạch dịch vụ và chú thích LB nội bộ chính xác được đặt cho thực thể nội bộ. + +--- + +## Giai đoạn 2 -- Tạo bí mật (~10 phút) + +Tất cả các bí mật được tạo thủ công trước khi triển khai ứng dụng. Điều này đảm bảo các giá trị nhạy cảm không bao giờ xuất hiện trong các tệp kê khai. + +### 2.1 Tạo không gian tên + +```bash +kubectl create namespace agenteye +``` + +**Kiểm tra nó:** + +```bash +kubectl get namespace agenteye +``` + +Kết quả dự kiến: trạng thái `Active`. + +--- + +### 2.2 Bí mật kéo hình ảnh + +Bí mật này xác thực với `ghcr.io` để kéo các hình ảnh vùng chứa AgentEye. Xem [enterprise-docs/github-token.md](/vi/agenteye/github-token) để biết cách tạo PAT của bạn. + +```bash +kubectl create secret docker-registry agenteye-image-pull \ + --namespace agenteye \ + --docker-server=ghcr.io \ + --docker-username=agenteye-enterprise \ + --docker-password="${AGENTEYE_TOKEN}" +``` + +**Kiểm tra nó:** + +```bash +kubectl get secret agenteye-image-pull -n agenteye -o jsonpath='{.type}' +``` + +Kết quả dự kiến: `kubernetes.io/dockerconfigjson`. + +**Kiểm tra nó (sâu)** -- xác minh mã thông báo có thể thực sự kéo hình ảnh không: + +Sử dụng thẻ hình ảnh `server` được ghim trong kustomization.yaml của overlay của bạn (hiện đang `v0.0.1-beta.48` trong cả lớp phủ `acme` được đóng gói và triển khai cơ sở). Thay thế thẻ bên dưới bằng thẻ bạn đang triển khai để kiểm tra này không trôi dạt qua các bản phát hành: + +```bash +kubectl run test-pull \ + --image=ghcr.io/agenteye-enterprise/server:v0.0.1-beta.48 \ + --overrides='{"spec":{"imagePullSecrets":[{"name":"agenteye-image-pull"}]}}' \ + --restart=Never -n agenteye --command -- echo ok + +# Chờ một vài giây để kéo, sau đó: +kubectl logs test-pull -n agenteye +kubectl delete pod test-pull -n agenteye +``` + +Kết quả dự kiến: `ok` in trong nhật ký. + +**Nếu nó không thành công:** `ErrImagePull` hoặc `401 Unauthorized` có nghĩa là PAT không hợp lệ hoặc thiếu phạm vi `read:packages`. Kiểm tra lại [enterprise-docs/github-token.md](/vi/agenteye/github-token). + +--- + +### 2.3 Thông tin đăng nhập PostgreSQL + +```bash +POSTGRES_PASSWORD=$(openssl rand -hex 24) + +kubectl create secret generic agenteye-postgres \ + --namespace agenteye \ + --from-literal=POSTGRES_USER=postgres \ + --from-literal=POSTGRES_PASSWORD="${POSTGRES_PASSWORD}" \ + --from-literal=POSTGRES_DB=agenteye +``` + +> **Quan trọng:** Chúng tôi sử dụng `-hex` (không phải `-base64`) để tạo mật khẩu. Đầu ra Base64 có thể chứa `+`, `/` và `=` khiến chuỗi kết nối `DATABASE_URL` bị hỏng. Xem [enterprise-docs/troubleshooting.md](/vi/agenteye/troubleshooting) để biết chi tiết. + +> **Lưu trữ `POSTGRES_PASSWORD` trong trình quản lý bí mật của bạn ngay lập tức.** Bạn sẽ cần nó nếu bạn bao giờ khôi phục từ bản sao lưu hoặc kết nối trực tiếp với cơ sở dữ liệu. + +**Kiểm tra nó:** + +```bash +kubectl get secret agenteye-postgres -n agenteye +``` + +Kết quả dự kiến: bí mật tồn tại. + +```bash +kubectl get secret agenteye-postgres -n agenteye \ + -o jsonpath='{.data.POSTGRES_PASSWORD}' | base64 -d | wc -c +``` + +Kết quả dự kiến: `48` (24 byte hex = 48 ký tự). + +--- + +### 2.4 Khóa API quản trị + +```bash +ADMIN_KEY=$(openssl rand -hex 32) + +kubectl create secret generic agenteye-admin-key \ + --namespace agenteye \ + --from-literal=ADMIN_KEY="${ADMIN_KEY}" +``` + +Khóa quản trị là thông tin đăng nhập bootstrap. Máy chủ upserts nó ở mỗi lần khởi động với tất cả các quyền. Sử dụng nó để tạo khóa trạm thu thập được xác định phạm vi trong Giai đoạn 7. Xem [enterprise-docs/api-keys.md](/vi/agenteye/api-keys) để xem mô hình quyền đầy đủ. + +> **Lưu trữ `ADMIN_KEY` trong trình quản lý bí mật của bạn ngay lập tức.** + +**Kiểm tra nó:** + +```bash +kubectl get secret agenteye-admin-key -n agenteye +``` + +Kết quả dự kiến: bí mật tồn tại. + +--- + +### 2.5 Cấu hình xác thực (đăng nhập bảng điều khiển) + +Bảng điều khiển sử dụng email + OTP cho đăng nhập người dùng. Nếu không có bí mật này, máy chủ vẫn khởi động và đường dẫn API `ADMIN_KEY` tiếp tục hoạt động, nhưng **không có người dùng nào có thể đăng nhập thông qua UI**. + +Tất cả các khóa được tham chiếu là `optional: true` trong bản kê khai cơ sở, vì vậy các bí mật riêng phần (hoặc không có bí mật nào cả) là được; máy chủ quay lại các giá trị mặc định được ghi chép. Gói mọi thứ vào một bí mật `agenteye-auth` duy nhất giúp bề mặt xác thực có thể xoay trong một địa điểm. + +```bash +kubectl create secret generic agenteye-auth \ + --namespace agenteye \ + --from-literal=ADMIN_EMAIL="admin@yourcompany.com" \ + --from-literal=ALLOWED_EMAILS="*@yourcompany.com" \ + --from-literal=SMTP_HOST="smtp.yourprovider.com" \ + --from-literal=SMTP_PORT="587" \ + --from-literal=SMTP_USERNAME="your-smtp-user" \ + --from-literal=SMTP_PASSWORD="your-smtp-password" \ + --from-literal=SMTP_FROM="noreply@yourcompany.com" \ + --from-literal=SMTP_TLS="starttls" \ + --from-literal=DEFAULT_ORG_NAME="Acme Corp" \ + --from-literal=DEFAULT_ORG_SLUG="acme" +``` + +| Khóa | Mục đích | +|---|---| +| `ADMIN_EMAIL` | Người dùng quản trị bootstrap. Upserted ở mỗi lần khởi động với tất cả các quyền và được bảo vệ khỏi xóa/chỉnh sửa quyền thông qua bảng điều khiển. Nếu không có nó, không có quản trị viên nào được gieo và đăng nhập đầu tiên là không thể. | +| `ALLOWED_EMAILS` | Danh sách cho phép được phân tách bằng dấu phẩy. Hỗ trợ địa chỉ chính xác (`user@example.com`) và ký tự đại diện miền (`*@example.com`). Nếu không có nó, **không có người dùng nào có thể đăng nhập hoặc được tạo**. | +| `SMTP_HOST`, `SMTP_PORT`, `SMTP_USERNAME`, `SMTP_PASSWORD`, `SMTP_FROM` | Bộ chuyển tiếp SMTP để gửi mã OTP. Nếu `SMTP_HOST` không được đặt, các mã OTP sẽ được ghi vào stdout của máy chủ thay vì được gửi qua email (hữu ích cho các bài kiểm tra khởi động). Cung cấp tất cả các khóa SMTP cùng nhau để gửi email thực. | +| `SMTP_TLS` | Một trong `starttls` (mặc định), `tls` hoặc `none`. | +| `DEFAULT_ORG_NAME`, `DEFAULT_ORG_SLUG` | Tùy chọn. Đặt cho tổ chức `default` được xây dựng sẵn tên hiển thị thân thiện và slug URL để nó sống ở ví dụ `/acme` thay vì `/default`. Được áp dụng chỉ **trên lần khởi động đầu tiên**; khi bạn đổi tên tổ chức bằng `agenteye-orgctl org rename` (xem §7.6) những cái này bị bỏ qua. Slug phải là 1–40 chữ cái thường alphanumerics có gạch ngang nội bộ duy nhất. Để trống cả hai để giữ `default` chung chung. | + +> **Lưu trữ thông tin xác thực SMTP trong trình quản lý bí mật của bạn.** + +**Kiểm tra nó:** + +```bash +kubectl get secret agenteye-auth -n agenteye \ + -o jsonpath='{.data}' | grep -o '"[A-Z_]*"' | sort -u +``` + +Kết quả dự kiến: các khóa bạn điền xuất hiện trong đầu ra. + +--- + +### 2.6 Khóa cô lập tổ chức đa người thuê (tùy chọn) + +Bỏ qua điều này đối với triển khai một người thuê; máy chủ chạy trên một tổ chức mặc định phát triển được xây dựng sẵn và phục vụ tổ chức `default` duy nhất một cách tốt. **Trước khi bạn tạo tổ chức thứ hai**, hãy đặt một `ORG_CH_SECRET` mạnh, ổn định: mật khẩu ClickHouse của mỗi tổ chức được dẫn xuất dưới dạng `HMAC(ORG_CH_SECRET, org_id)`, vì vậy mặc định phát triển được biết công khai sẽ mang lại thông tin xác thực theo tổ chức được dẫn xuất công khai. Lệnh `agenteye-orgctl org create` (xem [§7.6 Cấp phát các tổ chức](#76-provision-organizations-multi-tenant)) từ chối chạy trong khi máy chủ vẫn ở mặc định phát triển được xây dựng sẵn. + +```bash +kubectl create secret generic agenteye-org-ch-secret \ + --namespace agenteye \ + --from-literal=ORG_CH_SECRET="$(openssl rand -base64 48)" + +# Khởi động lại máy chủ để nó nhận giá trị mới. +kubectl -n agenteye rollout restart deployment/server +``` + +Máy chủ đọc điều này qua một **optional** `secretKeyRef`, vì vậy một cụm một người thuê không bao giờ tạo nó vẫn khởi động bình thường. Giữ giá trị **ổn định và giống nhau trên tất cả các bản sao**; quay nó vô hiệu hóa mật khẩu ClickHouse được dẫn xuất của mỗi tổ chức cho đến khi khởi động lại khỏi mục tiêu cấu hình lại các người dùng (một khởi động động với giá trị nhất quán ở khắp nơi chữa nó). Xem `deploy/base/server/secret.example.yaml`. + +> **Lưu trữ `ORG_CH_SECRET` trong trình quản lý bí mật của bạn và đừng quay nó một cách tùy tiện.** + +--- + +### 2.7 Xác minh tất cả các bí mật + +```bash +kubectl get secrets -n agenteye -o custom-columns='NAME:.metadata.name,TYPE:.type' +``` + +Đầu ra dự kiến (trong số bất kỳ bí mật mặc định nào): + +``` +NAME TYPE +agenteye-admin-key Opaque +agenteye-auth Opaque +agenteye-image-pull kubernetes.io/dockerconfigjson +agenteye-postgres Opaque +agenteye-org-ch-secret Opaque # chỉ nếu bạn hoàn thành §2.6 (đa người thuê) +``` + +Bốn bí mật cốt lõi (`agenteye-admin-key`, `agenteye-auth`, `agenteye-image-pull`, `agenteye-postgres`) phải có mặt trước khi tiếp tục. `agenteye-org-ch-secret` chỉ bắt buộc đối với triển khai đa người thuê (xem §2.6). + +--- + +## Giai đoạn 3 -- Triển khai ứng dụng (~5 phút) + +### 3.1 Cấu hình các tên máy chủ công khai + +cert-manager cần các tên máy chủ tiêu thụ và bảng điều khiển trước khi nó có thể yêu cầu chứng chỉ Let's Encrypt của họ. Sao chép mẫu và đặt cả hai: + +```bash +cp base/certificates/domain.env.example base/certificates/domain.env +# Chỉnh sửa base/certificates/domain.env và đặt: +# INGEST_DOMAIN=ingest.your-company.example (phân giải thành LB Traefik công khai) +# DASHBOARD_DOMAIN=agenteye.your-company.example (phân giải thành LB Traefik bảng điều khiển) +``` + +`domain.env` được gitignored; nó ở địa phương cho mỗi triển khai. Xây dựng kustomize không thành công ồn ào nếu khóa nào bị thiếu. + +> **DNS phải phân giải trước tiên.** Bạn không phải chỉ định DNS tại LB ngay bây giờ (chúng không tồn tại cho đến khi Giai đoạn 1.2 hoàn thành), nhưng cấp phát ACME ở bước 3.2 sẽ thử lại cho đến khi mỗi tên máy chủ phân giải thành LoadBalancer của nó. Bạn có thể đặt DNS ngay bây giờ (sử dụng tên máy chủ LB được nắm bắt trong Giai đoạn 1.4) hoặc tiếp tục và thêm các bản ghi trong Giai đoạn 4. + +--- + +### 3.2 Áp dụng bản kê khai + +Áp dụng cơ sở trực tiếp để cài đặt mới hoặc lớp phủ nếu bạn đã cắt một cho môi trường này (lớp phủ chỉ ghim các thẻ hình ảnh, biến env và giới hạn tài nguyên; chúng kế thừa chứng chỉ và định tuyến cơ sở): + +```bash +kubectl apply -k base/ +# hoặc +kubectl apply -k overlays// +``` + +Lớp phủ bao gồm cơ sở tự động; áp dụng một, không phải cả hai. + +--- + +### 3.3 Chờ các pod + +```bash +kubectl wait --for=condition=Ready pod -l 'app in (server,dashboard,postgres,clickhouse)' \ + -n agenteye --timeout=180s +``` + +Chờ được phạm vi cho các pod mặt phẳng dữ liệu cốt lõi. Pod `agent` (trợ lý AI) và `redis` tùy chọn xuất hiện bên cạnh chúng; trợ lý ở vô hoạt cho đến khi bạn cung cấp điểm cuối LLM của nó (xem [enterprise-docs/assistant.md](/vi/agenteye/assistant)), và Redis là bộ nhớ đệm tốt nhất, vì vậy không ai cần ở Sẵn sàng để nền tảng phục vụ lưu lượng truy cập. + +**Kiểm tra nó:** + +```bash +kubectl get pods -n agenteye +``` + +Kết quả dự kiến (pod `agent` và `redis` tùy chọn cũng xuất hiện và đạt `Running`): + +``` +NAME READY STATUS RESTARTS AGE +agent-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +clickhouse-0 1/1 Running 0 ... +dashboard-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +dashboard-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +postgres-0 1/1 Running 0 ... +redis-0 1/1 Running 0 ... +server-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +server-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +``` + +**Nếu nó không thành công:** + +| Trạng thái Pod | Nguyên nhân có thể | Lệnh gỡ lỗi | +|---|---|---| +| `ImagePullBackOff` | Bí mật kéo hình ảnh xấu hoặc PAT | `kubectl describe pod -n agenteye` | +| `CrashLoopBackOff` | Biến env xấu (ví dụ: DATABASE_URL) | `kubectl logs -n agenteye` | +| `Pending` | CPU/bộ nhớ không đủ hoặc không có nút | `kubectl describe pod -n agenteye` (kiểm tra Sự kiện) | + +--- + +### 3.4 Xác minh bộ lưu trữ + +```bash +kubectl get pvc -n agenteye +``` + +Kết quả dự kiến, cả hai có trạng thái `Bound`: + +| PVC | Dung lượng | Lưng | +|---|---|---| +| `postgres-data-postgres-0` | `50Gi` | Kho lưu trữ quan hệ/siêu dữ liệu PostgreSQL | +| `clickhouse-data-clickhouse-0` | `100Gi` | Kho lưu trữ phân tích sự kiện + đánh giá ClickHouse | + +Một PVC `redis-data-redis-0` (1Gi) cũng xuất hiện cho bộ nhớ đệm tùy chọn. + +**Nếu nó không thành công:** `Pending` có nghĩa là không có StorageClass nào có thể cấp phát khối lượng. Kiểm tra `kubectl get storageclass` và đảm bảo tồn tại một mặc định. Để sản xuất, lớp phủ khối lượng ClickHouse lên StorageClass SSD nhanh (ví dụ: gp3 trên AWS, pd-ssd trên GCP); thông lượng nén bị ảnh hưởng trên đĩa chậm. + +--- + +### 3.5 Xác minh chứng chỉ + +```bash +kubectl get certificates -n agenteye +``` + +Kết quả dự kiến: 3 chứng chỉ, tất cả `Ready: True`: + +| Tên | Công cộng | Mục đích | +|---|---|---| +| `mtls-ca` | `selfsigned` | CA riêng để phát hành chứng chỉ máy khách mTLS (hiệu lực 10 năm) | +| `ingest-tls` | `letsencrypt-prod` | Chứng chỉ TLS công khai cho điểm cuối tiêu thụ (90 ngày, tự động gia hạn) | +| `dashboard-tls` | `letsencrypt-prod` | Chứng chỉ TLS công khai cho bảng điều khiển (90 ngày, tự động gia hạn) | + +**Nếu `ingest-tls` hoặc `dashboard-tls` không sẵn sàng:** + +`kubectl describe certificate -n agenteye` và đọc Sự kiện. Các nguyên nhân phổ biến: + +- **DNS chưa chỉ đến LB.** Let's Encrypt phân giải tên máy chủ và nhấn cổng 80 để xác thực — `INGEST_DOMAIN` phải phân giải thành LB công khai, `DASHBOARD_DOMAIN` thành LB bảng điều khiển. Cho đến khi CNAME/Alias lan rộng, đơn đặt hàng vẫn `pending`. Khi DNS đúng, cert-manager thử lại tự động (không cần xóa Chứng chỉ). +- **Tên máy chủ không được thay thế.** Nếu `dnsNames` vẫn đọc `INGEST_DOMAIN_PLACEHOLDER` / `DASHBOARD_DOMAIN_PLACEHOLDER`, bạn đã bỏ qua bước 3.1 -- tạo `base/certificates/domain.env` và áp dụng lại. +- **Traefik bảng điều khiển không thể phục vụ thử thách** (`dashboard-tls` chỉ). Thực thể Traefik bảng điều khiển phải được cài đặt với tệp giá trị được đóng gói (Giai đoạn 1.2), điều này cho phép nhà cung cấp Ingress được xác định phạm vi phục vụ bộ giải quyết HTTP-01 của cert-manager. Một thực thể được cài đặt mà không có nó để thử thách không có tuyến đường và thứ tự `pending` mãi mãi. + +**Nếu `mtls-ca` không sẵn sàng:** cert-manager chính nó không khỏe. Kiểm tra lại các pod cert-manager từ bước 1.1. + +--- + +### 3.6 Xác minh CronJob + +```bash +kubectl get cronjobs -n agenteye +``` + +Kết quả dự kiến: + +| Tên | Lịch | Mục đích | +|---|---|---| +| `agenteye-backup` | `0 3 * * *` | Sao lưu Postgres + ClickHouse hàng ngày lúc 03:00 UTC | +| `cert-renewal-check` | `0 3,15 * * *` | Cảnh báo hết hạn chứng chỉ lúc 03:00 và 15:00 UTC | + +--- + +### 3.7 Xác minh máy chủ khởi động chính xác + +```bash +kubectl logs -n agenteye -l app=server --tail=20 +``` + +**Kiểm tra nó:** Tìm dòng khởi động cho biết máy chủ đang nghe trên cổng 8080. Không nên có lỗi kết nối cơ sở dữ liệu (máy chủ yêu cầu cả PostgreSQL và ClickHouse có thể truy cập được trước khi nó báo cáo Sẵn sàng). + +**Nếu nó không thành công:** Nguyên nhân phổ biến nhất là `POSTGRES_PASSWORD` chứa các ký tự không an toàn URL mà bảng `DATABASE_URL`. Xem [enterprise-docs/troubleshooting.md](/vi/agenteye/troubleshooting). + +--- + +### 3.8 Xác minh bảng điều khiển được kết nối với máy chủ + +```bash +kubectl logs -n agenteye -l app=dashboard --tail=20 +``` + +**Kiểm tra nó:** Tìm `Ready` trong đầu ra mà không có `ECONNREFUSED` hoặc các lỗi tương tự. + +**Nếu nó không thành công:** Kiểm tra rằng Dịch vụ `server` tồn tại (`kubectl get svc server -n agenteye`) và `AGENTEYE_SERVER_URL` được đặt thành `http://server:8080` trong triển khai bảng điều khiển. + +--- + +## Giai đoạn 4 -- Quyền truy cập mạng (~5 phút) + +### 4.1 Truy xuất địa chỉ LoadBalancer + +```bash +PUBLIC_IP=$(kubectl get svc -n traefik-public \ + -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') + +INTERNAL_IP=$(kubectl get svc -n traefik-dashboard \ + -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') +``` + +> Trên AWS EKS, LoadBalancer trả về tên máy chủ thay vì IP. Thay thế `.ip` bằng `.hostname` trong các lệnh trên. + +**Kiểm tra nó:** + +```bash +echo "Public (ingest): $PUBLIC_IP" +echo "Internal (dashboard): $INTERNAL_IP" +``` + +Cả hai phải không trống. + +--- + +### 4.2 Trỏ DNS tại LoadBalancer + +Tạo bản ghi DNS để các tên máy chủ từ `base/certificates/domain.env` phân giải thành LoadBalancer của họ — `INGEST_DOMAIN` thành LB Traefik **công khai**, `DASHBOARD_DOMAIN` thành LB Traefik **bảng điều khiển**: + +- **AWS Route 53:** Bản ghi `A` có `Alias = Yes`, mục tiêu = tên máy chủ LB. Đừng sử dụng A bình thường → IP; IP ELB xoay. +- **Bất kỳ nhà cung cấp nào khác:** `CNAME` từ tên máy chủ đến tên máy chủ LB. + +Xác minh: + +```bash +dig +short ingest.your-company.example +dig +short agenteye.your-company.example +``` + +Nên trả về cùng địa chỉ như `$PUBLIC_IP` và `$INTERNAL_IP` tương ứng (hoặc, trên EKS, phân giải thành cùng tên máy chủ `*.elb.amazonaws.com`). + +Khi DNS phân giải, cert-manager hoàn thành các đơn đặt hàng ACME chưa hoàn thành từ Giai đoạn 3.5 trong vòng một phút. Chạy lại `kubectl get certificates -n agenteye` cho đến khi cả `ingest-tls` và `dashboard-tls` hiển thị `Ready: True`. + +--- + +### 4.3 Tiếp cận điểm cuối tiêu thụ + +Điểm cuối tiêu thụ công khai thực thi TLS lẫn nhau, vì vậy mỗi yêu cầu (bao gồm `/health`) phải trình bày chứng chỉ khách hàng. Bạn phát hành chứng chỉ khách hàng đầu tiên của bạn trong Giai đoạn 5; nếu bạn đã có cái, hãy xác minh khả năng truy cập ngay bây giờ: + +```bash +curl -s --cert issued//client.crt \ + --key issued//client.key \ + https://ingest.your-company.example/health +``` + +Kết quả dự kiến: `{"status":"ok"}`. Không cần `-k` -- chứng chỉ máy chủ chuỗi đến CA công khai cho `INGEST_DOMAIN`, vì vậy nó xác thực so với kho tin cậy hệ thống. Tiếp cận điểm cuối tiêu thụ bằng tên máy chủ `INGEST_DOMAIN` của nó (khớp với chứng chỉ phát hành), không phải bởi IP/tên máy chủ LB thô. + +Điểm cuối bảng điều khiển được phục vụ trên `DASHBOARD_DOMAIN` có chứng chỉ được tin cậy công khai và không phải mTLS, vì vậy không cần `-k` và không cần chứng chỉ khách hàng: + +```bash +curl -s https://agenteye.your-company.example/ -o /dev/null -w '%{http_code}\n' +``` + +Tiếp cận bảng điều khiển bằng tên máy chủ của nó, không phải địa chỉ LB thô — chứng chỉ bị ràng buộc với `DASHBOARD_DOMAIN`, vì vậy địa chỉ thô hiển thị sự không khớp về tên chứng chỉ. + +**Nếu nó không thành công:** Nếu `curl` treo, kiểm tra rằng LB có thể truy cập được từ máy của bạn (VPN, nhóm bảo mật, quy tắc tường lửa). Lỗi bắt tay `certificate required` trên tên máy chủ tiêu thụ có nghĩa là không có chứng chỉ khách hàng được trình bày; hãy hoàn thành Giai đoạn 5 trước. Lỗi xác thực TLS trên tên máy chủ tiêu thụ có nghĩa là chứng chỉ máy chủ chưa hoàn thành phát hành; quay lại Giai đoạn 3.5 và giải quyết vấn đề ở đó. + +--- + +## Giai đoạn 5 -- Phát hành chứng chỉ khách hàng mTLS (~10 phút trên cụm) + +Trạm thu thập xác thực bằng **hai yếu tố**: chứng chỉ khách hàng (lớp vận tải, chứng minh yêu cầu đến từ một cụm được ủy quyền) và khóa API (lớp ứng dụng, chứng minh yêu cầu từ trạm thu thập có quyền `events:add`). Khóa rò rỉ vô dụng mà không có cert; cert bị đánh cắp vô dụng mà không có khóa hợp lệ. + +### 5.1 Phát hành chứng chỉ + +Mỗi cụm chạy trạm thu thập cần chứng chỉ khách hàng riêng của nó. Từ thư mục bản kê khai: + +```bash +cd base/certificates/client-certs +./issue-client-cert.sh +``` + +Thay thế `` bằng một định danh có ý nghĩa (ví dụ: `us-east-1-prod`, `staging`). + +**Kiểm tra nó:** Tập lệnh in `==> Done!` và liệt kê các tệp đầu ra. + +```bash +kubectl get certificate mtls-client- -n agenteye +``` + +Kết quả dự kiến: `Ready: True`. + +Tệp đầu ra trong `issued//`: + +| Tệp | Mục đích | +|---|---| +| `client.crt` | Chứng chỉ khách hàng (hiệu lực 90 ngày) | +| `client.key` | Khóa riêng máy khách | +| `ca.crt` | Chứng chỉ CA để xác minh máy chủ | +| `collector-mtls-secret.yaml` | Bí mật Kubernetes sẵn sàng áp dụng cho cụm trạm thu thập | + +--- + +### 5.1b Phương tiện thay thế: AWS Secrets Manager + +Nếu người tiêu dùng cert là một Pod Kubernetes cần `client.crt` và `client.key` trên đĩa -- trường hợp điển hình khi bạn chạy trạm thu thập agenteye-collector dưới dạng sidecar trong pod ứng dụng của bạn -- đẩy bó cert vào AWS Secrets Manager. Pod ứng dụng sau đó gắn nó qua [Secrets Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/) với IRSA, và quay một vòng chứng chỉ hoàn toàn tự động. + +```bash +cd base/certificates/client-certs +export AWS_REGION=us-east-1 # khu vực nơi khối lượng công việc của bạn chạy +./issue-client-cert.sh --save-to aws-secrets-manager +``` + +Khi chạy lại (gia hạn), tập lệnh gọi `PutSecretValue` trên cùng một bí mật, vì vậy ARN và tên giữ ổn định. CSI Driver chọn phiên bản mới trên bộ xoay tiếp theo của nó và viết lại các tệp bên trong pod. + +**Điều kiện tiên quyết:** + +- `aws` CLI v2 được xác thực cho tài khoản AWS của bạn. +- `jq` cài đặt. +- Biến môi trường `AWS_REGION` được đặt. +- Quyền IAM trên danh tính người gọi của bạn (phạm vi `Resource` thành `arn:aws:secretsmanager:::secret:agenteye/mtls-client/*`): + - `secretsmanager:CreateSecret` + - `secretsmanager:DescribeSecret` + - `secretsmanager:PutSecretValue` + - `secretsmanager:TagResource` + +**Tập lệnh làm gì ở chế độ này:** + +| Bước | Hành động | +|---|---| +| 1 | Phát hành / tái trích xuất cert qua cert-manager (giống như chế độ mặc định). | +| 2 | Gọi `DescribeSecret` trên `agenteye/mtls-client/` để quyết định tạo vs cập nhật. | +| 3 | Trên lần chạy đầu tiên: `CreateSecret` với tải trọng JSON ba khóa (`client.crt`, `client.key`, `ca.crt`), được gắn thẻ `AgentEyeCluster=`. Trên các lần chạy tiếp theo: `PutSecretValue` để xuất bản phiên bản mới; thẻ làm mới qua `TagResource`. | +| 4 | Xóa `issued//` chỉ sau khi tải lên thành công. Khi có lỗi, thư mục được bảo tồn để bạn thử lại. | + +**Nếu bí mật được lên lịch xóa**, tập lệnh không thành công với lỗi rõ ràng yêu cầu bạn chạy `aws secretsmanager restore-secret --secret-id agenteye/mtls-client/` trước khi thử lại. + +Để dây toàn bộ pod (SecretProviderClass, thiết lập IRSA, hành vi quay một vòng, gỡ lỗi) xem [enterprise-docs/single-pod-deployment.md](/vi/agenteye/single-pod-deployment). + +--- + +### 5.2 Xác minh chứng chỉ hoạt động + +Kiểm tra chứng chỉ phát hành so với mTLS ingress: + +```bash +curl -sk --cert issued//client.crt \ + --key issued//client.key \ + https://${PUBLIC_IP}/health +``` + +Kết quả dự kiến: `{"status":"ok"}` + +**Nếu nó không thành công:** + +| Lỗi | Nguyên nhân | Khắc phục | +|---|---|---| +| `certificate required` | Cert không được trình bày | Kiểm tra đường dẫn tệp trong lệnh `curl` | +| `bad certificate` | Không khớp CA | Xác minh `mtls-ca-issuer` phát hành cert: `kubectl describe certificate mtls-client- -n agenteye` | +| `connection refused` | Tên máy chủ hoặc LB sai không có thể truy cập | Kiểm tra `/etc/hosts` hoặc DNS | + +--- + +### 5.3 Gửi tới cụm trạm thu thập + +Gửi `collector-mtls-secret.yaml` cho đội vận hành cụm trạm thu thập. Họ áp dụng nó: + +```bash +kubectl apply -f collector-mtls-secret.yaml -n +``` \ No newline at end of file diff --git a/docs/vi/agenteye/managed-deployment.mdx b/docs/vi/agenteye/managed-deployment.mdx new file mode 100644 index 00000000..1f7ff406 --- /dev/null +++ b/docs/vi/agenteye/managed-deployment.mdx @@ -0,0 +1,172 @@ +--- +--- +title: "Triển khai được quản lý trên Cluster Kubernetes của bạn" +description: "Tài liệu Triển khai được quản lý AgentEye trên Cluster Kubernetes của bạn." +--- + + +AgentEye là một nền tảng quan sát và đánh giá tự lưu trữ cho các agent AI và LLM. Nó ghi lại các phiên làm việc của agent, các lệnh gọi công cụ, yêu cầu mô hình và lỗi, chuyển chúng thành phân tích và đánh giá có thể tìm kiếm, và hiển thị kết quả trên bảng điều khiển với trợ lý AI chỉ đọc tùy chọn. + +Trong mô hình triển khai được quản lý, bạn cung cấp một cluster Kubernetes chuyên dụng và Exosphere chạy toàn bộ nền tảng bên trong nó, triển khai, định cấu hình, vận hành, sao lưu và nâng cấp từng thành phần thay bạn. Nhóm của bạn nhận được giá trị của nền tảng (khả năng hiển thị agent, phân tích, đánh giá và trợ lý tùy chọn) mà không cần vận hành cơ sở dữ liệu, chứng chỉ hoặc nâng cấp. Tất cả dữ liệu được lưu giữ trong tài khoản đám mây của bạn. + +--- + +## Điều kiện tiên quyết + +- Một **GitHub PAT** để kéo các image container và tải xuống các artifact (xem [GitHub Token Setup](/vi/agenteye/github-token)) +- Một **cluster Kubernetes chuyên dụng** (xem yêu cầu bên dưới) +- Một **storage bucket** cho sao lưu cơ sở dữ liệu +- **Kết nối mạng**: cổng 443 đến bộ cân bằng tải của cluster + +--- + +## Bước 1: Cấp phát Cluster Kubernetes chuyên dụng + +Tạo một cluster Kubernetes dành riêng cho AgentEye. Nó không nên được chia sẻ với các khối công việc khác, vì vậy toàn bộ nền tảng (dịch vụ ứng dụng, cơ sở dữ liệu, phân tích và bộ nhớ đệm) chạy trong sự cô lập mà không ảnh hưởng đến cơ sở hạ tầng hiện có của bạn. + +| Yêu cầu | Chi tiết | +|---|---| +| **Phân phối** | Bất kỳ Kubernetes nào tuân thủ: EKS, GKE, AKS hoặc tự quản lý | +| **Phiên bản** | 1.27 hoặc mới hơn | +| **Nhóm nút** | Tối thiểu: **3 nút, 4 vCPU / 8 GB RAM mỗi cái** (các instance mục đích chung tiêu chuẩn) | +| **Lưu trữ** | StorageClass mặc định cấp phát các khối lượng khối (ví dụ: `gp3` trên AWS, `pd-ssd` trên GCP) | +| **Bộ cân bằng tải** | Cluster phải có khả năng cấp phát các dịch vụ LoadBalancer trên đám mây (mặc định trên EKS, GKE, AKS) | + +> Exosphere cài đặt và quản lý mọi thứ khác bên trong cluster: bộ điều khiển ingress, chứng chỉ TLS, cơ sở dữ liệu, bộ nhớ đệm, giám sát và tất cả các triển khai ứng dụng. + +--- + +## Bước 2: Cấp quyền truy cập cho Nhóm AgentEye + +Exosphere cần quyền truy cập cluster-admin (hoặc RBAC rộng tương đương) để quản lý các không gian tên, định nghĩa tài nguyên tùy chỉnh, bộ điều khiển ingress và các nhà cung cấp lưu trữ. + +| Yêu cầu | Chi tiết | +|---|---| +| **Phương pháp truy cập** | IAM role (ưu tiên cho EKS/GKE), kubeconfig hoặc truy cập dựa trên SSO | +| **VPN / bastion** | Nếu máy chủ API Kubernetes là riêng tư, cung cấp thông tin đăng nhập VPN hoặc truy cập bastion cho nhóm hoạt động Exosphere | + +--- + +## Bước 3: Định cấu hình Kết nối mạng + +Nhóm mạng của bạn cần cho phép lưu lượng đến trên **cổng 443** đến các bộ cân bằng tải của cluster. Triển khai chạy hai bộ cân bằng tải riêng biệt: một cho việc nhập sự kiện (bảo vệ bằng mTLS) và một cho bảng điều khiển: + +| Lưu lượng | Nguồn | Đích | Bảo mật | +|---|---|---|---| +| **Nhập sự kiện** | Pod bộ sưu tập trong các cluster của bạn | Ingress LoadBalancer, cổng 443 | mTLS (chứng chỉ máy khách) + khóa API | +| **Bảng điều khiển** | Trình duyệt nhà phát triển | Dashboard LoadBalancer, cổng 443 | HTTPS trên tên miền của bạn, đăng nhập OTP email không mật khẩu | + +Điểm cuối nhập được bảo vệ bằng mutual TLS; các bộ sưu tập phải trình bày một chứng chỉ máy khách hợp lệ **và** một khóa API hợp lệ trên mỗi yêu cầu. Bảng điều khiển chạy trên bộ cân bằng tải và tên máy chủ riêng của nó, với quyền truy cập bị hạn chế đối với các địa chỉ/tên miền email được phép. + +**Bản ghi DNS (một lần):** bạn tạo hai bản ghi CNAME trong một tên miền mà bạn kiểm soát - một cho điểm cuối nhập và một cho bảng điều khiển (ví dụ: `agenteye.your-company.example`) - trỏ đến các tên máy chủ bộ cân bằng tải mà Exosphere cung cấp. Exosphere sau đó cấp phát tự động các chứng chỉ TLS được tin cậy công khai cho cả hai tên máy chủ, bao gồm cả các lần gia hạn. + +> **Ghi chú cổng 80:** cấp phát chứng chỉ tự động và gia hạn xác thực qua HTTP trên cổng 80 của mỗi bộ cân bằng tải. Nếu tư thế bảo mật của bạn yêu cầu hạn chế bộ cân bằng tải bảng điều khiển đối với các dải IP công ty, hãy cho Exosphere biết trước - chúng tôi chuyển xác thực chứng chỉ thành phương pháp dựa trên DNS (một bản ghi DNS bổ sung ở phía bạn) để các lần gia hạn tiếp tục hoạt động phía sau hạn chế. + +> **Đi ra ngoài:** Các nút cluster cần quyền truy cập internet để kéo các image container từ `ghcr.io`. Nếu mạng của bạn hạn chế lưu lượng đi ra, hãy cho phép `ghcr.io` hoặc sao gương các image đến sổ đăng ký nội bộ của bạn. + +--- + +## Bước 4: Cung cấp Bucket Lưu trữ Sao lưu + +Sao lưu cơ sở dữ liệu được lưu trữ trong một bucket lưu trữ đám mây mà bạn sở hữu. + +| Yêu cầu | Chi tiết | +|---|---| +| **Dịch vụ** | S3 (AWS), GCS (GCP) hoặc Azure Blob Storage | +| **Truy cập** | Cấp quyền truy cập ghi cho các nút cluster thông qua IAM role cho các tài khoản dịch vụ (IRSA trên EKS, Workload Identity trên GKE) hoặc cung cấp thông tin đăng nhập | +| **Giữ lại** | Bạn kiểm soát chính sách vòng đời của bucket (khoảng thời gian giữ lại, quy tắc lưu trữ). Exosphere ghi sao lưu; bạn quyết định thời gian giữ chúng | + +Một sao lưu hàng ngày duy nhất xả cả PostgreSQL (trạng thái quan hệ) và ClickHouse (sự kiện và đánh giá) vào một kho lưu trữ nén và tải nó lên bucket của bạn. Sao lưu cũng chạy trước mỗi lần nâng cấp. + +--- + +## Bước 5: Chỉ định một Người liên hệ + +Cung cấp một người hoặc kênh Slack/Teams ở phía bạn cho các vấn đề cấp cluster: sức khỏe nút, giới hạn tài khoản đám mây, các thay đổi mạng. Hoạt động hàng ngày không liên quan đến liên hệ này. + +--- + +## Những gì chúng tôi triển khai + +Khi Exosphere có quyền truy cập cluster, các thành phần sau sẽ được triển khai và quản lý cho bạn: + +| Thành phần | Vai trò | +|---|---| +| **AgentEye Server** | API HTTP nhận các sự kiện từ các bộ sưu tập, chạy phân tích và cung cấp dữ liệu cho bảng điều khiển | +| **Bảng điều khiển** | Giao diện web để xem các phiên làm việc của agent, lệnh gọi công cụ, yêu cầu mô hình và lỗi; lưu trữ trợ lý AI chỉ đọc tùy chọn | +| **ClickHouse** | Kho dữ liệu chính yêu cầu cho các sự kiện, phân tích và đánh giá được nhập | +| **PostgreSQL** | Kho dữ liệu quan hệ cho các tổ chức, khóa API, người dùng, bảng điều khiển và các truy vấn đã lưu | +| **Redis** | Bộ nhớ đệm dùng chung tùy chọn và phần phụ trợ giới hạn tốc độ; nền tảng giảm độ che phủ một cách khoan dung nếu nó không khả dụng | +| **Trợ lý AI (tùy chọn)** | Thùng chứa trợ lý chỉ đọc nội bộ; giữ bị vô hiệu cho đến khi một điểm cuối LLM được định cấu hình | +| **Bộ điều khiển ingress** | Hai bộ cân bằng tải (một cho nhập được bảo vệ bằng mTLS, một cho bảng điều khiển) kết thúc TLS với chứng chỉ được tin cậy công khai, tự gia hạn và thực thi mTLS trên điểm cuối nhập | +| **cert-manager** | Tự động hóa cấp phát chứng chỉ TLS và cấp phát chứng chỉ máy khách mTLS | +| **Giám sát chứng chỉ** | Một công việc lên lịch kiểm tra hết hạn chứng chỉ và gửi cảnh báo (ví dụ: tới Slack) khi các chứng chỉ gần gia hạn | + +Việc cung cấp được quản lý cũng vận hành quy trình đánh giá của nền tảng, điều này đánh giá hoạt động của agent theo tiêu chí đánh giá của bạn. Xem [Assistant](/vi/agenteye/assistant) và [Evaluation Suite](/vi/agenteye/evaluation-suite) để biết những khả năng này cung cấp gì. + +--- + +## Những gì chúng tôi cung cấp cho bạn + +Sau khi triển khai hoàn tất, bạn sẽ nhận được: + +| Mục | Chi tiết | +|---|---| +| **URL bảng điều khiển** | Một tên máy chủ dưới tên miền của bạn (ví dụ: `https://agenteye.your-company.example`), được cung cấp với chứng chỉ TLS được tin cậy công khai, tự gia hạn. Bạn tạo một CNAME đến tên máy chủ bộ cân bằng tải mà chúng tôi cung cấp; đăng nhập là OTP email không mật khẩu | +| **Điểm cuối bộ sưu tập** | Đường dẫn `/events` của tên máy chủ nhập (ví dụ: `https://ingest.your-company.example/events`), được bảo vệ bằng mTLS | +| **Gói chứng chỉ máy khách** | Mỗi cluster: chứng chỉ máy khách, khóa riêng và chứng chỉ CA được cung cấp dưới dạng kê khai Secret của Kubernetes. Áp dụng nó một lần cho mỗi cluster | +| **GitHub PAT** | Để tải xuống các tệp nhị phân bộ sưu tập và các gói Python SDK | +| **Khóa API bộ sưu tập** | Các khóa được giới hạn phạm vi với quyền `events:add`, một cho mỗi triển khai bộ sưu tập | +| **Hướng dẫn cài đặt** | Tài liệu từng bước cho bộ sưu tập và Python SDK | + +--- + +## Những gì bạn làm sau khi thiết lập + +Công việc đang diễn ra duy nhất của bạn là trên các máy agent của riêng bạn, không phải cluster AgentEye: + +1. **Cài đặt bộ sưu tập** trong mỗi cluster Kubernetes chạy các agent AI: gắn chứng chỉ máy khách và định cấu hình URL điểm cuối và khóa API. Xem [Collector Installation](/vi/agenteye/collector-installation). +2. **Tích hợp Python SDK** vào mã agent của bạn. Xem [Python SDK](/vi/agenteye/python-sdk). +3. **Mở bảng điều khiển** trong trình duyệt của bạn để xem hoạt động của agent. + +Không cần vận hành cluster, không cần quản lý cơ sở dữ liệu, không cần gia hạn chứng chỉ, không cần nâng cấp. + +--- + +## Bảo mật + +- **Dữ liệu được lưu giữ trong tài khoản đám mây của bạn.** Cluster, lưu trữ và cơ sở dữ liệu đều chạy trong môi trường của bạn. Không có dữ liệu nào rời khỏi ranh giới của bạn. +- **Bạn kiểm soát quyền truy cập.** Cluster nằm trong tài khoản của bạn. Bạn có thể kiểm toán, giám sát hoặc thu hồi quyền truy cập của Exosphere bất cứ lúc nào. Tất cả các hoạt động đi qua nhật ký kiểm toán của đám mây của bạn (CloudTrail, GCP Audit Logs, v.v.). +- **mTLS trên nhập sự kiện.** Mỗi yêu cầu bộ sưu tập yêu cầu cả chứng chỉ máy khách hợp lệ và khóa API. Một khóa bị rò rỉ là vô dụng mà không có chứng chỉ; một chứng chỉ bị đánh cắp là vô dụng mà không có khóa hợp lệ. +- **Kiểm soát truy cập bảng điều khiển.** Bảng điều khiển chạy trên bộ cân bằng tải riêng, riêng biệt từ nhập sự kiện, và đăng nhập là OTP email không mật khẩu được hạn chế đối với các địa chỉ/tên miền email được phép. Danh sách cho phép dải nguồn IP trên bộ cân bằng tải có sẵn khi yêu cầu; vì gia hạn chứng chỉ tự động phải tiếp cận bộ cân bằng tải, Exosphere ghép hạn chế với xác thực chứng chỉ dựa trên DNS để các lần gia hạn tiếp tục hoạt động. +- **Chứng chỉ cho mỗi cluster.** Mỗi cluster của bạn nhận chứng chỉ máy khách của riêng nó. Nếu một cluster bị xâm phạm, chứng chỉ đó sẽ bị thu hồi độc lập mà không ảnh hưởng đến những chứng chỉ khác. + +--- + +## Lịch trình triển khai + +| Giai đoạn | Thời lượng | Sự tham gia của bạn | +|---|---|---| +| **Cấp phát cluster** | 1-2 ngày | Cấp phát cluster và cấp quyền truy cập cho Exosphere | +| **Thiết lập nền tảng** | 1 ngày | Không có; Exosphere cài đặt tất cả các thành phần cơ sở hạ tầng | +| **Triển khai ứng dụng** | 1 ngày | Không có; Exosphere triển khai máy chủ, bảng điều khiển và tạo khóa API | +| **Triển khai bộ sưu tập** | 1-3 ngày | Cài đặt các bộ sưu tập trong các cluster của bạn (với hướng dẫn từ Exosphere) | +| **Chạy sản xuất** | 1 tuần | Không có; Exosphere giám sát và điều chỉnh | + +Tổng cộng thường xuyên: **~2 tuần** từ khởi động đến sẵn sàng sản xuất. + +--- + +## Hỗ trợ + +Đối với các câu hỏi hoặc vấn đề, hãy liên hệ với Exosphere tại `support@exosphere.host`. + +--- + +## Các bước tiếp theo + +- [Getting Started](/vi/agenteye/getting-started): hướng dẫn toàn bộ +- [Collector Installation](/vi/agenteye/collector-installation): cài đặt và định cấu hình bộ sưu tập +- [Python SDK](/vi/agenteye/python-sdk): công cụ code agent của bạn +- [API Keys](/vi/agenteye/api-keys): quản lý quyền truy cập và quyền +- [Troubleshooting](/vi/agenteye/troubleshooting): các vấn đề chung và cách khắc phục \ No newline at end of file diff --git a/docs/vi/agenteye/python-sdk.mdx b/docs/vi/agenteye/python-sdk.mdx new file mode 100644 index 00000000..8c2883fb --- /dev/null +++ b/docs/vi/agenteye/python-sdk.mdx @@ -0,0 +1,387 @@ +--- +title: "Python SDK" +description: "Tài liệu AgentEye Python SDK." +--- + + +AgentEye Python SDK cung cấp cho bạn khả năng theo dõi toàn diện hành vi của các agent (mọi lần chạy agent, lệnh gọi tool, yêu cầu mô hình, hook và can thiệp của con người) để bạn có thể gỡ lỗi, kiểm toán và đánh giá chúng. Nó khởi tạo mã agent của bạn bằng cách ghi các sự kiện có cấu trúc vào các tệp JSONL cục bộ; daemon bộ sưu tập sẽ lấy những tệp này và tự động gửi chúng đến nền tảng. + +--- + +## Cài đặt + +Tải tệp wheel từ GitHub Releases bằng `AGENTEYE_TOKEN` của bạn. Nếu bạn chưa có token, hãy xem [Cài đặt Token GitHub](/vi/agenteye/github-token) để biết các bước cài đặt và quyền cần thiết. + +**Sử dụng `gh` CLI + pip:** + +```bash +VERSION=0.0.1b9 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "python-sdk/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-*.whl' +pip install "agenteye-${VERSION}-py3-none-any.whl" +``` + +**Sử dụng `gh` CLI + uv:** + +```bash +VERSION=0.0.1b9 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "python-sdk/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-*.whl' +uv add "./agenteye-${VERSION}-py3-none-any.whl" +``` + +**Sử dụng curl (không có `gh` CLI):** + +```bash +VERSION=0.0.1b9 +curl -fsSL \ + -H "Authorization: Bearer $AGENTEYE_TOKEN" \ + -L \ + "https://github.com/agenteye-enterprise/releases/releases/download/python-sdk%2Fv${VERSION}/agenteye-${VERSION}-py3-none-any.whl" \ + -o "agenteye-${VERSION}-py3-none-any.whl" +pip install "agenteye-${VERSION}-py3-none-any.whl" +``` + +--- + +## Bắt Đầu Nhanh + +```python +import agenteye + +agenteye.configure(environment="production") + +agenteye.event.agent_start(session_id="run-001", agent_id="planner", goal="answer user query") + +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", + input={"query": "latest AI research"}, +) + +agenteye.event.tool_result( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", + output={"results": ["..."]}, +) + +agenteye.event.agent_end(session_id="run-001", agent_id="planner", outcome="success") +``` + +--- + +## configure() + +```python +agenteye.configure( + base_dir=None, # Path | str | None. Mặc định: $AGENTEYE_HOME hoặc ~/.agenteye + flush_interval=0.5, # float, giây giữa các chu kỳ flush + environment=None, # str | None. Nhãn môi trường triển khai +) +``` + +Gọi một lần trước bất kỳ lệnh gọi `event.*` nào. An toàn nếu bỏ qua; các giá trị mặc định hoạt động không vấn đề. Tất cả các đối số chỉ dùng từ khóa; hãy truyền chúng theo tên như được hiển thị ở trên. + +Khi `base_dir` là `None` (mặc định), SDK đọc `$AGENTEYE_HOME` nếu được đặt, +nếu không sẽ quay lại `~/.agenteye`. Điều này phù hợp với cách phân giải của bộ sưu tập, +do đó một biến env `AGENTEYE_HOME` duy nhất sẽ cấu hình bộ spool sự kiện dùng chung cho cả +SDK và bộ sưu tập, cần thiết cho các triển khai sidecar / single-pod nơi +cả hai quy trình phải thống nhất về đường dẫn bộ spool. + +--- + +## Môi Trường + +Gắn nhãn mọi sự kiện bằng môi trường triển khai (`production`, `staging`, `qa`, `canary`, v.v.). Đặt nó một lần; SDK sẽ tự động gắn nó vào mọi sự kiện. + +**Tùy chọn 1: qua `configure()`:** + +```python +agenteye.configure(environment="production") +``` + +**Tùy chọn 2: qua biến môi trường:** + +```bash +export AGENTEYE_ENVIRONMENT=production +``` + +**Ưu tiên:** `configure(environment=...)` sẽ thắng biến môi trường. Nếu không có gì được đặt, mặc định là `"dev"`. + +Giá trị môi trường xuất hiện như một bộ lọc hạng nhất trong bảng điều khiển và được lưu trữ dưới dạng cột được lập chỉ mục trên máy chủ để truy vấn nhanh. + +**Ràng buộc:** các giá trị môi trường **không được chứa dấu phẩy `,` nghĩa đen**. Các bộ lọc bảng điều khiển sử dụng lựa chọn đa trên dây được phân tách bằng dấu phẩy (`?environment=prod,staging`), do đó một môi trường được đặt tên `prod,blue` sẽ bị chia thành hai giá trị. Các sự kiện có môi trường chứa dấu phẩy bị từ chối trong thời gian nhập. + +--- + +## Tham Chiếu Sự Kiện + +Tất cả các phương thức sự kiện yêu cầu hai trường này: + +| Trường | Loại | Mô tả | +|---|---|---| +| `session_id` | `str` | Xác định lần chạy agent cấp cao nhất | +| `agent_id` | `str` | Xác định agent nào trong phiên đã phát ra sự kiện | + +Tất cả các phương thức cũng chấp nhận `**kwargs` tùy ý cho siêu dữ liệu tùy chỉnh (xem [Trường Tùy Chỉnh](#custom-fields)). + +--- + +### `event.agent_start()` + +Được phát ra khi một agent bắt đầu công việc. + +```python +agenteye.event.agent_start( + session_id="run-001", + agent_id="planner", + goal="answer user query", # str | None + parent_id=None, # str | None - agent_id cha cho các agent lồng nhau +) +``` + +--- + +### `event.agent_end()` + +Được phát ra khi một agent kết thúc công việc. + +```python +agenteye.event.agent_end( + session_id="run-001", + agent_id="planner", + outcome="success", # str | None + summary="Answered query", # str | None +) +``` + +--- + +### `event.tool_use()` + +Được phát ra khi một agent gọi một tool. Ghép với `tool_result`; SDK tự động tính toán `duration_ms`. + +```python +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="web_search", # str, bắt buộc + tool_call_id="toolu_01", # str, bắt buộc - khóa tương quan cho tool_result khớp + input={"query": "..."}, # dict | None +) +``` + +--- + +### `event.tool_result()` + +Được phát ra khi một tool trả về. Tương quan với `tool_use` qua `tool_call_id`. + +```python +agenteye.event.tool_result( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", # phải khớp với tool_use trước đó + output={"results": ["..."]}, # Any | None + error=None, # str | None - đặt nếu tool đã nâng cao lỗi + # duration_ms được tính toán tự động - không truyền nó +) +``` + +--- + +### `event.model_request()` + +Được phát ra ngay trước khi gửi một lời nhắc đến LLM. + +```python +agenteye.event.model_request( + session_id="run-001", + agent_id="planner", + model="claude-sonnet-4-6", # str | None + messages=[ # list[dict] | None - các lần hội thoại + {"role": "user", "content": "..."}, + ], + system="You are helpful.", # Any | None - str hoặc danh sách các khối nội dung + tools=[ # list[dict] | None - các lược đồ tool được cung cấp cho mô hình + {"name": "search", "input_schema": {"type": "object"}}, + ], +) +``` + +Các mục `messages` chấp nhận cả nội dung đơn giản `content` hoặc nội dung kiểu Anthropic `content` là danh sách các khối. Các tham số lấy mẫu (`temperature`, `max_tokens`, v.v.) có thể được truyền dưới dạng kwargs bổ sung. + +--- + +### `event.model_response()` + +Được phát ra khi LLM trả về một phản hồi. + +```python +agenteye.event.model_response( + session_id="run-001", + agent_id="planner", + model="claude-sonnet-4-6", # str | None + stop_reason="end_turn", # str | None + input_tokens=1024, # int | None + output_tokens=256, # int | None + content=[ # Any | None - str, hoặc danh sách các khối nội dung + {"type": "text", "text": "..."}, + ], + role="assistant", # str | None +) +``` + +`content` chấp nhận một chuỗi đơn giản (các nhà cung cấp chung) hoặc một danh sách các khối nội dung kiểu Anthropic. Các lệnh gọi tool nằm bên trong `content` dưới dạng các khối `{"type": "tool_use", ...}`, không có trường `tool_calls` riêng biệt. + +--- + +### `event.hook_triggered()` + +Được phát ra khi một hook kích hoạt. Ghép với `hook_completed`; SDK tự động tính toán `duration_ms`. + +```python +agenteye.event.hook_triggered( + session_id="run-001", + agent_id="planner", + hook_name="pre_tool_use", # str, bắt buộc + hook_id="hook-abc", # str, bắt buộc - khóa tương quan + trigger_event="tool_use", # str | None + input={"tool": "search"}, # Any | None +) +``` + +--- + +### `event.hook_completed()` + +Được phát ra khi một hook kết thúc. Tương quan với `hook_triggered` qua `hook_id`. + +```python +agenteye.event.hook_completed( + session_id="run-001", + agent_id="planner", + hook_name="pre_tool_use", + hook_id="hook-abc", # phải khớp với hook_triggered trước đó + outcome="allow", # str | None + output=None, # Any | None + error=None, # str | None + # duration_ms được tính toán tự động - không truyền nó +) +``` + +--- + +### `event.error()` + +Được phát ra khi xảy ra lỗi không được xử lý. + +```python +agenteye.event.error( + session_id="run-001", + agent_id="planner", + error_type="TimeoutError", # str, bắt buộc + message="timed out", # str, bắt buộc + traceback="Traceback...", # str | None +) +``` + +--- + +## Sự Kiện Con Người Trong Vòng Lặp + +Các sự kiện con người trong vòng lặp cung cấp cho bạn giám sát các thời điểm khi một người bước vào quá trình thực thi của agent (chờ phê duyệt, cung cấp đầu vào, tạm dừng hoặc dừng agent). Chúng cho phép bạn đo lường con người mất bao lâu để phản hồi (SDK tự động tính toán `duration_ms` trên các sự kiện ghép), kiểm toán ai đã tạm dừng hoặc ngắt agent, và xây dựng các quy trình phê duyệt và giám sát xuất hiện trong bảng điều khiển. + +### `event.human_wait()` + +Được phát ra khi agent tạm dừng thực thi để chờ con người cung cấp đầu vào. Ghép với `human_input`; SDK tự động tính toán `duration_ms` (con người mất bao lâu để phản hồi). + +```python +agenteye.event.human_wait( + session_id="run-001", + agent_id="planner", + input_id="inp-abc", # str, bắt buộc - khóa tương quan cho human_input khớp + prompt="Do you approve this action?", # str | None - câu hỏi được hiển thị cho con người + options=["approve", "reject", "defer"], # list[str] | None - lựa chọn được trình bày cho con người + reason="approval_required", # str | None - lý do agent đang chờ đợi +) +``` + +### `event.human_input()` + +Được phát ra khi con người cung cấp đầu vào và agent tiếp tục. Tương quan với `human_wait` qua `input_id`. `duration_ms` được tính toán tự động và không được truyền bởi người gọi. + +```python +agenteye.event.human_input( + session_id="run-001", + agent_id="planner", + input_id="inp-abc", # str, bắt buộc - phải khớp với human_wait trước đó + response="approve", # str | None - câu trả lời của con người (văn bản tự do hoặc tùy chọn được chọn) + # duration_ms được tính toán tự động - không truyền nó +) +``` + +### `event.human_pause()` + +Được phát ra khi con người chủ động tạm dừng agent (ví dụ: qua điều khiển bảng điều khiển). Agent bị tạm dừng nhưng không bị kết thúc. + +```python +agenteye.event.human_pause( + session_id="run-001", + agent_id="planner", + reason="user_requested", # str | None + user_id="usr_42", # str | None - ai đã tạm dừng agent +) +``` + +### `event.human_interrupt()` + +Được phát ra khi con người chủ động dừng agent giữa chừng. Không giống như `human_pause`, công việc của agent bị kết thúc chứ không bị tạm dừng. + +```python +agenteye.event.human_interrupt( + session_id="run-001", + agent_id="planner", + reason="output_incorrect", # str | None + user_id="usr_42", # str | None - ai đã ngắt agent + at_step="tool_use:web_search", # str | None - agent đang làm gì khi bị dừng +) +``` + +--- + +## Trường Tùy Chỉnh + +Bất kỳ đối số từ khóa bổ sung nào được nối vào sự kiện sau các trường tiêu chuẩn: + +```python +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="db_query", + tool_call_id="toolu_02", + tenant_id="acme", # trường tùy chỉnh + region="us-east-1", # trường tùy chỉnh +) +``` + +`timestamp`, `type` và `environment` được dành riêng và sẽ nâng cao `ValueError` (`Reserved field names cannot be used as custom fields: [...]`) nếu được truyền dưới dạng trường tùy chỉnh. `session_id` và `agent_id` là các tham số bắt buộc trên mọi phương thức sự kiện và không thể được cung cấp lần thứ hai; Python sẽ nâng cao `TypeError` nếu bạn làm như vậy. Thay vào đó, hãy đặt môi trường bằng `configure(environment=...)` (hoặc biến `AGENTEYE_ENVIRONMENT`). + +--- + +## Cách Các Sự Kiện Được Ghi + +Các sự kiện được đệm trong quy trình và xóa đến đĩa mỗi `flush_interval` giây (mặc định 500 ms). Mỗi lần xóa ghi một tệp JSONL: + +``` +~/.agenteye/events/event-2026-04-01T12-00-00-000Z.jsonl +``` + +Bộ sưu tập theo dõi thư mục này và tải các tệp lên tự động. Bạn không cần quản lý các tệp này trực tiếp. \ No newline at end of file diff --git a/docs/vi/agenteye/single-pod-deployment.mdx b/docs/vi/agenteye/single-pod-deployment.mdx new file mode 100644 index 00000000..7fb8a446 --- /dev/null +++ b/docs/vi/agenteye/single-pod-deployment.mdx @@ -0,0 +1,484 @@ +--- +title: "Triển khai Single-Pod: Collector + Application Sidecar trên EKS" +description: "Tài liệu AgentEye Single-Pod Deployment: Collector + Application Sidecar trên EKS." +--- + + +Chạy ứng dụng của bạn và collector AgentEye **trong cùng một Pod Kubernetes** để telemetry không bao giờ phải vượt qua ranh giới mạng để được thu thập. SDK ứng dụng của bạn và collector chia sẻ một spool sự kiện trong pod duy nhất, có nghĩa là handoff telemetry độ trễ thấp, trong process không có localhost port để expose, không có service mesh để traverse, và vòng đời của collector được liên kết trực tiếp với workload mà nó quan sát. Chứng chỉ mTLS client mà collector trình bày được gửi trực tiếp vào pod của bạn từ AWS Secrets Manager, vì vậy vòng quay credential không yêu cầu sắp xếp tệp thủ công ở phía của bạn. + +Mô hình sidecar + shared-spool được mô tả ở đây là cloud-agnostic; hai container chia sẻ một spool sự kiện `emptyDir` hoạt động trên bất kỳ phân phối Kubernetes nào. Chỉ đường dẫn truyền tải chứng chỉ trong hướng dẫn này (AWS Secrets Manager + Secrets Store CSI Driver + IRSA) là cụ thể cho AWS / EKS. Nếu bạn chạy ở nơi khác, hãy giữ nguyên layout pod và spool, và thay thế cơ chế gắn secret của platform của bạn cho Phases 2 và 3. + +> **Khi nào nên sử dụng pattern này.** Chọn single-pod khi ứng dụng của bạn không nên gọi qua ranh giới mạng để tiếp cận collector (low-latency in-pod IPC, tight lifecycle coupling, per-tenant pod isolation). Đối với các fleet multi-app chia sẻ một collector trên mỗi node hoặc trên mỗi cluster, xem [enterprise-docs/kubernetes-deployment.md](/vi/agenteye/kubernetes-deployment) thay thế. + +--- + +## Tóm tắt nhanh + +``` +┌──────────────────────────────── Pod ─────────────────────────────────┐ +│ │ +│ ┌──────────────────────┐ ┌──────────────────────┐ │ +│ │ your-app │ │ agenteye-collector │ │ +│ │ (SDK writes JSONL) │ │ (sweeps events/, │ │ +│ │ │ │ uploads over mTLS) │ │ +│ └──────────┬───────────┘ └──────────┬───────────┘ │ +│ │ writes reads │ │ +│ ▼ ▼ │ +│ ┌────────────────────────────────────────────────────┐ │ +│ │ emptyDir: /var/lib/agenteye/{events,failed}/ │ │ +│ │ (AGENTEYE_HOME - shared event spool) │ │ +│ └────────────────────────────────────────────────────┘ │ +│ ▲ │ +│ │ reads cert │ +│ ┌────────┴─────────┐ │ +│ │ CSI (read-only): │ │ +│ │ /etc/agenteye/ │ │ +│ │ tls/client.{crt, │ │ +│ │ key}, ca.crt │ │ +│ └────────┬─────────┘ │ +└───────────────────────────────────────────────────┼──────────────────┘ + │ mounted by + │ Secrets Store CSI + │ (AWS provider + + │ IRSA) + ┌────────┴──────────┐ + │ AWS Secrets │ + │ Manager │ + │ agenteye/mtls- │ + │ client/ │ + └────────┬──────────┘ + ▲ + │ push on issue / + │ renewal + ┌────────┴──────────┐ + │ Exosphere │ + │ delivers the cert │ + │ bundle into your │ + │ Secrets Manager │ + │ on renewal │ + └───────────────────┘ + +Outbound: collector → AGENTEYE_URL (mTLS, using the CSI-mounted cert). +``` + +Hai dòng dữ liệu, hai volume: + +- **Events (in-pod):** SDK của app bạn ghi các tệp `.jsonl` vào `emptyDir` chia sẻ tại `$AGENTEYE_HOME/events/`; collector sweeper đọc chúng và upload. Không có localhost port, không có loopback, handoff thuần pure shared-filesystem. +- **mTLS cert (pod ← cloud):** Secrets Store CSI Driver gắn kết bundle chứng chỉ từ Secrets Manager vào một volume read-only tại `/etc/agenteye/tls/`, scoped đến collector container. + +**Hai bên độc lập:** + +| Bên | Trách nhiệm | +|---|---| +| Exosphere | Phát hành chứng chỉ mTLS client và gửi bundle vào **tài khoản AWS của bạn** trong Secrets Manager dưới một tên ổn định. Tái xuất bản bundle được gia hạn vào cùng secret trước khi hết hạn. | +| Bạn | Cài đặt Secrets Store CSI Driver, cấp quyền đọc cho ServiceAccount của pod tới secret thông qua IRSA, và áp dụng Pod manifest. Đó là tất cả. | + +--- + +## Điều kiện tiên quyết + +### Trong tài khoản AWS / EKS cluster của bạn + +- Một EKS cluster với **OIDC provider** được liên kết. Xác nhận bằng: + + ```bash + aws eks describe-cluster --name \ + --query "cluster.identity.oidc.issuer" --output text + ``` + + Nếu lệnh trả về một URL `https://oidc.eks.…`, OIDC được bật. Nếu không, hãy liên kết một: + + ```bash + eksctl utils associate-iam-oidc-provider \ + --cluster --approve + ``` + +- [Secrets Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/) và [AWS provider](https://github.com/aws/secrets-store-csi-driver-provider-aws) được cài đặt trong cluster (xem § Phase 2). + +- AWS CLI v2 và `kubectl` trên workstation của bạn. + +### Phối hợp với Exosphere + +Trước khi deploy, Exosphere gửi bundle mTLS client vào Secrets Manager của tài khoản AWS của bạn và cung cấp: + +- **Tên secret** (quy ước: `agenteye/mtls-client/`) +- **AWS region** mà secret được lưu trữ +- **URL backend AgentEye** để cấu hình collector +- **API key** collector của bạn (xem [enterprise-docs/api-keys.md](/vi/agenteye/api-keys)) + +--- + +## Phase 1: Cái gì Exosphere gửi + +Bạn không tự tạo ra chứng chỉ mTLS client. Exosphere phát hành nó và gửi bundle trực tiếp vào Secrets Manager của tài khoản AWS của bạn, vì vậy credential material duy nhất bao giờ được gửi tới môi trường của bạn là secret finished, ready-to-mount. + +Cái gì đến trong tài khoản của bạn: + +| Thuộc tính | Giá trị | +|---|---| +| Tên secret | `agenteye/mtls-client/` (ổn định qua renewals) | +| Region | AWS region bạn đã chỉ định cho EKS cluster của bạn | +| Payload | Một JSON secret duy nhất có ba keys (`client.crt`, `client.key`, và `ca.crt`), mỗi cái giữ PEM-encoded material | +| Tag | `AgentEyeCluster=` | + +Khi gia hạn, cùng secret được cập nhật tại chỗ với một phiên bản mới, vì vậy ARN và tên không bao giờ thay đổi; `SecretProviderClass` và IAM policy của bạn tiếp tục hoạt động không thay đổi. Để biết về vòng đời chứng chỉ (validity, renewal cadence, expiry alerting), xem [enterprise-docs/kubernetes-deployment.md](/vi/agenteye/kubernetes-deployment). + +--- + +## Phase 2: Cài đặt Secrets Store CSI Driver + AWS provider + +Bỏ qua bước này nếu bạn đã chạy một workload khác gắn AWS secrets qua CSI. + +```bash +# CSI Driver +helm repo add secrets-store-csi-driver \ + https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts +helm install -n kube-system csi-secrets-store \ + secrets-store-csi-driver/secrets-store-csi-driver \ + --set syncSecret.enabled=true \ + --set enableSecretRotation=true \ + --set rotationPollInterval=1h + +# AWS provider +kubectl apply -f \ + https://raw.githubusercontent.com/aws/secrets-store-csi-driver-provider-aws/main/deployment/aws-provider-installer.yaml +``` + +**Xác minh:** + +```bash +kubectl get pods -n kube-system | grep -E 'csi-secrets-store|aws-provider' +``` + +Kỳ vọng: `Running` cho mỗi pod. + +> **Tại sao `rotationPollInterval=1h`?** Khi Exosphere xuất bản một chứng chỉ được gia hạn, Secrets Manager được cập nhật tại chỗ. CSI Driver đọc lại secret trên khoảng thời gian này và ghi lại các tệp được gắn. Collector đọc các tệp chứng chỉ một lần khi khởi động, vì vậy nó chỉ bắt đầu trình bày chứng chỉ được gia hạn sau khi process khởi động lại; xem § Certificate rotation để biết cách trigger một. + +--- + +## Phase 3: Cấp quyền đọc cho pod để truy cập secret (IRSA) + +### 3.1 Tạo IAM policy + +Lưu dưới dạng `agenteye-mtls-reader-policy.json`: + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "ReadAgentEyeMtlsBundle", + "Effect": "Allow", + "Action": [ + "secretsmanager:GetSecretValue", + "secretsmanager:DescribeSecret" + ], + "Resource": "arn:aws:secretsmanager:::secret:agenteye/mtls-client/-*" + } + ] +} +``` + +Thay thế ``, ``, và ``. Hậu tố `-*` cuối cùng khớp với hậu tố ngẫu nhiên sáu ký tự AWS thêm vào mỗi secret ARN. + +Tạo policy: + +```bash +aws iam create-policy \ + --policy-name AgentEyeMtlsReader- \ + --policy-document file://agenteye-mtls-reader-policy.json +``` + +### 3.2 Tạo IAM role và liên kết nó với ServiceAccount của pod + +```bash +eksctl create iamserviceaccount \ + --name agenteye-pod \ + --namespace \ + --cluster \ + --role-name AgentEyePodRole- \ + --attach-policy-arn arn:aws:iam:::policy/AgentEyeMtlsReader- \ + --approve +``` + +Cái này tạo một `ServiceAccount` tên `agenteye-pod` với annotation `eks.amazonaws.com/role-arn` trỏ tới role mới. + +### 3.3 Quyền IAM bắt buộc: tóm tắt + +| Quyền | Phạm vi | Lý do | +|---|---|---| +| `secretsmanager:GetSecretValue` | `arn:aws:secretsmanager:::secret:agenteye/mtls-client/-*` | CSI Driver đọc bundle cert trên mỗi mount + rotation tick. | +| `secretsmanager:DescribeSecret` | giống nhau | CSI Driver gọi `DescribeSecret` để phát hiện thay đổi version giữa các polls. | + +**Không cấp** `secretsmanager:PutSecretValue`, `secretsmanager:UpdateSecret`, hoặc `secretsmanager:DeleteSecret` cho pod. Pod chỉ khi nào đọc secret; viết phiên bản mới vào nó được xử lý bởi Exosphere khi chứng chỉ được phát hành hoặc gia hạn. + +Nếu secret được mã hóa bằng customer-managed KMS key (không phải default `aws/secretsmanager` key), cũng cấp: + +```json +{ + "Effect": "Allow", + "Action": ["kms:Decrypt"], + "Resource": "arn:aws:kms:::key/", + "Condition": { + "StringEquals": { + "kms:ViaService": "secretsmanager..amazonaws.com" + } + } +} +``` + +--- + +## Phase 4: Deploy Pod + +### 4.1 SecretProviderClass + +`agenteye-mtls-spc.yaml`: + +```yaml +apiVersion: secrets-store.csi.x-k8s.io/v1 +kind: SecretProviderClass +metadata: + name: agenteye-mtls + namespace: +spec: + provider: aws + parameters: + objects: | + - objectName: "agenteye/mtls-client/" + objectType: "secretsmanager" + jmesPath: + - path: '"client.crt"' + objectAlias: "client.crt" + - path: '"client.key"' + objectAlias: "client.key" + - path: '"ca.crt"' + objectAlias: "ca.crt" +``` + +Khối `jmesPath` báo cho AWS provider chia JSON secret thành ba tệp riêng biệt trên disk. Quoting trong `'"client.crt"'` được yêu cầu vì JMESPath coi `.` là một sub-expression operator. + +```bash +kubectl apply -f agenteye-mtls-spc.yaml +``` + +### 4.2 Pod / Deployment manifest + +**Cách hai container nói chuyện với nhau.** AgentEye SDK và collector không giao tiếp qua một network socket; không có local HTTP port. SDK ghi event batches dưới dạng các tệp `.jsonl` vào `$AGENTEYE_HOME/events/`, và collector liên tục xem thư mục đó và upload từng tệp. Đối với một sidecar pod, cái này có nghĩa là: + +- Cả hai container gắn **cùng một** `emptyDir` volume tại **cùng một** path. +- Cả hai container đặt `AGENTEYE_HOME` tới path đó. +- Image ứng dụng của bạn phải có AgentEye SDK được cài đặt và cấu hình (xem [enterprise-docs/python-sdk.md](/vi/agenteye/python-sdk)). + +> Khi `AGENTEYE_HOME` chưa được set, cả SDK và collector đều mặc định tới `~/.agenteye`, và hai container có các thư mục home khác nhau, vì vậy chúng sẽ hạ cánh trên hai spools riêng biệt và handoff sẽ silently fail. Đặt `AGENTEYE_HOME` tới cùng một path tường minh trên **cả hai** containers. §4.3 verification và matching Troubleshooting row bắt cái này nếu nó bị bỏ sót. + +`agenteye-pod.yaml` (Deployment với một replica, scale khi cần): + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-app-with-collector + namespace: +spec: + replicas: 1 + selector: + matchLabels: + app: my-app-with-collector + template: + metadata: + labels: + app: my-app-with-collector + spec: + serviceAccountName: agenteye-pod + containers: + - name: app + image: + env: + # SDK writes event JSONL files into $AGENTEYE_HOME/events/ + - name: AGENTEYE_HOME + value: /var/lib/agenteye + volumeMounts: + - name: agenteye-spool + mountPath: /var/lib/agenteye + + - name: agenteye-collector + # Pin to a versioned :v tag for production; :beta-latest + # tracks the current beta build (:latest exists only for stable releases). + image: ghcr.io/agenteye-enterprise/collector:beta-latest + args: ["start"] + env: + # Must match the app container's AGENTEYE_HOME so the collector + # sweeps the same directory the SDK writes to. + - name: AGENTEYE_HOME + value: /var/lib/agenteye + - name: AGENTEYE_URL + value: "https://ingest.example.agenteye.com/events" + - name: AGENTEYE_KEY + valueFrom: + secretKeyRef: + name: agenteye-collector-api-key + key: key + - name: AGENTEYE_TLS_CERT + value: /etc/agenteye/tls/client.crt + - name: AGENTEYE_TLS_KEY + value: /etc/agenteye/tls/client.key + # Only when the AgentEye server presents a cert not signed by a + # publicly-trusted CA (e.g. self-signed by an in-cluster issuer + # because you have no real DNS domain). The CSI mount already + # exposes ca.crt alongside the client cert/key. + - name: AGENTEYE_TLS_CA + value: /etc/agenteye/tls/ca.crt + volumeMounts: + - name: agenteye-spool + mountPath: /var/lib/agenteye + - name: agenteye-mtls + mountPath: /etc/agenteye/tls + readOnly: true + livenessProbe: + exec: + command: ["agenteye-collector", "health"] + initialDelaySeconds: 10 + periodSeconds: 30 + + volumes: + # Shared event spool between app and collector. emptyDir is fine: + # events are transient and the collector drains them before pod + # termination on graceful shutdown. + - name: agenteye-spool + emptyDir: {} + # mTLS cert bundle, mounted read-only into the collector only. + - name: agenteye-mtls + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: agenteye-mtls +``` + +Secret `agenteye-collector-api-key` giữ API key của collector (xem [enterprise-docs/api-keys.md](/vi/agenteye/api-keys) để cấp phát). + +**Áp dụng:** + +```bash +kubectl apply -f agenteye-pod.yaml +``` + +### 4.3 Xác minh + +```bash +# Pod should be Running with 2/2 containers ready +kubectl get pods -n -l app=my-app-with-collector + +# Confirm the cert bundle was mounted +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- ls -l /etc/agenteye/tls/ +``` + +Kỳ vọng: `client.crt`, `client.key`, `ca.crt` tất cả đều có mặt và read-only, sở hữu bởi container user. + +**Xác nhận spool sự kiện chia sẻ được hiển thị cho cả hai containers:** + +```bash +# In the collector, should show the events/ and failed/ subdirs that +# the collector auto-creates on startup: +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- ls /var/lib/agenteye/ + +# In the app, should show the same directory contents: +kubectl exec -n deploy/my-app-with-collector \ + -c app -- ls /var/lib/agenteye/ +``` + +Nếu hai listings phân kỳ, volume không được gắn trong cả hai containers (hoặc `AGENTEYE_HOME` khác); xem § Troubleshooting. + +**End-to-end smoke test:** + +```bash +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- agenteye-collector flush +``` + +Kỳ vọng: collector upload bất kỳ queued events nào và in tóm tắt `Done: N/N uploaded, 0 failed.`. Nếu spool trống, nó in `No pending files.` và thoát mà không validate bất cứ gì — vì vậy chỉ chạy điều này sau khi app của bạn đã flush ít nhất một event. + +Lưu ý rằng `flush` thoát non-zero **chỉ** cho local setup faults: missing configuration (no URL/key resolved) hoặc unreadable/unparseable TLS cert (check § Troubleshooting). **Wrong API key không thay đổi exit code** — upload nhận một `401`, tệp được di chuyển đến `failed/`, và lệnh vẫn in `[FAILED] …` per file cộng với `Done: 0/N uploaded, N failed.` và thoát `0`. Để phát hiện một bad key hoặc rejected upload, đọc đầu ra `Done:`/`[FAILED]` hoặc kiểm tra các tệp hạ cánh trong `$AGENTEYE_HOME/failed/`, không phải exit code. + +--- + +## Xoay vòng chứng chỉ + +Chứng chỉ client có hiệu lực trong 90 ngày và được tự động gia hạn khoảng 15 ngày trước khi hết hạn; Exosphere sau đó xuất bản bundle được gia hạn vào cùng Secrets Manager secret. Từ đó, dòng in-pod là: + +1. Secret của Secrets Manager nhận được một phiên bản `AWSCURRENT` mới. ARN và tên không thay đổi. +2. Trong `rotationPollInterval` (1h theo mặc định; xem § Phase 2), CSI Driver đọc phiên bản mới và ghi lại các tệp dưới `/etc/agenteye/tls/`. +3. Collector tải các tệp chứng chỉ **một lần khi khởi động**, vì vậy nó tiếp tục trình bày chứng chỉ trước cho đến khi process khởi động lại. Để chuyển sang tài liệu được gia hạn, khởi động lại collector; rolling restart là đủ: + + ```bash + kubectl rollout restart deploy/my-app-with-collector -n + ``` + + Để làm cho điều này tự động, thêm một sidecar xem `/etc/agenteye/tls/` (ví dụ với `inotifywait`) và trigger rollout khi các tệp thay đổi. + +Vì chứng chỉ trước đó vẫn có hiệu lực khoảng 15 ngày sau khi gia hạn, bạn có một cửa sổ rộng để thực hiện restart mà không bị gián đoạn ingestion. Exosphere xuất bản bundle được gia hạn cho bạn; hành động thường xuyên duy nhất ở phía bạn là đảm bảo collector khởi động lại trong cửa sổ đó. + +--- + +## Khắc phục sự cố + +| Triệu chứng | Nguyên nhân có khả năng | Sửa chữa | +|---|---|---| +| Pod stuck in `ContainerCreating`, events show `MountVolume.SetUp failed for volume "agenteye-mtls"` | CSI provider không thể tiếp cận Secrets Manager | Kiểm tra IRSA được liên kết chính xác: `kubectl describe sa agenteye-pod -n ` cho thấy annotation `eks.amazonaws.com/role-arn`. Kiểm tra CloudTrail cho cuộc gọi AssumeRole. | +| Error: `AccessDeniedException: not authorized to perform secretsmanager:GetSecretValue` | IAM policy được scoped tới ARN sai | Secret ARN suffix là random; sử dụng `agenteye/mtls-client/-*` với wildcard, không phải ARN chính xác. | +| Error: `ParameterNotFound` từ AWS provider | Secret name mismatch giữa `SecretProviderClass.objects[].objectName` và secret mà Exosphere gửi | Xác nhận tên chính xác với `aws secretsmanager list-secrets --filters Key=tag-key,Values=AgentEyeCluster`. | +| `jmesPath` error, chỉ một tệp được gắn | JMESPath syntax | Các dấu chấm trong các keys JSON yêu cầu double-quoting: `'"client.crt"'`, không phải `client.crt`. | +| Collector logs `tls: bad certificate` sau một renewal | CSI Driver chưa poll phiên bản mới, hoặc collector vẫn chạy với chứng chỉ trước mà nó tải khi khởi động | Xác nhận các tệp được gắn đã cập nhật (`ls -l /etc/agenteye/tls/`), sau đó khởi động lại collector để tải chúng: `kubectl rollout restart deploy/my-app-with-collector -n `. Xem § Certificate rotation. | +| Collector container crashloops với `no such file or directory: /etc/agenteye/tls/client.crt` | Volume chưa được populate trên first start; startup probe quá aggressive | Thêm một small initial delay hoặc sử dụng init container chờ tệp tồn tại: `until [ -f /etc/agenteye/tls/client.crt ]; do sleep 1; done`. | +| CSI Driver pod `OOMKilled` | Default memory limits quá thấp cho clusters với nhiều SecretProviderClasses | Bump `--set linux.resources.limits.memory=200Mi` trong Helm install. | +| App chạy cleanly, `agenteye-collector flush` báo `No pending files.`, nhưng AgentEye dashboard của bạn không hiển thị sự kiện | App và collector không chia sẻ event spool | Kiểm tra (a) cả hai containers gắn cùng `agenteye-spool` emptyDir tại cùng path, và (b) cả hai đặt `AGENTEYE_HOME` tới path đó. Chạy hai kiểm tra `ls /var/lib/agenteye/` từ § 4.3; listings phải khớp. | + +**Logs để grab trước tiên:** + +```bash +kubectl logs -n kube-system -l app=secrets-store-csi-driver --tail=100 +kubectl logs -n kube-system -l app=csi-secrets-store-provider-aws --tail=100 +kubectl describe pod -n -l app=my-app-with-collector +``` + +--- + +## Tham khảo: tệp trên disk trong pod + +Pod có hai data paths trên disk: + +### mTLS cert bundle: `/etc/agenteye/tls/` (CSI, read-only, collector only) + +Được gắn bởi Secrets Store CSI Driver từ AWS Secrets Manager. + +| Tệp | Nội dung | Được sử dụng bởi collector như | +|---|---|---| +| `client.crt` | PEM-encoded client certificate | `AGENTEYE_TLS_CERT` | +| `client.key` | PEM-encoded private key | `AGENTEYE_TLS_KEY` | +| `ca.crt` | PEM-encoded CA cert | `AGENTEYE_TLS_CA` (optional, chỉ khi cert server AgentEye không được tin cậy công khai) | + +Cả ba được gắn read-only và sở hữu bởi container user. Chúng được ghi lại bởi CSI Driver khi secret quay vòng. + +### Event spool: `$AGENTEYE_HOME/` (emptyDir, shared read-write giữa cả hai containers) + +Chia sẻ qua một `emptyDir` volume tên `agenteye-spool`. + +| Path | Viết bởi | Đọc bởi | Mục đích | +|---|---|---|---| +| `$AGENTEYE_HOME/events/*.jsonl` | App (AgentEye SDK) | Collector sweeper | Event batches mà SDK đã flush, đợi upload. | +| `$AGENTEYE_HOME/failed/` | Collector (on upload failure) | Bạn (khi debug) | JSONL files mà collector không thể upload sau retries. | +| `$AGENTEYE_HOME/config.json` | Bạn (optional) | Collector | Optional collector config file (alternative to env vars). | + +Cả hai subdirectories `events/` và `failed/` được auto-created bởi collector khi khởi động; không cần `initContainer`. + +--- + +## Tài liệu liên quan + +- [enterprise-docs/collector-installation.md](/vi/agenteye/collector-installation): collector binary options, mTLS config reference, daemon modes. +- [enterprise-docs/kubernetes-deployment.md](/vi/agenteye/kubernetes-deployment): multi-pod deployment, cert issuance internals, lifecycle và expiry alerts. +- [enterprise-docs/api-keys.md](/vi/agenteye/api-keys): cấp phát collector API key được sử dụng bởi pod. +- [enterprise-docs/troubleshooting.md](/vi/agenteye/troubleshooting): cluster-wide troubleshooting index. \ No newline at end of file diff --git a/docs/vi/agenteye/tenant-management.mdx b/docs/vi/agenteye/tenant-management.mdx new file mode 100644 index 00000000..2d0545a6 --- /dev/null +++ b/docs/vi/agenteye/tenant-management.mdx @@ -0,0 +1,167 @@ +--- +title: "Quản lý Tenant (tổ chức & thành viên)" +description: "Tài liệu Quản lý Tenant AgentEye (tổ chức & thành viên)." +--- + + +Một phiên bản AgentEye duy nhất phục vụ nhiều **tổ chức** (tenants) hoàn toàn bị cách ly, vì vậy một phiên bản có thể lưu trữ các nhóm, đơn vị kinh doanh hoặc khách hàng khác biệt mà không lộ dữ liệu của một tenant cho tenant khác. Mọi hàng dữ liệu (sự kiện, đánh giá, phiên làm việc, bảng điều khiển, truy vấn đã lưu, cảnh báo, khóa API và thành viên) đều thuộc chính xác một tổ chức. Cách ly chính được thực thi trong mã ứng dụng: mọi yêu cầu được phạm vi hóa theo tổ chức với các vị từ `org_id` rõ ràng. Trên ClickHouse — nơi lưu trữ các sự kiện và đánh giá có khối lượng cao — điều này được hỗ trợ bởi việc thực thi mạnh mẽ ở cấp động cơ: mỗi tổ chức nhận được một người dùng ClickHouse chỉ đọc riêng với chính sách hàng cho mỗi tổ chức, do đó ngay cả SQL phân tích không đáng tin cậy cũng không bao giờ có thể đọc các hàng của tenant khác. Trên PostgreSQL, bảo mật cấp hàng bổ sung tính năng phòng chống sâu trên đường dẫn truy vấn chỉ đọc (`/queries/run`), thu hẹp phạm vi mà đường dẫn có thể nhìn thấy ngay cả khi bộ lọc cấp ứng dụng bị thiếu; kết nối ghi của chính máy chủ chạy dưới dạng chủ sở hữu bảng và do đó hoạt động thông qua phạm vi `org_id` cấp ứng dụng giống nhau. + +Vòng đời tenant được kiểm soát bởi người vận hành, trong khi mọi thứ các thành viên làm hàng ngày vẫn tự phục vụ trong bảng điều khiển. Tổ chức và tư cách thành viên của chúng được tạo và quản lý bằng CLI **`agenteye-orgctl`**, được cung cấp bên trong hình ảnh máy chủ và chạy **bên trong pod máy chủ hiện có**. Tạo và xóa tenant được cố ý giữ ngoài bảng điều khiển và API HTTP: không có **API HTTP và nút bảng điều khiển** cho vòng đời tenant, do đó nó bị chặn bởi quyền truy cập shell cluster/pod hơn là bề mặt ứng dụng. + +Trong một tổ chức, các thành viên làm việc hoàn toàn trong bảng điều khiển và API: họ đăng nhập, chuyển đổi giữa các tổ chức họ thuộc về, quản lý khóa API của riêng họ, xây dựng bảng điều khiển và truy vấn đã lưu, và cấu hình cảnh báo cho tổ chức của họ. Sự phân chia là rõ ràng: các nhà vận hành cung cấp và ngừng hoạt động các tenant và thành viên của họ thông qua CLI; các thành viên chạy mọi thứ bên trong một tenant thông qua giao diện người dùng. + +> **Các phiên bản triển khai của một tenant không cần bất kỳ điều này nào.** Cài đặt một tenant chạy mà không cần bất kỳ hành động từ người vận hành nào. Tất cả dữ liệu, người dùng và khóa sống trong một tổ chức `default` tích hợp được cung cấp tự động. Bạn chỉ cần hướng dẫn này khi bạn quyết định thêm một tổ chức thứ hai. + +--- + +## Điều kiện tiên quyết + +Trước khi bạn tạo **tổ chức thứ hai** của mình (tổ chức `default` tích hợp không cần gì): + +- **PostgreSQL 15+.** Lược đồ tư cách thành viên tổ chức sử dụng khóa ngoại `ON DELETE SET NULL` danh sách cột yêu cầu PostgreSQL 15+. Nâng cấp PostgreSQL trước khi cung cấp một tổ chức thứ hai. +- **Một `ORG_CH_SECRET` mạnh mẽ và ổn định.** Mật khẩu ClickHouse của mỗi tổ chức được lấy dưới dạng `HMAC(ORG_CH_SECRET, org_id)`, do đó mặc định phát triển tích hợp được biết công khai sẽ mang lại thông tin đăng nhập cho mỗi tổ chức có thể dẫn xuất công khai. `agenteye-orgctl org create` **từ chối chạy trong khi `ORG_CH_SECRET` không được đặt hoặc để ở mặc định phát triển tích hợp**. Đặt giá trị của riêng bạn trước tiên (xem [Triển khai → biến môi trường](/vi/agenteye/deployment) và, trên Kubernetes, [§2.6 của hướng dẫn Kubernetes](/vi/agenteye/kubernetes-deployment#26-multi-tenant-org-isolation-key-optional)). Giữ nó giống nhau trên tất cả các bản sao máy chủ và không xoay nó một cách tùy tiện; xoay nó bỏ rơi từng người dùng ClickHouse của tổ chức cho đến khi khởi động lại tiếp theo cung cấp lại chúng. + +--- + +## Chạy CLI + +`agenteye-orgctl` được cung cấp trong **hình ảnh giống như máy chủ** (cùng với `agenteye-server`). Bạn **không** triển khai một pod, Job hoặc Deployment riêng biệt cho nó; bạn thực thi nó bên trong pod máy chủ đang chạy, do đó nó đọc cùng `DATABASE_URL`, `CLICKHOUSE_URL` và `ORG_CH_SECRET` mà máy chủ sử dụng. + +**Kubernetes:** + +```bash +kubectl -n agenteye exec deploy/server -- agenteye-orgctl +``` + +**Docker Compose:** + +```bash +docker compose exec server agenteye-orgctl +``` + +Các ví dụ dưới đây hiển thị `agenteye-orgctl ` trơn tru để ngắn gọn; tiền tố mỗi cái với bất kỳ dòng nào trong hai dòng trên khớp với phiên bản triển khai của bạn. + +--- + +## Tham chiếu lệnh + +### Tổ chức + +| Lệnh | Nó làm gì | +|---|---| +| `org create --slug --name ` | Tạo một tổ chức mới. Từ chối chạy trong khi `ORG_CH_SECRET` không được đặt hoặc để ở mặc định phát triển tích hợp (đặt của riêng bạn trước tiên, xem Điều kiện tiên quyết). Cung cấp người dùng ClickHouse chỉ đọc của tổ chức + chính sách hàng. | +| `org list` | Liệt kê tất cả các tổ chức (slug, tên và trạng thái vòng đời). | +| `org rename --slug --name ` | Thay đổi tên hiển thị của tổ chức. Slug (được sử dụng trong URL và khóa) không thay đổi. | +| `org delete --slug ` | **Xóa mềm** tổ chức và loại bỏ người dùng ClickHouse của nó. Dữ liệu **được giữ lại**. Điều này thu hồi quyền truy cập và giải phóng thông tin đăng nhập ClickHouse cho mỗi tổ chức, nhưng không xóa sự kiện. Có thể đảo ngược bởi các nhà vận hành; bước đầu tiên an toàn trước một cuộc thanh lọc. | +| `org purge --slug ` | **Xóa dữ liệu không thể đảo ngược.** Tổ chức phải đã được `delete` rồi. Không bao giờ được phép trên tổ chức `default` tích hợp. Chỉ sử dụng khi bạn chắc chắn rằng dữ liệu của tenant nên bị hủy. | + +### Thành viên + +| Lệnh | Nó làm gì | +|---|---| +| `member add --org --email [--set ] [--add perm1,perm2] [--remove perm3] [--protected]` | Thêm một thành viên vào một tổ chức. Tùy chọn bắt đầu từ một bộ quyền tích hợp, sau đó thêm/loại bỏ các quyền riêng lẻ. `--protected` ghim thành viên để bảng điều khiển không thể xóa hoặc hạ cấp họ (xem bên dưới). Thành viên mới nhận được OTP khi đầu tiên đăng nhập bảng điều khiển. | +| `member list --org ` | Liệt kê các thành viên của tổ chức. Các cột đầu ra là `EMAIL`, `SET` (bộ tích hợp mà thành viên bắt đầu, hoặc `-`), `PROT` (liệu thành viên có được bảo vệ hay không) và `PERMISSIONS` (quyền hiệu lực của họ). Một email hiển thị với dấu `*` ở cuối là quản trị viên phiên bản; họ có quyền truy cập vào mọi tổ chức. | +| `member update --org --email [--set ...] [--add ...] [--remove ...] [--protected \| --unprotect]` | Thay đổi quyền của thành viên và/hoặc cờ bảo vệ. `--set` thay thế từ một bộ tích hợp; `--add` / `--remove` điều chỉnh các quyền riêng lẻ; `--protected` / `--unprotect` bật tính năng bảo vệ. Truyền chỉ `--protected`/`--unprotect` (không có cờ cấp) thay đổi bảo vệ một mình và để nguyên quyền hiện có. | +| `member remove --org --email ` | Loại bỏ một thành viên khỏi tổ chức. Từ chối nếu thành viên được bảo vệ; `--unprotect` họ trước tiên. (Một người có thể là thành viên của một số tổ chức; điều này chỉ ảnh hưởng đến tổ chức được đặt tên.) | + +Một người có thể là thành viên của nhiều hơn một tổ chức với **các** quyền khác nhau ở mỗi tổ chức, ví dụ một quản trị viên trong một tổ chức và chỉ đọc ở tổ chức khác. Mỗi tư cách thành viên được quản lý độc lập cho mỗi tổ chức: việc cấp hoặc thay đổi quyền của một người trong một tổ chức không ảnh hưởng đến tư cách thành viên của họ trong bất kỳ tổ chức nào khác. + +### Thành viên được bảo vệ (quản trị viên tổ chức không thể xóa) + +Bảo vệ đảm bảo một tổ chức không bao giờ có thể vô tình khoá chính nó ra khỏi tự quản lý. Theo mặc định, các quản trị viên của chính một tổ chức có thể thêm và xóa lẫn nhau thông qua trang người dùng tự phục vụ của bảng điều khiển, vì vậy họ có thể xóa quản trị viên cuối cùng và để tổ chức mà không có ai có thể quản lý nó. + +![Trang Người dùng: một thẻ cho mỗi người dùng bảng điều khiển với email, quyền cấp và điều khiển chỉnh sửa/vô hiệu hóa của họ](/agenteye/images/users.png) + +Để ngăn điều đó, đánh dấu một thành viên **được bảo vệ**: + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member add --org acme --email owner@acme.example --set admin --protected +``` + +Một thành viên được bảo vệ **không thể bị xóa hoặc hạ cấp thông qua bảng điều khiển**; những hành động đó trả về lỗi. Chỉ một nhà vận hành mới có thể thay đổi họ và chỉ thông qua CLI này: chạy `member update --org acme --email owner@acme.example --unprotect` trước tiên, sau đó xóa hoặc hạ cấp. Điều này đảm bảo mọi tổ chức giữ ít nhất một quản trị viên mà các thành viên của riêng họ không thể khoá, trong khi vẫn giữ kiểm soát tenant cho nhà vận hành. Bảo vệ **cho mỗi tổ chức**; bảo vệ ai đó trong một tổ chức không ảnh hưởng đến tư cách thành viên của họ ở tổ chức khác. + +### Bộ quyền tích hợp + +`--set` chấp nhận một trong ba bộ tích hợp, được áp dụng cho mỗi tổ chức: + +| Bộ | Dự định cho | +|---|---| +| `admin` | Quyền truy cập đầy đủ trong tổ chức, bao gồm quản lý khóa API và người dùng của tổ chức. | +| `standard` | Sử dụng hàng ngày: đọc + chạy truy vấn, xây dựng bảng điều khiển, thừa nhận sự cố. | +| `read-only` | Quyền truy cập chỉ xem dữ liệu và bảng điều khiển của tổ chức. | + +Bắt đầu từ một bộ với `--set`, sau đó tinh chỉnh bằng `--add` / `--remove` bằng cách sử dụng các mã thông báo quyền riêng lẻ được liệt kê trong [Khóa API](/vi/agenteye/api-keys). Các mã thông báo quyền tự chúng giống hệt với các mã được sử dụng cho khóa API. + +--- + +## Ví dụ thực hành + +Cung cấp một tenant `acme` mới, thêm quản trị viên đầu tiên của nó, để họ tạo một khóa, sau đó loại bỏ tổ chức. + +**1. Tạo tổ chức** (`ORG_CH_SECRET` phải đã được đặt thành giá trị mạnh mẽ, ổn định, không được để không đặt hoặc mặc định phát triển tích hợp): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org create --slug acme --name "Acme Corp" +``` + +**2. Thêm thành viên đầu tiên làm quản trị viên tổ chức:** + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member add --org acme --email alice@acme.example --set admin +``` + +Alice nhận được OTP lần đầu tiên cô đăng nhập vào bảng điều khiển. Từ đó trở đi, cô ấy làm việc hoàn toàn trong giao diện người dùng dưới tiền tố URL tổ chức của cô (ví dụ `/acme/sessions`). + +**3. Tạo khóa API cho mỗi tổ chức (trong bảng điều khiển):** + +Nhà vận hành **không** tạo khóa dữ liệu cho mỗi tổ chức từ CLI. Alice (hoặc bất kỳ thành viên tổ chức nào có `keys:create`) tạo khóa bộ sưu tập / bảng điều khiển cho tổ chức `acme` từ trang **Khóa** của bảng điều khiển. Mọi khóa cô tạo được tự động đóng dấu bằng tổ chức của cô và chỉ có thể đọc hoặc ghi dữ liệu của `acme`. Xem [Khóa API](/vi/agenteye/api-keys). + +**4. Điều chỉnh thành viên sau:** + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member update --org acme --email alice@acme.example --add alerts:write + +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member list --org acme +``` + +**5. Xóa mềm tổ chức** (thu hồi quyền truy cập + loại bỏ người dùng ClickHouse của nó; dữ liệu được giữ lại): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org delete --slug acme +``` + +**6. Thanh lọc tổ chức** (không thể đảo ngược; chỉ sau khi xóa mềm; không bao giờ tổ chức `default`): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org purge --slug acme +``` + +Trên Docker Compose, thay thế mỗi tiền tố `kubectl -n agenteye exec deploy/server --` bằng `docker compose exec server`. + +--- + +## Phân chia trách nhiệm + +Mọi thứ một thành viên tổ chức cần hàng ngày tự phục vụ trong bảng điều khiển và API, được phạm vi tự động cho tổ chức hiện tại của họ: + +- **Khóa API cho mỗi tổ chức** được tạo và quản lý bởi các thành viên tổ chức trong bảng điều khiển (hoặc thông qua API khóa với khóa mang `keys:create`). CLI **không** tạo khóa dữ liệu. Xem [Khóa API](/vi/agenteye/api-keys). +- **Chuyển đổi tổ chức** được xây dựng vào bảng điều khiển; các thành viên chuyển đổi giữa các tổ chức họ thuộc về từ bộ chuyển đổi tổ chức, và các trang có phạm vi tổ chức sống dưới `//…`. +- **Bảng điều khiển, truy vấn đã lưu, cảnh báo và tất cả việc sử dụng dữ liệu** xảy ra hoàn toàn trong giao diện người dùng và API, được phạm vi cho tổ chức hiện tại của thành viên. + +Nhà vận hành, sử dụng `agenteye-orgctl`, chỉ sở hữu vòng đời tổ chức + thành viên ****: tạo / đổi tên / xóa / thanh lọc một tổ chức và thêm / danh sách / cập nhật / xóa một thành viên. + +--- + +## Xem thêm + +- [Triển khai](/vi/agenteye/deployment): `ORG_CH_SECRET` và phần còn lại của môi trường máy chủ. +- [Triển khai Kubernetes](/vi/agenteye/kubernetes-deployment): §2.6 tạo Bí mật `agenteye-org-ch-secret` trước tổ chức đa tenant đầu tiên của bạn. +- [Khóa API](/vi/agenteye/api-keys): mô hình khóa cho mỗi tổ chức và các mã thông báo quyền được sử dụng bởi `--add` / `--remove`. +- [Khắc phục sự cố](/vi/agenteye/troubleshooting): các vấn đề về cung cấp đa tenant và cách ly ClickHouse. \ No newline at end of file diff --git a/docs/vi/agenteye/troubleshooting.mdx b/docs/vi/agenteye/troubleshooting.mdx new file mode 100644 index 00000000..797d11de --- /dev/null +++ b/docs/vi/agenteye/troubleshooting.mdx @@ -0,0 +1,594 @@ +--- +title: "Xử lý sự cố" +description: "Tài liệu xử lý sự cố AgentEye." +--- + + +Hướng dẫn này ánh xạ các triệu chứng bạn có khả năng gặp phải trong môi trường production đến một chẩn đoán cụ thể và cách khắc phục, để bạn có thể giải quyết sự cố từ các công cụ bạn đã có, mà không cần thiết lập thêm cơ sở hạ tầng quan sát. Nó bao gồm máy chủ, collector, dashboard, trợ lý AI, Python SDK, giám sát health và chứng chỉ, sao lưu, phân tích dựa trên ClickHouse và multi-tenancy. + +Các trang dashboard được phân biệt theo org dưới `//…`, và luồng sự kiện là trang chủ org (`//`). Tên trang trong hướng dẫn này (ví dụ `/sessions`, `/queries`) đề cập đến những route được phân biệt theo org đó. + +--- + +## Xem nhật ký + +AgentEye không đi kèm với stack logging hoặc monitoring. Cả máy chủ và dashboard đều ghi structured logs vào **stdout**, vì vậy bạn có thể đọc chúng trực tiếp bằng `kubectl` hoặc `docker`; không cần aggregator. + +### Kubernetes + +Theo dõi nhật ký trực tiếp cho máy chủ và dashboard: + +```bash +kubectl logs -n agenteye -l app=server -f --timestamps +kubectl logs -n agenteye -l app=dashboard -f --timestamps +``` + +Các biến thể hữu ích: + +| Mục đích | Lệnh | +|---|---| +| 200 dòng cuối cùng (không theo dõi) | `kubectl logs -n agenteye -l app=server --tail=200 --timestamps` | +| Nhật ký từ lần crash trước đó | `kubectl logs -n agenteye --previous` | +| Theo dõi tất cả các replica cùng một lúc | `kubectl logs -n agenteye -l app=server --max-log-requests=10 -f` | +| Postgres (StatefulSet) | `kubectl logs -n agenteye postgres-0 -f` | + +### Docker Compose + +```bash +docker logs -f agenteye-server +docker logs -f agenteye-dashboard +``` + +### Liên kết một yêu cầu duy nhất qua dashboard và máy chủ + +Mỗi yêu cầu dashboard được gắn thẻ với `request_id` và được lan truyền đến máy chủ qua header `x-request-id`. Máy chủ phản hồi nó trong header phản hồi và trong mỗi dòng nhật ký mà nó phát hành cho yêu cầu đó. Để theo dõi một yêu cầu từ đầu đến cuối: + +1. Ghi lại id từ header phản hồi, ví dụ: + ```bash + curl -i https://dashboard.example.com/api/events | grep -i x-request-id + # x-request-id: 9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a + ``` +2. Grep nhật ký của cả hai pod cho id đó: + ```bash + REQ=9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a + kubectl logs -n agenteye -l app=dashboard --tail=5000 | grep "$REQ" + kubectl logs -n agenteye -l app=server --tail=5000 | grep "$REQ" + ``` + +Bạn sẽ thấy các dòng `proxy passthrough`, `withAuth: authorized` và `upstream response` của dashboard cùng với cặp `http request received` / `http request completed` của máy chủ, tất cả đều chia sẻ `request_id` giống nhau. + +### JSON logs và `jq` + +Đặt `AE_LOG_JSON=1` trên dashboard (nó được bật mặc định khi `NODE_ENV=production`) để phát hành một đối tượng JSON trên mỗi dòng. Sau đó lọc cấu trúc: + +```bash +kubectl logs -n agenteye -l app=dashboard --tail=5000 \ + | jq 'select(.level == "warn" or .level == "error")' + +kubectl logs -n agenteye -l app=dashboard --tail=5000 \ + | jq 'select(.route == "POST /api/keys")' +``` + +Máy chủ Rust phát hành các cặp `key=value` tracing mà grep tốt mà không cần `jq`: + +```bash +kubectl logs -n agenteye -l app=server --tail=5000 | grep 'status=5' # 5xx +kubectl logs -n agenteye -l app=server --tail=5000 | grep 'actor_key_id=' +``` + +### Tăng mức chi tiết + +| Thành phần | Biến môi trường | Ví dụ | +|---|---|---| +| Server | `RUST_LOG` | `RUST_LOG=debug` hoặc `RUST_LOG=agenteye_server=debug,info` | +| Dashboard | `AE_LOG_LEVEL` | `AE_LOG_LEVEL=debug` | + +`debug` trên máy chủ thêm một dòng `api key authenticated` cho mỗi auth. `debug` trên dashboard thêm các dòng `upstream request`, `session validated` và `proxy passthrough`. + +### Giữ lại nhật ký + +Stdout của container là tạm thời; kubelet xoay vòng các tệp nhật ký (mặc định ~10 MiB trên mỗi container) và giữ một số ít trên đĩa. Khi một pod bị xóa, nhật ký cũng biến mất. Nếu bạn cần giữ lâu hơn hoặc tìm kiếm giữa các pod, hãy trỏ cluster của bạn đến bộ thu log (Loki, CloudWatch, Cloud Logging, Datadog, v.v.) theo dõi `/var/log/containers/`. AgentEye không yêu cầu hoặc quy định bất kỳ lựa chọn cụ thể nào. + +--- + +## Các vấn đề xác thực + +### `docker pull` không thành công với "unauthorized" + +Đảm bảo bạn đã xác thực Docker đối với GHCR bằng `AGENTEYE_TOKEN`: + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +Token phải có quyền `read:packages` trên org `agenteye-enterprise`. Liên hệ `support@exosphere.host` nếu token của bạn không hoạt động. + +### `gh release download` trả về 404 hoặc 401 + +- Xác nhận `AGENTEYE_TOKEN` được xuất trong shell của bạn: `echo $AGENTEYE_TOKEN` +- Xác nhận bạn đang sử dụng `GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download ...` (CLI `gh` đọc `GITHUB_TOKEN`) +- Token cần `contents:read` trên `agenteye-enterprise/releases` + +--- + +## Các vấn đề máy chủ + +### Máy chủ không thành công với "invalid port number" + +`POSTGRES_PASSWORD` (hoặc thông tin xác thực khác) chứa các ký tự đặc biệt của URL (`/`, `+`, `=`) làm phá vỡ phân tích cú pháp `DATABASE_URL`. Tạo lại mật khẩu bằng mã hóa hex: + +```bash +NEW_PASS=$(openssl rand -hex 24) +``` + +Sau đó cập nhật Kubernetes secret và mật khẩu bên trong Postgres (hoặc tạo lại `.env` cho Docker Compose), và khởi động lại máy chủ. Xem các bước đầy đủ trong [enterprise-docs/kubernetes-deployment.md](/vi/agenteye/kubernetes-deployment) § "PostgreSQL credentials". + +### Máy chủ thoát ngay lập tức khi khởi động + +Kiểm tra nhật ký container: + +```bash +docker logs agenteye-server +``` + +Các nguyên nhân phổ biến: +- `DATABASE_URL` không được đặt hoặc có định dạng sai: máy chủ sẽ ghi lại lỗi và thoát. +- Postgres không thể truy cập được: xác nhận container Postgres hoặc managed DB đang chạy và host/port chính xác. +- Migrations không thành công: kiểm tra nhật ký để tìm lỗi SQL. + +### `GET /health` trả về non-200 hoặc timeout + +Máy chủ vẫn có thể đang chạy migrations khi khởi động lần đầu. Đợi một vài giây và thử lại: + +```bash +curl http://localhost:8080/health +``` + +Nếu vấn đề vẫn tiếp tục, hãy kiểm tra `docker logs agenteye-server` để tìm lỗi. + +### `GET /ready` trả về 503 + +`/ready` là readiness probe: nó trả về `503` khi máy chủ không thể truy cập **Postgres hoặc ClickHouse**. Phần thân đặt tên phụ thuộc không thành công: + +```bash +curl -s http://localhost:8080/ready +# {"status":"not_ready","checks":{"postgres":"ok","clickhouse":"down","redis":"ok"}} +``` + +Sửa phụ thuộc nào mà nó báo cáo là `down`: pod ClickHouse/Postgres có `Running` không? `CLICKHOUSE_URL` / `DATABASE_URL` có chính xác và có thể truy cập được không? Trên Kubernetes, pod đọc `NotReady` cho đến khi `/ready` khôi phục; điều đó là bình thường và chính xác là tín hiệu để giám sát health cảnh báo. Redis không bao giờ là nguyên nhân: nó được báo cáo nhưng không làm hỏng readiness. + +### Collector trả về 401 Unauthorized + +API key của collector không có quyền `events:add`, hoặc key đã bị vô hiệu hóa. Tạo key mới với quyền chính xác: + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{"name":"new-collector","permissions":["events:add"]}' +``` + +### Các yêu cầu được xác thực đột ngột chậm (~200ms thay vì ~5ms) + +Đây là triệu chứng của Redis bị down trong khi `REDIS_URL` được đặt. Mỗi lệnh gọi cache timeout sau 100ms rồi rơi vào Postgres; trên các đường dẫn auth và OTP, yêu cầu tạo ra hai lần rơi như vậy. + +Xác nhận trong nhật ký máy chủ: + +``` +auth cache: L2 get failed error=redis call timed out +``` + +Giải pháp: + +1. `redis-cli -h ping` để xác nhận Redis có thể truy cập được trên mạng cluster. +2. Nếu Redis bị down tạm thời và hiện tại lại hoạt động, **khởi động lại server pods**. `redis::aio::ConnectionManager` không tái thiết lập đáng tin cậy sau khi kết nối cơ bản bị ngắt; khởi động lại pod tải kết nối mới một cách sạch sẽ. Điều tương tự cũng áp dụng cho dashboard. +3. Nếu bạn không muốn chạy Redis ngay bây giờ, hãy bỏ đặt `REDIS_URL` trong deployment và khởi động lại. Cả hai dịch vụ chạy mà không có cache (độ chính xác được bảo tồn; độ trễ quay trở lại baseline trước Redis). + +### Máy chủ báo cáo `OTP request rate-limited` trong nhật ký nhưng người dùng nói họ chỉ thử một lần + +Kiểm tra xem Redis có bị không thể truy cập được không. Đường dẫn fallback sử dụng `SELECT COUNT(*) FROM otp_codes WHERE created_at > now() - interval '15 minutes'`, nó nhìn thấy các hàng OTP được tạo trước đó. Nếu người dùng đã nhấp vào "Resend" suốt một giờ, cửa sổ 15 phút có thể vẫn chứa ≥5 mã. Giải quyết bằng cách chờ cửa sổ cuộn qua hoặc `DELETE FROM otp_codes WHERE user_id = $1 AND created_at > now() - interval '15 minutes'` (bảng điều khiển nhà điều hành). + +### Tôi đã thay đổi `ALLOWED_EMAILS` / `SESSION_TTL_SECS` / `OTP_TTL_SECS` và khởi động lại; không có gì xảy ra + +Các biến môi trường này là **first-boot seeds chỉ**. Khi bảng `settings` có một hàng cho khóa phù hợp, hàng đó là nguồn sự thật; biến môi trường được đọc một lần khi khởi động lần đầu rồi bị bỏ qua ở mọi lần khởi động lại tiếp theo. + +Để thay đổi chúng sau khi khởi động lần đầu, hãy đăng nhập vào dashboard và chỉnh sửa chúng dưới `/settings`. Thay đổi được áp dụng trong vòng một vài giây trên tất cả các replica; không cần khởi động lại. + +Nếu bạn cần buộc re-seed từ env (hiếm, thường chỉ hữu ích trong phát triển), `DELETE FROM settings WHERE key = ''` và khởi động lại máy chủ. Bootstrap sẽ nhận giá trị biến môi trường hiện tại khi khởi động lần tiếp theo. Chỉnh sửa qua `/settings` là con đường được hỗ trợ trong production. + +--- + +## Các vấn đề Collector + +### Collector bắt đầu nhưng các sự kiện không xuất hiện trong dashboard + +1. Xác nhận collector đang chạy: `systemctl status agenteye-collector` (Linux) hoặc kiểm tra quy trình. +2. Xác nhận `AGENTEYE_URL` trỏ đến `http(s)://your-server-host:8080/events` (lưu ý: đường dẫn `/events`). +3. Chạy một flush một lần để xem đầu ra ngay lập tức: + ```bash + agenteye-collector flush + ``` +4. Kiểm tra xem Python SDK có thực sự ghi các tệp không: `ls ${AGENTEYE_HOME:-~/.agenteye}/events/` +5. Nếu các tệp tồn tại trong `${AGENTEYE_HOME:-~/.agenteye}/failed/`, các uploads đang thất bại. Kiểm tra nhật ký collector để tìm lỗi, có khả năng là 4xx (bad key hoặc URL) hoặc sự cố mạng. + +### Các tệp đang tích lũy trong `$AGENTEYE_HOME/events/` và không được tải lên + +- Collector có thể không chạy. Khởi động nó: `agenteye-collector start`; nó tự động flush các sự kiện đã tồn tại khi khởi động. +- Kiểm tra health của collector: `agenteye-collector health` +- Collector có thể chạy nhưng không thể tiếp cận máy chủ. Kiểm tra quy tắc tường lửa giữa các host collector và máy chủ. + +### Các tệp trong `$AGENTEYE_HOME/failed/` + +Các tệp chuyển đến `failed/` sau khi tất cả các lần thử lại bị cạn kiệt (mặc định: 5 lần với backoff hàm mũ). Điều này có nghĩa là: +- Máy chủ trả về lỗi 4xx (bad key, URL sai, hoặc sự cố payload) +- Máy chủ không thể truy cập được cho toàn bộ cửa sổ thử lại + +Sửa vấn đề cơ bản, sau đó xếp hàng lại thủ công: + +```bash +mv ${AGENTEYE_HOME:-~/.agenteye}/failed/*.jsonl ${AGENTEYE_HOME:-~/.agenteye}/events/ +agenteye-collector flush +``` + +### Collector báo cáo `network error` trên mọi lần tải lên (TLS handshake không thành công) + +Nếu `curl -k` đối với `AGENTEYE_URL` thành công nhưng nhị phân collector thất bại mọi lần tải với `error sending request for url (...)`, máy chủ AgentEye đang trình bày chứng chỉ TLS không được ký bởi CA đáng tin cậy công khai. + +**Đường dẫn production** là tên máy chủ ingest ACME được cấu hình trong `deploy/base/certificates/domain.env` (xem [`kubernetes-deployment.md`](/vi/agenteye/kubernetes-deployment) Phase 3.1 / 4.2). Khi `INGEST_DOMAIN` phân giải thành public Traefik LB và cert-manager đã cấp chứng chỉ Let's Encrypt, collectors xác minh chứng chỉ máy chủ dựa trên cây tin cậy hệ thống với **không cần `AGENTEYE_TLS_CA`**; xóa nó khỏi cấu hình collector của bạn nếu nó được đặt chống lại việc triển khai tự ký cũ hơn. + +**Triệu chứng: collector hoạt động hôm qua, thất bại hôm nay sau khoảng 90 ngày.** Điều này có nghĩa là triển khai vẫn còn trên issuer `selfsigned` cũ cho `ingest-tls`. Chứng chỉ 90 ngày xoay vòng và tệp CA được ghim là đã lỗi thời. Sửa vĩnh viễn bằng cách chuyển cluster sang issuer ACME (Phase 3.1 của hướng dẫn triển khai). Giải pháp ngắn hạn: tái trích xuất chứng chỉ máy chủ hiện tại và cập nhật `AGENTEYE_TLS_CA`: + +```bash +kubectl get secret ingest-tls-cert -n agenteye \ + -o jsonpath='{.data.tls\.crt}' | base64 -d > /etc/agenteye/server-ca.crt +``` + +```bash +export AGENTEYE_TLS_CA=/etc/agenteye/server-ca.crt +agenteye-collector flush +``` + +`AGENTEYE_TLS_CA` thêm một neo tin cậy bổ sung; các gốc công khai tiêu chuẩn vẫn được tin cậy. + +### Chứng chỉ `ingest-tls` bị kẹt `Ready: False` sau khi triển khai + +```bash +kubectl describe certificate ingest-tls -n agenteye +``` + +Nhìn vào `Events` và `Order` / `Challenge` được tham chiếu. Các nguyên nhân phổ biến: + +- **DNS không phân giải thành public LB.** Trình xác nhận HTTP-01 không thể truy cập `INGEST_DOMAIN`. Xác minh với `dig +short INGEST_DOMAIN`; nó phải phân giải thành cùng một địa chỉ với `traefik-public` LoadBalancer's `EXTERNAL-IP`. cert-manager tự động thử lại khi DNS lan truyền; không cần xóa Chứng chỉ. +- **Port 80 bị chặn ở load balancer / security group.** HTTP-01 yêu cầu port 80 có thể truy cập được từ các bộ xác nhận công khai của Let's Encrypt. Nếu bạn có WAF upstream hoặc SG hạn chế `:80`, hãy mở nó (cấu hình Traefik chuyển hướng đến HTTPS, nhưng Boulder theo dõi chuyển hướng và chấp nhận phản hồi). +- **`dnsNames` không được thay thế.** Nếu `kubectl get certificate ingest-tls -n agenteye -o jsonpath='{.spec.dnsNames}'` cho thấy `INGEST_DOMAIN_PLACEHOLDER`, bạn đã bỏ qua bước `domain.env`; tạo nó từ `domain.env.example` và áp dụng lại. +- **Bị giới hạn tốc độ bởi Let's Encrypt.** Các đơn hàng thất bại lặp lại cho cùng một tên máy chủ kích hoạt giới hạn chứng chỉ trùng lặp hoặc xác thực thất bại. Đợi ít nhất một giờ trước khi thử lại; kiểm tra trạng thái Order để tìm thông báo giới hạn tốc độ chính xác. + +### Chứng chỉ `dashboard-tls` bị kẹt `Ready: False` / trình duyệt vẫn hiển thị cảnh báo + +Cùng dòng chẩn đoán như `ingest-tls` ở trên (`kubectl describe certificate dashboard-tls -n agenteye`); các nguyên nhân DNS, port-80, placeholder và rate-limit đều áp dụng, cộng với hai nguyên nhân cụ thể dashboard: + +- **`DASHBOARD_DOMAIN` phân giải thành LoadBalancer sai.** Nó phải trỏ đến *dashboard* Traefik LB, không phải ingest công khai. `dig +short` tên máy chủ và so sánh với địa chỉ LB dashboard. +- **Dashboard Traefik instance không thể phục vụ challenge.** Nó phải được cài đặt với tệp giá trị dashboard được đặt kèm, cho phép Ingress provider phạm vi cho trình giải quyết HTTP-01 của cert-manager. Không có nó, trình giải quyết không có thể định tuyến được và Đơn hàng vẫn `pending` mãi mãi. Nâng cấp instance với các giá trị được cung cấp; challenge đang chờ xử lý sau đó hoàn thành tự động. +- **LoadBalancer bị hạn chế IP.** Phạm vi nguồn áp dụng cho port 80 cũng, điều này chặn các bộ xác nhận của Let's Encrypt — cả lần cấp đầu tiên và mỗi lần gia hạn ~75 ngày. Mở lại LB, hoặc phối hợp một trình giải quyết DNS-01 với hỗ trợ trước khi khóa nó. + +Khi cấp phát đang thất bại, dashboard tiếp tục phục vụ chứng chỉ trước đó của nó (hoặc mặc định ingress trên cài đặt mới) — truy cập bị suy giảm bởi cảnh báo trình duyệt, không bao giờ bị ngắt. + +### CLI vẫn bỏ qua xác minh TLS sau khi dashboard có chứng chỉ đáng tin cậy + +`--insecure` được duy trì vào `cli.json` khi đăng nhập. Khi dashboard phục vụ chứng chỉ công khai đáng tin cậy, hãy đăng nhập lại bằng `agenteye --base-url https:// --secure login`; xác minh được lưu lại và cảnh báo khởi động biến mất. + +--- + +## Các vấn đề Dashboard + +### Không thể vô hiệu hóa hoặc chỉnh sửa người dùng `ADMIN_EMAIL` + +Thiết kế. Người dùng khớp với `ADMIN_EMAIL` được đánh dấu bảo vệ ở mỗi lần khởi động máy chủ: dashboard ẩn nút Disable cho hàng đó, và API từ chối `DELETE /users/:id` và `PUT /users/:id` chống lại nó với `403 Forbidden`. Trigger cơ sở dữ liệu cũng từ chối các câu lệnh `UPDATE` trực tiếp sẽ vô hiệu hóa hàng được bảo vệ. + +Để xoay bootstrap admin, hãy thay đổi `ADMIN_EMAIL` trong môi trường của bạn và khởi động lại máy chủ. Email mới được upsert như bảo vệ. Admin trước đó giữ lại cờ bảo vệ cho đến khi được xóa trong cơ sở dữ liệu (thường tốt, vì email trước đó vẫn là admin hợp lệ cho đến khi bạn rõ ràng xóa họ). + +### Dashboard không hiển thị sự kiện + +1. Xác nhận URL máy chủ và API key chính xác trong các biến môi trường của dashboard (`AGENTEYE_SERVER_URL`, `AGENTEYE_API_KEY`). +2. API key dashboard cần quyền `events:read`. +3. Xác nhận các sự kiện đã được ingested thực sự: `curl http://your-server:8080/events -H "Authorization: Bearer $ADMIN_KEY"` + +### `/errors` trống nhưng `/events` hiển thị các hàng đỏ + +Các phiên bản SDK mới hơn phát hành các lỗi như các sự kiện `agent_end` / `tool_result` / `hook_completed` với `outcome: "error"` trong payload, chứ không phải như hàng `event_type: "error"` chuyên dụng. Trang `/errors` giờ đây khớp với cả hai: bất kỳ hàng nào luồng `/events` sơn đỏ (`event_type='error'` rõ ràng, `outcome`/`status` payload trong tập thất bại, `is_error: true`, hoặc trường `error` truthy) xuất hiện trên `/errors`. Nếu trước đây bạn thấy "không có lỗi trong cửa sổ này" trong khi các hàng đỏ được hiển thị trên `/events`, hãy nâng cấp dashboard + máy chủ cùng nhau (bộ lọc mở rộng là `errored=true` trên `GET /events`) và hai chế độ xem sẽ đồng ý. + +### `/models`, `/tools`, hoặc `/hooks` chậm hoặc không tải trên phạm vi thời gian rộng + +**Triệu chứng:** trên bảng sự kiện lớn (hàng triệu hàng), mở `/models`, `/tools`, hoặc `/hooks` — hoặc mở rộng phạm vi thời gian thành `7d`, `30d`, hoặc `all` — các biểu đồ xoay và sau đó hiển thị lỗi tải. Máy chủ ghi nhật ký `MEMORY_LIMIT_EXCEEDED` ClickHouse (Code 241) hoặc timeout truy vấn cho yêu cầu `latency_aggregate`. + +**Nguyên nhân:** các bản dựng cũ hơn tính toán các rollup latency và phân phối trang này bằng một truy vấn đọc `payload` sự kiện thô hoàn chỉnh và ghép các sự kiện request/response với sắp xếp và kết hợp trong bộ nhớ. Do đó, bộ nhớ truy vấn đỉnh phát triển theo kích thước cửa sổ, vì vậy trên tenant bận rộn, một phạm vi rộng có thể vượt quá trần bộ nhớ cho mỗi truy vấn ClickHouse. + +**Sửa:** nâng cấp lên bản dựng bao gồm sửa chữa này. Rollup giờ đây chỉ đọc các cột được quảng bá nhỏ gọn và ghép các sự kiện với tổng hợp truyền phát, vì vậy bộ nhớ đỉnh không còn mở rộng theo payload thô — các cửa sổ rộng vẫn nằm trong trần bộ nhớ và trả về trong một phần thời gian. Sự cải thiện hoàn toàn là query-side: nó áp dụng cho tất cả các dữ liệu hiện có khi tải trang tiếp theo, không có re-ingest hoặc backfill. + +### Dashboard không tải được / trang trắng + +Kiểm tra nhật ký container dashboard: + +```bash +docker logs agenteye-dashboard +``` + +Nguyên nhân phổ biến nhất là `AGENTEYE_SERVER_URL` hoặc `AGENTEYE_API_KEY` bị thiếu hoặc trỏ đến máy chủ không thể truy cập được. + +### Phân tích / telemetry dashboard + +Dashboard gửi phân tích sử dụng sản phẩm ẩn danh cho PostHog mặc định, được định tuyến qua đường dẫn `/ingest` của chính dashboard (một reverse proxy cho `https://us.i.posthog.com`). Gửi chúng first-party có nghĩa là ad-blocker trình duyệt không bỏ chúng. Điều này độc lập với chức năng cốt lõi của dashboard: + +- **Container dashboard** (không phải trình duyệt) là những gì đạt PostHog. Nếu truy cập outbound của nó đến `https://us.i.posthog.com` bị chặn, telemetry im lặng no-ops; dashboard hoạt động bình thường và không có lỗi nào được hiển thị cho người dùng. +- Dữ liệu agent, session hoặc event không bao giờ được đưa vào, chỉ là sử dụng UI dashboard. +- Để vô hiệu hóa telemetry hoàn toàn, hãy đặt `AE_ANALYTICS_DISABLED=1` trên container dashboard và khởi động lại. Xem [Telemetry & privacy](/vi/agenteye/deployment#telemetry--privacy) trong hướng dẫn triển khai. + +### Telemetry / analytics CLI + +CLI `agenteye` gửi phân tích sử dụng ẩn danh cho PostHog mặc định: các lệnh nào chạy, trạng thái thành công/thoát, và khoảng thời gian. Điều này độc lập với chức năng CLI: + +- **Máy chạy CLI** đạt `https://us.i.posthog.com` trực tiếp. Nếu truy cập outbound của nó bị chặn, telemetry im lặng no-ops (gửi được giới hạn thời gian, vì vậy nó không bao giờ làm chậm lệnh) và CLI hoạt động bình thường. +- Dữ liệu agent, session hoặc event không bao giờ được đưa vào: **đối số lệnh và giá trị cờ** (URL dashboard, token, email, session ids, bộ lọc truy vấn) không bao giờ được gửi. +- Để vô hiệu hóa nó, hãy đặt `AGENTEYE_ANALYTICS_DISABLED=1` (hoặc `DO_NOT_TRACK=1` cross-tool) trong môi trường CLI. Xem [Telemetry & privacy](/vi/agenteye/cli#telemetry--privacy) trong hướng dẫn CLI. + +--- + +## Các vấn đề trợ lý AI + +Xem [enterprise-docs/assistant.md](/vi/agenteye/assistant) để thiết lập đầy đủ. + +### Bubble trợ lý không xuất hiện + +Bubble ẩn trừ khi **tất cả** những điều này giữ: + +- Người dùng đã đăng nhập có quyền `agent:use`. +- `AGENTEYE_AGENT_URL` được đặt trên dashboard và dịch vụ `agent` có thể truy cập được. +- Một điểm cuối LLM được cấu hình trên dịch vụ `agent` (`ANTHROPIC_API_KEY`, gateway qua `ANTHROPIC_BASE_URL`, hoặc Bedrock/Vertex). Không có bộ nào được đặt, agent báo cáo "not configured" và bubble ở ẩn. + +Kiểm tra health của agent từ host dashboard: `curl http://agent:9100/health` sẽ trả về `{"status":"ok","llm_configured":true,...}`. + +### Trợ lý nói nó không thể đọc cái gì đó + +Công cụ được gated theo người dùng. Nếu người dùng thiếu `evaluations:read` (hoặc `events:read`, `dashboards:read`), các công cụ phù hợp không được cung cấp và trợ lý sẽ nói nó không thể đọc dữ liệu đó. Cấp quyền đọc liên quan. + +### "assistant not configured" (HTTP 503) khi gửi + +Container `agent` không có điểm cuối LLM được cấu hình, hoặc `AGENTEYE_AGENT_TOKEN` của dashboard không khớp với agent. Đặt cả hai và khởi động lại. + +### Container `agent` khởi động lại / OOMs dưới tải + +Mỗi cuộc trò chuyện sinh ra một quá trình con tồn tại ngắn. Đảm bảo container chạy với một quá trình init (hình ảnh sử dụng `tini`; trong Compose đặt `init: true`) và cung cấp cho nó giới hạn bộ nhớ thích hợp. Giảm `AGENTEYE_AGENT_MAX_STEPS` nếu cần. + +--- + +## Các vấn đề CLI + +### `agenteye` không khởi động được với `ModuleNotFoundError: No module named 'click'` + +Cài đặt tươi `agenteye` CLI ở phiên bản **0.1.6** có thể gặp sự cố khi khởi động với: + +``` +ModuleNotFoundError: No module named 'click' +``` + +0.1.6 dựa vào `click` được cài đặt gián tiếp bởi `typer`; các bản phát hành `typer` hiện tại không còn kéo theo nó, vì vậy môi trường sạch sẽ kết thúc thiếu gói. **Nâng cấp lên 0.1.7 hoặc mới hơn**, phụ thuộc vào `click` trực tiếp: + +```bash +pipx upgrade agenteye # nếu cài đặt bằng pipx (hoặc: pipx install --force agenteye) +uv tool upgrade agenteye # nếu cài đặt bằng uv +pip install --upgrade agenteye +``` + +Xem [enterprise-docs/cli.md](/vi/agenteye/cli) để hướng dẫn cài đặt. + +--- + +## Các vấn đề Python SDK + +### Không có tệp nào xuất hiện trong `$AGENTEYE_HOME/events/` + +SDK lưu đệm các sự kiện và flush mỗi 500 ms theo mặc định. Nếu quá trình của bạn thoát trước flush, các sự kiện có thể bị mất. Gọi `agenteye.configure(flush_interval=0.1)` để flush nhanh hơn trong các script có thời gian sống ngắn, hoặc đảm bảo quá trình của bạn chạy đủ lâu để một chu kỳ flush. + +Nếu `AGENTEYE_HOME` được đặt, hãy xác minh SDK đang ghi vào `$AGENTEYE_HOME/events/` và không phải `~/.agenteye/events/` (yêu cầu SDK ≥ 0.0.1b5). + +### `ValueError: Reserved field names cannot be used as custom fields` + +Tên `timestamp`, `type` và `environment` được dành riêng và không thể được sử dụng làm trường tùy chỉnh. Chuyển bất kỳ chúng tăng: + +``` +ValueError: Reserved field names cannot be used as custom fields: [...] +``` + +Đổi tên trường tùy chỉnh vi phạm. Lưu ý rằng `session_id` và `agent_id` là tham số rõ ràng của lệnh gọi sự kiện, không phải trường tùy chỉnh; chuyển cái nào lại làm trường tùy chỉnh tăng `TypeError`. + +--- + +## Các vấn đề giám sát health + +### Không có cảnh báo nào đến Slack (Robusta) + +Cảnh báo health Robusta là **opt-in**; nó không gửi gì cho đến khi được cài đặt và trỏ đến kênh Slack. Xác minh bản phát hành và sink của nó: + +```bash +kubectl get pods -n robusta # robusta-runner + robusta-forwarder nên Running +kubectl logs -n robusta -l app=robusta-runner --tail=50 +``` + +Nguyên nhân phổ biến: `api_key` / `slack_channel` Slack không được đặt (hoặc token bị thu hồi); `api_key` là token cloud-relay Robusta (`robusta integrations slack`) nhưng `disableCloudRouting: true` được đặt kèm cần token **bot** Slack tự lưu trữ (`xoxb-…`), hoặc đặt `disableCloudRouting: false`; sink `scope` loại trừ namespace pods của bạn chạy trong (các giá trị được đặt kèm phạm vi đến `agenteye`); hoặc chưa có lỗi nào xảy ra. Buộc một cảnh báo thử bằng cách hạ pod: + +```bash +kubectl -n agenteye delete pod -l app=clickhouse # nó sẽ được tạo lại +``` + +Xem [enterprise-docs/health-monitoring.md](/vi/agenteye/health-monitoring#2-pod-failure-alerting-with-robusta-opt-in) để cài đặt và cấu hình. + +### Máy chủ giữ flapping `NotReady` + +Readiness probe hits `/ready`, nó không thành công khi Postgres hoặc ClickHouse không thể truy cập được. Nếu máy chủ chu kỳ trong và ngoài `NotReady`, một phụ thuộc là không thể truy cập được từng lúc; kiểm tra các pod ClickHouse và Postgres và `CLICKHOUSE_URL` / `DATABASE_URL` của máy chủ. Xác nhận `/ready` báo cáo: + +```bash +kubectl -n agenteye exec deploy/server -- sh -c 'curl -s localhost:8080/ready' +``` + +Probe này được cố ý khoan dung (ngưỡng thất bại hào phóng), vì vậy flapping kéo dài cho thấy vấn đề phụ thuộc thực tế chứ không phải probe quá tích cực. Liveness ở lại `/health`, vì vậy flapping readiness sẽ **không** khởi động lại pod. + +## Các vấn đề giám sát chứng chỉ + +### CronJob không gửi thông báo Slack + +`cert-renewal-check` CronJob yêu cầu URL webhook Slack được lưu trữ trong một Secret. Xác minh nó tồn tại: + +```bash +kubectl get secret cert-renewal-notify-config -n agenteye +``` + +Nếu thiếu, hãy tạo nó: + +```bash +kubectl create secret generic cert-renewal-notify-config \ + --namespace agenteye \ + --from-literal=SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL" +``` + +Không có secret, CronJob vẫn chạy và ghi kết quả vào stdout. Kiểm tra nhật ký với: + +```bash +kubectl logs -n agenteye -l job-name --tail=50 +``` + +### Chứng chỉ khách hàng hết hạn trước khi nhận được thông báo + +CronJob chạy mỗi 12 giờ. Nếu nó chưa chạy, hãy kiểm tra trạng thái của nó: + +```bash +kubectl get cronjob cert-renewal-check -n agenteye +``` + +Kích hoạt một kiểm tra thủ công: + +```bash +kubectl create job --from=cronjob/cert-renewal-check manual-cert-check -n agenteye +kubectl logs -n agenteye -l job-name=manual-cert-check +``` + +Để tái cấp chứng chỉ hết hạn ngay: + +```bash +cd base/certificates/client-certs +./issue-client-cert.sh +``` + +Sau đó áp dụng `collector-mtls-secret.yaml` được tạo lại trong cluster(s) chạy collectors của bạn và khởi động lại chúng: + +```bash +kubectl apply -f collector-mtls-secret.yaml -n +``` + +--- + +## Các vấn đề sao lưu + +### `agenteye-backup` không thành công với "No space left on device" + +CronJob `agenteye-backup` xả Postgres + ClickHouse vào scratch volume `backup-tmp` `emptyDir` (mặc định `30Gi`), sau đó **streams** lưu trữ `tar` thẳng đến S3 — lưu trữ nén không bao giờ được ghi lại vào scratch, vì vậy scratch chỉ cần giữ **raw dumps**, không dumps + sao chép lưu trữ on-disk thứ hai. Pod evicted / `No space left on device` do đó có nghĩa là **raw dumps** vượt quá kích thước scratch (dump ClickHouse `events` chiếm ưu thế và phát triển theo thời gian). Kiểm tra nhật ký của công việc không thành công: + +```bash +kubectl logs -n agenteye -l job-name= +``` + +Sửa: trong overlay của bạn, tăng `sizeLimit` `emptyDir` `backup-tmp` của CronJob vượt quá raw dump tổng cộng, và đảm bảo node có thể thực sự giữ nó (`sizeLimit` là một cap, không phải đặt trước). Nếu dumps vượt quá đĩa của một nút duy nhất, hãy thay thế `emptyDir` bằng PVC (EBS/PD) cho `backup-tmp`, hoặc nén dumps ở nguồn. + +> Các bản phát hành cũ hơn ghi `.tar.gz` vào *cùng* `20Gi` scratch như dumps, vì vậy `dumps + archive` tràn nó và pod được evicted **trước** upload chạy — điều này trông giống như lỗi S3 nhưng thực sự là đĩa. Streaming upload loại bỏ sự tăng gấp đôi đó. + +### `agenteye-backup` không thành công cài đặt `curl` + +Công việc chạy trên hình ảnh `postgres:16` và cài đặt `curl` khi khởi động để dump ClickHouse HTTP. Trên một cluster không có egress đến các gương gói Debian, bước `apt-get` không thành công. Hoặc cho phép egress đó từ backup pod, hoặc bake `curl` vào hình ảnh backup được soi kính/tùy chỉnh và tham chiếu nó trong overlay của bạn. + +### `agenteye-backup` chạy nhưng không có gì hạ xuống kho lưu trữ đối tượng + +Base vận chuyển một `BACKUP_BUCKET` thực (`ts-prod-agenteye/backups`) và `agenteye-backup` ServiceAccount. Công việc **streams** lưu trữ đến S3 (`tar cz … | aws s3 cp - s3://…`). Nếu backup pod không có quyền ghi vào bucket, upload lỗi — và vì script chạy dưới `set -euo pipefail`, một lỗi bất cứ nơi nào trong pipe đó **thất bại** toàn bộ công việc ở bước `upload` chứ không im lặng no-op (trap EXIT của pod ghi nhật ký `backup FAILED during step: upload`). Đây cũng là bước bạn tiếp cận *sau* khi sửa lỗi khoảng trắng scratch, vì vậy nếu backups trước đây bị evicted ở bước lưu trữ, hãy xác minh upload hiện tại hạ xuống. Grep nhật ký công việc không thành công để tìm lỗi S3: + +```bash +kubectl logs -n agenteye -l job-name= | grep -iE 's3|upload|denied' +``` + +Sửa: trong overlay của bạn đặt `BACKUP_BUCKET` thành bucket bạn sở hữu và chú thích `agenteye-backup` ServiceAccount hiện có bằng quyền ghi (IRSA / Workload Identity / Pod Identity). Xem phần **Backups** của [enterprise-docs/kubernetes-deployment.md](/vi/agenteye/kubernetes-deployment). + +--- + +## Đánh giá / sessions / queries dựa trên ClickHouse + +### Sidebar trang `/queries` trống sau khi nâng cấp + +Ba bảng (`events`, `evaluations`, `agent_sessions`) được dự kiến. Nếu sidebar SchemaBrowser trống sau khi nâng cấp, máy chủ không áp dụng DDL ClickHouse khi khởi động. Kiểm tra nhật ký máy chủ để tìm `failed to apply CH DDL statement`: + +```bash +kubectl logs -n agenteye deploy/server | grep -E 'clickhouse|CH DDL' +``` + +Nguyên nhân phổ biến nhất là ClickHouse không thể truy cập được trong khi migrations chạy. Máy chủ từ chối khởi động nếu không thể tiếp cận CH, vì vậy một pod bị kẹt thường có `CrashLoopBackOff` chứ không phải trang queries im lặng bị hỏng, nhưng DDL partial apply (một câu lệnh OK, 5 tiếp theo 5xx) để lại schema nửa nướng. Khởi động lại server pod sau khi CH được xác minh có thể truy cập: + +```bash +kubectl rollout restart deploy/server -n agenteye +``` + +### Các đánh giá mới không xuất hiện trong `/sessions` hoặc `/queries` + +Sau khi nâng cấp, các đánh giá mới được ghi vào ClickHouse, không phải Postgres, và bề mặt dưới `/sessions` (gated trên `evaluations:read`) và trong `/queries`. Nếu chúng không xuất hiện: + +1. Xác nhận đường dẫn evaluator được bật (`EVALUATOR_ENDPOINT` được đặt trên máy chủ) và sản xuất các kết quả terminal; kiểm tra các dòng `evaluation_finalized`. +2. Xác nhận CH có thể truy cập được từ máy chủ: `kubectl exec -n agenteye deploy/server -- curl -fsS http://clickhouse:8123/ping`. +3. Kiểm tra kỹ bảng CH: `kubectl exec -n agenteye clickhouse-0 -- clickhouse-client -q 'SELECT count() FROM agenteye.evaluations'`. + +### Truy vấn thất bại dưới tải bằng "Memory limit exceeded", hoặc ClickHouse bị `OOMKilled` + +**Triệu chứng:** dưới tải dashboard/truy vấn nặng, các trang phân tích (luồng sự kiện, `/sessions`, chế độ xem models/latency, trình chỉnh sửa SQL) bắt đầu thất bại hoặc timeout; máy chủ flaps `NotReady` một lúc; và pod ClickHouse hiển thị số lần khởi động lại tăng. Đây gần như luôn luôn là **bộ nhớ**, không phải CPU hoặc đĩa. + +**Xác nhận đó là bộ nhớ** (không phải vấn đề throughput mà sao chép sẽ sửa): + +1. Kiểm tra pod để tìm các lần bị kill out-of-memory: + ```bash + kubectl -n agenteye describe pod clickhouse-0 | grep -iE 'Restart Count|Last State|Reason|OOMKilled' + ``` + `Reason: OOMKilled` / `Exit Code: 137` với số lần khởi động lại tăng là điểm chỉ. + +2. Hỏi ClickHouse cái gì nó từ chối: + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT name, value FROM system.errors WHERE value>0 ORDER BY value DESC" + ``` + Số lượng `MEMORY_LIMIT_EXCEEDED` lớn là chữ ký. Thông báo đọc *"maximum: N GiB"* — **N là `0.9 × giới hạn bộ nhớ pod`** (`max_server_memory_usage_to_ram_ratio` trong `deploy/base/clickhouse/configmap.yaml`). Nếu các đọc nặng của bạn cần nhiều hơn N, chúng bị từ chối. + +3. Loại trừ những điều *không phải* là vấn đề — nếu CPU, part count và đĩa đều thấp, thêm replicas/sharding sẽ lãng phí chi phí: + ```bash + kubectl -n agenteye top pod clickhouse-0 + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT table, count() parts FROM system.parts WHERE active AND database='agenteye' GROUP BY table" + ``` + +**Nguyên nhân:** giới hạn bộ nhớ pod ClickHouse quá nhỏ cho tập làm việc phân tích. Những lần đọc nặng nhất kéo cột `payload` JSON thô, chạy `JSONExtract*` trên nó và sử dụng `FINAL` — mỗi cái có thể cần vài GiB. Nếu các cache được cấu hình (`mark_cache_size` + `uncompressed_cache_size`) lớn hơn pod, chúng tổng hợp nó: các cache được tính vào cùng ngân sách và làm đầy bộ nhớ truy vấn. + +**Sửa — mở rộng bộ nhớ ClickHouse:** + +1. Tăng giới hạn bộ nhớ ClickHouse trong overlay của bạn bằng cách vá `resources` container của `clickhouse` StatefulSet (cơ chế overlay tương tự được sử dụng cho `resources` của các thành phần khác). Ngân sách máy chủ có thể sử dụng là `0.9 × limit`, vì vậy giới hạn `6Gi` cung cấp ~5.4 GiB, `16Gi` cung cấp ~14 GiB. Đặt `requests.memory` thành một sàn thực, vì vậy bộ lập lịch dự trữ nó. Áp dụng điều này **tạo lại pod CH** (replica duy nhất → ~30–60s downtime phân tích); làm nó trong cửa sổ lưu lượng thấp. +2. Giữ các cache trong `deploy/base/clickhouse/configmap.yaml` tỷ lệ với giới hạn — các cache nhỏ (vài trăm MiB) an toàn trên một pod nhỏ; chỉ tăng chúng cùng với tăng giới hạn bộ nhớ phù hợp. Per-query `max_memory_usage` được đặt rõ ràng trong profile `users.xml` (xem phần nút cố định bên dưới) và được giữ dưới cap level máy chủ (`0.9 × limit`) để không có truy vấn duy nhất *được phép* RAM nhiều hơn container có. +3. Nếu chính nút là trần, hãy kiểm tra bộ nhớ máy chủ ClickHouse có thể thấy: + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT formatReadableSize(value) FROM system.asynchronous_metrics WHERE metric='OSMemoryTotal'" + ``` + Nếu chỉ có một chút trên giới hạn pod, hãy chuyển ClickHouse đến một nút lớn hơn (tối ưu hóa bộ nhớ) — qua node selector/affinity trong overlay của bạn — trước khi tăng giới hạn thêm. + +**Khi bạn không thể thêm bộ nhớ: chạy truy vấn trong RAM và thất bại nhanh — không tràn trên đĩa chậm.** Nếu nút được sửa và pod không thể lớn, cắt những gì bất kỳ truy vấn nào có thể sử dụng (vì vậy một truy vấn không thể chiếm toàn bộ nút) và, trên **đĩa dữ liệu chậm (non-SSD)**, **không** để các tổng hợp/sắp xếp lớn tràn trên đĩa. Tràn trên đĩa chậm chậm hơn timeout đọc khách hàng máy chủ, vì vậy một truy vấn tràn trả về dashboard `500` giữa chuyến bay trong khi ClickHouse tiếp tục xay — giữ truy vấn trong RAM và từ chối cái hiếm quá ngân sách một *nhanh* (`MEMORY_LIMIT_EXCEEDED`, sub-second) là cái khôi phục tải. Lưu ý một gotcha ClickHouse để áp dụng các cài đặt này: + +- **Đây là cài đặt *profile*, và ClickHouse đọc `` chỉ từ `users_config` (`users.xml` / `users.d/*.xml`) — không bao giờ từ `config.d`.** Một khối `` được đặt trong `config.d/agenteye.xml` là **im lặng bị bỏ qua** (`max_execution_time`, `max_memory_usage`, v.v. đơn giản là không áp dụng). Do đó, cấu hình được đặt kèm gửi chúng làm khóa `users.xml` trên `clickhouse-config` ConfigMap, được gắn tại `/etc/clickhouse-server/users.d/agenteye.xml`. +- Các mặc định được gửi: `max_memory_usage` (per-query ceiling — một truy vấn không thể tiêu thụ toàn bộ ngân sách máy chủ), `max_bytes_before_external_group_by` / `max_bytes_before_external_sort` = **`0` (tràn vô hiệu)** vì vậy truy vấn ở RAM chứ không bò trên đĩa chậm, và `max_execution_time` (bảo vệ runaway, căn chỉnh với timeout đọc khách hàng máy chủ). +- **Xác minh chúng hoạt động** (đây cũng là cách bạn phát hiện gotcha config.d): + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT name, value FROM system.settings + WHERE name IN ('max_memory_usage','max_bytes_before_external_group_by','max_execution_time')" + ``` + Mong đợi `max_memory_usage` khác không và `max_bytes_before_external_group_by = 0`. Nếu `max_memory_usage` đọc `0`/default, profile không được áp dụng — kiểm tra các cài đặt hoạt động trong `users.d` mount, không `config.d`. + +Trade-off: với tràn vô hiệu, một truy vấn có tập làm việc vượt quá `max_memory_usage` là **bị từ chối** (`MEMORY_LIMIT_EXCEEDED`) chứ không phải hoàn thành chậm — trên đĩa chậm trước đó từ chối nhanh là tốt hơn, vì một truy vấn tràn sẽ vượt quá timeout khách hàng và thất bại anyway. Nếu đĩa dữ liệu của bạn là **nhanh (S \ No newline at end of file diff --git a/docs/zh/agenteye/alerts.mdx b/docs/zh/agenteye/alerts.mdx new file mode 100644 index 00000000..89a4a5a3 --- /dev/null +++ b/docs/zh/agenteye/alerts.mdx @@ -0,0 +1,308 @@ +--- +title: "告警" +description: "AgentEye 告警文档。" +--- + +告警会按计划对规则进行评估,并在某项指标超过阈值时通知您。它们将 AgentEye 从一个被动的仪表盘转变为一个主动的事件通知系统,用于监测您真正关心的事项:错误率飙升、延迟回归、评估分数下降,或任何可以用 ClickHouse 查询表达的自定义事件。 + +本指南涵盖告警的定义、五种触发器类型、四种通知渠道、事件生命周期以及各项操作参数。 + +![告警页面:告警规则卡片网格,每张卡片显示其触发器类型、评估窗口、渠道以及信息/警告/严重等级徽章](/agenteye/images/alerts.png) + +--- + +## 核心概念 + +- **告警** — 规则本身。它定义了*检查什么*(触发器)、*检查频率*(评估间隔)、*何时判定为异常*(组合逻辑)、*严重程度*(等级),以及*通知谁/通知到哪里*(渠道)。 +- **事件** — 告警触发时所发生的事情。同一时间,一条告警最多只有一个开放中的事件。重复触发会更新同一事件的证据。事件需由操作员手动解决;规则停止触发时的自动解决功能已在规划中,但目前尚未启用。 +- **渠道** — 通知的发送目的地:电子邮件、Slack、通用 Webhook 或仪表盘内通知。每条告警可以附加任意组合的渠道。 + +告警和事件归属于某个组织,并在该组织的所有操作员之间共享(在单租户部署中,即内置的 `default` 组织)。事件可以分配给单个操作员进行分类处理。 + +--- + +## 触发器类型 + +共有五种类型,每种类型都有其对应的 JSON 规范。选择最符合您对"异常"定义方式的类型。仪表盘的**新建告警**表单会为您构建相应的规范,并根据您选择的触发器类型切换条件编辑器: + +![新建告警表单,包含基本信息(名称、描述、是否启用)以及触发器选择器,显示指标阈值、自定义 SQL、评估分数、评估失败和逐事件等选项](/agenteye/images/alert-new.png) + +### 1. `metric_threshold` + +最简单的类型。从固定列表中选择一个指标、一个运算符、一个阈值和一个时间窗口。 + +| 指标 | 计算内容 | +|---|---| +| `event_count` | 窗口内的事件总数 | +| `error_count` | `event_type = 'error'` 或任何 `error_type IS NOT NULL` 的事件 | +| `error_rate` | `error_count / event_count`(范围 0..1) | +| `p95_latency_ms` | 所有含 `duration_ms` 事件的 `quantile(0.95)(duration_ms)` | +| `p99_latency_ms` | `quantile(0.99)(duration_ms)` | +| `token_sum` | `SUM(input_tokens + output_tokens)` | + +运算符:`>`、`>=`、`<`、`<=`、`==`(也可使用 `gt`、`gte`、`lt`、`lte`、`eq`)。 + +可选过滤器:`environment`、`event_type`。 + +示例规范: + +```json +{ + "metric": "p95_latency_ms", + "filter": { "environment": "production" }, + "window_secs": 900, + "op": ">", + "value": 5000 +} +``` + +### 2. `custom_sql` + +适用于预设指标无法覆盖的场景。操作员提供的 SQL 会经过与 `/queries/run` 相同的安全检查(仅支持 SELECT/WITH,单条语句,最多返回 10,000 行),然后由调度器执行。支持两种模式: + +- **rows 模式**(不含 `op`/`value`):查询返回至少一行时,告警即触发。 +- **value 模式**:查询必须将某一列别名为 `metric_value`;调度器使用 `op` 将第一行的 `metric_value` 与 `value` 进行比较。 + +```json +{ + "sql": "SELECT count() AS metric_value FROM agenteye.events WHERE event_type = 'error' AND ts >= now() - INTERVAL 1 HOUR", + "op": ">", + "value": 100 +} +``` + +### 3. `evaluation_score` + +读取 `agenteye.evaluations` 并比较指定分数在某个窗口内的平均值。 + +```json +{ + "score_key": "hallucination", + "op": ">", + "value": 0.6, + "window_secs": 3600, + "min_count": 5, + "environment": "production" +} +``` + +`min_count` 用于防止单样本异常值的干扰;在窗口内至少有 N 条评估数据之前,调度器不会触发告警。 + +### 4. `eval_compound` + +用于捕获仅在*多个*评估分数同时出现时才显现的质量回归问题。与 `evaluation_score` 只监控单个命名分数不同,`eval_compound` 将多个评估分数条件组合到一条告警中,并使用所选逻辑合并结果;因此一条规则可以表达"helpfulness 下降**或**幻觉率上升时触发"、"仅当 helpfulness **且** tool-efficiency 均下降时触发",或"这三项检查中**至少 2 项**超出阈值时触发"。 + +每个条件读取 `agenteye.evaluations` 中某个命名分数在共享窗口内的平均值,并用其自身的运算符和阈值进行测试。布尔结果随后由 `combinator` 进行合并: + +| 合并器 | 逻辑 | 触发条件 | +|---|---|---| +| `"any"` | OR | 至少一个条件超出阈值 | +| `"all"` | AND | 所有条件均超出阈值 | +| `{ "at_least": N }` | M-of-N | 至少 N 个条件超出阈值 | + +```json +{ + "combinator": { "at_least": 2 }, + "conditions": [ + { "score_key": "hallucination", "op": ">", "value": 0.8 }, + { "score_key": "helpfulness", "op": "<", "value": 0.6 }, + { "score_key": "tone", "op": "<", "value": 0.5 } + ], + "window_secs": 3600, + "min_count": 5, + "environment": "production" +} +``` + +- `combinator`:`"any"`、`"all"` 或 `{ "at_least": N }`。 +- `conditions[]`:每项为 `{ score_key, op, value }`,使用与其他触发器相同的运算符(`>`、`>=`、`<`、`<=`、`==`)。 +- `window_secs`:应用于每个条件的共享回溯时长(默认 `3600`)。 +- `min_count`:每个条件在触发前所需的最少评估数量;窗口内样本不足的条件视为"未超出阈值"(默认 `1`)。 +- `environment`:可选;将每个条件限定到单个环境。 + +通知的证据记录每个条件的实测平均值、测试所用阈值、评估数量以及是否超出阈值,让您清楚地看到哪些检查项被触发。 + +### 5. `per_event` + +适用于"任何匹配 X 的事件已到达"类型的告警。无需聚合;调度器一旦在回溯窗口内发现匹配项即触发。 + +```json +{ + "event_type": "error", + "lookback_secs": 60, + "environment": "production", + "tool_name": "bash", + "agent_id": "caa", + "error_type": "TimeoutError", + "message_contains": "vertex-ai timed out" +} +``` + +所有过滤条件均为 AND 组合;未填写的字段不作限制。 + +| 字段 | 用途 | +|---|---| +| `agent_id` | 限定为特定 Agent 的错误(即 `/errors` 行中显示的那个)。 | +| `error_type` | 限定为特定错误类(如 `TimeoutError`),而非所有错误。 | +| `message_contains` | 对 `payload.message` 进行大小写不敏感的子字符串匹配。适用于捕获某种特定故障模式(如 `prompt is too long`),而无需对来自同一 Agent 的每个错误都发送告警。最多 200 个字符;按字面字符串匹配,不支持模式匹配。 | + +提示:将 `lookback_secs` 设置为与告警的 `eval_interval_secs` 大致匹配,以避免对同一事件重复通知。 + +**来自 `/errors` 的快捷方式:** 错误视图中每个错误分组的代表行(以及错误事件的会话事件详情面板)都有一个 **+ alert** 按钮,点击后会打开 `/alerts/new`,并预填充以该行 `event_type` + 环境为键的 `per_event` 触发器,名称会在载荷中存在 `error_type` 时自动从中提取。您仍需选择渠道并确认回溯时长,但匹配条件已为您填写完毕。按钮的显示需要操作员具有 `alerts:write` 权限。 + +--- + +## 组合逻辑(M of N) + +除触发器外,每条告警还有两个整数参数: + +- `eval_window`:查看最近多少次评估(默认 1) +- `min_breaches`:其中必须有多少次超出阈值才触发告警(默认 1) + +`1 of 1`(默认值)表示"首次超出阈值即触发"。`3 of 5` 表示"最近 5 次评估中有 3 次超出阈值时触发",适用于单次不良测量属于噪声的抖动信号。调度器为每条告警维护一个环形缓冲区,您无需手动管理状态。 + +--- + +## 评估间隔 + +`eval_interval_secs` 控制调度器运行规则的频率。取值范围为 `[30, 86400]`。仪表盘中的预设值:1m / 5m / 15m / 1h。请根据底层信号的变化速度选择合适的间隔:以 15 秒为间隔评估一条 5 分钟错误率告警会浪费 CPU 资源;逐事件告警需要较短的回溯窗口,否则会在两次评估之间静默丢失事件。 + +--- + +## 渠道 + +每条告警可以附加以下四种渠道的任意组合。每个渠道的凭据(Slack Webhook URL、通用 Webhook URL + 签名密钥、默认邮件收件人)在 **`/settings`** 中统一配置,并通过键名在每条告警中引用。这样,一个 Slack 频道可以服务于多条告警,而无需每条告警单独存储其 Webhook URL。 + +三种外部渠道类型(电子邮件、Slack、Webhook)还受到组织级开关 `alerts.enabled_channels` 的控制。当已触发的告警附加了不在此集合中的渠道类型时,调度器会跳过它,并记录一条状态为 `skipped_disabled`、目标为 `` 的 `alert_notifications` 记录(这样您就可以全局暂停某种渠道,例如所有 Slack 推送,而无需逐条编辑规则)。仪表盘内通知渠道始终可用。请参阅[配置](#configuration)。 + +### 电子邮件 + +复用发送 OTP 登录邮件的 SMTP 传输。收件人按以下顺序解析: + +1. 每个渠道的 `recipients[]` 覆盖设置(非空时使用)。 +2. `alerts.email_default_recipients` 设置(一个邮件地址字符串数组)。 + +如果未配置 SMTP,该渠道为空操作;调度器仍会记录一条目标为 `` 的 `alert_notifications` 记录,以便审计跟踪中可见此配置缺失。 + +### Slack + +向 [Incoming Webhook URL](https://api.slack.com/messaging/webhooks) 发送 Block Kit 消息。 + +- 默认 URL:`alerts.slack_default_webhook`(在 `/settings` 中设置)。 +- 每条告警的覆盖设置:将渠道的 `webhook_setting_key` 设置为任何其他 URL 类型的设置键,例如 `alerts.slack_oncall`、`alerts.slack_costs`。 + +消息头包含等级表情符(`:rotating_light:` / `:warning:` / `:bell:`),消息中附有直达事件页面的深链接按钮。 + +### 通用 Webhook + +用于与 PagerDuty、Opsgenie 或您自定义接收端集成的 JSON POST 方式。请求体结构: + +```json +{ + "schema_version": 1, + "event": "alert.firing", + "incident": { "id": "uuid", "url": "https://…/incidents/uuid", "opened_at": "2026-…" }, + "alert": { "id": "uuid", "name": "errors > 50/hr", "severity": "critical" }, + "breach": { "value": 73.0, "summary": "ErrorCount > 50 (observed 73.000)", "evidence": { … } } +} +``` + +当 `alerts.webhook_signing_secret` 已设置时,请求会包含 `X-AgentEye-Signature: sha256=` 请求头,该值为使用密钥对请求体计算的 HMAC-SHA256。请在接收端验证此签名后再信任载荷内容。 + +请求头 `X-AgentEye-Event` 携带 `alert.firing` / `alert.test`。(`alert.resolved` 保留给计划中的自动解决功能,目前尚未发出。) + +### 仪表盘内通知 + +无需外部推送:告警仅写入一条 `alert_notifications` 记录,由仪表盘的事件页面展示。适用于您正在调试规则且不希望向外部系统发送大量通知的场景,或用于操作员在日常分类处理期间查看的低紧急度告警。 + +--- + +## 事件生命周期 + +``` +firing ──ack──▶ acknowledged + │ │ + └────────────────────┴───── operator resolve ───▶ resolved +``` + +- **firing(触发中)** — 调度器刚刚开启事件,或检测到另一次超出阈值。触发通知只会发送一次(由事件上的 `notified_firing_at` 时间戳控制)。 +- **acknowledged(已确认)** — 操作员在 `/incidents/:id` 上点击了*确认*。事件仍视为开放;后续的阈值触发会更新证据,但不会重新发送通知。 +- **resolved(已解决)** — 操作员点击了*解决*。规则停止触发时的自动解决功能已在规划中,但目前尚未启用,因此开放的事件会一直保持开放,直到操作员手动解决。 + +之前的事件解决后,同一告警可以随时再次开启新事件。 + +**活动时间线。** 事件上的每个操作——开启、确认、解决——都会记录在一个只追加的活动日志中,并显示在事件的*活动*时间线上。每条记录都会标注执行操作的操作员(通过邮件地址)或**自动化**(对于调度器自主执行的操作,如因超出阈值自动开启)。确认操作是共享的:多位操作员可以确认同一事件,每位操作员都会作为独立的带归属条目出现。 + +**事件**收件箱按状态对开放事件进行分组,并支持按严重程度和负责人筛选: + +![事件收件箱,显示与告警关联及临时事件卡片,含严重程度徽章和负责人信息](/agenteye/images/incidents.png) + +打开某个事件后,可以看到超出阈值的证据、负责人与订阅者、带归属的活动时间线,以及评论区: + +![事件详情视图:父级告警、超出阈值摘要、负责人、订阅者、带归属的活动日志和讨论区](/agenteye/images/incident-detail.png) + +--- + +## 所需权限 + +编写告警*规则*和处理*事件*是两件独立的事情,各有独立的授权,因此您可以给值班轮换组授予事件处理权限,而无需同时赋予其修改规则的能力。 + +- `alerts:read`:查看告警规则。 +- `alerts:write`:创建、编辑、删除告警规则,以及触发测试通知。 +- `incidents:read`:查看事件。 +- `incidents:write`:开启不与告警关联的手动(临时)事件。 +- `incidents:ack`:确认、分配、评论和解决事件。 + +> **旧版 `alerts:ack`。** 被授予旧版 `alerts:ack` 令牌的密钥和操作员可继续使用:该令牌被视为 `incidents:ack`(并隐含 `incidents:read`),因此现有值班人员无需重新签发凭据即可保留其访问权限。新的授权请使用 `incidents:*` 系列。 + +在 API 密钥(`POST /keys`)和操作员(`PUT /users/:id`)上进行授权。当缺少某项权限时,仪表盘的 `PermGate` 会锁定相关按钮;您会在操作旁看到 `// 403` 提示。 + +> **邮件收件人选择器。** 告警编辑器的收件人选择器会列出您组织的成员,方便您按姓名选择。任何持有 `alerts:read` 或 `alerts:write` 权限的操作员均可加载此列表;为此目的查看团队成员目录**不需要** `users:read` 权限,且选择器仅返回成员邮件地址,不返回完整的用户记录。 + +--- + +## 配置 + +调度器使用的环境变量: + +| 变量 | 默认值 | 用途 | +|---|---|---| +| `ALERT_WORKERS` | `1` | 每个服务器实例的工作任务数。大多数部署只需要一个。 | +| `ALERT_CLAIM_BATCH` | `16` | 单次工作器 tick 处理的最大告警数。 | +| `ALERT_POLL_IDLE_SECS` | `5` | 队列为空时工作器的休眠时长。 | +| `ALERT_REQUEST_TIMEOUT_MS` | `15000` | 每次触发器评估的超时时长。 | +| `DASHBOARD_URL` | `https://app.befailproof.ai` | 用于在通知中构建事件魔法链接的域名。请设置为您的仪表盘主机地址。 | + +发生临时评估失败(ClickHouse 不可达、查询超时)后,调度器会以指数退避策略重试规则。一旦某条规则累计发生 **5** 次连续临时失败,它将按正常节奏重新调度,而不继续退避,因此持续失败的规则仍会定期重新评估。此上限为固定值,操作员不可调整。 + +渠道设置(通过 `/settings` 管理,而非环境变量): + +- `alerts.email_default_recipients`(`email_list`):邮件地址字符串的 JSON 数组——邮件渠道的默认收件人。 +- `alerts.slack_default_webhook`(`url`):默认 Slack Incoming Webhook URL。 +- `alerts.webhook_default_url`(`url`):默认通用 Webhook URL。 +- `alerts.webhook_signing_secret`(`secret`):HMAC-SHA256 密钥。GET 响应中始终返回 `""`;输入新值即可轮换。 +- `alerts.enabled_channels`(`channel_set`):告警触发时允许调度的外部渠道类型的组织级集合;默认包含全部三种(`email`、`slack`、`webhook`)。从此处移除某种类型会对所有告警全局屏蔽该渠道,无需逐条编辑规则。仪表盘内通知渠道始终推送,不受此设置影响。 + +--- + +## 验证新告警 + +在依赖新告警之前: + +1. 启用告警并附加至少一个通知渠道后保存。 +2. 在告警详情页选择**测试**,并确认每个已配置的目标都收到了模拟通知。 +3. 在第一次真实触发后,确认事件出现在**事件**列表中,且其测量值与仪表盘对应查询的结果相符。 + +条件恢复后,事件不会自动解决。操作员必须在事件详情页手动解决。 + +--- + +## 故障排查 + +| 现象 | 可能原因 | +|---|---| +| 告警从不触发 | `enabled = false`,或未附加渠道,或底层 CH 查询返回 0 行。使用*测试*确认渠道是否正常;使用 `/queries/run` 确认指标是否正常。 | +| Slack 通知未收到 | `alerts.slack_default_webhook`(或每条告警的覆盖键)未设置:检查 `alert_notifications.target` 中是否有 `` 记录;或 `slack` 类型在 `alerts.enabled_channels` 中被全局禁用:检查是否存在状态为 `skipped_disabled`、目标为 `` 的 `alert_notifications` 记录。 | +| 通用 Webhook 返回 401 | 接收端要求签名验证,但 `alerts.webhook_signing_secret` 未设置。在接收端验证 HMAC 是否与 `hmac_sha256(secret, body)` 匹配。 | +| 邮件提示"所有发送均失败" | SMTP 凭据错误,或 `from` 地址被您的邮件中继拒绝。该传输与发送 OTP 邮件的是同一个:如果 OTP 邮件正常,则 SMTP 传输本身没有问题。 | +| 事件反复重新开启 | 组合参数设置过于激进:尝试调高 `min_breaches` 或 `eval_window`,以避免临时尖峰重新开启您已解决的事件。 | \ No newline at end of file diff --git a/docs/zh/agenteye/api-keys.mdx b/docs/zh/agenteye/api-keys.mdx new file mode 100644 index 00000000..4e7376f5 --- /dev/null +++ b/docs/zh/agenteye/api-keys.mdx @@ -0,0 +1,255 @@ +--- +title: "API Keys" +description: "AgentEye API Keys 文档。" +--- + + +AgentEye 使用细粒度 API 密钥来控制对服务器的访问。每个密钥携带一个或多个权限,决定其可以执行的操作。 + +--- + +## 权限 + +服务器强制执行固定的权限目录;每个权限对应特定的 HTTP 路由。**管理员密钥**拥有全部权限;受限密钥仅拥有创建时授予的权限子集。创建密钥时,未知的权限字符串将被拒绝。 + +> **不可分配给密钥。** 有两个有效权限仅限于人工/仪表板使用,不能授予 API 密钥:`orgs:admin`(实例管理,仅限操作员)和 `keys:update`。向 `POST /keys` 或 `PATCH /keys/:id` 请求中尝试授予这两者之一时,将收到 HTTP 422 错误。关于为何持有者密钥可以创建密钥但不能编辑密钥,请参见下方 `keys:update` 行的说明。 + +### 事件写入与查询 + +| 权限 | HTTP 路由 | 允许的操作 | +|---|---|---| +| `events:add` | `POST /events` | 从采集器批量写入事件。这是采集器唯一需要的权限。 | +| `events:read` | `GET /events`、`GET /events/latency_aggregate`、`GET /events/environments`、`GET /events/models`、`GET /sessions/:session_id/export` | 查询事件、列出已知环境、列出数据中出现的模型标识符(供模型视图和模型筛选器使用)、计算延迟聚合以驱动热图/百分位带,以及将会话导出为 JSONL。共享筛选栏的维度端点 `GET /events/environments` 和 `GET /events/models` 可通过 **`events:read`** 或 **`evaluations:read`** 访问,因此会话页面(受 `evaluations:read` 限制)可复用相同的每组织维度。 | + +### 会话与评估 + +| 权限 | HTTP 路由 | 允许的操作 | +|---|---|---| +| `evaluations:read` | `GET /sessions`、`GET /evaluations`、`GET /evaluations/aggregate`、`GET /evaluations/environments`、`GET /evaluation-jobs` | 列出会话、读取评估结果、仪表板使用的汇总评估健康状态,以及评估任务工作队列状态。 | +| `evaluations:trigger` | `POST /sessions/:session_id/re-evaluate` | 手动将已完成的会话加入重新评估队列。 | + +### 仪表板 + +| 权限 | HTTP 路由 | 允许的操作 | +|---|---|---| +| `dashboards:read` | `GET /dashboards`、`GET /dashboards/:id`、`GET /dashboards/:id/tiles` | 列出仪表板、加载某个仪表板以及读取其磁贴。 | +| `dashboards:write` | `POST /dashboards`、`PUT /dashboards/:id`、`POST /dashboards/:id/tiles`、`PUT /dashboards/:id/tiles/:tile_id`、`DELETE /dashboards/:id/tiles/:tile_id`、`PUT /dashboards/:id/tiles/layout` | 创建和编辑仪表板、添加/编辑/删除磁贴,以及重新排列磁贴网格。 | +| `dashboards:delete` | `DELETE /dashboards/:id` | 删除整个仪表板(磁贴级别的删除属于 `dashboards:write`)。 | + +### 保存的查询(SQL 编辑器) + +| 权限 | HTTP 路由 | 允许的操作 | +|---|---|---| +| `queries:read` | `GET /queries`、`GET /queries/:id`、`GET /queries/schema` | 列出已保存的查询、加载某个查询,以及查看编辑器所针对的只读 ClickHouse 模式。 | +| `queries:write` | `POST /queries`、`PUT /queries/:id` | 创建和编辑已保存的查询。SQL 仍通过与 `queries:run` 调用相同的只读角色和 `sql_guard` 检查进行路由。 | +| `queries:delete` | `DELETE /queries/:id` | 删除已保存的查询。 | +| `queries:run` | `POST /queries/run` | 通过编辑器使用的只读角色执行已保存或临时 SQL。 | + +### AI 助手 + +| 权限 | HTTP 路由 | 允许的操作 | +|---|---|---| +| `agent:use` | `GET /agent/conversations`、`POST /agent/conversations`、`GET /agent/conversations/:id`、`PATCH /agent/conversations/:id`、`DELETE /agent/conversations/:id`、`PUT /agent/conversations/:id/messages` | 与仪表板 AI 助手对话并管理自己的(私有)会话。**用户**必须拥有此权限才能看到助手面板;助手自身的密钥为 `dashboard-assistant`,单独预置(见下文)。 | + +### API 密钥 + +| 权限 | HTTP 路由 | 允许的操作 | +|---|---|---| +| `keys:create` | `POST /keys` | 创建新的受限 API 密钥。**不**授予编辑现有密钥权限的能力(那是 `keys:update`)。 | +| `keys:read` | `GET /keys` | 列出现有密钥。此端点不返回密钥的密文。 | +| `keys:update` | `PATCH /keys/:id` | 编辑现有密钥的权限。这是**仅限人工/仪表板**的权限;不能分配给 API 密钥(持有者密钥可以创建密钥,但不能编辑密钥)。 | +| `keys:disable` | `POST /keys/:id/disable` | 吊销某个密钥。受保护的密钥(`admin`、`dashboard-assistant`)不能被禁用;请通过修改环境变量并重启来轮换它们。 | +| `keys:regenerate` | `POST /keys/:id/regenerate` | 轮换某个密钥的密文。受保护的密钥不能通过此路由重新生成。 | + +### 仪表板用户 + +| 权限 | HTTP 路由 | 允许的操作 | +|---|---|---| +| `users:create` | `POST /users`、`GET /users/defaults` | 邀请新的仪表板用户(发送邮件 + OTP 登录),并读取仪表板配置的默认权限集以预填邀请表单。 | +| `users:read` | `GET /users`、`GET /users/:id` | 列出用户并加载单个用户记录。 | +| `users:update` | `PUT /users/:id` | 编辑用户的权限。更新操作会向受影响的用户发送权限变更邮件,并在其下次请求时生效;无需重新登录。 | +| `users:delete` | `DELETE /users/:id`、`POST /users/:id/enable` | 禁用用户(立即吊销其会话)并重新启用之前被禁用的用户。 | + +这些权限支撑仪表板的**用户**页面,每位成员被授予的权限范围以标签形式展示: + +![用户页面:每位仪表板用户一张卡片,显示其邮箱、已授予权限以及编辑/禁用控件](/agenteye/images/users.png) + +### 运营设置 + +| 权限 | HTTP 路由 | 允许的操作 | +|---|---|---| +| `settings:read` | `GET /settings`、`GET /settings/schema`、`GET /settings/model-context-windows`、`GET /settings/model-context-windows/resolve` | 查看仪表板管理的运营设置及其元数据;列出每个模型的上下文窗口覆盖配置;以及解析某个模型的有效窗口。 | +| `settings:write` | `PUT /settings/:key`、`PUT /settings/model-context-windows`、`DELETE /settings/model-context-windows` | 编辑运营设置,添加、修改或删除每个模型的上下文窗口覆盖配置。更改对新事件立即生效,无需重启服务器。 | + +![设置页面:仪表板管理的运营设置,例如允许的登录方式以及会话/OTP 有效期,无需重启即可编辑](/agenteye/images/settings.png) + +### 告警与事故 + +| 权限 | HTTP 路由 | 允许的操作 | +|---|---|---| +| `alerts:read` | `GET /alerts`、`GET /alerts/:id` | 查看已配置的告警定义。 | +| `alerts:write` | `POST /alerts`、`PUT /alerts/:id`、`DELETE /alerts/:id`、`POST /alerts/:id/test` | 创建、编辑、删除和测试触发告警定义。 | +| `incidents:read` | `GET /alerts/incidents`、`GET /alerts/incidents/:iid`、`GET /alerts/incidents/:iid/comments`、`GET /alerts/incidents/:iid/subscribers` | 查看事故及其分类处理记录。 | +| `incidents:write` | `POST /alerts/:id/incidents` | 针对现有告警手动创建事故。 | +| `incidents:ack` | `POST /alerts/incidents/:iid/ack`、`POST /alerts/incidents/:iid/assign`、`POST /alerts/incidents/:iid/resolve`、`POST /alerts/incidents/:iid/comments`、`POST /alerts/incidents/:iid/subscribe`、`POST /alerts/incidents/:iid/unsubscribe` | 确认、分配、解决和评论事故。 | + +### 审计 + +| 权限 | HTTP 路由 | 允许的操作 | +|---|---|---| +| `audits:read` | `GET /audits`、`GET /audits/:id`、`GET /audits/:id/runs`、`GET /audits/findings`、`GET /audits/findings/:fid` | 查看审计定义、运行历史记录和发现项。 | +| `audits:write` | `POST /audits`、`PUT /audits/:id`、`DELETE /audits/:id`、`POST /audits/:id/run`、`POST /audits/findings/:fid/status` | 创建、编辑、删除和运行审计;对发现项进行分类处理(确认/静默/忽略/解决/重新开启/分配)。 | + +> 审计功能上线时,现有被授权者按照与告警相同的角色形态进行了扩展:每位持有 `alerts:read` 的用户和权限集均获得了 `audits:read`,每位持有 `alerts:write` 的用户均获得了 `audits:write`。现有 API 密钥**未被自动扩展**——如需访问审计功能,请为密钥显式授予 `audits:*`。 + +> 旧版 `alerts:ack` 令牌的存量授权会被解析为 `incidents:ack`,因此值班人员无需重新申请密钥即可保留访问权限。该令牌不再可从仪表板用户编辑器中分配;权限矩阵改为提供 `incidents:ack`。 + +> 收件人选择端点 `GET /alerts/recipients`(列出告警编辑器可通知的成员邮箱)可由持有 **`alerts:read`** 或 **`alerts:write`** 的用户访问,因此告警编辑器无需被授予 `users:read` 即可填充选择列表。 + +> 仪表板查看者需要同时拥有 **`dashboards:read`**(加载已保存的视图)和 **`evaluations:read`**(健康指标由评估数据计算得出)。授予 `dashboards:write` 可让用户创建或编辑仪表板,授予 `dashboards:delete` 可让其删除仪表板。 + +> `/health` 和 `/auth/*`(OTP 请求、OTP 验证、会话检查、退出登录)按设计不需要身份验证;它们是登录流程和存活探针。`GET /access-granters` 需要有效密钥但不需要特定权限,因此任何已登录用户均可查看应联系哪些管理员进行访问变更。 + +--- + +## 权限集 + +权限集允许你应用一个命名角色,而无需每次手动逐一选择权限令牌。无需为每位新仪表板用户或 API 密钥一一选择十几个权限,只需选择一个权限集,所有分配到该集合的用户都将获得一致且可审查的授权。编辑自定义权限集后,新的授权将自动重新应用于所有已分配该集合的用户,因此角色变更只需一次编辑,无需逐一修改每位成员。 + +每个组织预置三个内置权限集: + +| 权限集 | 权限内容 | 适用对象 | +|---|---|---| +| `read-only` | `events:read`、`keys:read`、`users:read`、`evaluations:read`、`dashboards:read`、`queries:read`、`settings:read`、`alerts:read`、`audits:read`、`incidents:read` | 对所有运营界面的只读访问。 | +| `standard` | `read-only` 中的所有权限,加上 `evaluations:trigger`、`queries:run`、`incidents:ack`、`agent:use` | 只读权限加上日常值班操作:运行查询、重新评估会话、确认事故以及使用 AI 助手。 | +| `admin` | 所有可分配权限 | 对组织的完全控制。 | + +三个内置权限集是**不可变的**;其名称含义始终固定,因此 `read-only`、`standard` 和 `admin` 可安全地在策略和入职流程中引用。操作员可以创建额外的**自定义权限集**,以满足组织特有的角色需求(例如"仪表板作者"角色或"仅限采集器"角色)。 + +权限集在仪表板中展示,并通过以下 API 进行管理:`GET /permission-sets`(列出,受 `users:read` 限制)、`POST /permission-sets`、`PUT /permission-sets/:name`、`DELETE /permission-sets/:name`(创建、编辑、删除自定义权限集,受 `settings:write` 限制)。删除或编辑内置权限集的操作将被拒绝。 + +权限集成员关系为另外两项功能提供支撑: + +- **`DEFAULT_USER_PERMISSIONS`**(管理员打开**+ 新建用户**时预选的授权)默认为 `standard` 权限集。请参阅[部署](/zh/agenteye/deployment)。 +- **`agenteye-orgctl` 上的 `--set` 标志**(操作员成员管理)以命名权限集为成员设置起始权限,然后可通过 `--add` / `--remove` 进行微调。请参阅[租户管理](/zh/agenteye/tenant-management)。 + +> 当权限集包含不可分配给密钥的权限(例如包含 `keys:update` 的自定义权限集)时,从该集合创建密钥将自动剔除不可分配的令牌;否则服务器将以 HTTP 422 拒绝该密钥。仪表板用户不受此限制。 + +--- + +## 引导管理员密钥 + +管理员密钥是操作员从零开始配置访问权限的唯一根凭证:通过它可以创建所有其他受限密钥、邀请第一批仪表板用户,以及在其他密钥存在之前配置实例。它是唯一不通过密钥 API 创建的密钥;它通过环境变量预置,以确保服务器在首次启动时即可访问。 + +在服务器上设置 `ADMIN_KEY` 环境变量。每次启动时,服务器将以该值为管理员密钥(拥有所有权限)执行 upsert 操作。 + +轮换方式:将 `ADMIN_KEY` 更改为新密文并重启服务器。 + +--- + +## 组织范围 + +**组织本身由操作员通过带外方式创建和管理,不通过此密钥 API。** 组织和成员的生命周期管理(创建/重命名/删除/清除组织;添加/更新/移除成员)通过在服务器 Pod 内运行的 **`agenteye-orgctl`** CLI 完成;没有对应的 HTTP API 或仪表板按钮。请参阅[租户管理](/zh/agenteye/tenant-management)。**不变的是:每个组织的 API 密钥仍由组织成员在仪表板(或通过此密钥 API)中创建。** + +在多组织部署中,组织成员创建的每个密钥(通过此密钥 API 或仪表板**密钥**页面)都**归属于一个组织**,并且只能读写该组织的数据;组织信息在密钥创建时被写入,并在每次请求时强制验证。两个引导密钥是唯一例外:`admin` 密钥(从 `ADMIN_KEY` 预置)和 `dashboard-assistant` 密钥(从 `AGENT_API_KEY` 预置)是**实例级别**的(不携带组织信息)。仪表板容器使用 `admin` 密钥进行身份验证,以便代表已登录成员代理每个组织的请求。单租户部署无需考虑这一点;所有密钥均归属于内置的 `default` 组织。 + +--- + +## 创建密钥 + +使用管理员密钥(或任何拥有 `keys:create` 权限的密钥)来创建额外的受限密钥。 + +### 采集器密钥(仅写入) + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "prod-collector", + "key": "your-collector-secret", + "permissions": ["events:add"] + }' +``` + +### 仪表板密钥(只读) + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "dashboard", + "key": "your-dashboard-secret", + "permissions": ["events:read", "keys:read"] + }' +``` + +通过 HTTP API 创建密钥时,需要自行提供 `key` 值;请选择一个强密文并妥善保存。(仪表板的方式则相反:它会为你生成一个强密文,并在创建时展示一次;请参阅[仪表板中的密钥管理](#key-management-in-the-dashboard)。)响应将确认密钥已创建: + +```json +{ + "id": "550e8400-e29b-41d4-a716-446655440000", + "name": "prod-collector", + "permissions": ["events:add"], + "created_at": "2026-04-01T12:00:00Z" +} +``` + +--- + +## 列出密钥 + +```bash +curl -s http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +列表响应不返回密钥密文,仅返回 ID、名称和权限。 + +--- + +## 禁用密钥 + +禁用操作将立即吊销访问权限,但不删除密钥记录。 + +```bash +curl -s -X POST http://your-server:8080/keys//disable \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +--- + +## 重新生成密钥 + +为现有密钥生成新的密文。旧密文立即失效。 + +```bash +curl -s -X POST http://your-server:8080/keys//regenerate \ + -H "Authorization: Bearer $ADMIN_KEY" +``` + +响应中包含新的明文密文,**仅展示一次**。 + +--- + +## 仪表板中的密钥管理 + +仪表板中的**密钥**页面提供了执行上述所有操作的 UI 界面。查看列表需要拥有 `keys:read` 权限,创建/编辑/禁用/重新生成操作分别需要 `keys:create` / `keys:update` / `keys:disable` / `keys:regenerate` 权限。编辑密钥权限(`keys:update`)与创建密钥(`keys:create`)是分开的,因此你可以授予操作员创建密钥的能力,而不赋予其重新调整现有密钥权限范围的能力,反之亦然。管理员密钥涵盖所有这些操作。 + +从仪表板创建密钥时无需提供密文;仪表板会为你生成一个强密文,并在创建时**展示一次**。请立即复制并妥善保存;与重新生成操作一样,密文不会再次显示。你仍然可以直接选择密钥的权限,或从权限集中导入(见下文)。 + +![API 密钥页面:每个密钥一张卡片,显示其名称、已授予权限和创建时间,并提供重新生成和禁用操作;受保护的密钥(如 `admin`)有特殊标记](/agenteye/images/api-keys.png) + +--- + +## 推荐的密钥布局 + +| 密钥 | 权限 | 使用方 | +|---|---|---| +| `admin`(通过 `ADMIN_KEY` 环境变量引导) | 全部 | 运营/配置,以及仪表板容器(使用 `ADMIN_KEY` 进行身份验证,并通过权限检查代理用户请求) | +| 每台主机的采集器密钥 | `events:add` | 每台 Agent 机器上的采集器 | +| `dashboard-assistant`(通过 `AGENT_API_KEY` 环境变量引导) | `events:read`、`evaluations:read`、`dashboards:read`、`dashboards:write`、`queries:read`、`queries:write`、`queries:run` | AI 助手容器,自动预置,**受保护**;不能通过 API 编辑 | +| 助手遥测密钥(可选) | `events:add` | AI 助手自我埋点(如已启用) | + +> **助手密钥。** 助手的密钥由服务器从 `AGENT_API_KEY` 环境变量**自动预置**(与 Agent 以 `AGENTEYE_API_KEY` 提交的密文相同);无需手动创建密钥,也不涉及管理员密钥。其权限在源代码中固定,因此无法通过错误配置扩大权限范围:对事件/评估/仪表板的读取权限,以及用于"让 AI 编写查询"创作流程的仪表板写入和查询读取/写入/运行权限。所有 SQL 仍通过与用户自编写查询相同的只读角色和 `sql_guard` 检查,因此这扩展了*创作界面*,而非数据界面;破坏性操作(`queries:delete`、`dashboards:delete`)被刻意排除在助手密钥之外。与 `admin` 密钥一样,它是**受保护的**:不能通过密钥 API 禁用或重新生成,只能通过更改 `AGENT_API_KEY` 并重启来轮换。仪表板**用户**还需要拥有 `agent:use` 权限才能看到并使用助手。如果启用自我埋点,请为助手提供一个单独的仅含 `events:add` 的密钥。 \ No newline at end of file diff --git a/docs/zh/agenteye/assistant.mdx b/docs/zh/agenteye/assistant.mdx new file mode 100644 index 00000000..287ea8c4 --- /dev/null +++ b/docs/zh/agenteye/assistant.mdx @@ -0,0 +1,195 @@ +--- +title: "AI 助手" +description: "AgentEye AI 助手文档。" +--- + +仪表盘包含一个可选的 **AI 助手**——一个停靠在仪表盘右侧的聊天面板,能以自然语言回答关于你的 Agent 的问题(如"本周生产环境的质量趋势如何?"、"今天哪些会话报错了?"、"总结一下这个会话"),并在用户授权后代为起草和保存 SQL 查询及仪表盘。助手会引用可点击的链接,直接跳转到相关会话、查询和仪表盘,同时具备**页面感知能力**:当你正在查看某个会话时询问"这个会话",助手会自动理解你的意图。 + +停靠栏默认显示为一条细 **44px 的垂直轨道**:包含一个 `›_` 提示字形和一个彩色的健康状态点。点击轨道(或按 `⌘J` / `Ctrl+J`)可展开为完整的聊天面板。展开后的面板可通过拖动左边缘在 320 到 640 像素之间**自由调整宽度**,且你的偏好宽度会在刷新后保留。 + +助手作为一个小型内部 **`agent`** 容器运行(基于 Claude Agent SDK),仅供仪表盘访问。**默认情况下处于禁用状态**,需配置 LLM 端点后才会显示。 + +--- + +## 能力范围 + +- **读取发起请求的用户有权访问的运营数据。** 包括事件、评估、会话、评估任务队列、已保存的查询和仪表盘,所有数据均根据用户的读取权限按请求进行范围限定。读取工具立即执行。 +- **写操作需逐项审批。** 助手可以创建已保存查询(`create_saved_query`、`update_saved_query`)、在只读角色下执行草稿 SQL 以进行验证(`run_query`),并将这些查询组合成仪表盘(`create_dashboard`、`update_dashboard`、`add_query_to_dashboard`)。每次写操作都会在聊天中暂停,显示**批准 / 拒绝 / 提问**提示;SDK 在操作员点击"批准"之前不会调用该工具。**助手永远不具备删除能力**;破坏性操作仅限操作员执行。 +- **起草的 SQL 会经过与用户编写的 SQL 相同的 `sql_guard` 验证和只读角色**(仅限 SELECT/WITH,不支持多语句)。执行路由取决于查询涉及的表:引用分析表(事件、评估、会话)的查询以组织的只读 ClickHouse 用户身份运行(通过行策略限定到该组织,执行上限为 10 秒,行数上限为 10 万);仅涉及关系表的查询则在只读 Postgres 角色下运行(10 秒,1 万行)。助手无法扩大数据访问范围,只能在操作员已有的查询权限范围内进行操作。 +- 助手使用**专用助手密钥**(见下文),该密钥预设了固定的权限集;即使模型出现异常行为,也无法超出这些权限范围。 +- 每个仪表盘用户需要拥有 **`agent:use`** 权限才能看到并使用助手。工具会按请求过滤以匹配用户自身的数据权限,例如拥有 `events:read` 的用户可获得事件工具,但不会获得 `dashboards:write` 工具。 + +--- + +## 页面感知的 AI 停靠栏:在 `/queries` 页面作为编辑器,其他页面作为聊天助手 + +右侧的助手停靠栏具有**页面感知能力**。模型选择器、对话历史、模型健康状态点和聊天输入框保持不变,但**空状态模板卡片、占位符文本以及用户消息实际调用的后端端点**都会根据当前路由自动切换。停靠栏会变成"你当前所在页面的 AI 助手"。 + +**两个后端,按页面自动选择(支持按卡片覆盖)。** + +| 路由 | 页面默认后端 | 原因 | +| ------------------------------ | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | +| `/queries`、`/queries/new` | `POST /api/agent/compose-sql`(无工具循环) | 用户正在从头开始;首个 token 延迟 ≤1 秒的 SQL 直接流式输出到编辑器 | +| `/queries/`(已有查询) | `POST /api/agent/chat`(完整工具循环助手),页面默认 | 自由输入的消息应允许用户提任何问题("解释一下"、"这是做什么的?");重构卡片通过 per-chip kind 切换回 compose-sql | +| 其他所有页面 | `POST /api/agent/chat`(完整工具循环助手) | 读取工具 + 审批门控的写入工具 | + +`/queries/` 上的卡片带有明确的 `kind` 字段,使单个页面可以无缝混用两种流程。默认卡片集包含两个**聊天**卡片(`解释当前查询`、`这个查询做什么?`)和五个 **compose-sql** 卡片(`按日期范围参数化`、`添加 status='error' 过滤条件` 等)。自由输入的消息回落到页面默认(聊天),因此"为什么这么慢?"这类问题会获得散文式回答,而点击`按日期范围参数化`卡片则会路由到 compose 端点并修改 SQL。 + +当编辑器处于**编辑模式**时(因为用户在 `/queries/` 上,或者 `/queries/new` 已加载了待处理的 SQL,导致 `currentSql` 不为空),系统提示词会从"编写一个新查询"切换为"对所提供的 SQL 进行最小化修改:保留表的选择、列名、连接结构、别名和缩进"。模型会接收到一组独立的修改前后示例(参数化、添加过滤条件、转换为按小时分桶),因此通过卡片触发的重构会生成针对编辑器中 SQL 的最小差异,而不是从头重写。 + +点击 compose 卡片(或在 `/queries/new` 上自由输入)→ SQL 以 ` ```sql ` 代码块的形式流式输出到助手消息中。**当流输出完成后,若当前路由挂载了 Monaco 编辑器,编辑器会自动进入差异视图**(左侧为原始内容,右侧为建议内容,顶部有`▾ AI 提出了修改`提示,下方有**接受 / 拒绝**按钮)。用户无需查找或点击"插入编辑器"按钮即可看到差异。"插入"按钮仍会显示在 SQL 块下方,作为手动重新触发的入口(在拒绝后或用户离开又返回时很有用);当用户在非编辑器页面(例如已保存查询列表)时,它是唯一的操作路径——此时会将 SQL 暂存到 `sessionStorage` 并跳转到 `/queries/new`,新挂载的编辑器在初始化时读取暂存内容并打开相同的差异视图。 + +如果建议的 SQL 与编辑器中已有的内容完全相同(无实质性修改),则跳过自动打开差异视图,避免弹出空差异。此时"插入编辑器"按钮同样不执行任何操作。 + +当用户在 `/queries/new` 上接受建议时,工具栏的主操作按钮显示为**`保存`**而非`创建`;SQL 由助手生成,操作的心智模型是"最终确认"而非"从头编写"。停靠栏插入 SQL 后标签立即切换为`保存`,直到页面导航才恢复。在 `/queries/` 上按钮始终为`保存`,不受影响。 + +在 `/queries` 以外的页面,停靠栏的行为与之前完全一致:带有工具审批卡片的完整聊天、页面上下文感知和引用链接。 + +**权限 / 访问控制。** compose 端点按用户的 `queries:run` 权限进行门控(等同于读取权限;用户仍需点击"接受"和"运行",而"运行"会经过 Rust 服务器上现有的 `sql_guard` + `references_ch_tables` 路由)。chat 端点按 `agent:use` 门控。两者都要求在 `agent` 容器上配置了 LLM 连接;若未配置,停靠栏会在两种路径上均显示"此部署未配置助手"的横幅。 + +**拒绝策略。** compose 模式会拒绝任何无法通过只读分析查询满足的请求,并输出 `-- REFUSE: <一句话原因>` 代替 SQL。它会拒绝会写入数据或访问分析视图以外的表(`api_keys`、`users`、`dashboards`、`saved_queries`、`evaluation_jobs`)的请求,也会拒绝在 compose 路径上的纯文本请求(如"解释一下"、"这是做什么的?")——这类请求应走 chat 路径并在那里获得散文式回答。停靠栏会将拒绝原因以内联红色错误卡片的形式显示在助手消息中,不插入任何内容。 + +**模型选择。** 与聊天路径共享。停靠栏标题中的模型选择器适用于两个端点(compose 调用会将选中的模型传递给 agent 服务上的 `resolveModel()`)。当 `AGENTEYE_AGENT_MODELS` 列出多个模型时,操作员可以为 compose 选择 Haiku 级别的模型,为聊天选择 Sonnet 级别的模型;用户按对话进行选择。 + +**按页面定制模板。** 每个页面都有自己的模板(标题、正文、占位符文本和建议卡片),使停靠栏能够适应你所在的页面。特定路由上提供的卡片与 compose 模型调优的意图一致,因此点击建议会产生预期的修改效果。 + +**禁用方式。** 与聊天路径相同:停靠栏和 compose 功能都通过 `agent` 容器及其 LLM 连接进行门控。如果你希望特定用户只使用聊天功能,移除 `queries:run` 权限(这也会禁用编辑器的**运行**按钮);如果你希望只使用 compose 功能,从该用户的角色中移除 `agent:use`,然后单独重新添加 `queries:run`,这样他们仍然可以执行自己编写的 SQL。 + +--- + +## 启用方式 + +`agent` 服务已包含在 Docker Compose 文件和 Kubernetes 清单中。要启用助手,需要提供 **(1)** LLM 端点 和 **(2)** 助手专用数据密钥。 + +### 1. 选择 LLM 连接方式 + +从以下选项中选择一种,并在 `agent` 服务上设置对应的变量: + +**a) 直接使用 Anthropic** + +``` +ANTHROPIC_API_KEY=sk-ant-... +``` + +**b) 通过 Portkey(推荐;使用模型目录 slug,仅需密钥)** + +``` +PORTKEY_API_KEY= +AGENTEYE_AGENT_MODEL=@/claude-sonnet-4-6 +``` + +这是最简单的方式:在 Portkey 中设置一个 **Anthropic 集成**(模型目录),系统会生成一个 **slug**。将模型命名为 `@/`,slug 中包含了 provider 和凭证路由,因此**不需要虚拟密钥**,只需你的 Portkey API 密钥即可。Agent 只发送 `x-portkey-api-key` 并指向 Portkey 网关,Portkey 负责解析其余内容。(使用*普通*模型名称会报错"x-portkey-config or x-portkey-provider header is required";`@slug/` 前缀是实现纯密钥访问的关键。)如需使用自托管网关,请设置 `PORTKEY_BASE_URL`。 + +如果你偏好按请求路由而非使用 slug,可以设置 `PORTKEY_VIRTUAL_KEY=`(或 `PORTKEY_CONFIG=`)配合普通的 `AGENTEYE_AGENT_MODEL`。 + +**c) 其他兼容 Anthropic 的网关(LiteLLM、自托管等)** + +``` +ANTHROPIC_BASE_URL=https://your-gateway +# 换行分隔的"Name: Value"格式请求头(非 JSON): +ANTHROPIC_CUSTOM_HEADERS=x-my-header: value +``` + +**d) Amazon Bedrock / Google Vertex** + +``` +CLAUDE_CODE_USE_BEDROCK=1 # + 环境中的标准 AWS 凭证 +# 或 +CLAUDE_CODE_USE_VERTEX=1 # + 环境中的标准 GCP 凭证 +``` + +可选地使用 `AGENTEYE_AGENT_MODEL` 固定默认模型(默认值为 `claude-sonnet-4-6`)。若需允许用户**从多个模型中选择**,将 `AGENTEYE_AGENT_MODELS` 设置为逗号分隔的允许列表(例如 `@anthropic-prod/claude-opus-4-7,@anthropic-prod/claude-sonnet-4-6`);聊天标题中会出现模型选择器,每个用户的选择会被记住。Agent 只会调用此允许列表中的模型。 + +### 2. 提供助手密钥 + +选择任意随机密钥,将其作为 `AGENTEYE_API_KEY` 提供给 **agent** 服务,同时作为 `AGENT_API_KEY` 提供给 **server** 服务(值相同)。服务器启动时会将其注册为名为 `dashboard-assistant` 的专用密钥,并赋予以下固定权限集:`events:read`、`evaluations:read`、`dashboards:read`、`dashboards:write`、`queries:read`、`queries:write`、`queries:run`。写入权限只通过审批门控的工具执行(见上文"能力范围"部分)。**无需手动创建密钥,也不涉及管理员密钥**。权限集在服务器中固定,且注册的密钥**受保护**:无法通过 keys API 禁用或重新生成;如需轮换,只需更改值并重启服务器。**请勿复用管理员/仪表盘密钥。** + +```bash +SECRET="$(openssl rand -base64 32)" +# 在 agent 服务上: +AGENTEYE_API_KEY="$SECRET" +# 在 server 服务上: +AGENT_API_KEY="$SECRET" +``` + +在 Kubernetes 上已为你完成配置:将 `AGENTEYE_API_KEY` 放入 `agenteye-agent` secret 中,服务器 Deployment 已自动将相同的值作为 `AGENT_API_KEY` 读取。 + +### 3. 设置仪表盘与 Agent 之间的共享令牌 + +在 **`dashboard`** 和 **`agent`** 服务上设置相同的 `AGENTEYE_AGENT_TOKEN`。仪表盘在调用内部 agent 服务时出示该令牌;Agent 会拒绝不携带此令牌的请求。 + +### 4. 授予用户访问权限 + +为相关的仪表盘操作员授予 `agent:use` 权限(参见 [enterprise-docs/api-keys.md](/zh/agenteye/api-keys))。没有该权限的用户将看不到助手。 + +配置好 LLM 端点和只读密钥后,重启 **server**(以注册只读密钥)和 **agent** 服务。任何拥有 `agent:use` 权限的用户的仪表盘右侧都会出现助手停靠栏,默认收起;点击轨道或按 `⌘J` / `Ctrl+J` 展开。 + +--- + +## 环境变量参考 + +在 **`agent`** 服务上设置: + +| 变量 | 用途 | +|---|---| +| `PORTKEY_API_KEY` | 通过 Portkey 路由(agent 据此构建网关连接) | +| `PORTKEY_VIRTUAL_KEY` | 你的 Anthropic 凭证的 Portkey 虚拟密钥(如果该密钥有默认配置则可选) | +| `PORTKEY_CONFIG` / `PORTKEY_BASE_URL` | 命名的 Portkey 配置 / 自托管 Portkey 网关 URL(可选) | +| `PORTKEY_PROVIDER` | Portkey provider slug——除 `PORTKEY_VIRTUAL_KEY` / `PORTKEY_CONFIG` 之外的第三种路由选项(仅在两者均未设置时使用) | +| `ANTHROPIC_API_KEY` | 直接访问 Anthropic(网关 / Bedrock / Vertex 的替代方案) | +| `ANTHROPIC_AUTH_TOKEN` | 用于通过 `Authorization: Bearer` 而非 `x-api-key` 进行身份验证的网关的 Bearer 令牌(可选) | +| `ANTHROPIC_BASE_URL` | 非 Portkey 网关的端点 | +| `ANTHROPIC_CUSTOM_HEADERS` | 非 Portkey 网关的额外请求头:换行分隔的 `Name: Value` 格式(非 JSON) | +| `CLAUDE_CODE_USE_BEDROCK` / `CLAUDE_CODE_USE_VERTEX` | 通过 Bedrock / Vertex 路由 | +| `AGENTEYE_AGENT_MODEL` | 默认模型 ID(默认值 `claude-sonnet-4-6`) | +| `AGENTEYE_AGENT_MODELS` | 用户可在聊天标题中选择的模型允许列表(逗号分隔)。不设置则使用单一固定模型。上述默认值必须包含在列表中(否则会自动添加)。 | +| `AGENTEYE_AGENT_MAX_CONCURRENCY` | 每个 Pod 的最大并发聊天数(默认 4);超出的请求返回 429 | +| `AGENTEYE_API_KEY` | 助手的数据密钥。与服务器的 `AGENT_API_KEY` 设置**相同**的值,服务器启动时会将其注册为具有固定范围权限集的密钥(见步骤 2)。 | +| `AGENTEYE_AGENT_TOKEN` | 与仪表盘共享的密钥 | +| `AGENTEYE_SERVER_URL` | AgentEye 服务器 URL(默认值 `http://server:8080`) | +| `AGENTEYE_AGENT_ALLOW_NO_ORG` | **多租户支持。** 默认关闭(安全失败):若 `/chat` 请求不携带组织上下文,助手会返回 `400` 拒绝请求,因为其所有工具都限定在单个组织范围内。仪表盘一旦具有组织感知能力,就会始终发送该上下文,因此通常无需设置此变量。仅在过渡期内使用,即尚未具备组织感知能力的仪表盘与已具备组织感知能力的 agent 通信时,设置为 `1` 使助手回退到 `default` 组织而非拒绝请求。仪表盘升级完成后请清除此设置。 | +| `AGENTEYE_AGENT_MAX_STEPS` | 每次回答的最大工具调用步数(默认 8) | +| `AGENTEYE_AGENT_TIMEOUT_MS` | `/chat` 请求的整体超时时间(包括所有模型轮次和工具步骤),单位毫秒(默认 90000);SQL 工具有独立的 10 秒上限 | +| `AGENTEYE_AGENT_SELF_TELEMETRY` | 设为 `1` 以将助手自身的运行记录到 AgentEye 中 | +| `AGENTEYE_TELEMETRY_API_KEY` | 用于自监控的独立 `events:add` 专用密钥 | +| `AGENTEYE_AGENT_ENV` | 应用于助手自监控数据的环境标签(默认值 `prod`) | + +在 **`dashboard`** 服务上设置: + +| 变量 | 用途 | +|---|---| +| `AGENTEYE_AGENT_URL` | 仪表盘访问 agent 服务的地址。随附的 Kubernetes 清单和 Compose 文件将此设置为 `http://agent:9100`。不设置则完全隐藏助手。 | +| `AGENTEYE_AGENT_TOKEN` | 必须与 agent 的令牌一致 | + +--- + +## 遥测与查看用户提问内容 + +提示词**内容默认保留在你自己的系统内**。共有三个层次: + +1. **对话存储**:每个提示词和回答都保存在你的 AgentEye 数据库中(按用户,私密),可从助手的历史记录切换器中重新加载。这是用户提问内容的持久记录。 +2. **产品分析**:仪表盘仅记录**元数据**(助手的使用频率、工具调用次数、延迟)到你的分析系统。此路径**不包含**提示词**文本**。 +3. **自监控(可选)**:设置 `AGENTEYE_AGENT_SELF_TELEMETRY=1`(以及仅具有 `events:add` 权限的 `AGENTEYE_TELEMETRY_API_KEY`),助手会将自身的运行记录到 AgentEye 中,以 `dashboard-assistant` agent 的身份存储。然后你可以在用于其他所有内容的同一会话/事件视图中查看用户提示词和助手的推理过程。注意:这些事件对任何拥有 `events:read` 权限的人可见;如果范围过广,请不要启用此功能。 + +--- + +## 禁用方式 + +以下任意一种方式均可禁用助手(停靠轨道消失): + +- 在仪表盘上取消设置 `AGENTEYE_AGENT_URL`,**或** +- 在 agent 上不配置 LLM 端点(不设置 `ANTHROPIC_API_KEY` / 网关 / Bedrock / Vertex),**或** +- 完全不部署 `agent` 服务。 + +--- + +## 安全摘要 + +- **无静默写入**:助手的写入工具(`create_saved_query`、`update_saved_query`、`create_dashboard`、`update_dashboard`、`add_query_to_dashboard`)在操作员明确点击聊天中的"批准"按钮之前无法执行;SDK 的调用前拦截会阻止工具执行,直到审批信号通过后台通道到达 agent。此拦截机制没有任何禁用设置。 +- **固定且受限的数据范围**:助手通过专用密钥向服务器进行身份验证,该密钥的权限集在服务器中固定(`events:read`、`evaluations:read`、`dashboards:read`、`dashboards:write`、`queries:read`、`queries:write`、`queries:run`)。它能够创建的写入内容仅限于已保存的查询和仪表盘;无论模型尝试什么操作,服务器都会拒绝超出该范围的请求。 +- **无删除权限**:密钥不包含删除权限,也不暴露任何删除工具。删除操作通过仪表盘 UI 由操作员执行,不经过助手。 +- **仅限内部访问**:agent 没有公开路由;只有仪表盘可以调用它,且必须携带共享令牌。(在 Kubernetes 中,NetworkPolicy 限制 agent 只能访问 AgentEye 服务器和 LLM 端点。) +- **按用户范围限定**:只有拥有 `agent:use` 权限的用户才能使用助手,且只提供与每个用户读取权限匹配的工具。 +- **无原始 HTML / 无链接外泄**:回答以经过净化处理的 Markdown 格式渲染;外部链接已被无害化处理。 + +常见问题请参见 [enterprise-docs/troubleshooting.md](/zh/agenteye/troubleshooting)。 \ No newline at end of file diff --git a/docs/zh/agenteye/audits.mdx b/docs/zh/agenteye/audits.mdx new file mode 100644 index 00000000..1beaf9e6 --- /dev/null +++ b/docs/zh/agenteye/audits.mdx @@ -0,0 +1,107 @@ +--- +title: "Audits — 智能改进检测" +description: "AgentEye Audits — 智能改进检测文档。" +--- + + +Audits 是定期运行的任务,跨会话挖掘 Agent 日志,寻找值得改进的内容。告警监控的是你已知的某个指标(近实时),而 Audit 则是**主动调查**:按你设定的计划,对时间窗口内的数据执行确定性的策略检查,然后让一个 **AI 可靠性 Agent** 对你的会话展开深入分析——该 Agent 自主查询数据、阅读可疑会话记录,必要时运行小型分析脚本,最终输出附有证据支撑的**改进建议**。 + +用 Audits 回答「我的 Agent 该修什么、怎么改进」,用告警在某个具体阈值被突破的瞬间收到通知。每条改进建议都链接到背后的具体会话和查询,一键即可创建预填好的告警,防止问题复发。 + +仪表板入口为 **`//audits`**(侧边栏 → *analyze* → *audits*),需要 `audits:read` / `audits:write` 权限。 + +--- + +## 一次运行的工作原理 + +每次运行包含两个层次——确定性的基础层和智能调查层。 + +### 1. 策略检查(确定性) + +在任何模型运行之前,Audit 会对时间窗口内的数据执行一批**SQL 策略检查**:有界的聚合查询,用于标记已知的问题模式,并报告有*多少*事件/*哪些*会话命中——但从不暴露命中的原始文本。检查目录包括: + +- **事件载荷中的密钥/凭据泄漏** — AWS 访问密钥、`sk-…` 格式的 API 密钥、PEM 私钥、JWT / Bearer Token,以及 `KEY=…` 形式的凭据赋值。 +- **提示注入标记** — 「ignore previous instructions」「reveal your system prompt」等类似语句。 +- **PII** — 符合 SSN 格式的数字(启发式匹配)。 +- **工具权限拒绝**和**工具调用失控循环**。 + +策略命中结果作为 findings(类型为 `policy`)持久化保存,**始终展示**(不受每次运行上限的限制),并作为初始线索交给 AI Agent。由于该层无需任何模型,即使 AI Agent 不可用,Audit 仍能产出最重要的安全信号。 + +### 2. 智能调查(AI) + +Audit 随后运行一个**自主可靠性 Agent**(与仪表板助手同款的 Claude Agent SDK 服务,但使用针对 Audit 的专用提示词)。Agent 根据 Audit 的**范围**(选定的 Agent × 环境)和**时间窗口**,执行以下操作: + +- 对你的分析表执行只读 SQL 查询; +- 阅读少量具有代表性的会话记录; +- 可选地在**隔离的 Pod 内沙箱**(无网络、无文件系统访问、密钥已清除)中编写并运行短小的 **Python 脚本**,处理 SQL 难以表达的分析任务——错误聚类、计算分布、对已抓取的载荷进行扫描; +- 记录每一条有充分证据支撑的**改进建议**。 + +Agent 从多条调查线索切入——错误聚类、与基线的偏差、会话记录中的目标失败、工具误用、质量/成本权衡、以及覆盖盲点——深度由 Audit 的**灵敏度**(低 / 中 / 高)决定。每条改进建议**必须引用证据**:Agent 实际检查过的会话 ID 和/或执行过的 SQL。服务器会验证所引用的会话确实存在,并**丢弃所有没有有效证据的改进建议**——Agent 只做调查,不做杜撰。 + +每条改进建议包含: + +- **建议**(具体的改进措施——调整提示词、修复工具 schema、调整重试策略、添加护栏、补充评估覆盖); +- **预期影响**和**工作量**估算(低 / 中 / 高); +- **重要程度** — `big`(需要立即通知运营人员)、`medium`(纳入本次运行报告)、`small`(仅作为仪表板上下文信息); +- 一个稳定的**指纹**(由问题的类别 + 范围生成,*而非*本次运行的会话),使同一问题在多次运行间可持续追踪,即使证据在变化; +- 以及,若某个简单的确定性监控器即可捕捉复发,则附带一条**建议告警**,一键即可创建。 + +> **AI 层是可选但推荐的。** 如果 Audit 流水线未配置 AI Agent,运行仍会执行并持久化策略 findings,并在智能层诚实报告「分析不可用」,而非悄然通过。 + +### 失败模式 + +改进建议会归类到你的组织持久化的**失败模式目录**中(或提议新增一种模式)。失败模式为跨运行的模式提供稳定的身份标识,支持长周期的复发追踪。 + +## 分类处理生命周期 + +在 finding 详情页(`/audits//findings/`): + +| 操作 | 效果 | +|---|---| +| **acknowledge(确认)** | 保持 finding 可见,但将其优先级降低一半。 | +| **resolve(解决)** | 标记为已修复。若该模式后来真正复现,会以**新**的状态重新打开——回归问题会被明确提示,而不会悄然折叠进历史记录。 | +| **mute(静音)** / **dismiss(忽略)** | 持久性抑制:记住该模式的指纹,即使跨多次运行也不再展示。mute 用于「已知、已接受」;dismiss 用于「无参考价值」。 | +| **reopen(重新打开)** | 清除抑制/解决状态,重新对该模式排列优先级。 | +| **assign(指派)** | 将 finding 路由给某位运营人员(组织成员)负责跟进,优先级和抑制状态不变。 | + +低信噪比的噪声通过每次运行的 findings 上限(`top_k`)在每个 Audit 中单独控制,仅限制智能层的改进建议。策略 findings 不受上限约束(与安全相关,始终展示)。被上限截断的内容会计入本次运行的统计数据——没有任何内容被悄然丢弃。 + +## 调度 + +- **频率**(`schedule_interval_secs`):从每小时到每周;**默认为每天**。Audits 的粒度刻意粗于告警——智能调查需要扫描完整时间窗口,运行时间长达数分钟。 +- **时间窗口**:固定滚动回溯(如「每次运行扫描过去 7 天」)或**自上次运行起**(默认)——每次运行从上一次成功运行结束的地方续接,并保留少量重叠,确保边界事件不被遗漏。 +- 下一次运行在上一次运行**完成**后整整一个间隔后才会调度,因此慢速运行不会导致同一个 Audit 堆叠出第二个并发运行。 +- Audit 页面上的 **Run now** 可立即触发运行。 + +## 模型选择 + +创建 Audit 时,可以从**运营人员为 Agent 服务配置的模型列表**中选择调查使用的模型。只配置了一个模型时,选择器以标题形式展示;配置了多个时,可手动选择。留空则使用已配置的默认模型。 + +## 通知 + +运行产出**新的** findings 时,Audit 会通过你的组织已配置的渠道发送通知——与告警流水线使用相同的 `alerts.enabled_channels` 门控和配置: + +- **Slack** — 汇总重要(`big`)的新条目,并附带深层链接。 +- **Email** — 一份精心排版的 **Audit 报告**,列出新的改进建议(按严重程度排序、每条附带建议、附深层链接),在 Audit 配置了 **email** 渠道且至少有一条新 finding 时发送。 + +反复出现但已知的 findings 不会重复通知。 + +## 配置参考 + +Audit 定义可在仪表板(`/audits/new`)或通过 API 管理。每个 Audit 的配置项包括:调度频率和时间窗口、范围(`{"environments": [...], "agent_ids": [...]}`)、灵敏度(`low` / `medium` / `high`)、通知渠道、每次运行的 findings 上限(`top_k`),以及模型(通过 `llm_budget.model`)。运营人员级别的服务器配置(超时、沙箱、Agent 服务 URL)详见 [deployment.md](/zh/agenteye/deployment)。 + +## API + +所有端点均以组织为作用域,使用标准 Bearer 密钥认证(参见 [api-keys.md](/zh/agenteye/api-keys))。 + +| 端点 | 权限 | 用途 | +|---|---|---| +| `GET /audits` · `POST /audits` | `audits:read` / `audits:write` | 列出 / 创建 Audit 定义。 | +| `GET` / `PUT` / `DELETE /audits/:id` | read / write / write | 查看、编辑、删除某个 Audit。 | +| `POST /audits/:id/run` | `audits:write` | 立即触发该 Audit 运行。 | +| `GET /audits/:id/runs` | `audits:read` | 运行历史(时间窗口、状态、统计数据、findings 数量)。 | +| `GET /audits/findings` | `audits:read` | 组织范围内的 findings,可按 `audit_id`、`status` 筛选,按优先级排序。 | +| `GET /audits/findings/:fid` | `audits:read` | Finding 完整详情(建议、证据、优先级)。 | +| `POST /audits/findings/:fid/status` | `audits:write` | 分类处理:`{"action": "ack" \| "mute" \| "dismiss" \| "resolve" \| "reopen" \| "assign"}`。 | + +关于「Audit 运行但未发现任何内容」「代码沙箱被禁用」「Audit 邮件未送达」等问题,请参见 [troubleshooting.md](/zh/agenteye/troubleshooting#audits)。 \ No newline at end of file diff --git a/docs/zh/agenteye/cli-recipes.mdx b/docs/zh/agenteye/cli-recipes.mdx new file mode 100644 index 00000000..e06d3a42 --- /dev/null +++ b/docs/zh/agenteye/cli-recipes.mdx @@ -0,0 +1,170 @@ +--- +title: "面向 Agent 的 CLI 使用手册" +description: "AgentEye 面向 Agent 的 CLI 使用手册文档。" +--- + + +直接在脚本或编码 Agent 中拉取会话、事件和评估数据(并触发重新评估),输出为 stdout 上干净的 JSON,可直接通过管道传入 `jq`。这些手册将 AgentEye 的可观测性数据转化为终端用户或 AI 编码 Agent(Claude Code、Cursor)可查询和自动化的形式,无需点击仪表板。 + +以下示例均可直接复制粘贴用于 AgentEye CLI(`agenteye`)。安装、认证及完整选项列表,请参阅 [CLI](/zh/agenteye/cli);运行 `agenteye -h` 或 `agenteye -h` 查看内置帮助。 + +## 黄金法则 + +1. **全局选项必须放在命令*之前*。** `agenteye --json sessions` 是正确的;`agenteye sessions --json` 则不对。全局选项包括 `--json`、`--base-url`、`--org`、`--token`、`--insecure`/`--secure`、`--timeout`、`--quiet`、`--no-color`。 +2. **解析输出时务必传入 `--json`。** 数据以 JSON 格式输出到 **stdout**;人类可读的状态信息和错误输出到 **stderr**,因此 stdout 保持干净,可直接管道传入 `jq`。 +3. **根据退出码判断结果**,而非 stderr 文本:`0` 成功 · `2` 参数错误 · `3` 无法连接仪表板 · `4` 未登录或会话已过期 · `5` 缺少权限。 +4. **用 `-h` 探索命令。** 每个命令都记录了其过滤器、值格式和 JSON 结构。 + +## 一次性初始化 + +```bash +export AGENTEYE_DASHBOARD_URL=https://agenteye.example.com # 避免重复输入 --base-url +agenteye login --email you@example.com # 粘贴邮件中的验证码;有效期约 24 小时 +``` + +## 执行操作前确认认证状态 + +`whoami` 在会话缺失或已过期时不会报错,而是返回 `logged_in:false`,因此 Agent 可以安全地探测认证状态。(如果未设置 base URL 或仪表板不可达,它仍可能以非零退出码退出。) + +```bash +if [ "$(agenteye --json whoami | jq -r .logged_in)" != "true" ]; then + echo "未认证。请运行:agenteye login" >&2; exit 1 +fi +``` + +## 查找失败或低分会话 + +```bash +# 过去 24 小时内评估出错的会话 +agenteye --json sessions --since 24h --status error | jq -r '.sessions[].session_id' + +# 某个 Agent 的 helpfulness 评分 <= 0.5 的评估 +agenteye --json evals --agent-id checkout-bot --score helpfulness:..0.5 \ + | jq '.evaluations[] | {session_id, scores}' +``` + +评分过滤在 **`evals`** 上,而非 `sessions`。`--score KEY:MIN..MAX` 可重复使用,多个条件取 AND;任一边界均可省略(`..0.5` 表示 ≤ 0.5,`0.9..` 表示 ≥ 0.9)。每次请求最多可传入 20 个评分过滤条件;超出则返回 HTTP 400。`sessions` 与 `evals` 共享 `--env`、`--status`、`--agent-id`、`--session-id` 及时间范围过滤器,但不支持 `--score`。 + +## 完整读取一个会话 + +没有单独的 `session show` 命令——将事件轨迹与会话评估结合使用: + +```bash +# 会话的最新评估(状态 + 评分) +agenteye --json evals --session-id run-001 | jq '.evaluations[0] | {status, scores}' + +# 运行中的所有事件(增大 --limit 以获取完整数据) +agenteye --json events --session-id run-001 --all --limit 1000 | jq '.events[] | {ts, event_type}' + +# 仅获取会话中的工具调用 +agenteye --json events --session-id run-001 --event-type tool_use,tool_result --all \ + | jq '.events[].payload' +``` + +## 获取全部数据(分页) + +结果按最新优先排序,并使用游标分页。 + +```bash +# 一次性获取:以每页 200 条的方式最多获取 500 条数据 +agenteye --json events --session-id run-001 --limit 500 --all > events.json + +# 手动分页:将 next_cursor 传回 +page=$(agenteye --json events --limit 100) +cursor=$(echo "$page" | jq -r '.next_cursor // empty') +[ -n "$cursor" ] && agenteye --json events --limit 100 --cursor "$cursor" +``` + +## 使用 --fields 精简输出 + +限制返回的字段(在表格和 `--json` 模式下均有效),以减少 Agent 需要处理的数据量。 + +```bash +agenteye --json sessions --since 7d --fields session_id,status,scores | jq -c '.sessions[]' +agenteye --json events --session-id run-001 --fields ts,event_type --all +``` + +未知字段名会被拒绝(退出码 `2`)并返回有效字段列表,这也是探索字段名的便捷方式。 + +## 探索有效的过滤器值 + +```bash +agenteye --json list envs | jq -r '.values[]' # --env 的可用值 +agenteye --json list tools | jq -r '.values[]' # 工具名称;也可查询 agents、models、event_types 等 +agenteye --json list score_filters | jq -r '.values[]' # --score KEY:MIN..MAX 中有效的 KEY +``` + +## 选择组织(多租户) + +如果您属于多个组织,可在登录时选择当前租户(该设置会被保存): + +```bash +agenteye login --org acme --email you@corp.com # 登录的同时设置租户 +agenteye --json orgs list | jq -r '.orgs[].org_slug' +agenteye --org globex --json sessions --since 24h # 仅对单次命令生效的覆盖 +``` + +多组织账户在未指定 `--org` 时会以非零退出码退出,并打印可供选择的组织列表。 + +## 为 SDK/收集器创建 API Key + +```bash +# Secret 仅打印一次——使用 --json 时为 .key 字段 +key=$(agenteye --json keys create ci-bot --add events:read.add | jq -r '.key') +agenteye keys regenerate ci-bot --yes # 轮换密钥;使用 agenteye keys disable ci-bot --yes 撤销 +``` + +## 运行已保存或临时查询 + +```bash +agenteye --json query run --sql "select count(*) from analytics.events" | jq '.rows' +agenteye --json query run errs --arg prod | jq '.rows' # 已保存的查询 + 位置参数 $1 +``` + +## 非交互式处理告警事件 + +```bash +id=$(agenteye --json incidents list --state firing | jq -r '.incidents[0].id') +agenteye incidents ack "$id" +agenteye incidents assign "$id" you@corp.com +agenteye incidents resolve "$id" --yes +``` + +> 变更操作在使用 `--json` 或 stdin 不是 TTY 时会自动跳过确认提示,因此 Agent 不会卡住;在其他情况下,可显式传入 `--yes`/`-y` 跳过确认。 + +## 脚本中的退出码处理 + +```bash +out=$(agenteye --json sessions --since 1h) || code=$? +case "${code:-0}" in + 0) echo "$out" | jq '.sessions | length' ;; + 4) echo "会话已过期,请运行 'agenteye login'。" >&2 ;; + 5) echo "缺少权限(请联系管理员获取 evaluations:read 权限)。" >&2 ;; + 3) echo "仪表板不可达,请检查 URL。" >&2 ;; + *) echo "未知错误(退出码 ${code})。" >&2 ;; +esac +``` + +## JSON 输出结构 + +| 命令 | stdout JSON(使用 `--json`) | +|---|---| +| `whoami` | `{"logged_in": true, "id", "email", "is_instance_admin", "active_org", "permissions": [...], "memberships": [...]}` 或 `{"logged_in": false}` | +| `orgs list` | `{"active_org", "orgs": [{"org_slug","org_name","permission_set","permissions"}]}` | +| `events` | `{"events": [...], "next_cursor": }` | +| `evals` | `{"evaluations": [...], "next_cursor": }` | +| `sessions` | `{"sessions": [...], "next_cursor": }` | +| `errors` | `{"errors": [...], "next_cursor": }` | +| `list ` | `{"kind", "values": [...]}` | +| `keys list` / `keys create` | `{"keys": [...]}` / `{id, name, permissions, created_at, key}`(`key` 仅显示一次) | +| `query run` | `{columns: [{name,type}], rows: [[...]], truncated, elapsed_ms}` | +| `users list` / `settings list` | `{"users": [...]}` / `{"settings": [...]}` | +| `alerts list` / `incidents list` | `{"alerts": [...]}` / `{"incidents": [...]}` | +| create/update/delete(任意) | 资源对象,或删除时返回 `{"deleted": true, "id"}` | +| 失败(任意,使用 `--json`) | stdout 输出 `{"error": "...", "exit_code": , "status"?: , "hint"?: "..."}` | + +- 每条 **event** 记录(`events`):`id, session_id, agent_id, event_type, ts, payload, environment`。 +- 每条 **evaluation** 记录(`evals`):`id, session_id, agent_id, environment, status, scores, reasoning, summary, error, attempt_count, duration_ms, completed_at, created_at`。 +- 每条 **session** 记录(`sessions`):`session_id, agent_id, environment, status, scores, event_count, started_at, last_event_at, first_event_id, last_event_id, latest_evaluation`。 + +每个命令的 `--fields` 仅接受其自身记录中的字段名——`sessions` 和 `evals` 的字段集不同,因此对一个命令有效的字段名可能会被另一个命令拒绝。 \ No newline at end of file diff --git a/docs/zh/agenteye/cli-skill.mdx b/docs/zh/agenteye/cli-skill.mdx new file mode 100644 index 00000000..97742769 --- /dev/null +++ b/docs/zh/agenteye/cli-skill.mdx @@ -0,0 +1,95 @@ +--- +title: "AgentEye CLI Agent Skill" +description: "AgentEye AgentEye CLI Agent Skill 文档。" +--- + + +**AgentEye CLI skill**(`agenteye-cli`)是一个可安装的 *Agent Skill*,它能让编程助手 —— Claude Code、Codex 及兼容工具 —— 通过自然语言请求来操作你的 AgentEye 部署,底层调用的是 [`agenteye` CLI](/zh/agenteye/cli)。比如:*"今天有没有什么问题?"*、*"给 CI 创建一个只能推送事件的密钥"*、*"确认正在触发的告警并分配给我"*。 + +它**不是**一项服务,也不是一个独立的二进制文件。它是一个小型指令包,依托你已安装的 CLI 运行:Agent 会调用 `agenteye --json …`,解析返回的 JSON,然后以自然语言回答你。它能做的一切,你自己输入同样的命令也完全可以实现。 + +--- + +## 与其他 AgentEye 界面的关系 + +AgentEye 提供四种方式访问相同的数据和控制功能,它们相辅相成: + +| 界面 | 说明 | 运行环境 | 适用场景 | +|---|---|---|---| +| **[CLI](/zh/agenteye/cli)** | `agenteye` 的命令与参数参考 | 你的终端 | 需要运行或脚本化某个具体命令时 | +| **[CLI 使用示例](/zh/agenteye/cli-recipes)** | 可直接复制使用的 `jq`/管道模式 | 终端 / 脚本 | 将 CLI 集成到自动化流程时 | +| **CLI skill**(本文档)| CLI 的自然语言入口 | 你工作站上的编程助手 | 想直接提问、让 Agent 自行选择命令时 | +| **[控制台内置 AI 助手](/zh/agenteye/assistant)** | 嵌入控制台的对话界面 | 集群中的内部 `agent` 容器 | 需要在控制台内针对数据进行问答时 | + +### 与控制台内置 AI 助手的区别——重要说明 + +这是两个截然不同的工具,影响范围差异很大: + +- **控制台内置 AI 助手**([assistant.md](/zh/agenteye/assistant))是嵌入控制台的对话界面,由内部 `agent` 容器提供支持。它是**只读加审批式写入**:可以草拟已保存的查询和仪表盘,但每次写操作都需要你明确点击确认,且不会执行删除操作。它受 `agent:use` 权限控制,只能访问你当前查看的组织数据。 +- **CLI skill** 运行在*你的*工作站上,置于*你的*编程助手中,以**你的身份**驱动 `agenteye` CLI。它能执行 CLI 的**全部功能,包括变更操作** —— 创建/轮换/禁用 API 密钥、修改组织设置、处理告警、删除已保存的查询 —— 仅受你 CLI 登录权限的限制。请像对待自己手动执行这些命令一样,谨慎使用它。 + +--- + +## 前置条件 + +1. 已安装 **`agenteye` CLI** 并加入 `PATH`(参见 [cli.md](/zh/agenteye/cli) — `pipx install agenteye`)。 +2. 已设置**控制台 URL**(`AGENTEYE_DASHBOARD_URL`,或由 Agent 传入 `--base-url`)。 +3. 已完成**登录**:请先手动执行 `agenteye login`。该 skill **无法**替你完成邮件一次性验证码登录——如果会话缺失或已过期(CLI 退出码为 `4`),它会提示你运行 `agenteye login`。 + +--- + +## 安装 Skill + +Agent Skill 是包含 `SKILL.md`(以及可选引用文件)的文件夹。将 `agenteye-cli` skill 的文件夹放到 Agent 的 skill 查找路径中即可完成安装: + +- **Claude Code** —— 将 `agenteye-cli/` 文件夹复制到 `~/.claude/skills/`(对所有项目生效)或 `/.claude/skills/`(仅对该仓库生效)。Claude Code 会自动发现它;可通过 `/skills` 列表确认,或直接提问匹配其描述的问题。 +- **Codex(OpenAI)** —— Codex 读取同一个 `SKILL.md`。随附的 `agents/openai.yaml` 设置了 `allow_implicit_invocation: true`,因此当任务匹配时 Codex 会自动选用该 skill;也可以通过 `$agenteye-cli` 显式调用。 + +该 skill 与 `agenteye` CLI 一同维护,作为 AgentEye 软件包的一部分进行分发——如果你没有 `agenteye-cli` 文件夹,请联系你的 AgentEye 对接人。它没有任何访问门槛:不需要 Docker 镜像,也不需要额外凭证,因为它只是驱动**公开的** `agenteye` CLI 访问你自己的控制台。 + +--- + +## 安全提示——Agent 运行 CLI 时,变更操作不会触发确认提示 + +**在允许 Agent 执行变更之前,请务必阅读本节。** + +`agenteye` CLI 在执行破坏性操作前通常会询问*"确定要继续吗?"*。但**当 CLI 未连接到终端时,该确认会被自动跳过——而编程助手运行 CLI 正是这种情况,`--json` 参数同样会跳过确认。** 因此,安全提示**不会**对 Agent 生效。 + +该 skill 在设计上做了补偿:它被指示在执行任何状态变更之前,先明确告知将要运行的确切命令,并获得你的明确**确认**。请保持这一习惯——当你通过 Agent 操作 AgentEye 时,*你*就是那道确认关卡。需要重点关注的变更命令包括: + +- `keys create` / `update` / `disable` / `regenerate` +- `users create` / `update` / `disable` / `enable` +- `settings set` +- `alerts create` / `update` / `delete` / `test` +- 写入类 `incidents` 子命令:`ack` / `assign` / `resolve` / `open` / `comment-add` / `comment-delete` / `subscribe` / `unsubscribe` +- `query create` / `update` / `delete` +- `agent rename` / `delete` +- `orgs switch` + +**观察类**命令(`events`、`sessions`、`evals`、`errors`、`list`、`whoami`、`orgs list/current/perms`)均为只读操作,不会产生任何变更。 + +由于 Agent 以**你的身份**行事,它只能执行你的登录权限所允许的操作——权限按**组织**维度解析(参见 [api-keys.md](/zh/agenteye/api-keys))。如果某条命令超出你的权限,会返回退出码 `5` 并明确指出所需权限名称,让 Agent 能够准确告诉你需要向管理员申请什么,而不是模糊地报错。 + +--- + +## 你可以提问的内容 + +该 skill 将自然语言意图映射到正确的 `agenteye` 命令,并会先通过 `list `、`whoami` 发现有效值,而不是凭空猜测: + +- *"最近 24 小时有什么异常或故障吗?"* → `errors --since 24h --aggregate`,然后分类汇总。 +- *"为什么会话 `run-001` 失败了?"* → `events --session-id run-001 --all` + `evals --session-id run-001`。 +- *"本周质量趋势如何?"* → `evals --aggregate --since 7d`,然后深入分析低分运行记录。 +- *"给 CI 创建一个只能推送事件的密钥。"* → `keys create ci --add events:add`(告知命令后创建并捕获一次性密钥)。 +- *"谁有访问权限?把 Dana 改为只读。"* → `users list` → `users update dana@… --permission-set read-only`(经你确认后执行)。 +- *"确认正在触发的告警并分配给我。"* → `incidents list --state firing` → `incidents ack ` / `incidents assign you@…`。 + +这些操作背后的具体命令、参数和 JSON 格式,请参阅 [cli.md](/zh/agenteye/cli) 和 [cli-recipes.md](/zh/agenteye/cli-recipes)。 + +--- + +## 另请参阅 + +- **[CLI](/zh/agenteye/cli)** —— `agenteye` 的完整命令与参数参考。 +- **[面向 Agent 的 CLI 使用示例](/zh/agenteye/cli-recipes)** —— 可直接复制的 `jq` 模式与退出码处理方案。 +- **[AI 助手](/zh/agenteye/assistant)** —— 控制台内置助手(请勿与本终端 skill 混淆)。 +- **[API 密钥](/zh/agenteye/api-keys)** —— 限制 skill 操作范围的按组织权限模型。 \ No newline at end of file diff --git a/docs/zh/agenteye/cli.mdx b/docs/zh/agenteye/cli.mdx new file mode 100644 index 00000000..b4606b63 --- /dev/null +++ b/docs/zh/agenteye/cli.mdx @@ -0,0 +1,292 @@ +--- +title: "CLI" +description: "AgentEye CLI 文档。" +--- + + +AgentEye CLI(`agenteye`)是用于访问 AgentEye 部署的终端客户端。它可查询数据(会话、事件日志、评估)并管理组织(API 密钥、用户、设置、告警、事件、已保存的查询)——凡是仪表板能做的事,均可通过脚本或编码智能体完成。所有命令均支持 `--json` 标志,对于在提示符下操作的人类用户或调用 shell 并解析结果的编码智能体(Claude Code、Cursor)来说同样适用。 + +> 这是 **`agenteye` CLI**,与 **采集器**守护进程(`agenteye-collector`)是两个不同的工具。CLI 与您的**仪表板**通信;采集器负责将事件发送到服务器。采集器相关内容请参阅 [采集器安装](/zh/agenteye/collector-installation)。 + +--- + +## 安装 + +CLI 以 **`agenteye`** 为包名发布到公共 PyPI。由于 AgentEye Python SDK 同样使用 `agenteye` 发行版名称,请在**隔离**环境中安装 CLI(使用 `pipx` 或 `uv tool`),避免两者在同一虚拟环境中产生冲突: + +```bash +pipx install agenteye +# 或 +uv tool install agenteye +``` + +如果您未将 Python SDK 安装到同一环境中,直接使用 `pip install agenteye` 也可以。CLI 需要 Python 3.10+,无需 GitHub token,是一个公开包。 + +安装后的命令为 **`agenteye`**: + +```bash +agenteye --version +agenteye --help +``` + +--- + +## 身份验证 + +CLI 通过邮件发送一次性验证码的方式向**仪表板**进行身份验证: + +```bash +agenteye login --email you@example.com +# 系统会向您的邮箱发送一个 6 位验证码,请在提示符处粘贴输入。 +``` + +会话令牌存储在 `~/.agenteye/cli.json` 中(仅当前用户可读,权限为 `0600`),默认有效期为 24 小时。过期后,请重新运行 `agenteye login`。 + +```bash +agenteye whoami # 显示当前用户、活跃组织及权限 +agenteye logout # 撤销会话并清除已存储的令牌 +``` + +`whoami` 在会话缺失或过期时不会报错——它会返回 `logged_in: false`,因此脚本或智能体可以安全地探测认证状态(若未设置基础 URL 或仪表板不可达,仍可能以非零状态退出)。 + +**前提条件:** 您的邮箱必须被允许登录仪表板(请联系您的 AgentEye 管理员),且仪表板在其基础 URL 处可达(参见 [配置](#configuration))。若您请求了验证码但未收到,您的邮箱可能尚未开通仪表板访问权限。 + +--- + +## 选择组织(多租户) + +如果您的账户属于多个组织,请在**登录时**选择活跃组织——该选择会被保存并应用于后续所有命令: + +```bash +agenteye login --org acme # 一步完成身份验证并设置活跃租户 +agenteye orgs list # 列出您可访问的组织(活跃组织会被标记) +agenteye orgs switch globex # 更改已保存的默认组织 +agenteye --org globex sessions # 仅对单条命令使用指定组织 +``` + +如果您只属于一个组织,系统会自动选择该组织,无需关注 `--org`。如果您属于多个组织且未指定,CLI 会列出所有组织并要求您使用 `--org ` 重新运行。活跃组织会随每次请求发送到仪表板,您的权限也是**按组织**解析的——`agenteye whoami` 会显示活跃组织、您在其中的权限以及所有成员关系。 + +--- + +## 配置 + +| 设置项 | 标志 | 环境变量 | 默认值 | +|---|---|---|---| +| 仪表板基础 URL | `--base-url` | `AGENTEYE_DASHBOARD_URL` | **必填**(无默认值)| +| 活跃组织/租户 | `--org` | `AGENTEYE_ORG` | 登录时选择;保存在 `~/.agenteye/cli.json` 中 | +| 会话令牌 | `--token` | `AGENTEYE_CLI_TOKEN` | 来自 `~/.agenteye/cli.json` | +| JSON 输出 | `--json` | `AGENTEYE_CLI_JSON` | 关闭 | +| 跳过 TLS 验证 | `--insecure` / `--secure` | `AGENTEYE_INSECURE` | 关闭(登录时保存)| +| 请求超时(秒) | `--timeout` | — | 30 | +| 禁用使用遥测 | _(无)_ | `AGENTEYE_ANALYTICS_DISABLED`(或 `DO_NOT_TRACK`)| 关闭(遥测开启)| + +解析优先级为:**标志 → 环境变量 → 配置文件**。没有默认值;您必须将 CLI 指向您的仪表板,可以每次命令时指定(`--base-url https://agenteye.example.com`),也可以通过环境变量一次性设置(首次 `login` 后也会自动保存): + +```bash +export AGENTEYE_DASHBOARD_URL=https://agenteye.example.com +``` + +配置目录遵循 `AGENTEYE_HOME` 约定(与 SDK 和采集器相同);若已设置,`cli.json` 位于 `$AGENTEYE_HOME/cli.json`。 + +### 自签名或内部 TLS + +如果您的仪表板使用自签名或内部证书(例如裸负载均衡器主机名)提供 HTTPS 服务,TLS 验证会因 `CERTIFICATE_VERIFY_FAILED` 错误而拒绝连接。请使用 `--insecure` 跳过证书验证: + +```bash +agenteye --base-url https://agenteye.internal --insecure login +``` + +**`--insecure` 在登录时会被保存到 `cli.json`**,后续命令会自动跳过验证,无需重复指定该标志。若需单次验证调用,或在下次登录时恢复验证,请使用 `--secure`。CLI 在任何联系仪表板的命令执行前,若验证已禁用,会向 stderr 输出警告。跳过验证会移除对中间人攻击的防护;请确保在依赖此功能前,您信任到仪表板的网络路径(VPN、私有子网等)。 + +--- + +## 遥测与隐私 + +CLI 会向 Exosphere 的分析服务(PostHog)发送**匿名使用分析数据**:包括执行了哪些命令(如 `sessions`、`keys create`)、是否成功以及耗时。这些使用信号用于指导功能优先级的决策。 + +- **任何智能体、会话或事件数据均不会离开您的基础设施。** 仅上报 CLI 使用情况:命令和子命令名称(如 `keys create`)、您使用的标志**名称**(从不包含标志值)、成功/退出状态和耗时——以及变更操作的单次事件(如 `api_key_created`、`query_run`),仅包含静态名称/枚举和粗略计数。您的仪表板 URL、会话令牌、邮箱、组织 slug、资源 ID、SQL、密钥机密和查询过滤器**绝不会**被发送。操作者仅通过不透明的内部 ID 标识,从不使用邮箱。 +- 遥测**默认启用**。如需关闭,请在 CLI 环境中设置 `AGENTEYE_ANALYTICS_DISABLED=1`(CLI 同样支持跨工具的 `DO_NOT_TRACK=1` 约定)。 +- CLI 直接向 PostHog(`https://us.i.posthog.com`)发送数据。**运行 CLI 的机器**需要对该主机的出站访问;若被阻止,遥测会静默失败(发送有时间限制,不会延迟或中断命令),CLI 正常运行不受影响。 + +--- + +## 全局选项与约定 + +请通读一遍,适用于所有命令。 + +- **全局选项必须放在命令之前。** `agenteye --json sessions` 正确;`agenteye sessions --json` 是用法错误。全局选项包括 `--json`、`--base-url`、`--org`、`--token`、`--insecure`/`--secure`、`--timeout`、`--quiet` 和 `--no-color`。 +- **`--json` 将纯 JSON 输出到 stdout,不输出其他内容。** 人类可读的状态行、警告和错误均输出到 **stderr**,因此即使显示了状态行,`--json` 的 stdout 捕获仍保持干净,可直接管道传给 `jq`。不加 `--json` 时,输出带边框的彩色视图,适合人类阅读。 +- **使用 `--help` 进行探索。** 每个命令和子命令都有 `--help`(以及 `-h` 别名):`agenteye -h`、`agenteye sessions -h`、`agenteye keys create -h`。顶层帮助还列出了退出码和全局选项。没有全局机器可读的接口清单;请使用各命令的 `--help`,以及针对这两个注册表的 `agenteye query schema` 和 `agenteye settings schema`。 +- **确认提示在脚本和智能体中自动跳过。** 创建/更新/删除命令在交互式终端中会提示"是否确认?",但**在 `--json` 模式下或 stdin 不是 TTY 时会自动跳过该提示**——脚本和智能体不会被挂起。可使用 `--yes`/`-y` 显式跳过。由于智能体不会触发确认提示,智能体应在执行破坏性操作前先向人类确认。 +- **分页:** 结果按最新优先排序,使用游标分页。`--limit N`(别名 `-n`)限制行数,**默认为 50**;`--all` 自动分页(每次 200 行)**直到 `--limit` 上限**——因此单独使用 `--all` 仍会在 50 条时停止。如需完整扫描,请指定较高的显式上限:`--all --limit 1000`。`--page-size N` 控制每次请求的分块大小(最大 200);`--cursor ` 从上一页的 `next_cursor` 处恢复。 +- **时间过滤:** `--since` 接受相对时间窗口——`15m`、`1h`、`6h`、`24h`、`7d`、`30d` 或 `all`(仪表板预设值)。`--from`/`--to` 接受显式的 ISO-8601 UTC 时间戳,**需包含 `T` 和时区**(如 `2026-06-01T00:00:00Z`),用于自定义范围并覆盖 `--since`;以空格分隔或不含时区的值为用法错误。 +- **`--fields a,b,c`**(适用于 `events`、`sessions`、`evals`、`errors`)将输出限制为指定字段,对表格视图和 `--json` 均有效。未知字段名会被拒绝并返回有效字段列表——是探索字段名的便捷方式。 +- **`--file payload.json`**(或 `--file -` 读取 stdin)在资源结构复杂时提供完整的 JSON 请求体——用于 `alerts create/update`、`settings set` 和 `users create/update`。已保存的查询 SQL 使用 `--sql @file.sql` 代替。 +- **多值过滤器**使用逗号分隔→作为集合匹配(同一过滤器内取并集,跨过滤器取交集):`--event-type tool_use,tool_result`。Click 选项不支持可变参数,因此 `--add a b` 会出错——请使用 `--add a,b`、重复标志(`--add a --add b`)或加引号(`--add "a b"`)。 + +--- + +## 命令参考 + +CLI 共有 **18 个顶层命令**。所有读取命令均支持 `--json` 和上述全局选项;运行 `agenteye -h`(或 ` -h`)查看任意命令的完整标志列表和 JSON 结构。 + +### 身份验证 — `login` · `logout` · `whoami` · `orgs` · `version` · `help` + +```bash +agenteye login --email you@example.com [--org acme] # 邮件一次性验证码;保存会话 +agenteye logout # 清除本机上已保存的会话 +agenteye whoami # 当前用户、活跃组织、权限 +agenteye version # 输出 CLI 版本(与 --version 相同) +agenteye help # 顶层帮助(与 --help 相同) +``` + +`orgs` 用于查看和切换活跃租户: + +```bash +agenteye orgs list # 您的组织 + 您在各组织的角色(活跃组织已标记) +agenteye orgs switch acme # 更改已保存的活跃组织(在 TTY 上省略 slug 可从列表中选择) +agenteye orgs current # 活跃组织的身份信息 +agenteye orgs perms # 您在活跃组织中的权限,按资源分组 +``` + +### 观察(只读)— `events` · `sessions` · `evals` · `errors` · `list` + +以上命令均无需确认。共享过滤器:`--session-id`、`--agent-id`、`--env`(**不是** `--environment`)以及时间范围(`--since` / `--from` / `--to`)。 + +```bash +# events(别名:原始逐步轨迹)——最新优先 +agenteye --json events --session-id run-001 --event-type tool_use,tool_result --all --limit 1000 +agenteye --json events --since 1h --search timeout --all | jq '.events[].payload' + +# sessions——每次智能体运行对应一行(时间/环境/智能体/会话/状态;无评分过滤) +agenteye --json sessions --since 24h --status error +agenteye --json sessions --agent-id checkout-bot --env prod --all --limit 1000 + +# evals——评估结果 + 评分;--score 按指标过滤,--aggregate 汇总统计 +agenteye --json evals --score helpfulness:0.5..0.8 --score tool_efficiency:..0.3 +agenteye --json evals --aggregate --since 7d --env prod # 状态分布 + 各评分键统计 + +# errors——出错事件;--aggregate 统计数量/会话/智能体/最后出现时间 +agenteye --json errors --since 24h --aggregate +agenteye --json errors --since 24h --error-type timeout --all --limit 1000 + +# list——在过滤前探索有效的过滤器值 +agenteye list envs # 还支持:agents event_types score_filters models hooks triggers tools error_types +``` + +`--score KEY:MIN..MAX`(仅适用于 **`evals`**,不适用于 `sessions`)可重复使用,多个条件取 AND;任一边界均可省略(`..0.5` 表示 ≤ 0.5,`0.9..` 表示 ≥ 0.9)。每次请求最多 20 个评分过滤器。`evals --scores-full` 返回完整的评分对象而非摘要。如需**端到端读取单个会话**,可将事件轨迹与评估结果结合使用: + +```bash +agenteye --json events --session-id run-001 --all --limit 1000 | jq '.events[] | {ts, event_type}' +agenteye --json evals --session-id run-001 # 该会话的评分 + 状态 +``` + +### 管理(权限受限)— `keys` · `users` · `settings` · `alerts` · `incidents` + +**`keys`** — API 密钥。密钥机密在本地生成后发送到服务器(服务器仅存储哈希值),并在创建/重新生成时**仅显示一次**——请及时保存。使用 `--json` 时,机密仅出现在 `key` 字段中。通过**名称**引用。 + +```bash +agenteye keys list # 活跃密钥优先,然后是已撤销的密钥 +agenteye keys show ci-bot +agenteye keys create ci-bot --add events:read.add # 按需限定权限范围;仅打印一次机密 +agenteye keys create ops --permission-set standard --remove queries:run # 以预设为基础,再裁剪 +agenteye keys update ci-bot --add evaluations:read --yes +agenteye keys regenerate ci-bot --yes # 轮换机密(旧机密立即失效) +agenteye keys disable ci-bot --yes # 撤销 +``` + +权限计算方式为 `(permission-set ∪ --add) − --remove`。令牌格式为 `slug:action`(如 `events:read`)或 `slug:action.action`(在一个资源上展开多个动作,如 `events:read.add` → `events:read`、`events:add`)。预设:`read-only`、`standard`、`admin`。仅限人类使用的权限(如 `keys:update`)不能授予密钥。 + +**`users`** — 组织成员,通过**邮箱**引用(也接受 UUID 形式的 ID)。 + +```bash +agenteye users list [--active-only] +agenteye users show dev@corp.com +agenteye users create dev@corp.com --permission-set standard +agenteye users update dev@corp.com --add alerts:write --remove queries:delete # 预览变更 + 确认 +agenteye users disable dev@corp.com --yes # 有受保护账户/自身账户防护 +agenteye users enable dev@corp.com +``` + +**`settings`** — 固定注册表(您可以读取和修改现有键;不能创建新键)。 + +```bash +agenteye settings list # 键 · 值 · 类型 · 更新时间(机密已脱敏) +agenteye settings schema # 每个键的接受规范(类型 · 范围 · 描述) +agenteye settings set session_ttl_secs --value 86400 --yes +``` + +**`alerts`** — 告警定义,通过**名称**引用。`create` 接受一个位置参数 NAME,加上标志或通过 `--file` 提供的完整 JSON 请求体。 + +```bash +agenteye alerts list +agenteye alerts show high-errors +agenteye alerts create high-errors --file alert.json # NAME 为必填项(位置参数) +agenteye alerts update high-errors --severity critical --yes +agenteye alerts test high-errors --yes # 触发一次测试通知 +agenteye alerts delete high-errors --yes +``` + +**`incidents`** — 告警事件,通过 ID 引用(支持短 ID)。`show` 会打印完整的活动日志——操作前请先阅读。 + +```bash +agenteye incidents list --state firing # 还支持:acknowledged、resolved +agenteye incidents count +agenteye incidents show +agenteye incidents ack +agenteye incidents assign you@corp.com # 受托人必须是操作员 +agenteye incidents resolve --yes +agenteye incidents open --alert-id --severity critical # 针对某个告警手动创建事件 +agenteye incidents comment-add "root cause: upstream 5xx" +agenteye incidents comment-list ; agenteye incidents comment-delete +agenteye incidents subscribe ; agenteye incidents unsubscribe ; agenteye incidents subscribers +``` + +### 分析与助手 — `query` · `agent` + +**`query`** — 已保存的 ClickHouse SQL 及临时查询执行器。已保存的查询通过**名称**引用;SQL 在服务端进行验证(仅支持 SELECT/WITH,有语句超时和行数限制)。 + +```bash +agenteye query schema [TABLE] # 分析视图的列结构 +agenteye query run --sql "select count(*) from analytics.events" +agenteye query run errs --arg prod --limit 100 # 运行已保存的查询 + 位置参数 $1 +agenteye query list ; agenteye query show errs +agenteye query create errs --sql @errs.sql --description "errored events (24h)" +agenteye query update errs --sql @errs.sql --yes ; agenteye query delete errs --yes +``` + +**`agent`** — 内置仪表板助手(与仪表板中可聊天的只读分析师相同)。聊天通过短 chat-id(支持前缀解析)引用。 + +```bash +agenteye agent health # 助手是否已配置/可达 +agenteye agent models # 可传递给 --model 的模型(默认已标记) +agenteye agent ask "which agents errored most in the last day?" # 开始对话;输出短 chat-id +agenteye agent ask --chat "and which tools did they call?" # 继续该对话 +agenteye agent chats ; agenteye agent show +agenteye agent rename --title "error triage" ; agenteye agent delete +``` + +--- + +## 退出码 + +| 退出码 | 含义 | +|---|---| +| 0 | 成功 | +| 1 | 意外错误(如仪表板返回 5xx)| +| 2 | 用法错误(无效参数、未知命令/标志、名称冲突)| +| 3 | 无法连接仪表板 | +| 4 | 未登录或会话已过期;请运行 `agenteye login` | +| 5 | 已认证,但账户缺少所需权限(错误消息会指明具体权限)| +| 6 | 请求的资源未找到(如未知的会话或事件 ID)| + +这些退出码使 CLI 可安全地用于脚本:编码智能体可以根据 `4` 提示用户重新认证,或根据 `5` 显示缺少的权限。退出码处理模式和 JSON 输出结构请参阅 [智能体 CLI 使用示例](/zh/agenteye/cli-recipes)。 + +--- + +## 另请参阅 + +- **[智能体 CLI 使用示例](/zh/agenteye/cli-recipes)** — 为驱动 CLI 的编码智能体准备的即用查询模式、`jq` 单行命令、`--fields` 投影、退出码处理及 JSON 输出结构。 +- **[AgentEye CLI skill](/zh/agenteye/cli-skill)** — 将此 CLI 打包为可安装的 Claude Code / Codex *skill*,让编码智能体通过自然语言请求驱动 AgentEye。 +- **[API 密钥](/zh/agenteye/api-keys)** — `keys create --add …` 背后的权限模型。 +- **[AI 助手](/zh/agenteye/assistant)** — 启用 `agent ask` 所使用的助手。 \ No newline at end of file diff --git a/docs/zh/agenteye/collector-installation.mdx b/docs/zh/agenteye/collector-installation.mdx new file mode 100644 index 00000000..048d79e5 --- /dev/null +++ b/docs/zh/agenteye/collector-installation.mdx @@ -0,0 +1,401 @@ +--- +title: "Collector 安装" +description: "AgentEye Collector 安装文档。" +--- + + +`agenteye-collector` 守护进程确保您的 Agent 遥测数据能够安全送达 AgentEye,且绝不会阻塞您的应用程序。您的代码将事件写入本地目录后即可继续运行;collector 接管后续工作,在毫秒级内完成每个文件的上传,并能在重启、网络中断和临时服务器错误后自动恢复。上传失败会以指数退避策略进行重试,定期的恢复扫描会将因崩溃或部署遗留的文件重新加入队列。最终实现持久可靠的"即发即忘"投递:您的 Agent 保持全速运行,同时 collector 确保没有任何事件在传输过程中丢失。 + +从机制上看,collector 是一个轻量级守护进程,它监听 `$AGENTEYE_HOME/events/`(默认:`~/.agenteye/events/`)目录中由 Python SDK 写入的 `.jsonl` 文件,并将其上传至 AgentEye 服务器。 + +> **名称变更:** collector 命令现已更名为 **`agenteye-collector`**(原名为 `agenteye`)。短名称 `agenteye` 现属于 AgentEye CLI。如果您正在升级现有安装,请参阅 [enterprise-docs/collector-migration.md](/zh/agenteye/collector-migration)。 + +--- + +## 前置条件 + +- 您的 `AGENTEYE_TOKEN`:自行生成的 GitHub PAT(参见 [enterprise-docs/github-token.md](/zh/agenteye/github-token)) +- 服务器 URL 和 collector API 密钥(参见 [enterprise-docs/api-keys.md](/zh/agenteye/api-keys)) + +--- + +## 方案 A:二进制文件(推荐) + +预编译的静态二进制文件适用于 Linux、macOS 和 Windows(x86_64 和 arm64)。请从 `agenteye-enterprise/releases` 仓库的最新 `collector/v` 发布标签中直接下载适合您平台的二进制文件。 + +可用的制品名称: + +| 平台 | 制品 | +|---|---| +| Linux x86_64 | `agenteye-collector-linux-x86_64` | +| Linux arm64 | `agenteye-collector-linux-arm64` | +| macOS x86_64 | `agenteye-collector-darwin-x86_64` | +| macOS arm64 | `agenteye-collector-darwin-arm64` | +| Windows x86_64 | `agenteye-collector-windows-x86_64.exe` | +| Windows arm64 | `agenteye-collector-windows-arm64.exe` | + +**使用 `gh` CLI 下载**(替换版本号并选择您平台对应的制品): + +```bash +VERSION=0.0.1-beta.13 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "collector/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-collector-linux-x86_64' + +chmod +x agenteye-collector-linux-x86_64 +sudo mv agenteye-collector-linux-x86_64 /usr/local/bin/agenteye-collector +``` + +**或使用 `curl`:** + +```bash +VERSION=0.0.1-beta.13 +ARTIFACT=agenteye-collector-linux-x86_64 +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + -L "https://github.com/agenteye-enterprise/releases/releases/download/collector%2Fv${VERSION}/${ARTIFACT}" \ + -o agenteye-collector +chmod +x agenteye-collector +sudo mv agenteye-collector /usr/local/bin/agenteye-collector +``` + +--- + +## 方案 B:Docker + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +docker pull ghcr.io/agenteye-enterprise/collector:beta-latest +``` + +> 当前 beta 构建发布浮动标签 `:beta-latest`;`:latest` 仅分配给稳定版本。对于可重现的部署,建议使用固定版本标签,例如 `:v0.0.1-beta.13`。 + +**运行:** + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-collector \ + -e AGENTEYE_URL=https://ingest.example.com/events \ + -e AGENTEYE_KEY="$AGENTEYE_KEY" \ + -e AGENTEYE_HOME=/data \ + -v "$HOME/.agenteye:/data" \ + ghcr.io/agenteye-enterprise/collector:beta-latest \ + start +``` + +官方镜像以非 root 用户运行,因此请显式设置 `AGENTEYE_HOME` 并将主机队列目录挂载到该路径。卷挂载与主机上 Python SDK 写入的 `~/.agenteye/` 目录共享。如果您在主机上已将 `AGENTEYE_HOME` 设置为其他位置,请挂载该目录而非 `$HOME/.agenteye`。 + +--- + +## 配置 + +所有选项均可通过以下三种方式设置(优先级从高到低): + +1. CLI 标志:`agenteye-collector start --url https://...` +2. 环境变量:`AGENTEYE_URL=https://...` +3. 配置文件:`~/.agenteye/config.json` + +### 必填选项 + +| 选项 | CLI 标志 | 环境变量 | config.json 键 | +|---|---|---|---| +| 后端 URL | `--url ` | `AGENTEYE_URL` | `"url"` | +| API 密钥 | `--key ` | `AGENTEYE_KEY` | `"key"` | + +### 可选选项(含默认值) + +| 选项 | CLI 标志 | 环境变量 | config.json 键 | 默认值 | +|---|---|---|---|---| +| 最大并发上传数 | `--max-concurrent-uploads ` | `AGENTEYE_MAX_CONCURRENT_UPLOADS` | `"max_concurrent_uploads"` | `64` | +| 扫描间隔(秒) | `--sweep-interval ` | `AGENTEYE_SWEEP_INTERVAL` | `"sweep_interval_secs"` | `60` | +| 扫描最小文件年龄(秒) | `--sweep-min-age ` | `AGENTEYE_SWEEP_MIN_AGE` | `"sweep_min_age_secs"` | `120` | +| 每次扫描最大文件数 | `--sweep-max-files ` | `AGENTEYE_SWEEP_MAX_FILES` | `"sweep_max_files"` | `64` | +| 最大上传尝试次数 | `--max-retries ` | `AGENTEYE_MAX_RETRIES` | `"max_retries"` | `5` | +| 重试基础延迟(毫秒) | `--retry-base-delay ` | `AGENTEYE_RETRY_BASE_DELAY` | `"retry_base_delay_ms"` | `1000` | + +### mTLS 选项(可选) + +对于需要双向 TLS(mTLS)的部署,collector 可在 TLS 握手期间出示客户端证书。若未设置这些选项,collector 将使用标准 HTTPS。 + +| 选项 | CLI 标志 | 环境变量 | config.json 键 | +|---|---|---|---| +| 客户端证书(PEM) | `--tls-cert ` | `AGENTEYE_TLS_CERT` | `"tls_cert"` | +| 客户端私钥(PEM) | `--tls-key ` | `AGENTEYE_TLS_KEY` | `"tls_key"` | +| 自定义 CA 证书(PEM) | `--tls-ca ` | `AGENTEYE_TLS_CA` | `"tls_ca"` | + +`--tls-cert` 和 `--tls-key` 必须同时设置,且文件必须为 PEM 编码格式。 + +`--tls-ca` 为独立选项,仅在 AgentEye 服务器使用非公开信任 CA 颁发的 TLS 证书时才需要(例如,在没有真实 DNS 域名的情况下,由集群内 `cert-manager` 颁发机构签发的自签名证书)。collector 会将所提供的 CA 作为额外的信任锚点添加;标准公共根证书仍然受信,因此现有部署不受影响。该文件可包含单个 PEM 证书或完整证书链(多个连续的 PEM 块)。 + +**是否在应用程序 Pod 中以 sidecar 方式运行 collector?** 请参阅 [enterprise-docs/single-pod-deployment.md](/zh/agenteye/single-pod-deployment) 了解完整的 EKS 方案:通过 AWS Secrets Manager + Secrets Store CSI Driver + IRSA 交付 mTLS 证书包,并支持自动轮换。 + +在 Kubernetes 中使用 Secret 交接模式运行时,将证书 Secret 挂载为卷,并将这些路径指向挂载的文件: + +```yaml +# 示例:collector Deployment 片段 +volumes: + - name: mtls-certs + secret: + secretName: agenteye-collector-mtls +containers: + - name: collector + env: + - name: AGENTEYE_TLS_CERT + value: /etc/agenteye/tls/tls.crt + - name: AGENTEYE_TLS_KEY + value: /etc/agenteye/tls/tls.key + # 仅当服务器证书不受公开信任时需要(例如集群内 + # 自签名 CA)。该 Secret 通常在 tls.crt/tls.key + # 旁边同时包含 ca.crt。 + - name: AGENTEYE_TLS_CA + value: /etc/agenteye/tls/ca.crt + volumeMounts: + - name: mtls-certs + mountPath: /etc/agenteye/tls + readOnly: true +``` + +### `~/.agenteye/config.json` 示例 + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "max_concurrent_uploads": 16, + "sweep_interval_secs": 30 +} +``` + +启用 mTLS: + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "tls_cert": "/etc/agenteye/tls/tls.crt", + "tls_key": "/etc/agenteye/tls/tls.key" +} +``` + +启用 mTLS 并使用自定义 CA(AgentEye 服务器使用自签名证书): + +```json +{ + "url": "https://ingest.example.com/events", + "key": "sk-...", + "tls_cert": "/etc/agenteye/tls/tls.crt", + "tls_key": "/etc/agenteye/tls/tls.key", + "tls_ca": "/etc/agenteye/tls/ca.crt" +} +``` + +如果设置了 `AGENTEYE_HOME`,则使用该目录替代 `~/.agenteye`。 + +--- + +## 初次设置 + +安装完成后,使用服务器 URL 和 API 密钥配置 collector: + +```bash +mkdir -p ~/.agenteye +cat > ~/.agenteye/config.json <<'EOF' +{ + "url": "https://ingest.example.com/events", + "key": "YOUR_COLLECTOR_KEY" +} +EOF +``` + +> 对于任何跨越不受信网络的部署,请使用 `https`,以避免事件以明文形式传输。明文形式 `http://your-server-host:8080/events` 仅适用于针对同一主机上服务器的纯本地测试。 + +**测试连接**(单次刷新,排空待发事件后退出): + +```bash +agenteye-collector flush +``` + +`flush` 将进度输出到 stdout。当队列为空时,打印 `No pending files.` 并以退出码 `0` 退出。否则,每个文件打印一行(`[UPLOADED] ` 或 `[FAILED] ()`),最后输出 `Done: / uploaded, failed.` 汇总信息。这使 `flush` 成为启动守护进程前验证 URL、密钥和 TLS 配置是否正确的便捷单次检查工具。 + +--- + +## 作为守护进程运行 + +### 直接运行 + +```bash +agenteye-collector start +``` + +### 容器 / Docker + +当 collector 与您的应用程序共用一个容器时,请使用进程管理器来运行它们。最简单的选择是 `supervisord`;它在各主流发行版中均有提供,能重启崩溃的进程、转发信号,并等待优雅关闭。 + +**`Dockerfile`:** + +```Dockerfile +FROM python:3.11-slim + +RUN apt-get update && apt-get install -y --no-install-recommends supervisor \ + && rm -rf /var/lib/apt/lists/* + +# 从官方镜像中拉取 agenteye-collector 二进制文件。 +# 固定特定标签(当前 beta 使用 :beta-latest,或使用 :v 标签); +# :latest 仅在稳定版本发布时使用。 +COPY --from=ghcr.io/agenteye-enterprise/collector:beta-latest \ + /usr/local/bin/agenteye-collector /usr/local/bin/agenteye-collector + +COPY supervisord.conf /etc/supervisor/conf.d/agenteye.conf +COPY my_agent.py /app/my_agent.py + +CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"] +``` + +**`supervisord.conf`:** + +```ini +[supervisord] +nodaemon=true +user=root + +[program:agenteye-collector] +command=/usr/local/bin/agenteye-collector start +autorestart=true +stopwaitsecs=30 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:app] +command=python /app/my_agent.py +autorestart=unexpected +stopwaitsecs=30 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +``` + +各配置项说明: + +- agenteye-collector 的 `autorestart=true`:任何退出(崩溃、panic、OOM)均自动重启。 +- 应用程序的 `autorestart=unexpected`:仅在非零退出时重启,避免以退出码 0 结束的单次 Agent 陷入循环。 +- `stopwaitsecs=30`:在 supervisord 升级为 SIGKILL 之前,为 collector 在收到 SIGTERM 后排空待发上传留出空间。 +- `stdout_logfile=/dev/stdout`,`*_maxbytes=0`:将两个程序的输出流式传输到容器 stdout,容器内不产生日志文件。 + +如前所述,在 `docker run -e` 中传递 `AGENTEYE_URL` / `AGENTEYE_KEY`(及任何 TLS 环境变量);supervisord 会继承这些环境变量。 + +> **使用独立容器?** 如果您将 collector 作为独立容器运行(Docker Compose 服务、Kubernetes sidecar 等),无需使用 supervisord;容器运行时的重启策略已承担此职责。EKS sidecar 方案请参阅 [enterprise-docs/single-pod-deployment.md](/zh/agenteye/single-pod-deployment)。 + +**Kubernetes 存活探针**(无论 collector 是独立运行还是在 supervisord 下运行均适用): + +```yaml +livenessProbe: + exec: + command: ["agenteye-collector", "health"] + initialDelaySeconds: 10 + periodSeconds: 30 +``` + +运行中的守护进程每 30 秒向 `$AGENTEYE_HOME/health.json` 写入一次心跳。`agenteye-collector health` 读取该文件,仅在心跳新鲜且上传任务正常运行时以退出码 `0`(健康)退出;当心跳超过 90 秒未更新(例如守护进程已停止)或监视器和扫描器在意外退出后正在重启时,以退出码 `1`(不健康)退出。心跳仅由 `start` 写入,因此请针对长期运行的守护进程而非单次 `flush` 命令配置探针。 + +### systemd(Linux,生产环境推荐) + +```ini +# /etc/systemd/system/agenteye-collector.service +[Unit] +Description=AgentEye Collector +After=network.target + +[Service] +ExecStart=/usr/local/bin/agenteye-collector start +Restart=on-failure +RestartSec=5 +EnvironmentFile=/etc/agenteye/env + +[Install] +WantedBy=multi-user.target +``` + +创建 `/etc/agenteye/env`: + +``` +AGENTEYE_URL=https://ingest.example.com/events +AGENTEYE_KEY=YOUR_COLLECTOR_KEY +``` + +```bash +sudo systemctl daemon-reload +sudo systemctl enable --now agenteye-collector +sudo systemctl status agenteye-collector +``` + +### launchd(macOS) + +```xml + + + + + + Label + ai.befailproof.agenteye-collector + ProgramArguments + + /usr/local/bin/agenteye-collector + start + + EnvironmentVariables + + AGENTEYE_URL + https://ingest.example.com/events + AGENTEYE_KEY + YOUR_COLLECTOR_KEY + + RunAtLoad + + KeepAlive + + + +``` + +```bash +launchctl load ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +``` + +--- + +## 升级 Collector + +Collector 不会自动更新。升级步骤如下: + +- **二进制文件:** 从最新的 `collector/v` 发布版本下载新的 `agenteye-collector--` 制品(参见[方案 A](#option-a-binary-recommended)),替换 `/usr/local/bin/agenteye-collector`,然后重启服务(`sudo systemctl restart agenteye-collector`、重新 `launchctl load`,或重启您的进程管理器)。 +- **Docker:** 执行 `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest`(或固定的 `:v` 标签;`:latest` 仅存在于稳定版本),然后重新创建容器。 + +下载私有发布仓库中的新二进制文件/镜像需要 `AGENTEYE_TOKEN`,但运行中的守护进程**不需要**该令牌。 + +--- + +## 子命令 + +| 命令 | 描述 | +|---|---| +| `agenteye-collector start` | 启动长期运行的守护进程。启动时会刷新上次运行遗留的所有事件,然后监视新文件并上传。监视器和扫描器在意外退出后自动重启,心跳每 30 秒写入 `health.json`。 | +| `agenteye-collector flush` | 单次执行:上传所有待处理文件后退出。队列为空时打印 `No pending files.`,否则输出每个文件的 `[UPLOADED]`/`[FAILED]` 日志及 `Done: / uploaded, failed.` 汇总信息。 | +| `agenteye-collector health` | 读取守护进程的 `health.json` 心跳。心跳新鲜且健康时以退出码 `0` 退出;心跳过期(超过 90 秒)或任务正在重启时以退出码 `1` 退出。 | + +--- + +## 目录结构 + +``` +~/.agenteye/ +├── config.json <- 可选配置文件 +├── events/ <- SDK 写入的 .jsonl 文件,由 collector 拾取 +└── failed/ <- 所有上传尝试均失败的文件 +``` + +`failed/` 目录中的文件不会自动重试。如需手动重新加入队列,请将其移回 `events/` 目录并运行 `agenteye-collector flush`。 \ No newline at end of file diff --git a/docs/zh/agenteye/collector-migration.mdx b/docs/zh/agenteye/collector-migration.mdx new file mode 100644 index 00000000..b8eba752 --- /dev/null +++ b/docs/zh/agenteye/collector-migration.mdx @@ -0,0 +1,170 @@ +--- +title: "迁移到 `agenteye-collector`" +description: "AgentEye 迁移到 `agenteye-collector` 的文档说明。" +--- + + +迁移过程不会破坏任何现有内容:无需停机,不会造成数据丢失,同时将短名称 `agenteye` 释放给 [AgentEye CLI](/zh/agenteye/cli) 使用,从而让采集器守护进程与 CLI 可以在同一台机器上共存。 + +采集器二进制文件已**从 `agenteye` 更名为 `agenteye-collector`**。短名称 `agenteye` 现在归属于 AgentEye CLI,这是一个独立工具,用于在终端中查询会话、事件和评估结果。 + +本指南将引导您完成现有采集器安装的迁移流程。 + +--- + +## 变更内容 + +| | 变更前 | 变更后 | +|---|---|---| +| 命令 / 二进制文件 | `agenteye` | `agenteye-collector` | +| 默认安装路径 | `/usr/local/bin/agenteye` | `/usr/local/bin/agenteye-collector` | +| 子命令 | `start`、`flush`、`health`、`update` | `start`、`flush`、`health` | +| 自动更新(`agenteye update`) | 内置 | **已移除**:请直接下载新二进制文件或拉取新镜像 | +| 安装脚本(`install.sh`) | 已提供 | **已移除**:请直接下载二进制文件(参见[采集器安装](/zh/agenteye/collector-installation)) | +| `AGENTEYE_TOKEN` | 下载**及**后台更新检查均需要 | 仅**下载**二进制文件 / 镜像时需要 | + +配置文件保持不变:相同的 `~/.agenteye/config.json`、相同的 `AGENTEYE_URL` / `AGENTEYE_KEY` / `AGENTEYE_HOME` / TLS 环境变量,以及相同的 `~/.agenteye/events/` 缓冲队列目录。**无需修改任何配置。** + +> 如果您以旧名称 `agenteye` 运行已更名的二进制文件,程序仍可正常工作,但会向 stderr 输出一行弃用警告,提示您切换到 `agenteye-collector`。 + +--- + +## 开始之前 + +- **现有的 `agenteye` 安装会继续运行**;升级操作不会立即造成任何中断。请有计划地执行迁移,最后再移除旧的二进制文件。 +- 请按以下顺序操作,以避免停机: + 1. 安装新的 `agenteye-collector` 二进制文件(或拉取新镜像)。 + 2. 更新您的服务定义 / 健康检查探针 / 脚本,使其调用 `agenteye-collector`。 + 3. 重新加载并重启服务,确认服务健康运行。 + 4. **完成上述步骤后**,再移除旧的 `/usr/local/bin/agenteye` 二进制文件。 + +--- + +## 1. 安装新的二进制文件 + +从最新的 `collector/v` 版本中下载适合您平台的文件(`agenteye-collector-linux-x86_64`、`agenteye-collector-darwin-arm64` 等;完整列表请参见[采集器安装 → 选项 A](/zh/agenteye/collector-installation#option-a-binary-recommended)),并将其放置到 `/usr/local/bin/agenteye-collector`。Docker 用户:执行 `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest`(或指定版本标签 `:v`,推荐使用固定版本;`:latest` 仅适用于稳定版本)。 + +验证安装: + +```bash +agenteye-collector --version +``` + +--- + +## 2. 更新您的部署配置 + +### systemd(Linux) + +编辑 `/etc/systemd/system/agenteye-collector.service`,将 `ExecStart` 指向新的二进制文件: + +```ini +[Service] +ExecStart=/usr/local/bin/agenteye-collector start +``` + +然后重新加载并重启: + +```bash +sudo systemctl daemon-reload +sudo systemctl restart agenteye-collector +sudo systemctl status agenteye-collector +``` + +### launchd(macOS) + +> **品牌更名提示:** 如果您现有的 plist 文件位于旧路径 +> `~/Library/LaunchAgents/host.exosphere.agenteye-collector.plist`,请将 +> 该文件重命名为 `ai.befailproof.agenteye-collector.plist`,并在重新加载前 +> 将文件内部的 `Label` 值也改为新的标识符。 + +在 `~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist` 中,将第一个 `ProgramArguments` 条目从 `/usr/local/bin/agenteye` 改为 `/usr/local/bin/agenteye-collector`,然后重新加载: + +```bash +launchctl unload ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +launchctl load ~/Library/LaunchAgents/ai.befailproof.agenteye-collector.plist +``` + +### supervisord + +在您的 `supervisord` 程序块中,将 `command` 设置为新的二进制文件: + +```ini +[program:agenteye-collector] +command=/usr/local/bin/agenteye-collector start +``` + +然后执行 `supervisorctl reread && supervisorctl update`。 + +### Docker / Kubernetes + +拉取新镜像(`ghcr.io/agenteye-enterprise/collector:beta-latest` 或固定版本标签 `:v`,推荐使用固定版本;`:latest` 仅适用于稳定版本)。镜像的入口点已经是 `agenteye-collector`,因此原有带 `start` 子命令的 `docker run` 命令无需任何修改即可继续使用。 + +**重要:请更新健康检查探针。** 如果您使用 Kubernetes 存活/就绪探针(或任何 `docker exec`)通过名称调用二进制文件,请将命令改为 `agenteye-collector`: + +```yaml +livenessProbe: + exec: + command: ["agenteye-collector", "health"] +``` + +新镜像**不**包含 `agenteye` 别名,因此仍调用 `agenteye` 的探针将会失败。请在部署新镜像的同一次发布中同步更新探针配置。 + +### Cron / 手动脚本 + +将所有 `agenteye start|flush|health` 调用替换为对应的 `agenteye-collector start|flush|health` 命令。**删除所有 `agenteye update` 的定时任务**;该子命令已不再存在(请参见[后续升级方式](#upgrades-from-now-on))。 + +--- + +## 3. 移除旧的二进制文件(最后执行) + +确认服务在 `agenteye-collector` 上正常运行且状态健康后,执行: + +```bash +sudo rm /usr/local/bin/agenteye +``` + +如果您同时使用 AgentEye CLI,此步骤尤为重要——CLI 会安装自己的 `agenteye` 命令;若旧的采集器二进制文件仍存留在 `/usr/local/bin/agenteye`,则 `agenteye` 这个名称在您的 `PATH` 中将产生歧义。 + +--- + + + +## 后续升级方式 + +采集器不再自动更新。升级方式如下: + +- **二进制文件:** 下载适合您平台的新文件(例如 `agenteye-collector-linux-x86_64`;完整列表请参见[采集器安装 → 选项 A](/zh/agenteye/collector-installation#option-a-binary-recommended)),替换 `/usr/local/bin/agenteye-collector`,然后重启服务。 +- **Docker:** 执行 `docker pull ghcr.io/agenteye-enterprise/collector:beta-latest`(或固定版本标签 `:v`,推荐使用;`:latest` 仅适用于稳定版本),然后重新创建容器。 + +`AGENTEYE_TOKEN` 仍然需要用于从私有发布仓库下载文件,但运行中的守护进程不再需要该令牌。 + +--- + +## 验证 + +```bash +agenteye-collector --version # 确认新二进制文件在 PATH 中 +agenteye-collector health # 退出码 0 表示健康 +agenteye-collector flush # 转发所有排队事件并正常退出 +``` + +然后确认新事件出现在您的仪表盘中。 + +--- + +## 回滚 + +迁移过程不会破坏任何内容。如需回滚,只需将服务定义重新指向旧的 `/usr/local/bin/agenteye` 二进制文件(前提是尚未将其删除)并重启服务即可。事件缓冲队列和配置文件为共享资源,不受影响。 + +--- + +## 故障排查 + +| 现象 | 原因 | 解决方法 | +|---|---|---| +| 每次运行时出现 `warning: the collector binary is now agenteye-collector …` | 您仍在使用旧名称 `agenteye` 调用二进制文件 | 改为调用 `agenteye-collector`;更新服务文件和脚本。 | +| systemd 报错:`.../agenteye: No such file or directory` | 在更新 `ExecStart` 之前就删除了旧的二进制文件 | 将 `ExecStart` 设置为 `/usr/local/bin/agenteye-collector start`,然后执行 `sudo systemctl daemon-reload`。 | +| 镜像升级后 Kubernetes Pod 崩溃重启循环 | 存活探针仍在运行 `agenteye` | 将探针命令改为 `["agenteye-collector", "health"]`。 | +| `agenteye: command not found`,但 `agenteye-collector` 可以正常使用 | 脚本 / 别名仍引用旧名称 | 将其更新为 `agenteye-collector`。 | +| 运行 `agenteye` 启动的是 CLI 而非采集器 | 您已安装 AgentEye CLI,它拥有 `agenteye` 命令 | 使用 `agenteye-collector` 运行守护进程,并删除 `/usr/local/bin/agenteye` 处残留的旧采集器二进制文件。 | diff --git a/docs/zh/agenteye/deployment.mdx b/docs/zh/agenteye/deployment.mdx new file mode 100644 index 00000000..3d11a537 --- /dev/null +++ b/docs/zh/agenteye/deployment.mdx @@ -0,0 +1,428 @@ +--- +title: "部署" +description: "AgentEye 部署文档。" +--- + + +本指南涵盖在生产环境中部署 AgentEye 服务端和控制台的相关内容。 + +--- + +## 架构概览 + +``` + [ AI agent 机器 ] [ 您的基础设施 ] + + Python SDK + | 写入 JSONL +----------------------+ + v +--->| PostgreSQL 15+ | + agenteye-collector --HTTP--+ | | (关系型存储) | + | | +----------------------+ + v | + +--------+ | +----------------------+ + | Server |<------+--->| ClickHouse 24+ | + +--------+ | | (事件 / 分析) | + ^ | +----------------------+ + API | | + | | +----------------------+ + +-----------+ +- - >| Redis 7+(可选) | + | Dashboard | +----------------------+ + +-----------+ +``` + +- **Server**:Rust HTTP 服务;接收事件批次,将其写入 ClickHouse,并在 PostgreSQL 中维护关系型状态。 +- **Dashboard**:Next.js Web 应用;完全通过服务端 API 进行读写操作。 +- **agenteye-collector**:部署在 agent 机器上,而非服务端主机上。 +- **Postgres 15+**:**必需**。(在多租户版本中从 14 升级而来;org-membership 模式使用了列列表 `ON DELETE SET NULL` 外键,这是 Postgres 15+ 的特性。部署此版本前请先升级 Postgres。)存储 OLTP 状态:`api_keys`、`users`、`sessions`、`evaluation_jobs`(队列)、`dashboards`、`saved_queries`、`otp_codes`,以及多租户表 `orgs`、`org_memberships`、`org_settings`。 +- **ClickHouse 24+**:**必需**。用于存储所有摄入事件的分析型存储。引擎:`ReplacingMergeTree`,按月分区,按 `(session_id, ts, dedup_key)` 排序。服务端通过 `CLICKHOUSE_URL` 连接;内置的 `deploy/base/clickhouse/` 提供了针对单节点的性能调优配置。**多租户要求:** 内置配置启用了 SQL 访问管理 + `users_without_row_policies_can_read_rows=false`,使服务端能够为每个组织创建一个只读 ClickHouse 用户 + 行策略(这是 SQL 编辑器和 AI agent 的引擎级隔离边界)。如果您使用自定义 ClickHouse 配置,请保留这些设置(参见 `deploy/base/clickhouse/configmap.yaml`)。 +- **Redis 7+**:*可选*,用作共享缓存 + 速率限制后端。服务端和控制台均通过 `REDIS_URL` 进行连接。若未配置,两者均会优雅降级至仅使用 Postgres 的路径。详见下方 **Redis(可选缓存)** 部分。 + +--- + +## 服务端 + +### 拉取镜像 + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +docker pull ghcr.io/agenteye-enterprise/server:beta-latest +``` + +> 当前构建发布于 `beta-latest` 标签下;`latest` 仅在稳定版发布时使用。生产环境中请固定使用具体的 `:v` 标签;参见[可用镜像标签](#available-image-tags)。 + +### 环境变量 + +| 变量 | 是否必需 | 默认值 | 说明 | +|---|---|---|---| +| `DATABASE_URL` | 是 | 无 | Postgres DSN。使用 `postgres://` scheme 的标准 libpq 连接字符串格式,支持 `?sslmode=require` 及其他 libpq 参数。密码不得包含 `/`、`+` 或 `=` 字符;请使用 `openssl rand -hex` 生成 URL 安全的密码。 | +| `ADMIN_KEY` | 否 | 无 | 引导管理员 API 密钥。每次启动时以全权限进行 upsert 操作。通过修改该值并重启来轮换密钥。 | +| `LISTEN_ADDR` | 否 | `0.0.0.0:8080` | 绑定的 TCP 地址 | +| `MAX_BODY_BYTES` | 否 | `134217728`(128 MB) | 请求体最大大小 | +| `ADMIN_EMAIL` | 否 | 无 | 引导管理员用户邮箱。每次启动时以全权限进行 upsert 并标记为受保护:无法通过控制台/API 禁用或修改其权限。要轮换引导管理员,修改 `ADMIN_EMAIL` 并重启;新邮箱将被 upsert 为受保护状态,旧邮箱在手动清除数据库记录之前仍保留受保护状态。 | +| `ALLOWED_EMAILS` | 否 | 无(全部阻止) | 允许创建用户和登录的邮箱列表,以逗号分隔。支持精确地址(`user@example.com`)和域名通配符(`*@example.com`)。若未设置,则无法创建或登录任何用户。**仅首次启动时生效**:首次启动时写入默认 org 的允许列表;此后每个 org 的允许列表以 [`//settings`](#operational-settings) 页面为准,修改此环境变量不再生效。 | +| `SMTP_HOST` | 否 | 无 | 用于发送 OTP 邮件的 SMTP 服务器主机名。若未设置,OTP 代码将输出到 stdout。 | +| `SMTP_PORT` | 否 | `587` | SMTP 服务器端口 | +| `SMTP_USERNAME` | 否 | 无 | SMTP 认证用户名 | +| `SMTP_PASSWORD` | 否 | 无 | SMTP 认证密码 | +| `SMTP_FROM` | 否 | 无 | OTP 邮件的发件人地址 | +| `SMTP_TLS` | 否 | STARTTLS | 除非明确关闭否则使用 STARTTLS:`false` 或 `0` 表示明文传输(无 TLS);其他任何值(包括未设置)均启用 STARTTLS。 | +| `DASHBOARD_URL` | 否 | 内置默认值 | 控制台来源地址,用于构建 OTP 邮件魔法链接和告警通知中的事件魔法链接。若未设置,将回退到内置默认值(仅 OTP 会优先使用控制台派生的请求来源)。在分域名部署时请设置此项,以确保邮件和 Slack/事件链接均指向您的控制台。详见下方 **邮件魔法链接 URL**;大多数运营人员无需设置此项。 | +| `SESSION_TTL_SECS` | 否 | `86400`(24 小时) | 控制台会话有效期(秒)。**仅首次启动时生效**:首次部署后可通过 [`//settings`](#operational-settings) 按 org 修改。 | +| `OTP_TTL_SECS` | 否 | `600`(10 分钟) | OTP 代码有效期(秒)。**仅首次启动时生效**:首次部署后可通过 [`//settings`](#operational-settings) 按 org 修改。 | +| `REDIS_URL` | 否 | 无 | 可选的共享缓存 + 速率限制后端,例如 `redis://redis:6379/0`。设置后,服务端将缓存已认证的 API 密钥查找、控制台的 `/models` 聚合数据、会话列表和环境列表分面;同时将 OTP 请求速率限制从 Postgres COUNT 切换为 Redis INCR。若未设置或不可达,服务端将在无缓存模式下运行(OTP 限制回退到 Postgres,其他缓存调用直接访问数据源)。详见下方 **Redis(可选缓存)**。 | +| `CLICKHOUSE_URL` | **是** | 无 | ClickHouse 实例的基础 URL,例如 `http://clickhouse:8123`。服务端每次启动时都会对此数据库应用事件模式,若无法连接 ClickHouse 则拒绝启动。详见下方 **ClickHouse(必需的分析存储)**。 | +| `CLICKHOUSE_DATABASE` | 否 | `agenteye` | ClickHouse 数据库(模式)名称。若不存在,服务端将在启动时创建。 | +| `ORG_CH_SECRET` | 否(单租户)/ **是(多 org)** | 开发默认值 | HMAC 密钥,用于派生每个组织的租户专属 ClickHouse 密码。SQL 编辑器和 AI agent 的 `run_query` 以 org 专属只读 ClickHouse 用户身份执行,其行策略在引擎层面强制租户隔离。单租户部署可使用内置开发默认值正常启动;**在配置第二个 org 之前,您必须设置一个强且稳定的值**,因为 `agenteye-orgctl org create` CLI 拒绝在内置开发默认值下运行。轮换该值会导致所有 org 的 ClickHouse 用户失效,直到下次启动时重新配置(启动时的对账会自动修复这一问题)。请保密此值,并在所有副本中保持一致。Org 配置本身仅限运营人员操作;详见下方 **Organizations(多租户)**。 | +| `DEFAULT_ORG_NAME` | 否 | `Default` | 内置默认 org 的显示名称。**仅首次启动时生效**,且仅在 org 仍保持其初始通用身份时于启动时应用,之后被忽略。一旦通过 `agenteye-orgctl org rename` 重命名 org,重命名结果即为权威值,此环境变量不再生效。 | +| `DEFAULT_ORG_SLUG` | 否 | `default` | 内置默认 org 的 URL slug,即其控制台路径(`//…`)。与 `DEFAULT_ORG_NAME` 相同的仅首次启动/初始状态语义。必须为 1-40 个小写字母数字字符,允许单个内部连字符,且不得为[保留字](#organizations-multi-tenancy);无效值将被忽略(org 保持 `default`)。允许单租户安装以例如 `/acme` 而非 `/default` 的形式呈现,无需任何部署后 CLI 步骤。 | +| `RUST_LOG` | 否 | `info` | 日志详细程度(`debug`、`warn`、`error`、`agenteye_server=trace`) | +| `EVALUATOR_ENDPOINT` | 否 | 无 | 评估器服务的基础 URL(例如 `http://evaluator:9000`)。若未设置,整个评估流水线为空操作;不写入任何队列行,也不运行任何工作进程。参见[评估套件](/zh/agenteye/evaluation-suite)。 | +| `EVALUATOR_TOKEN` | 否 | 无 | 以 `Authorization: Bearer ` 形式发送给评估器。**必须与评估器服务配置的值相同。** 仅当评估器配置为无 token 时才可选。 | +| `EVALUATOR_WORKERS` | 否 | `2` | 并发数:每个服务端实例中调度评估的工作任务数量。可安全地在多个水平扩展的服务端上运行。 | +| `EVALUATOR_CLAIM_BATCH` | 否 | `4` | 单个工作进程每次轮询时最多认领的评估数量。批次**并发**调度,因此您的评估器端点上的总并发数为 `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH`。 | +| `EVALUATOR_POLL_IDLE_SECS` | 否 | `2` | 无待处理任务时工作进程在两次调度尝试之间的休眠时间(秒)。 | +| `EVALUATOR_POLLING_INTERVAL_SECS` | 否 | `10` | 当评估器未返回每响应的 `next_poll_secs` 且未通过 `GET /config` 公布 `default_poll_interval_secs` 时,`GET /evaluate/{id}` 轮询的最终回退周期(秒)。 | +| `EVALUATOR_REQUEST_TIMEOUT_MS` | 否 | `30000` | 每次对评估器 HTTP 请求的超时时间(毫秒)。 | +| `EVALUATOR_MAX_ATTEMPTS` | 否 | `5` | 达到此次数的失败尝试后,评估将被记录为终止的 `error` 状态(若失败均为请求超时,则记录为 `timeout`)。 | +| `EVALUATOR_CONFIG_REFRESH_SECS` | 否 | `300`(5 分钟) | 服务端重新从评估器获取 `GET /config` 的频率。 | +| `EVALUATOR_MAX_POLL_DURATION_SECS` | 否 | `3600`(1 小时) | 会话在轮询队列中可停留的最大实际时间,超时后 AgentEye 将其终止为 `timeout` 状态。防止评估器永久返回 `pending` 的情况。 | +| `ALERT_WORKERS` | 否 | `1` | 并发数:每个服务端实例中评估告警规则的工作任务数量。参见[告警](/zh/agenteye/alerts)。 | +| `ALERT_CLAIM_BATCH` | 否 | `16` | 单个工作进程每次轮询时最多认领的告警数量。 | +| `ALERT_POLL_IDLE_SECS` | 否 | `5` | 队列为空时告警工作进程的休眠时间(秒)。 | +| `ALERT_REQUEST_TIMEOUT_MS` | 否 | `15000` | 每次触发评估的超时时间(ClickHouse 查询 + 出站 channel HTTP)。 | +| `ALERT_MAX_ATTEMPTS` | 否 | `5` | 连续瞬态失败达到此次数后,告警以正常周期重新调度,而非指数退避。 | +| `AUDIT_WORKERS` | 否 | `1` | 并发数:每个服务端实例中执行审计的工作任务数量。参见[审计](/zh/agenteye/audits)。 | +| `AUDIT_CLAIM_BATCH` | 否 | `1` | 单个工作进程每次轮询时最多认领的到期审计数量。由于 agentic 调查是一个长循环,默认值为 1。 | +| `AUDIT_POLL_IDLE_SECS` | 否 | `30` | 无待审计任务时审计工作进程的休眠时间(秒)。 | +| `AUDIT_REQUEST_TIMEOUT_MS` | 否 | `30000` | 每次对 ClickHouse 策略查询的超时时间(毫秒)。 | +| `AUDIT_LLM_TIMEOUT_MS` | 否 | `1440000` | 对 AI 助手服务进行 agentic 调查调用的超时时间。完整的 agent 循环需要数分钟;请将此值设置为**高于** agent 自身的 `AGENTEYE_AUDIT_TIMEOUT_MS`,以便 agent 在服务端放弃之前返回其部分发现结果。 | +| `AUDIT_MAX_ATTEMPTS` | 否 | `5` | 连续瞬态失败达到此次数后,审计以正常周期重新调度,而非指数退避。 | +| `AGENTEYE_AGENT_URL` / `AGENTEYE_AGENT_TOKEN` | 否 | — | 审计的 agentic 调查调用 AI 助手的 `agent` 服务,**复用与助手相同的连接**——因此这两个变量也需要在**服务端**上设置(内置的 manifests/compose 已完成此配置)。两者均设置 ⇒ 审计运行 AI 调查;任意一个未设置 ⇒ 审计**仅运行策略**(确定性 SQL 策略检查仍然运行),无论每个审计的 `llm_enabled` 标志如何。agent 还必须配置 LLM——参见 [assistant.md](/zh/agenteye/assistant)。 | + +**AI 助手服务——审计与沙箱设置。** Agentic 调查及其 pod 内 Python 沙箱在 **agent 服务**上调整(而非服务端),所有变量均以 `AGENTEYE_AUDIT_*` 为前缀,均为可选: + +| 变量 | 默认值 | 含义 | +|---|---|---| +| `AGENTEYE_AUDIT_MAX_STEPS` | `200` | 每次调查的最大 agent 轮次。 | +| `AGENTEYE_AUDIT_TIMEOUT_MS` | `1200000` | 单次调查的实际时间(20 分钟)。必须**低于**服务端的 `AUDIT_LLM_TIMEOUT_MS`。 | +| `AGENTEYE_AUDIT_MAX_CONCURRENCY` | `1` | 每个 agent pod 的并发调查数(与聊天助手的配额相互独立)。 | +| `AGENTEYE_AUDIT_SANDBOX_TIMEOUT_MS` / `_MEM_MB` / `_CPU_SECS` / `_OUTPUT_MAX_BYTES` / `_SCRIPT_MAX_BYTES` | `20000` / `768` / `10` / `64000` / `64000` | bubblewrap 沙箱的每脚本限制。 | + +**沙箱平台要求。** 审计代码沙箱在 bubblewrap 容器内运行模型的 Python,需要**非特权用户命名空间**。agent pod 必须允许 `clone()` 标志——在 agent 上设置 `seccompProfile: Unconfined`(k8s)或 `security_opt: [seccomp:unconfined]`(compose)。当节点内核禁用非特权用户命名空间时(例如某些 GKE COS 镜像),沙箱**预检失败,审计器自动降级为仅 SQL 模式**——不报错,只是在 agent 的 `/health` 上显示 `sandbox_available: false`。 + +### 运行 + +在环境中设置 `DATABASE_URL` 和 `CLICKHOUSE_URL`(服务端未连接 ClickHouse 时拒绝启动),然后传递给容器: + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-server \ + -e DATABASE_URL="$DATABASE_URL" \ + -e CLICKHOUSE_URL="$CLICKHOUSE_URL" \ + -e ADMIN_KEY="$ADMIN_KEY" \ + -p 8080:8080 \ + ghcr.io/agenteye-enterprise/server:beta-latest +``` + +服务端在启动时自动运行数据库迁移,无需单独的迁移步骤。 + +### 健康检查 + +``` +GET /health # 存活检查 - 进程启动后始终返回 {"status":"ok"} +GET /ready # 就绪检查 - Postgres + ClickHouse 可达时返回 200,否则返回 503 +``` + +无需认证。**存活**探针使用 `/health`,**就绪**/负载均衡器探针使用 `/ready`。`/ready` 检查服务端不可缺少的硬依赖(Postgres + ClickHouse),因此正在运行但无法连接数据库的服务端将被移出轮换并显示为 `NotReady`;Redis 会被报告但不会导致就绪检查失败。在内置 Kubernetes manifests 中,就绪探针已指向 `/ready`,存活探针保持在 `/health`。完整说明(包括 Kubernetes 原生 pod 故障告警到 Slack 的可选功能)参见 [enterprise-docs/health-monitoring.md](/zh/agenteye/health-monitoring)。 + +### 邮件魔法链接 URL + +OTP 登录邮件包含一个一键**打开控制台**的按钮。点击后用户将跳转至 `/login?token=&email=
`;控制台将该组合兑换为会话并重定向到应用,无需手动重新输入代码。服务端通过三个层级来解析用于构建链接的控制台来源地址: + +1. **`X-AgentEye-Dashboard-Url` 请求头**:由控制台的 `/api/auth/otp/request` 代理从其自身的公开来源自动设置。在同域名部署中(服务端与控制台共享主机,位于一个转发代理请求头的 ingress 之后),**无需任何配置**。 +2. **`DASHBOARD_URL` 环境变量**:如果控制台的访问地址与服务端 OTP 请求端点所见的来源不同(分域名 `api.example.com` / `app.example.com`),或者 ingress 未将公开主机名传递给控制台 pod(导致 `request.nextUrl.origin` 解析为类似 `0.0.0.0:3000` 的通配符地址),请设置此项。示例:`DASHBOARD_URL=https://app.example.com`。 +3. **默认值**:`https://app.befailproof.ai`,仅在以上两者均不存在时使用。 + +请求头值会经过验证:仅接受 `https://*` 和本地回环(`http://localhost*`、`http://127.0.0.1*`)来源,通配符绑定地址(`0.0.0.0`、`[::]`)即使带有 `https://` scheme 也会被拒绝。不符合条件的值将回退至第 2 层。 + +通过单行命令在运行中的集群上设置,无需文件,无需重新构建 kustomize: + +```bash +kubectl set env deployment/server -n agenteye \ + DASHBOARD_URL=https://app.example.com +``` + +此操作将触发滚动更新;新 pod 在首次请求时读取该值。请注意,此覆盖仅存在于 Deployment 上;后续对 overlay 执行 `kustomize build | kubectl apply` 将清除此设置,除非您将相同的环境变量添加到 overlay 的 `server-env.yaml` 补丁中。 + +--- + +## 控制台 + +### 拉取镜像 + +```bash +docker pull ghcr.io/agenteye-enterprise/dashboard:beta-latest +``` + +### 环境变量 + +| 变量 | 是否必需 | 默认值 | 说明 | +|---|---|---|---| +| `AGENTEYE_SERVER_URL` | 是 | 无 | 服务端的基础 URL,例如 `http://localhost:8080` | +| `AGENTEYE_API_KEY` | 是 | 无 | 控制台用于向服务端认证的 API 密钥。需要全部权限(建议使用管理员密钥)。 | +| `AE_LOG_LEVEL` | 否 | `info` | 服务端日志详细程度:`debug`、`info`、`warn`、`error`。设置为 `debug` 可在诊断问题时查看上游请求/响应行和会话验证追踪。 | +| `AE_LOG_JSON` | 否 | 自动 | `1` 强制 JSON 逐行输出;`0` 强制人类可读输出。未设置时,若 `NODE_ENV=production` 则自动启用 JSON。生产环境推荐使用 JSON 格式,以便通过 `jq` 或日志聚合器解析。 | +| `AE_ANALYTICS_DISABLED` | 否 | 无 | 设置为 `1`/`true` 可禁用控制台的匿名产品使用遥测。详见下方[遥测与隐私](#telemetry--privacy)。 | +| `REDIS_URL` | 否 | 无 | 可选的共享缓存后端,例如 `redis://redis:6379/0`。设置后,控制台在多副本间缓存 `validateSession()` 结果,并为延迟聚合/环境列表代理路由共享 Next.js 获取缓存。若 Redis 可达,边缘侧的 OTP 请求和验证速率限制也使用 Redis(Redis 不可达时开放通行;服务端侧限制是安全保障)。详见下方 **Redis(可选缓存)**。 | +| `AGENTEYE_AGENT_URL` | 否 | 无 | 可选 AI 助手 `agent` 服务的基础 URL,例如 `http://agent:9100`。**不设置则完全隐藏助手**:控制台不显示助手气泡。参见 [enterprise-docs/assistant.md](/zh/agenteye/assistant)。 | +| `AGENTEYE_AGENT_TOKEN` | 否 | 无 | 控制台向 `agent` 服务出示的共享密钥。必须与 agent 上配置的 `AGENTEYE_AGENT_TOKEN` 匹配。参见 [enterprise-docs/assistant.md](/zh/agenteye/assistant)。 | + +### 运行 + +```bash +docker run -d --restart unless-stopped \ + --name agenteye-dashboard \ + -e AGENTEYE_SERVER_URL="http://your-server-host:8080" \ + -e AGENTEYE_API_KEY="$ADMIN_KEY" \ + -p 3000:3000 \ + ghcr.io/agenteye-enterprise/dashboard:beta-latest +``` + +### 遥测与隐私 + +控制台向 Exosphere 的分析服务(PostHog)发送**匿名产品使用分析数据**:访问了哪些控制台页面,以及少量 UI 操作(如创建 API 密钥或重新评估会话)。此使用信号用于指导功能优先级排序。 + +- **任何 agent、会话或事件数据都不会离开您的基础设施。** 仅报告控制台 UI 使用情况。页面 URL 在发送前会去除标识符,运营人员仅以不透明的内部 ID 标识,绝不使用邮箱。 +- 遥测**默认启用**。若要完全关闭,请在控制台容器上设置 `AE_ANALYTICS_DISABLED=1` 并重启。 +- 分析数据发送到控制台自身的 `/ingest` 路径,由控制台反向代理至 PostHog(`https://us.i.posthog.com`)。保持请求为第一方可防止浏览器广告拦截器屏蔽。**控制台容器**需要能够访问 PostHog 的出站网络;若被阻断,遥测将静默失效,控制台不受影响。 + +--- + +## AI 助手(可选) + +控制台内置的 AI 助手让您的团队可以用自然语言查询 agent 数据(汇总会话、为 `/queries` 编辑器起草 SQL,以及将已保存的查询转化为控制台图块),无需离开控制台。它以独立的内部 `agent` 容器(基于 Claude Agents SDK)运行,仅控制台可访问,**在您配置 LLM 端点之前保持禁用状态**。 + +要启用它,您需要在 `agent` 服务上设置 LLM 连接(通过 `PORTKEY_API_KEY` + 模型目录 slug `AGENTEYE_AGENT_MODEL=@/` 使用 **Portkey**,或通过 `ANTHROPIC_API_KEY` 直连 Anthropic,或通过 `ANTHROPIC_BASE_URL` 使用其他网关,或使用 Bedrock/Vertex),以及一个**专用**数据密钥和与控制台匹配的共享 `AGENTEYE_AGENT_TOKEN`。控制台用户还需要 `agent:use` 权限。 + +助手的数据密钥无需手动创建:选择一个随机密钥,在 `agent` 上设置为 `AGENTEYE_API_KEY`,同时在 `server` 上设置为 `AGENT_API_KEY`,服务端将在启动时以固定权限集写入该密钥。其数据访问为只读(`events:read`、`evaluations:read`、`dashboards:read`、`queries:read`),并额外持有需审批的创作权限(`dashboards:write`、`queries:write`、`queries:run`),以便代表用户起草和验证已保存的查询并构建控制台图块;所有 SQL 仍通过 org 的只读 ClickHouse 角色运行,因此这扩展了助手的创作范围,而非其可访问的数据范围。这些权限固定在代码中,无法通过配置扩展。该密钥受保护;无法通过 API 禁用或重新生成,只能通过修改值并重启来轮换。请勿将管理员/控制台密钥复用于此用途。 + +完整设置、完整的环境变量参考、遥测选项和安全模型详见 **[enterprise-docs/assistant.md](/zh/agenteye/assistant)**。 + +--- + +## ClickHouse(必需的分析存储) + +ClickHouse 在高事件量下保持控制台响应,并允许 `/queries` SQL 编辑器在单一存储中跨事件、评估和会话进行联合查询。它是每个摄入事件、每个终止评估结果以及派生的每会话聚合数据的必需权威存储。PostgreSQL 存储关系型/可变状态表(api_keys、users、otp_codes、evaluation_jobs、dashboards、saved_queries);分析层存储在 ClickHouse 中,以便控制台的汇总统计和您自己的 SQL 查询可以原生扫描和联合,无需跨数据库往返。服务端未设置 `CLICKHOUSE_URL` 时拒绝启动。 + +### 模式 + +服务端启动时创建三个 ClickHouse 对象,均为幂等操作(`CREATE IF NOT EXISTS`): + +- **`agenteye.events`**:`ReplacingMergeTree(ingested_at)`,按 `toYYYYMM(ts)` 分区,按 `(session_id, ts, dedup_key)` 排序。重复插入(采集器重试)在合并时折叠为单行;服务端为每个事件计算确定性的 SHA-256 `dedup_key`,确保重试安全。 +- **`agenteye.evaluations`**:`ReplacingMergeTree(ingested_at)`,按 `toYYYYMM(finished_at)` 分区,按 `(session_id, finished_at, dedup_key)` 排序。由评估器流水线在每个终止评估结果时写入一次。与 `events` 相同的去重键模型。 +- **`agenteye.agent_sessions`**:基于 `agenteye.events` 的**视图**,非物理表。每列均为派生列(`started_at = min(ts)`、`last_event_at = max(ts)`、`ended_at = max(if event_type='agent_end', ts, NULL)`、`event_count = count()` 等)。无需每事件 upsert,无需单独回填;视图自动反映 `events` 中的所有内容。 + +为与引用 `analytics.evaluations` / `analytics.sessions` 的已保存查询保持向后兼容,服务端还会创建一个 `analytics` ClickHouse 数据库,其中包含基于 `agenteye.*` 表的视图;`analytics.events`、`analytics.evaluations`、`analytics.agent_sessions`、`analytics.sessions` 均可正常解析。 + +### 配置 + +内置的 docker-compose 和 `deploy/base/clickhouse/` 提供了针对 AgentEye 工作负载调优的 ClickHouse 服务: + +- 内置基础 overlay 中申请 2 GiB / 限制 4 GiB 内存(适配小型 POC/预发布节点);生产客户应覆盖配置——推荐最低配置为 2c / 4Gi 申请,6c / 8Gi 限制。`max_server_memory_usage_to_ram_ratio=0.9` +- 5 GiB 标记缓存 + 8 GiB 未压缩缓存 +- `background_pool_size=16`,`background_merges_mutations_concurrency_ratio=2` +- MergeTree:`parts_to_throw_insert=3000`,`parts_to_delay_insert=1500`,`non_replicated_deduplication_window=1000` +- `local_io_method=auto`(支持的内核上使用 io_uring) +- `fsync_metadata=0`:可接受,因为使用至少一次摄入 + ReplacingMergeTree 去重 +- `query_log` 启用,TTL 30 天;`query_thread_log` 已移除(高 QPS 下开销较大) +- 用户端查询 `max_execution_time=30` +- StatefulSet 模板中 100 GiB PVC(客户 overlay **应**覆盖为生产环境的快速 SSD 存储类) + +### 备份 + +您的完整数据集每晚在单个可恢复归档中捕获,因此集群或存储故障后可恢复。ClickHouse 由每日 `agenteye-backup` CronJob 自动备份,该任务在一次运行中同时转储 PostgreSQL 和 ClickHouse。ClickHouse 通过其 HTTP API 读取:`agenteye.events` 和 `agenteye.evaluations` 以 ClickHouse 原生格式转储(视图和行策略由服务端在启动时重新创建,因此表数据即为完整数据),与 Postgres 转储一起打包为单个压缩归档并上传至您的对象存储。 + +目标存储桶和云凭证按 overlay 配置。上传配置和恢复步骤详见 [enterprise-docs/kubernetes-deployment.md](/zh/agenteye/kubernetes-deployment) 的**备份**部分。 + +--- + +## Redis(可选缓存) + +Redis 是一个**可选**的共享缓存 + 速率限制后端,由服务端和控制台使用。部署 Redis 并在两个服务上设置 `REDIS_URL` 后: + +- **服务端**缓存已认证的 API 密钥查找、`/events/environments` + `/evaluations/environments` 列表、`/events/latency_aggregate` 汇总(控制台轮询的最重查询)、`/sessions` 列表,并将 OTP 请求速率限制从 Postgres `COUNT(*)` 切换为 Redis `INCR + EXPIRE`。 +- **控制台**缓存 `validateSession()` 结果,使典型页面加载发出的 10-20 次已认证 API 调用共享一次上游会话检查。同时在控制台边缘限制 OTP 请求和 OTP 验证的速率。 + +**两个服务在 Redis 不可达时均会优雅降级。** 每次缓存调用在有限超时内返回 `Err`,调用方回退到数据源(服务端的 Postgres,控制台的上游 Rust 服务端)。OTP 速率限制回退到服务端的 Postgres `COUNT(*)` 路径(安全属性得以保留);控制台的边缘 OTP 限制开放通行,而服务端侧限制仍然有效。Redis 故障只影响延迟,不影响正确性。 + +### 配置 + +docker-compose 套件已包含 Redis 服务,并将 `REDIS_URL=redis://redis:6379/0` 注入服务端和控制台。若要使用外部 Redis,将 `REDIS_URL` 设置为您的端点,并从 compose 文件中移除 `redis` 服务。 + +### 内存与持久化 + +内置 Redis 镜像使用 `--appendonly yes --appendfsync everysec --maxmemory 256mb --maxmemory-policy allkeys-lru` 运行。AOF 持久化使缓存在容器重启后存活;`everysec` 是正确的持久性/性能平衡,因为丢失最后一秒的缓存写入是无害的。LRU 淘汰策略控制内存增长。 + +### 何时不部署 Redis + +- 单实例开发/QA 环境。服务端的进程内缓存本身已提供了大部分单副本收益;Redis 增加的是单实例不需要的跨副本共享。 +- 运行额外服务的运营成本超过延迟收益的气隙安装环境。 + +--- + +## Docker Compose(推荐) + +`agenteye-enterprise/releases` 仓库中提供了 `docker-compose.yml`。通过单个命令即可启动 Postgres、ClickHouse、Redis、服务端和控制台。 + +```bash +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download \ + --repo agenteye-enterprise/releases \ + --pattern 'docker-compose.yml' \ + --dir ./agenteye +cd agenteye +``` + +**通过 `.env` 覆盖默认值:** + +``` +# 使用 URL 安全的密码(不含 /、+ 或 = 字符)。 +# 生成命令:openssl rand -hex 24 +POSTGRES_PASSWORD=your-db-password +ADMIN_KEY=your-admin-secret + +# 控制台认证 +ADMIN_EMAIL=admin@yourcompany.com +ALLOWED_EMAILS=*@yourcompany.com + +# 用于 OTP 邮件的 SMTP(省略则将 OTP 代码输出到 stdout) +# SMTP_HOST=smtp.yourprovider.com +# SMTP_PORT=587 +# SMTP_USERNAME=your-smtp-user +# SMTP_PASSWORD=your-smtp-password +# SMTP_FROM=noreply@yourcompany.com + +RUST_LOG=info +``` + +```bash +docker compose up -d +``` + +**停止(保留数据卷):** + +```bash +docker compose down +``` + +**停止并清除所有数据:** + +```bash +docker compose down -v +``` + +--- + +## 运营设置 + +以前通过环境变量固定的一小部分运营配置项现在可以从控制台的 **`//settings`** 页面按组织编辑;每个 org 独立配置。修改在数秒内生效,无需重启或重新部署。 + +| 设置 | 引导环境变量 | 控制内容 | +|---|---|---| +| 允许登录 | `ALLOWED_EMAILS` | 允许接收 OTP 并被添加为用户的邮箱(或 `*@domain.com` 通配符) | +| 默认用户权限 | `DEFAULT_USER_PERMISSIONS` | 管理员打开**+ 新用户**时预选的权限 token,以逗号分隔。每个 token 必须是 [API 密钥权限](/zh/agenteye/api-keys) 中列出的字符串之一。默认为 `standard` 预设:只读访问加上日常待命操作(触发重新评估、运行查询、确认事件、使用助手)。 | +| 会话有效期 | `SESSION_TTL_SECS` | 控制台登录在需要重新认证之前的有效时长。控制台每 5 秒重新检查上游会话,因此在 `//users` 上的权限更新在受影响用户的下次请求时生效,无需重新登录。 | +| 一次性代码有效期 | `OTP_TTL_SECS` | OTP / 魔法链接的可用时长 | +| 告警通知渠道 | `ALERTS_ENABLED_CHANNELS` | 告警调度器允许使用的渠道类型,以逗号分隔:`email`、`slack`、`webhook`。每个告警的具体配置仍在 `//alerts/` 中编辑,但调度器会通过此集合过滤所有出站投递;此处禁用的渠道将以 `skipped_disabled` 审计行短路。`dashboard` 渠道(本地审计插入)始终允许。默认三者全部开启。 | + +### 引导机制说明 + +设置以每个组织为单位存储在 `org_settings` 中。首次启动时,服务端从匹配的环境变量(若未设置则使用合理的默认值)写入默认 org 的缺失行。此后,**存储的值是权威来源,环境变量将被忽略**;后续重启时修改环境变量不会影响已有 org 的值,新增的 org 从默认值开始并自行配置。 + +这意味着: + +- 对于全新部署,按上述方式设置环境变量,默认 org 将在首次启动时读取它们。 +- 若要之后修改某个值,请登录控制台并在 `//settings` 下编辑。修改在数秒内在所有服务端副本上生效;无需重启。 +- 启动日志会记录哪些值已写入以及哪些已存在,方便您确认引导是否生效: + + ```text + INFO settings bootstrap: seeded default-org row key=allowed_sign_ins env_var=ALLOWED_EMAILS seeded_from_env=true + ``` + +#### 跨组织的登录语义 + +会话和 OTP 是全局于用户的,而非单个 org,因此在登录时有两条规则协调每 org 设置: + +- **会话 / OTP 有效期**:用户所属的所有 org 中最严格(最短)的有效期胜出。 +- **允许登录**:规则对每个 org 的允许列表与 org 成员资格取 OR:若任意 org 的允许列表接受用户的邮箱,**或**用户已是任意 org 的成员,则该用户可以请求 OTP。 + +### 权限 + +访问 `//settings` 页面需要两个权限: + +- `settings:read`:查看页面和当前值。 +- `settings:write`:保存修改。 + +引导管理员用户(从 `ADMIN_EMAIL` 写入)自动获得这两个权限以及所有其他权限。可根据需要在 `//users` 中将其授予其他用户。 + +--- + +## Organizations(多租户) + +单个部署可服务于多个隔离的 **organizations**(租户);每行数据归属于且仅归属于一个 org,隔离在数据库引擎层面强制执行。单租户安装无需进行任何配置;所有数据存储在内置的 `default` org 中。(您可以通过在首次启动前设置 `DEFAULT_ORG_NAME` / `DEFAULT_ORG_SLUG`,或随时使用 `agenteye-orgctl org rename` 重命名,为该 org 设置更友好的名称和 URL slug,例如让其位于 `/acme` 而非 `/default`。) + +**租户配置仅限运营人员操作。** Organizations 及其成员资格使用 **`agenteye-orgctl`** CLI 创建和管理,该 CLI **内置于服务端镜像**中(与 `agenteye-server` 并列),**在现有服务端 pod 内**运行;**没有独立的 pod/Job、没有 HTTP API,也没有控制台按钮**。它复用服务端的 `DATABASE_URL`、`CLICKHOUSE_URL` 和 `ORG_CH_SECRET`。 + +```bash +# Docker Compose - 进入运行中的服务端服务: +docker compose exec server agenteye-orgctl org create --slug acme --name "Acme Corp" +docker compose exec server agenteye-orgctl member add --org acme --email alice@acme.example --set admin + +# Kubernetes - 进入运行中的服务端 Deployment: +kubectl -n agenteye exec deploy/server -- agenteye-orgctl org list +``` + +可用命令:`org create | list | rename | delete | purge` 和 `member add | list | update | remove`,内置权限集 `admin`、`standard` 和 `read-only`。添加的成员在首次控制台登录时收到 OTP。 + +**在创建第二个 org 之前:** 设置强且稳定的 `ORG_CH_SECRET`(`org create` 命令拒绝在内置开发默认值下运行),并确保 Postgres 为 **15+** 版本。**未变更:** 每 org 的 API 密钥仍由控制台/API 中的 org 成员创建;只有 org + 成员生命周期移至 CLI。完整命令参考和操作示例详见 **[enterprise-docs/tenant-management.md](/zh/agenteye/tenant-management)**。 + +--- + +## 上下文窗口填充 + +每个 `model_response` 事件显示一个**上下文填充标签** — 输入加输出 token 占该模型上下文窗口的百分比。区间为 `healthy`(0–24%)、`watch`(25–49%)、`compacting`(50–74%)和 `reset context`(75–100%)。AgentEye 自动解析常见的模型 ID,因此无需初始配置。 + +组织发送的每个模型都会出现在 **Settings → model context windows** 下。拥有 `settings:write` 权限的用户可以覆盖其窗口大小或添加私有/代理模型(0–1,000,000 token);`0` 表示"未知",会隐藏标签。修改对新摄入的事件生效。拥有 `settings:read` 权限的用户可以查看列表。 + +升级后的新事件会立即计算填充值。若要同时为现有部署填充**历史**事件(以及每模型列表),请运行一次性回填命令——它内置于服务端镜像中(与 `agenteye-orgctl` 类似),在现有服务端 pod 中运行: + +```bash +# 预览(打印每 org 的变更,不实际修改): +kubectl -n agenteye exec deploy/server -- agenteye-backfill-context-window --dry-run +# 应用: +kubectl -n agenteye exec deploy/server -- agenteye-backfill-context-window +# docker compose: +docker compose exec server agenteye-backfill-context-window +``` + +该命令是幂等的(可安全重复运行),并复用 pod 中的 `DATABASE_URL` / `CLICKHOUSE_URL` / `REDIS_URL`。如果您编辑了模型窗口后希望重新计算现有事件,请再次运行。 + +--- + +## 生产注意事项 + +- **Postgres**:使用托管的 Postgres 服务或专用实例,并定期备份。`DATABASE_URL` 支持所有标准 libpq 参数,包括用于加密连接的 `sslmode=require`。 +- **TLS**:将服务端和控制台放在终止 TLS 的反向代理(nginx、Caddy、Traefik)之后。 +- **防火墙**:服务端端口(默认 8080)应仅对采集器机器和控制台主机可达,而非公共互联网。 +- **管理员密钥**:将 `ADMIN_KEY` 设置为强随机密钥。引导完成后,为采集器和控制台创建专用的作用域密钥,而非在所有地方使用管理员密钥。 +- **镜像标签**:在生产环境中使用发布 manifests 中固定的版本(例如 `server:v0.0.1-beta.48`),而非浮动标签,以避免意外升级。当前 beta 构建发布于 `beta-latest` 标签下;`latest` 仅在稳定版发布时使用。 +- **健康监控**:在 Kubernetes 上,就绪探针使用 `/ready`(Postgres + ClickHouse 可达性),存活探针保持在 `/health`。若要实现全集群范围内"AgentEye 是否正常运行"的 Slack 告警,请启用可选的 Robusta 插件;参见 [enterprise-docs/health-monitoring.md](/zh/agenteye/health-monitoring)。 + +--- + +## 可用镜像标签 + +| 标签 | 说明 | +|-----|-------------| +| `latest` | 最新稳定版 | +| `beta-latest` | 最新预发布版(beta) | +| `v` | 固定版本,例如 `v0.0.1-beta.48`(推荐用于生产) | \ No newline at end of file diff --git a/docs/zh/agenteye/evaluation-suite.mdx b/docs/zh/agenteye/evaluation-suite.mdx new file mode 100644 index 00000000..42d6dcf5 --- /dev/null +++ b/docs/zh/agenteye/evaluation-suite.mdx @@ -0,0 +1,358 @@ +--- +title: "评估套件" +description: "AgentEye 评估套件文档。" +--- + + +AgentEye 通过向**客户自有的评估服务**发送 POST 请求,将完整的事件记录提交,以对已完成的 agent 会话进行评分。评估服务可直接返回评分结果,或返回一个 `job_id` 供 AgentEye 轮询。评分结果将被存储并展示在仪表盘中。 + +本文档涵盖以下内容: + +1. 会话完成的检测方式。 +2. 评估服务必须实现的 HTTP 协议规范。 +3. AgentEye 服务器的配置方法。 +4. 查看评估结果。 +5. 故障排查。 + +如需使用已实现上述协议规范的 Python 辅助库,请参阅 +[PyPI 上的 `agenteye-evaluator` 包](https://pypi.org/project/agenteye-evaluator/)。 + +--- + +## 工作原理 + +```text +ingest /events ──▶ AgentEye ──── POST /evaluate ────▶ 评估服务 + (agent_end) server ◀──── done | pending ──── + │ + │ GET /evaluate/{job_id} ─────▶ + │ ◀──── done ────────────── + ▼ + evaluations (终态结果) +``` + +当 AgentEye SDK 为某个会话发出 `agent_end` 事件时,服务器会调度一次评估任务,并将完整的事件记录以 POST 请求发送至评估服务。评估服务可以: + +- **直接返回结果**,格式为 `{"status":"done", "scores":{...}, "reasoning":{...}, "summary":"..."}`。结果将追加至该会话的评估时间线中。`reasoning` 和 `summary` 为可选字段。 +- **延迟处理**,返回 `{"status":"pending", "job_id":"abc-123"}`。AgentEye 随后会调用 `GET {EVALUATOR_ENDPOINT}/evaluate/abc-123`,直至评估服务返回 `{"status":"done", ...}` 或 `{"status":"error", "error":"..."}`。 + + 轮询频率以单个任务为单位:`pending` 响应中可包含 `next_poll_secs` 来覆盖默认值;否则 AgentEye 使用 `GET /config` 中的 `default_poll_interval_secs`;再次兜底则使用服务器的 `EVALUATOR_POLLING_INTERVAL_SECS`(默认 10 秒)。所有值均限定在 [1s, 1h] 范围内。 + +对于从未发出 `agent_end` 事件的会话(例如 agent 进程崩溃),同样可以触发评估:评估服务的 `GET /config` 可返回 `{"inactivity_timeout_secs": 1800}`,AgentEye 将对闲置时间超过该值的会话发起评估。将该字段设为 `null` 或省略可禁用此兜底机制。 + +若未设置 `EVALUATOR_ENDPOINT`,整个评估管道将完全空操作。 + +一个会话可以随时间积累**多个终态评估结果**:每个 `agent_end` 事件(以及每次从仪表盘手动触发的重新评估)都会追加一条新的评估记录。这是评估已恢复对话的标准方式:用户结束 agent 后,稍后返回继续发送事件,再次结束 agent,第二次评估将针对更新后的完整记录运行。仪表盘将最新一次评估作为主要显示内容,历史评估以可折叠时间线的形式呈现。当某会话有评估正在运行时,该会话的后续 `agent_end` 事件将被忽略;等当前评估完成后,下一个 `agent_end` 事件才会正常入队新的评估任务。 + +闲置兜底机制在已恢复的会话中同样生效:如果在已有终态评估的情况下又有新事件到来,且会话随后闲置超过 `inactivity_timeout_secs`,则会触发新的评估任务入队。 + +瞬时错误(5xx、429、超时、网络错误)将以指数退避方式重试,最多重试 `EVALUATOR_MAX_ATTEMPTS` 次;4xx 响应为终态错误。AgentEye 支持多实例水平扩展,任务会分区处理,同一会话不会被并发派发两次。 + +--- + +## HTTP 协议规范 + +所有需要认证的路由均使用 **Bearer Token 认证**,双方必须配置相同的令牌值: + +- AgentEye 服务器:环境变量 `EVALUATOR_TOKEN` +- 评估服务:以相同方式配置(`agenteye-evaluator` SDK 按惯例读取 `EVALUATOR_TOKEN`) + +若未设置 `EVALUATOR_TOKEN`,服务器发送请求时不携带 `Authorization` 头;评估服务可选择接受匿名请求,这在纯内部网络环境下可行,但不建议在公网上使用。 + +### 评估服务必须实现的路由 + +| 路由 | 请求体/参数 | 响应 | +|---|---|---| +| `GET /health` | 无 | `{"status":"ok"}`(开放,无需认证) | +| `GET /config` | 无 | `{"inactivity_timeout_secs": \| null, "default_poll_interval_secs": \| omitted}` | +| `POST /evaluate` | `EvalRequest` JSON | `{"status":"done", ...}` 或 `{"status":"pending", "job_id":"..."}` | +| `GET /evaluate/{id}` | 无 | 与 `/evaluate` 相同的响应结构 | + +### 服务器发送的 `EvalRequest` 请求体 + +```json +{ + "schema_version": "1", + "session_id": "session-abc123", + "agent_id": "planner", + "environment": "production", + "started_at": "2026-05-10T12:00:00Z", + "ended_at": "2026-05-10T12:05:00Z", + "events": [ + { "id": 1234, "ts": "...", "event_type": "agent_start", "payload": { ... } }, + ... + ] +} +``` + +### 响应格式 + +**同步(直接返回结果):** + +```json +{ + "status": "done", + "scores": { "helpfulness": 0.85, "tool_efficiency": 0.6 }, + "reasoning": { + "helpfulness": "answered the question directly with citations", + "tool_efficiency": "called list_files three times when one would have done" + }, + "summary": "strong answer quality, weak tool selection" +} +``` + +`reasoning`(每个评分维度的解释说明映射)和 `summary`(整体总结段落)均为可选字段。`reasoning` 中的键应与 `scores` 中的键对应;仪表盘会在每个评分条下方渲染对应的解释内容。只返回 `scores` 的旧版评估服务无需修改仍可正常使用;`reasoning` 和 `summary` 字段在缺失时读取为 null,对应的界面元素将不显示。 + +**异步(延迟处理):** + +```json +{ "status": "pending", "job_id": "abc-123", "next_poll_secs": 30 } +``` + +`next_poll_secs` 为可选字段;若省略,服务器将依次回退至评估服务 `/config` 中的 `default_poll_interval_secs`,再回退至自身的 `EVALUATOR_POLLING_INTERVAL_SECS` 环境变量。 + +**评估服务侧终态错误:** + +```json +{ "status": "error", "error": "model service unavailable" } +``` + +服务器将任何其他 2xx 响应体视为协议错误,并为该会话记录终态 `error`。 + +--- + +## 使用 SDK 编写评估服务 + +`agenteye-evaluator` Python 包提供了一个带类型的 FastAPI 封装,已实现上述 HTTP 协议规范。从 PyPI 安装: + +```bash +pip install agenteye-evaluator +``` + +最简评估服务示例: + +```python +import os +from agenteye_evaluator import Evaluator, EvalRequest, EvalResponse + +app = Evaluator(token=os.environ["EVALUATOR_TOKEN"]) + +@app.evaluator +def run(req: EvalRequest) -> EvalResponse: + # 检查 req.events(完整的会话记录)并返回评分。 + tool_calls = sum(1 for e in req.events if e.event_type == "tool_use") + return EvalResponse( + scores={"tool_calls": float(tool_calls)}, + reasoning={"tool_calls": f"{tool_calls} tool invocations in the transcript"}, + summary="tight tool loop" if tool_calls < 5 else "agent looped on tools", + ) +``` + +`app` 实例为 ASGI 可调用对象,使用 `uvicorn module:app` 即可运行。 + +对于需要延迟处理耗时任务的评估服务,可返回 `JobPending` 并注册 `@app.job_lookup` 处理函数;AgentEye 服务器将轮询 `GET /evaluate/{job_id}`,直至返回终态状态或达到 `EVALUATOR_MAX_POLL_DURATION_SECS` 上限(默认 1 小时)。 + +完整 API 参考文档、异步模式说明及事件 schema 请参阅 `agenteye-evaluator` 的 README,该文件随每个发布包附带于 +[agenteye-enterprise releases 页面](https://github.com/agenteye-enterprise/releases),也可在该包的 PyPI 页面查阅。 + +--- + +## 在 Kubernetes 上运行评估服务 + +评估服务是**您自己的服务**:AgentEye 不提供默认的评估服务容器。发布包中包含 `deploy/examples/evaluator/` 目录下的 Kubernetes 参考清单,替换镜像地址和共享 Bearer Token 后即可直接应用。 + +### 1. 将评估服务容器化 + +评估服务的最简 Dockerfile: + +```dockerfile +FROM python:3.12-slim +WORKDIR /app +RUN pip install --no-cache-dir agenteye-evaluator uvicorn +COPY my_evaluator.py . +RUN useradd --uid 10001 --create-home --shell /usr/sbin/nologin evaluator \ + && chown -R evaluator:evaluator /app +USER evaluator +EXPOSE 9000 +CMD ["uvicorn", "my_evaluator:app", "--host", "0.0.0.0", "--port", "9000"] +``` + +设置 `runAsNonRoot`(UID 10001)可使容器兼容 Pod Security 受限配置文件。 + +### 2. 创建共享 Bearer Token + +```bash +kubectl -n agenteye create secret generic evaluator-token \ + --from-literal=token="$(openssl rand -hex 32)" +``` + +该值需与 AgentEye 服务器上的 `EVALUATOR_TOKEN` 保持一致。服务器每次请求均会发送 `Authorization: Bearer `;SDK 使用 `hmac.compare_digest` 进行常量时间校验,不匹配时返回 HTTP 401。 + +### 3. 应用示例清单 + +```bash +# 先编辑 deploy/examples/evaluator/deployment.yaml, +# 将 `image:` 指向您的镜像仓库,然后执行: +kubectl apply -k deploy/examples/evaluator/ +``` + +示例清单包含: + +- 2 副本的 Deployment,配置了 `runAsNonRoot`、只读根文件系统、删除所有 capabilities,以及基于 `/health` 的存活探针和就绪探针 +- 端口 9000 的 ClusterIP Service +- `secret.example.yaml` 模板(已从 Kustomization 中排除,请通过带外方式创建真实 Secret,避免令牌提交到 git) + +### 4. 将 AgentEye 连接到评估服务 + +在 AgentEye 服务器上设置: + +```bash +EVALUATOR_ENDPOINT=http://evaluator:9000 +EVALUATOR_TOKEN=<上面生成的值> +``` + +服务器会向所有评估服务 Pod 并发发送 `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH` 个请求(默认值:`2 × 4 = 8`)。请根据这些服务端参数同步调整 `replicas` 和每个 Pod 的资源限制。 + +### 验证 + +```bash +kubectl -n agenteye port-forward svc/evaluator 9000:9000 +curl -s http://localhost:9000/health # → {"status":"ok"} +``` + +在 agent 完整运行一次后,AgentEye 服务器上的 `GET /evaluations` 应返回一条 `status: "done"` 的记录,其中包含评估服务产生的评分。 + +--- + +## 配置 AgentEye 服务器 + +在服务器进程上设置以下环境变量: + +| 环境变量 | 说明 | +|---|---| +| `EVALUATOR_ENDPOINT` | 评估服务的基础 URL(如 `http://evaluator:9000`)。未设置时评估管道禁用。 | +| `EVALUATOR_TOKEN` | Bearer Token,必须与评估服务配置的值完全一致。 | +| `EVALUATOR_WORKERS` | 每个服务器实例的工作任务数(默认 2)。 | +| `EVALUATOR_CLAIM_BATCH` | 每次工作节拍认领的任务行数(默认 4)。批次内任务**并发**处理;对评估服务端点的实际并发数为 `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH`。 | +| `EVALUATOR_POLL_IDLE_SECS` | 无待评估任务时,工作线程在两次派发尝试之间的休眠时长(默认 2 秒)。 | +| `EVALUATOR_POLLING_INTERVAL_SECS` | 当单次响应中无 `next_poll_secs` 且评估服务也未设置 `default_poll_interval_secs` 时,`GET /evaluate/{id}` 的兜底轮询间隔(默认 10 秒)。 | +| `EVALUATOR_REQUEST_TIMEOUT_MS` | 单次请求超时时间(默认 30000 毫秒)。 | +| `EVALUATOR_MAX_ATTEMPTS` | 瞬时错误累计达到此次数后,结果记录为终态 `error`(默认 5 次)。 | +| `EVALUATOR_CONFIG_REFRESH_SECS` | `GET /config` 的刷新间隔(默认 300 秒)。 | +| `EVALUATOR_MAX_POLL_DURATION_SECS` | 会话在轮询队列中可停留的最长挂钟时间,超出后记录为 `timeout`(默认 3600 秒)。防止评估服务持续返回 `pending` 的情况。 | + +若要为整个实例启用自动评分,请创建包含上述两个键的 `agenteye-evaluator` Secret。在附带的 Kubernetes 清单中,服务器从该可选 Secret 中读取 `EVALUATOR_ENDPOINT` 和 `EVALUATOR_TOKEN`。请通过组织的标准密钥管理流程创建该 Secret,然后重启服务器 Deployment 使配置生效。 + +上述调优参数默认不在 Deployment 清单中配置;如需覆盖默认值,请在服务器容器的 Deployment 清单中显式添加对应的环境变量。 + +完整环境变量列表请参阅 [deployment.md](/zh/agenteye/deployment)。 + +--- + +## API 参考 + +| 方法 | 路径 | 所需权限 | 用途 | +|---|---|---|---| +| `GET` | `/evaluations` | `evaluations:read` | 查询终态结果。支持以下过滤参数:`session_id`、`agent_id`、`environment`、`status`(`done`/`error`/`timeout`)、`ts_from`、`ts_to`、`cursor`、`limit`、`score_filters`、`latest_per_session`。`limit` 默认为 50,上限为 200(注意与 `/events` 不同,后者上限为 1000)。`environment` 支持逗号分隔的多值列表(如 `environment=prod,staging`);单个值仍然有效。使用 `latest_per_session=true` 时,响应中每个 `session_id` 最多返回一条记录(按 `completed_at` 取最新),供会话列表页面将会话的评估时间线折叠为当前主要结果。默认为 false(返回完整历史记录)。 | +| `GET` | `/evaluations/aggregate` | `evaluations:read` | 对过滤后的数据集进行汇总统计:总数、done/error/timeout 分布、各评分键的统计指标(在任意 `scores` 键上计算 count/avg/min/max/p50)以及按时间分桶的趋势数据。接受与 `/evaluations` 相同的过滤参数,另外支持 `featured_keys`(评分键的 CSV 列表,用于趋势展示)和 `latest_per_session`。为仪表盘功能提供数据支持;指标在整个匹配数据集上精确计算,不进行采样。 | +| `GET` | `/evaluations/environments` | `evaluations:read` | 返回 `evaluations` 表中所有不同的 environment 值,用于填充评估数据范围内的过滤下拉框。 | +| `GET` | `/evaluation-jobs` | `evaluations:read` | 查看进行中的评估任务。可按 `status`(`pending`/`polling`)过滤。 | +| `GET` | `/events` | `events:read` | 流式获取会话的原始事件。支持以下参数:`session_id`、`agent_id`、`event_type`(CSV)、`environment`(CSV)、`ts_from`、`ts_to`、`cursor`、`limit`、`order`。`order` 为 `desc`(最新优先,默认)或 `asc`(最旧优先);不识别的值回退为 `desc`。通过响应中的 `next_cursor`(事件 id)进行游标分页:将其作为 `cursor` 传入可获取下一页;`asc` 模式下返回该 id 之后的事件,`desc` 模式下返回该 id 之前的事件。`limit` 默认为 50,上限为 1000。 | +| `GET` | `/sessions/:session_id/export` | `events:read` | 返回评估服务针对该会话所接收的完整 JSON 请求体,以名为 `session-.json` 的可下载附件形式提供。适用于将生产环境会话通过 `agenteye-evaluator` 进行离线回放测试。返回的字节与评估管道实际发送的内容完全一致。 | +| `POST` | `/sessions/:session_id/re-evaluate` | `evaluations:trigger` | 为会话入队一次新的评估任务;无论之前是否已有评估结果均可触发。新结果将**追加**至会话的评估时间线,而非覆盖之前的结果,历史评分仍可查看。入队成功返回 `202`,会话不存在返回 `404`,已有评估任务进行中返回 `409`。适用于部署新评估服务后的重新评估,或对从未发出 `agent_end` 的会话进行手动评估。 | + +### 按分数范围过滤:`score_filters` + +`GET /evaluations` 接受可选的 `score_filters` 参数,可根据 `scores` 对象中的数值进行精确筛选。该参数为逗号分隔的 `key:min..max` 条目列表;上下界均可省略。多个条目以逻辑与(AND)方式组合。指定键不存在或值非数字的记录将被排除。单次请求最多支持 20 个过滤条目,超出时返回 HTTP 400。 + +示例: +```text +# helpfulness 在 [0.5, 0.8] 范围内 +GET /evaluations?score_filters=helpfulness:0.5..0.8 + +# tool_efficiency 不超过 0.3(无下界) +GET /evaluations?score_filters=tool_efficiency:..0.3 + +# helpfulness >= 0.5 且 factuality >= 0.9 +GET /evaluations?score_filters=helpfulness:0.5..,factuality:0.9.. +``` + +每个 `/evaluations` 响应对象包含以下字段: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `evaluation_id` | string (UUID) | 本次终态评估的规范标识符。每次终态评估生成一个新的 UUID;单个会话可包含多个。 | +| `id` | string (UUID) | 向后兼容别名,值与 `evaluation_id` 相同。 | +| `session_id` | string | 本次评估所对应的会话。一个会话在时间线中可有多次评估记录。 | +| `agent_id` | string | 产生该会话的 agent 标识。 | +| `environment` | string | 从会话复制的环境标签。 | +| `status` | enum | `"done"`、`"error"`、`"timeout"` 之一。 | +| `scores` | object \| null | 评估服务返回的评分。 | +| `reasoning` | object \| null | 评估服务返回的可选评分维度解释映射,键通常与 `scores` 中的键对应。仪表盘在每个评分条下方渲染对应内容。 | +| `summary` | string \| null | 评估服务返回的可选整体总结段落。仪表盘在各评分细目上方将其作为评估结果的主标题显示。 | +| `error` | string \| null | 仅在 `"error"` / `"timeout"` 状态时填充。 | +| `attempt_count` | integer | 派发尝试次数(≥ 1)。 | +| `duration_ms` | integer \| null | 最后一次尝试的耗时。 | +| `completed_at` | string (ISO 8601 UTC) | 终态结果记录的时间。结果按 `completed_at` 降序排列(最新在前)。 | +| `created_at` | string (ISO 8601 UTC) | 与 `completed_at` 时间戳相同(一次性写入语义)。 | + +--- + +## 权限 + +| 权限 | 授权范围 | +|---|---| +| `evaluations:read` | 查看评估结果、在仪表盘中查看评分、加载仪表盘健康指标。 | +| `evaluations:trigger` | 通过 `POST /sessions/:session_id/re-evaluate` 或仪表盘的重新评估按钮,手动为会话入队评估任务。 | +| `dashboards:read` | 查看已保存的仪表盘(同时需要 `evaluations:read` 权限才能加载指标数据)。 | +| `dashboards:write` | 创建和编辑仪表盘。 | +| `dashboards:delete` | 删除仪表盘。 | + +引导管理员(`ADMIN_KEY`、`ADMIN_EMAIL`)自动获得上述所有权限。 + +--- + +## 查看结果 + +- **`/sessions/`**:事件时间线 + 右侧面板,显示会话评分及派发尝试中的错误信息。若您的密钥具有 `evaluations:trigger` 权限,导出按钮旁将出现**重新评估**按钮,适用于从未发出 `agent_end` 的会话,或在部署新评估服务后刷新评分。仪表盘会轮询新结果,在结果返回时更新右侧面板。 +- **`/sessions`**:可过滤的会话列表;评分列一目了然地显示每个会话的评估状态和评分。 +- **`/dashboards`**:已保存的评估健康视图(详见下方[仪表盘](#dashboards)章节)。 + +![会话列表,显示每个会话的评估状态标签和颜色编码的评分徽章(helpfulness、factuality、tool_efficiency、safety、coherence)](/agenteye/images/sessions-list.png) + +*会话列表一目了然地展示每次运行的评估状态和评分;红/黄/绿徽章使低分一眼可辨。* + +![会话详情页,右侧面板显示评估评分和派发状态](/agenteye/images/session-detail.png) + +*打开会话后,完整时间线与评估评分及派发器错误信息同时显示在右侧面板中。* + +--- + +## 仪表盘 + +**仪表盘**页面(`/dashboards`)允许您将评估过滤条件组合保存为具名可复用视图,一目了然地监控该评估数据切片的整体状况。仪表盘在**整个组织内共享**,所有具有 `dashboards:read` 权限的用户可看到相同的内容。 + +每个仪表盘固定以下配置: + +- **过滤条件**:与会话页面相同的控件,包括环境、状态、agent、滚动时间窗口和分数范围过滤器(`key:min..max`)。 +- **展示配置**:选择要展示的评分键、绿/黄/红健康阈值、显示哪些面板,以及是否折叠为每个会话的最新评估结果。 + +每张卡片显示匹配的会话数、done/error/timeout 分布、各展示评分的平均值,以及一个小型趋势迷你图。打开仪表盘后可查看完整大图面板;点击**在会话页面打开**可跳转至会话页面并预置对应的过滤条件。指标通过 `GET /evaluations/aggregate` 在服务端对全量匹配数据集精确计算,结果不进行采样。 + +![评估健康仪表盘,包含各评估维度的平均分条形图、工具成功/失败分布、热门工具列表及每小时事件量趋势](/agenteye/images/dashboard-quality.png) + +**权限说明:** 查看需要同时具备 `dashboards:read` 和 `evaluations:read`;创建和编辑需要 `dashboards:write`;删除需要 `dashboards:delete`。引导管理员自动获得所有上述权限。 + +--- + +## 故障排查 + +**会话已存在但未生成任何评估结果。** 请确认 `EVALUATOR_ENDPOINT` 已在服务器进程上设置,服务器与评估服务使用相同的 `EVALUATOR_TOKEN` 值,且评估服务的 `/health` 端点可从服务器正常访问。未设置 `EVALUATOR_ENDPOINT` 时评估管道为空操作。 + +**进行中的评估任务大量积压。** 通过 `GET /evaluation-jobs` 查看进行中的任务队列。检查每条记录上的 `attempt_count`、`next_attempt_at` 和 `last_error`。常见原因:评估服务不可达或持续返回 5xx(将以退避方式重试)、`EVALUATOR_TOKEN` 错误(401 为终态错误),或异步评估服务持续返回 `pending`(见下文)。 + +**会话已完成但无终态评估结果。** 执行 `GET /evaluation-jobs?status=polling` 查询;任务可能仍在进行中。若任务卡在 `pending` 状态,说明服务器无法正常访问评估服务;请检查评估服务是否正常运行以及 `EVALUATOR_TOKEN` 是否匹配。 + +**`HTTP 401 from evaluator: invalid bearer token`。** 服务器上的 `EVALUATOR_TOKEN` 与评估服务配置的值不一致,两者必须完全相同。 + +**异步评估服务持续返回 `pending`。** 服务器将持续轮询 `GET /evaluate/{job_id}`,直至评估服务返回 `done` 或 `error`,或达到 `EVALUATOR_MAX_POLL_DURATION_SECS` 上限(默认 1 小时)。超过上限后,评估结果记录为 `timeout` 并从进行中队列中移除。若您的评估服务合理地需要超过默认时长,请适当增大 `EVALUATOR_MAX_POLL_DURATION_SECS`。 \ No newline at end of file diff --git a/docs/zh/agenteye/getting-started.mdx b/docs/zh/agenteye/getting-started.mdx new file mode 100644 index 00000000..2663911d --- /dev/null +++ b/docs/zh/agenteye/getting-started.mdx @@ -0,0 +1,235 @@ +--- +title: "AgentEye 入门指南" +description: "AgentEye 入门指南文档。" +--- + + +本指南将带您完成 AgentEye 的完整配置流程:部署服务端与控制台、在智能体机器上安装收集器,以及为您的 Python 智能体代码添加埋点。 + +--- + +## 什么是 AgentEye? + +AgentEye 是一款**面向 AI 智能体的自托管可观测性与评估平台**。它记录智能体的每一个动作——运行过程中的每一步——并自动对每次已完成的运行质量进行评分,帮助您掌握智能体在生产环境中的行为,在用户发现问题之前提前捕获性能退化。 + +数据按单一方向流动:您的智能体代码通过 **Python SDK** 发送**事件** → 轻量级**收集器**守护进程批量将其上报至**服务端** → 事件与分析数据存储在 **ClickHouse** 中(组织、用户、API 密钥、控制台、保存的查询等运营状态存储在 **Postgres** 中)→ 您在**控制台**中浏览所有数据。 + +您将获得: + +- **事件** — 每次智能体运行的原始逐步记录(工具调用、模型调用、钩子、错误)。 +- **会话** — 将事件聚合为每次运行一行,每行均经过**自动评估与评分**。 +- **评估** — 由您自己的评估服务生成的质量分数,无需人工审查即可发现质量下滑。 +- **查询与控制台** — 基于 ClickHouse SQL 对数据进行保存查询,并绘制为组织范围内的共享控制台。 +- **告警与事件** — 当指标超过阈值时通知您(邮件、Slack、Webhook、控制台内通知),并提供事件处理工作流。 +- **CLI 与 AI 助手** — 终端客户端(`agenteye`)以及控制台内的助手,支持用自然语言提问。 + +所有组件均运行在您自己的基础设施上,可以作为单个 Docker Compose 栈(本指南)、生产级 Kubernetes 安装,或单个同地部署的 Pod。本指南将从头到尾搭建 Compose 栈。 + +--- + +## 第一步:认证 + +所有 AgentEye 制品均通过 `agenteye-enterprise` GitHub 组织分发。作为企业开发者,您可以生成自己的 GitHub PAT。请参阅 [enterprise-docs/github-token.md](/zh/agenteye/github-token) 了解详细步骤和所需权限。 + +```bash +export AGENTEYE_TOKEN= + +# Authenticate Docker against GHCR +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +--- + +## 第二步:部署服务端与控制台 + +服务端接收来自收集器的事件并使其可查询;控制台是您浏览数据的界面。摄入的事件与分析数据存储在 ClickHouse(必需的分析存储)中,Postgres 则保存运营状态,如组织、用户、API 密钥、控制台和保存的查询。 + +**下载发布的 Compose 文件:** + +```bash +mkdir -p ./agenteye +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + https://raw.githubusercontent.com/agenteye-enterprise/releases/main/docker-compose.yml \ + -o ./agenteye/docker-compose.yml +cd agenteye +``` + +**设置密钥:** + +创建 `.env` 文件,确保部署不使用默认的 `admin` 凭据。至少需要设置 `ADMIN_KEY` 和 `POSTGRES_PASSWORD`: + +```bash +POSTGRES_PASSWORD=your-db-password +ADMIN_KEY=your-admin-secret +``` + +同时在当前 Shell 中导出 `ADMIN_KEY`,以便后续步骤(如第三步的 `curl`)可以直接引用: + +```bash +export ADMIN_KEY=your-admin-secret +``` + +**启动服务栈:** + +```bash +docker compose up -d +``` + +这将启动完整的服务栈,包括必需的 ClickHouse 分析存储、可选的 Redis 缓存,以及服务端和控制台。服务端启动前 ClickHouse 必须处于健康状态。 + +服务端现在监听 `http://localhost:8080`,控制台监听 `http://localhost:3000`。 + +如需生产部署(自定义 Postgres、TLS、反向代理),请参阅 [enterprise-docs/deployment.md](/zh/agenteye/deployment)。 + +--- + +## 第三步:为收集器创建 API 密钥 + +每个收集器使用有范围限制的 API 密钥进行认证。使用第二步中设置的 `ADMIN_KEY` 创建一个: + +```bash +curl -s -X POST http://localhost:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{"name":"prod-collector","key":"your-collector-secret","permissions":["events:add"]}' +``` + +`key` 值由您自行提供,在第四步的收集器配置中使用。完整的密钥管理说明请参阅 [enterprise-docs/api-keys.md](/zh/agenteye/api-keys)。 + +--- + +## 第四步:安装收集器 + +在运行 AI 智能体的每台机器上安装收集器守护进程。 + +**下载二进制文件(Linux x86_64):** + +```bash +VERSION=0.0.1-beta.13 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "collector/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-collector-linux-x86_64' +chmod +x agenteye-collector-linux-x86_64 +sudo mv agenteye-collector-linux-x86_64 /usr/local/bin/agenteye-collector +``` + +> 上述命令下载的是 **Linux x86_64** 构建版本。如需 macOS(Apple Silicon 或 Intel)、Linux arm64,或 Docker / systemd / launchd 安装方式,请参阅 [collector-installation.md](/zh/agenteye/collector-installation),其中列出了各平台的下载链接——以上命令安装的是 Linux 二进制文件,无法在其他平台上运行。 + +**配置:** + +```bash +mkdir -p ~/.agenteye +cat > ~/.agenteye/config.json </…`)。 + +- **查询**(`//queries`):从针对事件和评估数据的可复用查询库中出发(包含内置预设和您自定义的查询)…… + +![保存的查询库:可复用查询的网格视图,包含内置预设和自定义查询](/agenteye/images/queries.png) + + ……然后在 SQL 编辑器中打开某个查询,进行调整并实时查看运行结果: + +![SQL 查询编辑器正在运行一条保存的查询,左侧为 Schema 侧边栏,右侧为实时结果表格](/agenteye/images/query-lab.png) + +- **控制台**(`//dashboards`):将查询以折线图、柱状图、面积图或饼图的形式固定为图块,组成在整个组织范围内共享的控制台。 + +![由保存的查询构建的控制台:每小时事件数折线图、按类型分类的错误柱状图、延迟面积图和按模型统计的 Token 数](/agenteye/images/dashboard-fleet.png) + +- **告警**(`//alerts`):将任何阈值提升为告警规则,通过邮件、Slack、Webhook 或控制台内通知进行提醒。请参阅 [enterprise-docs/alerts.md](/zh/agenteye/alerts)。 + +--- + +## 后续步骤 + +- [部署](/zh/agenteye/deployment):为生产环境加固 +- [API 密钥](/zh/agenteye/api-keys):管理访问权限 +- [故障排查](/zh/agenteye/troubleshooting):诊断问题 \ No newline at end of file diff --git a/docs/zh/agenteye/github-token.mdx b/docs/zh/agenteye/github-token.mdx new file mode 100644 index 00000000..5ef451bf --- /dev/null +++ b/docs/zh/agenteye/github-token.mdx @@ -0,0 +1,131 @@ +--- +title: "GitHub Token 配置" +description: "AgentEye GitHub Token 配置文档。" +--- + +GitHub 个人访问令牌(PAT)是解锁所有 AgentEye 资源的唯一凭证。使用一个令牌,您即可拉取 Docker 镜像、下载发布版二进制文件并安装 Python wheel 包,无需对各组件分别登录,也无需在团队内传递共享密钥。所有 AgentEye 资源均通过 `agenteye-enterprise` GitHub 组织分发;一旦您的组织获得访问权限,每位开发者或运维人员可自行生成并轮换各自的令牌,从而实现按人可审计、可撤销的访问控制。 + +在每台机器上,将令牌设置为环境变量并配置 Docker 凭证: + +```bash +export AGENTEYE_TOKEN= +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +> **用户名说明:** GHCR 会忽略 `docker login` 中的用户名,完全依赖令牌进行认证,因此任意非空值均可使用。本文档使用 `-u x` 以保持简洁;在创建 Kubernetes 镜像拉取密钥的部署清单中,可使用更具描述性的用户名,例如 `agenteye-enterprise`。两种写法均可接受。 + +--- + +## 方案 A:经典令牌(推荐) + +经典令牌是 AgentEye 最可靠的选择,因为 GHCR 的 `docker login` 和镜像拉取流程对经典令牌的支持最为全面且稳定。两个权限范围即可覆盖所有需求(拉取镜像和下载发布资源),一次认证即可完成,无需排查注册表的各种异常。其中 `read:packages` 是真正意义上的只读权限;而 `repo` 是唯一能够访问私有发布资源的经典权限范围,其定义本身较为宽泛——GitHub 将其定义为对私有仓库的完全控制权(读写权限)。 + +### 1. 创建令牌 + +前往 **GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic) → Generate new token (classic)**。 + +| 字段 | 值 | +|---|---| +| **Note** | `agenteye-<机器名或团队名>`(例如 `agenteye-prod-server`) | +| **Expiration** | 根据您的安全策略设置有效期;90 天是合理的默认值 | + +> **标签说明:** GitHub 对经典令牌将此字段标记为 **Note**,对细粒度令牌标记为 **Token name**。两者用途相同:作为便于后续审计和撤销的可读标识符。 + +### 2. 选择权限范围 + +| 权限范围 | 用途说明 | +|---|---| +| `read:packages` | 从 `ghcr.io/agenteye-enterprise/` 拉取 Docker 镜像及下载包资源 | +| `repo` | 读取 `agenteye-enterprise/releases` 中的私有仓库内容、原始文件及发布资源。这是 GitHub 宽泛的"完全控制私有仓库"范围(读写权限),并非只读范围——它只是唯一能授予私有发布资源访问权限的经典范围 | + +无需其他权限范围。 + +### 3. 生成并复制令牌 + +点击 **Generate token** 并立即复制令牌值;该值仅显示一次。请将其存储至您的密钥管理器或环境变量中。 + +--- + +## 方案 B:细粒度令牌 + +细粒度令牌可将访问范围限定在特定仓库和权限上,是最严格的最小权限选项。当您的组织安全策略要求使用细粒度令牌时,请选择此方案。 + +> **注意:** GHCR 对细粒度令牌的支持不如经典令牌稳定。如果按照以下步骤操作后 `docker login` 或 `docker pull` 失败,请回退至经典令牌(方案 A)。 + +### 1. 创建令牌 + +前往 **GitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokens → Generate new token**。 + +| 字段 | 值 | +|---|---| +| **Token name** | `agenteye-<机器名或团队名>`(例如 `agenteye-prod-server`) | +| **Expiration** | 根据您的安全策略设置有效期;90 天是合理的默认值 | +| **Resource owner** | `agenteye-enterprise` | +| **Repository access** | **Only select repositories** → `agenteye-enterprise/releases` | + +### 2. 设置仓库权限 + +在 **Permissions → Repository permissions** 下,进行如下设置: + +| 权限 | 访问级别 | +|---|---| +| **Contents** | Read-only | +| **Packages** | Read-only | + +其他所有权限可保持 **No access**。 + +> **注意:** 如果容器镜像(`ghcr.io/agenteye-enterprise/...`)作为组织级包而非仓库关联包发布,仅使用仓库范围的权限可能导致 Docker 登录失败。在这种情况下,请添加组织级权限:**Permissions → Organization permissions → Packages: Read-only**。 + +### 3. 各权限说明 + +| 权限 | 用途 | +|---|---| +| Contents: Read-only | 从 `agenteye-enterprise/releases` 下载 `docker-compose.yml`、发布版二进制文件及 Python wheel 包 | +| Packages: Read-only | 从 `ghcr.io/agenteye-enterprise/` 拉取 Docker 镜像 | + +### 4. 生成并复制令牌 + +点击 **Generate token** 并立即复制令牌值;该值仅显示一次。请将其存储至您的密钥管理器或环境变量中。 + +--- + +## 轮换令牌 + +定期轮换令牌可保持访问的可审计性,并在凭证泄露时将影响范围降至最低。令牌也可能随时过期或被撤销,因此轮换是保持认证有效的常规方式。轮换步骤如下: + +1. 按照上述步骤生成新令牌。 +2. 在您的环境变量或密钥管理器中更新 `AGENTEYE_TOKEN`。 +3. 重新进行 Docker 认证:`echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin` +4. 在 GitHub → Settings → Developer settings → Personal access tokens 中撤销旧令牌,打开与令牌类型对应的 **Tokens (classic)** 或 **Fine-grained tokens** 子页面,将其删除。 + +--- + +## 验证令牌 + +在将令牌接入部署流程之前,请先确认其可正常使用,以便认证问题在此阶段暴露,而非在发布过程中出现。以下每条命令分别验证上述其中一个权限范围: + +```bash +# Packages scope - authenticate Docker against GHCR +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin + +# Contents scope - fetch a raw release file +curl -fsSL \ + -H "Authorization: token $AGENTEYE_TOKEN" \ + https://raw.githubusercontent.com/agenteye-enterprise/releases/main/docker-compose.yml \ + -o /tmp/agenteye-compose-check.yml +``` + +`docker login` 成功即表示包权限范围有效;文件下载成功即表示内容权限范围有效。 + +--- + +## 故障排查 + +| 现象 | 可能原因 | 解决方法 | +|---|---|---| +| `docker login` 返回 401 | 令牌缺少 `Packages: Read-only`(细粒度)或 `read:packages`(经典)权限 | 添加包权限范围并重新生成令牌 | +| `curl` 请求原始 GitHub URL 返回 404 | 令牌缺少 `Contents: Read-only` 或 `repo` 权限范围 | 添加内容权限范围并重新生成令牌 | +| `gh release download` 返回 403 | 令牌未获授权访问 `agenteye-enterprise/releases` | 确认该仓库已包含在细粒度令牌的仓库访问范围内,或改用带有 `repo` 范围的经典令牌 | +| 令牌被接受但找不到镜像 | 细粒度令牌缺少组织级包权限 | 添加组织级 `Packages: Read-only` 权限 | + +如遇访问问题,请联系 `support@exosphere.host`。 \ No newline at end of file diff --git a/docs/zh/agenteye/health-monitoring.mdx b/docs/zh/agenteye/health-monitoring.mdx new file mode 100644 index 00000000..36b0d304 --- /dev/null +++ b/docs/zh/agenteye/health-monitoring.mdx @@ -0,0 +1,87 @@ +--- +title: "健康监控" +description: "AgentEye 健康监控文档。" +--- + +了解 AgentEye 部署本身何时**出现故障或性能下降**,而不仅仅是监测代理行为异常。检测机制**原生支持 Kubernetes**,更重要的是,它**独立于 AgentEye**:通过 Kubernetes 控制平面读取 Pod 状态,并检查 AgentEye 的强依赖项,因此即使服务器、ClickHouse 或 Postgres 本身发生故障,告警依然能够触发。 + +系统分为两层:第一层为内置功能,第二层为可选功能。 + +## 1. 感知依赖的就绪探针(内置) + +服务器暴露两个探针端点,各司其职: + +| 端点 | 探针类型 | 检查内容 | 鉴权 | +|---|---|---|---| +| `GET /health` | 存活探针 | 进程是否存活(始终返回 `{"status":"ok"}`) | 无 | +| `GET /ready` | 就绪探针 | 能否正常提供服务:**Postgres + ClickHouse** 是否可达 | 无 | + +当两个强依赖项均可达时,`/ready` 返回 `200`,响应体中 `"status":"ready"` 且所有检查项均为 `"ok"`;若任一依赖不可达,则返回 `503`,`"status":"not_ready"`。两种响应均携带如下格式的响应体: + +```json +{ "status": "not_ready", + "checks": { "postgres": "ok", "clickhouse": "down", "redis": "not_configured" } } +``` + +Redis 是可选缓存组件,服务器在其不可用时仍可降级运行,因此 Redis 状态仅作参考,**不会**影响就绪判断。配置了缓存时显示 `"ok"`,未配置时显示 `"not_configured"`,永远不会出现 `"down"`。 + +在随附的 Kubernetes 清单中,**就绪探针**指向 `/ready`,**存活探针**保持指向 `/health`。效果如下:一个*正在运行但无法连接数据库*的服务器会被从 Service 中摘除,并显示为 `NotReady` 状态,集群监控系统(见下文)可对此发出告警;而存活探针保持轻量,短暂的依赖波动不会触发 Pod 重启。探针配置了较宽松的失败阈值,避免瞬间抖动导致副本频繁进出轮换。 + +## 2. 使用 Robusta 进行 Pod 故障告警(可选) + +[Robusta](https://github.com/robusta-dev/robusta) 是一个 Kubernetes 原生监控工具,监听 API Server 并将 Pod 故障(`CrashLoopBackOff`、`OOMKilled`、`ImagePullBackOff`、`Pending`/`NotReady`、`Failed`、驱逐等)推送至 Slack。由于它直接观察控制平面而非查询 AgentEye,即使 AgentEye 完全不可用时依然能发出告警。 + +Robusta 作为可选附加组件随发布包提供。使用标准 Robusta Helm Chart 和以下 values 文件启用: + +1. 添加 Chart 仓库,并为目标频道准备好 Slack **Bot Token**(`xoxb-…`): + + ```bash + helm repo add robusta https://robusta-charts.storage.googleapis.com + helm repo update + ``` + + 由于以下配置将所有流量保持在集群内(`disableCloudRouting: true`),Token 需来自自托管的 Slack 应用:在 `https://api.slack.com/apps` 创建应用,添加 `chat:write` Bot 权限范围,将其安装到工作区,复制 **Bot User OAuth Token**(`xoxb-…`),并将 Bot 邀请到对应频道(`/invite @your-app`)。 + +2. 创建 `values.yaml`,填入每个部署的标识标签(`clusterName`)和 Slack 频道,并将范围限定在 `agenteye` 命名空间: + + ```yaml + clusterName: "acme-prod" # 每个部署的唯一标签,出现在所有告警中 + enablePrometheusStack: false # 仅 Pod 崩溃告警,不启用指标栈 + disableCloudRouting: true # 直接在集群内推送至 Slack + sinksConfig: + - slack_sink: + name: vendor_slack + slack_channel: "agenteye-fleet-health" + api_key: "REPLACE_WITH_SLACK_BOT_TOKEN" # xoxb-…(建议使用 --set 或 Secret) + scope: + include: + - namespace: [agenteye] # 仅推送 AgentEye 命名空间的告警,删除此项可扩大范围 + ``` + +3. 安装时固定 `--version` 为已知稳定的 Robusta Chart 版本([发布列表](https://github.com/robusta-dev/robusta/releases)),避免安装未经测试的 Chart: + + ```bash + helm install robusta robusta/robusta \ + --namespace robusta --create-namespace \ + --version \ + -f values.yaml \ + --set sinksConfig[0].slack_sink.api_key=$ROBUSTA_SLACK_TOKEN + ``` + +### 告警内容 + +- Kubernetes **Pod 状态**(哪个 AgentEye Pod 出现故障及原因)以及每个 Pod 的**镜像标签**(即运行中组件的**版本**)。 +- **不会有任何 AgentEye 事件数据或客户数据**离开集群。 +- 随附的 values 文件将告警范围限制在 **`agenteye` 命名空间**,同一集群中的其他工作负载不会被上报。 + +### 统一管理所有部署 + +将每个部署的 Robusta 都指向**同一个共享 Slack 频道**,每个部署使用各自的 `clusterName`。所有告警都会带上该标签,因此一个频道即可掌握整个集群群的健康状态,一眼便能看出是哪个部署出现了问题。 + +### 整个集群中断 + +纯集群内部的监控工具**无法上报整个集群或网络中断**(因为它会随集群一起宕机)。如果需要此类能力,请启用可选的 **Robusta UI Sink**:将 `disableCloudRouting` 设为 `false`,并在 `sinksConfig` 中添加 `robusta_sink`(Token 通过 `robusta gen-config` 获取)。这将提供一个聚合的多集群仪表盘,并标记任何停止上报心跳的集群。 + +## 故障排查 + +请参阅 [enterprise-docs/troubleshooting.md](/zh/agenteye/troubleshooting) 中的**健康监控**章节,了解"告警未送达"和"服务器持续 `NotReady` 抖动"等问题的处理方法。 \ No newline at end of file diff --git a/docs/zh/agenteye/kubernetes-deployment.mdx b/docs/zh/agenteye/kubernetes-deployment.mdx new file mode 100644 index 00000000..7bd511a1 --- /dev/null +++ b/docs/zh/agenteye/kubernetes-deployment.mdx @@ -0,0 +1,1031 @@ +--- +title: "Kubernetes 部署指南" +description: "AgentEye Kubernetes 部署指南文档。" +--- + + +本指南将 AgentEye 完整技术栈部署到专用 Kubernetes 集群: + +- **ClickHouse 24.8** —— 事件与评估分析的核心存储(StatefulSet,配备 100Gi 持久卷)。必须组件:缺少此组件服务器将拒绝启动。 +- **PostgreSQL 16** —— 组织、API 密钥、用户、仪表盘、保存的查询及身份验证的关系型/元数据存储(StatefulSet,配备 50Gi 持久卷) +- **Redis 7.2** —— 可选的共享缓存与限速后端;服务器和仪表盘在其不可用时仍可降级运行 +- **AgentEye Server** —— 用于事件摄入、分析和密钥管理的 Rust API(2 个副本) +- **AgentEye Dashboard** —— Next.js Web 界面(2 个副本) +- **AI 助手(agent 服务)** —— 可选的仪表盘内只读助手,监听端口 9100;在配置 LLM 端点之前保持静默 +- **Traefik(公网)** —— 用于收集器流量的入口控制器,启用 mTLS 保护 +- **Traefik(仪表盘)** —— 用于仪表盘的入口控制器,仅限 VPN/IP 白名单访问 +- **cert-manager** —— TLS 证书及 mTLS CA 管理 +- **备份 CronJob** —— 每日 UTC 03:00 同时备份 PostgreSQL 和 ClickHouse +- **证书续期监控** —— 在客户端证书临近过期时发出告警 + +**预计耗时:** 首次部署约 60--90 分钟。 + +如需了解由 Exosphere 代为处理所有事项的托管部署模式,请参阅 [enterprise-docs/managed-deployment.md](/zh/agenteye/managed-deployment)。 + +--- + +## 前置条件 + +在开始之前,请逐一执行以下验证命令,所有检查必须全部通过。 + +| 要求 | 最低版本 | 验证命令 | 预期结果 | +|---|---|---|---| +| Kubernetes 集群 | 1.27+ | `kubectl version` | Server Version >= v1.27 | +| Kustomize(随 kubectl 内置) | Kustomize v1.14+(随 kubectl 1.27+ 内置) | `kubectl kustomize --help` | 打印使用说明 | +| Helm | v3 | `helm version` | `Version:"v3.x.x"` | +| cluster-admin RBAC | -- | `kubectl auth can-i create namespaces` | `yes` | +| 默认 StorageClass | -- | `kubectl get storageclass` | 至少一行标记为 `(default)` | +| LoadBalancer 支持 | -- | 依赖云平台(EKS、GKE、AKS 均默认支持) | -- | +| GitHub PAT | -- | `echo $AGENTEYE_TOKEN` | 非空值(参见 [enterprise-docs/github-token.md](/zh/agenteye/github-token)) | +| openssl | -- | `openssl version` | OpenSSL 1.x 或 3.x | +| 云存储桶 | -- | 用于 PostgreSQL 和 ClickHouse 备份(S3、GCS 或 Azure Blob) | -- | + +**集群规格:** 最少 3 个节点,每个节点 4 vCPU / 8 GB 内存。完整要求请参阅 [enterprise-docs/managed-deployment.md](/zh/agenteye/managed-deployment)。 + +### 一次性执行所有检查 + +```bash +echo "--- Prerequisites Check ---" +kubectl version --client -o yaml 2>/dev/null | grep -q gitVersion && echo "PASS: kubectl" || echo "FAIL: kubectl not found" +helm version --short 2>/dev/null | grep -q v3 && echo "PASS: helm v3" || echo "FAIL: helm v3 not found" +kubectl auth can-i create namespaces 2>/dev/null | grep -q yes && echo "PASS: cluster-admin" || echo "FAIL: no cluster-admin" +kubectl get storageclass 2>/dev/null | grep -q default && echo "PASS: default StorageClass" || echo "FAIL: no default StorageClass" +[ -n "$AGENTEYE_TOKEN" ] && echo "PASS: AGENTEYE_TOKEN set" || echo "FAIL: AGENTEYE_TOKEN not set" +openssl version >/dev/null 2>&1 && echo "PASS: openssl" || echo "FAIL: openssl not found" +echo "---" +``` + +### 部署架构说明 + +**采集端点** 由您控制的域名提供服务(例如 `ingest.your-company.example`)。cert-manager 通过 HTTP-01 方式向 Let's Encrypt 申请公开受信任的 TLS 证书,因此收集器会使用系统信任库验证服务器证书,无需每个客户端单独固定 CA。 + +**仪表盘端点** 工作方式相同:由您控制的另一个域名提供服务(例如 `agenteye.your-company.example`),指向仪表盘 Traefik LoadBalancer,cert-manager 通过该 LoadBalancer 颁发 Let's Encrypt 证书。浏览器访问时将获得受信任的证书,不会出现警告。 + +> **证书颁发和续期通过 HTTP-01 验证**,因此两个 LoadBalancer 必须能从公网访问 80 端口。如需对仪表盘 LoadBalancer 进行 IP 限制,请先与支持团队协调配置 DNS-01 解析器,否则续期将静默失败并导致证书过期。 + +--- + +## 获取清单文件 + +```bash +git clone https://x:${AGENTEYE_TOKEN}@github.com/agenteye-enterprise/releases.git +cd releases/deploy +``` + +**验证:** + +```bash +ls base/kustomization.yaml +``` + +预期:文件存在。若不存在,说明克隆失败——请检查您的 `AGENTEYE_TOKEN`。 + +**目录结构:** + +``` +deploy/ + base/ 共享 Kustomize base(所有 K8s 资源) + overlays/ 特定集群的覆盖配置(镜像标签、主机名、资源限制) + third-party/ Traefik、cert-manager 及(可选)Robusta 健康监控的 Helm values 文件 +``` + +**base** 包含完整部署所需的所有资源,包括您在第 3.1 阶段配置的两个公开域名所需的 Let's Encrypt 证书。**overlay** 针对特定环境(如自定义镜像标签、资源限制、环境变量配置)对 base 进行补丁。**third-party** 目录包含外部基础设施的 Helm values 文件。 + +> **健康监控(可选):** 服务器的就绪探针已反映 Postgres 和 ClickHouse 的健康状态,`third-party/robusta/` 提供可选的 Kubernetes 原生 Pod 故障告警(发送到 Slack)。参见 [enterprise-docs/health-monitoring.md](/zh/agenteye/health-monitoring)。 + +--- + +## 第一阶段 —— 部署第三方基础设施(约 30 分钟) + +### 1.1 安装 cert-manager + +cert-manager 管理 HTTPS 所需的 TLS 证书,以及用于签发 mTLS 客户端证书的私有 CA。 + +```bash +helm repo add jetstack https://charts.jetstack.io +helm repo update + +helm install cert-manager jetstack/cert-manager \ + --namespace cert-manager --create-namespace \ + --set crds.install=true +``` + +**验证:** + +```bash +kubectl get pods -n cert-manager +``` + +预期:3 个 Pod 均处于 `Running` 状态——`cert-manager`、`cert-manager-cainjector`、`cert-manager-webhook`。 + +```bash +kubectl get crds | grep cert-manager +``` + +预期:至少包含 `certificates.cert-manager.io`、`clusterissuers.cert-manager.io`、`issuers.cert-manager.io`。 + +**排障:** Pod 处于 `CrashLoopBackOff` 通常意味着 CRD 未安装。请重新执行并添加 `--set crds.install=true`。若 webhook Pod 未通过就绪检查,请等待 30 秒后重试——它们启动可能需要一点时间。 + +--- + +### 1.2 安装 Traefik —— 公网采集入口控制器 + +此 Traefik 实例通过**外部** LoadBalancer 处理收集器流量。它负责 TLS 终止,并在采集端点上强制执行 mTLS(客户端证书验证)。 + +```bash +helm repo add traefik https://traefik.github.io/charts +helm repo update + +helm install traefik-public traefik/traefik \ + --namespace traefik-public --create-namespace \ + --version 39.0.8 \ + -f third-party/traefik/values-public.yaml +``` + +**验证:** + +```bash +kubectl get pods -n traefik-public +``` + +预期:1 个 Pod 处于 `Running` 状态。 + +```bash +kubectl get ingressclass traefik-public +``` + +预期:IngressClass 存在(非默认 class)。 + +**排障:** 执行 `kubectl describe pod -n traefik-public ` 检查镜像拉取错误或资源限制问题。 + +--- + +### 1.3 安装 Traefik —— 仪表盘入口控制器 + +此 Traefik 实例通过专用 LoadBalancer 提供仪表盘服务,并通过 IP 白名单进行访问限制。 + +> **该实例提供两种白名单机制。** 本指南使用 `values-dashboard.yaml`,通过可移植的 `service.loadBalancerSourceRanges` 字段限制访问。同时提供了 `values-internal.yaml`,适用于偏好使用 `service.beta.kubernetes.io/aws-load-balancer-source-ranges` 注解的 AWS 环境。两者选其一并保持一致;以下步骤基于 `values-dashboard.yaml`。 + +**安装前**,请编辑 `third-party/traefik/values-dashboard.yaml` 以设置允许的源 IP。`loadBalancerSourceRanges` 字段控制哪些 IP 可以访问仪表盘。默认值为 `0.0.0.0/0`(所有 IP);请将其限制为您的 VPN、办公室或已知出口 IP。 + +#### 白名单单个 IP + +```yaml +service: + loadBalancerSourceRanges: + - "/32" +``` + +#### 白名单多个 IP + +每行添加一个 IP 或 CIDR 块。`/32` 后缀匹配单个 IPv4 地址;CIDR 块(如 `/24`)匹配一个地址范围。可以自由混合单个 IP 和范围: + +```yaml +service: + loadBalancerSourceRanges: + - "203.0.113.10/32" # 办公室网关 + - "203.0.113.11/32" # 备用办公室网关 + - "198.51.100.0/24" # VPN 地址池 + - "192.0.2.50/32" # 值班工程师家庭 IP +``` + +维护列表时的建议: + +- 每行一条记录,并添加简短的 `#` 注释说明每个 IP 的归属或用途;这有助于未来的运维人员判断某条记录是否仍然需要。 +- 始终使用 CIDR 表示法。裸 IP(如 `203.0.113.10`)会被云提供商拒绝,请使用 `203.0.113.10/32`。 +- 对于 IPv6 范围,使用等效的 `/128`(单个地址)或更大的 CIDR,例如 `2001:db8::1/128`。并非所有云提供商都支持 IPv6 源地址范围,请查阅您所用提供商的 LoadBalancer 文档。 +- 该列表是**OR**关系:只要来源匹配任意一条记录,流量就会被放行。 + +编辑完文件后,继续执行下方的 `helm install`。若控制器已安装,使用相同参数执行 `helm upgrade`,或通过补丁方式在运行时更新 Service(见下一节)。 + +#### 运行时更新白名单 + +您可以直接 patch Service 来更改允许的 IP,无需执行 Helm 升级。**该 patch 会替换整个列表**;请务必包含所有希望保留的 IP,而不仅仅是新增的 IP。 + +将列表替换为新的 IP 集合: + +```bash +kubectl patch svc traefik-dashboard -n traefik-dashboard \ + -p '{"spec":{"loadBalancerSourceRanges":["203.0.113.10/32","198.51.100.0/24","192.0.2.50/32"]}}' +``` + +若要**追加** IP 而不丢失现有记录,请先读取当前列表,再使用合并后的集合执行 patch: + +```bash +# 1. 查看当前白名单 +kubectl get svc traefik-dashboard -n traefik-dashboard \ + -o jsonpath='{.spec.loadBalancerSourceRanges}' + +# 2. 将新 IP 加入完整列表后执行 patch +kubectl patch svc traefik-dashboard -n traefik-dashboard \ + -p '{"spec":{"loadBalancerSourceRanges":["/32","/32","/32"]}}' +``` + +> 运行时的 patch 不会自动同步回 `values-dashboard.yaml`。若希望在未来的 Helm 升级中保留该变更,请同时更新 values 文件并提交。 + +然后执行安装: + +```bash +helm install traefik-dashboard traefik/traefik \ + --namespace traefik-dashboard --create-namespace \ + --version 39.0.8 \ + -f third-party/traefik/values-dashboard.yaml +``` + +**验证:** + +```bash +kubectl get pods -n traefik-dashboard +``` + +预期:1 个 Pod 处于 `Running` 状态。 + +```bash +kubectl get ingressclass traefik-dashboard +``` + +预期:IngressClass 存在。 + +--- + +### 1.4 等待 LoadBalancer 分配 + +继续之前,两个 Traefik 实例均需获得外部 IP。 + +```bash +kubectl get svc -n traefik-public +kubectl get svc -n traefik-dashboard +``` + +**验证:** 两个 Service 均显示 `EXTERNAL-IP`(而非 ``)。 + +若仍处于 pending 状态,可监视分配过程: + +```bash +kubectl get svc -n traefik-public -w +``` + +IP 出现后按 `Ctrl+C`。IP 分配通常需要 2--5 分钟。 + +**排障:** 10 分钟后仍显示 `` 通常意味着云提供商无法创建 LoadBalancer。请检查:子网标签(EKS 需要 `kubernetes.io/role/elb`)、VPC 配置、服务配额,以及内部实例是否设置了正确的内部 LB 注解。 + +--- + +## 第二阶段 —— 创建 Secret(约 10 分钟) + +所有 Secret 均在部署应用前手动创建。这样可确保敏感信息永远不会出现在清单文件中。 + +### 2.1 创建命名空间 + +```bash +kubectl create namespace agenteye +``` + +**验证:** + +```bash +kubectl get namespace agenteye +``` + +预期:状态为 `Active`。 + +--- + +### 2.2 镜像拉取 Secret + +此 Secret 用于向 `ghcr.io` 进行身份验证,以拉取 AgentEye 容器镜像。关于如何生成 PAT,请参阅 [enterprise-docs/github-token.md](/zh/agenteye/github-token)。 + +```bash +kubectl create secret docker-registry agenteye-image-pull \ + --namespace agenteye \ + --docker-server=ghcr.io \ + --docker-username=agenteye-enterprise \ + --docker-password="${AGENTEYE_TOKEN}" +``` + +**验证:** + +```bash +kubectl get secret agenteye-image-pull -n agenteye -o jsonpath='{.type}' +``` + +预期:`kubernetes.io/dockerconfigjson`。 + +**深度验证** —— 确认 Token 实际可以拉取镜像: + +使用您 overlay 的 `kustomization.yaml` 中固定的 `server` 镜像标签(当前在内置 `acme` overlay 和 base 部署中均为 `v0.0.1-beta.48`)。请将下方标签替换为您实际部署的版本,以避免跨版本检查出现偏差: + +```bash +kubectl run test-pull \ + --image=ghcr.io/agenteye-enterprise/server:v0.0.1-beta.48 \ + --overrides='{"spec":{"imagePullSecrets":[{"name":"agenteye-image-pull"}]}}' \ + --restart=Never -n agenteye --command -- echo ok + +# 等待几秒拉取完成,然后: +kubectl logs test-pull -n agenteye +kubectl delete pod test-pull -n agenteye +``` + +预期:日志中打印 `ok`。 + +**排障:** `ErrImagePull` 或 `401 Unauthorized` 表示 PAT 无效或缺少 `read:packages` 权限范围。请重新检查 [enterprise-docs/github-token.md](/zh/agenteye/github-token)。 + +--- + +### 2.3 PostgreSQL 凭据 + +```bash +POSTGRES_PASSWORD=$(openssl rand -hex 24) + +kubectl create secret generic agenteye-postgres \ + --namespace agenteye \ + --from-literal=POSTGRES_USER=postgres \ + --from-literal=POSTGRES_PASSWORD="${POSTGRES_PASSWORD}" \ + --from-literal=POSTGRES_DB=agenteye +``` + +> **重要:** 我们使用 `-hex`(而非 `-base64`)生成密码。Base64 输出可能包含 `+`、`/` 和 `=`,这些字符会导致 `DATABASE_URL` 连接字符串解析失败。详情请参阅 [enterprise-docs/troubleshooting.md](/zh/agenteye/troubleshooting)。 + +> **请立即将 `POSTGRES_PASSWORD` 存入您的密钥管理器。** 在从备份恢复或直接连接数据库时,您将需要用到它。 + +**验证:** + +```bash +kubectl get secret agenteye-postgres -n agenteye +``` + +预期:Secret 存在。 + +```bash +kubectl get secret agenteye-postgres -n agenteye \ + -o jsonpath='{.data.POSTGRES_PASSWORD}' | base64 -d | wc -c +``` + +预期:`48`(24 个十六进制字节 = 48 个字符)。 + +--- + +### 2.4 管理员 API 密钥 + +```bash +ADMIN_KEY=$(openssl rand -hex 32) + +kubectl create secret generic agenteye-admin-key \ + --namespace agenteye \ + --from-literal=ADMIN_KEY="${ADMIN_KEY}" +``` + +管理员密钥是引导凭据。服务器每次启动时会以全部权限对其进行 upsert 操作。在第 7 阶段使用它创建有范围限制的收集器密钥。完整权限模型请参阅 [enterprise-docs/api-keys.md](/zh/agenteye/api-keys)。 + +> **请立即将 `ADMIN_KEY` 存入您的密钥管理器。** + +**验证:** + +```bash +kubectl get secret agenteye-admin-key -n agenteye +``` + +预期:Secret 存在。 + +--- + +### 2.5 身份验证配置(仪表盘登录) + +仪表盘使用邮箱 + OTP 方式登录。若没有此 Secret,服务器仍可正常启动,且 `ADMIN_KEY` API 路径继续工作,但**任何用户都无法通过界面登录**。 + +所有密钥在 base 清单中均标记为 `optional: true`,因此部分 Secret(或完全不设置)也没有问题;服务器会回退到文档说明的默认值。将所有内容统一放入 `agenteye-auth` Secret,便于在单一位置轮换整个认证配置。 + +```bash +kubectl create secret generic agenteye-auth \ + --namespace agenteye \ + --from-literal=ADMIN_EMAIL="admin@yourcompany.com" \ + --from-literal=ALLOWED_EMAILS="*@yourcompany.com" \ + --from-literal=SMTP_HOST="smtp.yourprovider.com" \ + --from-literal=SMTP_PORT="587" \ + --from-literal=SMTP_USERNAME="your-smtp-user" \ + --from-literal=SMTP_PASSWORD="your-smtp-password" \ + --from-literal=SMTP_FROM="noreply@yourcompany.com" \ + --from-literal=SMTP_TLS="starttls" \ + --from-literal=DEFAULT_ORG_NAME="Acme Corp" \ + --from-literal=DEFAULT_ORG_SLUG="acme" +``` + +| 键名 | 用途 | +|---|---| +| `ADMIN_EMAIL` | 引导管理员用户。每次启动时以全部权限进行 upsert,并受保护不可通过仪表盘删除或编辑权限。若未设置,则不会预置管理员,首次登录将无法完成。 | +| `ALLOWED_EMAILS` | 逗号分隔的白名单。支持精确地址(`user@example.com`)和域名通配符(`*@example.com`)。若未设置,**任何用户均无法登录或被创建**。 | +| `SMTP_HOST`、`SMTP_PORT`、`SMTP_USERNAME`、`SMTP_PASSWORD`、`SMTP_FROM` | 用于发送 OTP 验证码的 SMTP 中继。若 `SMTP_HOST` 未设置,OTP 验证码将记录到服务器的 stdout 而非发送邮件(适合首次启动冒烟测试)。如需真实邮件投递,请同时提供所有 SMTP 配置项。 | +| `SMTP_TLS` | 可选值:`starttls`(默认)、`tls` 或 `none`。 | +| `DEFAULT_ORG_NAME`、`DEFAULT_ORG_SLUG` | 可选。为内置 `default` 组织设置友好的显示名称和 URL slug,使其路径变为例如 `/acme` 而非 `/default`。**仅在首次启动时生效**;通过 `agenteye-orgctl org rename` 重命名组织后(见 §7.6),这些配置将被忽略。slug 必须为 1--40 个小写字母数字,内部可使用单个连字符。保持两者不设置则使用通用名称 `default`。 | + +> **请将 SMTP 凭据存入您的密钥管理器。** + +**验证:** + +```bash +kubectl get secret agenteye-auth -n agenteye \ + -o jsonpath='{.data}' | grep -o '"[A-Z_]*"' | sort -u +``` + +预期:您填入的密钥名称出现在输出中。 + +--- + +### 2.6 多租户组织隔离密钥(可选) + +单租户部署可跳过此步骤;服务器将使用内置的开发默认值,并可正常服务唯一的 `default` 组织。**在创建第二个组织之前**,请设置一个强壮且稳定的 `ORG_CH_SECRET`:每个组织的 ClickHouse 密码派生自 `HMAC(ORG_CH_SECRET, org_id)`,因此公开已知的开发默认值会产生可被公开推导的每组织凭据。`agenteye-orgctl org create` 命令(见 [§7.6 创建组织](#76-provision-organizations-multi-tenant))在服务器仍使用内置开发默认值时会拒绝执行。 + +```bash +kubectl create secret generic agenteye-org-ch-secret \ + --namespace agenteye \ + --from-literal=ORG_CH_SECRET="$(openssl rand -base64 48)" + +# 重启服务器以使其读取新值。 +kubectl -n agenteye rollout restart deployment/server +``` + +服务器通过**可选的** `secretKeyRef` 读取此配置,因此从未创建该 Secret 的单租户集群仍可正常启动。请确保该值**稳定且在所有副本中保持一致**;轮换该值会导致所有组织的派生 ClickHouse 密码失效,直到启动时的协调过程重新创建用户(在所有实例使用一致值的情况下进行滚动重启可自动修复)。详见 `deploy/base/server/secret.example.yaml`。 + +> **请将 `ORG_CH_SECRET` 存入密钥管理器,不要随意轮换。** + +--- + +### 2.7 验证所有 Secret + +```bash +kubectl get secrets -n agenteye -o custom-columns='NAME:.metadata.name,TYPE:.type' +``` + +预期输出(除任何默认 Secret 外): + +``` +NAME TYPE +agenteye-admin-key Opaque +agenteye-auth Opaque +agenteye-image-pull kubernetes.io/dockerconfigjson +agenteye-postgres Opaque +agenteye-org-ch-secret Opaque # 仅在完成 §2.6(多租户)后出现 +``` + +四个核心 Secret(`agenteye-admin-key`、`agenteye-auth`、`agenteye-image-pull`、`agenteye-postgres`)必须在继续操作前全部存在。`agenteye-org-ch-secret` 仅在多租户部署时需要(见 §2.6)。 + +--- + +## 第三阶段 —— 部署应用(约 5 分钟) + +### 3.1 配置公开域名 + +cert-manager 在请求 Let's Encrypt 证书之前需要知道采集端点和仪表盘的域名。复制模板文件并设置两个域名: + +```bash +cp base/certificates/domain.env.example base/certificates/domain.env +# 编辑 base/certificates/domain.env 并设置: +# INGEST_DOMAIN=ingest.your-company.example (解析到公网 Traefik LB) +# DASHBOARD_DOMAIN=agenteye.your-company.example (解析到仪表盘 Traefik LB) +``` + +`domain.env` 已被 gitignore,仅保留在各部署环境本地。若任意键缺失,kustomize 构建将明确报错。 + +> **DNS 必须先解析。** 您无需立即将 DNS 指向 LB(在第 1.2 阶段完成之前 LB 尚不存在),但第 3.2 步中的 ACME 颁发会持续重试,直到每个域名解析到其对应的 LoadBalancer。您可以现在设置 DNS(使用第 1.4 阶段记录的 LB 地址),或继续操作并在第 4 阶段添加 DNS 记录。 + +--- + +### 3.2 应用清单 + +对于全新安装,直接应用 base;如果您已为当前环境创建了 overlay,则应用该 overlay(overlay 仅固定镜像标签、环境变量和资源限制,并继承 base 的证书和路由配置): + +```bash +kubectl apply -k base/ +# 或 +kubectl apply -k overlays// +``` + +overlay 会自动包含 base,请只应用其中一个。 + +--- + +### 3.3 等待 Pod 就绪 + +```bash +kubectl wait --for=condition=Ready pod -l 'app in (server,dashboard,postgres,clickhouse)' \ + -n agenteye --timeout=180s +``` + +等待范围限定在核心数据平面 Pod。可选的 `agent`(AI 助手)和 `redis` Pod 会同步启动;助手在您配置 LLM 端点之前保持静默(见 [enterprise-docs/assistant.md](/zh/agenteye/assistant)),Redis 是尽力而为的缓存,因此两者无需就绪即可让平台正常提供服务。 + +**验证:** + +```bash +kubectl get pods -n agenteye +``` + +预期(可选的 `agent` 和 `redis` Pod 也会出现并达到 `Running` 状态): + +``` +NAME READY STATUS RESTARTS AGE +agent-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +clickhouse-0 1/1 Running 0 ... +dashboard-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +dashboard-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +postgres-0 1/1 Running 0 ... +redis-0 1/1 Running 0 ... +server-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +server-xxxxxxxxxx-xxxxx 1/1 Running 0 ... +``` + +**排障:** + +| Pod 状态 | 可能原因 | 调试命令 | +|---|---|---| +| `ImagePullBackOff` | 镜像拉取 Secret 或 PAT 有误 | `kubectl describe pod -n agenteye` | +| `CrashLoopBackOff` | 环境变量配置有误(如 DATABASE_URL) | `kubectl logs -n agenteye` | +| `Pending` | CPU/内存不足或无可用节点 | `kubectl describe pod -n agenteye`(查看 Events) | + +--- + +### 3.4 验证存储 + +```bash +kubectl get pvc -n agenteye +``` + +预期,两者均处于 `Bound` 状态: + +| PVC | 容量 | 用途 | +|---|---|---| +| `postgres-data-postgres-0` | `50Gi` | PostgreSQL 关系型/元数据存储 | +| `clickhouse-data-clickhouse-0` | `100Gi` | ClickHouse 事件和评估分析存储 | + +可选缓存的 `redis-data-redis-0` PVC(1Gi)也会出现。 + +**排障:** `Pending` 状态表示没有 StorageClass 能够创建该卷。请检查 `kubectl get storageclass` 并确保存在默认 StorageClass。生产环境建议在 overlay 中将 ClickHouse 卷配置为高速 SSD StorageClass(如 AWS 上的 gp3、GCP 上的 pd-ssd);磁盘性能差会严重影响压缩吞吐量。 + +--- + +### 3.5 验证证书 + +```bash +kubectl get certificates -n agenteye +``` + +预期:3 个证书,全部 `Ready: True`: + +| 名称 | 签发方 | 用途 | +|---|---|---| +| `mtls-ca` | `selfsigned` | 用于签发 mTLS 客户端证书的私有 CA(有效期 10 年) | +| `ingest-tls` | `letsencrypt-prod` | 采集端点的公开 TLS 证书(90 天,自动续期) | +| `dashboard-tls` | `letsencrypt-prod` | 仪表盘的公开 TLS 证书(90 天,自动续期) | + +**若 `ingest-tls` 或 `dashboard-tls` 未就绪:** + +执行 `kubectl describe certificate -n agenteye` 并查看 Events。常见原因: + +- **DNS 尚未指向 LB。** Let's Encrypt 会解析域名并访问 80 端口进行验证——`INGEST_DOMAIN` 必须解析到公网 LB,`DASHBOARD_DOMAIN` 必须解析到仪表盘 LB。在 CNAME/Alias 传播完成之前,证书颁发请求将保持 `pending` 状态。DNS 正确配置后,cert-manager 会自动重试(无需删除 Certificate 资源)。 +- **域名未替换。** 若 `dnsNames` 仍显示 `INGEST_DOMAIN_PLACEHOLDER` / `DASHBOARD_DOMAIN_PLACEHOLDER`,说明您跳过了步骤 3.1——请创建 `base/certificates/domain.env` 并重新应用。 +- **仪表盘 Traefik 无法处理验证请求**(仅影响 `dashboard-tls`)。仪表盘 Traefik 实例必须使用内置 values 文件安装(第 1.2 阶段),该文件启用了服务 cert-manager HTTP-01 解析器的 Ingress 提供者。若未使用该文件安装,验证请求将无法路由,颁发请求将永远处于 `pending` 状态。 + +**若 `mtls-ca` 未就绪:** cert-manager 本身不健康。请重新检查步骤 1.1 中的 cert-manager Pod。 + +--- + +### 3.6 验证 CronJob + +```bash +kubectl get cronjobs -n agenteye +``` + +预期: + +| 名称 | 调度 | 用途 | +|---|---|---| +| `agenteye-backup` | `0 3 * * *` | 每日 UTC 03:00 备份 Postgres 和 ClickHouse | +| `cert-renewal-check` | `0 3,15 * * *` | UTC 03:00 和 15:00 检查证书过期 | + +--- + +### 3.7 验证服务器正常启动 + +```bash +kubectl logs -n agenteye -l app=server --tail=20 +``` + +**验证:** 查找表明服务器正在监听 8080 端口的启动日志行。不应有数据库连接错误(服务器要求 PostgreSQL 和 ClickHouse 均可访问后才会报告就绪状态)。 + +**排障:** 最常见的原因是 `POSTGRES_PASSWORD` 包含 URL 不安全字符,导致 `DATABASE_URL` 解析失败。详见 [enterprise-docs/troubleshooting.md](/zh/agenteye/troubleshooting)。 + +--- + +### 3.8 验证仪表盘已连接到服务器 + +```bash +kubectl logs -n agenteye -l app=dashboard --tail=20 +``` + +**验证:** 在输出中查找 `Ready` 字样,且没有 `ECONNREFUSED` 或类似错误。 + +**排障:** 检查 `server` Service 是否存在(`kubectl get svc server -n agenteye`),以及仪表盘 Deployment 中 `AGENTEYE_SERVER_URL` 是否设置为 `http://server:8080`。 + +--- + +## 第四阶段 —— 配置网络访问(约 5 分钟) + +### 4.1 获取 LoadBalancer 地址 + +```bash +PUBLIC_IP=$(kubectl get svc -n traefik-public \ + -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') + +INTERNAL_IP=$(kubectl get svc -n traefik-dashboard \ + -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') +``` + +> 在 AWS EKS 上,LoadBalancer 返回的是域名而非 IP。请将上方命令中的 `.ip` 替换为 `.hostname`。 + +**验证:** + +```bash +echo "Public (ingest): $PUBLIC_IP" +echo "Internal (dashboard): $INTERNAL_IP" +``` + +两者均不能为空。 + +--- + +### 4.2 将 DNS 指向 LoadBalancer + +创建 DNS 记录,使 `base/certificates/domain.env` 中的域名解析到对应的 LoadBalancer——`INGEST_DOMAIN` 指向**公网** Traefik LB,`DASHBOARD_DOMAIN` 指向**仪表盘** Traefik LB: + +- **AWS Route 53:** 使用 `Alias = Yes` 的 `A` 记录,目标为 LB 域名。不要使用普通 A 记录直接指向 IP;ELB 的 IP 会轮换。 +- **其他 DNS 提供商:** 将域名 CNAME 指向 LB 域名。 + +验证: + +```bash +dig +short ingest.your-company.example +dig +short agenteye.your-company.example +``` + +结果应与 `$PUBLIC_IP` 和 `$INTERNAL_IP` 相同(在 EKS 上则解析到相同的 `*.elb.amazonaws.com` 域名)。 + +DNS 解析正常后,cert-manager 将在一分钟内完成第 3.5 阶段中待处理的 ACME 颁发请求。重复执行 `kubectl get certificates -n agenteye`,直到 `ingest-tls` 和 `dashboard-tls` 均显示 `Ready: True`。 + +--- + +### 4.3 访问采集端点 + +公网采集端点强制要求双向 TLS,因此每个请求(包括 `/health`)都必须携带客户端证书。您将在第 5 阶段颁发首个客户端证书;如果已有证书,现在可以验证可达性: + +```bash +curl -s --cert issued//client.crt \ + --key issued//client.key \ + https://ingest.your-company.example/health +``` + +预期:`{"status":"ok"}`。无需 `-k`——服务器证书链接到 `INGEST_DOMAIN` 的公开 CA,可通过系统信任库验证。请通过 `INGEST_DOMAIN` 域名访问采集端点(与颁发的证书匹配),而非直接使用 LoadBalancer IP/域名。 + +仪表盘端点通过 `DASHBOARD_DOMAIN` 提供服务,证书为公开受信任证书,且不在 mTLS 之后,因此无需 `-k` 和客户端证书: + +```bash +curl -s https://agenteye.your-company.example/ -o /dev/null -w '%{http_code}\n' +``` + +请通过域名而非原始 LB 地址访问仪表盘——证书绑定到 `DASHBOARD_DOMAIN`,直接访问原始地址会导致证书名称不匹配。 + +**排障:** 若 `curl` 挂起,检查您的机器是否可以访问 LB(VPN、安全组、防火墙规则)。采集域名出现 `certificate required` 握手错误表示未提交客户端证书;请先完成第 5 阶段。采集域名出现 TLS 验证错误表示服务器证书尚未颁发完成;请返回第 3.5 阶段解决问题。 + +--- + +## 第五阶段 —— 颁发 mTLS 客户端证书(每个集群约 10 分钟) + +收集器通过**双重因素**进行身份验证:客户端证书(传输层,证明请求来自授权集群)和 API 密钥(应用层,证明请求来自具有 `events:add` 权限的收集器)。泄露的密钥在没有证书的情况下无法使用;被盗的证书在没有有效密钥的情况下同样无法使用。 + +### 5.1 颁发证书 + +每个运行收集器的集群都需要自己的客户端证书。在清单目录中执行: + +```bash +cd base/certificates/client-certs +./issue-client-cert.sh +``` + +将 `` 替换为有意义的标识符(如 `us-east-1-prod`、`staging`)。 + +**验证:** 脚本打印 `==> Done!` 并列出输出文件。 + +```bash +kubectl get certificate mtls-client- -n agenteye +``` + +预期:`Ready: True`。 + +输出文件位于 `issued//`: + +| 文件 | 用途 | +|---|---| +| `client.crt` | 客户端证书(有效期 90 天) | +| `client.key` | 客户端私钥 | +| `ca.crt` | 用于服务器验证的 CA 证书 | +| `collector-mtls-secret.yaml` | 可直接应用到收集器集群的 Kubernetes Secret | + +--- + +### 5.1b 替代投递方式:AWS Secrets Manager + +如果证书的使用方是需要在磁盘上挂载 `client.crt` 和 `client.key` 的 Kubernetes Pod(以 agenteye-collector 作为应用 Pod 中的 Sidecar 时的典型场景),可以将证书包推送到 AWS Secrets Manager。应用 Pod 通过 [Secrets Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/) 结合 IRSA 方式挂载证书,证书轮换完全免人工干预。 + +```bash +cd base/certificates/client-certs +export AWS_REGION=us-east-1 # 您的工作负载所在区域 +./issue-client-cert.sh --save-to aws-secrets-manager +``` + +重新运行(续期)时,脚本会对同一个 Secret 调用 `PutSecretValue`,因此 ARN 和名称保持稳定。CSI Driver 在下次轮换轮询时获取新版本,并更新 Pod 内的文件。 + +**前置条件:** + +- 已通过 `aws` CLI v2 完成 AWS 账户身份验证。 +- 已安装 `jq`。 +- 已设置 `AWS_REGION` 环境变量。 +- 调用方身份具有以下 IAM 权限(将 `Resource` 范围限制到 `arn:aws:secretsmanager:::secret:agenteye/mtls-client/*`): + - `secretsmanager:CreateSecret` + - `secretsmanager:DescribeSecret` + - `secretsmanager:PutSecretValue` + - `secretsmanager:TagResource` + +**此模式下脚本的执行步骤:** + +| 步骤 | 操作 | +|---|---| +| 1 | 通过 cert-manager 颁发/重新提取证书(与默认模式相同)。 | +| 2 | 对 `agenteye/mtls-client/` 调用 `DescribeSecret`,判断是创建还是更新。 | +| 3 | 首次运行:调用 `CreateSecret`,写入包含三个键(`client.crt`、`client.key`、`ca.crt`)的 JSON 负载,并打标签 `AgentEyeCluster=`。后续运行:调用 `PutSecretValue` 发布新版本,并通过 `TagResource` 刷新标签。 | +| 4 | 仅在上传成功后删除 `issued//` 目录。如有任何失败,该目录将被保留以便重试。 | + +**若 Secret 已被计划删除**,脚本将报错并提示您先执行 `aws secretsmanager restore-secret --secret-id agenteye/mtls-client/` 再重试。 + +完整的 Pod 配置(SecretProviderClass、IRSA 设置、轮换行为、故障排除)请参阅 [enterprise-docs/single-pod-deployment.md](/zh/agenteye/single-pod-deployment)。 + +--- + +### 5.2 验证证书可用 + +对 mTLS 入口测试已颁发的证书: + +```bash +curl -sk --cert issued//client.crt \ + --key issued//client.key \ + https://${PUBLIC_IP}/health +``` + +预期:`{"status":"ok"}` + +**排障:** + +| 错误 | 原因 | 解决方法 | +|---|---|---| +| `certificate required` | 未提交证书 | 检查 `curl` 命令中的文件路径 | +| `bad certificate` | CA 不匹配 | 验证证书由 `mtls-ca-issuer` 签发:`kubectl describe certificate mtls-client- -n agenteye` | +| `connection refused` | 域名或 LB 无法访问 | 检查 `/etc/hosts` 或 DNS 配置 | + +--- + +### 5.3 发送到收集器集群 + +将 `collector-mtls-secret.yaml` 发送给负责运维收集器集群的团队。他们执行以下操作应用: + +```bash +kubectl apply -f collector-mtls-secret.yaml -n +``` + +然后配置收集器挂载该 Secret 并使用证书路径: + +```json +{ + "tls_cert": "/etc/agenteye/tls/client.crt", + "tls_key": "/etc/agenteye/tls/client.key" +} +``` + +完整的收集器安装说明(包括 Kubernetes 卷挂载)请参阅 [enterprise-docs/collector-installation.md](/zh/agenteye/collector-installation)。 + +**验证(在收集器集群中执行):** + +```bash +kubectl get secret agenteye-collector-mtls -n +``` + +预期:Secret 存在,包含 3 个数据键(`client.crt`、`client.key`、`ca.crt`)。 + +--- + +### 5.4 证书生命周期 + +| 属性 | 值 | +|---|---| +| 客户端证书有效期 | 90 天 | +| 自动续期 | cert-manager 在过期前 15 天自动续期 | +| CA 有效期 | 10 年 | +| 过期告警 | CronJob 在过期前 30 天发出告警(第 6 阶段) | + +cert-manager 会在 **AgentEye 集群**上自动续期证书,但续期后的证书必须重新分发到收集器集群。请在旧证书过期前重新执行 `issue-client-cert.sh` 并重新应用 `collector-mtls-secret.yaml`。 + +如果您使用 `--save-to aws-secrets-manager`(见 §5.1b),重新执行相同命令即可。脚本会对同一 Secret 调用 `PutSecretValue`;通过 Secrets Store CSI Driver 挂载 Secret 的 Pod 将在下次轮换轮询时获取新版本(默认每小时一次),无需重启 Pod。 + +--- + +### 5.5 吊销证书 + +若要立即阻止某集群的收集器访问: + +```bash +kubectl delete certificate mtls-client- -n agenteye +``` + +**验证:** 步骤 5.2 中的 `curl` 命令现在将返回 TLS 握手错误。 + +--- + +## 第六阶段 —— 证书续期监控(约 2 分钟) + +内置 CronJob 每 12 小时运行一次(UTC 03:00 和 15:00),检查所有带有 `agenteye.io/cert-type=mtls-client` 标签的客户端证书。当任意证书距离过期不足 30 天时发出告警。 + +### 6.1 启用 Slack 通知(可选) + +```bash +kubectl create secret generic cert-renewal-notify-config \ + --namespace agenteye \ + --from-literal=SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL" +``` + +若未设置此 Secret,CronJob 仍会正常运行,并将证书状态记录到 stdout。 + +**验证:** + +```bash +kubectl get secret cert-renewal-notify-config -n agenteye +``` + +预期:Secret 存在。 + +--- + +### 6.2 测试 CronJob + +```bash +kubectl create job --from=cronjob/cert-renewal-check test-cert-check -n agenteye + +kubectl wait --for=condition=Complete job/test-cert-check -n agenteye --timeout=60s + +kubectl logs -n agenteye -l job-name=test-cert-check +``` + +预期:输出包含所有证书及其过期状态的列表。若已配置 Slack webhook,请检查对应频道是否收到告警消息。 + +**排障:** 检查 RBAC——CronJob 的 ServiceAccount 需要对 cert-manager Certificate 资源有 `get, list` 权限。执行以下命令验证:`kubectl describe role cert-renewal-check -n agenteye`。 + +清理测试 Job: + +```bash +kubectl delete job test-cert-check -n agenteye +``` + +--- + +## 第七阶段 —— 端到端验证 + +本阶段确认整个流水线正常工作:健康检查、密钥创建、事件摄入和仪表盘展示。 + +> **注意:** 以下示例为方便起见,通过 LoadBalancer 原始地址(`${PUBLIC_IP}`)访问采集端点,因此需要传入 `-k`;服务器证书绑定到 `INGEST_DOMAIN` 而非 LB IP,跳过域名检查。采集端点在**所有**路径上都强制执行双向 TLS,因此每次调用也必须携带客户端证书(`--cert`/`--key`)。若要同时验证公开证书,请使用 `https://ingest.your-company.example/...` 替换 `${PUBLIC_IP}` 并去掉 `-k`。 + +### 7.1 健康检查 + +```bash +curl -sk --cert issued//client.crt \ + --key issued//client.key \ + https://${PUBLIC_IP}/health +``` + +预期:`{"status":"ok"}`,HTTP 200。 + +--- + +### 7.2 创建有范围限制的收集器密钥 + +管理员密钥用于引导和管理。请为收集器创建专用的 `events:add` 密钥: + +```bash +COLLECTOR_KEY=$(openssl rand -hex 32) + +curl -sk -X POST https://${PUBLIC_IP}/keys \ + --cert issued//client.crt \ + --key issued//client.key \ + -H "Authorization: Bearer ${ADMIN_KEY}" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "prod-collector", + "key": "'"${COLLECTOR_KEY}"'", + "permissions": ["events:add"] + }' +``` + +**验证:** 响应包含 `"id"`、`"name": "prod-collector"`、`"permissions": ["events:add"]`、`"created_at"`。 + +**验证:** 确认密钥出现在密钥列表中: + +```bash +curl -sk https://${PUBLIC_IP}/keys \ + --cert issued//client.crt \ + --key issued//client.key \ + -H "Authorization: Bearer ${ADMIN_KEY}" +``` + +预期:响应中包含 `prod-collector`。 + +完整的密钥管理参考请参阅 [enterprise-docs/api-keys.md](/zh/agenteye/api-keys)。 + +--- + +### 7.3 摄入测试事件 + +```bash +echo '{"session_id":"test","agent_id":"smoke-test","type":"test","timestamp":"2026-04-20T00:00:00Z"}' \ + | curl -sk --cert issued//client.crt \ + --key issued//client.key \ + -H "Authorization: Bearer ${COLLECTOR_KEY}" \ + -H "Content-Type: application/x-ndjson" \ + --data-binary @- \ + https://${PUBLIC_IP}/events +``` + +预期:`{"accepted":1,"skipped":0}`,HTTP 200。 + +**排障:** + +| HTTP 状态码 | 原因 | +|---|---| +| 401 | API 密钥无效或缺失 | +| 403 | 密钥缺少 `events:add` 权限 | +| TLS 握手错误 | 客户端证书问题——参见第 5 阶段排障 | + +--- + +### 7.4 在仪表盘中确认事件可见 + +在浏览器中打开 `https://agenteye.your-company.example`(您的 `DASHBOARD_DOMAIN`)。证书为公开受信任证书,不会出现警告。 + +> 如果仪表盘 LoadBalancer 受 IP 白名单限制且您无法连接,请验证您的 IP 是否已被允许: +> ```bash +> kubectl get svc traefik-dashboard -n traefik-dashboard -o jsonpath='{.spec.loadBalancerSourceRanges}' +> ``` +> 请注意,Let's Encrypt 通过 80 端口的 HTTP-01 方式续期仪表盘证书,而源地址范围限制适用于整个 LoadBalancer——在将其限制为企业网段之前,请先与支持团队协调配置 DNS-01 解析器,否则续期将静默失败。 + +**验证:** 冒烟测试事件应出现在事件列表中,session 为 `test`,agent 为 `smoke-test`。 + +**排障:** 检查仪表盘日志(`kubectl logs -n agenteye -l app=dashboard --tail=50`)。验证 `AGENTEYE_SERVER_URL` 和 `AGENTEYE_API_KEY` 是否正确设置。 + +--- + +### 7.5 测试备份 CronJob + +```bash +kubectl create job --from=cronjob/agenteye-backup test-backup -n agenteye + +kubectl wait --for=condition=Complete job/test-backup -n agenteye --timeout=300s + +kubectl logs -n agenteye -l job-name=test-backup +``` + +预期:日志中包含 `Backup created: agenteye-YYYYMMDD-HHMMSS.tar.gz (NNN)`;归档文件包含 Postgres 备份和 ClickHouse 表。 + +> S3 上传步骤已内置在 CronJob 中,每当 `BACKUP_BUCKET` 有值时运行(base 默认设置了一个默认桶值)。仅当 `BACKUP_BUCKET` 为空或字面值 `PLACEHOLDER` 时跳过。在正式依赖此功能之前,请将其指向您自己的存储桶,并为 `agenteye-backup` ServiceAccount 授予写入权限(见下方备份章节)。 + +清理: + +```bash +kubectl delete job test-backup -n agenteye +``` + +--- + +### 7.6 创建组织(多租户) + +单租户部署可跳过此步骤;所有数据存储在内置 `default` 组织中,无需任何额外操作。 + +如果您运行多个相互隔离的租户,组织及其成员通过 **`agenteye-orgctl`** CLI 进行管理。该工具**内置在服务器镜像中**(与 `agenteye-server` 并列),通过 `kubectl exec` **在现有 `server` Deployment 内运行;无需单独的 Pod、Job 或 Deployment,也没有 HTTP API 或仪表盘按钮用于租户生命周期管理。** 在服务器 Pod 中运行意味着它复用 Pod 的 `DATABASE_URL`、`CLICKHOUSE_URL` 以及 §2.6 中的 `ORG_CH_SECRET`。 + +> **前置条件:** 请先完成 §2.6。`org create` 在服务器仍使用内置开发 `ORG_CH_SECRET` 时会拒绝执行,且其创建的每组织 ClickHouse 用户依赖该 Secret 足够强壮且稳定。 + +**创建组织并添加首位管理员:** + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org create --slug acme --name "Acme Corp" + +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member add --org acme --email alice@acme.example --set admin +``` + +新成员首次通过仪表盘登录时会收到 OTP,之后完全在组织的 URL 前缀下(如 `/acme/...`)通过界面操作。 + +**其他命令**(同样通过 `kubectl -n agenteye exec deploy/ \ No newline at end of file diff --git a/docs/zh/agenteye/managed-deployment.mdx b/docs/zh/agenteye/managed-deployment.mdx new file mode 100644 index 00000000..846db575 --- /dev/null +++ b/docs/zh/agenteye/managed-deployment.mdx @@ -0,0 +1,171 @@ +--- +title: "在您的 Kubernetes 集群上进行托管部署" +description: "AgentEye 在您的 Kubernetes 集群上进行托管部署的文档。" +--- + + +AgentEye 是一个面向 AI 和 LLM Agent 的自托管可观测性与评估平台。它捕获 Agent 会话、工具调用、模型请求和错误,将其转化为可搜索的分析数据和评估结果,并在仪表板中展示,同时提供可选的只读 AI 助手。 + +在托管部署模式下,您提供一个专用的 Kubernetes 集群,Exosphere 在其中运行完整平台,代您部署、配置、运维、备份和升级每个组件。您的团队无需自行管理数据库、证书或版本升级,即可获得平台的全部价值(Agent 可见性、分析、评估以及可选的助手)。所有数据始终保留在您的云账户内。 + +--- + +## 前置条件 + +- 用于拉取容器镜像和下载制品的 **GitHub PAT**(请参阅 [GitHub Token 设置](/zh/agenteye/github-token)) +- 一个**专用 Kubernetes 集群**(请参阅下方要求) +- 用于数据库备份的**存储桶** +- **网络连通性**:集群负载均衡器的 443 端口入站访问 + +--- + +## 第一步:部署专用 Kubernetes 集群 + +创建一个专用于 AgentEye 的 Kubernetes 集群。该集群不应与其他工作负载共享,以确保整个平台(应用服务、数据库、分析和缓存)在隔离环境中运行,不影响您现有的基础设施。 + +| 要求 | 详情 | +|---|---| +| **发行版** | 任何符合标准的 Kubernetes:EKS、GKE、AKS 或自托管 | +| **版本** | 1.27 或更高 | +| **节点池** | 最低配置:**3 个节点,每节点 4 vCPU / 8 GB 内存**(标准通用实例) | +| **存储** | 默认 StorageClass,支持块存储卷(例如 AWS 上的 `gp3`、GCP 上的 `pd-ssd`) | +| **负载均衡器** | 集群必须能够创建云 LoadBalancer 服务(EKS、GKE、AKS 默认支持) | + +> Exosphere 会在集群内安装和管理其余所有组件:Ingress 控制器、TLS 证书、数据库、缓存、监控以及所有应用部署。 + +--- + +## 第二步:向 AgentEye 团队授予访问权限 + +Exosphere 需要 cluster-admin 权限(或同等范围的 RBAC 权限)来管理命名空间、自定义资源定义、Ingress 控制器和存储供应器。 + +| 要求 | 详情 | +|---|---| +| **访问方式** | IAM 角色(EKS/GKE 首选)、kubeconfig 或基于 SSO 的访问 | +| **VPN / 跳板机** | 如果 Kubernetes API Server 为私有网络,请为 Exosphere 运维团队提供 VPN 凭证或跳板机访问权限 | + +--- + +## 第三步:配置网络连通性 + +您的网络团队需要允许集群负载均衡器的 **443 端口**入站流量。部署会运行两个独立的负载均衡器:一个用于事件采集(mTLS 保护),一个用于仪表板: + +| 流量类型 | 来源 | 目标 | 安全措施 | +|---|---|---|---| +| **事件采集** | 您集群中的 Collector Pod | Ingest LoadBalancer,443 端口 | mTLS(客户端证书)+ API Key | +| **仪表板** | 开发者浏览器 | Dashboard LoadBalancer,443 端口 | 您域名上的 HTTPS,无密码邮件 OTP 登录 | + +Ingest 端点受双向 TLS 保护;Collector 每次请求都必须同时提供有效的客户端证书**和**有效的 API Key。仪表板运行在独立的负载均衡器和主机名上,登录仅限于您加入白名单的邮箱地址/域名。 + +**DNS 记录(一次性操作):** 您需要在自己控制的域名下创建两条 CNAME 记录——一条指向 Ingest 端点,一条指向仪表板(例如 `agenteye.your-company.example`)——均指向 Exosphere 提供的负载均衡器主机名。Exosphere 随后会自动为两个主机名申请公开受信任的 TLS 证书,包括自动续期。 + +> **关于 80 端口:** 自动证书申请和续期需要通过每个负载均衡器的 80 端口进行 HTTP 验证。如果您的安全策略要求将仪表板负载均衡器限制为企业 IP 段,请提前告知 Exosphere——我们会切换为基于 DNS 的证书验证方式(您需额外添加一条 DNS 记录),确保续期在限制策略下仍能正常工作。 + +> **出站流量:** 集群节点需要访问互联网,以从 `ghcr.io` 拉取容器镜像。如果您的网络限制出站流量,请将 `ghcr.io` 加入白名单,或将镜像同步至内部镜像仓库。 + +--- + +## 第四步:提供备份存储桶 + +数据库备份存储在您自己拥有的云存储桶中。 + +| 要求 | 详情 | +|---|---| +| **服务** | S3(AWS)、GCS(GCP)或 Azure Blob Storage | +| **访问权限** | 通过 IAM 角色(EKS 上的 IRSA,GKE 上的 Workload Identity)为集群节点授予写入权限,或直接提供凭证 | +| **保留策略** | 您控制存储桶的生命周期策略(保留期限、归档规则)。Exosphere 负责写入备份;保留时长由您决定 | + +每日执行一次全量备份,将 PostgreSQL(关系型状态数据)和 ClickHouse(事件与评估数据)打包为一个压缩归档文件并上传至您的存储桶。每次升级前也会执行备份。 + +--- + +## 第五步:指定联系人 + +请在您方指定一位负责人或 Slack/Teams 频道,用于处理集群层面的问题:节点健康状态、云账户配额、网络变更等。日常运维无需联系此负责人。 + +--- + +## 我们部署的内容 + +Exosphere 获得集群访问权限后,将为您部署并管理以下组件: + +| 组件 | 职责 | +|---|---| +| **AgentEye Server** | HTTP API,接收来自 Collector 的事件,运行分析,并向仪表板提供数据 | +| **仪表板** | Web 界面,用于查看 Agent 会话、工具调用、模型请求和错误;承载可选的只读 AI 助手 | +| **ClickHouse** | 必需的核心存储,用于存储采集的事件、分析数据和评估结果 | +| **PostgreSQL** | 关系型存储,用于组织、API Key、用户、仪表板和保存的查询 | +| **Redis** | 可选的共享缓存和限流后端;不可用时平台可优雅降级 | +| **AI 助手(可选)** | 内部只读助手容器;在配置 LLM 端点之前保持禁用状态 | +| **Ingress 控制器** | 两个负载均衡器(一个用于 mTLS 保护的 Ingest,一个用于仪表板),使用公开受信任、自动续期的证书终止 TLS,并在 Ingest 端点上强制执行 mTLS | +| **cert-manager** | 自动化 TLS 证书申请及 mTLS 客户端证书签发 | +| **证书监控** | 定时任务,检查证书到期时间,并在证书临近续期时发送告警(例如发送至 Slack) | + +托管服务还会运行平台的评估流水线,根据您的评估标准对 Agent 活动进行评分。请参阅 [助手](/zh/agenteye/assistant) 和 [评估套件](/zh/agenteye/evaluation-suite) 了解这些功能的详细介绍。 + +--- + +## 我们向您提供的内容 + +部署完成后,您将收到: + +| 内容 | 详情 | +|---|---| +| **仪表板 URL** | 您域名下的一个主机名(例如 `https://agenteye.your-company.example`),使用公开受信任、自动续期的 TLS 证书。您只需创建一条指向我们提供的负载均衡器主机名的 CNAME;登录方式为无密码邮件 OTP | +| **Collector 端点** | Ingest 主机名的 `/events` 路径(例如 `https://ingest.your-company.example/events`),受 mTLS 保护 | +| **客户端证书包** | 按集群分发:包含客户端证书、私钥和 CA 证书,以 Kubernetes Secret 清单形式交付。每个集群应用一次即可 | +| **GitHub PAT** | 用于下载 Collector 二进制文件和 Python SDK 包 | +| **Collector API Key** | 具有 `events:add` 权限的范围密钥,每个 Collector 部署一个 | +| **安装指南** | Collector 和 Python SDK 的分步文档 | + +--- + +## 设置完成后您需要做的事 + +您唯一持续性的工作是在自己的 Agent 机器上,而非 AgentEye 集群: + +1. **在每个运行 AI Agent 的 Kubernetes 集群中安装 Collector**:挂载客户端证书,配置端点 URL 和 API Key。请参阅 [Collector 安装](/zh/agenteye/collector-installation)。 +2. **将 Python SDK 集成到您的 Agent 代码中**。请参阅 [Python SDK](/zh/agenteye/python-sdk)。 +3. **在浏览器中打开仪表板**查看 Agent 活动。 + +无需进行集群运维、数据库管理、证书续期或版本升级。 + +--- + +## 安全性 + +- **数据始终保留在您的云账户中。** 集群、存储和数据库均运行在您的环境内,数据不会离开您的边界。 +- **您掌控访问权限。** 集群在您的账户下。您可以随时审计、监控或撤销 Exosphere 的访问权限。所有操作均通过您的云审计日志(CloudTrail、GCP Audit Logs 等)记录。 +- **事件采集使用 mTLS。** 每次 Collector 请求都需要同时提供有效的客户端证书和 API Key。泄露的 API Key 在没有证书的情况下毫无用处;被盗的证书在没有有效 API Key 的情况下同样无效。 +- **仪表板访问控制。** 仪表板运行在独立的负载均衡器上,与事件采集完全分离,登录方式为无密码邮件 OTP,仅限您白名单内的邮箱地址/域名。负载均衡器上的 IP 来源范围白名单可按需提供;由于自动证书续期需要访问负载均衡器,Exosphere 会将该限制与基于 DNS 的证书验证配对使用,确保续期正常工作。 +- **按集群颁发证书。** 您的每个集群都有独立的客户端证书。若某个集群遭到入侵,可单独吊销该证书,不影响其他集群。 + +--- + +## 部署时间线 + +| 阶段 | 时长 | 您的参与 | +|---|---|---| +| **集群部署** | 1-2 天 | 部署集群并向 Exosphere 授予访问权限 | +| **平台搭建** | 1 天 | 无需参与;Exosphere 安装所有基础设施组件 | +| **应用部署** | 1 天 | 无需参与;Exosphere 部署服务器、仪表板并创建 API Key | +| **Collector 上线** | 1-3 天 | 在您的集群中安装 Collector(Exosphere 提供指导) | +| **生产磨合期** | 1 周 | 无需参与;Exosphere 负责监控和调优 | + +典型总耗时:从启动到生产就绪约 **2 周**。 + +--- + +## 支持 + +如有问题,请通过 `support@exosphere.host` 联系 Exosphere。 + +--- + +## 下一步 + +- [快速入门](/zh/agenteye/getting-started):端到端操作指南 +- [Collector 安装](/zh/agenteye/collector-installation):安装和配置 Collector +- [Python SDK](/zh/agenteye/python-sdk):为您的 Agent 代码添加埋点 +- [API Key](/zh/agenteye/api-keys):管理访问权限和权限设置 +- [故障排查](/zh/agenteye/troubleshooting):常见问题与解决方案 \ No newline at end of file diff --git a/docs/zh/agenteye/python-sdk.mdx b/docs/zh/agenteye/python-sdk.mdx new file mode 100644 index 00000000..caa320f5 --- /dev/null +++ b/docs/zh/agenteye/python-sdk.mdx @@ -0,0 +1,383 @@ +--- +title: "Python SDK" +description: "AgentEye Python SDK 文档。" +--- + + +AgentEye Python SDK 为您提供对 Agent 行为的完整可见性(包括每次 Agent 运行、工具调用、模型请求、Hook 以及人工干预),帮助您调试、审计和评估它们。SDK 通过将结构化事件写入本地 JSONL 文件来对 Agent 代码进行埋点;采集器守护进程会自动拾取这些文件并将其上报至平台。 + +--- + +## 安装 + +使用您的 `AGENTEYE_TOKEN` 从 GitHub Releases 下载 wheel 包。如果您还没有 Token,请参阅 [GitHub Token 设置](/zh/agenteye/github-token) 了解设置步骤和所需权限。 + +**使用 `gh` CLI + pip:** + +```bash +VERSION=0.0.1b9 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "python-sdk/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-*.whl' +pip install "agenteye-${VERSION}-py3-none-any.whl" +``` + +**使用 `gh` CLI + uv:** + +```bash +VERSION=0.0.1b9 +GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download "python-sdk/v${VERSION}" \ + --repo agenteye-enterprise/releases \ + --pattern 'agenteye-*.whl' +uv add "./agenteye-${VERSION}-py3-none-any.whl" +``` + +**使用 curl(无需 `gh` CLI):** + +```bash +VERSION=0.0.1b9 +curl -fsSL \ + -H "Authorization: Bearer $AGENTEYE_TOKEN" \ + -L \ + "https://github.com/agenteye-enterprise/releases/releases/download/python-sdk%2Fv${VERSION}/agenteye-${VERSION}-py3-none-any.whl" \ + -o "agenteye-${VERSION}-py3-none-any.whl" +pip install "agenteye-${VERSION}-py3-none-any.whl" +``` + +--- + +## 快速开始 + +```python +import agenteye + +agenteye.configure(environment="production") + +agenteye.event.agent_start(session_id="run-001", agent_id="planner", goal="answer user query") + +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", + input={"query": "latest AI research"}, +) + +agenteye.event.tool_result( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", + output={"results": ["..."]}, +) + +agenteye.event.agent_end(session_id="run-001", agent_id="planner", outcome="success") +``` + +--- + +## configure() + +```python +agenteye.configure( + base_dir=None, # Path | str | None。默认值:$AGENTEYE_HOME 或 ~/.agenteye + flush_interval=0.5, # float,刷新周期间隔,单位:秒 + environment=None, # str | None。部署环境标签 +) +``` + +请在任何 `event.*` 调用之前调用一次。可以省略;默认配置开箱即用。所有参数均为仅限关键字参数,请按上方示例以命名方式传入。 + +当 `base_dir` 为 `None`(默认值)时,SDK 会优先读取 `$AGENTEYE_HOME`(若已设置),否则回退到 `~/.agenteye`。此行为与采集器自身的路径解析逻辑一致,因此只需配置一个 `AGENTEYE_HOME` 环境变量,即可同时为 SDK 和采集器指定共享事件缓冲目录,这在 sidecar / 单 Pod 部署场景中尤为重要——两个进程必须使用相同的缓冲路径。 + +--- + +## 环境 + +为每个事件打上部署环境标签(如 `production`、`staging`、`qa`、`canary` 等)。只需设置一次,SDK 会自动将其附加到每个事件上。 + +**方式一:通过 `configure()` 设置:** + +```python +agenteye.configure(environment="production") +``` + +**方式二:通过环境变量设置:** + +```bash +export AGENTEYE_ENVIRONMENT=production +``` + +**优先级:** `configure(environment=...)` 优先于环境变量。若两者均未设置,则默认为 `"dev"`。 + +环境值在仪表盘中作为一级筛选条件显示,并在服务器端以索引列形式存储,以支持快速查询。 + +**限制:** 环境值**不得包含字面逗号 `,`**。仪表盘筛选器在传输时使用逗号分隔的多选格式(`?environment=prod,staging`),因此名为 `prod,blue` 的环境值会被拆分为两个独立值。包含逗号的环境值在数据摄入时将被拒绝。 + +--- + +## 事件参考 + +所有事件方法均需要以下两个字段: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `session_id` | `str` | 标识顶层 Agent 运行实例 | +| `agent_id` | `str` | 标识会话中发出事件的具体 Agent | + +所有方法还接受任意 `**kwargs` 用于自定义元数据(参见[自定义字段](#custom-fields))。 + +--- + +### `event.agent_start()` + +Agent 开始工作时触发。 + +```python +agenteye.event.agent_start( + session_id="run-001", + agent_id="planner", + goal="answer user query", # str | None + parent_id=None, # str | None - 嵌套 Agent 的父 agent_id +) +``` + +--- + +### `event.agent_end()` + +Agent 完成工作时触发。 + +```python +agenteye.event.agent_end( + session_id="run-001", + agent_id="planner", + outcome="success", # str | None + summary="Answered query", # str | None +) +``` + +--- + +### `event.tool_use()` + +Agent 调用工具时触发。与 `tool_result` 配对使用;SDK 会自动计算 `duration_ms`。 + +```python +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="web_search", # str,必填 + tool_call_id="toolu_01", # str,必填 - 与对应 tool_result 的关联键 + input={"query": "..."}, # dict | None +) +``` + +--- + +### `event.tool_result()` + +工具返回结果时触发。通过 `tool_call_id` 与 `tool_use` 关联。 + +```python +agenteye.event.tool_result( + session_id="run-001", + agent_id="planner", + tool_name="web_search", + tool_call_id="toolu_01", # 必须与之前的 tool_use 匹配 + output={"results": ["..."]}, # Any | None + error=None, # str | None - 工具抛出异常时设置 + # duration_ms 由 SDK 自动计算,请勿手动传入 +) +``` + +--- + +### `event.model_request()` + +向 LLM 发送提示词之前触发。 + +```python +agenteye.event.model_request( + session_id="run-001", + agent_id="planner", + model="claude-sonnet-4-6", # str | None + messages=[ # list[dict] | None - 对话轮次 + {"role": "user", "content": "..."}, + ], + system="You are helpful.", # Any | None - 字符串或内容块列表 + tools=[ # list[dict] | None - 提供给模型的工具 schema + {"name": "search", "input_schema": {"type": "object"}}, + ], +) +``` + +`messages` 条目的 `content` 字段支持普通字符串或 Anthropic 风格的内容块列表。采样参数(`temperature`、`max_tokens` 等)可作为额外的 kwargs 传入。 + +--- + +### `event.model_response()` + +LLM 返回响应时触发。 + +```python +agenteye.event.model_response( + session_id="run-001", + agent_id="planner", + model="claude-sonnet-4-6", # str | None + stop_reason="end_turn", # str | None + input_tokens=1024, # int | None + output_tokens=256, # int | None + content=[ # Any | None - 字符串或内容块列表 + {"type": "text", "text": "..."}, + ], + role="assistant", # str | None +) +``` + +`content` 支持普通字符串(通用提供商)或 Anthropic 风格内容块列表。工具调用以 `{"type": "tool_use", ...}` 块的形式嵌入在 `content` 中,不单独设置 `tool_calls` 字段。 + +--- + +### `event.hook_triggered()` + +Hook 触发时触发。与 `hook_completed` 配对使用;SDK 会自动计算 `duration_ms`。 + +```python +agenteye.event.hook_triggered( + session_id="run-001", + agent_id="planner", + hook_name="pre_tool_use", # str,必填 + hook_id="hook-abc", # str,必填 - 关联键 + trigger_event="tool_use", # str | None + input={"tool": "search"}, # Any | None +) +``` + +--- + +### `event.hook_completed()` + +Hook 执行完成时触发。通过 `hook_id` 与 `hook_triggered` 关联。 + +```python +agenteye.event.hook_completed( + session_id="run-001", + agent_id="planner", + hook_name="pre_tool_use", + hook_id="hook-abc", # 必须与之前的 hook_triggered 匹配 + outcome="allow", # str | None + output=None, # Any | None + error=None, # str | None + # duration_ms 由 SDK 自动计算,请勿手动传入 +) +``` + +--- + +### `event.error()` + +发生未处理错误时触发。 + +```python +agenteye.event.error( + session_id="run-001", + agent_id="planner", + error_type="TimeoutError", # str,必填 + message="timed out", # str,必填 + traceback="Traceback...", # str | None +) +``` + +--- + +## 人机协作事件 + +人机协作事件让您能够监控人员介入 Agent 执行流程的关键时刻(等待审批、提供输入、暂停或停止 Agent)。通过这些事件,您可以衡量人类响应所需的时长(SDK 会自动为配对事件计算 `duration_ms`),审计是谁暂停或中断了 Agent,并构建在仪表盘中呈现的审批与监督工作流。 + +### `event.human_wait()` + +Agent 暂停执行并等待人工输入时触发。与 `human_input` 配对使用;SDK 会自动计算 `duration_ms`(即人类响应所用时长)。 + +```python +agenteye.event.human_wait( + session_id="run-001", + agent_id="planner", + input_id="inp-abc", # str,必填 - 与对应 human_input 的关联键 + prompt="Do you approve this action?", # str | None - 向人类展示的问题 + options=["approve", "reject", "defer"], # list[str] | None - 呈现给人类的选项 + reason="approval_required", # str | None - Agent 等待的原因 +) +``` + +### `event.human_input()` + +人类提供输入且 Agent 恢复执行时触发。通过 `input_id` 与 `human_wait` 关联。`duration_ms` 由 SDK 自动计算,调用方不得手动传入。 + +```python +agenteye.event.human_input( + session_id="run-001", + agent_id="planner", + input_id="inp-abc", # str,必填 - 必须与之前的 human_wait 匹配 + response="approve", # str | None - 人类的回答(自由文本或所选选项) + # duration_ms 由 SDK 自动计算,请勿手动传入 +) +``` + +### `event.human_pause()` + +人类主动暂停 Agent 时触发(例如通过仪表盘控件)。Agent 被挂起但未终止。 + +```python +agenteye.event.human_pause( + session_id="run-001", + agent_id="planner", + reason="user_requested", # str | None + user_id="usr_42", # str | None - 执行暂停操作的用户 +) +``` + +### `event.human_interrupt()` + +人类在 Agent 执行过程中主动停止 Agent 时触发。与 `human_pause` 不同,此操作会终止 Agent 的工作,而非挂起。 + +```python +agenteye.event.human_interrupt( + session_id="run-001", + agent_id="planner", + reason="output_incorrect", # str | None + user_id="usr_42", # str | None - 执行中断操作的用户 + at_step="tool_use:web_search", # str | None - Agent 被停止时正在执行的操作 +) +``` + +--- + +## 自定义字段 + +任何额外的关键字参数都会附加到事件的标准字段之后: + +```python +agenteye.event.tool_use( + session_id="run-001", + agent_id="planner", + tool_name="db_query", + tool_call_id="toolu_02", + tenant_id="acme", # 自定义字段 + region="us-east-1", # 自定义字段 +) +``` + +`timestamp`、`type` 和 `environment` 为保留字段,若将其作为自定义字段传入,将抛出 `ValueError`(`Reserved field names cannot be used as custom fields: [...]`)。`session_id` 和 `agent_id` 是每个事件方法的必填参数,不能二次传入;若重复传入,Python 会抛出 `TypeError`。请通过 `configure(environment=...)` 或 `AGENTEYE_ENVIRONMENT` 环境变量来设置环境值。 + +--- + +## 事件写入机制 + +事件在进程内缓冲,并每隔 `flush_interval` 秒(默认 500 毫秒)刷新到磁盘。每次刷新写入一个 JSONL 文件: + +``` +~/.agenteye/events/event-2026-04-01T12-00-00-000Z.jsonl +``` + +采集器会监视该目录并自动上传文件。您无需手动管理这些文件。 \ No newline at end of file diff --git a/docs/zh/agenteye/single-pod-deployment.mdx b/docs/zh/agenteye/single-pod-deployment.mdx new file mode 100644 index 00000000..d3837682 --- /dev/null +++ b/docs/zh/agenteye/single-pod-deployment.mdx @@ -0,0 +1,483 @@ +--- +title: "单 Pod 部署:EKS 上的 Collector + 应用 Sidecar" +description: "AgentEye 单 Pod 部署:EKS 上的 Collector + 应用 Sidecar 文档。" +--- + + +将您的应用与 AgentEye collector **部署在同一个 Kubernetes Pod 中**,使遥测数据在采集时无需跨越网络边界。应用的 SDK 与 collector 共享同一个 Pod 内的事件缓冲队列,从而实现低延迟的进程内遥测传递——无需暴露 localhost 端口,无需穿越服务网格,且 collector 的生命周期与其所监测的工作负载直接绑定。collector 所使用的 mTLS 客户端证书直接从 AWS Secrets Manager 注入到您的 Pod 中,因此证书轮换无需手动管理任何文件。 + +本文描述的 sidecar + 共享缓冲队列模型与云平台无关——两个容器共享一个 `emptyDir` 事件缓冲队列可在任意 Kubernetes 发行版上运行。本指南中仅证书交付路径(AWS Secrets Manager + Secrets Store CSI Driver + IRSA)特定于 AWS / EKS。如果您在其他平台上运行,保留 Pod 和缓冲队列的布局,并将第 2 阶段和第 3 阶段中的证书挂载机制替换为您所在平台对应的 Secret 挂载方式即可。 + +> **何时使用此模式。** 当您的应用不应通过网络边界访问 collector 时(低延迟 Pod 内 IPC、紧密的生命周期耦合、按租户的 Pod 隔离),请选择单 Pod 模式。对于每节点或每集群共享一个 collector 的多应用集群,请参阅 [enterprise-docs/kubernetes-deployment.md](/zh/agenteye/kubernetes-deployment)。 + +--- + +## 快速概览 + +``` +┌──────────────────────────────── Pod ─────────────────────────────────┐ +│ │ +│ ┌──────────────────────┐ ┌──────────────────────┐ │ +│ │ your-app │ │ agenteye-collector │ │ +│ │ (SDK writes JSONL) │ │ (sweeps events/, │ │ +│ │ │ │ uploads over mTLS) │ │ +│ └──────────┬───────────┘ └──────────┬───────────┘ │ +│ │ writes reads │ │ +│ ▼ ▼ │ +│ ┌────────────────────────────────────────────────────┐ │ +│ │ emptyDir: /var/lib/agenteye/{events,failed}/ │ │ +│ │ (AGENTEYE_HOME - shared event spool) │ │ +│ └────────────────────────────────────────────────────┘ │ +│ ▲ │ +│ │ reads cert │ +│ ┌────────┴─────────┐ │ +│ │ CSI (read-only): │ │ +│ │ /etc/agenteye/ │ │ +│ │ tls/client.{crt, │ │ +│ │ key}, ca.crt │ │ +│ └────────┬─────────┘ │ +└───────────────────────────────────────────────────┼──────────────────┘ + │ mounted by + │ Secrets Store CSI + │ (AWS provider + + │ IRSA) + ┌────────┴──────────┐ + │ AWS Secrets │ + │ Manager │ + │ agenteye/mtls- │ + │ client/ │ + └────────┬──────────┘ + ▲ + │ push on issue / + │ renewal + ┌────────┴──────────┐ + │ Exosphere │ + │ delivers the cert │ + │ bundle into your │ + │ Secrets Manager │ + │ on renewal │ + └───────────────────┘ + +Outbound: collector → AGENTEYE_URL (mTLS, using the CSI-mounted cert). +``` + +两条数据流,两个存储卷: + +- **事件(Pod 内):** 应用的 SDK 将 `.jsonl` 文件写入共享 `emptyDir` 的 `$AGENTEYE_HOME/events/` 目录;collector 的 sweeper 读取这些文件并上传。无 localhost 端口,无回环网络,纯共享文件系统传递。 +- **mTLS 证书(Pod ← 云端):** Secrets Store CSI Driver 将来自 Secrets Manager 的证书包挂载为只读卷,路径为 `/etc/agenteye/tls/`,仅限 collector 容器访问。 + +**两个独立的责任方:** + +| 责任方 | 职责 | +|---|---| +| Exosphere | 签发 mTLS 客户端证书,并将证书包以固定名称交付到**您的** AWS 账户的 Secrets Manager 中。在证书到期前将续签后的证书包重新发布到同一个 Secret 中。 | +| 您 | 安装 Secrets Store CSI Driver,通过 IRSA 授予 Pod 的 ServiceAccount 读取该 Secret 的权限,并应用 Pod manifest。仅此而已。 | + +--- + +## 前提条件 + +### 在您的 AWS 账户 / EKS 集群中 + +- 一个已关联 **OIDC provider** 的 EKS 集群。使用以下命令确认: + + ```bash + aws eks describe-cluster --name \ + --query "cluster.identity.oidc.issuer" --output text + ``` + + 如果命令返回 `https://oidc.eks.…` 格式的 URL,则 OIDC 已启用。否则,请关联一个: + + ```bash + eksctl utils associate-iam-oidc-provider \ + --cluster --approve + ``` + +- 集群中已安装 [Secrets Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/) 和 [AWS provider](https://github.com/aws/secrets-store-csi-driver-provider-aws)(见第 2 阶段)。 + +- 工作站上已安装 AWS CLI v2 和 `kubectl`。 + +### 与 Exosphere 的协作 + +在部署之前,Exosphere 会将 mTLS 客户端证书包交付到您 AWS 账户的 Secrets Manager 中,并提供: + +- **Secret 名称**(命名规范:`agenteye/mtls-client/`) +- Secret 所在的 **AWS 区域** +- 用于配置 collector 的 **AgentEye 后端 URL** +- 您的 collector **API 密钥**(参见 [enterprise-docs/api-keys.md](/zh/agenteye/api-keys)) + +--- + +## 第 1 阶段:Exosphere 交付的内容 + +您无需自行生成 mTLS 客户端证书。Exosphere 会签发证书并将证书包直接交付到您 AWS 账户的 Secrets Manager 中,因此进入您环境的唯一凭证材料就是这个已就绪、可直接挂载的 Secret。 + +您账户中将收到的内容: + +| 属性 | 值 | +|---|---| +| Secret 名称 | `agenteye/mtls-client/`(在续签过程中保持不变) | +| 区域 | 您为 EKS 集群指定的 AWS 区域 | +| 内容 | 一个包含三个键的 JSON Secret(`client.crt`、`client.key` 和 `ca.crt`),每个键存储 PEM 编码的内容 | +| 标签 | `AgentEyeCluster=` | + +续签时,同一个 Secret 会以新版本原地更新,因此 ARN 和名称永远不会变化;您的 `SecretProviderClass` 和 IAM 策略无需任何修改仍可正常工作。有关证书生命周期(有效期、续签节奏、到期告警)的详细信息,请参阅 [enterprise-docs/kubernetes-deployment.md](/zh/agenteye/kubernetes-deployment)。 + +--- + +## 第 2 阶段:安装 Secrets Store CSI Driver + AWS provider + +如果您的集群中已有其他工作负载通过 CSI 挂载 AWS Secret,请跳过此步骤。 + +```bash +# CSI Driver +helm repo add secrets-store-csi-driver \ + https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts +helm install -n kube-system csi-secrets-store \ + secrets-store-csi-driver/secrets-store-csi-driver \ + --set syncSecret.enabled=true \ + --set enableSecretRotation=true \ + --set rotationPollInterval=1h + +# AWS provider +kubectl apply -f \ + https://raw.githubusercontent.com/aws/secrets-store-csi-driver-provider-aws/main/deployment/aws-provider-installer.yaml +``` + +**验证:** + +```bash +kubectl get pods -n kube-system | grep -E 'csi-secrets-store|aws-provider' +``` + +预期结果:所有 Pod 均为 `Running` 状态。 + +> **为什么设置 `rotationPollInterval=1h`?** 当 Exosphere 发布续签后的证书时,Secrets Manager 会原地更新。CSI Driver 按此间隔重新读取 Secret 并刷新已挂载的文件。collector 仅在启动时读取一次证书文件,因此只有在进程重启后才会开始使用续签后的证书;关于如何触发重启,请参阅「证书轮换」章节。 + +--- + +## 第 3 阶段:授予 Pod 读取 Secret 的权限(IRSA) + +### 3.1 创建 IAM 策略 + +将以下内容保存为 `agenteye-mtls-reader-policy.json`: + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "ReadAgentEyeMtlsBundle", + "Effect": "Allow", + "Action": [ + "secretsmanager:GetSecretValue", + "secretsmanager:DescribeSecret" + ], + "Resource": "arn:aws:secretsmanager:::secret:agenteye/mtls-client/-*" + } + ] +} +``` + +将 ``、`` 和 `` 替换为实际值。末尾的 `-*` 用于匹配 AWS 为每个 Secret ARN 附加的六位随机后缀。 + +创建策略: + +```bash +aws iam create-policy \ + --policy-name AgentEyeMtlsReader- \ + --policy-document file://agenteye-mtls-reader-policy.json +``` + +### 3.2 创建 IAM 角色并绑定到 Pod 的 ServiceAccount + +```bash +eksctl create iamserviceaccount \ + --name agenteye-pod \ + --namespace \ + --cluster \ + --role-name AgentEyePodRole- \ + --attach-policy-arn arn:aws:iam:::policy/AgentEyeMtlsReader- \ + --approve +``` + +此命令会创建一个名为 `agenteye-pod` 的 `ServiceAccount`,并添加 `eks.amazonaws.com/role-arn` 注解指向新创建的角色。 + +### 3.3 所需 IAM 权限汇总 + +| 权限 | 范围 | 用途 | +|---|---|---| +| `secretsmanager:GetSecretValue` | `arn:aws:secretsmanager:::secret:agenteye/mtls-client/-*` | CSI Driver 在每次挂载和轮换轮询时读取证书包。 | +| `secretsmanager:DescribeSecret` | 同上 | CSI Driver 调用 `DescribeSecret` 以在轮询间隔之间检测版本变化。 | + +**请勿授予** Pod `secretsmanager:PutSecretValue`、`secretsmanager:UpdateSecret` 或 `secretsmanager:DeleteSecret` 权限。Pod 只需读取 Secret;向其写入新版本是 Exosphere 在签发或续签证书时负责的事情。 + +如果 Secret 使用客户托管的 KMS 密钥(而非默认的 `aws/secretsmanager` 密钥)加密,还需额外授予: + +```json +{ + "Effect": "Allow", + "Action": ["kms:Decrypt"], + "Resource": "arn:aws:kms:::key/", + "Condition": { + "StringEquals": { + "kms:ViaService": "secretsmanager..amazonaws.com" + } + } +} +``` + +--- + +## 第 4 阶段:部署 Pod + +### 4.1 SecretProviderClass + +`agenteye-mtls-spc.yaml`: + +```yaml +apiVersion: secrets-store.csi.x-k8s.io/v1 +kind: SecretProviderClass +metadata: + name: agenteye-mtls + namespace: +spec: + provider: aws + parameters: + objects: | + - objectName: "agenteye/mtls-client/" + objectType: "secretsmanager" + jmesPath: + - path: '"client.crt"' + objectAlias: "client.crt" + - path: '"client.key"' + objectAlias: "client.key" + - path: '"ca.crt"' + objectAlias: "ca.crt" +``` + +`jmesPath` 块告知 AWS provider 将 JSON Secret 拆分为磁盘上的三个独立文件。`'"client.crt"'` 中的引号写法是必须的,因为 JMESPath 将 `.` 视为子表达式运算符。 + +```bash +kubectl apply -f agenteye-mtls-spc.yaml +``` + +### 4.2 Pod / Deployment manifest + +**两个容器之间的通信方式。** AgentEye SDK 与 collector 之间不通过网络 socket 通信,没有本地 HTTP 端口。SDK 将事件批次以 `.jsonl` 文件的形式写入 `$AGENTEYE_HOME/events/`,collector 持续监视该目录并逐个上传文件。对于 sidecar Pod,这意味着: + +- 两个容器挂载**同一个** `emptyDir` 卷到**相同**路径。 +- 两个容器都将 `AGENTEYE_HOME` 设置为该路径。 +- 您的应用镜像必须已安装并配置了 AgentEye SDK(参见 [enterprise-docs/python-sdk.md](/zh/agenteye/python-sdk))。 + +> 当 `AGENTEYE_HOME` 未设置时,SDK 和 collector 都默认使用 `~/.agenteye`,而两个容器的 home 目录不同,因此它们会落到两个独立的缓冲队列,导致传递静默失败。请在**两个**容器上都将 `AGENTEYE_HOME` 设置为相同的显式路径。第 4.3 节的验证步骤和对应的故障排查条目可以帮助您发现此问题。 + +`agenteye-pod.yaml`(单副本 Deployment,可按需扩展): + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-app-with-collector + namespace: +spec: + replicas: 1 + selector: + matchLabels: + app: my-app-with-collector + template: + metadata: + labels: + app: my-app-with-collector + spec: + serviceAccountName: agenteye-pod + containers: + - name: app + image: + env: + # SDK writes event JSONL files into $AGENTEYE_HOME/events/ + - name: AGENTEYE_HOME + value: /var/lib/agenteye + volumeMounts: + - name: agenteye-spool + mountPath: /var/lib/agenteye + + - name: agenteye-collector + # Pin to a versioned :v tag for production; :beta-latest + # tracks the current beta build (:latest exists only for stable releases). + image: ghcr.io/agenteye-enterprise/collector:beta-latest + args: ["start"] + env: + # Must match the app container's AGENTEYE_HOME so the collector + # sweeps the same directory the SDK writes to. + - name: AGENTEYE_HOME + value: /var/lib/agenteye + - name: AGENTEYE_URL + value: "https://ingest.example.agenteye.com/events" + - name: AGENTEYE_KEY + valueFrom: + secretKeyRef: + name: agenteye-collector-api-key + key: key + - name: AGENTEYE_TLS_CERT + value: /etc/agenteye/tls/client.crt + - name: AGENTEYE_TLS_KEY + value: /etc/agenteye/tls/client.key + # Only when the AgentEye server presents a cert not signed by a + # publicly-trusted CA (e.g. self-signed by an in-cluster issuer + # because you have no real DNS domain). The CSI mount already + # exposes ca.crt alongside the client cert/key. + - name: AGENTEYE_TLS_CA + value: /etc/agenteye/tls/ca.crt + volumeMounts: + - name: agenteye-spool + mountPath: /var/lib/agenteye + - name: agenteye-mtls + mountPath: /etc/agenteye/tls + readOnly: true + livenessProbe: + exec: + command: ["agenteye-collector", "health"] + initialDelaySeconds: 10 + periodSeconds: 30 + + volumes: + # Shared event spool between app and collector. emptyDir is fine: + # events are transient and the collector drains them before pod + # termination on graceful shutdown. + - name: agenteye-spool + emptyDir: {} + # mTLS cert bundle, mounted read-only into the collector only. + - name: agenteye-mtls + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: agenteye-mtls +``` + +`agenteye-collector-api-key` Secret 中存储了 collector 的 API 密钥(关于如何配置,请参见 [enterprise-docs/api-keys.md](/zh/agenteye/api-keys))。 + +**应用:** + +```bash +kubectl apply -f agenteye-pod.yaml +``` + +### 4.3 验证 + +```bash +# Pod 应处于 Running 状态,且 2/2 个容器均已就绪 +kubectl get pods -n -l app=my-app-with-collector + +# 确认证书包已挂载 +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- ls -l /etc/agenteye/tls/ +``` + +预期结果:`client.crt`、`client.key`、`ca.crt` 均存在,均为只读,且归属于容器用户。 + +**确认共享事件缓冲队列对两个容器均可见:** + +```bash +# 在 collector 容器中,应显示 collector 启动时自动创建的 events/ 和 failed/ 子目录: +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- ls /var/lib/agenteye/ + +# 在应用容器中,应显示相同的目录内容: +kubectl exec -n deploy/my-app-with-collector \ + -c app -- ls /var/lib/agenteye/ +``` + +如果两次列出的内容不一致,说明该卷未挂载到两个容器中(或 `AGENTEYE_HOME` 设置不同);请参阅「故障排查」章节。 + +**端到端冒烟测试:** + +```bash +kubectl exec -n deploy/my-app-with-collector \ + -c agenteye-collector -- agenteye-collector flush +``` + +预期结果:collector 上传所有排队中的事件,并打印 `Done: N/N uploaded, 0 failed.` 摘要。如果缓冲队列为空,则打印 `No pending files.` 并退出,此时不会验证任何内容——因此仅在应用至少已刷新一个事件后再运行此命令。 + +请注意,`flush` 仅在出现本地配置故障时才会以非零状态退出:缺少配置(未解析出 URL/密钥)或 TLS 证书不可读/无法解析(请参阅故障排查章节)。**错误的 API 密钥不会改变退出码**——上传会收到 `401` 响应,文件被移至 `failed/`,命令仍会按文件打印 `[FAILED] …` 并输出 `Done: 0/N uploaded, N failed.`,然后以 `0` 退出。要检测错误的密钥或被拒绝的上传,请读取 `Done:`/`[FAILED]` 输出,或检查 `$AGENTEYE_HOME/failed/` 中是否有文件落入,而非依赖退出码。 + +--- + +## 证书轮换 + +客户端证书有效期为 90 天,并在到期约 15 天前自动续签;Exosphere 随后会将续签后的证书包发布到同一个 Secrets Manager Secret 中。此后,Pod 内的流程如下: + +1. Secrets Manager 的 Secret 获得新的 `AWSCURRENT` 版本。ARN 和名称保持不变。 +2. 在 `rotationPollInterval`(默认 1h;参见第 2 阶段)内,CSI Driver 读取新版本并刷新 `/etc/agenteye/tls/` 下的文件。 +3. collector 仅在**启动时**加载一次证书文件,因此在进程重启之前会持续使用之前加载的证书。要切换到续签后的证书,重启 collector 即可;滚动重启就足够了: + + ```bash + kubectl rollout restart deploy/my-app-with-collector -n + ``` + + 若要自动化此操作,可添加一个 sidecar 来监视 `/etc/agenteye/tls/`(例如使用 `inotifywait`),并在文件发生变化时触发滚动更新。 + +由于之前的证书在续签后仍有约 15 天的有效期,您有充足的时间在不中断数据采集的情况下完成重启。Exosphere 会为您发布续签后的证书包;您唯一需要定期执行的操作就是确保 collector 在此窗口期内完成重启。 + +--- + +## 故障排查 + +| 现象 | 可能原因 | 解决方法 | +|---|---|---| +| Pod 卡在 `ContainerCreating` 状态,事件显示 `MountVolume.SetUp failed for volume "agenteye-mtls"` | CSI provider 无法访问 Secrets Manager | 检查 IRSA 是否正确绑定:`kubectl describe sa agenteye-pod -n ` 应显示 `eks.amazonaws.com/role-arn` 注解。检查 CloudTrail 中的 AssumeRole 调用记录。 | +| 错误:`AccessDeniedException: not authorized to perform secretsmanager:GetSecretValue` | IAM 策略的 ARN 范围有误 | Secret ARN 后缀是随机的;请使用带通配符的 `agenteye/mtls-client/-*`,而非精确 ARN。 | +| AWS provider 报错 `ParameterNotFound` | `SecretProviderClass.objects[].objectName` 中的 Secret 名称与 Exosphere 交付的名称不匹配 | 使用 `aws secretsmanager list-secrets --filters Key=tag-key,Values=AgentEyeCluster` 确认确切名称。 | +| `jmesPath` 报错,仅挂载了一个文件 | JMESPath 语法问题 | JSON 键中的点号需要双引号:`'"client.crt"'`,而非 `client.crt`。 | +| collector 在续签后日志显示 `tls: bad certificate` | CSI Driver 尚未轮询到新版本,或 collector 仍在使用启动时加载的旧证书 | 确认挂载的文件已更新(`ls -l /etc/agenteye/tls/`),然后重启 collector 以加载新证书:`kubectl rollout restart deploy/my-app-with-collector -n `。参阅「证书轮换」章节。 | +| collector 容器崩溃循环,报错 `no such file or directory: /etc/agenteye/tls/client.crt` | 首次启动时卷尚未填充完成;启动探针超时过于激进 | 添加适当的初始延迟,或使用 init container 等待文件出现:`until [ -f /etc/agenteye/tls/client.crt ]; do sleep 1; done`。 | +| CSI Driver Pod 出现 `OOMKilled` | 集群中 SecretProviderClass 较多时默认内存限制过低 | 在 Helm 安装时增加 `--set linux.resources.limits.memory=200Mi`。 | +| 应用运行正常,`agenteye-collector flush` 报告 `No pending files.`,但 AgentEye 控制台中无事件显示 | 应用与 collector 未共享事件缓冲队列 | 检查:(a)两个容器是否挂载了同一个 `agenteye-spool` emptyDir 到相同路径;(b)两个容器是否都将 `AGENTEYE_HOME` 设置为该路径。执行第 4.3 节中的两个 `ls /var/lib/agenteye/` 检查,两次输出必须一致。 | + +**优先获取的日志:** + +```bash +kubectl logs -n kube-system -l app=secrets-store-csi-driver --tail=100 +kubectl logs -n kube-system -l app=csi-secrets-store-provider-aws --tail=100 +kubectl describe pod -n -l app=my-app-with-collector +``` + +--- + +## 参考:Pod 内的磁盘文件 + +Pod 内有两条磁盘数据路径: + +### mTLS 证书包:`/etc/agenteye/tls/`(CSI,只读,仅限 collector) + +由 Secrets Store CSI Driver 从 AWS Secrets Manager 挂载。 + +| 文件 | 内容 | collector 使用的环境变量 | +|---|---|---| +| `client.crt` | PEM 编码的客户端证书 | `AGENTEYE_TLS_CERT` | +| `client.key` | PEM 编码的私钥 | `AGENTEYE_TLS_KEY` | +| `ca.crt` | PEM 编码的 CA 证书 | `AGENTEYE_TLS_CA`(可选,仅当 AgentEye 服务端证书未被公共 CA 信任时使用) | + +三个文件均以只读方式挂载,归属于容器用户。Secret 轮换时由 CSI Driver 重新写入。 + +### 事件缓冲队列:`$AGENTEYE_HOME/`(emptyDir,两个容器共享读写) + +通过名为 `agenteye-spool` 的 `emptyDir` 卷共享。 + +| 路径 | 写入方 | 读取方 | 用途 | +|---|---|---|---| +| `$AGENTEYE_HOME/events/*.jsonl` | 应用(AgentEye SDK) | Collector sweeper | SDK 已刷新、等待上传的事件批次。 | +| `$AGENTEYE_HOME/failed/` | Collector(上传失败时) | 您(调试时) | collector 在重试后仍无法上传的 JSONL 文件。 | +| `$AGENTEYE_HOME/config.json` | 您(可选) | Collector | 可选的 collector 配置文件(环境变量的替代方式)。 | + +`events/` 和 `failed/` 子目录均由 collector 在启动时自动创建,无需 `initContainer`。 + +--- + +## 相关文档 + +- [enterprise-docs/collector-installation.md](/zh/agenteye/collector-installation):collector 二进制选项、mTLS 配置参考、守护进程模式。 +- [enterprise-docs/kubernetes-deployment.md](/zh/agenteye/kubernetes-deployment):多 Pod 部署、证书签发内部机制、生命周期与到期告警。 +- [enterprise-docs/api-keys.md](/zh/agenteye/api-keys):配置 Pod 使用的 collector API 密钥。 +- [enterprise-docs/troubleshooting.md](/zh/agenteye/troubleshooting):集群级故障排查索引。 \ No newline at end of file diff --git a/docs/zh/agenteye/tenant-management.mdx b/docs/zh/agenteye/tenant-management.mdx new file mode 100644 index 00000000..cfe0772d --- /dev/null +++ b/docs/zh/agenteye/tenant-management.mdx @@ -0,0 +1,166 @@ +--- +title: "租户管理(组织与成员)" +description: "AgentEye 租户管理(组织与成员)文档。" +--- + +单个 AgentEye 部署可服务于多个完全隔离的**组织**(租户),因此一个实例可以承载不同的团队、业务单元或客户,而不会将任何一个租户的数据暴露给其他租户。每一行数据(事件、评估、会话、仪表板、已保存查询、告警、API 密钥和成员)都归属于唯一一个组织。主要隔离由应用程序代码强制执行:每个请求都通过显式 `org_id` 谓词限定到其所属组织。在 ClickHouse 中——高容量事件和评估数据存储于此——这由强力的引擎级强制措施支撑:每个组织获得一个专用的只读 ClickHouse 用户,并配有按组织划分的行级策略,因此即使是不受信任的分析 SQL 也无法读取其他租户的数据行。在 PostgreSQL 上,行级安全为只读查询路径(`/queries/run`)增加了深度防御,即使应用层过滤器某时缺失,该路径所能访问的内容也会被收窄;服务器自身的写入连接以表所有者身份运行,因此通过相同的应用层 `org_id` 作用域进行操作。 + +租户生命周期由运维人员控制,而成员的日常操作则在仪表板中完全自助完成。组织及其成员关系通过 **`agenteye-orgctl`** CLI 创建和管理,该工具内置于服务器镜像中,并**在现有服务器 Pod 内运行**,因此会读取服务器使用的相同 `DATABASE_URL`、`CLICKHOUSE_URL` 和 `ORG_CH_SECRET`。租户的创建和删除被刻意排除在仪表板和 HTTP API 之外:**没有 HTTP API,也没有仪表板按钮**用于租户生命周期管理,因此它受集群/Pod Shell 访问权限而非应用程序界面的保护。 + +在组织内部,成员完全在仪表板和 API 中工作:他们登录、在所属组织之间切换、管理自己的 API 密钥、构建仪表板和已保存查询,以及为其组织配置告警。职责划分清晰:运维人员通过 CLI 配置和注销租户及其成员;成员则通过 UI 在租户内执行所有操作。 + +> **单租户部署无需进行任何此类操作。** 单租户安装无需任何运维人员操作即可运行。所有数据、用户和密钥都存在于自动配置的内置 `default` 组织中。只有当您决定添加第二个组织时,才需要参阅本指南。 + +--- + +## 前提条件 + +在创建**第二个**组织之前(内置 `default` 组织无需任何操作): + +- **PostgreSQL 15+。** 组织成员关系 schema 使用了列列表 `ON DELETE SET NULL` 外键,需要 PostgreSQL 15+。请在配置第二个组织之前升级 PostgreSQL。 +- **强固且稳定的 `ORG_CH_SECRET`。** 每个组织的 ClickHouse 密码派生自 `HMAC(ORG_CH_SECRET, org_id)`,因此使用公开已知的内置开发默认值会导致每个组织的凭据可被公开推导。`agenteye-orgctl org create` **在 `ORG_CH_SECRET` 未设置或保留内置开发默认值时拒绝运行**。请先设置您自己的值(参见[部署 → 环境变量](/zh/agenteye/deployment),以及在 Kubernetes 上,参见 [Kubernetes 指南的 §2.6](/zh/agenteye/kubernetes-deployment#26-multi-tenant-org-isolation-key-optional))。请在所有服务器副本间保持该值一致,且不要随意轮换;轮换后会使每个组织的 ClickHouse 用户变为孤立状态,直至下次启动重新配置。 + +--- + +## 运行 CLI + +`agenteye-orgctl` 与服务器打包在**同一镜像中**(与 `agenteye-server` 并列)。您**不需要**为其部署独立的 Pod、Job 或 Deployment;只需在已运行的服务器 Pod 内执行它,这样它就能读取服务器使用的相同 `DATABASE_URL`、`CLICKHOUSE_URL` 和 `ORG_CH_SECRET`。 + +**Kubernetes:** + +```bash +kubectl -n agenteye exec deploy/server -- agenteye-orgctl +``` + +**Docker Compose:** + +```bash +docker compose exec server agenteye-orgctl +``` + +以下示例为简洁起见仅显示裸命令 `agenteye-orgctl `;请根据您的部署方式在每条命令前加上上述两行中的对应前缀。 + +--- + +## 命令参考 + +### 组织 + +| 命令 | 说明 | +|---|---| +| `org create --slug --name ` | 创建新组织。在 `ORG_CH_SECRET` 未设置或保留内置开发默认值时拒绝运行(请先设置您自己的值,参见前提条件)。配置该组织的只读 ClickHouse 用户和行级策略。 | +| `org list` | 列出所有组织(slug、名称和生命周期状态)。 | +| `org rename --slug --name ` | 更改组织的显示名称。slug(用于 URL 和密钥)保持不变。 | +| `org delete --slug ` | **软删除**组织并删除其 ClickHouse 用户。数据**保留**。此操作撤销访问权限并释放按组织划分的 ClickHouse 凭据,但不会删除事件数据。可由运维人员恢复;是清除前安全的第一步。 | +| `org purge --slug ` | **不可逆的数据清除。** 组织必须已处于 `delete` 状态。不允许对内置 `default` 组织执行此操作。仅在您确定应销毁租户数据时使用。 | + +### 成员 + +| 命令 | 说明 | +|---|---| +| `member add --org --email [--set ] [--add perm1,perm2] [--remove perm3] [--protected]` | 将成员添加到组织。可选择从内置权限集开始,然后添加/移除单个权限。`--protected` 将该成员标记为受保护,使其无法通过仪表板被移除或降权(见下文)。新成员在首次登录仪表板时会收到一次性密码。 | +| `member list --org ` | 列出组织的成员。输出列为 `EMAIL`、`SET`(成员起始的内置权限集,或 `-`)、`PROT`(成员是否受保护)和 `PERMISSIONS`(其有效权限)。带尾随 `*` 的邮箱表示实例管理员,他们可访问每个组织。 | +| `member update --org --email [--set ...] [--add ...] [--remove ...] [--protected \| --unprotect]` | 更改成员的权限和/或受保护标志。`--set` 从内置权限集替换;`--add` / `--remove` 调整单个权限;`--protected` / `--unprotect` 切换保护状态。仅传递 `--protected`/`--unprotect`(不带授权标志)时,仅更改保护状态,现有权限保持不变。 | +| `member remove --org --email ` | 从组织中移除成员。若成员受保护则拒绝操作;请先执行 `--unprotect`。(一个用户可以是多个组织的成员;此操作仅影响指定组织。) | + +一个用户可以在多个组织中拥有**不同**的权限,例如在一个组织中是管理员,在另一个组织中是只读成员。每个成员关系按组织独立管理:在一个组织中授予或更改某人的权限不会影响其在其他组织中的成员关系。 + +### 受保护成员(不可移除的组织管理员) + +保护机制确保组织永远不会意外地将自己锁定在自我管理之外。默认情况下,组织自己的管理员可以通过仪表板的自助用户页面互相添加和移除,因此他们可能会移除最后一位管理员,导致组织无人能够管理。 + +![用户页面:每位仪表板用户显示为一张卡片,包含其邮箱、已授予权限以及编辑/禁用控件](/agenteye/images/users.png) + +为防止这种情况,将某位成员标记为**受保护**: + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member add --org acme --email owner@acme.example --set admin --protected +``` + +受保护成员**无法通过仪表板被移除或降权**;这些操作会返回错误。只有运维人员才能对其进行更改,且只能通过此 CLI 操作:先运行 `member update --org acme --email owner@acme.example --unprotect`,然后再移除或降权。这确保每个组织至少保留一位其成员无法锁定的管理员,同时将租户控制权仅限于运维人员。保护是**按组织**划分的;保护某人在一个组织中的身份不会影响其在其他组织中的成员关系。 + +### 内置权限集 + +`--set` 接受三个内置权限集之一,按组织应用: + +| 权限集 | 适用对象 | +|---|---| +| `admin` | 组织内的完整访问权限,包括管理组织的 API 密钥和用户。 | +| `standard` | 日常使用:读取和运行查询、构建仪表板、确认事件。 | +| `read-only` | 对组织数据和仪表板的只读访问权限。 | + +使用 `--set` 从权限集开始,然后使用 [API 密钥](/zh/agenteye/api-keys) 中列出的单个权限令牌通过 `--add` / `--remove` 进行微调。权限令牌本身与 API 密钥使用的完全相同。 + +--- + +## 操作示例 + +配置新的 `acme` 租户,添加其首位管理员,让其创建密钥,然后注销组织。 + +**1. 创建组织**(`ORG_CH_SECRET` 必须已设置为强固且稳定的值,不能未设置或使用内置开发默认值): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org create --slug acme --name "Acme Corp" +``` + +**2. 将首位成员添加为组织管理员:** + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member add --org acme --email alice@acme.example --set admin +``` + +Alice 首次登录仪表板时会收到一次性密码。此后她将完全在 UI 中、在其组织的 URL 前缀下工作(例如 `/acme/sessions`)。 + +**3. 创建按组织划分的 API 密钥(在仪表板中):** + +运维人员**不需要**通过 CLI 创建按组织划分的数据密钥。Alice(或任何拥有 `keys:create` 权限的组织成员)可以从仪表板的**密钥**页面为 `acme` 组织创建采集器/仪表板密钥。她创建的每个密钥都会自动标记其所属组织,且只能读写 `acme` 的数据。参见 [API 密钥](/zh/agenteye/api-keys)。 + +**4. 后续调整成员权限:** + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member update --org acme --email alice@acme.example --add alerts:write + +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl member list --org acme +``` + +**5. 软删除组织**(撤销访问权限并删除其 ClickHouse 用户;数据保留): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org delete --slug acme +``` + +**6. 清除组织**(不可逆;仅在软删除后执行;不可对 `default` 组织执行): + +```bash +kubectl -n agenteye exec deploy/server -- \ + agenteye-orgctl org purge --slug acme +``` + +使用 Docker Compose 时,将每条命令的 `kubectl -n agenteye exec deploy/server --` 前缀替换为 `docker compose exec server`。 + +--- + +## 职责划分 + +组织成员日常所需的一切操作均可在仪表板和 API 中自助完成,并自动限定在其当前组织范围内: + +- **按组织划分的 API 密钥**由组织成员在仪表板中创建和管理(或通过携带 `keys:create` 权限的密钥调用密钥 API)。CLI **不**创建数据密钥。参见 [API 密钥](/zh/agenteye/api-keys)。 +- **组织切换**内置于仪表板中;成员可通过组织切换器在所属组织之间切换,组织级页面位于 `//…` 下。 +- **仪表板、已保存查询、告警及所有数据使用**完全在 UI 和 API 中进行,限定在成员当前所属组织范围内。 + +运维人员通过 `agenteye-orgctl` 仅负责组织和成员的**生命周期**管理:创建/重命名/删除/清除组织,以及添加/列出/更新/移除成员。 + +--- + +## 另请参阅 + +- [部署](/zh/agenteye/deployment):`ORG_CH_SECRET` 及其他服务器环境变量。 +- [Kubernetes 部署](/zh/agenteye/kubernetes-deployment):§2.6 在您的首个多租户组织创建之前创建 `agenteye-org-ch-secret` Secret。 +- [API 密钥](/zh/agenteye/api-keys):按组织划分的密钥模型,以及 `--add` / `--remove` 使用的权限令牌。 +- [故障排除](/zh/agenteye/troubleshooting):多租户配置和 ClickHouse 隔离问题。 \ No newline at end of file diff --git a/docs/zh/agenteye/troubleshooting.mdx b/docs/zh/agenteye/troubleshooting.mdx new file mode 100644 index 00000000..6d7fb70a --- /dev/null +++ b/docs/zh/agenteye/troubleshooting.mdx @@ -0,0 +1,656 @@ +--- +title: "故障排查" +description: "AgentEye 故障排查文档。" +--- + + +本指南将生产环境中最常见的故障症状与具体诊断方法和修复步骤一一对应,让你能够直接用现有工具解决问题,无需搭建额外的可观测性基础设施。内容涵盖服务器、采集器、仪表盘、AI 助手、Python SDK、健康与证书监控、备份、ClickHouse 分析后端以及多租户等方面。 + +仪表盘页面的路由以组织为范围,格式为 `//…`,事件流即为组织主页(`//`)。本指南中提到的页面名称(如 `/sessions`、`/queries`)均指上述组织范围内的路由。 + +--- + +## 查看日志 + +AgentEye 不内置日志或监控栈。服务器和仪表盘均将结构化日志写入 **stdout**,因此可以直接通过 `kubectl` 或 `docker` 读取,无需聚合器。 + +### Kubernetes + +实时跟踪服务器和仪表盘的日志: + +```bash +kubectl logs -n agenteye -l app=server -f --timestamps +kubectl logs -n agenteye -l app=dashboard -f --timestamps +``` + +常用变体: + +| 目的 | 命令 | +|---|---| +| 最近 200 行(不跟踪) | `kubectl logs -n agenteye -l app=server --tail=200 --timestamps` | +| 上次崩溃前的日志 | `kubectl logs -n agenteye --previous` | +| 同时跟踪所有副本 | `kubectl logs -n agenteye -l app=server --max-log-requests=10 -f` | +| Postgres(StatefulSet) | `kubectl logs -n agenteye postgres-0 -f` | + +### Docker Compose + +```bash +docker logs -f agenteye-server +docker logs -f agenteye-dashboard +``` + +### 跨仪表盘与服务器关联单个请求 + +每个仪表盘请求都会附带 `request_id`,并通过 `x-request-id` 请求头传递给服务器。服务器会在响应头和该请求的每一行日志中回显该 ID。要端到端追踪某个请求: + +1. 从响应头中获取 ID,例如: + ```bash + curl -i https://dashboard.example.com/api/events | grep -i x-request-id + # x-request-id: 9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a + ``` +2. 在两个 Pod 的日志中 grep 该 ID: + ```bash + REQ=9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a + kubectl logs -n agenteye -l app=dashboard --tail=5000 | grep "$REQ" + kubectl logs -n agenteye -l app=server --tail=5000 | grep "$REQ" + ``` + +你将看到仪表盘的 `proxy passthrough`、`withAuth: authorized`、`upstream response` 日志行,以及服务器的 `http request received` / `http request completed` 日志对,它们共享同一个 `request_id`。 + +### JSON 日志与 `jq` + +在仪表盘上设置 `AE_LOG_JSON=1`(`NODE_ENV=production` 时默认开启),使其每行输出一个 JSON 对象,然后按结构过滤: + +```bash +kubectl logs -n agenteye -l app=dashboard --tail=5000 \ + | jq 'select(.level == "warn" or .level == "error")' + +kubectl logs -n agenteye -l app=dashboard --tail=5000 \ + | jq 'select(.route == "POST /api/keys")' +``` + +Rust 服务器以 `key=value` 格式输出 tracing 日志,无需 `jq` 即可直接 grep: + +```bash +kubectl logs -n agenteye -l app=server --tail=5000 | grep 'status=5' # 5xx +kubectl logs -n agenteye -l app=server --tail=5000 | grep 'actor_key_id=' +``` + +### 提高日志详细程度 + +| 组件 | 环境变量 | 示例 | +|---|---|---| +| 服务器 | `RUST_LOG` | `RUST_LOG=debug` 或 `RUST_LOG=agenteye_server=debug,info` | +| 仪表盘 | `AE_LOG_LEVEL` | `AE_LOG_LEVEL=debug` | + +服务器的 `debug` 级别会为每次认证添加 `api key authenticated` 日志行。仪表盘的 `debug` 级别会添加 `upstream request`、`session validated` 和 `proxy passthrough` 日志行。 + +### 日志保留 + +容器 stdout 是临时性的;kubelet 会轮转日志文件(默认每个容器约 10 MiB),并在磁盘上保留少量文件。Pod 删除后日志即消失。如需更长时间的保留或跨 Pod 搜索,请将集群接入日志采集器(Loki、CloudWatch、Cloud Logging、Datadog 等),令其跟踪 `/var/log/containers/`。AgentEye 不要求也不限定使用任何特定方案。 + +--- + +## 认证问题 + +### `docker pull` 报 "unauthorized" + +请确保已使用 `AGENTEYE_TOKEN` 向 GHCR 认证 Docker: + +```bash +echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin +``` + +该 token 必须具有 `agenteye-enterprise` 组织的 `read:packages` 权限。如果 token 无效,请联系 `support@exosphere.host`。 + +### `gh release download` 返回 404 或 401 + +- 确认 `AGENTEYE_TOKEN` 已在 shell 中导出:`echo $AGENTEYE_TOKEN` +- 确认使用了 `GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download ...`(`gh` CLI 读取 `GITHUB_TOKEN`) +- 该 token 需要对 `agenteye-enterprise/releases` 具有 `contents:read` 权限 + +--- + +## 服务器问题 + +### 服务器启动失败,报 "invalid port number" + +`POSTGRES_PASSWORD`(或其他凭据)包含 URL 特殊字符(`/`、`+`、`=`),导致 `DATABASE_URL` 解析失败。请使用十六进制编码重新生成密码: + +```bash +NEW_PASS=$(openssl rand -hex 24) +``` + +然后更新 Kubernetes Secret 和 Postgres 内部密码(或重新创建 Docker Compose 的 `.env` 文件),并重启服务器。完整步骤请参阅 [enterprise-docs/kubernetes-deployment.md](/zh/agenteye/kubernetes-deployment) 中的 "PostgreSQL credentials" 一节。 + +### 服务器启动后立即退出 + +检查容器日志: + +```bash +docker logs agenteye-server +``` + +常见原因: +- `DATABASE_URL` 未设置或格式错误:服务器会记录错误并退出。 +- Postgres 不可达:确认 Postgres 容器或托管数据库正在运行,且主机/端口配置正确。 +- 迁移失败:检查日志中是否有 SQL 错误。 + +### `GET /health` 返回非 200 或超时 + +服务器在首次启动时可能仍在执行迁移,请等待几秒后重试: + +```bash +curl http://localhost:8080/health +``` + +如果问题持续,请检查 `docker logs agenteye-server` 中的错误信息。 + +### `GET /ready` 返回 503 + +`/ready` 是就绪探针:当服务器无法访问 **Postgres 或 ClickHouse** 时返回 `503`。响应体会指明失败的依赖项: + +```bash +curl -s http://localhost:8080/ready +# {"status":"not_ready","checks":{"postgres":"ok","clickhouse":"down","redis":"ok"}} +``` + +修复响应中报告为 `down` 的依赖项:ClickHouse/Postgres Pod 是否处于 `Running` 状态?`CLICKHOUSE_URL` / `DATABASE_URL` 是否正确且可访问?在 Kubernetes 上,Pod 在 `/ready` 恢复前会显示 `NotReady`,这是预期行为,也正是健康监控告警所依赖的信号。Redis 不会导致就绪失败:它会被上报但不影响就绪判断。 + +### 采集器返回 401 Unauthorized + +采集器的 API key 没有 `events:add` 权限,或该 key 已被禁用。请创建一个具有正确权限的新 key: + +```bash +curl -s -X POST http://your-server:8080/keys \ + -H "Authorization: Bearer $ADMIN_KEY" \ + -H "Content-Type: application/json" \ + -d '{"name":"new-collector","permissions":["events:add"]}' +``` + +### 认证请求突然变慢(~200ms 而非 ~5ms) + +这是 `REDIS_URL` 已设置但 Redis 不可用时的典型症状。每次缓存调用在超时 100ms 后回退到 Postgres;在认证和 OTP 路径上,一次请求会经历两次这样的回退。 + +在服务器日志中确认: + +``` +auth cache: L2 get failed error=redis call timed out +``` + +解决方案: + +1. 执行 `redis-cli -h ping`,确认 Redis 在集群网络上可达。 +2. 如果 Redis 曾短暂不可用现已恢复,请**重启服务器 Pod**。`redis::aio::ConnectionManager` 在底层连接断开后无法可靠重连;重启 Pod 会重新建立干净的连接。仪表盘同理。 +3. 如果暂时不想运行 Redis,请在部署配置中取消设置 `REDIS_URL` 并重启。两个服务在没有缓存的情况下也能正常运行(正确性不受影响;延迟回退到引入 Redis 前的基准水平)。 + +### 服务器日志显示 `OTP request rate-limited`,但用户说只尝试了一次 + +检查 Redis 是否不可达。回退路径使用 `SELECT COUNT(*) FROM otp_codes WHERE created_at > now() - interval '15 minutes'`,会查到之前生成的 OTP 记录。如果用户在过去一小时内一直点击"重新发送",15 分钟窗口内可能仍存在 ≥5 条记录。解决方案:等待窗口滚动,或执行 `DELETE FROM otp_codes WHERE user_id = $1 AND created_at > now() - interval '15 minutes'`(操作员控制台)。 + +### 修改了 `ALLOWED_EMAILS` / `SESSION_TTL_SECS` / `OTP_TTL_SECS` 并重启后没有任何变化 + +这些环境变量**仅在首次启动时作为种子值使用**。一旦 `settings` 表中已有对应 key 的行,该行即为真实来源;环境变量在首次启动时读取一次,此后每次重启均被忽略。 + +若需在首次启动后修改,请登录仪表盘并在 `/settings` 页面编辑。修改会在数秒内在所有副本上生效,无需重启。 + +如需强制从环境变量重新初始化(罕见,通常仅用于开发环境),请执行 `DELETE FROM settings WHERE key = ''` 并重启服务器。服务器在下次启动时会读取当前环境变量的值。在生产环境中,推荐通过 `/settings` 页面编辑。 + +--- + +## 采集器问题 + +### 采集器已启动,但事件未出现在仪表盘中 + +1. 确认采集器正在运行:`systemctl status agenteye-collector`(Linux)或检查进程状态。 +2. 确认 `AGENTEYE_URL` 指向 `http(s)://your-server-host:8080/events`(注意:需包含 `/events` 路径)。 +3. 执行一次性强制上传,查看即时输出: + ```bash + agenteye-collector flush + ``` +4. 检查 Python SDK 是否正在写入文件:`ls ${AGENTEYE_HOME:-~/.agenteye}/events/` +5. 如果 `${AGENTEYE_HOME:-~/.agenteye}/failed/` 中存在文件,说明上传失败。检查采集器日志中的错误信息,通常是 4xx(key 错误或 URL 错误)或网络问题。 + +### 文件在 `$AGENTEYE_HOME/events/` 中堆积,未被上传 + +- 采集器可能未在运行。启动它:`agenteye-collector start`;它会在启动时自动上传已有的事件文件。 +- 检查采集器健康状态:`agenteye-collector health` +- 采集器可能正在运行但无法访问服务器。检查采集器主机与服务器主机之间的防火墙规则。 + +### `$AGENTEYE_HOME/failed/` 中存在文件 + +文件在所有重试尝试耗尽后(默认:5 次,指数退避)移至 `failed/`。这意味着: +- 服务器返回了 4xx 错误(key 错误、URL 错误或负载问题) +- 在整个重试窗口期间服务器不可达 + +修复根本原因后,手动重新排队: + +```bash +mv ${AGENTEYE_HOME:-~/.agenteye}/failed/*.jsonl ${AGENTEYE_HOME:-~/.agenteye}/events/ +agenteye-collector flush +``` + +### 采集器每次上传都报 `network error`(TLS 握手失败) + +如果对 `AGENTEYE_URL` 执行 `curl -k` 成功,但采集器二进制文件每次上传都报 `error sending request for url (...)`,说明 AgentEye 服务器提供的 TLS 证书不是由公信 CA 签发的。 + +**生产路径**是在 `deploy/base/certificates/domain.env` 中配置的 ACME 入站主机名(参见 [`kubernetes-deployment.md`](/zh/agenteye/kubernetes-deployment) 第 3.1 / 4.2 阶段)。一旦 `INGEST_DOMAIN` 解析到公网 Traefik LB 且 cert-manager 已颁发 Let's Encrypt 证书,采集器将使用系统信任存储验证服务器证书,**无需设置 `AGENTEYE_TLS_CA`**;如果之前针对旧的自签名部署设置过该配置,请清除它。 + +**症状:采集器昨天还正常,今天(约 90 天后)突然失败。** 这意味着集群的 `ingest-tls` 仍在使用旧版 `selfsigned` 颁发者。90 天证书已轮换,固定的 CA 文件已过期。永久修复方案:将集群切换到 ACME 颁发者(部署指南第 3.1 阶段)。短期解决方案:重新提取当前服务器证书并更新 `AGENTEYE_TLS_CA`: + +```bash +kubectl get secret ingest-tls-cert -n agenteye \ + -o jsonpath='{.data.tls\.crt}' | base64 -d > /etc/agenteye/server-ca.crt +``` + +```bash +export AGENTEYE_TLS_CA=/etc/agenteye/server-ca.crt +agenteye-collector flush +``` + +`AGENTEYE_TLS_CA` 会添加一个额外的信任锚点;标准公共根证书仍然受信任。 + +### 部署后 `ingest-tls` 证书一直处于 `Ready: False` + +```bash +kubectl describe certificate ingest-tls -n agenteye +``` + +查看 `Events` 以及关联的 `Order` / `Challenge`。常见原因: + +- **DNS 未解析到公网 LB。** HTTP-01 验证器无法访问 `INGEST_DOMAIN`。使用 `dig +short INGEST_DOMAIN` 验证;它应解析到与 `traefik-public` LoadBalancer 的 `EXTERNAL-IP` 相同的地址。DNS 传播完成后 cert-manager 会自动重试,无需删除 Certificate 资源。 +- **端口 80 在负载均衡器/安全组处被封锁。** HTTP-01 验证要求端口 80 对 Let's Encrypt 的公共验证器可访问。如果上游 WAF 或安全组限制了 `:80`,请开放它(Traefik 配置会重定向到 HTTPS,但 Boulder 会跟随重定向并接受响应)。 +- **`dnsNames` 未被替换。** 如果 `kubectl get certificate ingest-tls -n agenteye -o jsonpath='{.spec.dnsNames}'` 显示 `INGEST_DOMAIN_PLACEHOLDER`,说明你跳过了 `domain.env` 步骤;请从 `domain.env.example` 创建该文件并重新应用。 +- **被 Let's Encrypt 限流。** 对同一主机名反复失败的申请会触发重复证书或验证失败限制。请至少等待一小时后再重试;检查 Order 状态以获取确切的限流信息。 + +### `dashboard-tls` 证书一直处于 `Ready: False` / 浏览器仍显示警告 + +诊断流程与上述 `ingest-tls` 相同(`kubectl describe certificate dashboard-tls -n agenteye`);DNS、端口 80、占位符和限流原因同样适用,此外还有两个仪表盘专有原因: + +- **`DASHBOARD_DOMAIN` 解析到错误的 LoadBalancer。** 它必须指向*仪表盘* Traefik LB,而非公网入站 LB。对主机名执行 `dig +short` 并与仪表盘 LB 地址对比。 +- **仪表盘 Traefik 实例无法响应验证请求。** 必须使用附带的仪表盘 values 文件安装该实例,它会为 cert-manager 的 HTTP-01 解析器启用范围限定的 Ingress provider。没有它,解析器无法路由,Order 会一直处于 `pending` 状态。使用提供的 values 文件升级该实例,待处理的验证请求随后会自动完成。 +- **LoadBalancer 设置了 IP 限制。** 源 IP 范围限制同样适用于端口 80,这会阻止 Let's Encrypt 的验证器访问——无论是首次颁发还是约每 75 天的续期。请重新开放 LB,或在锁定之前与支持团队协商使用 DNS-01 解析器。 + +在证书颁发失败期间,仪表盘会继续提供之前的证书(或全新安装时 Ingress 的默认证书)——访问体验会因浏览器警告而降级,但不会完全不可用。 + +### 仪表盘获得受信任证书后,CLI 仍跳过 TLS 验证 + +`--insecure` 标志在登录时会持久化到 `cli.json`。一旦仪表盘提供公信证书,请使用 `agenteye --base-url https:// --secure login` 重新登录;验证选项会被保存为开启状态,启动时的警告也会消失。 + +--- + +## 仪表盘问题 + +### 无法禁用或编辑 `ADMIN_EMAIL` 用户 + +这是设计行为。匹配 `ADMIN_EMAIL` 的用户在每次服务器启动时都会被标记为受保护:仪表盘会在该行隐藏"禁用"按钮,且 API 会以 `403 Forbidden` 拒绝针对该用户的 `DELETE /users/:id` 和 `PUT /users/:id` 请求。数据库触发器也会拒绝直接禁用受保护行的 `UPDATE` 语句。 + +若要轮换引导管理员,请在环境变量中修改 `ADMIN_EMAIL` 并重启服务器。新邮箱会被 upsert 为受保护状态。之前的管理员会保留受保护标志,直到在数据库中手动清除(通常无需处理,因为之前的邮箱在你明确删除之前仍是有效的管理员)。 + +### 仪表盘不显示事件 + +1. 确认仪表盘环境变量中的服务器 URL 和 API key 配置正确(`AGENTEYE_SERVER_URL`、`AGENTEYE_API_KEY`)。 +2. 仪表盘 API key 需要 `events:read` 权限。 +3. 确认事件已被实际采集:`curl http://your-server:8080/events -H "Authorization: Bearer $ADMIN_KEY"` + +### `/errors` 为空,但 `/events` 显示红色行 + +较新版本的 SDK 将失败事件作为 `agent_end` / `tool_result` / `hook_completed` 类型、`outcome: "error"` 的事件发送,而非专门的 `event_type: "error"` 行。`/errors` 页面现在同时匹配两种情况:`/events` 流中任何标红的行(显式 `event_type='error'`、payload 的 `outcome`/`status` 属于失败集合、`is_error: true`,或 `error` 字段为真值)都会出现在 `/errors` 中。如果你之前在 `/events` 有红色行的同时看到"此窗口内无错误",请同时升级仪表盘和服务器(扩展后的过滤条件为 `GET /events` 上的 `errored=true`),两个视图将保持一致。 + +### `/models`、`/tools` 或 `/hooks` 在宽时间范围下加载缓慢或失败 + +**症状:** 在大型事件表(数百万行)上,打开 `/models`、`/tools` 或 `/hooks`,或将时间范围拓宽至 `7d`、`30d` 或 `all` 时,图表转圈后显示加载错误。服务器日志中记录了 `latency_aggregate` 请求的 ClickHouse `MEMORY_LIMIT_EXCEEDED`(Code 241)或查询超时。 + +**原因:** 旧版本在计算这些页面的延迟和分布汇总时,会读取完整的原始事件 `payload` 并通过内存排序和关联来配对请求/响应事件。查询峰值内存因此随窗口大小增长,在繁忙的租户上,宽时间范围可能超过 ClickHouse 的单查询内存上限。 + +**修复:** 升级到包含此修复的版本。汇总查询现在只读取紧凑的提升列,并通过流式聚合来配对事件,因此峰值内存不再随原始 payload 增长——宽时间范围也能保持在内存上限之内,且响应时间大幅缩短。该改进完全在查询层实现:无需重新采集或回填数据,下次页面加载时即对所有现有数据生效。 + +### 仪表盘加载失败 / 空白页面 + +检查仪表盘容器日志: + +```bash +docker logs agenteye-dashboard +``` + +最常见的原因是 `AGENTEYE_SERVER_URL` 或 `AGENTEYE_API_KEY` 缺失,或指向了不可达的服务器。 + +### 仪表盘分析 / 遥测 + +仪表盘默认会向 PostHog 发送匿名产品使用分析数据,通过仪表盘自身的 `/ingest` 路径(反向代理到 `https://us.i.posthog.com`)路由。以第一方方式发送可防止浏览器广告拦截器阻断它们。这与仪表盘的核心功能无关: + +- **仪表盘容器**(而非浏览器)负责访问 PostHog。如果其到 `https://us.i.posthog.com` 的出站访问被阻断,遥测会静默失效;仪表盘正常运行,用户不会看到任何错误。 +- 不会包含任何 Agent、会话或事件数据,仅包含仪表盘 UI 使用情况。 +- 若要完全禁用遥测,请在仪表盘容器上设置 `AE_ANALYTICS_DISABLED=1` 并重启。详见部署指南中的[遥测与隐私](/zh/agenteye/deployment#telemetry--privacy)。 + +### CLI 分析 / 遥测 + +`agenteye` CLI 默认向 PostHog 发送匿名使用分析数据:执行的命令、成功/退出状态和耗时。这与 CLI 的功能无关: + +- **运行 CLI 的机器**直接访问 `https://us.i.posthog.com`。如果出站访问被阻断,遥测会静默失效(发送有时间限制,不会延迟命令执行),CLI 正常运行。 +- 不会包含任何 Agent、会话或事件数据:命令**参数和标志值**(仪表盘 URL、token、邮箱、会话 ID、查询过滤器)绝不会被发送。 +- 若要禁用,请在 CLI 的环境中设置 `AGENTEYE_ANALYTICS_DISABLED=1`(或跨工具通用的 `DO_NOT_TRACK=1`)。详见 CLI 指南中的[遥测与隐私](/zh/agenteye/cli#telemetry--privacy)。 + +--- + +## AI 助手问题 + +完整设置请参阅 [enterprise-docs/assistant.md](/zh/agenteye/assistant)。 + +### 助手气泡未出现 + +气泡仅在以下**所有**条件均满足时才会显示: + +- 已登录用户具有 `agent:use` 权限。 +- 仪表盘上已设置 `AGENTEYE_AGENT_URL`,且 `agent` 服务可达。 +- `agent` 服务上已配置 LLM 端点(`ANTHROPIC_API_KEY`、通过 `ANTHROPIC_BASE_URL` 的网关,或 Bedrock/Vertex)。如果都未设置,agent 会报告"未配置",气泡保持隐藏。 + +从仪表盘主机检查 agent 的健康状态:`curl http://agent:9100/health` 应返回 `{"status":"ok","llm_configured":true,...}`。 + +### 助手提示无法读取某些内容 + +工具按用户设置门控权限。如果用户缺少 `evaluations:read`(或 `events:read`、`dashboards:read`),对应工具不会被提供,助手会提示无法读取该数据。请授予相关读取权限。 + +### 发送消息时报 "assistant not configured"(HTTP 503) + +`agent` 容器未配置 LLM 端点,或仪表盘的 `AGENTEYE_AGENT_TOKEN` 与 agent 的 token 不匹配。请同时设置并重启。 + +### `agent` 容器在负载下重启 / OOM + +每个对话会生成一个短生命周期的子进程。确保容器以 init 进程运行(镜像使用 `tini`;在 Compose 中设置 `init: true`),并提供足够的内存限制。如有需要,可降低 `AGENTEYE_AGENT_MAX_STEPS`。 + +--- + +## CLI 问题 + +### `agenteye` 启动失败,报 `ModuleNotFoundError: No module named 'click'` + +**0.1.6** 版本的 `agenteye` CLI 在全新安装后可能在启动时崩溃: + +``` +ModuleNotFoundError: No module named 'click' +``` + +0.1.6 依赖 `typer` 间接安装 `click`;而当前 `typer` 版本不再隐式引入 `click`,导致全新环境中缺少该包。**请升级到 0.1.7 或更新版本**,该版本直接依赖 `click`: + +```bash +pipx upgrade agenteye # 如果通过 pipx 安装(或:pipx install --force agenteye) +uv tool upgrade agenteye # 如果通过 uv 安装 +pip install --upgrade agenteye +``` + +安装指南请参阅 [enterprise-docs/cli.md](/zh/agenteye/cli)。 + +--- + +## Python SDK 问题 + +### `$AGENTEYE_HOME/events/` 中没有文件出现 + +SDK 默认每 500ms 缓冲并刷新一次事件。如果进程在刷新前退出,事件可能丢失。对于短生命周期脚本,请调用 `agenteye.configure(flush_interval=0.1)` 加快刷新速度,或确保进程运行时间足够完成一次刷新周期。 + +如果已设置 `AGENTEYE_HOME`,请确认 SDK 写入的是 `$AGENTEYE_HOME/events/` 而非 `~/.agenteye/events/`(需要 SDK ≥ 0.0.1b5)。 + +### `ValueError: Reserved field names cannot be used as custom fields` + +`timestamp`、`type` 和 `environment` 是保留名称,不能用作自定义字段。传递其中任何一个都会抛出: + +``` +ValueError: Reserved field names cannot be used as custom fields: [...] +``` + +请重命名相关自定义字段。注意 `session_id` 和 `agent_id` 是事件调用的显式参数,而非自定义字段;将它们作为自定义字段再次传递会抛出 `TypeError`。 + +--- + +## 健康监控问题 + +### Slack 未收到告警(Robusta) + +Robusta 健康告警需要**手动启用**;在安装并指向 Slack 频道之前不会发送任何内容。验证 release 及其 sink: + +```bash +kubectl get pods -n robusta # robusta-runner + robusta-forwarder 应处于 Running 状态 +kubectl logs -n robusta -l app=robusta-runner --tail=50 +``` + +常见原因:Slack `api_key` / `slack_channel` 未设置(或 token 已被吊销);`api_key` 是 Robusta 云中继 token(`robusta integrations slack`),但附带的 `disableCloudRouting: true` 需要自托管的 Slack **bot token**(`xoxb-…`),或者将 `disableCloudRouting` 设为 `false`;sink 的 `scope` 排除了你的 Pod 所在的命名空间(附带的 values 文件将范围限定为 `agenteye`);或者尚未发生任何故障。通过下线一个 Pod 强制触发测试告警: + +```bash +kubectl -n agenteye delete pod -l app=clickhouse # 它会被重新创建 +``` + +安装和配置说明请参阅 [enterprise-docs/health-monitoring.md](/zh/agenteye/health-monitoring#2-pod-failure-alerting-with-robusta-opt-in)。 + +### 服务器持续在 `NotReady` 状态反复横跳 + +就绪探针会访问 `/ready`,当 Postgres 或 ClickHouse 不可达时会失败。如果服务器在 `NotReady` 状态间反复切换,说明某个依赖项间歇性不可用;请检查 ClickHouse 和 Postgres Pod 以及服务器的 `CLICKHOUSE_URL` / `DATABASE_URL`。确认 `/ready` 报告的内容: + +```bash +kubectl -n agenteye exec deploy/server -- sh -c 'curl -s localhost:8080/ready' +``` + +该探针设计上具有一定容忍度(较大的失败阈值),因此持续的状态抖动表明存在真实的依赖项问题,而非探针配置过于激进。存活探针保持在 `/health` 上,因此就绪状态抖动**不会**重启 Pod。 + +## 证书监控问题 + +### CronJob 未发送 Slack 通知 + +`cert-renewal-check` CronJob 需要将 Slack webhook URL 存储在 Secret 中。验证它是否存在: + +```bash +kubectl get secret cert-renewal-notify-config -n agenteye +``` + +如果不存在,请创建: + +```bash +kubectl create secret generic cert-renewal-notify-config \ + --namespace agenteye \ + --from-literal=SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL" +``` + +没有该 Secret,CronJob 仍会运行并将结果记录到 stdout。通过以下命令检查日志: + +```bash +kubectl logs -n agenteye -l job-name --tail=50 +``` + +### 客户端证书在收到通知前已过期 + +CronJob 每 12 小时运行一次。如果它一直未运行,请检查其状态: + +```bash +kubectl get cronjob cert-renewal-check -n agenteye +``` + +触发手动检查: + +```bash +kubectl create job --from=cronjob/cert-renewal-check manual-cert-check -n agenteye +kubectl logs -n agenteye -l job-name=manual-cert-check +``` + +若要立即重新颁发已过期的证书: + +```bash +cd base/certificates/client-certs +./issue-client-cert.sh +``` + +然后在运行采集器的集群中应用重新生成的 `collector-mtls-secret.yaml` 并重启: + +```bash +kubectl apply -f collector-mtls-secret.yaml -n +``` + +--- + +## 备份问题 + +### `agenteye-backup` 报 "No space left on device" + +`agenteye-backup` CronJob 将 Postgres + ClickHouse 转储到 `backup-tmp` `emptyDir` 临时卷(默认 `30Gi`),然后**流式**将 `tar` 归档直接上传到 S3——压缩归档文件不会写回临时卷,因此临时卷只需容纳*原始转储文件*,而非转储文件加一份归档副本。Pod 被驱逐 / 报 `No space left on device` 意味着**原始转储文件**超出了临时卷大小(ClickHouse `events` 转储文件占主导,且随时间增长)。检查失败 Job 的日志: + +```bash +kubectl logs -n agenteye -l job-name= +``` + +修复方案:在你的 overlay 中,将 CronJob 的 `backup-tmp` `emptyDir` 的 `sizeLimit` 提高到超过原始转储总量,并确认节点的临时存储实际上能容纳这些数据(`sizeLimit` 是上限,而非预留量)。如果转储量超过单个节点的磁盘容量,请用 PVC(EBS/PD)替换 `backup-tmp` 的 `emptyDir`,或在源头压缩转储文件。 + +> 旧版本会将 `.tar.gz` 写入与转储文件相同的 `20Gi` 临时卷,导致 `转储文件 + 归档文件` 溢出,Pod 在上传前就被驱逐——表现上像 S3 故障,实际上是磁盘问题。流式上传消除了这种空间翻倍问题。 + +### `agenteye-backup` 安装 `curl` 失败 + +该 Job 在 `postgres:16` 镜像上运行,并在启动时安装 `curl` 以执行 ClickHouse HTTP 转储。在没有到 Debian 软件包镜像出站访问的集群上,`apt-get` 步骤会失败。请允许备份 Pod 的出站访问,或将 `curl` 预装到镜像副本/自定义备份镜像中,并在 overlay 中引用该镜像。 + +### `agenteye-backup` 运行但对象存储中没有文件 + +基础配置内置了真实的 `BACKUP_BUCKET`(`ts-prod-agenteye/backups`)和 `agenteye-backup` ServiceAccount。该 Job **流式**将归档上传到 S3(`tar cz … | aws s3 cp - s3://…`)。如果备份 Pod 没有该存储桶的写入权限,上传会报错——由于脚本在 `set -euo pipefail` 下运行,管道中任何位置的失败都会在 `upload` 步骤导致整个 Job 失败,而非静默失效(Pod 的 EXIT trap 会记录 `backup FAILED during step: upload`)。这也是修复临时卷驱逐问题后你会遇到的步骤,因此如果备份之前在归档步骤被驱逐,请验证上传现在是否成功。在失败 Job 的日志中搜索 S3 访问错误: + +```bash +kubectl logs -n agenteye -l job-name= | grep -iE 's3|upload|denied' +``` + +修复方案:在你的 overlay 中将 `BACKUP_BUCKET` 设置为你拥有的存储桶,并为现有的 `agenteye-backup` ServiceAccount 添加写入权限注解(IRSA / Workload Identity / Pod Identity)。详见 [enterprise-docs/kubernetes-deployment.md](/zh/agenteye/kubernetes-deployment) 中的**备份**章节。 + +--- + +## ClickHouse 支持的评估 / 会话 / 查询 + +### 升级后 `/queries` 页面侧边栏为空 + +预期存在三张表(`events`、`evaluations`、`agent_sessions`)。如果升级后 SchemaBrowser 侧边栏为空,说明服务器在启动时未能应用 ClickHouse DDL。检查服务器日志中的 `failed to apply CH DDL statement`: + +```bash +kubectl logs -n agenteye deploy/server | grep -E 'clickhouse|CH DDL' +``` + +最常见的原因是迁移运行期间 ClickHouse 不可达。服务器在无法访问 ClickHouse 时会拒绝启动,因此卡住的 Pod 通常处于 `CrashLoopBackOff` 状态,而非出现静默损坏的查询页面。但部分 DDL 应用(某条语句成功,后续报 5xx)会导致 schema 处于不完整状态。在确认 ClickHouse 可达后,重启服务器 Pod: + +```bash +kubectl rollout restart deploy/server -n agenteye +``` + +### 新评估未出现在 `/sessions` 或 `/queries` 中 + +升级后,新评估被写入 ClickHouse 而非 Postgres,并在 `/sessions`(需要 `evaluations:read` 权限)和 `/queries` 中显示。如果未出现: + +1. 确认评估器管道已启用(服务器上已设置 `EVALUATOR_ENDPOINT`)且正在产生终止结果;检查是否有 `evaluation_finalized` 日志行。 +2. 确认服务器可访问 ClickHouse:`kubectl exec -n agenteye deploy/server -- curl -fsS http://clickhouse:8123/ping`。 +3. 抽查 ClickHouse 表:`kubectl exec -n agenteye clickhouse-0 -- clickhouse-client -q 'SELECT count() FROM agenteye.evaluations'`。 + +### 负载下查询报 "Memory limit exceeded",或 ClickHouse 被 `OOMKilled` + +**症状:** 在仪表盘/查询负载较重时,分析页面(事件流、`/sessions`、模型/延迟视图、SQL 编辑器)开始失败或超时;服务器短暂抖动至 `NotReady`;ClickHouse Pod 的重启次数持续上升。这几乎总是**内存**问题,而非 CPU 或磁盘问题。 + +**确认是内存问题**(而非可通过复制解决的吞吐量问题): + +1. 检查 Pod 是否因内存不足被杀: + ```bash + kubectl -n agenteye describe pod clickhouse-0 | grep -iE 'Restart Count|Last State|Reason|OOMKilled' + ``` + `Reason: OOMKilled` / `Exit Code: 137` 加上持续上升的重启次数是明确信号。 + +2. 查询 ClickHouse 正在拒绝的内容: + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT name, value FROM system.errors WHERE value>0 ORDER BY value DESC" + ``` + `MEMORY_LIMIT_EXCEEDED` 计数较大是典型特征。错误消息中显示 *"maximum: N GiB"*——该 **N 值为 Pod 内存限制的 `0.9` 倍**(即 `deploy/base/clickhouse/configmap.yaml` 中的 `max_server_memory_usage_to_ram_ratio`)。如果繁重的读取需要超过 N 的内存,请求就会被拒绝。 + +3. 排除*不是*问题的因素——如果 CPU、part 数量和磁盘都较低,增加副本/分片只是浪费成本: + ```bash + kubectl -n agenteye top pod clickhouse-0 + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT table, count() parts FROM system.parts WHERE active AND database='agenteye' GROUP BY table" + ``` + +**原因:** ClickHouse Pod 的内存限制对于分析工作集来说太小。最繁重的读取操作会拉取原始 JSON `payload` 列,对其运行 `JSONExtract*`,并使用 `FINAL`——每项操作都可能需要数 GiB 内存。如果配置的缓存(`mark_cache_size` + `uncompressed_cache_size`)大于 Pod 内存,问题会加剧:缓存和查询内存共享同一预算,缓存会挤占查询内存。 + +**修复——扩展 ClickHouse 内存:** + +1. 在 overlay 中通过 patch `clickhouse` StatefulSet 容器的 `resources` 来提高 ClickHouse 内存限制(与其他组件 `resources` 使用相同的 overlay 机制)。可用的服务器预算为 `0.9 × 限制`,因此 `6Gi` 限制提供约 5.4 GiB,`16Gi` 限制提供约 14 GiB。同时将 `requests.memory` 设置为实际下限,让调度器进行预留。应用此配置**会重新创建 ClickHouse Pod**(单副本约有 30–60 秒的分析停机);请在低流量时段操作。 +2. 保持 `deploy/base/clickhouse/configmap.yaml` 中缓存与内存限制的比例——在小 Pod 上,小缓存(几百 MiB)是安全的;仅在同时提高内存限制时才增大缓存。`users.xml` profile 中显式设置了单查询的 `max_memory_usage`(见下文固定节点章节),并保持在服务器级上限(`0.9 × 限制`)以下,确保没有单个查询被允许使用超过容器拥有的内存。 +3. 如果节点本身是瓶颈,检查 ClickHouse 可见的主机内存: + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT formatReadableSize(value) FROM system.asynchronous_metrics WHERE metric='OSMemoryTotal'" + ``` + 如果该值仅略高于 Pod 限制,请在进一步提高限制之前,通过 overlay 中的节点选择器/亲和性将 ClickHouse 迁移到更大的(内存优化型)节点。 + +**无法增加内存时:让查询在内存中运行并快速失败——不要在慢速磁盘上溢出。** 如果节点固定且 Pod 无法扩容,请限制每个查询可使用的内存上限(避免单个查询耗尽整个节点),并且在**慢速(非 SSD)数据磁盘**上,**不要**让大型聚合/排序溢出到磁盘。在慢速磁盘上溢出比服务器的客户端读取超时还慢,溢出查询会在仪表盘返回 `500` 后继续在 ClickHouse 中执行——将查询保持在内存中并快速拒绝偶尔超预算的查询(`MEMORY_LIMIT_EXCEEDED`,亚秒级)才能恢复正常加载。应用这些配置时需注意 ClickHouse 的一个陷阱: + +- **这些是 *profile* 配置,ClickHouse 只从 `users_config`(`users.xml` / `users.d/*.xml`)读取 `` 块——绝不从 `config.d` 读取。** 放置在 `config.d/agenteye.xml` 中的 `` 块会**被静默忽略**(`max_execution_time`、`max_memory_usage` 等根本不会生效)。因此,附带的配置将它们作为 `users.xml` key 放在 `clickhouse-config` ConfigMap 中,挂载到 `/etc/clickhouse-server/users.d/agenteye.xml`。 +- 内置默认值:`max_memory_usage`(单查询上限——单个查询不能消耗整个服务器预算)、`max_bytes_before_external_group_by` / `max_bytes_before_external_sort` = **`0`(禁用溢出)**,使查询保持在内存中而不在慢速磁盘上爬行,以及 `max_execution_time`(失控保护,与服务器的客户端读取超时对齐)。 +- **验证配置已生效**(这也是检测 config.d 陷阱的方法): + ```bash + kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \ + "SELECT name, value FROM system.settings + WHERE name IN ('max_memory_usage','max_bytes_before_external_group_by','max_execution_time')" + ``` + 期望看到非零的 `max_memory_usage` 和 `max_bytes_before_external_group_by = 0`。如果 `max_memory_usage` 读取为 `0`/默认值,说明 profile 未被应用——检查配置是否在 `users.d` 挂载中,而非 `config.d`。 + +权衡:禁用溢出后,工作集超过 `max_memory_usage` 的查询会被**拒绝**(`MEMORY_LIMIT_EXCEEDED`),而非缓慢完成——在慢速磁盘上,这种快速拒绝更可取,因为溢出查询无论如何都会超过客户端超时而失败。如果你的数据磁盘**速度快(SSD)**,可以提高 `max_bytes_before_external_*` 阈值,允许大型查询溢出到磁盘并完成。 + +--- + +## 多租户(组织) + +### 启用组织的升级过程中出现错误(新旧服务器 Pod 混合) + +**症状:** 在滚动部署启用组织功能的版本时,部分请求失败:服务器日志在 `api_keys` 路径上显示 `there is no unique or exclusion constraint matching the ON CONFLICT specification`,以及/或告警/Slack/webhook 频道在滚动发布期间停止触发。 + +**原因:** 该升级将 `api_keys(name)` 上的旧实例级唯一索引替换为按组织划分的部分索引,并将告警频道配置(以及 `default_user_permissions`)从全局 `settings` 表迁移到每个组织的 `org_settings`。**旧版**服务器 Pod 仍然发出 `ON CONFLICT (name)`(现在没有匹配的约束)并从旧的 `settings` 行(现在为空)读取频道配置。新旧 Pod 对这两条路径无法安全共存。 + +**修复:** 不要对这次特定升级进行跨版本的慢速滚动。请彻底切换:将旧版服务器缩容至零(或使用短暂的维护窗口),与迁移一起启动新版本,而非同时运行新旧副本。切换完成后流量和采集立即恢复;这只影响版本过渡窗口。 + +### 创建组织在 `CREATE USER` / `CREATE ROW POLICY` 时失败,或一个组织能读取另一个组织的数据 + +**症状:** 创建组织时返回提及 `CREATE USER`、`CREATE ROW POLICY` 或"access management is disabled"的错误;更严重的情况是,一个组织的成员在 SQL 编辑器或助手中看到另一个组织的事件/评估数据。 + +**原因:** 按组织的隔离通过每个组织专用的 ClickHouse 用户 + 行策略来实现。这需要在 ClickHouse 上启用 SQL **访问管理**,并将 `users_without_row_policies_can_read_rows=false`。禁用访问管理时,创建组织时无法创建用户/策略;行策略默认值保持宽松时,有 SELECT 权限但无策略的用户会读取**所有**行(默认开放)。 + +**修复:** 使用附带的 `deploy/base/clickhouse/` 配置,它同时设置了这两项。如果你使用自定义的 ClickHouse 配置,请在服务器内部用户上启用 SQL 访问管理,并设置 `users_without_row_policies_can_read_rows=false`(参见 `deploy/base/clickhouse/configmap.yaml`),然后重启 ClickHouse 并使用 `agenteye-orgctl` CLI 重新创建组织(参见 [enterprise-docs/tenant-management.md](/zh/agenteye/tenant-management))。 + +### 修改 `ORG_CH_SECRET` 后组织用户失去 ClickHouse 访问权限 + +**症状:** 修改 `ORG_CH_SECRET` 或在不同副本上设置不一致后,SQL 编辑器和 AI 助手立即对所有组织返回 ClickHouse 认证失败。 + +**原因:** 每个组织的 ClickHouse 密码是以 `ORG_CH_SECRET` 为密钥的 HMAC 派生值。轮换该密钥(或在副本上运行不同的值)会使每个组织存储的 ClickHouse 凭据失效;派生密码不再匹配已创建的用户。 + +**修复:** 在创建第二个组织**之前**将 `ORG_CH_SECRET` 设置为一个强值,并在所有服务器副本上保持稳定一致。服务器的启动时协调会在启动时根据当前 Secret 重新创建每个组织的 ClickHouse 用户,因此对所有副本重启服务器(Secret 保持一致)会修复孤立的用户。请将该值视为长期 Secret,不要随意轮换。作为安全保护,如果 `ORG_CH_SECRET` 保持内置的开发默认值(即未设置),启动时协调**会跳过**非默认组织并记录错误,而非将其 ClickHouse 凭据重写为公知的开发值——这样单个副本在没有 Secret 的情况下重启时不会破坏其他副本。请一致设置该 Secret 并重启,以完成这些组织的创建。 + +### 启用组织后 AI 助手返回 400 / 拒绝聊天 + +**症状:** 助手面板加载成功,但每条消息都返回错误(HTTP `400`),且 agent 日志记录了被拒绝的无组织上下文的 `/chat` 请求。 + +**原因:** agent 具有组织感知能力,采用失败关闭策略;它会拒绝没有携带组织上下文的 `/chat` 请求。这发生在过渡性滚动发布期间,agent 已升级但发送请求的仪表盘尚未具备组织感知能力。 + +**修复:** 完成滚动发布,使仪表盘发送组织上下文(正常最终状态,无需特殊标志)。在尚未升级的仪表盘与已升级的 agent 通信的过渡期间,在 `agent` 服务上设置 `AGENTEYE_AGENT_ALLOW_NO_ORG=1`,使其回退到 `default` 组织而非拒绝请求,待仪表盘升级完成后清除该设置。详见 [enterprise-docs/assistant.md](/zh/agenteye/assistant#environment-variable-reference) 中的环境变量参考。 + +--- + +## 审计 + +### 审计从未运行(下次运行时间持续推迟,运行历史为空) + +**症状:** 审计页面显示*上次运行:从未*,或 `next run` 持续移到未来而运行历史中没有出现任何记录。 + +**原因:** 审计已禁用(禁用的审计没有队列条目),或服务器的审计工作进程无法认领工作。 + +**修复:** 确认审计已**启用**(立即运行按钮需要审计处于启用状态)。然后检查服务器日志中启动时的 `audits pipeline started` 以及 `audits:` 错误——`claim_due failed` 日志行指向 Postgres 连接问题。`AUDIT_WORKERS` 默认值为 `1`;必须 ≥ 1 才能运行任何审计。 + +### 审计运行成功但未发现任何问题 + +**症状:** 运行历史显示 `succeeded`,`findings: 0`,但 `/errors` 明确显示有失败记录。 + +**原因:** 扫描窗口未覆盖这些失败,或范围过滤器将其排除。 + +**修复:** 对照失败发生的时间检查运行记录的窗口(`window_from → window_to`)——在 `since_last` 模式下,每次运行只扫描自上次成功运行以来的数据,因此旧的失败只有*第一次*运行或 `fixed` 窗口审计才能看到。扩大 `scope`(环境 / agent ID)。运行统计显示 `policy_hits`(确定性策略触发次数)和 `improvements`(AI 调查记录的次数)——如果两者都为 0,说明该窗口/范围内确实没有发现任何内容。 + +### 运行显示 `analysis_unavailable`,只产生了 policy 类型的发现 + +**症状:** 运行统计包含 `analysis_unavailable`,且所有发现都是 `kind: policy`;没有 AI 改进建议出现。 + +**原因:** 智能体调查无法运行:服务器无法访问 agent 服务(**服务器**上未设置 `AGENTEYE_AGENT_URL` / `AGENTEYE_AGENT_TOKEN`——审计复用助手的连接),助手服务未配置 LLM,或调用报错/超时(`analysis_unavailable` 字符串中有详细信息)。确定 \ No newline at end of file