# PromptRails — Full Documentation > Consolidated dump of the full promptrails.ai/docs corpus for > LLM ingestion. Each section below corresponds to one doc page; > a `Source:` line identifies the canonical URL so quoted content > can be cited back to its home page. Generated from https://promptrails.ai/docs. --- # Introduction Source: https://promptrails.ai/docs/introduction > PromptRails is an AI agent orchestration platform for building, deploying, and monitoring LLM-powered applications. # What is PromptRails? PromptRails is a platform for building, deploying, and monitoring AI agents. It provides a complete infrastructure layer between your application and LLM providers, giving you full control over prompt engineering, agent orchestration, observability, and cost management. Whether you are prototyping a single chatbot or running a fleet of production agents across multiple LLM providers, PromptRails provides the tools to manage the entire lifecycle. ## Key Features - **Agent Orchestration** -- Build agents using five distinct execution strategies: simple, chain, multi-agent, workflow, and composite. Compose complex AI pipelines from reusable building blocks. - **Prompt Management** -- Version-controlled prompts with Jinja2 templating, input/output schemas, model assignment, and caching. Promote and roll back versions without code changes. - **Multi-Provider LLM Support** -- Connect to OpenAI, Anthropic, Google Gemini, DeepSeek, Fireworks, xAI, and OpenRouter through a unified credential system. - **Tracing and Observability** -- OpenTelemetry-style distributed tracing with 14 span kinds. Track every LLM call, tool invocation, guardrail evaluation, and data source query with full cost and latency breakdowns. - **Guardrails** -- 14 built-in scanner types for input and output validation including toxicity detection, PII filtering, prompt injection prevention, and more. Configure block, redact, or log actions per scanner. - **MCP Tools** -- First-class Model Context Protocol support. Connect external APIs, data sources, built-in functions, and remote MCP servers as tools for your agents. - **Data Sources** -- Query PostgreSQL, MySQL, BigQuery, Snowflake, Redshift, MSSQL, ClickHouse, or static files directly from your agents using versioned, parameterized query templates. - **Memory System** -- Five memory types (conversation, fact, procedure, episodic, semantic) with vector embedding support and semantic search for context-aware agents. - **Scoring and Evaluation** -- Score executions and spans with numeric, categorical, or boolean metrics. Support for manual scoring, API-based scoring, and LLM judge automated evaluation. - **Human-in-the-Loop Approvals** -- Pause agent execution at configurable checkpoints and require human approval before continuing. Integrate approval workflows via webhooks. - **Cost Tracking** -- Automatic per-execution and per-span cost calculation across all LLM providers. Workspace-wide cost summaries and per-agent cost analysis. - **Agent UI Deployments** -- Build and deploy interactive dashboards backed by your agents, prompts, and data sources. Multi-page layouts with a 12-column grid system and optional PIN protection. - **A2A Protocol** -- Agent-to-Agent communication via Google's A2A protocol with agent cards, JSON-RPC messaging, and task lifecycle management. - **SDKs and CLI** -- Official Python and JavaScript/TypeScript SDKs, a full-featured CLI, and an MCP server for IDE integration with Claude Desktop, Cursor, and Windsurf. ## How It Works PromptRails handles the full lifecycle of AI agents — from development to production. The platform provides: - **A web dashboard** for building and managing agents, prompts, and data sources - **REST APIs** for programmatic access to all platform features - **Real-time tracing** with detailed execution breakdowns - **Secure credential storage** with encrypted secrets All credentials are encrypted at rest and never exposed in API responses. ## Getting Started The fastest way to start using PromptRails is to install one of the SDKs and execute your first agent: - [Quickstart Guide](/docs/quickstart) -- Get up and running in under 5 minutes - [Python SDK](/docs/python-sdk) -- Full Python SDK reference - [JavaScript SDK](/docs/javascript-sdk) -- Full JavaScript/TypeScript SDK reference --- # Quickstart Source: https://promptrails.ai/docs/quickstart > Get up and running with PromptRails in under 5 minutes. Install the SDK, create an API key, execute an agent, and view traces. # Quickstart This guide walks you through installing the PromptRails SDK, creating an API key, executing your first agent, and viewing the execution trace. ## Prerequisites - A PromptRails account - A workspace with at least one configured agent - An LLM credential (e.g., OpenAI API key) added to your workspace ## Step 1: Install the SDK Install the PromptRails SDK for your language of choice. **Python** ```bash pip install promptrails ``` **JavaScript / TypeScript** ```bash npm install @promptrails/sdk ``` **Go** ```bash go get github.com/promptrails/go-sdk ``` ## Step 2: Create an API Key 1. Log in to the PromptRails dashboard 2. Navigate to **Settings > API Keys** 3. Click **Create API Key** 4. Give it a name (e.g., "Development Key") 5. Select the scopes you need. For this quickstart, select `*` (wildcard) to grant all permissions 6. Copy the generated key -- it is only shown once ## Step 3: Execute an Agent Use the SDK to execute an agent. You will need the agent ID, which you can find in the dashboard under **Agents**. **Python** ```python from promptrails import PromptRails client = PromptRails(api_key="your-api-key-here") # Execute an agent result = client.agents.execute( agent_id="your-agent-id", input={ "message": "What is the capital of France?" } ) print(result["data"]["output"]) ``` **Python (async)** ```python import asyncio from promptrails import AsyncPromptRails async def main(): client = AsyncPromptRails(api_key="your-api-key-here") result = await client.agents.execute( agent_id="your-agent-id", input={ "message": "What is the capital of France?" } ) print(result["data"]["output"]) await client.close() asyncio.run(main()) ``` **JavaScript / TypeScript** ```typescript import { PromptRails } from '@promptrails/sdk' const client = new PromptRails({ apiKey: 'your-api-key-here', }) const result = await client.agents.execute('your-agent-id', { input: { message: 'What is the capital of France?', }, }) console.log(result.data.output) ``` **Go** ```go package main import ( "context" "fmt" "log" promptrails "github.com/promptrails/go-sdk" ) func main() { client := promptrails.NewClient("your-api-key-here") ctx := context.Background() result, err := client.Agents.Execute(ctx, "your-agent-id", &promptrails.ExecuteAgentParams{ Input: map[string]any{"message": "What is the capital of France?"}, Sync: true, }) if err != nil { log.Fatal(err) } fmt.Println(result.Data.Output) } ``` ## Step 4: View the Execution After executing an agent, you can retrieve the execution details including status, output, token usage, and cost. **Python** ```python # List recent executions executions = client.executions.list(page=1, limit=10) for execution in executions["data"]: print(f"ID: {execution['id']}") print(f"Status: {execution['status']}") print(f"Cost: ${execution['cost']:.6f}") print(f"Duration: {execution['duration_ms']}ms") print("---") ``` **JavaScript / TypeScript** ```typescript const executions = await client.executions.list({ page: 1, limit: 10 }) for (const execution of executions.data) { console.log(`ID: ${execution.id}`) console.log(`Status: ${execution.status}`) console.log(`Cost: $${execution.cost.toFixed(6)}`) console.log(`Duration: ${execution.duration_ms}ms`) console.log('---') } ``` **Go** ```go executions, err := client.Executions.List(ctx, &promptrails.ListExecutionsParams{ Page: 1, Limit: 10, }) if err != nil { log.Fatal(err) } for _, exec := range executions.Data { fmt.Printf("ID: %s\n", exec.ID) fmt.Printf("Status: %s\n", exec.Status) fmt.Println("---") } ``` ## Step 5: View Traces Every execution produces a detailed trace showing the full execution flow, including LLM calls, tool invocations, guardrail evaluations, and more. **Python** ```python # Get traces for a specific execution traces = client.traces.list(execution_id="your-execution-id") for span in traces["data"]: print(f"Span: {span['name']} ({span['kind']})") print(f"Status: {span['status']}") print(f"Duration: {span['duration_ms']}ms") if span.get("cost"): print(f"Cost: ${span['cost']:.6f}") print("---") ``` **JavaScript / TypeScript** ```typescript const traces = await client.traces.list({ executionId: 'your-execution-id', }) for (const span of traces.data) { console.log(`Span: ${span.name} (${span.kind})`) console.log(`Status: ${span.status}`) console.log(`Duration: ${span.duration_ms}ms`) if (span.cost) { console.log(`Cost: $${span.cost.toFixed(6)}`) } console.log('---') } ``` **Go** ```go traces, err := client.Traces.List(ctx, &promptrails.ListTracesParams{ ExecutionID: "your-execution-id", }) if err != nil { log.Fatal(err) } for _, span := range traces.Data { fmt.Printf("Span: %s (%s)\n", span.Name, span.Kind) fmt.Printf("Status: %s\n", span.Status) fmt.Println("---") } ``` ## Step 6: Use Chat Sessions For multi-turn conversations, use the chat API to maintain conversation context across messages. **Python** ```python # Create a chat session session = client.chat.create_session(agent_id="your-agent-id") # Send messages response = client.chat.send_message( session.id, content="Hello, tell me about machine learning." ) print(response.content) # Continue the conversation response = client.chat.send_message( session.id, content="Can you give me a specific example?" ) print(response.content) ``` **JavaScript / TypeScript** ```typescript // Create a chat session const session = await client.chat.createSession({ agentId: 'your-agent-id', }) // Send messages const response = await client.chat.sendMessage(session.id, { content: 'Hello, tell me about machine learning.', }) console.log(response.content) // Continue the conversation const followUp = await client.chat.sendMessage(session.id, { content: 'Can you give me a specific example?', }) console.log(followUp.content) ``` ## Next Steps Now that you have executed your first agent, explore these topics to build more sophisticated AI applications: - [Agents](/docs/agents) -- Learn about the five agent types and how to configure them - [Prompts](/docs/prompts) -- Manage versioned prompts with Jinja2 templating - [Guardrails](/docs/guardrails) -- Add safety scanners to your agents - [MCP Tools](/docs/mcp-tools) -- Give your agents access to external tools - [Tracing](/docs/tracing) -- Deep-dive into execution observability - [API Keys and Scopes](/docs/api-keys-and-scopes) -- Configure fine-grained access control --- # Agents Source: https://promptrails.ai/docs/agents > Learn about PromptRails agents, the five agent types, configuration options, and how to create and manage AI agents. # Agents Agents are the core building blocks of PromptRails. An agent encapsulates an AI execution strategy, combining prompts, tools, data sources, guardrails, and memory into a single deployable unit. ## What is an Agent? An agent defines how an AI task is executed. It specifies: - Which prompts to use and in what order - Which LLM model to call - What tools are available for the agent to invoke - What guardrails to apply on input and output - How to handle multi-step reasoning, chaining, or orchestration - Input and output schemas for structured data handling Agents are workspace-scoped and identified by KSUID (K-Sortable Unique Identifiers). ## Agent Types PromptRails supports five agent types, each implementing a different execution strategy. ### Simple A simple agent executes a single prompt against an LLM. This is the most straightforward agent type, suitable for question-answering, text generation, classification, and other single-turn tasks. ``` Input -> Prompt Rendering -> LLM Call -> Output ``` ### Chain A chain agent executes multiple prompts sequentially, where the output of one step becomes the input for the next. Use chains for multi-step reasoning, data transformation pipelines, or tasks that require intermediate processing. ``` Input -> Prompt 1 -> LLM -> Prompt 2 -> LLM -> ... -> Output ``` ### Multi-Agent A multi-agent configuration runs multiple agents in parallel or routes between them based on the input. This is useful for ensemble approaches, specialized sub-agents, or tasks that benefit from multiple perspectives. ``` Input -> [Agent A, Agent B, Agent C] -> Aggregation -> Output ``` ### Workflow A workflow agent defines a directed graph of steps with conditional branching. Each step can be a prompt execution, tool call, data source query, or sub-agent invocation. Workflow agents support complex business logic with decision points. ``` Input -> Step 1 -> Condition -> Step 2a or Step 2b -> ... -> Output ``` ### Composite A composite agent combines multiple agent types into a single higher-level agent. It can orchestrate chains, workflows, and simple agents together, enabling the most complex execution patterns. ## Agent Configuration Each agent version carries a `config` object whose shape is a **typed discriminated union** keyed on the agent type — one of `SimpleAgentConfig`, `ChainAgentConfig`, `MultiAgentConfig`, `WorkflowAgentConfig`, or `CompositeAgentConfig`. The official SDKs expose each variant as a dedicated type; callers pick the one that matches the agent's type, and the SDK emits the `type` discriminator automatically. Common fields across all variants: | Field | Description | | -------------------------- | ------------------------------------------------------------- | | `temperature` | Sampling temperature (0.0 to 1.0). Simple agent only. | | `max_tokens` | Maximum tokens in the LLM response. Simple agent only. | | `llm_model_id` | LLM model identifier. Simple agent only. | | `approval_required` | Whether execution pauses for human approval (simple / chain). | | `approval_checkpoint_name` | Name of the approval checkpoint (simple / chain). | Type-specific fields: | Agent type | Config field | | ------------- | --------------------------------------- | | `simple` | `prompt_id` — one prompt per execution | | `chain` | `prompt_ids: PromptLink[]` — sequential | | `multi_agent` | `prompt_ids: PromptLink[]` — parallel | | `workflow` | `nodes: WorkflowNode[]` — DAG | | `composite` | `steps: CompositeStep[]` — sub-agents | Tools, data sources, guardrails, and memory are attached to the agent itself (or per-prompt) rather than via the config object — see [MCP Tools](/docs/mcp-tools), [Guardrails](/docs/guardrails), and [Memory](/docs/memory). See [Agent Versioning](/docs/agent-versioning#creating-a-version) for typed examples in all three SDKs. ## Agent Status Agents have two lifecycle states: | Status | Description | | ---------- | -------------------------------------------------------- | | `active` | The agent is available for execution | | `archived` | The agent is hidden from listings and cannot be executed | Archiving an agent is a soft operation -- the agent and its versions are preserved and can be restored. ## Creating an Agent **Python SDK** ```python from promptrails import PromptRails client = PromptRails(api_key="your-api-key") agent = client.agents.create( name="Customer Support Bot", description="Handles customer inquiries about products and orders", type="simple", labels=["support", "production"] ) print(f"Agent created: {agent['data']['id']}") ``` **JavaScript SDK** ```typescript import { PromptRails } from '@promptrails/sdk' const client = new PromptRails({ apiKey: 'your-api-key' }) const agent = await client.agents.create({ name: 'Customer Support Bot', description: 'Handles customer inquiries about products and orders', type: 'simple', labels: ['support', 'production'], }) console.log(`Agent created: ${agent.data.id}`) ``` ## Managing Agents ### List Agents ```python agents = client.agents.list(page=1, limit=20) for agent in agents["data"]: print(f"{agent['name']} ({agent['type']}) - {agent['status']}") ``` ### Get Agent Details ```python agent = client.agents.get(agent_id="your-agent-id") print(agent["data"]["current_version"]) ``` ### Update an Agent ```python client.agents.update( agent_id="your-agent-id", name="Updated Bot Name", description="Updated description" ) ``` ### Archive an Agent ```python client.agents.update( agent_id="your-agent-id", status="archived" ) ``` ## Executing an Agent Execute an agent by providing input that matches the agent's input schema: ```python result = client.agents.execute( agent_id="your-agent-id", input={ "message": "I need help with my order #12345" }, metadata={ "user_id": "customer-456", "channel": "web" } ) print(f"Status: {result['data']['status']}") print(f"Output: {result['data']['output']}") print(f"Cost: ${result['data']['cost']:.6f}") print(f"Duration: {result['data']['duration_ms']}ms") ``` ## Input and Output Schemas Agent versions can define JSON schemas for structured input and output validation: ```json { "input_schema": { "type": "object", "properties": { "message": { "type": "string" }, "language": { "type": "string", "default": "en" } }, "required": ["message"] }, "output_schema": { "type": "object", "properties": { "response": { "type": "string" }, "confidence": { "type": "number" } } } } ``` Input schemas are validated before execution. Output schemas define the expected structure of the agent's response. ## Labels Agents support arbitrary string labels for organization and filtering: ```python agent = client.agents.create( name="My Agent", type="simple", labels=["production", "customer-facing", "v2"] ) ``` ## Related Topics - [Agent Versioning](/docs/agent-versioning) -- Version management for agents - [Prompts](/docs/prompts) -- Prompt templates used by agents - [Guardrails](/docs/guardrails) -- Input/output safety scanners - [MCP Tools](/docs/mcp-tools) -- External tools available to agents - [Executions](/docs/executions) -- Execution lifecycle and monitoring --- # Agent Versioning Source: https://promptrails.ai/docs/agent-versioning > Manage agent versions, promote configurations, and roll back changes with PromptRails' immutable versioning system. # Agent Versioning PromptRails uses an immutable versioning system for agents. Every configuration change creates a new version, and you can promote any version to be the current active configuration. This enables safe iteration, A/B testing, and instant rollbacks. ## How Versioning Works Each agent has one or more **versions**. A version captures the complete execution configuration at a point in time: - Configuration object (system prompt, model, temperature, tools, etc.) - Input and output schemas - Linked prompt versions (with roles and sort order) - Version identifier (e.g., `v1`, `v2`, `v3`) - Version message (release notes) Versions are immutable once created. To change an agent's behavior, you create a new version rather than modifying an existing one. ### Current Version Exactly one version per agent is marked as `is_current = true`. When an agent is executed without specifying a version, the current version is used. The current version is what API consumers and chat sessions interact with by default. ## Creating a Version Config is a **typed discriminated union by agent type** — `SimpleAgentConfig`, `ChainAgentConfig`, `MultiAgentConfig`, `WorkflowAgentConfig`, or `CompositeAgentConfig`. The SDK injects the `type` discriminator automatically and catches schema mismatches (like `prompt_version_id` → `prompt_id`) at compile time instead of runtime. **Python SDK** ```python from promptrails import SimpleAgentConfig version = client.agents.create_version( agent_id="your-agent-id", version="1.0.0", config=SimpleAgentConfig( prompt_id="your-prompt-id", temperature=0.7, max_tokens=1024, approval_required=False, ), input_schema={ "type": "object", "properties": { "message": {"type": "string"} }, "required": ["message"] }, message="Initial version", ) print(f"Version created: {version.version}") ``` **JavaScript SDK** ```typescript import { SimpleAgentConfig } from '@promptrails/sdk' const simple: SimpleAgentConfig = { type: 'simple', prompt_id: 'your-prompt-id', temperature: 0.7, max_tokens: 1024, approval_required: false, } const version = await client.agents.createVersion('your-agent-id', { version: '1.0.0', config: simple, input_schema: { type: 'object', properties: { message: { type: 'string' }, }, required: ['message'], }, message: 'Initial version', }) console.log(`Version created: ${version.data.version}`) ``` **Go SDK** ```go simple := promptrails.SimpleAgentConfig{ PromptID: "your-prompt-id", Temperature: &temperature, MaxTokens: 1024, } version, err := client.Agents.CreateVersion(ctx, "your-agent-id", &promptrails.CreateVersionParams{ Version: "1.0.0", Config: simple, Message: "Initial version", }) ``` For chain, multi-agent, workflow, and composite configs see the [Linked Prompts](#linked-prompts) section below. ## Promoting a Version Promoting a version sets it as the current active configuration for the agent. The previously current version is demoted automatically. **Python SDK** ```python client.agents.promote_version( agent_id="your-agent-id", version_id="version-id-to-promote" ) ``` **JavaScript SDK** ```typescript await client.agents.promoteVersion('your-agent-id', 'version-id-to-promote') ``` After promotion, all new executions (unless a specific version is requested) will use the newly promoted version. ## Version History List all versions of an agent to review the change history: ```python versions = client.agents.list_versions(agent_id="your-agent-id") for v in versions["data"]: current = " (current)" if v["is_current"] else "" print(f"{v['version']}{current} - {v['message']} - {v['created_at']}") ``` ## Rolling Back To roll back to a previous version, simply promote it: ```python # List versions to find the one to roll back to versions = client.agents.list_versions(agent_id="your-agent-id") # Promote the previous version previous_version = versions["data"][1] # second most recent client.agents.promote_version( agent_id="your-agent-id", version_id=previous_version["id"] ) print(f"Rolled back to {previous_version['version']}") ``` Rollbacks are instant because versions are immutable -- there is no rebuild or redeployment step. ## Version Content Each version includes: | Field | Type | Description | | --------------- | --------- | ------------------------------------------------ | | `id` | KSUID | Unique version identifier | | `agent_id` | KSUID | Parent agent ID | | `version` | string | Version label (e.g., `v1`, `v2`) | | `config` | JSON | Complete execution configuration | | `input_schema` | JSON | Input validation schema | | `output_schema` | JSON | Output structure schema | | `is_current` | boolean | Whether this is the active version | | `message` | string | Version message / release notes | | `created_at` | timestamp | When the version was created | | `prompts` | array | Linked prompt versions with roles and sort order | ## Linked Prompts Chain, multi-agent, workflow, and composite configs reference prompts through a `PromptLink`: | Field | Description | | ------------ | --------------------------------------------------------------------------------------------------------------------- | | `prompt_id` | The prompt to use. Execution **auto-follows the prompt's current version** — you don't pin a specific prompt version. | | `role` | The role of the prompt in the agent (e.g., `main`, `writer`, `critic`) | | `sort_order` | Execution order for chain-type agents | Auto-follow means promoting a new prompt version instantly changes the behaviour of every agent linked to that prompt — no agent version bump required. If you want deterministic, pinned behaviour, cut a new prompt (rather than a new version) and switch the agent to link to it. ### Chain example ```python from promptrails import ChainAgentConfig, PromptLink chain = ChainAgentConfig( prompt_ids=[ PromptLink(prompt_id="researcher-prompt-id", role="research", sort_order=0), PromptLink(prompt_id="writer-prompt-id", role="write", sort_order=1), ], ) client.agents.create_version(agent_id="your-agent-id", version="1.0.0", config=chain) ``` > **Breaking change (SDK v0.3).** The old opaque > `config: Dict[str, Any]` / `Record` / > `map[string]any` is gone. The config JSON key > `prompt_ids[].prompt_version_id` was renamed to > `prompt_ids[].prompt_id`. Typed SDK callers don't need to touch > anything — the SDK emits the right shape. ## Best Practices - **Always include a version message** describing what changed and why - **Test new versions** by executing them directly (by version ID) before promoting - **Keep previous versions** as they serve as an audit trail and enable instant rollbacks - **Use input/output schemas** to catch breaking changes early - **Coordinate prompt and agent versions** -- when updating prompts, create a new agent version that links to the new prompt versions --- # Prompts Source: https://promptrails.ai/docs/prompts > Manage versioned prompts with Jinja2 templating, model assignment, caching, and structured input/output schemas. # Prompts Prompts are the instructions that guide LLM behavior. PromptRails provides a full prompt management system with versioning, templating, model assignment, and caching -- all configurable through the UI or API. ## Prompt Management Overview A prompt in PromptRails consists of: - **System prompt** -- Instructions that define the LLM's role and behavior - **User prompt** -- A template that renders the user's input into a structured message - **Model assignment** -- Which LLM model to use (with optional fallback) - **Parameters** -- Temperature, max tokens, top_p - **Input/output schemas** -- JSON schemas for validation - **Cache timeout** -- How long to cache responses - **Version history** -- Immutable versions with promotion Prompts are workspace-scoped and can be linked to one or more agents. ## Jinja2 Templating PromptRails uses Jinja2 templating for prompt rendering. This allows you to create dynamic prompts that incorporate variables from the execution input. ### Basic Variables ```jinja2 You are a customer support agent for {{ company_name }}. The customer's name is {{ customer_name }}. Please help them with their inquiry: {{ message }} ``` ### Conditionals ```jinja2 You are a {{ role }} assistant. {% if language == "spanish" %} Please respond in Spanish. {% elif language == "french" %} Please respond in French. {% else %} Please respond in English. {% endif %} User query: {{ message }} ``` ### Loops ```jinja2 Here are the relevant documents for context: {% for doc in documents %} Document {{ loop.index }}: {{ doc.title }} Content: {{ doc.content }} --- {% endfor %} Based on the above documents, answer: {{ question }} ``` ### Filters ```jinja2 Customer name: {{ name | upper }} Order date: {{ date | default("Unknown") }} Summary: {{ long_text | truncate(200) }} ``` ## Input and Output Schemas Define JSON schemas to validate inputs before prompt rendering and structure outputs from the LLM. ### Input Schema ```json { "type": "object", "properties": { "message": { "type": "string", "description": "The user's message" }, "language": { "type": "string", "enum": ["en", "es", "fr", "de"], "default": "en" }, "context": { "type": "array", "items": { "type": "string" } } }, "required": ["message"] } ``` ### Output Schema ```json { "type": "object", "properties": { "response": { "type": "string" }, "sentiment": { "type": "string", "enum": ["positive", "neutral", "negative"] }, "confidence": { "type": "number", "minimum": 0, "maximum": 1 } } } ``` ## Model Assignment Each prompt version specifies which LLM model to use: - **Primary model** -- The default model for execution - **Fallback model** -- Used if the primary model fails or is unavailable Supported providers include OpenAI, Anthropic, Google Gemini, DeepSeek, Fireworks, xAI, and OpenRouter. Models are configured globally and referenced by their PromptRails ID. ## Temperature, Max Tokens, and Top P | Parameter | Default | Range | Description | | ------------- | ---------------- | --------------- | --------------------------------------------------------------------- | | `temperature` | 0.7 | 0.0 - 1.0 | Controls randomness. Lower values produce more deterministic outputs. | | `max_tokens` | Provider default | Varies by model | Maximum number of tokens in the response. | | `top_p` | Provider default | 0.0 - 1.0 | Nucleus sampling. Controls diversity by limiting the token pool. | ## Prompt Caching PromptRails supports response caching at the prompt version level. When `cache_timeout` is set to a value greater than 0 (in seconds), identical inputs will return cached responses without making an LLM call. ```python version = client.prompts.create_version( prompt_id="your-prompt-id", system_prompt="You are a helpful assistant.", user_prompt="Translate '{{ text }}' to {{ target_language }}.", temperature=0.3, cache_timeout=3600, # Cache responses for 1 hour message="Added caching for translation prompt" ) ``` Caching is keyed on the rendered prompt content (after template variables are substituted), so different inputs produce different cache entries. ## Creating Prompts **Python SDK** ```python # Create a prompt prompt = client.prompts.create( name="Product Description Generator", description="Generates product descriptions from features" ) # Create the first version version = client.prompts.create_version( prompt_id=prompt["data"]["id"], system_prompt="You are an expert copywriter who writes compelling product descriptions.", user_prompt="""Write a product description for: Product: {{ product_name }} Category: {{ category }} Features: {% for feature in features %} - {{ feature }} {% endfor %} The description should be {{ tone }} and approximately {{ word_count }} words.""", input_schema={ "type": "object", "properties": { "product_name": {"type": "string"}, "category": {"type": "string"}, "features": {"type": "array", "items": {"type": "string"}}, "tone": {"type": "string", "default": "professional"}, "word_count": {"type": "integer", "default": 150} }, "required": ["product_name", "features"] }, temperature=0.8, max_tokens=512, message="Initial version" ) ``` **JavaScript SDK** ```typescript const prompt = await client.prompts.create({ name: 'Product Description Generator', description: 'Generates product descriptions from features', }) const version = await client.prompts.createVersion(prompt.data.id, { systemPrompt: 'You are an expert copywriter who writes compelling product descriptions.', userPrompt: `Write a product description for: Product: {{ product_name }} Category: {{ category }} Features: {% for feature in features %} - {{ feature }} {% endfor %}`, temperature: 0.8, maxTokens: 512, message: 'Initial version', }) ``` ## Testing Prompts Execute a prompt directly to test it without going through an agent: ```python result = client.prompts.execute( prompt_id="your-prompt-id", input={ "product_name": "Wireless Earbuds Pro", "category": "Electronics", "features": [ "Active noise cancellation", "30-hour battery life", "IPX5 water resistance" ], "tone": "enthusiastic" } ) print(result["data"]["output"]) ``` ## Prompt Status | Status | Description | | ---------- | --------------------------------------------------------- | | `active` | The prompt is available for use and execution | | `archived` | The prompt is hidden from listings and cannot be executed | ## Related Topics - [Prompt Versioning](/docs/prompt-versioning) -- Version management and promotion - [Agents](/docs/agents) -- How agents use prompts - [Tracing](/docs/tracing) -- Prompt rendering appears as `prompt` spans in traces --- # Prompt Versioning Source: https://promptrails.ai/docs/prompt-versioning > Version control for prompts with immutable versions, promotion, rollback, and release notes. # Prompt Versioning PromptRails provides immutable versioning for prompts, similar to agent versioning. Every change to a prompt's template, model assignment, or parameters creates a new version that can be tested independently before being promoted to production. ## How It Works Each prompt has one or more versions. A version captures: - System prompt text - User prompt template - Primary and fallback LLM model assignments - Temperature, max tokens, and top_p parameters - Input and output schemas - Cache timeout - Configuration object - Version message (release notes) Exactly one version per prompt is marked as `is_current`. This is the version used when an agent references the prompt without specifying a particular version. ## Version Fields | Field | Type | Description | | ----------------------- | --------- | -------------------------------------------- | | `id` | KSUID | Unique version identifier | | `prompt_id` | KSUID | Parent prompt ID | | `version` | string | Version label (e.g., `v1`, `v2`) | | `system_prompt` | string | System instructions for the LLM | | `user_prompt` | string | User message template (Jinja2) | | `llm_model_id` | KSUID | Primary LLM model | | `fallback_llm_model_id` | KSUID | Fallback LLM model | | `temperature` | float | Sampling temperature (0.0 - 1.0) | | `max_tokens` | integer | Maximum response tokens | | `top_p` | float | Nucleus sampling parameter | | `input_schema` | JSON | Input validation schema | | `output_schema` | JSON | Output structure schema | | `cache_timeout` | integer | Response cache TTL in seconds (0 = disabled) | | `config` | JSON | Additional configuration | | `is_current` | boolean | Whether this is the active version | | `message` | string | Version message / release notes | | `created_at` | timestamp | Creation timestamp | ## Creating a Version ```python version = client.prompts.create_version( prompt_id="your-prompt-id", system_prompt="You are a concise technical writer.", user_prompt="Summarize the following text in {{ max_sentences }} sentences:\n\n{{ text }}", temperature=0.5, max_tokens=256, input_schema={ "type": "object", "properties": { "text": {"type": "string"}, "max_sentences": {"type": "integer", "default": 3} }, "required": ["text"] }, message="Reduced temperature for more consistent summaries" ) ``` ## Promoting a Version Promotion sets a version as the current active version. The previously current version is automatically demoted. ```python client.prompts.promote_version( prompt_id="your-prompt-id", version_id="version-id-to-promote" ) ``` After promotion: - All agents referencing this prompt (via their current agent version) will use the newly promoted prompt version - Previous executions retain their original prompt version in the trace for reproducibility ## Viewing Version History ```python versions = client.prompts.list_versions(prompt_id="your-prompt-id") for v in versions["data"]: current_marker = " *" if v["is_current"] else "" print(f"{v['version']}{current_marker} | {v['message']} | {v['created_at']}") ``` ## Rolling Back Rolling back is simply promoting a previous version: ```python # Find the version you want to restore versions = client.prompts.list_versions(prompt_id="your-prompt-id") target = versions["data"][1] # previous version # Promote it client.prompts.promote_version( prompt_id="your-prompt-id", version_id=target["id"] ) ``` Since versions are immutable, rollback is instant and safe. The "rolled back from" version remains in history and can be re-promoted later. ## Version Messages Always include a descriptive message when creating a version. This serves as release notes and makes the version history meaningful: ```python # Good version messages "Initial prompt for customer support agent" "Reduced temperature from 0.9 to 0.5 for more consistent output" "Added fallback model (Claude) for reliability" "Updated system prompt to handle refund requests" "Switched to GPT-4o for improved accuracy on complex queries" ``` ## Best Practices - **One change per version** -- Make focused changes so you can isolate the impact of each modification - **Test before promoting** -- Execute the prompt version directly to verify behavior before making it current - **Document changes** -- Use version messages to explain what changed and why - **Coordinate with agent versions** -- When creating a new agent version, explicitly link it to the desired prompt versions to avoid unintended changes - **Use cache timeouts** -- For deterministic prompts (translation, classification), enable caching to reduce LLM costs and latency --- # Data Sources Source: https://promptrails.ai/docs/data-sources > Connect databases and static files to your agents with versioned query templates and parameterized queries. # Data Sources Data sources allow your agents to query external databases and files during execution. PromptRails supports multiple database technologies and provides versioned, parameterized query templates that can be safely used by agents. ## What Are Data Sources? A data source represents a connection to an external data store. It defines: - The database technology (PostgreSQL, MySQL, BigQuery, etc.) - Connection credentials (linked to an encrypted credential) - A query template with parameters - Caching configuration - Version history for safe iteration When an agent executes, it can query its linked data sources to retrieve contextual information, look up records, or pull analytics data. ## Supported Databases | Type | Identifier | Description | | --------------- | ------------- | -------------------------------- | | **PostgreSQL** | `postgresql` | Standard PostgreSQL databases | | **MySQL** | `mysql` | MySQL and MariaDB databases | | **BigQuery** | `bigquery` | Google BigQuery data warehouse | | **Snowflake** | `snowflake` | Snowflake cloud data platform | | **Redshift** | `redshift` | Amazon Redshift data warehouse | | **MSSQL** | `mssql` | Microsoft SQL Server | | **ClickHouse** | `clickhouse` | ClickHouse analytics database | | **Static File** | `static_file` | CSV, JSON, or other static files | ## Query Templates Data source versions include a query template that uses parameter placeholders. Parameters are substituted at execution time from the agent's input. ### Example: PostgreSQL Query ```sql SELECT order_id, status, total_amount, created_at FROM orders WHERE customer_id = :customer_id AND status = :status ORDER BY created_at DESC LIMIT :limit ``` ### Parameters Each query template defines its parameters: ```json [ { "name": "customer_id", "type": "string", "required": true, "description": "The customer's unique identifier" }, { "name": "status", "type": "string", "required": false, "default": "active", "description": "Order status filter" }, { "name": "limit", "type": "integer", "required": false, "default": "10", "description": "Maximum number of results" } ] ``` ## Creating a Data Source **Python SDK** ```python # Create the data source ds = client.data_sources.create( name="Customer Orders", description="Query customer order history", type="postgresql" ) # Create a version with query template version = client.data_sources.create_version( data_source_id=ds["data"]["id"], credential_id="your-postgresql-credential-id", query_template=""" SELECT order_id, status, total_amount, created_at FROM orders WHERE customer_id = :customer_id ORDER BY created_at DESC LIMIT :limit """, parameters=[ {"name": "customer_id", "type": "string", "required": True}, {"name": "limit", "type": "integer", "required": False, "default": "10"} ], cache_timeout=300, message="Initial query for customer orders" ) ``` **JavaScript SDK** ```typescript const ds = await client.dataSources.create({ name: 'Customer Orders', description: 'Query customer order history', type: 'postgresql', }) const version = await client.dataSources.createVersion(ds.data.id, { credentialId: 'your-postgresql-credential-id', queryTemplate: ` SELECT order_id, status, total_amount, created_at FROM orders WHERE customer_id = :customer_id ORDER BY created_at DESC LIMIT :limit `, parameters: [ { name: 'customer_id', type: 'string', required: true }, { name: 'limit', type: 'integer', required: false, default: '10' }, ], cacheTimeout: 300, message: 'Initial query for customer orders', }) ``` ## Version Management Data sources use the same immutable versioning pattern as agents and prompts: - Each version captures the query template, parameters, credential, and connection config - Exactly one version per data source is marked as current - Promote versions to make them active - Roll back by promoting a previous version ```python # List versions versions = client.data_sources.list_versions(data_source_id="your-ds-id") # Promote a version client.data_sources.promote_version( data_source_id="your-ds-id", version_id="version-to-promote" ) ``` ## Connection Configuration The `connection_config` object varies by database type. For databases that connect via the credential, this may be minimal. For BigQuery or Snowflake, it may include project/dataset/warehouse identifiers. ## Cache Timeout Each version specifies a `cache_timeout` in seconds: - `0` -- No caching (every query hits the database) - `3600` -- Cache results for 1 hour (default) - Any positive integer -- Cache duration in seconds Caching is keyed on the rendered query (after parameter substitution), so different parameter values produce independent cache entries. ## Output Format Data source versions support configurable output formats: - `json` (default) -- Query results as JSON arrays - `csv` -- Query results as CSV text ## Test Connections Before using a data source in production, test the connection: ```python result = client.data_sources.execute( data_source_id="your-ds-id", parameters={ "customer_id": "test-customer", "limit": 5 } ) print(f"Status: {result['data']['status']}") print(f"Duration: {result['data']['duration_ms']}ms") print(f"Results: {result['data']['result']}") ``` ## Using Data Sources in Agents Link data sources to agents through the agent version configuration. When the agent executes, it can query linked data sources as part of its pipeline: 1. The agent receives input 2. Parameters from the input are mapped to data source query parameters 3. The query is executed and results are returned 4. Results are injected into the prompt context for the LLM This enables agents to provide data-grounded responses based on real-time database queries. ## Data Source Status | Status | Description | | ---------- | ---------------------------- | | `active` | Available for use by agents | | `archived` | Hidden and cannot be queried | ## Related Topics - [Credentials](/docs/credentials) -- Database connection credentials - [Agents](/docs/agents) -- Using data sources in agent configurations - [Tracing](/docs/tracing) -- Data source queries appear as `datasource` spans --- # Credentials Source: https://promptrails.ai/docs/credentials > Manage credentials for LLM providers, media providers, data warehouses, and external tools securely. # Credentials Credentials store the API keys, connection strings, and secrets needed to connect to LLM providers, databases, and external services. All credential values are encrypted at rest and are never exposed in API responses. ## Credential Categories Credentials are organized into six categories: ### LLM Credentials Connect to LLM providers for prompt execution and agent orchestration. | Provider | Type Identifier | Description | | ------------- | --------------- | ------------------------------- | | OpenAI | `openai` | GPT-4, GPT-4o, GPT-3.5, etc. | | Anthropic | `anthropic` | Claude 3.5, Claude 3, etc. | | Google Gemini | `gemini` | Gemini Pro, Gemini Ultra, etc. | | DeepSeek | `deepseek` | DeepSeek chat and code models | | Fireworks | `fireworks` | Fireworks AI hosted models | | xAI | `xai` | Grok models | | OpenRouter | `openrouter` | Multi-provider routing | | Together AI | `together_ai` | Together AI hosted models | | Mistral | `mistral` | Mistral AI models | | Cohere | `cohere` | Cohere command and embed models | | Groq | `groq` | Groq high-speed inference | | Perplexity | `perplexity` | Search-augmented Sonar models | ### Speech Credentials Connect to speech providers for text-to-speech and speech-to-text. | Provider | Type Identifier | Description | | ------------ | --------------- | ---------------------------------- | | ElevenLabs | `elevenlabs` | High-quality TTS voices | | Deepgram | `deepgram` | TTS and STT with Nova models | | OpenAI Audio | `openai_audio` | OpenAI TTS (tts-1) and Whisper STT | ### Image Credentials Connect to image generation and editing providers. | Provider | Type Identifier | Description | | ------------ | --------------- | -------------------------------- | | Fal | `fal` | Fast image generation (FLUX, SD) | | Replicate | `replicate` | Run open-source models | | Stability AI | `stability` | Stable Diffusion models | | OpenAI Image | `openai_image` | DALL-E 3 and DALL-E 2 | ### Video Credentials Connect to video generation providers. | Provider | Type Identifier | Description | | -------- | --------------- | ------------------------------ | | Runway | `runway` | Gen-3 Alpha video generation | | Pika | `pika` | AI video generation | | Luma | `luma` | Dream Machine video generation | ### Data Warehouse Credentials Connect to databases for data source queries. | Database | Type Identifier | Description | | ----------- | --------------- | ------------------------------- | | PostgreSQL | `postgresql` | PostgreSQL connection string | | MySQL | `mysql` | MySQL connection string | | BigQuery | `bigquery` | Google BigQuery service account | | Snowflake | `snowflake` | Snowflake account credentials | | Redshift | `redshift` | Amazon Redshift connection | | MSSQL | `mssql` | Microsoft SQL Server | | ClickHouse | `clickhouse` | ClickHouse connection | | Static File | `static_file` | File-based data access | ### Tool Credentials Credentials for external APIs and services used by MCP tools. | Type | Description | | ---------- | ------------------------------------------------------- | | `api_key` | Generic API key authentication | | `oauth` | OAuth token-based authentication | | `database` | Generic database connection (with schema_type required) | | `smtp` | SMTP server credentials | ## Creating Credentials **Python SDK** ```python # LLM credential credential = client.credentials.create( name="OpenAI Production", category="llm", type="openai", value="sk-proj-your-openai-api-key", description="Production OpenAI API key" ) # Data warehouse credential db_credential = client.credentials.create( name="Analytics Database", category="data_warehouse", type="postgresql", value="postgresql://user:password@host:5432/analytics", description="Read-only analytics database" ) # Speech credential speech_credential = client.credentials.create( name="ElevenLabs Production", category="speech", type="elevenlabs", value="your-elevenlabs-api-key", description="ElevenLabs TTS API key" ) # Tool credential tool_credential = client.credentials.create( name="Slack Bot Token", category="tools", type="api_key", value="xoxb-your-slack-bot-token", description="Slack bot for notifications" ) ``` **JavaScript SDK** ```typescript const credential = await client.credentials.create({ name: 'OpenAI Production', category: 'llm', type: 'openai', value: 'sk-proj-your-openai-api-key', description: 'Production OpenAI API key', }) ``` ## Default Credentials You can mark one credential per type as the default. Default credentials are automatically used when no specific credential is specified: ```python client.credentials.set_default(credential_id="your-credential-id") ``` When an agent or prompt references a model from a provider (e.g., OpenAI), PromptRails uses the default credential for that provider type unless overridden. ## Connection Validation Validate that a credential can successfully connect to its target service: ```python result = client.credentials.validate(credential_id="your-credential-id") print(f"Valid: {result['data']['is_valid']}") ``` Validation checks vary by credential type: - LLM credentials: Makes a lightweight API call to verify the key - Database credentials: Attempts a connection and basic query - Tool credentials: Depends on the tool configuration ## Schema Discovery For data warehouse credentials, PromptRails can discover the database schema (tables, columns, types): ```python # Trigger schema discovery client.credentials.discover_schema(credential_id="your-credential-id") # Get the discovered schema credential = client.credentials.get(credential_id="your-credential-id") if credential["data"]["has_schema"]: print(f"Schema updated: {credential['data']['schema_updated_at']}") ``` The discovered schema includes: - Table names - Column names and data types - Nullability - Default values - Descriptions (where available) This schema information helps agents understand the database structure when constructing queries. ## Credential Response API responses include a safe representation of credentials (never the raw value): | Field | Description | | ------------------- | --------------------------------------------------------------- | | `id` | Unique credential identifier | | `name` | Display name | | `type` | Provider or database type | | `category` | `llm`, `speech`, `image`, `video`, `data_warehouse`, or `tools` | | `description` | Optional description | | `masked_content` | Masked credential value (e.g., `sk-pr...abcd`) | | `is_default` | Whether this is the default for its type | | `is_valid` | Whether the last validation check passed | | `has_schema` | Whether schema information is available | | `schema_updated_at` | When the schema was last discovered | | `created_at` | Creation timestamp | | `updated_at` | Last update timestamp | ## Updating Credentials When you update a credential, the new value is encrypted and stored. The previous value cannot be recovered. ```python client.credentials.update( credential_id="your-credential-id", value="new-api-key-value", name="Updated Name" ) ``` ## Deleting Credentials Credentials are soft-deleted. Deleting a credential does not affect historical execution traces but will prevent future use. ```python client.credentials.delete(credential_id="your-credential-id") ``` ## Related Topics - [Media Generation](/docs/media-generation) -- Using credentials for speech, image, and video - [Data Sources](/docs/data-sources) -- Using credentials for database queries - [MCP Tools](/docs/mcp-tools) -- Using credentials for tool authentication - [Security](/docs/security) -- Encryption and security practices --- # MCP Tools Source: https://promptrails.ai/docs/mcp-tools > Connect 50+ integrations, databases, media providers, and custom APIs to your agents using the Model Context Protocol (MCP). # MCP Tools PromptRails provides first-class support for the **Model Context Protocol (MCP)**, enabling your agents to invoke external tools, query databases, generate media, and connect to 50+ third-party services. ## What is MCP? The Model Context Protocol is an open standard for connecting LLMs to external tools and data sources. MCP defines how tools are discovered, described, and invoked, creating a uniform interface between AI agents and the services they interact with. In PromptRails, MCP tools are workspace-scoped resources that can be attached to any agent. When an LLM decides to use a tool during execution, PromptRails handles the invocation, parameter validation, and result formatting. ## Tool Types PromptRails supports six types of MCP tools: ### Integration Tools (`integration`) Integration tools connect to 27+ third-party services through the PromptRails integration service. Each integration provides a set of pre-built tools discovered via the MCP protocol. **Supported integrations:** | Category | Services | | -------------------- | ------------------------------------------------------------------ | | **Google** | Analytics, Search Console, Ads, Drive, Docs, Sheets, Slides, Gmail | | **CRM** | HubSpot, Salesforce, Pipedrive | | **Lead Generation** | Apollo.io | | **Accounting** | Stripe, Xero, QuickBooks | | **Issue Management** | Jira, Confluence, Linear, Trello, Notion | | **Development** | Sentry, Figma, Supabase, GitHub | | **Communication** | Slack, Telegram, Resend | Integration tools are installed from the **MCP Template Marketplace**. Each template handles credential setup, tool discovery, and configuration automatically. Google integrations support both **OAuth2** and **Service Account** authentication, including domain-wide delegation with user impersonation. ### Data Source Tools (`datasource`) Data source tools execute SQL queries against connected databases. They support dynamic queries — the agent writes the SQL at runtime. **Supported databases:** PostgreSQL, MySQL, BigQuery, Snowflake, Redshift, MSSQL, ClickHouse Install database tools from the template marketplace by selecting an existing database credential. The tool provides three actions: - **query** — Execute SQL queries - **list_tables** — List all tables in the database - **describe_table** — Get column details for a table ### Media Tools (`media`) Media tools generate speech, images, and video through AI providers. | Category | Providers | | -------------------- | ----------------------------------- | | **Text to Speech** | ElevenLabs, Deepgram | | **Speech to Text** | Deepgram | | **Image Generation** | Fal (FLUX), Replicate, Stability AI | | **Video Generation** | Runway, Pika, Luma Dream Machine | Media tools use workspace-level credentials configured in Settings > Credentials. ### API Tools (`api`) API tools make HTTP requests to external REST APIs. You define the endpoint, method, headers, and parameter mapping. ### Built-in Tools (`builtin`) Built-in tools provide predefined functionality that runs within the PromptRails platform: - **State Manager** — Store and retrieve key-value state during agent execution - **Math Calculator** — Perform mathematical calculations - **Date & Time** — Get current date and time in UTC ### Remote MCP Tools (`remote_mcp`) Remote MCP tools connect to external MCP servers that implement the full MCP protocol. This allows you to use tools from any MCP-compatible server. ## MCP Template Marketplace The template marketplace provides one-click installation for all supported integrations. Each template includes: - Pre-configured tool definitions - Credential setup with parameter validation - Setup instructions for the service - Automatic tool discovery **To install a template:** 1. Go to **MCP Templates** in your workspace 2. Find the integration you want 3. Enter the required credentials (API key, OAuth tokens, or Service Account) 4. Click **Install** The tool is created with all discovered sub-tools (e.g., installing HubSpot gives you `hubspot_search_contacts`, `hubspot_create_deal`, etc.). ## Tool Schema Each tool defines a JSON schema describing its parameters. This schema is provided to the LLM so it understands what parameters are available: ```json { "type": "object", "properties": { "query": { "type": "string", "description": "The search query" }, "max_results": { "type": "integer", "description": "Maximum number of results", "default": 10 } }, "required": ["query"] } ``` ## Adding Tools to Agents Tools are linked to agents through the agent version configuration in the UI or API. Any tool type can be attached to any agent type. ## Tool Discovery For integration and remote MCP tools, PromptRails discovers available sub-tools from the service. You can view and test discovered tools on the tool detail page under the **Test** tab. ## Tool Status | Status | Description | | ---------- | ----------------------------------- | | `active` | Tool is available for use | | `inactive` | Tool is disabled but not removed | | `error` | Tool encountered a connection error | | `archived` | Tool is permanently disabled | ## Tool Invocation Flow When an agent executes and the LLM decides to call a tool: 1. The LLM generates a tool call with parameters 2. PromptRails validates the parameters against the tool schema 3. The tool is invoked (API call, database query, MCP request, etc.) 4. Results are returned to the LLM for incorporation into the response 5. The entire tool call is recorded as an `mcp_call` trace span ## Related Topics - [Integrations](/integrations) — Browse all 50+ supported integrations - [Agents](/docs/agents) — Attaching tools to agents - [Credentials](/docs/credentials) — Authentication for tool endpoints - [MCP Server](/docs/mcp-server) — PromptRails as an MCP server for IDEs - [Tracing](/docs/tracing) — Tool calls appear as `tool` and `mcp_call` spans --- # Media Generation Source: https://promptrails.ai/docs/media-generation > Generate speech, images, and video using 8 media providers integrated into agents and workflows. # Media Generation PromptRails supports multi-modal media generation through 8 providers across three categories: speech, image, and video. Media providers can be used as MCP tools within agents or as dedicated workflow nodes. ## Providers ### Speech | Provider | Capabilities | Models | | ---------- | -------------------- | --------------------------------------- | | ElevenLabs | Text-to-Speech | eleven_multilingual_v2, eleven_turbo_v2 | | Deepgram | TTS + Speech-to-Text | aura-asteria-en, nova-2 | ### Image | Provider | Capabilities | Models | | ------------ | -------------------------- | ------------------------ | | Fal | Image generation & editing | FLUX, Stable Diffusion | | Replicate | Image generation | SDXL, open-source models | | Stability AI | Image generation & editing | Stable Diffusion 3, SDXL | ### Video | Provider | Capabilities | Models | | -------- | ------------------- | ------------- | | Runway | Text/image-to-video | Gen-3 Alpha | | Pika | Text/image-to-video | Pika 1.0 | | Luma | Text/image-to-video | Dream Machine | ## Using Media in Agents Media generation is available as MCP tools within agent executions. When a media tool is configured on an agent, the LLM can invoke it during execution. ### Available Tool Types - `tts` -- Text-to-speech generation - `stt` -- Speech-to-text transcription - `image_gen` -- Image generation from text prompt - `image_edit` -- Image editing with prompt - `video_gen` -- Video generation from text prompt - `video_from_image` -- Video generation from image + prompt ### Configuration Example ```python # Create an agent with media tools agent = client.agents.create( name="Content Creator", type="simple", config={ "model": "gpt-4o", "credential_id": "your-openai-credential-id", "tools": [ { "type": "media", "media_type": "image_gen", "provider": "fal", "model": "fal-ai/flux/schnell", "credential_id": "your-fal-credential-id" }, { "type": "media", "media_type": "tts", "provider": "elevenlabs", "model": "eleven_multilingual_v2", "credential_id": "your-elevenlabs-credential-id" } ] } ) ``` ## Using Media in Workflows Workflow agents can include media generation nodes alongside LLM and tool nodes. ```python agent = client.agents.create( name="Video Pipeline", type="workflow", config={ "nodes": [ { "id": "generate_script", "type": "llm", "model": "gpt-4o", "credential_id": "your-openai-credential-id", "prompt_id": "script-writer-prompt" }, { "id": "generate_image", "type": "media", "media_provider": "fal", "media_type": "image_gen", "model": "fal-ai/flux/schnell", "credential_id": "your-fal-credential-id" }, { "id": "generate_video", "type": "media", "media_provider": "runway", "media_type": "video_from_image", "model": "gen3a_turbo", "credential_id": "your-runway-credential-id" } ], "edges": [ { "from": "generate_script", "to": "generate_image" }, { "from": "generate_image", "to": "generate_video" } ] } ) ``` ## Video Polling Video generation is asynchronous. When a video job is submitted, PromptRails automatically polls the provider for completion using background workers. The polling configuration is: - **Max attempts**: 60 - **Poll interval**: 10 seconds - **Total timeout**: ~10 minutes Once the video is ready, the generated asset is downloaded and stored in your workspace's asset storage. ## Asset Storage All generated media (audio, images, video) is automatically uploaded to S3-compatible storage and tracked as assets. See [Assets](/docs/assets) for details on managing generated media. ## Tracing Media generation spans appear in execution traces with dedicated span kinds: - `speech` -- TTS and STT operations - `image` -- Image generation and editing - `video` -- Video generation Each span includes the provider, model, prompt, output URL, and estimated cost. See [Tracing](/docs/tracing) for more details. ## Related Topics - [Credentials](/docs/credentials) -- Setting up media provider credentials - [Assets](/docs/assets) -- Managing generated media files - [Agents](/docs/agents) -- Agent configuration - [Tracing](/docs/tracing) -- Execution observability --- # Assets Source: https://promptrails.ai/docs/assets > Browse, manage, and download media assets generated by agent executions. # Assets Assets are media files generated during agent executions -- audio from TTS, images from generation tools, and video from video providers. All assets are stored in S3-compatible storage and tracked with metadata for easy browsing and management. ## Asset Properties | Field | Description | | -------------- | ------------------------------------------- | | `id` | Unique asset identifier (KSUID) | | `workspace_id` | Workspace the asset belongs to | | `execution_id` | Execution that generated the asset | | `agent_id` | Agent that generated the asset | | `type` | `audio`, `image`, or `video` | | `provider` | Media provider (e.g., `elevenlabs`, `fal`) | | `file_name` | Original or generated file name | | `file_size` | Size in bytes | | `content_type` | MIME type (e.g., `image/png`, `audio/mpeg`) | | `storage_key` | S3 object key | | `metadata` | Additional metadata (model, prompt, etc.) | | `created_at` | Creation timestamp | ## Listing Assets ```python # List all assets assets = client.assets.list() # Filter by type images = client.assets.list(type="image") # Filter by provider fal_assets = client.assets.list(provider="fal") # Filter by execution exec_assets = client.assets.list(execution_id="your-execution-id") ``` ## Downloading Assets Assets are served via signed URLs with configurable expiration: ```python # Get a signed download URL signed = client.assets.get_signed_url(asset_id="your-asset-id") print(signed["url"]) # Temporary signed URL ``` ## Deleting Assets ```python client.assets.delete(asset_id="your-asset-id") ``` Deleting an asset removes the file from storage and the metadata record. This action is irreversible. ## Storage Configuration Asset storage uses S3-compatible backends. Configure via environment variables: | Variable | Description | | -------------------------- | ----------------------------------------- | | `STORAGE_ENDPOINT` | S3-compatible endpoint URL | | `STORAGE_REGION` | Storage region | | `STORAGE_BUCKET` | Bucket name | | `STORAGE_ACCESS_KEY_ID` | Access key ID | | `STORAGE_SECRET_KEY` | Secret access key | | `STORAGE_PUBLIC_URL` | Public URL prefix for assets | | `STORAGE_FORCE_PATH_STYLE` | Use path-style addressing (default: true) | Compatible with Railway Storage Buckets, MinIO, AWS S3, Cloudflare R2, and other S3-compatible services. ## Related Topics - [Media Generation](/docs/media-generation) -- Generating media with providers - [Tracing](/docs/tracing) -- Viewing media spans in execution traces - [Executions](/docs/executions) -- Execution lifecycle and outputs --- # Guardrails Source: https://promptrails.ai/docs/guardrails > Protect your agents with 14 built-in scanner types for input and output validation, including toxicity detection, PII filtering, and prompt injection prevention. # Guardrails Guardrails are safety scanners that validate agent inputs and outputs before and after LLM execution. They protect against harmful content, data leakage, prompt injection, and other risks. ## What Are Guardrails? A guardrail is a scanner attached to an agent that inspects content at a specific point in the execution pipeline: - **Input guardrails** scan the user's input before it reaches the LLM - **Output guardrails** scan the LLM's response before it is returned to the user Each guardrail has a scanner type, an action to take when triggered, and a sort order that determines the evaluation sequence. ## Direction: Input vs Output | Direction | When It Runs | Purpose | | --------- | -------------------- | ------------------------------------------------------------------------- | | `input` | Before LLM execution | Validate user input, block prompt injection, detect PII | | `output` | After LLM execution | Filter harmful responses, redact sensitive data, enforce content policies | ## Scanner Types PromptRails includes 14 built-in scanner types: ### Content Safety | Scanner | Identifier | Description | | ------------------- | ------------ | ---------------------------------------------------------------------- | | **Toxicity** | `toxicity` | Detects toxic, abusive, or hateful language in text | | **Harmful Content** | `harmful` | Identifies content that promotes harm, violence, or illegal activities | | **Bias Detection** | `bias` | Detects biased or discriminatory language | | **No Refusal** | `no_refusal` | Ensures the LLM does not refuse to answer (output only) | ### Data Protection | Scanner | Identifier | Description | | --------------------- | ----------- | -------------------------------------------------------------------------------------- | | **PII Detection** | `pii` | Detects personally identifiable information (names, emails, phone numbers, SSNs, etc.) | | **Anonymize** | `anonymize` | Replaces detected PII with placeholder tokens | | **Secrets Detection** | `secrets` | Detects API keys, passwords, tokens, and other secrets in text | | **Sensitive Data** | `sensitive` | Detects broader categories of sensitive information | ### Security | Scanner | Identifier | Description | | -------------------- | ------------------ | ---------------------------------------------------------------------------- | | **Prompt Injection** | `prompt_injection` | Detects attempts to override system instructions or inject malicious prompts | | **Invisible Text** | `invisible_text` | Detects hidden Unicode characters or zero-width text used for injection | | **Malicious URLs** | `malicious_urls` | Detects known malicious, phishing, or suspicious URLs | ### Content Filtering | Scanner | Identifier | Description | | ---------------------- | ---------------- | ----------------------------------------------------------- | | **Substring Ban** | `ban_substrings` | Blocks content containing specified banned words or phrases | | **Topic Ban** | `ban_topics` | Blocks content related to specified banned topics | | **Language Detection** | `language` | Ensures content is in the expected language(s) | ## Actions When a guardrail scanner triggers, it takes one of three actions: | Action | Behavior | | -------- | ------------------------------------------------------------------------ | | `block` | Stops execution and returns an error. The LLM response is not delivered. | | `redact` | Removes or replaces the offending content and continues execution. | | `log` | Records the detection in the trace but allows execution to continue. | ## Configuring Guardrails Guardrails are configured per agent. Each agent can have multiple guardrails with different scanners, directions, and actions. **Python SDK** ```python # Add an input guardrail for prompt injection client.guardrails.create( agent_id="your-agent-id", type="input", scanner_type="prompt_injection", action="block", sort_order=1, config={} ) # Add an output guardrail for PII client.guardrails.create( agent_id="your-agent-id", type="output", scanner_type="pii", action="redact", sort_order=1, config={ "entities": ["email", "phone", "ssn", "credit_card"] } ) # Add a substring ban client.guardrails.create( agent_id="your-agent-id", type="input", scanner_type="ban_substrings", action="block", sort_order=2, config={ "substrings": ["ignore previous instructions", "system prompt"], "case_sensitive": False } ) ``` **JavaScript SDK** ```typescript await client.guardrails.create({ agentId: 'your-agent-id', type: 'input', scannerType: 'prompt_injection', action: 'block', sortOrder: 1, config: {}, }) await client.guardrails.create({ agentId: 'your-agent-id', type: 'output', scannerType: 'pii', action: 'redact', sortOrder: 1, config: { entities: ['email', 'phone', 'ssn', 'credit_card'], }, }) ``` ## Sort Order Guardrails execute in sort order (ascending) within each direction. Lower numbers execute first. A typical input guardrail ordering might be: 1. `invisible_text` (sort_order: 1) -- Detect hidden characters first 2. `prompt_injection` (sort_order: 2) -- Block injection attempts 3. `toxicity` (sort_order: 3) -- Filter toxic content 4. `ban_substrings` (sort_order: 4) -- Apply custom word filters If a guardrail with `block` action triggers, subsequent guardrails are not evaluated. ## Scanner Configuration Each scanner type accepts a configuration object (`config`) for customization: ### ban_substrings ```json { "substrings": ["forbidden phrase", "blocked word"], "case_sensitive": false } ``` ### ban_topics ```json { "topics": ["politics", "religion", "gambling"] } ``` ### pii ```json { "entities": ["email", "phone", "ssn", "credit_card", "address"] } ``` ### language ```json { "languages": ["en", "es", "fr"], "action_on_mismatch": "block" } ``` ### toxicity, harmful, bias, prompt_injection, secrets, invisible_text, malicious_urls, anonymize, no_refusal, sensitive These scanners typically work with an empty configuration object `{}` and use their built-in detection models. ## Managing Guardrails ```python # List guardrails for an agent guardrails = client.guardrails.list(agent_id="your-agent-id") # Update a guardrail client.guardrails.update( guardrail_id="guardrail-id", action="log", # Change from block to log is_active=True ) # Disable a guardrail (without deleting) client.guardrails.update( guardrail_id="guardrail-id", is_active=False ) # Delete a guardrail client.guardrails.delete(guardrail_id="guardrail-id") ``` ## Guardrail Traces Every guardrail evaluation produces a `guardrail` span in the execution trace, recording: - Which scanner was used - Whether it triggered - What action was taken - The duration of the scan - Any details about detected content This provides full visibility into why content was blocked or redacted. ## Best Practices - **Layer your guardrails** -- Use multiple scanners in combination for defense in depth - **Start with `log` mode** -- Monitor what would be caught before switching to `block` - **Prioritize injection prevention** -- Always run `prompt_injection` on inputs - **Protect PII** -- Use `pii` or `anonymize` on outputs to prevent data leakage - **Test with adversarial inputs** -- Verify your guardrails catch edge cases - **Monitor guardrail traces** -- Review blocked content regularly to tune configurations ## Related Topics - [Agents](/docs/agents) -- Attaching guardrails to agents - [Tracing](/docs/tracing) -- Guardrail evaluation spans - [Security](/docs/security) -- Overall security architecture --- # Memory Source: https://promptrails.ai/docs/memory > Give your agents persistent memory with five memory types, vector embeddings, and semantic search. # Memory The memory system gives agents the ability to store and retrieve information across executions. This enables context-aware conversations, knowledge accumulation, and personalized interactions. ## Memory Types PromptRails supports five types of memory, each suited to different use cases: ### Conversation Memory (`conversation`) Stores conversation history and context. Used for maintaining context in multi-turn chat sessions. ```python client.memories.create( agent_id="your-agent-id", content="User prefers responses in bullet point format.", memory_type="conversation", importance=0.7, chat_session_id="optional-session-id" ) ``` ### Fact Memory (`fact`) Stores discrete facts and knowledge. Used for accumulating knowledge about users, products, or domains. ```python client.memories.create( agent_id="your-agent-id", content="Customer John Smith is a Premium tier subscriber since 2023.", memory_type="fact", importance=0.8, metadata={"entity": "customer", "customer_id": "john-smith-123"} ) ``` ### Procedure Memory (`procedure`) Stores step-by-step procedures and workflows. Used for remembering how to perform tasks. ```python client.memories.create( agent_id="your-agent-id", content="To process a refund: 1) Verify order ID 2) Check refund eligibility 3) Submit refund request 4) Notify customer", memory_type="procedure", importance=0.9 ) ``` ### Episodic Memory (`episodic`) Stores event records and experiences. Used for remembering specific interactions and outcomes. ```python client.memories.create( agent_id="your-agent-id", content="On 2024-01-15, customer reported issue with order #45678. Resolved by issuing replacement.", memory_type="episodic", importance=0.6, metadata={"event_type": "support_ticket", "resolution": "replacement"} ) ``` ### Semantic Memory (`semantic`) Stores conceptual knowledge with vector embeddings for semantic similarity search. Used for knowledge bases and retrieval-augmented generation (RAG). ```python client.memories.create( agent_id="your-agent-id", content="Our return policy allows returns within 30 days of purchase. Items must be in original packaging.", memory_type="semantic", importance=0.9, metadata={"topic": "return_policy", "version": "2024-Q1"} ) ``` ## Vector Embeddings Memories can be automatically embedded as vectors for semantic search. When a memory is created with content, PromptRails generates a vector embedding that enables similarity-based retrieval. This is particularly powerful for semantic memory types, enabling agents to find relevant knowledge based on meaning rather than exact keyword matching. ## Semantic Search Search memories by semantic similarity to find relevant context for the current interaction: ```python results = client.memories.search( agent_id="your-agent-id", query="What is the refund policy?", memory_type="semantic", limit=5 ) for memory in results["data"]: print(f"[{memory['importance']}] {memory['content']}") ``` ## Importance Scoring Each memory has an importance score between 0.0 and 1.0: | Range | Meaning | | --------- | ---------------------------------------------------- | | 0.0 - 0.3 | Low importance (casual observations, minor details) | | 0.3 - 0.6 | Medium importance (general knowledge, preferences) | | 0.6 - 0.8 | High importance (key facts, procedures) | | 0.8 - 1.0 | Critical importance (core rules, policies, identity) | Importance scores influence which memories are retrieved when context limits are applied. ## Access Tracking The memory system tracks how often each memory is accessed: - `access_count` -- Total number of times the memory has been retrieved - `last_accessed_at` -- Timestamp of the most recent access This metadata helps identify frequently used vs. stale memories. ## Memory CRUD Operations ### Create ```python memory = client.memories.create( agent_id="your-agent-id", content="The customer's preferred language is Spanish.", memory_type="fact", importance=0.7, metadata={"category": "preference"} ) ``` ### List ```python memories = client.memories.list( agent_id="your-agent-id", memory_type="fact", # optional filter page=1, limit=20 ) ``` ### Get ```python memory = client.memories.get(memory_id="memory-id") ``` ### Update ```python client.memories.update( memory_id="memory-id", content="Updated content", importance=0.9 ) ``` ### Delete ```python client.memories.delete(memory_id="memory-id") ``` ## Using Memories in Agents When memory is enabled for an agent, the execution pipeline: 1. Retrieves relevant memories based on the input (using semantic search for semantic memories) 2. Injects the retrieved memories into the prompt context 3. Optionally creates new memories from the interaction 4. Updates access counts for retrieved memories Enable memory in the agent configuration: ```python client.agents.create_version( agent_id="your-agent-id", config={ "memory_enabled": True, "memory_types": ["conversation", "fact", "semantic"], "max_memories": 10 }, message="Enabled memory system" ) ``` ## Memory Response Fields | Field | Type | Description | | ------------------ | --------- | --------------------------------------------------------- | | `id` | KSUID | Unique memory identifier | | `workspace_id` | KSUID | Workspace this memory belongs to | | `agent_id` | KSUID | Agent this memory is associated with | | `content` | string | The memory content | | `memory_type` | string | One of: conversation, fact, procedure, episodic, semantic | | `importance` | float | Importance score (0.0 to 1.0) | | `access_count` | integer | Number of times accessed | | `last_accessed_at` | timestamp | Last access time | | `metadata` | JSON | Arbitrary metadata | | `chat_session_id` | KSUID | Optional linked chat session | | `created_at` | timestamp | Creation time | | `updated_at` | timestamp | Last update time | ## Related Topics - [Agents](/docs/agents) -- Enabling memory in agent configurations - [Sessions and Chat](/docs/sessions-and-chat) -- Conversation memory in chat sessions - [Tracing](/docs/tracing) -- Memory operations appear as `memory` and `embedding` spans --- # Executions Source: https://promptrails.ai/docs/executions > Understand the agent execution lifecycle, status types, input/output capture, token usage, cost tracking, and async execution. # Executions An execution represents a single invocation of an agent. It captures the full lifecycle from input to output, including status, duration, token usage, cost, and metadata. ## Execution Lifecycle When an agent is executed, the following steps occur: 1. **Pending** -- The execution is created and queued 2. **Running** -- The execution pipeline is actively processing (prompt rendering, LLM calls, tool invocations, guardrail checks) 3. **Terminal state** -- The execution reaches one of: completed, failed, cancelled, awaiting_approval, or rejected ``` pending -> running -> completed -> failed -> cancelled -> awaiting_approval -> approved -> completed -> rejected ``` ## Status Types | Status | Description | | ------------------- | --------------------------------------------------------------- | | `pending` | Execution created, waiting to be processed | | `running` | Actively executing (LLM calls, tools, etc.) | | `completed` | Successfully finished with output | | `failed` | Encountered an error during execution | | `cancelled` | Manually cancelled before completion | | `awaiting_approval` | Paused at a checkpoint, waiting for human approval | | `rejected` | Human reviewer rejected the execution at an approval checkpoint | ## Input and Output ### Input The input is a JSON object provided when executing an agent. It must conform to the agent version's input schema (if defined). ```json { "message": "What is the status of order #12345?", "customer_id": "cust_789", "language": "en" } ``` ### Output The output is the result produced by the agent after successful execution. The structure depends on the agent type and configuration. ```json { "response": "Your order #12345 is currently in transit and expected to arrive by Friday.", "confidence": 0.95, "sources": ["order_database"] } ``` ## Token Usage and Cost Every execution tracks token consumption and cost: | Field | Description | | ------------- | ----------------------------------------------------------------- | | `token_usage` | JSON object with prompt and completion token counts | | `cost` | Total cost in USD (calculated from token usage and model pricing) | | `duration_ms` | Total execution time in milliseconds | Token usage example: ```json { "prompt_tokens": 450, "completion_tokens": 120, "total_tokens": 570 } ``` ## Metadata Executions can carry arbitrary metadata for tracking and filtering: ```python result = client.agents.execute( agent_id="your-agent-id", input={"message": "Hello"}, metadata={ "user_id": "user-456", "channel": "web", "environment": "production", "experiment_id": "exp-001" } ) ``` ## Sync vs Async Execution ### Synchronous Execution The default execution mode. The API call blocks until the execution completes and returns the result. ```python result = client.agents.execute( agent_id="your-agent-id", input={"message": "Hello"} ) # Result is immediately available print(result["data"]["output"]) ``` ### Asynchronous Execution For long-running executions, use async mode. The API returns immediately with the execution ID, and you poll for completion. ```python # Start async execution execution = client.agents.execute( agent_id="your-agent-id", input={"message": "Analyze this large dataset..."}, async_mode=True ) execution_id = execution["data"]["id"] # Poll for completion import time while True: status = client.executions.get(execution_id=execution_id) if status["data"]["status"] in ["completed", "failed", "rejected"]: break time.sleep(1) print(status["data"]["output"]) ``` ## Streaming Execution Events Instead of polling, subscribe to the execution's Server-Sent Events stream to receive `thinking`, `tool_start`, `tool_end`, `content`, and `done` frames as they happen. ``` GET /api/v1/executions/{execution_id}/stream Accept: text/event-stream ``` The event schema is identical to the chat streaming endpoint — see [Sessions and Chat](/docs/sessions-and-chat#streaming-responses-sse) for the full table. Useful when the execution was started outside a chat session (e.g. a one-shot `agents.execute` or a webhook trigger) and you still want live updates. ```typescript // JavaScript / TypeScript for await (const event of client.executions.stream(executionId)) { if (event.type === 'content') process.stdout.write(event.content) if (event.type === 'done') break } ``` ```python # Python — sync iterator (AsyncExecutionsResource.stream for async) from promptrails import ContentEvent, DoneEvent for event in client.executions.stream(execution_id): if isinstance(event, ContentEvent): print(event.content, end="", flush=True) elif isinstance(event, DoneEvent): break ``` ```go // Go stream, _ := client.Executions.Stream(ctx, executionID) defer stream.Close() for stream.Next() { if e, ok := stream.Event().(*promptrails.ContentEvent); ok { fmt.Print(e.Content) } } ``` Already-completed executions emit a single `done` (or `error`) frame and close, so the same code works whether you subscribe mid-run or after the fact. ## Listing and Filtering Executions ```python # List all executions executions = client.executions.list(page=1, limit=20) # Filter by agent executions = client.executions.list( agent_id="your-agent-id", page=1, limit=20 ) # Filter by status executions = client.executions.list( status="completed", page=1, limit=20 ) ``` **JavaScript SDK** ```typescript const executions = await client.executions.list({ agentId: 'your-agent-id', status: 'completed', page: 1, limit: 20, }) ``` ## Execution Response Fields | Field | Type | Description | | ------------------ | --------- | --------------------------------------------------- | | `id` | KSUID | Unique execution identifier | | `agent_id` | KSUID | The agent that was executed | | `agent_version_id` | KSUID | The specific agent version used | | `workspace_id` | KSUID | Workspace scope | | `user_id` | KSUID | User who initiated the execution (if authenticated) | | `session_id` | string | Chat session ID (if applicable) | | `status` | string | Current execution status | | `input` | JSON | Input provided to the agent | | `output` | JSON | Result produced by the agent | | `error` | string | Error message (if failed) | | `metadata` | JSON | Custom metadata | | `token_usage` | JSON | Token consumption breakdown | | `cost` | float | Total cost in USD | | `duration_ms` | integer | Total duration in milliseconds | | `trace_id` | string | Link to the execution trace | | `started_at` | timestamp | When execution started | | `completed_at` | timestamp | When execution finished | | `created_at` | timestamp | When the execution record was created | ## Related Topics - [Agents](/docs/agents) -- Executing agents - [Tracing](/docs/tracing) -- Detailed execution traces - [Cost Tracking](/docs/cost-tracking) -- Cost analysis - [Approvals](/docs/approvals) -- Human-in-the-loop execution flow - [Scoring and Evaluation](/docs/scoring-and-evaluation) -- Scoring executions --- # Tracing Source: https://promptrails.ai/docs/tracing > OpenTelemetry-style distributed tracing with 18 span kinds for complete visibility into agent execution, LLM calls, tool invocations, media generation, and more. # Tracing PromptRails provides comprehensive distributed tracing that captures every step of an agent execution. Inspired by OpenTelemetry, the tracing system records spans for LLM calls, tool invocations, guardrail evaluations, data source queries, memory operations, and more. ## How Tracing Works Every agent execution generates a **trace** -- a tree of **spans** that represent the individual operations performed during execution. Each span captures: - What happened (name, kind) - How long it took (duration, start/end timestamps) - What went in and came out (input/output) - Whether it succeeded (status, error details) - How much it cost (token usage, cost) - Context links (agent, prompt, model, execution, session) Spans form a parent-child hierarchy that reflects the execution flow: ``` agent (root span) ├── guardrail (input scan) ├── prompt (template rendering) ├── llm (model call) │ └── tool (tool call by LLM) │ └── mcp_call (MCP server invocation) ├── guardrail (output scan) └── memory (memory update) ``` ## Span Kinds PromptRails defines 18 span kinds: | Kind | Identifier | Description | | ------------------ | ---------------- | ------------------------------------------ | | **Agent** | `agent` | Top-level agent execution span | | **LLM** | `llm` | LLM model call (prompt + completion) | | **Tool** | `tool` | Tool invocation within an agent | | **Data Source** | `datasource` | Database or file query | | **Prompt** | `prompt` | Prompt template rendering | | **Guardrail** | `guardrail` | Input or output guardrail scan | | **Chain** | `chain` | Chain-type agent orchestration | | **Workflow** | `workflow` | Workflow step execution | | **Agent Step** | `agent_step` | Individual step in a multi-agent execution | | **MCP Call** | `mcp_call` | Remote MCP server tool call | | **Preprocessing** | `preprocessing` | Input preprocessing before LLM | | **Postprocessing** | `postprocessing` | Output postprocessing after LLM | | **Memory** | `memory` | Memory retrieval or storage | | **Embedding** | `embedding` | Vector embedding generation | | **Speech** | `speech` | Text-to-speech or speech-to-text operation | | **Image** | `image` | Image generation or editing | | **Video** | `video` | Video generation | | **Storage** | `storage` | Asset storage upload/download | ## Span Hierarchy Spans are organized in a tree structure using trace IDs, span IDs, and parent span IDs: - **trace_id** -- Groups all spans belonging to the same execution - **span_id** -- Uniquely identifies a single span - **parent_span_id** -- Links a span to its parent (empty for root spans) ### Example Trace for a Simple Agent ``` [agent] Customer Support Bot (15ms total) [guardrail] prompt_injection input scan (2ms) [prompt] Render main prompt (1ms) [llm] gpt-4o call (10ms, 450 prompt + 120 completion tokens, $0.003) [guardrail] pii output scan (2ms) ``` ### Example Trace for a Chain Agent ``` [chain] Data Analysis Pipeline (45ms total) [agent_step] Step 1: Data Extraction [datasource] Query analytics DB (8ms) [prompt] Render extraction prompt (1ms) [llm] gpt-4o call (15ms) [agent_step] Step 2: Analysis [memory] Retrieve analysis templates (2ms) [prompt] Render analysis prompt (1ms) [llm] claude-3.5-sonnet call (18ms) ``` ## Span Status and Levels ### Status | Status | Description | | ------- | ------------------------------- | | `ok` | The span completed successfully | | `error` | The span encountered an error | ### Level | Level | Description | | --------- | ---------------------------------- | | `debug` | Detailed diagnostic information | | `default` | Standard operational information | | `warning` | Something unexpected but non-fatal | | `error` | An error occurred | ## Span Attributes Each span carries an `attributes` JSON object with kind-specific metadata: ### LLM Span Attributes ```json { "model": "gpt-4o", "provider": "openai", "temperature": 0.7, "max_tokens": 1024, "prompt_tokens": 450, "completion_tokens": 120, "total_tokens": 570, "cost": 0.003 } ``` ### Guardrail Span Attributes ```json { "scanner_type": "prompt_injection", "direction": "input", "action": "block", "triggered": false } ``` ### Tool Span Attributes ```json { "tool_name": "weather_api", "tool_type": "api", "parameters": { "location": "New York" } } ``` ### Media Span Attributes (Speech / Image / Video) ```json { "provider": "fal", "model": "fal-ai/flux/schnell", "media_type": "image_gen", "prompt": "A futuristic city skyline at sunset", "asset_url": "https://storage.example.com/assets/image.png", "content_type": "image/png" } ``` ## Filtering Traces List and filter traces with multiple criteria: ```python traces = client.traces.list( agent_id="your-agent-id", # Filter by agent execution_id="execution-id", # Filter by execution kind="llm", # Filter by span kind status="ok", # Filter by status model_name="gpt-4o", # Filter by model session_id="session-id", # Filter by session user_id="user-id", # Filter by user page=1, limit=50 ) ``` **JavaScript SDK** ```typescript const traces = await client.traces.list({ agentId: 'your-agent-id', kind: 'llm', status: 'ok', page: 1, limit: 50, }) ``` ## Cost and Token Tracking Per Span Every LLM span includes precise cost and token tracking: | Field | Description | | ------------------- | ---------------------------------------- | | `prompt_tokens` | Number of input tokens sent to the model | | `completion_tokens` | Number of output tokens generated | | `total_tokens` | Sum of prompt and completion tokens | | `cost` | Cost in USD for this specific span | | `model_name` | The model used for this call | This enables granular cost attribution -- you can see exactly which LLM call in a multi-step execution was the most expensive. ## Error Information When a span has an error status, additional fields provide diagnostic information: | Field | Description | | --------------- | ------------------------------------------------------------------ | | `error_message` | Human-readable error description | | `error_type` | Error classification (e.g., `rate_limit`, `timeout`, `validation`) | | `error_stack` | Stack trace for debugging | ## Trace Fields | Field | Type | Description | | ---------------- | --------- | -------------------------------------- | | `id` | KSUID | Unique span record ID | | `trace_id` | string | Trace group identifier | | `span_id` | string | Unique span identifier | | `parent_span_id` | string | Parent span (empty for root) | | `name` | string | Span name | | `kind` | string | Span kind (one of 18 types) | | `status` | string | `ok` or `error` | | `level` | string | `debug`, `default`, `warning`, `error` | | `input` | JSON | Span input data | | `output` | JSON | Span output data | | `attributes` | JSON | Kind-specific metadata | | `tags` | JSON | Custom tags | | `token_usage` | JSON | Token consumption | | `cost` | float | Cost in USD | | `duration_ms` | integer | Duration in milliseconds | | `model_name` | string | LLM model name | | `agent_id` | KSUID | Associated agent | | `prompt_id` | KSUID | Associated prompt | | `execution_id` | KSUID | Associated execution | | `session_id` | string | Associated chat session | | `started_at` | timestamp | Span start time | | `ended_at` | timestamp | Span end time | ## Related Topics - [Executions](/docs/executions) -- Execution lifecycle - [Media Generation](/docs/media-generation) -- Speech, image, and video generation - [Cost Tracking](/docs/cost-tracking) -- Aggregated cost analysis - [Scoring and Evaluation](/docs/scoring-and-evaluation) -- Scoring individual spans --- # Sessions and Chat Source: https://promptrails.ai/docs/sessions-and-chat > Build multi-turn conversational experiences with chat sessions, message history, and WebSocket support. # Sessions and Chat PromptRails provides a session-based chat system for building multi-turn conversational experiences. Sessions maintain conversation context, message history, and metadata across multiple interactions with an agent. ## Chat Sessions Overview A chat session represents an ongoing conversation between a user and an agent. It maintains: - **Conversation history** -- All messages exchanged in the session - **Agent binding** -- The session is linked to a specific agent - **User binding** -- Optionally linked to an authenticated user - **Metadata** -- Custom metadata for tracking and filtering - **Title** -- Display name for the session ## Creating Sessions **Python SDK** ```python session = client.chat.create_session( agent_id="your-agent-id", title="Support Conversation", metadata={ "channel": "web", "user_id": "external-user-123" } ) session_id = session.id print(f"Session created: {session_id}") ``` **JavaScript SDK** ```typescript const session = await client.chat.createSession({ agentId: 'your-agent-id', title: 'Support Conversation', metadata: { channel: 'web', user_id: 'external-user-123', }, }) const sessionId = session.id ``` ## Sending Messages Send a message to a chat session and receive the agent's response: **Python SDK** ```python response = client.chat.send_message( session_id, content="Hi, I need help with my account." ) print(response.content) ``` **JavaScript SDK** ```typescript const response = await client.chat.sendMessage(sessionId, { content: 'Hi, I need help with my account.', }) console.log(response.content) ``` Each message sent to the chat API: 1. Loads the conversation history from the session 2. Constructs a prompt including the history and the new message 3. Executes the linked agent 4. Stores the user message and assistant response in the session 5. Returns the response ## Message History Retrieve the full message history for a session: ```python messages = client.chat.list_messages(session_id) for message in messages.data: print(f"[{message.role}]: {message.content}") ``` ## Multi-Turn Conversations Sessions automatically manage conversation context. Each new message includes the full conversation history, enabling the agent to reference previous exchanges: ```python # First message client.chat.send_message(session_id, content="What is machine learning?") # Follow-up (agent has context from the first message) client.chat.send_message(session_id, content="Can you give me a specific example?") # Another follow-up client.chat.send_message(session_id, content="How does that compare to deep learning?") ``` The agent receives the full conversation history with each request, so it can maintain coherent, contextual responses throughout the conversation. ## Streaming Responses (SSE) For real-time chat — token-by-token output, visible tool calls, and intermediate reasoning — post a message to the streaming endpoint. It returns a Server-Sent Events stream on the same HTTP connection. ``` POST /api/v1/chat/sessions/{session_id}/messages/stream Content-Type: application/json Accept: text/event-stream { "content": "Hello!" } ``` ### Event schema | Event | Data | Meaning | | ------------ | ----------------------------------- | ------------------------------------------------------------- | | `execution` | `{ execution_id, user_message_id }` | Emitted first. Correlate with executions / traces. | | `thinking` | `{ content }` | Intermediate reasoning text between tool rounds. | | `tool_start` | `{ id, name }` | The agent is about to execute a tool call. | | `tool_end` | `{ id, name, summary }` | A tool call finished. `summary` is a short display string. | | `content` | `{ content }` | Delta of the final assistant response. | | `done` | `{ output, token_usage, time }` | Terminal event. Carries the full output and token accounting. | | `error` | `{ message }` | Terminal error. | A typical stream emits `execution` first, zero or more `thinking` / `tool_start` / `tool_end` / `content` frames, then exactly one `done` or `error`. ### Consume it from an SDK ```typescript // JavaScript / TypeScript — @promptrails/sdk >= 0.3.1 for await (const event of client.chat.sendMessageStream(session.id, { content: 'Hello!', })) { if (event.type === 'content') process.stdout.write(event.content) if (event.type === 'done') break } ``` ```python # Python — promptrails >= 0.3.0 from promptrails import ContentEvent, DoneEvent for event in client.chat.send_message_stream(session_id, content="Hello!"): if isinstance(event, ContentEvent): print(event.content, end="", flush=True) elif isinstance(event, DoneEvent): break ``` ```go // Go — github.com/promptrails/go-sdk >= v0.3.1 stream, _ := client.Chat.SendMessageStream(ctx, sessionID, &promptrails.SendMessageParams{ Content: "Hello!", }) defer stream.Close() for stream.Next() { if e, ok := stream.Event().(*promptrails.ContentEvent); ok { fmt.Print(e.Content) } } ``` See each SDK's docs ([JavaScript](/docs/javascript-sdk), [Python](/docs/python-sdk), [Go](/docs/go-sdk)) for the full event-handling pattern, and [Executions](/docs/executions) for the related `GET /executions/:id/stream` endpoint when you want to subscribe to a run started outside of chat. ## Session Management ### List Sessions ```python sessions = client.chat.list_sessions(page=1, limit=20) for session in sessions.data: print(f"{session.title} - {session.created_at}") ``` ### Get Session Details ```python session = client.chat.get_session("session-id") messages = client.chat.list_messages("session-id", page=1, limit=100) print(f"Title: {session.title}") print(f"Messages: {len(messages.data)}") ``` ### Delete a Session ```python client.chat.delete_session("session-id") ``` ## Session Fields | Field | Type | Description | | -------------- | --------- | --------------------------- | | `id` | KSUID | Unique session identifier | | `workspace_id` | KSUID | Workspace scope | | `agent_id` | KSUID | The agent for this session | | `user_id` | KSUID | Optional authenticated user | | `title` | string | Display title | | `metadata` | JSON | Custom metadata | | `created_at` | timestamp | Session creation time | | `updated_at` | timestamp | Last activity time | ## Best Practices - **Set meaningful titles** -- Helps users find and resume conversations - **Use metadata** -- Track channel, user, experiment, or any context needed for analytics - **Clean up old sessions** -- Delete sessions that are no longer needed to manage storage - **Handle context limits** -- For very long conversations, be aware that conversation history may exceed the model's context window. Consider using summarization or memory for extended sessions. ## Related Topics - [Agents](/docs/agents) -- The agents that power chat sessions - [Memory](/docs/memory) -- Persistent memory across sessions - [Executions](/docs/executions) -- Each chat message creates an execution - [Tracing](/docs/tracing) -- Traces for individual chat messages --- # Scoring and Evaluation Source: https://promptrails.ai/docs/scoring-and-evaluation > Score and evaluate agent executions with numeric, categorical, and boolean metrics using manual, API, or LLM judge scoring. # Scoring and Evaluation PromptRails includes a scoring system for evaluating agent performance. You can score executions and individual spans with numeric, categorical, or boolean metrics using manual annotation, API-based automation, or LLM judge scoring. ## Overview Scores provide structured feedback on agent outputs. They enable: - **Quality monitoring** -- Track how well agents perform over time - **A/B testing** -- Compare agent versions quantitatively - **Regression detection** -- Identify when changes degrade performance - **Human evaluation** -- Collect manual ratings from reviewers - **Automated evaluation** -- Use LLM judges to score outputs at scale ## Score Types ### Numeric A score with a numeric value, optionally bounded by min/max values. ```python client.scores.create( trace_id="trace-id", name="relevance", data_type="numeric", value=4.5, comment="Response was highly relevant to the query" ) ``` ### Categorical A score from a predefined set of categories. ```python client.scores.create( trace_id="trace-id", name="quality", data_type="categorical", string_value="good", comment="Clear and helpful response" ) ``` ### Boolean A binary pass/fail score. ```python client.scores.create( trace_id="trace-id", name="factually_correct", data_type="boolean", bool_value=True, comment="All facts were verified" ) ``` ## Score Configurations Score configurations (templates) define reusable scoring schemas that ensure consistency across evaluations. ### Creating a Score Config ```python # Numeric config with range config = client.scores.create_config( name="Response Quality", data_type="numeric", min_value=1.0, max_value=5.0, description="Rate the overall quality of the agent's response" ) # Categorical config config = client.scores.create_config( name="Sentiment Accuracy", data_type="categorical", categories=["correct", "partially_correct", "incorrect"], description="How accurately the agent identified the sentiment" ) # Boolean config config = client.scores.create_config( name="Contains Hallucination", data_type="boolean", description="Whether the response contains fabricated information" ) ``` ### Using a Config When Scoring ```python client.scores.create( trace_id="trace-id", config_id=config["data"]["id"], name="Response Quality", data_type="numeric", value=4.0 ) ``` ## Score Sources Each score records how it was generated: | Source | Identifier | Description | | ------------- | ----------- | ------------------------------------------------ | | **Manual** | `manual` | Scored by a human reviewer through the UI or API | | **API** | `api` | Scored programmatically via the API | | **LLM Judge** | `llm_judge` | Scored automatically by an LLM evaluator | ## LLM Judge Scoring PromptRails supports automated scoring using LLM judges. An LLM judge evaluates agent outputs against criteria you define: ```python # Automated scoring is configured through score configs # and triggered during or after execution config = client.scores.create_config( name="Helpfulness", data_type="numeric", min_value=1.0, max_value=5.0, description="How helpful was the response to the user's question?" ) ``` LLM judges evaluate outputs based on the score config's description and data type, producing consistent, scalable evaluations. ## Execution-Level Scoring Score an entire execution: ```python client.scores.create( trace_id="trace-id", execution_id="execution-id", agent_id="agent-id", name="overall_quality", data_type="numeric", value=4.0, source="manual", comment="Good response with minor formatting issues" ) ``` ## Span-Level Scoring Score an individual span within an execution (e.g., a specific LLM call or tool result): ```python client.scores.create( trace_id="trace-id", span_id="span-id", name="tool_accuracy", data_type="boolean", bool_value=True, source="api", comment="Tool returned correct data" ) ``` ## Listing Scores ```python # List scores for a trace scores = client.scores.list(trace_id="trace-id") # List scores for an agent scores = client.scores.list(agent_id="agent-id", page=1, limit=50) for score in scores["data"]: print(f"{score['name']}: {score.get('value') or score.get('string_value') or score.get('bool_value')}") ``` ## Score Fields | Field | Type | Description | | --------------- | --------- | -------------------------------------- | | `id` | KSUID | Unique score identifier | | `workspace_id` | KSUID | Workspace scope | | `trace_id` | string | Associated trace | | `span_id` | string | Optional specific span | | `name` | string | Score name | | `value` | float | Numeric value (for numeric type) | | `string_value` | string | Category value (for categorical type) | | `bool_value` | boolean | Boolean value (for boolean type) | | `data_type` | string | `numeric`, `categorical`, or `boolean` | | `comment` | string | Optional comment or explanation | | `source` | string | `manual`, `api`, or `llm_judge` | | `config_id` | KSUID | Optional score config reference | | `execution_id` | KSUID | Optional execution reference | | `agent_id` | KSUID | Optional agent reference | | `created_by_id` | KSUID | User who created the score | | `created_at` | timestamp | Creation time | ## Best Practices - **Define score configs early** -- Create standardized scoring templates before starting evaluation - **Score consistently** -- Use the same configs across agent versions for meaningful comparisons - **Combine sources** -- Use manual scoring for calibration and LLM judges for scale - **Score at the right level** -- Use execution-level scores for overall quality and span-level scores for component accuracy - **Track over time** -- Monitor score trends to detect regressions ## Related Topics - [Executions](/docs/executions) -- What gets scored - [Tracing](/docs/tracing) -- Spans that can be individually scored - [Cost Tracking](/docs/cost-tracking) -- Correlate quality with cost --- # Cost Tracking Source: https://promptrails.ai/docs/cost-tracking > Track LLM costs per execution, per span, per agent, and across your entire workspace with automatic token usage and pricing calculations. # Cost Tracking PromptRails automatically calculates and tracks costs for every LLM call made during agent execution. This gives you full visibility into your AI spending at every level -- from individual LLM calls to workspace-wide summaries. ## How Costs Are Calculated Costs are calculated based on: 1. **Token usage** -- The number of prompt (input) and completion (output) tokens consumed 2. **Model pricing** -- The per-token price for the specific LLM model used 3. **Automatic aggregation** -- Span-level costs are rolled up to execution and workspace levels The formula is: ``` cost = (prompt_tokens * input_price_per_token) + (completion_tokens * output_price_per_token) ``` PromptRails maintains a database of LLM model pricing that is used for automatic cost calculation. ## Per-Execution Cost Breakdown Every execution includes total cost and token usage: ```python execution = client.executions.get(execution_id="your-execution-id") print(f"Total Cost: ${execution['data']['cost']:.6f}") print(f"Token Usage: {execution['data']['token_usage']}") print(f"Duration: {execution['data']['duration_ms']}ms") ``` For multi-step executions (chain, workflow, multi-agent), the execution cost is the sum of all LLM calls within that execution. ## Per-Span Cost Analysis Drill down into individual spans to see cost at the LLM call level: ```python traces = client.traces.list(execution_id="your-execution-id", kind="llm") for span in traces["data"]: print(f"Model: {span['model_name']}") print(f" Prompt tokens: {span.get('prompt_tokens', 0)}") print(f" Completion tokens: {span.get('completion_tokens', 0)}") print(f" Cost: ${span.get('cost', 0):.6f}") print(f" Duration: {span['duration_ms']}ms") print("---") ``` This is valuable for identifying which step in a complex pipeline is the most expensive. ## Token Usage Tracking Token usage is tracked with three metrics: | Metric | Description | | ------------------- | ----------------------------------------------- | | `prompt_tokens` | Number of tokens in the input sent to the model | | `completion_tokens` | Number of tokens in the model's response | | `total_tokens` | Sum of prompt and completion tokens | Token counts are provided by the LLM provider and recorded with each LLM span. ## Workspace-Wide Cost Summary Get aggregated cost data across your entire workspace: ```python summary = client.costs.get_summary() print(f"Total Cost: ${summary.total_cost:.2f}") print(f"Total Executions: {summary.total_executions}") print(f"Total Tokens: {summary.total_tokens}") ``` ## Per-Agent Cost Analysis Analyze costs broken down by agent to identify your most expensive workflows: ```python agent_costs = client.costs.get_agent_summary("your-agent-id") print(f"Agent Total Cost: ${agent_costs.total_cost:.2f}") print(f"Agent Executions: {agent_costs.total_executions}") print(f"Agent Tokens: {agent_costs.total_tokens}") ``` ## LLM Model Pricing PromptRails maintains pricing information for all supported LLM models. Prices are stored as cost per token (or per 1K/1M tokens depending on the model) and are used for automatic cost calculation. Supported providers and their models include: | Provider | Example Models | | ---------- | ------------------------------------------------ | | OpenAI | gpt-4o, gpt-4o-mini, gpt-4-turbo, gpt-3.5-turbo | | Anthropic | claude-3.5-sonnet, claude-3-opus, claude-3-haiku | | Google | gemini-pro, gemini-ultra | | DeepSeek | deepseek-chat, deepseek-coder | | Fireworks | Various hosted models | | xAI | grok-1, grok-2 | | OpenRouter | Aggregated pricing from multiple providers | ## Cost Optimization Tips - **Choose the right model** -- Use smaller, cheaper models (GPT-4o-mini, Claude 3 Haiku) for simple tasks and reserve expensive models for complex reasoning - **Use prompt caching** -- Enable cache timeouts on prompts to avoid duplicate LLM calls - **Monitor per-agent costs** -- Identify agents with unexpectedly high costs - **Set token limits** -- Use `max_tokens` to prevent runaway completions - **Review chain/workflow costs** -- Multi-step agents multiply LLM costs; optimize the number of steps - **Use data source caching** -- Cache database query results to reduce data source query overhead ## Related Topics - [Executions](/docs/executions) -- Execution-level cost data - [Tracing](/docs/tracing) -- Span-level cost breakdown - [Billing and Plans](/docs/billing-and-plans) -- Execution limits and plan pricing --- # Grafana Dashboard Source: https://promptrails.ai/docs/grafana-dashboard > Pre-built Grafana dashboards for monitoring PromptRails AI agents, prompts, costs, and execution trends. # Grafana Dashboard PromptRails provides pre-built [Grafana](https://grafana.com/) dashboards for monitoring your AI agents, prompts, and costs. The dashboards connect to the PromptRails API using the [Infinity datasource plugin](https://grafana.com/grafana/plugins/yesoreyeram-infinity-datasource/) and provide real-time visibility into execution trends, error rates, cost breakdowns, and more. The source code is available on [GitHub](https://github.com/promptrails/grafana-dashboard). ## Dashboards ### Overview Provides a high-level view of your PromptRails platform: | Panel | Type | Description | | -------------------- | ----------- | --------------------------------------- | | Total Executions | Stat | Total execution count | | Total Cost | Stat | Cumulative cost in USD | | Total Tokens | Stat | Total tokens consumed | | Error Count | Stat | Failed executions with color thresholds | | Avg Latency | Stat | Average execution duration | | Active Agents | Stat | Number of agents | | Executions Over Time | Bar Chart | Daily execution counts | | Cost Over Time | Bar Chart | Daily costs | | Error Rate Over Time | Time Series | Error rate percentage trend | | Agent Usage | Table | Executions and cost per agent | | Executions by Agent | Pie Chart | Execution distribution | | Cost by Agent | Pie Chart | Cost distribution | | Model Usage | Table | Requests, tokens, cost per model | | Score Trends | Time Series | Score averages over time | ### Cost Analysis Detailed cost breakdown across agents and models: | Panel | Type | Description | | -------------------- | ----------- | ------------------------ | | Total Cost | Stat | Overall cost | | Total Executions | Stat | Overall execution count | | Total Tokens | Stat | Overall token usage | | Cost by Agent | Bar Chart | Horizontal bar chart | | Cost by Model | Bar Chart | Horizontal bar chart | | Token Usage by Model | Table | Detailed model breakdown | | Daily Cost Trend | Time Series | Cost bar chart over time | ## Quick Start (Docker) The fastest way to get started is with Docker. This setup auto-provisions dashboards and the datasource. ```bash # 1. Clone git clone https://github.com/promptrails/grafana-dashboard cd grafana-dashboard # 2. Configure cp .env.example .env # Edit .env and set your PROMPTRAILS_API_KEY # 3. Start docker-compose up -d # 4. Open open http://localhost:3333 # Login: admin / admin ``` Dashboards are auto-provisioned in the **PromptRails** folder. The Docker setup also re-applies the datasource on startup so changes to `PROMPTRAILS_API_KEY` don't get stuck in Grafana's persisted volume. ## Manual Import (Existing Grafana) If you already have a Grafana instance, you can import the dashboards manually. ### 1. Install Infinity Datasource ```bash grafana-cli plugins install yesoreyeram-infinity-datasource ``` Or install from Grafana UI: **Configuration > Plugins > Search "Infinity"** ### 2. Create Datasource 1. Go to **Connections > Data Sources > Add data source** 2. Search for **Infinity** 3. Create an Infinity datasource with your preferred name 4. Under **Custom HTTP Headers**, add: - Header: `X-API-Key` - Value: Your PromptRails API key 5. Under **Security > Allowed Hosts**, add: `api.promptrails.ai` 6. Click **Save & Test** ### 3. Import Dashboards 1. Go to **Dashboards > Import** 2. Upload JSON files from the `exports/` folder in the [GitHub repository](https://github.com/promptrails/grafana-dashboard): - `overview.json` -- Main overview dashboard - `cost-analysis.json` -- Cost breakdown dashboard 3. When Grafana asks for **PromptRails**, select the Infinity datasource you created in the previous step ## Dashboard Variables | Variable | Default | Description | | -------- | ------- | ------------------------------------------ | | `days` | `30` | Time range for metrics (7, 14, 30, 60, 90) | ## Requirements - Grafana 10+ (tested with 11.4) - [Infinity Datasource Plugin](https://grafana.com/grafana/plugins/yesoreyeram-infinity-datasource/) - PromptRails API key (see [API Keys & Scopes](/docs/api-keys-and-scopes)) ## Troubleshooting ### `requested URL not allowed` If Query Inspector shows a `responseCodeFromServer: 401`, the URL allowlist is probably already correct and the actual problem is authentication. Check: 1. **Connections > Data Sources > your Infinity datasource > Security > Allowed Hosts** contains `api.promptrails.ai` 2. **Connections > Data Sources > your Infinity datasource > Custom HTTP Headers** has `X-API-Key` 3. The header value is your current `PROMPTRAILS_API_KEY` If you imported from `exports/`, also confirm the dashboard was mapped to the correct Infinity datasource during import. For Docker installs, re-run: ```bash docker-compose up -d ``` Grafana keeps datasource state in the `grafana-data` volume, so an old API key can survive container restarts unless the datasource is updated again. ## Related Topics - [Executions](/docs/executions) -- Execution lifecycle and monitoring - [Tracing](/docs/tracing) -- Distributed tracing for agent executions - [Cost Tracking](/docs/cost-tracking) -- Aggregated cost analysis - [Scoring & Evaluation](/docs/scoring-and-evaluation) -- Scoring and evaluation metrics --- # API Keys and Scopes Source: https://promptrails.ai/docs/api-keys-and-scopes > Create and manage API keys with fine-grained scopes, IP restrictions, CORS origin allowlists, and key expiration. # API Keys and Scopes API keys authenticate programmatic access to the PromptRails API. Each key can be scoped to specific permissions, restricted by IP address and CORS origin, and configured with an expiration date. ## Creating API Keys Create an API key from the PromptRails dashboard: 1. Open **Settings > API Keys**. 2. Select **Create API Key**. 3. Enter a name and choose the minimum required scopes. 4. Optionally add IP restrictions, allowed origins, and an expiration date. 5. Create the key and store the raw value securely. The raw API key value is returned only at creation time. It is stored as a hash and cannot be retrieved later. ## Scopes Scopes control what operations an API key can perform. PromptRails defines 24 granular scopes: ### Agent Scopes | Scope | Description | | ---------------- | ---------------------------------------------- | | `agents:read` | List and view agents and their versions | | `agents:write` | Create, update, and delete agents and versions | | `agents:execute` | Execute agents | ### Prompt Scopes | Scope | Description | | ----------------- | ----------------------------------------------- | | `prompts:read` | List and view prompts and their versions | | `prompts:write` | Create, update, and delete prompts and versions | | `prompts:execute` | Execute prompts directly | ### Data Source Scopes | Scope | Description | | ---------------------- | --------------------------------------- | | `data_sources:read` | List and view data sources | | `data_sources:write` | Create, update, and delete data sources | | `data_sources:execute` | Execute data source queries | ### Execution and Trace Scopes | Scope | Description | | ----------------- | ------------------------------- | | `executions:read` | List and view execution records | | `traces:read` | List and view trace spans | ### Credential Scopes | Scope | Description | | ------------------- | ---------------------------------------------- | | `credentials:read` | List and view credentials (masked values only) | | `credentials:write` | Create, update, and delete credentials | ### Session and Chat Scopes | Scope | Description | | --------------- | ------------------------------ | | `sessions:read` | List and view chat sessions | | `chat:write` | Send messages to chat sessions | ### Webhook Trigger Scopes | Scope | Description | | ------------------------ | ------------------------------------------- | | `webhook_triggers:read` | List and view webhook triggers | | `webhook_triggers:write` | Create, update, and delete webhook triggers | ### Score Scopes | Scope | Description | | -------------- | ------------------------------------------ | | `scores:read` | List and view scores and score configs | | `scores:write` | Create and update scores and score configs | ### Approval Scopes | Scope | Description | | ----------------- | ----------------------------------- | | `approvals:read` | List and view approval requests | | `approvals:write` | Approve or reject approval requests | ### Asset Scopes | Scope | Description | | -------------- | -------------------------------------- | | `assets:read` | List and view generated media assets | | `assets:write` | Delete assets and manage asset storage | ### Wildcard Scope | Scope | Description | | ----- | ----------------------------------------- | | `*` | Grants all permissions (use with caution) | ## IP Restrictions Restrict API key usage to specific IP addresses or CIDR ranges when creating or editing the key in the dashboard. You can mix individual IPs and CIDR ranges, including IPv6 entries. Requests from IPs not in the allowlist receive a `403 Forbidden` response. ## CORS Origin Restrictions Restrict which web origins can use the API key by adding an allowlist in the dashboard. This is most relevant for browser-based applications. ## Key Expiration Set an expiration date on API keys when creating or editing the key in the dashboard. Expired keys are automatically rejected. Use `last_used_at` to identify stale keys. ## Key Format API keys follow this format: - **Full key**: Returned only at creation time (e.g., `pr_live_abc123...xyz789`) - **Key prefix**: Stored and displayed for identification (e.g., `pr_live_ab`) - **Key hash**: SHA-256 hash stored in the database for authentication ## Authentication Include the API key in requests using the `X-API-Key` header: ```bash curl -H "X-API-Key: pr_live_abc123...xyz789" \ https://api.promptrails.ai/api/v1/agents ``` The same key can also be used with the PromptRails SDKs and CLI for authenticating requests. ## Managing Keys List, review, rotate, and delete API keys from **Settings > API Keys** in the dashboard. ## Key Rotation Best Practices - **Rotate keys regularly** -- Create a new key, update your applications, then delete the old key - **Use expiration dates** -- Set keys to expire and create replacement keys before expiration - **Minimize scopes** -- Grant only the permissions each integration needs - **Use separate keys per environment** -- Different keys for development, staging, and production - **Monitor usage** -- Check `last_used_at` to identify unused keys - **Never share keys** -- Each integration should have its own key - **Store securely** -- Keep keys in environment variables or secret managers, never in source code ## Key Response Fields | Field | Type | Description | | ----------------- | --------- | ----------------------------------- | | `id` | KSUID | Unique key identifier | | `workspace_id` | KSUID | Workspace scope | | `name` | string | Display name | | `key_prefix` | string | First characters for identification | | `scopes` | array | Granted permission scopes | | `allowed_ips` | array | IP allowlist | | `allowed_origins` | array | CORS origin allowlist | | `last_used_at` | timestamp | Last usage time | | `expires_at` | timestamp | Expiration time | | `created_at` | timestamp | Creation time | ## Related Topics - [Security](/docs/security) -- Overall security architecture - [REST API Reference](/docs/rest-api-reference) -- API authentication details - [Team and Roles](/docs/team-and-roles) -- User vs API key authentication --- # Webhook Triggers Source: https://promptrails.ai/docs/webhook-triggers > Trigger agent executions via HTTP webhooks with token authentication, HMAC signing, input mapping, and rate limiting. # Webhook Triggers Webhook triggers allow external systems to execute agents via HTTP requests. Each trigger is bound to a specific agent and authenticated with a unique token. Webhook triggers enable integrations with CI/CD pipelines, monitoring systems, form submissions, and any system that can make HTTP requests. ## What Are Webhook Triggers? A webhook trigger is a URL endpoint that, when called, executes a specific agent. Triggers include: - **Token authentication** -- Each trigger has a unique, encrypted token - **HMAC secret signing** -- Optional request signature verification - **Input mapping** -- Map webhook payload fields to agent input parameters - **Rate limiting** -- 30 requests per minute per IP address - **Activation control** -- Enable or disable triggers without deleting them ## Creating Triggers **Python SDK** ```python trigger = client.webhook_triggers.create( agent_id="your-agent-id", name="GitHub PR Review", generate_secret=True # Generate HMAC signing secret ) print(f"Trigger ID: {trigger['data']['id']}") print(f"Token: {trigger['data']['token']}") # Only shown once print(f"Secret: {trigger['data']['secret']}") # Only shown once (if generated) ``` **JavaScript SDK** ```typescript const trigger = await client.webhookTriggers.create({ agentId: 'your-agent-id', name: 'GitHub PR Review', generateSecret: true, }) console.log(`Token: ${trigger.data.token}`) console.log(`Secret: ${trigger.data.secret}`) ``` The token and secret are only returned at creation time. Store them securely. ## Token Authentication Every webhook request must include the trigger token for authentication. Include it in the `Authorization` header: ```bash curl -X POST https://api.promptrails.ai/api/v1/webhook/trigger \ -H "Authorization: Bearer wht_abc123..." \ -H "Content-Type: application/json" \ -d '{"message": "Review this PR", "pr_number": 42}' ``` ## HMAC Secret Signing When a secret is configured, PromptRails verifies request signatures to ensure requests are authentic: 1. The sender computes an HMAC-SHA256 of the request body using the shared secret 2. The signature is included in the request header 3. PromptRails verifies the signature before processing ```python import hmac import hashlib import json import requests payload = json.dumps({"message": "Hello"}) signature = hmac.new( secret.encode(), payload.encode(), hashlib.sha256 ).hexdigest() response = requests.post( "https://api.promptrails.ai/api/v1/webhook/trigger", headers={ "Authorization": "Bearer wht_abc123...", "X-Webhook-Signature": f"sha256={signature}", "Content-Type": "application/json" }, data=payload ) ``` ## Input Mapping The webhook payload is passed directly as the agent's input. Structure your webhook payload to match the agent's input schema: ```bash # If the agent expects {"message": string, "priority": string} curl -X POST https://api.promptrails.ai/api/v1/webhook/trigger \ -H "Authorization: Bearer wht_abc123..." \ -H "Content-Type: application/json" \ -d '{ "message": "Server CPU usage exceeded 90%", "priority": "high" }' ``` ## Rate Limiting Webhook triggers are rate limited to **30 requests per minute per IP address**. Exceeding this limit returns a `429 Too Many Requests` response. If you need higher throughput, consider: - Batching requests - Using the standard API with an API key instead - Distributing requests across multiple source IPs ## Activate / Deactivate Temporarily disable a trigger without deleting it: ```python # Deactivate client.webhook_triggers.update( trigger_id="trigger-id", is_active=False ) # Reactivate client.webhook_triggers.update( trigger_id="trigger-id", is_active=True ) ``` Requests to inactive triggers return a `403 Forbidden` response. ## Managing Triggers ### List Triggers ```python triggers = client.webhook_triggers.list() for trigger in triggers["data"]: status = "active" if trigger["is_active"] else "inactive" print(f"{trigger['name']} ({status}) - Agent: {trigger['agent_id']}") print(f" Token prefix: {trigger['token_prefix']}...") print(f" Has secret: {trigger['has_secret']}") print(f" Last used: {trigger.get('last_used_at', 'Never')}") ``` ### Delete a Trigger ```python client.webhook_triggers.delete(trigger_id="trigger-id") ``` ## Trigger Response Fields | Field | Type | Description | | --------------- | --------- | ---------------------------------- | | `id` | KSUID | Unique trigger identifier | | `workspace_id` | KSUID | Workspace scope | | `agent_id` | KSUID | Bound agent ID | | `name` | string | Display name | | `token_prefix` | string | First characters of the token | | `is_active` | boolean | Whether the trigger is active | | `has_secret` | boolean | Whether HMAC signing is configured | | `last_used_at` | timestamp | Last invocation time | | `created_by_id` | KSUID | Creator user ID | | `created_at` | timestamp | Creation time | | `updated_at` | timestamp | Last update time | ## Use Cases - **CI/CD Integration** -- Trigger code review agents on pull requests - **Monitoring Alerts** -- Execute diagnostic agents when alerts fire - **Form Submissions** -- Process form data through AI agents - **Scheduled Tasks** -- Use cron jobs to trigger periodic agent executions - **Third-Party Webhooks** -- Connect Slack, GitHub, Jira, or any webhook-capable system ## Related Topics - [Agents](/docs/agents) -- The agents that webhook triggers execute - [API Keys and Scopes](/docs/api-keys-and-scopes) -- Alternative authentication method - [Executions](/docs/executions) -- Webhook-triggered executions --- # Agent UI Deployments Source: https://promptrails.ai/docs/agent-ui-deployments > Build and deploy interactive dashboards backed by agents, prompts, and data sources with a grid layout system, multi-page navigation, and PIN protection. # Agent UI Deployments Agent UI Deployments let you create interactive web dashboards that expose your agents, prompts, and data sources to end users without writing any frontend code. Each deployment is a standalone application with its own URL, pages, layout, and optional PIN protection. ## Overview A deployment is a multi-page dashboard where each page contains boxes arranged in a grid layout. Each box is connected to an agent, prompt, or data source, and renders an interactive interface for execution. This enables non-technical users to interact with your AI agents through a simple, customizable web interface. ## Deployment Structure ``` Deployment ├── Page 1 (e.g., "Customer Lookup") │ ├── Box A: Customer Search Agent │ └── Box B: Order History Data Source ├── Page 2 (e.g., "Content Generator") │ ├── Box A: Blog Post Agent │ └── Box B: SEO Analysis Prompt └── Page 3 (e.g., "Analytics") └── Box A: Sales Dashboard Data Source ``` ## Grid Layout System Pages use a **12-column grid system** for responsive layouts. Each box has: | Property | Description | | -------- | ----------------------------- | | `grid_x` | Horizontal position (0-11) | | `grid_y` | Vertical position (row index) | | `grid_w` | Width in columns (1-12) | | `grid_h` | Height in rows | ### Layout Examples **Two equal columns:** ``` Box A: grid_x=0, grid_y=0, grid_w=6, grid_h=4 Box B: grid_x=6, grid_y=0, grid_w=6, grid_h=4 ``` **Full width + two columns below:** ``` Box A: grid_x=0, grid_y=0, grid_w=12, grid_h=3 Box B: grid_x=0, grid_y=3, grid_w=4, grid_h=4 Box C: grid_x=4, grid_y=3, grid_w=8, grid_h=4 ``` ## Box Types Each box connects to one source type: ### Agent Box (`agent`) Renders a form based on the agent's input schema and displays the execution result. ```python box = { "title": "Customer Support", "source_type": "agent", "source_id": "agent-ksuid", "grid_x": 0, "grid_y": 0, "grid_w": 12, "grid_h": 6 } ``` ### Prompt Box (`prompt`) Renders a form for the prompt's input schema and displays the LLM response. ```python box = { "title": "Text Summarizer", "source_type": "prompt", "source_id": "prompt-ksuid", "grid_x": 0, "grid_y": 0, "grid_w": 6, "grid_h": 4 } ``` ### Data Source Box (`data_source`) Renders a parameterized query form and displays results in a table. ```python box = { "title": "Sales Report", "source_type": "data_source", "source_id": "data-source-ksuid", "grid_x": 6, "grid_y": 0, "grid_w": 6, "grid_h": 4 } ``` ## Page Parameters Pages can define parameters that users fill in before executing boxes. Parameters are mapped to box inputs. | Field | Description | | --------------- | --------------------------------------- | | `name` | Parameter identifier | | `label` | Display label | | `param_type` | Input type (text, number, select, etc.) | | `default_value` | Default value | | `options` | Options for select-type parameters | | `required` | Whether the parameter is required | | `sort_order` | Display order | ```python parameter = { "name": "customer_email", "label": "Customer Email", "param_type": "text", "required": True, "sort_order": 1 } ``` ## Input Mapping Box input mapping connects page parameters to the box's source input fields: ```json { "message": "{{customer_email}}", "action": "lookup" } ``` This maps the page parameter `customer_email` to the agent's `message` input field. ## PIN Protection Deployments can require a PIN code for access. Enable **Require PIN** while configuring the deployment and set the PIN in the dashboard before publishing. When enabled, users must enter the correct PIN before accessing the deployment. The PIN is hashed before storage. ## Public URLs Each deployment has a unique slug that forms its public URL: ``` https://your-instance.com/d/internal-tools ``` Slugs must be unique across all deployments. ## Creating a Deployment Create deployments from the PromptRails dashboard: 1. Open **Agent UI Deployments** in your workspace. 2. Create a new deployment and set its name, slug, description, and PIN requirements. 3. Add one or more pages to define the navigation structure. 4. Add page parameters for shared inputs such as customer ID, email address, or date range. 5. Add boxes to each page and connect them to an agent, prompt, or data source. 6. Configure each box's layout and input mapping, then publish the deployment. ## Analytics Deployments track execution logs including: - Which boxes were executed - Input payloads and output summaries - Status (success/failure) - Session tracking - Error messages Review these logs from the deployment detail view in the dashboard to understand how end users are interacting with each page and box. ## Deployment Fields | Field | Type | Description | | ------------------- | --------- | ------------------------------- | | `id` | KSUID | Unique deployment identifier | | `workspace_id` | KSUID | Workspace scope | | `name` | string | Display name | | `description` | string | Optional description | | `slug` | string | URL slug (unique) | | `status` | string | `active` or `inactive` | | `require_pin` | boolean | Whether PIN is required | | `grid_columns` | integer | Grid column count (default: 12) | | `last_published_at` | timestamp | Last publish time | | `created_at` | timestamp | Creation time | | `updated_at` | timestamp | Last update time | ## Related Topics - [Agents](/docs/agents) -- Agents used in dashboard boxes - [Prompts](/docs/prompts) -- Prompts used in dashboard boxes - [Data Sources](/docs/data-sources) -- Data sources used in dashboard boxes --- # Approvals Source: https://promptrails.ai/docs/approvals > Implement human-in-the-loop workflows with configurable approval checkpoints, webhook notifications, and approve/reject decisions. # Approvals The approval system enables human-in-the-loop workflows where agent executions pause at configurable checkpoints and wait for human approval before continuing. This is essential for high-stakes operations where automated decisions need human oversight. ## Human-in-the-Loop Overview When an agent has approval enabled, the execution flow becomes: ``` Input -> Agent Execution -> Checkpoint -> PAUSE (awaiting_approval) | Human reviews execution | Approve -> Continue -> Output Reject -> Execution marked as rejected ``` This ensures that critical actions (financial transactions, customer communications, data modifications) are reviewed by a human before taking effect. ## Enabling Approvals on Agents Enable approvals in the agent version configuration: ```python client.agents.create_version( agent_id="your-agent-id", config={ "approval_required": True, "checkpoint_name": "review_response", "temperature": 0.7 }, message="Added approval requirement for customer responses" ) ``` | Config Field | Description | | ------------------- | -------------------------------------------------------------------------------------- | | `approval_required` | Set to `true` to enable the approval checkpoint | | `checkpoint_name` | A descriptive name for the checkpoint (e.g., "review_response", "approve_transaction") | ## Approval Request Flow ### 1. Execution Reaches Checkpoint When an agent with approvals enabled completes its LLM processing, instead of returning the result, it: 1. Creates an `ApprovalRequest` record 2. Sets the execution status to `awaiting_approval` 3. Fires a webhook event (`execution.awaiting_approval`) ### 2. Human Reviews The approval request is visible in: - The PromptRails dashboard (Approvals page) - Via the API (`approvals:read` scope) - Via webhook notifications The reviewer can see: - The agent that generated the output - The execution input and output - The checkpoint name - When the request was created - Optional expiration time ### 3. Decision The reviewer approves or rejects: ```python # Approve client.approvals.decide( approval_id="approval-request-id", decision="approved", reason="Response looks accurate and appropriate" ) # Reject client.approvals.decide( approval_id="approval-request-id", decision="rejected", reason="Response contains inaccurate pricing information" ) ``` ### 4. Execution Continues or Stops - **Approved**: Execution status changes to `completed` and the output is delivered - **Rejected**: Execution status changes to `rejected` and the output is discarded ## Approval Statuses | Status | Description | | ---------- | ------------------------------------------------------- | | `pending` | Awaiting human review | | `approved` | Approved by a reviewer | | `rejected` | Rejected by a reviewer | | `expired` | The approval request expired before a decision was made | ## Listing Approval Requests ```python # List pending approvals approvals = client.approvals.list(status="pending") for approval in approvals["data"]: print(f"ID: {approval['id']}") print(f"Agent: {approval['agent_id']}") print(f"Checkpoint: {approval['checkpoint_name']}") print(f"Created: {approval['created_at']}") print(f"Payload: {approval['payload']}") print("---") ``` **JavaScript SDK** ```typescript const approvals = await client.approvals.list({ status: 'pending' }) for (const approval of approvals.data) { console.log(`${approval.checkpoint_name} - ${approval.created_at}`) } ``` ## Webhook Notifications When an approval request is created or decided, webhook events are fired: | Event | Description | | ----------------------------- | ------------------------------------ | | `execution.awaiting_approval` | An execution is waiting for approval | | `approval.decided` | An approval was approved or rejected | These events can be used to notify reviewers via Slack, email, or other channels. ## Approval Request Fields | Field | Type | Description | | ----------------- | --------- | -------------------------------------------- | | `id` | KSUID | Unique approval request ID | | `execution_id` | KSUID | The paused execution | | `agent_id` | KSUID | The agent that generated the output | | `workspace_id` | KSUID | Workspace scope | | `checkpoint_name` | string | Name of the approval checkpoint | | `payload` | JSON | The execution output pending approval | | `status` | string | `pending`, `approved`, `rejected`, `expired` | | `decided_by` | KSUID | User who made the decision | | `decided_at` | timestamp | When the decision was made | | `expires_at` | timestamp | Optional expiration time | | `reason` | string | Optional reason for the decision | | `created_at` | timestamp | When the request was created | ## Best Practices - **Name checkpoints clearly** -- Use descriptive names like "review_customer_email" or "approve_refund" so reviewers understand what they are reviewing - **Set expiration times** -- For time-sensitive operations, set an expiration to prevent stale approvals from blocking the pipeline - **Monitor pending approvals** -- Set up webhook notifications to alert reviewers of new approval requests - **Include context in payload** -- Ensure the approval payload includes enough information for the reviewer to make an informed decision - **Document rejection reasons** -- Always provide a reason when rejecting to help improve the agent ## Related Topics - [Agents](/docs/agents) -- Configuring agents with approval checkpoints - [Executions](/docs/executions) -- Execution status integration - [Webhook Triggers](/docs/webhook-triggers) -- Webhook-triggered executions with approvals --- # n8n Integration Source: https://promptrails.ai/docs/n8n-integration > Use PromptRails as a node in your n8n workflows — execute agents, run prompts, manage chat sessions, and more. # n8n Integration The official [n8n](https://n8n.io/) community node for PromptRails lets you integrate AI agents, prompts, chat sessions, and data sources into your n8n workflows. Execute agents on schedule, respond to webhooks with AI, monitor costs, and build complex automation pipelines. ## Installation In your n8n instance: 1. Go to **Settings > Community Nodes** 2. Select **Install a community node** 3. Enter `@promptrails/n8n-nodes-promptrails` 4. Click **Install** ## Configuration Create a **PromptRails API** credential in n8n with the following fields: | Field | Description | | ------------ | ------------------------------------------------ | | **Host URL** | `https://api.promptrails.ai` (default) | | **API Key** | Your PromptRails API key (starts with `pr_key_`) | To create an API key, go to **Settings > API Keys** in the PromptRails dashboard. See [API Keys & Scopes](/docs/api-keys-and-scopes) for required scopes. ## Resources & Operations | Resource | Operations | Required Scopes | | --------------- | ----------------------------------------------------------------------- | ------------------------------------------- | | **Agent** | Execute, Preview, Get, List | `agents:read`, `agents:execute` | | **Prompt** | Run, Get, List | `prompts:read`, `prompts:execute` | | **Chat** | Create Session, Send Message, Get Session, List Sessions, List Messages | `chat:write`, `sessions:read` | | **Execution** | Get, List | `executions:read` | | **Data Source** | Query, Get, List | `data_sources:read`, `data_sources:execute` | | **Trace** | Get, List | `traces:read` | | **Cost** | Workspace Summary, Agent Summary | `executions:read` | ## Example Workflows ### Execute an Agent on Schedule Trigger an agent every hour and send the result to Slack: 1. **Schedule Trigger** — Run every hour 2. **PromptRails** — Resource: Agent, Operation: Execute, provide the Agent ID and variables 3. **Slack** — Post the agent output to a channel ### AI-Powered Webhook Responder Respond to incoming HTTP requests with an AI agent: 1. **Webhook** — Receive incoming requests 2. **PromptRails** — Resource: Chat, Operation: Send Message 3. **Respond to Webhook** — Return the agent's response ### Multi-Turn Chat Bot Build a stateful chatbot using chat sessions: 1. **Webhook** — Receive user messages 2. **IF** — Check if session ID exists in the request 3. **PromptRails** — Resource: Chat, Operation: Create Session (if new) 4. **PromptRails** — Resource: Chat, Operation: Send Message 5. **Respond to Webhook** — Return the response ### Daily Cost Monitoring Monitor your AI spending and get alerts: 1. **Schedule Trigger** — Run daily at 9 AM 2. **PromptRails** — Resource: Cost, Operation: Workspace Summary 3. **IF** — Check if total cost exceeds budget threshold 4. **Email / Slack** — Send an alert notification ### Data Source Query Pipeline Query a data source and process the results: 1. **Schedule Trigger** or **Webhook** — Trigger the workflow 2. **PromptRails** — Resource: Data Source, Operation: Query 3. **PromptRails** — Resource: Agent, Operation: Execute (analyze the query results) 4. **Google Sheets** — Write the analysis to a spreadsheet ## Tips - **Variables as JSON**: Agent Execute and Prompt Run accept variables as a JSON object. Use n8n expressions to build dynamic variables from previous nodes: `{{ JSON.stringify({ query: $json.message }) }}` - **Pagination**: List operations support `page` and `limit` parameters for paginating through results - **Error handling**: Use n8n's built-in error handling to retry failed operations or route to fallback paths - **Chaining**: Chain multiple PromptRails operations — e.g., create a chat session, then send messages in sequence ## Related Topics - [API Keys & Scopes](/docs/api-keys-and-scopes) -- Managing API keys and permissions - [Webhook Triggers](/docs/webhook-triggers) -- Trigger agents via HTTP webhooks - [REST API Reference](/docs/rest-api-reference) -- Full API documentation - [Python SDK](/docs/python-sdk) -- Python SDK alternative - [JavaScript SDK](/docs/javascript-sdk) -- JavaScript SDK alternative --- # Python SDK Source: https://promptrails.ai/docs/python-sdk > Official Python SDK for PromptRails with sync and async clients, automatic retries, and typed error handling. # Python SDK The official Python SDK for PromptRails provides both synchronous and asynchronous clients for interacting with the PromptRails API.
GitHub · PyPI
## Installation ```bash pip install promptrails ``` Requires Python 3.9 or later. Current release: **v0.3.0** — streaming chat & executions (sync and async), typed `AgentConfig` dataclasses, `VERSION` export. See the [changelog](https://github.com/promptrails/python-sdk/releases). ## Client Initialization ### Synchronous Client ```python from promptrails import PromptRails client = PromptRails( api_key="your-api-key", base_url="https://api.promptrails.ai", # default timeout=30.0, # seconds, default max_retries=3 # default ) ``` ### Async Client ```python from promptrails import AsyncPromptRails client = AsyncPromptRails( api_key="your-api-key", base_url="https://api.promptrails.ai", timeout=30.0, max_retries=3 ) ``` ### Context Manager Both clients support context managers for automatic cleanup: ```python # Sync with PromptRails(api_key="your-api-key") as client: result = client.agents.list() # Async async with AsyncPromptRails(api_key="your-api-key") as client: result = await client.agents.list() ``` ## Configuration | Parameter | Type | Default | Description | | ------------- | ----- | ---------------------------- | ------------------------------------------ | | `api_key` | str | Required | PromptRails API key | | `base_url` | str | `https://api.promptrails.ai` | API base URL | | `timeout` | float | 30.0 | Request timeout in seconds | | `max_retries` | int | 3 | Maximum retry attempts for failed requests | The API key is sent via the `X-API-Key` header with every request. ## Available Resources | Resource | Attribute | Description | | ---------------- | ------------------------- | --------------------------------------- | | Agents | `client.agents` | Agent CRUD, versioning, execution | | Prompts | `client.prompts` | Prompt CRUD, versioning, execution | | Executions | `client.executions` | Execution listing and details | | Credentials | `client.credentials` | Credential management | | Data Sources | `client.data_sources` | Data source CRUD, versioning, execution | | Chat | `client.chat` | Send messages to chat sessions | | Sessions | `client.sessions` | Chat session management | | Memories | `client.memories` | Agent memory CRUD and search | | Traces | `client.traces` | Trace listing and filtering | | Costs | `client.costs` | Cost analysis and summaries | | MCP Tools | `client.mcp_tools` | MCP tool management | | MCP Templates | `client.mcp_templates` | MCP template browsing | | Guardrails | `client.guardrails` | Guardrail configuration | | Approvals | `client.approvals` | Approval request management | | Scores | `client.scores` | Scoring and evaluation | | Templates | `client.templates` | Flow templates | | Dashboard | `client.dashboard` | Agent UI deployments | | A2A | `client.a2a` | Agent-to-Agent protocol | | LLM Models | `client.llm_models` | Available LLM models | | Webhook Triggers | `client.webhook_triggers` | Webhook trigger management | ## Common Operations ### Execute an Agent ```python result = client.agents.execute( agent_id="agent-id", input={"message": "Hello, world!"}, metadata={"source": "api"} ) print(result["data"]["output"]) print(f"Cost: ${result['data']['cost']:.6f}") ``` ### List Agents ```python agents = client.agents.list(page=1, limit=20) for agent in agents["data"]: print(f"{agent['name']} ({agent['type']})") ``` ### Create a Prompt ```python prompt = client.prompts.create( name="Summarizer", description="Summarizes text" ) version = client.prompts.create_version( prompt_id=prompt["data"]["id"], system_prompt="You are a concise summarizer.", user_prompt="Summarize: {{ text }}", temperature=0.5, message="Initial version" ) ``` ### Chat ```python session = client.chat.create_session(agent_id="agent-id") response = client.chat.send_message( session.id, content="What is PromptRails?" ) print(response.content) ``` ### Stream a Chat Turn `send_message_stream` posts a user message and yields typed Server-Sent Events on the same connection — use it to surface the agent's intermediate reasoning, tool calls, and token deltas in real time. ```python from promptrails import ( ContentEvent, DoneEvent, ErrorEvent, ExecutionEvent, ThinkingEvent, ToolEndEvent, ToolStartEvent, ) session = client.chat.create_session(agent_id="agent-id") for event in client.chat.send_message_stream( session.id, content="What is PromptRails?" ): if isinstance(event, ExecutionEvent): print("execution_id:", event.execution_id) elif isinstance(event, ThinkingEvent): print("[thinking]", event.content) elif isinstance(event, ToolStartEvent): print("[tool_start]", event.name) elif isinstance(event, ToolEndEvent): print("[tool_end]", event.name, event.summary) elif isinstance(event, ContentEvent): print(event.content, end="", flush=True) elif isinstance(event, DoneEvent): print("\n[done]", event.token_usage) elif isinstance(event, ErrorEvent): print("[error]", event.message) break ``` The async client exposes the same method on `AsyncChatResource`: ```python async for event in aclient.chat.send_message_stream( session.id, content="hello" ): ... ``` ### 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`: ```python for event in client.executions.stream(execution_id): if isinstance(event, ContentEvent): print(event.content, end="", flush=True) elif isinstance(event, DoneEvent): break ``` The async variant is available on `AsyncExecutionsResource.stream`. ### Search Memories ```python results = client.memories.search( agent_id="agent-id", query="refund policy", limit=5 ) ``` ### Create a Score ```python client.scores.create( trace_id="trace-id", name="quality", data_type="numeric", value=4.5, source="manual" ) ``` ### Approve an Execution ```python client.approvals.decide( approval_id="approval-id", decision="approved", reason="Looks good" ) ``` ## Typed Agent Config `agents.create_version` takes a typed `AgentConfig` dataclass — one of `SimpleAgentConfig`, `ChainAgentConfig`, `MultiAgentConfig`, `WorkflowAgentConfig`, or `CompositeAgentConfig`. `to_dict()` injects the `type` discriminator automatically and drops unset optional fields. ```python from promptrails import ( ChainAgentConfig, PromptLink, SimpleAgentConfig, ) # Simple agent — one prompt per execution simple = SimpleAgentConfig( prompt_id="prompt-id", approval_required=False, ) # Chain agent — prompts run sequentially chain = ChainAgentConfig( prompt_ids=[ PromptLink(prompt_id="p1", role="step1", sort_order=0), PromptLink(prompt_id="p2", role="step2", sort_order=1), ], ) client.agents.create_version( agent_id="agent-id", version="1.0.0", config=simple, set_current=True, ) ``` See [Agent Versioning](/docs/agent-versioning) for the per-type field reference. ## SDK Version ```python from promptrails import VERSION print(VERSION) # "0.3.0" ``` Every request is sent with `User-Agent: promptrails-python/` so backend telemetry can attribute traffic to the SDK release. ## Error Handling The SDK raises typed exceptions for different error scenarios: ```python from promptrails.exceptions import ( PromptRailsError, ValidationError, UnauthorizedError, ForbiddenError, NotFoundError, RateLimitError, ServerError, ) try: result = client.agents.execute(agent_id="invalid-id", input={}) except NotFoundError as e: print(f"Agent not found: {e.message}") except ValidationError as e: print(f"Invalid input: {e.message}") print(f"Details: {e.details}") except RateLimitError as e: print(f"Rate limited: {e.message}") except UnauthorizedError as e: print(f"Invalid API key: {e.message}") except ForbiddenError as e: print(f"Insufficient permissions: {e.message}") except ServerError as e: print(f"Server error ({e.status_code}): {e.message}") except PromptRailsError as e: print(f"Unexpected error: {e.message}") ``` ### Error Classes | Exception | HTTP Status | Description | | ------------------- | ----------- | ------------------------------------------------- | | `ValidationError` | 400 | Invalid request parameters | | `UnauthorizedError` | 401 | Invalid or missing API key | | `ForbiddenError` | 403 | Insufficient permissions or IP/origin restriction | | `NotFoundError` | 404 | Resource not found | | `RateLimitError` | 429 | Rate limit exceeded | | `ServerError` | 5xx | Server-side error | | `PromptRailsError` | Any | Base class for all SDK errors | All exceptions include: - `message` -- Human-readable error message - `status_code` -- HTTP status code - `code` -- Optional error code string - `details` -- Optional dictionary with additional error details ## Async Usage The async client mirrors the sync client's API but uses `await`: ```python import asyncio from promptrails import AsyncPromptRails async def main(): async with AsyncPromptRails(api_key="your-api-key") as client: # All methods are awaitable agents = await client.agents.list() result = await client.agents.execute( agent_id=agents["data"][0]["id"], input={"message": "Hello"} ) print(result["data"]["output"]) asyncio.run(main()) ``` ## Pagination List endpoints support pagination: ```python # Page-based pagination page1 = client.agents.list(page=1, limit=20) page2 = client.agents.list(page=2, limit=20) ``` ## Related Topics - [Examples](https://github.com/promptrails/examples/tree/main/python) -- Ready-to-run code examples - [Quickstart](/docs/quickstart) -- Getting started guide - [JavaScript SDK](/docs/javascript-sdk) -- JavaScript/TypeScript alternative - [Go SDK](/docs/go-sdk) -- Go alternative - [API Keys and Scopes](/docs/api-keys-and-scopes) -- API key management - [REST API Reference](/docs/rest-api-reference) -- Underlying REST API --- # JavaScript SDK Source: https://promptrails.ai/docs/javascript-sdk > Official JavaScript/TypeScript SDK for PromptRails with full type safety, ESM and CJS support, and automatic retries. # JavaScript SDK 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.
GitHub · npm
## Installation ```bash npm install @promptrails/sdk ``` Or with other package managers: ```bash yarn add @promptrails/sdk pnpm add @promptrails/sdk ``` Supports both ESM and CommonJS module formats. Current release: **v0.3.1** — streaming chat & executions, typed `AgentConfig` union, `VERSION` export. See the [changelog](https://github.com/promptrails/javascript-sdk/releases). ## Client Initialization ```typescript 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 | | Prompts | `client.prompts` | Prompt CRUD, versioning, execution | | Executions | `client.executions` | Execution listing and details | | Credentials | `client.credentials` | Credential management | | Data Sources | `client.dataSources` | Data source CRUD, versioning, execution | | Chat | `client.chat` | Send messages to chat sessions | | Sessions | `client.sessions` | Chat session management | | Memories | `client.memories` | Agent memory CRUD and search | | Traces | `client.traces` | Trace listing and filtering | | Costs | `client.costs` | Cost analysis and summaries | | MCP Tools | `client.mcpTools` | MCP tool management | | MCP Templates | `client.mcpTemplates` | MCP template browsing | | Guardrails | `client.guardrails` | Guardrail configuration | | Approvals | `client.approvals` | Approval request management | | Scores | `client.scores` | Scoring and evaluation | | Templates | `client.templates` | Flow templates | | Dashboard | `client.dashboard` | Agent UI deployments | | Sessions | `client.sessions` | Session management | | A2A | `client.a2a` | Agent-to-Agent protocol | | LLM Models | `client.llmModels` | Available LLM models | | Webhook Triggers | `client.webhookTriggers` | Webhook trigger management | ## Common Operations ### Execute an Agent ```typescript const result = await client.agents.execute('agent-id', { input: { message: 'Hello, world!' }, metadata: { source: 'api' }, }) console.log(result.data.output) console.log(`Cost: $${result.data.cost.toFixed(6)}`) ``` ### List Agents ```typescript 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 ```typescript const prompt = await client.prompts.create({ name: 'Summarizer', description: 'Summarizes text', }) const version = await client.prompts.createVersion(prompt.data.id, { systemPrompt: 'You are a concise summarizer.', userPrompt: 'Summarize: {{ text }}', temperature: 0.5, message: 'Initial version', }) ``` ### Chat ```typescript 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. ```typescript 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: ```typescript 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`: ```typescript for await (const event of client.executions.stream(executionId)) { if (event.type === 'content') process.stdout.write(event.content) if (event.type === 'done') break } ``` ### Search Memories ```typescript const results = await client.memories.search({ agentId: 'agent-id', query: 'refund policy', limit: 5, }) ``` ### Create a Score ```typescript await client.scores.create({ traceId: 'trace-id', name: 'quality', dataType: 'numeric', value: 4.5, source: 'manual', }) ``` ### Approve an Execution ```typescript await client.approvals.decide('approval-id', { decision: 'approved', reason: 'Looks good', }) ``` ## Typed Agent Config `createVersion` takes a typed `AgentConfig` — a discriminated union by agent type. The SDK injects the `type` discriminator automatically, so renames in the backend schema (e.g. `prompt_version_id` → `prompt_id`) surface as TypeScript errors instead of silent runtime failures. ```typescript import { SimpleAgentConfig, ChainAgentConfig, MultiAgentConfig, WorkflowAgentConfig, CompositeAgentConfig, PromptLink, } from '@promptrails/sdk' // Simple agent — one prompt per execution const simple: SimpleAgentConfig = { type: 'simple', prompt_id: 'prompt-id', approval_required: false, } // Chain agent — prompts run sequentially, output of step N feeds step N+1 const chain: ChainAgentConfig = { type: 'chain', prompt_ids: [ { prompt_id: 'p1', role: 'step1', sort_order: 0 }, { prompt_id: 'p2', role: 'step2', sort_order: 1 }, ], } await client.agents.createVersion('agent-id', { version: '1.0.0', config: simple, set_current: true, }) ``` Available variants: `SimpleAgentConfig`, `ChainAgentConfig`, `MultiAgentConfig`, `WorkflowAgentConfig`, `CompositeAgentConfig`. Chain and multi-agent configs use `PromptLink[]`; workflow uses `WorkflowNode[]`; composite uses `CompositeStep[]`. See [Agent Versioning](/docs/agent-versioning) for the per-type field reference. ## SDK Version ```typescript import { VERSION } from '@promptrails/sdk' console.log(VERSION) // "0.3.1" ``` The SDK also sends `User-Agent: promptrails-js/` 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: ```typescript import type { Agent, Prompt, Execution, Trace, Score, Credential, ChatSession, } from '@promptrails/sdk' ``` ## Error Handling The SDK throws typed errors for different HTTP status codes: ```typescript 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 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: ```typescript // ESM import { PromptRails } from '@promptrails/sdk' // CommonJS const { PromptRails } = require('@promptrails/sdk') ``` ## Pagination ```typescript // 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](https://github.com/promptrails/examples/tree/main/javascript) -- Ready-to-run code examples - [Quickstart](/docs/quickstart) -- Getting started guide - [Python SDK](/docs/python-sdk) -- Python alternative - [Go SDK](/docs/go-sdk) -- Go alternative - [API Keys and Scopes](/docs/api-keys-and-scopes) -- API key management - [REST API Reference](/docs/rest-api-reference) -- Underlying REST API --- # Go SDK Source: https://promptrails.ai/docs/go-sdk > Official Go SDK for PromptRails with functional options, typed errors, and automatic retries. # Go SDK The official Go SDK for PromptRails provides a fully typed client for interacting with the PromptRails API from any Go application.
GitHub · pkg.go.dev
## Installation ```bash go get github.com/promptrails/go-sdk@v0.3.1 ``` Requires Go 1.21 or later. Current release: **v0.3.1** — streaming chat & executions via `*ChatStream`, typed `AgentConfig` interface, `promptrails.Version` constant. See the [changelog](https://github.com/promptrails/go-sdk/releases). ## Client Initialization ```go import promptrails "github.com/promptrails/go-sdk" client := promptrails.NewClient("your-api-key") ``` ### With Options ```go import ( "time" promptrails "github.com/promptrails/go-sdk" ) client := promptrails.NewClient("your-api-key", promptrails.WithBaseURL("https://api.promptrails.ai"), // default promptrails.WithTimeout(30 * time.Second), // default promptrails.WithMaxRetries(3), // default ) ``` ## Configuration | Option | Type | Default | Description | | ---------------- | ------------- | ---------------------------- | ----------------------------- | | `WithBaseURL` | string | `https://api.promptrails.ai` | API base URL | | `WithTimeout` | time.Duration | 30s | HTTP request timeout | | `WithMaxRetries` | int | 3 | Maximum retry attempts on 5xx | The API key is sent via the `X-API-Key` header with every request. ## Available Resources | Resource | Field | Description | | ---------------- | ------------------------ | --------------------------------------- | | Agents | `client.Agents` | Agent CRUD, versioning, execution | | Prompts | `client.Prompts` | Prompt CRUD, versioning, execution | | Executions | `client.Executions` | Execution listing and details | | Credentials | `client.Credentials` | Credential management | | Data Sources | `client.DataSources` | Data source CRUD, versioning, execution | | Chat | `client.Chat` | Send messages to chat sessions | | Traces | `client.Traces` | Trace listing and filtering | | Costs | `client.Costs` | Cost analysis and summaries | | MCP Tools | `client.MCPTools` | MCP tool management | | Approvals | `client.Approvals` | Approval request management | | Scores | `client.Scores` | Scoring and evaluation | | A2A | `client.A2A` | Agent-to-Agent protocol | | Webhook Triggers | `client.WebhookTriggers` | Webhook trigger management | ## Common Operations ### Execute an Agent ```go ctx := context.Background() result, err := client.Agents.Execute(ctx, "agent-id", &promptrails.ExecuteAgentParams{ Input: map[string]any{"message": "Hello, world!"}, Sync: true, }) if err != nil { log.Fatal(err) } fmt.Println(result.Data.Output) ``` ### List Agents ```go agents, err := client.Agents.List(ctx, &promptrails.ListAgentsParams{ Page: 1, Limit: 20, }) if err != nil { log.Fatal(err) } for _, agent := range agents.Data { fmt.Printf("%s (%s)\n", agent.Name, agent.Type) } ``` ### Create a Prompt ```go prompt, err := client.Prompts.Create(ctx, &promptrails.CreatePromptParams{ Name: "Summarizer", Description: "Summarizes text", }) if err != nil { log.Fatal(err) } fmt.Println(prompt.Data.ID) ``` ### View Executions ```go executions, err := client.Executions.List(ctx, &promptrails.ListExecutionsParams{ Page: 1, Limit: 10, }) if err != nil { log.Fatal(err) } for _, exec := range executions.Data { fmt.Printf("ID: %s, Status: %s\n", exec.ID, exec.Status) } ``` ### Approve an Execution ```go err := client.Approvals.Decide(ctx, "approval-id", &promptrails.DecideApprovalParams{ Decision: "approved", Reason: "Looks good", }) ``` ### Stream a Chat Turn `Chat.SendMessageStream` posts a user message and returns a `*ChatStream` that yields typed events on the same HTTP connection. Cancel by cancelling `ctx`; always `defer stream.Close()`. ```go session, err := client.Chat.CreateSession(ctx, &promptrails.CreateSessionParams{ AgentID: "agent-id", }) if err != nil { log.Fatal(err) } stream, err := client.Chat.SendMessageStream(ctx, session.ID, &promptrails.SendMessageParams{ Content: "What is PromptRails?", }) if err != nil { log.Fatal(err) } defer stream.Close() for stream.Next() { switch e := stream.Event().(type) { case *promptrails.ExecutionEvent: log.Printf("execution_id: %s", e.ExecutionID) case *promptrails.ThinkingEvent: log.Printf("[thinking] %s", e.Content) case *promptrails.ToolStartEvent: log.Printf("[tool_start] %s", e.Name) case *promptrails.ToolEndEvent: log.Printf("[tool_end] %s (%s)", e.Name, e.Summary) case *promptrails.ContentEvent: fmt.Print(e.Content) case *promptrails.DoneEvent: fmt.Printf("\n[done] %d tokens\n", e.TokenUsage.TotalTokens) case *promptrails.ErrorEvent: log.Fatalf("[error] %s", e.Message) } } if err := stream.Err(); err != nil { log.Fatal(err) } ``` ### Stream an Existing Execution When an execution was started outside a chat (e.g. `Agents.Execute`), subscribe to its live event stream: ```go stream, err := client.Executions.Stream(ctx, executionID) if err != nil { log.Fatal(err) } defer stream.Close() for stream.Next() { if e, ok := stream.Event().(*promptrails.ContentEvent); ok { fmt.Print(e.Content) } } ``` ## Typed Agent Config `Agents.CreateVersion` takes a typed `AgentConfig` — an interface implemented by the five concrete variants. Each concrete type's `MarshalJSON` injects the required `type` discriminator. ```go import promptrails "github.com/promptrails/go-sdk" // Simple agent — one prompt per execution simple := promptrails.SimpleAgentConfig{ PromptID: "prompt-id", } // Chain agent — prompts run sequentially chain := promptrails.ChainAgentConfig{ PromptIDs: []promptrails.PromptLink{ {PromptID: "p1", Role: "step1", SortOrder: 0}, {PromptID: "p2", Role: "step2", SortOrder: 1}, }, } _, err := client.Agents.CreateVersion(ctx, "agent-id", &promptrails.CreateVersionParams{ Version: "1.0.0", Config: simple, // or chain, MultiAgentConfig, WorkflowAgentConfig, CompositeAgentConfig SetCurrent: true, }) ``` See [Agent Versioning](/docs/agent-versioning) for the per-type field reference. ## SDK Version ```go import promptrails "github.com/promptrails/go-sdk" fmt.Println(promptrails.Version) // "0.3.1" ``` Every request is sent with `User-Agent: promptrails-go/` so backend telemetry can attribute traffic to the SDK release. ## Error Handling The SDK returns typed errors for different HTTP status codes. Use `errors.As` to handle specific error types: ```go import "errors" result, err := client.Agents.Execute(ctx, "invalid-id", &promptrails.ExecuteAgentParams{ Input: map[string]any{}, }) if err != nil { var notFound *promptrails.NotFoundError var validation *promptrails.ValidationError var unauthorized *promptrails.UnauthorizedError var forbidden *promptrails.ForbiddenError var rateLimit *promptrails.RateLimitError var serverErr *promptrails.ServerError switch { case errors.As(err, ¬Found): fmt.Printf("Agent not found: %s\n", notFound.Message) case errors.As(err, &validation): fmt.Printf("Invalid input: %s\n", validation.Message) case errors.As(err, &unauthorized): fmt.Printf("Invalid API key: %s\n", unauthorized.Message) case errors.As(err, &forbidden): fmt.Printf("Insufficient permissions: %s\n", forbidden.Message) case errors.As(err, &rateLimit): fmt.Printf("Rate limited: %s\n", rateLimit.Message) case errors.As(err, &serverErr): fmt.Printf("Server error: %s\n", serverErr.Message) default: fmt.Printf("Unexpected error: %v\n", err) } } ``` ### Error Types | Error | HTTP Status | Description | | -------------------- | ----------- | ------------------------------------------------- | | `ValidationError` | 400 | Invalid request parameters | | `UnauthorizedError` | 401 | Invalid or missing API key | | `QuotaExceededError` | 402 | Plan quota exceeded | | `ForbiddenError` | 403 | Insufficient permissions or IP/origin restriction | | `NotFoundError` | 404 | Resource not found | | `RateLimitError` | 429 | Rate limit exceeded | | `ServerError` | 5xx | Server-side error | | `APIError` | Any | Base type for all API errors | All error types embed `APIError` which includes: - `StatusCode` -- HTTP status code - `Message` -- Human-readable error message - `Code` -- Optional error code string - `Details` -- Optional map with additional error details ## Context Support All SDK methods require a `context.Context` as the first argument, enabling cancellation and timeouts: ```go ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() result, err := client.Agents.Execute(ctx, "agent-id", &promptrails.ExecuteAgentParams{ Input: map[string]any{"message": "Hello"}, Sync: true, }) ``` ## Pagination List endpoints return paginated responses: ```go // Page-based pagination page1, _ := client.Agents.List(ctx, &promptrails.ListAgentsParams{Page: 1, Limit: 20}) page2, _ := client.Agents.List(ctx, &promptrails.ListAgentsParams{Page: 2, Limit: 20}) fmt.Printf("Total: %d, Pages: %d\n", page1.Meta.Total, page1.Meta.TotalPages) ``` ## Related Topics - [Examples](https://github.com/promptrails/examples/tree/main/go) -- Ready-to-run code examples - [Quickstart](/docs/quickstart) -- Getting started guide - [Python SDK](/docs/python-sdk) -- Python alternative - [JavaScript SDK](/docs/javascript-sdk) -- JavaScript/TypeScript alternative - [CLI](/docs/cli) -- Command-line interface - [API Keys and Scopes](/docs/api-keys-and-scopes) -- API key management - [REST API Reference](/docs/rest-api-reference) -- Underlying REST API --- # CLI Source: https://promptrails.ai/docs/cli > Manage PromptRails from the command line with the official CLI for agents, prompts, executions, credentials, and more. # CLI The PromptRails CLI provides command-line access to all major platform features. Use it for scripting, CI/CD pipelines, and quick operations from your terminal.
GitHub
## Installation ```bash # macOS (Homebrew) brew install promptrails/tap/promptrails # Download binary from GitHub releases # Replace OS and ARCH with your platform (e.g., darwin-arm64, linux-amd64) curl -sL https://github.com/promptrails/cli/releases/latest/download/promptrails-OS-ARCH.tar.gz | tar xz sudo mv promptrails /usr/local/bin/ ``` Verify installation: ```bash promptrails version ``` ## Authentication ### Initialize Configuration ```bash promptrails init ``` This creates configuration files at `~/.promptrails/config.json` and `~/.promptrails/credentials.json`, prompting for your API URL and API key. ### Environment Variables You can also authenticate via environment variables (useful for CI/CD): ```bash export PROMPTRAILS_API_KEY="your-api-key" export PROMPTRAILS_API_URL="https://api.promptrails.ai" ``` Environment variables take precedence over the config file. ## Commands ### Agent Commands ```bash # List agents promptrails agent list # Get agent details promptrails agent get # Create an agent promptrails agent create --name "My Agent" --type simple # Execute an agent promptrails agent execute --input '{"message": "Hello"}' # List agent versions promptrails agent versions # Promote a version promptrails agent promote ``` ### Prompt Commands ```bash # List prompts promptrails prompt list # Get prompt details promptrails prompt get # Create a prompt promptrails prompt create --name "Summarizer" # Execute a prompt promptrails prompt execute --input '{"text": "Long text..."}' # List versions promptrails prompt versions ``` ### Execution Commands ```bash # List recent executions promptrails execution list # Get execution details promptrails execution get # Filter by agent promptrails execution list --agent-id # Filter by status promptrails execution list --status completed ``` ### Credential Commands ```bash # List credentials promptrails credential list # Create a credential promptrails credential create \ --name "OpenAI Key" \ --category llm \ --type openai \ --value "sk-..." # Check a credential's validity promptrails credential check # Delete a credential promptrails credential delete ``` ### Webhook Trigger Commands ```bash # List triggers promptrails webhook-trigger list # Create a trigger promptrails webhook-trigger create \ --agent-id \ --name "Deploy Trigger" # Activate/deactivate promptrails webhook-trigger activate promptrails webhook-trigger deactivate ``` ### Workspace Commands ```bash # Show current workspace (determined by API key) promptrails workspace current ``` ### Other Commands ```bash # Check CLI and API status promptrails status # Show CLI version promptrails version ``` ## Output Formats The CLI supports two output formats: ### Table (default) ```bash promptrails agent list ``` ``` ID NAME TYPE STATUS 2NxAbc123def456ghi789jkl Customer Support simple active 2NxBbc456def789ghi012jkl Data Pipeline chain active 2NxCbc789def012ghi345jkl Multi-Agent System multi_agent archived ``` ### JSON ```bash promptrails agent list --output json ``` ```json { "data": [ { "id": "2NxAbc123def456ghi789jkl", "name": "Customer Support", "type": "simple", "status": "active" } ] } ``` ## Shell Completions Generate shell completion scripts: ```bash # Bash promptrails completion bash > /etc/bash_completion.d/promptrails # Zsh promptrails completion zsh > "${fpath[1]}/_promptrails" # Fish promptrails completion fish > ~/.config/fish/completions/promptrails.fish ``` ## CI/CD Usage ### GitHub Actions Example ```yaml name: Execute Agent on: push: branches: [main] jobs: execute: runs-on: ubuntu-latest steps: - name: Install CLI run: | curl -sL https://github.com/promptrails/cli/releases/latest/download/promptrails-linux-amd64.tar.gz | tar xz sudo mv promptrails /usr/local/bin/ - name: Execute agent env: PROMPTRAILS_API_KEY: ${{ secrets.PROMPTRAILS_API_KEY }} run: | promptrails agent execute ${{ vars.AGENT_ID }} \ --input '{"branch": "${{ github.ref_name }}", "commit": "${{ github.sha }}"}' \ --output json ``` ### GitLab CI Example ```yaml execute-agent: image: ubuntu:latest variables: PROMPTRAILS_API_KEY: $PROMPTRAILS_API_KEY script: - apt-get update && apt-get install -y curl - curl -sL https://github.com/promptrails/cli/releases/latest/download/promptrails-linux-amd64.tar.gz | tar xz - mv promptrails /usr/local/bin/ - promptrails agent execute $AGENT_ID --input '{"event": "deploy"}' ``` ## Environment Variables Reference | Variable | Description | | --------------------- | ---------------------------------------------------- | | `PROMPTRAILS_API_KEY` | API key for authentication | | `PROMPTRAILS_API_URL` | API base URL (default: `https://api.promptrails.ai`) | ## Related Topics - [API Keys and Scopes](/docs/api-keys-and-scopes) -- Creating API keys for CLI use - [Python SDK](/docs/python-sdk) -- Python alternative for scripting - [JavaScript SDK](/docs/javascript-sdk) -- JavaScript alternative - [Go SDK](/docs/go-sdk) -- Go alternative --- # MCP Server Source: https://promptrails.ai/docs/mcp-server > Connect your IDE to PromptRails with the built-in MCP server for Claude Desktop, Cursor, Windsurf, and other MCP-compatible tools. # MCP Server PromptRails includes a built-in MCP (Model Context Protocol) server that exposes the full platform API as tools for AI-powered IDEs. This enables you to manage agents, execute prompts, review traces, and more directly from Claude Desktop, Cursor, Windsurf, or any MCP-compatible client. ## What is the MCP Server? The MCP server translates PromptRails API operations into MCP tools that AI assistants can invoke. When connected, your IDE's AI assistant can: - Create and manage agents, prompts, and data sources - Execute agents and view results - Browse execution traces and costs - Manage credentials, guardrails, and memories - Handle approval requests - Send chat messages ## Connection Configuration ### Claude Desktop Add to your Claude Desktop configuration file (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS): ```json { "mcpServers": { "promptrails": { "command": "promptrails", "args": ["mcp", "serve"], "env": { "PROMPTRAILS_API_KEY": "your-api-key", "PROMPTRAILS_WORKSPACE_ID": "your-workspace-id", "PROMPTRAILS_API_URL": "https://api.promptrails.ai" } } } } ``` ### Cursor Add to your Cursor MCP settings (`.cursor/mcp.json` in your project root): ```json { "mcpServers": { "promptrails": { "command": "promptrails", "args": ["mcp", "serve"], "env": { "PROMPTRAILS_API_KEY": "your-api-key", "PROMPTRAILS_WORKSPACE_ID": "your-workspace-id", "PROMPTRAILS_API_URL": "https://api.promptrails.ai" } } } } ``` ### Windsurf Add to your Windsurf MCP configuration: ```json { "mcpServers": { "promptrails": { "command": "promptrails", "args": ["mcp", "serve"], "env": { "PROMPTRAILS_API_KEY": "your-api-key", "PROMPTRAILS_WORKSPACE_ID": "your-workspace-id", "PROMPTRAILS_API_URL": "https://api.promptrails.ai" } } } } ``` ## Available Tools The MCP server exposes tools across all major PromptRails resource categories: ### Agents | Tool | Description | | ----------------------- | -------------------------------- | | `list_agents` | List all agents in the workspace | | `get_agent` | Get agent details by ID | | `create_agent` | Create a new agent | | `update_agent` | Update agent properties | | `delete_agent` | Delete an agent | | `execute_agent` | Execute an agent with input | | `list_agent_versions` | List versions of an agent | | `create_agent_version` | Create a new agent version | | `promote_agent_version` | Promote a version to current | ### Prompts | Tool | Description | | ------------------------ | ------------------------ | | `list_prompts` | List all prompts | | `get_prompt` | Get prompt details | | `create_prompt` | Create a new prompt | | `update_prompt` | Update prompt properties | | `delete_prompt` | Delete a prompt | | `execute_prompt` | Execute a prompt | | `list_prompt_versions` | List prompt versions | | `create_prompt_version` | Create a prompt version | | `promote_prompt_version` | Promote a prompt version | ### Data Sources | Tool | Description | | --------------------- | --------------------------- | | `list_data_sources` | List data sources | | `get_data_source` | Get data source details | | `create_data_source` | Create a data source | | `execute_data_source` | Execute a data source query | ### Chat | Tool | Description | | ---------------- | --------------------- | | `list_sessions` | List chat sessions | | `create_session` | Create a chat session | | `send_message` | Send a chat message | ### Credentials | Tool | Description | | --------------------- | ------------------------- | | `list_credentials` | List credentials (masked) | | `create_credential` | Create a credential | | `validate_credential` | Test a credential | ### MCP Tools | Tool | Description | | ----------------- | ------------------ | | `list_mcp_tools` | List MCP tools | | `create_mcp_tool` | Create an MCP tool | | `update_mcp_tool` | Update an MCP tool | | `delete_mcp_tool` | Delete an MCP tool | ### Guardrails | Tool | Description | | ------------------ | ---------------------------- | | `list_guardrails` | List guardrails for an agent | | `create_guardrail` | Add a guardrail to an agent | | `update_guardrail` | Update guardrail config | | `delete_guardrail` | Remove a guardrail | ### Memories | Tool | Description | | ----------------- | ---------------------- | | `list_memories` | List agent memories | | `create_memory` | Create a memory | | `search_memories` | Semantic memory search | | `delete_memory` | Delete a memory | ### Approvals | Tool | Description | | ----------------- | ---------------------- | | `list_approvals` | List approval requests | | `decide_approval` | Approve or reject | ### Executions | Tool | Description | | ----------------- | --------------------- | | `list_executions` | List executions | | `get_execution` | Get execution details | ### Traces | Tool | Description | | ------------- | ---------------- | | `list_traces` | List trace spans | | `get_trace` | Get span details | ## API Key Authentication The MCP server authenticates using the same API keys used by the SDKs. The key's scopes determine which tools are available: - An API key with `agents:read` scope enables `list_agents` and `get_agent` - An API key with `*` scope enables all tools ## Example Usage Once connected, you can interact with PromptRails naturally through your IDE's AI assistant: ``` User: "List my agents" Assistant: [calls list_agents] You have 5 agents: 1. Customer Support Bot (simple, active) 2. Data Pipeline (chain, active) ... User: "Execute the Customer Support Bot with message 'What are your hours?'" Assistant: [calls execute_agent] The agent responded: "Our support hours are Monday-Friday, 9am-5pm EST..." Cost: $0.002, Duration: 1.2s User: "Show me the trace for that execution" Assistant: [calls list_traces] The execution trace shows: 1. [agent] Customer Support Bot (1200ms) - [guardrail] prompt_injection scan (15ms) - OK - [prompt] Render main prompt (2ms) - [llm] gpt-4o call (1150ms, 340 tokens, $0.002) - [guardrail] pii output scan (8ms) - OK ``` ## Related Topics - [CLI](/docs/cli) -- CLI installation (required for the MCP server) - [MCP Tools](/docs/mcp-tools) -- Using MCP tools within agents - [API Keys and Scopes](/docs/api-keys-and-scopes) -- Authentication --- # A2A Protocol Source: https://promptrails.ai/docs/a2a-protocol > Enable agent-to-agent communication with Google's A2A protocol, agent cards, JSON-RPC messaging, and task lifecycle management. # A2A Protocol PromptRails implements the **Agent-to-Agent (A2A) protocol**, an open standard by Google for inter-agent communication. A2A enables agents to discover each other, exchange messages, and coordinate on tasks across different systems and platforms. ## What is A2A? The A2A protocol defines a standard way for AI agents to: - **Discover** other agents through agent cards - **Communicate** using JSON-RPC messages - **Coordinate** work through a task lifecycle - **Exchange results** via task artifacts This enables multi-agent architectures where specialized agents collaborate to solve complex problems, even when running on different platforms. ## Agent Cards An agent card is a machine-readable description of an agent's capabilities. It includes: - Agent name and description - Supported input/output formats - Available skills and capabilities - Authentication requirements - Endpoint URL Agent cards enable automated discovery -- one agent can find and evaluate other agents based on their published capabilities. ```python # Get an agent's A2A card card = client.a2a.get_agent_card("your-agent-id") print(f"Name: {card.name}") print(f"Description: {card.description}") print(f"Skills: {[skill.name for skill in card.skills]}") ``` ## JSON-RPC Messaging A2A communication uses JSON-RPC 2.0 as the transport format. Messages include: ```json { "jsonrpc": "2.0", "method": "tasks/send", "params": { "id": "task-id", "message": { "role": "user", "parts": [ { "type": "text", "text": "Analyze this dataset and generate a report" } ] } } } ``` ## Task Lifecycle A2A tasks follow a defined lifecycle: ``` submitted -> working -> completed -> failed -> canceled -> rejected -> input_required -> (user provides input) -> working ``` ### Task Statuses | Status | Description | | ---------------- | -------------------------------------------------------- | | `submitted` | Task has been submitted to the agent | | `working` | Agent is actively processing the task | | `input_required` | Agent needs additional input to continue | | `completed` | Task finished successfully | | `failed` | Task encountered an error | | `canceled` | Task was cancelled by the requester | | `rejected` | Agent rejected the task (e.g., outside its capabilities) | ## Creating and Managing Tasks ### Send a Task ```python task = client.a2a.send_message( "your-agent-id", "Summarize the Q4 sales report", context_id="optional-conversation-context" ) print(f"Task ID: {task.id}") print(f"Status: {task.status.state}") ``` ### Get Task Status ```python task = client.a2a.get_task("task-id") print(f"Status: {task.status.state}") print(f"Messages: {len(task.messages)}") print(f"Artifacts: {len(task.artifacts)}") ``` ### Cancel a Task ```python client.a2a.cancel_task("task-id") ``` ## Task Artifacts When a task completes, the agent may produce artifacts -- structured outputs that represent the work product: ```json { "artifacts": [ { "type": "text", "text": "The Q4 sales report shows a 15% increase..." }, { "type": "file", "name": "report.pdf", "mimeType": "application/pdf", "data": "base64-encoded-content" } ] } ``` ## Multi-Agent Coordination A2A enables patterns like: ### Sequential Processing Agent A processes data, then passes results to Agent B for further analysis: ```python # Agent A: Data extraction task_a = client.a2a.send_message( "data-extractor-agent", "Extract sales data from Q4" ) # Wait for completion, then pass to Agent B # Agent B: Analysis task_b = client.a2a.send_message( "analyst-agent", f"Analyze: {task_a_result}", context_id=task_a.context_id ) ``` ### Parallel Processing Multiple agents work on different aspects simultaneously: ```python import asyncio async def multi_agent_analysis(): async with AsyncPromptRails(api_key="your-key") as client: tasks = await asyncio.gather( client.a2a.send_message("sentiment-agent", "Analyze sentiment"), client.a2a.send_message("topic-agent", "Extract key topics"), client.a2a.send_message("summary-agent", "Summarize the conversation"), ) return tasks ``` ### Input-Required Flow An agent can request additional input during processing: ```python task = client.a2a.send_message("agent-id", initial_message) # Check if the agent needs more input if task.status and task.status.state == "input_required": # Provide additional input task = client.a2a.send_message( "agent-id", "Additional context...", task_id=task.id, ) ``` ## Task Fields | Field | Type | Description | | ------------ | --------- | ------------------------------- | | `id` | KSUID | Unique task identifier | | `context_id` | string | Conversation context identifier | | `status` | object | Current task status payload | | `messages` | array | Message history | | `artifacts` | array | Task outputs | | `metadata` | JSON | Custom metadata | | `created_at` | timestamp | Creation time | | `updated_at` | timestamp | Last update time | ## Related Topics - [Agents](/docs/agents) -- Agents that participate in A2A - [Executions](/docs/executions) -- A2A tasks create executions - [Python SDK](/docs/python-sdk) -- Python A2A client - [JavaScript SDK](/docs/javascript-sdk) -- JavaScript A2A client --- # Local Emulator Source: https://promptrails.ai/docs/local-emulator > Run a local PromptRails API emulator for development and testing — like LocalStack for AWS, but for PromptRails. # Local Emulator PromptRails Local is an in-memory API emulator that lets you develop and test against the PromptRails API without a real backend. Think of it like [LocalStack](https://localstack.cloud) for AWS, but for PromptRails. All data lives in memory and resets on restart. It comes pre-loaded with example agents, prompts, credentials, and LLM models so you can start testing immediately. ## Quick Start ```bash docker run -p 8080:8080 bahattincinic/promptrails-local ``` The emulator starts with seed data and is ready to use: - **API**: http://localhost:8080/api/v1 - **Interactive Docs**: http://localhost:8080/docs (Scalar) - **Health Check**: http://localhost:8080/health ## Connect Your SDK Point any PromptRails SDK to the emulator by changing the base URL: ### Python ```python from promptrails import PromptRails client = PromptRails(api_key="test-key", base_url="http://localhost:8080") agents = client.agents.list() for agent in agents.data: print(f"{agent.name} ({agent.type})") # Execute an agent (returns simulated response) result = client.agents.execute( "39wNZZu78VawB207IOPonkoP38J", input={"topic": "AI agents"} ) print(result.status) # "completed" ``` ### JavaScript / TypeScript ```typescript import { PromptRails } from '@promptrails/sdk' const client = new PromptRails({ apiKey: 'test-key', baseUrl: 'http://localhost:8080', }) const agents = await client.agents.list() const result = await client.agents.execute('39wNZZu78VawB207IOPonkoP38J', { input: { topic: 'AI agents' }, }) ``` ### Go ```go client := promptrails.NewClient("test-key", promptrails.WithBaseURL("http://localhost:8080")) agents, _ := client.Agents.List(ctx, nil) result, _ := client.Agents.Execute(ctx, "39wNZZu78VawB207IOPonkoP38J", &promptrails.ExecuteAgentParams{ Input: map[string]any{"topic": "AI agents"}, }) ``` ## Pre-loaded Seed Data The emulator starts with example data so you can immediately test: | Resource | Count | Details | | --------------- | ----- | ------------------------------------------------------------- | | Agents | 6 | simple, chain, multi_agent, approval types | | Agent Versions | 15 | Multiple versions per agent | | Prompts | 8 | Various templates with `{{ variable }}` syntax | | Prompt Versions | 12 | With system/user prompts and input schemas | | Data Sources | 2 | PostgreSQL examples | | Credentials | 4 | OpenAI, Gemini, PostgreSQL, Linear | | LLM Models | 42 | Full catalog (OpenAI, Anthropic, Gemini, DeepSeek, xAI, etc.) | | MCP Tools | 6 | Builtin, datasource, remote, API types | | Guardrails | 1 | PII redaction example | | Memories | 4 | Fact, procedure, semantic types | ## Supported Endpoints | Resource | CRUD | Execute | Notes | | ---------------- | ---- | ----------------- | --------------------------------- | | Agents | Yes | Yes (simulated) | + versions, promote, preview | | Prompts | Yes | Yes (simulated) | + versions, promote, preview, run | | Executions | Read | Auto-created | Created by agent execute | | Data Sources | Yes | Mock results | + versions | | Credentials | Yes | — | No real validation | | Chat Sessions | Yes | Simulated replies | Multi-turn tracking | | LLM Models | Read | — | From seed catalog | | Traces | Read | Auto-created | Created by executions | | Scores | Yes | — | + score configs | | Approvals | Yes | — | Approve/reject flow | | Webhook Triggers | Yes | Yes | Token-based hook endpoint | | MCP Tools | Yes | — | + templates | | Guardrails | Yes | — | | | Memories | Yes | — | + search | ## Custom Fixtures Load your own test data from a directory: ```bash # Default seed + your custom data docker run -p 8080:8080 \ -v ./my-fixtures:/fixtures \ -e FIXTURES=/fixtures \ bahattincinic/promptrails-local # Only your data (no default seed) docker run -p 8080:8080 \ -v ./my-fixtures:/fixtures \ -e SEED=false \ -e FIXTURES=/fixtures \ bahattincinic/promptrails-local ``` Place JSON files in your fixtures directory — all files are optional: ``` my-fixtures/ agents.json agent_versions.json prompts.json prompt_versions.json credentials.json llm_models.json data_sources.json mcp_tools.json guardrails.json memories.json ``` See the [fixtures documentation](https://github.com/promptrails/promptrails-local/blob/main/docs/fixtures.md) for the complete file format reference. ## Configuration | Flag | Env | Default | Description | | ---------------- | -------------- | ------- | ---------------------------- | | `--port` | `PORT` | `8080` | Server port | | `--seed` | `SEED` | `true` | Load built-in seed data | | `--fixtures` | `FIXTURES` | — | Load fixtures from directory | | `--log-level` | `LOG_LEVEL` | `info` | debug, info, warn, error | | `--cors-origins` | `CORS_ORIGINS` | `*` | CORS allowed origins | ## Admin Endpoints Reset state between test runs: ```bash # Reset all data and reload seed curl -X POST http://localhost:8080/admin/reset # View store statistics curl http://localhost:8080/admin/store/stats ``` ## Use in CI/CD ```yaml # GitHub Actions example jobs: test: runs-on: ubuntu-latest services: promptrails: image: bahattincinic/promptrails-local ports: - 8080:8080 steps: - uses: actions/checkout@v4 - run: pytest tests/ -v env: PROMPTRAILS_BASE_URL: http://localhost:8080 ``` ## Authentication The emulator accepts any value for the `X-API-Key` header — no real authentication is performed. All data lives in a single flat namespace with no workspace isolation. ## Installation Options | Method | Command | | -------------- | ------------------------------------------------------------------------------------------------------- | | Docker | `docker run -p 8080:8080 bahattincinic/promptrails-local` | | Docker Compose | See [docker-compose.yml](https://github.com/promptrails/promptrails-local/blob/main/docker-compose.yml) | | Go Install | `go install github.com/promptrails/promptrails-local@latest` | | Binary | [GitHub Releases](https://github.com/promptrails/promptrails-local/releases) | --- # Skills Source: https://promptrails.ai/docs/skills > Install PromptRails skills for AI coding assistants like Claude Code, Cursor, and Windsurf to get contextual help with SDKs, CLI, and platform features. # Skills PromptRails provides **skills** for AI coding assistants — pre-built knowledge packages that teach tools like Claude Code, Cursor, and Windsurf how to work with PromptRails SDKs, CLI, agents, prompts, tracing, and more. When a skill is installed, your AI assistant automatically knows how to: - Use Python, JavaScript, and Go SDKs correctly - Run CLI commands for agent management - Create and configure agents, prompts, and data sources - Debug executions using tracing - Set up MCP tools and guardrails - Follow PromptRails best practices ## Installation ### Cursor Use the plugin system to install the PromptRails skill: ``` /add-plugin promptrails/skills ``` ### Skills CLI Install using the `npx skills` command: ```bash npx skills add promptrails/skills --skill "promptrails" ``` ### Claude Code Add the skill path to your project's `.claude/settings.json`: ```json { "skills": ["path/to/skills/skills/promptrails/SKILL.md"] } ``` Or clone the repository and symlink it into your Claude Code skills directory. ### Manual Setup Clone the [skills repository](https://github.com/promptrails/skills) and point your AI assistant's configuration to the `skills/promptrails/SKILL.md` file: ```bash git clone https://github.com/promptrails/skills.git promptrails-skills ``` ## What's Included The skill package includes a main skill definition and detailed reference guides: | Reference | Description | | ------------------ | ------------------------------------------------------------------ | | **CLI** | All CLI commands, flags, environment variables, and CI/CD examples | | **Python SDK** | Complete Python SDK API with sync/async patterns | | **JavaScript SDK** | Full JS/TS SDK API with TypeScript types | | **Go SDK** | Complete Go SDK API with context and error handling | | **Agents** | Agent types, configuration, versioning, and execution | | **Prompts** | Jinja2 templating, model assignment, caching | | **Tracing** | 18 span kinds, cost tracking, debugging | | **MCP Tools** | Tool types (API, datasource, builtin, remote MCP) | | **Data Sources** | Database connections, parameterized queries | ## How It Works Skills use a progressive disclosure approach: 1. The **main skill file** (`SKILL.md`) contains essential patterns and quick-start examples 2. **Reference files** provide detailed API documentation loaded only when needed 3. Your AI assistant uses the skill context to generate accurate, idiomatic code This means the assistant won't hallucinate API methods or use outdated patterns — it has the actual SDK reference available. ## Example Usage Once installed, you can ask your AI assistant things like: - "Execute my customer support agent with the Python SDK" - "Set up a chain agent with two prompts" - "Show me how to filter traces by LLM span kind" - "Create a webhook trigger for my agent using the CLI" - "Add a PII guardrail to my agent" The assistant will use the skill's reference materials to provide accurate, working code. ## Updating To get the latest skill definitions, update your installation: ```bash # Skills CLI npx skills update promptrails/skills # Manual cd promptrails-skills && git pull ``` ## Source Code The skills are open source and available on GitHub: - [github.com/promptrails/skills](https://github.com/promptrails/skills) ## Related Topics - [Python SDK](/docs/python-sdk) -- Full Python SDK documentation - [JavaScript SDK](/docs/javascript-sdk) -- Full JavaScript/TypeScript SDK documentation - [Go SDK](/docs/go-sdk) -- Full Go SDK documentation - [CLI](/docs/cli) -- CLI reference - [MCP Server](/docs/mcp-server) -- PromptRails as an MCP server for IDEs --- # Desktop Monitor Source: https://promptrails.ai/docs/desktop-monitor > Monitor AI agent executions, review approvals, and track costs from a lightweight desktop app that lives in your system tray. # Desktop Monitor PromptRails Monitor is a desktop app for monitoring your AI agent executions in real time. It lives in your system tray and gives you instant visibility into execution status, costs, traces, and pending approvals — without opening a browser tab. ## Features - **Live Execution Feed** — Real-time polling of agent executions with status, duration, and cost - **Trace Viewer** — Collapsible trace tree with span details, input/output, and token usage - **Approval Management** — View, approve, or reject pending human-in-the-loop approvals - **Native Notifications** — Get notified on new approvals and execution failures - **System Tray** — Quick overview panel on left-click, context menu on right-click - **Stats Dashboard** — Execution counts, success rates, costs, and top agents with 1D/7D/30D period tabs - **Infinite Scroll** — Load more executions and approvals as you scroll ## Screenshots ### Tray Panel Left-click on the tray icon to see a quick overview of your workspace — execution stats, success rate, cost, pending approvals, and top agents. Toggle between 1D, 7D, and 30D views. Tray Panel ### Execution Feed Browse all agent executions with status badges, duration, cost, and timestamps. Filter by status and scroll to load more. Execution Feed ### Stats Dashboard View execution counts, success rates, total cost, and average duration. See executions-by-day charts and top agents breakdown. Switch between 1D, 7D, and 30D periods. Stats Dashboard ### Approvals Review pending human-in-the-loop approvals. See checkpoint names, payload data, and approve or reject with an optional reason. Approvals ### Settings Configure polling interval (1–10 minutes), toggle notifications for approvals and failures, and disconnect to switch API keys. Settings ## Installation ### Homebrew (macOS) ```bash brew install --cask promptrails/tap/promptrails-monitor ``` ### Direct Download Download the latest release for your platform: | Platform | Format | | --------------------- | -------------------- | | macOS (Apple Silicon) | `.dmg` | | macOS (Intel) | `.dmg` | | Windows | `.msi` / `.exe` | | Linux | `.AppImage` / `.deb` | [Download from GitHub Releases →](https://github.com/promptrails/desktop/releases) ### Build from Source ```bash # Prerequisites: Node.js 18+, Rust 1.77+, pnpm 10+ git clone https://github.com/promptrails/desktop.git cd desktop pnpm install pnpm tauri build ``` ## Setup 1. Launch PromptRails Monitor 2. Enter your API key (`pr_...`) 3. Click **Connect** The API key is stored securely via the OS keychain. By default, the app connects to `https://api.promptrails.ai`. For self-hosted instances, click **Show advanced options** and enter your API URL. You can create an API key from the PromptRails dashboard under **Settings → API Keys**. See [API Keys and Scopes](/docs/api-keys-and-scopes) for details. ## Usage ### System Tray The app lives in your system tray: - **Left-click** — Opens a quick overview panel with stats, pending approvals, and top agents - **Right-click** — Context menu with "Open Monitor" and "Quit" ### Notifications The app sends native OS notifications for: - **New pending approvals** — When a human-in-the-loop checkpoint is triggered - **Execution failures** — When an agent execution fails Both can be toggled on/off in Settings. ### Polling The app polls the API at a configurable interval (default: 1 minute). Available options: 1 min, 2 min, 5 min, 10 min. Adjust in Settings. ### Disconnect To switch API keys or instances, go to **Settings → Disconnect**. This clears stored credentials and returns to the setup screen. ## Tech Stack Built with [Tauri v2](https://v2.tauri.app/) for a lightweight native shell (~10MB), React 18 + Vite for the frontend, and [@promptrails/sdk](https://www.npmjs.com/package/@promptrails/sdk) for API communication. --- # API Reference Source: https://promptrails.ai/docs/rest-api-reference > Interactive API reference for PromptRails with request/response examples, authentication details, and endpoint documentation. # API Reference PromptRails provides a comprehensive REST API for managing agents, prompts, executions, and all platform resources. ## Interactive Documentation Our API documentation is powered by Scalar and includes the full OpenAPI specification with request/response examples, authentication flows, and live testing capabilities. ## Base URL The API base URL depends on your deployment: - **Cloud**: `https://api.promptrails.ai` All API endpoints are prefixed with `/api/v1/`. ## Authentication ### API Key Authentication Include your API key in the `X-API-Key` header: ```bash curl -H "X-API-Key: pr_live_abc123..." \ https://api.promptrails.ai/api/v1/agents ``` ### JWT Authentication For user-based authentication (dashboard, frontend), include the JWT token in the `Authorization` header: ```bash curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \ https://api.promptrails.ai/api/v1/agents ``` ### Workspace Header Most endpoints require a workspace context. Include the `X-Workspace-ID` header: ```bash curl -H "X-API-Key: pr_live_abc123..." \ -H "X-Workspace-ID: 2NxAbc123def456ghi789jkl" \ https://api.promptrails.ai/api/v1/agents ``` When using an API key, the workspace is inferred from the key's workspace if not explicitly provided. ## Request Format All request bodies must be JSON with `Content-Type: application/json`: ```bash curl -X POST https://api.promptrails.ai/api/v1/agents \ -H "X-API-Key: pr_live_abc123..." \ -H "Content-Type: application/json" \ -d '{ "name": "My Agent", "type": "simple", "description": "A simple agent" }' ``` ## Response Format All responses use a standard JSON envelope: ### Success Response ```json { "data": { "id": "2NxAbc123def456ghi789jkl", "name": "My Agent", "type": "simple", "status": "active", "created_at": "2024-01-15T10:30:00Z" }, "message": "Agent created successfully" } ``` ### List Response ```json { "data": [ { "id": "...", "name": "Agent 1" }, { "id": "...", "name": "Agent 2" } ], "message": "", "pagination": { "page": 1, "limit": 20, "total": 42, "total_pages": 3 } } ``` ### Error Response ```json { "data": null, "error": "Agent not found", "message": "The requested agent does not exist" } ``` ## Streaming (Server-Sent Events) Two endpoints stream agent execution events over SSE. Set `Accept: text/event-stream` on the request; the server emits frames in the canonical `event: \ndata: \n\n` format. | Endpoint | Method | Purpose | | --------------------------------------------------- | ------ | ------------------------------------------------------------------ | | `/api/v1/chat/sessions/{sessionId}/messages/stream` | POST | Post a chat message and stream the run in one request. | | `/api/v1/executions/{executionId}/stream` | GET | Subscribe to an execution started elsewhere (polling replacement). | ### Event types | Event | Payload | Emitted when | | ------------ | ----------------------------------- | ---------------------------------------------------- | | `execution` | `{ execution_id, user_message_id }` | First frame of a chat stream. Correlate with traces. | | `thinking` | `{ content }` | Intermediate reasoning between tool rounds. | | `tool_start` | `{ id, name }` | A tool is about to execute. | | `tool_end` | `{ id, name, summary }` | A tool finished. `summary` is short display text. | | `content` | `{ content }` | Delta of the final assistant response. | | `done` | `{ output, token_usage, time }` | Terminal. Full output and token accounting. | | `error` | `{ message }` | Terminal. Surfaces a server-side error. | Each of the three official SDKs exposes typed wrappers — see the [JavaScript](/docs/javascript-sdk#stream-a-chat-turn), [Python](/docs/python-sdk#stream-a-chat-turn), and [Go](/docs/go-sdk#stream-a-chat-turn) guides. Unknown event names are safe to ignore so older clients keep working as new frames are added. ## Pagination List endpoints support pagination via query parameters: | Parameter | Default | Description | | --------- | ------- | --------------------------------------- | | `page` | 1 | Page number (1-based) | | `limit` | 20 | Items per page (max varies by endpoint) | ```bash GET /api/v1/agents?page=2&limit=10 ``` ## Error Codes | HTTP Status | Description | | ----------- | ----------------------------------------------------- | | `400` | Bad Request -- Invalid parameters or request body | | `401` | Unauthorized -- Missing or invalid authentication | | `402` | Payment Required -- Plan limit exceeded | | `403` | Forbidden -- Insufficient permissions | | `404` | Not Found -- Resource does not exist | | `409` | Conflict -- Resource already exists or state conflict | | `422` | Unprocessable Entity -- Validation error | | `429` | Too Many Requests -- Rate limit exceeded | | `500` | Internal Server Error -- Server-side error | ## Related Topics - [API Keys & Scopes](/docs/api-keys-and-scopes) -- Authentication setup - [Python SDK](/docs/python-sdk) -- Python client library - [JavaScript SDK](/docs/javascript-sdk) -- JavaScript client library --- # Workspace Management Source: https://promptrails.ai/docs/workspace-management > Create and manage workspaces to organize your agents, prompts, credentials, and team members. # Workspace Management Workspaces are the top-level organizational unit in PromptRails. Every resource -- agents, prompts, credentials, executions, traces, and team members -- belongs to a workspace. Users can create multiple workspaces and switch between them. ## Creating Workspaces Create a workspace through the PromptRails dashboard: 1. Open the workspace switcher. 2. Select **Create Workspace**. 3. Enter the workspace name and slug. 4. Confirm creation. When a user creates a workspace, they automatically become the **owner** of that workspace. ## Workspace Slug Each workspace has a unique slug: - Must be lowercase alphanumeric with hyphens - Must be unique across the platform Example slug: ```text my-company-staging ``` ## Workspace Settings Update workspace settings from the dashboard's workspace settings screen, including the display name and slug. ## Workspace Scope All resources in PromptRails are workspace-scoped: | Resource | Workspace-Scoped | | -------------------- | ---------------- | | Agents | Yes | | Prompts | Yes | | Credentials | Yes | | Data Sources | Yes | | MCP Tools | Yes | | Executions | Yes | | Traces | Yes | | Chat Sessions | Yes | | Memories | Yes | | Scores | Yes | | Guardrails | Yes (via agent) | | API Keys | Yes | | Webhook Triggers | Yes | | Approvals | Yes | | Agent UI Deployments | Yes | This means resources in one workspace are completely isolated from another workspace. A credential in workspace A cannot be used by an agent in workspace B. ## Plans and Limits Each workspace is associated with a billing plan that defines resource limits: - Maximum number of monthly executions - Maximum number of active agents - Maximum number of team members - Maximum number of data sources - Feature flags (memory, approvals, MCP, etc.) See [Billing and Plans](/docs/billing-and-plans) for details. ## Related Topics - [Team and Roles](/docs/team-and-roles) -- Managing workspace members - [Billing and Plans](/docs/billing-and-plans) -- Workspace billing configuration - [API Keys and Scopes](/docs/api-keys-and-scopes) -- Workspace-scoped API keys --- # Team and Roles Source: https://promptrails.ai/docs/team-and-roles > Manage workspace team members with role-based access control including Owner, Admin, and User roles. # Team and Roles PromptRails provides role-based access control (RBAC) for workspace team management. Each workspace member is assigned a role that determines their permissions. ## Role Hierarchy PromptRails defines three workspace roles with a clear hierarchy: ``` Owner > Admin > User ``` ### Owner The workspace owner has full control over all resources and settings. There is exactly one owner per workspace (the user who created it). | Permission | Allowed | | -------------------------------------------- | ------- | | Manage all resources (agents, prompts, etc.) | Yes | | Manage credentials | Yes | | Manage API keys | Yes | | Manage team members | Yes | | Change member roles | Yes | | Transfer ownership | Yes | | Delete the workspace | Yes | | Manage billing and plans | Yes | ### Admin Admins have broad permissions but cannot perform destructive workspace-level operations. | Permission | Allowed | | -------------------------------------------- | ------- | | Manage all resources (agents, prompts, etc.) | Yes | | Manage credentials | Yes | | Manage API keys | Yes | | Manage team members | Yes | | Change member roles (below their level) | Yes | | Transfer ownership | No | | Delete the workspace | No | | Manage billing and plans | Yes | ### User Users can work with resources but have limited administrative access. | Permission | Allowed | | ------------------------------------- | ------- | | View and execute agents | Yes | | View and execute prompts | Yes | | View executions and traces | Yes | | Create and manage their own resources | Yes | | Manage credentials | No | | Manage API keys | No | | Manage team members | No | | Manage billing | No | ## Adding Members Invite new members from the workspace settings in the PromptRails dashboard. Owners and admins can enter the user's email address and assign a role during the invitation flow. The invited user receives an email with an invitation link. Once accepted, they are added to the workspace with the specified role. ## Invitation Flow 1. **Owner/Admin sends invitation** -- Specifies email and role 2. **Invitation email sent** -- Contains a unique invitation link 3. **User accepts** -- Clicks the link and creates an account (if new) or logs in 4. **Member added** -- User is added to the workspace with the assigned role ### Invitation Statuses | Status | Description | | ---------- | ------------------------------------------ | | `pending` | Invitation sent, awaiting acceptance | | `accepted` | User accepted the invitation | | `revoked` | Invitation was cancelled before acceptance | ## Removing Members Remove members from the workspace settings screen in the dashboard. Removing a member revokes their access immediately. Their previously created resources remain in the workspace. ## Changing Roles Change member roles from the same team management screen in the dashboard. Role changes take effect immediately for all subsequent requests. ## API Key Auth vs User Auth PromptRails supports two authentication methods: ### User Authentication (JWT) - Used by the dashboard (frontend) - Authenticated via email/password login - Permissions based on workspace role - Session-based with access + refresh tokens ### API Key Authentication - Used by SDKs, CLI, and integrations - Authenticated via `X-API-Key` header - Permissions based on API key scopes (not user roles) - Workspace-scoped (each key belongs to one workspace) API keys provide more granular control than roles. A user with the "owner" role might create an API key with only `agents:read` scope for a specific integration. ## System Roles In addition to workspace roles, PromptRails has system-level roles: | Role | Description | | ------- | --------------------------------------------- | | `admin` | Platform administrator (access to backoffice) | | `user` | Regular platform user | System roles are separate from workspace roles. A user can be a system `user` but a workspace `owner`. ## Plan Limits Team member counts are subject to plan limits: | Plan | Max Team Members | | ---------- | ---------------- | | Free | 1 | | Starter | 3 | | Pro | 10 | | Enterprise | Unlimited | Attempting to add members beyond the plan limit returns a `402 Payment Required` error. ## Related Topics - [Workspace Management](/docs/workspace-management) -- Workspace creation and settings - [API Keys and Scopes](/docs/api-keys-and-scopes) -- API key permissions - [Security](/docs/security) -- Authentication and authorization - [Billing and Plans](/docs/billing-and-plans) -- Team member limits --- # Billing and Plans Source: https://promptrails.ai/docs/billing-and-plans > Understand PromptRails billing plans, execution limits, feature flags, execution packs, and Stripe-powered subscription management. # Billing and Plans PromptRails offers tiered billing plans that control resource limits and feature availability per workspace. Billing is managed through Stripe integration with support for subscriptions, execution packs, and invoices. ## Plan Tiers ### Free -- $0/forever The free tier is designed for experimentation and development. | Limit | Value | | ------------------ | ---------- | | Monthly Executions | 500 | | Team Members | 1 | | Active Agents | 3 | | Data Sources | 1 (static) | | Notifications | No | | **Features** | | | Basic analytics | Yes | | MCP Tools | No | | Memory | No | | Approvals | No | | Guardrails | No | | Webhooks | No | | Analytics Export | No | ### Starter -- $49/mo For small teams getting started with AI agents. | Limit | Value | | --------------------- | ----------- | | Monthly Executions | 10,000 | | Team Members | 5 | | Active Agents | 15 | | Data Sources | 5 | | Notification Channels | 2 (Webhook) | | Analytics History | 30 days | | **Features** | | | API Access | Yes | | MCP Tools | Yes | | Memory | Yes | | Approvals | No | | Guardrails | Yes | | Webhooks | Yes | | Analytics Export | No | ### Pro -- $199/mo For growing teams with production workloads. | Limit | Value | | --------------------- | -------------------- | | Monthly Executions | 100,000 | | Team Members | 20 | | Active Agents | 50 | | Data Sources | 25 | | Notification Channels | 10 (Webhook + Slack) | | Analytics History | 90 days | | **Features** | | | MCP Access | Yes | | All Memory Types | Yes | | LLM Judge Evaluations | Yes | | Approvals | Yes | | Guardrails | Yes | | Webhooks | Yes | | Analytics Export | Yes | | SSO | No | | Audit Log | Yes | ### Enterprise -- $699/mo For organizations that need unlimited access and dedicated support. | Limit | Value | | --------------------- | --------- | | Monthly Executions | Unlimited | | Team Members | Unlimited | | Active Agents | Unlimited | | Data Sources | Unlimited | | Notification Channels | Unlimited | | Analytics History | 1 year | | **Features** | | | All features | Yes | | SSO & SAML | Yes | | Custom Guardrails | Yes | | Custom SLAs | Yes | | Dedicated Support | Yes | ## Plan Limits Plans enforce limits on the following resources: | Resource | Description | | ----------------------- | ------------------------------------------ | | `monthly_executions` | Maximum agent executions per billing month | | `team_members` | Maximum workspace team members | | `active_agents` | Maximum active (non-archived) agents | | `data_sources` | Maximum data sources | | `notification_channels` | Maximum notification channels | | `score_configs` | Maximum score configuration templates | | `trace_retention_days` | How long traces are retained | | `api_rate_limit` | API requests per minute | When a limit is reached, the API returns a `402 Payment Required` error with a descriptive message. ## Feature Flags Plans also control access to platform features: | Feature | Description | | ----------------------- | ------------------------------- | | `notifications_enabled` | Email and push notifications | | `slack_enabled` | Slack integration | | `webhook_enabled` | Webhook triggers | | `memory_enabled` | Agent memory system | | `approvals_enabled` | Human-in-the-loop approvals | | `audit_log_enabled` | Audit logging | | `mcp_enabled` | MCP tools | | `analytics_export` | Export analytics data | | `sso_enabled` | Single sign-on | | `custom_guardrails` | Custom guardrail configurations | ## Execution Packs If you need more executions without upgrading your plan, you can purchase execution packs: - Execution packs add a fixed number of executions to your monthly quota - Packs are one-time purchases (not recurring) - Unused pack executions expire at the end of the billing period ``` Plan limit: 5,000 executions/month + Execution pack: 10,000 executions = Total available: 15,000 executions this month ``` ## Stripe Integration PromptRails uses Stripe for payment processing: - **Subscriptions** -- Monthly or annual recurring billing - **Execution packs** -- One-time purchases - **Invoices** -- Automatically generated and available in the dashboard - **Webhooks** -- Stripe events are processed for subscription lifecycle management ### Subscription Lifecycle ``` Create -> Active -> (renewal) -> Active -> (cancel) -> Canceled at period end -> (payment failed) -> Past due -> (retry) -> Active ``` ## Invoices View billing history and invoices: ``` Dashboard > Settings > Billing > Invoices ``` Each invoice includes: - Plan charges - Execution pack purchases - Payment status - Download link (PDF) ## Custom Plans Enterprise customers can have custom plans with: - Custom execution limits - Custom feature configurations - Custom pricing - Workspace-specific plan assignment Contact our sales team for custom plan configuration. ## Related Topics - [Workspace Management](/docs/workspace-management) -- Workspace-level billing - [Team and Roles](/docs/team-and-roles) -- Team member limits - [Cost Tracking](/docs/cost-tracking) -- LLM cost monitoring (separate from platform billing) --- # Security Source: https://promptrails.ai/docs/security > Security practices in PromptRails including encryption, authentication, API key security, and access control. # Security PromptRails is designed with security as a core concern. This page covers the encryption, authentication, authorization, and operational security measures built into the platform. ## Encryption ### At Rest - **Credentials** are encrypted before storage and never exposed in API responses. - **Passwords** are securely hashed to prevent brute-force attacks. - **Webhook trigger tokens** are encrypted before storage. - **PIN codes** for Agent UI deployments are hashed. ### In Transit - All API communication is encrypted via TLS. - WebSocket connections use secure WebSocket (WSS). ## Authentication ### User Authentication User authentication uses short-lived access tokens and refresh tokens. Multi-factor authentication (TOTP) is supported and can be enforced at the workspace level. ### API Key Authentication API keys provide programmatic access: - Keys are cryptographically generated - Only a hash is stored — the raw key is shown once at creation time - Keys are validated on every request ## API Key Security ### Scopes API keys support fine-grained scopes that follow the principle of least privilege. Always grant the minimum scopes needed for each integration. See [API Keys & Scopes](/docs/api-keys-and-scopes) for the full list. ### IP Restrictions API keys can be restricted to specific IP addresses or CIDR ranges from the PromptRails dashboard when you create or edit a key. Requests from non-allowed IPs are rejected with `403 Forbidden`. ### CORS Origin Restrictions For browser-based applications, API keys can restrict which origins are allowed by configuring an origin allowlist in the dashboard. ### Key Expiration Set expiration dates on API keys to enforce rotation: ## Rate Limiting PromptRails applies rate limiting to protect against abuse. Limits vary by endpoint and plan. ## Authorization ### Workspace Isolation All resources are workspace-scoped. Users can only access resources within workspaces they are members of. There is no cross-workspace data access. ### Role-Based Access Control Three workspace roles control user permissions: | Role | Level | | ----- | ------------------------------------------ | | Owner | Full control, including workspace deletion | | Admin | Resource and team management | | User | Resource usage with limited management | ### Credential Masking Credential values are never returned in API responses. Only a masked version is shown: ``` sk-proj-abc...xyz9 ``` The full value is only available at creation time and is encrypted immediately. ## Data Retention Deleted resources are retained for recovery and audit purposes. Historical references remain valid, and audit trails are preserved. ## Best Practices - Use API keys with the minimum required scopes - Set IP restrictions on production API keys - Enable MFA for all team members - Set key expiration dates and rotate regularly - Use CORS restrictions for browser-based integrations ## Reporting Vulnerabilities If you discover a security vulnerability, please report it to [security@promptrails.ai](mailto:security@promptrails.ai). ## Related Topics - [API Keys and Scopes](/docs/api-keys-and-scopes) -- Detailed API key management - [Credentials](/docs/credentials) -- Credential management - [Team and Roles](/docs/team-and-roles) -- Access control ---