Skip to content
Learn Agentic AI
Learn Agentic AI12 min read1 views

Building a TypeScript SDK for Your AI Agent Platform: Types, Client, and Documentation

A practical guide to building a TypeScript SDK for an AI agent platform, covering package setup with tsup, strong type definitions, a fetch-based HTTP client, and JSDoc-powered inline documentation.

Project Setup and Build Tooling

A TypeScript SDK must ship both ESM and CommonJS so that every consumer — whether they use Next.js, Node.js with require, or Vite — can import it without issues. Use tsup for builds:

// tsup.config.ts
import { defineConfig } from 'tsup';

export default defineConfig({
  entry: ['src/index.ts'],
  format: ['cjs', 'esm'],
  dts: true,
  splitting: false,
  sourcemap: true,
  clean: true,
  minify: false,
});

Your package.json exports should point to both builds:

{
  "name": "@myagent/sdk",
  "version": "0.1.0",
  "main": "./dist/index.cjs",
  "module": "./dist/index.js",
  "types": "./dist/index.d.ts",
  "exports": {
    ".": {
      "import": "./dist/index.js",
      "require": "./dist/index.cjs",
      "types": "./dist/index.d.ts"
    }
  }
}

This configuration ensures TypeScript users get full type inference, CommonJS users get a working require, and ESM users get tree-shakeable imports.

Defining Strong Types

The type definitions are the backbone of a TypeScript SDK. They serve triple duty: compile-time safety, IDE autocompletion, and living documentation.

flowchart TD
    START["Building a TypeScript SDK for Your AI Agent Platf…"] --> A
    A["Project Setup and Build Tooling"]
    A --> B
    B["Defining Strong Types"]
    B --> C
    C["The Fetch-Based HTTP Client"]
    C --> D
    D["Resource Classes with JSDoc"]
    D --> E
    E["Error Types"]
    E --> F
    F["FAQ"]
    F --> DONE["Key Takeaways"]
    style START fill:#4f46e5,stroke:#4338ca,color:#fff
    style DONE fill:#059669,stroke:#047857,color:#fff
// src/types.ts

export interface Agent {
  id: string;
  name: string;
  model: string;
  instructions: string;
  tools: ToolRef[];
  createdAt: string;
}

export interface ToolRef {
  id: string;
  name: string;
  type: 'function' | 'retrieval' | 'code_interpreter';
}

export interface CreateAgentParams {
  name: string;
  model?: string;
  instructions?: string;
  toolIds?: string[];
}

export interface RunResult {
  id: string;
  status: 'queued' | 'in_progress' | 'completed' | 'failed' | 'cancelled';
  output: string | null;
  usage: TokenUsage;
  toolCalls: ToolCallResult[];
  createdAt: string;
  completedAt: string | null;
}

export interface TokenUsage {
  promptTokens: number;
  completionTokens: number;
  totalTokens: number;
}

export interface ToolCallResult {
  id: string;
  toolName: string;
  arguments: Record<string, unknown>;
  result: string;
}

/** Pagination wrapper for list endpoints. */
export interface PaginatedList<T> {
  data: T[];
  total: number;
  hasMore: boolean;
}

Use union types for status fields rather than plain string. This catches typos at compile time and enables exhaustive switch checks.

The Fetch-Based HTTP Client

Build the client on the native fetch API. This avoids adding dependencies like axios and works in Node 18+, Deno, Bun, and the browser:

See AI Voice Agents Handle Real Calls

Book a free demo or calculate how much you can save with AI voice automation.

// src/client.ts
import type { Agent, CreateAgentParams, RunResult, PaginatedList } from './types';
import { AgentAPIError, AuthenticationError } from './errors';

export interface ClientOptions {
  apiKey: string;
  baseUrl?: string;
  timeout?: number;
}

export class AgentClient {
  private readonly apiKey: string;
  private readonly baseUrl: string;
  private readonly timeout: number;

  /** Resource namespaces */
  public readonly agents: AgentsResource;
  public readonly runs: RunsResource;

  constructor(options: ClientOptions) {
    this.apiKey = options.apiKey;
    this.baseUrl = options.baseUrl ?? 'https://api.myagent.ai/v1';
    this.timeout = options.timeout ?? 30_000;
    this.agents = new AgentsResource(this);
    this.runs = new RunsResource(this);
  }

  /** @internal */
  async request<T>(method: string, path: string, body?: unknown): Promise<T> {
    const controller = new AbortController();
    const timer = setTimeout(() => controller.abort(), this.timeout);

    try {
      const response = await fetch(`${this.baseUrl}${path}`, {
        method,
        headers: {
          'Authorization': `Bearer ${this.apiKey}`,
          'Content-Type': 'application/json',
          'User-Agent': '@myagent/sdk 0.1.0',
        },
        body: body ? JSON.stringify(body) : undefined,
        signal: controller.signal,
      });

      if (response.status === 401) {
        throw new AuthenticationError('Invalid API key');
      }
      if (!response.ok) {
        const error = await response.json().catch(() => ({}));
        throw new AgentAPIError(response.status, error.message ?? 'Unknown error');
      }
      return await response.json() as T;
    } finally {
      clearTimeout(timer);
    }
  }
}

