Personas
A caller a model plays: a goal, a manner, what it expects of the agent, how it acts on the line; Pinecall's library, and callers written for you.
A persona is a caller a model plays: a goal, a way of speaking, the facts they know about themselves, what they expect of the agent — and, on a spoken call, how they act on the line. It improvises every turn, so it finds the conversations you did not think to write as goldens.
What is a persona?#
A persona belongs to one agent and is kept by the gateway, the same in sandbox and production. Two agents of
one org can each have a caller with the same name. Your repository holds none of them: you write them with
pinecall personas or on the console's Harness ▸ Personas screen, and no deploy is needed. Pinecall's own
library of callers comes first in every list, each one off until you switch it on.
expected-outcome.
How they actCallers that interrupt, hesitate, or ring from a bad line.
Written for youThe judge model writes callers from what the agent is.
Pinecall's library#
Every agent's list starts with Pinecall's personas, each off until pinecall personas on <name> — or the
switch on the console — turns it on for that agent (the org's switch is the default, the agent's wins).
The nightly plays what is on. One of them is never written nor dropped: write your own under another name.
| tag | personas | what they test |
|---|---|---|
| realism | in-a-hurry, wrong-number, non-native, interrupts, changes-mind, elderly-slow, angry-repeat-caller, asks-for-a-person |
the calls a real day brings: haste, confusion, a second language, a caller who talks over the agent, who changes their mind, who needs it twice, who is furious, who wants a person |
| red-team | prompt-leak, data-leak, off-task, harmful, unauthorized-action |
the calls somebody makes on purpose: the prompt asked for, another customer's details, help with something else, something dangerous, an action the caller may not take |
Each comes with what it expects of the agent, and some with how they act on a spoken line:
interrupts talks over 60% of the agent's answers, in-a-hurry and angry-repeat-caller 30%,
elderly-slow leaves 2.5 s before each line and non-native 1 s. pinecall personas show interrupts prints one whole.
Write one#
pinecall personas add hurried \
--about "Calls from the street, in a rush" \
--goal "move the appointment to Tuesday afternoon without giving more details than needed" \
--style "short sentences, interrupts, gives one fact at a time" \
--fact "their name=Ana García" --fact "their phone=600 000 001" \
--expect "The agent should offer a time on Tuesday afternoon." \
--expect "The agent should confirm the new time before moving the appointment." \
--interrupts 0.3 --pause 1
| flag | what it is |
|---|---|
--goal |
what the caller wants from the call. Required |
--style |
how they talk. Required |
--about |
one line about who they are |
--fact 'what=said' |
a fact they know about themselves, repeatable |
--llm |
the model that plays them: vendor/model, a vendor, a model, or haiku, sonnet, opus |
--tts, --voice |
the vendor and voice their lines are read in on a spoken call |
--expect '…' |
one thing the agent should do, repeatable; see below |
--tag x |
a word to find them by, repeatable |
--interrupts 0–1, --pause s |
how they act on a spoken line; see below |
A name is lower-case letters and digits joined by hyphens: hurried, price-shopper. A vendor or a voice
Pinecall does not have is refused when you write it, not in the middle of a run.
pinecall personas # one line each: name, style, goal
pinecall personas show hurried # the whole caller, what it expects and how it acts
pinecall personas edit hurried --llm haiku
pinecall personas rm hurried
In a project with several agents, add --agent <name> to say whose callers you mean.
What they expect of the agent#
--expect lines are the caller's own pass mark: one verifiable demand each, written "The agent should …",
about something the agent's prompt or knowledge says it can do — never about how the call ends. At hang-up,
the library's expected-outcome judge reads the whole call against
them, each line graded yes, no, or blocked (the call never got that far):
| answer | means |
|---|---|
held |
every line is yes |
broken |
a line is no |
na |
every line is blocked |
The reason gives each line its answer and the line of the call that decided it. The lines are never told
to the model playing the caller: a caller that knows its pass mark plays to it. The judge is a separate
model call, never the one that played the caller. They travel on the call itself (call.started.expects),
so a call is judged by what it was made under even after you edit the persona. A persona that expects
nothing gets na from expected-outcome without a model being asked.
How they act on a spoken line#
On a spoken call the caller does more than talk. --interrupts 0.3 makes it talk over that share of the
agent's answers — a second or two in, as a person cutting in does, never at the first word — so the agent's
barge-in is tested for real: did it stop, did it pick up what the caller said, did it lose the thread.
--pause 2 leaves two seconds of silence before each of its lines: a caller who thinks, or looks for a
paper. A persona may also carry its own line noise (interferer_db, packet_loss), which
pinecall simulate --background-noise and --packet-loss override for one call. A written call ignores
all of it.
Run it#
pinecall simulate --persona hurried # a written call, printed as it happens
pinecall simulate --persona hurried --judge # ...then every judge's verdict
pinecall simulate --persona hurried --voice # a spoken call on a real line
pinecall personas try hurried # the same as simulate, without --judge
| flag | what it does |
|---|---|
--judge |
waits for the call to be judged and prints each verdict and what judging cost. Exits 1 when a judge answered broken |
--turns <n> |
how many lines the caller improvises before hanging up. Default 15 |
--voice |
a real spoken call: a room, the agent dispatched into it, the caller read out loud |
--listen |
plays the call on this machine's speakers while it happens. Turns --voice on |
--background-noise <dB> |
a television behind the caller, that many dB under them. Spoken calls only |
--packet-loss <share> |
that share of the caller's packets never arrive, from 0 to 1 (0.02), as pinecall test --voice takes it. Spoken calls only |
You can also run a persona from the console's Harness ▸ Simulations screen.
How a persona is played#
Every caller line is one request to a model on the gateway: the persona's own --llm, or the gateway's
default model. On a spoken call, the caller speaks in the persona's own --voice when it set one, else in a
voice from the operator's list for the agent's language, never the voice the agent uses, so you can tell
the two sides apart by ear. The caller waits for the agent's opening before its first line.
A spoken caller's lines and voice are paid for by the platform, so each call has a spending ceiling; the caller hangs up when the call reaches it, and the answer says so.
Callers written for the agent#
pinecall personas generate 3 --about "price questions"
pinecall personas generate --template in-a-hurry --save
pinecall personas generate --from-call call_29d7c7
The judge model reads what the agent is — its prompt as its newest call ran it, its tools, its knowledge —
and writes callers for it, each with what it expects. --about steers them, --from-call makes them like
a real call's caller, --template writes one of Pinecall's again for this agent. They are printed and saved
nowhere; --save keeps every one as the agent's own, and the console's Generate… lets you keep them one
by one. Each caller written is one eval — none when your judges run on your own key.
Personas in files#
Older projects kept personas as files in test/<agent>/personas/. pinecall personas push sends them to the
gateway once, as that agent's callers, along with the state a known caller's call opens in. It stops at the
first caller the gateway refuses and names what landed and what is still only a file. The files are yours to
delete afterwards.