aicodeswitch 5.2.9 → 5.2.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,360 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1400 860" font-family="ui-sans-serif, system-ui, -apple-system, 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif" text-rendering="geometricPrecision">
2
+ <title>AICodeSwitch 转流架构图</title>
3
+ <desc>展示 AI 编程工具(Claude Code / Codex / Cursor 等)的请求,经 AICodeSwitch 本地代理完成鉴权、路由、规则匹配、格式转换后,转流到上游 LLM 服务商(Anthropic / OpenAI / Gemini / DeepSeek 等),响应原路回流。</desc>
4
+
5
+ <defs>
6
+ <linearGradient id="bgGrad" x1="0" y1="0" x2="0" y2="1">
7
+ <stop offset="0" stop-color="#0c1326"/>
8
+ <stop offset=".5" stop-color="#111c3a"/>
9
+ <stop offset="1" stop-color="#090f1f"/>
10
+ </linearGradient>
11
+ <radialGradient id="bgGlow" cx=".5" cy=".06" r=".78">
12
+ <stop offset="0" stop-color="#22d3ee" stop-opacity=".18"/>
13
+ <stop offset=".45" stop-color="#7c3aed" stop-opacity=".10"/>
14
+ <stop offset="1" stop-color="#090f1f" stop-opacity="0"/>
15
+ </radialGradient>
16
+ <linearGradient id="titleGrad" x1="0" y1="0" x2="1" y2="0">
17
+ <stop offset="0" stop-color="#5eead4"/>
18
+ <stop offset=".45" stop-color="#22d3ee"/>
19
+ <stop offset=".75" stop-color="#a855f7"/>
20
+ <stop offset="1" stop-color="#ec4899"/>
21
+ </linearGradient>
22
+ <linearGradient id="coreStroke" x1="0" y1="0" x2="1" y2="1">
23
+ <stop offset="0" stop-color="#22d3ee"/>
24
+ <stop offset=".5" stop-color="#a855f7"/>
25
+ <stop offset="1" stop-color="#ec4899"/>
26
+ </linearGradient>
27
+ <linearGradient id="coreFill" x1="0" y1="0" x2="0" y2="1">
28
+ <stop offset="0" stop-color="#0f1830" stop-opacity=".92"/>
29
+ <stop offset="1" stop-color="#0b1124" stop-opacity=".92"/>
30
+ </linearGradient>
31
+ <linearGradient id="panelFill" x1="0" y1="0" x2="1" y2="0">
32
+ <stop offset="0" stop-color="#16234c" stop-opacity=".78"/>
33
+ <stop offset="1" stop-color="#101935" stop-opacity=".78"/>
34
+ </linearGradient>
35
+ <radialGradient id="dotCyan">
36
+ <stop offset="0" stop-color="#cffafe"/>
37
+ <stop offset=".45" stop-color="#22d3ee"/>
38
+ <stop offset="1" stop-color="#22d3ee" stop-opacity="0"/>
39
+ </radialGradient>
40
+ <radialGradient id="dotPurple">
41
+ <stop offset="0" stop-color="#f3e8ff"/>
42
+ <stop offset=".45" stop-color="#c084fc"/>
43
+ <stop offset="1" stop-color="#a855f7" stop-opacity="0"/>
44
+ </radialGradient>
45
+ <marker id="arrowCyan" viewBox="0 0 10 10" refX="8.5" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
46
+ <path d="M0,1 L9,5 L0,9 z" fill="#22d3ee"/>
47
+ </marker>
48
+ <marker id="arrowPurple" viewBox="0 0 10 10" refX="8.5" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
49
+ <path d="M0,1 L9,5 L0,9 z" fill="#c084fc"/>
50
+ </marker>
51
+ <style>
52
+ @media (prefers-reduced-motion: reduce){
53
+ animate,animateTransform,animateMotion{display:none}
54
+ }
55
+ </style>
56
+ </defs>
57
+
58
+ <!-- ============ background ============ -->
59
+ <rect width="1400" height="860" fill="url(#bgGrad)"/>
60
+ <rect width="1400" height="860" fill="url(#bgGlow)"/>
61
+
62
+ <!-- ============ title ============ -->
63
+ <text x="700" y="60" text-anchor="middle" font-size="32" font-weight="800" fill="url(#titleGrad)" letter-spacing="0.5">AICodeSwitch · 转流架构</text>
64
+ <text x="700" y="89" text-anchor="middle" font-size="14.5" fill="#8c9bc4">本地代理 · 把 AI 编程工具的请求智能路由并转换格式,转流到任意模型 API</text>
65
+
66
+ <!-- column captions -->
67
+ <text x="169" y="196" text-anchor="middle" font-size="12" font-weight="700" fill="#6f7da6" letter-spacing="2">客户端 · AI 编程工具</text>
68
+ <text x="1231" y="158" text-anchor="middle" font-size="12" font-weight="700" fill="#6f7da6" letter-spacing="2">上游 · LLM 服务商</text>
69
+
70
+ <!-- ============ LEFT column · clients ============ -->
71
+ <!-- Claude Code -->
72
+ <g>
73
+ <rect x="64" y="220" width="210" height="118" rx="16" fill="#111a33" stroke="#243156"/>
74
+ <rect x="66" y="238" width="4" height="82" rx="2" fill="#a855f7"/>
75
+ <circle cx="108" cy="264" r="22" fill="#a855f7" fill-opacity=".16" stroke="#a855f7" stroke-width="1.5"/>
76
+ <text x="108" y="271" text-anchor="middle" font-size="18" font-weight="800" fill="#d8b4fe">C</text>
77
+ <text x="142" y="258" font-size="16.5" font-weight="700" fill="#e6edf7">Claude Code</text>
78
+ <text x="142" y="280" font-size="12" fill="#8c9bc4">/v1/messages</text>
79
+ <g transform="translate(82,298)">
80
+ <rect width="118" height="24" rx="12" fill="#a855f7" fill-opacity=".12" stroke="#a855f7" stroke-opacity=".5"/>
81
+ <text x="59" y="16" text-anchor="middle" font-size="11" fill="#d8b4fe">Anthropic 协议</text>
82
+ </g>
83
+ </g>
84
+
85
+ <!-- Codex -->
86
+ <g>
87
+ <rect x="64" y="372" width="210" height="118" rx="16" fill="#111a33" stroke="#243156"/>
88
+ <rect x="66" y="390" width="4" height="82" rx="2" fill="#10b981"/>
89
+ <circle cx="108" cy="416" r="22" fill="#10b981" fill-opacity=".16" stroke="#10b981" stroke-width="1.5"/>
90
+ <text x="108" y="423" text-anchor="middle" font-size="15" font-weight="800" fill="#a7f3d0">Cx</text>
91
+ <text x="142" y="410" font-size="16.5" font-weight="700" fill="#e6edf7">Codex</text>
92
+ <text x="142" y="432" font-size="12" fill="#8c9bc4">/v1/responses</text>
93
+ <g transform="translate(82,450)">
94
+ <rect width="118" height="24" rx="12" fill="#10b981" fill-opacity=".12" stroke="#10b981" stroke-opacity=".5"/>
95
+ <text x="59" y="16" text-anchor="middle" font-size="11" fill="#a7f3d0">OpenAI 协议</text>
96
+ </g>
97
+ </g>
98
+
99
+ <!-- Cursor / others -->
100
+ <g>
101
+ <rect x="64" y="524" width="210" height="118" rx="16" fill="#111a33" stroke="#243156"/>
102
+ <rect x="66" y="542" width="4" height="82" rx="2" fill="#22d3ee"/>
103
+ <circle cx="108" cy="568" r="22" fill="#22d3ee" fill-opacity=".16" stroke="#22d3ee" stroke-width="1.5"/>
104
+ <text x="108" y="576" text-anchor="middle" font-size="20" font-weight="800" fill="#a5f3fc">+</text>
105
+ <text x="142" y="562" font-size="16.5" font-weight="700" fill="#e6edf7">Cursor · 其他</text>
106
+ <text x="142" y="584" font-size="12" fill="#8c9bc4">/v1/chat/completions</text>
107
+ <g transform="translate(82,602)">
108
+ <rect width="132" height="24" rx="12" fill="#22d3ee" fill-opacity=".12" stroke="#22d3ee" stroke-opacity=".5"/>
109
+ <text x="66" y="16" text-anchor="middle" font-size="11" fill="#a5f3fc">OpenAI 兼容</text>
110
+ </g>
111
+ </g>
112
+
113
+ <!-- ============ CENTER · core engine ============ -->
114
+ <g>
115
+ <rect x="360" y="150" width="680" height="550" rx="22" fill="url(#coreFill)" stroke="url(#coreStroke)" stroke-width="1.6">
116
+ <animate attributeName="stroke-opacity" values="0.55;0.95;0.55" dur="4.5s" repeatCount="indefinite"/>
117
+ </rect>
118
+ <!-- top highlight -->
119
+ <path d="M382,150 H1018 a22,22 0 0 1 22,22 V192 H360 V172 a22,22 0 0 1 22,-22 z" fill="#ffffff" fill-opacity=".035"/>
120
+ <!-- header -->
121
+ <rect x="386" y="166" width="16" height="16" rx="4" fill="url(#coreStroke)"/>
122
+ <text x="410" y="180" font-size="17" font-weight="800" fill="#e6edf7">AICodeSwitch Proxy Core</text>
123
+ <text x="1014" y="180" text-anchor="end" font-size="11.5" fill="#6f7da6">localhost · 中转引擎</text>
124
+
125
+ <!-- ── M1 Auth ── -->
126
+ <g>
127
+ <rect x="380" y="210" width="640" height="86" rx="14" fill="url(#panelFill)" stroke="#1f2c52"/>
128
+ <circle cx="416" cy="253" r="18" fill="#22d3ee" fill-opacity=".14" stroke="#22d3ee" stroke-width="1.4"/>
129
+ <g transform="translate(408,243)" stroke="#67e8f9" stroke-width="1.6" fill="none" stroke-linecap="round">
130
+ <rect x="2" y="7" width="12" height="9" rx="2"/>
131
+ <path d="M5,7 V5 a3,3 0 0 1 6,0 V7"/>
132
+ </g>
133
+ <text x="446" y="244" font-size="15.5" font-weight="700" fill="#e6edf7">① 鉴权 Auth</text>
134
+ <text x="446" y="266" font-size="12" fill="#8c9bc4">API Key 解析 · sk_ 池密钥 / skr_ 路由密钥 · JWT</text>
135
+ <g transform="translate(818,242)">
136
+ <rect width="202" height="22" rx="11" fill="#22d3ee" fill-opacity=".10" stroke="#22d3ee" stroke-opacity=".4"/>
137
+ <text x="101" y="15" text-anchor="middle" font-size="10" fill="#67e8f9">Authorization · x-api-key · x-goog-api-key</text>
138
+ </g>
139
+ </g>
140
+
141
+ <!-- ── M2 Route + Rules ── -->
142
+ <g>
143
+ <rect x="380" y="308" width="640" height="148" rx="14" fill="url(#panelFill)" stroke="#1f2c52"/>
144
+ <circle cx="416" cy="338" r="18" fill="#a855f7" fill-opacity=".14" stroke="#a855f7" stroke-width="1.4"/>
145
+ <g transform="translate(407,329)" stroke="#d8b4fe" stroke-width="1.4" fill="none" stroke-linecap="round" stroke-linejoin="round">
146
+ <circle cx="9" cy="9" r="7"/>
147
+ <path d="M9,4 L11,9 L9,14 L7,9 z" fill="#d8b4fe" stroke="none"/>
148
+ </g>
149
+ <text x="446" y="334" font-size="15.5" font-weight="700" fill="#e6edf7">② 路由 &amp; 规则 Route · Rules</text>
150
+ <text x="446" y="356" font-size="12" fill="#8c9bc4">按内容类型分发到候选上游池,失败自动回退(fallback)</text>
151
+
152
+ <!-- content-type pills -->
153
+ <g font-size="11" font-weight="600">
154
+ <g transform="translate(396,378)">
155
+ <rect width="68" height="24" rx="12" fill="#94a3b8" fill-opacity=".10" stroke="#94a3b8" stroke-opacity=".5"/>
156
+ <text x="34" y="16" text-anchor="middle" fill="#cbd5e1">default</text>
157
+ </g>
158
+ <g transform="translate(472,378)">
159
+ <rect width="72" height="24" rx="12" fill="#a855f7" fill-opacity=".12" stroke="#a855f7" stroke-opacity=".55"/>
160
+ <text x="36" y="16" text-anchor="middle" fill="#d8b4fe">thinking</text>
161
+ </g>
162
+ <g transform="translate(554,378)">
163
+ <rect width="100" height="24" rx="12" fill="#3b82f6" fill-opacity=".12" stroke="#3b82f6" stroke-opacity=".55"/>
164
+ <text x="50" y="16" text-anchor="middle" fill="#bfdbfe">long-context</text>
165
+ </g>
166
+ <g transform="translate(396,410)">
167
+ <rect width="140" height="24" rx="12" fill="#ec4899" fill-opacity=".12" stroke="#ec4899" stroke-opacity=".55"/>
168
+ <text x="70" y="16" text-anchor="middle" fill="#f9a8d4">image-understanding</text>
169
+ </g>
170
+ <g transform="translate(544,410)">
171
+ <rect width="86" height="24" rx="12" fill="#06b6d4" fill-opacity=".12" stroke="#06b6d4" stroke-opacity=".55"/>
172
+ <text x="43" y="16" text-anchor="middle" fill="#a5f3fc">background</text>
173
+ </g>
174
+ <g transform="translate(638,410)">
175
+ <rect width="66" height="24" rx="12" fill="#f59e0b" fill-opacity=".12" stroke="#f59e0b" stroke-opacity=".55"/>
176
+ <text x="33" y="16" text-anchor="middle" fill="#fcd34d">high-iq</text>
177
+ </g>
178
+ </g>
179
+ </g>
180
+
181
+ <!-- ── M3 Transformers ── -->
182
+ <g>
183
+ <rect x="380" y="468" width="640" height="104" rx="14" fill="url(#panelFill)" stroke="#1f2c52"/>
184
+ <circle cx="416" cy="500" r="18" fill="#ec4899" fill-opacity=".14" stroke="#ec4899" stroke-width="1.4"/>
185
+ <g transform="translate(407,491)" stroke="#f9a8d4" stroke-width="1.5" fill="none" stroke-linecap="round" stroke-linejoin="round">
186
+ <path d="M3,5 H15 M12,2 L15,5 L12,8"/>
187
+ <path d="M15,13 H3 M6,10 L3,13 L6,16"/>
188
+ </g>
189
+ <text x="446" y="498" font-size="15.5" font-weight="700" fill="#e6edf7">③ 格式转换 Transformers</text>
190
+ <text x="446" y="520" font-size="12" fill="#8c9bc4">Claude ↔ OpenAI ↔ Gemini ↔ DeepSeek · 双向转换 · SSE 流式</text>
191
+ <g transform="translate(446,536)" font-size="10.5" font-weight="700">
192
+ <rect x="0" y="0" width="56" height="22" rx="6" fill="#a855f7" fill-opacity=".16" stroke="#a855f7" stroke-opacity=".5"/>
193
+ <text x="28" y="15" text-anchor="middle" fill="#d8b4fe">Claude</text>
194
+ <text x="64" y="15" fill="#6f7da6">↔</text>
195
+ <rect x="78" y="0" width="58" height="22" rx="6" fill="#10b981" fill-opacity=".16" stroke="#10b981" stroke-opacity=".5"/>
196
+ <text x="107" y="15" text-anchor="middle" fill="#a7f3d0">OpenAI</text>
197
+ <text x="144" y="15" fill="#6f7da6">↔</text>
198
+ <rect x="158" y="0" width="58" height="22" rx="6" fill="#3b82f6" fill-opacity=".16" stroke="#3b82f6" stroke-opacity=".5"/>
199
+ <text x="187" y="15" text-anchor="middle" fill="#bfdbfe">Gemini</text>
200
+ <text x="224" y="15" fill="#6f7da6">↔</text>
201
+ <rect x="238" y="0" width="68" height="22" rx="6" fill="#8b5cf6" fill-opacity=".16" stroke="#8b5cf6" stroke-opacity=".5"/>
202
+ <text x="272" y="15" text-anchor="middle" fill="#c4b5fd">DeepSeek</text>
203
+ </g>
204
+ <g transform="translate(912,490)">
205
+ <rect width="96" height="22" rx="11" fill="#ec4899" fill-opacity=".12" stroke="#ec4899" stroke-opacity=".45"/>
206
+ <text x="48" y="15" text-anchor="middle" font-size="10.5" fill="#f9a8d4">SSE 流式</text>
207
+ </g>
208
+ </g>
209
+
210
+ <!-- ── M4 Logging ── -->
211
+ <g>
212
+ <rect x="380" y="584" width="640" height="92" rx="14" fill="url(#panelFill)" stroke="#1f2c52"/>
213
+ <circle cx="416" cy="616" r="18" fill="#10b981" fill-opacity=".14" stroke="#10b981" stroke-width="1.4"/>
214
+ <g transform="translate(407,607)" stroke="#6ee7b7" stroke-width="1.4" fill="none" stroke-linecap="round">
215
+ <path d="M3,15 H17"/>
216
+ <rect x="5" y="9" width="3" height="6" fill="#6ee7b7" stroke="none"/>
217
+ <rect x="10" y="5" width="3" height="10" fill="#6ee7b7" stroke="none"/>
218
+ <rect x="15" y="11" width="3" height="4" fill="#6ee7b7" stroke="none"/>
219
+ </g>
220
+ <text x="446" y="614" font-size="15.5" font-weight="700" fill="#e6edf7">④ 日志 / 会话 / 配额 Logging</text>
221
+ <text x="446" y="636" font-size="12" fill="#8c9bc4">请求日志 · 会话追踪 · 多维配额(Token / RPM / 并发)</text>
222
+ <g transform="translate(842,606)">
223
+ <rect width="78" height="22" rx="11" fill="#10b981" fill-opacity=".10" stroke="#10b981" stroke-opacity=".4"/>
224
+ <text x="39" y="15" text-anchor="middle" font-size="10.5" fill="#6ee7b7">Token 计费</text>
225
+ </g>
226
+ <g transform="translate(928,606)">
227
+ <rect width="78" height="22" rx="11" fill="#10b981" fill-opacity=".10" stroke="#10b981" stroke-opacity=".4"/>
228
+ <text x="39" y="15" text-anchor="middle" font-size="10.5" fill="#6ee7b7">配额限速</text>
229
+ </g>
230
+ </g>
231
+ </g>
232
+
233
+ <!-- ============ RIGHT column · upstream ============ -->
234
+ <!-- Anthropic -->
235
+ <g>
236
+ <rect x="1126" y="180" width="210" height="92" rx="14" fill="#111a33" stroke="#243156"/>
237
+ <rect x="1330" y="200" width="4" height="52" rx="2" fill="#f59e0b"/>
238
+ <circle cx="1158" cy="226" r="18" fill="#f59e0b" fill-opacity=".16" stroke="#f59e0b" stroke-width="1.5"/>
239
+ <text x="1158" y="232" text-anchor="middle" font-size="15" font-weight="800" fill="#fcd34d">A</text>
240
+ <text x="1188" y="221" font-size="14.5" font-weight="700" fill="#e6edf7">Anthropic</text>
241
+ <text x="1188" y="240" font-size="11.5" fill="#8c9bc4">Claude · claude-*</text>
242
+ </g>
243
+ <!-- OpenAI -->
244
+ <g>
245
+ <rect x="1126" y="288" width="210" height="92" rx="14" fill="#111a33" stroke="#243156"/>
246
+ <rect x="1330" y="308" width="4" height="52" rx="2" fill="#10b981"/>
247
+ <circle cx="1158" cy="334" r="18" fill="#10b981" fill-opacity=".16" stroke="#10b981" stroke-width="1.5"/>
248
+ <text x="1158" y="340" text-anchor="middle" font-size="15" font-weight="800" fill="#a7f3d0">O</text>
249
+ <text x="1188" y="329" font-size="14.5" font-weight="700" fill="#e6edf7">OpenAI</text>
250
+ <text x="1188" y="348" font-size="11.5" fill="#8c9bc4">GPT · o-*</text>
251
+ </g>
252
+ <!-- Gemini -->
253
+ <g>
254
+ <rect x="1126" y="396" width="210" height="92" rx="14" fill="#111a33" stroke="#243156"/>
255
+ <rect x="1330" y="416" width="4" height="52" rx="2" fill="#3b82f6"/>
256
+ <circle cx="1158" cy="442" r="18" fill="#3b82f6" fill-opacity=".16" stroke="#3b82f6" stroke-width="1.5"/>
257
+ <text x="1158" y="448" text-anchor="middle" font-size="15" font-weight="800" fill="#bfdbfe">G</text>
258
+ <text x="1188" y="437" font-size="14.5" font-weight="700" fill="#e6edf7">Google</text>
259
+ <text x="1188" y="456" font-size="11.5" fill="#8c9bc4">Gemini · gemini-*</text>
260
+ </g>
261
+ <!-- DeepSeek -->
262
+ <g>
263
+ <rect x="1126" y="504" width="210" height="92" rx="14" fill="#111a33" stroke="#243156"/>
264
+ <rect x="1330" y="524" width="4" height="52" rx="2" fill="#8b5cf6"/>
265
+ <circle cx="1158" cy="550" r="18" fill="#8b5cf6" fill-opacity=".16" stroke="#8b5cf6" stroke-width="1.5"/>
266
+ <text x="1158" y="556" text-anchor="middle" font-size="15" font-weight="800" fill="#c4b5fd">D</text>
267
+ <text x="1188" y="545" font-size="14.5" font-weight="700" fill="#e6edf7">DeepSeek</text>
268
+ <text x="1188" y="564" font-size="11.5" fill="#8c9bc4">deepseek-*</text>
269
+ </g>
270
+ <!-- Qwen / others -->
271
+ <g>
272
+ <rect x="1126" y="612" width="210" height="92" rx="14" fill="#111a33" stroke="#243156"/>
273
+ <rect x="1330" y="632" width="4" height="52" rx="2" fill="#06b6d4"/>
274
+ <circle cx="1158" cy="658" r="18" fill="#06b6d4" fill-opacity=".16" stroke="#06b6d4" stroke-width="1.5"/>
275
+ <text x="1158" y="664" text-anchor="middle" font-size="15" font-weight="800" fill="#a5f3fc">Q</text>
276
+ <text x="1188" y="653" font-size="14.5" font-weight="700" fill="#e6edf7">Qwen · Kimi 等</text>
277
+ <text x="1188" y="672" font-size="11.5" fill="#8c9bc4">兼容 OpenAI 协议</text>
278
+ </g>
279
+
280
+ <!-- ============ flow lines · LEFT (clients → core) ============ -->
281
+ <g fill="none">
282
+ <!-- L1 -->
283
+ <path d="M274,279 C314,279 322,375 360,375" stroke="#1c284f" stroke-width="2.2"/>
284
+ <path d="M274,279 C314,279 322,375 360,375" stroke="#22d3ee" stroke-width="2" stroke-linecap="round" stroke-dasharray="5 9" marker-end="url(#arrowCyan)" opacity=".92">
285
+ <animate attributeName="stroke-dashoffset" from="14" to="0" dur="1.1s" repeatCount="indefinite"/>
286
+ </path>
287
+ <circle r="3.8" fill="url(#dotCyan)">
288
+ <animateMotion dur="2.4s" repeatCount="indefinite" path="M274,279 C314,279 322,375 360,375"/>
289
+ </circle>
290
+ <!-- L2 -->
291
+ <path d="M274,431 C320,431 322,375 360,375" stroke="#1c284f" stroke-width="2.2"/>
292
+ <path d="M274,431 C320,431 322,375 360,375" stroke="#22d3ee" stroke-width="2" stroke-linecap="round" stroke-dasharray="5 9" marker-end="url(#arrowCyan)" opacity=".92">
293
+ <animate attributeName="stroke-dashoffset" from="14" to="0" dur="1.1s" begin="0.35s" repeatCount="indefinite"/>
294
+ </path>
295
+ <circle r="3.8" fill="url(#dotCyan)">
296
+ <animateMotion dur="2.4s" begin="0.8s" repeatCount="indefinite" path="M274,431 C320,431 322,375 360,375"/>
297
+ </circle>
298
+ <!-- L3 -->
299
+ <path d="M274,583 C326,583 324,375 360,375" stroke="#1c284f" stroke-width="2.2"/>
300
+ <path d="M274,583 C326,583 324,375 360,375" stroke="#22d3ee" stroke-width="2" stroke-linecap="round" stroke-dasharray="5 9" marker-end="url(#arrowCyan)" opacity=".92">
301
+ <animate attributeName="stroke-dashoffset" from="14" to="0" dur="1.1s" begin="0.7s" repeatCount="indefinite"/>
302
+ </path>
303
+ <circle r="3.8" fill="url(#dotCyan)">
304
+ <animateMotion dur="2.4s" begin="1.6s" repeatCount="indefinite" path="M274,583 C326,583 324,375 360,375"/>
305
+ </circle>
306
+ </g>
307
+
308
+ <!-- ============ flow lines · RIGHT (core → upstream) ============ -->
309
+ <g fill="none">
310
+ <!-- R1 -->
311
+ <path d="M1040,430 C1082,430 1088,226 1126,226" stroke="#1c284f" stroke-width="2.2"/>
312
+ <path d="M1040,430 C1082,430 1088,226 1126,226" stroke="#c084fc" stroke-width="2" stroke-linecap="round" stroke-dasharray="5 9" marker-end="url(#arrowPurple)" opacity=".92">
313
+ <animate attributeName="stroke-dashoffset" from="14" to="0" dur="1.2s" repeatCount="indefinite"/>
314
+ </path>
315
+ <circle r="3.8" fill="url(#dotPurple)">
316
+ <animateMotion dur="2.8s" repeatCount="indefinite" path="M1040,430 C1082,430 1088,226 1126,226"/>
317
+ </circle>
318
+ <!-- R2 -->
319
+ <path d="M1040,430 C1082,430 1088,334 1126,334" stroke="#1c284f" stroke-width="2.2"/>
320
+ <path d="M1040,430 C1082,430 1088,334 1126,334" stroke="#c084fc" stroke-width="2" stroke-linecap="round" stroke-dasharray="5 9" marker-end="url(#arrowPurple)" opacity=".92">
321
+ <animate attributeName="stroke-dashoffset" from="14" to="0" dur="1.2s" begin="0.3s" repeatCount="indefinite"/>
322
+ </path>
323
+ <circle r="3.8" fill="url(#dotPurple)">
324
+ <animateMotion dur="2.8s" begin="0.56s" repeatCount="indefinite" path="M1040,430 C1082,430 1088,334 1126,334"/>
325
+ </circle>
326
+ <!-- R3 -->
327
+ <path d="M1040,430 C1082,430 1088,442 1126,442" stroke="#1c284f" stroke-width="2.2"/>
328
+ <path d="M1040,430 C1082,430 1088,442 1126,442" stroke="#c084fc" stroke-width="2" stroke-linecap="round" stroke-dasharray="5 9" marker-end="url(#arrowPurple)" opacity=".92">
329
+ <animate attributeName="stroke-dashoffset" from="14" to="0" dur="1.2s" begin="0.6s" repeatCount="indefinite"/>
330
+ </path>
331
+ <circle r="3.8" fill="url(#dotPurple)">
332
+ <animateMotion dur="2.8s" begin="1.12s" repeatCount="indefinite" path="M1040,430 C1082,430 1088,442 1126,442"/>
333
+ </circle>
334
+ <!-- R4 -->
335
+ <path d="M1040,430 C1084,430 1088,550 1126,550" stroke="#1c284f" stroke-width="2.2"/>
336
+ <path d="M1040,430 C1084,430 1088,550 1126,550" stroke="#c084fc" stroke-width="2" stroke-linecap="round" stroke-dasharray="5 9" marker-end="url(#arrowPurple)" opacity=".92">
337
+ <animate attributeName="stroke-dashoffset" from="14" to="0" dur="1.2s" begin="0.9s" repeatCount="indefinite"/>
338
+ </path>
339
+ <circle r="3.8" fill="url(#dotPurple)">
340
+ <animateMotion dur="2.8s" begin="1.68s" repeatCount="indefinite" path="M1040,430 C1084,430 1088,550 1126,550"/>
341
+ </circle>
342
+ <!-- R5 -->
343
+ <path d="M1040,430 C1086,430 1088,658 1126,658" stroke="#1c284f" stroke-width="2.2"/>
344
+ <path d="M1040,430 C1086,430 1088,658 1126,658" stroke="#c084fc" stroke-width="2" stroke-linecap="round" stroke-dasharray="5 9" marker-end="url(#arrowPurple)" opacity=".92">
345
+ <animate attributeName="stroke-dashoffset" from="14" to="0" dur="1.2s" begin="1.2s" repeatCount="indefinite"/>
346
+ </path>
347
+ <circle r="3.8" fill="url(#dotPurple)">
348
+ <animateMotion dur="2.8s" begin="2.24s" repeatCount="indefinite" path="M1040,430 C1086,430 1088,658 1126,658"/>
349
+ </circle>
350
+ </g>
351
+
352
+ <!-- ============ footer caption + legend ============ -->
353
+ <text x="700" y="778" text-anchor="middle" font-size="12.5" fill="#7c89ab">流向:客户端发起请求 → 鉴权 → 路由 / 规则匹配 → 格式转换 → 上游模型;响应原路回流</text>
354
+ <g transform="translate(592,800)" font-size="11" fill="#8c9bc4">
355
+ <line x1="0" y1="0" x2="34" y2="0" stroke="#22d3ee" stroke-width="2" stroke-dasharray="5 9"/>
356
+ <text x="42" y="4">请求汇聚</text>
357
+ <line x1="130" y1="0" x2="164" y2="0" stroke="#c084fc" stroke-width="2" stroke-dasharray="5 9"/>
358
+ <text x="172" y="4">分发上游</text>
359
+ </g>
360
+ </svg>