# Deploy the Ballerina Leave Assistant Sample

WSO2 Agent Manager includes a ready to deploy sample agent written in Ballerina, called the Leave Assistant. It shows how a Ballerina agent runs on the platform's Ballerina buildpack, or on your own machine with its traces sent to Agent Manager, using a realistic HR scenario built around employee leave requests.

This guide explains what the sample does and walks you through running it either way. You do not need to write or change any code to follow it.

The sample lives in the platform's GitHub repository, at `samples/leave-assistant-agent`.

## What the Leave Assistant Does[​](#what-the-leave-assistant-does "Direct link to What the Leave Assistant Does")

The Leave Assistant is a chat agent that manages employee leave requests. An employee can check their leave balance, request time off, list their existing requests, or cancel one. A manager can approve or reject a request that is waiting for a decision.

The agent enforces real rules on its own, not just record keeping:

* Annual leave of three days or fewer, and all sick leave, are approved automatically as long as the employee has enough balance.
* Longer annual leave requests, and every unpaid leave request, are held as pending until a manager approves or rejects them.
* Cancelling or rejecting a request refunds any balance that had been deducted for it.
* Asking for more days than an employee has left is turned down with a clear explanation, not partially approved.

### Available Tools[​](#available-tools "Direct link to Available Tools")

| Tool                    | What it does                                                                                                   |
| ----------------------- | -------------------------------------------------------------------------------------------------------------- |
| Check leave balance     | Looks up how many annual and sick leave days an employee has left                                              |
| Request leave           | Files a new leave request, and either approves it right away or marks it pending, depending on the rules above |
| List leave requests     | Shows every request an employee has filed, past and present                                                    |
| Cancel a leave request  | Withdraws a request and refunds any balance it had used                                                        |
| Approve a leave request | Lets a manager approve a request that is waiting for a decision                                                |
| Reject a leave request  | Lets a manager turn down a request that is waiting for a decision, and refunds any balance used                |

### Sample Employees[​](#sample-employees "Direct link to Sample Employees")

Two employees are included with the sample so you can try it out right after deploying:

| Employee id | Name           | Annual leave balance | Sick leave balance |
| ----------- | -------------- | -------------------- | ------------------ |
| `E-3001`    | Priya Fernando | 14 days              | 7 days             |
| `E-3002`    | Kasun Silva    | 3 days               | 7 days             |

## Choose How to Host the Agent[​](#choose-how-to-host-the-agent "Direct link to Choose How to Host the Agent")

|                        | **Platform-Hosted**                                                                                                         | **Externally-Hosted**                                                                                     |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| Who builds and runs it | Agent Manager, from the GitHub repository                                                                                   | You, on your own machine                                                                                  |
| Tracing                | Automatic when **Enable auto instrumentation** is on (the default). Agent Manager supplies the tracing settings and API key | You turn it on in `Config.toml` and set the endpoint and an API key you generate as environment variables |
| How you chat with it   | The built in **Try It** window                                                                                              | HTTP requests to `localhost:8000`                                                                         |

See [Internal and External Agent](/agent-platform/docs/v2026.11.0/concepts/internal-and-external-agent/.md) for the full comparison.

## Prerequisites[​](#prerequisites "Direct link to Prerequisites")

* Platform-Hosted Agent
* Externally-Hosted Agent

- An OpenAI API key. The agent uses it to power its conversations.

note

Platform-hosted Ballerina agents must use Ballerina `2201.13.x`. The Ballerina buildpack supports only that version. The sample already sets `distribution = "2201.13.4"` in `Ballerina.toml`. Use `2201.14.x` only for an externally-hosted agent.

