A program is stored
under a name
Save code once. Pass other parameters on the next call. The name lets you reach the same program from an agent, an app or your own script.
What the record contains
| Field | Content |
|---|---|
name | A unique name, for example add_two_numbers_v1. |
description | What the program is for, its input and its result, in English. Helps you find the program. |
code | The program source code. |
cspl | The language or format the handler must understand. For this example: fython. |
kwargs | Default parameters. Values for a specific run are passed separately, in params. |
Save → read → call
- Save the code. Pass the name, description and language to
/api/expert/save. - Read the record back. Call
/api/expert/get. Compare theexpert_codefield with the original text. - Run it with parameters. Pass the name and input values to
/api/expert/run. - Run it again. Change only
params. You do not need to save again.
Use the same profile and agent in the request headers. Otherwise the record may end up outside the scope you search from.
Your first loop from Python
You need Python 3.8 or newer, an access token, the ID of your agent and the ID of a connected device. How to prepare access →
Save the code as first_call.py and run python3 first_call.py in a terminal. The script creates a program with a new random name in your account, checks the saved code and makes two calls. You type the token without it showing on screen; it is not written to a file.
import getpass
import json
import urllib.error
import urllib.request
import uuid
BASE = "https://api.extella.ai"
token = getpass.getpass("Extella API token: ")
agent = input("Agent ID: ").strip()
device = input("Device ID: ").strip()
profile = input("Profile ID [default]: ").strip() or "default"
if not token or not agent or not device:
raise SystemExit("Token, agent and device are required")
headers = {"X-Auth-Token": token, "X-Profile-Id": profile,
"X-Agent-Id": agent, "Content-Type": "application/json"}
def call(endpoint, body):
request = urllib.request.Request(
BASE + endpoint, data=json.dumps(body).encode(), headers=headers)
try:
with urllib.request.urlopen(request, timeout=150) as response:
answer = json.load(response)
except urllib.error.HTTPError as error:
raise SystemExit("HTTP " + str(error.code)) from None
if answer.get("status") in ("error", "failed"):
raise SystemExit("API reported an error; inspect the call in Extella")
return answer
name = "add_two_numbers_" + uuid.uuid4().hex[:12]
source = ("def " + name + "(a: float = 0, b: float = 0) -> dict:\n"
" return {\"total\": a + b}\n")
call("/api/expert/save", {
"name": name, "description": "Add two numbers a and b; return total.",
"code": source, "cspl": "fython", "kwargs": {}, "global": False})
saved = call("/api/expert/get", {"name": name})
if saved.get("expert_code", "").strip() != source.strip():
raise SystemExit("Saved code does not match; nothing was run")
print("Saved:", name)
for params in ({"a": 5, "b": 7}, {"a": 2, "b": 3}):
answer = call("/api/expert/run", {
"expert_name": name, "params": params, "targets": [device]})
print(json.dumps(answer, ensure_ascii=False, indent=2))
if answer.get("task_id"):
print("Deferred task; check its status before another call")
break
Look for total in the run result: first 12, then 5. If you get a task_id back, the work was deferred: check its status.
Changing a program and versions
Do not replace a working program blindly. Keep the original code on your side, make changes under a new name and compare the results on the same input. Only then switch the calling code or the agent.
If the response format changes, check every program and window that reads it. The same name does not guarantee that new results work with old consumers.
Build an application →