Prompt file imported from pkumar26/sharepoint-foundryagent (
.github/prompts/plan-conversationPersistence.prompt.md). Copyright stays with the author.
Plan: Conversation Persistence with Cosmos DB
Wire up the existing ConversationService and Conversation model to make multi-turn conversations real. The model, service, Cosmos CRUD, and frontend sidebar are already built — the gap is that POST /chat never reads or writes to Cosmos. This plan covers: Cosmos DB provisioning + RBAC, backend persistence in the chat endpoint, LLM-generated titles, Cosmos client lifecycle optimization, and frontend integration for loading history.
Steps
-
Provision Cosmos DB database + container — Run Azure CLI to create database
sharepoint-agentand containerconversationswith partition key/user_idand TTL enabled (--default-ttl -1) in the existingcosmos-xc4icdh2gdp6account inrg-ai-landing-zone-eastus2 -
Assign Cosmos RBAC roles — Grant
Cosmos DB Built-in Data Contributor(role00000000-0000-0000-0000-000000000002) to:- Container App Managed Identity (
80f72e51-b892-4640-bf80-78397395fc03) - Developer identity (for local dev via
DefaultAzureCredential) - Scope to
/dbs/sharepoint-agent/colls/conversations
- Container App Managed Identity (
-
Optimize Cosmos client lifecycle in src/main.py — Move
AsyncCosmosClient+ConversationServicecreation from per-request toapp.statein thelifespan()function. Initialize once, reuse across requests. Add a_get_conversation_service()FastAPI dependency -
Wire persistence into
POST /chatin src/main.py:- If
body.conversation_idis provided: load conversation viaConversationService.get_conversation(), extractconversation_historyfrom stored messages - If no
conversation_id: create new conversation viaConversationService.create_conversation() - Pass
conversation_historytoagent.answer_question() - After getting agent response: save user message + assistant message (with
source_references) viaConversationService.add_message()(two calls) - Return the real persisted
conversation_idinChatResponse
- If
-
Add LLM-generated conversation titles — Create a
generate_title()utility function in src/services/conversation.py using theopenaiSDK (AsyncAzureOpenAI). Call it after the first exchange (when creating a new conversation), requesting a 5-10 word title fromgpt-4owithmax_tokens=30, temperature=0.3. Update the conversation title asynchronously (fire-and-forget viaasyncio.create_taskso it doesn't block the response). Addtitlefield toChatResponseso the frontend can update the sidebar with the real title -
Update frontend (static/js/conversations.js, static/js/chat.js) — Update
onNewMessage()to usetitlefrom the chat response when available instead of truncating the user message. No other frontend changes needed — the sidebar already callsGET /conversations, loads history, and sendsconversation_idback -
Add
COSMOS_ENDPOINTto Container App env vars — Update the container app configuration withaz containerapp update --set-env-vars COSMOS_ENDPOINT=https://cosmos-xc4icdh2gdp6.documents.azure.com:443/ -
Tests — Update tests/integration/test_conversation_persistence.py to cover the new flow: create conversation on first message, load history on follow-up, title generation. Add happy-path contract tests for
GET /conversationsin tests/contract/test_conversations_api.py
Verification
- Local: Start server, send first message → verify Cosmos document created with generated title. Send follow-up → verify message appended and history used in response. Hit
GET /conversations→ verify list. Click sidebar item → verify history loads - Azure: Redeploy, confirm Cosmos RBAC works with Managed Identity (no 403s), verify multi-turn in the web UI
- Run
pytest tests/integration/test_conversation_persistence.pyandpytest tests/contract/test_conversations_api.py
Decisions
- Cosmos auth: Managed Identity (RBAC) via
DefaultAzureCredential— no keys - Title generation: LLM-generated via
openaiSDK (lightweight, no AutoGen overhead), fire-and-forget async task - Cosmos client: Singleton on
app.state(not per-request) for connection reuse - Scope: Full stack — backend + frontend sidebar wiring