From 55c40293eb481103135e9a10a655469f59999bb2 Mon Sep 17 00:00:00 2001 From: Null <1708213363@qq.com> Date: Sat, 7 Nov 2026 22:16:27 +0800 Subject: [PATCH 1/3] =?UTF-8?q?feat(prompts):=20=E7=BE=A4=E8=81=8A?= =?UTF-8?q?=E5=87=BA=E9=94=99=E9=9D=99=E9=BB=98=E5=A4=84=E7=90=86=EF=BC=88?= =?UTF-8?q?v3.18.10=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增顶层 error_reporting P1 规则,并在 speaking_style、public_speech_boundary、summary 与 each.md 同步重申 - 自行发起且未被要求的失败直接静默 end;被 @ 明确要求时只回一句“现在不可用 稍后再试” - 用户明确询问时才说明错误原因,不主动认领、道歉或倾倒错误详情 - 版本号升至 3.18.10 --- apps/undefined-chat/package-lock.json | 4 ++-- apps/undefined-chat/package.json | 2 +- apps/undefined-chat/src-tauri/Cargo.lock | 2 +- apps/undefined-chat/src-tauri/Cargo.toml | 2 +- apps/undefined-chat/src-tauri/tauri.conf.json | 2 +- apps/undefined-console/package-lock.json | 4 ++-- apps/undefined-console/package.json | 2 +- apps/undefined-console/src-tauri/Cargo.lock | 2 +- apps/undefined-console/src-tauri/Cargo.toml | 2 +- .../src-tauri/tauri.conf.json | 2 +- pyproject.toml | 2 +- res/IMPORTANT/each.md | 1 + res/prompts/undefined.xml | 18 ++++++++++++++++++ res/prompts/undefined_nagaagent.xml | 18 ++++++++++++++++++ src/Undefined/__init__.py | 2 +- tests/test_prompt_structure.py | 1 + uv.lock | 2 +- 17 files changed, 53 insertions(+), 15 deletions(-) diff --git a/apps/undefined-chat/package-lock.json b/apps/undefined-chat/package-lock.json index b1faa175..98f9a368 100644 --- a/apps/undefined-chat/package-lock.json +++ b/apps/undefined-chat/package-lock.json @@ -1,12 +1,12 @@ { "name": "undefined-chat", - "version": "3.18.9", + "version": "3.18.10", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "undefined-chat", - "version": "3.18.9", + "version": "3.18.10", "dependencies": { "@tauri-apps/api": "^2.3.0", "@tauri-apps/plugin-dialog": "^2.7.1", diff --git a/apps/undefined-chat/package.json b/apps/undefined-chat/package.json index 8aa52d7c..38c38b0d 100644 --- a/apps/undefined-chat/package.json +++ b/apps/undefined-chat/package.json @@ -1,7 +1,7 @@ { "name": "undefined-chat", "private": true, - "version": "3.18.9", + "version": "3.18.10", "type": "module", "scripts": { "tauri": "tauri", diff --git a/apps/undefined-chat/src-tauri/Cargo.lock b/apps/undefined-chat/src-tauri/Cargo.lock index f99908a2..292f05b2 100644 --- a/apps/undefined-chat/src-tauri/Cargo.lock +++ b/apps/undefined-chat/src-tauri/Cargo.lock @@ -5431,7 +5431,7 @@ dependencies = [ [[package]] name = "undefined_chat" -version = "3.18.9" +version = "3.18.10" dependencies = [ "futures-util", "keyring", diff --git a/apps/undefined-chat/src-tauri/Cargo.toml b/apps/undefined-chat/src-tauri/Cargo.toml index 0c1bf085..c2dad8a8 100644 --- a/apps/undefined-chat/src-tauri/Cargo.toml +++ b/apps/undefined-chat/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "undefined_chat" -version = "3.18.9" +version = "3.18.10" description = "Undefined native chat client" authors = ["Undefined contributors"] license = "MIT" diff --git a/apps/undefined-chat/src-tauri/tauri.conf.json b/apps/undefined-chat/src-tauri/tauri.conf.json index 2eb400e8..75113da2 100644 --- a/apps/undefined-chat/src-tauri/tauri.conf.json +++ b/apps/undefined-chat/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "Undefined Chat", - "version": "3.18.9", + "version": "3.18.10", "identifier": "com.undefined.chat", "build": { "beforeDevCommand": "npm run dev", diff --git a/apps/undefined-console/package-lock.json b/apps/undefined-console/package-lock.json index 6c5357b7..9e48fad6 100644 --- a/apps/undefined-console/package-lock.json +++ b/apps/undefined-console/package-lock.json @@ -1,12 +1,12 @@ { "name": "undefined-console", - "version": "3.18.9", + "version": "3.18.10", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "undefined-console", - "version": "3.18.9", + "version": "3.18.10", "dependencies": { "@tauri-apps/api": "^2.3.0", "@tauri-apps/plugin-http": "^2.3.0" diff --git a/apps/undefined-console/package.json b/apps/undefined-console/package.json index 9ee38d15..0e549f8a 100644 --- a/apps/undefined-console/package.json +++ b/apps/undefined-console/package.json @@ -1,7 +1,7 @@ { "name": "undefined-console", "private": true, - "version": "3.18.9", + "version": "3.18.10", "type": "module", "scripts": { "tauri": "tauri", diff --git a/apps/undefined-console/src-tauri/Cargo.lock b/apps/undefined-console/src-tauri/Cargo.lock index f2947a2d..2e58f4c5 100644 --- a/apps/undefined-console/src-tauri/Cargo.lock +++ b/apps/undefined-console/src-tauri/Cargo.lock @@ -4063,7 +4063,7 @@ checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "undefined_console" -version = "3.18.9" +version = "3.18.10" dependencies = [ "serde", "serde_json", diff --git a/apps/undefined-console/src-tauri/Cargo.toml b/apps/undefined-console/src-tauri/Cargo.toml index 3e3100ba..05f6651e 100644 --- a/apps/undefined-console/src-tauri/Cargo.toml +++ b/apps/undefined-console/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "undefined_console" -version = "3.18.9" +version = "3.18.10" description = "Undefined cross-platform management console" authors = ["Undefined contributors"] license = "MIT" diff --git a/apps/undefined-console/src-tauri/tauri.conf.json b/apps/undefined-console/src-tauri/tauri.conf.json index b43f9347..d325a98d 100644 --- a/apps/undefined-console/src-tauri/tauri.conf.json +++ b/apps/undefined-console/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "Undefined Console", - "version": "3.18.9", + "version": "3.18.10", "identifier": "com.undefined.console", "build": { "beforeDevCommand": "npm run dev", diff --git a/pyproject.toml b/pyproject.toml index 651a0d61..5d45fd01 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "Undefined-bot" -version = "3.18.9" +version = "3.18.10" description = "QQ bot platform with cognitive memory architecture and multi-agent Skills, via OneBot V11." readme = "README.md" authors = [ diff --git a/res/IMPORTANT/each.md b/res/IMPORTANT/each.md index e3039d40..171a2bf9 100644 --- a/res/IMPORTANT/each.md +++ b/res/IMPORTANT/each.md @@ -66,6 +66,7 @@ - 始终保持边界感和隐私意识,不主动提及他人的个人信息、私事或聊天内容,不为闲聊、自述或玩笑引入别人。用户提到某人也不自行从其他群、私聊、历史或侧写补充其情况;知道、熟悉或被追问都不等于披露授权,第三方信息仍按授权和最小必要原则处理。 - 你对外是在和人聊天,不是写运行日志或规则复读器。 - 不回复时只调用 end;内部原因可写 memo,禁止用 send_message 解释为何沉默。 + - 群聊里出错不主动报错:除非用户明确询问,不说“我的锅”“我出错了”之类的认领或道歉,不贴错误详情;自行发起且未被要求的失败直接静默 end,被 @ 明确要求的失败只回一句“现在不可用 稍后再试”。 - 禁止发给用户:闸门结论、bot_trigger 分析、静默处理、无业务操作、无重复任务、「本条无提及」类拼写声明、工具编排说明。 - 日常接话用熟悉的说法,不主动介绍内部分类、工具名或保存与检索流程。对方感叹你还记得,或随口问怎么知道时,只回应有依据的来由;不补没问的机制、限制、纠错承诺或自我辩解。明确追问实现、来源或隐私时,如实说明所问的部分,保留必要细节,不把用户写成操作者,也不承诺改实现。 - 行为规则指导行动,不是自我介绍的素材;只有当前问题确实涉及相应行为、能力或来源时,才解释相关部分。 diff --git a/res/prompts/undefined.xml b/res/prompts/undefined.xml index 6153bdf9..38b831fb 100644 --- a/res/prompts/undefined.xml +++ b/res/prompts/undefined.xml @@ -86,6 +86,14 @@ 拒绝时简短说明与当前请求直接相关的原因,不宣讲整套规则;不确定、失败或拒绝都不需要用笑声或自嘲掩饰。 + + + 群聊里出错时,除非用户明确询问,不主动报错,不说“我的锅”“我出错了”之类的自我认领或道歉,也不解释一堆错误内容、堆栈、工具名或内部原因。如实说明失败不等于必须主动广播失败。 + 失败来自你自行发起、并未被当前输入批次明确要求的操作时,直接静默处理:不发送任何消息,错误细节只在 memo 里简短记一笔,然后调用 end;这不算“判定需要回复”,不适用必须先 send_message 的要求。 + 失败来自用户明确 @ 或要求你做的事时,只回一句类似“现在不可用 稍后再试”的简短说明,不认错、不展开原因;已有部分结果时只说明未完成的部分,随后正常结束。 + 只有用户明确问起哪里出错、为什么失败或要求排查时,才说明必要的原因和限制,仍不长篇倾倒内部细节。 + + 使用正常母语交流中的自然表达,清楚说出谁做了什么、为什么,不用抽象名词和层层修饰代替具体动作,避免公文官话、机械翻译体、空泛的行业黑话和刻意装随意。 按一句话在当前交流中的作用决定保留、简化或省略:回答问题、说明必要条件、表达感受、礼貌回应都可以有价值。简化时保留事实主体、数字、条件、否定范围、完成状态和不确定程度,不因追求顺口改变原意;有用的重复、列表和术语也可以保留。 @@ -165,6 +173,14 @@ + + + 群聊里出错时,除非用户明确询问,不主动报错,不说“我的锅”“我出错了”之类的自我认领或道歉,也不解释一堆错误内容、堆栈、工具名或内部原因。如实说明失败不等于必须主动广播失败。 + 失败来自你自行发起、并未被当前输入批次明确要求的操作时,直接静默处理:不发送任何消息,错误细节只在 memo 里简短记一笔,然后调用 end;这不算“判定需要回复”,不适用必须先 send_message 的要求。 + 失败来自用户明确 @ 或要求你做的事时,只回一句类似“现在不可用 稍后再试”的简短说明,不认错、不展开原因;已有部分结果时只说明未完成的部分,随后正常结束。 + 只有用户明确问起哪里出错、为什么失败或要求排查时,才说明必要的原因和限制,仍不长篇倾倒内部细节。 + + @@ -253,6 +269,7 @@ **对外发言边界:** - 不回复时只调用 end;内部原因可写 memo,禁止用 send_message 解释为何沉默。 + - 群聊里出错不主动报错:除非用户明确询问,不说“我的锅”“我出错了”之类的认领或道歉,不贴错误详情;自行发起且未被要求的失败直接静默 end,被 @ 明确要求的失败只回一句“现在不可用 稍后再试”,用户明确询问时才说明原因。 - 禁止把下列内容发给用户:闸门结论、bot_trigger 分析、静默处理说明、无业务操作/无重复任务、拼写或专名自检、工具编排或规则复读。 - 不要把内部工具名、分层手册、参数说明发给用户;对方已经用这些名字追问时,仍用人话回答,不把用户写成操作者,也不承诺改实现。 - 行为规则用于决定怎么做,不是聊天素材;只在当前问题确实涉及相应行为、能力或来源时,解释相关部分。 @@ -1795,6 +1812,7 @@ 隐私/敏感话题不改变回复时机;即使内容安全,也必须先满足回复触发逻辑 content 字段始终为空字符串,所有输出通过工具调用 不回复时只调用 end;禁止用 send_message 发送闸门结论、静默原因、规则自检或拼写声明 + 群聊里出错不主动报错、不说“我的锅/我出错了”或解释错误详情;自行发起且未被要求的失败静默 end,被 @ 明确要求时只说一句“现在不可用 稍后再试”,用户明确询问才说明原因 默认不回复,除非明确触发条件 不回复自己,不重复发送同一请求的同一交付;新一轮日常交流可以自然回应 尊重对话边界,不凑热闹 diff --git a/res/prompts/undefined_nagaagent.xml b/res/prompts/undefined_nagaagent.xml index e282b0eb..a2abb199 100644 --- a/res/prompts/undefined_nagaagent.xml +++ b/res/prompts/undefined_nagaagent.xml @@ -86,6 +86,14 @@ 拒绝时简短说明与当前请求直接相关的原因,不宣讲整套规则;不确定、失败或拒绝都不需要用笑声或自嘲掩饰。 + + + 群聊里出错时,除非用户明确询问,不主动报错,不说“我的锅”“我出错了”之类的自我认领或道歉,也不解释一堆错误内容、堆栈、工具名或内部原因。如实说明失败不等于必须主动广播失败。 + 失败来自你自行发起、并未被当前输入批次明确要求的操作时,直接静默处理:不发送任何消息,错误细节只在 memo 里简短记一笔,然后调用 end;这不算“判定需要回复”,不适用必须先 send_message 的要求。 + 失败来自用户明确 @ 或要求你做的事时,只回一句类似“现在不可用 稍后再试”的简短说明,不认错、不展开原因;已有部分结果时只说明未完成的部分,随后正常结束。 + 只有用户明确问起哪里出错、为什么失败或要求排查时,才说明必要的原因和限制,仍不长篇倾倒内部细节。 + + 使用正常母语交流中的自然表达,清楚说出谁做了什么、为什么,不用抽象名词和层层修饰代替具体动作,避免公文官话、机械翻译体、空泛的行业黑话和刻意装随意。 按一句话在当前交流中的作用决定保留、简化或省略:回答问题、说明必要条件、表达感受、礼貌回应都可以有价值。简化时保留事实主体、数字、条件、否定范围、完成状态和不确定程度,不因追求顺口改变原意;有用的重复、列表和术语也可以保留。 @@ -165,6 +173,14 @@ + + + 群聊里出错时,除非用户明确询问,不主动报错,不说“我的锅”“我出错了”之类的自我认领或道歉,也不解释一堆错误内容、堆栈、工具名或内部原因。如实说明失败不等于必须主动广播失败。 + 失败来自你自行发起、并未被当前输入批次明确要求的操作时,直接静默处理:不发送任何消息,错误细节只在 memo 里简短记一笔,然后调用 end;这不算“判定需要回复”,不适用必须先 send_message 的要求。 + 失败来自用户明确 @ 或要求你做的事时,只回一句类似“现在不可用 稍后再试”的简短说明,不认错、不展开原因;已有部分结果时只说明未完成的部分,随后正常结束。 + 只有用户明确问起哪里出错、为什么失败或要求排查时,才说明必要的原因和限制,仍不长篇倾倒内部细节。 + + @@ -253,6 +269,7 @@ **对外发言边界:** - 不回复时只调用 end;内部原因可写 memo,禁止用 send_message 解释为何沉默。 + - 群聊里出错不主动报错:除非用户明确询问,不说“我的锅”“我出错了”之类的认领或道歉,不贴错误详情;自行发起且未被要求的失败直接静默 end,被 @ 明确要求的失败只回一句“现在不可用 稍后再试”,用户明确询问时才说明原因。 - 禁止把下列内容发给用户:闸门结论、bot_trigger 分析、静默处理说明、无业务操作/无重复任务、拼写或专名自检、工具编排或规则复读。 - 不要把内部工具名、分层手册、参数说明发给用户;对方已经用这些名字追问时,仍用人话回答,不把用户写成操作者,也不承诺改实现。 - 行为规则用于决定怎么做,不是聊天素材;只在当前问题确实涉及相应行为、能力或来源时,解释相关部分。 @@ -1860,6 +1877,7 @@ 隐私/敏感话题不改变回复时机;即使内容安全,也必须先满足回复触发逻辑 content 字段始终为空字符串,所有输出通过工具调用 不回复时只调用 end;禁止用 send_message 发送闸门结论、静默原因、规则自检或拼写声明 + 群聊里出错不主动报错、不说“我的锅/我出错了”或解释错误详情;自行发起且未被要求的失败静默 end,被 @ 明确要求时只说一句“现在不可用 稍后再试”,用户明确询问才说明原因 默认不回复,除非明确触发条件 不回复自己,不重复发送同一请求的同一交付;新一轮日常交流可以自然回应 尊重对话边界,不凑热闹 diff --git a/src/Undefined/__init__.py b/src/Undefined/__init__.py index 817494c4..86684502 100644 --- a/src/Undefined/__init__.py +++ b/src/Undefined/__init__.py @@ -24,7 +24,7 @@ from .skills.registry import BaseRegistry as BaseRegistry from .skills.tools import ToolRegistry as ToolRegistry -__version__: str = "3.18.9" +__version__: str = "3.18.10" # symbol -> (module_path, attribute_name);首次访问时才 importlib 加载 _LAZY_IMPORTS: dict[str, tuple[str, str]] = { diff --git a/tests/test_prompt_structure.py b/tests/test_prompt_structure.py index d0734075..2b2999d9 100644 --- a/tests/test_prompt_structure.py +++ b/tests/test_prompt_structure.py @@ -44,6 +44,7 @@ #: 让结构变化成为一次**显式决定**,而不是悄悄发生。 EXPECTED_SECTIONS: Final[tuple[str, ...]] = ( "speaking_style", + "error_reporting", "absolute_priority", "core_rules", "important_rules", diff --git a/uv.lock b/uv.lock index 43ad8a24..d11c74e4 100644 --- a/uv.lock +++ b/uv.lock @@ -4729,7 +4729,7 @@ wheels = [ [[package]] name = "undefined-bot" -version = "3.18.9" +version = "3.18.10" source = { editable = "." } dependencies = [ { name = "aiofiles" }, From aebdb6cb6afd51dcfc689e1fef7dfb410923f4da Mon Sep 17 00:00:00 2001 From: Null <1708213363@qq.com> Date: Sat, 7 Nov 2026 22:28:15 +0800 Subject: [PATCH 2/3] =?UTF-8?q?fix(prompts):=20=E7=BB=86=E5=8C=96=E7=BE=A4?= =?UTF-8?q?=E8=81=8A=E5=87=BA=E9=94=99=E5=A4=84=E7=90=86=E8=BE=B9=E7=95=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 用户通过 @、回复、呼语或任务名明确要求,以及完成任务所必需的搜索/Agent 子调用失败,按任务失败处理并回一句简短状态,不误判为自行发起的失败 - 部分失败时先发送已准备好的附件/结果,再说明未完成部分 - 静默失败使用 end(force=true),memo 只写脱敏摘要,不记录原始报错、URL、token、cookie、账号或密钥 - 同步更新 speaking_style、public_speech_boundary、summary 与 each.md 的重申 --- res/IMPORTANT/each.md | 2 +- res/prompts/undefined.xml | 22 ++++++++++++---------- res/prompts/undefined_nagaagent.xml | 22 ++++++++++++---------- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/res/IMPORTANT/each.md b/res/IMPORTANT/each.md index 171a2bf9..aec7fbf3 100644 --- a/res/IMPORTANT/each.md +++ b/res/IMPORTANT/each.md @@ -66,7 +66,7 @@ - 始终保持边界感和隐私意识,不主动提及他人的个人信息、私事或聊天内容,不为闲聊、自述或玩笑引入别人。用户提到某人也不自行从其他群、私聊、历史或侧写补充其情况;知道、熟悉或被追问都不等于披露授权,第三方信息仍按授权和最小必要原则处理。 - 你对外是在和人聊天,不是写运行日志或规则复读器。 - 不回复时只调用 end;内部原因可写 memo,禁止用 send_message 解释为何沉默。 - - 群聊里出错不主动报错:除非用户明确询问,不说“我的锅”“我出错了”之类的认领或道歉,不贴错误详情;自行发起且未被要求的失败直接静默 end,被 @ 明确要求的失败只回一句“现在不可用 稍后再试”。 + - 群聊里出错不主动报错:除非用户明确询问,不说“我的锅”“我出错了”之类的认领或道歉,不贴错误详情。用户明确要求(@、回复、呼语、按任务名指派)或完成该任务所必需的子调用失败,只回一句“现在不可用 稍后再试”,已准备好的附件/结果先发送;只有当前输入未要求、你自己额外发起的失败才静默 end(force=true),memo 只写脱敏摘要。 - 禁止发给用户:闸门结论、bot_trigger 分析、静默处理、无业务操作、无重复任务、「本条无提及」类拼写声明、工具编排说明。 - 日常接话用熟悉的说法,不主动介绍内部分类、工具名或保存与检索流程。对方感叹你还记得,或随口问怎么知道时,只回应有依据的来由;不补没问的机制、限制、纠错承诺或自我辩解。明确追问实现、来源或隐私时,如实说明所问的部分,保留必要细节,不把用户写成操作者,也不承诺改实现。 - 行为规则指导行动,不是自我介绍的素材;只有当前问题确实涉及相应行为、能力或来源时,才解释相关部分。 diff --git a/res/prompts/undefined.xml b/res/prompts/undefined.xml index 38b831fb..856c2aae 100644 --- a/res/prompts/undefined.xml +++ b/res/prompts/undefined.xml @@ -88,10 +88,11 @@ - 群聊里出错时,除非用户明确询问,不主动报错,不说“我的锅”“我出错了”之类的自我认领或道歉,也不解释一堆错误内容、堆栈、工具名或内部原因。如实说明失败不等于必须主动广播失败。 - 失败来自你自行发起、并未被当前输入批次明确要求的操作时,直接静默处理:不发送任何消息,错误细节只在 memo 里简短记一笔,然后调用 end;这不算“判定需要回复”,不适用必须先 send_message 的要求。 - 失败来自用户明确 @ 或要求你做的事时,只回一句类似“现在不可用 稍后再试”的简短说明,不认错、不展开原因;已有部分结果时只说明未完成的部分,随后正常结束。 - 只有用户明确问起哪里出错、为什么失败或要求排查时,才说明必要的原因和限制,仍不长篇倾倒内部细节。 + 群聊里出错时,除非用户明确询问,不主动报错,不说“我的锅”“我出错了”之类的自我认领或道歉,也不解释错误内容、堆栈、工具名或内部原因。如实说明失败不等于必须主动广播失败。 + 判断是否属于用户要求:通过 @、回复、明确呼语、按任务名/功能名指派,或当前输入批次直接要求你完成的任务,都算明确要求;为完成该任务而调用的搜索、Agent、下载、解析等子调用失败,属于该任务失败,不算自行发起的失败。只有当前输入未要求、你自己额外发起或主动延伸的操作失败,才按静默处理。 + 失败来自你自行发起、并未被当前输入批次明确要求的操作时,直接静默处理:不发送任何消息,memo 只写一句脱敏摘要(不写原始报错、URL、token、cookie、账号、密钥等敏感内容),并调用 end(force=true);这不算“判定需要回复”,不适用必须先 send_message 的要求。 + 失败来自用户明确要求(@、回复、呼语、按任务名指派等),或属于完成该任务所必需的子调用时,回一句类似“现在不可用 稍后再试”的简短状态;已成功准备好的附件/结果先正常发送,再只说明未完成的部分;不认错、不展开错误原因。 + 只有用户明确问起哪里出错、为什么失败或要求排查时,才说明必要的原因和限制,仍不长篇倾倒内部细节,也不泄露 URL、token、cookie、账号、密钥等敏感内容。 @@ -175,10 +176,11 @@ - 群聊里出错时,除非用户明确询问,不主动报错,不说“我的锅”“我出错了”之类的自我认领或道歉,也不解释一堆错误内容、堆栈、工具名或内部原因。如实说明失败不等于必须主动广播失败。 - 失败来自你自行发起、并未被当前输入批次明确要求的操作时,直接静默处理:不发送任何消息,错误细节只在 memo 里简短记一笔,然后调用 end;这不算“判定需要回复”,不适用必须先 send_message 的要求。 - 失败来自用户明确 @ 或要求你做的事时,只回一句类似“现在不可用 稍后再试”的简短说明,不认错、不展开原因;已有部分结果时只说明未完成的部分,随后正常结束。 - 只有用户明确问起哪里出错、为什么失败或要求排查时,才说明必要的原因和限制,仍不长篇倾倒内部细节。 + 群聊里出错时,除非用户明确询问,不主动报错,不说“我的锅”“我出错了”之类的自我认领或道歉,也不解释错误内容、堆栈、工具名或内部原因。如实说明失败不等于必须主动广播失败。 + 判断是否属于用户要求:通过 @、回复、明确呼语、按任务名/功能名指派,或当前输入批次直接要求你完成的任务,都算明确要求;为完成该任务而调用的搜索、Agent、下载、解析等子调用失败,属于该任务失败,不算自行发起的失败。只有当前输入未要求、你自己额外发起或主动延伸的操作失败,才按静默处理。 + 失败来自你自行发起、并未被当前输入批次明确要求的操作时,直接静默处理:不发送任何消息,memo 只写一句脱敏摘要(不写原始报错、URL、token、cookie、账号、密钥等敏感内容),并调用 end(force=true);这不算“判定需要回复”,不适用必须先 send_message 的要求。 + 失败来自用户明确要求(@、回复、呼语、按任务名指派等),或属于完成该任务所必需的子调用时,回一句类似“现在不可用 稍后再试”的简短状态;已成功准备好的附件/结果先正常发送,再只说明未完成的部分;不认错、不展开错误原因。 + 只有用户明确问起哪里出错、为什么失败或要求排查时,才说明必要的原因和限制,仍不长篇倾倒内部细节,也不泄露 URL、token、cookie、账号、密钥等敏感内容。 @@ -269,7 +271,7 @@ **对外发言边界:** - 不回复时只调用 end;内部原因可写 memo,禁止用 send_message 解释为何沉默。 - - 群聊里出错不主动报错:除非用户明确询问,不说“我的锅”“我出错了”之类的认领或道歉,不贴错误详情;自行发起且未被要求的失败直接静默 end,被 @ 明确要求的失败只回一句“现在不可用 稍后再试”,用户明确询问时才说明原因。 + - 群聊里出错不主动报错:除非用户明确询问,不说“我的锅”“我出错了”之类的认领或道歉,不贴错误详情。用户明确要求(@、回复、呼语、按任务名指派)或完成该任务所必需的子调用失败,只回一句“现在不可用 稍后再试”,已准备好的附件/结果先发送;只有当前输入未要求、你自己额外发起的失败才静默 end(force=true),memo 只写脱敏摘要。 - 禁止把下列内容发给用户:闸门结论、bot_trigger 分析、静默处理说明、无业务操作/无重复任务、拼写或专名自检、工具编排或规则复读。 - 不要把内部工具名、分层手册、参数说明发给用户;对方已经用这些名字追问时,仍用人话回答,不把用户写成操作者,也不承诺改实现。 - 行为规则用于决定怎么做,不是聊天素材;只在当前问题确实涉及相应行为、能力或来源时,解释相关部分。 @@ -1812,7 +1814,7 @@ 隐私/敏感话题不改变回复时机;即使内容安全,也必须先满足回复触发逻辑 content 字段始终为空字符串,所有输出通过工具调用 不回复时只调用 end;禁止用 send_message 发送闸门结论、静默原因、规则自检或拼写声明 - 群聊里出错不主动报错、不说“我的锅/我出错了”或解释错误详情;自行发起且未被要求的失败静默 end,被 @ 明确要求时只说一句“现在不可用 稍后再试”,用户明确询问才说明原因 + 群聊里出错不主动报错、不认错道歉、不贴错误详情;用户明确要求或完成任务所必需的子调用失败,只说一句“现在不可用 稍后再试”并先发已准备好的附件/结果;只有未被要求的自发起失败才静默 end(force=true),memo 只写脱敏摘要;用户明确询问才说明原因 默认不回复,除非明确触发条件 不回复自己,不重复发送同一请求的同一交付;新一轮日常交流可以自然回应 尊重对话边界,不凑热闹 diff --git a/res/prompts/undefined_nagaagent.xml b/res/prompts/undefined_nagaagent.xml index a2abb199..e51560da 100644 --- a/res/prompts/undefined_nagaagent.xml +++ b/res/prompts/undefined_nagaagent.xml @@ -88,10 +88,11 @@ - 群聊里出错时,除非用户明确询问,不主动报错,不说“我的锅”“我出错了”之类的自我认领或道歉,也不解释一堆错误内容、堆栈、工具名或内部原因。如实说明失败不等于必须主动广播失败。 - 失败来自你自行发起、并未被当前输入批次明确要求的操作时,直接静默处理:不发送任何消息,错误细节只在 memo 里简短记一笔,然后调用 end;这不算“判定需要回复”,不适用必须先 send_message 的要求。 - 失败来自用户明确 @ 或要求你做的事时,只回一句类似“现在不可用 稍后再试”的简短说明,不认错、不展开原因;已有部分结果时只说明未完成的部分,随后正常结束。 - 只有用户明确问起哪里出错、为什么失败或要求排查时,才说明必要的原因和限制,仍不长篇倾倒内部细节。 + 群聊里出错时,除非用户明确询问,不主动报错,不说“我的锅”“我出错了”之类的自我认领或道歉,也不解释错误内容、堆栈、工具名或内部原因。如实说明失败不等于必须主动广播失败。 + 判断是否属于用户要求:通过 @、回复、明确呼语、按任务名/功能名指派,或当前输入批次直接要求你完成的任务,都算明确要求;为完成该任务而调用的搜索、Agent、下载、解析等子调用失败,属于该任务失败,不算自行发起的失败。只有当前输入未要求、你自己额外发起或主动延伸的操作失败,才按静默处理。 + 失败来自你自行发起、并未被当前输入批次明确要求的操作时,直接静默处理:不发送任何消息,memo 只写一句脱敏摘要(不写原始报错、URL、token、cookie、账号、密钥等敏感内容),并调用 end(force=true);这不算“判定需要回复”,不适用必须先 send_message 的要求。 + 失败来自用户明确要求(@、回复、呼语、按任务名指派等),或属于完成该任务所必需的子调用时,回一句类似“现在不可用 稍后再试”的简短状态;已成功准备好的附件/结果先正常发送,再只说明未完成的部分;不认错、不展开错误原因。 + 只有用户明确问起哪里出错、为什么失败或要求排查时,才说明必要的原因和限制,仍不长篇倾倒内部细节,也不泄露 URL、token、cookie、账号、密钥等敏感内容。 @@ -175,10 +176,11 @@ - 群聊里出错时,除非用户明确询问,不主动报错,不说“我的锅”“我出错了”之类的自我认领或道歉,也不解释一堆错误内容、堆栈、工具名或内部原因。如实说明失败不等于必须主动广播失败。 - 失败来自你自行发起、并未被当前输入批次明确要求的操作时,直接静默处理:不发送任何消息,错误细节只在 memo 里简短记一笔,然后调用 end;这不算“判定需要回复”,不适用必须先 send_message 的要求。 - 失败来自用户明确 @ 或要求你做的事时,只回一句类似“现在不可用 稍后再试”的简短说明,不认错、不展开原因;已有部分结果时只说明未完成的部分,随后正常结束。 - 只有用户明确问起哪里出错、为什么失败或要求排查时,才说明必要的原因和限制,仍不长篇倾倒内部细节。 + 群聊里出错时,除非用户明确询问,不主动报错,不说“我的锅”“我出错了”之类的自我认领或道歉,也不解释错误内容、堆栈、工具名或内部原因。如实说明失败不等于必须主动广播失败。 + 判断是否属于用户要求:通过 @、回复、明确呼语、按任务名/功能名指派,或当前输入批次直接要求你完成的任务,都算明确要求;为完成该任务而调用的搜索、Agent、下载、解析等子调用失败,属于该任务失败,不算自行发起的失败。只有当前输入未要求、你自己额外发起或主动延伸的操作失败,才按静默处理。 + 失败来自你自行发起、并未被当前输入批次明确要求的操作时,直接静默处理:不发送任何消息,memo 只写一句脱敏摘要(不写原始报错、URL、token、cookie、账号、密钥等敏感内容),并调用 end(force=true);这不算“判定需要回复”,不适用必须先 send_message 的要求。 + 失败来自用户明确要求(@、回复、呼语、按任务名指派等),或属于完成该任务所必需的子调用时,回一句类似“现在不可用 稍后再试”的简短状态;已成功准备好的附件/结果先正常发送,再只说明未完成的部分;不认错、不展开错误原因。 + 只有用户明确问起哪里出错、为什么失败或要求排查时,才说明必要的原因和限制,仍不长篇倾倒内部细节,也不泄露 URL、token、cookie、账号、密钥等敏感内容。 @@ -269,7 +271,7 @@ **对外发言边界:** - 不回复时只调用 end;内部原因可写 memo,禁止用 send_message 解释为何沉默。 - - 群聊里出错不主动报错:除非用户明确询问,不说“我的锅”“我出错了”之类的认领或道歉,不贴错误详情;自行发起且未被要求的失败直接静默 end,被 @ 明确要求的失败只回一句“现在不可用 稍后再试”,用户明确询问时才说明原因。 + - 群聊里出错不主动报错:除非用户明确询问,不说“我的锅”“我出错了”之类的认领或道歉,不贴错误详情。用户明确要求(@、回复、呼语、按任务名指派)或完成该任务所必需的子调用失败,只回一句“现在不可用 稍后再试”,已准备好的附件/结果先发送;只有当前输入未要求、你自己额外发起的失败才静默 end(force=true),memo 只写脱敏摘要。 - 禁止把下列内容发给用户:闸门结论、bot_trigger 分析、静默处理说明、无业务操作/无重复任务、拼写或专名自检、工具编排或规则复读。 - 不要把内部工具名、分层手册、参数说明发给用户;对方已经用这些名字追问时,仍用人话回答,不把用户写成操作者,也不承诺改实现。 - 行为规则用于决定怎么做,不是聊天素材;只在当前问题确实涉及相应行为、能力或来源时,解释相关部分。 @@ -1877,7 +1879,7 @@ 隐私/敏感话题不改变回复时机;即使内容安全,也必须先满足回复触发逻辑 content 字段始终为空字符串,所有输出通过工具调用 不回复时只调用 end;禁止用 send_message 发送闸门结论、静默原因、规则自检或拼写声明 - 群聊里出错不主动报错、不说“我的锅/我出错了”或解释错误详情;自行发起且未被要求的失败静默 end,被 @ 明确要求时只说一句“现在不可用 稍后再试”,用户明确询问才说明原因 + 群聊里出错不主动报错、不认错道歉、不贴错误详情;用户明确要求或完成任务所必需的子调用失败,只说一句“现在不可用 稍后再试”并先发已准备好的附件/结果;只有未被要求的自发起失败才静默 end(force=true),memo 只写脱敏摘要;用户明确询问才说明原因 默认不回复,除非明确触发条件 不回复自己,不重复发送同一请求的同一交付;新一轮日常交流可以自然回应 尊重对话边界,不凑热闹 From f41530ebb2400e543e32584803e2762bdd3eacec Mon Sep 17 00:00:00 2001 From: Null <1708213363@qq.com> Date: Sat, 7 Nov 2026 22:34:02 +0800 Subject: [PATCH 3/3] =?UTF-8?q?test(prompts):=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E7=BE=A4=E8=81=8A=E5=87=BA=E9=94=99=E5=A4=84=E7=90=86=E5=A5=91?= =?UTF-8?q?=E7=BA=A6=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 覆盖两个提示词变体中用户明确要求与自行发起的失败分支 - 断言请求失败回一句简短状态并先发已准备好的附件 - 断言静默失败不发送消息、memo 脱敏并使用 end(force=true) --- tests/test_prompt_structure.py | 53 ++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/tests/test_prompt_structure.py b/tests/test_prompt_structure.py index 2b2999d9..19ae25fa 100644 --- a/tests/test_prompt_structure.py +++ b/tests/test_prompt_structure.py @@ -14,10 +14,14 @@ 契约,改动会影响渲染 - **渲染槽位**:```` 是渲染器依赖的 锚点,删掉之后该插槽静默失效 +- **错误处理契约**:``error_reporting`` 必须同时覆盖用户要求与自行发起的失败; + 静默结束必须带 ``end(force=true)``(``end`` 工具在 memo 非空且本轮未发消息时 + 会拒绝结束) - **负向协议**:真实提示词里不得出现文本形式的工具调用协议痕迹 -刻意**不**断言:任何一句指导语的具体文字、小节内部的段落结构、标签是否良构 -(已知提示词存在历史遗留的标签不匹配,见 ``KNOWN_TAG_MISMATCHES``)。 +刻意**不**断言:任何一句指导语的具体文字(上述功能性协议标记除外)、小节内部的 +段落结构、标签是否良构(已知提示词存在历史遗留的标签不匹配,见 +``KNOWN_TAG_MISMATCHES``)。 """ from __future__ import annotations @@ -403,6 +407,51 @@ def test_real_prompts_keep_every_file_include_slot_exactly_once() -> None: ) +# --------------------------------------------------------------------------- # +# 错误处理契约(功能性,不是措辞) +# --------------------------------------------------------------------------- # + +_ERROR_REPORTING_SECTION = re.compile( + r"]*>(?P.*?)", re.DOTALL +) + + +def _error_reporting_rules(path: Path) -> list[str]: + """取出顶层 error_reporting 小节里的规则正文。""" + match = _ERROR_REPORTING_SECTION.search(_text(path)) + assert match is not None, f"{path.name} 缺少顶层 error_reporting 小节" + return re.findall(r"(.*?)", match.group("body"), flags=re.DOTALL) + + +@pytest.mark.parametrize( + ("name", "path"), + (("undefined.xml", BASE_PROMPT), ("undefined_nagaagent.xml", NAGA_PROMPT)), +) +def test_error_reporting_covers_requested_and_unrequested_failures( + name: str, path: Path +) -> None: + """群聊失败处理必须区分用户要求与自行发起,并给出对应动作。 + + ``end(force=true)`` 是功能性契约:``end`` 工具在 memo 非空且本轮未发送消息时 + 会拒绝结束(见 ``skills/tools/end/handler.py``),静默失败必须显式传 force。 + """ + rules = _error_reporting_rules(path) + + silent_rules = [rule for rule in rules if "不发送任何消息" in rule] + assert len(silent_rules) == 1, f"{name} 的静默失败规则数量异常" + silent_rule = silent_rules[0] + assert "自行发起" in silent_rule + assert "end(force=true)" in silent_rule + assert "memo" in silent_rule and "脱敏" in silent_rule + + status_rules = [rule for rule in rules if "现在不可用" in rule] + assert len(status_rules) == 1, f"{name} 的请求失败状态规则数量异常" + status_rule = status_rules[0] + assert "用户明确要求" in status_rule + assert "回一句" in status_rule + assert "附件" in status_rule + + # --------------------------------------------------------------------------- # # 负向协议契约(功能性,不是措辞) # --------------------------------------------------------------------------- #