weaver-work-cli 0.1.40 → 0.1.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunks/{archive-JHTONRST.js → archive-J4I6MCKF.js} +2 -2
- package/dist/chunks/{archive-oa-FCHLCPHC.js → archive-oa-BRZKKTO4.js} +2 -2
- package/dist/chunks/{asset-RLIHC7DB.js → asset-L7D4FAOZ.js} +2 -2
- package/dist/chunks/{asset-idle-KVOFTLCP.js → asset-idle-DADLLV75.js} +2 -2
- package/dist/chunks/{attachment-content-RZYDB3MB.js → attachment-content-K4C7VLWQ.js} +3 -3
- package/dist/chunks/{blog-42OZTJNP.js → blog-BVGQ7NZL.js} +2 -2
- package/dist/chunks/{caizhilian-KRK547K5.js → caizhilian-SAADNFD6.js} +2 -2
- package/dist/chunks/{calendar-RTWAMKHD.js → calendar-Q7NQY5Z2.js} +61 -23
- package/dist/chunks/{chunk-LFMSDBZN.js → chunk-3KTFS4IA.js} +308 -153
- package/dist/chunks/{chunk-G2JSIUWF.js → chunk-4PD5NWAX.js} +89 -0
- package/dist/chunks/{chunk-T6EGVBKU.js → chunk-4RAE6JXP.js} +1 -1
- package/dist/chunks/{chunk-7BRU4EFH.js → chunk-72CKAUAG.js} +29 -2
- package/dist/chunks/{chunk-NETCCARD.js → chunk-APVFJUQH.js} +2 -2
- package/dist/chunks/{chunk-CAQNBBQA.js → chunk-BBKDXQEC.js} +2 -2
- package/dist/chunks/{chunk-57IECMWX.js → chunk-BIPYLLVS.js} +26 -12
- package/dist/chunks/{chunk-LN447PY2.js → chunk-EKWAQSLU.js} +3 -2
- package/dist/chunks/{chunk-4TEDNCON.js → chunk-FOAA27U5.js} +338 -52
- package/dist/chunks/{chunk-7U577Q7U.js → chunk-G4UR6NXN.js} +2 -2
- package/dist/chunks/{chunk-NJKREDA3.js → chunk-GEWYMQME.js} +1 -1
- package/dist/chunks/{chunk-I566ZYNF.js → chunk-GHXCDPTM.js} +1 -1
- package/dist/chunks/{chunk-4CTESSKI.js → chunk-IZ7S7QUS.js} +4 -4
- package/dist/chunks/{chunk-VNBU55SL.js → chunk-JPRO6ER2.js} +57 -2432
- package/dist/chunks/{chunk-IZSSVYAG.js → chunk-LADPYOWC.js} +2 -2
- package/dist/chunks/chunk-LDZQPUIA.js +1238 -0
- package/dist/chunks/chunk-NKZRQXST.js +2546 -0
- package/dist/chunks/{chunk-JWRZM2H2.js → chunk-QKNKR4RH.js} +3 -3
- package/dist/chunks/{chunk-FLS4DPGP.js → chunk-R4CHUSKC.js} +28 -15
- package/dist/chunks/{chunk-WFFNM65B.js → chunk-SA6VBIHY.js} +73 -19
- package/dist/chunks/{chunk-SPRHHSVC.js → chunk-TTPJJJC4.js} +2 -2
- package/dist/chunks/{chunk-7E6MUOEK.js → chunk-W7BEHOSR.js} +2 -2
- package/dist/chunks/{chunk-CXRQWOZ5.js → chunk-YRSZQUD2.js} +2 -2
- package/dist/chunks/{conflict-VR55AOOO.js → conflict-F2OMZRTO.js} +2 -2
- package/dist/chunks/{contract-HI4FNPYE.js → contract-5BETHRSG.js} +2 -2
- package/dist/chunks/{cowork-HJLI353D.js → cowork-3MN6EQQO.js} +22 -12
- package/dist/chunks/create-flow-5FQNNMVO.js +55 -0
- package/dist/chunks/{ebuilder-form-HTGI63UU.js → ebuilder-form-SBHOYBUD.js} +3 -3
- package/dist/chunks/{ehr-GYXIYH3A.js → ehr-KMOJULKG.js} +432 -1234
- package/dist/chunks/{env-DW3G4HUO.js → env-LB7NBL2O.js} +2 -2
- package/dist/chunks/{esb-I5INCEFE.js → esb-W2PJCFCX.js} +4 -4
- package/dist/chunks/{factory-TKXGXS6L.js → factory-6ZFQXQ46.js} +1 -1
- package/dist/chunks/{fna-K2MHTQ24.js → fna-ZQPCUV4R.js} +2 -2
- package/dist/chunks/{group-chat-VYBNMJLG.js → group-chat-2HHAJN46.js} +5 -3
- package/dist/chunks/{host-ZUQTJYYK.js → host-4CBHGOHT.js} +3 -3
- package/dist/chunks/{host-D5SERMAJ.js → host-ATKVNZAT.js} +3 -3
- package/dist/chunks/{host-JM4YVHFM.js → host-BQH22NTQ.js} +3 -3
- package/dist/chunks/{host-L3VLITMT.js → host-X2CSLFM6.js} +3 -3
- package/dist/chunks/{host-256GVCAH.js → host-YTODKMSL.js} +3 -3
- package/dist/chunks/{hrm-VLRBKTZB.js → hrm-FFM4UJFS.js} +4 -4
- package/dist/chunks/{im-QK3VTLXK.js → im-VEHKDQPB.js} +7 -7
- package/dist/chunks/{invoice-T5JTA32H.js → invoice-LVIKSIIF.js} +3 -3
- package/dist/chunks/{jiuchuanhui-P2FNEQVZ.js → jiuchuanhui-X6DINO5P.js} +2 -2
- package/dist/chunks/{lazy-dispatch-XRRI46M6.js → lazy-dispatch-KSWTN5L6.js} +4 -4
- package/dist/chunks/{mail-3Y7MJ6PS.js → mail-VDKRGUD3.js} +2 -2
- package/dist/chunks/{meeting-M7LTXGJE.js → meeting-CLC6HP3Z.js} +12 -11
- package/dist/chunks/{okr-OBC6S67L.js → okr-CHG4OO3U.js} +2 -2
- package/dist/chunks/{plan-5H6I53SK.js → plan-XWR75667.js} +2 -2
- package/dist/chunks/{project-L75QZV4S.js → project-5BXOOKMG.js} +40 -23
- package/dist/chunks/recruit-stage-DGMFNNDE.js +4507 -0
- package/dist/chunks/{registry-RXPN6BBT.js → registry-7FFOXIAW.js} +4 -4
- package/dist/chunks/{registry-KMHCPAAD.js → registry-BKBZPBAJ.js} +10 -9
- package/dist/chunks/{registry-QGHFNUWS.js → registry-OZSMDVPP.js} +2 -2
- package/dist/chunks/{registry-UGRBCBHO.js → registry-RHMW6ANW.js} +2 -2
- package/dist/chunks/{registry-NYPYMZXG.js → registry-Z43434VG.js} +1 -1
- package/dist/chunks/{room-recommend-A3UDC3CA.js → room-recommend-62H7ZQQ6.js} +4 -4
- package/dist/chunks/{schedule-5GCACCK7.js → schedule-FNXKH3DQ.js} +4 -4
- package/dist/chunks/{workflow-M5ZJ7DWF.js → workflow-ADHKCAJK.js} +6 -6
- package/dist/index.js +33 -28
- package/dist/internal/e10/auth/commands.js +1 -0
- package/dist/internal/e10/auth/messages.js +6 -0
- package/dist/internal/e10/auth/session.js +17 -0
- package/dist/internal/e10/auth/xiaoe.js +286 -44
- package/dist/internal/e10/auth-recovery.js +36 -5
- package/dist/internal/e10/context.js +56 -12
- package/dist/internal/e10/index.js +1 -1
- package/dist/internal/e10/network-error.js +93 -0
- package/dist/internal/e10/request-runtime.js +6 -0
- package/dist/shortcuts/calendar/operations/read.js +31 -22
- package/dist/shortcuts/calendar/operations/write.js +45 -1
- package/dist/shortcuts/cowork/operations/discuss-write.js +5 -1
- package/dist/shortcuts/cowork/operations/item-write.js +1 -7
- package/dist/shortcuts/cowork/operations/member-write.js +3 -1
- package/dist/shortcuts/cowork/operations/permission-write.js +5 -1
- package/dist/shortcuts/cowork/operations/shared.js +7 -0
- package/dist/shortcuts/ehr/operations/attend-write.js +43 -1
- package/dist/shortcuts/ehr/operations/hr-contact.js +7 -4
- package/dist/shortcuts/ehr/operations/hr-report.js +13 -7
- package/dist/shortcuts/ehr/operations/recruit-candidate-import.js +134 -59
- package/dist/shortcuts/ehr/operations/recruit-write.js +262 -17
- package/dist/shortcuts/ehr/operations/recruit.js +10 -4
- package/dist/shortcuts/ehr/operations/shared.js +47 -0
- package/dist/shortcuts/hrm/operations/org.js +118 -0
- package/dist/shortcuts/index.js +5 -0
- package/dist/shortcuts/meeting/operations/eb/catalog.js +4 -1
- package/dist/shortcuts/meeting/operations/eb/create-flow.js +85 -28
- package/dist/shortcuts/meeting/operations/eb/factory.js +33 -0
- package/dist/shortcuts/meeting/operations/eb/group-chat.js +25 -3
- package/dist/shortcuts/meeting/operations/eb/person-cache.js +96 -0
- package/dist/shortcuts/meeting/operations/eb/room-recommend.js +33 -11
- package/dist/shortcuts/project/operations/read.js +6 -25
- package/dist/shortcuts/project/operations/shared.js +22 -0
- package/dist/shortcuts/project/operations/write.js +28 -2
- package/dist/shortcuts/recruit-stage/context.js +119 -0
- package/dist/shortcuts/recruit-stage/continuation.js +73 -0
- package/dist/shortcuts/recruit-stage/errors.js +65 -0
- package/dist/shortcuts/recruit-stage/host.js +109 -0
- package/dist/shortcuts/recruit-stage/index.js +115 -0
- package/dist/shortcuts/recruit-stage/manifest.js +29 -0
- package/dist/shortcuts/recruit-stage/operations/interview-arrange.js +722 -0
- package/dist/shortcuts/recruit-stage/operations/interview-feedback.js +269 -0
- package/dist/shortcuts/recruit-stage/operations/jd-create.js +630 -0
- package/dist/shortcuts/recruit-stage/operations/list.js +431 -0
- package/dist/shortcuts/recruit-stage/operations/registry.js +38 -0
- package/dist/shortcuts/recruit-stage/operations/resume-import.js +1198 -0
- package/dist/shortcuts/recruit-stage/operations/search.js +158 -0
- package/dist/shortcuts/recruit-stage/operations/types.js +25 -0
- package/dist/shortcuts/recruit-stage/school-tiers.json +318 -0
- package/dist/shortcuts/recruit-stage/shared.js +608 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/detailFieldRules.js +4 -2
- package/dist/shortcuts/workflow/operations/todoSmartConvert/summaryCache.js +13 -6
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoDetailCache.js +17 -24
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoDetailFetcher.js +14 -9
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.collect.js +50 -8
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.core.js +2 -1
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.detail.js +17 -11
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.group.js +7 -39
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.groupSummary.js +3 -2
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.js +51 -15
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.pipeline.js +16 -1
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.smartGroup.js +151 -63
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.subGroup.js +56 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.summary.js +39 -14
- package/docs/e10-auth.md +7 -1
- package/docs/operation-manual.md +8 -0
- package/package.json +1 -1
- package/scripts/install-skill-to-xiaoe.mjs +105 -0
- package/scripts/package-skill.mjs +4 -2
- package/skill-template/business-info.json +24 -0
- package/skill-template/domains/recruit-stage.md +29 -0
- package/skills/weaver-e10-calendar/SKILL.md +2 -1
- package/skills/weaver-e10-calendar/references/calendar-write.md +54 -0
- package/skills/weaver-e10-cowork/SKILL.md +1 -1
- package/skills/weaver-e10-cowork/references/cowork-write.md +3 -1
- package/skills/weaver-e10-jucailin/SKILL.md +1 -1
- package/skills/weaver-e10-jucailin/references/attend-write.md +8 -0
- package/skills/weaver-e10-jucailin/references/hr-contact.md +8 -0
- package/skills/weaver-e10-jucailin/references/hr-report.md +8 -0
- package/skills/weaver-e10-jucailin/references/recruit-create.md +2 -2
- package/skills/weaver-e10-jucailin/references/recruit-read.md +1 -1
- package/skills/weaver-e10-jucailin/references/recruit-write.md +4 -3
- package/skills/weaver-e10-mail/SKILL.md +1 -1
- package/skills/weaver-e10-meeting/SKILL.md +32 -2
- package/skills/weaver-e10-meeting.zip +0 -0
- package/skills/weaver-e10-recruit-stage/SKILL.md +226 -0
- package/skills/weaver-e10-recruit-stage/agents/openai.yaml +119 -0
- package/skills/weaver-e10-recruit-stage/lib/recruit-xiaoe-file.mjs +188 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-arrange-interview.md +322 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-capability-check.md +127 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-check-install.md +65 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-detail-process.md +63 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-edit-interview-feedback.md +142 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-jd-create.md +73 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-jd-template.md +56 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-list-candidate.md +101 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-list-interview.md +148 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-match-candidates.md +77 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-output-links.md +59 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-resolve-creator.md +69 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-resolve-metadata.md +241 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-resume-import.md +438 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-resume-parse.md +128 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-search-candidate.md +146 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-urge-feedback.md +69 -0
- package/skills/weaver-e10-shared/SKILL.md +1 -1
- package/skills/weaver-e10-shared/references/e10-auth-and-session.md +4 -2
- package/skills/weaver-e10-shijingran/SKILL.md +3 -2
- package/skills/weaver-e10-shijingran/references/operations.md +3 -1
- package/skills/weaver-e10-shijingran/references/source-manifest.json +41 -40
- package/skills/weaver-e10-shijingran/references/write-operations.md +2 -0
- package/skills/weaver-e10-workflow/SKILL.md +4 -2
- package/skills/weaver-e10-workflow/aigroup/default.json +11 -9
- package/skills/weaver-e10-workflow/references/todo-smart-convert.md +23 -13
- package/skills/weaver-e10-workflow/tools/todo-summary.cjs +62 -20
- package/skills/weaver-e10-yepiaotong/SKILL.md +9 -10
- package/skills/weaver-e10-yepiaotong/references/invoice-agent-entry.md +6 -3
- package/dist/chunks/{chunk-E7OK5WD5.js → chunk-2LV74IWP.js} +5 -5
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
**触发分流(2026-10-28 用户定稿,与 `SKILL.md`「待办『汇总』vs『统计』分流」同口径)**:原话含 **「汇总待办」/「批量处理待办」/「摘要」** 等归拢说法 → 走本 operation;原话含 **「统计待办」** → 走 `workflow.todoStat`(不是本 operation);两类词同时出现按本 operation(归拢优先);三类词都没有("有哪些待办 / 列出来 / 多少条")→ `workflow.search`。**不要**为了"先看一眼有哪些"先去调 `todoStat` / `search` 再回头走本链路——那会多花一轮,且交付形态会被带偏。
|
|
6
6
|
|
|
7
7
|
> **⚠️ 2026-10-28 起:分组规则已外置到 JSON,代码不再按业务类型分支。**
|
|
8
|
-
> 唯一真源是 `skills/weaver-e10-workflow/aigroup/default.json`(`{defaults, rules[]}`,随 skill
|
|
8
|
+
> 唯一真源是 `skills/weaver-e10-workflow/aigroup/default.json`(`{defaults, rules[]}`,随 skill 分发)——**它同时是用户本机可直接编辑的规则文件**:用户调试、增删规则是常态,CLI 与执行方**只管读**,内容是什么就按什么跑;**禁止**与仓库版本比对、禁止覆盖「恢复」、禁止探究改动来源。用户意图另存同目录 `aigroup/user-intents.json`(`aigroup set` 写入;旧位置在 CLI 状态目录,兼容回读)。
|
|
9
9
|
> 现行规则要点:①没有 `aiGroup` ⇒ 全平铺;②`focus:true` ⇒ 按 `focusKeyword`(`[指标, 算子, 值]`,十种算子)确定性成一组,`groupTitle` 为组名,`sysArg` 指明指标取自列表属性还是流程详情;③`focus:false` ⇒ `aiContext`(流程标题/流程详情)交 AI 分组,**必须**给 `aiGroups`;④`focus:true` 收到多个计划子组时**只保留条数最多的一个**,其余平铺;⑤`aiGroups.seq` 已删除,只认 `requestIds`;⑥组摘要 `groupSummary.needAI:false` 时由 CLI 按 JSON `template` 渲染,`true` 时交 AI;⑦单条摘要由 `needSummary` 决定(false ⇒ 用标题);⑧`focus:false` 还可给 `groupingPrompt`(二次分组口径,见下节);⑨**`summaryRequiredFields`(要素级交付闸门,2026-11-01)**:规则声明的关键字清单,本组每条摘要必须逐项包含,缺任一项 ⇒ 导出闸门 `exit 1`(见 §6.1)。
|
|
10
10
|
|
|
11
11
|
**`groupingPrompt`(2026-10-29 新增,schemaVersion 3)**
|
|
12
12
|
- 位置 `aiGroup.groupRule.groupingPrompt`,**只在 `focus:false` 时有意义**;`focus:true` 给它会直接校验失败。可选,不给就按素材自由分组。
|
|
13
13
|
- 分工:`aiContext` 决定**看什么**(是否预取流程详情),`groupingPrompt` 决定**怎么切**(组名词表、归属规则)。
|
|
14
|
-
- 下发方式:`collect` 会把该字段原样放进 `groupingBrief[].groupingPrompt`,`
|
|
14
|
+
- 下发方式:`collect` 会把该字段原样放进 `groupingBrief[].groupingPrompt`,`subGroup` 阶段的 `ai_groups_required` 报错文案也会带上。**模型生成 `aiGroups` 前必须先读它并照做**(组名只能取它给的词表,不得新造)。
|
|
15
15
|
- 限制:非空字符串、≤500 字(会原样进模型上下文)。
|
|
16
16
|
> 本文档只描述**机制与执行规则**(aiGroups 格式与校验、子组解散/平铺机制、意图判定、素材与缓存、交付形态);**分组阈值、组名词表、摘要模板、排除清单等业务口径一律以 `aigroup/default.json` 为准**(`prep`/`build` 输出会回显相关内容),与本文冲突时以 JSON 为准。
|
|
17
17
|
|
|
@@ -38,7 +38,7 @@ weaver-work-cli --json workflow aigroup set --input-json '{"workflowName":["费
|
|
|
38
38
|
| --- | --- | --- |
|
|
39
39
|
| `workflowName` | 工作流名称 | 大组的 `title` 就是它 |
|
|
40
40
|
| **第一次分组** | 按 `workflowName` 把条目分到各个工作流;得到的每个组叫**工作流分组** | `runGroup` → `wfIdGroup[]` |
|
|
41
|
-
| **ai二次分组** | 在工作流分组**内部**再切子组的过程;**只有这一步需要 AI
|
|
41
|
+
| **ai二次分组** | 在工作流分组**内部**再切子组的过程;**只有这一步需要 AI 计划**。**位于单条摘要之后**(2026-11-03 解耦) | `subGroup` + `aiGroups` |
|
|
42
42
|
| **原始列表数据** | `/getTodoListData` 返回的待办条目集合,**整条链路的唯一数据源**(每条对应一个 `requestId`) | `collect` 的 `items[]` |
|
|
43
43
|
| **流程标题** | 条目标题 `requestNameTitle`;没有**流程详情数据**时,AI 只能靠它做语义判断,也是摘要的兜底文案 | `requestData.requestNameTitle` |
|
|
44
44
|
| **流程详情数据** | `/getWorkflowRequest` 返回的表单字段 + 基础信息;用于 a) 分组素材 b) 摘要素材 c) 阈值指标(请假天数/报销金额/到期时间) | `DetailFact { context, metrics }` |
|
|
@@ -54,9 +54,10 @@ weaver-work-cli --json workflow aigroup set --input-json '{"workflowName":["费
|
|
|
54
54
|
| --- | --- |
|
|
55
55
|
| `collect` | 调列表接口取数,并生成首次分组和 `groupingBrief` |
|
|
56
56
|
| `group` | 对已传入的 `items` 重新做首次分组 |
|
|
57
|
-
| `smartGroup` |
|
|
58
|
-
| `summaryContext` |
|
|
59
|
-
| `summary` | 回填 `aiSummaries
|
|
57
|
+
| `smartGroup` | 首次分组 + 详情回填 + **平铺**结构(**不做** ai 二次分组) |
|
|
58
|
+
| `summaryContext` | 生成单条摘要素材(按平铺结构切批) |
|
|
59
|
+
| `summary` | 回填 `aiSummaries`;`withSubGroup:true` 时同进程接着做二次分组 |
|
|
60
|
+
| `subGroup` | **ai 二次分组**:在已回填摘要的成品结构上应用 `aiGroups`,切出汇总项 |
|
|
60
61
|
| `groupSummaryContext` | 生成汇总项摘要素材 |
|
|
61
62
|
| `groupSummary` | 回填 `aiGroupSummaries` |
|
|
62
63
|
| `aggregate` | 兼容旧调用的本地去重、分组和金额合计 |
|
|
@@ -65,11 +66,15 @@ weaver-work-cli --json workflow aigroup set --input-json '{"workflowName":["费
|
|
|
65
66
|
|
|
66
67
|
```text
|
|
67
68
|
collect
|
|
68
|
-
-> smartGroup(可传 withDetailContext:true
|
|
69
|
-
-> summary
|
|
69
|
+
-> smartGroup(可传 withDetailContext:true;只做首次分组,平铺)
|
|
70
|
+
-> summary(回填单条摘要;withSubGroup:true 时接着做二次分组)
|
|
70
71
|
-> groupSummary(仅存在待回填组摘要时)
|
|
71
72
|
```
|
|
72
73
|
|
|
74
|
+
阶段划分(2026-11-03 用户定:**分组与摘要不耦合**):
|
|
75
|
+
`collect` → `smartGroup`(workflowName 分组)→ 单条摘要 → `subGroup`(ai 二次分组)→ 组摘要 → 导出。
|
|
76
|
+
`focus:false` 的组只在 **`subGroup`** 阶段要求 `aiGroups`;摘要阶段不再被它阻塞。
|
|
77
|
+
|
|
73
78
|
未传 `stage` 时,没有 `items` 进入 `collect`;传入 `items` 进入兼容的本地汇总;回灌带有最终结构的数据时由 CLI 推断后续阶段。显式 `stage` 优先。
|
|
74
79
|
|
|
75
80
|
每次模型调用由调用方把 AI 耗时追加到 `skillTiming`;CLI 会把当前阶段耗时追加到 `meta.timing.steps`。不要为没有执行的 AI 阶段填入耗时。
|
|
@@ -111,8 +116,9 @@ collect
|
|
|
111
116
|
**详情为空也写**;旧版本条目(v2 及更早,basicInfo 里还带标题)读取时视为无效,自动重拉;
|
|
112
117
|
`excludeOriginFormDataFields` 变了 ⇒ `excludeTag` 对不上 ⇒ 旧条目自动失效重拉(与摘要缓存的 pk 机制同思路);
|
|
113
118
|
- 摘要缓存:单条摘要文本。条目除 `maxChars`/`pk`(口径)外还带 **`dv`(详情素材特征值,2026-11-01 根治)**:写入时对当前详情素材(basicInfo+fields 内容哈希)取特征值,读取时与当前素材比对——素材升级/排除清单调整/详情缓存被清(无法核验)⇒ 旧摘要失效重写;无 `dv` 的旧条目按旧规则兼容命中。
|
|
114
|
-
|
|
119
|
+
**失效条件:由 `requestSummaryPrompt`(default.json / 用户意图)调整触发**——①`pk` **严格比对**(2026-11-04 收紧,取代 11-02 的「条目缺 pk 兼容命中」):调用方传了 pk 时,条目**缺 pk** 或 **pk 不等** ⇒ 一律失效重写。此前「缺 pk 就放过」等于「改 prompt 对老条目永远不生效」——缺 pk 只能说明口径未知,不能证明口径没变。空口径(`pk===''`)照常落库,因此改空 / 改回非空同样能失效,空口径组也不会每次 miss;②`maxChars` 仅在用户显式传 `--summary-chars` 时参与比对,规则/默认字数变化(如 50→150)**不作废**历史摘要;③`dv` 仍比对素材变化,**条目缺 `dv` 依旧兼容命中**(素材侧无法核验,未随本次收紧)。
|
|
115
120
|
记录里带 `lastFeedBackDateTime` 就是为了这个 key:**流程有新反馈 ⇒ key 变 ⇒ 缓存自然失效**。
|
|
121
|
+
- **缓存缺失/未命中 = 冷缓存(2026-11-03 用户定稿)**:`cache/` 下文件不存在、被清理或条目 miss,一律按「从未生成过」处理,直接走待写摘要流程;**禁止**追溯缓存丢失或被删的原因、**禁止**从备份恢复缓存、也不作为异常上报用户。
|
|
116
122
|
- 详情取数时机:`collect` 只为「用户给了 `groupFocus` 且意图适用于本组」的组预取字段;`smartGroup` 对全部条目走一次「缓存优先」的取数(命中零请求)。因此**冷缓存下详情请求集中在 `smartGroup`,`summary` 阶段通常 0 请求**。
|
|
117
123
|
- 摘要缓存**只省 AI、不省详情**:阈值指标只认流程详情数据,所以命中摘要的条目仍会查一次详情缓存;摘要为空的条目用标题兜底。
|
|
118
124
|
|
|
@@ -120,27 +126,31 @@ collect
|
|
|
120
126
|
|
|
121
127
|
- `groupBy` 支持 `workflow`、`urgency`、`date`、`none`,默认 `workflow`。
|
|
122
128
|
- 优先组固定为 `id=priority`、标题“建议优先处理的流程”,排在第一位。超时条目必入;没有级别 2 时才使用级别 1,级别 0 不因等级入选。
|
|
129
|
+
- **生成时机(2026-11-03 用户定)**:优先组**不再在分组阶段产出**,而是在**最终结构**上由 `assemblePriorityGroup()` 生成——摘要与组摘要全部回填后,按 `generalRules.priorityGroup` 从各工作流分组的 `displayItems` 里筛出条目、复制一份置顶。因此 `prep`/`build` 的组清单里**没有**这一组(组数比其他阶段少 1),只有最终导出结构才有;判据字段(`overTime`/`userOverTime`/`requestLevel`)都在 `requestData` 上,无需回查列表。该函数**幂等**(输入已有 priority 会先剔除再重建)。
|
|
123
130
|
- 优先组是**叠加视图**,不是筛选:入选条目**仍保留在各自的工作流分组里**(优先组只是置顶入口)。因此 `Σcount` 会大于 `totalCount`,**`totalCount` 一律按去重条数计(= collect 取到的全部条数),不做分组求和**。
|
|
124
131
|
- 普通组保持接口返回的首次出现顺序。只有调用方明确给出排序意图时才传 `groupOrder`;`topN` 只影响中间 Markdown,不裁剪最终数组。
|
|
125
132
|
- `groupingBrief` 用组内 1-based `idx` 标识条目;`idx` 与 `prep` 输出目录 `state.json` 里 `planGroups[].rows[].requestId` 一一对应。生成 `aiGroups` 时一律用 `requestId`:需要映射就从 `state.json` 一次性提取,不要手抄,更不要用 `seq`(已废弃)。
|
|
126
133
|
|
|
127
134
|
## 4. `smartGroup` 和 `aiGroups`
|
|
128
135
|
|
|
129
|
-
`aiGroups`
|
|
136
|
+
`aiGroups` 是扁平数组,每项允许 `groupId`、`title`、`requestIds`、`summary` 四个键(**`seq` 已废弃**;`summary` 是 2026-11-03 新增的可选键):
|
|
130
137
|
|
|
131
138
|
```json
|
|
132
139
|
[
|
|
133
|
-
{ "groupId": "workflow-id", "title": "安全通知", "requestIds": ["101", "103"] },
|
|
140
|
+
{ "groupId": "workflow-id", "title": "安全通知", "requestIds": ["101", "103"], "summary": "本组为安全补丁升级通告,含 2 条补丁安装提醒,建议优先处理。" },
|
|
134
141
|
{ "groupId": "workflow-id", "title": "制度通知", "requestIds": ["102", "104"] }
|
|
135
142
|
]
|
|
136
143
|
```
|
|
137
144
|
|
|
145
|
+
- **`summary`(组摘要)与分组在同一次交互产出**:给了就原样落到 `displayItems[].summary`,`groupSummaryBatches` 不再为它产批次 ⇒ **不必再跑一轮组摘要**。规则 `aiGroup.groupSummary.needAI === true` 的组(如内部留言、安全问题处理工单)**建议一定带**;`needAI:false` 的确定性组(请假/报销/问题支持)由 CLI 模板渲染,带了也以你给的为准。
|
|
146
|
+
- 写 `summary` 时手上有本组的标题 + 每条 `summary`(单条摘要已在前一步写进结构),直接概括即可;字数按 `groupSummaryMaxChars`(默认 100)。
|
|
147
|
+
|
|
138
148
|
- `requestIds` 必填且非空,成员必须属于本组;未知 `groupId`、未知 `requestId`、重复分配直接失败。
|
|
139
149
|
- 优先组不可二次分组。
|
|
140
150
|
- 组内少于 3 条时**一律平铺单条**,不产生任何汇总项——阈值组(1天以内 / 100元以内)、问题支持过期组、内部留言整组都不例外;**即使给了 `aiGroups` 也忽略**(CLI 写 warning)。这条是硬门槛,没有例外。
|
|
141
151
|
- **计划子组不足 2 条会被解散平铺**(CLI 写 warning「N 个子组不足 2 条,已解散」)——这是机制行为,与上一条相互独立:若 `groupingPrompt` 的自然粒度每组只有 1 条(如 安全问题处理工单 按 git 文件,11 条对应 11 个文件),按它给的计划会全部解散、整组平铺,**这是该计划的必然结果,不是错误**;要真正成组,就得按能凑够每组 ≥2 条的粒度给计划(如按文件族),且组名仍必须来自 `groupingPrompt` 口径、**不得为凑组虚构更粗粒度的新组名**(如"XML/Java 文件类型")。
|
|
142
152
|
- 组内至少 3 条时,完全省略 `aiGroups` 走 CLI 确定性分组;显式传入后,未知 `groupId`、未知 `requestId`、重复分配直接失败(**仅在本组计划会被采纳时校验**:意图适用于本类型,或本组是内部留言)。
|
|
143
|
-
- `aiGroups` 何时该给——**三种情形**(`prep` 输出会给组标 `[
|
|
153
|
+
- `aiGroups` 何时该给——**三种情形**(`prep` 输出会给组标 `[需二次分组]`,照标注执行即可):
|
|
144
154
|
- ① 用户给了侧重点(`groupFocus`),且侧重点**按意图表适用于本组类型**;
|
|
145
155
|
- ② 本组是**内部留言** —— 而且**≥3 条时是必须给**:没有侧重点(或侧重点不适用)就按**流程标题**分组,缺计划直接报 `ai_groups_required`;
|
|
146
156
|
- ③ 规则里 `aiGroup.groupRule.focus === false` 的组(如 **安全问题处理工单**,上下文=流程详情)——**≥3 条时必须给**,缺计划同样报 `ai_groups_required`。这类组的分组素材(如漏洞地址里的 git 文件)来自流程详情,prep 无侧重点时不带字段注记 ⇒ 按 references 上文的「单条查询详情」兜底取得,**不要用标题推断**。
|
|
@@ -281,7 +291,7 @@ collect
|
|
|
281
291
|
- `params_pc` / `params_mobile` 必须放在 `sdkOptions` 内、与 `routerProps_pc/mobile` 同级,**不要放进 `arguments` 层**。
|
|
282
292
|
- `app` 的值按原始字符写 **`@weapp/workflow`**(`@` 后面**没有**斜杠,共 15 个字符):**不要写成 `@//weapp/workflow`、不要转义成 `@\/\/weapp\/workflow`、也不要加前导空格**——带前导空格会导致 app 解析失败(用户 2026-10-27 以截图校正)。
|
|
283
293
|
- 脚本 `exportFinal` 已在 stdout 的 `[JSON_BEGIN]`/`[JSON_END]` 之间直接输出**带标签的整块载荷**,原样粘贴即可;交付 JSON 文件(`~/Downloads/<用户名>_<时间戳>.json`)由脚本自动落盘并打印路径,**默认不 `present_files`(见 §6.1 顶部)**。旧 `--file` 分支(写 `待办汇总-*.json` 外框归档)已于 2026-11-01 **删除**——传了也会被忽略,不要再依赖它。
|
|
284
|
-
- **交付硬闸门(2026-11-01)**:`finish`/`build` 导出前强制校验——①空单条摘要 >0、②空组摘要 >0、③待写摘要未全部回填(列出缺失 requestId)、④详情取数失败(`failed>0`,防"静默降级+标题编内容")、⑤**降级话术黑名单**(摘要含「未在标题体现 / 标题未体现 / 标题里没有 / 详见流程 /
|
|
294
|
+
- **交付硬闸门(2026-11-01)**:`finish`/`build` 导出前强制校验——①空单条摘要 >0、②空组摘要 >0、③待写摘要未全部回填(列出缺失 requestId)、④详情取数失败(`failed>0`,防"静默降级+标题编内容")、⑤**降级话术黑名单**(摘要含「未在标题体现 / 标题未体现 / 标题里没有 / 详见流程 / 详见详情」即拦截——把取数失败写成业务信息缺失;2026-11-03 按用户要求去掉「待确认」:摘要里出现"待确认"属于正常业务表述)、⑥**要素级校验**(规则 `summaryRequiredFields` 声明的关键字,本组每条摘要必须逐项包含,缺任一即拦截并列出缺失项)——任一命中即 `exit 1` 拒绝导出。显式豁免:`--allow-empty-summary`(豁免①②③⑤⑥)、`--allow-detail-fail`(豁免④)。**豁免是给"确认要带瑕疵出文件"用的,不要拿它当常规手段绕过校验。**
|
|
285
295
|
- **组摘要未回填 ≠ 失败(2026-11-02 P2 定稿)**:`finish`/`build` 遇到组摘要待回填时,把**完整素材**(含每个成员的 `requestId`、标题、发起人、单条摘要、`prompt`)写 `<out>/need-group-summaries.json`,以 **`exit 0` + `NEEDS_GROUP_SUMMARIES`** 返回、**不导出**(控制台只给紧凑清单,此前每批 400 字符的截断预览已废除);在该文件每个元素里补 `summary` 后用 `--group-summaries` **指回同一个文件**重跑即可(脚本自动只取 `groupId`/`summary`,`items` 等多余字段不外传)。`--allow-empty-summary` 豁免后才按空组摘要继续导出。上方①②④⑤⑥等真失败仍 `exit 1`。
|
|
286
296
|
- 体积见 §6.2:**不能按组拆成多个 `<browsertool>` 块**(拆开就不是合法载荷);超限时先在正文说明条数与预计体积,建议缩小范围,用户坚持再照做。
|
|
287
297
|
|
|
@@ -512,6 +512,23 @@ function loadAigroupRuleFile() {
|
|
|
512
512
|
return aigroupRuleFileCache;
|
|
513
513
|
}
|
|
514
514
|
|
|
515
|
+
// ── 规则指纹(2026-11-04 新增:交付纪律强化)────────────────────────────
|
|
516
|
+
// 对影响取数/分组/摘要口径的规则文件算指纹:aigroup/default.json + aigroup/user-intents.json(若存在)。
|
|
517
|
+
// prep 时写入 state,finish 导出前比对——规则在取数之后被改过 ⇒ 数据是旧口径产出,拒绝导出,
|
|
518
|
+
// 防「新规则 + 旧数据」的静默交付(2026-11-04 实测:快照 09:49 导出、规则 09:50 修改)。
|
|
519
|
+
function ruleFingerprint() {
|
|
520
|
+
const { createHash } = require('node:crypto');
|
|
521
|
+
const aigroupDir = path.join(path.resolve(__dirname, '..'), 'aigroup');
|
|
522
|
+
const parts = [];
|
|
523
|
+
for (const name of ['default.json', 'user-intents.json']) {
|
|
524
|
+
const file = path.join(aigroupDir, name);
|
|
525
|
+
if (!fs.existsSync(file)) continue;
|
|
526
|
+
const buf = fs.readFileSync(file);
|
|
527
|
+
parts.push(`${name}#${createHash('sha256').update(buf).digest('hex').slice(0, 16)}(${buf.length}B)`);
|
|
528
|
+
}
|
|
529
|
+
return parts.join(' | ');
|
|
530
|
+
}
|
|
531
|
+
|
|
515
532
|
/** 组名 → 该规则的 summaryRequiredFields(needSummary:false 的组不校验)。 */
|
|
516
533
|
function requiredFieldsFor(title) {
|
|
517
534
|
const rules = loadAigroupRuleFile().rules || [];
|
|
@@ -536,6 +553,20 @@ function exportFinal(result, dir, state, kept, opts = {}) {
|
|
|
536
553
|
const stats = groupStats(data.wfIdGroup);
|
|
537
554
|
const total = groupTotal;
|
|
538
555
|
// ── 交付硬闸门(2026-11-01 用户拍板):缺环节 / 静默降级出不了交付物,只有显式豁免才放行 ──
|
|
556
|
+
// ⓪ 规则新鲜度(2026-11-04 新增):取数之后规则文件被改过 ⇒ 本次数据是旧口径产出,
|
|
557
|
+
// 拒绝导出。旧 state(无 ruleFp)仅提示不拦截,保持向后兼容。
|
|
558
|
+
if (state.ruleFp) {
|
|
559
|
+
const nowFp = ruleFingerprint();
|
|
560
|
+
if (nowFp !== state.ruleFp && opts.allowStaleRules !== true) {
|
|
561
|
+
console.error('\n✖ 交付拦截:规则文件在取数之后被修改,本次数据是旧口径产出。');
|
|
562
|
+
console.error(' 取数时指纹:%s', state.ruleFp);
|
|
563
|
+
console.error(' 当前指纹 :%s', nowFp);
|
|
564
|
+
console.error(' → 请重新执行 run 取数后再 finish;确要带旧口径出文件,加 --allow-stale-rules 显式豁免。');
|
|
565
|
+
process.exit(1);
|
|
566
|
+
}
|
|
567
|
+
} else {
|
|
568
|
+
console.error('⚠ 本次 state 无规则指纹(旧版本产出),跳过规则新鲜度校验。');
|
|
569
|
+
}
|
|
539
570
|
const allowEmpty = opts.allowEmptySummary === true;
|
|
540
571
|
const detailFailed = Number(opts.detailFailed) || 0;
|
|
541
572
|
const groupEmpty = Number(opts.groupEmpty) || 0;
|
|
@@ -563,7 +594,7 @@ function exportFinal(result, dir, state, kept, opts = {}) {
|
|
|
563
594
|
}
|
|
564
595
|
// ⑤ 降级话术黑名单(2026-11-01):摘要正文出现"未在标题体现/详见流程"这类表述,
|
|
565
596
|
// 说明执行方把「自己没取到」写成了「业务对象没有」——按模板回查详情补齐后重写。
|
|
566
|
-
const DEGRADE_PHRASES = ['未在标题体现', '标题未体现', '标题里没有', '详见流程', '详见详情'
|
|
597
|
+
const DEGRADE_PHRASES = ['未在标题体现', '标题未体现', '标题里没有', '详见流程', '详见详情'];
|
|
567
598
|
const degraded = [];
|
|
568
599
|
for (const group of data.wfIdGroup || []) {
|
|
569
600
|
for (const item of group.displayItems || []) {
|
|
@@ -861,6 +892,7 @@ function cmdPrep(args) {
|
|
|
861
892
|
groupFocus: args.focus && args.focus !== true ? String(args.focus) : null,
|
|
862
893
|
summaryMaxChars: args["summary-chars"] ? Number(args["summary-chars"]) : null,
|
|
863
894
|
groupSummaryMaxChars: args["group-summary-chars"] ? Number(args["group-summary-chars"]) : null,
|
|
895
|
+
ruleFp: ruleFingerprint(),
|
|
864
896
|
fetched: all.length, kept: kept.length, dropped,
|
|
865
897
|
planGroups,
|
|
866
898
|
}));
|
|
@@ -901,7 +933,7 @@ function cmdPrep(args) {
|
|
|
901
933
|
const kind = kindOfTitle(group.title);
|
|
902
934
|
const skip = group.groupId === 'priority' || group.count <= 1 || (kind !== '' && !focusKinds.has(kind));
|
|
903
935
|
const rule = skip ? null : matchRule(group.title);
|
|
904
|
-
const marker = skip ? ' [无需分组]' : (rule || group.title.includes('内部留言') ? ' [
|
|
936
|
+
const marker = skip ? ' [无需分组]' : (rule || group.title.includes('内部留言') ? ' [需二次分组]' : '');
|
|
905
937
|
console.log(`=== ${group.groupId} | ${group.title} | ${group.count}${marker}`);
|
|
906
938
|
if (skip) continue;
|
|
907
939
|
// 回显规则内容:组名/分法只按 groupingPrompt 来(词表不得自造),摘要按 requestSummaryPrompt 写
|
|
@@ -916,7 +948,8 @@ function cmdPrep(args) {
|
|
|
916
948
|
}
|
|
917
949
|
}
|
|
918
950
|
console.log('\n下一步:node %s build --dir %s', path.basename(__filename), dir);
|
|
919
|
-
console.log('(标了 [
|
|
951
|
+
console.log('(标了 [需二次分组] 的组——内部留言、以及规则 focus:false 的组如 安全问题处理工单——在**单条摘要之后**的二次分组阶段才需要 aiGroups;build 阶段不需要,先把摘要写完)');
|
|
952
|
+
console.log('(写 aiGroups 时给 needAI:true 的组带上 summary 字段,分组+组摘要在同一轮拿到,不用再跑一次组摘要)');
|
|
920
953
|
}
|
|
921
954
|
|
|
922
955
|
function cmdBuild(args) {
|
|
@@ -926,7 +959,8 @@ function cmdBuild(args) {
|
|
|
926
959
|
const kept = readJson(path.join(dir, 'items.json'));
|
|
927
960
|
const planGroups = state.planGroups || [];
|
|
928
961
|
const countById = new Map(planGroups.map((g) => [g.groupId, g.count]));
|
|
929
|
-
// `--plan
|
|
962
|
+
// `--plan`:2026-11-03 起 build 阶段**不再消费** aiGroups(二次分组后移到 subGroup);
|
|
963
|
+
// 这里只做校验与落盘,finish 阶段自动读取目录里的 aiGroups.json。
|
|
930
964
|
// 不传时直接走 CLI 确定性分组(等价于 aiGroups 未传)。
|
|
931
965
|
let aiGroups;
|
|
932
966
|
if (planFile) {
|
|
@@ -937,7 +971,7 @@ function cmdBuild(args) {
|
|
|
937
971
|
const byGroup = new Map();
|
|
938
972
|
for (const entry of aiGroups) {
|
|
939
973
|
if (!entry || !entry.groupId || !Array.isArray(entry.requestIds)) {
|
|
940
|
-
console.error('✖ aiGroups 元素必须是 {groupId,title,requestIds:[...]}(seq 已废弃)'); process.exit(1);
|
|
974
|
+
console.error('✖ aiGroups 元素必须是 {groupId,title,requestIds:[...],summary?}(seq 已废弃)'); process.exit(1);
|
|
941
975
|
}
|
|
942
976
|
if (!countById.has(String(entry.groupId))) {
|
|
943
977
|
console.error(`✖ 未知 groupId ${entry.groupId}(合法值见 state.json 的 planGroups)`); process.exit(1);
|
|
@@ -965,8 +999,8 @@ function cmdBuild(args) {
|
|
|
965
999
|
const t = Date.now();
|
|
966
1000
|
const sg = runStage({
|
|
967
1001
|
stage: 'smartGroup',
|
|
1002
|
+
// 2026-11-03:本阶段只做 workflowName 首次分组 + 平铺结构(二次分组在 finish 的 subGroup)。
|
|
968
1003
|
items: kept,
|
|
969
|
-
...(aiGroups !== undefined ? { aiGroups } : {}),
|
|
970
1004
|
withDetailContext: true,
|
|
971
1005
|
...(state.groupFocus ? { groupFocus: state.groupFocus } : {}),
|
|
972
1006
|
...(state.summaryMaxChars ? { summaryMaxChars: state.summaryMaxChars } : {}),
|
|
@@ -1006,18 +1040,6 @@ function cmdBuild(args) {
|
|
|
1006
1040
|
}
|
|
1007
1041
|
console.log(' → 读 need-summaries.json(items[].requestId + context),摘要写成 aiSummaries.json(元素 {requestId,summary})后重跑:');
|
|
1008
1042
|
console.log(' node %s finish --dir %s --summaries <aiSummaries.json> --timing-report', path.basename(__filename), dir);
|
|
1009
|
-
// 组摘要(aiGroup.groupSummary.needAI=true 的汇总项):口径随批次下发,模型按它写 aiGroupSummaries
|
|
1010
|
-
const gsBatches = sg.data.groupSummaryBatches || [];
|
|
1011
|
-
if (gsBatches.length > 0) {
|
|
1012
|
-
console.log('\n待写组摘要(写成 aiGroupSummaries.json,元素 {groupId,summary}):');
|
|
1013
|
-
for (const b of gsBatches) {
|
|
1014
|
-
console.log(`### 组摘要 ${b.groupId}|${b.parentTitle} → ${b.title}|${b.count} 条|目标字数 ${b.suggestedMaxChars}`);
|
|
1015
|
-
if (b.prompt) console.log(`口径:${b.prompt}`);
|
|
1016
|
-
if (b.hint) console.log(`提示:${b.hint}`);
|
|
1017
|
-
if (b.stats && b.stats.tail) console.log(`tail:${b.stats.tail}`);
|
|
1018
|
-
}
|
|
1019
|
-
console.log('\nfinish 时加:--group-summaries <aiGroupSummaries.json>');
|
|
1020
|
-
}
|
|
1021
1043
|
}
|
|
1022
1044
|
|
|
1023
1045
|
function cmdFinish(args) {
|
|
@@ -1026,7 +1048,14 @@ function cmdFinish(args) {
|
|
|
1026
1048
|
const kept = readJson(path.join(dir, 'items.json'));
|
|
1027
1049
|
// `aiGroups.json` 可能不存在(build 没传 --plan 时就是确定性分组),此时按「未传 aiGroups」处理。
|
|
1028
1050
|
const planPath = path.join(dir, 'aiGroups.json');
|
|
1051
|
+
// `--plan` 给了就以它为准(落到目录里,后续 stage=subGroup 直接读)
|
|
1052
|
+
if (args.plan && args.plan !== true) {
|
|
1053
|
+
const src = String(args.plan);
|
|
1054
|
+
if (src !== planPath && fs.existsSync(src)) fs.copyFileSync(src, planPath);
|
|
1055
|
+
}
|
|
1029
1056
|
const aiGroups = fs.existsSync(planPath) ? readJson(planPath) : undefined;
|
|
1057
|
+
/** 有没有二次分组计划:没有就只回填单条摘要,不做 subGroup(也就不产组摘要、不导出)。 */
|
|
1058
|
+
const hasPlan = aiGroups !== undefined;
|
|
1030
1059
|
const sg = readJson(path.join(dir, 'smartgroup.json'));
|
|
1031
1060
|
|
|
1032
1061
|
// 即使没传 --summaries 也要跑一次 summary 阶段:这样才能让**摘要缓存**回填
|
|
@@ -1040,7 +1069,9 @@ function cmdFinish(args) {
|
|
|
1040
1069
|
withDetailContext: true,
|
|
1041
1070
|
wfIdGroup: sg.data.wfIdGroup,
|
|
1042
1071
|
aiSummaries,
|
|
1043
|
-
|
|
1072
|
+
// 单条摘要回填完 → 同进程做 ai 二次分组(stage=subGroup)→ 再产组摘要批次;
|
|
1073
|
+
// 没有 aiGroups 时只回填单条摘要,二次分组留到下一步(两条链路完全解耦)。
|
|
1074
|
+
...(hasPlan ? { withSubGroup: true, withGroupSummaryContext: true } : {}),
|
|
1044
1075
|
...(state.summaryMaxChars ? { summaryMaxChars: state.summaryMaxChars } : {}),
|
|
1045
1076
|
...(state.groupSummaryMaxChars ? { groupSummaryMaxChars: state.groupSummaryMaxChars } : {}),
|
|
1046
1077
|
skillTiming: { startedAt: state.startedAt, steps: [{ name: 'collect', kind: 'cli', durationMs: state.collectMs }] },
|
|
@@ -1053,6 +1084,15 @@ function cmdFinish(args) {
|
|
|
1053
1084
|
fs.writeFileSync(path.join(dir, 'state.json'), JSON.stringify(state));
|
|
1054
1085
|
console.log('summary 内部 %s / 含进程启动 %s(回填 %d 条,其余走缓存预填)',
|
|
1055
1086
|
summaryInternal === null ? '-' : fmt(summaryInternal), fmt(summaryWallMs), aiSummaries.length);
|
|
1087
|
+
if (!hasPlan) {
|
|
1088
|
+
// 2026-11-03:ai 二次分组与单条摘要解耦——没有计划就停在这里,不产组摘要、不导出。
|
|
1089
|
+
const filled = (result.meta && result.meta.summarized) || 0;
|
|
1090
|
+
const emptyN = (result.meta && result.meta.empty) || 0;
|
|
1091
|
+
console.log('单条摘要已回填 %d 条(空 %d)。ai 二次分组是下一步:', filled, emptyN);
|
|
1092
|
+
console.log(' 把 aiGroups.json 放到 %s(或 --plan <path>),再跑:', path.join(dir, 'aiGroups.json'));
|
|
1093
|
+
console.log(' node %s finish --dir %s --plan <aiGroups.json> --timing-report', path.basename(__filename), dir);
|
|
1094
|
+
return;
|
|
1095
|
+
}
|
|
1056
1096
|
// 未回填的缺失 id 不在这里单列:summary 阶段的信封不带 summaryBatches/summaryStats,
|
|
1057
1097
|
// 空 id 列表统一由 exportFinal 的闸门①从最终结构里就地提取(能直接给出 requestId)。
|
|
1058
1098
|
// 未知 requestId 的 aiSummaries 由 CLI 侧硬校验拒绝(ai_summary_unknown_request,非零退出)。
|
|
@@ -1118,6 +1158,7 @@ function cmdFinish(args) {
|
|
|
1118
1158
|
// 详情取数发生在 smartGroup 阶段 ⇒ failed 从 smartgroup.json 的 data.summaryStats 取。
|
|
1119
1159
|
allowEmptySummary: args['allow-empty-summary'] === true,
|
|
1120
1160
|
allowDetailFail: args['allow-detail-fail'] === true,
|
|
1161
|
+
allowStaleRules: args['allow-stale-rules'] === true,
|
|
1121
1162
|
detailFailed: ((sg.data || {}).summaryStats || {}).failed || 0,
|
|
1122
1163
|
groupEmpty: (finalResult.meta && finalResult.meta.groupEmpty) || 0,
|
|
1123
1164
|
});
|
|
@@ -1173,8 +1214,9 @@ else {
|
|
|
1173
1214
|
console.log('用法:node ' + path.basename(__filename) + ' <run|prep|build|finish> [options]');
|
|
1174
1215
|
console.log(' run [--days N | --from A --to B] [--limit 500] [--out DIR] [--timing-report] # 一次跑完 prep+build;用户没说时间段就都不传 = 不限时间取前 500 条');
|
|
1175
1216
|
console.log(' prep --limit 100 [--exclude 内部留言] [--days 1460] [--sub-category 待处理] [--tabid 7] [--isremarks 1,2] [--out DIR] # 小分类:--sub-category/--tabid(显式 tabid 优先);isremarks=备注筛选(数字逗号拼接)');
|
|
1176
|
-
console.log(' build --dir DIR [--plan aiGroups.json] #
|
|
1217
|
+
console.log(' build --dir DIR [--plan aiGroups.json] # aiGroups 可先落盘(不传也行):build 只做首次分组+平铺,二次分组在 finish');
|
|
1177
1218
|
console.log(' finish --dir DIR [--summaries aiSummaries.json] [--group-summaries aiGroupSummaries.json] [--timing-report]');
|
|
1219
|
+
console.log(' 规则新鲜度:finish 导出前比对 aigroup 指纹——规则在取数后被改过即拦截(新规则+旧数据出不了文件);确要带旧口径出文件加 --allow-stale-rules');
|
|
1178
1220
|
console.log(' 待写摘要素材:build/ run 停下时写 <out>/need-summaries.json(无损),控制台只留批次索引;写 aiSummaries.json 后 finish --summaries 回填');
|
|
1179
1221
|
console.log(' 组摘要未回填:以 exit 0 + NEEDS_GROUP_SUMMARIES 返回(不导出),完整素材在 <out>/need-group-summaries.json;');
|
|
1180
1222
|
console.log(' 在该文件补 summary 后用 --group-summaries 指回它重跑。真失败(空摘要/降级话术/要素缺失/详情失败)仍 exit 1;');
|
|
@@ -13,10 +13,10 @@ requires:
|
|
|
13
13
|
cliHelp: "weaver-work-cli invoice --help"
|
|
14
14
|
---
|
|
15
15
|
|
|
16
|
-
**CRITICAL — 开始前 MUST
|
|
16
|
+
**CRITICAL — 开始前 MUST 直接执行本技能的业务命令(`weaver-work-cli --json invoice run ...`);不要预先读取共享规则,也不要先跑 `auth status`、`doctor --e10`、`auth xiaoe` 等登录或状态检查。** 小e(XiaoE)环境下登录由 CLI 自己在公共会话加载层完成:进程内存在任意 `XIAOE_*` 环境变量(宿主新增 `XIAOE_CLIENT_TYPE=client|cloud`,分别表示桌面客户端与网页端)时,缺少本地会话会自动换取登录信息并继续执行原请求,已有会话被拒绝为失效时静默恢复并原样重放 1 次,换票结果落盘供后续命令复用。Agent 不参与该过程,**也不得在思考过程或回复中描述登录、换票、重登、会话恢复等中间步骤**,只呈现业务结果。仅以下三种情形才读取 `[../weaver-e10-shared/SKILL.md](../weaver-e10-shared/SKILL.md)`:① 命令不可用(`command not found` / 退出码 127),或返回 `authentication` / `session_expired` 且 CLI 自动恢复后仍失败、`subtype=xiaoe_credential_unavailable`;② 即将执行写入/删除/导入类操作(确认、continuation 与回查协议);③ 需要判定是否传 `--is-connector`。若共享规则不存在、CLI 未安装或读取失败,说明本技能的必需依赖缺失,必须调用宿主提供的提问/确认弹框,向用户说明必须补齐 `weaver-work-cli` 与共享 skill `weaver-e10-shared`(不补齐本技能无法执行)及补齐计划,并把下面两条待执行命令原样完整展示在确认信息中;Agent 不能在未确认时自行安装。用户明确确认后,Agent 必须直接代为按顺序执行且每条仅执行一次,不得要求或引导用户手动执行:① 缺 CLI 时执行 `npm install -g weaver-work-cli`;② 再执行 `weaver-work-cli skills install shared --target-dir <SKILLS_ROOT>` 装回共享 skill,`<SKILLS_ROOT>` 取本 SKILL.md 所在目录的上一级绝对目录(即与本技能同级的 skills 根目录),不要省略 `--target-dir`——省略会装进默认目录,导致本技能依然读不到共享规则。命令均成功后重新读取共享规则;仍读不到就停止并把结果报告用户,不得凭猜测继续。**
|
|
17
17
|
**`--is-connector` 判据**:用户明确使用连接器、或上下文要求用连接器完成任务 → 传 `true`;本次任务或上下文直接选择单独技能 → 不传;用户没有明确说明时,按**正在运行的这份 Skill 是哪一级**定——**用户级(条目标 `(user)`)不传,连接器级(标 `(connector)`)传**(同名 Skill 只会运行用户级那一份)。传 `true` 时不要再写 `--profile` / `--base-url`。完整规则见 `[../weaver-e10-shared/SKILL.md](../weaver-e10-shared/SKILL.md)`。
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
登录与会话由 CLI 托管,Agent 不做登录前置;只有本文件 CRITICAL 列出的三种情形才按共享规则使用 `weaver-work-cli auth ...` 命令体系判断登录态。禁止直接读取、列出、打印或解析用户主目录下的旧 `.e10-cli`、auth、config 或 Keychain 数据。
|
|
20
20
|
所有命令通过 `weaver-work-cli --json invoice run <operation>` 执行(唯一例外:报销单与开票流程的创建/修改调用 `weaver-e10-workflow` 技能的 `weaver-work-cli --json workflow run workflow.*`,见下方「报销填单」「AI 开票」):简单 JSON 优先传 `--input-json '<json>'`,复杂或多行 JSON 先写入 UTF-8 文件再传 `--input <path>`,只有确认当前 shell 能稳定传管道时才使用 `--input -`。调用前先按需读取 references 下对应的文件,查参数结构,不要猜字段;**references 是第一信息源**,`weaver-work-cli invoice schema` 是 operation、字段和风险等级的合约来源。
|
|
21
21
|
命令示例、提示词和临时说明必须同时兼容 Windows 和 macOS/Linux;涉及 JSON 输入、用户目录、路径分隔符、Python 启动器、文件删除、目录查看或文件比对时,同时给 Windows PowerShell 与 macOS/Linux(bash/zsh)两套示例。Agent 先根据当前系统和 shell 选择对应示例,不确定时用 `node -p "process.platform"` 判断。Windows/PowerShell 下不要使用 `printf`、`$HOME/...`、`~/...`、bash 反斜杠续行、`rm/ls/diff/python3` 等 Unix-only 写法。
|
|
22
22
|
涉及发票附件、图片、本地文件、远程 URL 文件或 OCR/文件解析的操作,执行前必须提醒用户:文件内容可能被上传到 E10 业票通、OCR/查验服务,并可能进入当前大模型上下文用于理解和处理;必须等待用户明确确认后才继续。
|
|
@@ -27,7 +27,7 @@ cliHelp: "weaver-work-cli invoice --help"
|
|
|
27
27
|
|
|
28
28
|
本文件在技能加载时已整体注入上下文,**不要再用 Read 读本 SKILL.md**;仅需核对 `version` / `agent_created` 时读前 15 行,且**修改本包内文件不必先确认 `agent_created`**(此处已声明 `true`)。
|
|
29
29
|
|
|
30
|
-
- **共享规则 `../weaver-e10-shared/SKILL.md`
|
|
30
|
+
- **共享规则 `../weaver-e10-shared/SKILL.md` 不是前置**:只有 CRITICAL 列出的三种情形才读,同一会话只读一次;内容已在本轮上下文时直接复用。
|
|
31
31
|
- **只读命中路由的那个 reference**。reference 是参数与字段的第一信息源;reference 已覆盖的参数不要再跑 `--help`,`schema` 只用于确认 operation 清单与风险等级。
|
|
32
32
|
- **单点查询压缩成三个动作**:读 1 个 reference → 1 条 CLI 命令 → 直接输出。已给出 `fid` / `number` 时禁止 `list → filter → get` 链路。
|
|
33
33
|
- **同一字段不重复查**:一轮内已有新鲜结果就复用,不要为"再确认一次"重跑同一个只读 operation。
|
|
@@ -163,13 +163,12 @@ cliHelp: "weaver-work-cli invoice --help"
|
|
|
163
163
|
- 失败后先看进程退出码、`error.type`、`error.subtype` 和 `error.message`
|
|
164
164
|
- **除非错误明确提示可恢复或需要补充参数,否则不要重复刷同一个 operation**
|
|
165
165
|
- 写请求已经发出后,遇到结果不确定必须停止;不要把 `.apply` 当成可重试读操作
|
|
166
|
-
- **错误为 `authentication`(未登录,如 `E10 auth not found`)或 `session_expired
|
|
167
|
-
-
|
|
168
|
-
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
- 显式登录后读操作可重新执行;写操作不得复用旧 continuation,必须重新 prepare 并重新确认。已返回 `partial/write_uncertain` 时先只读回查,禁止直接重放写入。
|
|
166
|
+
- **错误为 `authentication`(未登录,如 `E10 auth not found`)或 `session_expired`(登录态失效)时:不要盲目重试、不要换域名重试、不要用示例占位域名登录**。先判断 CLI 是否已经自动处理:
|
|
167
|
+
- **小e 环境(进程内存在任意 `XIAOE_*`,含 `XIAOE_CLIENT_TYPE=client|cloud`)**:登录缺失与过期都由 CLI 底层在公共请求层静默换取并原样重放 1 次,Agent 不执行任何登录命令——包括 `weaver-work-cli auth xiaoe`——也不重跑原业务命令,**也不在思考或回复里复述登录、换票、重登、会话恢复过程**。仍返回 `session_expired` 或 `authentication/xiaoe_credential_unavailable` 时,用一句话告知「小e 当前登录态不可用,请在小e 中重新登录后重试」并停止,不回退浏览器登录。
|
|
168
|
+
- **非小e 环境**才读取共享规则 `../weaver-e10-shared/references/e10-auth-and-session.md`,并按其中流程处理:
|
|
169
|
+
- 仅首次无会话或明确的 `auth not found`,才由 Agent 复用任务开始时的宿主判定。
|
|
170
|
+
- 首次认证且非 XiaoE 时不得执行 `auth xiaoe`;取得用户确认的真实 E10 登录域名后,执行 `weaver-work-cli auth login --base-url "<用户确认的 E10 登录域名>" --agent_type "<当前智能体名称>"`。环境不能完成本机浏览器回调时停止并反馈。
|
|
171
|
+
- 显式登录后读操作可重新执行;写操作不得复用旧 continuation,必须重新 prepare 并重新确认。已返回 `partial/write_uncertain` 时先只读回查,禁止直接重放写入。
|
|
173
172
|
- 登录类命令必须带 timeout 限时(上限 300 秒 / 5 分钟,后台运行 + 限时观察):输出一旦出现 `Open browser login`、`Waiting for E10 authorization callback` 或 `Could not open browser automatically`,即判定已降级到浏览器 OAuth,立即终止该命令并反馈,不得继续等待。登录失败不自动重试。
|
|
174
173
|
- 需要浏览器登录时必须携带发起方标识 `--agent_type "<当前智能体名称>"`(授权确认页展示用;宿主无法确认名称时才可省略,交由 CLI 从环境变量推断)。
|
|
175
174
|
|
|
@@ -6,13 +6,16 @@
|
|
|
6
6
|
|
|
7
7
|
## 准备命令
|
|
8
8
|
|
|
9
|
+
直接用一条不依赖登录态的只读命令确认可用:
|
|
10
|
+
|
|
9
11
|
```text
|
|
10
|
-
weaver-work-cli --version
|
|
11
|
-
weaver-work-cli doctor --e10
|
|
12
12
|
weaver-work-cli invoice schema
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
- **小e 环境(进程内存在任意 `XIAOE_*`,含 `XIAOE_CLIENT_TYPE=client|cloud`)**:不要执行 `weaver-work-cli --version` 或 `doctor --e10`,版本更新与登录由小e 客户端和 CLI 会话层托管;业务命令缺少会话时会自动换取登录信息并继续执行,已有会话失效时静默恢复并重放 1 次。
|
|
16
|
+
- **非小e 环境**首次使用才执行 `weaver-work-cli --version` 与 `doctor --e10`。
|
|
17
|
+
|
|
18
|
+
仅在认证最终失败(`authentication` / `session_expired` / `xiaoe_credential_unavailable`)时,才按共享规则读取 `../../weaver-e10-shared/references/e10-auth-and-session.md`。
|
|
16
19
|
|
|
17
20
|
## 固定入口
|
|
18
21
|
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { createRequire as __esbuildCreateRequire } from 'node:module';
|
|
2
2
|
const require = __esbuildCreateRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
imBusinessError,
|
|
5
|
+
imConfirmationError,
|
|
6
|
+
imValidationError
|
|
7
|
+
} from "./chunk-ZEDWSH32.js";
|
|
3
8
|
import {
|
|
4
9
|
collapseNewlines,
|
|
5
10
|
collectI18nIds,
|
|
@@ -12,11 +17,6 @@ import {
|
|
|
12
17
|
parseMsg,
|
|
13
18
|
senderName
|
|
14
19
|
} from "./chunk-YLCYX7LE.js";
|
|
15
|
-
import {
|
|
16
|
-
imBusinessError,
|
|
17
|
-
imConfirmationError,
|
|
18
|
-
imValidationError
|
|
19
|
-
} from "./chunk-ZEDWSH32.js";
|
|
20
20
|
|
|
21
21
|
// src/shortcuts/im/operations/types.ts
|
|
22
22
|
var READ = "read";
|