как опубликовать инструмент на histrio
карта шагов
что именно вы настраиваете
Первый шаг задаёт тип инструмента, а дальше сценарий расходится: для формы появляются настройка результата и проверка публикации, для чата остаются только шаги, связанные с диалогом и подключением сервера.
Шаг 1
Карточка
Обязательны только название, описание и категория. Здесь же выбирается interaction mode: Form или Chat.
Шаг 2
Форма / Чат
Для Form вы собираете input schema. Для Chat вы задаете context preset и callback timeout.
Шаг 3
Биллинг
Для Form доступны разовая оплата, usage-based и подписка. Для Chat остаются usage-based и подписка с token-priced метрикой.
Шаг 4
Endpoint
Секреты, auth, execute URL, callback secret и весь async callback contract, который реально ожидает backend.
Сценарий с формой
- Шаг 1: Карточка
- Шаг 2: Форма ввода
- Шаг 3: Биллинг
- Шаг 4: Endpoint
- Шаг 5: Ответ
- Шаг 6: Публикация с живой асинхронной проверкой
Сценарий с чатом
- Шаг 1: Карточка
- Шаг 2: Чат
- Шаг 3: Биллинг
- Шаг 4: Endpoint
- Шаг 5: Публикация без отдельного test request
Коротко
- Обязательные поля step 1: название, описание, категория.
- Step 2 блокируется любым пустым `key` или `label`.
- Для Form публикация невозможна без успешного async handshake.
- Callback URL появляется после первого сохранения draft.
подготовка
что стоит сделать до первого клика
Эти ограничения не всегда видны в UI сразу, но именно они чаще всего объясняют, почему инструмент не уходит на публикацию.
- У аккаунта должно быть право на публикацию. Если публикация недоступна для аккаунта или достигнут лимит опубликованных инструментов, submit будет заблокирован.
- Первое сохранение draft полезно сделать рано: только после этого платформа знает `toolId` и может сгенерировать реальный callback URL.
- Self-service путь ориентирован на публичный HTTPS endpoint. Режим `private_service` существует, но это отдельный admin-managed сценарий, а не обычная настройка с `/dashboard/tools/new`.
- В API-режиме редактор жёстко ведёт вас в `http_async_callback`. Синхронный HTTP контракт в этом wizard не настраивается.
- Если версия уже находится в `in_review`, повторный submit блокируется до решения модерации.
шаг 1
карточка инструмента
Это единственный шаг, который одновременно влияет и на каталог, и на остальной wizard.
Валидность первого шага проверяется очень просто: должны быть заполнены название,описание и выбранакатегория. Подкатегории, теги и текст CTA полезны, но не блокируют переход дальше.
Самый важный контрол на этом шаге interaction mode. Если выбрать Form, вы публикуете one-shot инструмент с input schema, отдельным шагом Ответ и live handshake перед модерацией. Если выбрать Chat, wizard превращается в developer-hosted conversational runtime: step 2 меняется на контекст чата, биллинг становится token-aware, а отдельный response step исчезает.
Что здесь редактируется
- Название и описание для каталога.
- Категория и подкатегории для фильтров и карточки.
- Теги (`skills`) для дополнительного поиска.
- Необязательный `customCtaLabel` для кнопки запуска.
Что видно только у Form
- Примеры результата: изображения и видео для публичной карточки.
- Инструкция после покупки: отдельное сообщение с тем, что делать клиенту после оплаты.
- Эти поля не блокируют step 1, но помогают продаже и онбордингу.
шаг 2
форма ввода или chat runtime
Здесь wizard расходится сильнее всего. Для Form этот шаг строит input schema, для Chat задаёт правила контекста и timeout callback.
Form: что делает шаг валидным
- Есть хотя бы одно поле.
- У всех полей и вложенных полей заполнены `label` и `key`.
- Нет повторяющихся `key`, включая repeatable group.
- Скрытые служебные поля заполнены так, чтобы реально могли попасть в payload.
Form: типы полей
- Text: одна строка текста
- Textarea: длинный бриф или prompt
- Number: числовой ввод
- Boolean: да / нет
- Select / Radio / Multiselect: варианты выбора
- File / Document / Image / Audio: файлы и медиа
- Date / URL / JSON / Secret: специальные типы
- Section: информационный блок без ввода
- Repeatable group: массив вложенных объектов
Form: важные свойства каждого поля
- У каждого поля должны быть заполнены `label` и `key`.
- `key` должен быть уникален не только среди верхнеуровневых полей, но и внутри вложенных repeatable group.
- Если поле помечено как `hidden`, оно не показывается клиенту, но уходит в payload автоматически.
- Для скрытого поля нужен `defaultValue`, иначе схема технически неполная.
- Опции можно задавать по строкам: `value`, `value => Label` или `1:1`.
- Repeatable group полезен для массивов референсов, контактов, файлов и любых списков объектов.
пример валидной input schema
показать›
[
{
"key": "prompt",
"label": "Что нужно сделать",
"type": "textarea",
"required": true,
"placeholder": "Опишите задачу и желаемый результат"
},
{
"key": "ratio",
"label": "Формат",
"type": "select",
"options": [
{ "value": "1:1", "label": "1:1" },
{ "value": "16:9", "label": "16:9" }
]
},
{
"key": "model",
"label": "Модель",
"type": "select",
"hidden": true,
"defaultValue": "gpt-image-1.5",
"options": [
{ "value": "gpt-image-1.5", "label": "GPT Image 1.5" }
]
},
{
"key": "references",
"label": "Референсы",
"type": "repeatable_group",
"minItems": 0,
"maxItems": 5,
"fields": [
{
"key": "url",
"label": "Ссылка",
"type": "url",
"required": true
},
{
"key": "note",
"label": "Комментарий",
"type": "text"
}
]
}
]Chat: context mode
- `message_only`: только текущее сообщение пользователя, лимит 32 KB.
- `recent_window`: текущее сообщение плюс до 20 предыдущих committed сообщений, лимит 128 KB.
- `full_session_truncated`: до 100 committed сообщений и лимит 256 KB; если история не влезает, платформа отрежет самые старые сообщения.
- В outbound context попадают только committed user/assistant messages. Pending, failed и служебные состояния не отправляются.
- Callback timeout для developer-hosted chat clamp-ится в диапазон 30–3600 секунд; дефолт 300.
Chat: что реально получает backend
- Committed transcript по выбранному preset.
- Текущее сообщение пользователя и metadata по вложениям.
- Callback deadline, чтобы backend понимал, сколько времени осталось.
- При token-priced биллинге ещё и billing context с текущими ставками и authorized ceiling.
шаг 3
биллинг
Здесь важно понимать не только labels в UI, но и кодовую логику `isPrimaryPlanBillingConfigured`, потому что именно она решает, готов ли шаг к публикации.
Для Form-инструментов primary offer считается готовым, если у него есть валидная цена для выбранной модели. Для usage_based достаточно unitPrice или displayPrice, а если включена динамическая цена, наличие базового pricing rule уже делает модель валидной. Для one_time_purchase нужна фиксированная displayPrice. Для subscription нужны цена и период.
Разовая оплата
Клиент платит один раз. В access rules можно продавать либо один запуск, либо постоянный доступ к инструменту.
Usage-based
Цена может быть фиксированной за единицу или динамической: базовая стоимость плюс множители по полям формы.
Подписка
Нужны цена периода и период. Доступ управляется как subscription entitlement, а автопродление задается прямо в offer.
Dynamic pricing у Form
- Работает только для `usage_based`.
- База: `unitPrice` как цена за единицу.
- Дальше можно умножать цену по visible полям формы.
- Практически полезны поля типов `number`, `select`, `radio`, `checkbox`, `toggle`.
- Публичный label цены может быть автоматическим или переопределенным вручную.
Пакеты
- Пакеты продают заранее оплаченный объём кредитов.
- Они появляются только после того, как у offer уже есть сохранённый id.
- Пакет нельзя построить без хотя бы одной сохранённой разовой или usage-based модели оплаты.
Chat: usage-based
- Разовая покупка у chat tool не поддерживается: wizard принудительно оставляет usage-based или subscription.
- Для готовности нужны `inputPricePer1M`, `outputPricePer1M` и `maxAttemptCharge`.
- Эти ставки участвуют в funding authorization до dispatch и в финальном расчете после callback.
Chat: subscription
- Нужны цена периода и сам период.
- Дополнительно нужны `includedBudgetPerPeriod`, `inputPricePer1M`, `outputPricePer1M`, `maxAttemptCharge`.
- Если в callback не придёт usageReport с `inputTokens` и `outputTokens`, token-priced chat billing не сможет посчитать итог.
шаг 4
endpoint, auth и callback contract
Это самый технический шаг wizard. Здесь чаще всего ломается публикация: неправильный execute URL, невыбранный callback secret, неверный handshake или неподписанный callback.
Секреты и auth
В верхней части шага вы храните API secrets, которые платформа потом подставляет в запросы к вашему backend. Клиент эти значения не видит. Ниже выбирается способ авторизации:
- `none`: без авторизации.
- `bearer_token`: платформа отправляет `Authorization: Bearer <secret>`.
- `header_secret`: платформа кладет секрет в ваш кастомный header, например `X-API-Key`.
- `query_token`: секрет добавляется в query string по заданному имени параметра.
- `basic_auth`: username и password хранятся как два отдельных секрета и уходят в `Authorization: Basic ...`.
Для обычного developer-hosted сценария нужен публичный https://... execute URL. В production backend отдельно валидирует, что и executeUrl, и callbackUrl используют HTTPS и публичный host. Исключение только для admin-managed private_service, который живет вне этого self-service гайда.
Callback URL платформа генерирует сама на основе toolId, поэтому в wizard вы начинаете видеть его только после первого сохранения черновика. Для Form и Chat это разные маршруты:
автогенерируемые callback endpoints
показать›
Form tool:
https://histrio.ru/backend/tool-executions/callbacks/:toolId
Chat tool:
https://histrio.ru/backend/tool-chat-executions/callbacks/:toolIdчто wizard отправляет в execute endpoint при test request или реальном form-run
показать›
{
"toolOrderId": "4dc6f4c6-1ec2-4c7e-b8fd-1f2bc5f94211",
"toolId": "tool_123",
"toolOfferId": "offer_123",
"endUserRef": "test_end_user_ref",
"input": {
"prompt": "Нарисуй упаковку молока на белом фоне",
"ratio": "1:1"
},
"callbackUrl": "https://histrio.ru/backend/tool-executions/callbacks/tool_123",
"testMode": true
}Какие headers платформа добавляет
- `content-type: application/json` всегда.
- `x-tool-id: <toolId>` всегда.
- `x-tool-test-request: true` во время live проверки перед публикацией.
- Плюс всё, что вы задали через auth: bearer, custom header, query token или basic auth.
Для успешного live handshake async endpoint не должен возвращать финальный результат сразу. При включенном `requireExplicitAsyncHandshake` backend ждёт JSON-объект со статусом queued или awaiting_callback. Если вернуть `result` сразу в ответе, wizard сочтет интеграцию невалидной.
минимальный успешный handshake response
показать›
{
"status": "queued",
"jobId": "job_123"
}подпись callback в x-tool-signature
показать›
import crypto from "node:crypto";
const rawBody = JSON.stringify(payload);
const signature = crypto
.createHmac("sha256", CALLBACK_SECRET)
.update(rawBody)
.digest("hex");
await fetch(callbackUrl, {
method: "POST",
headers: {
"content-type": "application/json",
"x-tool-signature": signature,
},
body: rawBody,
});form callback: success
показать›
{
"toolOrderId": "order_123",
"jobId": "job_123",
"status": "completed",
"result": {
"imageUrl": "https://cdn.example.com/result.png"
},
"artifacts": [
{
"label": "Rendered image",
"url": "https://cdn.example.com/result.png",
"mimeType": "image/png",
"sizeBytes": 2048
}
]
}form callback: failure
показать›
{
"toolOrderId": "order_123",
"status": "failed",
"error": "Provider timeout"
}Form callback: на что смотрит backend
- `toolOrderId` обязателен.
- Успешный callback должен нести объект `result` или объект целиком, если `result` не выделен отдельным ключом.
- Статус по умолчанию считается `completed`, но допустимы только `completed` и `failed`.
- Callback принимается только пока order находится в `awaiting_developer_callback`.
- Для callback artifacts нужны публичные HTTPS URL.
- Безопасные типы сводятся к изображениям, аудио, видео и документам; опасные mime types backend отвергнет.
- Даже безопасные файлы могут уйти в quarantine или rejection, если не проходят scanner / acceptance checks.
chat dispatch request к developer backend
показать›
{
"toolId": "tool_chat_123",
"sessionId": "session_123",
"attemptId": "attempt_123",
"userMessageId": "user_msg_123",
"assistantMessageId": "assistant_msg_pending_123",
"endUserRef": "tool_chat_123:user_123",
"callbackUrl": "https://histrio.ru/backend/tool-chat-executions/callbacks/tool_chat_123",
"callbackDeadlineAt": "2026-04-07T10:08:00.000Z",
"contextPreset": "recent_window",
"context": {
"preset": "recent_window",
"messages": [
{ "role": "user", "text": "older completed user" },
{ "role": "assistant", "text": "older completed assistant" },
{ "role": "user", "text": "Current request" }
]
},
"currentUserMessage": {
"id": "user_msg_123",
"text": "Current request"
},
"assistantMessage": {
"id": "assistant_msg_pending_123",
"status": "pending"
},
"billing": {
"billingModel": "usage_based",
"currency": "RUB",
"inputPricePer1M": "17.9",
"outputPricePer1M": "111.87",
"authorizedCeilingAmount": "25"
}
}chat callback: success
показать›
{
"sessionId": "session_123",
"attemptId": "attempt_123",
"userMessageId": "user_msg_123",
"status": "completed",
"assistantText": "Готово. Ниже результат и вложения.",
"artifacts": [
{
"url": "https://example.com/out.png",
"mimeType": "image/png",
"sizeBytes": 2048
}
],
"usageReport": {
"inputTokens": 120,
"outputTokens": 45,
"totalTokens": 165,
"provider": "openai",
"model": "gpt-4.1-mini"
}
}Chat callback: ограничения
- `sessionId`, `attemptId` и `userMessageId` обязательны.
- Успешный callback обязан содержать `assistantText`.
- Допустимые статусы только `completed` и `failed`.
- Если tool использует token-priced billing, в `usageReport` должны быть `inputTokens` и `outputTokens`.
- В одном chat callback можно прислать максимум 5 artifacts.
- Поддерживаются только `image/jpeg`, `image/png`, `image/webp`, `application/pdf`, `text/plain`, `text/csv`, `application/vnd.openxmlformats-officedocument.wordprocessingml.document`.
- Размерные лимиты разные: изображения до 10 MB, документы до 25 MB, общий callback budget до 50 MB.
- Chat backend обязан прислать `assistantText` при успешном callback; только artifacts без текста считаются невалидным callback.
Advanced settings
- `healthcheckUrl` опционален и полезен, если вы хотите быстро отсечь мёртвый runtime до основной нагрузки.
- `timeoutMs` и `retryCount` сохраняются в execution config. Для live test редактор поднимает timeout минимум до 120000 ms.
- В UI это звучит как 'оставьте по умолчанию, если не уверены' — и это хороший совет. Чаще всего достаточно дефолтных 120000 ms и 1 retry.
шаг 5/6
ответ, live handshake и отправка на модерацию
Финальные шаги различаются у Form и Chat, но их цель одна: показать платформе, что ваш runtime не только заполнен в UI, но и реально исполним.
Form: шаг 5 `Ответ`
- Нужно выбрать `primaryResultType`: текст, JSON, изображение, файл или отчет.
- Нужно выбрать `deliveryType`: inline, file, download или внешняя ссылка/доступ.
- Можно задать `postPurchaseMessage` и ограничения, но они не блокируют готовность шага.
Form: шаг 6 `Публикация`
- Wizard собирает test values из вашей формы и отправляет реальный HTTP request в execute endpoint.
- Если endpoint не ответит queued/awaiting_callback, публикация останется заблокированной.
- Если у инструмента нет visible input fields, в test request уйдут только hidden defaults.
- Private runtime из админки — единственный сценарий, где live handshake можно не требовать.
Chat: шаг 5 `Публикация`
- Отдельной кнопки test request нет.
- Готовность считается по checklist: карточка, chat runtime, биллинг, execute URL, auth и callback secret.
- Если всё заполнено и аккаунт может публиковать, инструмент можно сразу отправлять на модерацию.
финал
чеклист перед submit
Если пройти эти пункты слева направо, wizard обычно доходит до публикации без повторных кругов.
- Выбрали правильный interaction mode на step 1 и больше не путаете Form с Chat.
- У карточки есть понятные название, описание, категория и хотя бы минимально осмысленный CTA.
- Все form fields имеют уникальные `key`, а hidden поля реально могут отправиться без участия пользователя.
- Primary offer проходит правила готовности для своей billing model.
- Execute endpoint доступен по публичному HTTPS, а auth собран из сохранённых secrets.
- Callback secret выбран, callback URL уже сгенерирован после сохранения draft.
- Form endpoint возвращает `queued` / `awaiting_callback`, а не финальный `result` в ответ на handshake.
- Backend умеет подписывать raw callback body через `x-tool-signature`.
- Для chat token-priced биллинга callback отправляет `usageReport` с `inputTokens` и `outputTokens`.
- После live test request или publish checklist у аккаунта нет review gate: лимит публикаций не достигнут и версия не висит в `in_review`.