Make JSON body optional for list endpoints and Rename Metamessage Type to Label (#108)

* feat (storage): Remove strict requirement for body on list endpoints

* fix (storage): Rename metamessage_type to label with backwards compatability

* fix (schemas): Backwards compatability for metamessage_type and idiomatic schemas

* fix (docs): Update docs to reference label instead of metamessage type

* fix (storage): Rebase db migration and fix tests

* chore: alembic consistency
This commit is contained in:
Vineeth Voruganti 2025-05-14 16:19:30 -04:00 committed by GitHub
parent d0285189c3
commit 1b54b4703b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 492 additions and 23942 deletions

View File

@ -85,7 +85,7 @@ erDiagram
Metamessage {
BigInteger id PK
string public_id
string metamessage_type
string label
string content
string user_id FK
string session_id FK "nullable"

View File

@ -1894,11 +1894,11 @@
"x-codeSamples": [
{
"lang": "JavaScript",
"source": "import Honcho from 'honcho-ai';\n\nconst client = new Honcho({\n apiKey: process.env['HONCHO_API_KEY'], // This is the default and can be omitted\n});\n\nasync function main() {\n const metamessage = await client.apps.users.metamessages.create('app_id', 'user_id', {\n content: 'content',\n metamessage_type: 'x',\n });\n\n console.log(metamessage.id);\n}\n\nmain();"
"source": "import Honcho from 'honcho-ai';\n\nconst client = new Honcho({\n apiKey: process.env['HONCHO_API_KEY'], // This is the default and can be omitted\n});\n\nasync function main() {\n const metamessage = await client.apps.users.metamessages.create('app_id', 'user_id', {\n content: 'content',\n label: 'x',\n });\n\n console.log(metamessage.id);\n}\n\nmain();"
},
{
"lang": "Python",
"source": "import os\nfrom honcho import Honcho\n\nclient = Honcho(\n api_key=os.environ.get(\"HONCHO_API_KEY\"), # This is the default and can be omitted\n)\nmetamessage = client.apps.users.metamessages.create(\n user_id=\"user_id\",\n app_id=\"app_id\",\n content=\"content\",\n metamessage_type=\"x\",\n)\nprint(metamessage.id)"
"source": "import os\nfrom honcho import Honcho\n\nclient = Honcho(\n api_key=os.environ.get(\"HONCHO_API_KEY\"), # This is the default and can be omitted\n)\nmetamessage = client.apps.users.metamessages.create(\n user_id=\"user_id\",\n app_id=\"app_id\",\n content=\"content\",\n label=\"x\",\n)\nprint(metamessage.id)"
}
]
}
@ -1907,7 +1907,7 @@
"post": {
"tags": ["metamessages"],
"summary": "Get Metamessages",
"description": "Get metamessages with flexible filtering.\n\n- Filter by user only: No additional parameters needed\n- Filter by session: Provide session_id\n- Filter by message: Provide message_id (and session_id)\n- Filter by type: Provide metamessage_type\n- Filter by metadata: Provide filter object",
"description": "Get metamessages with flexible filtering.\n\n- Filter by user only: No additional parameters needed\n- Filter by session: Provide session_id\n- Filter by message: Provide message_id (and session_id)\n- Filter by type: Provide label\n- Filter by metadata: Provide filter object",
"operationId": "get_metamessages_v1_apps__app_id__users__user_id__metamessages_list_post",
"security": [{ "HTTPBearer": [] }, {}],
"parameters": [
@ -3651,7 +3651,7 @@
"Metamessage": {
"properties": {
"id": { "type": "string", "title": "Id" },
"metamessage_type": { "type": "string", "title": "Metamessage Type" },
"label": { "type": "string", "title": "Label" },
"content": { "type": "string", "title": "Content" },
"user_id": { "type": "string", "title": "User Id" },
"session_id": {
@ -3676,7 +3676,7 @@
"type": "object",
"required": [
"id",
"metamessage_type",
"label",
"content",
"user_id",
"session_id",
@ -3689,7 +3689,7 @@
},
"MetamessageCreate": {
"properties": {
"metamessage_type": {
"label": {
"type": "string",
"maxLength": 50,
"minLength": 1,
@ -3717,12 +3717,12 @@
}
},
"type": "object",
"required": ["metamessage_type", "content"],
"required": ["label", "content"],
"title": "MetamessageCreate"
},
"MetamessageGet": {
"properties": {
"metamessage_type": {
"label": {
"anyOf": [{ "type": "string" }, { "type": "null" }],
"title": "Metamessage Type"
},
@ -3755,7 +3755,7 @@
"anyOf": [{ "type": "string" }, { "type": "null" }],
"title": "Message Id"
},
"metamessage_type": {
"label": {
"anyOf": [{ "type": "string" }, { "type": "null" }],
"title": "Metamessage Type"
},
@ -4033,4 +4033,3 @@
"securitySchemes": { "HTTPBearer": { "type": "http", "scheme": "bearer" } }
}
}

23718
docs/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,118 @@
"""rename metamessage_type to label
Revision ID: 20f89a421aff
Revises: 556a16564f50
Create Date: 2025-05-13 16:11:54.859842
"""
from typing import Sequence, Union
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision: str = "20f89a421aff"
down_revision: Union[str, None] = "556a16564f50"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column(
"metamessages",
"metamessage_type",
new_column_name="label",
existing_type=sa.TEXT(),
)
# Drop old indexes
op.drop_index("idx_metamessages_lookup", table_name="metamessages")
op.drop_index("idx_metamessages_user_lookup", table_name="metamessages")
op.drop_index("idx_metamessages_session_lookup", table_name="metamessages")
op.drop_index("idx_metamessages_message_lookup", table_name="metamessages")
# Create new indexes with the 'label' column
op.create_index(
"idx_metamessages_lookup",
"metamessages",
["label", sa.text("id DESC")],
unique=False,
postgresql_include=["public_id", "message_id", "created_at"],
)
op.create_index(
"idx_metamessages_user_lookup",
"metamessages",
["user_id", "label", sa.text("id DESC")],
unique=False,
)
op.create_index(
"idx_metamessages_session_lookup",
"metamessages",
["session_id", "label", sa.text("id DESC")],
unique=False,
)
op.create_index(
"idx_metamessages_message_lookup",
"metamessages",
["message_id", "label", sa.text("id DESC")],
unique=False,
)
# Rename check constraint
op.execute("ALTER TABLE metamessages DROP CONSTRAINT metamessage_type_length;")
op.create_check_constraint("label_length", "metamessages", "length(label) <= 512")
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column(
"metamessages",
"label",
new_column_name="metamessage_type",
existing_type=sa.TEXT(),
)
# Drop new indexes
op.drop_index("idx_metamessages_lookup", table_name="metamessages")
op.drop_index("idx_metamessages_user_lookup", table_name="metamessages")
op.drop_index("idx_metamessages_session_lookup", table_name="metamessages")
op.drop_index("idx_metamessages_message_lookup", table_name="metamessages")
# Create old indexes with 'metamessage_type'
op.create_index(
"idx_metamessages_lookup",
"metamessages",
["metamessage_type", sa.text("id DESC")],
unique=False,
postgresql_include=["public_id", "message_id", "created_at"],
)
op.create_index(
"idx_metamessages_user_lookup",
"metamessages",
["user_id", "metamessage_type", sa.text("id DESC")],
unique=False,
)
op.create_index(
"idx_metamessages_session_lookup",
"metamessages",
["session_id", "metamessage_type", sa.text("id DESC")],
unique=False,
)
op.create_index(
"idx_metamessages_message_lookup",
"metamessages",
["message_id", "metamessage_type", sa.text("id DESC")],
unique=False,
)
# Revert check constraint rename
op.execute("ALTER TABLE metamessages DROP CONSTRAINT label_length;")
op.create_check_constraint(
"metamessage_type_length",
"metamessages",
"length(metamessage_type) <= 512",
)
# ### end Alembic commands ###

View File

@ -453,7 +453,7 @@ async def generate_user_representation(
select(models.Metamessage)
.where(models.Metamessage.session_id == session_id) # only from the same session
.where(
models.Metamessage.metamessage_type
models.Metamessage.label
== USER_REPRESENTATION_METAMESSAGE_TYPE
)
.order_by(models.Metamessage.id.desc())
@ -522,7 +522,7 @@ RELEVANT LONG-TERM FACTS ABOUT THE USER:
user_id=user_id,
session_id=session_id,
message_id=message_id if message_id else None,
metamessage_type=USER_REPRESENTATION_METAMESSAGE_TYPE,
label=USER_REPRESENTATION_METAMESSAGE_TYPE,
content=representation,
h_metadata={},
)

View File

@ -623,7 +623,7 @@ async def clone_session(
meta_data = {
"user_id": meta.user_id, # Preserve original user
"session_id": new_session.public_id,
"metamessage_type": meta.metamessage_type,
"label": meta.label,
"content": meta.content,
"h_metadata": meta.h_metadata,
"app_id": original_session.app_id,
@ -800,7 +800,7 @@ async def create_metamessage(
metamessage_data = {
"user_id": user_id,
"app_id": app_id,
"metamessage_type": metamessage.metamessage_type,
"label": metamessage.label,
"content": metamessage.content,
"h_metadata": metamessage.metadata,
}
@ -850,7 +850,7 @@ async def get_metamessages(
user_id: str,
session_id: Optional[str] = None,
message_id: Optional[str] = None,
metamessage_type: Optional[str] = None,
label: Optional[str] = None,
filter: Optional[dict] = None,
reverse: Optional[bool] = False,
) -> Select:
@ -869,9 +869,9 @@ async def get_metamessages(
if message_id is not None:
stmt = stmt.where(models.Metamessage.message_id == message_id)
# Filter by metamessage_type if provided
if metamessage_type is not None:
stmt = stmt.where(models.Metamessage.metamessage_type == metamessage_type)
# Filter by label if provided
if label is not None:
stmt = stmt.where(models.Metamessage.label == label)
# Apply metadata filter if provided
if filter is not None:
@ -960,8 +960,8 @@ async def update_metamessage(
if metamessage.metadata is not None:
metamessage_obj.h_metadata = metamessage.metadata
if metamessage.metamessage_type is not None:
metamessage_obj.metamessage_type = metamessage.metamessage_type
if metamessage.label is not None:
metamessage_obj.label = metamessage.label
await db.commit()
return metamessage_obj

View File

@ -152,7 +152,7 @@ class Metamessage(Base):
public_id: Mapped[str] = mapped_column(
TEXT, index=True, unique=True, default=generate_nanoid
)
metamessage_type: Mapped[str] = mapped_column(TEXT, index=True)
label: Mapped[str] = mapped_column(TEXT, index=True)
content: Mapped[str] = mapped_column(TEXT)
# Foreign keys - message_id is now optional
@ -179,9 +179,7 @@ class Metamessage(Base):
CheckConstraint("length(public_id) = 21", name="public_id_length"),
CheckConstraint("public_id ~ '^[A-Za-z0-9_-]+$'", name="public_id_format"),
CheckConstraint("length(content) <= 65535", name="content_length"),
CheckConstraint(
"length(metamessage_type) <= 512", name="metamessage_type_length"
),
CheckConstraint("length(label) <= 512", name="label_length"),
# Added constraints to ensure consistency
CheckConstraint(
"(message_id IS NULL) OR (session_id IS NOT NULL)",
@ -190,7 +188,7 @@ class Metamessage(Base):
# Keep existing index
Index(
"idx_metamessages_lookup",
"metamessage_type",
"label",
text("id DESC"),
postgresql_include=["public_id", "message_id", "created_at"],
),
@ -198,25 +196,25 @@ class Metamessage(Base):
Index(
"idx_metamessages_user_lookup",
"user_id",
"metamessage_type",
"label",
text("id DESC"),
),
Index(
"idx_metamessages_session_lookup",
"session_id",
"metamessage_type",
"label",
text("id DESC"),
),
Index(
"idx_metamessages_message_lookup",
"message_id",
"metamessage_type",
"label",
text("id DESC"),
),
)
def __repr__(self) -> str:
return f"Metamessages(id={self.id}, user_id={self.user_id}, session_id={self.session_id}, message_id={self.message_id}, metamessage_type={self.metamessage_type})"
return f"Metamessages(id={self.id}, user_id={self.user_id}, session_id={self.session_id}, message_id={self.message_id}, label={self.label})"
class Collection(Base):

View File

@ -52,8 +52,8 @@ async def get_app(
dependencies=[Depends(require_auth(admin=True))],
)
async def get_all_apps(
options: schemas.AppGet = Body(
..., description="Filtering and pagination options for the apps list"
options: Optional[schemas.AppGet] = Body(
None, description="Filtering and pagination options for the apps list"
),
reverse: Optional[bool] = Query(
False, description="Whether to reverse the order of results"
@ -61,12 +61,18 @@ async def get_all_apps(
db=db,
):
"""Get all Apps"""
filter_param = None
if options and hasattr(options, 'filter'):
filter_param = options.filter
if filter_param == {}:
filter_param = None
return await paginate(
db,
await crud.get_all_apps(
db,
reverse=reverse,
filter=options.filter,
filter=filter_param,
),
)

View File

@ -71,8 +71,8 @@ async def get_collection(
async def get_collections(
app_id: str = Path(..., description="ID of the app"),
user_id: str = Path(..., description="ID of the user"),
options: schemas.CollectionGet = Body(
..., description="Filtering options for the collections list"
options: Optional[schemas.CollectionGet] = Body(
None, description="Filtering options for the collections list"
),
reverse: Optional[bool] = Query(
False, description="Whether to reverse the order of results"
@ -80,10 +80,16 @@ async def get_collections(
db=db,
):
"""Get All Collections for a User"""
filter_param = None
if options and hasattr(options, 'filter'):
filter_param = options.filter
if filter_param == {}: # Explicitly check for empty dict
filter_param = None
return await paginate(
db,
await crud.get_collections(
db, app_id=app_id, user_id=user_id, filter=options.filter, reverse=reverse
db, app_id=app_id, user_id=user_id, filter=filter_param, reverse=reverse
),
)

View File

@ -31,8 +31,8 @@ async def get_documents(
app_id: str = Path(..., description="ID of the app"),
user_id: str = Path(..., description="ID of the user"),
collection_id: str = Path(..., description="ID of the collection"),
options: schemas.DocumentGet = Body(
..., description="Filtering options for the documents list"
options: Optional[schemas.DocumentGet] = Body(
None, description="Filtering options for the documents list"
),
reverse: Optional[bool] = Query(
False, description="Whether to reverse the order of results"
@ -40,13 +40,19 @@ async def get_documents(
db=db,
):
"""Get all of the Documents in a Collection"""
filter_param = None
if options and hasattr(options, "filter"):
filter_param = options.filter
if filter_param == {}: # Explicitly check for empty dict
filter_param = None
try:
documents_query = await crud.get_documents(
db,
app_id=app_id,
user_id=user_id,
collection_id=collection_id,
filter=options.filter,
filter=filter_param,
reverse=reverse,
)

View File

@ -243,8 +243,8 @@ async def get_messages(
app_id: str = Path(..., description="ID of the app"),
user_id: str = Path(..., description="ID of the user"),
session_id: str = Path(..., description="ID of the session"),
options: schemas.MessageGet = Body(
..., description="Filtering options for the messages list"
options: Optional[schemas.MessageGet] = Body(
None, description="Filtering options for the messages list"
),
reverse: Optional[bool] = Query(
False, description="Whether to reverse the order of results"
@ -253,9 +253,11 @@ async def get_messages(
):
"""Get all messages for a session"""
try:
filter = options.filter
if options.filter == {}:
filter = None
filter = None
if options and hasattr(options, 'filter'):
filter = options.filter
if filter == {}:
filter = None
messages_query = await crud.get_messages(
db,

View File

@ -50,8 +50,8 @@ async def create_metamessage(
async def get_metamessages(
app_id: str = Path(..., description="ID of the app"),
user_id: str = Path(..., description="ID of the user"),
options: schemas.MetamessageGet = Body(
..., description="Filtering options for the metamessages list"
options: Optional[schemas.MetamessageGet] = Body(
None, description="Filtering options for the metamessages list"
),
reverse: Optional[bool] = Query(
False, description="Whether to reverse the order of results"
@ -64,18 +64,35 @@ async def get_metamessages(
- Filter by user only: No additional parameters needed
- Filter by session: Provide session_id
- Filter by message: Provide message_id (and session_id)
- Filter by type: Provide metamessage_type
- Filter by type: Provide label
- Filter by metadata: Provide filter object
"""
session_id_param = None
message_id_param = None
label_param = None
filter_param = None
if options:
if hasattr(options, 'session_id') and options.session_id:
session_id_param = options.session_id
if hasattr(options, 'message_id') and options.message_id:
message_id_param = options.message_id
if hasattr(options, 'label') and options.label:
label_param = options.label
if hasattr(options, 'filter') and options.filter:
filter_param = options.filter
if filter_param == {}: # Explicitly check for empty dict
filter_param = None
try:
metamessages_query = await crud.get_metamessages(
db,
app_id=app_id,
user_id=user_id,
session_id=options.session_id,
message_id=options.message_id,
metamessage_type=options.metamessage_type,
filter=options.filter,
session_id=session_id_param,
message_id=message_id_param,
label=label_param,
filter=filter_param,
reverse=reverse,
)
return await paginate(db, metamessages_query)

View File

@ -81,8 +81,8 @@ async def get_session(
async def get_sessions(
app_id: str = Path(..., description="ID of the app"),
user_id: str = Path(..., description="ID of the user"),
options: schemas.SessionGet = Body(
..., description="Filtering and pagination options for the sessions list"
options: Optional[schemas.SessionGet] = Body(
None, description="Filtering and pagination options for the sessions list"
),
reverse: Optional[bool] = Query(
False, description="Whether to reverse the order of results"
@ -90,14 +90,25 @@ async def get_sessions(
db=db,
):
"""Get All Sessions for a User"""
filter_param = None
is_active_param = False # Default to None, meaning no filter on is_active
if options:
if hasattr(options, 'filter') and options.filter:
filter_param = options.filter
if filter_param == {}: # Explicitly check for empty dict
filter_param = None
if hasattr(options, 'is_active'): # Check if is_active is present
is_active_param = options.is_active
return await paginate(
db,
await crud.get_sessions(
app_id=app_id,
user_id=user_id,
reverse=reverse,
is_active=options.is_active,
filter=options.filter,
is_active=is_active_param,
filter=filter_param,
),
)

View File

@ -43,16 +43,22 @@ async def create_user(
)
async def get_users(
app_id: str = Path(..., description="ID of the app"),
options: schemas.UserGet = Body(
..., description="Filtering options for the users list"
options: Optional[schemas.UserGet] = Body(
None, description="Filtering options for the users list"
),
reverse: bool = Query(False, description="Whether to reverse the order of results"),
db=db,
):
"""Get All Users for an App"""
filter_param = None
if options and hasattr(options, 'filter'):
filter_param = options.filter
if filter_param == {}:
filter_param = None
return await paginate(
db,
await crud.get_users(db, app_id=app_id, reverse=reverse, filter=options.filter),
await crud.get_users(db, app_id=app_id, reverse=reverse, filter=filter_param),
)

View File

@ -1,7 +1,7 @@
import datetime
from typing import Annotated
from pydantic import BaseModel, ConfigDict, Field, field_validator
from pydantic import BaseModel, ConfigDict, Field, field_validator, computed_field
class AppBase(BaseModel):
@ -23,24 +23,14 @@ class AppUpdate(AppBase):
class App(AppBase):
public_id: str = Field(exclude=True)
id: str
public_id: str = Field(serialization_alias='id')
name: str
h_metadata: dict = Field(exclude=True)
metadata: dict
h_metadata: dict = Field(default={}, serialization_alias='metadata')
created_at: datetime.datetime
@field_validator("metadata", mode="before")
def fetch_h_metadata(cls, value, info):
return info.data.get("h_metadata", {})
@field_validator("id", mode="before")
def internal_to_public(cls, value, info):
return info.data.get("public_id", {})
model_config = ConfigDict(
from_attributes=True,
json_schema_extra={"exclude": ["h_metadata", "public_id"]},
populate_by_name=True
)
@ -59,29 +49,19 @@ class UserGet(UserBase):
class UserUpdate(UserBase):
name: str | None = None
metadata: dict | None = None # Allow user to explicitly set metadata to empty
metadata: dict | None = None
class User(UserBase):
public_id: str = Field(exclude=True)
id: str
public_id: str = Field(serialization_alias='id')
name: str
app_id: str
created_at: datetime.datetime
h_metadata: dict = Field(exclude=True)
metadata: dict
@field_validator("metadata", mode="before")
def fetch_h_metadata(cls, value, info):
return info.data.get("h_metadata", {})
@field_validator("id", mode="before")
def internal_to_public(cls, value, info):
return info.data.get("public_id", {})
h_metadata: dict = Field(default={}, serialization_alias='metadata')
model_config = ConfigDict(
from_attributes=True,
json_schema_extra={"exclude": ["h_metadata", "public_id"]},
populate_by_name=True
)
@ -104,28 +84,18 @@ class MessageUpdate(MessageBase):
class Message(MessageBase):
public_id: str = Field(exclude=True)
id: str
public_id: str = Field(serialization_alias='id')
content: str
is_user: bool
session_id: str
h_metadata: dict = Field(exclude=True)
metadata: dict
h_metadata: dict = Field(default={}, serialization_alias='metadata')
created_at: datetime.datetime
app_id: str
user_id: str
@field_validator("metadata", mode="before")
def fetch_h_metadata(cls, value, info):
return info.data.get("h_metadata", {})
@field_validator("id", mode="before")
def internal_to_public(cls, value, info):
return info.data.get("public_id", {})
model_config = ConfigDict(
from_attributes=True,
json_schema_extra={"exclude": ["h_metadata", "public_id"]},
populate_by_name=True
)
@ -147,28 +117,16 @@ class SessionUpdate(SessionBase):
class Session(SessionBase):
public_id: str = Field(exclude=True)
id: str
# messages: list[Message]
public_id: str = Field(serialization_alias='id')
is_active: bool
user_id: str
app_id: str
h_metadata: dict = Field(exclude=True)
metadata: dict
h_metadata: dict = Field(default={}, serialization_alias='metadata')
created_at: datetime.datetime
@field_validator("metadata", mode="before")
def fetch_h_metadata(cls, value, info):
return info.data.get("h_metadata", {})
@field_validator("id", mode="before")
def internal_to_public(cls, value, info):
return info.data.get("public_id", {})
model_config = ConfigDict(
from_attributes=True,
json_schema_extra={"exclude": ["h_metadata", "public_id"]},
populate_by_name=True
)
@ -177,51 +135,53 @@ class MetamessageBase(BaseModel):
class MetamessageCreate(MetamessageBase):
metamessage_type: Annotated[str, Field(min_length=1, max_length=50)]
label: Annotated[str, Field(min_length=1, max_length=50, alias='metamessage_type')]
content: Annotated[str, Field(min_length=0, max_length=50000)]
session_id: str | None = None
message_id: str | None = None
metadata: dict = {}
model_config = ConfigDict(populate_by_name=True)
class MetamessageGet(MetamessageBase):
metamessage_type: str | None = None
label: str | None = Field(default=None, alias='metamessage_type')
session_id: str | None = None
message_id: str | None = None
filter: dict | None = None
model_config = ConfigDict(populate_by_name=True)
class MetamessageUpdate(MetamessageBase):
session_id: str | None = None
message_id: str | None = None
metamessage_type: str | None = None
label: str | None = Field(default=None, alias='metamessage_type')
metadata: dict | None = None
model_config = ConfigDict(populate_by_name=True)
class Metamessage(MetamessageBase):
public_id: str = Field(exclude=True)
id: str
metamessage_type: str
public_id: str = Field(serialization_alias='id')
label: str
content: str
user_id: str
app_id: str
session_id: str | None
message_id: str | None
h_metadata: dict = Field(exclude=True)
metadata: dict
h_metadata: dict = Field(default={}, serialization_alias='metadata')
created_at: datetime.datetime
@field_validator("metadata", mode="before")
def fetch_h_metadata(cls, value, info):
return info.data.get("h_metadata", {})
@field_validator("id", mode="before")
def internal_to_public(cls, value, info):
return info.data.get("public_id", {})
# Included for backwards compatibility with the old metamessage_type field
@computed_field
@property
def metamessage_type(self) -> str:
return self.label
model_config = ConfigDict(
from_attributes=True,
json_schema_extra={"exclude": ["h_metadata", "public_id"]},
populate_by_name=True
)
@ -256,26 +216,16 @@ class CollectionUpdate(CollectionBase):
class Collection(CollectionBase):
public_id: str = Field(exclude=True)
id: str
public_id: str = Field(serialization_alias='id')
name: str
user_id: str
app_id: str
h_metadata: dict = Field(exclude=True)
metadata: dict
h_metadata: dict = Field(default={}, serialization_alias='metadata')
created_at: datetime.datetime
@field_validator("metadata", mode="before")
def fetch_h_metadata(cls, value, info):
return info.data.get("h_metadata", {})
@field_validator("id", mode="before")
def internal_to_public(cls, value, info):
return info.data.get("public_id", {})
model_config = ConfigDict(
from_attributes=True,
json_schema_extra={"exclude": ["h_metadata", "public_id"]},
populate_by_name=True
)
@ -304,27 +254,17 @@ class DocumentUpdate(DocumentBase):
class Document(DocumentBase):
public_id: str = Field(exclude=True)
id: str
public_id: str = Field(serialization_alias='id')
content: str
h_metadata: dict = Field(exclude=True)
metadata: dict
h_metadata: dict = Field(default={}, serialization_alias='metadata')
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):
return info.data.get("h_metadata", {})
@field_validator("id", mode="before")
def internal_to_public(cls, value, info):
return info.data.get("public_id", {})
model_config = ConfigDict(
from_attributes=True,
json_schema_extra={"exclude": ["h_metadata", "public_id"]},
populate_by_name=True
)

View File

@ -62,7 +62,7 @@ async def get_session_summaries(
If only_latest is False: A list of all summary metamessages for the session
"""
# Determine the metamessage type based on summary_type
metamessage_type = (
label = (
SummaryType.SHORT.value
if summary_type == SummaryType.SHORT
else SummaryType.LONG.value
@ -71,7 +71,7 @@ async def get_session_summaries(
stmt = (
select(models.Metamessage)
.where(models.Metamessage.session_id == session_id)
.where(models.Metamessage.metamessage_type == metamessage_type)
.where(models.Metamessage.label == label)
.order_by(models.Metamessage.id.desc())
)
@ -242,15 +242,15 @@ async def save_summary_metamessage(
Returns:
The created metamessage
"""
# Get the metamessage_type value from the enum
metamessage_type = summary_type.value
# Get the label value from the enum
label_value = summary_type.value
# Create and save the metamessage
metamessage = models.Metamessage(
user_id=user_id,
session_id=session_id,
message_id=message_id,
metamessage_type=metamessage_type,
label=label_value,
content=summary_content,
h_metadata={"message_count": message_count, "summary_type": summary_type.name},
)

View File

@ -7,11 +7,17 @@ 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, app_id=test_app.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
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()
@ -23,7 +29,7 @@ async def test_create_metamessage(client, db_session, sample_data):
"message_id": str(test_message.public_id),
"content": "Test Metamessage",
"metadata": {},
"metamessage_type": "test_type",
"label": "test_type",
},
)
assert response.status_code == 200
@ -33,6 +39,7 @@ async def test_create_metamessage(client, db_session, sample_data):
assert data["message_id"] == str(test_message.public_id)
assert data["content"] == "Test Metamessage"
assert data["metadata"] == {}
assert data["label"] == "test_type"
assert data["metamessage_type"] == "test_type"
@ -40,11 +47,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, app_id=test_app.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
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()
@ -55,7 +68,7 @@ async def test_get_metamessage(client, db_session, sample_data):
message_id=test_message.public_id,
content="Test Metamessage",
h_metadata={},
metamessage_type="test_type",
label="test_type",
)
db_session.add(test_metamessage)
await db_session.commit()
@ -71,6 +84,7 @@ async def test_get_metamessage(client, db_session, sample_data):
assert data["message_id"] == str(test_message.public_id)
assert data["content"] == "Test Metamessage"
assert data["metadata"] == {}
assert data["label"] == "test_type"
assert data["metamessage_type"] == "test_type"
@ -78,11 +92,17 @@ 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, app_id=test_app.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
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()
@ -95,7 +115,7 @@ async def test_get_metamessages_by_session(client, db_session, sample_data):
message_id=test_message.public_id,
content="Test Metamessage",
h_metadata={},
metamessage_type="test_type",
label="test_type",
)
test_metamessage_2 = models.Metamessage(
user_id=test_user.public_id,
@ -104,7 +124,7 @@ async def test_get_metamessages_by_session(client, db_session, sample_data):
message_id=test_message.public_id,
content="Test Metamessage",
h_metadata={},
metamessage_type="test_type",
label="test_type",
)
test_metamessage_3 = models.Metamessage(
user_id=test_user.public_id,
@ -113,7 +133,7 @@ async def test_get_metamessages_by_session(client, db_session, sample_data):
message_id=test_message.public_id,
content="Test Metamessage",
h_metadata={},
metamessage_type="test_type",
label="test_type",
)
test_metamessage_4 = models.Metamessage(
user_id=test_user.public_id,
@ -122,7 +142,7 @@ async def test_get_metamessages_by_session(client, db_session, sample_data):
message_id=test_message.public_id,
content="Test Metamessage",
h_metadata={},
metamessage_type="test_type_2",
label="test_type_2",
)
db_session.add(test_metamessage_1)
db_session.add(test_metamessage_2)
@ -135,7 +155,7 @@ async def test_get_metamessages_by_session(client, db_session, sample_data):
f"/v1/apps/{test_app.public_id}/users/{test_user.public_id}/metamessages/list",
json={
"session_id": str(test_session.public_id),
"metamessage_type": "test_type",
"label": "test_type",
},
)
@ -144,18 +164,26 @@ async def test_get_metamessages_by_session(client, db_session, sample_data):
assert "items" in data
assert len(data["items"]) == 3
assert data["items"][0]["content"] == "Test Metamessage"
assert data["items"][0]["label"] == "test_type"
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, 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)
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)
@ -163,13 +191,25 @@ 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, app_id=test_app.public_id, user_id=test_user.public_id
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, app_id=test_app.public_id, user_id=test_user.public_id
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, app_id=test_app.public_id, user_id=test_user.public_id
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)
@ -184,7 +224,7 @@ async def test_get_metamessage_by_user(client, db_session, sample_data):
message_id=test_message_1.public_id,
content="Test Metamessage",
h_metadata={},
metamessage_type="test_type",
label="test_type",
)
test_metamessage_2 = models.Metamessage(
user_id=test_user.public_id,
@ -193,7 +233,7 @@ async def test_get_metamessage_by_user(client, db_session, sample_data):
message_id=test_message_2.public_id,
content="Test Metamessage",
h_metadata={},
metamessage_type="test_type",
label="test_type",
)
test_metamessage_3 = models.Metamessage(
user_id=test_user.public_id,
@ -202,7 +242,7 @@ async def test_get_metamessage_by_user(client, db_session, sample_data):
message_id=test_message_3.public_id,
content="Test Metamessage",
h_metadata={},
metamessage_type="test_type",
label="test_type",
)
test_metamessage_4 = models.Metamessage(
user_id=test_user.public_id,
@ -211,7 +251,7 @@ async def test_get_metamessage_by_user(client, db_session, sample_data):
message_id=test_message_3.public_id,
content="Test Metamessage",
h_metadata={},
metamessage_type="test_type_2",
label="test_type_2",
)
# Create a user-level metamessage (no session/message)
test_metamessage_5 = models.Metamessage(
@ -219,7 +259,7 @@ async def test_get_metamessage_by_user(client, db_session, sample_data):
app_id=test_app.public_id,
content="User level metamessage",
h_metadata={},
metamessage_type="test_type",
label="test_type",
)
db_session.add(test_metamessage_1)
db_session.add(test_metamessage_2)
@ -231,16 +271,18 @@ async def test_get_metamessage_by_user(client, db_session, sample_data):
# Filter only by type across all user's metamessages
response = client.post(
f"/v1/apps/{test_app.public_id}/users/{test_user.public_id}/metamessages/list",
json={"metamessage_type": "test_type"},
json={"label": "test_type"},
)
assert response.status_code == 200
data = response.json()
assert len(data["items"]) == 4 # All test_type metamessages for the user
assert data["items"][0]["content"] in ["Test Metamessage", "User level metamessage"]
assert data["items"][0]["label"] == "test_type"
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):
test_app, test_user = sample_data
@ -251,7 +293,7 @@ async def test_create_user_level_metamessage(client, db_session, sample_data):
json={
"content": "User level insight",
"metadata": {"source": "user_profile"},
"metamessage_type": "user_insight",
"label": "user_insight",
},
)
assert response.status_code == 200
@ -263,16 +305,25 @@ async def test_create_user_level_metamessage(client, db_session, sample_data):
assert data["metadata"] == {"source": "user_profile"}
assert data["metamessage_type"] == "user_insight"
assert data["app_id"] == str(test_app.public_id)
assert data["label"] == "user_insight"
assert data["metamessage_type"] == "user_insight"
@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, app_id=test_app.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
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()
@ -283,7 +334,7 @@ async def test_update_metamessage(client, db_session, sample_data):
message_id=test_message.public_id,
content="Test Metamessage",
h_metadata={},
metamessage_type="test_type",
label="test_type",
)
db_session.add(test_metamessage)
await db_session.commit()
@ -292,14 +343,98 @@ async def test_update_metamessage(client, db_session, sample_data):
f"/v1/apps/{test_app.public_id}/users/{test_user.public_id}/metamessages/{test_metamessage.public_id}",
json={
"metadata": {"new_key": "new_value"},
"metamessage_type": "updated_type",
"label": "updated_type",
},
)
assert response.status_code == 200
data = response.json()
assert data["metadata"] == {"new_key": "new_value"}
assert data["label"] == "updated_type"
assert data["metamessage_type"] == "updated_type"
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)
assert data["app_id"] == str(test_app.public_id)
@pytest.mark.asyncio
async def test_create_metamessage_with_label_and_alias(client, db_session, sample_data):
test_app, test_user = sample_data
# Create a common session and message for both test cases
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="Shared message content",
is_user=True,
app_id=test_app.public_id,
user_id=test_user.public_id,
)
db_session.add(test_message)
await db_session.commit()
common_payload_parts = {
"session_id": str(test_session.public_id),
"message_id": str(test_message.public_id),
"metadata": {"source": "input_test"},
}
test_value_for_type = "input_consistency_test_type"
# 1. Create metamessage using "label"
response_with_label = client.post(
f"/v1/apps/{test_app.public_id}/users/{test_user.public_id}/metamessages",
json={
**common_payload_parts,
"content": "Content created with label",
"label": test_value_for_type,
},
)
assert response_with_label.status_code == 200
data_from_label_input = response_with_label.json()
# 2. Create metamessage using "metamessage_type" (alias)
response_with_alias = client.post(
f"/v1/apps/{test_app.public_id}/users/{test_user.public_id}/metamessages",
json={
**common_payload_parts,
"content": "Content created with alias",
"metamessage_type": test_value_for_type, # Using alias
},
)
assert response_with_alias.status_code == 200
data_from_alias_input = response_with_alias.json()
# Assertions for the first response (created with "label")
assert data_from_label_input["content"] == "Content created with label"
assert data_from_label_input["label"] == test_value_for_type
assert data_from_label_input["metamessage_type"] == test_value_for_type
assert data_from_label_input["metadata"] == common_payload_parts["metadata"]
assert data_from_label_input["metamessage_type"] == test_value_for_type
assert data_from_label_input["app_id"] == str(test_app.public_id)
assert data_from_label_input["user_id"] == str(test_user.public_id)
assert data_from_label_input["session_id"] == common_payload_parts["session_id"]
assert data_from_label_input["message_id"] == common_payload_parts["message_id"]
# Assertions for the second response (created with "metamessage_type")
assert data_from_alias_input["content"] == "Content created with alias"
assert (
data_from_alias_input["label"] == test_value_for_type
) # Output should still be "label"
assert data_from_alias_input["metamessage_type"] == test_value_for_type
assert data_from_alias_input["metadata"] == common_payload_parts["metadata"]
assert data_from_alias_input["metamessage_type"] == test_value_for_type
assert data_from_alias_input["user_id"] == str(test_user.public_id)
assert data_from_alias_input["session_id"] == common_payload_parts["session_id"]
assert data_from_alias_input["message_id"] == common_payload_parts["message_id"]
assert data_from_alias_input["app_id"] == str(test_app.public_id)
# Key assertion: The output for the type/label field is consistent ("label") and has the correct value
assert data_from_label_input["label"] == data_from_alias_input["label"]
assert (
data_from_label_input["metamessage_type"]
== data_from_alias_input["metamessage_type"]
)
assert data_from_label_input["label"] == data_from_label_input["metamessage_type"]
assert data_from_alias_input["label"] == data_from_alias_input["metamessage_type"]

View File

@ -59,7 +59,9 @@ 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={}, app_id=test_app.public_id)
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 +77,9 @@ 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"}, app_id=test_app.public_id
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 +97,9 @@ 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={}, app_id=test_app.public_id)
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 +116,9 @@ 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={}, app_id=test_app.public_id)
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 +137,9 @@ 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"}, app_id=test_app.public_id
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()
@ -188,7 +198,9 @@ 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"}, app_id=test_app.public_id
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,7 +266,9 @@ 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"}, app_id=test_app.public_id
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()
@ -285,7 +299,7 @@ async def test_deep_clone_session(client, db_session, sample_data):
message_id=test_message.public_id,
content="Test Metamessage 1",
h_metadata={},
metamessage_type="test_type",
label="test_type",
app_id=test_app.public_id,
)
test_metamessage_2 = models.Metamessage(
@ -294,7 +308,7 @@ async def test_deep_clone_session(client, db_session, sample_data):
message_id=test_message.public_id,
content="Test Metamessage 2",
h_metadata={},
metamessage_type="test_type",
label="test_type",
app_id=test_app.public_id,
)
test_metamessage_3 = models.Metamessage(
@ -303,7 +317,7 @@ async def test_deep_clone_session(client, db_session, sample_data):
message_id=test_message2.public_id,
content="Test Metamessage 3",
h_metadata={},
metamessage_type="test_type",
label="test_type",
app_id=test_app.public_id,
)
test_metamessage_4 = models.Metamessage(
@ -312,8 +326,8 @@ async def test_deep_clone_session(client, db_session, sample_data):
message_id=test_message2.public_id,
content="Test Metamessage 4",
h_metadata={},
metamessage_type="test_type_2",
app_id=test_app.public_id,
label="test_type_2",
)
db_session.add(test_metamessage_1)
@ -360,15 +374,19 @@ async def test_deep_clone_session(client, db_session, sample_data):
assert len(data["items"]) > 0
assert len(data["items"]) == 4
assert data["items"][0]["content"] == "Test Metamessage 1"
assert data["items"][0]["label"] == "test_type"
assert data["items"][0]["metamessage_type"] == "test_type"
assert data["items"][0]["metadata"] == {}
assert data["items"][1]["content"] == "Test Metamessage 2"
assert data["items"][1]["label"] == "test_type"
assert data["items"][1]["metamessage_type"] == "test_type"
assert data["items"][1]["metadata"] == {}
assert data["items"][2]["content"] == "Test Metamessage 3"
assert data["items"][2]["label"] == "test_type"
assert data["items"][2]["metamessage_type"] == "test_type"
assert data["items"][2]["metadata"] == {}
assert data["items"][3]["content"] == "Test Metamessage 4"
assert data["items"][3]["label"] == "test_type_2"
assert data["items"][3]["metamessage_type"] == "test_type_2"
assert data["items"][3]["metadata"] == {}
@ -378,7 +396,9 @@ 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"}, app_id=test_app.public_id
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()
@ -409,8 +429,8 @@ async def test_partial_deep_clone_session(client, db_session, sample_data):
message_id=test_message.public_id,
content="Test Metamessage 1",
h_metadata={},
metamessage_type="test_type",
app_id=test_app.public_id,
label="test_type",
)
test_metamessage_2 = models.Metamessage(
user_id=test_user.public_id,
@ -418,8 +438,8 @@ async def test_partial_deep_clone_session(client, db_session, sample_data):
message_id=test_message.public_id,
content="Test Metamessage 2",
h_metadata={},
metamessage_type="test_type",
app_id=test_app.public_id,
label="test_type",
)
test_metamessage_3 = models.Metamessage(
user_id=test_user.public_id,
@ -427,8 +447,8 @@ async def test_partial_deep_clone_session(client, db_session, sample_data):
message_id=test_message2.public_id,
content="Test Metamessage 3",
h_metadata={},
metamessage_type="test_type",
app_id=test_app.public_id,
label="test_type",
)
test_metamessage_4 = models.Metamessage(
user_id=test_user.public_id,
@ -436,8 +456,8 @@ async def test_partial_deep_clone_session(client, db_session, sample_data):
message_id=test_message2.public_id,
content="Test Metamessage 4",
h_metadata={},
metamessage_type="test_type_2",
app_id=test_app.public_id,
label="test_type_2",
)
db_session.add(test_metamessage_1)
@ -480,8 +500,10 @@ async def test_partial_deep_clone_session(client, db_session, sample_data):
assert len(data["items"]) > 0
assert len(data["items"]) == 2
assert data["items"][0]["content"] == "Test Metamessage 1"
assert data["items"][0]["label"] == "test_type"
assert data["items"][0]["metamessage_type"] == "test_type"
assert data["items"][0]["metadata"] == {}
assert data["items"][1]["content"] == "Test Metamessage 2"
assert data["items"][1]["label"] == "test_type"
assert data["items"][1]["metamessage_type"] == "test_type"
assert data["items"][1]["metadata"] == {}

View File

@ -245,11 +245,11 @@ def test_metamessage_validations_api(client, sample_data):
)
message_id = message_response.json()["id"]
# Test metamessage_type too short
# Test label too short
response = client.post(
f"/v1/apps/{test_app.public_id}/users/{test_user.public_id}/metamessages",
json={
"metamessage_type": "",
"label": "",
"content": "test content",
"session_id": session_id,
"message_id": message_id,
@ -258,15 +258,15 @@ def test_metamessage_validations_api(client, sample_data):
)
assert response.status_code == 422
error = response.json()["detail"][0]
assert error["loc"] == ["body", "metamessage_type"]
assert error["loc"] == ["body", "label"]
assert error["msg"] == "String should have at least 1 character"
assert error["type"] == "string_too_short"
# Test metamessage_type too long
# Test label too long
response = client.post(
f"/v1/apps/{test_app.public_id}/users/{test_user.public_id}/metamessages",
json={
"metamessage_type": "a" * 51,
"label": "a" * 51,
"content": "test content",
"session_id": session_id,
"message_id": message_id,
@ -275,7 +275,7 @@ def test_metamessage_validations_api(client, sample_data):
)
assert response.status_code == 422
error = response.json()["detail"][0]
assert error["loc"] == ["body", "metamessage_type"]
assert error["loc"] == ["body", "label"]
assert error["msg"] == "String should have at most 50 characters"
assert error["type"] == "string_too_long"
@ -283,7 +283,7 @@ def test_metamessage_validations_api(client, sample_data):
response = client.post(
f"/v1/apps/{test_app.public_id}/users/{test_user.public_id}/metamessages",
json={
"metamessage_type": "test_type",
"label": "test_type",
"content": "a" * 50001,
"message_id": message_id,
"session_id": session_id,

View File

@ -80,41 +80,43 @@ class TestMessageValidations:
class TestMetamessageValidations:
def test_valid_metamessage_create(self):
meta = MetamessageCreate(
metamessage_type="test",
label="test",
content="test content",
message_id="123",
metadata={},
)
assert meta.metamessage_type == "test"
assert meta.label == "test"
assert meta.content == "test content"
assert meta.message_id == "123"
def test_metamessage_type_too_short(self):
def test_label_too_short(self):
with pytest.raises(ValidationError) as exc_info:
MetamessageCreate(
metamessage_type="",
label="",
content="test",
message_id="123",
metadata={},
)
error_dict = exc_info.value.errors()[0]
error_dict = exc_info.value.errors(include_input=False)[0]
assert error_dict["type"] == "string_too_short"
assert error_dict["loc"] == ('label',)
def test_metamessage_type_too_long(self):
def test_label_too_long(self):
with pytest.raises(ValidationError) as exc_info:
MetamessageCreate(
metamessage_type="a" * 51,
label="a" * 51,
content="test",
message_id="123",
metadata={},
)
error_dict = exc_info.value.errors()[0]
error_dict = exc_info.value.errors(include_input=False)[0]
assert error_dict["type"] == "string_too_long"
assert error_dict["loc"] == ('label',)
def test_metamessage_content_too_long(self):
with pytest.raises(ValidationError) as exc_info:
MetamessageCreate(
metamessage_type="test",
label="test",
content="a" * 50001,
message_id="123",
metadata={},