JavaScript SDK for AI Agents

Use the PromptRails JavaScript and TypeScript SDK to run AI agents, manage prompts, inspect execution trees, and send LLM traces.

Best for

Engineers building against the API, SDKs, CLI, MCP, or local tooling

JavaScript SDK for AI Agents

The official JavaScript/TypeScript SDK for PromptRails provides a fully typed client for interacting with the PromptRails API from Node.js, Deno, or browser environments.

Use the JavaScript SDK when a web app, Node service, serverless function, or frontend-adjacent workflow needs to call PromptRails directly. You do not need it to try an agent inside the product; Studio, chat, triggers, and Agent UI deployments can run without SDK code.

For production applications, create a scoped API key, keep it server-side when possible, and inspect the resulting execution trace before exposing the workflow to users.

Installation

npm install @promptrails/sdk

Or with other package managers:

yarn add @promptrails/sdk
pnpm add @promptrails/sdk

Supports both ESM and CommonJS module formats.

Current release: v0.7.0 — the standalone @promptrails/sdk/tracing entry point for sending spans to PromptRails from any code, with LangChain, OpenAI, Anthropic, Google GenAI, and OpenTelemetry integrations. See the changelog.

Technical detailsClient setup and resource reference

Client Initialization

import { PromptRails } from '@promptrails/sdk'
 
const client = new PromptRails({
  apiKey: 'your-api-key',
  baseUrl: 'https://api.promptrails.ai', // default
  timeout: 30000, // milliseconds, default
  maxRetries: 3, // default
})

Configuration

ParameterTypeDefaultDescription
apiKeystringRequiredPromptRails API key
baseUrlstringhttps://api.promptrails.aiAPI base URL
timeoutnumber30000Request timeout in milliseconds
maxRetriesnumber3Maximum retry attempts

Available Resources

ResourcePropertyDescription
Agentsclient.agentsAgent CRUD, versioning, execution, playground, guardrails
Promptsclient.promptsPrompt CRUD and content-only versioning
Executionsclient.executionsListing, trees, cancel, approval inbox, approve/deny, stream
Credentialsclient.credentialsCredential management
Data Sourcesclient.dataSourcesData source CRUD, versioning, query
Chatclient.chatChat sessions and message streaming
Tracesclient.tracesTrace listing, summary, PII report, ingest
MCP Toolsclient.mcpToolsMCP tool management
MCP Templatesclient.mcpTemplatesMCP template browsing and install
Guardrailsclient.guardrailsScanner catalog and guardrail configuration
LLM Modelsclient.llmModelsAvailable LLM models
Agent Triggersclient.agentTriggersAgent trigger management (generic webhook, Slack, Telegram, Teams, WhatsApp, schedule)
Agent VFSclient.agentVfsRead, write, move, copy, grep, and inspect an agent’s virtual files
Assetsclient.assetsList, retrieve, sign, and delete generated assets
A2Aclient.a2aAgent-to-Agent protocol

Common Operations

Execute an Agent

const result = await client.agents.execute('agent-id', {
  input: { message: 'Hello, world!' },
})
 
console.log(result.output)
console.log(`Cost: $${result.cost.toFixed(6)}`)
Technical detailsMore JavaScript SDK operations

List Agents

const agents = await client.agents.list({ page: 1, limit: 20 })
 
for (const agent of agents.data) {
  console.log(`${agent.name} (${agent.type})`)
}

Create a Prompt

const prompt = await client.prompts.create({
  name: 'Summarizer',
  description: 'Summarizes text',
})
 
const version = await client.prompts.createVersion(prompt.id, {
  systemPrompt: 'You are a concise summarizer.',
  userPrompt: 'Summarize: {{ text }}',
  message: 'Initial version',
})

Prompt versions are content-only — model and sampling live on the agent version.

Chat

const session = await client.chat.createSession({
  agentId: 'agent-id',
})
 
const response = await client.chat.sendMessage(session.id, {
  content: 'What is PromptRails?',
})
 
console.log(response.content)

Stream a Chat Turn

sendMessageStream posts a user message and yields typed Server-Sent Events on the same HTTP connection — useful for showing the agent’s reasoning, tool calls, and token-by-token deltas in the UI.

const session = await client.chat.createSession({ agentId: 'agent-id' })
 
const controller = new AbortController()
 
for await (const event of client.chat.sendMessageStream(
  session.id,
  { content: 'What is PromptRails?' },
  { signal: controller.signal },
)) {
  switch (event.type) {
    case 'execution':
      console.log('execution_id:', event.executionId)
      break
    case 'thinking':
      console.log('[thinking]', event.content)
      break
    case 'tool_start':
      console.log('[tool_start]', event.name)
      break
    case 'tool_end':
      console.log('[tool_end]', event.name, event.summary)
      break
    case 'content':
      process.stdout.write(event.content)
      break
    case 'done':
      console.log('\n[done]', event.tokenUsage)
      break
    case 'error':
      console.error('[error]', event.message)
      break
  }
}

Cancel an in-flight stream with controller.abort(). All event shapes are exported via the StreamEvent discriminated union:

import type { StreamEvent } from '@promptrails/sdk'

Stream an Existing Execution

When an execution was started outside a chat (e.g. client.agents.execute), subscribe to its live event stream with client.executions.stream:

for await (const event of client.executions.stream(executionId)) {
  if (event.type === 'content') process.stdout.write(event.content)
  if (event.type === 'done') break
}

Inspect an Execution Tree

const tree = await client.executions.tree('execution-id') // children[] populated
for (const child of tree.children) {
  console.log(child.agent_id, child.status, child.cost)
}

Approve or Deny an Execution

