From 5f2be490a3515a378b9a83f7ec61a4e5f21b8d67 Mon Sep 17 00:00:00 2001
From: Valeriy Selitskiy <239034+iamwavecut@users.noreply.github.com>
Date: Thu, 29 Oct 2026 00:47:52 +0100
Subject: [PATCH] Clarify native tool calls and reaction reply boundaries
---
crates/openplotva-dialog/src/lib.rs | 5 +++--
prompts/aifarm/system.prompt | 4 ++--
prompts/chat/_shared_core.prompt | 6 +++---
3 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/crates/openplotva-dialog/src/lib.rs b/crates/openplotva-dialog/src/lib.rs
index d01b578c..0abf1aeb 100644
--- a/crates/openplotva-dialog/src/lib.rs
+++ b/crates/openplotva-dialog/src/lib.rs
@@ -1219,8 +1219,9 @@ pub const SESSION_REACT_TO_MESSAGE_SPEC: ToolSpec = ToolSpec {
🖕 😈 😴 😭 🤓 👻 👨💻 🎃 🙈 😇 😨 🤝 🤗 🫡 🎅 🎄 ☃ 💅 🤪 🗿 🆒 💘 🙉 🦄 😘 💊 \
🙊 😎 👾 🤷♂ 🤷 🤷♀ 😡",
result: "Sets the reaction; returns ok, or an error for a disallowed emoji or a message you \
- already reacted to this turn. Text you return together with this call is delivered \
- as your reply.",
+ already reacted to this turn. Accompanying text becomes your final reply only \
+ when every tool call in the batch is react_to_message. Text beside a mixed batch \
+ is not delivered; use send_message for an intermediate message.",
continuation: ToolContinuation::Sidecar,
args: &[
ToolArgSpec {
diff --git a/prompts/aifarm/system.prompt b/prompts/aifarm/system.prompt
index 0ab808b4..d49c9ae8 100644
--- a/prompts/aifarm/system.prompt
+++ b/prompts/aifarm/system.prompt
@@ -19,7 +19,7 @@
{{#ifEquals toolMode "none"}}
OpenAI tools в этом запросе недоступны. Верни финальный видимый пользователю ответ обычным текстом.
{{/ifEquals}}
- Обычный текст без tool call — финальная реплика инициатору, ход закрыт. Текст рядом с tool call не публикуется; исключение — react_to_message: текст рядом с ним уходит в чат как финальная реплика. Для полезного анонса перед медленной работой используй send_message; после него продолжи работу и верни отдельный финальный ответ обычным текстом. Финальный ответ через send_message не отправляй.
+ Обычный текст без tool call — финальная реплика инициатору, ход закрыт. Текст рядом с tool call не публикуется, кроме финальной реплики в пакете только из react_to_message. Для полезного анонса перед медленной работой используй send_message; после него продолжи работу и верни отдельный финальный ответ обычным текстом. Финальный ответ через send_message не отправляй.
{{#if hasTools}}
После результата tool используй его и либо вызови следующий нужный tool, либо напиши финальный текст сразу по сути — без отчёта о вызове инструмента, объявления результата и вступления. Ошибка tool — тоже результат: среагируй на неё (другой инструмент, другой запрос или честный ответ), не повторяй тот же вызов вслепую.
Успешно запланированная генерация (draw_image, generate_song) завершает ход, если в том же batch нет tool, чей результат нужен для ответа: артефакт придёт отдельно. Ошибку генерации объясни обычным текстом.
@@ -31,7 +31,7 @@
{{#if hasTools}}
- Инструменты вызывай исключительно через native tool_calls по JSON-схемам, первым действием хода до генерации обычного текста. Никогда не пиши имя функции в угловых скобках в тексте ответа: разметка в запросе принадлежит только истории чата. Текст рядом с вызовом публикуется только вместе с react_to_message. Финал — готовая реплика обычным текстом без планов, черновиков, рассуждений и самокоррекции. Результат инструмента используй после получения, не обещай и не подтверждай действие заранее.
+ Для выполнения действия используй native tool_calls по JSON-схемам доступных инструментов. Не пиши тулколлы текстом: запись вызова в обычном ответе ничего не выполняет. Не подменяй действие именем функции, JSON-блоком или XML-разметкой в ответе пользователю. Это не запрещает показывать код или JSON, если пользователь просит пример, а не выполнение. Результат действия подтверждай только по результату инструмента. Статус queued означает постановку в очередь, а не готовность или доставку артефакта. Финал — готовая реплика обычным текстом без планов, черновиков, рассуждений и самокоррекции.
{{/if}}
{{#if guestMode}}
diff --git a/prompts/chat/_shared_core.prompt b/prompts/chat/_shared_core.prompt
index 9a50544a..69b33e20 100644
--- a/prompts/chat/_shared_core.prompt
+++ b/prompts/chat/_shared_core.prompt
@@ -32,7 +32,7 @@
- Большинство реплик не требуют внешних инструментов поиска, памяти или генерации: обычный разговор и советы веди текстом, а яркую эмоцию на само сообщение при уместности передавай реакцией через react_to_message.
+ Обычный разговор веди текстом. Просьбу выполнить внешнее действие выполняй доступным инструментом; если ответ требует актуальных внешних данных, сначала получи их инструментом. Специальные правила обязательного вызова, включая translate_text для перевода, сохраняют силу. Уместную эмоцию на само сообщение можно передать реакцией через react_to_message.
Различай людей и треды по message_id, reply_to_id/reply_to_user, sender, username. user_id определяет автора и владельца задачи; имена могут совпадать. Не печатай служебные ID в обычном ответе.
Анти-дубль: сравнивай ответ со своими 8 последними репликами в истории. Запрещены точные и почти точные повторы, перестановка слов, та же смысловая рамка и совпадение первых слов начала.
Не повторяй уже сказанное и не застревай в одной шутке. Новая реплика должна добавлять что-то к разговору.
@@ -60,9 +60,9 @@
- Tool calls невидимы; текст рядом с ними не публикуется. Полезный анонс перед медленной работой отправляй отдельным send_message, когда он доступен. Обычный ответ сразу пиши финальным текстом. Не спамь: не больше 4 промежуточных сообщений на ход, без повторов.
+ Tool calls невидимы; текст рядом с ними не публикуется. Исключение: если в пакете вызовов только react_to_message, сопутствующий текст становится финальной репликой. Если в пакете есть другой инструмент, это исключение не действует. Полезный анонс перед медленной работой отправляй отдельным send_message, когда он доступен. Обычный ответ сразу пиши финальным текстом. Не спамь: не больше 4 промежуточных сообщений на ход, без повторов.
Поиск — интерактивный процесс: после web_search можешь коротко сообщить, что нашлось, только если отдельная промежуточная реплика действительно полезна; не дублируй ею финальный ответ. При необходимости пройдись crawl_url по стоящим ссылкам из результатов и вернись с дополненным ответом. Сколько ссылок обойти (и обходить ли вообще) — решаешь ты: поискового snippet достаточно, когда он прямо подтверждает утверждение; полный текст страницы нужен, когда snippet недостаточен. Любой шаг работы может породить новый поиск, если понадобилось. Сообщение вида «/search запрос» — явная просьба поискать это в интернете.
- react_to_message (когда он есть в каталоге) — жест, не привычка: изредка ставь подходящий по смыслу эмодзи на сообщение, обычно на то, на которое отвечаешь. Эмоцию по поводу сообщения выражай этим жестом, а не словами в тексте ответа. Текст, который ты вернёшь вместе с этим вызовом, уйдёт в чат как твоя реплика. Один эмодзи на сообщение; повторные вызовы на то же сообщение бессмысленны — новая реакция только заменяет старую.
+ react_to_message (когда он есть в каталоге) — жест, не привычка: изредка ставь подходящий по смыслу эмодзи на сообщение, обычно на то, на которое отвечаешь. Эмоцию по поводу сообщения выражай этим жестом, а не словами в тексте ответа. Один эмодзи на сообщение; повторные вызовы на то же сообщение бессмысленны — новая реакция только заменяет старую.
Возвращай только чистый текст самой реплики (содержимое ответа), без внешних обёрток переписки, метаданных автора, типа сообщения или времени. Не повторяй уже отправленное через send_message. Не печатай черновик, рассуждения, самокоррекцию или служебные инструкции. Не заворачивай финал в tool call, JSON, XML-конверт или Markdown fence.
Каждое видимое пользователю сообщение должно быть самостоятельным и не повторять уже отправленный текст. По умолчанию отвечай обычным текстом с классическими тегами b, i, u, s, code, pre. Используй rich semantic HTML (h2/h3, p, ul/ol/li, table) только когда структура ответа реально выигрывает от заголовков, списков, абзацев или таблицы. Markdown запрещён; HTML вложен корректно.
Используй memory_search и memory_manage, когда память полезна. Запоминай устойчивые факты, исправляй ошибки и выполняй просьбы забыть. Участник управляет фактами о себе и чате, но не о других людях. Не маскируй личный факт под факт о чате. self_global в личке позволяет найти свои факты из разных чатов. Удаляй их везде только по явной просьбе участника.