Developer Companion

CallFunc β€” Developer Reference

Setting up tools in Perxona β€” a hands-on guide for builders

Readable HTML layout Audience: Developers turning an HTTP API into agent tools
Blue blocks Concrete actions to take in the console.
Amber blocks Common gotchas, limits, and caveats.
Green blocks Checks that tell you things are working.
Purple blocks Prompt snippets you can hand to AI tools.

This manual shows you how to turn an HTTP endpoint you already have into a tool your Perxona agent can call β€” and, just as importantly, how to write it so the LLM actually understands when and how to use it.


1. How an LLM “sees” a tool

When the agent runs, Perxona hands the model a list of tools. Each tool is essentially this (the same shape OpenAI and Anthropic use under the hood):

{
  "name": "verb_noun",
  "description": "What the tool does, and when the model should reach for it.",
  "parameters": { /* the INPUT JSON Schema */ }
}

On every turn the model asks itself, using only that text:

  1. Should I call a tool at all? β†’ driven by the name + description.
  2. Which one? β†’ driven by how distinct the descriptions are from each other.
  3. With what arguments? β†’ driven by the input schema (field names, types, required, descriptions, enums, defaults).
  4. What did I get back / what do I tell the user? β†’ helped by the output schema (so it knows which fields come back and what type each one is).

So your job as a builder is to write those four things clearly. That’s the whole craft.

What actually happens on a call (under the hood)

