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:
parent
d0285189c3
commit
1b54b4703b
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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" } }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -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 ###
|
||||
|
|
@ -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={},
|
||||
)
|
||||
|
|
|
|||
16
src/crud.py
16
src/crud.py
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
136
src/schemas.py
136
src/schemas.py
|
|
@ -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
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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"] == {}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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={},
|
||||
|
|
|
|||
Loading…
Reference in New Issue