Skip to content

API Reference

SDK Exports

Import from openpets-sdk:

typescript
import {
  // Core
  z,
  createPlugin,
  createLazyPlugin,
  createSingleTool,
  createLogger,
  loadEnv,
  getEnv,
  setEnv,
  clearEnv,
  getConfig,
  getPetsConfig,
  syncEnvToConfig,

  // Read-Only Mode
  isReadOnly,
  setReadOnly,
  getReadOnlyStatus,
  filterToolsForReadOnly,

  // Error Handling
  ToolError,

  // Retry & Rate Limiting
  withRetry,
  withRateLimit,

  // Caching
  LocalCache,
  SingleValueCache,
  withCache,
  createCache,

  // Testing
  createTestHarness,

  // Advanced Tools
  createBatchTool,
  createPaginatedTool,
  createCodeExecutionTool,

  // Sessions & Artifacts
  useSession,
  createArtifact,
  getArtifact,

  // API Client
  BaseAPIClient,
  createAPIClientConfig,

  // Web Search
  webSearch,
  codeSearch,
  webSearchWithFallback,
  ExaProvider,

  // OAuth
  startOAuthFlow,
  refreshAndSaveTokens,
  getOAuthStatus,
  createOAuthTools,

  // TOON Format
  jsonToToon,
  formatResponseAsToon,

  // Prompts
  loadPrompts,
  ensurePromptsFolder,

  // Interceptors
  createLoggingInterceptor,
  createTimingInterceptor,
  createRedactionInterceptor,

  // Provider Validation
  validateProviders,

  // Schema Helpers
  stringField,
  optionalString,
  numberField,
  booleanField,
  stringEnum,
  withPagination,

  // Kennel (Pet Management)
  createKennel,
  discoverPets,
  loadPetConfig,
  savePetConfig,
  setEnvForPet,

  // Types
  type ToolDefinition,
  type ToolErrorCode,
  type ToolRecord,
  type PluginInstance,
  type CreatePluginOptions,
  type RetryConfig,
  type RateLimitConfig,
  type OAuthConfig,
  type APIClientConfig,
  type TestHarness,
  type SessionStore,
  type ArtifactRecord,
  type PetPrompt
} from "openpets-sdk"

Core Functions

createPlugin(tools)

Creates a multi-tool plugin from an array of tool definitions.

typescript
function createPlugin(tools: ToolDefinition[]): { tool: Record<string, any> }

Parameters:

  • tools - Array of ToolDefinition objects

Returns: An object with a tool record keyed by tool name.

Example:

typescript
const tools: ToolDefinition[] = [
  {
    name: "my-pet-list-items",
    description: "List all items",
    schema: z.object({}),
    execute: async () => JSON.stringify({ items: [] })
  }
]

return createPlugin(tools)

createLazyPlugin(tools, options?)

Creates a plugin where tool execute functions are only initialized when first called. Useful for pets with many tools to reduce startup time.

typescript
function createLazyPlugin(
  tools: ToolDefinition[],
  options?: CreatePluginOptions
): PluginInstance

createSingleTool(tool)

Creates a single OpenPets-compatible tool definition.

typescript
function createSingleTool(tool: Omit<ToolDefinition, "name">): {
  description: string
  args: ZodObject<any>
  execute: (args: any, context?: any) => Promise<string>
}

Example:

typescript
return createSingleTool({
  description: "Does one thing",
  schema: z.object({ input: z.string() }),
  execute: async (args) => args.input.toUpperCase()
})

createLogger(namespace)

Creates a namespaced logger instance.

typescript
function createLogger(namespace: string): Logger

Logger Methods:

  • debug(message, context?) - Debug level
  • info(message, context?) - Info level
  • warn(message, context?) - Warning level
  • error(message, context?) - Error level

Example:

typescript
const logger = createLogger("my-pet")
logger.info("Starting up", { version: "1.0.0" })
logger.error("Failed to connect", { error: err.message })

Environment Variables:

  • ENABLE_LOGGING=true - Enable logging
  • LOG_LEVEL=debug|info|warn|error - Set log level
  • DEBUG=true - Enable debug mode

