Gateway Live Session Handoff

Move an in-progress conversation onto a freshly created thread on another platform

Start a conversation on your laptop, continue it on Telegram — the same session, the same transcript, the next reply lands where you moved.

Diagram

Live Session Handoff

💻 Origin Session

🔀 BotOS.handoff

🧵 create_thread on target

🌱 seed_history

📱 New Thread

Quick Start

  1. Minimal handoff
    python
    from praisonai_bot.bots import BotOS, ThreadRef
    
    ref: ThreadRef = await botos.handoff(session_key, to="telegram")
    
    if ref.ok:
        print(f"Continue on {ref.target}")
  2. With a seed message and breadcrumb
    python
    from praisonai_bot.bots import BotOS, ThreadRef
    
    ref = await botos.handoff(
        session_key,
        to="telegram",
        name="Trip planning",
        seed_text="Continuing here — same conversation.",
        announce=True,
    )

How It Works

handoff reuses DeliveryRouter.create_thread to open the destination thread, then seeds it with the origin transcript so the conversation continues seamlessly — it adds no new per-platform behaviour.

Diagram
Destination SessionAdapterDeliveryRouterBotOSUserDestination SessionAdapterDeliveryRouterBotOSUseropt[seed_text]opt[announce and origin]handoff(session_key, to)create_thread(to, name, origin)open native threadthread_idstatus=”ok”, thread_idexport_history(session_key)seed_history(dest_session_key, history)deliver seed_text into new threaddeliver “Continued on <platform>.” to originThreadRef(status=”ok”, session_key=dest)

The destination session key is composed as platform:channel:thread — subsequent turns arriving on the new thread route to it through the normal inbound path.


ThreadRef

handoff returns a frozen ThreadRef describing the destination thread and the session key subsequent turns route to.

FieldTypeDefaultDescription
platformstr(required)Destination platform id
channelstr(required)Destination channel id
thread_idstr(required)New thread/topic id — "" on non-ok
session_keystr(required)Destination session key subsequent turns route to — "" on non-ok
statusstr"ok""ok" / "unsupported" / "failed" / "no_route"
okbool (property)—status == "ok"
targetstr (property)—"platform:channel:thread" (or "platform:channel" when thread_id is empty)

handoff() Parameters

ParamTypeDefaultDescription
session_keystr(required)Resolved session key to move — as reported by BotSessionManager.warm_sessions / get_user_ids
tostr(required)Destination target: "platform", "platform:channel", or a router alias
namestr""Optional thread name (defaults to "Handoff")
seed_textOptional[str]NoneOptional first message posted into the new thread
announceboolTrueLeave a "Continued on <platform>." breadcrumb in origin
originOptional[SessionSource]NoneSource of the original request (for breadcrumb + target resolution)

Status Decision Guide

Every call resolves to exactly one status — map it to the right caller action.

Diagram

ok

unsupported

failed

no_route

ThreadRef.status

ok?

✅ Start next turn on ref.session_key

↩️ Fall back to identity linking

↩️ Retry-safe fallback

🛑 Stop — log the bad target

ValueMeaningCaller action
"ok"The thread was created and the session re-homedStart the next turn on ref.session_key
"unsupported"The target adapter has no supports_threads capabilityFall back to identity linking / pairing
"failed"The transport rejected the thread attemptRetry-safe fallback
"no_route"The to target didn’t resolve to a reachable channelStop and log the bad target

Capability Requirements

The target adapter must set supports_threads=True on its PlatformCapabilities; otherwise handoff returns status == "unsupported" and seeds nothing.

Channelsupports_threadsHandoff
TelegramYesForum topic
DiscordYesNative thread
SlackYesThread anchoring
WhatsAppNounsupported
EmailNounsupported

See Platform Capabilities for the per-adapter descriptor.


Common Patterns

Chat-command style — a /handoff <platform> wrapper moves the session and reports the outcome back.

python
from praisonai_bot.bots import BotOS, ThreadRef

async def on_handoff_command(botos: BotOS, session_key: str, platform: str, origin):
    ref = await botos.handoff(session_key, to=platform, origin=origin)
    if ref.ok:
        return f"Moved — continue on {ref.target}"
    return f"Could not hand off: {ref.status}"

Programmatic hand-off after a long-running step — move the user to their phone once the work is done.

python
ref = await botos.handoff(session_key, to="telegram", seed_text="Flight booked — continue with me here.")
if not ref.ok:
    ...  # unsupported | failed | no_route — keep the origin conversation

Best Practices

Branch on ref.ok — handoff never raises

An unsupported or unreachable target returns a non-ok ThreadRef instead of throwing. Check ref.ok; you do not need try/except.

Pass announce=False for batch or CLI origins

The "Continued on <platform>." breadcrumb interrupts the origin. Silence it with announce=False when the origin is a batch job or CLI you don’t want to notify.

Handoff moves the transcript, not the run

The next turn starts on the destination as soon as ref.ok is True. Route the following message to ref.session_key — the in-flight run is not transferred.

Fall back to identity linking on unsupported platforms

Platforms without native threads (WhatsApp, Email) return status == "unsupported". Link the user’s identities instead of opening a thread.


Long-running hosts

Gateways, bots, and servers keep bounded state (PraisonAI #5772):

StateBehaviour
Background jobsFinished jobs older than 1 hour are evicted (checked at most every 60s); get_result still returns the outcome
Sub-agent completion eventsCapped at the latest 1000; wait_for_completions does not hang on aged-out events
SQLite memory connectionsConnections from dead threads are closed
Context compressor historyCapped at 100 sessions

Related