danielrosehill commited on
Commit
39f7e06
Β·
1 Parent(s): 8318700

Update from architecture repo 2026-03-10

Browse files
Files changed (1) hide show
  1. index.html +72 -54
index.html CHANGED
@@ -23,7 +23,7 @@
23
  <div class="hero">
24
  <h1>The <span>Agentic</span> Symphony</h1>
25
  <p>An interactive map of all the moving pieces in a production agentic AI system.</p>
26
- <div class="meta">v<strong id="version">2.0.0</strong> &middot; <strong id="node-count">38</strong> nodes &middot; <strong id="conn-count">36</strong> connections &middot; <strong>13</strong> layers</div>
27
  </div>
28
 
29
  <!-- Stats -->
@@ -143,7 +143,7 @@
143
  </div>
144
 
145
  <footer>
146
- <strong>The Agentic Symphony</strong> &middot; v2.0.0 &middot;
147
  By <a href="https://danielrosehill.com" target="_blank">Daniel Rosehill</a> / Carrot Cake AI &middot;
148
  <a href="https://github.com/danielrosehill/agentic-ai-architecture-map" target="_blank">GitHub</a> &middot;
149
  MIT License
@@ -153,7 +153,7 @@
153
  // ═══════════════════════════════════════
154
  // ARCHITECTURE DATA (V2)
155
  // ═══════════════════════════════════════
