diff --git a/docs/reports/model-provider-logos.md b/docs/reports/model-provider-logos.md
new file mode 100644
index 0000000..013879b
--- /dev/null
+++ b/docs/reports/model-provider-logos.md
@@ -0,0 +1,11 @@
+# Логотипы моделей и провайдеров
+
+2026-08-31, предварительная часть перед A50. База `17b368a`.
+
+Причина отсутствия изображений: getProviderIcon ссылался на codex.png, claude.png и другие файлы, отсутствовавшие в web/static; реальные provider ids antigravity/claude также не совпадали с алиасами в таблице. Неизвестным провайдерам ошибочно назначалась llama.png.
+
+Существующие OpenAI/Antigravity/OpenCode PNG скопированы без изменения из assets/providers. Набор дополнен локальными SVG Gemini, Claude, Grok, Ollama, NVIDIA, OpenRouter, DeepSeek, Qwen, Meta, Mistral, vLLM, LM Studio из [Lobe Icons](https://github.com/lobehub/lobe-icons). Лицензия MIT и точная ревизия сохранены рядом с файлами; загрузки с CDN при работе Hub нет.
+
+Провайдер определяется по provider id, логотип модели — по её семейству. Название модели не изменяется; неизвестная модель получает нейтральный символ. Нет выдачи Ollama за бренд любой размещённой на нём модели. Добавлены значки назначенных моделей в карточки аккаунтов, рядом с выбором модели в маршрутизации и вместо общего символа на узлах графа. Единственное изменение workflow.js — отображение изображения; топология и настройки не затронуты.
+
+Проверки: test_brand_icons.js проверяет алиасы, семейства, fallback и существование файлов; прежние два JS-набора проходят. Браузер подтвердил complete/naturalWidth для 16/16 изображений. Снимок: docs/screenshots/a50/brand-catalog.png. Это каталог, не доказательство сквозной работы A50 или авторизованных аккаунтов. Новый клиент находится в отдельном worktree A50; установленный Hub и preview A48 не заменены.
diff --git a/docs/screenshots/a50/brand-catalog.png b/docs/screenshots/a50/brand-catalog.png
new file mode 100644
index 0000000..7397cb0
Binary files /dev/null and b/docs/screenshots/a50/brand-catalog.png differ
diff --git a/src/antigravity_provider/router/web/static/app.js b/src/antigravity_provider/router/web/static/app.js
index ae65cdf..12f1f8b 100644
--- a/src/antigravity_provider/router/web/static/app.js
+++ b/src/antigravity_provider/router/web/static/app.js
@@ -787,6 +787,7 @@ function renderAccountCard(profile) {
+
${quotaGridHtml}
`;
@@ -991,14 +992,32 @@ function renderOverviewView() {
function getProviderIcon(provider) {
const map = {
- 'openai-codex': 'codex.png',
- 'google-antigravity': 'антигравити.png',
- 'opencode-go': 'opencode.png',
- 'anthropic-claude': 'claude.png',
- 'deepseek': 'deepseek.png',
- 'grok': 'grok.jfif'
+ 'openai-codex':'openai.png', openai:'openai.png', codex:'openai.png',
+ antigravity:'antigravity.png', 'google-antigravity':'antigravity.png',
+ 'opencode-go':'opencode.png', opencode:'opencode.png',
+ claude:'claude-color.svg', 'anthropic-claude':'claude-color.svg', anthropic:'claude-color.svg',
+ grok:'grok.svg', xai:'grok.svg', ollama:'ollama.svg',
+ nvidia:'nvidia-color.svg', openrouter:'openrouter.svg',
+ deepseek:'deepseek-color.svg', vllm:'vllm-color.svg', lmstudio:'lmstudio.svg',
+ local:'unknown.svg', 'llama.cpp':'unknown.svg',
};
- return map[provider] || 'llama.png';
+ return 'brands/'+(map[String(provider || '').toLowerCase()] || 'unknown.svg');
+}
+
+function getModelIcon(model) {
+ const name=String(model || '').toLowerCase().split('/').at(-1);
+ const family=[
+ [/^gemini(?:[-.:]|$)/,'gemini-color.svg'],
+ [/^claude(?:[-.:]|$)/,'claude-color.svg'],[/^(?:gpt|chatgpt|codex|o[134])(?:[-.:0-9]|$)/,'openai.png'],
+ [/^grok(?:[-.:]|$)/,'grok.svg'],[/^deepseek(?:[-.:]|$)/,'deepseek-color.svg'],
+ [/^qwen(?:[-.:0-9]|$)/,'qwen-color.svg'],[/^(?:llama|meta-llama)(?:[-.:0-9]|$)/,'meta-color.svg'],
+ [/^(?:mistral|mixtral|codestral|devstral|magistral)(?:[-.:0-9]|$)/,'mistral-color.svg'],
+ ].find(([pattern])=>pattern.test(name));
+ return 'brands/'+(family?.[1] || 'unknown.svg');
+}
+
+function modelBrandLabel(model) {
+ return `${escapeHtml(model || 'Модель: Н/Д')}`;
}
function renderRoutingView() { renderAccountRouting(); }
diff --git a/src/antigravity_provider/router/web/static/brands/LICENSE-lobe-icons.txt b/src/antigravity_provider/router/web/static/brands/LICENSE-lobe-icons.txt
new file mode 100644
index 0000000..1dd53d2
--- /dev/null
+++ b/src/antigravity_provider/router/web/static/brands/LICENSE-lobe-icons.txt
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023 LobeHub
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/src/antigravity_provider/router/web/static/brands/README.md b/src/antigravity_provider/router/web/static/brands/README.md
new file mode 100644
index 0000000..b1c0b3d
--- /dev/null
+++ b/src/antigravity_provider/router/web/static/brands/README.md
@@ -0,0 +1,3 @@
+# Brand assets
+
+Existing PNGs copied unchanged from assets/providers. Other SVG marks: https://github.com/lobehub/lobe-icons (MIT), revision 4aaf4ee1fb2678a7f989ea570f0f6ce14a9abf75; license bundled. Served locally without CDN. SVG geometry unchanged. Trademarks belong to their owners.
diff --git a/src/antigravity_provider/router/web/static/brands/antigravity.png b/src/antigravity_provider/router/web/static/brands/antigravity.png
new file mode 100644
index 0000000..d53a1b8
Binary files /dev/null and b/src/antigravity_provider/router/web/static/brands/antigravity.png differ
diff --git a/src/antigravity_provider/router/web/static/brands/catalog.html b/src/antigravity_provider/router/web/static/brands/catalog.html
new file mode 100644
index 0000000..b29d0f3
--- /dev/null
+++ b/src/antigravity_provider/router/web/static/brands/catalog.html
@@ -0,0 +1 @@
+Hermes Hub — логотипы моделей и провайдеров
Логотипы моделей и провайдеров
Локальные файлы. Первые три — существующий набор; остальные — масштабируемые SVG. Последний значок используется только для неизвестной модели.
openai.pngantigravity.pngopencode.pnggemini-color.svgclaude-color.svggrok.svgollama.svgnvidia-color.svgopenrouter.svgdeepseek-color.svgqwen-color.svgmeta-color.svgmistral-color.svgvllm-color.svglmstudio.svgunknown.svg
\ No newline at end of file
diff --git a/src/antigravity_provider/router/web/static/brands/claude-color.svg b/src/antigravity_provider/router/web/static/brands/claude-color.svg
new file mode 100644
index 0000000..62dc0db
--- /dev/null
+++ b/src/antigravity_provider/router/web/static/brands/claude-color.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/antigravity_provider/router/web/static/brands/deepseek-color.svg b/src/antigravity_provider/router/web/static/brands/deepseek-color.svg
new file mode 100644
index 0000000..3fc2302
--- /dev/null
+++ b/src/antigravity_provider/router/web/static/brands/deepseek-color.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/antigravity_provider/router/web/static/brands/gemini-color.svg b/src/antigravity_provider/router/web/static/brands/gemini-color.svg
new file mode 100644
index 0000000..62681df
--- /dev/null
+++ b/src/antigravity_provider/router/web/static/brands/gemini-color.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/antigravity_provider/router/web/static/brands/grok.svg b/src/antigravity_provider/router/web/static/brands/grok.svg
new file mode 100644
index 0000000..efb1a61
--- /dev/null
+++ b/src/antigravity_provider/router/web/static/brands/grok.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/antigravity_provider/router/web/static/brands/lmstudio.svg b/src/antigravity_provider/router/web/static/brands/lmstudio.svg
new file mode 100644
index 0000000..ea0816b
--- /dev/null
+++ b/src/antigravity_provider/router/web/static/brands/lmstudio.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/antigravity_provider/router/web/static/brands/meta-color.svg b/src/antigravity_provider/router/web/static/brands/meta-color.svg
new file mode 100644
index 0000000..a8a8d94
--- /dev/null
+++ b/src/antigravity_provider/router/web/static/brands/meta-color.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/antigravity_provider/router/web/static/brands/mistral-color.svg b/src/antigravity_provider/router/web/static/brands/mistral-color.svg
new file mode 100644
index 0000000..8e03e24
--- /dev/null
+++ b/src/antigravity_provider/router/web/static/brands/mistral-color.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/antigravity_provider/router/web/static/brands/nvidia-color.svg b/src/antigravity_provider/router/web/static/brands/nvidia-color.svg
new file mode 100644
index 0000000..a9683c2
--- /dev/null
+++ b/src/antigravity_provider/router/web/static/brands/nvidia-color.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/antigravity_provider/router/web/static/brands/ollama.svg b/src/antigravity_provider/router/web/static/brands/ollama.svg
new file mode 100644
index 0000000..cc887e3
--- /dev/null
+++ b/src/antigravity_provider/router/web/static/brands/ollama.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/antigravity_provider/router/web/static/brands/openai.png b/src/antigravity_provider/router/web/static/brands/openai.png
new file mode 100644
index 0000000..7bfb26c
Binary files /dev/null and b/src/antigravity_provider/router/web/static/brands/openai.png differ
diff --git a/src/antigravity_provider/router/web/static/brands/opencode.png b/src/antigravity_provider/router/web/static/brands/opencode.png
new file mode 100644
index 0000000..145cae7
Binary files /dev/null and b/src/antigravity_provider/router/web/static/brands/opencode.png differ
diff --git a/src/antigravity_provider/router/web/static/brands/openrouter.svg b/src/antigravity_provider/router/web/static/brands/openrouter.svg
new file mode 100644
index 0000000..029070c
--- /dev/null
+++ b/src/antigravity_provider/router/web/static/brands/openrouter.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/antigravity_provider/router/web/static/brands/qwen-color.svg b/src/antigravity_provider/router/web/static/brands/qwen-color.svg
new file mode 100644
index 0000000..f2d0ada
--- /dev/null
+++ b/src/antigravity_provider/router/web/static/brands/qwen-color.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/antigravity_provider/router/web/static/brands/unknown.svg b/src/antigravity_provider/router/web/static/brands/unknown.svg
new file mode 100644
index 0000000..38f80ad
--- /dev/null
+++ b/src/antigravity_provider/router/web/static/brands/unknown.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/antigravity_provider/router/web/static/brands/vllm-color.svg b/src/antigravity_provider/router/web/static/brands/vllm-color.svg
new file mode 100644
index 0000000..54acc3d
--- /dev/null
+++ b/src/antigravity_provider/router/web/static/brands/vllm-color.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/antigravity_provider/router/web/static/style.css b/src/antigravity_provider/router/web/static/style.css
index b677047..0f593bb 100644
--- a/src/antigravity_provider/router/web/static/style.css
+++ b/src/antigravity_provider/router/web/static/style.css
@@ -1915,3 +1915,12 @@ body[data-theme="medium"] .nav-item.active .nav-icon { stroke:var(--text-accent)
.status-dot.not-ready { background:var(--status-error); }
.status-dot.ready { background:var(--status-healthy); }
.resource-value { font-size:clamp(18px,1.7vw,26px); }
+/* Brand marks are local assets, separate for a provider and the model it hosts. */
+.brand-logo,.account-provider-tag img,.available-account-card>img { width:24px; height:24px; object-fit:contain; padding:3px; border-radius:4px; background:#fff; flex:none; }
+.model-brand { display:inline-flex; align-items:center; gap:6px; min-width:0; }
+.model-brand>span { overflow-wrap:anywhere; }
+.account-models { display:flex; gap:8px; flex-wrap:wrap; margin:10px 0; font-size:11px; }
+.account-models:empty { display:none; }
+.route-model-with-logo { display:flex; align-items:center; gap:6px; min-width:0; }
+.route-model-with-logo select { min-width:0; }
+.agent-node-icon .brand-logo { width:27px; height:27px; }
diff --git a/src/antigravity_provider/router/web/static/workflow.js b/src/antigravity_provider/router/web/static/workflow.js
index 9495d01..fdb750d 100644
--- a/src/antigravity_provider/router/web/static/workflow.js
+++ b/src/antigravity_provider/router/web/static/workflow.js
@@ -212,7 +212,7 @@ function renderWorkflowNodes(workflow) {
const assignment = `${cfg.model || 'Модель: Н/Д'} • ${cfg.account || 'Аккаунт: Н/Д'}`;
return `
- ⌘