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/sdkOr with other package managers:
yarn add @promptrails/sdk
pnpm add @promptrails/sdkSupports 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
| Parameter | Type | Default | Description |
|---|---|---|---|
apiKey | string | Required | PromptRails API key |
baseUrl | string | https://api.promptrails.ai | API base URL |
timeout | number | 30000 | Request timeout in milliseconds |
maxRetries | number | 3 | Maximum retry attempts |
Available Resources
| Resource | Property | Description |
|---|---|---|
| Agents | client.agents | Agent CRUD, versioning, execution, playground, guardrails |
| Prompts | client.prompts | Prompt CRUD and content-only versioning |
| Executions | client.executions | Listing, trees, cancel, approval inbox, approve/deny, stream |
| Credentials | client.credentials | Credential management |
| Data Sources | client.dataSources | Data source CRUD, versioning, query |
| Chat | client.chat | Chat sessions and message streaming |
| Traces | client.traces | Trace listing, summary, PII report, ingest |
| MCP Tools | client.mcpTools | MCP tool management |
| MCP Templates | client.mcpTemplates | MCP template browsing and install |
| Guardrails | client.guardrails | Scanner catalog and guardrail configuration |
| LLM Models | client.llmModels | Available LLM models |
| Agent Triggers | client.agentTriggers | Agent trigger management (generic webhook, Slack, Telegram, Teams, WhatsApp, schedule) |
| Agent VFS | client.agentVfs | Read, write, move, copy, grep, and inspect an agent’s virtual files |
| Assets | client.assets | List, retrieve, sign, and delete generated assets |
| A2A | client.a2a | Agent-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
| Exception | HTTP Status | Description |
|---|---|---|
ValidationError | 400 | Invalid request parameters |
UnauthorizedError | 401 | Invalid or missing API key |
ForbiddenError | 403 | Insufficient permissions |
NotFoundError | 404 | Resource not found |
RateLimitError | 429 | Rate limit exceeded |
ServerError | 5xx | Server-side error |
PromptRailsError | Any | Base class for all errors |
All error instances include:
message— Error descriptionstatusCode— HTTP status codecode— Optional error codedetails— 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 })Related Topics
- Examples — Ready-to-run code examples
- Quickstart — Getting started guide
- Python SDK — Python alternative
- Go SDK — Go alternative
- API Keys and Scopes — API key management
- REST API Reference — Underlying REST API