156
- const ARCH = {"meta":{"title":"Agentic AI Architecture Map","version":"2.0.0"},"layers":[{"id":"prompts","label":"Prompts","position":"center","order":1,"color":"#4a6fa5","description":"The instruction layer \u2014 where human intent enters the system.","nodes":[{"id":"user-prompt","label":"User Prompt","description":"The actual question or instruction from the end user."},{"id":"system-prompt","label":"System Prompt","description":"Developer-defined instructions that shape the model\u2019s behavior, persona, and constraints. Also the injection point for RAG context."},{"id":"vendor-prompt","label":"Vendor Prompt","description":"Hidden instructions baked in by the provider \u2014 RLHF alignment, safety guardrails. The model is never truly vanilla."}]},{"id":"models","label":"Models","position":"center","order":2,"color":"#8b5cf6","description":"Foundation models that power reasoning and generation.","nodes":[{"id":"commercial-models","label":"Commercial","description":"Proprietary frontier models \u2014 Claude, GPT, Gemini, Cohere."},{"id":"open-source-models","label":"Open Source","description":"Open-weight models \u2014 Llama, Mistral, Qwen, DeepSeek, Phi."},{"id":"fine-tuned-models","label":"Fine-Tuned","description":"Task-specific models fine-tuned on your data."},{"id":"embedding-models","label":"Embedding","description":"Embedding models for vector representations \u2014 power the vector store and RAG, not agent reasoning."}]},{"id":"inference","label":"Inference","position":"center","order":3,"color":"#6366f1","description":"Where and how models are served \u2014 the compute layer.","nodes":[{"id":"model-gateway","label":"Gateway","description":"Model gateway/router \u2014 handles model selection, load balancing, failover, rate limiting, cost tracking. OpenRouter (hosted) or LiteLLM (self-hosted)."},{"id":"cloud-apis","label":"Cloud APIs","description":"Hosted API endpoints \u2014 Anthropic, OpenAI, Google, AWS Bedrock."},{"id":"self-hosted","label":"Self-Hosted","description":"Your own servers \u2014 vLLM, TGI, Ollama."},{"id":"on-prem","label":"On-Prem","description":"Air-gapped data center deployments."},{"id":"edge","label":"Edge","description":"Lightweight models on devices \u2014 low latency, offline."},{"id":"prompt-cache","label":"Cache","description":"Prompt/response caching \u2014 semantic dedup, cost reduction, latency improvement."}]},{"id":"context-store","label":"Context Store","position":"center","order":4,"color":"#2563eb","style":"dashed","description":"Knowledge layer \u2014 RAG and persistent memory.","nodes":[{"id":"context-rag","label":"Context (RAG)","description":"Retrieval-Augmented Generation \u2014 grounding AI in your documents."},{"id":"memory","label":"Memory","description":"Multiple forms: mined, ad-hoc, implicit, structured."},{"id":"vector-store","label":"Vector Store","description":"Embedding-based semantic search indexes."}]},{"id":"agents","label":"Agents","position":"center","order":5,"color":"#e85d26","description":"Orchestration and execution \u2014 where AI systems reason, plan, and act.","nodes":[{"id":"orchestration","label":"Orchestration","description":"Routes to agents, pipelines, or workflows. Handles failures and state."},{"id":"agents-node","label":"Agents","description":"Autonomous systems that reason, plan, act. Tool selection is intelligent and non-deterministic. Execution is a loop."},{"id":"pipelines","label":"Pipelines","description":"Multi-step chains. Tools wired at design time \u2014 no intelligent selection."},{"id":"workflows","label":"Workflows","description":"Event-triggered sequences. Tools pre-configured at each node."}]},{"id":"mcp","label":"MCP","position":"center","order":6,"color":"#f5a623","description":"Model Context Protocol \u2014 the open standard for connecting AI to tools and data.","nodes":[{"id":"mcp-protocol","label":"Model Context Protocol","description":"The open standard for connecting AI models to external tools, services, and data sources."},{"id":"tool-registry","label":"Tool Registry","description":"Discovery mechanism for available tools \u2014 in MCP this is tools/list."}]},{"id":"hitl","label":"Human-in-the-Loop","position":"center","order":7,"color":"#b91c1c","description":"Approval checkpoints \u2014 the brakes on the system.","style":"checkpoint","nodes":[{"id":"hitl-checkpoint","label":"Human-in-the-Loop","description":"Humans review and authorize agent actions before execution."}]},{"id":"actions","label":"Actions","position":"center","order":8,"color":"#2563eb","style":"dashed","description":"External systems agents act on \u2014 bidirectional: agents read and write.","nodes":[{"id":"your-data","label":"Your Data","description":"Salesforce, HubSpot, Google Drive, Notion \u2014 via MCP."},{"id":"search-apis","label":"Search APIs","description":"Web search, news feeds, real-time data."},{"id":"external-services","label":"External Services","description":"Weather, time, public datasets."},{"id":"digital-wallets","label":"Digital Wallets","description":"Payment and financial actions \u2014 Stripe, crypto wallets, bank APIs."}]},{"id":"storage","label":"Storage","position":"center","order":9,"color":"#14b8a6","description":"Persistence \u2014 conversations, outputs, prompts.","nodes":[{"id":"conversations","label":"Conversations","description":"Persisted threads for auditing, replay, and context mining."},{"id":"outputs","label":"Outputs","description":"Generated text, structured data, files, artifacts."},{"id":"stored-prompts","label":"Prompts","description":"Prompt templates and versioned prompt libraries."},{"id":"postgres","label":"Postgres","description":"Production relational databases."},{"id":"data-lakes","label":"Data Lakes","description":"Large-scale unstructured storage \u2014 logs, documents, embeddings."}]},{"id":"frontends","label":"Frontends","position":"left","order":2,"color":"#4a6fa5","description":"User-facing interfaces.","nodes":[{"id":"frontends-card","label":"Frontends","description":"Chat windows, bots, web UIs, dashboards."}],"sub_items":["Chatbots","Slack","Telegram","Web UIs","Dashboards"]},{"id":"safety","label":"Safety","position":"right","order":2,"color":"#b91c1c","description":"Constraints at multiple points: input, agent, tool-level.","nodes":[{"id":"safety-card","label":"Safety","description":"Guardrails and oversight mechanisms."}],"sub_items":["Guardrails","Security Harnesses","Input Filtering"]},{"id":"observability","label":"Observability","position":"right","order":3,"color":"#065f46","description":"Eval, logging, monitoring. Feeds back into prompt optimization.","nodes":[{"id":"observability-card","label":"Observability","description":"Tracking decisions, quality, actions, health."}],"sub_items":["Eval","Logging","Monitoring"]},{"id":"destinations","label":"Destinations","position":"left","order":9,"color":"#7c3aed","description":"Downstream consumers of stored outputs.","nodes":[{"id":"prompt-library","label":"Prompt Library","description":"Versioned, curated prompt templates for reuse."},{"id":"wiki-km","label":"Wiki / KM","description":"Organizational knowledge management."},{"id":"data-warehouse","label":"Data Warehouse","description":"Analytics, compliance, long-term retention."}]}],"connections":[{"id":"input-flow","from":"frontends-card","to":"user-prompt","label":"INPUT","style":"dashed","color":"#4a6fa5","description":"User requests flow from frontend to prompt layer."},{"id":"prompts-to-models","from":"prompts","to":"models","color":"#4a6fa5","description":"Assembled prompts (user + system + vendor + RAG context + tool defs) sent to model."},{"id":"models-to-inference","from":"models","to":"inference","color":"#8b5cf6","description":"Selected model served through chosen inference path."},{"id":"gateway-to-cloud-apis","from":"model-gateway","to":"cloud-apis","color":"#6366f1","description":"Gateway routes to cloud APIs based on model selection, cost, latency, or fallback rules."},{"id":"gateway-to-self-hosted","from":"model-gateway","to":"self-hosted","color":"#6366f1","description":"Gateway routes to self-hosted endpoints. LiteLLM unifies local and cloud access."},{"id":"inference-to-agents","from":"inference","to":"agents","color":"#6366f1","description":"Inference results feed into the agent orchestration layer."},{"id":"orchestration-to-agents","from":"orchestration","to":"agents-node","style":"dashed","color":"#e85d26","description":"Dispatches to agents for intelligent, flexible execution."},{"id":"orchestration-to-pipelines","from":"orchestration","to":"pipelines","style":"dashed","color":"#e85d26","description":"Dispatches to pipelines when steps are known and fixed."},{"id":"orchestration-to-workflows","from":"orchestration","to":"workflows","style":"dashed","color":"#e85d26","description":"Dispatches to workflows for event-triggered execution."},{"id":"agentic-loop","from":"agents-node","to":"inference","style":"dashed","color":"#e85d26","label":"AGENTIC LOOP","description":"Iterative execution: after each tool result, agent returns to model. May loop many times per request.","invocation_pattern":"autonomous"},{"id":"agents-autonomous-to-mcp","from":"agents-node","to":"mcp","color":"#e85d26","label":"AUTONOMOUS","description":"Agents autonomously invoke tools \u2014 intelligent, non-deterministic selection.","invocation_pattern":"autonomous"},{"id":"pipelines-deterministic-to-mcp","from":"pipelines","to":"mcp","color":"#e85d26","style":"solid","label":"DETERMINISTIC","description":"Tools wired at design time. Developer decides sequence.","invocation_pattern":"deterministic"},{"id":"workflows-deterministic-to-mcp","from":"workflows","to":"mcp","color":"#e85d26","style":"solid","label":"DETERMINISTIC","description":"Tools pre-configured per workflow node, event-triggered.","invocation_pattern":"deterministic"},{"id":"mcp-to-hitl","from":"mcp","to":"hitl","color":"#f5a623","label":"TAKING ACTIONS","style":"solid","no_arrow":true,"description":"Actions pass through human approval before execution."},{"id":"hitl-to-actions","from":"hitl","to":"actions","color":"#b91c1c","description":"Approved actions proceed to external systems."},{"id":"actions-data-retrieval","from":"actions","to":"mcp-protocol","style":"dashed","color":"#2563eb","label":"DATA RETRIEVAL","description":"Data retrieved from external systems flows back through MCP. Actions are bidirectional.","invocation_pattern":"bidirectional"},{"id":"agents-to-storage","from":"agents","to":"storage","style":"dashed","color":"#14b8a6","description":"Agents persist conversations, outputs, and prompt data."},{"id":"storage-to-context","from":"storage","to":"context-store","style":"dashed","color":"#2563eb","label":"CONTEXT-MINING","description":"Mined memory pattern \u2014 outputs post-processed into retrievable context.","invocation_pattern":"transport"},{"id":"context-to-agents","from":"context-store","to":"agents","style":"dashed","color":"#2563eb","description":"Context feeds back into agents \u2014 the virtuous knowledge cycle."},{"id":"agents-adhoc-memory","from":"agents-node","to":"memory","style":"dashed","color":"#2563eb","label":"AD-HOC MEMORY","description":"Agent directly writes/reads memory artifacts. Agent decides what to remember.","invocation_pattern":"bidirectional"},{"id":"output-flow","from":"agents-node","to":"frontends-card","label":"OUTPUT","style":"dashed","color":"#e85d26","description":"Agent responses delivered back to user through frontend."},{"id":"safety-to-agents","from":"safety-card","to":"agents","color":"#b91c1c","description":"Safety guardrails constrain agent behavior."},{"id":"safety-to-prompts","from":"safety-card","to":"prompts","color":"#b91c1c","style":"dashed","description":"Input guardrails \u2014 injection detection, content filtering."},{"id":"safety-to-mcp","from":"safety-card","to":"mcp-protocol","color":"#b91c1c","style":"dashed","description":"Tool-level safety \u2014 restricting tool access, parameter validation."},{"id":"observability-to-agents","from":"observability-card","to":"agents","color":"#065f46","description":"Monitoring and logging of agent execution."},{"id":"observability-to-storage","from":"observability-card","to":"data-lakes","style":"dashed","color":"#065f46","description":"Traces, logs, metrics persisted for analysis."},{"id":"observability-to-prompts","from":"observability-card","to":"stored-prompts","style":"dashed","color":"#065f46","label":"PROMPT OPTIMIZATION","description":"Eval results drive prompt iteration and versioning."},{"id":"frontends-to-observability","from":"frontends-card","to":"observability-card","style":"dashed","color":"#4a6fa5","description":"User feedback and telemetry flow to observability."},{"id":"context-rag-to-system-prompt","from":"context-rag","to":"system-prompt","style":"dashed","color":"#2563eb","label":"CONTEXT INJECTION","description":"RAG results injected into system prompt."},{"id":"embedding-models-to-vector-store","from":"embedding-models","to":"vector-store","style":"dashed","color":"#8b5cf6","description":"Embedding models generate vectors for semantic search."},{"id":"stored-prompts-to-prompt-library","from":"stored-prompts","to":"prompt-library","style":"dashed","color":"#4a6fa5","description":"Curated prompts become a versioned library."},{"id":"outputs-to-wiki","from":"outputs","to":"wiki-km","style":"dashed","color":"#7c3aed","description":"Agent outputs published to knowledge management."},{"id":"outputs-to-data-warehouse","from":"outputs","to":"data-warehouse","style":"dashed","color":"#7c3aed","description":"Outputs flow to data warehouse for analytics and compliance."},{"id":"postgres-to-context-store","from":"postgres","to":"context-rag","style":"dashed","color":"#14b8a6","description":"DB records indexed into RAG pipeline."},{"id":"user-prompt-to-conversations","from":"user-prompt","to":"conversations","style":"dashed","color":"#4a6fa5","description":"Prompts persisted as conversations for context mining."},{"id":"conversations-to-postgres","from":"conversations","to":"postgres","style":"dashed","color":"#14b8a6","label":"USER CONTEXT MINING","description":"Conversations mined for user context \u2014 preferences, patterns, domain knowledge."}]};
157
 
