انتقل إلى المحتوى

الجلسات ومعرّفات الجلسات

عرض بصيغة Markdown

الجلسة محادثة دائمة بين عميل واحد ووكيل واحد. تحفظ كل رسالة بالترتيب، وهي ما يمنح الوكيل ذاكرة المحادثة. يمكنك مخاطبة الجلسة بالمعرّف الذي نصدره (sess_…) أو بمعرّفك الخاص (external_id)، مثل رقم طلب أو رقم تذكرة أو محادثة في نظامك.

هذا العقد جزء من التزامنا باستقرار الواجهة البرمجية.

  1. نحن نصدر المعرّف دائمًا. لكل جلسة id = sess_<26 chars>. لا يمكن تخمينه، ويُرتَّب حسب الوقت.
  2. يمكنك إضافة معرّفك الخاص external_id:
    • من 1 إلى 128 حرفًا تطابق ^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$ (الشرطة السفلية مقبولة، مثل cus_123)؛
    • حساس لحالة الأحرف؛
    • فريد داخل المشروع؛
    • يُحدَّد مرة واحدة ولا يتغير؛
    • لا يبدأ بـ sess_.
  3. المعرّفان يعملان في كل مكان تظهر فيه الجلسة في رابط. والاستجابات تعيد المعرّفين دائمًا.
  4. الجلب أو الإنشاء. الطلب POST /v1/sessions مع external_id:
    • يعيد 201 (created: true) أو 200 (created: false)؛
    • مع if_exists: "error" يعيد التطابقُ 409 session_exists؛
    • المعرّف external_id نفسه مع وكيل مختلف يعيد 409 session_agent_mismatch؛
    • الجلسات المغلقة يُعاد فتحها ما لم ترسل if_closed: "error"؛
    • الطلبات الأولى المتزامنة آمنة (فهرس فريد مع إدراج أو تحديث).
  5. المعرّفات ليست بيانات اعتماد.
    • كل طلب يخضع للتحقق من الهوية.
    • رموز العميل لا تصل إلا إلى جلسات عميلها نفسه.
    • المتصفحات لا تخاطب الجلسات بـ external_id باستخدام مفتاح قابل للنشر وحده.
  6. لا بيانات شخصية في المعرّفات. نعيد warnings: ["external_id_looks_like_phone"] (أو …_email) حين يبدو المعرّف بيانات تواصل. اشتقّ هذه القيم أولًا على خادمك بدالة تجزئة (انظر أدناه)، واحفظ بيانات التواصل في traits الخاصة بالعميل بدلًا من ذلك.
  7. الذاكرة والحدود تتبع العميل، لا معرّف الجلسة. تغيير معرّفات الجلسات لا يعيد ضبط سجل الإجراءات ولا الحدود الخاصة بالعميل الموثّق.
  8. السجل يمتد على الجلسة كلها (آخر history_limit رسالة). فترات الخمول لا تفعل سوى تحديث التعليمات المجمّدة وإصدار الوكيل (المقاطع)، ولا علاقة لها بنوافذ الفوترة.
  • ثلاثة أشياء فقط تنشئ الجلسات: POST /v1/sessions، وPOST /v1/widget/sessions، والواجهة المتوافقة مع OpenAI عندما تسمّي جلسة. أي رابط آخر يحمل {session} غير معروف يعيد 404 session_not_found.
  • القيم الافتراضية: if_exists افتراضيًا "resume"، وif_closed افتراضيًا "reopen".
  • الحقل input في POST /v1/sessions يُضاف ويُجاب عنه دائمًا، سواء أُنشئت الجلسة للتو أم استُؤنفت. طلب واحد لكل دور يكفي تكاملًا كاملًا.
  • عميل الجلسة يُحدَّد عند إنشائها. الاستئناف بـ end_user.external_id مختلف يعيد 409 session_end_user_mismatch. أما حقول الإنشاء الأخرى فتُتجاهل عند الاستئناف، وتخبرك الاستجابة بذلك عبر warnings: ["create_params_ignored"].
  • كيف يُقرأ المسار: لا يُعامل {session} معرّفًا منّا إلا إذا كان sess_ متبوعًا بـ 26 حرفًا صغيرًا بترميز base32، وكل ما عدا ذلك يُبحث عنه بوصفه external_id.
  • التجربة منفصلة. جلسات التجربة من لوحة التحكم في نطاق external_id خاص بها، ولا تصل أبدًا إلى جلسة حقيقية ولا تكتب فيها.
نافذة الطرفية
curl https://api.k-agent.kerneltics.com/v1/sessions \
-H "Authorization: Bearer $KAGENT_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"agent": "store-assistant",
"external_id": "order-8812",
"end_user": { "external_id": "cus_1042", "name": "فهد" },
"metadata": { "source": "order_page" },
"input": "توصلون أبها؟"
}'

