SSD Nodes Learn 🎉 VPS $5.50/মাস থেকে
নির্দেশিকা Matt Connorদ্বারা Matt Connor

SandBase agent runtime নিজে হোস্ট করার নিয়ম

আপনার নিজস্ব VPS-এ SandBase Harness v0.3.2 সেটআপ করার পূর্ণাঙ্গ নির্দেশিকা। এখানে ট্যাগড ইনস্টল, agent YAML কনফিগারেশন, MCP সার্ভার এবং Anthropic SDK কানেক্ট করার উপায় জানুন।

SandBase agent runtime নিজে হোস্ট করলে আপনি যা পাবেন

SandBase agent runtime নিজে হোস্ট করার অর্থ হলো আপনার নিজস্ব সার্ভারে SandBase Harness চালানো। এর ফলে সেশন, ক্রেডেনশিয়াল, মেমোরি এবং অডিট ট্রেইল অন্য কারো সার্ভারের পরিবর্তে আপনার নিজের ডিস্কে সংরক্ষিত থাকে। এটি একটি Node সার্ভিস। এটি 127.0.0.1:3000 পোর্টে লিসেন করে, একটি /v1 HTTP API এবং ওয়েব কনসোল পরিবেশন করে এবং আপনার এজেন্ট ফাইলের পাশেই SQLite-এ এর স্টেট বা অবস্থা জমা রাখে।

/v1 API-টি Claude Managed Agents (CMA)-এর আদলে তৈরি, যা হলো একটি হোস্ট করা ম্যানেজড-এজেন্ট API। এই রানটাইমটি উভয় দিক থেকেই গুরুত্বপূর্ণ: আপনি Anthropic SDK ব্যবহার করে কোড লিখতে পারেন এবং এর baseURL-কে আপনার নিজের সার্ভারের দিকে নির্দেশ করতে পারেন, পরবর্তীতে একই কোড কোনো হোস্ট করা ডিপ্লয়মেন্টে স্থানান্তর করা সম্ভব।

SandBase Harness কোনো মডেল সরবরাহ করে না। এটি একটি মডেলকে কল করে। 2026 সালের আগস্ট মাস পর্যন্ত এটি OpenAI, Anthropic এবং OpenAI-সামঞ্জস্যপূর্ণ এন্ডপয়েন্ট সমর্থন করে, যার মধ্যে সেলফ-হোস্টেড গেটওয়ে এবং DeepSeek V4-এর মতো প্রোভাইডার অন্তর্ভুক্ত। আপনাকে নিজস্ব API কি (key) ব্যবহার করতে হবে, অথবা এমন একটি লোকাল সার্ভার থাকতে হবে যা OpenAI API সমর্থন করে।

শুরু করার আগে আপনার যা প্রয়োজন

  • অন্তত 2 GB RAM সহ Ubuntu 24.04 চালিত একটি VPS। TypeScript build হলো ইনস্টলেশনের সবচেয়ে ভারী ধাপ।
  • Node.js 22 বা তার নতুন সংস্করণ এবং npm 10 বা তার নতুন সংস্করণ। প্রজেক্টের নিয়ম অনুযায়ী এই দুটিই সর্বনিম্ন প্রয়োজনীয় সংস্করণ।
  • git, এবং আপনি যে মডেল প্রোভাইডার ব্যবহার করতে চান তার একটি API key।
  • Docker, তবে এটি শুধুমাত্র তখনই প্রয়োজন যদি আপনি প্রতি সেশনের জন্য আলাদা কন্টেইনার স্যান্ডবক্স ব্যবহার করতে চান।

Ubuntu 24.04-এর নিজস্ব রিপোজিটরিতে Node 18.19 থাকে, যা প্রয়োজনীয় সর্বনিম্ন সংস্করণের চেয়ে পুরনো। তাই NodeSource থেকে Node সংগ্রহ করুন।

curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs git
node -v
npm -v

node -v কমান্ডটি চালালে v22 বা তার চেয়ে বেশি এবং npm -v কমান্ডটি চালালে 10 বা তার চেয়ে বেশি সংস্করণ দেখানোর কথা। যদি node -v কমান্ডটি এখনও v18.19.1 দেখায়, তবে ডিস্ট্রিবিউশনের প্যাকেজটি এখনও ইনস্টল করা আছে এবং PATH-এ সেটিই প্রাধান্য পাচ্ছে। এগিয়ে যাওয়ার আগে এটি মুছে ফেলুন, কারণ বিল্ড প্রক্রিয়াটি শেল যে node খুঁজে পাবে তার ওপর ভিত্তি করেই চলবে।

v0.3.2 ট্যাগ থেকে SandBase ইনস্টল করুন

একটি মুভিং ব্রাঞ্চ থেকে নয়, বরং সবসময় একটি নির্দিষ্ট ট্যাগ থেকে ইনস্টল করুন। main-এর একটি বেয়ার ক্লোন আপনাকে এক ঘণ্টা আগে যুক্ত হওয়া কোড দিতে পারে, যার ফলে নিচের কনফিগারেশন কি (keys) গুলোর সাথে তা নাও মিলতে পারে। 16 আগস্ট 2026 অনুযায়ী v0.3.2 হলো বর্তমান ট্যাগ।

sudo install -d -o "$USER" -g "$USER" /opt/sandbase
cd /opt/sandbase
git clone --branch v0.3.2 --depth 1 https://github.com/sandbaseai/sandbase-harness.git
cd sandbase-harness
npm ci
npm run build

npm install নয়, বরং npm ci ব্যবহার করুন। ci কমিট করা লকফাইলে থাকা সঠিক ভার্সনগুলো ইনস্টল করে, ফলে আপনার ট্রি (tree) মেইনটেইনারদের পরীক্ষিত ট্রির সাথে হুবহু মিলে যায়। npm install নতুন ভার্সনগুলো রিজলভ করতে পারে, যার ফলে একটি পিন করা ট্যাগ নীরবে তার পিন করা অবস্থা হারিয়ে ফেলে।

এখন একটি ওয়ার্কস্পেস তৈরি করুন। ওয়ার্কস্পেস হলো একটি আলাদা ডিরেক্টরি যা আপনার এজেন্ট ফাইল এবং সমস্ত রানটাইম স্টেট ধরে রাখে। সোর্স চেকআউটের বাইরে এটি রাখলে আপনি আপনার ডেটা স্পর্শ না করেই নতুন ট্যাগ পুল করতে পারবেন।

mkdir -p /opt/sandbase/workspace
cd /opt/sandbase/workspace
node /opt/sandbase/sandbase-harness/dist/index.js init
node /opt/sandbase/sandbase-harness/dist/index.js start

init ওয়ার্কস্পেসের ভেতর একটি .managed-agents/ ডিরেক্টরি তৈরি করে। start কনসোলটিকে http://127.0.0.1:3000/dashboard-এ এবং API-কে http://127.0.0.1:3000/v1-এ চালু করে। আপনার ল্যাপটপ থেকে এখনো এগুলোর কোনোটিতেই পৌঁছানো সম্ভব নয়, যা সঠিক এবং নিচে বিস্তারিত আলোচনা করা হয়েছে। আপাতত SSH-এর মাধ্যমে কনসোলে প্রবেশ করুন:

ssh -N -L 3000:127.0.0.1:3000 you@your-server

সেই দীর্ঘ node .../dist/index.js পাথটি বারবার টাইপ করা ক্লান্তিকর, তাই এটিকে একটি নাম দিন।

alias sandbase='node /opt/sandbase/sandbase-harness/dist/index.js'

নিচের কমান্ডগুলো সেই ভিত্তিতে sandbase <command> হিসেবে লেখা হয়েছে।

npm থেকে ইনস্টল করবেন না

প্রকল্পটি তাদের নিজস্ব ইনস্টলেশন নথিতে এটি উল্লেখ করেছে: npm-এ দৃশ্যমান unscoped managed-agents প্যাকেজটি এই প্রকল্প নয়। তাই npx managed-agents এবং npm install -g managed-agents কমান্ডগুলো আপনার কাঙ্ক্ষিত runtime-এর সাথে সম্পর্কহীন কিছু ডাউনলোড করবে। রক্ষণাবেক্ষণকারীরা আনুষ্ঠানিকভাবে কোনো scoped প্যাকেজ ঘোষণা না করা পর্যন্ত tagged GitHub সোর্স থেকে ইনস্টল করুন। প্রকল্পের ইতিহাসে এটি কোনো ছোটখাটো বিষয় নয়: v0.3.1 সংস্করণটি মূলত পুরনো npm quick start পদ্ধতিকে সরিয়ে pinned tagged-source পাথ দিয়ে প্রতিস্থাপন করার জন্যই আনা হয়েছে।

মডেল প্রোভাইডারের দিকে ওয়ার্কস্পেস নির্দেশ করুন

init .managed-agents/config.yaml লেখে। পুরো ওয়ার্কস্পেসের জন্য একটি প্রোভাইডার কনফিগার করা থাকে এবং পরবর্তীতে প্রতিটি এজেন্ট নির্দিষ্ট মডেল আইডি নির্বাচন করে।

model:
  provider: openai
  api_key: ${OPENAI_API_KEY}
storage:
  metadata:
    provider: sqlite
    options: {}
  artifacts:
    provider: local
    options:
      base_path: files

${OPENAI_API_KEY} ফর্মটি প্রসেস এনভায়রনমেন্ট থেকে মান গ্রহণ করে, তাই কি (key) কনফিগারেশন ফাইলের বাইরে থাকে এবং ফাইলের কোনো ব্যাকআপেও এটি অন্তর্ভুক্ত হয় না। এটি এমন একটি এনভায়রনমেন্ট ফাইলে রাখুন যা শুধুমাত্র root পড়তে পারে, কারণ systemd প্রিভিলেজ কমানোর আগেই root হিসেবে EnvironmentFile= পড়ে নেয়।

sudo install -d -m 750 /etc/sandbase
sudo touch /etc/sandbase/runtime.env
sudo chmod 600 /etc/sandbase/runtime.env

