Archived
M2: 基座能力 —— memory / toolbox / channel / message
- memory 任务记忆四性质(只追加·信封盖戳·治理先行·归侧)、活动记忆四层与条目三件套、
任务日志两级投影(结构化零 LLM / 叙述性小结不入事实库)、度量八指标只读投影
- toolbox 注册两审(静态审 + 试运行审)、效应等级决定运行时待遇、契约演进只增不破坏、
白名单与纯工具私有作用域、ToolInvoker(两缝之二,live/record/replay)
- channel 通道实例配置、入站归一(解析 → 系统写 → 数据事件)、出站发送与关联记录登记
- message 通知 / 跨任务征答(就地作答 · 驳回重答只增不改)/ 死信 / 无主兜底
app:message 接上 event 的 MessageFallback;派发器按目标 ID 取 advisory lock 串行消费 +
消费幂等表;/api/ingest 模拟邮件通道(mock 只在外界)
已验证:无主 RFQ 邮件入站 → 归属解析 no-match → 事件落库 → 兜底落 OP 岗位的消息要素
门禁五道全绿;150 个单元测试 + 1 个 PG 集成测试
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
This commit is contained in:
co-authored by
Claude Opus 5
parent
14d4fa046a
commit
f0444f1417
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* 任务日志:任务记忆的两级投影 —— 纯函数,零 IO(编码规范 §5.3;语义出处 OS 8.1)。
|
||||
*
|
||||
* 「做事与留痕是同一个动作,不存在补写日志」——
|
||||
* 结构化日志(零 LLM)以引擎事件流为骨架,按事件类型筛选、模板措辞;
|
||||
* **任何时刻可重算,口径与源恒一致**;归侧标签使其天然分栏。
|
||||
* 叙述性小结(LLM,可选)是视图不是事实,不入事实库 —— 由 usecase 经系统用途模型生成。
|
||||
*/
|
||||
import type { AttributionSide } from '@contracts';
|
||||
import { ATTRIBUTION_SIDE_LABEL } from '@contracts';
|
||||
import type { EntryKind, MemoryEntry } from './task-memory.ts';
|
||||
|
||||
export type LogLine = {
|
||||
readonly id: string;
|
||||
readonly at: string;
|
||||
readonly side: AttributionSide;
|
||||
readonly sideLabel: string;
|
||||
readonly title: string;
|
||||
readonly summary: string | undefined;
|
||||
readonly eventRef: string | undefined;
|
||||
readonly position: string | undefined;
|
||||
};
|
||||
|
||||
/** 骨架:只有这些种类进结构化日志(OS 8.1 列举) */
|
||||
const SKELETON: ReadonlySet<EntryKind> = new Set<EntryKind>([
|
||||
'engine-transition',
|
||||
'action',
|
||||
'result',
|
||||
'card-sent',
|
||||
'card-reply',
|
||||
'ledger-write',
|
||||
'action-intent',
|
||||
'release-verdict',
|
||||
'terminal',
|
||||
'human-input',
|
||||
]);
|
||||
|
||||
const TEMPLATE: Readonly<Record<EntryKind, (e: MemoryEntry) => string>> = {
|
||||
observation: (e) => `观察:${e.title}`,
|
||||
thought: (e) => `思考:${e.title}`,
|
||||
action: (e) => `调用:${e.title}`,
|
||||
result: (e) => `返回:${e.title}`,
|
||||
'engine-transition': (e) => `迁移:${e.title}`,
|
||||
evaluation: (e) => `求值:${e.title}`,
|
||||
'card-sent': (e) => `发出:${e.title}`,
|
||||
'card-reply': (e) => `回传:${e.title}`,
|
||||
'ledger-write': (e) => `写入:${e.title}`,
|
||||
'action-intent': (e) => `动作意向:${e.title}`,
|
||||
'release-verdict': (e) => `放行裁决:${e.title}`,
|
||||
terminal: (e) => `终态:${e.title}`,
|
||||
'human-input': (e) => `留言:${e.title}`,
|
||||
};
|
||||
|
||||
/** 结构化日志:零 LLM,可重算,每条自带谁 · 何时 · 依据 · 留痕指针 */
|
||||
export function structuredLog(entries: readonly MemoryEntry[]): LogLine[] {
|
||||
return entries
|
||||
.filter((e) => SKELETON.has(e.kind))
|
||||
.map((e) => ({
|
||||
id: e.id,
|
||||
at: e.at,
|
||||
side: e.side,
|
||||
sideLabel: ATTRIBUTION_SIDE_LABEL[e.side],
|
||||
title: TEMPLATE[e.kind](e),
|
||||
summary: typeof e.detail?.['summary'] === 'string' ? e.detail['summary'] : undefined,
|
||||
eventRef: e.eventRef,
|
||||
position: e.stamp.position,
|
||||
}));
|
||||
}
|
||||
|
||||
/** 归侧标签使日志天然分栏:机器做的 / 人做的 / 人裁的 / 在等谁 */
|
||||
export function splitBySide(lines: readonly LogLine[]): Record<AttributionSide, LogLine[]> {
|
||||
const out: Record<AttributionSide, LogLine[]> = {
|
||||
machine: [],
|
||||
human: [],
|
||||
'human-verdict': [],
|
||||
'world-wait': [],
|
||||
};
|
||||
for (const line of lines) out[line.side].push(line);
|
||||
return out;
|
||||
}
|
||||
|
||||
/* ── 度量八指标(OS 8.3):只读投影,零埋点,统计即查询 ─────────────── */
|
||||
|
||||
export type Metrics = {
|
||||
/** 自主率 = 机器产出 ÷(机器产出 + 人产出);裁决与等待不进分母 */
|
||||
readonly autonomy: number;
|
||||
/** 纠正率 = 被纠正批次 ÷ 提交批次 */
|
||||
readonly correction: number;
|
||||
/** 有效自主率 = 自主率 ×(1 − 纠正率) */
|
||||
readonly effectiveAutonomy: number;
|
||||
/** 打扰率 = 每单任务调用人类工具的次数 */
|
||||
readonly interruption: number;
|
||||
/** DMN 覆盖率 = 确定性求值占判断次数的比例 */
|
||||
readonly dmnCoverage: number;
|
||||
};
|
||||
|
||||
export type MetricsInput = {
|
||||
readonly entries: readonly MemoryEntry[];
|
||||
/** 提交批次数:每次放行提交 = 一个产出批次 */
|
||||
readonly submissions: number;
|
||||
/** 被纠正批次:驳回重做 / 驳回迭代 / 叫停 / 裁决推翻 */
|
||||
readonly corrections: number;
|
||||
readonly taskCount: number;
|
||||
/** 判断次数中由 DMN / 机检确定性求值的次数 */
|
||||
readonly deterministicJudgements: number;
|
||||
readonly totalJudgements: number;
|
||||
};
|
||||
|
||||
export function computeMetrics(input: MetricsInput): Metrics {
|
||||
const machine = input.entries.filter((e) => e.side === 'machine').length;
|
||||
const human = input.entries.filter((e) => e.side === 'human').length;
|
||||
const denominator = machine + human;
|
||||
const autonomy = denominator === 0 ? 0 : machine / denominator;
|
||||
const correction = input.submissions === 0 ? 0 : input.corrections / input.submissions;
|
||||
const cards = input.entries.filter((e) => e.kind === 'card-sent').length;
|
||||
return {
|
||||
autonomy,
|
||||
correction,
|
||||
effectiveAutonomy: autonomy * (1 - correction),
|
||||
interruption: input.taskCount === 0 ? 0 : cards / input.taskCount,
|
||||
dmnCoverage: input.totalJudgements === 0 ? 0 : input.deterministicJudgements / input.totalJudgements,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user