يعيد الطلب الأول 201:

{
"session": {
"id": "sess_01k6rz4p7h2c9m5x8w3t6v1qbg",
"object": "session",
"external_id": "order-8812",
"end_user_id": "eu_01k6rz3t5v7w9x1y2z4a6b8c0d",
"channel": "api",
"status": "active",
"mode": "agent",
"concurrency": "queue",
"version_policy": "latest",
"metadata": { "source": "order_page" },
"created_at": 1791271920
},
"created": true,
"message": { "id": "msg_01k6rz5b2c4d6e8f0g1h3j5k7m", "object": "message", "role": "user" },
"run": { "id": "run_01k6rz5a9d3f6g2h8j4k7m1n5p", "object": "run", "status": "completed", "outcome": "answered", "output_text": "إيه نعم، نوصّل لأبها خلال 3 إلى 5 أيام عمل، والتوصيل مجاني للطلبات فوق 200 ريال." },
"warnings": []
}

كل طلب لاحق بالمعرّف external_id نفسه يعيد 200 مع "created": false، ويضيف input الجديد ويجيب عنه.

الحقل النوع ملاحظات
agent نص، إلزامي معرّف الوكيل أو معرّفه النصي.
external_id نص معرّفك للجلسة؛ انظر العقد أعلاه. احذفه لتكتفي بمعرّفنا sess_.
end_user كائن {external_id, name?, traits?}. يمكن للمفاتيح السرية ضمان العميل فيصبح موثّقًا. ثابت طوال عمر الجلسة.
variables كائن قيم المتغيرات التي يعرّفها الوكيل. المتغيرات السرية غير مقبولة هنا.
metadata كائن حتى 16 مفتاحًا؛ المفتاح حتى 64 حرفًا والقيمة حتى 512. لا تُرسل إلى النموذج أبدًا.
concurrency queue · reject · interrupt ما يحدث عند وصول رسالة والوكيل يرد.
version_policy وversion latest · pinned ثبّت الجلسة على إصدار منشور واحد، أو اتبع الأحدث.
if_exists resume · error الافتراضي resume.
if_closed reopen · error الافتراضي reopen.
input نص أو أجزاء نصية يُضاف ويُجاب عنه في الطلب نفسه.
overrides كائن تجاوزات على مستوى الجلسة يسمح بها الوكيل، وتسري من المقطع التالي. للمفاتيح السرية فقط.
client_message_id نص يمنع تكرار input، كما في الرسائل.
stream وbackground وwait_seconds بثّ الرد، أو العودة فورًا، أو الانتظار حتى wait_seconds ثانية (الافتراضي 60 والحد الأقصى 110). وتبقى الحالة 201 أو 200 في كل الأحوال؛ والتشغيل الذي ما زال يعمل يُعاد كما هو.
الحالة الاستجابة
if_exists: "error" والجلسة موجودة 409 session_exists
المعرّف external_id نفسه مع وكيل مختلف 409 session_agent_mismatch
المعرّف external_id نفسه مع end_user.external_id مختلف 409 session_end_user_mismatch
if_closed: "error" والجلسة مغلقة 409 session_closed
external_id يخالف الصيغة، مثل sess_x أو order 8812 422 external_id_invalid
{
"error": {
"type": "conflict_error",
"code": "session_agent_mismatch",
"message": "المعرّف الخارجي (external_id) هذا مرتبط بجلسة لوكيل آخر.",
"param": "external_id",
"request_id": "req_01k6rz9f1j3m5p7r9t1w3y5a7c",
"doc_url": "https://k-agent.kerneltics.com/docs/en/reference/errors/#session_agent_mismatch"
}
}

إذا شغّلت عدة وكلاء على السجلات نفسها فأعطِ كلًا منهم نطاق معرّفات خاصًا، مثل support:order-8812 وsales:order-8812.

لا بيانات شخصية في المعرّفات

رابط القسم «لا بيانات شخصية في المعرّفات»

تظهر المعرّفات في السجلات والروابط وملفات التصدير. عندما يبدو external_id رقم هاتف (8 أرقام أو أكثر) أو عنوان بريد إلكتروني، تحمل الاستجابة تحذيرًا:

{ "warnings": ["external_id_looks_like_phone"] }

إذا كان مفتاحك الطبيعي بيانات شخصية فعلًا، فاشتقّ المعرّف على خادمك بتجزئة مفتاحية. النتيجة ثابتة للمدخل نفسه، ولا تكشف شيئًا، وتطابق صيغة external_id: ‏base32(HMAC-SHA256(secret_you_keep, value)) بأحرف صغيرة، وأول 32 حرفًا. لا يرى K-Agent سرّك ولا يخزّنه.