* An OpenAI API key. The agent uses it to power its conversations.
* [Ballerina](https://ballerina.io/downloads/) `2201.13.x` or `2201.14.x` installed. Check yours with `bal version`. The tracing setup differs between the two, and the steps below cover both.
* Git, to clone the sample.

## Deploy the Sample[​](#deploy-the-sample "Direct link to Deploy the Sample")

* Platform-Hosted Agent
* Externally-Hosted Agent

### Step 1: Start Creating the Agent[​](#step-1-start-creating-the-agent "Direct link to Step 1: Start Creating the Agent")

1. Open your project in Agent Manager and go to **Agents**.
2. Click **Add Agent**.
3. Select **Platform-Hosted Agent**.
4. Choose **Source Code** as the source type.

### Step 2: Fill in Agent Details[​](#step-2-fill-in-agent-details "Direct link to Step 2: Fill in Agent Details")

| Field                      | Value                                        |
| -------------------------- | -------------------------------------------- |
| **Name**                   | `Leave Assistant`                            |
| **Description (optional)** | `Ballerina employee leave request assistant` |

### Step 3: Fill in Repository Details[​](#step-3-fill-in-repository-details "Direct link to Step 3: Fill in Repository Details")

| Field                 | Value                                   |
| --------------------- | --------------------------------------- |
| **GitHub Repository** | `https://github.com/wso2/agent-manager` |
| **Branch**            | `main`                                  |
| **Project Path**      | `samples/leave-assistant-agent`         |

### Step 4: Choose Ballerina as the Build Type[​](#step-4-choose-ballerina-as-the-build-type "Direct link to Step 4: Choose Ballerina as the Build Type")

Select **Ballerina**. You will not see the **Language Version** or **Start Command** fields that other languages ask for. The platform reads the Ballerina version from the `distribution` field in the sample's `Ballerina.toml` and knows how to build and run it directly. That version must be `2201.13.x`, the only version the Ballerina buildpack supports.

Leave **Enable auto instrumentation** turned on. This lets Agent Manager automatically set up tracing for the agent, so its conversations and tool calls show up under **Observability** with no extra setup on your part.

The form also shows a **Tracing Support for Ballerina-Based Agents** note with the line `import ballerinax/amp as _;`. The sample already contains that line, so you have nothing to add. [How the Agent Is Instrumented](#how-the-agent-is-instrumented) explains what it does and what to add to your own agent.

### Step 5: Choose Chat Agent as the Interface Type[​](#step-5-choose-chat-agent-as-the-interface-type "Direct link to Step 5: Choose Chat Agent as the Interface Type")

Choose **Chat Agent**, not **Custom API Agent**. The sample already exposes the standard chat interface Agent Manager expects, so choosing Chat Agent gives you the built in **Try It** chat window immediately, with nothing further to configure. Custom API Agent is for agents that expose their own custom endpoints and would require you to supply an OpenAPI specification, which this sample does not use.

### Step 6: Set the Environment Variable[​](#step-6-set-the-environment-variable "Direct link to Step 6: Set the Environment Variable")

The agent needs your OpenAI API key to run. Add it as an environment variable:

1. Under **Environment Variables**, click **Add**.
2. In the **Key** field, enter `BAL_CONFIG_VAR_OPENAIAPIKEY`.
3. In the **Value** field, paste your OpenAI API key.
4. Turn on **Mark as Secret** so the key is stored securely.

Why this name looks unusual

Ballerina agents read their configuration from environment variables with a `BAL_CONFIG_VAR_` prefix, rather than a plain name like `OPENAI_API_KEY`. This is the one setup detail that differs between a Ballerina agent and agents written in other languages. Use the exact key name above. If it is entered differently, the agent will not receive the API key and will fail to respond.

### Step 7: Add File Mounts (Optional)[​](#step-7-add-file-mounts-optional "Direct link to Step 7: Add File Mounts (Optional)")

The Leave Assistant sample does not need any files mounted to run, so you can skip this step. It is included here so you know how to do it if you build your own Ballerina agent later and it needs one.

1. Under **File Mounts**, click **Add File**.
2. Enter a **File Name** to identify the file.
3. Enter the **Mount Path**, the absolute location inside the agent's container where the file should appear, for example `/etc/config/settings.toml`.
4. Paste or type the file's **Content**.
5. Turn on **Mark as Secret** if the file contains sensitive information.

Mounting a file only places it inside the container. Ballerina does not automatically read configuration out of a mounted file the way it reads environment variables, so the agent's code has to explicitly open and read the file to use its contents.

### Step 8: Deploy[​](#step-8-deploy "Direct link to Step 8: Deploy")

Review your settings and click **Deploy**. The build compiles the sample and packages it into a container image. This usually takes a few minutes.

### Step 1: Register the Agent[​](#step-1-register-the-agent "Direct link to Step 1: Register the Agent")

1. Open your project in Agent Manager and go to **Agents**.

2. Click **Add Agent**.

3. Select **Externally-Hosted Agent**.

4. Fill in the agent details:

   | Field                      | Value                                        |
   | -------------------------- | -------------------------------------------- |
   | **Name**                   | `Leave Assistant`                            |
   | **Description (optional)** | `Ballerina employee leave request assistant` |

5. Click **Register**.

The **Setup Agent** panel opens. In the top right, set **Language** to **Ballerina** and **Version** to your Ballerina version (`2201.13.x` or `2201.14.x`) to see the **Zero-code Instrumentation Guide** for it. Keep the panel open, since you need the API key and endpoint it shows in the steps below. If you close it, reopen it with **Setup Agent** on the agent's overview page.

### Step 2: Get the Sample Code[​](#step-2-get-the-sample-code "Direct link to Step 2: Get the Sample Code")

```
git clone https://github.com/wso2/agent-manager

cd agent-manager/samples/leave-assistant-agent
```

The sample already has the code changes tracing needs, so you do not need to edit anything:

* `Ballerina.toml` includes the build option that compiles observability into the program. Both Ballerina versions need it.

  ```
  [build-options]

  observabilityIncluded = true
  ```

* `main.bal` imports the Agent Manager module: `import ballerinax/amp as _;`. Only Ballerina `2201.13.x` uses it. On `2201.14.x` the module stays inactive, so the line does no harm.

### Step 3: Turn on Tracing in Config.toml[​](#step-3-turn-on-tracing-in-configtoml "Direct link to Step 3: Turn on Tracing in Config.toml")

How traces reach Agent Manager depends on your Ballerina version:

* **`2201.13.x`** uses the `ballerinax/amp` module, which the Setup Agent panel describes.
* **`2201.14.x`** uses Ballerina's built-in OpenTelemetry exporter. `ballerinax/amp` does not yet work on `2201.14.x`: the agent fails at startup when tracing is turned on.

Create a `Config.toml` file in the sample directory for your version:

* Ballerina 2201.13.x
* Ballerina 2201.14.x

```
[ballerina.observe]

tracingEnabled = true

tracingProvider = "amp"
```

```
[ballerina.observe]

tracingEnabled = true

tracingProvider = "otel"



[ballerina.otel]

tracesProtocol = "http/protobuf"
```

Agent Manager receives traces over HTTP, so `tracesProtocol` must be `http/protobuf`. Without it, the exporter uses gRPC and the traces do not arrive. See [OpenTelemetry trace configurations](https://ballerina.io/learn/supported-observability-tools-and-platforms/opentelemetry/#trace-configurations) for the other settings.

Ballerina reads `Config.toml` from the directory you run the agent in. The sample's `.gitignore` excludes it, so your local settings are never committed.

### Step 4: Generate an API Key[​](#step-4-generate-an-api-key "Direct link to Step 4: Generate an API Key")

In the Setup Agent panel, under **Generate API Key**, choose a **Token Duration**. The panel generates a key the first time it opens after you register the agent. To create one with a different duration, click **Regenerate**.

Copy the key right away. It is shown only once.

### Step 5: Set the Environment Variables[​](#step-5-set-the-environment-variables "Direct link to Step 5: Set the Environment Variables")

Set the trace endpoint and API key from the Setup Agent panel, along with your OpenAI API key. `<INSTRUMENTATION_URL>` is the endpoint shown in the panel's environment variable step.

* Ballerina 2201.13.x
* Ballerina 2201.14.x

```
export BAL_CONFIG_VAR_BALLERINAX_AMP_OTELENDPOINT="<INSTRUMENTATION_URL>"

export BAL_CONFIG_VAR_BALLERINAX_AMP_APIKEY="<your-generated-api-key>"

export BAL_CONFIG_VAR_OPENAIAPIKEY="<your-openai-api-key>"
```

The first two lines match step 5 of the Setup Agent panel, so you can copy them from there.

```
export BAL_CONFIG_VAR_BALLERINA_OTEL_TRACESENDPOINT="<INSTRUMENTATION_URL>/v1/traces"

export BAL_CONFIG_VAR_BALLERINA_OTEL_TRACESEXPORTERHEADERS="x-amp-api-key=<your-generated-api-key>"

export BAL_CONFIG_VAR_OPENAIAPIKEY="<your-openai-api-key>"
```

The first two lines match step 4 of the Setup Agent panel when **Version** is `2201.14.x`, so you can copy them from there. The endpoint ends in `/v1/traces` because the built-in exporter sends to the exact address you give it. The API key travels in the `x-amp-api-key` header.

The naming convention

Ballerina reads `configurable` values from environment variables named `BAL_CONFIG_VAR_` followed by the value's name in uppercase. For a value declared in another module, the module's organization and name come first. That gives `BAL_CONFIG_VAR_BALLERINAX_AMP_...` for `ballerinax/amp` and `BAL_CONFIG_VAR_BALLERINA_OTEL_...` for the built-in `ballerina/otel` exporter. Use the exact names above. If a name is entered differently, the agent does not receive that value.

### Step 6: Run the Agent[​](#step-6-run-the-agent "Direct link to Step 6: Run the Agent")

From the sample directory, in the same terminal where you set the environment variables:

```
bal run
```

Right after `Running executable`, Ballerina prints a line confirming that tracing started:

* Ballerina 2201.13.x
* Ballerina 2201.14.x

```
ballerina: started publishing traces to Amp on <INSTRUMENTATION_URL>/v1/traces
```

```
ballerina: started publishing traces to Otel on <INSTRUMENTATION_URL>/v1/traces [HTTP] (with 1 custom header(s))
```

If that line does not appear, tracing is off. Check that `Config.toml` is in the directory you ran `bal run` from. The agent then starts serving on `http://localhost:8000`.

## Try the Agent[​](#try-the-agent "Direct link to Try the Agent")

* Platform-Hosted Agent
* Externally-Hosted Agent

Once the deployment finishes, open the agent and click **Try It**. Some things to try:

```
What is my leave balance? My employee id is E-3001
```

```
I am E-3001, request 2 days annual leave starting tomorrow
```

```
I am E-3002, request 4 days annual leave starting Friday
```

The last one should come back as a clear rejection, since E-3002 only has 3 annual days left.

An externally-hosted agent has no **Try It** window, because Agent Manager does not run it. Send messages to the agent's `POST /chat` endpoint from a second terminal instead:

```
curl -s localhost:8000/chat \

  -H 'content-type: application/json' \

  -d '{"session_id": "s1", "message": "What is my leave balance? My employee id is E-3001"}'
```

The agent replies with a JSON object such as `{"response": "..."}`. Keep the same `session_id` across requests to continue the conversation. Some other messages to try:

```
I am E-3001, request 2 days annual leave starting tomorrow
```

```
I am E-3002, request 4 days annual leave starting Friday
```

The last one should come back as a clear rejection, since E-3002 only has 3 annual days left.

Open the **Observability** tab afterward to see which tool the agent called for each message.

## How the Agent Is Instrumented[​](#how-the-agent-is-instrumented "Direct link to How the Agent Is Instrumented")

The traces under **Observability** depend on three pieces. The sample already has the first two. For a platform-hosted agent, Agent Manager provides the third.

| Piece                                            | Where it lives                    | Who provides it                                           |
| ------------------------------------------------ | --------------------------------- | --------------------------------------------------------- |
| The `ballerinax/amp` import                      | `main.bal`                        | The sample                                                |
| The `observabilityIncluded` build option         | `Ballerina.toml`                  | The sample                                                |
| Tracing settings, collector address, and API key | The running agent's configuration | Agent Manager, when **Enable auto instrumentation** is on |

The sample is built on Ballerina `2201.13.x` (`distribution = "2201.13.4"` in `Ballerina.toml`), so it traces through the `ballerinax/amp` module. It imports the module for its side effect only, which is why the import ends in `as _`:

```
import ballerinax/amp as _;
```

It also turns on observability for the build in `Ballerina.toml`:

```
[build-options]

observabilityIncluded = true
```

At runtime Agent Manager turns tracing on with `amp` as the tracing provider. It also sets `BAL_CONFIG_VAR_BALLERINAX_AMP_OTELENDPOINT` and `BAL_CONFIG_VAR_BALLERINAX_AMP_APIKEY` for the agent. That is why the platform-hosted steps only ask for the OpenAI key, and why you do not add a tracing section to `Config.toml`.

### Add It to Your Own Ballerina Agent[​](#add-it-to-your-own-ballerina-agent "Direct link to Add It to Your Own Ballerina Agent")

For an agent you write yourself and deploy through Agent Manager:

1. Set `distribution` in `Ballerina.toml` to a `2201.13.x` version. The Ballerina buildpack supports only `2201.13.x`.
2. Add `import ballerinax/amp as _;` to one of your `.bal` files.
3. Add `observabilityIncluded = true` under `[build-options]` in `Ballerina.toml`.
4. Keep **Enable auto instrumentation** turned on when you create the agent.

That is all. The tracing settings and credentials come from Agent Manager.

### If the Agent Runs Outside Agent Manager[​](#if-the-agent-runs-outside-agent-manager "Direct link to If the Agent Runs Outside Agent Manager")

An externally-hosted Ballerina agent needs the same import and build option. It also needs the third piece, which Agent Manager cannot provide because it does not run the agent. You supply it yourself: the tracing settings in `Config.toml`, and the collector address and API key as environment variables.

Follow Steps 3 to 6 in the **Externally-Hosted Agent** tab under [Deploy the Sample](#deploy-the-sample). They work the same way for any Ballerina agent, not only the sample.

## Troubleshooting[​](#troubleshooting "Direct link to Troubleshooting")

| What you see                                                                                                             | What to do                                                                                                                                                                                                                                                                                                                                                                        |
| ------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| The runtime log of a platform-hosted agent shows a warning that `Config.toml` was not found                              | This is expected and can be ignored. `Config.toml` only matters when you run the agent yourself.                                                                                                                                                                                                                                                                                  |
| The agent does not respond, or an error mentions the API key                                                             | Confirm the environment variable is named exactly `BAL_CONFIG_VAR_OPENAIAPIKEY`, with no typos.                                                                                                                                                                                                                                                                                   |
| The deployment stays on "Deploying" for a long time                                                                      | Open the **Build** tab and confirm the build itself finished successfully before assuming something is wrong with the agent.                                                                                                                                                                                                                                                      |
| A platform-hosted agent responds, but no traces appear under **Observability**                                           | Confirm **Enable auto instrumentation** was on when you created the agent. For your own agent, also check that a `.bal` file has `import ballerinax/amp as _;` and `Ballerina.toml` has `observabilityIncluded = true`. See [How the Agent Is Instrumented](#how-the-agent-is-instrumented).                                                                                      |
| An externally-hosted agent responds, but no traces appear under **Observability**                                        | Confirm the startup log shows the `started publishing traces` line. If it does not, `Config.toml` is missing from the directory you ran `bal run` from, or it lacks the `[ballerina.observe]` settings. Also confirm the endpoint and API key variables for your Ballerina version are set in that terminal. If the API key has expired, generate a new one from **Setup Agent**. |
| On Ballerina `2201.14.x`, the agent fails at startup with `NoSuchMethodError` and a stack trace through `ballerinax.amp` | `Config.toml` sets `tracingProvider = "amp"`, which `2201.14.x` does not support yet. Use the `2201.14.x` setup in Steps 3 and 5.                                                                                                                                                                                                                                                 |

## See Also[​](#see-also "Direct link to See Also")

| Guide                                                                                            | What it covers                                                     |
| ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------ |
| [Create Your First Agent](/agent-platform/docs/v2026.11.0/tutorials/create-your-first-agent/.md) | The general agent creation flow, for any language                  |
| [Monitor Your Agent](/agent-platform/docs/v2026.11.0/tutorials/observe-first-agent/.md)          | Setting up and reading traces for a newly deployed agent           |
| [AMP Instrumentation](/agent-platform/docs/v2026.11.0/guides/amp-instrumentation/.md)            | How tracing works for platform-hosted and externally-hosted agents |
