MAF

9. Chat User Interface

Bring all previous modules together in four fully working interfaces: an interactive CLI, two web UIs (Chainlit and Streamlit), and a FastAPI REST API with a demo client β€” each powered by the same OpsAgent.

Module Goals

GoalCovered by
Build a runnable CLI chat for rapid local testinglab/app/cli/main.py
Create a polished web chat with built-in UIlab/app/web/chainlit/app.py
Create a customisable web chat with Streamlitlab/app/web/streamlit/app.py
Expose OpsAgent as a REST APIlab/app/web/fastapi/server.py
Consume the API from a Python clientlab/app/web/fastapi/client.py
Reuse every prior module in all interfacesShared app/shared/ layer

In This Module

Every interface activates the same full feature set:

ModuleFeature
Module 4Tools β€” Azure health check, deployment checklist, error diagnosis
Module 5MCP β€” Microsoft Learn documentation lookup
Module 6Multi-Turn β€” persistent conversation history per session
Module 7Memory β€” UserMemoryProvider remembers the user’s name
Module 8Workflow β€” three-step triage pipeline (severity tag β†’ agent β†’ output)

A shared module layer (app/shared/) contains the agent factory, workflow builder, tools, memory provider, and supporting MCP helpers so each interface imports them without duplication.

Folder Structure

lab/
└── app/
    β”œβ”€β”€ shared/
    β”‚   β”œβ”€β”€ agent.py        # Agent factory, workflow builder, classify_severity
    β”‚   β”œβ”€β”€ mcp.py          # Microsoft Learn / MCP integration helpers
    β”‚   β”œβ”€β”€ providers.py    # Module 7 UserMemoryProvider
    β”‚   β”œβ”€β”€ tools.py        # Module 4 tools (re-exported)
    β”‚   └── workflow.py     # Module 8 triage workflow builder
    β”œβ”€β”€ cli/
    β”‚   β”œβ”€β”€ main.py         # Interactive CLI
    β”‚   └── README.md
    └── web/
        β”œβ”€β”€ chainlit/
        β”‚   β”œβ”€β”€ app.py      # Chainlit web chat
        β”‚   β”œβ”€β”€ launcher.py # Chainlit app launcher
        β”‚   β”œβ”€β”€ chainlit.md
        β”‚   └── README.md
        β”œβ”€β”€ streamlit/
        β”‚   β”œβ”€β”€ app.py      # Streamlit web chat
        β”‚   └── README.md
        └── fastapi/
            β”œβ”€β”€ server.py   # FastAPI REST API
            β”œβ”€β”€ client.py   # Demo HTTP client
            └── README.md

Prerequisites

  • Completed Modules 1 – 8.
  • The lab/.env file contains GITHUB_TOKEN and GITHUB_MODEL.
  • The lab virtual environment is active (.venv).

Step 1 β€” Verify Dependencies

fastapi and uvicorn were added in this module. Confirm they are installed:

cd lab
uv sync

If you need to add them manually:

uv add "fastapi[standard]"

Step 2 β€” Explore the Shared Layer

Open lab/app/shared/agent.py. It provides three public functions used by all four interfaces:

FunctionWhat it does
create_chat_client(token, model)Returns a configured OpenAIChatCompletionClient
create_ops_agent(client)Returns an Agent wired with all Module 4–7 features
build_triage_workflow(client)Returns a compiled Module 8 Workflow

classify_severity(query) is also exported for interfaces that want to show the severity label before running the workflow.

Step 3 β€” Run the CLI

The CLI is the fastest way to test OpsAgent interactively.

cd lab/app/cli
python main.py

Available commands inside the CLI:

InputEffect
Any textRegular multi-turn chat (Modules 4 – 7 active)
!workflow <query>Runs the Module 8 triage pipeline
!statePrints current session state (user name from Module 7)
!helpLists all commands
exit or quitExits the CLI

Expected output (first turn):

