Tools — computations and actions

🔵 Engines that execute something: scripts, shell commands, subagents, workflows, as well as result delivery (email, files). For a summary table of all engines, see «Tool Reference».

5.10 script_tool

Rhai or JavaScript script.

kind: script_tool
name: currency
description: Конвертация валют.
script: currency.rhai          # .rhai → Rhai, .js → JavaScript (QuickJS)
parameters: { ... }
max_operations: 10000000

The script defines fn run(args) (Rhai) or function run(args) (JS). Full reference — 07-scripts.


5.14 subagent_tool

Delegate a task to a subagent. Spawns a child agent process, hands over the task, waits for completion and returns its final response. The child's spending is charged to the parent's session (inherits the budget group), followed by cleanup.

kind: subagent_tool
name: delegate_research
description: Делегировать исследование субагенту.
template: trace-agent          # или inline instructions + tools:
# instructions: "You are a research assistant."
# tools: [http_fetch, fs_read]
# budget: { max_per_turn: 2000, max_per_minute: 20000, max_total: 20000 }
Field Description
template template for delegation (takes priority over instructions)
instructions inline instructions without a template
tools names of the subagent's tools (overrides the template)
budget token limit { max_per_turn, max_per_minute, max_total }
output_schema JSON Schema of the structured result (the subagent finishes with job_done; the validated payload — in data)
params string pairs passed to the subagent as template_vars (visible to its tools via ToolContext), e.g. code_root for the code module
allow_params keys that the LLM can set in the params call argument (empty = static only)

Runtime arguments: task (required), optional template/instructions/ params.


ask_user

Asks the user a form (several questions at once) and returns structured answers { "answers": { "<id>": <value> } }. The turn is blocked until a response or timeout.

Types: text, textarea, number, select (radio), multiselect (checkbox), confirm (yes/no), date. For select/multiselect — options: [...]; allow_other: true adds a free-form "custom option".

{ "title": "Настройки проекта",
  "questions": [
    { "id": "os", "type": "select", "label": "ОС?", "options": ["Linux","macOS","Windows"], "allow_other": true },
    { "id": "features", "type": "multiselect", "label": "Фичи", "options": ["a","b"] },
    { "id": "proceed", "type": "confirm", "label": "Продолжить?" }
  ] }

The widget renders native controls; in messengers the questions are shown as text. Module agent_tools.


notify_tool

Draws the user's attention via notification channels. The level level sets the persistence: silent — a quiet line, notify — sound, alert — heads-up, alarm/call — repeat until acknowledged (on Android — alarm / ringtone). channels — any sinks (as in notify: for cron); empty = the event is saved to the message store.

kind: notify_tool
name: notify
description: Привлеки внимание пользователя.
level: alert
require_ack: false
# channels: [ { type: yandex_messenger, chat_id: "user@ya" } ]

Call arguments: title?, body (required), level?, require_ack?. Module agent_tools.


5.16 email_tool

Send an email (SMTP).

kind: email_tool
name: send_report
description: Отправить отчёт оператору.
smtp:
  host: smtp.example.com
  username: agent@example.com
  password_env: SMTP_PASSWORD     # или password: "..."
  from: agent@example.com
  tls: starttls                   # starttls (по умолч., 587) | ssl (465) | none (25)
  port: 587
to: ops@example.com
subject: "Agent report"
Field Description
smtp.host / username / from server, login, From (required)
smtp.password / password_env password inline or env name
smtp.tls starttls (default) | ssl | none
to / subject defaults overridden by arguments

Arguments: body (required), optional to / subject.


5.17 vk_tool

Calling the VK API on behalf of a community (group access token) — a universal gateway plus convenient actions for typical business tasks.

kind: vk_tool
name: vk_api
description: Вызвать VK API от имени сообщества.
token_env: VK_GROUP_TOKEN       # env с group access token (по умолч. VK_GROUP_TOKEN)
service_token_env: VK_SERVICE_TOKEN  # env с сервисным ключом (по умолч. VK_SERVICE_TOKEN)
api_version: "5.199"            # версия API (по умолч. "5.199")
owner_id: -123456789            # дефолтный владелец (для wall_post)
Field Description
token_env env name with the community token (group actions: send_message, wall_post, generic gateway)
service_token_env env name with the service key — for search/read methods (search) unavailable to group tokens
api_version VK API version (default 5.199)
owner_id default owner for wall_post (negative = group)

Two call modes. Generic gateway — any VK API method:

{ "method": "wall.get", "params": { "owner_id": -123456789, "count": 5 } }

Convenient actions (inside, the engine itself substitutes the required random_id and default parameters):

{ "action": "wall_post", "message": "Новый пост от агента" }
{ "action": "send_message", "peer_id": 123, "message": "Привет" }
{ "action": "search", "q": "бренд", "count": 10 }
Action VK method Token What it does
send_message messages.send group message to a dialog (peer_id, message, opt. attachment)
wall_post wall.post group post to the wall (owner_id, message, opt. attachments)
search newsfeed.search service search for posts/mentions (q, count)

Result: content — pretty-JSON of the response, data — parsed response (for composition with visualize_tool). The group token is needed with the permissions messages, wall, photos, docs, market, groups. Read/search methods (newsfeed.search, wall.get, groups.search) are unavailable to group tokens — they require a service key (service_token_env).


5.17.1 ym_tool

Sending messages and working with chats via the Yandex Messenger Bot API (Yandex 360) on behalf of a bot — the outgoing "twin" of the channel.yandex_messenger channel.

kind: ym_tool
name: yandex_messenger
description: Отправить сообщение в Яндекс Мессенджер.
token_env: YANDEX_MESSENGER_BOT_TOKEN  # env с токеном бота (по умолч.)
default_chat_id: ivan                  # опц.: логин или id чата по умолчанию
Field Description
token_env env name with the bot's OAuth token (default YANDEX_MESSENGER_BOT_TOKEN); the token is issued in Yandex 360 → "Bots in Messenger"
default_chat_id default recipient: login (personal chat) or group/channel id with a slash /

The recipient is set in the arguments: login (personal chat), chat_id (group/channel) or to (login, or chat id with a slash /); otherwise default_chat_id is used.

Action What it does
send text to a chat (text; markdown: true converts CommonMark to Messenger markup)
send_markdown same as send with markdown: true
send_file file-document (file — path, base64 or content; name, mime)
send_image image to the feed (file/base64/content)
send_typing show "typing…"
get_updates fetch updates (offset, limit), return updates and next_offset
get_file download a file by file_id (text — inline, binary — base64 + to the session draft)
{ "action": "send", "login": "ivan", "text": "Привет!" }
{ "action": "send", "chat_id": "0/0/4f24b544", "text": "**Отчёт** готов", "markdown": true }
{ "action": "get_updates", "offset": 0 }

