@talqing/mcp 0.10.0 → 0.12.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 +189 -64
- package/package.json +1 -1
- package/tools.json +146 -6
package/SKILL.md
CHANGED
|
@@ -37,8 +37,10 @@ An agent is a single object, `config`, plus what you attach to it:
|
|
|
37
37
|
- **`prompt`** — the system prompt. This is where the agent's behaviour lives.
|
|
38
38
|
- **`greeting`** — the line spoken on connect, and on the way in from a
|
|
39
39
|
handoff. Voice and video only. `greeting_interruptible: false` makes the
|
|
40
|
-
caller unable to cut it off (cascade only)
|
|
41
|
-
notice
|
|
40
|
+
caller unable to cut it off (cascade only). To tell callers they are recorded,
|
|
41
|
+
set `recording.notice` to the sentence and put `{{recording.notice}}` in the
|
|
42
|
+
greeting where it should be spoken; it plays uninterruptibly, needs recording
|
|
43
|
+
on and a cascade pipeline, and `null` means no notice.
|
|
42
44
|
|
|
43
45
|
Both are personalized per session: `{{userdata.field}}` is substituted from
|
|
44
46
|
the session's userdata when the agent starts, so *"You are speaking with
|
|
@@ -55,22 +57,28 @@ An agent is a single object, `config`, plus what you attach to it:
|
|
|
55
57
|
Two more roots are filled in from outside the session, and nothing inside one
|
|
56
58
|
can write either. They differ in who fills them.
|
|
57
59
|
|
|
58
|
-
**`{{system_vars.…}}` — ours.**
|
|
59
|
-
`GET /v1/catalog` returns them as `system_vars
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
- `{{system_vars.
|
|
60
|
+
**`{{system_vars.…}}` — ours.** Seven keys, and any other is rejected at save;
|
|
61
|
+
`GET /v1/catalog` returns them as `system_vars`, each with the `channels` it
|
|
62
|
+
has a value on.
|
|
63
|
+
|
|
64
|
+
- `{{system_vars.human_phone_number}}` — the person's number: who called or
|
|
65
|
+
wrote to you, or whom you called or wrote to
|
|
66
|
+
- `{{system_vars.agent_phone_number}}` — your number in this session
|
|
67
|
+
- `{{system_vars.direction}}` — `inbound` when they started the call or chat,
|
|
68
|
+
`outbound` when you did
|
|
69
|
+
- `{{system_vars.channel}}` — where the session is happening: `phone_call`,
|
|
70
|
+
`whatsapp_call`, `whatsapp_message`, `web_call`, `chat`, `telegram` or `stream`
|
|
65
71
|
- `{{system_vars.now}}` — `2026-08-19T19:26:59+05:30`, the machine format;
|
|
66
72
|
send it to an API, never read it aloud
|
|
67
73
|
- `{{system_vars.date}}` — `Wednesday, 19 August 2026`
|
|
68
74
|
- `{{system_vars.time}}` — `7:26 PM`
|
|
69
75
|
|
|
70
|
-
The first three come from
|
|
71
|
-
|
|
76
|
+
The first three come from a phone number — phone calls, WhatsApp calls,
|
|
77
|
+
WhatsApp chats and media streams — so they are empty on web calls, API chats
|
|
78
|
+
and Telegram; do not make one the only source of a fact the agent needs. One
|
|
72
79
|
agent can greet a caller and someone it called differently by branching on
|
|
73
|
-
`{{system_vars.direction}}
|
|
80
|
+
`{{system_vars.direction}}`, and one agent on several channels can adapt by
|
|
81
|
+
branching on `{{system_vars.channel}}`. The last three come from the agent's
|
|
74
82
|
**`timezone`** and work on every channel; using one without setting `timezone`
|
|
75
83
|
is a save error. In a prompt or greeting the clock is frozen at the moment the
|
|
76
84
|
agent started (re-resolving would throw away the model's prompt cache); inside
|
|
@@ -107,8 +115,9 @@ An agent is a single object, `config`, plus what you attach to it:
|
|
|
107
115
|
Four things to get right:
|
|
108
116
|
|
|
109
117
|
- **They are visible to the model.** Anything in `vars` may be read aloud or
|
|
110
|
-
repeated back. A credential belongs in
|
|
111
|
-
|
|
118
|
+
repeated back. A credential belongs in `secrets` on the same request when it
|
|
119
|
+
is per session, or in a workspace secret when it is shared — either is read
|
|
120
|
+
as `{{secrets.NAME}}` from a tool, where the model never sees it.
|
|
112
121
|
- **`required: true` refuses the session** that supplies no value for a
|
|
113
122
|
variable with no `default` — the call token, the dial, the batch and the chat,
|
|
114
123
|
before anything is compiled and before any provider is called.
|
|
@@ -649,17 +658,21 @@ states what to add; do not try to turn the derived silence off.
|
|
|
649
658
|
this tool run's own state, `{{userdata.field}}` the session's state,
|
|
650
659
|
`{{system_vars.field}}` what the platform knows about this session,
|
|
651
660
|
`{{vars.field}}` what the tenant supplied for it, and `{{secrets.NAME}}` a
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
not text.
|
|
656
|
-
|
|
657
|
-
`
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
661
|
+
secret — the session's own if it brought one of that name, else the workspace's.
|
|
662
|
+
A string that is exactly one template token keeps the resolved value's type.
|
|
663
|
+
Every one of these works in a URL, in the query, in the body **and in headers**.
|
|
664
|
+
A token whose root is not one of those six is an error at save, not text.
|
|
665
|
+
**A secret may only be sent by an `http` operation or read by a `code`
|
|
666
|
+
operation**: `{{secrets.…}}` in any other operation (`say`, `set_variable`,
|
|
667
|
+
`if`, `frontend_rpc`, `generate_reply`, a handoff…) is refused at save, because
|
|
668
|
+
it would be spoken, shown or stored.
|
|
669
|
+
|
|
670
|
+
`system_vars` is read-only, and its seven keys are the same ones the agent's prompt
|
|
671
|
+
reads: `human_phone_number`, `agent_phone_number`, `direction`, `channel`, `now`,
|
|
672
|
+
`date`, `time`. So a tool can POST the person's number to a CRM, stamp a record
|
|
673
|
+
with `{{system_vars.now}}`, or branch an `if` on the direction or the channel
|
|
674
|
+
without the agent having to ask. The phone keys are empty on web calls, API chats,
|
|
675
|
+
Telegram and in a dashboard test run; the clock keys resolve wherever the agent has a
|
|
663
676
|
`timezone`, and read the time the **tool ran** rather than the time the call
|
|
664
677
|
started.
|
|
665
678
|
|
|
@@ -897,15 +910,15 @@ same lifecycle hooks as an agent — minus everything that belongs to a
|
|
|
897
910
|
*session*, because a task never owns one.
|
|
898
911
|
|
|
899
912
|
**It runs two ways, and declares nothing that ties it to either.** On its own —
|
|
900
|
-
`POST /v1/
|
|
901
|
-
with tools and nobody to talk to. Attached to an agent through
|
|
913
|
+
`run_task` (`POST /v1/task-runs`), or an email batch drafting a row — it is an
|
|
914
|
+
LLM with tools and nobody to talk to. Attached to an agent through
|
|
902
915
|
`AgentConfig.tasks`, it takes over that conversation for as long as the job
|
|
903
|
-
takes, on the call's own voice and ears, and hands its result back
|
|
904
|
-
result.
|
|
916
|
+
takes, on the call's own voice and ears, and hands its result back to the
|
|
917
|
+
calling agent as a JSON tool result.
|
|
905
918
|
|
|
906
919
|
It is its own noun with its own operations (`list_tasks`, `create_task`,
|
|
907
|
-
`get_task`, `update_task`, `delete_task`, `run_task`, `list_task_runs
|
|
908
|
-
fourth agent channel. Use one wherever the work has an input and an answer
|
|
920
|
+
`get_task`, `update_task`, `delete_task`, `run_task`, `list_task_runs`, …) — not
|
|
921
|
+
a fourth agent channel. Use one wherever the work has an input and an answer
|
|
909
922
|
rather than a conversation: research a company from a domain, classify a
|
|
910
923
|
message, draft an opening line, take a shipping address mid-call.
|
|
911
924
|
|
|
@@ -916,7 +929,7 @@ message, draft an opening line, take a shipping address mid-call.
|
|
|
916
929
|
reads `{{vars.name}}` for the values the run was given, and
|
|
917
930
|
`{{system_vars.now}}` / `.date` / `.time` when `timezone` is set. It does
|
|
918
931
|
**not** read `{{system_vars.human_phone_number}}` / `.agent_phone_number` /
|
|
919
|
-
`.direction` — there is no
|
|
932
|
+
`.direction` / `.channel` — there is no session.
|
|
920
933
|
- **`llm`** — one model, with the same `fallback`, `reasoning_effort`,
|
|
921
934
|
`priority` and `builtin_tools` an agent's LLM has. A provider tool runs inside
|
|
922
935
|
a step rather than as one, so it costs no steps and real seconds. It is the
|
|
@@ -943,17 +956,31 @@ message, draft an opening line, take a shipping address mid-call.
|
|
|
943
956
|
refused too, rather than silently dropped — which is the one difference from an
|
|
944
957
|
agent, whose key space is open.
|
|
945
958
|
|
|
959
|
+
Two input kinds exist for tasks only. **`type: "file"`** takes a PDF (text or
|
|
960
|
+
scanned, up to 20 MB and 100 pages), supplied under the run's `files`; it has
|
|
961
|
+
no `default`. **`untrusted: true`** marks third-party text — a CV, an email, a
|
|
962
|
+
transcript. Both are **never templated**: `{{vars.cv}}` in the prompt, or an
|
|
963
|
+
untrusted value in a tool's URL, query or headers, is refused at save (a tool's
|
|
964
|
+
request body may carry untrusted text; nothing may carry a file). The run hands
|
|
965
|
+
them to the model as JSON in its opening message, under a line saying they are
|
|
966
|
+
data, not instructions — so the prompt should name them and say how to treat
|
|
967
|
+
them. Scanned pages reach the model as images, so they need a model with
|
|
968
|
+
vision. A task with either kind cannot be attached to an agent.
|
|
969
|
+
|
|
946
970
|
**They are also the schema of the tool an agent enters the task with**, minus
|
|
947
971
|
every name that agent declares and every name the session was started with. So
|
|
948
972
|
declare a variable only for what the caller or the model must supply: anything
|
|
949
973
|
the task can read for itself — `{{userdata.order_id}}`, `{{vars.region}}`,
|
|
950
974
|
`{{system_vars.date}}` — belongs in the prompt. Declare it instead and the
|
|
951
975
|
model is asked to invent it, and it will.
|
|
952
|
-
- **`output`** —
|
|
953
|
-
`
|
|
954
|
-
`
|
|
955
|
-
|
|
956
|
-
|
|
976
|
+
- **`output`** — the fields the model must produce, each with a `name`, a
|
|
977
|
+
`type` and a `description`. Types are `string`, `boolean`, `integer`,
|
|
978
|
+
`number`, `object` (takes `fields`, a list of the same shape) and `array`
|
|
979
|
+
(takes `items`: `{type, description, enum?, fields?, items?}` — an element has
|
|
980
|
+
no name and is never null). A `string` may take `enum`, 1–50 allowed values.
|
|
981
|
+
At most 25 top-level fields, 4 levels deep and 100 fields in all, and at least
|
|
982
|
+
one **to publish**. A grader returns `criteria: [{name, verdict, quote}]`
|
|
983
|
+
rather than one string to be parsed.
|
|
957
984
|
- **`max_steps`** (default 25, max 50) — how many LLM → tools → LLM **rounds**
|
|
958
985
|
a STANDALONE run may take. A round, not a tool call: four tools in one reply
|
|
959
986
|
cost one step. This is the runaway-loop guard. Entered by an agent the task
|
|
@@ -985,7 +1012,7 @@ trees, and the email batches already drafting with this task. Run it before
|
|
|
985
1012
|
are worth reporting but never block.
|
|
986
1013
|
|
|
987
1014
|
**Build order:** create the draft → write the prompt, `vars` and `output` →
|
|
988
|
-
`run_task` with `
|
|
1015
|
+
`run_task` with `task_id` and `task_version: "draft"` to try it → fix → `validate_task` →
|
|
989
1016
|
`publish_task` **when the person asks you to**. Publishing is their call, not
|
|
990
1017
|
yours: it changes what every run and every live email batch does.
|
|
991
1018
|
|
|
@@ -1002,7 +1029,7 @@ job is done enough to call it. It is required and
|
|
|
1002
1029
|
non-empty; a new task starts with `"Submit results if you are sure that you have achieved the goal of this task"`. **Make it specific**: what
|
|
1003
1030
|
"achieved" means for this task (e.g. "once the caller has confirmed the address").
|
|
1004
1031
|
|
|
1005
|
-
Every output field is a **required argument** of that tool — an optional one lets
|
|
1032
|
+
Every output field is a **required argument** of that tool, at every depth — an optional one lets
|
|
1006
1033
|
the model silently omit the address it failed to find, and "omitted" and "not
|
|
1007
1034
|
generated yet" then look identical to whoever reads the row. A field's own
|
|
1008
1035
|
`required` flag (default `true`) decides whether `null` is accepted: turn it off
|
|
@@ -1020,21 +1047,51 @@ IS how a task reports failure, so never add a success/failure boolean to `output
|
|
|
1020
1047
|
a value it may legitimately not find is a field with `required` off. Publishing
|
|
1021
1048
|
refuses either description blank.
|
|
1022
1049
|
|
|
1023
|
-
###
|
|
1050
|
+
### Running one
|
|
1024
1051
|
|
|
1025
1052
|
`run_task` **executes for real**: the tools call the tenant's endpoints with
|
|
1026
1053
|
their secrets, the MCP servers spend their credits, and the model spends their
|
|
1027
1054
|
tokens. A task that books, charges or sends will do so.
|
|
1028
1055
|
|
|
1029
|
-
|
|
1030
|
-
`
|
|
1031
|
-
in,
|
|
1032
|
-
|
|
1056
|
+
**What runs** is named like an agent on a call: `task_id` (the published
|
|
1057
|
+
version, an int `task_version`, or `task_version: "draft"` — the loop you build
|
|
1058
|
+
in, refused with the publish errors when the draft does not hold together), or
|
|
1059
|
+
a whole inline `task`. `task_override` changes anything for this run only
|
|
1060
|
+
(objects merge, lists replace, null clears) — a different model, say. The run
|
|
1061
|
+
stores the exact resolved config as `config`.
|
|
1062
|
+
|
|
1063
|
+
**Inline or background.** By default the call waits and answers with the
|
|
1064
|
+
finished run. `background: true` queues it and answers `202` at once; the
|
|
1065
|
+
workspace runs up to 3 background runs at a time, oldest first, and queues the
|
|
1066
|
+
rest — it never refuses for load. `run_task_batch` queues up to 1000 runs of one task in one
|
|
1067
|
+
call, all or nothing: one invalid item refuses the batch, naming `runs[i]`. Give
|
|
1068
|
+
each run `metadata` (≤16 string labels, e.g. `{candidate_id: "c_42"}`) and an
|
|
1069
|
+
`idempotency_key`: resending a key returns the existing run (`deduplicated`)
|
|
1070
|
+
instead of starting another — even after the task was republished — and the same
|
|
1071
|
+
key with a different request is a `409`. Read results with `list_task_runs`
|
|
1072
|
+
(filter by `task_id`, `status`, `metadata=key:value`, a creation window) and
|
|
1073
|
+
`get_task_run`, or subscribe a webhook to `task_run.completed`, sent once per run
|
|
1074
|
+
as it finishes.
|
|
1075
|
+
|
|
1076
|
+
**Retries.** A background run is tried again — at most 3 tries — when its
|
|
1077
|
+
worker stopped under it, or when the model provider failed transiently before
|
|
1078
|
+
any tool ran, so a side-effecting tool never runs twice. Everything else settles
|
|
1079
|
+
on the first try. `tries` says how many there were; cost adds up across them.
|
|
1080
|
+
|
|
1081
|
+
`cancel_task_run` stops a queued run at once and a running background one
|
|
1082
|
+
within seconds; an inline run cannot be canceled. `delete_task_run` (and
|
|
1083
|
+
`delete_task_runs` by metadata) erases a run's inputs, files, output, trace and
|
|
1084
|
+
config, keeping its cost and metadata — and a workspace's retention policy does
|
|
1085
|
+
the same on schedule (`content_expires_at`).
|
|
1086
|
+
|
|
1087
|
+
### Reading a run
|
|
1033
1088
|
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
`
|
|
1037
|
-
`
|
|
1089
|
+
`get_task_run` is the whole run — `config`, `vars`, `files` (each PDF's
|
|
1090
|
+
extracted text and its scanned pages, exactly what the model saw), `output`, a
|
|
1091
|
+
`trace` of every tool call and everything the model wrote (secrets redacted,
|
|
1092
|
+
long fields truncated and marked), `steps_used` against `max_steps`, the tokens
|
|
1093
|
+
each model spent and `provider_cost`. A result over 64 KB is refused back to the
|
|
1094
|
+
model, which is told to shorten it.
|
|
1038
1095
|
|
|
1039
1096
|
**`attempts` is worth reading.** A run that ends without calling `submit_result`
|
|
1040
1097
|
is re-prompted rather than failed, and **each re-prompt starts the step budget
|
|
@@ -1043,28 +1100,28 @@ the third go, having used up to three times the rounds `steps_used` shows.
|
|
|
1043
1100
|
`steps_used` is the busiest attempt's count, because that is the number the cap
|
|
1044
1101
|
governs; `timeout_seconds`, not `max_steps`, is what actually bounds a run.
|
|
1045
1102
|
|
|
1046
|
-
|
|
1047
|
-
problem it is:
|
|
1103
|
+
`status` is `queued`, `running`, `completed`, `failed` or `canceled`. A failure
|
|
1104
|
+
carries `error.type`, a closed vocabulary that says whose problem it is:
|
|
1048
1105
|
|
|
1049
|
-
- `
|
|
1050
|
-
|
|
1106
|
+
- `invalid_input` — a required input was missing, a file could not be
|
|
1107
|
+
downloaded or read, or the model cannot see scanned pages. Caught before the
|
|
1108
|
+
model ran, so it cost nothing.
|
|
1051
1109
|
- `no_output` — the model finished without calling `submit_result`, twice; the
|
|
1052
1110
|
framework already re-prompted it once. **Fix the prompt**: say what the task
|
|
1053
1111
|
is for and that finishing means calling the tool.
|
|
1054
1112
|
- `step_limit` — every round of an attempt was used and no result came back.
|
|
1055
1113
|
**Fix `max_steps`**, or narrow what the task does. Reported apart from
|
|
1056
1114
|
`no_output` precisely so nobody rewrites a prompt that was never the problem.
|
|
1057
|
-
- `timeout` — `timeout_seconds` elapsed.
|
|
1115
|
+
- `timeout` — `timeout_seconds` elapsed (reading the files counts).
|
|
1058
1116
|
- `provider_error` — the model or an MCP server failed. Not yours to fix.
|
|
1059
1117
|
- `configuration` — yours to tell them: a missing BYOK key, a tool version this
|
|
1060
1118
|
publish pinned that has since been deleted, an integration whose credential no
|
|
1061
1119
|
longer resolves.
|
|
1062
1120
|
- `platform` — ours.
|
|
1063
|
-
- `canceled` —
|
|
1064
|
-
automatically; a run started by hand is run again.
|
|
1121
|
+
- `canceled` — someone canceled it, or a deploy stopped an inline run.
|
|
1065
1122
|
|
|
1066
|
-
Each run records `task_version` — which published definition
|
|
1067
|
-
for a
|
|
1123
|
+
Each run records `task_version` — which published definition was its base, null
|
|
1124
|
+
for a draft or inline task. That is what makes two runs either side of an edit
|
|
1068
1125
|
tell apart.
|
|
1069
1126
|
|
|
1070
1127
|
Task runs are **not** in the Observability charts, which are built on calls and
|
|
@@ -1269,7 +1326,7 @@ collides with an output field name (one of the two would be unreachable); a
|
|
|
1269
1326
|
`from_email` whose domain is not verified on that Resend account right now.
|
|
1270
1327
|
|
|
1271
1328
|
**A header that exists but is blank on some rows still passes create** and fails
|
|
1272
|
-
those rows at draft time with `
|
|
1329
|
+
those rows at draft time with `invalid_input` — one row, not the batch, and with
|
|
1273
1330
|
no tokens spent. Flag blank cells in a required column before creating.
|
|
1274
1331
|
|
|
1275
1332
|
**A row that can never be sent is never drafted.** If a mapped column the task
|
|
@@ -1407,11 +1464,47 @@ Replies are answered by the agent on the sender's
|
|
|
1407
1464
|
`{{userdata.<column>}}` and the whole template, buttons included, as its own
|
|
1408
1465
|
first message — so write that agent's prompt against the CSV's column names.
|
|
1409
1466
|
|
|
1467
|
+
A tapped quick-reply button reaches the agent as its text; the item's `content`
|
|
1468
|
+
keeps the button's `payload` (never shown to the agent) and `replied_to`, the
|
|
1469
|
+
template it answers. Photos reach an agent whose model has `vision: true`; any
|
|
1470
|
+
other agent is told to ask for a description, so pick a vision model for a
|
|
1471
|
+
number people send photos to. Voice notes, video and documents are not read.
|
|
1472
|
+
|
|
1473
|
+
**One message to one person** is `create_conversation_item`, not a batch. `to`
|
|
1474
|
+
is a `conversation_id`, or `number` (your WhatsApp sender, E.164) plus `peer`
|
|
1475
|
+
(their number) to reach someone with no conversation yet. Four `type`s:
|
|
1476
|
+
|
|
1477
|
+
- `template` — an approved template with every variable filled
|
|
1478
|
+
(`template.variables`); may go any time.
|
|
1479
|
+
- `agent_text` — free text sent as the agent's own message.
|
|
1480
|
+
- `note` — background for the agent, never delivered (any contact, PSTN ones too).
|
|
1481
|
+
- `instruct` — the agent writes and sends the next message itself, in the
|
|
1482
|
+
conversation's language, without ever saying it was instructed. Refused with
|
|
1483
|
+
`voice_session_live` while they are on a call with the agent.
|
|
1484
|
+
|
|
1485
|
+
WhatsApp allows free text only within **24 hours of their last message or
|
|
1486
|
+
call** (`ref.whatsapp_window_expires_at`). Outside it `agent_text` and
|
|
1487
|
+
`instruct` are refused with `whatsapp_window_closed`, unless
|
|
1488
|
+
`on_window_closed: {opener: {id, variables}}` names a template to send first:
|
|
1489
|
+
the text is then `held` until they reply, and `expired` after 7 days. Prefer an
|
|
1490
|
+
opener over a bare template when what you want to say is free-form.
|
|
1491
|
+
`userdata` on a post joins the contact's and is what the agent answering their
|
|
1492
|
+
reply starts from. Send an `idempotency_key` when retrying is possible. A
|
|
1493
|
+
provider refusal still stores the item, `delivery_status: failed` (nothing resends it). While
|
|
1494
|
+
they have an open chat, post anything but a note into that chat's conversation:
|
|
1495
|
+
another one is refused with `chat_open_elsewhere`.
|
|
1496
|
+
|
|
1410
1497
|
## Secrets, keys and webhooks
|
|
1411
1498
|
|
|
1412
1499
|
**Secrets** are workspace values referenced as `{{secrets.NAME}}` from tool
|
|
1413
1500
|
operations and integration config. They are write-only: once stored, only the
|
|
1414
|
-
runtime resolves them.
|
|
1501
|
+
runtime resolves them. A session can also bring its own, as `secrets` on the
|
|
1502
|
+
request that starts it; for that session they join the workspace's under the
|
|
1503
|
+
same `{{secrets.NAME}}`, the session's value winning. A tool that reads a name
|
|
1504
|
+
that is not a workspace secret saves with a warning, and starting a session
|
|
1505
|
+
without supplying it is refused — an inbound call or chat, which has no
|
|
1506
|
+
request, gets one only from the inbound webhook below. Integration and carrier
|
|
1507
|
+
credentials and MCP server headers must be workspace secrets.
|
|
1415
1508
|
|
|
1416
1509
|
**BYOK.** Talqing runs agents on the workspace's own provider API keys and has
|
|
1417
1510
|
none of its own. `list_provider_keys` says which providers are configured, and
|
|
@@ -1422,7 +1515,21 @@ there, tell them the key has to be added before the agent can publish.
|
|
|
1422
1515
|
|
|
1423
1516
|
**Webhooks** are workspace-wide and fire for every agent. `event_types` lists
|
|
1424
1517
|
what can be subscribed to, and `webhook_deliveries` is where to look when one
|
|
1425
|
-
seems silent.
|
|
1518
|
+
seems silent. `session.refused` fires for every inbound call or channel chat
|
|
1519
|
+
turned away before an agent ran.
|
|
1520
|
+
|
|
1521
|
+
**The inbound webhook** is how an inbound PSTN call, WhatsApp call or new
|
|
1522
|
+
WhatsApp/Telegram chat gets what an outbound request would carry. An agent with
|
|
1523
|
+
`inbound_webhook: true` has Talqing POST `session.request` (channel, numbers,
|
|
1524
|
+
`contact_key`, the opening message) to the workspace's one URL
|
|
1525
|
+
(`set_inbound_webhook`) before the session starts; the answer may set `vars`,
|
|
1526
|
+
`secrets`, `agent_override`, `metadata` and `userdata`, each meaning what it
|
|
1527
|
+
means on `create_outbound_call`. No valid answer within 3 s **refuses the
|
|
1528
|
+
session** (`inbound_webhook_failed`, reason in `error`), so publishing such an
|
|
1529
|
+
agent needs the webhook set, and `test_inbound_webhook` checks a reply before
|
|
1530
|
+
real callers depend on it. A chat asks once, when it opens. `metadata` — the
|
|
1531
|
+
caller's own labels — appears on the call or chat and filters `list_calls` and
|
|
1532
|
+
`list_chats` (`metadata=key:value`).
|
|
1426
1533
|
|
|
1427
1534
|
## Running an agent, and reading what happened
|
|
1428
1535
|
|
|
@@ -1445,9 +1552,14 @@ every agent the session runs and is gone when the session ends. Use `userdata`
|
|
|
1445
1552
|
for facts about the person and `vars` for configuration of the session; unlike
|
|
1446
1553
|
`userdata`, `vars` is never written onto the caller's contact record and no tool
|
|
1447
1554
|
can change it mid-session. An empty string is a deliberate blank, not a request
|
|
1448
|
-
for the default. The model can see the values, so credentials
|
|
1449
|
-
|
|
1450
|
-
|
|
1555
|
+
for the default. The model can see the values, so credentials go in secrets. On
|
|
1556
|
+
a batch it is one bag for the whole campaign, copied onto every call it places —
|
|
1557
|
+
per-person data is what a recipient's `userdata` is for.
|
|
1558
|
+
|
|
1559
|
+
All three (not batches) also take `secrets`, `{NAME: value}`: credentials for
|
|
1560
|
+
that one session, read by its tools as `{{secrets.NAME}}` and never shown to the
|
|
1561
|
+
model or returned. A web call's `resume_call` keeps them, and its own `secrets`
|
|
1562
|
+
adds or replaces.
|
|
1451
1563
|
|
|
1452
1564
|
**Per-call configuration.** All three — and `create_call_batch` — also take four
|
|
1453
1565
|
fields that change what runs on that one call:
|
|
@@ -1494,7 +1606,13 @@ rather than as two messages. The agent's model must have `vision` (see *Images*
|
|
|
1494
1606
|
above) or the call is refused naming the model.
|
|
1495
1607
|
|
|
1496
1608
|
**Reading it back.** A *conversation* is the thread with a person, on any
|
|
1497
|
-
surface; a *call* is one voice or video session.
|
|
1609
|
+
surface; a *call* is one voice or video session. A person is one **contact**
|
|
1610
|
+
(`contact_key`) per business number: `phone:<your number>:<their number>` spans
|
|
1611
|
+
phone calls, WhatsApp messages and WhatsApp calls on that number, with one
|
|
1612
|
+
`userdata`. Which thread a session writes to is the answering agent's
|
|
1613
|
+
`conversation.context` (`transcript` joins their newest thread), except that a
|
|
1614
|
+
WhatsApp call always joins their open WhatsApp chat. Every item carries the
|
|
1615
|
+
`channel` it arrived on. `list_conversations` and
|
|
1498
1616
|
`list_conversation_items` are the transcript; `list_conversation_sessions` lists
|
|
1499
1617
|
its calls and chats, and `get_chat` gives one chat's cost and analysis.
|
|
1500
1618
|
`list_calls` and `get_call` cover phone and web calls — `get_call` gives the transcript with every tool call and
|
|
@@ -1506,6 +1624,13 @@ What a run costs is the provider spend on the workspace's own keys plus
|
|
|
1506
1624
|
Talqing's platform fee, which `get_catalog` gives: per minute on voice and
|
|
1507
1625
|
video, and $0.0001 per answered message on text.
|
|
1508
1626
|
|
|
1627
|
+
Items posted through `create_conversation_item` carry `post_type` and the
|
|
1628
|
+
`author` you gave (shown to people, never to the agent or the contact). Notes and
|
|
1629
|
+
instructions have no `channel`. Outbound WhatsApp and Telegram messages move
|
|
1630
|
+
through `delivery_status` (`queued`, `sent`, `delivered`, `read`, or
|
|
1631
|
+
`undelivered`/`failed` with `delivery_error`), and each move fires the
|
|
1632
|
+
`conversation.item.status` webhook.
|
|
1633
|
+
|
|
1509
1634
|
When an agent misbehaves, read the actual run before theorizing. The transcript
|
|
1510
1635
|
and the final `userdata` usually name the cause.
|
|
1511
1636
|
|
package/package.json
CHANGED
package/tools.json
CHANGED
|
@@ -395,7 +395,7 @@
|
|
|
395
395
|
"role": "write"
|
|
396
396
|
},
|
|
397
397
|
{
|
|
398
|
-
"description": "Run
|
|
398
|
+
"description": "Run a task for real: its tools, MCP servers and model all act and spend.",
|
|
399
399
|
"method": "POST",
|
|
400
400
|
"name": "run_task",
|
|
401
401
|
"parameters": {
|
|
@@ -404,12 +404,26 @@
|
|
|
404
404
|
"properties": {},
|
|
405
405
|
"type": "object"
|
|
406
406
|
},
|
|
407
|
-
"path": "/v1/
|
|
407
|
+
"path": "/v1/task-runs",
|
|
408
408
|
"read_only": false,
|
|
409
409
|
"role": "write"
|
|
410
410
|
},
|
|
411
411
|
{
|
|
412
|
-
"description": "
|
|
412
|
+
"description": "Queue up to 1000 runs of one task, in the background. One invalid item refuses all.",
|
|
413
|
+
"method": "POST",
|
|
414
|
+
"name": "run_task_batch",
|
|
415
|
+
"parameters": {
|
|
416
|
+
"additionalProperties": true,
|
|
417
|
+
"description": "Arguments not inlined: call describe_function('run_task_batch').",
|
|
418
|
+
"properties": {},
|
|
419
|
+
"type": "object"
|
|
420
|
+
},
|
|
421
|
+
"path": "/v1/task-runs/batch",
|
|
422
|
+
"read_only": false,
|
|
423
|
+
"role": "write"
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
"description": "Task runs, newest first, without traces or inputs.",
|
|
413
427
|
"method": "GET",
|
|
414
428
|
"name": "list_task_runs",
|
|
415
429
|
"parameters": {
|
|
@@ -418,12 +432,12 @@
|
|
|
418
432
|
"properties": {},
|
|
419
433
|
"type": "object"
|
|
420
434
|
},
|
|
421
|
-
"path": "/v1/
|
|
435
|
+
"path": "/v1/task-runs",
|
|
422
436
|
"read_only": true,
|
|
423
437
|
"role": "read"
|
|
424
438
|
},
|
|
425
439
|
{
|
|
426
|
-
"description": "One run in full:
|
|
440
|
+
"description": "One run in full: its config, inputs, output, trace and cost. Secrets are redacted.",
|
|
427
441
|
"method": "GET",
|
|
428
442
|
"name": "get_task_run",
|
|
429
443
|
"parameters": {
|
|
@@ -432,10 +446,52 @@
|
|
|
432
446
|
"properties": {},
|
|
433
447
|
"type": "object"
|
|
434
448
|
},
|
|
435
|
-
"path": "/v1/
|
|
449
|
+
"path": "/v1/task-runs/{run_id}",
|
|
436
450
|
"read_only": true,
|
|
437
451
|
"role": "read"
|
|
438
452
|
},
|
|
453
|
+
{
|
|
454
|
+
"description": "Cancel a queued or background run. A running one stops within seconds.",
|
|
455
|
+
"method": "POST",
|
|
456
|
+
"name": "cancel_task_run",
|
|
457
|
+
"parameters": {
|
|
458
|
+
"additionalProperties": true,
|
|
459
|
+
"description": "Arguments not inlined: call describe_function('cancel_task_run').",
|
|
460
|
+
"properties": {},
|
|
461
|
+
"type": "object"
|
|
462
|
+
},
|
|
463
|
+
"path": "/v1/task-runs/{run_id}/cancel",
|
|
464
|
+
"read_only": false,
|
|
465
|
+
"role": "write"
|
|
466
|
+
},
|
|
467
|
+
{
|
|
468
|
+
"description": "Delete a run's inputs, files, output and trace; its cost and metadata stay.",
|
|
469
|
+
"method": "DELETE",
|
|
470
|
+
"name": "delete_task_run",
|
|
471
|
+
"parameters": {
|
|
472
|
+
"additionalProperties": true,
|
|
473
|
+
"description": "Arguments not inlined: call describe_function('delete_task_run').",
|
|
474
|
+
"properties": {},
|
|
475
|
+
"type": "object"
|
|
476
|
+
},
|
|
477
|
+
"path": "/v1/task-runs/{run_id}",
|
|
478
|
+
"read_only": false,
|
|
479
|
+
"role": "write"
|
|
480
|
+
},
|
|
481
|
+
{
|
|
482
|
+
"description": "Delete the content of every run whose metadata matches, as `delete_task_run` does.",
|
|
483
|
+
"method": "POST",
|
|
484
|
+
"name": "delete_task_runs",
|
|
485
|
+
"parameters": {
|
|
486
|
+
"additionalProperties": true,
|
|
487
|
+
"description": "Arguments not inlined: call describe_function('delete_task_runs').",
|
|
488
|
+
"properties": {},
|
|
489
|
+
"type": "object"
|
|
490
|
+
},
|
|
491
|
+
"path": "/v1/task-runs/delete",
|
|
492
|
+
"read_only": false,
|
|
493
|
+
"role": "write"
|
|
494
|
+
},
|
|
439
495
|
{
|
|
440
496
|
"description": "List the workspace's integrations with their provider, status and config.",
|
|
441
497
|
"method": "GET",
|
|
@@ -1878,6 +1934,20 @@
|
|
|
1878
1934
|
"read_only": false,
|
|
1879
1935
|
"role": "write"
|
|
1880
1936
|
},
|
|
1937
|
+
{
|
|
1938
|
+
"description": "Post a template, agent text, note or instruction into a conversation, or start one with a person.",
|
|
1939
|
+
"method": "POST",
|
|
1940
|
+
"name": "create_conversation_item",
|
|
1941
|
+
"parameters": {
|
|
1942
|
+
"additionalProperties": true,
|
|
1943
|
+
"description": "Arguments not inlined: call describe_function('create_conversation_item').",
|
|
1944
|
+
"properties": {},
|
|
1945
|
+
"type": "object"
|
|
1946
|
+
},
|
|
1947
|
+
"path": "/v1/conversations/items",
|
|
1948
|
+
"read_only": false,
|
|
1949
|
+
"role": "write"
|
|
1950
|
+
},
|
|
1881
1951
|
{
|
|
1882
1952
|
"description": "Workspace analytics: volume, endings, recordings, response time and spend. One snapshot of a date range, up to 7 days.",
|
|
1883
1953
|
"method": "GET",
|
|
@@ -2046,6 +2116,76 @@
|
|
|
2046
2116
|
"read_only": true,
|
|
2047
2117
|
"role": "read"
|
|
2048
2118
|
},
|
|
2119
|
+
{
|
|
2120
|
+
"description": "Get the workspace's inbound session webhook.",
|
|
2121
|
+
"method": "GET",
|
|
2122
|
+
"name": "get_inbound_webhook",
|
|
2123
|
+
"parameters": {
|
|
2124
|
+
"additionalProperties": true,
|
|
2125
|
+
"description": "Arguments not inlined: call describe_function('get_inbound_webhook').",
|
|
2126
|
+
"properties": {},
|
|
2127
|
+
"type": "object"
|
|
2128
|
+
},
|
|
2129
|
+
"path": "/v1/inbound-webhook",
|
|
2130
|
+
"read_only": true,
|
|
2131
|
+
"role": "read"
|
|
2132
|
+
},
|
|
2133
|
+
{
|
|
2134
|
+
"description": "Set the URL asked for an inbound session's configuration.",
|
|
2135
|
+
"method": "PUT",
|
|
2136
|
+
"name": "set_inbound_webhook",
|
|
2137
|
+
"parameters": {
|
|
2138
|
+
"additionalProperties": true,
|
|
2139
|
+
"description": "Arguments not inlined: call describe_function('set_inbound_webhook').",
|
|
2140
|
+
"properties": {},
|
|
2141
|
+
"type": "object"
|
|
2142
|
+
},
|
|
2143
|
+
"path": "/v1/inbound-webhook",
|
|
2144
|
+
"read_only": false,
|
|
2145
|
+
"role": "write"
|
|
2146
|
+
},
|
|
2147
|
+
{
|
|
2148
|
+
"description": "Remove the inbound session webhook.",
|
|
2149
|
+
"method": "DELETE",
|
|
2150
|
+
"name": "delete_inbound_webhook",
|
|
2151
|
+
"parameters": {
|
|
2152
|
+
"additionalProperties": true,
|
|
2153
|
+
"description": "Arguments not inlined: call describe_function('delete_inbound_webhook').",
|
|
2154
|
+
"properties": {},
|
|
2155
|
+
"type": "object"
|
|
2156
|
+
},
|
|
2157
|
+
"path": "/v1/inbound-webhook",
|
|
2158
|
+
"read_only": false,
|
|
2159
|
+
"role": "write"
|
|
2160
|
+
},
|
|
2161
|
+
{
|
|
2162
|
+
"description": "Issue a new signing secret; the old one stops working at once.",
|
|
2163
|
+
"method": "POST",
|
|
2164
|
+
"name": "rotate_inbound_webhook_secret",
|
|
2165
|
+
"parameters": {
|
|
2166
|
+
"additionalProperties": true,
|
|
2167
|
+
"description": "Arguments not inlined: call describe_function('rotate_inbound_webhook_secret').",
|
|
2168
|
+
"properties": {},
|
|
2169
|
+
"type": "object"
|
|
2170
|
+
},
|
|
2171
|
+
"path": "/v1/inbound-webhook/rotate-secret",
|
|
2172
|
+
"read_only": false,
|
|
2173
|
+
"role": "write"
|
|
2174
|
+
},
|
|
2175
|
+
{
|
|
2176
|
+
"description": "Send a sample request and check the reply against the response schema.",
|
|
2177
|
+
"method": "POST",
|
|
2178
|
+
"name": "test_inbound_webhook",
|
|
2179
|
+
"parameters": {
|
|
2180
|
+
"additionalProperties": true,
|
|
2181
|
+
"description": "Arguments not inlined: call describe_function('test_inbound_webhook').",
|
|
2182
|
+
"properties": {},
|
|
2183
|
+
"type": "object"
|
|
2184
|
+
},
|
|
2185
|
+
"path": "/v1/inbound-webhook/test",
|
|
2186
|
+
"read_only": false,
|
|
2187
|
+
"role": "write"
|
|
2188
|
+
},
|
|
2049
2189
|
{
|
|
2050
2190
|
"description": "The provider catalog: every LLM, STT, TTS, realtime and avatar model that agents may use.",
|
|
2051
2191
|
"method": "GET",
|