Files
letta-server/letta/orm/identity.py
Kian Jones f5c4ab50f4 chore: add ty + pre-commit hook and repeal even more ruff rules (#9504)
* auto fixes

* auto fix pt2 and transitive deps and undefined var checking locals()

* manual fixes (ignored or letta-code fixed)

* fix circular import

* remove all ignores, add FastAPI rules and Ruff rules

* add ty and precommit

* ruff stuff

* ty check fixes

* ty check fixes pt 2

* error on invalid
2026-02-24 10:55:11 -08:00

75 lines
3.0 KiB
Python

import uuid
from typing import TYPE_CHECKING, List
if TYPE_CHECKING:
from letta.orm.agent import Agent
from letta.orm.block import Block
from letta.orm.organization import Organization
from sqlalchemy import String, UniqueConstraint
from sqlalchemy.dialects.postgresql import JSON
from sqlalchemy.orm import Mapped, mapped_column, relationship
from letta.orm.mixins import OrganizationMixin, ProjectMixin
from letta.orm.sqlalchemy_base import SqlalchemyBase
from letta.schemas.identity import Identity as PydanticIdentity, IdentityProperty
class Identity(SqlalchemyBase, OrganizationMixin, ProjectMixin):
"""Identity ORM class"""
__tablename__ = "identities"
__pydantic_model__ = PydanticIdentity
__table_args__ = (
UniqueConstraint(
"identifier_key",
"project_id",
"organization_id",
name="unique_identifier_key_project_id_organization_id",
postgresql_nulls_not_distinct=True,
# For SQLite compatibility, we'll need to handle the NULL case differently
# in the service layer since SQLite doesn't support postgresql_nulls_not_distinct
),
)
id: Mapped[str] = mapped_column(String, primary_key=True, default=lambda: f"identity-{uuid.uuid4()}")
identifier_key: Mapped[str] = mapped_column(nullable=False, doc="External, user-generated identifier key of the identity.")
name: Mapped[str] = mapped_column(nullable=False, doc="The name of the identity.")
identity_type: Mapped[str] = mapped_column(nullable=False, doc="The type of the identity.")
properties: Mapped[List["IdentityProperty"]] = mapped_column(
JSON, nullable=False, default=list, doc="List of properties associated with the identity"
)
# relationships
organization: Mapped["Organization"] = relationship("Organization", back_populates="identities")
agents: Mapped[List["Agent"]] = relationship(
"Agent", secondary="identities_agents", lazy="selectin", passive_deletes=True, back_populates="identities"
)
blocks: Mapped[List["Block"]] = relationship(
"Block", secondary="identities_blocks", lazy="selectin", passive_deletes=True, back_populates="identities"
)
# @property
# def agent_ids(self) -> List[str]:
# """Get just the agent IDs without loading the full agent objects"""
# return [agent.id for agent in self.agents]
# @property
# def block_ids(self) -> List[str]:
# """Get just the block IDs without loading the full agent objects"""
# return [block.id for block in self.blocks]
def to_pydantic(self) -> PydanticIdentity:
state = {
"id": self.id,
"identifier_key": self.identifier_key,
"name": self.name,
"identity_type": self.identity_type,
"project_id": self.project_id,
"agent_ids": [],
"block_ids": [],
"organization_id": self.organization_id,
"properties": self.properties or [],
}
return PydanticIdentity(**state)