Result: content — pretty-JSON, data — structured response ({ "sent": n, "recipient": "..." } for sending).


5.18 shell_tool

Run a CLI command. Universal launch of an external program: the command, flags, working directory and environment are fixed in YAML by the agent's author; the LLM merely substitutes values into input. Unlike an arbitrary fs_read, the LLM does not choose the command — it only chooses the arguments according to a given JSON Schema.

kind: shell_tool
name: git_log
description: Показать последние коммиты репозитория.
command: git
args: ["log", "--oneline", "-n", "{{ input.limit | default(10) }}"]
cwd: /srv/agent-os          # рабочая папка (по умолч. — папка сервера)
env:
  GIT_PAGER: "cat"          # доп. переменные окружения
stdin: "{{ input.text }}"   # текст в stdin (опционально)
timeout_secs: 30            # жёсткий таймаут (по умолч. 30)
capture: both               # stdout | stderr | both (по умолч.)
parse_json: false           # распарсить stdout как JSON в data.parsed
parameters: { ... }         # JSON Schema входа агента
Field Required Description
kind yes shell_tool
name yes name for the LLM
description no description for the LLM
command yes program (MiniJinja template over input)
args no list of arguments (each is a template)
cwd no working directory (template)
env no additional environment variables (values are templates)
stdin no text fed to stdin (template)
timeout_secs no timeout (default 30)
capture no which streams to return: stdout | stderr | both
parse_json no parse stdout as JSON into data.parsed

The command inherits the server's environment + env, and is executed with a time limit. Result: content — captured output, success — zero exit code, data — { exit_code, stdout, stderr, parsed? }.

All string fields are MiniJinja templates over input. If logging.temp_dir is set on the server, the variable {{ temp_dir }} is available in templates — the scratch directory of the current session, where you can generate a file (see file_tool with source temp).


5.19 workflow_tool

Run a workflow.

kind: workflow_tool
name: run_triage
description: Запустить воркфлоу триажа.
workflow: triage            # имя воркфлоу по умолчанию

Runs a workflow and returns its run id. The workflow name can be overridden with the workflow argument; input — the input payload. Requires that WorkflowService be connected in the core (done at server startup). See 12-workflows.


5.20 file_tool

Send a file to the user. Sends the user a file (report, document, data export) as a downloadable file block. The agent usually does not have access to the file system, so the content is taken from one of the sources:

kind: file_tool
name: send_file
description: Отправить файл пользователю.
max_bytes: 10485760   # макс. размер файла в байтах (по умолч. 10 МиБ)
Argument Description
name file name for download (required), e.g. report.html
mime MIME type (optional; inferred from the extension name)
content content as a string (markdown / HTML / CSV / JSON…)
data any JSON — serialized to a file (pretty JSON)
path read bytes from a local file (if the agent can write files)
temp { name } — read a file that another tool wrote to the session's scratch directory
state { key, scope?, path? } — a value from the state store (DB). scope: session/user/agent (default resolves user → session → agent); path — dot path into the value
source { tool, index, field, path } — the result of another tool in this session. field: content (default)/data/visual; index: 0 = last

The source is selected by priority content → data → path → temp → state → source. Example of a report assembled from the result of a previous tool:

# вызвать: send_file { "name": "report.csv", "source": { "tool": "build_report" } }

The LLM sees only a compact summary in content; the bytes themselves (base64) travel in visual and reach the web widget (download link), Android and Telegram (document).

Session scratch storage

If logging.temp_dir is set in the configuration, the core allocates each session a scratch directory <temp_dir>/<session_id>/. A generator tool (e.g. shell_tool, which runs an office CLI) writes a file there via {{ temp_dir }}, and file_tool retrieves it by name:

# shell_tool: нагенерить .xlsx в scratch сессии
kind: shell_tool
name: export_xlsx
description: Сгенерировать отчёт в Excel.
command: libreoffice
args: ["--headless", "--convert-to", "xlsx", "--outdir", "{{ temp_dir }}", "{{ input.docx }}"]

# вызвать: send_file { "name": "report.xlsx", "temp": { "name": "report.xlsx" } }

The directory is deleted when the session is closed/expires.


5.21 office_tool

An engine wrapper over OfficeCLI (a single self-contained binary, MS Office not needed). On first use the binary is downloaded automatically into data/officecli/ and verified by SHA-256; after that it is cached. The finished file is written to the session's scratch and returned as a file block (like file_tool) — no external shell_tool wrappers are needed.

kind: office_tool
name: make_docx
description: Собрать Word-документ из Markdown.
operation: create          # create | fill | extract | convert | edit | merge
format: docx               # docx | xlsx | pptx (для create/merge)
# template: templates/contract.docx   # для fill: путь к шаблону (отн. YAML)
# binary: /path/to/officecli         # опц. явный путь к бинарю
# download_url: "https://..."        # опц. переопределение
# sha256: "..."                      # опц. (пусто = не проверять)
# auto_download: true                # по умолч. true
# pdf_bin: soffice                   # fallback для PDF (если нет плагина)
# pdf_exporter: /path/to/officecli_pdf_exporter  # опц. явный путь к плагину
# timeout_secs: 120                  # таймаут одной команды

Operations

