Skip to main content
🔑
Get your Incredible API key
Generate your API key to start using this endpoint

Overview

The Agent API enables autonomous AI systems that can decide when and how to use tools (functions) to accomplish complex tasks. Unlike simple conversational endpoints, agents can break down multi-step problems, call appropriate tools, and use the results to provide comprehensive answers. What makes agents special:
  • Tool awareness - Agents understand what tools are available and when to use them
  • Multi-step reasoning - Can plan and execute complex workflows
  • Autonomous decision-making - Decides which tools to call and in what order
  • Result integration - Uses tool outputs to inform subsequent actions and final responses
Real-world use cases:
  • Data lookup and retrieval - Query databases, search APIs, fetch external data
  • Calculations and analysis - Perform computations, analyze data, generate reports
  • External integrations - Interact with third-party services, send notifications, create records
  • Workflow automation - Orchestrate multi-step business processes
  • Dynamic content generation - Fetch real-time data to generate accurate, current responses

Using Agent

The Agent endpoint enables autonomous tool calling through a simple request-response pattern:
  1. Initial Request - You send messages and define available tools
  2. Agent Planning - The model analyzes the request and decides which tools to call
  3. Tool Call Response - The API returns tool calls with arguments (doesn’t execute them)
  4. Your Execution - Your application executes the tool calls in your environment
  5. Follow-up Request - You send the tool results back to the agent
  6. Final Response - The agent uses tool results to generate the final answer
This gives you complete control over tool execution, security, and side effects. The agent plans what to do, but you control what actually happens. Tools are defined using JSON Schema with three key components: name (clear identifier), description (what it does and when to use it), and input_schema (parameter definitions). The quality of your tool descriptions directly impacts how well the agent uses them.

Examples

from incredible_python import Incredible

client = Incredible(api_key="YOUR_API_KEY")

tools = [
    {
        "name": "calculator",
        "description": "Perform basic arithmetic calculations",
        "input_schema": {
            "type": "object",
            "properties": {
                "expression": {"type": "string", "description": "Math expression to evaluate"}
            },
            "required": ["expression"]
        }
    }
]

response = client.agent(
    system_prompt="You are a helpful assistant that uses tools to answer questions accurately.",
    messages=[{"role": "user", "content": "What is 25 * 4?"}],
    tools=tools
)

# Check for tool calls
if response.tool_calls:
    for call in response.tool_calls:
        print(f"Tool: {call.name}, Inputs: {call.inputs}")
else:
    print(response.response)
What are messages? The conversation history as an array of message objects. Each message has a role (“user” or “assistant”) and content. The agent uses this context to understand the task and previous interactions. For multi-turn workflows, include previous tool call results in the message history so the agent can build on prior actions. What are tools? An array of tool definitions the agent can choose to call. Each tool needs three things:
  • name - Clear identifier (e.g., "get_weather", "search_database") using snake_case
  • description - Natural language explanation of what the tool does, its capabilities, limitations, and when to use it. Be specific—this is critical for the agent’s decision-making
  • input_schema - JSON Schema defining the tool’s parameters with type, properties, and required fields
Example tool definition:
{
  "name": "search_products",
  "description": "Search the product catalog by name, category, or keyword. Returns up to 10 matching products with prices and availability.",
  "input_schema": {
    "type": "object",
    "properties": {
      "query": {
        "type": "string",
        "description": "The search term or keyword"
      },
      "category": {
        "type": "string",
        "enum": ["electronics", "clothing", "home"],
        "description": "Optional category filter"
      }
    },
    "required": ["query"]
  }
}
Optional: System Prompts - Use the system_prompt parameter to define the agent’s behavior, personality, and constraints. The system prompt is passed as a separate parameter, not as part of the messages array. For example: system_prompt="You are a helpful assistant with access to tools. Always verify information with the search tool before answering. Be concise and cite your sources." Optional: Streaming - Set stream: true to watch the agent’s thinking process, tool calls, and responses in real-time. See the Streaming section below for details.

Working with Files in Agent Workflows

Agents can access file content when making tool calling decisions:
from incredible_python import Incredible

client = Incredible(api_key="YOUR_API_KEY")

# Upload a file
with open("data.csv", "rb") as f:
    file = client.files.upload(file=f)

# Agent can use file context with tools
tools = [
    {
        "name": "analyze_data",
        "description": "Analyze data from the provided file",
        "input_schema": {
            "type": "object",
            "properties": {
                "column": {"type": "string", "description": "Column to analyze"}
            },
            "required": ["column"]
        }
    }
]

