# Claude Agent SDK

> Claude Agent SDK (Python ও TypeScript) দিয়ে বানানো agent Tokens-এ চালান: ANTHROPIC_BASE_URL আর Tokens key সেট করা, model ID বাছা, opus, sonnet ও haiku alias সামলানো, streaming আর tool যোগ করা।

Claude Agent SDK হলো Anthropic-এর library, যা দিয়ে Claude Code-এর agent loop আপনার নিজের Python বা TypeScript program-এর ভেতরে চালানো যায়। ফাইল পড়া-বদলানো আর command চালানোর built-in tool, permission, session, subagent আর MCP, সবই এতে আছে। এটা শুধু পাতলা API client নয়। SDK একটা Claude Code process চালু করে তার সাথে কথা বলে, আর সেই process Anthropic Messages request পাঠায় `ANTHROPIC_BASE_URL` যেখানে বলে সেখানে। এটাকে `https://tokens.bd`-এ তাক করলে request গিয়ে পৌঁছায় Tokens-এর [/v1/messages](/docs/messages) endpoint-এ। শুধু একটা model ডাকতে চাইলে [Anthropic SDK](/docs/anthropic-sdk) ছোট আর সহজ পথ।

:::note[Documentation-এর সাথে মিলিয়ে দেখা]
এই গাইড code.claude.com-এর Claude Agent SDK documentation থেকে নেওয়া। October 2026-এ মিলিয়ে দেখা হয়েছে Python-এর `claude-agent-sdk` 0.2.165 আর TypeScript-এর `@anthropic-ai/claude-agent-sdk` 0.3.296-এর সাথে। code-টা documentation-এর সাথে মিলিয়ে দেখা হয়েছে, Tokens-এর বিরুদ্ধে শুরু থেকে শেষ পর্যন্ত চালিয়ে দেখা হয়নি।
:::

:::warning[Claude-ছাড়া অন্য model-এ যথাসাধ্য চেষ্টা]
Anthropic-এর gateway documentation বলছে, তারা "doesn't support routing Claude Code to non-Claude models through any gateway"। Agent SDK চালায় Claude Code-এরই agent, তাই একই কথা এখানেও খাটে। Model tool call ভালো সামলালে এটা চলে, আর সেটা model ধরে ধরে আলাদা। লম্বা run-এ agent দিশা হারালে SDK debug করার আগে model বদলে দেখুন। [Claude Code](/docs/claude-code) পেজেও একই সতর্কতা আছে।
:::

## যা যা লাগবে

- [API keys](/docs/api-keys) থেকে নেওয়া একটা Tokens key, যেটা `TOKENS_API_KEY` নামে export করা।
- [/models](/models) থেকে একটা model ID, যেমন `deepseek/deepseek-v4.1-flash`, যেটা tool calling সাপোর্ট করে ([Choosing a model](/docs/choosing-a-model))।
- Python 3.10 বা তার পরের version, অথবা Node.js 18 বা তার পরের। দুটো package-ই native Claude Code binary সাথে নিয়ে আসে, তাই বেশিরভাগ install-এ আলাদা করে Claude Code install করতে হয় না। কয়েকটা ক্ষেত্রে করতে হয়: pip-এর source install (যেমন Windows on ARM-এ), অথবা optional dependency বাদ দেওয়া npm install (`npm ci --omit=optional`)। তখন Claude Code native-ভাবে install করুন ([Claude Code](/docs/claude-code)), আর TypeScript-এ `pathToClaudeCodeExecutable` সেট করুন।

```bash
export TOKENS_API_KEY="tok_live_your_key"
```

## SDK কীভাবে Tokens-এ পৌঁছায়

SDK-র নিজের কোনো gateway option নেই। Anthropic-এর documentation অনুযায়ী সে যে Claude Code process চালু করে, তাকে environment variable পাস করে দেয়, আর এর জন্য প্রতিটা SDK-তে একটা `env` option আছে। আপনাকে তিনটে জিনিস সেট করতে হবে:

