---
title: 'استخدام Claude Tool Use في TypeScript: شرح Agentic'
description: 'شرح عملي لاستخدام أدوات Claude Sonnet 4.6: بناء typed agentic loop في TypeScript باستخدام Anthropic SDK 0.98، و parallel tool calls، و JSON Schema.'
url: https://nerdleveltech.com/ar/claude-sonnet-4-6-tool-use-typescript-agentic-loop-tutorial
language: ar
date: '2026-05-29'
category: ai-ml
tags:
  - claude
  - anthropic
  - tool-use
  - typescript
  - agentic
  - llm
  - sdk
  - sonnet-4.6
  - tutorial
  - ai-ml
markdown_url: https://nerdleveltech.com/ar/claude-sonnet-4-6-tool-use-typescript-agentic-loop-tutorial.md
attribution: 'Source: NerdLevelTech — https://nerdleveltech.com/ar/claude-sonnet-4-6-tool-use-typescript-agentic-loop-tutorial'
terms: https://nerdleveltech.com/llms.txt
---

# استخدام Claude Tool Use في TypeScript: شرح Agentic

لاستخدام ميزة استخدام الأدوات (tool use) مع Claude API في TypeScript، قم بتثبيت `@anthropic-ai/sdk`، وعرّف الأدوات باستخدام `name`، و `description`، و JSON Schema `input_schema`، ثم قم بعمل حلقة تكرارية (loop) على `client.messages.create` حتى يصبح `stop_reason` هو `end_turn`، مع تنفيذ الأدوات وإرسال النتائج مرة أخرى ككتل محتوى `tool_result` في كل دورة `tool_use`[^1].

## ملخص

ستقوم ببناء سكربت TypeScript بملف واحد (حوالي 140 سطرًا بما في ذلك تعريفات الأدوات والتحقق من صحتها) يحول Claude Sonnet 4.6 إلى وكيل (agent) يمكنه استدعاء وظائفك الخاصة. بيئة التشغيل هي Node 24 LTS، والـ SDK هو `@anthropic-ai/sdk@0.98.0`، ويتم التحقق من مدخلات الأدوات بواسطة Zod. بحلول النهاية، سيكون لديك حلقة وكيل (agentic loop) تعمل وتوزع المهام على أداتين بالتوازي، وتعالج الأخطاء بوضوح، وتخرج عند `end_turn`. وقت البناء: 20-25 دقيقة.

## ما ستتعلمه

- كيف يحول Claude `messages.create` API قائمة من الأدوات إلى حلقة وكيل مدفوعة بـ `stop_reason`
- كيفية كتابة JSON Schema صارم لـ `input_schema` والتحقق من `input` الخاص بالنموذج باستخدام Zod 4 أثناء التشغيل
- كيفية عمل استدعاءات الأدوات المتوازية — كتل `tool_use` متعددة في استجابة واحدة، يتم الرد عليها جميعًا في رسالة مستخدم واحدة
- قاعدة "يجب أن يأتي `tool_result` أولاً في مصفوفة محتوى المستخدم" التي تسبب أخطاء 400 عند مخالفتها
- كيفية تعيين كل `stop_reason` (`end_turn`، `tool_use`، `max_tokens`، `pause_turn`، `refusal`، `model_context_window_exceeded`) إلى مسار استرداد
- متى تفرض استخدام الأداة باستخدام `tool_choice` ومتى تتركها على `auto`

## المتطلبات الأساسية

