From c61701b52ddd51ed0a1eeff75b0153ee5faf9cdc Mon Sep 17 00:00:00 2001 From: Valeriy Selitskiy <239034+iamwavecut@users.noreply.github.com> Date: Tue, 20 Oct 2026 19:25:24 +0200 Subject: [PATCH] Report withheld run_python files as received; ask for local labels A SAFE virtual dialog told the model only "The script finished." after a withheld delivery, so Gemma kept writing send_files=[...] into its reply as if it still had to send the chart. The withheld files now read as received, like the other SAFE tools that fake delivery, so test dialogs continue the way a real chat does. Gemma also kept English chart labels for Russian requests although the tool description asked otherwise; the run_python line of the system prompt now asks for titles and labels in the user's language. --- crates/openplotva-app/src/python_sandbox.rs | 16 +++++++++++++--- prompts/aifarm/system.prompt | 2 +- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/crates/openplotva-app/src/python_sandbox.rs b/crates/openplotva-app/src/python_sandbox.rs index ddf2c685..93d19f6a 100644 --- a/crates/openplotva-app/src/python_sandbox.rs +++ b/crates/openplotva-app/src/python_sandbox.rs @@ -318,7 +318,8 @@ struct DeliveryOutcome { report: DeliveryReport, /// Named files left unsent because the script failed. skipped: Vec, - /// Files a run with withheld delivery would have sent. + /// Files a run with withheld delivery would have sent. The model reads + /// them as received, so a test dialog continues as a real chat would. withheld: Vec, /// Changed files left unsent because there were too many to send unasked. unselected: usize, @@ -501,10 +502,15 @@ fn run_result(response: &RunResponse, inputs: Vec, outcome: DeliveryOutc let (code, reason) = match (response.termination, response.exit_code) { (Termination::Exited, Some(0)) if report.errors.is_empty() => { - let message = if !report.sent.is_empty() { + let received = if report.sent.is_empty() { + &withheld + } else { + &report.sent + }; + let message = if !received.is_empty() { format!( "The script finished; the chat received {}.", - report.sent.join(", ") + received.join(", ") ) } else if unselected > 0 { format!( @@ -1294,6 +1300,10 @@ mod tests { assert_eq!(result.status, TOOL_RESULT_STATUS_OK); assert!(delivery.delivered.lock().expect("delivered").is_empty()); + assert_eq!( + result.message, + "The script finished; the chat received chart.png." + ); let data = result.data.expect("data"); assert_eq!(data["send_withheld"], json!(["chart.png"])); assert!(data.get("sent").is_none()); diff --git a/prompts/aifarm/system.prompt b/prompts/aifarm/system.prompt index 0e5c0627..b811c8ab 100644 --- a/prompts/aifarm/system.prompt +++ b/prompts/aifarm/system.prompt @@ -9,7 +9,7 @@ В случайном включении можно поставить реакцию или вызвать finish_turn без текста. При прямом обращении ответь или уточни. Команды и разговорные шорткаты задают намерение пользователя: выполни соответствующее действие через инструмент. Прямая просьба нарисовать, сгенерировать, переделать или отредактировать изображение требует вызова draw_image (draw_api для %). Не заменяй действие рассуждением, описанием, обещанием или вопросом «начать?». По известному запросу сразу вызови инструмент; уточняй только недостающую деталь, без которой результат нельзя получить. Обычное рисование не требует предварительного get_user_status: исполнитель сам проверит доступ и лимиты. Действующие ограничения контента и результат инструмента сохраняют силу. - Графики, диаграммы, схемы и планы по данным или размерам, таблицы, конвертацию файлов, обработку аудио и видео и точные расчёты делай через run_python: draw_image рисует иллюстрации, а не данные. Чтобы поправить прежний результат run_python, возьми его код из истории и измени только то, о чём просят. + Графики, диаграммы, схемы и планы по данным или размерам, таблицы, конвертацию файлов, обработку аудио и видео и точные расчёты делай через run_python: draw_image рисует иллюстрации, а не данные. Заголовки, подписи и текст на графиках пиши на языке собеседника. Чтобы поправить прежний результат run_python, возьми его код из истории и измени только то, о чём просят. Для draw_image и draw_api всегда передавай caption: короткое название запрошенного изображения на языке пользователя. Убери обращение к боту, просьбу рисовать и слова вежливости. Сохрани смысл, имена и детали пользователя; название оформи естественно, с заглавной буквы. «Плотва, нарисуй собаквака» → caption «Собака-квака»; «Плотва, а нарисуй же мне, пожалуйста, золотую рыбку в кляре» → caption «Золотая рыбка в кляре». В prompt передавай отдельные, при необходимости обогащённые инструкции генератору. Не добавляй в caption придуманные для генератора детали и технический промпт. Если вызов вернул image_caption_required, добавь подпись и повтори вызов: генерация ещё не началась.