# Function tool

POST tool arguments to your own HTTPS endpoint and feed the JSON response back to the LLM.

## Overview

The Function tool is how you connect the agent to **your** systems — CRMs, ticketing, internal APIs, payment processors, whatever you already have an HTTP wrapper for. You declare a JSON Schema for the arguments, point us at an endpoint, and the agent's runtime takes care of the round-trip:

1. You declare a JSON Schema for the arguments.
2. The LLM generates a tool call matching that schema.
3. Our backend `POST`s `{...args}` to your URL (with an optional bearer token).
4. Your endpoint runs its logic and returns JSON.
5. The response is fed to the LLM as context for its next turn.

Tap the **"How to use"** help button at the top of the modal for an inline walkthrough — it includes the same example as below.

## Configuration

| Field | Type | Notes |
| --- | --- | --- |
| Name | string | Unique identifier the LLM sees, e.g. `create_ticket`. Keep it short and snake_case. |
| Description | string | Tells the LLM *when* to call the tool. Be specific — this is the single most important field for tool-call accuracy. |
| Endpoint URL | HTTPS URL | Where we POST. Must be reachable from our backend. |
| Parameters JSON Schema | JSON object | Standard JSON Schema. The modal validates JSON on save. |
| Credential | optional | Picks a stored credential; we send its token as `Authorization: Bearer <token>`. |
| Extra headers | key/value rows | Static custom headers (e.g. `X-Source: agent-builder`). |

Default timeout is 30 seconds; override with `timeoutSeconds` on the tool config if needed.

## Example — `create_ticket`

**Parameters JSON Schema:**

```json
{
  "type": "object",
  "properties": {
    "title":    { "type": "string" },
    "priority": { "type": "string", "enum": ["low", "medium", "high", "urgent"] },
    "body":     { "type": "string" }
  },
  "required": ["title", "priority"]
}
```

**What hits your endpoint:**

```http
POST https://api.you.com/tickets
Authorization: Bearer <your-credential>
Content-Type: application/json
X-Source: agent-builder

{
  "title": "Checkout broken",
  "priority": "urgent",
  "body": "Three customers reported a 500 at step 4 in the last hour."
}
```

**Reply with any JSON — the LLM will read it:**

```json
{ "ticket_id": "TCK-42", "status": "open", "url": "https://you.zendesk.com/agent/tickets/42" }
```

The agent then replies to the user: *"Opened ticket TCK-42 (urgent). You can track it [here](...)."*

## Writing the receiving endpoint (FastAPI)

```python
from fastapi import FastAPI, Header, HTTPException
from pydantic import BaseModel
from typing import Literal, Optional

app = FastAPI()

class CreateTicket(BaseModel):
    title: str
    priority: Literal["low", "medium", "high", "urgent"]
    body: Optional[str] = ""

@app.post("/tickets")
async def create_ticket(payload: CreateTicket, authorization: str = Header(...)):
    if authorization != f"Bearer {EXPECTED_TOKEN}":
        raise HTTPException(401, "unauthorized")
    ticket = await zendesk.create(**payload.model_dump())
    return { "ticket_id": ticket.id, "status": ticket.status, "url": ticket.url }
```

Two things to notice: (1) we validate against the same schema we gave the LLM, which catches malformed calls early; (2) we return **small, structured JSON** — the LLM ingests every byte and you pay for it.

## Best practices

- **Test the endpoint with curl first.** Wire the tool only after the endpoint works end-to-end.
- **Use `enum` to restrict values.** The LLM respects enums almost perfectly — much more reliably than a description hint like *"must be one of..."*.
- **Return small, structured JSON.** `{"ok": true, "id": ...}` is enough. Dumping a 50 KB payload back to the LLM is slow and expensive.
- **Idempotency keys.** If the agent might retry, accept an idempotency key in the payload and de-dupe server-side.

## Gotchas

- HTTPS required — plain `http://` URLs are accepted by the modal but most browsers / proxies will block them at runtime.
- The bearer token comes from the **credential**, not from "Extra headers". Mixing both is allowed but the credential wins on `Authorization`.
- A non-2xx response is **not** an error from the LLM's perspective — it gets the full `{"status": "error", "status_code": 4xx, "body": ...}` envelope and may apologize and retry. Return a useful error message in the body.
- If you leave **Endpoint URL** blank, the tool falls back to the legacy "template-only" behavior, which is for builders only — production agents should always set the endpoint.

---

*Source: https://agentbuilder.systalink.sn/docs/tool-function — human documentation.*
*Other language: [/docs-md/fr/tool-function.md](/docs-md/fr/tool-function.md).*
*Machine-readable index: [/llms.txt](/llms.txt).*
