A company/organization that uses the platform.
| 11 | |
| 12 | |
| 13 | class Tenant(Base): |
| 14 | """A company/organization that uses the platform.""" |
| 15 | |
| 16 | __tablename__ = "tenants" |
| 17 | |
| 18 | id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) |
| 19 | name: Mapped[str] = mapped_column(String(200), nullable=False) |
| 20 | slug: Mapped[str] = mapped_column(String(50), unique=True, nullable=False, index=True) |
| 21 | im_provider: Mapped[str] = mapped_column( |
| 22 | Enum("feishu", "dingtalk", "wecom", "microsoft_teams", "web_only", name="im_provider_enum"), |
| 23 | default="web_only", |
| 24 | nullable=False, |
| 25 | ) |
| 26 | im_config: Mapped[dict | None] = mapped_column(JSON, default=None) |
| 27 | is_active: Mapped[bool] = mapped_column(Boolean, default=True) |
| 28 | created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) |
| 29 | |
| 30 | # Default quotas for new users |
| 31 | default_message_limit: Mapped[int] = mapped_column(Integer, default=50) |
| 32 | default_message_period: Mapped[str] = mapped_column(String(20), default="permanent") |
| 33 | default_max_agents: Mapped[int] = mapped_column(Integer, default=2) |
| 34 | default_agent_ttl_hours: Mapped[int] = mapped_column(Integer, default=0) |
| 35 | default_max_llm_calls_per_day: Mapped[int] = mapped_column(Integer, default=1000) |
| 36 | |
| 37 | # Heartbeat frequency floor (minutes) — agents cannot heartbeat faster than this |
| 38 | min_heartbeat_interval_minutes: Mapped[int] = mapped_column(Integer, default=240) |
| 39 | |
| 40 | # Default timezone for all agents in this company (IANA format, e.g. "Asia/Shanghai") |
| 41 | timezone: Mapped[str] = mapped_column(String(50), default="UTC") |
| 42 | # Company country/region code used to derive default timezone and business calendar. |
| 43 | country_region: Mapped[str] = mapped_column(String(10), default="001") |
| 44 | |
| 45 | # SSO configuration |
| 46 | sso_enabled: Mapped[bool] = mapped_column(Boolean, default=False) |
| 47 | sso_domain: Mapped[str | None] = mapped_column(String(255), unique=True, index=True, nullable=True) |
| 48 | |
| 49 | # Trigger limits — defaults for new agents & floor values |
| 50 | default_max_triggers: Mapped[int] = mapped_column(Integer, default=20) |
| 51 | min_poll_interval_floor: Mapped[int] = mapped_column(Integer, default=5) |
| 52 | max_webhook_rate_ceiling: Mapped[int] = mapped_column(Integer, default=5) |
| 53 | |
| 54 | # A2A async communication (notify / task_delegate) |
| 55 | # When False, all agent-to-agent messages use synchronous consult mode |
| 56 | a2a_async_enabled: Mapped[bool] = mapped_column(Boolean, default=True) |
| 57 | |
| 58 | # Company default LLM model. Auto-set to the first enabled model the admin |
| 59 | # adds; used as the initial primary_model_id for new agents created in this |
| 60 | # tenant. SET NULL on model delete so the tenant just has no default until |
| 61 | # an admin picks a new one. |
| 62 | default_model_id: Mapped[uuid.UUID | None] = mapped_column( |
| 63 | UUID(as_uuid=True), ForeignKey("llm_models.id", ondelete="SET NULL"), nullable=True, |
| 64 | ) |
| 65 | |
| 66 | @property |
| 67 | def logo_url(self) -> str | None: |
| 68 | """Tenant logo URL stored in flexible tenant config.""" |
| 69 | if isinstance(self.im_config, dict): |
| 70 | value = self.im_config.get("logo_url") |
no outgoing calls
no test coverage detected