ফাইলটি একটি এডিটরে খুলুন এবং OPENAI_API_KEY=sk-... লাইনটি যোগ করুন। প্রোভাইডার কি (key) এখানেই থাকা উচিত। সেশন চলাকালীন কোনো এজেন্ট যে সিক্রেট ব্যবহার করে তা বরং রানটাইমের ক্রেডেনশিয়াল ভল্টে রাখা উচিত; এটি একটি ভিন্ন সমস্যা যার প্রভাবের পরিধিও ভিন্ন। তাই কোনো প্রোডাকশন টোকেন কোথাও পেস্ট করার আগে AI এজেন্ট থেকে সিক্রেট দূরে রাখা বিষয়টি পড়ে নেওয়া জরুরি।

এজেন্ট YAML: mcp_servers, tools এবং permission policies

এজেন্টগুলোকে workspace-এর agents/ ডিরেক্টরিতে YAML ফাইল হিসেবে সংজ্ঞায়িত করা হয়। রানটাইমের এই অংশটিতেই আপনি মূলত কাজ করবেন।

name: Incident commander
description: Triages alerts and coordinates response.
model: gpt-4o
system: |-
  You are an on-call incident commander.
mcp_servers:
  - name: sentry
    type: url
    url: https://mcp.sentry.dev/mcp
tools:
  - type: agent_toolset_20260401
    default_config:
      permission_policy: { type: always_ask }
    configs:
      - name: bash
        permission_policy: { type: always_ask }
  - type: mcp_toolset
    mcp_server_name: sentry
metadata:
  template: incident-commander

এটি লোড করুন এবং ফাইলটি সঠিকভাবে জমা হয়েছে কি না তা পরীক্ষা করুন:

sandbase reload
sandbase list
sandbase chat agent_assistant --message "hello"

reload কমান্ডটি seed YAML-কে SQLite-এ ইমপোর্ট করে। list কমান্ডটি এখন একটি ID সহ এজেন্টটিকে প্রদর্শন করবে। যদি list-এ এটি দেখা না যায়, তবে ফাইলটি পার্স করা হয়নি এবং .managed-agents/logs/runtime.log ফাইলে এর কারণ লেখা থাকবে।

mcp_servers MCP (model context protocol) এন্ডপয়েন্ট ঘোষণা করে। type: url মানে হলো রানটাইম অন্য কোথাও চলমান কোনো সার্ভারের সাথে HTTP-এর মাধ্যমে যোগাযোগ করে। ফলে আপনি বর্তমানে যা কিছু পরিচালনা করছেন তা এখানে কাজ করবে, যার মধ্যে রানটাইমের সাথে একই VPS-এ হোস্ট করা MCP servers অন্তর্ভুক্ত।

একটি সার্ভার ঘোষণা করলেই তার টুলগুলো এজেন্টের কাছে চলে যায় না। tools লিস্টটি তা নিশ্চিত করে, যেখানে একটি mcp_toolset এন্ট্রির mcp_server_name অংশটি উপরের name-এর সাথে মিলতে হবে। যদি এজেন্ট এমন আচরণ করে যেন MCP টুলগুলো নেই, তবে অন্য কোথাও খোঁজার আগে এই দুটি স্ট্রিং অক্ষর অনুযায়ী মিলিয়ে দেখুন।

agent_toolset_20260401 হলো বিল্ট-ইন টুল সেট। তারিখযুক্ত সাফিক্সটি হলো একটি স্কিমা ভার্সন, তাই কোনো এজেন্ট যদি এর সাথে পিন করা থাকে, তবে সেটি সেই টুল ডেফিনিশনগুলোই ধরে রাখে যা দিয়ে এটি লেখা হয়েছিল। default_config সেটের প্রতিটি টুলের জন্য পলিসি নির্ধারণ করে এবং configs-এর অধীনে প্রতিটি এন্ট্রি নাম অনুযায়ী একটি টুলকে ওভাররাইড করে, যেমন উদাহরণে bash

permission_policy হলো সেই জায়গা যেখানে একটি রানটাইম সাধারণ মডেল কলের চেয়ে বেশি কার্যকর হয়ে ওঠে। always_ask সেশনটিকে থামিয়ে দেয় এবং কোনো কল কার্যকর হওয়ার আগে মানুষের অনুমোদনের জন্য অপেক্ষা করে। always_allow এটিকে অনুমতি দেয়। bash-কে always_ask হিসেবে সেট করার অর্থ হলো, আপনি সরাসরি কমান্ডটি না দেখে এজেন্ট কোনো শেল কমান্ড চালাতে পারবে না। এটি সেই একই নিয়ন্ত্রণ ব্যবস্থা যা আপনি নিরাপদে VPS-এ Claude Code চালানোর সময় ব্যবহার করবেন।

তিনটি স্যান্ডবক্স মোড এবং কোনটি কখন ব্যবহার করবেন

