1"use strict";(self.webpackChunksemantic_router_docs=self.webpackChunksemantic_router_docs||[]).push([[3524],{5145(e,n,s){s.r(n),s.d(n,{assets:()=>d,contentTitle:()=>l,default:()=>h,frontMatter:()=>i,metadata:()=>t,toc:()=>a});const t=JSON.parse('{"id":"tutorials/intelligent-route/router-memory","title":"Multi Turn Conversations","description":"Router Memory enables stateful conversations via the OpenAI Response API, supporting conversation chaining with previousresponseid.","source":"@site/versioned_docs/version-v0.2/tutorials/intelligent-route/router-memory.md","sourceDirName":"tutorials/intelligent-route","slug":"/tutorials/intelligent-route/router-memory","permalink":"/docs/v0.2/tutorials/intelligent-route/router-memory","draft":false,"unlisted":false,"editUrl":"https://github.com/vllm-project/semantic-router/edit/main/website/docs/tutorials/intelligent-route/router-memory.md","tags":[],"version":"v0.2","frontMatter":{},"sidebar":"tutorialSidebar","previous":{"title":"Intelligent LoRA Routing","permalink":"/docs/v0.2/tutorials/intelligent-route/lora-routing"},"next":{"title":"Model Selection Overview","permalink":"/docs/v0.2/tutorials/intelligent-route/model-selection/overview"}}');var r=s(74848),o=s(28453);const i={},l="Multi Turn Conversations",d={},a=[{value:"Overview",id:"overview",level:2},{value:"Request Flow",id:"request-flow",level:2},{value:"Endpoints",id:"endpoints",level:2},{value:"Configuration",id:"configuration",level:2},{value:"Usage",id:"usage",level:2},{value:"1. Create Response",id:"1-create-response",level:3},{value:"2. Continue Conversation",id:"2-continue-conversation",level:3},{value:"3. Get Response",id:"3-get-response",level:3},{value:"4. List Input Items",id:"4-list-input-items",level:3},{value:"5. Delete Response",id:"5-delete-response",level:3},{value:"API Translation",id:"api-translation",level:2},{value:"Reference",id:"reference",level:2}];function c(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",mermaid:"mermaid",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,o.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.header,{children:(0,r.jsx)(n.h1,{id:"multi-turn-conversations",children:"Multi Turn Conversations"})}),"\n",(0,r.jsxs)(n.p,{children:["Router Memory enables stateful conversations via the ",(0,r.jsx)(n.a,{href:"https://platform.openai.com/docs/api-reference/responses",children:"OpenAI Response API"}),", supporting conversation chaining with ",(0,r.jsx)(n.code,{children:"previous_response_id"}),"."]}),"\n",(0,r.jsx)(n.h2,{id:"overview",children:"Overview"}),"\n",(0,r.jsxs)(n.p,{children:["Semantic Router acts as the ",(0,r.jsx)(n.strong,{children:"unified brain"})," for multiple LLM backends that only support the Chat Completions API. It provides:"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Cross-Model Stateful Conversations"}),": Maintain conversation history across different models"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Unified Response API"}),": Single API interface regardless of backend model"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Transparent Translation"}),": Automatic conversion between Response API and Chat Completions"]}),"\n"]}),"\n",(0,r.jsx)(n.mermaid,{value:'flowchart TB\n subgraph Clients\n C1[Agent A]\n C2[Agent B]\n end\n\n subgraph SR["Semantic Router"]\n API[Response API]\n Store[(Conversation<br/>Store)]\n end\n\n subgraph Backends["LLM Backends (Chat Completions Only)"]\n M1[GPT-4o]\n M2[Claude]\n M3[Qwen]\n M4[Llama]\n end\n\n C1 & C2 --\x3e API\n API <--\x3e Store\n API --\x3e M1 & M2 & M3 & M4'}),"\n",(0,r.jsx)(n.p,{children:"With Router Memory, you can start a conversation with one model and continue it with another\u2014the conversation history is preserved in the router, not in any single backend."}),"\n",(0,r.jsx)(n.h2,{id:"request-flow",children:"Request Flow"}),"\n",(0,r.jsx)(n.mermaid,{value:'flowchart TB\n subgraph Client\n A1[POST /v1/responses]\n end\n\n subgraph Router["Semantic Router (extproc)"]\n B1[Receive Request]\n B2{Has previous_response_id?}\n B3[Load Conversation Chain]\n B4[Translate to Chat Completions]\n B5[Translate to Response API]\n B6[Store Response]\n end\n\n subgraph Store["Response Store"]\n C1[(Memory)]\n end\n\n subgraph Backend["Backend LLM"]\n D1[POST /v1/chat/completions]\n end\n\n A1 --\x3e B1\n B1 --\x3e B2\n B2 --\x3e|Yes| B3\n B2 --\x3e|No| B4\n B3 --\x3e C1\n C1 --\x3e B4\n B4 --\x3e D1\n D1 --\x3e B5\n B5 --\x3e B6\n B6 --\x3e C1\n B6 --\x3e A1'}),"\n",(0,r.jsx)(n.h2,{id:"endpoints",children:"Endpoints"}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Endpoint"}),(0,r.jsx)(n.th,{children:"Method"}),(0,r.jsx)(n.th,{children:"Description"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"/v1/responses"})}),(0,r.jsx)(n.td,{children:"POST"}),(0,r.jsx)(n.td,{children:"Create a new response"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"/v1/responses/{id}"})}),(0,r.jsx)(n.td,{children:"GET"}),(0,r.jsx)(n.td,{children:"Retrieve a stored response"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"/v1/responses/{id}"})}),(0,r.jsx)(n.td,{children:"DELETE"}),(0,r.jsx)(n.td,{children:"Delete a stored response"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"/v1/responses/{id}/input_items"})}),(0,r.jsx)(n.td,{children:"GET"}),(0,r.jsx)(n.td,{children:"List input items for a response"})]})]})]}),"\n",(0,r.jsx)(n.h2,{id:"configuration",children:"Configuration"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'response_api:\n enabled: true\n store_backend: "memory" # Currently only "memory" is supported\n ttl_seconds: 86400 # Default: 30 days\n max_responses: 1000\n'})}),"\n",(0,r.jsx)(n.h2,{id:"usage",children:"Usage"}),"\n",(0,r.jsx)(n.h3,{id:"1-create-response",children:"1. Create Response"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:'curl -X POST http://localhost:8801/v1/responses \\\n -H "Content-Type: application/json" \\\n -d \'{\n "model": "openai/gpt-oss-120b",\n "input": "Tell me a joke.",\n "instructions": "Remember my name is Xunzhuo. Then I will ask you!",\n "temperature": 0.7,\n "max_output_tokens": 100\n }\'\n'})}),"\n",(0,r.jsx)(n.p,{children:"Response:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-json",children:'{\n "id": "resp_7cb437001e1ad5b84b6dd8ef",\n "object": "response",\n "status": "completed",\n "output": [{\n "type": "message",\n "role": "assistant",\n "content": [{"type": "output_text", "text": "Sure thing, Xunzhuo! Why don\'t scientists trust atoms? Because they make up everything! \ud83d\ude04"}]\n }
1],\n "usage": {"input_tokens": 94, "output_tokens": 75, "total_tokens": 169}\n}\n'})}),"\n",(0,r.jsx)(n.h3,{id:"2-continue-conversation",children:"2. Continue Conversation"}),"\n",(0,r.jsxs)(n.p,{children:["Use ",(0,r.jsx)(n.code,{children:"previous_response_id"})," to chain conversations:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:'curl -X POST http://localhost:8801/v1/responses \\\n -H "Content-Type: application/json" \\\n -d \'{\n "model": "openai/gpt-oss-120b",\n "input": "What is my name?",\n "previous_response_id": "resp_7cb437001e1ad5b84b6dd8ef",\n "max_output_tokens": 100\n }\'\n'})}),"\n",(0,r.jsx)(n.p,{children:"Response:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-json",children:'{\n "id": "resp_ec2822df62e390dcb87aa61d",\n "status": "completed",\n "output": [{\n "type": "message",\n "role": "assistant",\n "content": [{"type": "output_text", "text": "Your name is Xunzhuo."}]\n }],\n "previous_response_id": "resp_7cb437001e1ad5b84b6dd8ef"\n}\n'})}),"\n",(0,r.jsx)(n.h3,{id:"3-get-response",children:"3. Get Response"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"curl http://localhost:8801/v1/responses/resp_7cb437001e1ad5b84b6dd8ef\n"})}),"\n",(0,r.jsx)(n.h3,{id:"4-list-input-items",children:"4. List Input Items"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"curl http://localhost:8801/v1/responses/resp_7cb437001e1ad5b84b6dd8ef/input_items\n"})}),"\n",(0,r.jsx)(n.p,{children:"Response:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-json",children:'{\n "object": "list",\n "data": [{\n "type": "message",\n "role": "system",\n "content": [{"type": "input_text", "text": "Remember my name is Xunzhuo."}]\n }],\n "has_more": false\n}\n'})}),"\n",(0,r.jsx)(n.h3,{id:"5-delete-response",children:"5. Delete Response"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"curl -X DELETE http://localhost:8801/v1/responses/resp_7cb437001e1ad5b84b6dd8ef\n"})}),"\n",(0,r.jsx)(n.h2,{id:"api-translation",children:"API Translation"}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Response API"}
1),(0,r.jsx)(n.th,{children:"Chat Completions"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"input"})}),(0,r.jsxs)(n.td,{children:[(0,r.jsx)(n.code,{children:"messages[].content"})," (role: user)"]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"instructions"})}),(0,r.jsxs)(n.td,{children:[(0,r.jsx)(n.code,{children:"messages[0]"})," (role: system)"]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"previous_response_id"})}),(0,r.jsxs)(n.td,{children:["Expanded to full ",(0,r.jsx)(n.code,{children:"messages"})," array"]})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"max_output_tokens"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"max_tokens"})})]})]})]}),"\n",(0,r.jsx)(n.h2,{id:"reference",children:"Reference"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"https://platform.openai.com/docs/api-reference/responses",children:"OpenAI Response API"})}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,o.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(c,{...e})}):c(e)}},28453(e,n,s){s.d(n,{R:()=>i,x:()=>l});var t=s(96540);const r={},o=t.createContext(r);function i(e){const n=t.useContext(o);return t.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:i(e.components),t.createElement(o.Provider,{value:n},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.