158
  // ═══════════════════════════════════════
159
  // HELPERS
@@ -263,7 +263,7 @@ document.querySelectorAll('nav .links a[href^="#"]').forEach(a => {
263
  // ═══════════════════════════════════════
264
  (function initDiagram() {
265
  const container = document.getElementById('diagram-container');
266
- const W = 1000, H = 1020;
267
  const centerW = 420;
268
  const centerX = (W - centerW) / 2;
269
  const centerCX = W / 2;
@@ -391,16 +391,16 @@ document.querySelectorAll('nav .links a[href^="#"]').forEach(a => {
391
  const arrowsG = g.append('g');
392
  const nodesG = g.append('g');
393
 
394
- // Y positions β€” restructured: Prompts β†’ Models β†’ Inference β†’ Context Store β†’ Agents β†’ MCP β†’ HITL β†’ Actions β†’ Storage
 
395
  const pY=20, pH=55;
396
  const mY=95, mH=60;
397
- const iY=175, iH=75;
398
- const csY=275, csH=65;
399
- const aY=370, aH=85;
400
- const mcpY=487, mcpH=55;
401
- const hitlY=574, hitlH=28;
402
- const actY=632, actH=95;
403
- const stY=760, stH=80;
404
 
405
  // ── PROMPTS ──
406
  layerBox(nodesG, centerX, pY, centerW, pH, '#4a6fa5', 'Prompts');
@@ -417,18 +417,25 @@ document.querySelectorAll('nav .links a[href^="#"]').forEach(a => {
417
  chip(nodesG, centerCX+160, mY+20, 'Embedding', '#a78bfa', 'Vector representations for RAG \u2014 distinct from generative LLMs.');
418
  drawConn(arrowsG, centerCX, mY+mH, centerCX, iY, '#8b5cf6');
419
 
420
- // ── INFERENCE ──
421
- layerBox(nodesG, centerX, iY, centerW, iH, '#6366f1', 'Inference');
422
- chip(nodesG, centerCX, iY+18, 'Gateway', '#6366f1', 'Model router \u2014 OpenRouter (hosted) or LiteLLM (self-hosted). Routes to cloud or local endpoints.');
423
- chip(nodesG, centerCX-110, iY+48, 'Cloud APIs', '#6366f1', 'Anthropic, OpenAI, Google, Bedrock.');
424
- chip(nodesG, centerCX-15, iY+48, 'Self-Hosted', '#6366f1', 'vLLM, TGI, Ollama.');
425
- chip(nodesG, centerCX+75, iY+48, 'On-Prem', '#818cf8', 'Air-gapped deployments.');
426
- chip(nodesG, centerCX+140, iY+48, 'Edge', '#818cf8', 'On-device, offline.');
427
- // Gateway routing arrows
428
- arrowsG.append('path').attr('d',`M${centerCX},${iY+34} L${centerCX-110},${iY+48}`).attr('stroke','#6366f1').attr('stroke-width',1.5).attr('opacity',0.4).attr('stroke-dasharray','3 2');
429
- arrowsG.append('path').attr('d',`M${centerCX},${iY+34} L${centerCX-15},${iY+48}`).attr('stroke','#6366f1').attr('stroke-width',1.5).attr('opacity',0.4).attr('stroke-dasharray','3 2');
430
  // Cache
431
- chip(nodesG, centerCX-170, iY+48, 'Cache', '#818cf8', 'Prompt/response caching \u2014 cost and latency reduction.');
 
 
 
 
 
 
 
 
 
 
432
 
433
  drawConn(arrowsG, centerCX, iY+iH, centerCX, csY, '#6366f1');
434
 
@@ -490,30 +497,11 @@ document.querySelectorAll('nav .links a[href^="#"]').forEach(a => {
490
  arrowsG.append('text').attr('x',centerCX+80).attr('y',(mcpY+mcpH+hitlY)/2+2).attr('text-anchor','start').attr('fill','#f5a623').attr('font-family','system-ui').attr('font-size','9').attr('font-weight','700').text('TAKING ACTIONS');
491
  drawConn(arrowsG, centerCX, hitlY+hitlH, centerCX, actY, '#b91c1c');
492
 
493
- // ── ACTIONS (was Integrations) ──
494
  layerBox(nodesG, centerX, actY, centerW, actH, '#2563eb', 'Actions', true);
495
- chip(nodesG, centerCX-95, actY+22, 'Your Data', '#2563eb', 'Salesforce, HubSpot, Google Drive, Notion.');
496
- chip(nodesG, centerCX+55, actY+22, 'Search APIs', '#2563eb', 'Web search, news, real-time data.');
497
- chip(nodesG, centerCX-65, actY+58, 'External Services', '#2563eb', 'Weather, time, public datasets.');
498
- chip(nodesG, centerCX+75, actY+58, 'Digital Wallets', '#1d4ed8', 'Stripe, crypto, bank APIs.');
499
-
500
- // ── STORAGE ──
501
- drawConn(arrowsG, centerCX+100, aY+aH, centerCX+100, stY, '#14b8a6', {dashed:true, opacity:0.4});
502
- layerBox(nodesG, centerX, stY, centerW, stH, '#14b8a6', 'Storage');
503
- chip(nodesG, centerCX-120, stY+18, 'Conversations', '#14b8a6', 'Persisted threads for auditing and mining.');
504
- chip(nodesG, centerCX-15, stY+18, 'Outputs', '#14b8a6', 'Generated text, data, artifacts.');
505
- chip(nodesG, centerCX+75, stY+18, 'Prompts', '#14b8a6', 'Versioned prompt templates.');
506
- chip(nodesG, centerCX-80, stY+50, 'Postgres', '#0d9488', 'Relational databases.');
507
- chip(nodesG, centerCX+70, stY+50, 'Data Lakes', '#0d9488', 'Logs, documents, embeddings.');
508
-
509
- // Storage -> Context Store feedback (curving left side, up)
510
- arrowsG.append('path')
511
- .attr('d', `M${centerX-4},${stY+stH/2} C${centerX-65},${stY+stH/2} ${centerX-65},${csY+csH/2} ${centerX},${csY+csH/2}`)
512
- .attr('fill','none').attr('stroke','#2563eb').attr('stroke-width',1.5).attr('stroke-dasharray','4 3').attr('opacity',0.4);
513
- arrowsG.append('polygon')
514
- .attr('points',`${centerX},${csY+csH/2} ${centerX-7},${csY+csH/2+4} ${centerX-7},${csY+csH/2-4}`)
515
- .attr('fill','#2563eb').attr('opacity',0.4);
516
- arrowsG.append('text').attr('x',centerX-70).attr('y',(stY+csY+csH)/2).attr('text-anchor','middle').attr('fill','#2563eb').attr('font-family','system-ui').attr('font-size','8').attr('font-weight','700').attr('transform',`rotate(-90,${centerX-70},${(stY+csY+csH)/2})`).text('CONTEXT-MINING');
517
 
518
  // ── LEFT: FRONTENDS ──
519
  const fe = card(nodesG, leftCX, mY+20, 130, 65, '#4a6fa5', '\u{1F4BB}', 'Frontends', 'Chat windows, bots, web UIs, dashboards.');
@@ -534,6 +522,35 @@ document.querySelectorAll('nav .links a[href^="#"]').forEach(a => {
534
  arrowsG.append('polygon').attr('points',`${leftCX+65},${fe.y+fe.h*0.7} ${leftCX+72},${fe.y+fe.h*0.7-4} ${leftCX+72},${fe.y+fe.h*0.7+4}`).attr('fill','#e85d26').attr('opacity',0.6);
535
  arrowsG.append('text').attr('x',(centerX+leftCX+65)/2).attr('y',aY+aH*0.65+14).attr('text-anchor','middle').attr('fill','#e85d26').attr('font-family','system-ui').attr('font-size','9').attr('font-weight','700').text('OUTPUT');
536
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
537
  // ── RIGHT: SAFETY + OBSERVABILITY ──
538
  const safetyC = card(nodesG, rightCX, mY+20, 130, 65, '#b91c1c', '\u{1F6E1}\uFE0F', 'Safety', 'Guardrails at prompts, agents, and tool level.');
539
  subChips(nodesG, rightCX, safetyC.y+safetyC.h+8, ['Guardrails'], '#b91c1c');
@@ -550,14 +567,15 @@ document.querySelectorAll('nav .links a[href^="#"]').forEach(a => {
550
  drawConn(arrowsG, rightCX-65, obsC.cy, centerX+centerW, aY+55, '#065f46');
551
 
552
  // ── RIGHT LOWER: DESTINATIONS ──
553
- chip(nodesG, rightCX, stY+4, 'Prompt Library', '#4a6fa5', 'Versioned, reusable prompt templates.');
554
- chip(nodesG, rightCX, stY+38, 'Wiki / KM', '#14b8a6', 'Organizational knowledge from agent outputs.');
555
- chip(nodesG, rightCX, stY+72, 'Data Warehouse', '#6366f1', 'Analytics, compliance, long-term retention.');
556
-
557
- // Storage -> Destinations arrows
558
- drawConn(arrowsG, centerCX+115, stY+18+14, rightCX-60, stY+4+14, '#4a6fa5', {dashed:true, opacity:0.4});
559
- drawConn(arrowsG, centerCX+25, stY+18+14, rightCX-50, stY+38+14, '#14b8a6', {dashed:true, opacity:0.4});
560
- drawConn(arrowsG, centerCX+25, stY+18+14, rightCX-60, stY+72+14, '#6366f1', {dashed:true, opacity:0.4});
 
561
 
562
  // Embedding -> Vector Store
563
  drawConn(arrowsG, centerCX+160, mY+20+28, centerCX+140, csY+25, '#8b5cf6', {dashed:true, opacity:0.35});
 
23
  <div class="hero">
24
  <h1>The <span>Agentic</span> Symphony</h1>
25
  <p>An interactive map of all the moving pieces in a production agentic AI system.</p>
26
+ <div class="meta">v<strong id="version">2.1.0</strong> &middot; <strong id="node-count">38</strong> nodes &middot; <strong id="conn-count">39</strong> connections &middot; <strong>14</strong> layers</div>
27
  </div>
28
 
29
  <!-- Stats -->
 
143
  </div>
144
 
145
  <footer>
146
+ <strong>The Agentic Symphony</strong> &middot; v2.1.0 &middot;
147
  By <a href="https://danielrosehill.com" target="_blank">Daniel Rosehill</a> / Carrot Cake AI &middot;
148
  <a href="https://github.com/danielrosehill/agentic-ai-architecture-map" target="_blank">GitHub</a> &middot;
149
  MIT License
 
153
  // ═══════════════════════════════════════
154
  // ARCHITECTURE DATA (V2)
155
  // ═══════════════════════════════════════
156
+ const ARCH = {"meta":{"title":"Agentic AI Architecture Map","version":"2.1.0"},"layers":[{"id":"prompts","label":"Prompts","position":"center","order":1,"color":"#4a6fa5","description":"The instruction layer \u2014 where human intent enters the system.","nodes":[{"id":"user-prompt","label":"User Prompt","description":"The actual question or instruction from the end user."},{"id":"system-prompt","label":"System Prompt","description":"Developer-defined instructions that shape the model\u2019s behavior, persona, and constraints. Also the injection point for RAG context."},{"id":"vendor-prompt","label":"Vendor Prompt","description":"Hidden instructions baked in by the provider \u2014 RLHF alignment, safety guardrails. The model is never truly vanilla."}]},{"id":"models","label":"Models","position":"center","order":2,"color":"#8b5cf6","description":"Foundation models that power reasoning and generation.","nodes":[{"id":"commercial-models","label":"Commercial","description":"Proprietary frontier models \u2014 Claude, GPT, Gemini, Cohere."},{"id":"open-source-models","label":"Open Source","description":"Open-weight models \u2014 Llama, Mistral, Qwen, DeepSeek, Phi."},{"id":"fine-tuned-models","label":"Fine-Tuned","description":"Task-specific models fine-tuned on your data."},{"id":"embedding-models","label":"Embedding","description":"Embedding models for vector representations \u2014 power the vector store and RAG, not agent reasoning."}]},{"id":"inference","label":"Inference","position":"center","order":3,"color":"#6366f1","description":"Where and how models are served \u2014 the compute layer. Gateway is optional: requests can route through a gateway or call endpoints directly.","nodes":[{"id":"model-gateway","label":"Gateway","description":"Model gateway/router \u2014 handles model selection, load balancing, failover, rate limiting, cost tracking. OpenRouter (hosted) or LiteLLM (self-hosted). Optional \u2014 agents can call endpoints directly."},{"id":"cloud-apis","label":"Cloud APIs","description":"Hosted API endpoints \u2014 Anthropic, OpenAI, Google, AWS Bedrock. Reachable via gateway or directly."},{"id":"self-hosted","label":"Self-Hosted","description":"Your own servers \u2014 vLLM, TGI, Ollama. Reachable via gateway or directly."},{"id":"on-prem","label":"On-Prem","description":"Air-gapped data center deployments."},{"id":"edge","label":"Edge","description":"Lightweight models on devices \u2014 low latency, offline."},{"id":"prompt-cache","label":"Cache","description":"Prompt/response caching \u2014 semantic dedup, cost reduction, latency improvement."}]},{"id":"context-store","label":"Context Store","position":"center","order":4,"color":"#2563eb","style":"dashed","description":"Knowledge layer \u2014 RAG and persistent memory.","nodes":[{"id":"context-rag","label":"Context (RAG)","description":"Retrieval-Augmented Generation \u2014 grounding AI in your documents."},{"id":"memory","label":"Memory","description":"Multiple forms: mined, ad-hoc, implicit, structured."},{"id":"vector-store","label":"Vector Store","description":"Embedding-based semantic search indexes."}]},{"id":"agents","label":"Agents","position":"center","order":5,"color":"#e85d26","description":"Orchestration and execution \u2014 where AI systems reason, plan, and act.","nodes":[{"id":"orchestration","label":"Orchestration","description":"Routes to agents, pipelines, or workflows. Handles failures and state."},{"id":"agents-node","label":"Agents","description":"Autonomous systems that reason, plan, act. Tool selection is intelligent and non-deterministic. Execution is a loop."},{"id":"pipelines","label":"Pipelines","description":"Multi-step chains. Tools wired at design time \u2014 no intelligent selection."},{"id":"workflows","label":"Workflows","description":"Event-triggered sequences. Tools pre-configured at each node."}]},{"id":"mcp","label":"MCP","position":"center","order":6,"color":"#f5a623","description":"Model Context Protocol \u2014 the open standard for connecting AI to tools and data.","nodes":[{"id":"mcp-protocol","label":"Model Context Protocol","description":"The open standard for connecting AI models to external tools, services, and data sources."},{"id":"tool-registry","label":"Tool Registry","description":"Discovery mechanism for available tools \u2014 in MCP this is tools/list."}]},{"id":"hitl","label":"Human-in-the-Loop","position":"center","order":7,"color":"#b91c1c","description":"Approval checkpoints \u2014 the brakes on the system.","style":"checkpoint","nodes":[{"id":"hitl-checkpoint","label":"Human-in-the-Loop","description":"Humans review and authorize agent actions before execution."}]},{"id":"actions","label":"Actions","position":"center","order":8,"color":"#2563eb","style":"dashed","description":"External systems agents act on \u2014 bidirectional: agents read and write.","nodes":[{"id":"your-data","label":"Your Data","description":"Salesforce, HubSpot, Google Drive, Notion \u2014 via MCP."},{"id":"external-services","label":"External Services","description":"Weather, time, public datasets."},{"id":"digital-wallets","label":"Digital Wallets","description":"Payment and financial actions \u2014 Stripe, crypto wallets, bank APIs."}]},{"id":"storage","label":"Storage","position":"left","order":9,"color":"#14b8a6","description":"Persistence \u2014 conversations, outputs, prompts.","nodes":[{"id":"conversations","label":"Conversations","description":"Persisted threads for auditing, replay, and context mining."},{"id":"outputs","label":"Outputs","description":"Generated text, structured data, files, artifacts."},{"id":"stored-prompts","label":"Prompts","description":"Prompt templates and versioned prompt libraries."},{"id":"postgres","label":"Postgres","description":"Production relational databases."},{"id":"data-lakes","label":"Data Lakes","description":"Large-scale unstructured storage \u2014 logs, documents, embeddings."}]},{"id":"frontends","label":"Frontends","position":"left","order":2,"color":"#4a6fa5","description":"User-facing interfaces.","nodes":[{"id":"frontends-card","label":"Frontends","description":"Chat windows, bots, web UIs, dashboards."}],"sub_items":["Chatbots","Slack","Telegram","Web UIs","Dashboards"]},{"id":"grounding","label":"Grounding","position":"left","order":5,"color":"#0891b2","description":"Real-time external data sources that ground agent responses in current information.","nodes":[{"id":"grounding-card","label":"Grounding","description":"External data sources that ground agent responses in current, real-world information."}],"sub_items":["Web Search","News Feeds","Real-Time Data"]},{"id":"safety","label":"Safety","position":"right","order":2,"color":"#b91c1c","description":"Constraints at multiple points: input, agent, tool-level.","nodes":[{"id":"safety-card","label":"Safety","description":"Guardrails and oversight mechanisms."}],"sub_items":["Guardrails","Security Harnesses","Input Filtering"]},{"id":"observability","label":"Observability","position":"right","order":3,"color":"#065f46","description":"Eval, logging, monitoring. Feeds back into prompt optimization.","nodes":[{"id":"observability-card","label":"Observability","description":"Tracking decisions, quality, actions, health."}],"sub_items":["Eval","Logging","Monitoring"]},{"id":"destinations","label":"Destinations","position":"left","order":9,"color":"#7c3aed","description":"Downstream consumers of stored outputs.","nodes":[{"id":"prompt-library","label":"Prompt Library","description":"Versioned, curated prompt templates for reuse."},{"id":"wiki-km","label":"Wiki / KM","description":"Organizational knowledge management."},{"id":"data-warehouse","label":"Data Warehouse","description":"Analytics, compliance, long-term retention."}]}],"connections":[{"id":"input-flow","from":"frontends-card","to":"user-prompt","label":"INPUT","style":"dashed","color":"#4a6fa5","description":"User requests flow from frontend to prompt layer."},{"id":"prompts-to-models","from":"prompts","to":"models","color":"#4a6fa5","description":"Assembled prompts (user + system + vendor + RAG context + tool defs) sent to model."},{"id":"models-to-inference","from":"models","to":"inference","color":"#8b5cf6","description":"Selected model served through chosen inference path."},{"id":"gateway-to-cloud-apis","from":"model-gateway","to":"cloud-apis","color":"#6366f1","description":"Gateway routes to cloud APIs based on model selection, cost, latency, or fallback rules."},{"id":"gateway-to-self-hosted","from":"model-gateway","to":"self-hosted","color":"#6366f1","description":"Gateway routes to self-hosted endpoints. LiteLLM unifies local and cloud access."},{"id":"direct-to-cloud-apis","from":"models","to":"cloud-apis","color":"#6366f1","style":"dashed","label":"DIRECT","description":"Direct inference path bypassing the gateway \u2014 agents call cloud API endpoints directly."},{"id":"direct-to-self-hosted","from":"models","to":"self-hosted","color":"#6366f1","style":"dashed","label":"DIRECT","description":"Direct inference path bypassing the gateway \u2014 agents call self-hosted endpoints directly."},{"id":"inference-to-agents","from":"inference","to":"agents","color":"#6366f1","description":"Inference results feed into the agent orchestration layer."},{"id":"orchestration-to-agents","from":"orchestration","to":"agents-node","style":"dashed","color":"#e85d26","description":"Dispatches to agents for intelligent, flexible execution."},{"id":"orchestration-to-pipelines","from":"orchestration","to":"pipelines","style":"dashed","color":"#e85d26","description":"Dispatches to pipelines when steps are known and fixed."},{"id":"orchestration-to-workflows","from":"orchestration","to":"workflows","style":"dashed","color":"#e85d26","description":"Dispatches to workflows for event-triggered execution."},{"id":"agentic-loop","from":"agents-node","to":"inference","style":"dashed","color":"#e85d26","label":"AGENTIC LOOP","description":"Iterative execution: after each tool result, agent returns to model. May loop many times per request.","invocation_pattern":"autonomous"},{"id":"agents-autonomous-to-mcp","from":"agents-node","to":"mcp","color":"#e85d26","label":"AUTONOMOUS","description":"Agents autonomously invoke tools \u2014 intelligent, non-deterministic selection.","invocation_pattern":"autonomous"},{"id":"pipelines-deterministic-to-mcp","from":"pipelines","to":"mcp","color":"#e85d26","style":"solid","label":"DETERMINISTIC","description":"Tools wired at design time. Developer decides sequence.","invocation_pattern":"deterministic"},{"id":"workflows-deterministic-to-mcp","from":"workflows","to":"mcp","color":"#e85d26","style":"solid","label":"DETERMINISTIC","description":"Tools pre-configured per workflow node, event-triggered.","invocation_pattern":"deterministic"},{"id":"mcp-to-hitl","from":"mcp","to":"hitl","color":"#f5a623","label":"TAKING ACTIONS","style":"solid","no_arrow":true,"description":"Actions pass through human approval before execution."},{"id":"hitl-to-actions","from":"hitl","to":"actions","color":"#b91c1c","description":"Approved actions proceed to external systems."},{"id":"actions-data-retrieval","from":"actions","to":"mcp-protocol","style":"dashed","color":"#2563eb","label":"DATA RETRIEVAL","description":"Data retrieved from external systems flows back through MCP. Actions are bidirectional.","invocation_pattern":"bidirectional"},{"id":"agents-to-storage","from":"agents","to":"storage","style":"dashed","color":"#14b8a6","description":"Agents persist conversations, outputs, and prompt data."},{"id":"storage-to-context","from":"storage","to":"context-store","style":"dashed","color":"#2563eb","label":"CONTEXT-MINING","description":"Mined memory pattern \u2014 outputs post-processed into retrievable context.","invocation_pattern":"transport"},{"id":"context-to-agents","from":"context-store","to":"agents","style":"dashed","color":"#2563eb","description":"Context feeds back into agents \u2014 the virtuous knowledge cycle."},{"id":"agents-adhoc-memory","from":"agents-node","to":"memory","style":"dashed","color":"#2563eb","label":"AD-HOC MEMORY","description":"Agent directly writes/reads memory artifacts. Agent decides what to remember.","invocation_pattern":"bidirectional"},{"id":"grounding-to-agents","from":"grounding-card","to":"agents","color":"#0891b2","style":"dashed","label":"GROUNDING","description":"Real-time external data \u2014 web search, news feeds, live APIs \u2014 grounds agent responses in current information."},{"id":"output-flow","from":"agents-node","to":"frontends-card","label":"OUTPUT","style":"dashed","color":"#e85d26","description":"Agent responses delivered back to user through frontend."},{"id":"safety-to-agents","from":"safety-card","to":"agents","color":"#b91c1c","description":"Safety guardrails constrain agent behavior."},{"id":"safety-to-prompts","from":"safety-card","to":"prompts","color":"#b91c1c","style":"dashed","description":"Input guardrails \u2014 injection detection, content filtering."},{"id":"safety-to-mcp","from":"safety-card","to":"mcp-protocol","color":"#b91c1c","style":"dashed","description":"Tool-level safety \u2014 restricting tool access, parameter validation."},{"id":"observability-to-agents","from":"observability-card","to":"agents","color":"#065f46","description":"Monitoring and logging of agent execution."},{"id":"observability-to-storage","from":"observability-card","to":"data-lakes","style":"dashed","color":"#065f46","description":"Traces, logs, metrics persisted for analysis."},{"id":"observability-to-prompts","from":"observability-card","to":"stored-prompts","style":"dashed","color":"#065f46","label":"PROMPT OPTIMIZATION","description":"Eval results drive prompt iteration and versioning."},{"id":"frontends-to-observability","from":"frontends-card","to":"observability-card","style":"dashed","color":"#4a6fa5","description":"User feedback and telemetry flow to observability."},{"id":"context-rag-to-system-prompt","from":"context-rag","to":"system-prompt","style":"dashed","color":"#2563eb","label":"CONTEXT INJECTION","description":"RAG results injected into system prompt."},{"id":"embedding-models-to-vector-store","from":"embedding-models","to":"vector-store","style":"dashed","color":"#8b5cf6","description":"Embedding models generate vectors for semantic search."},{"id":"stored-prompts-to-prompt-library","from":"stored-prompts","to":"prompt-library","style":"dashed","color":"#4a6fa5","description":"Curated prompts become a versioned library."},{"id":"outputs-to-wiki","from":"outputs","to":"wiki-km","style":"dashed","color":"#7c3aed","description":"Agent outputs published to knowledge management."},{"id":"outputs-to-data-warehouse","from":"outputs","to":"data-warehouse","style":"dashed","color":"#7c3aed","description":"Outputs flow to data warehouse for analytics and compliance."},{"id":"postgres-to-context-store","from":"postgres","to":"context-rag","style":"dashed","color":"#14b8a6","description":"DB records indexed into RAG pipeline."},{"id":"user-prompt-to-conversations","from":"user-prompt","to":"conversations","style":"dashed","color":"#4a6fa5","description":"Prompts persisted as conversations for context mining."},{"id":"conversations-to-postgres","from":"conversations","to":"postgres","style":"dashed","color":"#14b8a6","label":"USER CONTEXT MINING","description":"Conversations mined for user context \u2014 preferences, patterns, domain knowledge."}]};
157
 
158
  // ═══════════════════════════════════════
159
  // HELPERS
 
263
  // ═══════════════════════════════════════
264
  (function initDiagram() {
265
  const container = document.getElementById('diagram-container');
266
+ const W = 1000, H = 840;
267
  const centerW = 420;
268
  const centerX = (W - centerW) / 2;
269
  const centerCX = W / 2;
 
391
  const arrowsG = g.append('g');
392
  const nodesG = g.append('g');
393
 
394
+ // Y positions β€” restructured: Prompts -> Models -> Inference -> Context Store -> Agents -> MCP -> HITL -> Actions
395
+ // Storage and Grounding are now side elements (not in center column)
396
  const pY=20, pH=55;
397
  const mY=95, mH=60;
398
+ const iY=175, iH=85;
399
+ const csY=285, csH=65;
400
+ const aY=380, aH=85;
401
+ const mcpY=497, mcpH=55;
402
+ const hitlY=584, hitlH=28;
403
+ const actY=642, actH=75;
 
404
 
405
  // ── PROMPTS ──
406
  layerBox(nodesG, centerX, pY, centerW, pH, '#4a6fa5', 'Prompts');
 
417
  chip(nodesG, centerCX+160, mY+20, 'Embedding', '#a78bfa', 'Vector representations for RAG \u2014 distinct from generative LLMs.');
418
  drawConn(arrowsG, centerCX, mY+mH, centerCX, iY, '#8b5cf6');
419
 
420
+ // ── INFERENCE (gateway optional) ──
421
+ layerBox(nodesG, centerX, iY, centerW, iH, '#6366f1', 'Inference', false, 'Gateway Optional');
422
+ chip(nodesG, centerCX, iY+18, 'Gateway', '#6366f1', 'Optional model router \u2014 OpenRouter or LiteLLM. Routes to cloud or local endpoints.');
423
+ chip(nodesG, centerCX-110, iY+55, 'Cloud APIs', '#6366f1', 'Anthropic, OpenAI, Google, Bedrock.');
424
+ chip(nodesG, centerCX-15, iY+55, 'Self-Hosted', '#6366f1', 'vLLM, TGI, Ollama.');
425
+ chip(nodesG, centerCX+75, iY+55, 'On-Prem', '#818cf8', 'Air-gapped deployments.');
426
+ chip(nodesG, centerCX+140, iY+55, 'Edge', '#818cf8', 'On-device, offline.');
 
 
 
427
  // Cache
428
+ chip(nodesG, centerCX-170, iY+55, 'Cache', '#818cf8', 'Prompt/response caching \u2014 cost and latency reduction.');
429
+
430
+ // VIA GATEWAY routing arrows (from Gateway chip down to Cloud APIs and Self-Hosted)
431
+ arrowsG.append('path').attr('d',`M${centerCX-15},${iY+34} L${centerCX-110},${iY+55}`).attr('stroke','#6366f1').attr('stroke-width',1.5).attr('opacity',0.5).attr('stroke-dasharray','3 2');
432
+ arrowsG.append('path').attr('d',`M${centerCX+5},${iY+34} L${centerCX-15},${iY+55}`).attr('stroke','#6366f1').attr('stroke-width',1.5).attr('opacity',0.5).attr('stroke-dasharray','3 2');
433
+ arrowsG.append('text').attr('x',centerCX-55).attr('y',iY+42).attr('text-anchor','middle').attr('fill','#6366f1').attr('font-family','system-ui').attr('font-size','7.5').attr('font-weight','700').text('VIA GATEWAY');
434
+
435
+ // DIRECT arrows (from top of inference box directly down to Cloud APIs and Self-Hosted, bypassing Gateway)
436
+ arrowsG.append('path').attr('d',`M${centerCX-110},${iY+4} L${centerCX-110},${iY+55}`).attr('stroke','#6366f1').attr('stroke-width',1.5).attr('opacity',0.4).attr('stroke-dasharray','5 3');
437
+ arrowsG.append('path').attr('d',`M${centerCX-15},${iY+4} L${centerCX-15},${iY+55}`).attr('stroke','#6366f1').attr('stroke-width',1.5).attr('opacity',0.4).attr('stroke-dasharray','5 3');
438
+ arrowsG.append('text').attr('x',centerCX-65).attr('y',iY+11).attr('text-anchor','middle').attr('fill','#6366f1').attr('font-family','system-ui').attr('font-size','7.5').attr('font-weight','700').attr('opacity',0.6).text('DIRECT');
439
 
440
  drawConn(arrowsG, centerCX, iY+iH, centerCX, csY, '#6366f1');
441
 
 
497
  arrowsG.append('text').attr('x',centerCX+80).attr('y',(mcpY+mcpH+hitlY)/2+2).attr('text-anchor','start').attr('fill','#f5a623').attr('font-family','system-ui').attr('font-size','9').attr('font-weight','700').text('TAKING ACTIONS');
498
  drawConn(arrowsG, centerCX, hitlY+hitlH, centerCX, actY, '#b91c1c');
499
 
500
+ // ── ACTIONS (no more Search APIs β€” moved to Grounding) ──
501
  layerBox(nodesG, centerX, actY, centerW, actH, '#2563eb', 'Actions', true);
502
+ chip(nodesG, centerCX-85, actY+28, 'Your Data', '#2563eb', 'Salesforce, HubSpot, Google Drive, Notion.');
503
+ chip(nodesG, centerCX+15, actY+28, 'External Services', '#2563eb', 'Weather, time, public datasets.');
504
+ chip(nodesG, centerCX+120, actY+28, 'Digital Wallets', '#1d4ed8', 'Stripe, crypto, bank APIs.');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
505
 
506
  // ── LEFT: FRONTENDS ──
507
  const fe = card(nodesG, leftCX, mY+20, 130, 65, '#4a6fa5', '\u{1F4BB}', 'Frontends', 'Chat windows, bots, web UIs, dashboards.');
 
522
  arrowsG.append('polygon').attr('points',`${leftCX+65},${fe.y+fe.h*0.7} ${leftCX+72},${fe.y+fe.h*0.7-4} ${leftCX+72},${fe.y+fe.h*0.7+4}`).attr('fill','#e85d26').attr('opacity',0.6);
523
  arrowsG.append('text').attr('x',(centerX+leftCX+65)/2).attr('y',aY+aH*0.65+14).attr('text-anchor','middle').attr('fill','#e85d26').attr('font-family','system-ui').attr('font-size','9').attr('font-weight','700').text('OUTPUT');
524
 
525
+ // ── LEFT: GROUNDING (near agents) ──
526
+ const grC = card(nodesG, leftCX, aY+10, 130, 65, '#0891b2', '\u{1F310}', 'Grounding', 'Real-time external data that grounds agent responses.');
527
+ subChips(nodesG, leftCX, grC.y+grC.h+8, ['Web Search'], '#0891b2');
528
+ subChips(nodesG, leftCX, grC.y+grC.h+34, ['News Feeds'], '#0891b2');
529
+ subChips(nodesG, leftCX, grC.y+grC.h+60, ['Real-Time Data'], '#0891b2');
530
+ // Grounding -> Agents arrow
531
+ drawConn(arrowsG, leftCX+65, grC.cy, centerX, aY+40, '#0891b2', {dashed:true, label:'GROUNDING'});
532
+
533
+ // ── LEFT LOWER: STORAGE (side card) ──
534
+ const stCX = leftCX;
535
+ const stCardY = actY+10;
536
+ const storC = card(nodesG, stCX, stCardY, 130, 65, '#14b8a6', '\u{1F4BE}', 'Storage', 'Persistence \u2014 conversations, outputs, prompts, databases.');
537
+ subChips(nodesG, stCX, storC.y+storC.h+8, ['Conversations'], '#14b8a6');
538
+ subChips(nodesG, stCX, storC.y+storC.h+34, ['Outputs','Prompts'], '#14b8a6');
539
+ subChips(nodesG, stCX, storC.y+storC.h+60, ['Postgres'], '#14b8a6');
540
+ subChips(nodesG, stCX, storC.y+storC.h+86, ['Data Lakes'], '#14b8a6');
541
+
542
+ // Agents -> Storage arrow (from agents layer to side storage card)
543
+ drawConn(arrowsG, centerX, aY+aH-10, stCX+65, storC.cy, '#14b8a6', {dashed:true, opacity:0.5});
544
+
545
+ // Storage -> Context Store feedback (curving up from storage to context store)
546
+ arrowsG.append('path')
547
+ .attr('d', `M${stCX},${storC.y+10} C${stCX-40},${storC.y+10} ${stCX-40},${csY+csH/2} ${centerX},${csY+csH/2}`)
548
+ .attr('fill','none').attr('stroke','#2563eb').attr('stroke-width',1.5).attr('stroke-dasharray','4 3').attr('opacity',0.4);
549
+ arrowsG.append('polygon')
550
+ .attr('points',`${centerX},${csY+csH/2} ${centerX-7},${csY+csH/2+4} ${centerX-7},${csY+csH/2-4}`)
551
+ .attr('fill','#2563eb').attr('opacity',0.4);
552
+ arrowsG.append('text').attr('x',stCX-45).attr('y',(storC.y+csY+csH)/2).attr('text-anchor','middle').attr('fill','#2563eb').attr('font-family','system-ui').attr('font-size','8').attr('font-weight','700').attr('transform',`rotate(-90,${stCX-45},${(storC.y+csY+csH)/2})`).text('CONTEXT-MINING');
553
+
554
  // ── RIGHT: SAFETY + OBSERVABILITY ──
555
  const safetyC = card(nodesG, rightCX, mY+20, 130, 65, '#b91c1c', '\u{1F6E1}\uFE0F', 'Safety', 'Guardrails at prompts, agents, and tool level.');
556
  subChips(nodesG, rightCX, safetyC.y+safetyC.h+8, ['Guardrails'], '#b91c1c');
 
567
  drawConn(arrowsG, rightCX-65, obsC.cy, centerX+centerW, aY+55, '#065f46');
568
 
569
  // ── RIGHT LOWER: DESTINATIONS ──
570
+ const destY = actY+10;
571
+ chip(nodesG, rightCX, destY+4, 'Prompt Library', '#4a6fa5', 'Versioned, reusable prompt templates.');
572
+ chip(nodesG, rightCX, destY+38, 'Wiki / KM', '#14b8a6', 'Organizational knowledge from agent outputs.');
573
+ chip(nodesG, rightCX, destY+72, 'Data Warehouse', '#6366f1', 'Analytics, compliance, long-term retention.');
574
+
575
+ // Storage -> Destinations arrows (from storage card to destinations on the right)
576
+ drawConn(arrowsG, stCX+65, storC.y+storC.h-10, rightCX-60, destY+4+14, '#4a6fa5', {dashed:true, opacity:0.4});
577
+ drawConn(arrowsG, stCX+65, storC.y+storC.h-5, rightCX-50, destY+38+14, '#14b8a6', {dashed:true, opacity:0.4});
578
+ drawConn(arrowsG, stCX+65, storC.y+storC.h, rightCX-60, destY+72+14, '#6366f1', {dashed:true, opacity:0.4});
579
 
580
  // Embedding -> Vector Store
581
  drawConn(arrowsG, centerCX+160, mY+20+28, centerCX+140, csY+25, '#8b5cf6', {dashed:true, opacity:0.35});