# العملاء والهوية

> مع من يتحدث الوكيل — زوار مجهولون، ومستخدمون يضمنهم خادمك، ورموز عميل قصيرة العمر — وما الذي يتيحه التوثيق.

**العميل** (`eu_…`) هو الشخص الذي يحادث وكيلك. ينتمي العملاء إلى مشروع، ويحمل كلٌّ منهم معرّفك الخاص `external_id`، واسمًا `name` اختياريًا، و`traits` حرة (الخطة، المدينة، اللغة، فئة الحساب…). وترتبط بالعميل الجلساتُ وذاكرة إجراءات الوكيل والحدودُ الخاصة بكل مستخدم.

## ثلاث درجات للهوية

| الدرجة | كيف تتحقق | موثّق | الاستخدام المعتاد |
|---|---|---|---|
| **مجهول** | مفتاح قابل للنشر مع رمز جهاز، من الودجت | لا | زوار موقعك العام |
| **مُثبَت من الخادم** | طلب بمفتاح سري يتضمن `end_user` | نعم | خادمك يتحدث مع K-Agent |
| **رمز عميل** | رمز `ct_…` يصدره خادمك لعميل واحد ووكيل واحد | نعم، حتى 60 دقيقة | المستخدمون المسجّلون في تطبيقك على الويب أو الجوال |

**التوثيق صفة لبيانات الاعتماد، لا للعميل نفسه.** يكون الطلب موثّقًا حين يضمنه خادمك — بمفتاح سري أو برمز عميل أصدره. والشخص نفسه حين يدردش في الودجت مجهولًا لا يكون موثّقًا في تلك المحادثة.

### ما الذي يتيحه التوثيق

- **أدوات HTTP المرتبطة بالهوية.** الأداة التي تفعّل `requires_verified_user`، أو تستخدم العناصر النائبة `{{end_user.*}}`، لا تعمل إلا للعملاء الموثّقين. والنموذج لا يقدّم الهوية أبدًا: يملؤها K-Agent من بيانات الاعتماد. انظر [أدوات HTTP](/docs/guides/http-tools/).
- **الإجراءات للأشخاص المعروفين.** تُزال الأدوات ذات الأثر للعملاء المجهولين ما لم يفعّل الوكيل `tools.allow_anonymous_actions`.
- **ذاكرة عابرة للجلسات.** سجل الإجراءات («نُفّذ، لا تكرره») وحدود المعدّل الخاصة بالمستخدم تتبع العميل الموثّق عبر جلساته كلها. أما للمجهولين فنطاقها الجلسة.

## عرّف K-Agent بالمستخدم

من خادمك، أرسل `end_user` مع `ask` أو `POST /v1/sessions`:

```json
{
  "agent": "store-assistant",
  "external_id": "order-8812",
  "end_user": {
    "external_id": "cus_1042",
    "name": "فهد",
    "traits": { "plan": "gold", "city": "الرياض" }
  },
  "input": "أقدر أغير عنوان التوصيل؟"
}
```

- يُنشأ العميل عند أول ظهور ويُحدَّث لاحقًا (تُدمج `traits`).
- عميل الجلسة يُحدَّد عند إنشائها؛ والعميل المختلف يعيد `409 session_end_user_mismatch`.
- معرّفات العملاء `external_id` تتبع صيغة معرّفات الجلسات نفسها (`^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$`) ولا تبدأ بـ `eu_`.

ويمكنك إدارة العملاء مباشرة:

| الطريقة والمسار | الغرض |
|---|---|
| `POST /v1/end_users` | إنشاء أو تحديث حسب `external_id` |
| `GET /v1/end_users` | السرد |
| `GET /v1/end_users/{eu}` | القراءة (`{eu}` هو معرّف `eu_` أو `external_id` الخاص بك) |
| `PATCH /v1/end_users/{eu}` | تحديث الاسم أو الخصائص |
| `DELETE /v1/end_users/{eu}` | **محو** العميل وبياناته |

