---
title: "Building a TypeScript SDK for Your AI Agent Platform: Types, Client, and Documentation"
description: "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."
canonical: https://callsphere.ai/blog/building-typescript-sdk-ai-agent-platform-types-client
category: "Learn Agentic AI"
tags: ["TypeScript SDK", "API Client", "Developer Tools", "Agentic AI", "npm", "TypeScript"]
author: "CallSphere Team"
published: 2026-03-17T00:00:00.000Z
updated: 2026-05-07T00:27:45.779Z
---

# 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:

```typescript
// 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:

```json
{
  "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.

```mermaid
flowchart LR
    INPUT(["User intent"])
    PARSE["Parse plus
classify"]
    PLAN["Plan and tool
selection"]
    AGENT["Agent loop
LLM plus tools"]
    GUARD{"Guardrails
and policy"}
    EXEC["Execute and
verify result"]
    OBS[("Trace and metrics")]
    OUT(["Outcome plus
next action"])
    INPUT --> PARSE --> PLAN --> AGENT --> GUARD
    GUARD -->|Pass| EXEC --> OUT
    GUARD -->|Fail| AGENT
    AGENT --> OBS
    style AGENT fill:#4f46e5,stroke:#4338ca,color:#fff
    style GUARD fill:#f59e0b,stroke:#d97706,color:#1f2937
    style OBS fill:#ede9fe,stroke:#7c3aed,color:#1e1b4b
    style OUT fill:#059669,stroke:#047857,color:#fff
```

```typescript
// 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;
  result: string;
}

/** Pagination wrapper for list endpoints. */
export interface PaginatedList {
  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:

```typescript
// 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(method: string, path: string, body?: unknown): Promise {
    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:

```typescript
// 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 {
    return this.client.request('POST', '/agents', params);
  }

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

  /** List agents with pagination. */
  async list(limit = 20, offset = 0): Promise

> {
    return this.client.request>(
      'GET',
      `/agents?limit=${limit}&offset=${offset}`
    );
  }

  /** Delete an agent by ID. */
  async delete(agentId: string): Promise {
    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:

```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

---

Source: https://callsphere.ai/blog/building-typescript-sdk-ai-agent-platform-types-client
