5. Инструменты — состояние, базы и визуализация
🔵 Хранение состояния (scoped store, SQL-база DuckDB) и генерация визуальных блоков (графики/таблицы). Сводную таблицу всех движков см. в «Справочник инструментов».
5.11 state_tool
Хранилище состояния со скоупом. kind: state_tool открывает агенту scoped state
store ядра. Каждый YAML привязывает одну операцию (op) к одному скоупу +
ключу — агенту даётся узкая, целенаправленная способность (например «только
читать user/name»).
Конкретный id скоупа (session/user/template) резолвится в рантайме из контекста вызывающего инструмента — LLM никогда не видит чужой id.
| Поле | Обязат. | Описание |
|---|---|---|
kind |
да | state_tool |
name |
да | имя для LLM |
description |
да | описание для LLM |
op |
да | одна операция (см. таблицу ниже) |
scope |
да | user | session | agent |
key |
да | ключ хранения |
key_param |
нет | входной аргумент, перекрывающий key |
default |
нет | значение get при промахе |
ttl_secs |
нет | TTL для записей |
limit / offset |
нет | пагинация чтения коллекций |
filter |
нет | JSON-фильтр по коллекциям |
parameters |
нет | переопределить авто-схему |
Скоупы
| Скоуп | Хранится под | Резолвится из |
|---|---|---|
user |
user:<user_id> |
X-User-Id сессии |
session |
session:<session_id> |
текущая сессия |
agent |
agent:<template> |
имя шаблона агента |
Виды значений
| Вид | Запись | Чтение |
|---|---|---|
| скаляр | set |
get |
| список | push |
list, range |
| множество | sadd, srem |
smembers, scard |
delete удаляет любой ключ; keys перечисляет ключи скоупа.
op — справочник
| op | Описание | Авто-параметры | Возвращает |
|---|---|---|---|
get |
прочитать скаляр (или default/null) |
— | значение |
set |
upsert скаляра | value |
{"ok":true} |
delete |
удалить ключ | — | {"deleted":true|false} |
keys |
список ключей скоупа | limit, offset |
[{key,kind,size}] |
push |
добавить в список | value |
{"seq":N} |
list |
прочитать список | limit, offset |
["a", …] |
range |
срез списка [from..=to] |
from, to |
["a", …] |
sadd |
добавить в множество | value |
{"added":true|false} |
smembers |
члены множества | limit, offset |
["x", …] |
srem |
удалить из множества | value |
{"removed":true|false} |
scard |
размер множества | — | {"count":N} |
Чтение коллекций ограничено (по умолчанию 1000 элементов).
filter
filter:
path: meta.priority
op: gte # eq | ne | contains | prefix | gt | gte | lt | lte | exists
value: 3
Строковые операции регистронезависимы; gt/gte/lt/lte сравнивают численно.
5.17 duckdb_tool
Своя DuckDB-база для агента. Универсальный SQL-доступ к DuckDB: агент получает
собственную базу (или доступ к общей), а забота о соединениях и схеме остаётся в
движке. Подходит, когда key/value state_tool мало — нужны таблицы, JOIN,
агрегации, индексы.
kind: duckdb_tool
name: memory
description: SQL-база фактов пользователя.
path: data/dbs/{user}.db # файл, ":memory:" или шаблон пути
operation: query # необязательно: query | execute | schema
init: # необязательно: выполняются ОДИН раз (идемпотентно)
- |
CREATE TABLE IF NOT EXISTS facts (
id BIGINT PRIMARY KEY,
topic TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
readonly: false # запретить execute
limit: 100 # страница по умолчанию
max_rows: 1000 # жёсткий кап строк
| Поле | Обязат. | Описание |
|---|---|---|
kind |
да | duckdb_tool |
name |
да | имя для LLM |
description |
нет | описание для LLM |
path |
да | файл базы или :memory:. Поддерживает {user}, {session}, {template}/{agent} |
operation |
нет | привязать к одной операции; без него операция выбирается аргументом operation (по умолч. query) |
init |
нет | строка или список SQL; выполняется один раз при первом открытии базы |
readonly |
нет | true запрещает execute |
limit / max_rows |
нет | страница по умолчанию / кап строк |
parameters |
нет | переопределить авто-схему |
Операции
| operation | Назначение | Параметры |
|---|---|---|
query |
выполнить SQL и вернуть columns + rows |
sql, limit |
execute |
DDL/DML (CREATE, INSERT, UPDATE, DELETE, …) |
sql |
schema |
таблицы/вью и их колонки | table (необязательно) |
query материализует до limit строк и выставляет has_more, когда их больше —
агент повторяет запрос со своим LIMIT/OFFSET. Результат query дополнительно
кладётся в data (для композиции через visualize_tool source) и в visual
(таблица для UI); content — JSON для LLM. Временны́е типы (TIMESTAMP, DATE,
TIME) возвращаются строками ISO 8601.
Свои базы через user / session / agent
Плейсхолдеры в path резолвятся из контекста вызова:
path: data/dbs/{user}.db # одна база на пользователя
path: data/dbs/{template}.db # одна база на шаблон агента
path: data/dbs/{session}.db # одна база на сессию
Нерезолвимый плейсхолдер (например {user} без user id) — явная ошибка, а не
молчаливое падение в общий файл. Подстановка санитизируется (нельзя выйти из
каталога).
Общая база для нескольких инструментов и инстансов
DuckDB допускает одного писателя на файл, поэтому движок держит
процесс-глобальный пул соединений по каноническому пути: несколько
определений duckdb_tool (и параллельные сессии агентов), указывающих на один
файл, делят одно мьютекс-защищённое соединение. init при этом выполняется
ровно один раз. Пример — memory + memory_schema на общей {user}.db в
config/agents/db-demo/.
5.12 chart_tool и table_tool
Статичные визуальные данные. Движки для предвычисленных/статичных данных:
компактный content (сводка для LLM) + visual (полный блок для UI).
kind: table_tool
name: price_list
description: Показать прайс.
parameters: { type: object, properties: {} }
data_file: data/prices.json
title: "Цены"
summary: "{{ count }} позиций"
columns:
- { key: model, title: "Модель" }
- { key: price, title: "Цена", align: right }
options: { sortable: true, searchable: true }
kind: chart_tool
name: sales_chart
description: Продажи по кварталам.
parameters: { type: object, properties: {} }
data_file: data/sales.json # { type, title, labels, series }
summary: "{{ count }} точек"
Общие поля: kind, name, description, parameters, data_file (путь
относительно YAML) или inline data, summary (MiniJinja, контекст count),
ui. table_tool дополнительно: title, columns, options (sortable /
searchable / paged). chart_tool берёт data как spec (type = bar |
line | area | pie | scatter).
Оба движка принимают динамический аргумент data в вызове — он перекрывает
статичный data/data_file.
5.13 visualize_tool
Графики и таблицы из произвольных данных. Универсальный собрат
chart_tool/table_tool: превращает данные, переданные аргументами, в
график или таблицу, с пайплайном трансформаций. LLM отдаёт строки (или spec),
движок детерминированно агрегирует.
kind: visualize_tool
name: make_chart
description: Построить график/таблицу из переданных строк.
| Аргумент | Описание |
|---|---|
data |
массив объектов-строк, или полный spec таблицы/графика |
source |
сослаться на результат прошлого вызова инструмента: { tool, index, field, path, pages } |
group_by |
поле группировки |
aggregate |
{ count, sum, avg, min, max } — результаты с префиксом (sum_cost, …) |
filter |
{ field: { op: value } } |
sort |
{ by, dir: asc|desc } |
limit |
максимум строк |
as |
table | bar | line | area | pie | scatter |
title, x, series, columns, options |
оформление |
Композиция инструментов (source)
Вместо копирования данных можно сослаться на результат прошлого вызова в той же сессии:
{ "source": { "tool": "trace_sessions" }, "group_by": "agent",
"aggregate": { "sum": ["errors"] }, "as": "bar" }
trace_tool's sessions возвращает
структурированные строки в data — готовый источник. Явный data выигрывает у
source.