কোড এক্সিকিউট করে এমন টুল কলগুলো একটি স্যান্ডবক্সের ভেতরে চলে। এনভায়রনমেন্টের config অবজেক্টের ভেতরে sandbox_provider-এর মাধ্যমে অথবা কনসোলের Settings থেকে Sandbox-এ গিয়ে ব্যাকএন্ড নির্বাচন করা হয়। এনভায়রনমেন্টগুলো POST /v1/environments-এ API-এর মাধ্যমে তৈরি করা হয়।

local মোড কোডটিকে রানটাইমের একটি চাইল্ড প্রসেস হিসেবে হোস্ট মেশিনে, রানটাইমের নিজস্ব ব্যবহারকারীর অধীনে চালায়। এটি ডিফল্ট মোড এবং আপনি যখন একমাত্র ব্যবহারকারী এবং এজেন্ট শুধুমাত্র আপনার মালিকানাধীন ফাইলগুলো পড়ে, তখন এটি ব্যবহার করা যুক্তিসঙ্গত। এটি কোনো আইসোলেশন নয়। একটি টুল কল যা ফাইল ডিলিট করে, তা আপনার ফাইলগুলোই ডিলিট করবে এবং যে টুল কল /etc/sandbase/runtime.env পড়ে, তা আপনার প্রোভাইডার কি (key) পড়ে ফেলবে।

docker মোড প্রতি সেশনের জন্য একটি করে কন্টেইনার চালু করে।

{
  "sandbox_provider": "docker",
  "image": "node:22-slim",
  "resources": { "memory": "1g", "cpu": 1 }
}

সেশনটি নিজস্ব ফাইলসিস্টেম, মেমরি সিলিং এবং CPU শেয়ার পায় এবং সেশন শেষ হলে কন্টেইনারটি মুছে ফেলা হয়। যখনই কোনো এজেন্ট এমন কোড চালায় যা আপনি লেখেননি, তখনই এই মোডে সুইচ করুন। এর অসুবিধা হলো, রানটাইমের ব্যবহারকারীর Docker সকেটে অ্যাক্সেস প্রয়োজন এবং docker গ্রুপে সদস্যপদ থাকা মানেই হোস্ট মেশিনে root-এর সমান ক্ষমতা থাকা। প্রতি সেশনের কন্টেইনারগুলো প্রতি রান একটি কন্টেইনারসহ সেলফ-হোস্টেড এজেন্ট স্যান্ডবক্স-এর মতোই, তাই একটি এস্কেপড প্রসেস কী কী অ্যাক্সেস করতে পারে, সেই সংক্রান্ত যুক্তি এখানেও অপরিবর্তিত থাকে।

kubernetes মোড সেশনের ওয়ার্কলোডকে একটি পড (pod) হিসেবে চালায় এবং kubectl execkubectl cp দিয়ে তা নিয়ন্ত্রণ করে। রানটাইম ইমেজে kubectl থাকা প্রয়োজন এবং এর ServiceAccount-এর টার্গেট নেমস্পেসে পড তৈরি, ডিলিট, গেট, লিস্ট এবং ওয়াচ করার জন্য RBAC (role-based access control) পারমিশন থাকতে হয়, সাথে exec সাবরিসোর্সটিও প্রয়োজন। আপনি যদি আগে থেকেই কোনো ক্লাস্টার ব্যবহার করেন, কেবল তখনই এই মোডটি সেটআপ করা লাভজনক।

রানটাইম কেন 127.0.0.1-এ আবদ্ধ (bound) থাকে?

কারণ এটি কোনো প্রমাণীকরণ (authentication) ছাড়াই চালু হয়। যখন অন্তত একটি API key থাকে, তখন রানটাইম bearer-token প্রমাণীকরণ সক্রিয় করে, কিন্তু একটি নতুন init কোনো কী তৈরি করে না। ডিফল্ট অবস্থায় 0.0.0.0-তে বাইন্ড করলে শেল টুল এবং আপনার প্রোভাইডার কী-সহ একটি প্রমাণীকরণহীন এজেন্ট রানটাইম পাবলিক ইন্টারনেটে উন্মুক্ত হয়ে যেত।

তাই যখন আপনি এটিকে অ্যাক্সেসযোগ্য করতে চান, তখন বাইন্ড অ্যাড্রেস পরিবর্তন না করে অন্য দুটি কাজ করুন।

প্রথমত, প্রমাণীকরণ চালু করুন। সার্ভিস এনভায়রনমেন্ট ফাইলে MANAGED_AGENTS_API_KEY সেট করুন, অথবা POST /v1/api-keys দিয়ে একটি কী তৈরি করুন, যা একবার একটি secret_key ফিল্ড প্রদান করবে এবং পরবর্তীতে আর কখনোই তা দেখাবে না। এরপর ক্লায়েন্টরা প্রতিটি অনুরোধে Authorization: Bearer <key> পাঠাবে।

দ্বিতীয়ত, সামনে একটি reverse proxy বসান এবং সেখানে TLS (transport layer security) টার্মিনেট করুন। রানটাইম ডিজাইন অনুযায়ী plain HTTP সার্ভ করে এবং আশা করে যে অন্য কোনো মাধ্যম সার্টিফিকেট হ্যান্ডেল করবে।

server {
    listen 443 ssl;
    server_name agents.example.com;

    ssl_certificate     /etc/letsencrypt/live/agents.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/agents.example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Connection "";
        proxy_buffering off;
        proxy_read_timeout 3600s;
    }
}

এই লাইনগুলোর মধ্যে দুটি কেবল সাজসজ্জার জন্য নয়। proxy_buffering off গুরুত্বপূর্ণ কারণ সেশনগুলো server-sent events (SSE)-এর মাধ্যমে স্ট্রিম হয়, এবং বাফারিং চালু থাকলে nginx বাফার পূর্ণ না হওয়া পর্যন্ত রেসপন্স আটকে রাখে; ফলে এজেন্ট কাজ করার সময় কনসোলে কিছুই দেখা যায় না এবং শেষে সব তথ্য একসাথে প্রদর্শিত হয়। proxy_read_timeout 3600s গুরুত্বপূর্ণ কারণ ডিফল্ট সময়সীমা 60 সেকেন্ড, তাই এক মিনিটের বেশি সময় কোনো স্ট্রিম নীরব থাকলে প্রক্সি মাঝপথেই সংযোগ বিচ্ছিন্ন করে দেয় এবং মনে হয় যেন রানটাইম ক্র্যাশ করেছে।

ফায়ারওয়ালে, 22 এবং 443 পোর্ট ওপেন রাখুন। 3000 পোর্ট বন্ধ রাখুন, কারণ প্রক্সি এটিকে loopback-এর মাধ্যমে অ্যাক্সেস করে এবং বক্সের বাইরের কোনো কিছুর এটি প্রয়োজন নেই।

আপনার নিজস্ব বক্সে Anthropic SDK নির্দেশ করুন

রানটাইমটি একটি CMA-আকৃতির /v1 ইন্টারফেস ইমপ্লিমেন্ট করে, তাই একটি Anthropic SDK ক্লায়েন্ট একটি ফিল্ড পরিবর্তন করে এর সাথে যোগাযোগ করতে পারে।

import Anthropic from '@anthropic-ai/sdk';

const client = new Anthropic({
  apiKey: process.env.MANAGED_AGENTS_API_KEY ?? 'local-dev-key',
  baseURL: 'http://127.0.0.1:3000'
});

এটি Claude Managed Agents ক্লায়েন্টদের পাঠানো বিটা হেডারগুলোও গ্রহণ করে, যেমন anthropic-beta: managed-agents-2026-04-01 এবং anthropic-beta: agent-memory-2026-07-22। লোকাল রানটাইমের ক্ষেত্রে এগুলো ঐচ্ছিক। এগুলো রাখা হয়েছে যাতে হোস্ট করা ডিপ্লয়মেন্টের জন্য লেখা কোড এখানে কোনো পরিবর্তন ছাড়াই চলতে পারে।

সামঞ্জস্যতা প্রায় সম্পূর্ণ, তবে পুরোপুরি নয়। কোনো ইন্টারফেস আছে বলে ধরে নেওয়ার আগে চেকআউটের docs/api-matrix.md পড়ুন, কারণ প্রকল্পটি সেখানে তার নিজস্ব সীমাবদ্ধতাগুলো নথিবদ্ধ করেছে। এর মধ্যে ক্লায়েন্ট-সাইড কাস্টম টুলগুলোও অন্তর্ভুক্ত, যেগুলোর জন্য বর্তমান ইভেন্ট-রেজাল্ট প্রোটোকলের উপরে নামসহ রেজিস্ট্রেশন প্রয়োজন।

Plain HTTP একইভাবে কাজ করে এবং রানটাইমটি সচল কি না তা যাচাই করার দ্রুততম উপায় এটি:

curl -N -X POST http://127.0.0.1:3000/v1/sessions/SESSION_ID/messages \
  -H "Content-Type: application/json" \
  -d '{"content": "Hello", "stream": true}'

একটি সঠিক রেসপন্স হলো ইভেন্টের একটি স্ট্রিম যা ক্রমাগত আসতে থাকে। যদি সংযোগ বিচ্ছিন্ন হয়ে যায়, তবে পুরো টার্ন পুনরায় না চালিয়ে আপনার দেখা শেষ ইভেন্ট থেকে পুনরায় শুরু করুন:

curl -N http://127.0.0.1:3000/v1/sessions/SESSION_ID/events/stream \
  -H "Last-Event-ID: EVENT_ID"

এই রেজুমেবল স্ট্রিমটির কারণেই ল্যাপটপ বন্ধ হয়ে গেলেও সেশন টিকে থাকে। ইভেন্টগুলো সার্ভারে সংরক্ষিত থাকে, তাই ক্লায়েন্ট একমাত্র কপিটি ধরে রাখার পরিবর্তে একটি লগ পুনরায় প্লে করে।

যেখানে ক্রেডেনশিয়াল, মেমোরি এবং অডিট ট্রেইল ডিস্কে থাকে