| Setting                                          | মান                                                                                                         |
| ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------- |
| `ANTHROPIC_BASE_URL`                             | `https://tokens.bd`, `/v1` ছাড়া। Process নিজেই `/v1/messages` জুড়ে নেয়।                               |
| `ANTHROPIC_AUTH_TOKEN`                           | আপনার Tokens key। এটা `Authorization: Bearer` হিসেবে যায়, Tokens সেটা মেনে নেয়।                             |
| Model (`model` option আর alias variable-গুলো) | `deepseek/deepseek-v4.1-flash`-এর মতো একটা Tokens model ID, `sonnet` বা `opus` নয়। পরের অংশটা দেখুন।                    |

`ANTHROPIC_API_KEY`-ও চলে (এটা যায় `x-api-key` হিসেবে)। তবে দুটোর মধ্যে একটাই সেট করুন। এই পেজে `ANTHROPIC_AUTH_TOKEN` নেওয়া হয়েছে, [Claude Code](/docs/claude-code)-এর মতোই।

দুই SDK `env`-কে আলাদাভাবে সামলায়, আর এই তফাতটা গুরুত্বপূর্ণ:

- **TypeScript।** Process default-ভাবে আপনার environment পায়, কিন্তু `options.env` সেট করলে সেটা পুরো environment-কে বদলে দেয়। তাই `process.env` ছড়িয়ে (spread করে) দিন, নইলে process `PATH` সহ সবকিছু হারাবে।
- **Python।** `ClaudeAgentOptions(env=...)` থাকা environment-এর ওপরে মিশে (merge হয়ে) যায়।

SDK `.env` file পড়ে না। SDK চালু করার আগে সেগুলো নিজে load করুন, যেমন `dotenv` দিয়ে।

## Model ID বাছুন আর alias ঠিক করুন

`model` option নেয় "a Claude model alias or full model name" (Python-এ `ClaudeAgentOptions.model`, TypeScript-এ `options.model`)। Tokens model ID দিলে process সেটা Tokens-এ যেমন লেখা তেমনই পাঠায়।

ঝামেলাটা alias নিয়ে। Anthropic-এর model documentation বলছে, `sonnet`, `opus` আর `haiku` আপনার provider-এর সবচেয়ে নতুন Claude model-এ গিয়ে মেলে, আর `ANTHROPIC_BASE_URL` "changes where requests are sent, not which model answers them"। তাই Tokens-এ alias না বদলালে সেটা এখনও একটা Claude model-এর নামেই গিয়ে দাঁড়ায়, আর সেই model Tokens দেয় কিনা তার ঠিক নেই। আপনি না বললেও agent-এর কিছু অংশ alias ব্যবহার করে:

| কী                                                                  | কোন model নেয়                                                                                      |
| ------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| আপনার main loop                                                     | `model` option                                                                                      |
| ব্যাকগ্রাউন্ডের কাজ, যেমন session-এর নাম বসানো                         | `haiku` alias, অথবা সেট করা থাকলে `ANTHROPIC_DEFAULT_HAIKU_MODEL`                                   |
| আপনি বা কোনো subagent definition `sonnet`, `opus` ও `haiku` লিখলে | `ANTHROPIC_DEFAULT_SONNET_MODEL`, `ANTHROPIC_DEFAULT_OPUS_MODEL`, `ANTHROPIC_DEFAULT_HAIKU_MODEL` |
| নিজের কোনো model নেই এমন subagent                                     | `CLAUDE_CODE_SUBAGENT_MODEL`                                                                        |

সবগুলোতে একই Tokens ID বসিয়ে দিন, [Claude Code পেজ](/docs/claude-code) যেমন করে। তাহলে agent-এর কোনো অংশ এমন model চাইবে না যা Tokens-এ নেই। প্রতিটা variable-এ পুরো model ID দিতে হবে। ID copy করুন [/models](/models) থেকে বা `GET https://tokens.bd/v1/models` থেকে।

SDK একই process চালায় বলে Claude Code পেজের আরও দুটো variable এখানেও খাটে:

- `CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1` request থেকে Claude-only beta field-এর বেশিরভাগ সরিয়ে দেয়। এতে non-Claude model থেকে `400` error আসা ঠেকে।
- `CLAUDE_CODE_MAX_CONTEXT_TOKENS` Claude Code-কে model-এর আসল context window জানায়। চেনে না এমন ID-র জন্য সে ধরে নেয় 200K token, তাই ছোট window-র model compact না করে "prompt too long" দিয়ে ফেল করে। সংখ্যাটা নিন [/models](/models)-এ model-এর পেজ থেকে।

## Python: ছোট একটা agent

```bash
pip install --upgrade claude-agent-sdk
```

```python title="agent.py"
import asyncio
import os

from claude_agent_sdk import AssistantMessage, ClaudeAgentOptions, ResultMessage, query

MODEL = "deepseek/deepseek-v4.1-flash"

ENV = {
    "ANTHROPIC_BASE_URL": "https://tokens.bd",
    "ANTHROPIC_AUTH_TOKEN": os.environ["TOKENS_API_KEY"],
    "ANTHROPIC_DEFAULT_OPUS_MODEL": MODEL,
    "ANTHROPIC_DEFAULT_SONNET_MODEL": MODEL,
    "ANTHROPIC_DEFAULT_HAIKU_MODEL": MODEL,
    "CLAUDE_CODE_SUBAGENT_MODEL": MODEL,
    "CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS": "1",
}

options = ClaudeAgentOptions(
    model=MODEL,
    allowed_tools=["Read", "Glob", "Grep"],  # read-only tools, approved automatically
    max_turns=8,
    setting_sources=[],  # ignore ~/.claude/settings.json, see the note below
    env=ENV,
)


async def main() -> None:
    async for message in query(
        prompt="List the Python files in this folder and say in one sentence what each one does.",
        options=options,
    ):
        if isinstance(message, AssistantMessage):
            for block in message.content:
                if hasattr(block, "text"):
                    print(block.text)
                elif hasattr(block, "name"):
                    print(f"[tool: {block.name}]")
        elif isinstance(message, ResultMessage):
            print(f"Done: {message.subtype}, {message.num_turns} turns")


asyncio.run(main())
```

`query()` একটা async iterator ফেরত দেয়। প্রতিটা item একটা message: model-এর text, tool call, tool result, আর সবশেষে একটা `ResultMessage`। `allowed_tools` শুধু জিজ্ঞেস না করেই tool-গুলোকে অনুমতি দেয়। বাকি tool সরিয়ে দেয় না। কোনো tool সরাতে চাইলে `disallowed_tools` ব্যবহার করুন।

:::note[Settings file আপনার variable উল্টে দিতে পারে]
Claude Code `~/.claude/settings.json` আর project settings পড়ে। Anthropic-এর documentation বলছে, shell-এ export করা আর settings file-এর `env` block-এ একই variable থাকলে settings file-এর মানই জেতে। আপনি একই মেশিনে আগে [Claude Code](/docs/claude-code) setup করে রাখলে ওই file-এর base URL, key বা model আপনার agent-এও খাটবে। `setting_sources=[]` (Python) ওই file-গুলো এড়িয়ে যায়। এর মানে agent `CLAUDE.md`, skill বা project settings-ও load করবে না। ওগুলো চাইলে লাইনটা বাদ দিন।
:::

## TypeScript: ছোট একটা agent

```bash
npm install @anthropic-ai/claude-agent-sdk
npm install --save-dev tsx
```

`package.json`-এ `"type": "module"` দিন যাতে top-level `await` চলে, অথবা file-টার নাম রাখুন `agent.mts`।