flowchart TB A["LLM reads name + description + input schema
decides to call, emits arguments matching the input schema"] B["Perxona validates args (JSON Schema β†’ Pydantic),
injects your secret, and makes the HTTP request"] C["Your server runs and returns JSON"] D["Perxona feeds the JSON back to the LLM
(the output schema helps it interpret),
which then writes the user-facing reply β€” or calls another tool"] A --> B --> C --> D

You only build the server + the four text/shape signals. Perxona does the validation, the secret injection, and the HTTP call.


2. The two building blocks in Perxona

Setting up a tool is always two objects:

Object What it is What you put in it Does the LLM see it?
OutboundAPI The connection: where your server lives + how to authenticate Base URL, secret (API key) No β€” infrastructure only
CallFunc The tool the agent can call Name, description, method, path, input schema, output schema Yes β€” this is the contract
  • Create one OutboundAPI per backend (one base URL + one secret).
  • Create one CallFunc per operation, all pointing at that OutboundAPI.

CallFuncs live inside a Storyboard’s Panel, so a tool can be available only in the conversation states (panels) where it makes sense.


3. Setting up a tool

What you need first

Perxona calls your endpoint from the cloud, so before you open the console you need:

  • a public HTTPS base URL for your server β€” an address that only exists on your own machine is not reachable;
  • an authentication secret your server checks on every request (an API key, a bearer token, or none if the endpoint is genuinely public).

Step 1 β€” Create the OutboundAPI (the connection)

In the admin console (Backend Core / Outbound API), create one entry per backend:

Field What goes in it
Base URL Scheme + host your endpoints hang off. Individual paths belong to each CallFunc, not here.
Secret type API_KEY, Bearer, or None.
Header name The header your server reads the credential from.
Header value The credential itself β€” stored encrypted and injected at call time. The model never sees it.

Every CallFunc that hits the same backend points at this one entry, so a rotated key or a moved host is a single edit rather than one per tool.

Step 2 β€” Create a CallFunc (the tool)

Add one CallFunc per operation you want the agent to be able to perform:

Field What goes in it Does the LLM see it?
Type OUTBOUND_API No
Name A distinct verb_noun (Β§4.1) Yes
Method / Path The HTTP verb, and the path under the OutboundAPI’s base URL No
Description What it does and when to use it (Β§4.2) Yes
Input schema JSON Schema for the arguments (Β§4.3) Yes
Output schema JSON Schema for what comes back (Β§4.4) Yes

Keep the set of tools small and mutually distinct. Two tools whose descriptions overlap force the model to guess between them, and it will sometimes guess wrong.

Step 3 β€” Test it in a panel

Open a panel conversation and phrase a request the way a real user would β€” not in the vocabulary of your own schema. Three things to watch, in this order:

  1. Does it call at all? If not, the description is not stating a trigger.
  2. Does it call the right tool? If not, two descriptions overlap.
  3. Are the arguments right? If not, the field descriptions are missing formats, enums, or required.

Section 6 maps the common symptoms to fixes.


4. The craft: writing descriptions & schemas the LLM understands

This is the part that decides whether the agent feels smart or dumb. Some rules of thumb, with before/after.

4.1 Name = the verb the model matches on

Use a clear verb_noun β€” the verb says what the tool does, the noun says what it acts on. Keep names distinct so the model never has to guess between two similar tools.

4.2 Description = when to use it, not just what it is

The description is read on every turn as the model decides whether to call. Say what it does and the trigger (“use this when…”), plus any limits.

❌ Vague βœ… Clear
“Lookup endpoint.” “Look up <entity> by <key>. Optionally filter by <fields>. Returns <fields>. Use this when the user asks <trigger>.”
“Creates a record.” “Create <entity> from <required fields>. Use only when the user explicitly asks to create one. Returns a confirmation carrying the new id.”

Tips: - Mention what it returns, field by field, so the model knows this tool can answer the question in front of it. - State negative space (“only when the user explicitly asks for it”) to stop premature or accidental calls β€” especially for writes. - Don’t dump implementation details (DB, framework). The model doesn’t care and it wastes the context the model reasons over.

4.3 Input schema = the argument contract

Every property description is a hint the model uses to fill that field. Be concrete about format, because the model will copy your wording.

  • Formats: "Date, YYYY-MM-DD." and "Local start time, 24h HH:MM." make the model emit 2026-06-11 and 16:00 instead of "next Tuesday" or "4 PM".
  • required: list the fields the call cannot work without. The model will keep asking the user until it has them.
  • Defaults & bounds: a numeric field carrying default, minimum, and maximum can be omitted by the model, and bad values are rejected before they reach your server.
  • Enums are powerful: {"type":"string","enum":["confirmed","tentative"]} constrains the model to valid choices.
  • Keep it flat and small. Deeply nested input is harder for the model to fill reliably.

4.4 Output schema = how the model reads the result (and why you were asked to add it)

After the call, the model reads your JSON response. The output schema tells it what fields exist and what they mean, so it can:

  • pull the right value into its reply (e.g. surface a link field as a clickable link, or read a message field back verbatim);
  • understand types (that a count is a number, that a tags field is a list);
  • avoid hallucinating fields that aren’t there.

Describe each output field the same way you describe inputs. Noting that a link field is string | null, or that a status field distinguishes a completed write from a simulated one, is what lets the agent phrase its confirmation honestly instead of overstating what happened.

4.5 Golden rule


5. Safety & UX knobs

Knob What it does Use it for
Secret type (API_KEY / Bearer / None) Auth header injected at call time, stored encrypted Keep your endpoint private; never put keys in the description
Panel scoping A CallFunc only exists in the panels you add it to Hide booking tools until the user is in a “booking” state

6. Troubleshooting

Symptom Likely cause Fix
The model never calls the tool Description too vague / overlaps another tool Rewrite the description with a clear “use this when…” trigger; make names distinct
The model calls it with wrong args Field descriptions unclear, missing formats/enums Add description, formats, enum, required, defaults
The model repeats a write or loops The description never says when not to call Tighten the description’s negative space; scope the tool to the panel where it belongs
Public URL 404/timeout The base URL moved, or the server is down Re-check the OutboundAPI base URL, and that the host is reachable from outside your network

7. What Perxona CallFunc gives you

Everything above is the contract you write. This is what the platform does with it, and where the approach stops.

What you get

  • No code to write or host. Any HTTP API becomes a tool by pasting a base URL and a JSON Schema. An existing backend turns into agent tools in minutes, with no adapter service standing between the two.
  • Batteries included. Encrypted secrets, per-tool usage limits, human-in-the-loop confirmation, context templating, text-to-SQL safety, logging, and multi-tenant scoping all come with the platform.
  • Tight product integration. Tools live inside the persona and storyboard flow and can be panel-scoped β€” available only in the conversation state where they make sense β€” and they ride the same pipeline as memory, guardrails, and the conversation transcript.
  • Output schema as a first-class field. You declare what comes back, which helps the model interpret results and keeps its replies honest about what actually happened.

Where it stops

  • One HTTP round trip. No streaming, no long-running jobs, no stateful tool sessions.
  • Configured ahead of time. Tools are set up in the console; there is no discovery at runtime. Changing a tool means editing it there.
  • You host the endpoint. It has to be reachable from Perxona, and its uptime, latency, timeouts, and TLS are yours.
  • JSON Schema, kept simple. Input and output use JSON Schema (Draft 2020-12); very exotic schema features may not convert cleanly. Flat and simple is better for the model anyway.

8. One-page recap

  1. Two objects: one OutboundAPI (URL + API key) + one CallFunc per function (name, description, method, path, input schema, output schema).
  2. The model only sees name + description + input schema + output schema β€” write them for a smart stranger.
  3. Description = what it does + when to use it (+ what it returns, + what NOT to do).
  4. Input schema = field names, types, required, formats, defaults, enums.
  5. Output schema = what comes back, so the model reads results correctly.
  6. It’s HTTP + managed guardrails, no code β€” an endpoint you can already call becomes a tool the agent can use.