- Node.js 24 LTS (LTS نشط اعتبارًا من مايو 2026، مدعوم حتى أبريل 2028)[^2] — Node 22 في مرحلة الصيانة (Maintenance LTS) يعمل أيضًا، ولكن يوصى بـ Node 24
- مفتاح Anthropic API من [لوحة تحكم منصة Claude](https://platform.claude.com/settings/keys)، يتم تصديره كـ `ANTHROPIC_API_KEY`
- ميزانية بسيطة لـ API — تشغيل التحقق في نهاية هذا البرنامج التعليمي يكلف جزءًا بسيطًا من السنت بأسعار Sonnet 4.6 (3 دولارات لكل مليون توكن مدخلات، 15 دولارًا لكل مليون توكن مخرجات)[^3]

## كيف يمكنني استخدام ميزة استخدام الأدوات مع Claude API في TypeScript؟

استخدام الأدوات في Claude API هو عبارة عن حلقة طلب واستجابة: ترسل `messages.create` مع مصفوفة `tools` من تعريفات JSON Schema، ويعيد Claude إما إجابة نهائية (`stop_reason: "end_turn"`) أو كتلة واحدة أو أكثر من كتل محتوى `tool_use` (`stop_reason: "tool_use"`)، ثم يقوم الكود الخاص بك بتشغيل الأدوات، وترسل المخرجات مرة أخرى ككتل `tool_result` في رسالة المستخدم التالية[^1]. نفس الاستدعاء يستأنف المحادثة؛ Claude لا يحتفظ بحالة الخادم (server-side state) بين الدورات.

معامل `tools` هو نفس الشكل الذي استخدمه Claude منذ إطلاق الميزة للجميع: كل أداة هي `{ name, description, input_schema }`. الـ `name` يطابق `^[a-zA-Z0-9_-]{1,64}$`، والـ `input_schema` هو كائن JSON Schema 2020-12، والـ `description` هو نص عادي — توصي Anthropic بـ 3-4 جمل أو أكثر لأي شيء غير بسيط[^1].

## الخطوة 1 — تجهيز المشروع

```bash
mkdir claude-tools-agent && cd claude-tools-agent
npm init -y
npm pkg set type="module"
npm install --save-exact @anthropic-ai/sdk@0.98.0 zod@4.4.3
npm install --save-exact -D TypeScript@6.0.3 tsx@4.22.3 @types/node@24.12.4
```

خيار `--save-exact` يكتب `"@anthropic-ai/sdk": "0.98.0"` (بدون علامة caret) حتى لا يقوم أي `npm install` مستقبلي بتحديثك بصمت إلى إصدار رئيسي جديد أو إصدار تجريبي. يرسل Anthropic TypeScript SDK تحديثات متكررة تم إنشاؤها بواسطة Stainless، لذا فإن التثبيت الدقيق للإصدار هو الخيار الافتراضي الصحيح لقارئ البرنامج التعليمي الذي سيقوم بتشغيل هذا الكود بعد أسابيع من الآن.

الآن ضع ملف `tsconfig.json` صارم:

```json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "verbatimModuleSyntax": true,
    "allowImportingTsExtensions": true,
    "noEmit": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  },
  "include": ["src/**/*.ts"]
}
```

هناك علامتان تستحقان التسليط عليهما: `noUncheckedIndexedAccess` تجعل أي وصول للفهرس في `response.content` يعيد `ContentBlock | undefined`، وهو ما يتناسب جيدًا مع `.filter(b => b.type === 'tool_use')` ويوفر عليك عمليات التحويل باستخدام `as`؛ أما `verbatimModuleSyntax` فتتطلب استخدام `import type` صريح لعمليات استيراد الأنواع فقط، مما يحافظ على نظافة كود JS الناتج تحت محلل ESM الأصلي لـ Node 24.

## الخطوة 2 — تعريف أداة مكتوبة باستخدام JSON Schema

أنشئ ملف `src/agent.ts` وابدأ بأداة طقس واحدة. الشكل مطابق لمصفوفة `tools` في API: اسم `name`، وصف `description` طويل، و `input_schema`.

```TypeScript
import Anthropic from '@anthropic-ai/sdk';
import type {
  MessageParam,
  Tool,
  ToolResultBlockParam,
  ContentBlockParam,
} from '@anthropic-ai/sdk/resources/messages';
import { z } from 'zod';

const client = new Anthropic();

const GetWeatherInput = z.object({
  location: z.string(),
  unit: z.enum(['celsius', 'fahrenheit']).default('fahrenheit'),
});

const tools: Tool[] = [
  {
    name: 'get_weather',
    description:
      'Get the current weather for a city. Returns a short string ' +
      'like "72°F, partly cloudy". Use this whenever the user asks ' +
      'about current weather, conditions, or temperature.',
    input_schema: {
      type: 'object',
      properties: {
        location: {
          type: 'string',
          description: 'City and state, e.g. "San Francisco, CA"',
        },
        unit: {
          type: 'string',
          enum: ['celsius', 'fahrenheit'],
          description: 'Temperature unit (default fahrenheit)',
        },
      },
      required: ['location'],
    },
  },
];

function runWeather(input: unknown): string {
  // The SDK types `input` as `unknown` because the schema is JSON Schema,
  // not a TS type. Zod gives us a runtime check + an inferred TS type.
  const args = GetWeatherInput.parse(input);
  const temp = args.unit === 'celsius' ? '22°C' : '72°F';
  return `${temp}, partly cloudy in ${args.location}`;
}
```

هناك خياران في التصميم يستحقان التوضيح. أولاً، الـ `description` مطول عمدًا — وثائق Anthropic نفسها تصف أوصاف الأدوات بأنها "أهم عامل في أداء الأداة على الإطلاق" وتوصي بـ 3-4 جمل على الأقل للأدوات غير البسيطة[^1]. ثانيًا، يقوم الـ SDK بتعريف نوع `block.input` كـ `unknown`، وليس كشكل TypeScript المستنتج من المخطط الخاص بك. يقوم Zod هنا بعملية تحقق حقيقية — إذا تخيل Claude حقلاً غير موجود، فسيقوم `parse()` برمي خطأ، وستلتقطه في مسار الخطأ في الخطوة 6.

## ما هي حلقة stop\_reason لاستخدام أدوات Claude؟

حلقة الوكيل هي حلقة `while (true)` تعتمد على `stop_reason`. بعد كل استدعاء لـ `messages.create`، تقوم بفحص `response.stop_reason`: تعني `end_turn` أن Claude قد انتهى ويمكنك إرجاع نصه النهائي؛ وتعني `tool_use` أن Claude يريد استدعاء أداة واحدة أو أكثر ويجب عليك الرد بكتل `tool_result` مطابقة؛ أما `max_tokens` و `pause_turn` و `refusal` فهي مسارات استرداد مغطاة في الخطوة 6[^4].

## الخطوة 3 — إضافة حلقة الوكيل

أضف هذا إلى `src/agent.ts`:

```TypeScript
async function runAgent(userMessage: string): Promise<string> {
  const messages: MessageParam[] = [{ role: 'user', content: userMessage }];

  for (let turn = 0; turn < 10; turn++) {
    const response = await client.messages.create({
      model: 'claude-sonnet-4-6',
      max_tokens: 1024,
      tools,
      messages,
    });

    // Always push the assistant turn into history BEFORE we React to it.
    // The next call needs the original tool_use blocks present so that the
    // tool_result blocks we send back have matching tool_use_ids.
    messages.push({ role: 'assistant', content: response.content });

    if (response.stop_reason === 'end_turn') {
      const textBlocks = response.content.filter((b) => b.type === 'text');
      return textBlocks.map((b) => b.text).join('\n');
    }

    if (response.stop_reason === 'tool_use') {
      const toolResults: ToolResultBlockParam[] = response.content
        .filter((b) => b.type === 'tool_use')
        .map((block) => {
          try {
            const output =
              block.name === 'get_weather'
                ? runWeather(block.input)
                : `Unknown tool: ${block.name}`;
            return {
              type: 'tool_result' as const,
              tool_use_id: block.id,
              content: output,
            };
          } catch (err) {
            return {
              type: 'tool_result' as const,
              tool_use_id: block.id,
              content: err instanceof Error ? err.message : String(err),
              is_error: true,
            };
          }
        });

      // CRITICAL: tool_result blocks must come FIRST in the user content
      // array. If you append a text block before them you get a 400 with
      // "tool_use ids were found without tool_result blocks immediately
      // after". Trailing text after the tool_results is fine.
      const content: ContentBlockParam[] = toolResults;
      messages.push({ role: 'user', content });
      continue;
    }

    if (response.stop_reason === 'max_tokens') {
      throw new Error(
        'Response truncated. Retry with a higher max_tokens.',
      );
    }

    throw new Error(`Unexpected stop_reason: ${response.stop_reason`);
  }

  throw new Error('Tool loop exceeded 10 turns — possible infinite loop');
}

const out = await runAgent('What is the weather in Tokyo and Paris?');
console.log(out);
```

تحديد عدد الدورات (`turn < 10`) هو أرخص وسيلة لحماية فاتورتك من وكيل قد يخرج عن السيطرة. في بيئة الإنتاج، ستقوم بتتبع إجمالي توكنز المدخلات والمخرجات بدلاً من ذلك، ولكن وضع حد أقصى للدورات هو الإجراء الوقائي الصحيح لمستوى هذا البرنامج التعليمي.

## الخطوة 4 — التشغيل ومراقبة الحلقة

```bash
export ANTHROPIC_API_KEY="sk-ant-..."
npx tsx src/agent.ts
```

شكل المخرجات المتوقع — ستختلف الصياغة الدقيقة من Claude، لكن الهيكل مستقر:

```
Here's the current weather for both cities:

Tokyo: 72°F, partly cloudy
Paris: 72°F, partly cloudy

Both cities are experiencing similar mild conditions today.
```

ما حدث للتو: أرسل Claude رسالة مساعد واحدة تحتوي على كتلتين `tool_use` (واحدة لكل مدينة)، قامت حلقتنا بتشغيل `runWeather` مرتين، وجمعت النتيجتين في رسالة مستخدم واحدة تحتوي على كتلتين `tool_result`، وكانت استجابة Claude التالية تحتوي على `stop_reason: "end_turn"` مع ملخص بلغة طبيعية. هذا هو استخدام الأدوات المتوازي — الموضح في الخطوة 5.

## كيف يمكنني التعامل مع استدعاءات الأدوات المتوازية من Claude؟

استدعاءات الأدوات المتوازية (Parallel tool calls) هي الوضع الافتراضي في موديلات Claude 4. عندما يحتاج Claude لاستدعاء أداتين للإجابة على سؤال، فإنه يرسل كلي بلوكات `tool_use` في نفس رسالة المساعد (assistant message)، ويجب أن يتضمن ردك بلوكات `tool_result` لجميع هذه الأدوات — في رسالة مستخدم (user message) واحدة، مع وضع بلوكات `tool_result` قبل أي نص[^1]. لإلغاء الاشتراك، قم بتعيين `disable_parallel_tool_use: true` في كائن `tool_choice` — على سبيل المثال: `tool_choice: { type: 'auto', disable_parallel_tool_use: true }`[^1].

## الخطوة 5 — إضافة أداة ثانية لجعل التوازي مرئياً

أضف أداة `get_time` التي تُرجع الوقت الحالي لمدينة ما. أوضح عرض توضيحي هو طرح سؤال على Claude يتطلب استخدام الأداتين معاً:

```TypeScript
const GetTimeInput = z.object({
  timezone: z.string(),
});

tools.push({
  name: 'get_time',
  description:
    'Get the current local time for an IANA timezone string like ' +
    '"America/Los_Angeles" or "Asia/Tokyo". Returns a string like ' +
    '"2026-05-29 18:39:48" (YYYY-MM-DD HH:MM:SS, local to that timezone, ' +
    '24-hour). Use this whenever the user asks what time it is somewhere.',
  input_schema: {
    type: 'object',
    properties: {
      timezone: {
        type: 'string',
        description: 'IANA timezone, e.g. "Asia/Tokyo"',
      },
    },
    required: ['timezone'],
  },
});

function runTime(input: unknown): string {
  const args = GetTimeInput.parse(input);
  // sv-SE renders YYYY-MM-DD HH:MM:SS, which is what the tool description
  // promises. Intl is built into Node, no extra deps needed.
  return new Intl.DateTimeFormat('sv-SE', {
    timeZone: args.timezone,
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit',
    hour12: false,
  }).format(new Date());
}
```

قم بربطها بالموزع (dispatcher) في `runAgent`:

```TypeScript
const output =
  block.name === 'get_weather' ? runWeather(block.input)
  : block.name === 'get_time' ? runTime(block.input)
  : `Unknown tool: ${block.name}`;
```

الآن قم بتغيير الطلب (prompt) لإجبار استخدام كلتا الأداتين:

```TypeScript
const out = await runAgent(
  'What time is it in Tokyo and what is the weather in Paris?',
);
```

أعد التشغيل باستخدام `npx tsx src/agent.ts`. سيحتوي `response.content` في الجولة الأولى على بلوكين `tool_use` جنباً إلى جنب؛ ستقوم حلقتنا بالتفرع، وتشغيل كليهما، وإرسال رسالة مستخدم واحدة تحتوي على بلوكين `tool_result`، وتنتهي الجولة الثانية لـ Claude بـ `end_turn`. إذا قمت بتسجيل `response.content.filter(b => b.type === 'tool_use').length` بعد الاستدعاء الأول، فسترى القيمة `2`.

## ما الفرق بين بلوكات tool\_use و tool\_result؟

تظهر بلوكات `tool_use` في رسائل المساعد — وهي تصف الاستدعاء الذي يريد Claude إجراءه، مع `id`، و `name`، وكائن `input`. تظهر بلوكات `tool_result` في رسائل المستخدم — وهي تحمل مخرجات الأداة مرة أخرى إلى Claude، مع الإشارة إلى الاستدعاء الأصلي بواسطة `tool_use_id`. يجب أن يكون لكل بلوك `tool_use` في جولة المساعد بلوك `tool_result` مطابق (نفس الـ `tool_use_id`) في جولة المستخدم التالية مباشرة، قبل أي نص، وإلا سيعيد الـ API خطأ 400[^1].

## الخطوة 6 — أخطاء الأدوات و stop\_reasons غير المتوقعة

تتعامل الحلقة بالفعل مع حالة الخطأ الشائعة — إذا قام `runWeather` برمي خطأ (بسبب فشل تحليل Zod، أو لأن المدينة غير معروفة)، فإن فرع `catch` يعيد `is_error: true` في بلوك `tool_result`. يرى Claude رسالة الخطأ ويقرر ما إذا كان سيحاول مرة أخرى بمدخلات مختلفة، أو يطلب من المستخدم التوضيح، أو يستسلم.

أربع قيم لـ `stop_reason` أقل شيوعاً تستحق المعالجة صراحة[^4]:

| سبب التوقف (Stop reason)        | ماذا يعني                                                                                                                                                                        | الاسترداد (Recovery)                                                                                                                          |
| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `max_tokens`                    | تم قطع الاستجابة، ربما في منتصف `tool_use`                                                                                                                                       | أعد محاولة نفس الطلب بقيمة `max_tokens` أعلى؛ إذا كان آخر بلوك محتوى هو `tool_use`، فلا يمكنك تشغيل تلك الأداة حتى تحصل على البلوك كاملاً[^1] |
| `pause_turn`                    | يتم إرجاعه عندما تصل حلقة أخذ العينات من جانب الخادم إلى حد التكرار الخاص بها أثناء تشغيل أدوات الخادم (الافتراضي 10 تكرارات)؛ أدوات العميل التي حددتها هنا لن ترى هذا أبداً[^4] | أضف `response.content` إلى السجل وأعد الإرسال بنفس المعاملات للمتابعة                                                                         |
| `refusal`                       | رفض Claude الإجابة لأسباب تتعلق بالسلامة                                                                                                                                         | اعرض نص الرفض للمستخدم؛ لا تحاول الإعادة تلقائياً، ستحصل فقط على نفس الإجابة[^4]                                                              |
| `model_context_window_exceeded` | وصلت الاستجابة إلى نافذة سياق الموديل قبل الوصول إلى `max_tokens`. متاح افتراضياً في Sonnet 4.5 والموديلات الأحدث، بما في ذلك Sonnet 4.6[^4]                                     | الاستجابة الجزئية صالحة؛ تعامل معها مثل `max_tokens` (حذر المستخدم، أو تابع بطلب أقصر)                                                        |

يلتقط فرع `Unexpected stop_reason` في حلقتنا أي شيء لم نعالجه صراحة، بما في ذلك `refusal` و `model_context_window_exceeded` — قم بترقية هذه إلى بلوكات `if` مخصصة بمجرد معرفة كيف تريد إظهارها.

## التحقق

قم بتشغيل السكريبت النهائي مرة أخرى مع طلب الأدوات المتوازية والتقط الهيكل:

```bash
npx tsx src/agent.ts
```

أنت تبحث عن ثلاثة أشياء:

1. يخرج السكريبت بكود 0 — لا توجد أخطاء مرفوعة، ولا توجد أخطاء 400 حول فقدان بلوكات `tool_result`
2. المخرجات المطبوعة تذكر كلاً من طوكيو وباريس (تم تشغيل أداة واحدة لكل منهما)
3. استمرت الحلقة لجولتين بالضبط — الجولة الأولى `stop_reason: "tool_use"`، والجولة الثانية `stop_reason: "end_turn"`

لتأكيد عدد الجولات برمجياً، قم بتسجيل `turn` في أعلى الحلقة أو استبدل `console.log(out)` بـ `console.log({ out, turns: ... })`. إذا رأيت أكثر من جولتين للطلب أعلاه، فمن المحتمل أن Claude استدعى أداة واحدة، ونظر في النتيجة، وقرر استدعاء أداة أخرى — هذه هي الحلقة الوكيلة (agentic loop) تقوم بعملها، وليست خطأً.

## استكشاف الأخطاء وإصلاحها

**"tool\_use ids were found without tool\_result blocks immediately after"** — رسالة المساعد التي تحتوي على بلوكات `tool_use` لم تتبعها مباشرة رسالة مستخدم يبدأ محتواها ببلوكات `tool_result` المطابقة. السببان الأكثر شيوعاً: إلحاق بلوك نصي قبل الـ `tool_result` في مصفوفة محتوى المستخدم (يتطلب الـ API وجود الـ `tool_result` أولاً، ثم النص بعده)، أو تخطي رسالة المساعد تماماً بعد رسالة ذات `stop_reason: "tool_use"`.

**"Input tag does not match any valid tag" أو عدم تطابق المخطط (schema mismatch)** — قام Claude بإنشاء `input` لا يطابق الـ `input_schema` الخاص بك. أضف `strict: true` إلى تعريف الأداة لجعل الـ API يضمن التحقق من صحة المخطط لأسماء الأدوات والمدخلات[^5] — لاحظ أن استخدام الأدوات الصارم (strict tool use) يتطلب أيضاً `additionalProperties: false` في كل مخطط كائن ويدعم فقط مجموعة فرعية مقيدة من JSON Schema، لذا تحقق من وثائق الوضع الصارم قبل التمكين. وتحقق من الـ `description` الخاص بك — يشير دليل استخدام الأدوات من Anthropic مراراً وتكراراً إلى أن الأوصاف الغامضة هي السبب الجذري للوسائط السيئة[^1].

**الحلقة تعمل للأبد** — يستدعي Claude نفس الأداة مراراً وتكراراً لأنه غير راضٍ عن النتيجة. اجعل سلسلة الإرجاع الخاصة بالأداة تتضمن الإجابة التي يحتاجها Claude ("temperature: 22°C, conditions: partly cloudy") بدلاً من مجرد تأكيدات ("weather lookup complete")؛ وحافظ على سقف الجولات في `runAgent` قصيراً حتى تثق في سطح أدواتك.

**`429 rate_limit_error`** — أنت تصل إلى حد الطلبات في الدقيقة الخاص بفئتك. أضف `await new Promise(r => setTimeout(r, 1000))` بين الجولات، أو استخدم خطاف الإعادة المدمج في SDK عن طريق تمرير `maxRetries: 3` إلى `new Anthropic({ maxRetries: 3 })`.

## كيف أجبر Claude على استخدام أداة معينة؟

قم بتمرير `tool_choice` في الطلب. الخيار `{type: 'auto'}` (الافتراضي عند تعيين `tools`) يترك لـ Claude القرار؛ بينما `{type: 'any'}` يجبره على استخدام أداة ما ولكن ليس أداة محددة؛ أما `{type: 'tool', name: 'get_weather'}` فيجبره على استخدام تلك الأداة تحديداً؛ و `{type: 'none'}` يعطل جميع الأدوات[^1]. لاحظ أن `any` و `tool` غير متوافقين مع التفكير الممتد (extended thinking) في Sonnet 4.6 — فقط `auto` و `none` هما اللذان يعملان عند تفعيل التفكير الممتد[^1].

## الخطوات التالية ومزيد من القراءة

توفر حزمة أدوات التطوير (SDK) الخاصة بـ Anthropic لـ TypeScript مساعداً تجريبياً (beta helper)، وهو `client.beta.messages.toolRunner`، الذي يغلف الحلقة اليدوية المذكورة أعلاه ويضيف `betaZodTool` المعتمد على Zod، والضغط التلقائي للسياقات الطويلة، وإلغاء العمليات المدمج عبر `AbortSignal`[^6]. إنه الخيار الصحيح للإنتاج بمجرد استيعابك لما تفعله الحلقة اليدوية — لكن الحلقة اليدوية هي ما يعمل في الخلفية، وواجهة `messages.create` المستقرة وغير التجريبية هي ما تعتمد عليه وكلاء الإنتاج منذ أن أصبح استخدام الأدوات متاحاً بشكل عام (GA) في عام 2024.

إذا كنت تنتقل إلى ما هو أبعد من مجرد سكربت واحد، فإن الخطوة الطبيعية التالية هي عرض نفس مجموعة الأدوات هذه من خلال [خادم MCP في TypeScript مع OAuth و HTTP قابل للبث](https://nerdleveltech.com/mcp-server-TypeScript-oauth-streamable-http-production-tutorial) بحيث يمكن لأي عميل يدعم MCP (مثل Claude Code أو Cursor أو واجهتك الخاصة) الاتصال به. إذا كنت ترغب في تقييم المطالبات (prompts) التي تقود وكيلك، فإن [promptfoo مع التأكيدات وبوابات CI](https://nerdleveltech.com/promptfoo-test-llm-prompts-ci-tutorial) يمنحك اختبارات تراجع لكل مطالبة. وإذا كنت ترغب في استبدال Sonnet 4.6 بـ GPT-5.4 أو Gemini 2.5 Pro دون تغيير الكود الخاص بك، فإن [LiteLLM Proxy](https://nerdleveltech.com/litellm-proxy-production-llm-gateway-tutorial) يمنحك نفس واجهة Messages API عبر مختلف المزودين.

[^1]: Anthropic, "How to implement tool use" — <https://platform.claude.com/docs/en/agents-and-tools/tool-use/implement-tool-use> (verified 2026-05-29)

[^2]: Node.js Release Schedule — <https://nodejs.org/en/about/previous-releases> (Node 24 LTS, Active LTS through April 2028; verified 2026-05-29)

[^3]: Anthropic, "Models overview" — <https://platform.claude.com/docs/en/about-claude/models/overview> (Claude Sonnet 4.6: $3 / $15 per million input/output tokens, 1M context window, 64k max output; verified 2026-05-29)

[^4]: Anthropic, "Handling stop reasons" — <https://platform.claude.com/docs/en/build-with-claude/handling-stop-reasons> (StopReason values: `end_turn`, `max_tokens`, `stop_sequence`, `tool_use`, `pause_turn`, `refusal`, and `model_context_window_exceeded` which is available by default on Sonnet 4.5 and newer; the SDK 0.98.0 `StopReason` type currently enumerates the first six and the seventh value falls through to the loop's "Unexpected stop\_reason" branch; verified 2026-05-29)

[^5]: Anthropic, "Strict tool use" — <https://platform.claude.com/docs/en/agents-and-tools/tool-use/strict-tool-use> (and the parent "Structured outputs" page at <https://platform.claude.com/docs/en/build-with-claude/structured-outputs> — `strict: true` on tool definitions enables grammar-constrained validation on tool names and inputs; requires `additionalProperties: false` and the supported JSON Schema subset; GA on Sonnet 4.6; verified 2026-05-29)

[^6]: Anthropic TypeScript SDK helpers — <https://GitHub.com/anthropics/anthropic-sdk-TypeScript/blob/main/helpers.md#tool-helpers> (`client.beta.messages.toolRunner`, `betaZodTool`, `ToolError`; verified 2026-05-29)
