Simplify chat UI and wire memory context
This commit is contained in:
@@ -15,6 +15,7 @@ class MemoryRecord(BaseModel):
|
||||
id: int | None = None
|
||||
memory_id: str
|
||||
text: str
|
||||
scope: str = "workspace"
|
||||
workspace: str
|
||||
conversation_id: str | None = None
|
||||
memory_type: str = "note"
|
||||
@@ -37,6 +38,7 @@ class MemoryStore:
|
||||
id integer primary key autoincrement,
|
||||
memory_id text not null unique,
|
||||
text text not null,
|
||||
scope text not null default 'workspace',
|
||||
workspace text not null,
|
||||
conversation_id text,
|
||||
memory_type text not null,
|
||||
@@ -53,12 +55,22 @@ class MemoryStore:
|
||||
on memories(workspace, created_at)
|
||||
"""
|
||||
)
|
||||
await self._ensure_scope_column(db)
|
||||
await db.commit()
|
||||
|
||||
async def _ensure_scope_column(self, db: aiosqlite.Connection) -> None:
|
||||
cursor = await db.execute("pragma table_info(memories)")
|
||||
columns = {row[1] for row in await cursor.fetchall()}
|
||||
if "scope" not in columns:
|
||||
await db.execute(
|
||||
"alter table memories add column scope text not null default 'workspace'"
|
||||
)
|
||||
|
||||
async def add(
|
||||
self,
|
||||
text: str,
|
||||
workspace: str,
|
||||
scope: str = "workspace",
|
||||
conversation_id: str | None = None,
|
||||
memory_type: str = "note",
|
||||
importance: float = 0.5,
|
||||
@@ -72,13 +84,14 @@ class MemoryStore:
|
||||
cursor = await db.execute(
|
||||
"""
|
||||
insert into memories(
|
||||
memory_id, text, workspace, conversation_id, memory_type,
|
||||
memory_id, text, scope, workspace, conversation_id, memory_type,
|
||||
importance, metadata_json, created_at, updated_at
|
||||
) values (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
memory_id,
|
||||
clean_text,
|
||||
self._normalize_scope(scope),
|
||||
workspace,
|
||||
conversation_id,
|
||||
memory_type or "note",
|
||||
@@ -94,6 +107,7 @@ class MemoryStore:
|
||||
id=row_id,
|
||||
memory_id=memory_id,
|
||||
text=clean_text,
|
||||
scope=self._normalize_scope(scope),
|
||||
workspace=workspace,
|
||||
conversation_id=conversation_id,
|
||||
memory_type=memory_type or "note",
|
||||
@@ -114,7 +128,7 @@ class MemoryStore:
|
||||
cursor = await db.execute(
|
||||
"""
|
||||
select * from memories
|
||||
where workspace = ?
|
||||
where workspace = ? or scope = 'global'
|
||||
order by importance desc, created_at desc
|
||||
limit ?
|
||||
""",
|
||||
@@ -164,11 +178,75 @@ class MemoryStore:
|
||||
rows = await cursor.fetchall()
|
||||
return [self._row_to_record(row) for row in rows]
|
||||
|
||||
async def relevant(
|
||||
self,
|
||||
workspace: str,
|
||||
conversation_id: str | None = None,
|
||||
query: str = "",
|
||||
limit: int = 8,
|
||||
) -> list[MemoryRecord]:
|
||||
await self.init()
|
||||
bounded_limit = min(max(limit, 1), 30)
|
||||
terms = [term.lower() for term in query.split() if len(term) >= 3]
|
||||
async with aiosqlite.connect(self.db_path) as db:
|
||||
db.row_factory = aiosqlite.Row
|
||||
cursor = await db.execute(
|
||||
"""
|
||||
select * from memories
|
||||
where scope = 'global'
|
||||
or (scope = 'workspace' and workspace = ?)
|
||||
or (scope = 'conversation' and workspace = ? and conversation_id = ?)
|
||||
order by
|
||||
case scope
|
||||
when 'global' then 0
|
||||
when 'conversation' then 1
|
||||
else 2
|
||||
end,
|
||||
importance desc,
|
||||
created_at desc
|
||||
limit ?
|
||||
""",
|
||||
(workspace, workspace, conversation_id, bounded_limit * 3),
|
||||
)
|
||||
rows = await cursor.fetchall()
|
||||
records = [self._row_to_record(row) for row in rows]
|
||||
if not terms:
|
||||
return records[:bounded_limit]
|
||||
matching = [
|
||||
record
|
||||
for record in records
|
||||
if any(term in record.text.lower() for term in terms)
|
||||
or record.scope == "global"
|
||||
]
|
||||
return matching[:bounded_limit]
|
||||
|
||||
def infer_scope(self, text: str, workspace: str, conversation_id: str | None) -> str:
|
||||
lowered = text.lower()
|
||||
global_markers = (
|
||||
"user prefers",
|
||||
"пользователь предпочитает",
|
||||
"отвечай",
|
||||
"always",
|
||||
"всегда",
|
||||
"rx580",
|
||||
"radeon",
|
||||
"vulkan",
|
||||
)
|
||||
if any(marker in lowered for marker in global_markers):
|
||||
return "global"
|
||||
if conversation_id and any(marker in lowered for marker in ("this chat", "этот чат", "диалог")):
|
||||
return "conversation"
|
||||
return "workspace" if workspace else "global"
|
||||
|
||||
def _normalize_scope(self, scope: str) -> str:
|
||||
return scope if scope in {"global", "workspace", "conversation"} else "workspace"
|
||||
|
||||
def _row_to_record(self, row: aiosqlite.Row) -> MemoryRecord:
|
||||
return MemoryRecord(
|
||||
id=row["id"],
|
||||
memory_id=row["memory_id"],
|
||||
text=row["text"],
|
||||
scope=row["scope"],
|
||||
workspace=row["workspace"],
|
||||
conversation_id=row["conversation_id"],
|
||||
memory_type=row["memory_type"],
|
||||
|
||||
Reference in New Issue
Block a user