response = client.agent(
    system_prompt="You are a data analyst assistant. Use the available tools to analyze data when needed.",
    messages=[
        {"role": "user", "content": "Analyze the sales data", "file_ids": [file.file_id]}
    ],
    tools=tools
)

if response.tool_calls:
    for call in response.tool_calls:
        print(f"Tool: {call.name}, Inputs: {call.inputs}")

Streaming Agent Responses

Agent streaming is particularly powerful because it provides visibility into the agent’s decision-making process. You can watch in real-time as the agent:
  • Reasons through the problem (thinking events)
  • Decides which tools to call (tool_call events)
  • Generates its final response (content events)
This transparency is valuable for:
  • Debugging - See exactly how the agent interprets tasks and why it chooses certain tools
  • User Experience - Show users what’s happening during complex multi-step workflows
  • Early Intervention - Detect and handle issues before the agent completes its full response
  • Progress Indication - Provide real-time feedback for long-running agent tasks
Enable streaming by setting stream: true:
from incredible_python import Incredible

client = Incredible(api_key="YOUR_API_KEY")

tools = [
    {
        "name": "calculator",
        "description": "Perform arithmetic calculations",
        "input_schema": {
            "type": "object",
            "properties": {
                "expression": {"type": "string", "description": "Math expression to evaluate"}
            },
            "required": ["expression"]
        }
    }
]

# Stream agent response
stream = client.agent(
    system_prompt="You are a helpful calculator assistant.",
    messages=[{"role": "user", "content": "What is 157 * 23?"}],
    tools=tools,
    stream=True
)

# Process streaming events (returns dict-like objects)
for event in stream:
    if event.get("thinking"):
        print(f"[Thinking: {event['thinking']}]")
    if event.get("tool_call"):
        tc = event["tool_call"]
        print(f"[Tool call: {tc['name']}({tc['inputs']})]")
    if event.get("content"):
        print(event["content"], end="", flush=True)
    if event.get("done"):
        print("\n[Stream complete]")
Stream Event Types:
  • thinking - Agent’s reasoning process in real-time
  • tool_call - Tool call requests as they’re decided
  • content - Text response chunks as they’re generated
  • done - Signals completion of the stream
  • error - Any errors that occurred during generation
Benefits of Agent Streaming:
  • See the agent’s decision-making process live
  • Detect tool calls immediately without waiting
  • Provide real-time feedback to users
  • Handle long-running agent workflows efficiently

Response

{
  "success": true,
  "response": "I'll check the weather in San Francisco for you.",
  "tool_calls": [
    {
      "id": "call_123",
      "name": "get_weather",
      "inputs": {
        "location": "San Francisco"
      }
    }
  ]
}

Tool Execution Pattern

Implementing agentic workflows requires a specific pattern for handling tool calls. Here’s the complete flow with implementation guidance:

Step 1: Initial Request

Send your user’s message along with tool definitions:
response = client.agent(
    system_prompt="You are a helpful assistant with access to weather and time tools.",
    messages=[
        {"role": "user", "content": "What's the weather in Tokyo and what time is it there?"}
    ],
    tools=[weather_tool, time_tool]
)

Step 2: Check for Tool Calls

The agent analyzes the request and decides if tools are needed:
if response.tool_calls:
    # Agent wants to use tools
    print(f"Agent needs {len(response.tool_calls)} tools")
    for call in response.tool_calls:
        print(f"- {call.name} with args: {call.inputs}")
else:
    # Agent has sufficient information to respond
    print(response.response)
    return

Step 3: Execute Tools

Your application executes the requested tools in your environment. This is where you maintain security, rate limiting, and control:
tool_results = []
for call in response.tool_calls:
    if call.name == "get_weather":
        result = get_weather(call.inputs["location"])
    elif call.name == "get_time":
        result = get_time(call.inputs["timezone"])
    
    tool_results.append({
        "tool_call_id": call.id,
        "result": result
    })

Step 4: Send Results Back

Add the tool results to the conversation and make a follow-up request:
# Add assistant's response to conversation
if response.response:
    messages.append({"role": "assistant", "content": response.response})

# Add tool results as a user message
result_summary = "\n".join([
    f"Tool '{r['tool_call_id']}' result: {r['result']}" 
    for r in tool_results
])
messages.append({"role": "user", "content": result_summary})

# Get final response with tool results
final_response = client.agent(
    system_prompt="You are a helpful assistant with access to weather and time tools.",
    messages=messages,
    tools=[weather_tool, time_tool]
)