Approvals are execution-scoped in API v2. Runs parked at waiting_approval are resumed from the inbox:

const inbox = await client.executions.approvalInbox()
for (const exec of inbox.data) {
  await client.executions.approve(exec.id, { reason: 'Looks good' })
  // or: await client.executions.deny(exec.id, { reason: 'Denied' })
}
Technical detailsJavaScript SDK advanced details

Typed Agent Config

createVersion takes a typed AgentConfig — a discriminated union of the two API v2 kinds, PromptAgentConfig (an agent) and WorkflowAgentConfig (a workflow). Model, sampling, budget, approval policy, cache TTL and the tool / sub-agent / guardrail attachments are not part of config — they are version-scoped fields passed alongside it, all typed.

import type {
  PromptAgentConfig,
  ModelConfig,
  RunBudget,
} from '@promptrails/sdk'
 
const config: PromptAgentConfig = { type: 'agent', prompt_id: 'prompt-id' }
const model_config: ModelConfig = { model_id: 'gpt-4o', temperature: 0.2 }
const run_budget: RunBudget = { max_cost: 1.0, max_tool_calls: 20 }
 
await client.agents.createVersion('agent-id', {
  version: '1.0.0',
  config,
  model_config,
  run_budget,
  tools: [{ mcp_tool_id: 'tool-id', requires_approval: true }],
  guardrails: [{ type: 'input', scanner_type: 'pii' }],
  set_current: true,
})

For the workflow kind, build config with WorkflowAgentConfig ({ type: 'workflow', nodes: WorkflowNode[] }). See Agent Versioning for the full field reference.

Tracing

The @promptrails/sdk/tracing entry point sends spans to PromptRails from any code, without managing your prompts or agents on the platform. It is independent of the API client and only needs an API key with the traces:write scope.

import { Tracer } from '@promptrails/sdk/tracing'
 
const tracer = new Tracer({ apiKey: 'pr_...' })
 
await tracer.span('agent-run', { kind: 'agent' }, async (root) => {
  root.setInput({ q: 'weather?' })
  await tracer.span('llm-call', { kind: 'llm' }, async (llm) => {
    llm.setModel('gpt-4o').setUsage(120, 30)
  })
})
 
await tracer.flush()

Framework integrations

Subpath imports auto-instrument popular frameworks:

// LangChain
import { PromptRailsCallbackHandler } from '@promptrails/sdk/tracing/integrations/langchain'
await chain.invoke(inputs, { callbacks: [new PromptRailsCallbackHandler(tracer)] })
 
// OpenAI
import { traceOpenAI } from '@promptrails/sdk/tracing/integrations/openai'
const client = traceOpenAI(new OpenAI(), tracer)
 
// Anthropic
import { traceAnthropic } from '@promptrails/sdk/tracing/integrations/anthropic'
const anthropic = traceAnthropic(new Anthropic(), tracer)
 
// Google GenAI
import { traceGoogle } from '@promptrails/sdk/tracing/integrations/google'
const google = traceGoogle(new GoogleGenAI({ apiKey: '...' }), tracer)

See the Tracing guide for span kinds, batching, and the OpenTelemetry bridge.

SDK Version

import { VERSION } from '@promptrails/sdk'
console.log(VERSION) // "0.7.0"

The SDK also sends User-Agent: promptrails-js/<version> on every request (except in browsers, where fetch ignores the header).

TypeScript Types

The SDK includes full TypeScript type definitions. All request and response types are exported:

import type {
  Agent,
  AgentVersion,
  AgentExecution,
  Prompt,
  Trace,
  TraceSummary,
  Credential,
  ChatSession,
} from '@promptrails/sdk'

Error Handling

The SDK throws typed errors for different HTTP status codes:

import {
  PromptRailsError,
  ValidationError,
  UnauthorizedError,
  ForbiddenError,
  NotFoundError,
  RateLimitError,
  ServerError,
} from '@promptrails/sdk'
 
try {
  const result = await client.agents.execute('invalid-id', { input: {} })
} catch (error) {
  if (error instanceof NotFoundError) {
    console.log(`Agent not found: ${error.message}`)
  } else if (error instanceof ValidationError) {
    console.log(`Invalid input: ${error.message}`)
    console.log(`Details:`, error.details)
  } else if (error instanceof RateLimitError) {
    console.log(`Rate limited: ${error.message}`)
  } else if (error instanceof UnauthorizedError) {
    console.log(`Invalid API key: ${error.message}`)
  } else if (error instanceof ForbiddenError) {
    console.log(`Insufficient permissions: ${error.message}`)
  } else if (error instanceof ServerError) {
    console.log(`Server error (${error.statusCode}): ${error.message}`)
  } else if (error instanceof PromptRailsError) {
    console.log(`Unexpected error: ${error.message}`)
  }
}

Error Classes

ExceptionHTTP StatusDescription
ValidationError400Invalid request parameters
UnauthorizedError401Invalid or missing API key
ForbiddenError403Insufficient permissions
NotFoundError404Resource not found
RateLimitError429Rate limit exceeded
ServerError5xxServer-side error
PromptRailsErrorAnyBase class for all errors

All error instances include:

  • message — Error description
  • statusCode — HTTP status code
  • code — Optional error code
  • details — Optional additional details object

ESM and CJS Support

The SDK ships with both ESM and CommonJS builds:

// ESM
import { PromptRails } from '@promptrails/sdk'
 
// CommonJS
const { PromptRails } = require('@promptrails/sdk')

Pagination

// Page-based pagination
const page1 = await client.agents.list({ page: 1, limit: 20 })
const page2 = await client.agents.list({ page: 2, limit: 20 })