Инструменты
Инструмент — это именованное действие, которое может вызвать ИИ, с типизированными входными параметрами — напримерsend_email(to, subject, body). Инструменты объявляются в файле tools.ts навыка и, для инструментов, которые предоставляет ваше приложение, поддерживаются HTTP-маршрутом в одном из ваших компонентов. Эта страница — источник истины для контракта инструмента; раздел Навыки описывает, где находится tools.ts.
Объявление инструмента
Каждая запись вtools.ts имеет безопасное для провайдера name, дружественное displayName, description, Zod-схему input и target, который указывает, что вызывает Kazzle.
Целевые адреса
target — это переиспользуемый адрес для инструмента или кнопки требуемого действия. Прямой вызов инструмента ИИ и клик по кнопке могут использовать один и тот же объект target, поэтому оба выполняют одинаковый код.
HTTP-целевые адреса используют одинаковые поля запроса:
body: '${input}'.
Ссылки
Kazzle разрешает ссылки в полях HTTP-целевого адресаquery, headers, body и url перед отправкой:
${input}— весь входной параметр инструмента или весь входной параметр кнопки.${input.path}— вложенное значение из входного параметра.${env.NAME}— именованная переменная окружения из объявленныхenv.collection+env.environmentкомпонента приложения-владельца.
$${input.name}, когда вам нужен буквальный текст ${input.name}.
Запрос обработчика
Для целевого адресаapp добавьте соответствующий маршрут в компонент-цель. С body: '${input}' Kazzle отправляет типизированный входной параметр как тело JSON:
app также получают:
Целевые адреса приложения не могут устанавливать
Authorization через headers; Kazzle владеет этим заголовком. Прочитайте контекст с помощью toolContext(req) из @kazzle/app/tools, когда обработчик должен различать поток и Tools API.
Инструмент, объявленный без соответствующего маршрута, не имеет практической пользы — добавьте оба вместе. tools.json не поддерживается; компилятор приложения завершается с ошибкой, если находит его.
Ответ обработчика
Возвращайте простой текст или JSON с до трёх каналов:content— простой результат, который читает ИИ (передаётся модели). Обязателен.markdown— опционально. Краткое резюме в формате rich-text, отображаемое в карточке инструмента (react-markdown; необработанный HTML экранируется). Хорошо подходит для предложения, небольшого списка, встроенной ссылки. Голый относительный путь отображается как мёртвый предварительно отформатированный текст — ссылки должны быть абсолютными.embedUrl— опционально. Абсолютный URL, который предоставляет ваше приложение; карточка отображает его в изолированном iframe. Это способ показать реальный полноширинный интерфейс — экран подключения, панель управления, диаграмму. Ваше приложение размещает и владеет страницей, поэтому она может быть полностью интерактивной с вашим собственным бэкендом, cookies и OAuth. Ничего не записывается на диск.
embedUrl имеет приоритет над markdown, когда оба установлены. Всегда сохраняйте значимый content — это то, что читает ИИ.
Требуемое действие
Инструмент приложения может приостановить поток, когда требуется действие пользователя (или устройства). Возвращайтеtype: 'action_required' с заголовком карточки и кнопками. Действительно только когда toolContext(req).source === 'thread' — через Tools API (source: 'api') возвращайте обычную ошибку домена.
/chat/resume после нажатия кнопки. Соответствующие клиенты видят кнопки автора; несоответствующие клиенты всё ещё видят Skip/Cancel плюс “Continue on ”. Кнопка без target отправляет свой input как результат инструмента. Кнопка с целевым адресом сначала выполняет этот целевой адрес, затем использует результат целевого адреса как результат инструмента.
Rich UI — встроенная страница, размещённая приложением
Когда результат инструмента визуален или интерактивен (экран подключения, диаграмма, панель сводки), предоставляйте страницу из одного из ваших компонентов и возвращайте её абсолютный URL какembedUrl. Создавайте URL из внедрённого URL компонента — никогда не используйте относительный путь.
embedUrl вместо выдачи HTML-строк: ваше приложение уже предоставляет страницы, интерфейс остаётся интерактивным и версионируется вместе с вашим кодом, и никакие артефакты для каждого вызова не записываются никуда.