The shape
- One
async def run():at the top level, with no parameters — everything it needs is already in scope. - Return a dict. It is kept under the step’s result key for the rest of the run: later steps read a field as
{{key.field}}in messages, as a Code result in conditions and contact updates, and other code steps asx_results["key"]["field"]. - Success or failure. Return
{"status": "error", "message": "..."}to take the Failure exit. Raising, a refused code check and the timeout take it too. Anything else takes Success. - Timeout up to 30 seconds per step (10 by default); a message’s code steps share 60 seconds. Give every network call a shorter timeout of its own.
What is in scope
x_message by what the user sent
x_history
Each message has role (user or assistant), text, type, time, msg_id, media_link, and for replies who sent them: agent_id (the agent), workflow_node (the workflow step), flow_step (the Advanced agent step). Count or search the chat with it instead of keeping state:
update_contact_custom
Writes to the contact of this chat. Keys are your contact attribute names; a name that is not an attribute is skipped and listed in skipped. x_contact and every later step see the new values at once. In Test Chat nothing is saved.
Writing it: Generate with AI, Verify, Test
Every code step is also verified when you press Update (only the ones that changed and were not verified yet), and checked again every time it runs. Code that breaks the rules is never run: the step takes its Failure exit.
What the code checks refuse
- Modules that reach the server:
os,sys,subprocess,socket,pathlib,shutil,importlib,pickle,io,tempfile,multiprocessingand similar — directly or through another module. open,eval,exec,compile,__import__,globals,vars,dir;getattrwith a computed name; dunder attributes.- Environment variables, and the platform’s own packages (
utils,apps,database,redis,pymongo,clickhouse_connect,azure,boto3…). - Hard-coded keys, tokens or passwords — save them in Settings → Secrets and read them with
x_secrets.
Testing safely
In Test Chat, code runs for real, the user’s phone number is0000000000, and contact writes are not saved. Branch on x_context["is_test"] for anything that must not happen in a test — creating a real payment link, booking, messaging someone: