---
title: "Exiting the agent loop"
icon: "lucide/DoorOpen"
---
import InstallSDKSnippet from "@/snippets/install-sdk.mdx"

After your agent has finished a workflow, you'll usually want to explicitly end that loop by calling the CopilotKit exit method in your agent code.

Exiting the agent has different effects depending on mode:

- **Router Mode**: Exiting the agent hands responsibility for handling input back to the router, which can initiate chat, call actions, other agents, etc. The router can return to this agent later (starting a new loop) to satisfy a user request.

- **Agent Lock Mode**: Exiting the agent restarts the workflow loop for the current agent.

In this example from [our email-sending app](https://github.com/copilotkit/copilotkit/tree/main/examples/coagents-qa), the `send_email` node explicitly exits, then manually sends a response back to the user as a `ToolMessage`:

<Steps>
    <Step>
        ### Install the CopilotKit SDK
        <InstallSDKSnippet components={props.components}/>
    </Step>

    <Step>
        ### Exit the agent loop
        This will exit the agent session as soon as the current LangGraph run is finished, either by a breakpoint or by reaching the `END` node.

        <Tabs groupId="language_langgraph_agent" items={['Python', 'TypeScript']} default="Python" persist>
            <Tab value="Python">
                ```python
                from copilotkit.langgraph import (copilotkit_exit)
                # ...
                async def send_email_node(state: EmailAgentState, config: RunnableConfig):
                    """Send an email."""

                    await copilotkit_exit(config) # [!code highlight]

                    # get the last message and cast to ToolMessage
                    last_message = cast(ToolMessage, state["messages"][-1])
                    if last_message.content == "CANCEL":
                        return {
                            "messages": [AIMessage(content="❌ Cancelled sending email.")],
                        }
                    else:
                        return {
                            "messages": [AIMessage(content="✅ Sent email.")],
                        }
                ```
            </Tab>
            <Tab value="TypeScript">
                ```typescript
                import { copilotkitExit } from "@copilotkit/sdk-js/langgraph";

                // ...

                async function sendEmailNode(state: EmailAgentState, config: RunnableConfig): Promise<{ messages: any[] }> {
                    // Send an email.

                    await copilotkitExit(config); // [!code highlight]

                    // get the last message and cast to ToolMessage
                    const lastMessage = state.messages[state.messages.length - 1] as ToolMessage;
                    if (lastMessage.content === "CANCEL") {
                        return {
                            messages: [new AIMessage(content="❌ Cancelled sending email.")],
                        }
                    } else {
                        return {
                            messages: [new AIMessage(content="✅ Sent email.")],
                        }
                    }
                }
                ```
            </Tab>
        </Tabs>
    </Step>
</Steps>
