Text Generation
Transformers
English
Spanish
iot
smart-home
home-assistant
tool-calling
agent
cybersecurity
devops
ollama
inference-pipeline
autonomous-agent
raspberry-pi
qwen3-coder
Instructions to use MrMoz33/tokioai-coder-iot with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use MrMoz33/tokioai-coder-iot with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="MrMoz33/tokioai-coder-iot")# pip install -U transformers accelerate # Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("MrMoz33/tokioai-coder-iot", device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use MrMoz33/tokioai-coder-iot with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "MrMoz33/tokioai-coder-iot" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "MrMoz33/tokioai-coder-iot", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker
docker model run hf.co/MrMoz33/tokioai-coder-iot
- SGLang
How to use MrMoz33/tokioai-coder-iot with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "MrMoz33/tokioai-coder-iot" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "MrMoz33/tokioai-coder-iot", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "MrMoz33/tokioai-coder-iot" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "MrMoz33/tokioai-coder-iot", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }' - Docker Model Runner
How to use MrMoz33/tokioai-coder-iot with Docker Model Runner:
docker model run hf.co/MrMoz33/tokioai-coder-iot
Download engine/router.py from MrMoz33/tokioai-coder-iot: direct link, hf CLI and curl.
- Browser
- Download file 18.5 kB
-
https://huggingface.co/MrMoz33/tokioai-coder-iot/resolve/main/engine/router.py
- Command line
-
hf download hf://MrMoz33/tokioai-coder-iot/engine/router.py
-
curl -L -o router.py https://huggingface.co/MrMoz33/tokioai-coder-iot/resolve/main/engine/router.py
18.5 kB
| """ | |
| TokioAI Engine v3.0 -- Router / Intent Classifier | |
| Classifies user intent and builds optimal prompts with dynamic few-shot injection. | |
| v3.0 changes: | |
| - System prompt rewritten with INVESTIGATION PLAYBOOKS | |
| - "esta funcionando X?" is ALWAYS tool_call, never text | |
| - Better Spanish + investigation pattern detection | |
| - Knowledge about the local system (Pi, HA, Docker) | |
| """ | |
| import re | |
| from typing import Dict, List, Optional, Tuple | |
| from .schemas import TOOL_DEFINITIONS, tools_to_prompt_text | |
| # ============================================================ | |
| # INTENT CLASSIFICATION (zero-cost, pure regex/heuristics) | |
| # ============================================================ | |
| TOOL_INDICATORS = [ | |
| # Direct action verbs | |
| r'\b(run|execute|check|show|list|find|search|scan|install|deploy|restart|stop|start|kill|create|delete|remove|move|copy|rename)\b', | |
| # System queries (these ALWAYS need real data) | |
| r'\b(disk|memory|cpu|ram|process|port|network|service|docker|container|pid|uptime|load)\b', | |
| r'\b(file|directory|folder|path|config|log|permission)\b', | |
| # Specific commands | |
| r'\b(ls|cat|grep|find|ps|df|du|top|htop|netstat|ss|curl|wget|ping|nmap|apt|pip|npm|systemctl)\b', | |
| # Target references | |
| r'\b(raspi|raspberry|gcp|router|server|vm|machine|host)\b', | |
| # File operations | |
| r'\b(read|write|edit|modify|update|append|save)\s+(the\s+)?file\b', | |
| r'/[a-z]+(/[a-z0-9_./-]+)+', # Unix paths | |
| # Diagnostic | |
| r'\b(diagnos|health|status)\b', | |
| # STATE QUERIES -- these ALWAYS need tools (never answer from "knowledge") | |
| r'\b(running|installed|active|enabled|listening|open|up|down|alive|funciona|funcionando|corriendo|prendid[oa]|encendid[oa]|andando)\b', | |
| r'\b(version|cuant[oa]s?|cuales|which|where|donde|what.*running|que.*corre|que.*hay)\b', | |
| # Investigation patterns | |
| r'\b(check|verify|test|try|connect|access|reach|investigate)\b', | |
| # Home automation | |
| r'\b(home\s*assistant|hass|hassio|zigbee|zwave|mqtt|tasmota|esphome|automation|sensor|switch|light)\b', | |
| ] | |
| CODE_INDICATORS = [ | |
| r'\b(write|create|build|implement|code|script|function|class|program)\b.*\b(in|using|with)\s+(python|bash|javascript|rust|go|c\+\+|java|typescript)\b', | |
| r'\b(write|create|build)\b.*\b(python|bash|javascript|rust|go|java|typescript)\b.*\b(script|function|program|code)\b', | |
| r'\b(algorithm|data\s+structure|design\s+pattern|architecture)\b', | |
| r'\b(bug|error|fix|debug|traceback|exception|syntax)\b.*\b(code|script|program|file)\b', | |
| ] | |
| TEXT_INDICATORS = [ | |
| # Greetings (EN + ES) | |
| r'^(hi|hello|hey|hola|que\s+tal|buenos?\s+d[ií]as?|buenas?\s+(?:tardes?|noches?))\s*[.!?]*$', | |
| r'^(thanks?|thank\s+you|gracias|thx|de\s+nada)\s*[.!?]*$', | |
| # Conversational follow-ups | |
| r'^(como\s+(va|estas?|andas?|te\s+va)|how\s+are\s+you|how\'?s\s+it\s+going|what\'?s\s+up)\s*[.!?]*$', | |
| r'^(todo\s+bien|bien\s+y\s+tu|genial|cool|nice|great|awesome)\s*[.!?]*$', | |
| r'^(que\s+onda|que\s+hay|que\s+pasa|que\s+cuentas)\s*[.!?]*$', | |
| # Short affirmations | |
| r'^(yes|no|ok|okay|sure|maybe|si|no|dale|genial|perfecto|claro|obvio|exacto|listo)\s*[.!?]*$', | |
| # Identity / meta questions | |
| r'\b(who\s+are\s+you|what\s+can\s+you|tell\s+me\s+about\s+yourself)\b', | |
| r'\b(opinion|think\s+about|recommend|suggest|advice)\b', | |
| # Explicit CONCEPT explanations (NOT status checks) | |
| r'^(explain|describe|define)\s+(the\s+)?(concept|theory|protocol|idea|principle|difference)\b', | |
| r'^what\s+is\s+(a\s+)?(concept|theory|protocol|principle|idea|technique|method)\b', | |
| ] | |
| class IntentType: | |
| TOOL_CALL = "tool_call" | |
| CODE = "code" | |
| TEXT = "text" | |
| DECISION = "decision" | |
| def classify_intent(user_message: str, conversation_history: list = None) -> Tuple[str, float]: | |
| """ | |
| Classify user intent. Returns (intent_type, confidence). | |
| v3.0 RULE: Any question about whether something IS RUNNING, IS INSTALLED, | |
| IS WORKING, etc. is ALWAYS a tool_call. We can never answer these from | |
| "knowledge" -- we must CHECK THE ACTUAL SYSTEM. | |
| """ | |
| msg = user_message.lower().strip() | |
| # Investigation prompts from the engine itself | |
| if msg.startswith("investigation"): | |
| return IntentType.DECISION, 0.9 | |
| if "gathered enough" in msg or "final answer" in msg or "what i found" in msg: | |
| return IntentType.DECISION, 0.8 | |
| # Empty or very short | |
| if len(msg) < 3: | |
| return IntentType.TEXT, 0.9 | |
| # ===== STRONG TEXT SIGNALS (pure greetings, thanks, etc.) ===== | |
| # These are ONLY pure conversational. "hola" alone = text. | |
| # But "hola, esta funcionando HA?" = tool_call (caught by tool indicators below) | |
| for pattern in TEXT_INDICATORS: | |
| if re.match(pattern, msg, re.IGNORECASE): | |
| return IntentType.TEXT, 0.95 | |
| # ===== STATE QUESTIONS ARE ALWAYS TOOL CALLS ===== | |
| # "esta funcionando X?" / "is X running?" / "funciona el HA?" / etc. | |
| state_patterns = [ | |
| r'\b(esta|está)\s+(funcionando|corriendo|andando|prendid[oa]|activ[oa]|instalad[oa])\b', | |
| r'\b(funciona|corre|anda)\s+(el|la|lo|los|las)?\s*\w+', | |
| r'\bis\s+\w+\s+(running|installed|active|working|up|down|alive|enabled|listening)\b', | |
| r'\b(running|installed|active|working|funciona)\b.*\?', | |
| r'\bcheck\s+(if|whether|that)\b', | |
| # Port/network state queries | |
| r'\b(puerto|port)\s+\d+', | |
| r'\bhay\s+algo\s+(en|corriendo|escuchando)', | |
| r'\b(que|qué)\s+(hay|corre|esta)\s+(en|corriendo)', | |
| r'\b(listening|escuchando)\s+(on|en)\b', | |
| # Who/what is queries about system state | |
| r'\b(quien|quién|who)\s+(esta|está|is)\s+(logueado|logged|conectado|connected)\b', | |
| r'\b(puertos?|ports?)\s+(estan|están|are)\s+(escuchando|listening|abiertos?|open)\b', | |
| r'\b(vulnerabilidad|vulnerability|vulnerabilidades|vulnerabilities)\b', | |
| r'\b(audit|auditoria|auditoría)\b.*\b(seguridad|security)\b', | |
| r'\b(seguridad|security)\b.*\b(audit|auditoria|auditoría)\b', | |
| r'\b(logueado|logged\s+in|conectado)\b', | |
| # Vision / robot camera queries | |
| r'\b(que\s+ves|qué\s+ves|what\s+do\s+you\s+see|what\s+can\s+you\s+see)\b', | |
| r'\b(mira|look|fijate|fíjate|observa|observe)\b', | |
| r'\b(hay\s+alguien|is\s+anyone|is\s+there\s+anyone|who\s+is\s+there|quien\s+hay)\b', | |
| r'\b(muestra|show\s+me|take\s+a\s+(photo|picture|snapshot)|saca\s+una?\s+foto)\b', | |
| r'\b(camara|cámara|camera)\b', | |
| r'\b(ves\s+algo|see\s+anything|what.s\s+around)\b', | |
| r'\b(describe\s+(the\s+)?room|describe\s+(la\s+)?habitaci[oó]n|describe\s+(el\s+)?entorno)\b', | |
| ] | |
| for pattern in state_patterns: | |
| if re.search(pattern, msg, re.IGNORECASE): | |
| return IntentType.TOOL_CALL, 0.95 | |
| # ===== "what is X?" knowledge questions (concept, not status) ===== | |
| # "what is docker?" = text. "what is running on port 8123?" = tool. | |
| if re.match(r'^(what\s+is|what\s+are|explain|describe|define|que\s+es|qué\s+es)\s+', msg): | |
| # Check if it's asking about runtime state | |
| if re.search(r'\b(running|on\s+port|installed|active|listening|my\s+server|this\s+machine)\b', msg): | |
| return IntentType.TOOL_CALL, 0.9 | |
| return IntentType.TEXT, 0.85 | |
| # Score each category | |
| tool_score = 0 | |
| code_score = 0 | |
| text_score = 0 | |
| for pattern in TOOL_INDICATORS: | |
| if re.search(pattern, msg, re.IGNORECASE): | |
| tool_score += 1 | |
| for pattern in CODE_INDICATORS: | |
| if re.search(pattern, msg, re.IGNORECASE): | |
| code_score += 1 | |
| for pattern in TEXT_INDICATORS: | |
| if re.search(pattern, msg, re.IGNORECASE): | |
| text_score += 1 | |
| # Boost: previous turn context | |
| if conversation_history: | |
| last = conversation_history[-1] if conversation_history else None | |
| if last and last.get("role") == "tool": | |
| tool_score += 2 | |
| if last and last.get("role") == "assistant": | |
| content = last.get("content", "") | |
| if "I ran:" in content or "Result of" in content: | |
| tool_score += 1 | |
| # Determine winner | |
| scores = { | |
| IntentType.TOOL_CALL: tool_score, | |
| IntentType.CODE: code_score, | |
| IntentType.TEXT: text_score, | |
| } | |
| max_score = max(scores.values()) | |
| total = sum(scores.values()) or 1 | |
| if max_score == 0: | |
| if len(msg) < 30: | |
| return IntentType.TEXT, 0.6 | |
| # Longer messages with no clear indicators -> decision | |
| return IntentType.DECISION, 0.4 | |
| winner = max(scores, key=scores.get) | |
| confidence = max_score / (total + 1) | |
| # Close scores -> decision | |
| if tool_score > 0 and text_score > 0 and abs(tool_score - text_score) <= 1: | |
| return IntentType.DECISION, 0.5 | |
| return winner, min(confidence, 0.95) | |
| # ============================================================ | |
| # SYSTEM PROMPT (v3.0 -- with investigation playbooks) | |
| # ============================================================ | |
| SYSTEM_PROMPT_BASE = """You are TokioAI -- an elite cybersecurity and DevOps AI agent. | |
| You execute commands, fix bugs, deploy infrastructure, and solve problems. | |
| You have full access to the user's systems via tools. | |
| ## CRITICAL RULES -- NEVER VIOLATE THESE | |
| 1. NEVER simulate or fake tool execution in your text responses. | |
| WRONG: writing "```bash\ndf -h\n```\nResult: ..." in your text. | |
| RIGHT: call the execute_local tool with {"command": "df -h"}. | |
| The engine will execute the tool and give you the real result. | |
| 2. When you need system information, ALWAYS use a tool call. | |
| NEVER make up or guess command output. NEVER write fake results. | |
| 3. Your text responses should contain ONLY your analysis and conclusions. | |
| NEVER include "I ran:", "Result of tool:", or "```bash" blocks that | |
| simulate command execution. | |
| 4. If you already have real tool results in the conversation, summarize | |
| them in plain language. Do NOT echo back raw tool output format. | |
| ## ENVIRONMENT | |
| You are running on a Raspberry Pi 5 (your-device, Debian/aarch64). | |
| Key services: | |
| - Home Assistant: runs as Docker container "homeassistant" (NOT systemd). Check with: docker ps | grep home | |
| - Docker: available. Most services run as containers. | |
| - Ollama: runs locally, accessed via SSH tunnel to L4 GPU on port 8200 | |
| - TokioAI Engine: this server (port 8080) | |
| - SSH tunnels: several active to GCP services | |
| When checking if something is running, ALWAYS check both systemd AND docker. | |
| ## ROBOT VISION (robot_vision tool) | |
| You have a camera on the PiCar-X robot. Use the robot_vision tool to SEE what the robot sees. | |
| - Use it when the user asks: "que ves?", "what do you see?", "look around", "describe the room", "hay alguien?", "who is there?" | |
| - The tool captures a live photo from the robot's camera and analyzes it with a vision AI model (moondream) | |
| - You can pass a specific question: robot_vision(question="how many people are in the room?") | |
| - Or leave question empty for a general description | |
| - The robot camera is at a low angle (ground level), so perspective may be different from human height | |
| - Response includes image size, capture time, analysis time, and the visual description | |
| - ALWAYS use robot_vision for visual questions. NEVER say "I can't see" -- you CAN see through the robot. | |
| ## HOME ASSISTANT VERIFICATION (CRITICAL) | |
| After calling ANY HA service (media, lights, switches, etc.), you MUST: | |
| 1. Execute the service call | |
| 2. Wait 3 seconds (sleep 3) | |
| 3. GET the entity state to confirm it ACTUALLY changed | |
| 4. Report what is ACTUALLY happening, not what you hoped | |
| HA auth: HA_TOKEN=$(cat ~/.ha_token) && curl -s -H "Authorization: Bearer $HA_TOKEN" ... | |
| Base URL: http://localhost:8123 | |
| For music changes specifically: | |
| After play_media, run: sleep 3 && HA_TOKEN=$(cat ~/.ha_token) && curl -s -H "Authorization: Bearer $HA_TOKEN" http://localhost:8123/api/states/media_player.YOUR_SPEAKER | python3 -c "import sys,json;s=json.load(sys.stdin);a=s['attributes'];print(f'State: {s[\"state\"]}, Title: {a.get(\"media_title\",\"?\")}, Artist: {a.get(\"media_artist\",\"?\")}')" | |
| If title/artist didn't change or state is not "playing", tell the user it FAILED. | |
| A 200 OK from the API only means HA received the request, NOT that it worked. ALWAYS verify. | |
| ## HOME ASSISTANT COOKBOOK (execute via execute_local tool) | |
| Auth pattern: HA_TOKEN=$(cat ~/.ha_token) && curl -s -H "Authorization: Bearer $HA_TOKEN" ... | |
| Base: http://localhost:8123 | |
| MEDIA (YOUR_SPEAKER (e.g. Amazon Echo), entity: media_player.YOUR_SPEAKER): | |
| - What's playing: GET /api/states/media_player.YOUR_SPEAKER (check media_title, media_artist, state) | |
| - CHANGE MUSIC: POST /api/services/media_player/play_media with {"entity_id":"media_player.YOUR_SPEAKER","media_content_type":"music","media_content_id":"QUERY"} (e.g. "blues", "rock", "Beatles") | |
| - Volume: POST /api/services/media_player/volume_set with {"entity_id":"media_player.YOUR_SPEAKER","volume_level":0.5} | |
| - Play/Pause: POST /api/services/media_player/media_play_pause with {"entity_id":"media_player.YOUR_SPEAKER"} | |
| - Next/Prev: POST /api/services/media_player/media_next_track or media_previous_track | |
| - TTS (Alexa speaks): POST /api/services/notify/alexa_media_YOUR_SPEAKER with {"message":"TEXT","data":{"type":"tts"}} | |
| - Announce: POST /api/services/notify/alexa_media_YOUR_SPEAKER with {"message":"TEXT","data":{"type":"announce"}} | |
| NEVER use notify to change music. notify is ONLY for TTS/announcements. | |
| LIGHTS: light.living_room, light.bedroom, light.kitchen (customize for your setup) | |
| - Turn on/off: POST /api/services/light/turn_on or turn_off with {"entity_id":"light.ENTITY"} | |
| - Brightness: turn_on with {"entity_id":"light.ENTITY","brightness":128} (0-255) | |
| - Color: turn_on with {"entity_id":"light.ENTITY","rgb_color":[255,0,0]} | |
| SWITCHES: switch.YOUR_SWITCH (customize) | |
| SENSORS: sensor.YOUR_TEMPERATURE, weather.forecast_home (customize) | |
| VACUUM: vacuum.YOUR_VACUUM (start, stop, return_to_base) | |
| ## CORE RULES | |
| - Be DIRECT. Act first, explain after. | |
| - NEVER give up. If something fails, try alternatives. | |
| - When investigating: diagnose -> try alternatives -> root cause -> answer. | |
| - NEVER output passwords, API keys, or tokens in plain text. | |
| - Be concise but thorough. | |
| ## INVESTIGATION BEHAVIOR | |
| You are an INVESTIGATOR. When asked about system state, security, or any technical question: | |
| 1. ALWAYS check the actual system. NEVER speculate or say "you should check X" -- CHECK IT YOURSELF. | |
| 2. If the first command doesn't give the full picture, run MORE commands automatically. | |
| 3. For security questions: check configs, ports, services, permissions, logs. Don't stop at 1 command. | |
| 4. For "is X running?": check systemctl, docker, ps, ports. Try multiple approaches. | |
| 5. NEVER ask "do you want me to check more?" -- just CHECK IT. You are the expert. | |
| 6. NEVER say "you should review X" -- YOU review it and report findings. | |
| 7. Think like a senior security engineer: be thorough, check multiple angles, report specifics. | |
| 8. Always use TOOL CALLS -- never simulate commands in your text response. | |
| ## ANSWER FORMAT | |
| When you've gathered enough information: | |
| - State what you found CLEARLY | |
| - If something is running: say what it is, where, which port, how it was started | |
| - If something is NOT available: say what you tried and why you're confident it's not there | |
| - NEVER give generic "recommendations" -- give FACTS based on what you actually found | |
| - NEVER guess or assume what service runs on a port -- only report what the tool output ACTUALLY shows | |
| - If ss/netstat shows a process name, report THAT name. Do NOT map port numbers to "well-known" services unless the output confirms it | |
| - Report EXACTLY what the command output says. If a port shows "ssh" as the process, say it's an SSH tunnel, not "Vault" or "Redis" etc.""" | |
| PROMPT_TOOL_CALL = """ | |
| The user wants you to DO something or CHECK something. Use the appropriate tool. | |
| - For shell commands: use execute_local | |
| - For file reading: use read_file | |
| - For searching: use search_files | |
| - For diagnostics: use diagnose | |
| - For seeing/looking/camera/vision: use robot_vision | |
| Call the tool IMMEDIATELY. Do not explain what you will do -- just do it. | |
| If you need multiple pieces of information, call the MOST IMPORTANT tool first. | |
| If a tool fails, you'll get a chance to try again with a different approach. | |
| NEVER ask the user "want me to check more?" -- you ARE the expert, so CHECK IT YOURSELF. | |
| NEVER recommend actions without doing them first. ACT, then REPORT.""" | |
| PROMPT_CODE = """ | |
| The user wants code or technical explanation. | |
| - If they want to CREATE a file: use write_file with the complete code | |
| - If they want to MODIFY code: use read_file first, then edit_file | |
| - If they want EXPLANATION: respond directly with concise, expert-level text | |
| - Show code, not descriptions of code""" | |
| PROMPT_TEXT = """ | |
| The user is having a conversation or asking a knowledge question. | |
| Respond directly WITHOUT using any tools. | |
| Be concise and helpful. Answer from your knowledge. | |
| Do NOT call any tools for pure knowledge questions. | |
| Do NOT simulate tool execution in your text. Just answer naturally.""" | |
| PROMPT_DECISION = """ | |
| You must decide: does this need a tool, or can you answer from knowledge? | |
| Guidelines: | |
| - "What is X?" (concept) = text answer | |
| - "Is X running?" / "Check X" / "Show X" = USE A TOOL (requires system state) | |
| - Anything about the current system state = USE A TOOL | |
| - Anything you can answer from pure knowledge = text answer | |
| - When in doubt, USE A TOOL -- it's better to check than to guess""" | |
| INTENT_PROMPTS = { | |
| IntentType.TOOL_CALL: PROMPT_TOOL_CALL, | |
| IntentType.CODE: PROMPT_CODE, | |
| IntentType.TEXT: PROMPT_TEXT, | |
| IntentType.DECISION: PROMPT_DECISION, | |
| } | |
| def build_system_prompt( | |
| intent: str, | |
| few_shot_examples: List[Dict] = None, | |
| extra_context: str = None, | |
| ) -> str: | |
| """Build the optimal system prompt for a given intent.""" | |
| parts = [SYSTEM_PROMPT_BASE] | |
| # Add intent-specific instructions | |
| parts.append(INTENT_PROMPTS.get(intent, PROMPT_DECISION)) | |
| # Add tool descriptions (for tool/decision intents) | |
| if intent in (IntentType.TOOL_CALL, IntentType.DECISION): | |
| parts.append("\n" + tools_to_prompt_text()) | |
| # Add few-shot examples | |
| if few_shot_examples: | |
| parts.append("\n--- RELEVANT EXAMPLES ---") | |
| for ex in few_shot_examples[:3]: | |
| parts.append(f"User: {ex.get('input', '')}") | |
| parts.append(f"Response: {ex.get('output', '')}") | |
| parts.append("--- END EXAMPLES ---") | |
| if extra_context: | |
| parts.append(f"\n{extra_context}") | |
| return "\n".join(parts) | |