> ## Documentation Index
> Fetch the complete documentation index at: https://lousho.com/llms.txt
> Use this file to discover all available pages before exploring further.

# أوضاع الصلاحيات

يضع وضع الصلاحيات الوكيل في حالة مسمّاة بدل كتابة القواعد: انظر ولا تلمس (`plan`)، أو عدّل الملفات من دون سؤال (`acceptEdits`)، أو لا تتوقف أبدًا (`dontAsk`). بدّله في منتصف الجلسة كما تعمل مع وكيل برمجة: خطّط أولًا، ثم دعه يعدّل.

```ts theme={null}
import { createAgent, createFsTools, MemoryWorkspace } from '@lousho/build-ai-agent';
import { mockModel } from '@lousho/build-ai-agent/testing';

const workspace = new MemoryWorkspace({ files: { 'notes.md': '# Notes\n' } });
const agent = createAgent({
  provider: mockModel(['I would add a "Todo" section to notes.md.', 'Done.']),
  instructions: 'You are a coding agent.',
  tools: createFsTools(workspace, { needsApproval: { write_file: true, edit_file: true } }),
});

const session = agent.session({ permissionMode: 'plan' });
await session.send('Plan how to add a todo list to notes.md.'); // reads only; writes are refused
session.setPermissionMode('acceptEdits');
await session.send('Apply the plan.'); // write_file and edit_file run without asking
```

