docs(architecture): 添加 OpenClaw 系统架构全景图解

- 新增 15 个 Mermaid 架构图解文件,涵盖系统核心组件
- 添加系统架构全景图,展示外部消息平台到 LLM 提供商的完整流程
- 新增网关层、通道管理、路由层、ACP 协议层、Agent 运行时等模块架构图
- 添加记忆系统、心跳系统、插件系统、安全架构等专项设计图
- 新增消息流转序列图和启动流程图
- 添加容器化部署架构和数据存储结构图
- 配置 Mermaid 图表样式,统一科技感视觉主题
- 添加完整的系统设计模式思维导图
- 新增 456 行深度架构分析文章,覆盖六大核心子系统
This commit is contained in:
2026-03-12 09:31:11 +08:00
parent 023fbb0fb5
commit 5f639d8400
37 changed files with 1128 additions and 0 deletions
+95
View File
@@ -0,0 +1,95 @@
graph TB
subgraph "外部消息平台"
TG[Telegram]
SL[Slack]
DC[Discord]
WA[WhatsApp]
SG[Signal]
FS[飞书]
MORE[30+ 其他平台...]
end
subgraph "OpenClaw 核心运行时"
subgraph "Gateway 网关层"
WS[WebSocket Server<br/>端口 18789]
AUTH[认证中间件<br/>Ed25519 设备身份]
PROTO[协议处理器<br/>AJV Schema 校验]
RL[速率限制]
end
subgraph "通道管理"
CM[Channel Manager]
CP1[Telegram Plugin]
CP2[Slack Plugin]
CP3[Discord Plugin]
CPN[... N 个通道插件]
end
subgraph "路由层"
RT[Route Resolver<br/>消息 → Agent 映射]
SK[Session Key Parser<br/>会话键解析]
end
subgraph "ACP 协议层"
ACP_SVR[ACP Server]
ACP_TR[ACP Translator<br/>协议翻译器]
ACP_SM[ACP Session Manager<br/>会话管理器 + Actor 队列]
end
subgraph "Agent 运行时"
PI[Pi Agent Runner<br/>LLM 推理引擎]
TC[Tool Catalog<br/>工具注册表]
SKL[Skills System<br/>技能加载器]
SA[Subagent Registry<br/>子 Agent 注册]
AP[Auth Profiles<br/>模型凭证管理]
end
subgraph "记忆系统"
MM[Memory Index Manager]
VEC[向量检索<br/>sqlite-vec]
FTS[全文搜索<br/>SQLite FTS5]
EMB[Embedding Providers<br/>OpenAI/Gemini/Voyage/Ollama]
end
subgraph "心跳系统"
HB[Heartbeat Runner<br/>定时唤醒]
HMD[HEARTBEAT.md<br/>任务配置文件]
end
subgraph "存储层"
SS[Session Store<br/>JSON/JSONL 文件]
CF[Config Store<br/>config.json]
DI[Device Identity<br/>密钥对存储]
end
end
subgraph "LLM 提供商"
CLAUDE[Claude / Anthropic]
GPT[GPT / OpenAI]
GEM[Gemini / Google]
QWEN[Qwen / 通义]
OL[Ollama 本地模型]
MORE_LLM[Grok/Groq/Azure/...]
end
TG & SL & DC & WA & SG & FS & MORE --> CM
CM --> CP1 & CP2 & CP3 & CPN
CP1 & CP2 & CP3 & CPN --> RT
RT --> SK --> ACP_SM
WS --> AUTH --> PROTO --> ACP_SVR
ACP_SVR --> ACP_TR --> ACP_SM
ACP_SM --> PI
PI --> TC & SKL & SA
PI --> MM
MM --> VEC & FTS
VEC & FTS --> EMB
PI --> AP --> CLAUDE & GPT & GEM & QWEN & OL & MORE_LLM
PI --> SS
HB --> HMD --> PI
ACP_SM --> SS
style WS fill:#4A90D9,color:#fff
style PI fill:#E74C3C,color:#fff
style MM fill:#27AE60,color:#fff
style HB fill:#F39C12,color:#fff
style CM fill:#8E44AD,color:#fff
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 538 KiB

