*** title: Sessions description: The runtime universe for your agent. ------------------------------------------------- The **Session** (`AgentSession`) is the container that holds your active conversation. It creates a sandbox for every user connection, managing state, resources, and the event loop. **One Session = One User** Every time a user connects via WebSocket (or phone), a new `AgentSession` instance is spawned. This ensures total isolation—variables set in one session never leak to another. *** ## Core Capabilities The Session is your primary interface for controlling the agent's environment. ### 1. Graph Construction You don't just add nodes; you build a graph. The session provides methods to define exactly how events flow. ```python async def on_start(session: AgentSession): # Add nodes to the sandbox session.add_node(agent) session.add_node(logger) # Define custom flow: Logger -> Agent session.add_edge(logger, agent) await session.start() ``` ### 2. Event Hooks **Power Feature:** You can listen to events globally! Use the `@session.on_event` decorator to inject logic without creating a dedicated node. This is perfect for simple side-effects like logging analytics or sending welcome messages. ```python @session.on_event("system.user_joined") async def welcome(session, event): print(f"User {event.session_id} connected!") @session.on_event("agent.speak") async def track_speech(session, event): metrics.increment("agent_speech_count") ``` ### 3. Automatic Plumbing The session automatically manages the entry and exit points of your graph. * **Root Node**: Automatically created. Receives events from the client and forwards them to your nodes. * **Sink Node**: Automatically created. Catches events from your nodes and sends them back to the client. *** ## SDK Reference | Method | Description | | :-------------------------------- | :--------------------------------------------------------------------- | | `session.add_node(node)` | Registers a node in the graph. | | `session.add_edge(parent, child)` | Connect two nodes explicitly. | | `session.start()` | Locks the graph, validates no cycles exist, and starts the event loop. | | `session.wait_until_complete()` | Keeps the process alive until the WebSocket disconnects. | | `session.context` | A dict-like object for storing session-scoped state. | **Cycle Detection** When you call `start()`, the session runs a validation algorithm. If your graph contains a cycle (A → B → A), it will raise a `ValueError` immediately to prevent infinite loops. *** ## Example: Complete Setup A full example showing graph building, hooks, and lifecycle management. ```python from smallestai.atoms.agent.session import AgentSession from smallestai.atoms.agent.server import AtomsApp async def setup(session: AgentSession): # 1. Initialize Nodes agent = SalesAgent() tracker = StatsTracker() # 2. Build Graph session.add_node(tracker) session.add_node(agent) session.add_edge(tracker, agent) # Events go Tracker -> Agent # 3. Register Hooks @session.on_event("system.control.interrupt") async def on_interrupt(session, event): print("User interrupted the agent!") # 4. Launch await session.start() await session.wait_until_complete() if __name__ == "__main__": app = AtomsApp(setup_handler=setup) app.run() ```