44
55import time
66import uuid
7- from typing import Literal , Optional
7+ from typing import Literal
88
99from open_webui .internal .db import Base , get_async_db_context
1010from pydantic import BaseModel , ConfigDict
11- from sqlalchemy import BigInteger , Column , String , Text , delete , select
11+ from sqlalchemy import JSON , BigInteger , Column , String , Text , delete , select
1212from sqlalchemy .ext .asyncio import AsyncSession
1313
1414
@@ -20,7 +20,9 @@ class Memory(Base): # user memory store
2020 id = Column (String , primary_key = True , unique = True )
2121 user_id = Column (String , index = True )
2222 type = Column (String , default = 'context' , server_default = 'context' , index = True )
23+ path = Column (Text , nullable = True )
2324 content = Column (Text ) # free-form text learned from conversation
25+ meta = Column (JSON , nullable = True )
2426 updated_at = Column (BigInteger ) # epoch seconds
2527 created_at = Column (BigInteger ) # epoch seconds
2628
@@ -31,7 +33,9 @@ class MemoryModel(BaseModel):
3133 id : str
3234 user_id : str
3335 type : Literal ['user' , 'context' ] = 'context'
36+ path : str | None = None
3437 content : str
38+ meta : dict | None = None
3539 updated_at : int # timestamp in epoch
3640 created_at : int # timestamp in epoch
3741 model_config = ConfigDict (from_attributes = True ) # allows ORM mapping
@@ -47,6 +51,8 @@ async def insert_new_memory(
4751 user_id : str ,
4852 content : str ,
4953 memory_type : str | None = None ,
54+ path : str | None = None ,
55+ meta : dict | None = None ,
5056 db : AsyncSession | None = None ,
5157 ) -> MemoryModel | None :
5258 """Persist a new memory entry and return the created model."""
@@ -56,7 +62,9 @@ async def insert_new_memory(
5662 id = str (uuid .uuid4 ()),
5763 user_id = user_id ,
5864 type = self .normalize_memory_type (memory_type ),
65+ path = path ,
5966 content = content ,
67+ meta = meta ,
6068 created_at = now ,
6169 updated_at = now ,
6270 )
@@ -71,6 +79,9 @@ async def update_memory_by_id_and_user_id(
7179 user_id : str ,
7280 content : str | None ,
7381 memory_type : str | None = None ,
82+ path : str | None = None ,
83+ update_path : bool = False ,
84+ meta : dict | None = None ,
7485 db : AsyncSession | None = None ,
7586 ) -> MemoryModel | None :
7687 async with get_async_db_context (db ) as db :
@@ -83,6 +94,10 @@ async def update_memory_by_id_and_user_id(
8394 memory .content = content
8495 if memory_type is not None :
8596 memory .type = self .normalize_memory_type (memory_type )
97+ if update_path :
98+ memory .path = path
99+ if meta is not None :
100+ memory .meta = {** (memory .meta or {}), ** meta }
86101 memory .updated_at = int (time .time ())
87102
88103 await db .commit ()
@@ -167,8 +182,9 @@ async def apply_memory_operations(
167182 if action == 'add' :
168183 content = operation .get ('content' , '' ).strip ()
169184 memory_type = self .normalize_memory_type (operation .get ('type' ))
185+ path = operation .get ('path' )
170186 result = await db .execute (
171- select (Memory ).filter_by (user_id = user_id , content = content , type = memory_type )
187+ select (Memory ).filter_by (user_id = user_id , content = content , type = memory_type , path = path )
172188 )
173189 existing = result .scalars ().first ()
174190 if existing :
@@ -186,7 +202,9 @@ async def apply_memory_operations(
186202 id = str (uuid .uuid4 ()),
187203 user_id = user_id ,
188204 type = memory_type ,
205+ path = path ,
189206 content = content ,
207+ meta = operation .get ('meta' ),
190208 created_at = now ,
191209 updated_at = now ,
192210 )
@@ -204,6 +222,23 @@ async def apply_memory_operations(
204222 memory .content = content
205223 if operation .get ('type' ) is not None :
206224 memory .type = self .normalize_memory_type (operation .get ('type' ))
225+ if 'path' in operation :
226+ memory .path = operation .get ('path' )
227+ if operation .get ('meta' ) is not None :
228+ memory .meta = {** (memory .meta or {}), ** operation .get ('meta' )}
229+ memory .updated_at = now
230+ await db .flush ()
231+ results .append ({'action' : action , 'status' : 'updated' , 'memory' : MemoryModel .model_validate (memory )})
232+
233+ elif action == 'move' :
234+ memory_id = operation .get ('id' )
235+ memory = await db .get (Memory , memory_id )
236+ if not memory or memory .user_id != user_id :
237+ raise ValueError (f'Memory not found: { memory_id } ' )
238+
239+ memory .path = operation .get ('path' )
240+ if operation .get ('meta' ) is not None :
241+ memory .meta = {** (memory .meta or {}), ** operation .get ('meta' )}
207242 memory .updated_at = now
208243 await db .flush ()
209244 results .append ({'action' : action , 'status' : 'updated' , 'memory' : MemoryModel .model_validate (memory )})
0 commit comments