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

# How It Works

> Understanding the execution model

export const TypeScript = props => {
  const getLang = () => {
    let lang = null;
    try {
      const raw = window.localStorage.getItem('code');
      lang = raw;
      try {
        lang = JSON.parse(raw);
      } catch (_err) {}
    } catch (_err) {}
    return (lang || '').toLowerCase();
  };
  const lang = getLang();
  return <span class="when-lang when-typescript" style={{
    display: lang.includes('typescript') ? 'inline' : 'none'
  }}>{props.children}</span>;
};

export const Python = props => {
  let lang = null;
  try {
    const raw = window.localStorage.getItem('code');
    lang = raw;
    try {
      lang = JSON.parse(raw);
    } catch (_err) {}
  } catch (_err) {}
  lang = (lang || 'Python').toLowerCase();
  if (!['python', 'typescript'].some(l => lang.includes(l))) {
    lang = 'python';
  }
  return <span class="when-lang when-python" style={{
    display: lang.includes('python') ? 'inline' : 'none'
  }}>{props.children}</span>;
};

## Overview

The Agentica SDK allows agents to write and execute **arbitrary Python code** in a **sandboxed execution environment**, while maintaining **direct access to objects in your runtime**.

## Why?

The Agentica SDK is built on the premise that **code is the most expressive interface through which models can interact with their environment**; with the Agentica SDK, agents can manage and **engineer their own context**, manipulate and return objects **by reference** and dynamically **create their own tools**.

Check out the blog post [Beyond Code Mode: The Agentica SDK](https://symbolica.ai/blog/introducing-agentica).

## The Mental Model

This is achieved by **Warp**, the Agentica SDK's protocol that combines **Remote Procedure Call (RPC)** with **transparent proxying in a Python REPL** using a language-agnostic object model.

* **Sandboxed execution**: Agents write Python code that is executed in a safe, isolated environment
* **Warp bridge**: Functions you pass in [scope](/concepts/scope) appear in the sandbox as stubs, but execute in your runtime
* **Your code stays local**: All actual computation happens in your process with full access to your dependencies
* **Objects are warped**: Return values from your functions are represented as lightweight proxies in the sandbox, not fully serialized
* **Type safety enforced**: Return values are validated against your type annotations

## Anatomy of an Invocation

Let's walk through exactly what happens when you call an agentic function (much like an agent). Consider the simplified example below where we have elided portions of the code for clarity.

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

  # Your existing types and functions
  class OrderResult: ...
  class CustomerTier: ...
  def get_customer_tier(name: str) -> CustomerTier: ...
  def calculate_discount(tier: CustomerTier) -> float: ...

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

  # Call the function
  result = await process_order("Alice", 100.0)
  ```

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

  // Your existing types and functions
  class OrderResult { ... }
  class CustomerTier { ... }
  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 discount, and create order",
      { customerName, basePrice, getCustomerTier, calculateDiscount }
    );
  }

  // Call the function
  const result = await processOrder("Alice", 100.0);
  ```
</CodeGroup>

### What Happens Behind the Scenes

When <Python>`process_order("Alice", 100.0)`</Python><TypeScript>`await processOrder("Alice", 100.0)`</TypeScript> is called, it triggers the following interaction.

**1. The Agentica SDK sends a request to the underlying model** with:

* The instruction: `"Look up customer tier, calculate discount, and create order"`
* The input parameters: <Python>`customer_name = "Alice"`, `base_price = 100.0`</Python><TypeScript>`customerName = "Alice"`, `basePrice = 100.0`</TypeScript>
* The signatures and docstrings of functions in [scope](/concepts/scope): <Python>`get_customer_tier()`, `calculate_discount()`</Python><TypeScript>`getCustomerTier()`, `calculateDiscount()`</TypeScript>
* The details of the types in [scope](/concepts/scope): `OrderResult`, `CustomerTier`
* The details of the expected return type, `OrderResult`

**2. The agent interactively writes and evaluates code in a sandboxed REPL environment**.

The agent always writes **Python code** in the sandbox, regardless of whether you're using the Python or TypeScript SDK. From its perspective, the Python REPL in the sandbox has everything in [scope](/concepts/scope): `get_customer_tier`, `calculate_discount`, `OrderResult`, `CustomerTier`, etc. The agent can write and evaluate code like normal. Here's what a sample REPL session could look like.

````markdown wrap expandable An example of an agent's output in the Agentica SDK. theme={null}
[Agent]
I should begin by obtaining the customer tier
```python
tier = get_customer_tier(customer_name)
tier
```
[Execution]
```
CustomerTier(level='gold', benefits=['free_shipping', 'priority_support'])
```
[Agent]
This must be an important customer
```python
I need to calculate the discount factor
discount = calculate_discount(tier)
discount
```
[Execution]
```
0.15
```
[Agent]
That looks reasonable, a 15% discount. I should compute the price using the discount
```python
final_price = base_price * (1 - discount)
final_price
```
[Execution]
```
85.0
```
[Agent]
Good, let me assemble the order
```python
return OrderResult(
     customer=customer_name,
     original_price=base_price,
     discount=discount,
     final_price=final_price
)
```
[Execution]
```
No output was produced.
```
````

<Note>
  **Async Functions in the REPL:** The REPL includes a top-level event loop, so async functions work naturally. When you pass async functions from your runtime, they appear in the REPL as functions returning `Future[T]` (Python `async def foo(...) -> T` becomes `def foo(...) -> Future[T]`, TypeScript `async function foo(...): Promise<T>` similarly translates). The agent can use top-level `await`, and standard patterns like `asyncio.gather()` work as expected.
</Note>

### A breakdown

Let's break down the key lines from the agent's output above:

```python theme={null}
tier = get_customer_tier(customer_name)
```

This calls a **stub function** in the sandbox — `get_customer_tier` was never defined in the sandbox, but Warp makes it *appear* to be present in the agent's execution environment. The stub intercepts the call and sends an RPC to **your runtime**, where your actual `get_customer_tier()` executes with access to your database, environment, etc.

```python theme={null}
tier
CustomerTier(level='gold', benefits=['free_shipping', 'priority_support'])
```

The return value is **warped** back to the sandbox. On inspection, the agent sees what looks like a `CustomerTier` object, but it's actually a lightweight reference to the real object in your runtime.

```python theme={null}
discount = calculate_discount(tier)
```

When the agent passes `tier` to another function, Warp resolves the proxy back to the real object. Your actual `calculate_discount()` executes in your runtime with the real `CustomerTier` object.

```python theme={null}
final_price = base_price * (1 - discount)
```

Simple calculations execute directly in the sandbox -- no RPC needed for basic operations.

```python theme={null}
result = OrderResult(...)
```

Instantiating `OrderResult` triggers your actual class constructor in your runtime via Warp, returning another proxy.

**3. The result type is validated and returned** to your code:

```python theme={null}
result = await process_order("Alice", 100.0)
# Returns: OrderResult(customer="Alice", original_price=100.0, discount=0.15, final_price=85.0)
```

Observe that no schema was generated or needed to return a value to your code. Instead an object was instantiated in your runtime and the Agentica SDK ensures that the type of `result` matches the required return type (`OrderResult`), which ensures type safety.

### Current limitations

Agents and agentic functions currently cannot:

* define a type and then return an instance of that type
* return functions, types, or generators that they have defined themselves

<Note>
  **Expanded module support**: Entire modules (e.g. `numpy`, `pandas`, `scipy`, `sympy`), C-implemented functions, and pure lambdas can now be passed from the client into agent scope and warped (proxied by reference) to the sandbox.
</Note>

### Bug reports

To report bugs and errors to the Agentica team, please create an issue in the relevant GitHub repo ([Python SDK](https://github.com/symbolica-ai/agentica-python-sdk) or [TypeScript SDK](https://github.com/symbolica-ai/agentica-typescript-sdk)) and include the agent logs (filenames are printed to output).

Happy programming!

## Next Steps

<CardGroup cols={2}>
  <Card title="Scope" icon="wrench" href="/concepts/scope">
    Learn about passing functions, state, and types
  </Card>

  <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="Examples" icon="code" href="/guides/examples">
    See practical examples
  </Card>
</CardGroup>
