نظرة عامة
يمكن للتطبيقات تعريف قدرات ذكاء اصطناعي تعمل داخل مساحة العمل — تعليمات مهارات قابلة لإعادة الاستخدام ووكلاء بموجهات نظام مخصّصة.defineSkill
عرّف مهارات وكلاء الذكاء الاصطناعي
defineSkill
عرّف مهارات وكلاء الذكاء الاصطناعي
تُحدِّد المهارات تعليمات وإمكانات قابلة لإعادة الاستخدام يمكن لوكلاء الذكاء الاصطناعي استخدامها داخل مساحة العمل لديك. استخدم النقاط الرئيسية:
defineSkill() لتعريف مهارات مع تحقّق مدمج:src/skills/example-skill.ts
nameهي سلسلة معرّف فريدة للمهارة (يُنصَح باستخدام kebab-case).labelهو اسم العرض المقروء للبشر الظاهر في واجهة المستخدم.contentيحتوي على تعليمات المهارة — وهو النص الذي يستخدمه وكيل الذكاء الاصطناعي.icon(اختياري) يحدّد الأيقونة المعروضة في واجهة المستخدم.description(اختياري) يوفّر سياقًا إضافيًا حول غرض المهارة.
defineAgent
عرِّف وكلاء الذكاء الاصطناعي باستخدام موجهات مخصّصة
defineAgent
عرِّف وكلاء الذكاء الاصطناعي باستخدام موجهات مخصّصة
الوكلاء هم مساعدون ذكاء اصطناعي يعيشون داخل مساحة العمل لديك. استخدم النقاط الرئيسية:ملاحظات حول المخطط:
defineAgent() لإنشاء وكلاء بموجه نظام مخصّص:src/agents/example-agent.ts
nameهي سلسلة معرّف فريدة للوكيل (يُنصح باستخدام kebab-case).labelهو اسم العرض الظاهر في واجهة المستخدم.promptهو موجه النظام الذي يحدّد سلوك الوكيل.description(اختياري) يوفّر سياقًا حول ما يفعله الوكيل.icon(اختياري) يحدّد الأيقونة المعروضة في واجهة المستخدم.modelId(اختياري) يتجاوز نموذج الذكاء الاصطناعي الافتراضي الذي يستخدمه الوكيل.responseFormat(اختياري) يحدد شكل الإخراج الافتراضي للوكيل. القيمة الافتراضية هي{ type: 'text' }للنص الحر. استخدم{ type: 'json', schema }لفرض مخرجات JSON منظمة. يمكن لاستدعاءrunAgent()أو لخطوة ذكاء اصطناعي في سير عمل طلب شكل مختلف، ويكون له الأسبقية.- يربط
roleUniversalIdentifier(اختياري) الوكيل بدور يحدده تطبيقك. يجب ألا يمنح ذلك الدور صلاحيات أكثر من دور التطبيق، وإلا فسيفشل الإصدار؛ راجع أدوار الوكلاء. - يُفعّل
modelConfiguration(اختياري) الأدوات الأصلية للنموذج، كما تفعل صفحة إعدادات الوكيل:{ webSearch: { enabled: true }, twitterSearch: { enabled: true } }. لا تعمل كل أداة إلا مع النماذج التي تدعمها. اتركه خارجًا لإبقائها معطلة. - يُخفي
isSystem(اختياري، وقيمته الافتراضيةfalse) الوكيل من قوائم الوكلاء، مثل الوكلاء الذين ينشئهم Twenty لخطوات الذكاء الاصطناعي لسير العمل. إنه يغيّر ما يُعرض فقط: لا يمكن تغيير وكلاء التطبيق إلا من خلال التطبيق، بغض النظر عما تقوله هذه العلامة.
responseFormat إلى { type: 'json' } ووفّر schema:src/agents/structured-agent.ts
- المخطط كائن مسطح: يجب أن يكون
typeلكل خاصية نوعًا بدائيًا (stringأوnumberأوboolean). الكائنات المتداخلة والمصفوفات غير مدعومة. description(اختياري) على كل خاصية يوجه النموذج لما يجب وضعه هناك.required(اختياري) يسرد الخصائص التي يجب على النموذج إرجاعها دائمًا.additionalProperties: false(اختياري) يمنع أي خاصية غير معرّفة فيproperties.
defineMcpServer
إتاحة خادم MCP خارجي لذكاء اصطناعي مساحة العمل (بيتا)
defineMcpServer
إتاحة خادم MCP خارجي لذكاء اصطناعي مساحة العمل (بيتا)
استخدم النقاط الرئيسية:
defineMcpServer() لإصدار خادم MCP بعيد (HTTP قابل للبث) مع تطبيقك، بحيث يتمكن ذكاء اصطناعي مساحة العمل من استخدام أدواته دون مزامنة تلك البيانات مع Twenty:src/mcp-servers/github.ts
nameبصيغة snake_case (أحرف صغيرة وأرقام وشرطات سفلية، يبدأ بحرف، وبحد أقصى 32 حرفًا) وفريد في مساحة العمل. يُضاف كبادئة إلى أسماء أدوات الخادم.- يجب أن يكون
urlعنوان URL من نوع HTTP أو HTTPS. - يشير
connectionProvider(اختياري) إلى موفر اتصال معلن بواسطة التطبيق نفسه. ترسل الاستدعاءات رمز الوصول الخاص بذلك الاتصال كرمز Bearer. احذفه لخادم عام. - لا يمكن أن يتغير عنوان URL في إصدار لاحق أثناء ربط موفر اتصال، لذلك لا تُرسل الرموز أبدًا إلى مضيف آخر.
- يمكن لمساحات العمل إلغاء تنشيط الخادم؛ ويحافظ إصدار لاحق من التطبيق على هذا الخيار.
- يتطلب
"engines": { "twenty": ">=2.53.0" }.
runAgent
تشغيل وكيل من دالة منطقية
runAgent
تشغيل وكيل من دالة منطقية
تتيح النقاط الرئيسية:يتطلب التحميل علامة الإذن ثم يعمل التنفيذ باستخدام دور العضو نفسه: يمكنه القيام بكل ما يمكن
لذلك العضو القيام به ولا أكثر، وتنسب إليه السجلات التي ينشئها، وتُطبَّق أذوناتُه على مستوى الصف. لا يشارك دور الوكيل — فهو الإعداد الافتراضي للتطبيق لعمليات التنفيذ التي لا يقف خلفها أي شخص. احذف الحقل في عمليات التنفيذ الذاتية (المهام المجدولة، مشغلات أحداث قاعدة البيانات): في هذه الحالة يحتفظ الوكيل بدوره الخاص. يبقى التطبيق الفاعل مرتبطًا بسياق التنفيذ لأغراض التتبّع وإثبات المصدر، دون تقييد أذونات العضو.تطبيقك مسؤول عن تعيين الشخص الذي شغّل التنفيذ إلى عضو في مساحة العمل. يتطلب تسمية عضو ما رمز وصول للتطبيق، وما يمكن للرمز تسميته يعتمد على ما إذا كان يتضمن مستخدمًا أم لا:
runAgent() لدالة منطقية تشغيل أحد وكلاء تطبيقك (مع مهاراته وأدواته). عرِّف الوكيل باستخدام universalIdentifier الذي مررته إلى defineAgent()، ومرِّر ما تريد أن يعمل عليه باعتباره input:src/logic-functions/run-enricher.ts
inputعبارة عن سلسلة نصية، أو قائمة تضم من 1 إلى 100 رسالة ({ role: 'user' | 'assistant', content: string }). يمكن أن تتضمن رسالةuserأيضًا مرفقات ملفات (انظر أدناه). لإجراء محادثة، مرّرthreadبدلًا من إعادة تشغيل الأدوار السابقة بنفسك.- افتراضيا، ينتظر الاستدعاء الوكيل، الذي يمكنه قراءة/تحديث السجلات
بنفسه عبر أدواته الخاصة — يُرجع
runAgent()بمجرد اكتمال التشغيل. مررwaitForCompletion: falseللإرجاع بمجرد بدء التشغيل: تكونstatusحينهاRUNNINGوresult: null، ويصل الرد إلى محادثةthreadId. يُرجع التشغيل الذي يستمر لأكثر من 15 دقيقة أيضا بالحالةRUNNING. - يمكن للوكيل أيضًا التوقف مؤقتًا حتى يتغير سجل أو يمر بعض الوقت.
تُرجع
runAgent()بعد ذلكsuccess: trueوstatus: 'SUSPENDED'وresult: null؛ ثم يواصل الوكيل العمل بنفسه لاحقًا، ويصل ردّه إلى محادثةthreadId. يفشل استدعاءthreadالذي لا يزال وكيله في حالة انتظار إلى أن ينتهي. - يُخزَّن كل استدعاء مع مدخلاته وحالته، بالإضافة إلى رده واستخدامه
عند اكتماله، بحيث يظهر في عمليات تشغيل الوكيل. من دون
thread، يحصل الاستدعاء على محادثة خاصة به: يسمّيهاthreadId، ولا يراها أي استدعاء لاحق مطلقًا. - لا يمكن للتطبيق تشغيل سوى وكلائه الخاصين.
- يجب أن يمنح الدور الافتراضي للتطبيق علامة الإذن
AI— أضِفSystemPermissionFlag.AIإلىpermissionFlagUniversalIdentifiersالخاصة به (أو عيِّنcanAccessAllTools: true). بدون ذلك، تفشلrunAgent()بخطأ في الأذونات. - اضبط قيمة كبيرة لـ
timeoutSecondsعلى الدالة المنطقية — قد يستغرق تشغيل الوكيل عدة ثوانٍ. - تكون
statusبالقيمةCOMPLETEDمعresultغير فارغ عند اكتمال التشغيل دون انتظار؛ وبالقيمةSUSPENDEDمعsuccess: trueوresult: nullأثناء الانتظار؛ وبالقيمةRUNNINGمعsuccess: trueوresult: nullعندما لا ينتظر الاستدعاء التشغيل؛ وبالقيمةFAILEDمعsuccess: falseواحتواءerrorعلى السبب (على سبيل المثال، عندما تنفد أرصدة الذكاء الاصطناعي لمساحة العمل أثناء التشغيل).
src/roles/default-role.ts
إرسال الملفات مع رسالة
يمكن أن تحمل رسالةuser attachments، بحيث يرى الوكيل لقطة شاشة أو ملف PDF
بدلاً من اسمه فقط. يشير كل إدخال إلى ملف سبق لتطبيقك
تحميله إلى مجلد agent-chat:src/logic-functions/describe-screenshot.ts
UPLOAD_FILE في الدور الافتراضي للتطبيق،
إلى جانب AI. filename اختياري ويُستخدم فقط لتسمية الملف للنموذج.- يمكن لرسائل
userفقط أن تحمل مرفقات. لا يمكن تمثيلها في دور assistant، لذا ترفضهاrunAgent()هناك بدلاً من إسقاطها. - بحد أقصى 10 مرفقات لكل رسالة.
- يجب أن يشير
fileIdإلى ملف تم تحميله بالكامل في مساحة العمل نفسها، ضمن مجلدagent-chat. أي شيء آخر يؤدي إلى فشل الاستدعاء بدلاً من الإجابة بهدوء من دون الملف.
طلب نتيجة منظَّمة
مرّرresponseFormat للحصول على شكل لهذه المكالمة فقط. له الأسبقية على
responseFormat الخاص بالوكيل، لذا يمكن لوكيل واحد خدمة المستدعين الذين يحتاجون إلى
مخرجات مختلفة. يستخدم المخطط نفسه مثل defineAgent():src/logic-functions/score-lead.ts
متابعة محادثة
مرّرthread وسيتولى Twenty الاحتفاظ بالمحادثة لك: لا يرسل كل استدعاء سوى
الإدخال الجديد، ويرى الوكيل الأدوار السابقة، بما في ذلك ما أعادته أدواته. استخدم أي معرّف ثابت من جانبك كمفتاح، مثل قناة Slack
وطابع زمني لسلسلة المحادثة:src/logic-functions/reply-in-thread.ts
- تقتصر المفاتيح على تطبيقك ووكيلك، لذا لا يشترك تطبيقان مطلقًا في
محادثة واحدة. لا يمكن تمرير
threadإلا باستخدام رموز وصول التطبيق. inputلا يمكن أن يحتوي إلا على رسائلuser: فالمحادثة تحتوي بالفعل على ردود الوكيل.additionalInstructionsتُعطى للنموذج لهذا الاستدعاء فقط ولا يتم تخزينها، وهي مناسبة للإرشادات الخاصة بكل طلب، مثل قواعد التنسيق أو موعد نهائي. وهي تعمل دونthreadأيضًا.- يُخزَّن كل تشغيل كدور مع حالته، بما في ذلك عمليات التشغيل الفاشلة. يُخزَّن استخدامه عند عودة الوكيل، حتى إذا نفدت أرصدته. إن التشغيل الفاشل ليس جزءًا من المحادثة، لذا لا تراه المكالمة التالية له.
- تعمل الاستدعاءات على سلسلة المحادثة نفسها واحدًا تلو الآخر: ينتظر الاستدعاء الثاني حتى ينتهي الأول، لذا يرى كلٌّ منها الأدوار التي سبقته.
- عندما تُنفَّذ الأدوار بصفتها أعضاء مختلفين (انظر أدناه)، لا يرى كل منها سوى النص الخاص بأدوار الآخرين، ولا يرى مطلقًا نتائج أدواتهم، إذ قُرئت تلك النتائج باستخدام أذونات شخص آخر.
التشغيل نيابةً عن أحد أعضاء مساحة العمل
مررrunAsWorkspaceMemberId عندما يتم تشغيل التنفيذ بواسطة شخص — مثل روبوت دردشة يجيب على رسالة، مثلاً — لكي يتصرف الوكيل بصفة ذلك العضو بدلًا من التطبيق:src/logic-functions/answer-question.ts
- يمكن لرمز بدون مستخدم مرفق أن يسمّي أي عضو. تعمل الدالة المنطقية بدون مستخدم، وكذلك الرموز المُنشأة عبر
client_credentialsأو من مفتاح API. - لا يمكن لرمز مُصدَر نيابةً عن مستخدم، كما يستقبله مكوّن الواجهة الأمامية، أن يسمّي إلا العضو الخاص بذلك المستخدم فقط.
متابعة محادثة
يقرأ التطبيق المحادثات التي يجريها مع وكلائه عبر واجهة برمجة التطبيقات نفسها المستخدمة للدردشة: تُرجعlistConversationMessages() سجلها، وتُنتج
streamConversation() أحداثها المباشرة، رمزًا تلو الآخر. سمِّ
المحادثة باستخدام الوكيل ومفتاح thread الذي تمرره إلى runAgent()؛ ويمكنك
بدء متابعتها قبل أن يصل إليها التشغيل الأول.src/logic-functions/follow-conversation.ts
- الأحداث خاصة بالدردشة نفسها: يحمل
stream-chunkكائنUIMessageChunkمن AI SDK ومعرّفseq، وتوضح الإشعارات مثلmessage-persisted(تم حفظ رسالة: رسالة عضو أو الرد، الذي يحملturnIdالخاص بتشغيله)، وcredits-exhausted(توقف الرد عند نفاد الأرصدة من مساحة العمل)، وqueue-updatedأوstream-errorمتى تقرأ السجل مرة أخرى. يصلkeepaliveعند الاتصال، ثم كل بضع ثوانٍ: اقرأ السجل عند أول واحد، لأن ما حدث قبله موجود فيه. - لتحويل المقاطع إلى رسائل كما تفعل الدردشة، مررها إلى
readUIMessageStream()من الحزمةai. - تُرجع
listConversationMessages()القيمة{ messages, streamCatchup }: الرسائل المحفوظة ككائناتUIMessageمن AI SDK، كما تنشئها الدردشة، ومقاطع رد ما زال يُبث. اعرض تلك المقاطع، ثم تخطَّ المقاطع المباشرة التي يكون فيهاseqأقل من أو مساويًا لـstreamCatchup.maxSeq، لأنها تكررها. - تُرجع
runAgent()القيمةrunId، أي الدور الذي تفتحه المكالمة: تحمل رسائل ذلك التشغيل هذه القيمة كـmetadata.turnId. يستمر التشغيل الذي ينتظر في أدوار لاحقة من المحادثة. - يبقى الدفق مفتوحًا حتى تُلغي
signalالخاص به أو تستخدمbreak، ويُطلق خطأً إذا انقطع الاتصال: أعد إنشاء الدفق للاستئناف. - يقرأ التطبيق محادثاته الخاصة فقط. تُظهر الأدوار التي فتحها عضو في مكان آخر،
مثل الدردشة، نصها فقط في السجل والبث المباشر وفي التشغيل التالي
للوكيل: في البث المباشر، تصل مقاطعها الأخرى كمقاطع
message-metadataفارغة، لذلك يبقىseqبلا فجوات. تبقى الأدوار التي شغّلها تطبيقك كعضو (انظر أعلاه) كاملة عندما يقرأها بنفسه. - يتطلب
"engines": { "twenty": ">=2.56.0" }.
إنشاء بالذكاء الاصطناعي
استدعِ نموذجًا من دالة منطقية، من دون وكيل
إنشاء بالذكاء الاصطناعي
استدعِ نموذجًا من دالة منطقية، من دون وكيل
تستدعي النطاق لا يؤدي إلا إلى التضييق: فهو لا يمنح أي شيء لا يملكه المتصل بالفعل.لعرض الرد أثناء كتابته، مرر
ai.generate() نموذجًا من دالة منطقية. بخلاف
runAgent()، لا تحتاج إلى defineAgent(): تحمل المكالمة تعليماتها
الخاصة، ولا تفتح أي محادثة. استخدمها للمهام التي تُنفذ لمرة واحدة، مثل
التصنيف أو التلخيص أو الاستخراج.inputعبارة عن سلسلة، أو قائمة برسائل{ role: 'user' | 'assistant', content }.- يضيف
instructions(اختياري) تعليمات النظام الخاصة بالمتصل. - يختار
modelId(اختياري) النموذج. من دونه، تستخدم المكالمة النموذج الافتراضي لمساحة العمل. - يعمل
responseFormat(اختياري) كما فيrunAgent(). مع{ type: 'json', schema }، يُضاف المخطط إلى طلب النموذج نفسه، لذا يتطلب جواب JSON طلبًا واحدًا (بالإضافة إلى خطوات الأداة عندما يمنحscopeالأدوات). - يتيح
scope(اختياري) للمكالمة استخدام قاعدة البيانات، كما هو موضح أدناه.
{ success, text, object, error, runId, usage }:textهو رد الاستجابة النصية، ويكونnullلاستجابة JSON.objectهو نتيجة استجابة JSON، ويكونnullبخلاف ذلك.- يشرح
errorالتشغيل الفاشل عندما تكونsuccessهيfalse. يُحل التشغيل الذي يفشل بهذه الطريقة بدلًا من إطلاق خطأ؛ أما المكالمة التي لا يمكنها بدء تشغيل، مثل مكالمة ذات إدخال غير صالح، فتُطلق خطأً. - يحدد
runIdالتشغيل المسجل، مع نموذجه واستخدامه وأرصدته. usageهو{ inputTokens, outputTokens }: ما أنفقه التشغيل، بما في ذلك الخطوات التي انتهت قبل الإخفاق.
scope، لا تقرأ المكالمة أي سجلات ولا تكتبها. للسماح لها باستخدام
قاعدة البيانات، مرر scope، مكتوبًا مثل أذونات الدور:onChunk. تُحل المكالمة مع ذلك
إلى النتيجة نفسها، بمجرد تمرير المقطع الأخير إلى onChunk. إذا لم تصل
نهاية الدفق مطلقًا، تتوقف عن الانتظار بمجرد وصول النتيجة ومرور 5 ثوانٍ
من دون مقطع جديد، وتظل تمرر كل مقطع تلقته حتى ذلك الحين:- تتبع المكالمة التشغيل عبر الاشتراك نفسه الذي تستخدمه
streamConversation(): تشترك أولًا، وتنتظر حتى يصبح الاشتراك مباشرًا، ثم تبدأ التشغيل، لذلك لا يفوتها أي مقطع. - المقاطع خاصة بالدردشة نفسها: مررها إلى
readUIMessageStream()من حزمةaiلإنشاء الرسالة. - يلغي
signalالمكالمة: يُرفض بخطأ الإلغاء ويغلق الدفق. يستمر التشغيل نفسه، ويُسجل كالمعتاد. - بمجرد أن يصبح الدفق مباشرًا، لا يؤدي فشله إلا إلى إيقاف المقاطع: تظل المكالمة
تُحل بنتيجة التشغيل، التي تُفوتر في كلتا الحالتين. تُرفض المكالمة
عندما يفشل الاشتراك قبل أن يصبح مباشرًا، لذلك لا يبدأ التشغيل
مطلقًا، أو عندما يُطلق
onChunkخطأً. - يتابع التطبيق عمليات التشغيل الخاصة به فقط، لذا يحتاج
onChunkإلى رمز مميز للتطبيق. - يتطلب
"engines": { "twenty": ">=2.56.0" }.
تتطلب
ai.generate() علامة إذن الذكاء الاصطناعي في الدور الافتراضي للتطبيق،
مثل runAgent().sendInboxMessage
بدء محادثة أو متابعتها في دردشات الأعضاء
sendInboxMessage
بدء محادثة أو متابعتها في دردشات الأعضاء
ينشر
sendInboxMessage() رسالة من تطبيقك في دردشات عضو واحد أو أكثر من أعضاء
مساحة العمل. يمكن أن ينتهي باستدعاء أداة يجيب عنه العضو من الدردشة،
وبعد ذلك تستمر المحادثة مع مساعد Twenty. اطّلع على
البريد الوارد لمعرفة خياراته ومساعدات
الإشارة وكيفية النشر من مكوّن أمامي.