Cross-platform sessions let one user keep a single conversation across every messaging platform.
from praisonai . bots import BotOS
from praisonaiagents import Agent
from praisonaiagents . session import FileIdentityResolver
agent = Agent ( name = " assistant " , instructions = " Be helpful. " )
resolver = FileIdentityResolver () # ~/.praisonai/identity.json
resolver . link ( " telegram " , " 12345 " , " alice " )
resolver . link ( " discord " , " snowflake-1 " , " alice " )
BotOS (
agent = agent ,
platforms =[ " telegram " , " discord " ],
identity_resolver = resolver ,
). run ()
How It Works
Quick Start
One platform, one user
from praisonai . bots import Bot
from praisonaiagents import Agent
agent = Agent ( name = " assistant " , instructions = " Be helpful. " )
bot = Bot ( " telegram " , agent = agent )
await bot . start ()
Two platforms, one user
from praisonai . bots import BotOS
from praisonaiagents import Agent
from praisonaiagents . session import FileIdentityResolver
agent = Agent ( name = " assistant " , instructions = " Be helpful. " )
resolver = FileIdentityResolver ()
resolver . link ( " telegram " , " 12345 " , " alice " )
resolver . link ( " discord " , " snowflake-1 " , " alice " )
botos = BotOS (
agent = agent ,
platforms =[ " telegram " , " discord " ],
identity_resolver = resolver ,
)
await botos . start ()
In-process testing / ephemeral
from praisonai . bots import BotOS
from praisonaiagents import Agent
from praisonaiagents . session import InMemoryIdentityResolver
agent = Agent ( name = " assistant " , instructions = " Be helpful. " )
resolver = InMemoryIdentityResolver () # Ephemeral for tests
resolver . link ( " telegram " , " 12345 " , " alice " )
resolver . link ( " discord " , " snowflake-1 " , " alice " )
botos = BotOS (
agent = agent ,
platforms =[ " telegram " , " discord " ],
identity_resolver = resolver ,
)
Choosing Your Resolver
SessionContext for Tools
Any tool the agent calls can read who is messaging:
from praisonaiagents import Agent
from praisonaiagents . session import get_session_context
def whoami () -> str :
ctx = get_session_context ()
return f "You are { ctx . user_name or ctx . user_id } on { ctx . platform } "
agent = Agent ( name = " assistant " , instructions = " Use whoami when asked. " , tools =[ whoami ])
SessionContext Fields
Field Type Description platformstr"telegram", "discord", "slack", …chat_idstrPlatform chat / channel id chat_namestrHuman-readable channel name thread_idstrThread / topic id (Slack threads, Telegram topics) user_idstrRaw platform user id user_namestrDisplay name unified_user_idstrResult of IdentityResolver.resolve()
Use set_session_context / clear_session_context for advanced custom adapters. Returns a token; reset in a finally block.
Mirror for Outbound Deliveries
Cron jobs, scheduled deliveries, and cross-platform replies need to mirror the assistant’s outbound message into the user’s history:
from praisonai . bots import mirror_to_session
# After sending a notification programmatically
mirror_to_session (
session_mgr = bot . _session ,
user_id = " alice " ,
message_text = " Reminder: your standup is in 5 minutes. " ,
source_label = " cron " ,
)
Parameters
Parameter Type Description session_mgrBotSessionManagerSession manager instance user_idstrUnified user ID message_textstrMessage content to mirror source_labelstrSource identifier ("cron", "web", "cross_platform") metadatadictOptional extra metadata lockthreading.RLockOptional lock for synchronization
Errors are swallowed and logged — a mirror failure must never break the outbound delivery itself.
Storage & Privacy
FileIdentityResolver defaults to ~/.praisonai/identity.json (override via PRAISONAI_IDENTITY_PATH env var or constructor path=). File is written atomically and chmod 0o600.
Identity links are explicit and opt-in . No automatic linking — wire the resolver only after a verified DM-pairing flow confirms the same human controls both accounts.
Without a resolver, the legacy bot_{platform}_{user_id} storage key is preserved bit-for-bit — fully backward compatible.
Best Practices
Use FileIdentityResolver by default
For production single-host bots, FileIdentityResolver provides persistent storage with atomic writes and proper file permissions. from praisonaiagents . session import FileIdentityResolver
resolver = FileIdentityResolver () # ~/.praisonai/identity.json
Implement custom IdentityResolverProtocol for scale
For multi-process/multi-host deployments, back it with SQLite, Redis, or a database: from praisonaiagents . session import IdentityResolverProtocol
class DatabaseIdentityResolver :
def resolve ( self , platform : str , platform_user_id : str ) -> str :
# Query your database
pass
def link ( self , platform : str , platform_user_id : str , unified_user_id : str ) -> None :
# Store in your database
pass
Never auto-link based on display name. Always require a DM-verified pairing flow: # After DM verification succeeds
resolver . link ( " telegram " , telegram_user_id , verified_unified_id )
resolver . link ( " discord " , discord_user_id , verified_unified_id )
Read SessionContext in tools
Instead of os.environ, read SessionContext — concurrent message handlers won’t trample each other: def get_user_platform () -> str :
ctx = get_session_context ()
return ctx . platform # Thread-safe, context-aware
BotOS Multi-platform bot orchestrator
Messaging Bots Platform-specific bot guides