রানটাইমের মালিকানাধীন সবকিছুই ওয়ার্কস্পেসের .managed-agents/ ডিরেক্টরির অধীনে থাকে।

.managed-agents/
├── config.yaml
├── data.db
├── logs/runtime.log
├── files/
├── skills/
├── snapshots/
└── sandbox/
  • data.db হলো SQLite মেটাডেটা: এজেন্ট, সেশন, ক্রেডেনশিয়াল ভল্ট এন্ট্রি, মেমোরি স্টোর এন্ট্রি এবং API কি।
  • files/ আপলোড করা ফাইলের বাইট ধারণ করে এবং skills/ আপলোড করা স্কিল প্যাকেজগুলো ধারণ করে।
  • snapshots/ সেশন ওয়ার্কস্পেসের স্ন্যাপশট ধারণ করে এবং sandbox/ লোকাল-মোড সেশনের ওয়ার্কিং ডিরেক্টরিগুলো ধারণ করে।
  • logs/runtime.log হলো প্রথম জায়গা যেখানে আপনার দেখা উচিত যখন কোনো কিছু কোনো আউটপুট ছাড়াই কাজ করা বন্ধ করে দেয়।

ক্রেডেনশিয়াল ভল্ট হলো সিক্রেটের গ্রুপ, যার প্রতিটি auth_type যেমন environment_variable দিয়ে যোগ করা হয় এবং সেশন তৈরির সময় vault_ids-এর মাধ্যমে সেশনের সাথে সংযুক্ত করা হয়। মেমোরি স্টোরগুলো নামযুক্ত এন্ট্রি ধারণ করে যা আপনি একটি memory_store হিসেবে সেশনে মাউন্ট করেন, যার নিজস্ব অ্যাক্সেস সেটিং এবং নির্দেশনা থাকে। উভয়ই data.db-এ থাকে, যা এই রানটাইম এবং একটি সাধারণ মডেল কলের মধ্যে মূল পার্থক্য: রানটাইম সেশনগুলোর মধ্যে তথ্য মনে রাখে এবং যা ঘটেছে তা লিখে রাখে।

যেহেতু এটি একটি একক ডিরেক্টরি, তাই এটিকে একক ব্যাকআপ হিসেবে রাখুন।

sudo systemctl stop sandbase
sudo tar czf /root/sandbase-$(date +%F).tgz -C /opt/sandbase/workspace .managed-agents
sudo systemctl start sandbase

প্রথমে সার্ভিসটি বন্ধ করুন। রানটাইম যখন লিখছে তখন একটি SQLite ডাটাবেস কপি করলে এমন একটি ফাইল তৈরি হতে পারে যা রিস্টোর করার সময় খুলবে না, এবং আপনি এটি তখনই জানতে পারবেন যখন আপনার এটি সবচেয়ে বেশি প্রয়োজন হবে। আপনি যদি এজেন্ট YAML-কে git-এ এবং স্টেট অন্য কোথাও রাখতে চান, তবে ডিপ্লয়মেন্ট ডকুমেন্টেশন start-এ --data-dir ব্যবহার করে স্টেটের অবস্থান নির্ধারণ করার সুবিধা দেয়।

রিস্টোর করার প্রক্রিয়াটি বিপরীত: একটি নতুন বক্সে একই ট্যাগ চেক আউট করুন, আর্কাইভটি ওয়ার্কস্পেসে আনপ্যাক করুন এবং সার্ভিসটি চালু করুন। আপনি যদি ${OPENAI_API_KEY} ফরম ব্যবহার করে থাকেন তবে আপনার প্রোভাইডার কি আর্কাইভে থাকবে না, তাই সেটি এমন কোথাও রাখুন যেখানে আপনি পরবর্তীতে তা খুঁজে পাবেন।

systemd-এর অধীনে চালানো

রানটাইমকে নিজস্ব ব্যবহারকারীর অধীনে চালান যাতে লোকাল স্যান্ডবক্স মোডে কোনো টুল আপনার হয়ে কাজ করতে না পারে।

sudo adduser --system --group --no-create-home --home /opt/sandbase sandbase
sudo chown -R sandbase:sandbase /opt/sandbase

এটি /etc/systemd/system/sandbase.service হিসেবে সেভ করুন।

[Unit]
Description=SandBase Harness runtime
After=network-online.target

[Service]
User=sandbase
Group=sandbase
WorkingDirectory=/opt/sandbase/workspace
EnvironmentFile=/etc/sandbase/runtime.env
ExecStart=/usr/bin/node /opt/sandbase/sandbase-harness/dist/index.js start --host 127.0.0.1 --port 3000
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

প্রজেক্টের নিজস্ব ডিপ্লয়মেন্ট উদাহরণে PATH-এ একটি managed-agents বাইনারি কল করা হয়। ট্যাগ করা সোর্স ইন্সটলেশন এটি তৈরি করে না, তাই ExecStart বিল্ট এন্ট্রি পয়েন্টের বিপরীতে node চালায়।

sudo systemctl daemon-reload
sudo systemctl enable --now sandbase
sudo systemctl status sandbase
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3000/dashboard

