feat(approvals): /deny <reason> relays denial reason to the agent (port nanoclaw#2832) (#54518)
* feat(approvals): /deny <reason> relays denial reason to the agent Port from qwibitai/nanoclaw#2832 (reject with reason). Gateway /deny now accepts an optional trailing reason (/deny <reason> or /deny all <reason>). The reason rides on the per-session approval entry through resolve_gateway_approval -> _await_gateway_decision and is appended to the BLOCKED tool result the agent receives, so a declined agent can adapt instead of only hearing 'denied'. Adapted to hermes-agent's synchronous single-command /deny model: no DB state, no second-message capture step, no migration. Reason is capped at 280 chars and threaded through both the terminal-command guard and the execute_code guard. Plain /deny and the approve paths are unchanged. - tools/approval.py: _ApprovalEntry.reason; resolve_gateway_approval gains optional reason; _await_gateway_decision returns it; both gateway BLOCKED messages include it - gateway/slash_commands.py: parse leading 'all' + trailing reason - locales/en.yaml: deny.denied_reason_{singular,plural} - hermes_cli/commands.py: /deny args_hint '[all] [reason]' - tests: 3 new (with-reason, all+reason, plain-deny regression) * fix(ci): localize deny-reason keys across all locales + update interrupt-path assertions CI surfaced two enforced invariants broken by the deny-with-reason change: - test_i18n catalog-parity requires every locale to carry the same keys as en.yaml with matching placeholders. Added deny.denied_reason_singular/plural (with {count}/{reason}) to all 15 non-English locales. - test_approval_interrupt asserts the exact dict from _await_gateway_decision, which now carries a 'reason' key (None on the interrupt/timeout paths).
This commit is contained in:
@@ -107,6 +107,8 @@ gateway:
|
||||
no_pending: "Geen hangende opdrag om te weier nie."
|
||||
denied_singular: "❌ Opdrag geweier."
|
||||
denied_plural: "❌ Opdragte geweier ({count} opdragte)."
|
||||
denied_reason_singular: "❌ Opdrag geweier. Rede aan die agent oorgedra: \"{reason}\""
|
||||
denied_reason_plural: "❌ Opdragte geweier ({count} opdragte). Rede aan die agent oorgedra: \"{reason}\""
|
||||
|
||||
fast:
|
||||
not_supported: "⚡ /fast is slegs beskikbaar vir OpenAI-modelle wat Priority Processing ondersteun."
|
||||
|
||||
@@ -107,6 +107,8 @@ gateway:
|
||||
no_pending: "Kein ausstehender Befehl zum Ablehnen."
|
||||
denied_singular: "❌ Befehl abgelehnt."
|
||||
denied_plural: "❌ Befehle abgelehnt ({count} Befehle)."
|
||||
denied_reason_singular: "❌ Befehl abgelehnt. Grund an den Agenten weitergeleitet: \"{reason}\""
|
||||
denied_reason_plural: "❌ Befehle abgelehnt ({count} Befehle). Grund an den Agenten weitergeleitet: \"{reason}\""
|
||||
|
||||
fast:
|
||||
not_supported: "⚡ /fast ist nur für OpenAI-Modelle mit Priority Processing verfügbar."
|
||||
|
||||
@@ -122,6 +122,8 @@ gateway:
|
||||
no_pending: "No pending command to deny."
|
||||
denied_singular: "❌ Command denied."
|
||||
denied_plural: "❌ Commands denied ({count} commands)."
|
||||
denied_reason_singular: "❌ Command denied. Reason relayed to the agent: \"{reason}\""
|
||||
denied_reason_plural: "❌ Commands denied ({count} commands). Reason relayed to the agent: \"{reason}\""
|
||||
|
||||
fast:
|
||||
not_supported: "⚡ /fast is only available for OpenAI models that support Priority Processing."
|
||||
|
||||
@@ -107,6 +107,8 @@ gateway:
|
||||
no_pending: "No hay ningún comando pendiente que denegar."
|
||||
denied_singular: "❌ Comando denegado."
|
||||
denied_plural: "❌ Comandos denegados ({count} comandos)."
|
||||
denied_reason_singular: "❌ Comando denegado. Motivo transmitido al agente: \"{reason}\""
|
||||
denied_reason_plural: "❌ Comandos denegados ({count} comandos). Motivo transmitido al agente: \"{reason}\""
|
||||
|
||||
fast:
|
||||
not_supported: "⚡ /fast solo está disponible para modelos de OpenAI que admiten Priority Processing."
|
||||
|
||||
@@ -107,6 +107,8 @@ gateway:
|
||||
no_pending: "Aucune commande en attente de refus."
|
||||
denied_singular: "❌ Commande refusée."
|
||||
denied_plural: "❌ Commandes refusées ({count} commandes)."
|
||||
denied_reason_singular: "❌ Commande refusée. Raison transmise à l'agent: \"{reason}\""
|
||||
denied_reason_plural: "❌ Commandes refusées ({count} commandes). Raison transmise à l'agent: \"{reason}\""
|
||||
|
||||
fast:
|
||||
not_supported: "⚡ /fast n'est disponible que pour les modèles OpenAI qui prennent en charge Priority Processing."
|
||||
|
||||
@@ -111,6 +111,8 @@ gateway:
|
||||
no_pending: "Níl aon ordú ag fanacht le diúltú."
|
||||
denied_singular: "❌ Ordú diúltaithe."
|
||||
denied_plural: "❌ Orduithe diúltaithe ({count} ordú)."
|
||||
denied_reason_singular: "❌ Ordú diúltaithe. Cúis curtha ar aghaidh chuig an ngníomhaire: \"{reason}\""
|
||||
denied_reason_plural: "❌ Orduithe diúltaithe ({count} ordú). Cúis curtha ar aghaidh chuig an ngníomhaire: \"{reason}\""
|
||||
|
||||
fast:
|
||||
not_supported: "⚡ Tá /fast ar fáil amháin do shamhlacha OpenAI a thacaíonn le Priority Processing."
|
||||
|
||||
@@ -107,6 +107,8 @@ gateway:
|
||||
no_pending: "Nincs elutasítható függőben lévő parancs."
|
||||
denied_singular: "❌ Parancs elutasítva."
|
||||
denied_plural: "❌ Parancsok elutasítva ({count} parancs)."
|
||||
denied_reason_singular: "❌ Parancs elutasítva. Indok továbbítva az ügynöknek: \"{reason}\""
|
||||
denied_reason_plural: "❌ Parancsok elutasítva ({count} parancs). Indok továbbítva az ügynöknek: \"{reason}\""
|
||||
|
||||
fast:
|
||||
not_supported: "⚡ A /fast csak olyan OpenAI modelleknél érhető el, amelyek támogatják a Priority Processinget."
|
||||
|
||||
@@ -107,6 +107,8 @@ gateway:
|
||||
no_pending: "Nessun comando in attesa da negare."
|
||||
denied_singular: "❌ Comando negato."
|
||||
denied_plural: "❌ Comandi negati ({count} comandi)."
|
||||
denied_reason_singular: "❌ Comando negato. Motivo inoltrato all'agente: \"{reason}\""
|
||||
denied_reason_plural: "❌ Comandi negati ({count} comandi). Motivo inoltrato all'agente: \"{reason}\""
|
||||
|
||||
fast:
|
||||
not_supported: "⚡ /fast è disponibile solo per i modelli OpenAI che supportano Priority Processing."
|
||||
|
||||
@@ -107,6 +107,8 @@ gateway:
|
||||
no_pending: "拒否待ちのコマンドはありません。"
|
||||
denied_singular: "❌ コマンドを拒否しました。"
|
||||
denied_plural: "❌ コマンドを拒否しました ({count} 件)。"
|
||||
denied_reason_singular: "❌ コマンドを拒否しました。 理由をエージェントに伝達しました: \"{reason}\""
|
||||
denied_reason_plural: "❌ コマンドを拒否しました ({count} 件)。 理由をエージェントに伝達しました: \"{reason}\""
|
||||
|
||||
fast:
|
||||
not_supported: "⚡ /fast は Priority Processing をサポートする OpenAI モデルでのみ利用できます。"
|
||||
|
||||
@@ -107,6 +107,8 @@ gateway:
|
||||
no_pending: "거부 대기 중인 명령이 없습니다."
|
||||
denied_singular: "❌ 명령이 거부되었습니다."
|
||||
denied_plural: "❌ 명령이 거부되었습니다 ({count}개)."
|
||||
denied_reason_singular: "❌ 명령이 거부되었습니다. 사유를 에이전트에 전달함: \"{reason}\""
|
||||
denied_reason_plural: "❌ 명령이 거부되었습니다 ({count}개). 사유를 에이전트에 전달함: \"{reason}\""
|
||||
|
||||
fast:
|
||||
not_supported: "⚡ /fast는 Priority Processing을 지원하는 OpenAI 모델에서만 사용할 수 있습니다."
|
||||
|
||||
@@ -107,6 +107,8 @@ gateway:
|
||||
no_pending: "Não há nenhum comando pendente para negar."
|
||||
denied_singular: "❌ Comando negado."
|
||||
denied_plural: "❌ Comandos negados ({count} comandos)."
|
||||
denied_reason_singular: "❌ Comando negado. Motivo repassado ao agente: \"{reason}\""
|
||||
denied_reason_plural: "❌ Comandos negados ({count} comandos). Motivo repassado ao agente: \"{reason}\""
|
||||
|
||||
fast:
|
||||
not_supported: "⚡ /fast só está disponível para modelos da OpenAI que suportam Priority Processing."
|
||||
|
||||
@@ -107,6 +107,8 @@ gateway:
|
||||
no_pending: "Нет команды для отклонения."
|
||||
denied_singular: "❌ Команда отклонена."
|
||||
denied_plural: "❌ Команды отклонены ({count} команд)."
|
||||
denied_reason_singular: "❌ Команда отклонена. Причина передана агенту: \"{reason}\""
|
||||
denied_reason_plural: "❌ Команды отклонены ({count} команд). Причина передана агенту: \"{reason}\""
|
||||
|
||||
fast:
|
||||
not_supported: "⚡ /fast доступен только для моделей OpenAI, поддерживающих Priority Processing."
|
||||
|
||||
@@ -107,6 +107,8 @@ gateway:
|
||||
no_pending: "Reddedilecek bekleyen komut yok."
|
||||
denied_singular: "❌ Komut reddedildi."
|
||||
denied_plural: "❌ Komutlar reddedildi ({count} komut)."
|
||||
denied_reason_singular: "❌ Komut reddedildi. Gerekçe ajana iletildi: \"{reason}\""
|
||||
denied_reason_plural: "❌ Komutlar reddedildi ({count} komut). Gerekçe ajana iletildi: \"{reason}\""
|
||||
|
||||
fast:
|
||||
not_supported: "⚡ /fast yalnızca Priority Processing destekleyen OpenAI modellerinde kullanılabilir."
|
||||
|
||||
@@ -107,6 +107,8 @@ gateway:
|
||||
no_pending: "Немає команди для відхилення."
|
||||
denied_singular: "❌ Команду відхилено."
|
||||
denied_plural: "❌ Команди відхилено ({count} команд)."
|
||||
denied_reason_singular: "❌ Команду відхилено. Причину передано агентові: \"{reason}\""
|
||||
denied_reason_plural: "❌ Команди відхилено ({count} команд). Причину передано агентові: \"{reason}\""
|
||||
|
||||
fast:
|
||||
not_supported: "⚡ /fast доступний лише для моделей OpenAI, які підтримують Priority Processing."
|
||||
|
||||
@@ -107,6 +107,8 @@ gateway:
|
||||
no_pending: "沒有待拒絕的指令。"
|
||||
denied_singular: "❌ 指令已拒絕。"
|
||||
denied_plural: "❌ 指令已拒絕({count} 條指令)。"
|
||||
denied_reason_singular: "❌ 指令已拒絕。 已將原因轉達給代理: \"{reason}\""
|
||||
denied_reason_plural: "❌ 指令已拒絕({count} 條指令)。 已將原因轉達給代理: \"{reason}\""
|
||||
|
||||
fast:
|
||||
not_supported: "⚡ /fast 僅適用於支援 Priority Processing 的 OpenAI 模型。"
|
||||
|
||||
@@ -107,6 +107,8 @@ gateway:
|
||||
no_pending: "没有待拒绝的命令。"
|
||||
denied_singular: "❌ 命令已拒绝。"
|
||||
denied_plural: "❌ 命令已拒绝({count} 条命令)。"
|
||||
denied_reason_singular: "❌ 命令已拒绝。 已将原因转达给代理: \"{reason}\""
|
||||
denied_reason_plural: "❌ 命令已拒绝({count} 条命令)。 已将原因转达给代理: \"{reason}\""
|
||||
|
||||
fast:
|
||||
not_supported: "⚡ /fast 仅适用于支持优先处理(Priority Processing)的 OpenAI 模型。"
|
||||
|
||||
Reference in New Issue
Block a user