الأوضاع إعدادات مسبقة فوق [قواعد الصلاحيات](/ar/approvals#سياسات-الصلاحيات) و`needsApproval`، وليست نظامًا ثانيًا: تُطبَّق في النهاية، على ما قرّرته القواعد وحواجز الحماية و`needsApproval` الخاص بالأداة.

## الأوضاع

| الوضع | الأدوات للقراءة فقط | تعديل الملفات | أدوات أخرى تطلب موافقة | أدوات أخرى لا تطلب موافقة |
| - | - | - | - | - |
| `'default'` | البوابة العادية | البوابة العادية | تتوقف لطلب موافقة | تعمل |
| `'plan'` | البوابة العادية (قد تطلب موافقة أيضًا) | مرفوضة | مرفوضة | مرفوضة |
| `'acceptEdits'` | البوابة العادية | تعمل من دون سؤال | تتوقف لطلب موافقة | تعمل |
| `'dontAsk'` | البوابة العادية، لكن الاستدعاء الذي سيطلب موافقة يُرفض | مرفوضة حين ستطلب موافقة | مرفوضة | تعمل |

* **`plan`**: يُرفض استدعاء أي أداة ليست للقراءة فقط مع `kind: 'denied'` والسبب `The agent is in plan mode: it may read but not change anything. Describe the change instead.`، وذلك حتى لو طابقته قاعدة `allow`. والتشغيل الذي يبدأ في وضع plan يحصل أيضًا على فقرة واحدة في موجّه النظام تخبر النموذج بذلك. أما استدعاء أداة غير معروفة فيحصل على خطأ عدم العثور المعتاد، فيرى النموذج المشكلة الحقيقية.
* **`acceptEdits`**: الاستدعاء الذي كان سيتوقف لطلب موافقة يعمل من دون سؤال إذا كانت أداته تعديلًا للملفات (`editsFiles`، أدناه). ويبقى كل ما عدا ذلك على حاله.
* **`dontAsk`**: الاستدعاء الذي كان سيتوقف لطلب موافقة - قاعدة `ask` أو `needsApproval` أو `ask_question` - يُرفض مع السبب `The agent is in dontAsk mode: calls that need approval are refused.` أما الاستدعاءات التي وافقت عليها قاعدة `allow` والاستدعاءات التي لا تحتاج موافقة فتعمل. ولا شيء يتوقف، لذلك لا يُستدعى `approve` أبدًا.

### أي الأدوات للقراءة فقط

لا يسمح وضع plan بتشغيل أداة إلا إذا أعلنت أنها لا تغيّر شيئًا. والأداة التي لا تعلن شيئًا تُعامل كأداة لها آثار جانبية وتُرفض.

* أداة لها `annotations: { readOnlyHint: true }`. من المدمجة: `read_file` و`list_dir` و`glob` و`grep` و`todo_read` و`current_date` و`day_name` و`web_fetch` و`load_skill` وكل أداة ذاكرة `recall_<name>`، و`agent_status` / `agent_await` (تراقبان الوكلاء الفرعيين في الخلفية). ولـ[أداة OpenAPI](/ar/openapi-tools) لعملية `GET` التلميح نفسه، وتحتفظ [أداة MCP](/ar/mcp) بالتلميح الذي أرسله خادمها: وهو كلمة الخادم لا ضمانًا، فلا تربط إلا خوادم تثق بها.
* الأداة المدمجة `ask_question` (هي تسأل فقط؛ ويتوقف الاستدعاء بانتظار الجواب) والأداة `task` (يرث وكيلها الفرعي وضع plan، انظر أدناه).
* [أدوات المزوّد المستضافة](/ar/hosted-tools) تعمل داخل طلب المزوّد، فلا يمكن رفض أي استدعاء. يرسل وضع plan الأداتين `webSearch()` و`fileSearch()` (فهما تقرآن) ويترك `codeInterpreter()` وكل `hostedTool()` خارج طلب النموذج؛ وترسلها الأوضاع الأخرى كلها.

أعلن أداة مخصّصة للقراءة فقط هكذا:

```ts theme={null}
import { defineTool } from '@lousho/build-ai-agent';
import { z } from 'zod';

const lookUpOrder = defineTool({
  name: 'look_up_order',
  description: 'Read an order by id',
  input: z.object({ id: z.string() }),
  annotations: { readOnlyHint: true },
  execute: async ({ id }) => ({ id, status: 'shipped' }),
});
```

التلميح وعد تقطعه عن أداتك: يثق به وضع plan.

### تعديل الملفات: العلامة `editsFiles`

يوافق `acceptEdits` فقط على الأدوات الموسومة بأنها تعديل للملفات: `write_file` و`edit_file` من `createFsTools()`، وأي أداة معرَّفة بـ `editsFiles: true` (تُخزَّن في `metadata.editsFiles`). لا تُعدّ أداة تعديلًا للملفات باسمها وحده أبدًا، فأداة من صنعك اسمها `write_file` لا يُوافَق عليها بصمت.

```ts theme={null}
import { defineTool } from '@lousho/build-ai-agent';
import { z } from 'zod';

const appendLine = defineTool({
  name: 'append_line',
  description: 'Append a line to a file in the project',
  input: z.object({ path: z.string(), line: z.string() }),
  needsApproval: true,
  editsFiles: true,
  execute: async ({ path, line }) => `appended to ${path}: ${line}`,
});
```

## ترتيب التقييم

لكل استدعاء أداة، بهذا الترتيب:

1. التحقق من الوسائط، ثم [خطّافات](/ar/hooks) `preToolCall`. رفض الخطّاف ينهي الأمر هنا.
2. قواعد الصلاحيات (`permissions`). قاعدة `deny` تنهي الأمر هنا.
3. [حواجز حماية](/ar/guardrails) الأداة. الحجب ينهي التشغيل.
4. `needsApproval` الخاص بالأداة. الرفض ينهي الأمر هنا؛ وقاعدة `allow` أو `ask` تحلّ محل طلبها.
5. وضع الصلاحيات، على ما تبقّى.

لذلك لا يحوّل أي وضع الرفضَ إلى تشغيل: رفض الخطّاف وقاعدة `deny` ورفض `needsApproval` تبقى رفضًا في كل وضع، ولا يوافق `acceptEdits` أبدًا على استدعاء حجبه حاجز حماية.

## ضبط الوضع وتبديله

* `createAgent({ permissionMode })`: وضع الوكيل. الدالة تُقرأ عند كل استدعاء أداة، فالوضع الذي تبدّله أثناء تشغيل جارٍ يسري على استدعائه التالي.
* `agent.send(message, { permissionMode })` / `agent.stream(...)`: الوضع لذلك التشغيل وحده.
* `agent.session({ permissionMode })`، ثم `session.setPermissionMode(mode)` والمُجلِب `session.permissionMode`. تقرأ الجلسة وضعها عند كل استدعاء أداة في الدورة، فإن استُدعيت `setPermissionMode()` أثناء دورة (من مستمع `tool.start` مثلًا) سرت من استدعاء الأداة التالي في تلك الدورة. وافتراضيًا تأخذ الجلسة وضع الوكيل.

التبديل دائمًا استدعاء صريح لـ `setPermissionMode()`. ويُبلَّغ كل تبديل إلى `onPermissionModeChange` مع `{ sessionId, from, to, at }`:

```ts theme={null}
import { createAgent } from '@lousho/build-ai-agent';

const agent = createAgent({
  provider,
  instructions: 'You are a coding agent.',
  onPermissionDecision: (entry) => console.log(entry.toolName, entry.decision, entry.mode),
  onPermissionModeChange: ({ sessionId, from, to, at }) => console.log(at, sessionId, `${from} -> ${to}`),
});
```

يُضبط موجّه النظام عند بدء التشغيل: لا يُخبَر بوضع plan إلا التشغيل (أو دورة الجلسة) الذي يبدأ فيه. أما التبديل أثناء التشغيل فتفرضه بوابة استدعاء الأداة وحدها، وهذا كافٍ لأن سبب الاستدعاء المرفوض يُعلم النموذج.

## سجل التدقيق

ما دام وضع غير `'default'` مضبوطًا، يُدقَّق قرار كل استدعاء أداة حتى لو لم يضبط الوكيل `permissions` ولا `onPermissionDecision`: يذهب إلى `onPermissionDecision` (إن ضُبط) ويُبثّ كحدث `permission.decision`. ويُضبط الحقل `mode` في الإدخال حين غيّر الوضع نتيجة الاستدعاء: `'plan'` أو `'dontAsk'` مع `decision: 'deny'` و`reason` الوضع، و`'acceptEdits'` مع `decision: 'allow'`. وحين يرفض الوضع استدعاءً طابقته قاعدة `allow` يحتفظ الإدخال بـ `rule.index` لتلك القاعدة. وتذهب تبديلات الوضع إلى `onPermissionModeChange`. ويستلم `onPermissionDecision` من يعمل التشغيل نيابةً عنه بوصفه وسيطه الثاني، `{ principal }`؛ أما الإدخال والحدث فلا يحملان هوية المستدعي (انظر [auth](/ar/auth#الهويات-في-الأدوات-والموافقات)).

## الوكلاء الفرعيون

يعمل الوكيل الفرعي (الأداة `task` أو مهمة في الخلفية أو `createDelegateTool()`) بوضع الوكيل الرئيسي ما دام وضعه ليس `'default'`، وبـ `permissionMode` الخاص به فيما عدا ذلك. والوكيل الفرعي المنشأ بـ `permissionMode: 'plan'` يبقى في وضع plan أيًّا كان وضع الوكيل الرئيسي. ويُقرأ الوضع عند كل استدعاء أداة للوكيل الفرعي، فتبديل وضع جلسة الوكيل الرئيسي يسري على وكيل فرعي قيد التشغيل. وهذا ما يجعل `task` آمنة في وضع plan: فلا يستطيع الوكيل الفرعي تغيير شيء بدوره.

أما [الوكيل الفرعي البعيد](/ar/sub-agents) (`remoteAgent()`) فيعمل على خادم آخر بصلاحيات ذلك الخادم، فلا يمكن إلزامه بوضع الوكيل الرئيسي: في وضع plan يُرفض استدعاء `task` إليه من دون الاتصال به، وفي وضع `dontAsk` تُفشل الموافقة البعيدة المهمة بدل أن توقف الوكيل الرئيسي مؤقتًا.

## الاستئناف بعد موافقة

لا يُحفظ الوضع في نقاط الحفظ ولا في لقطات الموافقات. التشغيل الذي يتابعه `agent.approvals.resolve()` يستخدم الوضع الحالي للجلسة المتوقفة إذا كان التشغيل المتوقف تابعًا لجلسة، وإلا وضع الوكيل (لا الوضع الذي مرّره استدعاء `send()`). فالدورة التي توقفت في `'default'` وحُسمت بعد `session.setPermissionMode('dontAsk')` تشغّل الاستدعاء الموافَق عليه ثم ترفض الاستدعاءات التي تليه وكانت ستطلب موافقة. وفي وضع plan يُرفض الاستدعاء الموافَق عليه نفسه أيضًا إذا لم تكن أداته للقراءة فقط.

الاستئناف في عملية أخرى يستخدم الوضع الذي يملكه الوكيل أو الجلسة المستأنِفة.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.