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 endpoint-এ। শুধু একটা model ডাকতে চাইলে Anthropic SDK ছোট আর সহজ পথ।
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-এর বিরুদ্ধে শুরু থেকে শেষ পর্যন্ত চালিয়ে দেখা হয়নি।
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 পেজেও একই সতর্কতা আছে।
যা যা লাগবে#
- API keys থেকে নেওয়া একটা Tokens key, যেটা
TOKENS_API_KEYনামে export করা। - /models থেকে একটা model ID, যেমন
deepseek/deepseek-v4.1-flash, যেটা tool calling সাপোর্ট করে (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), আর TypeScript-এpathToClaudeCodeExecutableসেট করুন।
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-এর মতোই।
দুই SDK env-কে আলাদাভাবে সামলায়, আর এই তফাতটা গুরুত্বপূর্ণ:
- TypeScript। Process default-ভাবে আপনার environment পায়, কিন্তু
options.envসেট করলে সেটা পুরো environment-কে বদলে দেয়। তাইprocess.envছড়িয়ে (spread করে) দিন, নইলে processPATHসহ সবকিছু হারাবে। - 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 পেজ যেমন করে। তাহলে agent-এর কোনো অংশ এমন model চাইবে না যা Tokens-এ নেই। প্রতিটা variable-এ পুরো model ID দিতে হবে। ID copy করুন /models থেকে বা GET https://tokens.bd/v1/models থেকে।
SDK একই process চালায় বলে Claude Code পেজের আরও দুটো variable এখানেও খাটে:
CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1request থেকে Claude-only beta field-এর বেশিরভাগ সরিয়ে দেয়। এতে non-Claude model থেকে400error আসা ঠেকে।CLAUDE_CODE_MAX_CONTEXT_TOKENSClaude Code-কে model-এর আসল context window জানায়। চেনে না এমন ID-র জন্য সে ধরে নেয় 200K token, তাই ছোট window-র model compact না করে "prompt too long" দিয়ে ফেল করে। সংখ্যাটা নিন /models-এ model-এর পেজ থেকে।
Python: ছোট একটা agent#
pip install --upgrade claude-agent-sdkimport 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 ব্যবহার করুন।
Settings file আপনার variable উল্টে দিতে পারে
Claude Code ~/.claude/settings.json আর project settings পড়ে। Anthropic-এর documentation বলছে, shell-এ export করা আর settings file-এর env block-এ একই variable থাকলে settings file-এর মানই জেতে। আপনি একই মেশিনে আগে Claude Code setup করে রাখলে ওই file-এর base URL, key বা model আপনার agent-এও খাটবে। setting_sources=[] (Python) ওই file-গুলো এড়িয়ে যায়। এর মানে agent CLAUDE.md, skill বা project settings-ও load করবে না। ওগুলো চাইলে লাইনটা বাদ দিন।
TypeScript: ছোট একটা agent#
npm install @anthropic-ai/claude-agent-sdk
npm install --save-dev tsxpackage.json-এ "type": "module" দিন যাতে top-level await চলে, অথবা file-টার নাম রাখুন agent.mts।
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}`);
}
}npx tsx agent.tsCode-এ 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 পড়েন।
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)// 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, 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-সহ।
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,
)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-এর হিসাবে পড়ে। Non-Claude model-এর জন্য tool call কীভাবে সামলানো হয়, তা দেখুন Tool calling-এ।
ঠিকমতো চলছে কিনা দেখুন#
প্রথমে SDK ছাড়াই endpoint আর model ID test করুন (macOS, Linux, WSL বা Git 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-এর Usage analytics-এও দেখা যায়, আপনার সেট করা model ID-র নিচে। Log-এ অন্য কোনো model দেখালে বুঝবেন alias variable-এর একটা সেট করা হয়নি।
ResultMessage-এ total_cost_usd নামে একটা field আছে। ওটা SDK-র নিজের আন্দাজ, Tokens যা bill করে তা নয়। আসল হিসাব পাবেন Tokens-এর usage page আর GET /v1/tokens/usage-এ।
Model বাছাই#
Agent loop নির্ভর করে tool call, লম্বা context আর system prompt মেনে চলার ওপর। এসবে model-এ model-এ বিস্তর তফাত। কোনগুলো agent-এর কাজে মানায়, তা Choosing a model-এ আছে। fallback_model (Python) বা fallbackModel (TypeScript) দিতে হলে অন্য একটা Tokens ID-ই দিন, কখনো Claude-এর নাম নয়। max_turns কম রাখা আর key-তে মাসিক spend cap বসানো (API keys) থাকলে loop বেসামাল হলেও ক্ষতি সীমিত থাকে।
সীমাবদ্ধতা আর যা চলে না#
- শুধু Claude-এর feature। Fast mode সরাসরি Anthropic-এর API-তে গিয়ে যাচাই করে, তাই Tokens দিয়ে চলে না। Gateway credential সেট থাকলে Remote Control আর voice dictation বন্ধ থাকে। Extended thinking আর prompt caching চলে শুধু তখনই, যখন Tokens ID-র পেছনের model সেগুলো সাপোর্ট করে (Reasoning, Prompt caching)।
- Claude Code-এর নিজের model picker।
/modelpicker 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 আর Troubleshooting, আর support-এর সাথে যোগাযোগের সময় x-tokens-request-id header-এর মান দিয়ে দিন।