Skip to main content

Overview

While other frameworks have separate concepts for tools, state, and schemas, Agentica’s unique model unifies all of these into a single concept: Scope. After all, it’s just code. Agentica agents can operate via REPL and RPC, so they can directly access anything you pass to them. This includes:
  • Functions which replace the need for bespoke “tools”
  • Variables which replace the need for explicit “state” objects
  • Types which replace the need for special “schemas”
This means you may write normal code with normal objects, and the AI can use them directly.

Types Replace Schemas

Instead of defining schemas in a special format, just pass your classes. The agent will instantiate them, and if your validation logic fails, the error is passed back to the agent to fix.
from agentica import magic
from dataclasses import dataclass
from typing import Literal

@dataclass
class PaymentRequest:
    amount: float
    currency: Literal["USD", "EUR", "GBP"]
    customer_email: str

    def __post_init__(self):
        if self.amount <= 0:
            raise ValueError("Amount must be positive")
        if "@" not in self.customer_email:
            raise ValueError("Invalid email address")

@magic(PaymentRequest)
def extract_payment_info(invoice_text: str) -> PaymentRequest:
    """Parse invoice and return a validated PaymentRequest"""
    ...

Functions Replace Tools

Instead of wrapping functions in special tool definitions or separating the concept of functions and tools, just pass your functions directly.
from agentica import magic

# Your existing classes
class OrderResult: ...
class CustomerTier: ...
# Your existing functions
def get_customer_tier(name: str) -> CustomerTier: ...
def calculate_price(tier: CustomerTier, base_price: float) -> float: ...

@magic(get_customer_tier, calculate_price)
def process_order(customer_name: str, base_price: float) -> OrderResult:
    """Look up customer tier, calculate price, and create order"""
    ...

Variables Replace State

Instead of creating special state management objects or context managers, just pass your variables directly. Because Agentica passes by reference, you can include stateful objects like database connections and API clients that can’t be serialized.
from agentica import magic

# Your existing class
class Product: ...
# Stateful objects that can't be serialized
db_connection = DatabaseConnection(host="prod-db")
cache = RedisClient(url="redis://localhost")
current_user = User(id="123", tier="gold")

@magic(db_connection, cache, current_user)
def get_personalized_recommendations() -> list[Product]:
    """Query database for user's history, check cache, and generate recommendations"""
    ...

Summary: Why Scope

Scope matches how programming works. In any programming language, functions have scope—they can access variables, call other functions, and use types. Agentica’s magic functions and agents work the same way. If magic functions are just functions, they naturally have scope and we match that expectation. Everything is data. Because Agentica treats everything—functions, variables, types, even SDK clients—as data, you can pass anything to anything. This includes:
  • Passing functions to magic functions and visa-versa; typed function composition and hand-offs.
  • Passing Agent objects to other agents (enabling dynamic multi-agent systems).
  • Passing SDK clients, database connections, or any object that is live in your codebase.
One concept instead of three. Other frameworks force you to learn separate APIs for tools, state, and schemas. Agentica just uses scope—the same concept you already know from programming. After all, it’s just code.

Next Steps