Archived
用户定的两件,一并落地。
**一、活动不再分 flow 和 loop —— 彻底退役 flow**
· `flow-engine` 模块整个删除(runner 379 行 + step-sequence 184 行 + 测试);
· `paradigm` 从清单身份、`activity_package`/`task` 两张表、任务卡与活动库一并退场;
`businessModel` 不再是判别联合 —— 只有案例模型(CMMN + 说明书 + DMN)一形;
· task 的引擎分派从「按 paradigm 取两个之一」收成**唯一的引擎**;
· `activities/` 四个 flow 活动(A1 受理 / A4 定价 / A6 议价 / A7 归档)各写了一份
案例模型:阶段照原来的步分,触达世界的项一律 manualActivationRule,
能算的交 DMN(A1 的三分类 P-03、A4 的 P-01/P-02)不交 Agent;
· 六个占位槽位的骨架从「机器步落台账 + 一张验收单」改成案例骨架,包版本 0.8.0 → 0.9.0。
**代价写在明处,不假装没有**:`turn-runner` 每一拍都要 `agent.decide` ——
环境里没有模型 key,案例活动一步也走不动。三套端到端(统一报价 / 新建流程包 / 测试台
Trace)整套跳过,文件头写明恢复条件:①有可用模型 ②走法改写成按 Enabled 集推进。
**不许把断言改松让它变绿** —— 绿得不诚实比红着更坏。debt.md 已记。
**二、审批活动可管**(新能力)
· `sys.approval_template`:审批点**可复用的那一半** —— 审批人看哪几项、按什么名字看、
怎么催、说什么话。谁来审不在里面(与活动点同口径,运营时轮值);驳回回哪个节点
也不在里面(那是每张图自己的事,留在节点上);
· 三条路由 + 引用反查:还被审批点引着就不许删(409),删了那些节点会**静默**退回旧行为;
· 运行时 `basisOf`:引了模板就按模板筛与改名,没引即旧行为(载荷全摊开)。
模板改了只影响新发出的审批单 —— 在途单的依据在发出那一刻已定形。
**三、活动库重做**:一区两格 —— 「活动(装进来的)」与「审批活动(配出来的)」,
都用流程卡那套两段式卡片(头 + 四格数据板),幽灵卡当入口(装入活动 / 新建审批活动);
「标准/案例」那一维随范式一起撤,业务分类成了唯一的一维,以行内小签呈现。
迁移 0020:两张表 drop paradigm、建 approval_template。已在开发库跑过并重播种。
实测(丁子乔账号):建「定价审批」模板 → 流程包 A5 属性里选得到 → 引用反查计数正确。
四闸绿(api:check 随本提交)。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
213 lines
9.2 KiB
TypeScript
213 lines
9.2 KiB
TypeScript
/**
|
|
* 活动包清单六区与资产形状(编码规范 §8.1;语义出处 OS 11.1,AM 11)。
|
|
*
|
|
* 清单机器可读,系统**不执行代码即知包为何物** —— 导入登记、安装静态审、编排装配读的都是清单。
|
|
* 资产与包分离版本化(OS 11.3):包版本管代码 / 契约 / 交互模版 / Harness;
|
|
* 资产版本管业务模型 / DMN / 技能 —— 包只携初始版,此后由进化管线在系统内产生。
|
|
*/
|
|
import { z } from 'zod';
|
|
import { activityIdSchema, skillIdSchema } from './id.ts';
|
|
import { jsonSchemaSchema, sevenPartContractSchema } from './contract7.ts';
|
|
import { listenerSpecSchema } from './envelope.ts';
|
|
import { objectDeclarationSchema } from './ledger.ts';
|
|
|
|
/* ── ① 身份 ─────────────────────────────────────────────────────────── */
|
|
|
|
export const manifestIdentitySchema = z.object({
|
|
activityId: activityIdSchema,
|
|
name: z.string().min(1),
|
|
packageVersion: z.string().min(1),
|
|
/**
|
|
* 业务分类(一级,组织自定)—— 活动库唯一的一维。
|
|
* 「活动类型(标准/案例)」那一维 2026-07-29 撤销:活动不再分范式,**一律 loop**。
|
|
*/
|
|
category: z.string().min(1),
|
|
sdkVersion: z.string().min(1),
|
|
checksum: z.string().min(1),
|
|
signature: z.string().optional(),
|
|
});
|
|
export type ManifestIdentity = z.infer<typeof manifestIdentitySchema>;
|
|
|
|
/* ── ③ 声明 ─────────────────────────────────────────────────────────── */
|
|
|
|
export const harnessConfigSchema = z.object({
|
|
/** 记忆窗口:每次 LLM 调用加载多少轮会话历史 —— 活动侧唯一记忆接口(AM 09) */
|
|
memoryWindow: z.number().int().min(1).max(200).default(20),
|
|
/** 停滞检测:多久无推进算空转(ISO-8601 duration) */
|
|
stallAfter: z.string().min(2).default('PT30M'),
|
|
/** 时限阶梯 */
|
|
nudge: z.array(z.object({ after: z.string().min(2), action: z.enum(['nudge', 'escalate']) })).default([]),
|
|
/** 步失败的默认重试(flow 每步可覆盖) */
|
|
retry: z.object({ times: z.number().int().min(0).max(10).default(2), backoff: z.string().default('PT30S') }).default({
|
|
times: 2,
|
|
backoff: 'PT30S',
|
|
}),
|
|
});
|
|
export type HarnessConfig = z.infer<typeof harnessConfigSchema>;
|
|
|
|
export const manifestDeclarationsSchema = z.object({
|
|
/** 模型声明:自定义模型名(逻辑名);安装静态审核对名称已绑定 */
|
|
models: z.array(z.string().min(1)).default([]),
|
|
/** 工具声明:调用契约引用 + 版本约束 */
|
|
tools: z.array(z.object({ name: z.string().min(1), version: z.string().optional() })).default([]),
|
|
/** 台账与共享域使用声明(域.对象.字段) */
|
|
ledger: z.array(objectDeclarationSchema).default([]),
|
|
/** 静态监听声明 —— 时限必配,悬空监听安装时拒绝 */
|
|
listeners: z.array(listenerSpecSchema).default([]),
|
|
harness: harnessConfigSchema,
|
|
});
|
|
export type ManifestDeclarations = z.infer<typeof manifestDeclarationsSchema>;
|
|
|
|
/* ── ④ 资产初始版 ───────────────────────────────────────────────────── */
|
|
|
|
/* loop 的业务模型:CMMN XML + 案例说明书 + DMN(AM 03) */
|
|
|
|
export const dmnDecisionTableSchema = z.object({
|
|
id: z.string().min(1),
|
|
label: z.string(),
|
|
hitPolicy: z.enum(['UNIQUE', 'FIRST', 'PRIORITY', 'COLLECT']).default('FIRST'),
|
|
inputs: z.array(z.object({ name: z.string().min(1), expression: z.string().min(1) })).min(1),
|
|
outputs: z.array(z.object({ name: z.string().min(1) })).min(1),
|
|
rules: z
|
|
.array(
|
|
z.object({
|
|
id: z.string().min(1),
|
|
/** 单元格谓词:S-FEEL(空串 = 「-」任意匹配) */
|
|
when: z.array(z.string()),
|
|
then: z.array(z.unknown()),
|
|
annotation: z.string().optional(),
|
|
}),
|
|
)
|
|
.min(1),
|
|
});
|
|
export type DmnDecisionTable = z.infer<typeof dmnDecisionTableSchema>;
|
|
|
|
export const dmnModelSchema = z.object({
|
|
/** DRD:声明「定什么需要知道什么」—— 决策 → 依赖的决策 / 输入项 */
|
|
drd: z.array(
|
|
z.object({
|
|
decision: z.string().min(1),
|
|
requires: z.array(z.string()).default([]),
|
|
inputs: z.array(z.string()).default([]),
|
|
}),
|
|
),
|
|
tables: z.array(dmnDecisionTableSchema),
|
|
});
|
|
export type DmnModel = z.infer<typeof dmnModelSchema>;
|
|
|
|
export const loopModelSchema = z.object({
|
|
/** 案例模型 · 机器面:CMMN XML,语义引擎以它为运行结构 */
|
|
cmmnXml: z.string().min(1),
|
|
/** 案例模型 · 叙事面:说明书,与 XML **同版本发布,不允许分叉**(AM 12.2) */
|
|
narrative: z.string().min(1),
|
|
dmn: dmnModelSchema,
|
|
});
|
|
export type LoopModel = z.infer<typeof loopModelSchema>;
|
|
|
|
/**
|
|
* 业务模型只有一种(2026-07-29 用户定:活动不再分 flow 和 loop,内部实现都是 Loop)——
|
|
* 案例模型 CMMN + 说明书 + DMN。步序声明(flow)连同它的引擎一并退役:
|
|
* 一件事该怎么办,由 Agent 依案例模型临场决定,不再有「照谱执行」这一路。
|
|
*/
|
|
export const businessModelSchema = loopModelSchema;
|
|
export type BusinessModel = z.infer<typeof businessModelSchema>;
|
|
|
|
/* 技能(AM 08):载方法不载权力 */
|
|
|
|
export const skillSchema = z.object({
|
|
id: skillIdSchema,
|
|
label: z.string().min(1),
|
|
/** 何时适用 —— 常驻上下文只有目录,按事加载正文 */
|
|
applicability: z.string().min(1),
|
|
/** 怎么判断、怎么编排工具 */
|
|
method: z.string().min(1),
|
|
/** 结晶片段脚本:反复出现的确定性子序列;按纯工具规矩注册留痕 */
|
|
crystallized: z
|
|
.array(z.object({ tool: z.string().min(1), input: z.record(z.string(), z.string()) }))
|
|
.default([]),
|
|
knowledgeRefs: z.array(z.string()).default([]),
|
|
version: z.string().min(1),
|
|
});
|
|
export type Skill = z.infer<typeof skillSchema>;
|
|
|
|
export const manifestAssetsSchema = z.object({
|
|
businessModel: businessModelSchema,
|
|
skills: z.array(skillSchema).default([]),
|
|
/** 视图 HTML 模版 —— 模版是内容不是代码,容器净化渲染、无脚本执行权 */
|
|
viewTemplates: z.array(z.object({ name: z.string().min(1), html: z.string() })).default([]),
|
|
/** 卡内容 schema */
|
|
cardSchemas: z.record(z.string(), jsonSchemaSchema).default({}),
|
|
/** 蒸馏钩子:终态封卷 / 里程碑达成时从任务记忆归纳 */
|
|
distillHooks: z
|
|
.array(z.object({ on: z.enum(['terminal', 'milestone']), milestone: z.string().optional(), prompt: z.string() }))
|
|
.default([]),
|
|
});
|
|
export type ManifestAssets = z.infer<typeof manifestAssetsSchema>;
|
|
|
|
/* ── ⑤ 样例集 ───────────────────────────────────────────────────────── */
|
|
|
|
export const sampleCaseSchema = z.object({
|
|
name: z.string().min(1),
|
|
input: z.record(z.string(), z.unknown()),
|
|
message: z.string().optional(),
|
|
/** 期望输出口与载荷形状 —— 首装审与回归的依据 */
|
|
expect: z.object({
|
|
ports: z.array(z.string()).min(1),
|
|
payloadShape: jsonSchemaSchema.optional(),
|
|
}),
|
|
});
|
|
export type SampleCase = z.infer<typeof sampleCaseSchema>;
|
|
|
|
/* ── 清单六区合体 ───────────────────────────────────────────────────── */
|
|
|
|
export const activityManifestSchema = z.object({
|
|
identity: manifestIdentitySchema,
|
|
contract: sevenPartContractSchema,
|
|
declarations: manifestDeclarationsSchema,
|
|
assets: manifestAssetsSchema,
|
|
samples: z.array(sampleCaseSchema).min(1),
|
|
/** ⑥ 代码入口:.JS 产物的入口与校验和 */
|
|
entry: z.object({ file: z.string().min(1), checksum: z.string().min(1) }),
|
|
});
|
|
export type ActivityManifest = z.infer<typeof activityManifestSchema>;
|
|
|
|
/* ── 安装两审的报告形状(OS 11.2) ─────────────────────────────────── */
|
|
|
|
export const staticAuditFindingSchema = z.object({
|
|
code: z.enum([
|
|
'signature-invalid',
|
|
'sdk-incompatible',
|
|
'schema-invalid',
|
|
'tool-contract-missing',
|
|
'model-name-unbound',
|
|
'dangling-listener',
|
|
'template-has-script',
|
|
'environment-capability',
|
|
'dynamic-eval',
|
|
'ledger-type-conflict',
|
|
'acceptance-level-misreported',
|
|
]),
|
|
severity: z.enum(['error', 'warn']),
|
|
message: z.string(),
|
|
at: z.string().optional(),
|
|
});
|
|
export type StaticAuditFinding = z.infer<typeof staticAuditFindingSchema>;
|
|
|
|
export const replayAuditReportSchema = z.object({
|
|
/** 「旧成不坏」是生效硬门;「旧败能成」为报告参考项,不作门槛 */
|
|
oldPassStillPass: z.boolean(),
|
|
checked: z.number().int().min(0),
|
|
regressions: z.array(z.object({ taskId: z.string(), detail: z.string() })).default([]),
|
|
newlyBlocked: z.array(z.object({ taskId: z.string(), detail: z.string() })).default([]),
|
|
/** 首次安装无历史:免回放审,以静态审 + 样例集替代 */
|
|
skippedNoHistory: z.boolean().default(false),
|
|
});
|
|
export type ReplayAuditReport = z.infer<typeof replayAuditReportSchema>;
|
|
|
|
export const installVerdictSchema = z.object({
|
|
accepted: z.boolean(),
|
|
staticFindings: z.array(staticAuditFindingSchema),
|
|
replay: replayAuditReportSchema,
|
|
});
|
|
export type InstallVerdict = z.infer<typeof installVerdictSchema>;
|