operation What it does Arguments
create build a document from scratch name + content (docx, Markdown) / rows+columns or csv (xlsx) / slides (pptx)
fill fill a template with {{key}} placeholders name + data (object) or rows (array → mail merge, result is a zip)
extract read a document as text/CSV for the LLM temp/path + optional mode (text/outline/annotated/issues/csv)
convert export to HTML/SVG/PDF name (.html/.svg/.pdf) + temp/path
edit apply edits set/add/remove/replace name + temp/path + ops: [{ action, path, type?, props?, find?, replace? }]
merge merge several documents into one name + `files: [{ temp

Template placeholders (fill)

The template uses double curly braces {{key}} — in paragraphs, tables, headers/footers, and chart titles. Filling is a officecli merge:

# вызвать: fill_contract { "name": "dogovor.docx", "data": { "client": "ООО Ромашка", "sum": "150000" } }
# вызвать (mail merge): fill_contract { "name": "dogovor.docx", "rows": [ {...}, {...} ] }
#   → вернёт dogovor.zip с N заполненными файлами

A template .docx with placeholders can be produced yourself from Markdown: make_docx → contract.md with text of the form {{client}}.

Editing (edit)

edit copies the input document to the output and applies the list of edits (the source is not modified). Each edit is a { action, path, ... }:

# вызвать: edit_doc { "name": "edited.docx", "temp": { "name": "in.docx" },
#   "ops": [
#     { "action": "replace", "path": "/body", "find": "ООО Старое", "replace": "ООО Новое" },
#     { "action": "set",     "path": "/body/p[1]/r[1]", "props": { "bold": true } },
#     { "action": "add",     "path": "/body", "type": "paragraph", "props": { "text": "Новый абзац" } },
#     { "action": "remove",  "path": "/body/p[3]" }
#   ] }

Actions: set (properties via --prop), add (element --type), remove, replace (find/replace text via --find/--replace). path — the address of an OfficeCLI element (/body/p[1], /Sheet1/A1, /slide[1]/shape[1], …).

Examples (full set)

A ready-made "secretary" agent is in config/agents/office/ — it also contains all these tools and the contract template templates/contract.docx. Below are excerpts.

1. create — document from scratch

# tools/make_docx.yaml
kind: office_tool
name: make_docx
description: Собрать Word из Markdown.
operation: create
format: docx
// вызов: { "name": "report.docx", "content": "# Отчёт\n\nТекст..." }
# tools/make_xlsx.yaml
kind: office_tool
name: make_xlsx
description: Собрать Excel из таблицы.
operation: create
format: xlsx
// вызов: { "name": "price.xlsx", "columns": ["Name","Price"], "rows": [["Apple",3],["Banana",5]] }

2. fill — template with {{key}} + mail merge

# tools/fill_contract.yaml
kind: office_tool
name: fill_contract
description: Заполнить договор данными.
operation: fill
format: docx
template: ../templates/contract.docx   # путь отн. этого YAML
// один документ: { "name": "dogovor.docx", "data": { "client": "ООО Ромашка", "sum": "150000" } }
// mail merge:    { "name": "dogovor.docx", "rows": [ { "client": "A" }, { "client": "B" } ] }
//   → вернёт dogovor.zip с N заполненными файлами

3. extract — reading (text or CSV)

kind: office_tool
name: extract_text
description: Прочитать документ текстом.
operation: extract
// { "temp": { "name": "dogovor.docx" } }              → текст
// { "temp": { "name": "price.xlsx" }, "mode": "csv" }  → CSV

4. convert — HTML / SVG / PDF

kind: office_tool
name: convert_pdf
description: Экспорт в PDF.
operation: convert
// { "name": "out.html", "temp": { "name": "in.docx" } }
// { "name": "out.pdf",  "temp": { "name": "in.docx" } }   // плагин + headless Chromium

5. edit — targeted edits

kind: office_tool
name: edit_doc
description: Внести правки в документ.
operation: edit
// { "name": "out.docx", "temp": { "name": "in.docx" }, "ops": [
//     { "action": "replace", "path": "/body", "find": "старое", "replace": "новое" } ] }

6. merge — merge documents

kind: office_tool
name: merge_docs
description: Объединить документы в один.
operation: merge
format: docx           # docx — склейка текста; xlsx — конкатенация строк
// { "name": "all.docx", "files": [ { "temp": { "name": "a.docx" } }, { "temp": { "name": "b.docx" } } ] }

Formats and limitations


5.24 storage_tool

Access to external file storage: S3-compatible object storage (AWS S3, MinIO, Yandex Object Storage, Cloud.ru), WebDAV (Nextcloud, ownCloud), and FTP/FTPS. Operations list / get / put / delete, scope — optional prefix. Secrets — from env.

kind: storage_tool
name: upload_report
description: Выгрузить отчёт в объектное хранилище.
storage:
  backend: s3               # s3 | webdav | ftp
  endpoint: https://s3.example.com
  bucket: reports
  region: us-east-1
  access_key_env: S3_ACCESS_KEY
  secret_key_env: S3_SECRET_KEY
  path_style: true          # по умолч. true (MinIO-стиль)
prefix: uploads/            # опц. базовый префикс (скоуп агента)
operation: put              # опц.: list | get | put | delete

Backends

backend Fields Note
s3 endpoint, bucket, region, access_key_env, secret_key_env, path_style? any S3-compatible service
webdav base_url, username_env, password_env base_url — file root (e.g. …/remote.php/dav/files/user/)
ftp host, port?, username_env, password_env, tls? tls: none | explicit (FTPS, default)

Operations

operation Purpose Parameters
list list files under a prefix prefix (additional sub-prefix)
get download a file key → text in content + file block
put upload a file key + content/data/path/temp
delete delete a file key

Without operation, the operation is selected by the operation argument (default list). get returns the content as text (if it is text ≤ 20 thousand characters) and always as a file block in visual; list returns an array of {key, size, last_modified} in data + a table.


5.25 calendar_tool

Reading and managing Google Calendar on behalf of a service account (2-legged OAuth — JWT bearer, without interactive consent). The engine itself exchanges the service account key for an access token (with a TTL cache) and calls the Google Calendar API v3.

kind: calendar_tool
name: calendar
description: Читать и управлять календарём.
credentials_file: data/google-calendar/service_account.json  # путь к JSON-ключу
# credentials_env: GOOGLE_SERVICE_ACCOUNT_JSON  # или env с JSON-текстом (по умолч.)
# credentials: { ... }                          # или inline-объект (не рекомендуется)
calendar_id: petrochenko.pavel.a@gmail.com      # дефолтный календарь (перекрывается аргументом)
Field Description
credentials_file path to the service account JSON key (takes priority over the others)
credentials_env name of the env with the key JSON text (default GOOGLE_SERVICE_ACCOUNT_JSON)
credentials inline key (not recommended — keep secrets in a file/env)
calendar_id default calendar id (overridden by the calendar_id argument)

Secrets are not kept in YAML. Key resolution order: credentials_file → credentials → env credentials_env.

Actions (the action argument):

Action API method What it does
list_calendars calendarList.list list the service account's calendars
list events.list events in a range (time_min/time_max, max_results, q)
get events.get a single event (event_id)
create events.insert create an event (summary, start, end, location, description, attendees)
update events.update modify an event (event_id + the same fields)
delete events.delete delete an event (event_id)
quick_add events.quickAdd create an event from free text (text)
{ "action": "list", "time_min": "2026-09-07T00:00:00Z", "max_results": 20 }
{ "action": "create", "summary": "Созвон", "start": "2026-09-10T15:00:00+03:00", "end": "2026-09-10T16:00:00+03:00" }
{ "action": "quick_add", "text": "Ужин завтра в 19:00" }

start/end accept an RFC3339 string (→ dateTime) or an object { dateTime, timeZone } / { date } (all-day event). A full event can be passed as an event object. Generic gateway: method (in ресурс.действие notation)

{ "method": "events.list", "params": { "timeMin": "2026-09-07T00:00:00Z" } }
{ "method": "calendars.insert", "body": { "summary": "Рабочий календарь" } }

Supported methods: calendarList.list, events.list/get/insert/ update/delete/quickAdd, calendars.insert/delete, freebusy.query.

Result: content — pretty-JSON of the response, data — the parsed response (for composition with visualize_tool).

Setting up access

  1. Create a service account (or take an existing JSON key) and enable the Google Calendar API in the project (Cloud Console → API Library).
  2. Give the service account access to the calendar: calendar settings → "Share with specific people" → add client_email with "Make changes to events" permission.
  3. Specify calendar_id — usually the owner's email (name@gmail.com) or xxx@group.calendar.google.com (the "Calendar ID" field in the settings).

Nuance: list_calendars for a service account may return an empty list — it has no calendars "of its own", and calendars shared into calendarList are not added automatically. Work directly via calendar_id (set in the config or the argument).


5.26 google_tool

Reading and managing Google Drive / Sheets / Docs / Slides. Two authorization modes: service account (2-legged OAuth / JWT) — suitable only for reading; and user OAuth — for reading and writing (with the real account's quota). One google_tool instance works with one service (the service field); for multiple services, connect multiple tools.

kind: google_tool
name: gdrive
description: Обзор и управление Google Drive.
service: drive               # drive | sheets | docs | slides
auth: oauth                  # oauth (рекомендуется) | service_account
oauth:
  client_id: 123-abc.apps.googleusercontent.com
  client_secret_env: GOOGLE_OAUTH_CLIENT_SECRET
  token_file: data/google-oauth/drive_token.json
# для service_account (только чтение):
# credentials_file: data/google-calendar/service_account.json
# scopes: ["https://www.googleapis.com/auth/drive.file"]  # опц. переопределение
Field Description
service target service: drive | sheets | docs | slides
auth oauth (not set by default — service_account) | service_account
oauth.client_id / client_id_env OAuth client id (inline or env)
oauth.client_secret / client_secret_env OAuth client secret (env)
oauth.token_file file where the refresh token is stored after authorize_code
oauth.redirect_uri redirect URI (default — OOB copy-paste)
credentials_file / credentials_env / credentials service account key (same as calendar_tool)
scopes optional override of OAuth scopes

User authorization (OAuth)

A one-time step, performed through the tool itself:

  1. Call the authorize action — a consent URL will be returned.
  2. Open the URL, sign in to Google, and grant access.
  3. Copy the code and call authorize_code with the code field — the refresh token will be saved to token_file.
{ "action": "authorize" }
{ "action": "authorize_code", "code": "4/0A..." }

After that, the tool refreshes the access token automatically using the refresh token.

Each service supports a generic gateway method (notation ресурс.действие)

Actions by service

Drive (service: drive):

Action API method What it does
list files.list list files (q, page_size)
get files.get file metadata (file_id)
create_folder files.create create folder (name, opt. parents)
upload files.create (multipart) upload file (name, content, mime_type, parents)
export files.export export a Google file to a format (file_id, mime_type, opt. name)
download files.get?alt=media download file contents (file_id, opt. name)
delete files.delete delete file (file_id)

export/download return text (text) for text formats, and binary (PDF/DOCX/XLSX) — as base64 + a file in the session scratch directory (for file_tool).

Sheets (service: sheets):

Action API method What it does
create spreadsheets.create create spreadsheet (title)
get spreadsheets.get spreadsheet metadata (spreadsheet_id)
read spreadsheets.values.get read range (spreadsheet_id, range)
write spreadsheets.values.update write range (spreadsheet_id, range, values)
append spreadsheets.values.append append rows (spreadsheet_id, range, values)
import values.update write CSV (csv) or an array (values) into a range
export values.get export a range as csv or json (format)
add_chart batchUpdate embedded chart (range, title, chart_type: COLUMN/BAR/LINE/PIE/AREA)

Docs (service: docs):

Action API method What it does
create documents.create create document (title)
import create + batchUpdate create a document with text (title, content)
build create + batchUpdate build a document from blocks (title, blocks)
export documents.get extract document text (document_id)
get documents.get raw document JSON (document_id)
insert_text documents.batchUpdate insert text (document_id, text, opt. index)

build builds a document from structured blocks with styles:

{ "action": "build", "title": "Отчёт", "blocks": [
    { "type": "heading", "text": "Раздел", "level": 1 },
    { "type": "paragraph", "text": "Жирный синий", "style": { "bold": true, "color": "#0000FF", "fontSize": 14, "align": "CENTER" } },
    { "type": "bullet", "items": ["a", "b"] },
    { "type": "numbered", "items": ["раз", "два"] },
    { "type": "table", "rows": [["Имя", "Значение"], ["alpha", 1]] },
    { "type": "image", "url": "https://…/img.png" },
    { "type": "page_break" }
] }

style supports bold/italic/underline/strikethrough, color (#RRGGBB), background_color (#RRGGBB), font (font name, e.g. Arial, Times New Roman), weight (400=normal, 700=bold), fontSize (pt), align (START/CENTER/END/JUSTIFIED), lineSpacing.

Slides (service: slides):

Action API method What it does
create presentations.create create presentation (title)
build create + batchUpdate build a presentation from slides (title, slides)
add_slide batchUpdate add slide (presentation_id, title, bullets)
outline presentations.get simplified text outline of slides
export files.export export to PDF (presentation_id, opt. mime_type)
get presentations.get raw presentation JSON
{ "action": "build", "title": "Презентация", "slides": [
    { "title": "Титул", "bullets": ["пункт 1", "пункт 2"] },
    { "title": "Картинка", "image": { "url": "https://…/img.png" } }
] }

Universal request batching

The batch_update action is a universal primitive: pass a raw list of requests and it will be applied to the target resource (document_id / presentation_id / spreadsheet_id):

{ "action": "batch_update", "document_id": "<id>", "requests": [
    { "insertText": { "text": "hi\n", "location": { "index": 1 } } },
    { "updateTextStyle": { "range": { "startIndex": 1, "endIndex": 3 }, "textStyle": { "bold": true }, "fields": "*" } }
] }

This is an escape hatch for any operation not covered by the convenient actions (the same effect is achieved by method: documents.batchUpdate + body: {requests: [...]}).

API limitations

Example calls:

{ "action": "list", "q": "name contains 'report'", "page_size": 20 }
{ "action": "upload", "name": "notes.txt", "content": "hello", "mime_type": "text/plain", "parents": ["<folder_id>"] }
{ "action": "export", "file_id": "<id>", "mime_type": "application/pdf", "name": "report.pdf" }
{ "action": "import", "spreadsheet_id": "<id>", "range": "A1:C4", "csv": "a,b,c\n1,2,3\n" }
{ "action": "export", "document_id": "<id>" }
{ "action": "build", "title": "Отчёт", "blocks": [ ... ] }

Generic gateway (for non-standard methods):

{ "method": "files.list", "params": { "q": "mimeType='application/vnd.google-apps.folder'" } }
{ "method": "spreadsheets.values.get", "spreadsheet_id": "<id>", "range": "Sheet1!A1:D10" }
{ "method": "documents.get", "document_id": "<id>" }
{ "method": "presentations.get", "presentation_id": "<id>" }

Supported methods: files.list/get/create/delete/copy, permissions.list/create, spreadsheets.create/get/values.get/ values.update/values.append/batchUpdate, documents.create/get/ batchUpdate, presentations.create/get/batchUpdate.

Result: content — pretty JSON of the response, data — the parsed response.

Setting up access

  1. Enable the required APIs (Drive / Sheets / Docs / Slides) in the Cloud Console.
  2. For OAuth mode (write): create an OAuth client ID (type "Desktop app"), specify client_id/client_secret, go through authorize → authorize_code.

Important about the service account. It has no Drive quota of its own — it cannot upload/create files (storage quota exceeded / caller does not have permission) even in shared folders (the service account still becomes the file owner). Therefore, for writing, use OAuth mode; a service account is only suitable for reading shared files.

{ "action": "upload", "name": "report.csv", "content": "a,b\n1,2", "mime_type": "text/csv" }
{ "action": "create", "title": "Отчёт" }

5.26.1 yandex_tool

Working with Yandex services (Disk and Calendar) on behalf of a real Yandex account via 3-legged OAuth2. Yandex has no service accounts, so authorization is always user-based: a one-time authorize step → authorize_code saves the refresh token to token_file, after which access tokens are refreshed automatically. One instance of yandex_tool works with one service (the service field).

kind: yandex_tool
name: yandex_disk
description: Обзор и управление Яндекс.Диском.
service: disk               # disk | calendar
oauth:
  client_id: "…"            # id приложения (inline или client_id_env)
  client_secret_env: YANDEX_OAUTH_CLIENT_SECRET
  token_file: data/yandex-oauth/disk_token.json
# email: you@yandex.ru      # обязателен для calendar (путь CalDAV)
# scopes: ["cloud_api:disk.read", ...]   # опц. переопределение
Field Description
service target service: disk | calendar
email Yandex email of the account — required for calendar (path …/calendars/{email}/events-default/)
calendar name of the calendar collection for CalDAV (default events-default)
oauth.client_id / client_id_env OAuth client id (inline or env)
oauth.client_secret / client_secret_env OAuth client secret (env; may be omitted for public apps)
oauth.token_file file where the refresh token is stored after authorize_code
oauth.redirect_uri redirect URI — must match the app's Callback URL (for "API access" apps this is https://oauth.yandex.ru/verification_code)
scopes optional override of OAuth scopes

Authorization (one-time step, via the tool itself):

{ "action": "authorize" }
{ "action": "authorize_code", "code": "…" }

Disk (service: disk)

Base URL https://cloud-api.yandex.net/v1/disk, header Authorization: OAuth <token> (not Bearer). Actions:

Action API method What it does
info GET /disk Disk info (capacity, limits)
list GET /resources folder contents (path, default /; limit/offset/sort)
get GET /resources resource metadata (path)
create_folder PUT /resources create folder (path)
delete DELETE /resources delete (path, opt. permanently)
copy POST /resources/copy copy (from, path, opt. overwrite)
move POST /resources/move move (from, path, opt. overwrite)
upload GET /resources/upload → PUT href upload file (path, content)
download GET /resources/download → GET href download file (path, opt. name)
publish / unpublish `PUT /resources/publish unpublish`
files GET /resources/files flat list of all files (limit/offset)
last_uploaded GET /resources/last-uploaded most recently uploaded files

upload performs a two-step upload (first obtains a temporary href from the API, then PUT the contents there). download is likewise two-step and returns text (text) for text formats, and binary ones as base64 + a file in the session's scratch directory.

Calendar (service: calendar)

Yandex has no public Calendar REST API — it works over the CalDAV protocol (RFC 4791) at https://caldav.yandex.ru. The token is passed in the same header Authorization: OAuth <token>; for REPORT/PROPFIND you need Content-Type: text/xml, for events — text/calendar. The email field is required (the path …/calendars/{email}/events-default/ is built from it).

Action CalDAV What it does
list_calendars — default calendar (Yandex has only one)
list REPORT (calendar-query) events in a range (from/to RFC3339, opt. limit)
get GET …/{uid}.ics a single event (uid)
create PUT …/{uid}.ics create event (summary, start, end, location, description; uid is auto-generated)
update PUT …/{uid}.ics overwrite event (uid + fields)
delete DELETE …/{uid}.ics delete event (uid)

start/end accept an RFC3339 string (→ UTC), a YYYY-MM-DD string (all-day event), or a { dateTime, timeZone } object. An event is identified by the uid field (or the event_id alias).

{ "action": "list", "from": "2026-09-01T00:00:00Z" }
{ "action": "create", "summary": "Созвон", "start": "2026-09-10T15:00:00+03:00", "end": "2026-09-10T16:00:00+03:00" }
{ "action": "delete", "uid": "agent-os-abc123" }

Generic gateway

For non-standard Disk calls: method + params (query) + body. Examples: resources, resources.download, resources.upload, resources.copy, resources.move, resources.files.

{ "action": "list", "path": "/documents" }
{ "action": "upload", "path": "/report.csv", "content": "a,b\n1,2" }
{ "action": "create", "summary": "Созвон", "start": "2026-09-10T15:00:00+03:00", "end": "2026-09-10T16:00:00+03:00" }
{ "method": "resources", "params": { "path": "/" } }

Setting up access

  1. Register an application at oauth.yandex.ru (type "Web services" for a client_secret, or "For API access").
  2. Specify the required permissions: for Disk — cloud_api:disk.read / write / info, for Calendar — calendar:all.
  3. redirect_uri (oauth.redirect_uri) must match the application's Callback URL. For "For API access" applications this is a fixed value https://oauth.yandex.ru/verification_code.
  4. Complete authorize → authorize_code, the refresh token will be saved in token_file.

5.27 vision_tool

Image analysis by a vision model (deepseek-v4-flash-vision-exp): OCR, description, answering a question about an image. The tool accepts one or more images, sends them to the model, and returns text. Tokens (including image tokens) are charged to the calling agent's budget through the core's LLM service.

kind: vision_tool
name: vision
description: Прочитать текст / описать / ответить на вопрос по картинке(ам).
model: vision                 # именованная модель из server.yaml → models:
prompt: "Transcribe all text visible in the image(s) verbatim, in reading order."
detail: auto                  # low | high | original | auto
max_tokens: 2048
Field Description
model named model (provider) from server.yaml → models: (default vision)
prompt default prompt (overridden by the prompt argument)
detail low | high | original | auto
max_tokens response limit (default 2048)

Arguments: images (array of strings, required), prompt?, detail?.

Each element of images is an http(s) URL, a data:image/...;base64,..., or a path to a local file (absolute or relative to the session's scratch directory; it is read and encoded in base64). Example call:

{ "images": ["https://example.com/shot.png"], "prompt": "Что за ошибка на скрине?" }

The result is content with the model's response.

5.28 request_attachment

Requesting an attachment from the user right during the agent's operation (not via widget buttons): the agent calls the tool, the core sends an input_request event to the channel, the channel shows a prompt, the user attaches a file / takes a screenshot / photo — and the run continues. The uploaded file lands in the session's scratch directory, and the tool returns its name — after that it can be read (vision_tool by name, file_tool, etc.).

Works in interactive channels: web chat (the widget shows a prompt card), Telegram, VK, and Yandex Messenger (the bot sends a message "send a file/photo", and the user's reply with media resolves the request). In batch channels (cron/email/webhook) there is no UI — the call will end with a timeout.

kind: request_attachment
name: request_image
description: Попросить пользователя прислать файл, скриншот или фото.
prompt: "Пожалуйста, прикрепите файл, сделайте скриншот или фото."
timeout_secs: 300
Field Description
prompt default text shown to the user (overridden by the description argument)
timeout_secs how long to wait for a response (default 300)

Arguments: kind (file | screenshot | photo), description?, timeout_secs?.

The result is content with JSON of the form {"kind":"screenshot","files":[{"name":"screenshot-....png","mime":"image/png","size":12345}]}.

5.28.1 oauth_connect

Asks the user to authorize access to a connector (an OAuth-protected external API — Google Drive, Yandex.Disk, etc., config connectors: in §3). The agent calls the tool, the core sends an input_request event to the channel with the authorization URL, the user opens it and grants consent; the callback /v1/connectors/callback exchanges the code, saves the token (per-user, encrypted), and resolves the request — the run continues.

kind: oauth_connect
name: oauth_connect
description: Попросить пользователя авторизовать доступ к коннектору.
timeout_secs: 300

Arguments: connector (connector name), timeout_secs?. The result is JSON {"connector":"gdrive","granted":true}.

5.28.2 connector_request

An authenticated HTTP request through the connector on behalf of the user (the token is looked up by user_id, and if expired — auto-refreshed via refresh_token).

kind: connector_request
name: connector_request
description: Сделать авторизованный запрос через коннектор.

Arguments: connector, method (GET/POST/PATCH/DELETE/…), url, body? (JSON/text). The result is the response body (content); on error — Error: <status>: <body>.

5.28.3 await_event

Suspend the run and wait for an external event: a callback POST /v1/events/callback (source webhook) or a timer (source cron). This is a generalized primitive "wait until something happens externally" — unlike request_attachment (waits for a file) and oauth_connect (waits for OAuth), here an arbitrary external trigger is awaited.

kind: await_event
name: wait_payment
description: Дождаться подтверждения оплаты по correlation id.
timeout_secs: 600
event:
  source: webhook         # webhook (default) | cron
  id_pointer: /object/id  # где id в теле коллбэка (default /id)
  # id_query: payment_id  # либо query-параметр (взаимоисключает id_pointer)
Field Description
event.source webhook (default) — wait for a callback; cron — timer
event.id_pointer JSON-pointer → correlation id in the callback body (default /id)
event.id_query name of the query parameter (mutually exclusive with id_pointer)
event.delay_secs for source: cron — how many seconds to wait
timeout_secs how long to wait for the event (default 600)

source: webhook: argument event_id (required) — the id we are waiting for. While the run is suspended, input_request is sent to the channel; the external system sends POST /v1/events/callback { ... } (auth — events.token_env), the core matches the callback by id (via event.id_pointer/id_query) and resolves the run. The result is {"event_id":"...","payload":{...}}.

source: cron: argument delay_secs — simply wait N seconds and continue.

5.28.4 async_action

A complete declarative asynchronous flow start → prompt → suspend → callback → resume: first an HTTP request creates a resource (a payment, etc.), then from its response the correlation id and the URL to display are extracted, and the run is suspended until the callback.

kind: async_action
name: sbp_payment
description: Принять оплату по СБП и дождаться подтверждения.
parameters:
  type: object
  properties: { amount: { type: string } }
  required: [amount]
start:                 # поля как у rest_tool (method/url/json/headers/oauth2/sign)
  method: POST
  url: "https://api.yookassa.ru/v3/payments"
  json: { amount: { value: "{{ amount }}", currency: "RUB" }, capture: true }
  headers:
    Authorization: "Basic {{ (env_var('YOOKASSA_SHOP_ID') ~ ':' ~ env_var('YOOKASSA_SECRET_KEY')) | base64 }}"
prompt:
  message: "Оплатите по QR:"
  url_pointer: /confirmation/confirmation_url
resolve:
  id_pointer: /id
callback:
  id_pointer: /object/id
timeout_secs: 600
Field Description
start HTTP initiator request (fields as in rest_tool/site_tool)
prompt.message text shown to the user
prompt.url_pointer JSON-pointer → URL in the response start (the channel shows a button/link)
resolve.id_pointer JSON-pointer → correlation id in the response start
callback.id_pointer / callback.id_query where the id is in the callback (default /id)

Flow: start is executed by the site_tool engine (and its template rendering/authorization), the id/url are extracted from the response, then the same suspend/resume as in await_event (route /v1/events/callback). The result is {"event_id":"...","payload":{...}}.

5.28.5 show_link

Show the user a link as a button (in the widget, clicking opens a window with the link; in messengers, a link in the message/button). By itself it waits for nothing and does nothing — it simply presents a URL.

kind: show_link
name: open_link
description: Показать пользователю ссылку.
wait: false       # true — показать «Открыть» + «Готово» и ждать подтверждения
timeout_secs: 300
Field Description
wait false (default) — show and return control; true — wait for user confirmation ("Done")
timeout_secs how long to wait for confirmation (only with wait: true)

Arguments: url (required), message?, wait? (overrides the config). The result is {"shown":true} (or {"shown":true,"confirmed":true} with wait: true).

5.28.6 escalate_to_operator

Hand the dialog over to a live operator (agent-initiated escalation). The agent calls the tool, the core opens an escalation and sends a card to the operator in the configured channels (approval.operator_notify in server.yaml — Yandex Messenger / Telegram / webhook). The operator writes /accept, communicates with the user, and finishes with the /release command; if idle for longer than timeout_secs, control returns to the agent with timeout_message. The same mechanism exists in the escalate hook (see hooks).

kind: escalate_to_operator
name: escalate_to_operator
description: Передать диалог живому оператору.
contact: |
  📞 +7 (383) 363-40-37
  ✉️ priem@nsu.ru
connecting_message: "Соединяю вас с оператором, пожалуйста, подождите…"
unavailable_message: "Оператор сейчас недоступен.\n{contact}"
context_messages: 12
Field Description
contact contact that the agent gives the user if the operator is unavailable
connecting_message message to the user when the escalation opens
unavailable_message text for the unavailable operator; {contact} is substituted from contact
context_messages how many recent session messages to attach to the operator card (0 = no history)

Arguments: reason (off_topic | empty_answer | user_requested | other), question?. The result is content with JSON {"status":"escalated","request_id":"…","message":"…"} or {"status":"unavailable","contact":"…"} (then the agent itself gives the contact). Works in interactive channels (web widget, Telegram, VK, Yandex Messenger); the operator's replies reach the user in their channel (web — in the same SSE stream).

Operator channels

The card is sent to the channels from config/server.yaml → approval.operator_notify (the same list as for action approvals — see approvals). Empty = operators are not notified.

# config/server.yaml
approval:
  operator_notify:
    - type: yandex_messenger
      chat_id: "pawelpetrochenko"      # логин оператора; для группового чата — id со слэшем
      token_env: YANDEX_MESSENGER_BOT_TOKEN
    - type: telegram
      chat_id: -100123456789            # приватный чат или группа операторов
      token_env: TG_OPERATOR_TOKEN
    - type: webhook
      url: https://ops.example.com/escalations
      token_env: OPS_WEBHOOK_TOKEN      # необязательно

Secrets — only via token_env (variables from .env), not in YAML.

Channel Card delivery How the operator replies
yandex_messenger sendText to a personal chat/chat_id text in the chat: /accept, messages, /release
telegram card with inline buttons "✅ Take over" / "↩️ Return to bot" buttons or text /accept, /release
webhook POST JSON of the escalation event (bearer from token_env) notification only; reply — via the messenger

Operator commands: /accept [id] — take over the dialog; /release [id] (also /agent, !bot) — return control to the agent; any other text goes to the user. The operator's replies are delivered to the user's channel (web — in the same SSE stream). If idle for longer than timeout_secs, the escalation is closed and timeout_message is sent to the user.

Approvals and escalations share a single approval.operator_notify: one bot serves both, a shared long-poll getUpdates. If the operator has previously written to the bot, they will receive the card in the same chat.

5.29 image_tool

Image processing directly on the server (without a vision model): cropping, resizing, grayscale, rotate/flip, brightness/contrast/blur, and format conversion. The source is http(s) URL, data: URL, a local path (absolute or relative to the session's scratch directory), or a file from scratch via temp: { name }. Operations are submitted in a batch to ops and applied in order.

kind: image_tool
name: image_edit
description: Обрезать / изменить размер / ч/б / повернуть / отконвертировать картинку.
max_bytes: 26214400            # лимит размера входного/выходного файла (по умолч. 25 MiB)
Operation Arguments Effect
crop { x, y, width, height } or { left, top, right, bottom } crop a rectangle
resize { width, height, fit?, filter? } fit: contain (default) / exact / cover; filter: nearest / triangle / catmullrom / gaussian / lanczos3
grayscale — desaturate
rotate { degrees } (90 / 180 / 270) rotate losslessly
flip { direction } (horizontal / vertical / both) flip
brightness { value } add to pixels (negative — darken)
contrast { factor } 1.0 = no change
blur { sigma } gaussian blur
format { format, quality? } convert to png / jpeg / webp / gif / bmp / tiff; quality (1–100) for jpeg
info — record current dimensions/format (no changes)

Call arguments: input (string — URL / data: URL / path) or temp: { name }, ops (array of operations), output? (filename for writing to scratch), send? (explicitly controls delivery: by default false when output is set — only to scratch; otherwise true).

Output. The result is encoded into bytes and:

Without ops the tool returns only the image metadata (width/height/format/size).

A ready-made recipe for generating images from text on top of image_tool (free, no API key) — section 5.32.

Example (URL → crop → resize → grayscale → jpeg, return to the user and save to scratch):

{
  "input": "https://example.com/photo.jpg",
  "ops": [
    { "op": "crop", "x": 0, "y": 0, "width": 800, "height": 600 },
    { "op": "resize", "width": 400, "height": 400, "fit": "cover" },
    { "op": "grayscale" },
    { "op": "format", "format": "jpeg", "quality": 85 }
  ],
  "output": "avatar.jpg",
  "send": true
}

5.30 mcp_tool

Connect a single tool from an external MCP server (Model Context Protocol). The agent hosts MCP tools, but is not itself an MCP server — mcp_tool acts as a client that, using the tool: field, calls a specific tool on the server.

Transports:

description and parameters (JSON Schema) are taken from the server's tools/list if not overridden in YAML, so the LLM sees exactly the schema that the server declares. The schema is fetched at config load time (not at runtime); if the server is unavailable at load time — a fallback schema is registered, and the connection error will be returned at call time.

kind: mcp_tool
name: read_file               # имя, под которым тул виден агенту
description: Прочитать файл  # необязательно — по умолчанию из схемы сервера
server:
  transport: stdio            # stdio | http | sse
  command: npx                # только stdio
  args: ["-y", "@modelcontextprotocol/server-filesystem", "/data"]
  env: {}                     # только stdio, доп. переменные для процесса
  # — или удалённый сервер —
  # transport: http
  # url: https://example.com/mcp
  # headers: { Authorization: "Bearer ${MCP_TOKEN}" }
  timeout_secs: 30
tool: read_file               # имя тула на MCP-сервере (обязательно)
parameters: {}                # необязательное перекрытие JSON Schema
ui: {}                        # необязательный UI-конфиг
# arguments: '{ "path": "{{ input.path }}", "encoding": "utf-8" }'
Field Required Description
kind yes mcp_tool
name yes local tool name for the LLM
server yes server config (see below)
tool yes tool name on the MCP server
description no description override (otherwise from tools/list)
parameters no JSON Schema override (otherwise from tools/list)
arguments no call argument template (see below)
ui no UI config (icons, output templates)

Fields of the server block:

Field Transport Description
transport — stdio | http | sse
command stdio program (required)
args stdio arguments
env stdio additional process environment variables
url http/sse MCP endpoint URL (required)
headers http/sse additional request headers
timeout_secs — request/handshake timeout (default 30)

${ENV_VAR} in command, args, env, url and headers is expanded from the process environment — secrets are not hardcoded into YAML.

Call templating. Without arguments in tools/call, the raw input from the LLM is passed. The arguments field is a MiniJinja template string that is rendered into a JSON document; the scope provides input, temp_dir, session_id, user_id, template. This way the agent author can inject fixed fields, remap the LLM input to the server schema, or substitute the user identifier:

arguments: '{ "query": "{{ input.query }}", "user": "{{ user_id }}", "limit": 10 }'

Connections to the same server are reused (pool by server), so several mcp_tool referencing the same server keep a single live process / HTTP session.

5.31 wait_tool

Pause for a specified number of seconds — to pace polling of a long operation (for example, a benchmark), rather than calling the tool dozens of times in a row.

kind: wait_tool
name: wait
description: "Подождать N секунд."
max_seconds: 120        # потолок на один вызов (по умолчанию 120)

Arguments: seconds (integer, required; clamped to 1..max_seconds), reason? (string). Response — Waited Ns (reason). Continue now. The tool is universal (module agent_tools), available to any agent via tool_files.

5.32 Image generation (text-to-image)

A ready-made "text → image" recipe without an API key, on the free service Pollinations. This is not a separate kind, but a combination of two tools (the script_tool + image_tool pattern).

It is easier to use the native engine image_gen_tool (section 5.33) — it does the same thing with a single tool. The recipe is kept as an example of composing script_tool + image_tool via call_tool.

Both live in config/tools/ and are reused by any agent. In tool_files the agent needs just two lines (paths are relative to the agent directory, hence ../../tools/):

tool_files:
  - ../../tools/generate_image.yaml   # генерация
  - ../../tools/image_fetch.yaml      # служебная доставка картинки в чат

After that the LLM sees generate_image(prompt, width?, height?, seed?, model?, style?).

Agent's own style (thin wrapper)

The implementation is a shared config/tools/generate_image.js. To set the default style and sizes, create a thin wrapper in the agent that references the same script, with the fields style / width / height / deliver:

# config/agents/<agent>/tools/generate_image.yaml
kind: script_tool
name: generate_image
description: Нарисовать иллюстрацию в стиле агента.
script: ../../../tools/generate_image.js   # общая реализация
style: "dark historical oil painting, 16th century, muted palette, storm light"
width: 1024
height: 768
parameters:
  type: object
  properties:
    prompt: { type: string }
  required: [prompt]

style from the wrapper is appended to the prompt and overridden by the call (style in the arguments); deliver changes the name of the delivery tool (by default image_fetch). Ready-made examples: the image agent (no style) and egidia (gloomy historical painting).

../../tools/… links work in the config file tree (and in the git config, where config/tools/ exists). The admin agent builder ("Builder") operates on a self-contained agent bundle and does not copy files outside its directory — when actively using Builder, keep a copy of the tools inside <agent>/tools/.

How it works

The script encodes the prompt, builds the URL https://image.pollinations.ai/prompt/<prompt>?width=…&height=…&seed=…&nologo=true and calls call_tool("image_fetch", { input: url, ops: [{ "op": "info" }], send: true }). image_fetch, like any image_tool, downloads the URL and on send: true returns an file block; the script returns this block in visual, and it is rendered in the UI (see common fields).

Without the tool-calling service (offline agent-os tool) call_tool throws — the script catches this and returns the ready-made URL in content (handy for debugging the config without a server).

Limitations

5.33 image_gen_tool

A native "text → image" engine. Unlike the recipe in 5.32, this is a separate kind: it renders the backend URL itself, downloads the bytes and returns an file block — without script_tool, call_tool and a second tool.

kind: image_gen_tool
name: generate_image
description: Сгенерировать картинку по описанию.
url_template: "https://image.pollinations.ai/prompt/{prompt}?width={width}&height={height}&seed={seed}&nologo=true"
model: flux            # добавляется как &model=…, если шаблон без {model}
style: "dark oil painting, 16th century"   # дописывается к промпту
width: 1024
height: 768
max_bytes: 26214400    # лимит размера ответа (по умолчанию 25 МиБ)
# send: true           # отдавать пользователю (по умолчанию true, если нет output)
# output: image.jpg    # имя файла для записи в scratch сессии
# headers: { Authorization: "Bearer ${IMAGE_API_KEY}" }   # ${ENV} раскрывается

Call arguments: prompt (required), width, height, seed, model, style, output, send.

YAML field Purpose
url_template request template; placeholders (URL-encoded): {prompt}, {style}, {model}, {width}, {height}, {seed}. Empty → Pollinations
model default model (appended as &model=… if the template has no {model})
style default style, appended to the prompt via ,
width / height default sizes (clamped to 64..2048)
output / send scratch file and delivery (same as image_tool)
max_bytes response size limit (default 25 MiB)
headers extra headers; ${ENV_VAR} is expanded from the environment

How it works. The engine builds the URL from url_template, downloads the response, checks that it is a recognizable image (image::guess_format), and returns an file block (base64) — the image is shown in all channels (widget, Telegram, VK, Yandex Messenger, Android). A backend error (e.g. HTTP 402 on a limit) is returned as success: false with the text.

Another provider. Only url_template changes (and headers if needed): local Stable Diffusion/ComfyUI, an OpenAI-compatible API, etc.

Connection examples: the image agent (no style) and egidia (gloomy historical painting).