# Functions Runtime

The functions runtime provides a way to define and run Python functions in a way
that makes it easy to operate with function-calling LLMs.

## Stateless functions

Functions that have no state can be defined in a way that is compatible with the runtime in the following way:

```python title="functions_runtime.py"
--8<-- "functions_runtime.py:stateless_function"
```

1. The decorator will register the function with the runtime.
2. Type hints are mandatory. This is important as the runtime will use them to generate documentation for the LLM, and to validate the LLM-provided arguments.
3. Note that the function is documented with the expected arguments. This is important as the runtime will convert this information into useful documentation for the LLM.

!!! note
    When using tools as part of a suite there is no need to manually instantiate the runtime and register functions with it. This is only useful if you want to run an agent that uses the functions runtime as a standalone tool.

The runtime can be used to run the function:

```python title="functions_runtime.py"
--8<-- "functions_runtime.py:run_stateless_function"
```

1. The first argument is the environment (`None` in this case as the function is stateless)

## Stateful functions

We can also define functions that rely on a stateful environment. This environment can't be given as argument by the LLM, so it is injected by the runtime in the function call. This is done by using the [`Depends`][agentdojo.functions_runtime.Depends] class for the environment-related arguments when defining the function. Let's show an example where the environment contains a counter:

```python title="functions_runtime.py"
--8<-- "functions_runtime.py:stateful_function"
```

1. This argument is a dependency that will be injected by the runtime. The runtime will extract the `counter` field from the environment and pass it to the function. This is because the agent can't (and should not!) provide the state to the tool.
2. No argument is documented as `counter` is a dependency.
3. This is another way to register a function with the runtime. This is useful when the function is defined outside the runtime creation scope.

The runtime can be used to run the function:

```python title="functions_runtime.py"
--8<-- "functions_runtime.py:run_stateful_function"
```

1. Note that now the first argument is the environment. The runtime will inject the state into the function call.


## Error handling

By default, the runtime will catch exceptions raised by the function and return them to the LLM. This is useful to let the LLM recover from errors.

```python title="functions_runtime.py"
--8<-- "functions_runtime.py:error"
```

1. In this case, the exception is raised because the function is expecting a number but the LLM is providing a string (that can't be coerced to a number).

However, the runtime can also raise exceptions the `raise_on_error` to the [`run_function`][agentdojo.functions_runtime.FunctionsRuntime.run_function] method is `True`:

```python title="functions_runtime.py"
--8<-- "functions_runtime.py:exception"
```
