# rrusson/virtualryan architecture

> Architecture diagram of the GitHub repository rrusson/virtualryan, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-09-25). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/rrusson/virtualryan
- Repository: https://github.com/rrusson/virtualryan
- Video tour (about a minute): https://gitdiagram.com/rrusson/virtualryan/video

## Overview

VirtualRyan is a resume and professional-background question-answering chatbot, with both a browser chat interface and an A2A interface for agent clients. In the browser workflow, a visitor submits a question, the client sends it to the chat API, and the server retrieves conversation history before asking the LLM; the response and updated history return to the interface, which can also speak the answer. The shared chat library adds resume context from text files. A2A clients use a separate handler and agent-card discovery path. The README documents GitHub Models as the intended provider; the sampled library supports configurable OpenAI-compatible endpoints, so the provider connection is shown generically. The A2A and frontend subsystem links reflect documented capabilities and tree paths; their unsampled implementation details are not inferred.

Main entry points: [`VirtualRyan.Server/Controllers/ChatController.cs`](https://github.com/rrusson/virtualryan/blob/main/VirtualRyan.Server/Controllers/ChatController.cs) (Chat endpoint), [`virtualryan.client/src/ResumeChat.tsx`](https://github.com/rrusson/virtualryan/blob/main/virtualryan.client/src/ResumeChat.tsx) (Chat interface), [`ChatBotLibrary/RyanChat.cs`](https://github.com/rrusson/virtualryan/blob/main/ChatBotLibrary/RyanChat.cs) (Chat client), [`VirtualRyan.Server/Program.cs`](https://github.com/rrusson/virtualryan/blob/main/VirtualRyan.Server/Program.cs) (HTTP hosting)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_client["Browser chat"]
  node_browser["Browser app<br/>[App.tsx]"]
  node_chatui["Chat interface<br/>[ResumeChat.tsx]"]
  node_chatstate["Chat state<br/>[useChat.ts]"]
  node_speech["Speech I/O<br/>[speechToText.ts]"]
  node_voice["Text-to-speech<br/>[textToSpeech.ts]"]
end

subgraph group_server["Chat API"]
  node_chatapi["Chat endpoint<br/>[ChatController.cs]"]
  node_history[("Conversation history")]
  node_ratemiddleware["A2A rate middleware"]
  node_ratelimits["Rate limits"]
  node_hosting["HTTP hosting<br/>[Program.cs]"]
end

subgraph group_agent["A2A access"]
  node_a2aendpoint["A2A endpoints<br/>[Program.cs]"]
  node_a2ahandler["A2A handler<br/>[A2AService.cs]"]
  node_agentcard["Agent card<br/>[A2AService.cs]"]
  node_callerlookup["Caller card lookup<br/>[A2AService.cs]"]
end

subgraph group_knowledge["Answer generation"]
  node_chatlibrary["Chat client<br/>[RyanChat.cs]"]
  node_contextfiles["Resume context"]
  node_filereader["Context reader<br/>[TextFileReader.cs]"]
end

node_visitor(("Visitor"))
node_a2aclient(("A2A client"))
node_llm{{"LLM provider"}}
node_cardresolver{{"Agent-card resolver"}}

node_visitor -->|"opens"| node_browser
node_browser -->|"renders"| node_chatui
node_chatui -->|"manages messages"| node_chatstate
node_chatui -.->|"captures speech"| node_speech
node_chatstate -.->|"speaks answer"| node_voice
node_chatui -->|"posts question"| node_chatapi
node_chatapi -->|"loads history"| node_history
node_chatapi -->|"asks with history"| node_chatlibrary
node_chatapi -->|"saves updated history"| node_history
node_chatlibrary -->|"reads context"| node_filereader
node_filereader -->|"loads text"| node_contextfiles
node_chatlibrary -->|"sends prompt"| node_llm
node_chatapi -->|"served by"| node_hosting
node_hosting -->|"applies to A2A"| node_ratemiddleware
node_ratemiddleware -->|"checks requests"| node_ratelimits
node_a2aclient -->|"discovers or sends"| node_a2aendpoint
node_a2aendpoint -->|"dispatches request"| node_a2ahandler
node_a2ahandler -->|"asks question"| node_chatlibrary
node_a2ahandler -->|"resolves caller"| node_callerlookup
node_callerlookup -.->|"fetches card"| node_cardresolver
node_hosting -->|"builds and exposes"| node_agentcard

click node_browser "https://github.com/rrusson/virtualryan/blob/main/virtualryan.client/src/App.tsx"
click node_chatui "https://github.com/rrusson/virtualryan/blob/main/virtualryan.client/src/ResumeChat.tsx"
click node_chatstate "https://github.com/rrusson/virtualryan/blob/main/virtualryan.client/src/hooks/useChat.ts"
click node_speech "https://github.com/rrusson/virtualryan/blob/main/virtualryan.client/src/speechToText.ts"
click node_voice "https://github.com/rrusson/virtualryan/blob/main/virtualryan.client/src/textToSpeech.ts"
click node_chatapi "https://github.com/rrusson/virtualryan/blob/main/VirtualRyan.Server/Controllers/ChatController.cs"
click node_history "https://github.com/rrusson/virtualryan/blob/main/VirtualRyan.Server/Services/ConversationHistoryService.cs"
click node_ratemiddleware "https://github.com/rrusson/virtualryan/blob/main/VirtualRyan.Server/Middleware/RateLimitingMiddleware.cs"
click node_ratelimits "https://github.com/rrusson/virtualryan/blob/main/VirtualRyan.Server/Services/RateLimitingService.cs"
click node_hosting "https://github.com/rrusson/virtualryan/blob/main/VirtualRyan.Server/Program.cs"
click node_a2aendpoint "https://github.com/rrusson/virtualryan/blob/main/VirtualRyan.Server/Program.cs"
click node_a2ahandler "https://github.com/rrusson/virtualryan/blob/main/VirtualRyan.Server/Services/A2AService.cs"
click node_agentcard "https://github.com/rrusson/virtualryan/blob/main/VirtualRyan.Server/Services/A2AService.cs"
click node_callerlookup "https://github.com/rrusson/virtualryan/blob/main/VirtualRyan.Server/Services/A2AService.cs"
click node_chatlibrary "https://github.com/rrusson/virtualryan/blob/main/ChatBotLibrary/RyanChat.cs"
click node_contextfiles "https://github.com/rrusson/virtualryan/blob/main/ChatBotLibrary/Context/RussonResume2026.txt"
click node_filereader "https://github.com/rrusson/virtualryan/blob/main/ChatBotLibrary/TextFileReader.cs"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_browser,node_chatui,node_chatstate,node_speech,node_voice,node_a2aclient toneBlue
class node_chatapi,node_history,node_ratemiddleware,node_ratelimits,node_hosting toneAmber
class node_a2aendpoint,node_a2ahandler,node_agentcard,node_callerlookup toneMint
class node_chatlibrary,node_contextfiles,node_filereader toneRose
class node_visitor,node_llm,node_cardresolver toneIndigo
```

## Components

### Browser chat

- [Browser app](https://github.com/rrusson/virtualryan/blob/main/virtualryan.client/src/App.tsx): `virtualryan.client/src/App.tsx`
- [Chat interface](https://github.com/rrusson/virtualryan/blob/main/virtualryan.client/src/ResumeChat.tsx): `virtualryan.client/src/ResumeChat.tsx`
- [Chat state](https://github.com/rrusson/virtualryan/blob/main/virtualryan.client/src/hooks/useChat.ts): `virtualryan.client/src/hooks/useChat.ts`
- [Speech I/O](https://github.com/rrusson/virtualryan/blob/main/virtualryan.client/src/speechToText.ts): `virtualryan.client/src/speechToText.ts`
- [Text-to-speech](https://github.com/rrusson/virtualryan/blob/main/virtualryan.client/src/textToSpeech.ts): `virtualryan.client/src/textToSpeech.ts`

### Chat API

- [Chat endpoint](https://github.com/rrusson/virtualryan/blob/main/VirtualRyan.Server/Controllers/ChatController.cs): `VirtualRyan.Server/Controllers/ChatController.cs`
- [Conversation history](https://github.com/rrusson/virtualryan/blob/main/VirtualRyan.Server/Services/ConversationHistoryService.cs): `VirtualRyan.Server/Services/ConversationHistoryService.cs`
- [A2A rate middleware](https://github.com/rrusson/virtualryan/blob/main/VirtualRyan.Server/Middleware/RateLimitingMiddleware.cs): `VirtualRyan.Server/Middleware/RateLimitingMiddleware.cs`
- [Rate limits](https://github.com/rrusson/virtualryan/blob/main/VirtualRyan.Server/Services/RateLimitingService.cs): `VirtualRyan.Server/Services/RateLimitingService.cs`
- [HTTP hosting](https://github.com/rrusson/virtualryan/blob/main/VirtualRyan.Server/Program.cs): `VirtualRyan.Server/Program.cs`

### A2A access

- [A2A endpoints](https://github.com/rrusson/virtualryan/blob/main/VirtualRyan.Server/Program.cs): `VirtualRyan.Server/Program.cs`
- [A2A handler](https://github.com/rrusson/virtualryan/blob/main/VirtualRyan.Server/Services/A2AService.cs): `VirtualRyan.Server/Services/A2AService.cs`
- [Agent card](https://github.com/rrusson/virtualryan/blob/main/VirtualRyan.Server/Services/A2AService.cs): `VirtualRyan.Server/Services/A2AService.cs`
- [Caller card lookup](https://github.com/rrusson/virtualryan/blob/main/VirtualRyan.Server/Services/A2AService.cs): `VirtualRyan.Server/Services/A2AService.cs`

### Answer generation

- [Chat client](https://github.com/rrusson/virtualryan/blob/main/ChatBotLibrary/RyanChat.cs): `ChatBotLibrary/RyanChat.cs`
- [Resume context](https://github.com/rrusson/virtualryan/blob/main/ChatBotLibrary/Context/RussonResume2026.txt): `ChatBotLibrary/Context/RussonResume2026.txt`
- [Context reader](https://github.com/rrusson/virtualryan/blob/main/ChatBotLibrary/TextFileReader.cs): `ChatBotLibrary/TextFileReader.cs`

### Other components

- **Visitor**
- **A2A client**
- **LLM provider**
- **Agent-card resolver**

## Connections

- Visitor → Browser app: opens
- Browser app → Chat interface: renders
- Chat interface → Chat state: manages messages
- Chat interface → Speech I/O: captures speech
- Chat state → Text-to-speech: speaks answer
- Chat interface → Chat endpoint: posts question
- Chat endpoint → Conversation history: loads history
- Chat endpoint → Chat client: asks with history
- Chat endpoint → Conversation history: saves updated history
- Chat client → Context reader: reads context
- Context reader → Resume context: loads text
- Chat client → LLM provider: sends prompt
- Chat endpoint → HTTP hosting: served by
- HTTP hosting → A2A rate middleware: applies to A2A
- A2A rate middleware → Rate limits: checks requests
- A2A client → A2A endpoints: discovers or sends
- A2A endpoints → A2A handler: dispatches request
- A2A handler → Chat client: asks question
- A2A handler → Caller card lookup: resolves caller
- Caller card lookup → Agent-card resolver: fetches card
- HTTP hosting → Agent card: builds and exposes
