weaver-work-cli 0.1.33 → 0.1.36
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-FVFY6GZN.js → archive-XBVH7JU7.js} +2 -2
- package/dist/chunks/{archive-oa-NW3OD4UV.js → archive-oa-MZM3EKFQ.js} +2 -2
- package/dist/chunks/{asset-7QJKMIDV.js → asset-4XO7UOUW.js} +2 -2
- package/dist/chunks/{attachment-content-OSAVA6K3.js → attachment-content-VXSWANAC.js} +3 -3
- package/dist/chunks/{blog-I7SDPNW4.js → blog-PGZKOPSC.js} +2 -2
- package/dist/chunks/{caizhilian-O37ZIQNY.js → caizhilian-BH4ZVGUN.js} +2 -2
- package/dist/chunks/{calendar-7KXE4ED3.js → calendar-MXEMTIO4.js} +2 -2
- package/dist/chunks/{chunk-VBCFFFGT.js → chunk-5DQEEGCC.js} +4 -1
- package/dist/chunks/{chunk-KAS45KNR.js → chunk-6LLJFKJE.js} +1 -1
- package/dist/chunks/{chunk-HEL5XTYI.js → chunk-BPE37FPB.js} +26 -4
- package/dist/chunks/{chunk-IHUYP6LO.js → chunk-F746NKNF.js} +1 -1
- package/dist/chunks/{chunk-MQ2I5AA3.js → chunk-HXJQI5NM.js} +2 -2
- package/dist/chunks/{chunk-ILMBNVSG.js → chunk-I6QGIBDM.js} +2 -2
- package/dist/chunks/{chunk-EEWPQE3O.js → chunk-JCSN3JGM.js} +2 -2
- package/dist/chunks/{chunk-D223PTXU.js → chunk-JNG42JKG.js} +29 -1
- package/dist/chunks/{chunk-6ATGWRZM.js → chunk-JUXVYKII.js} +4 -1
- package/dist/chunks/{chunk-GFPXQIY2.js → chunk-JYKABYCV.js} +2 -2
- package/dist/chunks/{chunk-Q6LWB5HX.js → chunk-NCOVUAZK.js} +2 -2
- package/dist/chunks/{chunk-WY74UBJ6.js → chunk-QHFANTX7.js} +900 -204
- package/dist/chunks/{chunk-WRRJ4GG2.js → chunk-QYGO5EE2.js} +2 -2
- package/dist/chunks/{chunk-RBGOMK4Y.js → chunk-T72N74ZT.js} +2 -2
- package/dist/chunks/{chunk-MEEFGWTM.js → chunk-TC6MZAO3.js} +84 -9
- package/dist/chunks/{chunk-OCU4RLHC.js → chunk-VPUTVEMC.js} +98 -34
- package/dist/chunks/{chunk-PRHJGPMA.js → chunk-VPXOPQJI.js} +2 -2
- package/dist/chunks/{chunk-NHA62QD7.js → chunk-WXFPWCXG.js} +3 -3
- package/dist/chunks/{chunk-2FLWXFVS.js → chunk-XMGSYD6S.js} +4 -4
- package/dist/chunks/{conflict-SFNEVJY5.js → conflict-JAB2LJEZ.js} +2 -2
- package/dist/chunks/contract-XI2EEIZU.js +9110 -0
- package/dist/chunks/{cowork-CKWYHXYB.js → cowork-SCPGLBA4.js} +44 -25
- package/dist/chunks/{ebuilder-form-KOLJRVZD.js → ebuilder-form-EYLHNOTA.js} +3 -3
- package/dist/chunks/{ehr-WFOC3B4D.js → ehr-EAP77IMT.js} +172 -9
- package/dist/chunks/{esb-LJZTN663.js → esb-2TGGXEE7.js} +4 -4
- package/dist/chunks/{fna-F7QRIIZC.js → fna-2X7ZE7BU.js} +13 -8
- package/dist/chunks/{host-VQ6JJXGQ.js → host-C6EL2RKL.js} +3 -3
- package/dist/chunks/{host-BCGUVEWX.js → host-I4NRK4MX.js} +3 -3
- package/dist/chunks/{host-DGE2TZD4.js → host-Q4LZGCRU.js} +3 -3
- package/dist/chunks/{host-BQBRHVR3.js → host-UEI5FGDM.js} +3 -3
- package/dist/chunks/{host-KXPTEWFS.js → host-XCLDDXKQ.js} +3 -3
- package/dist/chunks/{hrm-NI6XAKW5.js → hrm-YXERJM76.js} +3 -3
- package/dist/chunks/{im-7TRTF3KT.js → im-A4VZN2TQ.js} +3 -3
- package/dist/chunks/{invoice-AOXWJKYT.js → invoice-2Z6YPMIS.js} +3 -3
- package/dist/chunks/{jiuchuanhui-7NQWEZAW.js → jiuchuanhui-AR5GMKZB.js} +2 -2
- package/dist/chunks/{lazy-dispatch-RNS4EE4S.js → lazy-dispatch-QXW7P4X3.js} +4 -4
- package/dist/chunks/{mail-VDHJAB4O.js → mail-7GZ6CPBJ.js} +44 -23
- package/dist/chunks/{meeting-GA7XCNNP.js → meeting-3NMGA3MB.js} +74 -10
- package/dist/chunks/{okr-TQIRERPQ.js → okr-BZ6XUOAG.js} +2 -2
- package/dist/chunks/{plan-4RY4LN2P.js → plan-DR5CMUYP.js} +2 -2
- package/dist/chunks/{project-D6XT2OC5.js → project-6J63MK33.js} +2 -2
- package/dist/chunks/{registry-JHRIDQ3A.js → registry-KDD7DHNK.js} +4 -4
- package/dist/chunks/{registry-VOGKFFTR.js → registry-TKX2E7C7.js} +2 -2
- package/dist/chunks/{registry-QKMI43Q6.js → registry-VRTNC6UR.js} +8 -8
- package/dist/chunks/{room-recommend-D4EUOOWY.js → room-recommend-XCWRMB5P.js} +4 -4
- package/dist/chunks/{schedule-XPFBHPCV.js → schedule-IVBICP32.js} +4 -4
- package/dist/chunks/{workflow-HLBZRWIY.js → workflow-D74NFK3C.js} +11 -4
- package/dist/index.js +31 -26
- package/dist/internal/e10/fetch-timing.js +31 -0
- package/dist/internal/e10/request-runtime.js +5 -0
- package/dist/shortcuts/cowork/host.js +8 -0
- package/dist/shortcuts/cowork/operations/types.js +17 -2
- package/dist/shortcuts/ehr/operations/recruit-write.js +35 -0
- package/dist/shortcuts/ehr/operations/recruit.js +147 -0
- package/dist/shortcuts/fna/operations/expense-chart.js +19 -7
- package/dist/shortcuts/index.js +5 -0
- package/dist/shortcuts/mail/host.js +8 -0
- package/dist/shortcuts/mail/operations/types.js +17 -2
- package/dist/shortcuts/meeting/index.js +79 -1
- package/dist/shortcuts/meeting/manifest.js +10 -0
- package/dist/shortcuts/meeting/operations/eb/catalog.js +5 -0
- package/dist/shortcuts/meeting/operations/eb/conflict.js +6 -1
- package/dist/shortcuts/meeting/operations/eb/create-flow.js +1047 -134
- package/dist/shortcuts/meeting/operations/eb/factory.js +101 -7
- package/dist/shortcuts/meeting/operations/eb/room-recommend.js +36 -2
- package/dist/shortcuts/meeting/operations/eb-fallback.js +4 -0
- package/dist/shortcuts/meeting/operations/env.js +6 -0
- package/dist/shortcuts/meeting/operations/invitation.js +79 -20
- package/dist/shortcuts/workflow/endpoints.js +8 -3
- package/dist/shortcuts/workflow/operations/form.js +181 -34
- package/dist/shortcuts/workflow/operations.js +23 -1
- package/docs/ehr.md +1 -1
- package/docs/fna.md +2 -1
- package/package.json +1 -1
- package/skill-template/business-info.json +18 -0
- package/skill-template/domains/cowork.md +14 -0
- package/skills/weaver-e10-cowork/SKILL.md +101 -0
- package/skills/weaver-e10-cowork/references/cowork-read.md +90 -0
- package/skills/weaver-e10-cowork/references/cowork-write.md +131 -0
- package/skills/weaver-e10-cowork/references/safety-boundaries.md +45 -0
- package/skills/weaver-e10-jucailin/SKILL.md +21 -3
- package/skills/weaver-e10-jucailin/references/recruit-read.md +25 -0
- package/skills/weaver-e10-jucailin/references/recruit-write.md +13 -0
- package/skills/weaver-e10-jucailin/references/salary.md +15 -11
- package/skills/weaver-e10-mail/SKILL.md +12 -9
- package/skills/weaver-e10-meeting/SKILL.md +284 -34
- package/skills/weaver-e10-meeting/references/meeting-eb.md +131 -0
- package/skills/weaver-e10-meeting/references/meeting-invitation.md +28 -2
- package/skills/weaver-e10-meeting.zip +0 -0
- package/skills/weaver-e10-qiyecheng/SKILL.md +5 -2
- package/skills/weaver-e10-qiyecheng/references/catalog.md +2 -2
- package/skills/weaver-e10-qiyecheng/references/expense-chart.md +15 -1
- package/skills/weaver-e10-qiyecheng/references/source-manifest.json +22 -21
|
@@ -26,6 +26,7 @@ import { continuationReplayError } from '../continuation.js';
|
|
|
26
26
|
import { writeStateFileBestEffort } from '../state.js';
|
|
27
27
|
import { buildHistoryRequestData, fetchHistoryListSnapshot, filterHistoryRequestData, pickUniqueMineWorkflow, prefetchHistoryDetails } from './read.js';
|
|
28
28
|
import { hasXiaoEEnv } from '../../../internal/e10/auth/xiaoe.js';
|
|
29
|
+
import { createFetchTimingSink, runWithFetchTiming } from '../../../internal/e10/fetch-timing.js';
|
|
29
30
|
import { buildChatSceneInput, formatLocalNow, requestFormFill } from './chatscene.js';
|
|
30
31
|
// ---------------------------------------------------------------------------
|
|
31
32
|
// 常量(与 Python 源逐条对齐)
|
|
@@ -1485,7 +1486,23 @@ async function resolveCreateWorkflow(rawWorkflow, env) {
|
|
|
1485
1486
|
// 澄清文案里回显的是**用户原话**(不是切分后的关键词)——用户要能认出自己给的条件
|
|
1486
1487
|
const queryText = rawTerms.join('、');
|
|
1487
1488
|
if (!rawTerms.length) {
|
|
1488
|
-
|
|
1489
|
+
// ★ 2026-10-30 用户裁定:这一档不是「名称没匹配上」,而是**必填入参 `workflow` 根本没给**
|
|
1490
|
+
// (缺键 / 空数组 / 空字符串都算)。原先与「只给了填充词」共用同一句澄清,模型看到的是
|
|
1491
|
+
// 「请提供完整名称」,于是键名写错(如写成 `workflows`、`name`)时不知道自己漏了 `workflow`,
|
|
1492
|
+
// 只会回头把锅甩给用户。现在单独标 `clarificationReason=workflow_required` 并下发
|
|
1493
|
+
// `missingInput` + `requiredInput`,让模型知道「是我少传了入参、要按这个形态补」。
|
|
1494
|
+
throw workflowClarificationError('workflow', '', '要发起哪个流程?请提供该流程的完整名称(或其它可用于检索的关键词)后再继续。', [], {
|
|
1495
|
+
clarificationReason: 'workflow_required',
|
|
1496
|
+
missingInput: ['workflow'],
|
|
1497
|
+
requiredInput: {
|
|
1498
|
+
workflow: {
|
|
1499
|
+
required: true,
|
|
1500
|
+
type: 'string | string[]',
|
|
1501
|
+
description: '要发起的工作流:完整名称、名称关键词,或「名称(ID)」;纯数字按工作流 ID 处理。',
|
|
1502
|
+
example: ['费用报销'],
|
|
1503
|
+
},
|
|
1504
|
+
},
|
|
1505
|
+
});
|
|
1489
1506
|
}
|
|
1490
1507
|
// 先做**纯本地**的解析:显式 ID(`名称(ID)` / 纯数字)与名称关键词(一格可含多个,见
|
|
1491
1508
|
// `splitCreateKeywords`)。这一步不依赖远端结果,于是能先判"到底有没有可用条件"——
|
|
@@ -1751,9 +1768,9 @@ function singleExplicitWorkflowId(rawWorkflow) {
|
|
|
1751
1768
|
return parsed.id ?? (/^[0-9]+$/.test(terms[0]) ? terms[0] : '');
|
|
1752
1769
|
}
|
|
1753
1770
|
/** 表单载入 + 该工作流的记忆:两者只共享 `workflowId`,可以并行。 */
|
|
1754
|
-
async function loadCreateFormPack(workflowId, env) {
|
|
1771
|
+
async function loadCreateFormPack(workflowId, env, options = {}) {
|
|
1755
1772
|
const [{ data }, workflowMemory] = await Promise.all([
|
|
1756
|
-
buildCreateFormData(workflowId, env),
|
|
1773
|
+
buildCreateFormData(workflowId, env, options),
|
|
1757
1774
|
// 记忆读取是 best-effort(内部全 catch),不会把表单载入的错误顶掉。
|
|
1758
1775
|
fetchWorkflowMemory(workflowId, env),
|
|
1759
1776
|
]);
|
|
@@ -1839,7 +1856,7 @@ async function resolveIntentFill(pack, userQuestion, baseUrl, env) {
|
|
|
1839
1856
|
* 现在返回的就是纯取数结果:`fields` + `historyRequestData` + `systemFields` + 记忆,
|
|
1840
1857
|
* 由模型自己拼 `data` 后交给 `createRequest`。
|
|
1841
1858
|
*/
|
|
1842
|
-
async function prepareCreateFormPayload(args, env) {
|
|
1859
|
+
async function prepareCreateFormPayload(args, env, options = {}) {
|
|
1843
1860
|
// 会话是**惰性**加载的(`ensureSession` 只在首次调用时填充)。本命令随后会并发发起多个请求,
|
|
1844
1861
|
// 先在这里显式取一次,避免并发首调各自走一遍会话初始化。
|
|
1845
1862
|
//
|
|
@@ -1858,11 +1875,11 @@ async function prepareCreateFormPayload(args, env) {
|
|
|
1858
1875
|
// `commonParam.authInfo` 给出;该 ID 不可用时由载入表单一侧的 `readCreateFormBlock`
|
|
1859
1876
|
// 抛出**可判别**的澄清(不是把它伪装成"没有匹配到可发起的工作流")。
|
|
1860
1877
|
target = { id: explicitId, name: '', source: 'workflowId' };
|
|
1861
|
-
pack = await loadCreateFormPack(explicitId, env);
|
|
1878
|
+
pack = await loadCreateFormPack(explicitId, env, options);
|
|
1862
1879
|
}
|
|
1863
1880
|
else {
|
|
1864
1881
|
target = await resolveCreateWorkflow(args.workflow, env);
|
|
1865
|
-
pack = await loadCreateFormPack(target.id, env);
|
|
1882
|
+
pack = await loadCreateFormPack(target.id, env, options);
|
|
1866
1883
|
}
|
|
1867
1884
|
// ★ 2026-10-15 用户裁定:`createForm` 改用**字符口径 20,000** 的**严格档**(见
|
|
1868
1885
|
// `CREATE_FORM_STDOUT_SAFE_CHARS` / `compactFormOutput` 的 `charBudget`)。
|
|
@@ -1954,7 +1971,21 @@ async function commandCreateForm(args, env) {
|
|
|
1954
1971
|
* 与旧版的差别只有一处:`workflowId` 由调用方(`resolveCreateWorkflow`)解析好后传进来,
|
|
1955
1972
|
* 不再是本函数的入参校验点。
|
|
1956
1973
|
*/
|
|
1957
|
-
async function buildCreateFormData(workflowId, env) {
|
|
1974
|
+
async function buildCreateFormData(workflowId, env, options = {}) {
|
|
1975
|
+
/**
|
|
1976
|
+
* 明细字段的标记形态(2026-10-30 用户裁定):
|
|
1977
|
+
* - 缺省 `subFormId` —— `createForm` 口径,明细字段带 `subFormId`(`data.details` 的键);
|
|
1978
|
+
* - `isDetail` —— `createRequestDirect` 独有的口径,明细字段带 `isDetail: true`、不再下发 `subFormId`。
|
|
1979
|
+
*/
|
|
1980
|
+
const detailMark = options.detailMark === 'isDetail' ? 'isDetail' : 'subFormId';
|
|
1981
|
+
/**
|
|
1982
|
+
* ★ 2026-10-30 用户裁定:`getHistory` 是 `createRequestDirect` 的**隐藏入参**(只在 CLI 实现层支持,
|
|
1983
|
+
* 不进 `inputSchema`、不进 skill)。传 `false` 时「历史发起流程」这一段整块不做 ——
|
|
1984
|
+
* 不发 `getMineListData`(列表)、不发明细,也不要组装;输出里 `historyRequestData` 直接给 `null`。
|
|
1985
|
+
*
|
|
1986
|
+
* 缺省(含 `createForm` 这一侧,它从不传)一律按 `true`,行为与从前一字不差。
|
|
1987
|
+
*/
|
|
1988
|
+
const getHistory = options.getHistory !== false;
|
|
1958
1989
|
const query = { workflowId, isCreate: 1, ...AJAX_QUERY };
|
|
1959
1990
|
const body = { workflowId, isCreate: 1, isMobile: 0 };
|
|
1960
1991
|
/**
|
|
@@ -1965,7 +1996,9 @@ async function buildCreateFormData(workflowId, env) {
|
|
|
1965
1996
|
* `.catch(() => null)` 是必须的:这个 Promise 可能因为表单后续抛错而**没人 await**,
|
|
1966
1997
|
* 兜住之后就不会留下未处理的拒绝;真要暴露的认证/网络错误由同批的载入请求抛出,不会被吞掉。
|
|
1967
1998
|
*/
|
|
1968
|
-
const historyListSnapshot =
|
|
1999
|
+
const historyListSnapshot = getHistory
|
|
2000
|
+
? fetchHistoryListSnapshot(env, { workflowId }).catch(() => null)
|
|
2001
|
+
: Promise.resolve(null);
|
|
1969
2002
|
/**
|
|
1970
2003
|
* 明细请求紧跟着**列表**走(2026-10-29 用户口径):它的入参只有 `requestId`(列表给的)与会话
|
|
1971
2004
|
* `userId`,与 `getFormLayout` **没有任何参数依赖**;原先排在 layout 之后纯属写法问题,白等约
|
|
@@ -1976,7 +2009,9 @@ async function buildCreateFormData(workflowId, env) {
|
|
|
1976
2009
|
* 空处理免得留下未处理的拒绝。真正的认证/网络错误仍由 `buildHistoryRequestData` 里那次 `await`
|
|
1977
2010
|
* 决定去留(口径不变)。
|
|
1978
2011
|
*/
|
|
1979
|
-
const historyDetails =
|
|
2012
|
+
const historyDetails = getHistory
|
|
2013
|
+
? historyListSnapshot.then(async (snapshot) => (snapshot && snapshot.requestIds.length ? prefetchHistoryDetails(env, snapshot) : null))
|
|
2014
|
+
: Promise.resolve(null);
|
|
1980
2015
|
historyDetails.catch(() => { });
|
|
1981
2016
|
// 2026-09-22:这四个接口**彼此没有数据依赖**(入参只需要 workflowId,见各自的 query/body),
|
|
1982
2017
|
// 真机实测各 171–429 ms、串行合计约 1.1 s;并行后只受最慢的一个约束。
|
|
@@ -2254,12 +2289,20 @@ async function buildCreateFormData(workflowId, env) {
|
|
|
2254
2289
|
// 不在当前布局上的字段不下发——模型既填不了也看不到。
|
|
2255
2290
|
if (!modelFieldIds.has(String(field.id ?? '')))
|
|
2256
2291
|
continue;
|
|
2257
|
-
//
|
|
2258
|
-
//
|
|
2292
|
+
// 明细标记**按命令分档**(2026-10-30 用户裁定:改成 isDetail 只对 `createRequestDirect` 生效):
|
|
2293
|
+
// - `createRequestDirect`:键序 `id|name|isDetail|componentKey`,明细字段带 `isDetail: true`,
|
|
2294
|
+
// 主表字段**整个省略**该键(缺键=主表;恒写 `isDetail:false` 白占体积),且**不下发** `subFormId`;
|
|
2295
|
+
// - `createForm`(默认档):维持原口径,明细字段带 `subFormId`(它就是 `data.details` 的键),
|
|
2296
|
+
// 主表字段省略该键。
|
|
2259
2297
|
const slimSubFormId = String(field.subFormId ?? '');
|
|
2260
2298
|
const item = { id: field.id, name: field.name };
|
|
2261
|
-
if (
|
|
2299
|
+
if (detailMark === 'isDetail') {
|
|
2300
|
+
if (slimSubFormId)
|
|
2301
|
+
item.isDetail = true;
|
|
2302
|
+
}
|
|
2303
|
+
else if (slimSubFormId) {
|
|
2262
2304
|
item.subFormId = slimSubFormId;
|
|
2305
|
+
}
|
|
2263
2306
|
item.componentKey = field.componentKey;
|
|
2264
2307
|
// 表单初始化时就有的值(OA 预填 + onLoadForm 联动带出)——有才出现该键;**没有默认值的字段不带**。
|
|
2265
2308
|
// CLI 拼 `data` 时会自动并入,模型**不必显式传**;用户本次明确改写了它才按用户说的覆盖(见
|
|
@@ -2335,7 +2378,7 @@ async function buildCreateFormData(workflowId, env) {
|
|
|
2335
2378
|
...requiredFieldsList.map((f) => String(f?.id ?? '')),
|
|
2336
2379
|
...Object.values(subFormRequired).flatMap((list) => list.map((f) => String(f?.id ?? ''))),
|
|
2337
2380
|
].filter(Boolean))];
|
|
2338
|
-
const historyCache = fields.length
|
|
2381
|
+
const historyCache = getHistory && fields.length
|
|
2339
2382
|
? await buildHistoryRequestData(env, fields, historyRequiredFieldIds.map((id) => ({ id, name: String((fieldsById.get(id) || {}).name ?? id) })), { allFormFields: true, workflowId },
|
|
2340
2383
|
// 本命令开头就已并发发起的列表请求:这里只补「详情」那几步(P2)。
|
|
2341
2384
|
historyListSnapshot,
|
|
@@ -2407,7 +2450,9 @@ async function buildCreateFormData(workflowId, env) {
|
|
|
2407
2450
|
// 历史参考值(近一年、非草稿、最近 5 条「我发起的」)——填值前先看它,能直接照用的字段就别去
|
|
2408
2451
|
// 问用户。字段范围与 `fields` **同一口径**(见 modelFieldIds 注释);完整结果(本表单全部字段)
|
|
2409
2452
|
// 仍随句柄留给 `createRequest` 用(条件必填要到那边才现身)。
|
|
2410
|
-
|
|
2453
|
+
// `getHistory:false`(隐藏入参)时整段历史取数没做 ⇒ 这里给 `null`(不是空数组:空数组表示
|
|
2454
|
+
// "查了但没数据",两者含义不同)。
|
|
2455
|
+
historyRequestData: getHistory ? filterHistoryRequestData(historyCache, modelFieldIds) : null,
|
|
2411
2456
|
systemFields: {
|
|
2412
2457
|
permissions: minorInfo.permissions || {},
|
|
2413
2458
|
defaults: context.systemFields.defaults,
|
|
@@ -3821,9 +3866,11 @@ async function runFieldLinkage(env, ctx, entries, actionTypes, allDetails, isEdi
|
|
|
3821
3866
|
}
|
|
3822
3867
|
if (!dataList.length && !runDataList.length)
|
|
3823
3868
|
return [];
|
|
3869
|
+
// 建模表单的联动接口 `module` 是 `ebuilderform`(与布局 / 保存的 `ebuildercard` 不同,真机请求体实证)。
|
|
3870
|
+
const linkageModule = formModuleName(ctx.frame && ctx.frame.relate_type, 'ebuilderform');
|
|
3824
3871
|
const executeParam = {
|
|
3825
3872
|
formId: ctx.layout.form_id,
|
|
3826
|
-
module:
|
|
3873
|
+
module: linkageModule,
|
|
3827
3874
|
dataList,
|
|
3828
3875
|
runDataList,
|
|
3829
3876
|
moduleDataList: [],
|
|
@@ -3867,9 +3914,10 @@ async function runFieldLinkage(env, ctx, entries, actionTypes, allDetails, isEdi
|
|
|
3867
3914
|
if (frame.layout_multi_id)
|
|
3868
3915
|
executeParam.layoutId = frame.layout_multi_id;
|
|
3869
3916
|
}
|
|
3870
|
-
const payload = { formId: ctx.layout.form_id, module:
|
|
3917
|
+
const payload = { formId: ctx.layout.form_id, module: linkageModule, executeParam };
|
|
3871
3918
|
const relateType = (ctx.frame && ctx.frame.relate_type) || '';
|
|
3872
|
-
|
|
3919
|
+
// 建模表单的联动接口在 `/api/ebuilder/form/` 下,与布局 / 保存的 `/api/ebuilder/flow/` 不同(真机实证)。
|
|
3920
|
+
const endpoint = formApiUrl(FORM_ENDPOINTS.fdLinkage, relateType, '/api/ebuilder/form/');
|
|
3873
3921
|
const response = await requestJson(env, 'POST', endpoint, AJAX_QUERY, payload);
|
|
3874
3922
|
// requestJson 内部已解包一层(responseData),此处不可再取 .data
|
|
3875
3923
|
const data = (response && typeof response === 'object') ? response : null;
|
|
@@ -4646,6 +4694,8 @@ function linkageResultNotice(linkageDetails, fields, hiddenSubforms, rowHidden,
|
|
|
4646
4694
|
* 的就是与普通链路同一段代码),它们不是必填判定。
|
|
4647
4695
|
* - 句柄**不消费**:本分支在任何写请求之前返回,同一个 `context` 之后仍可正常重发。
|
|
4648
4696
|
* - `title` 取**工作流名称**;`src` 与两处 `routerProps_*` 的 `initialEntries` 用**工作流 id**;
|
|
4697
|
+
* `src` 末尾另按 `&<字段id>=<值>` 拼上本次要填的字段(2026-10-30 用户裁定,与下面
|
|
4698
|
+
* `params.customParams` 同一份数据);
|
|
4649
4699
|
* `params.customParams` 取 `createRequest` **入参**经解析后的字段值(不含表单默认值、不含联动带出的值),
|
|
4650
4700
|
* 同段 `fieldAssignKeys` 列出这次要填的**全部字段 id**(`,` 连接)。
|
|
4651
4701
|
*/
|
|
@@ -4798,10 +4848,31 @@ function xiaoECustomParams(preview) {
|
|
|
4798
4848
|
}
|
|
4799
4849
|
return { values, keys: ordered };
|
|
4800
4850
|
}
|
|
4851
|
+
/**
|
|
4852
|
+
* `src` 末尾的字段参数(2026-10-30 用户裁定):`&<字段id>=<值>`,与 `params.customParams` 里那份
|
|
4853
|
+
* 字段值**同一份数据、同一顺序**(`fieldAssignKeys` 是元信息,不进 URL)。
|
|
4854
|
+
*
|
|
4855
|
+
* 值**原样拼、不做任何百分号编码**:客户端自己解析这段 query(按 `&` 切键值对、再按 `=` 切第一个
|
|
4856
|
+
* 等号),中文、空格、`,` / `;` / `#` 等都不需要转义,拼出来的字面值必须与 `params.customParams`
|
|
4857
|
+
* 里逐字相同。唯一代价是值本身含 `&` 时会截断——按用户口径以此为准,不在此处兜底改写。
|
|
4858
|
+
*/
|
|
4859
|
+
function xiaoESrcFieldQuery(params) {
|
|
4860
|
+
let query = '';
|
|
4861
|
+
for (const fieldId of params.keys) {
|
|
4862
|
+
const text = params.values[fieldId];
|
|
4863
|
+
if (!text)
|
|
4864
|
+
continue;
|
|
4865
|
+
query += `&${fieldId}=${text}`;
|
|
4866
|
+
}
|
|
4867
|
+
return query;
|
|
4868
|
+
}
|
|
4801
4869
|
/**
|
|
4802
4870
|
* 渲染 `<browsertool>` 块(该块**整体**就是小e 环境下 `createRequest` 的 `finalMarkdown`)。
|
|
4803
4871
|
*
|
|
4804
4872
|
* 除 `title` / `src` / 两处 `routerProps_*` 的 `initialEntries` / `params.customParams` 外全部写死。
|
|
4873
|
+
*
|
|
4874
|
+
* `src` 形如 `…/flowpage/create/<workflowId>?workflowId=<workflowId>&isCreate=1&<字段id>=<值>&…`
|
|
4875
|
+
* —— 末尾的字段参数与 `params.customParams` 同源(2026-10-30 用户裁定)。
|
|
4805
4876
|
*/
|
|
4806
4877
|
function renderXiaoEFillFormMarkdown(params) {
|
|
4807
4878
|
const base = String(params.baseUrl ?? '').replace(/\/+$/u, '');
|
|
@@ -4814,7 +4885,7 @@ function renderXiaoEFillFormMarkdown(params) {
|
|
|
4814
4885
|
arguments: {
|
|
4815
4886
|
type: 'e10',
|
|
4816
4887
|
title: String(params.title ?? ''),
|
|
4817
|
-
src: `${base}/sp/workflow${createPath}?workflowId=${workflowId}&isCreate=1`,
|
|
4888
|
+
src: `${base}/sp/workflow${createPath}?workflowId=${workflowId}&isCreate=1${xiaoESrcFieldQuery(params.customParams)}`,
|
|
4818
4889
|
sdkOptions: {
|
|
4819
4890
|
compName: XIAOE_FILL_FORM_SDK_OPTIONS.compName,
|
|
4820
4891
|
routerType: XIAOE_FILL_FORM_SDK_OPTIONS.routerType,
|
|
@@ -4840,7 +4911,8 @@ function renderXiaoEFillFormMarkdown(params) {
|
|
|
4840
4911
|
* - `durationMs` = 命令入口 → 结果产出;
|
|
4841
4912
|
* - `apiDurations` = 每个接口(并行批次合成一个 key,取墙钟、不叠加);
|
|
4842
4913
|
* - `apiSlowest` = 每个**真并行**批里谁最慢(`[{ batch, name, ms, items }]`,`ms` 是该接口自身耗时,
|
|
4843
|
-
* `items` 是批内每个成员的 `{ name, at, ms }`,按 `ms`
|
|
4914
|
+
* `items` 是批内每个成员的 `{ name, at, ms, fetchAt, fetchEnd, fetchCost }`,按 `ms` 降序;
|
|
4915
|
+
* `fetchAt`/`fetchEnd`/`fetchCost` 描述其中纯 fetch 那一段);
|
|
4844
4916
|
* - `authMs` = 登录取凭据(首次会话解析)的墙钟 —— 这一段走 auth 层自己的 fetch、不经
|
|
4845
4917
|
* `host.workflowRequest`,`apiDurations` 统计不到,单独给一个数才能对上账。
|
|
4846
4918
|
*
|
|
@@ -5469,15 +5541,27 @@ function apiShortName(path) {
|
|
|
5469
5541
|
* 给 host 套一层**逐接口计时**(只包请求,不改返回、不吞异常)。
|
|
5470
5542
|
*
|
|
5471
5543
|
* `finally` 里落片段:请求失败(超时 / 业务错误 / 抛错)同样要记 —— 恰恰是这类请求最需要看到耗时。
|
|
5544
|
+
*
|
|
5545
|
+
* 片段里除整段耗时外,还记**纯 fetch** 那一段(`fetchMs`,2026-10-30 用户要求):它由
|
|
5546
|
+
* `runWithFetchTiming` 开一个旁路 sink、`E10RequestRuntime` 在 fetch 前后各打一枪得到,
|
|
5547
|
+
* 两条链路都只读不改请求/返回值。
|
|
5472
5548
|
*/
|
|
5473
5549
|
function withApiTiming(host, spans) {
|
|
5474
5550
|
const record = async (path, run) => {
|
|
5475
5551
|
const start = Date.now();
|
|
5552
|
+
const fetchTiming = createFetchTimingSink();
|
|
5476
5553
|
try {
|
|
5477
|
-
return await run
|
|
5554
|
+
return await runWithFetchTiming(fetchTiming, run);
|
|
5478
5555
|
}
|
|
5479
5556
|
finally {
|
|
5480
|
-
spans.push({
|
|
5557
|
+
spans.push({
|
|
5558
|
+
name: apiShortName(path),
|
|
5559
|
+
start,
|
|
5560
|
+
end: Date.now(),
|
|
5561
|
+
fetchStart: fetchTiming.fetchStart,
|
|
5562
|
+
fetchEnd: fetchTiming.fetchEnd,
|
|
5563
|
+
fetchMs: fetchTiming.fetchMs,
|
|
5564
|
+
});
|
|
5481
5565
|
}
|
|
5482
5566
|
};
|
|
5483
5567
|
return {
|
|
@@ -5506,7 +5590,9 @@ function withApiTiming(host, spans) {
|
|
|
5506
5590
|
* - 批内**全是同一个接口**时也不产(如 5 个并发的 `getWorkflowRequest` 取历史详情):请求都一样,
|
|
5507
5591
|
* "谁最慢"没有区分意义,只有批的墙钟有用(2026-10-22 用户第二轮裁定);
|
|
5508
5592
|
* - `ms` 取该接口**自身**耗时(`end - start`),不是批墙钟;
|
|
5509
|
-
* - 每条另带 `items`:批内**每个**成员的 `{name, at, ms}`(`at`
|
|
5593
|
+
* - 每条另带 `items`:批内**每个**成员的 `{name, at, ms, fetchAt, fetchEnd, fetchCost}`(`at` 相对批
|
|
5594
|
+
* 起点;`ms` 自身耗时;`fetchAt`/`fetchEnd` 是其中**纯 fetch**(发出请求 → 收到响应头)的起止偏移、
|
|
5595
|
+
* `fetchCost` 是它的耗时,2026-10-30 用户要求),按 `ms` 降序。
|
|
5510
5596
|
* 2026-10-26 用户要求:只看最慢项判断不出「优化它值不值」——若批内多个接口耗时接近,
|
|
5511
5597
|
* 砍掉最慢那个的收益有限,得看整条关键路径的分布;
|
|
5512
5598
|
* - 顺序=批的时间顺序,与 `apiDurations` 的 key 一一对应。
|
|
@@ -5541,13 +5627,17 @@ function summarizeApiSpans(spans) {
|
|
|
5541
5627
|
// 批内全是同一个接口 ⇒ 不产最慢项("5 个 getWorkflowRequest 里谁最慢"没有区分意义)。
|
|
5542
5628
|
if (group.length > 1 && new Set(names).size > 1) {
|
|
5543
5629
|
const origin = Math.min(...group.map((item) => item.start));
|
|
5544
|
-
// 批内逐个成员都留一条(`at` 相对批起点,`ms`
|
|
5545
|
-
//
|
|
5630
|
+
// 批内逐个成员都留一条(`at` 相对批起点,`ms` 自身耗时;`fetchAt`/`fetchEnd` 是其中纯 fetch
|
|
5631
|
+
// 的起止偏移、`fetchCost` 是它自身的耗时),按耗时降序;并列取先开始的(`at` 升序),
|
|
5632
|
+
// 保证同一份输入每次输出一致。`name`/`ms` 就取这一项。
|
|
5546
5633
|
const items = group
|
|
5547
5634
|
.map((item) => ({
|
|
5548
5635
|
name: item.name,
|
|
5549
5636
|
at: Math.max(0, Math.round(item.start - origin)),
|
|
5550
5637
|
ms: Math.max(0, Math.round(item.end - item.start)),
|
|
5638
|
+
fetchAt: item.fetchStart === null ? null : Math.max(0, Math.round(item.fetchStart - origin)),
|
|
5639
|
+
fetchEnd: item.fetchEnd === null ? null : Math.max(0, Math.round(item.fetchEnd - origin)),
|
|
5640
|
+
fetchCost: Math.max(0, Math.round(item.fetchMs)),
|
|
5551
5641
|
}))
|
|
5552
5642
|
.sort((a, b) => (b.ms - a.ms) || (a.at - b.at));
|
|
5553
5643
|
slowest.push({ batch: key, name: items[0].name, ms: items[0].ms, items });
|
|
@@ -5555,6 +5645,26 @@ function summarizeApiSpans(spans) {
|
|
|
5555
5645
|
}
|
|
5556
5646
|
return { durations, slowest };
|
|
5557
5647
|
}
|
|
5648
|
+
/**
|
|
5649
|
+
* `createRequestDirect` 的**隐藏入参** `getHistory` 取值(2026-10-30 用户裁定)。
|
|
5650
|
+
*
|
|
5651
|
+
* 只在 CLI 实现层支持:**不写进** `inputSchema`、不写进 skill 文档,模型侧看不到、也没法从
|
|
5652
|
+
* `workflow schema` 里读到;需要时由调用方(桌面端 / 脚本)自己塞进 `--input-json`。
|
|
5653
|
+
*
|
|
5654
|
+
* 口径:缺省、`null`、`undefined`、空串、其它非 `false` 的真值 ⇒ `true`(与从前的行为完全一致);
|
|
5655
|
+
* 只有明确表达"不要"的写法才关掉:`false` / `0` / `"false"` / `"0"`(大小写、首尾空格都不敏感)。
|
|
5656
|
+
* 宽松接受字符串是为了调用方从环境变量或配置里透传时不必先转类型。
|
|
5657
|
+
*/
|
|
5658
|
+
function readHiddenGetHistory(value) {
|
|
5659
|
+
if (value === false || value === 0)
|
|
5660
|
+
return false;
|
|
5661
|
+
if (typeof value === 'string') {
|
|
5662
|
+
const text = value.trim().toLowerCase();
|
|
5663
|
+
if (text === 'false' || text === '0')
|
|
5664
|
+
return false;
|
|
5665
|
+
}
|
|
5666
|
+
return true;
|
|
5667
|
+
}
|
|
5558
5668
|
/**
|
|
5559
5669
|
* `workflow.createRequestDirect` —— **取数命令**(2026-10-22 用户裁定,语义已变)。
|
|
5560
5670
|
*
|
|
@@ -5576,6 +5686,10 @@ function summarizeApiSpans(spans) {
|
|
|
5576
5686
|
* 5. **输出降级**(按 20,000 **字符**,与 `createForm` 同一个宿主口径):
|
|
5577
5687
|
* 全量超线 ⇒ `historyRequestData` 留空数组(键还在);仍超 ⇒ `userMemory` 留空串(键还在;小e 档没有
|
|
5578
5688
|
* 这个键,不补);**`fields` 自己也超线时不再裁**(宁大不丢)—— 它是唯一不可省的,砍了这条命令就没有意义。
|
|
5689
|
+
* 6. **隐藏入参 `getHistory`**(2026-10-30 用户裁定):只在实现层支持,**不进 schema、不进 skill**。
|
|
5690
|
+
* 不传 = `true`(原行为);传 `false` 时整段「历史发起流程」取数(`getMineListData` 列表 + 明细)
|
|
5691
|
+
* 一次都不发,输出里 `historyRequestData` 直接是 `null`(不是空数组——空数组的意思是"查了但没数据")。
|
|
5692
|
+
* 这一档也不参与上面的输出降级。
|
|
5579
5693
|
*
|
|
5580
5694
|
* ## 耗时
|
|
5581
5695
|
* 与 `createForm` 完全同口径,全部收在 `timing` 一个桶里:`durationMs`(整条命令)/
|
|
@@ -5588,9 +5702,15 @@ async function commandCreateRequestDirect(args, env) {
|
|
|
5588
5702
|
// 计时从**命令入口**开始算(含会话解析、工作流消歧、表单载入)。
|
|
5589
5703
|
const spans = [];
|
|
5590
5704
|
const timedEnv = { ...env, host: withApiTiming(env.host, spans) };
|
|
5705
|
+
// 隐藏入参(不进 schema / skill):`false` 时不跑「历史发起流程」那段取数。
|
|
5706
|
+
const getHistory = readHiddenGetHistory(args.getHistory);
|
|
5591
5707
|
// 取数段本身已经不碰 `chatScene`(`createForm` 自 2026-10-23 起不再接 `userQuestion`),
|
|
5592
|
-
//
|
|
5593
|
-
|
|
5708
|
+
// 这里不必再置空任何入参。`detailMark` 也是**本命令独有**:明细字段标 `isDetail: true`、
|
|
5709
|
+
// 不再下发 `subFormId`(`createForm` 仍走老口径,见 `buildCreateFormData`)。
|
|
5710
|
+
const { payload, authMs } = await prepareCreateFormPayload(args, timedEnv, {
|
|
5711
|
+
getHistory,
|
|
5712
|
+
detailMark: 'isDetail',
|
|
5713
|
+
});
|
|
5594
5714
|
const contextId = String(payload.contextId ?? '');
|
|
5595
5715
|
if (!contextId) {
|
|
5596
5716
|
// `prepareCreateFormPayload` 正常返回时 contextId 必然存在;这里只用来判断
|
|
@@ -5625,8 +5745,10 @@ async function commandCreateRequestDirect(args, env) {
|
|
|
5625
5745
|
const overLine = () => finalStdoutChars({ ...data, ...reserve }, 'workflow.createRequestDirect') > CREATE_FORM_STDOUT_SAFE_CHARS;
|
|
5626
5746
|
// 两级降级:先砍历史(留空 key)→ 再砍记忆(留空 key)。`fields` 不参与裁剪。
|
|
5627
5747
|
// 小e 档没有 `userMemory` 这个键,第二级跳过(不能借"写空串"把它重新加回来)。
|
|
5748
|
+
// `getHistory:false` 时历史那一档本来就没查(值是 `null`)⇒ 不参与降级,否则会把"没查"说成"查了没数据"。
|
|
5628
5749
|
if (overLine()) {
|
|
5629
|
-
|
|
5750
|
+
if (getHistory)
|
|
5751
|
+
data.historyRequestData = [];
|
|
5630
5752
|
if ('userMemory' in data && overLine())
|
|
5631
5753
|
data.userMemory = '';
|
|
5632
5754
|
}
|
|
@@ -5649,10 +5771,30 @@ function formatRemark(value) {
|
|
|
5649
5771
|
return text;
|
|
5650
5772
|
return `_weaverMte_<p>${text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')}</p>`;
|
|
5651
5773
|
}
|
|
5774
|
+
/**
|
|
5775
|
+
* 表单所属模块名:建模表单(`relateType=WEA_EBUILDER`)按接口取自己的 service 名,其余是 `workflow`。
|
|
5776
|
+
*
|
|
5777
|
+
* 服务端按请求体里的 `module` 解析 `@Service("<module>_FormCoreService")`:建模表单传 `workflow`
|
|
5778
|
+
* 会直接 500「未找到名为 FormCoreService 的实例对象」(2026-10-29 e-cology 建模流程实测:只把该值
|
|
5779
|
+
* 改成 `ebuildercard` 即 200)。所以凡是请求体带 `module` 的表单接口(布局 / 附件 / 保存 / 联动)
|
|
5780
|
+
* 都必须按表单类型取值,不能硬编码。
|
|
5781
|
+
*
|
|
5782
|
+
* ⚠️ 建模表单内部**不是同一个值**,必须按接口分别给(均为真机请求体实证):
|
|
5783
|
+
* - `getFormLayout` / `saveFormData` / 附件上传 → `ebuildercard`
|
|
5784
|
+
* - `executeFdLinkage` / `getFormDataAndLayout` → `ebuilderform`
|
|
5785
|
+
*
|
|
5786
|
+
* 注意这两个值**不按目录/同族划分**:`getFormDataAndLayout` 与 `getFormLayout` 同在 `form/core` 下,
|
|
5787
|
+
* 前者是 `ebuilderform`、后者是 `ebuildercard`。所以只能按接口真机样例取值,不能靠推断。
|
|
5788
|
+
*/
|
|
5789
|
+
function formModuleName(relateType, ebModule = 'ebuildercard') {
|
|
5790
|
+
return String(relateType ?? '').trim() === 'WEA_EBUILDER' ? ebModule : 'workflow';
|
|
5791
|
+
}
|
|
5652
5792
|
function buildSaveBody(context, prepared) {
|
|
5653
5793
|
const runtime = context.runtime;
|
|
5794
|
+
// 顶层 `module` 与 `formData.module` 是同一条判据:建模表单的 saveFormData 也走 ebuilder 的服务。
|
|
5795
|
+
const moduleName = formModuleName(context.frame?.relate_type);
|
|
5654
5796
|
return {
|
|
5655
|
-
module:
|
|
5797
|
+
module: moduleName,
|
|
5656
5798
|
customParam: {
|
|
5657
5799
|
isCreate: true,
|
|
5658
5800
|
requestId: runtime.request_id,
|
|
@@ -5670,7 +5812,7 @@ function buildSaveBody(context, prepared) {
|
|
|
5670
5812
|
},
|
|
5671
5813
|
employeeId: runtime.employee_id,
|
|
5672
5814
|
formData: {
|
|
5673
|
-
module:
|
|
5815
|
+
module: moduleName,
|
|
5674
5816
|
presetDataId: runtime.request_id,
|
|
5675
5817
|
dataDetails: prepared.dataDetails,
|
|
5676
5818
|
client: 'pc',
|
|
@@ -6171,12 +6313,15 @@ async function runCreateNodeFieldVerification(env, context, switches) {
|
|
|
6171
6313
|
// ---------------------------------------------------------------------------
|
|
6172
6314
|
// editLoad / editPrepare / editSave
|
|
6173
6315
|
// ---------------------------------------------------------------------------
|
|
6174
|
-
function buildEditDataLayoutRequest(requestId, workflowId, nodeId, formId, dataId, layoutMultiId, viewFormNodeId, permissionType, runtime) {
|
|
6316
|
+
function buildEditDataLayoutRequest(requestId, workflowId, nodeId, formId, dataId, layoutMultiId, viewFormNodeId, permissionType, runtime, relateType) {
|
|
6175
6317
|
return {
|
|
6176
6318
|
terminalType: 'PC',
|
|
6177
6319
|
dataId,
|
|
6178
6320
|
formId,
|
|
6179
|
-
|
|
6321
|
+
// 建模表单取 `ebuilderform`(2026-10-30 真机请求体实证),**不是** `ebuildercard`:
|
|
6322
|
+
// 同为 `form/core` 下的接口,`getFormLayout` / `saveFormData` 是 `ebuildercard`,
|
|
6323
|
+
// 本接口与 `executeFdLinkage` 是 `ebuilderform` —— 建模表单内部不能按"同族"推定。
|
|
6324
|
+
module: formModuleName(relateType, 'ebuilderform'),
|
|
6180
6325
|
newLayout: true,
|
|
6181
6326
|
cacheUid: null,
|
|
6182
6327
|
layoutMultiId,
|
|
@@ -6250,7 +6395,7 @@ async function commandEditLoad(args, env) {
|
|
|
6250
6395
|
tenantSetting = {};
|
|
6251
6396
|
}
|
|
6252
6397
|
const dataId = requestId;
|
|
6253
|
-
const dlResp = await requestJson(env, 'POST', formApiUrl(FORM_ENDPOINTS.formDataAndLayout, frame.relate_type), { formId: frame.form_id, dataId, ...AJAX_QUERY }, buildEditDataLayoutRequest(requestId, workflowId, runtime.node_id, frame.form_id, dataId, frame.layout_multi_id, frame.view_form_node_id, frame.permission_type, runtime));
|
|
6398
|
+
const dlResp = await requestJson(env, 'POST', formApiUrl(FORM_ENDPOINTS.formDataAndLayout, frame.relate_type), { formId: frame.form_id, dataId, ...AJAX_QUERY }, buildEditDataLayoutRequest(requestId, workflowId, runtime.node_id, frame.form_id, dataId, frame.layout_multi_id, frame.view_form_node_id, frame.permission_type, runtime, frame.relate_type));
|
|
6254
6399
|
const dlData = dlResp;
|
|
6255
6400
|
if (!dlData || typeof dlData !== 'object')
|
|
6256
6401
|
throw workflowApiError('format_error', 'getFormDataAndLayout 未返回有效 data');
|
|
@@ -6558,8 +6703,10 @@ async function commandEditPrepare(args, env) {
|
|
|
6558
6703
|
}
|
|
6559
6704
|
function buildEditSaveBody(context, prepared) {
|
|
6560
6705
|
const runtime = context.runtime || {};
|
|
6706
|
+
// 同 `buildSaveBody`:改已有表单时也按表单类型取 module,建模表单要 `ebuildercard`。
|
|
6707
|
+
const moduleName = formModuleName(context.frame?.relate_type);
|
|
6561
6708
|
return {
|
|
6562
|
-
module:
|
|
6709
|
+
module: moduleName,
|
|
6563
6710
|
customParam: {
|
|
6564
6711
|
isCreate: false,
|
|
6565
6712
|
requestId: context.requestId ?? context.request_id,
|
|
@@ -6579,7 +6726,7 @@ function buildEditSaveBody(context, prepared) {
|
|
|
6579
6726
|
formData: {
|
|
6580
6727
|
id: context.data_id,
|
|
6581
6728
|
updateTimeStamp: context.update_time_stamp || '',
|
|
6582
|
-
module:
|
|
6729
|
+
module: moduleName,
|
|
6583
6730
|
dataDelRows: [],
|
|
6584
6731
|
dataDetails: prepared.dataDetails || [],
|
|
6585
6732
|
client: 'pc',
|
|
@@ -59,6 +59,12 @@ function clarificationEnvelope(error, operation) {
|
|
|
59
59
|
? details.clarificationQuestion
|
|
60
60
|
: error.message;
|
|
61
61
|
const reason = typeof details.clarificationReason === 'string' ? details.clarificationReason : '';
|
|
62
|
+
// 必填入参缺失(当前只有 `workflow_required` 一档)时,把「缺了哪个键、该按什么形态补」一并下发:
|
|
63
|
+
// 模型原先只能看到「请提供完整名称」,无法区分「用户没说要发起什么」与「我键名写错了」。
|
|
64
|
+
const missingInput = Array.isArray(details.missingInput) ? details.missingInput.map(String) : [];
|
|
65
|
+
const requiredInput = details.requiredInput && typeof details.requiredInput === 'object'
|
|
66
|
+
? details.requiredInput
|
|
67
|
+
: null;
|
|
62
68
|
return workflowSuccess(operation, {
|
|
63
69
|
type: 'workflowClarification',
|
|
64
70
|
status: 'NEEDS_CLARIFICATION',
|
|
@@ -66,6 +72,8 @@ function clarificationEnvelope(error, operation) {
|
|
|
66
72
|
clarificationKeyword: details.clarificationKeyword ?? null,
|
|
67
73
|
clarificationQuestion: question,
|
|
68
74
|
...(reason ? { clarificationReason: reason } : {}),
|
|
75
|
+
...(missingInput.length ? { missingInput } : {}),
|
|
76
|
+
...(missingInput.length && requiredInput ? { requiredInput } : {}),
|
|
69
77
|
candidates,
|
|
70
78
|
candidateCount: candidates.length,
|
|
71
79
|
note: clarificationNote(reason, candidates.length),
|
|
@@ -80,10 +88,24 @@ function clarificationEnvelope(error, operation) {
|
|
|
80
88
|
* - `no_create_right` —— 流程**存在**但当前账号没有发起权限,**绝不能**说成"不存在"
|
|
81
89
|
* (那正是把"没权限"伪装成"没有这条流程",与项目纪律相反)。
|
|
82
90
|
*
|
|
83
|
-
*
|
|
91
|
+
* 2026-10-30 新增一档:
|
|
92
|
+
* - `workflow_required` —— **必填入参没给**(缺键/空数组/空字符串)。它不是「名称匹配不到」,
|
|
93
|
+
* 而是调用方少传了入参;文案必须让模型先认账、再问用户要流程名,而不是让用户去"核对名称"。
|
|
94
|
+
*
|
|
95
|
+
* 无 `reason` 时(名称解析 0 / 多命中 / 只给了填充词)保持原文案不变。
|
|
84
96
|
*/
|
|
85
97
|
function clarificationNote(reason, candidateCount) {
|
|
86
98
|
const base = '这不是失败,也**不代表查询已执行**:本次查询已停止,没有返回任何流程数据。';
|
|
99
|
+
// ★ 2026-10-30:`workflow_required` = **必填入参没给**,与「名称匹配不到」性质完全不同。
|
|
100
|
+
// 这里要模型先认账(少传了入参),而不是去问用户「是不是名字打错了」。
|
|
101
|
+
if (reason === 'workflow_required') {
|
|
102
|
+
return '本次命令**没有拿到必填入参 `workflow`**(没写这个键、空数组、空字符串都算没给)——'
|
|
103
|
+
+ '命令停在了查询之前:**没有发起任何流程**,也没有去查可发起列表,'
|
|
104
|
+
+ '这既不是执行失败,也不代表「没有匹配的流程」。'
|
|
105
|
+
+ '请先向用户确认要发起哪个流程(**必须问,不要自己猜,也不要拿相似的名字代替**),'
|
|
106
|
+
+ '再按 `requiredInput.workflow` 给出的形态把入参补上、重发同一条命令。'
|
|
107
|
+
+ '注意 `--input` 接收的是**文件路径**(`-` 表示标准输入),内联 JSON 要用 `--input-json`。';
|
|
108
|
+
}
|
|
87
109
|
if (reason === 'workflow_not_exist') {
|
|
88
110
|
return base + '请如实告知用户:该工作流不存在(可能已删除或被停用),'
|
|
89
111
|
+ '请用户改用该流程的完整名称(或其它可用于检索的关键词)重新指定——**不要向用户索取 ID**。'
|
package/docs/ehr.md
CHANGED
|
@@ -56,7 +56,7 @@ weaver-work-cli --json ehr run <operation> --input -
|
|
|
56
56
|
|
|
57
57
|
CLI 原样透传整个响应对象,不做重命名;取用方按上表判断。
|
|
58
58
|
|
|
59
|
-
**每页条数**:由服务端按接口独立配置,**`pageSize` 传参无效**(实测):通讯录 100、出勤表格类 20、`worktime`/`leave.report` 10、hr 报表 20、薪酬 `bill.list
|
|
59
|
+
**每页条数**:由服务端按接口独立配置,**`pageSize` 传参无效**(实测):通讯录 100、出勤表格类 20、`worktime`/`leave.report` 10、hr 报表 20、薪酬 `bill.list` 20、`empchange.list` 100。全量数据一律递增 `current` 翻页。
|
|
60
60
|
|
|
61
61
|
**成功响应的 `data` 恒存在**:业务数据为 `undefined` 时(如社保福利、调薪记录为空)统一补为 `null`,避免 `JSON.stringify` 省略该键导致调用方需判断键是否存在。
|
|
62
62
|
|
package/docs/fna.md
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
| `fna.expense.reimbursed.sum` | read | POST `expense/center/getSumReimbursedAmountByAi`;body 可空 |
|
|
22
22
|
| `fna.expense.loan.sum` | read | POST `expense/center/getSumLoanAmountByAi`;只认数字 ID;空 data 自动重试 2 次;已知仅统计首条记录缺陷 |
|
|
23
23
|
| `fna.expense.prepay.writeoff.sum` | read | POST `expense/center/selectPrepayWriteOffAmountBySkill`;body 可空 |
|
|
24
|
-
| `fna.expense.chart` | read | GET `getExpenseChart`(`/api/secondev/fna/`);`userInput` 必填 ≤500 字;`maxRows` 本地截断 1-5000,默认 200;超时 180s;返回 `kind=rows/empty/clarify/blocked/unexpected` |
|
|
24
|
+
| `fna.expense.chart` | read | GET `getExpenseChart`(`/api/secondev/fna/`);`userInput` 必填 ≤500 字;`maxRows` 本地截断 1-5000,默认 200;超时 180s;返回 `kind=rows/empty/clarify/blocked/unexpected`;无权限文案额外返回 `meta.permissionDenied=true` |
|
|
25
25
|
| `fna.loan.main.page` | read | POST `loanManagementMenu/mainPage` |
|
|
26
26
|
| `fna.loan.main.list` | read | POST `loanManagementMenu/mainPageList`;`current`/`pageSize`/`menuCode`/`permissionSetCode` 必填 |
|
|
27
27
|
| `fna.loan.remind.repay.prepare` | write | 校验 displayData 行并预览,不发送 |
|
|
@@ -65,6 +65,7 @@ weaver-work-cli --json fna run fna.invoice.writeoff.list --input-json '{"current
|
|
|
65
65
|
- `menuCode`/`permissionSetCode` 环境相关,示例值需与环境核对。
|
|
66
66
|
- 超 2^53 的 requestId 无法用 JS 数字精确表达,保留字符串并提示人工核验(真实环境 ID 一般在安全整数内,已按数字发送)。
|
|
67
67
|
- `fna.expense.chart`:`code` 恒为 200,必须按 `data` 类型/`kind` 判成败;追问与安全拦截都是字符串 `data`,`meta.messageKindInferred=true` 表示归类为 CLI 推断。实测真实查询 3.3~66.6s,CLI 超时设 180s,禁止自动重试(每次都会消耗模型额度)。不做当前人强制过滤,结果可能是全租户范围;`userInput` 为商品化输入,个人口径必须改用 `fna.expense.reimbursed.sum`。二开包未安装时该 operation 会 404/500,需与其它 `fna.*` 正常但本 operation 失败区分。
|
|
68
|
+
- `fna.expense.chart` 的权限语义:文案含「权限 / 越权」时 CLI 归类为 `clarify` 并置 `meta.permissionDenied=true`(纯权限提示不带「不明确」关键词也照样识别,避免落进 `unexpected` 被误判)。这是**终止信号**,不是换问法信号:Agent 必须直接告知权限边界,禁止改调 `fna.expense.reimbursed.sum`、`fna.budget.*`、借款 / 核销等接口按部门 / 人员 / 金额拼装同一份报表,也禁止自写 SQL 绕过。
|
|
68
69
|
|
|
69
70
|
## 验证
|
|
70
71
|
|
package/package.json
CHANGED
|
@@ -29,6 +29,24 @@
|
|
|
29
29
|
"紧急程度",
|
|
30
30
|
"参与人"
|
|
31
31
|
],
|
|
32
|
+
"weaver-e10-cowork": [
|
|
33
|
+
"协作",
|
|
34
|
+
"协作区",
|
|
35
|
+
"协作事项",
|
|
36
|
+
"工作协作",
|
|
37
|
+
"讨论",
|
|
38
|
+
"回复讨论",
|
|
39
|
+
"协作参与人",
|
|
40
|
+
"共享权限",
|
|
41
|
+
"申请加入",
|
|
42
|
+
"待我审批",
|
|
43
|
+
"我关注的",
|
|
44
|
+
"我收藏的",
|
|
45
|
+
"我的事项",
|
|
46
|
+
"相关我",
|
|
47
|
+
"结束协作",
|
|
48
|
+
"协作版块"
|
|
49
|
+
],
|
|
32
50
|
"weaver-e10-meeting": [
|
|
33
51
|
"会议",
|
|
34
52
|
"会议室",
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
本业务域用于 E10 协作区(工作协作)。入口 `SKILL.md` 只做路由与执行纪律:CRITICAL 共享前置、命令面、按场景读 reference、写操作 prepare→确认→apply 协议、输出纪律。具体 operation、字段与失败处理拆到 `references/`:
|
|
2
|
+
|
|
3
|
+
- `cowork-read.md`:13 类列表(scope)、搜索条件元数据、计数、详情、讨论记录、参与人、关联资源、投票日志、版块表单、元数据、共享权限列表。
|
|
4
|
+
- `cowork-write.md`:新建/结束协作、隐藏/投票、发布讨论、讨论置顶/删除/审批、成员邀请/重新加入/申请加入、加入申请审批、事项与交流审批台、共享对象增删。
|
|
5
|
+
- `safety-boundaries.md`:未实现能力(浏览选择器、点赞组件、权限单元高级配置、搜索 UI 元数据)、红线、能力边界与可见性。
|
|
6
|
+
|
|
7
|
+
Agent 调优重点:
|
|
8
|
+
|
|
9
|
+
- `weaver-work-cli cowork schema` 是 operation 合约第一信息源,契约外的命令与参数一律禁止。
|
|
10
|
+
- 业务输入不得包含 Cookie、ETEAMSID、Token、UA;认证与请求头由 `weaver-e10-shared` 与 CLI 托管。
|
|
11
|
+
- 列表筛选用「值字段 + 对应 `*Condition`」;`itemStatus` 取 `1` 进行中 / `2` 已结束(`0` 等于全部)。
|
|
12
|
+
- 动作类写操作(审批、删除、置顶、审批台)的 id 必须先由对应列表查询取得,禁止凭示例或猜测提交。
|
|
13
|
+
- 写操作只接受 CLI 生成的 `continuation`,`confirm=true` 必须在用户明确确认后传入;`partial/write_uncertain` 时先核对现状,禁止自动重试。
|
|
14
|
+
- 查询为空如实说明「没有符合条件的协作或无权查看」,不要断言系统里没有,也不要改用相邻接口拼凑。
|