@talqing/mcp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/SKILL.md ADDED
@@ -0,0 +1,1270 @@
1
+ ---
2
+ name: talqing
3
+ description: >-
4
+ Build, publish and operate Talqing AI voice, video and text agents — agent
5
+ config and model stack, custom tools and their operation trees, MCP and
6
+ messaging integrations, knowledge bases, phone numbers, secrets and webhooks,
7
+ plus placing calls and reading back transcripts, cost and latency. Use
8
+ whenever working against a Talqing workspace through the talqing MCP server.
9
+ ---
10
+
11
+ <!-- Generated by openapi/export.py from backend/services/copilot/skill.md. Edit that file, then re-run the export. -->
12
+
13
+ # Building agents on Talqing
14
+
15
+ Talqing is a no-code builder for AI voice, video and text agents. Everything you
16
+ can build here you could otherwise have written as a LiveKit agent by hand: a
17
+ model stack, a system prompt, callable tools, knowledge, and lifecycle hooks.
18
+ The same machinery also runs **agent tasks** — an agent nobody talks to, which
19
+ takes named inputs and returns a typed result.
20
+
21
+ The same surface takes an agent all the way to production: give it a phone
22
+ number, run it, and read back every call it handled.
23
+
24
+ You reach the platform through one operation per API endpoint. Each operation's
25
+ arguments mirror its HTTP call — path and query parameters at the top level, the
26
+ request body under `body`. Every operation acts as the signed-in user, inside
27
+ their workspace only, with their role's permissions. Managing who is in the
28
+ workspace is the one thing that stays in the dashboard.
29
+
30
+ ## What an agent is
31
+
32
+ An agent is a single object, `config`, plus what you attach to it:
33
+
34
+ - **`name`** — unique in the workspace.
35
+ - **`channel`** — `voice` (phone/web call), `video` (a voice agent wearing an
36
+ Anam avatar) or `text` (chat). The channel decides which model slots exist.
37
+ - **`prompt`** — the system prompt. This is where the agent's behaviour lives.
38
+ - **`greeting`** — the line spoken on connect. Voice and video only.
39
+
40
+ Both are personalized per session: `{{userdata.field}}` is substituted from
41
+ the session's userdata when the agent starts, so *"You are speaking with
42
+ {{userdata.name}}, a {{userdata.tier}} customer"* becomes a real sentence on
43
+ the call. A field that is not in userdata resolves to nothing, so write the
44
+ prompt so it still reads if one is absent. `{{args.…}}` and `{{secrets.…}}`
45
+ are rejected here — those belong to a tool call.
46
+
47
+ A token whose root is not one of ours is an **error**, not text: a bare
48
+ `{{name}}`, a `{{customer.number}}` pasted from another platform, or a typo
49
+ like `{{userdate.name}}` is refused when the agent is saved. Rewrite each one
50
+ onto a real root rather than leaving it in.
51
+
52
+ Two more roots are filled in from outside the session, and nothing inside one
53
+ can write either. They differ in who fills them.
54
+
55
+ **`{{system_vars.…}}` — ours.** Six keys, and any other is rejected at save;
56
+ `GET /v1/catalog` returns them as `system_vars`.
57
+
58
+ - `{{system_vars.human_phone_number}}` — the other party, the caller inbound
59
+ and the person you called outbound
60
+ - `{{system_vars.agent_phone_number}}` — your number on this call
61
+ - `{{system_vars.direction}}` — `inbound` or `outbound`
62
+ - `{{system_vars.now}}` — `2026-08-19T19:26:59+05:30`, the machine format;
63
+ send it to an API, never read it aloud
64
+ - `{{system_vars.date}}` — `Wednesday, 19 August 2026`
65
+ - `{{system_vars.time}}` — `7:26 PM`
66
+
67
+ The first three come from the call, so they are empty on web calls and on text
68
+ conversations — do not make one the only source of a fact the agent needs. One
69
+ agent can greet a caller and someone it called differently by branching on
70
+ `{{system_vars.direction}}`. The last three come from the agent's
71
+ **`timezone`** and work on every channel; using one without setting `timezone`
72
+ is a save error. In a prompt or greeting the clock is frozen at the moment the
73
+ agent started (re-resolving would throw away the model's prompt cache); inside
74
+ a tool it is the moment the tool ran.
75
+
76
+ **`{{vars.…}}` — the tenant's.** The agent's own **`vars`** declares them, and
77
+ the request that starts a session supplies values that override the declared
78
+ defaults. See **`vars`** below.
79
+ - **`llm`, `stt`, `tts`** — `{provider, model}` from the provider catalog. Text
80
+ agents have only `llm`; voice and video need all three.
81
+ - **`language`** — the one language the caller and the agent speak, shared by
82
+ every model. `null` is Auto. Voice and video only.
83
+ - **`timezone`** — an IANA name such as `Asia/Kolkata`. What the three
84
+ `{{system_vars.…}}` clock variables resolve against, on every channel. `null`
85
+ until one of them is used, and then required. Set it whenever the agent has to
86
+ reason about opening hours, "today", or an appointment time.
87
+ - **`vars`** — the variables this agent reads as `{{vars.name}}`, each
88
+ `{name, description, default, required}`. Names are `[A-Za-z_][A-Za-z0-9_]*`
89
+ and unique within the agent; `default` is a string or `null`.
90
+
91
+ Values arrive on the **request that starts the session** — `vars` on
92
+ `calls_token`, `create_outbound_call`, `create_call_batch` or
93
+ `create_text_conversation` — and override the defaults. One bag per session,
94
+ reaching *every* agent on it: the entry agent, every team member, and a handoff
95
+ target that was never in the plan, each merged over its own declared defaults.
96
+ Nothing inside the session can write it.
97
+
98
+ Four things to get right:
99
+
100
+ - **They are visible to the model.** Anything in `vars` may be read aloud or
101
+ repeated back. A credential belongs in a workspace secret, read as
102
+ `{{secrets.NAME}}` from a tool, where the model never sees it.
103
+ - **`required: true` refuses the session** that supplies no value for a
104
+ variable with no `default` — the call token, the dial, the batch and the text
105
+ conversation, before anything is compiled and before any provider is called.
106
+ An empty string counts as a value; a `default` satisfies it outright. Nothing
107
+ is enforced once a session is connected, so a handoff target that needs a
108
+ value nobody supplied reads it as empty rather than ending the call.
109
+ - **An inbound call or message has no request of ours**, so only the declared
110
+ defaults resolve — which makes the rule above a hard one for inbound voice: a
111
+ voice agent that requires a variable with no default cannot answer a phone
112
+ number at all, and assigning the number, publishing that config under one
113
+ already assigned, and rolling back to it are all refused. Anything an inbound
114
+ session needs has to have a default.
115
+ - **`agent_override.vars` means something different**: it changes an agent's
116
+ *declarations and defaults* for one call. The top-level `vars` on the same
117
+ request supplies *values*. Both can appear on one call and they do not
118
+ conflict — the override decides what is declared, the top-level bag what it
119
+ is worth.
120
+
121
+ Reading `{{vars.x}}` where `x` is not declared is a **warning**, not an error:
122
+ the key space is open, because an agent or a tool defined inline in the same
123
+ request may legitimately read one nothing declared beforehand.
124
+
125
+ Prefer `userdata` for facts about the *person* and `vars` for configuration of
126
+ the *session*. `userdata` is merged onto the caller's contact record, replayed
127
+ into their next conversation, and writable by any tool; `vars` is none of those.
128
+ - **`avatar`** — video only: `{provider, model, avatar_id, name}`.
129
+ - **`turn_handling`** — turn detection, endpointing, interruption and preemptive
130
+ generation. Voice and video only.
131
+ - **`background_audio`** — ambient and thinking sounds mixed into the agent's
132
+ output. Any transfer stops the ambient bed while the caller waits and plays
133
+ hold music instead, so `ambient: hold_music` only sets how loud that is.
134
+ - **`noise_cancellation`** — cleans up the caller's audio before the agent hears
135
+ it: `{enabled, provider, model, enhancement_level}`, `provider`/`model` from
136
+ the catalog. Off unless asked for, and it needs that provider's key under
137
+ BYOK. `enhancement_level` runs 0.0–1.0; 0.5 is conservative, 0.8 is the
138
+ default, 1.0 suppresses interfering speech hardest. Voice and video only.
139
+ - **`tools`** — published tools the agent's LLM may call mid-conversation, each
140
+ `{"tool_id": "...", "tool_version": null}`. Write `tool_version` as null (or
141
+ leave it out): a draft tracks whatever is published now, and publishing fills
142
+ the version in.
143
+
144
+ An entry may instead carry `{"tool": {name, description, json_schema,
145
+ operations, …}}` — a whole tool written inline. On an agent that is a
146
+ *shorthand*, not a second kind of tool: `create_agent` and `update_agent`
147
+ create it, publish v1 and store `{"tool_id": "..."}` in its place, so the
148
+ agent and its tools can be built in one request. Use it for exactly that.
149
+ Attaching an existing tool is still `tool_id`.
150
+ - **`kb_ids`** — ready knowledge bases for grounded answers.
151
+ - **`mcps`** — external MCP servers whose tools the agent may call, each
152
+ `{"integration_id": "..."}` naming an active, MCP-capable integration. Which
153
+ of a server's tools may be called is the integration's own `allowed_tools`,
154
+ not this list. As with `tools`, an entry may instead carry `{"mcp": {name,
155
+ url, headers, allowed_tools}}`, which is created as a `custom_mcp` integration
156
+ and replaced by its id.
157
+ - **`handoffs`** — where this agent may pass the conversation next, each
158
+ `{"name": "Billing", "agent_id": "...", "description": "...", "context":
159
+ "transcript" | "summary" | "none", "recent_turns": 2, "summary_prompt": "...",
160
+ "message": "..."}`. The compiler turns each entry into one tool the model can
161
+ call, `handoff_to_<name>`, and the model routes on `description` — so write
162
+ that as what belongs there ("invoices, refunds, payment questions"), not as an
163
+ instruction.
164
+
165
+ **This is how you build a multi-agent flow.** Do not create a one-node tool
166
+ per edge: three agents routing to each other is three agents with `handoffs`
167
+ on them, not three agents plus six published tools. The `handoff` *operation*
168
+ is still right for a CONDITIONAL handoff — look the account up, and *if* it is
169
+ enterprise, hand to the enterprise desk — because that decision belongs in an
170
+ operation tree rather than to the model.
171
+
172
+ `agent_id` names a stored agent, entered at its latest published version.
173
+ Leaving it out resolves `name` against the team defined on the call that runs
174
+ the agent, which publishes with a warning rather than an error.
175
+
176
+ **`context` is what the next agent starts from** — the same three words an
177
+ agent's own `conversation.context` uses for what a new *call* starts from.
178
+
179
+ - `transcript` (the default) hands over everything said so far. Nothing to
180
+ configure, and the target pays for all of it on every turn it then takes.
181
+ - `summary` asks THIS agent to write the summary itself, as an argument on the
182
+ `handoff_to_*` tool, in the same turn as the decision to hand over. There is
183
+ no second LLM call, so a realtime agent can use it too. It costs a pause
184
+ before the handoff — the agent writes 60–100 tokens before the tool returns
185
+ — and buys a short, focused context that the source agent chose, instead of
186
+ forty turns the target has to re-read every turn.
187
+ - `none` starts the target with only its own instructions.
188
+
189
+ **`recent_turns`** (1–10) is how many recent turns cross *verbatim* alongside
190
+ the summary, so the target knows what is being asked right now. A turn starts
191
+ at a user message and runs until the next one, so a turn that took a tool call
192
+ and two replies crosses whole. Tool calls themselves never cross — their
193
+ results are knowledge, and knowledge belongs in the summary.
194
+
195
+ Leave it out and each policy answers for itself: `summary` carries two turns,
196
+ and `none` carries none. Under `summary` the tail can be sized down to one turn
197
+ but **not** switched off — a summary with no tail leaves the target knowing the
198
+ history and not the question. Under `none` it is opt-in, and `{"context":
199
+ "none", "recent_turns": 3}` is a real and useful combination: the last three
200
+ turns and nothing else. Past ten turns the honest answer is `transcript`.
201
+
202
+ **`summary_prompt`** replaces the platform's default line with your own. It is
203
+ the *description of the tool argument*, so it is literally what the agent is
204
+ asked to write. It takes `{{userdata.…}}`, `{{system_vars.…}}` and
205
+ `{{vars.…}}` like the description and the message do. The default is one line
206
+ naming three buckets — what the caller wants, what has been done, what is still
207
+ open — and a longer one buys a longer pause before the handoff.
208
+
209
+ `recent_turns` and `summary_prompt` are **rejected** where they do not apply,
210
+ rather than ignored: no `recent_turns` under `transcript`, which already
211
+ carries every turn, and no `summary_prompt` outside `summary`.
212
+
213
+ **`summary` is not a privacy boundary, and must not be described as one.** It
214
+ narrows what the target model is shown; it guarantees nothing. The tail always
215
+ crosses. `userdata` crosses regardless — it is session state every agent on the
216
+ call shares. The full transcript is still recorded and still displayed. A later
217
+ `transcript` hop shows that agent the whole call, including the part `summary`
218
+ scoped away. And the summary is written by an LLM the caller has been talking
219
+ to, so it is exactly as trustworthy as anything else the model says. The one
220
+ thing that does hold is that the source agent's raw tool results do not cross.
221
+ - **`conversation`** — what a new call knows about earlier ones with the same
222
+ person: `context` is `none` (the default — every call starts clean, though
223
+ earlier conversations are still saved against that caller), `summary` (the
224
+ agent is told, as background, what happened on recent ones) or `transcript`
225
+ (one long conversation across every call). `summary_limit` bounds how many
226
+ recent calls `summary` describes — leave it out for all of them — and
227
+ `initialize_userdata` decides whether the call also starts from what the agent
228
+ learned about this person before.
229
+
230
+ This is the answer whenever someone wants an agent to remember, or to forget,
231
+ earlier calls. **Never write that instruction into the prompt** — a model told
232
+ to ignore what is in its context is being asked to do the impossible, and a
233
+ model told to remember cannot see what was never loaded. Set the field.
234
+ `summary` needs call analysis with its summary switched on, and publish
235
+ refuses it otherwise. A text agent is always `transcript` and cannot be
236
+ changed: a chat thread has no boundary anyone would recognise.
237
+ - **`on_enter`, `on_exit`, `on_user_turn_completed`** — one such tool reference
238
+ each, run as lifecycle hooks.
239
+
240
+ ## Draft and published
241
+
242
+ Every write lands on the **draft**. Live traffic runs the last **published**
243
+ version, which is an immutable snapshot. Nothing you change reaches a real
244
+ caller until the agent is published.
245
+
246
+ The order that matters:
247
+
248
+ 1. Create or update the tool, including its operation tree.
249
+ 2. `validate_tool`, then `publish_tool`. Attaching an unpublished tool is
250
+ rejected.
251
+ 3. Attach it through the agent's `tools` or a hook.
252
+ 4. `validate_agent`, then `publish_agent`.
253
+
254
+ Publishing an agent pins each attached tool to the tool version that is live *at
255
+ that moment*. Republishing a tool therefore does not change live behaviour until
256
+ the agent is published again — say so rather than leaving the user to discover
257
+ it.
258
+
259
+ ## Writing config
260
+
261
+ `update_agent` and `create_agent` take the **whole** config, not a patch.
262
+ Anything you leave out reverts to its default — omitting `tools` detaches
263
+ every tool. Always read the current config first, apply your change to it, and
264
+ send the result back.
265
+
266
+ The config is validated on every write. Unknown models, a model that does not
267
+ support the channel, a language the model does not offer, a speed outside the
268
+ model's range, an unpublished tool, a knowledge base that is not ready — all are
269
+ refused with an explanation. Read the error and correct it; that is faster than
270
+ guessing.
271
+
272
+ Some fields are normalized for you. Switching to `text` clears `stt`, `tts`,
273
+ `greeting`, `turn_handling` and `avatar`. Switching to `video` fills in an
274
+ `avatar`, and always has `resume_false_interruption` off — the avatar cannot
275
+ resume a sentence it has already stopped rendering.
276
+
277
+ ### Choosing models
278
+
279
+ `get_catalog` is the only source of valid `provider`/`model` pairs, and it also
280
+ states what each entry supports: which channels, its language codes and default
281
+ language, whether it accepts a speed and within what range, and its default
282
+ voice. Read it before choosing; do not assume a model exists.
283
+
284
+ ### Images
285
+
286
+ People can attach a photo to a web chat, a web voice call or a web video call,
287
+ and the agent sees it. **There is no setting for this** — whether an agent can
288
+ read images is decided by the model it runs, and `vision` on that model's catalog
289
+ entry is where it says so. Every LLM entry today reads images; the two
290
+ `grok-voice-*` realtime entries do not, and an agent on one of them cannot be
291
+ sent a photo at all. If a user wants image input, check `vision` before picking
292
+ the model rather than changing anything on the agent.
293
+
294
+ A phone call carries no files, so this is web only.
295
+
296
+ ### Vision input (screen share)
297
+
298
+ `vision_input` is what the agent *watches* during a call, as opposed to the
299
+ images people send it. Do not confuse it with `vision` on a catalog entry: that
300
+ is what the model *can* do, measured and not configurable, and it is the
301
+ precondition for this.
302
+
303
+ `vision_input.screenshare.enabled` lets the agent see the caller's screen while
304
+ they share it. On each of their turns the agent is handed the single newest
305
+ frame and only that one, so a long call does not grow slower or more expensive —
306
+ and when nobody is sharing, the agent is told so and asks rather than inventing a
307
+ screen. Set `vision_input.screenshare.record` as well to keep what was shared as a
308
+ 1 fps video beside the call recording, deleted under the same retention policy.
309
+
310
+ Four rules decide whether it can be turned on at all:
311
+
312
+ - **Web voice and video calls only.** A phone call has no screen to share, and
313
+ the same agent config over a phone number simply never offers it — no setting
314
+ changes, and the agent is never told it can see.
315
+ - **Cascade only.** Turning it on with `realtime` set is refused when the agent
316
+ is saved: a speech-to-speech model detects turns inside the provider's socket,
317
+ so there is no moment at which it could be handed a frame.
318
+ - **The model must read images.** Publish fails, naming the model, if the LLM or
319
+ its fallback has `vision: false`. Check `get_catalog` before choosing.
320
+ - **The caller's client has to publish a track.** Our dashboard's test call and
321
+ the TypeScript SDK's `useTalqingScreenShare` both do; a customer's own surface
322
+ has to call `getDisplayMedia` from a click, which is a browser rule nothing on
323
+ our side can work around. So the agent asking out loud is what starts sharing.
324
+
325
+ It also forces `turn_handling.preemptive_generation` off, because the frame
326
+ changes the context the speculative reply was generated against.
327
+
328
+ ### How long the model may think
329
+
330
+ **On a voice or video agent, give the model the least thinking it will accept.**
331
+ Every second of reasoning is a second of silence on a live call, and a caller who
332
+ hears nothing assumes the line has dropped. Take the **first** value in that
333
+ model's catalog `reasoning_efforts` list, or leave `reasoning_effort` unset —
334
+ the list is ordered fastest first, and unset already means that first value.
335
+ Raise it only when the user asks for it and accepts the pause, and tell them what
336
+ it costs them in silence.
337
+
338
+ Do not reason about the effort names, because they do not order the same way at
339
+ every vendor. `minimal` sounds like the floor and is not: on xAI's grok-4.3 it
340
+ burned *more* thinking than `low`, so `none` is the only setting there that
341
+ truly stops it. OpenAI rejects `minimal` outright and starts at `none`. The
342
+ catalog's order is measured; the names are marketing.
343
+
344
+ A text agent has no such pressure — nobody is listening to silence — so spend
345
+ thinking there freely when the task benefits from it.
346
+
347
+ Language is set **once**, on the agent: `config.language`. There is no language
348
+ field on `stt`, `tts` or `realtime`. Each model translates the agent's language
349
+ into its own spelling, so Hindi reaches Deepgram as `hi` and Sarvam as `hi-IN`
350
+ without you doing anything. Rules worth knowing before you hit them:
351
+
352
+ - Use a code that appears in some model's catalog languages; `null` means Auto.
353
+ - A model that publishes languages must be able to speak the one you chose, or
354
+ the write is refused. Prefer picking the language first, then models that
355
+ cover it.
356
+ - **A model with `language_required: true` refuses Auto**, because its API has no
357
+ detection to fall back on — Soniox TTS is like this, and an agent on it will not
358
+ publish until `config.language` is set. Every other model takes a null
359
+ `language`. On Soniox TTS the setting is not cosmetic: the code chosen is the
360
+ phonetic system the text is read through, so English sent as `es` comes out as
361
+ noise rather than accented English.
362
+ - **Auto is not detection on Raya.** None of its three entries detect anything;
363
+ they send their `default_language` (`en`) when the agent is on Auto. For a Raya
364
+ agent taking Indic calls, set `config.language` — Hindi audio transcribed as
365
+ English does not come back transliterated, it comes back with words missing, and
366
+ the agent never learns it misheard.
367
+ - **Auto does not mean "detects" everywhere.** A model with a `default_language`
368
+ runs on that code when the agent is on Auto, and the ones spelled `unknown`,
369
+ `multi` or `auto` are the providers' own words for detection. The rest are
370
+ real languages, and English is what a model that cannot detect falls back to:
371
+ `deepgram/nova-3` and both xAI speech-to-text models transcribe as English on
372
+ Auto and will mistranscribe a caller who speaks anything else. For an agent
373
+ taking non-English calls on Auto, pick `deepgram/nova-3-general` (`multi`),
374
+ `deepgram/flux-general-multi`, `sarvam/saaras:v3` (`unknown`), ElevenLabs
375
+ Scribe or OpenAI — all of which detect for real.
376
+ - Models that publish no languages (OpenAI TTS is multilingual, Deepgram encodes
377
+ the language in the voice) simply ignore the setting.
378
+
379
+ A catalog entry may carry a `note` — a caveat the *prompt* has to answer, not a
380
+ description of the model. Read it before writing the prompt and tell the user what
381
+ you did about it. No entry carries one today.
382
+
383
+ An STT entry with `streaming: false` transcribes each utterance in one request
384
+ instead of over a socket. That buys a lower price, and costs the round-trip:
385
+ the agent replies about half a second later than it would on a streaming model,
386
+ and word-count interruption stops working because there are no interim
387
+ transcripts. Prefer a streaming model unless price is the point.
388
+
389
+ `stt`, `llm` and `tts` each take an optional `fallback` — a second
390
+ provider/model the agent switches to mid-call if the primary starts failing.
391
+ Leave it unset unless the user asks for redundancy; it is not free to set up:
392
+ the fallback provider needs its own BYOK key before the agent will publish, and
393
+ a session that fails over is billed to both providers for the parts each one
394
+ served. The fallback must be a different provider/model from the primary, and it
395
+ cannot have a fallback of its own. A speech-to-text fallback must also match the
396
+ primary's `streaming` flag —
397
+ streaming backs streaming, batch backs batch — so end-of-turn timing stays the
398
+ same before and after a failover.
399
+
400
+ `llm.builtin_tools` — and `llm.fallback.builtin_tools`, separately — switches on the tools the model provider runs itself during
401
+ the reply — web search, X search, a code sandbox, a provider-side document
402
+ store. Each is `{type, config}`, and the *only* valid types and config keys are
403
+ the ones the chosen model's catalog entry lists under `builtin_tools`, so read
404
+ `catalog` before setting them. They are not Talqing tools: there is nothing to
405
+ create, publish or attach, and nothing runs on our side. Two things to tell the
406
+ user before switching one on — the provider bills per call, which our cost
407
+ estimate does not include; and the search or code run happens *before* the agent
408
+ speaks, which on a voice call is a few seconds of silence, so the prompt should
409
+ have the agent say it is looking something up. The failover model carries its
410
+ own list, set against its own catalog entry: the same tool name is a different
411
+ object at each vendor, so one model's settings are never copied to the other. A
412
+ failover with fewer tools (or none) is fine — it keeps the call and loses the
413
+ search, which is the right way round.
414
+
415
+ `catalog_voices` browses the voices for a provider — use it before picking a
416
+ voice by style, accent or gender. `catalog_avatars` is the face gallery for
417
+ video agents; an avatar's `id` becomes `avatar.avatar_id`, while `avatar.model`
418
+ comes from the provider catalog.
419
+
420
+ **Setting an ElevenLabs voice takes one more step.** After choosing the voice —
421
+ and, for a shared-library voice, after `add_elevenlabs_voice` has saved it — call
422
+ `elevenlabs_voice_settings` with the id you are going to use and copy the
423
+ `stability` and `similarity_boost` it returns onto the same `tts` object as the
424
+ voice. ElevenLabs applies a voice's own tuning only to a request that carries no
425
+ overrides at all, and Talqing always sends a speed, so a voice set without these
426
+ speaks in ElevenLabs' generic default instead of the voice its author shipped —
427
+ audibly, and with nothing to show why. They belong to that voice: replace them
428
+ whenever you change it, and clear them if you move to a model whose catalog entry
429
+ does not set `supports_voice_settings` (only ElevenLabs does), which agent
430
+ validation refuses outright.
431
+
432
+ ### Expressive delivery
433
+
434
+ `tts.expressive` lets the agent write delivery tags — a laugh, a whisper, a
435
+ pause before the key detail — into the words it speaks. Only for a model whose
436
+ catalog entry carries an `expressive` block; that block's `prompt` is what gets
437
+ appended to the agent's system prompt, and the tag vocabulary is inside it. Read
438
+ it before writing a tag anywhere yourself: the dialects differ per model, and a
439
+ tag from the wrong one is silently dropped rather than spoken.
440
+
441
+ It costs a little on both sides of a turn — the added prompt, and every tag the
442
+ model emits as billed output. Say so before switching it on.
443
+
444
+ Two rules the API enforces, both at publish:
445
+
446
+ - A fallback voice must match the primary's `expressive` setting. The dialect is
447
+ taught once, from the primary, and a failover happens mid-turn — so the
448
+ fallback has to be a voice that speaks tags too. In practice that means the
449
+ two dialect models back each other, or there is no fallback.
450
+ - Every handoff target of an expressive agent must use the **same** provider,
451
+ model and `expressive` setting. The target inherits a transcript full of tags
452
+ and starts writing its own; a voice that cannot speak them reads them out.
453
+ Handing off *into* an expressive agent is fine.
454
+
455
+ **Nothing validates a tag you write by hand** into a greeting, a `say` line or a
456
+ handoff message. On a voice with no dialect it reaches the caller as the word
457
+ itself, so do not put one there unless the agent's own voice speaks it.
458
+
459
+ ### Turn detection
460
+
461
+ **There is no setting for this.** What ends the caller's turn follows from the
462
+ speech-to-text model and `config.language`, so do not go looking for a knob and
463
+ do not promise the user one — change the models or the language instead:
464
+
465
+ - **Streaming speech-to-text** → its own end-of-speech detector ends the turn. It
466
+ can keep listening when it hears the caller is not finished, so
467
+ `endpointing.min_silence_duration` is the window it gets rather than the whole
468
+ wait, and its transcription round-trip lands on top. Deepgram Flux and Sarvam
469
+ Saaras endpoint on their own schedule and ignore that window entirely, so on
470
+ those two the setting is a floor.
471
+ - **Batch speech-to-text** (`streaming: false` — xAI `xai-stt-batch`, ElevenLabs
472
+ `scribe_v2`, OpenAI `gpt-4o-transcribe`) → it has no endpointer at all, so
473
+ LiveKit's audio end-of-turn model takes over when `config.language` is one of
474
+ the fourteen it was trained on: Arabic, Chinese, Dutch, English, French,
475
+ German, Hindi, Indonesian, Italian, Japanese, Korean, Portuguese, Spanish,
476
+ Turkish. It judges whether the *sentence* sounds finished, so it waits through
477
+ a caller who pauses mid-thought ("I need to think about that for… a moment").
478
+ Any other language, or Auto, falls back to plain silence.
479
+
480
+ So if the user complains the agent cuts people off mid-sentence, the lever is a
481
+ batch model plus one of those fourteen languages — that is the only pipeline that
482
+ hears meaning rather than silence. Otherwise raise
483
+ `endpointing.min_silence_duration` (minimum 0.25s).
484
+
485
+ `endpointing.max_silence_duration` is how long the agent waits when the end-of-turn
486
+ model says the caller is mid-thought, so it only does anything on that same
487
+ batch-plus-supported-language pipeline.
488
+
489
+ ### Video
490
+
491
+ `channel: "video"` is a voice agent wearing an Anam avatar. The avatar joins the
492
+ call as a second participant and lip-syncs to the agent's own audio, whichever
493
+ model produced it — so video runs on either pipeline, the STT-LLM-TTS cascade or
494
+ a realtime speech-to-speech model, and everything true of that pipeline on
495
+ `voice` stays true here.
496
+
497
+ A video agent needs both an avatar model and an `avatar_id` before it will
498
+ publish; `get_catalog` lists the avatar models and `catalog_avatars` the faces.
499
+ Avatar time bills per wall-clock minute for the whole call, idle included, on top
500
+ of whatever the models cost.
501
+
502
+ ## Tools
503
+
504
+ A tool is one capability the agent's LLM can call mid-conversation. It has:
505
+
506
+ - **`name`** — the function name the LLM sees. A valid identifier, snake_case,
507
+ describing the capability. `knowledge_fetch` is reserved.
508
+ - **`description`** — tells the LLM *when* to call it. This matters as much as
509
+ the implementation.
510
+ - **`json_schema`** — the arguments the LLM supplies. Declare only values the
511
+ agent can know or ask the caller for. **Give every property a `description`**:
512
+ it is the only instruction the agent's model gets on what to put there and how
513
+ to get it out of the conversation, and a bare `{"type": "string"}` is how a
514
+ tool ends up called with the wrong value. Mark the ones the tool cannot run
515
+ without as `required`, and use an `enum` wherever the set of values is closed.
516
+ - **`long_running_task`** — voice and video agents keep talking while it runs;
517
+ text agents wait for the result either way.
518
+ - **`silent`** — no immediate reply after it runs. You rarely need to set it: a
519
+ tool in which no operation can return a response (see below) is silent
520
+ automatically, and so is any run that reaches `end_call`.
521
+ - **`disable_interruptions`** — the caller cannot barge in while it works.
522
+ - **`operations`** — the tree that runs when it is called.
523
+
524
+ Prefer one meaningful business capability per tool over many thin ones.
525
+
526
+ ### The operation tree
527
+
528
+ `operations` is an ordered list. Sending it replaces the tree entirely, so
529
+ include every node you want to keep.
530
+
531
+ Each node is `{kind, config, on_error?}`, and `kind` decides the rest: an
532
+ operation is a union of eleven shapes, one per kind, each carrying only the
533
+ fields that kind has. `on_error` is `abort` (default) or `continue`.
534
+
535
+ `silent`, `publish_fields` and `background_execution` exist on `http`, `code` and
536
+ `frontend_rpc` and on nothing else, because those three are the only kinds that
537
+ produce a result — there is nothing for the other eight to hide, to publish out
538
+ of, or to stop waiting for. `then` and `else` belong to an `if` in the same way.
539
+ Sending one of them on a kind that does not have it is rejected, not ignored.
540
+
541
+ `silent: true` still runs the operation but hides its response from the agent's
542
+ LLM — use it for noisy intermediate steps.
543
+
544
+ **Silence is derived, not defaulted.** If no operation in the tree can return a
545
+ response, the tool is silent whatever `silent` says — including operations inside
546
+ `if` branches. So a tool that is just `say "Your appointment is confirmed"` says
547
+ that once, rather than saying it and then improvising a second sentence on top.
548
+ If the agent should add a closing line, add a `generate_reply` operation that
549
+ states what to add; do not try to turn the derived silence off.
550
+
551
+ **Templates.** `{{args.field}}` reads the tool's arguments, `{{tooldata.field}}`
552
+ this tool run's own state, `{{userdata.field}}` the session's state,
553
+ `{{system_vars.field}}` what the platform knows about this session,
554
+ `{{vars.field}}` what the tenant supplied for it, and `{{secrets.NAME}}` a
555
+ workspace secret. A string that is exactly one template token keeps the resolved
556
+ value's type. Every one of these works in a URL, in the query, in the body **and
557
+ in headers**. A token whose root is not one of those six is an error at save,
558
+ not text.
559
+
560
+ `system_vars` is read-only, and its six keys are the same ones the agent's prompt
561
+ reads: `human_phone_number`, `agent_phone_number`, `direction`, `now`, `date`,
562
+ `time`. So a tool can POST the caller's number to a CRM, stamp a record with
563
+ `{{system_vars.now}}`, or branch an `if` on the direction without the agent
564
+ having to ask. The phone-call keys are empty on web calls, on text conversations
565
+ and in a dashboard test run; the clock keys resolve wherever the agent has a
566
+ `timezone`, and read the time the **tool ran** rather than the time the call
567
+ started.
568
+
569
+ `vars` is read-only too: whatever the calling agent declares, with whatever the
570
+ request that started the session supplied merged over it — so
571
+ `https://{{vars.api_domain}}/book` is one tool serving every reseller, without a
572
+ copy of it per customer. A tool is workspace-level and does not know which agent
573
+ will call it, so a `{{vars.…}}` it reads is only checked against declarations
574
+ when an agent that attaches it is published.
575
+
576
+ Do not compare `{{system_vars.time}}` or `{{system_vars.date}}` in an `if`: `gt`
577
+ and `lt` need two numbers, so `"7:26 PM"` against `"09:00"` fails the operation
578
+ rather than quietly taking `else`. Business-hours logic belongs in a `code`
579
+ operation over `new Date(input.system_vars.now)`.
580
+
581
+ **The two stores.** `tooldata` is created empty every time the tool runs and is
582
+ gone when it returns — only later operations in the same tree can read it.
583
+ `userdata` belongs to the session: other tools, later turns and the agent's
584
+ prompt read it, and it is persisted with the call. Prefer `tooldata` for the
585
+ plumbing between two operations, and `userdata` only for what the conversation
586
+ should still know afterwards.
587
+
588
+ **Dataflow.** An operation's result is *not* automatically visible to the next
589
+ one. `http`, `code` and `frontend_rpc` may declare `publish_fields`, each
590
+ `{path, key?, store}`: `path` picks a value out of the response, `key` names it
591
+ (the last path segment when omitted), and `store` is `tooldata` or `userdata`.
592
+ `store` is required — it is the difference between a value that dies with the
593
+ tool and one the whole session carries.
594
+
595
+ `set_variable` writes one templated value directly, with the same required
596
+ `store`.
597
+
598
+ Reading `{{tooldata.X}}` when nothing earlier in the tool publishes `X` is an
599
+ **error** — tooldata starts empty, so that read can only resolve to nothing.
600
+ Reading `{{userdata.X}}` that the tool does not publish is only a **warning**:
601
+ X has to already be in session userdata, which means something else — the API
602
+ caller, an earlier tool — must put it there first. Say that in the agent's prompt.
603
+
604
+ **Kinds:**
605
+
606
+ Each kind's fields, their bounds and their defaults are in the schema; what
607
+ follows is what the schema cannot tell you. Every `timeout` is in **seconds**,
608
+ never milliseconds: the caller is on the line while an operation runs, so a long
609
+ timeout is a hung call rather than a patient one — reach for `long_running_task`
610
+ instead.
611
+
612
+ - **`http`** — calls a REST API. Expects JSON; a non-2xx status or a non-JSON
613
+ response fails the operation. Every root templates into headers as well as the
614
+ URL, query and body — but an `Authorization` built out of `{{args.…}}` is a
615
+ credential the *model* chose, so put credentials in `{{secrets.…}}`.
616
+ - **`code`** — TypeScript for transformations and shaping. `source_ts` must
617
+ `export default async function handler(input)`, where `input` is
618
+ `{args, tooldata, userdata, system_vars, vars, secrets}`, and return an object.
619
+ The sandbox has `console` and a guarded `fetch` for public http(s) URLs — no
620
+ Node APIs, no imports.
621
+
622
+ That input object is the whole interface: a code operation has **no template
623
+ syntax**. Write `input.system_vars.now`, never `{{system_vars.now}}` — braces
624
+ in the TypeScript are neither substituted nor flagged, so a `{{args.id}}`
625
+ inside a string literal ships to the tenant's API as literal braces. (This is
626
+ also the only place braces are allowed to survive, so a script that needs to
627
+ build a mustache template for something downstream can.)
628
+ - **`if`** — compares `left` with `right` and runs its `then` or its `else`.
629
+ Because an `if` is terminal in its chain, `on_error: "continue"` on one means
630
+ *neither branch runs and the tree ends there* — a real outcome to reach for,
631
+ and the only thing `continue` can mean on an operation nothing follows.
632
+ - **`set_variable`** — writes one templated value into `tooldata` or `userdata`.
633
+ - **`say`** — spoken verbatim.
634
+ - **`generate_reply`** — the LLM writes the reply.
635
+ - **`add_message`** — adds a system message without triggering a reply.
636
+ - **`end_call`** — put a `say` immediately before it if there should be a
637
+ goodbye, and word that goodbye as what actually happens: the call ends here.
638
+ Never say "let me transfer you", "please hold" or "someone will call you
639
+ back" before an `end_call` — the caller hears a promise and then silence. The
640
+ goodbye always finishes playing before the call drops, and the agent never
641
+ says anything after it, so `wait_for_playback` on that `say` is unnecessary.
642
+ - **`handoff`** — moves the call to another agent. `context` is `transcript`,
643
+ `summary` or `none` — the same three words as an agent's own
644
+ `conversation.context`, because it is the same question about the next agent
645
+ rather than the next call. A named
646
+ `target_agent_id` must already be published; `agent_name` resolves against the
647
+ team defined on the call. Handoff moves the call between **agents on this
648
+ platform**. To reach a *person*, use `transfer`.
649
+
650
+ `context: "summary"` **requires** a `summary`, and it is a value rather than a
651
+ request: this tree runs after the model's tool call, so there is no argument
652
+ being written at that moment to take one from. Point it at where the text comes
653
+ from — `{{args.summary}}` (a property on this tool's own `json_schema` that the
654
+ model filled), `{{tooldata.brief}}` (something an earlier `http` or `code` op
655
+ published), or fixed prose. There is no second LLM call either way. A `summary`
656
+ under any other context is an error.
657
+
658
+ `recent_turns` works exactly as it does on `handoffs[]`: the tail that
659
+ crosses verbatim, defaulting to two turns under `summary` and to none under
660
+ `none`, and rejected under `transcript`.
661
+
662
+ Reach for this operation only when the decision is the TREE's — after an
663
+ `http` lookup, inside an `if`. When the model should decide which desk the
664
+ caller wants, put the destinations on the agent's own `handoffs` field
665
+ instead: that is one line per edge rather than a tool with a lifecycle.
666
+ - **`transfer`** — hands the caller to a human being on `destination`, a literal
667
+ phone number in full international format (`+14155550101`). **Phone calls
668
+ only** — on a web or text session the operation fails.
669
+
670
+ The number is fixed at publish and is never templated or chosen by the model:
671
+ `{{args.number}}` is not accepted, and neither is a number the caller reads
672
+ out. If a user asks for either, say so plainly — it is a toll-fraud rule, not
673
+ an oversight.
674
+
675
+ How the caller is reached is the platform's business, not the builder's: we
676
+ dial the person into the call and step out. Do not offer a choice, and do not
677
+ mention SIP. One consequence is worth stating if a user asks about it: the
678
+ person answering sees the workspace's own number, not the caller's, because
679
+ the leg is dialled from the workspace's trunk.
680
+
681
+ `mode` decides what the *caller* experiences, and it is the only choice the
682
+ builder gets about how a transfer runs:
683
+
684
+ - **`cold`** (the default) — the agent finishes its line, then the caller
685
+ hears hold music for as long as the other phone takes to ring, and a person
686
+ answers. There is no introduction and no "let me hand you over to Sarah".
687
+ - **`warm`** — the caller goes on hold with hold music while the agent rings
688
+ the person on a separate line, tells them who is calling and what they want,
689
+ answers their questions, and only then puts the two together. The caller
690
+ hears none of the briefing. It costs a second AI conversation, which is
691
+ billed to the workspace like any other, and it takes as long as the briefing
692
+ takes — so it suits escalation to a colleague, not a busy queue.
693
+
694
+ Pick `warm` when the person answering needs context to be useful, or when the
695
+ user says "brief them first" / "don't just dump the caller on them". Pick
696
+ `cold` for a straight "put me through to sales". If the user has not said,
697
+ ask — the difference is a minute of hold music, and it is theirs to choose.
698
+
699
+ With `warm` the person answering can also **decline**, and then the caller
700
+ comes back to the agent and the call carries on. The agent is told why in
701
+ general terms; it never hears or repeats that person's own words.
702
+
703
+ `ringing_timeout` bounds the *ringing*, not a warm briefing. `on_failure` is
704
+ `continue` (the default: the agent is told
705
+ plainly why and keeps talking to the caller) or `end_call`. What the agent is
706
+ told is always plain English about the person being called — "the line was
707
+ busy", "nobody answered", "they aren't able to take the call right now", "the
708
+ call went through to their voicemail" — never a technical reason.
709
+
710
+ Put a `say` immediately **before** it if the caller should hear a line, and
711
+ don't bother with `wait_for_playback` — the transfer already waits for it to
712
+ finish. Unlike `end_call`, "let me transfer you" is a promise the platform can
713
+ keep, so say it here and never before an `end_call`. Word it for the mode:
714
+ before a `warm` transfer, "let me speak to them first and bring you in" is
715
+ true; before a `cold` one it is a lie.
716
+
717
+ Once the transfer succeeds this call is over as far as the platform is
718
+ concerned — the agent says nothing more, and the call's duration and recording
719
+ cover only the part the agent was on. On `warm`, the briefing itself is not
720
+ recorded either; it is kept on the call's timeline as a `transfer.briefing`
721
+ event so a workspace can review what was said about a caller.
722
+
723
+ **Multiple destinations: one tool per destination, not one tool that
724
+ branches.** `transfer_to_billing`, `transfer_to_sales`, `transfer_to_support`
725
+ — each argument-free, each one `say` and one `transfer`. The model then picks
726
+ a *tool*, which is the thing it chooses most reliably, every destination gets
727
+ its own name and description, and the tool list reads like the org chart.
728
+ Nesting five `if`s inside one tool is worse in every one of those respects.
729
+
730
+ **The tool's `description` is the escalation policy.** For every other kind a
731
+ weak description costs a mis-timed API call; here it decides whether a
732
+ frustrated caller reaches a person. "Transfer to a human" invites the model to
733
+ escalate at the first sign of difficulty. "Use only after you have tried to
734
+ answer the question and the caller has asked for a person, or is clearly
735
+ distressed" is a policy. Ask the user *when* escalation should happen rather
736
+ than assuming, and write the second kind.
737
+
738
+ Tick tool-level `disable_interruptions` on a transfer tool, so the caller
739
+ cannot talk over "connecting you now" and turn a waited line into an
740
+ interrupted one. Two shapes it cannot have: the tool may not be
741
+ `long_running_task`, and it may not be a lifecycle hook — both are refused at
742
+ publish, because the handover has to happen inside the turn that asked for it.
743
+ - **`frontend_rpc`** — awaits a handler on the connected web client and can
744
+ publish from its response.
745
+
746
+ `background_execution: true` on `http`, `code` or `frontend_rpc` fires and
747
+ forgets — no response, so no `publish_fields`.
748
+
749
+ **`wait_for_playback`** (on `say` and `generate_reply`) holds the
750
+ tree until that line has finished playing. Leave it off — the usual `say` is a
751
+ filler that exists to *cover* the next operation's latency ("let me pull that up
752
+ for you" → `http` → "your balance is …"), and waiting there lengthens every call
753
+ for nothing. Tick it only when the caller must have heard the line before the
754
+ next operation runs: a disclosure before a recording starts, or a promise before
755
+ a side effect they might still retract. Two things to know before relying on it:
756
+ the wait also covers whatever the agent was already saying in the same turn (so
757
+ on a filler it can stall the call for several seconds), and an interrupted line
758
+ counts as finished — it is not proof the caller heard it. Pair it with tool-level
759
+ `disable_interruptions` when that matters.
760
+
761
+ **The branching rule.** `if`, `handoff`, `end_call` and `transfer` are terminal
762
+ in their chain, and a chain is the top-level list or any `then`/`else` list.
763
+ Nothing may follow them there, and branches do not rejoin. If work must happen after a branch,
764
+ duplicate it into both branches or move the branch later. For an early-exit guard,
765
+ put the rest of the flow inside the guard's `else`. Anything the tool has to do
766
+ before hanging up — logging the outcome, posting a lead — goes **before** the
767
+ `end_call`, not after it: the session is already closing by then.
768
+
769
+ ## Lifecycle hooks
770
+
771
+ Each hook points at a **published tool id**, or null.
772
+
773
+ - **`on_enter`** — a session opens. On voice and video it runs alongside the
774
+ greeting on first entry; on text, when the conversation window opens. Handoffs
775
+ skip the greeting.
776
+ - **`on_exit`** — the session closes: call end or handoff on voice and video;
777
+ on text, `end_call`, a closed window, or about a minute idle.
778
+ - **`on_user_turn_completed`** — after every user turn, before the LLM replies.
779
+ Each spoken turn on voice and video, each inbound message on text. The user's
780
+ words arrive as `{{args.user_message}}`. On an agent with
781
+ `vision_input.screenshare` on, the newest frame of the shared screen is already
782
+ in the context this hook runs against, so anything the tool adds lands after
783
+ it.
784
+
785
+ ## Agent tasks
786
+
787
+ An **agent task** is an agent nobody talks to. Same prompt, same model, same
788
+ tools, same MCP servers — minus every conversational organ (speech, greeting,
789
+ turn-taking, handoffs, knowledge bases), plus the one thing a conversation
790
+ cannot have: a **typed structured output**. It takes named inputs, does some
791
+ work, and returns a value. `POST /v1/tasks/{task_id}/runs` runs one and waits.
792
+
793
+ It is its own noun with its own operations (`list_tasks`, `create_task`,
794
+ `get_task`, `update_task`, `delete_task`, `run_task`, `list_task_runs`) — not a
795
+ fourth agent channel. Use one wherever the work has an input and an answer
796
+ rather than a conversation: research a company from a domain, classify a
797
+ message, draft an opening line, pull a field out of a document.
798
+
799
+ `config` is:
800
+
801
+ - **`name`** — unique in the workspace.
802
+ - **`prompt`** — the system prompt, and the whole of the task's behaviour. It
803
+ reads `{{vars.name}}` for the values the run was given, and
804
+ `{{system_vars.now}}` / `.date` / `.time` when `timezone` is set. It does
805
+ **not** read `{{system_vars.human_phone_number}}` / `.agent_phone_number` /
806
+ `.direction` — there is no call.
807
+ - **`llm`** — one model, with the same `fallback`, `reasoning_effort`,
808
+ `priority` and `builtin_tools` an agent's LLM has. There is no `stt`, `tts`,
809
+ `realtime`, `greeting`, `turn_handling`, `avatar`, `handoffs`, `recording`,
810
+ `analysis`, `kb_ids` or lifecycle hook — a task has nobody to hear, nobody to
811
+ greet, nothing to hand over and one turn to hook.
812
+ - **`tools`** / **`mcps`** — exactly an agent's, attached by id or defined
813
+ inline. **A task never pins a tool version**: republishing a tool changes
814
+ every task that uses it, immediately, with no step in between. That is
815
+ defensible for a bounded job and would not be for a live call, which is why
816
+ agents pin and tasks do not.
817
+ - **`vars`** — the task's **inputs**, declared exactly as an agent's variables
818
+ are: a `name`, a `description`, an optional `default` and `required`. A run
819
+ supplies values by name; one it omits falls back to the `default`, and a
820
+ `required` variable with neither is refused *before* anything is compiled, so
821
+ that failure costs nothing. A value for a name the task does not declare is
822
+ refused too, rather than silently dropped — which is the one difference from an
823
+ agent, whose key space is open.
824
+ - **`output`** — a flat list of the fields the model must produce, each with a
825
+ `name`, a `type` (`string`, `boolean`, `integer` or `number`) and a
826
+ `description`. At least one, at most 25. No arrays and no nested objects: a
827
+ task that wants to return five talking points returns one string containing
828
+ them.
829
+ - **`max_steps`** (default 25, max 50) — how many LLM → tools → LLM **rounds**
830
+ the run may take. A round, not a tool call: four tools in one reply cost one
831
+ step. This is the runaway-loop guard.
832
+ - **`timeout_seconds`** (default 120, max 600) — the real time budget.
833
+
834
+ A name may not appear in both `vars` and `output`: a run's inputs and its output
835
+ are read side by side, so a collision would make one of the two unreachable.
836
+
837
+ **There is no draft and no publish step.** One config, strict at save: an
838
+ invalid one is refused with a 400 listing every problem and nothing is stored,
839
+ so a task that exists can always run. An edit takes effect on the next run with
840
+ nothing in between — there are no versions, so there is no earlier wording to go
841
+ back to and nothing records which definition produced an earlier run.
842
+ `create_task` and `update_task` also return **`warnings`**: the problems that
843
+ are real but not fatal, such as a prompt reading a variable nothing declares.
844
+ There is no publish screen to show them on, so read them where they are.
845
+
846
+ ### The output tool
847
+
848
+ The model does not "return" the output. At compile time the task gains one
849
+ generated tool, **`submit_result`**, whose arguments are exactly the `output`
850
+ fields, and one generated paragraph telling it that calling that tool is how the
851
+ run finishes. Both are written for you: never declare a tool named
852
+ `submit_result`, and never write that paragraph into the prompt yourself.
853
+
854
+ Every output field is **required and nullable** in that tool. The model must say
855
+ something about every field, including "I could not find it" — an optional field
856
+ lets it silently omit the address it failed to find, and "omitted" and "not
857
+ generated yet" then look identical to whoever reads the row. Say so in each
858
+ field's `description`: that description is the only instruction the model gets
859
+ about what belongs there.
860
+
861
+ ### Reading a run
862
+
863
+ `run_task` **executes for real**: the tools call the tenant's endpoints with
864
+ their secrets, the MCP servers spend their credits, and the model spends their
865
+ tokens. A task that books, charges or sends will do so.
866
+
867
+ The response is the whole run — `output`, a `trace` of every tool call and
868
+ everything the model wrote (secrets redacted, long fields truncated and marked),
869
+ `steps_used` against `max_steps`, the tokens each model spent and
870
+ `provider_cost`.
871
+
872
+ **`attempts` is worth reading.** A run that ends without calling `submit_result`
873
+ is re-prompted rather than failed, and **each re-prompt starts the step budget
874
+ over** — so `attempts: 3` means the run hit `max_steps` twice and recovered on
875
+ the third go, having used up to three times the rounds `steps_used` shows.
876
+ `steps_used` is the busiest attempt's count, because that is the number the cap
877
+ governs; `timeout_seconds`, not `max_steps`, is what actually bounds a run.
878
+
879
+ A failure carries `error.type`, and it is a closed vocabulary that says whose
880
+ problem it is:
881
+
882
+ - `missing_vars` — a required input had no value and no default. Caught before
883
+ anything ran, so it cost nothing.
884
+ - `no_output` — the model finished without calling `submit_result`, twice; the
885
+ framework already re-prompted it once. **Fix the prompt**: say what the task
886
+ is for and that finishing means calling the tool.
887
+ - `step_limit` — every round of an attempt was used and no result came back.
888
+ **Fix `max_steps`**, or narrow what the task does. Reported apart from
889
+ `no_output` precisely so nobody rewrites a prompt that was never the problem.
890
+ - `timeout` — `timeout_seconds` elapsed.
891
+ - `provider_error` — the model or an MCP server failed. Not yours to fix.
892
+ - `configuration` — yours to tell them: a missing BYOK key, a deleted or
893
+ unpublished tool, an integration whose credential no longer resolves.
894
+ - `platform` — ours.
895
+
896
+ Task runs are **not** in the Observability charts, which are built on calls and
897
+ conversations. `list_task_runs` is where a task's own history lives.
898
+
899
+ ## Integrations
900
+
901
+ Integrations are external services, and they come in two shapes.
902
+
903
+ **MCP integrations** give an agent tools from an external server. Attach them
904
+ in the agent's own config, as `mcps` — the same place as `tools` and
905
+ `kb_ids`, written by `create_agent` or `update_agent`, and frozen at publish
906
+ like the rest of it. So attaching one **takes a publish** before a call sees it.
907
+ `list_integration_mcp_tools` connects to the server and lists everything it
908
+ offers, which also proves the connection works.
909
+
910
+ Which of those tools an agent may actually call is the integration's
911
+ `allowed_tools`, approved once on the integration and shared by every agent
912
+ attached to it. Null means all of them. Patch the list to narrow it — worth
913
+ doing on a large server, since every approved tool is described to the model on
914
+ every turn, and a voice agent picking from ninety of them is slower and less
915
+ accurate than one picking from six. Unlike the attachment, that approval is
916
+ live: narrowing it reaches every already-published agent on its next turn.
917
+
918
+ **Channel integrations** (Telegram) deploy an agent to a messaging
919
+ channel through *triggers*, not MCP attachment. A trigger binds an inbound event
920
+ to a published text agent and decides what happens with the reply.
921
+
922
+ `integration_catalog` is the authoritative list of providers and, in
923
+ `setup_fields`, exactly what each one needs — read it instead of guessing.
924
+ Providers whose `auth_type` is `oauth` must be connected from the dashboard's
925
+ Integrations page; you cannot create them through the API. Manual providers take
926
+ their credentials on create: pass the plaintext token or key and the platform
927
+ stores it as a workspace secret and wires the reference, or pass an existing
928
+ `{{secrets.NAME}}`.
929
+
930
+ ## Phone numbers
931
+
932
+ A voice or video agent answers the phone once a number is pointed at it. Three
933
+ things have to line up, in order:
934
+
935
+ 1. **A carrier account** — the credential for a phone network.
936
+ `list_telephony_providers` states exactly which fields each carrier needs;
937
+ `create_telephony_account` records them, and `provision_telephony_account`
938
+ builds the SIP trunk. Credentials may be passed as plaintext (stored as a
939
+ workspace secret) or as an existing `{{secrets.NAME}}`.
940
+ 2. **A number on it** — `list_remote_numbers` shows what the account owns at
941
+ the carrier, and `import_phone_numbers` brings the chosen ones in and
942
+ provisions them. Numbers are bought at the carrier, never here. Import
943
+ reports per number: read every `ok` rather than trusting the 200.
944
+ 3. **An agent on the number** — `assign_phone_number` puts a **published**
945
+ voice or video agent on it. Republishing the agent updates live calls
946
+ automatically; the assignment is not redone.
947
+
948
+ `readiness` on a number is the honest answer to "does this work": `live`,
949
+ `needs_agent`, `needs_carrier_setup`, `setting_up`, `error` or `disabled`.
950
+
951
+ Some carrier work happens in the carrier's own console and no API can confirm
952
+ it — that is what an account's `setup_steps` are for. A step marked
953
+ `user_confirmable` is done by the user, who then confirms it with
954
+ `patch_telephony_account`'s `console_setup_confirmed`. Do not claim inbound
955
+ calling works while such a step is outstanding.
956
+
957
+ ## Batch outbound calling
958
+
959
+ To call a *list* of people rather than one, create a **batch**: an agent, one of
960
+ its outbound-capable numbers, a list of recipients, and a schedule.
961
+ `create_call_batch` is the only way to schedule a call for later — a single
962
+ scheduled call is a one-row batch — and it is the most expensive operation on
963
+ this platform, because one call to it can place thousands of billable dials.
964
+
965
+ **A batch is policy plus a recipient list.** The policy — schedule, business
966
+ hours, concurrency, agent, retry rule — can be changed at any time with
967
+ `patch_call_batch`, and the next dial picks it up. The recipient list is the
968
+ work: who has been called and how it went, one row each, read back through
969
+ `list_call_batch_recipients`.
970
+
971
+ **Personalization is `userdata`.** Each recipient carries `to` plus a string map
972
+ that becomes that call's session state, so `{{userdata.first_name}}` in the
973
+ agent's prompt or greeting is that person's name. There are no per-recipient
974
+ overrides of anything else — one batch is one agent, one number, one clock.
975
+
976
+ **Scheduling.** `timezone` is the batch's clock. `start_at` says when it begins
977
+ (omit it to start immediately) and `calling_window` says which hours and
978
+ weekdays it may dial in, so a list uploaded at 23:00 can start at 11:00
979
+ tomorrow, stop at 18:00 and resume at 10:00 on the next weekday untouched. A
980
+ window may cross midnight; the days then name the evening it starts on.
981
+ `next_dial_at` on the batch says when it will dial next, which is how you tell
982
+ "waiting for Monday" apart from "stuck".
983
+
984
+ **Say these two things before creating one**, because a user who discovers
985
+ either from an invoice will not forgive us:
986
+
987
+ - **Answering machines are not detected.** A call that reaches voicemail is
988
+ answered, billed, and reported as completed.
989
+ - **Every call runs the agent's current published version**, so republishing
990
+ mid-batch changes every call placed after that moment.
991
+
992
+ **Steering it.** `pause_call_batch` stops new calls and lets live ones finish;
993
+ `resume_call_batch` carries on. `cancel_call_batch` is final and there is no
994
+ delete — a batch is the record of money spent. `add_call_batch_recipients`
995
+ appends to a running batch and silently skips numbers it already holds, so
996
+ re-uploading an exported list never calls anyone twice.
997
+
998
+ **Watching it.** `get_call_batch` has live counts and `failure_reason`; a batch
999
+ that stops itself did so after ten consecutive setup failures (an unpublished
1000
+ agent, an expired carrier credential, a trunk refusing everything).
1001
+ `list_calls` with `batch_id` gives the calls themselves — transcripts,
1002
+ recordings and cost.
1003
+
1004
+ ## Email outbound
1005
+
1006
+ To email a *list* rather than one person, create an **email batch**: a CSV, an
1007
+ agent task that drafts each row, a connected Resend account, and a mapping that
1008
+ says which column carries the address, the subject and the body.
1009
+
1010
+ **Four things to say before creating one.** A user who discovers any of them
1011
+ afterwards will not forgive us:
1012
+
1013
+ - **Resend's terms prohibit unsolicited email, cold outreach, purchased lists
1014
+ and scraped contact data**, and require that every recipient has explicitly
1015
+ opted in. This runs on *their* Resend account under *their* agreement.
1016
+ - **Nothing is sent that they have not reviewed and selected.** Creating a batch
1017
+ only drafts.
1018
+ - **Every row runs the task as it stands right now.** Editing it while a batch
1019
+ is drafting changes every row generated after that moment, and there is no way
1020
+ to get the old wording back.
1021
+ - **Bounces and spam complaints are only visible if they point a Resend webhook
1022
+ at this workspace.** The URL is on the integration's page.
1023
+
1024
+ ### The column space
1025
+
1026
+ A row has **one flat column space, filled from two directions**: the CSV
1027
+ supplies some columns, the task's `output` supplies the rest, and a person's
1028
+ edits sit on top. `field_map` points `to`, `subject` and `body` at names in that
1029
+ merged space, and each may name **either** a CSV header or a field the task
1030
+ produces. That is what makes "the CSV already has addresses" and "the CSV has
1031
+ phone numbers and the task looks the address up" the same feature.
1032
+
1033
+ A row is sendable when all three resolve to a non-empty string and `to` parses
1034
+ as an address. Every other field the task produces is kept on the row verbatim
1035
+ as context and read by nobody.
1036
+
1037
+ Refused at create, all at once: a mapped name that is neither a column nor an
1038
+ output field; a mapped output field that is not a `string`; a CSV header that
1039
+ collides with an output field name (one of the two would be unreachable); a
1040
+ `required` variable the task declares that has no column and no default; a
1041
+ `from_email` whose domain is not verified on that Resend account right now.
1042
+
1043
+ **A header that exists but is blank on some rows still passes create** and fails
1044
+ those rows at draft time with `missing_vars` — one row, not the batch, and with
1045
+ no tokens spent. Flag blank cells in a required column before creating.
1046
+
1047
+ ### Two jobs, and a human between them
1048
+
1049
+ **Drafting** starts on `start_at` (or immediately), honours `calling_window` on
1050
+ the batch's `timezone`, runs `max_concurrency` rows at a time, and stops when
1051
+ the last row lands. Its `status` is about drafting and nothing else —
1052
+ `scheduled`, `drafting`, `paused`, `drafted`, `canceled`, `failed`. A `drafted`
1053
+ batch means *"the drafts are ready to review"*, never "finished": it says
1054
+ nothing about what has been sent.
1055
+
1056
+ **Sending** is separate and only ever happens when a person asks.
1057
+ `send_email_batch_recipients` takes **at most 50 rows, named one by one**. There
1058
+ is no `selection` shorthand on it, no bulk endpoint, and there must not be one:
1059
+ a 5 000-row batch cannot leave the building without a hundred deliberate calls,
1060
+ each of which should follow reading the fifty drafts it covers. That friction is
1061
+ the only structural safeguard this feature has — **do not offer to work around
1062
+ it.** `skip`, `restore` and `retry` *do* take `selection: "all_eligible"`,
1063
+ because they are reversible and mailing strangers is not.
1064
+
1065
+ Each send may override `from_email` / `from_name` / `reply_to` for that call
1066
+ alone; the batch's own default is unchanged. The Resend account itself is not
1067
+ overridable — a different account is a different batch.
1068
+
1069
+ ### Fixing rows
1070
+
1071
+ `list_email_batch_recipients` returns each row's `columns` (the merged space),
1072
+ its three halves separately, and `not_ready_reason` — why it cannot be sent yet,
1073
+ null when it can. `patch_email_batch_recipient` edits cells: the edit is stored
1074
+ apart from what the model wrote, merged last, and an empty value clears it. That
1075
+ is the answer to a row whose task returned `null` for the address — type one in.
1076
+
1077
+ `retry_email_batch_recipients` re-drafts rows whose drafting failed, and is the
1078
+ one action that revives a batch that already finished drafting.
1079
+
1080
+ **One address is mailed at most once per batch**, enforced when the row is
1081
+ claimed for sending: the second row settles `skipped` with
1082
+ `duplicate_recipient`. There is no cross-batch dedup and no suppression list of
1083
+ ours — Resend keeps one and auto-suppresses hard bounces and complaints.
1084
+
1085
+ ### Watching it
1086
+
1087
+ `get_email_batch` carries live counts, `failure_reason`, `next_draft_at` (which
1088
+ is how "waiting for Monday" is told apart from "stuck") and the drafting cost so
1089
+ far. A batch that stops itself did so after ten consecutive drafting failures,
1090
+ or on the first `configuration` failure (a deleted task, a field map an edit
1091
+ broke) or the first account-level send failure (a revoked key, an unverified
1092
+ domain) — because those will fail identically for every remaining row.
1093
+
1094
+ `delivery_status` on a row is Resend's verdict, separate from ours: `sent` is
1095
+ what we did, `delivered` / `bounced` / `complained` is what happened next.
1096
+
1097
+ ## Knowledge bases
1098
+
1099
+ A knowledge base gives an agent grounded answers over crawled content. Attach
1100
+ ready ones through the agent's `kb_ids`; only `ready` ones can be attached.
1101
+
1102
+ Building one runs in three stages and takes minutes, not seconds:
1103
+
1104
+ 1. `create_kb` with the site URLs starts the crawl. It returns immediately at
1105
+ `discovering` — poll `get_kb` until `status` is `review`.
1106
+ 2. At `review`, `discovered` holds every URL the crawl found. Choose the ones
1107
+ worth indexing and pass them to `build_kb`. This choice decides the quality
1108
+ of the whole knowledge base: prefer pages that answer real questions over
1109
+ everything the crawl happened to reach.
1110
+ 3. The KB moves through `transcribing` and `generating` to `ready`. Keep
1111
+ polling `get_kb`; `progress` says what stage it is in and `error` says if it
1112
+ stopped.
1113
+
1114
+ Once ready, `get_kb_prompt` is the table of contents exactly as the agent
1115
+ receives it — read it to judge what the agent will actually be able to find,
1116
+ since a vague entry is one it will never fetch. `list_pages` shows which URLs
1117
+ failed to transcribe, `patch_node` corrects an entry by hand, and
1118
+ `regenerate_toc` rebuilds the structure without crawling again.
1119
+
1120
+ Tell the user a build is running rather than waiting silently through it, and
1121
+ never poll a build in a tight loop.
1122
+
1123
+ ## Secrets, keys and webhooks
1124
+
1125
+ **Secrets** are workspace values referenced as `{{secrets.NAME}}` from tool
1126
+ operations and integration config. They are write-only: once stored, only the
1127
+ runtime resolves them.
1128
+
1129
+ **BYOK.** Talqing runs agents on the workspace's own provider API keys and has
1130
+ none of its own. `list_provider_keys` says which providers are configured, and
1131
+ every key it lists was accepted by that provider when it was saved —
1132
+ `set_provider_key` calls the provider first and stores nothing it rejects.
1133
+ Prefer models from configured providers; if the user wants one that is not
1134
+ there, tell them the key has to be added before the agent can publish.
1135
+
1136
+ **Webhooks** are workspace-wide and fire for every agent. `event_types` lists
1137
+ what can be subscribed to, and `webhook_deliveries` is where to look when one
1138
+ seems silent.
1139
+
1140
+ ## Running an agent, and reading what happened
1141
+
1142
+ Published agents can be run from here, and every run leaves a record.
1143
+
1144
+ **Starting something.** `create_outbound_call` dials a real phone number from
1145
+ one of the workspace's numbers and puts a published voice agent on the call.
1146
+ `create_text_conversation` plus `create_text_message` talks to a published text
1147
+ agent — the fastest way to try one. `calls_token` mints the token a *browser*
1148
+ needs to join a web call; it starts nothing by itself.
1149
+
1150
+ All three take `userdata`, which seeds the session's state and is readable as
1151
+ `{{userdata.field}}` from the agent's prompt, greeting and tools. That is how
1152
+ you pass in who is being reached and why — one published agent, personalized
1153
+ per call. Keys beginning with `_talqing` are reserved.
1154
+
1155
+ All three — and `create_call_batch` — also take `vars`, a flat `{name: value}`
1156
+ map of strings read as `{{vars.name}}`. It overrides the declared defaults on
1157
+ every agent the session runs and is gone when the session ends. Use `userdata`
1158
+ for facts about the person and `vars` for configuration of the session; unlike
1159
+ `userdata`, `vars` is never written onto the caller's contact record and no tool
1160
+ can change it mid-session. An empty string is a deliberate blank, not a request
1161
+ for the default. The model can see the values, so credentials stay in workspace
1162
+ secrets. On a batch it is one bag for the whole campaign, copied onto every call
1163
+ it places — per-person data is what a recipient's `userdata` is for. On a text
1164
+ conversation it is fixed for the life of the thread.
1165
+
1166
+ **Per-call configuration.** All three — and `create_call_batch` — also take four
1167
+ fields that change what runs on that one call:
1168
+
1169
+ - `agent_version` — pin a version, or `"draft"` to run the unpublished working
1170
+ copy. That is how you try an edit without publishing over what live callers
1171
+ are hearing.
1172
+ - `agent_override` — an `AgentConfig` with only the fields this call changes.
1173
+ Absent keys keep the published value, an explicit `null` clears a field,
1174
+ objects deep-merge and lists replace wholesale. So `{"tts": {"voice":
1175
+ "aditi"}}` changes the voice and leaves the provider and model alone. Note
1176
+ that `agent_override.vars` is a list of *declarations* and replaces them
1177
+ wholesale, while the top-level `vars` above supplies *values*.
1178
+ - `agent` — a whole agent definition, run for this call and stored nowhere.
1179
+ - `agent_team` — `{"members": [{name, …the same four fields…}]}`, a cast of
1180
+ agents for one call. **`members[0]` answers**, and members reach each other
1181
+ through `handoffs` entries that name them.
1182
+
1183
+ `agent_id`/`agent`/`agent_version`/`agent_override` and `agent_team` are
1184
+ mutually exclusive: one agent, or a team of them.
1185
+
1186
+ **Prefer `agent_id` and `userdata`.** Reach for `agent_override` when one call
1187
+ genuinely differs from the published agent, and for `agent` or `agent_team` only
1188
+ when the definition is generated per request and would never be reused. An agent
1189
+ that exists in the workspace has an editor, a version history, a diff and reuse
1190
+ across calls; an inline one has none of those and disappears with the call.
1191
+ Composing an inline team by habit ends with a workspace that has no agents in it.
1192
+
1193
+ The merged result is validated by the same rules that guard publishing, so a
1194
+ bad override is a 400 at create — naming the problem — rather than a call that
1195
+ connects and then fails.
1196
+
1197
+ `create_text_message` returns as soon as the message is accepted — the agent
1198
+ replies asynchronously, so poll `list_conversation_items` (with `order: desc`)
1199
+ for the reply. Give it a few seconds, and expect several items when the agent
1200
+ calls tools.
1201
+
1202
+ It can also carry `images`: up to four `{data_url, filename}` entries beside
1203
+ `message`, each a base64 `data:image/...` URL of a JPEG, PNG or WebP under 10 MB.
1204
+ The caption and the photo arrive as one turn and one item, so send them together
1205
+ rather than as two messages. The agent's model must have `vision` (see *Images*
1206
+ above) or the call is refused naming the model.
1207
+
1208
+ **Reading it back.** A *conversation* is the thread with a person, on any
1209
+ surface; a *call* is one voice or video session. `list_conversations` and
1210
+ `list_conversation_items` are the transcript; `list_conversation_sessions` says
1211
+ which agent version handled each turn of it. `list_calls` and `get_call` cover
1212
+ phone and web calls — `get_call` gives the transcript with every tool call and
1213
+ its output, plus usage, cost and a per-stage latency breakdown, which is where
1214
+ you find out why an agent did something odd or answered slowly.
1215
+ `get_observability` is the workspace view: sessions, spend and latency per day.
1216
+
1217
+ What a run costs is the provider spend on the workspace's own keys plus
1218
+ Talqing's per-minute platform fee, which `get_catalog` gives per channel. **Text
1219
+ agents carry no platform fee at all** — a text conversation costs the workspace
1220
+ only what its own LLM key was charged.
1221
+
1222
+ When an agent misbehaves, read the actual run before theorizing. The transcript
1223
+ and the final `userdata` usually name the cause.
1224
+
1225
+ ## Rules
1226
+
1227
+ - **Never publish an agent unless asked.** Propose it when the draft is ready
1228
+ and wait for the user to say publish, deploy or go live. Publishing a *tool*
1229
+ needs no confirmation — it is a prerequisite for attaching it.
1230
+ - **Never reach a real person unless asked for that specific contact.** An
1231
+ outbound call rings someone's phone and costs money; a text message to a
1232
+ connected channel is a message they receive. Both are irreversible. Test
1233
+ against a number or thread the user has named, never one you picked.
1234
+ - **Delete only on an explicit request naming the target.** Agents, tools,
1235
+ knowledge bases, carrier accounts, integrations, triggers, secrets, webhooks
1236
+ and tokens are all permanent. Taking a phone number out of service stops real
1237
+ callers from reaching anyone — treat it the same way.
1238
+ - **Never echo a secret back.** Personal access tokens, webhook signing secrets
1239
+ and provider keys are shown once; repeating one puts it in the conversation
1240
+ transcript.
1241
+ - **Validate before you claim something is ready.** `validate_tool` after tool
1242
+ changes, `validate_agent` after config, hook or handoff changes. Treat errors
1243
+ as work to do and summarize warnings plainly. Validation runs on the server
1244
+ against rules you cannot check by reading a draft, so **never report a
1245
+ validation result you did not get back from the operation**, and never answer
1246
+ a request to validate by reasoning about the config instead of calling it.
1247
+ - **Do not invent fields.** Author tools and configs through the exact schemas
1248
+ the operations declare. A field the schema does not have is rejected. An
1249
+ argument whose description ends in `describe_schema('X')` carries a
1250
+ placeholder instead of its shape — fetch it before writing one, never
1251
+ reconstruct it from memory.
1252
+ - **Say what the platform does not do.** Decline capabilities that do not exist
1253
+ yet rather than approximating them.
1254
+
1255
+ ## Writing agent prompts
1256
+
1257
+ The agent prompt is the deliverable that decides whether the agent is any good.
1258
+ Give it a role, a goal, the rules it must follow, when to use which tool, and
1259
+ the language and tone to use.
1260
+
1261
+ For voice and video, write for speech, not for a document:
1262
+
1263
+ - Natural, brief and warm. Easy to interrupt.
1264
+ - Never dump long information — give the next useful chunk and ask whether to go
1265
+ on.
1266
+ - No markdown, emoji, raw JSON or list formatting in what the agent says.
1267
+ - Text-to-speech mangles abbreviations, symbols and numbers; spell out the forms
1268
+ that matter, or give pronunciation rules.
1269
+ - Make tool use explicit: when to call each tool, what to collect first, and
1270
+ what to say while waiting.