AskTGE — System Design Document
Team Global Express · AI Centre of Excellence How the four interconnected services that make up the AskTGE platform work together. Last mapped: 2026-06-10
1. Purpose & Scope
AskTGE is TGE's enterprise multi-agent AI platform. What users call "AskTGE" is not one app — it is a constellation of four independently-deployed services sharing one AWS account, one Azure AD tenant, and (critically) one AgentCore Memory store.
This doc maps the four repos, what each does, how they talk, and the data/identity that binds them.
| Repo (local dir) | Role | Runtime / Deploy |
|---|---|---|
asktge | User-facing web hub + orchestrator | Flask + Gunicorn (eventlet), ECS Fargate |
multiagent-backend | The actual conversational agent ("multipurpose"/OutlookAgent/Documind/TenderIQ) | LangGraph on AWS Bedrock AgentCore |
datamate | SQLMatic — NL→SQL agent over Redshift via MCP | LangGraph on AWS Bedrock AgentCore |
historyapi | Read/manage chat history | Async FastAPI, ECS Fargate |
All four live under GitLab gitlab.com/teamglobalexp/tge_ai_agents/*.
2. System Context (C4 Level 1)
┌──────────────────────┐
│ TGE Employee │
│ (browser) │
└──────────┬───────────┘
│ HTTPS + Azure AD SSO (OAuth2/PKCE)
▼
┌──────────────────────┐
│ asktge │ ← Flask hub / orchestrator
│ (routes→services) │ SSE streaming to browser
└───┬───────┬───────┬───┘
invoke_client.py │ │ history_client.py
│ │ │
┌────────────────────┘ │ └──────────────────┐
▼ ▼ ▼
┌───────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ multiagent- │ │ historyapi │ │ datamate │
│ backend │ │ (FastAPI/ECS) │ │ (SQLMatic) │
│ AgentCore │ │ reads history │ │ AgentCore │
│ LangGraph │ └───────┬──────────┘ │ + Redshift MCP │
└──────┬────────┘ │ └────────┬────────┘
│ writes turns │ reads turns │ SQL
▼ ▼ ▼
┌─────────────────────────────────────────────┐ ┌─────────────────┐
│ Shared AWS data plane: │ │ Amazon Redshift │
│ • AgentCore Memory (memory_*_env-…) │ │ Serverless │
│ • DynamoDB (sessions/turns) │ └─────────────────┘
│ • Bedrock KBs + Guardrails + S3 citations │
└─────────────────────────────────────────────┘
The binding fact: asktge, multiagent-backend, and historyapi all set the same AGENTCORE_MEMORY_ID per environment:
- Production:
memory_production_env-3N0XlR7T10 - Staging:
memory_staging_env-Px3te82OhR
multiagent-backend writes conversation turns into that memory; historyapi reads them back; asktge orchestrates both. That shared memory ID is the spine of the whole platform.
3. The Four Services
3.1 asktge — Web Hub & Orchestrator
Stack: Flask 3.1.3, Flask-SocketIO, Flask-Session (filesystem), Gunicorn eventlet workers, Python 3.10+. Docker → ECS Fargate.
Architecture: strict layering — Routes (Blueprints) → Services → Utils/Tools → External clients. Lazy init of heavy clients; background warmup threads post-startup.
Route blueprints (routes/):
auth_routes—/login /logout /callback /refresh(Azure AD OAuth2/PKCE)chat_routes—/chat /stream /send_message(SSE streaming to browser)file_routes—/upload /process_filehistory_routes—/history /load_sessionfeedback_routes—/feedback /analyticsutility_routes—/health /version /configsimple_download_routes—/download
Service layer (services/): ChatService (AI orchestration), NewChatStorageService (persistence/retrieval).
Two outbound clients are the integration seams:
| Client | Talks to | Endpoint(s) |
|---|---|---|
invoke_client.py | the agent backends | …sqlmatic…elb…/documind/api/invoke; https://tge-ai.awsagreenspace.local/multipurpose-agent/api/invoke |
history_client.py | historyapi | internal-AskTGE-HistAPI-{env}-…elb…:{8512 prod / 8812 staging} |
invoke_client.invoke_agent(...) posts a payload {sessionId, userId, agentId, prompt|messages, kb_id} to the agent /invoke endpoint. agentId is the router key — "Documind", "OutlookAgent", "TenderIQ", etc. select behaviour inside the AgentCore backend.
Agent registry (config/agents.py): dataclass AgentConfig registry (AskTGE, DataMate, AskLegal, Documind, TenderIQ, OutlookAgent, Nick Persona…). Visibility filtered per-request by AD group (Nick Persona is restricted). KB IDs live in config/knowledge_bases.py (Documind 0PKBENEOJZ, TenderIQ WAZKC2CY69, SQLMatic B5YEKE26GQ).
Local heavy lifting done in-process (not in the agents): document ingest (PDF/OCR, DOCX, XLSX, PPTX, images), invoice analysis, PII redaction, document/Excel/PPT/board-memo generation, SerpAPI search, Mermaid ERD from DataMate results.
3.2 multiagent-backend — The Conversational Agent
This is the "AI" behind AskTGE, Documind, TenderIQ, OutlookAgent. Despite the dir name (origin: outlook-agent repo), app.py builds a BedrockAgentCoreApp — i.e. it is deployed on AWS Bedrock AgentCore, invoked via the AgentCore runtime / the /multipurpose-agent/api/invoke and /documind/api/invoke paths that asktge calls.
Stack: LangGraph + LangChain, bedrock_agentcore SDK, boto3, Claude Sonnet 4 (BEDROCK_MODEL_ID), Python.
Module map:
ai/graphs.py— LangGraph graph builder (get_graph), LLM factories (_get_llm,_get_llm_fast);ai/spreadsheet_deepagent.py— deep spreadsheet sub-agent;ai/prompts.py,ai/models.py(+ observability).event_processing/—event_parser(LangGraphEventParser),event_formatter(ConsumerEventFormatter),response_accumulator(StreamingResponseAccumulator). Turns LangGraphastream_eventsinto SSE for asktge.storage/memory.py—_load_short_term,_store_turn,_store_complete_response,_summarize_old_turns→ writes to AgentCore Memory (AGENTCORE_MEMORY_ID).storage/dynamodb.py—_store_session_metadata.tools/—kb_search(Bedrock KB retrieve +_generate_presigned_urlfor S3 citations),deep_extraction,rate_limiter(internet search throttle).- Guardrails:
utils/error_handlingdetects/extracts Bedrock Guardrail interventions → user-friendly refusal messages.
Notable behaviour: citation enrichment (_enrich_citations_async) runs after the token stream so presigned-URL S3 calls never block streaming; parallelised via asyncio.gather + asyncio.to_thread. Config: AVAILABLE_AGENT_IDS, CONTEXT_TURNS/OUTLOOK_CONTEXT_TURNS, CONTEXT_CHAR_LIMIT, DEEP_EXTRACTION_ENABLED.
3.3 datamate — SQLMatic (NL→SQL over Redshift)
Stack: LangGraph agent (datamate/agent/ mirrors multiagent-backend's layout) on Bedrock AgentCore, Claude 4 Sonnet. Plus a separate MCP layer (datamate/mcp/): my_redshift_mcp + semantic-mcp, FastMCP servers.
How it queries data (MCP_REDSHIFT_INTEGRATION.md):
User question → LangGraph agent → LangChain tools (4 Redshift tools)
→ HTTP MCP client (JSON-RPC 2.0) → MCP Redshift server (FastMCP)
→ Amazon Redshift Serverless
Tools: redshift_list_schemas(), list tables, describe columns, run read-only SQL. Agent chains them; read-only safety enforced. Has its own cost/ module (bedrock_pricing.json + calculator) and ENCRYPTION_IMPLEMENTATION.md.
Deployment artifacts (top-level JSONs) describe the AgentCore deployment:
artifact.json— ECR container…/datamate/agent:<sha>network.json— VPC mode, sgsg-0ac5853078b7ff59c, two subnetsauthorizer.json— custom JWT authorizer = Azure AD (tenant0767fb79-…, audience77ca29af-…)headers.json— allowlistAuthorizationprotocol.json— HTTP
asktge reaches SQLMatic via the internal-sqlmatic-…elb… load balancer; results feed asktge's Mermaid ERD / chart generation (KB B5YEKE26GQ). Schema references for the underlying DBs sit in asktge/DB_Schema_Files/ (Goldhopper, MYTEAMGE, Rockhopper_NSW, TAPS, TED-EDS, TED-RDS).
3.4 historyapi — Chat History Service
Stack: async FastAPI (AgentCore History API - ASYNC), aioboto3 shared session via lifespan, structlog with per-request correlation IDs. Docker → ECS, ports 8512 (prod) / 8812 (staging).
Routers:
api/routes/history.py(prefix=/history) — v2 + v1 endpoints:GET /history/v2/user/session,…/v2/user/sessions/summaryDELETE /history/v2/user/session,PATCH /history/v2/user/session/rename- v1 legacy:
/history/user/session,/user/agent,/user,/user/recent
api/routes/admin.py— admin ops.
Services: memory_service (AgentCore Memory client — reads the same AGENTCORE_MEMORY_ID), dynamodb_service, encryption_service + local_encryption_service, secure_history_service. Starts in degraded mode if AGENTCORE_MEMORY_ID unset (memory client test non-fatal).
asktge/history_client.py consumes these (TTL-cached 5 min, USE_V2_ENDPOINT=true by default) to render the history panel and restore sessions.
4. Identity & Trust Boundary
One Azure AD tenant 0767fb79-566f-449b-a7eb-c665c261bc2e secures everything:
- Browser → asktge: OAuth2 PKCE interactive SSO (
auth_module.py), server-side encrypted Flask sessions, auto token refresh. - asktge → datamate (AgentCore): custom JWT authorizer validates Azure AD token (audience
77ca29af-…), onlyAuthorizationheader passed through. - asktge → multiagent-backend: AgentCore runtime invoke (ARN via
AGENTCORE_ARN/AGENTCORE_ARN_STAGING). - AD group gating: restricted agents (Nick Persona) filtered in
get_visible_agents(). - Internal ECS traffic over
*.elb.amazonaws.com/*.awsagreenspace.local(HTTP, self-signed — SSL warnings disabled in clients), inside VPC.
5. End-to-End Request Flows
5.1 General chat (Documind / OutlookAgent / TenderIQ)
1. Browser POST /stream (asktge chat_routes) [SSE opened]
2. @login_required → session token validated
3. ChatService builds prompt; files already PII-redacted & extracted locally
4. invoke_client.invoke_agent(agentId, sessionId, userId, prompt, kb_id)
5. multiagent-backend (AgentCore): LangGraph runs
→ KB retrieve (Bedrock) + tools + Guardrails
→ astream_events → SSE tokens back to asktge → browser (word-by-word)
6. Backend storage/memory: _store_turn / _store_complete_response → AgentCore Memory + DynamoDB
7. Citations enriched async (S3 presigned) after stream completes
8. On-demand: asktge generates DOCX/PDF/XLSX/PPT if download intent detected
5.2 DataMate (NL→SQL)
1. Browser selects DataMate agent → asktge
2. invoke to SQLMatic ELB (Azure AD JWT)
3. datamate LangGraph → Redshift MCP tools (JSON-RPC) → Redshift Serverless
4. Rows returned → asktge tools/ build Mermaid ERD + bar/pie charts
5. Streamed back via SSE
5.3 History load / restore
1. Browser opens history panel → asktge history_routes
2. history_client GET /history/v2/user/sessions/summary (TTL-cached)
3. historyapi reads AgentCore Memory + DynamoDB (shared memory ID), decrypts
4. Session restore → resume conversation context
6. Shared State & Coupling Map
| Shared resource | Producer | Consumer(s) | Coupling type |
|---|---|---|---|
AgentCore Memory (memory_*_env) | multiagent-backend (write) | historyapi (read), asktge | tight, implicit |
| DynamoDB sessions/turns | multiagent-backend | historyapi, asktge | tight |
| Azure AD tenant | — | all four | identity |
| Bedrock KBs + Guardrails | Bedrock | multiagent-backend, asktge | config (KB IDs) |
agentId contract | asktge (sends) | multiagent-backend (routes) | API contract |
| Redshift | datamate MCP | datamate only | isolated |
Risk note: the AgentCore Memory ID coupling is the platform's biggest hidden dependency — it is wired only through matching .env values across three repos. A drift between asktge / multiagent-backend / historyapi memory IDs silently breaks history without breaking live chat. Worth a single sourced config or a startup assertion.
7. Deployment Topology
| Service | Build → Run |
|---|---|
| asktge | Dockerfile → ECS Fargate; behind ALB; Gunicorn eventlet |
| historyapi | Dockerfile → ECS Fargate; ALB ports 8512/8812 |
| multiagent-backend | Dockerfile → Bedrock AgentCore runtime (ARN) |
| datamate (agent) | ECR image → Bedrock AgentCore (VPC, JWT authz) |
| datamate (mcp) | FastMCP server(s) in VPC, reached over HTTP/JSON-RPC |
Two staging/prod splits everywhere via ENVIRONMENT env var, separate ELBs, separate memory IDs, separate AgentCore ARNs.
8. Open Questions / Things To Verify
invoke_clientdefault base_url is the sqlmatic ELB/documind/api, yet code also callstge-ai.awsagreenspace.local/multipurpose-agent/api/invoke. Confirm which agents route through which ELB in prod (paths appear co-located behind one LB).multiagent-backend/config/settings.pydefault memory ID (memory_56vzf-b1iQHU78Br) differs from the.envvalues — confirm.envalways overrides in deployed envs.historyapionly exposes GET/DELETE/PATCH — turn writes happen exclusively inmultiagent-backend. Confirm no other writer.datamatetop-levelREADME.mdis the GitLab stub; real docs live inagent/README_MODULAR.md,agent/AI_GRAPHS_DOCUMENTATION.md,agent/MCP_REDSHIFT_INTEGRATION.md.
Appendix A — Endpoint Quick Reference
| From → To | URL |
|---|---|
| asktge → DataMate (prod) | internal-sqlmatic-1910921802.ap-southeast-2.elb.amazonaws.com |
| asktge → multipurpose agent | https://tge-ai.awsagreenspace.local/multipurpose-agent/api/invoke |
| asktge → historyapi (prod) | internal-AskTGE-HistAPI-production-369019032.ap-southeast-2.elb.amazonaws.com:8512 |
| asktge → historyapi (staging) | internal-AskTGE-HistAPI-staging-565808081.ap-southeast-2.elb.amazonaws.com:8812 |
| Bedrock AgentCore | ARN via AGENTCORE_ARN / AGENTCORE_ARN_STAGING |
Appendix B — Knowledge Base IDs
| Agent | KB ID |
|---|---|
| Documind | 0PKBENEOJZ |
| TenderIQ | WAZKC2CY69 |
| SQLMatic | B5YEKE26GQ |