Resource Classes with JSDoc

Each resource class groups related endpoints and provides detailed JSDoc that appears in IDE tooltips:

// src/resources/agents.ts

class AgentsResource {
  constructor(private client: AgentClient) {}

  /**
   * Create a new AI agent.
   *
   * @param params - The agent configuration.
   * @returns The created agent with a unique ID.
   * @throws {AuthenticationError} If the API key is invalid.
   * @throws {AgentAPIError} If the server rejects the request.
   *
   * @example
   * const agent = await client.agents.create({
   *   name: 'Support Bot',
   *   model: 'gpt-4o',
   *   instructions: 'Answer customer questions.',
   * });
   */
  async create(params: CreateAgentParams): Promise<Agent> {
    return this.client.request<Agent>('POST', '/agents', params);
  }

  /** Retrieve an agent by ID. */
  async get(agentId: string): Promise<Agent> {
    return this.client.request<Agent>('GET', `/agents/${agentId}`);
  }

  /** List agents with pagination. */
  async list(limit = 20, offset = 0): Promise<PaginatedList<Agent>> {
    return this.client.request<PaginatedList<Agent>>(
      'GET',
      `/agents?limit=${limit}&offset=${offset}`
    );
  }

  /** Delete an agent by ID. */
  async delete(agentId: string): Promise<void> {
    await this.client.request('DELETE', `/agents/${agentId}`);
  }
}

The JSDoc @example blocks are critical. They show up directly in VS Code hover tooltips, so developers see working code without ever opening a documentation site.

Error Types

A clean error hierarchy in TypeScript:

// src/errors.ts

export class MyAgentError extends Error {
  constructor(message: string) {
    super(message);
    this.name = 'MyAgentError';
  }
}

export class AgentAPIError extends MyAgentError {
  constructor(
    public readonly statusCode: number,
    message: string,
  ) {
    super(`[${statusCode}] ${message}`);
    this.name = 'AgentAPIError';
  }
}

export class AuthenticationError extends MyAgentError {
  constructor(message: string) {
    super(message);
    this.name = 'AuthenticationError';
  }
}

FAQ

Should I use fetch or axios for the HTTP layer?

Use native fetch. As of Node 18, fetch is built in and requires zero dependencies. Axios adds 30KB+ to your bundle and introduces a third-party dependency that needs its own security updates. The only exception is if you need automatic cookie handling or request interceptors — but for API SDKs, middleware patterns handle those concerns better.

How do I support both Node.js and browser environments?

Build on fetch and avoid Node-specific APIs like fs or process in your core client. If you need Node-specific features such as file uploads from disk, put them in a separate @myagent/sdk-node package that extends the base client. This keeps the core bundle browser-compatible.

How important are JSDoc examples in an SDK?

Extremely important. IDE-integrated documentation is where developers spend most of their time. A JSDoc @example block that shows a complete, runnable snippet is worth more than an entire documentation page because it appears exactly at the moment of need — when the developer is typing code.


#TypeScriptSDK #APIClient #DeveloperTools #AgenticAI #Npm #TypeScript #LearnAI #AIEngineering

Share
C

Written by

CallSphere Team

Expert insights on AI voice agents and customer communication automation.

Try CallSphere AI Voice Agents

See how AI voice agents work for your industry. Live demo available -- no signup required.

Related Articles You May Like

Learn Agentic AI

Fine-Tuning LLMs for Agentic Tasks: When and How to Customize Foundation Models

When fine-tuning beats prompting for AI agents: dataset creation from agent traces, SFT and DPO training approaches, evaluation methodology, and cost-benefit analysis for agentic fine-tuning.

AI Interview Prep

7 Agentic AI & Multi-Agent System Interview Questions for 2026

Real agentic AI and multi-agent system interview questions from Anthropic, OpenAI, and Microsoft in 2026. Covers agent design patterns, memory systems, safety, orchestration frameworks, tool calling, and evaluation.

Learn Agentic AI

How NVIDIA Vera CPU Solves the Agentic AI Bottleneck: Architecture Deep Dive

Technical analysis of NVIDIA's Vera CPU designed for agentic AI workloads — why the CPU is the bottleneck, how Vera's architecture addresses it, and what it means for agent performance.

Learn Agentic AI

Building Your First MCP Server: Connect AI Agents to Any External Tool

Step-by-step tutorial on building an MCP server in TypeScript, registering tools and resources, handling requests, and connecting to Claude and other LLM clients.

Learn Agentic AI

Adaptive Thinking in Claude 4.6: How AI Agents Decide When and How Much to Reason

Technical exploration of adaptive thinking in Claude 4.6 — how the model dynamically adjusts reasoning depth, its impact on agent architectures, and practical implementation patterns.

Learn Agentic AI

How to Build an AI Coding Assistant with Claude and MCP: Step-by-Step Guide

Build a powerful AI coding assistant that reads files, runs tests, and fixes bugs using the Claude API and Model Context Protocol servers in TypeScript.