feat(notice): 「发布校园公告」裸意图直达表单 + 修发文部门下拉与假的发布方式
build / build-push (push) Successful in 1m9s

- IntentShortcut 泛化成规则表(Rule{短语集 → Intent}):加新意图只需
  ① 一条 Intent ② 一个短语集 ③ RULES.add(...),不用动 AgentOrchestrator。
  新增 NOTICE_PUBLISH —— 仅教职工(notice.publish),学生无落点则落回模型如实说明。
  短语表只收带「发/发布」动词的说法(发布公告/发个公告/发布校园公告/发通知…),
  光说「公告」「通知」更像查询,不收,避免误判。
- ★ 修 prepareOptionCall 漏拼字典工具的 fixed 参数:公文部门字典是
  /api/dict/List?type=1,丢了 type 前端取回的是「没指定类型」的结果 → 空下拉。
- deptId 补 optionsKeys("k","v"):平台通用字典返回 {k,v} 而非 id/name;
  服务端兜底 fetchDictOptions 的候选键也补上 k/v。
- ★ 移除 notice.publish 的 publishType 与 deptName:后端 /api/notice/Create 就是
  直接发布(无 publishType 字段,是否转审批由学校「应用设置」绑定的流程决定),
  声明它会让用户以为选了「存草稿」却仍然直接发出;deptName 由后端按 deptId 反查字典。
- system prompt 加第 10 条说明。
- 测试:新增 NoticeIntentFormTest(7),IntentDirectFormTest 加教师/学生两条公告用例
  (仍用「一调就炸」的假 LLM 证明不过大模型);全量 71/71。
This commit is contained in:
lijing
2026-10-12 18:54:15 +08:00
parent c11d331371
commit d2c6c185b5
7 changed files with 352 additions and 47 deletions
@@ -54,36 +54,35 @@ public final class CampusNoticeTools {
.readAt("/"));
list.add(ToolDef.of("notice.deptDics", MODULE, "发文部门字典",
"查询可选的发文部门(发布公告时填 deptId 用)。",
"查询本校本模块可选的发文部门(发布公告时填 deptId 用)。"
+ "仅在用户明确问「有哪些发文部门」时使用;"
+ "发布公告时**不要**先调它 —— 表单的「发文部门」下拉会自动带出可选值。",
"GET", "/api/dict/List")
.fix("type", "1")
.readAt("/list/new"));
list.add(ToolDef.of("notice.publish", MODULE, "发布校园公告",
"发布一条校园公告。调用前必须确认:标题 title、正文 content、发文部门 deptId;"
+ "缺失就问用户,不要编造部门。",
"发布一条校园公告,**立即生效、全站可见**(是否转审批由学校「应用设置」里的流程绑定决定,"
+ "请求侧无法选择)。调用前必须确认:标题 title、正文 content、发文部门 deptId;"
+ "缺失就直接调用本工具,系统会弹出表单让用户补齐,不要用文字反复追问;"
+ "发文部门必须来自字典,不要编造。",
"POST_JSON", "/api/notice/Create")
.p(ToolParam.required("title", "string", "公告标题")
.label("公告标题").eg("关于国庆假期安排的通知"),
ToolParam.required("content", "string", "公告正文(纯文本)")
.label("公告正文").as("textarea").eg("各位老师、同学:经学校研究决定……"),
ToolParam.required("deptId", "string", "发文部门 id,来自 notice.deptDics")
.label("发文部门").optionsFrom("notice.deptDics"),
ToolParam.optional("deptName", "string", "发文部门名称")
.label("发文部门名称"),
ToolParam.optional("type", "integer", "重要程度")
ToolParam.required("deptId", "string", "发文部门 id,来自 notice.deptDics 的 k 字段")
.label("发文部门")
.optionsFrom("notice.deptDics").optionsKeys("k", "v"),
ToolParam.optional("type", "integer", "重要程度:1 普通 / 2 重要")
.label("重要程度").dft("1")
.options(new String[]{"1", "2"}, new String[]{"普通", "重要"}),
ToolParam.optional("receiptFlag", "integer", "是否需要阅读回执")
ToolParam.optional("receiptFlag", "integer", "是否需要阅读回执(要回执时收件人需点确认)")
.label("需要阅读回执").dft("0")
.options(new String[]{"0", "1"}, new String[]{"否", "是"}),
ToolParam.optional("smsFlag", "integer", "是否同时发短信")
ToolParam.optional("smsFlag", "integer", "是否同时发短信提醒")
.label("同时发短信").dft("0")
.options(new String[]{"0", "1"}, new String[]{"否", "是"}),
ToolParam.optional("publishType", "string", "发布方式")
.label("发布方式").dft("direct")
.options(new String[]{"direct", "draft", "approve"},
new String[]{"直接发布", "存草稿", "提交审批"}))
.options(new String[]{"0", "1"}, new String[]{"否", "是"}))
.write("/list/new")
.modId(null));