---
name: agent-os-tools
description: Писать определения инструментов Agent OS на YAML — site_tool, browser_tool, archive_tool, json_tool, rss_tool, pdf_tool, trace_tool, geo_tool, script_tool, state_tool, table_tool, chart_tool, visualize_tool, subagent_tool, email_tool, workflow_tool, duckdb_tool, sql_tool, shell_tool, file_tool, office_tool, vk_tool. Используй, когда просят создать инструмент, заскрейпить сайт (в т.ч. JS-сайт через headless-браузер), искать по архиву/JSON/RSS, читать PDF, хранить состояние, отрисовать таблицу/график, делегировать задачу субагенту, геокодировать, отправить письмо, сгенерировать Word/Excel/PowerPoint, работать с PostgreSQL/MySQL или отправить файл.
---

# Agent OS — инструменты

Инструменты — YAML-файлы в `config/agents/<agent>/tools/`. Поле `kind:` выбирает
движок. Полный справочник (сводная таблица + разделы): `docs/05-tools-reference.md`.

## Движки (`kind:`)

| kind | Назначение |
|---|---|
| `site_tool` | HTTP-запрос → извлечение полей (JSON-указатели, матч по массиву, трансформации) → формат |
| `browser_tool` | headless-браузер: шаги (goto/click/type/check/eval/screenshot/pdf) + JS-скрипт в странице |
| `archive_tool` | поиск по локальному текстовому архиву (`search`, `search_grouped`, `lookup`, `read_chunks`, `outline`) |
| `json_tool` | декларативный поиск по предзагруженному JSON |
| `rss_tool` | поиск по RSS-лентам |
| `pdf_tool` | скачать + читать PDF постранично |
| `trace_tool` | запросы к трейсам агентов (события, сессии, транскрипты) |
| `geo_tool` | геокодинг (Nominatim) и POI (Overpass): locate / places / distance |
| `script_tool` | скриптовый инструмент на JavaScript или Rhai (см. скилл `agent-os-scripts`) |
| `state_tool` | scoped-хранилище — операции get/set/delete/push/list/set на ключе user/session/agent |
| `table_tool` | статичные данные → интерактивная таблица (sort/search/paging) |
| `chart_tool` | статичные данные → график |
| `visualize_tool` | динамические данные → график/таблица с трансформацией (group_by/aggregate/filter/sort) и композицией `source` |
| `subagent_tool` | делегировать задачу дочернему агенту (`template` или inline `instructions`+`tools`) и вернуть ответ |
| `email_tool` | отправить письмо по SMTP |
| `workflow_tool` | запустить воркфлоу и вернуть run id |
| `duckdb_tool` | своя DuckDB-база для агента (query/execute/schema, `init`, `{user}`/`{session}`/`{template}`) |
| `sql_tool` | SQL-доступ к внешней PostgreSQL/MySQL (query/execute/schema, `url_env`, пул по URL) |
| `shell_tool` | запустить внешнюю команду CLI (команда/args/env фиксируются в YAML) |
| `file_tool` | отправить файл пользователю (content/data/path/temp/state/source) |
| `office_tool` | генерация/чтение Word·Excel·PowerPoint через OfficeCLI (`create`/`fill`/`extract`/`convert`/`edit`/`merge`, PDF-плагин) |
| `vk_tool` | вызов VK API от имени сообщества (`method`/`params` или `action`) |
| `dll_tool` | нативный Rust-плагин (см. `docs/20-native-plugins.md`) |

## Общие поля (все kind'ы)

```yaml
kind: site_tool
name: my_tool                  # имя, которое вызывает LLM
description: >                 # показывается LLM
  Что делает инструмент.
parameters:                    # JSON Schema для function calling
  type: object
  properties:
    query: { type: string, description: "..." }
  required: [query]
ui:                            # опциональный рендер в виджете
  icon: 🚗
  call_template: "Ищу {{ input.query }}..."
  result_template: "{{ extracted.total }} найдено"
warnings:                      # опциональные декларативные предупреждения (в трейсах)
  - contains: '"count": 0'     # подстрока в выводе JSON
    message: "Нет результатов"
  - failed: true               # или: матч на success=false
    message: "Инструмент упал"
```

## `site_tool` (самый частый)

```yaml
kind: site_tool
name: my_scraper
description: Парсит страницу товара.
parameters: { type: object, properties: { url: { type: string } }, required: [url] }

fetch:
  url: "{{ input.url }}"        # MiniJinja-шаблон; или base/path/path_opt/query
  method: GET                   # GET (по умолч.) или POST/PUT/PATCH/DELETE
  timeout_secs: 15
  cache_ttl_secs: 300
  headers:
    User-Agent: "MyBot/1.0"
    Authorization: "Bearer {{ env_var('API_KEY') }}"

source:
  type: script_json             # JSON внутри <script> (нужен `contains:`)
  contains: productData         # или type: json для чистого JSON-ответа API

extract:
  title: { pointer: /productData/title }
  price: { pointer: /productData/price, transform: int }
  images:
    pointer: /productData/images
    collect_all: true
    value: /src
    transform: [ { skip: 0 }, { take: 5 } ]
  status:
    compute:
      - when: { op: not_null, pointer: /sold }  then: sold
    default: active

output:
  title: "{{ extracted.title }}"
  price: "{{ extracted.price }}"
```