```ts title="agent.ts"
import { query } from "@anthropic-ai/claude-agent-sdk";

const model = "deepseek/deepseek-v4.1-flash";

const env = {
  ...process.env, // required: setting env replaces the whole environment
  ANTHROPIC_BASE_URL: "https://tokens.bd",
  ANTHROPIC_AUTH_TOKEN: process.env.TOKENS_API_KEY,
  ANTHROPIC_DEFAULT_OPUS_MODEL: model,
  ANTHROPIC_DEFAULT_SONNET_MODEL: model,
  ANTHROPIC_DEFAULT_HAIKU_MODEL: model,
  CLAUDE_CODE_SUBAGENT_MODEL: model,
  CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS: "1",
};

for await (const message of query({
  prompt: "List the TypeScript files in this folder and say in one sentence what each one does.",
  options: {
    model,
    allowedTools: ["Read", "Glob", "Grep"], // read-only tools, approved automatically
    maxTurns: 8,
    settingSources: [], // ignore ~/.claude/settings.json
    env,
  },
})) {
  if (message.type === "assistant" && message.message?.content) {
    for (const block of message.message.content) {
      if ("text" in block) console.log(block.text);
      else if ("name" in block) console.log(`[tool: ${block.name}]`);
    }
  } else if (message.type === "result") {
    console.log(`Done: ${message.subtype}`);
  }
}
```

```bash
npx tsx agent.ts
```

Code-এ `env` পাস করতে না চাইলে একই variable-গুলো যে shell-এ program চালান সেখানে export করুন। TypeScript-এ process সেগুলো পেয়ে যায়। Python-এও সেগুলো পৌঁছায়, কারণ `env` থাকা environment-এর ওপরে merge হয়।

## Output stream করুন

Default-ভাবে SDK model একটা text block বা tool call শেষ করলে তবেই পুরোটা একসাথে দেয়। Token ধরে ধরে text পেতে partial message চালু করুন। তখন SDK আরও দেয় Messages API-র raw stream event, আর আপনি সেখান থেকে text delta পড়েন।

:::code-tabs

```python title="Python"
from claude_agent_sdk import ClaudeAgentOptions, query
from claude_agent_sdk.types import StreamEvent

# MODEL and ENV are defined in the minimal program above
options = ClaudeAgentOptions(
    model=MODEL,
    include_partial_messages=True,
    setting_sources=[],
    env=ENV,
)


async def stream() -> None:
    async for message in query(
        prompt="Explain optimistic locking in two sentences.", options=options
    ):
        if isinstance(message, StreamEvent):
            event = message.event
            if event.get("type") == "content_block_delta":
                delta = event.get("delta", {})
                if delta.get("type") == "text_delta":
                    print(delta.get("text", ""), end="", flush=True)
```

```ts title="TypeScript"
// model and env are defined in the minimal program above
for await (const message of query({
  prompt: "Explain optimistic locking in two sentences.",
  options: { model, includePartialMessages: true, settingSources: [], env },
})) {
  if (message.type === "stream_event") {
    const event = message.event;
    if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
      process.stdout.write(event.delta.text);
    }
  }
}
```

:::

Event-গুলোর গড়ন Anthropic streaming-এর মতো, যা Tokens যেকোনো model-এর জন্যই বানিয়ে দেয় ([Messages](/docs/messages), [Streaming](/docs/streaming))। Stream event শুধু main agent-এর। Subagent-এর token delta এখানে আসে না।

## নিজের tool যোগ করুন

Built-in tool ছাড়াও নিজের code-এর function agent-কে দেওয়া যায়, in-process MCP server হিসেবে। Python-এ এটা বানায় `@tool` আর `create_sdk_mcp_server`। TypeScript-এ বানায় `tool` আর `createSdkMcpServer`, Zod schema-সহ।

:::code-tabs

```python title="Python"
from typing import Any

from claude_agent_sdk import ClaudeAgentOptions, create_sdk_mcp_server, tool


@tool("get_weather", "Current weather for a city", {"city": str})
async def get_weather(args: dict[str, Any]) -> dict[str, Any]:
    return {"content": [{"type": "text", "text": f"{args['city']}: light rain, 29C"}]}


weather = create_sdk_mcp_server(name="weather", version="1.0.0", tools=[get_weather])

# MODEL and ENV are defined in the minimal program above
options = ClaudeAgentOptions(
    model=MODEL,
    mcp_servers={"weather": weather},
    allowed_tools=["mcp__weather__get_weather"],  # MCP tools are named mcp__<server>__<tool>
    max_turns=5,
    setting_sources=[],
    env=ENV,
)
```

