feat: 重构 memory 系统,支持 user memory 和 work memory 分离

This commit is contained in:
qzl
2026-03-23 14:25:47 +08:00
parent 3aacc756db
commit 6be616f108
70 changed files with 7031 additions and 431 deletions
-2
View File
@@ -12,7 +12,6 @@ from schemas.inbox.messages import (
parse_calendar_content,
)
from schemas.invite_codes import InviteCodeRewardConfig
from schemas.memories import MemoryContext
from schemas.messages import AgentChatMessageMetadata
from schemas.schedule.items import (
AttachmentType,
@@ -36,7 +35,6 @@ __all__ = [
"InboxMessageStatus",
"InboxMessageType",
"InviteCodeRewardConfig",
"MemoryContext",
"ScheduleItemMetadata",
"ScheduleItemMetadataAttachment",
"ScheduleItemSourceType",
+4 -2
View File
@@ -20,7 +20,7 @@ class ContextWindowMode(str, Enum):
NUMBER = "number"
class MemoryContextConfig(BaseModel):
class MessageContextConfig(BaseModel):
model_config = ConfigDict(extra="forbid")
source: ContextSource = ContextSource.LATEST_CHAT
@@ -32,7 +32,7 @@ class RuntimeConfig(BaseModel):
model_config = ConfigDict(extra="forbid")
enabled_tools: list[AgentTool] = Field(default_factory=list, max_length=32)
context: MemoryContextConfig = Field(default_factory=MemoryContextConfig)
context: MessageContextConfig = Field(default_factory=MessageContextConfig)
class AutomationJobConfig(RuntimeConfig):
@@ -46,6 +46,7 @@ class AutomationJob(BaseModel):
id: UUID
owner_id: UUID
bootstrap_key: str | None = Field(default=None, min_length=1, max_length=64)
title: str = Field(..., min_length=1, max_length=255)
config: AutomationJobConfig
schedule_type: ScheduleType
@@ -63,6 +64,7 @@ class AutomationJob(BaseModel):
return cls(
id=obj.id,
owner_id=obj.owner_id,
bootstrap_key=obj.bootstrap_key,
title=obj.title,
config=AutomationJobConfig.model_validate(obj.config or {}),
schedule_type=obj.schedule_type,
+18 -33
View File
@@ -2,10 +2,19 @@ from __future__ import annotations
from datetime import datetime
from enum import Enum
from typing import Any, ClassVar, Literal
from typing import ClassVar, Literal
from uuid import UUID
from pydantic import BaseModel, ConfigDict, Field
from pydantic import BaseModel, ConfigDict
from schemas.memories.memory_content import (
TeamMember,
UserMemoryContent,
UserPreferences,
WorkHabit,
WorkProfileContent,
WorkProject,
)
class MemoryType(str, Enum):
@@ -13,12 +22,6 @@ class MemoryType(str, Enum):
WORK = "work"
class MemorySource(str, Enum):
MANUAL = "manual"
AGENT = "agent"
IMPORTED = "imported"
class MemoryStatus(str, Enum):
ACTIVE = "active"
DISABLED = "disabled"
@@ -33,38 +36,20 @@ class MemoryModel(BaseModel):
owner_id: UUID
agent_id: UUID | None = None
memory_type: Literal["user", "work"]
title: str | None = None
content: dict[str, Any]
source: MemorySource
content: UserMemoryContent | WorkProfileContent
status: MemoryStatus
created_at: datetime
updated_at: datetime
class MemoryContext(BaseModel):
model_config: ClassVar[ConfigDict] = ConfigDict(extra="forbid")
memory_type: MemoryType
source: MemorySource
title: str | None = None
content: dict[str, Any]
created_at: datetime
updated_at: datetime
class MemoryListResponse(BaseModel):
model_config: ClassVar[ConfigDict] = ConfigDict(extra="forbid")
owner_id: UUID
memories: list[MemoryContext] = Field(default_factory=list)
total: int
__all__ = [
"MemoryContext",
"MemoryListResponse",
"MemoryModel",
"MemorySource",
"MemoryStatus",
"MemoryType",
"TeamMember",
"UserMemoryContent",
"UserPreferences",
"WorkHabit",
"WorkProfileContent",
"WorkProject",
]
@@ -0,0 +1,192 @@
from __future__ import annotations
from datetime import date, datetime
from typing import Literal
from pydantic import BaseModel, ConfigDict, Field
Weekday = Literal["mon", "tue", "wed", "thu", "fri", "sat", "sun"]
ProjectStatus = Literal["planned", "active", "paused", "completed"]
PreferenceLevel = Literal["like", "neutral", "avoid"]
MemorySource = Literal["user", "inferred", "calendar", "email", "agent"]
class MemoryMeta(BaseModel):
source: MemorySource | None = Field(default=None, description="记忆来源")
confidence: float = Field(default=1.0, ge=0.0, le=1.0, description="置信度")
last_updated_at: datetime | None = Field(default=None, description="最后更新时间")
class TimeWindow(BaseModel):
weekdays: list[Weekday] = Field(default_factory=list, description="适用星期")
start: str = Field(description="开始时间,HH:MM")
end: str = Field(description="结束时间,HH:MM")
class PersonMemory(BaseModel):
name: str = Field(description="人物姓名")
relationship: str | None = Field(
default=None, description="与用户关系,如家人/同事/导师/朋友"
)
role: str | None = Field(default=None, description="角色,如老板/导师/合作方")
preferred_contact_channel: str | None = Field(
default=None, description="偏好联系方式"
)
notes: str | None = Field(default=None, description="补充说明")
meta: MemoryMeta = Field(default_factory=MemoryMeta)
class PlaceMemory(BaseModel):
name: str = Field(description="地点名称")
category: str | None = Field(
default=None, description="地点类别,如home/office/gym/cafe"
)
address: str | None = Field(default=None, description="地址")
timezone: str | None = Field(default=None, description="地点时区")
commute_minutes: int | None = Field(default=None, ge=0, description="典型通勤时长")
preference: PreferenceLevel | None = Field(default=None, description="地点偏好")
notes: str | None = Field(default=None, description="补充说明")
meta: MemoryMeta = Field(default_factory=MemoryMeta)
class UserPreferences(BaseModel):
communication_style: str | None = Field(
default=None, description="沟通风格,如简洁直接"
)
language_preference: list[str] = Field(default_factory=list, description="语言偏好")
location_preference: str | None = Field(
default=None, description="地点偏好,如喜欢远程"
)
work_lifestyle: str | None = Field(default=None, description="作息方式,如早睡早起")
notification_preference: list[str] = Field(
default_factory=list, description="通知方式偏好"
)
class SchedulingPreferences(BaseModel):
productive_windows: list[TimeWindow] = Field(
default_factory=list, description="高效率时段"
)
preferred_meeting_windows: list[TimeWindow] = Field(
default_factory=list, description="偏好的会议时段"
)
no_meeting_windows: list[TimeWindow] = Field(
default_factory=list, description="尽量不安排会议的时段"
)
deep_work_windows: list[TimeWindow] = Field(
default_factory=list, description="深度工作时段"
)
preferred_meeting_duration_minutes: list[int] = Field(
default_factory=lambda: [30, 60], description="偏好的会议时长"
)
meeting_buffer_minutes: int | None = Field(
default=None, ge=0, description="会议间缓冲时间"
)
max_meetings_per_day: int | None = Field(
default=None, ge=0, description="单日会议上限"
)
notes: str | None = Field(default=None, description="其他排程说明")
class RecurringRoutine(BaseModel):
name: str = Field(description="周期性安排名称")
description: str | None = Field(default=None, description="周期性安排描述")
cadence: str | None = Field(
default=None, description="频率,如daily/weekly/monthly"
)
time_windows: list[TimeWindow] = Field(
default_factory=list, description="通常发生时段"
)
importance: str | None = Field(default=None, description="重要程度")
meta: MemoryMeta = Field(default_factory=MemoryMeta)
class UserMemoryContent(BaseModel):
model_config = ConfigDict(extra="allow")
occupation: str | None = Field(default=None, description="职业")
timezone: str | None = Field(default=None, description="时区")
primary_language: str | None = Field(default=None, description="主要语言")
people: list[PersonMemory] = Field(default_factory=list, description="重要人物")
places: list[PlaceMemory] = Field(default_factory=list, description="常去地点")
preferences: UserPreferences = Field(default_factory=UserPreferences)
scheduling_preferences: SchedulingPreferences = Field(
default_factory=SchedulingPreferences
)
interests: list[str] = Field(default_factory=list, description="兴趣爱好")
avoid_topics: list[str] = Field(default_factory=list, description="不想讨论的话题")
custom_rules: list[str] = Field(default_factory=list, description="用户自定义规则")
recurring_routines: list[RecurringRoutine] = Field(
default_factory=list, description="周期性习惯/安排"
)
class Milestone(BaseModel):
name: str = Field(description="里程碑名称")
due_date: date | None = Field(default=None, description="截止日期")
status: str | None = Field(default=None, description="状态")
notes: str | None = Field(default=None, description="补充说明")
class WorkProject(BaseModel):
name: str = Field(description="项目名")
description: str | None = Field(default=None, description="项目描述")
status: ProjectStatus | None = Field(default=None, description="项目状态")
priority: str | None = Field(default=None, description="项目优先级")
deadline: date | None = Field(default=None, description="项目截止时间")
collaborators: list[str] = Field(default_factory=list, description="协作人")
key_milestones: list[Milestone] = Field(
default_factory=list, description="关键里程碑"
)
notes: str | None = Field(default=None, description="补充说明")
meta: MemoryMeta = Field(default_factory=MemoryMeta)
class WorkHabit(BaseModel):
available_hours: list[TimeWindow] = Field(
default_factory=list, description="常规可工作时间"
)
deep_work_blocks: list[TimeWindow] = Field(
default_factory=list, description="偏好的深度工作时间"
)
preferred_meeting_windows: list[TimeWindow] = Field(
default_factory=list, description="偏好的会议时间"
)
no_meeting_windows: list[TimeWindow] = Field(
default_factory=list, description="不希望开会的时间"
)
preferred_meeting_duration_minutes: list[int] = Field(
default_factory=lambda: [30, 60], description="偏好的会议时长"
)
notification_channel: str | None = Field(default=None, description="首选沟通渠道")
notes: str | None = Field(default=None, description="补充说明")
class TeamMember(BaseModel):
name: str = Field(description="成员姓名")
role: str | None = Field(default=None, description="团队角色")
relationship: str | None = Field(
default=None, description="关系,如直属上级/同事/合作方"
)
preferred_contact_channel: str | None = Field(
default=None, description="偏好沟通渠道"
)
notes: str | None = Field(default=None, description="补充说明")
meta: MemoryMeta = Field(default_factory=MemoryMeta)
class WorkProfileContent(BaseModel):
model_config = ConfigDict(extra="allow")
occupation: str | None = Field(default=None, description="职业身份")
expertise: list[str] = Field(default_factory=list, description="专业领域")
preferred_tools: list[str] = Field(default_factory=list, description="惯用工具")
current_projects: list[WorkProject] = Field(
default_factory=list, description="长期项目画像"
)
work_habits: WorkHabit = Field(default_factory=WorkHabit)
team_members: list[TeamMember] = Field(default_factory=list, description="团队成员")
team_context: str | None = Field(default=None, description="团队背景")
work_rules: list[str] = Field(
default_factory=list, description="工作规则或默认原则"
)