feat: 限定记忆命名空间为7种分类
- 新增 ALLOWED_MEMORY_NAMESPACES 常量定义允许的命名空间 - 添加 namespace 验证函数 is_valid_namespace() - memory_manage 工具 schema 使用 enum 限制 namespace - memory_search 工具 schema 使用 enum 提示可用 namespace - 更新系统提示词添加命名空间分类说明 - 更新记忆维护提示词添加命名空间分类说明 - 修复测试中使用旧 namespace 的问题 命名空间分类: - user: 用户记忆 - semantic: 语义记忆 - episodic: 情景记忆 - skill: 技能记忆 - environment: 环境记忆 - reflection: 反思记忆 - other: 其他记忆
This commit is contained in:
parent
7d9355fd78
commit
1288ba268f
@ -38,10 +38,20 @@
|
||||
|
||||
### 记忆写入
|
||||
|
||||
#### 命名空间分类
|
||||
记忆必须使用以下命名空间之一:
|
||||
- `user` - 用户记忆:用户长期偏好、身份背景和历史协作信息
|
||||
- `semantic` - 语义记忆:结构化或非结构化知识内容
|
||||
- `episodic` - 情景记忆:历史对话、任务执行过程及关键事件
|
||||
- `skill` - 技能记忆:技能定义、工作流、工具调用策略及最佳实践
|
||||
- `environment` - 环境记忆:外部系统状态、运行环境配置和实时资源信息
|
||||
- `reflection` - 反思记忆:成功经验、失败原因和优化建议
|
||||
- `other` - 其他记忆:不属于以上分类的其他内容
|
||||
|
||||
#### 写入规则
|
||||
- 写入或修改记忆时使用 memory_manage。
|
||||
- 遇到未来仍有用的信息时写入记忆:用户长期偏好、稳定事实、用户对你的纠正、持续任务或项目上下文、明确决策等。
|
||||
- 写入时优先使用规范 namespace:preferences、profile、tasks、decisions。
|
||||
- 写入时必须使用允许的命名空间:user、semantic、episodic、skill、environment、reflection、other。
|
||||
- 优先调用 memory_manage(action='put');同一 namespace/key 可直接覆盖更新。
|
||||
|
||||
#### 【重要注意!】以下场景视为高价值加分,必须记录记忆
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
|
||||
- merges:对象数组。每个对象必须包含 source_ids、namespace、memory_key、content。
|
||||
- source_ids: 字符串数组,要合并的源记忆ID列表
|
||||
- namespace: 目标命名空间
|
||||
- namespace: 目标命名空间(必须是以下之一:user、semantic、episodic、skill、environment、reflection、other)
|
||||
- memory_key: 目标记忆键(可以自由决定)
|
||||
- content: 合并后的内容
|
||||
- conflicts:对象数组。每个对象必须包含 source_ids、note。
|
||||
@ -27,6 +27,16 @@
|
||||
- note: 冲突说明
|
||||
- low_value_ids:需要删除的低价值候选记忆 ID 数组
|
||||
|
||||
命名空间分类说明:
|
||||
|
||||
- `user` - 用户记忆:用户长期偏好、身份背景和历史协作信息
|
||||
- `semantic` - 语义记忆:结构化或非结构化知识内容
|
||||
- `episodic` - 情景记忆:历史对话、任务执行过程及关键事件
|
||||
- `skill` - 技能记忆:技能定义、工作流、工具调用策略及最佳实践
|
||||
- `environment` - 环境记忆:外部系统状态、运行环境配置和实时资源信息
|
||||
- `reflection` - 反思记忆:成功经验、失败原因和优化建议
|
||||
- `other` - 其他记忆:不属于以上分类的其他内容
|
||||
|
||||
组织原则:
|
||||
|
||||
- 根据记忆的语义内容自然分组
|
||||
|
||||
@ -1192,7 +1192,7 @@ mod tests {
|
||||
.put_memory(&crate::storage::MemoryUpsert {
|
||||
scope_kind: "user".to_string(),
|
||||
scope_key: "feishu:user-1".to_string(),
|
||||
namespace: "profile".to_string(),
|
||||
namespace: "user".to_string(),
|
||||
memory_key: "work".to_string(),
|
||||
content: "用户在做AI产品".to_string(),
|
||||
source_type: "message".to_string(),
|
||||
@ -1282,7 +1282,7 @@ mod tests {
|
||||
.put_memory(&crate::storage::MemoryUpsert {
|
||||
scope_kind: "user".to_string(),
|
||||
scope_key: "feishu:user-1".to_string(),
|
||||
namespace: "profile".to_string(),
|
||||
namespace: "user".to_string(),
|
||||
memory_key: "work".to_string(),
|
||||
content: "用户在做AI产品".to_string(),
|
||||
source_type: "message".to_string(),
|
||||
@ -1371,7 +1371,7 @@ mod tests {
|
||||
.put_memory(&crate::storage::MemoryUpsert {
|
||||
scope_kind: "user".to_string(),
|
||||
scope_key: "feishu:user-1".to_string(),
|
||||
namespace: "profile".to_string(),
|
||||
namespace: "user".to_string(),
|
||||
memory_key: "work".to_string(),
|
||||
content: "用户在做AI产品".to_string(),
|
||||
source_type: "message".to_string(),
|
||||
@ -1442,7 +1442,7 @@ mod tests {
|
||||
.put_memory(&crate::storage::MemoryUpsert {
|
||||
scope_kind: "user".to_string(),
|
||||
scope_key: "feishu:user-1".to_string(),
|
||||
namespace: "profile".to_string(),
|
||||
namespace: "user".to_string(),
|
||||
memory_key: "work".to_string(),
|
||||
content: "用户在做AI产品".to_string(),
|
||||
source_type: "message".to_string(),
|
||||
@ -1522,7 +1522,7 @@ mod tests {
|
||||
.put_memory(&crate::storage::MemoryUpsert {
|
||||
scope_kind: "user".to_string(),
|
||||
scope_key: "feishu:user-1".to_string(),
|
||||
namespace: "profile".to_string(),
|
||||
namespace: "user".to_string(),
|
||||
memory_key: "work".to_string(),
|
||||
content: "用户在做AI产品".to_string(),
|
||||
source_type: "message".to_string(),
|
||||
@ -1590,7 +1590,7 @@ mod tests {
|
||||
.put_memory(&crate::storage::MemoryUpsert {
|
||||
scope_kind: "user".to_string(),
|
||||
scope_key: scope_key.to_string(),
|
||||
namespace: "profile".to_string(),
|
||||
namespace: "user".to_string(),
|
||||
memory_key: "work".to_string(),
|
||||
content: format!("{} 在做AI产品", scope_key),
|
||||
source_type: "message".to_string(),
|
||||
@ -1623,7 +1623,7 @@ mod tests {
|
||||
.put_memory(&crate::storage::MemoryUpsert {
|
||||
scope_kind: "user".to_string(),
|
||||
scope_key: scope_key.to_string(),
|
||||
namespace: "profile".to_string(),
|
||||
namespace: "user".to_string(),
|
||||
memory_key: "work_short".to_string(),
|
||||
content: "用户在做AI产品".to_string(),
|
||||
source_type: "message".to_string(),
|
||||
@ -1638,7 +1638,7 @@ mod tests {
|
||||
.put_memory(&crate::storage::MemoryUpsert {
|
||||
scope_kind: "user".to_string(),
|
||||
scope_key: scope_key.to_string(),
|
||||
namespace: "profile".to_string(),
|
||||
namespace: "user".to_string(),
|
||||
memory_key: "work_detail".to_string(),
|
||||
content: "用户主要在做AI产品设计和实现".to_string(),
|
||||
source_type: "message".to_string(),
|
||||
@ -1653,7 +1653,7 @@ mod tests {
|
||||
.put_memory(&crate::storage::MemoryUpsert {
|
||||
scope_kind: "user".to_string(),
|
||||
scope_key: scope_key.to_string(),
|
||||
namespace: "notes".to_string(),
|
||||
namespace: "other".to_string(),
|
||||
memory_key: "temporary".to_string(),
|
||||
content: "今天临时提到过一个无后续的小细节".to_string(),
|
||||
source_type: "message".to_string(),
|
||||
@ -1671,7 +1671,7 @@ mod tests {
|
||||
.put_memory(&crate::storage::MemoryUpsert {
|
||||
scope_kind: "user".to_string(),
|
||||
scope_key: scope_key.to_string(),
|
||||
namespace: "profile".to_string(),
|
||||
namespace: "user".to_string(),
|
||||
memory_key: format!("extra_{}", i),
|
||||
content: format!("额外记忆 {}", i),
|
||||
source_type: "message".to_string(),
|
||||
@ -1692,7 +1692,7 @@ mod tests {
|
||||
let output = MemoryOrganizationOutput {
|
||||
merges: vec![MemoryMaintenanceMerge {
|
||||
source_ids: vec![work.id.clone(), role.id.clone()],
|
||||
namespace: "profile".to_string(),
|
||||
namespace: "user".to_string(),
|
||||
memory_key: "work".to_string(),
|
||||
content: "用户主要在做AI产品设计与实现".to_string(),
|
||||
}],
|
||||
@ -1715,10 +1715,10 @@ mod tests {
|
||||
let all_memories = store.list_memories_for_scope("user", scope_key).unwrap();
|
||||
// 过滤掉 _meta 记录
|
||||
let user_memories: Vec<_> = all_memories.iter().filter(|m| m.namespace != "_meta").collect();
|
||||
// 合并 2 条为 1 条,删除 1 条,7 - 2 + 1 = 6 条(加上 _meta 记录)
|
||||
assert_eq!(user_memories.len(), 6);
|
||||
// 合并 2 条为 1 条,删除 1 条,7 - 2 + 1 = 5 条
|
||||
assert_eq!(user_memories.len(), 5);
|
||||
// 验证合并后的记忆存在
|
||||
assert!(user_memories.iter().any(|m| m.namespace == "profile" && m.memory_key == "work"));
|
||||
assert!(user_memories.iter().any(|m| m.namespace == "user" && m.memory_key == "work"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1948,7 +1948,7 @@ mod tests {
|
||||
id: "1".to_string(),
|
||||
scope_kind: "user".to_string(),
|
||||
scope_key: "feishu:user-1".to_string(),
|
||||
namespace: "profile".to_string(),
|
||||
namespace: "user".to_string(),
|
||||
memory_key: "work".to_string(),
|
||||
content: "用户在做AI产品".to_string(),
|
||||
source_type: "message".to_string(),
|
||||
@ -1964,7 +1964,7 @@ mod tests {
|
||||
id: "2".to_string(),
|
||||
scope_kind: "user".to_string(),
|
||||
scope_key: "feishu:user-1".to_string(),
|
||||
namespace: "profile".to_string(),
|
||||
namespace: "user".to_string(),
|
||||
memory_key: "work".to_string(),
|
||||
content: "用户在做AI产品".to_string(),
|
||||
source_type: "message".to_string(),
|
||||
@ -1980,7 +1980,7 @@ mod tests {
|
||||
id: "3".to_string(),
|
||||
scope_kind: "user".to_string(),
|
||||
scope_key: "feishu:user-1".to_string(),
|
||||
namespace: "preferences".to_string(),
|
||||
namespace: "user".to_string(),
|
||||
memory_key: "style".to_string(),
|
||||
content: "偏好简洁表达".to_string(),
|
||||
source_type: "message".to_string(),
|
||||
|
||||
@ -16,8 +16,9 @@ pub use ports::{
|
||||
SkillEventRepository,
|
||||
};
|
||||
pub use records::{
|
||||
MemoryRecord, MemoryUpsert, SchedulerJobRecord, SchedulerJobState, SchedulerJobStatus,
|
||||
SchedulerJobUpsert, SessionRecord, SkillEventRecord, TopicRecord,
|
||||
allowed_namespace_names, get_namespace_description, is_valid_namespace,
|
||||
ALLOWED_MEMORY_NAMESPACES, MemoryRecord, MemoryUpsert, SchedulerJobRecord, SchedulerJobState,
|
||||
SchedulerJobStatus, SchedulerJobUpsert, SessionRecord, SkillEventRecord, TopicRecord,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -2284,7 +2285,7 @@ mod tests {
|
||||
.put_memory(&MemoryUpsert {
|
||||
scope_kind: "user".to_string(),
|
||||
scope_key: format!("{}:user-1", TEST_CHANNEL),
|
||||
namespace: "profile".to_string(),
|
||||
namespace: "user".to_string(),
|
||||
memory_key: "language".to_string(),
|
||||
content: "Rust".to_string(),
|
||||
source_type: "message".to_string(),
|
||||
@ -2303,7 +2304,7 @@ mod tests {
|
||||
assert_eq!(saved.source_message_seq, Some(7));
|
||||
|
||||
let fetched = store
|
||||
.get_memory("user", "test-channel:user-1", "profile", "language")
|
||||
.get_memory("user", "test-channel:user-1", "user", "language")
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
assert_eq!(fetched.id, saved.id);
|
||||
@ -2318,7 +2319,7 @@ mod tests {
|
||||
.put_memory(&MemoryUpsert {
|
||||
scope_kind: "user".to_string(),
|
||||
scope_key: format!("{}:user-1", TEST_CHANNEL),
|
||||
namespace: "preferences".to_string(),
|
||||
namespace: "user".to_string(),
|
||||
memory_key: "editor".to_string(),
|
||||
content: "Prefers rust-analyzer and cargo test output".to_string(),
|
||||
source_type: "message".to_string(),
|
||||
@ -2340,7 +2341,7 @@ mod tests {
|
||||
.put_memory(&MemoryUpsert {
|
||||
scope_kind: "user".to_string(),
|
||||
scope_key: format!("{}:user-1", TEST_CHANNEL),
|
||||
namespace: "preferences".to_string(),
|
||||
namespace: "user".to_string(),
|
||||
memory_key: "editor".to_string(),
|
||||
content: "Prefers clippy diagnostics".to_string(),
|
||||
source_type: "message".to_string(),
|
||||
@ -2363,7 +2364,7 @@ mod tests {
|
||||
assert_eq!(new_hits.len(), 1);
|
||||
|
||||
let deleted = store
|
||||
.delete_memory("user", "test-channel:user-1", "preferences", "editor")
|
||||
.delete_memory("user", "test-channel:user-1", "user", "editor")
|
||||
.unwrap();
|
||||
assert!(deleted);
|
||||
|
||||
@ -2381,7 +2382,7 @@ mod tests {
|
||||
.put_memory(&MemoryUpsert {
|
||||
scope_kind: "user".to_string(),
|
||||
scope_key: format!("{}:user-1", TEST_CHANNEL),
|
||||
namespace: "preferences".to_string(),
|
||||
namespace: "user".to_string(),
|
||||
memory_key: "email_folder_preference".to_string(),
|
||||
content: "用户提到邮件时默认查看代收邮箱。".to_string(),
|
||||
source_type: "message".to_string(),
|
||||
@ -2409,7 +2410,7 @@ mod tests {
|
||||
.put_memory(&MemoryUpsert {
|
||||
scope_kind: "user".to_string(),
|
||||
scope_key: format!("{}:user-1", TEST_CHANNEL),
|
||||
namespace: "preferences".to_string(),
|
||||
namespace: "user".to_string(),
|
||||
memory_key: "editor".to_string(),
|
||||
content: "Prefers rust-analyzer and cargo test output".to_string(),
|
||||
source_type: "message".to_string(),
|
||||
@ -2425,7 +2426,7 @@ mod tests {
|
||||
.put_memory(&MemoryUpsert {
|
||||
scope_kind: "user".to_string(),
|
||||
scope_key: format!("{}:user-1", TEST_CHANNEL),
|
||||
namespace: "tasks".to_string(),
|
||||
namespace: "episodic".to_string(),
|
||||
memory_key: "quality".to_string(),
|
||||
content: "Tracks clippy warnings before release".to_string(),
|
||||
source_type: "message".to_string(),
|
||||
@ -2460,7 +2461,7 @@ mod tests {
|
||||
.put_memory(&MemoryUpsert {
|
||||
scope_kind: "user".to_string(),
|
||||
scope_key: format!("{}:user-2", TEST_CHANNEL),
|
||||
namespace: "preferences".to_string(),
|
||||
namespace: "user".to_string(),
|
||||
memory_key: "style".to_string(),
|
||||
content: "偏好简洁表达".to_string(),
|
||||
source_type: "message".to_string(),
|
||||
@ -2475,7 +2476,7 @@ mod tests {
|
||||
.put_memory(&MemoryUpsert {
|
||||
scope_kind: "user".to_string(),
|
||||
scope_key: format!("{}:user-1", TEST_CHANNEL),
|
||||
namespace: "profile".to_string(),
|
||||
namespace: "user".to_string(),
|
||||
memory_key: "work".to_string(),
|
||||
content: "用户在做AI产品".to_string(),
|
||||
source_type: "message".to_string(),
|
||||
|
||||
@ -1,5 +1,37 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// 允许的记忆命名空间列表
|
||||
///
|
||||
/// 每个命名空间代表一类记忆内容,用于分类管理和检索。
|
||||
/// 禁止使用未在此列表中的 namespace 创建记忆。
|
||||
pub const ALLOWED_MEMORY_NAMESPACES: &[(&str, &str)] = &[
|
||||
("user", "用户记忆:存储用户长期偏好、身份背景和历史协作信息,实现跨会话的个性化服务与持续协作"),
|
||||
("semantic", "语义记忆:存储结构化或非结构化知识内容,支持知识检索、问答增强和长期知识积累"),
|
||||
("episodic", "情景记忆:记录历史对话、任务执行过程及关键事件,支持经验回溯、案例复用和行为追踪"),
|
||||
("skill", "技能记忆:存储技能定义、工作流、工具调用策略及最佳实践,支持能力复用与自动化执行"),
|
||||
("environment", "环境记忆:存储外部系统状态、运行环境配置和实时资源信息,为智能决策提供环境感知能力"),
|
||||
("reflection", "反思记忆:沉淀任务执行过程中的成功经验、失败原因和优化建议,支持智能体持续学习与自我改进"),
|
||||
("other", "其他记忆:不属于以上分类的其他记忆内容"),
|
||||
];
|
||||
|
||||
/// 验证 namespace 是否在允许列表中
|
||||
pub fn is_valid_namespace(namespace: &str) -> bool {
|
||||
ALLOWED_MEMORY_NAMESPACES.iter().any(|(name, _)| *name == namespace)
|
||||
}
|
||||
|
||||
/// 获取 namespace 的中文描述
|
||||
pub fn get_namespace_description(namespace: &str) -> Option<&'static str> {
|
||||
ALLOWED_MEMORY_NAMESPACES
|
||||
.iter()
|
||||
.find(|(name, _)| *name == namespace)
|
||||
.map(|(_, desc)| *desc)
|
||||
}
|
||||
|
||||
/// 获取所有允许的 namespace 名称列表(用于 JSON schema enum)
|
||||
pub fn allowed_namespace_names() -> Vec<&'static str> {
|
||||
ALLOWED_MEMORY_NAMESPACES.iter().map(|(name, _)| *name).collect()
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SkillEventRecord {
|
||||
pub id: String,
|
||||
|
||||
@ -3,7 +3,7 @@ use std::sync::Arc;
|
||||
use async_trait::async_trait;
|
||||
use serde_json::json;
|
||||
|
||||
use crate::storage::{MemoryRecord, MemoryRepository, MemoryUpsert};
|
||||
use crate::storage::{is_valid_namespace, MemoryRecord, MemoryRepository, MemoryUpsert};
|
||||
use crate::tools::traits::{Tool, ToolContext, ToolResult};
|
||||
|
||||
pub struct MemoryManageTool {
|
||||
@ -27,25 +27,27 @@ impl Tool for MemoryManageTool {
|
||||
}
|
||||
|
||||
fn parameters_schema(&self) -> serde_json::Value {
|
||||
let namespaces = crate::storage::allowed_namespace_names();
|
||||
json!({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
"enum": ["put", "update", "delete"],
|
||||
"description": "Management action to perform. Use 'put' to create or overwrite, 'update' to modify an existing record, and 'delete' to remove one. Use memory_search for retrieval."
|
||||
"description": "管理操作。put 用于创建或覆盖,update 用于修改已有记录,delete 用于删除。检索请使用 memory_search。"
|
||||
},
|
||||
"namespace": {
|
||||
"type": "string",
|
||||
"description": "Optional memory namespace filter, such as profile, preferences, or tasks"
|
||||
"enum": namespaces,
|
||||
"description": "记忆命名空间分类"
|
||||
},
|
||||
"key": {
|
||||
"type": "string",
|
||||
"description": "Exact memory key within the namespace"
|
||||
"description": "命名空间内的记忆键名"
|
||||
},
|
||||
"content": {
|
||||
"type": "string",
|
||||
"description": "Memory content for put/update"
|
||||
"description": "put/update 时的记忆内容"
|
||||
}
|
||||
},
|
||||
"required": ["action"]
|
||||
@ -145,6 +147,14 @@ fn build_memory_upsert(
|
||||
Some(namespace) => namespace,
|
||||
None => return Err(error_result("Missing required parameter: namespace")),
|
||||
};
|
||||
// 验证 namespace 是否在允许列表中
|
||||
if !is_valid_namespace(namespace) {
|
||||
let allowed = crate::storage::allowed_namespace_names().join(", ");
|
||||
return Err(error_result(&format!(
|
||||
"Invalid namespace '{}'. Allowed namespaces: {}",
|
||||
namespace, allowed
|
||||
)));
|
||||
}
|
||||
let key = match args.get("key").and_then(|value| value.as_str()) {
|
||||
Some(key) => key,
|
||||
None => return Err(error_result("Missing required parameter: key")),
|
||||
@ -237,7 +247,7 @@ mod tests {
|
||||
&context,
|
||||
json!({
|
||||
"action": "put",
|
||||
"namespace": "profile",
|
||||
"namespace": "user",
|
||||
"key": "language",
|
||||
"content": "Rust"
|
||||
}),
|
||||
@ -282,7 +292,7 @@ mod tests {
|
||||
&context,
|
||||
json!({
|
||||
"action": "get",
|
||||
"namespace": "profile",
|
||||
"namespace": "user",
|
||||
"key": "language"
|
||||
}),
|
||||
)
|
||||
|
||||
@ -28,33 +28,35 @@ impl Tool for MemorySearchTool {
|
||||
}
|
||||
|
||||
fn parameters_schema(&self) -> serde_json::Value {
|
||||
let namespaces = crate::storage::allowed_namespace_names();
|
||||
json!({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
"enum": ["search", "get", "list"],
|
||||
"description": "Retrieval action. Use 'search' for multi-keyword recall, 'get' for an exact namespace/key read, and 'list' to browse recent memories."
|
||||
"description": "检索操作。search 用于多关键词召回,get 用于精确 namespace/key 读取,list 用于浏览最近记忆。"
|
||||
},
|
||||
"namespace": {
|
||||
"type": "string",
|
||||
"description": "Optional namespace filter, such as profile, preferences, tasks, or decisions. Required for get."
|
||||
"enum": namespaces,
|
||||
"description": "可选的命名空间过滤。get 操作时必填。"
|
||||
},
|
||||
"queries": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Keyword queries for memory search. Provide multiple concise bilingual keywords, English aliases, and likely snake_case memory_key terms when known. Search matches any of the provided entries. Required for search.",
|
||||
"description": "搜索关键词数组。建议提供多个简洁的双语关键词、英文别名和可能的 snake_case memory_key。search 操作时必填。",
|
||||
"minItems": 1
|
||||
},
|
||||
"key": {
|
||||
"type": "string",
|
||||
"description": "Exact memory key within the namespace. Required for get."
|
||||
"description": "命名空间内的记忆键名。get 操作时必填。"
|
||||
},
|
||||
"limit": {
|
||||
"type": "integer",
|
||||
"description": "Maximum number of memories to return",
|
||||
"description": "返回记忆的最大数量",
|
||||
"minimum": 1,
|
||||
"default": 10
|
||||
}
|
||||
@ -233,7 +235,7 @@ mod tests {
|
||||
.put_memory(&crate::storage::MemoryUpsert {
|
||||
scope_kind: "user".to_string(),
|
||||
scope_key: TEST_CHANNEL.to_string(),
|
||||
namespace: "preferences".to_string(),
|
||||
namespace: "user".to_string(),
|
||||
memory_key: "language".to_string(),
|
||||
content: "User prefers Chinese responses".to_string(),
|
||||
source_type: "message".to_string(),
|
||||
@ -274,7 +276,7 @@ mod tests {
|
||||
&context,
|
||||
json!({
|
||||
"action": "get",
|
||||
"namespace": "preferences",
|
||||
"namespace": "user",
|
||||
"key": "language"
|
||||
}),
|
||||
)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user