```ts title="TypeScript"
import { createSdkMcpServer, query, tool } from "@anthropic-ai/claude-agent-sdk";
import { z } from "zod";

const getWeather = tool(
  "get_weather",
  "Current weather for a city",
  { city: z.string() },
  async ({ city }) => ({
    content: [{ type: "text", text: `${city}: light rain, 29C` }],
  }),
);

const weather = createSdkMcpServer({ name: "weather", version: "1.0.0", tools: [getWeather] });

// model and env are defined in the minimal program above
const options = {
  model,
  mcpServers: { weather },
  allowedTools: ["mcp__weather__get_weather"],
  maxTurns: 5,
  settingSources: [],
  env,
};
```

:::

`options` নিয়ে `query()`-তে দিন, ছোট উদাহরণগুলোর মতোই। TypeScript package-এর peer dependency হিসেবে `zod` 4 লাগে। প্রতিটা tool round মানে আরেকটা `/v1/messages` request, তাই একটা agent run-এ কয়েকটা request খরচ হয় আর সেগুলো আপনার [rate limits](/docs/rate-limits)-এর হিসাবে পড়ে। Non-Claude model-এর জন্য tool call কীভাবে সামলানো হয়, তা দেখুন [Tool calling](/docs/tool-calling)-এ।

## ঠিকমতো চলছে কিনা দেখুন

প্রথমে SDK ছাড়াই endpoint আর model ID test করুন (macOS, Linux, WSL বা Git Bash-এ):

```bash
curl -sS -w '\n%{http_code}\n' -X POST "https://tokens.bd/v1/messages" \
  -H "Authorization: Bearer $TOKENS_API_KEY" \
  -H "anthropic-version: 2023-06-01" -H "content-type: application/json" \
  -d '{"model": "deepseek/deepseek-v4.1-flash", "max_tokens": 1, "messages": [{"role": "user", "content": "."}]}'
```

`200` এলে বুঝবেন key আর model ঠিক আছে। এরপর ছোট program-টা চালান। আপনি দেখবেন কোন কোন tool ডাকা হলো, model-এর উত্তর, আর `Done: success`। Request-গুলো [Dashboard](/dashboard)-এর Usage analytics-এও দেখা যায়, আপনার সেট করা model ID-র নিচে। Log-এ অন্য কোনো model দেখালে বুঝবেন alias variable-এর একটা সেট করা হয়নি।

`ResultMessage`-এ `total_cost_usd` নামে একটা field আছে। ওটা SDK-র নিজের আন্দাজ, Tokens যা bill করে তা নয়। আসল হিসাব পাবেন Tokens-এর [usage page আর `GET /v1/tokens/usage`](/docs/models-and-usage)-এ।

## Model বাছাই

Agent loop নির্ভর করে tool call, লম্বা context আর system prompt মেনে চলার ওপর। এসবে model-এ model-এ বিস্তর তফাত। কোনগুলো agent-এর কাজে মানায়, তা [Choosing a model](/docs/choosing-a-model)-এ আছে। `fallback_model` (Python) বা `fallbackModel` (TypeScript) দিতে হলে অন্য একটা Tokens ID-ই দিন, কখনো Claude-এর নাম নয়। `max_turns` কম রাখা আর key-তে মাসিক spend cap বসানো ([API keys](/docs/api-keys)) থাকলে loop বেসামাল হলেও ক্ষতি সীমিত থাকে।

## সীমাবদ্ধতা আর যা চলে না