+21
View File
@@ -0,0 +1,21 @@
sequenceDiagram
participant Client as 客户端/CLI
participant GW as Gateway Server
participant Auth as 认证中间件
participant Proto as 协议处理器
participant CM as Channel Manager
participant RT as Route Resolver
Client->>GW: WebSocket 连接 (ws://localhost:18789)
GW->>Auth: 设备认证 (Ed25519 签名)
Auth-->>GW: 认证通过 + 设备 Token
GW->>Proto: Hello 握手 (PROTOCOL_VERSION)
Proto-->>Client: HelloOk (capabilities, scopes)
Note over Client,RT: 消息流
Client->>GW: RequestFrame: chat.send
GW->>Proto: AJV Schema 校验
Proto->>RT: 路由解析 (channel + peer → agent)
RT-->>GW: sessionKey + agentId
GW->>CM: 分发到对应通道
Binary file not shown.

After

Width:  |  Height:  |  Size: 538 KiB

+11
View File
@@ -0,0 +1,11 @@
graph LR
A[加载配置] --> B[校验认证配置]
B --> C[初始化 Secrets]
C --> D[加载插件]
D --> E[创建 Channel Manager]
E --> F[初始化 Memory Manager]
F --> G[启动 Heartbeat Runner]
G --> H[启动 WebSocket Server]
H --> I[挂载协议处理器]
I --> J[启动 Sidecars<br/>发现/健康监控/Cron]
J --> K[✅ Ready]
Binary file not shown.

After

Width:  |  Height:  |  Size: 221 KiB

+19
View File
@@ -0,0 +1,19 @@
graph TB
subgraph "ACP 协议栈"
EXT[外部 ACP 客户端<br/>stdin/stdout]
CONN[AgentSideConnection<br/>ndJSON 流]
AGENT[AcpGatewayAgent<br/>协议翻译器]
CLIENT[GatewayClient<br/>WebSocket]
MGR[AcpSessionManager<br/>会话管理单例]
end
subgraph "运行时缓存"
CACHE[RuntimeCache<br/>sessionKey → Handle]
QUEUE[ActorQueue<br/>每会话串行化]
EVICT[空闲驱逐<br/>TTL 超时清理]
end
EXT --> CONN --> AGENT --> CLIENT
AGENT --> MGR
MGR --> CACHE & QUEUE
CACHE --> EVICT
Binary file not shown.

After

Width:  |  Height:  |  Size: 393 KiB

+48
View File
@@ -0,0 +1,48 @@
graph TB
subgraph "Agent 运行时"
PI[Pi Agent Runner<br/>核心推理引擎]
subgraph "模型集成"
MC[Model Catalog<br/>模型目录]
AP[Auth Profiles<br/>凭证管理]
FB[Fallback Chains<br/>模型降级链]
TH[Thinking Mode<br/>思考/推理模式]
end
subgraph "工具系统"
TC[Tool Catalog]
T1[web_search 网络搜索]
T2[browser_tool 浏览器]
T3[system.run 终端执行]
T4[system.spawn_acp 子Agent]
T5[channel actions 通道操作]
end
subgraph "技能系统"
SL[Skill Loader<br/>jiti 动态导入]
SF[skill.json 元数据]
SH[skill.ts 运行时处理器]
end
subgraph "子 Agent"
SR[Subagent Registry]
SP[Spawn ACP<br/>隔离会话派生]
end
end
PI --> MC --> AP --> FB
PI --> TC --> T1 & T2 & T3 & T4 & T5
PI --> SL --> SF & SH
PI --> SR --> SP
MC --> TH
subgraph "LLM 提供商"
L1[Anthropic Claude]
L2[OpenAI GPT]
L3[Google Gemini]
L4[Qwen 通义千问]
L5[Ollama 本地]
L6[Groq / Grok / Azure / Minimax / 火山引擎]
end
FB --> L1 & L2 & L3 & L4 & L5 & L6
Binary file not shown.

After

Width:  |  Height:  |  Size: 766 KiB

+16
View File
@@ -0,0 +1,16 @@
sequenceDiagram
participant Agent as Agent Runtime
participant EA as ExecApprovalManager
participant Admin as 管理员
participant CMD as 命令执行
Agent->>EA: system.run("rm -rf /tmp/data")
EA->>EA: 检查是否为危险操作
EA->>Admin: 显示审批请求
Admin-->>EA: ✅ 批准 / ❌ 拒绝
alt 批准
EA->>CMD: 执行命令
CMD-->>Agent: 返回结果
else 拒绝
EA-->>Agent: 操作被拒绝
end
Binary file not shown.

After

Width:  |  Height:  |  Size: 336 KiB

+19
View File
@@ -0,0 +1,19 @@
graph TB
subgraph "插件生命周期"
D[1. Discovery 发现<br/>扫描 extensions/ 目录]
M[2. Manifest 加载<br/>读取 openclaw.plugin.json]
R[3. Runtime 创建<br/>初始化 Hook Runner]
REG[4. Registration 注册<br/>setActivePluginRegistry]
end
D --> M --> R --> REG
subgraph "插件类型"
CH[通道插件 ×34<br/>Telegram/Slack/Discord/...]
MEM[记忆插件<br/>memory-core / memory-lancedb]
AUTH_P[认证插件<br/>google-gemini-cli-auth 等]
DIAG[诊断插件<br/>diagnostics-otel]
SPEC[特殊插件<br/>thread-ownership / llm-task]
end
REG --> CH & MEM & AUTH_P & DIAG & SPEC
Binary file not shown.

After

Width:  |  Height:  |  Size: 510 KiB

+39
View File
@@ -0,0 +1,39 @@
graph TB
subgraph "记忆系统架构"
Q[搜索查询]
subgraph "混合搜索引擎"
VS[向量检索<br/>sqlite-vec]
BM[BM25 全文搜索<br/>SQLite FTS5]
HY[混合排序<br/>加权合并 + 时间衰减]
end
subgraph "Embedding 提供商"
E1[OpenAI<br/>text-embedding-3-small/large]
E2[Gemini<br/>Generalist Multimodal]
E3[Voyage<br/>voyage-large-2-instruct]
E4[Mistral<br/>mistral-embed]
E5[Ollama<br/>本地模型]
end
subgraph "存储层"
DB[(SQLite 数据库)]
CV[chunks_vec 表<br/>向量嵌入]
CF[chunks_fts 表<br/>FTS5 全文索引]
EC[embedding_cache 表<br/>查询缓存 + TTL]
end
RES[搜索结果<br/>相关度排序]
end
Q --> VS & BM
VS --> HY
BM --> HY
VS --> E1 & E2 & E3 & E4 & E5
E1 & E2 & E3 & E4 & E5 --> CV
BM --> CF
HY --> RES
DB --> CV & CF & EC
style HY fill:#27AE60,color:#fff
style DB fill:#3498DB,color:#fff
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

+25
View File
@@ -0,0 +1,25 @@
sequenceDiagram
participant Timer as 定时器 (默认 30 分钟)
participant HB as Heartbeat Runner
participant FS as 文件系统
participant Agent as Agent Runtime
participant LLM as LLM 提供商
participant Channel as 消息通道
loop 每 30 分钟
Timer->>HB: 触发心跳
HB->>FS: 读取 HEARTBEAT.md
alt HEARTBEAT.md 为空或不存在
HB->>HB: 跳过,不调用 API
else HEARTBEAT.md 有任务内容
HB->>Agent: 发送 HEARTBEAT_PROMPT
Agent->>LLM: 推理 + 任务执行
LLM-->>Agent: 执行结果
alt 返回 HEARTBEAT_OK
Agent-->>HB: 无需操作,静默
else 有实际输出
Agent->>Channel: 发送结果到通道
Channel-->>HB: 显示 ACK 反应 (👀)
end
end
end
Binary file not shown.

After

Width:  |  Height:  |  Size: 595 KiB

+45
View File
@@ -0,0 +1,45 @@
graph TB
subgraph "① 消息接收"
MSG[用户消息<br/>Telegram/Slack/...]
SDK[平台 SDK<br/>原生协议接收]
NORM[消息标准化<br/>统一格式]
end
subgraph "② 路由决策"
RT[Route Resolver<br/>channel + peer → agentId]
BIND[Session Binding<br/>会话绑定服务]
SK[Session Key<br/>生成会话键]
end
subgraph "③ 会话管理"
ACP[ACP Session Manager]
LOCK[Session Write Lock<br/>防并发写入]
LOAD[加载会话历史<br/>JSONL 转录]
end
subgraph "④ Agent 推理"
PI[Pi Agent Runner]
LLM[LLM API 调用<br/>含 Thinking Mode]
TOOL[工具调用<br/>审批 → 执行]
MEM[记忆检索<br/>混合搜索]
end
subgraph "⑤ 响应投递"
STREAM[流式响应<br/>逐 Token 返回]
TRANS[格式转换<br/>适配目标平台]
DELIVER[投递到通道<br/>支持线程/回复]
PERSIST[持久化<br/>会话 + 记忆写入]
end
MSG --> SDK --> NORM
NORM --> RT --> BIND --> SK
SK --> ACP --> LOCK --> LOAD
LOAD --> PI --> LLM
LLM --> TOOL
TOOL --> MEM
LLM --> STREAM --> TRANS --> DELIVER
DELIVER --> PERSIST
style MSG fill:#9B59B6,color:#fff
style PI fill:#E74C3C,color:#fff
style DELIVER fill:#2ECC71,color:#fff
Binary file not shown.

After

Width:  |  Height:  |  Size: 800 KiB

+27
View File
@@ -0,0 +1,27 @@
graph LR
subgraph "~/.openclaw/ 存储结构"
subgraph "设备层"
DI[device-identity.json<br/>Ed25519 密钥对]
CRED[credentials/<br/>设备 Token]
end
subgraph "配置层"
CONFIG[config.json<br/>全局配置]
SECRETS[secrets/<br/>API Key 引用]
end
subgraph "Agent 层 (per-agent)"
subgraph "agents/main/"
SESS[sessions.json<br/>会话元数据]
TRANS[sessions/*.jsonl<br/>会话转录]
WS[workspace/<br/>工作区文件]
HMD2[HEARTBEAT.md]
MEMDB[memory.sqlite<br/>向量+全文索引]
end
end
end
style DI fill:#E67E22,color:#fff
style CONFIG fill:#3498DB,color:#fff
style SESS fill:#2ECC71,color:#fff
style MEMDB fill:#9B59B6,color:#fff
Binary file not shown.

After

Width:  |  Height:  |  Size: 505 KiB

+33
View File
@@ -0,0 +1,33 @@
graph TB
subgraph "安全层级"
subgraph "L1: 网络层"
TLS[TLS/mTLS 加密]
FP[证书指纹验证]
CWE[CWE-319 防护<br/>禁止明文WS到非回环]
end
subgraph "L2: 认证层"
DEV[设备认证<br/>Ed25519 签名]
TOKEN[设备 Token<br/>长期访问令牌]
OAUTH[OAuth 集成<br/>Google/Discord 等]
PWD[密码认证<br/>本地网关备选]
end
subgraph "L3: 授权层"
SCOPE[操作域 Scopes]
PAIR[设备配对审批]
ROLE[Owner vs User 角色]
end
subgraph "L4: 执行层"
APPROVE[工具审批门<br/>危险操作拦截]
SANDBOX[沙箱策略<br/>inherit/require/forbidden]
AUDIT[审计日志]
SCAN[危险工具扫描]
end
end
TLS --> DEV --> SCOPE --> APPROVE
FP --> TOKEN --> PAIR --> SANDBOX
CWE --> OAUTH --> ROLE --> AUDIT
PWD --> SCAN
Binary file not shown.

After

Width:  |  Height:  |  Size: 620 KiB

+24
View File
@@ -0,0 +1,24 @@
graph TB
subgraph "通道插件架构"
IF[ChannelPlugin 接口]
subgraph "插件实现"
TG[Telegram<br/>Bot API]
SL[Slack<br/>Bolt SDK]
DC[Discord<br/>discord.js]
WA[WhatsApp<br/>Baileys]
SIG[Signal<br/>signal-cli]
FS[飞书<br/>Open API]
end
subgraph "生命周期"
INIT[initialize<br/>认证 + 连接]
LISTEN[listen<br/>消息监听]
ROUTE[route<br/>路由到 Agent]
DELIVER[deliver<br/>回传响应]
SHUTDOWN[shutdown<br/>优雅断开]
end
end
IF --> TG & SL & DC & WA & SIG & FS
TG & SL & DC & WA & SIG & FS --> INIT --> LISTEN --> ROUTE --> DELIVER --> SHUTDOWN
Binary file not shown.

After

Width:  |  Height:  |  Size: 683 KiB

+24
View File
@@ -0,0 +1,24 @@
graph TB
subgraph "Docker Compose"
GW_SVC[gateway 服务<br/>Node.js 运行时]
CLI_SVC[cli 服务<br/>命令行交互]
HC[健康检查<br/>端口 18789]
end
subgraph "Docker 镜像"
BASE[Dockerfile<br/>多阶段构建]
SB[Dockerfile.sandbox<br/>沙箱镜像]
SBB[Dockerfile.sandbox-browser<br/>浏览器沙箱]
SBC[Dockerfile.sandbox-common<br/>公共沙箱基础]
end
subgraph "其他部署"
FLY[fly.toml<br/>Fly.io 部署]
RENDER[render.yaml<br/>Render 部署]
PODMAN[Podman<br/>无 root 容器]
end
GW_SVC --> BASE
CLI_SVC --> BASE
GW_SVC --> HC
BASE --> SB & SBB & SBC
Binary file not shown.

After

Width:  |  Height:  |  Size: 541 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

+23
View File
@@ -0,0 +1,23 @@
mindmap
root((OpenClaw<br/>设计模式))
消息驱动
WebSocket 双向通信
EventFrame 事件流
RequestFrame 请求/响应
插件化
34 个通道插件
Hook 系统 7 个钩子
动态加载 jiti
会话隔离
Actor 队列串行化
Session Write Lock
Per-agent 存储隔离
安全纵深
L1 网络加密
L2 设备认证
L3 域控授权
L4 执行审批
韧性设计
模型降级链
连接重试退避
嵌入失败恢复
Binary file not shown.

After

Width:  |  Height:  |  Size: 568 KiB

+37
View File
@@ -0,0 +1,37 @@
{
"theme": "base",
"themeVariables": {
"primaryColor": "#0d2137",
"primaryTextColor": "#e0f7fa",
"primaryBorderColor": "#00e5ff",
"lineColor": "#00b8d4",
"secondaryColor": "#0a1628",
"secondaryTextColor": "#b2ebf2",
"secondaryBorderColor": "#00bcd4",
"tertiaryColor": "#112240",
"tertiaryTextColor": "#e0f7fa",
"tertiaryBorderColor": "#26c6da",
"noteBkgColor": "#0d2137",
"noteTextColor": "#e0f7fa",
"noteBorderColor": "#00e5ff",
"edgeLabelBackground": "#0a1628",
"clusterBkg": "#0a1a2e",
"clusterBorder": "#1a5276",
"titleColor": "#00e5ff",
"actorBkg": "#0d2137",
"actorBorder": "#00e5ff",
"actorTextColor": "#e0f7fa",
"actorLineColor": "#00b8d4",
"signalColor": "#00e5ff",
"signalTextColor": "#e0f7fa",
"labelBoxBkgColor": "#0d2137",
"labelBoxBorderColor": "#00e5ff",
"labelTextColor": "#e0f7fa",
"loopTextColor": "#80deea",
"activationBorderColor": "#00e5ff",
"activationBkgColor": "#112240",
"sequenceNumberColor": "#00e5ff",
"fontFamily": "SF Pro Display, -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica Neue, Arial, sans-serif",
"fontSize": "15px"
}
}
+7
View File
@@ -0,0 +1,7 @@
.mindmap-node text, .mindmap-node tspan,
.node text, .node tspan,
.label text, .label tspan,
text, tspan {
fill: #ffffff !important;
color: #ffffff !important;
}
+44
View File
@@ -0,0 +1,44 @@
/* Mindmap sci-fi style - force visible node backgrounds */
text, tspan {
fill: #e0f7fa !important;
font-family: 'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif !important;
}
/* Root node */
.mindmap-node:first-of-type circle {
fill: #0d2137 !important;
stroke: #00e5ff !important;
stroke-width: 3px !important;
filter: drop-shadow(0 0 12px rgba(0, 229, 255, 0.6)) !important;
}
/* All mindmap section/node shapes */
.mindmap-node rect,
.mindmap-node polygon,
.mindmap-node circle,
.mindmap-node ellipse,
.mindmap-node path {
stroke: #00b8d4 !important;
stroke-width: 2px !important;
filter: drop-shadow(0 0 6px rgba(0, 229, 255, 0.35)) !important;
}
/* Force different section colors instead of black */
.section-0 rect, .section-0 path { fill: #0d3b66 !important; stroke: #00e5ff !important; }
.section-1 rect, .section-1 path { fill: #1a3a4a !important; stroke: #26c6da !important; }
.section-2 rect, .section-2 path { fill: #1b3044 !important; stroke: #4dd0e1 !important; }
.section-3 rect, .section-3 path { fill: #14293d !important; stroke: #00bcd4 !important; }
.section-4 rect, .section-4 path { fill: #0f2b3d !important; stroke: #80deea !important; }
/* Generic fallback: any rect/path that ends up black */
rect[fill="#000"], rect[fill="#000000"], rect[fill="black"],
path[fill="#000"], path[fill="#000000"], path[fill="black"] {
fill: #0d3b66 !important;
}
/* Lines between nodes */
line, path.edge {
stroke: #00b8d4 !important;
stroke-width: 2px !important;
}
+115
View File
@@ -0,0 +1,115 @@
/* Sci-fi / Tech style for mermaid diagrams */
/* Node styling */
.node rect, .node polygon, .node circle, .node ellipse {
stroke-width: 2px !important;
filter: drop-shadow(0 0 6px rgba(0, 229, 255, 0.4)) !important;
rx: 8 !important;
ry: 8 !important;
}
/* All text white/cyan */
text, tspan {
fill: #e0f7fa !important;
font-family: 'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif !important;
}
/* Cluster/subgraph borders */
.cluster rect {
stroke: #1a6a8a !important;
stroke-width: 2px !important;
stroke-dasharray: 6 3 !important;
fill: rgba(10, 26, 46, 0.7) !important;
rx: 12 !important;
ry: 12 !important;
filter: drop-shadow(0 0 8px rgba(0, 184, 212, 0.2)) !important;
}
/* Cluster labels */
.cluster text, .cluster tspan {
fill: #4dd0e1 !important;
font-weight: 600 !important;
font-size: 14px !important;
}
/* Edge/arrow lines */
.edge-pattern-solid, .flowchart-link {
stroke: #00b8d4 !important;
stroke-width: 2px !important;
}
/* Arrow markers */
marker path {
fill: #00e5ff !important;
}
/* Sequence diagram lines */
.messageLine0, .messageLine1 {
stroke: #00b8d4 !important;
stroke-width: 2px !important;
}
/* Sequence diagram actors */
.actor {
stroke: #00e5ff !important;
fill: #0d2137 !important;
stroke-width: 2px !important;
filter: drop-shadow(0 0 6px rgba(0, 229, 255, 0.3)) !important;
}
/* Labels on edges */
.edgeLabel rect {
fill: #0a1628 !important;
opacity: 0.9 !important;
}
.edgeLabel span, .edgeLabel text, .edgeLabel tspan {
fill: #80deea !important;
color: #80deea !important;
font-size: 12px !important;
}
/* Note boxes */
.note {
fill: #112240 !important;
stroke: #00e5ff !important;
}
/* Mindmap specific */
.mindmap-node rect, .mindmap-node circle, .mindmap-node polygon {
filter: drop-shadow(0 0 6px rgba(0, 229, 255, 0.4)) !important;
}
.mindmap-node text, .mindmap-node tspan {
fill: #e0f7fa !important;
}
/* Activation bars in sequence diagrams */
.activation0, .activation1, .activation2 {
fill: #112240 !important;
stroke: #00e5ff !important;
}
/* Loop/alt boxes */
.loopLine {
stroke: #1a6a8a !important;
stroke-dasharray: 4 3 !important;
}
.loopText tspan, .loopText text {
fill: #4dd0e1 !important;
}
/* Label styling */
.label text, .label tspan {
fill: #e0f7fa !important;
}
/* Highlighted nodes with custom styles from mermaid */
[style*="fill:#4A90D9"], [style*="fill:#E74C3C"], [style*="fill:#27AE60"],
[style*="fill:#F39C12"], [style*="fill:#8E44AD"], [style*="fill:#9B59B6"],
[style*="fill:#2ECC71"], [style*="fill:#3498DB"], [style*="fill:#E67E22"] {
filter: drop-shadow(0 0 10px rgba(0, 229, 255, 0.6)) !important;
stroke: #00e5ff !important;
stroke-width: 2px !important;
}