import { createHmac } from 'node:crypto';
const ALPHABET = 'abcdefghijklmnopqrstuvwxyz234567';
export function hashExternalId(value, secret) {
const digest = createHmac('sha256', secret).update(value, 'utf8').digest();
let out = '';
let bits = 0;
let acc = 0;
for (const byte of digest) {
acc = ((acc << 8) | byte) & 0xffff;
bits += 8;
while (bits >= 5) {
out += ALPHABET[(acc >>> (bits - 5)) & 31];
bits -= 5;
}
}
return out.slice(0, 32);
}
hashExternalId('+966501234567', process.env.ID_HASH_SECRET);

الدوال الأربع تعطي القيمة نفسها: hashExternalId('+966501234567', 'my-hmac-secret') يساوي cs6vd2wrba2hf5w2ozuvftyoq5dewzhb. حافظ على ثبات السر — تغييره يغيّر كل المعرّفات.

قد تصل رسالتان والوكيل ما زال يرد على الأولى. يحدد concurrency في الجلسة ما يحدث:

السياسة السلوك الافتراضي لـ
queue تنتظر الرسائل دورها ويُجاب عنها بالترتيب. تنتظر 10 رسائل كحد أقصى، والحادية عشرة تحصل على 409 session_queue_full. جلسات الواجهة البرمجية
reject الرسالة التي تصل أثناء الرد تحصل على 409 session_busy مع Retry-After: 2. لا يُحفظ شيء. —
interrupt يُترك الرد الجاري (superseded)، ويجيب رد واحد جديد عن كل الرسائل غير المُجاب عنها معًا. جلسات الودجت

التشغيل المُستبدَل لا ينفّذ أي أداة ولا يكتب أي مخرج بعد استبداله. استخدم interrupt في واجهات الدردشة التي يرسل فيها الناس عدة رسائل قصيرة متتالية.

  • السجل يمتد على الجلسة كلها. يرى كل رد آخر history_limit رسالة (الافتراضي 12)، ويبدأ القطع عند رسالة من العميل فلا تنقسم أي مبادلة. والعودة في اليوم التالي لا تعيد المحادثة إلى البداية.
  • السجل نصّي. تُرسل الأدوار السابقة نصًا عاديًا؛ أما استدعاءات الأدوات وتفكير النموذج فتبقى داخل التشغيل الذي أنتجها.
  • ردود فريقك محسوبة. رسائل human_agent العامة تظهر للوكيل أدوارًا للمساعد بعد انتهاء التحويل؛ أما الملاحظات الداخلية فلا تظهر أبدًا.
  • المقاطع أجزاء الجلسة بين فترات الخمول (idle_timeout_minutes، الافتراضي 30 دقيقة). عند بداية المقطع يُحدَّد إصدار الوكيل والتعليمات وقائمة الأدوات ثم تُجمَّد حتى المقطع التالي. ويبدأ مقطع جديد أيضًا بعد نشر إصدار جديد، أو عند تغيّر متغيرات الجلسة، أو بعد 24 ساعة. المقاطع لا تقطع السجل ولا علاقة لها بالفوترة.
الإجراء الطريقة
قراءة جلسة GET /v1/sessions/{session} (المعرّف أو external_id)
تغيير البيانات الوصفية أو المتغيرات أو التجاوزات أو التزامن، أو إلغاء flagged PATCH /v1/sessions/{session}
الإغلاق POST /v1/sessions/{session}/close. رسالة جديدة من العميل تعيد فتحها.
الحذف النهائي DELETE /v1/sessions/{session} — يحذف الرسائل والتشغيلات والأحداث والتحويلات والتذاكر.
السرد والتصفية GET /v1/sessions?agent=&end_user=&external_id=&status=&mode=&flagged=&channel=&created_after=&created_before=
قراءة السجل GET /v1/sessions/{session}/messages
المتابعة المباشرة GET /v1/sessions/{session}/events — انظر التشغيلات والبث

يقبل POST /v1/sessions/{session}/messages الحقل input ومعه اختياريًا client_message_id وstream وbackground وwait_seconds وvariables وmetadata، ويعيد {session, message, run}:

  • client_message_id يجعل إعادة إرسال الرسالة آمنة: المعرّف نفسه يعيد {session, message, run} الأصلية مع Idempotent-Replayed: true بدل رد ثانٍ. والمعرّف نفسه مع نص مختلف يعيد 409 client_message_id_conflict.
  • وضع الموظف: ما دامت المحادثة بيد فريقك تُحفظ الرسالة، وتكون run قيمتها null، وsession.mode قيمتها "human".
  • background: true يعيد 202 فورًا والتشغيل قيد التنفيذ؛ تابعه عبر GET /v1/runs/{run} أو بث أحداث الجلسة.

يرد فريقك عبر نقطة النهاية نفسها مع role: "human_agent" — انظر دليل مكتب التحويل.