By Sagar Shankaran, Founder of CallSphere
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.
Key takeaways
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.
The type definitions are the backbone of a TypeScript SDK. They serve triple duty: compile-time safety, IDE autocompletion, and living documentation.
Hear it before you finish reading
Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.
flowchart LR
INPUT(["User intent"])
PARSE["Parse plus<br/>classify"]
PLAN["Plan and tool<br/>selection"]
AGENT["Agent loop<br/>LLM plus tools"]
GUARD{"Guardrails<br/>and policy"}
EXEC["Execute and<br/>verify result"]
OBS[("Trace and metrics")]
OUT(["Outcome plus<br/>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
// 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.
Build the client on the native fetch API. This avoids adding dependencies like axios and works in Node 18+, Deno, Bun, and the browser:
// 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);
}
}
}
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.
Still reading? Stop comparing — try CallSphere live.
CallSphere ships complete AI voice agents per industry — 14 tools for healthcare, 10 agents for real estate, 4 specialists for salons. See how it actually handles a call before you book a demo.
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';
}
}
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.
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.
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

Written by
Sagar Shankaran· Founder, CallSphere
LinkedInSagar Shankaran is the founder of CallSphere, where he builds production AI voice and chat agents deployed across healthcare, hospitality, real estate, and home services. He writes about agentic AI, LLM engineering, and shipping voice agents that handle real calls in production.
See how AI voice agents work for your industry. Live demo available -- no signup required.
How leaders should think about Claude Code 2.1 productivity — adoption patterns, ROI, competitive dynamics, and what DORA metrics AI means for the next 12 months.
Enterprise CIO Guide perspective on Comet's general-availability launch put an agentic browser in front of millions of consumers, and it works better than the demos suggested.
Enterprise CIO Guide perspective on Harvey AI's enterprise rollout numbers show legal agents have moved past the pilot stage at AmLaw 100 firms.
Enterprise CIO Guide perspective on Hippocratic AI's deployment numbers show healthcare voice agents are moving from pilot to production across major US health systems.
Enterprise CIO Guide perspective on AutoGen 0.5 brings async-first execution, an extension architecture, and tighter Azure integration.
Enterprise CIO Guide perspective on Google and partners pushed the Agent-to-Agent (A2A) protocol to standardize how agents from different vendors talk to each other.
© 2026 CallSphere Inc. All rights reserved.
Made within San Francisco