{"id":31141,"date":"2026-10-20T13:35:49","date_gmt":"2026-10-20T13:35:49","guid":{"rendered":"https:\/\/umang.pk\/2026\/10\/20\/%d9%b9%d8%a7%d8%a6%d9%be-%d8%a7%d8%b3%da%a9%d8%b1%d9%be%d9%b9-%d9%85%db%8c%da%ba-%d8%b4%d8%b1%d9%88%d8%b9-%d8%b3%db%92-ai-%d8%a7%db%8c%d8%ac%d9%86%d9%b9-%da%a9%d8%a7-%d8%a7%d8%b3%d8%aa%d8%b9%d9%85\/"},"modified":"2026-10-20T13:35:51","modified_gmt":"2026-10-20T13:35:51","slug":"%d9%b9%d8%a7%d8%a6%d9%be-%d8%a7%d8%b3%da%a9%d8%b1%d9%be%d9%b9-%d9%85%db%8c%da%ba-%d8%b4%d8%b1%d9%88%d8%b9-%d8%b3%db%92-ai-%d8%a7%db%8c%d8%ac%d9%86%d9%b9-%da%a9%d8%a7-%d8%a7%d8%b3%d8%aa%d8%b9%d9%85","status":"publish","type":"post","link":"https:\/\/umang.pk\/en_us\/2026\/10\/20\/%d9%b9%d8%a7%d8%a6%d9%be-%d8%a7%d8%b3%da%a9%d8%b1%d9%be%d9%b9-%d9%85%db%8c%da%ba-%d8%b4%d8%b1%d9%88%d8%b9-%d8%b3%db%92-ai-%d8%a7%db%8c%d8%ac%d9%86%d9%b9-%da%a9%d8%a7-%d8%a7%d8%b3%d8%aa%d8%b9%d9%85\/","title":{"rendered":"\u0679\u0627\u0626\u067e \u0627\u0633\u06a9\u0631\u067e\u0679 \u0645\u06cc\u06ba \u0634\u0631\u0648\u0639 \u0633\u06d2 AI \u0627\u06cc\u062c\u0646\u0679 \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u06cc\u0633\u06d2 \u06a9\u0631\u06cc\u06ba\u06d4"},"content":{"rendered":"\n<div id=\"\">\n<p>\u0628\u06c1\u062a \u0633\u06d2 AI \u0627\u06cc\u062c\u0646\u0679 \u0679\u06cc\u0648\u0679\u0648\u0631\u06cc\u0644 \u0632\u0628\u0627\u0646 \u06a9\u06d2 \u0645\u0627\u0688\u0644 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0634\u0631\u0648\u0639 \u06c1\u0648\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u0627\u0633\u06d2 \u06a9\u0686\u06be \u0679\u0648\u0644\u0632 \u062f\u06cc\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u0627\u0648\u0631 \u0627\u0633 \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u0627\u0633 \u0648\u0642\u062a \u062a\u06a9 \u0644\u0648\u067e \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba \u062c\u0628 \u062a\u06a9 \u06a9\u06c1 \u06cc\u06c1 \u062c\u0648\u0627\u0628 \u0646\u06c1\u06cc\u06ba \u0628\u0646\u0627\u062a\u0627\u06d4 \u0679\u0648\u0644 \u06a9\u0627\u0644 \u06a9\u0648 \u0638\u0627\u06c1\u0631 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u06cc\u06c1 \u06a9\u0627\u0641\u06cc \u06c1\u06d2\u060c \u0644\u06cc\u06a9\u0646 \u0627\u0646\u062c\u06cc\u0646\u0626\u0631\u0646\u06af \u06a9\u06d2 \u062f\u0644\u0686\u0633\u067e \u0633\u0648\u0627\u0644\u0627\u062a \u06a9\u06d2 \u062c\u0648\u0627\u0628\u0627\u062a \u0628\u0627\u0642\u06cc \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u0627\u06af\u0631 \u0679\u0648\u0644 \u0646\u0627\u06a9\u0627\u0645 \u06c1\u0648 \u062c\u0627\u0626\u06d2 \u062a\u0648 \u06a9\u06cc\u0627 \u06c1\u0648\u06af\u0627\u061f \u062f\u0639\u0648\u0648\u06ba \u06a9\u06cc \u062a\u0635\u062f\u06cc\u0642 \u06a9\u0648\u0646 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u061f \u0627\u06cc\u062c\u0646\u0679 \u06a9\u0648 \u063a\u06cc\u0631 \u0645\u0639\u06cc\u0646\u06c1 \u0645\u062f\u062a \u062a\u06a9 \u0686\u0644\u0627\u0646\u06d2\u060c \u063a\u06cc\u0631 \u0645\u062d\u0641\u0648\u0638 \u062d\u06a9\u0645\u0648\u06ba \u067e\u0631 \u0639\u0645\u0644 \u06a9\u0631\u0646\u06d2\u060c \u06cc\u0627 \u0633\u06cc\u0627\u0642 \u0648 \u0633\u0628\u0627\u0642 \u06a9\u06cc \u0648\u0646\u0688\u0648 \u06a9\u0648 \u062e\u062a\u0645 \u06a9\u0631\u0646\u06d2 \u0633\u06d2 \u06a9\u06cc\u0633\u06d2 \u0631\u0648\u06a9\u0627 \u062c\u0627\u0626\u06d2\u061f \u0627\u0648\u0631 \u0622\u067e \u063a\u06cc\u0631 \u0645\u062a\u0648\u0642\u0639 \u0645\u0627\u0688\u0644 \u06a9\u06d2 \u062c\u0648\u0627\u0628\u0627\u062a \u067e\u0631 \u0628\u06be\u0631\u0648\u0633\u06c1 \u06a9\u06cc\u06d2 \u0628\u063a\u06cc\u0631 \u0627\u0633 \u06a9\u06cc \u062c\u0627\u0646\u0686 \u06a9\u06cc\u0633\u06d2 \u06a9\u0631\u06cc\u06ba \u06af\u06d2\u061f<\/p>\n<p>\u06cc\u06c1 \u06c1\u06d2 <strong>\u0627\u06cc\u062c\u0646\u0679 \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644<\/strong>: \u0648\u06c1 \u0633\u0627\u0641\u0679 \u0648\u06cc\u0626\u0631 \u062c\u0648 \u0632\u0628\u0627\u0646 \u06a9\u06d2 \u0645\u0627\u0688\u0644 \u0627\u0648\u0631 \u0627\u0633 \u0645\u0627\u062d\u0648\u0644 \u06a9\u06d2 \u062f\u0631\u0645\u06cc\u0627\u0646 \u06a9\u06be\u0691\u0627 \u06c1\u06d2 \u062c\u0633 \u0645\u06cc\u06ba \u06cc\u06c1 \u06a9\u0627\u0645 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0627\u0633 \u0679\u06cc\u0648\u0679\u0648\u0631\u06cc\u0644 \u0645\u06cc\u06ba\u060c \u06c1\u0645 \u0645\u062b\u0627\u0644 \u06a9\u06d2 \u0637\u0648\u0631 \u067e\u0631 \u0627\u06cc\u06a9 \u06a9\u0648\u0688\u0646\u06af \u0627\u06cc\u062c\u0646\u0679 \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 TypeScript \u0645\u06cc\u06ba \u0627\u06cc\u06a9 \u0686\u06be\u0648\u0679\u0627\u060c \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0646\u0646\u062f\u06c1-\u0627\u06cc\u06af\u0646\u0648\u0633\u0679\u06a9 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u0628\u0646\u0627\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u0628\u0646\u06cc\u0627\u062f\u06cc \u0627\u06cc\u06af\u0632\u06cc\u06a9\u06cc\u0648\u0634\u0646 \u0644\u0648\u067e \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0634\u0631\u0648\u0639 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2\u060c \u06c1\u0645 \u0628\u062a\u062f\u0631\u06cc\u062c \u0679\u0648\u0644 \u06a9\u06cc \u062a\u0648\u062b\u06cc\u0642\u060c \u0648\u0631\u06a9 \u0627\u0633\u067e\u06cc\u0633 \u0622\u0626\u0633\u0648\u0644\u06cc\u0634\u0646\u060c \u0627\u06cc\u06af\u0632\u06cc\u06a9\u06cc\u0648\u0634\u0646 \u0628\u062c\u0679\u060c \u0633\u06cc\u0627\u0642 \u0648 \u0633\u0628\u0627\u0642 \u06a9\u0627 \u0627\u0646\u062a\u0638\u0627\u0645\u060c \u0645\u0634\u0627\u06c1\u062f\u0627\u062a\u06cc\u060c \u0627\u0648\u0631 \u0688\u06cc\u0679\u0631\u0645\u0646\u0633\u0679\u06a9 \u0627\u06cc\u0631\u0631 \u0679\u06cc\u0633\u0679\u0646\u06af \u0634\u0627\u0645\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<h2 id=\"heading-what-well-cover\">\u062c\u0633 \u06a9\u0627 \u06c1\u0645 \u0627\u062d\u0627\u0637\u06c1 \u06a9\u0631\u06cc\u06ba \u06af\u06d2\u06d4<\/h2>\n<h2 id=\"heading-prerequisites\">\u0634\u0631\u0637\u06cc\u06ba<\/h2>\n<p>\u0627\u06af\u0631 \u0622\u067e TypeScript \u0633\u06d2 \u0648\u0627\u0642\u0641 \u06c1\u06cc\u06ba \u0627\u0648\u0631 AI \u0627\u06cc\u062c\u0646\u0679\u0633 \u06a9\u06d2 \u0628\u0627\u0631\u06d2 \u0645\u06cc\u06ba \u0628\u0646\u06cc\u0627\u062f\u06cc \u0645\u0639\u0644\u0648\u0645\u0627\u062a \u0631\u06a9\u06be\u062a\u06d2 \u06c1\u06cc\u06ba \u062a\u0648 \u06cc\u06c1 \u0645\u062f\u062f\u06af\u0627\u0631 \u062b\u0627\u0628\u062a \u06c1\u0648\u06af\u0627\u06d4 \u06cc\u06c1 Node.js 24\u060c TypeScript\u060c \u0627\u0648\u0631 \u06a9\u0645 \u0633\u06d2 \u06a9\u0645 \u0627\u0646\u062d\u0635\u0627\u0631 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0628\u0644\u0679 \u0627\u0646 \u0679\u06cc\u0633\u0679 \u0631\u0646\u0631 \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0645\u06a9\u0645\u0644 \u0639\u0645\u0644 \u062f\u0631\u0622\u0645\u062f \u0633\u0627\u062a\u06be\u06cc \u0631\u06cc\u067e\u0648\u0632\u0679\u0631\u06cc\u060c \u0627\u06cc\u062c\u0646\u0679-\u06c1\u0627\u0631\u0646\u0633-\u0641\u0631\u0645 \u0633\u06a9\u0631\u06cc\u0686 \u0645\u06cc\u06ba \u062f\u0633\u062a\u06cc\u0627\u0628 \u06c1\u06d2\u06d4 \u06c1\u0631 \u0633\u06cc\u06a9\u0634\u0646 \u0627\u06cc\u06a9 \u06af\u0679 \u0679\u06cc\u06af \u0633\u06d2 \u0645\u0645\u0627\u062b\u0644 \u06c1\u06d2\u060c \u0644\u06c1\u0630\u0627 \u0622\u067e \u0627\u0633 \u0645\u0646\u0635\u0648\u0628\u06d2 \u06a9\u06cc \u067e\u06cc\u0631\u0648\u06cc \u06a9\u0631 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba \u06a9\u06cc\u0648\u0646\u06a9\u06c1 \u0627\u0633\u06d2 \u062d\u062a\u0645\u06cc \u06a9\u0648\u0688 \u0633\u06d2 \u0634\u0631\u0648\u0639 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2 \u062a\u06cc\u0627\u0631 \u06a9\u06cc\u0627 \u06af\u06cc\u0627 \u06c1\u06d2\u06d4<\/p>\n<h2 id=\"heading-1-build-the-basic-agent-loop\">1. \u0627\u06cc\u06a9 \u0628\u0646\u06cc\u0627\u062f\u06cc \u0627\u06cc\u062c\u0646\u0679 \u0644\u0648\u067e \u0628\u0646\u0627\u0646\u0627<\/h2>\n<p>\u067e\u06cc\u0631\u0648\u06cc \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u0628\u062a\u062f\u0627\u0626\u06cc \u0633\u0646\u06af \u0645\u06cc\u0644 \u06a9\u0648 \u062f\u06cc\u06a9\u06be\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-shell\">git clone https:\/\/github.com\/gkoos\/agent-harness-from-scratch.git\ncd agent-harness-from-scratch\ngit switch --detach 01-model-loop\nnpm ci\nnpm run typecheck\nnpm test\nnpm run demo\n<\/code><\/pre>\n<p>\u0639\u0644\u06cc\u062d\u062f\u06c1 \u0686\u06cc\u06a9 \u0622\u0624\u0679 \u0622\u067e \u06a9\u0648 \u0634\u0627\u062e\u0648\u06ba \u06a9\u0648 \u0645\u0646\u062a\u0642\u0644 \u06a9\u06cc\u06d2 \u0628\u063a\u06cc\u0631 \u06cc\u06c1\u0627\u06ba \u0628\u06cc\u0627\u0646 \u06a9\u0631\u062f\u06c1 \u0639\u06cc\u0646 \u0645\u0637\u0627\u0628\u0642 \u0627\u0633\u0646\u06cc\u067e \u0634\u0627\u0679\u0633 \u062f\u06cc\u06a9\u06be\u0646\u06d2 \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u062f\u06cc\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u062c\u0628 \u0622\u067e \u0627\u06af\u0644\u06d2 \u062d\u0635\u06d2 \u067e\u0631 \u067e\u06c1\u0646\u0686 \u062c\u0627\u0626\u06cc\u06ba \u062a\u0648 \u0627\u0633 \u0679\u06cc\u06af \u067e\u0631 \u062c\u0627\u0626\u06cc\u06ba\u06d4 Node.js 24 \u0627\u0648\u0631 npm \u0627\u0646\u0633\u0679\u0627\u0644 \u06c1\u0648\u0646\u0627 \u0636\u0631\u0648\u0631\u06cc \u06c1\u06d2\u06d4<\/p>\n<p>\u0633\u0628 \u0633\u06d2 \u0627\u06c1\u0645 \u0622\u0631\u06a9\u06cc\u0679\u06cc\u06a9\u0686\u0631\u0644 \u0641\u06cc\u0635\u0644\u06c1 \u06c1\u06d2 <strong>\u062c\u0628 \u06a9\u0646\u0679\u0631\u0648\u0644 \u0686\u0644 \u0631\u06c1\u0627 \u06c1\u06d2\u060c \u0645\u0627\u0688\u0644 \u06a9\u0627\u0631\u0631\u0648\u0627\u0626\u06cc\u0648\u06ba \u06a9\u06cc \u062a\u062c\u0648\u06cc\u0632 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/strong>. \u062c\u0628 \u0645\u0627\u0688\u0644 \u0679\u0648\u0644 \u06a9\u0627\u0644 \u06a9\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u062a\u0648 \u06cc\u06c1 \u062f\u0631\u062d\u0642\u06cc\u0642\u062a \u06a9\u0686\u06be \u0628\u06be\u06cc \u0646\u06c1\u06cc\u06ba \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u0679\u0648\u0644 \u06a9\u06d2 \u0646\u0627\u0645 \u0627\u0648\u0631 \u062f\u0644\u0627\u0626\u0644 \u067e\u0631 \u0645\u0634\u062a\u0645\u0644 \u0627\u06cc\u06a9 \u0645\u0646\u0638\u0645 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u0628\u0646\u0627\u0626\u06cc\u06d4 \u06c1\u0627\u0631\u0646\u0633 \u06a9\u0648 \u0627\u0633 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u06cc \u062a\u0634\u0631\u06cc\u062d \u06a9\u0631\u0646\u0627 \u0686\u0627\u06c1\u06cc\u06d2\u060c \u0627\u0633 \u06a9\u06d2 \u0646\u0641\u0627\u0630 \u06a9\u0648 \u06a9\u0627\u0644 \u06a9\u0631\u0646\u0627 \u0686\u0627\u06c1\u06cc\u06d2\u060c \u0627\u0648\u0631 \u0646\u062a\u0627\u0626\u062c \u06a9\u0648 \u0645\u0627\u0688\u0644 \u067e\u0631 \u0648\u0627\u067e\u0633 \u06a9\u0631\u0646\u0627 \u0686\u0627\u06c1\u06cc\u06d2\u06d4<\/p>\n<p>\u062a\u0639\u0627\u0645\u0644\u0627\u062a \u062f\u0631\u062c \u0630\u06cc\u0644 \u06c1\u06cc\u06ba:<\/p>\n<p>\u0622\u0626\u06cc\u06d2 \u0627\u06cc\u06a9 \u0645\u0639\u0627\u06c1\u062f\u06d2 \u06a9\u06cc \u0648\u0636\u0627\u062d\u062a \u06a9\u0631\u06a9\u06d2 \u0634\u0631\u0648\u0639 \u06a9\u0631\u06cc\u06ba\u06d4 <code>src\/core\/types.ts<\/code>.<\/p>\n<pre><code class=\"language-typescript\">export type ToolCall = { id: string; name: string; arguments: unknown };\n\nexport type Message =\n  | { role: 'user'; content: string }\n  | { role: 'assistant'; content: string; toolCalls?: ToolCall[] }\n  | { role: 'tool'; callId: string; content: string; isError: boolean };\n\nexport interface ToolDefinition {\n  name: string;\n  description: string;\n  parameters: Record<string unknown=\"\">; \/\/ JSON Schema for the model\n}\n\nexport interface Tool extends ToolDefinition {\n  execute(argumentsValue: unknown, signal: AbortSignal): Promise<unknown>;\n}\n\nexport interface Model {\n  generate(input: {\n    messages: readonly Message[];\n    tools: readonly ToolDefinition[];\n    signal: AbortSignal;\n  }): Promise<{ content: string; toolCalls?: ToolCall[] }>;\n}\n\nexport type AgentResult = {\n  status: 'completed' | 'step_limit' | 'aborted';\n  answer?: string;\n  messages: Message[];\n  steps: number;\n};\n<\/unknown><\/string><\/code><\/pre>\n<p>\u06a9\u06c1 <code>Model<\/code> \u0627\u0646\u0679\u0631\u0641\u06cc\u0633 \u0645\u06cc\u06ba \u062c\u0627\u0646 \u0628\u0648\u062c\u06be \u06a9\u0631 OpenAI\u060c Anthropic\u060c \u06cc\u0627 \u06a9\u0633\u06cc \u062f\u0648\u0633\u0631\u06d2 \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0646\u0646\u062f\u06c1 \u0633\u06d2 \u0645\u062a\u0639\u0644\u0642 \u06a9\u0648\u0626\u06cc \u0645\u0648\u0627\u062f \u0634\u0627\u0645\u0644 \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4 \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0646\u0646\u062f\u06c1 \u0627\u0688\u0627\u067e\u0679\u0631 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0648 \u062a\u0628\u062f\u06cc\u0644 \u06a9\u06cc\u06d2 \u0628\u063a\u06cc\u0631 APIs \u0627\u0648\u0631 \u0627\u0646 \u0627\u0642\u0633\u0627\u0645 \u06a9\u06d2 \u062f\u0631\u0645\u06cc\u0627\u0646 \u062a\u0628\u062f\u06cc\u0644 \u06a9\u0631 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u0622\u0644\u06d2 \u06a9\u06d2 \u062f\u0644\u0627\u0626\u0644 \u06c1\u06cc\u06ba: <code>unknown<\/code>\u0646\u06c1\u06cc\u06ba <code>any<\/code>. \u0645\u0627\u0688\u0644 \u0633\u06d2 \u062a\u06cc\u0627\u0631 \u06a9\u0631\u062f\u06c1 \u0688\u06cc\u0679\u0627 \u0627\u06cc\u06a9 \u0646\u0627\u0642\u0627\u0628\u0644 \u0627\u0639\u062a\u0628\u0627\u0631 \u0627\u0646 \u067e\u0679 \u06c1\u06d2\u06d4 \u06c1\u0645 \u0627\u0633\u06d2 \u0627\u06af\u0644\u06d2 \u062d\u0635\u06d2 \u0645\u06cc\u06ba \u0686\u0644\u0627\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u0627\u0633 \u06a9\u06cc \u062a\u0648\u062b\u06cc\u0642 \u06a9\u0631\u06cc\u06ba \u06af\u06d2\u06d4<\/p>\n<p>\u0627\u06cc\u062c\u0646\u0679 \u0644\u0648\u067e <code>src\/core\/agent.ts<\/code> \u0627\u0646 \u0622\u0633\u0627\u0646 \u0627\u0642\u062f\u0627\u0645\u0627\u062a \u067e\u0631 \u0639\u0645\u0644 \u06a9\u0631\u06cc\u06ba:<\/p>\n<ol>\n<li>\n<p>\u0645\u0627\u0688\u0644 \u06a9\u0648 \u0688\u0627\u0626\u06cc\u0644\u0627\u06af \u0627\u0648\u0631 \u062f\u0633\u062a\u06cc\u0627\u0628 \u0679\u0648\u0644 \u06a9\u06cc \u062a\u0639\u0631\u06cc\u0641\u06cc\u06ba \u0628\u06be\u06cc\u062c\u06cc\u06ba\u06d4<\/p>\n<\/li>\n<li>\n<p>\u06af\u0641\u062a\u06af\u0648 \u0645\u06cc\u06ba \u0645\u0627\u0688\u0644 \u06a9\u0627 \u062c\u0648\u0627\u0628 \u0634\u0627\u0645\u0644 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<\/li>\n<li>\n<p>\u0627\u06af\u0631 \u0622\u067e \u0646\u06d2 \u06a9\u0633\u06cc \u0679\u0648\u0644 \u06a9\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u06cc \u06c1\u06d2 \u062a\u0648 \u0627\u0633\u06d2 \u0686\u0644\u0627\u0626\u06cc\u06ba \u0627\u0648\u0631 \u0646\u062a\u0627\u0626\u062c \u06a9\u0648 \u0634\u0627\u0645\u0644 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<\/li>\n<li>\n<p>\u0627\u0633 \u0648\u0642\u062a \u062a\u06a9 \u0627\u0639\u0627\u062f\u06c1 \u06a9\u0631\u06cc\u06ba \u062c\u0628 \u062a\u06a9 \u06a9\u06c1 \u0645\u0627\u0688\u0644 \u062d\u062a\u0645\u06cc \u062c\u0648\u0627\u0628 \u0646\u06c1 \u062f\u06d2 \u06cc\u0627 \u06c1\u0627\u0631\u0646\u0633 \u0642\u062f\u0645 \u06a9\u06cc \u062d\u062f \u062a\u06a9 \u0646\u06c1 \u067e\u06c1\u0646\u0686 \u062c\u0627\u0626\u06d2\u06d4<\/p>\n<\/li>\n<\/ol>\n<p>\u06cc\u06c1\u0627\u06ba \u0645\u06a9\u0645\u0644 \u0627\u0628\u062a\u062f\u0627\u0626\u06cc \u0644\u0648\u067e \u06c1\u06d2: <code>src\/core\/agent.ts<\/code>. \u0645\u0627\u0688\u0644 \u0679\u0648\u0644 \u06a9\u06cc \u062a\u0639\u0631\u06cc\u0641\u06cc\u06ba \u062d\u0627\u0635\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u06c1\u0627\u0631\u0646\u0633 \u0642\u0627\u0628\u0644 \u0639\u0645\u0644 \u0639\u0645\u0644 \u062f\u0631\u0622\u0645\u062f \u0631\u06a9\u06be\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-typescript\">import type { AgentResult, Message, Model, Tool } from '.\/types.ts';\n\nexport async function runAgent(options: {\n  model: Model;\n  tools: readonly Tool[];\n  prompt: string;\n  maxSteps?: number;\n  signal?: AbortSignal;\n}): Promise<agentresult> {\n  const { model, tools, prompt, maxSteps = 10 } = options;\n  if (!Number.isSafeInteger(maxSteps) || maxSteps < 1) {\n    throw new RangeError('maxSteps must be a positive safe integer');\n  }\n  const signal = options.signal ?? new AbortController().signal;\n  const messages: Message[] = [{ role: 'user', content: prompt }];\n  const registry = new Map(tools.map(tool => [tool.name, tool]));\n  if (registry.size !== tools.length) throw new Error('Duplicate tool names');\n  const definitions = tools.map(({ name, description, parameters }) => ({ name, description, parameters }));\n\n  for (let step = 0; step < maxSteps; step++) {\n    if (signal.aborted) return { status: 'aborted', messages, steps: step };\n    let response;\n    try {\n      response = await model.generate({ messages: [...messages], tools: definitions, signal });\n    } catch (error) {\n      if (signal.aborted) return { status: 'aborted', messages, steps: step };\n      throw error;\n    }\n    if (signal.aborted) return { status: 'aborted', messages, steps: step };\n    const calls = response.toolCalls ?? [];\n    messages.push({ role: 'assistant', content: response.content, ...(calls.length ? { toolCalls: calls } : {}) });\n    if (!calls.length) return { status: 'completed', answer: response.content, messages, steps: step + 1 };\n\n    for (const call of calls) {\n      if (signal.aborted) return { status: 'aborted', messages, steps: step + 1 };\n      const tool = registry.get(call.name);\n      if (!tool) {\n        messages.push({ role: 'tool', callId: call.id, content: `Unknown tool: ${call.name}`, isError: true });\n        continue;\n      }\n      try {\n        const result = await tool.execute(call.arguments, signal);\n        if (signal.aborted) return { status: 'aborted', messages, steps: step + 1 };\n        messages.push({ role: 'tool', callId: call.id, content: JSON.stringify(result) ?? 'null', isError: false });\n      } catch (error) {\n        if (signal.aborted) return { status: 'aborted', messages, steps: step + 1 };\n        messages.push({\n          role: 'tool', callId: call.id,\n          content: error instanceof Error ? error.message : String(error),\n          isError: true\n        });\n      }\n    }\n  }\n  return { status: 'step_limit', messages, steps: maxSteps };\n}\n<\/agentresult><\/code><\/pre>\n<p>\u0627\u06af\u0631 \u06cc\u06c1 \u0679\u0648\u0644 \u06a9\u0648 \u06a9\u0627\u0644 \u06a9\u06cc\u06d2 \u0628\u063a\u06cc\u0631 \u062c\u0648\u0627\u0628 \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u060c \u062a\u0648 \u0639\u0645\u0644\u062f\u0631\u0622\u0645\u062f \u062e\u062a\u0645 \u06c1\u0648\u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4 \u0628\u0635\u0648\u0631\u062a \u062f\u06cc\u06af\u0631\u060c \u06c1\u0627\u0631\u0646\u0633 \u06c1\u0631 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u0631\u062f\u06c1 \u0679\u0648\u0644 \u06a9\u0648 \u062a\u0644\u0627\u0634 \u06a9\u0631\u06d2 \u06af\u0627 \u0627\u0648\u0631 \u0627\u0633 \u067e\u0631 \u0639\u0645\u0644 \u062f\u0631\u0622\u0645\u062f \u06a9\u0631\u06d2 \u06af\u0627\u06d4<\/p>\n<p>\u0679\u0648\u0644 \u06a9\u06cc \u062e\u0631\u0627\u0628\u06cc \u06a9\u06cc \u0648\u062c\u06c1 \u0633\u06d2 \u0627\u06cc\u062c\u0646\u0679 \u062e\u0648\u062f \u0628\u062e\u0648\u062f \u062e\u062a\u0645 \u0646\u06c1\u06cc\u06ba \u06c1\u0648\u062a\u0627 \u06c1\u06d2\u06d4 \u0627\u0633 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2\u060c \u06c1\u0627\u0631\u0646\u0633 \u0627\u0635\u0644 \u06a9\u0627\u0644 ID \u0633\u06d2 \u0645\u062a\u0639\u0644\u0642 \u0627\u06cc\u06a9 \u0627\u06cc\u0631\u0631 \u0645\u06cc\u0633\u062c \u0644\u0627\u06af \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u06cc\u06c1 \u0645\u0627\u0688\u0644 \u06a9\u0648 \u0627\u06af\u0644\u06cc \u0628\u0627\u0631 \u0644\u0627\u067e\u062a\u06c1 \u0641\u0627\u0626\u0644\u0648\u06ba \u06cc\u0627 \u0646\u0627\u06a9\u0627\u0645 \u0622\u067e\u0631\u06cc\u0634\u0646\u0632 \u067e\u0631 \u0631\u062f\u0639\u0645\u0644 \u0638\u0627\u06c1\u0631 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u06c1\u0645 \u0645\u0627\u0688\u0644 \u06a9\u06cc \u06af\u0631\u062f\u0634\u0648\u06ba \u06a9\u06cc \u0632\u06cc\u0627\u062f\u06c1 \u0633\u06d2 \u0632\u06cc\u0627\u062f\u06c1 \u062a\u0639\u062f\u0627\u062f \u0628\u06be\u06cc \u0644\u06af\u0627\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u0645\u0627\u0688\u0644 \u06a9\u0627\u0645 \u06a9\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u0631\u0646\u0627 \u062c\u0627\u0631\u06cc \u0631\u06a9\u06be \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u060c \u0644\u06cc\u06a9\u0646 \u06cc\u06c1 \u0627\u0633 \u06a9\u06d2 \u0639\u0645\u0644 \u062f\u0631\u0622\u0645\u062f \u06a9\u06d2 \u0648\u0642\u062a \u06cc\u0627 \u062a\u06a9\u0631\u0627\u0631 \u06a9\u06cc \u062a\u0639\u062f\u0627\u062f \u06a9\u0627 \u062a\u0639\u06cc\u0646 \u0646\u06c1\u06cc\u06ba \u06a9\u0631 \u0633\u06a9\u062a\u0627 \u062c\u0633 \u06a9\u0627 \u0627\u0633\u06d2 \u062d\u0642 \u06c1\u06d2\u06d4<\/p>\n<h3 id=\"heading-test-without-a-real-model\">\u062c\u0633\u0645\u0627\u0646\u06cc \u0645\u0627\u0688\u0644 \u06a9\u06d2 \u0628\u063a\u06cc\u0631 \u0679\u06cc\u0633\u0679 \u06a9\u0631\u06cc\u06ba\u06d4<\/h3>\n<p>\u0627\u067e\u0646\u06d2 \u0679\u06cc\u0633\u0679\u0648\u06ba \u0645\u06cc\u06ba \u0646\u0627\u0646 \u0688\u06cc\u0679\u0631\u0645\u0646\u0633\u0679\u06a9 API \u06a9\u0627\u0644\u0632 \u06a9\u0631\u0646\u06d2 (\u0627\u0648\u0631 \u0679\u0648\u06a9\u0646\u0632 \u06cc\u0627 GPU \u067e\u0627\u0648\u0631 \u062c\u0644\u0627\u0646\u06d2) \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2\u060c \u0622\u067e \u062c\u0639\u0644\u06cc\u060c \u0627\u0633\u06a9\u0631\u067e\u0679\u0688 \u0645\u0627\u0688\u0644\u0632 \u0645\u062a\u0639\u0627\u0631\u0641 \u06a9\u0631\u0648\u0627\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 <code>src\/models\/fake.ts<\/code>. \u067e\u06c1\u0644\u06d2 \u0633\u06d2 \u0637\u06d2 \u0634\u062f\u06c1 \u062c\u0648\u0627\u0628 \u0644\u0648\u0679\u0627\u062a\u0627 \u06c1\u06d2 (\u067e\u06c1\u0644\u06d2 \u0679\u0648\u0644 \u06a9\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a\u060c \u067e\u06be\u0631 \u062d\u062a\u0645\u06cc \u062c\u0648\u0627\u0628)\u06d4<\/p>\n<p>\u0627\u06cc\u06a9 \u062c\u0639\u0644\u06cc \u0645\u0627\u0688\u0644 \u062c\u0648\u0627\u0628\u0627\u062a \u06a9\u06cc \u0627\u06cc\u06a9 \u0633\u06cc\u0631\u06cc\u0632 \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u062a\u06cc\u0627\u0631 \u06c1\u0648\u062a\u0627 \u06c1\u06d2\u06d4 \u0627\u0633\u06a9\u0631\u067e\u0679 \u06a9\u0648 \u062e\u062a\u0645 \u06a9\u0631\u0646\u0627 \u0627\u06cc\u06a9 \u062e\u0631\u0627\u0628\u06cc \u06c1\u06d2\u060c \u0644\u06c1\u0630\u0627 \u0627\u0636\u0627\u0641\u06cc \u063a\u06cc\u0631 \u0645\u062a\u0648\u0642\u0639 \u0645\u0627\u0688\u0644 \u0679\u0631\u0627\u0646\u0632\u06cc\u0634\u0646\u0632 \u062e\u0648\u062f \u0628\u062e\u0648\u062f \u067e\u0627\u0633 \u0646\u06c1\u06cc\u06ba \u06c1\u0648\u06ba \u06af\u06cc\u06d4<\/p>\n<pre><code class=\"language-typescript\">\/\/ src\/models\/fake.ts\nimport type { Model } from '..\/core\/types.ts';\n\nexport function scriptedModel(\n  responses: Array<awaited>>>\n): Model {\n  let index = 0;\n  return {\n    async generate() {\n      const response = responses[index++];\n      if (!response) throw new Error('Scripted model exhausted');\n      return response;\n    }\n  };\n}\n<\/awaited><\/code><\/pre>\n<p>\u06cc\u06c1\u0627\u06ba \u0627\u06cc\u06a9 \u06a9\u0645 \u0633\u06d2 \u06a9\u0645 \u0679\u06cc\u0633\u0679 \u06c1\u06d2: <code>tests\/agent.test.ts<\/code>. \u067e\u06be\u0631 \u0686\u0644\u0627\u0626\u06cc\u06ba: <code>npm test<\/code>:<\/p>\n<pre><code class=\"language-typescript\">import { test } from 'node:test';\nimport assert from 'node:assert\/strict';\nimport { runAgent } from '..\/src\/core\/agent.ts';\nimport { scriptedModel } from '..\/src\/models\/fake.ts';\n\ntest('executes a tool and returns the final answer', async () => {\n  const result = await runAgent({\n    prompt: 'Say hello',\n    tools: [{\n      name: 'hello', description: 'Return a greeting',\n      parameters: { type: 'object' },\n      async execute() { return 'Hello'; }\n    }],\n    model: scriptedModel([\n      { content: '', toolCalls: [{ id: '1', name: 'hello', arguments: {} }] },\n      { content: 'Done' }\n    ])\n  });\n  assert.equal(result.status, 'completed');\n  assert.equal(result.answer, 'Done');\n  assert.deepEqual(result.messages[2], {\n    role: 'tool', callId: '1', content: '\"Hello\"', isError: false\n  });\n});\n<\/code><\/pre>\n<p>\u0633\u0627\u062a\u06be \u0648\u0627\u0644\u0627 \u0688\u06cc\u0645\u0648 \u0628\u06be\u06cc \u0627\u0633\u06cc \u0637\u0631\u0632 \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u0627\u0636\u0627\u0641\u06cc \u0679\u06cc\u0633\u0679\u0648\u06ba \u0645\u06cc\u06ba \u0646\u0627\u0645\u0639\u0644\u0648\u0645 \u0679\u0648\u0644\u0632\u060c \u0642\u062f\u0645 \u06a9\u06cc \u062d\u062f\u0648\u062f\u060c \u0627\u0648\u0631 API \u06a9\u0644\u06cc\u062f\u060c \u0646\u06cc\u0679 \u0648\u0631\u06a9 \u062a\u06a9 \u0631\u0633\u0627\u0626\u06cc\u060c \u06cc\u0627 \u0679\u0648\u06a9\u0646 \u0644\u0627\u06af\u062a \u06a9\u06d2 \u0628\u063a\u06cc\u0631 \u0645\u0646\u0633\u0648\u062e\u06cc \u06a9\u0627 \u0627\u062d\u0627\u0637\u06c1 \u06a9\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0641\u06cc \u0627\u0644\u062d\u0627\u0644 \u0627\u06cc\u06a9 \u0648\u0631\u06a9\u0646\u06af \u0627\u06cc\u062c\u0646\u0679 \u0644\u0648\u067e \u0645\u0648\u062c\u0648\u062f \u06c1\u06d2\u060c \u0644\u06cc\u06a9\u0646 \u06cc\u06c1 \u0627\u0628 \u0628\u06be\u06cc \u0645\u0627\u0688\u0644 \u062c\u0646\u0631\u06cc\u0634\u0646 \u0679\u0648\u0644 \u06a9\u06d2 \u062f\u0644\u0627\u0626\u0644 \u067e\u0631 \u0628\u06be\u0631\u0648\u0633\u06c1 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0631\u062c\u0633\u0679\u0631\u0688 \u0679\u0648\u0644\u0632 \u06a9\u06cc\u0627 \u06a9\u0631 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba \u0627\u0633 \u067e\u0631 \u06a9\u0648\u0626\u06cc \u0628\u0627\u0645\u0639\u0646\u06cc \u067e\u0627\u0628\u0646\u062f\u06cc \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4<\/p>\n<p>\u067e\u06c1\u0644\u0627 \u0644\u0648\u067e \u0645\u0627\u0688\u0644 \u06a9\u0648 \u0646\u0627\u0645 \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06c1 \u0627\u06cc\u06a9 \u0679\u0648\u0644 \u06a9\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u062f\u06cc\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u067e\u06be\u0631 \u0627\u0646 \u062f\u0644\u0627\u0626\u0644 \u06a9\u0648 \u0628\u0631\u0627\u06c1 \u0631\u0627\u0633\u062a \u0646\u0641\u0627\u0630 \u0645\u06cc\u06ba \u0645\u0646\u062a\u0642\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u06cc\u06c1 \u0688\u06cc\u0645\u0648 \u0645\u06cc\u06ba \u06a9\u0627\u0645 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u0644\u06cc\u06a9\u0646 \u0679\u0648\u0644 \u0679\u067e \u0635\u0631\u0641 \u06a9\u06c1\u062a\u0627 \u06c1\u06d2\u06d4 <em>\u062f\u0631\u062e\u0648\u0627\u0633\u062a<\/em> \u0645\u0627\u0688\u0644 \u06a9\u06d2 \u0644\u06cc\u06d2 \u06a9\u0648\u0626\u06cc \u06af\u0627\u0631\u0646\u0679\u06cc \u0646\u06c1\u06cc\u06ba \u06c1\u06d2 \u06a9\u06c1 \u0645\u0627\u0688\u0644 \u062f\u0631\u0633\u062a \u062f\u0644\u0627\u0626\u0644 \u0648\u0627\u067e\u0633 \u06a9\u0631\u06d2 \u06af\u0627\u06d4<\/p>\n<p>\u0627\u0633 \u062d\u0635\u06d2 \u0645\u06cc\u06ba\u060c \u0633\u0627\u062a\u06be\u06cc \u0630\u062e\u06cc\u0631\u06c1 \u0645\u06cc\u06ba \u062f\u0648\u0633\u0631\u0627 \u0633\u0646\u06af \u0645\u06cc\u0644 \u062f\u06cc\u06a9\u06be\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-shell\">git switch --detach 02-tool-dispatch\n<\/code><\/pre>\n<p>\u06cc\u06c1 \u0679\u06cc\u06af \u0634\u0627\u0645\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2: <code>src\/core\/registry.ts<\/code>\u0679\u0648\u0644 \u0631\u062c\u0633\u0679\u0631\u06cc\u0634\u0646 \u0627\u0648\u0631 \u0631\u0646 \u0679\u0627\u0626\u0645 \u062f\u0644\u06cc\u0644 \u06a9\u06cc \u062a\u0648\u062b\u06cc\u0642 \u06a9\u0648 \u06c1\u06cc\u0646\u0688\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u06cc\u06c1 \u0646\u0627\u06a9\u0627\u0645\u06cc \u06a9\u06d2 \u0631\u0648\u06cc\u06d2 \u06a9\u0648 \u0628\u06be\u06cc \u0628\u062f\u0644 \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4 <code>src\/core\/agent.ts<\/code>.<\/p>\n<h3 id=\"heading-a-registry-with-explicit-contracts\">\u0648\u0627\u0636\u062d \u0645\u0639\u0627\u06c1\u062f\u06d2 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0631\u062c\u0633\u0679\u0631\u06cc<\/h3>\n<p>\u06a9\u06c1 <code>ToolRegistry<\/code> \u0627\u0628\u062a\u062f\u0627\u0626\u06cc \u0644\u0648\u067e \u06a9\u06d2 \u0644\u06cc\u06d2 \u0639\u0627\u0645 \u06a9\u0648 \u0628\u062f\u0644 \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4 <code>Map<\/code>. \u063a\u0644\u0637 \u06cc\u0627 \u0688\u067e\u0644\u06cc\u06a9\u06cc\u0679 \u0679\u0648\u0644 \u06a9\u06d2 \u0646\u0627\u0645\u0648\u06ba \u06a9\u0648 \u0645\u0633\u062a\u0631\u062f \u06a9\u0631\u06cc\u06ba \u0627\u0648\u0631 \u0635\u0631\u0641 \u0645\u0627\u0688\u0644 \u06a9\u06d2 \u0644\u06cc\u06d2 \u062f\u0631\u06a9\u0627\u0631 \u062a\u0639\u0631\u06cc\u0641\u06cc\u06ba \u0633\u0627\u0645\u0646\u06d2 \u0631\u06a9\u06be\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-typescript\">import type { Tool, ToolDefinition } from '.\/types.ts';\n\nexport class ToolRegistry {\n  private readonly tools = new Map<string tool=\"\">();\n  constructor(tools: readonly Tool[]) {\n    for (const tool of tools) {\n      if (!\/^[a-zA-Z][a-zA-Z0-9_-]*$\/.test(tool.name)) throw new Error(`Invalid tool name: ${tool.name}`);\n      if (this.tools.has(tool.name)) throw new Error(`Duplicate tool name: ${tool.name}`);\n      this.tools.set(tool.name, tool);\n    }\n  }\n  definitions(): ToolDefinition[] {\n    return [...this.tools.values()].map(({ name, description, parameters }) => ({ name, description, parameters }));\n  }\n  get(name: string): Tool | undefined { return this.tools.get(name); }\n}\n<\/string><\/code><\/pre>\n<p>\u0627\u0633\u06d2 \u0628\u0646\u0627\u0626\u06cc\u06ba <code>const registry = new ToolRegistry(tools)<\/code> \u0627\u0633 \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 \u0645\u0627\u0688\u0644 \u0648\u0627\u0642\u0641\u06cc\u062a \u06a9\u06cc \u062a\u0639\u0631\u06cc\u0641 \u062d\u0627\u0635\u0644 \u06a9\u0631\u06cc\u06ba: <code>registry.definitions()<\/code>. \u062c\u0628 \u062c\u0648\u0627\u0628 \u0679\u0648\u0644 \u0633\u06d2 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u062a\u0648 \u06cc\u06c1 \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0631\u062f\u06c1 \u062f\u0644\u0627\u0626\u0644 \u06a9\u06cc \u062a\u0648\u062b\u06cc\u0642 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 <strong>\u067e\u06c1\u0644\u06d2<\/strong> \u06a9\u0627\u0644 \u06a9\u0631\u0646\u0627 <code>execute<\/code>:<\/p>\n<pre><code class=\"language-typescript\">const tool = registry.get(call.name);\nif (!tool) {\n  messages.push({\n    role: 'tool', callId: call.id,\n    content: `Unknown tool: ${call.name}`, isError: true\n  });\n  continue;\n}\n\nconst validationErrors = validate(call.arguments, tool.parameters);\nif (validationErrors.length) {\n  messages.push({\n    role: 'tool', callId: call.id,\n    content: `Invalid arguments: ${validationErrors.join('; ')}`,\n    isError: true\n  });\n  continue;\n}\n<\/code><\/pre>\n<p>\u06cc\u06c1 \u0627\u06cc\u06a9 \u0627\u06c1\u0645 \u062d\u062f \u06c1\u06d2\u06d4 <code>arguments: unknown<\/code> \u06cc\u06c1 \u0627\u0633 \u0648\u0642\u062a \u062a\u06a9 \u0646\u0627\u0642\u0627\u0628\u0644 \u0627\u0639\u062a\u0645\u0627\u062f \u0631\u06c1\u06d2 \u06af\u0627 \u062c\u0628 \u062a\u06a9 \u06c1\u0627\u0631\u0646\u0633 \u0627\u0633 \u06a9\u06cc \u062a\u0635\u062f\u06cc\u0642 \u0646\u06c1\u06cc\u06ba \u06a9\u0631 \u0644\u06cc\u062a\u0627\u06d4 \u0627\u06af\u0631 \u062a\u0648\u062b\u06cc\u0642 \u0646\u0627\u06a9\u0627\u0645 \u06c1\u0648\u062c\u0627\u062a\u06cc \u06c1\u06d2\u060c \u062a\u0648 \u0679\u0648\u0644 \u0646\u06c1\u06cc\u06ba \u0686\u0644\u06d2 \u06af\u0627\u06d4 \u0627\u0633 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2\u060c \u0645\u0627\u0688\u0644 \u06a9\u0648 \u0627\u0635\u0644 \u06a9\u0627\u0644 ID \u0633\u06d2 \u0645\u062a\u0639\u0644\u0642 \u0627\u06cc\u06a9 \u062e\u0631\u0627\u0628\u06cc \u06a9\u0627 \u0646\u062a\u06cc\u062c\u06c1 \u0645\u0648\u0635\u0648\u0644 \u06c1\u0648\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0633\u0628\u0642 \u06a9\u06d2 <code>validate<\/code> \u0641\u0646\u06a9\u0634\u0646\u0632 JSON \u0627\u0633\u06a9\u06cc\u0645\u0627 \u06a9\u06d2 \u062c\u0627\u0646 \u0628\u0648\u062c\u06be \u06a9\u0631 \u0686\u06be\u0648\u0679\u06d2 \u0630\u06cc\u0644\u06cc \u0633\u06cc\u0679 \u06a9\u06cc \u062d\u0645\u0627\u06cc\u062a \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba: \u0642\u062f\u06cc\u0645 \u0627\u0648\u0631 \u06a9\u0646\u0679\u06cc\u0646\u0631\u0632\u06d4 <code>type<\/code> \u0686\u06cc\u06a9\u060c \u0631\u06cc\u0648\u0631\u0633 <code>properties<\/code>\u060c <code>required<\/code> \u0628\u06cc\u0679\u0631\u06cc\u060c <code>additionalProperties: false<\/code>\u0627\u0646\u062a\u0638\u0627\u0645 <code>items<\/code>\u0627\u0648\u0631 <code>enum<\/code>. \u06cc\u06c1 \u062f\u0631\u062c \u0630\u06cc\u0644 \u0631\u0627\u0633\u062a\u0648\u06ba \u06a9\u06cc \u0627\u0637\u0644\u0627\u0639 \u062f\u06cc\u062a\u0627 \u06c1\u06d2: <code>$.flags[0]<\/code> \u0627\u0633 \u0633\u06d2 \u0622\u067e \u06a9\u0648 \u063a\u0644\u0637 \u0627\u0646 \u067e\u0679 \u06a9\u06cc \u0634\u0646\u0627\u062e\u062a \u0645\u06cc\u06ba \u0645\u062f\u062f \u0645\u0644\u06d2 \u06af\u06cc\u06d4 \u06a9\u06c1 <strong>~ \u0646\u06c1\u06cc\u06ba<\/strong> \u06cc\u06c1 \u0627\u06cc\u06a9 \u0645\u06a9\u0645\u0644 JSON \u0627\u0633\u06a9\u06cc\u0645\u0627 \u06a9\u0627 \u0646\u0641\u0627\u0630 \u06c1\u06d2 \u0627\u0648\u0631 \u0631\u062c\u0633\u0679\u0631\u06cc\u0634\u0646 \u067e\u0631 \u0679\u0648\u0644 \u0627\u0633\u06a9\u06cc\u0645\u0627 \u06a9\u06cc \u062a\u0648\u062b\u06cc\u0642 \u0646\u06c1\u06cc\u06ba \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0627\u0648\u067e\u0631 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u06cc\u06d2 \u06af\u0626\u06d2 \u062a\u0648\u062b\u06cc\u0642 \u06a9\u0627\u0631 \u06c1\u06cc\u06ba: \u06cc\u06c1 \u067e\u06c1\u0644\u06d2 \u0627\u0639\u0644\u0627\u0646 \u06a9\u0631\u062f\u06c1 \u0642\u0633\u0645 \u06a9\u06cc \u062c\u0627\u0646\u0686 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u067e\u06be\u0631 \u0628\u0627\u0631 \u0628\u0627\u0631 \u0622\u0628\u062c\u06cc\u06a9\u0679 \u06a9\u06cc \u062e\u0635\u0648\u0635\u06cc\u0627\u062a \u0627\u0648\u0631 \u0635\u0641\u0648\u06ba \u06a9\u06cc \u0627\u0634\u06cc\u0627\u0621 \u06a9\u0648 \u0686\u06cc\u06a9 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-typescript\">export function validate(value: unknown, schema: Record<string unknown=\"\">, path=\"$\"): string[] {\n  const errors: string[] = [];\n  const type = schema.type;\n  if (typeof type !== 'string') return [`${path}: schema must declare a type`];\n  const matches = type === 'object' ? value !== null && typeof value === 'object' && !Array.isArray(value)\n    : type === 'array' ? Array.isArray(value)\n    : type === 'integer' ? typeof value === 'number' && Number.isInteger(value)\n    : type === 'number' ? typeof value === 'number' && Number.isFinite(value)\n    : type === 'null' ? value === null\n    : type === 'string' || type === 'boolean' ? typeof value === type : false;\n  if (!matches) return [`${path}: expected ${type}`];\n  if (Array.isArray(schema.enum) && !schema.enum.some(item => Object.is(item, value))) {\n    errors.push(`${path}: not an allowed value`);\n  }\n  if (type === 'object') {\n    const obj = value as Record<string unknown=\"\">;\n    const properties = (schema.properties ?? {}) as Record<string record=\"\" unknown=\"\">>;\n    for (const key of (schema.required ?? []) as string[]) {\n      if (!Object.hasOwn(obj, key)) errors.push(`${path}.${key}: required`);\n    }\n    for (const [key, item] of Object.entries(obj)) {\n      if (Object.hasOwn(properties, key)) errors.push(...validate(item, properties[key]!, `${path}.${key}`));\n      else if (schema.additionalProperties === false) errors.push(`${path}.${key}: unexpected property`);\n    }\n  }\n  if (type === 'array' && schema.items && typeof schema.items === 'object') {\n    (value as unknown[]).forEach((item, index) => {\n      errors.push(...validate(\n        item, schema.items as Record<string unknown=\"\">, `${path}[${index}]`\n      ));\n    });\n  }\n  return errors;\n}\n<\/string><\/string><\/string><\/string><\/code><\/pre>\n<h3 id=\"heading-not-every-error-means-the-same-thing\">\u062a\u0645\u0627\u0645 \u063a\u0644\u0637\u06cc\u0648\u06ba \u06a9\u0627 \u0645\u0637\u0644\u0628 \u0627\u06cc\u06a9 \u06c1\u06cc \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4<\/h3>\n<p>\u0633\u0646\u06af \u0645\u06cc\u0644 2 \u0627\u06c1\u0645 \u0641\u0631\u0642 \u0628\u06be\u06cc \u067e\u06cc\u0634 \u06a9\u0631\u062a\u0627 \u06c1\u06d2: <strong>\u0622\u0644\u06d2 \u06a9\u06cc \u0646\u0627\u06a9\u0627\u0645\u06cc<\/strong> \u0627\u0648\u0631 <strong>\u0645\u0627\u0688\u0644 \u06a9\u06cc \u0646\u0627\u06a9\u0627\u0645\u06cc<\/strong>.<\/p>\n<p>\u0646\u0627\u0645\u0639\u0644\u0648\u0645 \u0679\u0648\u0644\u0632\u060c \u063a\u0644\u0637 \u062f\u0644\u0627\u0626\u0644\u060c \u06cc\u0627 \u0679\u0648\u0644\u0632 \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u0627\u0679\u06be\u0627\u0626\u06d2 \u06af\u0626\u06d2 \u0627\u0633\u062a\u062b\u0646\u06cc\u0670 \u06c1\u06cc\u06ba\u06d4 <code>role: 'tool'<\/code> \u0627\u06cc\u06a9 \u067e\u06cc\u063a\u0627\u0645 \u0628\u06be\u06cc\u062c\u06cc\u06ba <code>isError: true<\/code>. \u0645\u0627\u0688\u0644 \u0646\u062a\u0627\u0626\u062c \u06a9\u06cc \u062c\u0627\u0646\u0686 \u06a9\u0631 \u0633\u06a9\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0627\u06af\u0644\u06cc \u0628\u0627\u0631\u06cc \u06a9\u0686\u06be \u0645\u062e\u062a\u0644\u0641 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u06a9\u0648\u0634\u0634 \u06a9\u0631 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u06d4 \u0627\u0633 \u06a9\u06d2 \u0628\u0631\u0639\u06a9\u0633\u060c \u0627\u06af\u0631 <code>model.generate()<\/code> \u062c\u0628 \u062e\u0648\u062f \u06c1\u06cc \u067e\u06be\u06cc\u0646\u06a9 \u062f\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u060c \u062a\u0648 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u0627\u0633 \u0637\u0631\u062d \u062e\u062a\u0645 \u06c1\u0648\u062a\u0627 \u06c1\u06d2: <code>status: 'model_error'<\/code> \u0627\u0648\u0631 \u063a\u0644\u0637\u06cc \u06a9\u06d2 \u067e\u06cc\u063a\u0627\u0645 \u06a9\u0648 \u0644\u0627\u06af \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u06cc\u06c1 \u0635\u0631\u0641 \u0633\u0648\u062c\u0646 \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4 \u06af\u0645\u0634\u062f\u06c1 \u0641\u0627\u0626\u0644\u0648\u06ba \u06a9\u0648 \u0628\u0627\u0632\u06cc\u0627\u0641\u062a \u06a9\u06cc\u0627 \u062c\u0627 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u060c \u0644\u06cc\u06a9\u0646 \u0645\u0627\u0688\u0644 \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0646\u0646\u062f\u06c1 \u06a9\u06cc \u0639\u062f\u0645 \u062f\u0633\u062a\u06cc\u0627\u0628\u06cc \u06a9\u0627 \u0645\u0637\u0644\u0628 \u06c1\u06d2 \u06a9\u06c1 \u0628\u0627\u0632\u06cc\u0627\u0641\u062a \u06a9\u06cc \u0631\u06c1\u0646\u0645\u0627\u0626\u06cc \u06a9\u06d2 \u0644\u06cc\u06d2 \u06a9\u0648\u0626\u06cc \u0645\u0627\u0688\u0644 \u062c\u0648\u0627\u0628 \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4 \u06c1\u0627\u0631\u0646\u0633 \u06a9\u0648 \u06cc\u06c1 \u0628\u06c1\u0627\u0646\u06c1 \u0646\u06c1\u06cc\u06ba \u06a9\u0631\u0646\u0627 \u0686\u0627\u06c1\u0626\u06d2 \u06a9\u06c1 \u06cc\u06c1 \u0648\u06c1\u06cc \u0635\u0648\u0631\u062a\u062d\u0627\u0644 \u06c1\u06d2\u06d4<\/p>\n<p>\u0644\u0648\u067e \u0645\u06cc\u06ba \u0645\u0648\u062c\u0648\u062f <code>model.generate()<\/code> \u06c1\u0691\u067e\u0646\u06d2 \u0627\u0648\u0631 \u062f\u0648\u0628\u0627\u0631\u06c1 \u067e\u06be\u06cc\u0646\u06a9\u0646\u06d2 \u0648\u0627\u0644\u06d2 \u0628\u0644\u0627\u06a9\u0633 \u06a9\u0648 \u0633\u0627\u062e\u062a\u06cc \u0646\u062a\u0627\u0626\u062c \u0645\u06cc\u06ba \u062a\u0628\u062f\u06cc\u0644 \u0627\u0648\u0631 \u0634\u0627\u0645\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 <code>'model_error'<\/code> \u0627\u0648\u0631 \u0627\u062e\u062a\u06cc\u0627\u0631\u06cc <code>error?: string<\/code> \u0645\u06cc\u062f\u0627\u0646 <code>AgentResult<\/code>:<\/p>\n<pre><code class=\"language-typescript\">if (signal.aborted) return { status: 'aborted', messages, steps: step };\nreturn {\n  status: 'model_error', messages, steps: step,\n  error: error instanceof Error ? error.message : String(error)\n};\n<\/code><\/pre>\n<p>\u0679\u0648\u0644 \u0627\u06cc\u06af\u0632\u06cc\u06a9\u06cc\u0648\u0634\u0646 \u06a9\u06cc\u0686 \u0628\u0644\u0627\u06a9 \u0627\u0628 \u0628\u06be\u06cc \u0627\u06cc\u0631\u0631 \u0645\u06cc\u0633\u062c \u06a9\u0648 \u0644\u0627\u06af \u06a9\u0631\u06d2 \u06af\u0627 \u0627\u0648\u0631 \u0644\u0648\u067e \u06a9\u0648 \u062c\u0627\u0631\u06cc \u0631\u06a9\u06be\u06d2 \u06af\u0627\u06d4<\/p>\n<p>\u0688\u06cc\u0679\u0631\u0645\u0646\u0633\u0679\u06a9 \u0679\u06cc\u0633\u0679\u0646\u06af \u0627\u0633 \u0641\u0631\u0642 \u06a9\u0648 \u0679\u06be\u0648\u0633 \u0628\u0646\u0627\u062a\u06cc \u06c1\u06d2\u06d4 \u0645\u06cc\u06ba <code>tests\/agent.test.ts<\/code>\u063a\u0644\u0637 <code>echo<\/code> \u062f\u0639\u0648\u06cc\u0670 \u0645\u0633\u062a\u0631\u062f \u06a9\u0631 \u062f\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4 <strong>\u0679\u0648\u0644 \u06a9\u0648 \u06a9\u0627\u0644 \u06a9\u06cc\u06d2 \u0628\u063a\u06cc\u0631<\/strong>\u0627\u06cc\u06a9 \u0627\u0679\u06be\u0627\u0626\u06d2 \u06af\u0626\u06d2 \u0679\u0648\u0644 \u06a9\u06cc \u0631\u0639\u0627\u06cc\u062a \u0627\u0633\u06a9\u0631\u067e\u0679 \u0645\u0627\u0688\u0644 \u06a9\u0648 \u062d\u062a\u0645\u06cc \u062c\u0648\u0627\u0628 \u0648\u0627\u067e\u0633 \u06a9\u0631\u0646\u06d2 \u06a9\u0627 \u0633\u0628\u0628 \u0628\u0646 \u0633\u06a9\u062a\u06cc \u06c1\u06d2\u06d4 <code>tests\/registry.test.ts<\/code> \u06af\u06be\u0631\u06cc\u0644\u0648 \u062f\u0644\u0627\u0626\u0644 \u06a9\u06cc \u062a\u0648\u062b\u06cc\u0642 \u06a9\u0631\u06cc\u06ba \u0627\u0648\u0631 \u063a\u06cc\u0631 \u0645\u062a\u0648\u0642\u0639 \u062e\u0635\u0648\u0635\u06cc\u0627\u062a \u06a9\u06cc \u062c\u0627\u0646\u0686 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<p>\u0627\u0628 \u062a\u06a9\u060c \u0627\u06cc\u06a9 \u0627\u06cc\u062c\u0646\u0679 \u0627\u06cc\u06a9 \u0679\u0648\u0644 \u06a9\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u0631 \u0633\u06a9\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u06c1\u0627\u0631\u0646\u0633 \u0627\u0633 \u062f\u0644\u06cc\u0644 \u06a9\u06cc \u062a\u0648\u062b\u06cc\u0642 \u06a9\u0631\u06d2 \u06af\u0627\u06d4 \u0644\u06cc\u06a9\u0646 \u062a\u0648\u062b\u06cc\u0642 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u0645\u06cc\u06ba \u06c1\u06d2\u06d4 <em>\u062f\u0631\u0633\u062a \u0634\u06a9\u0644<\/em>. \u062f\u0631\u0633\u062a \u067e\u0691\u06be\u0646\u06d2 \u06a9\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a <code>..\/..\/secrets.txt<\/code> \u06cc\u06c1 \u0627\u0628 \u0628\u06be\u06cc \u0627\u06cc\u06a9 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06c1\u06d2 \u062c\u0633 \u0633\u06d2 \u06c1\u0645\u06cc\u06ba \u0627\u0646\u06a9\u0627\u0631 \u06a9\u0631\u0646\u0627 \u0686\u0627\u06c1\u06cc\u06d2\u06d4<\/p>\n<p>\u0633\u0627\u062a\u06be\u06cc \u0630\u062e\u06cc\u0631\u06c1 \u0645\u06cc\u06ba \u0633\u0646\u06af \u0645\u06cc\u0644 3 \u062f\u06cc\u06a9\u06be\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-shell\">git switch --detach 03-workspace-tools\n<\/code><\/pre>\n<p>\u06cc\u06c1 \u0633\u0646\u06af \u0645\u06cc\u0644 \u0648\u0631\u06a9 \u0627\u0633\u067e\u06cc\u0633 \u0641\u0627\u0626\u0644 \u0679\u0648\u0644\u0632 \u0627\u0648\u0631 \u0645\u062d\u062f\u0648\u062f \u06a9\u0645\u0627\u0646\u0688 \u0679\u0648\u0644\u0632 \u06a9\u0627 \u0627\u0636\u0627\u0641\u06c1 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u0646\u06c1 \u06c1\u06cc \u06a9\u0633\u06cc \u0645\u062e\u0635\u0648\u0635 \u0645\u0627\u0688\u0644 \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0646\u0646\u062f\u06c1 \u067e\u0631 \u0645\u0646\u062d\u0635\u0631 \u06c1\u06d2\u06d4<\/p>\n<h3 id=\"heading-confine-file-operations-to-a-workspace\">\u0641\u0627\u0626\u0644 \u06a9\u06cc \u06a9\u0627\u0631\u0631\u0648\u0627\u0626\u06cc\u0648\u06ba \u06a9\u0648 \u0627\u067e\u0646\u06d2 \u0648\u0631\u06a9 \u0627\u0633\u067e\u06cc\u0633 \u062a\u06a9 \u0645\u062d\u062f\u0648\u062f \u0631\u06a9\u06be\u06cc\u06ba<\/h3>\n<p>\u06a9\u0648\u0688\u0646\u06af \u0627\u06cc\u062c\u0646\u0679\u0648\u06ba \u06a9\u0648 \u0641\u0627\u0626\u0644\u0648\u06ba \u06a9\u0648 \u067e\u0691\u06be\u0646\u0627 \u0627\u0648\u0631 \u0627\u0646 \u0645\u06cc\u06ba \u062a\u0631\u0645\u06cc\u0645 \u06a9\u0631\u0646\u06cc \u0686\u0627\u06c1\u06cc\u06d2\u060c \u0644\u06cc\u06a9\u0646 \u0627\u0646\u06c1\u06cc\u06ba \u062e\u0648\u062f \u0628\u062e\u0648\u062f \u067e\u0648\u0631\u06d2 \u0641\u0627\u0626\u0644 \u0633\u0633\u0679\u0645 \u062a\u06a9 \u0631\u0633\u0627\u0626\u06cc \u0646\u06c1\u06cc\u06ba \u062f\u06cc \u062c\u0627\u0646\u06cc \u0686\u0627\u06c1\u06cc\u06d2\u06d4 \u06a9\u06c1 <code>Workspace<\/code> \u062c\u0628 \u06a9\u0648\u0626\u06cc \u06a9\u0644\u0627\u0633 \u0628\u0646\u062a\u06cc \u06c1\u06d2\u060c \u062a\u0648 \u06cc\u06c1 \u0627\u0633 \u06a9\u06cc \u06a9\u06cc\u0646\u0646\u06cc\u06a9\u0644 \u062c\u0691 \u06a9\u06cc \u062a\u0635\u062f\u06cc\u0642 \u06a9\u0631\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-typescript\">const workspace = await Workspace.open('\/path\/to\/project');\nconst tools = workspaceTools(workspace);\n<\/code><\/pre>\n<p>\u0646\u062a\u06cc\u062c\u06c1 <code>read_file<\/code> \u0627\u0648\u0631 <code>write_file<\/code> \u0679\u0648\u0644 \u0627\u0633 \u062c\u0691 \u0633\u06d2 \u0645\u062a\u0639\u0644\u0642 \u0631\u0627\u0633\u062a\u0648\u06ba \u06a9\u0648 \u0642\u0628\u0648\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u0641\u0627\u0626\u0644 \u06a9\u06be\u0648\u0644\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2\u060c <code>Workspace<\/code> \u0645\u0637\u0644\u0642 \u0631\u0627\u0633\u062a\u06d2\u060c \u0631\u0627\u0633\u062a\u06d2 \u062c\u0648 \u062c\u0691 \u0633\u06d2 \u0628\u0686 \u062c\u0627\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u0627\u0648\u0631 \u0645\u0648\u062c\u0648\u062f\u06c1 \u0631\u0627\u0633\u062a\u06d2 \u06a9\u06d2 \u0627\u062c\u0632\u0627\u0621 \u0633\u06d2 \u0639\u0644\u0627\u0645\u062a\u06cc \u0631\u0648\u0627\u0628\u0637 \u06a9\u0648 \u0645\u0633\u062a\u0631\u062f \u06a9\u0631\u06cc\u06ba\u06d4 \u0644\u06a9\u06be\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u067e\u06cc\u0631\u0646\u0679 \u0688\u0627\u0626\u0631\u06a9\u0679\u0631\u06cc \u06a9\u0627 \u06c1\u0648\u0646\u0627 \u0636\u0631\u0648\u0631\u06cc \u06c1\u06d2\u06d4 \u06cc\u06c1 \u0679\u0648\u0644 \u0628\u06d2 \u062a\u0631\u062a\u06cc\u0628 \u0688\u0627\u0626\u0631\u06cc\u06a9\u0679\u0631\u06cc \u062f\u0631\u062e\u062a \u0646\u06c1\u06cc\u06ba \u0628\u0646\u0627\u062a\u0627\u06d4<\/p>\n<p>\u06cc\u06c1 \u062f\u0648\u0646\u0648\u06ba \u0637\u0631\u06cc\u0642\u06d2 \u0627\u0646\u062f\u0631\u0648\u0646\u06cc \u06c1\u06cc\u06ba\u06d4 <code>Workspace<\/code> \u0631\u0627\u0633\u062a\u06d2 \u06a9\u06cc \u062a\u0635\u062f\u06cc\u0642 \u06a9\u0631\u06cc\u06ba\u06d4 \u0641\u0627\u0626\u0644 \u062f\u0631\u0622\u0645\u062f \u06a9\u0631\u06cc\u06ba\u06d4 <code>isAbsolute<\/code>\u060c <code>relative<\/code>\u0627\u0648\u0631 <code>resolve<\/code> \u0633\u06d2 <code>node:path<\/code>\u0627\u0648\u0631 <code>lstat<\/code> \u0627\u0648\u0631 <code>realpath<\/code> \u0633\u06d2 <code>node:fs\/promises<\/code>. <code>Workspace.open()<\/code> \u0688\u067e\u0627\u0631\u0679\u0645\u0646\u0679 \u0627\u0633\u0679\u0648\u0631 <code>await realpath(root)<\/code> \u067e\u0633\u0646\u062f <code>this.root<\/code>:<\/p>\n<pre><code class=\"language-typescript\">private lexical(path: string): string {\n    if (!path || isAbsolute(path)) throw new Error('Expected a relative workspace path');\n    const full = resolve(this.root, path);\n    const rel = relative(this.root, full);\n    if (!rel || rel === '..' || rel.startsWith(`..${process.platform === 'win32' ? '\\' : '\/'}`) || isAbsolute(rel)) {\n      throw new Error('Path is outside the workspace or refers to its root');\n    }\n    return full;\n  }\n\n  \/** Reject symlinks in every existing component, not just the final file. *\/\n  private async check(path: string, allowMissingFinal: boolean): Promise<string> {\n    const full = this.lexical(path);\n    const rel = relative(this.root, full);\n    const parts = rel.split(\/[\\\/]\/);\n    let current = this.root;\n    for (let i = 0; i < parts.length; i++) {\n      current = resolve(current, parts[i]!);\n      try {\n        const stat = await lstat(current);\n        if (stat.isSymbolicLink()) throw new Error('Symbolic links are not permitted');\n        if (i < parts.length - 1 &#038;&#038; !stat.isDirectory()) throw new Error('Parent is not a directory');\n      } catch (error) {\n        if (allowMissingFinal &#038;&#038; i === parts.length - 1 &#038;&#038; (error as NodeJS.ErrnoException).code === 'ENOENT') break;\n        throw error;\n      }\n    }\n    return full;\n  }\n<\/string><\/code><\/pre>\n<p><code>read<\/code>    \u0641\u0648\u0646 \u06a9\u0627\u0644 <code>this.check(path, false)<\/code> \u0645\u0648\u062c\u0648\u062f\u06c1 \u0641\u0627\u0626\u0644 \u06a9\u0648 \u06a9\u06be\u0648\u0644\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2\u06d4 <code>write<\/code> \u0641\u0648\u0646 \u06a9\u0627\u0644 <code>this.check(path, true)<\/code>\u0635\u0631\u0641 \u062d\u062a\u0645\u06cc \u0641\u0627\u0626\u0644\u0648\u06ba \u06a9\u0648 \u063a\u0627\u0626\u0628 \u06c1\u0648\u0646\u06d2 \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4 \u0644\u0627\u067e\u062a\u06c1 \u067e\u06cc\u0631\u0646\u0679 \u0688\u0627\u0626\u0631\u06cc\u06a9\u0679\u0631\u06cc\u0632 \u06cc\u0627 \u0639\u0644\u0627\u0645\u062a\u06cc \u0644\u0646\u06a9\u0633 \u0627\u0628\u06be\u06cc \u0628\u06be\u06cc \u062c\u0627\u0646\u0686 \u0645\u06cc\u06ba \u0646\u0627\u06a9\u0627\u0645 \u0631\u06c1\u06cc\u06ba \u06af\u06d2\u06d4<\/p>\n<p>\u062d\u062f\u0648\u062f \u06a9\u0648 \u0646\u0627\u0641\u0630 \u06a9\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2: <strong>\u0679\u0648\u0644 \u067e\u0631 \u0639\u0645\u0644 \u062f\u0631\u0622\u0645\u062f<\/strong>\u06c1\u0645 \u0645\u0627\u0688\u0644 \u06a9\u0648 \u06a9\u0627\u0645 \u06a9\u0631\u0646\u06d2 \u06a9\u0648 \u0646\u06c1\u06cc\u06ba \u06a9\u06c1\u06c1 \u0631\u06c1\u06d2 \u06c1\u06cc\u06ba\u06d4 \u0645\u0627\u0688\u0644 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u0631 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u06d4 <code>..\/secret.txt<\/code>\u062a\u0627\u06c1\u0645\u060c \u06cc\u06c1 \u0648\u0631\u06a9 \u0627\u0633\u067e\u06cc\u0633 \u0645\u06cc\u06ba \u06a9\u06be\u0644\u0646\u06d2 \u0633\u06d2 \u0627\u0646\u06a9\u0627\u0631 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u0627\u0633 \u06a9\u06d2 \u0628\u0639\u062f \u06c1\u0627\u0631\u0646\u0633 \u063a\u0644\u0637\u06cc \u06a9\u0648 \u0627\u06cc\u06a9 \u0642\u0627\u0628\u0644 \u0628\u0627\u0632\u06cc\u0627\u0641\u062a \u0679\u0648\u0644 \u06a9\u06d2 \u0646\u062a\u06cc\u062c\u06d2 \u06a9\u06d2 \u0637\u0648\u0631 \u067e\u0631 \u0631\u067e\u0648\u0631\u0679 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u062c\u06cc\u0633\u0627 \u06a9\u06c1 \u0627\u0633 \u0646\u06d2 Milestone 2 \u0645\u06cc\u06ba \u063a\u0644\u0637 \u062f\u0644\u06cc\u0644 \u06a9\u06d2 \u0644\u06cc\u06d2 \u06a9\u06cc\u0627 \u062a\u06be\u0627\u06d4<\/p>\n<p>\u0645\u0632\u06cc\u062f \u062a\u0635\u062f\u06cc\u0642 \u06a9\u06d2 \u0644\u06cc\u06d2\u060c \u0622\u067e \u06a9\u06d2 \u0646\u0641\u0627\u0630 \u0645\u06cc\u06ba\u060c \u0627\u0633 \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 \u0641\u0627\u0626\u0644 \u06a9\u0648 \u06a9\u06be\u0648\u0644\u06cc\u06ba: <code>O_NOFOLLOW<\/code> \u0627\u06af\u0631 \u062a\u0639\u0627\u0648\u0646 \u06cc\u0627\u0641\u062a\u06c1 \u06c1\u06d2 \u062a\u0648\u060c \u0622\u062e\u0631\u06cc \u0631\u0627\u0633\u062a\u06d2 \u06a9\u06d2 \u0627\u062c\u0632\u0627\u0621 \u0645\u06cc\u06ba \u0639\u0644\u0627\u0645\u062a\u06cc \u0644\u0646\u06a9\u0633 \u06a9\u06cc \u067e\u06cc\u0631\u0648\u06cc \u0633\u06d2 \u06af\u0631\u06cc\u0632 \u06a9\u0631\u06cc\u06ba\u06d4 \u0627\u0633 \u0633\u06d2 \u062a\u0645\u0627\u0645 \u062a\u0646\u0627\u0632\u0639\u0627\u062a \u062e\u062a\u0645 \u0646\u06c1\u06cc\u06ba \u06c1\u0648\u062a\u06d2\u06d4 \u0688\u0627\u0626\u0631\u06a9\u0679\u0631\u06cc \u06a9\u06d2 \u0627\u062c\u0632\u0627\u0621 \u062a\u0648\u062b\u06cc\u0642 \u0627\u0648\u0631 \u06a9\u06be\u0648\u0644\u0646\u06d2 \u06a9\u06d2 \u062f\u0631\u0645\u06cc\u0627\u0646 \u062a\u0628\u062f\u06cc\u0644 \u06c1\u0648 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u06cc\u06c1 \u0627\u06cc\u06a9 \u0645\u0641\u06cc\u062f \u062a\u0631\u0628\u06cc\u062a\u06cc \u062d\u062f \u06c1\u06d2\u06d4 <strong>~ \u0646\u06c1\u06cc\u06ba<\/strong> OS \u0633\u0637\u062d \u06a9\u0627 \u0633\u06cc\u0646\u0688 \u0628\u0627\u06a9\u0633\u06d4<\/p>\n<h3 id=\"heading-let-the-model-choose-commands-not-invent-them\">\u0645\u0627\u0688\u0644 \u06a9\u0648 \u062e\u0648\u062f \u06a9\u0645\u0627\u0646\u0688\u0632 \u06a9\u0648 \u0645\u0646\u062a\u062e\u0628 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2 \u06a9\u0645\u0627\u0646\u0688\u0632 \u06a9\u0627 \u0627\u0646\u062a\u062e\u0627\u0628 \u06a9\u0631\u0646\u06d2 \u06a9\u0648 \u06a9\u06c1\u06cc\u06ba\u06d4<\/h3>\n<p>\u06a9\u0645\u0627\u0646\u0688 \u067e\u0631 \u0639\u0645\u0644 \u062f\u0631\u0622\u0645\u062f \u0628\u06c1\u062a \u0632\u06cc\u0627\u062f\u06c1 \u062d\u0633\u0627\u0633 \u06c1\u06d2\u06d4 \u0645\u0627\u0688\u0644 \u0633\u06d2 \u062a\u06cc\u0627\u0631 \u06a9\u0631\u062f\u06c1 \u0634\u06cc\u0644 \u0633\u0679\u0631\u0646\u06af \u06a9\u0648 \u0642\u0628\u0648\u0644 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2 \u0627\u06cc\u06a9 \u0646\u0627\u0645\u0632\u062f \u06a9\u0645\u0627\u0646\u0688 \u067e\u06cc\u0634 \u0633\u06cc\u0679 \u06a9\u0648 \u0631\u062c\u0633\u0679\u0631 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-typescript\">const tool = commandTool(projectRoot, {\n  test: {\n    executable: process.execPath,\n    args: ['--test', 'tests\/example.test.js']\n  }\n});\n<\/code><\/pre>\n<p>\u0645\u0627\u0688\u0644 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u0631 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u06d4 <code>{ \"command\": \"test\" }<\/code>\u062a\u0627\u06c1\u0645\u060c \u0622\u067e \u06a9\u0648\u0626\u06cc \u0627\u0648\u0631 \u0642\u0627\u0628\u0644 \u0639\u0645\u0644\u060c \u0627\u0636\u0627\u0641\u06cc \u062f\u0644\u0627\u0626\u0644\u060c \u06cc\u0627 \u0634\u06cc\u0644 \u0646\u062d\u0648 \u0641\u0631\u0627\u06c1\u0645 \u0646\u06c1\u06cc\u06ba \u06a9\u0631 \u0633\u06a9\u062a\u06d2\u06d4 \u06a9\u0645\u0627\u0646\u0688 \u0679\u0648\u0644 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0688\u0633\u067e\u06cc\u0686 \u06a9\u06cc \u062d\u062f\u0648\u062f \u06cc\u06c1 \u06c1\u06cc\u06ba: <code>execute(value, signal)<\/code> \u0637\u0631\u06cc\u0642\u06c1):<\/p>\n<pre><code class=\"language-typescript\">signal.throwIfAborted();\nconst name = (value as { command: string }).command;\nif (!Object.hasOwn(presets, name)) throw new Error('Command not permitted');\nconst preset = presets[name]!;\nconst timeout = preset.timeoutMs ?? 10_000;\nif (!Number.isSafeInteger(timeout) || timeout < 1) {\n  throw new Error('Invalid timeout');\n}\n\n\/\/ Inside the Promise that collects the command's result:\nconst child = spawn(preset.executable, [...preset.args], {\n  cwd, shell: false, signal, windowsHide: true,\n  stdio: ['ignore', 'pipe', 'pipe']\n});\nconst timer = setTimeout(() => child.kill(), timeout);\n<\/code><\/pre>\n<p>\u06cc\u06c1\u0627\u06ba <code>spawn<\/code> \u0633\u06d2 \u0622\u062a\u0627 \u06c1\u06d2 <code>node:child_process<\/code>\u060c <code>cwd<\/code> \u06cc\u06c1 \u06a9\u0646\u0641\u06cc\u06af\u0631 \u0634\u062f\u06c1 \u067e\u0631\u0648\u062c\u06cc\u06a9\u0679 \u0631\u0648\u0679 \u06c1\u06d2\u06d4 <code>presets<\/code> \u06cc\u06c1 \u0627\u06cc\u06a9 \u0646\u0642\u0634\u06c1 \u06c1\u06d2 \u062c\u0648 \u0627\u0648\u067e\u0631 \u0688\u0648\u06cc\u0644\u067e\u0631 \u0646\u06d2 \u0641\u0631\u0627\u06c1\u0645 \u06a9\u06cc\u0627 \u06c1\u06d2\u06d4 \u0631\u0632\u0644\u0679 \u06c1\u06cc\u0646\u0688\u0644\u0631 stdout \u0627\u0648\u0631 stderr \u06a9\u0648 \u0627\u06a9\u0679\u06be\u0627 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0627\u067e\u0646\u06d2 \u0628\u0686\u0648\u06ba \u06a9\u0648 \u062e\u062a\u0645 \u0627\u0648\u0631 \u0635\u0627\u0641 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u062c\u0628 \u06a9\u06cc\u067e\u0686\u0631 \u06a9\u06cc\u06d2 \u06af\u0626\u06d2 \u062a\u0627\u0631\u0648\u06ba \u0645\u06cc\u06ba \u0633\u06d2 \u0627\u06cc\u06a9 65,536 \u062d\u0631\u0648\u0641 \u0633\u06d2 \u0632\u06cc\u0627\u062f\u06c1 \u06c1\u0648 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4 <code>timer<\/code> \u0627\u06cc\u06a9 \u062e\u0631\u0627\u0628\u06cc \u0648\u0627\u0642\u0639 \u06c1\u0648\u062a\u06cc \u06c1\u06d2 \u06cc\u0627 \u0628\u0627\u06c1\u0631 \u0646\u06a9\u0644 \u062c\u0627\u062a\u06cc \u06c1\u06d2\u06d4 \u0646\u0641\u0627\u0630 \u0628\u0627\u0626\u0679\u0633 \u06a9\u06cc \u0635\u062d\u06cc\u062d \u062a\u0639\u062f\u0627\u062f \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2 JavaScript \u0633\u0679\u0631\u0646\u06af \u06a9\u06cc \u0644\u0645\u0628\u0627\u0626\u06cc \u06a9\u06cc \u067e\u06cc\u0645\u0627\u0626\u0634 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0627\u0633 \u0633\u06d2 \u0627\u0646 \u06a9\u0645\u0627\u0646\u0688\u0632 \u06a9\u06cc \u062a\u0639\u062f\u0627\u062f \u06a9\u0645 \u06c1\u0648 \u062c\u0627\u062a\u06cc \u06c1\u06d2 \u062c\u0646 \u0633\u06d2 \u0645\u0627\u0688\u0644 \u0645\u0646\u062a\u062e\u0628 \u06a9\u0631 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u060c \u0644\u06cc\u06a9\u0646 \u0627\u0633 \u0628\u0627\u062a \u06a9\u06cc \u0636\u0645\u0627\u0646\u062a \u0646\u06c1\u06cc\u06ba \u062f\u06cc\u062a\u0627 \u06a9\u06c1 \u0627\u0633 \u06a9\u06d2 \u0645\u0646\u062a\u062e\u0628 \u06a9\u0631\u062f\u06c1 \u06a9\u0645\u0627\u0646\u0688\u0632 \u0628\u06d2 \u0636\u0631\u0631 \u06c1\u06cc\u06ba\u06d4 \u0679\u06cc\u0633\u0679 \u0627\u0633\u06a9\u0631\u067e\u0679 \u062e\u0648\u062f \u0641\u0627\u0626\u0644\u0648\u06ba \u06a9\u0648 \u067e\u0691\u06be \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u060c \u0646\u06cc\u0679 \u0648\u0631\u06a9 \u062a\u06a9 \u0631\u0633\u0627\u0626\u06cc \u062d\u0627\u0635\u0644 \u06a9\u0631 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u060c \u06cc\u0627 \u0686\u0627\u0626\u0644\u0688 \u067e\u0631\u0648\u0633\u06cc\u0633 \u0634\u0631\u0648\u0639 \u06a9\u0631 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u06d4 \u0648\u0642\u062a \u062e\u062a\u0645 \u06c1\u0648\u0646\u06d2 \u0648\u0627\u0644\u06d2 \u0628\u0686\u06d2 \u06a9\u0648 \u062e\u062a\u0645 \u06a9\u0631\u0646\u06d2 \u0633\u06d2 \u067e\u0648\u0631\u06d2 \u0639\u0645\u0644 \u06a9\u06d2 \u062f\u0631\u062e\u062a \u06a9\u0648 \u0642\u0627\u0628\u0644 \u0627\u0639\u062a\u0645\u0627\u062f \u0637\u0631\u06cc\u0642\u06d2 \u0633\u06d2 \u062e\u062a\u0645 \u0646\u06c1\u06cc\u06ba \u06a9\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4 \u063a\u06cc\u0631 \u0628\u06be\u0631\u0648\u0633\u06c1 \u0645\u0646\u062f \u0630\u062e\u06cc\u0631\u0648\u06ba \u06a9\u0648 \u0686\u0644\u0627\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0639\u0645\u0644 \u06a9\u0648 \u0627\u0644\u06af \u062a\u06be\u0644\u06af \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06c1\u0648\u062a\u06cc \u06c1\u06d2\u060c \u062c\u06cc\u0633\u06d2 \u06a9\u06c1 \u0627\u06cc\u06a9 \u0645\u0646\u0627\u0633\u0628 \u0637\u0631\u06cc\u0642\u06d2 \u0633\u06d2 \u062a\u0634\u06a9\u06cc\u0644 \u0634\u062f\u06c1 \u06a9\u0646\u0679\u06cc\u0646\u0631 \u06cc\u0627 OS \u0633\u06cc\u0646\u0688 \u0628\u0627\u06a9\u0633\u06d4<\/p>\n<p>\u0633\u0646\u06af \u0645\u06cc\u0644 3 \u0679\u06cc\u0633\u0679 \u0639\u0627\u0645 \u067e\u0691\u06be\u0646\u06d2 \u0627\u0648\u0631 \u0644\u06a9\u06be\u0646\u06d2\u060c \u0679\u0631\u0627\u0648\u0631\u0633\u0644 \u06a9\u0648\u0634\u0634\u0648\u06ba\u060c \u0639\u0644\u0627\u0645\u062a\u06cc \u0644\u0646\u06a9\u0633\u060c \u0642\u0627\u0628\u0644 \u0628\u0627\u0632\u06cc\u0627\u0641\u062a \u0631\u0633\u0627\u0626\u06cc \u06a9\u06cc \u0646\u0627\u06a9\u0627\u0645\u06cc\u0648\u06ba\u060c \u0627\u0648\u0631 \u06a9\u0645\u0627\u0646 \u06a9\u06d2 \u0646\u0627\u0645\u0648\u06ba \u06a9\u0627 \u0627\u062d\u0627\u0637\u06c1 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<h2 id=\"heading-4-put-limits-on-execution\">4. \u0639\u0645\u0644 \u062f\u0631\u0622\u0645\u062f \u06a9\u0648 \u0645\u062d\u062f\u0648\u062f \u06a9\u0631\u06cc\u06ba\u06d4<\/h2>\n<p>\u06c1\u0645\u0627\u0631\u06d2 \u0627\u06cc\u062c\u0646\u0679 \u0627\u0628 \u062b\u0627\u0628\u062a \u0634\u062f\u06c1 \u0679\u0648\u0644\u0632 \u06a9\u0648 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u0628\u0634\u0645\u0648\u0644 \u0648\u0631\u06a9 \u0627\u0633\u067e\u06cc\u0633 \u0633\u06d2 \u0622\u06af\u0627\u06c1 \u0641\u0627\u0626\u0644 \u0622\u067e\u0631\u06cc\u0634\u0646\u0632 \u0627\u0648\u0631 \u067e\u06c1\u0644\u06d2 \u0633\u06d2 \u0637\u06d2 \u0634\u062f\u06c1 \u06a9\u0645\u0627\u0646\u0688\u0632\u06d4 \u062a\u0627\u06c1\u0645\u060c \u0636\u0631\u0648\u0631\u06cc \u0646\u06c1\u06cc\u06ba \u06a9\u06c1 \u062f\u0631\u0633\u062a \u06a9\u0627\u0631\u0631\u0648\u0627\u0626\u06cc\u0648\u06ba \u06a9\u0648 \u063a\u06cc\u0631 \u0645\u0639\u06cc\u0646\u06c1 \u0645\u062f\u062a \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u062c\u0627\u0632\u062a \u062f\u06cc \u062c\u0627\u0626\u06d2\u06d4 \u0627\u06cc\u06a9 \u0645\u0627\u0688\u0644 \u0633\u06cc\u0646\u06a9\u0691\u0648\u06ba \u0679\u0648\u0644 \u06a9\u0627\u0644\u0632 \u06a9\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u0631 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u060c \u06cc\u0627 \u0627\u06cc\u062c\u0646\u0679 \u06a9\u06d2 \u0646\u062a\u0627\u0626\u062c \u06a9\u0627 \u0627\u0646\u062a\u0638\u0627\u0631 \u06a9\u0631\u062a\u06d2 \u0648\u0642\u062a \u06a9\u0645\u0627\u0646\u0688 \u0644\u0679\u06a9 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u0627\u0633 \u0633\u0646\u06af \u0645\u06cc\u0644 \u067e\u0631 \u06c1\u0645 <strong>\u0686\u0644\u0627\u0646\u06d2 \u06a9\u06cc \u0630\u0645\u06c1 \u062f\u0627\u0631\u06cc \u06a9\u0648 \u0645\u062d\u062f\u0648\u062f \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/strong> \u0645\u0627\u0688\u0644 \u0633\u06d2 \u0639\u0632\u062a \u0645\u0627\u0646\u06af\u0646\u06d2 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2\u06d4<\/p>\n<p>\u0628\u0631\u0627\u06c1 \u06a9\u0631\u0645 \u062f\u0631\u0633\u062a \u0631\u06cc\u067e\u0648\u0632\u0679\u0631\u06cc \u0648\u0631\u0698\u0646 \u06a9\u06cc \u067e\u06cc\u0631\u0648\u06cc \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-shell\">git switch --detach 04-execution-limits\n<\/code><\/pre>\n<p>\u0627\u06af\u0631 \u0622\u067e \u0646\u06d2 \u0627\u0628\u06be\u06cc \u062a\u06a9 \u0627\u067e\u0646\u06d2 \u067e\u0631\u0648\u062c\u06cc\u06a9\u0679 \u06a9\u0648 \u06a9\u0644\u0648\u0646 \u0646\u06c1\u06cc\u06ba \u06a9\u06cc\u0627 \u06c1\u06d2 \u062a\u0648 \u0627\u0633 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0634\u0631\u0648\u0639 \u06a9\u0631\u06cc\u06ba: <code>git clone https:\/\/github.com\/gkoos\/agent-harness-from-scratch.git<\/code> \u0627\u0648\u0631 <code>cd agent-harness-from-scratch<\/code>.<\/p>\n<h3 id=\"heading-count-turns-and-tool-calls-separately\">\u0627\u0646\u0642\u0644\u0627\u0628\u0627\u062a \u0627\u0648\u0631 \u0679\u0648\u0644 \u06a9\u0627\u0644\u0632 \u06a9\u0627 \u0627\u0644\u06af \u0633\u06d2 \u062d\u0633\u0627\u0628 \u0644\u06af\u0627\u0626\u06cc\u06ba\u06d4<\/h3>\n<p>\u0645\u062a\u0646 <code>maxSteps<\/code> \u062a\u0631\u062a\u06cc\u0628\u0627\u062a \u0645\u0627\u0688\u0644 \u06a9\u06d2 \u062c\u0648\u0627\u0628 \u06a9\u0648 \u0645\u062d\u062f\u0648\u062f \u06a9\u0631\u062a\u06cc \u06c1\u06cc\u06ba\u060c \u0646\u06c1 \u06a9\u06c1 \u0679\u0648\u0644 \u06a9\u0627\u0644\u0632 \u06a9\u06cc \u062a\u0639\u062f\u0627\u062f\u06d4 \u0627\u06a9\u06cc\u0644\u06d2 \u06af\u0631\u062f\u0634 \u06a9\u06cc \u062d\u062f\u0648\u062f \u06a9\u0627\u0645 \u06a9\u06d2 \u0628\u0648\u062c\u06be \u06a9\u0648 \u0645\u062d\u062f\u0648\u062f \u0646\u06c1\u06cc\u06ba \u06a9\u0631\u062a\u06cc \u06c1\u06cc\u06ba\u060c \u06a9\u06cc\u0648\u0646\u06a9\u06c1 \u0627\u06cc\u06a9 \u062c\u0648\u0627\u0628 \u0645\u062a\u0639\u062f\u062f \u0679\u0648\u0644\u0632 \u06a9\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u0631 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u06c1\u0645 \u062a\u0648\u0633\u06cc\u0639 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba <code>runAgent<\/code> \u062f\u0648 \u0627\u0636\u0627\u0641\u06cc \u0627\u062e\u062a\u06cc\u0627\u0631\u0627\u062a \u06c1\u06cc\u06ba:<\/p>\n<pre><code class=\"language-typescript\">const result = await runAgent({\n  model,\n  tools,\n  prompt: 'Check the project',\n  maxSteps: 10,\n  maxToolCalls: 30,\n  timeoutMs: 15_000\n});\n<\/code><\/pre>\n<p>\u062a\u0645\u0627\u0645 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u0631\u062f\u06c1 \u06a9\u0627\u0644\u06cc\u06ba\u060c \u0628\u0634\u0645\u0648\u0644 \u0646\u0627\u0645\u0639\u0644\u0648\u0645 \u0679\u0648\u0644\u0632 \u0648\u0627\u0644\u06cc \u06a9\u0627\u0644\u0632 \u0627\u0648\u0631 \u063a\u0644\u0637 \u062f\u0644\u0627\u0626\u0644\u060c \u0679\u0648\u0644 \u06a9\u0627\u0644 \u06a9\u0627 \u0628\u062c\u0679 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u06cc\u06c1 \u0636\u0631\u0648\u0631\u06cc \u06c1\u06d2 \u06a9\u06cc\u0648\u0646\u06a9\u06c1 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u0646\u0627\u06a9\u0627\u0645 \u06c1\u0648\u0646\u06d2 \u06a9\u06cc \u0635\u0648\u0631\u062a \u0645\u06cc\u06ba \u0628\u06be\u06cc\u060c \u06cc\u06c1 \u06c1\u0627\u0631\u0646\u0633 \u06a9\u0627 \u06a9\u0627\u0645 \u06a9\u06be\u0627\u062a\u06cc \u06c1\u06d2\u06d4 \u062f\u0648\u0628\u0627\u0631\u06c1 \u062a\u0631\u062a\u06cc\u0628 \u062f\u06cc\u06ba <code>let toolCalls = 0<\/code> \u06c1\u0645 \u0627\u0633 \u0645\u06cc\u06ba \u0627\u0636\u0627\u0641\u06c1 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba \u0627\u0633 \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u06a9\u06c1 \u06c1\u0645 \u0644\u0648\u067e \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u06c1\u0631 \u0627\u062c\u0627\u0632\u062a \u06cc\u0627\u0641\u062a\u06c1 \u06a9\u0631\u0646\u0633\u06cc \u06a9\u06d2 \u0644\u06cc\u06d2 \u0679\u0648\u0644 \u062a\u0644\u0627\u0634 \u06a9\u0631\u06cc\u06ba\u06d4 \u0628\u06cc\u0686 \u0645\u06cc\u06ba \u0645\u0633\u062a\u0631\u062f \u0634\u062f\u06c1 \u062f\u0639\u0648\u06d2 \u0627\u0648\u0631 \u0646\u0627\u0645\u0639\u0644\u0648\u0645 \u0679\u0648\u0644\u0632 \u0628\u06be\u06cc \u0634\u0627\u0645\u0644 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u0627\u06cc\u06a9 \u0645\u0627\u0688\u0644 \u0627\u06cc\u06a9 \u0633\u0627\u062a\u06be \u0645\u062a\u0639\u062f\u062f \u0679\u0648\u0644 \u06a9\u0627\u0644\u0632 \u0628\u06be\u06cc \u0648\u0627\u067e\u0633 \u06a9\u0631 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u06d4 \u06cc\u06c1 \u062f\u0631\u06cc\u0627\u0641\u062a \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2 \u06a9\u06c1 \u0622\u067e \u06a9\u0627 \u0628\u062c\u0679 \u067e\u06c1\u0644\u06d2 \u0686\u0646\u062f \u0631\u0646\u0632 \u06a9\u06d2 \u0628\u0639\u062f \u062e\u062a\u0645 \u06c1\u0648 \u06af\u06cc\u0627 \u06c1\u06d2\u060c \u06c1\u0627\u0631\u0646\u0633 \u06cc\u0642\u06cc\u0646\u06cc \u0628\u0646\u0627\u062a\u0627 \u06c1\u06d2 \u06a9\u06c1: <strong>\u0645\u06a9\u0645\u0644 \u0628\u06cc\u0686<\/strong> \u062a\u0646\u062f\u0631\u0633\u062a\u06cc:<\/p>\n<pre><code class=\"language-typescript\">if (calls.length > maxToolCalls - toolCalls) {\n  return { status: 'tool_limit', messages, steps, toolCalls };\n}\n<\/code><\/pre>\n<p>\u06cc\u06c1 \u0631\u0648\u06a9\u062a\u0627 \u06c1\u06d2\u06d4 <em>\u0628\u062c\u0679 \u067e\u0631 \u0645\u0628\u0646\u06cc<\/em> \u062c\u0632\u0648\u06cc \u0639\u0645\u0644\u062f\u0631\u0622\u0645\u062f\u06d4 \u06c1\u0645 \u0628\u06cc\u0686 \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u0646\u06c1\u06cc\u06ba \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u0679\u0648\u0644 \u0627\u0628 \u0628\u06be\u06cc \u0646\u0627\u06a9\u0627\u0645 \u06c1\u0648 \u0633\u06a9\u062a\u0627 \u06c1\u06d2 \u06cc\u0627 \u067e\u06be\u0627\u0646\u0633\u06cc \u062f\u0631\u0645\u06cc\u0627\u0646 \u0645\u06cc\u06ba \u0645\u0646\u0633\u0648\u062e \u06c1\u0648 \u0633\u06a9\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<h3 id=\"heading-propagate-cancellation-and-deadlines\">\u0645\u0646\u0633\u0648\u062e\u06cc \u0627\u0648\u0631 \u0622\u062e\u0631\u06cc \u062a\u0627\u0631\u06cc\u062e \u06a9\u06cc \u062a\u0628\u0644\u06cc\u063a<\/h3>\n<p>\u0628\u06be\u06cc\u062c\u0646\u06d2 \u0648\u0627\u0644\u0627 \u06c1\u06d2\u06d4 <code>AbortSignal<\/code>\u062c\u0628\u06a9\u06c1 <code>timeoutMs<\/code> \u062f\u0627\u062e\u0644\u06cc \u0688\u06cc\u0688 \u0644\u0627\u0626\u0646 \u0628\u0646\u0627\u0626\u06cc\u06ba\u06d4 \u0627\u06cc\u06a9 \u06a9\u0646\u0679\u0631\u0648\u0644 \u0627\u0646 \u0639\u0646\u0627\u0635\u0631 \u06a9\u0648 \u0627\u0633 \u0637\u0631\u062d \u062c\u0648\u0691\u062a\u0627 \u06c1\u06d2: <code>AbortController<\/code> \u0645\u0627\u0688\u0644\u0632 \u0627\u0648\u0631 \u0679\u0648\u0644\u0632 \u06a9\u0648 \u0633\u06af\u0646\u0644\u0632 \u062f\u06cc\u06ba\u06d4<\/p>\n<p>\u062a\u0631\u062a\u06cc\u0628\u0627\u062a \u0627\u0633 \u0633\u06af\u0646\u0644 \u06a9\u0648 \u062a\u0628\u062f\u06cc\u0644 \u06a9\u0631\u062a\u06cc \u06c1\u06cc\u06ba \u062c\u0648 \u0622\u067e \u0646\u06d2 \u0627\u0628\u062a\u062f\u0627\u0626\u06cc \u0644\u0648\u067e \u0645\u06cc\u06ba \u0628\u0631\u0627\u06c1 \u0631\u0627\u0633\u062a \u0645\u0646\u062a\u062e\u0628 \u06a9\u06cc\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-typescript\">const controller = new AbortController();\nlet timedOut = false;\nconst onAbort = () => controller.abort(options.signal?.reason);\nif (options.signal?.aborted) onAbort();\nelse options.signal?.addEventListener('abort', onAbort, { once: true });\nconst timer = timeoutMs === undefined ? undefined : setTimeout(() => {\n  timedOut = true;\n  controller.abort(new Error('Agent deadline exceeded'));\n}, timeoutMs);\nconst signal = controller.signal;\n<\/code><\/pre>\n<p>\u06cc\u06c1 \u067e\u0627\u0633 \u06a9\u0631\u0648 <code>signal<\/code> \u06a9\u0648 <code>model.generate()<\/code> \u0627\u0648\u0631 <code>tool.execute()<\/code>\u062c\u06cc\u0633\u0627 \u06a9\u06c1 \u0627\u0635\u0644 \u0644\u0648\u067e \u0645\u06cc\u06ba \u06c1\u06d2\u06d4 \u0644\u0648\u067e \u0644\u067e\u06cc\u0679. <code>try<\/code>\/<code>finally<\/code> \u0644\u06c1\u0630\u0627 \u062a\u06a9\u0645\u06cc\u0644 \u0627\u0648\u0631 \u0627\u0628\u062a\u062f\u0627\u0626\u06cc \u0648\u0627\u067e\u0633\u06cc \u06a9\u06d2 \u0679\u0627\u0626\u0645\u0631 \u0627\u0648\u0631 \u0633\u0627\u0645\u0639\u06cc\u0646 \u062f\u0648\u0646\u0648\u06ba\u06d4<\/p>\n<pre><code class=\"language-typescript\">try {\n  \/\/ The execution loop goes here, using controller.signal.\n} finally {\n  if (timer !== undefined) clearTimeout(timer);\n  options.signal?.removeEventListener('abort', onAbort);\n}\n<\/code><\/pre>\n<p>\u067e\u06be\u0627\u0646\u0633\u06cc \u06a9\u06cc \u062d\u062f \u067e\u0631 \u0686\u06cc\u06a9 \u06a9\u0631\u06cc\u06ba\u06d4 <code>signal.aborted<\/code> \u0627\u0648\u0631 \u0648\u0627\u067e\u0633 \u0622\u0648 <code>timedOut ? 'timeout' : 'aborted'<\/code> \u062c\u06cc\u0633\u0627 \u06a9\u06c1 \u06c1\u06d2\u06d4 \u0646\u062a\u0627\u0626\u062c \u0628\u06be\u06cc \u0628\u062a\u0627\u0626\u06d2 \u062c\u0627\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 <code>steps<\/code> \u0627\u0648\u0631 <code>toolCalls<\/code>\u06a9\u0627\u0644 \u06a9\u0631\u0646\u06d2 \u0648\u0627\u0644\u0627 \u062f\u06cc\u06a9\u06be \u0633\u06a9\u062a\u0627 \u06c1\u06d2 \u06a9\u06c1 \u062e\u062a\u0645 \u06c1\u0648\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u06a9\u062a\u0646\u0627 \u06a9\u0627\u0645 \u06c1\u0648\u0627 \u06c1\u06d2\u06d4<\/p>\n<p><strong>\u06cc\u06c1 \u0627\u06cc\u06a9 \u06a9\u0648\u0622\u067e\u0631\u06cc\u0679\u0648 \u0628\u0631\u0637\u0631\u0641\u06cc \u06c1\u06d2\u060c \u0632\u0628\u0631\u062f\u0633\u062a\u06cc \u0628\u0631\u0637\u0631\u0641\u06cc \u0646\u06c1\u06cc\u06ba\u06d4<\/strong> \u0627\u06af\u0631 \u0627\u0688\u0627\u067e\u0679\u0631 \u0627\u0633 \u0633\u06af\u0646\u0644 \u06a9\u0648 \u0646\u0638\u0631 \u0627\u0646\u062f\u0627\u0632 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u062a\u0648 \u0632\u06cc\u0631 \u0627\u0644\u062a\u0648\u0627\u0621 \u06a9\u0627\u0631\u0631\u0648\u0627\u0626\u06cc\u0627\u06ba \u0627\u067e\u0646\u06cc \u0622\u062e\u0631\u06cc \u062a\u0627\u0631\u06cc\u062e \u0633\u06d2 \u0632\u06cc\u0627\u062f\u06c1 \u062f\u06cc\u0631 \u062a\u06a9 \u062c\u0627\u0631\u06cc \u0631\u06c1 \u0633\u06a9\u062a\u06cc \u06c1\u06cc\u06ba\u06d4 \u0627\u0633\u06cc \u0637\u0631\u062d\u060c \u0628\u0686\u06d2 \u06a9\u06d2 \u0639\u0645\u0644 \u06a9\u0648 \u0642\u062a\u0644 \u06a9\u0631\u0646\u06d2 \u0633\u06d2 \u0636\u0631\u0648\u0631\u06cc \u0646\u06c1\u06cc\u06ba \u06a9\u06c1 \u0628\u0686\u06d2 \u06a9\u0627 \u0639\u0645\u0644 \u0631\u06a9 \u062c\u0627\u0626\u06d2\u06d4 \u0633\u062e\u062a \u0639\u0645\u0644 \u062f\u0631\u0622\u0645\u062f \u06a9\u06cc \u062d\u062f\u0648\u062f \u06a9\u06d2 \u0644\u06cc\u06d2 \u0639\u0645\u0644 \u06cc\u0627 \u06a9\u0646\u0679\u06cc\u0646\u0631 \u062a\u0646\u06c1\u0627\u0626\u06cc \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06c1\u0648\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<h3 id=\"heading-test-the-limits-without-waiting-for-real-failures\">\u062d\u0642\u06cc\u0642\u06cc \u0646\u0627\u06a9\u0627\u0645\u06cc \u06a9\u0627 \u0627\u0646\u062a\u0638\u0627\u0631 \u06a9\u06cc\u06d2 \u0628\u063a\u06cc\u0631 \u0627\u067e\u0646\u06cc \u062d\u062f\u0648\u062f \u06a9\u06cc \u062c\u0627\u0646\u0686 \u06a9\u0631\u06cc\u06ba\u06d4<\/h3>\n<p>\u06a9\u06c1 <code>budget tests<\/code> \u0636\u0631\u0648\u0631\u062a \u0633\u06d2 \u0632\u06cc\u0627\u062f\u06c1 \u0628\u062c\u0679 \u0648\u0627\u0644\u06cc \u062c\u06af\u06c1\u0648\u06ba \u06a9\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u0631\u0646\u06d2 \u0627\u0648\u0631 \u062a\u0635\u062f\u06cc\u0642 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u0633\u06a9\u0631\u067e\u0679 \u0645\u0627\u0688\u0644 \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u06cc\u06ba\u06d4 <strong>\u0632\u06cc\u0631\u0648 \u0679\u0648\u0644 \u0631\u0646<\/strong>. \u062f\u0648\u0633\u0631\u06d2 \u0679\u06cc\u0633\u0679 \u0627\u0633 \u0628\u0627\u062a \u06a9\u0627 \u062a\u0639\u06cc\u0646 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba \u06a9\u06c1 \u0622\u06cc\u0627 \u063a\u0644\u0637 \u062f\u0631\u062e\u0648\u0627\u0633\u062a\u06cc\u06ba \u0628\u062c\u0679 \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06cc \u06c1\u06cc\u06ba\u060c \u0622\u06cc\u0627 \u067e\u06c1\u0644\u06d2 \u0633\u06d2 \u0627\u0633\u0642\u0627\u0637 \u0634\u062f\u06c1 \u0633\u06af\u0646\u0644\u0632 \u0645\u0627\u0688\u0644 \u06a9\u0627\u0644\u0632 \u06a9\u0648 \u0631\u0648\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u0627\u0648\u0631 \u0622\u06cc\u0627 \u0628\u0627\u06c1\u0645\u06cc \u062a\u0639\u0627\u0648\u0646 \u06a9\u06d2 \u0645\u0627\u0688\u0644 \u0627\u0648\u0631 \u0679\u0648\u0644\u0632 \u0688\u06cc\u0688 \u0644\u0627\u0626\u0646 \u067e\u0631 \u0631\u06a9 \u062c\u0627\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u0646\u062a\u0627\u0626\u062c \u06a9\u06cc \u0627\u0642\u0633\u0627\u0645 \u06c1\u06cc\u06ba: <code>types.ts<\/code> \u0627\u0628 \u062a\u0645\u06cc\u0632 \u06a9\u0631\u0648 <code>completed<\/code>\u060c <code>step_limit<\/code>\u060c <code>tool_limit<\/code>\u060c <code>aborted<\/code>\u060c <code>timeout<\/code>\u0627\u0648\u0631 <code>model_error<\/code>. \u06cc\u06c1 \u0646\u062a\u0627\u0626\u062c \u062c\u0627\u0646 \u0628\u0648\u062c\u06be \u06a9\u0631 \u0645\u062e\u062a\u0644\u0641 \u06c1\u06cc\u06ba\u06d4 \u0639\u0645\u0644 \u062f\u0631\u0622\u0645\u062f \u06a9\u0633\u06cc \u0628\u06be\u06cc \u0635\u0627\u0631\u0641 \u06a9\u06cc \u06a9\u0627\u0631\u0631\u0648\u0627\u0626\u06cc \u06a9\u0648 \u0645\u06a9\u0645\u0644 \u06a9\u06cc\u06d2 \u0628\u063a\u06cc\u0631 \u062f\u0631\u0633\u062a \u0637\u0631\u06cc\u0642\u06d2 \u0633\u06d2 \u0631\u0648\u06a9 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<h2 id=\"heading-5-keep-the-context-under-control\">5. \u0635\u0648\u0631\u062a\u062d\u0627\u0644 \u067e\u0631 \u0642\u0627\u0628\u0648 \u067e\u0627\u0644\u06cc\u06ba\u06d4<\/h2>\n<p>\u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u0646\u06d2 \u0648\u0627\u0644\u0648\u06ba \u06a9\u06d2 \u067e\u0627\u0633 \u0627\u0628 \u0645\u062d\u062f\u0648\u062f \u0622\u067e\u0631\u06cc\u0679\u0646\u06af \u0648\u0642\u062a \u06c1\u06d2\u060c \u0644\u06cc\u06a9\u0646 \u0628\u0627\u062a \u0686\u06cc\u062a \u0645\u06cc\u06ba \u0627\u0636\u0627\u0641\u06c1 \u06c1\u0648\u062a\u0627 \u062c\u0627 \u0631\u06c1\u0627 \u06c1\u06d2\u06d4 \u062a\u0645\u0627\u0645 \u0645\u0627\u0688\u0644 \u06a9\u06d2 \u062c\u0648\u0627\u0628\u0627\u062a \u0627\u0648\u0631 \u0679\u0648\u0644 \u06a9\u06d2 \u0646\u062a\u0627\u0626\u062c \u0645\u0627\u0688\u0644 \u06a9\u0648 \u0648\u0627\u067e\u0633 \u0628\u06be\u06cc\u062c\u06d2 \u06af\u0626\u06d2 \u0627\u06cc\u06a9 \u0627\u0648\u0631 \u067e\u06cc\u063a\u0627\u0645 \u0628\u0646 \u062c\u0627\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u0627\u06cc\u06a9 \u0641\u0627\u0626\u0644 \u06a9\u0648 \u067e\u0691\u06be\u0646\u06d2 \u0633\u06d2 \u06c1\u0632\u0627\u0631\u0648\u06ba \u0644\u0627\u0626\u0646\u06cc\u06ba \u0648\u0627\u067e\u0633 \u0622 \u0633\u06a9\u062a\u06cc \u06c1\u06cc\u06ba\u06d4 \u0645\u062a\u0639\u062f\u062f \u062a\u06a9\u0631\u0627\u0631 \u0645\u0627\u0688\u0644 \u06a9\u06cc \u0633\u06cc\u0627\u0642 \u0648 \u0633\u0628\u0627\u0642 \u06a9\u06cc \u06a9\u06be\u0691\u06a9\u06cc \u06a9\u0648 \u0645\u0631\u062d\u0644\u06c1 \u0648\u0627\u0631 \u0628\u062c\u0679 \u062a\u06a9 \u067e\u06c1\u0646\u0686\u0646\u06d2 \u0633\u06d2 \u0628\u06c1\u062a \u067e\u06c1\u0644\u06d2 \u062e\u062a\u0645 \u06a9\u0631\u0646\u06d2 \u06a9\u0627 \u0633\u0628\u0628 \u0628\u0646 \u0633\u06a9\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<p>\u0633\u0646\u06af \u0645\u06cc\u0644 5 \u062f\u0631\u062c \u0630\u06cc\u0644 \u0627\u062e\u062a\u0644\u0627\u0641\u0627\u062a \u06a9\u0648 \u0645\u062a\u0639\u0627\u0631\u0641 \u06a9\u0631\u0627\u062a\u0627 \u06c1\u06d2: <strong>\u0631\u067e\u0648\u0631\u0679 \u06a9\u0627\u0631\u0688\u0632 \u062c\u0648 \u06c1\u0645 \u0627\u067e\u0646\u06d2 \u067e\u0627\u0633 \u0631\u06a9\u06be\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/strong> \u0627\u0648\u0631 <strong>\u067e\u06cc\u063a\u0627\u0645 \u06c1\u0645 \u0645\u0627\u0688\u0644 \u06a9\u0648 \u0628\u06be\u06cc\u062c\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/strong>. \u0639\u0645\u0644 \u062f\u0631\u0622\u0645\u062f \u06a9\u0648 \u0686\u06cc\u06a9 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-shell\">git switch --detach 05-context\n<\/code><\/pre>\n<p>\u0645\u062a\u0639\u0644\u0642\u06c1 \u0641\u0627\u0626\u0644\u06cc\u06ba \u06c1\u06cc\u06ba\u06d4 <code>src\/core\/context.ts<\/code>\u060c <code>src\/core\/agent.ts<\/code>\u0627\u0648\u0631 <code>tests\/context.test.ts<\/code>.<\/p>\n<h3 id=\"heading-bound-tool-output-and-model-facing-history\">\u067e\u0627\u0628\u0646\u062f \u0679\u0648\u0644 \u0622\u0624\u0679 \u067e\u0679 \u0627\u0648\u0631 \u0645\u0627\u0688\u0644 \u067e\u0631 \u0645\u0628\u0646\u06cc \u0631\u06cc\u06a9\u0627\u0631\u0688\u0646\u06af<\/h3>\n<p>\u0646\u06cc\u0627 <code>context<\/code> \u0627\u062e\u062a\u06cc\u0627\u0631\u0627\u062a \u0646\u06d2 \u062f\u0648 \u0627\u0644\u06af \u0627\u0644\u06af \u062d\u062f\u0648\u062f \u0645\u0642\u0631\u0631 \u06a9\u06cc \u06c1\u06cc\u06ba:<\/p>\n<pre><code class=\"language-typescript\">const result = await runAgent({\n  prompt: 'Inspect the project',\n  model,\n  tools,\n  context: {\n    maxContextChars: 32_000,\n    maxToolResultChars: 8_000\n  }\n});\n<\/code><\/pre>\n<p><code>maxToolResultChars<\/code>    \u06c1\u0631 \u0622\u0644\u06d2 \u06a9\u06d2 \u0646\u062a\u0627\u0626\u062c \u06a9\u06cc \u062d\u062f\u0648\u062f <strong>\u067e\u06c1\u0644\u06d2<\/strong> \u0627\u067e\u0646\u06d2 \u0631\u067e\u0648\u0631\u0679 \u06a9\u0627\u0631\u0688 \u067e\u0631 \u062c\u0627\u0626\u06cc\u06ba\u06d4 \u0628\u0691\u06d2 \u0646\u062a\u0627\u0626\u062c \u0634\u0631\u0648\u0639 \u0627\u0648\u0631 \u0627\u062e\u062a\u062a\u0627\u0645 \u06a9\u0648 \u0628\u0631\u0642\u0631\u0627\u0631 \u0631\u06a9\u06be\u062a\u06d2 \u06c1\u06cc\u06ba \u0627\u0648\u0631 \u062f\u0631\u0645\u06cc\u0627\u0646 \u0645\u06cc\u06ba \u0628\u06cc\u0636\u0648\u06cc \u06c1\u0648\u062a\u0627 \u06c1\u06d2\u06d4 \u0636\u0627\u0626\u0639 \u0634\u062f\u06c1 \u062d\u0635\u0648\u06ba \u06a9\u0648 \u0628\u0639\u062f \u0645\u06cc\u06ba \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u0646\u06c1\u06cc\u06ba \u06a9\u06cc\u0627 \u062c\u0627 \u0633\u06a9\u062a\u0627\u06d4 <code>result.messages<\/code>.<\/p>\n<p>\u0679\u0631\u0646\u06a9\u06cc\u0634\u0646 \u06c1\u06cc\u0644\u067e\u0631 \u0645\u0627\u0631\u06a9\u0631 \u06a9\u06d2 \u0644\u06cc\u06d2 \u062c\u06af\u06c1 \u0645\u062d\u0641\u0648\u0638 \u0631\u06a9\u06be\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u067e\u06be\u0631 \u0628\u0627\u0642\u06cc \u062c\u06af\u06c1 \u06a9\u0648 \u0634\u0631\u0648\u0639 \u0627\u0648\u0631 \u0627\u062e\u062a\u062a\u0627\u0645 \u06a9\u06d2 \u062f\u0631\u0645\u06cc\u0627\u0646 \u062a\u0642\u0633\u06cc\u0645 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-typescript\">export function boundToolResult(content: string, limit: number): string {\n  if (content.length <= limit) return content;\n  const marker = `n...[${content.length - limit} or more characters omitted]...n`;\n  if (marker.length >= limit) return marker.slice(0, limit);\n  const remaining = limit - marker.length;\n  const front = Math.ceil(remaining \/ 2);\n  const back = Math.floor(remaining \/ 2);\n  return content.slice(0, front) + marker + (back ? content.slice(-back) : '');\n}\n<\/code><\/pre>\n<p>\u06a9\u0627\u0645\u06cc\u0627\u0628 \u0646\u062a\u0627\u0626\u062c \u0627\u0648\u0631 \u063a\u0644\u0637\u06cc \u06a9\u06d2 \u062a\u0627\u0631 \u062f\u0648\u0646\u0648\u06ba \u0644\u0627\u06af \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u062f\u06cc\u06ba\u06d4 <code>content: boundToolResult(content, context.maxToolResultChars)<\/code>. \u06cc\u06c1 \u06a9\u0645\u067e\u06cc\u06a9\u0679 \u0648\u0631\u0698\u0646 \u0648\u0627\u0636\u062d \u0637\u0648\u0631 \u067e\u0631 \u0635\u0641\u0631 \u06a9\u06cc \u0644\u0645\u0628\u0627\u0626\u06cc \u0648\u0627\u0644\u06cc \u062f\u0645\u0648\u06ba \u06a9\u0648 \u06c1\u06cc\u0646\u0688\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 <code>slice(-0)<\/code> \u0622\u067e \u063a\u0644\u0637\u06cc \u0633\u06d2 \u067e\u0648\u0631\u0627 \u0646\u062a\u06cc\u062c\u06c1 \u0646\u06c1\u06cc\u06ba \u0631\u06a9\u06be \u0633\u06a9\u062a\u06d2\u06d4<\/p>\n<p><code>maxContextChars<\/code>    \u0645\u0627\u0688\u0644 \u06a9\u0648 \u0628\u06be\u06cc\u062c\u06d2 \u06af\u0626\u06d2 \u0633\u0644\u0633\u0644\u06c1 \u0648\u0627\u0631 \u067e\u06cc\u063a\u0627\u0645\u0627\u062a \u06a9\u06cc \u0635\u0641 \u06a9\u0648 \u0645\u062d\u062f\u0648\u062f \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u06c1\u0627\u0631\u0646\u0633 \u067e\u0686\u06be\u0644\u06d2 \u067e\u06cc\u063a\u0627\u0645\u0627\u062a \u06a9\u0648 \u0648\u0627\u067e\u0633 \u06a9\u06cc \u06af\u0626\u06cc \u062a\u0627\u0631\u06cc\u062e \u0645\u06cc\u06ba \u0631\u06a9\u06be\u062a\u0627 \u06c1\u06d2\u060c \u0644\u06cc\u06a9\u0646 <code>selectContext()<\/code> \u0632\u06cc\u0627\u062f\u06c1 \u0633\u06d2 \u0632\u06cc\u0627\u062f\u06c1 \u0627\u0628\u062a\u062f\u0627\u0626\u06cc \u0635\u0627\u0631\u0641 \u06a9\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a\u06cc\u06ba \u0627\u0648\u0631 \u062d\u0627\u0644\u06cc\u06c1 \u0645\u0648\u0691 \u0628\u06be\u06cc\u062c\u06cc\u06ba\u06d4 \u06a9\u0648\u0626\u06cc \u062e\u0644\u0627\u0635\u06c1 \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4 \u0627\u0633 \u0645\u0648\u0691 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0686\u06be\u0648\u0691\u06cc \u06af\u0626\u06cc \u062a\u0641\u0635\u06cc\u0644\u0627\u062a \u0645\u0627\u0688\u0644 \u0645\u06cc\u06ba \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u0646\u06c1\u06cc\u06ba \u06a9\u06cc \u062c\u0627 \u0633\u06a9\u062a\u06cc \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u06cc\u06c1 \u06a9\u0631\u06cc\u06a9\u0679\u0631 \u06a9\u06cc \u062d\u062f \u06c1\u06d2\u060c \u0679\u0648\u06a9\u0646 \u06a9\u06cc \u062d\u062f \u0646\u06c1\u06cc\u06ba\u06d4 \u0679\u0648\u0644 \u06a9\u06cc \u062a\u0639\u0631\u06cc\u0641 \u0627\u0648\u0631 \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0646\u0646\u062f\u06c1 \u06a9\u06d2 \u0645\u062e\u0635\u0648\u0635 \u0627\u0648\u0648\u0631 \u06c1\u06cc\u0688 \u06a9\u0648 \u0686\u06be\u0648\u0691 \u06a9\u0631\u060c JSON \u0633\u06cc\u0631\u06cc\u0644\u0627\u0626\u0632\u06cc\u0634\u0646 \u06a9\u06d2 \u0628\u0639\u062f JavaScript \u0633\u0679\u0631\u0646\u06af \u06a9\u06cc \u0644\u0645\u0628\u0627\u0626\u06cc \u06a9\u06cc \u067e\u06cc\u0645\u0627\u0626\u0634 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u0627\u0635\u0644 \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0646\u0646\u062f\u06c1 \u0627\u0688\u0627\u067e\u0679\u0631 \u06a9\u0648 \u0679\u0648\u06a9\u0646 \u06a9\u06cc \u0634\u0646\u0627\u062e\u062a \u06a9\u0627 \u0627\u06a9\u0627\u0624\u0646\u0679 \u0627\u0648\u0631 \u062c\u0648\u0627\u0628\u0627\u062a \u06a9\u06d2 \u0644\u06cc\u06d2 \u0645\u062e\u0635\u0648\u0635 \u062c\u06af\u06c1 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06c1\u0648\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<h3 id=\"heading-dont-split-a-tool-call-from-its-result\">\u0679\u0648\u0644 \u06a9\u0627\u0644\u0632 \u06a9\u0648 \u0646\u062a\u0627\u0626\u062c \u0633\u06d2 \u0627\u0644\u06af \u0646\u06c1 \u06a9\u0631\u06cc\u06ba\u06d4<\/h3>\n<p>\u0633\u06cc\u0627\u0642 \u0648 \u0633\u0628\u0627\u0642 \u06a9\u0648 \u062a\u0631\u0627\u0634\u0646\u0627 \u0627\u062a\u0646\u0627 \u0622\u0633\u0627\u0646 \u0646\u06c1\u06cc\u06ba \u062c\u062a\u0646\u0627 \u067e\u0631\u0627\u0646\u06d2 \u067e\u06cc\u063a\u0627\u0645 \u06a9\u0648 \u06c1\u0679\u0627\u0646\u0627 \u06c1\u06d2\u06d4 \u0645\u0639\u0627\u0648\u0646 \u062c\u0648\u0627\u0628 \u0645\u062a\u0639\u062f\u062f \u0679\u0648\u0644\u0632 \u06a9\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u0631 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u060c \u062c\u0646 \u0645\u06cc\u06ba \u0633\u06d2 \u06c1\u0631 \u0627\u06cc\u06a9 \u06a9\u06cc \u0634\u0646\u0627\u062e\u062a \u06a9\u0627\u0644 \u0622\u0626\u06cc \u0688\u06cc \u0633\u06d2 \u06c1\u0648\u062a\u06cc \u06c1\u06d2\u06d4 \u0646\u062a\u0627\u0626\u062c \u06a9\u0627 \u0635\u0631\u0641 \u0627\u06cc\u06a9 \u062d\u0635\u06c1 \u0628\u06be\u06cc\u062c\u0646\u06d2 \u0633\u06d2 \u063a\u0644\u0637 \u06cc\u0627 \u06af\u0645\u0631\u0627\u06c1 \u06a9\u0646 \u06af\u0641\u062a\u06af\u0648 \u06c1\u0648\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<p>\u0644\u06c1\u0630\u0627 \u0633\u0644\u06cc\u06a9\u0679\u0631 \u062b\u0627\u0646\u0648\u06cc \u067e\u06cc\u063a\u0627\u0645\u0627\u062a \u06a9\u0648 \u06c1\u06cc\u0646\u0688\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 <strong>\u0627\u0633 \u0628\u06cc\u0686 \u06a9\u06d2 \u062a\u0645\u0627\u0645 \u0646\u062a\u0627\u0626\u062c<\/strong> \u0627\u06cc\u06a9 \u0644\u0627\u0632\u0645 \u0648 \u0645\u0644\u0632\u0648\u0645 \u06af\u0631\u0648\u067e \u06a9\u06d2 \u0637\u0648\u0631 \u067e\u0631\u06d4 \u067e\u0648\u0631\u06d2 \u06af\u0631\u0648\u067e \u06a9\u0648 \u0634\u0627\u0645\u0644 \u06a9\u0631\u06cc\u06ba \u06cc\u0627 \u0686\u06be\u0648\u0691 \u062f\u06cc\u06ba\u06d4 \u06cc\u06c1 \u063a\u06cc\u0631 \u0645\u062a\u0636\u0627\u062f \u0646\u062a\u0627\u0626\u062c \u0627\u0648\u0631 \u0646\u0627\u0645\u06a9\u0645\u0644 \u062a\u0639\u06cc\u0646\u0627\u062a\u06cc\u0648\u06ba \u06a9\u0648 \u0628\u06be\u06cc \u0645\u0633\u062a\u0631\u062f \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u0628\u062c\u0627\u0626\u06d2 \u0627\u0633 \u06a9\u06d2 \u06a9\u06c1 \u062e\u0627\u0645\u0648\u0634\u06cc \u0633\u06d2 \u0645\u062a\u0636\u0627\u062f \u0633\u06cc\u0627\u0642 \u0648 \u0633\u0628\u0627\u0642 \u06a9\u06cc \u062a\u0639\u0645\u06cc\u0631 \u06a9\u06cc \u062c\u0627\u0626\u06d2\u06d4<\/p>\n<p>\u06cc\u06c1\u0627\u06ba <code>selectContext()<\/code> \u0633\u06d2 <code>src\/core\/context.ts<\/code>\u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 <code>Message<\/code> \u0633\u06cc\u06a9\u0634\u0646 1 \u0645\u06cc\u06ba \u0628\u06cc\u0627\u0646 \u06a9\u0631\u062f\u06c1 \u0642\u0633\u0645\u06d4 \u067e\u06c1\u0644\u0627 \u0644\u0648\u067e \u0679\u0631\u0627\u0646\u0633\u06a9\u0631\u067e\u0679\u0633 \u06a9\u06cc \u062a\u0648\u062b\u06cc\u0642 \u0627\u0648\u0631 \u06af\u0631\u0648\u067e \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u062f\u0648\u0633\u0631\u0627 \u0628\u062c\u0679 \u0645\u06a9\u0645\u0644 \u06c1\u0648\u0646\u06d2 \u062a\u06a9 \u067e\u0648\u0631\u06d2 \u06af\u0631\u0648\u067e \u06a9\u0648 \u0648\u0627\u067e\u0633 \u0644\u06d2 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-typescript\">import type { Message } from '.\/types.ts';\n\nconst size = (messages: readonly Message[]) => JSON.stringify(messages).length;\n\nexport function selectContext(messages: readonly Message[], maxChars: number): Message[] {\n  if (!Number.isSafeInteger(maxChars) || maxChars < 1) {\n    throw new RangeError('maxContextChars must be a positive safe integer');\n  }\n  if (!messages.length) return [];\n  const groups: Message[][] = [];\n  for (let i = 0; i < messages.length;) {\n    const message = messages[i]!;\n    if (message.role === 'assistant' &#038;&#038; message.toolCalls?.length) {\n      const ids = new Set(message.toolCalls.map(call => call.id));\n      if (ids.size !== message.toolCalls.length) throw new Error('Duplicate tool call IDs in assistant turn');\n      const group: Message[] = [message];\n      i++;\n      while (i < messages.length &#038;&#038; messages[i]!.role === 'tool') {\n        const result = messages[i]!;\n        if (result.role === 'tool' &#038;&#038; !ids.delete(result.callId)) throw new Error('Orphan or duplicate tool result');\n        group.push(result);\n        i++;\n      }\n      if (ids.size) throw new Error('Incomplete tool result batch');\n      groups.push(group);\n    } else {\n      if (message.role === 'tool') throw new Error('Orphan tool result');\n      groups.push([message]);\n      i++;\n    }\n  }\n  const first = groups[0]!;\n  if (first[0]?.role !== 'user') throw new Error('Conversation must start with a user message');\n  const recent: Message[][] = [];\n  for (let i = groups.length - 1; i >= 1; i--) {\n    const group = groups[i]!;\n    const next = [...first, ...[group, ...recent].flat()];\n    if (size(next) > maxChars) {\n      if (recent.length === 0) throw new Error('Context budget too small for latest turn');\n      break;\n    }\n    recent.unshift(group);\n  }\n  const selected = [...first, ...recent.flat()];\n  if (size(selected) > maxChars) throw new Error('Context budget too small for required messages');\n  return selected;\n}\n<\/code><\/pre>\n<p>\u06c1\u0631 \u0645\u0627\u0688\u0644 \u06a9\u0627\u0644 \u0633\u06d2 \u067e\u06c1\u0644\u06d2\u060c \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u06cc\u06ba: <code>selectContext(messages, context.maxContextChars)<\/code> \u0627\u0633 \u06a9\u0627 <code>messages<\/code> \u0627\u0646 \u067e\u0679 \u0627\u06af\u0631 \u06cc\u0627 \u062a\u0648 \u0627\u0628\u062a\u062f\u0627\u0626\u06cc \u0627\u0634\u0627\u0631\u06c1 \u06cc\u0627 \u0633\u0628 \u0633\u06d2 \u062d\u0627\u0644\u06cc\u06c1 \u0645\u0637\u0644\u0648\u0628\u06c1 \u06af\u0631\u0648\u067e \u0645\u0645\u0627\u062b\u0644 \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u060c \u0633\u0644\u06cc\u06a9\u0679\u0631 \u06a9\u0648 \u067e\u06be\u06cc\u0646\u06a9 \u062f\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u06c1\u0627\u0631\u0646\u0633 \u0648\u0627\u067e\u0633 \u06a9\u0631 \u062f\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4 <code>context_limit<\/code>. \u06cc\u06c1 \u0639\u0645\u0644 \u062f\u0631\u0622\u0645\u062f \u06a9\u0627 \u0641\u06cc\u0635\u0644\u06c1 \u06c1\u06d2\u060c \u0679\u0648\u0644 \u06a9\u06cc \u063a\u0644\u0637\u06cc \u0646\u06c1\u06cc\u06ba \u062c\u0633 \u0633\u06d2 \u0645\u0627\u0688\u0644 \u0679\u06be\u06cc\u06a9 \u06c1\u0648 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0688\u06cc\u0679\u0631\u0645\u0646\u0633\u0679\u06a9 \u0679\u06cc\u0633\u0679 \u0628\u06cc\u0686 \u06a9\u06d2 \u062a\u062d\u0641\u0638\u060c \u06cc\u062a\u06cc\u0645 \u06a9\u0627 \u067e\u062a\u06c1 \u0644\u06af\u0627\u0646\u06d2\u060c \u0622\u0624\u0679 \u067e\u0679 \u0679\u0631\u0646\u06a9\u06cc\u0634\u0646\u060c \u0627\u0648\u0631 \u0645\u0627\u0688\u0644 \u0627\u0648\u0631\u06cc\u0646\u0679\u06cc\u0634\u0646 \u067e\u0631\u0648\u062c\u06cc\u06a9\u0634\u0646 \u06a9\u0648 \u0644\u0627\u06af\u0648 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u0648\u06c1 \u0627\u0633 \u0628\u0627\u062a \u06a9\u0648 \u06cc\u0642\u06cc\u0646\u06cc \u0628\u0646\u0627\u062a\u06d2 \u06c1\u06cc\u06ba \u06a9\u06c1 \u0633\u06cc\u0627\u0642 \u0648 \u0633\u0628\u0627\u0642 \u0646\u06c1 \u0635\u0631\u0641 \u0686\u06be\u0648\u0679\u0627 \u06c1\u06d2\u060c \u0644\u06cc\u06a9\u0646 \u067e\u06be\u0631 \u0628\u06be\u06cc \u0627\u06cc\u06a9 \u0645\u0631\u0628\u0648\u0637 \u06af\u0641\u062a\u06af\u0648 \u06a9\u06cc \u0646\u0645\u0627\u0626\u0646\u062f\u06af\u06cc \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u0627\u06af\u0644\u0627\u060c \u06c1\u0645 \u0627\u0646 \u0641\u06cc\u0635\u0644\u0648\u06ba \u06a9\u0648 \u0642\u0627\u0628\u0644 \u0645\u0634\u0627\u06c1\u062f\u06c1 \u0628\u0646\u0627\u0626\u06cc\u06ba \u06af\u06d2\u06d4<\/p>\n<h2 id=\"heading-6-make-agent-execution-observable\">6. \u0627\u06cc\u062c\u0646\u0679 \u06a9\u06d2 \u0639\u0645\u0644 \u06a9\u0648 \u0642\u0627\u0628\u0644 \u0645\u0634\u0627\u06c1\u062f\u06c1 \u0628\u0646\u0627\u0626\u06cc\u06ba<\/h2>\n<p>\u0627\u06cc\u062c\u0646\u0679 \u063a\u06cc\u0631 \u0645\u062a\u0648\u0642\u0639 \u06a9\u0627\u0645 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 \u0635\u062d\u06cc\u062d \u062c\u0648\u0627\u0628 \u062f\u06d2 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u060c \u062c\u06cc\u0633\u06d2 \u06a9\u06c1 \u0646\u0627\u06a9\u0627\u0645 \u0622\u067e\u0631\u06cc\u0634\u0646 \u06a9\u06cc \u062f\u0648\u0628\u0627\u0631\u06c1 \u06a9\u0648\u0634\u0634 \u06a9\u0631\u0646\u0627\u060c \u063a\u06cc\u0631 \u0636\u0631\u0648\u0631\u06cc \u0645\u0627\u0688\u0644 \u06a9\u0627\u0644 \u06a9\u0631\u0646\u0627\u060c \u06cc\u0627 \u0627\u067e\u0646\u0627 \u0632\u06cc\u0627\u062f\u06c1 \u062a\u0631 \u0648\u0642\u062a \u0627\u06cc\u06a9 \u0679\u0648\u0644 \u0645\u06cc\u06ba \u06af\u0632\u0627\u0631\u0646\u0627\u06d4 \u0627\u06a9\u06cc\u0644\u06d2 \u0622\u062e\u0631\u06cc \u062c\u0648\u0627\u0628 \u06c1\u0645\u06cc\u06ba \u0646\u06c1\u06cc\u06ba \u0628\u062a\u0627\u062a\u0627 \u06a9\u06c1 \u06a9\u06cc\u0627 \u06c1\u0648\u0627 \u06c1\u06d2\u06d4 \u0622\u067e \u06a9\u0648 \u0644\u0627\u06af\u0646\u06af \u06a9\u06d2 \u0641\u0631\u06cc\u0645 \u0648\u0631\u06a9 \u0645\u06cc\u06ba \u0627\u067e\u0646\u06d2 \u06a9\u0646\u0679\u0631\u0648\u0644 \u06a9\u0648 \u062a\u0628\u062f\u06cc\u0644 \u06a9\u06cc\u06d2 \u0628\u063a\u06cc\u0631 \u0639\u0645\u0644 \u062f\u0631\u0622\u0645\u062f \u06a9\u06d2 \u0648\u0627\u0642\u0639\u0627\u062a \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06c1\u06d2\u06d4<\/p>\n<p>\u0633\u0627\u062a\u06be\u06cc \u0630\u062e\u06cc\u0631\u06c1 \u0645\u06cc\u06ba \u0627\u0633 \u0633\u0646\u06af \u0645\u06cc\u0644 \u06a9\u0648 \u062f\u06cc\u06a9\u06be\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-shell\">git switch --detach 06-observability\n<\/code><\/pre>\n<p>\u0639\u0645\u0644 \u062f\u0631\u0622\u0645\u062f <code>src\/core\/events.ts<\/code>\u0627\u0646\u0636\u0645\u0627\u0645 <code>src\/core\/agent.ts<\/code>.<\/p>\n<h3 id=\"heading-emit-events-at-execution-boundaries\">\u067e\u06be\u0627\u0646\u0633\u06cc \u06a9\u06cc \u062d\u062f\u0648\u062f \u0645\u06cc\u06ba \u0648\u0627\u0642\u0639\u0627\u062a \u06a9\u0627 \u0627\u062e\u0631\u0627\u062c<\/h3>\n<p>\u0627\u067e\u0646\u0627 \u0627\u0646\u062a\u062e\u0627\u0628 \u0634\u0627\u0645\u0644 \u06a9\u0631\u06cc\u06ba\u06d4 <code>onEvent<\/code> \u06a9\u0627\u0644 \u0628\u06cc\u06a9 <code>runAgent<\/code>. \u06c1\u0627\u0631\u0646\u0633 \u062c\u0627\u0631\u06cc \u06a9\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4 <code>model_start<\/code> \u0627\u0648\u0631 <code>model_end<\/code> \u0645\u0627\u0688\u0644 \u06a9\u0627\u0644\u0646\u06af \u06a9\u06d2 \u0628\u0627\u0631\u06d2 \u0645\u06cc\u06ba <code>tool_start<\/code> \u0627\u0648\u0631 <code>tool_end<\/code> \u0679\u0648\u0644 \u0688\u0633\u067e\u06cc\u0686 \u06a9\u06d2 \u0627\u0631\u062f \u06af\u0631\u062f\u060c <code>model_error<\/code> \u062c\u0628 \u0645\u0627\u0688\u0644 \u0622\u067e\u0631\u06cc\u0634\u0646 \u0646\u0627\u06a9\u0627\u0645 \u06c1\u0648\u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4 <code>run_end<\/code> \u062c\u0628 \u067e\u06be\u0627\u0646\u0633\u06cc \u062e\u062a\u0645 \u06c1\u0648\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<p>\u06c1\u0631 \u0627\u06cc\u0648\u0646\u0679 \u0645\u06cc\u06ba \u0627\u06cc\u06a9 \u0627\u06cc\u06af\u0632\u06cc\u06a9\u06cc\u0648\u0634\u0646 ID\u060c \u0627\u06cc\u06a9 \u0628\u0691\u06be\u062a\u06cc \u06c1\u0648\u0626\u06cc \u062a\u0631\u062a\u06cc\u0628 \u0646\u0645\u0628\u0631\u060c \u0627\u0648\u0631 \u0679\u0627\u0626\u0645 \u0627\u0633\u0679\u06cc\u0645\u067e \u06c1\u0648\u062a\u0627 \u06c1\u06d2\u06d4 \u0645\u0627\u0688\u0644 \u0627\u0648\u0631 \u0679\u0648\u0644 \u06a9\u06cc \u062a\u06a9\u0645\u06cc\u0644 \u06a9\u06d2 \u0648\u0627\u0642\u0639\u0627\u062a \u0628\u06be\u06cc \u0627\u06cc\u06a9 \u0645\u0648\u0646\u0648\u0679\u0648\u0646\u06a9 \u06af\u06be\u0691\u06cc \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 \u0646\u0627\u067e\u06d2 \u06af\u0626\u06d2 \u062f\u0648\u0631\u0627\u0646\u06cc\u06d2 \u06a9\u06cc \u0627\u0637\u0644\u0627\u0639 \u062f\u06cc\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u06cc\u06c1 \u06a9\u0627\u0631\u0631\u0648\u0627\u0626\u06cc\u0648\u06ba \u06a9\u06cc \u062a\u0631\u062a\u06cc\u0628 \u06a9\u0648 \u062f\u0648\u0628\u0627\u0631\u06c1 \u062a\u0631\u062a\u06cc\u0628 \u062f\u06cc\u0646\u06d2 \u0627\u0648\u0631 \u0633\u0633\u062a \u06a9\u0627\u0644\u0648\u06ba \u06a9\u06cc \u0634\u0646\u0627\u062e\u062a \u06a9\u06d2 \u0644\u06cc\u06d2 \u06a9\u0627\u0641\u06cc \u0645\u0639\u0644\u0648\u0645\u0627\u062a \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-typescript\">const events: AgentEvent[] = [];\n\nconst result = await runAgent({\n  prompt: 'Inspect the project',\n  model,\n  tools,\n  onEvent: event => events.push(event),\n});\n\nconsole.log(result.runId, events);\n<\/code><\/pre>\n<p>\u062f\u0631\u0622\u0645\u062f <code>AgentEvent<\/code> \u0633\u06d2 <code>src\/core\/events.ts<\/code>. \u06a9\u0627\u0644 \u0628\u06cc\u06a9 \u0627\u062e\u062a\u06cc\u0627\u0631\u06cc \u06c1\u06d2\u06d4 \u06a9\u0627\u0644 \u06a9\u0631\u0646\u06d2 \u0648\u0627\u0644\u06d2 \u062c\u0646 \u06a9\u0648 \u0679\u06cc\u0644\u06cc \u0645\u06cc\u0679\u0631\u06cc \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u0646\u06c1\u06cc\u06ba \u06c1\u06d2 \u0648\u06c1 \u06a9\u0627\u0644 \u0628\u06cc\u06a9 \u06a9\u0648 \u0686\u06be\u0648\u0691 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u0627\u06cc\u06a9 \u0628\u0627\u0631\u06cc\u06a9 \u062a\u0642\u0627\u0636\u0627 \u06c1\u06d2\u06d4 <strong>\u0645\u0634\u0627\u06c1\u062f\u0627\u062a\u06cc \u0639\u0645\u0644 \u06a9\u0648 \u06a9\u0646\u0679\u0631\u0648\u0644 \u0646\u06c1\u06cc\u06ba \u06a9\u0631\u0646\u0627 \u0686\u0627\u06c1\u0626\u06d2\u06d4<\/strong>. \u0627\u06cc\u06a9 \u06a9\u0627\u0645\u06cc\u0627\u0628 \u0679\u0648\u0644 \u06a9\u0627\u0644 \u06a9\u0633\u06cc \u0627\u06cc\u0648\u0646\u0679 \u0633\u0646\u0646\u06d2 \u0648\u0627\u0644\u06d2 \u0645\u06cc\u06ba \u0627\u0633\u062a\u062b\u0646\u0627\u0621 \u06a9\u06cc \u0648\u062c\u06c1 \u0633\u06d2 \u0646\u0627\u06a9\u0627\u0645 \u0646\u06c1\u06cc\u06ba \u06c1\u0648\u0646\u06cc \u0686\u0627\u06c1\u06cc\u06d2\u06d4 \u0627\u06cc\u0648\u0646\u0679 \u0627\u06cc\u0645\u06cc\u0679\u0631 \u0633\u0627\u0645\u0639\u06cc\u0646 \u06a9\u06d2 \u0627\u0633\u062a\u062b\u0646\u0627\u0621 \u06a9\u0648 \u067e\u06a9\u0691\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0627\u062e\u062a\u06cc\u0627\u0631\u06cc \u0637\u0648\u0631 \u067e\u0631 \u0627\u0646 \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u0631\u067e\u0648\u0631\u0679 \u06a9\u0631\u062a\u0627 \u06c1\u06d2: <code>onObserverError<\/code>\u0627\u0633 \u06c1\u06cc\u0646\u0688\u0644\u0631 \u06a9\u06cc \u0646\u0627\u06a9\u0627\u0645\u06cc \u0628\u06be\u06cc \u062f\u0628 \u062c\u0627\u062a\u06cc \u06c1\u06d2\u06d4 \u062a\u0627\u06c1\u0645\u060c \u0686\u0648\u0646\u06a9\u06c1 \u06a9\u0627\u0644 \u0628\u06cc\u06a9\u0633 \u06c1\u0645 \u0622\u06c1\u0646\u06af \u06c1\u0648\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u0627\u06cc\u06a9 \u0633\u0633\u062a \u0633\u0646\u0646\u06d2 \u0648\u0627\u0644\u0627 \u0627\u0628 \u0628\u06be\u06cc \u0627\u06cc\u062c\u0646\u0679 \u06a9\u0648 \u062a\u0627\u062e\u06cc\u0631 \u06a9\u0631\u06d2 \u06af\u0627\u06d4<\/p>\n<p>emitter \u06a9\u06cc \u0637\u0631\u0641 \u0633\u06d2 \u067e\u06cc\u062f\u0627 <code>runId<\/code> \u0627\u06cc\u06a9 \u0628\u0627\u0631 <code>randomUUID()<\/code> \u0633\u06d2 <code>node:crypto<\/code>\u0627\u0648\u0631 \u062f\u0648\u0628\u0627\u0631\u06c1 \u062a\u0631\u062a\u06cc\u0628 \u062f\u06cc\u06ba <code>sequence<\/code> 0. \u06a9\u06c1 <code>emit(event)<\/code> \u06cc\u06c1 \u0637\u0631\u06cc\u0642\u06c1 \u0627\u06cc\u0648\u0646\u0679 \u06a9\u0648 \u0628\u0691\u06be\u0627\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u062f\u0648\u0646\u0648\u06ba \u06a9\u0627\u0644 \u0628\u06cc\u06a9\u0633 \u06a9\u0648 \u0627\u0644\u06af \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-typescript\">const enriched = {\n  ...event, runId, sequence: ++sequence,\n  timestamp: new Date().toISOString()\n};\ntry {\n  options.onEvent?.(enriched);\n} catch (error) {\n  try { options.onObserverError?.(error); }\n  catch { \/* Observer failures cannot change the run outcome. *\/ }\n}\n<\/code><\/pre>\n<p>\u0645\u0627\u0688\u0644 \u06cc\u0627 \u0679\u0648\u0644 \u0628\u0627\u0624\u0646\u0688\u0631\u06cc \u067e\u0631 \u0645\u062d\u0641\u0648\u0638 \u06a9\u0631\u06cc\u06ba\u06d4 <code>const start = performance.now()<\/code> \u067e\u06be\u0627\u0646\u0633\u06cc \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u0627\u062e\u0631\u0627\u062c <code>durationMs: performance.now() - start<\/code> \u0622\u0628 \u0648 \u06c1\u0648\u0627 \u0634\u06cc\u0626\u0631 \u06a9\u0631\u06cc\u06ba <code>finish()<\/code> \u0645\u062f\u062f\u06af\u0627\u0631 \u062e\u0627\u0631\u062c \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 <code>run_end<\/code> \u06c1\u0631 \u0679\u0631\u0645\u06cc\u0646\u0644 \u06a9\u06d2 \u0627\u067e\u0646\u06d2 \u0646\u062a\u0627\u0626\u062c \u0648\u0627\u067e\u0633 \u06a9\u0631\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u0645\u0634\u0627\u06c1\u062f\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u0628\u062a\u062f\u0627\u0626\u06cc \u0679\u0631\u0645\u06cc\u0646\u06cc\u0634\u0646 \u06a9\u0648 \u0628\u06be\u06cc \u0628\u0631\u0642\u0631\u0627\u0631 \u0631\u06a9\u06be\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<h3 id=\"heading-account-for-model-usage-without-inventing-it\">\u0645\u0627\u0688\u0644\u0632 \u06a9\u0648 \u062a\u06cc\u0627\u0631 \u06a9\u06cc\u06d2 \u0628\u063a\u06cc\u0631 \u0627\u0646 \u06a9\u06d2 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u06cc \u0648\u0636\u0627\u062d\u062a \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/h3>\n<p>\u0622\u067e \u0627\u062e\u062a\u06cc\u0627\u0631\u06cc \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0646\u0646\u062f\u06c1 \u0631\u067e\u0648\u0631\u0679\u0646\u06af \u0679\u0648\u06a9\u0646\u0632 \u06a9\u06d2 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u0645\u0627\u0688\u0644 \u06a9\u06d2 \u062c\u0648\u0627\u0628 \u06a9\u0648 \u0628\u06be\u06cc \u0628\u0691\u06be\u0627 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-typescript\">return {\n  content: 'Done',\n  usage: { inputTokens: 125, outputTokens: 20 },\n};\n<\/code><\/pre>\n<p>\u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u06cc \u0627\u0637\u0644\u0627\u0639 \u062f\u06cc \u06af\u0626\u06cc \u06af\u0646\u062a\u06cc \u06a9\u0648 \u0627\u0633 \u0637\u0631\u062d \u062c\u0645\u0639 \u06a9\u0631\u062a\u0627 \u06c1\u06d2: <code>result.usage<\/code>\u067e\u06c1\u0644\u0648 \u0628\u06c1 \u067e\u06c1\u0644\u0648 <code>modelCallsWithUsage<\/code>. \u06cc\u06c1 \u0622\u062e\u0631\u06cc \u0641\u06cc\u0644\u0688 \u0627\u06c1\u0645 \u06c1\u06d2\u06d4 0 \u0631\u067e\u0648\u0631\u0679 \u0634\u062f\u06c1 \u0679\u0648\u06a9\u0646 \u06a9\u06d2 \u0633\u0627\u062a\u06be 0 \u06a9\u06cc \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u06cc \u0631\u067e\u0648\u0631\u0679\u0646\u06af \u06a9\u0627\u0644 \u06a9\u0627 \u0645\u0637\u0644\u0628 \u06c1\u06d2: <strong>\u0646\u0627\u0645\u0639\u0644\u0648\u0645 \u0627\u0633\u062a\u0639\u0645\u0627\u0644<\/strong>\u06cc\u06c1 \u0645\u0641\u062a \u062f\u0648\u0691\u0646\u0627 \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4 \u06a9\u0644 \u06a9\u0648 \u062e\u0648\u062f \u0628\u062e\u0648\u062f \u062e\u0631\u0627\u0628 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2\u060c \u063a\u0644\u0637 \u0634\u0645\u0627\u0631 \u0645\u0633\u062a\u0631\u062f \u06a9\u0631 \u062f\u06cc\u06d2 \u062c\u0627\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u062c\u0645\u0639 \u06a9\u0631\u0646\u06d2 \u0648\u0627\u0644\u0627 \u0627\u062e\u062a\u06cc\u0627\u0631\u06cc \u0627\u0646 \u067e\u0679 \u0627\u0648\u0631 \u0622\u0624\u0679 \u067e\u0679 \u0634\u0645\u0627\u0631 \u0644\u06cc\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0627\u0646\u0641\u0631\u0627\u062f\u06cc \u0642\u062f\u0631\u0648\u06ba \u0627\u0648\u0631 \u0646\u062a\u06cc\u062c\u06d2 \u06a9\u06cc \u0631\u0642\u0645 \u062f\u0648\u0646\u0648\u06ba \u06a9\u06cc \u062a\u0635\u062f\u06cc\u0642 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-typescript\">export type Usage = { inputTokens?: number; outputTokens?: number };\nexport type UsageTotals = {\n  inputTokens: number; outputTokens: number; modelCallsWithUsage: number\n};\n\nexport function addUsage(totals: UsageTotals, usage: Usage | undefined): void {\n  if (!usage) return;\n  for (const value of [usage.inputTokens, usage.outputTokens]) {\n    if (value !== undefined && (!Number.isSafeInteger(value) || value < 0)) {\n      throw new RangeError('Model usage must contain nonnegative safe integers');\n    }\n  }\n  if (!Number.isSafeInteger(totals.inputTokens + (usage.inputTokens ?? 0)) ||\n      !Number.isSafeInteger(totals.outputTokens + (usage.outputTokens ?? 0))) {\n    throw new RangeError('Accumulated model usage exceeds safe integer range');\n  }\n  totals.inputTokens += usage.inputTokens ?? 0;\n  totals.outputTokens += usage.outputTokens ?? 0;\n  totals.modelCallsWithUsage++;\n}\n<\/code><\/pre>\n<p>\u0639\u0645\u0644 \u06a9\u06d2 \u0622\u063a\u0627\u0632 \u067e\u0631\u060c \u06c1\u0645 \u06a9\u0644 \u06a9\u0648 0 \u0633\u06d2 \u0634\u0631\u0648\u0639 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 <code>usage?: Usage<\/code> \u0645\u0627\u0688\u0644 \u062c\u0648\u0627\u0628\u06cc \u0645\u0639\u0627\u06c1\u062f\u0648\u06ba \u06a9\u0648 \u06a9\u0627\u0644 \u06a9\u0631\u06cc\u06ba\u06d4 <code>addUsage(totals, response.usage)<\/code> \u06c1\u0631 \u062c\u0648\u0627\u0628 \u06a9\u06cc \u062a\u0635\u062f\u06cc\u0642 \u06a9\u06d2 \u0628\u0639\u062f\u060c \u0646\u062a\u0627\u0626\u062c \u0645\u06cc\u06ba \u06a9\u0644 \u06a9\u06cc \u0627\u06cc\u06a9 \u06a9\u0627\u067e\u06cc \u0634\u0627\u0645\u0644 \u06a9\u0631\u06cc\u06ba\u06d4 \u0627\u06af\u0631 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u063a\u0627\u0626\u0628 \u06c1\u06d2 \u062a\u0648 \u06a9\u0627\u0624\u0646\u0679\u0631 \u062a\u0628\u062f\u06cc\u0644 \u0646\u06c1\u06cc\u06ba \u06c1\u0648\u06af\u0627\u06d4<\/p>\n<p>\u0627\u06cc\u0648\u0646\u0679 \u067e\u06d2 \u0644\u0648\u0688 \u062c\u0627\u0646 \u0628\u0648\u062c\u06be \u06a9\u0631 \u067e\u0631\u0627\u0645\u067e\u0679\u0633\u060c \u0679\u0648\u0644 \u0622\u0631\u06af\u0648\u0645\u0646\u0679\u0633 \u0627\u0648\u0631 \u0679\u0648\u0644 \u06a9\u06d2 \u0646\u062a\u0627\u0626\u062c \u06a9\u0648 \u0686\u06be\u0648\u0691 \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4 \u0627\u06cc\u06a9\u0633\u067e\u0648\u0631\u0679 \u0645\u06cc\u06ba \u0627\u062d\u062a\u06cc\u0627\u0637 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06c1\u06d2 \u06a9\u06cc\u0648\u0646\u06a9\u06c1 \u0627\u06cc\u0631\u0631 \u0633\u0679\u0631\u0646\u06af\u0632 \u0645\u06cc\u06ba \u0627\u0628 \u0628\u06be\u06cc \u062d\u0633\u0627\u0633 \u0688\u06cc\u0679\u0627 \u06c1\u0648 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u06d4 \u06cc\u06c1 \u062a\u0642\u0633\u06cc\u0645 \u0634\u062f\u06c1 \u0679\u0631\u06cc\u0633\u0646\u06af \u06cc\u0627 \u0627\u0646\u062a\u06c1\u0627\u0626\u06cc \u067e\u0627\u0626\u06cc\u062f\u0627\u0631 \u0622\u0688\u0679 \u0644\u0627\u06af \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2 \u06c1\u0644\u06a9\u0627 \u067e\u06be\u0644\u06a9\u0627\u060c \u0627\u0646 \u0645\u06cc\u0645\u0648\u0631\u06cc \u0627\u0646\u0633\u0679\u0631\u0648\u0645\u06cc\u0646\u0679\u06cc\u0634\u0646 \u06c1\u06d2\u06d4<\/p>\n<p>\u0679\u06cc\u0633\u0679 <code>tests\/events.test.ts<\/code> \u0627\u06cc\u0648\u0646\u0679 \u0622\u0631\u0688\u0631\u0646\u06af\u060c \u0627\u0631\u062a\u0628\u0627\u0637\u060c \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u0627\u06a9\u0627\u0624\u0646\u0679\u0646\u06af\u060c \u0645\u0628\u0635\u0631 \u062a\u0646\u06c1\u0627\u0626\u06cc\u060c \u0627\u0648\u0631 \u0679\u0631\u0645\u06cc\u0646\u0644 \u0648\u0627\u0642\u0639\u0627\u062a \u06a9\u0648 \u0686\u06cc\u06a9 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<h2 id=\"heading-7-test-the-failure-paths-not-just-the-happy-path\">7. \u0646\u0627\u06a9\u0627\u0645 \u0631\u0627\u0633\u062a\u0648\u06ba \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0633\u0627\u062a\u06be \u062e\u0648\u0634 \u06a9\u0646 \u0631\u0627\u0633\u062a\u0648\u06ba \u06a9\u06cc \u062c\u0627\u0646\u0686 \u06a9\u0631\u06cc\u06ba\u06d4<\/h2>\n<p>\u06c1\u0645\u0627\u0631\u06d2 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u0645\u06cc\u06ba \u0627\u0628 \u0679\u0648\u0644 \u06a9\u06cc \u062a\u0648\u062b\u06cc\u0642\u060c \u0639\u0645\u0644\u062f\u0631\u0622\u0645\u062f \u06a9\u06cc \u0631\u06a9\u0627\u0648\u0679\u06cc\u06ba\u060c \u0633\u06cc\u0627\u0642 \u0648 \u0633\u0628\u0627\u0642 \u06a9\u0627 \u0627\u0646\u062a\u0638\u0627\u0645\u060c \u0627\u0648\u0631 \u0645\u0634\u0627\u06c1\u062f\u06c1 \u06c1\u06d2\u06d4 \u062a\u0627\u06c1\u0645\u060c \u06cc\u06c1 \u0645\u06cc\u06a9\u0627\u0646\u0632\u0645 \u0628\u0627\u062a \u0686\u06cc\u062a \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba. \u0645\u0627\u0688\u0644 \u063a\u0644\u0637 \u0679\u0648\u0644 \u06a9\u0627\u0644\u0632 \u0648\u0627\u067e\u0633 \u06a9\u0631 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u060c \u0628\u06cc\u0686\u0632 \u06a9\u0648 \u0642\u0628\u0644 \u0627\u0632 \u0648\u0642\u062a \u0645\u0646\u0633\u0648\u062e \u06a9\u06cc\u0627 \u062c\u0627 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u060c \u0627\u0648\u0631 \u0645\u0633\u062a\u0631\u062f \u0634\u062f\u06c1 \u0628\u06cc\u0686\u0632 \u06af\u0641\u062a\u06af\u0648 \u06a9\u0648 \u0645\u0627\u0688\u0644 \u06a9\u0648 \u0648\u0627\u067e\u0633 \u0628\u06be\u06cc\u062c\u0646\u06d2 \u0633\u06d2 \u0642\u0627\u0635\u0631 \u0631\u06c1 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u0622\u062e\u0631\u06cc \u0633\u0646\u06af \u0645\u06cc\u0644 \u0628\u0631\u0627\u06c1 \u0631\u0627\u0633\u062a \u0627\u0646 \u062d\u062f\u0648\u062f \u06a9\u0648 \u062c\u0627\u0646\u0686\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0622\u062e\u0631\u06cc \u0633\u0646\u06af \u0645\u06cc\u0644 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0633\u0627\u062a\u06be\u06cc \u0630\u062e\u06cc\u0631\u06c1 \u06a9\u0648 \u0686\u06cc\u06a9 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-shell\">git switch --detach 07-testing\n<\/code><\/pre>\n<p>\u0646\u0626\u06d2 \u0679\u06cc\u0633\u0679 \u06c1\u0648 \u0631\u06c1\u06d2 \u06c1\u06cc\u06ba\u06d4 <code>tests\/failures.test.ts<\/code>. \u06cc\u06c1 \u067e\u06c1\u0644\u06d2 \u0633\u0646\u06af \u0645\u06cc\u0644 \u06a9\u06d2 \u0637\u0648\u0631 \u067e\u0631 \u0648\u06c1\u06cc \u0627\u0633\u06a9\u0631\u067e\u0679 \u0645\u0627\u0688\u0644 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u0644\u06c1\u0630\u0627 \u0622\u067e API \u06a9\u0644\u06cc\u062f \u06a9\u06d2 \u0628\u063a\u06cc\u0631 \u063a\u0644\u0637\u06cc \u06a9\u0648 \u062f\u0648\u0628\u0627\u0631\u06c1 \u067e\u06cc\u0634 \u06a9\u0631 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<h3 id=\"heading-validate-the-model-response-before-trusting-it\">\u0627\u0646 \u067e\u0631 \u0628\u06be\u0631\u0648\u0633\u06c1 \u06a9\u0631\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u0645\u0627\u0688\u0644 \u06a9\u06d2 \u062c\u0648\u0627\u0628\u0627\u062a \u06a9\u06cc \u062a\u0635\u062f\u06cc\u0642 \u06a9\u0631\u06cc\u06ba\u06d4<\/h3>\n<p>\u062a\u0635\u062f\u06cc\u0642 \u06a9\u0627 \u0622\u0644\u06c1 <em>\u0639\u0646\u0635\u0631<\/em> \u06cc\u06c1 \u06a9\u0627\u0641\u06cc \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4 \u0645\u0627\u0688\u0644 \u0627\u0688\u0627\u067e\u0679\u0631 \u063a\u0644\u0637 \u062c\u0648\u0627\u0628 \u062f\u06d2 \u0633\u06a9\u062a\u0627 \u06c1\u06d2: \u063a\u0627\u0626\u0628\u06d4 <code>content<\/code>\u063a\u06cc\u0631 \u0645\u0646\u0638\u0645 <code>toolCalls<\/code>\u063a\u0627\u0626\u0628 \u062f\u0644\u0627\u0626\u0644 \u06cc\u0627 \u0688\u067e\u0644\u06cc\u06a9\u06cc\u0679 \u06a9\u0627\u0644 IDs\u06d4 \u0646\u06cc\u0627 <code>validateModelResponse()<\/code> \u062c\u0648\u0627\u0628 \u06a9\u0648 \u0631\u06cc\u06a9\u0627\u0631\u0688 \u06a9\u0631\u0646\u06d2 \u06cc\u0627 \u0627\u0633 \u067e\u0631 \u0639\u0645\u0644 \u06a9\u0631\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u06c1\u0627\u0631\u0646\u0633 \u062c\u0648\u0627\u0628\u06cc \u0644\u0641\u0627\u0641\u06d2 \u06a9\u0648 \u0686\u06cc\u06a9 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-typescript\">import type { Model, ToolCall } from '.\/types.ts';\n\n\/** Validate the adapter boundary before accepting a model turn or running side effects. *\/\nexport function validateModelResponse(value: unknown): asserts value is Awaited<returntype>> {\n  if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n    throw new TypeError('Model response must be an object');\n  }\n  const response = value as Record<string unknown=\"\">;\n  if (typeof response.content !== 'string') throw new TypeError('Model response content must be a string');\n  if (response.toolCalls === undefined) return;\n  if (!Array.isArray(response.toolCalls)) throw new TypeError('Model toolCalls must be an array');\n  const ids = new Set<string>();\n  for (const call of response.toolCalls as unknown[]) {\n    if (call === null || typeof call !== 'object' || Array.isArray(call)) {\n      throw new TypeError('Tool call must be an object');\n    }\n    const item = call as Partial<toolcall>;\n    if (typeof item.id !== 'string' || !item.id.trim()) throw new TypeError('Tool call id must be a nonempty string');\n    if (typeof item.name !== 'string' || !item.name.trim()) {\n      throw new TypeError('Tool call name must be a nonempty string');\n    }\n    if (!Object.hasOwn(item, 'arguments')) throw new TypeError('Tool call arguments are missing');\n    if (ids.has(item.id)) throw new TypeError(`Duplicate tool call id: ${item.id}`);\n    ids.add(item.id);\n  }\n}\n<\/toolcall><\/string><\/string><\/returntype><\/code><\/pre>\n<p>\u06a9\u0627\u0644 <code>validateModelResponse(response)<\/code> \u067e\u06be\u0631 <code>addUsage(usage, response.usage)<\/code> \u0645\u06cc\u06ba <code>try<\/code> \u0641\u0648\u0631\u0627\u064b \u0628\u0639\u062f \u0628\u0644\u0627\u06a9 \u06a9\u0631 \u062f\u06cc\u06ba\u06d4 <code>model.generate()<\/code>\u062b\u0627\u0646\u0648\u06cc \u067e\u06cc\u063a\u0627\u0645 \u0634\u0627\u0645\u0644 \u06a9\u0631\u0646\u06d2 \u06cc\u0627 \u0679\u0648\u0644 \u0686\u0644\u0627\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2\u06d4 \u062c\u0628 \u06a9\u0648\u0626\u06cc \u0628\u06be\u06cc \u0627\u0633\u06d2 \u067e\u06be\u06cc\u0646\u06a9\u062a\u0627 \u06c1\u06d2 \u062a\u0648 \u0648\u06c1 \u0627\u0633\u06d2 \u0686\u06be\u0648\u0691 \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4 <code>model_error<\/code> \u0627\u0648\u0631 \u0648\u0627\u067e\u0633 \u0622\u0648 <code>finish('model_error', { error: message })<\/code>\u06a9\u06c1\u0627\u06ba <code>message<\/code> \u06cc\u06c1 \u0627\u06cc\u06a9 \u0627\u0633\u062a\u062b\u0646\u0627\u0626\u06cc \u067e\u06cc\u063a\u0627\u0645 \u06c1\u06d2\u06d4<\/p>\n<p>\u0627\u06cc\u06a9 \u063a\u0644\u0637 \u062c\u0648\u0627\u0628 \u0627\u0633 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u062e\u062a\u0645 \u06c1\u0648\u062a\u0627 \u06c1\u06d2: <code>model_error<\/code>\u0622\u0644\u06d2 \u06a9\u06d2 \u06a9\u0648\u0626\u06cc \u0636\u0645\u0646\u06cc \u0627\u062b\u0631\u0627\u062a \u0646\u06c1\u06cc\u06ba \u06c1\u06cc\u06ba\u06d4 \u06cc\u06c1 \u063a\u0644\u0637 \u062f\u0644\u0627\u0626\u0644 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0627\u06cc\u06a9 \u062f\u0631\u0633\u062a \u0679\u0648\u0644 \u06a9\u0627\u0644 \u0633\u06d2 \u0645\u062e\u062a\u0644\u0641 \u06c1\u06d2\u06d4 \u0645\u0624\u062e\u0631 \u0627\u0644\u0630\u06a9\u0631 \u0627\u06cc\u06a9 \u0642\u0627\u0628\u0644 \u0628\u0627\u0632\u06cc\u0627\u0641\u062a \u0679\u0648\u0644 \u06a9\u06cc \u062e\u0631\u0627\u0628\u06cc \u0628\u0646 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u060c \u062c\u0633 \u0633\u06d2 \u0645\u0627\u0688\u0644 \u06a9\u0648 \u062f\u0648\u0628\u0627\u0631\u06c1 \u06a9\u0648\u0634\u0634 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u0645\u0644\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<h3 id=\"heading-keep-rejected-batches-out-of-the-transcript\">\u0645\u0633\u062a\u0631\u062f \u0634\u062f\u06c1 \u0628\u06cc\u0686\u0648\u06ba \u06a9\u0648 \u0631\u06cc\u06a9\u0627\u0631\u0688 \u0633\u06d2 \u062e\u0627\u0631\u062c \u06a9\u0631\u06cc\u06ba\u06d4<\/h3>\n<p>\u06c1\u0645\u0627\u0631\u06cc \u062c\u0627\u0646\u0686 \u0646\u06d2 \u062d\u0642\u06cc\u0642\u06cc \u0627\u0646\u0636\u0645\u0627\u0645 \u06a9\u06cc \u062e\u0631\u0627\u0628\u06cc\u0648\u06ba \u06a9\u0648 \u0628\u06be\u06cc \u0628\u06d2 \u0646\u0642\u0627\u0628 \u06a9\u06cc\u0627\u06d4 \u0627\u0633 \u0633\u06d2 \u067e\u06c1\u0644\u06d2\u060c \u0627\u06cc\u06a9 \u0645\u0639\u0627\u0648\u0646 \u067e\u06cc\u063a\u0627\u0645 \u062c\u0633 \u0645\u06cc\u06ba \u0679\u0648\u0644 \u06a9\u0627\u0644 \u0634\u0627\u0645\u0644 \u062a\u06be\u06cc \u06c1\u0627\u0631\u0646\u0633 \u0645\u06cc\u06ba \u0634\u0627\u0645\u0644 \u06a9\u06cc \u06af\u0626\u06cc \u062a\u06be\u06cc\u06d4 <em>\u067e\u06c1\u0644\u06d2<\/em> \u0686\u06cc\u06a9 \u06a9\u0631\u06cc\u06ba \u06a9\u06c1 \u0622\u06cc\u0627 \u0628\u06cc\u0686 \u0633\u06d2 \u062a\u062c\u0627\u0648\u0632 \u06a9\u06cc\u0627 \u06af\u06cc\u0627 \u06c1\u06d2\u06d4 <code>maxToolCalls<\/code>. \u0627\u0633 \u067e\u0644\u06cc\u0633\u0645\u0646\u0679 \u06a9\u0648 \u0645\u0633\u062a\u0631\u062f \u06a9\u0631\u0646\u06d2 \u0633\u06d2 \u0622\u067e \u06a9\u06cc \u06af\u0641\u062a\u06af\u0648 \u0645\u06cc\u06ba \u0627\u06cc\u06a9 \u063a\u06cc\u0631 \u062c\u0648\u0627\u0628\u06cc \u0679\u0648\u0644 \u06a9\u0627\u0644 \u0631\u06c1 \u062c\u0627\u0626\u06d2 \u06af\u06cc\u06d4<\/p>\n<p>\u0627\u0635\u0644\u0627\u062d\u0627\u062a \u0686\u06be\u0648\u0679\u06cc \u0644\u06cc\u06a9\u0646 \u0627\u06c1\u0645 \u06c1\u06cc\u06ba\u06d4 <strong>\u062b\u0627\u0646\u0648\u06cc \u0645\u0648\u0691 \u0644\u0627\u06af \u06a9\u0631\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u0627\u067e\u0646\u0627 \u0628\u062c\u0679 \u0686\u06cc\u06a9 \u06a9\u0631\u06cc\u06ba\u06d4<\/strong>.<\/p>\n<pre><code class=\"language-typescript\">if (calls.length > maxToolCalls - toolCalls) {\n  return finish('tool_limit');\n}\nmessages.push({\n  role: 'assistant',\n  content: response.content,\n  ...(calls.length ? { toolCalls: calls } : {})\n});\n<\/code><\/pre>\n<p>\u062c\u0628 \u0631\u067e\u0648\u0631\u0679 \u06a9\u0627\u0631\u0688 \u06a9\u06cc \u0628\u0627\u062a \u0622\u062a\u06cc \u06c1\u06d2 \u062a\u0648 \u06cc\u06c1 \u0628\u062c\u0679 \u06a9\u0648 \u0645\u0633\u062a\u0631\u062f \u06a9\u0631\u0646\u06d2 \u06a9\u0648 \u062c\u0648\u06c1\u0631\u06cc \u0628\u0646\u0627 \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4 \u067e\u06c1\u0644\u06d2 \u0633\u06d2 \u0645\u0646\u0638\u0648\u0631 \u0634\u062f\u06c1 \u067e\u0644\u06cc\u0633\u0645\u0646\u0679 \u06a9\u06d2 \u062f\u0648\u0631\u0627\u0646 \u0645\u0646\u0633\u0648\u062e\u06cc \u06a9\u0627 \u0646\u062a\u06cc\u062c\u06c1 \u0627\u0628 \u0628\u06be\u06cc \u0646\u0627\u0645\u06a9\u0645\u0644 \u062d\u062a\u0645\u06cc \u0631\u06cc\u06a9\u0627\u0631\u0688 \u06a9\u06cc \u0635\u0648\u0631\u062a \u0645\u06cc\u06ba \u0646\u06a9\u0644 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u06d4 \u0627\u0646 \u0637\u0631\u06cc\u0642\u0648\u06ba \u06a9\u0648 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0634\u0631\u0648\u0639 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u06cc\u0688\u062c\u0633\u0679\u0645\u0646\u0679 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06c1\u0648\u06af\u06cc\u06d4<\/p>\n<h3 id=\"heading-use-reproducible-variation\">\u062f\u0648\u0628\u0627\u0631\u06c1 \u067e\u06cc\u062f\u0627 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0642\u0627\u0628\u0644 \u0645\u062a\u063a\u06cc\u0631\u0627\u062a \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u06cc\u06ba\u06d4<\/h3>\n<p>\u063a\u0644\u0637 \u062c\u0648\u0627\u0628\u0627\u062a\u060c \u0645\u0646\u0633\u0648\u062e\u06cc\u060c \u0627\u0648\u0631 \u0645\u0628\u0635\u0631 \u06a9\u06cc \u0646\u0627\u06a9\u0627\u0645\u06cc\u0648\u06ba \u06a9\u06d2 \u0644\u06cc\u06d2 \u06c1\u062f\u0641 \u0634\u062f\u06c1 \u0679\u06cc\u0633\u0679\u0648\u06ba \u06a9\u06d2 \u0633\u0627\u062a\u06be\u060c \u06c1\u0645 \u0686\u0644\u0627\u0626\u06cc\u06ba \u06af\u06d2: <strong>150 \u0628\u06cc\u062c \u0648\u0627\u0644\u06d2 \u0679\u0648\u0644 \u06a9\u06cc \u062a\u0639\u06cc\u0646\u0627\u062a\u06cc \u06a9\u06d2 \u0645\u0646\u0638\u0631\u0646\u0627\u0645\u06d2\u06d4<\/strong> \u0628\u06cc\u0686 \u06a9\u06d2 \u0633\u0627\u0626\u0632 \u0627\u0648\u0631 \u0628\u062c\u0679 \u0645\u062e\u062a\u0644\u0641 \u06c1\u0648\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u0627\u06cc\u06a9 \u0641\u06a9\u0633\u0688 \u0633\u06cc\u0648\u0688\u0648\u0631\u0646\u0688\u0645 \u0628\u06cc\u062c \u06c1\u0631 \u0631\u0646 \u0645\u06cc\u06ba \u0627\u06cc\u06a9 \u06c1\u06cc \u062a\u0631\u062a\u06cc\u0628 \u067e\u06cc\u062f\u0627 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u0646\u0627\u06a9\u0627\u0645\u06cc\u0648\u06ba \u06a9\u0648 \u062f\u0648\u0628\u0627\u0631\u06c1 \u067e\u06cc\u062f\u0627 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0642\u0627\u0628\u0644 \u0628\u0646\u0627\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u062f\u0631\u062c \u0630\u06cc\u0644 \u0645\u062b\u0627\u0644\u06cc\u06ba \u0627\u0633 \u0633\u06d2 \u062a\u0639\u0644\u0642 \u0631\u06a9\u06be\u062a\u06cc \u06c1\u06cc\u06ba: <code>tests\/failures.test.ts<\/code>. \u0648\u06c1 \u0645\u0646\u0627\u0633\u0628 \u0637\u0631\u06cc\u0642\u06d2 \u0633\u06d2 \u0641\u0627\u0631\u0645\u06cc\u0679 \u0634\u062f\u06c1 \u06a9\u0631\u0646\u0633\u06cc \u0628\u0646\u0627\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u06cc\u06a9 \u0646\u0648\u0646 \u0641\u0631\u06cc\u0644\u0632 \u0679\u0648\u0644 \u0627\u0648\u0631 \u0627\u06cc\u06a9 \u0645\u062f\u062f\u06af\u0627\u0631 \u06a9\u0627 \u0627\u0634\u062a\u0631\u0627\u06a9 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-typescript\">import { test } from 'node:test';\nimport assert from 'node:assert\/strict';\nimport { runAgent } from '..\/src\/core\/agent.ts';\nimport { scriptedModel } from '..\/src\/models\/fake.ts';\nimport type { Tool } from '..\/src\/core\/types.ts';\n\nconst noop: Tool = {\n  name: 'noop', description: 'Return a fixed result',\n  parameters: { type: 'object' },\n  async execute() { return 'ok'; }\n};\nconst call = (id: string) => ({ id, name: 'noop', arguments: {} });\n<\/code><\/pre>\n<p>\u067e\u06c1\u0644\u06d2 \u0679\u06cc\u0633\u0679 \u0645\u06cc\u06ba\u060c \u06c1\u0645 \u0628\u062c\u0679 \u06a9\u0648 0 \u0633\u06d2 8 \u0627\u0648\u0631 \u0628\u06cc\u0686 \u06a9\u0627 \u0633\u0627\u0626\u0632 0 \u0633\u06d2 12 \u062a\u06a9 \u062a\u0628\u062f\u06cc\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u0639\u0645\u0644 \u062f\u0631\u0622\u0645\u062f \u06a9\u06cc \u06af\u0646\u062a\u06cc\u060c \u0628\u0627\u06c1\u0631 \u0646\u06a9\u0644\u0646\u06d2 \u06a9\u06cc \u062d\u06cc\u062b\u06cc\u062a\u060c \u0627\u0648\u0631 \u0622\u06cc\u0627 \u0645\u0633\u062a\u0631\u062f \u0634\u062f\u06c1 \u06a9\u0627\u0644\u06cc\u06ba \u062a\u0627\u0631\u06cc\u062e \u0633\u06d2 \u062e\u0627\u0631\u062c \u06c1\u06cc\u06ba \u06cc\u0627 \u0646\u06c1\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-typescript\">test('seeded batches respect tool budgets', async () => {\n  let seed = 0x12345678;\n  const next = () => {\n    seed ^= seed << 13;\n    seed ^= seed >>> 17;\n    seed ^= seed << 5;\n    return seed >>> 0;\n  };\n\n  for (let i = 0; i < 150; i++) {\n    const limit = next() % 9;\n    const batch = next() % 13;\n    let executed = 0;\n    const result = await runAgent({\n      prompt: 'test', maxToolCalls: limit,\n      tools: [{\n        ...noop,\n        async execute() { executed++; return 'ok'; }\n      }],\n      model: scriptedModel([\n        {\n          content: '',\n          toolCalls: Array.from({ length: batch }, (_, j) => call(`call-${j}`))\n        },\n        { content: 'done' }\n      ])\n    });\n\n    const admitted = batch <= limit;\n    assert.equal(executed, admitted ? batch : 0, `case ${i}`);\n    assert.equal(result.toolCalls, admitted ? batch : 0, `case ${i}`);\n    assert.equal(\n      result.status, admitted ? 'completed' : 'tool_limit', `case ${i}`\n    );\n    if (!admitted) {\n      assert.deepEqual(result.messages, [{ role: 'user', content: 'test' }]);\n    }\n  }\n});\n<\/code><\/pre>\n<p>\u0627\u06cc\u06a9 \u0645\u0646\u0638\u0648\u0631 \u0634\u062f\u06c1 \u062a\u0639\u06cc\u0646\u0627\u062a\u06cc \u062a\u0645\u0627\u0645 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u0631\u062f\u06c1 \u0679\u0648\u0644\u0632 \u06a9\u0648 \u0686\u0644\u0627\u062a\u06cc \u06c1\u06d2\u060c \u062c\u0628\u06a9\u06c1 \u0632\u06cc\u0627\u062f\u06c1 \u0628\u062c\u0679 \u06a9\u06cc \u062a\u0639\u06cc\u0646\u0627\u062a\u06cc \u0635\u0641\u0631 \u067e\u0631 \u0686\u0644\u062a\u06cc \u06c1\u06d2\u06d4 \u06a9\u06c1 <code>case<\/code> \u0644\u06cc\u0628\u0644 \u062a\u06cc\u0627\u0631 \u06a9\u0631\u062f\u06c1 \u0645\u0646\u0638\u0631\u0646\u0627\u0645\u0648\u06ba \u0645\u06cc\u06ba \u0646\u0627\u06a9\u0627\u0645 \u0645\u0646\u0638\u0631\u0646\u0627\u0645\u0648\u06ba \u06a9\u06cc \u0646\u0634\u0627\u0646\u062f\u06c1\u06cc \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0627\u0646\u06c1\u06cc\u06ba \u0627\u06cc\u06a9 \u0645\u0642\u0631\u0631\u06c1 \u0628\u06cc\u062c \u06a9\u06d2 \u0633\u0627\u062a\u06be \u062f\u0648\u0628\u0627\u0631\u06c1 \u062a\u06cc\u0627\u0631 \u06a9\u0631 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0627\u06cc\u06a9 \u0627\u0636\u0627\u0641\u06cc 60 \u0631\u0646\u0632 \u0627\u0633 \u0628\u0627\u062a \u06a9\u0627 \u062a\u0639\u06cc\u0646 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u06a9\u06cc\u06d2 \u062c\u0627\u062a\u06d2 \u06c1\u06cc\u06ba \u06a9\u06c1 \u0622\u06cc\u0627 \u0679\u0648\u0644 \u06a9\u0627 \u0627\u0633\u062a\u062b\u0646\u06cc\u0670 \u0627\u06cc\u06a9 \u0642\u0627\u0628\u0644 \u0628\u0627\u0632\u06cc\u0627\u0641\u062a \u063a\u0644\u0637\u06cc \u0628\u0646\u06cc \u06c1\u0648\u0626\u06cc \u06c1\u06d2\u06d4 \u06cc\u06c1 \u0627\u06cc\u06a9 \u0645\u062e\u062a\u0644\u0641 \u063a\u0644\u0637\u06cc \u06a9\u06d2 \u067e\u06cc\u063a\u0627\u0645 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0627\u0633\u06cc \u0646\u0627\u06a9\u0627\u0645\u06cc \u06a9\u06d2 \u0631\u0627\u0633\u062a\u06d2 \u06a9\u0648 \u062f\u06c1\u0631\u0627\u062a\u0627 \u06c1\u06d2\u06d4 \u0628\u06cc\u062c \u06a9\u06cc \u062a\u0628\u062f\u06cc\u0644\u06cc \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u0646\u06c1\u06cc\u06ba \u06a9\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-typescript\">test('tool exceptions remain recoverable', async () => {\n  let executed = 0;\n  for (let i = 0; i < 60; i++) {\n    const result = await runAgent({\n      prompt: 'test',\n      tools: [{\n        ...noop,\n        async execute() {\n          executed++;\n          throw new Error(`failure ${i}`);\n        }\n      }],\n      model: scriptedModel([\n        { content: '', toolCalls: [call('1')] },\n        { content: 'recovered' }\n      ])\n    });\n    assert.equal(result.status, 'completed');\n    assert.equal(result.answer, 'recovered');\n    assert.ok(result.messages.some(message =>\n      message.role === 'tool' && message.isError &&\n      message.content === `failure ${i}`\n    ));\n  }\n  assert.equal(executed, 60);\n});\n<\/code><\/pre>\n<p>\u0628\u06cc\u062c \u06a9\u06d2 \u0645\u0646\u0638\u0631\u0646\u0627\u0645\u06d2 \u062c\u0627\u0626\u06cc\u062f\u0627\u062f \u06a9\u06d2 \u0637\u0631\u0632 \u06a9\u06d2 \u0686\u06cc\u06a9 \u06c1\u0648\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u062c\u0628\u06a9\u06c1 \u0627\u0633\u062a\u062b\u0646\u06cc\u0670 \u0679\u06cc\u0633\u0679 \u0628\u0627\u0631 \u0628\u0627\u0631 \u0645\u062e\u0635\u0648\u0635 \u0628\u062d\u0627\u0644\u06cc \u06a9\u06d2 \u0631\u0627\u0633\u062a\u0648\u06ba \u06a9\u0648 \u0686\u06cc\u06a9 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u06cc\u06c1 \u0622\u067e\u0631\u06cc\u0679\u0646\u06af \u0633\u0633\u0679\u0645 \u0633\u06cc\u0646\u0688 \u0628\u0627\u06a9\u0633\u0646\u06af \u06a9\u06cc \u062f\u0631\u0633\u062a\u06af\u06cc \u06a9\u0648 \u062b\u0627\u0628\u062a \u06cc\u0627 \u062a\u0628\u062f\u06cc\u0644 \u0646\u06c1\u06cc\u06ba \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u0644\u06cc\u06a9\u0646 \u062f\u0648\u0646\u0648\u06ba \u062c\u0633\u0645\u0627\u0646\u06cc \u0645\u0627\u0688\u0644 \u06a9\u06d2 \u0628\u063a\u06cc\u0631 \u0686\u0644\u062a\u06d2 \u06c1\u06cc\u06ba \u0627\u0648\u0631 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u06d2 \u0631\u0648\u06cc\u06d2 \u06a9\u06d2 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0642\u0627\u0628\u0644 \u062b\u0628\u0648\u062a \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u0627\u0628 \u06c1\u0645 \u0646\u06d2 \u0627\u06cc\u06a9 \u0627\u06cc\u06af\u0632\u06cc\u06a9\u06cc\u0648\u0634\u0646 \u0644\u06cc\u0626\u0631 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0627\u06cc\u06a9 \u06c1\u0627\u0631\u0646\u0633 \u0628\u0646\u0627\u06cc\u0627 \u06c1\u06d2 \u062c\u0648 \u0627\u06cc\u06a9 \u0633\u0627\u062f\u06c1 \u0645\u0627\u0688\u0644\/\u0679\u0648\u0644 \u0644\u0648\u067e \u0645\u06cc\u06ba \u062a\u0648\u062b\u06cc\u0642\u060c \u0627\u062c\u0627\u0632\u062a\u060c \u067e\u0627\u0628\u0646\u062f\u06cc\u0627\u06ba\u060c \u0633\u06cc\u0627\u0642 \u0648 \u0633\u0628\u0627\u0642 \u0627\u0648\u0631 \u0679\u06cc\u0644\u06cc \u0645\u06cc\u0679\u0631\u06cc \u06a9\u0627 \u0645\u0627\u0644\u06a9 \u06c1\u06d2\u06d4 \u0645\u0627\u0688\u0644 \u0627\u0628 \u0628\u06be\u06cc \u06a9\u0627\u0631\u0631\u0648\u0627\u0626\u06cc \u06a9\u0627 \u0645\u0634\u0648\u0631\u06c1 \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u060c \u0644\u06cc\u06a9\u0646 <strong>\u0627\u0635\u0644 \u0645\u06cc\u06ba \u06a9\u06cc\u0627 \u06c1\u0648\u062a\u0627 \u06c1\u06d2 \u0627\u0633 \u06a9\u0627 \u062a\u0639\u06cc\u0646 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u0626\u06d2 \u06a9\u0646\u0679\u0631\u0648\u0644 \u0630\u0645\u06c1 \u062f\u0627\u0631 \u06c1\u06d2\u06d4<\/strong>.<\/p>\n<p>\u062f\u0631\u062c \u0630\u06cc\u0644 \u0645\u062b\u0627\u0644 \u06a9\u0648 \u0686\u0644\u0627\u0646\u06d2 \u06a9\u06cc \u06a9\u0648\u0634\u0634 \u06a9\u0631\u06cc\u06ba: <code>npm test<\/code>. \u0631\u06cc\u067e\u0648\u0632\u0679\u0631\u06cc \u0645\u06cc\u06ba \u0645\u06a9\u0645\u0644 \u0633\u0646\u06af \u0645\u06cc\u0644 \u06a9\u06d2 \u0646\u0641\u0627\u0630 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0627\u0648\u067e\u0631 \u0628\u06cc\u0627\u0646 \u06a9\u0631\u062f\u06c1 \u062d\u062f\u0648\u062f \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u0636\u0627\u0641\u06cc \u0679\u0627\u0631\u06af\u0679 \u06a9\u06cc\u0633\u0632 \u0634\u0627\u0645\u0644 \u06c1\u06cc\u06ba\u06d4<\/p>\n<h2 id=\"heading-where-to-go-next-connect-a-real-language-model\">\u0627\u06af\u0644\u0627 \u0645\u0631\u062d\u0644\u06c1: \u0627\u0635\u0644 \u0632\u0628\u0627\u0646 \u06a9\u06d2 \u0645\u0627\u0688\u0644 \u06a9\u0648 \u062c\u0648\u0691\u0646\u0627<\/h2>\n<p>\u0627\u0633 \u067e\u0648\u0631\u06d2 \u0679\u06cc\u0648\u0679\u0648\u0631\u06cc\u0644 \u06a9\u06d2 \u062f\u0648\u0631\u0627\u0646\u060c \u06c1\u0645 \u0646\u06d2 \u0627\u0635\u0644 LLM \u06a9\u0648 \u06a9\u0627\u0644 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2 \u0627\u0633\u06a9\u0631\u067e\u0679 \u0645\u0627\u0688\u0644 \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u06cc\u0627\u06d4 \u06cc\u06c1 \u062c\u0627\u0646 \u0628\u0648\u062c\u06be \u06a9\u0631 \u06c1\u06d2\u06d4 \u062a\u0639\u06cc\u06cc\u0646\u0627\u062a\u06cc \u062c\u0648\u0627\u0628\u0627\u062a \u0622\u067e \u06a9\u0648 \u0646\u06cc\u0679 \u0648\u0631\u06a9 \u06a9\u0627\u0644\u0632\u060c API \u06a9\u06cc\u0632\u060c \u06cc\u0627 \u063a\u06cc\u0631 \u0645\u062a\u0648\u0642\u0639 \u0645\u0627\u0688\u0644 \u06a9\u06d2 \u0631\u0648\u06cc\u06d2 \u06a9\u06d2 \u0628\u063a\u06cc\u0631\u060c \u0646\u0627\u06a9\u0627\u0645\u06cc \u06a9\u06d2 \u0631\u0627\u0633\u062a\u0648\u06ba \u0633\u0645\u06cc\u062a\u060c \u0627\u067e\u0646\u06d2 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u06cc \u062c\u0627\u0646\u0686 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u062f\u06cc\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u062a\u0627\u06c1\u0645 <code>Model<\/code> \u0627\u0646\u0679\u0631\u0641\u06cc\u0633 \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0646\u0646\u062f\u06af\u0627\u0646 \u06a9\u0648 \u0642\u0627\u0628\u0644 \u062a\u0628\u0627\u062f\u0644\u06c1 \u06c1\u0648\u0646\u06d2 \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u062f\u06cc\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0688\u06cc\u0632\u0627\u0626\u0646 \u06a9\u06cc\u0627 \u06af\u06cc\u0627 \u06c1\u06d2\u06d4 OpenAI\u060c Anthropic\u060c \u06cc\u0627 \u06a9\u0633\u06cc \u062f\u0648\u0633\u0631\u06d2 \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0646\u0646\u062f\u06c1 \u06a9\u0648 \u0645\u0631\u0628\u0648\u0637 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u06cc\u062c\u0646\u0679 \u0644\u0648\u067e \u06a9\u0648 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0644\u06a9\u06be\u0646\u06d2 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4 \u0622\u067e \u06a9\u0648 \u0635\u0631\u0641 \u0627\u067e\u0646\u06d2 \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0646\u0646\u062f\u06c1 \u06a9\u06d2 API \u0627\u0648\u0631 \u0645\u0648\u062c\u0648\u062f\u06c1 \u0627\u0642\u0633\u0627\u0645 \u06a9\u0648 \u062a\u0628\u062f\u06cc\u0644 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u06cc\u06a9 \u0627\u0688\u0627\u067e\u0679\u0631 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06c1\u06d2\u06d4<\/p>\n<p>\u0645\u062b\u0627\u0644 \u06a9\u06d2 \u0637\u0648\u0631 \u067e\u0631\u060c \u0627\u06cc\u06a9 OpenAI \u0627\u0688\u0627\u067e\u0679\u0631 \u062c\u0648 Responses API \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u0627\u0633 \u0637\u0631\u062d \u0646\u0638\u0631 \u0622\u0626\u06d2 \u06af\u0627:<\/p>\n<pre><code class=\"language-typescript\">\/\/ src\/models\/openai.ts\nimport OpenAI from 'openai';\nimport type { Model } from '..\/core\/types.ts';\n\nexport function openAIModel(client: OpenAI): Model {\n  return {\n    async generate({ messages, tools, signal }) {\n      const response = await client.responses.create(\n        {\n          model: 'YOUR_MODEL',\n          input: toOpenAIInput(messages),\n          tools: toOpenAITools(tools),\n        },\n        { signal }\n      );\n\n      return {\n        content: extractText(response),\n        toolCalls: extractToolCalls(response),\n        usage: extractUsage(response),\n      };\n    },\n  };\n}\n<\/code><\/pre>\n<p>\u06cc\u06c1 \u0627\u06cc\u06a9 \u0622\u0631\u06a9\u06cc\u0679\u06cc\u06a9\u0686\u0631\u0644 \u062e\u0627\u06a9\u06c1 \u06c1\u06d2\u060c \u0645\u06a9\u0645\u0644 \u0627\u0688\u0627\u067e\u0679\u0631 \u0646\u06c1\u06cc\u06ba\u06d4 \u062a\u0628\u0627\u062f\u0644\u0648\u06ba \u06a9\u0627 \u0641\u0646\u06a9\u0634\u0646 \u067e\u06cc\u063a\u0627\u0645\u0627\u062a \u0627\u0648\u0631 \u0679\u0648\u0644 \u06a9\u06cc \u062a\u0639\u0631\u06cc\u0641\u0648\u06ba \u06a9\u0648 \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0646\u0646\u062f\u06c1 \u06a9\u06cc \u0634\u06a9\u0644 \u0645\u06cc\u06ba \u062a\u0628\u062f\u06cc\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u067e\u06be\u0631 \u062c\u0648\u0627\u0628 \u06a9\u0648 \u0645\u0639\u0645\u0648\u0644 \u0628\u0646\u0627\u062a\u0627 \u06c1\u06d2\u06d4 \u062e\u0627\u0635 \u0637\u0648\u0631 \u067e\u0631\u060c \u0627\u0633\u06d2 \u0679\u0648\u0644 \u06a9\u0627\u0644 \u0622\u0626\u06cc \u0688\u06cc\u0632\u060c \u067e\u0627\u0631\u0633 \u0679\u0648\u0644 \u0622\u0631\u06af\u06cc\u0648\u0645\u06cc\u0646\u0679\u0633\u060c \u0627\u0648\u0631 \u0628\u0639\u062f \u0645\u06cc\u06ba \u0622\u0646\u06d2 \u0648\u0627\u0644\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a\u0648\u06ba \u0645\u06cc\u06ba \u0635\u062d\u06cc\u062d \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0679\u0648\u0644 \u06a9\u06d2 \u0646\u062a\u0627\u0626\u062c \u06a9\u0648 \u0645\u0646\u0633\u0644\u06a9 \u06a9\u0631\u0646\u0627 \u0686\u0627\u06c1\u06cc\u06d2\u06d4<\/p>\n<p>\u0627\u0688\u0627\u067e\u0679\u0631 \u06c1\u0627\u0631\u0646\u0633 \u0633\u06d2 \u0633\u06af\u0646\u0644 \u0628\u06be\u06cc \u0644\u06d2 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4 <code>AbortSignal<\/code>\u0645\u0646\u0633\u0648\u062e\u06cc \u06a9\u0648 API \u06a9\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a\u0648\u06ba \u067e\u0631 \u067e\u06be\u06cc\u0644\u0627\u0646\u06d2 \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u062f\u06cc\u06ba\u06d4 \u0633\u067e\u0644\u0627\u0626\u0631 \u06a9\u06cc \u063a\u0644\u0637\u06cc\u0627\u06ba \u0627\u06cc\u06a9 \u0645\u0633\u062a\u062b\u0646\u06cc\u0670 \u06c1\u06cc\u06ba\u060c \u062c\u0633\u06d2 Harness \u067e\u06c1\u0644\u06d2 \u0633\u06d2 \u06c1\u06cc \u0645\u0646\u062f\u0631\u062c\u06c1 \u0630\u06cc\u0644 \u0637\u0648\u0631 \u067e\u0631 \u0633\u0646\u0628\u06be\u0627\u0644\u062a\u0627 \u06c1\u06d2: <code>model_error<\/code> \u0646\u062a\u06cc\u062c\u06c1<\/p>\n<p>\u0627\u06cc\u06a9 \u0628\u0627\u0631 \u062c\u0628 \u0627\u0688\u0627\u067e\u0679\u0631 \u0644\u0627\u06af\u0648 \u06c1\u0648\u062a\u0627 \u06c1\u06d2\u06d4 <code>Model<\/code>\u0628\u0627\u0642\u06cc \u0646\u0638\u0627\u0645 \u0628\u062f\u0633\u062a\u0648\u0631 \u0628\u0631\u0642\u0631\u0627\u0631 \u06c1\u06d2\u06d4 \u0627\u0633 \u0633\u06d2 \u0642\u0637\u0639 \u0646\u0638\u0631 \u06a9\u06c1 \u06a9\u0648\u0646 \u0633\u0627 \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0646\u0646\u062f\u06c1 \u0627\u06af\u0644\u0627 \u062c\u0648\u0627\u0628 \u067e\u06cc\u0634 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u0648\u06c1\u06cc \u0679\u0648\u0644 \u0631\u062c\u0633\u0679\u0631\u06cc\u060c \u062f\u0644\u06cc\u0644 \u06a9\u06cc \u062a\u0648\u062b\u06cc\u0642\u060c \u0639\u0645\u0644\u062f\u0631\u0622\u0645\u062f \u0628\u062c\u0679\u060c \u0633\u06cc\u0627\u0642 \u0648 \u0633\u0628\u0627\u0642 \u06a9\u0627 \u0627\u0646\u062a\u0638\u0627\u0645\u060c \u0627\u0648\u0631 \u0645\u0634\u0627\u06c1\u062f\u06c1 \u0642\u0627\u0628\u0644 \u0639\u0645\u0644 \u06c1\u06d2\u06d4<\/p>\n<p>\u0627\u06cc\u06a9\u0633\u067e\u0644\u0648\u0631 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0642\u0627\u0628\u0644 \u0627\u0636\u0627\u0641\u06cc \u0628\u06c1\u062a\u0631\u06cc\u0648\u06ba \u0645\u06cc\u06ba \u0641\u06cc \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0646\u0646\u062f\u06c1 \u0679\u0648\u06a9\u0646 \u0627\u06a9\u0627\u0624\u0646\u0679\u0646\u06af\u060c API \u06a9\u06cc \u062f\u0648\u0628\u0627\u0631\u06c1 \u06a9\u0648\u0634\u0634 \u0627\u0648\u0631 \u0634\u0631\u062d \u06a9\u0648 \u0645\u062d\u062f\u0648\u062f \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u06c1\u06cc\u0646\u0688\u0644\u0646\u06af\u060c \u0628\u0627\u062a \u0686\u06cc\u062a \u06a9\u0627 \u0645\u0633\u062a\u0642\u0644 \u0644\u0627\u06af\u0646\u06af\u060c \u0627\u0648\u0631 \u0646\u0627\u0642\u0627\u0628\u0644 \u0627\u0639\u062a\u0645\u0627\u062f \u06a9\u0648\u0688 \u067e\u0631 \u0639\u0645\u0644 \u062f\u0631\u0622\u0645\u062f \u06a9\u06d2 \u0644\u06cc\u06d2 \u0645\u0636\u0628\u0648\u0637 \u0639\u0645\u0644 \u062a\u0646\u06c1\u0627\u0626\u06cc \u0634\u0627\u0645\u0644 \u06c1\u06cc\u06ba\u06d4 \u06cc\u06c1 \u0627\u067e\u0646\u06d2 \u0622\u067e \u0645\u06cc\u06ba \u0627\u06cc\u06a9 \u0627\u06c1\u0645 \u0627\u0646\u062c\u06cc\u0646\u0626\u0631\u0646\u06af \u0686\u06cc\u0644\u0646\u062c \u06c1\u06d2\u060c \u0644\u06cc\u06a9\u0646 \u06cc\u06c1 \u0645\u062e\u062a\u0644\u0641 \u0641\u0646 \u062a\u0639\u0645\u06cc\u0631 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2 \u06c1\u0645\u0627\u0631\u06cc \u0645\u0642\u0631\u0631 \u06a9\u0631\u062f\u06c1 \u062d\u062f\u0648\u062f \u0645\u06cc\u06ba \u0641\u0679 \u0628\u06cc\u0679\u06be\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0645\u06a9\u0645\u0644 \u0646\u0641\u0627\u0630 \u06cc\u06c1\u0627\u06ba \u067e\u0627\u06cc\u0627 \u062c\u0627 \u0633\u06a9\u062a\u0627 \u06c1\u06d2: <code>07-testing<\/code> \u0627\u06c1\u0645 \u0642\u062f\u0645\u06d4<\/p>\n<p>\u06c1\u0645 \u0646\u06d2 \u0635\u0631\u0641 \u0627\u06cc\u06a9 \u0644\u0648\u067e \u0633\u06d2 \u0632\u06cc\u0627\u062f\u06c1 \u0628\u0646\u0627\u06cc\u0627 \u06c1\u06d2 \u062c\u0648 \u0645\u0627\u0688\u0644 \u06a9\u0648 \u067e\u0631\u0627\u0645\u067e\u0679 \u0628\u06be\u06cc\u062c\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0627\u0641\u0639\u0627\u0644 \u06a9\u0648 \u0627\u0646\u062c\u0627\u0645 \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4 \u06c1\u0645 \u0646\u06d2 \u0627\u06cc\u06a9 \u0645\u0634\u06cc\u0646 \u0628\u0646\u0627\u0626\u06cc \u06c1\u06d2 \u062c\u0648 \u0641\u06cc\u0635\u0644\u06d2 \u06a9\u0631\u062a\u06cc \u06c1\u06d2\u06d4 <strong>\u06a9\u0646 \u06a9\u0627\u0631\u0631\u0648\u0627\u0626\u06cc\u0648\u06ba \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u06c1\u06d2\u060c \u06a9\u062a\u0646\u0627 \u06a9\u0627\u0645 \u06c1\u0648 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u060c \u0645\u0627\u0688\u0644 \u06a9\u0648 \u06a9\u0648\u0646 \u0633\u0627 \u0633\u06cc\u0627\u0642 \u0648 \u0633\u0628\u0627\u0642 \u0645\u0644\u062a\u0627 \u06c1\u06d2\u060c \u0627\u0648\u0631 \u063a\u0644\u0637\u06cc\u0648\u06ba \u06a9\u0648 \u06a9\u06cc\u0633\u06d2 \u06c1\u06cc\u0646\u0688\u0644 \u0627\u0648\u0631 \u0645\u0634\u0627\u06c1\u062f\u06c1 \u06a9\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4<\/strong>.<\/p>\n<p>\u06cc\u06c1 \u0679\u0648\u0644\u0632 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0644\u06cc\u0646\u06af\u0648\u06cc\u062c \u0645\u0627\u0688\u0644 \u0627\u0648\u0631 \u0627\u06cc\u062c\u0646\u0679 \u06a9\u06d2 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u06d2 \u062f\u0631\u0645\u06cc\u0627\u0646 \u0636\u0631\u0648\u0631\u06cc \u0641\u0631\u0642 \u06c1\u06d2\u06d4<\/p>\n<\/p><\/div>\n","protected":false},"excerpt":{"rendered":"<p>\u0628\u06c1\u062a \u0633\u06d2 AI \u0627\u06cc\u062c\u0646\u0679 \u0679\u06cc\u0648\u0679\u0648\u0631\u06cc\u0644 \u0632\u0628\u0627\u0646 \u06a9\u06d2 \u0645\u0627\u0688\u0644 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0634\u0631\u0648\u0639 \u06c1\u0648\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u0627\u0633\u06d2 \u06a9\u0686\u06be \u0679\u0648\u0644\u0632 \u062f\u06cc\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u0627\u0648\u0631 \u0627\u0633 \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u0627\u0633 \u0648\u0642\u062a \u062a\u06a9 \u0644\u0648\u067e \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba \u062c\u0628 \u062a\u06a9 \u06a9\u06c1 \u06cc\u06c1 \u062c\u0648\u0627\u0628 \u0646\u06c1\u06cc\u06ba \u0628\u0646\u0627\u062a\u0627\u06d4 \u0679\u0648\u0644 \u06a9\u0627\u0644 \u06a9\u0648 \u0638\u0627\u06c1\u0631 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u06cc\u06c1 \u06a9\u0627\u0641\u06cc \u06c1\u06d2\u060c \u0644\u06cc\u06a9\u0646 \u0627\u0646\u062c\u06cc\u0646\u0626\u0631\u0646\u06af \u06a9\u06d2 \u062f\u0644\u0686\u0633\u067e \u0633\u0648\u0627\u0644\u0627\u062a \u06a9\u06d2 \u062c\u0648\u0627\u0628\u0627\u062a \u0628\u0627\u0642\u06cc \u06c1\u06cc\u06ba\u06d4 \u0627\u06af\u0631 [&hellip;]<\/p>\n","protected":false},"author":7,"featured_media":31142,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[1],"tags":[],"class_list":["post-31141","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog"],"_links":{"self":[{"href":"https:\/\/umang.pk\/en_us\/wp-json\/wp\/v2\/posts\/31141","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/umang.pk\/en_us\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/umang.pk\/en_us\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/umang.pk\/en_us\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"https:\/\/umang.pk\/en_us\/wp-json\/wp\/v2\/comments?post=31141"}],"version-history":[{"count":1,"href":"https:\/\/umang.pk\/en_us\/wp-json\/wp\/v2\/posts\/31141\/revisions"}],"predecessor-version":[{"id":31143,"href":"https:\/\/umang.pk\/en_us\/wp-json\/wp\/v2\/posts\/31141\/revisions\/31143"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/umang.pk\/en_us\/wp-json\/wp\/v2\/media\/31142"}],"wp:attachment":[{"href":"https:\/\/umang.pk\/en_us\/wp-json\/wp\/v2\/media?parent=31141"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/umang.pk\/en_us\/wp-json\/wp\/v2\/categories?post=31141"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/umang.pk\/en_us\/wp-json\/wp\/v2\/tags?post=31141"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}