loadEnv(petId)

Loads environment variables for a pet.

typescript
function loadEnv(petId?: string): Record<string, string>

Load Order:

  1. .pets/config.json values (furthest directories first, nearest last)
  2. .env values (furthest directories first, nearest last)

loadEnv() does not automatically merge arbitrary process.env values.

Example:

typescript
const env = loadEnv("my-pet")
const apiKey = env.MY_PET_API_KEY

Types

ToolDefinition<T>

typescript
interface ToolDefinition<T extends Record<string, any> = any> {
  name: string
  description: string
  schema: z.ZodObject<any>
  execute: (args: T) => Promise<string>
  deprecated?: ToolDeprecation
  hints?: ToolHints
  search?: ToolSearchMetadata
  cache?: ToolCacheConfig
  coreFields?: CoreFieldsSpec
  stream?: (args: T) => AsyncIterable<string>
}

ToolError

Structured error class for classifiable tool failures.

typescript
class ToolError extends Error {
  code: ToolErrorCode
  retryable: boolean
  retryAfter?: number
  statusCode?: number
}

type ToolErrorCode =
  | "RATE_LIMITED"
  | "NOT_FOUND"
  | "UNAUTHORIZED"
  | "FORBIDDEN"
  | "TIMEOUT"
  | "VALIDATION_ERROR"
  | "UPSTREAM_ERROR"
  | "NOT_CONFIGURED"

Example:

typescript
throw new ToolError({
  code: "RATE_LIMITED",
  message: "Exceeded API limit",
  retryable: true,
  retryAfter: 30
})

PluginInstance

typescript
interface PluginInstance {
  tool: ToolRecord
}

type ToolRecord = Record<string, {
  description: string
  args: z.ZodObject<any>
  execute: (args: any, context?: any) => Promise<string>
}>

Schema Helpers

Available Helpers

typescript
import {
  stringField,
  optionalString,
  numberField,
  booleanField,
  stringEnum,
  withPagination
} from "openpets-sdk"

stringField(description)

typescript
const schema = z.object({
  query: stringField("Search query")
})

withPagination(schema)

Adds perPage and page fields:

typescript
const schema = withPagination(z.object({
  status: z.string()
}))
// Adds: perPage?: number, page?: number

Zod Instance

Always use the z export from the SDK:

typescript
import { z } from "openpets-sdk"

const schema = z.object({
  name: z.string(),
  count: z.number().optional(),
  type: z.enum(["a", "b", "c"])
})

Allowed Schema Types

TypeExample
Stringz.string()
Numberz.number()
Booleanz.boolean()
String Arrayz.array(z.string())
Number Arrayz.array(z.number())
Objectz.object({ key: z.string() })
Enumz.enum(["a", "b"])
Optionalz.string().optional()

Not Allowed

  • z.array(z.object({...})) - Nested objects in arrays
  • z.record() - Record types
  • z.union() with objects

Cache Utilities

LocalCache<T>

typescript
import { LocalCache } from "openpets-sdk"

const cache = new LocalCache<MyData>({
  ttl: 60000,  // 1 minute
  maxSize: 100
})

cache.set("key", data)
const value = cache.get("key")
cache.delete("key")
cache.clear()

withCache(cache, key, fetcher)

Reads from cache and falls back to fetcher() when needed:

typescript
const cache = new LocalCache<any>({ ttl: 30000 })
const data = await withCache(cache, "users:list", async () => {
  return fetch("https://api.example.com/users").then(r => r.json())
})

Retry & Rate Limiting

withRetry(operation, config?)

Retries an async operation with exponential backoff and jitter.

typescript
async function withRetry<T>(
  operation: () => Promise<T>,
  config?: RetryConfig
): Promise<T>
typescript
interface RetryConfig {
  maxRetries?: number          // default: 3
  baseDelayMs?: number         // default: 500
  maxDelayMs?: number          // default: 10000
  jitterMs?: number | { min: number; max: number }
  retryableErrorCodes?: ToolErrorCode[]
  retryableStatusCodes?: number[]
  shouldRetry?: (error: unknown) => boolean
  onRetry?: (event: RetryEvent) => void
}

Example:

typescript
const data = await withRetry(() => fetchAPI("/users"), {
  maxRetries: 5,
  baseDelayMs: 1000
})

withRateLimit(operation, config?)

Wraps an operation with rate-limit awareness and automatic retry on 429 responses.

typescript
async function withRateLimit<T>(
  operation: () => Promise<T>,
  config?: RateLimitConfig
): Promise<T>
typescript
interface RateLimitConfig extends RetryConfig {
  key?: string
  getRetryAfter?: (error: unknown) => number | undefined
}

Testing

createTestHarness(factory)

Creates a test harness for unit testing pet plugins without real API calls.

typescript
function createTestHarness(factory: () => Promise<PluginInstance>): TestHarness
typescript
interface TestHarness {
  setEnv: (vars: Record<string, string>) => void
  mockFetch: (url: string, response: MockFetchResponse) => void
  clearFetchMocks: () => void
  listTools: () => Promise<string[]>
  executeTool: (name: string, args?: Record<string, any>) => Promise<any>
  validateSchemas: () => Promise<SchemaValidationResult>
  reset: () => void
  dispose: () => void
}

Example:

typescript
const harness = createTestHarness(MyPlugin)
harness.setEnv({ MY_API_KEY: "test-key" })
harness.mockFetch("https://api.example.com/users", { users: [] })

const tools = await harness.listTools()
const result = await harness.executeTool("my-pet-list-users")

harness.dispose()

Advanced Tool Builders

createBatchTool(config)

Creates a tool that processes multiple items in a single invocation.

typescript
function createBatchTool<TArgs>(config: BatchToolConfig): ToolDefinition

createPaginatedTool(config)

Creates a tool with built-in pagination support (offset, cursor, or link-based).

typescript
function createPaginatedTool<TArgs, TItem>(
  config: PaginatedToolConfig<TArgs, TItem>
): ToolDefinition
typescript
type PaginationMode = "offset" | "cursor" | "link"

createCodeExecutionTool(options)

Creates a sandboxed code execution tool.

typescript
function createCodeExecutionTool(options: CreateCodeExecutionToolOptions): ToolDefinition

Sessions & Artifacts

useSession(petName, options?)

Creates a session store for maintaining state across tool calls.

typescript
function useSession(petName: string, options?: SessionOptions): SessionStore
typescript
interface SessionStore {
  get: (key: string) => any
  set: (key: string, value: any) => void
  delete: (key: string) => boolean
  clear: () => void
  keys: () => string[]
  has: (key: string) => boolean
}

createArtifact(ref, data, options?)

Stores an artifact (large result, file, etc.) for later retrieval.

typescript
function createArtifact(
  ref: string,
  data: any,
  options?: ArtifactOptions
): ArtifactRecord

getArtifact(ref, options?)

Retrieves a stored artifact by reference.

typescript
function getArtifact(ref: string, options?: ArtifactOptions): ArtifactRecord | null

API Client

BaseAPIClient

Abstract base class for building typed API clients with built-in retry, rate limiting, and connection testing.

typescript
abstract class BaseAPIClient {
  constructor(config: APIClientConfig)
  abstract testConnection(): Promise<ConnectionTestResult>
}
typescript
interface APIClientConfig {
  baseUrl: string
  apiKey: string
  timeout?: number    // default: 30000
  retries?: number    // default: 3
  debug?: boolean
  headers?: Record<string, string>
}

createAPIClientConfig(options)

Factory for creating APIClientConfig with defaults applied.

typescript
function createAPIClientConfig(options: Partial<APIClientConfig> & { baseUrl: string; apiKey: string }): APIClientConfig

OAuth

startOAuthFlow(config, options?)

Runs a complete OAuth 2.0 authorization code flow: starts a local callback server, opens the browser, exchanges the code for tokens, and saves them to pets.json.

typescript
async function startOAuthFlow(
  config: OAuthConfig,
  options?: OAuthFlowOptions
): Promise<OAuthResult>

