Add LRU Cache + Add App_Id / User_Id to resource tables (#107)

* init LRU cache

* update schemas

* fix tests

* fix sql queries

* make user_id/app_id nullable

* add migration

* enhance migration and change query in agent.py

* make cache asyncio safe

* add index to migrations and add utils

* fix fkey naming convention

* coderabbit comments

* remove remaining joins from crud and agent

* fix test
This commit is contained in:
Rajat Ahuja 2025-05-14 15:50:24 -04:00 committed by GitHub
parent ecced6b9f8
commit d0285189c3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 772 additions and 120 deletions

32
migrations/utils.py Normal file
View File

@ -0,0 +1,32 @@
from os import getenv
from typing import Optional
from alembic import op
import sqlalchemy as sa
def get_schema() -> str:
return getenv("DATABASE_SCHEMA", "public")
def column_exists(table_name: str, column_name: str, inspector: Optional[sa.Inspector] = None) -> bool:
"""Check if a column exists in a table."""
if inspector is None:
inspector = sa.inspect(op.get_bind())
schema = get_schema()
existing_columns = [col["name"] for col in inspector.get_columns(table_name, schema=schema)]
return column_name in existing_columns
def fk_exists(table_name: str, fk_name: str, inspector: Optional[sa.Inspector] = None) -> bool:
"""Check if a foreign key exists in a table."""
if inspector is None:
inspector = sa.inspect(op.get_bind())
schema = get_schema()
foreign_keys = inspector.get_foreign_keys(table_name, schema=schema)
return any(fk.get("name") == fk_name for fk in foreign_keys)
def index_exists(table_name: str, index_name: str, inspector: Optional[sa.Inspector] = None) -> bool:
"""Check if an index exists in a table."""
if inspector is None:
inspector = sa.inspect(op.get_bind())
schema = get_schema()
indexes = inspector.get_indexes(table_name, schema=schema)
return any(idx["name"] == index_name for idx in indexes)

View File

@ -0,0 +1,493 @@
"""add user id and app id to tables
Revision ID: 556a16564f50
Revises: b765d82110bd
Create Date: 2025-05-13 17:10:33.805495
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
from sqlalchemy.exc import IntegrityError, ProgrammingError
from migrations.utils import (
get_schema,
column_exists,
fk_exists,
index_exists,
)
# revision identifiers, used by Alembic.
revision: str = '556a16564f50'
down_revision: Union[str, None] = 'b765d82110bd'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
schema = get_schema()
conn = op.get_bind()
inspector = sa.inspect(conn)
# 1. SESSIONS TABLE
if not column_exists("sessions", "app_id", inspector):
op.add_column("sessions", sa.Column("app_id", sa.Text(), nullable=True), schema=schema)
print("Added app_id column to sessions table")
else:
print("app_id column already exists in sessions table")
# Create foreign key constraint for app_id
if not fk_exists("sessions", "sessions_app_id_fkey", inspector):
try:
op.create_foreign_key(
"sessions_app_id_fkey",
"sessions",
"apps",
["app_id"],
["public_id"],
source_schema=schema,
referent_schema=schema
)
print("Created app_id foreign key for sessions table")
except IntegrityError:
print("Cannot create app_id foreign key for sessions table - integrity error")
else:
print("app_id foreign key already exists for sessions table")
# Data migration: Fill app_id from users table
try:
op.execute("""
UPDATE sessions s
SET app_id = u.app_id
FROM users u
WHERE s.user_id = u.public_id
AND (s.app_id IS NULL OR s.app_id <> u.app_id)
""")
print("Updated app_id values from users for sessions table")
except Exception as e:
print(f"Error updating app_id values for sessions table: {e}")
# Make app_id non-nullable
try:
op.alter_column("sessions", "app_id", nullable=False, schema=schema)
print("Made app_id non-nullable for sessions table")
except (ProgrammingError, IntegrityError) as e:
print(f"Error making app_id non-nullable for sessions table: {e}")
# Create index for sessions.app_id
if not index_exists("sessions", "ix_sessions_app_id"):
op.create_index(op.f("ix_sessions_app_id"), "sessions", ["app_id"], unique=False, schema=schema)
print("Created index ix_sessions_app_id")
else:
print("Index ix_sessions_app_id already exists")
# 2. MESSAGES TABLE
if not column_exists("messages", "app_id", inspector):
op.add_column("messages", sa.Column("app_id", sa.Text()), schema=schema)
print("Added app_id column to messages table")
else:
print("app_id column already exists in messages table")
if not column_exists("messages", "user_id", inspector):
op.add_column("messages", sa.Column("user_id", sa.Text()), schema=schema)
print("Added user_id column to messages table")
else:
print("user_id column already exists in messages table")
# Create foreign key constraints for app_id and user_id
if not fk_exists("messages", "messages_app_id_fkey", inspector):
try:
op.create_foreign_key(
"messages_app_id_fkey",
"messages",
"apps",
["app_id"],
["public_id"],
source_schema=schema,
referent_schema=schema
)
print("Created app_id foreign key for messages table")
except IntegrityError:
print("Cannot create app_id foreign key for messages table - integrity error")
else:
print("app_id foreign key already exists for messages table")
if not fk_exists("messages", "messages_user_id_fkey", inspector):
try:
op.create_foreign_key(
"messages_user_id_fkey",
"messages",
"users",
["user_id"],
["public_id"],
source_schema=schema,
referent_schema=schema
)
print("Created user_id foreign key for messages table")
except IntegrityError:
print("Cannot create user_id foreign key for messages table - integrity error")
else:
print("user_id foreign key already exists for messages table")
# Data migration: Fill app_id and user_id from sessions table
try:
op.execute("""
UPDATE messages m
SET app_id = s.app_id, user_id = s.user_id
FROM sessions s
WHERE m.session_id = s.public_id
AND (
m.app_id IS NULL OR m.app_id <> s.app_id OR
m.user_id IS NULL OR m.user_id <> s.user_id
)
""")
print("Updated app_id and user_id values from sessions for messages table")
except Exception as e:
print(f"Error updating app_id and user_id values for messages table: {e}")
# Make app_id and user_id non-nullable
try:
op.alter_column("messages", "app_id", nullable=False, schema=schema)
op.alter_column("messages", "user_id", nullable=False, schema=schema)
print("Made app_id and user_id non-nullable for messages table")
except (ProgrammingError, IntegrityError) as e:
print(f"Error making app_id and user_id non-nullable for messages table: {e}")
# Create indices for messages foreign keys
if not index_exists("messages", "ix_messages_app_id"):
op.create_index(op.f("ix_messages_app_id"), "messages", ["app_id"], unique=False, schema=schema)
print("Created index ix_messages_app_id")
else:
print("Index ix_messages_app_id already exists")
if not index_exists("messages", "ix_messages_user_id"):
op.create_index(op.f("ix_messages_user_id"), "messages", ["user_id"], unique=False, schema=schema)
print("Created index ix_messages_user_id")
else:
print("Index ix_messages_user_id already exists")
# 3. METAMESSAGES TABLE
if not column_exists("metamessages", "app_id", inspector):
op.add_column("metamessages", sa.Column("app_id", sa.Text()), schema=schema)
print("Added app_id column to metamessages table")
else:
print("app_id column already exists in metamessages table")
# Create foreign key constraint for app_id
if not fk_exists("metamessages", "metamessages_app_id_fkey", inspector):
try:
op.create_foreign_key(
"metamessages_app_id_fkey",
"metamessages",
"apps",
["app_id"],
["public_id"],
source_schema=schema,
referent_schema=schema
)
print("Created app_id foreign key for metamessages table")
except IntegrityError:
print("Cannot create app_id foreign key for metamessages table - integrity error")
else:
print("app_id foreign key already exists for metamessages table")
# Data migration: Fill app_id from users table
try:
op.execute("""
UPDATE metamessages m
SET app_id = u.app_id
FROM users u
WHERE m.user_id = u.public_id
AND (m.app_id IS NULL OR m.app_id <> u.app_id)
""")
print("Updated app_id values from users")
except Exception as e:
print(f"Error updating app_id values: {e}")
# Make app_id non-nullable
try:
op.alter_column("metamessages", "app_id", nullable=False, schema=schema)
print("Made app_id non-nullable for metamessages table")
except (ProgrammingError, IntegrityError) as e:
print(f"Error making app_id non-nullable for metamessages table: {e}")
# Create index for metamessages.app_id
if not index_exists("metamessages", "ix_metamessages_app_id"):
op.create_index(op.f("ix_metamessages_app_id"), "metamessages", ["app_id"], unique=False, schema=schema)
print("Created index ix_metamessages_app_id")
else:
print("Index ix_metamessages_app_id already exists")
# 4. COLLECTIONS TABLE
if not column_exists("collections", "app_id", inspector):
op.add_column("collections", sa.Column("app_id", sa.Text()), schema=schema)
print("Added app_id column to collections table")
else:
print("app_id column already exists in collections table")
# Create foreign key constraint for app_id
if not fk_exists("collections", "collections_app_id_fkey", inspector):
try:
op.create_foreign_key(
"collections_app_id_fkey",
"collections",
"apps",
["app_id"],
["public_id"],
source_schema=schema,
referent_schema=schema
)
print("Created app_id foreign key for collections table")
except IntegrityError:
print("Cannot create app_id foreign key for collections table - integrity error")
else:
print("app_id foreign key already exists for collections table")
# Data migration: Fill app_id from users table
try:
op.execute("""
UPDATE collections c
SET app_id = u.app_id
FROM users u
WHERE c.user_id = u.public_id
AND (c.app_id IS NULL OR c.app_id <> u.app_id)
""")
print("Updated app_id values from users for collections table")
except Exception as e:
print(f"Error updating app_id values for collections table: {e}")
# Make app_id non-nullable
try:
op.alter_column("collections", "app_id", nullable=False, schema=schema)
print("Made app_id non-nullable for collections table")
except (ProgrammingError, IntegrityError) as e:
print(f"Error making app_id non-nullable for collections table: {e}")
# Create index for collections.app_id
if not index_exists("collections", "ix_collections_app_id"):
op.create_index(op.f("ix_collections_app_id"), "collections", ["app_id"], unique=False, schema=schema)
print("Created index ix_collections_app_id")
else:
print("Index ix_collections_app_id already exists")
# 5. DOCUMENTS TABLE
if not column_exists("documents", "app_id", inspector):
op.add_column("documents", sa.Column("app_id", sa.Text()), schema=schema)
print("Added app_id column to documents table")
else:
print("app_id column already exists in documents table")
if not column_exists("documents", "user_id", inspector):
op.add_column("documents", sa.Column("user_id", sa.Text()), schema=schema)
print("Added user_id column to documents table")
else:
print("user_id column already exists in documents table")
# Create foreign key constraints for app_id and user_id
if not fk_exists("documents", "documents_app_id_fkey", inspector):
try:
op.create_foreign_key(
"documents_app_id_fkey",
"documents",
"apps",
["app_id"],
["public_id"],
source_schema=schema,
referent_schema=schema
)
print("Created app_id foreign key for documents table")
except IntegrityError:
print("Cannot create app_id foreign key for documents table - integrity error")
else:
print("app_id foreign key already exists for documents table")
if not fk_exists("documents", "documents_user_id_fkey", inspector):
try:
op.create_foreign_key(
"documents_user_id_fkey",
"documents",
"users",
["user_id"],
["public_id"],
source_schema=schema,
referent_schema=schema
)
print("Created user_id foreign key for documents table")
except IntegrityError:
print("Cannot create user_id foreign key for documents table - integrity error")
else:
print("user_id foreign key already exists for documents table")
# Data migration: Fill app_id and user_id from collections table
try:
op.execute("""
UPDATE documents d
SET app_id = c.app_id, user_id = c.user_id
FROM collections c
WHERE d.collection_id = c.public_id
AND (
d.app_id IS NULL OR d.app_id <> c.app_id OR
d.user_id IS NULL OR d.user_id <> c.user_id
)
""")
print("Updated app_id and user_id values from collections for documents table")
except Exception as e:
print(f"Error updating app_id and user_id values for documents table: {e}")
# Make app_id and user_id non-nullable
try:
op.alter_column("documents", "app_id", nullable=False, schema=schema)
op.alter_column("documents", "user_id", nullable=False, schema=schema)
print("Made app_id and user_id non-nullable for documents table")
except (ProgrammingError, IntegrityError) as e:
print(f"Error making app_id and user_id non-nullable for documents table: {e}")
# Create indices for documents foreign keys
if not index_exists("documents", "ix_documents_app_id"):
op.create_index(op.f("ix_documents_app_id"), "documents", ["app_id"], unique=False, schema=schema)
print("Created index ix_documents_app_id")
else:
print("Index ix_documents_app_id already exists")
if not index_exists("documents", "ix_documents_user_id"):
op.create_index(op.f("ix_documents_user_id"), "documents", ["user_id"], unique=False, schema=schema)
print("Created index ix_documents_user_id")
else:
print("Index ix_documents_user_id already exists")
def downgrade():
schema = get_schema()
inspector = sa.inspect(op.get_bind())
# 5. Documents table
# Drop indices
if index_exists("documents", "ix_documents_app_id", inspector):
op.drop_index("ix_documents_app_id", table_name="documents", schema=schema)
print("Dropped index ix_documents_app_id")
if index_exists("documents", "ix_documents_user_id", inspector):
op.drop_index("ix_documents_user_id", table_name="documents", schema=schema)
print("Dropped index ix_documents_user_id")
# Make app_id and user_id nullable again
op.alter_column("documents", "app_id", nullable=True, schema=schema)
op.alter_column("documents", "user_id", nullable=True, schema=schema)
print("Made app_id and user_id nullable again for documents table")
# Drop foreign key constraints
try:
op.drop_constraint("documents_user_id_fkey", "documents", schema=schema)
print("Dropped user_id foreign key for documents table")
except Exception as e:
print(f"Error dropping user_id foreign key for documents table: {e}")
try:
op.drop_constraint("documents_app_id_fkey", "documents", schema=schema)
print("Dropped app_id foreign key for documents table")
except Exception as e:
print(f"Error dropping app_id foreign key for documents table: {e}")
# Drop the columns
op.drop_column("documents", "user_id", schema=schema)
op.drop_column("documents", "app_id", schema=schema)
print("Dropped app_id and user_id columns from documents table")
# 4. Collections table
# Drop indices
if index_exists("collections", "ix_collections_app_id", inspector):
op.drop_index("ix_collections_app_id", table_name="collections", schema=schema)
print("Dropped index ix_collections_app_id")
# Make app_id nullable again
op.alter_column("collections", "app_id", nullable=True, schema=schema)
print("Made app_id nullable again for collections table")
# Drop foreign key constraint
try:
op.drop_constraint("collections_app_id_fkey", "collections", schema=schema)
print("Dropped app_id foreign key for collections table")
except Exception as e:
print(f"Error dropping app_id foreign key for collections table: {e}")
# Drop the column
op.drop_column("collections", "app_id", schema=schema)
print("Dropped app_id column from collections table")
# 3. Metamessages table
# Drop indices
if index_exists("metamessages", "ix_metamessages_app_id", inspector):
op.drop_index("ix_metamessages_app_id", table_name="metamessages", schema=schema)
print("Dropped index ix_metamessages_app_id")
# Make app_id nullable again
op.alter_column("metamessages", "app_id", nullable=True, schema=schema)
print("Made app_id nullable again for metamessages table")
# Drop foreign key constraint
try:
op.drop_constraint("metamessages_app_id_fkey", "metamessages", schema=schema)
print("Dropped app_id foreign key for metamessages table")
except Exception as e:
print(f"Error dropping app_id foreign key for metamessages table: {e}")
# Drop the column
op.drop_column("metamessages", "app_id", schema=schema)
print("Dropped app_id column from metamessages table")
# 2. Messages table
# Drop indices
if index_exists("messages", "ix_messages_app_id", inspector):
op.drop_index("ix_messages_app_id", table_name="messages", schema=schema)
print("Dropped index ix_messages_app_id")
if index_exists("messages", "ix_messages_user_id", inspector):
op.drop_index("ix_messages_user_id", table_name="messages", schema=schema)
print("Dropped index ix_messages_user_id")
# Make app_id and user_id nullable again
op.alter_column("messages", "app_id", nullable=True, schema=schema)
op.alter_column("messages", "user_id", nullable=True, schema=schema)
print("Made app_id and user_id nullable again for messages table")
# Drop foreign key constraints
try:
op.drop_constraint("messages_user_id_fkey", "messages", schema=schema)
print("Dropped user_id foreign key for messages table")
except Exception as e:
print(f"Error dropping user_id foreign key for messages table: {e}")
try:
op.drop_constraint("messages_app_id_fkey", "messages", schema=schema)
print("Dropped app_id foreign key for messages table")
except Exception as e:
print(f"Error dropping app_id foreign key for messages table: {e}")
# Drop the columns
op.drop_column("messages", "user_id", schema=schema)
op.drop_column("messages", "app_id", schema=schema)
print("Dropped app_id and user_id columns from messages table")
# 1. Sessions table
# Drop indices
if index_exists("sessions", "ix_sessions_app_id", inspector):
op.drop_index("ix_sessions_app_id", table_name="sessions", schema=schema)
print("Dropped index ix_sessions_app_id")
# Make app_id nullable again
op.alter_column("sessions", "app_id", nullable=True, schema=schema)
print("Made app_id nullable again for sessions table")
# Drop foreign key constraint
try:
op.drop_constraint("sessions_app_id_fkey", "sessions", schema=schema)
print("Dropped app_id foreign key for sessions table")
except Exception as e:
print(f"Error dropping app_id foreign key for sessions table: {e}")
# Drop the column
op.drop_column("sessions", "app_id", schema=schema)
print("Dropped app_id column from sessions table")

View File

@ -191,19 +191,16 @@ async def chat(
f"Created embedding store with collection_id: {collection.public_id if collection else None}"
)
# 2. Get the latest user message to attach the user representation to
stmt = (
select(models.Message)
.join(models.Session, models.Session.public_id == models.Message.session_id)
.join(models.User, models.User.public_id == models.Session.user_id)
.join(models.App, models.App.public_id == models.User.app_id)
.where(models.App.public_id == app_id)
.where(models.User.public_id == user_id)
.where(models.Message.session_id == session_id)
.where(models.Message.is_user)
.order_by(models.Message.id.desc())
.limit(1)
)
select(models.Message)
.where(models.Message.app_id == app_id)
.where(models.Message.user_id == user_id)
.where(models.Message.session_id == session_id)
.where(models.Message.is_user)
.order_by(models.Message.id.desc())
.limit(1)
)
latest_messages = await db.execute(stmt)
latest_message = latest_messages.scalar_one_or_none()
latest_message_id = latest_message.public_id if latest_message else None
@ -454,12 +451,7 @@ async def generate_user_representation(
logger.debug(f"Fetching latest representation for session {session_id}")
latest_representation_stmt = (
select(models.Metamessage)
.join(
models.Message,
models.Message.public_id == models.Metamessage.message_id,
)
.join(models.Session, models.Message.session_id == models.Session.public_id)
.where(models.Session.public_id == session_id) # Only from the same session
.where(models.Metamessage.session_id == session_id) # only from the same session
.where(
models.Metamessage.metamessage_type
== USER_REPRESENTATION_METAMESSAGE_TYPE

View File

@ -346,8 +346,7 @@ async def get_session(
"""
stmt = (
select(models.Session)
.join(models.User, models.User.public_id == models.Session.user_id)
.where(models.User.app_id == app_id)
.where(models.Session.app_id == app_id)
.where(models.Session.public_id == session_id)
)
if user_id is not None:
@ -361,7 +360,6 @@ async def get_session(
async def get_sessions(
db: AsyncSession,
app_id: str,
user_id: str,
reverse: Optional[bool] = False,
@ -370,8 +368,7 @@ async def get_sessions(
) -> Select:
stmt = (
select(models.Session)
.join(models.User, models.User.public_id == models.Session.user_id)
.where(models.User.app_id == app_id)
.where(models.Session.app_id == app_id)
.where(models.Session.user_id == user_id)
)
@ -416,6 +413,7 @@ async def create_session(
honcho_session = models.Session(
user_id=user_id,
app_id=app_id,
h_metadata=session.metadata,
)
db.add(honcho_session)
@ -488,10 +486,9 @@ async def delete_session(
"""
stmt = (
select(models.Session)
.join(models.User, models.User.public_id == models.Session.user_id)
.where(models.Session.public_id == session_id)
.where(models.User.app_id == app_id)
.where(models.Session.user_id == user_id)
.where(models.Session.app_id == app_id)
)
result = await db.execute(stmt)
honcho_session = result.scalar_one_or_none()
@ -531,10 +528,9 @@ async def clone_session(
# Get the original session
stmt = (
select(models.Session)
.join(models.User, models.User.public_id == models.Session.user_id)
.where(models.Session.public_id == original_session_id)
.where(models.Session.app_id == app_id)
.where(models.Session.user_id == user_id)
.where(models.User.app_id == app_id)
.where(models.Session.public_id == original_session_id)
)
original_session = await db.scalar(stmt)
if not original_session:
@ -556,6 +552,7 @@ async def clone_session(
# Create new session
new_session = models.Session(
user_id=original_session.user_id,
app_id=original_session.app_id,
h_metadata=original_session.h_metadata,
)
db.add(new_session)
@ -583,6 +580,8 @@ async def clone_session(
"content": message.content,
"is_user": message.is_user,
"h_metadata": message.h_metadata,
"app_id": original_session.app_id,
"user_id": original_session.user_id,
}
for message in messages_to_clone
]
@ -599,8 +598,10 @@ async def clone_session(
# Handle metamessages if deep copy is requested
if deep_copy:
# Fetch all metamessages tied to the session in a single query
stmt = select(models.Metamessage).where(
models.Metamessage.session_id == original_session_id
stmt = (
select(models.Metamessage)
.where(models.Metamessage.session_id == original_session_id)
.order_by(models.Metamessage.id) # Explicit ordering by id
)
if cutoff_message_id is not None and cutoff_message is not None:
# Only get metamessages related to messages we're cloning
@ -625,6 +626,7 @@ async def clone_session(
"metamessage_type": meta.metamessage_type,
"content": meta.content,
"h_metadata": meta.h_metadata,
"app_id": original_session.app_id,
}
# If the metamessage was tied to a message, tie it to the corresponding new message
@ -666,6 +668,8 @@ async def create_message(
is_user=message.is_user,
content=message.content,
h_metadata=message.metadata,
user_id=user_id,
app_id=app_id,
)
db.add(honcho_message)
await db.commit()
@ -696,6 +700,8 @@ async def create_messages(
"is_user": message.is_user,
"content": message.content,
"h_metadata": message.metadata,
"user_id": user_id,
"app_id": app_id,
}
for message in messages
]
@ -718,11 +724,8 @@ async def get_messages(
) -> Select:
stmt = (
select(models.Message)
.join(models.Session, models.Session.public_id == models.Message.session_id)
.join(models.User, models.User.public_id == models.Session.user_id)
.join(models.App, models.App.public_id == models.User.app_id)
.where(models.App.public_id == app_id)
.where(models.User.public_id == user_id)
.where(models.Message.app_id == app_id)
.where(models.Message.user_id == user_id)
.where(models.Message.session_id == session_id)
)
@ -746,11 +749,9 @@ async def get_message(
) -> Optional[models.Message]:
stmt = (
select(models.Message)
.join(models.Session, models.Session.public_id == models.Message.session_id)
.join(models.User, models.User.public_id == models.Session.user_id)
.where(models.User.app_id == app_id)
.where(models.User.public_id == user_id)
.where(models.Session.public_id == session_id)
.where(models.Message.app_id == app_id)
.where(models.Message.user_id == user_id)
.where(models.Message.session_id == session_id)
.where(models.Message.public_id == message_id)
)
result = await db.execute(stmt)
@ -798,6 +799,7 @@ async def create_metamessage(
# Initialize metamessage data
metamessage_data = {
"user_id": user_id,
"app_id": app_id,
"metamessage_type": metamessage.metamessage_type,
"content": metamessage.content,
"h_metadata": metamessage.metadata,
@ -855,10 +857,8 @@ async def get_metamessages(
# Base query starts with metamessage and user relationship
stmt = (
select(models.Metamessage)
.join(models.User, models.User.public_id == models.Metamessage.user_id)
.join(models.App, models.App.public_id == models.User.app_id)
.where(models.App.public_id == app_id)
.where(models.User.public_id == user_id)
.where(models.Metamessage.app_id == app_id)
.where(models.Metamessage.user_id == user_id)
)
# If session_id is provided, filter by it
@ -897,9 +897,8 @@ async def get_metamessage(
# Base query for metamessage by ID
stmt = (
select(models.Metamessage)
.join(models.User, models.User.public_id == models.Metamessage.user_id)
.where(models.User.app_id == app_id)
.where(models.User.public_id == user_id)
.where(models.Metamessage.app_id == app_id)
.where(models.Metamessage.user_id == user_id)
.where(models.Metamessage.public_id == metamessage_id)
)
@ -985,9 +984,8 @@ async def get_collections(
"""Get a distinct list of the names of collections associated with a user"""
stmt = (
select(models.Collection)
.join(models.User, models.User.public_id == models.Collection.user_id)
.where(models.User.app_id == app_id)
.where(models.User.public_id == user_id)
.where(models.Collection.app_id == app_id)
.where(models.Collection.user_id == user_id)
)
if filter is not None:
@ -1021,9 +1019,8 @@ async def get_collection_by_id(
"""
stmt = (
select(models.Collection)
.join(models.User, models.User.public_id == models.Collection.user_id)
.where(models.User.app_id == app_id)
.where(models.User.public_id == user_id)
.where(models.Collection.app_id == app_id)
.where(models.Collection.user_id == user_id)
.where(models.Collection.public_id == collection_id)
)
result = await db.execute(stmt)
@ -1058,9 +1055,8 @@ async def get_collection_by_name(
"""
stmt = (
select(models.Collection)
.join(models.User, models.User.public_id == models.Collection.user_id)
.where(models.User.app_id == app_id)
.where(models.User.public_id == user_id)
.where(models.Collection.app_id == app_id)
.where(models.Collection.user_id == user_id)
.where(models.Collection.name == name)
)
result = await db.execute(stmt)
@ -1109,6 +1105,7 @@ async def create_collection(
honcho_collection = models.Collection(
user_id=user_id,
app_id=app_id,
name=collection.name,
h_metadata=collection.metadata,
)
@ -1133,6 +1130,7 @@ async def create_user_protected_collection(
) -> models.Collection:
honcho_collection = models.Collection(
user_id=user_id,
app_id=app_id,
name=DEF_PROTECTED_COLLECTION_NAME,
)
try:
@ -1283,13 +1281,8 @@ async def get_documents(
) -> Select:
stmt = (
select(models.Document)
.join(
models.Collection,
models.Collection.public_id == models.Document.collection_id,
)
.join(models.User, models.User.public_id == models.Collection.user_id)
.where(models.User.app_id == app_id)
.where(models.User.public_id == user_id)
.where(models.Document.app_id == app_id)
.where(models.Document.user_id == user_id)
.where(models.Document.collection_id == collection_id)
)
@ -1329,13 +1322,8 @@ async def get_document(
"""
stmt = (
select(models.Document)
.join(
models.Collection,
models.Collection.public_id == models.Document.collection_id,
)
.join(models.User, models.User.public_id == models.Collection.user_id)
.where(models.User.app_id == app_id)
.where(models.User.public_id == user_id)
.where(models.Document.app_id == app_id)
.where(models.Document.user_id == user_id)
.where(models.Document.collection_id == collection_id)
.where(models.Document.public_id == document_id)
)
@ -1367,13 +1355,8 @@ async def query_documents(
embedding_query = response.data[0].embedding
stmt = (
select(models.Document)
.join(
models.Collection,
models.Collection.public_id == models.Document.collection_id,
)
.join(models.User, models.User.public_id == models.Collection.user_id)
.where(models.User.app_id == app_id)
.where(models.User.public_id == user_id)
.where(models.Document.app_id == app_id)
.where(models.Document.user_id == user_id)
.where(models.Document.collection_id == collection_id)
# .limit(top_k)
)
@ -1447,6 +1430,8 @@ async def create_document(
return duplicate
honcho_document = models.Document(
app_id=app_id,
user_id=user_id,
collection_id=collection_id,
content=document.content,
h_metadata=document.metadata,
@ -1454,6 +1439,7 @@ async def create_document(
)
db.add(honcho_document)
await db.commit()
await db.refresh(honcho_document)
return honcho_document
@ -1511,13 +1497,8 @@ async def delete_document(
)
stmt = (
select(models.Document)
.join(
models.Collection,
models.Collection.public_id == models.Document.collection_id,
)
.join(models.User, models.User.public_id == models.Collection.user_id)
.where(models.User.app_id == app_id)
.where(models.User.public_id == user_id)
.where(models.Document.app_id == app_id)
.where(models.Document.user_id == user_id)
.where(models.Document.collection_id == collection_id)
.where(models.Document.public_id == document_id)
)

View File

@ -92,6 +92,7 @@ class Session(Base):
messages = relationship("Message", back_populates="session")
metamessages = relationship("Metamessage", back_populates="session")
user_id: Mapped[str] = mapped_column(ForeignKey("users.public_id"), index=True)
app_id: Mapped[str] = mapped_column(ForeignKey("apps.public_id"), index=True)
user = relationship("User", back_populates="sessions")
__table_args__ = (
@ -124,6 +125,8 @@ class Message(Base):
)
session = relationship("Session", back_populates="messages")
metamessages = relationship("Metamessage", back_populates="message")
user_id: Mapped[str] = mapped_column(ForeignKey("users.public_id"), index=True)
app_id: Mapped[str] = mapped_column(ForeignKey("apps.public_id"), index=True)
__table_args__ = (
CheckConstraint("length(public_id) = 21", name="public_id_length"),
@ -154,6 +157,7 @@ class Metamessage(Base):
# Foreign keys - message_id is now optional
user_id: Mapped[str] = mapped_column(ForeignKey("users.public_id"), index=True)
app_id: Mapped[str] = mapped_column(ForeignKey("apps.public_id"), index=True)
session_id: Mapped[str | None] = mapped_column(
ForeignKey("sessions.public_id"), index=True, nullable=True
)
@ -236,6 +240,7 @@ class Collection(Base):
user_id: Mapped[str] = mapped_column(
TEXT, ForeignKey("users.public_id"), index=True
)
app_id: Mapped[str] = mapped_column(ForeignKey("apps.public_id"), index=True)
__table_args__ = (
UniqueConstraint("name", "user_id", name="unique_name_collection_user"),
@ -263,6 +268,8 @@ class Document(Base):
collection_id: Mapped[str] = mapped_column(
TEXT, ForeignKey("collections.public_id"), index=True
)
user_id: Mapped[str] = mapped_column(ForeignKey("users.public_id"), index=True)
app_id: Mapped[str] = mapped_column(ForeignKey("apps.public_id"), index=True)
collection = relationship("Collection", back_populates="documents")
__table_args__ = (

View File

@ -93,7 +93,6 @@ async def get_sessions(
return await paginate(
db,
await crud.get_sessions(
db,
app_id=app_id,
user_id=user_id,
reverse=reverse,

View File

@ -112,6 +112,8 @@ class Message(MessageBase):
h_metadata: dict = Field(exclude=True)
metadata: dict
created_at: datetime.datetime
app_id: str
user_id: str
@field_validator("metadata", mode="before")
def fetch_h_metadata(cls, value, info):
@ -150,6 +152,7 @@ class Session(SessionBase):
# messages: list[Message]
is_active: bool
user_id: str
app_id: str
h_metadata: dict = Field(exclude=True)
metadata: dict
@ -201,6 +204,7 @@ class Metamessage(MetamessageBase):
metamessage_type: str
content: str
user_id: str
app_id: str
session_id: str | None
message_id: str | None
h_metadata: dict = Field(exclude=True)
@ -256,6 +260,7 @@ class Collection(CollectionBase):
id: str
name: str
user_id: str
app_id: str
h_metadata: dict = Field(exclude=True)
metadata: dict
created_at: datetime.datetime
@ -306,6 +311,8 @@ class Document(DocumentBase):
metadata: dict
created_at: datetime.datetime
collection_id: str
app_id: str
user_id: str
@field_validator("metadata", mode="before")
def fetch_h_metadata(cls, value, info):

98
src/utils/cache.py Normal file
View File

@ -0,0 +1,98 @@
from collections import OrderedDict
import asyncio
class LRUCache:
"""
A simple asyncio-safe LRU cache implementation.
This cache automatically evicts the least recently used items when it reaches
its capacity limit. All operations are protected by an asyncio lock for
concurrent access safety.
"""
def __init__(self, capacity=100):
"""
Initialize the LRU cache.
Args:
capacity (int): Maximum number of items to store in the cache
"""
self._cache = OrderedDict()
self._capacity = max(1, capacity)
self._lock = asyncio.Lock()
async def get(self, key):
"""
Get a value from the cache.
Args:
key: The key to look up
Returns:
The cached value or None if not found
"""
async with self._lock:
if key not in self._cache:
return None
# Move accessed item to the end to mark as most recently used
value = self._cache.pop(key)
self._cache[key] = value
return value
async def put(self, key, value):
"""
Add or update an entry in the cache.
Args:
key: The key to store
value: The value to store
Returns:
The value that was stored
"""
async with self._lock:
# If key already exists, remove it first to update its position
if key in self._cache:
self._cache.pop(key)
# If at capacity, remove the least recently used item
elif len(self._cache) >= self._capacity:
self._cache.popitem(last=False)
# Add the new item
self._cache[key] = value
return value
async def delete(self, key):
"""
Remove an item from the cache.
Args:
key: The key to remove
Returns:
bool: True if the key was removed, False if it didn't exist
"""
async with self._lock:
if key in self._cache:
self._cache.pop(key)
return True
return False
def generate_cache_key(model_type: str, app_id: str, user_id: str, model_id: str):
"""
Generate a cache key for a given model type, app ID, user ID, and model ID.
Args:
model_type (str): The type of model to generate a cache key for (e.g. "collection", "document", "message", "session", "user")
app_id (str): The ID of the app to generate a cache key for
user_id (str): The ID of the user to generate a cache key for
model_id (str): The ID of the model to generate a cache key for
Returns:
str: A cache key for the given model type, app ID, user ID, and model ID
"""
return f"{model_type}:{app_id}:{user_id}:{model_id}"

View File

@ -7,7 +7,7 @@ from src import models # Import your SQLAlchemy models
async def test_create_message(client, db_session, sample_data):
test_app, test_user = sample_data
# Create a test session
test_session = models.Session(user_id=test_user.public_id)
test_session = models.Session(user_id=test_user.public_id, app_id=test_app.public_id)
db_session.add(test_session)
await db_session.commit()
@ -31,11 +31,11 @@ async def test_create_message(client, db_session, sample_data):
async def test_get_messages(client, db_session, sample_data):
test_app, test_user = sample_data
# Create a test session and message
test_session = models.Session(user_id=test_user.public_id)
test_session = models.Session(user_id=test_user.public_id, app_id=test_app.public_id)
db_session.add(test_session)
await db_session.commit()
test_message = models.Message(
session_id=test_session.public_id, content="Test message", is_user=True
session_id=test_session.public_id, content="Test message", is_user=True, app_id=test_app.public_id, user_id=test_user.public_id
)
db_session.add(test_message)
await db_session.commit()
@ -57,19 +57,23 @@ async def test_get_messages(client, db_session, sample_data):
async def test_get_filtered_messages(client, db_session, sample_data):
test_app, test_user = sample_data
# Create a test session and message
test_session = models.Session(user_id=test_user.public_id)
test_session = models.Session(user_id=test_user.public_id, app_id=test_app.public_id)
db_session.add(test_session)
await db_session.commit()
test_message = models.Message(
session_id=test_session.public_id,
content="Test message",
is_user=True,
app_id=test_app.public_id,
user_id=test_user.public_id,
h_metadata={"key": "value"},
)
test_message2 = models.Message(
session_id=test_session.public_id,
content="Test message",
is_user=True,
app_id=test_app.public_id,
user_id=test_user.public_id,
h_metadata={"key": "value2"},
)
db_session.add(test_message)
@ -94,11 +98,11 @@ async def test_get_filtered_messages(client, db_session, sample_data):
async def test_update_message(client, db_session, sample_data):
test_app, test_user = sample_data
# Create a test session and message
test_session = models.Session(user_id=test_user.public_id)
test_session = models.Session(user_id=test_user.public_id, app_id=test_app.public_id)
db_session.add(test_session)
await db_session.commit()
test_message = models.Message(
session_id=test_session.public_id, content="Test message", is_user=True
session_id=test_session.public_id, content="Test message", is_user=True, app_id=test_app.public_id, user_id=test_user.public_id
)
db_session.add(test_message)
await db_session.commit()
@ -116,11 +120,11 @@ async def test_update_message(client, db_session, sample_data):
async def test_update_message_empty_metadata(client, db_session, sample_data):
test_app, test_user = sample_data
# Create a test session and message
test_session = models.Session(user_id=test_user.public_id)
test_session = models.Session(user_id=test_user.public_id, app_id=test_app.public_id)
db_session.add(test_session)
await db_session.commit()
test_message = models.Message(
session_id=test_session.public_id, content="Test message", is_user=True
session_id=test_session.public_id, content="Test message", is_user=True, app_id=test_app.public_id, user_id=test_user.public_id
)
db_session.add(test_message)
await db_session.commit()
@ -139,7 +143,7 @@ async def test_update_message_empty_metadata(client, db_session, sample_data):
async def test_create_batch_messages(client, db_session, sample_data):
test_app, test_user = sample_data
# Create a test session
test_session = models.Session(user_id=test_user.public_id)
test_session = models.Session(user_id=test_user.public_id, app_id=test_app.public_id)
db_session.add(test_session)
await db_session.commit()
@ -187,7 +191,7 @@ async def test_create_batch_messages(client, db_session, sample_data):
@pytest.mark.asyncio
async def test_create_batch_messages_limit(client, db_session, sample_data):
test_app, test_user = sample_data
test_session = models.Session(user_id=test_user.public_id)
test_session = models.Session(user_id=test_user.public_id, app_id=test_app.public_id)
db_session.add(test_session)
await db_session.commit()

View File

@ -7,11 +7,11 @@ from src import models # Import your SQLAlchemy models
async def test_create_metamessage(client, db_session, sample_data):
test_app, test_user = sample_data
# Create a test session
test_session = models.Session(user_id=test_user.public_id)
test_session = models.Session(user_id=test_user.public_id, app_id=test_app.public_id)
db_session.add(test_session)
await db_session.commit()
test_message = models.Message(
session_id=test_session.public_id, content="Test message", is_user=True
session_id=test_session.public_id, content="Test message", is_user=True, app_id=test_app.public_id, user_id=test_user.public_id
)
db_session.add(test_message)
await db_session.commit()
@ -40,16 +40,17 @@ async def test_create_metamessage(client, db_session, sample_data):
async def test_get_metamessage(client, db_session, sample_data):
test_app, test_user = sample_data
# Create a test session
test_session = models.Session(user_id=test_user.public_id)
test_session = models.Session(user_id=test_user.public_id, app_id=test_app.public_id)
db_session.add(test_session)
await db_session.commit()
test_message = models.Message(
session_id=test_session.public_id, content="Test message", is_user=True
session_id=test_session.public_id, content="Test message", is_user=True, app_id=test_app.public_id, user_id=test_user.public_id
)
db_session.add(test_message)
await db_session.commit()
test_metamessage = models.Metamessage(
user_id=test_user.public_id,
app_id=test_app.public_id,
session_id=test_session.public_id,
message_id=test_message.public_id,
content="Test Metamessage",
@ -65,6 +66,7 @@ async def test_get_metamessage(client, db_session, sample_data):
assert response.status_code == 200
data = response.json()
assert data["user_id"] == str(test_user.public_id)
assert data["app_id"] == str(test_app.public_id)
assert data["session_id"] == str(test_session.public_id)
assert data["message_id"] == str(test_message.public_id)
assert data["content"] == "Test Metamessage"
@ -76,11 +78,11 @@ async def test_get_metamessage(client, db_session, sample_data):
async def test_get_metamessages_by_session(client, db_session, sample_data):
test_app, test_user = sample_data
# Create a test session
test_session = models.Session(user_id=test_user.public_id)
test_session = models.Session(user_id=test_user.public_id, app_id=test_app.public_id)
db_session.add(test_session)
await db_session.commit()
test_message = models.Message(
session_id=test_session.public_id, content="Test message", is_user=True
session_id=test_session.public_id, content="Test message", is_user=True, app_id=test_app.public_id, user_id=test_user.public_id
)
db_session.add(test_message)
await db_session.commit()
@ -88,6 +90,7 @@ async def test_get_metamessages_by_session(client, db_session, sample_data):
# Create metamessages for the same session
test_metamessage_1 = models.Metamessage(
user_id=test_user.public_id,
app_id=test_app.public_id,
session_id=test_session.public_id,
message_id=test_message.public_id,
content="Test Metamessage",
@ -96,6 +99,7 @@ async def test_get_metamessages_by_session(client, db_session, sample_data):
)
test_metamessage_2 = models.Metamessage(
user_id=test_user.public_id,
app_id=test_app.public_id,
session_id=test_session.public_id,
message_id=test_message.public_id,
content="Test Metamessage",
@ -104,6 +108,7 @@ async def test_get_metamessages_by_session(client, db_session, sample_data):
)
test_metamessage_3 = models.Metamessage(
user_id=test_user.public_id,
app_id=test_app.public_id,
session_id=test_session.public_id,
message_id=test_message.public_id,
content="Test Metamessage",
@ -112,6 +117,7 @@ async def test_get_metamessages_by_session(client, db_session, sample_data):
)
test_metamessage_4 = models.Metamessage(
user_id=test_user.public_id,
app_id=test_app.public_id,
session_id=test_session.public_id,
message_id=test_message.public_id,
content="Test Metamessage",
@ -141,15 +147,15 @@ async def test_get_metamessages_by_session(client, db_session, sample_data):
assert data["items"][0]["metamessage_type"] == "test_type"
assert data["items"][0]["session_id"] == str(test_session.public_id)
assert data["items"][0]["metadata"] == {}
assert data["items"][0]["app_id"] == str(test_app.public_id)
@pytest.mark.asyncio
async def test_get_metamessage_by_user(client, db_session, sample_data):
test_app, test_user = sample_data
# Create 3 test sessions
test_session_1 = models.Session(user_id=test_user.public_id)
test_session_2 = models.Session(user_id=test_user.public_id)
test_session_3 = models.Session(user_id=test_user.public_id)
test_session_1 = models.Session(user_id=test_user.public_id, app_id=test_app.public_id)
test_session_2 = models.Session(user_id=test_user.public_id, app_id=test_app.public_id)
test_session_3 = models.Session(user_id=test_user.public_id, app_id=test_app.public_id)
db_session.add(test_session_1)
db_session.add(test_session_2)
db_session.add(test_session_3)
@ -157,13 +163,13 @@ async def test_get_metamessage_by_user(client, db_session, sample_data):
# Create a message in each session
test_message_1 = models.Message(
session_id=test_session_1.public_id, content="Test message", is_user=True
session_id=test_session_1.public_id, content="Test message", is_user=True, app_id=test_app.public_id, user_id=test_user.public_id
)
test_message_2 = models.Message(
session_id=test_session_2.public_id, content="Test message", is_user=True
session_id=test_session_2.public_id, content="Test message", is_user=True, app_id=test_app.public_id, user_id=test_user.public_id
)
test_message_3 = models.Message(
session_id=test_session_3.public_id, content="Test message", is_user=True
session_id=test_session_3.public_id, content="Test message", is_user=True, app_id=test_app.public_id, user_id=test_user.public_id
)
db_session.add(test_message_1)
db_session.add(test_message_2)
@ -173,6 +179,7 @@ async def test_get_metamessage_by_user(client, db_session, sample_data):
# Create metamessages across different sessions
test_metamessage_1 = models.Metamessage(
user_id=test_user.public_id,
app_id=test_app.public_id,
session_id=test_session_1.public_id,
message_id=test_message_1.public_id,
content="Test Metamessage",
@ -181,6 +188,7 @@ async def test_get_metamessage_by_user(client, db_session, sample_data):
)
test_metamessage_2 = models.Metamessage(
user_id=test_user.public_id,
app_id=test_app.public_id,
session_id=test_session_2.public_id,
message_id=test_message_2.public_id,
content="Test Metamessage",
@ -189,6 +197,7 @@ async def test_get_metamessage_by_user(client, db_session, sample_data):
)
test_metamessage_3 = models.Metamessage(
user_id=test_user.public_id,
app_id=test_app.public_id,
session_id=test_session_3.public_id,
message_id=test_message_3.public_id,
content="Test Metamessage",
@ -197,6 +206,7 @@ async def test_get_metamessage_by_user(client, db_session, sample_data):
)
test_metamessage_4 = models.Metamessage(
user_id=test_user.public_id,
app_id=test_app.public_id,
session_id=test_session_3.public_id,
message_id=test_message_3.public_id,
content="Test Metamessage",
@ -206,6 +216,7 @@ async def test_get_metamessage_by_user(client, db_session, sample_data):
# Create a user-level metamessage (no session/message)
test_metamessage_5 = models.Metamessage(
user_id=test_user.public_id,
app_id=test_app.public_id,
content="User level metamessage",
h_metadata={},
metamessage_type="test_type",
@ -228,7 +239,7 @@ async def test_get_metamessage_by_user(client, db_session, sample_data):
assert data["items"][0]["content"] in ["Test Metamessage", "User level metamessage"]
assert data["items"][0]["metamessage_type"] == "test_type"
assert data["items"][0]["user_id"] == str(test_user.public_id)
assert data["items"][0]["app_id"] == str(test_app.public_id)
@pytest.mark.asyncio
async def test_create_user_level_metamessage(client, db_session, sample_data):
@ -251,22 +262,23 @@ async def test_create_user_level_metamessage(client, db_session, sample_data):
assert data["content"] == "User level insight"
assert data["metadata"] == {"source": "user_profile"}
assert data["metamessage_type"] == "user_insight"
assert data["app_id"] == str(test_app.public_id)
@pytest.mark.asyncio
async def test_update_metamessage(client, db_session, sample_data):
test_app, test_user = sample_data
# Create a test session
test_session = models.Session(user_id=test_user.public_id)
test_session = models.Session(user_id=test_user.public_id, app_id=test_app.public_id)
db_session.add(test_session)
await db_session.commit()
test_message = models.Message(
session_id=test_session.public_id, content="Test message", is_user=True
session_id=test_session.public_id, content="Test message", is_user=True, app_id=test_app.public_id, user_id=test_user.public_id
)
db_session.add(test_message)
await db_session.commit()
test_metamessage = models.Metamessage(
user_id=test_user.public_id,
app_id=test_app.public_id,
session_id=test_session.public_id,
message_id=test_message.public_id,
content="Test Metamessage",
@ -290,3 +302,4 @@ async def test_update_metamessage(client, db_session, sample_data):
assert data["user_id"] == str(test_user.public_id)
assert data["session_id"] == str(test_session.public_id)
assert data["message_id"] == str(test_message.public_id)
assert data["app_id"] == str(test_app.public_id)

View File

@ -59,7 +59,7 @@ async def test_get_sessions(client, db_session, sample_data):
async def test_empty_update_session(client, db_session, sample_data):
test_app, test_user = sample_data
# Create a test session
test_session = models.Session(user_id=test_user.public_id, h_metadata={})
test_session = models.Session(user_id=test_user.public_id, h_metadata={}, app_id=test_app.public_id)
db_session.add(test_session)
await db_session.commit()
@ -75,7 +75,7 @@ async def test_update_delete_metadata(client, db_session, sample_data):
test_app, test_user = sample_data
# Create a test session
test_session = models.Session(
user_id=test_user.public_id, h_metadata={"default": "value"}
user_id=test_user.public_id, h_metadata={"default": "value"}, app_id=test_app.public_id
)
db_session.add(test_session)
await db_session.commit()
@ -93,7 +93,7 @@ async def test_update_delete_metadata(client, db_session, sample_data):
async def test_update_session(client, db_session, sample_data):
test_app, test_user = sample_data
# Create a test session
test_session = models.Session(user_id=test_user.public_id, h_metadata={})
test_session = models.Session(user_id=test_user.public_id, h_metadata={}, app_id=test_app.public_id)
db_session.add(test_session)
await db_session.commit()
@ -110,7 +110,7 @@ async def test_update_session(client, db_session, sample_data):
async def test_delete_session(client, db_session, sample_data):
test_app, test_user = sample_data
# Create a test session
test_session = models.Session(user_id=test_user.public_id, h_metadata={})
test_session = models.Session(user_id=test_user.public_id, h_metadata={}, app_id=test_app.public_id)
db_session.add(test_session)
await db_session.commit()
response = client.delete(
@ -129,7 +129,7 @@ async def test_clone_session(client, db_session, sample_data):
test_app, test_user = sample_data
# Create a test session
test_session = models.Session(
user_id=test_user.public_id, h_metadata={"test": "key"}
user_id=test_user.public_id, h_metadata={"test": "key"}, app_id=test_app.public_id
)
db_session.add(test_session)
await db_session.commit()
@ -139,12 +139,16 @@ async def test_clone_session(client, db_session, sample_data):
content="Test message",
is_user=True,
h_metadata={"key": "value"},
app_id=test_app.public_id,
user_id=test_user.public_id,
)
test_message2 = models.Message(
session_id=test_session.public_id,
content="Test message 2",
is_user=True,
h_metadata={"key": "value2"},
app_id=test_app.public_id,
user_id=test_user.public_id,
)
db_session.add(test_message)
db_session.add(test_message2)
@ -184,7 +188,7 @@ async def test_partial_clone_session(client, db_session, sample_data):
test_app, test_user = sample_data
# Create a test session
test_session = models.Session(
user_id=test_user.public_id, h_metadata={"test": "key"}
user_id=test_user.public_id, h_metadata={"test": "key"}, app_id=test_app.public_id
)
db_session.add(test_session)
await db_session.commit()
@ -194,12 +198,16 @@ async def test_partial_clone_session(client, db_session, sample_data):
content="Test message",
is_user=True,
h_metadata={"key": "value"},
app_id=test_app.public_id,
user_id=test_user.public_id,
)
test_message2 = models.Message(
session_id=test_session.public_id,
content="Test message 2",
is_user=True,
h_metadata={"key": "value2"},
app_id=test_app.public_id,
user_id=test_user.public_id,
)
test_message3 = models.Message(
@ -207,6 +215,8 @@ async def test_partial_clone_session(client, db_session, sample_data):
content="Test message 2",
is_user=True,
h_metadata={"key": "value2"},
app_id=test_app.public_id,
user_id=test_user.public_id,
)
db_session.add(test_message)
@ -244,7 +254,7 @@ async def test_deep_clone_session(client, db_session, sample_data):
test_app, test_user = sample_data
# Create a test session
test_session = models.Session(
user_id=test_user.public_id, h_metadata={"test": "key"}
user_id=test_user.public_id, h_metadata={"test": "key"}, app_id=test_app.public_id
)
db_session.add(test_session)
await db_session.commit()
@ -254,12 +264,16 @@ async def test_deep_clone_session(client, db_session, sample_data):
content="Test message",
is_user=True,
h_metadata={"key": "value"},
app_id=test_app.public_id,
user_id=test_user.public_id,
)
test_message2 = models.Message(
session_id=test_session.public_id,
content="Test message 2",
is_user=True,
h_metadata={"key": "value2"},
app_id=test_app.public_id,
user_id=test_user.public_id,
)
db_session.add(test_message)
db_session.add(test_message2)
@ -272,6 +286,7 @@ async def test_deep_clone_session(client, db_session, sample_data):
content="Test Metamessage 1",
h_metadata={},
metamessage_type="test_type",
app_id=test_app.public_id,
)
test_metamessage_2 = models.Metamessage(
user_id=test_user.public_id,
@ -280,6 +295,7 @@ async def test_deep_clone_session(client, db_session, sample_data):
content="Test Metamessage 2",
h_metadata={},
metamessage_type="test_type",
app_id=test_app.public_id,
)
test_metamessage_3 = models.Metamessage(
user_id=test_user.public_id,
@ -288,6 +304,7 @@ async def test_deep_clone_session(client, db_session, sample_data):
content="Test Metamessage 3",
h_metadata={},
metamessage_type="test_type",
app_id=test_app.public_id,
)
test_metamessage_4 = models.Metamessage(
user_id=test_user.public_id,
@ -296,6 +313,7 @@ async def test_deep_clone_session(client, db_session, sample_data):
content="Test Metamessage 4",
h_metadata={},
metamessage_type="test_type_2",
app_id=test_app.public_id,
)
db_session.add(test_metamessage_1)
@ -360,7 +378,7 @@ async def test_partial_deep_clone_session(client, db_session, sample_data):
test_app, test_user = sample_data
# Create a test session
test_session = models.Session(
user_id=test_user.public_id, h_metadata={"test": "key"}
user_id=test_user.public_id, h_metadata={"test": "key"}, app_id=test_app.public_id
)
db_session.add(test_session)
await db_session.commit()
@ -370,12 +388,16 @@ async def test_partial_deep_clone_session(client, db_session, sample_data):
content="Test message",
is_user=True,
h_metadata={"key": "value"},
app_id=test_app.public_id,
user_id=test_user.public_id,
)
test_message2 = models.Message(
session_id=test_session.public_id,
content="Test message 2",
is_user=True,
h_metadata={"key": "value2"},
app_id=test_app.public_id,
user_id=test_user.public_id,
)
db_session.add(test_message)
db_session.add(test_message2)
@ -388,6 +410,7 @@ async def test_partial_deep_clone_session(client, db_session, sample_data):
content="Test Metamessage 1",
h_metadata={},
metamessage_type="test_type",
app_id=test_app.public_id,
)
test_metamessage_2 = models.Metamessage(
user_id=test_user.public_id,
@ -396,6 +419,7 @@ async def test_partial_deep_clone_session(client, db_session, sample_data):
content="Test Metamessage 2",
h_metadata={},
metamessage_type="test_type",
app_id=test_app.public_id,
)
test_metamessage_3 = models.Metamessage(
user_id=test_user.public_id,
@ -404,6 +428,7 @@ async def test_partial_deep_clone_session(client, db_session, sample_data):
content="Test Metamessage 3",
h_metadata={},
metamessage_type="test_type",
app_id=test_app.public_id,
)
test_metamessage_4 = models.Metamessage(
user_id=test_user.public_id,
@ -412,6 +437,7 @@ async def test_partial_deep_clone_session(client, db_session, sample_data):
content="Test Metamessage 4",
h_metadata={},
metamessage_type="test_type_2",
app_id=test_app.public_id,
)
db_session.add(test_metamessage_1)