{"slug":"swml-context-switch","title":"SWML Context Switch — Multi-Persona AI in One Call","tags":["signalwire","swml","context-switch","multi-persona","ai-routing"],"agent_summary":"The `context_switch` verb (and FunctionResult.switch_context) lets a live AI agent change persona mid-call. Use cases: triage agent → specialist agent, language change, escalation. Covers consolidate semantics and prompt overrides.","trigger_phrases":["context switch SWML","switch AI persona mid-call","consolidate context","triage to specialist agent","FunctionResult.switch_context","swml_change_context"],"runnable":true,"markdown":"\n# SWML `context_switch` — Mid-Call Persona Change\n\n`context_switch` swaps the active AI persona without dropping the call. Common pattern: a generic triage agent answers, identifies what the caller needs, and hands off to a specialist persona (sales, support, billing) that has its own prompt and SWAIG tools — all in the same call session.\n\n## The two ways to switch contexts\n\n### 1. From SWML (declarative)\n\nUse when contexts are predefined and selection happens via SWAIG or `cond`.\n\n```yaml\nversion: 1.0.0\nsections:\n  main:\n    - answer: {}\n    - ai:\n        prompt: { text: \"You are a triage agent. Identify if the caller needs sales, support, or billing.\" }\n        SWAIG:\n          defaults: { web_hook_url: \"https://your.api/swaig\" }\n          functions:\n            - function: route_to_sales\n              description: Caller needs sales.\n            - function: route_to_support\n              description: Caller needs technical support.\n            - function: route_to_billing\n              description: Caller has a billing question.\n```\n\nThe SWAIG handler returns a `FunctionResult` that switches the context.\n\n### 2. From a SWAIG handler (programmatic)\n\nIn the handler:\n\n```python\nfrom signalwire import FunctionResult\n\ndef route_to_sales(args, raw_data=None):\n    return FunctionResult(\"Connecting you to a sales specialist.\").switch_context(\n        \"sales\",\n        system_prompt=\"\"\"You are a senior sales rep for Acme Corp.\n        Focus on pricing, demos, and closing.\n        Use the lookup_pricing and book_demo tools as needed.\"\"\",\n        consolidate=True,\n    )\n\ndef route_to_support(args, raw_data=None):\n    return FunctionResult(\"Connecting you to support.\").switch_context(\n        \"support\",\n        system_prompt=\"You are a tier-2 support engineer. Triage and create a ticket.\",\n        consolidate=True,\n    )\n```\n\n## `switch_context` parameters\n\n| Parameter | Notes |\n|---|---|\n| `context_name` | Required. Name of the context to enter. |\n| `system_prompt` | Override the new context's prompt at runtime. Optional. |\n| `consolidate` | If `true`, replaces the entire conversation history with a one-paragraph summary before the new context starts. If `false`, the new persona inherits the full prior conversation. Defaults to `false`. |\n| `user_prompt` | Optional opening turn the AI will respond to inside the new context. |\n\n`consolidate=True` is the default in any handoff scenario — you don't want the specialist agent re-reading every word the caller said to the triage agent.\n\n## ContextBuilder (Python SDK) — defining the contexts up front\n\nUse [Context Builder](/topic/agents-context-builder) to define multiple contexts inside one agent.\n\n```python\ncontexts = self.define_contexts()\n\nmain = contexts.add_context(\"default\")\nmain.add_step(\"menu\") \\\n    .set_text(\"Ask whether the caller needs sales, support, or billing.\") \\\n    .set_functions(\"none\") \\\n    .set_valid_contexts([\"sales\", \"support\", \"billing\"])\n\nsales = contexts.add_context(\"sales\")\nsales.set_system_prompt(\"You are a friendly sales representative for Acme Corp.\")\nsales.add_step(\"qualify\") \\\n    .set_text(\"Understand what product the caller is interested in.\") \\\n    .set_functions([\"check_inventory\", \"get_pricing\"]) \\\n    .set_valid_steps([\"close\"])\nsales.add_step(\"close\") \\\n    .set_text(\"Close the sale or schedule a follow-up.\") \\\n    .set_valid_contexts([\"default\"])\n\nsupport = contexts.add_context(\"support\")\nsupport.set_system_prompt(\"You are a tier-2 support engineer.\")\nsupport.add_step(\"triage\").set_text(\"Get problem details, system info, urgency.\")\n```\n\nWhen the triage agent calls `switch_context(\"sales\")`, the SDK loads the sales context's system prompt, allowed functions, and entry step.\n\n## Mid-call language switch\n\n`switch_context` is the canonical way to change language mid-call. Define a Spanish context with its own voice, then switch:\n\n```python\nspanish = contexts.add_context(\"spanish\")\nspanish.set_system_prompt(\"Eres un agente bilingüe. Responde solo en español.\")\n# Languages are set at the agent level, but the prompt forces Spanish output.\n```\n\n```python\ndef switch_to_spanish(args, raw_data=None):\n    return FunctionResult(\"Cambiando al español.\").switch_context(\n        \"spanish\",\n        consolidate=True,\n    )\n```\n\nFor TTS voice changes per language, use the agent's [`languages` config](/topic/swml-ai-verb#languages-and-hints) — the AI picks the voice based on detected output language.\n\n## `consolidate` — when to set it false\n\n`consolidate=False` keeps the prior conversation in context. Use cases:\n\n- \"Hold while I check\" → backend lookup → resume same persona with new data.\n- Side-quest into a specialist that returns to the original persona.\n\n`consolidate=True` (recommended for handoffs):\n\n- Triage → specialist agent that should not see the triage chatter.\n- Compliance reset before billing questions.\n- Persona reset after extracting structured data.\n\n## `goto` vs `execute` vs `switch_context` — which one to use\n\n| Verb | Effect |\n|---|---|\n| `goto` | Jump to a different SWML section (no AI context implied). |\n| `execute` | Fetch and run a sub-SWML, return when done. The active AI session pauses during execution. |\n| `switch_context` (SWAIG return) | Keep the AI session alive, change its persona/tools/prompt. |\n\nIf the call has an active `ai` verb, prefer `switch_context` — it keeps the speech recognition, hints, and language settings warm.\n\n## Anti-patterns\n\n- Switching contexts without `consolidate=True` when the new persona shouldn't know the prior chat — leaks context, confuses the specialist agent.\n- Defining 10+ contexts on one agent — split into multiple agents on an [AgentServer](/topic/signalwire-python-agents-sdk#agentserver-multiple-agents-one-port) instead.\n- Switching contexts inside a `confirm` SWML — confirm scripts run on the callee leg, not the AI session.\n- Forgetting to `set_valid_contexts` on the source context — the SDK will refuse to transition.\n\n## See also\n\n- [Context Builder for multi-step flows](/topic/agents-context-builder)\n- [SWML AI verb](/topic/swml-ai-verb)\n- [SWAIG functions](/topic/swaig-functions)\n- [Python Agents SDK](/topic/signalwire-python-agents-sdk)\n","html":"<h1>SWML <code>context_switch</code> — Mid-Call Persona Change</h1>\n<p><code>context_switch</code> swaps the active AI persona without dropping the call. Common pattern: a generic triage agent answers, identifies what the caller needs, and hands off to a specialist persona (sales, support, billing) that has its own prompt and SWAIG tools — all in the same call session.</p>\n<h2>The two ways to switch contexts</h2>\n<h3>1. From SWML (declarative)</h3>\n<p>Use when contexts are predefined and selection happens via SWAIG or <code>cond</code>.</p>\n<pre><code class=\"language-yaml\">version: 1.0.0\nsections:\n  main:\n    - answer: {}\n    - ai:\n        prompt: { text: \"You are a triage agent. Identify if the caller needs sales, support, or billing.\" }\n        SWAIG:\n          defaults: { web_hook_url: \"https://your.api/swaig\" }\n          functions:\n            - function: route_to_sales\n              description: Caller needs sales.\n            - function: route_to_support\n              description: Caller needs technical support.\n            - function: route_to_billing\n              description: Caller has a billing question.\n</code></pre>\n<p>The SWAIG handler returns a <code>FunctionResult</code> that switches the context.</p>\n<h3>2. From a SWAIG handler (programmatic)</h3>\n<p>In the handler:</p>\n<pre><code class=\"language-python\">from signalwire import FunctionResult\n\ndef route_to_sales(args, raw_data=None):\n    return FunctionResult(\"Connecting you to a sales specialist.\").switch_context(\n        \"sales\",\n        system_prompt=\"\"\"You are a senior sales rep for Acme Corp.\n        Focus on pricing, demos, and closing.\n        Use the lookup_pricing and book_demo tools as needed.\"\"\",\n        consolidate=True,\n    )\n\ndef route_to_support(args, raw_data=None):\n    return FunctionResult(\"Connecting you to support.\").switch_context(\n        \"support\",\n        system_prompt=\"You are a tier-2 support engineer. Triage and create a ticket.\",\n        consolidate=True,\n    )\n</code></pre>\n<h2><code>switch_context</code> parameters</h2>\n<p>| Parameter | Notes |\n|---|---|\n| <code>context_name</code> | Required. Name of the context to enter. |\n| <code>system_prompt</code> | Override the new context's prompt at runtime. Optional. |\n| <code>consolidate</code> | If <code>true</code>, replaces the entire conversation history with a one-paragraph summary before the new context starts. If <code>false</code>, the new persona inherits the full prior conversation. Defaults to <code>false</code>. |\n| <code>user_prompt</code> | Optional opening turn the AI will respond to inside the new context. |</p>\n<p><code>consolidate=True</code> is the default in any handoff scenario — you don't want the specialist agent re-reading every word the caller said to the triage agent.</p>\n<h2>ContextBuilder (Python SDK) — defining the contexts up front</h2>\n<p>Use <a href=\"/topic/agents-context-builder\">Context Builder</a> to define multiple contexts inside one agent.</p>\n<pre><code class=\"language-python\">contexts = self.define_contexts()\n\nmain = contexts.add_context(\"default\")\nmain.add_step(\"menu\") \\\n    .set_text(\"Ask whether the caller needs sales, support, or billing.\") \\\n    .set_functions(\"none\") \\\n    .set_valid_contexts([\"sales\", \"support\", \"billing\"])\n\nsales = contexts.add_context(\"sales\")\nsales.set_system_prompt(\"You are a friendly sales representative for Acme Corp.\")\nsales.add_step(\"qualify\") \\\n    .set_text(\"Understand what product the caller is interested in.\") \\\n    .set_functions([\"check_inventory\", \"get_pricing\"]) \\\n    .set_valid_steps([\"close\"])\nsales.add_step(\"close\") \\\n    .set_text(\"Close the sale or schedule a follow-up.\") \\\n    .set_valid_contexts([\"default\"])\n\nsupport = contexts.add_context(\"support\")\nsupport.set_system_prompt(\"You are a tier-2 support engineer.\")\nsupport.add_step(\"triage\").set_text(\"Get problem details, system info, urgency.\")\n</code></pre>\n<p>When the triage agent calls <code>switch_context(\"sales\")</code>, the SDK loads the sales context's system prompt, allowed functions, and entry step.</p>\n<h2>Mid-call language switch</h2>\n<p><code>switch_context</code> is the canonical way to change language mid-call. Define a Spanish context with its own voice, then switch:</p>\n<pre><code class=\"language-python\">spanish = contexts.add_context(\"spanish\")\nspanish.set_system_prompt(\"Eres un agente bilingüe. Responde solo en español.\")\n# Languages are set at the agent level, but the prompt forces Spanish output.\n</code></pre>\n<pre><code class=\"language-python\">def switch_to_spanish(args, raw_data=None):\n    return FunctionResult(\"Cambiando al español.\").switch_context(\n        \"spanish\",\n        consolidate=True,\n    )\n</code></pre>\n<p>For TTS voice changes per language, use the agent's <a href=\"/topic/swml-ai-verb#languages-and-hints\"><code>languages</code> config</a> — the AI picks the voice based on detected output language.</p>\n<h2><code>consolidate</code> — when to set it false</h2>\n<p><code>consolidate=False</code> keeps the prior conversation in context. Use cases:</p>\n<ul>\n<li>\"Hold while I check\" → backend lookup → resume same persona with new data.</li>\n<li>Side-quest into a specialist that returns to the original persona.</li>\n</ul>\n<p><code>consolidate=True</code> (recommended for handoffs):</p>\n<ul>\n<li>Triage → specialist agent that should not see the triage chatter.</li>\n<li>Compliance reset before billing questions.</li>\n<li>Persona reset after extracting structured data.</li>\n</ul>\n<h2><code>goto</code> vs <code>execute</code> vs <code>switch_context</code> — which one to use</h2>\n<p>| Verb | Effect |\n|---|---|\n| <code>goto</code> | Jump to a different SWML section (no AI context implied). |\n| <code>execute</code> | Fetch and run a sub-SWML, return when done. The active AI session pauses during execution. |\n| <code>switch_context</code> (SWAIG return) | Keep the AI session alive, change its persona/tools/prompt. |</p>\n<p>If the call has an active <code>ai</code> verb, prefer <code>switch_context</code> — it keeps the speech recognition, hints, and language settings warm.</p>\n<h2>Anti-patterns</h2>\n<ul>\n<li>Switching contexts without <code>consolidate=True</code> when the new persona shouldn't know the prior chat — leaks context, confuses the specialist agent.</li>\n<li>Defining 10+ contexts on one agent — split into multiple agents on an <a href=\"/topic/signalwire-python-agents-sdk#agentserver-multiple-agents-one-port\">AgentServer</a> instead.</li>\n<li>Switching contexts inside a <code>confirm</code> SWML — confirm scripts run on the callee leg, not the AI session.</li>\n<li>Forgetting to <code>set_valid_contexts</code> on the source context — the SDK will refuse to transition.</li>\n</ul>\n<h2>See also</h2>\n<ul>\n<li><a href=\"/topic/agents-context-builder\">Context Builder for multi-step flows</a></li>\n<li><a href=\"/topic/swml-ai-verb\">SWML AI verb</a></li>\n<li><a href=\"/topic/swaig-functions\">SWAIG functions</a></li>\n<li><a href=\"/topic/signalwire-python-agents-sdk\">Python Agents SDK</a></li>\n</ul>\n"}