refreshAndSaveTokens(config)

Refreshes an expired access token using a stored refresh token.

typescript
async function refreshAndSaveTokens(config: OAuthConfig): Promise<OAuthResult>

getOAuthStatus(config)

Returns the current authentication status for an OAuth-configured pet.

typescript
function getOAuthStatus(config: OAuthConfig): {
  authenticated: boolean
  hasRefreshToken: boolean
  expiresAt?: number
}

createOAuthTools(config)

Creates a set of tools for managing OAuth from within a pet (authenticate, status, refresh, disconnect).

typescript
function createOAuthTools(config: OAuthConfig): ToolDefinition[]

TOON Format

Token-optimized output format for LLM consumption (~24% token reduction vs JSON).

jsonToToon(data, indent?)

Converts any JSON-serializable value to TOON format.

typescript
function jsonToToon(data: any, indent?: string): string

formatResponseAsToon(response)

Converts a tool response (string or object) to TOON format.

typescript
function formatResponseAsToon(response: any): string

webSearch(query, options?)

Searches the web using configured search providers.

typescript
async function webSearch(
  query: string,
  options?: WebSearchOptions
): Promise<WebSearchResponse>

codeSearch(query, options?)

Searches code repositories.

typescript
async function codeSearch(
  query: string,
  options?: CodeSearchOptions
): Promise<CodeSearchResponse>

webSearchWithFallback(query, options?)

Web search with automatic fallback between providers.

typescript
async function webSearchWithFallback(
  query: string,
  options?: WebSearchOptions
): Promise<WebSearchResponse>

Read-Only Mode

isReadOnly(petId)

Returns true if read-only mode is enabled for the given pet.

typescript
function isReadOnly(petId: string): boolean

filterToolsForReadOnly(tools, writePatterns, readOnly, logger?)

Filters out write tools when read-only mode is active.

typescript
function filterToolsForReadOnly(
  tools: ToolDefinition[],
  writePatterns: string[],
  readOnly: boolean,
  logger?: Logger
): ToolDefinition[]

Example:

typescript
const WRITE_PATTERNS = ["create", "update", "delete", "add-", "remove-"]
const tools = filterToolsForReadOnly(allTools, WRITE_PATTERNS, isReadOnly("my-pet"), logger)

Interceptors

Interceptors wrap tool executions to add cross-cutting concerns.

createLoggingInterceptor(options?)

Logs every tool invocation and result.

createTimingInterceptor(options?)

Measures and reports execution time for each tool call.

createRedactionInterceptor(options?)

Redacts sensitive values from tool arguments and results before logging.


Prompts

loadPrompts(petName, options?)

Loads prompt files from a pet's prompts/ directory.

typescript
function loadPrompts(petName: string, options?: LoadPromptsOptions): PetPrompt[]
typescript
interface PetPrompt {
  name: string
  content: string
  when: "always" | "on-demand"
  metadata?: Record<string, any>
}

ensurePromptsFolder()

Creates the prompts/ directory structure if it doesn't exist.


Provider Validation

validateProviders(packageJson, pluginDir)

Validates that a pet's package.json provider declarations match the actual implementation.

typescript
function validateProviders(packageJson: any, pluginDir: string): ProviderValidationReport

Environment & Config

getEnv(key, petId?)

Gets a single environment variable value.

typescript
function getEnv(key: string, petId?: string): string | undefined

setEnv(key, value, options?)

Sets an environment variable in pets.json or .env.

setConfig(petId, configValues, projectDir?)

Sets non-secret project configuration values in pets.json under petConfig.<petId>.

typescript
function setConfig(petId: string, configValues: Record<string, unknown>, projectDir?: string): { success: boolean; message: string }

clearEnv(key, options?)

Removes an environment variable from the config.

getConfig(petId, key, fallback?, projectDir?)

Gets a typed configuration value from pets.json.

typescript
function getConfig<T>(petId: string, key: string, fallback?: T, projectDir?: string): T | undefined

syncEnvToConfig(projectDir?)

Migrates .env variables to pets.json format.


Next Steps