forked from ChaiHao/BPOS-MVP
打扰上限要覆盖「人步 + 人兜底」;发卡失败走声明的失败走向
A7 归档卡在最后一步:调人预算 1/1 触顶,S4 放行卡发不出来, 而引擎每一拍重发一次 —— 六行一模一样的「调用:步 4」,卡永远不出现,也永远不报错。 两处修: ① 发卡被 Harness 拦下(调人预算触顶等)= **这一步失败了**,走它声明的失败走向。 不接住就是无限重发:预算照烧、负责人什么也看不到。 ② 四个 flow 活动的打扰上限只按**人步**算,没算**声明的人兜底**。 声明了 `fallback: human` 就等于承认这一步可能要调人,预算却不给它留位置 —— 兜底一触发,后面的放行卡必然发不出。按「人步 + 人兜底」重算: A1 4 / A4 3 / A6 3 / A7 2。 gates: tsc / eslint / depcruise / 399 测试 全绿 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
This commit is contained in:
@@ -13,7 +13,7 @@ export const manifest: ActivityManifest = {
|
|||||||
identity: {
|
identity: {
|
||||||
activityId: ACTIVITY_ID,
|
activityId: ACTIVITY_ID,
|
||||||
name: 'A7 · 情报归档',
|
name: 'A7 · 情报归档',
|
||||||
packageVersion: '0.1.1',
|
packageVersion: '0.1.2',
|
||||||
category: '统一报价',
|
category: '统一报价',
|
||||||
paradigm: 'flow',
|
paradigm: 'flow',
|
||||||
sdkVersion: '0.1.0-m5',
|
sdkVersion: '0.1.0-m5',
|
||||||
@@ -56,13 +56,13 @@ export const manifest: ActivityManifest = {
|
|||||||
{ key: 'bd-release', label: 'BD 放行', level: 'L5' },
|
{ key: 'bd-release', label: 'BD 放行', level: 'L5' },
|
||||||
],
|
],
|
||||||
prohibitions: [{ key: 'no-blank-archive', statement: '不得空归档 —— 每一单不成交的报价也是情报资产' }],
|
prohibitions: [{ key: 'no-blank-archive', statement: '不得空归档 —— 每一单不成交的报价也是情报资产' }],
|
||||||
authorization: { discretion: [], preauthorizedActions: [], humanCallBudget: 1 },
|
authorization: { discretion: [], preauthorizedActions: [], humanCallBudget: 2 },
|
||||||
resources: {
|
resources: {
|
||||||
tools: [],
|
tools: [],
|
||||||
skills: [],
|
skills: [],
|
||||||
models: ['quote-extractor'],
|
models: ['quote-extractor'],
|
||||||
roles: ['BD'],
|
roles: ['BD'],
|
||||||
budget: { steps: 30, tokens: 60_000, activeMinutes: 60, humanCalls: 1 },
|
budget: { steps: 30, tokens: 60_000, activeMinutes: 60, humanCalls: 2 },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ export const manifest: ActivityManifest = {
|
|||||||
identity: {
|
identity: {
|
||||||
activityId: ACTIVITY_ID,
|
activityId: ACTIVITY_ID,
|
||||||
name: 'A1 · RFQ 需求分析',
|
name: 'A1 · RFQ 需求分析',
|
||||||
packageVersion: '0.1.2',
|
packageVersion: '0.1.3',
|
||||||
category: '统一报价',
|
category: '统一报价',
|
||||||
paradigm: 'flow',
|
paradigm: 'flow',
|
||||||
sdkVersion: '0.1.0-m5',
|
sdkVersion: '0.1.0-m5',
|
||||||
@@ -95,14 +95,14 @@ export const manifest: ActivityManifest = {
|
|||||||
authorization: {
|
authorization: {
|
||||||
discretion: [{ key: 'ask-back', statement: '缺次要字段可受理并追问,缺 PN/数量/交期必须退回补全' }],
|
discretion: [{ key: 'ask-back', statement: '缺次要字段可受理并追问,缺 PN/数量/交期必须退回补全' }],
|
||||||
preauthorizedActions: [],
|
preauthorizedActions: [],
|
||||||
humanCallBudget: 3,
|
humanCallBudget: 4,
|
||||||
},
|
},
|
||||||
resources: {
|
resources: {
|
||||||
tools: [{ name: 'crm.history-price-read' }],
|
tools: [{ name: 'crm.history-price-read' }],
|
||||||
skills: [],
|
skills: [],
|
||||||
models: ['quote-extractor'],
|
models: ['quote-extractor'],
|
||||||
roles: ['BD'],
|
roles: ['BD'],
|
||||||
budget: { steps: 40, tokens: 120_000, activeMinutes: 60, humanCalls: 3 },
|
budget: { steps: 40, tokens: 120_000, activeMinutes: 60, humanCalls: 4 },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export const manifest: ActivityManifest = {
|
|||||||
identity: {
|
identity: {
|
||||||
activityId: ACTIVITY_ID,
|
activityId: ACTIVITY_ID,
|
||||||
name: 'A6 · 报价议价',
|
name: 'A6 · 报价议价',
|
||||||
packageVersion: '0.1.1',
|
packageVersion: '0.1.2',
|
||||||
category: '统一报价',
|
category: '统一报价',
|
||||||
paradigm: 'flow',
|
paradigm: 'flow',
|
||||||
sdkVersion: '0.1.0-m5',
|
sdkVersion: '0.1.0-m5',
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ export const manifest: ActivityManifest = {
|
|||||||
identity: {
|
identity: {
|
||||||
activityId: ACTIVITY_ID,
|
activityId: ACTIVITY_ID,
|
||||||
name: 'A4 · 成本定价',
|
name: 'A4 · 成本定价',
|
||||||
packageVersion: '0.1.2',
|
packageVersion: '0.1.3',
|
||||||
category: '统一报价',
|
category: '统一报价',
|
||||||
paradigm: 'flow',
|
paradigm: 'flow',
|
||||||
sdkVersion: '0.1.0-m5',
|
sdkVersion: '0.1.0-m5',
|
||||||
@@ -110,14 +110,14 @@ export const manifest: ActivityManifest = {
|
|||||||
authorization: {
|
authorization: {
|
||||||
discretion: [{ key: 'margin-band', statement: '在 P-01 给出的毛利区间内自决;出区间必须调人决策' }],
|
discretion: [{ key: 'margin-band', statement: '在 P-01 给出的毛利区间内自决;出区间必须调人决策' }],
|
||||||
preauthorizedActions: [],
|
preauthorizedActions: [],
|
||||||
humanCallBudget: 2,
|
humanCallBudget: 3,
|
||||||
},
|
},
|
||||||
resources: {
|
resources: {
|
||||||
tools: [{ name: 'quote-pricing.basis' }, { name: 'crm.history-price-read' }],
|
tools: [{ name: 'quote-pricing.basis' }, { name: 'crm.history-price-read' }],
|
||||||
skills: [],
|
skills: [],
|
||||||
models: ['quote-extractor'],
|
models: ['quote-extractor'],
|
||||||
roles: ['BD'],
|
roles: ['BD'],
|
||||||
budget: { steps: 60, tokens: 150_000, activeMinutes: 120, humanCalls: 2 },
|
budget: { steps: 60, tokens: 150_000, activeMinutes: 120, humanCalls: 3 },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -151,14 +151,28 @@ export function createFlowRunner(deps: FlowRunnerDeps): FlowEngineService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case 'human': {
|
case 'human': {
|
||||||
// 异步步:完成条件 = 人事件;时限必配
|
// 异步步:完成条件 = 人事件;时限必配。
|
||||||
const card = await deps.cards.issue({
|
// 发卡本身可能被 Harness 拦下(调人预算触顶等)—— 那是**这一步失败了**,
|
||||||
taskId,
|
// 走它声明的失败走向;不接住就会每一拍重发一次、永远发不出去也永远不报错。
|
||||||
ownerId: context.ownerId,
|
let card: { id: string };
|
||||||
humanCallCap: context.humanCallCap,
|
try {
|
||||||
workOrder: step.workOrder,
|
card = await deps.cards.issue({
|
||||||
card: step.card,
|
taskId,
|
||||||
});
|
ownerId: context.ownerId,
|
||||||
|
humanCallCap: context.humanCallCap,
|
||||||
|
workOrder: step.workOrder,
|
||||||
|
card: step.card,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
return handleFailure(
|
||||||
|
taskId,
|
||||||
|
step,
|
||||||
|
index,
|
||||||
|
position,
|
||||||
|
attempt,
|
||||||
|
error instanceof Error ? error.message : String(error),
|
||||||
|
);
|
||||||
|
}
|
||||||
await deps.listeners.register({
|
await deps.listeners.register({
|
||||||
taskId,
|
taskId,
|
||||||
eventType: 'human',
|
eventType: 'human',
|
||||||
|
|||||||
Reference in New Issue
Block a user