Step 5: Final Response

The agent processes the tool results and generates a comprehensive answer:
print(final_response.response)
# "It's currently 15°C and partly cloudy in Tokyo. The local time is 3:45 PM JST."

Complete Example: Interactive Calculator Agent

Here’s a complete, runnable example that demonstrates the full agent loop with tool calling:
from incredible_python import Incredible
import math

client = Incredible(api_key="YOUR_API_KEY")

# Define the calculator tool
calculator_tool = {
    "name": "calculate",
    "description": "Perform math operations: add, subtract, multiply, divide, sqrt, power",
    "input_schema": {
        "type": "object",
        "properties": {
            "operation": {
                "type": "string",
                "enum": ["add", "subtract", "multiply", "divide", "sqrt", "power"],
                "description": "The math operation to perform"
            },
            "a": {"type": "number", "description": "First number"},
            "b": {"type": "number", "description": "Second number (not needed for sqrt)"}
        },
        "required": ["operation", "a"]
    }
}

def execute_calculate(inputs: dict) -> str:
    """Execute the calculator tool."""
    op = inputs["operation"]
    a = inputs["a"]
    b = inputs.get("b")
    
    if op == "add": return str(a + b)
    elif op == "subtract": return str(a - b)
    elif op == "multiply": return str(a * b)
    elif op == "divide": return str(a / b) if b != 0 else "Error: division by zero"
    elif op == "sqrt": return str(math.sqrt(a)) if a >= 0 else "Error: negative number"
    elif op == "power": return str(a ** b)
    return "Unknown operation"

SYSTEM_PROMPT = "You are a helpful calculator assistant. Use the calculate tool for all math operations."

def run_agent(user_message: str, messages: list) -> str:
    """Run one turn of the agent, handling tool calls."""
    messages.append({"role": "user", "content": user_message})
    
    response = client.agent(system_prompt=SYSTEM_PROMPT, messages=messages, tools=[calculator_tool])
    
    # Handle tool calls if any
    if response.tool_calls:
        for call in response.tool_calls:
            print(f"🔧 Calling: {call.name}({call.inputs})")
            result = execute_calculate(call.inputs)
            print(f"   Result: {result}")
        
        # Add assistant response and tool results to conversation
        if response.response:
            messages.append({"role": "assistant", "content": response.response})
        messages.append({"role": "user", "content": f"Tool result: {result}"})
        
        # Get final response
        final = client.agent(system_prompt=SYSTEM_PROMPT, messages=messages, tools=[calculator_tool])
        messages.append({"role": "assistant", "content": final.response})
        return final.response
    
    messages.append({"role": "assistant", "content": response.response})
    return response.response

# Interactive loop
messages = []
print("Calculator Agent - type 'quit' to exit\n")

while True:
    user_input = input("You: ").strip()
    if user_input.lower() == "quit":
        break
    
    reply = run_agent(user_input, messages)
    print(f"Agent: {reply}\n")
Example session:
You: What is 125 * 48?
🔧 Calling: calculate({'operation': 'multiply', 'a': 125, 'b': 48})
   Result: 6000
Agent: 125 × 48 = 6,000

You: Now divide that by 4
🔧 Calling: calculate({'operation': 'divide', 'a': 6000, 'b': 4})
   Result: 1500.0
Agent: 6,000 ÷ 4 = 1,500

Best Practices

Tool Design:
  • Keep tools focused - each tool should do one thing well
  • Write clear, detailed descriptions - they’re critical for agent decision-making
  • Include examples in descriptions when behavior might be ambiguous
  • Validate inputs before execution - don’t trust the agent’s arguments blindly
Error Handling:
  • Always handle tool execution failures gracefully
  • Return error messages to the agent so it can adapt
  • Implement timeouts for long-running tools
  • Consider fallback strategies when tools fail
Security:
  • Never expose dangerous operations directly as tools
  • Implement authorization checks before executing tools
  • Sanitize tool inputs to prevent injection attacks
  • Rate limit tool executions to prevent abuse
  • Log tool calls for audit trails
Performance:
  • Execute independent tool calls in parallel when possible
  • Cache tool results for repeated queries
  • Set reasonable timeout limits
  • Consider async execution for slow tools
User Experience:
  • Use streaming to show progress during multi-step workflows
  • Provide clear feedback when tools are being executed
  • Allow users to cancel long-running agent tasks
  • Display tool call details for transparency