Типы полей `extract`: **простое** (`pointer`, `value`, `fallback`, `transform`),
**массив** (`array_match: {field: value}`, `collect_all`, `item_fields`),
**вычисляемое** (`compute:` с `when`/`then`/`default`).

Другие типы `source`: `json_ld`, `file_json`, `devalue`, `html` (CSS-селекторы).

Трансформации (цепочкой): `lookup`, `truncate`, `take`, `skip`, `len`,
`not_null`, `bool`, `int`, `filter` (шаблон), `transliterate`, `strip_html`.

## `archive_tool`

```yaml
kind: archive_tool
name: ngu_search
description: Поиск по архиву НГУ.
parameters: { type: object, properties: { query: { type: string } }, required: [query] }
mode: search_grouped            # search | search_grouped | lookup | read_chunks | outline
archive:
  path: data/ngu                # каталог архива (meta.json + docs.bin + terms.bin)
  default_limit: 10
filters:                        # опциональный пост-фильтр по meta-полям
  - { field: price, op: gte, param: price_min }
sort: { field: price, order: asc }
```

## `json_tool`

```yaml
kind: json_tool
name: find_brands
description: Поиск по предзагруженному JSON.
parameters: { type: object, properties: { query: { type: string } }, required: [query] }
data_file: data/drom_brands.json
search:
  paths: ["*.top", "*.all"]     # JSON-пути; `*` = все ключи
  field: name
  query_param: query
  mode: contains
  limit: 20
  dedupe_by: id
computed:
  slug: "{{ item.url | path_segment(0) }}"
```

## `rss_tool`

```yaml
kind: rss_tool
name: rss_search
description: Поиск новостей.
parameters: { type: object, properties: { site: { type: string }, query: { type: string } }, required: [site, query] }
feeds:
  lenta: "https://lenta.ru/rss"
```

## `pdf_tool`

```yaml
kind: pdf_tool
name: pdf_read
description: Читать страницу PDF.
parameters: { type: object, properties: { url: { type: string }, page: { type: integer } }, required: [url] }
fetch: { url: "{{ input.url }}", timeout_secs: 30, cache_ttl_secs: 3600 }
pdf: { chars_per_page: 3000 }
```

## `state_tool`

Scoped-персистентность на user/session/agent. Один инструмент = одна операция
`op` на одном `scope`+`key`; конкретный id (user/session/template) резолвится из
вызывающего, никогда не подставляется LLM.

```yaml
kind: state_tool
name: set_user_name
description: Запомнить имя пользователя.
op: set                        # get | set | delete | keys | push | list | range
                               # | sadd | smembers | srem | scard
scope: user                    # user | session | agent
key: name
# key_param: pref              # опц. входной аргумент, перекрывающий `key`
# default: friend              # `get` возвращает это при промахе
# ttl_secs: 3600               # TTL на записи (set/push/sadd)
# limit: 20                    # размер страницы для list/smembers/keys (кап 1000)
# filter:                      # JSON-фильтр на чтение коллекций
#   path: meta.priority
#   op: gte                    # eq | ne | contains | prefix | gt | gte | lt | lte | exists
#   value: 3
```

Тип ключа фиксируется при первой записи: скаляр (`set`/`get`), список
(`push`/`list`/`range`), множество (`sadd`/`smembers`/`srem`/`scard`). `delete`
удаляет любой вид; `keys` перечисляет `{key, kind, size}`. Полный справочник:
`docs/05-tools-state.md` (state_tool).

## `table_tool` и `chart_tool`

Предвычисленные/статичные данные → визуальный блок. `content` (сводка для LLM) и
`visual` (блок) строятся из `data_file` (отн. YAML инструмента) или inline `data`.

```yaml
kind: table_tool
name: price_list
description: Показать прайс.
parameters: { type: object, properties: {} }
data_file: data/prices.json      # массив строк, или { rows, columns }
title: "Цены"
summary: "{{ count }} позиций"   # → content (LLM); по умолчанию {"count": n}
columns:                         # опц.; выводятся из ключей строк, если опущены
  - { key: model, title: "Модель" }
  - { key: price, title: "Цена", align: right }
options: { sortable: true, searchable: true }
```

```yaml
kind: chart_tool
name: sales_chart
description: Продажи по кварталам.
parameters: { type: object, properties: {} }
data_file: data/sales.json       # { type, title, labels, series }
summary: "{{ count }} точек"
```

## Визуальные блоки на любом инструменте

Любой инструмент может отрисовать график/таблицу рядом с текстом через
`ui.result_blocks` (шаблоны поверх `extracted`) или верхнеуровневое поле `visual:`
(поверх сырого `extracted`, минуя LLM). Полная модель блоков (chart/table spec,
`continuation`) — `docs/05-tools-core.md` (общие поля).

## Тестирование инструмента (без сервера и LLM)

```bash
site_tool config/agents/<agent>/tools/<tool>.yaml '{"query":"..."}'
```

Печатает аргументы, `call_template`, вывод для LLM, `result_template`.
