# Programmatic Tool Calling (PTC) Configuration

### Overview

**Programmatic Tool Calling (PTC)** lets a Digital Employee orchestrate tools through Python code executed in a sandboxed environment, rather than making individual API round-trips for each tool call.

When PTC is enabled, the agent gets access to an `execute_ptc_code` tool. The agent can write Python code that calls its registered tools, processes intermediate results, and returns only the final output to its context window.

> **Note**: PTC is currently only supported for **local runs** (`run(..., local=True)`).

For the canonical guide, see the [AIP PTC Guide](https://gdplabs.gitbook.io/gl-aip/how-to-guides/programmatic-tool-calling).

### Key Concepts

#### Why use PTC?

| Benefit                        | Description                                                                                         |
| ------------------------------ | --------------------------------------------------------------------------------------------------- |
| **Context Window Protection**  | Intermediate results stay in the sandbox — only the final output is returned to the agent's context |
| **Parallel Execution**         | The agent can call multiple tools concurrently within a single code block                           |
| **Reduced Inference Overhead** | One model pass writes the code; execution replaces multiple model-tool-model round-trips            |

#### How PTC works

1. The agent receives a task requiring multiple tool calls.
2. The agent writes a Python script and invokes `execute_ptc_code`.
3. The script runs inside an [E2B](https://e2b.dev) sandbox with all registered tools available.
4. Only the final printed output is returned to the agent's context.

#### The `PTC` configuration object

PTC is configured via the `PTC` class from `glaip_sdk.ptc`:

{% code lineNumbers="true" %}

```python
from glaip_sdk.ptc import PTC

ptc_config = PTC(
    enabled=True,
    sandbox_timeout=120.0,
)
```

{% endcode %}

The instance is passed to `DigitalEmployee` via the `ptc` parameter. Tools registered on the Digital Employee are automatically made available in the sandbox — you do not need to configure them separately.

#### Prerequisites

* `E2B_API_KEY` must be set (get one at <https://e2b.dev>)
* `OPENAI_API_KEY` (or another supported model key) must be set
* `glaip-sdk` installed with `[local]` extras

### Complete Example

The file [`examples/ptc/ptc_example.py`](https://github.com/GDP-ADMIN/CATAPA-SDK/blob/release/v0.0.x/python/digital-employee-core/examples/ptc/ptc_example.py) demonstrates the PTC workflow.

#### Step 1: Import required components

{% code lineNumbers="true" %}

```python
from dotenv import load_dotenv
from glaip_sdk import Tool
from glaip_sdk.ptc import PTC

from digital_employee_core import (
    DigitalEmployee,
    DigitalEmployeeIdentity,
    DigitalEmployeeJob,
)
from digital_employee_core.connectors.tools.utility_tools import time_tool
from examples.ptc.tools.calculator_tool import CalculatorTool

load_dotenv()
```

{% endcode %}

#### Step 2: Create the Digital Employee identity

{% code lineNumbers="true" %}

```python
job = DigitalEmployeeJob(
    title="PTC Assistant",
    description="A helpful assistant with Programmatic Tool Calling enabled",
    instruction=(
        "You are a helpful assistant with Programmatic Tool Calling (PTC) enabled. "
        "When you need to orchestrate multiple tool calls or process data programmatically, "
        "you can write Python code using the execute_ptc_code tool.\n\n"
        "Use PTC when you need to:\n"
        "1. Call multiple tools and process their results\n"
        "2. Perform calculations or data transformations\n"
        "3. Keep intermediate results out of context\n\n"
        "Provide clear and helpful responses."
    ),
)

identity = DigitalEmployeeIdentity(
    name="PTC Assistant",
    email="ptc.assistant@example.com",
    job=job,
)
```

{% endcode %}

#### Step 3: Configure PTC and attach tools

{% code lineNumbers="true" %}

```python
ptc_config = PTC(
    enabled=True,
    sandbox_timeout=120.0,  # Maximum execution time in seconds, optional
)

calculator_tool = Tool.from_langchain(CalculatorTool)

digital_employee = DigitalEmployee(
    identity=identity,
    tools=[time_tool, calculator_tool],
    ptc=ptc_config,
)
```

{% endcode %}

All tools passed to `DigitalEmployee` are automatically available inside the PTC sandbox.

#### Step 4: Run locally

{% code lineNumbers="true" %}

```python
message = "Calculate what time it will be in 3.5 hours. Directly show me the time without any intermediate output."

result = digital_employee.run(message=message, local=True)
print(result)
```

{% endcode %}

> **Note**: Do **not** call `deploy()` for local PTC runs. Use `run(..., local=True)` directly.

#### What this example shows

* PTC is activated with `PTC(enabled=True)`.
* Tools are registered on the Digital Employee — no separate sandbox configuration needed.
* The agent can orchestrate `time_tool` and `calculator_tool` in a single code block.
* Intermediate results (e.g., the raw time value) stay in the sandbox; only the final answer is returned to the model context.

### Configuration Reference

| Parameter              | Type                | Default               | Description                                                                                                                              |
| ---------------------- | ------------------- | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `enabled`              | `bool`              | `False`               | Activates PTC. Must be `True` to use PTC.                                                                                                |
| `sandbox_timeout`      | `float`             | `120.0`               | Maximum execution time (seconds) for a sandbox run.                                                                                      |
| `default_tool_timeout` | `float`             | `60.0`                | Per-tool call timeout (seconds) inside the sandbox.                                                                                      |
| `sandbox_template`     | `str \| None`       | `"aip-agents-ptc-v1"` | E2B sandbox template identifier.                                                                                                         |
| `prompt`               | `dict \| None`      | `None`                | Prompt configuration for the `execute_ptc_code` tool description. Accepts `{"mode": "...", "include_example": bool}`.                    |
| `ptc_packages`         | `list[str] \| None` | `None`                | Additional Python packages to install in the sandbox. `None` uses smart package selection; an explicit list is additive to the defaults. |

> **Not supported**: `custom_tools` — tools are always auto-derived from the `DigitalEmployee.tools` list.

### Common Use Cases

#### Parallel tool calls

The agent can call multiple tools concurrently in one code block, without extra round-trips:

{% code lineNumbers="true" %}

```python
# Agent-generated code running inside the sandbox
result_a = time_tool()
result_b = calculator_tool(expression="365 * 24")
print(f"Time: {result_a}, Hours in a year: {result_b}")
```

{% endcode %}

#### Installing extra sandbox packages

{% code lineNumbers="true" %}

```python
ptc_config = PTC(
    enabled=True,
    ptc_packages=["pandas==2.2.0", "numpy"],
)
```

{% endcode %}

#### Extending the sandbox timeout for long-running tasks

{% code lineNumbers="true" %}

```python
ptc_config = PTC(
    enabled=True,
    sandbox_timeout=300.0,   # 5 minutes
    default_tool_timeout=90.0,
)
```

{% endcode %}

### Best Practices

#### 1. Mention `execute_ptc_code` in the job instruction

Explicitly tell the agent when and how to use PTC in the `instruction` field:

{% code lineNumbers="true" %}

```python
instruction=(
    "When orchestrating multiple tool calls, use execute_ptc_code to run them "
    "in a single Python block and return only the final result."
)
```

{% endcode %}

Without this hint, the agent may fall back to individual tool calls.

#### 2. Keep `sandbox_timeout` proportional to task complexity

A short timeout is fine for quick calculations; increase it for tasks that involve many sequential tool calls or heavy data processing.

#### 3. Use `ptc_packages` only when needed

If `ptc_packages` is `None` (the default), aip-agents selects packages automatically based on which tools are registered. Only set it explicitly when you need a package that is not auto-detected.

#### 4. Do not call `deploy()` for local PTC runs

PTC is a local-only feature. Call `run(..., local=True)` directly — skip `deploy()`.

#### 5. Use a single `DigitalEmployee` instance per session

Constructing a new `DigitalEmployee` on every request means a cold sandbox start for each run. Reuse the instance across calls to amortize sandbox startup time.

### Troubleshooting

#### `E2B_API_KEY` not set

**Problem**: The sandbox fails to start with an authentication error.

**Solution**: Obtain an API key from <https://e2b.dev> and add it to your `.env` file:

{% code lineNumbers="true" %}

```bash
E2B_API_KEY=your_key_here
```

{% endcode %}

#### `glaip-sdk[local]` not installed

**Problem**: Import errors or missing sandbox dependencies.

**Solution**: Install the `local` extras:

{% code lineNumbers="true" %}

```bash
poetry add "glaip-sdk[local]"
```

{% endcode %}

#### Agent not using `execute_ptc_code`

**Problem**: The agent calls tools individually instead of using PTC.

**Solution**: Add explicit PTC guidance to the job `instruction`. The model needs to be told when PTC is the preferred approach (see Best Practice 1 above).

#### Sandbox timeout exceeded

**Problem**: Execution is cut off mid-run with a timeout error.

**Solution**: Increase `sandbox_timeout` and, if tools are slow, `default_tool_timeout`:

{% code lineNumbers="true" %}

```python
ptc_config = PTC(
    enabled=True,
    sandbox_timeout=300.0,
    default_tool_timeout=90.0,
)
```

{% endcode %}

#### Tool not available inside the sandbox

**Problem**: The agent's PTC code raises an import or `NameError` for a registered tool.

**Solution**: Verify the tool is passed to `DigitalEmployee(tools=[...])`. Tools are auto-derived from this list — no additional sandbox configuration is required.