একটি সঠিক ফলাফলের ক্ষেত্রে status থেকে active (running) এবং curl থেকে 200 পাওয়া যায়। অন্য কিছু হলে, প্রথমে journalctl -u sandbase -n 50 এবং দ্বিতীয়ত .managed-agents/logs/runtime.log পড়ুন। enable --now হলো গুরুত্বপূর্ণ অংশ, কারণ হাতে শুরু করা কোনো প্রসেস পরবর্তী রিবুটের পর আর থাকে না।

কী কী সমস্যা হতে পারে এবং আপনি যে বার্তাগুলো দেখবেন

npm run build কোনো ত্রুটির বার্তা ছাড়াই npm থেকে বন্ধ হয়ে যায়। 1 GB RAM-এর VPS-এ TypeScript কম্পাইল করার সময় কার্নেলের out-of-memory killer প্রক্রিয়াটিকে বন্ধ করে দেয়, যা npm-এর পরিবর্তে কার্নেল লগে রিপোর্ট করা হয়। journalctl -k | grep -i "out of memory" চালিয়ে এটি নিশ্চিত করুন, যা বন্ধ হয়ে যাওয়া node প্রসেসটির নামসহ একটি লাইন দেখাবে। swap যোগ করুন অথবা বড় কোনো ইনস্ট্যান্সে বিল্ড করে dist/ ফাইলটি কপি করে আনুন।

Error: listen EADDRINUSE: address already in use 127.0.0.1:3000 অন্য কোনো প্রসেস ইতিমধ্যে পোর্টটি দখল করে রেখেছে। sudo ss -lntp | grep 3000 কমান্ডটি সেই প্রসেসের নাম জানাবে। হয় সেই প্রসেসটি বন্ধ করুন, অথবা --port 3001 ব্যবহার করে রানটাইম শুরু করুন এবং প্রক্সি আপডেট করুন।

আপনার ল্যাপটপ থেকে ড্যাশবোর্ড লোড হচ্ছে না। এটি প্রত্যাশিত আচরণ, কারণ রানটাইমটি loopback-এ বাইন্ড করা থাকে। উপরের SSH tunnel ব্যবহার করুন অথবা রিভার্স প্রক্সি সেটআপ সম্পন্ন করুন। --host 0.0.0.0 ব্যবহার করে এটি ঠিক করার চেষ্টা করবেন না, কারণ কি (key) তৈরি না হওয়া পর্যন্ত অথেন্টিকেশন বন্ধ থাকে।

Docker স্যান্ডবক্স permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock ত্রুটির কারণে ব্যর্থ হচ্ছে। sandbase ইউজারটি docker গ্রুপে নেই। sudo usermod -aG docker sandbase কমান্ড দিয়ে এটি ঠিক করুন এবং সার্ভিসটি রিস্টার্ট করুন। মনে রাখবেন, আপনি কী অনুমতি দিচ্ছেন: এই গ্রুপটি হোস্ট মেশিনে root-এর সমান ক্ষমতা রাখে, তাই রানটাইমকে আলাদা ইউজার দেওয়ার মূল উদ্দেশ্যটি এতে আংশিক ব্যাহত হয়।

Kubernetes স্যান্ডবক্স Error from server (Forbidden) ত্রুটির কারণে ব্যর্থ হচ্ছে। ServiceAccount-এর পড পারমিশন বা exec সাবরিসোর্সের অভাব রয়েছে। kubectl auth can-i create pods/exec -n <namespace> দিয়ে সরাসরি এটি পরীক্ষা করুন, যা yes অথবা no উত্তর দেবে।

API কি (key) যোগ করার পর প্রতিটি অনুরোধে 401 ত্রুটি দেখাচ্ছে। প্রথম কি (key) তৈরি হওয়ার সাথে সাথেই অথেন্টিকেশন চালু হয়ে যায় এবং এটি API-এর পাশাপাশি কনসোলের ক্ষেত্রেও প্রযোজ্য। Authorization: Bearer <key> পাঠান, এবং যদি কি (key) হারিয়ে ফেলেন তবে নতুন একটি তৈরি করুন, কারণ secret_key শুধুমাত্র একবারই দেখানো হয় এবং এটি পড়ার যোগ্য কোনো ফরম্যাটে সংরক্ষিত থাকে না।

একটি MCP সার্ভারের টুলগুলো সেশনে দেখা যাচ্ছে না। mcp_servers ফাইলের tools ব্লকের mcp_server_name-এর সাথে name মিলিয়ে দেখুন। এরপর curl -i <url> ব্যবহার করে নিশ্চিত করুন যে রানটাইম সার্ভার থেকে সরাসরি ওই URL-এ পৌঁছাতে পারছে কি না। URL-ভিত্তিক MCP সার্ভার একটি নেটওয়ার্ক ডিপেন্ডেন্সি, এবং একটি VPS আপনার ল্যাপটপের চেয়ে ভিন্নভাবে নাম রেজলভ করে ও ট্রাফিক রাউট করে।

FAQ

আমি কি OpenAI বা Anthropic-এর কী (key) ছাড়া SandBase Harness চালাতে পারি?