╔══════════════════════════════════════════════════════════╗
β•‘          OpsAgent CLI β€” Module 9                         β•‘
β•‘  Active features:                                        β•‘
β•‘    βœ… Module 4 β€” Tools                                   β•‘
β•‘    βœ… Module 5 β€” MCP (Microsoft Learn)                   β•‘
β•‘    βœ… Module 6 β€” Multi-Turn History                      β•‘
β•‘    βœ… Module 7 β€” User Memory                             β•‘
β•‘    βœ… Module 8 β€” Workflow  (!workflow <query>)            β•‘
β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
πŸ‘€ You:

Step 4 β€” Run the Chainlit Web Chat

Chainlit provides a ready-made chat UI with no custom HTML required.

cd lab
python -m app.web.chainlit.launcher

Open http://localhost:8000 in your browser.

The launcher sets CHAINLIT_APP_ROOT to lab/app/web/chainlit, so Chainlit stores its .chainlit/ and .files/ folders next to the Chainlit app instead of under lab/.

Workflow command: in the chat input, type:

/workflow production database is down

This triggers the Module 8 triage pipeline and returns OpsAgent’s resolution steps inside the chat thread.

How the lifecycle works:

EventAction
on_chat_startCreates OpenAIChatCompletionClient, calls agent.__aenter__(), creates session
on_messageDispatches to /workflow handler or regular agent.run()
on_chat_endCalls agent.__aexit__() to release MCP connections

Step 5 β€” Run the Streamlit Web Chat

cd lab/app/web/streamlit
streamlit run app.py

Open http://localhost:8501 in your browser.

Sidebar features:

  • Active module list
  • Run Triage Workflow panel β€” enter a query and click β–Ά Run Workflow
  • Session State viewer β€” shows the user name captured by Module 7
  • Clear Chat button

Why a background thread? Streamlit re-runs the entire script on every user interaction. The SyncOpsAgent class keeps a dedicated asyncio event loop alive in a daemon thread so the async agent, its MCP connections, and its session state all persist across re-runs.

Step 6 β€” Run the FastAPI API and Client

Start the server

cd lab/app/web/fastapi
fastapi dev server.py

Open http://localhost:8000/docs for the interactive Swagger UI.

Endpoints

MethodPathDescription
GET/api/healthHealth check
POST/api/chatMulti-turn chat
POST/api/workflowRun the triage pipeline

Multi-turn chat request

POST /api/chat
{
  "message": "My name is Alex. What can you help me with?",
  "session_id": "my-session"
}

Pass the same session_id on every request to preserve conversation history (Module 6) and user memory (Module 7).

Workflow request

POST /api/workflow
{
  "query": "production server is down!"
}

Response:

{
  "severity": "CRITICAL",
  "query": "production server is down!",
  "response": "1. Verify network connectivity…"
}

Run the demo client

In a separate terminal (server must be running):

cd lab/app/web/fastapi
python client.py

The client demonstrates a three-turn chat (name introduction β†’ tool call β†’ name recall) and three workflow queries using the same session_id.

Expected Outcomes

After completing this module you will have:

  • βœ… An interactive CLI that exercises every workshop module
  • βœ… A Chainlit web chat with /workflow command support
  • βœ… A Streamlit web chat with a sidebar workflow panel and session state viewer
  • βœ… A FastAPI server exposing OpsAgent as a REST API
  • βœ… A demo HTTP client validating multi-turn memory and workflow across API calls
  • βœ… A shared app/shared/ layer that prevents code duplication

Key Concepts

ConceptWhere it appears
Shared agent factoryapp/shared/agent.py β€” create_ops_agent()
Async lifecycle managementCLI: async with agent; Chainlit: __aenter__/__aexit__; FastAPI: lifespan context
Async-to-sync bridgeStreamlit SyncOpsAgent β€” background thread + asyncio.run_coroutine_threadsafe
Per-session historyInMemoryHistoryProvider(load_messages=True) inside the agent
User memoryUserMemoryProvider β€” extracts and injects user name across turns
Triage workflowbuild_triage_workflow() β€” triage_input β†’ agent β†’ capture_output
Session isolationFastAPI _sessions dict; Streamlit st.session_state; Chainlit cl.user_session

Next

Continue to 10. Host Agent.