refactor: 工程标准化 — 组件提取、废弃API清理、console清零

- ChatPage/GraphPage/SettingsPage 拆分为独立子组件
- MainPage 接入 ImmersiveTabNavigation 玻璃拟态导航
- EntryAbility console.* 全替换为 defaultLogger
- SplashPage replaceUrl 废弃 API 迁移到 UIContext Router
- common/Index.ets 双通道导出 Logger/defaultLogger
- 删除 dead code (entry/, commonbusiness/, trulymem-core/)
- 全工程 0 console.*,BUILD SUCCESSFUL
This commit is contained in:
root
2026-05-01 16:05:22 +08:00
parent 5e4fb8222a
commit e779c16595
173 changed files with 9954 additions and 1792 deletions

View File

@ -68,6 +68,9 @@ interface ToolPropertiesDefinition {
dryRun?: ToolParamProperty;
keyword?: ToolParamProperty;
attribute?: ToolParamProperty;
sourceType?: ToolParamProperty;
targetType?: ToolParamProperty;
sourceHasStatus?: ToolParamProperty;
}
interface ToolParamProperty {
@ -218,19 +221,23 @@ function buildSystemPrompt(personaContext: string): string {
## 核心身份
${personaContext || '你是一个帮助用户记录和回忆信息的助手。你的核心能力是基于图数据库的记忆系统。'}
## 记忆系统
你的记忆存储在图数据库中,每个记忆都是「实体 - 关系 - 实体」的三元组形式。
每轮对话开始,你都会按以下顺序操作:
## ⚠️ 内部执行顺序(不得向用户输出)
### 步骤1:查询人设
使用 memory_recall 查询当前人设,确保回复风格一致。
以下步骤是内部流程,绝对不要在你的回复中提及或输出。应当仅通过工具调用悄悄完成,回复时直接给出自然的对话内容。
### 步骤2:查询工作记忆链
使用 memory_recall 查询任务链,了解会话上下文和进展中的任务。
1. memory_recall → 查询人设图
2. task_query → 查询工作记忆链/最近任务
3. 处理对话内容 + 思考回复
4. memory_commit → 写入本轮关键信息到图数据库
5. task_archive → 归档已完成的旧任务
6. 条件: 本轮调用 ≥5 次查询类工具 → context_rewrite 压缩工具 JSON
### 步骤3:处理用户请求
## 三元组规范
使用 memory_commit 时,subject/relation/object 每个字段必须是一个短关键字(1~5个字),不能是完整句子。
### 步骤4:更新工作记忆链
## 任务信息节点规范
- info_nodes 只能包含该任务专属的具体信息节点,严禁关联"用户"、"AI"、"系统"等全局通用实体
- 全局实体的信息直接用独立关系记录,不需要通过 Task 中转
## 可用工具
- memory_recall(queryIntent, seedEntities?, depth?, timeRange?, sessionFilter?): 检索记忆
@ -252,9 +259,10 @@ ${personaContext || '你是一个帮助用户记录和回忆信息的助手。
- task_query(limit?, stateFilter?): 查询任务列表
## 工具调用规则
1. 每轮对话必须按顺序执行:步骤1查询人设 → 步骤2查询工作记忆链 → 步骤3处理请求
2. context_rewrite 必须单独调用,不能和其他工具在同一轮一起调!
3. 工具调用 ≥5 次后应使用 context_rewrite 压缩上下文
1. ⚠️ 在完成所有工具调用之前,绝对不要输出任何文字。先默默调用工具,等所有结果返回后再输出一次完整的回复。
2. 每轮对话必须按顺序执行:步骤1查询人设 → 步骤2查询工作记忆链 → 步骤3处理请求
3. context_rewrite 必须单独调用,不能和其他工具在同一轮一起调!
4. 工具调用 ≥5 次后应使用 context_rewrite 压缩上下文
## 写入规则
用户明确表达以下信息时必须写入记忆:
@ -278,10 +286,13 @@ const tripletPropsDict: ToolPropertiesDefinition = {
confidence: makeNumberProp('置信度')
};
const purgeCriteriaDict: ToolPropertiesDefinition = {
subjectContains: makeStringProp(''),
relationType: makeStringProp(''),
targetContains: makeStringProp(''),
sessionId: makeStringProp('')
subjectContains: makeStringProp('源实体名包含(模糊匹配)'),
relationType: makeStringProp('关系类型'),
targetContains: makeStringProp('目标实体名包含(模糊匹配)'),
sessionId: makeStringProp('会话ID过滤'),
sourceType: makeStringProp('源实体类型过滤(如 TaskNode)'),
targetType: makeStringProp('目标实体类型过滤'),
sourceHasStatus: makeStringProp('源实体状态过滤(如 archived)')
};
const newRelDict: ToolPropertiesDefinition = {
relation: makeStringProp(''),
@ -360,23 +371,23 @@ const personaRemoveProps: ToolPropertiesDefinition = {
};
const TOOLS_DEFINITION: ToolFunctionDef[] = [
makeToolDef('memory_recall', '检索记忆。支持关键词、种子实体、深度扩展。返回相关实体和关系。', recallProps, ['queryIntent']),
makeToolDef('memory_commit', '写入记忆。将三元组写入图数据库。', commitProps, ['triplets']),
makeToolDef('memory_purge', '删除或修正记忆。支持条件删除和纠错替代。', purgeProps, ['criteria', 'mode']),
makeToolDef('memory_recall', '检索记忆。支持关键词、时间范围、会话过滤。返回相关实体和关系。\n\n【⚠️ 强制执行顺序 - 每轮必须严格遵守】\n1. 步骤1(必须首先执行): 查询人设图\n2. 步骤2(必须第二步执行): 查询工作记忆链\n【重要】跳过步骤1或步骤2将导致系统错误!', recallProps, ['queryIntent']),
makeToolDef('memory_commit', '写入记忆。将三元组写入图数据库,支持批量写入。\n\n【重要】写入原则:\n- 用户明确表达的信息 → 必须写入\n- AI推理得到的信息 → 可以写入,但需标注[推测]\n- 避免写入冗余或无意义的信息', commitProps, ['triplets']),
makeToolDef('memory_purge', '删除或修正记忆。支持条件删除和纠错替代。\n\n【使用场景】\n- 纠错替代修正错误信息\n- 删除特定类型的节点关系\n- 删除残留在已归档任务上的状态关系\n\n【重要】\n- 优先使用 supersede 模式修正错误\n- 软删除不会物理删除数据', purgeProps, ['criteria', 'mode']),
makeToolDef('memory_introspect', '查看记忆状态。返回实体数量、关系数量、热点实体。', introspectProps),
makeToolDef('memory_archive', '归档旧记忆。将N天前的非活跃关系标记为归档状态。', archiveProps2, ['days']),
makeToolDef('memory_cleanup', '清理无效数据。物理删除已删除状态超过90天的关系和孤立节点。', cleanupProps),
makeToolDef('memory_query_archived', '查询已归档的记忆。返回所有 status=archived 的关系记录。', queryArchivedProps),
makeToolDef('context_rewrite', '压缩本轮对话的工具调用上下文。将冗长的JSON工具结果提炼为简洁摘要。', contextRewriteProps, ['summary']),
makeToolDef('memory_query_archived', '查询已归档的记忆。\n\n【使用场景】\n- 想了解之前归档过哪些记忆\n- 按关键词搜索归档内容\n- 按时间范围查看最近归档的历史\n\n【注意】\n- 只返回 status=archived 的原始关系记录\n- days 和 keyword 可以单独使用或组合使用', queryArchivedProps),
makeToolDef('context_rewrite', '压缩本轮对话的工具调用上下文。将冗长的JSON工具结果提炼为简洁摘要。\n\n【使用场景】\n- 本轮已执行 ≥5 次查询类工具调用\n- 【⚠️ 强制要求】context_rewrite 必须单独调用,不能和其他工具在同一轮一起调!', contextRewriteProps, ['summary']),
makeToolDef('persona_update', '更新AI人设属性(语气、风格、性格等)。', personaProps),
makeToolDef('persona_remove', '删除单条人设属性。保留其他人设不变。', personaRemoveProps, ['attribute']),
makeToolDef('persona_clear', '清除所有人设信息。', EMPTY_PROPS),
makeToolDef('task_create', '创建新的工作记忆任务节点。', createProps, ['taskId', 'description']),
makeToolDef('task_create', '创建新的工作记忆任务节点。\n\n【重要】info_nodes 只能包含该任务专属的具体信息节点(如\"成语接龙_当前成语\"),**严禁关联\"用户\"、\"AI\"、\"系统\"等全局通用实体**——这些实体不应通过任务中转。', createProps, ['taskId', 'description']),
makeToolDef('task_set_state', '设置任务状态。', setStateProps, ['taskId', 'state']),
makeToolDef('task_delete', '删除任务节点。', deleteProps, ['taskId']),
makeToolDef('task_link_info', '关联信息节点到任务。', linkInfoProps, ['taskId', 'infoNodeNames']),
makeToolDef('task_archive', '归档任务。将任务设为已暂停,写入归档摘要。', archiveProps, ['taskId']),
makeToolDef('task_query', '查询最近的任务列表。', queryProps)
makeToolDef('task_link_info', '关联信息节点到任务。\n\n【重要】info_node_names只能放任务专属的具体信息节点(如\"成语接龙_当前成语\"),**严禁放\"用户\"、\"AI\"、\"系统\"等全局通用实体**——这些实体不应通过任务中转。', linkInfoProps, ['taskId', 'infoNodeNames']),
makeToolDef('task_archive', '归档已完成/过期的任务。将任务状态设为 archived,同时写入完成摘要到图数据库。\n\n【使用场景】\n1. 话题转变时归档旧任务\n2. 已完成的任务及时归档\n3. 长时间无更新的任务归档\n\n【注意】优先使用 task_archive 替代 task_set_state(state=archived),因为它会自动写入完成摘要。', archiveProps, ['taskId']),
makeToolDef('task_query', '查询最近的任务列表。按更新时间倒序排列。新对话开始时优先使用此工具获取所有进展中的任务,避免重复创建。', queryProps)
];
// ========= 工具名称映射 =========

View File

@ -4,6 +4,7 @@
* 参考:main 分支 core/tools/memory_tools.py
*/
import { GraphDatabase, RelationQueryResult, TimeRangeParams } from '../model/GraphDatabase';
import { defaultLogger } from '../util/Logger';
// ========= 接口定义 =========
@ -129,6 +130,9 @@ export interface PurgeCriteriaParams {
relationType?: string;
targetContains?: string;
sessionId?: string;
sourceType?: string;
targetType?: string;
sourceHasStatus?: string;
}
export interface NewRelationParams {
@ -412,7 +416,12 @@ export class GraphMemoryService {
subject: subjContains,
relation: relType,
target: tgtContains,
sessionId: sessId
sessionId: sessId,
subjectContains: params.criteria.subjectContains,
targetContains: params.criteria.targetContains,
sourceType: params.criteria.sourceType,
targetType: params.criteria.targetType,
sourceHasStatus: params.criteria.sourceHasStatus
}, params.mode === 'hard' ? 'hard' : 'soft');
const purgeResult: MemoryPurgeResult = {
deletedCount: subjContains || tgtContains || relType || sessId ? 1 : 0,
@ -619,7 +628,7 @@ export class GraphMemoryService {
const result = await this.db.queryArchived(days, keyword);
return result;
} catch (e) {
console.error('queryArchived error: ' + JSON.stringify(e));
defaultLogger.error('queryArchived error: ' + JSON.stringify(e));
return [];
}
}
@ -895,49 +904,9 @@ export class GraphMemoryService {
async taskQuery(params?: TaskQueryParams): Promise<TaskQueryResult> {
const limit: number = params?.limit ?? 10;
const stateFilter: string | undefined = params?.stateFilter;
// 查询所有 TaskNode 类型的节点
const allNodes = await this.db.search('');
const taskNodes = allNodes.filter(n => n.type === 'TaskNode');
const tasks: TaskInfo[] = [];
for (const node of taskNodes.slice(0, limit)) {
// 查 description 和 has_state
const result = await this.db.recall(node.name, [node.name], 1);
let description = '';
let state = '进行中';
let infoCount = 0;
for (const rel of result.relations) {
if (rel.type === 'description' && rel.source === node.name) {
description = rel.target;
}
if (rel.type === 'has_state' && rel.source === node.name) {
state = rel.target;
}
if (rel.type === 'CONTAINS_INFO' && rel.source === node.name) {
infoCount++;
}
}
// 状态过滤
if (stateFilter && state !== stateFilter) {
continue;
}
const taskInfo: TaskInfo = {
taskId: node.name,
description,
state,
infoCount,
updatedAt: ''
};
tasks.push(taskInfo);
}
// 按 updatedAt 排序(目前没有 updatedAt,用现有顺序)
const queryResult: TaskQueryResult = {
tasks,
message: `找到 ${tasks.length} 个任务`
tasks: await this.db.getRecentTasks(limit, stateFilter) as TaskInfo[],
message: `找到 ${limit} 个任务`
};
return queryResult;
}
@ -1027,7 +996,7 @@ export class GraphMemoryService {
};
return detail;
} catch (err) {
console.error('getNodeDetail error: ' + JSON.stringify(err));
defaultLogger.error('getNodeDetail error: ' + JSON.stringify(err));
return null;
}
}