Knaph

ایمن نگه داشتنِ عامل20 از 37

زنجیره‌ی هوک‌ها

در درسِ «[هوک‌ها در عاملِ خودتان](hooks-in-your-agent)» به mini دو فهرست هوک دادید: هوک‌های پیش از اجرا که می‌توانند جلوی یک فراخوانیِ ابزار را بگیرند، و هوک‌های پس از اجرا که می‌توانند خروجی‌اش را تغییر دهند. اینجا تابعی را می‌نویسید که آن‌ها را اجرا می‌کند، یعنی run_tool، همان‌طور که mini می‌نویسد. در این تمرین هیچ مدلی صدا زده نمی‌شود: فراخوانی‌های ابزار به‌صورتِ ورودی می‌آیند، انگار مدل نوشته باشدشان. ## آنچه از پیش آماده است کدِ آغاز یک پوشه‌ی خیالی از فایل‌ها و دو ابزار به شما می‌دهد: - read_file(path) متنِ یک فایل را برمی‌گرداند، یا برای فایلی که وجود ندارد FileNotFoundError می‌دهد؛ - run_command(command) فقط ran: <command> را برمی‌گرداند. شش هوک هم در آن هست. هوک‌های پیش از اجرا: no_secrets (جلوی هر مسیری را که .env در آن باشد می‌گیرد)، no_rm (جلوی دستورهایی را که rm دارند می‌گیرد) و only_txt (جلوی خواندنِ فایلی را که به .txt ختم نمی‌شود می‌گیرد). هوک‌های پس از اجرا: cut_long (۴۰ نویسه‌ی اول را نگه می‌دارد و [cut] را اضافه می‌کند)، hide_keys (کلیدهای sk-... را به sk-*** تبدیل می‌کند) و tag ([tool name] را جلوی خروجی می‌گذارد). ## ورودی دو خط می‌گویند کدام هوک‌ها روشن‌اند، به ترتیب. بعد یک خط با ---، و بعد در هر خط یک فراخوانیِ ابزار: شناسه‌اش، نامِ ابزار، و ورودی‌هایش به‌صورتِ JSON: ``text before: no_secrets after: cut_long --- t1 read_file {"path": "notes.txt"} t2 read_file {"path": ".env"} t3 run_command {"command": "ls"} ` ## آنچه باید بنویسید run_tool(block, before, after) را کامل کنید. این تابع یک دیکشنریِ tool_result برمی‌گرداند و main آن را به‌صورتِ JSON چاپ می‌کند. قاعده‌ها، به ترتیب: 1. **ابزارِ ناشناخته** با دلیلِ no tool called <name> رد می‌شود. 2. **هوک‌های پیش از اجرا به ترتیب اجرا می‌شوند.** به محضِ اینکه یکی دلیلی برگرداند، بایستید: جلوی فراخوانی گرفته شده و هوک‌های بعدی اجرا نمی‌شوند. 3. **فراخوانیِ ردشده** "content": "Blocked: <reason>" را همراهِ "is_error": True برمی‌گرداند و هیچ اتفاقِ دیگری نمی‌افتد. 4. **وگرنه ابزار اجرا می‌شود**، با ورودی‌ها به‌صورتِ آرگومان‌های نام‌دار: TOOLS[name](args)`. اگر خطا داد، `"content": "Error: <the error's message>"` را همراهِ `"is_error": True` برگردانید. هوک‌های پس از اجرا اجرا نمی‌شوند. 5. بعد هوک‌های پس از اجرا به ترتیب اجرا می‌شوند، هر کدام روی خروجیِ قبلی. 6. نتیجه‌ای که کار کرده** اصلاً کلیدِ is_error ندارد. برای نمونه‌ی بالا، خروجی این است: ``text {"content": "Buy milk.\nCall Sara about the March repo [cut]", "tool_use_id": "t1", "type": "tool_result"} {"content": "Blocked: never read .env files", "is_error": true, "tool_use_id": "t2", "type": "tool_result"} {"content": "ran: ls", "tool_use_id": "t3", "type": "tool_result"} ` <details> <summary>یک راهنمایی، اگر گیر کردید</summary> run_tool خودِ mini در یک حلقه reason = reason or hook(name, args) را به کار می‌برد. این هر هوک را فقط تا وقتی صدا می‌زند که هنوز چیزی جلوی فراخوانی را نگرفته باشد. با reason = None if name in TOOLS else f"no tool called {name}"` شروع کنید. </details> وقتی کار کرد، به چیزی که ساخته‌اید نگاه کنید: قاعده‌های mini دیگر در ابزارهایش پخش نیستند. هر فراخوانی، از هر ابزاری، هر بار از همین چند خط و به همین ترتیب می‌گذرد.

ورود برای امتحان این تمرین.