- **শুধু Claude-এর feature।** Fast mode সরাসরি Anthropic-এর API-তে গিয়ে যাচাই করে, তাই Tokens দিয়ে চলে না। Gateway credential সেট থাকলে Remote Control আর voice dictation বন্ধ থাকে। Extended thinking আর prompt caching চলে শুধু তখনই, যখন Tokens ID-র পেছনের model সেগুলো সাপোর্ট করে ([Reasoning](/docs/reasoning), [Prompt caching](/docs/prompt-caching))।
- **Claude Code-এর নিজের model picker।** `/model` picker interactive CLI-র জিনিস। SDK-তে model ঠিক করতে হয় options-এ।
- **Anthropic-এর server-side tool।** Hosted web search-এর মতো যে tool Anthropic-এর নিজের দিকে চলে, gateway-র জন্য সেগুলোর কথা documentation-এ নেই, আর non-Claude model-এর ক্ষেত্রেও Anthropic সেগুলো documentation-এ রাখেনি। ভরসা করার আগে একটা test করে নিন, আর নিজের tool বা MCP server-কেই বেছে নিন।
- **Login।** SDK দিয়ে বানানো product-এ claude.ai login বা তার rate limit দেওয়ার অনুমতি Anthropic third-party developer-দের দেয় না, তাই এখানে যেমন দেখানো হয়েছে, API key ব্যবহার করুন।
- **Cloud provider mode।** `CLAUDE_CODE_USE_BEDROCK` বা `CLAUDE_CODE_USE_VERTEX`-এর মতো variable অন্য provider বেছে নেয়। Tokens-এর সাথে এগুলো সেট করবেন না।
- **ব্যাকগ্রাউন্ড traffic।** Claude Code gateway-র বাইরে Anthropic-এ version check আর telemetry পাঠায়। `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1` সেটা বন্ধ করে, বিনিময়ে auto-update চলে যায়।

## সমস্যা হলে

**প্রতিটা request-এ 404।** Base URL শেষ হয়েছে `/v1` দিয়ে। Process নিজেই `/v1/messages` জুড়ে নেয়, তাই `https://tokens.bd` ব্যবহার করুন।

**401 `invalid_api_key`, অথবা `Not logged in`।** Key ভুল, নয়তো variable-গুলো process-এ পৌঁছায়নি। TypeScript-এ দেখুন `env`-এ `...process.env` আছে কিনা। Python-এ `env` dict দেখুন। আরও দেখুন `~/.claude/settings.json` আপনার মান উল্টে দিচ্ছে কিনা (`settingSources: []` ব্যবহার করুন)। SDK `.env` file load করে না।

**404 `model_not_found`।** ID-টা Tokens চেনে না, নয়তো কোনো alias (`sonnet`, `opus`, `haiku`) একটা Claude-এর নামে গিয়ে দাঁড়িয়েছে। Alias variable-গুলোতে আপনার Tokens ID বসান, আর ID-টা `GET https://tokens.bd/v1/models`-এর সাথে মিলিয়ে দেখুন।

**`thinking`, `effort`, `context_management` বা অচেনা field নিয়ে 400 error।** Claude Code adaptive thinking আর beta field পাঠায়, যেগুলো non-Claude model ফিরিয়ে দেয়। `CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1` তার বেশিরভাগ সরিয়ে দেয়। তারপরও একটা model ফেল করলে অন্য model চেষ্টা করুন।

**"Prompt is too long", অথবা session কখনো compact হয় না।** অচেনা ID-র জন্য Claude Code ধরে নেয় 200K context। `CLAUDE_CODE_MAX_CONTEXT_TOKENS` model-এর আসল window-তে সেট করুন।

**Process চালুই হয় না।** Bundled binary install হয়নি। Claude Code native-ভাবে install করুন, আর TypeScript-এ `pathToClaudeCodeExecutable` সেট করুন।

**402 `insufficient_credits`, 403 `model_not_allowed_on_key` বা `tier_permission_denied`, 429 `window_exhausted` বা `concurrency_limit`।** এগুলো অ্যাকাউন্টের সীমার ব্যাপার, SDK-র সমস্যা নয়। কয়েকটা subagent-ওয়ালা run একসাথে অনেক request পাঠায়, তাতে `concurrency_limit` লাগতে পারে। দেখুন [Errors](/docs/errors) আর [Troubleshooting](/docs/troubleshooting), আর [support](/docs/support)-এর সাথে যোগাযোগের সময় `x-tokens-request-id` header-এর মান দিয়ে দিন।

---
Page: https://tokens.bd/bn/docs/claude-agent-sdk
