Агенты
Агент — готовый сценарий ассистента: карточка на первом экране, которая запускает диалог со своим промптом, первым сообщением и вариантами ответа. Здесь — объект агента и методы управления.
Что такое агент
Агент — самостоятельная запись ассистента (таблица agents), а не часть настроек первого экрана. У агента своя подпись, картинка, промпт, заготовленное первое сообщение, варианты ответа, категории и десятки необязательных настроек в config. Посетитель видит агента карточкой или кнопкой на приветственном экране, в каталоге «Помощники» или открывает его прямой ссылкой.
Что происходит при выборе агента, задаёт action: обычный агент (send) начинает диалог своим промптом, image открывает экран создания изображения, document — загрузку документа, character — диалог с персонажем. Промпт агента уходит скрытым первым сообщением пользователя или добавляется к системному промпту на весь диалог — это решает config.prompt_target.
Раньше агент назывался «командой» (command). Старые пути /assistants/{assistantId}/commands… работают как вечные синонимы /agents…: тот же обработчик, те же поля, те же ответы. Ответы дублируют объект под старым ключом — commands в списке и command в создании и изменении. В новом коде используйте /agents и ключ agent.
Как агент попадает на экран
Агент не привязан к экрану напрямую. Секция приветственного экрана выбирает агентов по категории: в секцию «Изображения» попадают все агенты, у которых эта строка есть в categories, в порядке order и с ограничением limit секции. Один агент может стоять в нескольких секциях сразу. Сами секции и вкладки категорий настраиваются на странице Первые экраны.
Вид секции берётся из display_type первого агента категории, поэтому у агентов одной категории вид должен совпадать.
display_type | Как выглядит |
|---|---|
button | Кнопка: значок Lucide из icon и подпись. Умолчание, если поле пустое |
icon-tile | Плитка с эмодзи из emoji и подписью |
image-tile | Картинка из image, подпись поверх неё |
image-caption | Картинка 16:9, подпись под ней |
persona | Большая карточка: картинка, название и subtitle |
Агент без категории или с категорией, которой нет ни в одной секции, на приветственном экране не виден, но открывается ссылкой ?agent=<slug> и может попасть в каталог по тегу. Подробнее — Экран-профиль и ссылки.
Объект агента
Все методы отдают агента одним плоским объектом: колонки таблицы плюс ключи из config, разложенные на верхний уровень. Ключи config, которые у агента не заданы, в объекте отсутствуют — кроме нескольких, которые есть всегда (отмечены ниже). Полный список ключей config — на странице Свойства config.
| Свойство | Тип | Описание |
|---|---|---|
id | integer | Идентификатор агента. Только чтение |
slug | string или null | Идентификатор для ссылок ?agent=<slug>, до 120 символов. Не задан — собирается из label транслитом (Канва → kanva). Уникален в пределах ассистента: при совпадении добавляется -2, -3. Пустая строка в PUT пересобирает slug из label |
order | integer | Позиция в списке агентов ассистента, от 0. Не задан при создании — агент встаёт последним |
label | string | Подпись карточки и название агента, до 255 символов. При создании ключ обязателен; пустое значение превращается в «Новый агент». Переводится через locales |
icon | string или null | Имя значка Lucide для display_type: button, до 64 символов |
emoji | string или null | Эмодзи для icon-tile и persona, до 16 символов |
image | string или null | Картинка карточки, до 1024 символов: полный https:// адрес или путь /storage/…. Может быть коротким видео mp4 или webm — тогда нужен image_poster. Одна на все языки. В запросе можно прислать data URL, файл или внешнюю ссылку — см. «Картинка в запросе агента» |
image_poster | string или null | Статичная картинка (png, jpg, webp, gif) для видео в image: показывается в шапке чата, списках и превью ссылки. Видео сюда не принимается (422) |
reference_image | string или null | Картинка-образец, до 1024 символов. У action: image уходит вместе с промптом; в обычном чате, начатом этим агентом, подмешивается к каждой генерации изображения |
subtitle | string или null | Короткое описание, до 255 символов: подзаголовок карточки persona, описание в каталоге и на экране-профиле. Переводится |
badge | string или null | Мини-бейдж на карточке, до 64 символов. Переводится |
action | string | Что делает агент: send, image, document, voice, diagram, plot, search, character. Умолчание send |
display_type | string или null | Вид карточки: button, icon-tile, image-tile, image-caption, persona |
prompt | string или null | Промпт агента. Куда он уходит — задаёт prompt_target. Изменение промпта сбрасывает кэш ответов агента. Переводится |
prepared_response | string или null | Заготовленное первое сообщение: показывается сразу, без вызова модели. Переводится |
category | string или null | Первая категория из categories. Старое поле, сервер держит его равным categories[0] |
categories | array | Все категории агента: до 10 строк по 64 символа. Пустые и повторы выбрасываются. Одни на все языки. Есть всегда |
dialog_type | string или null | Тип диалога для подбора своего пейволла. Приводится к нижнему регистру, оставляются a-z, цифры, _, -, пробел, до 64 символов |
file_upload_autosend | boolean | Отправлять сообщение сразу после выбора файла кнопкой «Загрузить файл». Умолчание false, null в запросе — тоже false. Есть всегда |
locales | object или null | Переводы текстовых полей по языкам, см. ниже. Есть всегда |
cached_responses | object или null | Автоматический кэш ответов модели по языкам. Только чтение, пишет сам чат. Есть всегда |
prepared_suggestions | array | Варианты ответа под первым сообщением [{text, response, response_cached}]. Есть всегда, см. Свойства config |
prepared_images | array | Галерея картинок первого сообщения [{url, alt}]. Есть всегда |
gallery_layout | string | Раскладка галереи: grid или row. Есть всегда |
tags | array | Служебные теги для отбора. Есть всегда |
source_id | integer или null | Из какого агента скопирован. Есть всегда |
root_id | integer | Корень цепочки копий, у оригинала — свой id. Есть всегда |
config | object | Только в запросе: все ключи config одним объектом. В ответе не приходит — ключи уже разложены плоско |
Как ведут себя значения action:
action | Что происходит при выборе |
|---|---|
send | Обычный агент: диалог с промптом, заготовленным первым сообщением и вариантами ответа |
image | Экран создания изображения: загрузка фото, промпт, лендинг. Тексты экрана — ключи image_* в config |
document | Экран загрузки документа. Тексты — ключи document_* |
voice | Голосовой режим |
diagram | Режим диаграмм |
plot | Режим графиков |
search | Поиск в интернете |
character | Диалог с персонажем: имя и аватар из character_name и character_avatar, промпт становится системным |
Переводы: locales
Текстовые поля переводятся картой «язык → поля». Учитываются только переводимые ключи, остальные (action, image, categories, tags и т.п.) молча отбрасываются — они одни на все языки.
Переводимые ключи: label, prompt, prepared_response, prepared_suggestions, subtitle, badge, character_name, file_upload_button_label, out_of_credits_text, out_of_credits_image, profile_author, page_markdown, все тексты экранов image_* и document_* (кроме флагов и image_layout, image_references, image_gallery_kind, image_landing_action).
{
"locales": {
"en": { "label": "Resume for a job", "subtitle": "Tailor your CV", "profile_author": "HR team" },
"de": { "label": "Lebenslauf" }
}
}
Внутри перевода старое имя profile_markdown тоже принимается и сохраняется как page_markdown. Базовый page_markdown — английская страница агента, в locales.<язык>.page_markdown лежит полный документ страницы на этом языке, см. Свойства config.
В PUT карта сливается с сохранённой: прислали {"en": {"badge": "new"}} — поменяется только en.badge, остальные языки и поля останутся. Удалить язык этим методом нельзя, только перезаписать поля. Пустой перевод на чтении не перекрывает базовое значение. Язык должен быть включён у ассистента — см. Языки и переводы.
Список агентов
Все агенты ассистента в порядке order, со всеми языками в locales. Параметра языка нет: тексты отдаются в базовом виде, а response_cached у вариантов ответа всегда null — сам кэш лежит в cached_responses.
GET /assistants/{assistantId}/agents
| Параметр | Тип | Обяз. | Описание |
|---|---|---|---|
assistantId | integer | да | Путь. Свой ассистент или открытый вам совместным доступом |
curl -s "$BASE/assistants/$ASSISTANT/agents" \
-H "Authorization: Bearer $KEY"
{
"success": true,
"agents": [
{
"id": 3676,
"slug": "scholar-gpt",
"order": 47,
"label": "Scholar GPT",
"icon": null,
"emoji": null,
"image": "/storage/welcome-cards/scholar-gpt-avatar.png",
"image_poster": null,
"reference_image": null,
"subtitle": "Enhance research with 200M+ resources and built-in critical reading skills.",
"badge": null,
"action": "send",
"display_type": "image-tile",
"prompt": "You are Scholar GPT. …",
"prepared_response": null,
"category": "Исследования и анализ",
"categories": ["Исследования и анализ"],
"dialog_type": null,
"file_upload_autosend": false,
"tags": ["customgpt"],
"prompt_target": "system",
"profile_author": "awesomegpts.ai",
"profile_screens": [],
"prepared_suggestions": [
{ "text": "Find the latest research about AI", "response": null, "response_cached": null }
],
"locales": { "en": { "…": "…" } },
"prepared_images": [],
"gallery_layout": "grid",
"cached_responses": null,
"source_id": null,
"root_id": 3676
}
],
"commands": ["… тот же массив …"]
}
Создать агента
Создаёт агента в конце списка. Картинку можно отдать прямо в этом запросе — data URL, файлом или внешней ссылкой, см. раздел «Картинка в запросе агента» ниже. Ключи config шлются плоско на верхнем уровне ("tags": […], "page_markdown": "…") или одним объектом config — проверяются они одинаково.
POST /assistants/{assistantId}/agents
Все параметры, кроме assistantId, — в теле (application/json или multipart/form-data).
| Параметр | Тип | Обяз. | Описание |
|---|---|---|---|
assistantId | integer | да | Путь |
label | string или null | да | Название и подпись карточки, до 255 символов. Ключ должен присутствовать; пусто или null — «Новый агент». Переводится |
slug | string | нет | Идентификатор для ссылок ?agent=<slug>, до 120 символов. Не задан — собирается из label транслитом, при совпадении с другим агентом ассистента получает суффикс -2, -3 |
action | string | нет | send (умолчание), image, document, voice, diagram, plot, search, character |
display_type | string | нет | button (умолчание), icon-tile, image-tile, image-caption, persona |
icon | string | нет | Значок Lucide для button, до 64 символов |
emoji | string | нет | Эмодзи для icon-tile и persona, до 16 символов |
image | string или file | нет | Картинка карточки и аватар профиля. Адрес (https://…, /storage/…), data URL, внешняя ссылка или файл multipart. Картинки png, jpeg, webp, gif; файлом ещё svg и видео mp4, webm. После сохранения — адрес до 1024 символов |
image_poster | string или file | нет | Статичный кадр к видео в image: png, jpeg, webp, gif. Видео — 422 |
reference_image | string или file | нет | Картинка-образец для генерации изображений |
subtitle | string | нет | Короткое описание, до 255 символов: подзаголовок persona, описание в каталоге и на экране-профиле. Переводится |
badge | string | нет | Мини-бейдж, до 64 символов. Переводится |
prompt | string | нет | Промпт агента, длина не ограничена. Куда уходит — prompt_target. Переводится |
prepared_response | string | нет | Заготовленное первое сообщение, показывается без вызова модели. Переводится |
categories | array | нет | Категории — вкладки и секции приветственного экрана: до 10 строк по 64 символа, пустые и повторы убираются. Заменяется целиком |
category | string | нет | Старое поле: одна категория, до 64 символов. Прислали только его — categories станет [category]; прислали оба — побеждает categories |
dialog_type | string | нет | Тип диалога для подбора своего пейволла, до 64 символов; нижний регистр, a-z, цифры, _, -, пробел |
order | integer | нет | Позиция в списке, от 0. Не задан — последним |
file_upload_autosend | boolean | нет | Отправлять сообщение сразу после выбора файла кнопкой «Загрузить файл». Умолчание false |
locales | object | нет | Переводы: {"en": {"label": "…"}, "ru": {"page_markdown": "…"}}, см. «Переводы: locales» выше |
config | object | нет | Ключи config одним объектом. Слияние — ниже |
ключи config плоско | — | нет | prompt_target, prepared_suggestions, prepared_images, tags, profile_author, profile_author_url, profile_screens, page_url, page_markdown, model, capabilities и остальные — все ключи с типами и лимитами на странице Свойства config |
Как сливается config. Из присланных ключей — сначала из объекта config, затем плоских — собирается правка и накладывается на сохранённый config агента (при создании — на пустой). Присланный ключ заменяет значение, "ключ": null удаляет ключ, неприсланные остаются как были. Если ключ пришёл и плоско, и внутри config, побеждает плоский. Значения-массивы (tags, prepared_suggestions, prepared_images, profile_screens) внутри ключа не сливаются — массив заменяется целиком. Строки profile_author, profile_author_url, page_markdown обрезаются по краям, пустая строка удаляет ключ.
Пример: агент в стиле кастомного GPT
Один запрос создаёт агента с аватаром из data URL, экраном-профилем, вариантами сообщений, адресом страницы на сайте и её текстом на двух языках. page_markdown — полный документ страницы для OnPress: frontmatter, строка вставки чата onpress/assistant и тело с H2 и FAQ. Базовый документ — английский, русский лежит в locales.ru.page_markdown. Формат документа — на странице Свойства config.
Английский документ page-en.md (сокращён):
---
name: "CV Review"
seo_title: "CV Review — find weak spots in your resume | bota.chat"
seo_description: "CV Review: get a point-by-point resume check with concrete fixes. Try it free on bota.chat."
keyword: "cv review"
slug: razbor-reziume
url: /base/razbor-reziume/
status: publish
lang: en
frame: landing
---
<!-- onpress/assistant {"id":"x8OA7Azs4hBy","agent":"razbor-reziume","agent_view":"profile"} /-->
CV Review is an assistant that checks your resume point by point and suggests concrete fixes.
## What it checks
Structure, wording of your experience, achievements with numbers, keywords for the job.
## CV Review FAQ
<!-- onpress/faq -->
### Is it free?
Yes, the first checks are free.
<!-- /onpress/faq -->
Русский документ page-ru.md устроен так же, с lang: ru и своими текстами. Тело запроса собираем скриптом, чтобы подставить base64 картинки и документы страниц:
python3 - <<'EOF' > agent.json
import base64, json
img = base64.b64encode(open("avatar.png", "rb").read()).decode()
print(json.dumps({
"label": "Разбор резюме",
"slug": "razbor-reziume",
"action": "send",
"display_type": "image-tile",
"image": f"data:image/png;base64,{img}",
"subtitle": "Найду слабые места в резюме и предложу правки",
"prompt": "Ты карьерный консультант. Разбирай резюме пользователя по пунктам.",
"prompt_target": "system",
"categories": ["Производительность"],
"tags": ["customgpt"],
"profile_author": "Команда bota.chat",
"profile_author_url": "https://bota.chat/",
"page_url": "/base/razbor-reziume/",
"page_markdown": open("page-en.md").read(),
"prepared_suggestions": [
{"text": "Проверь моё резюме"},
"Как описать опыт без стажа?",
{"text": "Сделай резюме короче", "response": "Пришлите резюме текстом или файлом."}
],
"locales": {
"en": {"label": "CV review", "subtitle": "I will find weak spots in your CV and suggest fixes"},
"ru": {"page_markdown": open("page-ru.md").read()}
}
}, ensure_ascii=False))
EOF
curl -s -X POST "$BASE/assistants/$ASSISTANT/agents" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
--data-binary @agent.json
Ответ (живой запрос, сокращён):
{
"success": true,
"agent": {
"id": 3687,
"slug": "razbor-reziume",
"order": 51,
"label": "Разбор резюме",
"image": "https://framesuite.app/storage/welcome-cards/6794ffb4-1e8d-4d9b-b82e-be3fc12118b7.png",
"image_poster": null,
"subtitle": "Найду слабые места в резюме и предложу правки",
"action": "send",
"display_type": "image-tile",
"prompt": "Ты карьерный консультант. Разбирай резюме пользователя по пунктам.",
"prepared_response": null,
"category": "Производительность",
"categories": ["Производительность"],
"file_upload_autosend": false,
"prompt_target": "system",
"prepared_suggestions": [
{ "text": "Проверь моё резюме", "response": null, "response_cached": null },
{ "text": "Как описать опыт без стажа?", "response": null, "response_cached": null },
{ "text": "Сделай резюме короче", "response": "Пришлите резюме текстом или файлом.", "response_cached": null }
],
"profile_author": "Команда bota.chat",
"profile_author_url": "https://bota.chat/",
"page_url": "/base/razbor-reziume/",
"page_markdown": "---\nname: \"CV Review\"\n…\n<!-- /onpress/faq -->",
"tags": ["customgpt"],
"locales": {
"en": { "label": "CV review", "subtitle": "I will find weak spots in your CV and suggest fixes" },
"ru": { "page_markdown": "---\nname: \"Разбор резюме\"\n…" }
},
"prepared_images": [],
"gallery_layout": "grid",
"cached_responses": null,
"source_id": null,
"root_id": 3687
},
"command": { "…": "тот же объект" }
}
В image уже адрес на framesuite.app — картинка сохранена так же, как через upload/image. У page_markdown и profile_author_url обрезаются пробелы по краям, остальное хранится как прислано. Остальные колонки (icon, emoji, badge и т.д.) в ответе тоже есть, со значением null.
Изменить агента
Меняет только присланные поля. Ключи config — плоские и внутри объекта config — сливаются с сохранённым config по тем же правилам, что при создании; locales сливаются с сохранёнными переводами. Картинки принимаются так же, как при создании; файлом — только через POST с _method=PUT, см. ниже.
PUT /assistants/{assistantId}/agents/{agentId}
| Параметр | Тип | Обяз. | Описание |
|---|---|---|---|
assistantId | integer | да | Путь |
agentId | integer | да | Путь. Агент этого ассистента |
| любые параметры создания | — | нет | Тело. Все необязательны, label тоже |
В примере английская страница пишется старым именем profile_markdown, page_url удаляется через config, profile_author_url — плоским null, profile_author меняется внутри config, русская страница заменяется в locales:
curl -s -X PUT "$BASE/assistants/$ASSISTANT/agents/3687" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{
"profile_markdown": "---\nname: \"CV Review\"\n…",
"config": {"page_url": null, "profile_author": "Команда docs"},
"profile_author_url": null,
"locales": {"ru": {"profile_markdown": "---\nname: \"Разбор резюме\"\n…"}}
}'
Ответ (живой запрос, только затронутые и соседние ключи):
{
"success": true,
"agent": {
"id": 3687,
"image": "https://framesuite.app/storage/welcome-cards/6794ffb4-1e8d-4d9b-b82e-be3fc12118b7.png",
"profile_author": "Команда docs",
"page_markdown": "---\nname: \"CV Review\"\n…",
"tags": ["customgpt"],
"locales": {
"en": { "label": "CV review", "subtitle": "I will find weak spots in your CV and suggest fixes" },
"ru": { "page_markdown": "---\nname: \"Разбор резюме\"\n…" }
}
},
"command": { "…": "тот же объект" }
}
page_url и profile_author_url из ответа пропали, profile_markdown сохранился как page_markdown и под старым именем не отдаётся, остальной config (tags, варианты сообщений) не тронут. В locales поменялась только русская страница, en остался как был.
Повторный PUT всего агента, полученного через GET, безопасен: адреса картинок уже на framesuite.app, заново они не скачиваются.
Объект config в PUT не заменяет сохранённый, а вливается в него: присланный ключ заменяет значение, "ключ": null удаляет ключ, неприсланные остаются. До 26.09.2026 объект config заменял всё целиком.
Удалить агента
Удаляет агента вместе с его настройками. Файлы базы знаний с агентом не удаляются — снимите их заранее методом базы знаний.
DELETE /assistants/{assistantId}/agents/{agentId}
| Параметр | Тип | Обяз. | Описание |
|---|---|---|---|
assistantId | integer | да | Путь |
agentId | integer | да | Путь |
curl -s -X DELETE "$BASE/assistants/$ASSISTANT/agents/3682" \
-H "Authorization: Bearer $KEY"
{ "success": true }
Изменить порядок агентов
Выставляет order по позиции в присланном списке: первый id получает 0, второй 1 и так далее. Агенты, которых нет в списке, сохраняют свой order — поэтому присылайте полный список, иначе позиции совпадут. Порядок общий для всех секций и каталога.
PUT /assistants/{assistantId}/agents/reorder
| Параметр | Тип | Обяз. | Описание |
|---|---|---|---|
assistantId | integer | да | Путь |
ids | array | да | Тело. Id агентов сверху вниз. Элемент — число или объект {"id": …}. Синонимы имени поля: order, agents, commands |
curl -s -X PUT "$BASE/assistants/$ASSISTANT/agents/reorder" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"ids": [797, 936, 944, 799]}'
{ "success": true, "updated": 4 }
updated — сколько id из списка нашлось у ассистента. Чужие id пропускаются.
Картинка в запросе агента
Картинки агента отдаются прямо в POST /agents и PUT /agents/{agentId} — отдельная загрузка через upload/image не нужна. Сервер сохраняет файл тем же путём, что upload/image: те же лимиты, папка, сжатие и webp-копия, — и записывает в поле свой адрес. В ответе агент уже с https://framesuite.app/storage/….
| Поле | Как сохраняется |
|---|---|
image, image_poster, reference_image, character_avatar, элементы image_references | Как context=card: папка welcome-cards/, ширина до 480 px |
url элементов prepared_images (или элемент-строка), out_of_credits_image, locales.<язык>.out_of_credits_image | Как context=content: папка welcome-content/, ширина до 1600 px |
Поля из config принимаются и плоско, и внутри объекта config.
| Способ | Значение поля | Форматы и лимиты |
|---|---|---|
| data URL в JSON | data:image/png;base64,… | png, jpeg, webp, gif. Тип определяется по содержимому, а не по заголовку data URL. До 5 МБ, gif до 4 МБ |
| Файл multipart | -F image=@avatar.png, галерея — -F 'prepared_images[]=@a.png' | Как у upload/image с нужным context: в поля card — ещё svg и видео mp4, webm (до 8 МБ). Формат — по расширению имени файла |
| Внешняя ссылка | https://… | Сервер скачивает её: таймаут 15 с, до 3 редиректов, ответ только с Content-Type: image/*, лимиты как у data URL. Приватные и служебные адреса (localhost, 10.*, 192.168.*, 169.254.* и т.п., в том числе после редиректа) не скачиваются. Ссылка на видео (.mp4, .webm) остаётся ссылкой как есть |
Не перекачиваются адреса framesuite.app и его поддоменов, пути /storage/… и значения, которые у агента уже сохранены. Если в image видео, статичный кадр положите в image_poster тем же способом — иначе в шапке чата, списках и превью ссылки у агента будет заглушка.
Файлом: multipart
В multipart поля-объекты и списки — config, locales, prepared_suggestions, prepared_images, image_references, categories, tags, capabilities, profile_screens — передаются строкой JSON, остальные — обычными полями формы.
curl -s -X POST "$BASE/assistants/$ASSISTANT/agents" \
-H "Authorization: Bearer $KEY" \
-F "label=Юрист" \
-F "display_type=persona" \
-F "image=@avatar.png" \
-F 'categories=["Документы"]' \
-F 'config={"tags":["customgpt"],"page_markdown":"Текст страницы","agent_callable":true}' \
-F 'prepared_suggestions=[{"text":"Проверь договор"}]'
PHP не разбирает multipart у PUT, поэтому заменить картинку файлом можно только через POST на адрес агента с полем _method=PUT:
curl -s -X POST "$BASE/assistants/$ASSISTANT/agents/3687" \
-H "Authorization: Bearer $KEY" \
-F _method=PUT \
-F image=@new.png
Обычное поле формы всегда строка: -F agent_callable=0 сохранится в config строкой "0", а не false. Флаги config (agent_callable, unlimited, agent_post и другие) передавайте внутри JSON-строки config — там они остаются настоящими true и false.
Внешней ссылкой
curl -s -X PUT "$BASE/assistants/$ASSISTANT/agents/3687" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{
"image": "https://bota.chat/wp-content/uploads/sites/264/2026/09/upload-59e988d2-150x150.png",
"prepared_images": [{"url": "https://bota.chat/wp-content/uploads/sites/264/2026/09/upload-59e988d2-150x150.png", "alt": "Пример"}]
}'
{
"success": true,
"agent": {
"id": 3687,
"image": "https://framesuite.app/storage/welcome-cards/0556f374-7d60-45b2-acca-1d9750122177.png",
"prepared_images": [
{ "url": "https://framesuite.app/storage/welcome-content/990401e4-32b1-4666-ad00-69eb333e0415.png", "alt": "Пример" }
]
},
"command": { "…": "тот же объект" }
}
Ошибки картинок
Ошибка — 422 в общем формате, запрос не выполняется целиком. Ключ ошибки — путь поля: image, prepared_images.0, config.prepared_images.0.url, locales.en.out_of_credits_image.
| Текст ошибки | Когда |
|---|---|
image: ожидается data URL вида data:image/png;base64,… | Нет ;base64 или запятой |
image: не удалось декодировать base64. | Битый base64 |
image: не картинка: принимаются png, jpeg, webp и gif (получено text/plain). | Содержимое data URL или ссылки — не картинка этих форматов |
image: картинка больше 5120 КБ. | data URL или файл по ссылке слишком большой |
image: ссылка не принимается: IP 127.0.0.1 принадлежит приватному или зарезервированному диапазону. | Ссылка на приватный или служебный адрес |
image: по ссылке не картинка (Content-Type text/html). | Ссылка отдала не картинку |
image: ссылка ответила кодом 404. | Ссылка отдала ошибку |
image: не удалось скачать картинку по ссылке. | Таймаут или обрыв соединения |
config: ожидается JSON-объект или массив. | В multipart строка поля-объекта не разбирается как JSON |
{
"success": false,
"errors": { "image": ["image: не удалось декодировать base64."] }
}
Запасной путь — загрузить файл отдельно через upload/image и записать полученный url в поле агента.
Скопировать агента
Отдельного метода копирования в /api/v1 нет: кнопка «Копировать» в таблице агентов дашборда работает только в интерфейсе. Она переносит все поля агента, кроме кэша ответов, и очищает у копии page_url; при копировании в другого ассистента снимает frame_id и оставляет в profile_screens только экраны приёмника. Через API агент копируется двумя запросами — взять его из списка и создать заново без служебных полей. Так можно скопировать и в другого ассистента, к которому у ключа есть доступ.
SRC=3676 # какой агент копируем
TARGET=$ASSISTANT # куда: этот же или другой ассистент
curl -s "$BASE/assistants/$ASSISTANT/agents" -H "Authorization: Bearer $KEY" \
| jq --argjson id $SRC '.agents[] | select(.id == $id)
| .source_id = .id
| del(.id, .slug, .order, .category, .cached_responses, .page_url)
| .label = .label + " (копия)"' > copy.json
curl -s -X POST "$BASE/assistants/$TARGET/agents" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
--data-binary @copy.json
Что учесть:
| Что | Как |
|---|---|
slug | Не переносите — новый соберётся из label, у того же ассистента получит суффикс -2 |
source_id, root_id | Поставьте source_id = id оригинала и оставьте root_id оригинала — так копии схлопываются с ним в общей аналитике |
cached_responses | Не переносится: кэш ответов принадлежит оригиналу |
page_url | Уберите, как делает дашборд: два агента с одним адресом страницы на сайте не нужны |
frame_id, profile_screens | Фрейм и приветственные экраны принадлежат ассистенту: при копировании в другого ассистента уберите frame_id (иначе 422) и оставьте в profile_screens только слаги экранов нового ассистента |
| Коннекторы, секреты, база знаний | Не копируются. Коннекторы и файлы знаний перенесите их методами, значения секретов заведите заново — API их не отдаёт |
| Картинки | Адреса /storage/… общие для платформы и работают у любого ассистента |
Ошибки
| HTTP | Когда |
|---|---|
| 401 | Нет ключа или он неверный |
| 403 | {"success": false, "error": "Account disabled", "message": "…"} — владелец ключа отключён, см. Авторизация |
| 404 | {"success": false, "error": "Project not found or access denied"} — ассистент не ваш и не открыт вам совместным доступом. Доступ — только свои и расшаренные ассистенты, исключений для администраторов платформы в API нет |
| 404 | {"success": false, "error": "Agent not found", "message": "Agent not found"} — агент другого ассистента |
| 404 | Ассистента или агента с таким id нет вовсе: {"success": false, "error": "No query results for model …", "message": "…"}. Нечисловой id ассистента или агента в пути — тоже 404 (The route … could not be found.) |
| 422 | Ошибка проверки полей: {"success": false, "errors": {"поле": ["текст"]}} |
| 422 | POST без ключа label: The label field must be present. |
| 422 | profile_author_url не http(s)-ссылка: profile_author_url: ожидается ссылка http(s)://… (внутри config — под ключом config.profile_author_url) |
| 422 | Пустая строка в profile_screens: The profile_screens.0 field must be a string. |
| 422 | Картинка в запросе не сохранилась — см. «Ошибки картинок» выше |
| 422 | reorder: ids must be array, ids is empty, no agents matched в поле message |
Пример ответа 422:
{
"success": false,
"errors": {
"action": ["The selected action is invalid."],
"gallery_layout": ["gallery_layout: допустимо только \"grid\" (сетка с переносом) или \"row\" (одна строка с прокруткой)."],
"categories": ["Категорий у агента может быть не больше 10."],
"config.panel": ["The selected config.panel is invalid."],
"config.tags": ["The config.tags field must be an array."]
}
}
Ключи внутри объекта config проверяются теми же правилами, что плоские, и ошибка по ним приходит под именем config.<ключ>.
Дальше
- Свойства config — все настройки агента: первое сообщение, варианты ответа, модель, теги, профиль.
- Экран-профиль и ссылки — как открыть агента ссылкой и показать его карточкой в стиле GPT.
- Сценарии — агент с профилем и страницей на сайте, копирование.