Playbooks
A playbook is a set of tasks that leads to a result: the tasks a selection must cover before it is submitted, the order in which they open, the choices between several ways of doing a task, and the tasks that only hold for some selections.
playbooks:
- name: open-company
goal: "open a company: the structure, then (optionally) the accounting"
tasks:
formation: {skill: formation, label: "Your company"}
accounting: {skill: accounting, required: false, label: "Your accounting", after: [formation]}
- name: take-meal-order
goal: "order a meal: the dishes, then pickup or delivery"
tasks:
dishes: {skill: takeMealSelection, label: "Your dishes"}
handover:
label: "Pickup or delivery"
after: [dishes]
one_of: # two methods, one skill: each is one of its kinds
pickup: {skill: takeDeliveryOption, kind: pickup}
delivery: {skill: takeDeliveryOption, kind: delivery}
choose: customer # the person picks (the default)
The goal and the tasks
goalis the result the playbook leads to, in a sentence. It is what the agent sees in order to offer it (start_playbook, its brief). Absent, the playbook's name is shown.tasksare keyed by name: the nameafter,all_ofand$submitted[<task>.<call>]cite, never the skill's.
A task is written in exactly one of these three forms:
| form | meaning |
|---|---|
{skill: x}, or {skill: x, kind: k} | the action of a skill; with kind, of a single kind of that skill |
{one_of: {method: {skill, kind, when, params}}, choose: …} | several methods; only one does the task |
{all_of: [a, b]} | done when a and b are done; a meeting point for after |
And on the task:
| key | meaning |
|---|---|
when | the task only holds if this condition holds (Conditions) — on every form |
required | the playbook cannot be submitted without it — true by default. Not on an all_of |
label | the task's title as the person reads it, in their language: in the stepper and at the head of its lines in the selection. Absent, the skill's name made readable, in English. Not on an all_of |
after | the tasks that must be done before this one opens. Not on an all_of |
params | binds parameters of its skill to what another task filed (A task's params). On the {skill} form and on each method of a one_of; never on the one_of itself nor on an all_of |
An all_of is not a step: it has no title, no place in the stepper, no lines of its own, and it
never blocks the submit. Each task it names says for itself whether it is required.
A skill is the action of a single task of a playbook: a card finds its task by its skill. Two
methods of one one_of may share a skill, as long as each names its own kind. Two playbooks may
give the same task name; only a $submitted[…] written on a skill's call, which holds for the whole
station, refuses a name that designates two different calls (The submit).
Choosing a method — choose
A one_of has at least two methods. Each is the action of a skill (skill), or of a single one
of its kinds (kind), and may carry a when. Only one method does the task.
| value | who chooses |
|---|---|
customer (default) | the person, among the methods whose when holds. The step presents them, each with the tool that shows it; the agent is told to call one or the other, depending on what the person asks for |
rule | the first method whose when holds. The others' lines are refused. If that method's skill is withheld from the station, the task has no method: it is skipped, the next method is not taken in its place |
A method without when is mandatory: it always holds, so the task always has a method. Under
rule, it is the last one.
Conditions — when
A when, on a task or on a method, reads one thing only: $selection.kinds, the kinds of the
lines still in the selection and of what this journey has already filed. It is read as a list, on
the right of in or not in:
wrapping:
skill: gift-wrap
required: false
when: "'gift' in $selection.kinds"
- A task whose
whenis false is skipped: it is not a step, never blocks the submit, and its lines are refused. The tasks placedafterit do not wait on it. If the condition cannot be evaluated, the task holds. - A method only holds if its
whenis true. - A
whendoes not look at its own task's kinds: a task's line is not chosen yet when it is added, so the condition would close it for ever. Condition a task on what comes before it.
A task's params
A skill reads its parameters ($params.<name>) in the args of its submit calls. A task binds
a parameter of its skill to what another task of the same playbook filed:
$submitted[<task>.<call>].<output>.
skills:
- name: repondre
params:
refund_id: {} # no default: only a task sets it
invoke: {method: draftReply}
kinds: {reply: {}}
submit:
- {name: send, tool: sendReply, args: {body.draft: "$item.ref", body.refund_id: "$params.refund_id"}}
playbooks:
- name: ticket
tasks:
geste:
label: "Gesture"
one_of: # each method has a call `pay` that keeps `id`
remboursement: {skill: rembourser}
avoir: {skill: avoir}
reponse:
skill: repondre
label: "Reply"
params: {refund_id: "$submitted[geste.pay].id"}
- The reference makes the order.
reponsewaits forgeste, as ifafter: [geste]were written: a line ofreponseis refused untilgesteis done ("Reply opens once Gesture is done — choose that first"). - A binding is read in its own playbook. Two playbooks may give the same name to different tasks: each reads its own.
- A choice is one reference. Both methods of
gestehave a callpay:$submitted[geste.pay]reads the one that was filed. - At submit, the call of
reponseleaves after the call ofgeste, in the same submit, with its answer. Outside this playbook, the parameter is itsdefault; what the submit does when nothing sets it is in The submit.
How it opens
auto_triggeron a skill: using it opens the playbook.start_playbook: the agent opens it itself, when it judges it is the right journey.
The agent chooses. A playbook without auto_trigger is flagged at load time ("only reachable
through start_playbook").
What it guarantees
-
A task is done when the selection contains an item of a kind of its methods that hold (a method's
kind, else every kind of its skill). This is read from the selection, never from the conversation: the person can stop and come back. A skipped task counts as done for the tasks that wait on it; anall_ofis done when each task it names is. A choice that holds two methods, or a method ruled out, is not done: the journey stays on it. -
The order and the choices, at each choice (
step_open). While the playbook is active, a line is refused, with the reason, in the station's language, and nothing is written, when:- a task of its
afteris not done: "Your accounting opens once Your company is done — choose that first"; - its task does not hold for this selection: "wrapping does not apply to this selection";
- it is of a kind of the skill its task does not take (
kind): "Pickup does not take this choice"; - its method does not hold: "delivery is not available for Pickup or delivery with this selection";
- under
choose: rule, another method is the one: "Pickup or delivery is done by pickup with this selection"; - another method of the task is already in the selection: "Pickup or delivery: pickup is already
in your selection — remove it to take delivery instead". An add that replaces the other method
in its part (
max_items: 1) goes through: the order is checked on the selection as the add leaves it.
What this journey already filed counts as chosen. In the stepper, a waiting task is shown as not available, with the kinds still missing. A task also waits for the tasks its
paramsread. Withoutafterorparams, tasks can be done in any order. - a task of its
-
The submit is blocked, with the reason:
-
as long as a
requiredtask that holds is not done: "Pickup or delivery is required by this order — add pickup or delivery first"; -
as long as the selection keeps a line the submit must not file — chosen before the journey opened, or made wrong by a later choice:
- a line of a task that no longer holds (its
whenturned false after the choice: pickup replaced the delivery a courier message was written for): "Courier message does not apply to this selection"; - a line of a kind its task does not take: "Pickup does not take this choice";
- a method ruled out by the rule or by its
when: "Pickup or delivery is done by pickup with this selection", "delivery is not available for Pickup or delivery with this selection"; - two methods of one choice: "Pickup or delivery takes one choice — keep only one of: pickup, delivery".
The agent reads it too: while it is so, it says what holds the submit and lets the person remove the line, instead of offering to confirm.
- a line of a task that no longer holds (its
A task already filed by a partial submit of this journey stays done — for a choice, the filed method stays its method, whatever the rule or a
whensays afterwards, and another method's line is refused: the rest can be retried. -
-
If the journey's state cannot be read, choosing a line a playbook rule binds and the submit are blocked too, with a sentence that says so ("the order of this flow cannot be checked right now — try again in a moment"): never an order out of sequence or without its required tasks.
These sentences come from Convoy's catalogue, in French or English according to global.language;
the tenant's widget.labels do not change them.
What load refuses
| written | refused because |
|---|---|
| a task with none of the three forms, or several | nobody could tell what it does |
kind without skill, choose without one_of | they apply to nothing |
| a skill or a kind that is not declared | the task would have nothing to show it done |
| a skill in two tasks of the same playbook | a card could not tell which task it belongs to |
| two methods that take the same kind | a line could not tell which method it is |
a one_of with fewer than two methods, or where every method has a when | it is no choice; or a selection could leave no method at all |
under choose: rule, the method without when before another one | the methods after it could never be chosen |
| a method whose skill produces no kind | nothing could show it chosen |
| a required task that nothing produces a kind for | nothing could show it done |
a when that reads anything other than $selection.kinds ($memory, $submitted[…], $read[…], $result[…], $item…), or does not read it as a list | the reason is given: it cannot be read here |
a when that looks for a kind the station does not have | the condition would never hold (or always, with not in) |
a task's or a method's when that looks for a kind of its own task (for an all_of, of the tasks it joins) | the line is not chosen yet when it is added: the task would stay closed, or change between the choice and the submit |
an all_of of fewer than two tasks, that names itself or a missing task | the meeting point would never be reached |
required, label or after on an all_of | it is not a step |
an all_of over tasks ordered between them | they cannot be done together |
an after that names a missing task, or a task nothing can show done | the task would never open |
an after or an all_of that loops | no task of the loop would ever open |
a required task placed after an optional one, directly or through an all_of | it would make the optional one required in practice |
params on a one_of (write them on each method) or on an all_of | they run no skill of their own |
a binding to $read[…] | a read leaves no trace a task can read yet |
a binding to $result[…] | sub-playbooks do not exist yet |
a binding to a fixed value, or to any other $… reference | a fixed value is the skill's default; a task binds only to $submitted[<task>.<call>].<output> |
a binding to a parameter the skill does not declare, or that its invoke.args reads | it would set nothing; or the invoke would read the default while the submit reads the binding |
a binding to a task missing from the playbook, to the task itself, to a call the task does not make, to an output the call does not keep, to a call that is not a request | the reference would resolve empty |
a binding to a task that has a when | it may be skipped: its answer would never exist |
a binding to a one_of with a method that does not make the call | chosen, that method would leave nothing to read |
an after contrary to a binding (geste placed after reponse, which reads it) | the written order contradicts the data |
a required task whose params read an optional task | it would make the optional one required in practice |
a skill parameter without default that no task binds | nothing would set it: every call reading it would be held |
What it does not guarantee yet
- Conditions on anything but the chosen kinds. A
whenreads neither a room fact, nor a total, nor what a task read or filed. For a real data dependency, usedepends_onon the skill: it holds even outside the journey. - Choice by the model. No
choose: clm, nofallback. - What a task sets or starts. No
paramsbound to$read[…]or$result[…]; nodepends_on,on_openorguardson a task; noresult, no playbook-levelsubmit_guard, noactivation, no sub-playbooks. Every tool stays presented to the model, whichever task is open. - Reads (the skills that only answer) cannot be required tasks, nor be cited by an
after: they produce no kind, nothing shows them done.
See Current limits.