Skip to main content
When the same person uses your agent on both Telegram and Discord, they appear as two different users with separate memory stores. Identity resolution merges these into a single canonical identity, so the agent remembers context across platforms.

How It Works

The IdentityResolver maps (platform, platform_user_id) pairs to a single canonical_user_id. This canonical ID is then used for memory scoping, so all platforms share the same memory store.

Quick Example

from definable.interfaces import (
    SQLiteIdentityResolver,
    TelegramInterface,
    TelegramConfig,
    DiscordInterface,
    DiscordConfig,
    serve,
)

# Create a shared identity resolver
resolver = SQLiteIdentityResolver(db_path="./identity.db")

# Link platform accounts to canonical IDs
async with resolver:
    await resolver.link("telegram", "123456", "alice", username="Alice T")
    await resolver.link("discord", "789012", "alice", username="Alice D")

# Both interfaces use the same resolver
telegram = TelegramInterface(
    agent=agent,
    config=TelegramConfig(bot_token="..."),
    identity_resolver=resolver,
)

discord = DiscordInterface(
    agent=agent,
    config=DiscordConfig(bot_token="..."),
    identity_resolver=resolver,
)

# Messages from either platform resolve to user_id="alice"
await serve(telegram, discord, identity_resolver=resolver)

IdentityResolver Protocol

Any identity resolver must implement:
MethodDescription
await initialize()Set up the resolver (create tables, connect)
await close()Clean up resources
await resolve(platform, platform_user_id)Get the canonical user ID, or None if not linked
await link(platform, platform_user_id, canonical_user_id, username=None)Create or update a link
await unlink(platform, platform_user_id)Remove a link. Returns True if a link was removed
await get_identities(canonical_user_id)Get all platform identities for a canonical user

SQLiteIdentityResolver

The built-in implementation uses SQLite for persistence:
from definable.interfaces import SQLiteIdentityResolver

resolver = SQLiteIdentityResolver(db_path="./identity.db")
db_path
str
default:"./identity.db"
Path to the SQLite database file. Created automatically.
Supports async context manager:
async with SQLiteIdentityResolver(db_path="./identity.db") as resolver:
    await resolver.link("telegram", "123", "alice")
    user_id = await resolver.resolve("telegram", "123")  # "alice"

PlatformIdentity

The get_identities() method returns PlatformIdentity objects:
FieldTypeDescription
platformstrPlatform name (e.g., "telegram", "discord")
platform_user_idstrUser ID on that platform
canonical_user_idstrThe shared canonical ID
usernamestr | NoneOptional display name
linked_atfloatUnix timestamp of when the link was created

Integration with BaseInterface

Pass identity_resolver when creating any interface:
interface = TelegramInterface(
    agent=agent,
    config=config,
    identity_resolver=resolver,
)
When a message arrives, the interface calls resolver.resolve(platform, platform_user_id) before creating the agent session. If a canonical ID is found, it’s used as the user_id for memory and session scoping.

Integration with serve()

When using serve() for multi-interface deployments, pass the resolver once and it propagates to all interfaces:
await serve(
    telegram_interface,
    discord_interface,
    signal_interface,
    identity_resolver=resolver,
)