হ্যাঁ, যদি আপনার কাছে OpenAI-এর সাথে সামঞ্জস্যপূর্ণ কোনো endpoint থাকে। এই runtime-টি OpenAI, Anthropic এবং OpenAI-এর সাথে সামঞ্জস্যপূর্ণ প্রোভাইডারদের সমর্থন করে, তাই OpenAI API-তে কাজ করে এমন যেকোনো লোকাল সার্ভার এখানে ব্যবহার করা যাবে। .managed-agents/config.yaml-এ ওয়ার্কস্পেস প্রোভাইডার সেট করুন এবং api_key ও endpoint-কে সেটির দিকে নির্দেশ করুন। এই runtime-এর নিজস্ব কোনো মডেল নেই, তাই কলগুলোর উত্তর দেওয়ার জন্য কোনো না কোনো সার্ভিসের প্রয়োজন হবে।

পাবলিক পোর্টে runtime এক্সপোজ করা কি নিরাপদ?

ইনস্টল করা অবস্থায় এটি নিরাপদ নয়। এটি ডিফল্টভাবে 127.0.0.1:3000-এ বাইন্ড হয় এবং কোনো অথেন্টিকেশন ছাড়াই চালু হয়, আর এর সমাধান শুধু ভিন্ন কোনো বাইন্ড অ্যাড্রেস ব্যবহার করা নয়। একটি API key তৈরি করুন অথবা MANAGED_AGENTS_API_KEY সেট করুন, যাতে bearer-token অথেন্টিকেশন চালু হয়। এরপর TLS-এর জন্য সামনে Nginx বা Caddy বসান এবং ফায়ারওয়ালে পোর্ট 3000 বন্ধ রাখুন, যাতে শুধুমাত্র প্রক্সির মাধ্যমেই প্রবেশ করা যায়।

লোকাল, Docker এবং Kubernetes স্যান্ডবক্সের মধ্যে পার্থক্য কী?

local হোস্ট মেশিনে runtime-এর চাইল্ড প্রসেস হিসেবে টুল কোড চালায়, যেখানে runtime ব্যবহারকারীর পারমিশন থাকে এবং কোনো আইসোলেশন থাকে না। docker প্রতিটি সেশনের জন্য আলাদা কন্টেইনার তৈরি করে, যার নিজস্ব ফাইলসিস্টেম, মেমোরি লিমিট এবং CPU শেয়ার থাকে এবং সেশন শেষ হলে সেটি মুছে ফেলা হয়। kubernetes সেশনটিকে একটি পড হিসেবে চালায় এবং kubectl exec দিয়ে নিয়ন্ত্রণ করে, যার জন্য runtime ইমেজের ভেতরে kubectl এবং টার্গেট নেমস্পেসে পড ও exec সাবরিসোর্সের জন্য RBAC পারমিশন প্রয়োজন।

ব্যাকআপ নেওয়ার জন্য ঠিক কী কী প্রয়োজন?

ওয়ার্কস্পেসের .managed-agents/ ডিরেক্টরি। এটি config.yaml, এবং এজেন্ট, সেশন, ক্রেডেনশিয়াল ভল্ট এন্ট্রি ও মেমোরি এন্ট্রি সম্বলিত data.db SQLite ডেটাবেস ধারণ করে; এছাড়া আপলোড করা ফাইল, স্কিল প্যাকেজ এবং সেশন স্ন্যাপশটও এর অন্তর্ভুক্ত। কপি করার আগে সার্ভিসটি বন্ধ করে নিন যাতে আর্কাইভ করার সময় SQLite ডেটাবেসে কোনো রাইট অপারেশন না হয়। ${OPENAI_API_KEY} হিসেবে উল্লেখ করা প্রোভাইডার API key-গুলো এই ব্যাকআপের ভেতরে থাকে না, তাই সেগুলো আলাদাভাবে সংরক্ষণ করুন।

main ব্রাঞ্চের পরিবর্তে v0.3.2 ট্যাগ ক্লোন করব কেন?

একটি ট্যাগ হলো একটি নির্দিষ্ট কোডবেস, তাই আপনি যে কনফিগারেশন কী (key) এবং CLI কমান্ডগুলো সম্পর্কে পড়ছেন, সেগুলোই আপনি পাবেন। main প্রতিনিয়ত পরিবর্তিত হয় এবং গাইড লেখার সময় থেকে আপনার রান করার সময়ের মধ্যে কোনো কনফিগারেশন কী-এর নাম পরিবর্তন হয়ে যেতে পারে। প্রকল্পটি আরও সতর্ক করে যে, npm-এ থাকা আনস্কোপড managed-agents প্যাকেজটি এই প্রজেক্টের নয়, তাই npx managed-agents কমান্ডটি সম্পূর্ণ ভিন্ন কিছু ইনস্টল করবে। রিলিজ v0.3.1 মূলত সেই npm কুইক স্টার্টের পরিবর্তে পিন করা ট্যাগড-সোর্স পাথ ব্যবহারের জন্য আনা হয়েছে।