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:
JCAI Main Agent
2026-07-27 01:16:52 +08:00
co-authored by Claude Opus 5
parent 14d4fa046a
commit f0444f1417
73 changed files with 7488 additions and 31 deletions
+51
View File
@@ -0,0 +1,51 @@
/**
* module: memory —— 对外类型(编码规范 §10.1)。
*/
import type { AttributionSide, TaskId } from '@contracts';
import type { ActivityMemoryEntry, CandidateIncrement, Evidence, MemoryLayer } from './internal/domain/activity-memory.ts';
import type { EntryKind, GovernanceMark, MemoryEntry, VersionStamp } from './internal/domain/task-memory.ts';
import type { LogLine, Metrics, MetricsInput } from './internal/domain/task-log.ts';
export type { ActivityMemoryEntry, AttributionSide, CandidateIncrement, EntryKind, Evidence, GovernanceMark, LogLine, MemoryEntry, MemoryLayer, Metrics, MetricsInput, VersionStamp, };
export { NoEvidenceError } from './internal/domain/activity-memory.ts';
/** 追加一条任务记忆 —— 归侧由 kind 自动推导,调用方不得指定(零埋点) */
export type AppendEntry = {
readonly taskId: TaskId;
readonly kind: EntryKind;
readonly title: string;
readonly detail?: Record<string, unknown>;
readonly stamp: VersionStamp;
readonly governance?: Partial<GovernanceMark>;
readonly linksTo?: string;
readonly eventRef?: string;
};
export type DistillInput = {
readonly taskId: TaskId;
readonly activityId: string;
readonly trigger: 'terminal' | 'milestone';
readonly milestone?: string;
readonly prompt: string;
};
export type MemoryService = {
append(entry: AppendEntry): Promise<MemoryEntry>;
history(taskId: TaskId): Promise<MemoryEntry[]>;
/** 活动侧唯一可配置项:窗口大小 —— 每次 LLM 调用加载多少轮 */
window(taskId: TaskId, size: number): Promise<MemoryEntry[]>;
seal(taskId: TaskId): Promise<void>;
taskLog(taskId: TaskId, options?: {
canSeeMasked?: boolean;
}): Promise<LogLine[]>;
/** 叙述性小结(LLM,可选)—— 叙述是视图不是事实,不入事实库 */
narrate(taskId: TaskId): Promise<string | undefined>;
loadActivityMemory(activityId: string, options?: {
layers?: readonly MemoryLayer[];
limit?: number;
}): Promise<ActivityMemoryEntry[]>;
/** **不设直写旁路**:唯一写入口是蒸馏钩子 */
distill(input: DistillInput): Promise<ActivityMemoryEntry[]>;
/** 人可修剪 —— 治理台 · 记忆管理 */
prune(entryId: string): Promise<void>;
setIncrementState(entryId: string, state: CandidateIncrement['state']): Promise<void>;
metrics(input: Omit<MetricsInput, 'entries'> & {
taskIds: readonly TaskId[];
}): Promise<Metrics>;
};
+13
View File
@@ -0,0 +1,13 @@
/**
* module: memory —— 唯一出口。只做 re-export,不写逻辑(编码规范 §10.1)。
*/
export type { ActivityMemoryEntry, AppendEntry, AttributionSide, CandidateIncrement, DistillInput, EntryKind, Evidence, GovernanceMark, LogLine, MemoryEntry, MemoryLayer, MemoryService, Metrics, MetricsInput, VersionStamp, } from './contract.ts';
export { NoEvidenceError } from './contract.ts';
export type { ActivityMemoryStore, Clock, IdGenerator, SystemModel, TaskMemoryStore } from './port.ts';
export type { MemoryServiceDeps } from './internal/usecase/memory-service.ts';
export { createMemoryService } from './internal/usecase/memory-service.ts';
export { assertThreePart, isBinding, MEMORY_LAYER_LABEL, MEMORY_LAYER_TARGET, MEMORY_LAYERS, selectForLoading, } from './internal/domain/activity-memory.ts';
export { assertAppendOnly, deriveSide, distillable, ENTRY_KINDS, redactForReader, windowOf, } from './internal/domain/task-memory.ts';
export { computeMetrics, splitBySide, structuredLog } from './internal/domain/task-log.ts';
export { createActivityMemoryStore, createTaskMemoryStore } from './internal/adapter/memory-store.ts';
export { activityMemoryTable, taskMemorySealTable, taskMemoryTable } from './internal/adapter/memory-schema.ts';
+42
View File
@@ -0,0 +1,42 @@
/**
* module: memory —— 本模块要外界提供的能力(编码规范 §10.1 / §5.3)。
*/
import type { TaskId } from '@contracts';
import type { ActivityMemoryEntry, MemoryLayer } from './internal/domain/activity-memory.ts';
import type { MemoryEntry } from './internal/domain/task-memory.ts';
export type Clock = {
now(): Date;
};
export type IdGenerator = {
next(): string;
};
export type TaskMemoryStore = {
nextSeq(taskId: TaskId): Promise<number>;
append(entry: MemoryEntry): Promise<void>;
list(taskId: TaskId): Promise<MemoryEntry[]>;
tail(taskId: TaskId, size: number): Promise<MemoryEntry[]>;
seal(taskId: TaskId, at: Date): Promise<void>;
isSealed(taskId: TaskId): Promise<boolean>;
};
export type ActivityMemoryStore = {
list(activityId: string, layers: readonly MemoryLayer[] | undefined, limit: number): Promise<ActivityMemoryEntry[]>;
insertMany(entries: readonly ActivityMemoryEntry[]): Promise<void>;
prune(entryId: string, at: Date): Promise<void>;
setIncrementState(entryId: string, state: string): Promise<void>;
};
/**
* 模型调用 —— app 注入 `llm`(L1)的 ModelGateway。
* 蒸馏钩子与叙述性小结用**系统用途**绑定实例:计量入系统账、不占活动预算(OS 02)。
*/
export type SystemModel = {
generate(input: {
readonly model: string;
readonly prompt: string;
readonly outputSchema?: Record<string, unknown>;
}): Promise<{
text: string;
object?: unknown;
}>;
/** 系统用途模型名;未配置即 undefined —— 此时叙述与蒸馏静默跳过,不报错 */
systemModelName(): Promise<string | undefined>;
};