Building AI Agents with Our SDK
The platform SDK is a TypeScript-first Node.js library designed for building production AI agents. It abstracts provider differences behind a unified interface, provides built-in tools for common operations, supports real-time streaming with typed chunks, and integrates with the platform for governance, RBAC, and audit logging. This post walks through the SDK's architecture, core methods, and the patterns you need to build agents that work in production.
Core Architecture
The SDK is organized around a small set of composable primitives. At the center is the provider factory, which creates LLM client instances for any supported backend. Providers expose a consistent interface regardless of the underlying model service, so agent logic remains portable across providers.
The provider factory supports the following backends: createProvider('anthropic') for Claude models via the Anthropic API, createProvider('openai') for GPT models via the OpenAI API, createProvider('bedrock') for models through AWS Bedrock, and createProvider('ollama') for locally-hosted models via Ollama. Each provider handles authentication, request formatting, and response parsing for its respective backend. Your agent code calls the same methods regardless of which provider is active.
Key Methods
The SDK exposes a focused set of methods that cover the full lifecycle of agent interactions.
complete()
The complete() method sends a prompt to the configured provider and returns the full response. This is the simplest interaction pattern — fire a request, wait for the complete response. It accepts a messages array, model selection parameters, temperature, max tokens, and an optional tool configuration. The response includes the generated text, token usage metrics, and any tool calls the model decided to make.
stream()
The stream() method provides real-time streaming of model responses. Instead of waiting for the complete response, you receive typed chunks as they are generated. Chunk types include text_delta (incremental text), tool_call_delta (incremental tool call construction), and done (stream completion with final usage metrics). Streaming is essential for interactive applications where users expect to see responses as they are generated rather than waiting for the full output.
createAgent()
The createAgent() method constructs an agent instance with a defined behavior loop. An agent is more than a single LLM call — it is an iterative process that follows the Prompt, Reason, Act, Observe, Iterate, Complete pattern. The agent receives a task, reasons about how to accomplish it, decides whether to use tools, calls tools if needed, observes the results, and iterates until the task is complete or a termination condition is reached.
The createAgent() configuration accepts a system prompt (defining the agent's role and constraints), a list of available tools (built-in, custom, or MCP-sourced), maximum iteration limits (preventing runaway loops), and provider configuration. The agent manages its own conversation history, tool call state, and iteration tracking internally.
getMCPTools()
The getMCPTools() method connects to MCP servers and retrieves their tool definitions in a format the SDK can use directly. This bridges the MCP ecosystem with the SDK's agent framework: any MCP server — whether it exposes a database, an API, a filesystem, or any other resource — can be made available to an agent on the platform through a single method call. The returned tool definitions include the MCP server's declared capabilities, parameter schemas, and descriptions.
listModels() and healthCheck()
The listModels() method queries the configured provider for available models, returning their identifiers, context window sizes, and capability metadata. The healthCheck() method verifies connectivity to the provider and returns latency and availability information. Both are operational methods designed for platform integration — monitoring dashboards, model selection UIs, and automated health monitoring.
Built-In Tools
The SDK ships with a set of built-in tools that cover common agent operations. These are not external dependencies — they are part of the SDK itself and execute within the agent's runtime environment.
- shell: Execute shell commands with configurable timeout and working directory. Commands run in a sandboxed subprocess with restricted permissions.
- read_file: Read file contents from the filesystem. Supports text files with encoding detection and binary files with base64 output.
- write_file: Write content to the filesystem. Supports creating new files and overwriting existing ones with atomic write operations.
- list_files: List files and directories with optional recursive traversal, glob pattern matching, and metadata output (size, modification time).
- delete_file: Remove files or directories with confirmation requirements for non-empty directories.
- search: Full-text search across files with regex support, context lines, and file type filtering.
Each built-in tool is defined with a Zod schema that specifies its input parameters, output format, and validation rules. The schema serves double duty: it validates inputs at runtime and provides the parameter descriptions that the LLM uses to decide how to call the tool.
Custom Tools with Zod Schemas
Beyond built-in tools, you define custom tools using Zod schemas. A custom tool consists of a name, a description (used by the LLM for tool selection), a Zod schema defining the input parameters, and a handler function that executes the tool logic.
The Zod schema approach provides type safety at every level. The schema validates inputs before the handler executes. TypeScript infers the handler's parameter types from the schema, so you get compile-time type checking. The schema's descriptions are automatically converted to the format the LLM provider expects for tool definitions. You write one schema and get validation, type safety, and LLM-facing documentation from a single source of truth.
This is particularly important for production agents where malformed tool inputs can cause downstream failures. The schema acts as a contract between the LLM and the tool — if the LLM generates invalid parameters, they are rejected before the handler executes, and the agent receives a structured error message it can use to correct its approach.
Streaming Architecture
The streaming implementation uses typed discriminated unions for chunk types. Each chunk has a type field (text_delta, tool_call_delta, or done) and type-specific payload fields. This design enables exhaustive pattern matching in TypeScript — the compiler enforces that you handle all chunk types, preventing runtime errors from unexpected chunk formats.
The text_delta chunks carry incremental text content as the model generates it. The tool_call_delta chunks carry incremental construction of tool call parameters — the tool name, argument JSON, and call ID are built up across multiple chunks as the model generates them. The done chunk carries the final usage metrics (input tokens, output tokens, total tokens) and a stop reason indicating why generation ended (natural stop, tool use, max tokens).
Platform Integration
When running inside the platform, the SDK automatically integrates with platform-level services. Authentication is handled through the platform's auth layer — agent API calls are authenticated against the workspace's credential store, with RBAC policies determining which models, tools, and resources each agent can access.
Workspace isolation ensures that agents in different workspaces cannot access each other's resources, credentials, or conversation histories. Audit logging captures every agent interaction — every LLM call, every tool invocation, every streaming session — with full context for compliance and debugging.
MCP tools accessed through the platform are subject to the platform's governance policies. A tool call that would execute directly in a standalone context passes through the platform's human-in-the-loop approval flow when configured. The SDK handles this transparently — the agent code does not change between standalone and platform-managed execution. The governance layer sits between the agent and the tool, enforced by the platform, invisible to the agent logic.
The platform SDK is designed around a simple principle: agent logic should be portable across providers, tools should be composable and type-safe, and governance should be structural rather than procedural. Write your agent once. Run it anywhere. Govern it through the platform. That is the architecture.