:::tip[بيانات التواصل مكانها الخصائص]
أرقام الجوال والبريد الإلكتروني لا تصلح معرّفات أبدًا. ضعها في `traits`، وإذا احتجت مفتاحًا ثابتًا مشتقًا منها [فاشتقّه بالتجزئة على خادمك](/docs/concepts/sessions/#لا-بيانات-شخصية-في-المعرّفات).
:::

## رموز العميل

يتيح رمز العميل لمتصفح أو تطبيق جوال أن يحادث الوكيل **بوصفه عميلًا موثّقًا واحدًا**، دون أن يرى مفتاحك السري أبدًا. يصدره خادمك بمفتاح سري (النطاق `runs:write`) ويسلّمه للعميل:

```bash
curl https://api.k-agent.kerneltics.com/v1/client_tokens \
  -H "Authorization: Bearer $KAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent": "store-assistant",
    "end_user": { "external_id": "cus_1042", "name": "فهد" },
    "ttl_seconds": 900
  }'
```

```json
{
  "token": "ct_5RfQ0mXwJ8bT2nLk9pY4vC7hD1sG6aE3uZ0iWqNxb7K",
  "expires_at": 1791272820,
  "end_user": { "id": "eu_01k6rz3t5v7w9x1y2z4a6b8c0d", "object": "end_user", "external_id": "cus_1042", "name": "فهد" }
}
```

- `ttl_seconds` حدها الأقصى 3600، وقيمتها الافتراضية 900 (15 دقيقة).
- اربط الرمز بمحادثة واحدة عبر `session` (معرّف `sess_` أو `external_id`)، أو دع العميل يفتح محادثته.
- لا تحدد `variables` إلا المتغيرات التي يعرّفها الوكيل بخاصية `client_settable`؛ والمتغيرات السرية لا تُحفظ في الرموز أبدًا.
- تُحفظ الرموز مجزّأة ويمكن إلغاؤها. يتوقف الرمز عن العمل عند انتهاء صلاحيته (`401 token_expired`)، أو عند إلغائه، أو عند إلغاء المفتاح الذي أصدره، أو عند محو عميله.
- البث المفتوح يتلقى `event: error` مع `{"code": "token_expired"}` عند انتهاء صلاحية الرمز. احصل على رمز جديد وأعد الاتصال مع `Last-Event-ID`.

يعرض [دليل الودجت](/docs/guides/widget/#3-المستخدمون-المسجّلون-موثّقون) المسار الكامل مع خوادم Node وPython.

### ما الذي تستطيع بيانات اعتماد المتصفح استدعاءه

المفاتيح القابلة للنشر ورموز العميل محصورة في قائمة قصيرة من المسارات. أي مسار آخر يعيد `403 principal_not_allowed`، والجلسة أو التشغيل التابع لعميل آخر يعيد `404`.

| بيانات الاعتماد | المسارات المسموح بها |
|---|---|
| مفتاح قابل للنشر (`kt_pk_…`) | `GET /v1/widget/config?agent=…` و`POST /v1/widget/sessions` |
| رمز عميل (`ct_…`) | `POST /v1/widget/sessions` · `GET /v1/sessions/{session}` · `GET` و`POST /v1/sessions/{session}/messages` · `GET /v1/sessions/{session}/events` · `POST /v1/sessions/{session}/handoff` · `POST /v1/sessions/{session}/close` · `GET /v1/runs/{run}` · `GET /v1/runs/{run}/events` · `POST /v1/runs/{run}/cancel` · `POST /v1/runs/{run}/submit_tool_outputs` |

مع رمز العميل تُرسل الرسائل بدور `role: "user"` فقط، ولا تحمل تجاوزات ولا إصدارًا ولا عميلًا آخر ولا إعدادات جلسة. وتُحذف البيانات الوصفية والمتغيرات من استجابات الجلسة، ولا تتضمن القوائم الملاحظات الداخلية ولا رسائل النظام. أما خطوات التشغيل (التتبع) فلا تتاح لبيانات اعتماد المتصفح أبدًا.

## زوار الودجت المجهولون

عندما يبدأ الودجت دون رمز عميل، ينشئ `POST /v1/widget/sessions` عميلًا مجهولًا مرتبطًا **برمز جهاز** (`dt_…`). يُعاد رمز الجهاز مرة واحدة، ويُحفظ مجزّأً، ويتيح للمتصفح نفسه استئناف محادثته لاحقًا. ولا يُطابَق العملاء المجهولون أبدًا مع أي `external_id` ولا يُدمجون به.

لحركة المجهولين حدود خاصة: لكل عنوان IP، 20 جلسة ودجت و60 رسالة في الساعة؛ و40 رسالة كحد أقصى للجلسة المجهولة الواحدة؛ ولكل وكيل `widget.anonymous_daily_conversations` (الافتراضي 200). وبعد بلوغ الحد يرى الزوار إشعارًا مهذبًا بالمحاولة لاحقًا.

## المحو والاحتفاظ

يمحو `DELETE /v1/end_users/{eu}` الشخص في معاملة واحدة، لتلبية طلبات أصحاب البيانات وفق نظام حماية البيانات الشخصية في السعودية:

- تُحذف جلساته وتشغيلاته مع كل رسائلها وخطواتها وأحداثها وتحويلاتها وتذاكرها؛
- تبقى سجلات الاستخدام لأغراض الفوترة لكن يُفصل ارتباطها بالشخص؛
- يُسجَّل الحذف في سجل التدقيق بالمعرّف فقط؛
- تتوقف رموز العميل الخاصة به فورًا.

يتطلب ذلك مفتاحًا سريًا بالنطاق `sessions:write`، أو مسؤولًا في لوحة التحكم. وبمعزل عن ذلك تُحذف الجلسات كاملة تلقائيًا بعد أن يتجاوز خمولها مدة `retention_days` في المشروع (الافتراضي 365 يومًا).
