> ## Documentation Index
> Fetch the complete documentation index at: https://docs.symbolica.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Scope

> The unified interface for functions, state, and types

## Overview

While other frameworks have separate concepts for tools, state, and schemas, the Agentica SDK's unique model unifies all of these into a single concept: **scope**. After all, it's just code.

Agents built with the Agentica SDK operate via [REPL and Warp RPC](/concepts/how-it-works), 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 agents 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.

<CodeGroup>
  ```python Python theme={null}
  from agentica import agentic
  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")

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

  ```typescript TypeScript theme={null}
  import { agentic } from '@symbolica/agentica';

  type Currency = 'USD' | 'EUR' | 'GBP';

  class PaymentRequest {
    amount: number;
    currency: Currency;
    customerEmail: string;

    constructor(amount: number, currency: Currency, customerEmail: string) {
      if (amount <= 0) {
        throw new Error("Amount must be positive");
      }
      if (!customerEmail.includes("@")) {
        throw new Error("Invalid email address");
      }
      this.amount = amount;
      this.currency = currency;
      this.customerEmail = customerEmail;
    }
  }

  async function extractPaymentInfo(invoiceText: string): Promise<PaymentRequest> {
    return agentic<PaymentRequest>(
      "Parse invoice and return a validated PaymentRequest",
      { invoiceText, PaymentRequest }
    );
  }
  ```
</CodeGroup>

## Functions Replace Tools

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

<CodeGroup>
  ```python Python theme={null}
  from agentica import agentic

  # 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: ...

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

  ```typescript TypeScript theme={null}
  import { agentic } from '@symbolica/agentica';

  // Your existing classes
  class OrderResult { ... }
  class CustomerTier { ... }
  // Your existing functions
  function getCustomerTier(name: string): CustomerTier { ... }
  function calculateDiscount(tier: CustomerTier): number { ... }

  async function processOrder(customerName: string, basePrice: number): Promise<OrderResult> {
    return agentic<OrderResult>(
      "Look up customer tier, calculate price, and create order",
      { customerName, basePrice, getCustomerTier, calculateDiscount }
    );
  }
  ```
</CodeGroup>

## Variables Replace State

Because the Agentica SDK can warp objects by reference as well as by value, you can give agents access to stateful resources like functions, database connections, third party modules, instantiated API clients, even custom classes!

You can either provide such resources to an agentic function by passing them through function arguments -- so they can differ from call to call -- or as global resources present at the time you define the agentic function itself.

<CodeGroup>
  ```python Python theme={null}
  from agentica import agentic
  import numpy as np
  import sqlite3

  db = sqlite3.connect("inventory.db")

  # Stateful resources that agentic function can interact with
  resources = dict(
    db=db,
    cache=RedisClient(url="redis://localhost"),
    current_user=User(id="123", tier="gold")
  )

  # Pass entire modules and live connections directly
  @agentic(np, scope=resources)
  async def reorder_check(threshold: float) -> list[str]:
      """Query the products table for items whose stock is below
      `threshold` standard deviations from the mean, and return
      their names."""
      ...

  low_stock = await reorder_check(1.5)
  ```

  ```typescript TypeScript theme={null}
  import { agentic } from '@symbolica/agentica';

  // Your existing class
  class Product { ... }
  // Stateful objects that can't be serialized
  const dbConnection = new DatabaseConnection({ host: "prod-db" });
  const cache = new RedisClient({ url: "redis://localhost" });
  const currentUser = new User({ id: "123", tier: "gold" });

  async function getPersonalizedRecommendations(): Promise<Product[]> {
    return agentic<Product[]>(
      "Query database for user's history, check cache, and generate recommendations",
      { dbConnection, cache, currentUser }
    );
  }
  ```
</CodeGroup>

## 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. The Agentica SDK's agentic functions and agents work the same way. If agentic functions are just functions, they naturally have scope and we match that expectation.

**Everything is data.** Because the Agentica SDK treats everything -- functions, variables, types, even SDK clients -- as data, you can pass anything to anything. This includes:

* Passing functions to agentic functions and vice 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. The Agentica SDK just uses scope -- the same concept you already know from programming. After all, it's just code.

## Next Steps

<CardGroup cols={2}>
  <Card title="Functions vs Agents" icon="wand-magic-sparkles" href="/concepts/agentic-vs-agents">
    Understand when to use each
  </Card>

  <Card title="Agentic Functions" icon="wand-magic-sparkles" href="/concepts/agentic">
    Dive into agentic function usage
  </Card>

  <Card title="Agents" icon="user-tie" href="/concepts/agent">
    Learn about agent usage
  </Card>

  <Card title="Advanced" icon="hat-wizard" href="/concepts/unmcp">
    Learn how we unwrap MCP
  </Card>
</CardGroup>
