What is an Agent?
An Agent wraps an LLM with a system prompt, temperature, a set of tools, and optional knowledge bases. When you send a message, the agent enters a ReAct (Reason + Act) loop: the LLM decides whether it needs to call a tool, executes the tool if needed, observes the result, and either calls another tool or generates a final response. This loop continues for up to 25 steps (configurable per run). On the final step, tools are withheld so the LLM is forced to produce a text response.The ReAct Loop
Context Management
The agent automatically manages its context window. Before each LLM call, it estimates the token count and, if nearing the model’s context limit, triggers proactive compaction: first pruning old tool results (replacing them with placeholders while keeping the last 3 user turns), then if still over the limit, summarizing the older conversation using a lightweight LLM (gpt-4.1-nano). If the LLM returns a prompt_too_long error, the agent retries with compaction. If the LLM output is truncated, the agent injects a “continue where you left off” message and retries up to 3 times.Tool Types
Agents can use three categories of tools: builtin tools provided by the platform, custom tools that call your HTTP endpoints, and MCP server tools discovered at runtime.Builtin Tools
The platform provides eight builtin tools. Assign them to an agent by name via POST /api/agents/{id}/tools. The database tools include schema-level access control: when assigning them, you configure which schemas and tables the agent can access.| Tool | Description | Constraints |
|---|---|---|
| database_query | Execute read-only SQL SELECT queries against the project database | Must start with SELECT. Multi-statement blocked (no semicolons). Results capped at 50,000 chars. Rollback after read. |
| database_write | Execute INSERT, UPDATE, and DELETE operations | UPDATE requires a WHERE clause (no mass updates). DELETE requires a WHERE clause (no mass deletes). All identifiers validated against injection. |
| http_request | Make HTTP requests to external APIs | Response capped at 10,000 chars. 30-second timeout. No SSRF validation — see warning below. |
| code_execute | Run Python or JavaScript in a sandboxed environment | Delegated to external sandbox service. Default 30-second timeout, configurable per call. |
| storage_read | List and download files from project storage buckets | Binary files return a signed URL instead of content. Supports list (with prefix/limit/offset) and download operations. |
| storage_write | Upload text content to project storage buckets | UTF-8 text content only. Returns path and file size. |
| web_search | Search the web using Exa.ai. Five search_type modes (auto, neural, keyword, plus the agentic deep and deep-reasoning tiers), domain filters, date ranges, category filter, and content depth control | Results capped at 20K-50K chars by content mode. 1-10 results. Requires EXA_API_KEY. deep / deep-reasoning are slower and bill at higher tiers — see below. |
| web_scrape | Extract content from web pages as clean markdown, with optional AI vision image analysis | Results capped at 200K chars. Supports markdown/HTML/links formats. include_images uses gpt-4.1-mini vision. Direct image URLs bypass Firecrawl. Requires FIRECRAWL_API_KEY. |
Web search modes (search_type)
The web_search tool accepts a search_type argument that selects how Exa runs the query. The first three are standard single-pass searches; the last two run Exa’s agentic deep search, which iterates over multiple queries and reads more pages for higher-quality results, at the cost of latency and credits.
search_type | What it does | Relative cost |
|---|---|---|
auto (default) | Exa picks neural or keyword per query | Standard |
neural | Semantic / meaning-based search | Standard |
keyword | Exact term matching | Standard |
deep | Agentic deep search — slower, broader, higher quality | Higher |
deep-reasoning | Agentic deep search with an added reasoning pass — slowest and highest quality | Highest |
web_search arguments apply to every mode: num_results (1–10, default 5), include_domains / exclude_domains, start_date / end_date (ISO 8601 published-date bounds), category (company, news, research paper, tweet, github, wikipedia, personal site), and content_mode (highlights default, compact_text, or full_text).
Billing follows the mode. A standard search bills the
web_search action; deep bills web_search_deep and deep-reasoning bills web_search_deep_reasoning, both priced higher than a standard search. The tier is resolved from the actual search_type sent to Exa, including when you pin search_type in an agent’s tool config, so a deep search always bills the deep rate, never the standard one. Exact per-action prices live on the pricing page. If the search fails for a platform-side reason (5xx, 429, timeout, or a missing EXA_API_KEY), the call is not billed; only tenant-fault 4xx errors stay billed.Tool prerequisites
Some builtin tools need an API key or sandbox configured before they’ll work. If the prerequisite is missing, the tool returns a JSON error message to the agent (e.g."Exa API key not configured. Set it in Settings > Tools.") rather than throwing.
| Tool | What it needs | Where to set it |
|---|---|---|
database_query / database_write | — | No setup. Uses the project’s superuser connection automatically. |
http_request | — | No setup. |
code_execute | A code sandbox service (CODE_SANDBOX_URL, optional CODE_SANDBOX_API_KEY) | Platform-level env var — set by the platform team for managed cloud; self-host operators configure their own sandbox. Without it the tool returns "Code sandbox is not configured". |
storage_read / storage_write | — | No setup. Uses the project’s Storage service. |
web_search | EXA_API_KEY setting | Studio → Settings → Tools, or PUT /api/settings/EXA_API_KEY |
web_scrape | FIRECRAWL_API_KEY setting (and optional VISION_MODEL if include_images: true) | Studio → Settings → Tools, or PUT /api/settings/FIRECRAWL_API_KEY. VISION_MODEL defaults to gpt-4.1-mini. |
PUT /api/settings/{key}. See Settings API.
Custom Tools
Custom tools call your own HTTP endpoints. You define the tool with a name, description, JSON Schema for inputs, an endpoint URL, HTTP method, and optional headers. When the agent decides to use the tool, the platform POSTs the tool arguments as JSON to your endpoint and returns the response to the agent. Responses are capped at 10,000 characters. Timeout is 30 seconds. SSRF validation prevents the agent from calling internal network addresses.MCP Servers
MCP (Model Context Protocol) servers let you connect agents to external tool providers. Add an MCP server URL to your agent, and at the start of each run the platform sends atools/list JSON-RPC request to discover available tools. Discovered tools are namespaced (mcp__{server_name}__{tool_name}) and added to the agent’s tool set alongside builtin and custom tools. Tool calls are executed via tools/call JSON-RPC requests. Timeout is 30 seconds for both discovery and per tool call.
Transport: the platform’s MCP client speaks JSON-RPC over HTTP POST to the server URL. (The DB schema accepts a transport field with default http; other values like sse are stored but not consumed by the current client.) Use a server that exposes JSON-RPC over HTTP; most MCP server frameworks do this by default.
Headers: any headers you configure on the server (typically for auth) are sent on both tools/list and tools/call requests. There’s no per-call header injection.
enabled flag: if you set enabled: false on an MCP server, discovery skips it entirely: its tools aren’t added and no tools/call requests fire. Use this to temporarily disconnect a server without removing it.
Failure handling: if tools/list fails (network error, non-200, JSON-RPC error), the agent run continues without that server’s tools (fail-open). The failure is logged but not surfaced as a run error.
Tool annotations: the platform reads annotations.readOnlyHint, destructiveHint, and openWorldHint from each discovered tool and uses them for concurrency / safety planning. A readOnlyHint: true tool may be called in parallel with other read-only tools.
Knowledge Base Search Tool
When you link a knowledge base to an agent, the platform automatically creates a knowledge_search tool. The agent can call this tool with a natural language query to search the KB using whatever retrieval strategy is configured (vector, hybrid, full-text, or tree search). If multiple KBs are linked, a single knowledge_search tool is created with a knowledge_base_names filter parameter so the agent can target specific KBs. The search tool is concurrency-safe and read-only, so it runs in parallel with other safe tools.Sessions & Memory
Every agent conversation happens within a session. A session stores a sequence of runs, each containing the user input, assistant response, tool calls, tool results, and usage statistics. When you pass a session_id with a new message, the platform loads all completed runs from that session and reconstructs the full message history for the LLM. Sessions persist until explicitly deleted, enabling long-running multi-turn conversations. New sessions are created automatically if no session_id is provided; the start SSE event returns the generated session_id for future use.Hooks & Middleware
Hooks let you intercept agent execution at discrete lifecycle boundaries with three types of middleware: HTTP webhooks, rule-based policies, and human approval gates. Each hook is configured with anevent (when it fires), a type (what it does), an optional matcher (which tool to target by name), and a config object.
| Event | When it fires | Can block? | Can modify? |
|---|---|---|---|
OnRunStart | Before the run begins processing | Yes (fails the entire run) | No |
PreToolUse | Before each tool execution | Yes (returns an error to the LLM) | Yes (modified_input replaces the tool arguments) |
OnDelegation | Before a delegate-tool call, in multi-agent setups (fires after PreToolUse, only for delegate tools) | Yes (blocks the delegation) | No |
PostToolUse | After each tool execution | No | Yes (modified_output replaces the tool result) |
PreResponse | After the ReAct loop, before returning the final content | Yes (replaces the response with a blocked message) | Yes (modified_output replaces the final content) |
OnRunComplete | After successful completion (fire-and-forget) | No | No |
| Hook type | Behavior |
|---|---|
http | POSTs the event payload to a webhook URL and applies the JSON response (see contract below). Fail-open on any error (non-200, timeout, or unreachable). Timeout defaults to 5s (config.timeout_seconds); custom config.headers are sent with the request, and the URL is SSRF-validated. |
rule | Evaluates conditions locally against the tool arguments (or, for output events, {"output": ...}). Supports operators CONTAINS, STARTS_WITH, MATCHES (regex), and IN. First matching deny rule wins. |
approval | Pauses execution and emits an approval_requested SSE event. Blocks until the approve endpoint is called or config.timeout (default 300s) expires. |
HTTP hook contract
When anhttp hook fires, Powabase sends a POST to config.url with this body:
tool_name is "" for non-tool events (OnRunStart, PreResponse, OnRunComplete). data carries the event’s input: the tool arguments for tool events, {"message": "<user input>"} for OnRunStart, {} for PreResponse. output is present only when there is one (PostToolUse → the tool result, PreResponse → the assembled content).
Your endpoint must return 200 with a JSON body; any other status (or a timeout/error) is treated as allow (fail-open):
actiondefaults to"allow"; return"deny"to block (only on blockable events; see the table).modified_inputreplaces the tool arguments (PreToolUseonly).modified_outputreplaces the tool result (PostToolUse) or the final content (PreResponse).
Hook record fields
A hook is created withevent and type (both required) and a config object (required, may be {}). Optional: matcher (a tool name; omit to match all tools), enabled (default true), and position (an integer that orders hook execution, default 0). Hooks are immutable once created: to change one, delete it and add a new one. See the Agents API reference for the CRUD endpoints.
The API stores
event and type exactly as sent and does not validate them against the lists above. A hook with an unrecognized event or type is created successfully but never fires, so a typo fails silently. Use the exact values documented here.Human-in-the-Loop Approval
The approval flow is implemented as a PreToolUse hook of type approval. When the agent tries to call a matching tool, execution pauses: the SSE stream emits an approval_requested event with the tool name and arguments, then the thread blocks waiting for a decision. Your application calls POST /api/agents/runs/{run_id}/approve with {approved: true} or {approved: false}. On approval, the tool executes normally and the stream resumes. On rejection, the tool call is skipped and the agent receives a denial message so it can choose an alternative approach. If no decision arrives within 300 seconds (configurable), the tool call is blocked with a timeout error.Streaming
The streaming endpoint (POST /api/agents/{id}/run/stream) returns Server-Sent Events for the entire run lifecycle. When tools are present, the agent runs the full ReAct loop and events are emitted as they occur. When no tools are assigned, the agent streams LLM tokens directly as chunk events. If the client disconnects mid-stream, the platform detects the GeneratorExit, sets the abort signal to stop the agent, and spawns a background thread to persist the partial run.Sync (Non-Streaming) Run
The sync endpoint (POST /api/agents/{id}/run) runs the agent without streaming and returns the full response as JSON. In this mode, no tools are loaded and no ReAct loop runs: the agent makes a single LLM call with the conversation context. This is useful for simple question-answering where tool use isn’t needed.Limits & Safeguards
| Constraint | Default | Notes |
|---|---|---|
| Max ReAct steps | 25 | Configurable per run. On the final step, tools are withheld to force a text response. |
| Doom loop detection | 3 identical calls | If the last 3 tool calls have the same name and arguments, the run fails. |
| Output truncation recovery | 3 retries | If the LLM output is truncated, the agent retries with a continuation prompt. |
| Context compaction failures | 3 attempts | After 3 failed compaction attempts, the agent stops trying to compact. |
| LLM retries | 3 | Automatic retry on transient LLM errors. |
| Custom/MCP tool timeout | 30 seconds | Per-tool execution timeout. |
| Tool result truncation | 50,000 chars | Results beyond this are truncated. KB search and delegation have no limit. |
| Approval timeout | 300 seconds | Configurable via hook config. Blocks tool execution until decision arrives. |
| Max orchestration depth | 3 | Prevents infinite recursive delegation between agents. |
Next Steps
Build an Agent
Create an agent, assign tools, and start chatting.
Advanced Agent Config
Add MCP servers, hooks, and approval flows.
Multi-Agent Orchestration
Coordinate multiple agents for complex tasks.
Agents API Reference
Full endpoint documentation.